summaryrefslogtreecommitdiffstats
path: root/private/ntos/ndis
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/ndis')
-rw-r--r--private/ntos/ndis/aic5900/aic5900.h65
-rw-r--r--private/ntos/ndis/aic5900/aic5900.rc39
-rw-r--r--private/ntos/ndis/aic5900/data.c38
-rw-r--r--private/ntos/ndis/aic5900/debug.c221
-rw-r--r--private/ntos/ndis/aic5900/debug.h106
-rw-r--r--private/ntos/ndis/aic5900/dirs0
-rw-r--r--private/ntos/ndis/aic5900/eeprom.h174
-rw-r--r--private/ntos/ndis/aic5900/hw.h502
-rw-r--r--private/ntos/ndis/aic5900/init.c1534
-rw-r--r--private/ntos/ndis/aic5900/int.c100
-rw-r--r--private/ntos/ndis/aic5900/makefile6
-rw-r--r--private/ntos/ndis/aic5900/memmgr.h72
-rw-r--r--private/ntos/ndis/aic5900/protos.h182
-rw-r--r--private/ntos/ndis/aic5900/receive.c68
-rw-r--r--private/ntos/ndis/aic5900/request.c81
-rw-r--r--private/ntos/ndis/aic5900/reset.c79
-rw-r--r--private/ntos/ndis/aic5900/sar.h781
-rw-r--r--private/ntos/ndis/aic5900/send.c44
-rw-r--r--private/ntos/ndis/aic5900/sources54
-rw-r--r--private/ntos/ndis/aic5900/sw.h330
-rw-r--r--private/ntos/ndis/aic5900/vc.c593
-rw-r--r--private/ntos/ndis/dc21x4.bc/alloc.c1
-rw-r--r--private/ntos/ndis/dc21x4.bc/copy.c1
-rw-r--r--private/ntos/ndis/dc21x4.bc/dc21x4.c1
-rw-r--r--private/ntos/ndis/dc21x4.bc/dc21x4.rc2
-rw-r--r--private/ntos/ndis/dc21x4.bc/filter.c1
-rw-r--r--private/ntos/ndis/dc21x4.bc/init.c1
-rw-r--r--private/ntos/ndis/dc21x4.bc/interrup.c1
-rw-r--r--private/ntos/ndis/dc21x4.bc/mactophy.c2
-rw-r--r--private/ntos/ndis/dc21x4.bc/makefile7
-rw-r--r--private/ntos/ndis/dc21x4.bc/media.c1
-rw-r--r--private/ntos/ndis/dc21x4.bc/miigen.c2
-rw-r--r--private/ntos/ndis/dc21x4.bc/miiphy.c2
-rw-r--r--private/ntos/ndis/dc21x4.bc/monitor.c1
-rw-r--r--private/ntos/ndis/dc21x4.bc/register.c1
-rw-r--r--private/ntos/ndis/dc21x4.bc/request.c1
-rw-r--r--private/ntos/ndis/dc21x4.bc/reset.c1
-rw-r--r--private/ntos/ndis/dc21x4.bc/send.c1
-rw-r--r--private/ntos/ndis/dc21x4.bc/sources49
-rw-r--r--private/ntos/ndis/dc21x4.bc/srom.c1
-rw-r--r--private/ntos/ndis/dc21x4.bc/transfer.c1
-rw-r--r--private/ntos/ndis/dc21x4/alloc.c825
-rw-r--r--private/ntos/ndis/dc21x4/copy.c205
-rw-r--r--private/ntos/ndis/dc21x4/crc.h68
-rw-r--r--private/ntos/ndis/dc21x4/d21x4def.h827
-rw-r--r--private/ntos/ndis/dc21x4/d21x4det.h80
-rw-r--r--private/ntos/ndis/dc21x4/d21x4fct.h809
-rw-r--r--private/ntos/ndis/dc21x4/d21x4hrd.h828
-rw-r--r--private/ntos/ndis/dc21x4/d21x4oid.h102
-rw-r--r--private/ntos/ndis/dc21x4/d21x4rgs.h140
-rw-r--r--private/ntos/ndis/dc21x4/dc21x4.c134
-rw-r--r--private/ntos/ndis/dc21x4/dc21x4.hlpbin0 -> 13339 bytes
-rw-r--r--private/ntos/ndis/dc21x4/dc21x4.hpj47
-rw-r--r--private/ntos/ndis/dc21x4/dc21x4.rc66
-rw-r--r--private/ntos/ndis/dc21x4/dc21x4.rtf199
-rw-r--r--private/ntos/ndis/dc21x4/filter.c758
-rw-r--r--private/ntos/ndis/dc21x4/init.c881
-rw-r--r--private/ntos/ndis/dc21x4/interrup.c1726
-rw-r--r--private/ntos/ndis/dc21x4/mactophy.c701
-rw-r--r--private/ntos/ndis/dc21x4/makefile7
-rw-r--r--private/ntos/ndis/dc21x4/makefile.inc5
-rw-r--r--private/ntos/ndis/dc21x4/media.c2047
-rw-r--r--private/ntos/ndis/dc21x4/mii.h453
-rw-r--r--private/ntos/ndis/dc21x4/miigen.c524
-rw-r--r--private/ntos/ndis/dc21x4/miiphy.c1913
-rw-r--r--private/ntos/ndis/dc21x4/monitor.c354
-rw-r--r--private/ntos/ndis/dc21x4/precomp.h9
-rw-r--r--private/ntos/ndis/dc21x4/register.c2469
-rw-r--r--private/ntos/ndis/dc21x4/request.c530
-rw-r--r--private/ntos/ndis/dc21x4/reset.c337
-rw-r--r--private/ntos/ndis/dc21x4/send.c664
-rw-r--r--private/ntos/ndis/dc21x4/sources58
-rw-r--r--private/ntos/ndis/dc21x4/srom.c1521
-rw-r--r--private/ntos/ndis/dc21x4/transfer.c82
-rw-r--r--private/ntos/ndis/dc21x4/version.h7
-rw-r--r--private/ntos/ndis/detect/dirs26
-rw-r--r--private/ntos/ndis/detect/dll/makefile6
-rw-r--r--private/ntos/ndis/detect/dll/netdtect.c1573
-rw-r--r--private/ntos/ndis/detect/dll/netdtect.def25
-rw-r--r--private/ntos/ndis/detect/dll/netdtect.rc39
-rw-r--r--private/ntos/ndis/detect/dll/sources54
-rw-r--r--private/ntos/ndis/detect/driver/makefile6
-rw-r--r--private/ntos/ndis/detect/driver/netdtect.c3061
-rw-r--r--private/ntos/ndis/detect/driver/netdtect.rc39
-rw-r--r--private/ntos/ndis/detect/driver/sources42
-rw-r--r--private/ntos/ndis/detect/exe/init.c88
-rw-r--r--private/ntos/ndis/detect/exe/makefile6
-rw-r--r--private/ntos/ndis/detect/exe/netdtect.c517
-rw-r--r--private/ntos/ndis/detect/exe/sources52
-rw-r--r--private/ntos/ndis/detect/inc/netdtect.h312
-rw-r--r--private/ntos/ndis/digi/digifile/dgatlas.c108
-rw-r--r--private/ntos/ndis/digi/digifile/dgatlas.h194
-rw-r--r--private/ntos/ndis/digi/digifile/digifile.c637
-rw-r--r--private/ntos/ndis/digi/digifile/digifile.h105
-rw-r--r--private/ntos/ndis/digi/digifile/makefile7
-rw-r--r--private/ntos/ndis/digi/digifile/makefile.inc15
-rw-r--r--private/ntos/ndis/digi/digifile/memprint.c922
-rw-r--r--private/ntos/ndis/digi/digifile/memprint.h73
-rw-r--r--private/ntos/ndis/digi/digifile/sources47
-rw-r--r--private/ntos/ndis/digi/dirs27
-rw-r--r--private/ntos/ndis/digi/images/adp.binbin0 -> 59288 bytes
-rw-r--r--private/ntos/ndis/digi/images/idp_xfs.binbin0 -> 131072 bytes
-rw-r--r--private/ntos/ndis/digi/pcimac/adapter.h223
-rw-r--r--private/ntos/ndis/digi/pcimac/ansihelp.c487
-rw-r--r--private/ntos/ndis/digi/pcimac/ansihelp.h109
-rw-r--r--private/ntos/ndis/digi/pcimac/cm.h162
-rw-r--r--private/ntos/ndis/digi/pcimac/cm_chan.c106
-rw-r--r--private/ntos/ndis/digi/pcimac/cm_conn.c323
-rw-r--r--private/ntos/ndis/digi/pcimac/cm_init.c488
-rw-r--r--private/ntos/ndis/digi/pcimac/cm_prof.c51
-rw-r--r--private/ntos/ndis/digi/pcimac/cm_pub.h134
-rw-r--r--private/ntos/ndis/digi/pcimac/cm_q931.c943
-rw-r--r--private/ntos/ndis/digi/pcimac/cm_stat.c31
-rw-r--r--private/ntos/ndis/digi/pcimac/cm_state.c757
-rw-r--r--private/ntos/ndis/digi/pcimac/cm_timer.c78
-rw-r--r--private/ntos/ndis/digi/pcimac/cnf.h13
-rw-r--r--private/ntos/ndis/digi/pcimac/dgbrip.h33
-rw-r--r--private/ntos/ndis/digi/pcimac/disp.c105
-rw-r--r--private/ntos/ndis/digi/pcimac/disp.h147
-rw-r--r--private/ntos/ndis/digi/pcimac/event.h31
-rw-r--r--private/ntos/ndis/digi/pcimac/frame.h196
-rw-r--r--private/ntos/ndis/digi/pcimac/idd.h440
-rw-r--r--private/ntos/ndis/digi/pcimac/idd_init.c894
-rw-r--r--private/ntos/ndis/digi/pcimac/idd_io.c672
-rw-r--r--private/ntos/ndis/digi/pcimac/idd_msg.c168
-rw-r--r--private/ntos/ndis/digi/pcimac/idd_nv.c140
-rw-r--r--private/ntos/ndis/digi/pcimac/idd_proc.c988
-rw-r--r--private/ntos/ndis/digi/pcimac/idd_pub.h59
-rw-r--r--private/ntos/ndis/digi/pcimac/idd_run.c868
-rw-r--r--private/ntos/ndis/digi/pcimac/io.h27
-rw-r--r--private/ntos/ndis/digi/pcimac/io_core.c435
-rw-r--r--private/ntos/ndis/digi/pcimac/io_pub.h153
-rw-r--r--private/ntos/ndis/digi/pcimac/lanoid.c240
-rw-r--r--private/ntos/ndis/digi/pcimac/makefile6
-rw-r--r--private/ntos/ndis/digi/pcimac/mtl.h306
-rw-r--r--private/ntos/ndis/digi/pcimac/mtl_init.c195
-rw-r--r--private/ntos/ndis/digi/pcimac/mtl_rx.c840
-rw-r--r--private/ntos/ndis/digi/pcimac/mtl_set.c228
-rw-r--r--private/ntos/ndis/digi/pcimac/mtl_tick.c47
-rw-r--r--private/ntos/ndis/digi/pcimac/mtl_tx.c1092
-rw-r--r--private/ntos/ndis/digi/pcimac/mydefs.h376
-rw-r--r--private/ntos/ndis/digi/pcimac/mytypes.h39
-rw-r--r--private/ntos/ndis/digi/pcimac/opcodes.h152
-rw-r--r--private/ntos/ndis/digi/pcimac/pcimac.c2385
-rw-r--r--private/ntos/ndis/digi/pcimac/pcimac.rc28
-rw-r--r--private/ntos/ndis/digi/pcimac/res.h52
-rw-r--r--private/ntos/ndis/digi/pcimac/res_core.c261
-rw-r--r--private/ntos/ndis/digi/pcimac/sema.h8
-rw-r--r--private/ntos/ndis/digi/pcimac/sources74
-rw-r--r--private/ntos/ndis/digi/pcimac/tapioid.c2535
-rw-r--r--private/ntos/ndis/digi/pcimac/tapioid.h440
-rw-r--r--private/ntos/ndis/digi/pcimac/trc.h71
-rw-r--r--private/ntos/ndis/digi/pcimac/trc_core.c357
-rw-r--r--private/ntos/ndis/digi/pcimac/trc_pub.h49
-rw-r--r--private/ntos/ndis/digi/pcimac/util.c146
-rw-r--r--private/ntos/ndis/digi/pcimac/util.h27
-rw-r--r--private/ntos/ndis/digi/pcimac/wan_conn.c122
-rw-r--r--private/ntos/ndis/digi/pcimac/wanoid.c226
-rw-r--r--private/ntos/ndis/dirs62
-rw-r--r--private/ntos/ndis/elnk16/elnk16.c35
-rw-r--r--private/ntos/ndis/elnk16/elnk16.ini21
-rw-r--r--private/ntos/ndis/elnk16/elnk16.rc39
-rw-r--r--private/ntos/ndis/elnk16/makefile6
-rw-r--r--private/ntos/ndis/elnk16/sources45
-rw-r--r--private/ntos/ndis/elnk16/switch.h42
-rw-r--r--private/ntos/ndis/elnk3/card.c1321
-rw-r--r--private/ntos/ndis/elnk3/config.c514
-rw-r--r--private/ntos/ndis/elnk3/debug.h133
-rw-r--r--private/ntos/ndis/elnk3/elnk3.c174
-rw-r--r--private/ntos/ndis/elnk3/elnk3.h424
-rw-r--r--private/ntos/ndis/elnk3/elnk3.rc39
-rw-r--r--private/ntos/ndis/elnk3/elnk3hrd.h549
-rw-r--r--private/ntos/ndis/elnk3/elnk3sft.h361
-rw-r--r--private/ntos/ndis/elnk3/init.c897
-rw-r--r--private/ntos/ndis/elnk3/interrup.c418
-rw-r--r--private/ntos/ndis/elnk3/keywords.h56
-rw-r--r--private/ntos/ndis/elnk3/makefile6
-rw-r--r--private/ntos/ndis/elnk3/receive.c1722
-rw-r--r--private/ntos/ndis/elnk3/request.c839
-rw-r--r--private/ntos/ndis/elnk3/send.c292
-rw-r--r--private/ntos/ndis/elnk3/sources51
-rw-r--r--private/ntos/ndis/elnkii.new/card.c3155
-rw-r--r--private/ntos/ndis/elnkii.new/elnkhrd.h811
-rw-r--r--private/ntos/ndis/elnkii.new/elnkii.c1825
-rw-r--r--private/ntos/ndis/elnkii.new/elnkii.rc39
-rw-r--r--private/ntos/ndis/elnkii.new/elnksft.h824
-rw-r--r--private/ntos/ndis/elnkii.new/interrup.c395
-rw-r--r--private/ntos/ndis/elnkii.new/keywords.h56
-rw-r--r--private/ntos/ndis/elnkii.new/makefile6
-rw-r--r--private/ntos/ndis/elnkii.new/rcv.c893
-rw-r--r--private/ntos/ndis/elnkii.new/send.c455
-rw-r--r--private/ntos/ndis/elnkii.new/sources49
-rw-r--r--private/ntos/ndis/elnkii/card.c2780
-rw-r--r--private/ntos/ndis/elnkii/elnkhrd.h780
-rw-r--r--private/ntos/ndis/elnkii/elnkii.c4010
-rw-r--r--private/ntos/ndis/elnkii/elnkii.rc39
-rw-r--r--private/ntos/ndis/elnkii/elnksft.h1295
-rw-r--r--private/ntos/ndis/elnkii/interrup.c2426
-rw-r--r--private/ntos/ndis/elnkii/keywords.h56
-rw-r--r--private/ntos/ndis/elnkii/makefile6
-rw-r--r--private/ntos/ndis/elnkii/pend.c440
-rw-r--r--private/ntos/ndis/elnkii/sources45
-rw-r--r--private/ntos/ndis/elnkmc/82586.h367
-rw-r--r--private/ntos/ndis/elnkmc/command.c607
-rw-r--r--private/ntos/ndis/elnkmc/elnk.c2071
-rw-r--r--private/ntos/ndis/elnkmc/elnkhw.h315
-rw-r--r--private/ntos/ndis/elnkmc/elnkmc.rc39
-rw-r--r--private/ntos/ndis/elnkmc/elnksw.h973
-rw-r--r--private/ntos/ndis/elnkmc/interrup.c1981
-rw-r--r--private/ntos/ndis/elnkmc/keywords.h47
-rw-r--r--private/ntos/ndis/elnkmc/loopback.c282
-rw-r--r--private/ntos/ndis/elnkmc/makefile6
-rw-r--r--private/ntos/ndis/elnkmc/packet.c437
-rw-r--r--private/ntos/ndis/elnkmc/request.c1859
-rw-r--r--private/ntos/ndis/elnkmc/reset.c2331
-rw-r--r--private/ntos/ndis/elnkmc/send.c340
-rw-r--r--private/ntos/ndis/elnkmc/sources50
-rw-r--r--private/ntos/ndis/elnkmc/switch.h39
-rw-r--r--private/ntos/ndis/elnkmc/transfer.c167
-rw-r--r--private/ntos/ndis/htdsu/card.c722
-rw-r--r--private/ntos/ndis/htdsu/card.h521
-rw-r--r--private/ntos/ndis/htdsu/debug.c112
-rw-r--r--private/ntos/ndis/htdsu/debug.h137
-rw-r--r--private/ntos/ndis/htdsu/htdsu.c1395
-rw-r--r--private/ntos/ndis/htdsu/htdsu.h931
-rw-r--r--private/ntos/ndis/htdsu/htdsu.rc9
-rw-r--r--private/ntos/ndis/htdsu/interrup.c656
-rw-r--r--private/ntos/ndis/htdsu/keywords.h77
-rw-r--r--private/ntos/ndis/htdsu/link.c587
-rw-r--r--private/ntos/ndis/htdsu/makefile7
-rw-r--r--private/ntos/ndis/htdsu/oemsetnt.inf1241
-rw-r--r--private/ntos/ndis/htdsu/receive.c199
-rw-r--r--private/ntos/ndis/htdsu/request.c661
-rw-r--r--private/ntos/ndis/htdsu/send.c502
-rw-r--r--private/ntos/ndis/htdsu/sources53
-rw-r--r--private/ntos/ndis/htdsu/tapi.c5001
-rw-r--r--private/ntos/ndis/htdsu/version.h62
-rw-r--r--private/ntos/ndis/ibmtok/ibmtok.c5906
-rw-r--r--private/ntos/ndis/ibmtok/ibmtok.rc39
-rw-r--r--private/ntos/ndis/ibmtok/interrup.c4855
-rw-r--r--private/ntos/ndis/ibmtok/keywords.h54
-rw-r--r--private/ntos/ndis/ibmtok/makefile6
-rw-r--r--private/ntos/ndis/ibmtok/packet.c732
-rw-r--r--private/ntos/ndis/ibmtok/send.c322
-rw-r--r--private/ntos/ndis/ibmtok/sources48
-rw-r--r--private/ntos/ndis/ibmtok/tokhrd.h667
-rw-r--r--private/ntos/ndis/ibmtok/toksft.h1373
-rw-r--r--private/ntos/ndis/ibmtok/transfer.c412
-rw-r--r--private/ntos/ndis/ibmtok2e/command.c1811
-rw-r--r--private/ntos/ndis/ibmtok2e/interrup.c1501
-rw-r--r--private/ntos/ndis/ibmtok2e/makefile6
-rw-r--r--private/ntos/ndis/ibmtok2e/reset.c1937
-rw-r--r--private/ntos/ndis/ibmtok2e/send.c740
-rw-r--r--private/ntos/ndis/ibmtok2e/sources53
-rw-r--r--private/ntos/ndis/ibmtok2e/tok162.c2145
-rw-r--r--private/ntos/ndis/ibmtok2e/tok162.rc38
-rw-r--r--private/ntos/ndis/ibmtok2e/tok162hw.h950
-rw-r--r--private/ntos/ndis/ibmtok2e/tok162pr.h314
-rw-r--r--private/ntos/ndis/ibmtok2e/tok162sw.h738
-rw-r--r--private/ntos/ndis/ibmtok2i/command.c715
-rw-r--r--private/ntos/ndis/ibmtok2i/interrup.c1376
-rw-r--r--private/ntos/ndis/ibmtok2i/log.txt77
-rw-r--r--private/ntos/ndis/ibmtok2i/makefile6
-rw-r--r--private/ntos/ndis/ibmtok2i/request.c1346
-rw-r--r--private/ntos/ndis/ibmtok2i/reset.c1918
-rw-r--r--private/ntos/ndis/ibmtok2i/send.c706
-rw-r--r--private/ntos/ndis/ibmtok2i/sources48
-rw-r--r--private/ntos/ndis/ibmtok2i/tok162.c2504
-rw-r--r--private/ntos/ndis/ibmtok2i/tok162.rc38
-rw-r--r--private/ntos/ndis/ibmtok2i/tok162hw.h1382
-rw-r--r--private/ntos/ndis/ibmtok2i/tok162pr.h315
-rw-r--r--private/ntos/ndis/ibmtok2i/tok162sw.h699
-rw-r--r--private/ntos/ndis/ieepro/82595.h218
-rw-r--r--private/ntos/ndis/ieepro/eeprom.c392
-rw-r--r--private/ntos/ndis/ieepro/epro.c512
-rw-r--r--private/ntos/ndis/ieepro/epro.h221
-rw-r--r--private/ntos/ndis/ieepro/epro.rc39
-rw-r--r--private/ntos/ndis/ieepro/eprodbg.c57
-rw-r--r--private/ntos/ndis/ieepro/eprodbg.h129
-rw-r--r--private/ntos/ndis/ieepro/eprohw.h202
-rw-r--r--private/ntos/ndis/ieepro/eprosw.h254
-rw-r--r--private/ntos/ndis/ieepro/init.c1418
-rw-r--r--private/ntos/ndis/ieepro/makefile6
-rw-r--r--private/ntos/ndis/ieepro/request.c989
-rw-r--r--private/ntos/ndis/ieepro/sndrcv.c1178
-rw-r--r--private/ntos/ndis/ieepro/sources48
-rw-r--r--private/ntos/ndis/inc/ndisprv.h32
-rw-r--r--private/ntos/ndis/irmini/actisys.c113
-rw-r--r--private/ntos/ndis/irmini/actisys.h20
-rw-r--r--private/ntos/ndis/irmini/adaptec.c328
-rw-r--r--private/ntos/ndis/irmini/adaptec.h18
-rw-r--r--private/ntos/ndis/irmini/comm.c1050
-rw-r--r--private/ntos/ndis/irmini/comm.h194
-rw-r--r--private/ntos/ndis/irmini/convert.c228
-rw-r--r--private/ntos/ndis/irmini/crystal.c373
-rw-r--r--private/ntos/ndis/irmini/crystal.h20
-rw-r--r--private/ntos/ndis/irmini/dongle.h80
-rw-r--r--private/ntos/ndis/irmini/esi.c99
-rw-r--r--private/ntos/ndis/irmini/esi.h20
-rw-r--r--private/ntos/ndis/irmini/externs.h161
-rw-r--r--private/ntos/ndis/irmini/fcs.c83
-rw-r--r--private/ntos/ndis/irmini/irmini.c1222
-rw-r--r--private/ntos/ndis/irmini/irmini.h180
-rw-r--r--private/ntos/ndis/irmini/irmini.rc39
-rw-r--r--private/ntos/ndis/irmini/makefile9
-rw-r--r--private/ntos/ndis/irmini/nscdemo.c198
-rw-r--r--private/ntos/ndis/irmini/nscdemo.h20
-rw-r--r--private/ntos/ndis/irmini/oemsetup.inf1475
-rw-r--r--private/ntos/ndis/irmini/parallax.c113
-rw-r--r--private/ntos/ndis/irmini/parallax.h20
-rw-r--r--private/ntos/ndis/irmini/request.c290
-rw-r--r--private/ntos/ndis/irmini/resource.c303
-rw-r--r--private/ntos/ndis/irmini/settings.c139
-rw-r--r--private/ntos/ndis/irmini/settings.h226
-rw-r--r--private/ntos/ndis/irmini/sources32
-rw-r--r--private/ntos/ndis/lance/dectc.c301
-rw-r--r--private/ntos/ndis/lance/dectc.h29
-rw-r--r--private/ntos/ndis/lance/details.c428
-rw-r--r--private/ntos/ndis/lance/keywords.h56
-rw-r--r--private/ntos/ndis/lance/lance.c4974
-rw-r--r--private/ntos/ndis/lance/lance.rc39
-rw-r--r--private/ntos/ndis/lance/lancehrd.h479
-rw-r--r--private/ntos/ndis/lance/lancesft.h962
-rw-r--r--private/ntos/ndis/lance/makefile6
-rw-r--r--private/ntos/ndis/lance/send.c437
-rw-r--r--private/ntos/ndis/lance/sources47
-rw-r--r--private/ntos/ndis/lance/transfer.c389
-rw-r--r--private/ntos/ndis/loop/debug.h47
-rw-r--r--private/ntos/ndis/loop/loop.c1378
-rw-r--r--private/ntos/ndis/loop/loop.h223
-rw-r--r--private/ntos/ndis/loop/loop.rc39
-rw-r--r--private/ntos/ndis/loop/makefile6
-rw-r--r--private/ntos/ndis/loop/request.c1255
-rw-r--r--private/ntos/ndis/loop/send.c717
-rw-r--r--private/ntos/ndis/loop/sources20
-rw-r--r--private/ntos/ndis/lsl/frames.h189
-rw-r--r--private/ntos/ndis/lsl/init.c2060
-rw-r--r--private/ntos/ndis/lsl/lsl.h526
-rw-r--r--private/ntos/ndis/lsl/lslmlid.c2085
-rw-r--r--private/ntos/ndis/lsl/lslmlid.h85
-rw-r--r--private/ntos/ndis/lsl/makefile6
-rw-r--r--private/ntos/ndis/lsl/mlid.h361
-rw-r--r--private/ntos/ndis/lsl/mlidrcv.c589
-rw-r--r--private/ntos/ndis/lsl/mlidsend.c875
-rw-r--r--private/ntos/ndis/lsl/mlidstat.c363
-rw-r--r--private/ntos/ndis/lsl/ndismlid.c1183
-rw-r--r--private/ntos/ndis/lsl/ndismlid.h128
-rw-r--r--private/ntos/ndis/lsl/sources46
-rw-r--r--private/ntos/ndis/lt200/lt200.rc38
-rw-r--r--private/ntos/ndis/lt200/ltdebug.h103
-rw-r--r--private/ntos/ndis/lt200/ltfirm.c755
-rw-r--r--private/ntos/ndis/lt200/ltfirm.h42
-rw-r--r--private/ntos/ndis/lt200/ltglobal.h48
-rw-r--r--private/ntos/ndis/lt200/lthrd.h85
-rw-r--r--private/ntos/ndis/lt200/ltinit.c738
-rw-r--r--private/ntos/ndis/lt200/ltinit.h96
-rw-r--r--private/ntos/ndis/lt200/ltloop.c185
-rw-r--r--private/ntos/ndis/lt200/ltloop.h37
-rw-r--r--private/ntos/ndis/lt200/ltmain.h53
-rw-r--r--private/ntos/ndis/lt200/ltrecv.c523
-rw-r--r--private/ntos/ndis/lt200/ltrecv.h78
-rw-r--r--private/ntos/ndis/lt200/ltreg.c262
-rw-r--r--private/ntos/ndis/lt200/ltreg.h80
-rw-r--r--private/ntos/ndis/lt200/ltreq.c651
-rw-r--r--private/ntos/ndis/lt200/ltreq.h159
-rw-r--r--private/ntos/ndis/lt200/ltreset.c344
-rw-r--r--private/ntos/ndis/lt200/ltreset.h58
-rw-r--r--private/ntos/ndis/lt200/ltsend.c342
-rw-r--r--private/ntos/ndis/lt200/ltsend.h43
-rw-r--r--private/ntos/ndis/lt200/ltsft.h223
-rw-r--r--private/ntos/ndis/lt200/lttimer.c280
-rw-r--r--private/ntos/ndis/lt200/lttimer.h46
-rw-r--r--private/ntos/ndis/lt200/ltutils.c610
-rw-r--r--private/ntos/ndis/lt200/ltutils.h184
-rw-r--r--private/ntos/ndis/lt200/makefile6
-rw-r--r--private/ntos/ndis/lt200/sources50
-rw-r--r--private/ntos/ndis/madge/detect/makefile7
-rw-r--r--private/ntos/ndis/madge/detect/mdgat.c1956
-rw-r--r--private/ntos/ndis/madge/detect/mdgeisa.c1288
-rw-r--r--private/ntos/ndis/madge/detect/mdgmc.c1316
-rw-r--r--private/ntos/ndis/madge/detect/mdgncdet.c1101
-rw-r--r--private/ntos/ndis/madge/detect/mdgncdet.def18
-rw-r--r--private/ntos/ndis/madge/detect/mdgncdet.h930
-rw-r--r--private/ntos/ndis/madge/detect/mdgncdet.rc27
-rw-r--r--private/ntos/ndis/madge/detect/mdgncdet.upd200
-rw-r--r--private/ntos/ndis/madge/detect/mdgpci.c1446
-rw-r--r--private/ntos/ndis/madge/detect/mdgpcmc.c1396
-rw-r--r--private/ntos/ndis/madge/detect/mdgpnp.c2231
-rw-r--r--private/ntos/ndis/madge/detect/mdgsm16.c1495
-rw-r--r--private/ntos/ndis/madge/detect/mdgutils.c1599
-rw-r--r--private/ntos/ndis/madge/detect/sources47
-rw-r--r--private/ntos/ndis/madge/dirs29
-rw-r--r--private/ntos/ndis/madge/dll/blmadge.icobin0 -> 766 bytes
-rw-r--r--private/ntos/ndis/madge/dll/brmadge.icobin0 -> 766 bytes
-rw-r--r--private/ntos/ndis/madge/dll/madge.icobin0 -> 766 bytes
-rw-r--r--private/ntos/ndis/madge/dll/makefile1
-rw-r--r--private/ntos/ndis/madge/dll/makefile.inc5
-rw-r--r--private/ntos/ndis/madge/dll/mdgmpdlg.c124
-rw-r--r--private/ntos/ndis/madge/dll/mdgmpdlg.def8
-rw-r--r--private/ntos/ndis/madge/dll/mdgmpdlg.dlg111
-rw-r--r--private/ntos/ndis/madge/dll/mdgmpdlg.h6
-rw-r--r--private/ntos/ndis/madge/dll/mdgmpdlg.hlpbin0 -> 18350 bytes
-rw-r--r--private/ntos/ndis/madge/dll/mdgmpdlg.hpj18
-rw-r--r--private/ntos/ndis/madge/dll/mdgmpdlg.rc36
-rw-r--r--private/ntos/ndis/madge/dll/mdgmpdlg.resbin0 -> 6496 bytes
-rw-r--r--private/ntos/ndis/madge/dll/mdgmpdlg.rtf307
-rw-r--r--private/ntos/ndis/madge/dll/mdgmpdlg.upd181
-rw-r--r--private/ntos/ndis/madge/dll/oemsetup.upd241
-rw-r--r--private/ntos/ndis/madge/dll/sources42
-rw-r--r--private/ntos/ndis/madge/dll/tlmadge.icobin0 -> 766 bytes
-rw-r--r--private/ntos/ndis/madge/dll/trmadge.icobin0 -> 766 bytes
-rw-r--r--private/ntos/ndis/madge/dll/uilstf.h481
-rw-r--r--private/ntos/ndis/madge/driver/dispatch.c919
-rw-r--r--private/ntos/ndis/madge/driver/drv_err.c555
-rw-r--r--private/ntos/ndis/madge/driver/drv_init.c1656
-rw-r--r--private/ntos/ndis/madge/driver/drv_irq.c413
-rw-r--r--private/ntos/ndis/madge/driver/drv_srb.c1849
-rw-r--r--private/ntos/ndis/madge/driver/ftk.upd279
-rw-r--r--private/ntos/ndis/madge/driver/ftk_poke.c267
-rw-r--r--private/ntos/ndis/madge/driver/ftk_user.c2187
-rw-r--r--private/ntos/ndis/madge/driver/head_def/ftk_adap.h280
-rw-r--r--private/ntos/ndis/madge/driver/head_def/ftk_at.h234
-rw-r--r--private/ntos/ndis/madge/driver/head_def/ftk_card.h341
-rw-r--r--private/ntos/ndis/madge/driver/head_def/ftk_defs.h52
-rw-r--r--private/ntos/ndis/madge/driver/head_def/ftk_down.h128
-rw-r--r--private/ntos/ndis/madge/driver/head_def/ftk_eisa.h132
-rw-r--r--private/ntos/ndis/madge/driver/head_def/ftk_err.h389
-rw-r--r--private/ntos/ndis/madge/driver/head_def/ftk_fm.h351
-rw-r--r--private/ntos/ndis/madge/driver/head_def/ftk_init.h330
-rw-r--r--private/ntos/ndis/madge/driver/head_def/ftk_macr.h157
-rw-r--r--private/ntos/ndis/madge/driver/head_def/ftk_mc.h195
-rw-r--r--private/ntos/ndis/madge/driver/head_def/ftk_pci.h150
-rw-r--r--private/ntos/ndis/madge/driver/head_def/ftk_pci2.h122
-rw-r--r--private/ntos/ndis/madge/driver/head_def/ftk_pcit.h109
-rw-r--r--private/ntos/ndis/madge/driver/head_def/ftk_pcmc.h256
-rw-r--r--private/ntos/ndis/madge/driver/head_def/ftk_pnp.h142
-rw-r--r--private/ntos/ndis/madge/driver/head_def/ftk_poke.h52
-rw-r--r--private/ntos/ndis/madge/driver/head_def/ftk_sm16.h100
-rw-r--r--private/ntos/ndis/madge/driver/head_def/ftk_srb.h279
-rw-r--r--private/ntos/ndis/madge/driver/head_def/ftk_tab.h1054
-rw-r--r--private/ntos/ndis/madge/driver/head_def/ftk_user.h666
-rw-r--r--private/ntos/ndis/madge/driver/head_mod/drv_err.h56
-rw-r--r--private/ntos/ndis/madge/driver/head_mod/drv_init.h79
-rw-r--r--private/ntos/ndis/madge/driver/head_mod/drv_irq.h48
-rw-r--r--private/ntos/ndis/madge/driver/head_mod/drv_misc.h81
-rw-r--r--private/ntos/ndis/madge/driver/head_mod/drv_rxtx.h201
-rw-r--r--private/ntos/ndis/madge/driver/head_mod/drv_srb.h110
-rw-r--r--private/ntos/ndis/madge/driver/head_mod/ftk_extr.h67
-rw-r--r--private/ntos/ndis/madge/driver/head_mod/ftk_intr.h76
-rw-r--r--private/ntos/ndis/madge/driver/head_mod/hwi_at.h75
-rw-r--r--private/ntos/ndis/madge/driver/head_mod/hwi_eisa.h72
-rw-r--r--private/ntos/ndis/madge/driver/head_mod/hwi_gen.h127
-rw-r--r--private/ntos/ndis/madge/driver/head_mod/hwi_mc.h72
-rw-r--r--private/ntos/ndis/madge/driver/head_mod/hwi_pci.h61
-rw-r--r--private/ntos/ndis/madge/driver/head_mod/hwi_pci2.h56
-rw-r--r--private/ntos/ndis/madge/driver/head_mod/hwi_pcit.h56
-rw-r--r--private/ntos/ndis/madge/driver/head_mod/hwi_pcmc.h77
-rw-r--r--private/ntos/ndis/madge/driver/head_mod/hwi_pnp.h72
-rw-r--r--private/ntos/ndis/madge/driver/head_mod/hwi_sm16.h70
-rw-r--r--private/ntos/ndis/madge/driver/head_mod/sys_allo.h95
-rw-r--r--private/ntos/ndis/madge/driver/head_mod/sys_buff.h67
-rw-r--r--private/ntos/ndis/madge/driver/head_mod/sys_cs.h651
-rw-r--r--private/ntos/ndis/madge/driver/head_mod/sys_dma.h60
-rw-r--r--private/ntos/ndis/madge/driver/head_mod/sys_irq.h65
-rw-r--r--private/ntos/ndis/madge/driver/head_mod/sys_mem.h206
-rw-r--r--private/ntos/ndis/madge/driver/head_mod/sys_pci.h93
-rw-r--r--private/ntos/ndis/madge/driver/head_mod/sys_pcmc.h50
-rw-r--r--private/ntos/ndis/madge/driver/head_mod/sys_time.h52
-rw-r--r--private/ntos/ndis/madge/driver/head_mod/util.h80
-rw-r--r--private/ntos/ndis/madge/driver/hwi_at.c2206
-rw-r--r--private/ntos/ndis/madge/driver/hwi_eisa.c1054
-rw-r--r--private/ntos/ndis/madge/driver/hwi_gen.c2077
-rw-r--r--private/ntos/ndis/madge/driver/hwi_mc.c1326
-rw-r--r--private/ntos/ndis/madge/driver/hwi_pci.c1567
-rw-r--r--private/ntos/ndis/madge/driver/hwi_pci2.c1792
-rw-r--r--private/ntos/ndis/madge/driver/hwi_pcit.c2028
-rw-r--r--private/ntos/ndis/madge/driver/hwi_pcmc.c3366
-rw-r--r--private/ntos/ndis/madge/driver/hwi_pnp.c2490
-rw-r--r--private/ntos/ndis/madge/driver/hwi_sm16.c1191
-rw-r--r--private/ntos/ndis/madge/driver/inc/ndismod.h792
-rw-r--r--private/ntos/ndis/madge/driver/inc/user.h235
-rw-r--r--private/ntos/ndis/madge/driver/madge.c3393
-rw-r--r--private/ntos/ndis/madge/driver/makefile7
-rw-r--r--private/ntos/ndis/madge/driver/makefile.inc5
-rw-r--r--private/ntos/ndis/madge/driver/mdgerrs.h154
-rw-r--r--private/ntos/ndis/madge/driver/mdgerrs.rc2
-rw-r--r--private/ntos/ndis/madge/driver/mdgmport.binbin0 -> 57142 bytes
-rw-r--r--private/ntos/ndis/madge/driver/mdgmport.rc26
-rw-r--r--private/ntos/ndis/madge/driver/mdgmport.upd553
-rw-r--r--private/ntos/ndis/madge/driver/msg00001.binbin0 -> 2744 bytes
-rw-r--r--private/ntos/ndis/madge/driver/request.c1158
-rw-r--r--private/ntos/ndis/madge/driver/sources56
-rw-r--r--private/ntos/ndis/madge/driver/sys_allo.c492
-rw-r--r--private/ntos/ndis/madge/driver/sys_dma.c233
-rw-r--r--private/ntos/ndis/madge/driver/sys_irq.c119
-rw-r--r--private/ntos/ndis/madge/driver/sys_mem.c925
-rw-r--r--private/ntos/ndis/madge/driver/sys_time.c80
-rw-r--r--private/ntos/ndis/madge/driver/util.c252
-rw-r--r--private/ntos/ndis/ndis30/afilter.c2083
-rw-r--r--private/ntos/ndis/ndis30/afilter.h339
-rw-r--r--private/ntos/ndis/ndis30/efilter.c2252
-rw-r--r--private/ntos/ndis/ndis30/efilter.h605
-rw-r--r--private/ntos/ndis/ndis30/ffilter.c3193
-rw-r--r--private/ntos/ndis/ndis30/ffilter.h692
-rw-r--r--private/ntos/ndis/ndis30/makefile6
-rw-r--r--private/ntos/ndis/ndis30/makefile.inc2
-rw-r--r--private/ntos/ndis/ndis30/miniport.c10214
-rw-r--r--private/ntos/ndis/ndis30/minisub.c280
-rw-r--r--private/ntos/ndis/ndis30/ndis.prf102
-rw-r--r--private/ntos/ndis/ndis30/ndis.rc39
-rw-r--r--private/ntos/ndis/ndis30/ndis.src185
-rw-r--r--private/ntos/ndis/ndis30/ndismac.h1218
-rw-r--r--private/ntos/ndis/ndis30/ndismain.h1976
-rw-r--r--private/ntos/ndis/ndis30/ndismini.h1216
-rw-r--r--private/ntos/ndis/ndis30/precomp.h6
-rw-r--r--private/ntos/ndis/ndis30/sources59
-rw-r--r--private/ntos/ndis/ndis30/tfilter.c2119
-rw-r--r--private/ntos/ndis/ndis30/tfilter.h558
-rw-r--r--private/ntos/ndis/ndis30/wrapper.c17480
-rw-r--r--private/ntos/ndis/ndis30/wrapper.h473
-rw-r--r--private/ntos/ndis/ndis30/wrapper.txt120
-rw-r--r--private/ntos/ndis/ndis40/afilter.c2617
-rw-r--r--private/ntos/ndis/ndis40/bus.c1009
-rw-r--r--private/ntos/ndis/ndis40/common.c3452
-rw-r--r--private/ntos/ndis/ndis40/config.c2788
-rw-r--r--private/ntos/ndis/ndis40/configm.c2077
-rw-r--r--private/ntos/ndis/ndis40/data.c190
-rw-r--r--private/ntos/ndis/ndis40/debug.c422
-rw-r--r--private/ntos/ndis/ndis40/dirs23
-rw-r--r--private/ntos/ndis/ndis40/dummy.c56
-rw-r--r--private/ntos/ndis/ndis40/efilter.c2845
-rw-r--r--private/ntos/ndis/ndis40/ffilter.c3869
-rw-r--r--private/ntos/ndis/ndis40/filter.h181
-rw-r--r--private/ntos/ndis/ndis40/init.c1415
-rw-r--r--private/ntos/ndis/ndis40/initpnp.c2463
-rw-r--r--private/ntos/ndis/ndis40/mac.c3591
-rw-r--r--private/ntos/ndis/ndis40/mac.h48
-rw-r--r--private/ntos/ndis/ndis40/makefile6
-rw-r--r--private/ntos/ndis/ndis40/makefile.inc11
-rw-r--r--private/ntos/ndis/ndis40/mini.h251
-rw-r--r--private/ntos/ndis/ndis40/minint.c1293
-rw-r--r--private/ntos/ndis/ndis40/miniport.c3180
-rw-r--r--private/ntos/ndis/ndis40/minisub.c569
-rw-r--r--private/ntos/ndis/ndis40/mp/makefile6
-rw-r--r--private/ntos/ndis/ndis40/mp/ndis.prf136
-rw-r--r--private/ntos/ndis/ndis40/mp/sources29
-rw-r--r--private/ntos/ndis/ndis40/ndis.c1349
-rw-r--r--private/ntos/ndis/ndis40/ndis.rc39
-rw-r--r--private/ntos/ndis/ndis40/ndis.src328
-rw-r--r--private/ntos/ndis/ndis40/ndis_co.c3873
-rw-r--r--private/ntos/ndis/ndis40/ndisdbg.h270
-rw-r--r--private/ntos/ndis/ndis40/ndisnt.h325
-rw-r--r--private/ntos/ndis/ndis40/ndistags.h53
-rw-r--r--private/ntos/ndis/ndis40/pragma.h733
-rw-r--r--private/ntos/ndis/ndis40/precomp.h17
-rw-r--r--private/ntos/ndis/ndis40/protocol.c1757
-rw-r--r--private/ntos/ndis/ndis40/protos.h1991
-rw-r--r--private/ntos/ndis/ndis40/requestm.c3994
-rw-r--r--private/ntos/ndis/ndis40/sendm.c3212
-rw-r--r--private/ntos/ndis/ndis40/sendm.h334
-rw-r--r--private/ntos/ndis/ndis40/sources.inc77
-rw-r--r--private/ntos/ndis/ndis40/tfilter.c2813
-rw-r--r--private/ntos/ndis/ndis40/timer.c794
-rw-r--r--private/ntos/ndis/ndis40/timerm.c1080
-rw-r--r--private/ntos/ndis/ndis40/up/makefile6
-rw-r--r--private/ntos/ndis/ndis40/up/ndis.prf136
-rw-r--r--private/ntos/ndis/ndis40/up/sources29
-rw-r--r--private/ntos/ndis/ndis40/wrapper.h681
-rw-r--r--private/ntos/ndis/ndis40/wrapper.txt120
-rw-r--r--private/ntos/ndis/ndistapi/intrface.h138
-rw-r--r--private/ntos/ndis/ndistapi/makefile7
-rw-r--r--private/ntos/ndis/ndistapi/ndistapi.c2873
-rw-r--r--private/ntos/ndis/ndistapi/ndistapi.rc38
-rw-r--r--private/ntos/ndis/ndistapi/ndistapi.src7
-rw-r--r--private/ntos/ndis/ndistapi/private.h251
-rw-r--r--private/ntos/ndis/ndistapi/sources40
-rw-r--r--private/ntos/ndis/ndiswan/adapter.h132
-rw-r--r--private/ntos/ndis/ndiswan/ccp.c456
-rw-r--r--private/ntos/ndis/ndiswan/compress.c1689
-rw-r--r--private/ntos/ndis/ndiswan/compress.h187
-rw-r--r--private/ntos/ndis/ndiswan/dirs26
-rw-r--r--private/ntos/ndis/ndiswan/export/makefile6
-rw-r--r--private/ntos/ndis/ndiswan/export/sources59
-rw-r--r--private/ntos/ndis/ndiswan/global.h52
-rw-r--r--private/ntos/ndis/ndiswan/indicate.c611
-rw-r--r--private/ntos/ndis/ndiswan/io.c4608
-rw-r--r--private/ntos/ndis/ndiswan/kdexts/api.c385
-rw-r--r--private/ntos/ndis/ndiswan/kdexts/display.c543
-rw-r--r--private/ntos/ndis/ndiswan/kdexts/display.h54
-rw-r--r--private/ntos/ndis/ndiswan/kdexts/makefile6
-rw-r--r--private/ntos/ndis/ndiswan/kdexts/sources49
-rw-r--r--private/ntos/ndis/ndiswan/kdexts/wanhelp.c183
-rw-r--r--private/ntos/ndis/ndiswan/kdexts/wanhelp.def48
-rw-r--r--private/ntos/ndis/ndiswan/kdexts/wanhelp.h99
-rw-r--r--private/ntos/ndis/ndiswan/kdexts/wanhelp.rc12
-rw-r--r--private/ntos/ndis/ndiswan/loopback.c148
-rw-r--r--private/ntos/ndis/ndiswan/memory.c1624
-rw-r--r--private/ntos/ndis/ndiswan/miniport.c576
-rw-r--r--private/ntos/ndis/ndiswan/ndiswan.c1346
-rw-r--r--private/ntos/ndis/ndiswan/ndiswan.rc43
-rw-r--r--private/ntos/ndis/ndiswan/protocol.c723
-rw-r--r--private/ntos/ndis/ndiswan/receive.c2865
-rw-r--r--private/ntos/ndis/ndiswan/request.c541
-rw-r--r--private/ntos/ndis/ndiswan/send.c3080
-rw-r--r--private/ntos/ndis/ndiswan/tapi.c144
-rw-r--r--private/ntos/ndis/ndiswan/tcpip.h52
-rw-r--r--private/ntos/ndis/ndiswan/util.c323
-rw-r--r--private/ntos/ndis/ndiswan/vjslip.c885
-rw-r--r--private/ntos/ndis/ndiswan/vjslip.h249
-rw-r--r--private/ntos/ndis/ndiswan/wan.h42
-rw-r--r--private/ntos/ndis/ndiswan/wandefs.h649
-rw-r--r--private/ntos/ndis/ndiswan/wanproto.h696
-rw-r--r--private/ntos/ndis/ndiswan/wantypes.h505
-rw-r--r--private/ntos/ndis/ne1000/makefile6
-rw-r--r--private/ntos/ndis/ne1000/ne1000.c30
-rw-r--r--private/ntos/ndis/ne1000/ne1000.rc39
-rw-r--r--private/ntos/ndis/ne1000/sources43
-rw-r--r--private/ntos/ndis/ne2000/card.c3212
-rw-r--r--private/ntos/ndis/ne2000/interrup.c2126
-rw-r--r--private/ntos/ndis/ne2000/keywords.h54
-rw-r--r--private/ntos/ndis/ne2000/makefile6
-rw-r--r--private/ntos/ndis/ne2000/ne2000.c2054
-rw-r--r--private/ntos/ndis/ne2000/ne2000.rc39
-rw-r--r--private/ntos/ndis/ne2000/ne2000hw.h557
-rw-r--r--private/ntos/ndis/ne2000/ne2000sw.h877
-rw-r--r--private/ntos/ndis/ne2000/sources45
-rw-r--r--private/ntos/ndis/ne3200/command.c272
-rw-r--r--private/ntos/ndis/ne3200/interrup.c835
-rw-r--r--private/ntos/ndis/ne3200/keywords.h43
-rw-r--r--private/ntos/ndis/ne3200/mac2hex/mac.binbin0 -> 4096 bytes
-rw-r--r--private/ntos/ndis/ne3200/mac2hex/mac2hex.c309
-rw-r--r--private/ntos/ndis/ne3200/mac2hex/mac2hex.def5
-rw-r--r--private/ntos/ndis/ne3200/mac2hex/makefile6
-rw-r--r--private/ntos/ndis/ne3200/mac2hex/sources19
-rw-r--r--private/ntos/ndis/ne3200/makefile6
-rw-r--r--private/ntos/ndis/ne3200/makefile.inc5
-rw-r--r--private/ntos/ndis/ne3200/ne3200.binbin0 -> 4096 bytes
-rw-r--r--private/ntos/ndis/ne3200/ne3200.c2497
-rw-r--r--private/ntos/ndis/ne3200/ne3200.ini18
-rw-r--r--private/ntos/ndis/ne3200/ne3200.prf40
-rw-r--r--private/ntos/ndis/ne3200/ne3200.rc39
-rw-r--r--private/ntos/ndis/ne3200/ne3200hw.h964
-rw-r--r--private/ntos/ndis/ne3200/ne3200pr.h273
-rw-r--r--private/ntos/ndis/ne3200/ne3200sw.h805
-rw-r--r--private/ntos/ndis/ne3200/request.c954
-rw-r--r--private/ntos/ndis/ne3200/reset.c1805
-rw-r--r--private/ntos/ndis/ne3200/send.c816
-rw-r--r--private/ntos/ndis/ne3200/sources51
-rw-r--r--private/ntos/ndis/netflex.bc/init.c1
-rw-r--r--private/ntos/ndis/netflex.bc/initd.c1
-rw-r--r--private/ntos/ndis/netflex.bc/int.c1
-rw-r--r--private/ntos/ndis/netflex.bc/makefile6
-rw-r--r--private/ntos/ndis/netflex.bc/netflex.rc1
-rw-r--r--private/ntos/ndis/netflex.bc/netflxbc.prf27
-rw-r--r--private/ntos/ndis/netflex.bc/receive.c1
-rw-r--r--private/ntos/ndis/netflex.bc/request.c1
-rw-r--r--private/ntos/ndis/netflex.bc/reset.c1
-rw-r--r--private/ntos/ndis/netflex.bc/sources83
-rw-r--r--private/ntos/ndis/netflex.bc/support.c1
-rw-r--r--private/ntos/ndis/netflex.bc/transmit.c1
-rw-r--r--private/ntos/ndis/netflex/adapter.h137
-rw-r--r--private/ntos/ndis/netflex/cpqntssd.ver68
-rw-r--r--private/ntos/ndis/netflex/init.c1605
-rw-r--r--private/ntos/ndis/netflex/initd.c230
-rw-r--r--private/ntos/ndis/netflex/int.c977
-rw-r--r--private/ntos/ndis/netflex/macstrct.h581
-rw-r--r--private/ntos/ndis/netflex/makefile6
-rw-r--r--private/ntos/ndis/netflex/makefile.inc5
-rw-r--r--private/ntos/ndis/netflex/netflex.rc40
-rw-r--r--private/ntos/ndis/netflex/netflx.binbin0 -> 110720 bytes
-rw-r--r--private/ntos/ndis/netflex/netflx.prf27
-rw-r--r--private/ntos/ndis/netflex/protos.h450
-rw-r--r--private/ntos/ndis/netflex/receive.c633
-rw-r--r--private/ntos/ndis/netflex/request.c2148
-rw-r--r--private/ntos/ndis/netflex/reset.c1924
-rw-r--r--private/ntos/ndis/netflex/sources84
-rw-r--r--private/ntos/ndis/netflex/support.c1986
-rw-r--r--private/ntos/ndis/netflex/tmsstrct.h606
-rw-r--r--private/ntos/ndis/netflex/transmit.c802
-rw-r--r--private/ntos/ndis/odimac/keywords.h54
-rw-r--r--private/ntos/ndis/odimac/mlid.c4413
-rw-r--r--private/ntos/ndis/odimac/mlidsft.h814
-rw-r--r--private/ntos/ndis/odimac/odihsm.h418
-rw-r--r--private/ntos/ndis/odimac/umi.c336
-rw-r--r--private/ntos/ndis/pc586e/filter.c1824
-rw-r--r--private/ntos/ndis/pc586e/filter.h402
-rw-r--r--private/ntos/ndis/pc586e/loopback.c523
-rw-r--r--private/ntos/ndis/pc586e/makefile6
-rw-r--r--private/ntos/ndis/pc586e/packet.c535
-rw-r--r--private/ntos/ndis/pc586e/pc586.c4269
-rw-r--r--private/ntos/ndis/pc586e/pc586e.c119
-rw-r--r--private/ntos/ndis/pc586e/pc586hrd.h438
-rw-r--r--private/ntos/ndis/pc586e/pc586sft.h889
-rw-r--r--private/ntos/ndis/pc586e/pc586snd.c1300
-rw-r--r--private/ntos/ndis/pc586e/pc586xfr.c620
-rw-r--r--private/ntos/ndis/pc586e/sources47
-rw-r--r--private/ntos/ndis/pc586e/ushort.c98
-rw-r--r--private/ntos/ndis/pcimac/adapter.h230
-rw-r--r--private/ntos/ndis/pcimac/adp.binbin0 -> 55908 bytes
-rw-r--r--private/ntos/ndis/pcimac/cm.h162
-rw-r--r--private/ntos/ndis/pcimac/cm_chan.c107
-rw-r--r--private/ntos/ndis/pcimac/cm_conn.c324
-rw-r--r--private/ntos/ndis/pcimac/cm_init.c489
-rw-r--r--private/ntos/ndis/pcimac/cm_prof.c52
-rw-r--r--private/ntos/ndis/pcimac/cm_pub.h134
-rw-r--r--private/ntos/ndis/pcimac/cm_q931.c950
-rw-r--r--private/ntos/ndis/pcimac/cm_stat.c32
-rw-r--r--private/ntos/ndis/pcimac/cm_state.c755
-rw-r--r--private/ntos/ndis/pcimac/cm_timer.c79
-rw-r--r--private/ntos/ndis/pcimac/cnf.h13
-rw-r--r--private/ntos/ndis/pcimac/disp.c132
-rw-r--r--private/ntos/ndis/pcimac/disp.h42
-rw-r--r--private/ntos/ndis/pcimac/event.h31
-rw-r--r--private/ntos/ndis/pcimac/frame.h196
-rw-r--r--private/ntos/ndis/pcimac/idd.h440
-rw-r--r--private/ntos/ndis/pcimac/idd_init.c909
-rw-r--r--private/ntos/ndis/pcimac/idd_io.c593
-rw-r--r--private/ntos/ndis/pcimac/idd_msg.c163
-rw-r--r--private/ntos/ndis/pcimac/idd_nv.c140
-rw-r--r--private/ntos/ndis/pcimac/idd_proc.c947
-rw-r--r--private/ntos/ndis/pcimac/idd_pub.h59
-rw-r--r--private/ntos/ndis/pcimac/idd_run.c777
-rw-r--r--private/ntos/ndis/pcimac/idp_xfs.binbin0 -> 131072 bytes
-rw-r--r--private/ntos/ndis/pcimac/io.h21
-rw-r--r--private/ntos/ndis/pcimac/io_core.c322
-rw-r--r--private/ntos/ndis/pcimac/io_pub.h140
-rw-r--r--private/ntos/ndis/pcimac/lanoid.c243
-rw-r--r--private/ntos/ndis/pcimac/makefile6
-rw-r--r--private/ntos/ndis/pcimac/mtl.h306
-rw-r--r--private/ntos/ndis/pcimac/mtl_init.c196
-rw-r--r--private/ntos/ndis/pcimac/mtl_rx.c819
-rw-r--r--private/ntos/ndis/pcimac/mtl_set.c229
-rw-r--r--private/ntos/ndis/pcimac/mtl_tick.c48
-rw-r--r--private/ntos/ndis/pcimac/mtl_tx.c1066
-rw-r--r--private/ntos/ndis/pcimac/mydefs.h354
-rw-r--r--private/ntos/ndis/pcimac/mytypes.h39
-rw-r--r--private/ntos/ndis/pcimac/opcodes.h152
-rw-r--r--private/ntos/ndis/pcimac/pcimac.c2071
-rw-r--r--private/ntos/ndis/pcimac/pcimac.rc23
-rw-r--r--private/ntos/ndis/pcimac/res.h52
-rw-r--r--private/ntos/ndis/pcimac/res_core.c262
-rw-r--r--private/ntos/ndis/pcimac/sema.h8
-rw-r--r--private/ntos/ndis/pcimac/sources69
-rw-r--r--private/ntos/ndis/pcimac/tapioid.c2590
-rw-r--r--private/ntos/ndis/pcimac/tapioid.h440
-rw-r--r--private/ntos/ndis/pcimac/trc.h71
-rw-r--r--private/ntos/ndis/pcimac/trc_core.c358
-rw-r--r--private/ntos/ndis/pcimac/trc_pub.h49
-rw-r--r--private/ntos/ndis/pcimac/util.c117
-rw-r--r--private/ntos/ndis/pcimac/util.h27
-rw-r--r--private/ntos/ndis/pcimac/wan_conn.c123
-rw-r--r--private/ntos/ndis/pcimac/wanoid.c228
-rw-r--r--private/ntos/ndis/sonic/alloc.c1137
-rw-r--r--private/ntos/ndis/sonic/i386/sonicdet.h68
-rw-r--r--private/ntos/ndis/sonic/interrup.c1694
-rw-r--r--private/ntos/ndis/sonic/makefile6
-rw-r--r--private/ntos/ndis/sonic/mips/sonicdet.h89
-rw-r--r--private/ntos/ndis/sonic/request.c890
-rw-r--r--private/ntos/ndis/sonic/send.c1305
-rw-r--r--private/ntos/ndis/sonic/sonic.c2800
-rw-r--r--private/ntos/ndis/sonic/sonic.rc39
-rw-r--r--private/ntos/ndis/sonic/sonichrd.h791
-rw-r--r--private/ntos/ndis/sonic/sonicsft.h1039
-rw-r--r--private/ntos/ndis/sonic/sources61
-rw-r--r--private/ntos/ndis/sonic/transfer.c247
-rw-r--r--private/ntos/ndis/testmac/makefile6
-rw-r--r--private/ntos/ndis/testmac/sources41
-rw-r--r--private/ntos/ndis/testmac/testmac.c1236
-rw-r--r--private/ntos/ndis/testmac/testmac.h349
-rw-r--r--private/ntos/ndis/testprot/dirs28
-rw-r--r--private/ntos/ndis/testprot/docs/arcnet.docbin0 -> 41019 bytes
-rw-r--r--private/ntos/ndis/testprot/docs/rfc1051227
-rw-r--r--private/ntos/ndis/testprot/docs/rfc1201388
-rw-r--r--private/ntos/ndis/testprot/inc/common.h835
-rw-r--r--private/ntos/ndis/testprot/inc/defaults.h193
-rw-r--r--private/ntos/ndis/testprot/tpctl/cmd.c4160
-rw-r--r--private/ntos/ndis/testprot/tpctl/cpuperf.c307
-rw-r--r--private/ntos/ndis/testprot/tpctl/globals.c390
-rw-r--r--private/ntos/ndis/testprot/tpctl/info.c1497
-rw-r--r--private/ntos/ndis/testprot/tpctl/init.c1098
-rw-r--r--private/ntos/ndis/testprot/tpctl/makefile6
-rw-r--r--private/ntos/ndis/testprot/tpctl/parse.c2526
-rw-r--r--private/ntos/ndis/testprot/tpctl/parse.h312
-rw-r--r--private/ntos/ndis/testprot/tpctl/results.c1312
-rw-r--r--private/ntos/ndis/testprot/tpctl/sources49
-rw-r--r--private/ntos/ndis/testprot/tpctl/tp_ndis.h180
-rw-r--r--private/ntos/ndis/testprot/tpctl/tpctl.c3852
-rw-r--r--private/ntos/ndis/testprot/tpctl/tpctl.h751
-rw-r--r--private/ntos/ndis/testprot/tpdiff.new/makefile11
-rw-r--r--private/ntos/ndis/testprot/tpdiff.new/sources63
-rw-r--r--private/ntos/ndis/testprot/tpdiff.new/tpdiff.c2527
-rw-r--r--private/ntos/ndis/testprot/tpdiff.new/tpdiff.h213
-rw-r--r--private/ntos/ndis/testprot/tpdiff/makefile6
-rw-r--r--private/ntos/ndis/testprot/tpdiff/sources48
-rw-r--r--private/ntos/ndis/testprot/tpdiff/tpdiff.c1749
-rw-r--r--private/ntos/ndis/testprot/tpdrvr/buffer.c313
-rw-r--r--private/ntos/ndis/testprot/tpdrvr/makefile6
-rw-r--r--private/ntos/ndis/testprot/tpdrvr/media.c385
-rw-r--r--private/ntos/ndis/testprot/tpdrvr/media.h350
-rw-r--r--private/ntos/ndis/testprot/tpdrvr/packet.c2164
-rw-r--r--private/ntos/ndis/testprot/tpdrvr/perf.c2162
-rw-r--r--private/ntos/ndis/testprot/tpdrvr/protocol.c442
-rw-r--r--private/ntos/ndis/testprot/tpdrvr/sources57
-rw-r--r--private/ntos/ndis/testprot/tpdrvr/stress.c2503
-rw-r--r--private/ntos/ndis/testprot/tpdrvr/strfunc.c1858
-rw-r--r--private/ntos/ndis/testprot/tpdrvr/strrcv.c1280
-rw-r--r--private/ntos/ndis/testprot/tpdrvr/tpdefs.h769
-rw-r--r--private/ntos/ndis/testprot/tpdrvr/tpdrvr.c1656
-rw-r--r--private/ntos/ndis/testprot/tpdrvr/tpfunc.c4639
-rw-r--r--private/ntos/ndis/testprot/tpdrvr/tpprocs.h841
-rw-r--r--private/ntos/ndis/testprot/tpdrvr/tpreq.c952
-rw-r--r--private/ntos/ndis/testprot/tpdrvr/tputils.c1080
-rw-r--r--private/ntos/ndis/testprot/tpkd/makefile6
-rw-r--r--private/ntos/ndis/testprot/tpkd/sources55
-rw-r--r--private/ntos/ndis/testprot/tpkd/tpkd.c450
-rw-r--r--private/ntos/ndis/testprot/tpkd/tpkd.def8
-rw-r--r--private/ntos/ndis/testprot/tpkd/tpkd.h781
-rw-r--r--private/ntos/ndis/testprot/tplib/makefile6
-rw-r--r--private/ntos/ndis/testprot/tplib/oids.c206
-rw-r--r--private/ntos/ndis/testprot/tplib/sources47
-rw-r--r--private/ntos/ndis/ubnei/card.c1910
-rw-r--r--private/ntos/ndis/ubnei/config.c532
-rw-r--r--private/ntos/ndis/ubnei/debug.h90
-rw-r--r--private/ntos/ndis/ubnei/init.c770
-rw-r--r--private/ntos/ndis/ubnei/initdata.c223
-rw-r--r--private/ntos/ndis/ubnei/interrup.c337
-rw-r--r--private/ntos/ndis/ubnei/keywords.h57
-rw-r--r--private/ntos/ndis/ubnei/makefile6
-rw-r--r--private/ntos/ndis/ubnei/makefile.inc5
-rw-r--r--private/ntos/ndis/ubnei/map.c256
-rw-r--r--private/ntos/ndis/ubnei/map.h164
-rw-r--r--private/ntos/ndis/ubnei/niudata.h562
-rw-r--r--private/ntos/ndis/ubnei/receive.c482
-rw-r--r--private/ntos/ndis/ubnei/request.c713
-rw-r--r--private/ntos/ndis/ubnei/send.c369
-rw-r--r--private/ntos/ndis/ubnei/sources55
-rw-r--r--private/ntos/ndis/ubnei/ubhard.h303
-rw-r--r--private/ntos/ndis/ubnei/ubnei.binbin0 -> 5420 bytes
-rw-r--r--private/ntos/ndis/ubnei/ubnei.c567
-rw-r--r--private/ntos/ndis/ubnei/ubnei.h332
-rw-r--r--private/ntos/ndis/ubnei/ubnei.rc12
-rw-r--r--private/ntos/ndis/ubnei/ubsoft.h381
-rw-r--r--private/ntos/ndis/wd/keywords.h54
-rw-r--r--private/ntos/ndis/wd/lmi.c5854
-rw-r--r--private/ntos/ndis/wd/makefile6
-rw-r--r--private/ntos/ndis/wd/sources44
-rw-r--r--private/ntos/ndis/wd/umi.c347
-rw-r--r--private/ntos/ndis/wd/wd.c4599
-rw-r--r--private/ntos/ndis/wd/wdhrd.h915
-rw-r--r--private/ntos/ndis/wd/wdlan.rc39
-rw-r--r--private/ntos/ndis/wd/wdlmi.h865
-rw-r--r--private/ntos/ndis/wd/wdlmireg.h424
-rw-r--r--private/ntos/ndis/wd/wdsft.h852
-rw-r--r--private/ntos/ndis/wd/wdumi.h45
854 files changed, 516090 insertions, 0 deletions
diff --git a/private/ntos/ndis/aic5900/aic5900.h b/private/ntos/ndis/aic5900/aic5900.h
new file mode 100644
index 000000000..3df4dee4d
--- /dev/null
+++ b/private/ntos/ndis/aic5900/aic5900.h
@@ -0,0 +1,65 @@
+
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ D:\nt\private\ntos\ndis\aic5900\aic5900.h
+
+Abstract:
+
+Author:
+
+ Kyle Brandon (KyleB)
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#ifndef __AIC5900_H
+#define __AIC5900_H
+
+#include "ndis.h"
+#include "atm.h"
+
+#if BINARY_COMPATIBLE
+#include <pci.h>
+#endif
+
+#include "eeprom.h"
+#include "hw.h"
+#include "sw.h"
+#include "sar.h"
+#include "protos.h"
+#include "debug.h"
+#include <memmgr.h>
+
+//
+// Module identifiers.
+//
+#define MODULE_DEBUG 0x00010000
+#define MODULE_INIT 0x00020000
+#define MODULE_INT 0x00030000
+#define MODULE_RECEIVE 0x00040000
+#define MODULE_REQUEST 0x00050000
+#define MODULE_RESET 0x00060000
+#define MODULE_SEND 0x00070000
+#define MODULE_VC 0x00080000
+#define MODULE_SUPPORT 0x00090000
+#define MODULE_DATA 0x000a0000
+
+
+//
+// Extern definitions for global data.
+//
+
+extern NDIS_HANDLE gWrapperHandle;
+extern NDIS_STRING gaRegistryParameterString[];
+
+
+#endif // __AIC5900_H
diff --git a/private/ntos/ndis/aic5900/aic5900.rc b/private/ntos/ndis/aic5900/aic5900.rc
new file mode 100644
index 000000000..5b4a29625
--- /dev/null
+++ b/private/ntos/ndis/aic5900/aic5900.rc
@@ -0,0 +1,39 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT__LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "Microsoft Corp. DEC ATM Driver"
+#define VER_INTERNALNAME_STR "OTTO.SYS"
+#define VER_ORIGINALFILENAME_STR "OTTO.SYS"
+
+#include "common.ver"
+
diff --git a/private/ntos/ndis/aic5900/data.c b/private/ntos/ndis/aic5900/data.c
new file mode 100644
index 000000000..91eb3cd94
--- /dev/null
+++ b/private/ntos/ndis/aic5900/data.c
@@ -0,0 +1,38 @@
+
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ D:\nt\private\ntos\ndis\aic5900\data.c
+
+Abstract:
+
+ This file contains global definitions.
+
+Author:
+
+ Kyle Brandon (KyleB)
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "aic5900.h"
+
+#define MODULE_NUMBER MODULE_DATA
+
+NDIS_HANDLE gWrapperHandle = NULL;
+NDIS_STRING gaRegistryParameterString[Aic5900MaxRegistryEntry] =
+{
+ NDIS_STRING_CONST("BusNumber"),
+ NDIS_STRING_CONST("SlotNumber"),
+ NDIS_STRING_CONST("VcHashTableSize")
+};
+
+
diff --git a/private/ntos/ndis/aic5900/debug.c b/private/ntos/ndis/aic5900/debug.c
new file mode 100644
index 000000000..897d67e91
--- /dev/null
+++ b/private/ntos/ndis/aic5900/debug.c
@@ -0,0 +1,221 @@
+
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ D:\nt\private\ntos\ndis\aic5900\debug.c
+
+Abstract:
+
+Author:
+
+ Kyle Brandon (KyleB)
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "aic5900.h"
+
+//
+// Define module number for debug code
+//
+#define MODULE_NUMBER MODULE_DEBUG
+
+
+#if DBG
+
+ULONG gAic5900DebugSystems = DBG_COMP_ALL;
+LONG gAic5900DebugLevel = DBG_LEVEL_INFO;
+ULONG gAic5900DebugInformationOffset;
+
+VOID
+dbgInitializeDebugInformation(
+ IN PADAPTER_BLOCK pAdapter
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+
+}
+
+
+VOID
+dbgDumpHardwareInformation(
+ IN PHARDWARE_INFO HwInfo
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ if ((DBG_LEVEL_INFO >= gAic5900DebugLevel) &&
+ ((gAic5900DebugSystems & DBG_COMP_INIT) == DBG_COMP_INIT))
+ {
+ DbgPrint("FCodeImage: 0x%x\n", HwInfo->FCodeImage);
+ DbgPrint("NicModelNumber: 0x%x\n", HwInfo->NicModelNumber);
+ DbgPrint("RomVersionNumber: 0x%x\n", HwInfo->RomVersionNumber);
+
+ DbgPrint("rEpromOffset: 0x%x\n", HwInfo->rEpromOffset);
+ DbgPrint("rEpromSize: 0x%x\n", HwInfo->rEpromSize);
+ DbgPrint("rEprom: 0x%x\n", HwInfo->rEprom);
+
+ DbgPrint("rwEpromOffset: 0x%x\n", HwInfo->rwEpromOffset);
+ DbgPrint("rwEpromSize: 0x%x\n", HwInfo->rwEpromSize);
+ DbgPrint("rwEprom: 0x%x\n", HwInfo->rwEprom);
+
+ DbgPrint("PhyOffset: 0x%x\n", HwInfo->PhyOffset);
+ DbgPrint("PhySize: 0x%x\n", HwInfo->PhySize);
+ DbgPrint("Phy: 0x%x\n", HwInfo->Phy);
+
+ DbgPrint("ExternalOffset: 0x%x\n", HwInfo->ExternalOffset);
+ DbgPrint("ExternalSize: 0x%x\n", HwInfo->ExternalSize);
+ DbgPrint("External: 0x%x\n", HwInfo->External);
+
+ DbgPrint("MidwayOffset: 0x%x\n", HwInfo->MidwayOffset);
+ DbgPrint("MidwaySize: 0x%x\n", HwInfo->MidwaySize);
+ DbgPrint("Midway: 0x%x\n", HwInfo->Midway);
+
+ DbgPrint("PciCfgOffset: 0x%x\n", HwInfo->PciCfgOffset);
+ DbgPrint("PciCfgSize: 0x%x\n", HwInfo->PciCfgSize);
+ DbgPrint("PciConfigSpace: 0x%x\n", HwInfo->PciConfigSpace);
+
+ DbgPrint("SarRamOffset: 0x%x\n", HwInfo->SarRamOffset);
+ DbgPrint("SarRamSize: 0x%x\n", HwInfo->SarRamSize);
+ DbgPrint("SarRam: 0x%x\n", HwInfo->SarRam);
+
+ DbgPrint("PermanentAddress: %02x-%02x-%02x-%02x-%02x-%02x\n",
+ HwInfo->PermanentAddress[0],
+ HwInfo->PermanentAddress[1],
+ HwInfo->PermanentAddress[2],
+ HwInfo->PermanentAddress[3],
+ HwInfo->PermanentAddress[4],
+ HwInfo->PermanentAddress[5]);
+ }
+}
+
+VOID
+dbgDumpPciFCodeImage(
+ IN PPCI_FCODE_IMAGE PciFcodeImage
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ if ((DBG_LEVEL_INFO >= gAic5900DebugLevel) &&
+ ((gAic5900DebugSystems & DBG_COMP_INIT) == DBG_COMP_INIT))
+ {
+ //
+ // Dump the fcode header.
+ //
+ DbgPrint("PCI FCode Image\n");
+ DbgPrint(" FCodeHeader 0x%x\n", PciFcodeImage->FCodeHeader);
+ DbgPrint(" Name 0x%x\n", PciFcodeImage->Name);
+ DbgPrint(" Model 0x%x\n", PciFcodeImage->Model);
+ DbgPrint(" Intr 0x%x\n", PciFcodeImage->Intr);
+ DbgPrint(" RomVersionNumber 0x%x\n", PciFcodeImage->RomVersionNumber);
+ DbgPrint(" RomVersionString 0x%x\n", PciFcodeImage->RomVersionString);
+ DbgPrint(" RomDateString 0x%x\n", PciFcodeImage->RomDateString);
+ DbgPrint(" roEpromOffset 0x%x\n", PciFcodeImage->roEpromOffset);
+ DbgPrint(" roEpromSize 0x%x\n", PciFcodeImage->roEpromSize);
+ DbgPrint(" rwEpromOffset 0x%x\n", PciFcodeImage->rwEpromOffset);
+ DbgPrint(" rwEpromSize 0x%x\n", PciFcodeImage->rwEpromSize);
+ DbgPrint(" PhyOffset 0x%x\n", PciFcodeImage->PhyOffset);
+ DbgPrint(" PhySize 0x%x\n", PciFcodeImage->PhySize);
+ DbgPrint(" ExternalOffset 0x%x\n", PciFcodeImage->ExternalOffset);
+ DbgPrint(" ExternalSize 0x%x\n", PciFcodeImage->ExternalSize);
+ DbgPrint(" SarOffset 0x%x\n", PciFcodeImage->SarOffset);
+ DbgPrint(" SarSize 0x%x\n", PciFcodeImage->SarSize);
+ DbgPrint(" PciConfigOffset 0x%x\n", PciFcodeImage->PciConfigOffset);
+ DbgPrint(" PciConfigSize 0x%x\n", PciFcodeImage->PciConfigSize);
+ DbgPrint(" SarMemOffset 0x%x\n", PciFcodeImage->SarMemOffset);
+ DbgPrint(" SarMemSize 0x%x\n", PciFcodeImage->SarMemSize);
+ }
+}
+
+
+VOID
+dbgDumpPciCommonConfig(
+ IN PPCI_COMMON_CONFIG PciCommonConfig
+ )
+/*++
+
+Routine Description:
+
+ This routine will dump the PCI config header.
+
+Arguments:
+
+ PciCommonConfig - Pointer to memory block that contains the PCI header.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UINT c;
+
+ if ((DBG_LEVEL_INFO >= gAic5900DebugLevel) &&
+ ((gAic5900DebugSystems & DBG_COMP_INIT) == DBG_COMP_INIT))
+ {
+ //
+ // Display the PCI config info.
+ //
+ DbgPrint("PCI->VendorID = 0x%x\n", PciCommonConfig->VendorID);
+ DbgPrint("PCI->DeviceID = 0x%x\n", PciCommonConfig->DeviceID);
+ DbgPrint("PCI->Command = 0x%x\n", PciCommonConfig->Command);
+ DbgPrint("PCI->Status = 0x%x\n", PciCommonConfig->Status);
+ DbgPrint("PCI->RevisionID = 0x%x\n", PciCommonConfig->RevisionID);
+ DbgPrint("PCI->ProgIf = 0x%x\n", PciCommonConfig->ProgIf);
+ DbgPrint("PCI->SubClass = 0x%x\n", PciCommonConfig->SubClass);
+ DbgPrint("PCI->BaseClass = 0x%x\n", PciCommonConfig->BaseClass);
+ DbgPrint("PCI->CacheLineSize = 0x%x\n", PciCommonConfig->CacheLineSize);
+ DbgPrint("PCI->LatencyTimer = 0x%x\n", PciCommonConfig->LatencyTimer);
+ DbgPrint("PCI->HeaderType = 0x%x\n", PciCommonConfig->HeaderType);
+ DbgPrint("PCI->BIST = 0x%x\n", PciCommonConfig->BIST);
+
+ for (c = 0; c < PCI_TYPE0_ADDRESSES; c++)
+ {
+ DbgPrint("PCI->BaseAddresses[%u] = 0x%x\n", c, PciCommonConfig->u.type0.BaseAddresses[c]);
+ }
+
+ DbgPrint("PCI->SubVendorID = 0x%x\n", PciCommonConfig->u.type0.SubVendorID);
+ DbgPrint("PCI->SubSystemID = 0x%x\n", PciCommonConfig->u.type0.SubSystemID);
+
+ DbgPrint("PCI->ROMBaseAddress = 0x%x\n", PciCommonConfig->u.type0.ROMBaseAddress);
+ DbgPrint("PCI->Reserved2.1 = 0x%x\n", PciCommonConfig->u.type0.Reserved2[0]);
+ DbgPrint("PCI->Reserved2.2 = 0x%x\n", PciCommonConfig->u.type0.Reserved2[1]);
+ DbgPrint("PCI->InterruptLine = 0x%x\n", PciCommonConfig->u.type0.InterruptLine);
+ DbgPrint("PCI->InterruptPin = 0x%x\n", PciCommonConfig->u.type0.InterruptPin);
+ DbgPrint("PCI->MinimumGrant = 0x%x\n", PciCommonConfig->u.type0.MinimumGrant);
+ DbgPrint("PCI->MaximumLatency = 0x%x\n", PciCommonConfig->u.type0.MaximumLatency);
+ }
+}
+
+
+#endif
diff --git a/private/ntos/ndis/aic5900/debug.h b/private/ntos/ndis/aic5900/debug.h
new file mode 100644
index 000000000..c66b0ff86
--- /dev/null
+++ b/private/ntos/ndis/aic5900/debug.h
@@ -0,0 +1,106 @@
+
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ D:\nt\private\ntos\ndis\aic5900\debug.h
+
+Abstract:
+
+Author:
+
+ Kyle Brandon (KyleB)
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#ifndef __DEBUG_H
+#define __DEBUG_H
+
+#define DBG_LEVEL_INFO 0x0000
+#define DBG_LEVEL_LOG 0x0800
+#define DBG_LEVEL_WARN 0x1000
+#define DBG_LEVEL_ERR 0x2000
+#define DBG_LEVEL_FATAL 0x3000
+
+#define DBG_COMP_INIT 0x00000001
+#define DBG_COMP_SEND 0x00000002
+#define DBG_COMP_RECV 0x00000004
+#define DBG_COMP_REQUEST 0x00000008
+#define DBG_COMP_UNLOAD 0x00000010
+#define DBG_COMP_LOCKS 0x00000020
+#define DBG_COMP_VC 0x00000040
+
+#define DBG_COMP_ALL 0xFFFFFFFF
+
+#if DBG
+
+VOID
+dbgDumpHardwareInformation(
+ IN PHARDWARE_INFO HwInfo
+ );
+
+VOID
+dbgDumpPciFCodeImage(
+ IN PPCI_FCODE_IMAGE PciFcodeImage
+ );
+
+VOID
+dbgDumpPciCommonConfig(
+ IN PPCI_COMMON_CONFIG PciCommonConfig
+ );
+
+VOID
+dbgInitializeDebugInformation(
+ IN PADAPTER_BLOCK pAdapter
+ );
+
+extern ULONG gAic5900DebugSystems;
+extern LONG gAic5900DebugLevel;
+extern ULONG gAic5900DebugInformationOffset;
+
+#define DBGPRINT(Component, Level, Fmt) \
+{ \
+ if ((Level >= gAic5900DebugLevel) && \
+ ((gAic5900DebugSystems & Component) == Component)) \
+ { \
+ DbgPrint("***AIC5900*** (%x, %d) ", \
+ MODULE_NUMBER >> 16, __LINE__); \
+ DbgPrint Fmt; \
+ } \
+}
+
+#define DBGBREAK(Component, Level) \
+{ \
+ if ((Level >= gAic5900DebugLevel) && (gAic5900DebugSystems & Component)) \
+ { \
+ DbgPrint("***AIC5900*** DbgBreak @ %x, %d", MODULE_NUMBER, __LINE__); \
+ DbgBreakPoint(); \
+ } \
+}
+
+#define IF_DBG(Component, Level) if ((Level >= gAic5900DebugLevel) && (gAic5900DebugSystems & Component))
+
+#else
+
+#define dbgDumpHardwareInformation(HwInfo)
+#define dbgDumpPciFCodeImage(PciFcodeImage)
+#define dbgDumpPciCommonConfig(_PciCommonConfig)
+
+#define dbgInitializeDebugInformation(_Adapter)
+
+#define DBGPRINT(Component, Level, Fmt)
+#define DBGBREAK(Component, Level)
+
+#define IF_DBG(Component, Level) if (FALSE)
+
+#endif
+
+#endif // __DEBUG_H
diff --git a/private/ntos/ndis/aic5900/dirs b/private/ntos/ndis/aic5900/dirs
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/private/ntos/ndis/aic5900/dirs
diff --git a/private/ntos/ndis/aic5900/eeprom.h b/private/ntos/ndis/aic5900/eeprom.h
new file mode 100644
index 000000000..35dfbd1b0
--- /dev/null
+++ b/private/ntos/ndis/aic5900/eeprom.h
@@ -0,0 +1,174 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ D:\nt\private\ntos\ndis\aic5900\eeprom.h
+
+Abstract:
+
+ AIC5900 PCI EEPROM information.
+
+Author:
+
+ Kyle Brandon (KyleB)
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#ifndef __EEPROM_H
+#define __EEPROM_H
+
+#define EEPROM_READ_BUFFER(pDst, pSrc, Length) \
+{ \
+ UINT _c; \
+ \
+ for (_c = 0; _c < Length; _c++) \
+ { \
+ NdisReadRegisterUchar((PUCHAR)(pSrc) + _c, (PUCHAR)(pDst) + _c); \
+ } \
+}
+
+#define EEPROM_READ_UCHAR(Src, Dst) NdisReadRegisterUchar((Src), (Dst))
+
+#define EEPROM_READ_ULONG(Src, Dst) \
+{ \
+ NdisReadRegisterUchar((PUCHAR)(Src) + 0, (PUCHAR)(Dst) + 3); \
+ NdisReadRegisterUchar((PUCHAR)(Src) + 1, (PUCHAR)(Dst) + 2); \
+ NdisReadRegisterUchar((PUCHAR)(Src) + 2, (PUCHAR)(Dst) + 1); \
+ NdisReadRegisterUchar((PUCHAR)(Src) + 3, (PUCHAR)(Dst) + 0); \
+}
+
+#define AIC_ULONG_TO_ULONG(Dst, Src) \
+{ \
+ *((PUCHAR)(Dst) + 3) = *((PUCHAR)(Src) + 0); \
+ *((PUCHAR)(Dst) + 2) = *((PUCHAR)(Src) + 1); \
+ *((PUCHAR)(Dst) + 1) = *((PUCHAR)(Src) + 2); \
+ *((PUCHAR)(Dst) + 0) = *((PUCHAR)(Src) + 3); \
+}
+
+
+//
+// EEPROM manufacturer structure.
+//
+typedef struct EEPROM_MANUFACTURER_INFO
+{
+ UCHAR MacAddress[6];
+ UCHAR InverseMacAddress[6];
+ UCHAR Padding[52];
+}
+ EEPROM_MANUFACTURER_INFO,
+ *PEEPROM_MANUFACTURER_INFO;
+
+
+
+//
+// BUGBUG: Remove this structure if i don't use it anywhere.
+//
+// Structure definitions
+//
+typedef struct PCI_ROM_BIOS_HEADER
+{
+ UCHAR PciBiosSignature[2]; // Literal 0x55AA
+ UCHAR PciFCodeOffset[2]; // Offset from the begining of
+ // this header to where the FCode
+ // image starts. This item is
+ // storred as little endian
+ UCHAR Reserved[18]; // PCI forum reserved space
+ UCHAR PciDataOffset[2]; // Offset from the begining of
+ // this header to where the PCI
+ // data structure image starts.
+ // This item is storred as
+ // little endian.
+}
+ PCI_ROM_BIOS_HEADER,
+ *PPCI_ROM_BIOS_HEADER;
+
+
+#define FCODE_NAME ((ULONG)'atmo')
+
+//
+// Offsets into the PCI_FCODE_IMAGE.
+//
+#define FCODE_HEADER_LEN 0x08 // FCode tokenizer crates this header
+#define NAME_STRING_OFFSET 0x100 // pascal string at this offset
+#define MODEL_STRING_OFFSET 0x180 // pascal string at this offset
+#define INTERUPT_NUM_OFFSET 0x200 // 32-bit number at this offset
+#define VERSION_NUM_OFFSET 0x280 // pascal string at this offset
+#define VERSION_STRING_OFFSET 0x300 // pascal string at this offset
+#define DATE_STRING_OFFSET 0x380 // pascal string at this offset
+
+#define EEPROM_R_ADDR_OFFSET 0x400 // 32-bit number at this offset
+#define EEPROM_R_SIZE_OFFSET 0x40C // 32-bit number at this offset
+
+#define EEPROM_RW_ADDR_OFFSET 0x420 // 32-bit number at this offset
+#define EEPROM_RW_SIZE_OFFSET 0x42C // 32-bit number at this offset
+
+#define PHY_REGS_ADDR_OFFSET 0x440 // 32-bit number at this offset
+#define PHY_REGS_SIZE_OFFSET 0x44C // 32-bit number at this offset
+
+#define EXTERN_REGS_ADDR_OFFSET 0x460 // 32-bit number at this offset
+#define EXTERN_REGS_SIZE_OFFSET 0x46C // 32-bit number at this offset
+
+#define ORION_SAR_REGS_ADDR_OFFSET 0x480 // 32-bit number at this offset
+#define ORION_SAR_REGS_SIZE_OFFSET 0x48C // 32-bit number at this offset
+
+#define ORION_PCI_REGS_ADDR_OFFSET 0x4A0 // 32-bit number at this offset
+#define ORION_PCI_REGS_SIZE_OFFSET 0x4AC // 32-bit number at this offset
+
+#define SRAM_ADDR_OFFSET 0x4C0 // 32-bit number at this offset
+#define SRAM_SIZE_OFFSET 0x4CC // 32-bit number at this offset
+
+#define FCODE_SIZE 0x64B
+
+//
+// Format of the PCI FCode.
+//
+typedef struct PCI_FCODE_IMAGE
+{
+ UCHAR FCodeHeader[NAME_STRING_OFFSET];
+
+ UCHAR Name[MODEL_STRING_OFFSET - NAME_STRING_OFFSET];
+
+ UCHAR Model[INTERUPT_NUM_OFFSET - MODEL_STRING_OFFSET];
+
+ UCHAR Intr[VERSION_NUM_OFFSET - INTERUPT_NUM_OFFSET];
+
+ UCHAR RomVersionNumber[VERSION_STRING_OFFSET - VERSION_NUM_OFFSET];
+
+ UCHAR RomVersionString[DATE_STRING_OFFSET - VERSION_STRING_OFFSET];
+
+ UCHAR RomDateString[EEPROM_R_ADDR_OFFSET - DATE_STRING_OFFSET];
+
+ UCHAR roEpromOffset[EEPROM_R_SIZE_OFFSET - EEPROM_R_ADDR_OFFSET];
+ UCHAR roEpromSize[EEPROM_RW_ADDR_OFFSET - EEPROM_R_SIZE_OFFSET];
+
+ UCHAR rwEpromOffset[EEPROM_RW_SIZE_OFFSET - EEPROM_RW_ADDR_OFFSET];
+ UCHAR rwEpromSize[PHY_REGS_ADDR_OFFSET - EEPROM_RW_SIZE_OFFSET];
+
+ UCHAR PhyOffset[PHY_REGS_SIZE_OFFSET - PHY_REGS_ADDR_OFFSET];
+ UCHAR PhySize[EXTERN_REGS_ADDR_OFFSET - PHY_REGS_SIZE_OFFSET];
+
+ UCHAR ExternalOffset[EXTERN_REGS_SIZE_OFFSET - EXTERN_REGS_ADDR_OFFSET];
+ UCHAR ExternalSize[ORION_SAR_REGS_ADDR_OFFSET - EXTERN_REGS_SIZE_OFFSET];
+
+ UCHAR SarOffset[ORION_SAR_REGS_SIZE_OFFSET - ORION_SAR_REGS_ADDR_OFFSET];
+ UCHAR SarSize[ORION_PCI_REGS_ADDR_OFFSET - ORION_SAR_REGS_SIZE_OFFSET];
+
+ UCHAR PciConfigOffset[ORION_PCI_REGS_SIZE_OFFSET - ORION_PCI_REGS_ADDR_OFFSET];
+ UCHAR PciConfigSize[SRAM_ADDR_OFFSET - ORION_PCI_REGS_SIZE_OFFSET];
+
+ UCHAR SarMemOffset[SRAM_SIZE_OFFSET - SRAM_ADDR_OFFSET];
+ UCHAR SarMemSize[FCODE_SIZE - SRAM_SIZE_OFFSET];
+}
+ PCI_FCODE_IMAGE,
+ *PPCI_FCODE_IMAGE;
+
+
+#endif // __EEPROM_H
diff --git a/private/ntos/ndis/aic5900/hw.h b/private/ntos/ndis/aic5900/hw.h
new file mode 100644
index 000000000..6347266e9
--- /dev/null
+++ b/private/ntos/ndis/aic5900/hw.h
@@ -0,0 +1,502 @@
+
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ D:\nt\private\ntos\ndis\aic5900\hw.h
+
+Abstract:
+
+Author:
+
+ Kyle Brandon (KyleB)
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#ifndef __HW_H
+#define __HW_H
+
+//
+// New types and forward pointers...
+//
+typedef struct _HARDWARE_INFO HARDWARE_INFO, *PHARDWARE_INFO;
+typedef struct _ADAPTER_BLOCK ADAPTER_BLOCK, *PADAPTER_BLOCK;
+typedef struct _VC_BLOCK VC_BLOCK, *PVC_BLOCK;
+
+typedef struct _XMIT_SEG_CHANNEL XMIT_SEG_CHANNEL, *PXMIT_SEG_CHANNEL;
+typedef struct _SAR_INFO SAR_INFO, *PSAR_INFO;
+
+typedef struct _MIDWAY_XMIT_REGISTERS MIDWAY_XMIT_REGISTERS, *PMIDWAY_XMIT_REGISTERS;
+typedef struct _MIDWAY_REGISTERS MIDWAY_REGISTERS, *PMIDWAY_REGISTERS;
+
+typedef volatile ULONG HWUL, *PHWUL;
+typedef volatile UCHAR HWUC, *PHWUC;
+
+#define BIT(x) (1 << (x))
+
+
+//
+// VC range supported by the aic5900
+//
+#define MAX_VCS 1024
+#define MIN_VCS 0
+
+//
+// NIC Cell clock rate.
+//
+//
+//
+#define CELL_CLOCK_25MHZ (25000000)
+#define CELL_CLOCK_16MHZ (16000000)
+
+//
+// PCI id's
+//
+#define ADAPTEC_PCI_VENDOR_ID 0x9004
+#define AIC5900_PCI_DEVICE_ID 0x5900
+
+//
+// Adaptec ATM adapter models supported.
+//
+#define ANA_5910 5
+#define ANA_5930 7
+#define ANA_5940 8
+
+#define ANA_INVALID (UINT)-1
+
+
+//
+//
+//
+//
+#define ATM_ADDRESS_LENGTH 6
+
+#define PCI_DEVICE_SPECIFIC_OFFSET 0x40
+
+typedef union _PCI_DEVICE_CONFIG
+{
+ struct
+ {
+ UCHAR SoftwareReset:1;
+ UCHAR EnableInterrupt:1;
+ UCHAR TargetSwapBytes:1;
+ UCHAR MasterSwapBytes:1;
+ UCHAR EnableIncrement:1;
+ UCHAR SoftwareInterrupt:1;
+ UCHAR TestDMA:1;
+ UCHAR Reserved:1;
+ };
+
+ UCHAR reg;
+}
+ PCI_DEVICE_CONFIG,
+ *PPCI_DEVICE_CONFIG;
+
+typedef union _PCI_DEVICE_STATUS
+{
+ struct
+ {
+ UCHAR VoltageSense:1;
+ UCHAR IllegalByteEnable:1;
+ UCHAR IllegalWrite:1;
+ UCHAR IllegalOverlap:1;
+ UCHAR IllegalDescriptor:1;
+ UCHAR Reserved:3;
+ };
+
+ UCHAR reg;
+}
+ PCI_DEVICE_STATUS,
+ *PPCI_DEVICE_STATUS;
+
+typedef union _PCI_DEVICE_INTERRUPT_STATUS
+{
+ struct
+ {
+ UCHAR DprInt:1;
+ UCHAR reserved:2;
+ UCHAR StaInt:1;
+ UCHAR RtaInt:1;
+ UCHAR RmaInt:1;
+ UCHAR SseInt:1;
+ UCHAR DpeInt:1;
+ };
+
+ UCHAR reg;
+}
+ PCI_DEVICE_INTERRUPT_STATUS,
+ *PPCI_DEVICE_INTERRUPT_STATUS;
+
+typedef union _PCI_DEVICE_ENABLE_PCI_INTERRUPT
+{
+ struct
+ {
+ UCHAR EnableDprInt:1;
+ UCHAR reserved:2;
+ UCHAR EnableStaInt:1;
+ UCHAR EnableRtaInt:1;
+ UCHAR EnableRmaInt:1;
+ UCHAR EnableSseInt:1;
+ UCHAR EnableDpeInt:1;
+ };
+
+ UCHAR reg;
+}
+ PCI_DEVICE_ENABLE_PCI_INTERRUPT,
+ *PPCI_DEVICE_ENABLE_PCI_INTERRUPT;
+
+typedef union _PCI_DEVICE_GENERAL_PURPOSE_IO_REGISTERS
+{
+ struct
+ {
+ UCHAR GPIOREG0:1;
+ UCHAR GPIOREG1:1;
+ UCHAR GPIOREG2:1;
+ UCHAR GPIOREG3:1;
+ UCHAR reserved:4;
+ };
+
+ UCHAR reg;
+}
+ PCI_DEVICE_GENERAL_PURPOSE_IO_REGISTERS,
+ *PPCI_DEVICE_GENERAL_PURPOSE_IO_REGISTERS;
+
+typedef union _PCI_DEVICE_GENERAL_PURPOSE_IOCTL
+{
+ struct
+ {
+ UCHAR GPIOCTL0:1;
+ UCHAR GPIOCTL1:1;
+ UCHAR GPIOCTL2:1;
+ UCHAR GPIOCTL3:1;
+ UCHAR reserved:4;
+ };
+
+ UCHAR reg;
+}
+ PCI_DEVICE_GENERAL_PURPOSE_IOCTL,
+ *PPCI_DEVICE_GENERAL_PURPOSE_IOCTL;
+
+typedef union _PCI_DEVICE_DMA_CONTROL
+{
+ struct
+ {
+ UCHAR StopOnPerr:1;
+ UCHAR DualAddressCycleEnable:1;
+ UCHAR CacheThresholdEnable:1;
+ UCHAR MemoryReadCmdEnable:1;
+ UCHAR Reserved:4;
+ };
+
+ UCHAR reg;
+}
+ PCI_DEVICE_DMA_CONTROL,
+ *PPCI_DEVICE_DMA_CONTROL;
+
+typedef union _PCI_DEVICE_DMA_STATUS
+{
+ struct
+ {
+ UCHAR FifoEmpty:1;
+ UCHAR FifoFull:1;
+ UCHAR FifoThreshold:1;
+ UCHAR HostDmaDone:1;
+ UCHAR FifoCacheThreshold:1;
+ UCHAR Reserved:3;
+ };
+
+ UCHAR reg;
+}
+ PCI_DEVICE_DMA_STATUS,
+ *PPCI_DEVICE_DMA_STATUS;
+
+typedef union _PCI_DEVICE_DMA_DIAG
+{
+ struct
+ {
+ UCHAR HostDmaEnable:1;
+ UCHAR DataPathDirection:1;
+ UCHAR Reserved:6;
+ };
+
+ UCHAR reg;
+}
+ PCI_DEVICE_DMA_DIAG,
+ *PPCI_DEVICE_DMA_DIAG;
+
+typedef union _PCI_DEVICE_HOST_COUNT
+{
+ struct
+ {
+ ULONG hcLowLow:8;
+ ULONG hcLowHigh:8;
+ ULONG hcHighLow:8;
+ ULONG Reserved:8;
+ };
+
+ ULONG reg;
+}
+ PCI_DEVICE_HOST_COUNT,
+ *PPCI_DEVICE_HOST_COUNT;
+
+typedef union _PCI_DEVICE_DATA_FIFO_READ_ADDRESS
+{
+ struct
+ {
+ UCHAR MasterFifoPointer:7;
+ UCHAR Reserved:1;
+ };
+
+ UCHAR reg;
+}
+ PCI_DEVICE_DATA_FIFO_READ_ADDRESS,
+ *PPCI_DEVICE_DATA_FIFO_READ_ADDRESS;
+
+typedef union _PCI_DEVICE_DATA_FIFO_WRITE_ADDRESS
+{
+ struct
+ {
+ UCHAR MasterFifoPointer:7;
+ UCHAR Reserved:1;
+ };
+
+ UCHAR reg;
+}
+ PCI_DEVICE_DATA_FIFO_WRITE_ADDRESS,
+ *PPCI_DEVICE_DATA_FIFO_WRITE_ADDRESS;
+
+typedef union _PCI_DEVICE_DATA_FIFO_THRESHOLD
+{
+ struct
+ {
+ UCHAR Reserved0:2;
+ UCHAR DFTHRSH:4;
+ UCHAR Reserved1:2;
+ };
+
+ UCHAR reg;
+}
+ PCI_DEVICE_DATA_FIFO_THRESHOLD,
+ *PPCI_DEVICE_DATA_FIFO_THRESHOLD;
+
+typedef union _PCI_DEVICE_LOW_HOST_ADDRESS
+{
+ struct
+ {
+ UCHAR lhaLowLow;
+ UCHAR lhaLowHigh;
+ UCHAR lhaHighLow;
+ UCHAR lhaHighHigh;
+ };
+
+ ULONG reg;
+}
+ PCI_DEVICE_LOW_HOST_ADDRESS,
+ *PPCI_DEVICE_LOW_HOST_ADDRESS;
+
+typedef union _PCI_DEVICE_HIGH_HOST_ADDRESS
+{
+ struct
+ {
+ ULONG hhaLowLow:8;
+ ULONG hhaLowHigh:8;
+ ULONG hhaHighLow:8;
+ ULONG hhaHighHigh:8;
+ };
+
+ ULONG reg;
+}
+ PCI_DEVICE_HIGH_HOST_ADDRESS,
+ *PPCI_DEVICE_HIGH_HOST_ADDRESS;
+
+typedef union _PCI_DEVICE_FIFO_DATA_REGISTER
+{
+ struct
+ {
+ ULONG dfrLowLow:8;
+ ULONG dfrLowHigh:8;
+ ULONG dfrHighLow:8;
+ ULONG dfrHighHigh:8;
+ };
+
+ ULONG reg;
+}
+ PCI_DEVICE_FIFO_DATA_REGISTER,
+ *PPCI_DEVICE_FIFO_DATA_REGISTER;
+
+typedef union _PCI_DEVICE_DATA_ADDRESS
+{
+ struct
+ {
+ ULONG daLowLow:8;
+ ULONG daLowHigh:8;
+ ULONG daHighLow:8;
+ ULONG daHighHigh:8;
+ };
+
+ ULONG reg;
+}
+ PCI_DEVICE_DATA_ADDRESS,
+ *PPCI_DEVICE_DATA_ADDRESS;
+
+typedef union _PCI_DEVICE_DATA_PORT
+{
+ struct
+ {
+ ULONG dpLowLow:8;
+ ULONG dpLowHigh:8;
+ ULONG dpHighLow:8;
+ ULONG dpHighHigh:8;
+ };
+
+ ULONG reg;
+}
+ PCI_DEVICE_DATA_PORT,
+ *PPCI_DEVICE_DATA_PORT;
+
+#define PCI_DEVICE_CONFIG_OFFSET 0x40
+#define PCI_DEVICE_STATUS_OFFSET 0x41
+#define PCI_INTERRUPT_STATUS_OFFSET 0x44
+#define PCI_ENABLE_INTERRUPT_OFFSET 0x45
+#define PCI_GENERAL_PURPOSE_IO_PORT_OFFSET 0x46
+#define PCI_GENERAL_PURPOSE_IOCTL_OFFSET 0x47
+#define PCI_DMA_CONTROL_OFFSET 0x4C
+#define PCI_DMA_STATUS_OFFSET 0x4D
+#define PCI_DMA_DIAGNOSTIC_OFFSET 0x4E
+#define PCI_HOST_COUNT0_OFFSET 0x50
+#define PCI_HOST_COUNT1_OFFSET 0x51
+#define PCI_HOST_COUNT2_OFFSET 0x52
+#define PCI_DATA_FIFO_READ_ADDRESS_OFFSET 0x54
+#define PCI_DATA_FIFO_WRITE_ADDRESS_OFFSET 0x55
+#define PCI_DATA_FIFO_THRESHOLD_OFFSET 0x56
+#define PCI_LOW_HOST_ADDRESS0_OFFSET 0x58
+#define PCI_LOW_HOST_ADDRESS1_OFFSET 0x59
+#define PCI_LOW_HOST_ADDRESS2_OFFSET 0x5A
+#define PCI_LOW_HOST_ADDRESS3_OFFSET 0x5B
+#define PCI_HIGH_HOST_ADDRESS0_OFFSET 0x5C
+#define PCI_HIGH_HOST_ADDRESS1_OFFSET 0x5D
+#define PCI_HIGH_HOST_ADDRESS2_OFFSET 0x5E
+#define PCI_HIGH_HOST_ADDRESS3_OFFSET 0x5F
+#define PCI_FIFO_DATA_REGISTER0_OFFSET 0x60
+#define PCI_FIFO_DATA_REGISTER1_OFFSET 0x61
+#define PCI_FIFO_DATA_REGISTER2_OFFSET 0x62
+#define PCI_FIFO_DATA_REGISTER3_OFFSET 0x63
+
+
+#define SET_PCI_DEV_CFG(_HwInfo, _reg) NdisWriteRegisterUchar(((_HwInfo)->PciConfigSpace + PCI_DEVICE_CONFIG_OFFSET), (_reg))
+#define GET_PCI_DEV_CFG(_HwInfo, _reg) NdisReadRegisterUchar(((_HwInfo)->PciConfigSpace + PCI_DEVICE_CONFIG_OFFSET), (PUCHAR)(_reg))
+
+
+#define SET_PCI_DEV_STATUS(_HwInfo, _reg) NdisWriteRegisterUchar(((_HwInfo)->PciConfigSpace + PCI_DEVICE_STATUS_OFFSET), (_reg))
+#define GET_PCI_DEV_STATUS(_HwInfo, _reg) NdisReadRegisterUchar(((_HwInfo)->PciConfigSpace + PCI_DEVICE_STATUS_OFFSET), (PUCHAR)(_reg))
+
+#define SET_PCI_DEV_INT_STATUS(_HwInfo, _reg) NdisWriteRegisterUchar(((_HwInfo)->PciConfigSpace + PCI_INTERRUPT_STATUS_OFFSET), (_reg))
+#define GET_PCI_DEV_INT_STATUS(_HwInfo, _reg) NdisReadRegisterUchar(((_HwInfo)->PciConfigSpace + PCI_INTERRUPT_STATUS_OFFSET), (PUCHAR)(_reg))
+
+#define SET_PCI_DEV_ENABLE_INT(_HwInfo, _reg) NdisWriteRegisterUchar(((_HwInfo)->PciConfigSpace + PCI_ENABLE_INTERRUPT_OFFSET), (_reg))
+#define GET_PCI_DEV_ENABLE_INT(_HwInfo, _reg) NdisReadRegisterUchar(((_HwInfo)->PciConfigSpace + PCI_ENABLE_INTERRUPT_OFFSET), (PUCHAR)(_reg))
+
+
+#define SET_PCI_DEV_GP_IO_REG(_HwInfo, _reg) NdisWriteRegisterUchar(((_HwInfo)->PciConfigSpace + PCI_GENERAL_PURPOSE_IO_PORT_OFFSET), (_reg))
+#define GET_PCI_DEV_GP_IO_REG(_HwInfo, _reg) NdisReadRegisterUchar(((_HwInfo)->PciConfigSpace + PCI_GENERAL_PURPOSE_IO_PORT_OFFSET), (PUCHAR)(_reg))
+
+#define SET_PCI_DEV_GP_IOCTL(_HwInfo, _reg) NdisWriteRegisterUchar(((_HwInfo)->PciConfigSpace + PCI_GENERAL_PURPOSE_IOCTL_OFFSET), (_reg))
+#define GET_PCI_DEV_GP_IOCTL(_HwInfo, _reg) NdisReadRegisterUchar(((_HwInfo)->PciConfigSpace + PCI_GENERAL_PURPOSE_IOCTL_OFFSET), (PUCHAR)(_reg))
+
+#define SET_PCI_DEV_DMA_CONTROL(_HwInfo, _reg) NdisWriteRegisterUchar(((_HwInfo)->PciConfigSpace + PCI_DMA_CONTROL_OFFSET), (_reg))
+#define GET_PCI_DEV_DMA_CONTROL(_HwInfo, _reg) NdisReadRegisterUchar(((_HwInfo)->PciConfigSpace + PCI_DMA_CONTROL_OFFSET), (PUCHAR)(_reg))
+
+#define SET_PCI_DEV_DMA_STATUS(_HwInfo, _reg) NdisWriteRegisterUchar(((_HwInfo)->PciConfigSpace + PCI_DMA_STATUS_OFFSET), (_reg))
+#define GET_PCI_DEV_DMA_STATUS(_HwInfo, _reg) NdisReadRegisterUchar(((_HwInfo)->PciConfigSpace + PCI_DMA_STATUS_OFFSET), (PUCHAR)(_reg))
+
+
+#define SET_PCI_DEV_DMA_DIAG(_HwInfo, _reg) NdisWriteRegisterUchar(((_HwInfo)->PciConfigSpace + PCI_DMA_DIAGNOSTIC_OFFSET), (_reg))
+#define GET_PCI_DEV_DMA_DIAG(_HwInfo, _reg) NdisReadRegisterUchar(((_HwInfo)->PciConfigSpace + PCI_DMA_DIAGNOSTIC_OFFSET), (PUCHAR)(_reg))
+
+#define SET_PCI_DEV_DATA_READ_ADDRESS(_HwInfo, _reg) NdisWriteRegisterUchar(((_HwInfo)->PciConfigSpace + PCI_DATA_FIFO_READ_ADDRESS_OFFSET), (_reg))
+#define GET_PCI_DEV_DATA_READ_ADDRESS(_HwInfo, _reg) NdisReadRegisterUchar(((_HwInfo)->PciConfigSpace + PCI_DATA_FIFO_READ_ADDRESS_OFFSET), (PUCHAR)(_reg))
+
+#define SET_PCI_DEV_DATA_WRITE_ADDRESS(_HwInfo, _reg) NdisWriteRegisterUchar(((_HwInfo)->PciConfigSpace + PCI_DATA_FIFO_WRITE_ADDRESS_OFFSET), (_reg))
+#define GET_PCI_DEV_DATA_WRITE_ADDRESS(_HwInfo, _reg) NdisReadRegisterUchar(((_HwInfo)->PciConfigSpace + PCI_DATA_FIFO_WRITE_ADDRESS_OFFSET), (PUCHAR)(_reg))
+
+#define SET_PCI_DEV_DATA_THRESHOLD(_HwInfo, _reg) NdisWriteRegisterUchar(((_HwInfo)->PciConfigSpace + PCI_DATA_FIFO_THRESHOLD_OFFSET), (_reg))
+#define GET_PCI_DEV_DATA_THRESHOLD(_HwInfo, _reg) NdisReadRegisterUchar(((_HwInfo)->PciConfigSpace + PCI_DATA_FIFO_THRESHOLD_OFFSET), (PUCHAR)(_reg))
+
+
+//////////////////////////////////////////////////////////////////////////
+//
+// SUNI REGISTER SET
+//
+//////////////////////////////////////////////////////////////////////////
+
+//
+// SUNI Master Reset and Identify register.
+//
+#define SUNI_MASTER_RESET_IDENTITY 0x00
+#define SET_SUNI_MASTER_RESET_IDEN(_HwInfo, _value) NdisWriteRegisterUchar(((_HwInfo)->Phy + SUNI_MASTER_RESET_IDENTITY), (_value))
+#define GET_SUNI_MASTER_RESET_IDEN(_HwInfo, _value) NdisReadRegisterUchar(((_HwInfo)->Phy + SUNI_MASTER_RESET_IDENTITY), (_value))
+
+#define fSUNI_MRI_RESET 0x80
+
+//
+// RACP Interrupt Enable/Status
+//
+#define SUNI_RACP_INTERRUPT_ENABLE_STATUS 0x144
+#define SET_SUNI_RACP_INT_ENABLE_STATUS(_HwInfo, _value) NdisWriteRegisterUchar(((_HwInfo)->Phy + SUNI_RACP_INTERRUPT_ENABLE_STATUS), (_value))
+#define GET_SUNI_RACP_INT_ENABLE_STATUS(_HwInfo, _value) NdisReadRegisterUchar(((_HwInfo)->Phy + SUNI_RACP_INTERRUPT_ENABLE_STATUS), (_value))
+
+#define fSUNI_RACP_IES_FUDRI 0x01
+#define fSUNI_RACP_IES_FOVRI 0x02
+#define fSUNI_RACP_IES_UHCSI 0x04
+#define fSUNI_RACP_IES_CHCSI 0x08
+#define fSUNI_RACP_IES_OOCDI 0x10
+#define fSUNI_RACP_IES_FIFOE 0x20
+#define fSUNI_RACP_IES_HCSE 0x40
+#define fSUNI_RACP_IES_OOCDE 0x80
+
+
+//
+// Master Test
+//
+#define SUNI_MASTER_TEST 0x200
+#define SET_SUNI_MASTER_TEST(_HwInfo, _value) NdisWriteRegisterUchar(((_HwInfo)->Phy + SUNI_MASTER_TEST), (_value))
+#define GET_SUNI_MASTER_TEST(_HwInfo, _value) NdisReadRegisterUchar(((_HwInfo)->Phy + SUNI_MASTER_TEST), (_value))
+
+//////////////////////////////////////////////////////////////////////////
+//
+// IBM 25Mbp TC chipset
+//
+//////////////////////////////////////////////////////////////////////////
+
+#define IBM_TC_STATUS 0x00
+#define SET_IBM_TC_STATUS(_HwInfo, _value) NdisWriteRegisterUchar(((_HwInfo)->Phy + IBM_TC_STATUS), (_value))
+#define GET_IBM_TC_STATUS(_HwInfo, _value) NdisReadRegisterUchar(((_HwInfo)->Phy + IBM_TC_STATUS), (_value))
+
+#define IBM_TC_MODE 0x00
+#define SET_IBM_TC_MODE(_HwInfo, _value) NdisWriteRegisterUchar(((_HwInfo)->Phy + IBM_TC_MODE), (_value))
+#define GET_IBM_TC_MODE(_HwInfo, _value) NdisReadRegisterUchar(((_HwInfo)->Phy + IBM_TC_MODE), (_value))
+
+#define IBM_TC_FLUSH_RECEIVE_FIFO 0x00
+#define SET_IBM_TC_FLUSH_RECEIVE_FIFO(_HwInfo, _value) NdisWriteRegisterUchar(((_HwInfo)->Phy + IBM_TC_FLUSH_RECEIVE_FIFO), (_value))
+#define GET_IBM_TC_FLUSH_RECEIVE_FIFO(_HwInfo, _value) NdisReadRegisterUchar(((_HwInfo)->Phy + IBM_TC_FLUSH_RECEIVE_FIFO), (_value))
+
+#define IBM_TC_SOFTWARE_RESET 0x00
+#define SET_IBM_TC_SOFTWARE_RESET(_HwInfo, _value) NdisWriteRegisterUchar(((_HwInfo)->Phy + IBM_TC_SOFTWARE_RESET), (_value))
+#define GET_IBM_TC_SOFTWARE_RESET(_HwInfo, _value) NdisReadRegisterUchar(((_HwInfo)->Phy + IBM_TC_SOFTWARE_RESET), (_value))
+
+#define IBM_TC_MASK 0x00
+#define SET_IBM_TC_MASK(_HwInfo, _value) NdisWriteRegisterUchar(((_HwInfo)->Phy + IBM_TC_MASK), (_value))
+#define GET_IBM_TC_MASK(_HwInfo, _value) NdisReadRegisterUchar(((_HwInfo)->Phy + IBM_TC_MASK), (_value))
+
+
+#endif // __HW_H
+
+
diff --git a/private/ntos/ndis/aic5900/init.c b/private/ntos/ndis/aic5900/init.c
new file mode 100644
index 000000000..5c497d026
--- /dev/null
+++ b/private/ntos/ndis/aic5900/init.c
@@ -0,0 +1,1534 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ D:\nt\private\ntos\ndis\aic5900\init.c
+
+Abstract:
+
+Author:
+
+ Kyle Brandon (KyleB)
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "aic5900.h"
+
+#define MODULE_NUMBER MODULE_INIT
+
+#pragma NDIS_INIT_FUNCTION(DriverEntry)
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+ NDIS_MINIPORT_CHARACTERISTICS Aic5900Chars;
+ NDIS_HANDLE hWrapper;
+
+ //
+ // Initialize the wrapper.
+ //
+ NdisMInitializeWrapper(
+ &hWrapper,
+ DriverObject,
+ RegistryPath,
+ NULL);
+
+ NdisZeroMemory(&Aic5900Chars, sizeof(Aic5900Chars));
+
+ //
+ // Initialize the miniport characteristics.
+ //
+ Aic5900Chars.MajorNdisVersion = AIC5900_NDIS_MAJOR_VERSION;
+ Aic5900Chars.MinorNdisVersion = AIC5900_NDIS_MINOR_VERSION;
+ Aic5900Chars.CheckForHangHandler = Aic5900CheckForHang;
+ Aic5900Chars.DisableInterruptHandler = Aic5900DisableInterrupt;
+ Aic5900Chars.EnableInterruptHandler = Aic5900EnableInterrupt;
+ Aic5900Chars.HaltHandler = Aic5900Halt;
+ Aic5900Chars.HandleInterruptHandler = Aic5900HandleInterrupt;
+ Aic5900Chars.InitializeHandler = Aic5900Initialize;
+ Aic5900Chars.ISRHandler = Aic5900ISR;
+ Aic5900Chars.ReconfigureHandler = NULL;
+ Aic5900Chars.ResetHandler = Aic5900Reset;
+
+ Aic5900Chars.ReturnPacketHandler = Aic5900ReturnPackets;
+ Aic5900Chars.AllocateCompleteHandler = Aic5900AllocateComplete;
+ Aic5900Chars.SetInformationHandler = Aic5900SetInformation;
+ Aic5900Chars.QueryInformationHandler = Aic5900QueryInformation;
+
+ Aic5900Chars.CoSendPacketsHandler = Aic5900SendPackets;
+
+ Aic5900Chars.CoCreateVcHandler = Aic5900CreateVc;
+ Aic5900Chars.CoDeleteVcHandler = Aic5900DeleteVc;
+ Aic5900Chars.CoActivateVcHandler = Aic5900ActivateVc;
+ Aic5900Chars.CoDeactivateVcHandler = Aic5900DeactivateVc;
+ Aic5900Chars.CoRequestHandler = Aic5900Request;
+
+ //
+ // Register the miniport with NDIS.
+ //
+ Status = NdisMRegisterMiniport(
+ hWrapper,
+ &Aic5900Chars,
+ sizeof(Aic5900Chars));
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ //
+ // Save the handle to the wrapper.
+ //
+ gWrapperHandle = hWrapper;
+ }
+#if DBG
+ else
+ {
+ DbgPrint("NdisMRegisterMiniport failed! Status: 0x%x\n", Status);
+ }
+#endif
+
+
+ return(Status);
+}
+
+
+NDIS_STATUS
+aic5900ReadConfigurationInformation(
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PAIC5900_REGISTRY_PARAMETER pRegistryParameter
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+ NDIS_HANDLE ConfigHandle;
+ PNDIS_CONFIGURATION_PARAMETER pConfigParameter;
+ UINT c;
+
+ //
+ // Open the configuration section of the registry for this adapter.
+ //
+ NdisOpenConfiguration(&Status, &ConfigHandle, ConfigurationHandle);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("Unable to open the Aic5900's Parameters registry key\n"));
+
+ return(Status);
+ }
+
+ //
+ // Read in the registry parameters.
+ //
+ for (c = 0; c < Aic5900MaxRegistryEntry; c++)
+ {
+ NdisReadConfiguration(
+ &Status,
+ &pConfigParameter,
+ ConfigHandle,
+ &gaRegistryParameterString[c],
+ NdisParameterHexInteger);
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ pRegistryParameter[c].fPresent = TRUE;
+ pRegistryParameter[c].Value = pConfigParameter->ParameterData.IntegerData;
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
+ ("Read registry parameter: %u = 0x%x\n", c, pRegistryParameter[c].Value));
+ }
+
+ }
+
+ //
+ // Close the configuration handle.
+ //
+ NdisCloseConfiguration(ConfigHandle);
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+aic5900ReadPciConfiguration(
+ IN PADAPTER_BLOCK pAdapter
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PPCI_COMMON_CONFIG PciCommonConfig;
+ PHARDWARE_INFO pHwInfo = pAdapter->HardwareInfo;
+ PNDIS_RESOURCE_LIST ResourceList;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR Resource;
+ NDIS_STATUS Status;
+ UINT c;
+ UINT Temp;
+
+ //
+ // Allocate memory for the pci common config space.
+ //
+ ALLOCATE_MEMORY(
+ &Status,
+ &pHwInfo->PciCommonConfig,
+ PCI_COMMON_HDR_LENGTH);
+ if (NULL == pHwInfo->PciCommonConfig)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("aic5900ReadPciConfiguration() failed to allocate memory for PCI Common Config.\n"));
+
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ PciCommonConfig = pHwInfo->PciCommonConfig;
+
+ //
+ // Read the board id. This is a combination of the vendor id and
+ // the device id.
+ //
+ Temp = NdisReadPciSlotInformation(
+ pAdapter->MiniportAdapterHandle,
+ pHwInfo->SlotNumber,
+ 0,
+ PciCommonConfig,
+ PCI_COMMON_HDR_LENGTH);
+ if (Temp != PCI_COMMON_HDR_LENGTH)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("Unable to read PCI configuration header\n"));
+
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // Verify vendor & device id's.
+ //
+ if ((ADAPTEC_PCI_VENDOR_ID != PciCommonConfig->VendorID) ||
+ (AIC5900_PCI_DEVICE_ID != PciCommonConfig->DeviceID))
+ {
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // Set the command word in pci space.
+ //
+ PciCommonConfig->Command = PCI_ENABLE_MEMORY_SPACE |
+ PCI_ENABLE_BUS_MASTER |
+ PCI_ENABLE_WRITE_AND_INVALIDATE |
+ PCI_ENABLE_SERR;
+
+ NdisWritePciSlotInformation(
+ pAdapter->MiniportAdapterHandle,
+ pHwInfo->SlotNumber,
+ FIELD_OFFSET(PCI_COMMON_CONFIG, Command),
+ &PciCommonConfig->Command,
+ sizeof(PciCommonConfig->Command));
+
+ NdisReadPciSlotInformation(
+ pAdapter->MiniportAdapterHandle,
+ pHwInfo->SlotNumber,
+ 0,
+ PciCommonConfig,
+ PCI_COMMON_HDR_LENGTH);
+
+ PciCommonConfig->u.type0.BaseAddresses[0] &= 0xFFFFFFF0;
+
+ //
+ // For noisy debug dump what we find in the PCI space.
+ //
+ dbgDumpPciCommonConfig(PciCommonConfig);
+
+ //
+ // Assign the pci resources.
+ //
+ Status = NdisMPciAssignResources(
+ pAdapter->MiniportAdapterHandle,
+ pHwInfo->SlotNumber,
+ &ResourceList);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("NdisMPciAssignResoures() failed: 0x%x\n", Status));
+
+ return(Status);
+ }
+
+ //
+ // Walk the resource list to get the adapters configuration
+ // information.
+ //
+ for (c = 0; c < ResourceList->Count; c++)
+ {
+ Resource = &ResourceList->PartialDescriptors[c];
+ switch (Resource->Type)
+ {
+ case CmResourceTypeInterrupt:
+ //
+ // Save the interrupt number with our adapter block.
+ //
+ pHwInfo->InterruptLevel = Resource->u.Interrupt.Level;
+ pHwInfo->InterruptVector = Resource->u.Interrupt.Vector;
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
+ ("Configured to use interrupt Level: %u interrupt vector: %u\n", pHwInfo->InterruptLevel, pHwInfo->InterruptVector));
+
+ break;
+
+ case CmResourceTypeMemory:
+
+ //
+ // Save the memory mapped base physical address and it's length.
+ //
+ pHwInfo->PhysicalIoSpace = Resource->u.Memory.Start;
+ pHwInfo->IoSpaceLength = Resource->u.Memory.Length;
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
+ ("Configured to use mapped memory memory 0x%x:0x%x of length 0x%x\n",
+ NdisGetPhysicalAddressHigh(pHwInfo->PhysicalIoSpace),
+ NdisGetPhysicalAddressLow(pHwInfo->PhysicalIoSpace),
+ pHwInfo->IoSpaceLength));
+
+ break;
+
+ case CmResourceTypePort:
+
+ //
+ // Save the port.
+ //
+ pHwInfo->InitialPort = NdisGetPhysicalAddressLow(Resource->u.Port.Start);
+ pHwInfo->NumberOfPorts = Resource->u.Port.Length;
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
+ ("Configured to use port memory 0x%x of length 0x%x\n",
+ pHwInfo->InitialPort,
+ pHwInfo->NumberOfPorts));
+
+ break;
+ }
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+aic5900GetNicModelNumberFromString(
+ IN PHARDWARE_INFO pHwInfo
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ ULONG NicModel;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ AIC_ULONG_TO_ULONG(&NicModel, (PULONG)(&pHwInfo->FCodeImage->Model[5]));
+
+ //
+ // Compare the second DWORD in the NicModelString
+ //
+ switch (NicModel)
+ {
+ case '5910':
+ pHwInfo->NicModelNumber = ANA_5910;
+
+ //
+ // This is a 25Mbps adapter and has a 16MHz cell clock.
+ //
+ pHwInfo->CellClockRate = CELL_CLOCK_16MHZ;
+
+ break;
+
+ case '5930':
+ pHwInfo->NicModelNumber = ANA_5930;
+
+ //
+ // This is a 155Mbps adapter and has a 25MHz cell clock.
+ //
+ pHwInfo->CellClockRate = CELL_CLOCK_25MHZ;
+
+ break;
+
+ case '5940':
+ pHwInfo->NicModelNumber = ANA_5940;
+
+ //
+ // This is a 155Mbps adapter and has a 25MHz cell clock.
+ //
+ pHwInfo->CellClockRate = CELL_CLOCK_25MHZ;
+
+ break;
+
+ default:
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("Invalid NIC Model String!\n"));
+
+ pHwInfo->NicModelNumber = ANA_INVALID;
+
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ return(Status);
+}
+
+
+NDIS_STATUS
+aic5900ReadEepromInformation(
+ IN PADAPTER_BLOCK pAdapter
+ )
+/*++
+
+Routine Description:
+
+ This routine will map the EEPROM address into memory and read the offsets for the other
+ information that will be needed.
+
+Arguments:
+
+ pAdapter - Pointer to the adapter block to save the information.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if everthing went ok.
+ NDIS_STATUS_FAILURE otherwise.
+
+--*/
+{
+ NDIS_PHYSICAL_ADDRESS PhysicalAddress;
+ NDIS_STATUS Status;
+ PHARDWARE_INFO pHwInfo;
+
+ PPCI_FCODE_IMAGE pFCode;
+ PPCI_FCODE_IMAGE pFCodeImage;
+
+ PUCHAR EepromBase = NULL;
+ UCHAR HighByte;
+ UCHAR LowByte;
+
+ USHORT FCodeImageOffset;
+ ULONG FCodeName;
+
+ do
+ {
+ //
+ // Initialize the hardware info.
+ //
+ pHwInfo = pAdapter->HardwareInfo;
+
+ //
+ // Map the first part of the EEPROM to read the
+ // configuration information.
+ //
+ PhysicalAddress = pHwInfo->PhysicalIoSpace;
+
+ Status = NdisMMapIoSpace(
+ &EepromBase,
+ pAdapter->MiniportAdapterHandle,
+ PhysicalAddress,
+ FCODE_SIZE);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("Failed to map the PCI FCode I/O space into memory\n"));
+ break;
+ }
+
+ //
+ // Get the offset to the Fcode image.
+ //
+ EEPROM_READ_UCHAR(EepromBase + 3, &HighByte);
+ EEPROM_READ_UCHAR(EepromBase + 2, &LowByte);
+ FCodeImageOffset = (USHORT)((HighByte << 8) + LowByte);
+
+ if (0xFFFF == FCodeImageOffset)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("Invalid data read from the EEPROM.\n"));
+ Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+ break;
+ }
+
+ pFCode = (PPCI_FCODE_IMAGE)(EepromBase + FCodeImageOffset);
+
+ ALLOCATE_MEMORY(&Status, &pHwInfo->FCodeImage, FCODE_SIZE);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("Failed to allocate memory for the eeprom image\n"));
+ break;
+ }
+
+ EEPROM_READ_BUFFER(pHwInfo->FCodeImage, pFCode, FCODE_SIZE);
+
+ pFCodeImage = pHwInfo->FCodeImage;
+
+ //
+ // For debug this will get dumped.
+ //
+ dbgDumpPciFCodeImage(pFCodeImage);
+
+ //
+ // Check the name parameter in the fcode image.
+ // We add 1 since this name is in PASCAL format (the first byte
+ // is the length of the string)....
+ //
+ AIC_ULONG_TO_ULONG(&FCodeName, (PULONG)(&pFCodeImage->Name[1]));
+ if (FCodeName != FCODE_NAME)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("Invalid name in FCode Image\n"));
+
+ Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+ break;
+ }
+
+ //
+ // Get the model number for the NIC.
+ //
+ Status = aic5900GetNicModelNumberFromString(pHwInfo);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+ break;
+ }
+
+ //
+ // Get the ROM version number.
+ //
+ AIC_ULONG_TO_ULONG(&pHwInfo->RomVersionNumber, &pFCodeImage->RomVersionNumber);
+
+ //
+ // Get EPROM offset and size and map in.
+ //
+ AIC_ULONG_TO_ULONG(&pHwInfo->rEpromOffset, &pFCodeImage->roEpromOffset);
+ AIC_ULONG_TO_ULONG(&pHwInfo->rEpromSize, &pFCodeImage->roEpromSize);
+
+ NdisSetPhysicalAddressLow(
+ PhysicalAddress,
+ NdisGetPhysicalAddressLow(pHwInfo->PhysicalIoSpace) +
+ pHwInfo->rEpromOffset);
+
+ Status = NdisMMapIoSpace(
+ &pHwInfo->rEprom,
+ pAdapter->MiniportAdapterHandle,
+ PhysicalAddress,
+ pHwInfo->rEpromSize);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ break;
+ }
+
+ //
+ // Get R/W EPROM offset and size and map in.
+ //
+ AIC_ULONG_TO_ULONG(&pHwInfo->rwEpromOffset, &pFCodeImage->rwEpromOffset);
+ AIC_ULONG_TO_ULONG(&pHwInfo->rwEpromSize, &pFCodeImage->rwEpromSize);
+
+ NdisSetPhysicalAddressLow(
+ PhysicalAddress,
+ NdisGetPhysicalAddressLow(pHwInfo->PhysicalIoSpace) +
+ pHwInfo->rwEpromOffset);
+
+ Status = NdisMMapIoSpace(
+ &pHwInfo->rwEprom,
+ pAdapter->MiniportAdapterHandle,
+ PhysicalAddress,
+ pHwInfo->rwEpromSize);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ break;
+ }
+
+ //
+ // Get PHY offset and size and map in.
+ //
+ AIC_ULONG_TO_ULONG(&pHwInfo->PhyOffset, &pFCodeImage->PhyOffset);
+ AIC_ULONG_TO_ULONG(&pHwInfo->PhySize, &pFCodeImage->PhySize);
+
+ NdisSetPhysicalAddressLow(
+ PhysicalAddress,
+ NdisGetPhysicalAddressLow(pHwInfo->PhysicalIoSpace) +
+ pHwInfo->PhyOffset);
+
+ Status = NdisMMapIoSpace(
+ (PVOID *)&pHwInfo->Phy,
+ pAdapter->MiniportAdapterHandle,
+ PhysicalAddress,
+ pHwInfo->PhySize);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ break;
+ }
+
+ //
+ // Get EXTERNAL offset and size and map in.
+ //
+ AIC_ULONG_TO_ULONG(&pHwInfo->ExternalOffset, &pFCodeImage->ExternalOffset);
+ AIC_ULONG_TO_ULONG(&pHwInfo->ExternalSize, &pFCodeImage->ExternalSize);
+
+ NdisSetPhysicalAddressLow(
+ PhysicalAddress,
+ NdisGetPhysicalAddressLow(pHwInfo->PhysicalIoSpace) +
+ pHwInfo->ExternalOffset);
+
+ Status = NdisMMapIoSpace(
+ &pHwInfo->External,
+ pAdapter->MiniportAdapterHandle,
+ PhysicalAddress,
+ pHwInfo->ExternalSize);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ break;
+ }
+
+ //
+ // Get SAR offset and size and map in.
+ //
+ AIC_ULONG_TO_ULONG(&pHwInfo->MidwayOffset, &pFCodeImage->SarOffset);
+ AIC_ULONG_TO_ULONG(&pHwInfo->MidwaySize, &pFCodeImage->SarSize);
+
+ NdisSetPhysicalAddressLow(
+ PhysicalAddress,
+ NdisGetPhysicalAddressLow(pHwInfo->PhysicalIoSpace) +
+ pHwInfo->MidwayOffset);
+
+ Status = NdisMMapIoSpace(
+ (PVOID *)&pHwInfo->Midway,
+ pAdapter->MiniportAdapterHandle,
+ PhysicalAddress,
+ pHwInfo->MidwaySize);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ break;
+ }
+
+ //
+ // Get PCI Config offset and size and map in.
+ //
+ AIC_ULONG_TO_ULONG(&pHwInfo->PciCfgOffset, &pFCodeImage->PciConfigOffset);
+ AIC_ULONG_TO_ULONG(&pHwInfo->PciCfgSize, &pFCodeImage->PciConfigSize);
+
+ NdisSetPhysicalAddressLow(
+ PhysicalAddress,
+ NdisGetPhysicalAddressLow(pHwInfo->PhysicalIoSpace) +
+ pHwInfo->PciCfgOffset);
+
+ Status = NdisMMapIoSpace(
+ (PVOID *)&pHwInfo->PciConfigSpace,
+ pAdapter->MiniportAdapterHandle,
+ PhysicalAddress,
+ pHwInfo->PciCfgSize);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ break;
+ }
+
+ //
+ // Get SAR RAM offset and size and map in.
+ //
+ AIC_ULONG_TO_ULONG(&pHwInfo->SarRamOffset, &pFCodeImage->SarMemOffset);
+ AIC_ULONG_TO_ULONG(&pHwInfo->SarRamSize, &pFCodeImage->SarMemSize);
+
+ NdisSetPhysicalAddressLow(
+ PhysicalAddress,
+ NdisGetPhysicalAddressLow(pHwInfo->PhysicalIoSpace) +
+ pHwInfo->SarRamOffset);
+
+ Status = NdisMMapIoSpace(
+ (PVOID *)&pHwInfo->SarRam,
+ pAdapter->MiniportAdapterHandle,
+ PhysicalAddress,
+ pHwInfo->SarRamSize);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ break;
+ }
+
+ //
+ // Read in the manufacturer address for the nic.
+ //
+ EEPROM_READ_BUFFER(
+ pHwInfo->PermanentAddress,
+ (((PUCHAR)pHwInfo->rEprom) + pHwInfo->rEpromSize) - sizeof(EEPROM_MANUFACTURER_INFO),
+ ATM_ADDRESS_LENGTH);
+
+ //
+ // Save the permanent address in the station address by default.
+ //
+ NdisMoveMemory(
+ pHwInfo->StationAddress,
+ pHwInfo->PermanentAddress,
+ ATM_ADDRESS_LENGTH);
+
+ dbgDumpHardwareInformation(pHwInfo);
+ } while (FALSE);
+
+ if (EepromBase != NULL)
+ {
+ NdisMUnmapIoSpace(
+ pAdapter->MiniportAdapterHandle,
+ (PVOID)EepromBase,
+ FCODE_SIZE);
+ }
+
+ return(Status);
+}
+
+VOID
+aic5900FreeResources(
+ IN PADAPTER_BLOCK pAdapter
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PHARDWARE_INFO pHwInfo;
+ PVC_BLOCK pVc;
+ PLIST_ENTRY Link;
+
+ if (NULL != pAdapter)
+ {
+ if (NULL != pAdapter->HardwareInfo)
+ {
+ pHwInfo = pAdapter->HardwareInfo;
+
+ if (NULL != pHwInfo->PciCommonConfig)
+ {
+ FREE_MEMORY(pHwInfo->PciCommonConfig, PCI_COMMON_HDR_LENGTH);
+ }
+
+ if (NULL != pHwInfo->PortOffset)
+ {
+ NdisMDeregisterIoPortRange(
+ pAdapter->MiniportAdapterHandle,
+ pHwInfo->InitialPort,
+ pHwInfo->NumberOfPorts,
+ pHwInfo->PortOffset);
+ }
+
+ if (NULL != pHwInfo->rEprom)
+ {
+ NdisMUnmapIoSpace(
+ pAdapter->MiniportAdapterHandle,
+ pHwInfo->rEprom,
+ pHwInfo->rEpromSize);
+ }
+
+ if (NULL != pHwInfo->rwEprom)
+ {
+ NdisMUnmapIoSpace(
+ pAdapter->MiniportAdapterHandle,
+ pHwInfo->rwEprom,
+ pHwInfo->rwEpromSize);
+ }
+
+ if (NULL != pHwInfo->Phy)
+ {
+ NdisMUnmapIoSpace(
+ pAdapter->MiniportAdapterHandle,
+ pHwInfo->Phy,
+ pHwInfo->PhySize);
+ }
+
+ if (NULL != pHwInfo->External)
+ {
+ NdisMUnmapIoSpace(
+ pAdapter->MiniportAdapterHandle,
+ pHwInfo->External,
+ pHwInfo->ExternalSize);
+ }
+
+ if (NULL != pHwInfo->Midway)
+ {
+ NdisMUnmapIoSpace(
+ pAdapter->MiniportAdapterHandle,
+ pHwInfo->Midway,
+ pHwInfo->MidwaySize);
+ }
+
+ if (NULL != pHwInfo->PciConfigSpace)
+ {
+ NdisMUnmapIoSpace(
+ pAdapter->MiniportAdapterHandle,
+ pHwInfo->PciConfigSpace,
+ pHwInfo->PciCfgSize);
+ }
+
+ if (NULL != pHwInfo->SarRam)
+ {
+ NdisMUnmapIoSpace(
+ pAdapter->MiniportAdapterHandle,
+ (PVOID)pHwInfo->SarRam,
+ pHwInfo->SarRamSize);
+ }
+
+ if (NULL != pHwInfo->FCodeImage)
+ {
+ FREE_MEMORY(pHwInfo->FCodeImage, FCODE_SIZE);
+ }
+
+ if (HW_TEST_FLAG(pHwInfo, fHARDWARE_INFO_INTERRUPT_REGISTERED))
+ {
+ NdisMDeregisterInterrupt(&pHwInfo->Interrupt);
+ }
+
+ //
+ // Free the spin lock for the hardware information.
+ //
+ NdisFreeSpinLock(&pHwInfo->Lock);
+
+ //
+ // Free the memory used for the hardware information.
+ //
+ FREE_MEMORY(pHwInfo, sizeof(HARDWARE_INFO));
+ }
+
+ ///
+ // Clean up our list of active VCs.
+ ///
+ while (!IsListEmpty(&pAdapter->ActiveVcList))
+ {
+ //
+ // Remove the VC from the list, deactivate it and delete it.
+ //
+ Link = RemoveHeadList(&pAdapter->ActiveVcList);
+ pVc = CONTAINING_RECORD(Link, VC_BLOCK, Link);
+ Aic5900DeactivateVc((NDIS_HANDLE)pVc);
+ Aic5900DeleteVc((NDIS_HANDLE)pVc);
+ }
+
+ //
+ // Walk our list of inactive VCs.
+ //
+ while (!IsListEmpty(&pAdapter->InactiveVcList))
+ {
+ //
+ // Remove the VC from the list and delete it.
+ //
+ Link = RemoveHeadList(&pAdapter->InactiveVcList);
+ pVc = CONTAINING_RECORD(Link, VC_BLOCK, Link);
+ Aic5900DeleteVc((NDIS_HANDLE)pVc);
+ }
+
+ //
+ // Free up the spin lock for the adapter block.
+ //
+ NdisFreeSpinLock(&pAdapter->Lock);
+
+ //
+ // Free the memory allocated for the adapter block.
+ //
+ FREE_MEMORY(pAdapter, sizeof(ADAPTER_BLOCK));
+ }
+}
+
+
+NDIS_STATUS
+aic5900InitPciRegisters(
+ IN PADAPTER_BLOCK pAdapter
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PHARDWARE_INFO pHwInfo = pAdapter->HardwareInfo;
+ PCI_DEVICE_CONFIG regConfig;
+ PCI_DEVICE_ENABLE_PCI_INTERRUPT regEnableInt;
+ PCI_DEVICE_DMA_CONTROL regDmaControl;
+
+ //
+ // Reset the ORION
+ //
+ GET_PCI_DEV_CFG(pHwInfo, &regConfig);
+ regConfig.SoftwareReset = 1;
+ SET_PCI_DEV_CFG(pHwInfo, regConfig.reg);
+
+ //
+ // Program the interrupt enable register.
+ //
+ GET_PCI_DEV_ENABLE_INT(pHwInfo, &regEnableInt);
+ regEnableInt.EnableDpeInt = 0;
+ regEnableInt.EnableSseInt = 1;
+ regEnableInt.EnableStaInt = 1;
+ regEnableInt.EnableRmaInt = 1;
+ regEnableInt.EnableRtaInt = 1;
+ regEnableInt.EnableDprInt = 1;
+ SET_PCI_DEV_ENABLE_INT(pHwInfo, regEnableInt.reg);
+
+ //
+ // Program the PCI device config register.
+ //
+ GET_PCI_DEV_CFG(pHwInfo, &regConfig);
+ regConfig.MasterSwapBytes = 1;
+ regConfig.EnableInterrupt = 1;
+ SET_PCI_DEV_CFG(pHwInfo, regConfig.reg);
+
+ //
+ // Program the DMA control register.
+ //
+ GET_PCI_DEV_DMA_CONTROL(pHwInfo, &regDmaControl);
+ regDmaControl.CacheThresholdEnable = 1;
+ SET_PCI_DEV_DMA_CONTROL(pHwInfo, regDmaControl.reg);
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+aic5900InitPhyRegisters(
+ IN PADAPTER_BLOCK pAdapter
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PHARDWARE_INFO pHwInfo = pAdapter->HardwareInfo;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ switch (pAdapter->HardwareInfo->NicModelNumber)
+ {
+ case ANA_5910:
+
+ //
+ // Reset the IBM TC and PDM chips. The host can reset TC
+ // and PDM chips by first writing a word to the Software Reset
+ // register and then reading it back.
+ //
+ // Reset clears the STATUS register and flushes the TC receive
+ // FIFO.
+ //
+ SET_IBM_TC_SOFTWARE_RESET(pHwInfo, 0);
+
+ //
+ // Enable TC overrun and cell error interrupts.
+ //
+ SET_IBM_TC_MASK(pHwInfo, 0x04);
+
+ break;
+
+ case ANA_5940:
+ case ANA_5930:
+
+ //
+ // Set and clear the reset bit for the phy.
+ //
+ SET_SUNI_MASTER_RESET_IDEN(pHwInfo, fSUNI_MRI_RESET);
+ SET_SUNI_MASTER_RESET_IDEN(pHwInfo, 0);
+
+ //
+ // Clear the SUNI test mode.
+ //
+ SET_SUNI_MASTER_TEST(pHwInfo, 0);
+
+ //
+ // Enable SUNI RACP interrupts.
+ //
+ SET_SUNI_RACP_INT_ENABLE_STATUS(pHwInfo, (fSUNI_RACP_IES_FIFOE | fSUNI_RACP_IES_HCSE));
+
+ break;
+
+ default:
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
+ ("aic5900InitPhyRegisters: Unknown adapter model 0x%x\n", pAdapter->HardwareInfo->NicModelNumber));
+
+ Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+
+ break;
+ }
+
+ return(Status);
+}
+
+NDIS_STATUS
+aic5900InitSarRegisters(
+ IN PADAPTER_BLOCK pAdapter
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PSAR_INFO pSar;
+ PHARDWARE_INFO pHwInfo = pAdapter->HardwareInfo;
+ PXMIT_SEG_CHANNEL pCurrent;
+ ULONG RamOffset;
+ UINT c;
+
+ do
+ {
+ //
+ // Allocate memory for the sar.
+ //
+ ALLOCATE_MEMORY(&Status, &pSar, sizeof(SAR_INFO));
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ break;
+ }
+
+ ZERO_MEMORY(pSar, sizeof(SAR_INFO));
+
+ NdisAllocateSpinLock(&pSar->lockFreeXmitSegment);
+
+ //
+ // Initialize the VCI table, DMA receive and transmit queues,
+ // the service list, and everything else in the SAR ram.
+ //
+ for (c = 0; c < pHwInfo->SarRamSize / 4; c++)
+ {
+ NdisWriteRegisterUlong(pHwInfo->SarRam + c, 0);
+ }
+
+ //
+ // Initialize the memory manager for our sar ram....
+ //
+ Status = Aic5900InitializeRamInfo(&pHwInfo->hRamInfo, pHwInfo->SarRamSize);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("Unable to initialize the memory manager for the adapter memory\n"));
+
+ break;
+ }
+
+ //
+ // Allocate memory for the VCI table.
+ // NOTE:
+ // We don't need to save the ram offset since this is always
+ // at offset 0.
+ //
+ Status = Aic5900AllocateRam(
+ &RamOffset,
+ pHwInfo->hRamInfo,
+ sizeof(MIDWAY_VCI_TABLE_ENTRY) * MAX_VCS);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DBGPRINT(DBG_COMP_VC, DBG_LEVEL_ERR,
+ ("Unable to allocate the VCI table in adapter ram\n"));
+
+ break;
+ }
+
+ ASSERT(MIDWAY_VCI_TABLE_OFFSET == RamOffset);
+
+ //
+ // Allocate memory for the receive DMA queue.
+ // NOTE:
+ // We don't need to save the RAM offset since this is always at
+ // offset 0x4000.
+ //
+ Status = Aic5900AllocateRam(
+ &RamOffset,
+ pHwInfo->hRamInfo,
+ sizeof(MIDWAY_DMA_DESC) * MIDWAY_DMA_QUEUE_SIZE);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("Unable to allocate the receive queue from the adapter ram\n"));
+
+ break;
+ }
+
+ ASSERT(MIDWAY_RECEIVE_DMA_QUEUE_OFFSET == RamOffset);
+
+ //
+ // Allocate memory for the transmit DMA queue.
+ // NOTE:
+ // We don't need to save the RAM offset since this is always at
+ // offset 0x5000.
+ //
+ Status = Aic5900AllocateRam(
+ &RamOffset,
+ pHwInfo->hRamInfo,
+ sizeof(MIDWAY_DMA_DESC) * MIDWAY_DMA_QUEUE_SIZE);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("Unable to allocate the transmit queue from the adapter ram\n"));
+
+ break;
+ }
+
+ ASSERT(MIDWAY_TRANSMIT_DMA_QUEUE_OFFSET == RamOffset);
+
+ //
+ // Allocate memory for the service queue.
+ // NOTE:
+ // We don't need to save the RAM offset since this is always at
+ // offset 0x6000.
+ //
+ Status = Aic5900AllocateRam(
+ &RamOffset,
+ pHwInfo->hRamInfo,
+ sizeof(MIDWAY_SERVICE_LIST) * MIDWAY_SERVICE_QUEUE_SIZE);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("Unable to allocate the service queue\n"));
+
+ break;
+ }
+
+ ASSERT(MIDWAY_SERVICE_QUEUE_OFFSET == RamOffset);
+
+ //
+ // Get a block of nic ram for the transmit channel.
+ //
+ Status = Aic5900AllocateRam(&RamOffset, pHwInfo->hRamInfo, BLOCK_16K);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("Unable to allocate adapter memory for the UBR channel\n"));
+
+ break;
+ }
+
+ //
+ // Setup the UBR (best effort) channel.
+ //
+ pCurrent = &pSar->XmitSegChannel[0];
+ pSar->ubrXmitChannel = pCurrent;
+
+ NdisZeroMemory(pCurrent, sizeof(XMIT_SEG_CHANNEL));
+
+ NdisAllocateSpinLock(&pCurrent->lock);
+ pCurrent->Adapter = pAdapter;
+ pCurrent->MidwayChannelNumber = MIDWAY_XMIT_SEG_CHANNEL_UBR;
+
+ pCurrent->MidwayInitRegs.XmitPlace.Size =
+ CONVERT_BYTE_SIZE_TO_MIDWAY_SIZE(BLOCK_16K / 4);
+ pCurrent->MidwayInitRegs.XmitPlace.Location =
+ CONVERT_BYTE_OFFSET_TO_MIDWAY_LOCATION(RamOffset);
+ pCurrent->MidwayInitRegs.XmitReadPointer.Register = 0;
+ pCurrent->MidwayInitRegs.XmitDescriptorStart.Register = 0;
+
+ pCurrent->MidwayTransmitRegs =
+ &pHwInfo->Midway->TransmitRegisters[MIDWAY_XMIT_SEG_CHANNEL_UBR];
+
+ pCurrent->SegmentSize = BLOCK_SIZE_16k / 4;
+ pCurrent->Segment = (HWUL *)&pHwInfo->SarRam[RamOffset / 4];
+ pCurrent->SegmentReadPointer = 0;
+ pCurrent->SegmentWritePointer = 0;
+ pCurrent->SegmentRoom = BLOCK_SIZE_16k / 4;
+ pCurrent->XmitPduBytes = 0;
+
+ InitializeListHead(&pCurrent->SegmentWaitQ);
+ InitializeListHead(&pCurrent->TransmitWaitQ);
+
+ for (c = 1, pCurrent = &pSar->XmitSegChannel[c];
+ c < MIDWAY_MAX_SEGMENT_CHANNELS;
+ c++, pCurrent++)
+ {
+ NdisZeroMemory(pCurrent, sizeof(XMIT_SEG_CHANNEL));
+ NdisAllocateSpinLock(&pCurrent->lock);
+
+ pCurrent->Adapter = pAdapter;
+ pCurrent->MidwayChannelNumber = c;
+
+ //
+ // Place the segment channel on the free queue.
+ //
+ pCurrent->Next = pSar->FreeXmitSegChannel;
+ pSar->FreeXmitSegChannel = pCurrent;
+
+ //
+ // Get a pointer to the midway transmit registers.
+ //
+ pCurrent->MidwayTransmitRegs =
+ &pHwInfo->Midway->TransmitRegisters[c];
+
+ //
+ // Initialize the queues.
+ //
+ InitializeListHead(&pCurrent->SegmentWaitQ);
+ InitializeListHead(&pCurrent->TransmitWaitQ);
+ }
+
+ //
+ // Initialize the Midway Master Control register.
+ //
+ pSar->MidwayMasterControl = (MID_REG_MC_S_DMA_ENABLE |
+ MID_REG_MC_S_XMT_ENABLE |
+ MID_REG_MC_S_RCV_ENABLE |
+ MID_REG_MC_S_XMT_LOCK_MODE);
+ pHwInfo->Midway->MCS = pSar->MidwayMasterControl;
+
+ //
+ // Initialize the UBR transmit channel.
+ //
+ pHwInfo->Midway->TransmitRegisters[MIDWAY_XMIT_SEG_CHANNEL_UBR].XmitPlace.Register =
+ pSar->ubrXmitChannel->MidwayInitRegs.XmitPlace.Register;
+
+ pHwInfo->Midway->TransmitRegisters[MIDWAY_XMIT_SEG_CHANNEL_UBR].XmitReadPointer.Register =
+ pSar->ubrXmitChannel->MidwayInitRegs.XmitReadPointer.Register;
+
+ pHwInfo->Midway->TransmitRegisters[MIDWAY_XMIT_SEG_CHANNEL_UBR].XmitDescriptorStart.Register =
+ pSar->ubrXmitChannel->MidwayInitRegs.XmitDescriptorStart.Register;
+
+ pHwInfo->InterruptMask = MID_REG_INT_PCI |
+ MID_REG_INT_XMT_COMPLETE_7 |
+ MID_REG_INT_XMT_COMPLETE_6 |
+ MID_REG_INT_XMT_COMPLETE_5 |
+ MID_REG_INT_XMT_COMPLETE_4 |
+ MID_REG_INT_XMT_COMPLETE_3 |
+ MID_REG_INT_XMT_COMPLETE_2 |
+ MID_REG_INT_XMT_COMPLETE_1 |
+ MID_REG_INT_XMT_COMPLETE_0 |
+ MID_REG_INT_XMT_DMA_OVFL |
+ MID_REG_INT_XMT_IDEN_MISMTCH |
+ MID_REG_INT_DMA_ERR_ACK |
+ MID_REG_INT_RCV_DMA_COMPLETE |
+ MID_REG_INT_XMT_DMA_COMPLETE |
+ MID_REG_INT_SERVICE |
+ MID_REG_INT_SUNI_INT;
+
+ pHwInfo->Midway->IE = pHwInfo->InterruptMask;
+
+ Status = NDIS_STATUS_SUCCESS;
+ } while (FALSE);
+
+ //
+ // If we failed somewhere above then we need to cleanup....
+ //
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ if (NULL != pHwInfo->hRamInfo)
+ {
+ Aic5900UnloadRamInfo(pHwInfo->hRamInfo);
+ }
+
+ if (NULL != pSar)
+ {
+ NdisFreeSpinLock(&pSar->lockFreeXmitSegment);
+ FREE_MEMORY(pSar, sizeof(SAR_INFO));
+ }
+ }
+
+ return(Status);
+}
+
+
+NDIS_STATUS
+Aic5900Initialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ UINT c;
+ PADAPTER_BLOCK pAdapter;
+ PHARDWARE_INFO pHwInfo;
+ NDIS_STATUS Status;
+ PAIC5900_REGISTRY_PARAMETER pRegistryParameter;
+
+ do
+ {
+ //
+ // Initialize for clean-up.
+ //
+ pAdapter = NULL;
+
+ //
+ // Do we support any of the given media types?
+ //
+ for (c = 0; c < MediumArraySize; c++)
+ {
+ if (MediumArray[c] == NdisMediumAtm)
+ {
+ break;
+ }
+ }
+
+ //
+ // If we went through the whole media list without finding
+ // a supported media type let the wrapper know.
+ //
+ if (c == MediumArraySize)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("Media not supported by version of ndis\n"));
+
+ Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
+
+ break;
+ }
+
+ *SelectedMediumIndex = c;
+
+ //
+ // Allocate memory for the registry parameters.
+ //
+ ALLOCATE_MEMORY(
+ &Status,
+ &pRegistryParameter,
+ sizeof(AIC5900_REGISTRY_PARAMETER) * Aic5900MaxRegistryEntry);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_COMP_ERR,
+ ("Unable to allocate memroy for the registry parameters\n"));
+
+ break;
+ }
+
+ ZERO_MEMORY(
+ pRegistryParameter,
+ sizeof(AIC5900_REGISTRY_PARAMETER) * Aic5900MaxRegistryEntry);
+
+ //
+ // Fill in some default registry values.
+ //
+ pRegistryParameter[Aic5900VcHashTableSize].Value = 13;
+
+ //
+ // Read our parameters out of the registry.
+ //
+ Status = aic5900ReadConfigurationInformation(
+ pRegistryParameter,
+ ConfigurationHandle);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("Failed to read the configuration information from the registry\n"));
+
+ break;
+ }
+
+ //
+ // Allocate memory for our adapter block and initialize it.
+ //
+ ALLOCATE_MEMORY(
+ &Status,
+ &pAdapter,
+ sizeof(ADAPTER_BLOCK) +
+ (pRegistryParameter[Aic5900VcHashTableSize].Value * sizeof(ULONG)));
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("Failed to allocate memory for the adapter block\n"));
+ break;
+ }
+
+ ZERO_MEMORY(pAdapter, sizeof(ADAPTER_BLOCK));
+
+ pAdapter->MiniportAdapterHandle = MiniportAdapterHandle;
+
+ NdisAllocateSpinLock(&pAdapter->Lock);
+
+ //
+ // Spin lock and other odd allocations/initializations.
+ //
+ InitializeListHead(&pAdapter->ActiveVcList);
+ InitializeListHead(&pAdapter->InactiveVcList);
+
+ //
+ // Allocate memory for the hardware information.
+ //
+ ALLOCATE_MEMORY(&Status, &pAdapter->HardwareInfo, sizeof(HARDWARE_INFO));
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("Failed to allocate memory for the hardware information\n"));
+
+ break;
+ }
+
+ ZERO_MEMORY(pAdapter->HardwareInfo, sizeof(HARDWARE_INFO));
+
+ pHwInfo = pAdapter->HardwareInfo;
+
+ NdisAllocateSpinLock(&pHwInfo->Lock);
+
+ //
+ // Get the registry parameters.
+ //
+ ASSERT(pRegistryParameter[Aic5900BusNumber].fPresent);
+ pHwInfo->BusNumber = pRegistryParameter[Aic5900BusNumber].Value;
+
+ ASSERT(pRegistryParameter[Aic5900SlotNumber].fPresent);
+ pHwInfo->SlotNumber = pRegistryParameter[Aic5900SlotNumber].Value;
+
+ //
+ // Set the atributes for the adapter.
+ //
+ NdisMSetAttributes(
+ MiniportAdapterHandle,
+ (NDIS_HANDLE)pAdapter,
+ TRUE,
+ NdisInterfacePci);
+
+ //
+ // Assign the PCI resources.
+ //
+ Status = aic5900ReadPciConfiguration(pAdapter);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("Failed to read the PCI configuration information\n"));
+ break;
+ }
+
+ //
+ // Register the Port addresses.
+ //
+ Status = NdisMRegisterIoPortRange(
+ &pHwInfo->PortOffset,
+ pAdapter->MiniportAdapterHandle,
+ pHwInfo->InitialPort,
+ pHwInfo->NumberOfPorts);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("Failed to register the I/O port range\n"));
+ break;
+ }
+
+ //
+ // Get the EEPROM parameters
+ //
+ Status = aic5900ReadEepromInformation(pAdapter);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("Failed to read the EEPROM information from the adapter\n"));
+ break;
+ }
+
+ //
+ // Register the interrupt.
+ //
+ Status = NdisMRegisterInterrupt(
+ &pHwInfo->Interrupt,
+ pAdapter->MiniportAdapterHandle,
+ pHwInfo->InterruptVector,
+ pHwInfo->InterruptLevel,
+ TRUE,
+ TRUE,
+ NdisInterruptLevelSensitive);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("Failed to register the interrupt with ndis\n"));
+ break;
+ }
+
+ //
+ // Initialize the PCI device/configuration registers.
+ //
+ Status = aic5900InitPciRegisters(pAdapter);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("Failed to initialize the PCI Device/Configuration registers\n"));
+
+ break;
+ }
+
+ Status = aic5900InitPhyRegisters(pAdapter);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("Failed to initialize the PHY registers\n"));
+
+ break;
+ }
+
+ //
+ // Initialize the SAR
+ //
+ Status = aic5900InitSarRegisters(pAdapter);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("Failed to initialize the SAR registers\n"));
+
+ break;
+ }
+
+ //
+ // Return success.
+ //
+ Status = NDIS_STATUS_SUCCESS;
+
+ } while (FALSE);
+
+ //
+ // Should we clean up?
+ //
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ aic5900FreeResources(pAdapter);
+ }
+
+ return(Status);
+}
+
diff --git a/private/ntos/ndis/aic5900/int.c b/private/ntos/ndis/aic5900/int.c
new file mode 100644
index 000000000..d01953356
--- /dev/null
+++ b/private/ntos/ndis/aic5900/int.c
@@ -0,0 +1,100 @@
+
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ D:\nt\private\ntos\ndis\aic5900\int.c
+
+Abstract:
+
+Author:
+
+ Kyle Brandon (KyleB)
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "aic5900.h"
+
+#define MODULE_NUMBER MODULE_INT
+
+VOID
+Aic5900EnableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+
+}
+
+VOID
+Aic5900DisableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+
+}
+
+VOID
+Aic5900ISR(
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueDpc,
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ *InterruptRecognized = TRUE;
+ *QueueDpc = FALSE;
+}
+
+VOID
+Aic5900HandleInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+
+}
+
+
+
diff --git a/private/ntos/ndis/aic5900/makefile b/private/ntos/ndis/aic5900/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/aic5900/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/aic5900/memmgr.h b/private/ntos/ndis/aic5900/memmgr.h
new file mode 100644
index 000000000..963503f6f
--- /dev/null
+++ b/private/ntos/ndis/aic5900/memmgr.h
@@ -0,0 +1,72 @@
+
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ D:\nt\private\ntos\ndis\aic5900\memmgr.h
+
+Abstract:
+
+Author:
+
+ Kyle Brandon (KyleB)
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#ifndef __MEMMGR_H
+#define __MEMMGR_H
+
+//
+// RAM memory block supported.
+//
+#define BLOCK_1K 1024
+#define BLOCK_2K 2048
+#define BLOCK_4K 4096
+#define BLOCK_8K 8192
+#define BLOCK_16K 16384
+#define BLOCK_32K 32768
+#define BLOCK_64K 65536
+#define BLOCK_128K 131072
+
+//
+// One memory map range.
+//
+#define MAP_RANGE BLOCK_32K
+
+NDIS_STATUS
+Aic5900InitializeRamInfo(
+ OUT NDIS_HANDLE *hRamInfo,
+ IN ULONG MaxRamSize
+ );
+
+VOID
+Aic5900UnloadRamInfo(
+ IN NDIS_HANDLE hRamInfo
+ );
+
+NDIS_STATUS
+Aic5900AllocateRam(
+ OUT PULONG pRamOffset,
+ IN NDIS_HANDLE hRamInfo,
+ IN ULONG SizeNeeded
+ );
+
+VOID
+Aic5900FreeRam(
+ IN NDIS_HANDLE hRamInfo,
+ IN ULONG RamOffset,
+ IN ULONG RamSize
+ );
+
+
+
+
+#endif // __MEMMGR_H
diff --git a/private/ntos/ndis/aic5900/protos.h b/private/ntos/ndis/aic5900/protos.h
new file mode 100644
index 000000000..ca0c446ef
--- /dev/null
+++ b/private/ntos/ndis/aic5900/protos.h
@@ -0,0 +1,182 @@
+
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ D:\nt\private\ntos\ndis\aic5900\protos.h
+
+Abstract:
+
+Author:
+
+ Kyle Brandon (KyleB)
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#ifndef __PROTOS_H
+#define __PROTOS_H
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+NDIS_STATUS
+Aic5900Initialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE ConfigurationHandle
+ );
+
+VOID
+Aic5900EnableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+VOID
+Aic5900DisableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+VOID
+Aic5900ISR(
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueDpc,
+ IN PVOID Context
+ );
+
+VOID
+Aic5900HandleInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+NDIS_STATUS
+Aic5900ReturnPackets(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET Packet
+ );
+
+VOID
+Aic5900AllocateComplete(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PVOID VirtualAddress,
+ IN PNDIS_PHYSICAL_ADDRESS PhysicalAddress,
+ IN ULONG Length,
+ IN PVOID Context
+ );
+
+///
+// PROTOTYPES FOR REQUEST CODE
+///
+NDIS_STATUS
+Aic5900SetInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ );
+
+NDIS_STATUS
+Aic5900QueryInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ );
+
+NDIS_STATUS
+Aic5900Request(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE MiniportVcContext OPTIONAL,
+ IN OUT PNDIS_REQUEST NdisCoRequest
+ );
+
+///
+// PROTOTYPES FOR RESET CODE
+///
+BOOLEAN
+Aic5900CheckForHang(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+NDIS_STATUS
+Aic5900Reset(
+ OUT PBOOLEAN AddressingReset,
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+///
+// PROTOTYPES FOR HALTING THE ADAPTER AND CLEANUP
+///
+
+VOID
+aic5900FreeResources(
+ IN PADAPTER_BLOCK pAdapter
+ );
+
+VOID
+Aic5900Halt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+///
+// PROTOTYPES FOR SEND PATH
+///
+VOID
+Aic5900SendPackets(
+ IN NDIS_HANDLE MiniportVcContext,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ );
+
+
+///
+// PROTOTYPES FOR VC Creation and Deletion
+///
+
+NDIS_STATUS
+Aic5900CreateVc(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE NdisVcHandle,
+ OUT PNDIS_HANDLE MiniportVcContext
+ );
+
+NDIS_STATUS
+Aic5900DeleteVc(
+ IN NDIS_HANDLE MiniportVcContext
+ );
+
+NDIS_STATUS
+Aic5900ActivateVc(
+ IN NDIS_HANDLE MiniportVcContext,
+ IN PCO_MEDIA_PARAMETERS MediaParameters
+ );
+
+NDIS_STATUS
+Aic5900DeactivateVc(
+ IN NDIS_HANDLE MiniportVcContext
+ );
+
+VOID
+aic5900DeactivateVcComplete(
+ IN PADAPTER_BLOCK pAdapter,
+ IN PVC_BLOCK pVc
+ );
+
+#endif // __PROTOS_H
diff --git a/private/ntos/ndis/aic5900/receive.c b/private/ntos/ndis/aic5900/receive.c
new file mode 100644
index 000000000..c2a619461
--- /dev/null
+++ b/private/ntos/ndis/aic5900/receive.c
@@ -0,0 +1,68 @@
+
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ D:\nt\private\ntos\ndis\aic5900\receive.c
+
+Abstract:
+
+Author:
+
+ Kyle Brandon (KyleB)
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "aic5900.h"
+
+#define MODULE_NUMBER MODULE_RECEIVE
+
+NDIS_STATUS
+Aic5900ReturnPackets(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+
+ return(NDIS_STATUS_FAILURE);
+}
+
+
+VOID
+Aic5900AllocateComplete(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PVOID VirtualAddress,
+ IN PNDIS_PHYSICAL_ADDRESS PhysicalAddress,
+ IN ULONG Length,
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+
+}
+
diff --git a/private/ntos/ndis/aic5900/request.c b/private/ntos/ndis/aic5900/request.c
new file mode 100644
index 000000000..5a6f394ca
--- /dev/null
+++ b/private/ntos/ndis/aic5900/request.c
@@ -0,0 +1,81 @@
+
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ D:\nt\private\ntos\ndis\aic5900\request.c
+
+Abstract:
+
+Author:
+
+ Kyle Brandon (KyleB)
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "aic5900.h"
+
+#define MODULE_NUMBER MODULE_REQUEST
+
+NDIS_STATUS
+Aic5900SetInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ return(NDIS_STATUS_FAILURE);
+}
+
+NDIS_STATUS
+Aic5900QueryInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ return(NDIS_STATUS_FAILURE);
+}
+
+NDIS_STATUS
+Aic5900Request(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE MiniportVcContext OPTIONAL,
+ IN OUT PNDIS_REQUEST NdisCoRequest
+ )
+{
+ return(NDIS_STATUS_SUCCESS);
+}
+
diff --git a/private/ntos/ndis/aic5900/reset.c b/private/ntos/ndis/aic5900/reset.c
new file mode 100644
index 000000000..4e581da94
--- /dev/null
+++ b/private/ntos/ndis/aic5900/reset.c
@@ -0,0 +1,79 @@
+
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ D:\nt\private\ntos\ndis\aic5900\reset.c
+
+Abstract:
+
+Author:
+
+ Kyle Brandon (KyleB)
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "aic5900.h"
+
+#define MODULE_NUMBER MODULE_RESET
+
+BOOLEAN
+Aic5900CheckForHang(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ return(FALSE);
+}
+
+NDIS_STATUS
+Aic5900Reset(
+ OUT PBOOLEAN AddressingReset,
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ return(NDIS_STATUS_FAILURE);
+}
+
+VOID
+Aic5900Halt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ aic5900FreeResources((PADAPTER_BLOCK)MiniportAdapterContext);
+}
+
diff --git a/private/ntos/ndis/aic5900/sar.h b/private/ntos/ndis/aic5900/sar.h
new file mode 100644
index 000000000..ff201ee35
--- /dev/null
+++ b/private/ntos/ndis/aic5900/sar.h
@@ -0,0 +1,781 @@
+
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ D:\nt\private\ntos\ndis\aic5900\sar.h
+
+Abstract:
+
+Author:
+
+ Kyle Brandon (KyleB)
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#ifndef __SAR_H
+#define __SAR_H
+
+//
+// MIDWAY macros.
+//
+#define MID_XMTREG_PLACE2SIZE(place) ((place >> 10) & 0x3)
+#define MID_XMTREG_PLACE2LOCATION(place) (place & 0x3ff)
+#define MIDWAY_MAX_SEGMENT_CHANNELS 8
+
+#define MIDWAY_XMIT_SEG_CHANNEL_UBR 0
+
+#define BLOCK_SIZE_1k 1024
+#define BLOCK_SIZE_2k 2048
+#define BLOCK_SIZE_4k 4096
+#define BLOCK_SIZE_8k 8192
+#define BLOCK_SIZE_16k 16384
+#define BLOCK_SIZE_32k 32768
+#define BLOCK_SIZE_64k 65536
+#define BLOCK_SIZE_128k 131072
+
+#define CONVERT_BYTE_OFFSET_TO_MIDWAY_LOCATION(_offset) ((_offset) >> 10)
+#define CONVERT_WORD_OFFSET_TO_MIDWAY_LOCATION(_offset) ((_offset) >> 8)
+
+#define CONVERT_MIDWAY_LOCATION_TO_BYTE_OFFSET(_location) ((_location) << 10)
+#define CONVERT_MIDWAY_LOCATION_TO_WORD_OFFSET(_location) ((_location) << 8)
+
+#define CONVERT_BYTE_SIZE_TO_MIDWAY_SIZE(_size) CONVERT_WORD_SIZE_TO_MIDWAY_SIZE((_size) / 4)
+#define CONVERT_WORD_SIZE_TO_MIDWAY_SIZE(_size) \
+ ((256 == (_size)) ? 0 : \
+ (512 == (_size)) ? 1 : \
+ (1024 == (_size)) ? 2 : \
+ (2048 == (_size)) ? 3 : \
+ (4096 == (_size)) ? 4 : \
+ (8192 == (_size)) ? 5 : \
+ (16384 == (_size)) ? 6 : 7)
+
+//
+// This is the VC that all OAM cells are forced to go to.
+//
+#define MIDWAY_OAM_VCI 3
+
+#define ATMHEADER_PTI_OAM_SEG 4
+#define ATMHEADER_PTI_OAM_END2END 5
+
+#define MIDWAY_DMA_QUEUE_SIZE 512
+#define MIDWAY_SERVICE_QUEUE_SIZE 1024
+
+
+//
+// These are always the same and are used for clarity in the driver code.
+//
+#define MIDWAY_VCI_TABLE_OFFSET 0
+#define MIDWAY_RECEIVE_DMA_QUEUE_OFFSET 0x4000
+#define MIDWAY_TRANSMIT_DMA_QUEUE_OFFSET 0x5000
+#define MIDWAY_SERVICE_QUEUE_OFFSET 0x6000
+
+//
+// MIDWAY_XMIT_REGISTERS
+//
+// Description:
+// This is the data structure for the MIDWAY ATM transmit channel
+// register set.
+// This structure is defined seperately from the MIDWAY_REGS structure
+// because there are 8 transmit engines that each have a set of registers.
+// For a full description consult the Midway (SBUS) ASIC Specification.
+//
+// Elements:
+// xmt_place - Contains the Size/Location of the XMT segment
+// memory for the queue.
+// xmt_rdptr - Points to the next 32 bit word to be transfered to
+// the PHY. Maintained by Midway.
+// xmt_descrstart - Points to the start of the Segmentation buffer
+// (descriptor), currently being DMA'd into the
+// segment memory queue.
+//
+struct _MIDWAY_XMIT_REGISTERS
+{
+ union
+ {
+ struct _XmitPlace
+ {
+ HWUL Location:11;
+ HWUL Size:3;
+ HWUL Reserved0: 18;
+ };
+
+ HWUL Register;
+ }
+ XmitPlace;
+
+ union
+ {
+ struct _XmitReadPointer
+ {
+ HWUL Pointer:15;
+ HWUL Reserved0:17;
+ };
+
+ HWUL Register;
+ }
+ XmitReadPointer;
+
+ union
+ {
+ struct _XmitDescriptorStart
+ {
+ HWUL Pointer:15;
+ HWUL Reserved0:17;
+ };
+
+ HWUL Register;
+ }
+ XmitDescriptorStart;
+
+ HWUL XmitUnused;
+};
+
+#define MIDWAY_XMTREG_PLACE2SIZE(_place) (((_place) >> 10) & 0x3)
+#define MIDWAY_XMTREG_PLACE2LOCATION(_place) ((_place) & 0x3ff)
+
+//
+// MIDWAY_REGISTERS
+//
+// Description:
+// This data structure defines the MIDWAY ATM ASIC register set.
+// For a full description consult the Midway (SBUS) ASIC Specification.
+// If you look carefully, the member names in this structure match
+// the names used in the document. Simply tack 'mid_reg_' on to the
+// front of the names in the document.
+//
+// Elements:
+// ResetID - Midway Reset / ID
+// ISA - Interrupt Status Acknowledge
+// IS - Interrupt Status
+// IE - Interrupt Enable
+// MCS - Master Control/Status
+// Statistics - Statistics
+// ServiceList - Service List Write Pointer.
+// DmaWriteRcv - RCV DMA write pointer
+// DmaReadRcv - RCV DMA read pointer
+// DmaWriteXmit - XMT DMA write pointer
+// DmaReadXmit - XMT DMA read pointer
+// Unused[3] -
+// TransmitRegisters - XMT channel registers
+//
+// Note:
+// The midway is a 32-bit only device. Make sure that all accesses
+// to the registers are 32-bit accesses. The adapter will assist you
+// in ensuring this by forcing bus errors if you attmept anything
+// other than 32-bit accesses.
+// the structures that come before the MIDWAY_REGISTERS are defined as
+// a union of bit fields and a ULONG, this is so that the register can
+// be easily constructed and then copied in a single 32-bit operation
+// to the hardware register.
+//
+
+typedef struct _MIDWAY_REG_RESET_ID
+{
+ union
+ {
+ struct
+ {
+ HWUL ConfigId1: 5;
+ HWUL ConV6: 1;
+ HWUL ConSuni: 1;
+ HWUL ConfigId2: 1;
+ HWUL MotherId: 3;
+ HWUL reserved0: 17;
+ HWUL SarId: 4;
+ };
+
+ HWUL Register;
+ };
+}
+ MIDWAY_REG_RESET_ID,
+ *PMIDWAY_REG_RESET_ID;
+
+typedef struct _MIDWAY_REG_ISA
+{
+ union
+ {
+ struct
+ {
+ HWUL StatusOverflow:1;
+ HWUL Suni:1;
+ HWUL Service:1;
+ HWUL XmitDmaComplete:1;
+ HWUL RcvDmaComplete:1;
+ HWUL DmaErrorAck:1;
+ HWUL Reserved0:1;
+ HWUL XmitIdenMismatch:1;
+ HWUL XmitDmaOverflow:1;
+ HWUL XmitComplete0:1;
+ HWUL XmitComplete1:1;
+ HWUL XmitComplete2:1;
+ HWUL XmitComplete3:1;
+ HWUL XmitComplete4:1;
+ HWUL XmitComplete5:1;
+ HWUL XmitComplete6:1;
+ HWUL XmitComplete7:1;
+ HWUL Pci:1;
+ HWUL Reserved1:14;
+ };
+
+ HWUL Register;
+ };
+}
+ MIDWAY_REG_ISA,
+ *PMIDWAY_REG_ISA;
+
+typedef struct _MIDWAY_REG_IS
+{
+ union
+ {
+ struct
+ {
+ HWUL StatusOverflow:1;
+ HWUL Suni:1;
+ HWUL Service:1;
+ HWUL XmitDmaComplete:1;
+ HWUL RcvDmaComplete:1;
+ HWUL DmaErrorAck:1;
+ HWUL Reserved0:1;
+ HWUL XmitIdenMismatch:1;
+ HWUL XmitDmaOverflow:1;
+ HWUL XmitComplete0:1;
+ HWUL XmitComplete1:1;
+ HWUL XmitComplete2:1;
+ HWUL XmitComplete3:1;
+ HWUL XmitComplete4:1;
+ HWUL XmitComplete5:1;
+ HWUL XmitComplete6:1;
+ HWUL XmitComplete7:1;
+ HWUL Pci: 1;
+ HWUL Reserved1:14;
+ };
+
+ HWUL Register;
+ };
+}
+ MIDWAY_REG_IS,
+ *PMIDWAY_REG_IS;
+
+typedef struct _MIDWAY_REG_IE
+{
+ union
+ {
+ struct
+ {
+ HWUL EnableStatusOverflow:1;
+ HWUL EnableSuni:1;
+ HWUL EnableService:1;
+ HWUL EnableXmitDmaComplete:1;
+ HWUL EnableRcvDmaComplete:1;
+ HWUL EnableDmaErrorAck:1;
+ HWUL Reserved0:1;
+ HWUL EnableXmitIdenMismatch:1;
+ HWUL EnableXmitDmaOverflow: 1;
+ HWUL EnableXmitComplete0:1;
+ HWUL EnableXmitComplete1:1;
+ HWUL EnableXmitComplete2:1;
+ HWUL EnableXmitComplete3:1;
+ HWUL EnableXmitComplete4:1;
+ HWUL EnableXmitComplete5:1;
+ HWUL EnableXmitComplete6:1;
+ HWUL EnableXmitComplete7:1;
+ HWUL EnablePci:1;
+ HWUL Reserved1:14;
+ };
+
+ HWUL Register;
+ };
+}
+ MIDWAY_REG_IE,
+ *PMIDWAY_REG_IE;
+
+typedef struct _MIDWAY_REG_MCS
+{
+ union
+ {
+ struct
+ {
+ HWUL Wait500us:1;
+ HWUL Wait1ms:1;
+ HWUL RcvEnable:1;
+ HWUL XmitEnable:1;
+ HWUL DmaEnable:1;
+ HWUL XmitLockMode:1;
+ HWUL Wait2ms:1;
+ HWUL Wait4ms:1;
+ HWUL Reserved0:24;
+ };
+
+ HWUL Register;
+ };
+}
+ MIDWAY_REG_MCS,
+ *PMIDWAY_REG_MCS;
+
+typedef struct _MIDWAY_REG_STATISTICS
+{
+ union
+ {
+ struct
+ {
+ HWUL OverflowTrash:16;
+ HWUL VciTrash:16;
+ };
+
+ HWUL Register;
+ };
+}
+ MIDWAY_REG_STATISTICS,
+ *PMIDWAY_REG_STATISTICS;
+
+typedef struct _MIDWAY_REG_SERVICE_LIST
+{
+ union
+ {
+ struct
+ {
+ HWUL WritePointer:10;
+ HWUL Reserved0:22;
+ };
+
+ HWUL Register;
+ };
+}
+ MIDWAY_REG_SERVICE_LIST,
+ *PMIDWAY_REG_SERVICE_LIST;
+
+typedef struct _MIDWAY_REG_DMA_WRITE_RCV
+{
+ union
+ {
+ struct
+ {
+ HWUL Pointer:9;
+ HWUL Reserved0: 23;
+ };
+
+ HWUL Register;
+ };
+}
+ MIDWAY_REG_DMA_WRITE_RCV,
+ *PMIDWAY_REG_DMA_WRITE_RCV;
+
+typedef struct _MIDWAY_REG_DMA_READ_RCV
+{
+ union
+ {
+ struct
+ {
+ HWUL Pointer:9;
+ HWUL Reserved0:23;
+ };
+
+ HWUL Register;
+ };
+}
+ MIDWAY_REG_DMA_READ_RCV,
+ *PMIDWAY_REG_DMA_READ_RCV;
+
+struct _MIDWAY_REG_DMA_WRITE_XMIT
+{
+ union
+ {
+ struct
+ {
+ HWUL Pointer:9;
+ HWUL Reserved0:23;
+ };
+
+ HWUL Register;
+ };
+}
+ MIDWAY_REG_DMA_WRITE_XMIT,
+ *PMIDWAY_REG_DMA_WRITE_XMIT;
+
+struct _MIDWAY_REG_DMA_READ_XMIT
+{
+ union
+ {
+ struct
+ {
+ HWUL Pointer:9;
+ HWUL Reserved0:23;
+ };
+
+ HWUL Register;
+ };
+}
+ MIDWAY_REG_DMA_READ_XMIT,
+ *PMIDWAY_REG_DMA_READ_XMIT;
+
+struct _MIDWAY_REGISTERS
+{
+ HWUL ResetId;
+ HWUL ISA;
+ HWUL IS;
+ HWUL IE;
+ HWUL MCS;
+ HWUL Statistics;
+ HWUL ServiceList;
+
+ HWUL Reserved;
+
+ HWUL DmaWriteRcv;
+ HWUL DmaReadRcv;
+ HWUL DmaWriteXmit;
+ HWUL DmaReadXmit;
+
+ HWUL Unused[4];
+
+ MIDWAY_XMIT_REGISTERS TransmitRegisters[MIDWAY_MAX_SEGMENT_CHANNELS];
+};
+
+
+//
+// The following defines are used for the interrupt registers.
+//
+// IS - If a bit is set then the interrupt is pending.
+// ISA - If a bit is set then the interrupt is pending.
+// When read, ALL bits are cleared. Accept SUNI_INT &
+// STAT_OVFL which require additionl action. ??PCI_INT??
+// IE - If a bit is set then the interrupt is enabled.
+//
+#define MID_REG_INT_PCI BIT(17)
+#define MID_REG_INT_XMT_COMPLETE_7 BIT(16)
+#define MID_REG_INT_XMT_COMPLETE_6 BIT(15)
+#define MID_REG_INT_XMT_COMPLETE_5 BIT(14)
+#define MID_REG_INT_XMT_COMPLETE_4 BIT(13)
+#define MID_REG_INT_XMT_COMPLETE_3 BIT(12)
+#define MID_REG_INT_XMT_COMPLETE_2 BIT(11)
+#define MID_REG_INT_XMT_COMPLETE_1 BIT(10)
+#define MID_REG_INT_XMT_COMPLETE_0 BIT(9)
+#define MID_REG_INT_XMT_DMA_OVFL BIT(8)
+#define MID_REG_INT_XMT_IDEN_MISMTCH BIT(7)
+#define MID_REG_INT_DMA_ERR_ACK BIT(5)
+#define MID_REG_INT_RCV_DMA_COMPLETE BIT(4)
+#define MID_REG_INT_XMT_DMA_COMPLETE BIT(3)
+#define MID_REG_INT_SERVICE BIT(2)
+#define MID_REG_INT_SUNI_INT BIT(1)
+#define MID_REG_INT_STAT_OVFL BIT(0)
+
+#define MID_REG_MC_S_WAIT_4_MS bit(7)
+#define MID_REG_MC_S_WAIT_2_MS BIT(6)
+#define MID_REG_MC_S_XMT_LOCK_MODE BIT(5)
+#define MID_REG_MC_S_DMA_ENABLE BIT(4)
+#define MID_REG_MC_S_XMT_ENABLE BIT(3)
+#define MID_REG_MC_S_RCV_ENABLE BIT(2)
+#define MID_REG_MC_S_WAIT_1_MS BIT(1)
+#define MID_REG_MC_S_WAIT_500_US BIT(0)
+
+
+#define MID_REG_STAT_VCI_TRASH(reg_value) ((reg_value >> 0x16) & 0xff)
+#define MID_REG_STAT_OVFL_TRASH(reg_value) (reg_value & 0xff)
+
+//
+// Format for the Midway's service list. This is simply a 1k queue,
+// of VC's that need DMA servicing
+//
+typedef struct _MIDWAY_SERVICE_LIST
+{
+ union
+ {
+ struct
+ {
+ HWUL VciNumber:10;
+ HWUL Reserved;
+ };
+
+ HWUL Register;
+ };
+}
+ MIDWAY_SERVICE_LIST,
+ *PMIDWAY_SERVICE_LIST;
+
+
+typedef struct _MIDWAY_DMA_DESC
+{
+ union
+ {
+ struct
+ {
+ //
+ // This is used to skip a block of memory instead of performing
+ // DMA transfers.
+ //
+ HWUL JustKidding:1;
+
+ //
+ // The End field is set by the host when setting up the descriptor
+ // for the last DMA block of a PDU. It must be set in the last
+ // DMA_Descriptor for the VCI.
+ //
+ HWUL End:1;
+
+ //
+ // This is the VC that points to the Reassembly_queue with the
+ // data to be DMA'd.
+ //
+ HWUL Vci:10;
+
+ //
+ // Number of bytes to be transfered.
+ //
+ HWUL Count:18;
+
+ HWUL Reserved:2;
+ };
+
+ HWUL Register;
+ };
+
+ HWUL LowHostAddress;
+}
+ MIDWAY_DMA_DESC,
+ *PMIDWAY_DMA_DESC;
+
+typedef union _VCI_TABLE_ENTRY_WORD_0
+{
+ struct
+ {
+ //
+ // This identifies whether or not the VCI is currently in the
+ // Service_list.
+ //
+ HWUL InService:1;
+
+ HWUL Reserved:14;
+
+ //
+ // Specifies the size of the Reassembly_queue.
+ //
+ HWUL Size:3;
+
+ //
+ // This contains up to the 11 MSBs of the address location of the
+ // corresponding Reassembly_queue in adapter memory.
+ //
+ HWUL Location:11;
+
+ //
+ // When set we will preserve OAM F5 cellson the given VCI and
+ // direct them to VCI 3 (the OAM channel). When clear the
+ // OAM F5 cells that are received on this VCI will be trashed.
+ //
+ HWUL PtiMode:1;
+
+ //
+ // Indicates the operation mode of the VC:
+ // 00 = Trash
+ // 01 = non-AAL5
+ // 10 = AAL5
+ // 11 = Reserved
+ //
+ HWUL Mode:2;
+ };
+
+ HWUL Register;
+}
+ _VCI_TABLE_ENTRY_WORD_0,
+ *PVCI_TABLE_ENTRY_WORD_0;
+
+typedef union _VCI_TABLE_ENTRY_WORD_1
+{
+ struct
+ {
+ //
+ // Points to the last 32-bit word that was DMA'd to host memory
+ // from the Reassembly_queue.
+ //
+ HWUL ReadPtr:15;
+
+ HWUL Reserved0:1;
+
+ //
+ // Points to the start of the reassembly buffer descriptor
+ // currently being reassembled in the Reassembly_queue, or
+ // the next free location in adapter memory when the channel
+ // is idle.
+ //
+ HWUL DescStart:15;
+
+ HWUL Reserved1:1;
+ };
+
+ HWUL Register;
+}
+ VCI_TABLE_ENTRY_WORD_1,
+ *PVCI_TABLE_ENTRY_WORD_1;
+
+typedef union _VCI_TABLE_ENTRY_WORD_2
+{
+ struct
+ {
+ //
+ // Contains the temporary cell count for the PDU currently being
+ // reassembled.
+ //
+ HWUL CellCount:11;
+
+ HWUL Reserved0:3;
+
+ //
+ // Indicates the current state of the VCI:
+ // 00 = Idle
+ // 01 = Reassembling
+ // 11 = Trashing
+ //
+ HWUL State:2;
+
+ //
+ // Points to the next free 32-bit word which will be overwritten
+ // by the next reassembled word in the Reassembly_queue.
+ //
+ HWUL writeptr: 15;
+
+ HWUL Reserved1: 1;
+ };
+
+ HWUL Register;
+}
+ VCI_TABLE_ENTRY_WORD_2,
+ *PVCI_TABLE_ENTRY_WORD_2;
+
+typedef struct _MIDWAY_VCI_TABLE_ENTRY
+{
+ //
+ // See the above structures for the definitions of these.
+ //
+ HWUL Register0;
+ HWUL Register1;
+ HWUL Register2;
+
+ //
+ // This last ULONG contains the temporary CRC value being calculated
+ // by the PDU currently being reassembled.
+ //
+ HWUL Register3;
+}
+ MIDWAY_VCI_TABLE_ENTRY,
+ *PMIDWAY_VCI_TABLE_ENTRY;
+
+
+//
+// Transmit Segmentation Channel.
+//
+// This is allocated for each segmentation channel. This has
+// all the information about each channel, e.g. buffers, size, etc....
+//
+
+struct _XMIT_SEG_CHANNEL
+{
+ PXMIT_SEG_CHANNEL Next; // Next pointer.
+ PADAPTER_BLOCK Adapter; // Pointer to the adapter.
+
+ UINT MidwayChannelNumber;
+
+ //
+ // Copy of the Midway transmit registers. This is the initial set of
+ // the transmit registers for the segmentation channel.
+ //
+ MIDWAY_XMIT_REGISTERS MidwayInitRegs;
+
+ //
+ // Pointer to the transmit registers.
+ //
+ PMIDWAY_XMIT_REGISTERS MidwayTransmitRegs;
+
+ //
+ // Size of the segment in 32-bit words.
+ //
+ UINT SegmentSize;
+
+ //
+ // Pointer to the segment memory on the nic.
+ //
+ HWUL *Segment;
+
+ //
+ // Host copy of the read pointer. This is used to determine how much
+ // memory has been freed up when the transmit complete interrupt occurs.
+ //
+ UINT SegmentReadPointer;
+
+ //
+ // Host copy of the write pointer. This is in size of words.
+ //
+ UINT SegmentWritePointer;
+
+ //
+ // The amount of free memory that is available in the transmit segment.
+ //
+ UINT SegmentRoom;
+
+ //
+ // Queue of transmit descriptors waiting for segment room.
+ //
+ LIST_ENTRY SegmentWaitQ;
+
+ //
+ // Queue of transmit descriptors waiting for transmit completion.
+ // These have been handed to the DMA/XMIT engine and are awaiting
+ // completion.
+ //
+ LIST_ENTRY TransmitWaitQ;
+
+ //
+ // Number of Bytes queued on the channel.
+ //
+ UINT XmitPduBytes;
+
+ //
+ // Flags for the transmit segmentation channel.
+ //
+ ULONG flags;
+
+ //
+ // Spin lock for this structure.
+ //
+ NDIS_SPIN_LOCK lock;
+};
+
+#define fXSC_XMIT_START_ACTIVE 0x00000001
+#define fXSC_CBR_ONLY 0x00000002
+
+//
+// Contains information about the Segmentation and Reassembly unit.
+//
+struct _SAR_INFO
+{
+ //
+ // Number of segmentation channels.
+ //
+ XMIT_SEG_CHANNEL XmitSegChannel[MIDWAY_MAX_SEGMENT_CHANNELS];
+
+ //
+ // Points to the free segmentation channel.
+ //
+ PXMIT_SEG_CHANNEL FreeXmitSegChannel;
+ NDIS_SPIN_LOCK lockFreeXmitSegment;
+
+ //
+ // UBR transmit channel.
+ //
+ PXMIT_SEG_CHANNEL ubrXmitChannel;
+
+ UINT ReceiveServiceEntry;
+
+ UINT MidwayMasterControl;
+};
+
+
+
+#endif // __SAR_H
diff --git a/private/ntos/ndis/aic5900/send.c b/private/ntos/ndis/aic5900/send.c
new file mode 100644
index 000000000..664d60866
--- /dev/null
+++ b/private/ntos/ndis/aic5900/send.c
@@ -0,0 +1,44 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ D:\nt\private\ntos\ndis\aic5900\send.c
+
+Abstract:
+
+Author:
+
+ Kyle Brandon (KyleB)
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "aic5900.h"
+
+#define MODULE_NUMBER MODULE_SEND
+
+
+VOID
+Aic5900SendPackets(
+ IN NDIS_HANDLE MiniportVcContext,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+}
diff --git a/private/ntos/ndis/aic5900/sources b/private/ntos/ndis/aic5900/sources
new file mode 100644
index 000000000..89ff408c2
--- /dev/null
+++ b/private/ntos/ndis/aic5900/sources
@@ -0,0 +1,54 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+ Carol Fuss 13-July-1992 - Converted for the Netflx driver.
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=aic5900
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib lib\*\memmgr.lib
+
+C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER -DNDIS41_MINIPORT
+
+INCLUDES=..\..\inc
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+RELATIVE_DEPTH=..\..
+
+SOURCES=init.c\
+ int.c\
+ receive.c\
+ request.c\
+ reset.c\
+ send.c\
+ vc.c\
+ debug.c\
+ data.c\
+ aic5900.rc
+
+
diff --git a/private/ntos/ndis/aic5900/sw.h b/private/ntos/ndis/aic5900/sw.h
new file mode 100644
index 000000000..4401ed2ab
--- /dev/null
+++ b/private/ntos/ndis/aic5900/sw.h
@@ -0,0 +1,330 @@
+
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ D:\nt\private\ntos\ndis\aic5900\sw.h
+
+Abstract:
+
+Author:
+
+ Kyle Brandon (KyleB)
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#ifndef __SW_H
+#define __SW_H
+
+#define AIC5900_NDIS_MAJOR_VERSION 4
+#define AIC5900_NDIS_MINOR_VERSION 1
+
+//
+// This macro is used to convert big-endian to host format.
+//
+#define GET_USHORT_2_USHORT(Dst, Src) \
+ *((PUSHORT)(Dst)) = ((*((PUCHAR)(Src) + 0) << 8) + \
+ (*((PUCHAR)(Src) + 1)))
+
+#define GET_ULONG_2_ULONG(Dst, Src) \
+ *((PULONG)(Dst)) = ((*((PUCHAR)(Src) + 0) << 24) + \
+ (*((PUCHAR)(Src) + 1) << 16) + \
+ (*((PUCHAR)(Src) + 2) << 8) + \
+ (*((PUCHAR)(Src) + 3)))
+
+
+//
+// Macros used to allocate and free memory.
+//
+#define ALLOCATE_MEMORY(_pStatus, _pAddress, _Length) \
+{ \
+ NDIS_PHYSICAL_ADDRESS _HighestAddress; \
+ \
+ NdisSetPhysicalAddressLow(_HighestAddress, 0xffffffff); \
+ NdisSetPhysicalAddressHigh(_HighestAddress, 0xffffffff); \
+ \
+ *(_pStatus) = NdisAllocateMemory( \
+ (PVOID *)(_pAddress), \
+ (UINT)(_Length), \
+ 0, \
+ _HighestAddress); \
+}
+
+#define FREE_MEMORY(_Address, _Length) \
+{ \
+ NdisFreeMemory((PVOID)(_Address), (UINT)(_Length), 0); \
+}
+
+#define ZERO_MEMORY(_Address, _Length) \
+{ \
+ NdisZeroMemory((_Address), (_Length)); \
+}
+
+//
+// The following enumeration contains the possible registry parameters.
+//
+typedef enum _AIC5900_REGISTRY_ENTRY
+{
+ Aic5900BusNumber = 0,
+ Aic5900SlotNumber,
+ Aic5900VcHashTableSize,
+ Aic5900MaxRegistryEntry
+}
+ AIC5900_REGISTRY_ENTRY;
+
+
+//
+// The following structure is used to keep track of registry
+// parameters temporarily.
+//
+typedef struct _AIC5900_REGISTRY_PARAMETER
+{
+ BOOLEAN fPresent;
+ ULONG Value;
+}
+ AIC5900_REGISTRY_PARAMETER,
+ *PAIC5900_REGISTRY_PARAMETER;
+
+typedef struct _HARDWARE_INFO
+{
+ //
+ // Flags information on the HARDWARE_INFO structure.
+ //
+ ULONG Flags;
+ NDIS_SPIN_LOCK Lock;
+
+ //
+ // Bus Information.
+ //
+ UINT BusNumber;
+ UINT SlotNumber;
+
+ //
+ // Information from the PCI configuration information.
+ //
+ PPCI_COMMON_CONFIG PciCommonConfig;
+
+ //
+ // Interrupt information.
+ //
+ ULONG InterruptLevel;
+ ULONG InterruptVector;
+ NDIS_MINIPORT_INTERRUPT Interrupt;
+ ULONG InterruptMask;
+
+ //
+ // I/O port information.
+ //
+ PVOID PortOffset;
+ UINT InitialPort;
+ ULONG NumberOfPorts;
+
+ //
+ // Memory mapped I/O space information.
+ //
+ PVOID MappedIoSpace;
+ NDIS_PHYSICAL_ADDRESS PhysicalIoSpace;
+ ULONG IoSpaceLength;
+
+ PPCI_FCODE_IMAGE FCodeImage;
+
+ UINT NicModelNumber; // Model identifier.
+ UINT RomVersionNumber; // Version number of the FCode.
+
+ ULONG CellClockRate; // Rate of the cell clock. This is used
+ // in determining cell rate.
+
+ ///
+ // The following are I/O space memory offsets and sizes.
+ // NOTE:
+ // The following offsets are from the PciFCode pointer.
+ ///
+
+ ULONG rEpromOffset; // Offset of read-only EPROM info into I/O space.
+ ULONG rEpromSize; // Size of read-only EPROM info.
+ PVOID rEprom; // Mapped pointer to read-only EPROM info.
+
+ ULONG rwEpromOffset; // Offset of read-write EPROM info into I/O space.
+ ULONG rwEpromSize; // Size of read-only EPROM info.
+ PVOID rwEprom; // Mapped pointer to read-write EPROM info.
+
+ ULONG PhyOffset; // Offset of PHY registers into I/O space.
+ ULONG PhySize; // Size of PHY reigsters.
+ PUCHAR Phy; // Mapped pointer to the PHY registers.
+
+ ULONG ExternalOffset; // Offset of EXTERNAL registers into I/O space.
+ ULONG ExternalSize; // Size of EXTERNAL registers
+ PVOID External; // Mapped pointer to EXTERNAL registers.
+
+ ULONG MidwayOffset; // Offset of SAR registers into I/O space.
+ ULONG MidwaySize; // Size of SAR registers.
+ PMIDWAY_REGISTERS Midway; // Mapped pointer to the SAR registers.
+
+ ULONG PciCfgOffset; // Offset of PCI Config registers in I/O space.
+ ULONG PciCfgSize; // Size of PCI Config registers.
+ PUCHAR PciConfigSpace; // Mapped pointer to the PCI configuration space.
+
+ ULONG SarRamOffset; // Offset of SAR Ram in I/O space.
+ ULONG SarRamSize; // Size of SAR Ram.
+ PULONG SarRam; // Mapped pointer to SAR Ram.
+
+ NDIS_HANDLE hRamInfo; // Handle for the memory manager.
+
+ //
+ // address of the adapter.
+ //
+ UCHAR PermanentAddress[ATM_ADDRESS_LENGTH];
+ UCHAR StationAddress[ATM_ADDRESS_LENGTH];
+};
+
+//
+// Macros for flag manipulation.
+//
+#define HW_TEST_FLAG(x, f) ((x)->Flags & (f))
+#define HW_SET_FLAG(x, f) ((x)->Flags |= (f))
+#define HW_CLEAR_FLAG(x, f) ((x)->Flags &= ~(f))
+
+
+//
+// Flag definitions.
+//
+#define fHARDWARE_INFO_INTERRUPT_REGISTERED 0x00000001
+
+typedef struct _ADAPTER_BLOCK
+{
+ //
+ // Handle for use in calls into NDIS.
+ //
+ NDIS_HANDLE MiniportAdapterHandle;
+
+ ULONG References;
+ NDIS_SPIN_LOCK Lock;
+
+ //
+ // Flags describing the adapter state.
+ //
+ ULONG Flags;
+
+ ///
+ //
+ ///
+ PHARDWARE_INFO HardwareInfo;
+
+ ///
+ // List of the Vc's
+ //
+ // We maintain 2 lists of VCs. Those that have been activated
+ // and thoes that are not.
+ ///
+ LIST_ENTRY InactiveVcList;
+ LIST_ENTRY ActiveVcList;
+
+ //
+ // The following cannot be moved!!!!
+ // This is the hash list of a given VCI to it's PVC_BLOCK
+ //
+ PVC_BLOCK VcHashList[1];
+};
+
+//
+// Macros for adapter flag manipulation
+//
+#define ADAPTER_SET_FLAG(_adapter, _f) (_adapter)->Flags |= (_f)
+#define ADAPTER_CLEAR_FLAG(_adapter, _f) (_adapter)->Flags &= ~(_f)
+#define ADAPTER_TEST_FLAG(_adapter, _f) (((_adapter)->Flags & (_f)) != (_f))
+
+//
+// Flags for describing the Adapter state.
+//
+#define fADAPTER_RESET_IN_PROGRESS 0x00000001
+
+
+typedef struct _VC_BLOCK
+{
+ LIST_ENTRY Link;
+
+ PVC_BLOCK NextVcHash; // Pointer to the next VC in the hash list.
+
+ PADAPTER_BLOCK Adapter;
+ PHARDWARE_INFO HwInfo;
+ NDIS_HANDLE NdisVcHandle;
+
+ ULONG References; // Number of outstanding references
+ // on this VC.
+
+ NDIS_SPIN_LOCK Lock; // Protection for this structure.
+
+ ULONG Flags; // Flags describing vc state.
+
+ //
+ // ATM media parameters for this VC.
+ //
+ ULONG MediaFlags;
+
+ ATM_VPIVCI VpiVci; // VCI assigned to the VC.
+ ATM_AAL_TYPE AALType; // AAL type supported by this VC.
+
+ //
+ // The type of service for this VC.
+ //
+ ATM_SERVICE_CATEGORY ServiceCategory;
+
+ //
+ //
+ //
+ ULONG AverageCellRate;
+ ULONG PeakCellRate;
+ ULONG BurstLengthCells;
+
+ //
+ // Maximum length of the SDU...
+ //
+ ULONG MaxSduSize;
+
+ ATM_MEDIA_PARAMETERS MediaParameters;
+};
+
+//
+// Macros for VC flag manipulation
+//
+#define VC_SET_FLAG(_vc, _f) (_vc)->Flags |= (_f)
+#define VC_CLEAR_FLAG(_vc, _f) (_vc)->Flags &= ~(_f)
+#define VC_TEST_FLAG(_vc, _f) (((_vc)->Flags & (_f)) != (_f))
+
+//
+// Flags describing VC state.
+//
+#define fVC_ACTIVE 0x00000001
+#define fVC_DEACTIVATING 0x00000002
+#define fVC_TRANSMIT 0x00000004
+#define fVC_RECEIVE 0x00000008
+
+
+//
+//
+//
+#define aic5900ReferenceAdapter(_adapter) (_adapter)->References++
+#define aic5900DereferenceAdapter(_adapter) (_adapter)->References--
+
+#define aic5900ReferenceVc(_vc) (_vc)->References++
+
+#define aic5900DereferenceVc(_vc) \
+{ \
+ (_vc)->References--; \
+ if (((--(_vc)->References) == 0) && \
+ VC_TEST_FLAG((_vc), fVC_DEACTIVATING)) \
+ { \
+ aic5900DeactivateVcComplete((_vc)->Adapter, (_vc)); \
+ } \
+}
+
+#endif // __SW_H
+
diff --git a/private/ntos/ndis/aic5900/vc.c b/private/ntos/ndis/aic5900/vc.c
new file mode 100644
index 000000000..4e048e97b
--- /dev/null
+++ b/private/ntos/ndis/aic5900/vc.c
@@ -0,0 +1,593 @@
+
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ D:\nt\private\ntos\ndis\aic5900\vc.c
+
+Abstract:
+
+Author:
+
+ Kyle Brandon (KyleB)
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "aic5900.h"
+
+#define MODULE_NUMBER MODULE_VC
+
+NDIS_STATUS
+Aic5900CreateVc(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE NdisVcHandle,
+ OUT PNDIS_HANDLE MiniportVcContext
+ )
+/*++
+
+Routine Description:
+
+ This is the NDIS 4.1 handler to create a VC. This will allocate necessary
+ system resources for the VC.
+
+Arguments:
+
+ MiniportAdapterContext - Pointer to our ADAPTER_BLOCK.
+ NdisVcHandle - Handle that NDIS uses to identify the VC that
+ is about to be created.
+ MiniportVcContext - Storage to hold context information about
+ the newly created VC.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if we successfully create the new VC.
+
+--*/
+{
+ PADAPTER_BLOCK pAdapter = (PADAPTER_BLOCK)MiniportAdapterContext;
+ PVC_BLOCK pVc;
+ NDIS_STATUS Status;
+
+ DBGPRINT(DBG_COMP_VC, DBG_LEVEL_INFO,
+ ("==>Aic5900CreateVc\n"));
+
+ //
+ // I'm paranoid.
+ //
+ MiniportVcContext = NULL;
+
+ //
+ // Allocate memory for the VC.
+ //
+ ALLOCATE_MEMORY(&Status, &pVc, sizeof(VC_BLOCK));
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ //
+ // Initialize memory.
+ //
+ NdisZeroMemory(pVc, sizeof(VC_BLOCK));
+
+ //
+ // Save a pointer to the adapter block with the vc.
+ //
+ pVc->Adapter = pAdapter;
+ pVc->NdisVcHandle = NdisVcHandle;
+ pVc->References = 1;
+
+ NdisAllocateSpinLock(&pVc->Lock);
+
+ NdisAcquireSpinLock(&pAdapter->Lock);
+
+ //
+ // Add the VC to the adapter's inactive list.
+ //
+ InsertHeadList(&pAdapter->InactiveVcList, &pVc->Link);
+
+ //
+ // This adapter has another reference...
+ //
+ pAdapter->References++;
+
+ NdisReleaseSpinLock(&pAdapter->Lock);
+
+ //
+ // Return the pointer to the new VC as the context.
+ //
+ MiniportVcContext = (PNDIS_HANDLE)pVc;
+
+ DBGPRINT(DBG_COMP_VC, DBG_LEVEL_INFO,
+ ("<==Aic5900CreateVc\n"));
+
+ return(Status);
+}
+
+NDIS_STATUS
+Aic5900DeleteVc(
+ IN NDIS_HANDLE MiniportVcContext
+ )
+/*++
+
+Routine Description:
+
+ This is the NDIS 4.1 handler to delete a given VC. This routine will
+ free any resources that are associated with the VC. For the VC to
+ be deleted it MUST be deactivated first.
+
+Arguments:
+
+ MiniportVcContext - Pointer to the VC_BLOCK describing the VC that
+ is to be deleted.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if the VC is successfully deleted.
+
+--*/
+{
+ PVC_BLOCK pVc = (PVC_BLOCK)MiniportVcContext;
+ PADAPTER_BLOCK pAdapter = pVc->Adapter;
+
+ DBGPRINT(DBG_COMP_VC, DBG_LEVEL_INFO,
+ ("==>Aic5900DeleteVc\n"));
+
+ NdisAcquireSpinLock(&pAdapter->Lock);
+ NdisDprAcquireSpinLock(&pVc->Lock);
+
+ //
+ // Verify that this VC is inactive.
+ //
+ if (VC_TEST_FLAG(pVc, (fVC_ACTIVE | fVC_DEACTIVATING)))
+ {
+ //
+ // Cannot delete a VC that is still active.
+ //
+ NdisDprReleaseSpinLock(&pVc->Lock);
+ NdisReleaseSpinLock(&pAdapter->Lock);
+
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // If a VC is deactive then it had better have only the creation
+ // reference count on it!
+ //
+ ASSERT(1 == pVc->References);
+
+ //
+ // Remove the VC from the inactive list.
+ //
+ RemoveEntryList(&pVc->Link);
+
+ NdisDprReleaseSpinLock(&pVc->Lock);
+ NdisReleaseSpinLock(&pAdapter->Lock);
+
+ //
+ // Clean up the resources that were allocated on behalf of the
+ // VC_BLOCK.
+ //
+ NdisFreeSpinLock(&pVc->Lock);
+
+ //
+ // Free the memory that was taken by the vc.
+ //
+ FREE_MEMORY(pVc, sizeof(PVC_BLOCK));
+
+ DBGPRINT(DBG_COMP_VC, DBG_LEVEL_INFO,
+ ("<==Aic5900DeleteVc\n"));
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+aic5900AllocateTransmitSegment(
+ IN PADAPTER_BLOCK pAdapter,
+ IN PVC_BLOCK pVc,
+ IN PATM_MEDIA_PARAMETERS pMediaParms
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+
+ //
+ // We do different things based upon the service category.
+ //
+ switch (pMediaParms->Transmit.ServiceCategory)
+ {
+ case ATM_SERVICE_CATEGORY_UBR:
+
+ break;
+
+ case ATM_SERVICE_CATEGORY_CBR:
+
+ break;
+
+ default:
+
+ Status = NDIS_STATUS_INVALID_DATA;
+
+ break;
+ }
+
+ return(Status);
+}
+
+
+NDIS_STATUS
+aic5900ValidateVpiVci(
+ IN PADAPTER_BLOCK pAdapter,
+ IN PATM_MEDIA_PARAMETERS pMediaParms
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PVC_BLOCK pCurrentVc;
+ NDIS_STATUS Status;
+ BOOLEAN fInvalidVc = FALSE;
+
+ //
+ // We only support VPI of 0!
+ //
+ if (pMediaParms->ConnectionId.Vpi != 0)
+ {
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ if ((pMediaParms->ConnectionId.Vci < MIN_VCS) ||
+ (pMediaParms->ConnectionId.Vci > (MAX_VCS - 1)))
+ {
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // See if we have a VC with the given VPI/VCI
+ //
+ pCurrentVc = CONTAINING_RECORD(&pAdapter->ActiveVcList.Flink, VC_BLOCK, Link);
+ while (pCurrentVc != (PVC_BLOCK)&pAdapter->ActiveVcList)
+ {
+ if ((pCurrentVc->VpiVci.Vpi == pMediaParms->ConnectionId.Vpi) &&
+ (pCurrentVc->VpiVci.Vci == pMediaParms->ConnectionId.Vci))
+ {
+ fInvalidVc = TRUE;
+ break;
+ }
+
+ pCurrentVc = (PVC_BLOCK)pCurrentVc->Link.Flink;
+ }
+
+ //
+ // Did we find a VC with the given VPI/VCI.
+ //
+ if (fInvalidVc)
+ {
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+Aic5900ActivateVc(
+ IN NDIS_HANDLE MiniportVcContext,
+ IN PCO_MEDIA_PARAMETERS MediaParameters
+ )
+/*++
+
+Routine Description:
+
+ This is the NDIS 4.1 handler to activate a given VC. This will allocate
+ hardware resources, e.g. QoS, for a VC that was already created.
+
+Arguments:
+
+ MiniportVcContext - Pointer to the VC_BLOCK representing the VC to
+ activate.
+ MediaParameters - ATM parameters (in our case) that are used to
+ describe the VC.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if the VC is successfully activated.
+
+--*/
+{
+ PVC_BLOCK pVc = (PVC_BLOCK)MiniportVcContext;
+ PADAPTER_BLOCK pAdapter = pVc->Adapter;
+ PATM_MEDIA_PARAMETERS pMediaParms;
+ PVC_BLOCK pTempVc;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ DBGPRINT(DBG_COMP_VC, DBG_LEVEL_INFO,
+ ("==>Aic5900ActivateVc"));
+
+ NdisDprAcquireSpinLock(&pVc->Lock);
+
+ do
+ {
+ //
+ // If the VC is already active then we will need to
+ // re-activate the VC with new parameters.....
+ //
+ if (VC_TEST_FLAG(pVc, fVC_ACTIVE))
+ {
+ //
+ // Not ready for this yet....
+ //
+ DbgBreakPoint();
+ }
+
+ //
+ // Are there any media specific parameters that we recognize?
+ //
+ if ((MediaParameters->MediaSpecific.ParamType != ATM_MEDIA_SPECIFIC) ||
+ (MediaParameters->MediaSpecific.Length != sizeof(ATM_MEDIA_PARAMETERS)))
+ {
+ DBGPRINT(DBG_COMP_VC, DBG_LEVEL_ERR,
+ ("Invalid media parameters for vc creation\n"));
+
+ Status = NDIS_STATUS_INVALID_DATA;
+
+ break;
+ }
+
+ pMediaParms = (PATM_MEDIA_PARAMETERS)MediaParameters->MediaSpecific.Parameters;
+
+ //
+ // Validate the VPI/VCI
+ //
+ Status = aic5900ValidateVpiVci(pAdapter, pMediaParms);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ break;
+ }
+
+ //
+ // Save the VCI with our VC information.
+ //
+ pVc->VpiVci = pMediaParms->ConnectionId;
+
+ //
+ // Check the AAL type.
+ //
+ if ((pMediaParms->AALType & (AAL_TYPE_AAL0 | AAL_TYPE_AAL5)) !=
+ (AAL_TYPE_AAL0 | AAL_TYPE_AAL5))
+ {
+ Status = NDIS_STATUS_INVALID_DATA;
+
+ break;
+ }
+
+ //
+ // Save the AAL information with our VC.
+ //
+ pVc->AALType = pMediaParms->AALType;
+
+ //
+ // Verify that we can support the given VC parameters.
+ //
+ if ((pVc->MediaFlags & TRANSMIT_VC) == TRANSMIT_VC)
+ {
+ VC_SET_FLAG(pVc, fVC_TRANSMIT);
+
+ //
+ // Allocate transmit resources.
+ //
+ Status = aic5900AllocateTransmitSegment(pAdapter, pVc, pMediaParms);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+
+
+ }
+ }
+
+ if ((pVc->MediaFlags & RECEIVE_VC) == RECEIVE_VC)
+ {
+ VC_SET_FLAG(pVc, fVC_RECEIVE);
+
+ //
+ // Allocate receive resources.
+ //
+
+ }
+
+ VC_SET_FLAG(pVc, fVC_ACTIVE);
+
+ } while (FALSE);
+
+ NdisDprReleaseSpinLock(&pVc->Lock);
+ NdisReleaseSpinLock(&pAdapter->Lock);
+
+ DBGPRINT(DBG_COMP_VC, DBG_LEVEL_INFO,
+ ("<==Aic5900ActivateVc"));
+
+ return(Status);
+}
+
+NDIS_STATUS
+Aic5900DeactivateVc(
+ IN NDIS_HANDLE MiniportVcContext
+ )
+/*++
+
+Routine Description:
+
+ This is the NDIS 4.1 handler to deactivate a given VC.
+ This does not free any resources, but simply marks the VC as unusable.
+
+Arguments:
+
+ MiniportVcContext - Pointer to our VC_BLOCK that was allocated in
+ Aic5900CreateVc().
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if we successfully deactivate the VC.
+
+--*/
+{
+ PVC_BLOCK pVc = (PVC_BLOCK)MiniportVcContext;
+ PADAPTER_BLOCK pAdapter = pVc->Adapter;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ DBGPRINT(DBG_COMP_VC, DBG_LEVEL_INFO,
+ ("==>Aic5900DeactivateVc\n"));
+
+ NdisAcquireSpinLock(&pAdapter->Lock);
+
+ if (ADAPTER_TEST_FLAG(pAdapter, fADAPTER_RESET_IN_PROGRESS))
+ {
+ NdisReleaseSpinLock(&pAdapter->Lock);
+
+ return(NDIS_STATUS_RESET_IN_PROGRESS);
+ }
+
+ NdisDprAcquireSpinLock(&pVc->Lock);
+
+ do
+ {
+ if (!VC_TEST_FLAG(pVc, fVC_ACTIVE) ||
+ VC_TEST_FLAG(pVc, fVC_DEACTIVATING))
+ {
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // Mark the VC.
+ //
+ VC_CLEAR_FLAG(pVc, fVC_ACTIVE);
+
+ //
+ // Can't deactivate a VC with outstanding references....
+ //
+ if (pVc->References > 1)
+ {
+ Status = NDIS_STATUS_PENDING;
+
+ break;
+ }
+
+ aic5900DeactivateVcComplete(pAdapter, pVc);
+
+ } while (FALSE);
+
+ //
+ // If we are pending the deactivation then mark the VC as
+ // deactivating.
+ //
+ if (Status == NDIS_STATUS_PENDING)
+ {
+ VC_SET_FLAG(pVc, fVC_DEACTIVATING);
+ }
+
+ NdisDprReleaseSpinLock(&pVc->Lock);
+ NdisReleaseSpinLock(&pAdapter->Lock);
+
+ DBGPRINT(DBG_COMP_VC, DBG_LEVEL_INFO,
+ ("<==Aic5900DeactivateVc\n"));
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+VOID
+aic5900DeactivateVcComplete(
+ IN PADAPTER_BLOCK pAdapter,
+ IN PVC_BLOCK pVc
+ )
+/*++
+
+Routine Description:
+
+ This routine is called to complete the deactivation of the VC.
+ this does NOT call NdisMCoDeactivateVcComplete() it is simply a place
+ to put common code...
+
+Arguments:
+
+ pAdapter - Pointer to the ADAPTER_BLOCK owning the VC.
+ pVc - Pointer to the VC that is being deactivated.
+
+Return Value:
+
+
+Notes:
+
+ THIS ROUTINE MUST BE CALLED WITH BOTH THE ADAPTER_BLOCK AND THE VC'S
+ LOCKS ACQUIRED!!!!!
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ DBGPRINT(DBG_COMP_VC, DBG_LEVEL_INFO,
+ ("==>DeactivateVcComplete\n"));
+
+ ASSERT(!VC_TEST_FLAG(pVc, fVC_ACTIVE));
+ ASSERT(pVc->References == 1);
+
+ //
+ // Remove the VC from the active list and place it on the inactive list.
+ //
+ RemoveEntryList(&pVc->Link);
+ InsertHeadList(&pAdapter->InactiveVcList, &pVc->Link);
+
+ //
+ // Free up an transmit resources...
+ //
+ if (VC_TEST_FLAG(pVc, fVC_TRANSMIT))
+ {
+
+ }
+
+ //
+ // Free up any receive resources...
+ //
+ if (VC_TEST_FLAG(pVc, fVC_RECEIVE))
+ {
+
+
+ }
+
+ //
+ // If this is a pending call then complete the deactivation back to
+ // the call manager.
+ //
+ if (VC_TEST_FLAG(pVc, fVC_DEACTIVATING))
+ {
+ NdisDprReleaseSpinLock(&pVc->Lock);
+ NdisReleaseSpinLock(&pAdapter->Lock);
+
+ NdisMCoDeactivateVcComplete(Status, pVc->NdisVcHandle);
+
+ NdisAcquireSpinLock(&pAdapter->Lock);
+ NdisDprAcquireSpinLock(&pVc->Lock);
+ }
+
+ DBGPRINT(DBG_COMP_VC, DBG_LEVEL_INFO,
+ ("<==DeactivateVcComplete\n"));
+}
diff --git a/private/ntos/ndis/dc21x4.bc/alloc.c b/private/ntos/ndis/dc21x4.bc/alloc.c
new file mode 100644
index 000000000..1cf6113b9
--- /dev/null
+++ b/private/ntos/ndis/dc21x4.bc/alloc.c
@@ -0,0 +1 @@
+#include <..\dc21x4\alloc.c>
diff --git a/private/ntos/ndis/dc21x4.bc/copy.c b/private/ntos/ndis/dc21x4.bc/copy.c
new file mode 100644
index 000000000..e6eda3707
--- /dev/null
+++ b/private/ntos/ndis/dc21x4.bc/copy.c
@@ -0,0 +1 @@
+#include <..\dc21x4\copy.c>
diff --git a/private/ntos/ndis/dc21x4.bc/dc21x4.c b/private/ntos/ndis/dc21x4.bc/dc21x4.c
new file mode 100644
index 000000000..edae3acae
--- /dev/null
+++ b/private/ntos/ndis/dc21x4.bc/dc21x4.c
@@ -0,0 +1 @@
+#include <..\dc21x4\dc21x4.c>
diff --git a/private/ntos/ndis/dc21x4.bc/dc21x4.rc b/private/ntos/ndis/dc21x4.bc/dc21x4.rc
new file mode 100644
index 000000000..1509f3b2d
--- /dev/null
+++ b/private/ntos/ndis/dc21x4.bc/dc21x4.rc
@@ -0,0 +1,2 @@
+#include <..\dc21x4\dc21x4.rc>
+
diff --git a/private/ntos/ndis/dc21x4.bc/filter.c b/private/ntos/ndis/dc21x4.bc/filter.c
new file mode 100644
index 000000000..f8d24c318
--- /dev/null
+++ b/private/ntos/ndis/dc21x4.bc/filter.c
@@ -0,0 +1 @@
+#include <..\dc21x4\filter.c>
diff --git a/private/ntos/ndis/dc21x4.bc/init.c b/private/ntos/ndis/dc21x4.bc/init.c
new file mode 100644
index 000000000..c685e3878
--- /dev/null
+++ b/private/ntos/ndis/dc21x4.bc/init.c
@@ -0,0 +1 @@
+#include <..\dc21x4\init.c>
diff --git a/private/ntos/ndis/dc21x4.bc/interrup.c b/private/ntos/ndis/dc21x4.bc/interrup.c
new file mode 100644
index 000000000..bffe64c70
--- /dev/null
+++ b/private/ntos/ndis/dc21x4.bc/interrup.c
@@ -0,0 +1 @@
+#include <..\dc21x4\interrup.c>
diff --git a/private/ntos/ndis/dc21x4.bc/mactophy.c b/private/ntos/ndis/dc21x4.bc/mactophy.c
new file mode 100644
index 000000000..1abda33af
--- /dev/null
+++ b/private/ntos/ndis/dc21x4.bc/mactophy.c
@@ -0,0 +1,2 @@
+#include <..\dc21x4\mactophy.c>
+
diff --git a/private/ntos/ndis/dc21x4.bc/makefile b/private/ntos/ndis/dc21x4.bc/makefile
new file mode 100644
index 000000000..58189757d
--- /dev/null
+++ b/private/ntos/ndis/dc21x4.bc/makefile
@@ -0,0 +1,7 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the driver components of the Windows NT DDK
+#
+
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/dc21x4.bc/media.c b/private/ntos/ndis/dc21x4.bc/media.c
new file mode 100644
index 000000000..6a114878f
--- /dev/null
+++ b/private/ntos/ndis/dc21x4.bc/media.c
@@ -0,0 +1 @@
+#include <..\dc21x4\media.c>
diff --git a/private/ntos/ndis/dc21x4.bc/miigen.c b/private/ntos/ndis/dc21x4.bc/miigen.c
new file mode 100644
index 000000000..e5c896a46
--- /dev/null
+++ b/private/ntos/ndis/dc21x4.bc/miigen.c
@@ -0,0 +1,2 @@
+#include <..\dc21x4\miigen.c>
+
diff --git a/private/ntos/ndis/dc21x4.bc/miiphy.c b/private/ntos/ndis/dc21x4.bc/miiphy.c
new file mode 100644
index 000000000..bd227d572
--- /dev/null
+++ b/private/ntos/ndis/dc21x4.bc/miiphy.c
@@ -0,0 +1,2 @@
+#include <..\dc21x4\miiphy.c>
+
diff --git a/private/ntos/ndis/dc21x4.bc/monitor.c b/private/ntos/ndis/dc21x4.bc/monitor.c
new file mode 100644
index 000000000..0df5fd0cf
--- /dev/null
+++ b/private/ntos/ndis/dc21x4.bc/monitor.c
@@ -0,0 +1 @@
+#include <..\dc21x4\monitor.c>
diff --git a/private/ntos/ndis/dc21x4.bc/register.c b/private/ntos/ndis/dc21x4.bc/register.c
new file mode 100644
index 000000000..419da3ed2
--- /dev/null
+++ b/private/ntos/ndis/dc21x4.bc/register.c
@@ -0,0 +1 @@
+#include <..\dc21x4\register.c>
diff --git a/private/ntos/ndis/dc21x4.bc/request.c b/private/ntos/ndis/dc21x4.bc/request.c
new file mode 100644
index 000000000..f63f2bdec
--- /dev/null
+++ b/private/ntos/ndis/dc21x4.bc/request.c
@@ -0,0 +1 @@
+#include <..\dc21x4\request.c>
diff --git a/private/ntos/ndis/dc21x4.bc/reset.c b/private/ntos/ndis/dc21x4.bc/reset.c
new file mode 100644
index 000000000..2b8625576
--- /dev/null
+++ b/private/ntos/ndis/dc21x4.bc/reset.c
@@ -0,0 +1 @@
+#include <..\dc21x4\reset.c>
diff --git a/private/ntos/ndis/dc21x4.bc/send.c b/private/ntos/ndis/dc21x4.bc/send.c
new file mode 100644
index 000000000..196f8066c
--- /dev/null
+++ b/private/ntos/ndis/dc21x4.bc/send.c
@@ -0,0 +1 @@
+#include <..\dc21x4\send.c>
diff --git a/private/ntos/ndis/dc21x4.bc/sources b/private/ntos/ndis/dc21x4.bc/sources
new file mode 100644
index 000000000..ecd972a06
--- /dev/null
+++ b/private/ntos/ndis/dc21x4.bc/sources
@@ -0,0 +1,49 @@
+!if 0
+ Copyright (C) 1992-1995 by Digital Equipment Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the DC21X4 NDIS3 miniport driver being built
+ and the list of sources files needed to build it.
+ It specifies also the compiler switches specific to this driver
+
+Author:
+
+ Philippe Klein
+
+!endif
+
+TARGETNAME=DC21X4BC
+TARGETTYPE=DRIVER
+
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+INCLUDES=..\..\inc;..\dc21x4
+
+C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER
+C_DEFINES=$(C_DEFINES) -DNDIS40_MINIPORT
+LINKER_FLAGS=$(LINKER_FLAGS) /map
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=alloc.c \
+ copy.c \
+ dc21x4.c \
+ filter.c \
+ init.c \
+ interrup.c \
+ media.c \
+ register.c \
+ request.c \
+ reset.c \
+ send.c \
+ monitor.c \
+ srom.c \
+ mactophy.c \
+ miigen.c \
+ miiphy.c \
+ dc21x4.rc
diff --git a/private/ntos/ndis/dc21x4.bc/srom.c b/private/ntos/ndis/dc21x4.bc/srom.c
new file mode 100644
index 000000000..b94a064b0
--- /dev/null
+++ b/private/ntos/ndis/dc21x4.bc/srom.c
@@ -0,0 +1 @@
+#include <..\dc21x4\srom.c>
diff --git a/private/ntos/ndis/dc21x4.bc/transfer.c b/private/ntos/ndis/dc21x4.bc/transfer.c
new file mode 100644
index 000000000..63c85cc8c
--- /dev/null
+++ b/private/ntos/ndis/dc21x4.bc/transfer.c
@@ -0,0 +1 @@
+#include <..\dc21x4\transfer.c>
diff --git a/private/ntos/ndis/dc21x4/alloc.c b/private/ntos/ndis/dc21x4/alloc.c
new file mode 100644
index 000000000..90d5fbea2
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/alloc.c
@@ -0,0 +1,825 @@
+/*+
+ * file: alloc.c
+ *
+ * Copyright (C) 1994 by
+ * Digital Equipment Corporation, Maynard, Massachusetts.
+ * All rights reserved.
+ *
+ * This software is furnished under a license and may be used and copied
+ * only in accordance of the terms of such license and with the
+ * inclusion of the above copyright notice. This software or any other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person. No title to and ownership of the software is hereby
+ * transferred.
+ *
+ * The information in this software is subject to change without notice
+ * and should not be construed as a commitment by digital equipment
+ * corporation.
+ *
+ * Digital assumes no responsibility for the use or reliability of its
+ * software on equipment which is not supplied by digital.
+ *
+ *
+ * Abstract: This file is part of the NDIS 4.0 miniport driver for
+ * DEC's DC21X4 Ethernet controller family.
+ *
+ *
+ * Author: Philippe Klein
+ *
+ * Revision History:
+ *
+ * phk 31-Jul-1994 Initial entry
+ * phk 11-Dec-1994 Allocate the shared data buffers in
+ * cached memory.
+ *
+-*/
+
+#include <precomp.h>
+
+#pragma NDIS_PAGABLE_FUNCTION(AllocateAdapterMemory)
+#pragma NDIS_PAGABLE_FUNCTION(FreeAdapterMemory)
+#pragma NDIS_PAGABLE_FUNCTION(AlignStructure)
+
+
+
+
+
+
+
+
+
+
+/*+
+ *
+ * AllocateAdapterMemory
+ *
+ * Routine Description:
+ *
+ * This routine allocates memory for:
+ *
+ * - Transmit descriptor ring
+ * - Receive descriptor ring
+ * - Receive buffers
+ * - Transmit buffer
+ * - Setup buffer
+ *
+ * Arguments:
+ *
+ * Adapter - The adapter to allocate memory for.
+ *
+ * Functional description
+ *
+ * For each allocated zone, we maintain a set of pointers:
+ * - virtual & physical addresses of the allocated block
+ * - virtual & physical addresses of the aligned structure (descriptor ring, buffer,...)
+ * whithin the block
+ *
+ * Return Value:
+ *
+ * Returns FALSE if an allocation fails.
+ *
+-*/
+extern
+BOOLEAN
+AllocateAdapterMemory(
+ IN PDC21X4_ADAPTER Adapter
+ )
+{
+ PDC21X4_TRANSMIT_DESCRIPTOR TransmitDescriptor;
+ PDC21X4_RECEIVE_DESCRIPTOR ReceiveDescriptor;
+
+ NDIS_STATUS Status;
+
+ PRCV_HEADER RcvHeader;
+ PNDIS_PACKET Packet;
+
+ ULONG AllocSize;
+ PULONG AllocVa;
+ NDIS_PHYSICAL_ADDRESS AllocPa;
+ ULONG Va;
+
+ ULONG Pa;
+
+ UINT i;
+ ULONG Offset;
+
+ INT TransmitDescriptorRingSize;
+ INT ReceiveDescriptorRingSize;
+
+ Adapter->RcvHeaderSize =
+ ((RCV_HEADER_SIZE + Adapter->CacheLineSize - 1) / Adapter->CacheLineSize)
+ * Adapter->CacheLineSize;
+
+
+#if _DBG
+ DbgPrint("Alloc Rcv_ring[%d desc.], Txm_ring[%d desc.], setup_buf[%d]...\n",
+ Adapter->ReceiveRingSize,
+ TRANSMIT_RING_SIZE,
+ DC21X4_SETUP_BUFFER_SIZE
+ );
+#endif
+
+ // Allocate space for transmit descriptor ring,
+ // the receive descriptor ring and the setup buffer
+
+ TransmitDescriptorRingSize =
+ Adapter->DescriptorSize * TRANSMIT_RING_SIZE;
+ ReceiveDescriptorRingSize =
+ Adapter->DescriptorSize * Adapter->ReceiveRingSize;
+
+ Adapter->DescriptorRing.AllocSize =
+ TransmitDescriptorRingSize
+ + ReceiveDescriptorRingSize
+ + DC21X4_SETUP_BUFFER_SIZE
+ + Adapter->CacheLineSize;
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ Adapter->DescriptorRing.AllocSize,
+ FALSE, // NON-CACHED
+ (PVOID *)&Adapter->DescriptorRing.AllocVa, // virtual ...
+ &Adapter->DescriptorRing.AllocPa // and physical address of the allocation
+ );
+
+ // Check the allocation success
+
+ if ((PVOID)Adapter->DescriptorRing.AllocVa == (PVOID)NULL) {
+ return FALSE;
+ }
+ if (NdisGetPhysicalAddressHigh(Adapter->DescriptorRing.AllocPa) != 0) {
+ return FALSE;
+ }
+
+ NdisZeroMemory (
+ (PVOID)(Adapter->DescriptorRing.AllocVa),
+ (ULONG)(Adapter->DescriptorRing.AllocSize)
+ );
+
+ // Align to the next cache line boundary
+
+ AlignStructure (
+ &Adapter->DescriptorRing,
+ Adapter->CacheLineSize
+ );
+
+ Adapter->TransmitDescriptorRingVa = Adapter->DescriptorRing.Va;
+ Adapter->TransmitDescriptorRingPa = Adapter->DescriptorRing.Pa;
+ Offset = TransmitDescriptorRingSize;
+
+ Adapter->ReceiveDescriptorRingVa = Adapter->DescriptorRing.Va + Offset;
+ Adapter->ReceiveDescriptorRingPa = Adapter->DescriptorRing.Pa + Offset;
+ Offset += ReceiveDescriptorRingSize;
+
+ Adapter->SetupBufferVa = Adapter->DescriptorRing.Va + Offset;
+ Adapter->SetupBufferPa = Adapter->DescriptorRing.Pa + Offset;
+
+ //Initialize the setup buffer
+
+ NdisZeroMemory (
+ (PVOID)(Adapter->SetupBufferVa),
+ DC21X4_SETUP_BUFFER_SIZE
+ );
+
+
+ // Allocate a pool of NDIS buffers
+
+ NdisAllocateBufferPool(
+ &Status,
+ &Adapter->FlushBufferPoolHandle,
+ ( Adapter->ReceiveRingSize
+ + Adapter->ExtraReceiveBuffers
+ + DC21X4_NUMBER_OF_MAX_TRANSMIT_BUFFERS
+ + DC21X4_NUMBER_OF_MIN_TRANSMIT_BUFFERS )
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ return FALSE;
+ }
+
+
+ // Allocate a pool of packets.
+#if _DBG
+ DbgPrint("Allocate PacketPool [%d packets]\n",
+ Adapter->ExtraReceivePackets);
+#endif
+ NdisAllocatePacketPool(
+ &Status,
+ &Adapter->ReceivePacketPool,
+ Adapter->ExtraReceivePackets,
+ 0
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ return FALSE;
+ }
+
+ // Allocate all of the packets out of the packet pool
+ // and place them on a queue.
+
+ for (i = 0; i < Adapter->ExtraReceivePackets; i++) {
+
+ // Allocate a packet from the pool.
+ NdisAllocatePacket(
+ &Status,
+ &Packet,
+ Adapter->ReceivePacketPool
+ );
+ if (Status != NDIS_STATUS_SUCCESS) {
+ return(FALSE);
+ }
+
+ // Set the header size in the packet's Out-Of-Band information.
+ // All other fields in the Out-Of-Band information have been
+ // initialized to 0 by NdisAllocatePacket().
+
+ NDIS_SET_PACKET_HEADER_SIZE(Packet, ETH_HEADER_SIZE);
+
+ // Place it on the receive packet free list.
+
+ RCV_RESERVED(Packet)->Next = Adapter->FreePacketList;
+ Adapter->FreePacketList = Packet;
+ }
+
+ // Clear out the free receive list of buffers.
+ Adapter->FreeRcvList = NULL;
+
+
+ // We allocate the receive buffers. We allocate both
+ // the buffers for the descriptor ring and the extra
+ // buffers and place them all on the free queue.
+
+#if _DBG
+ DbgPrint("Allocate Receive Buffers [%d]\n",
+ Adapter->ExtraReceiveBuffers+Adapter->ReceiveRingSize);
+#endif
+
+ // Attempt to allocate all the receive buffer space
+ // in one block
+ // If it fails,allocate each buffer individually
+
+ // Allocation size
+ Adapter->RcvBufferSpace.AllocSize =
+ ((Adapter->ExtraReceiveBuffers + Adapter->ReceiveRingSize)
+ * (DC21X4_RECEIVE_BUFFER_SIZE + Adapter->RcvHeaderSize))
+ + Adapter->CacheLineSize;
+
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ Adapter->RcvBufferSpace.AllocSize,
+ TRUE,
+ (PVOID *)&Adapter->RcvBufferSpace.AllocVa,
+ &Adapter->RcvBufferSpace.AllocPa
+ );
+
+ // Check the allocation success
+ if (((PVOID)Adapter->RcvBufferSpace.AllocVa != (PVOID)NULL)
+ && (NdisGetPhysicalAddressHigh(Adapter->RcvBufferSpace.AllocPa) == 0)) {
+
+ NdisZeroMemory (
+ (PVOID)(Adapter->RcvBufferSpace.AllocVa),
+ (ULONG)(Adapter->RcvBufferSpace.AllocSize)
+ );
+
+ // Align to the next cache line boundary
+
+ AlignStructure (
+ &Adapter->RcvBufferSpace,
+ Adapter->CacheLineSize
+ );
+
+ // Allocation size needed for the receive buffer
+ AllocSize = DC21X4_RECEIVE_BUFFER_SIZE
+ + Adapter->RcvHeaderSize;
+ Offset=0;
+ }
+ else
+ {
+ // Allocation size needed for the receive buffer
+ AllocSize = DC21X4_RECEIVE_BUFFER_SIZE
+ + Adapter->RcvHeaderSize
+ + Adapter->CacheLineSize;
+
+
+ Adapter->RcvBufferSpace.Va=0;
+ }
+
+ for (i = 0;
+ i < (Adapter->ExtraReceiveBuffers + Adapter->ReceiveRingSize);
+ i++
+ ) {
+
+ if (Adapter->RcvBufferSpace.Va != 0) {
+
+ Va = Adapter->RcvBufferSpace.Va + Offset;
+ Pa = Adapter->RcvBufferSpace.Pa + Offset;
+ Offset += AllocSize;
+
+ }
+ else
+ {
+ // Allocate a receive buffer.
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ AllocSize,
+ TRUE,
+ (PVOID *)&AllocVa,
+ &AllocPa
+ );
+ if (((PVOID)AllocVa == (PVOID)NULL)
+ || (NdisGetPhysicalAddressHigh(AllocPa) != 0)) {
+ return FALSE;
+ }
+
+ NdisZeroMemory(AllocVa, AllocSize);
+
+ // Align on the cache line boundary
+
+ Offset = Adapter->CacheLineSize - ((ULONG)AllocVa % Adapter->CacheLineSize);
+ Va = (ULONG)(AllocVa) + Offset;
+ Pa = NdisGetPhysicalAddressLow(AllocPa) + Offset;
+
+ }
+
+ //The receive header points to the aligned va.
+
+ RcvHeader = (PRCV_HEADER)Va;
+
+ RcvHeader->AllocVa = (ULONG)AllocVa;
+ RcvHeader->AllocPa = AllocPa;
+ RcvHeader->AllocSize = (USHORT)AllocSize;
+
+ // These addresses point to the data buffer
+
+ RcvHeader->Va = (ULONG)(Va + Adapter->RcvHeaderSize);
+ RcvHeader->Pa = Pa + Adapter->RcvHeaderSize;
+ RcvHeader->Size = DC21X4_RECEIVE_BUFFER_SIZE;
+
+#if DBG
+ RcvHeader->Signature = 'dHxR';
+#if _DBG
+ DbgPrint(
+ "%-3d RcvHeader: %lx, RcvBuffer: %lx/%lx, HeaderSize: %lx\n",
+ i,RcvHeader,
+ RcvHeader->Va,
+ RcvHeader->Pa,
+ Adapter->RcvHeaderSize
+ );
+#endif
+#endif
+ // Allocate an NDIS flush buffer for each receive buffer.
+
+ NdisAllocateBuffer(
+ &Status,
+ &RcvHeader->FlushBuffer,
+ Adapter->FlushBufferPoolHandle,
+ (PVOID)RcvHeader->Va,
+ DC21X4_RECEIVE_BUFFER_SIZE
+ );
+ if (Status != NDIS_STATUS_SUCCESS) {
+ return FALSE;
+ }
+
+ // Grab a packet off of the free packet list and
+ // associate it with the buffer.
+
+ Packet = Adapter->FreePacketList;
+ Adapter->FreePacketList = RCV_RESERVED(Packet)->Next;
+
+ // Chain the buffer on the packet.
+
+ NdisChainBufferAtFront(Packet, RcvHeader->FlushBuffer);
+
+ // Save a pointer to the receive header with the packet.
+
+ RCV_RESERVED(Packet)->RcvHeader = RcvHeader;
+
+ // Save the packet with the receive header.
+
+ RcvHeader->Packet = Packet;
+
+ // Place the descriptor on the free queue.
+
+ RcvHeader->Next = Adapter->FreeRcvList;
+ Adapter->FreeRcvList = RcvHeader;
+
+ Adapter->CurrentReceiveBufferCount++;
+ }
+
+
+#if _DBG
+ DbgPrint("Init Rcv ring..\n");
+#endif
+
+ // Assign the receive buffers to the descriptors.
+
+ for (i = 0,
+ ReceiveDescriptor = (PDC21X4_RECEIVE_DESCRIPTOR)Adapter->ReceiveDescriptorRingVa,
+ Pa = Adapter->ReceiveDescriptorRingPa;
+ i < Adapter->ReceiveRingSize;
+ i++,
+ (PCHAR)ReceiveDescriptor += Adapter->DescriptorSize,
+ Pa += Adapter->DescriptorSize
+ ) {
+
+ // Grab a receive buffer from the free list.
+
+ ASSERT(Adapter->FreeRcvList != NULL);
+ RcvHeader = Adapter->FreeRcvList;
+ Adapter->FreeRcvList = RcvHeader->Next;
+
+ Adapter->CurrentReceiveBufferCount--;
+
+ // Associate the buffer with the descriptor.
+
+ ReceiveDescriptor->RcvHeader = RcvHeader;
+ ReceiveDescriptor->FirstBufferAddress = RcvHeader->Pa;
+
+
+ ReceiveDescriptor->Status = DESC_OWNED_BY_DC21X4;
+ ReceiveDescriptor->Control = DC21X4_RECEIVE_BUFFER_SIZE;
+
+ ReceiveDescriptor->Next =
+ (PDC21X4_RECEIVE_DESCRIPTOR)((PCHAR)ReceiveDescriptor + Adapter->DescriptorSize);
+
+ }
+
+ //last descriptor of the ring
+
+ (PCHAR)ReceiveDescriptor -= Adapter->DescriptorSize;
+ ReceiveDescriptor->Control |= DC21X4_RDES_SECOND_ADDR_CHAINED;
+ ReceiveDescriptor->SecondBufferAddress = Adapter->ReceiveDescriptorRingPa;
+ ReceiveDescriptor->Next =
+ (PDC21X4_RECEIVE_DESCRIPTOR)Adapter->ReceiveDescriptorRingVa;
+
+#if _DBG
+ DbgPrint("Init Txm ring..\n");
+#endif
+
+ // Initialize the Transmit Descriptor ring
+
+ for (i=0,
+ TransmitDescriptor = (PDC21X4_TRANSMIT_DESCRIPTOR)Adapter->TransmitDescriptorRingVa,
+ Pa = Adapter->TransmitDescriptorRingPa;
+ i < TRANSMIT_RING_SIZE;
+ i++,
+ (PCHAR)TransmitDescriptor += Adapter->DescriptorSize,
+ Pa += Adapter->DescriptorSize
+ ) {
+
+ TransmitDescriptor->MapTableIndex = i * NUMBER_OF_SEGMENT_PER_DESC;
+ TransmitDescriptor->DescriptorPa = Pa;
+ TransmitDescriptor->Next =
+ (PDC21X4_TRANSMIT_DESCRIPTOR)((PCHAR)TransmitDescriptor + Adapter->DescriptorSize);
+
+ }
+
+ //last descriptor of the ring
+ (PCHAR)TransmitDescriptor -= Adapter->DescriptorSize;
+ TransmitDescriptor->Control = DC21X4_TDES_SECOND_ADDR_CHAINED;
+ TransmitDescriptor->SecondBufferAddress = Adapter->TransmitDescriptorRingPa;
+ TransmitDescriptor->Next =
+ (PDC21X4_TRANSMIT_DESCRIPTOR)Adapter->TransmitDescriptorRingVa;
+
+
+ // Txm buffers
+
+ for (i = 0;i < DC21X4_NUMBER_OF_MAX_TRANSMIT_BUFFERS;i ++) {
+
+ Adapter->MaxTransmitBuffer[i].AllocSize =
+ DC21X4_MAX_TRANSMIT_BUFFER_SIZE + Adapter->CacheLineSize;
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ Adapter->MaxTransmitBuffer[i].AllocSize,
+ TRUE, // CACHED
+ (PVOID *)&Adapter->MaxTransmitBuffer[i].AllocVa, // virtual ...
+ &Adapter->MaxTransmitBuffer[i].AllocPa // and physical address of the buffer allocation
+ );
+
+ // Check the allocation success
+
+ if (((PVOID)Adapter->MaxTransmitBuffer[i].AllocVa == (PVOID)NULL)
+ || (NdisGetPhysicalAddressHigh(Adapter->MaxTransmitBuffer[i].AllocPa) != 0)) {
+ return FALSE;
+ }
+
+ // Align the buffer on the cache line boundary
+
+ AlignStructure (
+ &Adapter->MaxTransmitBuffer[i],
+ Adapter->CacheLineSize
+ );
+
+
+ // Allocate an NDIS flush buffer for each transmit buffer
+
+ NdisAllocateBuffer(
+ &Status,
+ &Adapter->MaxTransmitBuffer[i].FlushBuffer,
+ Adapter->FlushBufferPoolHandle,
+ (PVOID)Adapter->MaxTransmitBuffer[i].Va,
+ DC21X4_MAX_TRANSMIT_BUFFER_SIZE
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ return FALSE;
+ }
+ }
+
+ // Allocate the minimal packet buffers
+
+ Adapter->MinTransmitBuffer[0].AllocSize =
+ (DC21X4_NUMBER_OF_MIN_TRANSMIT_BUFFERS * DC21X4_MIN_TRANSMIT_BUFFER_SIZE)
+ + Adapter->CacheLineSize;
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ Adapter->MinTransmitBuffer[0].AllocSize,
+ TRUE, // CACHED
+ (PVOID *)&Adapter->MinTransmitBuffer[0].AllocVa, // virtual ...
+ &Adapter->MinTransmitBuffer[0].AllocPa // and physical address of the buffer allocation
+ );
+
+ // Check the allocation success
+
+ if (((PVOID)Adapter->MinTransmitBuffer[0].AllocVa == (PVOID)NULL)
+ || (NdisGetPhysicalAddressHigh(Adapter->MinTransmitBuffer[0].AllocPa) != 0)) {
+
+ Adapter->DontUseMinTransmitBuffer = TRUE;
+ return TRUE;
+ }
+
+ // Align the buffer on the cache line boundary
+
+ AlignStructure (
+ &Adapter->MinTransmitBuffer[0],
+ Adapter->CacheLineSize
+ );
+
+ for (i = 0;i < DC21X4_NUMBER_OF_MIN_TRANSMIT_BUFFERS;i ++) {
+
+ Offset = i * DC21X4_MIN_TRANSMIT_BUFFER_SIZE;
+
+ Adapter->MinTransmitBuffer[i].Va =
+ Adapter->MinTransmitBuffer[0].Va + Offset;
+
+ Adapter->MinTransmitBuffer[i].Pa =
+ Adapter->MinTransmitBuffer[0].Pa + Offset;
+
+ // Allocate an NDIS flush buffer for each transmit buffer
+
+ NdisAllocateBuffer(
+ &Status,
+ &Adapter->MinTransmitBuffer[i].FlushBuffer,
+ Adapter->FlushBufferPoolHandle,
+ (PVOID)Adapter->MinTransmitBuffer[i].Va,
+ DC21X4_MIN_TRANSMIT_BUFFER_SIZE
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ return FALSE;
+ }
+ }
+
+ // Allocation has completed successfully
+
+ return TRUE;
+}
+
+
+
+
+
+
+
+
+/*+
+ *
+ * FreeAdapterMemory
+ *
+ * Routine Description:
+ *
+ * Frees the memory previously allocated by
+ * AllocateAdapterMemory
+ *
+ * Arguments:
+ *
+ * Adapter - The adapter to deallocate memory for.
+ *
+ * Return Value:
+ *
+ * None.
+ *
+-*/
+extern
+VOID
+FreeAdapterMemory(
+ IN PDC21X4_ADAPTER Adapter
+ )
+{
+
+ PDC21X4_RECEIVE_DESCRIPTOR ReceiveDescriptor;
+ PRCV_HEADER RcvHeader;
+ PNDIS_PACKET Packet;
+ UINT i;
+
+ if ((PVOID)Adapter->DescriptorRing.AllocVa == (PVOID)NULL) {
+ // AllocateAdapterMemory failed on the first allocation:
+ // no ressources were allocated
+ return;
+ }
+
+ for (i = 0,
+ ReceiveDescriptor = (PDC21X4_RECEIVE_DESCRIPTOR)Adapter->ReceiveDescriptorRingVa;
+ i < Adapter->ReceiveRingSize;
+ i++,
+ (PCHAR)ReceiveDescriptor += Adapter->DescriptorSize
+ ) {
+
+ if (ReceiveDescriptor->RcvHeader) {
+
+ RcvHeader = ReceiveDescriptor->RcvHeader;
+
+ if (RcvHeader->FlushBuffer) {
+ NdisFreeBuffer(RcvHeader->FlushBuffer);
+ }
+ if (RcvHeader->Packet) {
+ NdisFreePacket(RcvHeader->Packet);
+ }
+
+ if (!Adapter->RcvBufferSpace.Va)
+
+ {
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ RcvHeader->AllocSize,
+ TRUE,
+ (PVOID)RcvHeader->AllocVa,
+ RcvHeader->AllocPa
+ );
+ }
+
+ }
+ }
+
+ while (Adapter->FreeRcvList != NULL) {
+
+ RcvHeader = Adapter->FreeRcvList;
+ Adapter->FreeRcvList = RcvHeader->Next;
+
+ if (RcvHeader->FlushBuffer) {
+ NdisFreeBuffer(RcvHeader->FlushBuffer);
+ }
+ if ( !Adapter->RcvBufferSpace.Va
+ && RcvHeader->AllocVa)
+ {
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ RcvHeader->AllocSize,
+ TRUE,
+ (PVOID)RcvHeader->AllocVa,
+ RcvHeader->AllocPa
+ );
+ }
+ }
+
+ while (Adapter->FreePacketList != NULL)
+ {
+ Packet = Adapter->FreePacketList;
+ Adapter->FreePacketList = RCV_RESERVED(Packet)->Next;
+
+ if (NULL != Packet)
+ {
+ NdisFreePacket(Packet);
+ }
+ }
+
+ if (Adapter->RcvBufferSpace.Va) {
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ Adapter->RcvBufferSpace.AllocSize,
+ TRUE,
+ (PVOID)Adapter->RcvBufferSpace.AllocVa,
+ Adapter->RcvBufferSpace.AllocPa
+ );
+ }
+
+ if (Adapter->ReceivePacketPool) {
+ NdisFreePacketPool((PVOID)Adapter->ReceivePacketPool);
+ }
+
+
+ for (i = 0; i < DC21X4_NUMBER_OF_MAX_TRANSMIT_BUFFERS;i ++ ) {
+
+ if (Adapter->MaxTransmitBuffer[i].AllocVa) {
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ Adapter->MaxTransmitBuffer[i].AllocSize,
+ TRUE,
+ (PVOID)Adapter->MaxTransmitBuffer[i].AllocVa,
+ Adapter->MaxTransmitBuffer[i].AllocPa
+ );
+
+ }
+
+ if (Adapter->MaxTransmitBuffer[i].FlushBuffer) {
+ NdisFreeBuffer(Adapter->MaxTransmitBuffer[i].FlushBuffer);
+ }
+ }
+
+ if (Adapter->MinTransmitBuffer[0].AllocVa &&
+ !Adapter->DontUseMinTransmitBuffer) {
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ Adapter->MinTransmitBuffer[0].AllocSize,
+ TRUE,
+ (PVOID)Adapter->MinTransmitBuffer[0].AllocVa,
+ Adapter->MinTransmitBuffer[0].AllocPa
+ );
+
+ }
+
+ for (i = 0; i < DC21X4_NUMBER_OF_MIN_TRANSMIT_BUFFERS;i ++ ) {
+
+ if (Adapter->MinTransmitBuffer[i].FlushBuffer) {
+ NdisFreeBuffer(Adapter->MinTransmitBuffer[i].FlushBuffer);
+ }
+ }
+
+
+ if (Adapter->FlushBufferPoolHandle) {
+ NdisFreeBufferPool(Adapter->FlushBufferPoolHandle);
+ }
+
+
+ if (Adapter->DescriptorRing.AllocVa) {
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ Adapter->DescriptorRing.AllocSize,
+ FALSE,
+ (PVOID)Adapter->DescriptorRing.AllocVa,
+ Adapter->DescriptorRing.AllocPa
+ );
+
+ }
+
+}
+
+
+
+
+
+
+
+
+/*
+ * AlignStructure
+ *
+ * Align a structure within a bloc of allocated memory
+ * on a specified boundary
+ *
+ */
+VOID
+AlignStructure (
+ IN PALLOCATION_MAP Map,
+ IN UINT Boundary
+ )
+{
+ ULONG AlignmentOffset;
+
+ AlignmentOffset = Boundary - ((ULONG)(Map->AllocVa) % Boundary);
+ Map->Va = (ULONG)(Map->AllocVa) + AlignmentOffset;
+ Map->Pa = NdisGetPhysicalAddressLow(Map->AllocPa)+ AlignmentOffset;
+
+}
+
+
+
+
+
+
+/*
+ * DC21X4AllocateComplete
+ *
+ *
+ *
+ */
+VOID
+DC21X4AllocateComplete(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PVOID VirtualAddress,
+ IN PNDIS_PHYSICAL_ADDRESS PhysicalAddress,
+ IN ULONG Length,
+ IN PVOID Context
+ )
+{
+
+}
+
+
diff --git a/private/ntos/ndis/dc21x4/copy.c b/private/ntos/ndis/dc21x4/copy.c
new file mode 100644
index 000000000..39442d2e5
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/copy.c
@@ -0,0 +1,205 @@
+/*+
+ * file: copy.c
+ *
+ * Copyright (C) 1992-1995 by
+ * Digital Equipment Corporation, Maynard, Massachusetts.
+ * All rights reserved.
+ *
+ * This software is furnished under a license and may be used and copied
+ * only in accordance of the terms of such license and with the
+ * inclusion of the above copyright notice. This software or any other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person. No title to and ownership of the software is hereby
+ * transferred.
+ *
+ * The information in this software is subject to change without notice
+ * and should not be construed as a commitment by digital equipment
+ * corporation.
+ *
+ * Digital assumes no responsibility for the use or reliability of its
+ * software on equipment which is not supplied by digital.
+ *
+ *
+ * Abstract: This file is the part of the NDIS 4.0 miniport driver for DEC's
+ * DC21X4 Ethernet Adapter family.
+ * This module implements the routines to move data
+ * between NDIS packets and buffers
+ *
+ * Author: Philippe Klein
+ *
+ * Revision History:
+ *
+ * phk 28-Aug-1994 Initial entry
+ *
+-*/
+
+#include <precomp.h>
+
+
+
+
+
+
+
+
+/*+
+ * CopyFromPacketToBuffer
+ *
+ * Routine Description:
+ *
+ * Copy from an ndis packet into a buffer.
+ *
+ * Arguments:
+ *
+ * Packet - Source
+ *
+ * Offset - The offset whitin the packet of the first byte
+ * to copy
+ *
+ * Buffer - Destination
+ *
+ * BytesToCopy - The number of bytes to copy
+ *
+ * BytesCopied - The number of bytes actually copied. Can be less then
+ * BytesToCopy if the packet is shorter than BytesToCopy.
+ *
+ * Return Value:
+ *
+ * None
+ *
+-*/
+extern
+VOID
+CopyFromPacketToBuffer (
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ IN PCHAR Buffer,
+ IN UINT BytesToCopy,
+ OUT PUINT BytesCopied
+ )
+
+{
+
+ UINT NdisBufferCount;
+ PNDIS_BUFFER CurrentBuffer;
+ PVOID VirtualAddress;
+ UINT CurrentLength;
+ UINT LocalBytesCopied;
+ UINT AmountToMove;
+
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ &NdisBufferCount,
+ &CurrentBuffer,
+ NULL
+ );
+
+
+ // Check if zero length copy or null packet
+
+ if (!BytesToCopy || !NdisBufferCount) {
+ *BytesCopied = 0;
+ return;
+ }
+
+ // Get the first buffer.
+
+ NdisQueryBuffer(
+ CurrentBuffer,
+ &VirtualAddress,
+ &CurrentLength
+ );
+
+
+ LocalBytesCopied = 0;
+
+ // If there is an offset move first to the beginning of the data
+ // block which may be in a subsequent buffer
+
+ if (Offset) {
+
+ while (Offset > CurrentLength) {
+
+ // No data are copied from this buffer;
+
+ Offset -= CurrentLength;
+
+ //Get the next buffer
+
+ NdisGetNextBuffer(
+ CurrentBuffer,
+ &CurrentBuffer
+ );
+
+ if (!CurrentBuffer) {
+ *BytesCopied = LocalBytesCopied;
+ return;
+ }
+
+ NdisQueryBuffer(
+ CurrentBuffer,
+ &VirtualAddress,
+ &CurrentLength
+ );
+
+ }
+
+ VirtualAddress = (PCHAR)VirtualAddress + Offset;
+ CurrentLength -= Offset;
+ }
+
+
+ // Copy the data
+
+ while (LocalBytesCopied < BytesToCopy) {
+
+ if (!CurrentLength) {
+
+ //The current buffer has been fully copied
+ //Get the next one
+
+ NdisGetNextBuffer(
+ CurrentBuffer,
+ &CurrentBuffer
+ );
+
+ if (!CurrentBuffer) {
+ // There is no more buffer.
+ break;
+ }
+
+ NdisQueryBuffer(
+ CurrentBuffer,
+ &VirtualAddress,
+ &CurrentLength
+ );
+ }
+
+ // Copy the data.
+
+ AmountToMove = min (CurrentLength , BytesToCopy - LocalBytesCopied);
+
+ MOVE_MEMORY(
+ Buffer,
+ VirtualAddress,
+ AmountToMove
+ );
+
+ LocalBytesCopied += AmountToMove;
+ CurrentLength -= AmountToMove;
+
+ Buffer = (PCHAR)Buffer + AmountToMove;
+ VirtualAddress = (PCHAR)VirtualAddress + AmountToMove;
+
+ }
+
+ *BytesCopied = LocalBytesCopied;
+
+}
+
+
+
+
+
diff --git a/private/ntos/ndis/dc21x4/crc.h b/private/ntos/ndis/dc21x4/crc.h
new file mode 100644
index 000000000..aa54be6d8
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/crc.h
@@ -0,0 +1,68 @@
+ULONG CrcTable[256] =
+{
+ 0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL,
+ 0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L,
+ 0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L,
+ 0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, 0x90BF1D91L,
+ 0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL,
+ 0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L,
+ 0x136C9856L, 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL,
+ 0x14015C4FL, 0x63066CD9L, 0xFA0F3D63L, 0x8D080DF5L,
+ 0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, 0xA2677172L,
+ 0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL,
+ 0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L,
+ 0x32D86CE3L, 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L,
+ 0x26D930ACL, 0x51DE003AL, 0xC8D75180L, 0xBFD06116L,
+ 0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L, 0xB8BDA50FL,
+ 0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L,
+ 0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL,
+ 0x76DC4190L, 0x01DB7106L, 0x98D220BCL, 0xEFD5102AL,
+ 0x71B18589L, 0x06B6B51FL, 0x9FBFE4A5L, 0xE8B8D433L,
+ 0x7807C9A2L, 0x0F00F934L, 0x9609A88EL, 0xE10E9818L,
+ 0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L,
+ 0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL,
+ 0x6C0695EDL, 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L,
+ 0x65B0D9C6L, 0x12B7E950L, 0x8BBEB8EAL, 0xFCB9887CL,
+ 0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, 0xFBD44C65L,
+ 0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L,
+ 0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL,
+ 0x4369E96AL, 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L,
+ 0x44042D73L, 0x33031DE5L, 0xAA0A4C5FL, 0xDD0D7CC9L,
+ 0x5005713CL, 0x270241AAL, 0xBE0B1010L, 0xC90C2086L,
+ 0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL,
+ 0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L,
+ 0x59B33D17L, 0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL,
+ 0xEDB88320L, 0x9ABFB3B6L, 0x03B6E20CL, 0x74B1D29AL,
+ 0xEAD54739L, 0x9DD277AFL, 0x04DB2615L, 0x73DC1683L,
+ 0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L,
+ 0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L,
+ 0xF00F9344L, 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL,
+ 0xF762575DL, 0x806567CBL, 0x196C3671L, 0x6E6B06E7L,
+ 0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, 0x67DD4ACCL,
+ 0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L,
+ 0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L,
+ 0xD1BB67F1L, 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL,
+ 0xD80D2BDAL, 0xAF0A1B4CL, 0x36034AF6L, 0x41047A60L,
+ 0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL, 0x4669BE79L,
+ 0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L,
+ 0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL,
+ 0xC5BA3BBEL, 0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L,
+ 0xC2D7FFA7L, 0xB5D0CF31L, 0x2CD99E8BL, 0x5BDEAE1DL,
+ 0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, 0x026D930AL,
+ 0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L,
+ 0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L,
+ 0x92D28E9BL, 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L,
+ 0x86D3D2D4L, 0xF1D4E242L, 0x68DDB3F8L, 0x1FDA836EL,
+ 0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, 0x18B74777L,
+ 0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL,
+ 0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L,
+ 0xA00AE278L, 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L,
+ 0xA7672661L, 0xD06016F7L, 0x4969474DL, 0x3E6E77DBL,
+ 0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L, 0x37D83BF0L,
+ 0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L,
+ 0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L,
+ 0xBAD03605L, 0xCDD70693L, 0x54DE5729L, 0x23D967BFL,
+ 0xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L,
+ 0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL
+};
+
diff --git a/private/ntos/ndis/dc21x4/d21x4def.h b/private/ntos/ndis/dc21x4/d21x4def.h
new file mode 100644
index 000000000..3a64c7a23
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/d21x4def.h
@@ -0,0 +1,827 @@
+/*+
+ * file: d21x4def.h
+ *
+ * Copyright (C) 1992-1995 by
+ * Digital Equipment Corporation, Maynard, Massachusetts.
+ * All rights reserved.
+ *
+ * This software is furnished under a license and may be used and copied
+ * only in accordance of the terms of such license and with the
+ * inclusion of the above copyright notice. This software or any other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person. No title to and ownership of the software is hereby
+ * transferred.
+ *
+ * The information in this software is subject to change without notice
+ * and should not be construed as a commitment by digital equipment
+ * corporation.
+ *
+ * Digital assumes no responsibility for the use or reliability of its
+ * software on equipment which is not supplied by digital.
+ *
+ *
+ * Abstract: This file contains the definitions of the macros used by
+ * the NDIS 4.0 miniport driver for DEC's DC21X4 PCI Ethernet
+ * Adapter family
+ *
+ * Author: Philippe Klein
+ *
+ * Revision History:
+ *
+ * phk 28-Aug-1994 Initial entry
+ *
+-*/
+
+
+
+
+
+
+
+
+
+
+
+// NDIS Revision level
+
+#define DC21X4_NDIS_MAJOR_VERSION 4
+#define DC21X4_NDIS_MINOR_VERSION 0
+
+// static is defined as EXTERN during the debug phase to allow
+// breakpoints to be set on them.
+
+#define DC21X4_DEVL 0
+
+//Filtering mode
+
+typedef enum _FILTERING_MODE {
+ DC21X4_PERFECT_FILTERING,
+ DC21X4_HASH_FILTERING
+} FILTERING_MODE;
+
+//CAM load
+
+typedef enum _LOAD_CAM {
+ LOAD_COMPLETED,
+ LOAD_PENDING,
+ LOAD_IN_PROGRESS
+} LOAD_CAM;
+
+// Packet Type
+
+typedef enum _PACKET_TYPE {
+ TXM_DIRECTED_FRAME,
+ TXM_MULTICAST_FRAME,
+ TXM_BROADCAST_FRAME,
+ RCV_DIRECTED_FRAME,
+ RCV_MULTICAST_FRAME,
+ RCV_BROADCAST_FRAME,
+} PACKET_TYPE;
+
+//LINK STATUS
+
+typedef enum _LINK_STATUS {
+ LinkFail=0,
+ LinkPass,
+ MiiLinkPass
+} LINK_STATUS;
+
+//TIMER
+
+typedef enum _TIMER_FLAG {
+ NoTimer=0,
+ SpaTimer,
+ AncTimeout,
+ DeferredLinkCheck,
+ AncPolling,
+ DeferredAnc
+} TIMER_FLAG;
+
+
+//INTERRUPT
+
+typedef enum _INTERRUPT_MSK {
+ NoInterruptMasked=0,
+ TxmInterruptMasked,
+ TxmRcvInterruptMasked
+} INTERRUPT_MSK;
+
+typedef enum _LINK_HANDLER_MODE {
+ NoNway,
+ NwayWorkAround,
+ Nway,
+ FullNway
+} LINK_HANDLER_MODE;
+
+//SEND MODE
+
+typedef enum _SEND_MODE {
+ CopyMinBuffer,
+ CopyMaxBuffer,
+ MappedBuffer
+} SEND_MODE;
+
+
+// Error log values
+
+#define DC21X4_ERRMSG_REGISTRY (ULONG)0x01
+#define DC21X4_ERRMSG_ALLOC_MEMORY (ULONG)0x02
+#define DC21X4_ERRMSG_SROM (ULONG)0x03
+#define DC21X4_ERRMSG_MEDIA (ULONG)0x04
+#define DC21X4_ERRMSG_LOAD_CAM (ULONG)0x05
+#define DC21X4_ERRMSG_INIT_DEVICE (ULONG)0x06
+#define DC21X4_ERRMSG_SYSTEM_ERROR (ULONG)0x07
+#define DC21X4_ERRMSG_TXM_JABBER_TIMEOUT (ULONG)0x08
+
+#define min(a,b) ((a)<(b) ? (a) : (b))
+#define max(a,b) ((a)>(b) ? (a) : (b))
+
+// OID parsing
+
+#define OID_TYPE_MASK 0xffff0000
+#define OID_TYPE_GENERAL_OPERATIONAL 0x00010000
+#define OID_TYPE_GENERAL_STATISTICS 0x00020000
+#define OID_TYPE_802_3_OPERATIONAL 0x01010000
+#define OID_TYPE_802_3_STATISTICS 0x01020000
+
+#define OID_REQUIRED_MASK 0x0000ff00
+#define OID_REQUIRED_MANDATORY 0x00000100
+#define OID_REQUIRED_OPTIONAL 0x00000200
+
+#define OID_INDEX_MASK 0x000000ff
+
+// Indexes in the GeneralMandatory array.
+
+#define GM_TRANSMIT_OK 0x00
+#define GM_RECEIVE_OK 0x01
+#define GM_TRANSMIT_ERROR 0x02
+#define GM_RECEIVE_ERROR 0x03
+#define GM_MISSED_FRAMES 0x04
+#define GM_ARRAY_SIZE 0x05
+
+// Indexes in the GeneralOptional array.
+
+#define GO_DIRECTED_TRANSMITS 0x00
+#define GO_MULTICAST_TRANSMITS 0x01
+#define GO_BROADCAST_TRANSMITS 0x02
+
+#define GO_DIRECTED_RECEIVES 0x00
+#define GO_MULTICAST_RECEIVES 0x01
+#define GO_BROADCAST_RECEIVES 0x02
+
+#define GO_COUNT_ARRAY_SIZE 0x06
+
+#define GO_RECEIVE_CRC_ERROR 0x00
+#define GO_TRANSMIT_QUEUE_LENGTH 0x01
+#define GO_ARRAY_SIZE 0x02
+
+// Indexes in the MediaMandatory array.
+
+#define MM_RECEIVE_ALIGNMENT_ERROR 0x00
+#define MM_TRANSMIT_ONE_COLLISION 0x01
+#define MM_TRANSMIT_MULT_COLLISIONS 0x02
+#define MM_ARRAY_SIZE 0x03
+
+// Indexes in the MediaOptional array
+#define MO_TRANSMIT_DEFERRED 0x00
+#define MO_TRANSMIT_EXC_COLLISIONS 0x01
+#define MO_RECEIVE_OVERFLOW 0x02
+#define MO_TRANSMIT_UNDERRUN 0x03
+#define MO_TRANSMIT_HEARTBEAT_FAILURE 0x04
+#define MO_TRANSMIT_CRS_LOST 0x05
+#define MO_TRANSMIT_LATE_COLLISION 0x06
+#define MO_ARRAY_SIZE 0x07
+
+// 64_bit counter
+
+typedef struct _DC21X4_LARGE_INTEGER {
+
+ ULONG LowPart;
+ ULONG HighPart;
+
+} DC21X4_LARGE_INTEGER, *PDC21X4_LARGE_INTEGER;
+
+
+// GeneralOptional counters
+
+typedef struct _GEN_OPTIONAL_COUNT{
+ DC21X4_LARGE_INTEGER ByteCount;
+ ULONG FrameCount;
+} GEN_OPTIONAL_COUNT, *PGEN_OPTIONAL_COUNT;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// This type defines the physical addresses used by DC21X4
+
+typedef ULONG DC21X4_PHYSICAL_ADDRESS,*PDC21X4_PHYSICAL_ADDRESS;
+
+
+// Receive descriptor
+
+typedef struct _DC21X4_RECEIVE_DESCRIPTOR {
+
+ ULONG Status; // Status bits returned upon completion
+ ULONG Control; // Control bits and byte_counts
+ DC21X4_PHYSICAL_ADDRESS FirstBufferAddress; // First Buffer Address
+ DC21X4_PHYSICAL_ADDRESS SecondBufferAddress; // Second Buffer Address
+
+ // Driver's reserved field (12 ULONG max)
+
+ struct _DC21X4_RECEIVE_DESCRIPTOR *Next; // Next Descriptor;
+ struct _RCV_HEADER *RcvHeader;
+
+} DC21X4_RECEIVE_DESCRIPTOR, *PDC21X4_RECEIVE_DESCRIPTOR;
+
+// Transmit descriptor
+
+typedef struct _DC21X4_TRANSMIT_DESCRIPTOR {
+
+ ULONG Status; // Status bits returned upon completion
+ ULONG Control; // Control bits and byte_counts
+ DC21X4_PHYSICAL_ADDRESS FirstBufferAddress; // First Buffer Address
+ DC21X4_PHYSICAL_ADDRESS SecondBufferAddress; // Second Buffer Address
+
+ // Driver's reserved field (12 ULONG max)
+
+ ULONG DescriptorPa; // Descriptor's Physical Address
+ ULONG MapTableIndex; // index into the Mapping Table
+
+ struct _DC21X4_TRANSMIT_DESCRIPTOR *Next; // Next Descriptor;
+
+ struct _DC21X4_TRANSMIT_DESCRIPTOR *DescPointer; // Pointer to the first or last segment's desc.
+
+ PNDIS_PACKET Packet; // Pointer to the packet mapped by this descriptor
+ USHORT PacketSize; // Size of the packet
+ UCHAR PacketType; // Packet Type (Directed,Multicast,...)
+ UCHAR SendStatus; // Status
+
+} DC21X4_TRANSMIT_DESCRIPTOR, *PDC21X4_TRANSMIT_DESCRIPTOR;
+
+
+#define DC21X4_MAX_MULTICAST_ADDRESSES 36 // This number is arbitrary
+ // and can be increased if needed
+
+// Number of entries in the Setup buffer.
+
+#define DC21X4_SETUP_PERFECT_ENTRIES 16
+#define DC21X4_SETUP_HASH_ENTRIES 512
+
+// Maximum number of multicast address for Perfect filtering
+// The two first addresses are reserved for the adapter and the
+// Broadcast addresses
+
+#define DC21X4_MAX_MULTICAST_PERFECT 14
+
+// Setup buffer
+//
+// In perfect filtering mode, the setup buffer
+// contains 16 Ethernet address
+// The Ethernet address, divided into three pieces in
+// order from most significant to least significant.
+// In each piece only the low-order 16 bits are used.
+// For example address A8-09-65-12-34-36 will be stored as
+// 0x000009A8
+// 0x00001265
+// 0x00007634
+//
+// In Hashing mode , the setup buffer contains
+// a single physical address and a 512_bit hash filter
+
+typedef union _DC21X4_SETUP_BUFFER {
+
+ struct {
+ ULONG PhysicalAddress[DC21X4_SETUP_PERFECT_ENTRIES][3];
+ } Perfect;
+
+ struct {
+ ULONG Filter[32];
+ ULONG Mbz1[7];
+ ULONG PhysicalAddress[3];
+ ULONG Mbz2[6];
+ } Hash;
+
+} DC21X4_SETUP_BUFFER, *PDC21X4_SETUP_BUFFER;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// **********************************************************************
+// DC21X4 PCI configuration space
+// **********************************************************************
+
+#define CFID 0 //ID Register
+#define CFCS 1 //Command/Status Register
+#define CFRV 2 //Revision Register
+#define CFLT 3 //Latency Timer Register
+#define CBIO 4 //Base I/O Address Register
+#define CBMA 5 //Base Memory Address Register
+#define SSID 11 //Subsystem ID Register
+#define CBER 12 //Expansion ROM Address Register
+#define CFIT 15 //Interrupt Register
+#define CFDA 16 //Driver Area register
+
+#define PCI_CONFIG_SIZE 17
+
+
+typedef struct _DC21X4_PCI_CONFIGURATION {
+
+ ULONG Reg[PCI_CONFIG_SIZE];
+
+}DC21X4_PCI_CONFIGURATION, *PDC21X4_PCI_CONFIGURATION;
+
+
+// **********************************************************************
+// DC21X4 configuration
+// Hold the values of the Registry keys
+// **********************************************************************
+
+typedef struct _DC21X4_CONFIGURATION {
+
+ BOOLEAN Present; // Registry key status
+ ULONG RegistryValue; // Registry Value
+ ULONG CsrValue; // Csr Value
+
+}DC21X4_CONFIGURATION, *PDC21X4_CONFIGURATION;
+
+
+
+
+
+
+
+
+
+
+
+
+// **********************************************************************
+// Allocation Map
+//
+// This structure holds the mapping parameters of a structure allocated
+// in memory
+// **********************************************************************
+typedef struct _ALLOCATION_MAP {
+
+ ULONG AllocVa; // virtual address of the memory block allocated to the structure
+ NDIS_PHYSICAL_ADDRESS AllocPa; // physical address of the memory block allocated to the structure
+ ULONG AllocSize; // size of the allocated block
+ ULONG Va; // virtual address of the aligned structure
+ ULONG Pa; // physical address of the aligned structure
+ ULONG Size; // size of the structure
+ PNDIS_BUFFER FlushBuffer; // NDIS Flush Buffer
+
+} ALLOCATION_MAP,*PALLOCATION_MAP;
+
+
+// **********************************************************************
+// Header for receive buffers so that we can keep track of them
+// **********************************************************************
+
+typedef struct _RCV_HEADER {
+ ALLOCATION_MAP;
+ struct _RCV_HEADER *Next; // Pointer to the next receive buffer.
+ PNDIS_PACKET Packet; // NDIS packet associated with the buffer.
+#if DBG
+ ULONG Signature; // Used to identify the receive header.
+#endif
+}RCV_HEADER,*PRCV_HEADER;
+
+#define RCV_HEADER_SIZE (sizeof(RCV_HEADER))
+
+// Reserved section for receive packets
+// that are released up to the bindings.
+
+typedef struct _RCV_PACKET_RESERVED {
+
+ PRCV_HEADER RcvHeader;
+ union {
+ PNDIS_PACKET Next;
+ PDC21X4_RECEIVE_DESCRIPTOR Descriptor;
+ };
+} RCV_PACKET_RESERVED,*PRCV_PACKET_RESERVED;
+
+#define RCV_RESERVED(x) ((PRCV_PACKET_RESERVED)(x)->MiniportReserved)
+
+#define MAX_PACKET_ARRAY 32
+
+
+
+// **********************************************************************
+// DC21X4 Physical Mapping
+//
+// Holds the physical mapping information
+// **********************************************************************
+
+typedef struct _PHYSICAL_MAPPING {
+
+ ULONG Register;
+ PNDIS_BUFFER Buffer;
+ BOOLEAN Valid;
+
+}PHYSICAL_MAPPING, *PPHYSICAL_MAPPING;
+
+// **********************************************************************
+// DC21X4 Media Table
+//
+// Holds the media programming values
+// **********************************************************************
+
+typedef struct _MEDIA_TABLE {
+
+ ULONG GeneralPurposeCtrl;
+ ULONG GeneralPurposeData;
+ ULONG SiaRegister[3];
+ ULONG Mode;
+ ULONG Polarity;
+ ULONG SenseMask;
+
+}MEDIA_TABLE, *PMEDIA_TABLE;
+
+
+// **********************************************************************
+// DC21X4 PHY Table
+//
+// Holds the PHY values
+// **********************************************************************
+
+typedef struct _PHY_TABLE {
+
+ BOOLEAN Present;
+ INT GepSequenceLength;
+ INT ResetSequenceLength;
+ USHORT MediaCapabilities;
+ USHORT NwayAdvertisement;
+ USHORT FullDuplexBits;
+ USHORT TxThresholdModeBits;
+ USHORT GeneralPurposeCtrl;
+ USHORT GepSequence[MAX_GPR_SEQUENCE];
+ UCHAR ResetSequence[MAX_RESET_SEQUENCE];
+ ULONG GepInterruptMask;
+
+}PHY_TABLE, *PPHY_TABLE;
+
+
+
+
+
+
+
+
+
+
+
+// *******************************************************************
+// DC21X4_ADAPTER
+//
+// This Adapter block contains the state of an adapter.
+// Initialized during the adapter registration.
+//
+// *******************************************************************
+
+typedef struct _DC21X4_ADAPTER {
+
+ NDIS_HANDLE MiniportAdapterHandle; // Handle given by NDIS when the adapter is registered.
+
+ NDIS_HANDLE FlushBufferPoolHandle; // Handle returned by NDIS which
+ // identifies a pool of flush buffers
+
+ NDIS_MINIPORT_INTERRUPT Interrupt; // Holds the interrupt object for this adapter.
+
+ NDIS_MINIPORT_TIMER Timer; // Holds the timer object
+ NDIS_MINIPORT_TIMER MonitorTimer;
+ NDIS_MINIPORT_TIMER ResetTimer;
+
+ UINT LinkCheckCount;
+
+ NDIS_SPIN_LOCK EnqueueSpinLock; // Send/Request SpinLock
+ NDIS_SPIN_LOCK FullDuplexSpinLock; // Send/Receive SpinLock
+
+ ULONG AdapterType; // The type of the adapter (EISA,PCI,...)
+ ULONG DeviceId; // The adapter CFID
+ ULONG SlotNumber; // The Slot Number of this adapter;
+ UINT RevisionNumber; // The Revision Number of this adapter
+
+ BOOLEAN InterruptLatched;
+ BOOLEAN PermanentAddressValid;
+ BOOLEAN FullDuplex;
+ BOOLEAN FullDuplexLink;
+ BOOLEAN DynamicAutoSense;
+ BOOLEAN DefaultMediumFlag;
+ BOOLEAN ParityError;
+ BOOLEAN ResetInProgress;
+ BOOLEAN Initializing;
+ BOOLEAN MediaNway;
+ BOOLEAN NwayEnabled;
+ BOOLEAN NwayProtocol;
+ BOOLEAN FirstAncInterrupt;
+ INT AutoNegotiationCount;
+ BOOLEAN OverflowWorkAround;
+ BOOLEAN IndicateOverflow;
+
+ UINT LinkStatus;
+ UINT PreviousLinkStatus;
+
+ ULONG LinkSpeed;
+
+ INT TransceiverDelay;
+
+ ULONG PciRegMap[DC21X4_MAX_CONFIGURATION]; // Pci Configuration Register Mapping
+ ULONG CsrMap[DC21X4_MAX_CSR]; // DC21X4 Csr Mapping
+
+ // The burnt-in network address from the hardware.
+ UCHAR PermanentNetworkAddress[ETH_LENGTH_OF_ADDRESS];
+
+ // The current network address from the hardware.
+ UCHAR CurrentNetworkAddress[ETH_LENGTH_OF_ADDRESS];
+
+ ULONG MaxMulticastAddresses;
+
+
+ ULONG CacheLineSize; // The size of the Cache lines
+
+ ULONG PciCommand;
+ ULONG PciLatencyTimer;
+ ULONG PciDriverArea;
+
+ ULONG IOBaseAddress; // Base address of the DC21X4 ports.
+ ULONG PortOffset;
+ ULONG IOSpace;
+
+ ULONG OperationMode;
+ ULONG InterruptMask;
+ ULONG BusMode;
+
+ ULONG Gep_Sia2;
+
+ UINT MediaType; // DC21X4 Connection mode
+ UINT MediaCapable;
+ INT DefaultMedium;
+ INT SelectedMedium;
+ INT MediaCount;
+
+ INT MediaPrecedence[MAX_MEDIA_TABLE]; // Hold the Media precedences
+ MEDIA_TABLE Media[MAX_MEDIA_TABLE]; // Hold the Media parameters
+
+ BOOLEAN PhyMediumInSrom; // Phy medium listed in SROM
+ BOOLEAN PhyPresent; // Phy adapter present
+ BOOLEAN PhyNwayCapable;
+ BOOLEAN Indicate10BTLink;
+ BOOLEAN Force10;
+
+ UINT PhyNumber;
+ UINT MiiMediaType; // DC21X4 MiiConnection mode
+
+ MII_GEN_INFO MiiGen; // Hold the PHY information
+ PHY_TABLE Phy[MAX_PHY_TABLE]; // Hold the PHY parameters
+
+ BOOLEAN IgnoreTimer;
+ INT TimerFlag;
+ INT PollCount;
+
+ NDIS_PHYSICAL_ADDRESS HighestAllocAddress; // Upper boundary for allocation
+
+ ULONG InterruptStatus; // Holds a value of the interrupt status
+ // (set by the ISR, cleared by the
+ // interrupt handler routine)
+
+ ULONG SiaStatus; // Holds the value of the SIA status
+
+
+ UINT DescriptorSize; // The size of a descriptor entry into the descriptor ring
+ // (Reflects bus_mode<skip_length>)
+
+ UINT FilteringMode; // Filtering mode (Perfect/Hashing)
+ UINT FilterClass; // Filter class
+
+ ALLOCATION_MAP DescriptorRing; // Descriptor Ring Allocation Map
+
+ ULONG ReceiveDescriptorRingVa; // Receive Descriptor Ring Virtual Address
+ ULONG ReceiveDescriptorRingPa; // Receive Descriptor Ring Physical Address
+ ALLOCATION_MAP RcvBufferSpace;
+
+ PDC21X4_RECEIVE_DESCRIPTOR DequeueReceiveDescriptor;
+
+ UINT ReceiveRingSize; // Receive Descriptor Ring Size
+
+ ULONG TransmitDescriptorRingVa; // Transmit Descriptor Ring Virtual Address
+ ULONG TransmitDescriptorRingPa; // Transmit Descriptor Ring Physical Address
+
+ BOOLEAN DisableTransmitPolling; // Transmit Polling Flag
+
+ ALLOCATION_MAP
+ MaxTransmitBuffer[DC21X4_NUMBER_OF_MAX_TRANSMIT_BUFFERS];
+
+ ALLOCATION_MAP
+ MinTransmitBuffer[DC21X4_NUMBER_OF_MIN_TRANSMIT_BUFFERS];
+ BOOLEAN DontUseMinTransmitBuffer;
+
+ ULONG SetupBufferVa; // Setup Buffer Virtual address
+ ULONG SetupBufferPa; // Setup Buffer Physical address
+
+ PHYSICAL_MAPPING
+ PhysicalMapping [TRANSMIT_RING_SIZE * NUMBER_OF_SEGMENT_PER_DESC];
+
+ PDC21X4_TRANSMIT_DESCRIPTOR EnqueueTransmitDescriptor;
+ PDC21X4_TRANSMIT_DESCRIPTOR DequeueTransmitDescriptor;
+ UINT FreeTransmitDescriptorCount; // Free Transmit Descriptor Count
+
+ UINT AllocMapRegisters; // Allocated Map Registers
+ UINT FreeMapRegisters; // Free Map Register count
+ UINT MapRegisterIndex;
+
+ UINT TxmThreshold; // Transmit threshold
+ ULONG Threshold10Mbps; // Threshold 10Mbps
+ ULONG Threshold100Mbps; // Threshold 100Mbps
+ ULONG TransmitDefaultDescriptorErrorMask; // Transmit Descriptor Error bit mask
+ ULONG TransmitDescriptorErrorMask; // Transmit Descriptor Error bit mask
+
+ UINT PhysicalSegmentThreshold;
+
+ UINT MaxTransmitBufferIndex; // Max Transmit Buffer Index;
+ UINT MaxTransmitBufferInUse; // Max Transmit Buffer Count;
+
+ UINT MinTransmitBufferIndex; // Min Transmit Buffer Index;
+ UINT MinTransmitBufferInUse; // Min Transmit Buffer Count;
+
+ UINT NoCarrierCount;
+ UINT ExcessCollisionsCount;
+ UINT UnderrunRetryCount;
+ UINT UnderrunMaxRetries;
+ UINT UnderrunThreshold;
+
+
+ ULONG InterruptModeration;
+ ULONG Polling;
+ ULONG TxmPolling;
+ ULONG RcvTxmPolling;
+
+ INT InterruptThreshold;
+ INT InterruptCount;
+ INT LastInterruptCount;
+
+ INT FrameThreshold;
+ INT FrameCount;
+
+ ULONG TiPeriod; // Transmit Interrupt period
+ ULONG TiCount; // Transmit interrupt period counter
+
+ ULONG SoftwareCRC; // CRC Sofware generation mode
+
+ INT TransmitFrameCount; // Holds the last snapshoted Txm frame count
+ INT ReceiveFrameCount; // Holds the last snapshoted Rcv frame count
+
+ ULONG LinkHandlerMode;
+
+
+ UINT RcvHeaderSize;
+
+ // Information for releasing of the receive buffers.
+
+ NDIS_HANDLE ReceivePacketPool;
+ ULONG ExtraReceivePackets;
+ PNDIS_PACKET FreePacketList;
+ PNDIS_PACKET PacketArray[MAX_PACKET_ARRAY];
+
+ ULONG ExtraReceiveBuffers;
+ PRCV_HEADER FreeRcvList;
+ ULONG CurrentReceiveBufferCount;
+ ULONG NeededReceiveBuffers;
+
+
+ // Adapter statistics
+
+ ULONG GeneralMandatory[GM_ARRAY_SIZE];
+
+ GEN_OPTIONAL_COUNT GeneralOptionalCount[GO_COUNT_ARRAY_SIZE];
+
+ ULONG GeneralOptional[GO_ARRAY_SIZE];
+
+ ULONG MediaMandatory[MM_ARRAY_SIZE];
+ ULONG MediaOptional[MO_ARRAY_SIZE];
+
+
+} DC21X4_ADAPTER,*PDC21X4_ADAPTER;
+
+// **********************************************************************
+// DC21X4_SYNCH_CONTEXT
+//
+//Context structure while synchronizing with interrupt
+//
+// **********************************************************************
+
+typedef struct _DC21X4_SYNCH_CONTEXT {
+
+ PDC21X4_ADAPTER Adapter;
+ ULONG IsrStatus;
+
+} DC21X4_SYNCH_CONTEXT,*PDC21X4_SYNCH_CONTEXT;
+
+// **********************************************************************
+// CHECKSUM structure
+//
+// Structure for holding checksum and its status when reading the SROM.
+//
+// **********************************************************************
+
+typedef struct _CHECKSUM
+{
+ USHORT Accumulator;
+ USHORT Value;
+ UCHAR Status;
+} CHECKSUM, *PCHECKSUM;
+
+
+
+
+
+
+
+
+
+
+
+
+// Macros used for memory allocation and deallocation.
+
+#define ALLOC_MEMORY(Status, Address, Length) { \
+ \
+ NDIS_PHYSICAL_ADDRESS HighestAddress; \
+ NdisSetPhysicalAddressLow(HighestAddress,0xffffffff); \
+ NdisSetPhysicalAddressHigh(HighestAddress,0xffffffff); \
+ *(Status) = NdisAllocateMemory((PVOID)(Address), \
+ (UINT)(Length), \
+ 0, \
+ HighestAddress \
+ ); \
+}
+
+#define FREE_MEMORY(Address, Length) \
+ \
+ NdisFreeMemory((PVOID)(Address), \
+ (UINT)(Length), \
+ 0 \
+ )
+
+#define MOVE_MEMORY(Destination,Source,Length) \
+ \
+ NdisMoveMemory((PVOID)(Destination), \
+ (PVOID)(Source), \
+ (ULONG)(Length) \
+ ) \
+
+#define ZERO_MEMORY(Destination,Length) \
+ \
+ NdisZeroMemory((PVOID)(Destination), \
+ (ULONG)(Length) \
+ )
+
+
+// 64_bit counter addition
+
+#define ADD_ULONG_TO_LARGE_INTEGER(LargeInteger,Ulong ) { \
+ (LargeInteger).LowPart += (Ulong); \
+ if ((LargeInteger).LowPart < (Ulong)) \
+ (LargeInteger).HighPart++; \
+}
+
+//Frame type
+
+#define IS_MULTICAST(_addr) \
+ ((*(UNALIGNED UCHAR *)(_addr) & 1) == 1)
+
+#define IS_BROADCAST(_addr) \
+ ( (*(UNALIGNED ULONG *)(_addr) == 0xffffffff) && \
+ (*(UNALIGNED USHORT *)((UINT)(_addr) + 4) == 0xffff) \
+ )
+
+#define CHECK_PACKET_TYPE(dst) \
+ ( IS_MULTICAST(dst) ? \
+ ( IS_BROADCAST(dst) ? TXM_BROADCAST_FRAME : \
+ TXM_MULTICAST_FRAME) : TXM_DIRECTED_FRAME \
+ )
+
+#define IS_NULL_ADDRESS(_addr) \
+ ( (*(UNALIGNED ULONG *)(_addr) == 0) && \
+ (*(UNALIGNED USHORT *)((UINT)(_addr) + 4) == 0) \
+ )
diff --git a/private/ntos/ndis/dc21x4/d21x4det.h b/private/ntos/ndis/dc21x4/d21x4det.h
new file mode 100644
index 000000000..02650ce8c
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/d21x4det.h
@@ -0,0 +1,80 @@
+/*
+ * file: d21x4det.h
+ *
+ * Copyright (C) 1992-1995,1992-1995 by
+ * Digital Equipment Corporation, Maynard, Massachusetts.
+ * All rights reserved.
+ *
+ * This software is furnished under a license and may be used and copied
+ * only in accordance of the terms of such license and with the
+ * inclusion of the above copyright notice. This software or any other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person. No title to and ownership of the software is hereby
+ * transferred.
+ *
+ * The information in this software is subject to change without notice
+ * and should not be construed as a commitment by digital equipment
+ * corporation.
+ *
+ * Digital assumes no responsibility for the use or reliability of its
+ * software on equipment which is not supplied by digital.
+ *
+ *
+ * Abstract:
+ * NDIS 4.0 miniport driver for DEC's DC21X4 Ethernet Adapter
+ * family.
+ *
+ * Author: Philippe Klein
+ *
+ * Revision History:
+ *
+ * phk 28-Aug-1994 Initial entry
+ *
+-*/
+
+
+
+#define DC21X4_WRITE_PORT(_Port, _Value) { \
+ \
+ NdisRawWritePortUlong( \
+ Adapter->CsrMap[(_Port)], \
+ (ULONG)(_Value) \
+ ); \
+}
+
+#define DC21X4_READ_PORT(_Port, _Value) { \
+ \
+ NdisRawReadPortUlong( \
+ Adapter->CsrMap[(_Port)], \
+ (PULONG)(_Value) \
+ ); \
+}
+
+#define DC21X4_WRITE_PCI_REGISTER(_Reg, _Value) { \
+ \
+ NdisRawWritePortUlong( \
+ Adapter->PciRegMap[_Reg], \
+ (ULONG)(_Value) \
+ ); \
+}
+
+#define DC21X4_READ_PCI_REGISTER(_Reg, _Value) { \
+ \
+ NdisRawReadPortUlong( \
+ Adapter->PciRegMap[_Reg], \
+ (PULONG)(_Value) \
+ ); \
+}
+
+#define DC21X4_INTERRUPT_LEVEL_DEFAULT 5
+#define DC21X4_INTERRUPT_MODE_DEFAULT NdisInterruptLevelSensitive
+#define DC21X4_ADAPTER_TYPE_DEFAULT NdisInterfaceEisa
+
+// Intel PCI memory controller
+
+#define PCI_CDC_CFID 0x04838086
+#define PCI_PCMC_CFID 0x04A38086
+
+#define PCI_HBC_OFFSET 0x53
+#define PCI_HBC_HPPE 0x02
+
diff --git a/private/ntos/ndis/dc21x4/d21x4fct.h b/private/ntos/ndis/dc21x4/d21x4fct.h
new file mode 100644
index 000000000..9978f54f7
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/d21x4fct.h
@@ -0,0 +1,809 @@
+/*+
+ * file: d21x4fct.h
+ *
+ * Copyright (C) 1992-1995 by
+ * Digital Equipment Corporation, Maynard, Massachusetts.
+ * All rights reserved.
+ *
+ * This software is furnished under a license and may be used and copied
+ * only in accordance of the terms of such license and with the
+ * inclusion of the above copyright notice. This software or any other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person. No title to and ownership of the software is hereby
+ * transferred.
+ *
+ * The information in this software is subject to change without notice
+ * and should not be construed as a commitment by digital equipment
+ * corporation.
+ *
+ * Digital assumes no responsibility for the use or reliability of its
+ * software on equipment which is not supplied by digital.
+ *
+ *
+ * Abstract: This file contains the functions prototyping for the
+ * NDIS 4.0 miniport driver for DEC's DC21X4 Ethernet controler
+ *
+ * Author: Philippe Klein
+ *
+ * Revision History:
+ *
+ * phk 28-Aug-1994 Initial entry
+ *
+-*/
+
+// DC21X4.C
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+
+// ALLOC.C
+
+extern
+BOOLEAN
+AllocateAdapterMemory(
+ IN PDC21X4_ADAPTER Adapter
+ );
+
+extern
+VOID
+FreeAdapterMemory(
+ IN PDC21X4_ADAPTER Adapter
+ );
+
+VOID
+AlignStructure (
+ IN PALLOCATION_MAP Map,
+ IN UINT Boundary
+ );
+
+
+VOID
+DC21X4AllocateComplete(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PVOID VirtualAddress,
+ IN PNDIS_PHYSICAL_ADDRESS PhysicalAddress,
+ IN ULONG Length,
+ IN PVOID Context
+ );
+
+
+// COPY.C
+
+extern
+VOID
+CopyFromPacketToBuffer (
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ IN PCHAR Buffer,
+ IN UINT BytesToCopy,
+ OUT PUINT BytesCopied
+ );
+
+
+// FILTER.C
+
+extern
+VOID
+DC21X4InitializeCam (
+ IN PDC21X4_ADAPTER Adapter,
+ IN PUSHORT Address
+ );
+
+extern
+BOOLEAN
+DC21X4LoadCam (
+ IN PDC21X4_ADAPTER Adapter,
+ IN BOOLEAN InterruptMode
+ );
+
+extern
+NDIS_STATUS
+DC21X4ChangeFilter (
+ IN PDC21X4_ADAPTER Adapter,
+ IN ULONG NewFilterClass
+ );
+
+VOID
+AddBroadcastToSetup (
+ IN PDC21X4_ADAPTER Adapter
+ );
+
+VOID
+RemoveBroadcastFromSetup (
+ IN PDC21X4_ADAPTER Adapter
+ );
+
+extern
+NDIS_STATUS
+DC21X4ChangeMulticastAddresses(
+ IN PDC21X4_ADAPTER Adapter,
+ IN PVOID MulticastAddresses,
+ IN UINT AddressCount
+ );
+
+// INIT.C
+
+extern
+VOID
+DC21X4InitializeRegisters(
+ IN PDC21X4_ADAPTER Adapter
+ );
+
+extern
+VOID
+DC21X4StopAdapter(
+ IN PDC21X4_ADAPTER Adapter
+ );
+
+extern
+VOID
+DC21X4StartAdapter(
+ IN PDC21X4_ADAPTER Adapter
+ );
+
+extern
+VOID
+DC21X4WriteGepRegister(
+ IN PDC21X4_ADAPTER Adapter,
+ IN ULONG Data
+ );
+
+extern
+VOID
+DC21X4InitializeGepRegisters(
+ IN PDC21X4_ADAPTER Adapter,
+ IN BOOLEAN Phy
+ );
+
+extern
+VOID
+DC21X4InitializeMediaRegisters(
+ IN PDC21X4_ADAPTER Adapter,
+ IN BOOLEAN Phy
+ );
+
+extern
+VOID
+DC2104InitializeSiaRegisters(
+ IN PDC21X4_ADAPTER Adapter
+ );
+
+extern
+VOID
+DC21X4InitPciConfigurationRegisters(
+ IN PDC21X4_ADAPTER Adapter
+ );
+
+
+extern
+VOID
+DC21X4StopReceiverAndTransmitter(
+ IN PDC21X4_ADAPTER Adapter
+ );
+
+// INTERRUP.C;
+
+extern
+VOID
+DC21X4Isr(
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueMiniportHandleInterrupt,
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+VOID
+DC21X4SynchClearIsr(
+ IN PDC21X4_SYNCH_CONTEXT SyncContext
+ );
+
+VOID
+DC21X4HandleInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+VOID
+HandleGepInterrupt(
+ IN PDC21X4_ADAPTER Adapter
+ );
+
+VOID
+HandleLinkPassInterrupt(
+ IN PDC21X4_ADAPTER Adapter,
+ IN OUT PULONG IsrStatus
+ );
+
+VOID
+HandleLinkFailInterrupt(
+ IN PDC21X4_ADAPTER Adapter,
+ IN OUT PULONG IsrStatus
+ );
+
+
+VOID
+SwitchMediumToTpNway(
+ IN PDC21X4_ADAPTER Adapter
+ );
+
+PDC21X4_RECEIVE_DESCRIPTOR
+ProcessReceiveDescRing(
+ IN PDC21X4_ADAPTER Adapter
+ );
+
+PDC21X4_TRANSMIT_DESCRIPTOR
+ProcessTransmitDescRing(
+ IN PDC21X4_ADAPTER Adapter
+ );
+
+extern
+VOID
+DC21X4EnableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+extern
+VOID
+DC21X4DisableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+
+extern
+NDIS_STATUS
+DC21X4ReturnPacket(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET Packet
+ );
+
+
+// MEDIA.C
+
+extern
+BOOLEAN
+DC21X4MediaDetect(
+ IN PDC21X4_ADAPTER Adapter
+ );
+
+extern
+BOOLEAN
+DC2114Sense100BaseTxLink(
+ IN PDC21X4_ADAPTER Adapter
+ );
+
+extern
+VOID
+DC21X4DynamicAutoSense (
+ IN PVOID Systemspecific1,
+ IN PDC21X4_ADAPTER Adapter,
+ IN PVOID Systemspecific2,
+ IN PVOID Systemspecific3
+ );
+
+extern
+BOOLEAN
+DC21X4AutoSense (
+ IN PDC21X4_ADAPTER Adapter
+ );
+
+extern
+VOID
+DC21X4SwitchMedia(
+ IN PDC21X4_ADAPTER Adapter,
+ IN LONG NextMedia
+ );
+
+extern
+VOID
+DC21X4StartAutoSenseTimer(
+ IN PDC21X4_ADAPTER Adapter,
+ IN UINT Value
+ );
+
+extern
+VOID
+DC21X4StopAutoSenseTimer(
+ IN PDC21X4_ADAPTER Adapter
+ );
+
+extern
+VOID
+DC21X4EnableNway(
+ IN PDC21X4_ADAPTER Adapter
+ );
+
+extern
+VOID
+DC21X4DisableNway(
+ IN PDC21X4_ADAPTER Adapter
+ );
+
+
+extern
+VOID
+DC21X4IndicateMediaStatus(
+ IN PDC21X4_ADAPTER Adapter,
+ IN UINT Status
+ );
+
+
+// MACTOPHY.C
+
+extern
+BOOLEAN
+DC21X4PhyInit(
+ IN PDC21X4_ADAPTER Adapter
+);
+
+
+extern
+BOOLEAN
+DC21X4SetPhyConnection(
+ IN PDC21X4_ADAPTER Adapter
+);
+
+
+void
+SetMacConnection(
+ IN PDC21X4_ADAPTER Adapter
+);
+
+
+extern
+BOOLEAN
+DC21X4MiiAutoDetect(
+ IN PDC21X4_ADAPTER Adapter
+);
+
+
+extern
+BOOLEAN
+DC21X4MiiAutoSense(
+ IN PDC21X4_ADAPTER Adapter
+);
+
+
+extern
+VOID
+SelectNonMiiPort(
+ IN PDC21X4_ADAPTER Adapter
+);
+
+extern
+VOID
+DC21X4SetPhyControl(
+ PDC21X4_ADAPTER Adapter,
+ USHORT AdminControl
+);
+
+
+// MIIGEN.C
+
+extern
+BOOLEAN
+MiiGenInit(
+ IN PDC21X4_ADAPTER Adapter
+);
+
+extern
+BOOLEAN
+FindAndInitMiiPhys(
+ IN PDC21X4_ADAPTER Adapter
+);
+
+extern
+USHORT
+MiiGenGetCapabilities(
+ PDC21X4_ADAPTER Adapter
+);
+
+extern
+BOOLEAN
+MiiGenCheckConnection(
+ PDC21X4_ADAPTER Adapter,
+ USHORT Connection
+);
+
+extern
+BOOLEAN
+MiiGenSetConnection(
+ PDC21X4_ADAPTER Adapter,
+ UINT Connection,
+ USHORT NwayAdvertisement
+);
+
+
+extern
+BOOLEAN
+MiiGenGetConnectionStatus (
+ PDC21X4_ADAPTER Adapter,
+ PUSHORT ConnectionStatus
+);
+
+
+extern
+BOOLEAN
+MiiGenGetConnection(
+ PDC21X4_ADAPTER Adapter,
+ PUSHORT Connection
+);
+
+extern
+void
+MiiGenAdminStatus(
+ PDC21X4_ADAPTER Adapter,
+ PUSHORT AdminStatus
+);
+
+
+extern
+BOOLEAN
+MiiGenAdminControl(
+ PDC21X4_ADAPTER Adapter,
+ USHORT AdminControl
+);
+
+
+void
+MiiFreeResources(
+ PDC21X4_ADAPTER Adapter
+);
+
+// MIIPHY.C
+
+BOOLEAN
+MiiPhyInit(
+ PDC21X4_ADAPTER Adapter,
+ PMII_PHY_INFO PhyInfoPtr
+ );
+
+void
+MiiPhyGetCapabilities(
+ PMII_PHY_INFO PhyInfoPTR,
+ PCAPABILITY Capabilities
+ );
+
+BOOLEAN
+MiiPhySetConnectionType(
+ PDC21X4_ADAPTER Adapter,
+ PMII_PHY_INFO PhyInfoPtr,
+ USHORT Connection,
+ USHORT Advertisement
+ );
+
+BOOLEAN
+MiiPhyGetConnectionType(
+ PDC21X4_ADAPTER Adapter,
+ PMII_PHY_INFO PhyInfoPtr,
+ PUSHORT ConnectionStatus
+ );
+
+BOOLEAN
+MiiPhyGetConnectionStatus(
+ PDC21X4_ADAPTER Adapter,
+ PMII_PHY_INFO PhyInfoPtr,
+ PUSHORT ConnectionStatus
+ );
+
+void
+MiiPhyAdminStatus(
+ PDC21X4_ADAPTER Adapter,
+ PMII_PHY_INFO PhyInfoPtr,
+ PMII_STATUS Status
+ );
+
+void
+MiiPhyAdminControl(
+ PDC21X4_ADAPTER Adapter,
+ PMII_PHY_INFO PhyInfoPtr,
+ MII_STATUS Control
+ );
+
+BOOLEAN
+MiiPhyReadRegister(
+ PDC21X4_ADAPTER Adapter,
+ PMII_PHY_INFO PhyInfoPtr,
+ USHORT RegNum,
+ PUSHORT Register
+ );
+
+void
+MiiPhyWriteRegister(
+ PDC21X4_ADAPTER Adapter,
+ PMII_PHY_INFO PhyInfoPtr,
+ USHORT RegNum,
+ USHORT Register
+ );
+
+void
+MiiPhyNwayGetLocalAbility(
+ PDC21X4_ADAPTER Adapter,
+ PMII_PHY_INFO PhyInfoPtr,
+ PCAPABILITY Ability
+ );
+
+void
+MiiPhyNwaySetLocalAbility(
+ PDC21X4_ADAPTER Adapter,
+ PMII_PHY_INFO PhyInfoPtr,
+ USHORT MediaBits
+ );
+
+void
+MiiPhyNwayGetPartnerAbility(
+ PDC21X4_ADAPTER Adapter,
+ PMII_PHY_INFO PhyInfoPtr,
+ PCAPABILITY Ability
+ );
+
+
+BOOLEAN
+FindMiiPhyDevice(
+ PDC21X4_ADAPTER Adapter,
+ PMII_PHY_INFO PhyInfoPtr
+ );
+
+void
+WriteMii(
+ PDC21X4_ADAPTER Adapter,
+ ULONG MiiData,
+ INT DataSize
+ );
+
+void
+MiiOutThreeState(
+ PDC21X4_ADAPTER Adapter
+);
+
+void
+InitPhyInfoEntries(
+ PMII_PHY_INFO PhyInfoPtr
+ );
+
+void
+ConvertConnectionToControl(
+ PMII_PHY_INFO PhyInfoPtr,
+ PUSHORT Connection
+ );
+
+void
+ConvertMediaTypeToNwayLocalAbility(
+ USHORT MediaType,
+ PCAPABILITY NwayLocalAbility
+ );
+
+BOOLEAN
+ConvertNwayToConnectionType(
+ CAPABILITY NwayReg,
+ PUSHORT Connection
+ );
+
+BOOLEAN
+CheckConnectionSupport(
+ PMII_PHY_INFO PhyInfoPtr,
+ USHORT ConCommand
+ );
+
+
+extern
+BOOLEAN
+GetBroadcomPhyConnectionType(
+ PDC21X4_ADAPTER Adapter,
+ PMII_PHY_INFO PhyInfoPtr,
+ PUSHORT Connection
+ );
+
+void
+HandleBroadcomMediaChangeFrom10To100(
+ PDC21X4_ADAPTER Adapter,
+ PMII_PHY_INFO PhyInfoPtr
+ );
+
+
+// MONITOR.C
+
+extern
+VOID
+DC21X4ModerateInterrupt (
+ IN PVOID Systemspecific1,
+ IN PDC21X4_ADAPTER Adapter,
+ IN PVOID Systemspecific2,
+ IN PVOID Systemspecific3
+ );
+
+
+extern
+BOOLEAN
+DC21X4CheckforHang(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+
+// REGISTER.C
+
+extern
+NDIS_STATUS
+DC21X4Initialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE ConfigurationHandle
+ );
+
+extern
+VOID
+FreeAdapterResources(
+ IN PDC21X4_ADAPTER Adapter,
+ IN INT Step
+ );
+
+NDIS_STATUS
+FindPciConfiguration(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN ULONG SlotNumber,
+ OUT PULONG PortStart,
+ OUT PULONG PortLength,
+ OUT PULONG InterruptLevel,
+ OUT PULONG InterruptVector
+ );
+
+extern
+VOID
+DC21X4Halt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+extern
+VOID
+DC21X4Shutdown(
+ IN PVOID ShutdownContext
+ );
+
+#if _MIPS_
+
+NTSTATUS
+DC21X4HardwareSaveInformation(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+BOOLEAN
+DC21X4HardwareVerifyChecksum(
+ IN PDC21X4_ADAPTER Adapter,
+ IN PUCHAR EthernetAddress
+ );
+
+NDIS_STATUS
+DC21X4HardwareGetDetails(
+ IN PDC21X4_ADAPTER Adapter,
+ IN UINT Controller,
+ IN UINT MultifunctionAdapter
+ );
+
+#endif
+
+
+// REQUEST.C
+
+extern
+NDIS_STATUS
+DC21X4QueryInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+ );
+
+extern
+NDIS_STATUS
+DC21X4SetInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ );
+
+// RESET.C
+
+extern
+NDIS_STATUS
+DC21X4Reset(
+ OUT PBOOLEAN AddressingReset,
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+extern
+VOID
+DC21X4DeferredReset(
+ IN PVOID Systemspecific1,
+ IN PDC21X4_ADAPTER Adapter,
+ IN PVOID Systemspecific2,
+ IN PVOID Systemspecific3
+ );
+
+// SEND.C
+
+extern
+NDIS_STATUS
+DC21X4Send(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET Packet,
+ IN UINT Flags
+ );
+
+
+extern
+NDIS_STATUS
+DC21X4SendPackets(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ );
+
+
+extern
+ULONG
+CRC32 (
+ IN PUCHAR Data,
+ IN UINT Len
+ );
+
+//SROM.C
+
+extern
+NDIS_STATUS
+DC21X4ReadSerialRom (
+ IN PDC21X4_ADAPTER Adapter
+ );
+
+BOOLEAN
+VerifyChecksum(
+ IN UNALIGNED UCHAR *EthAddress
+ );
+
+NDIS_STATUS
+DC21X4ParseSRom(
+ IN PDC21X4_ADAPTER Adapter
+ );
+
+extern
+VOID
+DC21X4ParseExtendedBlock(
+ IN PDC21X4_ADAPTER Adapter,
+ IN OUT UNALIGNED UCHAR **MediaBlock,
+ IN USHORT GeneralPurposeCtrl,
+ OUT PUCHAR PMediaCode
+ );
+
+extern
+VOID
+DC21X4ParseFixedBlock(
+ IN PDC21X4_ADAPTER Adapter,
+ IN OUT UNALIGNED UCHAR **MediaBlock,
+ IN USHORT GeneralPurposeCtrl,
+ OUT PUCHAR PMediaCode
+ );
+
+BOOLEAN
+DC21X4ReadSRom(
+ IN PDC21X4_ADAPTER Adapter,
+ IN OUT PULONG Offset,
+ IN USHORT Len,
+ OUT PUCHAR Buffer
+ );
+
+
+
+
diff --git a/private/ntos/ndis/dc21x4/d21x4hrd.h b/private/ntos/ndis/dc21x4/d21x4hrd.h
new file mode 100644
index 000000000..35fdba3fc
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/d21x4hrd.h
@@ -0,0 +1,828 @@
+/*
+ * file: d21x4hrd.h
+ *
+ * Copyright (C) 1992-1995 by
+ * Digital Equipment Corporation, Maynard, Massachusetts.
+ * All rights reserved.
+ *
+ * This software is furnished under a license and may be used and copied
+ * only in accordance of the terms of such license and with the
+ * inclusion of the above copyright notice. This software or any other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person. No title to and ownership of the software is hereby
+ * transferred.
+ *
+ * The information in this software is subject to change without notice
+ * and should not be construed as a commitment by digital equipment
+ * corporation.
+ *
+ * Digital assumes no responsibility for the use or reliability of its
+ * software on equipment which is not supplied by digital.
+ *
+ *
+ * Abstract: This file contains the hardware related definitions for the
+ * DEC's DC21X4 NDIS 4.0 miniport driver
+ *
+ * Author: Philippe Klein
+ *
+ * Revision History:
+ *
+ * phk 28-Aug-1994 Initial entry
+ *
+ *
+-*/
+
+
+
+
+
+
+
+
+
+
+// Adapter ID & revisions
+
+#define DC21040_CFID 0x00021011
+#define DC21040_REV1 0x00
+#define DC21040_REV2_0 0x20
+#define DC21040_REV2_2 0x22
+
+
+#define DC21041_CFID 0x00141011
+#define DC21041_REV1_0 0x10
+#define DC21041_REV1_1 0x11
+#define DC21041_REV2_0 0x20
+
+#define DC21140_CFID 0x00091011
+#define DC21140_REV1_1 0x11
+#define DC21140_REV1_2 0x12
+#define DC21140_REV2_0 0x20
+#define DC21140_REV2_1 0x21
+#define DC21140_REV2_2 0x22
+
+#define DC21142_CFID 0x00191011
+#define DC21142_REV1 0x10
+#define DC21142_REV1_0 0x10
+#define DC21142_REV1_1 0x11
+
+
+typedef enum _CFID_INDEX {
+ DefaultCfidIndex,
+ DC21040CfidIndex,
+ DC21041CfidIndex,
+ DC21140CfidIndex,
+ MAX_CFIDS
+} CFID_INDEX;
+
+
+#define DE425_COMPRESSED_ID 0x5042A310 //"DEC4250"
+#define DC21X4_INTERRUPT_LEVEL_SENSITIVE 0
+#define DC21X4_INTERRUPT_LATCHED 1
+
+// Media types
+
+typedef enum _MEDIA_TYPE {
+ Medium10BaseT,
+ Medium10Base2,
+ Medium10Base5,
+ Medium100BaseTx,
+ Medium10BaseTFd,
+ Medium100BaseTxFd,
+ Medium100BaseT4,
+ Medium100BaseFx,
+ Medium100BaseFxFd,
+ MAX_MEDIA_TABLE
+} MEDIA_TYPE;
+
+#define Medium10Base2_5 0xff
+
+
+// PHY Media
+
+typedef enum _PHY_MEDIA_TYPE {
+ MediumMii10BaseT=MAX_MEDIA_TABLE,
+ MediumMii10BaseTFd,
+ MediumMii10Base2,
+ MediumMii10Base5,
+ MediumMii100BaseTx,
+ MediumMii100BaseTxFd,
+ MediumMii100BaseT4,
+ MediumMii100BaseFx,
+ MediumMii100BaseFxFd,
+ MAX_PHY_MEDIA
+} PHY_MEDIA_TYPE;
+
+
+#define MEDIA_MASK 0x00ff
+#define CONTROL_MASK 0xFF00
+
+// Media modes
+
+#define MEDIA_NWAY 0x0100
+#define MEDIA_FULL_DUPLEX 0x0200
+#define MEDIA_LINK_DISABLE 0x0400
+#define MEDIA_AUTOSENSE 0x0800
+
+#define MediaAutoSense (MEDIA_AUTOSENSE | MEDIA_NWAY)
+#define MediaAutoSenseNoNway (MEDIA_AUTOSENSE)
+
+#define Medium10BaseTNway (Medium10BaseT | MEDIA_NWAY)
+#define Medium10BaseTFullDuplex (Medium10BaseTFd | MEDIA_FULL_DUPLEX)
+#define Medium10BaseTLinkDisable (Medium10BaseT | MEDIA_LINK_DISABLE)
+
+#define Medium100BaseTxFullDuplex (Medium100BaseTxFd | MEDIA_FULL_DUPLEX)
+
+
+#define MediumMii10BaseTFullDuplex (MediumMii10BaseTFd | MEDIA_FULL_DUPLEX)
+#define MediumMii100BaseTxFullDuplex (MediumMii100BaseTxFd | MEDIA_FULL_DUPLEX)
+#define MediaMiiAutoSense (MediumMii10BaseT | MEDIA_AUTOSENSE)
+
+
+// Media Capable mask
+
+#define MEDIUM_10BT (1<<Medium10BaseT)
+#define MEDIUM_10B2 (1<<Medium10Base2)
+#define MEDIUM_10B5 (1<<Medium10Base5)
+#define MEDIUM_100BTX (1<<Medium100BaseTx)
+
+//Default Cache Line Size (in bytes)
+#define DC21X4_DEFAULT_CACHE_LINE_SIZE 64
+
+//DC21X4 Register index
+
+//PCI Configuration registers
+
+#define DC21X4_PCI_ID 0
+#define DC21X4_PCI_COMMAND 1
+#define DC21X4_PCI_REVISION 2
+#define DC21X4_PCI_LATENCY_TIMER 3
+#define DC21X4_PCI_BASE_IO_ADDRESS 4
+#define DC21X4_PCI_INTERRUPT 5
+#define DC21X4_PCI_DRIVER_AREA 6
+
+#define DC21X4_MAX_CONFIGURATION 7
+
+//Command & Status Registers
+
+#define DC21X4_BUS_MODE 0
+#define DC21X4_TXM_POLL_DEMAND 1
+#define DC21X4_RCV_POLL_DEMAND 2
+#define DC21X4_RCV_DESC_RING 3
+#define DC21X4_TXM_DESC_RING 4
+#define DC21X4_STATUS 5
+#define DC21X4_OPERATION_MODE 6
+#define DC21X4_INTERRUPT_MASK 7
+#define DC21X4_MISSED_FRAME 8
+#define DC21X4_IDPROM 9
+#define DC21X4_RESERVED 10
+#define DC21X4_TIMER 11
+#define DC21X4_SIA_STATUS 12
+#define DC21X4_GEN_PURPOSE 12
+#define DC21X4_SIA_MODE_0 13
+#define DC21X4_SIA_MODE_1 14
+#define DC21X4_SIA_MODE_2 15
+#define DC21X4_MAX_CSR 16
+
+
+//EISA Mapping
+
+#define EISA_REG0_OFFSET 0xc88
+#define EISA_REG1_OFFSET 0xc89
+
+#define EISA_CFGSCR1_OFFSET 0x8C
+#define EISA_CFGSCR2_OFFSET 0x98
+
+#define EISA_CFID_OFFSET 0x08
+#define EISA_CFCS_OFFSET 0x0c
+#define EISA_CFRV_OFFSET 0x18
+#define EISA_CFLT_OFFSET 0x1C
+#define EISA_CBIO_OFFSET 0x28
+
+#define EISA_CSR_OFFSET 0x10
+
+#define EISA_ID_PROM_OFFSET 0xc90
+
+#define EISA_DC21040_REGISTER_SPACE 240
+#define EISA_DC21140_REGISTER_SPACE 240
+
+//PCI mapping
+
+#define PCI_CFID_OFFSET 0x00
+#define PCI_CFCS_OFFSET 0x04
+#define PCI_CFRV_OFFSET 0x08
+#define PCI_CFLT_OFFSET 0x0C
+#define PCI_CBIO_OFFSET 0x10
+#define PCI_CFIT_OFFSET 0x3C
+#define PCI_CFDA_OFFSET 0x40
+
+#define PCI_CSR_OFFSET 0x08
+
+# define SLOT_NUMBER_OFFSET 12
+# define IRQ_BIT_NUMBER 1
+
+
+//Constants for the CONFIG_ID register
+
+#define DC21X4_DEVICE_ID ((ULONG)(0x0000FFFF))
+#define DC21X4_VENDOR_ID ((ULONG)(0xFFFF0000))
+
+//Constants for the CONFIG_COMMAND register
+
+#define DC21X4_MEMORY_SPACE_ACCESS ((ULONG)(0x00000001))
+#define DC21X4_MASTER_OPERATION ((ULONG)(0x00000002))
+#define DC21X4_PARITY_ERROR_RESPONSE ((ULONG)(0x00000004))
+#define DC21X4_DEVSEL_TIMING ((ULONG)(0x00000008))
+
+#define DC21X4_PCI_COMMAND_DEFAULT_VALUE 0x05 // Parity Response = 0
+ // Master Operation = 1
+ // Memory Space Access = 0
+ // IO Space Access = 1
+
+//Constants for the CONFIG_REVISION register
+
+#define DC21X4_REVISION_ID ((ULONG)(0x000000FF))
+#define DC21X4_MAJOR_REV ((ULONG)(0x000000F0))
+#define DC21X4_MINOR_REV ((ULONG)(0x0000000F))
+
+//Constants for the CONFIG_LATENCY_TIMER register
+
+#define DC21X4_LATENCY_TIMER ((ULONG)(0x0000FF00))
+
+#define DC21X4_PCI_LATENCY_TIMER_DEFAULT_VALUE 0xFF00
+
+//Constants for the CONFIG_BASE_IO_ADDRESS register
+
+#define DC21X4_IO_SPACE ((ULONG)(0x00000001))
+#define DC21X4_BASE_IO_ADDRESS ((ULONG)(0xFFFFFF80))
+
+//Constants for the CONFIG_INTERRUPT register
+
+#define DC21X4_CFIT_INTERRUPT_LINE ((ULONG)(0x000000FF))
+
+//Constants for the CONFIG_DRIVER_AREA register
+
+#define DC21X4_REGISTRED ((ULONG)(0x00000100))
+
+#define CFDA_SNOOZE_MODE 0x40000000
+
+
+//Constants for the BUS_MODE register
+
+#define DC21X4_SW_RESET ((ULONG)(0x00000001))
+#define DC21X4_BUS_ARBITRATION ((ULONG)(0x00000002))
+#define DC21X4_SKIP_LENGTH ((ULONG)(0x0000003C))
+#define DC21X4_ENDIAN ((ULONG)(0x00000080))
+#define DC21X4_BURST_LENGTH ((ULONG)(0x00003F00))
+#define DC21X4_CACHE_ALIGNMENT ((ULONG)(0x0000C000))
+#define DC21X4_AUTO_POLLING ((ULONG)(0x00070000))
+
+#define BUS_ARBITRATION_BIT_NUMBER 1
+#define BURST_LENGTH_BIT_NUMBER 8
+#define AUTO_POLLING_BIT_NUMBER 16
+
+#define DC21X4_BURST_LENGTH_DEFAULT_VALUE 16
+
+#define DC21X4_SKIP_64 ((ULONG)(0x00000030))
+#define DC21X4_SKIP_128 ((ULONG)(0x00000070))
+
+#define DC21X4_ALIGN_32 ((ULONG)(0x00004000))
+#define DC21X4_ALIGN_64 ((ULONG)(0x00008000))
+#define DC21X4_ALIGN_128 ((ULONG)(0x0000C000))
+
+//Constants for the TXM_POLL_DEMAND & RCV_POLL_DEMAND
+
+#define DC21X4_POLL_DEMAND ((ULONG)(0x00000001))
+
+
+//Constants for the STATUS register (CSR5)
+
+#define DC21X4_TXM_INTERRUPT ((ULONG)(0x00000001))
+#define DC21X4_TXM_STOPPED ((ULONG)(0x00000002))
+#define DC21X4_TXM_BUFFER_UNAVAILABLE ((ULONG)(0x00000004))
+#define DC21X4_TXM_JABBER_TIMEOUT ((ULONG)(0x00000008))
+#define DC21X4_LINK_PASS ((ULONG)(0x00000010))
+#define DC21X4_TXM_UNDERRUN ((ULONG)(0x00000020))
+#define DC21X4_RCV_INTERRUPT ((ULONG)(0x00000040))
+#define DC21X4_RCV_BUFFER_UNAVAILABLE ((ULONG)(0x00000080))
+#define DC21X4_RCV_STOPPED ((ULONG)(0x00000100))
+#define DC21X4_RCV_WATCHDOG_TIMEOUT ((ULONG)(0x00000200))
+#define DC21X4_10B5_10BT_SWITCH ((ULONG)(0x00000400))
+#define DC21X4_FULL_DUPLEX_SHORT_FRAME ((ULONG)(0x00000800))
+#define DC21X4_LINK_FAIL ((ULONG)(0x00001000))
+#define DC21X4_SYSTEM_ERROR ((ULONG)(0x00002000))
+#define DC21X4_ABNORMAL_INTERRUPT ((ULONG)(0x00008000))
+#define DC21X4_NORMAL_INTERRUPT ((ULONG)(0x00010000))
+#define DC21X4_RCV_PROCESS_STATE ((ULONG)(0x000E0000))
+#define DC21X4_TXM_PROCESS_STATE ((ULONG)(0x00700000))
+#define DC21X4_ERROR_BITS ((ULONG)(0x03800000))
+#define DC21X4_GEP_INTERRUPT ((ULONG)(0x04000000))
+
+#define DC21X4_TXM_PROCESS_SUSPENDED ((ULONG)(0x00600000))
+
+#define DC21X4_STATUS_INTERRUPTS ((ULONG)(0x0001BFFF))
+
+//Constants for the OPERATION_MODE register (CSR6)
+
+#define DC21X4_RCV_HASH_FILTER_MODE ((ULONG)(0x00000001))
+#define DC21X4_RCV_START ((ULONG)(0x00000002))
+#define DC21X4_PASS_BAD_FRAMES ((ULONG)(0x00000008))
+#define DC21X4_INVERSE_FILTERING ((ULONG)(0x00000010))
+#define DC21X4_STOP_BACKOFF_COUNTER ((ULONG)(0x00000020))
+#define DC21X4_PROMISCUOUS_MODE ((ULONG)(0x00000040))
+#define DC21X4_PASS_ALL_MULTICAST ((ULONG)(0x00000080))
+#define DC21X4_FLAKY_OSC_DISABLE ((ULONG)(0x00000100))
+#define DC21X4_FULL_DUPLEX_MODE ((ULONG)(0x00000200))
+#define DC21X4_OPERATING_MODE ((ULONG)(0x00000C00))
+#define DC21X4_FORCE_COLLISION_MODE ((ULONG)(0x00001000))
+#define DC21X4_TXM_START ((ULONG)(0x00002000))
+#define DC21X4_TXM_THRESHOLD ((ULONG)(0x0000C000))
+#define DC21X4_BACK_PRESSURE ((ULONG)(0x00010000))
+#define DC21X4_CAPTURE_EFFECT ((ULONG)(0x00020000))
+#define DC21X4_PORT_SELECT ((ULONG)(0x00040000))
+#define DC21X4_HEARTBEAT_DISABLE ((ULONG)(0x00080000))
+#define DC21X4_STORE_AND_FORWARD ((ULONG)(0x00200000))
+#define DC21X4_TXM_THRESHOLD_MODE ((ULONG)(0x00400000))
+#define DC21X4_CS_MODE ((ULONG)(0x00800000))
+#define DC21X4_SCRAMBLER ((ULONG)(0x01000000))
+#define DC21X4_LINK_HYSTERESIS ((ULONG)(0x02000000))
+
+#define DC21X4_INTERNAL_LOOPBACK_MODE ((ULONG)(0x00000400))
+#define DC21X4_EXTERNAL_LOOPBACK_MODE ((ULONG)(0x00000800))
+
+#define DC21X4_TXM10_THRESHOLD_72 ((ULONG)(0x00000000))
+#define DC21X4_TXM10_THRESHOLD_96 ((ULONG)(0x00004000))
+#define DC21X4_TXM10_THRESHOLD_128 ((ULONG)(0x00008000))
+#define DC21X4_TXM10_THRESHOLD_160 ((ULONG)(0x0000C000))
+
+#define DC21X4_TXM100_THRESHOLD_128 ((ULONG)(0x00000000))
+#define DC21X4_TXM100_THRESHOLD_256 ((ULONG)(0x00004000))
+#define DC21X4_TXM100_THRESHOLD_512 ((ULONG)(0x00008000))
+#define DC21X4_TXM100_THRESHOLD_1024 ((ULONG)(0x0000C000))
+
+#define DC21X4_DEFAULT_THRESHOLD_10MBPS DC21X4_TXM10_THRESHOLD_96
+#define DC21X4_DEFAULT_THRESHOLD_100MBPS DC21X4_TXM100_THRESHOLD_512
+
+#define DC21X4_MODE_MASK ((ULONG)( \
+ DC21X4_TXM_THRESHOLD_MODE \
+ | DC21X4_FULL_DUPLEX_MODE \
+ | DC21X4_STORE_AND_FORWARD \
+ ))
+
+#define DC21X4_MEDIUM_MASK ((ULONG)( \
+ DC21X4_TXM_THRESHOLD \
+ | DC21X4_PORT_SELECT \
+ | DC21X4_HEARTBEAT_DISABLE \
+ | DC21X4_FULL_DUPLEX_MODE \
+ | DC21X4_TXM_THRESHOLD_MODE \
+ | DC21X4_CS_MODE \
+ | DC21X4_SCRAMBLER \
+ | DC21X4_LINK_HYSTERESIS \
+ ))
+
+//initial values
+
+#define DC21X4_OPMODE_100BTX ((ULONG)( \
+ DC21X4_HEARTBEAT_DISABLE \
+ | DC21X4_LINK_HYSTERESIS \
+ ))
+
+//Constants for the INTERRUPT_MASK register (CSR7)
+
+#define DC21X4_MSK_TXM_INTERRUPT ((ULONG)(0x00000001))
+#define DC21X4_MSK_TXM_STOPPED ((ULONG)(0x00000002))
+#define DC21X4_MSK_TXM_BUFFER_UNAVAILABLE ((ULONG)(0x00000004))
+#define DC21X4_MSK_TXM_JABBER_TIMEOUT ((ULONG)(0x00000008))
+#define DC21X4_MSK_LINK_PASS ((ULONG)(0x00000010))
+#define DC21X4_MSK_TXM_UNDERRUN ((ULONG)(0x00000020))
+
+#define DC21X4_MSK_RCV_INTERRUPT ((ULONG)(0x00000040))
+#define DC21X4_MSK_RCV_BUFFER_UNAVAILABLE ((ULONG)(0x00000080))
+#define DC21X4_MSK_RCV_STOPPED ((ULONG)(0x00000100))
+#define DC21X4_MSK_RCV_WATCHDOG_TIMEOUT ((ULONG)(0x00000200))
+#define DC21X4_MSK_10B5_10BT_SWITCH ((ULONG)(0x00000400))
+#define DC21X4_MSK_TIMER_EXPIRED ((ULONG)(0x00000800))
+#define DC21X4_MSK_FULL_DUPLEX ((ULONG)(0x00000800))
+#define DC21X4_MSK_LINK_FAIL ((ULONG)(0x00001000))
+#define DC21X4_MSK_SYSTEM_ERROR ((ULONG)(0x00002000))
+#define DC21X4_MSK_EARLY_INTERRUPT ((ULONG)(0x00004000))
+#define DC21X4_MSK_ABNORMAL_INTERRUPT ((ULONG)(0x00008000))
+#define DC21X4_MSK_NORMAL_INTERRUPT ((ULONG)(0x00010000))
+#define DC21X4_MSK_GEP_INTERRUPT ((ULONG)(0x04000000))
+
+
+//initial value
+
+#define DC21X4_TXM_INTERRUPTS ((ULONG)( \
+ DC21X4_MSK_TXM_INTERRUPT \
+ | DC21X4_MSK_TXM_STOPPED \
+ | DC21X4_MSK_TXM_JABBER_TIMEOUT \
+ ))
+
+#define DC21X4_RCV_INTERRUPTS ((ULONG)( \
+ DC21X4_MSK_TXM_STOPPED \
+ | DC21X4_MSK_RCV_INTERRUPT \
+ ))
+
+#define DC21X4_MSK_MSK_DEFAULT_VALUE ((ULONG)( \
+ DC21X4_TXM_INTERRUPTS \
+ | DC21X4_RCV_INTERRUPTS \
+ | DC21X4_MSK_LINK_PASS \
+ | DC21X4_MSK_LINK_FAIL \
+ | DC21X4_MSK_TIMER_EXPIRED \
+ | DC21X4_MSK_SYSTEM_ERROR \
+ | DC21X4_MSK_ABNORMAL_INTERRUPT \
+ | DC21X4_MSK_NORMAL_INTERRUPT \
+ ))
+
+//Constants for the MISSED_FRAME/OVERFLOW register
+
+#define DC21X4_MISSED_FRAME_COUNTER ((ULONG)(0x0000FFFF))
+
+#define DC21X4_OVERFLOW_COUNTER ((ULONG)(0x00001FFF))
+#define DC21X4_OVERFLOW_COUNTER_SHIFT 16
+
+// Constants for the SERIAL ROM register
+
+#define DC21X4_IDPROM_DATA_UNVALID ((ULONG)(0x80000000))
+#define DC21X4_IDPROM_DATA ((ULONG)(0x000000FF))
+
+// Constants for the TIMER register
+
+#define DC21X4_TIMER_CON_MODE ((ULONG)(0x00010000))
+
+
+//Constants for the DC2104 SIA_STATUS register (CSR12)
+
+#define DC21X4_10B5_10BT_INDICATION ((ULONG)(0x00000001))
+#define DC21X4_NETWORK_CONNECTION_ERROR ((ULONG)(0x00000002))
+#define DC21X4_LINKFAIL_10 ((ULONG)(0x00000004))
+#define DC21X4_AUTO_POLARITY_STATE ((ULONG)(0x00000008))
+#define DC21X4_DPLL_SELF_TEST_DONE ((ULONG)(0x00000010))
+#define DC21X4_DPLL_SELF_TEST_PASS ((ULONG)(0x00000020))
+#define DC21X4_DPLL_ALL_ZERO ((ULONG)(0x00000040))
+#define DC21X4_DPLL_ALL_ONE ((ULONG)(0x00000080))
+#define DC21X4_SELECTED_PORT_ACTIVE ((ULONG)(0x00000100))
+#define DC21X4_NON_SELECTED_PORT_ACTIVE ((ULONG)(0x00000200))
+#define DC21X4_AUTO_NEGOTIATION_STATE ((ULONG)(0x00007000))
+#define DC21X4_LINK_PARTNER_NEGOTIABLE ((ULONG)(0x00008000))
+
+#define DC21X4_SELECTED_FIELD_MASK ((ULONG)(0x001F0000))
+#define DC21X4_SELECTED_FIELD ((ULONG)(0x00010000))
+
+#define DC21X4_LINK_PARTNER_10BT ((ULONG)(0x00200000))
+#define DC21X4_LINK_PARTNER_10BT_FD ((ULONG)(0x00400000))
+
+#define DC21X4_RESTART_AUTO_NEGOTIATION ((ULONG)(0x00001000))
+
+//Constants for the AutoNegotation states
+
+#define ANS_ACKNOWLEDGE_DETECTED ((ULONG)(0x00003000))
+#define ANS_ACKNOWLEDGE_COMPLETED ((ULONG)(0x00004000))
+#define ANS_AUTO_NEGOTIATION_COMPLETED ((ULONG)(0x00005000))
+
+#define DC21X4_LINK_PASS_MASK ((ULONG)( \
+ DC21X4_LINKFAIL_10 \
+ | DC21X4_AUTO_NEGOTIATION_STATE \
+ ))
+
+#define DC21X4_LINK_PASS_STATUS ((ULONG)( \
+ ANS_AUTO_NEGOTIATION_COMPLETED \
+ ))
+
+//Constants for the SIA_MODE_0 registers (CSR13)
+
+#define DC21X4_SIA_RST ((ULONG)(0x00000001))
+#define DC21X4_10B5_10BT_SELECTION ((ULONG)(0x00000002))
+#define DC21X4_CSR_AUTO_CONFIGURATION ((ULONG)(0x00000004))
+#define DC21X4_10B5_MODE ((ULONG)(0x00000008))
+
+#define DC21X4_AUTOSENSE_FLG ((ULONG)(0x80000005))
+#define DC21X4_FULL_DUPLEX_FLG ((ULONG)(0x40000005))
+#define DC21X4_LINK_DISABLE_FLG ((ULONG)(0x10000005))
+#define DC21X4_10B5_FLG ((ULONG)(0x0000000D))
+#define DC21X4_10B2_FLG ((ULONG)(0x2000000D))
+
+#define DC21X4_RESET_SIA ((ULONG)(0x00000000))
+
+
+//Constants for the SIA_MODE_1 registers (CSR14)
+
+
+#define DC21X4_AUTO_NEGOTIATION_ENABLE ((ULONG)(0x00000080))
+
+
+//Constants for the SIA_MODE_2 registers (CSR15)
+#define DC21142_SIA2_MASK ((ULONG)(0x0000FFFF))
+#define DC21142_GEP_MASK ((ULONG)(0xFFFF0000))
+
+#define DC21142_GEP_SHIFT 16
+
+
+//DC21040:
+
+//Constants for SIA TP mode
+
+#define DC21040_SIA0_10BT ((ULONG)(0x00008F01))
+#define DC21040_SIA1_10BT ((ULONG)(0x0000FFFF))
+#define DC21040_SIA1_10BT_FULL_DUPLEX ((ULONG)(0x0000FFFD))
+#define DC21040_SIA1_10BT_LINK_DISABLE ((ULONG)(0x0000CFFF))
+#define DC21040_SIA2_10BT ((ULONG)(0x00000000))
+
+//Constants for SIA BNC Thinwire mode
+
+#define DC21040_SIA0_10B2 ((ULONG)(0x0000EF09))
+#define DC21040_SIA1_10B2 ((ULONG)(0x00000705))
+#define DC21040_SIA2_10B2 ((ULONG)(0x00000006))
+
+//Constants for SIA AUI Thickwire mode
+
+#define DC21040_SIA0_10B5 ((ULONG)(0x00008F09))
+#define DC21040_SIA1_10B5 ((ULONG)(0x00000705))
+#define DC21040_SIA2_10B5 ((ULONG)(0x00000006))
+
+
+//DC21041:
+
+//Constants for SIA TP mode
+
+#define DC21041_SIA0_10BT ((ULONG)(0x0000EF01))
+#define DC21041_SIA1_10BT ((ULONG)(0x0000FF3F))
+#define DC21041_SIA1_10BT_FULL_DUPLEX ((ULONG)(0x00007F3D))
+#define DC21041_SIA1_10BT_LINK_DISABLE ((ULONG)(0x00004F3F))
+#define DC21041_SIA2_10BT ((ULONG)(0x00000008))
+
+//Constants for SIA BNC
+
+#define DC21041_SIA0_10B2 ((ULONG)(0x0000EF09))
+#define DC21041_SIA1_10B2 ((ULONG)(0x00000705))
+#define DC21041_SIA2_10B2 ((ULONG)(0x00000006))
+
+//Constants for SIA AUI mode
+
+#define DC21041_SIA0_10B5 ((ULONG)(0x0000EF09))
+#define DC21041_SIA1_10B5 ((ULONG)(0x00000705))
+#define DC21041_SIA2_10B5 ((ULONG)(0x0000000E))
+
+#define DC21041_LINK_TEST_ENABLED ((ULONG)(0x0000F038))
+
+
+//DC21142:
+
+//Constants for SIA TP mode
+
+#define DC21142_SIA0_10BT ((ULONG)(0x00000001))
+#define DC21142_SIA1_10BT ((ULONG)(0x00007F3F))
+#define DC21142_SIA1_10BT_FULL_DUPLEX ((ULONG)(0x00007F3D))
+#define DC21142_SIA1_10BT_LINK_DISABLE ((ULONG)(0x00004F3F))
+#define DC21142_SIA2_10BT ((ULONG)(0x00000008)) // turn off the BNC transceiver
+
+//Constants for SIA BNC
+
+#define DC21142_SIA0_10B2 ((ULONG)(0x00000009))
+#define DC21142_SIA1_10B2 ((ULONG)(0x00000705))
+#define DC21142_SIA2_10B2 ((ULONG)(0x00000006))
+
+//Constants for SIA AUI mode
+
+#define DC21142_SIA0_10B5 ((ULONG)(0x00000009))
+#define DC21142_SIA1_10B5 ((ULONG)(0x00000705))
+#define DC21142_SIA2_10B5 ((ULONG)(0x0000000E))
+
+//Constant for MII mode
+
+#define DC21142_SIA1_MII_HALF_DUPLEX ((ULONG)(0x00007F3F))
+#define DC21142_SIA1_MII_FULL_DUPLEX ((ULONG)(0x00007F3D))
+
+#define DC21142_GPR_BIT_SHIFT 16
+
+#define DC21X4_GEP_INTERRUPT_BIT_SHIFT 29
+
+#define DC21142_LINK_TEST_ENABLED ((ULONG)(0x0000F038)) //while in BNC or AUI mode
+
+
+#define DC21X4_NWAY_ENABLED ((ULONG)(0x000000C0))
+
+//Constants for the RCV descriptor RDES
+
+#define DC21X4_RDES_OVERFLOW ((ULONG)(0x00000001))
+#define DC21X4_RDES_CRC_ERROR ((ULONG)(0x00000002))
+#define DC21X4_RDES_DRIBBLING_BIT ((ULONG)(0x00000004))
+#define DC21X4_RDES_RCV_WATCHDOG_TIMEOUT ((ULONG)(0x00000010))
+#define DC21X4_RDES_FRAME_TYPE ((ULONG)(0x00000020))
+#define DC21X4_RDES_COLLISION_SEEN ((ULONG)(0x00000040))
+#define DC21X4_RDES_FRAME_TOO_LONG ((ULONG)(0x00000080))
+#define DC21X4_RDES_LAST_DESCRIPTOR ((ULONG)(0x00000100))
+#define DC21X4_RDES_FIRST_DESCRIPTOR ((ULONG)(0x00000200))
+#define DC21X4_RDES_MULTICAST_FRAME ((ULONG)(0x00000400))
+#define DC21X4_RDES_RUNT_FRAME ((ULONG)(0x00000800))
+#define DC21X4_RDES_DATA_TYPE ((ULONG)(0x00003000))
+#define DC21X4_RDES_LENGTH_ERROR ((ULONG)(0x00004000))
+#define DC21X4_RDES_ERROR_SUMMARY ((ULONG)(0x00008000))
+#define DC21X4_RDES_FRAME_LENGTH ((ULONG)(0x7FFF0000))
+#define DC21X4_RDES_OWN_BIT ((ULONG)(0x80000000))
+
+#define DC21X4_RDES_FIRST_BUFFER_SIZE ((ULONG)(0x000007FF))
+#define DC21X4_RDES_SECOND_BUFFER_SIZE ((ULONG)(0x003FF800))
+#define DC21X4_RDES_SECOND_ADDR_CHAINED ((ULONG)(0x01000000))
+#define DC21X4_RDES_END_OF_RING ((ULONG)(0x02000000))
+
+#define RDES_FRAME_LENGTH_BIT_NUMBER 16
+
+
+//Constants for the TXM descriptor TDES
+
+#define DC21X4_TDES_DEFERRED ((ULONG)(0x00000001))
+#define DC21X4_TDES_UNDERRUN_ERROR ((ULONG)(0x00000002))
+#define DC21X4_TDES_LINK_FAIL ((ULONG)(0x00000004))
+#define DC21X4_TDES_COLLISION_COUNT ((ULONG)(0x00000078))
+#define DC21X4_TDES_HEARTBEAT_FAIL ((ULONG)(0x00000080))
+#define DC21X4_TDES_EXCESSIVE_COLLISIONS ((ULONG)(0x00000100))
+#define DC21X4_TDES_LATE_COLLISION ((ULONG)(0x00000200))
+#define DC21X4_TDES_NO_CARRIER ((ULONG)(0x00000400))
+#define DC21X4_TDES_LOSS_OF_CARRIER ((ULONG)(0x00000800))
+#define DC21X4_TDES_TXM_JABBER_TIMEOUT ((ULONG)(0x00004000))
+#define DC21X4_TDES_ERROR_SUMMARY ((ULONG)(0x00008000))
+#define DC21X4_TDES_OWN_BIT ((ULONG)(0x80000000))
+
+#define DC21X4_TDES_ERROR_MASK ((ULONG)( \
+ DC21X4_TDES_UNDERRUN_ERROR \
+ | DC21X4_TDES_EXCESSIVE_COLLISIONS \
+ | DC21X4_TDES_LATE_COLLISION \
+ | DC21X4_TDES_NO_CARRIER \
+ | DC21X4_TDES_LOSS_OF_CARRIER \
+ | DC21X4_TDES_TXM_JABBER_TIMEOUT \
+ ))
+
+#define DC21X4_TDES_FIRST_BUFFER_SIZE ((ULONG)(0x000007FF))
+#define DC21X4_TDES_SECOND_BUFFER_SIZE ((ULONG)(0x003FF800))
+#define DC21X4_TDES_HASH_FILTERING ((ULONG)(0x00400000))
+#define DC21X4_TDES_DISABLE_PADDING ((ULONG)(0x00800000))
+#define DC21X4_TDES_SECOND_ADDR_CHAINED ((ULONG)(0x01000000))
+#define DC21X4_TDES_END_OF_RING ((ULONG)(0x02000000))
+#define DC21X4_TDES_ADD_CRC_DISABLE ((ULONG)(0x04000000))
+#define DC21X4_TDES_SETUP_PACKET ((ULONG)(0x08000000))
+#define DC21X4_TDES_INVERSE_FILTERING ((ULONG)(0x10000000))
+#define DC21X4_TDES_FIRST_SEGMENT ((ULONG)(0x20000000))
+#define DC21X4_TDES_LAST_SEGMENT ((ULONG)(0x40000000))
+#define DC21X4_TDES_INTERRUPT_ON_COMPLETION ((ULONG)(0x80000000))
+
+#define TDES_SECOND_BUFFER_SIZE_BIT_NUMBER 11
+#define TDES_COLLISION_COUNT_BIT_NUMBER 3
+
+
+//Ownership of descriptors.
+
+#define DESC_OWNED_BY_SYSTEM ((ULONG)(0x00000000))
+#define DESC_OWNED_BY_DC21X4 ((ULONG)(0x80000000))
+
+//Size of the Ethernet frame header
+
+#define ETH_HEADER_SIZE 14
+
+//Size of the frame CRC field
+
+#define ETH_CRC_SIZE 4
+
+//Number of buffer segments per DC21X4 descriptor
+
+#define NUMBER_OF_SEGMENT_PER_DESC 2
+
+//Maximum buffer size
+
+#define DC21X4_MAX_BUFFER_SIZE 1536 // 12*128(=max cache line size)
+
+//Maximum LookAhead is the size maximum of the frame
+
+#define DC21X4_MAX_FRAME_SIZE 1514
+#define DC21X4_MAX_LOOKAHEAD 1514
+
+//Maximum number of physical segments DC21X4 accepts
+//in a single Ndis buffer. Above this threshold, the packet
+//is copied into a single physically contiguous buffer
+
+#define DC21X4_MAX_SEGMENTS 8
+
+//Minimal size of a Txm packet to be directly mapped
+//into the Transmit Ring.Under this threshold, the packet
+//is copied into a preallocated Txm buffer to avoid
+//the (expensive) physical mapping translation
+
+#define DC21X4_MIN_TXM_SIZE 256
+
+
+//Number of descriptors reserved for Txm packets
+//into the Txm desc ring
+
+#define DC21X4_NUMBER_OF_TRANSMIT_DESCRIPTORS 64
+
+//Number of descriptors reserved for setup processing
+//into the Txm desc ring
+
+#define DC21X4_NUMBER_OF_SETUP_DESCRIPTORS 2
+
+//Size of the Transmit descriptor ring
+
+#define TRANSMIT_RING_SIZE (DC21X4_NUMBER_OF_TRANSMIT_DESCRIPTORS+DC21X4_NUMBER_OF_SETUP_DESCRIPTORS+1)
+
+//Number and size of allocated Txm buffers;
+//Nbr of Txm buffers MUST BE A POWER OF 2
+
+#define DC21X4_NUMBER_OF_MAX_TRANSMIT_BUFFERS 4
+#define DC21X4_MAX_TRANSMIT_BUFFER_SIZE DC21X4_MAX_BUFFER_SIZE
+
+#define DC21X4_NUMBER_OF_MIN_TRANSMIT_BUFFERS 16
+#define DC21X4_MIN_TRANSMIT_BUFFER_SIZE DC21X4_MIN_TXM_SIZE
+
+
+//Number and size of allocated setup buffers
+
+#define DC21X4_NUMBER_OF_SETUP_BUFFERS 1
+#define DC21X4_SETUP_BUFFER_SIZE 192
+
+//Physical mapping registers allocated to the adapter
+
+#if _ALPHA_
+#define DEFAULT_MAP_REGISTERS 64
+#else
+#define DEFAULT_MAP_REGISTERS 32
+#endif
+
+
+#define DC21X4_MIN_MAP_REGISTERS 4
+#define DC21X4_MAX_MAP_REGISTERS 64
+
+//Size of the Receive descriptor ring
+
+#define DC21X4_MIN_RECEIVE_RING_SIZE 8
+#define DC21X4_MAX_RECEIVE_RING_SIZE 64
+
+#define DC21X4_RECEIVE_RING_SIZE 16
+
+#define DC21X4_RECEIVE_PACKETS 100
+
+//Size of allocated receive buffers:
+
+#define DC21X4_RECEIVE_BUFFER_SIZE DC21X4_MAX_BUFFER_SIZE
+
+
+//No_carrier & ExecessCollisions counter threshold
+
+#define NO_CARRIER_THRESHOLD 4
+#define EXCESS_COLLISIONS_THRESHOLD 4
+
+
+//Transmit Underrun Threshold and Max retries
+
+#define DC21X4_UNDERRUN_THRESHOLD 10
+#define DC21X4_UNDERRUN_MAX_RETRIES 2
+
+
+
+
+//Interrupt and frame thresholds for interrupt moderation
+
+#define DC21X4_MSK_THRESHOLD_DEFAULT_VALUE 500 //interrupt/second
+#define DC21X4_FRAME_THRESHOLD_DEFAULT_VALUE 400 //frames/second
+
+//NdisStallExecution (in microseconds)
+
+#define MILLISECOND 1000
+
+//Timer (in milliseconds)
+
+#define DC21X4_ANC_TIMEOUT 3000 // 3 s
+#define DC21X4_SPA_TICK 2000 // 2 s
+#define DC21X4_MII_TICK 5000 // 5 s
+#define DC21X4_LINK_DELAY 1000 // 1 s
+#define DC21X4_POLL_DELAY 100 // 100 ms
+#define DC21X4_ANC_DELAY 500 // 500 ms
+
+#define POLL_COUNT_TIMEOUT 40 // *DC21X4_POLL_DELAY = 4s
+
+#define MAX_LINK_CHECK 10
+#define LINK_CHECK_PERIOD 1000 // 1s
+
+#define INT_MONITOR_PERIOD 500 // 500ms
+
+// Built_in timer for MII100 (81.9 us tick)
+
+#define ONE_MILLISECOND_TICK 12 // 12 * 81.9 us
+
+//Loop timeout (*10 milliseconds)
+
+#define DC21X4_SETUP_TIMEOUT 50 // *10ms
+#define DC21X4_TXM_TIMEOUT 50 // *10ms
+#define DC21X4_RVC_TIMEOUT 50 // *10ms
+
+//Line speed (* 100 bps)
+
+#define TEN_MBPS 100000 // * 100bps
+#define ONE_HUNDRED_MBPS 1000000 // * 100bps
+
+
+
+
+
+
+
diff --git a/private/ntos/ndis/dc21x4/d21x4oid.h b/private/ntos/ndis/dc21x4/d21x4oid.h
new file mode 100644
index 000000000..1b13ef953
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/d21x4oid.h
@@ -0,0 +1,102 @@
+/*+
+ * file: d21x4oid.h
+ *
+ * Copyright (C) 1992-1995 by
+ * Digital Equipment Corporation, Maynard, Massachusetts.
+ * All rights reserved.
+ *
+ * This software is furnished under a license and may be used and copied
+ * only in accordance of the terms of such license and with the
+ * inclusion of the above copyright notice. This software or any other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person. No title to and ownership of the software is hereby
+ * transferred.
+ *
+ * The information in this software is subject to change without notice
+ * and should not be construed as a commitment by digital equipment
+ * corporation.
+ *
+ * Digital assumes no responsibility for the use or reliability of its
+ * software on equipment which is not supplied by digital.
+ *
+ *
+ * Abstract: This file contains the Object Identifiers (OIDs) supported by
+ * the NDIS 4.0 miniport driver for DEC's DC21X4 Ethernet Adapter
+ * family
+ *
+ * Author: Philippe Klein
+ *
+ * Revision History:
+ *
+ * phk 28-aug-1994 Initial entry
+ *
+-*/
+
+
+
+
+
+
+static const UCHAR DC21040EisaDescriptor[] = "DEC DC21040 EISA Ethernet Adapter";
+static const UCHAR DC21040PciDescriptor[] = "DEC DC21040 PCI Ethernet Adapter";
+static const UCHAR DC21041PciDescriptor[] = "DEC DC21041 PCI Ethernet Adapter";
+static const UCHAR DC21140PciDescriptor[] = "DEC DC21140 PCI Fast Ethernet Adapter";
+static const UCHAR DC21142PciDescriptor[] = "DEC DC21142 PCI Fast Ethernet Adapter";
+
+static const NDIS_OID DC21X4GlobalOids[] = {
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MEDIA_CONNECT_STATUS,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+ OID_GEN_DIRECTED_BYTES_XMIT,
+ OID_GEN_DIRECTED_FRAMES_XMIT,
+ OID_GEN_MULTICAST_BYTES_XMIT,
+ OID_GEN_MULTICAST_FRAMES_XMIT,
+ OID_GEN_BROADCAST_BYTES_XMIT,
+ OID_GEN_BROADCAST_FRAMES_XMIT,
+ OID_GEN_DIRECTED_BYTES_RCV,
+ OID_GEN_DIRECTED_FRAMES_RCV,
+ OID_GEN_MULTICAST_BYTES_RCV,
+ OID_GEN_MULTICAST_FRAMES_RCV,
+ OID_GEN_BROADCAST_BYTES_RCV,
+ OID_GEN_BROADCAST_FRAMES_RCV,
+ OID_GEN_RCV_CRC_ERROR,
+ OID_GEN_TRANSMIT_QUEUE_LENGTH,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ OID_802_3_RCV_ERROR_ALIGNMENT,
+ OID_802_3_XMIT_ONE_COLLISION,
+ OID_802_3_XMIT_MORE_COLLISIONS,
+ OID_802_3_XMIT_DEFERRED,
+ OID_802_3_XMIT_MAX_COLLISIONS,
+ OID_802_3_RCV_OVERRUN,
+ OID_802_3_XMIT_UNDERRUN,
+ OID_802_3_XMIT_HEARTBEAT_FAILURE,
+ OID_802_3_XMIT_TIMES_CRS_LOST,
+ OID_802_3_XMIT_LATE_COLLISIONS
+ };
+
+
diff --git a/private/ntos/ndis/dc21x4/d21x4rgs.h b/private/ntos/ndis/dc21x4/d21x4rgs.h
new file mode 100644
index 000000000..d4adf9918
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/d21x4rgs.h
@@ -0,0 +1,140 @@
+/*+
+ * file: d21x4rgs.h
+ *
+ * Copyright (C) 1992-1995 by
+ * Digital Equipment Corporation, Maynard, Massachusetts.
+ * All rights reserved.
+ *
+ * This software is furnished under a license and may be used and copied
+ * only in accordance of the terms of such license and with the
+ * inclusion of the above copyright notice. This software or any other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person. No title to and ownership of the software is hereby
+ * transferred.
+ *
+ * The information in this software is subject to change without notice
+ * and should not be construed as a commitment by digital equipment
+ * corporation.
+ *
+ * Digital assumes no responsibility for the use or reliability of its
+ * software on equipment which is not supplied by digital.
+ *
+ *
+ * Abstract: This file contains the string definitions of the
+ * Registry keys for the NDIS 4.0 miniport driver for
+ * DEC's DC21X4 Ethernet Adapter family.
+ *
+ * Author: Philippe Klein
+ *
+ * Revision History:
+ *
+ * phk 28-Aug-1994 Initial entry
+ * phk 12-Mar-1995 Add ConnectionType table
+ *
+-*/
+
+
+
+
+
+
+// Registry keys
+
+typedef enum DC21X4_REGISTRY_KEY {
+ RGS_ADPT = 0, // AdapterType
+ RGS_BUSN, // BusNumber
+ RGS_DEVN, // SlotNumber
+ RGS_FCTN, // FunctionNumber
+ RGS_CFID, // AdapterCfid
+ RGS_CFCS, // PciCommand
+ RGS_CFLT, // PciLatencyTimer
+ RGS_BLEN, // BurstLen
+ RGS_FARB, // FifoArbitration
+ RGS_THRS, // TransmitThreshold
+ RGS_THRS100, // TransmitThreshold100
+ RGS_BKOC, // BackoffCounter
+ RGS_BKPR, // BackPressure
+ RGS_CPTE, // CaptureEffect
+ RGS_TI, // TiPeriod
+ RGS_SCRC, // SoftwareCRC
+ RGS_ESIA, // ExternalSia
+ RGS_SIA0, // SiaRegister0
+ RGS_SIA1, // SiaRegister1
+ RGS_SIA2, // SiaRegister2
+ RGS_TRNS, // TransceiverDelay
+ RGS_CLSZ, // CacheLineSize
+ RGS_PLDM, // AutomaticPolling
+ RGS_RCVR, // ReceiveBuffers
+ RGS_STFD, // StoreAndForward
+ RGS_MAPR, // MapRegisters
+ RGS_ITMG, // InterruptMitigation
+ RGS_ITHR, // InterruptThreshold
+ RGS_FTHR, // FrameThreshold
+ RGS_UTHR, // UnderrunThreshold
+ RGS_UNDR, // UnderrunRetry
+ RGS_SNOO, // SnoozeMode
+ RGS_NWAY, // NwayProtocol
+ RGS_RCV_BUFS, // ExtraReceiveBuffers
+ RGS_RCV_PKTS, // ExtraReceivePackets
+ RGS_CNCT, // ConnectionType
+ MAX_RGS
+} DC21X4_REGISTRY_KEY;
+
+NDIS_STRING DC21X4ConfigString[] = {
+
+ NDIS_STRING_CONST("AdapterType"),
+ NDIS_STRING_CONST("BusNumber"),
+ NDIS_STRING_CONST("SlotNumber"),
+ NDIS_STRING_CONST("FunctionNumber"),
+ NDIS_STRING_CONST("AdapterCfid"),
+ NDIS_STRING_CONST("PciCommand"),
+ NDIS_STRING_CONST("PciLatencyTimer"),
+ NDIS_STRING_CONST("BurstLength"),
+ NDIS_STRING_CONST("FifoArbitration"),
+ NDIS_STRING_CONST("TransmitThreshold"),
+ NDIS_STRING_CONST("TransmitThreshold100"),
+ NDIS_STRING_CONST("BackoffCounter"),
+ NDIS_STRING_CONST("BackPressure"),
+ NDIS_STRING_CONST("CaptureEffect"),
+ NDIS_STRING_CONST("TiPeriod"),
+ NDIS_STRING_CONST("SoftwareCRC"),
+ NDIS_STRING_CONST("ExternalSia"),
+ NDIS_STRING_CONST("SiaRegister0"),
+ NDIS_STRING_CONST("SiaRegister1"),
+ NDIS_STRING_CONST("SiaRegister2"),
+ NDIS_STRING_CONST("TransceiverDelay"),
+ NDIS_STRING_CONST("CacheLineSize"),
+ NDIS_STRING_CONST("AutomaticPolling"),
+ NDIS_STRING_CONST("ReceiveBuffers"),
+ NDIS_STRING_CONST("StoreAndForward"),
+ NDIS_STRING_CONST("MapRegisters"),
+ NDIS_STRING_CONST("InterruptMitigation"),
+ NDIS_STRING_CONST("InterruptThreshold"),
+ NDIS_STRING_CONST("FrameThreshold"),
+ NDIS_STRING_CONST("UnderrunThreshold"),
+ NDIS_STRING_CONST("UnderrunRetry"),
+ NDIS_STRING_CONST("SnoozeMode"),
+ NDIS_STRING_CONST("NwayProtocol"),
+ NDIS_STRING_CONST("ExtraReceiveBuffers"),
+ NDIS_STRING_CONST("ExtraReceivePackets"),
+ NDIS_STRING_CONST("ConnectionType")
+};
+
+static const ULONG ConnectionType[]= {
+ 0x900, // 0 = AutoDetect , AutoSense
+ 0x001, // 1 = 10Base2 (BNC)
+ 0x000, // 2 = 10BaseT (TP)
+ 0x204, // 3 = 10BaseT Full_Duplex
+ 0x400, // 4 = 10BaseT No_Link_Test
+ 0x002, // 5 = 10Base5 (AUI)
+ 0x800, // 6 = AutoSense No_Nway
+ 0x900, // 7 = Reserved
+ 0x003, // 8 = 100BaseTx
+ 0x205, // 9 = 100BaseTx Full_Duplex
+ 0x006, //10 = 100BaseT4
+ 0x007, //11 = 100BaseFx
+ 0x208 //12 = 100BaseFx Full_Duplex
+};
+
+#define MAX_MEDIA 13
+
diff --git a/private/ntos/ndis/dc21x4/dc21x4.c b/private/ntos/ndis/dc21x4/dc21x4.c
new file mode 100644
index 000000000..1356686f2
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/dc21x4.c
@@ -0,0 +1,134 @@
+/*+
+ * file: DC21X4.c
+ *
+ * Copyright (C) 1992-1995 by
+ * Digital Equipment Corporation, Maynard, Massachusetts.
+ * All rights reserved.
+ *
+ * This software is furnished under a license and may be used and copied
+ * only in accordance of the terms of such license and with the
+ * inclusion of the above copyright notice. This software or any other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person. No title to and ownership of the software is hereby
+ * transferred.
+ *
+ * The information in this software is subject to change without notice
+ * and should not be construed as a commitment by digital equipment
+ * corporation.
+ *
+ * Digital assumes no responsibility for the use or reliability of its
+ * software on equipment which is not supplied by digital.
+ *
+ *
+ * Abstract: This file is the main file of the NDIS 4.0 miniport driver
+ * for DEC's 21X4 Ethernet Adapter family.
+ *
+ * Author: Philippe Klein
+ *
+ * Revision History:
+ *
+ * phk 30-Jul-1994 Initial entry
+ *
+-*/
+
+#include <precomp.h>
+
+#if __DBG
+#include "version.h"
+#endif
+
+
+
+
+
+
+
+
+#pragma NDIS_INIT_FUNCTION(DriverEntry)
+
+/*+
+ * DriverEntry
+ *
+ * Routine description:
+ *
+ * Driver Entry is the initial entry point of the DC21X4 driver called
+ * by the operating system.
+ *
+-*/
+
+
+// This is the NT-specific driver entry point.
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+
+{
+ NDIS_STATUS NdisStatus;
+ NDIS_HANDLE DC21X4WrapperHandle;
+ NDIS_MINIPORT_CHARACTERISTICS DC21X4Char;
+
+#if __DBG
+ DbgPrint("\n\n DC21X4 NDIS4.0 miniport driver %s - Built %s %s\n\n",
+ DRIVER_VERSION_STR,__DATE__,__TIME__);
+#endif
+
+ // Initialize the wrapper.
+#if __DBG
+ DbgPrint("NdisMInitializeWrapper\n");
+#endif
+
+ NdisMInitializeWrapper(
+ &DC21X4WrapperHandle,
+ DriverObject,
+ RegistryPath,
+ NULL
+ );
+
+#if _DBG
+ DbgPrint(" NdisMrapperHandle = %x\n",DC21X4WrapperHandle);
+#endif
+
+ // Initialize the characteristics before registering the MAC
+
+ DC21X4Char.MajorNdisVersion = DC21X4_NDIS_MAJOR_VERSION;
+ DC21X4Char.MinorNdisVersion = DC21X4_NDIS_MINOR_VERSION;
+ DC21X4Char.CheckForHangHandler = DC21X4CheckforHang;
+ DC21X4Char.DisableInterruptHandler = DC21X4DisableInterrupt;
+ DC21X4Char.EnableInterruptHandler = DC21X4EnableInterrupt;
+ DC21X4Char.HaltHandler = DC21X4Halt;
+ DC21X4Char.HandleInterruptHandler = DC21X4HandleInterrupt;
+ DC21X4Char.InitializeHandler = DC21X4Initialize;
+ DC21X4Char.ISRHandler = DC21X4Isr;
+ DC21X4Char.QueryInformationHandler = DC21X4QueryInformation;
+ DC21X4Char.ReconfigureHandler = NULL;
+ DC21X4Char.ResetHandler = DC21X4Reset;
+ DC21X4Char.SendHandler = DC21X4Send;
+ DC21X4Char.SetInformationHandler = DC21X4SetInformation;
+ DC21X4Char.TransferDataHandler = NULL;
+ DC21X4Char.ReturnPacketHandler = DC21X4ReturnPacket;
+ DC21X4Char.SendPacketsHandler = NULL; //DC21X4SendPackets;
+ DC21X4Char.AllocateCompleteHandler = DC21X4AllocateComplete;
+#if __DBG
+ DbgPrint("NdisMRegisterMiniport\n");
+#endif
+
+ NdisStatus = NdisMRegisterMiniport(
+ DC21X4WrapperHandle,
+ &DC21X4Char,
+ sizeof(DC21X4Char)
+ );
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ // Mac Registration completes on failure
+#if __DBG
+ DbgPrint(" NdisMRegisterMiniport failed: Status = %x\n",NdisStatus);
+#endif
+ NdisTerminateWrapper(DC21X4WrapperHandle, NULL);
+ }
+ return NdisStatus;
+}
+
diff --git a/private/ntos/ndis/dc21x4/dc21x4.hlp b/private/ntos/ndis/dc21x4/dc21x4.hlp
new file mode 100644
index 000000000..b0a38d700
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/dc21x4.hlp
Binary files differ
diff --git a/private/ntos/ndis/dc21x4/dc21x4.hpj b/private/ntos/ndis/dc21x4/dc21x4.hpj
new file mode 100644
index 000000000..9d9ef063f
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/dc21x4.hpj
@@ -0,0 +1,47 @@
+[OPTIONS]
+TITLE=Windows NT Setup
+CONTENTS=ALL
+ERRORLOG=dc21x4.err
+COMPRESS=0
+WARNING=3
+COPYRIGHT=Digital Equipment Corporation
+
+[FILES]
+dc21x4.rtf
+
+[MAP]
+ALL 1
+DC21040_TITLE 10
+DC21041_TITLE 20
+DC21140_TITLE 30
+DC21142_TITLE 40
+DC21143_TITLE 50
+EB40_TITLE 100
+EB41_TITLE 110
+EB140_TITLE 120
+EB142_TITLE 130
+EB143_TITLE 140
+MULTIA_TITLE 200
+DE434_TITLE 210
+DE435_TITLE 220
+DE436_TITLE 230
+DE450_TITLE 240
+DE500_TITLE 250
+
+AUTODETECT 1000
+AUTOSENSE 1010
+AUTOSENSE_NW 1020
+10BT 1030
+10BT_FD 1040
+10BT_NLT 1050
+10B2 1060
+10B5 1070
+100BTX 1080
+100BTX_FD 1090
+100BT4 1100
+100BFX 1110
+
+[WINDOWS]
+main=,(400,100,500,600),0,,,
+
+
diff --git a/private/ntos/ndis/dc21x4/dc21x4.rc b/private/ntos/ndis/dc21x4/dc21x4.rc
new file mode 100644
index 000000000..8e966c908
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/dc21x4.rc
@@ -0,0 +1,66 @@
+#include "version.h"
+#include <windows.h>
+
+#ifdef RC_INVOKED
+
+#define VER_LEGALCOPYRIGHT_YEARS "1992-1996"
+
+#define VER_LEGALCOPYRIGHT_STR "Copyright\251 Digital Equip. Corp." VER_LEGALCOPYRIGHT_YEARS
+
+#define VER_FILETYPE VFT_DRV
+
+#define VER_FILESUBTYPE FT2_DRV_NETWORK
+
+#define VER_PRODUCTVERSION DRIVER_VERSION
+
+#define VER_PRODUCTVERSION_STR DRIVER_VERSION_STR
+
+
+#define VER_FILEDESCRIPTION_STR "NDIS 4.0 DC21X4 miniport driver"
+
+#define VER_INTERNALNAME_STR "DC21X4.SYS"
+
+#define VER_PRODUCTNAME_STR "Digital Semiconductor\256 21X4 PCI Ethernet controllers"
+
+#define VER_COMPANYNAME_STR "Digital Semiconductor - Digital Equipment Corporation."
+
+
+
+#define VER_ORIGINALFILENAME_STR VER_INTERNALNAME_STR
+
+#define VER_FILEVERSION VER_PRODUCTVERSION
+
+#define VER_FILEVERSION_STR VER_PRODUCTVERSION_STR
+
+
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION VER_FILEVERSION
+PRODUCTVERSION VER_PRODUCTVERSION
+
+
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904B0" /* LANG_ENGLISH/SUBLANG_ENGLISH_US, Unicode CP */
+ BEGIN
+ VALUE "CompanyName", VER_COMPANYNAME_STR
+ VALUE "FileDescription", VER_FILEDESCRIPTION_STR
+ VALUE "FileVersion", VER_FILEVERSION_STR
+ VALUE "InternalName", VER_INTERNALNAME_STR
+ VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR
+ VALUE "OriginalFilename",VER_ORIGINALFILENAME_STR
+ VALUE "ProductName", VER_PRODUCTNAME_STR
+ VALUE "ProductVersion", VER_PRODUCTVERSION_STR
+ END
+
+ END
+
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x040904B0L
+ END
+END
+#endif
+
+
+
diff --git a/private/ntos/ndis/dc21x4/dc21x4.rtf b/private/ntos/ndis/dc21x4/dc21x4.rtf
new file mode 100644
index 000000000..94e9e0972
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/dc21x4.rtf
@@ -0,0 +1,199 @@
+{\rtf1\ansi\deff31
+{\fonttbl
+\f0\fswiss System;
+\f1\fmodern Fixedsys;
+\f2\fmodern 8514oem;
+\f3\fmodern Modern;
+\f4\fscript Script;
+\f5\froman Roman;
+\f6\fswiss Small Fonts;
+\f7\froman MS Serif;
+\f8\fmodern Courier;
+\f9\fswiss MS Sans Serif;
+\f10\fswiss V1 Lucida Sans;
+\f11\fswiss V1 Lucida Sans Bold;
+\f12\fswiss V1 Lucida Sans Italic;
+\f13\fswiss V2 Lucida Sans;
+\f14\fswiss V2 Lucida Sans Bold;
+\f15\fswiss V2 Lucida Sans Italic;
+\f16\fswiss V3 Lucida Sans;
+\f17\fswiss V3 Lucida Sans Bold;
+\f18\fswiss V3 Lucida Sans Italic;
+\f19\fswiss V4 Lucida Sans;
+\f20\fswiss V4 Lucida Sans Bold;
+\f21\fswiss V4 Lucida Sans Italic;
+\f22\fswiss V5 Lucida Sans;
+\f23\fswiss V6 Lucida Sans;
+\f24\fswiss V7 Lucida Sans;
+\f25\fswiss V7 Lucida Sans Bold;
+\f26\fswiss V7 Lucida Sans Italic;
+\f29\fnil Simple Latin;
+\f30\froman HM Phonetic;
+\f31\fswiss Arial;
+\f32\fmodern Courier New;
+\f33\froman Times New Roman;
+\f34\fnil Wingdings;
+\f35\froman Book Antiqua;
+\f36\fswiss Arial Narrow;
+\f37\froman Bookman Old Style;
+\f38\fswiss Century Gothic;
+\f39\fscript Monotype Corsiva;
+\f40\fnil Monotype Sorts;
+\f41\froman Century Schoolbook;
+\f42\froman MT Extra;
+\f43\fmodern MS LineDraw;
+\f44\fdecor Algerian;
+\f45\fswiss Arial Rounded MT Bold;
+\f46\fdecor Braggadocio;
+\f47\fswiss Britannic Bold;
+\f48\fscript Brush Script MT;
+\f49\fdecor Colonna MT;
+\f50\fdecor Desdemona;
+\f51\froman Footlight MT Light;
+\f52\fswiss Impact;
+\f53\fdecor Kino MT;
+\f54\froman Wide Latin;
+\f55\fscript Matura MT Script Capitals;
+\f56\fdecor Playbill;
+\f57\froman Symbol;
+\f58\fswiss Lucida Sans;
+\f59\fscript Lucida Blackletter;
+\f60\fscript Lucida Handwriting;
+\f61\fdecor Stencil;
+\f79\fnil MF Graffiti;
+\f84\fnil MS Reference 1;
+\f85\fnil MS Reference 2;
+}
+{\colortbl;
+\red0\green0\blue0;
+\red128\green0\blue0;
+\red0\green128\blue0;
+\red128\green128\blue0;
+\red0\green0\blue128;
+\red128\green0\blue128;
+\red0\green128\blue128;
+\red128\green128\blue128;
+\red192\green192\blue192;
+\red255\green0\blue0;
+\red0\green255\blue0;
+\red255\green255\blue0;
+\red0\green0\blue255;
+\red255\green0\blue255;
+\red0\green255\blue255;
+\red255\green255\blue255;
+}
+${\footnote $ D21x4 Family}
+#{\footnote # ALL}
++{\footnote + 00001}
+\keepn \f9 \fs24 \cf0 Digital Semiconductor's 21X4 PCI Ethernet Controller Family\par\pard\fs20\cf0 \par \uldb 21040\uldb0 \v DC21040_TITLE\v0 \par\uldb 21041\uldb0 \v DC21041_TITLE\v0 \par\uldb 21140\uldb0 \v DC21140_TITLE\v0 \par\uldb 21142\uldb0 \v DC21142_TITLE\v0 \par\uldb 21143\uldb0 \v DC21143_TITLE\v0 \par\uldb EB40\uldb0 \v EB40_TITLE\v0 \par\uldb EB41\uldb0 \v EB41_TITLE\v0 \par\uldb EB140\uldb0 \v EB140_TITLE\v0 \par\uldb EB142\uldb0 \v EB142_TITLE\v0 \par\uldb EB143\uldb0 \v EB143_TITLE\v0 \par\uldb MULTIA\uldb0 \v MULTIA_TITLE\v0 \par\page
+${\footnote $ Digital Semiconductor's 21040 PCI Ethernet Controller}
+#{\footnote # DC21040_TITLE}
++{\footnote + 00002}
+\keepn \f9 \fs24 \cf0 Digital Semiconductor's 21040 PCI Ethernet Controller \par \pard \f9 \fs24 \pard \fs20 \cf0 Use this dialog box to setup the medium connection for Digital Equipment Corporation's Digital Semiconductor's 21040 based Adapter.\par \par \ul AutoDetect\ul0 \v AUTODETECT\v0 \par \ul Twisted_Pair (10BaseT)\ul0 \v 10BT\v0 \par \ul Twisted_Pair Full_Duplex\ul0 \v 10BT_FD\v0 \par \ul Twisted_Pair No_Link_Test\ul0 \v 10BT_NLT\v0 \par \ul BNC (10Base2)\ul0 \v 10B2\v0 \par \ul AUI (10Base5)\ul0 \v 10B5\v0 \par \page
+${\footnote $ Digital Semiconductor's 21041 PCI Ethernet Controller}
+#{\footnote # DC21041_TITLE}
++{\footnote + 00003}
+\keepn \f9 \fs24 \cf0 Digital Semiconductor's 21041 PCI Ethernet Controller \par \pard \f9 \fs24 \pard \fs20 \cf0 Use this dialog box to setup the medium connection for Digital Equipment Corporation's Digital Semiconductor's 21041 based Adapter.\par \par \ul AutoSense\ul0 \v AUTOSENSE\v0 \par \ul AutoSense No_Nway\ul0 \v AUTOSENSE_NW\v0 \par \ul Twisted_Pair (10BaseT)\ul0 \v 10BT\v0 \par \ul Twisted_Pair Full_Duplex\ul0 \v 10BT_FD\v0 \par \ul Twisted_Pair No_Link_Test\ul0 \v 10BT_NLT\v0 \par \ul BNC (10Base2)\ul0 \v 10B2\v0 \par \ul AUI (10Base5)\ul0 \v 10B5\v0 \par \page
+${\footnote $ Digital Semiconductor's 21140 PCI Fast Ethernet Controller}
+#{\footnote # DC21140_TITLE}
++{\footnote + 00004}
+\keepn \f9 \fs24 \cf0 Digital Semiconductor's 21140 PCI Fast Ethernet Controller \par \pard \f9 \fs24 \pard \fs20 \cf0 Use this dialog box to setup the medium connection for Digital Equipment Corporation's Digital Semiconductor's 21140 based Adapter.\par \par \ul AutoSense\ul0 \v AUTOSENSE\v0 \par \ul AutoSense No_Nway\ul0 \v AUTOSENSE_NW\v0 \par \ul 100BaseTx\ul0 \v 100BTX\v0 \par \ul 100BaseTx Full_Duplex\ul0 \v 100BTX_FD\v0 \par \ul 100BaseT4\ul0 \v 100BT4\v0 \par \ul 100BaseFx\ul0 \v 100BFX\v0 \par \ul 10BaseT\ul0 \v 10BT\v0 \par \ul 10BaseT Full_Duplex\ul0 \v 10BT_FD\v0 \par \page
+${\footnote $ Digital Semiconductor's DC21142 PCI Ethernet Controller}
+#{\footnote # DC21142_TITLE}
++{\footnote + 00005}
+\keepn \f9 \fs24 \cf0 Digital Semiconductor's 21142 PCI Ethernet Controller \par \pard \f9 \fs24 \pard \fs20 \cf0 Use this dialog box to setup the medium connection for Digital Equipment Corporation's Digital Semiconductor's 21142 based Adapter.\par \par \ul AutoSense\ul0 \v AUTOSENSE\v0 \par \ul 100BaseTx\ul0 \v 100BTX\v0 \par \ul 100BaseTx Full_Duplex\ul0 \v 100BTX_FD\v0 \par \ul 100BaseT4\ul0 \v 100BT4\v0 \par \ul 100BaseFx\ul0 \v 100BFX\v0 \par \ul 10BaseT\ul0 \v 10BT\v0 \par \ul 10BaseT Full_Duplex\ul0 \v 10BT_FD\v0 \par \ul 10BaseT No_Link_Test\ul0 \v 10BT_NLT\v0 \par \ul 10Base2 (BNC)\ul0 \v 10B2\v0 \par \ul 10Base5 (AUI)\ul0 \v 10B5\v0 \par \page
+${\footnote $ Digital Semiconductor's DC21143 PCI Ethernet Controller}
+#{\footnote # DC21143_TITLE}
++{\footnote + 00006}
+\keepn \f9 \fs24 \cf0 Digital Semiconductor's 21143 PCI Ethernet Controller \par \pard \f9 \fs24 \pard \fs20 \cf0 Use this dialog box to setup the medium connection for Digital Equipment Corporation's Digital Semiconductor's 21143 based Adapter.\par \par \ul AutoSense\ul0 \v AUTOSENSE\v0 \par \ul 100BaseTx\ul0 \v 100BTX\v0 \par \ul 100BaseTx Full_Duplex\ul0 \v 100BTX_FD\v0 \par \ul 100BaseT4\ul0 \v 100BT4\v0 \par \ul 100BaseFx\ul0 \v 100BFX\v0 \par \ul 10BaseT\ul0 \v 10BT\v0 \par \ul 10BaseT Full_Duplex\ul0 \v 10BT_FD\v0 \par \ul 10BaseT No_Link_Test\ul0 \v 10BT_NLT\v0 \par \ul 10Base2 (BNC)\ul0 \v 10B2\v0 \par \ul 10Base5 (AUI)\ul0 \v 10B5\v0 \par \page
+${\footnote $ EB40 - Digital Semiconductor's 21040 Evaluation Board}
+#{\footnote # EB40_TITLE}
++{\footnote + 00007}
+\keepn \f9 \fs24 \cf0 EB40 - Digital Semiconductor's 21040's Evaluation Board\par \pard \f9 \fs24 \pard \fs20 \cf0 Use this dialog box to setup the medium connection for Digital Equipment Corporation's EB40 Evaluation Board.\par \par \ul Twisted_Pair (10BaseT)\ul0 \v 10BT\v0 \par \ul Twisted_Pair Full_Duplex\ul0 \v 10BT_FD\v0 \par \ul Twisted_Pair No_Link_Test\ul0 \v 10BT_NLT\v0 \par \page
+${\footnote $ EB41 - Digital Semiconductor's 21041 Evaluation Board}
+#{\footnote # EB41_TITLE}
++{\footnote + 00008}
+\keepn \f9 \fs24 \cf0 EB41 - Digital Semiconductor's 21041's Evaluation Board\par \pard \f9 \fs24 \pard \fs20 \cf0 Use this dialog box to setup the medium connection for Digital Equipment Corporation's EB41 Evaluation Board.\par \par \ul AutoSense\ul0 \v AUTOSENSE\v0 \par \ul AutoSense No_Nway \ul0 \v AUTOSENSE_NW\v0 \par \ul Twisted_Pair (10BaseT)\ul0 \v 10BT\v0 \par \ul Twisted_Pair Full_Duplex\ul0 \v 10BT_FD\v0 \par \ul Twisted_Pair No_Link_Test\ul0 \v 10BT_NLT\v0 \par \ul BNC (10Base2)\ul0 \v 10B2\v0 \par \ul AUI (10Base5)\ul0 \v 10B5\v0 \par \page
+${\footnote $ EB140 - Digital Semiconductor's 21140 Evaluation Board}
+#{\footnote # EB140_TITLE}
++{\footnote + 00009}
+\keepn \f9 \fs24 \cf0 EB140 - Digital Semiconductor's 21140's Evaluation Board\par \pard \f9 \fs24 \pard \fs20 \cf0 Use this dialog box to setup the medium connection for Digital Equipment Corporation's EB140 Evaluation Board.\par \par \ul AutoSense\ul0 \v AUTOSENSE\v0 \par \ul 100BaseTx\ul0 \v 100BTX\v0 \par \ul 100BaseTx Full_Duplex\ul0 \v 10BT_FD\v0 \par \ul 10BaseT\ul0 \v 10BT\v0 \par \ul 10BaseT Full_Duplex\ul0 \v 10BT_FD\v0 \par \page
+#{\footnote # EB142_TITLE}
++{\footnote + 00010}
+\keepn \f9 \fs24 \cf0 EB142 - Digital Semiconductor's 21142's Evaluation Board\par \pard \f9 \fs24 \pard \fs20 \cf0 Use this dialog box to setup the medium connection for Digital Equipment Corporation's EB142 Evaluation Board.\par \par \ul AutoSense\ul0 \v AUTOSENSE\v0 \par \ul 100BaseTx\ul0 \v 100BTX\v0 \par \ul 100BaseTx Full_Duplex\ul0 \v 100BTX_FD\v0 \par \ul 100BaseT4\ul0 \v 100BT4\v0 \par \ul 100BaseFx\ul0 \v 100BFX\v0 \par \ul 10BaseT\ul0 \v 10BT\v0 \par \ul 10BaseT Full_Duplex\ul0 \v 10BT_FD\v0 \par \ul 10BaseT No_Link_Test\ul0 \v 10BT_NLT\v0 \par \ul 10Base2 (BNC)\ul0 \v 10B2\v0 \par \page
+#{\footnote # EB143_TITLE}
++{\footnote + 00011}
+\keepn \f9 \fs24 \cf0 EB143 - Digital Semiconductor's 21143's Evaluation Board\par \pard \f9 \fs24 \pard \fs20 \cf0 Use this dialog box to setup the medium connection for Digital Equipment Corporation's EB143 Evaluation Board.\par \par \ul AutoSense\ul0 \v AUTOSENSE\v0 \par \ul 100BaseTx\ul0 \v 100BTX\v0 \par \ul 100BaseTx Full_Duplex\ul0 \v 100BTX_FD\v0 \par \ul 100BaseT4\ul0 \v 100BT4\v0 \par \ul 100BaseFx\ul0 \v 100BFX\v0 \par \ul 10BaseT\ul0 \v 10BT\v0 \par \ul 10BaseT Full_Duplex\ul0 \v 10BT_FD\v0 \par \ul 10BaseT No_Link_Test\ul0 \v 10BT_NLT\v0 \par \ul 10Base2 (BNC)\ul0 \v 10B2\v0 \par \page
+${\footnote $ DEC multia's Ethernet Controller}
+#{\footnote # MULTIA_TITLE}
++{\footnote + 00012}
+\keepn \f9 \fs24 \cf0 DEC multia's Ethernet Controller \par \pard \f9 \fs24 \pard \fs20 \cf0 Use this dialog box to setup the medium connection for Digital Equipment Corporation multia's Ethernet Controller.\par \par\ul AutoDetect\ul0 \v AUTODETECT\v0 \par \ul Twisted_Pair (10BaseT)\ul0 \v 10BT\v0 \par \ul Twisted_Pair Full_Duplex\ul0 \v 10BT_FD\v0 \par \ul Twisted_Pair No_Link_Test\ul0 \v 10BT_NLT\v0 \par \ul BNC (10Base2)\ul0 \v 10B2\v0 \par \ul AUI (10Base5)\ul0 \v 10B5\v0 \par \page
+${\footnote $ DEC DE434 EtherWORKS Turbo PCI TP Adapter}
+#{\footnote # DE434_TITLE}
++{\footnote + 00013}
+\keepn \f9 \fs24 \cf0 DEC DE434 EtherWORKS Turbo PCI TP Adapter\par \pard \f9 \fs24 \pard \fs20 \cf0 Use this dialog box to setup the medium connection for Digital Equipment Corporation's DE434 EtherWORKS Turbo PCI TP Adapter.\par \par \ul AutoDetect\ul0 \v AUTODETECT\v0 \par \ul Twisted_Pair (10BaseT)\ul0 \v 10BT\v0 \par \ul Twisted_Pair Full_Duplex\ul0 \v 10BT_FD\v0 \par \ul Twisted_Pair No_Link_Test\ul0 \v 10BT_NLT\v0 \par \page
+${\footnote $ DEC DE435 EtherWORKS Turbo PCI Adapter}
+#{\footnote # DE435_TITLE}
++{\footnote + 00014}
+\keepn \f9 \fs24 \cf0 DEC DE435 EtherWORKS Turbo PCI Adapter\par \pard \f9 \fs24 \pard \fs20 \cf0 Use this dialog box to setup the medium connection for Digital Equipment Corporation's DE435 EtherWORKS Turbo PCI Adapter.\par \par \ul AutoDetect\ul0 \v AUTODETECT\v0 \par \ul Twisted_Pair (10BaseT)\ul0 \v 10BT\v0 \par \ul Twisted_Pair Full_Duplex\ul0 \v 10BT_FD\v0 \par \ul Twisted_Pair No_Link_Test\ul0 \v 10BT_NLT\v0 \par \ul BNC (10Base2)\ul0 \v 10B2\v0 \par \ul AUI (10Base5)\ul0 \v 10B5\v0 \par \page
+${\footnote $ DEC DE436 EtherWORKS Turbo PCI Quad Adapter}
+#{\footnote # DE436_TITLE}
++{\footnote + 00015}
+\keepn \f9 \fs24 \cf0 DEC DE436 EtherWORKS Turbo PCI Quad Adapter\par \pard \f9 \fs24 \pard \fs20 \cf0 Use this dialog box to setup the medium connection for Digital Equipment Corporation's DE436 EtherWORKS Turbo PCI Quad Adapter.\par \par \ul AutoDetect\ul0 \v AUTODETECT\v0 \par \ul Twisted_Pair (10BaseT)\ul0 \v 10BT\v0 \par \ul Twisted_Pair Full_Duplex\ul0 \v 10BT_FD\v0 \par \ul Twisted_Pair No_Link_Test\ul0 \v 10BT_NLT\v0 \par \page
+${\footnote $ DEC DE435 EtherWORKS Turbo PCI Adapter}
+#{\footnote # DE450_TITLE}
++{\footnote + 00016}
+\keepn \f9 \fs24 \cf0 DEC DE450 EtherWORKS Turbo PCI Adapter\par \pard \f9 \fs24 \pard \fs20 \cf0 Use this dialog box to setup the medium connection for Digital Equipment Corporation's DE450 EtherWORKS Turbo PCI Adapter.\par \par \ul AutoDetect\ul0 \v AUTODETECT\v0 \par \ul Twisted_Pair (10BaseT)\ul0 \v 10BT\v0 \par \ul Twisted_Pair Full_Duplex\ul0 \v 10BT_FD\v0 \par \ul Twisted_Pair No_Link_Test\ul0 \v 10BT_NLT\v0 \par \ul BNC (10Base2)\ul0 \v 10B2\v0 \par \ul AUI (10Base5)\ul0 \v 10B5\v0 \par \page
+${\footnote $ DEC DE500 FastEtherWORKS Turbo PCI Adapter}
+#{\footnote # DE500_TITLE}
++{\footnote + 00017}
+\keepn \f9 \fs24 \cf0 DEC DE500 FastEtherWORKS Turbo PCI Adapter\par \pard \f9 \fs24 \pard \fs20 \cf0 Use this dialog box to setup the medium connection for Digital Equipment Corporation's DE500 FastEtherWORKS Turbo PCI Adapter.\par \par \ul AutoSense\ul0 \v AUTOSENSE\v0 \par \ul 100BaseTx\ul0 \v 100BTX\v0 \par \ul 100BaseTx Full_Duplex\ul0 \v 10BT_FD\v0 \par \ul 10BaseT\ul0 \v 10BT\v0 \par \ul 10BaseT Full_Duplex\ul0 \v 10BT_FD\v0 \par \page
+${\footnote $ AutoDetect}
+#{\footnote # AUTODETECT}
++{\footnote + 00018}
+\f9 \fs24 \pard \fs20 \cf0 Check once the 10BaseT (TP), 10Base2 (BNC) and 10Base5 (AUI) media ports and select the first live media. \par This detection takes place during driver initialization: the wire should be connected \b before\b0 the system boots and media \b cannot \b0 be switched during run time.\par AutoDectect does\cf10 \cf1 \b not\b0 check 10BaseT's Full_Duplex and No_Link_Test modes.\par \fs24 \page
+${\footnote $ AutoSense}
+#{\footnote # AUTOSENSE}
++{\footnote + 00019}
+\f9 \fs24 \pard \fs20 \cf0 Autosense the media ports supported by the Adapter and dynamically switch to the live media.\par (AutoSense does \b not \b0 sense 10BaseT's No_Link_Test mode.)\par \fs24 \page
+${\footnote $ AutoSense - No_Nway}
+#{\footnote # AUTOSENSE_NW}
++{\footnote + 00020}
+\f9 \fs24 \pard \fs20 \cf0 Autosense the media ports supported by the Adapter and dynamically switch to the live media.\par Nway's negociation is\b disabled\b0 .\par (AutoSense no_Nway does \b not \b0 sense 10BaseT's No_Link_Test mode.)\par \page
+${\footnote $ 10BaseT}
+#{\footnote # 10BT}
++{\footnote + 00021}
+\f9 \fs24 \pard \fs20 \cf0 Select the 10BaseT medium connection (RJ connector).\par \fs24 \page
+${\footnote $ 10BaseT - Full_Duplex}
+#{\footnote # 10BT_FD}
++{\footnote + 00022}
+\f9 \fs24 \pard \fs20 \cf0 Select the 10BaseT Full_Duplex medium connection (RJ connector).\par \page
+${\footnote $ 10BaseT No_Link_Test}
+#{\footnote # 10BT_NLT}
++{\footnote + 00023}
+\f9 \fs24 \pard \fs20 \cf0 Select the 10BaseT medium connection (RJ connector) with no Link Integrity Test.\par Choose this option if the Adapter is connected to a hub which does \b not\b0 generate link pulses to check the link integrity.\par \fs24 \page
+${\footnote $ 10Base2 - BNC}
+#{\footnote # 10B2}
++{\footnote + 00024}
+\f9 \fs24 \pard \fs20 \cf0 Select the 10Base2 medium connection (BNC connector).\par \fs24 \page
+${\footnote $ 10Base5 - AUI}
+#{\footnote # 10B5}
++{\footnote + 00025}
+\f9 \fs24 \pard \fs20 \cf0 Select the 10Base5 medium connection (AUI 15_pin connector).\par \fs24 \page
+${\footnote $ 100BaseTx}
+#{\footnote # 100BTX}
++{\footnote + 00026}
+\f9 \fs24 \pard \fs20 \cf0 Select the Fast Ethernet 100BaseTx medium connection (RJ connector).\par \fs24 \page
+${\footnote $ 100BaseTx Full_Duplex}
+#{\footnote # 100BTX_FD}
++{\footnote + 00027}
+\f9 \fs24 \pard \fs20 \cf0 Select the Fast Ethernet 100BaseTx Full_Duplex medium connection (RJ connector).\par \page
+${\footnote $ 100BaseT4}
+#{\footnote # 100BT4}
++{\footnote + 00028}
+\f9 \fs24 \pard \fs20 \cf0 Select the Fast Ethernet 100BaseT4 medium connection (RJ connector).\par \fs24 \page
+${\footnote $ 100BaseFx}
+#{\footnote # 100BFX}
++{\footnote + 00029}
+\f9 \fs24 \pard \fs20 \cf0 Select the Fast Ethernet 100BaseFx medium connection.\par \fs24 \page
+}
diff --git a/private/ntos/ndis/dc21x4/filter.c b/private/ntos/ndis/dc21x4/filter.c
new file mode 100644
index 000000000..d358f5d35
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/filter.c
@@ -0,0 +1,758 @@
+/*+
+ * file: filter.c
+ *
+ * Copyright (C) 1992-1995 by
+ * Digital Equipment Corporation, Maynard, Massachusetts.
+ * All rights reserved.
+ *
+ * This software is furnished under a license and may be used and copied
+ * only in accordance of the terms of such license and with the
+ * inclusion of the above copyright notice. This software or any other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person. No title to and ownership of the software is hereby
+ * transferred.
+ *
+ * The information in this software is subject to change without notice
+ * and should not be construed as a commitment by digital equipment
+ * corporation.
+ *
+ * Digital assumes no responsibility for the use or reliability of its
+ * software on equipment which is not supplied by digital.
+ *
+ *
+ * Abstract: This file is part of the NDIS 4.0 miniport driver for DEC's
+ * DC21X4 Ethernet adapter family.
+ *
+ * Author: Philippe Klein
+ *
+ * Revision History:
+ *
+ * phk 31-Jul-94 Creation date
+ *
+ * phk 18-dec-94 Add a dummy descriptor in front of the setup
+ * descriptor to cover the underrun before
+ * setup descriptor case.
+ *
+-*/
+
+#include <precomp.h>
+
+
+
+
+#pragma NDIS_PAGABLE_FUNCTION(DC21X4InitializeCam)
+
+/*+
+ *
+ * DC21X4InitializeCam
+ *
+ * Routine Description:
+ *
+ * Initialize the DC21X4 CAM
+ *
+-*/
+extern
+VOID
+DC21X4InitializeCam (
+ IN PDC21X4_ADAPTER Adapter,
+ IN PUSHORT Address
+ )
+{
+
+ UINT i;
+ PDC21X4_SETUP_BUFFER SetupBuffer;
+
+ SetupBuffer = (PDC21X4_SETUP_BUFFER)Adapter->SetupBufferVa;
+
+ // Perfect Filtering Setup Buffer
+
+ Adapter->FilteringMode = DC21X4_PERFECT_FILTERING;
+
+ // Copy Address into the first entry
+
+ for (i=0; i<3; i++) {
+
+ (USHORT)(SetupBuffer->Perfect.PhysicalAddress[0][i]) = *Address++;
+ }
+
+ // Duplicate the first entry in all the remaining
+ // entries of the filter
+
+ for (i = 1; i < DC21X4_SETUP_PERFECT_ENTRIES; i++) {
+
+ MOVE_MEMORY(
+ SetupBuffer->Perfect.PhysicalAddress[i],
+ SetupBuffer->Perfect.PhysicalAddress[0],
+ sizeof(ULONG)*3
+ );
+ }
+
+ return;
+}
+
+
+
+
+
+
+
+
+
+
+/*+
+ *
+ * DC21X4LoadCam
+ *
+ * Routine Description:
+ *
+ * Load the Setup Buffer into DC21X4's CAM
+ *
+ * Arguments:
+ *
+ * Adapter - the Adapter for the hardware
+ * InterruptMode - Synchronize the Setup Buffer completion on interrupt
+ *
+-*/
+extern
+BOOLEAN
+DC21X4LoadCam (
+ IN PDC21X4_ADAPTER Adapter,
+ IN BOOLEAN InterruptMode
+ )
+{
+ PDC21X4_TRANSMIT_DESCRIPTOR SetupDescriptor;
+ PDC21X4_TRANSMIT_DESCRIPTOR DummyDescriptor;
+ UINT Time = DC21X4_SETUP_TIMEOUT;
+ ULONG DC21X4Status;
+ ULONG DC21X4Command;
+
+#if _DBG
+ PULONG t;
+ UINT i;
+ DbgPrint("DC21X4LoadCam\n");
+#endif
+
+
+ if (!InterruptMode) {
+
+ // Mask the interrupts
+ DC21X4_WRITE_PORT(
+ DC21X4_INTERRUPT_MASK,
+ 0
+ );
+ }
+
+
+ if (Adapter->FullDuplex) {
+ NdisDprAcquireSpinLock(&Adapter->EnqueueSpinLock);
+ }
+
+ DummyDescriptor = Adapter->EnqueueTransmitDescriptor;
+ Adapter->EnqueueTransmitDescriptor = (Adapter->EnqueueTransmitDescriptor)->Next;
+
+ SetupDescriptor = Adapter->EnqueueTransmitDescriptor;
+ Adapter->EnqueueTransmitDescriptor = (Adapter->EnqueueTransmitDescriptor)->Next;
+
+ if (Adapter->FullDuplex) {
+ NdisDprReleaseSpinLock(&Adapter->EnqueueSpinLock);
+ NdisDprAcquireSpinLock(&Adapter->FullDuplexSpinLock);
+ }
+
+ Adapter->FreeTransmitDescriptorCount -= 2;
+
+ if (Adapter->FullDuplex) {
+ NdisDprReleaseSpinLock(&Adapter->FullDuplexSpinLock);
+ }
+
+ // Initialize the Dummy descriptor
+
+ DummyDescriptor->Control &= DC21X4_TDES_SECOND_ADDR_CHAINED;
+ DummyDescriptor->FirstBufferAddress = 0;
+ DummyDescriptor->Status = DESC_OWNED_BY_DC21X4;
+
+ // Initialize the Setup descriptor
+
+ SetupDescriptor->Control &= DC21X4_TDES_SECOND_ADDR_CHAINED;
+ SetupDescriptor->Control |=
+ (DC21X4_TDES_SETUP_PACKET | DC21X4_TDES_INTERRUPT_ON_COMPLETION
+ | DC21X4_SETUP_BUFFER_SIZE);
+
+ if (Adapter->FilteringMode != DC21X4_PERFECT_FILTERING) {
+ SetupDescriptor->Control |= DC21X4_TDES_HASH_FILTERING;
+ }
+
+ SetupDescriptor->FirstBufferAddress = Adapter->SetupBufferPa;
+ SetupDescriptor->Status = DESC_OWNED_BY_DC21X4;
+
+#if _DBG
+ DbgPrint("Setup Descriptor: %08x\n %08x\n %08x\n %08x\n %08x\n",
+ SetupDescriptor,
+ SetupDescriptor->Status,
+ SetupDescriptor->Control,
+ SetupDescriptor->FirstBufferAddress,
+ SetupDescriptor->SecondBufferAddress);
+
+ t = (PULONG)Adapter->SetupBufferVa;
+ DbgPrint("Setup buffer:\n");
+ for (i = 0; i < 16; i++, t+=3) {
+ DbgPrint(" [%08x] %08x %08x %08x\n",t,*t,*(t+1),*(t+2));
+ }
+#endif
+
+
+ // Start or Poll the Transmitter to process the Setup Frame
+
+ if ((Adapter->DeviceId == DC21040_CFID) &&
+ (Adapter->RevisionNumber == DC21040_REV1)) {
+
+ // Txm hang workaround : Disable the SIA before
+ // writing the Operation Mode register
+ // SFD workaround : Disable the Receiver before processing
+ // the setup packet
+
+ DC21X4_WRITE_PORT(
+ DC21X4_SIA_MODE_0,
+ DC21X4_RESET_SIA
+ );
+
+ NdisStallExecution(1*MILLISECOND); // Wait 1 ms
+
+ DC21X4_WRITE_PORT(
+ DC21X4_OPERATION_MODE,
+ (Adapter->OperationMode & ~DC21X4_RCV_START)
+ );
+ }
+
+ DC21X4_READ_PORT(
+ DC21X4_OPERATION_MODE,
+ &DC21X4Command
+ );
+
+ if (DC21X4Command & DC21X4_TXM_START) {
+
+ DC21X4_WRITE_PORT(
+ DC21X4_OPERATION_MODE,
+ Adapter->OperationMode
+ );
+
+ if (!Adapter->DisableTransmitPolling) {
+
+#if _DBG
+ DbgPrint(" Txm Poll_demand\n");
+#endif
+ DC21X4_WRITE_PORT(
+ DC21X4_TXM_POLL_DEMAND,
+ 1
+ );
+ }
+
+ }
+ else {
+#if _DBG
+ DbgPrint(" Start Txm\n");
+#endif
+ Adapter->OperationMode |= DC21X4_TXM_START;
+ DC21X4_WRITE_PORT(
+ DC21X4_OPERATION_MODE,
+ Adapter->OperationMode
+ );
+ }
+
+ if (InterruptMode) {
+ return TRUE;
+ }
+ else {
+
+ // Poll for completion
+
+ while (Time--) {
+
+ NdisStallExecution(5*MILLISECOND); //wait 5 ms
+
+ DC21X4_READ_PORT(
+ DC21X4_STATUS,
+ &DC21X4Status
+ );
+
+ if (DC21X4Status & DC21X4_TXM_BUFFER_UNAVAILABLE) {
+
+ DC21X4_WRITE_PORT(
+ DC21X4_STATUS,
+ DC21X4_TXM_INTERRUPTS
+ );
+ break;
+ }
+
+ }
+
+ Adapter->DequeueTransmitDescriptor =
+ ((Adapter->DequeueTransmitDescriptor)->Next)->Next;
+
+ if (Adapter->FullDuplex) {
+ NdisDprAcquireSpinLock(&Adapter->FullDuplexSpinLock);
+ }
+
+ Adapter->FreeTransmitDescriptorCount += 2;
+
+ if (Adapter->FullDuplex) {
+ NdisDprReleaseSpinLock(&Adapter->FullDuplexSpinLock);
+ }
+
+ if ((Adapter->DeviceId == DC21040_CFID) &&
+ (Adapter->RevisionNumber == DC21040_REV1)) {
+
+ //Restart the Receiver and Enable the SIA
+
+ DC21X4_WRITE_PORT(
+ DC21X4_OPERATION_MODE,
+ Adapter->OperationMode
+ );
+
+ DC21X4_WRITE_PORT(
+ DC21X4_SIA_MODE_0,
+ Adapter->Media[Adapter->SelectedMedium].SiaRegister[0]
+ );
+ }
+
+ if (Time > 0) {
+
+ //Restore the interrupt mask
+ DC21X4_WRITE_PORT(
+ DC21X4_INTERRUPT_MASK,
+ Adapter->InterruptMask
+ );
+
+ return TRUE;
+ }
+ else {
+ return FALSE;
+ }
+
+ }
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+/*++
+ *
+ * DC21X4ChangeFilter
+ *
+ * Routine Description:
+ *
+ * Action routine called when a filter class is modified
+ *
+-*/
+extern
+NDIS_STATUS
+DC21X4ChangeFilter (
+ IN PDC21X4_ADAPTER Adapter,
+ IN ULONG NewFilterClass
+ )
+{
+
+ ULONG Command;
+ ULONG PrevFilterClass;
+
+#if _DBG
+ DbgPrint("DC21X4ChangeClasses NewClass= %x\n",NewFilterClass);
+#endif
+
+ PrevFilterClass = Adapter->FilterClass;
+ Adapter->FilterClass = NewFilterClass;
+
+ Command = Adapter->OperationMode &
+ ~(DC21X4_PROMISCUOUS_MODE | DC21X4_PASS_ALL_MULTICAST);
+
+ if (NewFilterClass & NDIS_PACKET_TYPE_PROMISCUOUS) {
+#if _DBG
+ DbgPrint(" Promiscuous Mode\n");
+#endif
+ Command |= DC21X4_PROMISCUOUS_MODE;
+ }
+
+ else if (NewFilterClass & NDIS_PACKET_TYPE_ALL_MULTICAST) {
+#if _DBG
+ DbgPrint(" All_Multicast Mode\n");
+#endif
+ Command |= DC21X4_PASS_ALL_MULTICAST;
+ }
+
+ if (NewFilterClass & NDIS_PACKET_TYPE_BROADCAST) {
+
+#if _DBG
+ DbgPrint(" Broadcast Mode\n");
+#endif
+ // If broadcast was not previously enabled an entry for the
+ // broadcast address should be added into the CAM
+
+ if (!(PrevFilterClass & NDIS_PACKET_TYPE_BROADCAST)) {
+
+ AddBroadcastToSetup (
+ Adapter
+ );
+ Adapter->OperationMode = Command;
+
+ DC21X4LoadCam(
+ Adapter,
+ TRUE
+ );
+
+ return NDIS_STATUS_PENDING;
+ }
+ }
+
+ else if (PrevFilterClass & NDIS_PACKET_TYPE_BROADCAST) {
+
+ // Broadcast was previously enabled and should be
+ // disabled now by removing the braodcast address entry
+ // from to CAM
+
+ RemoveBroadcastFromSetup (
+ Adapter
+ );
+ Adapter->OperationMode = Command;
+
+ DC21X4LoadCam(
+ Adapter,
+ TRUE
+ );
+
+ return NDIS_STATUS_PENDING;
+ }
+
+ if (Command != Adapter->OperationMode) {
+
+ // Modify the DC21X4 Serial Command Register
+
+ Adapter->OperationMode = Command;
+
+ switch (Adapter->DeviceId) {
+
+ case DC21040_CFID:
+
+ if (Adapter->RevisionNumber == DC21040_REV1) {
+
+ // Txm hang workaround : Disable the SIA before
+ // writing the Operation Mode register
+
+ DC21X4_WRITE_PORT(
+ DC21X4_SIA_MODE_0,
+ DC21X4_RESET_SIA
+ );
+
+ NdisStallExecution(1*MILLISECOND); // Wait 1 ms
+
+
+ DC21X4_WRITE_PORT(
+ DC21X4_OPERATION_MODE,
+ Adapter->OperationMode
+ );
+
+ DC21X4_WRITE_PORT(
+ DC21X4_SIA_MODE_0,
+ Adapter->Media[Adapter->SelectedMedium].SiaRegister[0]
+ );
+ break;
+ }
+
+ default:
+
+ DC21X4_WRITE_PORT(
+ DC21X4_OPERATION_MODE,
+ Adapter->OperationMode
+ );
+ }
+
+ }
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+
+
+
+
+
+
+
+
+/*+
+ *
+ * AddBroadcastToSetup (Adapter);
+ *
+ * Routine Description:
+ *
+ * Add the Broadcast address to the DC21X4 Setup Buffer
+ *
+-*/
+
+VOID
+AddBroadcastToSetup (
+ IN PDC21X4_ADAPTER Adapter
+ )
+
+{
+
+ PDC21X4_SETUP_BUFFER SetupBuffer;
+ UINT i;
+
+#if _DBG
+ PULONG t;
+ DbgPrint("AddBroadcastToSetup\n");
+#endif
+
+ SetupBuffer = (PDC21X4_SETUP_BUFFER)Adapter->SetupBufferVa;
+
+ if (Adapter->FilteringMode == DC21X4_PERFECT_FILTERING) {
+
+ // Load the broadcast address in the second entry
+ // of the Setup Buffer
+
+ for (i=0; i<3; i++) {
+
+ SetupBuffer->Perfect.PhysicalAddress[1][i] = 0x0000ffff;
+ }
+
+ }
+ else {
+
+ // Add the Broadcast hit to the Hash Filter
+ // (HashIndex(Broadcast_address) = 255)
+
+ SetupBuffer->Hash.Filter[15] |= 0x8000;
+ }
+
+}
+
+
+
+
+
+
+
+
+
+
+/*+
+ *
+ * RemoveBroadcastFromSetup (Adapter);
+ *
+ * Routine Description:
+ *
+ * Remove the Broadcast address from the DC21X4 Setup Buffer
+ *
+-*/
+
+VOID
+RemoveBroadcastFromSetup (
+ IN PDC21X4_ADAPTER Adapter
+ )
+{
+
+ PDC21X4_SETUP_BUFFER SetupBuffer;
+
+#if _DBG
+ DbgPrint("RemoveBroadcastFromSetup\n");
+#endif
+
+ SetupBuffer = (PDC21X4_SETUP_BUFFER)Adapter->SetupBufferVa;
+
+ if (Adapter->FilteringMode == DC21X4_PERFECT_FILTERING) {
+
+ // Duplicate the Adapter entry (1st entry) into the
+ // broadcast entry (2nd entry)
+
+ MOVE_MEMORY (
+ SetupBuffer->Perfect.PhysicalAddress[1],
+ SetupBuffer->Perfect.PhysicalAddress[0],
+ sizeof(ULONG)*3
+ );
+ }
+ else {
+
+ // Remove the Broadcast hit from the Hash Filter
+ // (HashIndex(Broadcast_address) = 255)
+
+ SetupBuffer->Hash.Filter[15] &= ~0x8000;
+ }
+}
+
+
+
+
+
+
+
+
+
+
+/*+
+ *
+ * DC21X4ChangeAddresses
+ *
+ * Routine Description:
+ *
+ * Load a new Multicast Addresse list into the adapter's CAM
+ *
+-*/
+extern
+NDIS_STATUS
+DC21X4ChangeMulticastAddresses(
+ IN PDC21X4_ADAPTER Adapter,
+ IN PVOID MulticastAddresses,
+ IN UINT AddressCount
+ )
+
+{
+ PDC21X4_SETUP_BUFFER SetupBuffer;
+
+ PUSHORT AsUShort;
+ PUCHAR MultAddr;
+ PULONG Buffer;
+ UINT HashIndex;
+ UINT i;
+
+#if _DBG
+ DbgPrint("DC21X4ChangeMulticastAddresses\n");
+#endif
+
+ if (AddressCount > Adapter->MaxMulticastAddresses) {
+ return NDIS_STATUS_MULTICAST_FULL;
+ }
+
+ SetupBuffer = (PDC21X4_SETUP_BUFFER)Adapter->SetupBufferVa;
+
+ // Reinitialize the Setup Buffer and load the DC21X4's CAM
+
+ if (AddressCount <= DC21X4_MAX_MULTICAST_PERFECT) {
+
+#if _DBG
+ DbgPrint("Perfect Filtering\n");
+#endif
+ // Perfect Filtering
+
+ //The first entry is the Adapter address
+
+ AsUShort = (PUSHORT)Adapter->CurrentNetworkAddress;
+
+ for (i=0; i<3; i++,AsUShort++) {
+
+ (USHORT)(SetupBuffer->Perfect.PhysicalAddress[0][i]) = *AsUShort;
+ }
+
+ //The second entry is a broadcast address if Broadcast_Enable
+ //otherwise it is a duplicate of the first entry
+
+ if ( Adapter->FilterClass & NDIS_PACKET_TYPE_BROADCAST) {
+
+ for (i=0; i<3; i++) {
+
+ SetupBuffer->Perfect.PhysicalAddress[1][i] = 0x0000ffff;
+ }
+ }
+ else {
+ MOVE_MEMORY (
+ SetupBuffer->Perfect.PhysicalAddress[1],
+ SetupBuffer->Perfect.PhysicalAddress[0],
+ sizeof(ULONG)*3
+ );
+ }
+
+ // Load the new multicast list;
+
+ AsUShort = (PUSHORT)MulticastAddresses;
+ Buffer = (PULONG)SetupBuffer->Perfect.PhysicalAddress[2];
+
+ for (i=0; i< AddressCount * 3; i++,AsUShort++) {
+ *(PUSHORT)Buffer = *AsUShort;
+ Buffer++;
+ }
+
+ // Duplicate the Adapter adress in the remaining entries
+ // of the buffer
+
+ for (i=AddressCount+2; i< DC21X4_SETUP_PERFECT_ENTRIES; i++ ) {
+
+ MOVE_MEMORY(
+ SetupBuffer->Perfect.PhysicalAddress[i],
+ SetupBuffer->Perfect.PhysicalAddress[0],
+ sizeof(ULONG)*3
+ );
+ }
+
+ Adapter->FilteringMode = DC21X4_PERFECT_FILTERING;
+
+ }
+
+ else {
+
+
+#if _DBG
+ DbgPrint("Hashing\n");
+#endif
+ //Hashing
+
+ // Initialize the SetupBuffer
+
+ NdisZeroMemory (
+ (PVOID)(SetupBuffer->Hash.Filter),
+ (ULONG)(sizeof(SetupBuffer->Hash))
+ );
+
+ // Load the hash filter
+
+ MultAddr = (PUCHAR)MulticastAddresses;
+ for (i=0; i < AddressCount; i++, MultAddr += ETH_LENGTH_OF_ADDRESS) {
+
+ if (IS_MULTICAST(MultAddr)) {
+
+ HashIndex = ~CRC32(MultAddr,ETH_LENGTH_OF_ADDRESS) & 0x1FF;
+ SetupBuffer->Hash.Filter[HashIndex/16] |= (1 << (HashIndex % 16));
+#if _DBG
+ DbgPrint(" >>HashIndex = %d [%d]bit=%d\n",HashIndex,(HashIndex/16),(HashIndex%16));
+#endif
+ }
+
+ }
+
+
+ if (Adapter->FilterClass & NDIS_PACKET_TYPE_BROADCAST) {
+
+ // Add the Broadcast entry to the Hash Filter
+ // (Hash_Index(Broadcast_address) = 255)
+
+ SetupBuffer->Hash.Filter[15] |= 0x80000;
+ }
+
+ // Load the Adapter Address
+
+ AsUShort = (PUSHORT)Adapter->CurrentNetworkAddress;
+ for (i=0; i<3; i++, AsUShort++) {
+
+ (USHORT)(SetupBuffer->Hash.PhysicalAddress[i]) = *AsUShort;
+ }
+
+ Adapter->FilteringMode = DC21X4_HASH_FILTERING;
+ }
+
+ DC21X4LoadCam(
+ Adapter,
+ TRUE
+ );
+
+ return NDIS_STATUS_PENDING;
+
+}
+
+
diff --git a/private/ntos/ndis/dc21x4/init.c b/private/ntos/ndis/dc21x4/init.c
new file mode 100644
index 000000000..915a085fc
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/init.c
@@ -0,0 +1,881 @@
+/*+
+ * file: init.c
+ *
+ * Copyright (C) 1992-1995 by
+ * Digital Equipment Corporation, Maynard, Massachusetts.
+ * All rights reserved.
+ *
+ * This software is furnished under a license and may be used and copied
+ * only in accordance of the terms of such license and with the
+ * inclusion of the above copyright notice. This software or any other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person. No title to and ownership of the software is hereby
+ * transferred.
+ *
+ * The information in this software is subject to change without notice
+ * and should not be construed as a commitment by digital equipment
+ * corporation.
+ *
+ * Digital assumes no responsibility for the use or reliability of its
+ * software on equipment which is not supplied by digital.
+ *
+ *
+ * Abstract: This file is part of the NDIS 4.0 miniport driver for
+ * DEC's DC21X4 Ethernet Adapter family.
+ * It contains the adapter's register initialization routines
+ *
+ * Author: Philippe Klein
+ *
+ * Revision History:
+ *
+ * phk 28-Aug-1992 Initial entry
+ *
+-*/
+
+#include <precomp.h>
+
+
+
+
+
+
+
+
+
+
+/*+
+ *
+ * DC21X4InitPciConfigurationRegisters
+ *
+ * Routine Description:
+ *
+ * This routine initialize the DC21X4 PCI Configuration
+ * Registers
+ *
+ * Arguments:
+ *
+ * Adapter - The adapter whose hardware is to be initialized.
+ *
+ * Return Value:
+ *
+ * NONE
+ *
+-*/
+extern
+VOID
+DC21X4InitPciConfigurationRegisters(
+ IN PDC21X4_ADAPTER Adapter
+ )
+{
+
+ ULONG Value;
+ BOOLEAN SetTimer = FALSE;
+
+#if _DBG
+ DbgPrint("DC21X4InitPciConfigurationRegisters\n");
+#endif
+
+ switch (Adapter->AdapterType) {
+
+ case NdisInterfacePci:
+
+ //initialize the Command Register
+
+ NdisWritePciSlotInformation(
+ Adapter->MiniportAdapterHandle,
+ Adapter->SlotNumber,
+ PCI_CFCS_OFFSET,
+ &Adapter->PciCommand,
+ sizeof(Adapter->PciCommand)
+ );
+
+ //initialize the latency timer if not initialized already
+ //or if a latency value has been stored in the Registry
+
+ if (Adapter->PciLatencyTimer) {
+ SetTimer = TRUE;
+ }
+ else {
+ NdisReadPciSlotInformation(
+ Adapter->MiniportAdapterHandle,
+ Adapter->SlotNumber,
+ PCI_CFLT_OFFSET,
+ &Adapter->PciLatencyTimer,
+ sizeof(Adapter->PciLatencyTimer)
+ );
+
+ if (Adapter->PciLatencyTimer == 0) {
+ Adapter->PciLatencyTimer =
+ DC21X4_PCI_LATENCY_TIMER_DEFAULT_VALUE;
+ SetTimer = TRUE;
+ }
+ }
+
+ if (SetTimer) {
+
+ NdisWritePciSlotInformation(
+ Adapter->MiniportAdapterHandle,
+ Adapter->SlotNumber,
+ PCI_CFLT_OFFSET,
+ &Adapter->PciLatencyTimer,
+ sizeof(Adapter->PciLatencyTimer)
+ );
+ }
+
+ // Initialize the CFDA Register
+
+ NdisWritePciSlotInformation(
+ Adapter->MiniportAdapterHandle,
+ Adapter->SlotNumber,
+ PCI_CFDA_OFFSET,
+ &Adapter->PciDriverArea,
+ sizeof(Adapter->PciDriverArea)
+ );
+
+#if __DBG
+ NdisReadPciSlotInformation(
+ Adapter->MiniportAdapterHandle,
+ Adapter->SlotNumber,
+ PCI_CFCS_OFFSET,
+ &Value,
+ sizeof(Value)
+ );
+
+ DbgPrint("CFCS = %08x\n",Value);
+
+ NdisReadPciSlotInformation(
+ Adapter->MiniportAdapterHandle,
+ Adapter->SlotNumber,
+ PCI_CFLT_OFFSET,
+ &Value,
+ sizeof(Value)
+ );
+
+ DbgPrint("CFLT = %08x\n",Value);
+
+
+ NdisReadPciSlotInformation(
+ Adapter->MiniportAdapterHandle,
+ Adapter->SlotNumber,
+ PCI_CBIO_OFFSET,
+ &Value,
+ sizeof(Value)
+ );
+
+ DbgPrint("CBIO = %08x\n",Value);
+
+ NdisReadPciSlotInformation(
+ Adapter->MiniportAdapterHandle,
+ Adapter->SlotNumber,
+ PCI_CFDA_OFFSET,
+ &Value,
+ sizeof(Value)
+ );
+
+ DbgPrint("CFDA = %08x\n",Value);
+
+#endif
+
+ break;
+
+ case NdisInterfaceEisa:
+
+ DC21X4_WRITE_PCI_REGISTER(
+ DC21X4_PCI_COMMAND,
+ Adapter->PciCommand
+ );
+
+ DC21X4_WRITE_PCI_REGISTER(
+ DC21X4_PCI_LATENCY_TIMER,
+ DC21X4_PCI_LATENCY_TIMER_DEFAULT_VALUE
+ );
+
+ DC21X4_WRITE_PCI_REGISTER(
+ DC21X4_PCI_BASE_IO_ADDRESS,
+ (Adapter->IOBaseAddress | DC21X4_IO_SPACE)
+ );
+ }
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*+
+ *
+ * DC21X4InitializeRegisters
+ *
+ * Routine Description:
+ *
+ * This routine initialize the DC21X4 CSRs
+ *
+ * Arguments:
+ *
+ * Adapter - The adapter whose hardware is to be initialized.
+ *
+ * Return Value:
+ *
+ * NONE
+ *
+-*/
+extern
+VOID
+DC21X4InitializeRegisters(
+ IN PDC21X4_ADAPTER Adapter
+ )
+{
+
+ UINT i;
+
+ PDC21X4_TRANSMIT_DESCRIPTOR TransmitDescriptor;
+ PDC21X4_RECEIVE_DESCRIPTOR ReceiveDescriptor;
+
+ // Reset DC21X4
+
+ DC21X4StopAdapter(Adapter);
+
+ switch (Adapter->AdapterType) {
+
+ case NdisInterfaceEisa:
+
+ DC21X4InitPciConfigurationRegisters (Adapter);
+ break;
+
+ case NdisInterfacePci:
+
+ switch (Adapter->DeviceId) {
+
+ case DC21040_CFID :
+
+ if (Adapter->RevisionNumber == DC21040_REV1) {
+
+ // The PCI configuration registers should
+ // be reinitialized after reset
+
+ DC21X4InitPciConfigurationRegisters (Adapter);
+ }
+ break;
+
+ case DC21140_CFID :
+
+ //Initialize PortSelect and reset the chip
+ DC21X4_WRITE_PORT(
+ DC21X4_OPERATION_MODE,
+ Adapter->OperationMode & ~(DC21X4_RCV_START | DC21X4_TXM_START)
+ );
+
+ DC21X4StopAdapter(Adapter);
+
+ break;
+ }
+ }
+
+ // Initialize the descriptor ownership in the
+ // Transmit and Receive descriptor rings
+
+ for (i=0,
+ TransmitDescriptor = (PDC21X4_TRANSMIT_DESCRIPTOR)Adapter->TransmitDescriptorRingVa;
+ i < TRANSMIT_RING_SIZE;
+ i++) {
+ TransmitDescriptor->Status = DESC_OWNED_BY_SYSTEM;
+ TransmitDescriptor = TransmitDescriptor->Next;
+ }
+
+ for (i=0,
+ ReceiveDescriptor = (PDC21X4_RECEIVE_DESCRIPTOR)Adapter->ReceiveDescriptorRingVa;
+ i < Adapter->ReceiveRingSize;
+ i++) {
+ ReceiveDescriptor->Status = DESC_OWNED_BY_DC21X4;
+ ReceiveDescriptor = ReceiveDescriptor->Next;
+ }
+
+ // Initialize the DC21X4 CSRs
+
+#if _DBG
+ DbgPrint(" Init DC21X4 CSRs\n");
+#endif
+
+#if __DBG
+ DbgPrint(" CSR0 (bus mode): %08x\n",
+ Adapter->BusMode);
+#endif
+ DC21X4_WRITE_PORT(
+ DC21X4_BUS_MODE,
+ Adapter->BusMode
+ );
+
+#if __DBG
+ DbgPrint(" CSR3 (Rx desc Ring): %08x\n",
+ Adapter->ReceiveDescriptorRingPa);
+#endif
+ DC21X4_WRITE_PORT(
+ DC21X4_RCV_DESC_RING,
+ Adapter->ReceiveDescriptorRingPa
+ );
+#if _DBG
+ DbgPrint(" CSR4 (Tx desc Ring): %08x\n",
+ Adapter->TransmitDescriptorRingPa);
+#endif
+ DC21X4_WRITE_PORT(
+ DC21X4_TXM_DESC_RING,
+ Adapter->TransmitDescriptorRingPa
+ );
+
+
+ switch (Adapter->DeviceId) {
+
+ case DC21040_CFID :
+
+ DC21X4_WRITE_PORT(
+ DC21X4_RESERVED,
+ 0
+ );
+
+ }
+
+}
+
+
+
+
+
+
+
+
+
+
+/*+
+ *
+ * DC21X4StopAdapter
+ *
+ *
+ * Routine Description:
+ *
+ * This routine stops the DC21X4 by resetting
+ * the chip.
+ *
+ * NOTE: This is not a gracefull stop.
+ *
+ * Arguments:
+ *
+ * Adapter - The adapter for the DC21X4 to stop.
+ *
+ * Return Value:
+ *
+ * None.
+ *
+-*/
+extern
+VOID
+DC21X4StopAdapter(
+ IN PDC21X4_ADAPTER Adapter
+ )
+{
+
+#if __DBG
+ DbgPrint("DC21X4StopAdapter\n");
+#endif
+
+ DC21X4IndicateMediaStatus(Adapter,LinkFail);
+
+ switch (Adapter->AdapterType) {
+
+ case NdisInterfaceEisa:
+
+ // Use HW reset instead of SW reset
+
+#if _DBG
+ DbgPrint(" HW reset\n");
+#endif
+
+ NdisRawWritePortUchar (
+ Adapter->PortOffset + EISA_REG1_OFFSET,
+ 0x01
+ );
+
+ NdisRawWritePortUchar (
+ Adapter->PortOffset + EISA_REG1_OFFSET,
+ 0
+ );
+
+ break;
+
+ default:
+
+ // Set the SW Reset bit in BUS_MODE register
+
+#if _DBG
+ DbgPrint(" SW reset\n");
+#endif
+
+ DC21X4_WRITE_PORT(
+ DC21X4_BUS_MODE,
+ DC21X4_SW_RESET);
+ }
+
+ // Wait 50 PCI bus cycles to wait for reset completion
+
+ NdisStallExecution(2*MILLISECOND); // Wait for 2 ms
+
+}
+
+
+
+
+
+
+
+
+
+
+/*+
+ *
+ * DC21X4StartAdapter
+ *
+ *
+ * Routine Description:
+ *
+ * This routine starts DC21X4's Txm & Rcv processes.
+ *
+ * At this point The Txm descriptor ring should be empty
+ * and the TxM process should enter the SUSPENDED state
+ *
+ * The 1st Rxm descriptor of the Rcv ring should available
+ * and the RxM process should enter the RUNNING state
+ *
+ * Note:
+ *
+ * This routine assume that only a single thread of
+ * execution is working with this particular adapter.
+ *
+ * Arguments:
+ *
+ * Adapter - The adapter for the DC21X4 to stop.
+ *
+ * Return Value:
+ *
+ * None.
+ *
+-*/
+extern
+VOID
+DC21X4StartAdapter(
+ IN PDC21X4_ADAPTER Adapter
+ )
+{
+
+#if __DBG
+ DbgPrint("DC21X4StartAdapter\n");
+#endif
+
+ // Set the RCV_START and TXM_START bits in
+ // the OPERATION_MODE register
+
+ Adapter->OperationMode |= (DC21X4_RCV_START | DC21X4_TXM_START );
+
+ switch (Adapter->DeviceId) {
+
+ case DC21040_CFID :
+
+ if (Adapter->RevisionNumber == DC21040_REV1) {
+
+ // Txm hang workaround : Disable the SIA before
+ // writing the Operation Mode register
+
+ DC21X4_WRITE_PORT(
+ DC21X4_SIA_MODE_0,
+ DC21X4_RESET_SIA
+ );
+
+ NdisStallExecution(1*MILLISECOND); // Wait 1 ms
+
+ DC21X4_WRITE_PORT(
+ DC21X4_OPERATION_MODE,
+ Adapter->OperationMode
+ );
+
+ DC21X4_WRITE_PORT(
+ DC21X4_SIA_MODE_0,
+ Adapter->Media[Adapter->SelectedMedium].SiaRegister[0]
+ );
+
+ break;
+
+ }
+
+ default:
+
+ DC21X4_WRITE_PORT(
+ DC21X4_OPERATION_MODE,
+ Adapter->OperationMode
+ );
+ }
+
+}
+
+
+
+/*+
+ *
+ * DC21X4WriteGepRegister
+ *
+ *
+ * Routine Description:
+ *
+ * Write the DC21X4 General Purpose Register
+ *
+ *
+ * Arguments:
+ *
+ * Adapter
+ * Data
+ *
+ * Return Value:
+ *
+ * None.
+ *
+-*/
+extern
+VOID
+DC21X4WriteGepRegister(
+ IN PDC21X4_ADAPTER Adapter,
+ IN ULONG Data
+ )
+{
+
+ switch (Adapter->DeviceId) {
+
+ case DC21142_CFID:
+
+ Adapter->Gep_Sia2 = (Data << DC21142_GEP_SHIFT)
+ | (Adapter->Gep_Sia2 & DC21142_SIA2_MASK);
+
+ DC21X4_WRITE_PORT(
+ DC21X4_SIA_MODE_2,
+ Adapter->Gep_Sia2
+ );
+ break;
+
+ default:
+
+ DC21X4_WRITE_PORT(
+ DC21X4_GEN_PURPOSE,
+ Data
+ );
+
+ }
+}
+
+
+
+/*+
+ *
+ * DC21X4InitializeGepRegisters
+ *
+ *
+ * Routine Description:
+ *
+ * This routine initializes the GEP registers of the DC21140 adapters
+ *
+ *
+ * Arguments:
+ *
+ * Adapter - The adapter for the DC21X4 to initialize
+ *
+ * Return Value:
+ *
+ * None.
+ *
+-*/
+extern
+VOID
+DC21X4InitializeGepRegisters(
+ IN PDC21X4_ADAPTER Adapter,
+ IN BOOLEAN Phy
+ )
+{
+
+ INT Seq;
+
+#if __DBG
+ DbgPrint("InitializeGepRegisters\n");
+#endif
+
+
+ if (Phy) {
+
+ // Write the Gen Purpose register with the PHY's required sequence:
+ // Control,Data_1,...,Data_n
+
+#if __DBG
+ DbgPrint("InitializeGepRegisters: Control=%08x\n",
+ Adapter->Phy[Adapter->PhyNumber].GeneralPurposeCtrl);
+#endif
+ DC21X4WriteGepRegister(
+ Adapter,
+ (ULONG)Adapter->Phy[Adapter->PhyNumber].GeneralPurposeCtrl
+ );
+
+ for (Seq=0; Seq < Adapter->Phy[Adapter->PhyNumber].GepSequenceLength; Seq++) {
+#if __DBG
+ DbgPrint("InitializeGepRegisters: DATA[%d]=%04x\n",
+ Seq, Adapter->Phy[Adapter->PhyNumber].GepSequence[Seq]);
+#endif
+ DC21X4WriteGepRegister(
+ Adapter,
+ (ULONG)Adapter->Phy[Adapter->PhyNumber].GepSequence[Seq]
+ );
+ }
+ }
+ else {
+
+#if __DBG
+ DbgPrint("InitializeGepRegisters:\n");
+ DbgPrint(" GeneralPurpose Ctrl : %08x\n",
+ Adapter->Media[Adapter->SelectedMedium].GeneralPurposeCtrl);
+ DbgPrint(" GeneralPurpose Data : %08x\n",
+ Adapter->Media[Adapter->SelectedMedium].GeneralPurposeData);
+#endif
+
+ DC21X4WriteGepRegister(
+ Adapter,
+ (ULONG)Adapter->Media[Adapter->SelectedMedium].GeneralPurposeCtrl
+ );
+
+ DC21X4WriteGepRegister(
+ Adapter,
+ (ULONG)Adapter->Media[Adapter->SelectedMedium].GeneralPurposeData
+ );
+ }
+
+}
+
+
+
+/*+
+ * DC21X4InitializeMediaRegisters
+ *
+ * Routine Description:
+ *
+ * Initialize the DC21X4 Media (GEP &internal SIA) registers
+ *
+ *
+ * Arguments:
+ *
+ * Adapter
+ *
+ *
+ * Return Value:
+ *
+ * None.
+ *
+-*/
+extern
+VOID
+DC21X4InitializeMediaRegisters(
+ IN PDC21X4_ADAPTER Adapter,
+ IN BOOLEAN Phy
+ )
+{
+#if __DBG
+ DbgPrint("InitializeMediaRegisters\n");
+#endif
+
+ switch (Adapter->DeviceId) {
+
+ case DC21040_CFID :
+ case DC21041_CFID :
+
+ DC2104InitializeSiaRegisters(Adapter);
+ break;
+
+ case DC21140_CFID :
+
+ DC21X4InitializeGepRegisters(Adapter,Phy);
+ break;
+
+ case DC21142_CFID :
+
+ DC21X4InitializeGepRegisters(Adapter,Phy);
+ DC2104InitializeSiaRegisters(Adapter);
+ break;
+
+ }
+}
+
+
+
+
+
+
+
+
+
+/*+
+ *
+ * DC2104InitializeSiaRegisters
+ *
+ *
+ * Routine Description:
+ *
+ * This routine initializes the SIA register of the DC2104x adapters
+ *
+ *
+ * Arguments:
+ *
+ * Adapter - The adapter for the DC21X4 to initialize
+ *
+ * Return Value:
+ *
+ * None.
+ *
+-*/
+extern
+VOID
+DC2104InitializeSiaRegisters(
+ IN PDC21X4_ADAPTER Adapter
+ )
+
+{
+ UINT i;
+
+#if __DBG
+ DbgPrint("DC2104InitializeSiaRegisters\n");
+#endif
+
+ DC21X4_WRITE_PORT(
+ DC21X4_SIA_MODE_0,
+ DC21X4_RESET_SIA
+ );
+
+ for (i=0;i<2;i++) {
+ NdisStallExecution(5*MILLISECOND);
+ }
+
+#if __DBG
+ DbgPrint(" CSR15: %08x\n",Adapter->Media[Adapter->SelectedMedium].SiaRegister[2]);
+ DbgPrint(" CSR14: %08x\n",Adapter->Media[Adapter->SelectedMedium].SiaRegister[1]);
+ DbgPrint(" CSR13: %08x\n",Adapter->Media[Adapter->SelectedMedium].SiaRegister[0]);
+
+#endif
+
+ switch (Adapter->DeviceId) {
+
+ case DC21142_CFID:
+
+ Adapter->Gep_Sia2 =
+ (Adapter->Media[Adapter->SelectedMedium].SiaRegister[2] & DC21142_SIA2_MASK)
+ | (Adapter->Gep_Sia2 & DC21142_GEP_MASK);
+
+ DC21X4_WRITE_PORT(
+ DC21X4_SIA_MODE_2,
+ Adapter->Gep_Sia2
+ );
+
+ break;
+
+ default:
+
+ DC21X4_WRITE_PORT(
+ DC21X4_SIA_MODE_2,
+ Adapter->Media[Adapter->SelectedMedium].SiaRegister[2]
+ );
+ }
+
+ DC21X4_WRITE_PORT(
+ DC21X4_SIA_MODE_1,
+ Adapter->Media[Adapter->SelectedMedium].SiaRegister[1]
+ );
+
+ DC21X4_WRITE_PORT(
+ DC21X4_SIA_MODE_0,
+ Adapter->Media[Adapter->SelectedMedium].SiaRegister[0]
+ );
+
+#if 0
+ //Restart the Receiver and Transmitter
+ DC21X4_WRITE_PORT(
+ DC21X4_OPERATION_MODE,
+ Adapter->OperationMode
+ );
+#endif
+
+}
+
+
+
+
+
+
+
+
+
+
+
+/*+
+ *
+ * DC21X4StopReceiverAndTransmitter
+ *
+ *
+ * Routine Description:
+ *
+ * Gracefull stop the Receiver and Transmitter and
+ * synchronize on completion
+ *
+ *
+ * Arguments:
+ *
+ * Adapter - The adapter for the DC21X4 to initialize
+ *
+ * Return Value:
+ *
+ * None.
+ *
+-*/
+extern
+VOID
+DC21X4StopReceiverAndTransmitter(
+ IN PDC21X4_ADAPTER Adapter
+ )
+
+{
+
+ ULONG Status;
+ UINT Time=50;
+
+ //Request the Receiver and Transmitter to stop
+
+ DC21X4_WRITE_PORT(
+ DC21X4_OPERATION_MODE,
+ 0
+ );
+
+ //Wait for completion
+
+ while (Time--) {
+
+ DC21X4_READ_PORT(
+ DC21X4_STATUS,
+ &Status
+ );
+
+ if (Status & (DC21X4_RCV_PROCESS_STATE
+ | DC21X4_TXM_PROCESS_STATE) == 0) {
+ break;
+ }
+
+ NdisStallExecution(2*MILLISECOND);
+ }
+
+ return;
+
+}
diff --git a/private/ntos/ndis/dc21x4/interrup.c b/private/ntos/ndis/dc21x4/interrup.c
new file mode 100644
index 000000000..9de60bc52
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/interrup.c
@@ -0,0 +1,1726 @@
+/*+
+ * file: interrup.c
+ *
+ * Copyright (C) 1992-1995 by
+ * Digital Equipment Corporation, Maynard, Massachusetts.
+ * All rights reserved.
+ *
+ * This software is furnished under a license and may be used and copied
+ * only in accordance of the terms of such license and with the
+ * inclusion of the above copyright notice. This software or any other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person. No title to and ownership of the software is hereby
+ * transferred.
+ *
+ * The information in this software is subject to change without notice
+ * and should not be construed as a commitment by digital equipment
+ * corporation.
+ *
+ * Digital assumes no responsibility for the use or reliability of its
+ * software on equipment which is not supplied by digital.
+ *
+ *
+ * Abstract: This file contains the interrupt handling routines for
+ * the NDIS 4.0 miniport driver for DEC's DC21X4 Ethernet
+ * controller family .
+ *
+ * Author: Philippe Klein
+ *
+ * Revision History:
+ *
+ * phk 09-Aug-1994 Initial entry
+ * phk 09-Feb-1995 V2.0
+ *
+-*/
+
+#include <precomp.h>
+
+
+
+
+
+
+
+
+
+
+
+
+// Logging code to keep track of receive buffers and packets.
+
+#if DBG
+#define PACKET_LOG_SIZE 1024
+
+typedef struct _PACKET_LOG {
+
+ PNDIS_PACKET Packet;
+ PRCV_HEADER RcvHeader;
+ ULONG Ident1;
+ ULONG Ident2;
+
+}PACKET_LOG,*PPACKET_LOG;
+
+
+UINT dc21x4CurrentLogEntry = (PACKET_LOG_SIZE - 1);
+PPACKET_LOG dc21x4PacketLogHead = NULL;
+PACKET_LOG dc21x4PacketLog[PACKET_LOG_SIZE] = {0};
+
+VOID DC21X4LogPacket(PNDIS_PACKET Packet, PRCV_HEADER RcvHeader, UINT Ident1, UINT Ident2) {
+
+ dc21x4PacketLogHead = &dc21x4PacketLog[dc21x4CurrentLogEntry];
+
+ dc21x4PacketLogHead->Packet = Packet;
+ dc21x4PacketLogHead->RcvHeader = RcvHeader;
+ dc21x4PacketLogHead->Ident1 = Ident1;
+ dc21x4PacketLogHead->Ident2 = Ident2;
+
+ if (dc21x4CurrentLogEntry-- == 0) {
+ dc21x4CurrentLogEntry = (PACKET_LOG_SIZE - 1);
+ }
+}
+#else
+
+#define DC21X4LogPacket(Packet, RcvHeader, Ident1, Ident2)
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+/*+
+ *
+ * DC21X4Isr
+ *
+ * Routine Description:
+ *
+ * Interrupt service routine.
+ * Get the value of ISR and clear the adapter's interrupt status
+ *
+-*/
+
+extern
+VOID
+DC21X4Isr(
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueMiniportHandleInterrupt,
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+{
+
+ PDC21X4_ADAPTER Adapter;
+ ULONG Status;
+ ULONG IsrStatus;
+
+#if _DBG
+ DbgPrint("DC21X4Isr\n");
+#endif
+
+ Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
+
+ // Read the interrupt field of the adapter's Status CSR
+
+ DC21X4_READ_PORT(
+ DC21X4_STATUS,
+ &Status
+ );
+
+ IsrStatus = Status & DC21X4_STATUS_INTERRUPTS;
+
+#if _DBG
+ DbgPrint("ISR[%08x] Interrupt Status = %08x\n",Adapter,IsrStatus);
+#endif
+
+ // Check if the shared interrupt is recognized by the adapter
+
+ if (IsrStatus == 0) {
+
+ *InterruptRecognized = FALSE;
+ *QueueMiniportHandleInterrupt = FALSE;
+ return;
+ }
+
+ *InterruptRecognized = TRUE;
+
+ //Mask the interrupts
+ //(shared interrupts should be disabled in the ISR).
+
+ DC21X4_WRITE_PORT(
+ DC21X4_INTERRUPT_MASK,
+ 0
+ );
+
+ //Clear the interrupts
+
+ DC21X4_WRITE_PORT(
+ DC21X4_STATUS,
+ Status
+ );
+
+ if (IsrStatus & DC21X4_SYSTEM_ERROR) {
+
+ // This is a fatal error caused by a system hardware
+ // failure: stop the DC21X4 chip
+#if __DBG
+ DbgPrint("\n\nDC21X4_SYSTEM_ERROR!!!\n\n");
+#endif
+ Adapter->ParityError = TRUE;
+
+ DC21X4StopAdapter(Adapter);
+
+ *QueueMiniportHandleInterrupt = FALSE;
+ return;
+ }
+
+#if __DBG
+ if (IsrStatus & DC21X4_LINK_FAIL) {
+ DbgPrint("ISR: LinkFail interrupt\n");
+ }
+ else if (IsrStatus & DC21X4_LINK_PASS) {
+ DbgPrint("ISR: LinkPass interrupt\n");
+ }
+#endif
+
+ // count the number of Rcv & Txm interrupts
+
+ if ( (IsrStatus & Adapter->InterruptMask)
+ & (DC21X4_RCV_INTERRUPTS | DC21X4_TXM_INTERRUPTS)) {
+ Adapter->InterruptCount++;
+ }
+
+ Adapter->InterruptStatus |= IsrStatus;
+ *QueueMiniportHandleInterrupt = TRUE;
+ return;
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+/*++
+ *
+ * DC21X4SynchClearIsr
+ *
+ * Routine Description:
+ *
+ * This routine is used by the interrupt handler to synchronize
+ * with the interrupt service routine while accessing the shared
+ * ISR value.
+ *
+ * The routine clears the Adapter's Interrupt Status CSR
+ *
+ * Arguments:
+ *
+ * SyncContext - A pointer to a structure storing a pointer to the
+ * adapter and the ISR Status value.
+ *
+ * Return Value:
+ *
+ * None
+ *
+-*/
+
+VOID
+DC21X4SynchClearIsr(
+ IN PDC21X4_SYNCH_CONTEXT SyncContext
+ )
+{
+ PDC21X4_ADAPTER Adapter = SyncContext->Adapter;
+
+#if _DBG
+ DbgPrint("DC21X4SynchClearIsr [%08x]\n",
+ ( DC21X4_RCV_INTERRUPTS
+ | DC21X4_TXM_INTERRUPTS
+ | SyncContext->IsrStatus));
+#endif
+
+ //Clear the interrupt status
+
+ DC21X4_WRITE_PORT(
+ DC21X4_STATUS,
+ ( DC21X4_RCV_INTERRUPTS
+ | DC21X4_TXM_INTERRUPTS
+ | SyncContext->IsrStatus)
+ );
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+/*++
+ *
+ * DC21X4HandleInterrupt
+ *
+ * Routine Description:
+ *
+ * This routine is queued by the interrupt service routine and
+ * handle the routines associated with the interrupts
+ *
+-*/
+
+extern
+VOID
+DC21X4HandleInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+
+{
+
+ PDC21X4_ADAPTER Adapter;
+ PDC21X4_RECEIVE_DESCRIPTOR ReceiveDescriptor;
+ PDC21X4_TRANSMIT_DESCRIPTOR TransmitDescriptor;
+
+ DC21X4_SYNCH_CONTEXT SyncContext;
+
+ ULONG Status;
+ ULONG IsrStatus;
+
+#if _DBG
+ DbgPrint("DC21X4HandleInterrupt\n");
+#endif
+
+ Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
+ SyncContext.Adapter = Adapter;
+
+ while (TRUE) {
+
+ IsrStatus = Adapter->InterruptStatus;
+ SyncContext.IsrStatus = IsrStatus;
+
+ if (IsrStatus & ( DC21X4_LINK_FAIL
+ | DC21X4_LINK_PASS
+ | DC21X4_GEP_INTERRUPT
+ )
+ ) {
+
+ if (IsrStatus & DC21X4_GEP_INTERRUPT) {
+ HandleGepInterrupt(Adapter);
+ }
+ if (IsrStatus & DC21X4_LINK_FAIL) {
+ HandleLinkFailInterrupt(Adapter,&IsrStatus);
+ }
+ if (IsrStatus & DC21X4_LINK_PASS) {
+ HandleLinkPassInterrupt(Adapter,&IsrStatus);
+ }
+ }
+
+ // Clear the Interrupt Status CSR
+
+
+ NdisMSynchronizeWithInterrupt(
+ &Adapter->Interrupt,
+ DC21X4SynchClearIsr,
+ &SyncContext
+ );
+
+ if (Adapter->ResetInProgress) {
+ return;
+ }
+
+ // Check the Receive and Transmit Descriptor
+ // rings to process any pending packet
+
+ ReceiveDescriptor =
+ ProcessReceiveDescRing (Adapter);
+
+ TransmitDescriptor =
+ ProcessTransmitDescRing (Adapter);
+
+
+ // Check if there is more work to do
+
+ DC21X4_READ_PORT(
+ DC21X4_STATUS,
+ &Status
+ );
+
+ Adapter->InterruptStatus =
+ Status & DC21X4_STATUS_INTERRUPTS;
+
+ if (Adapter->InterruptStatus) {
+ continue;
+ }
+
+#if _DBG
+ DbgPrint("Rcv Status %08x\n",ReceiveDescriptor->Status);
+#endif
+ if ((ReceiveDescriptor->Status & DC21X4_RDES_OWN_BIT) == DESC_OWNED_BY_SYSTEM) {
+ // More Receive frames should be processed
+ continue;
+ }
+
+#if _DBG
+ DbgPrint("Txm Status %08x\n",TransmitDescriptor->Status);
+#endif
+ if (Adapter->DequeueTransmitDescriptor == Adapter->EnqueueTransmitDescriptor) {
+ break;
+ }
+
+ else if ((TransmitDescriptor->Status & DC21X4_TDES_OWN_BIT) == DESC_OWNED_BY_DC21X4) {
+
+ // The transmit ring contains Txm descriptor(s): Poll_transmit
+ // the adapter
+ // (if Txm is running (expected case), this is a no_op
+ // if Txm is suspendend (abnormal case caused by Motorola
+ // Eagle chip set's cache coherency problem) the transmission
+ // will resume)
+ DC21X4_WRITE_PORT(
+ DC21X4_TXM_POLL_DEMAND,
+ 1
+ );
+ break;
+ }
+ }
+
+ if (Adapter->Polling) {
+
+ //Restart the monitor timer
+
+ DC21X4_WRITE_PORT(
+ DC21X4_TIMER,
+ Adapter->Polling
+ );
+ }
+
+#if _DBG
+ DbgPrint("Interrupt Handler completed\n");
+#endif
+
+}
+
+
+
+
+/*+
+ *
+ * HandleGepInterrupt
+ *
+ * Routine Description:
+ *
+ * Handle the GEP interrupt
+ *
+ * Arguments:
+ *
+ * Adapter - The adapter to indicate to.
+ *
+ * Return Value:
+ *
+ * None.
+ *
+-*/
+VOID
+HandleGepInterrupt(
+ IN PDC21X4_ADAPTER Adapter
+ )
+{
+ ULONG Gep;
+#if __DBG
+ DbgPrint("Handle GEP interrupt\n");
+#endif
+
+ //Read the GEP register
+
+ DC21X4_READ_PORT(
+ DC21X4_SIA_MODE_2,
+ &Gep
+ );
+
+ if ( (Gep & Adapter->Phy[Adapter->PhyNumber].GepInterruptMask)
+ && (Adapter->PhyMediumInSrom)
+ ) {
+
+#if __DBG
+ DbgPrint("GEP Interrupt:\n");
+#endif
+ // A MII card was plugged in: Initialize the PHY
+
+ DC21X4IndicateMediaStatus(Adapter,LinkFail);
+
+#if __DBG
+ DbgPrint("Init the PHY...\n");
+#endif
+ Adapter->PhyPresent = DC21X4PhyInit(Adapter);
+#if __DBG
+ DbgPrint("Adapter->PhyPresent=%d\n",Adapter->PhyPresent);
+#endif
+
+ if (Adapter->PhyPresent) {
+
+ DC21X4SetPhyConnection(
+ Adapter
+ );
+
+ if ( (Adapter->PhyNwayCapable)
+ && (Adapter->MediaType & MEDIA_NWAY)
+ ) {
+ //PHY is Nway capable: disable DC21X4's Nway
+ DC21X4DisableNway (Adapter);
+ }
+
+ // Start the AutoSense timer
+ DC21X4StartAutoSenseTimer(
+ Adapter,
+ (UINT)0
+ );
+ }
+ }
+
+}
+
+
+
+
+
+/*+
+ *
+ * HandleLinkFailInterrupt
+ *
+ * Routine Description:
+ *
+ * Handle the Link_Fail interrupt
+ *
+ * Arguments:
+ *
+ * Adapter - The adapter to indicate to.
+ * IsrStatus - Interrupt status
+ * Return Value:
+ *
+ * None.
+ *
+-*/
+VOID
+HandleLinkFailInterrupt(
+ IN PDC21X4_ADAPTER Adapter,
+ IN OUT PULONG IsrStatus
+ )
+{
+
+#if __DBG
+ DbgPrint("Handle Link Fail interrupt\n");
+#endif
+
+ if (Adapter->SelectedMedium != Medium10BaseT) {
+ return;
+ }
+
+ if (Adapter->PhyPresent) {
+
+ DC21X4SetPhyControl(
+ Adapter,
+ MiiGenAdminRelease10
+ );
+
+ }
+
+ switch (Adapter->DeviceId) {
+
+ case DC21040_CFID:
+
+ DC21X4IndicateMediaStatus(Adapter,LinkFail);
+ *IsrStatus &= ~(
+ DC21X4_LINK_PASS
+ );
+
+ //21040 does not provide a Link_pass interrupt:
+ //Start the AutoSense timer to poll on Link Pass
+
+ DC21X4StartAutoSenseTimer(
+ Adapter,
+ DC21X4_SPA_TICK
+ );
+ return;
+
+ case DC21142_CFID:
+
+ Adapter->Indicate10BTLink = FALSE;
+
+ case DC21041_CFID:
+
+ switch (Adapter->LinkHandlerMode) {
+
+ case NwayWorkAround:
+
+ DC21X4IndicateMediaStatus(Adapter,LinkFail);
+ *IsrStatus &= ~(
+ DC21X4_LINK_PASS
+ );
+
+ if ((!Adapter->NwayEnabled) && (Adapter->MediaNway)) {
+
+ SwitchMediumToTpNway(Adapter);
+
+ }
+ break;
+
+ case Nway:
+
+ DC21X4IndicateMediaStatus(Adapter,LinkFail);
+ *IsrStatus &= ~(
+ DC21X4_LINK_PASS
+ );
+
+ if ((Adapter->MediaType & MEDIA_AUTOSENSE)
+ ||(Adapter->MediaNway)
+ ){
+
+ //Stop the Link Timer if active
+ if (Adapter->TimerFlag != NoTimer) {
+ DC21X4StopAutoSenseTimer(Adapter);
+ }
+
+ //Start the Anc Timer to timeout if the
+ //Nway autonegotiation does not complete
+
+ Adapter->TimerFlag=AncTimeout;
+
+ NdisMSetTimer(
+ &Adapter->Timer,
+ DC21X4_ANC_TIMEOUT
+ );
+ }
+ break;
+
+
+ default:
+
+ DC21X4IndicateMediaStatus(Adapter,LinkFail);
+ *IsrStatus &= ~(
+ DC21X4_LINK_PASS
+ );
+
+ if (Adapter->MediaType & MEDIA_AUTOSENSE) {
+
+ DC21X4SwitchMedia(
+ Adapter,
+ Medium10Base2_5
+ );
+ }
+ else if (Adapter->MediaType & MEDIA_NWAY) {
+
+ //Stop the Link Timer if active
+ if (Adapter->TimerFlag != NoTimer) {
+ DC21X4StopAutoSenseTimer(Adapter);
+ }
+
+ //Start the Anc Timer to timeout if the
+ //Nway autonegotiation does not complete
+
+ Adapter->TimerFlag=AncTimeout;
+
+ NdisMSetTimer(
+ &Adapter->Timer,
+ DC21X4_ANC_TIMEOUT
+ );
+ }
+ break;
+ }
+ }
+
+}
+
+
+
+
+/*+
+ *
+ * HandleLinkPassInterrupt
+ *
+ * Routine Description:
+ *
+ * Handle the LinkPass/ANC interrupt
+ *
+ * Arguments:
+ *
+ * Adapter - The adapter to indicate to.
+ * IsrStatus - Interrupt status
+ * Return Value:
+ *
+ * None.
+ *
+-*/
+VOID
+HandleLinkPassInterrupt(
+ IN PDC21X4_ADAPTER Adapter,
+ IN OUT PULONG IsrStatus
+ )
+{
+
+ INT i;
+
+#if __DBG
+ DbgPrint("Handle Link Pass interrupt\n");
+#endif
+
+
+ switch (Adapter->DeviceId) {
+
+ case DC21041_CFID:
+ case DC21142_CFID:
+ switch (Adapter->LinkHandlerMode) {
+
+ case NwayWorkAround:
+
+ if (Adapter->TimerFlag==AncPolling){
+ return;
+ }
+ else if ( (Adapter->SelectedMedium != Medium10BaseT)
+ || (Adapter->FirstAncInterrupt)) {
+
+ SwitchMediumToTpNway(Adapter);
+ }
+
+ else {
+ DC21X4IndicateMediaStatus(Adapter,LinkPass);
+ }
+
+ Adapter->FirstAncInterrupt = FALSE;
+ return;
+
+ case Nway:
+
+ if (Adapter->MediaNway) {
+
+ //NWAY enabled: Auto_Negotiation_Completed interrupt
+#if __DBG
+ DbgPrint("AutoNegotiation Completed\n");
+#endif
+ //Stop the Anc or Spa timer if active
+ if (Adapter->TimerFlag != NoTimer) {
+ DC21X4StopAutoSenseTimer(Adapter);
+ }
+
+ //Start the Link timer to defer the
+ //Link Status check
+ Adapter->TimerFlag=DeferredLinkCheck;
+ NdisMSetTimer(
+ &Adapter->Timer,
+ DC21X4_LINK_DELAY
+ );
+
+ return;
+ }
+
+ default:
+
+ //No NWAY: Link Pass interrupt
+
+ if (Adapter->SelectedMedium != Medium10BaseT) {
+
+ if (Adapter->MediaType & MEDIA_AUTOSENSE) {
+
+ if ( (Adapter->TimerFlag != NoTimer)
+ && (!Adapter->PhyPresent) ){
+
+ DC21X4StopAutoSenseTimer(Adapter);
+ }
+
+ //Switch to 10BaseT
+ DC21X4SwitchMedia(
+ Adapter,
+ Medium10BaseT
+ );
+ }
+ }
+ else {
+
+ if (Adapter->PhyPresent) {
+
+ // Deferred the indicaton of the 10BT link
+ // to poll first the PHY Link status
+ // to check if the link interrupt
+ // is not a false 10BT link generated by
+ // 100BTx pulses.
+
+ Adapter->Indicate10BTLink = TRUE;
+ return;
+
+ }
+ DC21X4IndicateMediaStatus(Adapter,LinkPass);
+
+ }
+ return;
+
+
+ }
+ break;
+
+ default:
+
+ DC21X4IndicateMediaStatus(Adapter,LinkPass);
+ }
+
+}
+
+
+
+/*+
+ *
+ * SwitchMediumToTpNway
+ *
+ * Routine Description:
+ *
+ * Switch Medium to 10BaseT with Nway enabled
+ *
+ * Arguments:
+ *
+ * Adapter - The adapter to indicate to.
+ *
+ * Return Value:
+ *
+ * None.
+ *
+-*/
+VOID
+SwitchMediumToTpNway(
+ IN PDC21X4_ADAPTER Adapter
+ )
+{
+
+ //Stop the Spa timer if active
+
+ if (Adapter->TimerFlag != NoTimer) {
+ DC21X4StopAutoSenseTimer(Adapter);
+ }
+
+ //Switch medium to TP with Nway enabled :
+
+ DC21X4SwitchMedia(
+ Adapter,
+ Medium10BaseTNway
+ );
+
+ Adapter->AutoNegotiationCount = 0;
+
+ //Initialize the Poll timeout counter
+ Adapter->PollCount= POLL_COUNT_TIMEOUT;
+
+ //Start the Poll timer to
+ //poll the AutoNegotiation State
+
+ Adapter->TimerFlag=AncPolling;
+ NdisMSetTimer(
+ &Adapter->Timer,
+ DC21X4_POLL_DELAY
+ );
+
+}
+
+
+
+
+
+/*+
+ *
+ * ProcessReceiveDescRing
+ *
+ * Routine Description:
+ *
+ * Process the packets that have finished receiving.
+ *
+ * Arguments:
+ *
+ * Adapter - The adapter to indicate to.
+ *
+ * Return Value:
+ *
+ * None.
+ *
+-*/
+PDC21X4_RECEIVE_DESCRIPTOR
+ProcessReceiveDescRing(
+ IN PDC21X4_ADAPTER Adapter
+ )
+{
+
+ // Walk down the receive descriptors ring starting at the
+ // last known descriptor owned by the adapter
+ //
+ // Examine each receive ring descriptor for errors.
+ //
+ // When we have the entire packet (and error processing doesn't
+ // prevent us from indicating it), we give the routine that
+ // processes the packet through the filter, the buffers virtual
+ // address (which is always the lookahead size) and as the
+ // MAC context the address of the first data byte.
+
+ PDC21X4_RECEIVE_DESCRIPTOR CurrentDescriptor;
+
+ PVOID FrameVa;
+ USHORT FrameType;
+
+ UINT FrameSize;
+ UINT LookAheadSize;
+
+ BOOLEAN fStopReceiveProcessing = FALSE;
+
+ PRCV_HEADER RcvHeader;
+ PNDIS_PACKET Packet;
+ PPNDIS_PACKET pPktArray;
+ PNDIS_BUFFER Buffer;
+ ULONG Length;
+ UINT Index;
+ UINT Count;
+ UINT i;
+ PDC21X4_RECEIVE_DESCRIPTOR DescriptorMark;
+ ULONG Status;
+ ULONG Register;
+ INT Timeout;
+ ULONG OverflowCount;
+ ULONG MissedFrames;
+
+ NDIS_PHYSICAL_ADDRESS Pa;
+
+#if _DBG
+ DbgPrint("ProcessReceiveInterrupts\n");
+#endif
+
+ NdisSetPhysicalAddressHigh(Pa,0);
+ DescriptorMark = Adapter->DequeueReceiveDescriptor;
+
+ while (!fStopReceiveProcessing) {
+
+ // Grab a max of MAX_PACKET_ARRAY packets at a time.
+
+ for (Count = 0, pPktArray = Adapter->PacketArray; Count < MAX_PACKET_ARRAY;) {
+
+ // Get the current receive descriptor.
+
+ CurrentDescriptor = Adapter->DequeueReceiveDescriptor;
+#if _DBG
+ DbgPrint("RcvDesc [%08x]\n",CurrentDescriptor);
+#endif
+
+ // If the descriptor is not owned by the system, we are done.
+
+ if ((CurrentDescriptor->Status & DC21X4_RDES_OWN_BIT) != DESC_OWNED_BY_SYSTEM) {
+ fStopReceiveProcessing = TRUE;
+ break;
+ }
+
+ if (Adapter->OverflowWorkAround) {
+
+ if (CurrentDescriptor==DescriptorMark) {
+
+ // Mark the next descriptor not owned by the system into the ring
+
+ do {
+ DescriptorMark = DescriptorMark->Next;
+ }
+ while (
+ ((DescriptorMark->Status & DC21X4_RDES_OWN_BIT) != DESC_OWNED_BY_DC21X4)
+ && (DescriptorMark != Adapter->DequeueReceiveDescriptor)
+ );
+
+ if (!Adapter->IndicateOverflow) {
+
+ //Check if an overflow occured for at least one
+ // of the packets currently queued into the Rcv ring
+
+ DC21X4_READ_PORT(
+ DC21X4_MISSED_FRAME,
+ &Register
+ );
+
+ MissedFrames = Register & DC21X4_MISSED_FRAME_COUNTER;
+ if (MissedFrames) {
+ Adapter->GeneralMandatory[GM_MISSED_FRAMES] += MissedFrames;
+ }
+ OverflowCount = (Register >> DC21X4_OVERFLOW_COUNTER_SHIFT)
+ & DC21X4_OVERFLOW_COUNTER;
+ if (OverflowCount) {
+ Adapter->IndicateOverflow = TRUE;
+ Adapter->MediaOptional[MO_RECEIVE_OVERFLOW]+= OverflowCount;
+ }
+
+ }
+
+ if (Adapter->IndicateOverflow) {
+
+ //Stop the Receiver
+ DC21X4_WRITE_PORT(
+ DC21X4_OPERATION_MODE,
+ Adapter->OperationMode & ~(DC21X4_RCV_START)
+ );
+
+ // Discard the packets queued into the ring:
+ // Reclaim all the descriptors owned by the system
+
+
+ while (((Adapter->DequeueReceiveDescriptor)->Status & DC21X4_RDES_OWN_BIT)
+ == DESC_OWNED_BY_SYSTEM
+ ) {
+
+ (Adapter->DequeueReceiveDescriptor)->Status = DESC_OWNED_BY_DC21X4;
+ Adapter->MediaOptional[MO_RECEIVE_OVERFLOW]++;
+ Adapter->DequeueReceiveDescriptor = (Adapter->DequeueReceiveDescriptor)->Next;
+ }
+
+ Adapter->IndicateOverflow = FALSE;
+
+ // Wait for the Receiver to stop
+ Timeout = DC21X4_RVC_TIMEOUT;
+
+ while (Timeout--) {
+
+ DC21X4_READ_PORT(
+ DC21X4_STATUS,
+ &Status
+ );
+
+ if ((Status & (DC21X4_RCV_PROCESS_STATE)) == 0) {
+ break;
+ }
+ NdisStallExecution(2*MILLISECOND);
+ }
+
+ // Once the Receiver is stopped reclaim the descriptors
+ // owned by the system (this happends if a reception was
+ // in progress when tyhe stop_receive command was issued
+
+ while (((Adapter->DequeueReceiveDescriptor)->Status & DC21X4_RDES_OWN_BIT)
+ == DESC_OWNED_BY_SYSTEM
+ ) {
+
+ (Adapter->DequeueReceiveDescriptor)->Status = DESC_OWNED_BY_DC21X4;
+ Adapter->MediaOptional[MO_RECEIVE_OVERFLOW]++;
+ Adapter->DequeueReceiveDescriptor = (Adapter->DequeueReceiveDescriptor)->Next;
+ }
+
+ // Restart the Receiver
+ DC21X4_WRITE_PORT(
+ DC21X4_OPERATION_MODE,
+ Adapter->OperationMode
+ );
+
+ DescriptorMark = Adapter->DequeueReceiveDescriptor;
+ //leave the "for Count" loop back to the "while" loop
+ break;
+ }
+
+ }
+
+ }
+
+ Adapter->DequeueReceiveDescriptor = CurrentDescriptor->Next;
+
+ if (!(CurrentDescriptor->Status & DC21X4_RDES_ERROR_SUMMARY)) {
+
+ // The frame was received correctly
+
+ FrameSize = ((CurrentDescriptor->Status & DC21X4_RDES_FRAME_LENGTH) >> RDES_FRAME_LENGTH_BIT_NUMBER)
+ - ETH_CRC_SIZE;
+
+ // Get a pointer to the receive buffer header.
+
+ RcvHeader = CurrentDescriptor->RcvHeader;
+ ASSERT(RcvHeader->Signature == 'dHxR');
+
+ FrameVa = (PVOID)(RcvHeader->Va);
+
+ NdisFlushBuffer(
+ RcvHeader->FlushBuffer,
+ FALSE
+ );
+
+ NdisSetPhysicalAddressLow(Pa,RcvHeader->Pa);
+
+ NdisMUpdateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ RcvHeader->Size,
+ (PVOID)RcvHeader->Va,
+ Pa
+ );
+
+ // Adjust the length of the flush buffer to the
+ // length of the packet.
+
+ NdisAdjustBufferLength(
+ RcvHeader->FlushBuffer,
+ FrameSize
+ );
+
+
+ // Save the packet in the packet array.
+
+ Packet = RcvHeader->Packet;
+ *pPktArray = Packet;
+
+ // Log the packet.
+
+ DC21X4LogPacket(Packet, RcvHeader, '-', Count);
+ // Update the statistics based on Receive status;
+#if _DBG
+ DbgPrint("Receive ok\n");
+#endif
+ Adapter->GeneralMandatory[GM_RECEIVE_OK]++;
+
+ // DC21X4 flags Rcv Multicast address but does not
+ // support a specific flag for Rcv Broadcast address
+
+ if (CurrentDescriptor->Status & DC21X4_RDES_MULTICAST_FRAME) {
+ FrameType = (IS_BROADCAST (FrameVa)) ? RCV_BROADCAST_FRAME: RCV_MULTICAST_FRAME;
+ }
+ else {
+ FrameType = RCV_DIRECTED_FRAME;
+ }
+#if _DBG
+ DbgPrint("FrameType = %d\n",FrameType);
+#endif
+ Adapter->GeneralOptionalCount[FrameType].FrameCount++;
+
+ ADD_ULONG_TO_LARGE_INTEGER(
+ Adapter->GeneralOptionalCount[FrameType].ByteCount,
+ FrameSize
+ );
+ // Can the binding keep the packet?
+
+ if (Adapter->FreeRcvList != NULL) {
+
+ NDIS_SET_PACKET_STATUS(*pPktArray, NDIS_STATUS_SUCCESS);
+
+ // Remove the receive buffer from the ring
+ // and replace it with an extra one.
+
+ RcvHeader = Adapter->FreeRcvList;
+ Adapter->FreeRcvList = RcvHeader->Next;
+
+ Adapter->CurrentReceiveBufferCount--;
+
+ // Setup a new receive buffer for the current descriptor.
+
+ CurrentDescriptor->RcvHeader = RcvHeader;
+ CurrentDescriptor->FirstBufferAddress = RcvHeader->Pa;
+ CurrentDescriptor->Status = DESC_OWNED_BY_DC21X4;
+ }
+ else {
+
+ // Mark the packet as copy only...
+
+ NDIS_SET_PACKET_STATUS(*pPktArray, NDIS_STATUS_RESOURCES);
+
+ Adapter->NeededReceiveBuffers++;
+ RCV_RESERVED(Packet)->Descriptor = CurrentDescriptor;
+ }
+
+ Count ++;
+ pPktArray ++;
+ }
+ else {
+
+ // The frame was received with errors:
+ // Update the statistics based on the Receive status.
+#if _DBG
+ DbgPrint("Receive_error: DescStatus = %08x\n",CurrentDescriptor->Status);
+#endif
+ Adapter->GeneralMandatory[GM_RECEIVE_ERROR]++;
+
+ if (CurrentDescriptor->Status & DC21X4_RDES_DRIBBLING_BIT) {
+#if _DBG
+ DbgPrint(" Rcv Alignment Error\n");
+#endif
+ Adapter->MediaMandatory[MM_RECEIVE_ALIGNMENT_ERROR]++;
+ }
+ else if (CurrentDescriptor->Status & DC21X4_RDES_CRC_ERROR) {
+#if _DBG
+ DbgPrint(" Rcv CRC Error\n");
+#endif
+ Adapter->GeneralOptional[GO_RECEIVE_CRC_ERROR]++;
+ }
+
+ if (CurrentDescriptor->Status & DC21X4_RDES_OVERFLOW) {
+#if _DBG
+ DbgPrint(" Rcv Overflow\n");
+#endif
+ Adapter->MediaOptional[MO_RECEIVE_OVERFLOW]++;
+ }
+
+ CurrentDescriptor->Status = DESC_OWNED_BY_DC21X4;
+ }
+
+ }
+
+ // Did we get any packets to indicate up?
+
+ if (Count != 0) {
+
+
+ // Indicate the packets up to the filter library.
+
+ NdisMIndicateReceivePacket(Adapter->MiniportAdapterHandle,
+ Adapter->PacketArray,
+ Count);
+
+
+ // Determine which packets were kept and which ones
+ // were not.
+
+ for (i = 0, pPktArray = Adapter->PacketArray;
+ i < Count;
+ i++, pPktArray ++) {
+
+ // If the status code for the packet is not
+ // status pending then we can place the resources back
+ // on the free lists.
+
+ if (NDIS_GET_PACKET_STATUS(*pPktArray) != NDIS_STATUS_PENDING) {
+
+ // Get a pointer to the receive header.
+
+ RcvHeader = RCV_RESERVED(*pPktArray)->RcvHeader;
+ ASSERT(RcvHeader->Signature == 'dHxR');
+
+ DC21X4LogPacket(*pPktArray, RcvHeader, '+', i);
+
+ // Adjust the buffer length.
+
+ NdisAdjustBufferLength(
+ RcvHeader->FlushBuffer,
+ DC21X4_MAX_FRAME_SIZE
+ );
+
+ // If we indicated to the binding that it couldn't
+ // keep this packet then don't place it back on the
+ // list!!!
+
+ if (NDIS_GET_PACKET_STATUS(*pPktArray) == NDIS_STATUS_RESOURCES) {
+ RCV_RESERVED(*pPktArray)->Descriptor->Status = DESC_OWNED_BY_DC21X4;
+ }
+ else {
+
+ // Place the buffer back on the free queue.
+
+ RcvHeader->Next = Adapter->FreeRcvList;
+ Adapter->FreeRcvList = RcvHeader;
+ }
+ }
+ }
+ }
+ }
+ return CurrentDescriptor;
+
+}
+
+
+
+
+
+
+
+
+
+
+/*+
+ *
+ * ProcessTransmitDescRing
+ *
+ * Routine Description:
+ *
+ * Process the packets that have finished transmitting
+ *
+ * Arguments:
+ *
+ * Adapter - The adapter to indicate to.
+ *
+ * Return Value:
+ *
+ * None.
+ *
+-*/
+
+
+PDC21X4_TRANSMIT_DESCRIPTOR
+ProcessTransmitDescRing(
+ IN PDC21X4_ADAPTER Adapter
+ )
+{
+
+ PDC21X4_TRANSMIT_DESCRIPTOR CurrentDescriptor;
+ PDC21X4_TRANSMIT_DESCRIPTOR Descptr;
+ UINT Collisions;
+ NDIS_STATUS NdisStatus;
+ UINT MapPtr;
+ ULONG ProcessStatus;
+ ULONG DescOwnership;
+
+ ULONG TxmDescriptorCount = 0;
+ ULONG MapRegistersCount = 0;
+ ULONG MaxTransmitBufferCount = 0;
+ ULONG MinTransmitBufferCount = 0;
+ ULONG GoTransmitCount = 0;
+
+#if _DBG
+ DbgPrint("ProcessTransmitInterrupts\n");
+#endif
+
+ // If the Transmit descriptor ring is not empty,
+ // walk the ring from the last known descriptor owned by the adapter
+
+ while (Adapter->DequeueTransmitDescriptor != Adapter->EnqueueTransmitDescriptor) {
+
+ CurrentDescriptor = Adapter->DequeueTransmitDescriptor;
+
+ // If the current descriptor is not owned by the system, we are done.
+
+ if ((CurrentDescriptor->Status & DC21X4_TDES_OWN_BIT) != DESC_OWNED_BY_SYSTEM) {
+ break;
+ }
+
+ if (CurrentDescriptor->Control & DC21X4_TDES_SETUP_PACKET) {
+
+#if _DBG
+ DbgPrint("Int: TxmDesc %08x - Setup desc.\n",CurrentDescriptor);
+#endif
+ // Setup buffer
+ // Complete the pended Set Information request
+ // which originated the CAM load
+
+#if _DBG
+ DbgPrint("Complete Set Information\n");
+#endif
+ NdisMSetInformationComplete (
+ Adapter->MiniportAdapterHandle,
+ NDIS_STATUS_SUCCESS
+ );
+
+ if ( (Adapter->DeviceId == DC21040_CFID)
+ && (Adapter->RevisionNumber == DC21040_REV1)) {
+
+ // SFD bug workaround :
+ // Restart the Receiver and Enable the Sia
+
+ DC21X4_WRITE_PORT(
+ DC21X4_OPERATION_MODE,
+ Adapter->OperationMode
+ );
+
+ DC21X4_WRITE_PORT(
+ DC21X4_SIA_MODE_0,
+ Adapter->Media[Adapter->SelectedMedium].SiaRegister[0]
+ );
+ }
+
+ TxmDescriptorCount++;
+ Adapter->DequeueTransmitDescriptor = CurrentDescriptor->Next;
+
+ }
+
+ else if (CurrentDescriptor->Control & DC21X4_TDES_LAST_SEGMENT) {
+
+#if _DBG
+ DbgPrint("Int: TxmDesc %08x - Last segment desc.\n",CurrentDescriptor);
+#endif
+ // if Underrun check if the packet should be requeued
+ if ( (CurrentDescriptor->Status & DC21X4_TDES_UNDERRUN_ERROR)
+ && (Adapter->UnderrunRetryCount < Adapter->UnderrunMaxRetries)
+ ) {
+
+ // The Txm packet can only be requeued
+ // if the Txm process has not been restarted
+ // by a Txm Poll demand
+
+ Adapter->DisableTransmitPolling = TRUE;
+
+ DC21X4_READ_PORT(
+ DC21X4_STATUS,
+ &ProcessStatus
+ );
+
+ ProcessStatus &= DC21X4_TXM_PROCESS_STATE;
+
+ DescOwnership = (CurrentDescriptor->Next != Adapter->EnqueueTransmitDescriptor) ?
+ (CurrentDescriptor->Next)->Status & DC21X4_TDES_OWN_BIT :
+ DESC_OWNED_BY_DC21X4;
+
+ if ((ProcessStatus == DC21X4_TXM_PROCESS_SUSPENDED) && (DescOwnership == DESC_OWNED_BY_DC21X4)) {
+
+ // Requeue the Txm packet
+#if __DBG
+ DbgPrint(" Txm Underrun: Retry = %d\n",Adapter->UnderrunRetryCount);
+#endif
+ //Stop the transmitter
+
+ DC21X4_WRITE_PORT(
+ DC21X4_OPERATION_MODE,
+ Adapter->OperationMode & ~(DC21X4_TXM_START)
+ );
+
+ //Reinitialize the descriptor's ownership bits
+
+ //First segment descriptor
+ Descptr = CurrentDescriptor->DescPointer;
+
+ DC21X4_WRITE_PORT(
+ DC21X4_TXM_DESC_RING,
+ Descptr->DescriptorPa
+ );
+
+ while (TRUE) {
+
+ Descptr->Status = DESC_OWNED_BY_DC21X4;
+ if (Descptr == CurrentDescriptor) {
+ break;
+ }
+ else {
+ Descptr = Descptr->Next;
+ }
+ }
+
+ Adapter->DisableTransmitPolling = FALSE;
+
+ //Restart the transmitter
+
+ DC21X4_WRITE_PORT(
+ DC21X4_OPERATION_MODE,
+ Adapter->OperationMode
+ );
+
+ Adapter->UnderrunRetryCount++;
+
+ return CurrentDescriptor;
+ }
+ else {
+ Adapter->DisableTransmitPolling = FALSE;
+
+ }
+
+ }
+
+ Adapter->UnderrunRetryCount = 0 ;
+
+ // Point to the first segment descriptor and walk down the descriptors
+ // mapping the current frame to free the physical mapping table
+
+ Descptr = CurrentDescriptor->DescPointer;
+
+ while (TRUE) {
+
+ // If this descriptor points the first segment of a Ndis Buffer, free the
+ // Physical Mapping table of this buffer
+
+ for (MapPtr = Descptr->MapTableIndex;
+ MapPtr < Descptr->MapTableIndex + NUMBER_OF_SEGMENT_PER_DESC;
+ MapPtr++) {
+
+ if (Adapter->PhysicalMapping[MapPtr].Valid) {
+#if _DBG
+ DbgPrint(" NdisMCompleteBufferPhysicalMapping (%d)\n",MapPtr);
+#endif
+ NdisMCompleteBufferPhysicalMapping(
+ Adapter->MiniportAdapterHandle,
+ Adapter->PhysicalMapping[MapPtr].Buffer,
+ Adapter->PhysicalMapping[MapPtr].Register
+ );
+
+ Adapter->PhysicalMapping[MapPtr].Valid = FALSE;
+ MapRegistersCount++;
+ }
+ }
+
+ if (Descptr == CurrentDescriptor) {
+ break;
+ }
+ else {
+ TxmDescriptorCount++;
+ Descptr = Descptr->Next;
+ }
+
+ }
+
+ // If this packet was copied into a preallocated Txm Buffer,
+ // free the resources
+
+ if (CurrentDescriptor->SendStatus == CopyMaxBuffer) {
+ MaxTransmitBufferCount++;
+ }
+ else if (CurrentDescriptor->SendStatus == CopyMinBuffer) {
+ MinTransmitBufferCount++;
+ }
+
+ // Update the statistics based on the Transmit status
+
+ if (!(CurrentDescriptor->Status & Adapter->TransmitDescriptorErrorMask)) {
+
+ // The frame was transmitted correctly
+
+ Collisions = (CurrentDescriptor->Status & DC21X4_TDES_COLLISION_COUNT)
+ >> TDES_COLLISION_COUNT_BIT_NUMBER;
+
+ if (Collisions == 1) {
+ Adapter->MediaMandatory[MM_TRANSMIT_ONE_COLLISION]++;
+ }
+ else if (Collisions > 1) {
+ Adapter->MediaMandatory[MM_TRANSMIT_MULT_COLLISIONS]++;
+ }
+ if (CurrentDescriptor->Status & DC21X4_TDES_DEFERRED) {
+ Adapter->MediaOptional[MO_TRANSMIT_DEFERRED]++;
+ }
+ if (CurrentDescriptor->Status & DC21X4_TDES_HEARTBEAT_FAIL) {
+ Adapter->MediaOptional[MO_TRANSMIT_HEARTBEAT_FAILURE]++;
+ }
+
+ Adapter->GeneralOptionalCount[CurrentDescriptor->PacketType].FrameCount++;
+ ADD_ULONG_TO_LARGE_INTEGER(
+ Adapter->GeneralOptionalCount[CurrentDescriptor->PacketType].ByteCount,
+ CurrentDescriptor->PacketSize
+ );
+
+ Adapter->GeneralMandatory[GM_TRANSMIT_OK]++;
+ NdisStatus = NDIS_STATUS_SUCCESS;
+ }
+
+ else {
+
+#if _DBG
+ DbgPrint("Transmit_error: DescStatus = %08x\n",CurrentDescriptor->Status);
+#endif
+ if (CurrentDescriptor->Status & DC21X4_TDES_TXM_JABBER_TIMEOUT) {
+
+ // This indicates a severe SIA hardware error. Stop the adapter
+ // to avoid generating noise on the net
+#if __DBG
+ DbgPrint("DC21X4 TXM JABBER TIMEOUT!!!\n");
+#endif
+ DC21X4StopAdapter(Adapter);
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 1,
+ DC21X4_ERRMSG_TXM_JABBER_TIMEOUT
+ );
+ }
+
+ if (CurrentDescriptor->Status & DC21X4_TDES_EXCESSIVE_COLLISIONS) {
+#if _DBG
+ DbgPrint(" Txm Excess Collisions\n");
+#endif
+ Adapter->MediaOptional[MO_TRANSMIT_EXC_COLLISIONS]++;
+ Adapter->ExcessCollisionsCount++;
+ }
+ else {
+ Adapter->ExcessCollisionsCount=0;
+ }
+
+ if (CurrentDescriptor->Status & DC21X4_TDES_UNDERRUN_ERROR) {
+
+ Adapter->MediaOptional[MO_TRANSMIT_UNDERRUN]++;
+#if __DBG
+ DbgPrint(" Txm Underrun [UnderrunCount=%d]\n",Adapter->MediaOptional[MO_TRANSMIT_UNDERRUN]);
+#endif
+
+ if ( (Adapter->MediaOptional[MO_TRANSMIT_UNDERRUN] >= Adapter->UnderrunThreshold)
+ && !(Adapter->OperationMode & DC21X4_STORE_AND_FORWARD)
+ ) {
+
+ //Force StoreAndForward mode
+#if __DBG
+ DbgPrint("UnderrunCount=%d : Force StoreAnd Forward mode\n",
+ Adapter->MediaOptional[MO_TRANSMIT_UNDERRUN]);
+#endif
+ DC21X4StopReceiverAndTransmitter(Adapter);
+
+ Adapter->OperationMode |= DC21X4_STORE_AND_FORWARD;
+
+ DC21X4_WRITE_PORT(
+ DC21X4_OPERATION_MODE,
+ Adapter->OperationMode
+ );
+ }
+
+ }
+ else if (CurrentDescriptor->Status & DC21X4_TDES_LATE_COLLISION) {
+#if _DBG
+ DbgPrint(" Txm Late Collision\n");
+#endif
+ Adapter->MediaOptional[MO_TRANSMIT_LATE_COLLISION]++;
+ }
+ if (CurrentDescriptor->Status & DC21X4_TDES_NO_CARRIER) {
+#if _DBG
+ DbgPrint(" Txm No Carrier\n");
+#endif
+ Adapter->NoCarrierCount++;
+ }
+ else {
+ Adapter->NoCarrierCount=0;
+ }
+
+ Adapter->GeneralMandatory[GM_TRANSMIT_ERROR]++;
+ NdisStatus = NDIS_STATUS_FAILURE;
+
+ }
+
+ GoTransmitCount++;
+
+// if (CurrentDescriptor->SendStatus == MappedBuffer) {
+#if _DBG
+ DbgPrint(" Signal Tx Completion desc= %08x\n", CurrentDescriptor);
+#endif
+ NdisMSendComplete(
+ Adapter->MiniportAdapterHandle,
+ CurrentDescriptor->Packet,
+ NdisStatus
+ );
+
+// }
+
+ TxmDescriptorCount++;
+ Adapter->DequeueTransmitDescriptor = CurrentDescriptor->Next;
+ }
+
+ else if (CurrentDescriptor->Control & DC21X4_TDES_FIRST_SEGMENT) {
+
+#if _DBG
+ DbgPrint("Int: TxmDesc %08x - First segment desc.\n",CurrentDescriptor);
+#endif
+ Adapter->DequeueTransmitDescriptor = CurrentDescriptor->DescPointer;
+
+ }
+
+ else {
+
+ TxmDescriptorCount++;
+ Adapter->DequeueTransmitDescriptor = CurrentDescriptor->Next;
+ }
+
+ }
+
+ if (Adapter->FullDuplex) {
+ NdisDprAcquireSpinLock(&Adapter->FullDuplexSpinLock);
+ }
+
+ Adapter->FreeTransmitDescriptorCount += TxmDescriptorCount;
+
+ Adapter->FreeMapRegisters += MapRegistersCount;
+
+ Adapter->MaxTransmitBufferInUse -= MaxTransmitBufferCount;
+
+ Adapter->MinTransmitBufferInUse -= MinTransmitBufferCount;
+
+ Adapter->GeneralOptional[GO_TRANSMIT_QUEUE_LENGTH] -= GoTransmitCount;
+
+ if (Adapter->FullDuplex) {
+ NdisDprReleaseSpinLock(&Adapter->FullDuplexSpinLock);
+ }
+
+ return Adapter->DequeueTransmitDescriptor;
+
+}
+
+/*+
+ *
+ * DC21X4EnableInterrupt
+ *
+-*/
+extern
+VOID
+DC21X4EnableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+{
+ PDC21X4_ADAPTER Adapter;
+
+ Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
+
+ DC21X4_WRITE_PORT(
+ DC21X4_INTERRUPT_MASK,
+ Adapter->InterruptMask
+ );
+ return;
+}
+
+/*+
+ *
+ * DC21X4DisableInterrupt
+ *
+-*/
+extern
+VOID
+DC21X4DisableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+{
+ PDC21X4_ADAPTER Adapter;
+
+ Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
+
+ DC21X4_WRITE_PORT(
+ DC21X4_INTERRUPT_MASK,
+ 0
+ );
+ return;
+}
+
+
+/*+
+ *
+ *DC21X4ReturnPacket
+ *
+ * Routine Description:
+ *
+ * Place a buufer released by the binding back into its free list
+ *
+ * Arguments:
+ *
+ * Return Value:
+ *
+-*/
+NDIS_STATUS
+DC21X4ReturnPacket(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET Packet
+ )
+
+{
+
+ PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
+ PRCV_HEADER RcvHeader;
+
+
+ // Get a pointer to the receive header.
+
+ RcvHeader = RCV_RESERVED(Packet)->RcvHeader;
+ ASSERT(RcvHeader->Signature == 'dHxR');
+
+ DC21X4LogPacket(Packet, RcvHeader, '+', (ULONG)-1);
+
+
+ // Adjust the buffer length.
+
+ NdisAdjustBufferLength(
+ RcvHeader->FlushBuffer,
+ DC21X4_RECEIVE_BUFFER_SIZE
+ );
+
+ // Place the buffer back on the free queue.
+
+ RcvHeader->Next = Adapter->FreeRcvList;
+ Adapter->FreeRcvList = RcvHeader;
+
+ return NDIS_STATUS_SUCCESS;
+
+}
+
diff --git a/private/ntos/ndis/dc21x4/mactophy.c b/private/ntos/ndis/dc21x4/mactophy.c
new file mode 100644
index 000000000..e8ac6cde0
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/mactophy.c
@@ -0,0 +1,701 @@
+/*+
+ * file: mactophy.c
+ *
+ * Copyright (C) 1992-1995 by
+ * Digital Equipment Corporation, Maynard, Massachusetts.
+ * All rights reserved.
+ *
+ * This software is furnished under a license and may be used and copied
+ * only in accordance of the terms of such license and with the
+ * inclusion of the above copyright notice. This software or any other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person. No title to and ownership of the software is hereby
+ * transferred.
+ *
+ * The information in this software is subject to change without notice
+ * and should not be construed as a commitment by digital equipment
+ * corporation.
+ *
+ * Digital assumes no responsibility for the use or reliability of its
+ * software on equipment which is not supplied by digital.
+ *
+ *
+ * Abstract: This file contains the code to access the MII PHY device
+ * (initialization, set the connections, and sensing of the
+ * link.
+ *
+ * Author: Claudio Hazan
+ *
+ * Revision History:
+ *
+ * 15-Oct-95 ch Creation
+ * 20-Dec-95 phk Cleanup, add support for DC21142
+ *
+-*/
+
+#include <precomp.h>
+
+#define LINK_PASS_MAX_LOOP 350
+#define LINK_PASS_DELAY (10*MILLISECOND)
+
+#if MII_DBG
+PUCHAR MiiMediumString[] = {
+ "","","","","","","","","",
+ "Mii10BaseT",
+ "Mii10BaseT_FD",
+ "Mii10Base2",
+ "Mii10Base5",
+ "Mii100BaseTx",
+ "Mii100BaseTx_FD",
+ "Mii100BaseT4",
+ "Mii100BaseFx",
+ "Mii100BaseFx_FD"
+};
+#endif
+
+/*+
+ * DC21X4PhyInit
+ *
+ * Routine Description:
+ *
+ * This routine initializes each PHY present in the SROM; Reset each Phy
+ * if there is a Reset sequence specified there, Initializes the Phys and
+ * updates the Capabilities tables from the values contained in the SROM
+ * with the values supported by the Phys.
+ *
+ * Arguments:
+ *
+ * Adapter - Pointer to the Data Structure
+ *
+ * Return Value:
+ *
+ * True if any PHY was succesfully initialized.
+ *
+-*/
+extern
+BOOLEAN
+DC21X4PhyInit(
+ IN PDC21X4_ADAPTER Adapter
+ )
+{
+ BOOLEAN PhyPresent;
+ BOOLEAN ConnectionPresent=FALSE;
+ USHORT Capabilities;
+ INT PhyNumber;
+ INT Seq;
+
+ ULONG Data;
+
+#if MII_DBG
+ DbgPrint("DC21X4PhyInit\n");
+#endif
+ // Reset all the phys using its reset sequence.
+
+ if (!Adapter->PhyMediumInSrom) {
+#if __DBG
+ DbgPrint("No PHY Media in SROM\n");
+#endif
+ return FALSE;
+ }
+
+#if __DBG
+ DbgPrint("PHY Reset\n");
+#endif
+
+ Adapter->Force10 = FALSE;
+
+ for (PhyNumber=0; PhyNumber < MAX_PHY_TABLE; PhyNumber++) {
+
+ if (Adapter->Phy[Adapter->PhyNumber].ResetSequenceLength != 0) {
+
+ DC21X4WriteGepRegister(
+ Adapter,
+ (ULONG)Adapter->Phy[Adapter->PhyNumber].GeneralPurposeCtrl
+ );
+
+ for (Seq=0; Seq < Adapter->Phy[Adapter->PhyNumber].ResetSequenceLength; Seq++) {
+#if MII_DBG
+ DbgPrint("Sequence[%d]=%04x\n", Seq, Adapter->Phy[PhyNumber].ResetSequence[Seq]);
+#endif
+ DELAY (5); // 5 microseconds
+
+ DC21X4WriteGepRegister(
+ Adapter,
+ (ULONG)Adapter->Phy[Adapter->PhyNumber].ResetSequence[Seq]
+ );
+ }
+ }
+ }
+
+ Adapter->PhyNumber = 0;
+ PhyPresent = MiiGenInit(Adapter);
+
+ if (PhyPresent) {
+#if __DBG
+ DbgPrint("Phy: Initialization OK\n");
+#endif
+
+ Capabilities = MiiGenGetCapabilities(Adapter);
+
+ // Convert the MediaType to the MiiMediaType values
+
+ Adapter->MiiMediaType =
+ ConvertMediaTypeToMiiType[Adapter->MediaType & MEDIA_MASK]
+ | (Adapter->MediaType & CONTROL_MASK);
+
+#if MII_DBG
+ DbgPrint("Translate MediaType %x to MiiMediaType %x\n",
+ Adapter->MediaType,Adapter->MiiMediaType);
+#endif
+
+ Adapter->PhyNwayCapable = ( ((Adapter->MiiMediaType & MEDIA_NWAY) != 0)
+ && ((Capabilities & MiiPhyNwayCapable) != 0)
+ );
+
+ // Merge the PHY Capabilities with the medium stored in SROM
+
+ for (PhyNumber=0; PhyNumber < MAX_PHY_TABLE; PhyNumber++) {
+
+ Adapter->Phy[PhyNumber].MediaCapabilities &= Capabilities;
+
+
+ Adapter->Phy[PhyNumber].MediaCapabilities |= (Capabilities & MiiPhyNwayCapable);
+#if MII_DBG
+ DbgPrint("Merged Capabilities (SROM&PHY)= %04x\n", Adapter->Phy[PhyNumber].MediaCapabilities);
+#endif
+ Adapter->MiiGen.Phys[PhyNumber]->PhyCapabilities = Adapter->Phy[PhyNumber].MediaCapabilities;
+ }
+ }
+ if (PhyPresent) {
+#if MII_DBG
+ DbgPrint("Check if Connection is supported\n");
+#endif
+ // Now check the Connection.
+ ConnectionPresent = MiiGenCheckConnection(
+ Adapter,
+ (USHORT)Adapter->MiiMediaType
+ );
+
+ if (!ConnectionPresent) {
+ //Force the Phy to 10
+ DC21X4SetPhyControl(
+ Adapter,
+ MiiGenAdminForce10
+ );
+ }
+ }
+
+ return (PhyPresent && ConnectionPresent);
+}
+
+
+/*+
+ * DC21X4SetPhyConnection
+ *
+ * Routine Description:
+ *
+ * This function first resets the MAC (which could reset the PHY) and
+ * initialize CSR6 and CSR12 registers. Then sets the PHY to
+ * the required medium.
+ *
+ * Arguments:
+ *
+ * Adapter - Pointer to the Data Structure
+ *
+ * Return Value:
+ *
+ * True if the requested Medium is supported by the Phy.
+ *
+-*/
+extern
+BOOLEAN
+DC21X4SetPhyConnection(
+ IN PDC21X4_ADAPTER Adapter
+ )
+{
+ BOOLEAN MediaSupported;
+
+ // First set Mac Connection.
+#if MII_DBG
+ DbgPrint("DC21X4SetPhyConnection\n");
+#endif
+ SetMacConnection(Adapter);
+
+ // Now set the PHY Connection.
+ MediaSupported = MiiGenSetConnection(
+ Adapter,
+ Adapter->MiiMediaType,
+ Adapter->Phy[Adapter->PhyNumber].NwayAdvertisement
+ );
+ return MediaSupported;
+
+}
+
+
+
+/*+
+ * SetMacConnection
+ *
+ * Routine Description:
+ *
+ * This function initialize the CSR6 and CSR12 registers according to the
+ * values present in the SROM for the Selected Medium.
+ *
+ * Arguments:
+ *
+ * Adapter - Pointer to the Data Structure
+ *
+ * Return Value:
+ *
+ *
+-*/
+
+void
+SetMacConnection(
+ IN PDC21X4_ADAPTER Adapter
+ )
+{
+
+ USHORT MediaPositionMask;
+ ULONG OperationMode;
+
+#if MII_DBG
+ DbgPrint("SetMacConnection\n");
+#endif
+ // First of all find the media type.
+
+ MediaPositionMask = MediaBitTable[(Adapter->MiiMediaType & MEDIA_MASK)];
+#if MII_DBG
+ DbgPrint(" MiiMediaType %04x Bitmap %04x\n",
+ Adapter->MiiMediaType,MediaPositionMask);
+#endif
+
+ // If unknown media, just return.
+ if (MediaPositionMask == 0) {
+#if __DBG
+ DbgPrint("UNKNOWN Phy Medium %x!!!\n",Adapter->MiiMediaType);
+#endif
+ return;
+ }
+
+ // select Port_Select MII (disable HEARTBEAT in MII mode).
+ OperationMode = Adapter->OperationMode | (DC21X4_PORT_SELECT | DC21X4_HEARTBEAT_DISABLE);
+
+ if (Adapter->Phy[Adapter->PhyNumber].MediaCapabilities & MediaPositionMask) {
+
+ if (Adapter->Phy[Adapter->PhyNumber].FullDuplexBits & MediaPositionMask) {
+ // Set FullDuplex bit
+ OperationMode |= DC21X4_FULL_DUPLEX_MODE;
+ }
+ else {
+ //Reset FullDuplex bit
+ OperationMode &= ~DC21X4_FULL_DUPLEX_MODE;
+ }
+ if (Adapter->Phy[Adapter->PhyNumber].TxThresholdModeBits & MediaPositionMask) {
+ // Set TTM bit
+ OperationMode &= ~(Adapter->Threshold100Mbps);
+ OperationMode |= (DC21X4_TXM_THRESHOLD_MODE | Adapter->Threshold10Mbps);
+ }
+ else {
+ // Reset TTM bit
+ OperationMode &= ~(DC21X4_TXM_THRESHOLD_MODE | Adapter->Threshold10Mbps);
+ OperationMode |= Adapter->Threshold100Mbps;
+ }
+
+#if __DBG
+ DbgPrint("SetMacConnection:%s FullDuplex & %s TTM bits in CSR6\n",
+ OperationMode & DC21X4_FULL_DUPLEX_MODE ? "Set" : "Reset",
+ OperationMode & DC21X4_TXM_THRESHOLD_MODE ? "Set" : "Reset");
+#endif
+
+ }
+
+ // Switch Medium:
+
+ DC21X4IndicateMediaStatus(
+ Adapter,
+ LinkFail
+ );
+
+ // if TTM or FDX setting has changed, stop the TXM and RCV process before modifying
+ // these modes
+
+ if ((OperationMode & DC21X4_MODE_MASK) != (Adapter->OperationMode & DC21X4_MODE_MASK) ) {
+#if MII_DBG
+ DbgPrint("FDX or TTM setting has changed: stop RCV and TXM\n");
+#endif
+ DC21X4StopReceiverAndTransmitter(Adapter);
+ }
+
+ switch (Adapter->DeviceId) {
+
+ case DC21142_CFID:
+
+ //Initialize the Sia Registers for MII operation
+ // Reset Sia (CSR13)
+ // Turn off the BNC transceiver (CSR15)
+ // Disable Autonegotiation (CSR14)
+
+ DC21X4_WRITE_PORT(
+ DC21X4_SIA_MODE_0,
+ DC21X4_RESET_SIA
+ );
+
+ Adapter->Gep_Sia2 =
+ (DC21142_SIA2_10BT & DC21142_SIA2_MASK)
+ | (Adapter->Gep_Sia2 & DC21142_GEP_MASK);
+
+ DC21X4_WRITE_PORT(
+ DC21X4_SIA_MODE_2,
+ Adapter->Gep_Sia2
+ );
+
+ DC21X4_WRITE_PORT(
+ DC21X4_SIA_MODE_1,
+ 0
+ );
+
+ break;
+ }
+
+
+ // Init the Command Register.
+
+ Adapter->OperationMode = OperationMode;
+
+#if __DBG
+ DbgPrint("SetMacConnection: Write CSR6=%08x\n", OperationMode);
+#endif
+ DC21X4_WRITE_PORT(
+ DC21X4_OPERATION_MODE,
+ Adapter->OperationMode
+ );
+ DELAY(5);
+
+ DC21X4InitializeGepRegisters(Adapter,TRUE);
+
+}
+
+/*+
+ * DC21X4MiiAutoDetect
+ *
+ * Routine Description:
+ *
+ * This function contains the power up autosensing for PHYs.
+ *
+ * Arguments:
+ *
+ * Adapter - Pointer to the Data Structure
+ *
+ * Return Value:
+ *
+ * Link status
+ *
+-*/
+extern
+BOOLEAN
+DC21X4MiiAutoDetect(
+ IN PDC21X4_ADAPTER Adapter
+ )
+{
+ ULONG OperationMode;
+ INT Loop;
+ USHORT ConnectionStatus;
+ USHORT TmpMedia;
+ BOOLEAN Link;
+#if MII_DBG
+ ULONG Status;
+#endif
+
+ Link = MiiGenGetConnectionStatus(
+ Adapter,
+ &ConnectionStatus
+ );
+ DC21X4IndicateMediaStatus(
+ Adapter,
+ Link ? MiiLinkPass : LinkFail
+ );
+
+ // If no link available while still negotiating, continue to
+ // check the link up to 3s.
+
+ if (!Link) {
+#if MII_DBG
+ Loop = 30;
+#else
+ Loop = LINK_PASS_MAX_LOOP;
+#endif
+ while (!Link && Loop--) {
+#if MII_DBG
+ DbgPrint("LinkPass=FALSE: wait up to 3 seconds %d\n", Loop);
+#endif
+ DELAY(LINK_PASS_DELAY);
+ Link = MiiGenGetConnectionStatus(
+ Adapter,
+ &ConnectionStatus
+ );
+ }
+ DC21X4IndicateMediaStatus(
+ Adapter,
+ Link ? MiiLinkPass : LinkFail
+ );
+ }
+
+#if MII_DBG
+ DC21X4_READ_PORT(
+ DC21X4_OPERATION_MODE,
+ &Status
+ );
+ DbgPrint("CSR6= %08x, OperationMode=%08x\n", Status, Adapter->OperationMode);
+#endif
+
+ // In AutoSense mode, we must know which media has been chosen to set the MAC.
+ // otherwise the MAC has been already set.
+
+ if (Adapter->MiiMediaType & MEDIA_AUTOSENSE){
+#if MII_DBG
+ DbgPrint("AutoSense to check which Medium was chosen\n");
+#endif
+ Link = MiiGenGetConnection(
+ Adapter,
+ &TmpMedia
+ );
+ DC21X4IndicateMediaStatus(
+ Adapter,
+ Link ? MiiLinkPass : LinkFail
+ );
+
+ if (Link){
+#if MII_DBG
+ DbgPrint("LinkPass= TRUE; Medium = %s\n",
+ MiiMediumString[TmpMedia&MEDIA_MASK]);
+#endif
+ Adapter->MiiMediaType = (TmpMedia | MEDIA_AUTOSENSE);
+ SetMacConnection(Adapter);
+ }
+ }
+
+ if ( !Link
+ && (Adapter->MediaCapable)
+ && (Adapter->MiiMediaType & MEDIA_AUTOSENSE)
+ ) {
+
+ //Switch back to the non_MII port
+
+ SelectNonMiiPort(Adapter);
+
+ }
+
+ return Link;
+
+}
+
+
+/*+
+ * DC21X4DynamicMiiAutoSense
+ *
+ * Routine Description:
+ *
+ * This function performs the PHY Dynamic Autosense
+ *
+ * Arguments:
+ *
+ * Adapter - Pointer to the Data Structure
+ *
+ * Return Value:
+ *
+ * Link status
+ *
+-*/
+extern
+BOOLEAN
+DC21X4MiiAutoSense(
+ IN PDC21X4_ADAPTER Adapter
+ )
+
+{
+ ULONG OperationMode;
+ USHORT CurrentMedia;
+ USHORT ConnectionStatus;
+ BOOLEAN Link;
+ BOOLEAN SwitchPort=FALSE;
+
+#if MII_DBG
+ DbgPrint("DC21X4MiiAutoSense\n");
+#endif
+
+ Link = MiiGenGetConnectionStatus(
+ Adapter,
+ &ConnectionStatus
+ );
+
+#if MII_DBG
+ DbgPrint("MiiMediaType = %04x, ConnectionStatus = %04x\n",
+ Adapter->MiiMediaType, ConnectionStatus);
+#endif
+
+ if (Adapter->MiiMediaType & MEDIA_AUTOSENSE) {
+
+ if (Link &&
+ ((ConnectionStatus & MEDIA_STATUS_MASK) == MEDIA_LINK_PASS_WITH_PF)){
+
+ // There was a link failure
+ // Check the current medium
+
+ Link = MiiGenGetConnection(
+ Adapter,
+ &CurrentMedia
+ );
+
+ if ( Link
+ && ( (Adapter->MiiMediaType != CurrentMedia)
+ || (Adapter->LinkStatus != MiiLinkPass)
+ )
+ ){
+
+ //The link is up but the medium has changed
+#if MII_DBG
+ DbgPrint("Mii Medium has changed: New Mii Medium = %s \n",
+ MiiMediumString[CurrentMedia&MEDIA_MASK]);
+#endif
+ Adapter->MiiMediaType = (CurrentMedia | MEDIA_AUTOSENSE);
+ SetMacConnection(Adapter);
+ }
+ }
+ }
+
+ // do not indicate the Mii Link down transition
+ // if the non_Mii link is up.
+ // In any other case indicate the transition
+
+ if (Link || (Adapter->LinkStatus != LinkPass)) {
+
+ DC21X4IndicateMediaStatus(
+ Adapter,
+ Link ? MiiLinkPass : LinkFail
+ );
+ }
+
+ if ( !Link
+ && (Adapter->MediaCapable)
+ && (Adapter->MiiMediaType & MEDIA_AUTOSENSE)
+ ) {
+
+ if ((ConnectionStatus & MEDIA_STATUS_MASK) == MEDIA_READ_REGISTER_FAILED){
+
+ //PHY is not connected anymore
+
+ Adapter->PhyPresent=FALSE;
+
+ if (Adapter->MediaType & MEDIA_NWAY) {
+
+ //Enable Nway Negotiation
+ DC21X4EnableNway (Adapter);
+
+ SwitchPort=TRUE;
+ }
+ }
+ else if (Adapter->OperationMode & DC21X4_PORT_SELECT){
+
+ // Mii link is down,current port is Mii,
+ // at least one non Mii port is populated:
+ //Switch Port_Select to enable the non MII ports
+ SwitchPort = TRUE;
+ }
+
+ if (SwitchPort) {
+
+ SelectNonMiiPort(Adapter);
+
+ }
+
+ }
+
+ return Link;
+
+}
+
+/*+
+ * SelectNonMiiPort
+ *
+ * Routine Description:
+ *
+ * This function selects the DC21X4 non_MII port
+ *
+ * Arguments:
+ *
+ * Adapter - Pointer to the Data Structure
+ *
+ * Return Value:
+ *
+ * None
+ *
+-*/
+extern
+VOID
+SelectNonMiiPort(
+ IN PDC21X4_ADAPTER Adapter
+ )
+
+{
+
+ ULONG OperationMode;
+
+ OperationMode = Adapter->OperationMode & ~(DC21X4_MEDIUM_MASK);
+ OperationMode |= Adapter->Media[Adapter->SelectedMedium].Mode;
+
+ if ((OperationMode & DC21X4_MODE_MASK) != (Adapter->OperationMode & DC21X4_MODE_MASK)) {
+ DC21X4StopReceiverAndTransmitter(Adapter);
+ }
+
+ Adapter->OperationMode = OperationMode;
+
+ DC21X4_WRITE_PORT(
+ DC21X4_OPERATION_MODE,
+ Adapter->OperationMode
+ );
+
+ DC21X4InitializeMediaRegisters(Adapter,FALSE);
+
+ switch (Adapter->SelectedMedium) {
+
+ case Medium10Base2:
+ case Medium10Base5:
+
+ DC21X4IndicateMediaStatus(Adapter,LinkPass);
+ break;
+ }
+
+}
+
+
+/*+
+ * DC21X4SetPhyControl
+ *
+ * Routine Description:
+ *
+ * This function modifies the PHY Control register.
+ *
+ * Arguments:
+ *
+ * Adapter - Pointer to the Data Structure
+ * Control - The Control to perform
+ *
+ * Return Value:
+ *
+ * none
+-*/
+extern
+VOID
+DC21X4SetPhyControl(
+ PDC21X4_ADAPTER Adapter,
+ USHORT AdminControl
+ )
+{
+
+ MiiGenAdminControl(Adapter, AdminControl);
+ return;
+
+}
+
+
diff --git a/private/ntos/ndis/dc21x4/makefile b/private/ntos/ndis/dc21x4/makefile
new file mode 100644
index 000000000..58189757d
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/makefile
@@ -0,0 +1,7 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the driver components of the Windows NT DDK
+#
+
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/dc21x4/makefile.inc b/private/ntos/ndis/dc21x4/makefile.inc
new file mode 100644
index 000000000..0b46b8d78
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/makefile.inc
@@ -0,0 +1,5 @@
+dc21x4.hlp: $(TARGETEXEFILES)
+ chmode -r dc21x4.hlp
+ binplace dc21x4.hlp
+ touch dc21x4.hlp
+ chmode +r dc21x4.hlp
diff --git a/private/ntos/ndis/dc21x4/media.c b/private/ntos/ndis/dc21x4/media.c
new file mode 100644
index 000000000..745b34085
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/media.c
@@ -0,0 +1,2047 @@
+/*+
+ * file: media.c
+ *
+ * Copyright (C) 1992-1995 by
+ * Digital Equipment Corporation, Maynard, Massachusetts.
+ * All rights reserved.
+ *
+ * This software is furnished under a license and may be used and copied
+ * only in accordance of the terms of such license and with the
+ * inclusion of the above copyright notice. This software or any other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person. No title to and ownership of the software is hereby
+ * transferred.
+ *
+ * The information in this software is subject to change without notice
+ * and should not be construed as a commitment by digital equipment
+ * corporation.
+ *
+ * Digital assumes no responsibility for the use or reliability of its
+ * software on equipment which is not supplied by digital.
+ *
+ *
+ * Abstract: This file contains the Media detection code of the
+ * NDIS 4.0 miniport driver for DEC's DC21X4 Ethernet Adapter
+ * family.
+ *
+ * Author: Philippe Klein
+ *
+ * Revision History:
+ *
+ * phk 01-Dec-1994 Initial entry
+ * phk 31-Jan-1994 Add Polarity support
+ * phk 26-Apr-1995 Modify the DC21140 MediaDetect and
+ * AutoSense routines
+ *
+-*/
+
+#include <precomp.h>
+
+#define MII100_TICK 30 // 2.5ms (81.9 us/tick)
+#define EXT10_TICK 12 // 2.5ms (204.8 us/tick)
+#define MII10_TICK 3 // 2.5ms (819.2 us/tick)
+
+#define ONE_SECOND_DELAY 400 // * 2.5 ms
+#define FIVE_MILLISECONDS_DELAY 2 // * 2.5 ms
+
+#define MAX_RETRY 4
+
+#define GEP_READ_DELAY 200 // milliseconds
+
+#define DC21X4_LINK_STATUS(_status,_adapter,_medium) \
+ (BOOLEAN) ( ( ( (_status) ^ (_adapter)->Media[(_medium)].Polarity) \
+ & (_adapter)->Media[(_medium)].SenseMask ) != 0)
+
+#if __DBG
+PUCHAR MediumString[] = {
+ "10BaseT",
+ "10Base2",
+ "10Base5",
+ "100BaseTx",
+ "10BaseT_FD",
+ "100BaseTx_FD",
+ "100BaseT4",
+ "100BaseFx",
+ "100BaseFx_FD",
+ "Mii10BaseT",
+ "Mii10BaseT_FD",
+ "Mii10Base2",
+ "Mii10Base5",
+ "Mii100BaseTx",
+ "Mii100BaseTx_FD",
+ "Mii100BaseT4",
+ "Mii100BaseFx",
+ "Mii100BaseFx_FD"
+};
+
+#endif
+
+/*+
+ * DC21X4MediaDetect
+ *
+ * Routine Description:
+ *
+ * DC21X4MediaDetect:
+ *
+ * checks the DC2104x media ports in the following order:
+ * 10BaseT -> 10Base2 -> 10Base5
+ *
+ * checks the DC21140 link status
+ *
+ * Arguments:
+ *
+ * Adapter
+ *
+ * Return Value:
+ *
+ * TRUE if the Autosense timer should be fired
+ *
+-*/
+
+extern
+BOOLEAN
+DC21X4MediaDetect(
+ IN PDC21X4_ADAPTER Adapter
+ )
+{
+
+ PDC21X4_TRANSMIT_DESCRIPTOR TxmDescriptor;
+ ULONG Status;
+ UINT PacketSize = 64;
+ INT Time;
+ INT CurrentMedium=0;
+ INT i;
+ INT j;
+
+ BOOLEAN Link=FALSE;
+ BOOLEAN Sensed=FALSE;
+#if __DBG
+ DbgPrint("DC21X4MediaDetect\n");
+#endif
+
+ switch (Adapter->DeviceId) {
+
+ case DC21140_CFID:
+
+ if (Adapter->MediaType & MEDIA_AUTOSENSE) {
+
+ //AutoSense mode:
+
+ //Initialize the General Purpose Control register
+
+ CurrentMedium = Adapter->MediaPrecedence[0];
+
+ DC21X4_WRITE_PORT(
+ DC21X4_GEN_PURPOSE,
+ Adapter->Media[CurrentMedium].GeneralPurposeCtrl
+ );
+
+ //Check the link status of each medium supported
+ //by the adapter until afirst link is detected up.
+
+ for (i=Adapter->MediaCount; i>0; i--) {
+
+ CurrentMedium = Adapter->MediaPrecedence[i-1];
+#if __DBG
+ DbgPrint("DC21X4MediaDetect: %d - Check medium %x \n",
+ i,CurrentMedium);
+#endif
+
+ if (( (CurrentMedium == Medium100BaseTx)
+ ||(CurrentMedium == Medium10BaseT)
+ )
+ && (!Sensed)
+ ) {
+
+ // 100BaseTx or 10BaseT medium:
+ // Check the 100BaseTx & the 10BaseT link
+
+ Link = DC2114Sense100BaseTxLink(Adapter);
+ Sensed = TRUE;
+#if __DBG
+ DbgPrint(" Link[%x]=%d\n",
+ (Link?Adapter->SelectedMedium:CurrentMedium),Link);
+#endif
+ if (Link) {
+ // a link was detected up
+ break;
+ }
+ }
+ else {
+
+ //Medium is not 100BaseTx or 10BaseT:
+ //Initialize the Mode and GEP registers
+ //and check the link status
+
+ DC21X4_WRITE_PORT(
+ DC21X4_OPERATION_MODE,
+ ((Adapter->OperationMode & ~(DC21X4_MEDIUM_MASK))
+ | Adapter->Media[CurrentMedium].Mode)
+ );
+
+ DC21X4_WRITE_PORT(
+ DC21X4_GEN_PURPOSE,
+ Adapter->Media[CurrentMedium].GeneralPurposeData
+ );
+
+ for (j=0;j<(GEP_READ_DELAY/5);j++) {
+ NdisStallExecution(5*MILLISECOND);
+ }
+
+ DC21X4_READ_PORT(
+ DC21X4_GEN_PURPOSE,
+ &Status
+ );
+
+ Link = DC21X4_LINK_STATUS(Status,Adapter,CurrentMedium);
+#if __DBG
+ DbgPrint(" Link[%x]=%d\n",CurrentMedium,Link);
+#endif
+ if (Link) {
+
+ // The link was detected up:
+ // select the current medium
+
+ Adapter->SelectedMedium = CurrentMedium;
+ Adapter->OperationMode &= ~(DC21X4_MEDIUM_MASK);
+ Adapter->OperationMode |= Adapter->Media[CurrentMedium].Mode;
+ break;
+ }
+
+ }
+
+ }
+
+ DC21X4IndicateMediaStatus(
+ Adapter,
+ Link ? LinkPass : LinkFail
+ );
+
+ if (!Link) {
+
+ //No link detected: select the default medium
+#if __DBG
+ DbgPrint("MediaDetect: No link - Select the default Medium (%x)\n",
+ Adapter->DefaultMedium);
+#endif
+ Adapter->SelectedMedium = Adapter->DefaultMedium;
+
+ Adapter->OperationMode &= ~(DC21X4_MEDIUM_MASK);
+ Adapter->OperationMode |= Adapter->Media[Adapter->SelectedMedium].Mode;
+
+ DC21X4_WRITE_PORT(
+ DC21X4_OPERATION_MODE,
+ Adapter->OperationMode
+ );
+
+ DC21X4_WRITE_PORT(
+ DC21X4_GEN_PURPOSE,
+ Adapter->Media[Adapter->SelectedMedium].GeneralPurposeData
+ );
+ }
+
+ }
+ else {
+
+ // Not AutoSense mode
+
+ if (Adapter->Media[Adapter->SelectedMedium].SenseMask) {
+
+ //Check the link status of the select medium
+
+ DC21X4_READ_PORT(
+ DC21X4_GEN_PURPOSE,
+ &Status
+ );
+
+ Link = DC21X4_LINK_STATUS(Status,Adapter,Adapter->SelectedMedium);
+ DC21X4IndicateMediaStatus(
+ Adapter,
+ Link ? LinkPass : LinkFail
+ );
+ }
+ else {
+
+ //There is no link status reported in the
+ //General Purpose Register for the selected medium:
+ //Set the LinkPass flag but do not start AutoSense
+
+ if (!Adapter->PhyPresent) {
+ DC21X4IndicateMediaStatus(Adapter,LinkPass);
+ }
+ return Adapter->PhyPresent;
+ }
+ }
+
+ // if DynamicAutoSense mode is disabled clear
+ // the AutoSense flag in MediaType to disable
+ // the medium link dynamic check but fire the
+ // Spa timer anyway to check the link status
+ // of the selected medium
+
+ if (!Adapter->DynamicAutoSense) {
+ Adapter->MediaType &= ~(MEDIA_AUTOSENSE);
+ }
+
+ return TRUE;
+
+
+ case DC21041_CFID:
+ case DC21142_CFID:
+
+ if (!(Adapter->MediaType & MEDIA_AUTOSENSE)) {
+ return Adapter->PhyPresent;
+ }
+ if (Adapter->SelectedMedium != Medium10BaseT) {
+
+ // Selected medium is 10Base2 or 10Base5
+
+ DC21X4IndicateMediaStatus(Adapter,LinkPass);
+
+ return TRUE;
+ }
+ return Adapter->PhyPresent;
+
+ case DC21040_CFID:
+
+ if (Adapter->SelectedMedium != Medium10BaseT) {
+
+ DC21X4IndicateMediaStatus(Adapter,LinkPass);
+ return FALSE;
+ }
+
+ // Selected Medium = 10BaseT:
+ // Check the TP Link status
+
+ do {
+
+ // Read the SIA satus
+
+ DC21X4_READ_PORT(
+ DC21X4_SIA_STATUS,
+ &Status
+ );
+
+#if __DBG
+ DbgPrint("Sia Status = %08x\n",Status);
+#endif
+
+ if (!(Status & DC21X4_LINKFAIL_10)) {
+#if __DBG
+ DbgPrint("MediaDetect: TP Link established\n");
+#endif
+ DC21X4IndicateMediaStatus(Adapter,LinkPass);
+ return FALSE;
+ }
+
+ if (Status & DC21X4_NETWORK_CONNECTION_ERROR) {
+#if __DBG
+ DbgPrint("MediaDetect: TP Link failure\n");
+#endif
+ break;
+ }
+
+ }
+ while ((Status & DC21X4_LINKFAIL_10)
+ && !(Status & DC21X4_NETWORK_CONNECTION_ERROR));
+
+ if (!(Adapter->MediaType & MEDIA_AUTOSENSE)) {
+
+ DC21X4IndicateMediaStatus(Adapter,LinkFail);
+ return FALSE;
+ }
+
+ // AutoSense mode: Link Pass failure
+
+#if __DBG
+ DbgPrint(" 10BaseT link failure: switch to 10Base2 \n");
+#endif
+ Adapter->SelectedMedium = Medium10Base2;
+ DC2104InitializeSiaRegisters(
+ Adapter
+ );
+
+ // wait at least 300ms for the 10Base2 transceivers
+ // to stabilize
+
+ for (i=0; i< max(Adapter->TransceiverDelay,30); i++) {
+ for (j=0;j<2;j++) {
+ NdisStallExecution(5*MILLISECOND);
+ }
+ }
+
+ //Send a minimal size packet (with an false CRC) to check
+ //the carrier status
+
+ ZERO_MEMORY (
+ Adapter->MaxTransmitBuffer[Adapter->MaxTransmitBufferIndex].Va,
+ PacketSize
+ );
+
+ MOVE_MEMORY (
+ Adapter->MaxTransmitBuffer[Adapter->MaxTransmitBufferIndex].Va,
+ Adapter->CurrentNetworkAddress,
+ ETH_LENGTH_OF_ADDRESS
+ );
+
+ MOVE_MEMORY (
+ Adapter->MaxTransmitBuffer[Adapter->MaxTransmitBufferIndex].Va + ETH_LENGTH_OF_ADDRESS,
+ Adapter->CurrentNetworkAddress,
+ ETH_LENGTH_OF_ADDRESS
+ );
+
+ TxmDescriptor = Adapter->EnqueueTransmitDescriptor;
+ Adapter->EnqueueTransmitDescriptor = (Adapter->EnqueueTransmitDescriptor)->Next;
+ Adapter->DequeueTransmitDescriptor = Adapter->EnqueueTransmitDescriptor;
+
+ // Initialize the descriptor
+
+ TxmDescriptor->Control &= DC21X4_TDES_SECOND_ADDR_CHAINED;
+ TxmDescriptor->Control |=
+ ( DC21X4_TDES_FIRST_SEGMENT | DC21X4_TDES_LAST_SEGMENT
+ | DC21X4_TDES_ADD_CRC_DISABLE | PacketSize );
+
+ TxmDescriptor->FirstBufferAddress =
+ Adapter->MaxTransmitBuffer[Adapter->MaxTransmitBufferIndex].Pa;
+
+ TxmDescriptor->Status = DESC_OWNED_BY_DC21X4;
+
+ // Mask the interrupts
+ DC21X4_WRITE_PORT(
+ DC21X4_INTERRUPT_MASK,
+ 0
+ );
+
+#if __DBG
+ DbgPrint(" send a test packet\n");
+#endif
+ DC21X4_WRITE_PORT(
+ DC21X4_TXM_POLL_DEMAND,
+ 1
+ );
+
+ // Poll for completion
+
+ Time = DC21X4_TXM_TIMEOUT;
+
+ while (--Time) {
+
+ for (j=0;j<2;j++) {
+ NdisStallExecution(5*MILLISECOND);
+ }
+
+ DC21X4_READ_PORT(
+ DC21X4_STATUS,
+ &Status
+ );
+#if __DBG
+ DbgPrint(" CSR5 = %08x Time = %d\n",Status,Time);
+#endif
+ if (Status & DC21X4_TXM_BUFFER_UNAVAILABLE) {
+ break;
+ }
+
+ }
+#if __DBG
+ DbgPrint(" Desc status = %08x Time = %d \n",TxmDescriptor->Status,Time);
+#endif
+
+ //Check if Status_Error or Timeout
+
+ if (TxmDescriptor->Status & DC21X4_TDES_ERROR_SUMMARY || (Time <= 0) ) {
+
+ //switch to AUI Port
+#if __DBG
+ DbgPrint(" 10Base2 failure: switch to 10Base5\n");
+#endif
+
+ Adapter->SelectedMedium = Medium10Base5;
+
+ //Reset the adapter to clean up the Txm path
+
+ DC21X4InitializeRegisters(
+ Adapter
+ );
+ DC2104InitializeSiaRegisters(
+ Adapter
+ );
+
+ Adapter->DequeueReceiveDescriptor =
+ (PDC21X4_RECEIVE_DESCRIPTOR)Adapter->ReceiveDescriptorRingVa;
+ Adapter->EnqueueTransmitDescriptor =
+ (PDC21X4_TRANSMIT_DESCRIPTOR)Adapter->TransmitDescriptorRingVa;
+ Adapter->DequeueTransmitDescriptor =
+ Adapter->EnqueueTransmitDescriptor;
+
+ DC21X4StartAdapter(Adapter);
+
+ }
+ else {
+
+ //Clear Txm interrupts
+
+ DC21X4_WRITE_PORT(
+ DC21X4_STATUS,
+ Status
+ );
+
+ }
+
+ //Restore the interrupt mask
+
+ DC21X4_WRITE_PORT(
+ DC21X4_INTERRUPT_MASK,
+ Adapter->InterruptMask
+ );
+
+ DC21X4IndicateMediaStatus(Adapter,LinkPass);
+ return FALSE;
+ }
+
+ return FALSE;
+}
+
+
+
+
+
+/*+
+ *
+ *DC2114Sense100BaseTxLink
+ *
+ * Routine Description:
+ *
+ * Sense the DC2114X 100BaseTx and 10BaseT link status
+ *
+ * Arguments:
+ *
+ * Adapter
+ *
+ * Return Value:
+ *
+ * Link Status
+ *
+-*/
+extern
+BOOLEAN
+DC2114Sense100BaseTxLink(
+ IN PDC21X4_ADAPTER Adapter
+ )
+
+{
+
+ ULONG Status;
+ ULONG Mode100Tx;
+ ULONG CFDA_Data;
+ INT Loop;
+ INT Retry = MAX_RETRY;
+ INT AssertionTime;
+ INT CurrentTime;
+ INT AssertionThreshold;
+ INT Timeout;
+ INT Medium10Tick;
+ INT i;
+
+ BOOLEAN Link = FALSE;
+ BOOLEAN Scrambler;
+
+#if __DBG
+ DbgPrint("Sense100BaseTxLink\n");
+#endif
+
+ // If the adapter is in Snooze mode,
+ // switch to regular mode to enable the
+ // built-in timer
+
+ if (Adapter->PciDriverArea & CFDA_SNOOZE_MODE) {
+
+ CFDA_Data = Adapter->PciDriverArea & ~CFDA_SNOOZE_MODE;
+
+ NdisWritePciSlotInformation(
+ Adapter->MiniportAdapterHandle,
+ Adapter->SlotNumber,
+ PCI_CFDA_OFFSET,
+ &CFDA_Data,
+ sizeof(CFDA_Data)
+ );
+ }
+
+ //Mask the Timer_Expired interrupt
+
+ DC21X4_WRITE_PORT(
+ DC21X4_INTERRUPT_MASK,
+ Adapter->InterruptMask & ~(DC21X4_MSK_TIMER_EXPIRED)
+ );
+
+ //Sense the 100BaseTx & 10BaseT link
+
+ Mode100Tx =
+ ( (Adapter->OperationMode & ~(DC21X4_MEDIUM_MASK))
+ | Adapter->Media[Medium100BaseTx].Mode
+ )
+ & ~(DC21X4_SCRAMBLER);
+
+ // Set the 10 Mbps timer tick
+ Medium10Tick =
+ (Adapter->Media[Medium10BaseT].Mode & DC21X4_PORT_SELECT) ?
+ MII10_TICK : EXT10_TICK;
+
+ while (Retry-- && !Link) {
+
+ //if DC21140 Rev1.1 disable the scrambler
+ Scrambler = (Adapter->RevisionNumber != DC21140_REV1_1);
+
+ Loop=2;
+ while(Loop-- && !Link) {
+
+ AssertionThreshold =
+ Scrambler? FIVE_MILLISECONDS_DELAY : ONE_SECOND_DELAY;
+
+ Timeout = (3 * AssertionThreshold);
+
+ if (Adapter->MediaCapable & MEDIUM_100BTX) {
+
+ //Select 100BaseTx
+
+ DC21X4_WRITE_PORT(
+ DC21X4_OPERATION_MODE,
+ Mode100Tx
+ | ( Scrambler ? DC21X4_SCRAMBLER : 0 )
+ );
+
+ DC21X4_WRITE_PORT(
+ DC21X4_GEN_PURPOSE,
+ Adapter->Media[Medium100BaseTx].GeneralPurposeData
+ );
+
+ // Check 100BaseTx Symbol Link for a
+ // continuous assertion of 'AssertionThreshold'
+
+ AssertionTime = 0;
+ CurrentTime = 0;
+
+ //Start the built_in timer in cyclic mode of
+ //2.5 ms ticks
+ DC21X4_WRITE_PORT(
+ DC21X4_TIMER,
+ MII100_TICK | DC21X4_TIMER_CON_MODE
+ );
+
+ while ((CurrentTime < (Timeout+1)) && !Link) {
+
+ DC21X4_READ_PORT(
+ DC21X4_STATUS,
+ &Status
+ );
+
+ if (Status & DC21X4_MSK_TIMER_EXPIRED) {
+
+ DC21X4_WRITE_PORT(
+ DC21X4_STATUS,
+ DC21X4_MSK_TIMER_EXPIRED
+ );
+ CurrentTime++;
+ }
+
+ DC21X4_READ_PORT(
+ DC21X4_GEN_PURPOSE,
+ &Status
+ );
+
+ if (DC21X4_LINK_STATUS(Status,Adapter,Medium100BaseTx)) {
+
+ // Link is asserted
+ if (AssertionTime == 0 ) {
+ //First assertion
+ AssertionTime = CurrentTime+1;
+ }
+ else {
+ Link = ((CurrentTime - AssertionTime) >= AssertionThreshold);
+ }
+ }
+ else {
+ // No link
+ AssertionTime = 0;
+ }
+ }
+
+ //Stop the built_in timer
+
+ DC21X4_WRITE_PORT(
+ DC21X4_TIMER,
+ 0
+ );
+
+ DC21X4_WRITE_PORT(
+ DC21X4_STATUS,
+ DC21X4_MSK_TIMER_EXPIRED
+ );
+
+ if (Link) {
+
+ // 100BaseTx link detected: Select 100BaseTx
+
+ Adapter->SelectedMedium = Medium100BaseTx;
+
+ Adapter->OperationMode &= ~(DC21X4_MEDIUM_MASK);
+ Adapter->OperationMode |= Adapter->Media[Medium100BaseTx].Mode;
+
+ if (!Scrambler) {
+
+ //Turn the scrambler on
+
+ DC21X4_WRITE_PORT(
+ DC21X4_OPERATION_MODE,
+ Adapter->OperationMode
+ );
+ }
+
+ break;
+
+ }
+
+ }
+
+ // No 100BaseTx link detected:
+
+ if (Adapter->MediaCapable & MEDIUM_10BT) {
+
+ // Switch to 10BaseT
+
+ DC21X4_WRITE_PORT(
+ DC21X4_OPERATION_MODE,
+ (Adapter->OperationMode &~(DC21X4_MEDIUM_MASK))
+ | Adapter->Media[Medium10BaseT].Mode
+ );
+
+ DC21X4_WRITE_PORT(
+ DC21X4_GEN_PURPOSE,
+ Adapter->Media[Medium10BaseT].GeneralPurposeData
+ );
+
+ //Check the 10BaseT link status
+
+ // Start the built_in timer for
+ // half the 100BaseTx timeout
+
+ DC21X4_WRITE_PORT(
+ DC21X4_TIMER,
+ (Timeout/2) * Medium10Tick
+ );
+
+ while (!Link) {
+
+ //Check the 10BaseT link
+
+ for (i=0,Link=TRUE; i<2; i++) {
+
+ DC21X4_READ_PORT(
+ DC21X4_GEN_PURPOSE,
+ &Status
+ );
+ Link = Link && DC21X4_LINK_STATUS(Status,Adapter,Medium10BaseT);
+ }
+
+ DC21X4_READ_PORT(
+ DC21X4_STATUS,
+ &Status
+ );
+
+ if (Status & DC21X4_MSK_TIMER_EXPIRED) {
+ break;
+ }
+ }
+
+ }
+
+ if (Link) {
+
+ // 10BaseT link detected:
+
+ //Stop the timer
+
+ DC21X4_WRITE_PORT(
+ DC21X4_TIMER,
+ 0
+ );
+
+ DC21X4_WRITE_PORT(
+ DC21X4_STATUS,
+ DC21X4_MSK_TIMER_EXPIRED
+ );
+
+ if (Loop) {
+
+ // first detection of 10BT link:
+ // check the 100BaseTx link again to reject
+ // a 'false' 10BT link link induced by the 100BTX
+ Link = FALSE;
+ }
+ else {
+
+ // 10BT link detected twice:
+ // select Medium10BaseT
+
+ Adapter->SelectedMedium = Medium10BaseT;
+
+ Adapter->OperationMode &= ~(DC21X4_MEDIUM_MASK);
+ Adapter->OperationMode |= Adapter->Media[Medium10BaseT].Mode;
+ }
+ }
+ else if (Loop) {
+
+ if (Scrambler) {
+
+ //Disable the scrambler and restart the
+ //link check
+ Scrambler = FALSE;
+ Loop = 2;
+ }
+ else {
+
+ // First loop & Scrambler disbled:
+ // leave the loop and select the default medium
+ Retry = 0;
+ break;
+ }
+ }
+
+ } // endwhile Loop
+
+ } //endwhile Retry
+
+
+ //Demask the Timer_Expired interrupt
+
+ DC21X4_WRITE_PORT(
+ DC21X4_STATUS,
+ DC21X4_MSK_TIMER_EXPIRED
+ );
+
+ DC21X4_WRITE_PORT(
+ DC21X4_INTERRUPT_MASK,
+ Adapter->InterruptMask
+ );
+
+ if (Adapter->PciDriverArea & CFDA_SNOOZE_MODE) {
+
+ //set to the initial snooze mode
+
+ NdisWritePciSlotInformation(
+ Adapter->MiniportAdapterHandle,
+ Adapter->SlotNumber,
+ PCI_CFDA_OFFSET,
+ &Adapter->PciDriverArea,
+ sizeof(Adapter->PciDriverArea)
+ );
+ }
+
+#if __DBG
+ if (Link)
+ DbgPrint("Sense: SelectMedium = %s\n",
+ Adapter->SelectedMedium==Medium100BaseTx?"100BaseTx":"10BaseT");
+#endif
+
+ return Link;
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*+
+ * DC21X4DynamicAutoSense
+ *
+ * Routine Description:
+ *
+ * Autosense between the PHY's Autosense routine and the
+ * other media autosense's routine
+ *
+ * Arguments:
+ *
+ * Adapter
+ *
+-*/
+extern
+VOID
+DC21X4DynamicAutoSense (
+ IN PVOID Systemspecific1,
+ IN PDC21X4_ADAPTER Adapter,
+ IN PVOID Systemspecific2,
+ IN PVOID Systemspecific3
+ )
+{
+
+ BOOLEAN LinkStatus=FALSE;
+ BOOLEAN StartTimer=TRUE;
+ BOOLEAN LoopbackMode;
+
+#if _DBG
+ DbgPrint("DC21X4DynamicAutoSense\n");
+#endif
+
+ if ( (Adapter->PhyPresent)
+ && (!Adapter->Force10)
+ ){
+ LinkStatus = DC21X4MiiAutoSense(Adapter);
+ }
+
+ if (Adapter->Indicate10BTLink) {
+
+ Adapter->Indicate10BTLink = FALSE;
+
+ if (!LinkStatus) {
+
+ // The current link is a 10BaseT link
+
+#if 0
+ DC21X4SetPhyControl(
+ Adapter,
+ (USHORT)MiiGenAdminIsolate
+ );
+#endif
+
+ DC21X4SetPhyControl(
+ Adapter,
+ (USHORT)((Adapter->OperationMode & DC21X4_FULL_DUPLEX_MODE) ?
+ MiiGenAdminForce10Fd : MiiGenAdminForce10)
+ );
+
+ DC21X4IndicateMediaStatus(Adapter,LinkPass);
+ }
+ }
+
+ if ( !LinkStatus
+ && (Adapter->MediaCapable)
+ ) {
+ StartTimer = DC21X4AutoSense(Adapter);
+ }
+
+ // Restart the Autosense timer
+
+ if (StartTimer) {
+
+ DC21X4StartAutoSenseTimer(
+ Adapter,
+ (UINT)((Adapter->PhyPresent) ? DC21X4_MII_TICK : DC21X4_SPA_TICK)
+ );
+
+ }
+
+}
+
+
+/*+
+ * DC21X4AutoSense
+ *
+ * Routine Description:
+ *
+ * Autosense the DC21041 10Base2/10Base5 port
+ * Autosense the DC21140 100BaseTx/10BaseT link
+ *
+ * Arguments:
+ *
+ * Adapter
+ *
+ * Return:
+ *
+ * TRUE if AutoSense Timer should be fired
+ *
+-*/
+extern
+BOOLEAN
+DC21X4AutoSense (
+ IN PDC21X4_ADAPTER Adapter
+ )
+{
+ ULONG Status;
+ BOOLEAN SelectedPortActive;
+ BOOLEAN SwitchMedium;
+ BOOLEAN FullDuplex;
+
+ INT CurrentMedium=0;
+ INT NextMedium;
+ INT index;
+
+#if _DBG
+ DbgPrint("Autosense routine\n");
+#endif
+
+ switch (Adapter->DeviceId) {
+
+ case DC21040_CFID:
+
+ if (Adapter->LinkStatus != LinkFail) {
+ return FALSE;
+ }
+
+ //DC21040 supports Link_Fail interrupt
+ //but does not support Link_Pass
+ //Check the Link status:
+ //If link is up wait for Link_Fail interrupt
+ //otherwhise poll the link status
+
+ DC21X4_READ_PORT(
+ DC21X4_SIA_STATUS,
+ &Status
+ );
+
+ if ((Status & DC21X4_LINKFAIL_10) == 0) {
+ DC21X4IndicateMediaStatus(Adapter,LinkPass);
+ return FALSE;
+ }
+ break;
+
+ case DC21041_CFID:
+ case DC21142_CFID:
+ if (!(Adapter->MediaType & MEDIA_AUTOSENSE)) {
+ return Adapter->PhyPresent;
+ }
+
+ if (Adapter->IgnoreTimer) {
+ Adapter->IgnoreTimer = FALSE;
+ return FALSE;
+ }
+
+ switch (Adapter->TimerFlag) {
+
+ case AncPolling:
+
+ if (Adapter->PollCount--) {
+
+ //Read the SIA Status
+
+ DC21X4_READ_PORT(
+ DC21X4_SIA_STATUS,
+ &Status
+ );
+
+ //check the AutoNegotation State
+
+ switch (Status & DC21X4_AUTO_NEGOTIATION_STATE) {
+
+ case ANS_ACKNOWLEDGE_DETECTED:
+ case ANS_ACKNOWLEDGE_COMPLETED:
+
+ //store the Sia status snapshot
+ Adapter->SiaStatus = Status;
+
+ default:
+
+ // Restart the Poll timer
+ NdisMSetTimer(
+ &Adapter->Timer,
+ DC21X4_POLL_DELAY
+ );
+ return FALSE;
+
+ case ANS_AUTO_NEGOTIATION_COMPLETED:
+
+ //Check the Link Partner capabilities
+
+ // LPN SF 10BT_FD 10BT Link_Partner Medium
+ // 0 xx x x not_negotiable 10BT
+ // 1 01 1 x 10BT_FD capable 10BT_FD
+ // 1 01 0 1 10BT_HD capable 10BT
+ // 1 01 0 0 no_common_mode 10B2/5
+ // 1 !01 x x no_common_mode 10B2/5
+
+ if (!(Status & DC21X4_LINK_PARTNER_NEGOTIABLE)) {
+#if __DBG
+ DbgPrint("Link Partner not negotiable\n");
+#endif
+ if (++Adapter->AutoNegotiationCount < 2) {
+
+
+ //Fire the Restart AutoNegotation Timer
+ // to defer the restart of the auto_negotiation
+
+ Adapter->TimerFlag=DeferredAnc;
+ NdisMSetTimer(
+ &Adapter->Timer,
+ DC21X4_ANC_DELAY
+ );
+
+ return FALSE;
+
+ }
+ else {
+ NextMedium = Medium10BaseT;
+ FullDuplex=FALSE;
+ }
+ }
+
+ else {
+
+ // Link Partner negotiable
+
+ if (!Adapter->SiaStatus) {
+
+ //Restart the AutoNegotiation
+
+ //Reinitialize the Poll timeout counter
+ Adapter->PollCount= POLL_COUNT_TIMEOUT;
+
+ DC21X4_WRITE_PORT(
+ DC21X4_SIA_STATUS,
+ DC21X4_RESTART_AUTO_NEGOTIATION
+ );
+
+ //Restart the Poll timer to
+ //poll on AutoNegotiation State
+
+ Adapter->TimerFlag=AncPolling;
+ NdisMSetTimer(
+ &Adapter->Timer,
+ DC21X4_POLL_DELAY
+ );
+
+ return FALSE;
+
+ }
+ else if ((Adapter->SiaStatus & DC21X4_SELECTED_FIELD_MASK) != DC21X4_SELECTED_FIELD) {
+ NextMedium=Medium10Base2_5;
+ FullDuplex=FALSE;
+ }
+ else if (Adapter->SiaStatus & DC21X4_LINK_PARTNER_10BT_FD) {
+ //10BT Full Duplex capable
+ NextMedium=Medium10BaseT;
+ FullDuplex=TRUE;
+ }
+ else if (Adapter->SiaStatus & DC21X4_LINK_PARTNER_10BT) {
+ //10BT Half Duplex capable
+ NextMedium=Medium10BaseT;
+ FullDuplex=FALSE;
+ }
+ else {
+ //no common mode
+ NextMedium=Medium10Base2_5;
+ FullDuplex=FALSE;
+ }
+ }
+ }
+ }
+ else {
+ //poll timeout
+ NextMedium = Medium10Base2_5;
+ FullDuplex=FALSE;
+ }
+
+ Adapter->TimerFlag = NoTimer;
+
+ //Reinitialize the Sia status snapshot
+ Adapter->SiaStatus = 0;
+
+ if (!FullDuplex) {
+ // Stop the Receiver and Transmitter to
+ // reset the Full_duplex mode
+ DC21X4StopReceiverAndTransmitter(
+ Adapter
+ );
+
+ Adapter->OperationMode &= ~(DC21X4_FULL_DUPLEX_MODE);
+ }
+
+
+ // Switch to the selected medium
+
+ Adapter->NwayEnabled=FALSE;
+
+ if (NextMedium == Medium10Base2_5) {
+
+ DC21X4SwitchMedia(
+ Adapter,
+ Medium10Base2_5
+ );
+ }
+ else {
+
+ //10BaseT: Disable NWAY
+
+ DC21X4_WRITE_PORT(
+ DC21X4_SIA_MODE_1,
+ Adapter->Media[Medium10BaseT].SiaRegister[1]
+ );
+
+ DC21X4IndicateMediaStatus(Adapter,LinkPass);
+
+ }
+
+ if (!FullDuplex) {
+
+ //Restart the Receiver and Transmitter
+ DC21X4_WRITE_PORT(
+ DC21X4_OPERATION_MODE,
+ Adapter->OperationMode
+ );
+ }
+ return FALSE;
+
+ case DeferredAnc:
+
+ //Restart the AutoNegotiation
+
+ //Reinitialize the Poll timeout counter
+ Adapter->PollCount= POLL_COUNT_TIMEOUT;
+ Adapter->SiaStatus = 0;
+
+
+ DC21X4_WRITE_PORT(
+ DC21X4_SIA_STATUS,
+ DC21X4_RESTART_AUTO_NEGOTIATION
+ );
+
+ //Restart the Poll timer to
+ //poll on AutoNegotiation State
+
+ Adapter->TimerFlag=AncPolling;
+ NdisMSetTimer(
+ &Adapter->Timer,
+ DC21X4_POLL_DELAY
+ );
+
+ return FALSE;
+
+
+ case AncTimeout:
+
+ // AutoNegotiation timeout:
+ Adapter->TimerFlag = NoTimer;
+
+ if (Adapter->MediaType & MEDIA_AUTOSENSE) {
+
+ // Switch medium from 10BaseT
+ DC21X4SwitchMedia(
+ Adapter,
+ Medium10Base2_5
+ );
+ }
+ return FALSE;
+
+
+ case DeferredLinkCheck:
+
+ Adapter->TimerFlag = NoTimer;
+
+ //Check the 10BaseT Link Status
+
+ DC21X4_READ_PORT(
+ DC21X4_SIA_STATUS,
+ &Status
+ );
+
+ if ((Status & DC21X4_LINK_PASS_MASK) == DC21X4_LINK_PASS_STATUS) {
+
+ //Link Pass:
+
+ if (Adapter->SelectedMedium == Medium10BaseT) {
+
+ //10BaseT link is up
+ DC21X4IndicateMediaStatus(Adapter,LinkPass);
+ return Adapter->PhyPresent;
+ }
+ else {
+
+ //Switch the medium to 10BaseT and start the
+ //Anc Timer to timeout if the Nway Autonegotiation
+ //does not complete
+ Adapter->TimerFlag = AncTimeout;
+ NdisMSetTimer(
+ &Adapter->Timer,
+ DC21X4_ANC_TIMEOUT
+ );
+ DC21X4SwitchMedia(
+ Adapter,
+ Medium10BaseT
+ );
+ return FALSE;
+ }
+ }
+ else {
+
+ // No 10baseT link:
+ // If the current Medium is not 10BaseT,
+ //ignore this state and enters the Selected_Port_Active check
+ //instead
+ if (Adapter->SelectedMedium == Medium10BaseT) {
+
+ if (Adapter->MediaType & MEDIA_AUTOSENSE) {
+
+ // Switch medium from 10BaseT
+ DC21X4SwitchMedia(
+ Adapter,
+ Medium10Base2_5
+ );
+ }
+ return FALSE;
+ }
+ }
+
+ case SpaTimer:
+
+ //Selected_Port_Active (10Base2/10Base5 media) periodic check
+
+ if (Adapter->SelectedMedium == Medium10BaseT) {
+ break;
+ }
+
+ if ((Adapter->MediaCapable & (MEDIUM_10B2 | MEDIUM_10B5)) !=
+ (MEDIUM_10B2 | MEDIUM_10B5)) {
+
+ //The board does not support both 10Base2 & 10Base5 ports
+ break;
+ }
+
+ // Read the Selected_Port_Active Status
+
+ DC21X4_READ_PORT(
+ DC21X4_SIA_STATUS,
+ &Status
+ );
+
+ SelectedPortActive = ((Status & DC21X4_SELECTED_PORT_ACTIVE) != 0);
+
+#if __DBG
+ DbgPrint("Autosense: SelectePortActive=%d Nocarrier=%d ExcessColl=%d\n",
+ SelectedPortActive,
+ Adapter->NoCarrierCount,
+ Adapter->ExcessCollisionsCount);
+#endif
+ if ( (!SelectedPortActive)
+ || (Adapter->NoCarrierCount >= NO_CARRIER_THRESHOLD)
+ || (Adapter->ExcessCollisionsCount >= EXCESS_COLLISIONS_THRESHOLD)
+ ) {
+
+ //Switch medium port
+ Adapter->SelectedMedium = (Adapter->SelectedMedium == Medium10Base2) ?
+ Medium10Base5 : Medium10Base2;
+#if __DBG
+ DbgPrint("Autosense: Switch Media to %s\n",
+ MediumString[Adapter->SelectedMedium]);
+#endif
+ DC21X4_WRITE_PORT(
+ DC21X4_SIA_MODE_2,
+ Adapter->Media[Adapter->SelectedMedium].SiaRegister[2]
+ );
+
+ //reset the NoCarrier and ExcessCollisions counters
+
+ Adapter->NoCarrierCount = 0;
+ Adapter->ExcessCollisionsCount = 0;
+ }
+
+ // clear the SPA flag into the Sia Status register:
+
+ DC21X4_WRITE_PORT(
+ DC21X4_SIA_STATUS,
+ DC21X4_SELECTED_PORT_ACTIVE
+ );
+
+ break;
+
+ case NoTimer:
+
+ return FALSE;
+
+ }
+ break;
+
+ case DC21140_CFID:
+
+ if (!Adapter->Media[Adapter->SelectedMedium].SenseMask) {
+ DC21X4IndicateMediaStatus(Adapter,LinkPass);
+ return Adapter->PhyPresent;
+ }
+
+ if ( (!(Adapter->MediaType & MEDIA_AUTOSENSE))
+ && (Adapter->PhyPresent)
+ ) {
+ return TRUE;
+ }
+
+ //Check the Link status
+
+ DC21X4_READ_PORT(
+ DC21X4_GEN_PURPOSE,
+ &Status
+ );
+
+ DC21X4IndicateMediaStatus(
+ Adapter,
+ DC21X4_LINK_STATUS(Status,Adapter,Adapter->SelectedMedium) ?
+ LinkPass : LinkFail
+ );
+
+ if (Adapter->MediaType & MEDIA_AUTOSENSE) {
+
+ //Check the link status of every medium supported
+ //by the adapter
+
+ for (index=Adapter->MediaCount; index>0; index--) {
+
+ CurrentMedium = Adapter->MediaPrecedence[index-1];
+
+ if (DC21X4_LINK_STATUS(Status,Adapter,CurrentMedium)) {
+ break;
+ }
+ }
+
+ if (index > 0) {
+
+ // A link was detected,switch to this medium if:
+ // current > selected (a medium link of higher precedence is up
+ // current < selected (selected medium link is down)
+
+ SwitchMedium = (CurrentMedium != Adapter->SelectedMedium);
+ }
+ else {
+
+ // no link detected:
+ // switch to the default medium if defined and different
+ // of the selected medium
+ // otherwise stay with the selected medium
+
+ CurrentMedium = Adapter->DefaultMedium;
+ SwitchMedium = Adapter->DefaultMediumFlag
+ && (Adapter->SelectedMedium != Adapter->DefaultMedium);
+
+ }
+
+ if (SwitchMedium) {
+#if __DBG
+ DbgPrint("Autosense: 21140 - Switch Medium to %s\n",
+ MediumString[CurrentMedium]);
+#endif
+
+ DC21X4SwitchMedia(
+ Adapter,
+ CurrentMedium
+ );
+
+ DC21X4_READ_PORT(
+ DC21X4_GEN_PURPOSE,
+ &Status
+ );
+#if __DBG
+ DbgPrint("Autosense 21140: Link=%s\n",
+ Adapter->LinkStatus ? "UP":"DOWN");
+#endif
+ }
+
+ }
+ break;
+ }
+
+ return TRUE;
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*++
+ *
+ * DC21X4SwitchMedia
+ *
+ * Routine Description:
+ *
+ * This routine switches DC21X4's media ports
+ *
+ * Arguments:
+ *
+ * Adapter
+ * NewMedium : the new medium to switch to
+ *
+ * Return Value:
+ *
+ * None
+ *
+-*/
+extern
+VOID
+DC21X4SwitchMedia(
+ IN PDC21X4_ADAPTER Adapter,
+ IN LONG NewMedium
+ )
+{
+
+ ULONG Status;
+ BOOLEAN SpaTimer=FALSE;
+ ULONG FullDuplex=0;
+ UINT j;
+
+#if __DBG
+ DbgPrint("DC21X4SwitchMedia [->%x]\n",NewMedium);
+#endif
+
+ DC21X4IndicateMediaStatus(Adapter,LinkFail);
+
+ switch (Adapter->DeviceId) {
+
+
+
+ case DC21142_CFID:
+ case DC21041_CFID:
+
+ switch (NewMedium) {
+
+
+ case Medium10BaseT:
+#if __DBG
+ DbgPrint("Medium = %s %s \n",
+ MediumString[NewMedium],
+ FullDuplex ? "Full_Duplex" : "");
+#endif
+ Adapter->SelectedMedium = NewMedium;
+ DC2104InitializeSiaRegisters(Adapter);
+ return;
+
+ case Medium10BaseTNway:
+#if __DBG
+ DbgPrint("Medium = 10BaseT - Nway enabled\n");
+#endif
+ NewMedium &= MEDIA_MASK;
+ Adapter->SelectedMedium = NewMedium;
+ Adapter->NwayEnabled=TRUE;
+
+ //Stop the Receiver and the Transmitter
+ DC21X4StopReceiverAndTransmitter(Adapter);
+
+ //enable Nway
+ Adapter->Media[Medium10BaseT].SiaRegister[1] |= DC21X4_NWAY_ENABLED;
+
+ DC2104InitializeSiaRegisters(Adapter);
+
+ Adapter->Media[Medium10BaseT].SiaRegister[1] &= ~(DC21X4_NWAY_ENABLED);
+
+ //Restart the Receiver and Transmitter in Full Duplex mode
+ Adapter->OperationMode |= DC21X4_FULL_DUPLEX_MODE;
+
+ DC21X4_WRITE_PORT(
+ DC21X4_OPERATION_MODE,
+ Adapter->OperationMode
+ );
+
+ return;
+
+ case Medium10Base2:
+
+ //switch medium to 10Base2
+ SpaTimer = (Adapter->MediaCapable & MEDIUM_10B5);
+ break;
+
+ case Medium10Base5:
+
+ //switch medium to 10Base5
+ SpaTimer = (Adapter->MediaCapable & MEDIUM_10B2);
+ break;
+
+ case Medium10Base2_5:
+
+ switch (Adapter->MediaCapable & (MEDIUM_10B2 | MEDIUM_10B5)) {
+
+ case (MEDIUM_10B2 | MEDIUM_10B5) :
+
+ // 10Base2 & 10Base5 ports are both populated:
+ // if Non_Selected_Port_Active select 10Base5
+ // otherwise select 10Base2
+
+ DC21X4_READ_PORT(
+ DC21X4_SIA_STATUS,
+ &Status
+ );
+
+ NewMedium = (Status & DC21X4_NON_SELECTED_PORT_ACTIVE) ?
+ Medium10Base5 : Medium10Base2;
+
+ SpaTimer = TRUE;
+ break;
+
+ case MEDIUM_10B2 :
+
+ // 10Base2 port only is populated:
+ NewMedium = Medium10Base2;
+ break;
+
+ case MEDIUM_10B5 :
+
+ // 10Base5 port only is populated
+ NewMedium = Medium10Base5;
+ break;
+
+ default:
+
+ if (Adapter->PhyPresent) {
+
+ //Start the AutoSense Timer to poll the PHY Link
+ DC21X4StartAutoSenseTimer(
+ Adapter,
+ (UINT)DC21X4_MII_TICK
+ );
+ }
+ return;
+
+ }
+
+ }
+
+#if __DBG
+ DbgPrint("Medium = %s %s\n",
+ MediumString[NewMedium],
+ Adapter->Media[NewMedium].SiaRegister[1] & DC21X4_AUTO_NEGOTIATION_ENABLE ?
+ "- NWAY Enabled" : "");
+#endif
+
+ Adapter->SelectedMedium=NewMedium;
+
+ DC2104InitializeSiaRegisters(Adapter);
+ DC21X4IndicateMediaStatus(Adapter,LinkPass);
+
+ if (SpaTimer || Adapter->PhyPresent) {
+#if __DBG
+ DbgPrint("Start the AutoSense timer\n");
+#endif
+ //Reset the NoCarrier and ExcessCollisions counters
+
+ Adapter->NoCarrierCount = 0;
+ Adapter->ExcessCollisionsCount = 0;
+
+ //Start the AutoSense Timer
+ DC21X4StartAutoSenseTimer(
+ Adapter,
+ (UINT)((Adapter->PhyPresent) ? DC21X4_MII_TICK : DC21X4_SPA_TICK)
+ );
+
+ }
+ break;
+
+
+ case DC21140_CFID:
+
+ // Switch medium:
+ // Reload GEP and OperationMode registers
+
+ Adapter->OperationMode &= ~(DC21X4_MEDIUM_MASK);
+ Adapter->OperationMode |= Adapter->Media[NewMedium].Mode;
+
+ Adapter->SelectedMedium = NewMedium;
+
+ DC21X4_WRITE_PORT(
+ DC21X4_GEN_PURPOSE,
+ Adapter->Media[NewMedium].GeneralPurposeData
+ );
+
+ DC21X4_WRITE_PORT(
+ DC21X4_OPERATION_MODE,
+ Adapter->OperationMode
+ );
+
+ for (j=0;j<(GEP_READ_DELAY/5);j++) {
+ NdisStallExecution(5*MILLISECOND);
+ }
+
+ DC21X4_READ_PORT(
+ DC21X4_GEN_PURPOSE,
+ &Status
+ );
+
+ DC21X4IndicateMediaStatus(
+ Adapter,
+ DC21X4_LINK_STATUS(Status,Adapter,Adapter->SelectedMedium) ?
+ LinkPass : LinkFail
+ );
+
+ return;
+
+ }
+
+}
+ /*++
+ *
+ * DC21X4StartAutoSenseTimer
+ *
+ * Routine Description:
+ *
+ * Start the AutoSense Timer
+ *
+ * Arguments:
+ *
+ * Adapter
+ *
+ * Return Value:
+ *
+ * None
+ *
+-*/
+extern
+VOID
+DC21X4StartAutoSenseTimer(
+ IN PDC21X4_ADAPTER Adapter,
+ IN UINT Value
+ )
+{
+
+
+ Adapter->TimerFlag=SpaTimer;
+
+ NdisMSetTimer(
+ &Adapter->Timer,
+ Value
+ );
+
+}
+
+/*++
+ *
+ * DC21X4StopAutoSenseTimer
+ *
+ * Routine Description:
+ *
+ * Stop the AutoSense Timer
+ *
+ * Arguments:
+ *
+ * Adapter
+ *
+ * Return Value:
+ *
+ * None
+ *
+-*/
+extern
+VOID
+DC21X4StopAutoSenseTimer(
+ IN PDC21X4_ADAPTER Adapter
+ )
+{
+ BOOLEAN Canceled;
+
+ Adapter->TimerFlag = NoTimer;
+
+ NdisMCancelTimer(
+ &Adapter->Timer,
+ &Canceled
+ );
+
+ Adapter->IgnoreTimer = !Canceled;
+
+}
+
+
+
+/*+
+ * DC21X4EnableNway
+ *
+ * Routine Description:
+ *
+ * Enable the Nway Negotiation
+ *
+ * Arguments:
+ *
+ * Adapter - The adapter in question.
+ *
+ * Return Value:
+ *
+ * None
+ *
+-*/
+extern
+VOID
+DC21X4EnableNway(
+ IN PDC21X4_ADAPTER Adapter
+ )
+{
+
+ULONG Mask;
+
+#if __DBG
+ DbgPrint("Enable Nway Negotiation\n");
+#endif
+
+ switch (Adapter->DeviceId) {
+
+ case DC21041_CFID:
+
+ switch (Adapter->RevisionNumber) {
+
+ case DC21041_REV2_0:
+ if (Adapter->NwayProtocol) {
+ Adapter->MediaNway = TRUE;
+ Adapter->LinkHandlerMode=NwayWorkAround;
+ break;
+ }
+ case DC21041_REV1_1:
+ case DC21041_REV1_0:
+
+ Adapter->MediaNway = FALSE;
+ Adapter->LinkHandlerMode=NoNway;
+ break;
+
+ default:
+
+ Adapter->MediaNway = TRUE;
+ Adapter->LinkHandlerMode=Nway;
+
+ Adapter->Media[Medium10BaseT].SiaRegister[1] |= DC21X4_NWAY_ENABLED;
+ Adapter->Media[Medium10Base2].SiaRegister[1] |= DC21X4_NWAY_ENABLED;
+ Adapter->Media[Medium10Base5].SiaRegister[1] |= DC21X4_NWAY_ENABLED;
+
+ Adapter->Media[Medium10BaseT].Mode |= DC21X4_FULL_DUPLEX_MODE;
+ Adapter->Media[Medium10Base2].Mode |= DC21X4_FULL_DUPLEX_MODE;
+ Adapter->Media[Medium10Base5].Mode |= DC21X4_FULL_DUPLEX_MODE;
+ }
+ break;
+
+ case DC21142_CFID:
+
+ switch (Adapter->RevisionNumber) {
+
+ case DC21142_REV1_0:
+ case DC21142_REV1_1:
+
+ if (Adapter->NwayProtocol) {
+ Adapter->MediaNway = TRUE;
+ Adapter->LinkHandlerMode=NwayWorkAround;
+ }
+ else {
+ Adapter->MediaNway = FALSE;
+ Adapter->LinkHandlerMode=NoNway;
+ }
+ break;
+
+ default:
+
+ Adapter->MediaNway = TRUE;
+ Adapter->LinkHandlerMode=Nway;
+
+ Adapter->Media[Medium10BaseT].SiaRegister[1] |= DC21X4_NWAY_ENABLED;
+ Adapter->Media[Medium10Base2].SiaRegister[1] |= DC21X4_NWAY_ENABLED;
+ Adapter->Media[Medium10Base5].SiaRegister[1] |= DC21X4_NWAY_ENABLED;
+
+ Adapter->Media[Medium10BaseT].Mode |= DC21X4_FULL_DUPLEX_MODE;
+ Adapter->Media[Medium10Base2].Mode |= DC21X4_FULL_DUPLEX_MODE;
+ Adapter->Media[Medium10Base5].Mode |= DC21X4_FULL_DUPLEX_MODE;
+
+ }
+
+ break;
+
+
+ }
+
+}
+
+
+/*+
+ * DC21X4DisableNway
+ *
+ * Routine Description:
+ *
+ * Disable the Nway Negotiation
+ *
+ * Arguments:
+ *
+ * Adapter - The adapter in question.
+ *
+ * Return Value:
+ *
+ * None
+ *
+-*/
+extern
+VOID
+DC21X4DisableNway(
+ IN PDC21X4_ADAPTER Adapter
+ )
+{
+
+#if __DBG
+ DbgPrint("Disable Nway Negotiation\n");
+#endif
+
+ Adapter->MediaNway = FALSE;
+ Adapter->LinkHandlerMode=NoNway;
+
+ switch (Adapter->DeviceId) {
+
+ case DC21041_CFID:
+ case DC21142_CFID:
+ Adapter->Media[Medium10BaseT].SiaRegister[1] &= ~DC21X4_NWAY_ENABLED;
+ Adapter->Media[Medium10Base2].SiaRegister[1] &= ~DC21X4_NWAY_ENABLED;
+ Adapter->Media[Medium10Base5].SiaRegister[1] &= ~DC21X4_NWAY_ENABLED;
+
+ Adapter->Media[Medium10BaseT].Mode &= ~DC21X4_FULL_DUPLEX_MODE;
+ Adapter->Media[Medium10Base2].Mode &= ~DC21X4_FULL_DUPLEX_MODE;
+ Adapter->Media[Medium10Base5].Mode &= ~DC21X4_FULL_DUPLEX_MODE;
+
+ break;
+
+
+ }
+
+}
+
+
+
+/*++
+ *
+ * DC21X4IndicateMediaStatus
+ *
+ * Routine Description:
+ *
+ * Indicate the media status
+ *
+ * Arguments:
+ *
+ * Adapter
+ *
+ * Return Value:
+ *
+ * None
+ *
+-*/
+extern
+VOID
+DC21X4IndicateMediaStatus(
+ IN PDC21X4_ADAPTER Adapter,
+ IN UINT Status
+ )
+{
+
+ ULONG LinkPartner;
+
+ Adapter->LinkStatus=Status;
+
+ if (Status != Adapter->PreviousLinkStatus) {
+
+ switch (Adapter->LinkStatus) {
+
+#if __DBG
+ case LinkFail:
+ DbgPrint("IndicateMediaStatus: Link FAIL\n");
+ break;
+#endif
+
+ case LinkPass:
+
+ switch (Adapter->SelectedMedium) {
+
+ case Medium100BaseTx:
+ case Medium100BaseT4:
+ case Medium100BaseFx:
+
+ Adapter->LinkSpeed = ONE_HUNDRED_MBPS;
+ break;
+
+ default:
+
+ Adapter->LinkSpeed = TEN_MBPS;
+ break;
+ }
+
+ if (Adapter->MediaNway) {
+
+ //Nway: read the Link Partner Ability to check
+ // Half/Full Duplex link mode
+
+ DC21X4_READ_PORT(
+ DC21X4_SIA_STATUS,
+ &LinkPartner
+ );
+
+ Adapter->FullDuplexLink =
+ LinkPartner & (DC21X4_LINK_PARTNER_10BT_FD) ?
+ TRUE : FALSE ;
+ }
+ else {
+ Adapter->FullDuplexLink =
+ (Adapter->MediaType & MEDIA_FULL_DUPLEX) != 0;
+ }
+
+#if __DBG
+ DbgPrint("IndicateMediaStatus: %s%s Link PASS\n",
+ MediumString[Adapter->SelectedMedium],
+ Adapter->FullDuplexLink ? " Full_Duplex" : "");
+#endif
+ break;
+
+ case MiiLinkPass:
+
+ Adapter->LinkSpeed = TEN_MBPS;
+ Adapter->FullDuplexLink = FALSE;
+
+ switch (Adapter->MiiMediaType & MEDIA_MASK) {
+
+ case MediumMii10BaseTFd:
+
+ Adapter->FullDuplexLink = TRUE;
+ break;
+
+ case MediumMii100BaseTxFd:
+ case MediumMii100BaseFxFd:
+
+ Adapter->FullDuplexLink = TRUE;
+
+ case MediumMii100BaseTx:
+ case MediumMii100BaseT4:
+ case MediumMii100BaseFx:
+
+ Adapter->LinkSpeed = ONE_HUNDRED_MBPS;
+ break;
+ }
+#if __DBG
+ DbgPrint("IndicateMediaStatus: %s%s MiiLink PASS\n",
+ MediumString[Adapter->MiiMediaType & MEDIA_MASK],
+ Adapter->FullDuplexLink ? " Full_Duplex" : "");
+#endif
+ break;
+ }
+
+ if (Adapter->FullDuplexLink) {
+ Adapter->TransmitDescriptorErrorMask &=
+ ~(DC21X4_TDES_NO_CARRIER | DC21X4_TDES_LOSS_OF_CARRIER);
+ }
+ else {
+ Adapter->TransmitDescriptorErrorMask =
+ Adapter->TransmitDefaultDescriptorErrorMask;
+ }
+
+ if (!Adapter->Initializing) {
+ NdisMIndicateStatus (
+ Adapter->MiniportAdapterHandle,
+ (Status == LinkFail ? NDIS_STATUS_MEDIA_DISCONNECT : NDIS_STATUS_MEDIA_CONNECT),
+ NULL,
+ 0
+ );
+ }
+
+ Adapter->PreviousLinkStatus = Status;
+
+ }
+
+}
+
+
diff --git a/private/ntos/ndis/dc21x4/mii.h b/private/ntos/ndis/dc21x4/mii.h
new file mode 100644
index 000000000..aae0f7b9f
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/mii.h
@@ -0,0 +1,453 @@
+/*+
+ * file: mii.h
+ *
+ * Copyright (C) 1992-1995 by
+ * Digital Equipment Corporation, Maynard, Massachusetts.
+ * All rights reserved.
+ *
+ * This software is furnished under a license and may be used and copied
+ * only in accordance of the terms of such license and with the
+ * inclusion of the above copyright notice. This software or any other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person. No title to and ownership of the software is hereby
+ * transferred.
+ *
+ * The information in this software is subject to change without notice
+ * and should not be construed as a commitment by digital equipment
+ * corporation.
+ *
+ * Digital assumes no responsibility for the use or reliability of its
+ * software on equipment which is not supplied by digital.
+ *
+ *
+ * Abstract: This file contains the definition of the MII protocol
+ * This file is part of the DEC's DC21X4 Ethernet Controller
+ * driver
+ *
+ * Author: Claudio Hazan
+ *
+ * Revision History:
+ *
+ * 20-Nov-95 ch Initial version
+ * 20-Dec-95 phk Modified
+ *
+-*/
+
+
+#define PHY_ADDR_ALIGN 23 // shift
+#define REG_ADDR_ALIGN 18 // shift
+
+#define MII_MDO_BIT_POSITION 17
+#define MII_MDI_BIT_POSITION 19
+#define MII_DELAY 1 // uS
+
+
+#define MII_WRITE ((ULONG) (0x00002000))
+#define MII_CLK ((ULONG) (0x00010000))
+#define MII_MDO_MASK ((ULONG) (0x00020000))
+#define MII_MDI_MASK ((ULONG) (0x00080000))
+
+#define PRE ((ULONG) (0xFFFFFFFF))
+#define MII_READ_FRAME ((ULONG) (0x60000000))
+#define MII_WRITE_FRAME ((ULONG) (0x50020000))
+
+#define TEST_PATTERN 0xAA5500FF
+
+#define CSR_READ 0x4000
+#define SEL_SROM 0x0800
+
+#define RESET_DELAY 10000
+
+// MII related bits in CSR9
+
+#define MII_READ ((ULONG) 0x00044000)
+#define MII_WRITE_TS ((ULONG) 0x00042000)
+#define MII_DATA_1 ((ULONG) 0x00020000) // MDO = 1
+#define MII_DATA_0 ((ULONG) 0x00000000) // MDO = 0
+
+#define MII_10BITS_TO_MDO_SHIFT 5 // number of left shifts needed to
+ // put MSB of MII_PhyAddr packed
+ // with MII_RegNumber in the MDO
+ // bit position at CSR9
+#define MII_16BITS_TO_MDO_SHIFT 2 // number of left shifts needed to
+ // put MSB of MII write data in
+ // the MDO bit position at CSR9
+
+#define MII_READ_DATA_MASK MII_MDI_MASK // MDI bit mask
+
+#define MAX_PHYADD 32
+
+//PHY Types
+
+#define PHY_NUMBER 0 // No Multiple PHYs support yet
+#define MAX_PHY_TABLE (PHY_NUMBER+1)
+#define MAX_GPR_SEQUENCE 5
+#define MAX_RESET_SEQUENCE 5
+
+#define NO_SELECTED_PHY 0x00FF
+
+
+#define MiiPhyCtrlReset ((USHORT) 0x8000)
+#define MiiPhyCtrlLoopBack ((USHORT) 0x4000)
+#define MiiPhyCtrlSpeed100 ((USHORT) 0x2000)
+#define MiiPhyCtrlEnableNway ((USHORT) 0x1000)
+#define MiiPhyCtrlPowerDown ((USHORT) 0x0800)
+#define MiiPhyCtrlIsolate ((USHORT) 0x0400)
+#define MiiPhyCtrlRestartNway ((USHORT) 0x0200)
+#define MiiPhyCtrlDuplexMode ((USHORT) 0x0100)
+#define MiiPhyCtrlCollisionTest ((USHORT) 0x0080)
+#define MiiPhyCtrlReservedBitsMask ((USHORT) 0x007F)
+#define MiiPhyCtrlForce10 ((USHORT) 0xCEFF)
+
+
+#define MiiPhy100BaseT4 ((USHORT) 0x8000)
+#define MiiPhy100BaseTxFD ((USHORT) 0x4000)
+#define MiiPhy100BaseTx ((USHORT) 0x2000)
+#define MiiPhy10BaseTFD ((USHORT) 0x1000)
+#define MiiPhy10BaseT ((USHORT) 0x0800)
+#define MiiPhyStatReservedBitsMask ((USHORT) 0x07C0)
+#define MiiPhyNwayComplete ((USHORT) 0x0020)
+#define MiiPhyRemoteFault ((USHORT) 0x0010)
+#define MiiPhyNwayCapable ((USHORT) 0x0008)
+#define MiiPhyLinkStatus ((USHORT) 0x0004)
+#define MiiPhyJabberDetect ((USHORT) 0x0002)
+#define MiiPhyExtendedCapabilities ((USHORT) 0x0001)
+
+#define MiiPhyMediaCapabilitiesMask (MiiPhy100BaseT4 | \
+ MiiPhy100BaseTxFD | \
+ MiiPhy100BaseTx | \
+ MiiPhy10BaseTFD | \
+ MiiPhy10BaseT)
+
+#define MiiPhyCapabilitiesMask (MiiPhyMediaCapabilitiesMask | \
+ MiiPhyNwayCapable)
+
+// Vendors' PHY IDs
+
+//National
+
+#define DP83840_0 ((ULONG) 0x20005C00)
+
+//Broadcom
+
+#define BCM5000_0 ((ULONG) 0x03E00000)
+#define MII_BROADCOM_EXTENDED_REG_ADDRESS 16
+
+#define BROADCOM_EXT_REG_FORCE_FAIL_EN_MASK 0x100
+#define BROADCOM_EXT_REG_SPEED_MASK 0x2
+
+//Generic
+
+#define GENERIC_PHY ((ULONG) 0xFFFFFFFF)
+
+// Useful masks
+
+#define VENDOR_ID_MASK ((ULONG) 0xFFFFFC00)
+#define VENDOR_ID_RIGHT_JUSTIFY 10
+
+#define VENDOR_MODEL_MASK ((USHORT) 0x03F0)
+#define VENDOR_MODEL_RIGHT_JUSTIFY 4
+
+#define VENDOR_Rev_MASK ((USHORT) 0x000F)
+
+#define MiiPhyNwayNextPageAble ((USHORT) 0x8000)
+#define MiiPhyNwayACK ((USHORT) 0x4000)
+#define MiiPhyNwayRemoteFault ((USHORT) 0x2000)
+#define MiiPhyNwayReservedBitsMask ((USHORT) 0x1C00)
+#define MiiPhyNway100BaseT4 ((USHORT) 0x0200)
+#define MiiPhyNway100BaseTxFD ((USHORT) 0x0100)
+#define MiiPhyNway100BaseTx ((USHORT) 0x0080)
+#define MiiPhyNway10BaseTFD ((USHORT) 0x0040)
+#define MiiPhyNway10BaseT ((USHORT) 0x0020)
+#define MiiPhyNwaySelectorMask ((USHORT) 0x001F)
+
+// MiiPhyNwayCapabilitiesMask - 0x03E0
+
+#define MiiPhyNwayCapabilitiesMask (MiiPhyNway100BaseT4 | \
+ MiiPhyNway100BaseTxFD | \
+ MiiPhyNway100BaseTx | \
+ MiiPhyNway10BaseTFD | \
+ MiiPhyNway10BaseT)
+
+#define NWAY_802_3_Selector 1
+
+#define MiiPhyNwayExpReservedBitsMask ((USHORT) 0xFFE0)
+#define MiiPhyNwayExpMultipleLinkFault ((USHORT) 0x0010)
+#define MiiPhyNwayExpLinkPartnerNextPageAble ((USHORT) 0x0008)
+#define MiiPhyNwayExpNextPageAble ((USHORT) 0x0004)
+#define MiiPhyNwayExpReceivedLinkCodePage ((USHORT) 0x0002)
+#define MiiPhyNwayExpLinkPartnerNwayAble ((USHORT) 0x0001)
+
+
+// MII PHY Register's
+
+#define PhyControlReg 0
+#define PhyStatusReg 1
+#define PhyId_1 2
+#define PhyId_2 3
+#define PhyNwayAdvertisement 4
+#define PhyNwayLinkPartnerAbility 5
+#define PhyNwayExpansion 6
+#define PhyNwayNextPageTransmit 7
+#define PhyReserved 8 // 8-15 are PHY's reserved
+#define PhyVendorSpecific 16 // 16-31 are Vendor's Specific
+#define NatPhyParRegister 25
+#define MAX_PHY_REGS 32
+
+#define DELAY(_time) NdisStallExecution(_time)
+
+//National Phy PAR Register
+#define PAR_SPEED_10 ((USHORT)0x0040)
+
+
+// MAC connection capabilities
+
+#define MAC_CONN_UNKNOWN ((USHORT) 0xFFFF)
+
+
+//PHY Type Values
+
+#define PHY_TYPE_UNKNOWN ((UCHAR) 0xFF) // Initializing, true state or type not known
+#define PHY_TYPE_SIA 0 // 10MB/s Manchester
+#define PHY_TYPE_MII 1 // MII PHY
+
+//PHY Operation Modes
+
+#define PHY_OM_UNKNOWN ((UCHAR) 0xFF)
+
+//PHY_OM_AUTOSENSE
+
+#define PHY_OM_NWAY MiiPhyNwayCapable
+#define PHY_NO_SPECIAL_OM 0
+
+//Media Attachment Interface Status
+
+#define MAI_UNKNOWN ((UCHAR) 0xFF)
+#define MAI_Absent 0
+#define MAI_Present 1
+#define MAI_PresentConnected 3
+
+// MAU list
+
+#define MAU_UNKNOWN 0
+#define MAU_10BaseT MiiPhy10BaseT
+#define MAU_10BaseTFD MiiPhy10BaseTFD
+//MAU_BNC
+//MAU_AUI
+#define MAU_100BaseT4 MiiPhy100BaseT4
+#define MAU_100BaseTX MiiPhy100BaseTx
+#define MAU_100BaseFX MiiPhy100BaseTx
+#define MAU_100BaseTXFD MiiPhy100BaseTxFD
+#define MAU_100BaseFXFD MiiPhy100BaseTxFD
+//MAU_10BaseFX
+
+#define NWAY_10BaseT MiiPhyNway10BaseT
+#define NWAY_100BaseT4 MiiPhyNway100BaseT4
+#define NWAY_100BaseTX MiiPhyNway100BaseTx
+#define NWAY_10BaseTFD MiiPhyNway10BaseTFD
+#define NWAY_100BaseTXFD MiiPhyNway100BaseTxFD
+
+// define Media status
+
+#define MEDIA_STATE_UNKNOWN 0x00FF
+#define MEDIA_STATE_UNDEFINED 0x00FE
+#define MEDIA_READ_REGISTER_FAILED 0x00FD
+#define MEDIA_LINK_FAIL 0x0000
+#define MEDIA_LINK_PASS 0x0001
+#define MEDIA_LINK_PASS_WITH_PF 0x0002
+
+#define MEDIA_STATUS_MASK 0x00FF
+
+// define NWAY Availability & status
+
+#define NWAY_UNKNOWN 0xFF00 //PHY is still initializing
+#define NWAY_NOT_SUPPORTED 0x0000 //No NWAY in this Phy
+#define NWAY_SUPPORTED 0x0100 //NWAY supported
+#define NWAY_DISABLED 0x0200 //NWAY present but disabled
+#define NWAY_CONFIGURING 0x0300 //NWAY still configuring
+#define NWAY_COMPLETE 0x0400 //NWAY negotiation is done
+
+#define NWAY_STATUS_MASK 0xFF00
+
+typedef enum _MII_STATUS {
+ MiiGenAdminReset,
+ MiiGenAdminOperational,
+ MiiGenAdminStandBy,
+ MiiGenAdminPowerDown,
+ MiiGenAdminForce10,
+ MiiGenAdminForce10Fd,
+ MiiGenAdminRelease10
+} MII_STATUS, *PMII_STATUS;
+
+typedef USHORT CAPABILITY, *PCAPABILITY;
+
+typedef struct _PHY_EXT_ROUTINES_ENTRIES {
+
+ BOOLEAN (*PhyInit)(PDC21X4_ADAPTER,PMII_PHY_INFO);
+ void (*PhyGetCapabilities)(PMII_PHY_INFO,PCAPABILITY);
+ BOOLEAN (*PhySetConnectionType)(PDC21X4_ADAPTER,PMII_PHY_INFO,USHORT,USHORT);
+ BOOLEAN (*PhyGetConnectionType)(PDC21X4_ADAPTER,PMII_PHY_INFO,PUSHORT);
+ BOOLEAN (*PhyGetConnectionStatus)(PDC21X4_ADAPTER,PMII_PHY_INFO,PUSHORT);
+ void (*PhyAdminStatus)(PDC21X4_ADAPTER,PMII_PHY_INFO,PMII_STATUS);
+ void (*PhyAdminControl)(PDC21X4_ADAPTER,PMII_PHY_INFO,PMII_STATUS);
+
+}PHY_EXT_ROUTINES_ENTRIES;
+
+typedef struct _PHY_INT_ROUTINES_ENTRIES {
+
+ BOOLEAN (*PhyReadRegister)(PDC21X4_ADAPTER,PMII_PHY_INFO,USHORT,PUSHORT);
+ BOOLEAN (*PhyWriteRegister)(PDC21X4_ADAPTER,PMII_PHY_INFO,USHORT,PUSHORT);
+ void (*PhyNwayGetLocalAbility)(PDC21X4_ADAPTER,PMII_PHY_INFO,PCAPABILITY);
+ void (*PhyNwaySetLocalAbility)(PDC21X4_ADAPTER,PMII_PHY_INFO,USHORT);
+ void (*PhyNwayGetPartnerAbility)(PDC21X4_ADAPTER,PMII_PHY_INFO,PCAPABILITY);
+
+}PHY_INT_ROUTINES_ENTRIES;
+
+
+typedef struct _MII_PHY_INFO {
+
+ BOOLEAN StructValid;
+ USHORT PhyAddress;
+ ULONG PhyId;
+ USHORT PhyCapabilities;
+ USHORT PhyMediaAdvertisement;
+ USHORT PhyRegs[MAX_PHY_REGS];
+ USHORT PreviousControl;
+ PHY_EXT_ROUTINES_ENTRIES PhyExtRoutines;
+ PHY_INT_ROUTINES_ENTRIES PhyIntRoutines;
+
+} MII_PHY_INFO, *PMII_PHY_INFO;
+
+
+typedef struct _MII_GEN_INFO {
+
+ USHORT NumOfPhys;
+ USHORT PhysCapabilities;
+ USHORT SelectedPhy; // 0 means that all phys are isolated
+ PMII_PHY_INFO Phys[MAX_PHY_TABLE];
+
+} MII_GEN_INFO, *PMII_GEN_INFO;
+
+
+//Data Structure holding PHY's registers mask
+
+static const USHORT PhyRegsReservedBitsMasks[] = {
+
+ MiiPhyCtrlReservedBitsMask, // Control reg reserved bits mask
+ MiiPhyStatReservedBitsMask, // Status reg reserved bits PhyID reserved bits mask
+ 0, // PhyID reserved bits mask
+ 0, // PhyID reserved bits mask
+ MiiPhyNwayReservedBitsMask, // Nway Local ability reserved bits mask
+ MiiPhyNwayReservedBitsMask, // Nway Partner ability reserved bits mask
+ MiiPhyNwayExpReservedBitsMask, // Nway Expansion
+ 0,0,0,0,0,0,0,0,0,0,0,0,0, // Other regs
+ 0,0,0,0,0,0,0,0,0,0,0,0 // Other regs
+ };
+
+static const UINT AdminControlConversionTable[] = {
+ MiiPhyCtrlReset, // Reset
+ 0x0, // Operational
+ MiiPhyCtrlIsolate, // StandBy / Isolate
+ MiiPhyCtrlPowerDown, // Powerdown
+ 0x0, // Force10
+ MiiPhyCtrlDuplexMode, // Force10Fd
+ 0x0 // Release10
+ };
+
+
+static const USHORT MediaBitTable[] = {
+ 0x0000, // TP
+ 0x0000, // BNC
+ 0x0000, // AUI
+ 0x0000, // 100BaseTx/SymScr
+ 0x0000, // TP-FD
+ 0x0000, // 100BaseTx-FD/SymScr-FD
+ 0x0000, // 100BaseT4
+ 0x0000, // 100BaseFx
+ 0x0000, // 100BaseFx-FD
+ 0x0800, // MediaMiiTP
+ 0x1000, // MediaMiiTpFD
+ 0x0000, // MediaMiiBNC
+ 0x0000, // MediaMiiAUI
+ 0x2000, // MediaMii100BaseTX
+ 0x4000, // MediaMii100BaseTxFD
+ 0x8000, // MediaMii100BaseT4
+ 0x0000, // MediaMii100BaseFX
+ 0x0000 // MediaMii100BaseFxFD
+};
+
+static const USHORT ConvertMediaTypeToMiiType[] = {
+ 0x0009, // TP -> MII TP
+ 0x000B, // BNC -> MII BNC
+ 0x000C, // AUI -> MII AUI
+ 0x000D, // 100BaseTx -> MII 100BaseTx
+ 0x020A, // TP-FD -> MII TP-FD
+ 0x020E, // 100BaseTx-FD -> MII 100BaseTxFD
+ 0x000F, // 100BaseT4 -> MII 100BaseT4
+ 0x0010, // 100BaseFx -> MII 100BaseFx
+ 0x0211 // 100BaseFx-FD -> MII 100BaseFxFD
+};
+
+static const USHORT MediaToCommandConversionTable[] = {
+ 0x0000, // TP
+ 0x0000, // BNC
+ 0x0000, // AUI
+ 0x2000, // 100BaseTx/SymScr
+ 0x0100, // TP-FD
+ 0x2100, // 100BaseTx-FD/SymScr-FD
+ 0x2000, // 100BaseT4
+ 0x2000, // 100BaseFx
+ 0x2100, // 100BaseFx-FD
+ 0x0000, // MediaMiiTP
+ 0x0100, // MediaMiiTpFD
+ 0x0000, // MediaMiiBNC
+ 0x0000, // MediaMiiAUI
+ 0x2000, // MediaMii100BaseTX
+ 0x2100, // MediaMii100BaseTxFD
+ 0x2000, // MediaMii100BaseT4
+ 0x2000, // MediaMii100BaseFX
+ 0x2100 // MediaMii100BaseFxFD
+};
+
+static const USHORT MediaToNwayConversionTable[] = {
+ 0x0020, // TP
+ 0x0000, // BNC
+ 0x0000, // AUI
+ 0x0080, // 100BaseTx/SymScr
+ 0x0040, // TP-FD
+ 0x0100, // 100BaseTx-FD/SymScr-FD
+ 0x0200, // 100BaseT4
+ 0x0080, // 100BaseFx
+ 0x0100, // 100BaseFx-FD
+ 0x0020, // MediaMiiTP
+ 0x0040, // MediaMiiTpFD
+ 0x0000, // MediaMiiBNC
+ 0x0000, // MediaMiiAUI
+ 0x0080, // MediaMii100BaseTX
+ 0x0100, // MediaMii100BaseTxFD
+ 0x0200, // MediaMii100BaseT4
+ 0x0080, // MediaMii100BaseFX
+ 0x0100 // MediaMii100BaseFxFD
+};
+
+static const USHORT MediaToStatusConversionTable[] = {
+ 0x0800, // TP
+ 0x0000, // BNC
+ 0x0000, // AUI
+ 0x2000, // 100BaseTx/SymScr
+ 0x1000, // TP-FD
+ 0x4000, // 100BaseTx-FD/SymScr-FD
+ 0x8000, // 100BaseT4
+ 0x2000, // 100BaseFx
+ 0x4000, // 100BaseFx-FD
+ 0x0800, // MediaMiiTP
+ 0x1000, // MediaMiiTpFD
+ 0x0000, // MediaMiiBNC
+ 0x0000, // MediaMiiAUI
+ 0x2000, // MediaMii100BaseTX
+ 0x4000, // MediaMii100BaseTxFD
+ 0x8000, // MediaMii100BaseT4
+ 0x2000, // MediaMii100BaseFX
+ 0x4000 // MediaMii100BaseFxFD
+ };
+
diff --git a/private/ntos/ndis/dc21x4/miigen.c b/private/ntos/ndis/dc21x4/miigen.c
new file mode 100644
index 000000000..d1d7d4333
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/miigen.c
@@ -0,0 +1,524 @@
+/*+
+ * file: miigen.c
+ *
+ * Copyright (C) 1992-1995 by
+ * Digital Equipment Corporation, Maynard, Massachusetts.
+ * All rights reserved.
+ *
+ * This software is furnished under a license and may be used and copied
+ * only in accordance of the terms of such license and with the
+ * inclusion of the above copyright notice. This software or any other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person. No title to and ownership of the software is hereby
+ * transferred.
+ *
+ * The information in this software is subject to change without notice
+ * and should not be construed as a commitment by digital equipment
+ * corporation.
+ *
+ * Digital assumes no responsibility for the use or reliability of its
+ * software on equipment which is not supplied by digital.
+ *
+ *
+ * Abstract: This file contains the code needed to support the
+ * generic PHY chip through MII connection
+ *
+ * Author: Claudio Hazan
+ *
+ * Revision History:
+ *
+ * 20-Nov-95 as Initial version
+ * 20-Dec-95 phk Cleanup
+ *
+-*/
+
+
+#include <precomp.h>
+
+
+
+/*+
+ *
+ *MiiGenInit(Adapter)
+ *
+ *Description:
+ * This Routine is called to initialize the module:
+ * - Initializes its internal structures.
+ * - Calls FindMiiPhysProc to find the first PHY on the adapter card
+ * - If a PHY is found then
+ * - Calls the PHY's init routine.
+ * - Gets the PHY's capabilities and saves them
+ * as the generic PHY capabilities.
+ *
+ *On Entry:
+ *
+ *Returns: FALSE - no PHY was found.
+ * TRUE - a PHY was found.
+ *
+-*/
+extern
+BOOLEAN
+MiiGenInit(
+ PDC21X4_ADAPTER Adapter
+ )
+{
+
+ CAPABILITY Cap;
+ UINT Loop;
+ UINT Retry=2;
+ UINT Count;
+ ULONG Status;
+
+#if MII_DBG
+ DbgPrint("MiiGenInit\n");
+#endif
+
+ //Find the first PHY connected
+
+ if (!FindAndInitMiiPhys(Adapter)) {
+#if MII_DBG
+ DbgPrint("***MiiGenInit: No PHY was found\n");
+#endif
+ return FALSE;
+ }
+
+ // Set Generic PHY capabilities
+
+ (Adapter->MiiGen.Phys[Adapter->PhyNumber])->PhyExtRoutines.PhyGetCapabilities(
+ Adapter->MiiGen.Phys[Adapter->PhyNumber],
+ &Cap
+ );
+ // Update General Phys' capabilities
+
+ Adapter->MiiGen.PhysCapabilities |= Cap;
+#if MII_DBG
+ DbgPrint("MiiGenInit: PHY Capabilities= %04x\n", Cap);
+#endif
+
+ // Selected PHY number
+ Adapter->MiiGen.SelectedPhy = Adapter->PhyNumber;
+
+ return TRUE;
+}
+
+
+
+
+/*+
+ *
+ * MiiGenGetCapabilities (Adapter)
+ *
+ *
+ * Description:
+ *
+ * Returns the Generic Phy capabilities
+ *
+ * Returns:
+ *
+ * Phys capabilities
+ *
+-*/
+extern
+USHORT
+MiiGenGetCapabilities(
+ PDC21X4_ADAPTER Adapter
+ )
+{
+#if __DBG
+ DbgPrint("MiiGenGetCapabilities\n");
+#endif
+ return(Adapter->MiiGen.PhysCapabilities);
+}
+
+
+/*+
+ *
+ *MiiGenCheckConnection
+ *
+ *Description:
+ * Checks if the desired connection is supported by the PHY.
+ *
+ *On Entry:
+ * Connection - the desired connection.
+ *
+ *Returns
+ * FALSE - upon failing to support connection.
+ * TRUE - on success.
+ *
+-*/
+
+extern
+BOOLEAN
+MiiGenCheckConnection(
+ PDC21X4_ADAPTER Adapter,
+ USHORT Connection
+ )
+{
+ // Check PHY's connection
+#if MII_DBG
+ DbgPrint("MiiGenCheckConnection\n");
+#endif
+
+ return CheckConnectionSupport(
+ Adapter->MiiGen.Phys[Adapter->PhyNumber],
+ Connection
+ );
+}
+
+
+/*+
+ *
+ *MiiGenSetConnection
+ *
+ *Description:
+ * Sets PHY's connection to the desired connection and advertised
+ *
+ * (PHY will remain Isolated and selecting one of them will
+ * be done via the Admin control procedure).
+ *
+ *On Entry:
+ * Connection - the desired connection.
+ * NWAYAdvertisement (if =0 -> use PHY's defaults)
+ *
+ *Returns
+ * FALES - upon failing to set connection.
+ * TRUE - on success.
+ *
+-*/
+
+extern
+BOOLEAN
+MiiGenSetConnection(
+ PDC21X4_ADAPTER Adapter,
+ UINT Connection,
+ USHORT NwayAdvertisement
+ )
+{
+ // Set PHY's connection
+#if MII_DBG
+ DbgPrint("MiiGenSetConnection\n");
+#endif
+
+ return (Adapter->MiiGen.Phys[Adapter->PhyNumber])->PhyExtRoutines.PhySetConnectionType(
+ Adapter,
+ Adapter->MiiGen.Phys[Adapter->PhyNumber],
+ Connection,
+ NwayAdvertisement
+ );
+}
+
+/*+
+ *
+ *MiiGenGetConnectionStatus
+ *
+ *Description:
+ * Returns the connection status of the Phy
+ *
+ *On Entry:
+ *
+ *On Return:
+ * ConnectionStatus - hold connection status
+ *
+ *Return: FALSE: Upon Status "error" (Nway configuring or Link-Fail)
+ * TRUE: No error
+ *
+-*/
+extern
+BOOLEAN
+MiiGenGetConnectionStatus (
+ PDC21X4_ADAPTER Adapter,
+ PUSHORT ConnectionStatus
+ )
+{
+#if MII_DBG
+ DbgPrint("MiiGenGetConnectionStatus\n");
+#endif
+ return Adapter->MiiGen.Phys[Adapter->PhyNumber]->PhyExtRoutines.PhyGetConnectionStatus(
+ Adapter,
+ Adapter->MiiGen.Phys[Adapter->PhyNumber],
+ ConnectionStatus
+ );
+}
+
+
+
+/*+
+ *
+ *MiiGenGetConnection
+ *
+ *Description:
+ * Returns the connection type of the PHY if possible (PHY Nway
+ * is either disabled or completed).
+ *
+ *
+ *On Return:
+ * Connection - Phys connection.
+ *
+ *Returns; FALSE - set Upon error (Connection = MAC_CONN_UNKNOWN)
+ * TRUE - valid connection type.
+ *
+-*/
+extern
+BOOLEAN
+MiiGenGetConnection(
+ PDC21X4_ADAPTER Adapter,
+ PUSHORT Connection
+ )
+{
+
+ // Is the PHY in a "stable" state ?
+
+#if MII_DBG
+ DbgPrint("MiiGenGetConnection\n");
+#endif
+ if (Adapter->MiiGen.Phys[Adapter->PhyNumber]->PhyExtRoutines.PhyGetConnectionStatus(
+ Adapter,
+ Adapter->MiiGen.Phys[Adapter->PhyNumber],
+ Connection
+ )
+ ) {
+
+ // PHY is in a stable state - get Connection
+
+ return Adapter->MiiGen.Phys[Adapter->PhyNumber]->PhyExtRoutines.PhyGetConnectionType(
+ Adapter,
+ Adapter->MiiGen.Phys[Adapter->PhyNumber],
+ Connection
+ );
+ }
+ else {
+
+ // NWAY Not in stable state or Link_Fail.
+ *Connection = MAC_CONN_UNKNOWN;
+#if MII_DBG
+ DbgPrint("***MiiGenGetConnection: Connection= %04x Unknown by the PHY or status not stable\n", *Connection);
+#endif
+ return FALSE;
+ }
+
+}
+
+
+
+
+
+
+/*+
+ *
+ *MiiGenAdminStatus
+ *
+ *Description:
+ * Returnes the Admin status of the PHY.
+ *
+ *On Return:
+ * AdminStatus
+ *
+ *Returns:
+ * None
+ *
+-*/
+extern
+void
+MiiGenAdminStatus(
+ PDC21X4_ADAPTER Adapter,
+ PUSHORT AdminStatus
+ )
+{
+
+ // Get PHY Status
+#if MII_DBG
+ DbgPrint("MiiGenAdminStatus\n");
+#endif
+
+ Adapter->MiiGen.Phys[Adapter->PhyNumber]->PhyExtRoutines.PhyAdminStatus(
+ Adapter,
+ Adapter->MiiGen.Phys[Adapter->PhyNumber],
+ AdminStatus
+ );
+
+}
+
+
+
+
+
+
+
+/*+
+ *
+ *MiiGenAdminControl
+ *
+ *Description:
+ * Performs the requested Admin control on the Phy.
+ *
+ *On Entry:
+ * AdminControl
+ *
+ *Returns:
+ * FALSE - upon Failure.
+ * TRUE - Perform Admin control OK.
+ *
+-*/
+extern
+BOOLEAN
+MiiGenAdminControl(
+ PDC21X4_ADAPTER Adapter,
+ USHORT AdminControl
+ )
+{
+ // Perform the operation on the Phy
+#if MII_DBG
+ DbgPrint("MiiGenAdminControl: %s\n",
+ AdminControl == MiiGenAdminReset? "Reset" :
+ AdminControl == MiiGenAdminOperational? "Operational" :
+ AdminControl == MiiGenAdminForce10? "Force10" :
+ AdminControl == MiiGenAdminForce10Fd? "Force10Fd" :
+ AdminControl == MiiGenAdminRelease10? "Release10" :
+ AdminControl == MiiGenAdminStandBy? "StandBy" :
+ AdminControl == MiiGenAdminPowerDown? "PowerDown" :
+ "Unknown Command!!!!"
+ );
+#endif
+
+ Adapter->MiiGen.Phys[Adapter->PhyNumber]->PhyExtRoutines.PhyAdminControl(
+ Adapter,
+ Adapter->MiiGen.Phys[Adapter->PhyNumber],
+ AdminControl
+ );
+
+ // Perform Generic PHY operations related to the specified command
+
+ switch (AdminControl) {
+
+ case MiiGenAdminReset:
+ case MiiGenAdminOperational:
+ case MiiGenAdminForce10:
+ case MiiGenAdminForce10Fd:
+ case MiiGenAdminRelease10:
+
+ Adapter->MiiGen.SelectedPhy = Adapter->PhyNumber;
+ break;
+
+ case MiiGenAdminStandBy:
+ case MiiGenAdminPowerDown:
+
+ Adapter->MiiGen.SelectedPhy = NO_SELECTED_PHY;
+ break;
+
+
+ default:
+ // If reached this point Unknown command
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+
+
+
+
+
+/*+
+ *
+ *FindAndInitMiiPhysProc
+ *
+ *Description:
+ * This Routine Scans the entire Nic's Phys address space and
+ * for a PHY and Initializes each PHY found .
+ *
+ *On Return:
+ *
+ * Note: The driver currently supports only 1 single PHY per
+ * adapter
+ *
+ *Returns:
+ *
+ * TRUE if a PHY was found and initialized successfully
+-*/
+BOOLEAN
+FindAndInitMiiPhys(
+ PDC21X4_ADAPTER Adapter
+ )
+{
+ INT PhysCount = 0; // Start from address 0
+ NDIS_STATUS NdisStatus;
+
+#if MII_DBG
+ DbgPrint("FindAndInitMiiPhys\n");
+#endif
+
+ if (!Adapter->MiiGen.Phys[Adapter->PhyNumber]) {
+
+ ALLOC_MEMORY(
+ &NdisStatus,
+ &(Adapter->MiiGen.Phys[Adapter->PhyNumber]),
+ sizeof(MII_PHY_INFO)
+ );
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ return FALSE;
+ }
+
+ }
+
+ // Init the routine's structure.
+ InitPhyInfoEntries(
+ Adapter->MiiGen.Phys[Adapter->PhyNumber]
+ );
+
+ while (PhysCount < MAX_PHYADD) {
+
+ // did we pass the legal address range ?
+ // Is there a PHY in this address?
+
+ Adapter->MiiGen.Phys[Adapter->PhyNumber]->PhyAddress = PhysCount;
+#if MII_DBG
+ DbgPrint("Adapter->MiiGen.Phys[Adapter->PhyNumber]->PhyAddress=%02x\n",Adapter->MiiGen.Phys[Adapter->PhyNumber]->PhyAddress);
+#endif
+ if (MiiPhyInit(
+ Adapter,
+ Adapter->MiiGen.Phys[Adapter->PhyNumber]
+ ) ) {
+ // Found a PHY - Handle it
+#if MII_DBG
+ DbgPrint("FindAndInitMiiPhys: A PHY was found at address= %d\n", PhysCount);
+#endif
+ Adapter->MiiGen.NumOfPhys++; // inc # of phys found
+ return TRUE;
+ }
+ PhysCount++; // Look at next PHY address.
+ }
+
+ FREE_MEMORY(
+ Adapter->MiiGen.Phys[Adapter->PhyNumber],
+ sizeof(MII_PHY_INFO)
+ );
+ Adapter->MiiGen.Phys[Adapter->PhyNumber] = (PMII_PHY_INFO)NULL;
+
+ return FALSE;
+}
+
+
+/*+
+ *
+ * MiiFreeResources
+ *
+ *Description:
+ * Free the resources allocated to Mii
+ *
+-*/
+void
+MiiFreeResources(
+ PDC21X4_ADAPTER Adapter
+ )
+
+{
+ if (Adapter->MiiGen.Phys[Adapter->PhyNumber]) {
+ FREE_MEMORY(
+ Adapter->MiiGen.Phys[Adapter->PhyNumber],
+ sizeof(MII_PHY_INFO)
+ );
+ Adapter->MiiGen.Phys[Adapter->PhyNumber] = (PMII_PHY_INFO)NULL;
+ }
+}
diff --git a/private/ntos/ndis/dc21x4/miiphy.c b/private/ntos/ndis/dc21x4/miiphy.c
new file mode 100644
index 000000000..e06d02195
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/miiphy.c
@@ -0,0 +1,1913 @@
+/*+
+ * file: miiphy.c
+ *
+ * Copyright (C) 1992-1995 by
+ * Digital Equipment Corporation, Maynard, Massachusetts.
+ * All rights reserved.
+ *
+ * This software is furnished under a license and may be used and copied
+ * only in accordance of the terms of such license and with the
+ * inclusion of the above copyright notice. This software or any other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person. No title to and ownership of the software is hereby
+ * transferred.
+ *
+ * The information in this software is subject to change without notice
+ * and should not be construed as a commitment by digital equipment
+ * corporation.
+ *
+ * Digital assumes no responsibility for the use or reliability of its
+ * software on equipment which is not supplied by digital.
+ *
+ *
+ * Abstract: This file contains the code to support the MII protocol
+ * to access the PHY chip.
+ * This file is part of the DEC's DC21X4 Ethernet Controller
+ * driver
+ *
+ * Author: Claudio Hazan
+ *
+ * Revision History:
+ *
+ * 20-Nov-95 ch Initial version
+ * 20-Dec-95 phk Cleanup
+ *
+-*/
+
+#include <precomp.h>
+
+
+/*+
+ *
+ * MiiPhyInit
+ *
+ * Description : Initializes Mii PHY entry variables.
+ * Searches for PHY in given address, initializes it if found.
+ *
+ * Input parameters:
+ *
+ * PDC21X4_ADAPTER - Adapter The Adapter's DS
+ * PhyInfoPtr - PMII_PHY_INFO pointer to struct with PHY info
+ *
+ * Output parameters:
+ *
+ * None.
+-*/
+extern
+BOOLEAN
+MiiPhyInit(
+ PDC21X4_ADAPTER Adapter,
+ PMII_PHY_INFO PhyInfoPtr
+ )
+{
+
+ USHORT i;
+
+#if MII_DBG
+ DbgPrint("MiiPhyInit\n");
+#endif
+
+ if ( !(FindMiiPhyDevice(Adapter, PhyInfoPtr)) ) {
+ return FALSE;
+ }
+
+#if MII_DBG
+ DbgPrint("MiiPhyDevice FOUND!\n");
+#endif
+
+ // Reset the PHY to return it to his default values
+ PhyInfoPtr->PhyExtRoutines.PhyAdminControl(
+ Adapter,
+ PhyInfoPtr,
+ MiiGenAdminReset
+ );
+
+ // Once the PHY is reset, read the values of its
+ // whole registers
+
+ if ( !(FindMiiPhyDevice(Adapter, PhyInfoPtr)) ) {
+ return FALSE;
+ }
+
+ // get and save PHY capabilities
+ PhyInfoPtr->PhyCapabilities =
+ PhyInfoPtr->PhyRegs[PhyStatusReg] & MiiPhyCapabilitiesMask;
+
+ switch (PhyInfoPtr->PhyId) {
+
+ case BCM5000_0:
+
+#if MII_DBG
+ DbgPrint("Broadcom PHY...\n");
+#endif
+ // allow Autosense
+ PhyInfoPtr->PhyCapabilities |= MiiPhyNwayCapable;
+ break;
+ }
+#if MII_DBG
+ DbgPrint("PhyCapabilities = %04x\n", PhyInfoPtr->PhyCapabilities);
+#endif
+
+ // get and save PHY's NWAY Advertisement
+ PhyInfoPtr->PhyIntRoutines.PhyNwayGetLocalAbility(
+ Adapter,
+ PhyInfoPtr,
+ &(PhyInfoPtr->PhyMediaAdvertisement)
+ );
+#if MII_DBG
+ DbgPrint("PhyMediaAdvertisement = %04x\n", PhyInfoPtr->PhyMediaAdvertisement);
+#endif
+
+ // put the PHY in operational mode
+ PhyInfoPtr->PhyExtRoutines.PhyAdminControl(
+ Adapter,
+ PhyInfoPtr,
+ MiiGenAdminOperational
+ );
+
+ /* mark that PHY entry is valid */
+ PhyInfoPtr->StructValid = TRUE;
+
+#if MII_DBG
+ DbgPrint("MiiPhyInit Done\n");
+#endif
+ return TRUE;
+
+}
+
+
+/*+
+ *
+ * MiiPhyGetCapabilities
+ *
+ * Description : Returns the PHY capabilities.
+
+ * Input parameters:
+ *
+ * PhyInfoPtr - PMII_PHY_INFO pointer to struct with PHY info
+ *
+ * Output parameters:
+ *
+ * Capabilities - CAPABILITY
+ *
+ *
+-*/
+extern
+void
+MiiPhyGetCapabilities(
+ PMII_PHY_INFO PhyInfoPtr,
+ CAPABILITY *Capabilities
+ )
+{
+#if MII_DBG
+ DbgPrint("MiiPhyGetCapabilities\n");
+#endif
+ *Capabilities = PhyInfoPtr->PhyCapabilities;
+ return;
+}
+
+
+
+
+/*+
+ *
+ * MiiPhySetConnectionType
+ *
+ * Description:
+ *
+ * if (Connection == NWAY) then
+ * if (Advertisement != 0 )
+ * Change LocalAdvertisement
+ * and Set RestartNway bit
+ * set NWAy bit On in CTRL register
+ * else
+ * Translate Media to appropriate control bits
+ * write CTRL reg
+ * and return success
+ *
+ * Input parameters:
+ *
+ * PhyInfoPtr - PMII_PHY_INFO pointer to struct with PHY info
+ * Connection - USHORT
+ * Advertisement - USHORT
+ *
+ * Output parameters:
+ *
+ * None.
+ *
+ * On return - FALSE if PHY does not support Connection, TRUE otherwise.
+ *
+-*/
+extern
+BOOLEAN
+MiiPhySetConnectionType(
+ PDC21X4_ADAPTER Adapter,
+ PMII_PHY_INFO PhyInfoPtr,
+ USHORT Connection,
+ USHORT Advertisement
+ )
+{
+#if MII_DBG
+ DbgPrint("MiiPhySetConnectionType\n");
+#endif
+ // Check if the PHY supports this connection ?
+ if(!CheckConnectionSupport(
+ PhyInfoPtr,
+ Connection
+ )){
+#if MII_DBG
+ DbgPrint("***The Connection %04x is not supported by the Phy\n", Connection);
+#endif
+ return FALSE;
+ }
+
+ // Convert Connection type to Control_word
+ ConvertConnectionToControl(
+ PhyInfoPtr,
+ &Connection
+ );
+
+ // Clear Previous Connection bits from Control_word
+ // (Leave only Isolate and Power-down bits)
+ PhyInfoPtr->PhyRegs[PhyControlReg] &=
+ (MiiPhyCtrlIsolate | MiiPhyCtrlPowerDown);
+
+ // Create the new Control_word
+ PhyInfoPtr->PhyRegs[PhyControlReg] |= Connection;
+
+ // If operation mode is NWAY - set its parameters
+ if (Connection & MiiPhyCtrlEnableNway) {
+ PhyInfoPtr->PhyIntRoutines.PhyNwaySetLocalAbility(
+ Adapter,
+ PhyInfoPtr,
+ Advertisement
+ );
+ }
+
+ // write the new control word
+#if MII_DBG
+ DbgPrint("New Control_word= %04x\n", PhyInfoPtr->PhyRegs[PhyControlReg]);
+#endif
+ PhyInfoPtr ->PhyIntRoutines.PhyWriteRegister(
+ Adapter,
+ PhyInfoPtr ,
+ PhyControlReg,
+ PhyInfoPtr->PhyRegs[PhyControlReg]
+ );
+
+ // Don't save RestartNway bit !
+ PhyInfoPtr ->PhyRegs[PhyControlReg] &= ~MiiPhyCtrlRestartNway;
+
+ switch (PhyInfoPtr ->PhyId) {
+
+ case BCM5000_0:
+
+ // Need to be reset between 10Base to 100Base transitions
+#if MII_DBG
+ DbgPrint("Broadcom - 10B to 100B transition\n");
+#endif
+ HandleBroadcomMediaChangeFrom10To100(
+ Adapter,
+ PhyInfoPtr
+ );
+ break;
+ }
+
+ return TRUE;
+}
+
+/*+
+ *
+ * MiiPhyGetConnectionType
+ *
+ * Description:
+ *
+ * Returns selected connection of the PHY.
+ * If PHY connection is not yet resolved and wait is required,
+ * waits for connection resolution and returns it.
+ * If not - returns error status.
+ *
+ * Input parameters:
+ *
+ * PhyInfoPtr - PMII_PHY_INFO pointer to struct with PHY info
+ *
+ * Output parameters:
+ *
+ * ConnectionStatus - Status
+ *
+ * On Return
+ * Upon error - FALSE
+ * ConnectionStatus - error status
+ *
+ * Upon success - TRUE
+ * ConnectionStatus - selected connection.
+ *
+ *Remarks:
+ *
+ * We use the NWAY capable bit in the PHY capabilities field to
+ * overcome Broadcom's AutoSense issue.
+ *
+-*/
+extern
+BOOLEAN
+MiiPhyGetConnectionType(
+ PDC21X4_ADAPTER Adapter,
+ PMII_PHY_INFO PhyInfoPtr,
+ PUSHORT ConnectionStatus
+ )
+{
+
+ CAPABILITY LocalAbility;
+ CAPABILITY PartnerAbility;
+ CAPABILITY Ability;
+ USHORT Register;
+
+#if MII_DBG
+ DbgPrint("MiiPhyGetConnectionType\n");
+#endif
+ switch (PhyInfoPtr->PhyId) {
+
+ case BCM5000_0:
+
+ if (!GetBroadcomPhyConnectionType(
+ Adapter,
+ PhyInfoPtr,
+ ConnectionStatus
+ )
+ ) {
+
+#if MII_DBG
+ DbgPrint("***Connection not supported by Broadcom's Phy\n");
+#endif
+ *ConnectionStatus = MAC_CONN_UNKNOWN;
+ return FALSE;
+ }
+ else {
+ HandleBroadcomMediaChangeFrom10To100(
+ Adapter,
+ PhyInfoPtr
+ );
+ return TRUE;
+ }
+ break;
+
+ default:
+
+ if (PhyInfoPtr->PhyRegs[PhyControlReg] & MiiPhyCtrlEnableNway) {
+
+ // NWAY selected:
+ // get partner and local abilities,
+ // use them to retrieve the selected connection type
+#if MII_DBG
+ DbgPrint("Not Broadcom PHY: enable NWAY\n");
+#endif
+ PhyInfoPtr->PhyIntRoutines.PhyNwayGetLocalAbility(
+ Adapter,
+ PhyInfoPtr,
+ &LocalAbility
+ );
+
+ PhyInfoPtr->PhyIntRoutines.PhyNwayGetPartnerAbility(
+ Adapter,
+ PhyInfoPtr,
+ &PartnerAbility
+ );
+
+ Ability = LocalAbility & PartnerAbility;
+#if MII_DBG
+ DbgPrint("LocalAbility : %04x\n",LocalAbility);
+ DbgPrint("PartnerAbility : %04x\n",PartnerAbility);
+#endif
+
+ if (!Ability){
+ // No common mode:
+#if MII_DBG
+ DbgPrint("No Common Mode...\n");
+#endif
+
+ if (PhyInfoPtr->PhyId == DP83840_0) {
+
+ //National's Phy Speed Sensing workaround:
+ //read the Speed_bit in the PAR register to sense
+ //the connection speed
+
+ if (PhyInfoPtr->PhyIntRoutines.PhyReadRegister(
+ Adapter,
+ PhyInfoPtr ,
+ NatPhyParRegister,
+ &Register
+ )) {
+
+ Ability = (LocalAbility &
+ ((Register & PAR_SPEED_10) ? MiiPhy10BaseT : MiiPhy100BaseTx) >>6);
+#if MII_DBG
+ DbgPrint("National: Ability : %04x\n", Ability);
+#endif
+ }
+ }
+ }
+ return (Ability ?
+ ConvertNwayToConnectionType(Ability, ConnectionStatus) : FALSE);
+ }
+ else {
+
+ // Nway not supported or not selected,
+ // connection has been selected via CommandReg
+
+ if (PhyInfoPtr->PhyRegs[PhyControlReg] & MiiPhyCtrlDuplexMode) {
+
+ // Full Duplex Medium
+
+ *ConnectionStatus =
+ (PhyInfoPtr->PhyRegs[PhyControlReg] & MiiPhyCtrlSpeed100) ?
+ MediumMii100BaseTxFullDuplex : MediumMii10BaseTFullDuplex;
+#if MII_DBG
+ DbgPrint("Full Duplex Medium; ConnectionStatus= %04x\n",*ConnectionStatus);
+#endif
+ }
+ else if (PhyInfoPtr->PhyRegs[PhyControlReg] & MiiPhyCtrlSpeed100) {
+
+ *ConnectionStatus =
+ (PhyInfoPtr->PhyRegs[PhyStatusReg] & MiiPhy100BaseTx) ?
+ MediumMii100BaseTx : MediumMii100BaseT4;
+ }
+ else{
+ *ConnectionStatus = MediumMii10BaseT;
+ }
+#if MII_DBG
+ DbgPrint("ConnectionStatus= %04x\n",*ConnectionStatus);
+#endif
+ return TRUE;
+ }
+ }
+
+}
+
+/*+
+ *
+ * MiiPhyGetConnectionStatus
+ *
+ * Description:
+ *
+ * Returns the connection status of the PHY.
+ * Rewrites the command word read from the PHY in its entry
+ * in the PhysArray.
+ *
+ * Connection status has the following attributes:
+ * NwayAdminStatus
+ * MAUStatus
+ *
+ *On Entry:
+ * PhyInfoPtr
+ *
+ *On Return:
+ * ConnectionStatus :
+ * High byte - Nwaystatus
+ * Low byte - LinkStatus
+ *
+ *On return
+ * TRUE - on success
+ * FALSE - on fail, the return Connection Status is not valid
+ *
+-*/
+extern
+BOOLEAN
+MiiPhyGetConnectionStatus (
+ PDC21X4_ADAPTER Adapter,
+ PMII_PHY_INFO PhyInfoPtr ,
+ PUSHORT ConnectionStatus
+ )
+{
+
+ //Init all Status bytes to UNKNOWN
+ CAPABILITY NwayStatus=NWAY_UNKNOWN;
+ CAPABILITY LinkStatus=MEDIA_STATE_UNKNOWN;
+
+ CAPABILITY Ability;
+ CAPABILITY LocalAbility;
+ CAPABILITY PartnerAbility;
+
+ ULONG Register;
+
+#if MII_DBG
+ DbgPrint("MiiPhyGetConnectionStatus\n");
+#endif
+ // Read and save Control Reg since the speed selection may be
+ // forced via an hardware pin causing the software selection
+ // to be ignored
+
+ if (!PhyInfoPtr->PhyIntRoutines.PhyReadRegister(
+ Adapter,
+ PhyInfoPtr ,
+ PhyControlReg,
+ &(PhyInfoPtr->PhyRegs[PhyControlReg])
+ )) {
+
+ LinkStatus = MEDIA_READ_REGISTER_FAILED;
+ *ConnectionStatus = NwayStatus | LinkStatus;
+ return FALSE;
+ }
+
+#if MII_DBG
+ DbgPrint("PHY's ControlReg = %04x\n",PhyInfoPtr->PhyRegs[PhyControlReg]);
+#endif
+
+ // Read & save Status word
+ if (!PhyInfoPtr->PhyIntRoutines.PhyReadRegister(
+ Adapter,
+ PhyInfoPtr,
+ PhyStatusReg,
+ &(PhyInfoPtr->PhyRegs[PhyStatusReg])
+ )) {
+ LinkStatus = MEDIA_READ_REGISTER_FAILED;
+ *ConnectionStatus = NwayStatus | LinkStatus;
+ return FALSE;
+ }
+#if MII_DBG
+ DbgPrint("PHY's StatusReg = %04x\n",PhyInfoPtr->PhyRegs[PhyStatusReg]);
+#endif
+ if (PhyInfoPtr->PhyRegs[PhyStatusReg] == 0){
+ LinkStatus = MEDIA_READ_REGISTER_FAILED;
+ *ConnectionStatus = NwayStatus | LinkStatus;
+ return FALSE;
+ }
+
+ // Set Nway status according to Nway complete & ability bits & enable
+
+ switch (PhyInfoPtr->PhyId) {
+
+ case BCM5000_0:
+
+ // Broadcom
+
+ if (PhyInfoPtr ->PhyRegs[PhyControlReg] & MiiPhyCtrlEnableNway) {
+
+ NwayStatus = NWAY_COMPLETE;
+ }
+ else {
+
+ NwayStatus = NWAY_DISABLED;
+ }
+ break;
+
+ default:
+
+ if (PhyInfoPtr ->PhyRegs[PhyStatusReg] & MiiPhyNwayCapable) {
+
+ if (PhyInfoPtr ->PhyRegs[PhyControlReg] & MiiPhyCtrlEnableNway) {
+
+ if (PhyInfoPtr ->PhyRegs[PhyStatusReg] & MiiPhyNwayComplete) {
+ NwayStatus = NWAY_COMPLETE;
+ }
+ else {
+ // assume configuration not done yet
+ NwayStatus = NWAY_CONFIGURING;
+ *ConnectionStatus = NwayStatus | LinkStatus;
+ return FALSE;
+ }
+ }
+ else {
+ NwayStatus = NWAY_DISABLED;
+ }
+ }
+ else {
+ NwayStatus = NWAY_NOT_SUPPORTED;
+ }
+ }
+
+ // Set link status according to link bit.
+ // Since LinkStatus bit latches Link-Fail status
+ // the link status is find as follows:
+ //
+ // If Status Reg indicate LinkPass then
+ // LinkStatus=LINK_PASS
+ // else
+ // Read Status Register
+ // If Status Reg indicate LinkPass then
+ // LinkStatus=LINK_PASS_WITH_PF
+ // else
+ // LinkStatus=LINK_FAIL
+ // endif
+ // endif
+
+
+ // Check if the Link status indicates a
+ // PHY's supported medium
+ // Only if the Phy is NWAY's Capable or NWAY is enabled
+
+ if (NwayStatus == NWAY_COMPLETE) {
+
+ PhyInfoPtr->PhyIntRoutines.PhyNwayGetLocalAbility(
+ Adapter,
+ PhyInfoPtr,
+ &LocalAbility
+ );
+
+ PhyInfoPtr->PhyIntRoutines.PhyNwayGetPartnerAbility(
+ Adapter,
+ PhyInfoPtr,
+ &PartnerAbility
+ );
+
+ if (PhyInfoPtr->PhyId == DP83840_0) {
+
+ //National's Phy Speed Sensing workaround:
+ //read the Speed_bit in the PAR register to sense
+ //the connection speed
+
+ if (PhyInfoPtr->PhyIntRoutines.PhyReadRegister(
+ Adapter,
+ PhyInfoPtr ,
+ NatPhyParRegister,
+ &Register
+ )) {
+
+ Ability = (LocalAbility &
+ ((Register & PAR_SPEED_10) ? MiiPhy10BaseT : MiiPhy100BaseTx ) >>6);
+#if MII_DBG
+ DbgPrint("National: Speed sense -> %s\n",
+ (Register & PAR_SPEED_10) ? "10Mbps" : "100Mbps" );
+#endif
+ }
+ }
+ else {
+ Ability = LocalAbility & PartnerAbility;
+ }
+
+ if (!(Ability)) {
+ LinkStatus = MEDIA_LINK_FAIL;
+ *ConnectionStatus = NwayStatus | LinkStatus;
+ return FALSE;
+ }
+ }
+
+ if (!(PhyInfoPtr->PhyRegs[PhyStatusReg] & MiiPhyLinkStatus)) {
+
+ // Link fail: Read again Status Reg
+ if (!PhyInfoPtr->PhyIntRoutines.PhyReadRegister(
+ Adapter,
+ PhyInfoPtr,
+ PhyStatusReg,
+ &(PhyInfoPtr->PhyRegs[PhyStatusReg])
+ )) {
+ return FALSE;
+ }
+
+ if (!(PhyInfoPtr->PhyRegs[PhyStatusReg] & MiiPhyLinkStatus)) {
+
+ // Link bit is still in Fail state
+ LinkStatus = MEDIA_LINK_FAIL;
+ }
+ else {
+#if MII_DBG
+ DbgPrint("LinkPass with Previous Failure\n");
+#endif
+ LinkStatus = MEDIA_LINK_PASS_WITH_PF;
+ }
+ }
+ else {
+ LinkStatus = MEDIA_LINK_PASS;
+ }
+
+ *ConnectionStatus = NwayStatus | LinkStatus;
+ return (LinkStatus != MEDIA_LINK_FAIL);
+
+}
+
+/*+
+ *
+ * MiiPhyAdminControl
+ *
+ * Description:
+ *
+ * Performs the Control command on the specified Phy.
+ * Control command can be one of the following:
+ * Reset - reset the PHY (returns it to defaults)
+ * PowerDown
+ * StandBy
+ * Operational
+ *
+ * Input parameters:
+ *
+ * PhyInfoPtr - PMII_PHY_INFO pointer to MII_PHY_INFO
+ * Control - MII_STATUS
+ *
+ * AdminControlConversionTable - used in this routine
+ *
+ * Output parameters:
+ *
+ * None.
+ *
+-*/
+extern
+void
+MiiPhyAdminControl(
+ PDC21X4_ADAPTER Adapter,
+ PMII_PHY_INFO PhyInfoPtr,
+ MII_STATUS Control
+ )
+{
+ MII_STATUS Status = MiiGenAdminReset;
+ INT i = 0;
+
+#if MII_DBG
+ DbgPrint("MiiPhyAdminControl\n");
+#endif
+
+ switch (Control) {
+
+ case MiiGenAdminForce10:
+ case MiiGenAdminForce10Fd:
+
+ PhyInfoPtr->PreviousControl = PhyInfoPtr->PhyRegs[PhyControlReg];
+ PhyInfoPtr->PhyRegs[PhyControlReg] &= MiiPhyCtrlForce10;
+ Adapter->Force10 = TRUE;
+ break;
+
+ case MiiGenAdminRelease10:
+
+ PhyInfoPtr->PhyRegs[PhyControlReg] = PhyInfoPtr->PreviousControl;
+ Adapter->Force10 = FALSE;
+ break;
+
+ default:
+ // Clear previous Control bits
+ PhyInfoPtr->PhyRegs[PhyControlReg] &= ~(MiiPhyCtrlReset |
+ MiiPhyCtrlPowerDown |
+ MiiPhyCtrlIsolate);
+ }
+
+ // Write Control register
+#if MII_DBG
+ DbgPrint("Write ControlReg = %04x\n",(PhyInfoPtr->PhyRegs[PhyControlReg]|
+ AdminControlConversionTable[Control]));
+#endif
+ PhyInfoPtr->PhyIntRoutines.PhyWriteRegister(
+ Adapter,
+ PhyInfoPtr,
+ PhyControlReg,
+ (PhyInfoPtr->PhyRegs[PhyControlReg] | AdminControlConversionTable[Control])
+ );
+
+ if (Control == MiiGenAdminReset) {
+ // Delay until reset done and chip stabilizes
+#if MII_DBG
+ DbgPrint("Control = Reset; Delay until done and chip stabilizes\n");
+#endif
+ while ( (i++) < RESET_DELAY ) {
+ PhyInfoPtr->PhyExtRoutines.PhyAdminStatus(
+ Adapter,
+ PhyInfoPtr,
+ &Status
+ );
+ if ( Status != MiiGenAdminReset ) {
+ break;
+ }
+
+ }
+#if MII_DBG
+ DbgPrint("Control = %x after Delay \n", Status);
+#endif
+ }
+
+ return;
+
+}
+
+
+/*+
+ *
+ * MiiPhyAdminStatus
+ *
+ * Description:
+ *
+ * Returns PHY admin status, which can be one of the following:
+ * Reset - reset process is in progress (not completed yet)
+ * PowerDown - Chip is in Power Down mode
+ * StandBy - Chip listening but not accessing mii data lines
+ * Operational - Chip is fully active
+ *
+ * Input parameters:
+ *
+ * PhyInfoPtr - PMII_PHY_INFO pointer to MII_PHY_INFO
+ *
+ * Output parameters:
+ *
+ * Status - MII_STATUS
+ *
+ *
+ * Note: Interrupts are disabled.
+ *
+-*/
+extern
+void
+MiiPhyAdminStatus(
+ PDC21X4_ADAPTER Adapter,
+ PMII_PHY_INFO PhyInfoPtr,
+ PMII_STATUS Status
+ )
+{
+
+ USHORT RegVal = 0;
+ SHORT i = 3;
+
+#if MII_DBG
+ DbgPrint("MiiPhyAdminStatus\n");
+#endif
+ // Reads 3 times to garanty that 0 is a real value
+ while (i--) {
+ PhyInfoPtr->PhyIntRoutines.PhyReadRegister(
+ Adapter,
+ PhyInfoPtr,
+ PhyControlReg,
+ &RegVal
+ );
+ if (RegVal) {
+ break;
+ }
+ }
+
+ switch (RegVal) {
+
+ case MiiPhyCtrlReset:
+
+ *Status = MiiGenAdminReset;
+ break;
+
+ case MiiPhyCtrlPowerDown:
+
+ *Status = MiiGenAdminPowerDown;
+ break;
+
+ case MiiPhyCtrlIsolate:
+
+ *Status = MiiGenAdminStandBy;
+ break;
+
+ default:
+
+ *Status = MiiGenAdminOperational;
+ }
+#if _DBG
+ DbgPrint("AdminStatus = %x\n", Status);
+#endif
+
+ return;
+}
+
+
+
+//***************************************************************************
+//* Mii PHY Internal Routines *
+//***************************************************************************
+/*+
+ *
+ * MiiPhyReadRegister
+ *
+ * Description:
+ *
+ * Reads contents of register RegNum into *Register.
+ *
+ * Input parameters:
+ *
+ * PDC21X4_ADAPTER - Adapter The Adapter DS.
+ * PhyInfoPtr - PMII_PHY_INFO pointer to MII_PHY_INFO
+ * RegNum - USHORT # of register to be read
+ *
+ * Output parameters:
+ *
+ * *Register - USHORT contents of RegNum
+ *
+ * On return - TRUE if reading completed successfully, FALSE otherwise.
+ *
+ *
+ *
+ * +-----------------------------------------------------------------------+
+ * | Management frame fields |
+ * +------+-------+----+----+-------+-------+----+------------------+------+
+ * | | PRE | ST | OP | PHYAD | REGAD | TA | DATA | IDLE |
+ * +------+-------+----+----+-------+-------+----+------------------+------+
+ * |Read | 1...1 | 01 | 10 | AAAAA | RRRRR | Z0 | DDDDDDDDDDDDDDDD | Z |
+ * +------+-------+----+----+-------+-------+----+------------------+------+
+ *
+ * Note: Interrupts are disabled.
+ *
+-*/
+extern
+BOOLEAN
+MiiPhyReadRegister(
+ PDC21X4_ADAPTER Adapter,
+ PMII_PHY_INFO PhyInfoPtr,
+ USHORT RegNum,
+ PUSHORT RegDat
+ )
+{
+ ULONG CommandWord;
+ ULONG Tmp = 0;
+ USHORT Data = 0;
+ INT i;
+ INT SizeOfUshort = ((sizeof(USHORT))*8);
+ BOOLEAN Succeed=TRUE;
+
+#if _DBG
+ DbgPrint("MiiPhyReadRegister\n");
+#endif
+ // Write Preamble
+ WriteMii(Adapter, PRE, 2*SizeOfUshort);
+
+ // Prepare command word
+ CommandWord = PhyInfoPtr->PhyAddress << PHY_ADDR_ALIGN;
+ CommandWord |= (RegNum << REG_ADDR_ALIGN);
+ CommandWord |= MII_READ_FRAME;
+#if _DBG
+ DbgPrint("CommandWord=%08x\n", CommandWord);
+#endif
+ WriteMii(Adapter, CommandWord, SizeOfUshort-2);
+
+ MiiOutThreeState(Adapter);
+
+ // Check that the PHY chip generated a zero bit the 2nd clock
+ DC21X4_READ_PORT(
+ DC21X4_IDPROM,
+ &Tmp
+ );
+
+ if (Tmp & MII_READ_DATA_MASK) {
+#if _DBG
+ DbgPrint("***No Zero bit generated after 3 states\n");
+#endif
+ Succeed = FALSE;
+ }
+
+ // read data WORD
+ (*RegDat) = 0;
+ for (i=0; i<SizeOfUshort; i++) {
+ DC21X4_WRITE_PORT(
+ DC21X4_IDPROM,
+ MII_READ
+ );
+ DELAY(MII_DELAY);
+ DC21X4_WRITE_PORT(
+ DC21X4_IDPROM,
+ (MII_READ | MII_CLK)
+ );
+ DELAY(MII_DELAY);
+ DC21X4_READ_PORT(
+ DC21X4_IDPROM,
+ &Tmp
+ );
+ DELAY(MII_DELAY);
+ Data = (USHORT) ((Tmp >> MII_MDI_BIT_POSITION) & 0x0001);
+ (*RegDat) = ((*RegDat) << 1) | Data;
+ }
+
+#if _DBG
+ DbgPrint("&RegData=%08x Reg[%d]=%04x\n", RegDat, RegNum, *RegDat);
+#endif
+ MiiOutThreeState(Adapter);
+
+ // clear reserved bits
+ (*RegDat) &= ~PhyRegsReservedBitsMasks[RegNum];
+#if _DBG
+ DbgPrint("After Mask, Reg[%d]=%04x\n", RegNum, *RegDat);
+#endif
+
+ return Succeed;
+}
+
+
+
+
+/*+
+ *
+ * MiiPhyWriteRegister
+ *
+ * Description:
+ *
+ * Writes contents of Register to register number RegNum.
+ *
+ * Input parameters:
+ *
+ * PhyInfoPtr - PMII_PHY_INFO pointer to MII_PHY_INFO
+ * RegNum - USHORT
+ * Register - USHORT
+ *
+ * Output parameters:
+ *
+ * None.
+ *
+ *
+ * +-----------------------------------------------------------------------+
+ * | Management frame fields |
+ * +------+-------+----+----+-------+-------+----+------------------+------+
+ * | | PRE | ST | OP | PHYAD | REGAD | TA | DATA | IDLE |
+ * +------+-------+----+----+-------+-------+----+------------------+------+
+ * |Write | 1...1 | 01 | 01 | AAAAA | RRRRR | 10 | DDDDDDDDDDDDDDDD | Z |
+ * +------+-------+----+----+-------+-------+----+------------------+------+
+ *
+ * Note: Interrupts are disabled.
+ *
+-*/
+extern
+void
+MiiPhyWriteRegister(
+ PDC21X4_ADAPTER Adapter,
+ PMII_PHY_INFO PhyInfoPtr,
+ USHORT RegNum,
+ USHORT Register
+ )
+{
+
+ ULONG CommandWord;
+ INT SizeOfUshort = ((sizeof(USHORT))*8);
+
+#if _DBG
+ DbgPrint("MiiPhyWriteRegister\n");
+#endif
+ // Clear reserved bits
+ Register &= ~PhyRegsReservedBitsMasks[RegNum];
+
+ WriteMii(Adapter, PRE, 2*SizeOfUshort);
+
+ // Prepare command word
+ CommandWord = (PhyInfoPtr->PhyAddress << PHY_ADDR_ALIGN);
+ CommandWord |= (RegNum << REG_ADDR_ALIGN);
+ CommandWord |= (MII_WRITE_FRAME | Register);
+
+#if _DBG
+ DbgPrint("CommandWord to write: %08x\n", CommandWord);
+#endif
+ WriteMii(Adapter, CommandWord, 2*SizeOfUshort);
+
+ MiiOutThreeState(Adapter);
+ return;
+}
+
+
+
+
+/*+
+ *
+ * MiiPhyNwayGetLocalAbility
+ *
+ * Description:
+ *
+ * Returns local abilities of the PHY according to the value
+ * written in Nway Local Abilities register.
+ *
+ * Input parameters:
+ *
+ * PhyInfoPtr - PMII_PHY_INFO pointer to MII_PHY_INFO
+ *
+ * Output parameters
+ *
+ * *Ability - NwayCapacity
+ *
+ *
+-*/
+extern
+void
+MiiPhyNwayGetLocalAbility(
+ PDC21X4_ADAPTER Adapter,
+ PMII_PHY_INFO PhyInfoPtr,
+ PCAPABILITY Ability
+ )
+{
+
+#if MII_DBG
+ DbgPrint("MiiPhyNwayGetLocalAbility\n");
+#endif
+
+ switch (PhyInfoPtr->PhyId) {
+
+ case BCM5000_0:
+
+ // Broadcom's PHY
+ *Ability = (PhyInfoPtr->PhyCapabilities >> 6);
+ break;
+
+ default:
+
+ if (PhyInfoPtr->PhyIntRoutines.PhyReadRegister(
+ Adapter,
+ PhyInfoPtr,
+ PhyNwayAdvertisement,
+ &(PhyInfoPtr->PhyRegs[PhyNwayAdvertisement])
+ )
+ ) {
+
+ *Ability = PhyInfoPtr->PhyRegs[PhyNwayAdvertisement] & MiiPhyNwayCapabilitiesMask;
+ }
+ else {
+ *Ability = 0;
+ }
+ }
+ return;
+
+}
+
+
+
+
+/*+
+ *
+ * MiiPhyNwaySetLocalAbility
+ *
+ * Description:
+ *
+ * Modifies the local PHY Local abilities Advertisement register value
+ * for the purpose of limiting the media connections to be negotiated
+ * (/sent) to the link partner.
+ *
+ * Input parameters:
+ *
+ * PhyInfoPtr - PMII_PHY_INFO
+ * MediaBits - USHORT
+ *
+ * Output parameters:
+ *
+ * None.
+ *
+ *
+-*/
+extern
+void
+MiiPhyNwaySetLocalAbility(
+ PDC21X4_ADAPTER Adapter,
+ PMII_PHY_INFO PhyInfoPtr,
+ USHORT MediaBits
+ )
+{
+
+#if MII_DBG
+ DbgPrint("MiiPhyNwaySetLocalAbility\n");
+#endif
+
+ if (PhyInfoPtr->PhyId != BCM5000_0){
+ PhyInfoPtr->PhyRegs[PhyNwayAdvertisement] =
+ (PhyInfoPtr->PhyMediaAdvertisement & MediaBits) |
+ NWAY_802_3_Selector;
+
+#if MII_DBG
+ DbgPrint("PhyInfoPtr->PhyRegs[PhyNwayAdvertisement] = %04x\n", PhyInfoPtr->PhyRegs[PhyNwayAdvertisement]);
+ DbgPrint("SROM Advertisement = %04x\n", MediaBits);
+#endif
+ PhyInfoPtr->PhyIntRoutines.PhyWriteRegister(
+ Adapter,
+ PhyInfoPtr,
+ PhyNwayAdvertisement,
+ PhyInfoPtr->PhyRegs[PhyNwayAdvertisement]
+ );
+ }
+ return;
+}
+
+
+
+
+
+
+/*+
+ *
+ * MiiPhyNwayGetPartnerAbility
+ *
+ * Description:
+ *
+ * Returns link partner abilities as written in the link partner
+ * abilities register (which reflects link partner's Advertisement
+ * register).
+ * Input parameters:
+ *
+ * PhyInfoPtr - PMII_PHY_INFO pointer to struct with PHY info
+ *
+ * Output parameters:
+ *
+ * *Ability - NWayAbility pointer to partner abilities
+ *
+ *
+ * A value of 0 will be returned If link partner is not Nway capable or
+ * does not support any known medium.
+ *
+-*/
+extern
+void
+MiiPhyNwayGetPartnerAbility(
+ PDC21X4_ADAPTER Adapter,
+ PMII_PHY_INFO PhyInfoPtr,
+ PCAPABILITY Ability
+ )
+{
+
+#if MII_DBG
+ DbgPrint("MiiPhyNwayGetPartnerAbility\n");
+#endif
+ if (PhyInfoPtr->PhyIntRoutines.PhyReadRegister(
+ Adapter,
+ PhyInfoPtr,
+ PhyNwayLinkPartnerAbility,
+ &(PhyInfoPtr->PhyRegs[PhyNwayLinkPartnerAbility])
+ )
+ ) {
+
+ PhyInfoPtr->PhyRegs[PhyNwayLinkPartnerAbility] &= MiiPhyNwayCapabilitiesMask;
+ *Ability = PhyInfoPtr->PhyRegs[PhyNwayLinkPartnerAbility];
+ }
+ else {
+ *Ability = 0;
+ }
+ return;
+
+}
+
+
+
+/*+
+ *
+ * FindMiiPhyDevice
+ *
+ * Description:
+ *
+ * Receives MII PHY address and checks if a PHY exists there.
+ * PhyInfotPtr->PhyAddress holds the PHY address
+ *
+ * Input parameter:
+ *
+ * PhyInfoPtr - PMII_PHY_INFO pointer to struct with PHY info
+ *
+ * Return value:
+ *
+ * FALSE - if no such PHY is found
+ * TRUE - otherwise
+ *
+ *****************************************************************************/
+extern
+BOOLEAN
+FindMiiPhyDevice(
+ PDC21X4_ADAPTER Adapter,
+ PMII_PHY_INFO PhyInfoPtr
+ )
+{
+ USHORT RegOffset;
+ USHORT RegData;
+
+#if MII_DBG
+ DbgPrint("FindMiiPhyDevice\n");
+#endif
+
+ // Read PHY's Registers
+
+ //The first two registers are mandatory
+ for (RegOffset=0; RegOffset<=PhyStatusReg; RegOffset++) {
+ if(PhyInfoPtr->PhyIntRoutines.PhyReadRegister(
+ Adapter,
+ PhyInfoPtr,
+ RegOffset,
+ &RegData
+ ) ){
+ PhyInfoPtr->PhyRegs[RegOffset] = RegData;
+ }
+ else {
+ return FALSE;
+ }
+ }
+
+ // Read the Phy's Id Registers
+ for (; RegOffset<=PhyId_2; RegOffset++) {
+ if(PhyInfoPtr->PhyIntRoutines.PhyReadRegister(
+ Adapter,
+ PhyInfoPtr,
+ RegOffset,
+ &RegData
+ ) ){
+ PhyInfoPtr->PhyRegs[RegOffset] = RegData;
+ }
+ else {
+ break;
+ }
+ }
+ if (RegOffset > PhyId_2) {
+ PhyInfoPtr->PhyId =
+ (PhyInfoPtr->PhyRegs[PhyId_1] <<16) | PhyInfoPtr->PhyRegs[PhyId_2];
+ }
+
+
+ //Read the remaining registers
+ for (RegOffset=PhyNwayAdvertisement; RegOffset<MAX_PHY_REGS; RegOffset++) {
+ if(PhyInfoPtr->PhyIntRoutines.PhyReadRegister(
+ Adapter,
+ PhyInfoPtr,
+ RegOffset,
+ &RegData
+ ) ){
+ PhyInfoPtr->PhyRegs[RegOffset] = RegData;
+ }
+ else {
+ break;
+ }
+ }
+
+ //Check if the required number of registers have been read
+ //successfully
+
+ switch (PhyInfoPtr->PhyId) {
+
+ case BCM5000_0 :
+ case DP83840_0 :
+
+ if (RegOffset < MAX_PHY_REGS) {
+ return FALSE;
+ }
+ break;
+
+ default:
+
+ if ( ( (PhyInfoPtr->PhyRegs[PhyStatusReg] | MiiPhyNwayCapable)
+ && (RegOffset <= PhyNwayLinkPartnerAbility)
+ )
+ || ( (PhyInfoPtr->PhyRegs[PhyNwayAdvertisement] | MiiPhyNwayNextPageAble)
+ && (RegOffset <= PhyNwayExpansion )
+ )
+ ){
+ return FALSE;
+ }
+ break;
+ }
+
+#if MII_DBG
+ DbgPrint("Device PhyId= %08x\n", PhyInfoPtr->PhyId);
+ DbgPrint("PhyStatusReg= %04x\n", PhyInfoPtr->PhyRegs[PhyStatusReg]);
+#endif
+
+ //return FALSE if the Status Register is all 0's
+ //otherwise return TRUE;
+
+ return (PhyInfoPtr->PhyRegs[PhyStatusReg] !=0);
+
+}
+
+
+/*+
+ *
+ * WriteMii
+ *
+ * Description:
+ *
+ * Writes the data size bits from the MiiData to the Mii control lines.
+ *
+ * Input parameters
+ * MiiData - The data to be written
+ * DataSize - The number of bits to write
+ *
+ * Output parameters
+ * None.
+ *
+ * Return Value
+ * TRUE if success, FALSE if hardware failure encountered.
+ *
+-*/
+extern
+void
+WriteMii(
+ PDC21X4_ADAPTER Adapter,
+ ULONG MiiData,
+ int DataSize
+ )
+{
+
+ INT i;
+ ULONG Dbit;
+
+#if _DBG
+ DbgPrint("WriteMii\n");
+ DbgPrint("PHY: Data to write = %08x\n", MiiData);
+#endif
+
+ // Write the data to the PHY
+
+ for (i = DataSize; i> 0; i--) {
+
+ Dbit = ((MiiData >> (31-MII_MDO_BIT_POSITION)) & MII_MDO_MASK);
+
+ DC21X4_WRITE_PORT(
+ DC21X4_IDPROM,
+ MII_WRITE | Dbit
+ );
+
+ DELAY(MII_DELAY);
+
+ DC21X4_WRITE_PORT(
+ DC21X4_IDPROM,
+ MII_WRITE | MII_CLK | Dbit
+ );
+
+ DELAY(MII_DELAY);
+
+ MiiData = MiiData << 1;
+ }
+
+
+}
+
+
+
+
+/*+**************************************************************************
+ *
+ * MiiOutThreeState
+ *
+ * Description:
+ *
+ * Puts the MDIO port in threestate for the turn around bits
+ * in MII read and at end of MII management sequence.
+ *
+ * Parameters
+ * None.
+ *
+-*/
+extern
+void
+MiiOutThreeState(
+ PDC21X4_ADAPTER Adapter
+ )
+{
+
+#if _DBG
+ DbgPrint("MiiOutThreeState\n");
+#endif
+ DC21X4_WRITE_PORT(
+ DC21X4_IDPROM,
+ MII_WRITE_TS
+ );
+ DELAY(MII_DELAY);
+ DC21X4_WRITE_PORT(
+ DC21X4_IDPROM,
+ (MII_WRITE_TS | MII_CLK)
+ );
+ DELAY(MII_DELAY);
+
+ return;
+}
+
+/*+
+ *
+ * InitPhyInfoEntries
+ *
+ * Description:
+ *
+ * Initializes the MII PHY struct by directing pointers of struct
+ * routines to routines addresses.
+ * (these addresses cannot be resolved at compile time).
+ *
+ * Parameter:
+ *
+ * PhyInfoPtr - PMII_PHY_INFO pointer to struct with PHY info
+ *
+ *
+-*/
+extern
+void
+InitPhyInfoEntries(
+ PMII_PHY_INFO PhyInfoPtr
+ )
+{
+ NDIS_STATUS NdisStatus;
+
+#if MII_DBG
+ DbgPrint("InitPhyInfoEntries\n");
+#endif
+
+ PhyInfoPtr->PhyExtRoutines.PhyInit = (void *)MiiPhyInit;
+ PhyInfoPtr->PhyExtRoutines.PhyGetCapabilities = (void *)MiiPhyGetCapabilities;
+ PhyInfoPtr->PhyExtRoutines.PhySetConnectionType = (void *)MiiPhySetConnectionType;
+ PhyInfoPtr->PhyExtRoutines.PhyGetConnectionType = (void *)MiiPhyGetConnectionType;
+ PhyInfoPtr->PhyExtRoutines.PhyGetConnectionStatus = (void *)MiiPhyGetConnectionStatus;
+ PhyInfoPtr->PhyExtRoutines.PhyAdminControl = (void *)MiiPhyAdminControl;
+ PhyInfoPtr->PhyExtRoutines.PhyAdminStatus = (void *)MiiPhyAdminStatus;
+
+ PhyInfoPtr->PhyIntRoutines.PhyReadRegister = (void *)MiiPhyReadRegister;
+ PhyInfoPtr->PhyIntRoutines.PhyWriteRegister = (void *)MiiPhyWriteRegister;
+ PhyInfoPtr->PhyIntRoutines.PhyNwayGetLocalAbility = (void *)MiiPhyNwayGetLocalAbility;
+ PhyInfoPtr->PhyIntRoutines.PhyNwaySetLocalAbility = (void *)MiiPhyNwaySetLocalAbility;
+ PhyInfoPtr->PhyIntRoutines.PhyNwayGetPartnerAbility = (void *)MiiPhyNwayGetPartnerAbility;
+
+ return;
+}
+
+/*+
+ *
+ * ConvertConnectionToControl
+ *
+ * Input parameters
+ * PhyInfoPtr - PMII_PHY_INFO pointer to struct with PHY info
+ * Connection - ConnectionType
+ *
+ * Output parameters
+ * Converted Connection - ConnectionType
+ *
+ * Note: Interrupts are disabled.
+ *
+-*/
+extern
+void
+ConvertConnectionToControl(
+ PMII_PHY_INFO PhyInfotPtr,
+ PUSHORT Connection
+ )
+{
+
+ USHORT OM_bits = ((*Connection) & CONTROL_MASK);
+
+#if MII_DBG
+ DbgPrint("ConvertConnectionToControl\n");
+ DbgPrint("Before Conversion: Connection = %04x\n", *Connection);
+#endif
+ // Convert Media Type to control bits
+
+ *Connection = MediaToCommandConversionTable[*Connection & MEDIA_MASK];
+
+ // Check if Nway bits are also needed
+
+ if (( OM_bits & (MEDIA_NWAY | MEDIA_AUTOSENSE))) {
+
+ // Autosense or Nway are required:
+
+ switch (PhyInfotPtr->PhyId) {
+
+ default:
+
+ *Connection |= MiiPhyCtrlRestartNway;
+
+ case BCM5000_0:
+
+ *Connection |= MiiPhyCtrlEnableNway;
+ }
+
+ }
+
+#if MII_DBG
+ DbgPrint("After Conversion: Connection = %04x\n", *Connection);
+#endif
+
+ return;
+
+}
+
+
+/*+
+ *
+ * ConvertMediaTypeToNwayLocalAbility
+ *
+ * Input parameters
+ * MediaType - USHORT (in SROM format)
+ *
+ * Output parameters
+ * NwayLocalAbility - CAPABILITY
+ *
+-*/
+extern
+void
+ConvertMediaTypeToNwayLocalAbility(
+ USHORT MediaType,
+ PCAPABILITY NwayLocalAbility
+ )
+{
+
+#if MII_DBG
+ DbgPrint("ConvertMediaTypeToNwayLocalAbility\n");
+ DbgPrint("MediaType = %04x\n", MediaType);
+#endif
+
+ // Convert MediaType to Nway Advertisement bits
+
+ *NwayLocalAbility = MediaToNwayConversionTable[(MediaType & MEDIA_MASK)];
+#if MII_DBG
+ DbgPrint("NwayLocalAbility = %04x\n", *NwayLocalAbility);
+#endif
+ return;
+
+}
+
+/*+
+ *
+ * ConvertNwayToConnectionType
+ *
+ * Description:
+ *
+ * Returns highest precedence media type whose bit is set in Nway
+ * word, according to the following table:
+ * +----+---------------------------+--------+
+ * |Bit | Technology |Priority|
+ * +----+---------------------------+--------+
+ * | A0 | 10Base-T (Half-Duplex) | 5(LSP) |
+ * +----+---------------------------+--------+
+ * | A1 | 10Base-T Full-Duplex | 4 |
+ * +----+---------------------------+--------+
+ * | A2 | 100Base-TX (Half-Duplex) | 3 |
+ * +----+---------------------------+--------+
+ * | A3 | 100Base-TX Full-Duplex | 1(MSP) |
+ * +----+---------------------------+--------+
+ * | A4 | 100Base-T4 | 2 |
+ * +----+---------------------------+--------+
+ *
+ *On Entry:
+ * NwayReg - Nway register bits (in Advertisement format).
+ *On Return:
+ * NwayReg - The converted ConnectionType
+ *
+ *Return Value
+ * FALSE - No Media Found
+ * TRUE - Media found and returned in NwayReg
+ *
+-*/
+extern
+BOOLEAN
+ConvertNwayToConnectionType(
+ CAPABILITY NwayReg,
+ PUSHORT Connection
+ )
+{
+
+#if MII_DBG
+ DbgPrint("ConvertNwayToConnectionType\n");
+#endif
+ if (NwayReg & MiiPhyNway100BaseTxFD) {
+ // 100BaseTx FD
+ *Connection = (MediumMii100BaseTxFullDuplex | MediaAutoSense);
+ }
+ else if (NwayReg & MiiPhyNway100BaseT4) {
+ // 100BaseT4
+ *Connection = (MediumMii100BaseT4 | MediaAutoSense);
+ }
+ else if (NwayReg & MiiPhyNway100BaseTx) {
+ // 100BaseTx
+ *Connection = (MediumMii100BaseTx | MediaAutoSense);
+ }
+ else if (NwayReg & MiiPhyNway10BaseTFD) {
+ // 10BaseT FD
+ *Connection = (MediumMii10BaseTFullDuplex | MediaAutoSense);
+ }
+ else if (NwayReg & MiiPhyNway10BaseT) {
+ // 10BaseT
+ *Connection = (MediumMii10BaseT | MediaAutoSense);
+ }
+ else {
+ // No media found
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+/*+
+ *
+ * CheckConnectionSupport
+ *
+ * Input parameters:
+ *
+ * PhyInfoPtr - PMII_PHY_INFO pointer to struct with PHY info
+ * MiiMediaCapable - Mii Media capability mask from the SROM
+ * ConCommand - Connection command bits (in SROM format)
+ *
+ * Return value:
+ *
+ * FALSE - Connection NOT supported
+ * TRUE - Connection supported
+ *
+-*/
+extern
+BOOLEAN
+CheckConnectionSupport(
+ PMII_PHY_INFO PhyInfoPtr,
+ USHORT ConCommand
+ )
+{
+ USHORT StatusBits;
+
+#if MII_DBG
+ DbgPrint("CheckConnectionSupport\n");
+#endif
+
+ if ((ConCommand & (MEDIA_NWAY | MEDIA_AUTOSENSE))){
+ //NWAY or AutoSense are required
+#if MII_DBG
+ DbgPrint("NWAY or AutoSensing\n");
+#endif
+ return ((PhyInfoPtr->PhyCapabilities & MiiPhyNwayCapable) != 0);
+ }
+
+ //Convert media to status bits
+
+ StatusBits = MediaToStatusConversionTable[(ConCommand & MEDIA_MASK)];
+#if MII_DBG
+ DbgPrint("Before Conversion: ConCommand = %04x\n", ConCommand);
+ DbgPrint("After Conversion: StatusBits = %04x\n", StatusBits);
+#endif
+
+ //Return TRUE if the requested medium is supported by the PHY
+
+ return ((StatusBits & PhyInfoPtr->PhyCapabilities) != 0);
+
+}
+
+
+
+
+
+
+
+
+
+
+//****************************************************************************
+//* Broadcom support routines *
+//****************************************************************************
+
+/*+
+ *Broadcom extended register (address 16)
+ *---------------------------------------
+ *
+ * +-----+----------------+---------------------------+-----------------------------+
+ * | Bit | Name | Description | Comments |
+ * +-----+----------------+---------------------------+-----------------------------+
+ * | 15 | JABDIS |1=Jubber Disabled | Default 0 (R/W) |
+ * | | |1=Jubber Enabled | |
+ * +-----+----------------+---------------------------+-----------------------------+
+ * | 14 | LINKDIS |1=Link test Disabled | Default 0 (R/W) |
+ * | | |0=Link test Enabled | |
+ * +-----+----------------+---------------------------+-----------------------------+
+ * |13-9 | reserved | |Write as 0, Ignore on read |
+ * +-----+----------------+---------------------------+-----------------------------+
+ * | 8 |FORCEFAIL_EN |1=Force fail enabled | Default 1 (R/W) |
+ * | | |0=Force fail disabled | |
+ * +-----+----------------+---------------------------+-----------------------------+
+ * | 7-5 |RV_CNTR |Revision control indicator | Value is 000 (RO) |
+ * +-----+----------------+---------------------------+-----------------------------+
+ * | 4-3 |HSQ:LSQ |Defines the squelch mode of|10=High squelch, 00=Normal |
+ * | | |the carrier sense mechanism|01=Low Squelch,11=Not allowed|
+ * | | | |Default 00 (R/W) |
+ * +-----+----------------+---------------------------+-----------------------------+
+ * | 2 |TXDAC power mode| |Default 0 (R/W) |
+ * +-----+----------------+---------------------------+-----------------------------+
+ * | 1 |Speed Indication|1 = 100Mbps mode |Default 0 RO |
+ * | | |0 = 10Mbps mode | |
+ * +-----+----------------+---------------------------+-----------------------------+
+ * | 0 |reserved | | |
+ * +-----+----------------+---------------------------+-----------------------------+
+-*/
+
+
+
+
+
+/*+
+ *
+ * HandleBroadcomMediaChangeFrom10To100
+ *
+ * Description:
+ *
+ * Handle Broadcom special requirements for speed change from 10 to 100 Mbps
+ *
+ * Input parameters:
+ *
+ * PhyInfoPtr - PMII_PHY_INFO pointer to struct with PHY info
+ *
+ * Output parameters:
+ *
+ * None.
+ *
+ *
+-*/
+extern
+void
+HandleBroadcomMediaChangeFrom10To100(
+ PDC21X4_ADAPTER Adapter,
+ PMII_PHY_INFO PhyInfoPtr
+ )
+{
+
+ USHORT Register;
+
+#if MII_DBG
+ DbgPrint("HandleBroadcomMediaChangeFrom10To100\n");
+#endif
+ PhyInfoPtr->PhyIntRoutines.PhyReadRegister(
+ Adapter,
+ PhyInfoPtr,
+ MII_BROADCOM_EXTENDED_REG_ADDRESS,
+ &Register
+ );
+
+ if ( (Register != PhyInfoPtr->PhyRegs[MII_BROADCOM_EXTENDED_REG_ADDRESS])
+ && (Register & BROADCOM_EXT_REG_FORCE_FAIL_EN_MASK)
+ && (Register & BROADCOM_EXT_REG_SPEED_MASK)
+ && !( PhyInfoPtr->PhyRegs[MII_BROADCOM_EXTENDED_REG_ADDRESS]
+ & BROADCOM_EXT_REG_SPEED_MASK
+ )
+ ) {
+ // Speed has changed :
+ // reset the PHY and restore the old control value
+#if MII_DBG
+ DbgPrint("Speed has changed; reset PHY and restore old ctrl value\n");
+#endif
+ PhyInfoPtr->PhyExtRoutines.PhyAdminControl(
+ Adapter,
+ PhyInfoPtr,
+ MiiGenAdminReset
+ );
+ PhyInfoPtr->PhyIntRoutines.PhyWriteRegister(
+ Adapter,
+ PhyInfoPtr,
+ PhyControlReg,
+ PhyInfoPtr->PhyRegs[PhyControlReg]
+ );
+ }
+ PhyInfoPtr->PhyRegs[MII_BROADCOM_EXTENDED_REG_ADDRESS] = Register;
+
+ return;
+}
+
+
+
+
+
+
+/*+
+ *
+ * GetBroadcomPhyConnectionType
+ *
+ * Description:
+ *
+ * Returns connection type, which may be one of the following:
+ * T4
+ * Tp
+ * TpFD
+ *
+ * Input parameters:
+ *
+ * PhyInfoPtr - PMII_PHY_INFO pointer to struct with PHY info
+ *
+ * Output parameters:
+ *
+ * Connection - ConnectionType
+ *
+ * On return
+ * Returns TRUE if
+ *
+-*/
+extern
+BOOLEAN
+GetBroadcomPhyConnectionType(
+ PDC21X4_ADAPTER Adapter,
+ PMII_PHY_INFO PhyInfoPtr,
+ PUSHORT Connection
+ )
+{
+
+ USHORT Register;
+
+#if MII_DBG
+ DbgPrint("GetBroadcomPhyConnectionType\n");
+#endif
+ if (!PhyInfoPtr->PhyIntRoutines.PhyReadRegister(
+ Adapter,
+ PhyInfoPtr,
+ MII_BROADCOM_EXTENDED_REG_ADDRESS,
+ &Register
+ )) {
+ return FALSE;
+ }
+
+ if ((Register & BROADCOM_EXT_REG_FORCE_FAIL_EN_MASK) == 0){
+ return FALSE;
+ }
+
+ if (!PhyInfoPtr->PhyIntRoutines.PhyReadRegister(
+ Adapter,
+ PhyInfoPtr,
+ PhyControlReg,
+ &(PhyInfoPtr->PhyRegs[PhyControlReg])
+ )) {
+ return FALSE;
+ }
+
+ if (Register & BROADCOM_EXT_REG_SPEED_MASK){
+ // Speed is 100Mbps
+ *Connection = MediumMii100BaseT4;
+ }
+ else {
+ // Speed is 10Mbps
+ *Connection =
+ (PhyInfoPtr->PhyRegs[PhyControlReg] & MiiPhyCtrlDuplexMode) ?
+ MediumMii10BaseTFullDuplex : MediumMii10BaseT;
+ }
+
+ if (PhyInfoPtr->PhyRegs[PhyControlReg] & MiiPhyCtrlEnableNway) {
+ *Connection |= (MEDIA_AUTOSENSE | MEDIA_NWAY);
+ }
+#if MII_DBG
+ DbgPrint("ConnectionType= %04x\n", *Connection);
+#endif
+
+ return TRUE;
+}
+
diff --git a/private/ntos/ndis/dc21x4/monitor.c b/private/ntos/ndis/dc21x4/monitor.c
new file mode 100644
index 000000000..fafb162e2
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/monitor.c
@@ -0,0 +1,354 @@
+/*+
+ * file: monitor.c
+ *
+ * Copyright (C) 1992-1995 by
+ * Digital Equipment Corporation, Maynard, Massachusetts.
+ * All rights reserved.
+ *
+ * This software is furnished under a license and may be used and copied
+ * only in accordance of the terms of such license and with the
+ * inclusion of the above copyright notice. This software or any other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person. No title to and ownership of the software is hereby
+ * transferred.
+ *
+ * The information in this software is subject to change without notice
+ * and should not be construed as a commitment by digital equipment
+ * corporation.
+ *
+ * Digital assumes no responsibility for the use or reliability of its
+ * software on equipment which is not supplied by digital.
+ *
+ *
+ * Abstract: This file is part of the NDIS 4.0 miniport driver for DEC's
+ * DC21X4 Ethernet adapter.
+ *
+ * Author: Philippe Klein
+ *
+ * Revision History:
+ *
+ * phk 28-Aug-1994 initial entry
+ *
+-*/
+
+#include <precomp.h>
+
+
+
+
+
+/*+
+ *
+ * DC21X4ModerateInterrupt
+ *
+ * Routine Description:
+ *
+ * Enable/Disable Rcv & Txm interrups based on the
+ * Rcv+Txm frames/second rate
+ *
+ * Arguments:
+ *
+ * Adapter
+ *
+-*/
+extern
+VOID
+DC21X4ModerateInterrupt (
+ IN PVOID Systemspecific1,
+ IN PDC21X4_ADAPTER Adapter,
+ IN PVOID Systemspecific2,
+ IN PVOID Systemspecific3
+ )
+{
+
+ INT FrameCount;
+ INT FrameRate;
+ INT InterruptRate;
+ ULONG CFDA_Data;
+
+
+ //snapshot the number of frames processed and the number of
+ // interrupt handled during the last monitor interval
+
+ FrameCount = Adapter->GeneralMandatory[GM_RECEIVE_OK]
+ + Adapter->GeneralMandatory[GM_RECEIVE_ERROR]
+ + Adapter->GeneralMandatory[GM_TRANSMIT_OK]
+ + Adapter->GeneralMandatory[GM_TRANSMIT_ERROR];
+
+ FrameRate = FrameCount - Adapter->FrameCount;
+
+ InterruptRate = Adapter->InterruptCount - Adapter->LastInterruptCount;
+
+ //save the snapshots
+
+ Adapter->FrameCount = FrameCount;
+ Adapter->LastInterruptCount = Adapter->InterruptCount;
+
+
+ if (InterruptRate > Adapter->InterruptThreshold) {
+ switch (Adapter->InterruptModeration) {
+
+ case NoInterruptMasked:
+
+ //Mask the Txm Interrupts
+ Adapter->InterruptModeration = TxmInterruptMasked;
+
+ Adapter->InterruptMask &= ~(DC21X4_TXM_INTERRUPTS);
+
+ DC21X4_WRITE_PORT(
+ DC21X4_INTERRUPT_MASK,
+ Adapter->InterruptMask
+ );
+
+ //Start the built_in timer to poll the Txm descriptor ring
+
+ // If the adapter is in Snooze mode,
+ // switch to regular mode to enable the
+ // built-in timer
+
+ if (Adapter->PciDriverArea & CFDA_SNOOZE_MODE) {
+
+ CFDA_Data = Adapter->PciDriverArea & ~CFDA_SNOOZE_MODE;
+
+ NdisWritePciSlotInformation(
+ Adapter->MiniportAdapterHandle,
+ Adapter->SlotNumber,
+ PCI_CFDA_OFFSET,
+ &CFDA_Data,
+ sizeof(CFDA_Data)
+ );
+ }
+
+ Adapter->Polling = Adapter->TxmPolling;
+ DC21X4_WRITE_PORT(
+ DC21X4_TIMER,
+ Adapter->Polling
+ );
+ break;
+
+ case TxmInterruptMasked:
+
+ //Mask the Rcv Interrupts
+ Adapter->InterruptModeration = TxmRcvInterruptMasked;
+
+ Adapter->InterruptMask &= ~(DC21X4_RCV_INTERRUPTS);
+
+ DC21X4_WRITE_PORT(
+ DC21X4_INTERRUPT_MASK,
+ Adapter->InterruptMask
+ );
+
+ //Restart the built_in timer to poll the Rcv & Txm descriptor rings
+
+ Adapter->Polling = Adapter->RcvTxmPolling;
+ DC21X4_WRITE_PORT(
+ DC21X4_TIMER,
+ Adapter->Polling
+ );
+ break;
+ }
+
+ }
+
+ else if (FrameRate < Adapter->FrameThreshold) {
+ switch (Adapter->InterruptModeration) {
+
+ case TxmRcvInterruptMasked:
+
+ //Demask the Rcv Interrupts
+
+ Adapter->InterruptModeration = TxmInterruptMasked;
+
+ Adapter->InterruptMask |= DC21X4_RCV_INTERRUPTS;
+
+ DC21X4_WRITE_PORT(
+ DC21X4_INTERRUPT_MASK,
+ Adapter->InterruptMask
+ );
+
+ //Restart the built_in timer to poll the Txm descriptor ring
+ Adapter->Polling = Adapter->TxmPolling;
+ DC21X4_WRITE_PORT(
+ DC21X4_TIMER,
+ Adapter->Polling
+ );
+ break;
+
+ case TxmInterruptMasked:
+
+ //Demask the Txm Interrupts
+ Adapter->InterruptModeration = NoInterruptMasked;
+
+ Adapter->InterruptMask |= DC21X4_TXM_INTERRUPTS;
+
+ DC21X4_WRITE_PORT(
+ DC21X4_INTERRUPT_MASK,
+ Adapter->InterruptMask
+ );
+
+ //Stop the Polling timer
+
+ Adapter->Polling = 0;
+
+ DC21X4_WRITE_PORT(
+ DC21X4_TIMER,
+ Adapter->Polling
+ );
+
+ if (Adapter->PciDriverArea & CFDA_SNOOZE_MODE) {
+
+ //set to the initial snooze mode
+
+ NdisWritePciSlotInformation(
+ Adapter->MiniportAdapterHandle,
+ Adapter->SlotNumber,
+ PCI_CFDA_OFFSET,
+ &Adapter->PciDriverArea,
+ sizeof(Adapter->PciDriverArea)
+ );
+ }
+
+ break;
+ }
+
+ }
+
+ //Restart the interrupt monitor timer
+
+ NdisMSetTimer(
+ &Adapter->MonitorTimer,
+ INT_MONITOR_PERIOD
+ );
+
+ }
+
+
+
+
+
+ /*+
+ *
+ * DC21X4CheckforHang
+ *
+ * Routine Description:
+ *
+ * The DC21X4CheckforHang routine verifies that no unprocessed descriptor
+ * are left due to the interrupt synchronization on PCI where the
+ * interrupt posted by DC21X4 can be handled before the associated
+ * descriptor has been effectively closed into memory.
+ *
+ * The algorithm is as follows:
+ *
+ * if "current" Rx descriptor is owned by the host
+ * if current Rx_frame_count == snapshoted Rx_frame_count
+ * generate an interrupt
+ * else
+ * snashots the current Rx_frame_count
+ *
+ * if "current" Tx descriptor is owned by the host
+ * if current Tx_frame_count == snapshoted Tx_frame_count
+ * generate an interrupt
+ * else
+ * snashots the current Tx_frame_count
+ *
+ * Arguments:
+ *
+ * Adapter
+ *
+ * Return Value:
+ *
+ * None
+ *
+ -*/
+ extern
+ BOOLEAN
+ DC21X4CheckforHang(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+ {
+
+ PDC21X4_ADAPTER Adapter;
+ INT TransmitFrameCount;
+ INT ReceiveFrameCount;
+
+ PDC21X4_RECEIVE_DESCRIPTOR ReceiveDescriptor;
+ PDC21X4_TRANSMIT_DESCRIPTOR TransmitDescriptor;
+
+ BOOLEAN GenerateInterrupt = FALSE;
+
+ Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
+
+ if (Adapter->Polling) {
+ return FALSE;
+ }
+
+ ReceiveDescriptor = Adapter->DequeueReceiveDescriptor;
+
+ if ((ReceiveDescriptor->Status & DC21X4_RDES_OWN_BIT) == DESC_OWNED_BY_SYSTEM ) {
+
+ ReceiveFrameCount = Adapter->GeneralMandatory[GM_RECEIVE_OK]
+ + Adapter->GeneralMandatory[GM_RECEIVE_ERROR];
+
+ GenerateInterrupt = (ReceiveFrameCount == Adapter->ReceiveFrameCount);
+
+ Adapter->ReceiveFrameCount = ReceiveFrameCount;
+
+ }
+
+ TransmitDescriptor = Adapter->DequeueTransmitDescriptor;
+
+ if (Adapter->GeneralOptional[GO_TRANSMIT_QUEUE_LENGTH] &&
+ ((TransmitDescriptor->Status & DC21X4_TDES_OWN_BIT) == DESC_OWNED_BY_SYSTEM)) {
+
+ TransmitFrameCount = Adapter->GeneralMandatory[GM_TRANSMIT_OK]
+ + Adapter->GeneralMandatory[GM_TRANSMIT_ERROR];
+
+ GenerateInterrupt = GenerateInterrupt ||
+ (TransmitFrameCount == Adapter->TransmitFrameCount);
+
+ Adapter->TransmitFrameCount = TransmitFrameCount;
+
+ }
+
+ if (GenerateInterrupt) {
+
+
+ switch (Adapter->DeviceId) {
+
+ case DC21040_CFID:
+
+ //Stop/start the Txm process to generate an Txm interrupt
+#if _DBG
+ DbgPrint("Stop/Start Txm\n");
+#endif
+ DC21X4_WRITE_PORT(
+ DC21X4_OPERATION_MODE,
+ Adapter->OperationMode & ~(DC21X4_TXM_START)
+ );
+
+ DC21X4_WRITE_PORT(
+ DC21X4_OPERATION_MODE,
+ Adapter->OperationMode
+ );
+ break;
+
+ default:
+
+ // Start the DC21X4 built_in timer to generate
+ // an Timer_expired interrupt
+
+ DC21X4_WRITE_PORT(
+ DC21X4_TIMER,
+ 1
+ );
+
+ }
+
+ }
+
+ return FALSE;
+
+ }
+
+
+
diff --git a/private/ntos/ndis/dc21x4/precomp.h b/private/ntos/ndis/dc21x4/precomp.h
new file mode 100644
index 000000000..147d76a53
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/precomp.h
@@ -0,0 +1,9 @@
+#include <ndis.h>
+#include <efilter.h>
+#include <mii.h>
+#include <d21x4det.h>
+#include <d21x4hrd.h>
+#include <d21x4def.h>
+#include <d21x4fct.h>
+#include <d21x4oid.h>
+
diff --git a/private/ntos/ndis/dc21x4/register.c b/private/ntos/ndis/dc21x4/register.c
new file mode 100644
index 000000000..113d34b3f
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/register.c
@@ -0,0 +1,2469 @@
+/*+
+ * file: register.c
+ *
+ * Copyright (C) 1992-1995 by
+ * Digital Equipment Corporation, Maynard, Massachusetts.
+ * All rights reserved.
+ *
+ * This software is furnished under a license and may be used and copied
+ * only in accordance of the terms of such license and with the
+ * inclusion of the above copyright notice. This software or any other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person. No title to and ownership of the software is hereby
+ * transferred.
+ *
+ * The information in this software is subject to change without notice
+ * and should not be construed as a commitment by digital equipment
+ * corporation.
+ *
+ * Digital assumes no responsibility for the use or reliability of its
+ * software on equipment which is not supplied by digital.
+ *
+ *
+ * Abstract: This file contains the Adapter Registration code of the
+ * NDIS 4.0 miniport driver for DEC's DC21X4 Ethernet Adapter
+ * family.
+ *
+ * Author: Philippe Klein
+ *
+ * Revision History:
+ *
+ * phk 31-Jul-95 Initial entry
+ * phk 12-Jan-95 V2.0 Add DC21041
+ * Add Win95 and PowerPC fixes to the miniport
+ * phk 20-Feb-95 Add "sonic" callback for MIPS platforms
+ * phk 23-Feb-95 Fix MediaType retrieval from Eisa ECU data
+ *
+-*/
+
+#include <precomp.h>
+#include <d21x4rgs.h>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#ifdef _MIPS_
+
+// Global variables used to keep track of the
+// last multi-function adapter found.
+
+UINT MultifunctionAdapterNumber = 0;
+UINT ControllerNumber = 0;
+
+#endif
+
+#pragma NDIS_PAGABLE_FUNCTION(DC21X4Initialize)
+
+/*+
+ * DC21X4Initialize
+ *
+ * Routine Description:
+ *
+ * DC21X4Initialize is called to have the Miniport driver
+ * initialize the adapter
+ *
+-*/
+
+extern
+NDIS_STATUS
+DC21X4Initialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE WrapperConfigurationHandle
+ )
+{
+ NDIS_HANDLE ConfigurationHandle;
+ NDIS_STATUS NdisStatus;
+ PDC21X4_ADAPTER Adapter;
+
+ PNDIS_CONFIGURATION_PARAMETER Configuration;
+ PUCHAR NetworkAddress;
+ UCHAR SWNetworkAddress[6];
+ UINT NetworkAddressLength;
+ ULONG InterruptVector;
+ ULONG InterruptLevel;
+
+ UINT MapRegisterCount;
+
+ NDIS_INTERRUPT_MODE InterruptMode = NdisInterruptLevelSensitive;
+
+ NDIS_EISA_FUNCTION_INFORMATION EisaData;
+
+ DC21X4_CONFIGURATION DC21X4Configuration[MAX_RGS];
+ DC21X4_PCI_CONFIGURATION DC21X4PciConfiguration;
+
+ USHORT IntPort;
+ USHORT PciCFCSPort;
+ USHORT PciCFLTPort;
+ USHORT BusModePort;
+ USHORT SiaPort;
+
+ PUCHAR BytePtr;
+
+ UCHAR InitType;
+
+ ULONG PortValue;
+ ULONG PortAddress;
+ ULONG Mask;
+ ULONG Mode;
+
+ UCHAR PortWidth;
+ UCHAR UseMask;
+
+ UCHAR Value;
+
+ UINT Irq[4] = { 5, 9, 10, 11};
+ UINT Width[4] = {sizeof(UCHAR), sizeof(USHORT), sizeof(ULONG), 1};
+
+ UINT i;
+
+ BOOLEAN Link=FALSE;
+ BOOLEAN StartTimer=TRUE;
+
+#if __DBG
+ DbgPrint ("\nDC21X4Initialize\n");
+#endif
+
+ // Search for the 802.3 media type in the Medium Array
+
+ for (i=0; i<MediumArraySize; i++) {
+
+ if (MediumArray[i] == NdisMedium802_3)
+ break;
+ }
+
+ if (i == MediumArraySize) {
+ return NDIS_STATUS_UNSUPPORTED_MEDIA;
+ }
+
+ *SelectedMediumIndex = i;
+
+#if __DBG
+ DbgPrint("Media = 802_3\n");
+#endif
+
+
+ // Allocate and initialize the Adapter block
+
+ ALLOC_MEMORY (&NdisStatus, &Adapter, sizeof(DC21X4_ADAPTER));
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ // Cannot allocate the adapter
+ return NdisStatus;
+ }
+#if __DBG
+ DbgPrint("Adapter block &%08x %d bytes\n",&Adapter,sizeof(DC21X4_ADAPTER));
+#endif
+ ZERO_MEMORY (Adapter,sizeof(DC21X4_ADAPTER));
+
+ Adapter->Initializing = TRUE;
+ Adapter->MiniportAdapterHandle = MiniportAdapterHandle;
+
+ // Initialize the DC21X4 Csr Configuration array
+
+ ZERO_MEMORY (DC21X4Configuration, sizeof(DC21X4Configuration));
+
+ DC21X4Configuration[RGS_CFCS].CsrValue = DC21X4_PCI_COMMAND_DEFAULT_VALUE;
+
+ DC21X4Configuration[RGS_BLEN].RegistryValue = DC21X4_BURST_LENGTH_DEFAULT_VALUE;
+ DC21X4Configuration[RGS_RCVR].RegistryValue = DC21X4_RECEIVE_RING_SIZE;
+ DC21X4Configuration[RGS_ITHR].RegistryValue = DC21X4_MSK_THRESHOLD_DEFAULT_VALUE;
+ DC21X4Configuration[RGS_FTHR].RegistryValue = DC21X4_FRAME_THRESHOLD_DEFAULT_VALUE;
+
+ DC21X4Configuration[RGS_UTHR].RegistryValue = DC21X4_UNDERRUN_THRESHOLD;
+ DC21X4Configuration[RGS_UNDR].RegistryValue = DC21X4_UNDERRUN_MAX_RETRIES;
+
+ DC21X4Configuration[RGS_SNOO].RegistryValue = 0;
+ DC21X4Configuration[RGS_NWAY].RegistryValue = 1;
+
+ // Open the configuration info.
+
+#if __DBG
+ DbgPrint ("NdisOpenConfiguration\n");
+#endif
+
+ NdisOpenConfiguration(
+ &NdisStatus,
+ &ConfigurationHandle,
+ WrapperConfigurationHandle
+ );
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ FREE_MEMORY(Adapter, sizeof(DC21X4_ADAPTER));
+ return NdisStatus;
+ }
+
+ // Query the Registry
+
+ for (i=0; i < MAX_RGS; i++ ) {
+
+ NdisReadConfiguration(
+ &NdisStatus,
+ &Configuration,
+ ConfigurationHandle,
+ &DC21X4ConfigString[i],
+ NdisParameterHexInteger
+ );
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ DC21X4Configuration[i].Present = TRUE;
+ DC21X4Configuration[i].RegistryValue =
+ Configuration->ParameterData.IntegerData;
+#if __DBG
+ DbgPrint("Registry[%2d]=%x\n",
+ i,DC21X4Configuration[i].RegistryValue);
+#endif
+ }
+
+ }
+
+
+ // Check that our adapter type is supported.
+
+ if (DC21X4Configuration[RGS_ADPT].Present) {
+ Adapter->AdapterType = DC21X4Configuration[RGS_ADPT].RegistryValue;
+ }
+ else {
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
+ 1,
+ DC21X4_ERRMSG_REGISTRY
+ );
+ FreeAdapterResources(Adapter,1);
+ return NdisStatus;
+ }
+
+ switch (Adapter->AdapterType) {
+
+ case NdisInterfacePci:
+
+ break;
+
+
+ case NdisInterfaceEisa:
+
+ // Read the EISA Slot Information block
+#if __DBG
+ DbgPrint ("ReadEisaSlotInformation\n");
+#endif
+ NdisReadEisaSlotInformation(
+ &NdisStatus,
+ WrapperConfigurationHandle,
+ &Adapter->SlotNumber,
+ &EisaData
+ );
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+#if __DBG
+ DbgPrint("DC21X4: Could not read EISA Config data\n");
+#endif
+ NdisCloseConfiguration(ConfigurationHandle);
+ FREE_MEMORY(Adapter, sizeof(DC21X4_ADAPTER));
+ return NdisStatus;
+ }
+
+ // Now we walk through the Eisa Initialization Data block to
+ // read the interrupt information.
+ // Initalization Data entry format:
+ //
+ // Byte 0 : Initialization Type
+ // bit<7> = 0 - Last Entry
+ // 1 - More entries to follow
+ // bit<2> = Port Value or Mask Value
+ // 0 - write value to port
+ // 1 - use mask and value
+ // bit<1:0> = Type of access
+ // 00 byte address
+ // 01 word address
+ // 10 lword address
+ // Byte 1 = LSByte of port I/O address
+ // Byte 2 = MSByte of port I/O address
+ // if Byte_0<2> = 0 (no mask) then
+ // Byte_0<1:0> = Port width to write
+ // 00 Byte 3 = Port Value
+ // 01 Byte 3-4 = Port Value
+ // 10 Byte 3-6 = Port Value
+ // if Byte_0<2> = 1 (use mask) then
+ // Byte_0<1:0> = width of port value and mask
+ // 00 Byte 3 = Port Value
+ // Byte 4 = Port Mask
+ // 01 Byte 3-4 = Port Value
+ // Byte 5-6 = Port Mask
+ // 10 Byte 3-6 = Port Value
+ // Byte 7-10 = Port Mask
+
+ BytePtr = (PUCHAR)EisaData.InitializationData;
+ PciCFCSPort= (USHORT)(Adapter->SlotNumber << SLOT_NUMBER_OFFSET) + EISA_CFCS_OFFSET;
+ PciCFLTPort= (USHORT)(Adapter->SlotNumber << SLOT_NUMBER_OFFSET) + EISA_CFLT_OFFSET;
+ IntPort = (USHORT)(Adapter->SlotNumber << SLOT_NUMBER_OFFSET) + EISA_REG0_OFFSET;
+ BusModePort= (USHORT)(Adapter->SlotNumber << SLOT_NUMBER_OFFSET) + EISA_CFGSCR1_OFFSET;
+ SiaPort = (USHORT)(Adapter->SlotNumber << SLOT_NUMBER_OFFSET) + EISA_CFGSCR2_OFFSET;
+
+ do {
+
+#if __DBG
+ DbgPrint("BytePtr = %x \n", BytePtr);
+#endif
+ InitType = *(BytePtr++);
+
+ UseMask = InitType & 0x04;
+ PortWidth = InitType & 0x03;
+
+ PortAddress = *(UNALIGNED USHORT *)(BytePtr);
+ (ULONG)BytePtr += sizeof(USHORT);
+
+ PortValue = 0;
+ MOVE_MEMORY(&PortValue,BytePtr,Width[PortWidth]);
+ (ULONG)BytePtr += Width[PortWidth];
+
+ Mask = 0;
+ if (UseMask) {
+ MOVE_MEMORY(&Mask,BytePtr,Width[PortWidth]);
+ (ULONG)BytePtr += Width[PortWidth];
+ }
+#if __DBG
+ DbgPrint("InitType = %x PortAddress = %08x Value=%x Mask=%x\n",
+ InitType,PortAddress,PortValue,Mask);
+#endif
+ if (PortAddress == IntPort) {
+
+ Value = ((UCHAR)PortValue & ~(UCHAR)Mask);
+
+ InterruptVector = Irq[(Value & 0x06) >> IRQ_BIT_NUMBER];
+ InterruptLevel = InterruptVector;
+
+ InterruptMode = (Value & 0x01) ?
+ NdisInterruptLatched : NdisInterruptLevelSensitive;
+
+#if __DBG
+ DbgPrint("Eisa data: InterruptVector = %d\n",InterruptVector);
+ DbgPrint(" InterruptLevel = %d\n",InterruptLevel);
+ DbgPrint(" InterruptMode = %d\n",InterruptMode);
+#endif
+ }
+ else if (PortAddress == PciCFCSPort) {
+
+ if (!DC21X4Configuration[RGS_CFCS].Present) {
+ DC21X4Configuration[RGS_CFCS].CsrValue = PortValue;
+#if __DBG
+ DbgPrint("Eisa CFCS = %08x\n",DC21X4Configuration[RGS_CFCS].CsrValue);
+#endif
+ }
+
+ }
+ else if (PortAddress == PciCFLTPort) {
+
+ if (!DC21X4Configuration[RGS_CFLT].Present) {
+ DC21X4Configuration[RGS_CFLT].CsrValue = PortValue;
+#if __DBG
+ DbgPrint("Eisa CFLT = %08x\n",DC21X4Configuration[RGS_CFLT].CsrValue);
+#endif
+ }
+ }
+ else if (PortAddress == BusModePort) {
+ Adapter->BusMode = PortValue;
+#if __DBG
+ DbgPrint("Eisa CSR0 = %08x\n",PortValue);
+#endif
+ }
+ else if (PortAddress == SiaPort) {
+
+ switch (PortValue) {
+
+ default:
+ case DC21X4_AUTOSENSE_FLG:
+
+ DC21X4Configuration[RGS_CNCT].RegistryValue = 0; //AutoSense
+ break;
+
+ case DC21X4_10B2_FLG:
+
+ DC21X4Configuration[RGS_CNCT].RegistryValue = 1; //BNC
+ break;
+
+ case DC21X4_FULL_DUPLEX_FLG:
+
+ DC21X4Configuration[RGS_CNCT].RegistryValue = 3; //TpFD
+ break;
+
+ case DC21X4_LINK_DISABLE_FLG:
+
+ DC21X4Configuration[RGS_CNCT].RegistryValue = 4; //TpNLT
+ break;
+
+ case DC21X4_10B5_FLG:
+
+ DC21X4Configuration[RGS_CNCT].RegistryValue = 5; //AUI
+ break;
+
+ }
+ }
+
+ } while (InitType & 0x80);
+
+ break;
+
+ default:
+
+ // This adapter type is not supported by this driver
+#if __DBG
+ DbgPrint("DC21X4: Unsupported adapter type: %lx\n", Configuration->ParameterData.IntegerData);
+#endif
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
+ 1,
+ DC21X4_ERRMSG_REGISTRY
+ );
+ NdisCloseConfiguration(ConfigurationHandle);
+ FreeAdapterResources(Adapter,1);
+ return NDIS_STATUS_FAILURE;
+ }
+
+ // Adapter CFID
+
+ if (!DC21X4Configuration[RGS_CFID].Present) {
+#if __DBG
+ DbgPrint("DC21X4: AdapterCfid is missing into the Registry\n");
+#endif
+ NdisCloseConfiguration(ConfigurationHandle);
+ FREE_MEMORY(Adapter, sizeof(DC21X4_ADAPTER));
+ return NDIS_STATUS_FAILURE;
+ }
+ Adapter->DeviceId = DC21X4Configuration[RGS_CFID].RegistryValue;
+#if __DBG
+ DbgPrint ("Registry(Cfid)=%x\n",Adapter->DeviceId);
+#endif
+
+ // PCI registers
+
+ if (DC21X4Configuration[RGS_CFCS].Present) {
+ DC21X4Configuration[RGS_CFCS].CsrValue =
+ DC21X4Configuration[RGS_CFCS].RegistryValue;
+ }
+ if (DC21X4Configuration[RGS_CFLT].Present) {
+ DC21X4Configuration[RGS_CFLT].CsrValue =
+ DC21X4Configuration[RGS_CFLT].RegistryValue;
+ }
+
+ // Bus Mode register
+
+
+ if (DC21X4Configuration[RGS_BLEN].Present) {
+
+ // Valid Burst length values are 1,2,4,8,16 & 32 (DC2114x only)
+ switch (DC21X4Configuration[RGS_BLEN].RegistryValue) {
+
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+
+ break;
+
+ case 32:
+
+ if ( (Adapter->DeviceId == DC21040_CFID)
+ ||(Adapter->DeviceId == DC21041_CFID)) {
+
+ //max burst limit = 16 LW
+ DC21X4Configuration[RGS_BLEN].RegistryValue = 16;
+ }
+ break;
+
+ default:
+ DC21X4Configuration[RGS_BLEN].RegistryValue = DC21X4_BURST_LENGTH_DEFAULT_VALUE;
+ }
+ }
+
+ Adapter->BusMode &= ~(DC21X4_BURST_LENGTH);
+ Adapter->BusMode |=
+ (DC21X4Configuration[RGS_BLEN].RegistryValue << BURST_LENGTH_BIT_NUMBER);
+#if __DBG
+ DbgPrint ("Burst Length = %d LW\n",DC21X4Configuration[RGS_BLEN].RegistryValue);
+#endif
+
+ if (DC21X4Configuration[RGS_FARB].Present) {
+
+ Adapter->BusMode &= ~(DC21X4_BUS_ARBITRATION);
+ Adapter->BusMode |=
+ (DC21X4Configuration[RGS_FARB].RegistryValue << BUS_ARBITRATION_BIT_NUMBER);
+#if __DBG
+ DbgPrint ("Bus Arbitration = %x\n",DC21X4Configuration[RGS_FARB].RegistryValue);
+#endif
+ }
+
+ if (DC21X4Configuration[RGS_PLDM].Present) {
+#if __DBG
+ DbgPrint ("Poll Demand = %x\n",DC21X4Configuration[RGS_PLDM].RegistryValue);
+#endif
+ // Initialize the Txm Automatic Poll Demand field
+
+ Adapter->BusMode |=
+ (DC21X4Configuration[RGS_PLDM].RegistryValue << AUTO_POLLING_BIT_NUMBER);
+ }
+
+ // Read the network address from the Registry
+#if __DBG
+ DbgPrint ("NdisReadNetworkAddress\n");
+#endif
+
+ NdisReadNetworkAddress(
+ &NdisStatus,
+ (PVOID *)&NetworkAddress,
+ &NetworkAddressLength,
+ ConfigurationHandle
+ );
+
+ // Check if we get a valid network address
+
+ if ((NdisStatus == NDIS_STATUS_SUCCESS)
+ && (NetworkAddressLength == ETH_LENGTH_OF_ADDRESS)
+ && !(IS_NULL_ADDRESS(NetworkAddress))
+ ){
+ MOVE_MEMORY(
+ &SWNetworkAddress[0],
+ NetworkAddress,
+ ETH_LENGTH_OF_ADDRESS
+ );
+ NetworkAddress = &SWNetworkAddress[0];
+#if __DBG
+ DbgPrint("Network address from registry = %.2x-%.2x-%.2x-%.2x-%.2x-%.2x\n",
+ *(NetworkAddress),*(NetworkAddress+1),*(NetworkAddress+2),
+ *(NetworkAddress+3),*(NetworkAddress+4),*(NetworkAddress+5));
+#endif
+ }
+ else {
+ // no SW configured network address available
+ NetworkAddress = NULL;
+ }
+
+ // Close the Configuration
+#if __DBG
+ DbgPrint ("NdisCloseConfiguration\n");
+#endif
+ NdisCloseConfiguration(ConfigurationHandle);
+
+
+ // Register the Adapter Type
+#if __DBG
+ DbgPrint ("NdisMSetAttributes AdapterContext =%x\n",Adapter);
+#endif
+
+ NdisMSetAttributes(
+ MiniportAdapterHandle,
+ Adapter,
+ TRUE,
+ Adapter->AdapterType
+ );
+
+
+ switch (Adapter->AdapterType) {
+
+ case NdisInterfacePci:
+
+ Adapter->SlotNumber = DC21X4Configuration[RGS_DEVN].RegistryValue;
+
+ NdisReadPciSlotInformation(
+ MiniportAdapterHandle,
+ Adapter->SlotNumber,
+ PCI_CFID_OFFSET,
+ &DC21X4PciConfiguration,
+ sizeof(ULONG)
+ );
+
+ if (DC21X4PciConfiguration.Reg[CFID] !=
+ DC21X4Configuration[RGS_CFID].RegistryValue) {
+#if __DBG
+ DbgPrint("Adapter's CFID [%x] does not match Registry's CFID [%x] !!\n",
+ DC21X4PciConfiguration.Reg[CFID],
+ DC21X4Configuration[RGS_CFID].RegistryValue);
+#endif
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
+ 0
+ );
+ FreeAdapterResources(Adapter,1);
+ return NDIS_STATUS_ADAPTER_NOT_FOUND;
+ }
+
+ NdisStatus = FindPciConfiguration(
+ MiniportAdapterHandle,
+ Adapter->SlotNumber,
+ &Adapter->IOBaseAddress,
+ &Adapter->IOSpace,
+ &InterruptLevel,
+ &InterruptVector
+ );
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ FREE_MEMORY(Adapter, sizeof(DC21X4_ADAPTER));
+ return NdisStatus;
+ }
+
+ NdisReadPciSlotInformation(
+ MiniportAdapterHandle,
+ Adapter->SlotNumber,
+ PCI_CFID_OFFSET,
+ &DC21X4PciConfiguration,
+ sizeof(DC21X4PciConfiguration)
+ );
+
+ InterruptMode = NdisInterruptLevelSensitive;
+
+#if __DBG
+ DbgPrint("SubSystem ID = %x\n", DC21X4PciConfiguration.Reg[SSID]);
+#endif
+
+ break;
+
+ case NdisInterfaceEisa:
+
+ Adapter->IOBaseAddress = (Adapter->SlotNumber << SLOT_NUMBER_OFFSET);
+
+ switch (Adapter->DeviceId) {
+
+ default:
+ case DC21040_CFID:
+
+ Adapter->IOSpace = EISA_DC21040_REGISTER_SPACE;
+ break;
+
+ case DC21140_CFID:
+
+ Adapter->IOSpace = EISA_DC21140_REGISTER_SPACE;
+ break;
+ }
+
+ }
+
+ // Register the IoPortRange
+
+#if __DBG
+ DbgPrint("NdisMRegisterIOPortRange\n");
+#endif
+ NdisStatus = NdisMRegisterIoPortRange(
+ (PVOID *)(&(Adapter->PortOffset)),
+ MiniportAdapterHandle,
+ Adapter->IOBaseAddress,
+ Adapter->IOSpace
+ );
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+#if __DBG
+ DbgPrint(" Failed: Status = %x\n",NdisStatus);
+#endif
+ FREE_MEMORY(Adapter, sizeof(DC21X4_ADAPTER));
+ return NdisStatus;
+ }
+
+ //Map the adapter CSR addresses
+
+ switch (Adapter->AdapterType) {
+
+ case NdisInterfacePci:
+
+ for (i=0; i < DC21X4_MAX_CSR; i++) {
+ Adapter->CsrMap[i] = Adapter->PortOffset + (i * PCI_CSR_OFFSET);
+ }
+ break;
+
+ case NdisInterfaceEisa:
+
+ Adapter->PciRegMap[DC21X4_PCI_ID] = Adapter->PortOffset + EISA_CFID_OFFSET;
+ Adapter->PciRegMap[DC21X4_PCI_COMMAND] = Adapter->PortOffset + EISA_CFCS_OFFSET;
+ Adapter->PciRegMap[DC21X4_PCI_REVISION] = Adapter->PortOffset + EISA_CFRV_OFFSET;
+ Adapter->PciRegMap[DC21X4_PCI_LATENCY_TIMER] = Adapter->PortOffset + EISA_CFLT_OFFSET;
+ Adapter->PciRegMap[DC21X4_PCI_BASE_IO_ADDRESS] = Adapter->PortOffset + EISA_CBIO_OFFSET;
+
+ for (i=0; i < DC21X4_MAX_CSR; i++) {
+ Adapter->CsrMap[i] = Adapter->PortOffset + (i * EISA_CSR_OFFSET);
+ }
+
+ // Read DC21X4 Device_Id and Revision Number
+
+ DC21X4_READ_PCI_REGISTER(
+ DC21X4_PCI_ID,
+ &DC21X4PciConfiguration.Reg[CFID]
+ );
+#if __DBG
+ DbgPrint("PCI[Cfid]=%x\n",DC21X4PciConfiguration.Reg[CFID]);
+#endif
+
+ if (DC21X4PciConfiguration.Reg[CFID] !=
+ DC21X4Configuration[RGS_CFID].RegistryValue) {
+
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
+ 0
+ );
+
+ FreeAdapterResources(Adapter,2);
+ return NDIS_STATUS_ADAPTER_NOT_FOUND;
+ }
+
+ DC21X4_READ_PCI_REGISTER(
+ DC21X4_PCI_REVISION,
+ &DC21X4PciConfiguration.Reg[CFRV]
+ );
+
+ break;
+ }
+
+ Adapter->RevisionNumber =
+ DC21X4PciConfiguration.Reg[CFRV] & DC21X4_REVISION_ID;
+
+#if __DBG
+ DbgPrint("RevisionNumber= %x\n",Adapter->RevisionNumber);
+#endif
+
+
+
+ // Allocate the Map registers;
+ // if the number of map registers is not specified into the Registry,
+ // query the number of map registers supported by this platform
+ // and allocate 1/8th.
+ // The number of map register allocated to the adapter is casted
+ // to the range [DC21X4_MIN_MAP_REGISTERS,..,DC21X4_MAX_MAP_REGISTERS]
+
+ if (DC21X4Configuration[RGS_MAPR].Present) {
+ Adapter->AllocMapRegisters = DC21X4Configuration[RGS_MAPR].RegistryValue;
+ }
+ else {
+ NdisStatus = NdisQueryMapRegisterCount(
+ Adapter->AdapterType,
+ &MapRegisterCount
+ );
+
+ Adapter->AllocMapRegisters = (NdisStatus == NDIS_STATUS_SUCCESS) ?
+ MapRegisterCount/8 : DC21X4_MAX_MAP_REGISTERS;
+ }
+
+ Adapter->AllocMapRegisters =
+ max(min(Adapter->AllocMapRegisters,DC21X4_MAX_MAP_REGISTERS),DC21X4_MIN_MAP_REGISTERS);
+
+#if __DBG
+ DbgPrint("NdisMAllocateMapRegisters: allocate %d map registers)\n",
+ Adapter->AllocMapRegisters);
+#endif
+
+ NdisMAllocateMapRegisters(
+ MiniportAdapterHandle,
+ 0,
+ TRUE,
+ Adapter->AllocMapRegisters,
+ DC21X4_MAX_BUFFER_SIZE
+ );
+
+ Adapter->PhysicalSegmentThreshold =
+ min(Adapter->AllocMapRegisters,DC21X4_MAX_SEGMENTS);
+#if __DBG
+ DbgPrint("Txm Segment Threshold = %d\n",Adapter->PhysicalSegmentThreshold);
+#endif
+
+
+ if (DC21X4Configuration[RGS_ITMG].RegistryValue == 1) {
+
+ // normalize the Interrupt and Frame thresholds to rate/second
+
+ Adapter->InterruptThreshold =
+ max((ULONG)((DC21X4Configuration[RGS_ITHR].RegistryValue * INT_MONITOR_PERIOD) / 1000),1);
+
+ Adapter->FrameThreshold =
+ max((ULONG)((DC21X4Configuration[RGS_FTHR].RegistryValue * INT_MONITOR_PERIOD) / 1000),1);
+
+ // calculate the Rcv & Txm descriptor ring polling frequencies for the on board timer
+ // based on the interrupt threshold
+
+ Adapter->RcvTxmPolling = max((ULONG)(1000/Adapter->InterruptThreshold),1) * ONE_MILLISECOND_TICK;
+ Adapter->TxmPolling = Adapter->RcvTxmPolling * 10;
+ }
+
+ Adapter->TiPeriod = DC21X4Configuration[RGS_TI].RegistryValue;
+
+ Adapter->PciCommand = DC21X4Configuration[RGS_CFCS].CsrValue;
+
+ Adapter->InterruptMask = DC21X4_MSK_MSK_DEFAULT_VALUE;
+
+ switch (Adapter->DeviceId) {
+
+ case DC21142_CFID:
+
+ Adapter->InterruptMask |= DC21X4_MSK_GEP_INTERRUPT;
+ break;
+ }
+
+ Adapter->TransmitDefaultDescriptorErrorMask = DC21X4_TDES_ERROR_MASK;
+
+ Adapter->PciLatencyTimer = DC21X4Configuration[RGS_CFLT].CsrValue;
+
+ Adapter->PciDriverArea |=
+ (DC21X4Configuration[RGS_SNOO].RegistryValue == 1) ? CFDA_SNOOZE_MODE : 0;
+
+ Adapter->NwayProtocol = (BOOLEAN)DC21X4Configuration[RGS_NWAY].RegistryValue;
+
+ Adapter->UnderrunThreshold = DC21X4Configuration[RGS_UTHR].RegistryValue;
+ Adapter->UnderrunMaxRetries = DC21X4Configuration[RGS_UNDR].RegistryValue;
+#if __DBG
+ DbgPrint("UnderrunThreshold = %d \n", Adapter->UnderrunThreshold);
+ DbgPrint("UnderrunMaxRetries = %d \n",Adapter->UnderrunMaxRetries);
+#endif
+
+ Adapter->TransceiverDelay = (INT)DC21X4Configuration[RGS_TRNS].RegistryValue;
+
+ // Allocate memory for all of the adapter structures:
+ // Rcv & Txm Descriptor rings
+ // Rcv Buffers
+ // Setup Buffer
+
+ Adapter->ReceiveRingSize =
+ max(min(DC21X4Configuration[RGS_RCVR].RegistryValue,DC21X4_MAX_RECEIVE_RING_SIZE),DC21X4_MIN_RECEIVE_RING_SIZE);
+
+
+ // Get the number of extra receive buffers that we need to allocate.
+ // If this platform has scare Map registers ressources, and no
+ // ExtraReceiveBuffers is specified into the Registry,
+ // do not allocate any extra receive buffers
+
+ Adapter->ExtraReceiveBuffers = DC21X4Configuration[RGS_RCV_BUFS].Present ?
+ DC21X4Configuration[RGS_RCV_BUFS].RegistryValue :
+ (Adapter->AllocMapRegisters < DC21X4_MAX_MAP_REGISTERS) ? 0 :
+ Adapter->ReceiveRingSize;
+
+ // Get the number of extra packets that we need for receive indications.
+ // If this platform has scare Map registers ressources, and no
+ // ExtraReceivePackets is specified into the Registry,
+ // allocate just enough packets for the receive ring but not extra ones.
+
+ Adapter->ExtraReceivePackets = DC21X4Configuration[RGS_RCV_PKTS].Present ?
+ DC21X4Configuration[RGS_RCV_PKTS].RegistryValue :
+ (Adapter->AllocMapRegisters < DC21X4_MAX_MAP_REGISTERS) ?
+ Adapter->ReceiveRingSize : DC21X4_RECEIVE_PACKETS;
+
+ // Make sure that there are enough packets for the receive ring.
+
+ Adapter->ExtraReceivePackets =
+ max(Adapter->ExtraReceivePackets, (Adapter->ReceiveRingSize + Adapter->ExtraReceiveBuffers));
+
+
+ Adapter->FreeMapRegisters = Adapter->AllocMapRegisters;
+
+#if __DBG
+ DbgPrint("ReceiveRingSize = %d \n", Adapter->ReceiveRingSize);
+ DbgPrint("FreeMapRegisters = %d \n", Adapter->FreeMapRegisters);
+ DbgPrint("ExtraReceiveBuffers = %d \n", Adapter->ExtraReceiveBuffers);
+ DbgPrint("ExtraReceivePackets = %d \n", Adapter->ExtraReceivePackets);
+#endif
+
+ // Get the size of the Cache line
+ // Sizes supported by DC21X4 are 16,32,64 or 128 bytes.
+ // Default value is 64 bytes
+
+ if (DC21X4Configuration[RGS_CLSZ].Present) {
+ Adapter->CacheLineSize = DC21X4Configuration[RGS_CLSZ].RegistryValue;
+#if __DBG
+ DbgPrint("CacheLineSize from Registry = %d\n",Adapter->CacheLineSize);
+#endif
+ }
+ else {
+ Adapter->CacheLineSize = NdisGetCacheFillSize() * sizeof(ULONG);
+#if __DBG
+ DbgPrint("NdisGetCacheFillSize = %d\n",Adapter->CacheLineSize);
+#endif
+ }
+
+ switch (Adapter->CacheLineSize) {
+
+ case 64:
+ case 128:
+ break;
+
+ default:
+ Adapter->CacheLineSize = DC21X4_DEFAULT_CACHE_LINE_SIZE;
+#if __DBG
+ DbgPrint("CacheLineSize defaulted to %d\n",Adapter->CacheLineSize);
+#endif
+ }
+
+ // DC21X4 maximum mapping address is 32 bits
+
+ NdisSetPhysicalAddressLow(Adapter->HighestAllocAddress,0xffffffff);
+ NdisSetPhysicalAddressHigh(Adapter->HighestAllocAddress,0);
+
+ // To avoid multiple write to the same cache line,
+ // one descriptor only is loaded per cache line:
+ // DescriptorSize is the size of an descriptor entry into the
+ // descriptor ring.
+ // Minimum descriptor size is 64 to keep 12 longwords within the descriptor
+ // as reserved area for the driver.
+
+ Adapter->BusMode &= ~(DC21X4_SKIP_LENGTH | DC21X4_CACHE_ALIGNMENT);
+
+ switch (Adapter->CacheLineSize) {
+
+ default :
+
+ Adapter->DescriptorSize = 64;
+ Adapter->BusMode |= DC21X4_SKIP_64;
+ break;
+
+ case 128 :
+
+ Adapter->DescriptorSize = 128;
+ Adapter->BusMode |= DC21X4_SKIP_128;
+ break;
+ }
+
+ switch (DC21X4Configuration[RGS_BLEN].RegistryValue) {
+
+ case 8 :
+
+ Adapter->BusMode |= DC21X4_ALIGN_32;
+ break;
+
+ case 16 :
+
+ Adapter->BusMode |= DC21X4_ALIGN_64;
+ break;
+
+ default:
+ case 32 :
+
+ Adapter->BusMode |= DC21X4_ALIGN_128;
+ break;
+ }
+
+#if __DBG
+ DbgPrint("AllocateAdapterMemory\n");
+#endif
+ if (!AllocateAdapterMemory(Adapter)) {
+
+ // Call to AllocateAdapterMemory failed.
+#if __DBG
+ DbgPrint(" Failed!\n");
+#endif
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 1,
+ DC21X4_ERRMSG_ALLOC_MEMORY
+ );
+
+ FreeAdapterResources(Adapter,3);
+ return NDIS_STATUS_RESOURCES;
+ }
+
+#if __DBG
+ DbgPrint(" Tx Ring Va = %08x\n",Adapter->TransmitDescriptorRingVa);
+ DbgPrint(" Pa = %08x\n",Adapter->TransmitDescriptorRingPa);
+ DbgPrint("\n");
+ DbgPrint(" Rx Ring Va = %08x\n",Adapter->ReceiveDescriptorRingVa);
+ DbgPrint(" Pa = %08x\n",Adapter->ReceiveDescriptorRingPa);
+ DbgPrint("\n");
+ DbgPrint(" Sp Buff Va = %08x\n",Adapter->SetupBufferVa);
+ DbgPrint(" Pa = %08x\n",Adapter->SetupBufferPa);
+ DbgPrint("\n");
+
+
+#endif
+
+ // Initialize the descriptor index
+
+ Adapter->DequeueReceiveDescriptor =
+ (PDC21X4_RECEIVE_DESCRIPTOR)Adapter->ReceiveDescriptorRingVa;
+ Adapter->EnqueueTransmitDescriptor =
+ (PDC21X4_TRANSMIT_DESCRIPTOR)Adapter->TransmitDescriptorRingVa;
+ Adapter->DequeueTransmitDescriptor =
+ Adapter->EnqueueTransmitDescriptor;
+
+ Adapter->FreeTransmitDescriptorCount = TRANSMIT_RING_SIZE - 1;
+
+ // Initialize the DC21X4's PCI Configuration registers
+
+ DC21X4InitPciConfigurationRegisters(Adapter);
+ DC21X4StopAdapter(Adapter);
+
+
+ // Transmit Threshold:
+
+ switch (Adapter->DeviceId) {
+
+ case DC21040_CFID:
+
+ // DC21040 Pass1 & Pass2 FIFO Underrun workaround:
+ // set the minimal threshold to
+ // - 96 bytes if no SoftwareCRC
+ // 160 bytes if SoftwareCRC
+
+ switch (Adapter->RevisionNumber) {
+
+ case DC21040_REV1:
+ case DC21040_REV2_0:
+ case DC21040_REV2_2:
+
+ Adapter->TransmitDefaultDescriptorErrorMask &= ~(DC21X4_TDES_LOSS_OF_CARRIER);
+ Adapter->SoftwareCRC = DC21X4Configuration[RGS_SCRC].RegistryValue;
+
+ DC21X4Configuration[RGS_THRS].RegistryValue =
+ (Adapter->SoftwareCRC) ? 160 : max(96,DC21X4Configuration[RGS_THRS].RegistryValue);
+ }
+ }
+
+ switch (DC21X4Configuration[RGS_THRS].RegistryValue) {
+
+ case 160:
+ Adapter->Threshold10Mbps = DC21X4_TXM10_THRESHOLD_160;
+ break;
+
+ case 128:
+ Adapter->Threshold10Mbps = DC21X4_TXM10_THRESHOLD_128;
+ break;
+
+ case 96:
+ Adapter->Threshold10Mbps = DC21X4_TXM10_THRESHOLD_96;
+ break;
+
+ default:
+ DC21X4Configuration[RGS_THRS].RegistryValue = 96;
+ Adapter->Threshold10Mbps = DC21X4_DEFAULT_THRESHOLD_10MBPS;
+ }
+
+ Adapter->TxmThreshold = DC21X4Configuration[RGS_THRS].RegistryValue;
+
+ switch (DC21X4Configuration[RGS_THRS100].RegistryValue) {
+
+ case 1024:
+ Adapter->Threshold100Mbps = DC21X4_TXM100_THRESHOLD_1024;
+ break;
+
+ case 512:
+ Adapter->Threshold100Mbps = DC21X4_TXM100_THRESHOLD_512;
+ break;
+
+ case 256:
+ Adapter->Threshold100Mbps = DC21X4_TXM100_THRESHOLD_256;
+ break;
+
+ case 128:
+ Adapter->Threshold100Mbps = DC21X4_TXM100_THRESHOLD_128;
+ break;
+
+ default:
+ Adapter->Threshold100Mbps = DC21X4_DEFAULT_THRESHOLD_100MBPS;
+ }
+
+ if (DC21X4Configuration[RGS_STFD].RegistryValue == 1) {
+ Adapter->OperationMode |= DC21X4_STORE_AND_FORWARD;
+ }
+
+#if __DBG
+ DbgPrint("Threshold10Mbps=%x\n", Adapter->Threshold10Mbps);
+ DbgPrint("Threshold100Mbps=%x\n", Adapter->Threshold100Mbps);
+ DbgPrint("SoftwareCRC=%x\n", Adapter->SoftwareCRC);
+ DbgPrint("StoreAndForward=%x\n", Adapter->OperationMode & DC21X4_STORE_AND_FORWARD);
+#endif
+
+ // MediaType
+
+ if (DC21X4Configuration[RGS_CNCT].RegistryValue > MAX_MEDIA) {
+ DC21X4Configuration[RGS_CNCT].RegistryValue = 0;
+ }
+ Adapter->MediaType = ConnectionType[DC21X4Configuration[RGS_CNCT].RegistryValue];
+
+ // Read the DC21X4 SERIAL ROM
+
+ NdisStatus = DC21X4ReadSerialRom(Adapter);
+
+#ifndef _MIPS_
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_INVALID_VALUE_FROM_ADAPTER,
+ 1,
+ DC21X4_ERRMSG_SROM
+ );
+ FreeAdapterResources(Adapter,3);
+ return NdisStatus;
+ }
+
+#endif
+
+ // Set the network address.
+
+ if (!NetworkAddress) {
+
+#ifdef _MIPS_
+
+ if (!Adapter->PermanentAddressValid) {
+
+ // Read the network address from the registry
+ // by iterating on MultifunctionAdapter and Controller.
+ // We set the global variables for these two entities so
+ // that for multiple adapters we don't re-use the same ethernet
+ // address, but rather we look in the registry for the next adapter
+ // instance.
+
+ for (;
+ MultifunctionAdapterNumber < 8;
+ MultifunctionAdapterNumber++) {
+
+ for (;
+ ControllerNumber < 16;
+ ControllerNumber++) {
+
+ NdisStatus = DC21X4HardwareGetDetails(Adapter,
+ MultifunctionAdapterNumber,
+ ControllerNumber);
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ ControllerNumber++;
+ break;
+
+ }
+ }
+ }
+
+ }
+#endif
+ if (Adapter->PermanentAddressValid) {
+ // Use the burnt-in network address
+ NetworkAddress = &Adapter->PermanentNetworkAddress[0];
+ }
+ else {
+ // no readable network address
+
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_NETWORK_ADDRESS,
+ 0
+ );
+ FreeAdapterResources(Adapter,3);
+ return NDIS_STATUS_FAILURE;
+ }
+
+ }
+
+ MOVE_MEMORY(
+ &Adapter->CurrentNetworkAddress[0],
+ NetworkAddress,
+ ETH_LENGTH_OF_ADDRESS
+ );
+
+#if __DBG
+ DbgPrint("Network address = %.2x-%.2x-%.2x-%.2x-%.2x-%.2x\n",
+ Adapter->CurrentNetworkAddress[0],
+ Adapter->CurrentNetworkAddress[1],
+ Adapter->CurrentNetworkAddress[2],
+ Adapter->CurrentNetworkAddress[3],
+ Adapter->CurrentNetworkAddress[4],
+ Adapter->CurrentNetworkAddress[5]);
+#endif
+
+ Adapter->MaxMulticastAddresses = DC21X4_MAX_MULTICAST_ADDRESSES;
+
+ switch (Adapter->DeviceId) {
+
+ case DC21140_CFID:
+
+ switch (Adapter->RevisionNumber) {
+
+ // dc21140 pass1_1 & pass1_2 limited to
+ // perfect filtering only
+
+ case DC21140_REV1_1:
+ case DC21140_REV1_2:
+
+ Adapter->MaxMulticastAddresses = DC21X4_MAX_MULTICAST_PERFECT;
+ break;
+
+ case DC21140_REV2_0:
+ case DC21140_REV2_1:
+ case DC21140_REV2_2:
+
+ Adapter->OverflowWorkAround = TRUE;
+ break;
+ }
+ break;
+
+ case DC21142_CFID:
+
+ switch (Adapter->RevisionNumber) {
+
+ case DC21142_REV1_0:
+ case DC21142_REV1_1:
+
+ Adapter->OverflowWorkAround = TRUE;
+ break;
+ }
+ break;
+ }
+
+#if __DBG
+ DbgPrint("MaxMulticastAddresses = %d\n",Adapter->MaxMulticastAddresses);
+#endif
+
+ // Initialize DC21X4's CAM with the Network Address
+
+#if __DBG
+ DbgPrint("DC21X4InitializeCam\n");
+#endif
+ DC21X4InitializeCam (
+ Adapter,
+ (PUSHORT)Adapter->CurrentNetworkAddress
+ );
+
+
+ // Initialize the interrupt.
+#if __DBG
+ DbgPrint("Init Interrupt\n");
+#endif
+#if __DBG
+ DbgPrint("Interrupt Vector = 0x%x\n",InterruptVector);
+ DbgPrint("Interrupt Level = 0x%x\n",InterruptLevel);
+#endif
+
+ NdisStatus = NdisMRegisterInterrupt(
+ &Adapter->Interrupt,
+ MiniportAdapterHandle,
+ InterruptVector,
+ InterruptLevel,
+ FALSE,
+ TRUE, //SHARED
+ (NDIS_INTERRUPT_MODE)InterruptMode
+ );
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_INTERRUPT_CONNECT,
+ 0
+ );
+
+ FreeAdapterResources(Adapter,3);
+ return NdisStatus;
+ }
+
+ // Initialize the FullDuplex SpinLocks
+
+ NdisAllocateSpinLock(
+ &Adapter->EnqueueSpinLock
+ );
+ NdisAllocateSpinLock(
+ &Adapter->FullDuplexSpinLock
+ );
+
+ // Register the adapter to receive shutdown notification:
+
+ NdisMRegisterAdapterShutdownHandler(
+ MiniportAdapterHandle,
+ Adapter,
+ (PVOID)DC21X4Shutdown
+ );
+
+ // Initialize the Media Autosense Timer
+
+ NdisMInitializeTimer(
+ &Adapter->Timer,
+ MiniportAdapterHandle,
+ (PNDIS_TIMER_FUNCTION)&DC21X4DynamicAutoSense,
+ (PVOID)Adapter
+ );
+
+ // Initialize the Reset Timer
+
+ NdisMInitializeTimer(
+ &Adapter->ResetTimer,
+ MiniportAdapterHandle,
+ (PNDIS_TIMER_FUNCTION)&DC21X4DeferredReset,
+ (PVOID)Adapter
+ );
+
+ // Initialize the Monitor Timer
+
+ NdisMInitializeTimer(
+ &Adapter->MonitorTimer,
+ MiniportAdapterHandle,
+ (PNDIS_TIMER_FUNCTION)&DC21X4ModerateInterrupt,
+ (PVOID)Adapter
+ );
+
+ // Initialize the DC21X4's CSRs
+
+ DC21X4InitializeRegisters(
+ Adapter
+ );
+
+ if (Adapter->PhyMediumInSrom) {
+
+ // Try to initialize the PHY.
+ Adapter->PhyPresent = DC21X4PhyInit(Adapter);
+#if __DBG
+ DbgPrint("Adapter->PhyPresent=%d\n",Adapter->PhyPresent);
+#endif
+ }
+#if __DBG
+ else {
+ DbgPrint("No PHY Medium in SROM\n");
+ }
+#endif
+
+ //Initialize the non PHY media
+
+ Mode = ( ((DC21X4Configuration[RGS_BKOC].RegistryValue) ? DC21X4_STOP_BACKOFF_COUNTER : 0 )
+ | ((DC21X4Configuration[RGS_BKPR].RegistryValue) ? DC21X4_BACK_PRESSURE : 0 )
+ | ((DC21X4Configuration[RGS_CPTE].RegistryValue) ? DC21X4_CAPTURE_EFFECT : 0 )
+ );
+
+ switch (Adapter->DeviceId) {
+
+ case DC21040_CFID:
+ case DC21041_CFID:
+ case DC21142_CFID:
+
+ if (DC21X4Configuration[RGS_ESIA].Present) {
+
+ //overwrite the SIA default values with the values stored in the
+ //Registry
+
+ i = ConnectionType[DC21X4Configuration[RGS_ESIA].RegistryValue] & 0xF;
+
+ Adapter->Media[i].SiaRegister[0] = DC21X4Configuration[RGS_SIA0].RegistryValue;
+ Adapter->Media[i].SiaRegister[1] = DC21X4Configuration[RGS_SIA1].RegistryValue;
+ Adapter->Media[i].SiaRegister[2] = DC21X4Configuration[RGS_SIA2].RegistryValue;
+ }
+ }
+
+ switch (Adapter->DeviceId) {
+
+ case DC21040_CFID:
+
+ Adapter->LinkSpeed = TEN_MBPS;
+
+ Mode |= Adapter->Threshold10Mbps;
+
+ Adapter->Media[Medium10BaseT].Mode |= Mode;
+ Adapter->Media[Medium10Base2].Mode |= Mode;
+ Adapter->Media[Medium10Base5].Mode |= Mode;
+
+ if (Adapter->MediaType == Medium10BaseTFullDuplex) {
+ Adapter->MediaType = (Medium10BaseT | MEDIA_FULL_DUPLEX);
+ Adapter->Media[Medium10BaseT].SiaRegister[1] = DC21040_SIA1_10BT_FULL_DUPLEX;
+ Adapter->Media[Medium10BaseT].Mode |= DC21X4_FULL_DUPLEX_MODE;
+ Adapter->FullDuplexLink = TRUE;
+ }
+ else if (Adapter->MediaType & MEDIA_LINK_DISABLE) {
+ //Disable Link Test
+ Adapter->Media[Medium10BaseT].SiaRegister[1] = DC21040_SIA1_10BT_LINK_DISABLE;
+ }
+
+ Adapter->SelectedMedium = Adapter->MediaType & MEDIA_MASK;
+ Adapter->MediaCapable &= (1 << Adapter->SelectedMedium);
+
+ break;
+
+ case DC21041_CFID:
+
+ Adapter->LinkSpeed = TEN_MBPS;
+
+ Mode |= Adapter->Threshold10Mbps;
+
+ Adapter->Media[Medium10BaseT].Mode |= Mode;
+ Adapter->Media[Medium10Base2].Mode |= Mode;
+ Adapter->Media[Medium10Base5].Mode |= Mode;
+
+ if (Adapter->MediaType == Medium10BaseTFullDuplex) {
+ Adapter->MediaType = (Medium10BaseT | MEDIA_FULL_DUPLEX);
+ }
+
+ if(Adapter->MediaType & MEDIA_NWAY) {
+
+ //Enable Nway Negotiation
+ DC21X4EnableNway (Adapter);
+ }
+
+ if (Adapter->MediaType & MEDIA_AUTOSENSE) {
+
+ //AutoSense mode:
+ Adapter->Media[Medium10Base2].SiaRegister[1] |= DC21041_LINK_TEST_ENABLED;
+ Adapter->Media[Medium10Base5].SiaRegister[1] |= DC21041_LINK_TEST_ENABLED;
+
+ // TP link is down after reset: Initialize to 10Base2 or 10Base5
+ Adapter->SelectedMedium = (Adapter->MediaCapable & MEDIUM_10B2) ?
+ Medium10Base2 : Medium10Base5;
+ }
+ else {
+ Adapter->SelectedMedium = Adapter->MediaType & MEDIA_MASK;
+ Adapter->MediaCapable &= (1 << Adapter->SelectedMedium);
+ }
+ if (Adapter->MediaType & MEDIA_FULL_DUPLEX) {
+
+ // Full Duplex mode:
+ Adapter->Media[Medium10BaseT].Mode |= DC21X4_FULL_DUPLEX_MODE;
+ Adapter->Media[Medium10BaseT].SiaRegister[1] = DC21041_SIA1_10BT_FULL_DUPLEX;
+ Adapter->FullDuplexLink = TRUE;
+ }
+ else if (Adapter->MediaType & MEDIA_LINK_DISABLE) {
+
+ //Disable Link Test mode:
+ Adapter->Media[Medium10BaseT].SiaRegister[1] = DC21041_SIA1_10BT_LINK_DISABLE;
+ }
+
+ break;
+
+ case DC21140_CFID :
+
+ Mode |= DC21X4_LINK_HYSTERESIS;
+
+ Adapter->Media[Medium10BaseT].Mode |= Mode;
+ Adapter->Media[Medium10Base2].Mode |= Mode;
+ Adapter->Media[Medium10Base5].Mode |= Mode;
+ Adapter->Media[Medium100BaseTx].Mode |= Mode;
+ Adapter->Media[Medium100BaseTxFd].Mode |= Mode;
+ Adapter->Media[Medium100BaseT4].Mode |= Mode;
+
+ // Select Scrambler mode to enable 100BaseTx link status
+ // while in 10BT mode
+
+ Adapter->Media[Medium10BaseT].Mode |= DC21X4_SCRAMBLER;
+ Adapter->Media[Medium10Base2].Mode |= DC21X4_SCRAMBLER;
+ Adapter->Media[Medium10Base5].Mode |= DC21X4_SCRAMBLER;
+ Adapter->Media[Medium100BaseTx].Mode |= DC21X4_OPMODE_100BTX;
+ Adapter->Media[Medium100BaseTxFd].Mode |= DC21X4_OPMODE_100BTX;
+
+ if (Adapter->MediaType & MEDIA_FULL_DUPLEX) {
+ Adapter->Media[Medium10BaseT].Mode |= DC21X4_FULL_DUPLEX_MODE;
+ Adapter->Media[Medium100BaseTxFd].Mode |= DC21X4_FULL_DUPLEX_MODE;
+ Adapter->FullDuplexLink = TRUE;
+ }
+
+ if (!(Adapter->MediaType & MEDIA_AUTOSENSE)) {
+ Adapter->SelectedMedium = Adapter->MediaType & MEDIA_MASK;
+ Adapter->MediaCapable &= (1 << Adapter->SelectedMedium);
+
+ Adapter->LinkSpeed =
+ (Adapter->Media[Adapter->SelectedMedium].Mode & DC21X4_SCRAMBLER) ?
+ TEN_MBPS : ONE_HUNDRED_MBPS;
+ }
+ else {
+ Adapter->LinkSpeed = TEN_MBPS;
+ }
+ break;
+
+ case DC21142_CFID:
+
+ Mask = Mode | Adapter->Threshold10Mbps;
+
+ Adapter->Media[Medium10BaseT].Mode |= Mask;
+ Adapter->Media[Medium10Base2].Mode |= Mask;
+ Adapter->Media[Medium10Base5].Mode |= Mask;
+
+ Mask = Mode | Adapter->Threshold100Mbps;
+
+ Adapter->Media[Medium100BaseTx].Mode |= Mask;
+ Adapter->Media[Medium100BaseT4].Mode |= Mask;
+
+ if (Adapter->MediaType == Medium10BaseTFullDuplex) {
+ Adapter->MediaType = (Medium10BaseT | MEDIA_FULL_DUPLEX);
+ }
+
+ if (Adapter->MediaType & MEDIA_NWAY) {
+
+ // if the PHY is present and NWAY capable, the Nway negotiation
+ // is performed by the PHY,otherwise by the DC21X4
+
+ if (!(Adapter->PhyPresent && Adapter->PhyNwayCapable)) {
+
+ //Enable DC21X4's Nway Negotiation
+ DC21X4EnableNway (Adapter);
+ }
+#if __DBG
+ else {
+ DbgPrint("PHY Nway capable: Disable DC21X4's NWAY\n");
+ }
+#endif
+ }
+
+ if (Adapter->MediaType & MEDIA_AUTOSENSE) {
+
+ //AutoSense mode:
+
+ Adapter->Media[Medium10Base2].SiaRegister[1] |=DC21142_LINK_TEST_ENABLED;
+ Adapter->Media[Medium10Base5].SiaRegister[1] |=DC21142_LINK_TEST_ENABLED;
+
+ // TP link is down after reset:
+ // Initialize to 10Base2 or 10Base5 if populated
+
+ Adapter->SelectedMedium =
+ (Adapter->MediaCapable & MEDIUM_10B2) ? Medium10Base2 :
+ (Adapter->MediaCapable & MEDIUM_10B5) ? Medium10Base5 :
+ Adapter->MediaType & MEDIA_MASK;
+
+ Adapter->LinkSpeed = TEN_MBPS;
+ }
+ else{
+
+ //Non AutoSense mode:
+
+ Adapter->SelectedMedium = Adapter->MediaType & MEDIA_MASK;
+ Adapter->MediaCapable &= (1 << Adapter->SelectedMedium);
+
+ switch (Adapter->SelectedMedium) {
+
+ case Medium100BaseTx:
+ case Medium100BaseT4:
+ case Medium100BaseFx:
+
+ Adapter->LinkSpeed = ONE_HUNDRED_MBPS;
+ break;
+
+ default:
+
+ Adapter->LinkSpeed = TEN_MBPS;
+ break;
+ }
+ }
+
+ if (Adapter->MediaType & MEDIA_FULL_DUPLEX) {
+
+ // Full Duplex mode:
+ Adapter->Media[Medium10BaseT].SiaRegister[1] = DC21142_SIA1_10BT_FULL_DUPLEX;
+
+ Adapter->Media[Medium10BaseT].Mode |= DC21X4_FULL_DUPLEX_MODE;
+ Adapter->Media[Medium100BaseTx].Mode |= DC21X4_FULL_DUPLEX_MODE;
+ Adapter->FullDuplexLink = TRUE;
+
+ }
+ else if (Adapter->MediaType & MEDIA_LINK_DISABLE) {
+
+ //Disable Link Test mode:
+ Adapter->Media[Medium10BaseT].SiaRegister[1] =DC21142_SIA1_10BT_LINK_DISABLE;
+ }
+ break;
+
+ }
+
+
+#if __DBG
+ DbgPrint ("MediaType = %x\n",Adapter->MediaType);
+#endif
+
+ if (Adapter->PhyPresent) {
+
+ //Try to establish the Mii PHY connection
+
+#if 0
+ if (!(Adapter->MiiMediaType & MEDIA_NWAY)) {
+
+ DC21X4SetPhyControl(
+ Adapter,
+ (USHORT)MiiGenAdminIsolate
+ );
+ }
+#endif
+
+ Adapter->PhyPresent=DC21X4SetPhyConnection(Adapter);
+#if __DBG
+ DbgPrint("PHY Connection %s for the requested medium: %x\n",
+ Adapter->PhyPresent ? "succeed" : "failed" , Adapter->MiiMediaType);
+#endif
+ }
+
+ //Check that at least one of the selected media is
+ //supported by this adapter
+
+ if (!Adapter->PhyPresent && !Adapter->MediaCapable) {
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
+ 1,
+ DC21X4_ERRMSG_MEDIA
+ );
+ FreeAdapterResources(Adapter,4);
+ return NDIS_STATUS_UNSUPPORTED_MEDIA;
+ }
+
+ Adapter->OperationMode |= Adapter->Media[Adapter->SelectedMedium].Mode;
+
+ Adapter->TransmitDescriptorErrorMask =
+ Adapter->TransmitDefaultDescriptorErrorMask;
+ if (Adapter->FullDuplexLink) {
+ //Mask Loss_of_Carrrier and No_Carrier Txm status bits
+ Adapter->TransmitDescriptorErrorMask &=
+ ~(DC21X4_TDES_NO_CARRIER | DC21X4_TDES_LOSS_OF_CARRIER);
+ }
+
+ if (!Adapter->PhyPresent) {
+ // Initialize the Medium registers
+ DC21X4InitializeMediaRegisters(
+ Adapter,
+ FALSE
+ );
+ }
+
+ // Load DC21X4's Cam in polling mode
+
+ if (!DC21X4LoadCam(
+ Adapter,
+ FALSE)) {
+
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_TIMEOUT,
+ 1,
+ DC21X4_ERRMSG_LOAD_CAM
+ );
+ FreeAdapterResources(Adapter,5);
+ return NDIS_STATUS_FAILURE;
+ }
+
+ if (Adapter->ParityError) {
+
+ FreeAdapterResources(Adapter,5);
+ return NDIS_STATUS_FAILURE;
+ }
+
+ // Start DC21X4's Txm and Rcv Processes
+
+ Adapter->FirstAncInterrupt = TRUE;
+
+ DC21X4StartAdapter(Adapter);
+
+ {
+ // Media link Detection
+ if (Adapter->PhyPresent) {
+ Link = DC21X4MiiAutoDetect(
+ Adapter
+ );
+ }
+ if ( (!Adapter->PhyPresent)
+ || (!Link
+ && (Adapter->MediaCapable)
+ )
+ ) {
+
+ StartTimer = DC21X4MediaDetect(
+ Adapter
+ );
+ }
+
+ // Start the Autosense timer if not yet started
+
+ if (StartTimer && (Adapter->TimerFlag==NoTimer)) {
+
+ DC21X4StartAutoSenseTimer(
+ Adapter,
+ (UINT)(2*DC21X4_SPA_TICK)
+ );
+ }
+
+ }
+
+ switch (Adapter->DeviceId) {
+
+ case DC21140_CFID:
+ case DC21142_CFID:
+
+ if (Adapter->InterruptThreshold) {
+#if __DBG
+ DbgPrint ("Start Monitor timer\n");
+#endif
+ NdisMSetTimer(
+ &Adapter->MonitorTimer,
+ INT_MONITOR_PERIOD
+ );
+ }
+ }
+
+ //The Initialization is completed
+#if __DBG
+ DbgPrint ("Initialize done\n");
+#endif
+ Adapter->Initializing = FALSE;
+ return NDIS_STATUS_SUCCESS;
+
+}
+
+#pragma NDIS_PAGABLE_FUNCTION(FreeAdapterResources)
+
+/*+
+ * DC21X4FreeAdapterResources
+ *
+ * Routine Description:
+ *
+ * Free the adapter resources
+ *
+ * Arguments:
+ *
+ * Adapter
+ * Step
+ *
+ * Return Value:
+ *
+ * None
+ *
+-*/
+
+extern
+VOID
+FreeAdapterResources(
+ IN PDC21X4_ADAPTER Adapter,
+ IN INT Step
+ )
+{
+
+ switch (Step) {
+
+ case 5:
+
+
+ NdisMDeregisterAdapterShutdownHandler(
+ Adapter->MiniportAdapterHandle
+ );
+
+ NdisFreeSpinLock(
+ &Adapter->EnqueueSpinLock
+ );
+ NdisFreeSpinLock(
+ &Adapter->FullDuplexSpinLock
+ );
+
+ NdisMDeregisterInterrupt(
+ &Adapter->Interrupt
+ );
+
+ case 4:
+
+ if (Adapter->PhyPresent) {
+ MiiFreeResources(Adapter);
+ }
+
+ case 3:
+
+ FreeAdapterMemory(
+ Adapter
+ );
+
+ NdisMFreeMapRegisters(
+ Adapter->MiniportAdapterHandle
+ );
+
+ case 2:
+
+ NdisMDeregisterIoPortRange(
+ Adapter->MiniportAdapterHandle,
+ Adapter->IOBaseAddress,
+ Adapter->IOSpace,
+ (PVOID)Adapter->PortOffset
+ );
+
+ case 1:
+
+ FREE_MEMORY(
+ Adapter,
+ sizeof(DC21X4_ADAPTER)
+ );
+ }
+
+}
+
+#pragma NDIS_PAGABLE_FUNCTION(FindPciConfiguration)
+
+/*+
+ * FindPciConfiguration
+ *
+ *
+ * Routine Description:
+ *
+ * Assign resources and walk the resource list
+ * to extract the configuration information
+ *
+ *
+ * Arguments:
+ *
+ * NdisMacHandle
+ * NdisWrapperHandle
+ * NdisConfigurationHandle
+ * SlotNumber
+ *
+ * Return Value:
+ *
+ * TRUE if valid information
+ *
+-*/
+
+
+NDIS_STATUS
+FindPciConfiguration(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN ULONG SlotNumber,
+ OUT PULONG PortStart,
+ OUT PULONG PortLength,
+ OUT PULONG InterruptLevel,
+ OUT PULONG InterruptVector
+ )
+{
+
+ PNDIS_RESOURCE_LIST ResourceList;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor;
+
+ NDIS_STATUS NdisStatus;
+ ULONG i;
+
+#if __DBG
+ DbgPrint("PCI Assign Resources\n");
+#endif
+
+ NdisStatus = NdisMPciAssignResources(
+ MiniportAdapterHandle,
+ SlotNumber,
+ &ResourceList
+ );
+
+ if (NdisStatus!= NDIS_STATUS_SUCCESS) {
+ return NdisStatus;
+ }
+
+#if __DBG
+ DbgPrint(" ResourceList = %x Count = %d\n",
+ ResourceList,ResourceList->Count);
+#endif
+
+ // Walk the resources list to extract the configuration
+ // information needed to register the adapter
+
+ for (i=0;i < ResourceList->Count; i++) {
+
+ ResourceDescriptor = &ResourceList->PartialDescriptors[i];
+
+ switch (ResourceDescriptor->Type) {
+
+ case CmResourceTypeInterrupt:
+
+ *InterruptLevel = ResourceDescriptor->u.Interrupt.Level;
+ *InterruptVector = ResourceDescriptor->u.Interrupt.Vector;
+#if __DBG
+ DbgPrint(" Interrupt Level=%x Vector=%x\n",
+ ResourceDescriptor->u.Interrupt.Level,
+ ResourceDescriptor->u.Interrupt.Vector);
+#endif
+
+ break;
+
+ case CmResourceTypePort:
+
+ *PortStart = NdisGetPhysicalAddressLow(ResourceDescriptor->u.Port.Start);
+ *PortLength = ResourceDescriptor->u.Port.Length;
+#if __DBG
+ DbgPrint(" Port = %x Len = %x\n",
+ NdisGetPhysicalAddressLow(ResourceDescriptor->u.Port.Start),
+ ResourceDescriptor->u.Port.Length);
+#endif
+ break;
+ }
+ }
+
+ return NdisStatus;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*+
+ * DC21X4Halt
+ *
+ * Routine Description:
+ *
+ * DC21X4Halt stop the adapter and deregister all its resources
+ *
+-*/
+
+extern
+VOID
+DC21X4Halt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+{
+
+ PDC21X4_ADAPTER Adapter;
+ BOOLEAN Canceled;
+
+ Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
+
+#if __DBG
+ DbgPrint("DC21X4Halt\n");
+#endif
+
+ //
+ // stop the adapter
+ //
+ switch (Adapter->AdapterType) {
+
+ case NdisInterfaceEisa:
+
+ // Use HW reset instead of SW reset
+
+#if _DBG
+ DbgPrint(" HW reset\n");
+#endif
+
+ NdisRawWritePortUchar (
+ Adapter->PortOffset + EISA_REG1_OFFSET,
+ 0x01
+ );
+
+ NdisRawWritePortUchar (
+ Adapter->PortOffset + EISA_REG1_OFFSET,
+ 0
+ );
+
+ break;
+
+ default:
+
+ // Set the SW Reset bit in BUS_MODE register
+
+#if _DBG
+ DbgPrint(" SW reset\n");
+#endif
+
+ DC21X4_WRITE_PORT(
+ DC21X4_BUS_MODE,
+ DC21X4_SW_RESET);
+ }
+
+ // Wait 50 PCI bus cycles to wait for reset completion
+
+ NdisStallExecution(2*MILLISECOND); // Wait for 2 ms
+
+ //Deregister the adapter's resources
+
+ FreeAdapterMemory(Adapter);
+
+ NdisMCancelTimer(
+ &Adapter->Timer,
+ &Canceled
+ );
+
+
+ NdisMCancelTimer(
+ &Adapter->MonitorTimer,
+ &Canceled
+ );
+
+
+ NdisMDeregisterAdapterShutdownHandler(
+ Adapter->MiniportAdapterHandle
+ );
+
+ NdisFreeSpinLock(
+ &Adapter->EnqueueSpinLock
+ );
+ NdisFreeSpinLock(
+ &Adapter->FullDuplexSpinLock
+ );
+
+
+ NdisMDeregisterInterrupt(
+ &Adapter->Interrupt
+ );
+
+ NdisMDeregisterIoPortRange(
+ Adapter->MiniportAdapterHandle,
+ Adapter->IOBaseAddress,
+ Adapter->IOSpace,
+ (PVOID)Adapter->PortOffset
+ );
+
+ NdisMFreeMapRegisters(
+ Adapter->MiniportAdapterHandle
+ );
+
+
+ if (Adapter->PhyPresent) {
+ MiiFreeResources(Adapter);
+ }
+
+ FREE_MEMORY(Adapter, sizeof(DC21X4_ADAPTER));
+
+ return;
+
+}
+
+
+
+
+
+
+
+
+
+
+/*+
+ *
+ * DC21X4Shutdown
+ *
+ * Routine Description:
+ *
+ * Handle system shutdown operation. This is currently done by
+ * forcing DC21X4 reset.
+ *
+ * Arguments:
+ *
+ * ShutdownContext - A pointer to a DC21X4_ADAPTER structure. This
+ * is the value passed as the context parameter
+ * to the function NdisRegisterAdapterShutdownHandler().
+ *
+ * Return Value:
+ *
+ * none
+ *
+-*/
+extern
+VOID
+DC21X4Shutdown(
+ IN PVOID ShutdownContext
+ )
+{
+
+ PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)ShutdownContext;
+
+#if __DBG
+ DbgPrint("DC21X4Shutdown\n");
+#endif
+
+ Adapter->Initializing = TRUE;
+ DC21X4StopAdapter(Adapter);
+
+}
+
+
+
+
+
+
+
+
+
+
+#ifdef _MIPS_
+
+// The next routines are to support reading the registry to
+// obtain information about the DC21X4 on MIPS machines.
+
+// This structure is used as the Context in the callbacks
+// to DC21X4HardwareSaveInformation.
+
+typedef struct _DC21X4_HARDWARE_INFO {
+
+ // These are read out of the "Configuration Data" data.
+
+ CCHAR InterruptVector;
+ KIRQL InterruptLevel;
+ USHORT DataConfigurationRegister;
+ LARGE_INTEGER PortAddress;
+ BOOLEAN DataValid;
+ UCHAR EthernetAddress[8];
+ BOOLEAN AddressValid;
+
+ // This is set to TRUE if "Identifier" is equal to "DC21040".
+
+ BOOLEAN DC21X4Identifier;
+
+} DC21X4_HARDWARE_INFO, *PDC21X4_HARDWARE_INFO;
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*+
+ *
+ * DC21X4HardwareSaveInformation
+ *
+ * Routine Description:
+ *
+ * This routine is a callback routine for RtlQueryRegistryValues.
+ * It is called back with the data for the "Identifier" value
+ * and verifies that it is "DC21040", then is called back with
+ * the resource list and records the ports, interrupt number,
+ * and DCR value.
+ *
+ * Arguments:
+ *
+ * ValueName - The name of the value ("Identifier" or "Configuration Data").
+ * ValueType - The type of the value (REG_SZ or REG_BINARY).
+ * ValueData - The null-terminated data for the value.
+ * ValueLength - The length of ValueData (ignored).
+ * Context - A pointer to the DC21X4_HARDWARE_INFO structure.
+ * EntryContext - FALSE for "Identifier", TRUE for "Configuration Data".
+ *
+ * Return Value:
+ *
+ * STATUS_SUCCESS
+ *
+-*/
+
+NTSTATUS
+DC21X4HardwareSaveInformation(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+{
+ PDC21X4_HARDWARE_INFO HardwareInfo = (PDC21X4_HARDWARE_INFO)Context;
+
+ if ((BOOLEAN)EntryContext) {
+
+ // This is the "Configuration Data" callback.
+
+ if ((ValueType == REG_BINARY || ValueType == REG_FULL_RESOURCE_DESCRIPTOR) &&
+ (ValueLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR))) {
+
+ BOOLEAN DeviceSpecificRead = FALSE;
+ UINT i;
+
+ PCM_PARTIAL_RESOURCE_LIST ResourceList;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor;
+ PCM_SONIC_DEVICE_DATA DC21X4DeviceData;
+
+ ResourceList =
+ &((PCM_FULL_RESOURCE_DESCRIPTOR)ValueData)->PartialResourceList;
+
+ for (i = 0; i < ResourceList->Count; i++) {
+
+ ResourceDescriptor = &(ResourceList->PartialDescriptors[i]);
+
+ switch (ResourceDescriptor->Type) {
+
+ case CmResourceTypeDeviceSpecific:
+
+ if (i == ResourceList->Count-1) {
+
+ DC21X4DeviceData = (PCM_SONIC_DEVICE_DATA)
+ &(ResourceList->PartialDescriptors[ResourceList->Count]);
+
+ // Make sure we have enough room for each element we read.
+
+ if (ResourceDescriptor->u.DeviceSpecificData.DataSize >=
+ (ULONG)(FIELD_OFFSET (CM_SONIC_DEVICE_DATA, EthernetAddress[0]))) {
+
+ HardwareInfo->DataConfigurationRegister =
+ DC21X4DeviceData->DataConfigurationRegister;
+ DeviceSpecificRead = TRUE;
+
+ if (ResourceDescriptor->u.DeviceSpecificData.DataSize >=
+ (ULONG)(FIELD_OFFSET (CM_SONIC_DEVICE_DATA, EthernetAddress[0]) + 8)) {
+
+ MOVE_MEMORY(
+ HardwareInfo->EthernetAddress,
+ DC21X4DeviceData->EthernetAddress,
+ 8);
+
+ HardwareInfo->AddressValid = TRUE;
+ }
+ }
+ }
+ break;
+ }
+
+ }
+
+ // Make sure we got all we wanted.
+
+ if (DeviceSpecificRead) {
+ HardwareInfo->DataValid = TRUE;
+ }
+
+ }
+
+ }
+ else {
+
+ static const WCHAR DC21040String[] = L"DC21040";
+
+ // This is the "Identifier" callback.
+
+ if ((ValueType == REG_SZ) &&
+ (ValueLength >= sizeof(DC21040String)) &&
+ (RtlCompareMemory (ValueData, (PVOID)&DC21040String, sizeof(DC21040String)) == sizeof(DC21040String))) {
+
+ HardwareInfo->DC21X4Identifier = TRUE;
+
+ }
+ }
+
+ return STATUS_SUCCESS;
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*+
+ *
+ * DC21X4HardwareVerifyChecksum
+ *
+ * Routine Description:
+ *
+ * This routine verifies that the checksum on the address
+ * on MIPS systems.
+ *
+ * Arguments:
+ *
+ * Adapter - The adapter which is being verified.
+ *
+ * EthernetAddress - A pointer to the address, with the checksum
+ * following it.
+ *
+ * ErrorLogData - If the checksum is bad, returns the address
+ * and the checksum we expected.
+ *
+ * Return Value:
+ *
+ * TRUE if the checksum is correct.
+ *
+-*/
+
+BOOLEAN
+DC21X4HardwareVerifyChecksum(
+ IN PDC21X4_ADAPTER Adapter,
+ IN PUCHAR EthernetAddress
+ )
+
+{
+ UINT i;
+ USHORT CheckSum = 0;
+
+ // The network address is stored in the first 6 bytes of
+ // EthernetAddress. Following that is a zero byte followed
+ // by a value such that the sum of a checksum on the six
+ // bytes and this value is 0xff. The checksum is computed
+ // by adding together the six bytes, with the carry being
+ // wrapped back to the first byte.
+
+ for (i=0; i<6; i++) {
+
+ CheckSum += EthernetAddress[i];
+ if (CheckSum > 0xff) {
+ CheckSum -= 0xff;
+ }
+ }
+
+ if ((EthernetAddress[6] != 0x00) ||
+ ((EthernetAddress[7] + CheckSum) != 0xff)) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*+
+ * DC21X4HardwareGetDetails
+ *
+ * Routine Description:
+ *
+ * This routine gets the ethernet address from the registry
+ *
+ * Arguments:
+ *
+ * Adapter - The adapter in question.
+ *
+ * Controller - For the internal version, it is the
+ * NetworkController number.
+ *
+ * MultifunctionAdapter - For the internal version, it is the adapter number.
+ *
+ * Return Value:
+ *
+ * STATUS_SUCCESS if it read the ethernet address successfully;
+ * STATUS_FAILURE otherwise.
+ *
+-*/
+
+NDIS_STATUS
+DC21X4HardwareGetDetails(
+ IN PDC21X4_ADAPTER Adapter,
+ IN UINT Controller,
+ IN UINT MultifunctionAdapter
+ )
+
+{
+ LPWSTR ConfigDataPath = L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter\\#\\NetworkController\\#";
+ LPWSTR IdentifierString = L"Identifier";
+ LPWSTR ConfigDataString = L"Configuration Data";
+ RTL_QUERY_REGISTRY_TABLE QueryTable[4];
+ DC21X4_HARDWARE_INFO DC21X4HardwareInfo;
+ NTSTATUS Status;
+
+
+ switch (Adapter->AdapterType) {
+
+ case NdisInterfacePci:
+
+ // For MIPS systems, we have to query the registry to obtain
+ // information about the ethernet address.
+
+ // NOTE: The following code is NT-specific for the MIPS R4000 hardware.
+
+ // We initialize an RTL_QUERY_TABLE to retrieve the Identifer
+ // and ConfigurationData strings from the registry.
+
+ // Set up QueryTable to do the following:
+
+ // 1) Call DC21X4HardwareSaveInformation for the "Identifier" value.
+
+ QueryTable[0].QueryRoutine = DC21X4HardwareSaveInformation;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[0].Name = IdentifierString;
+ QueryTable[0].EntryContext = (PVOID)FALSE;
+ QueryTable[0].DefaultType = REG_NONE;
+
+ // 2) Call DC21X4HardwareSaveInformation for the "Configuration Data" value.
+
+ QueryTable[1].QueryRoutine = DC21X4HardwareSaveInformation;
+ QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[1].Name = ConfigDataString;
+ QueryTable[1].EntryContext = (PVOID)TRUE;
+ QueryTable[1].DefaultType = REG_NONE;
+
+ // 3) Stop
+
+ QueryTable[2].QueryRoutine = NULL;
+ QueryTable[2].Flags = 0;
+ QueryTable[2].Name = NULL;
+
+ // Modify ConfigDataPath to replace the two # symbols with
+ // the MultifunctionAdapter number and NetworkController number.
+
+ ConfigDataPath[67] = (WCHAR)('0' + MultifunctionAdapter);
+ ConfigDataPath[87] = (WCHAR)('0' + Controller);
+
+ DC21X4HardwareInfo.DataValid = FALSE;
+ DC21X4HardwareInfo.AddressValid = FALSE;
+ DC21X4HardwareInfo.DC21X4Identifier = FALSE;
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ ConfigDataPath,
+ QueryTable,
+ (PVOID)&DC21X4HardwareInfo,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+#if __DBG
+ DbgPrint ("Could not read hardware information\n");
+#endif
+ return NDIS_STATUS_FAILURE;
+ }
+
+ if (DC21X4HardwareInfo.DataValid && DC21X4HardwareInfo.DC21X4Identifier) {
+
+ if (DC21X4HardwareInfo.AddressValid) {
+
+ if (!DC21X4HardwareVerifyChecksum(Adapter, DC21X4HardwareInfo.EthernetAddress)) {
+#if __DBG
+ DbgPrint("Invalid registry network address checksum!!\n");
+#endif
+ return NDIS_STATUS_FAILURE;
+ }
+
+ MOVE_MEMORY(
+ Adapter->PermanentNetworkAddress,
+ DC21X4HardwareInfo.EthernetAddress,
+ 8);
+ Adapter->PermanentAddressValid = TRUE;
+
+ }
+
+ return NDIS_STATUS_SUCCESS;
+ }
+ else {
+
+#if __DBG
+ DbgPrint ("Incorrect registry hardware information\n");
+#endif
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+
+ return NDIS_STATUS_FAILURE;
+
+}
+
+#endif
+
diff --git a/private/ntos/ndis/dc21x4/request.c b/private/ntos/ndis/dc21x4/request.c
new file mode 100644
index 000000000..a29f09643
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/request.c
@@ -0,0 +1,530 @@
+/*+
+ * file: request.c
+ *
+ * Copyright (C) 1992-1995 by
+ * Digital Equipment Corporation, Maynard, Massachusetts.
+ * All rights reserved.
+ *
+ * This software is furnished under a license and may be used and copied
+ * only in accordance of the terms of such license and with the
+ * inclusion of the above copyright notice. This software or any other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person. No title to and ownership of the software is hereby
+ * transferred.
+ *
+ * The information in this software is subject to change without notice
+ * and should not be construed as a commitment by digital equipment
+ * corporation.
+ *
+ * Digital assumes no responsibility for the use or reliability of its
+ * software on equipment which is not supplied by digital.
+ *
+ *
+ * Abstract: This file contains the request handler for the NDIS 4.0
+ * miniport driver for DEC's DC21X4 Ethernet adapter.
+ *
+ * Author: Philippe Klein
+ *
+ * Revision History:
+ *
+ * phk 28-Aug-1994 Initial entry
+ *
+-*/
+
+#include <precomp.h>
+
+
+
+
+
+
+/*+
+ *
+ * DC21X4QueryInformation
+ *
+ * Routine Description:
+ *
+ * DC21X4QueryInformation handles a query operation for a
+ * single OID.
+ *
+-*/
+
+extern
+NDIS_STATUS
+DC21X4QueryInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+ )
+
+{
+ NDIS_STATUS NdisStatus;
+ PDC21X4_ADAPTER Adapter;
+
+ PNDIS_OID OidArray;
+ NDIS_OID OidIndex;
+ INT MaxOid;
+ BOOLEAN ValidOid;
+
+ UINT MissedFrames;
+ UINT Overflows;
+
+ ULONG Buffer;
+ PVOID BufferPtr;
+ UINT BufferLength;
+
+ INT i;
+
+#if _DBG
+ DbgPrint("DC21X4QueryInformation\n");
+ DbgPrint(" Oid = %08x\n",Oid);
+#endif
+
+ Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
+
+ // Check that the OID is valid.
+
+ OidArray = (PNDIS_OID)DC21X4GlobalOids;
+ MaxOid = sizeof(DC21X4GlobalOids)/sizeof(ULONG);
+
+ ValidOid = FALSE;
+
+ for (i=0; i<MaxOid; i++) {
+
+ if (Oid == OidArray[i]) {
+ ValidOid = TRUE;
+ break;
+ }
+ }
+ if (ValidOid == FALSE) {
+#if _DBG
+ DbgPrint(" INVALID Oid\n");
+#endif
+ *BytesWritten = 0;
+ return NDIS_STATUS_INVALID_OID;
+ }
+
+ BufferPtr = &Buffer;
+ BufferLength = sizeof(Buffer);
+
+ switch (Oid & OID_TYPE_MASK) {
+
+ case OID_TYPE_GENERAL_OPERATIONAL:
+
+ switch (Oid) {
+
+ case OID_GEN_SUPPORTED_LIST:
+
+ BufferPtr = (PVOID)OidArray;
+ BufferLength = sizeof(DC21X4GlobalOids);
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+
+ Buffer = NdisHardwareStatusReady;
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+
+ Buffer = NdisMedium802_3;
+ break;
+
+ case OID_GEN_MEDIA_CONNECT_STATUS:
+
+ Buffer = Adapter->LinkStatus == LinkFail ?
+ NdisMediaStateDisconnected : NdisMediaStateConnected;
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+
+ Buffer = DC21X4_MAX_LOOKAHEAD;
+ break;
+
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+
+ Buffer = DC21X4_MAX_FRAME_SIZE - ETH_HEADER_SIZE;
+ break;
+
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+
+ Buffer = DC21X4_MAX_FRAME_SIZE;
+ break;
+
+ case OID_GEN_LINK_SPEED:
+
+ Buffer = Adapter->LinkSpeed;
+ break;
+
+ case OID_GEN_MAC_OPTIONS:
+
+ Buffer = NDIS_MAC_OPTION_TRANSFERS_NOT_PEND
+ | NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA
+ | NDIS_MAC_OPTION_RECEIVE_SERIALIZED
+ | NDIS_MAC_OPTION_NO_LOOPBACK;
+ if (Adapter->FullDuplexLink) {
+ Buffer |= NDIS_MAC_OPTION_FULL_DUPLEX;
+ }
+ Adapter->FullDuplex = Adapter->FullDuplexLink;
+ break;
+
+ case OID_GEN_PROTOCOL_OPTIONS:
+
+ BufferLength = 0;
+ break;
+
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+
+ Buffer =
+ ((DC21X4_NUMBER_OF_MAX_TRANSMIT_BUFFERS)
+ *(DC21X4_MAX_TRANSMIT_BUFFER_SIZE + Adapter->CacheLineSize))
+ + ((DC21X4_NUMBER_OF_MAX_TRANSMIT_BUFFERS)
+ *(DC21X4_MAX_TRANSMIT_BUFFER_SIZE + Adapter->CacheLineSize))
+ + (DC21X4_SETUP_BUFFER_SIZE);
+ break;
+
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+
+ if (Adapter->RcvBufferSpace.AllocSize) {
+ Buffer = Adapter->RcvBufferSpace.AllocSize;
+ }
+ else {
+ Buffer =
+ ( (Adapter->ReceiveRingSize + Adapter->ExtraReceiveBuffers)
+ * (DC21X4_RECEIVE_BUFFER_SIZE + Adapter->RcvHeaderSize + Adapter->CacheLineSize)
+ );
+ }
+ break;
+
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+
+ Buffer = DC21X4_MAX_TRANSMIT_BUFFER_SIZE;
+ break;
+
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+
+ Buffer = DC21X4_RECEIVE_BUFFER_SIZE;
+ break;
+
+ case OID_GEN_VENDOR_ID:
+
+ if (Adapter->PermanentAddressValid) {
+
+ Buffer = 0;
+ MOVE_MEMORY (BufferPtr, Adapter->PermanentNetworkAddress, 3);
+ BufferLength = 3;
+ }
+ else {
+ BufferLength = 0;
+ }
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+
+ switch(Adapter->DeviceId) {
+
+ case DC21040_CFID:
+
+ switch (Adapter->AdapterType) {
+
+ case NdisInterfaceEisa:
+
+ BufferPtr = (PVOID)DC21040EisaDescriptor;
+ BufferLength = sizeof(DC21040EisaDescriptor);
+ break;
+
+ default:
+ case NdisInterfacePci:
+
+ BufferPtr = (PVOID)DC21040PciDescriptor;
+ BufferLength = sizeof(DC21040PciDescriptor);
+ break;
+ }
+ break;
+
+ case DC21041_CFID:
+
+ BufferPtr = (PVOID)DC21041PciDescriptor;
+ BufferLength = sizeof(DC21041PciDescriptor);
+ break;
+
+ case DC21140_CFID:
+
+ BufferPtr = (PVOID)DC21140PciDescriptor;
+ BufferLength = sizeof(DC21140PciDescriptor);
+ break;
+
+ case DC21142_CFID:
+
+ BufferPtr = (PVOID)DC21142PciDescriptor;
+ BufferLength = sizeof(DC21142PciDescriptor);
+ break;
+
+
+ default:
+
+ BufferLength = 0;
+ }
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ Buffer = DC21X4_MAX_LOOKAHEAD;
+ break;
+
+ case OID_GEN_DRIVER_VERSION:
+
+ Buffer = (DC21X4_NDIS_MAJOR_VERSION << 8)
+ + DC21X4_NDIS_MINOR_VERSION;
+ BufferLength = sizeof(USHORT);
+ }
+
+ break;
+
+ case OID_TYPE_GENERAL_STATISTICS:
+
+ DC21X4_READ_PORT(
+ DC21X4_MISSED_FRAME,
+ &Buffer
+ );
+
+ MissedFrames = Buffer & DC21X4_MISSED_FRAME_COUNTER;
+ Adapter->GeneralMandatory[GM_MISSED_FRAMES] += MissedFrames;
+
+ switch(Adapter->DeviceId) {
+
+ case DC21041_CFID:
+ case DC21142_CFID:
+
+ Overflows = (Buffer >> DC21X4_OVERFLOW_COUNTER_SHIFT)
+ & DC21X4_OVERFLOW_COUNTER;
+ Adapter->IndicateOverflow = (Overflows!=0);
+ Adapter->MediaOptional[MO_RECEIVE_OVERFLOW]+= Overflows;
+
+ }
+
+ OidIndex = (Oid & OID_INDEX_MASK) - 1;
+
+ switch (Oid & OID_REQUIRED_MASK) {
+
+ case OID_REQUIRED_MANDATORY:
+
+ BufferPtr = (PVOID)&Adapter->GeneralMandatory[OidIndex];
+#if _DBG
+ DbgPrint("GMandatory[%d] = %d\n", OidIndex,
+ Adapter->GeneralMandatory[OidIndex]);
+#endif
+ break;
+
+
+ case OID_REQUIRED_OPTIONAL:
+
+ if (Oid == OID_GEN_RCV_CRC_ERROR) {
+
+ BufferPtr = &Adapter->GeneralOptional[GO_RECEIVE_CRC_ERROR];
+ break;
+ }
+
+ if (Oid == OID_GEN_TRANSMIT_QUEUE_LENGTH) {
+
+ BufferPtr = &Adapter->GeneralOptional[GO_TRANSMIT_QUEUE_LENGTH];
+ break;
+ }
+
+ if (OidIndex & 0x01) {
+
+ // Frame count
+ BufferPtr = &Adapter->GeneralOptionalCount[OidIndex >> 1].FrameCount;
+#if _DBG
+ DbgPrint("FrameCount[%d] = %d\n", OidIndex >> 1,
+ Adapter->GeneralOptionalCount[OidIndex >> 1].FrameCount);
+#endif
+ } else {
+
+ // Byte count
+ BufferPtr = &Adapter->GeneralOptionalCount[OidIndex >> 1].ByteCount;
+ BufferLength = sizeof(DC21X4_LARGE_INTEGER);
+#if _DBG
+ DbgPrint("ByteCount[%d] = %d\n", OidIndex >> 1,
+ Adapter->GeneralOptionalCount[OidIndex >> 1].ByteCount);
+#endif
+ }
+
+ }
+
+ break;
+
+ case OID_TYPE_802_3_OPERATIONAL:
+
+ switch (Oid) {
+
+ case OID_802_3_PERMANENT_ADDRESS:
+
+ if (Adapter->PermanentAddressValid) {
+ BufferPtr = Adapter->PermanentNetworkAddress;
+ BufferLength = 6;
+ }
+ else {
+ BufferLength = 0;
+ }
+ break;
+
+ case OID_802_3_CURRENT_ADDRESS:
+
+ BufferPtr = Adapter->CurrentNetworkAddress;
+ BufferLength = 6;
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+
+ Buffer = Adapter->MaxMulticastAddresses;
+ }
+ break;
+
+ case OID_TYPE_802_3_STATISTICS:
+
+ OidIndex = (Oid & OID_INDEX_MASK) - 1;
+
+ switch (Oid & OID_REQUIRED_MASK) {
+
+ case OID_REQUIRED_MANDATORY:
+
+ BufferPtr = &Adapter->MediaMandatory[OidIndex];
+ break;
+
+ case OID_REQUIRED_OPTIONAL:
+
+ BufferPtr = &Adapter->MediaOptional[OidIndex];
+ }
+ break;
+
+ }
+
+
+ if (BufferLength > InformationBufferLength) {
+ *BytesNeeded = BufferLength;
+ NdisStatus = NDIS_STATUS_INVALID_LENGTH;
+ }
+ else {
+ MOVE_MEMORY(InformationBuffer,BufferPtr,BufferLength);
+ *BytesWritten = BufferLength;
+ NdisStatus = NDIS_STATUS_SUCCESS;
+ }
+
+ return NdisStatus;
+
+}
+
+
+
+
+
+
+
+
+/*+
+ * DC21X4SetInformation
+ *
+ * Routine Description:
+ *
+ * DC21X4SetInformation handles a set operation for a
+ * single OID.
+ *
+-*/
+extern
+NDIS_STATUS
+DC21X4SetInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ )
+
+{
+ NDIS_STATUS NdisStatus;
+ PDC21X4_ADAPTER Adapter;
+ ULONG Filter;
+
+#if _DBG
+ DbgPrint("DC21X4SetInformation\n");
+ DbgPrint(" Oid = %08x\n",Oid);
+#endif
+
+
+ Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
+
+ *BytesNeeded = 0;
+
+ switch (Oid) {
+
+ case OID_802_3_MULTICAST_LIST:
+
+ if (InformationBufferLength % ETH_LENGTH_OF_ADDRESS) {
+ *BytesRead = 0;
+ NdisStatus = NDIS_STATUS_INVALID_LENGTH;
+ }
+ else {
+
+ NdisStatus = DC21X4ChangeMulticastAddresses(
+ Adapter,
+ InformationBuffer,
+ (InformationBufferLength/ETH_LENGTH_OF_ADDRESS)
+ );
+ }
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ if (InformationBufferLength != sizeof(Filter)) {
+ *BytesRead = 0;
+ *BytesNeeded = sizeof(Filter);
+ return NDIS_STATUS_INVALID_LENGTH;
+ }
+
+ MOVE_MEMORY(&Filter,InformationBuffer,sizeof(Filter));
+ *BytesRead = 4;
+
+ if (Filter & ( NDIS_PACKET_TYPE_SOURCE_ROUTING
+ | NDIS_PACKET_TYPE_SMT
+ | NDIS_PACKET_TYPE_MAC_FRAME
+ | NDIS_PACKET_TYPE_FUNCTIONAL
+ | NDIS_PACKET_TYPE_ALL_FUNCTIONAL
+ | NDIS_PACKET_TYPE_GROUP
+ )) {
+
+ NdisStatus = NDIS_STATUS_NOT_SUPPORTED;
+ }
+ else {
+
+ NdisStatus = DC21X4ChangeFilter (
+ Adapter,
+ Filter
+ );
+ }
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ // We indicate success but do not modify the
+ // DC21X4 Lookahead parameter which always
+ // indicate the whole packet.
+ //
+
+ NdisStatus = NDIS_STATUS_SUCCESS;
+ break;
+
+ default:
+
+ NdisStatus = NDIS_STATUS_INVALID_OID;
+ }
+
+ return NdisStatus;
+
+}
+
diff --git a/private/ntos/ndis/dc21x4/reset.c b/private/ntos/ndis/dc21x4/reset.c
new file mode 100644
index 000000000..b3fdcecd3
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/reset.c
@@ -0,0 +1,337 @@
+/*+
+ * file: reset.c
+ *
+ * Copyright (C) 1992-1995 by
+ * Digital Equipment Corporation, Maynard, Massachusetts.
+ * All rights reserved.
+ *
+ * This software is furnished under a license and may be used and copied
+ * only in accordance of the terms of such license and with the
+ * inclusion of the above copyright notice. This software or any other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person. No title to and ownership of the software is hereby
+ * transferred.
+ *
+ * The information in this software is subject to change without notice
+ * and should not be construed as a commitment by digital equipment
+ * corporation.
+ *
+ * Digital assumes no responsibility for the use or reliability of its
+ * software on equipment which is not supplied by digital.
+ *
+ *
+ * Abstract: This file contains the Reset code of the
+ * NDIS 4.0 miniport driver for DEC's DC21X4 Ethernet
+ * adapter family.
+ *
+ * Author: Philippe Klein
+ *
+ * Revision History:
+ *
+ * phk 08-Aug-1994 Initial entry
+ *
+-*/
+
+#include <precomp.h>
+
+
+
+
+
+
+
+/*+
+ *
+ *
+ * DC21X4Reset
+ *
+ * Routine Description:
+ *
+ * Reset the adapter
+ *
+-*/
+
+extern
+NDIS_STATUS
+DC21X4Reset(
+ OUT PBOOLEAN AddressingReset,
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+{
+ PDC21X4_ADAPTER Adapter;
+#if 0
+ PDC21X4_TRANSMIT_DESCRIPTOR CurrentDescriptor;
+#endif
+ INT i;
+ BOOLEAN StartTimer = TRUE;
+ BOOLEAN Link = FALSE;
+
+#if _DBG
+ DbgPrint("DC21X4Reset\n");
+#endif
+
+ Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
+ *AddressingReset = FALSE;
+
+
+ //Stop the AutoSense Timer if active
+
+ if (Adapter->TimerFlag != NoTimer) {
+ DC21X4StopAutoSenseTimer(Adapter);
+ }
+
+ // Stop the adapter
+ DC21X4StopAdapter(Adapter);
+
+#if 0
+ // Walk down the Transmit descriptor ring to close all pending packets
+
+ while (Adapter->DequeueTransmitDescriptor != Adapter->EnqueueTransmitDescriptor) {
+
+ CurrentDescriptor = Adapter->DequeueTransmitDescriptor;
+
+ if (CurrentDescriptor->Control & DC21X4_TDES_SETUP_PACKET) {
+
+ // Setup buffer:
+ // Complete the pended Set Information request
+
+#if _DBG
+ DbgPrint("Reset: NdisMSetInformationComplete\n");
+#endif
+ NdisMSetInformationComplete (
+ Adapter->MiniportAdapterHandle,
+ NDIS_STATUS_FAILURE
+ );
+ }
+ else if (CurrentDescriptor->Control & DC21X4_TDES_LAST_SEGMENT) {
+
+#if _DBG
+ DbgPrint("Reset: NdisMSendComplete [Packet: %08x]\n",CurrentDescriptor->Packet);
+#endif
+ NdisMSendComplete(
+ Adapter->MiniportAdapterHandle,
+ CurrentDescriptor->Packet,
+ NDIS_STATUS_FAILURE
+ );
+ }
+ Adapter->DequeueTransmitDescriptor = CurrentDescriptor->Next;
+ }
+#endif
+
+ // Free up all the map registers
+ for (i=0;
+ i < (TRANSMIT_RING_SIZE * NUMBER_OF_SEGMENT_PER_DESC);
+ i++
+ ) {
+
+ if (Adapter->PhysicalMapping[i].Valid) {
+#if _DBG
+ DbgPrint("Reset: NdisMCompleteBufferPhysicalMapping (%d)\n",i);
+#endif
+ NdisMCompleteBufferPhysicalMapping(
+ Adapter->MiniportAdapterHandle,
+ Adapter->PhysicalMapping[i].Buffer,
+ Adapter->PhysicalMapping[i].Register
+ );
+ Adapter->PhysicalMapping[i].Valid = FALSE;
+ Adapter->FreeMapRegisters++;
+ }
+ }
+#if _DBG
+ DbgPrint("Reset: FreeMapRegisters = %d\n",Adapter->FreeMapRegisters);
+#endif
+
+ // Reinitialize the descriptor pointers
+
+ Adapter->DequeueReceiveDescriptor =
+ (PDC21X4_RECEIVE_DESCRIPTOR)Adapter->ReceiveDescriptorRingVa;
+ Adapter->EnqueueTransmitDescriptor =
+ (PDC21X4_TRANSMIT_DESCRIPTOR)Adapter->TransmitDescriptorRingVa;
+ Adapter->DequeueTransmitDescriptor =
+ Adapter->EnqueueTransmitDescriptor;
+
+ Adapter->FreeTransmitDescriptorCount = TRANSMIT_RING_SIZE - 1;
+
+ // Initialize the statistic counters
+
+ ZERO_MEMORY (
+ &Adapter->GeneralMandatory[0],
+ GM_ARRAY_SIZE * sizeof(ULONG)
+ );
+ ZERO_MEMORY (
+ &Adapter->GeneralOptional[0],
+ GO_ARRAY_SIZE * sizeof(ULONG)
+ );
+ ZERO_MEMORY (
+ &Adapter->GeneralOptionalCount[0],
+ GO_COUNT_ARRAY_SIZE * sizeof(GEN_OPTIONAL_COUNT)
+ );
+ ZERO_MEMORY (
+ &Adapter->MediaMandatory[0],
+ MM_ARRAY_SIZE * sizeof(ULONG)
+ );
+ ZERO_MEMORY (
+ &Adapter->MediaOptional[0],
+ MO_ARRAY_SIZE * sizeof(ULONG)
+ );
+
+#if _DBG
+ DbgPrint("initialize DC21X4 CSRS\n");
+#endif
+
+ // Renitialize the DC21X4 registers
+ DC21X4InitializeRegisters(Adapter);
+
+ // Initialize the PHY
+ if (Adapter->PhyMediumInSrom) {
+ Adapter->PhyPresent = DC21X4PhyInit(Adapter);
+ }
+ if (Adapter->PhyPresent) {
+
+#if 0
+ if (!(Adapter->MiiMediaType & MEDIA_NWAY)) {
+
+ DC21X4SetPhyControl(
+ Adapter,
+ (USHORT)MiiGenAdminIsolate
+ );
+ }
+#endif
+
+ DC21X4SetPhyConnection(Adapter);
+
+ }
+
+ // Because the DC21X4 wakes up in promiscuous mode after reset
+ // we reload the DC21X4's Cam (in polling mode)
+
+ if (!DC21X4LoadCam(
+ Adapter,
+ FALSE)) {
+ return NDIS_STATUS_HARD_ERRORS;
+ }
+
+ if (!Adapter->PhyPresent) {
+ DC21X4InitializeMediaRegisters(Adapter,FALSE);
+ }
+
+ Adapter->FirstAncInterrupt = TRUE;
+ Adapter->IndicateOverflow = FALSE;
+
+//// //Restart the Transmitter and Receiver
+//// DC21X4StartAdapter(Adapter);
+
+ // Media link Detection
+ if (Adapter->PhyPresent) {
+ Link = DC21X4MiiAutoDetect(
+ Adapter
+ );
+ }
+ if ( (!Adapter->PhyPresent)
+ || (!Link
+ && (Adapter->MediaCapable)
+ )
+ ) {
+
+ StartTimer = DC21X4MediaDetect(
+ Adapter
+ );
+ }
+
+ // Start the Autosense timer if not yet started
+
+ if (StartTimer && (Adapter->TimerFlag==NoTimer)) {
+
+ DC21X4StartAutoSenseTimer(
+ Adapter,
+ ((Adapter->PhyPresent) ? DC21X4_MII_TICK : DC21X4_SPA_TICK)
+ );
+ }
+
+ if (Adapter->LinkStatus == LinkFail) {
+
+ // Defer the completion of the reset routine
+ // until the Link is up
+
+ Adapter->LinkCheckCount = MAX_LINK_CHECK;
+
+ NdisMSetTimer(
+ &Adapter->ResetTimer,
+ LINK_CHECK_PERIOD
+ );
+ Adapter->ResetInProgress = TRUE;
+ return NDIS_STATUS_PENDING;
+
+ }
+ else {
+
+ //Restart the Receiver & Transmitter
+ DC21X4StartAdapter(Adapter);
+
+ //Complete the Reset routine synchronously
+ return NDIS_STATUS_SUCCESS;
+ }
+}
+
+/*+
+ *
+ *
+ * DC21X4DeferredReset
+ *
+ * Routine Description:
+ *
+ * Reset routine
+ *
+-*/
+extern
+VOID
+DC21X4DeferredReset (
+ IN PVOID Systemspecific1,
+ IN PDC21X4_ADAPTER Adapter,
+ IN PVOID Systemspecific2,
+ IN PVOID Systemspecific3
+ )
+{
+
+#if _DBG
+ DbgPrint("DC21X4DeferredReset\n");
+#endif
+
+#if __DBG
+ DbgPrint("DC21X4DeferredReset: LinkStatus=%x LinkCheckCount=%d\n",
+ Adapter->LinkStatus,Adapter->LinkCheckCount);
+#endif
+ Adapter->LinkCheckCount--;
+
+ if ( (Adapter->LinkStatus !=LinkFail)
+ || (Adapter->LinkCheckCount == 0)
+ ) {
+
+ //Indicate the assynchronous completion of the
+ //Reset routine
+
+#if __DBG
+ DbgPrint("DC21X4DeferredReset: Indicate ResetComplete\n");
+#endif
+ NdisMResetComplete(
+ Adapter->MiniportAdapterHandle,
+ NDIS_STATUS_SUCCESS,
+ FALSE
+ );
+
+ Adapter->ResetInProgress = FALSE;
+
+ //Restart the Receiver & Transmitter
+ DC21X4StartAdapter(Adapter);
+
+ }
+ else {
+ // Fire the ResetTimer for an other link check
+ NdisMSetTimer(
+ &Adapter->ResetTimer,
+ LINK_CHECK_PERIOD
+ );
+ }
+
+}
+
diff --git a/private/ntos/ndis/dc21x4/send.c b/private/ntos/ndis/dc21x4/send.c
new file mode 100644
index 000000000..7cfbacf94
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/send.c
@@ -0,0 +1,664 @@
+/*+
+ * file: send.c
+ *
+ * Copyright (C) 1992-1995 by
+ * Digital Equipment Corporation, Maynard, Massachusetts.
+ * All rights reserved.
+ *
+ * This software is furnished under a license and may be used and copied
+ * only in accordance of the terms of such license and with the
+ * inclusion of the above copyright notice. This software or any other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person. No title to and ownership of the software is hereby
+ * transferred.
+ *
+ * The information in this software is subject to change without notice
+ * and should not be construed as a commitment by digital equipment
+ * corporation.
+ *
+ * Digital assumes no responsibility for the use or reliability of its
+ * software on equipment which is not supplied by digital.
+ *
+ *
+ * Abstract: This file is part of the NDIS 4.0 miniport driver for
+ * Digital Equipment's DC21X4 Ethernet adapter family.
+ * It contains the code for submitting a packet for
+ * transmission.
+ *
+ * Author: Philippe Klein
+ *
+ * Revision History:
+ *
+ * phk 28-Aug-1994 creation date
+ *
+-*/
+
+#include <precomp.h>
+#include <crc.h>
+
+
+
+
+
+
+
+
+
+
+
+/*+
+ * DC21X4Send
+ *
+ * Routine Description:
+ *
+ * The DC21X4Send request instructs a MAC to transmit a packet through
+ * the adapter onto the medium.
+ *
+ * Arguments:
+ *
+ * MiniportAdapterContext -
+ * Packet - A pointer to a descriptor for the packet to transmit
+ *
+ * Return Value:
+ *
+ * The status of the operation.
+ *
+-*/
+
+extern
+NDIS_STATUS
+DC21X4Send(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET Packet,
+ IN UINT Flags
+ )
+{
+
+ PDC21X4_ADAPTER Adapter;
+
+ UINT PacketSize;
+ UCHAR PacketType;
+
+ PNDIS_BUFFER CurrentBuffer;
+ UINT NdisBufferCount;
+ UINT PhysicalSegmentCount;
+ UINT MapTableIndex;
+
+ PVOID TxmBuffer;
+ PUCHAR Tmp;
+
+ NDIS_STATUS NdisStatus;
+ NDIS_PHYSICAL_ADDRESS_UNIT PhysicalSegmentArray[DC21X4_MAX_SEGMENTS];
+ UINT BufferPhysicalSegments;
+
+ BOOLEAN FirstSegment;
+ BOOLEAN FirstBuffer;
+
+ PDC21X4_TRANSMIT_DESCRIPTOR FirstSegmentDescriptor=NULL;
+ PDC21X4_TRANSMIT_DESCRIPTOR LastSegmentDescriptor=NULL;
+ PDC21X4_TRANSMIT_DESCRIPTOR CurrentDescriptor=NULL;
+
+ UINT Length;
+ UINT Buffer;
+ UINT Segment;
+
+ UCHAR SendMode;
+
+ BOOLEAN GenerateCRC=FALSE;
+
+ ULONG TxmDescriptorCount = 0;
+ ULONG MapRegistersCount = 0;
+ ULONG MaxTransmitBufferCount = 0;
+ ULONG MinTransmitBufferCount = 0;
+ ULONG GoTransmitCount = 0;
+
+#if _DBG
+ DbgPrint("DC21X4Send AdapterContext =%x Packet=%08x\n",
+ MiniportAdapterContext,Packet);
+#endif
+
+ Adapter = (PDC21X4_ADAPTER)(MiniportAdapterContext);
+
+ //Check the link status
+ if (Adapter->LinkStatus == LinkFail) {
+ return NDIS_STATUS_NO_CABLE;
+ }
+
+ NdisQueryPacket(
+ Packet,
+ &PhysicalSegmentCount,
+ &NdisBufferCount,
+ &CurrentBuffer,
+ &PacketSize
+ );
+
+ if (PacketSize > DC21X4_MAX_FRAME_SIZE) {
+ return NDIS_STATUS_INVALID_PACKET;
+ }
+
+ // NT BUG: Clean up the msw of the PhysicalSegmentCount
+ PhysicalSegmentCount &= 0xFFFF;
+
+#if _DBG
+ DbgPrint(" PacketSize= %d\n BufferCount= %d\n SegmentCount= %d\n",
+ PacketSize,NdisBufferCount,PhysicalSegmentCount);
+ DbgPrint(" FreeTxmDescCount = %d\n",Adapter->FreeTransmitDescriptorCount);
+#endif
+
+ ASSERT(NdisBufferCount != 0);
+
+ // DC21040 Pass1 and Pass2:
+ // if SoftwareCRC mode is enabled, generate the CRC by software
+ // for packet > Transmit threshold
+
+ if (Adapter->SoftwareCRC) {
+ GenerateCRC = (PacketSize > Adapter->TxmThreshold);
+ }
+
+ // if the Ndis Packet is too fragmented or GenerateCRC is on,
+ // copy the packet into a single buffer
+
+ if ( (PhysicalSegmentCount > Adapter->PhysicalSegmentThreshold) || GenerateCRC ) {
+
+ if ((Adapter->MaxTransmitBufferInUse == DC21X4_NUMBER_OF_MAX_TRANSMIT_BUFFERS) ||
+ (Adapter->FreeTransmitDescriptorCount <= DC21X4_NUMBER_OF_SETUP_DESCRIPTORS)
+ ) {
+
+ // All the Txm buffer are currently allocated or
+ // there is no free Txm descriptor in the ring
+#if _DBG
+ DbgPrint ("No free Txm buffer or Txm desc...\n");
+#endif
+ return NDIS_STATUS_RESOURCES;
+ }
+ else {
+ SendMode = CopyMaxBuffer;
+ }
+ }
+
+ // if the Ndis Packet is smaller than DC21X4_MIN_TXM_SIZE,
+ // copy the packet into a preallocated Txm buffer if the resource
+ // is available
+
+ else if ((PacketSize <= DC21X4_MIN_TXM_SIZE)
+ && (Adapter->MinTransmitBufferInUse < DC21X4_NUMBER_OF_MIN_TRANSMIT_BUFFERS)
+ && !Adapter->DontUseMinTransmitBuffer)
+ {
+ SendMode = CopyMinBuffer;
+ }
+
+ // Check if there are enough descriptors available in the ring to load
+ // the packet and enough free map registers to map the whole packet
+
+ else if ( (PhysicalSegmentCount >
+ ((Adapter->FreeTransmitDescriptorCount - DC21X4_NUMBER_OF_SETUP_DESCRIPTORS) * NUMBER_OF_SEGMENT_PER_DESC))
+ ||(PhysicalSegmentCount > Adapter->FreeMapRegisters)
+ ){
+
+ // not enough descriptors in the ring
+ // or enough map registers to load the whole packet
+#if _DBG
+ DbgPrint("Not enough txm desc or enough map registers\n");
+ DbgPrint("Phys. segment count=%d FreeTxDesc=%d FreeMapReg=%d\n",
+ PhysicalSegmentCount,
+ (Adapter->FreeTransmitDescriptorCount-DC21X4_NUMBER_OF_SETUP_DESCRIPTORS) * NUMBER_OF_SEGMENT_PER_DESC,
+ Adapter->FreeMapRegisters);
+#endif
+ return NDIS_STATUS_RESOURCES;
+ }
+ else {
+ SendMode = MappedBuffer;
+ }
+
+ // For now, do not separately count multicast, broadcast and
+ // directed packets/bytes and avoid having to map the buffer, which
+ // is a very expensive operation. The mapping happens when we call
+ // NdisQueryBuffer with a VirtualAddress argument.
+#if 0
+ NdisQueryBuffer(
+ CurrentBuffer,
+ &TxmBuffer,
+ &Length
+ );
+
+ ASSERT(Length >= ETH_LENGTH_OF_ADDRESS);
+
+ PacketType = CHECK_PACKET_TYPE(TxmBuffer);
+#else
+ PacketType = TXM_DIRECTED_FRAME;
+#endif
+
+
+ // Until Send and Request are serialized
+ // the Enqueue pointer which can modified in both
+ // send and filter routines should be protected by a SpinLock
+
+ if (Adapter->FullDuplex) {
+ NdisDprAcquireSpinLock(&Adapter->EnqueueSpinLock);
+ }
+
+
+ switch (SendMode) {
+
+ case CopyMaxBuffer:
+
+ // Copy the Packet into a Max Txm Buffer
+
+ TxmBuffer = (PVOID)Adapter->MaxTransmitBuffer[Adapter->MaxTransmitBufferIndex].Va;
+
+#if _DBG
+ DbgPrint ("Copy packet %x into a Max Txm buffer [%d]\n",Packet,Adapter->MaxTransmitBufferIndex);
+#endif
+
+ CopyFromPacketToBuffer (
+ Packet,
+ 0,
+ TxmBuffer,
+ PacketSize,
+ &Length
+ );
+
+ ASSERT (Length == PacketSize);
+ ASSERT(Length >= ETH_LENGTH_OF_ADDRESS);
+
+ CurrentDescriptor = Adapter->EnqueueTransmitDescriptor;
+
+ Adapter->EnqueueTransmitDescriptor = CurrentDescriptor->Next;
+
+ MaxTransmitBufferCount++;
+ TxmDescriptorCount++;
+
+
+ //Clear all the Descriptor Control word but the SECOND_ADDR_CHAINED flag;
+ CurrentDescriptor->Control &= DC21X4_TDES_SECOND_ADDR_CHAINED;
+
+ // If GenerateCRC, add the software generated CRC
+ // to the end of the buffer
+
+ if (GenerateCRC) {
+
+ Tmp = (PUCHAR)TxmBuffer;
+ *(UNALIGNED ULONG *)&Tmp[PacketSize] =
+ CRC32 (
+ &Tmp[0],
+ PacketSize
+ );
+ PacketSize += sizeof(UINT);
+ CurrentDescriptor->Control |= DC21X4_TDES_ADD_CRC_DISABLE;
+#if _DBG
+ DbgPrint(" Software CRC = %02x %02x %02x %02x\n",
+ Tmp[PacketSize-4],Tmp[PacketSize-3],
+ Tmp[PacketSize-2],Tmp[PacketSize-1]);
+#endif
+ }
+
+ CurrentDescriptor->Control |= (
+ DC21X4_TDES_FIRST_SEGMENT
+ | PacketSize);
+
+ FirstSegmentDescriptor = CurrentDescriptor;
+ LastSegmentDescriptor = FirstSegmentDescriptor;
+
+ CurrentDescriptor->FirstBufferAddress =
+ Adapter->MaxTransmitBuffer[Adapter->MaxTransmitBufferIndex].Pa;
+
+ NdisFlushBuffer(
+ Adapter->MaxTransmitBuffer[Adapter->MaxTransmitBufferIndex].FlushBuffer,
+ TRUE
+ );
+
+ Adapter->MaxTransmitBufferIndex++;
+ Adapter->MaxTransmitBufferIndex &= (DC21X4_NUMBER_OF_MAX_TRANSMIT_BUFFERS-1);
+
+#if _DBG
+ DbgPrint (" [%08x]\n %08x\n %08x\n %08x\n",
+ CurrentDescriptor,
+ CurrentDescriptor->Status,
+ CurrentDescriptor->Control,
+ CurrentDescriptor->FirstBufferAddress);
+#endif
+ NdisStatus = NDIS_STATUS_PENDING;
+// NdisStatus = NDIS_STATUS_SUCCESS; // hapi stress test pb
+
+ break;
+
+
+ case CopyMinBuffer:
+
+ // Copy the Packet into a Min Txm Buffer
+
+ TxmBuffer = (PVOID)Adapter->MinTransmitBuffer[Adapter->MinTransmitBufferIndex].Va;
+
+#if _DBG
+ DbgPrint ("Copy packet %x into a Min Txm buffer [%d]\n",
+ Packet,Adapter->MinTransmitBufferIndex);
+#endif
+
+ CopyFromPacketToBuffer (
+ Packet,
+ 0,
+ TxmBuffer,
+ PacketSize,
+ &Length
+ );
+
+ ASSERT (Length == PacketSize);
+
+ ASSERT(Length >= ETH_LENGTH_OF_ADDRESS);
+
+ CurrentDescriptor = Adapter->EnqueueTransmitDescriptor;
+
+ Adapter->EnqueueTransmitDescriptor = CurrentDescriptor->Next;
+
+ MinTransmitBufferCount++;
+ TxmDescriptorCount++;
+
+
+ //Clear all the Descriptor Control word but the SECOND_ADDR_CHAINED flag;
+ CurrentDescriptor->Control &= DC21X4_TDES_SECOND_ADDR_CHAINED;
+
+
+ CurrentDescriptor->Control |= (
+ DC21X4_TDES_FIRST_SEGMENT
+ | PacketSize);
+
+ FirstSegmentDescriptor = CurrentDescriptor;
+ LastSegmentDescriptor = FirstSegmentDescriptor;
+
+ CurrentDescriptor->FirstBufferAddress =
+ Adapter->MinTransmitBuffer[Adapter->MinTransmitBufferIndex].Pa;
+
+ NdisFlushBuffer(
+ Adapter->MinTransmitBuffer[Adapter->MinTransmitBufferIndex].FlushBuffer,
+ TRUE
+ );
+
+ Adapter->MinTransmitBufferIndex++;
+ Adapter->MinTransmitBufferIndex &= (DC21X4_NUMBER_OF_MIN_TRANSMIT_BUFFERS-1);
+
+#if _DBG
+ DbgPrint (" [%08x]\n %08x\n %08x\n %08x\n",
+ CurrentDescriptor,
+ CurrentDescriptor->Status,
+ CurrentDescriptor->Control,
+ CurrentDescriptor->FirstBufferAddress);
+#endif
+
+ NdisStatus = NDIS_STATUS_PENDING;
+// NdisStatus = NDIS_STATUS_SUCCESS; // hapi stress test pb
+
+ break;
+
+
+ case MappedBuffer:
+
+ FirstSegment = TRUE;
+ FirstBuffer = TRUE;
+
+ FirstSegmentDescriptor = Adapter->EnqueueTransmitDescriptor;
+ LastSegmentDescriptor = FirstSegmentDescriptor;
+
+ MapTableIndex = FirstSegmentDescriptor->MapTableIndex;
+
+ FirstSegmentDescriptor->Control &= DC21X4_TDES_SECOND_ADDR_CHAINED ;
+ FirstSegmentDescriptor->Control |= DC21X4_TDES_FIRST_SEGMENT;
+
+
+ for (Buffer=0; Buffer<NdisBufferCount; Buffer++) {
+
+ // Get the mapping of the physical segments
+ // of the current buffer
+#if _DBG
+ DbgPrint("NdisMStartBufferPhysicalMapping (%d)\n",MapTableIndex);
+ DbgPrint("MapRegisterIndex = %d\n",Adapter->MapRegisterIndex);
+ DbgPrint("FreeMapRegisters = %d\n",Adapter->FreeMapRegisters);
+#endif
+
+ NdisMStartBufferPhysicalMapping(
+ Adapter->MiniportAdapterHandle,
+ CurrentBuffer,
+ Adapter->MapRegisterIndex,
+ TRUE,
+ PhysicalSegmentArray,
+ &BufferPhysicalSegments
+ );
+
+ if (BufferPhysicalSegments) {
+
+ // Save the CurrentBuffer address for NdisCompleteBufferPhysicalMapping
+
+ Adapter->PhysicalMapping[MapTableIndex].Register = Adapter->MapRegisterIndex;
+ Adapter->PhysicalMapping[MapTableIndex].Buffer = CurrentBuffer;
+ Adapter->PhysicalMapping[MapTableIndex].Valid = TRUE;
+
+ Adapter->MapRegisterIndex++;
+ if (Adapter->MapRegisterIndex >= Adapter->AllocMapRegisters) {
+ Adapter->MapRegisterIndex = 0;
+ }
+
+ MapRegistersCount++;
+
+ // Put the physical segments for this buffer into
+ // the transmit descriptors.
+#if _DBG
+ DbgPrint(" Nb segments = %d\n",BufferPhysicalSegments);
+#endif
+ for (Segment=0; Segment<BufferPhysicalSegments;) {
+
+ ASSERT (NdisGetPhysicalAddressHigh(PhysicalSegmentArray[Segment].PhysicalAddress) == 0);
+
+ if (FirstBuffer) {
+
+ FirstBuffer = FALSE;
+
+ CurrentDescriptor = Adapter->EnqueueTransmitDescriptor;
+ LastSegmentDescriptor = CurrentDescriptor;
+
+ // Point to the next descriptor in the ring;
+ Adapter->EnqueueTransmitDescriptor= (Adapter->EnqueueTransmitDescriptor)->Next;
+
+ TxmDescriptorCount++;
+
+ if (FirstSegment) {
+
+ // The ownership bit of the first segment descriptor will be changed
+ // after the entire frame is fully mapped into the transmit ring
+
+ FirstSegment = FALSE;
+
+ }
+ else {
+
+ //Clear all the Descriptor Control word but the SECOND_ADDR_CHAINED flag;
+ CurrentDescriptor->Control &= DC21X4_TDES_SECOND_ADDR_CHAINED ;
+
+ // set the ownership bit to DC21X4
+ CurrentDescriptor->Status = DESC_OWNED_BY_DC21X4;
+ }
+
+ //First BufferSize
+ CurrentDescriptor->Control |= PhysicalSegmentArray[Segment].Length;
+
+ //First Buffer Address
+ CurrentDescriptor->FirstBufferAddress =
+ NdisGetPhysicalAddressLow(PhysicalSegmentArray[Segment].PhysicalAddress);
+
+ MapTableIndex++;
+
+ }
+ else {
+
+ FirstBuffer=TRUE;
+
+ MapTableIndex = (Adapter->EnqueueTransmitDescriptor)->MapTableIndex;
+
+ if (CurrentDescriptor->Control & DC21X4_TDES_SECOND_ADDR_CHAINED) {
+ continue;
+ }
+ else {
+
+ // Second BufferSize
+ CurrentDescriptor->Control |=
+ (PhysicalSegmentArray[Segment].Length << TDES_SECOND_BUFFER_SIZE_BIT_NUMBER);
+
+ // Second Buffer Address
+ CurrentDescriptor->SecondBufferAddress =
+ NdisGetPhysicalAddressLow(PhysicalSegmentArray[Segment].PhysicalAddress);
+ }
+ }
+ Segment++;
+ }
+ }
+
+ else {
+
+ // No physical segments in this Ndis buffer
+
+ NdisMCompleteBufferPhysicalMapping(
+ Adapter->MiniportAdapterHandle,
+ CurrentBuffer,
+ Adapter->MapRegisterIndex
+ );
+
+ }
+
+ NdisFlushBuffer(
+ CurrentBuffer,
+ TRUE
+ );
+
+ // Get the Next Buffer;
+
+ NdisGetNextBuffer(
+ CurrentBuffer,
+ &CurrentBuffer
+ );
+
+ }
+
+ NdisStatus = NDIS_STATUS_PENDING;
+
+ break;
+
+ }
+
+ // Save the information needed by the Txm interrupt handler
+ // to complete the Send request
+
+ LastSegmentDescriptor->Packet = Packet;
+ LastSegmentDescriptor->PacketType = PacketType;
+ LastSegmentDescriptor->PacketSize = PacketSize;
+ LastSegmentDescriptor->SendStatus = SendMode;
+
+ LastSegmentDescriptor->Control |= DC21X4_TDES_LAST_SEGMENT;
+
+ LastSegmentDescriptor->Control |= DC21X4_TDES_INTERRUPT_ON_COMPLETION;
+
+ GoTransmitCount++;
+
+ // Desc Pointer of last segment descriptor points the first segment descriptor
+ LastSegmentDescriptor->DescPointer = FirstSegmentDescriptor;
+
+ // Desc Pointer of first segment descriptor points the last segment descriptor
+ FirstSegmentDescriptor->DescPointer = LastSegmentDescriptor;
+
+ if (Adapter->FullDuplex) {
+ NdisDprReleaseSpinLock(&Adapter->EnqueueSpinLock);
+ NdisDprAcquireSpinLock(&Adapter->FullDuplexSpinLock);
+ }
+
+ Adapter->FreeTransmitDescriptorCount -= TxmDescriptorCount;
+
+ Adapter->FreeMapRegisters -= MapRegistersCount;
+
+ Adapter->MaxTransmitBufferInUse += MaxTransmitBufferCount;
+
+ Adapter->MinTransmitBufferInUse += MinTransmitBufferCount;
+
+ Adapter->GeneralOptional[GO_TRANSMIT_QUEUE_LENGTH] += GoTransmitCount;
+
+ if (Adapter->FullDuplex) {
+ NdisDprReleaseSpinLock(&Adapter->FullDuplexSpinLock);
+ }
+
+ // Set the Ownership bit off the First_Segment descriptor;
+ FirstSegmentDescriptor->Status = DESC_OWNED_BY_DC21X4;
+
+ if (!Adapter->DisableTransmitPolling) {
+
+ // Poll Transmit the adapter
+
+ DC21X4_WRITE_PORT(
+ DC21X4_TXM_POLL_DEMAND,
+ 1
+ );
+ }
+
+ return NdisStatus;
+
+}
+
+
+
+
+
+
+
+
+
+
+/*+
+ *
+ * CRC32
+ *
+ * Routine Description:
+ *
+ * Generate a CRC-32 from the data stream
+ *
+ * Arguments:
+ *
+ * Data - the data stream
+ * Len - the length of the stream
+ *
+ *Return Value:
+ *
+ * CRC-32
+ *
+-*/
+extern
+ULONG
+CRC32 (
+ IN PUCHAR Data,
+ IN UINT Len
+ )
+{
+ ULONG Crc = 0xffffffff;
+
+ while (Len--) {
+ Crc = CrcTable[(Crc ^ *Data++) & 0xFF] ^ (Crc >> 8);
+ }
+
+ return ~Crc;
+
+}
+
+
+
+
+
+
+/*+
+ *
+ * NdisSendPackets
+ *
+ *
+-*/
+NDIS_STATUS
+DC21X4SendPackets(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ ) {
+ return NDIS_STATUS_SUCCESS;
+}
+
diff --git a/private/ntos/ndis/dc21x4/sources b/private/ntos/ndis/dc21x4/sources
new file mode 100644
index 000000000..646d7d741
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/sources
@@ -0,0 +1,58 @@
+!if 0
+ Copyright (C) 1992-1995 by Digital Equipment Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the DC21X4 NDIS 4.0 miniport driver being built
+ and the list of sources files needed to build it.
+ It specifies also the compiler switches specific to this driver
+
+Author:
+
+ Philippe Klein
+
+!endif
+
+TARGETNAME=DC21X4
+TARGETTYPE=DRIVER
+
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+INCLUDES=..\..\inc
+
+C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER
+C_DEFINES=$(C_DEFINES) -DNDIS40_MINIPORT
+C_DEFINES=$(C_DEFINES) -DBINARY_COMPATIBLE=0
+C_DEFINES=$(C_DEFINES) -DDBG=0
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=alloc.c \
+ copy.c \
+ dc21x4.c \
+ filter.c \
+ init.c \
+ interrup.c \
+ media.c \
+ monitor.c \
+ register.c \
+ request.c \
+ reset.c \
+ send.c \
+ srom.c \
+ mactophy.c \
+ miigen.c \
+ miiphy.c \
+ dc21x4.rc
+
+NTTARGETFILES=dc21x4.hlp
+
+PRECOMPILED_INCLUDE=precomp.h
+PRECOMPILED_PCH=precomp.pch
+PRECOMPILED_OBJ=precomp.obj
+
+
diff --git a/private/ntos/ndis/dc21x4/srom.c b/private/ntos/ndis/dc21x4/srom.c
new file mode 100644
index 000000000..85962f2c2
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/srom.c
@@ -0,0 +1,1521 @@
+/*+
+ * file: srom.c
+ *
+ * Copyright (C) 1992-1995 by
+ * Digital Equipment Corporation, Maynard, Massachusetts.
+ * All rights reserved.
+ *
+ * This software is furnished under a license and may be used and copied
+ * only in accordance of the terms of such license and with the
+ * inclusion of the above copyright notice. This software or any other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person. No title to and ownership of the software is hereby
+ * transferred.
+ *
+ * The information in this software is subject to change without notice
+ * and should not be construed as a commitment by digital equipment
+ * corporation.
+ *
+ * Digital assumes no responsibility for the use or reliability of its
+ * software on equipment which is not supplied by digital.
+ *
+ *
+ * Abstract: This file contains the code to access the onboard ROM of
+ * adapters based on DEC's DC21X4 Ethernet Controller.
+ *
+ * Author: Philippe klein
+ *
+ * Revision History:
+ *
+ * 05-Oct-95 phk Modified Miniport version
+ * 10-Jan-95 phk Add ParseSRom
+ * 29-Nov-95 phk Add parsing for SROM format V3
+ *
+-*/
+
+#include <precomp.h>
+
+#define SROM_93LC46B_SIZE 64 //words
+#define SROM_93LC46B_MAX_CYCLES 25
+#define SROM_93LC46B_ADDRESS_MSB 5
+#define SROM_93LC46B_DATA_MSB 15
+#define SROM_93LC46B_DATA_BIT 3
+
+#define SROM_93LC46B_VALID_BITMASK 0x8
+
+#define SROM_93LC46B_DELAY (10)
+
+#define CSR_READ 0x4000
+#define CSR_WRITE 0x2000
+#define SEL_SROM 0x0800
+#define DATA_1 0x0004
+#define DATA_0 0x0000
+#define CLK 0x0002
+#define CS 0x0001
+
+#define DISABLE_AUTOSENSE 0x8000
+
+#define EXT 0x40
+#define DC21X4_MEDIA 0x3F
+
+
+#define MODE 0x0071
+#define SENSE_BN 0x000E
+#define SENSE_DIS 0x8000
+#define DEFAULT 0x4000
+#define POLARITY 0x0080
+
+#define SENSE_SHIFT 1
+#define MODE_SHIFT 18
+
+#define SROM_LEGACY 0x00
+#define SROM_V1 0x01
+#define SROM_V2 0x02
+#define SROM_V3 0x03
+
+#define SROM_SIZE (SROM_93LC46B_SIZE*2)
+
+#define SROM_IEEE_LEN 32
+#define TEST_PATTERN 0xAA5500FF
+#define SROM_TIMEOUT 50
+
+#define ZX312_SIGNATURE 0x0095C000
+
+#define GET_MODE(_command) \
+ ( (*(UNALIGNED ULONG *)(_command) & MODE) << MODE_SHIFT )
+
+#define IF_DEFAULT_MEDIA(_command) \
+ ( *(UNALIGNED ULONG *)(_command) & DEFAULT )
+
+#define GET_POLARITY(_command) \
+ ( (*(UNALIGNED ULONG *)(_command) & POLARITY) ? 0xffffffff : 0 )
+
+#define GET_SENSE_MASK(_command) \
+ ((*(UNALIGNED ULONG *)(_command) & SENSE_DIS) ? \
+ 0 : (ULONG)(1 << ((*(UNALIGNED ULONG *)(_command) & SENSE_BN)>> SENSE_SHIFT )))
+
+#pragma pack(1)
+typedef struct _SROM_ID_BLOCK{
+
+ USHORT VendorID;
+ USHORT SysID;
+ USHORT Reserved[6];
+ USHORT ID_Checksum;
+ UCHAR FormatVersion;
+ UCHAR AdapterCount;
+ UCHAR NetworkAddress[ETH_LENGTH_OF_ADDRESS];
+
+} SROM_ID_BLOCK, *PSROM_ID_BLOCK;
+
+typedef struct _ADAPTER_ENTRIES{
+
+ UCHAR DeviceNumber;
+ USHORT Offset;
+
+} ADAPTER_ENTRIES, *PADAPTER_ENTRIES;
+
+#pragma pack()
+
+#define DE500_STR 0x1D
+#define BOARD_SIGNATURE(_srom) \
+ ((*(UNALIGNED ULONG *)&(_srom)[DE500_STR] == *(PULONG)&DE500Strng[0]) && \
+ (*(UNALIGNED ULONG *)&(_srom)[DE500_STR+sizeof(ULONG)] == *(PULONG)&DE500Strng[sizeof(ULONG)]))
+
+// PHY Parsing definitions
+
+#define EXTENDED_FORMAT 0x80
+
+#define LENGTH 0x7f
+#define TYPE_0 0x0
+#define TYPE_1 0x1
+#define TYPE_2 0x2
+#define TYPE_3 0x3
+
+#define MEDIA_CAPABILITIES_MASK 0xf800
+#define NWAY_ADVERTISEMENT_MASK 0x03e0
+
+
+
+
+
+
+
+
+
+
+#pragma NDIS_PAGABLE_FUNCTION(DC21X4ReadSerialRom)
+
+/*+
+ *
+ * DC21X4ReadSerialRom
+ *
+ * Routine Description:
+ *
+ * Read the Dc21X4 Serial Rom to retrieve the adapter information
+ *
+ * Arguments:
+ *
+ * Adapter
+ *
+ * Return Value:
+ *
+ * Status
+ *
+ *
+-*/
+extern
+NDIS_STATUS
+DC21X4ReadSerialRom (
+ IN PDC21X4_ADAPTER Adapter
+ )
+
+{
+ UNALIGNED UCHAR *EthAddress;
+ UCHAR IdProm[SROM_IEEE_LEN *2];
+
+ ULONG Value;
+ INT Time;
+ UINT i;
+
+#if __DBG
+ DbgPrint ("DC21X4ReadSerialROM\n");
+#endif
+
+ //Read the Station Address
+
+ switch (Adapter->AdapterType) {
+
+ case NdisInterfacePci:
+
+ // Read the Network Address from the PCI board ID ROM
+ // through DC21X4's Serial ROM port
+
+ switch (Adapter->DeviceId) {
+
+ default:
+
+ return DC21X4ParseSRom(Adapter);
+
+ case DC21040_CFID:
+
+ Adapter->MediaCapable =
+ (MEDIUM_10BT | MEDIUM_10B2 | MEDIUM_10B5);
+
+ //Initialize DC21040s ID_PROM pointer
+
+ DC21X4_WRITE_PORT(
+ DC21X4_IDPROM,
+ 0
+ );
+
+ // Read the 32 bytes of the Ethernet ID PROM
+
+ for (i = 0; i < SROM_IEEE_LEN; i++) {
+
+ Time = SROM_TIMEOUT;
+
+ do {
+ NdisStallExecution(1*MILLISECOND); // Wait 1 ms
+ DC21X4_READ_PORT(
+ DC21X4_IDPROM,
+ &Value
+ );
+ }
+ while ((Value & DC21X4_IDPROM_DATA_UNVALID) && ((Time--)>0));
+ if (Time > 0) {
+ IdProm[i] = (UCHAR)(Value & DC21X4_IDPROM_DATA);
+ }
+ else {
+ return NDIS_STATUS_FAILURE;
+ }
+ }
+
+ EthAddress = &IdProm[0];
+
+ }
+ break;
+
+ case NdisInterfaceEisa:
+
+ Adapter->MediaCapable =
+ (MEDIUM_10BT | MEDIUM_10B2 | MEDIUM_10B5);
+
+ // Read the 32 bytes of the Ethernet ID PROM
+
+ for (i = 0; i < SROM_IEEE_LEN; i++) {
+
+ NdisRawReadPortUchar(
+ Adapter->PortOffset + EISA_ID_PROM_OFFSET,
+ &IdProm[i]
+ );
+#if __DBG
+ DbgPrint ("Eisa: IDROM @%x %x r\n",
+ Adapter->PortOffset + EISA_ID_PROM_OFFSET, IdProm[i]);
+#endif
+ }
+
+ // Duplicate the ID Prom data in the 32 upper bytes of
+ // the array to cover the case where the 2 test patterns
+ // rap around the 32 bytes block
+
+ MOVE_MEMORY (
+ &IdProm[SROM_IEEE_LEN],
+ &IdProm[0],
+ SROM_IEEE_LEN
+ );
+
+ //Align on the test patterns
+
+ for (i=4; i <= SROM_IEEE_LEN*2; i++) {
+
+ if ( (*(UNALIGNED ULONG *)&IdProm[i-4] == TEST_PATTERN) &&
+ (*(UNALIGNED ULONG *)&IdProm[i] == TEST_PATTERN)
+ ) break;
+ }
+
+ if ( i >= SROM_IEEE_LEN ) {
+ // The test patterns were not found
+ Adapter->PermanentAddressValid = FALSE;
+ return NDIS_STATUS_SUCCESS;
+ }
+ else {
+ EthAddress = &IdProm[i+4];
+ }
+
+ break;
+
+ }
+
+ if (IS_NULL_ADDRESS(EthAddress)) {
+ Adapter->PermanentAddressValid = FALSE;
+#if __DBG
+ DbgPrint ("SROM: NULL Burnt_In Ethernet Address\n");
+#endif
+ }
+ else if ((*(PULONG)EthAddress & 0xFFFFFF) == ZX312_SIGNATURE) {
+ // Zynx ZX312 Rev3's SROM does not contain a checksum
+ Adapter->PermanentAddressValid = TRUE;
+#if __DBG
+ DbgPrint ("SROM: ZX312 Rev3\n");
+#endif
+ }
+ else {
+ Adapter->PermanentAddressValid =
+ VerifyChecksum(EthAddress);
+#if __DBG
+ if (!Adapter->PermanentAddressValid)
+ DbgPrint ("SROM: Invalid CheckSum\n");
+#endif
+ }
+
+ if (Adapter->PermanentAddressValid) {
+ MOVE_MEMORY (
+ &Adapter->PermanentNetworkAddress[0],
+ EthAddress,
+ ETH_LENGTH_OF_ADDRESS
+ );
+ }
+
+
+ //Sia values
+
+ Adapter->Media[Medium10BaseT].SiaRegister[0] = DC21040_SIA0_10BT;
+ Adapter->Media[Medium10BaseT].SiaRegister[1] = DC21040_SIA1_10BT;
+ Adapter->Media[Medium10BaseT].SiaRegister[2] = DC21040_SIA2_10BT;
+
+ Adapter->Media[Medium10Base2].SiaRegister[0] = DC21040_SIA0_10B2;
+ Adapter->Media[Medium10Base2].SiaRegister[1] = DC21040_SIA1_10B2;
+ Adapter->Media[Medium10Base2].SiaRegister[2] = DC21040_SIA2_10B2;
+
+ Adapter->Media[Medium10Base5].SiaRegister[0] = DC21040_SIA0_10B5;
+ Adapter->Media[Medium10Base5].SiaRegister[1] = DC21040_SIA1_10B5;
+ Adapter->Media[Medium10Base5].SiaRegister[2] = DC21040_SIA2_10B5;
+
+ return NDIS_STATUS_SUCCESS;
+
+}
+
+
+
+
+
+
+
+
+
+
+#pragma NDIS_PAGABLE_FUNCTION(VerifyChecksum)
+
+/*+
+ *
+ * VerifyChecksum
+ *
+ * Routine Description:
+ *
+ * Verify the checksum of an Ethernet Address
+ *
+ * Arguments:
+ *
+ * Adapter - The adapter which is being verified.
+ *
+ * EthAddress - A pointer to the address to be checked
+ * This 6_byte Ethernet address is followed
+ * by a zero byte, followed by a value such
+ * that the sum of a checksum on the Ethernet
+ * address and this value is 0xff.
+ *
+ * Return Value:
+ *
+ * TRUE if success
+ *
+-*/
+
+
+BOOLEAN
+VerifyChecksum(
+ IN UNALIGNED UCHAR *EthAddress
+ )
+{
+
+ UINT i;
+ UCHAR CheckSum[2];
+ ULONG Sum = 0;
+
+ // The checksum yields from the polynom:
+ // 10 2 9 8
+ // (B[0]*2 + B[1]*2 + B[2]*2 + B[3]*2 + B[4]*2 + B[5]) mod (2**16-1)
+
+ for (i=0; i<= 2; i++) {
+
+ Sum *= 2;
+
+ if (Sum > 0xffff) Sum -= 0xffff;
+
+ Sum += (*(EthAddress+(2*i)) << 8) + *(EthAddress+(2*i)+1);
+
+ if (Sum > 0xffff) Sum -= 0xffff;
+ }
+
+ if (Sum >= 0xffff) {
+ Sum = 0;
+ }
+
+ CheckSum[0] = (UCHAR)(Sum / 0x100);
+ CheckSum[1] = (UCHAR)(Sum % 0x100);
+
+#if __DBG
+ DbgPrint(" CheckSum = %02x %02x\n",CheckSum[0],CheckSum[1]);
+#endif
+ return (*(UNALIGNED USHORT *)CheckSum == *(UNALIGNED USHORT *)(EthAddress + 6)) ;
+
+}
+
+
+
+
+
+
+
+
+
+
+/*+
+ * DC21X4ParseExtendedBlock
+ *
+ * Routine Description:
+ *
+ * This routine is called by the SROM Parser and takes care of the
+ * parsing of the info block with Extended format (EXT=1) in the 21140's
+ * info leaf.
+ *
+ * Arguments:
+ *
+ * Adapter - Pointer to the Data Structure
+ * MediaBlock - Pointer to the Serial Rom data.
+ * GeneralPurposeCtrl - Value of the General Purpose Ctrl
+ *
+ * Return Value:
+ *
+ * None
+ *
+-*/
+extern
+VOID
+DC21X4ParseExtendedBlock(
+ IN PDC21X4_ADAPTER Adapter,
+ IN OUT UNALIGNED UCHAR **MediaBlock,
+ IN USHORT GeneralPurposeCtrl,
+ OUT PUCHAR PMediaCode
+ )
+{
+
+ UNALIGNED UCHAR *DataBytePtr;
+ UNALIGNED USHORT *DataWordPtr;
+ UNALIGNED UCHAR *EndOfBlock;
+
+ UCHAR MediaCode;
+
+ INT i;
+ INT PhyNumber;
+ UCHAR Length;
+ UCHAR Type;
+ USHORT External;
+
+ DataBytePtr = (UNALIGNED CHAR *)(*MediaBlock);
+
+ Length = (*(DataBytePtr++) & LENGTH);
+ EndOfBlock = DataBytePtr + Length;
+
+ Type = *(DataBytePtr++);
+
+#if __DBG
+ DbgPrint("Block Length =%02x\n", Length);
+ DbgPrint("Block Type =%02x\n", Type);
+#endif
+
+
+ switch (Type) {
+
+ case TYPE_0:
+
+ DC21X4ParseFixedBlock(
+ Adapter,
+ &DataBytePtr,
+ GeneralPurposeCtrl,
+ PMediaCode
+ );
+ break;
+
+ case TYPE_1:
+ case TYPE_3:
+
+ PhyNumber = (INT) *(DataBytePtr++);
+ if (PhyNumber >= MAX_PHY_TABLE) {
+#if __DBG
+ DbgPrint("PhyNumber =%02x Out of RANGE!!!\n", PhyNumber);
+#endif
+ break;
+ }
+
+ //General Purpose Control
+ Adapter->Phy[PhyNumber].GeneralPurposeCtrl = GeneralPurposeCtrl;
+
+ //General Purpose Data
+
+ Adapter->Phy[PhyNumber].GepSequenceLength = (INT) *(DataBytePtr++);
+
+ if (Adapter->Phy[PhyNumber].GepSequenceLength > MAX_GPR_SEQUENCE) {
+#if __DBG
+ DbgPrint("GepSequence =%02x Out of RANGE!!!\n",
+ Adapter->Phy[PhyNumber].GepSequenceLength );
+#endif
+ break;
+ }
+
+ switch (Type) {
+
+ case TYPE_1:
+
+ //GepSequence Length in bytes
+
+ for (i=0; i < Adapter->Phy[PhyNumber].GepSequenceLength; i++) {
+ Adapter->Phy[PhyNumber].GepSequence[i] = *(DataBytePtr++);
+ }
+ break;
+
+ case TYPE_3:
+
+ //GepSequence Length in words
+
+ for (i=0; i < Adapter->Phy[PhyNumber].GepSequenceLength; i++) {
+ Adapter->Phy[PhyNumber].GepSequence[i] = *(UNALIGNED USHORT *)(DataBytePtr);
+ DataBytePtr += sizeof(USHORT);
+ }
+ break;
+ }
+
+ // Reset sequence
+
+ Adapter->Phy[PhyNumber].ResetSequenceLength = (INT) *(DataBytePtr++);
+
+ if (Adapter->Phy[PhyNumber].ResetSequenceLength > MAX_RESET_SEQUENCE) {
+#if __DBG
+ DbgPrint("ResetSequence =%02x Out of RANGE!!!\n",
+ Adapter->Phy[PhyNumber].ResetSequenceLength );
+#endif
+ break;
+ }
+
+ for (i=0; i < Adapter->Phy[PhyNumber].ResetSequenceLength; i++) {
+ Adapter->Phy[PhyNumber].ResetSequence[i] = *(DataBytePtr++);
+ }
+
+ // Capabilities,Nway,FullDuplex & TxmThreshold
+
+ DataWordPtr = (UNALIGNED USHORT *) DataBytePtr;
+
+ Adapter->Phy[PhyNumber].MediaCapabilities =
+ (*(DataWordPtr++) & MEDIA_CAPABILITIES_MASK);
+ Adapter->Phy[PhyNumber].NwayAdvertisement =
+ (*(DataWordPtr++) & NWAY_ADVERTISEMENT_MASK);
+ Adapter->Phy[PhyNumber].FullDuplexBits =
+ (*(DataWordPtr++) & MEDIA_CAPABILITIES_MASK);
+ Adapter->Phy[PhyNumber].TxThresholdModeBits =
+ (*(DataWordPtr++) & MEDIA_CAPABILITIES_MASK);
+ Adapter->Phy[PhyNumber].Present = TRUE;
+
+ Adapter->PhyMediumInSrom = TRUE;
+
+ DataBytePtr = (UNALIGNED UCHAR *) DataWordPtr;
+
+ // GEP Interrupt
+
+ switch (Type) {
+
+ case TYPE_3:
+
+ Adapter->Phy[PhyNumber].GepInterruptMask =
+ *(DataBytePtr++) << DC21X4_GEP_INTERRUPT_BIT_SHIFT;
+ break;
+ }
+
+
+#if __DBG
+ DbgPrint("PHY Number= %02x\n", PhyNumber);
+ DbgPrint("GPR Sequence Length= %d\n", Adapter->Phy[PhyNumber].GepSequenceLength);
+ for (i=0; i < Adapter->Phy[PhyNumber].GepSequenceLength; i++) {
+ DbgPrint("GPR Sequence[%d]=%02x\n", i, Adapter->Phy[PhyNumber].GepSequence[i]);
+ }
+ DbgPrint("RESET Sequence Length= %d\n", Adapter->Phy[PhyNumber].ResetSequenceLength);
+ for (i=0; i < Adapter->Phy[PhyNumber].ResetSequenceLength; i++) {
+ DbgPrint("RESET Sequence[%d]=%02x\n", i, Adapter->Phy[PhyNumber].ResetSequence[i]);
+ }
+ DbgPrint("Media Capabilities= %04x\n", Adapter->Phy[PhyNumber].MediaCapabilities);
+ DbgPrint("NWAY Advertisement= %04x\n", Adapter->Phy[PhyNumber].NwayAdvertisement);
+ DbgPrint("FD Bit map= %02x\n",Adapter->Phy[PhyNumber].FullDuplexBits);
+ DbgPrint("TTM Bit map= %02x\n",Adapter->Phy[PhyNumber].TxThresholdModeBits);
+ DbgPrint("GEP Interrupt mask = %01x\n",Adapter->Phy[PhyNumber].GepInterruptMask);
+#endif
+
+ break;
+
+ case TYPE_2:
+
+ MediaCode = *(DataBytePtr) & DC21X4_MEDIA;
+ if (MediaCode >= MAX_MEDIA_TABLE) {
+ break;
+ }
+ Adapter->MediaCapable |= 1 << MediaCode;
+ External = *(DataBytePtr++) & EXT;
+#if __DBG
+ DbgPrint("SRom: Media Code= %02x\n", MediaCode);
+ DbgPrint("SRom: Media Capable= %02x\n", Adapter->MediaCapable);
+#endif
+
+ DataWordPtr = (UNALIGNED USHORT *)DataBytePtr;
+
+ if (External) {
+
+ // EXT bit is set :
+ // overwrite the SIA Registers default values
+ // with the values stored into the SROM
+
+ Adapter->Media[MediaCode].SiaRegister[0] =
+ ((ULONG)*(DataWordPtr++) & 0xFFFF);
+ Adapter->Media[MediaCode].SiaRegister[1] =
+ ((ULONG)*(DataWordPtr++) & 0xFFFF);
+ Adapter->Media[MediaCode].SiaRegister[2] =
+ ((ULONG)*(DataWordPtr++) & 0xFFFF);
+#if __DBG
+ DbgPrint("SRom: EXT= 1:\n");
+ DbgPrint("SRom: SiaReg[0]= %08x\n",Adapter->Media[MediaCode].SiaRegister[0]);
+ DbgPrint("SRom: SiaReg[1]= %08x\n",Adapter->Media[MediaCode].SiaRegister[1]);
+ DbgPrint("SRom: SiaReg[2]= %08x\n",Adapter->Media[MediaCode].SiaRegister[2]);
+#endif
+ }
+ Adapter->Media[MediaCode].GeneralPurposeCtrl =
+ ((ULONG)*(DataWordPtr++) & 0xFFFF);
+ Adapter->Media[MediaCode].GeneralPurposeData =
+ ((ULONG)*(DataWordPtr) & 0xFFFF);
+#if __DBG
+ DbgPrint("SRom: Gep Ctrl = %08x\n",Adapter->Media[MediaCode].GeneralPurposeCtrl);
+ DbgPrint("SRom: Gep Data = %08x\n",Adapter->Media[MediaCode].GeneralPurposeData);
+#endif
+
+ *PMediaCode = MediaCode;
+
+ break;
+
+
+ default:
+
+#if __DBG
+ DbgPrint("Type =%02x unknown... skipping\n", Type );
+#endif
+ break;
+
+ }
+
+ *MediaBlock = EndOfBlock;
+
+}
+
+
+
+
+
+
+
+
+
+
+/*+
+ * DC21X4ParseFixedBlock
+ *
+ * Routine Description:
+ *
+ * This routine is called by the SROM Parser and takes care of the
+ * parsing of the info block with fixed format (EXT=0) in the 21140's
+ * info leaf.
+ *
+ * Arguments:
+ *
+ * Adapter - Pointer to the Data Structure
+ * DataBytePtr - Pointer to the Serial Rom data.
+ * GeneralPurposeCtrl - Value of the General Purpose Ctrl
+ *
+ * Return Value:
+ *
+ * None.
+ *
+-*/
+extern
+VOID
+DC21X4ParseFixedBlock(
+ IN PDC21X4_ADAPTER Adapter,
+ IN OUT UNALIGNED UCHAR **MediaBlock,
+ IN USHORT GeneralPurposeCtrl,
+ OUT PUCHAR PMediaCode
+ )
+{
+ UNALIGNED UCHAR *DataBytePtr;
+ UCHAR MediaCode;
+
+ DataBytePtr = (UNALIGNED CHAR *)(*MediaBlock);
+
+ MediaCode = *(DataBytePtr) & DC21X4_MEDIA;
+
+ if (MediaCode >= MAX_MEDIA_TABLE) {
+ DataBytePtr += ((2*sizeof(DataBytePtr)) + sizeof(USHORT));
+ *MediaBlock = DataBytePtr;
+ return ;
+ }
+ Adapter->MediaCapable |= 1 << MediaCode;
+
+ Adapter->Media[MediaCode].GeneralPurposeCtrl =
+ (ULONG)GeneralPurposeCtrl;
+ Adapter->Media[MediaCode].GeneralPurposeData =
+ (ULONG)(*(++DataBytePtr) & 0xFF);
+ Adapter->Media[MediaCode].Mode =
+ GET_MODE(++DataBytePtr);
+ Adapter->Media[MediaCode].Polarity =
+ GET_POLARITY(DataBytePtr);
+ Adapter->Media[MediaCode].SenseMask =
+ GET_SENSE_MASK(DataBytePtr);
+
+#if __DBG
+ DbgPrint("Media Code= %02x\n", MediaCode);
+ DbgPrint("Media Capable= %02x\n", Adapter->MediaCapable);
+ DbgPrint("GPData= %02x\n",Adapter->Media[MediaCode].GeneralPurposeData);
+ DbgPrint("Mode= %02x\n",Adapter->Media[MediaCode].Mode);
+ DbgPrint("Polarity= %x\n",Adapter->Media[MediaCode].Polarity);
+ DbgPrint("Sense Mask= %x\n",Adapter->Media[MediaCode].SenseMask);
+#endif
+
+ Adapter->Media[MediaCode].Mode |=
+ (Adapter->Media[MediaCode].Mode & DC21X4_TXM_THRESHOLD_MODE)?
+ Adapter->Threshold10Mbps : Adapter->Threshold100Mbps;
+
+ if ( Adapter->Media[MediaCode].SenseMask
+ && MediaCode != Medium10BaseTFd
+ && MediaCode != Medium100BaseTxFd
+ && MediaCode != Medium100BaseFxFd){
+
+ //Add the media code to the MediaPrecedence table
+ Adapter->MediaPrecedence[Adapter->MediaCount++] = MediaCode;
+ }
+
+ // Check if default media
+ if (IF_DEFAULT_MEDIA(DataBytePtr)) {
+ Adapter->DefaultMediumFlag = TRUE;
+ Adapter->DefaultMedium = MediaCode;
+#if __DBG
+ DbgPrint("SRom: Default Media = %04x\n",MediaCode);
+#endif
+ }
+
+
+ *PMediaCode = MediaCode;
+
+ DataBytePtr += sizeof(USHORT);
+ *MediaBlock = DataBytePtr;
+
+}
+
+
+
+
+
+
+
+
+
+
+
+#pragma NDIS_PAGABLE_FUNCTION(DC21X4ParseSRom)
+
+/*
+ * DC21X4ParseSRom
+ *
+ * Routine Description:
+ *
+ * ParseSRom parses the Serial ROM to retrieve the Ethernet Station
+ * address of the adapter and the adapter's media specific information
+ *
+ * Adapter - pointer to adapter structure
+ *
+ * Return Value:
+ *
+ * Ndis Status
+ *
+-*/
+
+
+NDIS_STATUS
+DC21X4ParseSRom(
+ IN PDC21X4_ADAPTER Adapter
+ )
+{
+
+ PSROM_ID_BLOCK SRomIdBlock;
+ UNALIGNED ADAPTER_ENTRIES *AdapterEntry;
+ UNALIGNED UCHAR *DataBytePtr;
+ UNALIGNED USHORT *DataWordPtr;
+ PUCHAR SRomData;
+
+ USHORT GeneralPurposeCtrl;
+ USHORT MediaCount;
+ USHORT MediaType;
+ UCHAR MediaCode;
+ ULONG Offset = 0;
+ INT Index = 0;
+ INT i;
+
+ BOOLEAN ExtendedFormat;
+
+ ULONG CheckSum;
+ UCHAR Tmp[ETH_LENGTH_OF_ADDRESS];
+
+ UCHAR DC21140Leaf [] = {
+ 0x00,0x08, // AutoSense
+ 0x1f, // General Purpose Ctrl
+ 0x04, // Media Count
+ 0x00,0x0b,0x8e,0x00, // Tp
+ 0x03,0x1b,0x6d,0x00, // 100BaseTx
+ 0x04,0x03,0x8e,0x00, // TpFd
+ 0x05,0x1b,0x6d,0x00 // 100BaseTxFd
+ };
+
+UCHAR DE500Strng[] = {"DE500-XA"};
+
+
+ NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
+
+
+ // Allocate space to dump the whole SROM
+
+ ALLOC_MEMORY (&NdisStatus, &SRomData, SROM_SIZE);
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+#if __DBG
+ DbgPrint ( "SROM ALLOC_MEMORY FAILED\n");
+#endif
+ return NdisStatus;
+ }
+
+ // Read the whole ROM
+
+ if (DC21X4ReadSRom(
+ Adapter,
+ &Offset,
+ SROM_SIZE,
+ SRomData)) {
+
+ SRomIdBlock = (PSROM_ID_BLOCK)SRomData;
+ }
+ else {
+#if __DBG
+ DbgPrint ( "ReadSRom failed\n");
+#endif
+ FREE_MEMORY(SRomData, SROM_SIZE);
+ return NDIS_STATUS_HARD_ERRORS;
+ }
+
+ // Check the Checksum
+
+ CheckSum = CRC32(SRomData,SROM_SIZE-2) & 0xFFFF;
+ if (CheckSum != *(PUSHORT)&SRomData[SROM_SIZE-2]) {
+
+ // Check if the SROM is a "legacy" formated SROM
+ // containing only the network address
+
+ if ((Adapter-> DeviceId == DC21140_CFID)
+ && !IS_NULL_ADDRESS(SRomData)
+ && VerifyChecksum(SRomData)
+ ) {
+
+#if __DBG
+ DbgPrint ( "Legacy SRom...\n");
+#endif
+ MOVE_MEMORY (
+ &Adapter->PermanentNetworkAddress[0],
+ &SRomData[0],
+ ETH_LENGTH_OF_ADDRESS
+ );
+
+ Adapter->PermanentAddressValid = TRUE;
+
+ SRomIdBlock->FormatVersion = SROM_LEGACY;
+ DataBytePtr = &DC21140Leaf[0];
+ }
+
+ else {
+#if __DBG
+ DbgPrint ( "Invalid SROM Checksum - Expected:%04x Read:%04x\n",
+ CheckSum,*(PUSHORT)&SRomData[SROM_SIZE-2]);
+#endif
+ FREE_MEMORY(SRomData, SROM_SIZE);
+ return NDIS_STATUS_SOFT_ERRORS;
+ }
+ }
+
+ // Check the SROM Version
+
+ switch (SRomIdBlock->FormatVersion) {
+
+ default:
+
+#if __DBG
+ DbgPrint ("SRom: Unsupported Format Version (%x)!\n",
+ SRomIdBlock->FormatVersion);
+#endif
+ FREE_MEMORY(SRomData, SROM_SIZE);
+ return NDIS_STATUS_SOFT_ERRORS;
+
+ case SROM_V1:
+ case SROM_V3:
+
+ // Parse the Adapter Device Number.
+#if __DBG
+ DbgPrint ("SRom: Version: %2x\n",SRomIdBlock->FormatVersion );
+ DbgPrint ("SRom: Adapter Count: %2x\n", SRomIdBlock->AdapterCount);
+ DbgPrint ("SRom: Network Base Address: %02x-%02x-%02x-%02x-%02x-%02x\n",
+ SRomIdBlock->NetworkAddress[0],SRomIdBlock->NetworkAddress[1],
+ SRomIdBlock->NetworkAddress[2],SRomIdBlock->NetworkAddress[3],
+ SRomIdBlock->NetworkAddress[4],SRomIdBlock->NetworkAddress[5]);
+#endif
+
+ AdapterEntry = (PADAPTER_ENTRIES)&SRomData[sizeof(SROM_ID_BLOCK)];
+
+ if ((INT)SRomIdBlock->AdapterCount > 1) {
+
+ // Parse the Adapter's Device Number.
+ for (; Index < (INT)SRomIdBlock->AdapterCount; Index++,AdapterEntry++) {
+
+#if __DBG
+ DbgPrint ("SRom: DeviceNumber, %2x\n",AdapterEntry->DeviceNumber );
+ DbgPrint ("SRom: Offset, %4x\n", AdapterEntry->Offset);
+#endif
+ if (AdapterEntry->DeviceNumber == (UCHAR)Adapter->SlotNumber) {
+ break;
+ }
+ }
+ }
+
+ if (Index == (INT)SRomIdBlock->AdapterCount) {
+#if __DBG
+ DbgPrint("SRom: Adapter's Device Number %d not found in SROM\n",
+ Adapter->SlotNumber);
+#endif
+ FREE_MEMORY(SRomData, SROM_SIZE);
+ return NDIS_STATUS_ADAPTER_NOT_FOUND;
+ }
+
+ // Check if the Station Address is a NULL Address
+
+ if IS_NULL_ADDRESS(SRomIdBlock->NetworkAddress) {
+
+#if __DBG
+ DbgPrint ("SRom: NULL Network Address\n");
+#endif
+ Adapter->PermanentAddressValid = FALSE;
+ }
+ else {
+
+ if (Index !=0) {
+
+ // Add the adapter index to the base network Address
+ // (The carry is propagated to the 3 lower bytes
+ // of the address only (the 3 upper bytes are the vendor id))
+
+ for (i=0;i<3;i++) {
+ Tmp[i] = SRomIdBlock->NetworkAddress[ETH_LENGTH_OF_ADDRESS-(i+1)];
+ }
+ *(UNALIGNED ULONG *)&Tmp[0] += Index;
+ for (i=0;i<3;i++) {
+ SRomIdBlock->NetworkAddress[ETH_LENGTH_OF_ADDRESS-(i+1)] = Tmp[i];
+ }
+
+
+ }
+#if __DBG
+ DbgPrint ("SRom: Network Address: %02x-%02x-%02x-%02x-%02x-%02x\n",
+ SRomIdBlock->NetworkAddress[0],SRomIdBlock->NetworkAddress[1],
+ SRomIdBlock->NetworkAddress[2],SRomIdBlock->NetworkAddress[3],
+ SRomIdBlock->NetworkAddress[4],SRomIdBlock->NetworkAddress[5]);
+#endif
+ MOVE_MEMORY (
+ &Adapter->PermanentNetworkAddress[0],
+ SRomIdBlock->NetworkAddress,
+ ETH_LENGTH_OF_ADDRESS
+ );
+
+ Adapter->PermanentAddressValid = TRUE;
+ }
+
+ //Parse the Media Info Blocks.
+
+ DataBytePtr = &(SRomData[AdapterEntry->Offset]);
+
+ case SROM_LEGACY:
+
+ Adapter->MediaCapable = 0;
+
+ switch (Adapter-> DeviceId) {
+
+ case DC21041_CFID:
+
+ // Initialize the Media table with the default values.
+
+ Adapter->Media[Medium10BaseT].SiaRegister[0] = DC21041_SIA0_10BT;
+ Adapter->Media[Medium10BaseT].SiaRegister[1] = DC21041_SIA1_10BT;
+ Adapter->Media[Medium10BaseT].SiaRegister[2] = DC21041_SIA2_10BT;
+
+ Adapter->Media[Medium10Base2].SiaRegister[0] = DC21041_SIA0_10B2;
+ Adapter->Media[Medium10Base2].SiaRegister[1] = DC21041_SIA1_10B2;
+ Adapter->Media[Medium10Base2].SiaRegister[2] = DC21041_SIA2_10B2;
+
+ Adapter->Media[Medium10Base5].SiaRegister[0] = DC21041_SIA0_10B5;
+ Adapter->Media[Medium10Base5].SiaRegister[1] = DC21041_SIA1_10B5;
+ Adapter->Media[Medium10Base5].SiaRegister[2] = DC21041_SIA2_10B5;
+
+ MediaType = *(UNALIGNED USHORT *)DataBytePtr;
+ DataBytePtr += sizeof(USHORT);
+
+ MediaCount = *(DataBytePtr++);
+#if __DBG
+ DbgPrint("SRom: MediaType= %04x \n", MediaType);
+ DbgPrint("SRom: Media Count= %d \n", MediaCount);
+#endif
+ for (Index=0; Index < MediaCount; Index++) {
+
+ MediaCode = *DataBytePtr & DC21X4_MEDIA;
+
+ if (MediaCode >= MAX_MEDIA_TABLE) {
+ DataBytePtr += (sizeof(DataBytePtr)
+ + ((*DataBytePtr & EXT) ? (3 * sizeof(DataWordPtr)):0));
+ continue;
+ }
+
+ Adapter->MediaCapable |= 1 << MediaCode;
+#if __DBG
+ DbgPrint("SRom: Media Code= %02x\n", MediaCode);
+ DbgPrint("SRom: Media Capable= %02x\n", Adapter->MediaCapable);
+#endif
+
+ if (*(DataBytePtr++) & EXT) {
+
+ // EXT bit is set :
+ // overwrite the SIA Registers default values
+ // with the values stored into the SROM
+
+ DataWordPtr = (UNALIGNED USHORT *) DataBytePtr;
+ Adapter->Media[MediaCode].SiaRegister[0] =
+ ((ULONG)*(DataWordPtr++) & 0xFFFF);
+ Adapter->Media[MediaCode].SiaRegister[1] =
+ ((ULONG)*(DataWordPtr++) & 0xFFFF);
+ Adapter->Media[MediaCode].SiaRegister[2] =
+ ((ULONG)*(DataWordPtr++) & 0xFFFF);
+ DataBytePtr = (UNALIGNED UCHAR *) DataWordPtr;
+#if __DBG
+ DbgPrint("SRom: EXT= 1:\n");
+ DbgPrint("SRom: SiaReg[0]= %08x\n",Adapter->Media[MediaCode].SiaRegister[0]);
+ DbgPrint("SRom: SiaReg[1]= %08x\n",Adapter->Media[MediaCode].SiaRegister[1]);
+ DbgPrint("SRom: SiaReg[2]= %08x\n",Adapter->Media[MediaCode].SiaRegister[2]);
+#endif
+ }
+
+ }
+
+ break;
+
+ case DC21140_CFID:
+
+ switch (SRomIdBlock->FormatVersion) {
+
+ case SROM_LEGACY:
+ case SROM_V1:
+
+ if (Adapter->RevisionNumber == DC21140_REV1_1) {
+ Adapter->DynamicAutoSense = BOARD_SIGNATURE(SRomData);
+ break;
+ }
+
+ default:
+
+ //MediaType
+
+ MediaType = *(UNALIGNED USHORT *)DataBytePtr;
+ Adapter->DynamicAutoSense = ((MediaType & DISABLE_AUTOSENSE) == 0);
+#if __DBG
+ DbgPrint("SRom: MediaType= %04x \n", MediaType);
+#endif
+ }
+
+#if __DBG
+ DbgPrint("SRom: Dynamic Autosense %s\n",
+ Adapter->DynamicAutoSense? "Enabled":"Disabled");
+#endif
+
+ DataBytePtr += sizeof(USHORT);
+
+ GeneralPurposeCtrl = (((USHORT)*(DataBytePtr++) & 0xFF)|(0x100));
+
+ MediaCount = *(DataBytePtr++);
+
+#if __DBG
+ DbgPrint("SRom: General Purpose Control= %08x \n", GeneralPurposeCtrl);
+ DbgPrint("SRom: MediaCount= %d \n", MediaCount);
+#endif
+ for (Index=0; Index < MediaCount; Index++) {
+
+ ExtendedFormat = (*DataBytePtr & EXTENDED_FORMAT);
+
+ if ((SRomIdBlock->FormatVersion == SROM_V3) && ExtendedFormat) {
+ DC21X4ParseExtendedBlock(
+ Adapter,
+ &DataBytePtr,
+ GeneralPurposeCtrl,
+ &MediaCode
+ );
+ }
+ else {
+ DC21X4ParseFixedBlock(
+ Adapter,
+ &DataBytePtr,
+ GeneralPurposeCtrl,
+ &MediaCode
+ );
+ }
+
+ }
+
+ if (!Adapter->DefaultMediumFlag && Adapter->MediaCount>0) {
+ Adapter->DefaultMedium =
+ Adapter->MediaPrecedence[Adapter->MediaCount-1];
+ }
+ break;
+
+ case DC21142_CFID:
+
+ if (SRomIdBlock->FormatVersion < SROM_V3) {
+#if __DBG
+ DbgPrint ("SRom: Unsupported Format Version (%x)!\n",
+ SRomIdBlock->FormatVersion);
+#endif
+ FREE_MEMORY(SRomData, SROM_SIZE);
+ return NDIS_STATUS_SOFT_ERRORS;
+ }
+
+ // Initialize the Media table with the default values.
+
+ Adapter->Media[Medium10BaseT].SiaRegister[0] = DC21142_SIA0_10BT;
+ Adapter->Media[Medium10BaseT].SiaRegister[1] = DC21142_SIA1_10BT;
+ Adapter->Media[Medium10BaseT].SiaRegister[2] = DC21142_SIA2_10BT;
+
+ Adapter->Media[Medium10Base2].SiaRegister[0] = DC21142_SIA0_10B2;
+ Adapter->Media[Medium10Base2].SiaRegister[1] = DC21142_SIA1_10B2;
+ Adapter->Media[Medium10Base2].SiaRegister[2] = DC21142_SIA2_10B2;
+
+ Adapter->Media[Medium10Base5].SiaRegister[0] = DC21142_SIA0_10B5;
+ Adapter->Media[Medium10Base5].SiaRegister[1] = DC21142_SIA1_10B5;
+ Adapter->Media[Medium10Base5].SiaRegister[2] = DC21142_SIA2_10B5;
+
+
+ MediaType = *(UNALIGNED USHORT *)DataBytePtr;
+
+ Adapter->DynamicAutoSense = ((MediaType & DISABLE_AUTOSENSE) == 0);
+#if __DBG
+ DbgPrint("SRom: Dynamic Autosense %s\n",
+ Adapter->DynamicAutoSense? "Enabled":"Disabled");
+#endif
+ DataBytePtr += sizeof(USHORT);
+ MediaCount = *(DataBytePtr++);
+#if __DBG
+ DbgPrint("SRom: MediaType= %04x \n", MediaType);
+ DbgPrint("SRom: MediaCount= %d \n", MediaCount);
+#endif
+
+ for (Index=0; Index < MediaCount; Index++) {
+
+ DC21X4ParseExtendedBlock(
+ Adapter,
+ (PVOID)&DataBytePtr,
+ (USHORT)NULL,
+ &MediaCode
+ );
+ }
+
+ if (!Adapter->DefaultMediumFlag && Adapter->MediaCount>0) {
+ Adapter->DefaultMedium =
+ Adapter->MediaPrecedence[Adapter->MediaCount-1];
+ }
+
+ break;
+
+ default:
+
+ NdisStatus = NDIS_STATUS_DEVICE_FAILED;
+ }
+
+ break;
+
+ }
+
+ if ( (MediaCount == 1)
+ && Adapter->MediaCapable
+ && !Adapter->PhyMediumInSrom
+ ) {
+
+ //Force MediaType to the single supported medium
+#if __DBG
+ DbgPrint("SRom: One single supported medium: Force MediaType %04x to ",Adapter->MediaType);
+#endif
+ Adapter->MediaType &= ~(MEDIA_MASK | MEDIA_AUTOSENSE);
+ Adapter->MediaType |= MediaCode;
+#if __DBG
+ DbgPrint("%04x\n",Adapter->MediaType);
+#endif
+ }
+
+ //if no 10Base port is populated, switch Port_Select to 100Base
+
+ if (!(Adapter->MediaCapable & (MEDIUM_10BT | MEDIUM_10B2 | MEDIUM_10B5))) {
+ Adapter->OperationMode |= DC21X4_PORT_SELECT;
+ }
+
+ FREE_MEMORY(SRomData, SROM_SIZE);
+ return NdisStatus;
+
+
+}
+
+
+
+
+
+
+
+
+
+#pragma NDIS_PAGABLE_FUNCTION(DC21X4ReadSRom)
+
+/*
+ * DC21X4ReadSRom
+ *
+ * Routine Description:
+ *
+ * ReadSRom is called by DC21X4RegisterAdapter to read the onboard ROM
+ * for the network address and other parameters.
+ * This routine reads the required number of bytes from the given
+ * offset in the ROM.
+ *
+ * Arguments:
+ *
+ * Adapter -
+ *
+ * Offset - byte offset into SROM to start reading from. Must
+ * be word aligned
+ * Len - number of bytes to read
+ * Data - pointer to buffer to read data into.
+ * if NULL, don't return data
+ *
+ * Return Value:
+ *
+ * TRUE if success, FALSE if hardware failure encountered.
+ *
+-*/
+
+
+BOOLEAN
+DC21X4ReadSRom(
+ IN PDC21X4_ADAPTER Adapter,
+ IN OUT PULONG Offset,
+ IN USHORT Len,
+ OUT PUCHAR Buffer
+ )
+{
+
+ INT i;
+ INT j;
+ ULONG Dbit;
+ ULONG Dout;
+ USHORT WOffset;
+ USHORT WLen;
+ USHORT WData;
+
+ // Make sure the ROM_Address is EVEN.
+
+ if (*Offset & 1)
+ {
+#if __DBG
+ DbgPrint ("ReadSRom failure - Offset not word aligned\n");
+#endif
+ return FALSE;
+ }
+
+ // Round up the length to multiple of words.
+ WLen = (Len + 1) / 2;
+
+ // Convert the ROM_Address byte offset to word offset
+ WOffset = (USHORT)(*Offset >> 1);
+
+ // Make sure the requested read does not exceed the ROM size
+
+ if ( (WOffset + WLen) > SROM_93LC46B_SIZE) {
+#if __DBG
+ DbgPrint ("ReadSRom warning - address range excedes ROM size\n");
+#endif
+ return FALSE;
+ }
+
+
+ // Switch CSR to work with new SROM interface
+
+ DC21X4_WRITE_PORT(
+ DC21X4_IDPROM,
+ CSR_WRITE | SEL_SROM
+ );
+
+ // Make sure SROM is in idle state
+ // (deliver it enough clocks with CS set, Din = 0).
+
+ for (i = 0; i < SROM_93LC46B_MAX_CYCLES; i++) {
+
+ DC21X4_WRITE_PORT(
+ DC21X4_IDPROM,
+ CSR_WRITE | SEL_SROM | CS | CLK
+ );
+
+ NdisStallExecution(SROM_93LC46B_DELAY);
+
+ DC21X4_WRITE_PORT(
+ DC21X4_IDPROM,
+ CSR_WRITE | SEL_SROM | CS
+ );
+
+ NdisStallExecution(SROM_93LC46B_DELAY);
+
+ }
+
+ DC21X4_WRITE_PORT(
+ DC21X4_IDPROM,
+ CSR_WRITE | SEL_SROM
+ );
+
+ NdisStallExecution(SROM_93LC46B_DELAY);
+
+
+ // Read the data
+
+ for (j = 0; j < WLen; j++,WOffset++) {
+
+ //Output the READ command to the SROM
+
+ DC21X4_WRITE_PORT(
+ DC21X4_IDPROM,
+ CSR_WRITE | SEL_SROM | CS | DATA_1
+ );
+
+ DC21X4_WRITE_PORT(
+ DC21X4_IDPROM,
+ CSR_WRITE | SEL_SROM | CS | CLK | DATA_1
+ );
+
+ NdisStallExecution(SROM_93LC46B_DELAY);
+
+ DC21X4_WRITE_PORT(
+ DC21X4_IDPROM,
+ CSR_WRITE | SEL_SROM | CS | DATA_1
+ );
+
+ NdisStallExecution(SROM_93LC46B_DELAY);
+
+ DC21X4_WRITE_PORT(
+ DC21X4_IDPROM,
+ CSR_WRITE | SEL_SROM | CS | DATA_1
+ );
+
+ DC21X4_WRITE_PORT(
+ DC21X4_IDPROM,
+ CSR_WRITE | SEL_SROM | CS | CLK | DATA_1
+ );
+
+ NdisStallExecution(SROM_93LC46B_DELAY);
+
+ DC21X4_WRITE_PORT(
+ DC21X4_IDPROM,
+ CSR_WRITE | SEL_SROM | CS | DATA_1
+ );
+
+ NdisStallExecution(SROM_93LC46B_DELAY);
+
+ DC21X4_WRITE_PORT(
+ DC21X4_IDPROM,
+ CSR_WRITE | SEL_SROM | CS | DATA_0
+ );
+
+ DC21X4_WRITE_PORT(
+ DC21X4_IDPROM,
+ CSR_WRITE | SEL_SROM | CS | CLK | DATA_0
+ );
+
+ NdisStallExecution(SROM_93LC46B_DELAY);
+
+ DC21X4_WRITE_PORT(
+ DC21X4_IDPROM,
+ CSR_WRITE | SEL_SROM | CS | DATA_0
+ );
+
+ NdisStallExecution(SROM_93LC46B_DELAY);
+
+
+ // Output the WORD Address of the SROM
+
+ for (i = SROM_93LC46B_ADDRESS_MSB; i>= 0; i--) {
+
+ Dbit = (USHORT)((WOffset >> i) & 1) << 2;
+
+ DC21X4_WRITE_PORT(
+ DC21X4_IDPROM,
+ CSR_WRITE | SEL_SROM | CS | Dbit
+ );
+
+ DC21X4_WRITE_PORT(
+ DC21X4_IDPROM,
+ CSR_WRITE | SEL_SROM | CS | CLK | Dbit
+ );
+
+ NdisStallExecution(SROM_93LC46B_DELAY);
+
+ DC21X4_WRITE_PORT(
+ DC21X4_IDPROM,
+ CSR_WRITE | SEL_SROM | CS | Dbit
+ );
+
+ NdisStallExecution(SROM_93LC46B_DELAY);
+
+ }
+
+
+ // Verify that the SROM output data became now 0.
+
+ DC21X4_READ_PORT(
+ DC21X4_IDPROM,
+ &Dout
+ );
+
+ if (Dout & SROM_93LC46B_VALID_BITMASK) {
+#if __DBG
+ DbgPrint ("ReadSRom failure - SROM didn't become busy in read command\n");
+#endif
+ return(FALSE);
+ }
+
+ // Read the data from the SROM
+
+ WData = 0;
+ for (i = SROM_93LC46B_DATA_MSB; i >= 0; i--) {
+
+ DC21X4_WRITE_PORT(
+ DC21X4_IDPROM,
+ CSR_WRITE | SEL_SROM | CS | CLK
+ );
+
+ NdisStallExecution(SROM_93LC46B_DELAY);
+
+ DC21X4_READ_PORT(
+ DC21X4_IDPROM,
+ &Dout
+ );
+
+ DC21X4_WRITE_PORT(
+ DC21X4_IDPROM,
+ CSR_WRITE | SEL_SROM | CS
+ );
+
+ WData |= ((Dout >> SROM_93LC46B_DATA_BIT) & 1) << i;
+
+ NdisStallExecution(SROM_93LC46B_DELAY);
+
+ }
+
+#if _DBG
+ DbgPrint("Data = %04x\n",WData);
+#endif
+
+ // Put our read data in user buffer
+
+ if (Buffer) {
+
+ if (Len >= 2) {
+
+ *(PUSHORT)Buffer = WData;
+ Buffer += 2;
+ Len -= 2;
+ }
+ else {
+
+ // Least significant byte only is copied
+ *Buffer = WData & 0xff;
+ Buffer++;
+ Len--;
+ }
+
+ }
+
+ //Negate the chip select (CS) to end the SROM command
+
+ DC21X4_WRITE_PORT(
+ DC21X4_IDPROM,
+ CSR_WRITE | SEL_SROM
+ );
+
+ NdisStallExecution(SROM_93LC46B_DELAY);
+
+ }
+
+ *Offset = WOffset << 1;
+ return TRUE;
+
+}
+
diff --git a/private/ntos/ndis/dc21x4/transfer.c b/private/ntos/ndis/dc21x4/transfer.c
new file mode 100644
index 000000000..c45b88712
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/transfer.c
@@ -0,0 +1,82 @@
+/*+
+ * file: transfer.c
+ *
+ * Copyright (C) 1992-1995 by
+ * Digital Equipment Corporation, Maynard, Massachusetts.
+ * All rights reserved.
+ *
+ * This software is furnished under a license and may be used and copied
+ * only in accordance of the terms of such license and with the
+ * inclusion of the above copyright notice. This software or any other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person. No title to and ownership of the software is hereby
+ * transferred.
+ *
+ * The information in this software is subject to change without notice
+ * and should not be construed as a commitment by digital equipment
+ * corporation.
+ *
+ * Digital assumes no responsibility for the use or reliability of its
+ * software on equipment which is not supplied by digital.
+ *
+ *
+ * Abstract: This file is part of the NDIS3.0 miniport driver for DEC's
+ * DC21X4 Ethernet Adapter and implements the MiniportTransferData
+ * API
+ *
+ * Author: Philippe Klein
+ *
+ * Revision History:
+ *
+ * phk 28-Aug-1994 Initial entry
+ *
+-*/
+
+#include <precomp.h>
+
+
+
+/*+
+ *
+ * DC21X4TransferData
+ *
+ * Routine Description:
+ *
+ * The protocol driver calls DC21X4TransferData to instruct
+ * the driver to copy the contents of the received packet into
+ * a specified packet buffer.
+ *
+-*/
+
+extern
+NDIS_STATUS
+DC21X4TransferData(
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+ )
+
+{
+
+ PDC21X4_ADAPTER Adapter;
+
+#if _DBG
+ DbgPrint("DC21X4TransferData\n");
+#endif
+
+ Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
+
+ CopyFromBufferToPacket(
+ (PCHAR)((ULONG)MiniportReceiveContext + ByteOffset),
+ Packet,
+ 0,
+ BytesToTransfer,
+ BytesTransferred
+ );
+
+ return NDIS_STATUS_SUCCESS;
+
+}
diff --git a/private/ntos/ndis/dc21x4/version.h b/private/ntos/ndis/dc21x4/version.h
new file mode 100644
index 000000000..133f3ddeb
--- /dev/null
+++ b/private/ntos/ndis/dc21x4/version.h
@@ -0,0 +1,7 @@
+// DC21X4 NDIS4.0 miniport driver version
+
+#define DRIVER_VERSION 4,03,00
+#define DRIVER_VERSION_STR "v4.03"
+
+
+
diff --git a/private/ntos/ndis/detect/dirs b/private/ntos/ndis/detect/dirs
new file mode 100644
index 000000000..a33ecad84
--- /dev/null
+++ b/private/ntos/ndis/detect/dirs
@@ -0,0 +1,26 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=dll \
+ driver
+
+OPTIONAL_DIRS=exe
diff --git a/private/ntos/ndis/detect/dll/makefile b/private/ntos/ndis/detect/dll/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/detect/dll/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/detect/dll/netdtect.c b/private/ntos/ndis/detect/dll/netdtect.c
new file mode 100644
index 000000000..daa5d087a
--- /dev/null
+++ b/private/ntos/ndis/detect/dll/netdtect.c
@@ -0,0 +1,1573 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ netdtect.c
+
+Abstract:
+
+ This is the command line interface and execution for the
+ netdtect.exe tester.
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) October 1992
+
+Revision History:
+
+
+--*/
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+
+#include <windows.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ntddnetd.h>
+#include "netdtect.h"
+
+//
+// This is the handle to the driver object.
+//
+HANDLE hFileHandle = (HANDLE)NULL;
+
+
+
+BOOLEAN
+DetectInitialInit(
+ IN PVOID DllHandle,
+ IN ULONG Reason,
+ IN PCONTEXT Context OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine calls CreateFile to open the device driver.
+
+Arguments:
+
+ DllHandle - Not Used
+
+ Reason - Attach or Detach
+
+ Context - Not Used
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+
+ if (Reason == 0) {
+
+ //
+ // This is the close
+ //
+
+ if (hFileHandle != (HANDLE)NULL) {
+
+ CloseHandle( hFileHandle );
+
+ }
+
+ }
+
+ return TRUE;
+}
+
+NTSTATUS
+DetectCheckPortUsage(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG Port,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends off the IOCTL for reading the port.
+
+Arguments:
+
+ InterfaceType - Type of bus (ISA, EISA)
+
+ BusNumber - Bus number in the system.
+
+ Port - Port number to read from.
+
+ Length - Number of ports to check for.
+
+Return Value:
+
+ The status of the call.
+
+--*/
+
+
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ CMD_ARGS CmdArgs;
+ NTSTATUS NtStatus;
+
+ if (hFileHandle == NULL) {
+
+ hFileHandle = CreateFile(
+ DLL_CREATE_DEVICE_NAME,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, // lpSecurityAttirbutes
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+ NULL // lpTemplateFile
+ );
+
+ if ( hFileHandle == (HANDLE)-1 ) {
+ NtStatus = GetLastError();
+ return(NtStatus);
+ }
+
+ }
+
+ //
+ // Set this value
+ //
+
+ CmdArgs.CPU.InterfaceType = InterfaceType;
+ CmdArgs.CPU.Port = Port;
+ CmdArgs.CPU.Length = Length;
+ CmdArgs.CPU.BusNumber = BusNumber;
+
+ NtStatus = NtDeviceIoControlFile(
+ hFileHandle,
+ NULL, // Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock,
+ IOCTL_NETDTECT_CPU,
+ (PVOID)(&CmdArgs),
+ sizeof(CMD_ARGS),
+ NULL,
+ 0
+ );
+
+ return(NtStatus);
+}
+
+NTSTATUS
+DetectReadPortUchar(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG Port,
+ OUT PUCHAR Value
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends off the IOCTL for reading the port.
+
+Arguments:
+
+ InterfaceType - Type of bus (ISA, EISA)
+
+ BusNumber - Bus number in the system.
+
+ Port - Port number to read from.
+
+ Value - Pointer to place the result.
+
+Return Value:
+
+ The status of the call.
+
+--*/
+
+
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ CMD_ARGS CmdArgs;
+ NTSTATUS NtStatus;
+
+ if (hFileHandle == NULL) {
+
+ hFileHandle = CreateFile(
+ DLL_CREATE_DEVICE_NAME,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, // lpSecurityAttirbutes
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+ NULL // lpTemplateFile
+ );
+
+ if ( hFileHandle == (HANDLE)-1 ) {
+ NtStatus = GetLastError();
+ return(NtStatus);
+ }
+
+ }
+
+ //
+ // Set this value
+ //
+
+ CmdArgs.RP.InterfaceType = InterfaceType;
+ CmdArgs.RP.Port = Port;
+ CmdArgs.RP.BusNumber = BusNumber;
+
+ NtStatus = NtDeviceIoControlFile(
+ hFileHandle,
+ NULL, // Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock,
+ IOCTL_NETDTECT_RPC,
+ (PVOID)(&CmdArgs),
+ sizeof(CMD_ARGS),
+ (PVOID)Value,
+ sizeof(UCHAR)
+ );
+
+ return(NtStatus);
+}
+
+
+NTSTATUS
+DetectReadPortUshort(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG Port,
+ OUT PUSHORT Value
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends off the IOCTL for reading the port.
+
+Arguments:
+
+ InterfaceType - Type of bus (ISA, EISA)
+
+ BusNumber - Bus number in the system.
+
+ Port - Port number to read from.
+
+ Value - Pointer to place the result.
+
+Return Value:
+
+ The status of the call.
+
+--*/
+
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ CMD_ARGS CmdArgs;
+ NTSTATUS NtStatus;
+
+ if (hFileHandle == NULL) {
+
+ hFileHandle = CreateFile(
+ DLL_CREATE_DEVICE_NAME,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, // lpSecurityAttirbutes
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+ NULL // lpTemplateFile
+ );
+
+ if ( hFileHandle == (HANDLE)-1 ) {
+ NtStatus = GetLastError();
+ return(NtStatus);
+ }
+
+ }
+
+ //
+ // Set this value
+ //
+
+ CmdArgs.RP.InterfaceType = InterfaceType;
+ CmdArgs.RP.Port = Port;
+ CmdArgs.RP.BusNumber = BusNumber;
+
+ NtStatus = NtDeviceIoControlFile(
+ hFileHandle,
+ NULL, // Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock,
+ IOCTL_NETDTECT_RPS,
+ (PVOID)(&CmdArgs),
+ sizeof(CMD_ARGS),
+ (PVOID)Value,
+ sizeof(USHORT)
+ );
+
+
+ return(NtStatus);
+}
+
+
+
+NTSTATUS
+DetectReadPortUlong(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG Port,
+ OUT PULONG Value
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends off the IOCTL for reading the port.
+
+Arguments:
+
+ InterfaceType - Type of bus (ISA, EISA)
+
+ BusNumber - Bus number in the system.
+
+ Port - Port number to read from.
+
+ Value - Pointer to place the result.
+
+Return Value:
+
+ The status of the call.
+
+--*/
+
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ CMD_ARGS CmdArgs;
+ NTSTATUS NtStatus;
+
+ if (hFileHandle == NULL) {
+
+ hFileHandle = CreateFile(
+ DLL_CREATE_DEVICE_NAME,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, // lpSecurityAttirbutes
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+ NULL // lpTemplateFile
+ );
+
+ if ( hFileHandle == (HANDLE)-1 ) {
+ NtStatus = GetLastError();
+ return(NtStatus);
+ }
+
+ }
+
+ //
+ // Set this value
+ //
+
+ CmdArgs.RP.InterfaceType = InterfaceType;
+ CmdArgs.RP.Port = Port;
+ CmdArgs.RP.BusNumber = BusNumber;
+
+ NtStatus = NtDeviceIoControlFile(
+ hFileHandle,
+ NULL, // Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock,
+ IOCTL_NETDTECT_RPL,
+ (PVOID)(&CmdArgs),
+ sizeof(CMD_ARGS),
+ (PVOID)Value,
+ sizeof(ULONG)
+ );
+
+
+ return(NtStatus);
+}
+
+
+NTSTATUS
+DetectWritePortUchar(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG Port,
+ IN UCHAR Value
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends off the IOCTL for writing the port.
+
+Arguments:
+
+ InterfaceType - Type of bus (ISA, EISA)
+
+ BusNumber - Bus number in the system.
+
+ Port - Port number to write to.
+
+ Value - Value to write to the port.
+
+Return Value:
+
+ The status of the call.
+
+--*/
+
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ CMD_ARGS CmdArgs;
+ NTSTATUS NtStatus;
+
+ if (hFileHandle == NULL) {
+
+ hFileHandle = CreateFile(
+ DLL_CREATE_DEVICE_NAME,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, // lpSecurityAttirbutes
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+ NULL // lpTemplateFile
+ );
+
+ if ( hFileHandle == (HANDLE)-1 ) {
+ NtStatus = GetLastError();
+ return(NtStatus);
+ }
+
+ }
+
+ //
+ // Set this value
+ //
+
+ CmdArgs.WPC.InterfaceType = InterfaceType;
+ CmdArgs.WPC.Port = Port;
+ CmdArgs.WPC.BusNumber = BusNumber;
+ CmdArgs.WPC.Value = Value;
+
+ NtStatus = NtDeviceIoControlFile(
+ hFileHandle,
+ NULL, // Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock,
+ IOCTL_NETDTECT_WPC,
+ (PVOID)(&CmdArgs),
+ sizeof(CMD_ARGS),
+ NULL,
+ 0
+ );
+
+ return(NtStatus);
+}
+
+
+
+NTSTATUS
+DetectWritePortUshort(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG Port,
+ IN USHORT Value
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends off the IOCTL for writing the port.
+
+Arguments:
+
+ InterfaceType - Type of bus (ISA, EISA)
+
+ BusNumber - Bus number in the system.
+
+ Port - Port number to write to.
+
+ Value - Value to write to the port.
+
+Return Value:
+
+ The status of the call.
+
+--*/
+
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ CMD_ARGS CmdArgs;
+ NTSTATUS NtStatus;
+
+ if (hFileHandle == NULL) {
+
+ hFileHandle = CreateFile(
+ DLL_CREATE_DEVICE_NAME,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, // lpSecurityAttirbutes
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+ NULL // lpTemplateFile
+ );
+
+ if ( hFileHandle == (HANDLE)-1 ) {
+ NtStatus = GetLastError();
+ return(NtStatus);
+ }
+
+ }
+
+ //
+ // Set this value
+ //
+
+ CmdArgs.WPS.InterfaceType = InterfaceType;
+ CmdArgs.WPS.Port = Port;
+ CmdArgs.WPS.BusNumber = BusNumber;
+ CmdArgs.WPS.Value = Value;
+
+ NtStatus = NtDeviceIoControlFile(
+ hFileHandle,
+ NULL, // Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock,
+ IOCTL_NETDTECT_WPS,
+ (PVOID)(&CmdArgs),
+ sizeof(CMD_ARGS),
+ NULL,
+ 0
+ );
+
+ return(NtStatus);
+}
+
+
+NTSTATUS
+DetectWritePortUlong(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG Port,
+ IN ULONG Value
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends off the IOCTL for writing the port.
+
+Arguments:
+
+ InterfaceType - Type of bus (ISA, EISA)
+
+ BusNumber - Bus number in the system.
+
+ Port - Port number to write to.
+
+ Value - Value to write to the port.
+
+Return Value:
+
+ The status of the call.
+
+--*/
+
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ CMD_ARGS CmdArgs;
+ NTSTATUS NtStatus;
+
+ if (hFileHandle == NULL) {
+
+ hFileHandle = CreateFile(
+ DLL_CREATE_DEVICE_NAME,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, // lpSecurityAttirbutes
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+ NULL // lpTemplateFile
+ );
+
+ if ( hFileHandle == (HANDLE)-1 ) {
+ NtStatus = GetLastError();
+ return(NtStatus);
+ }
+
+ }
+
+ //
+ // Set this value
+ //
+
+ CmdArgs.WPL.InterfaceType = InterfaceType;
+ CmdArgs.WPL.Port = Port;
+ CmdArgs.WPL.BusNumber = BusNumber;
+ CmdArgs.WPL.Value = Value;
+
+ NtStatus = NtDeviceIoControlFile(
+ hFileHandle,
+ NULL, // Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock,
+ IOCTL_NETDTECT_WPL,
+ (PVOID)(&CmdArgs),
+ sizeof(CMD_ARGS),
+ NULL,
+ 0
+ );
+
+ return(NtStatus);
+}
+
+
+NTSTATUS
+DetectCheckMemoryUsage(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG BaseAddress,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends off the IOCTL for reading the port.
+
+Arguments:
+
+ InterfaceType - Type of bus (ISA, EISA)
+
+ BusNumber - Bus number in the system.
+
+ BaseAddress - Hardware address to play with.
+
+ Length - Number of ports to check for.
+
+Return Value:
+
+ The status of the call.
+
+--*/
+
+
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ CMD_ARGS CmdArgs;
+ NTSTATUS NtStatus;
+
+ if (hFileHandle == NULL) {
+
+ hFileHandle = CreateFile(
+ DLL_CREATE_DEVICE_NAME,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, // lpSecurityAttirbutes
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+ NULL // lpTemplateFile
+ );
+
+ if ( hFileHandle == (HANDLE)-1 ) {
+ NtStatus = GetLastError();
+ return(NtStatus);
+ }
+
+ }
+
+ //
+ // Set this value
+ //
+
+ CmdArgs.CMU.InterfaceType = InterfaceType;
+ CmdArgs.CMU.BaseAddress = BaseAddress;
+ CmdArgs.CMU.Length = Length;
+ CmdArgs.CMU.BusNumber = BusNumber;
+
+ NtStatus = NtDeviceIoControlFile(
+ hFileHandle,
+ NULL, // Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock,
+ IOCTL_NETDTECT_CMU,
+ (PVOID)(&CmdArgs),
+ sizeof(CMD_ARGS),
+ NULL,
+ 0
+ );
+
+ return(NtStatus);
+}
+
+
+NTSTATUS
+DetectReadMappedMemory(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG BaseAddress,
+ IN ULONG Length,
+ OUT PVOID Data
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends off the IOCTL for reading from memory.
+
+Arguments:
+
+ InterfaceType - Type of bus (ISA, EISA)
+
+ BusNumber - Bus number in the system.
+
+ BaseAddress - Memory address to read from.
+
+ Length - Number of bytes to read.
+
+ Data - Pointer to data buffer at least Length bytes long to store
+ the data into.
+
+Return Value:
+
+ The status of the call.
+
+--*/
+
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ CMD_ARGS CmdArgs;
+ NTSTATUS NtStatus;
+
+ if (hFileHandle == NULL) {
+
+ hFileHandle = CreateFile(
+ DLL_CREATE_DEVICE_NAME,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, // lpSecurityAttirbutes
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+ NULL // lpTemplateFile
+ );
+
+ if ( hFileHandle == (HANDLE)-1 ) {
+ NtStatus = GetLastError();
+ return(NtStatus);
+ }
+
+ }
+
+ //
+ // Set this value
+ //
+
+ CmdArgs.MEM.InterfaceType = InterfaceType;
+ CmdArgs.MEM.BusNumber = BusNumber;
+ CmdArgs.MEM.Address = BaseAddress;
+ CmdArgs.MEM.Length = Length;
+
+
+ NtStatus = NtDeviceIoControlFile(
+ hFileHandle,
+ NULL, // Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock,
+ IOCTL_NETDTECT_RM,
+ (PVOID)(&CmdArgs),
+ sizeof(CMD_ARGS),
+ Data,
+ Length
+ );
+
+ return(NtStatus);
+}
+
+
+NTSTATUS
+DetectWriteMappedMemory(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG BaseAddress,
+ IN ULONG Length,
+ IN PVOID Data
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends off the IOCTL for writing to memory.
+
+Arguments:
+
+ InterfaceType - Type of bus (ISA, EISA)
+
+ BusNumber - Bus number in the system.
+
+ BaseAddress - Memory address to write to.
+
+ Length - Number of bytes to write.
+
+ Data - Pointer to data buffer at least Length bytes long containing
+ the bytes to write to memory.
+
+Return Value:
+
+ The status of the call.
+
+--*/
+
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ CMD_ARGS CmdArgs;
+ NTSTATUS NtStatus;
+
+ if (hFileHandle == NULL) {
+
+ hFileHandle = CreateFile(
+ DLL_CREATE_DEVICE_NAME,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, // lpSecurityAttirbutes
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+ NULL // lpTemplateFile
+ );
+
+ if ( hFileHandle == (HANDLE)-1 ) {
+ NtStatus = GetLastError();
+ return(NtStatus);
+ }
+
+ }
+
+ //
+ // Set this value
+ //
+
+ CmdArgs.MEM.InterfaceType = InterfaceType;
+ CmdArgs.MEM.BusNumber = BusNumber;
+ CmdArgs.MEM.Address = BaseAddress;
+ CmdArgs.MEM.Length = Length;
+
+
+ NtStatus = NtDeviceIoControlFile(
+ hFileHandle,
+ NULL, // Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock,
+ IOCTL_NETDTECT_WM,
+ (PVOID)(&CmdArgs),
+ sizeof(CMD_ARGS),
+ Data,
+ Length
+ );
+
+ return(NtStatus);
+}
+
+
+NTSTATUS
+DetectSetInterruptTrap(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ OUT PHANDLE TrapHandle,
+ IN UCHAR InterruptList[],
+ IN ULONG InterruptListLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends off the IOCTL for claiming a range of interrupts.
+
+Arguments:
+
+ InterfaceType - Type of bus (ISA, EISA)
+
+ BusNumber - Bus number in the system.
+
+ TrapHandle - A pointer to a handle for storing a handle for this
+ interrupt trap.
+
+ InterruptList - A pointer to a list of interrupt numbers to try and
+ trap.
+
+ InterruptListLength - Number of numbers in InterruptList.
+
+Return Value:
+
+ The status of the call.
+
+--*/
+
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ CMD_ARGS CmdArgs;
+ NTSTATUS NtStatus;
+
+ if (hFileHandle == NULL) {
+
+ hFileHandle = CreateFile(
+ DLL_CREATE_DEVICE_NAME,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, // lpSecurityAttirbutes
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+ NULL // lpTemplateFile
+ );
+
+ if ( hFileHandle == (HANDLE)-1 ) {
+ NtStatus = GetLastError();
+ return(NtStatus);
+ }
+
+ }
+
+ //
+ // Set this value
+ //
+
+ CmdArgs.SIT.TrapHandle = NULL;
+ CmdArgs.SIT.InterruptListLength = InterruptListLength;
+ CmdArgs.SIT.InterfaceType = InterfaceType;
+ CmdArgs.SIT.BusNumber = BusNumber;
+
+
+ NtStatus = NtDeviceIoControlFile(
+ hFileHandle,
+ NULL, // Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock,
+ IOCTL_NETDTECT_SIT,
+ (PVOID)(&CmdArgs),
+ sizeof(CMD_ARGS),
+ (PVOID)InterruptList,
+ InterruptListLength
+ );
+
+ if (NtStatus == STATUS_SUCCESS) {
+
+ *TrapHandle = CmdArgs.SIT.TrapHandle;
+
+ } else {
+
+ *TrapHandle = (HANDLE)NULL;
+
+ }
+
+ return(NtStatus);
+}
+
+
+NTSTATUS
+DetectQueryInterruptTrap(
+ IN HANDLE TrapHandle,
+ OUT UCHAR InterruptList[],
+ IN ULONG InterruptListLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends off the IOCTL for querying a previously set up
+ interrupt trap.
+
+Arguments:
+
+ TrapHandle - The handle from a SetInterruptTrap call.
+
+ InterruptList - A pointer to an array for storing the results of the
+ query. The first index corresponds to the first index of the
+ SetInterruptTrap call, etc.
+
+ InterruptListLength - Number of spaces in InterruptList, this must be
+ at least as long as the list passed to SetInterruptTrap.
+
+Return Value:
+
+ The status of the call.
+
+--*/
+
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ CMD_ARGS CmdArgs;
+ NTSTATUS NtStatus;
+
+ if (hFileHandle == NULL) {
+
+ hFileHandle = CreateFile(
+ DLL_CREATE_DEVICE_NAME,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, // lpSecurityAttirbutes
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+ NULL // lpTemplateFile
+ );
+
+ if ( hFileHandle == (HANDLE)-1 ) {
+ NtStatus = GetLastError();
+ return(NtStatus);
+ }
+
+ }
+
+ if (TrapHandle == NULL) {
+ return(STATUS_INVALID_HANDLE);
+ }
+
+ //
+ // Set this value
+ //
+
+ CmdArgs.QIT.TrapHandle = TrapHandle;
+
+ NtStatus = NtDeviceIoControlFile(
+ hFileHandle,
+ NULL, // Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock,
+ IOCTL_NETDTECT_QIT,
+ (PVOID)(&CmdArgs),
+ sizeof(CMD_ARGS),
+ (PVOID)InterruptList,
+ InterruptListLength
+ );
+
+ return(NtStatus);
+}
+
+
+NTSTATUS
+DetectRemoveInterruptTrap(
+ IN HANDLE TrapHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends off the IOCTL for removing a previously set up
+ interrupt trap.
+
+Arguments:
+
+ TrapHandle - The handle from a SetInterruptTrap call.
+
+Return Value:
+
+ The status of the call.
+
+--*/
+
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ CMD_ARGS CmdArgs;
+ NTSTATUS NtStatus;
+
+ if (hFileHandle == NULL) {
+
+ hFileHandle = CreateFile(
+ DLL_CREATE_DEVICE_NAME,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, // lpSecurityAttirbutes
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+ NULL // lpTemplateFile
+ );
+
+ if ( hFileHandle == (HANDLE)-1 ) {
+ NtStatus = GetLastError();
+ return(NtStatus);
+ }
+
+ }
+
+ if (TrapHandle == NULL) {
+ return(STATUS_INVALID_HANDLE);
+ }
+
+ //
+ // Set this value
+ //
+
+ CmdArgs.RIT.TrapHandle = TrapHandle;
+
+ NtStatus = NtDeviceIoControlFile(
+ hFileHandle,
+ NULL, // Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock,
+ IOCTL_NETDTECT_RIT,
+ (PVOID)(&CmdArgs),
+ sizeof(CMD_ARGS),
+ NULL,
+ 0
+ );
+ return(NtStatus);
+}
+
+NTSTATUS
+DetectClaimResource(
+ IN ULONG NumberOfResources,
+ IN PVOID Data
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends off the IOCTL for claiming resources.
+
+Arguments:
+
+ NumberOfResources - Number of elements in Data.
+
+ Claim - Should the values be claimed?
+
+ Data - Pointer to data buffer at least Length bytes long containing
+ the bytes to write to memory.
+
+Return Value:
+
+ The status of the call.
+
+--*/
+
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ CMD_ARGS CmdArgs;
+ NTSTATUS NtStatus;
+
+ if (hFileHandle == NULL) {
+
+ hFileHandle = CreateFile(
+ DLL_CREATE_DEVICE_NAME,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, // lpSecurityAttirbutes
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+ NULL // lpTemplateFile
+ );
+
+ if ( hFileHandle == (HANDLE)-1 ) {
+ NtStatus = GetLastError();
+ return(NtStatus);
+ }
+
+ }
+
+ //
+ // Set this value
+ //
+
+ CmdArgs.CR.NumberOfResources = NumberOfResources;
+
+ NtStatus = NtDeviceIoControlFile(
+ hFileHandle,
+ NULL, // Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock,
+ IOCTL_NETDTECT_CR,
+ (PVOID)(&CmdArgs),
+ sizeof(CMD_ARGS),
+ Data,
+ NumberOfResources * sizeof(NETDTECT_RESOURCE)
+ );
+
+ return(NtStatus);
+}
+
+NTSTATUS
+DetectTemporaryClaimResource(
+ IN PNETDTECT_RESOURCE Resource
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends off the IOCTL for temporarily claiming a resource.
+
+Arguments:
+
+ Resource - The resource to claim.
+
+Return Value:
+
+ The status of the call.
+
+--*/
+
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ CMD_ARGS CmdArgs;
+ NTSTATUS NtStatus;
+
+ if (hFileHandle == NULL) {
+
+ hFileHandle = CreateFile(
+ DLL_CREATE_DEVICE_NAME,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, // lpSecurityAttirbutes
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+ NULL // lpTemplateFile
+ );
+
+ if ( hFileHandle == (HANDLE)-1 ) {
+ NtStatus = GetLastError();
+ return(NtStatus);
+ }
+
+ }
+
+ NtStatus = NtDeviceIoControlFile(
+ hFileHandle,
+ NULL, // Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock,
+ IOCTL_NETDTECT_TCR,
+ (PVOID)(&CmdArgs),
+ sizeof(CMD_ARGS),
+ Resource,
+ sizeof(NETDTECT_RESOURCE)
+ );
+
+ return(NtStatus);
+}
+
+NTSTATUS
+DetectFreeSpecificTemporaryResource(
+ IN PNETDTECT_RESOURCE Resource
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends off the IOCTL for temporarily claiming a resource.
+
+Arguments:
+
+ Resource - The resource to claim.
+
+Return Value:
+
+ The status of the call.
+
+--*/
+
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ CMD_ARGS CmdArgs;
+ NTSTATUS NtStatus;
+
+ if (hFileHandle == NULL)
+ {
+ hFileHandle = CreateFile(
+ DLL_CREATE_DEVICE_NAME,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+ NULL);
+ if ( hFileHandle == (HANDLE)-1 )
+ {
+ NtStatus = GetLastError();
+ return(NtStatus);
+ }
+ }
+
+ NtStatus = NtDeviceIoControlFile(
+ hFileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ IOCTL_NETDTECT_FTSR,
+ (PVOID)(&CmdArgs),
+ sizeof(CMD_ARGS),
+ Resource,
+ sizeof(NETDTECT_RESOURCE));
+
+ return(NtStatus);
+}
+
+
+NTSTATUS
+DetectFreeTemporaryResources(
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends off the IOCTL for freeing all temporarily claimed resources.
+
+Arguments:
+
+ NONE
+
+Return Value:
+
+ The status of the call.
+
+--*/
+
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ CMD_ARGS CmdArgs;
+ NTSTATUS NtStatus;
+
+ if (hFileHandle == NULL) {
+
+ hFileHandle = CreateFile(
+ DLL_CREATE_DEVICE_NAME,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, // lpSecurityAttirbutes
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+ NULL // lpTemplateFile
+ );
+
+ if ( hFileHandle == (HANDLE)-1 ) {
+ NtStatus = GetLastError();
+ return(NtStatus);
+ }
+
+ }
+
+ NtStatus = NtDeviceIoControlFile(
+ hFileHandle,
+ NULL, // Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock,
+ IOCTL_NETDTECT_FTR,
+ (PVOID)(&CmdArgs),
+ sizeof(CMD_ARGS),
+ NULL,
+ 0
+ );
+
+ return(NtStatus);
+}
+
+
+
+NTSTATUS
+DetectReadPciSlotInformation(
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN ULONG Length,
+ OUT PVOID Data
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends off the IOCTL for reading from PCI config space.
+
+Arguments:
+
+ BusNumber - Bus number in the system.
+
+ SlotNumber - The slot number to read from.
+
+ Offset - The offset within config space to read from.
+
+ Length - Number of bytes to read.
+
+ Data - Pointer to data buffer at least Length bytes long to store
+ the data into.
+
+Return Value:
+
+ The status of the call.
+
+--*/
+
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ CMD_ARGS CmdArgs;
+ NTSTATUS NtStatus;
+
+ if (hFileHandle == NULL) {
+
+ hFileHandle = CreateFile(
+ DLL_CREATE_DEVICE_NAME,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, // lpSecurityAttirbutes
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+ NULL // lpTemplateFile
+ );
+
+ if ( hFileHandle == (HANDLE)-1 ) {
+ NtStatus = GetLastError();
+ return(NtStatus);
+ }
+
+ }
+
+ //
+ // Set this value
+ //
+
+ CmdArgs.PCI.SlotNumber = SlotNumber;
+ CmdArgs.PCI.BusNumber = BusNumber;
+ CmdArgs.PCI.Offset = Offset;
+ CmdArgs.PCI.Length = Length;
+
+
+ NtStatus = NtDeviceIoControlFile(
+ hFileHandle,
+ NULL, // Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock,
+ IOCTL_NETDTECT_RPCI,
+ (PVOID)(&CmdArgs),
+ sizeof(CMD_ARGS),
+ Data,
+ Length
+ );
+
+ return(NtStatus);
+}
+
+
+NTSTATUS
+DetectWritePciSlotInformation(
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN ULONG Length,
+ IN PVOID Data
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends off the IOCTL for writing to PCI config space.
+
+Arguments:
+
+ BusNumber - Bus number in the system.
+
+ SlotNumber - The slot number to write to.
+
+ Offset - The offset within config space to write to.
+
+ Length - Number of bytes to write.
+
+ Data - Pointer to data buffer at least Length bytes long containing
+ the bytes to write to memory.
+
+Return Value:
+
+ The status of the call.
+
+--*/
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ CMD_ARGS CmdArgs;
+ NTSTATUS NtStatus;
+
+ if (hFileHandle == NULL) {
+
+ hFileHandle = CreateFile(
+ DLL_CREATE_DEVICE_NAME,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, // lpSecurityAttirbutes
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+ NULL // lpTemplateFile
+ );
+
+ if ( hFileHandle == (HANDLE)-1 ) {
+ NtStatus = GetLastError();
+ return(NtStatus);
+ }
+
+ }
+
+ //
+ // Set this value
+ //
+
+ CmdArgs.PCI.SlotNumber = SlotNumber;
+ CmdArgs.PCI.BusNumber = BusNumber;
+ CmdArgs.PCI.Offset = Offset;
+ CmdArgs.PCI.Length = Length;
+
+
+ NtStatus = NtDeviceIoControlFile(
+ hFileHandle,
+ NULL, // Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock,
+ IOCTL_NETDTECT_WPCI,
+ (PVOID)(&CmdArgs),
+ sizeof(CMD_ARGS),
+ Data,
+ Length
+ );
+
+ return(NtStatus);
+}
+
+
diff --git a/private/ntos/ndis/detect/dll/netdtect.def b/private/ntos/ndis/detect/dll/netdtect.def
new file mode 100644
index 000000000..3af8f03a2
--- /dev/null
+++ b/private/ntos/ndis/detect/dll/netdtect.def
@@ -0,0 +1,25 @@
+LIBRARY netdtect
+
+DESCRIPTION 'Net Card Detection Support'
+
+EXPORTS
+ DetectInitialInit
+ DetectCheckPortUsage
+ DetectCheckMemoryUsage
+ DetectReadPortUchar
+ DetectReadPortUshort
+ DetectReadPortUlong
+ DetectWritePortUchar
+ DetectWritePortUshort
+ DetectWritePortUlong
+ DetectReadMappedMemory
+ DetectWriteMappedMemory
+ DetectSetInterruptTrap
+ DetectQueryInterruptTrap
+ DetectRemoveInterruptTrap
+ DetectClaimResource
+ DetectTemporaryClaimResource
+ DetectFreeTemporaryResources
+ DetectReadPciSlotInformation
+ DetectWritePciSlotInformation
+ DetectFreeSpecificTemporaryResource
diff --git a/private/ntos/ndis/detect/dll/netdtect.rc b/private/ntos/ndis/detect/dll/netdtect.rc
new file mode 100644
index 000000000..75ad4636a
--- /dev/null
+++ b/private/ntos/ndis/detect/dll/netdtect.rc
@@ -0,0 +1,39 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DLL
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "Network Card Detection - User Mode APIs"
+#define VER_INTERNALNAME_STR "NETDTECT.DLL"
+#define VER_ORIGINALFILENAME_STR "NETDTECT.DLL"
+
+#include "common.ver"
+
diff --git a/private/ntos/ndis/detect/dll/sources b/private/ntos/ndis/detect/dll/sources
new file mode 100644
index 000000000..830eb967f
--- /dev/null
+++ b/private/ntos/ndis/detect/dll/sources
@@ -0,0 +1,54 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+UMLIBS=obj\*\netdtect.lib \nt\public\sdk\lib\*\setargv.obj
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=netdtect
+MINORCOMP=netdtect
+
+TARGETNAME=netdtect
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DYNLINK
+TARGETLIBS=\nt\public\sdk\lib\*\kernel32.lib
+
+
+DLLENTRY=DetectInitialInit
+
+INCLUDES=..\..\wrapper;..\inc;..\..\..\inc
+
+SOURCES=netdtect.c \
+ netdtect.rc
+
+i860_SOURCES=
+
+i386_SOURCES=
+
+MIPS_SOURCES=
+
+RELATIVE_DEPTH=..\..\..
+NTTEST=
+OPTIONAL_NTTEST=
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+
diff --git a/private/ntos/ndis/detect/driver/makefile b/private/ntos/ndis/detect/driver/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/detect/driver/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/detect/driver/netdtect.c b/private/ntos/ndis/detect/driver/netdtect.c
new file mode 100644
index 000000000..6b8ba2204
--- /dev/null
+++ b/private/ntos/ndis/detect/driver/netdtect.c
@@ -0,0 +1,3061 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ netdtect.c
+
+Abstract:
+
+ This file contains all the routines exported for reading/writing ports
+ and memory during the net card detection phase.
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) October 1992.
+
+Environment:
+
+ Kernel Mode Operating Systems : NT
+ Future Operating Systems: DOS6.0
+
+Revision History:
+
+--*/
+
+
+
+#include <ntddk.h>
+#include <ntddnetd.h>
+#include "netdtect.h"
+#include "..\..\..\inc\ndis.h"
+
+
+#if DBG
+
+UCHAR NetDTectDebug = 0; // DEBUG_LOUD;
+
+#endif
+
+
+NTSTATUS
+NetDTectCreateDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN STRING DeviceName
+ );
+
+NTSTATUS
+NetDTectCreateSymbolicLinkObject(
+ VOID
+ );
+
+NTSTATUS
+NetDTectCreate(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NetDTectCleanUp(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NetDTectClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NetDTectControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NetDTectHandleRequest(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+StartPortMapping(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG InitialPort,
+ IN ULONG SizeOfPort,
+ OUT PVOID *InitialPortMapping,
+ OUT PBOOLEAN Mapped
+ );
+
+NTSTATUS
+EndPortMapping(
+ IN PVOID InitialPortMapping,
+ IN ULONG SizeOfPort,
+ IN BOOLEAN Mapped
+ );
+
+NTSTATUS
+StartMemoryMapping(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG Address,
+ IN ULONG Length,
+ OUT PVOID *VirtualAddress,
+ OUT PBOOLEAN Mapped
+ );
+
+NTSTATUS
+EndMemoryMapping(
+ IN PVOID VirtualAddress,
+ IN ULONG Length,
+ IN BOOLEAN Mapped
+ );
+
+
+VOID
+NetDtectCopyFromMappedMemory(
+ OUT PMDL OutputMdl,
+ IN PUCHAR MemoryMapping,
+ IN ULONG Length
+ );
+
+VOID
+NetDtectCopyToMappedMemory(
+ OUT PMDL OutputMdl,
+ IN PUCHAR MemoryMapping,
+ IN ULONG Length
+ );
+
+BOOLEAN
+NetDtectIsr(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID Context
+ );
+
+//
+// Structures for interrupt trapping
+//
+
+typedef struct _INTERRUPT_TRAP {
+
+ BOOLEAN AlreadyInUse;
+ ULONG InterruptCount;
+ PKINTERRUPT InterruptObject;
+
+} INTERRUPT_TRAP, * PINTERRUPT_TRAP;
+
+typedef struct _INTERRUPT_TRAP_LIST {
+
+ ULONG NumberOfInterrupts;
+ INTERRUPT_TRAP InterruptList[1];
+
+} INTERRUPT_TRAP_LIST, * PINTERRUPT_TRAP_LIST;
+
+
+PDRIVER_OBJECT NetDtectDriverObject;
+
+
+//
+// Variable for resource claiming
+//
+
+PNETDTECT_RESOURCE ClaimedResourceList = NULL;
+ULONG NumberOfClaimedResources = 0;
+
+PNETDTECT_RESOURCE TemporaryClaimedResourceList = NULL;
+ULONG NumberOfTemporaryClaimedResources = 0;
+
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs initialization of the driver.
+ It creates the device objects for the driver and performs
+ other driver initialization.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ STRING nameString;
+ NTSTATUS Status;
+
+ //
+ // Store driver object
+ //
+
+ NetDtectDriverObject = DriverObject;
+
+ //
+ // First initialize the struct,
+ //
+
+ RtlInitString( &nameString, DRIVER_DEVICE_NAME );
+
+ Status = NetDTectCreateDevice(
+ DriverObject,
+ nameString
+ );
+
+ if (!NT_SUCCESS (Status)) {
+ DbgPrint ("NETDTECT: failed to create device: %X\n", Status);
+ return Status;
+ }
+
+ //
+ // Create symbolic link between the Dos Device name and Nt
+ // Device name for the driver.
+ //
+
+ Status = NetDTectCreateSymbolicLinkObject( );
+
+ if (!NT_SUCCESS (Status)) {
+ DbgPrint ("NETDTECT: failed to create symbolic link: %X\n", Status);
+ return Status;
+ }
+
+ return Status;
+}
+
+BOOLEAN
+NetDtectCheckPortUsage(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG PortNumber,
+ IN ULONG Length
+)
+/*++
+
+Routine Description:
+
+ This routine checks if a port is currently in use somewhere in the
+ system via IoReportUsage -- which fails if there is a conflict.
+
+Arguments:
+
+ InterfaceType - The bus type (ISA, EISA)
+ BusNumber - Bus number in the system
+ PortNumber - Address of the port to access.
+ Length - Number of ports from the base address to access.
+
+Return Value:
+
+ FALSE if there is a conflict, else TRUE
+
+--*/
+
+{
+ NTSTATUS NtStatus;
+ BOOLEAN Conflict;
+ NTSTATUS FirstNtStatus;
+ BOOLEAN FirstConflict;
+ PCM_RESOURCE_LIST Resources;
+ ULONG i;
+
+ //
+ // Check the resources we've claimed for ourselves
+ //
+ for (i = 0; i < NumberOfClaimedResources; i++)
+ {
+ if ((ClaimedResourceList[i].InterfaceType == InterfaceType) &&
+ (ClaimedResourceList[i].BusNumber == BusNumber) &&
+ (ClaimedResourceList[i].Type == NETDTECT_PORT_RESOURCE))
+ {
+ if (PortNumber < ClaimedResourceList[i].Value)
+ {
+ if ((PortNumber + Length) > ClaimedResourceList[i].Value)
+ {
+ return(FALSE);
+ }
+ }
+ else if (PortNumber == ClaimedResourceList[i].Value)
+ {
+ return(FALSE);
+ }
+ else if (PortNumber < (ClaimedResourceList[i].Value + ClaimedResourceList[i].Length))
+ {
+ return(FALSE);
+ }
+ }
+ }
+
+ for (i = 0; i < NumberOfTemporaryClaimedResources; i++)
+ {
+ if ((TemporaryClaimedResourceList[i].InterfaceType == InterfaceType) &&
+ (TemporaryClaimedResourceList[i].BusNumber == BusNumber) &&
+ (TemporaryClaimedResourceList[i].Type == NETDTECT_PORT_RESOURCE))
+ {
+ if (PortNumber < TemporaryClaimedResourceList[i].Value)
+ {
+ if ((PortNumber + Length) > TemporaryClaimedResourceList[i].Value)
+ {
+ return(FALSE);
+ }
+ }
+ else if (PortNumber == TemporaryClaimedResourceList[i].Value)
+ {
+ return(FALSE);
+ }
+ else if (PortNumber < (TemporaryClaimedResourceList[i].Value +
+ TemporaryClaimedResourceList[i].Length))
+ {
+ return(FALSE);
+ }
+ }
+ }
+
+ //
+ // Allocate space for resources
+ //
+ Resources = (PCM_RESOURCE_LIST)ExAllocatePool(NonPagedPool,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
+ if (Resources == NULL)
+ {
+ //
+ // Error out
+ //
+ return(FALSE);
+ }
+
+ Resources->Count = 1;
+ Resources->List[0].InterfaceType = InterfaceType;
+ Resources->List[0].BusNumber = BusNumber;
+ Resources->List[0].PartialResourceList.Version = 0;
+ Resources->List[0].PartialResourceList.Revision = 0;
+ Resources->List[0].PartialResourceList.Count = 1;
+
+ //
+ // Setup port
+ //
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].Type = CmResourceTypePort;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].ShareDisposition = CmResourceShareDriverExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].Flags =
+ (InterfaceType == Internal)?
+ CM_RESOURCE_PORT_MEMORY :
+ CM_RESOURCE_PORT_IO;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Start.QuadPart =
+ PortNumber;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Length =
+ Length;
+
+ //
+ // Submit Resources
+ //
+
+#if 0
+
+ FirstConflict = FALSE;
+ FirstNtStatus = STATUS_SUCCESS;
+
+#else
+
+ FirstNtStatus = IoReportResourceUsage(
+ NULL,
+ NetDtectDriverObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ NULL,
+ NULL,
+ 0,
+ TRUE,
+ &FirstConflict
+ );
+
+#endif
+
+ //
+ // Now clear it out
+ //
+ Resources->List[0].PartialResourceList.Count = 0;
+
+#if 0
+
+ Conflict = FALSE;
+ NtStatus = STATUS_SUCCESS;
+
+#else
+
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ NetDtectDriverObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ NULL,
+ NULL,
+ 0,
+ TRUE,
+ &Conflict
+ );
+
+#endif
+
+ ExFreePool(Resources);
+
+ //
+ // Check for conflict.
+ //
+
+ if (FirstConflict || (FirstNtStatus != STATUS_SUCCESS)) {
+
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+BOOLEAN
+NetDtectCheckMemoryUsage(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG Address,
+ IN ULONG Length
+)
+/*++
+Routine Description:
+
+ This routine checks if a range of memory is currently in use somewhere
+ in the system via IoReportUsage -- which fails if there is a conflict.
+
+Arguments:
+
+ InterfaceType - The bus type (ISA, EISA)
+ BusNumber - Bus number in the system
+ Address - Starting Address of the memory to access.
+ Length - Length of memory from the base address to access.
+
+Return Value:
+
+ FALSE if there is a conflict, else TRUE
+
+--*/
+{
+ NTSTATUS NtStatus;
+ BOOLEAN Conflict;
+ NTSTATUS FirstNtStatus;
+ BOOLEAN FirstConflict;
+ PCM_RESOURCE_LIST Resources;
+ ULONG i;
+
+ //
+ // Check the resources we've claimed for ourselves
+ //
+
+ for (i = 0; i < NumberOfClaimedResources; i++) {
+
+ if ((ClaimedResourceList[i].InterfaceType == InterfaceType) &&
+ (ClaimedResourceList[i].BusNumber == BusNumber) &&
+ (ClaimedResourceList[i].Type == NETDTECT_MEMORY_RESOURCE)) {
+
+ if (Address < ClaimedResourceList[i].Value) {
+
+ if ((Address + Length) > ClaimedResourceList[i].Value) {
+
+ return(FALSE);
+
+ }
+
+ } else if (Address == ClaimedResourceList[i].Value) {
+
+ return(FALSE);
+
+ } else if (Address < (ClaimedResourceList[i].Value + ClaimedResourceList[i].Length)) {
+
+ return(FALSE);
+
+ }
+
+ }
+
+ }
+
+ for (i = 0; i < NumberOfTemporaryClaimedResources; i++) {
+
+ if ((TemporaryClaimedResourceList[i].InterfaceType == InterfaceType) &&
+ (TemporaryClaimedResourceList[i].BusNumber == BusNumber) &&
+ (TemporaryClaimedResourceList[i].Type == NETDTECT_MEMORY_RESOURCE)) {
+
+ if (Address < TemporaryClaimedResourceList[i].Value) {
+
+ if ((Address + Length) > TemporaryClaimedResourceList[i].Value) {
+
+ return(FALSE);
+
+ }
+
+ } else if (Address == TemporaryClaimedResourceList[i].Value) {
+
+ return(FALSE);
+
+ } else if (Address < (TemporaryClaimedResourceList[i].Value +
+ TemporaryClaimedResourceList[i].Length)) {
+
+ return(FALSE);
+
+ }
+
+ }
+
+ }
+
+ //
+ // Allocate space for resources
+ //
+
+ Resources = (PCM_RESOURCE_LIST)ExAllocatePool(
+ NonPagedPool,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)
+ );
+
+ if (Resources == NULL) {
+
+ //
+ // Error out
+ //
+
+ return(FALSE);
+
+ }
+
+ Resources->Count = 1;
+ Resources->List[0].InterfaceType = InterfaceType;
+ Resources->List[0].BusNumber = BusNumber;
+ Resources->List[0].PartialResourceList.Version = 0;
+ Resources->List[0].PartialResourceList.Revision = 0;
+ Resources->List[0].PartialResourceList.Count = 1;
+
+ //
+ // Setup memory
+ //
+
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].Type =
+ CmResourceTypeMemory;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].ShareDisposition =
+ CmResourceShareDriverExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].Flags =
+ CM_RESOURCE_MEMORY_READ_WRITE;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Memory.Start.QuadPart =
+ Address;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Memory.Length =
+ Length;
+
+
+ //
+ // Submit Resources
+ //
+
+#if 0
+
+ FirstConflict = FALSE;
+ FirstNtStatus = STATUS_SUCCESS;
+
+#else
+
+ FirstNtStatus = IoReportResourceUsage(
+ NULL,
+ NetDtectDriverObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ NULL,
+ NULL,
+ 0,
+ TRUE,
+ &FirstConflict
+ );
+#endif
+
+ //
+ // Now clear it out
+ //
+ Resources->List[0].PartialResourceList.Count = 0;
+
+#if 0
+
+ Conflict = FALSE;
+ NtStatus = STATUS_SUCCESS;
+
+#else
+
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ NetDtectDriverObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ NULL,
+ NULL,
+ 0,
+ TRUE,
+ &Conflict
+ );
+#endif
+
+ ExFreePool(Resources);
+
+ //
+ // Check for conflict.
+ //
+
+ if (FirstConflict || (FirstNtStatus != STATUS_SUCCESS)) {
+
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+BOOLEAN
+NetDtectCheckInterruptUsage(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN UCHAR Irql
+)
+/*++
+
+Routine Description:
+
+ This routine checks if an interrupt is currently in use somewhere in the
+ system via IoReportUsage -- which fails if there is a conflict.
+
+Arguments:
+
+ InterfaceType - The bus type (ISA, EISA)
+ BusNumber - Bus number in the system
+ Irql - Interrupt number to check.
+
+Return Value:
+
+ FALSE if there is a conflict, else TRUE
+
+--*/
+
+{
+ NTSTATUS NtStatus;
+ BOOLEAN Conflict;
+ NTSTATUS FirstNtStatus;
+ BOOLEAN FirstConflict;
+ PCM_RESOURCE_LIST Resources;
+ ULONG i;
+
+ //
+ // Check the resources we've claimed for ourselves
+ //
+
+ for (i = 0; i < NumberOfClaimedResources; i++) {
+
+ if ((ClaimedResourceList[i].InterfaceType == InterfaceType) &&
+ (ClaimedResourceList[i].BusNumber == BusNumber) &&
+ (ClaimedResourceList[i].Type == NETDTECT_IRQ_RESOURCE)) {
+
+ if (Irql == ClaimedResourceList[i].Value) {
+
+ return(FALSE);
+
+ }
+
+ }
+
+ }
+
+ for (i = 0; i < NumberOfTemporaryClaimedResources; i++) {
+
+ if ((TemporaryClaimedResourceList[i].InterfaceType == InterfaceType) &&
+ (TemporaryClaimedResourceList[i].BusNumber == BusNumber) &&
+ (TemporaryClaimedResourceList[i].Type == NETDTECT_IRQ_RESOURCE)) {
+
+ if (Irql == TemporaryClaimedResourceList[i].Value) {
+
+ return(FALSE);
+
+ }
+
+ }
+
+ }
+
+ //
+ // Allocate space for resources
+ //
+
+ Resources = (PCM_RESOURCE_LIST)ExAllocatePool(
+ NonPagedPool,
+ sizeof(CM_RESOURCE_LIST) +
+ (sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * 2)
+ );
+
+ if (Resources == NULL) {
+
+ //
+ // Error out
+ //
+
+ return(FALSE);
+
+ }
+
+ if ((Irql == 2) &&
+ ((InterfaceType == Isa) || (InterfaceType == Eisa))) {
+
+ Resources->Count = 1;
+ Resources->List[0].InterfaceType = InterfaceType;
+ Resources->List[0].BusNumber = BusNumber;
+ Resources->List[0].PartialResourceList.Version = 0;
+ Resources->List[0].PartialResourceList.Revision = 0;
+ Resources->List[0].PartialResourceList.Count = 2;
+
+ //
+ // Setup interrupt
+ //
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].Type = CmResourceTypeInterrupt;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].ShareDisposition = CmResourceShareDriverExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].Flags = CM_RESOURCE_INTERRUPT_LATCHED;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Interrupt.Level =
+ 2;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Interrupt.Vector =
+ 2;
+
+ //
+ // Setup interrupt
+ //
+ Resources->List[0].PartialResourceList.PartialDescriptors[1].Type = CmResourceTypeInterrupt;
+ Resources->List[0].PartialResourceList.PartialDescriptors[1].ShareDisposition = CmResourceShareDriverExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[1].Flags = CM_RESOURCE_INTERRUPT_LATCHED;
+ Resources->List[0].PartialResourceList.PartialDescriptors[1].u.Interrupt.Level =
+ 9;
+ Resources->List[0].PartialResourceList.PartialDescriptors[1].u.Interrupt.Vector =
+ 9;
+
+ } else {
+
+ Resources->Count = 1;
+ Resources->List[0].InterfaceType = InterfaceType;
+ Resources->List[0].BusNumber = BusNumber;
+ Resources->List[0].PartialResourceList.Version = 0;
+ Resources->List[0].PartialResourceList.Revision = 0;
+ Resources->List[0].PartialResourceList.Count = 1;
+
+ //
+ // Setup interrupt
+ //
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].Type = CmResourceTypeInterrupt;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].ShareDisposition = CmResourceShareDriverExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].Flags = CM_RESOURCE_INTERRUPT_LATCHED;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Interrupt.Level =
+ Irql;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Interrupt.Vector =
+ Irql;
+
+ }
+
+ //
+ // Submit Resources
+ //
+
+#if 0
+
+ FirstConflict = FALSE;
+ FirstNtStatus = STATUS_SUCCESS;
+
+#else
+
+ FirstNtStatus = IoReportResourceUsage(
+ NULL,
+ NetDtectDriverObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ NULL,
+ NULL,
+ 0,
+ TRUE,
+ &FirstConflict
+ );
+
+#endif
+
+ //
+ // Now clear it out
+ //
+ Resources->List[0].PartialResourceList.Count = 0;
+
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ NetDtectDriverObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ NULL,
+ NULL,
+ 0,
+ TRUE,
+ &Conflict
+ );
+
+ //
+ // Check for conflict.
+ //
+
+ ExFreePool(Resources);
+
+ if (FirstConflict || (FirstNtStatus != STATUS_SUCCESS)) {
+
+ //
+ // Free memory
+ //
+
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+
+NTSTATUS
+NetDTectCreateDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN STRING DeviceName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates and initializes a device structure.
+
+Arguments:
+
+ DriverObject - pointer to the IO subsystem supplied driver object.
+
+ DeviceName - pointer to the name of the device this device object points to.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INSUFFICIENT_RESOURCES otherwise.
+
+--*/
+
+{
+ NTSTATUS Status;
+ UNICODE_STRING unicodeString;
+ PDEVICE_OBJECT deviceObject;
+
+
+ //
+ // Convert the input name string to Unicode until it is actually
+ // passed as a Unicode string.
+ //
+
+ Status = RtlAnsiStringToUnicodeString(
+ &unicodeString,
+ &DeviceName,
+ TRUE
+ );
+
+ if ( !NT_SUCCESS( Status )) {
+ return Status;
+ }
+
+ //
+ // Create the device object for Test Protocol.
+ //
+
+ Status = IoCreateDevice(
+ DriverObject,
+ 0,
+ &unicodeString,
+ FILE_DEVICE_UNKNOWN, //*\\ Fix this.....
+ 0,
+ FALSE,
+ &deviceObject
+ );
+
+ RtlFreeUnicodeString( &unicodeString );
+
+ if ( !NT_SUCCESS( Status )) {
+ return Status;
+ }
+
+ deviceObject->Flags |= DO_DIRECT_IO;
+
+ //
+ // Initialize the driver object with this driver's entry points.
+ //
+
+ DriverObject->MajorFunction[IRP_MJ_CREATE] = NetDTectCreate;
+ DriverObject->MajorFunction[IRP_MJ_CLOSE] = NetDTectClose;
+ DriverObject->MajorFunction[IRP_MJ_CLEANUP] = NetDTectCleanUp;
+ DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = NetDTectControl;
+
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+NetDTectCreateSymbolicLinkObject(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine creates a symbolic link for DOS names to the Nt name.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INSUFFICIENT_RESOURCES otherwise.
+
+--*/
+
+{
+ NTSTATUS Status;
+ STRING DosString;
+ STRING NtString;
+ UNICODE_STRING DosUnicodeString;
+ UNICODE_STRING NtUnicodeString;
+
+ RtlInitAnsiString( &DosString, DOS_DRIVER_DEVICE_NAME );
+
+ Status = RtlAnsiStringToUnicodeString(
+ &DosUnicodeString,
+ &DosString,
+ TRUE
+ );
+
+ if ( !NT_SUCCESS( Status )) {
+ return Status;
+ }
+
+ RtlInitAnsiString( &NtString, DRIVER_DEVICE_NAME );
+
+ Status = RtlAnsiStringToUnicodeString(
+ &NtUnicodeString,
+ &NtString,
+ TRUE
+ );
+
+ if ( !NT_SUCCESS( Status )) {
+ return Status;
+ }
+
+ Status = IoCreateSymbolicLink(
+ &DosUnicodeString,
+ &NtUnicodeString
+ );
+
+ if ( Status != STATUS_SUCCESS ) {
+ return Status;
+ }
+
+ RtlFreeUnicodeString( &DosUnicodeString );
+ RtlFreeUnicodeString( &NtUnicodeString );
+
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+NetDTectCreate(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the main dispatch routine for the IRP_MJ_CREATE
+ major function.
+
+ The Create function always returns STATUS_SUCCESS since there
+ are no data structures on a per-open basis.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+NetDTectCleanUp(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the main dispatch routine for the IRP_MJ_CLEANUP
+ major function.
+
+ The function always returns STATUS_SUCCESS since there
+ are no data structures on a per-open basis.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+NetDTectClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+
+Routine Description:
+
+ This routine is the main dispatch routine for the IRP_MJ_CLOSE
+ major function.
+
+ The function always returns STATUS_SUCCESS since there
+ are no data structures on a per-open basis.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+
+{
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+ return(STATUS_SUCCESS);
+}
+
+
+NTSTATUS
+NetDTectControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the main dispatch routine for the IRP_MJ_CONTROL
+ major function.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+ PIO_STACK_LOCATION IrpSp;
+
+ //
+ // Make sure status information is consistent every time.
+ //
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+
+ //
+ // Get a pointer to the current stack location in the IRP. This is where
+ // the function codes and parameters are stored.
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ //
+ // Case on the function that is being performed by the requestor. If the
+ // operation is a valid one for this device, then make it look like it was
+ // successfully completed, where possible.
+ //
+
+ if (IrpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
+
+ //
+ // The DeviceControl function is the main path to the
+ // driver interface. Every request is has an Io Control
+ // code that is used by this function to determine the routine to
+ // call.
+ //
+
+ IF_VERY_LOUD( DbgPrint("NetDTectControl: IRP_MJ_DEVICE_CONTROL\n"); )
+
+ NetDTectHandleRequest( DeviceObject, Irp, IrpSp );
+
+ } else {
+
+ //
+ // Error!
+ //
+
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+
+ }
+
+ IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
+
+ return(Irp->IoStatus.Status);
+
+}
+
+
+NTSTATUS
+NetDTectHandleRequest(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the main routine for handling the IRP_MJ_CONTROL
+ IOCTLs.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+ IrpSp - Pointer to the stack location in the Irp.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PVOID InputBuffer;
+ ULONG InputBufferLength;
+ PVOID OutputBuffer;
+ ULONG OutputLength;
+ PCMD_ARGS CmdArgs;
+ ULONG CmdCode;
+ PMDL OutputMdl;
+ PUCHAR BufferAddress;
+ PVOID PortMapping;
+ PVOID MemoryMapping;
+ PINTERRUPT_TRAP_LIST InterruptTrapList;
+ PNETDTECT_RESOURCE Resources;
+ PCM_RESOURCE_LIST ResourceList;
+ NTSTATUS NtStatus;
+ BOOLEAN Mapped;
+ BOOLEAN Conflict;
+ ULONG i, j;
+ PNETDTECT_RESOURCE TmpResourceList;
+ PNETDTECT_RESOURCE ClaimedResource;
+
+ //
+ // Get the Input and Output buffers for the Incoming commands,
+ // and the buffer to return the results in.
+ //
+
+ InputBuffer = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
+ InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+ OutputBuffer = Irp->UserBuffer;
+ OutputLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+ CmdArgs = ((PCMD_ARGS)InputBuffer);
+
+ Irp->IoStatus.Information = 0;
+
+ //
+ // Now switch to the specific command to call.
+ //
+
+ CmdArgs = ((PCMD_ARGS)InputBuffer);
+ CmdCode = IrpSp->Parameters.DeviceIoControl.IoControlCode;
+
+ switch ( CmdCode ) {
+
+ case IOCTL_NETDTECT_RPC:
+
+ //
+ // READ_PORT_UCHAR
+ //
+
+ IF_VERY_LOUD( DbgPrint("NETDETECT: ReadPortUChar\n"); )
+ IF_VERY_LOUD( DbgPrint("\tPort 0x%x\n", CmdArgs->RP.Port); )
+ IF_VERY_LOUD( DbgPrint("\tBus 0x%x\n", CmdArgs->RP.BusNumber); )
+ IF_VERY_LOUD( DbgPrint("\n"); )
+
+ if (OutputLength < sizeof(UCHAR)) {
+ Status = Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ //
+ // SetUp for the port read
+ //
+
+ Status = StartPortMapping(
+ CmdArgs->RP.InterfaceType,
+ CmdArgs->RP.BusNumber,
+ CmdArgs->RP.Port,
+ sizeof(UCHAR),
+ &PortMapping,
+ &Mapped
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ Irp->IoStatus.Status = Status;
+ break;
+
+ }
+
+ //
+ // Read from the port
+ //
+
+ *((PUCHAR)OutputBuffer) = (UCHAR)READ_PORT_UCHAR((PUCHAR)PortMapping);
+
+ IF_VERY_LOUD( DbgPrint("\tRead : 0x%x\n",*((PUCHAR)OutputBuffer)); )
+
+ //
+ // End port mapping
+ //
+
+ EndPortMapping(
+ PortMapping,
+ sizeof(UCHAR),
+ Mapped
+ );
+
+ Status = Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ break;
+
+ case IOCTL_NETDTECT_RPS:
+
+ //
+ // READ_PORT_USHORT
+ //
+
+ IF_VERY_LOUD( DbgPrint("NETDETECT: ReadPortUShort\n"); )
+ IF_VERY_LOUD( DbgPrint("\tPort 0x%x\n", CmdArgs->RP.Port); )
+ IF_VERY_LOUD( DbgPrint("\tBus 0x%x\n", CmdArgs->RP.BusNumber); )
+ IF_VERY_LOUD( DbgPrint("\n"); )
+
+ if (OutputLength < sizeof(USHORT)) {
+ Status = Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ //
+ // Start mapping
+ //
+
+ Status = StartPortMapping(
+ CmdArgs->RP.InterfaceType,
+ CmdArgs->RP.BusNumber,
+ CmdArgs->RP.Port,
+ sizeof(USHORT),
+ &PortMapping,
+ &Mapped
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ Irp->IoStatus.Status = Status;
+ break;
+
+ }
+
+ //
+ // Read from the port
+ //
+
+ *((PUSHORT)OutputBuffer) = (USHORT)READ_PORT_USHORT((PUSHORT)PortMapping);
+
+ IF_VERY_LOUD( DbgPrint("\tRead : 0x%x\n",*((PUSHORT)OutputBuffer)); )
+
+ //
+ // End port mapping
+ //
+
+ EndPortMapping(
+ PortMapping,
+ sizeof(USHORT),
+ Mapped
+ );
+
+ Status = Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ break;
+
+ case IOCTL_NETDTECT_RPL:
+
+ //
+ // READ_PORT_ULONG
+ //
+
+ IF_VERY_LOUD( DbgPrint("NETDETECT: ReadPortULong\n"); )
+ IF_VERY_LOUD( DbgPrint("\tPort 0x%x\n", CmdArgs->RP.Port); )
+ IF_VERY_LOUD( DbgPrint("\tBus 0x%x\n", CmdArgs->RP.BusNumber); )
+ IF_VERY_LOUD( DbgPrint("\n"); )
+
+ if (OutputLength < sizeof(ULONG)) {
+ Status = Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ //
+ // Start mapping
+ //
+
+ Status = StartPortMapping(
+ CmdArgs->RP.InterfaceType,
+ CmdArgs->RP.BusNumber,
+ CmdArgs->RP.Port,
+ sizeof(ULONG),
+ &PortMapping,
+ &Mapped
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ Irp->IoStatus.Status = Status;
+ break;
+
+ }
+
+ //
+ // Read from the port
+ //
+
+ *((PULONG)OutputBuffer) = (ULONG)READ_PORT_ULONG((PULONG)PortMapping);
+
+ IF_VERY_LOUD( DbgPrint("\tRead : 0x%x\n",*((PULONG)OutputBuffer)); )
+
+ //
+ // End port mapping
+ //
+
+ EndPortMapping(
+ PortMapping,
+ sizeof(ULONG),
+ Mapped
+ );
+
+ Status = Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ break;
+
+ case IOCTL_NETDTECT_WPC:
+
+ //
+ // WRITE_PORT_UCHAR
+ //
+
+ IF_VERY_LOUD( DbgPrint("NETDETECT: WritePortUChar\n"); )
+ IF_VERY_LOUD( DbgPrint("\tPort 0x%x\n", CmdArgs->WPC.Port); )
+ IF_VERY_LOUD( DbgPrint("\tBus 0x%x\n", CmdArgs->WPC.BusNumber); )
+ IF_VERY_LOUD( DbgPrint("\tValue 0x%x\n", CmdArgs->WPC.Value); )
+ IF_VERY_LOUD( DbgPrint("\n"); )
+
+ //
+ // Map the space
+ //
+
+ Status = StartPortMapping(
+ CmdArgs->WPC.InterfaceType,
+ CmdArgs->WPC.BusNumber,
+ CmdArgs->WPC.Port,
+ sizeof(UCHAR),
+ &PortMapping,
+ &Mapped
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ Irp->IoStatus.Status = Status;
+ break;
+
+ }
+
+ //
+ // Write to the port
+ //
+
+ WRITE_PORT_UCHAR((PUCHAR)PortMapping, CmdArgs->WPC.Value);
+
+ //
+ // Read from the port
+ //
+
+ // READ_PORT_UCHAR((PUCHAR)PortMapping);
+
+ //
+ // End port mapping
+ //
+
+ EndPortMapping(
+ PortMapping,
+ sizeof(UCHAR),
+ Mapped
+ );
+
+ Status = Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ break;
+
+ case IOCTL_NETDTECT_WPS:
+
+ //
+ // WRITE_PORT_USHORT
+ //
+
+ IF_VERY_LOUD( DbgPrint("NETDETECT: WritePortUShort\n"); )
+ IF_VERY_LOUD( DbgPrint("\tPort 0x%x\n", CmdArgs->WPS.Port); )
+ IF_VERY_LOUD( DbgPrint("\tBus 0x%x\n", CmdArgs->WPS.BusNumber); )
+ IF_VERY_LOUD( DbgPrint("\tValue 0x%x\n", CmdArgs->WPS.Value); )
+ IF_VERY_LOUD( DbgPrint("\n"); )
+
+ //
+ // Map the space
+ //
+
+ Status = StartPortMapping(
+ CmdArgs->WPS.InterfaceType,
+ CmdArgs->WPS.BusNumber,
+ CmdArgs->WPS.Port,
+ sizeof(USHORT),
+ &PortMapping,
+ &Mapped
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ Irp->IoStatus.Status = Status;
+ break;
+
+ }
+
+ //
+ // Write to the port
+ //
+
+ WRITE_PORT_USHORT((PUSHORT)PortMapping, CmdArgs->WPS.Value);
+
+ //
+ // Read from the port
+ //
+
+ // READ_PORT_USHORT((PUSHORT)PortMapping);
+
+ //
+ // End port mapping
+ //
+
+ EndPortMapping(
+ PortMapping,
+ sizeof(USHORT),
+ Mapped
+ );
+
+ Status = Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ break;
+
+ case IOCTL_NETDTECT_WPL:
+
+ //
+ // WRITE_PORT_ULONG
+ //
+
+ IF_VERY_LOUD( DbgPrint("NETDETECT: ReadPortULong\n"); )
+ IF_VERY_LOUD( DbgPrint("\tPort 0x%x\n", CmdArgs->WPL.Port); )
+ IF_VERY_LOUD( DbgPrint("\tBus 0x%x\n", CmdArgs->WPL.BusNumber); )
+ IF_VERY_LOUD( DbgPrint("\tValue 0x%x\n", CmdArgs->WPL.Value); )
+ IF_VERY_LOUD( DbgPrint("\n"); )
+
+ //
+ // Map the space
+ //
+
+ Status = StartPortMapping(
+ CmdArgs->WPL.InterfaceType,
+ CmdArgs->WPL.BusNumber,
+ CmdArgs->WPL.Port,
+ sizeof(ULONG),
+ &PortMapping,
+ &Mapped
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ Irp->IoStatus.Status = Status;
+ break;
+
+ }
+
+ //
+ // Write to the port
+ //
+
+ WRITE_PORT_ULONG((PULONG)PortMapping, CmdArgs->WPL.Value);
+
+ //
+ // Read from the port
+ //
+
+ // READ_PORT_ULONG((PULONG)PortMapping);
+
+ //
+ // End port mapping
+ //
+
+ EndPortMapping(
+ PortMapping,
+ sizeof(ULONG),
+ Mapped
+ );
+
+ Status = Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ break;
+
+ case IOCTL_NETDTECT_RM:
+
+
+ //
+ // READ_MEMORY
+ //
+
+ InputBuffer = Irp->AssociatedIrp.SystemBuffer;
+ InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+ OutputMdl = Irp->MdlAddress;
+ OutputLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+ CmdArgs = (PCMD_ARGS)InputBuffer;
+
+ IF_LOUD( DbgPrint("NETDETECT: ReadMemory\n"); )
+ IF_LOUD( DbgPrint("\tAddress 0x%x\n", CmdArgs->MEM.Address); )
+ IF_LOUD( DbgPrint("\tLength 0x%x\n", CmdArgs->MEM.Length); )
+ IF_LOUD( DbgPrint("\n"); )
+
+ if (OutputLength < CmdArgs->MEM.Length) {
+ Status = Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // SetUp for the memory read
+ //
+
+ StartMemoryMapping(
+ CmdArgs->MEM.InterfaceType,
+ CmdArgs->MEM.BusNumber,
+ CmdArgs->MEM.Address,
+ CmdArgs->MEM.Length,
+ &MemoryMapping,
+ &Mapped
+ );
+
+ //
+ // Read from memory into IRP
+ //
+
+ NetDtectCopyFromMappedMemory(
+ OutputMdl,
+ (PUCHAR)MemoryMapping,
+ CmdArgs->MEM.Length
+ );
+
+ //
+ // End mapping
+ //
+
+ EndMemoryMapping(MemoryMapping, CmdArgs->MEM.Length, Mapped);
+
+ Status = Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ break;
+
+ case IOCTL_NETDTECT_WM:
+
+ //
+ // WRITE_MEMORY
+ //
+
+ InputBuffer = Irp->AssociatedIrp.SystemBuffer;
+ InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+ OutputMdl = Irp->MdlAddress;
+ OutputLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+ CmdArgs = (PCMD_ARGS)InputBuffer;
+
+ IF_LOUD( DbgPrint("NETDETECT: WriteMemory\n"); )
+ IF_LOUD( DbgPrint("\tAddress 0x%x\n", CmdArgs->MEM.Address); )
+ IF_LOUD( DbgPrint("\tLength 0x%x\n", CmdArgs->MEM.Length); )
+ IF_LOUD( DbgPrint("\n"); )
+
+ if (OutputLength < CmdArgs->MEM.Length) {
+ Status = Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // SetUp for the memory write
+ //
+
+ StartMemoryMapping(
+ CmdArgs->MEM.InterfaceType,
+ CmdArgs->MEM.BusNumber,
+ CmdArgs->MEM.Address,
+ CmdArgs->MEM.Length,
+ &MemoryMapping,
+ &Mapped
+ );
+
+ //
+ // Copy from IRP into memory
+ //
+
+ NetDtectCopyToMappedMemory(
+ OutputMdl,
+ (PUCHAR)MemoryMapping,
+ CmdArgs->MEM.Length
+ );
+
+ //
+ // End mapping
+ //
+
+ EndMemoryMapping(MemoryMapping, CmdArgs->MEM.Length, Mapped);
+
+ Status = Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ break;
+
+ case IOCTL_NETDTECT_SIT:
+
+ //
+ // SET_INTERRUPT_TRAP
+ //
+
+ IF_LOUD( DbgPrint("NETDETECT: SetInterruptTrap\n"); )
+ IF_LOUD( DbgPrint("\tHandle 0x%x\n", CmdArgs->SIT.TrapHandle); )
+ IF_LOUD( DbgPrint("\tListLen 0x%x\n", CmdArgs->SIT.InterruptListLength); )
+ IF_LOUD(
+
+ for (i=0; i < CmdArgs->SIT.InterruptListLength; i++) {
+ DbgPrint("\t\tInt : %d\n",*(((PUCHAR)OutputBuffer) + i));
+ }
+
+ )
+
+ IF_LOUD( DbgPrint("\n"); )
+
+
+ if (OutputLength < CmdArgs->SIT.InterruptListLength) {
+
+ Status = Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+
+ }
+
+ //
+ // Allocate space for the structure
+ //
+
+ InterruptTrapList = (PINTERRUPT_TRAP_LIST)ExAllocatePool(
+ NonPagedPool,
+ sizeof(INTERRUPT_TRAP_LIST) +
+ (sizeof(INTERRUPT_TRAP) *
+ CmdArgs->SIT.InterruptListLength)
+ );
+
+ if (InterruptTrapList == NULL) {
+
+ Status = Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+
+ }
+
+ //
+ // Initialize the structure
+ //
+ InterruptTrapList->NumberOfInterrupts = CmdArgs->SIT.InterruptListLength;
+
+ //
+ // Connect to each interrupt in turn
+ //
+ for (i=0; i < CmdArgs->SIT.InterruptListLength; i++) {
+
+ UCHAR InterruptNumber;
+ ULONG Vector;
+ KIRQL Irql;
+ KAFFINITY InterruptAffinity;
+
+ InterruptNumber = *(((PUCHAR)OutputBuffer) + i);
+
+ InterruptTrapList->InterruptList[i].InterruptCount = 0;
+ InterruptTrapList->InterruptList[i].AlreadyInUse = FALSE;
+ InterruptTrapList->InterruptList[i].InterruptObject = NULL;
+
+ if (NetDtectCheckInterruptUsage(
+ CmdArgs->SIT.InterfaceType,
+ CmdArgs->SIT.BusNumber,
+ InterruptNumber
+ )) {
+
+ //
+ // Get the system interrupt vector and IRQL.
+ //
+
+ Vector = HalGetInterruptVector(
+ CmdArgs->SIT.InterfaceType, // InterfaceType
+ CmdArgs->SIT.BusNumber, // BusNumber
+ (ULONG)InterruptNumber, // BusInterruptLevel
+ (ULONG)InterruptNumber, // BusInterruptVector
+ &Irql, // Irql
+ &InterruptAffinity
+ );
+
+ Status = IoConnectInterrupt(
+ &(InterruptTrapList->InterruptList[i].InterruptObject),
+ (PKSERVICE_ROUTINE)NetDtectIsr,
+ &(InterruptTrapList->InterruptList[i]),
+ NULL,
+ Vector,
+ Irql,
+ Irql,
+ (KINTERRUPT_MODE)Latched,
+ FALSE, // Exclusive interrupt
+ InterruptAffinity,
+ FALSE
+ );
+
+ } else {
+
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+ if (!NT_SUCCESS(Status)) {
+
+ IF_VERY_LOUD( DbgPrint("\tIndex is in use %d\n", i); )
+ InterruptTrapList->InterruptList[i].AlreadyInUse = TRUE;
+
+ } else {
+
+ IF_VERY_LOUD( DbgPrint("\tIndex is connected %d\n", i); )
+
+ }
+
+ }
+
+ //
+ // Return handle
+ //
+
+ CmdArgs->SIT.TrapHandle = (PVOID)(InterruptTrapList);
+
+ IF_VERY_LOUD( DbgPrint("\n"); )
+
+ Status = Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ break;
+
+ case IOCTL_NETDTECT_QIT:
+
+ //
+ // QUERY_INTERRUPT_TRAP
+ //
+
+ IF_LOUD( DbgPrint("NETDETECT: QUERY_INTERRUPT_TRAP\n"); )
+ IF_LOUD( DbgPrint("\tHandle 0x%x\n", CmdArgs->QIT.TrapHandle); )
+ IF_LOUD( DbgPrint("\n"); )
+
+ InterruptTrapList = (PINTERRUPT_TRAP_LIST)(CmdArgs->QIT.TrapHandle);
+
+ if (OutputLength < InterruptTrapList->NumberOfInterrupts) {
+
+ IF_LOUD( DbgPrint("NETDTECT: Not enough memory provided!\n"); )
+
+ Status = Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ break;
+ }
+
+ for (i=0; i < InterruptTrapList->NumberOfInterrupts; i++) {
+
+ if (InterruptTrapList->InterruptList[i].AlreadyInUse) {
+
+ //
+ // In use by another device
+ //
+ *(((PUCHAR)OutputBuffer) + i) = 3;
+
+ IF_VERY_LOUD( DbgPrint("Index %d is in use\n", i); )
+
+ } else if (InterruptTrapList->InterruptList[i].InterruptCount > 1) {
+
+ IF_VERY_LOUD( DbgPrint("Index %d had many interrupts\n", i); )
+
+ InterruptTrapList->InterruptList[i].InterruptCount = 0;
+ *(((PUCHAR)OutputBuffer) + i) = 2;
+
+ } else if (InterruptTrapList->InterruptList[i].InterruptCount == 1) {
+
+ IF_VERY_LOUD( DbgPrint("Index %d had 1 interrupt\n", i); )
+
+ InterruptTrapList->InterruptList[i].InterruptCount = 0;
+ *(((PUCHAR)OutputBuffer) + i) = 1;
+
+ } else {
+
+ IF_VERY_LOUD( DbgPrint("Index %d had no activity\n", i); )
+
+ *(((PUCHAR)OutputBuffer) + i) = 0;
+
+ }
+
+ }
+
+ Status = Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IF_VERY_LOUD( DbgPrint("\n", i); )
+
+ break;
+
+ case IOCTL_NETDTECT_RIT:
+
+ //
+ // REMOVE_INTERRUPT_TRAP
+ //
+
+ IF_LOUD( DbgPrint("NETDETECT: RemoveInterruptTrap\n"); )
+ IF_LOUD( DbgPrint("\tHandle 0x%x\n", CmdArgs->RIT.TrapHandle); )
+ IF_LOUD( DbgPrint("\n"); )
+
+ InterruptTrapList = (PINTERRUPT_TRAP_LIST)(CmdArgs->RIT.TrapHandle);
+
+ //
+ // Disconnect the interrupts
+ //
+
+ for (i=0; i < InterruptTrapList->NumberOfInterrupts; i++) {
+
+ if (!(InterruptTrapList->InterruptList[i].AlreadyInUse)) {
+ IF_VERY_LOUD( DbgPrint("\tDisconnecting index %d\n", i); )
+ IoDisconnectInterrupt(
+ InterruptTrapList->InterruptList[i].InterruptObject
+ );
+
+ }
+ }
+
+ //
+ // Free up the memory
+ //
+
+ ExFreePool(InterruptTrapList);
+
+ IF_VERY_LOUD( DbgPrint("\n"); )
+
+ Status = Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ break;
+
+ case IOCTL_NETDTECT_CPU:
+
+ //
+ // CHECK_PORT_USAGE
+ //
+
+ IF_VERY_LOUD( DbgPrint("NETDETECT: CheckPortUsage\n"); )
+ IF_VERY_LOUD( DbgPrint("\tPort 0x%x\n", CmdArgs->CPU.Port); )
+ IF_VERY_LOUD( DbgPrint("\tBus 0x%x\n", CmdArgs->CPU.BusNumber); )
+ IF_VERY_LOUD( DbgPrint("\tLength 0x%x\n", CmdArgs->CPU.Length); )
+ IF_VERY_LOUD( DbgPrint("\n"); )
+
+ if (NetDtectCheckPortUsage(
+ CmdArgs->CPU.InterfaceType,
+ CmdArgs->CPU.BusNumber,
+ CmdArgs->CPU.Port,
+ CmdArgs->CPU.Length)) {
+
+ Status = Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ } else {
+
+ Status = Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+
+ }
+
+ break;
+
+ case IOCTL_NETDTECT_CMU:
+
+ //
+ // CHECK_MEMORY_USAGE
+ //
+
+ IF_LOUD( DbgPrint("NETDETECT: CheckMemoryUsage\n"); )
+ IF_LOUD( DbgPrint("\tMemory 0x%x\n", CmdArgs->CMU.BaseAddress); )
+ IF_LOUD( DbgPrint("\tBus 0x%x\n", CmdArgs->CMU.BusNumber); )
+ IF_LOUD( DbgPrint("\tLength 0x%x\n", CmdArgs->CMU.Length); )
+ IF_LOUD( DbgPrint("\n"); )
+
+ if (NetDtectCheckMemoryUsage(
+ CmdArgs->CMU.InterfaceType,
+ CmdArgs->CMU.BusNumber,
+ CmdArgs->CMU.BaseAddress,
+ CmdArgs->CMU.Length)) {
+
+ Status = Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ } else {
+
+ Status = Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+
+ }
+
+ break;
+
+ case IOCTL_NETDTECT_CR:
+
+ //
+ // CLAIM_RESOURCE
+ //
+ InputBuffer = Irp->AssociatedIrp.SystemBuffer;
+ InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+ OutputMdl = Irp->MdlAddress;
+ OutputLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+ CmdArgs = (PCMD_ARGS)InputBuffer;
+
+ IF_LOUD( DbgPrint("NETDETECT: ClaimResource\n"); )
+ IF_LOUD( DbgPrint("\tNumber 0x%x\n", CmdArgs->CR.NumberOfResources); )
+ IF_LOUD( DbgPrint("\n"); )
+
+ //
+ // Get resource list
+ //
+
+ Resources = (PNETDTECT_RESOURCE)MmGetSystemAddressForMdl(OutputMdl);
+
+ if (MmGetMdlByteCount(OutputMdl) <
+ (CmdArgs->CR.NumberOfResources * sizeof(NETDTECT_RESOURCE))) {
+
+ Status = Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+
+ }
+
+ //
+ // Vefify that there is no conflict with the TemporaryClaimedList
+ //
+ ClaimedResource = Resources;
+
+ for (j = 0; j < CmdArgs->CR.NumberOfResources; j++, ClaimedResource++)
+ {
+ for (i = 0; i < NumberOfTemporaryClaimedResources; i++)
+ {
+ if ((TemporaryClaimedResourceList[i].InterfaceType == ClaimedResource->InterfaceType) &&
+ (TemporaryClaimedResourceList[i].BusNumber == ClaimedResource->BusNumber) &&
+ (TemporaryClaimedResourceList[i].Type == ClaimedResource->Type))
+ {
+ if (ClaimedResource->Value < TemporaryClaimedResourceList[i].Value)
+ {
+ if ((ClaimedResource->Value + ClaimedResource->Length) >
+ TemporaryClaimedResourceList[i].Value)
+ {
+ Status = Irp->IoStatus.Status = STATUS_CONFLICTING_ADDRESSES;
+ break;
+ }
+ }
+ else if (ClaimedResource->Value == TemporaryClaimedResourceList[i].Value)
+ {
+ Status = Irp->IoStatus.Status = STATUS_CONFLICTING_ADDRESSES;
+ break;
+ }
+ else if (ClaimedResource->Value <
+ (TemporaryClaimedResourceList[i].Value +
+ TemporaryClaimedResourceList[i].Length))
+ {
+ Status = Irp->IoStatus.Status = STATUS_CONFLICTING_ADDRESSES;
+ break;
+ }
+ }
+ }
+ }
+
+ //
+ // Allocate buffer for submitting resources
+ //
+ ResourceList = (PCM_RESOURCE_LIST)ExAllocatePool(
+ NonPagedPool,
+ sizeof(CM_RESOURCE_LIST) +
+ (CmdArgs->CR.NumberOfResources *
+ sizeof(CM_FULL_RESOURCE_DESCRIPTOR)));
+
+ if (ResourceList == NULL)
+ {
+ Status = Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ TmpResourceList = (PNETDTECT_RESOURCE)ExAllocatePool(
+ NonPagedPool,
+ CmdArgs->CR.NumberOfResources *
+ sizeof(NETDTECT_RESOURCE));
+
+ if (TmpResourceList == NULL)
+ {
+ Status = Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ ExFreePool(ResourceList);
+ break;
+ }
+
+ //
+ // Copy list into the Io Resource list.
+ //
+ ResourceList->Count = CmdArgs->CR.NumberOfResources;
+
+ for (i = 0; i < ResourceList->Count; i++)
+ {
+ ResourceList->List[i].InterfaceType = Resources->InterfaceType;
+ ResourceList->List[i].BusNumber = Resources->BusNumber;
+ ResourceList->List[i].PartialResourceList.Count = 1;
+ ResourceList->List[i].PartialResourceList.Revision = 0;
+ ResourceList->List[i].PartialResourceList.Version = 0;
+
+ switch (Resources->Type)
+ {
+ case NETDTECT_IRQ_RESOURCE:
+
+ ResourceList->List[i].PartialResourceList.PartialDescriptors[0].Type = CmResourceTypeInterrupt;
+ ResourceList->List[i].PartialResourceList.PartialDescriptors[0].ShareDisposition = CmResourceShareDriverExclusive;
+ ResourceList->List[i].PartialResourceList.PartialDescriptors[0].Flags = (USHORT)(Resources->Flags);
+ ResourceList->List[i].PartialResourceList.PartialDescriptors[0].u.Interrupt.Level = (ULONG)Resources->Value;
+ ResourceList->List[i].PartialResourceList.PartialDescriptors[0].u.Interrupt.Vector = (ULONG)Resources->Value;
+
+ break;
+
+ case NETDTECT_MEMORY_RESOURCE:
+
+ ResourceList->List[i].PartialResourceList.PartialDescriptors[0].Type = CmResourceTypeMemory;
+ ResourceList->List[i].PartialResourceList.PartialDescriptors[0].ShareDisposition = CmResourceShareDriverExclusive;
+ ResourceList->List[i].PartialResourceList.PartialDescriptors[0].Flags = CM_RESOURCE_MEMORY_READ_WRITE;
+ ResourceList->List[i].PartialResourceList.PartialDescriptors[0].u.Memory.Start.QuadPart =
+ Resources->Value;
+ ResourceList->List[i].PartialResourceList.PartialDescriptors[0].u.Memory.Length = Resources->Length;
+
+ break;
+
+ case NETDTECT_PORT_RESOURCE:
+
+ ResourceList->List[i].PartialResourceList.PartialDescriptors[0].Type = CmResourceTypePort;
+ ResourceList->List[i].PartialResourceList.PartialDescriptors[0].ShareDisposition = CmResourceShareDriverExclusive;
+ ResourceList->List[i].PartialResourceList.PartialDescriptors[0].Flags = CM_RESOURCE_PORT_IO;
+ ResourceList->List[i].PartialResourceList.PartialDescriptors[0].u.Port.Start.QuadPart =
+ Resources->Value;
+ ResourceList->List[i].PartialResourceList.PartialDescriptors[0].u.Port.Length = Resources->Length;
+
+ break;
+
+ case NETDTECT_DMA_RESOURCE:
+
+ ResourceList->List[i].PartialResourceList.PartialDescriptors[0].Type = CmResourceTypeDma;
+ ResourceList->List[i].PartialResourceList.PartialDescriptors[0].ShareDisposition = CmResourceShareDriverExclusive;
+ ResourceList->List[i].PartialResourceList.PartialDescriptors[0].u.Dma.Channel = Resources->Value;
+ ResourceList->List[i].PartialResourceList.PartialDescriptors[0].u.Dma.Port = Resources->Length;
+
+ break;
+
+ }
+
+ Resources++;
+
+ }
+
+ //
+ // Submit Resources
+ //
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ NetDtectDriverObject,
+ ResourceList,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ NULL,
+ NULL,
+ 0,
+ FALSE,
+ &Conflict);
+
+ //
+ // Check for conflict.
+ //
+ if (Conflict || (NtStatus != STATUS_SUCCESS))
+ {
+ Status = STATUS_SUCCESS;
+
+ Irp->IoStatus.Status = (Conflict?STATUS_CONFLICTING_ADDRESSES:NtStatus);
+
+ ExFreePool(TmpResourceList);
+ }
+ else
+ {
+ Status = Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ if (ClaimedResourceList != NULL)
+ {
+ ExFreePool(ClaimedResourceList);
+ }
+
+ ClaimedResourceList = TmpResourceList;
+ NumberOfClaimedResources = CmdArgs->CR.NumberOfResources;
+
+ RtlCopyMemory(ClaimedResourceList,
+ InputBuffer,
+ CmdArgs->CR.NumberOfResources *
+ sizeof(NETDTECT_RESOURCE));
+ }
+
+ //
+ // Free buffer
+ //
+ ExFreePool(ResourceList);
+
+ break;
+
+ case IOCTL_NETDTECT_TCR:
+
+ //
+ // TEMP_CLAIM_RESOURCE
+ //
+ InputBuffer = Irp->AssociatedIrp.SystemBuffer;
+ InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+ OutputMdl = Irp->MdlAddress;
+ OutputLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+
+ IF_LOUD( DbgPrint("NETDETECT: TemporaryClaimResource\n"); )
+ IF_LOUD( DbgPrint("\n"); )
+
+ ClaimedResource = (PNETDTECT_RESOURCE)MmGetSystemAddressForMdl(OutputMdl);
+
+ if (MmGetMdlByteCount(OutputMdl) < sizeof(NETDTECT_RESOURCE))
+ {
+ Status = Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ //
+ // Check for conflict with current list.
+ //
+ for (i = 0; i < NumberOfClaimedResources; i++)
+ {
+ if ((ClaimedResourceList[i].InterfaceType == ClaimedResource->InterfaceType) &&
+ (ClaimedResourceList[i].BusNumber == ClaimedResource->BusNumber) &&
+ (ClaimedResourceList[i].Type == ClaimedResource->Type))
+ {
+ if (ClaimedResource->Value < ClaimedResourceList[i].Value)
+ {
+ if ((ClaimedResource->Value + ClaimedResource->Length) >
+ ClaimedResourceList[i].Value)
+ {
+ Status = Irp->IoStatus.Status = STATUS_CONFLICTING_ADDRESSES;
+ break;
+ }
+ }
+ else if (ClaimedResource->Value == ClaimedResourceList[i].Value)
+ {
+ Status = Irp->IoStatus.Status = STATUS_CONFLICTING_ADDRESSES;
+ break;
+ }
+ else if (ClaimedResource->Value <
+ (ClaimedResourceList[i].Value + ClaimedResourceList[i].Length))
+ {
+ Status = Irp->IoStatus.Status = STATUS_CONFLICTING_ADDRESSES;
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < NumberOfTemporaryClaimedResources; i++)
+ {
+ if ((TemporaryClaimedResourceList[i].InterfaceType == ClaimedResource->InterfaceType) &&
+ (TemporaryClaimedResourceList[i].BusNumber == ClaimedResource->BusNumber) &&
+ (TemporaryClaimedResourceList[i].Type == ClaimedResource->Type))
+ {
+ if (ClaimedResource->Value < TemporaryClaimedResourceList[i].Value)
+ {
+ if ((ClaimedResource->Value + ClaimedResource->Length) >
+ TemporaryClaimedResourceList[i].Value)
+ {
+ Status = Irp->IoStatus.Status = STATUS_CONFLICTING_ADDRESSES;
+ break;
+ }
+ }
+ else if (ClaimedResource->Value == TemporaryClaimedResourceList[i].Value)
+ {
+ Status = Irp->IoStatus.Status = STATUS_CONFLICTING_ADDRESSES;
+ break;
+ }
+ else if (ClaimedResource->Value <
+ (TemporaryClaimedResourceList[i].Value +
+ TemporaryClaimedResourceList[i].Length))
+ {
+ Status = Irp->IoStatus.Status = STATUS_CONFLICTING_ADDRESSES;
+ break;
+ }
+ }
+ }
+
+ //
+ // Allocate space for the new list
+ //
+ TmpResourceList = (PNETDTECT_RESOURCE)ExAllocatePool(
+ NonPagedPool,
+ (NumberOfTemporaryClaimedResources + 1) *
+ sizeof(NETDTECT_RESOURCE));
+
+ if (TmpResourceList == NULL)
+ {
+ Status = Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ //
+ // Copy old list into new list
+ //
+ if (TemporaryClaimedResourceList != NULL)
+ {
+ RtlCopyMemory(TmpResourceList,
+ TemporaryClaimedResourceList,
+ NumberOfTemporaryClaimedResources * sizeof(NETDTECT_RESOURCE));
+ }
+
+ RtlCopyMemory(TmpResourceList + NumberOfTemporaryClaimedResources,
+ ClaimedResource,
+ sizeof(NETDTECT_RESOURCE));
+
+ //
+ // Free old list
+ //
+ if (TemporaryClaimedResourceList != NULL)
+ {
+ ExFreePool(TemporaryClaimedResourceList);
+ }
+
+ TemporaryClaimedResourceList = TmpResourceList;
+
+ NumberOfTemporaryClaimedResources++;
+
+ break;
+
+ case IOCTL_NETDTECT_FTSR:
+
+ //
+ // TEMP_FREE_SPECIFIC_RESOURCE
+ //
+ InputBuffer = Irp->AssociatedIrp.SystemBuffer;
+ InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+ OutputMdl = Irp->MdlAddress;
+ OutputLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+
+ IF_LOUD( DbgPrint("NETDETECT: TemporaryFreeSpecificResource\n"); )
+ IF_LOUD( DbgPrint("\n"); )
+
+ ClaimedResource = (PNETDTECT_RESOURCE)MmGetSystemAddressForMdl(OutputMdl);
+
+ if (MmGetMdlByteCount(OutputMdl) < sizeof(NETDTECT_RESOURCE))
+ {
+ Status = Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ //
+ // Are there any temporary resources allocated?
+ //
+ if ((NULL == TemporaryClaimedResourceList) ||
+ (0 == NumberOfTemporaryClaimedResources))
+ {
+ Status = Irp->IoStatus.Status = STATUS_SUCCESS;
+ break;
+ }
+
+ //
+ // Try and find the resource passed to us.
+ //
+ for (i = 0; i < NumberOfTemporaryClaimedResources; i++)
+ {
+ if (RtlEqualMemory(&TemporaryClaimedResourceList[i], ClaimedResource, sizeof(NETDTECT_RESOURCE)))
+ {
+ //
+ // We found the one that we need to skip!
+ //
+ break;
+ }
+ }
+
+ //
+ // did we find our resource?
+ //
+ if (i != NumberOfTemporaryClaimedResources)
+ {
+ UINT c;
+
+ //
+ // We only create a new list if there is more than one
+ // resource left.
+ //
+
+ if (1 == NumberOfTemporaryClaimedResources)
+ {
+ TmpResourceList = NULL;
+ }
+ else
+ {
+ //
+ // Allocate space for the new list
+ //
+ TmpResourceList = ExAllocatePool(
+ NonPagedPool,
+ (NumberOfTemporaryClaimedResources - 1) *
+ sizeof(NETDTECT_RESOURCE));
+ if (TmpResourceList == NULL)
+ {
+ Status = Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ //
+ // copy the resources before the one that we are removing.
+ //
+ for (c = 0; c < i; c++)
+ {
+ RtlCopyMemory(
+ &TmpResourceList[c],
+ &TemporaryClaimedResourceList[c],
+ sizeof(NETDTECT_RESOURCE));
+ }
+
+ //
+ // copy the resources after the one that we are removing.
+ //
+ for (c = i; c < (NumberOfTemporaryClaimedResources - 1); c++)
+ {
+ TmpResourceList[c] = TemporaryClaimedResourceList[c + 1];
+ }
+ }
+
+ ExFreePool(TemporaryClaimedResourceList);
+ TemporaryClaimedResourceList = TmpResourceList;
+ NumberOfTemporaryClaimedResources--;
+ }
+
+ Status = Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ break;
+
+ case IOCTL_NETDTECT_FTR:
+
+ //
+ // FREE_TEMP_RESOURCE
+ //
+
+ InputBuffer = Irp->AssociatedIrp.SystemBuffer;
+ InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+ OutputMdl = Irp->MdlAddress;
+ OutputLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+
+ IF_LOUD( DbgPrint("NETDETECT: FreeTemporaryClaimedResources\n"); )
+ IF_LOUD( DbgPrint("\n"); )
+
+ if (TemporaryClaimedResourceList != NULL) {
+
+ ExFreePool(TemporaryClaimedResourceList);
+ TemporaryClaimedResourceList = NULL;
+ NumberOfTemporaryClaimedResources = 0;
+
+ }
+
+ Status = Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ break;
+
+
+ case IOCTL_NETDTECT_RPCI:
+
+
+ //
+ // READ_PCI_INFORMATION
+ //
+
+ InputBuffer = Irp->AssociatedIrp.SystemBuffer;
+ InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+ OutputMdl = Irp->MdlAddress;
+ OutputLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+ CmdArgs = (PCMD_ARGS)InputBuffer;
+
+ IF_LOUD( DbgPrint("NETDETECT: ReadPciMemory\n"); )
+ IF_LOUD( DbgPrint("\tSlot 0x%x\n", CmdArgs->PCI.SlotNumber); )
+ IF_LOUD( DbgPrint("\tLength 0x%x\n", CmdArgs->PCI.Length); )
+ IF_LOUD( DbgPrint("\tOffset 0x%x\n", CmdArgs->PCI.Offset); )
+ IF_LOUD( DbgPrint("\n"); )
+
+ if (OutputLength < CmdArgs->PCI.Length) {
+ Status = Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ BufferAddress = MmGetSystemAddressForMdl(OutputMdl);
+
+ OutputLength = HalGetBusDataByOffset(
+ PCIConfiguration,
+ CmdArgs->PCI.BusNumber,
+ CmdArgs->PCI.SlotNumber,
+ BufferAddress,
+ CmdArgs->PCI.Offset,
+ CmdArgs->PCI.Length
+ );
+
+ Status = Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ break;
+
+ case IOCTL_NETDTECT_WPCI:
+
+ //
+ // WRITE_PCI_INFORMATION
+ //
+
+ InputBuffer = Irp->AssociatedIrp.SystemBuffer;
+ InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+ OutputMdl = Irp->MdlAddress;
+ OutputLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+ CmdArgs = (PCMD_ARGS)InputBuffer;
+
+ IF_LOUD( DbgPrint("NETDETECT: WritePciMemory\n"); )
+ IF_LOUD( DbgPrint("\tSlot 0x%x\n", CmdArgs->PCI.SlotNumber); )
+ IF_LOUD( DbgPrint("\tLength 0x%x\n", CmdArgs->PCI.Length); )
+ IF_LOUD( DbgPrint("\tOffset 0x%x\n", CmdArgs->PCI.Offset); )
+ IF_LOUD( DbgPrint("\n"); )
+
+ if (OutputLength < CmdArgs->PCI.Length) {
+ Status = Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ BufferAddress = MmGetSystemAddressForMdl(OutputMdl);
+
+ OutputLength = HalSetBusDataByOffset(
+ PCIConfiguration,
+ CmdArgs->PCI.BusNumber,
+ CmdArgs->PCI.SlotNumber,
+ BufferAddress,
+ CmdArgs->PCI.Offset,
+ CmdArgs->PCI.Length
+ );
+
+ Status = Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ break;
+
+ default:
+
+ IF_LOUD( DbgPrint("Invalid Command Entered\n"); )
+
+ Status = Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+
+ break;
+
+ }
+
+ return Status;
+
+}
+
+
+
+NTSTATUS
+StartPortMapping(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG InitialPort,
+ IN ULONG SizeOfPort,
+ OUT PVOID *InitialPortMapping,
+ OUT PBOOLEAN Mapped
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initialize the mapping of a port address into virtual
+ space dependent on the bus number, etc.
+
+Arguments:
+
+ InterfaceType - The bus type (ISA, EISA)
+ BusNumber - Bus number in the system
+ InitialPort - Address of the port to access.
+ SizeOfPort - Number of ports from the base address to access.
+ InitialPortMapping - The virtual address space to use when accessing the
+ port.
+ Mapped - Did an MmMapIoSpace() take place.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ PHYSICAL_ADDRESS PortAddress;
+ PHYSICAL_ADDRESS InitialPortAddress;
+ ULONG addressSpace;
+
+ //
+ // Get the system physical address for this card. The card uses
+ // I/O space, except for "internal" Jazz devices which use
+ // memory space.
+ //
+
+ *Mapped = FALSE;
+
+ addressSpace = (InterfaceType == Internal) ? 0 : 1;
+
+ InitialPortAddress.LowPart = InitialPort;
+
+ InitialPortAddress.HighPart = 0;
+
+ HalTranslateBusAddress(
+ InterfaceType, // InterfaceType
+ BusNumber, // BusNumber
+ InitialPortAddress, // Bus Address
+ &addressSpace, // AddressSpace
+ &PortAddress // Translated address
+ );
+
+ if (addressSpace == 0) {
+
+ //
+ // memory space
+ //
+
+ *InitialPortMapping = MmMapIoSpace(
+ PortAddress,
+ SizeOfPort,
+ FALSE
+ );
+
+ if (*InitialPortMapping == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ *Mapped = TRUE;
+
+ } else {
+
+ //
+ // I/O space
+ //
+
+ *InitialPortMapping = (PVOID)PortAddress.LowPart;
+
+ }
+
+ return(STATUS_SUCCESS);
+
+}
+
+
+NTSTATUS
+EndPortMapping(
+ IN PVOID InitialPortMapping,
+ IN ULONG SizeOfPort,
+ IN BOOLEAN Mapped
+ )
+
+/*++
+
+Routine Description:
+
+ This routine undoes the mapping of a port address into virtual
+ space dependent on the bus number, etc.
+
+Arguments:
+
+ InitialPortMapping - The virtual address space to use when accessing the
+ port.
+ SizeOfPort - Number of ports from the base address to access.
+ Mapped - Do we need to call MmUnmapIoSpace.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+
+ if (Mapped) {
+
+ //
+ // memory space
+ //
+
+ MmUnmapIoSpace(InitialPortMapping, SizeOfPort);
+
+ }
+
+ return(STATUS_SUCCESS);
+
+}
+
+
+NTSTATUS
+StartMemoryMapping(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG Address,
+ IN ULONG Length,
+ OUT PVOID *VirtualAddress,
+ OUT PBOOLEAN Mapped
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initialize the mapping of a memory address into virtual
+ space dependent on the bus number, etc.
+
+Arguments:
+
+ InterfaceType - The bus type (ISA, EISA)
+ BusNumber - Bus number in the system
+ Address - Address to access.
+ Length - Length of space from the base address to access.
+ VirtualAddress - The virtual address space to use when accessing the
+ memory.
+ Mapped - Was MmMapIoSpace used?
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ PHYSICAL_ADDRESS PhysicalAddress;
+ PHYSICAL_ADDRESS VirtualPhysicalAddress;
+ ULONG addressSpace = 0;
+
+
+ PhysicalAddress.LowPart = Address;
+
+ PhysicalAddress.HighPart = 0;
+
+ HalTranslateBusAddress(
+ InterfaceType, // InterfaceType
+ BusNumber, // BusNumber
+ PhysicalAddress, // Bus Address
+ &addressSpace, // AddressSpace
+ &VirtualPhysicalAddress // Translated address
+ );
+
+ if (addressSpace == 0) {
+
+ //
+ // memory space
+ //
+
+ *Mapped = TRUE;
+
+ *VirtualAddress = MmMapIoSpace(VirtualPhysicalAddress, (Length), FALSE);
+
+ } else {
+
+ //
+ // I/O space
+ //
+
+ *Mapped = FALSE;
+
+ *VirtualAddress = (PVOID)(VirtualPhysicalAddress.LowPart);
+
+ }
+
+ if (*VirtualAddress == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ return(STATUS_SUCCESS);
+
+}
+
+
+NTSTATUS
+EndMemoryMapping(
+ IN PVOID VirtualAddress,
+ IN ULONG Length,
+ IN BOOLEAN Mapped
+ )
+
+/*++
+
+Routine Description:
+
+ This routine undoes the mapping of a memory address into virtual
+ space dependent on the bus number, etc.
+
+Arguments:
+
+ VirtualAddress - The virtual address space to use when accessing the
+ memory.
+ Length - Length of space from the base address to access.
+ Mapped - Was memory mapped with MmMapIoSpace?
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+
+ if (Mapped) {
+
+ MmUnmapIoSpace(VirtualAddress, Length);
+
+ }
+
+ return(STATUS_SUCCESS);
+
+}
+
+
+VOID
+NetDtectCopyFromMappedMemory(
+ OUT PMDL OutputMdl,
+ IN PUCHAR MemoryMapping,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine copys from a virtual address into an MDL.
+
+Arguments:
+
+ OutputMdl - Destination MDL
+ MemoryMapping - Address to copy from. It must have been mapped.
+ Length - Length of space from the base address to access.
+
+Return Value:
+
+ none.
+
+--*/
+{
+ ULONG BytesLeft, BytesWanted, BytesNow;
+ PUCHAR BufferAddress;
+ ULONG BufferLength;
+
+ BytesLeft = BytesWanted = Length;
+
+ //
+ // Loop, filling each buffer in the packet until there
+ // are no more buffers or the data has all been copied.
+ //
+
+ while (BytesLeft > 0) {
+
+ BufferAddress = MmGetSystemAddressForMdl(OutputMdl);
+ BufferLength = MmGetMdlByteCount(OutputMdl);
+
+ //
+ // Is this buffer large enough
+ //
+
+ if (BufferLength < BytesLeft) {
+
+ BytesNow = BufferLength;
+
+ } else {
+
+ BytesNow = BytesLeft;
+ }
+
+ //
+ // Copy this buffer
+ //
+
+#ifdef i386
+
+ memcpy(BufferAddress, MemoryMapping, BytesNow);
+
+#else
+#ifdef _M_MRX000
+
+ {
+ PUCHAR _Src = (MemoryMapping);
+ PUCHAR _Dest = (BufferAddress);
+ PUCHAR _End = _Dest + (BytesNow);
+ while (_Dest < _End) {
+ *_Dest++ = *_Src++;
+ }
+ }
+
+#else
+
+ //
+ // Alpha
+ //
+
+ READ_REGISTER_BUFFER_UCHAR(MemoryMapping,BufferAddress,BytesNow);
+
+#endif
+#endif
+
+ MemoryMapping += BytesNow;
+
+ BytesLeft -= BytesNow;
+
+
+ //
+ // Is the transfer done now?
+ //
+
+ if (BytesLeft == 0) {
+
+ break;
+
+ }
+
+ //
+ // Go to next buffer
+ //
+
+ OutputMdl = OutputMdl->Next;
+
+ }
+
+}
+
+
+VOID
+NetDtectCopyToMappedMemory(
+ OUT PMDL OutputMdl,
+ IN PUCHAR MemoryMapping,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine copys to a virtual address from an MDL.
+
+Arguments:
+
+ OutputMdl - Source MDL
+ MemoryMapping - Address to copy to. It must have been mapped.
+ Length - Length of space from the base address to access.
+
+Return Value:
+
+ none.
+
+--*/
+{
+ ULONG BytesLeft, BytesWanted, BytesNow;
+ PUCHAR BufferAddress;
+ ULONG BufferLength;
+
+ BytesLeft = BytesWanted = Length;
+
+ //
+ // Loop, filling each buffer in the packet until there
+ // are no more buffers or the data has all been copied.
+ //
+
+ while (BytesLeft > 0) {
+
+ BufferAddress = MmGetSystemAddressForMdl(OutputMdl);
+ BufferLength = MmGetMdlByteCount(OutputMdl);
+
+ //
+ // Is this buffer large enough
+ //
+
+ if (BufferLength < BytesLeft) {
+
+ BytesNow = BufferLength;
+
+ } else {
+
+ BytesNow = BytesLeft;
+ }
+
+ //
+ // Copy this buffer
+ //
+
+#ifdef i386
+
+ memcpy(MemoryMapping, BufferAddress, BytesNow);
+
+#else
+#ifdef _M_MRX000
+
+ {
+ PUCHAR _Src = (BufferAddress);
+ PUCHAR _Dest = (MemoryMapping);
+ PUCHAR _End = _Dest + (BytesNow);
+ while (_Dest < _End) {
+ *_Dest++ = *_Src++;
+ }
+ }
+
+#else
+
+ //
+ // Alpha
+ //
+
+ WRITE_REGISTER_BUFFER_UCHAR(MemoryMapping,BufferAddress,BytesNow);
+
+#endif
+#endif
+
+ MemoryMapping += BytesNow;
+
+ BytesLeft -= BytesNow;
+
+
+ //
+ // Is the transfer done now?
+ //
+
+ if (BytesLeft == 0) {
+
+ break;
+
+ }
+
+ //
+ // Go to next buffer
+ //
+
+ OutputMdl = OutputMdl->Next;
+
+ }
+
+}
+
+BOOLEAN
+NetDtectIsr(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ Handles ALL interrupts, setting the appropriate flags,
+ depending on the context.
+
+Arguments:
+
+ Interrupt - Interrupt object.
+
+ Context - Really a pointer to the interrupt_trap.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Get adapter from context.
+ //
+
+ PINTERRUPT_TRAP InterruptTrap = (PINTERRUPT_TRAP)(Context);
+
+ UNREFERENCED_PARAMETER(Interrupt);
+
+ //
+ // Increment the interrupt count
+ //
+
+ ASSERT(!(InterruptTrap->AlreadyInUse));
+
+ InterruptTrap->InterruptCount++;
+
+ return FALSE;
+
+}
+
diff --git a/private/ntos/ndis/detect/driver/netdtect.rc b/private/ntos/ndis/detect/driver/netdtect.rc
new file mode 100644
index 000000000..f8930ea23
--- /dev/null
+++ b/private/ntos/ndis/detect/driver/netdtect.rc
@@ -0,0 +1,39 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "Network Card Detection driver"
+#define VER_INTERNALNAME_STR "NETDTECT.SYS"
+#define VER_ORIGINALFILENAME_STR "NETDTECT.SYS"
+
+#include "common.ver"
+
diff --git a/private/ntos/ndis/detect/driver/sources b/private/ntos/ndis/detect/driver/sources
new file mode 100644
index 000000000..bb7f88424
--- /dev/null
+++ b/private/ntos/ndis/detect/driver/sources
@@ -0,0 +1,42 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=netdtect
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=
+
+INCLUDES=..\inc;..\..\..\inc
+
+SOURCES= netdtect.c \
+ netdtect.rc
+
+RELATIVE_DEPTH=..\..\..
+
+MSC_WARNING_LEVEL=/W3 /WX
+
diff --git a/private/ntos/ndis/detect/exe/init.c b/private/ntos/ndis/detect/exe/init.c
new file mode 100644
index 000000000..9f12c6165
--- /dev/null
+++ b/private/ntos/ndis/detect/exe/init.c
@@ -0,0 +1,88 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ init.c
+
+Abstract:
+
+ This is the main routine for testing the driver for the net detection driver
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) October 1992
+
+Revision History:
+
+--*/
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+
+#include <windows.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "netdtect.h"
+
+
+//
+// the MAIN routine
+//
+
+extern
+DWORD
+NetDTectRun(
+ VOID
+ );
+
+
+int _cdecl
+main(
+ IN WORD argc,
+ IN LPSTR argv[]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the control structures, opens the
+ driver, and send it a wakeup ioctl. Once this has completed
+ the user is presented with the test prompt to enter commands.
+
+Arguments:
+
+ IN WORD argc - Supplies the number of parameters
+ IN LPSTR argv[] - Supplies the parameter list.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DWORD Status;
+
+ //
+ // Start the actual tests, this prompts for the commands.
+ //
+
+ Status = NetDTectRun();
+
+ if ( Status != NO_ERROR ) {
+ printf("Exiting with error 0x%x from NetDTectRun\n", Status);
+ ExitProcess((DWORD)Status);
+ }
+
+ ExitProcess((DWORD)NO_ERROR);
+}
+
+
+
diff --git a/private/ntos/ndis/detect/exe/makefile b/private/ntos/ndis/detect/exe/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/detect/exe/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/detect/exe/netdtect.c b/private/ntos/ndis/detect/exe/netdtect.c
new file mode 100644
index 000000000..4d4c54625
--- /dev/null
+++ b/private/ntos/ndis/detect/exe/netdtect.c
@@ -0,0 +1,517 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ netdtect.c
+
+Abstract:
+
+ This is the command line interface and execution for the
+ netdtect.exe tester.
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) October 1992
+
+Revision History:
+
+
+--*/
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+
+#include <windows.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "netdtect.h"
+
+
+DWORD
+NetDTectRun(
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the main funciton of the program. It
+ prompts the user for commands and then issues the
+ call to NtDeviceIoControlFile.
+
+Arguments:
+
+ None;
+
+Return Value:
+
+ DWORD - the status of the last call to take place.
+
+--*/
+
+{
+ UCHAR EmptyLine[80];
+ UCHAR Command;
+ UCHAR CharDescriptor;
+ USHORT ShortDescriptor;
+ ULONG LongDescriptor;
+ ULONG Port;
+ ULONG Address;
+ ULONG Length;
+ ULONG Number;
+ ULONG TrapLength = 0;
+ HANDLE TrapHandle;
+ UCHAR i;
+
+ ULONG BusNumber = 0;
+ PUCHAR OutputBuffer;
+ UCHAR OutputBufferSize = 80;
+
+ NTSTATUS NtStatus;
+
+ //
+ // Alloc space for the interrupt list.
+ //
+
+ OutputBuffer = (PUCHAR)GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT,OutputBufferSize );
+
+ if ( OutputBuffer == NULL ) {
+ printf("\n\tGlobalAlloc failed to alloc OutputBuffer\n");
+ return (DWORD)STATUS_INVALID_HANDLE;
+ }
+
+ while ( TRUE ) {
+
+ printf("[NETDTECT] :");
+
+ scanf(" %c", &Command);
+
+ switch( Command ) {
+
+ case 'b':
+ case 'B':
+
+ scanf(" %l",&BusNumber);
+ gets(EmptyLine);
+
+ continue;
+
+ case 'i':
+ case 'I':
+
+ //
+ // We have a command to issue to the driver, do it now.
+ //
+
+ if (scanf(" %c %x", &CharDescriptor, &Port) != 2) {
+
+ //
+ // Error!
+ //
+
+ printf("\tMissing value\n");
+ gets(EmptyLine);
+ continue;
+
+ }
+
+ switch (CharDescriptor) {
+
+ case 'c':
+ case 'C':
+
+ NtStatus = DetectReadPortUchar(
+ Isa,
+ BusNumber,
+ Port,
+ &CharDescriptor
+ );
+
+ printf("\t0x%x\n",CharDescriptor);
+ break;
+
+ case 's':
+ case 'S':
+
+ NtStatus = DetectReadPortUshort(
+ Isa,
+ BusNumber,
+ Port,
+ &ShortDescriptor
+ );
+
+ printf("\t0x%x\n",ShortDescriptor);
+ break;
+
+ case 'l':
+ case 'L':
+
+ NtStatus = DetectReadPortUlong(
+ Isa,
+ BusNumber,
+ Port,
+ &LongDescriptor
+ );
+ printf("\t0x%x\n",LongDescriptor);
+ break;
+
+ default:
+
+ printf("\tInvalid value\n");
+ gets(EmptyLine);
+ continue;
+
+ }
+
+ break;
+
+ case 'o':
+ case 'O':
+
+ //
+ // We have a command to issue to the driver, do it now.
+ //
+
+ if (scanf(" %c %x", &CharDescriptor, &Port) != 2) {
+
+ //
+ // Error!
+ //
+
+ printf("\tMissing value\n");
+ gets(EmptyLine);
+ continue;
+
+ }
+
+ switch (CharDescriptor) {
+
+ case 'c':
+ case 'C':
+
+ if (!scanf(" %x", &LongDescriptor)) {
+
+
+ //
+ // Error!
+ //
+
+ printf("\tMissing value\n");
+ gets(EmptyLine);
+ continue;
+
+ }
+
+ NtStatus = DetectWritePortUchar(
+ Isa,
+ BusNumber,
+ Port,
+ (UCHAR)LongDescriptor
+ );
+
+ break;
+
+ case 's':
+ case 'S':
+
+ if (!scanf(" %hx", &ShortDescriptor)) {
+
+
+ //
+ // Error!
+ //
+
+ printf("\tMissing value\n");
+ gets(EmptyLine);
+ continue;
+
+ }
+
+
+ NtStatus = DetectWritePortUshort(
+ Isa,
+ BusNumber,
+ Port,
+ ShortDescriptor
+ );
+
+ break;
+
+ case 'l':
+ case 'L':
+
+ if (!scanf(" %lx", &LongDescriptor)) {
+
+
+ //
+ // Error!
+ //
+
+ printf("\tMissing value\n");
+ gets(EmptyLine);
+ continue;
+
+ }
+
+
+ NtStatus = DetectWritePortUlong(
+ Isa,
+ BusNumber,
+ Port,
+ LongDescriptor
+ );
+
+ break;
+
+ default:
+
+ printf("\tInvalid value\n");
+ gets(EmptyLine);
+ continue;
+
+ }
+
+ break;
+
+ case 'r':
+ case 'R':
+
+ //
+ // We have a command to issue to the driver, do it now.
+ //
+
+ if (scanf(" %lx %li", &Address, &Length) != 2) {
+
+ //
+ // Error!
+ //
+
+ printf("\tMissing value\n");
+ gets(EmptyLine);
+ continue;
+
+ }
+
+ if (Length > OutputBufferSize) {
+
+ printf("\tNot enough memory in EXE\n");
+ gets(EmptyLine);
+ continue;
+ }
+
+ NtStatus = DetectReadMappedMemory(
+ Isa,
+ BusNumber,
+ Address,
+ Length,
+ OutputBuffer
+ );
+
+ printf("%6x ",Address);
+
+ for (i=0; i < Length; i++) {
+ printf("%2x ", *(((PUCHAR)OutputBuffer) + i));
+
+ if ((i%8) == 7) {
+
+ UCHAR Count;
+
+ printf(" | ");
+
+ Count = 0;
+
+ for (;Count < 8; Count ++) {
+
+ printf(" %c", *(((PUCHAR)OutputBuffer) + i - (7-Count)));
+
+ }
+
+ printf("\n");
+
+ if ((i+1) < Length) {
+ printf("%6x ",Address + i + 1);
+ }
+
+ }
+
+ }
+
+ if ((i%8) != 0) {
+ printf("\n");
+ }
+
+ break;
+
+ case 'w':
+ case 'W':
+
+ //
+ // We have a command to issue to the driver, do it now.
+ //
+
+ if (scanf(" %lx %li", &Address, &Length) != 2) {
+
+ //
+ // Error!
+ //
+
+ printf("\tMissing value\n");
+ gets(EmptyLine);
+ continue;
+
+ }
+
+ if (Length > OutputBufferSize) {
+
+ printf("\tNot enough memory in EXE\n");
+ gets(EmptyLine);
+ continue;
+ }
+
+ for (i=0; i < Length; i++) {
+
+ scanf(" %x", &Number);
+
+ *(((PUCHAR)OutputBuffer)+i) = (UCHAR)Number;
+
+ }
+
+ NtStatus = DetectWriteMappedMemory(
+ Isa,
+ BusNumber,
+ Address,
+ Length,
+ OutputBuffer
+ );
+
+ break;
+
+ case 's':
+ case 'S':
+
+ //
+ // Get the line so we can parse it.
+ //
+ gets(EmptyLine);
+
+ Length = strlen(EmptyLine);
+
+ Number = 0;
+
+ //
+ // Now search for interrupt numbers
+ //
+ for (i=0; i < Length; i++) {
+
+ ULONG Tmp;
+
+ if ((EmptyLine[i] < '0') || (EmptyLine[i] > '9')) {
+ continue;
+ }
+
+ if (!sscanf(EmptyLine + i," %d", &Tmp)) {
+ break;
+ }
+
+ if ((UCHAR)Tmp > 9) {
+ i++;
+ }
+
+ *(((PUCHAR)OutputBuffer) + Number) = (UCHAR)Tmp;
+ Number++;
+
+ }
+
+ TrapLength = Number;
+
+ NtStatus = DetectSetInterruptTrap(
+ Isa,
+ BusNumber,
+ &TrapHandle,
+ OutputBuffer,
+ Number
+ );
+
+ break;
+
+ case 'q':
+ case 'Q':
+
+ NtStatus = DetectQueryInterruptTrap(
+ TrapHandle,
+ OutputBuffer,
+ TrapLength
+ );
+
+ for (i=0; i < TrapLength; i++) {
+ printf("\tIndex %d : %d\n", i, *(((PUCHAR)OutputBuffer)+i));
+ }
+
+ break;
+
+ case 'd':
+ case 'D':
+
+ NtStatus = DetectRemoveInterruptTrap(
+ TrapHandle
+ );
+
+ break;
+
+ case 'x':
+ case 'X':
+
+ gets(EmptyLine);
+ printf("\n");
+ printf("The ghosts that haunt me now.\n");
+ return(NO_ERROR);
+
+
+ default:
+
+ printf("\nInvalid Command Entered.\n",NULL);
+ printf("\n");
+ printf("\tb - Set bus number\n\t\tb <number>\n");
+ printf("\td - Remove interrupt trap\n\t\td\n");
+ printf("\ti - In from a port\n\t\ti <c,s,l> <port>\n");
+ printf("\to - Out to a port\n\t\to <c,s,l> <port> <value>\n");
+ printf("\tq - Query interrupt trap\n\t\tq <int-list>\n");
+ printf("\tr - Read memory\n\t\tr <address> <length>\n");
+ printf("\ts - Set interrupt trap\n\t\ts <int-list>\n");
+ printf("\tw - Write memory\n\t\tw <address>\n");
+ printf("\tx - eXit\n");
+ printf("\n");
+
+ gets(EmptyLine);
+
+ continue;
+
+ }
+
+ if ((Command != 's') && (Command != 'S')) {
+ gets(EmptyLine);
+ }
+
+ if ( NtStatus != STATUS_SUCCESS ) {
+
+ printf("The command failed with 0x%x\n", NtStatus);
+
+ }
+
+ }
+
+ //
+ // The test has ended successfully
+ //
+
+ GlobalFree( OutputBuffer );
+
+ return STATUS_SUCCESS;
+}
+
diff --git a/private/ntos/ndis/detect/exe/sources b/private/ntos/ndis/detect/exe/sources
new file mode 100644
index 000000000..01444d60d
--- /dev/null
+++ b/private/ntos/ndis/detect/exe/sources
@@ -0,0 +1,52 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+UMLIBS=\nt\public\sdk\lib\*\setargv.obj
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=testprot
+MINORCOMP=tpctl
+
+TARGETNAME=netdtect
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+INCLUDES=..\..\wrapper;..\inc;..\..\..\inc
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=init.c \
+ netdtect.c
+
+i860_SOURCES=
+
+i386_SOURCES=
+
+MIPS_SOURCES=
+
+RELATIVE_DEPTH=..\..\..
+NTTEST=
+OPTIONAL_NTTEST=
+
+UMTYPE=console
+UMAPPL=netdtect
+UMLIBS=\nt\public\sdk\lib\*\netdtect.lib \nt\public\sdk\lib\*\setargv.obj obj\*\init.obj
diff --git a/private/ntos/ndis/detect/inc/netdtect.h b/private/ntos/ndis/detect/inc/netdtect.h
new file mode 100644
index 000000000..dad95bacc
--- /dev/null
+++ b/private/ntos/ndis/detect/inc/netdtect.h
@@ -0,0 +1,312 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ netdtect.h
+
+Abstract:
+
+ Default definitions for driver and its control application.
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) October 1992
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+--*/
+
+#if DBG
+
+extern UCHAR NetDTectDebug;
+
+#define DEBUG_LOUD 0x1
+#define DEBUG_VERY_LOUD 0x2
+
+
+#define IF_LOUD( A ) if(NetDTectDebug & DEBUG_LOUD) { A }
+#define IF_VERY_LOUD( A ) if(NetDTectDebug & DEBUG_VERY_LOUD) { A }
+
+#else
+
+#define IF_LOUD( A )
+#define IF_VERY_LOUD( A )
+
+#endif
+
+
+
+
+//
+// Device Name - this string is the name of the device. It is the name
+// that should be passed to NtOpenFile when accessing the device.
+//
+// Note: For devices that support multiple units, it should be suffixed
+// with the Ascii representation of the unit number.
+//
+
+#define DRIVER_DEVICE_NAME "\\Device\\NtNetDetect"
+
+//
+// Device Name - this string is the name of the device in DOS space which
+// maps from the DRIVER_DEVICE_NAME
+//
+
+#define DOS_DRIVER_DEVICE_NAME "\\DosDevices\\NetDTect"
+
+
+//
+// The symbolic link for the device driver name for win32 apis
+//
+
+#define DLL_CREATE_DEVICE_NAME "\\\\.\\NetDTect"
+
+
+//
+// NtDeviceIoControlFile IoControlCode values for this device.
+//
+// Warning: Remember that the low two bits of the code represent the
+// method, and specify how the input and output buffers are
+// passed to the driver via NtDeviceIoControlFile()
+//
+//
+
+
+//
+// Control codes
+//
+#define NETDTECT_READ_PORT_UCHAR 0x0
+#define NETDTECT_READ_PORT_USHORT 0x1
+#define NETDTECT_READ_PORT_ULONG 0x2
+#define NETDTECT_WRITE_PORT_UCHAR 0x3
+#define NETDTECT_WRITE_PORT_USHORT 0x4
+#define NETDTECT_WRITE_PORT_ULONG 0x5
+#define NETDTECT_READ_MAPPED_MEMORY 0x6
+#define NETDTECT_WRITE_MAPPED_MEMORY 0x7
+#define NETDTECT_SET_INTERRUPT_TRAP 0x8
+#define NETDTECT_QUERY_INTERRUPT_TRAP 0x9
+#define NETDTECT_REMOVE_INTERRUPT_TRAP 0xA
+#define NETDTECT_CHECK_PORT_USAGE 0xB
+#define NETDTECT_CHECK_MEMORY_USAGE 0xC
+#define NETDTECT_CLAIM_RESOURCE 0xD
+#define NETDTECT_TEMP_CLAIM_RESOURCE 0xE
+#define NETDTECT_FREE_TEMP_RESOURCES 0xF
+#define NETDTECT_RPCI 0x10
+#define NETDTECT_WPCI 0x11
+#define NETDTECT_FREE_TEMP_SPECIFIC_RESOURCES 0x12
+
+#define IOCTL_BASE FILE_DEVICE_UNKNOWN
+
+#define IOCTL_RP_METHOD 3
+#define IOCTL_WP_METHOD 3
+#define IOCTL_SIT_METHOD 3
+#define IOCTL_QIT_METHOD 3
+#define IOCTL_RIT_METHOD 3
+#define IOCTL_WM_METHOD 1
+#define IOCTL_RM_METHOD 2
+#define IOCTL_CP_METHOD 3
+#define IOCTL_CM_METHOD 3
+#define IOCTL_CR_METHOD 1
+
+
+#define NETDTECT_CONTROL_CODE(request, method) \
+ ((IOCTL_BASE)<<16 | (request<<2) | method)
+
+
+#define IOCTL_NETDTECT_RPC NETDTECT_CONTROL_CODE( NETDTECT_READ_PORT_UCHAR, \
+ IOCTL_RP_METHOD )
+#define IOCTL_NETDTECT_RPS NETDTECT_CONTROL_CODE( NETDTECT_READ_PORT_USHORT, \
+ IOCTL_RP_METHOD )
+#define IOCTL_NETDTECT_RPL NETDTECT_CONTROL_CODE( NETDTECT_READ_PORT_ULONG, \
+ IOCTL_RP_METHOD )
+
+#define IOCTL_NETDTECT_WPC NETDTECT_CONTROL_CODE( NETDTECT_WRITE_PORT_UCHAR, \
+ IOCTL_WP_METHOD )
+#define IOCTL_NETDTECT_WPS NETDTECT_CONTROL_CODE( NETDTECT_WRITE_PORT_USHORT, \
+ IOCTL_WP_METHOD )
+#define IOCTL_NETDTECT_WPL NETDTECT_CONTROL_CODE( NETDTECT_WRITE_PORT_ULONG, \
+ IOCTL_WP_METHOD )
+
+#define IOCTL_NETDTECT_RM NETDTECT_CONTROL_CODE( NETDTECT_READ_MAPPED_MEMORY, \
+ IOCTL_RM_METHOD )
+#define IOCTL_NETDTECT_WM NETDTECT_CONTROL_CODE( NETDTECT_WRITE_MAPPED_MEMORY, \
+ IOCTL_WM_METHOD )
+
+#define IOCTL_NETDTECT_SIT NETDTECT_CONTROL_CODE( NETDTECT_SET_INTERRUPT_TRAP, \
+ IOCTL_SIT_METHOD )
+#define IOCTL_NETDTECT_QIT NETDTECT_CONTROL_CODE( NETDTECT_QUERY_INTERRUPT_TRAP, \
+ IOCTL_QIT_METHOD )
+#define IOCTL_NETDTECT_RIT NETDTECT_CONTROL_CODE( NETDTECT_REMOVE_INTERRUPT_TRAP, \
+ IOCTL_RIT_METHOD )
+#define IOCTL_NETDTECT_CPU NETDTECT_CONTROL_CODE( NETDTECT_CHECK_PORT_USAGE, \
+ IOCTL_CP_METHOD )
+#define IOCTL_NETDTECT_CMU NETDTECT_CONTROL_CODE( NETDTECT_CHECK_MEMORY_USAGE, \
+ IOCTL_CM_METHOD )
+#define IOCTL_NETDTECT_CR NETDTECT_CONTROL_CODE( NETDTECT_CLAIM_RESOURCE, \
+ IOCTL_CR_METHOD )
+#define IOCTL_NETDTECT_TCR NETDTECT_CONTROL_CODE( NETDTECT_TEMP_CLAIM_RESOURCE, \
+ IOCTL_CR_METHOD )
+#define IOCTL_NETDTECT_FTR NETDTECT_CONTROL_CODE( NETDTECT_FREE_TEMP_RESOURCES, \
+ IOCTL_CR_METHOD )
+#define IOCTL_NETDTECT_FTSR NETDTECT_CONTROL_CODE( NETDTECT_FREE_TEMP_SPECIFIC_RESOURCES, \
+ IOCTL_CR_METHOD )
+
+#define IOCTL_NETDTECT_RPCI NETDTECT_CONTROL_CODE( NETDTECT_RPCI, \
+ IOCTL_CR_METHOD )
+#define IOCTL_NETDTECT_WPCI NETDTECT_CONTROL_CODE( NETDTECT_WPCI, \
+ IOCTL_CR_METHOD )
+//
+// Structure for holding the information in the IRP SystemBuffer
+//
+typedef union _CMD_ARGS
+{
+ //
+ // READ_PORT_*
+ //
+ struct _RP
+ {
+ INTERFACE_TYPE InterfaceType;
+ ULONG Port;
+ ULONG BusNumber;
+ ULONG Value;
+ }
+ RP;
+
+ //
+ // WRITE_PORT_UCHAR
+ //
+ struct _WPC
+ {
+ INTERFACE_TYPE InterfaceType;
+ ULONG Port;
+ ULONG BusNumber;
+ UCHAR Value;
+ }
+ WPC;
+
+
+ //
+ // WRITE_PORT_USHORT
+ //
+ struct _WPS
+ {
+ INTERFACE_TYPE InterfaceType;
+ ULONG Port;
+ ULONG BusNumber;
+ USHORT Value;
+ }
+ WPS;
+
+
+ //
+ // WRITE_PORT_ULONG
+ //
+ struct _WPL
+ {
+ INTERFACE_TYPE InterfaceType;
+ ULONG Port;
+ ULONG BusNumber;
+ ULONG Value;
+ }
+ WPL;
+
+
+ //
+ // READ/WRITE MEMORY
+ //
+ struct _MEM
+ {
+ INTERFACE_TYPE InterfaceType;
+ ULONG Address;
+ ULONG BusNumber;
+ ULONG Length;
+ }
+ MEM;
+
+
+ //
+ // SET_INTERRUPT_TRAP
+ //
+ struct _SIT
+ {
+ INTERFACE_TYPE InterfaceType;
+ PHANDLE TrapHandle;
+ ULONG InterruptListLength;
+ ULONG BusNumber;
+ }
+ SIT;
+
+ //
+ // QUERY_INTERRUPT_TRAP
+ //
+ struct _QIT
+ {
+ HANDLE TrapHandle;
+ }
+ QIT;
+
+ //
+ // REMOVE_INTERRUPT_TRAP
+ //
+ struct _RIT
+ {
+ HANDLE TrapHandle;
+ }
+ RIT;
+
+ //
+ // CHECK_PORT_USAGE
+ //
+ struct _CPU
+ {
+ INTERFACE_TYPE InterfaceType;
+ ULONG Port;
+ ULONG BusNumber;
+ ULONG Length;
+ }
+ CPU;
+
+ //
+ // CHECK_MEMORY_USAGE
+ //
+ struct _CMU
+ {
+ INTERFACE_TYPE InterfaceType;
+ ULONG BaseAddress;
+ ULONG BusNumber;
+ ULONG Length;
+ }
+ CMU;
+
+ //
+ // CLAIM_RESOURCE
+ //
+ struct _CR
+ {
+ ULONG NumberOfResources;
+ }
+ CR;
+
+ //
+ // Get/Set PCI information
+ //
+ struct _PCI
+ {
+ ULONG BusNumber;
+ ULONG SlotNumber;
+ ULONG Offset;
+ ULONG Length;
+ }
+ PCI;
+}
+ CMD_ARGS,
+ *PCMD_ARGS;
+
+
+
diff --git a/private/ntos/ndis/digi/digifile/dgatlas.c b/private/ntos/ndis/digi/digifile/dgatlas.c
new file mode 100644
index 000000000..2d846926c
--- /dev/null
+++ b/private/ntos/ndis/digi/digifile/dgatlas.c
@@ -0,0 +1,108 @@
+/*++
+
+*****************************************************************************
+* *
+* This software contains proprietary and confidential information of *
+* *
+* Digi International Inc. *
+* *
+* By accepting transfer of this copy, Recipient agrees to retain this *
+* software in confidence, to prevent disclosure to others, and to make *
+* no use of this software other than that for which it was delivered. *
+* This is an unpublished copyrighted work of Digi International Inc. *
+* Except as permitted by federal law, 17 USC 117, copying is strictly *
+* prohibited. *
+* *
+*****************************************************************************
+
+Module Name:
+
+ dgatlas.c
+
+Abstract:
+
+ This module is responsible for Atlas functionality common to all
+ drivers.
+
+--*/
+
+#include <ntddk.h>
+
+
+NTSTATUS DigiRegisterAtlasName( IN PUNICODE_STRING DeviceName,
+ IN PUNICODE_STRING ValueName,
+ IN PUNICODE_STRING ValueEntry )
+/*++
+
+Routine Description:
+
+ This routine will register the passed in value name and its associated
+ value for Atlas to find. In addition, we will create a symbolic
+ link to a name which is accessible for Atlas to open and exchange
+ information.
+
+Arguments:
+
+ DeviceName - pointer to unicode string to use when creating a
+ symbolic link. It is assumed this device name is all ready
+ created and ready to have symbolic links created.
+
+ ValueName - pointer to unicode string to be used as the registry
+ value name.
+
+ Value - pointer to unicode string to be used as the value associated
+ with ValueName.
+
+Return Value:
+
+ - STATUS_SUCCESS if successful
+
+ - Error indicating problem
+
+--*/
+{
+#define DEFAULT_DIGI_ATLAS_DEVICEMAP L"DigiAtlas"
+ NTSTATUS Status;
+ UNICODE_STRING LinkName;
+ WCHAR LinkNameBuffer[32];
+
+ //
+ // First, we create the required link symbolic name from the passed
+ // in value name.
+ //
+ RtlInitUnicodeString( &LinkName, NULL );
+ LinkName.Buffer = &LinkNameBuffer[0];
+ LinkName.MaximumLength = sizeof(LinkNameBuffer);
+ LinkName.Length = 0;
+
+ RtlAppendUnicodeToString( &LinkName, L"\\DosDevices\\" );
+ RtlAppendUnicodeStringToString( &LinkName, ValueEntry );
+
+ //
+ // Create the symbolic link first.
+ //
+
+ Status = IoCreateSymbolicLink( &LinkName,
+ DeviceName );
+
+ if( NT_ERROR(Status) )
+ return( Status );
+
+ //
+ // We need to add a \\.\ to the beginning of ValueEntry.
+ //
+ LinkName.Length = 0;
+ RtlZeroMemory( LinkName.Buffer, LinkName.MaximumLength );
+ RtlAppendUnicodeToString( &LinkName, L"\\\\.\\" );
+ RtlAppendUnicodeStringToString( &LinkName, ValueEntry );
+
+ Status = RtlWriteRegistryValue( RTL_REGISTRY_DEVICEMAP,
+ DEFAULT_DIGI_ATLAS_DEVICEMAP,
+ ValueName->Buffer,
+ REG_SZ,
+ LinkName.Buffer,
+ LinkName.Length + sizeof(WCHAR) );
+
+ return( Status );
+
+} // end DigiRegisterAtlasName
diff --git a/private/ntos/ndis/digi/digifile/dgatlas.h b/private/ntos/ndis/digi/digifile/dgatlas.h
new file mode 100644
index 000000000..1899ca354
--- /dev/null
+++ b/private/ntos/ndis/digi/digifile/dgatlas.h
@@ -0,0 +1,194 @@
+#ifndef DGATLAS_H
+#define DGATLAS_H
+
+/*++
+*****************************************************************************
+* *
+* This software contains proprietary and confidential information of *
+* *
+* Digi International Inc. *
+* *
+* By accepting transfer of this copy, Recipient agrees to retain this *
+* software in confidence, to prevent disclosure to others, and to make *
+* no use of this software other than that for which it was delivered. *
+* This is an unpublished copyrighted work of Digi International Inc. *
+* Except as permitted by federal law, 17 USC 117, copying is strictly *
+* prohibited. *
+* *
+*****************************************************************************
+++*/
+
+
+/////////////////////////////////////// Agent/Driver Commands section
+
+#pragma pack(4)
+
+#define MAX_DESCLEN 128
+#define GLOBAL_ATLAS_STRUCTURE_VERSION 1
+
+#define DIGI_PERSONALITY_FR ((DWORD)' RF') // Frame Relay
+#define DIGI_PERSONALITY_X25 ((DWORD)' 52X') // X.25
+#define DIGI_PERSONALITY_PRI ((DWORD)' IRP') // ISDN PRI
+#define DIGI_PERSONALITY_BRI ((DWORD)' IRB') // ISDN BRI
+
+#define DIGI_ATLAS_IOCTL CTL_CODE(FILE_DEVICE_PARALLEL_PORT, 3072, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+typedef struct _DIGI_PERSONALITY_
+{
+ DWORD dwVersion;
+ DWORD dwPersonalityTag;
+ DWORD dwId; // passed back by driver to uniquely
+ // id this adapter.
+ char szDesc[MAX_DESCLEN];
+} DIGI_PERSONALITY, *PDIGI_PERSONALITY;
+
+typedef enum _MAX_PERSONALITIES_ { MaxPersonalitiesPerAdapter = 4 } MAX_PERSONALITIES;
+
+//// payload for EnumAdapters command (was _DIGI_Personality_)
+//
+typedef struct _DIGI_ADAPTER_
+{
+ DWORD dwVersion;
+ DWORD dwMemoryAddress;
+ DWORD dwMemoryRange;
+
+ DWORD dwIOAddress;
+ DWORD dwIORange;
+
+ DWORD dwInterruptNumber; // bitmask indicating which interrupt(s) are
+ // in use by this adapter instance.
+
+ DWORD dwDMA; // bitmask indicating which DMA channels are
+ // in use by this adapter instance.
+
+ DWORD dwPersonalities; // number of personality structs that follow
+ DIGI_PERSONALITY Personalities[MaxPersonalitiesPerAdapter];
+} DIGI_ADAPTER, *PDIGI_ADAPTER;
+
+typedef enum _MAX_ADAPTERS_ { MaxAdaptersInSystem = 8 } MAX_ADAPTERS;
+
+typedef struct _DIGI_SYSTEM_
+{
+ DWORD dwVersion;
+ DWORD dwAdapters; // number of adapter structs that follow
+ DIGI_ADAPTER Adapters[MaxAdaptersInSystem];
+} DIGI_SYSTEM, *PDIGI_SYSTEM;
+
+
+//////////////////////////////////////////////// Personality/Driver Section
+//
+// Internal Digi Command IDS; 0-1023 are agent/device driver
+// 1024-8191 are personality/device driver
+
+typedef enum _DIGI_ATLAS_COMMAND_
+{
+ EnumAdapters, // pdu = DIGI_ADAPTER
+ LastGeneralID = 1023
+} DIGI_ATLAS_COMMAND;
+
+
+ ///////////////////////// Header of payload in AS_Msg
+//
+typedef struct _ATLAS_PDU_HEADER_
+{
+ DWORD dwHeaderSize; // offset to payload Buffer
+ DWORD dwPayloadSize; // size (in bytes) of Buffer following this header
+ DWORD dwVersion; // version of this PDU
+ DWORD dwFlags; // reserved for future use
+ DWORD dwCommand; // a value of type DIGI_ATLAS_COMMAND
+ DWORD dwAdapter; // identifies adapter to which command is targeted
+ DWORD dwClientContext; // reserved for client use
+ DWORD dwServerContext; // reserved for server use
+} ATLAS_PDU_HEADER, *PATLAS_PDU_HEADER;
+
+///////////////////////// Macro to access header and payload of a buffer
+// containing an Atlas command
+//
+#define GET_HEADER(X) ((ATLAS_PDU_HEADER*)X)
+#define GET_PAYLOAD(X) ((BYTE*)((BYTE*)X+((ATLAS_PDU_HEADER*)X)->dwHeaderSize))
+
+//
+// MEMBERS
+//
+// dwHeaderSize is used to size the header independently from the size of
+// the payload. This assures that entities will always be able to find
+// the start of the buffer regardless of additional header fields that
+// might be added in the future.
+//
+// dwPayloadSize indicates the length of the payload beyond this header,
+// which follows immediately after the header.
+//
+// dwVersion is the version of the Atlas Agent to which the command is
+// addressed. The client sending this command should use this as a hint
+// of the oldest version of the agent capable of interpreting this command.
+// The agent will return its version in the reply.
+//
+// Flags is reserved for future use and should be set to 0.
+//
+// dwCommand indicates the opcode of this command. Opcodes 0-1023 are
+// reserved for commands in which the agent is an active participant. They
+// are generic in the sense that they either are client/agent commands
+// only or apply to all personalities/device drivers. See the enum,
+// DIGI_ATLAS_COMMAND, for a list of currently supported opcodes in the
+// range 0-1023. Opcodes 1024-8191 are personality specific and thus
+// fall outside the scope of this header.
+//
+// dwAdapter identifies which adapter is the receiver of this command.
+// This field is currently unused. The intent was to provide an unused
+// header member should it become necessary to address adapters at
+// the command protocol level rather than as part of an internal struct
+// embedded in the payload.
+//
+// dwClientContext is a variable for exclusive use by the client sending
+// this command. Any server, including the agent, promises both that
+// it will ignore it and not alter it in subsequent replies.
+//
+// dwServerContext is a variable for exclusive use by the server replying
+// to this command. Subsequent commands sent as part of the same
+// transaction must preserve this value.
+//
+// REMARKS
+//
+// 1. An Atlas command pdu consists is a buffer the first part, the header,
+// of which is formated according to the ATLAS_PDU_HEADER above and
+// whose second part, the payload, is specified by the protocol between
+// some personality and its associated driver. The payload may be
+// accessed by using the macro defined above:
+//
+// // packing a buffer
+//
+// extern ATLAS_PDU_HEADER header;
+// extern Payload myPayload;
+//
+// header.HeaderSize = sizeof(ATLAS_PDU_HEADER);
+// header.PayloadSize = sizeof(Payload);
+//
+// BYTE* buffer = new BYTE [header.HeaderSize+header.PayloadSize];
+// memcpy(buffer, &header, header.HeaderSize);
+// memcpy(GET_PAYLOAD(buffer), &myPayload, header.PayloadSize);
+//
+// // unpacking a buffer
+//
+// memcpy(&header, GetHeader(buffer), GetHeader(buffer)->HeaderSize);
+// memcpy(&payload, GetPayload(buffer), GetHeader(buffer)->PayloadSize);
+//
+// Note that argument to either macro is any kind of pointer.
+//
+// 2. You add new members to ATLAS_PDU_HEADER with the following restrictions:
+//
+// 2.1 They must be added to the end of the current version
+// 2.2 All instances of the new struct must set the Version member
+// to a value > then the current version.
+// 2.3 The new member must be a DWORD or a type whose size is a
+// multiple of the size of a DWORD.
+//
+// 3. New versions of ATLAS_PDU_HEADER must not remove members from
+// previous versions.
+//
+
+
+#pragma pack()
+
+#endif
+
+
diff --git a/private/ntos/ndis/digi/digifile/digifile.c b/private/ntos/ndis/digi/digifile/digifile.c
new file mode 100644
index 000000000..edf8dba75
--- /dev/null
+++ b/private/ntos/ndis/digi/digifile/digifile.c
@@ -0,0 +1,637 @@
+/*++
+
+--*/
+
+#include <ntddk.h>
+#include <stdarg.h>
+#include <ntverp.h> // Include to determine what version of NT
+
+//
+// This is a fix for changes in DDK releases.
+//
+#ifdef VER_PRODUCTBUILD
+#define rmm VER_PRODUCTBUILD
+#endif
+
+#include "digifile.h"
+#include "memprint.h"
+
+#ifdef ALLOC_PRAGMA
+
+#if rmm > 528
+#pragma message( "\n\\\\\n\\\\ Including PAGED CODE\n\\\\ \n" )
+#pragma alloc_text( PAGEDIGIFILE, DigiOpenFile )
+#pragma alloc_text( PAGEDIGIFILE, DigiCloseFile )
+#pragma alloc_text( PAGEDIGIFILE, DigiMapFile )
+#pragma alloc_text( PAGEDIGIFILE, DigiUnmapFile )
+#endif
+
+#endif
+
+VOID DigiCheckMem( VOID );
+
+#if 0
+#define DigiCheckMem() \
+{ \
+ PLIST_ENTRY _DigiQueue; \
+ KIRQL _OldIrql, _CurrentIrql; \
+ \
+ _CurrentIrql = KeGetCurrentIrql(); \
+ \
+ _DigiQueue = &GlobalNonPagedMemQueue; \
+ \
+ KeAcquireSpinLock( &GlobalMemSpinLock, &_OldIrql ); \
+ \
+ while( _DigiQueue->Flink != &GlobalNonPagedMemQueue ) \
+ { \
+ PDIGI_MEM_DESCRIPTOR _MemDesc; \
+ PUCHAR _Buf; \
+ \
+ _MemDesc = CONTAINING_RECORD( _DigiQueue->Flink, \
+ DIGI_MEM_DESCRIPTOR, \
+ ListEntry ); \
+ \
+ _Buf = (PUCHAR)_MemDesc + sizeof(DIGI_MEM_DESCRIPTOR); \
+ if( (_MemDesc->BeginTag != (ULONG)'lkir') || \
+ (*(PULONG)(_Buf + _MemDesc->Length) != (ULONG)'igid') ) \
+ { \
+ DbgPrint( "DigiCheckMem corruption found (0x%x)!\n", _MemDesc ); \
+ DbgBreakPoint(); \
+ break; \
+ } \
+ \
+ _DigiQueue = _DigiQueue->Flink; \
+ } \
+ \
+ if( _CurrentIrql < DISPATCH_LEVEL ) \
+ { \
+ _DigiQueue = &GlobalPagedMemQueue; \
+ while( _DigiQueue->Flink != &GlobalPagedMemQueue ) \
+ { \
+ PDIGI_MEM_DESCRIPTOR _MemDesc; \
+ PUCHAR _Buf; \
+ \
+ _MemDesc = CONTAINING_RECORD( _DigiQueue->Flink, \
+ DIGI_MEM_DESCRIPTOR, \
+ ListEntry ); \
+ \
+ _Buf = (PUCHAR)_MemDesc + sizeof(DIGI_MEM_DESCRIPTOR); \
+ if( (_MemDesc->BeginTag != (ULONG)'lkir') || \
+ (*(PULONG)(_Buf + _MemDesc->Length) != (ULONG)'igid') ) \
+ { \
+ DbgPrint( "DigiCheckMem corruption found (0x%x)!\n", _MemDesc ); \
+ DbgBreakPoint(); \
+ break; \
+ } \
+ \
+ _DigiQueue = _DigiQueue->Flink; \
+ } \
+ } \
+ \
+ KeReleaseSpinLock( &GlobalMemSpinLock, _OldIrql ); \
+}
+#endif
+
+//
+// Describes an open DIGI file
+//
+
+typedef struct _DIGI_FILE_DESCRIPTOR
+{
+ HANDLE NtFileHandle;
+ PVOID Data;
+ KSPIN_LOCK Lock;
+ BOOLEAN Mapped;
+} DIGI_FILE_DESCRIPTOR, *PDIGI_FILE_DESCRIPTOR;
+
+
+typedef struct _DIGI_MEM_DESCRIPTOR_
+{
+ ULONG BeginTag;
+ ULONG Length;
+ LIST_ENTRY ListEntry;
+} DIGI_MEM_DESCRIPTOR, *PDIGI_MEM_DESCRIPTOR;
+
+//
+// Global Data
+//
+ULONG TotalMemAllocated=0L;
+ULONG DefaultPoolTag=(ULONG)('igiD');
+LIST_ENTRY GlobalPagedMemQueue={&GlobalPagedMemQueue,&GlobalPagedMemQueue};
+LIST_ENTRY GlobalNonPagedMemQueue={&GlobalNonPagedMemQueue,&GlobalNonPagedMemQueue};
+KSPIN_LOCK GlobalMemSpinLock;
+
+
+VOID DigiOpenFile( OUT PNTSTATUS Status,
+ OUT PHANDLE FileHandle,
+ OUT PULONG FileLength,
+ IN PUNICODE_STRING FileName,
+ IN PHYSICAL_ADDRESS HighestAcceptableAddress )
+/*++
+
+Routine Description:
+
+ This routine opens a file for future mapping and reads its contents
+ into allocated memory.
+
+Arguments:
+
+ Status - The status of the operation
+
+ FileHandle - A handle to be associated with this open
+
+ FileLength - Returns the length of the file
+
+ FileName - The name of the file
+
+ HighestAcceptableAddress - The highest physical address at which
+ the memory for the file can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ NTSTATUS NtStatus;
+ IO_STATUS_BLOCK IoStatus;
+ HANDLE NtFileHandle;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ ULONG LengthOfFile;
+ WCHAR PathPrefix[] = L"\\SystemRoot\\system32\\drivers\\";
+ UNICODE_STRING FullFileName;
+ ULONG FullFileNameLength;
+ PDIGI_FILE_DESCRIPTOR FileDescriptor;
+ PVOID FileImage;
+
+ //
+ // This structure represents the data from the
+ // NtQueryInformationFile API with an information
+ // class of FileStandardInformation.
+ //
+
+ FILE_STANDARD_INFORMATION StandardInfo;
+
+ //
+ // Insert the correct path prefix.
+ //
+
+ FullFileNameLength = sizeof(PathPrefix) + FileName->MaximumLength;
+
+ FullFileName.Buffer = DigiAllocMem( NonPagedPool,
+ FullFileNameLength );
+
+ if (FullFileName.Buffer == NULL) {
+ *Status = STATUS_INSUFFICIENT_RESOURCES;
+ return;
+ }
+
+ FullFileName.Length = sizeof (PathPrefix) - sizeof(WCHAR);
+ FullFileName.MaximumLength = (USHORT)FullFileNameLength;
+ RtlMoveMemory (FullFileName.Buffer, PathPrefix, sizeof(PathPrefix));
+
+ RtlAppendUnicodeStringToString (&FullFileName, FileName);
+
+#if DBG
+ DbgPrint ("DIGIFILE: Attempting to open %wZ\n", &FullFileName);
+#endif
+
+ InitializeObjectAttributes ( &ObjectAttributes,
+ &FullFileName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL );
+
+ NtStatus = ZwCreateFile( &NtFileHandle,
+ SYNCHRONIZE | FILE_READ_DATA,
+ &ObjectAttributes,
+ &IoStatus,
+ NULL, // alloc size = none
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ,
+ FILE_OPEN,
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL, // eabuffer
+ 0 ); // ealength
+
+ if( !NT_SUCCESS(NtStatus) )
+ {
+#if DBG
+ DbgPrint ("Error opening file %x\n", NtStatus);
+#endif
+ DigiFreeMem( FullFileName.Buffer );
+ *Status = DIGI_STATUS_FILE_NOT_FOUND;
+ return;
+ }
+
+ DigiFreeMem( FullFileName.Buffer );
+
+ //
+ // Query the object to determine its length.
+ //
+
+ NtStatus = ZwQueryInformationFile( NtFileHandle,
+ &IoStatus,
+ &StandardInfo,
+ sizeof(FILE_STANDARD_INFORMATION),
+ FileStandardInformation );
+
+ if (!NT_SUCCESS(NtStatus)) {
+#if DBG
+ DbgPrint ("Error querying info on file %x\n", NtStatus);
+#endif
+ ZwClose( NtFileHandle );
+ *Status = NtStatus;
+ return;
+ }
+
+ LengthOfFile = StandardInfo.EndOfFile.LowPart;
+
+#if DBG
+ DbgPrint ("File length is %d\n", LengthOfFile);
+#endif
+
+ //
+ // Might be corrupted.
+ //
+
+ if( LengthOfFile < 1 )
+ {
+#if DBG
+ DbgPrint ("Bad file length %d\n", LengthOfFile);
+#endif
+ ZwClose( NtFileHandle );
+ *Status = DIGI_STATUS_ERROR_READING_FILE;
+ return;
+ }
+
+ //
+ // Allocate buffer for this file
+ //
+
+ FileImage = DigiAllocMem( NonPagedPool,
+ LengthOfFile );
+
+ if( FileImage == NULL )
+ {
+#if DBG
+ DbgPrint ("Could not allocate buffer\n");
+#endif
+ ZwClose( NtFileHandle );
+ *Status = DIGI_STATUS_ERROR_READING_FILE;
+ return;
+ }
+
+ //
+ // Read the file into our buffer.
+ //
+
+ NtStatus = ZwReadFile( NtFileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ FileImage,
+ LengthOfFile,
+ NULL,
+ NULL );
+
+ ZwClose( NtFileHandle );
+
+ if( (!NT_SUCCESS(NtStatus)) || (IoStatus.Information != LengthOfFile) )
+ {
+#if DBG
+ DbgPrint ("error reading file %x\n", NtStatus);
+#endif
+ *Status = DIGI_STATUS_ERROR_READING_FILE;
+ DigiFreeMem( FileImage );
+ return;
+ }
+
+ //
+ // Allocate a structure to describe the file.
+ //
+
+ FileDescriptor = DigiAllocMem( NonPagedPool,
+ sizeof(DIGI_FILE_DESCRIPTOR) );
+
+ if( FileDescriptor == NULL )
+ {
+ *Status = STATUS_INSUFFICIENT_RESOURCES;
+ DigiFreeMem( FileImage );
+ return;
+ }
+
+
+ FileDescriptor->NtFileHandle = NtFileHandle;
+ FileDescriptor->Data = FileImage;
+ KeInitializeSpinLock( &FileDescriptor->Lock );
+ FileDescriptor->Mapped = FALSE;
+
+ *FileHandle = (HANDLE)FileDescriptor;
+ *FileLength = LengthOfFile;
+ *Status = STATUS_SUCCESS;
+}
+
+
+VOID DigiCloseFile( IN HANDLE FileHandle )
+/*++
+
+Routine Description:
+
+ This routine closes a file previously opened with DigiOpenFile.
+ The file is unmapped if needed and the memory is freed.
+
+Arguments:
+
+ FileHandle - The handle returned by DigiOpenFile
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PDIGI_FILE_DESCRIPTOR FileDescriptor = (PDIGI_FILE_DESCRIPTOR)FileHandle;
+
+ DigiFreeMem( FileDescriptor->Data );
+ DigiFreeMem( FileDescriptor );
+}
+
+
+
+VOID DigiMapFile( OUT PNTSTATUS Status,
+ OUT PVOID * MappedBuffer,
+ IN HANDLE FileHandle )
+/*++
+
+Routine Description:
+
+ This routine maps an open file, so that the contents can be accessed.
+ Files can only have one active mapping at any time.
+
+Arguments:
+
+ Status - The status of the operation
+
+ MappedBuffer - Returns the virtual address of the mapping.
+
+ FileHandle - The handle returned by DigiOpenFile.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PDIGI_FILE_DESCRIPTOR FileDescriptor = (PDIGI_FILE_DESCRIPTOR)FileHandle;
+ KIRQL oldirql;
+
+ KeAcquireSpinLock (&FileDescriptor->Lock, &oldirql);
+
+ if (FileDescriptor->Mapped == TRUE) {
+ *Status = DIGI_STATUS_ALREADY_MAPPED;
+ KeReleaseSpinLock (&FileDescriptor->Lock, oldirql);
+ return;
+ }
+
+ FileDescriptor->Mapped = TRUE;
+ KeReleaseSpinLock (&FileDescriptor->Lock, oldirql);
+
+ *MappedBuffer = FileDescriptor->Data;
+ *Status = STATUS_SUCCESS;
+}
+
+
+VOID DigiUnmapFile( IN HANDLE FileHandle )
+/*++
+
+Routine Description:
+
+ This routine unmaps a file previously mapped with DigiOpenFile.
+ The file is unmapped if needed and the memory is freed.
+
+Arguments:
+
+ FileHandle - The handle returned by DigiOpenFile
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PDIGI_FILE_DESCRIPTOR FileDescriptor = (PDIGI_FILE_DESCRIPTOR)FileHandle;
+ KIRQL oldirql;
+
+ KeAcquireSpinLock (&FileDescriptor->Lock, &oldirql);
+ FileDescriptor->Mapped = FALSE;
+ KeReleaseSpinLock (&FileDescriptor->Lock, oldirql);
+}
+
+
+
+PVOID DigiInitMem( IN ULONG PoolTag )
+/*++
+
+Routine Description:
+
+Arguments:
+
+ PoolTag - Tag to use when allocating memory.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ DefaultPoolTag = PoolTag;
+ InitializeListHead( &GlobalPagedMemQueue );
+ InitializeListHead( &GlobalNonPagedMemQueue );
+ KeInitializeSpinLock( &GlobalMemSpinLock );
+
+ return( NULL );
+} // end DigiInitMem
+
+
+
+#if DBG || DIGICHECKMEM
+
+PVOID DigiAllocMem( IN POOL_TYPE PoolType, IN ULONG Length )
+/*++
+
+Routine Description:
+
+Arguments:
+
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+ KIRQL OldIrql;
+ PDIGI_MEM_DESCRIPTOR buf;
+ ULONG Len = ((Length + (sizeof(ULONG)-1)) & ~(sizeof(ULONG)-1));
+
+ //
+ // Check memory consistency.
+ //
+ DigiCheckMem();
+
+ if( (buf = (PDIGI_MEM_DESCRIPTOR)ExAllocatePoolWithTag( PoolType,
+ Len + sizeof(DIGI_MEM_DESCRIPTOR) + sizeof(ULONG),
+ DefaultPoolTag)) == NULL )
+ return(NULL);
+
+ TotalMemAllocated += Len;
+
+ buf->Length = Len;
+ buf->BeginTag = (ULONG)'lkir';
+
+ *(PULONG)((PUCHAR)buf + Len + sizeof(DIGI_MEM_DESCRIPTOR)) = (ULONG)'igid';
+
+ //
+ // Insert onto tail of global memory queue
+ //
+
+ KeAcquireSpinLock( &GlobalMemSpinLock, &OldIrql );
+
+ if( PoolType == PagedPool )
+ {
+ InsertTailList( &GlobalPagedMemQueue,
+ &(buf->ListEntry) );
+ }
+ else
+ {
+ InsertTailList( &GlobalNonPagedMemQueue,
+ &(buf->ListEntry) );
+ }
+
+ KeReleaseSpinLock( &GlobalMemSpinLock, OldIrql );
+
+ return( (PUCHAR)buf + (sizeof(DIGI_MEM_DESCRIPTOR)) );
+
+} // end DigiAllocMem
+
+
+
+VOID DigiFreeMem( IN PVOID Buf )
+/*++
+
+Routine Description:
+
+ Does consistency check on passed in memory block and free's the memory
+ block.
+
+Arguments:
+
+ Buf - pointer to memory block which is to be freed.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PDIGI_MEM_DESCRIPTOR RealBuf;
+ KIRQL OldIrql;
+ ULONG Length;
+
+ //
+ // Check memory consistency.
+ //
+ DigiCheckMem();
+
+ RealBuf = (PDIGI_MEM_DESCRIPTOR)((PUCHAR)Buf - sizeof(DIGI_MEM_DESCRIPTOR));
+ Length = RealBuf->Length;
+
+ if( RealBuf->BeginTag != (ULONG)'lkir' )
+ {
+ DbgPrint( "Memory has been corrupted!\n" );
+ DbgBreakPoint();
+ }
+
+ if( *(PULONG)((PUCHAR)Buf + Length) != (ULONG)'igid' )
+ {
+ DbgPrint("Memory Overrun\n");
+ DbgBreakPoint();
+ }
+
+ TotalMemAllocated -= Length;
+
+ KeAcquireSpinLock( &GlobalMemSpinLock, &OldIrql );
+ RemoveEntryList( &(RealBuf->ListEntry) );
+ KeReleaseSpinLock( &GlobalMemSpinLock, OldIrql );
+
+ ExFreePool( RealBuf );
+} // end DigiFreeMem
+
+
+VOID DigiCheckMem( VOID )
+{
+ PLIST_ENTRY _DigiQueue;
+ KIRQL _OldIrql, _CurrentIrql;
+
+ if( DigiPrintFlags & MEM_PRINT_FLAG_NOMEMCHECK )
+ return;
+
+ _DigiQueue = &GlobalNonPagedMemQueue;
+
+ KeAcquireSpinLock( &GlobalMemSpinLock, &_OldIrql );
+
+ while( _DigiQueue->Flink != &GlobalNonPagedMemQueue )
+ {
+ PDIGI_MEM_DESCRIPTOR _MemDesc;
+ PUCHAR _Buf;
+
+ _MemDesc = CONTAINING_RECORD( _DigiQueue->Flink,
+ DIGI_MEM_DESCRIPTOR,
+ ListEntry );
+
+ _Buf = (PUCHAR)_MemDesc + sizeof(DIGI_MEM_DESCRIPTOR);
+ if( (_MemDesc->BeginTag != (ULONG)'lkir') ||
+ (*(PULONG)(_Buf + _MemDesc->Length) != (ULONG)'igid') )
+ {
+ DbgPrint( "DigiCheckMem corruption found (0x%x)!n", _MemDesc );
+ DbgBreakPoint();
+ break;
+ }
+
+ _DigiQueue = _DigiQueue->Flink;
+ }
+
+ _DigiQueue = &GlobalPagedMemQueue;
+ _CurrentIrql = KeGetCurrentIrql();
+
+ while( (_CurrentIrql < DISPATCH_LEVEL) &&
+ (_DigiQueue->Flink != &GlobalPagedMemQueue) )
+ {
+ PDIGI_MEM_DESCRIPTOR _MemDesc;
+ PUCHAR _Buf;
+
+ _MemDesc = CONTAINING_RECORD( _DigiQueue->Flink,
+ DIGI_MEM_DESCRIPTOR,
+ ListEntry );
+
+ _Buf = (PUCHAR)_MemDesc + sizeof(DIGI_MEM_DESCRIPTOR);
+ if( (_MemDesc->BeginTag != (ULONG)'lkir') ||
+ (*(PULONG)(_Buf + _MemDesc->Length) != (ULONG)'igid') )
+ {
+ DbgPrint( "DigiCheckMem corruption found (0x%x)!n", _MemDesc );
+ DbgBreakPoint();
+ break;
+ }
+
+ _DigiQueue = _DigiQueue->Flink;
+ _CurrentIrql = KeGetCurrentIrql();
+ }
+
+ KeReleaseSpinLock( &GlobalMemSpinLock, _OldIrql );
+}
+
+#endif // end #if DBG || DIGICHECKMEM
diff --git a/private/ntos/ndis/digi/digifile/digifile.h b/private/ntos/ndis/digi/digifile/digifile.h
new file mode 100644
index 000000000..3f30774ba
--- /dev/null
+++ b/private/ntos/ndis/digi/digifile/digifile.h
@@ -0,0 +1,105 @@
+#include <ntverp.h>
+
+#ifdef VER_PRODUCTBUILD
+#define rmm VER_PRODUCTBUILD
+#endif
+
+
+#define DIGI_PHYSICAL_ADDRESS_CONST(_Low, _High) \
+ { (ULONG)(_Low), (LONG)(_High) }
+
+#define DIGI_STATUS_FILE_NOT_FOUND ((NTSTATUS)0xC001001BL)
+#define DIGI_STATUS_ERROR_READING_FILE ((NTSTATUS)0xC001001CL)
+#define DIGI_STATUS_ALREADY_MAPPED ((NTSTATUS)0xC001001DL)
+
+
+VOID DigiOpenFile( OUT PNTSTATUS Status,
+ OUT PHANDLE FileHandle,
+ OUT PULONG FileLength,
+ IN PUNICODE_STRING FileName,
+ IN PHYSICAL_ADDRESS HighestAcceptableAddress );
+
+VOID DigiCloseFile( IN HANDLE FileHandle );
+
+VOID DigiMapFile( OUT PNTSTATUS Status,
+ OUT PVOID * MappedBuffer,
+ IN HANDLE FileHandle );
+
+VOID DigiUnmapFile( IN HANDLE FileHandle );
+
+#ifndef POOL_TAGGING
+#define ExAllocatePoolWithTag(a,b,c) ExAllocatePool(a,b)
+#endif //POOL_TAGGING
+
+PVOID DigiInitMem( IN ULONG PoolTag );
+extern ULONG DefaultPoolTag;
+
+#if DBG || DIGICHECKMEM
+
+PVOID DigiAllocMem( IN POOL_TYPE PoolType, IN ULONG Length );
+VOID DigiFreeMem( IN PVOID Buf );
+
+#else
+
+#define DigiAllocMem( PoolType, Length ) ExAllocatePoolWithTag( PoolType, \
+ Length, \
+ DefaultPoolTag )
+#define DigiFreeMem( Buffer ) ExFreePool( Buffer )
+
+#endif
+
+//
+// The following are prototypes for functions found in dgatlas.c
+//
+NTSTATUS DigiRegisterAtlasName( IN PUNICODE_STRING DeviceName,
+ IN PUNICODE_STRING ValueName,
+ IN PUNICODE_STRING ValueEntry );
+
+
+#if rmm <= 807
+#define MmLockPagableCodeSection( a ) MmLockPagableImageSection( a )
+#endif
+
+#if rmm <= 528
+
+NTSTATUS
+NTAPI
+ZwCreateFile(
+ OUT PHANDLE FileHandle,
+ IN ACCESS_MASK DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ IN PLARGE_INTEGER AllocationSize OPTIONAL,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG CreateDisposition,
+ IN ULONG CreateOptions,
+ IN PVOID EaBuffer OPTIONAL,
+ IN ULONG EaLength
+ );
+
+NTSTATUS
+NTAPI
+ZwQueryInformationFile(
+ IN HANDLE FileHandle,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ OUT PVOID FileInformation,
+ IN ULONG Length,
+ IN FILE_INFORMATION_CLASS FileInformationClass
+ );
+
+NTSTATUS
+NTAPI
+ZwReadFile(
+ IN HANDLE FileHandle,
+ IN HANDLE Event OPTIONAL,
+ IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
+ IN PVOID ApcContext OPTIONAL,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ IN PLARGE_INTEGER ByteOffset OPTIONAL,
+ IN PULONG Key OPTIONAL
+ );
+
+#endif
diff --git a/private/ntos/ndis/digi/digifile/makefile b/private/ntos/ndis/digi/digifile/makefile
new file mode 100644
index 000000000..58189757d
--- /dev/null
+++ b/private/ntos/ndis/digi/digifile/makefile
@@ -0,0 +1,7 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the driver components of the Windows NT DDK
+#
+
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/digi/digifile/makefile.inc b/private/ntos/ndis/digi/digifile/makefile.inc
new file mode 100644
index 000000000..bfd14171b
--- /dev/null
+++ b/private/ntos/ndis/digi/digifile/makefile.inc
@@ -0,0 +1,15 @@
+..\lib\*:
+ mkdir ..\lib\*
+
+..\inc:
+ mkdir ..\inc
+
+..\inc\digifile.h: digifile.h
+ copy digifile.h ..\inc
+
+..\inc\memprint.h: memprint.h
+ copy memprint.h ..\inc
+
+..\inc\dgatlas.h: dgatlas.h
+ copy dgatlas.h ..\inc
+
diff --git a/private/ntos/ndis/digi/digifile/memprint.c b/private/ntos/ndis/digi/digifile/memprint.c
new file mode 100644
index 000000000..e81189a7b
--- /dev/null
+++ b/private/ntos/ndis/digi/digifile/memprint.c
@@ -0,0 +1,922 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ memprint.c
+
+Abstract:
+
+ This module contains the routines to implement in-memory DbgPrint.
+ DbgPrint text is stored in a large circular buffer, and optionally
+ written to a file and/or the debug console. Output to file is
+ buffered to allow high performance by the file system.
+
+Author:
+
+ David Treadwell (davidtr) 05-Oct-1990
+
+Revision History:
+
+--*/
+//
+// so it compiles when it includes ps.h
+//typedef unsigned long LCID; /* locale ID */
+
+#pragma message( "**** Including DEBUG functionality ****")
+
+#include "ntddk.h"
+
+#include <ntverp.h> // Include to determine what version of NT
+
+#ifdef VER_PRODUCTBUILD
+#define rmm VER_PRODUCTBUILD
+#endif
+
+#include "digifile.h"
+
+// The rest of the #includes are standard
+#include <stdarg.h>
+#include <string.h>
+#include "stdio.h"
+
+#include <memprint.h>
+#undef DbgPrint
+#undef MemPrintPreInitSettings
+#undef MemPrintInitialize
+#undef MemPrintQuit
+#undef MemPrint
+#undef MemPrintFlush
+
+
+#define MEM_PRINT_DEF_BUFFER_SIZE (65536 * 8)
+
+#define MEM_PRINT_LOG_FILE_NAME "\\SystemRoot\\DigiSer.log"
+
+//
+// Forward declarations.
+//
+
+VOID MemPrintWriteCompleteApc ( IN PVOID ApcContext,
+ IN PIO_STATUS_BLOCK IoStatusBlock );
+
+VOID DigiPrintWriteThread ( IN PVOID Dummy );
+
+
+//
+// Global data. It is all protected by MemPrintSpinLock.
+//
+
+PVOID ThreadObjectPointer;
+HANDLE fileHandle;
+UCHAR TurnOffSniffer=1;
+
+CLONG MemPrintBufferSize = MEM_PRINT_DEF_BUFFER_SIZE;
+PCHAR MemPrintBuffer;
+
+ULONG DigiPrintFlags = (MEM_PRINT_FLAG_CONSOLE | MEM_PRINT_FLAG_NOMEMCHECK);
+ULONG AttemptedTempBufferAllocs=0;
+
+ULONG MemPrintFailures=0;
+
+CHAR DefaultLogFileName[1024]=MEM_PRINT_LOG_FILE_NAME;
+
+//
+// Protect writing to the buffer
+//
+KSPIN_LOCK MemPrintSpinLock;
+
+BOOLEAN MemPrintInitialized = FALSE;
+BOOLEAN UnloadingDriver = FALSE;
+
+KEVENT MemPrintQuitEvent;
+KEVENT MemPrintWriteToLogEvent;
+
+LARGE_INTEGER totalBytesWritten;
+LARGE_INTEGER fileAllocationSize;
+
+ULONG BufferInOffset, BufferOutOffset;
+
+
+VOID MemPrintPreInitSettings( PCHAR NewLogFileName,
+ ULONG NewBufferSize )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ strcpy( DefaultLogFileName, NewLogFileName );
+ MemPrintBufferSize = NewBufferSize;
+} // end MemPrintPreInitSettings
+
+
+
+NTSTATUS MemPrintInitialize ( VOID )
+/*++
+
+Routine Description:
+
+ This is the initialization routine for the in-memory DbgPrint routine.
+ It should be called before the first call to MemPrint to set up the
+ various structures used and to start the log file write thread.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ NTSTATUS status;
+ HANDLE threadHandle;
+ KPRIORITY threadPriorityLevel;
+
+ OBJECT_ATTRIBUTES objectAttributes;
+ PCHAR fileName;
+ ANSI_STRING fileNameString;
+
+ UNICODE_STRING UnicodeFileName;
+
+ LARGE_INTEGER delayInterval;
+ ULONG attempts = 0;
+
+ IO_STATUS_BLOCK localIoStatusBlock;
+
+ PETHREAD CurrentThread;
+ PEPROCESS CurrentProcess;
+
+ if( MemPrintInitialized )
+ {
+ //
+ // we have all ready been called. Just return.
+ //
+ return( STATUS_SUCCESS );
+ }
+
+ fileName = DefaultLogFileName;
+ UnloadingDriver = FALSE;
+
+ //
+ // Initialize the total bytes written and write size variables.
+ //
+
+ totalBytesWritten.QuadPart = 0;
+ fileAllocationSize.QuadPart = 0;
+ BufferInOffset = BufferOutOffset = 0;
+
+ //
+ // Allocate memory for the circular buffer that will receive
+ // the text and data. If we can't do it, try again with a buffer
+ // half as large. If that fails, quit trying.
+ //
+
+ MemPrintBuffer = (PCHAR)DigiAllocMem( NonPagedPool, MemPrintBufferSize );
+
+ if( MemPrintBuffer == NULL )
+ {
+ MemPrintBufferSize /= 2;
+ DbgPrint( "Unable to allocate DbgPrint buffer--trying size = %ld\n",
+ MemPrintBufferSize );
+ MemPrintBuffer = DigiAllocMem( NonPagedPool, MemPrintBufferSize );
+
+ if( MemPrintBuffer == NULL )
+ {
+ DbgPrint( "Couldn't allocate DbgPrint buffer.\n" );
+ return( STATUS_INSUFFICIENT_RESOURCES );
+ }
+ }
+
+ DbgPrint( "MemPrint buffer from %lx to %lx\n",
+ MemPrintBuffer, MemPrintBuffer + MemPrintBufferSize );
+
+ //
+ // Allocate the spin lock that protects access to the various
+ // pointers and the circular buffer. This ensures integrity of the
+ // buffer.
+ //
+
+ KeInitializeSpinLock( &MemPrintSpinLock );
+
+ KeInitializeEvent( &MemPrintQuitEvent,
+ SynchronizationEvent,
+ (BOOLEAN)FALSE );
+
+ KeInitializeEvent( &MemPrintWriteToLogEvent,
+ SynchronizationEvent,
+ (BOOLEAN)FALSE );
+
+ //
+ // Initialize the string containing the file name and the object
+ // attributes structure that will describe the log file to open.
+ //
+
+ RtlInitAnsiString( &fileNameString,
+ fileName );
+ status = RtlAnsiStringToUnicodeString( &UnicodeFileName,
+ &fileNameString,
+ (BOOLEAN)TRUE );
+ ASSERT(NT_SUCCESS(status));
+
+ InitializeObjectAttributes( &objectAttributes,
+ &UnicodeFileName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL );
+
+ //
+ // Set the allocation size of the log file to be three times the
+ // size of the circular buffer. When it fills up, we'll extend
+ // it.
+ //
+
+ fileAllocationSize.QuadPart += MemPrintBufferSize;
+
+ //
+ // Open the log file.
+ //
+ // !!! The loop here is to help avoid a system initialization
+ // timing problem, and should be removed when the problem is
+ // fixed.
+ //
+
+ while ( TRUE ) {
+
+ status = ZwCreateFile( &fileHandle,
+ FILE_WRITE_DATA,
+ &objectAttributes,
+ &localIoStatusBlock,
+ &fileAllocationSize,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ,
+ FILE_OVERWRITE_IF,
+ FILE_SEQUENTIAL_ONLY,
+ NULL,
+ 0L );
+
+ if( (status != STATUS_OBJECT_PATH_NOT_FOUND) || (++attempts >= 3) )
+ {
+ RtlFreeUnicodeString( &UnicodeFileName );
+ break;
+ }
+
+ delayInterval.LowPart = (ULONG)(-5*10*1000*1000); // five second delay
+ delayInterval.HighPart = -1;
+ KeDelayExecutionThread( (KPROCESSOR_MODE)KernelMode,
+ (BOOLEAN)FALSE,
+ &delayInterval );
+ }
+
+ if( NT_ERROR(status) )
+ {
+ DbgPrint( "NtCreateFile for log file failed: 0x%x\n", status );
+ DigiFreeMem( MemPrintBuffer );
+ return( status );
+ } else
+ {
+ DbgPrint( "Successfully opened logfile %s\n", fileName );
+ }
+
+ //
+ // Set the priority of the write thread.
+ //
+
+ threadPriorityLevel = LOW_REALTIME_PRIORITY + 1;
+
+ CurrentThread = PsGetCurrentThread();
+ CurrentProcess = PsGetCurrentProcess();
+
+ //
+ // Start the thread that writes subbuffers from the large circular
+ // buffer to disk.
+ //
+
+ status = PsCreateSystemThread( &threadHandle,
+ THREAD_ALL_ACCESS,
+ NULL,
+ (HANDLE)0L,
+ NULL,
+ DigiPrintWriteThread,
+ NULL );
+
+ if( NT_ERROR(status) )
+ {
+ DbgPrint( "MemPrintInitialize: PsCreateSystemThread failed: 0x%x\n",
+ status );
+ //
+ // Cleanup
+ //
+ ZwClose( fileHandle );
+ DigiFreeMem( MemPrintBuffer );
+
+ return( status );
+ }
+
+ status = ObReferenceObjectByHandle( threadHandle,
+ THREAD_ALL_ACCESS,
+ NULL,
+ KernelMode,
+ &ThreadObjectPointer,
+ NULL );
+
+ if( NT_ERROR(status) )
+ {
+ ZwClose( fileHandle );
+ DigiFreeMem( MemPrintBuffer );
+
+ return( status );
+ }
+
+ MemPrintInitialized = TRUE;
+
+ return( STATUS_SUCCESS );
+
+} // MemPrintInitialize
+
+
+
+VOID MemPrintQuit(VOID)
+/*++
+
+Routine Description:
+
+ Called to cleanup.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ KIRQL oldIrql;
+
+ KeAcquireSpinLock( &MemPrintSpinLock, &oldIrql );
+
+ UnloadingDriver = TRUE;
+
+ if( !MemPrintInitialized )
+ {
+ KeReleaseSpinLock( &MemPrintSpinLock, oldIrql );
+ return;
+ }
+
+ KeSetEvent( &MemPrintWriteToLogEvent,
+ 2,
+ (BOOLEAN)FALSE );
+
+ KeReleaseSpinLock( &MemPrintSpinLock, oldIrql );
+
+ KeWaitForSingleObject( ThreadObjectPointer,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL );
+
+ DigiFreeMem( MemPrintBuffer );
+
+ ZwClose( fileHandle );
+
+} // MemPrintQuit
+
+
+
+VOID MemPrint ( CHAR *Format, ... )
+/*++
+
+Routine Description:
+
+ This routine is called in place of DbgPrint to process in-memory
+ printing.
+
+Arguments:
+
+ Format - A format string in the style of DbgPrint.
+
+ - formatting arguments.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ va_list arglist;
+ KIRQL oldIrql;
+ ULONG CurrentOutOffset, CurrentInOffset;
+ ULONG BytesToMove;
+ PCHAR tempBuffer, CopyTempBuffer;
+ ULONG tempBufferLen;
+
+ tempBuffer = DigiAllocMem( NonPagedPool, 1024 );
+
+ if( tempBuffer == NULL )
+ {
+ //
+ // Only print out failure msg every ten times.
+ //
+ if( (AttemptedTempBufferAllocs % 10) == 0 )
+ DbgPrint( "Unable to alloc temp buffer for MemPrint.\n" );
+
+ AttemptedTempBufferAllocs++;
+ return;
+ }
+
+ CopyTempBuffer = tempBuffer;
+
+ va_start( arglist, Format );
+
+#if defined (_X86_)
+ _vsnprintf( tempBuffer, 1024, Format, arglist );
+#elif defined (_MIPS_)
+ _vsnprintf( tempBuffer, 1024, Format, arglist );
+#elif defined (_ALPHA_)
+ vsprintf( tempBuffer, Format, arglist );
+#else
+ vsprintf( tempBuffer, Format, arglist );
+#endif
+
+ va_end( arglist );
+
+ //
+ // If memory DbgPrint has not been initialized, simply print to the
+ // console.
+ //
+
+ if( !MemPrintInitialized ||
+ UnloadingDriver )
+ {
+ //
+ // Just dump to console and return.
+ //
+
+ DbgPrint( "%s", tempBuffer );
+ goto ExitMemPrintFree;
+ }
+
+ if( DigiPrintFlags & MEM_PRINT_FLAG_CONSOLE )
+ DbgPrint( "%s", tempBuffer );
+
+ tempBufferLen = strlen(tempBuffer);
+ BytesToMove = tempBufferLen;
+
+ ASSERT( tempBufferLen+1 <= 1024 );
+
+ //
+ // Acquire the spin lock that synchronizes access to the pointers
+ // and circular buffer.
+ //
+
+ KeAcquireSpinLock( &MemPrintSpinLock, &oldIrql );
+
+ CurrentOutOffset = BufferOutOffset;
+ CurrentInOffset = BufferInOffset;
+
+ while( tempBufferLen )
+ {
+ if( CurrentOutOffset > CurrentInOffset )
+ {
+ //
+ // Take into account that we don't want to write one less
+ // so we don't put the CurrentInOffset equal to CurrentOutOffset.
+ //
+ BytesToMove = CurrentOutOffset - CurrentInOffset - 1;
+ }
+ else if( CurrentOutOffset < CurrentInOffset )
+ {
+ BytesToMove = CurrentOutOffset + MemPrintBufferSize - CurrentInOffset;
+ }
+ else
+ {
+ //
+ // We have the full buffer,
+ //
+ BytesToMove = MemPrintBufferSize - 1;
+ }
+
+ //
+ // We know how many bytes are available in the buffer. Now determine
+ // how many bytes we can actually write.
+ //
+ if( BytesToMove >= tempBufferLen )
+ {
+ //
+ // We can put the whole thing into the memprint buffer.
+ //
+ BytesToMove = tempBufferLen;
+ }
+// else
+// {
+// //
+// // We can only put part of the print request into the memprint
+// // buffer.
+// //
+// if( (MemPrintFailures % 1000) == 0 )
+// DbgPrint( "Unable to place entire print request into memprint buffer!\n" );
+// else
+// DbgPrint( "^" );
+//
+// MemPrintFailures++;
+// }
+
+ if( BytesToMove == 0 )
+ {
+ //
+ // More than likely, we ran out of buffer space.
+ //
+ if( (MemPrintFailures % 1000) == 0 )
+ DbgPrint( "Out of buffer space for MemPrint request, failures = %u!\n",
+ MemPrintFailures );
+// else
+// DbgPrint( "." );
+
+ MemPrintFailures++;
+ break;
+ }
+
+ //
+ // Okay, we know how many bytes we can potentially move. Now determine
+ // if we need to worry about wrapping the circular buffer.
+ //
+ if( (BytesToMove + CurrentInOffset) >= MemPrintBufferSize )
+ {
+ //
+ // readjust so we only write the number of bytes to the end
+ // of the buffer.
+ //
+ BytesToMove = MemPrintBufferSize - CurrentInOffset;
+ }
+
+ RtlMoveMemory( &MemPrintBuffer[CurrentInOffset],
+ tempBuffer,
+ BytesToMove );
+
+ tempBufferLen -= BytesToMove;
+
+ tempBuffer += BytesToMove;
+
+ CurrentInOffset += BytesToMove;
+
+ //
+ // Adjust the CurrentInOffset for circular buffer wrapping.
+ //
+ ASSERT( CurrentInOffset <= MemPrintBufferSize );
+
+ if( CurrentInOffset == MemPrintBufferSize )
+ CurrentInOffset = 0;
+
+ }
+
+ BufferInOffset = CurrentInOffset;
+
+ KeReleaseSpinLock( &MemPrintSpinLock, oldIrql );
+
+ //
+ // Set the event that will wake up the thread writing subbuffers
+ // to disk.
+ //
+
+ KeSetEvent( &MemPrintWriteToLogEvent,
+ 2,
+ (BOOLEAN)FALSE );
+
+ExitMemPrintFree:
+
+ DigiFreeMem( CopyTempBuffer );
+
+ return;
+
+} // MemPrint
+
+
+
+VOID MemPrintFlush ( VOID )
+
+/*++
+
+Routine Description:
+
+ This is obsolete now since the write thread will try to write
+ as much of the circular buffer as possible.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ return;
+
+} // MemPrintFlush
+
+
+
+VOID DigiPrintWriteThread ( IN PVOID Dummy )
+
+/*++
+
+Routine Description:
+
+ The log file write thread executes this routine. It sets up the
+ log file for writing, then waits for subbuffers to fill, writing
+ them to disk when they do. When the log file fills, new space
+ for it is allocated on disk to prevent the file system from
+ having to do it.
+
+Arguments:
+
+ Dummy - Ignored.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NTSTATUS status;
+ NTSTATUS waitStatus;
+
+ IO_STATUS_BLOCK localIoStatusBlock;
+
+ LARGE_INTEGER delayInterval;
+ ULONG NumberBytesToWrite;
+
+ Dummy;
+
+ //
+ // Delay for 20 seconds before we start executing. This will hopefully
+ // allow the system to get further along at boot time.
+ //
+ delayInterval.LowPart = (ULONG)(-20*10*1000*1000); // twenty second delay
+ delayInterval.HighPart = -1;
+ KeDelayExecutionThread( (KPROCESSOR_MODE)KernelMode,
+ (BOOLEAN)FALSE,
+ &delayInterval );
+
+ KeSetPriorityThread( KeGetCurrentThread(),
+ LOW_REALTIME_PRIORITY + 1 );
+
+ //
+ // Loop waiting for one of the subbuffer full events to be signaled.
+ // When one is signaled, wake up and write the subbuffer to the log
+ // file.
+ //
+
+ if( UnloadingDriver )
+ {
+ KeSetEvent( &MemPrintQuitEvent,
+ 2,
+ FALSE );
+ PsTerminateSystemThread( STATUS_SUCCESS );
+ }
+
+ while( TRUE )
+ {
+ PUCHAR tmpPtr;
+ ULONG CurrentOutOffset, CurrentInOffset;
+ KIRQL oldIrql;
+
+ waitStatus = KeWaitForSingleObject( &MemPrintWriteToLogEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ NULL );
+
+ if( !NT_SUCCESS(waitStatus) )
+ {
+ DbgPrint( "KeWaitForMultipleObjects failed: 0x%x\n", waitStatus );
+ continue;
+ }
+
+ //
+ // Check the DbgPrint flags to see if we really want to write
+ // this.
+ //
+
+ if( !(DigiPrintFlags & MEM_PRINT_FLAG_FILE) )
+ {
+ //
+ // There is nothing for us to do.
+ //
+ if( UnloadingDriver )
+ {
+ KeSetEvent( &MemPrintQuitEvent,
+ 2,
+ FALSE );
+ PsTerminateSystemThread( STATUS_SUCCESS );
+ }
+
+ continue;
+ }
+
+ //
+ // Take a snap shoot of the in pointer. It is possible it will
+ // change on us.
+ //
+ KeAcquireSpinLock( &MemPrintSpinLock, &oldIrql );
+
+ CurrentInOffset = BufferInOffset;
+ CurrentOutOffset = BufferOutOffset;
+
+ KeReleaseSpinLock( &MemPrintSpinLock, oldIrql );
+
+ while( CurrentInOffset != CurrentOutOffset )
+ {
+ ASSERT( CurrentInOffset <= MemPrintBufferSize );
+ ASSERT( CurrentOutOffset <= MemPrintBufferSize );
+
+ if( CurrentInOffset > CurrentOutOffset )
+ {
+ //
+ // We only need to do one write to the log file.
+ //
+ NumberBytesToWrite = CurrentInOffset - CurrentOutOffset;
+ }
+ else
+ {
+ //
+ // We have a buffer wrap situation and as a result need
+ // to account by making two write's to the log file.
+ //
+ NumberBytesToWrite = MemPrintBufferSize - CurrentOutOffset;
+ }
+
+ ASSERT( (CurrentOutOffset + NumberBytesToWrite) <= MemPrintBufferSize );
+
+ tmpPtr = MemPrintBuffer + CurrentOutOffset;
+ //
+ // Start the write operation. The APC routine will handle
+ // checking the return status from the write and updating
+ // BufferOutOffset.
+ //
+
+ status = ZwWriteFile( fileHandle,
+ NULL,
+ (PIO_APC_ROUTINE)MemPrintWriteCompleteApc,
+ (PVOID)NumberBytesToWrite,
+ &localIoStatusBlock,
+ tmpPtr,
+ NumberBytesToWrite,
+ &totalBytesWritten,
+ NULL );
+
+
+ if( !NT_SUCCESS(status) )
+ {
+ DbgPrint( "ZwWriteFile for log file failed: 0x%x\n", status );
+ }
+
+ //
+ // Update the count of bytes written to the log file.
+ //
+
+ CurrentOutOffset += NumberBytesToWrite;
+ ASSERT( CurrentOutOffset <= MemPrintBufferSize );
+
+ if( CurrentOutOffset >= MemPrintBufferSize )
+ CurrentOutOffset = 0;
+
+ totalBytesWritten.QuadPart += NumberBytesToWrite;
+
+ //
+ // Extend the file if we have reached the end of what we have
+ // thus far allocated for the file. This increases performance
+ // by extending the file here rather than in the file system,
+ // which would have to extend it each time a write past end of
+ // file comes in.
+ //
+
+ if( (totalBytesWritten.QuadPart >= fileAllocationSize.QuadPart) )
+ {
+ fileAllocationSize.QuadPart = fileAllocationSize.QuadPart + MemPrintBufferSize;
+
+ DbgPrint( "Enlarging logfile %s to %ld bytes.\n",
+ DefaultLogFileName,
+ fileAllocationSize.LowPart );
+
+ status = ZwSetInformationFile( fileHandle,
+ &localIoStatusBlock,
+ &fileAllocationSize,
+ sizeof(fileAllocationSize),
+ FileAllocationInformation );
+
+ if( !NT_SUCCESS(status) )
+ {
+ DbgPrint( "Attempt to extend log file failed: 0x%x\n", status );
+ fileAllocationSize.QuadPart = fileAllocationSize.QuadPart - MemPrintBufferSize;
+ }
+ }
+
+ }
+
+ if( UnloadingDriver )
+ {
+ KeSetEvent( &MemPrintQuitEvent,
+ 2,
+ FALSE );
+ PsTerminateSystemThread( STATUS_SUCCESS );
+ }
+ }
+
+ return;
+
+} // DigiPrintWriteThread
+
+
+
+VOID MemPrintWriteCompleteApc( IN PVOID ApcContext,
+ IN PIO_STATUS_BLOCK IoStatusBlock )
+/*++
+
+Routine Description:
+
+ This APC routine is called when the current write to disk complete.
+ It checks for success, printing a message if the write failed.
+ It also updates BufferOutOffset.
+
+Arguments:
+
+ ApcContext - contains what the CurrentInOffset was when
+ ZwWriteFile was called.
+
+ IoStatusBlock - the status block for the operation.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ KIRQL oldIrql;
+ ULONG NumberBytesWritten=(ULONG)ApcContext;
+
+ if( !NT_SUCCESS(IoStatusBlock->Status) )
+ {
+ DbgPrint( "ZwWriteFile for subbuffer %ld failed: 0x%x\n",
+ ApcContext,
+ IoStatusBlock->Status );
+ return;
+ }
+
+// ASSERT( IoStatusBlock->Information == NumberBytesWritten );
+
+ //
+ // Acquire the spin lock that protects memory print global variables
+ // and set the subbuffer writing boolean to FALSE so that other
+ // threads can write to the subbuffer if necessary.
+ //
+
+ KeAcquireSpinLock( &MemPrintSpinLock, &oldIrql );
+
+ if( BufferOutOffset + IoStatusBlock->Information > MemPrintBufferSize )
+ {
+ BufferOutOffset = ( (BufferOutOffset + IoStatusBlock->Information) -
+ MemPrintBufferSize );
+ }
+ else if( BufferOutOffset + IoStatusBlock->Information < MemPrintBufferSize )
+ {
+ BufferOutOffset += IoStatusBlock->Information;
+ }
+ else
+ {
+ BufferOutOffset = 0;
+ }
+
+// BufferOutOffset += NumberBytesWritten;
+//
+// ASSERT( BufferOutOffset <= MemPrintBufferSize );
+//
+// if( BufferOutOffset == MemPrintBufferSize )
+// BufferOutOffset = 0;
+
+ KeReleaseSpinLock( &MemPrintSpinLock, oldIrql );
+
+ return;
+
+} // MemPrintWriteCompleteApc
+
+
diff --git a/private/ntos/ndis/digi/digifile/memprint.h b/private/ntos/ndis/digi/digifile/memprint.h
new file mode 100644
index 000000000..844b8a279
--- /dev/null
+++ b/private/ntos/ndis/digi/digifile/memprint.h
@@ -0,0 +1,73 @@
+/*++ BUILD Version: 0001 // Increment this if a change has global effects
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ memprint.h
+
+Abstract:
+
+ Include file for in-memory DbgPrint function. Including this file
+ will change DbgPrints to a routine which puts the display text in a
+ circular buffer in memory. By default, the text is then sent to the
+ console via DbgPrint. By changing the value of the DigiPrintFlags
+ flag, however, the text may be routed to a file instead, thereby
+ significantly speeding up the DbgPrint operation.
+
+Author:
+
+ David Treadwell (davidtr) 05-Oct-1990
+
+Revision History:
+
+--*/
+
+#ifndef _MEMPRINT_
+#define _MEMPRINT_
+
+#define MEM_PRINT_FLAG_CONSOLE 0x00000001
+#define MEM_PRINT_FLAG_FILE 0x00000002
+#define MEM_PRINT_FLAG_HEADER 0x00000004
+#define MEM_PRINT_FLAG_QUIT 0x00000008
+#define MEM_PRINT_FLAG_NOMEMCHECK 0x80000000
+
+extern ULONG DigiPrintFlags;
+extern UCHAR TurnOffSniffer;
+
+//
+// Exported routines. MemPrintInitialize sets up the circular buffer
+// and other memory, MemPrint writes text to the console and/or a
+// log file, and MemPrintFlush writes the current subbuffer to disk
+// whether or not it is full.
+//
+
+#if DBG
+VOID MemPrintPreInitSettings( PCHAR NewLogFileName,
+ ULONG NewBufferSize );
+
+NTSTATUS MemPrintInitialize ( VOID );
+
+VOID MemPrintQuit ( VOID );
+
+VOID MemPrint ( CHAR *Format, ... );
+
+VOID MemPrintFlush ( VOID );
+
+#define DbgPrint MemPrint
+
+#else
+
+#define MemPrintPreInitSettings( a, b )
+
+#define MemPrintInitialize()
+
+#define MemPrintQuit()
+
+#define MemPrint()
+
+#define MemPrintFlush()
+#endif
+
+#endif // def _MEMPRINT_
+
diff --git a/private/ntos/ndis/digi/digifile/sources b/private/ntos/ndis/digi/digifile/sources
new file mode 100644
index 000000000..36d4e3c03
--- /dev/null
+++ b/private/ntos/ndis/digi/digifile/sources
@@ -0,0 +1,47 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=
+MINORCOMP=
+
+TARGETNAME=digifile
+TARGETPATH=..\lib
+TARGETTYPE=LIBRARY
+
+INCLUDES=..\inc; \
+ $(_NTBINDIR)\private\ntos\inc
+
+SOURCES= \
+ memprint.c \
+ digifile.c \
+ dgatlas.c
+
+NTTARGETFILE0=\
+ ..\lib\* \
+ ..\inc \
+
+NTTARGETFILE1= \
+ ..\inc\digifile.h \
+ ..\inc\memprint.h \
+ ..\inc\dgatlas.h
diff --git a/private/ntos/ndis/digi/dirs b/private/ntos/ndis/digi/dirs
new file mode 100644
index 000000000..175b71bfe
--- /dev/null
+++ b/private/ntos/ndis/digi/dirs
@@ -0,0 +1,27 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=\
+ digifile \
+ pcimac
+
+
diff --git a/private/ntos/ndis/digi/images/adp.bin b/private/ntos/ndis/digi/images/adp.bin
new file mode 100644
index 000000000..ba3812fcf
--- /dev/null
+++ b/private/ntos/ndis/digi/images/adp.bin
Binary files differ
diff --git a/private/ntos/ndis/digi/images/idp_xfs.bin b/private/ntos/ndis/digi/images/idp_xfs.bin
new file mode 100644
index 000000000..cae71d83e
--- /dev/null
+++ b/private/ntos/ndis/digi/images/idp_xfs.bin
Binary files differ
diff --git a/private/ntos/ndis/digi/pcimac/adapter.h b/private/ntos/ndis/digi/pcimac/adapter.h
new file mode 100644
index 000000000..9a6f3b43e
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/adapter.h
@@ -0,0 +1,223 @@
+/*
+ * ADAPTER.H - NDIS Adapter Interface, main include file
+ */
+
+
+#ifndef _ADAPTER_
+#define _ADAPTER_
+
+#define PCIMAC_KEY_BOARDTYPE "BoardType"
+#define PCIMAC_KEY_BASEIO "IOBaseAddress"
+#define PCIMAC_KEY_BASEMEM "MemoryMappedBaseAddress"
+#define PCIMAC_KEY_BOARDNAME "BoardName"
+#define PCIMAC_KEY_LINENAME "LineName"
+#define PCIMAC_KEY_NUMLINES "NumberOfLines"
+#define PCIMAC_KEY_IDPFILENAME "IDPImageFileName"
+#define PCIMAC_KEY_SWITCHSTYLE "SwitchStyle"
+#define PCIMAC_KEY_TERMINALMANAGEMENT "TerminalManagement"
+#define PCIMAC_KEY_NUMLTERMS "LogicalTerminals"
+#define PCIMAC_KEY_TEI "TEI"
+#define PCIMAC_KEY_SPID "SPID"
+#define PCIMAC_KEY_ADDRESS "Address"
+#define PCIMAC_KEY_LINE "Line"
+#define PCIMAC_KEY_LTERM "LTerm"
+#define PCIMAC_KEY_WAITFORL3 "WaitForL3"
+#define PCIMAC_KEY_GENERICDEFINES "GenericDefines"
+
+/* global driver obect */
+typedef struct tagDRIVER_BLOCK
+{
+ NDIS_HANDLE NdisMacHandle;
+ NDIS_HANDLE NdisWrapperHandle;
+ struct _ADAPTER* AdapterTbl[MAX_ADAPTERS_IN_SYSTEM];
+ ULONG InDriverFlag;
+ ULONG NumberOfAdaptersInSystem;
+ ULONG NextAdapterToPoll;
+ struct _ADAPTER* CurrentAdapter;
+ NDIS_SPIN_LOCK lock;
+} DRIVER_BLOCK;
+
+typedef struct _ADAPTER
+{
+ NDIS_HANDLE Handle;
+// ULONG InDriverFlag;
+// NDIS_SPIN_LOCK InDriverLock;
+ CHAR Name[64];
+ ULONG BaseIO;
+ PVOID VBaseIO;
+ ULONG BaseMem;
+ PVOID VBaseMem;
+ ULONG BoardType;
+ ULONG TapiBaseID;
+ ULONG NumberOfIddOnAdapter;
+ ULONG LastIddPolled;
+ VOID *TapiLineInfo[MAX_CM_PER_ADAPTER]; // 8
+ VOID *IddTbl[MAX_IDD_PER_ADAPTER]; // 4
+ VOID *CmTbl[MAX_CM_PER_ADAPTER]; // 8
+ VOID *MtlTbl[MAX_MTL_PER_ADAPTER]; // 8
+ NDIS_MINIPORT_TIMER IddPollTimer; // idd polling timer
+ NDIS_MINIPORT_TIMER MtlPollTimer; // mtl polling timer
+ NDIS_MINIPORT_TIMER CmPollTimer; // cm polling timer
+}ADAPTER;
+
+typedef struct _CONFIGPARAM
+{
+ INT ParamType;
+ CHAR String[512];
+ ULONG StringLen;
+ ULONG Value;
+ ULONG MustBePresent;
+ NDIS_HANDLE ConfigHandle;
+ NDIS_HANDLE AdapterHandle;
+} CONFIGPARAM;
+
+VOID StopTimers(ADAPTER* Adapter);
+VOID StartTimers(ADAPTER* Adapter);
+
+//VOID
+//SetInDriverFlag(
+// ADAPTER *Adapter
+// );
+//
+//VOID
+//ClearInDriverFlag(
+// ADAPTER *Adapter
+// );
+//
+//ULONG
+//CheckInDriverFlag(
+// ADAPTER *Adapter
+// );
+
+VOID
+SetInDriverFlag(
+ ADAPTER *Adapter
+ );
+
+VOID
+ClearInDriverFlag(
+ ADAPTER *Adapter
+ );
+
+ULONG
+CheckInDriverFlag(
+ ADAPTER *Adapter
+ );
+
+BOOLEAN
+PcimacCheckForHang(
+ NDIS_HANDLE AdapterContext
+ );
+
+VOID
+PcimacHalt(
+ NDIS_HANDLE AdapterContext
+ );
+
+NDIS_STATUS
+PcimacInitialize(
+ PNDIS_STATUS OpenErrorStatus,
+ PUINT SelectMediumIndex,
+ PNDIS_MEDIUM MediumArray,
+ UINT MediumArraySize,
+ NDIS_HANDLE AdapterHandle,
+ NDIS_HANDLE WrapperConfigurationContext
+ );
+
+NDIS_STATUS
+PcimacSetQueryInfo(
+ NDIS_HANDLE AdapterContext,
+ NDIS_OID Oid,
+ PVOID InfoBuffer,
+ ULONG InfoBufferLen,
+ PULONG BytesWritten,
+ PULONG BytesNeeded
+ );
+
+NDIS_STATUS
+PcimacReconfigure(
+ PNDIS_STATUS OpenErrorStatus,
+ NDIS_HANDLE AdapterContext,
+ NDIS_HANDLE WrapperConfigurationContext
+ );
+
+NDIS_STATUS
+PcimacReset(
+ PBOOLEAN AddressingReset,
+ NDIS_HANDLE AdapterContext
+ );
+
+NDIS_STATUS
+PcimacSend(
+ NDIS_HANDLE MacBindingHandle,
+ NDIS_HANDLE LinkContext,
+ PNDIS_WAN_PACKET WanPacket
+ );
+
+INT
+IoEnumAdapter(
+ VOID *cmd_1
+ );
+
+ADAPTER*
+GetAdapterByIndex(
+ ULONG Index
+ );
+
+ULONG
+EnumAdaptersInSystem(
+ VOID
+ );
+
+ADAPTER*
+GetNextAdapter(
+ ADAPTER *Adapter
+ );
+
+VOID
+AdapterDestroy(
+ ADAPTER *Adapter
+ );
+
+NDIS_STATUS
+WanOidProc(
+ NDIS_HANDLE AdapterContext,
+ NDIS_OID Oid,
+ PVOID InfoBuffer,
+ ULONG InfoBufferLen,
+ PULONG BytesReadWritten,
+ PULONG BytesNeeded
+ );
+
+NDIS_STATUS
+TapiOidProc(
+ NDIS_HANDLE AdapterContext,
+ NDIS_OID Oid,
+ PVOID InfoBuffer,
+ ULONG InfoBufferLen,
+ PULONG BytesWritten,
+ PULONG BytesNeeded
+ );
+
+NDIS_STATUS
+LanOidProc(
+ NDIS_HANDLE AdapterContext,
+ NDIS_OID Oid,
+ PVOID InfoBuffer,
+ ULONG InfoBufferLen,
+ PULONG BytesReadWritten,
+ PULONG BytesNeeded
+ );
+
+
+#if DIGIASSERT
+#undef ASSERT
+#define ASSERT( STRING ) \
+ if( !(STRING) ) \
+ { \
+ DbgPrint( "ASSERT failed: " #STRING "\nfile: %s, line %d\n", __FILE__, __LINE__ ); \
+ DbgBreakPoint(); \
+ }
+#endif
+
+#endif /* _ADAPTER_ */
diff --git a/private/ntos/ndis/digi/pcimac/ansihelp.c b/private/ntos/ndis/digi/pcimac/ansihelp.c
new file mode 100644
index 000000000..1886e88d1
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/ansihelp.c
@@ -0,0 +1,487 @@
+
+#include <ndis.h>
+//#include <ansihelp.h>
+
+#define _XA 0x200
+#define _XS 0x100
+#define _BB 0x80
+#define _CN 0x40
+#define _DI 0x20
+#define _LO 0x10
+#define _PU 0x08
+#define _SP 0x04
+#define _UP 0x02
+#define _XD 0x01
+#define XDI (_DI | _XD)
+#define XLO (_LO | _XD)
+#define XUP (_UP | _XD)
+
+static const SHORT CTypeTable[257] = {
+ 0,
+ _BB, _BB, _BB, _BB, _BB, _BB, _BB, _BB,
+ _BB, _CN, _CN, _CN, _CN, _CN, _BB, _BB,
+ _BB, _BB, _BB, _BB, _BB, _BB, _BB, _BB,
+ _BB, _BB, _BB, _BB, _BB, _BB, _BB, _BB,
+ _SP, _PU, _PU, _PU, _PU, _PU, _PU, _PU,
+ _PU, _PU, _PU, _PU, _PU, _PU, _PU, _PU,
+ XDI, XDI, XDI, XDI, XDI, XDI, XDI, XDI,
+ XDI, XDI, _PU, _PU, _PU, _PU, _PU, _PU,
+ _PU, XUP, XUP, XUP, XUP, XUP, XUP, _PU,
+ _UP, _UP, _UP, _UP, _UP, _UP, _UP, _UP,
+ _UP, _UP, _UP, _UP, _UP, _UP, _UP, _UP,
+ _UP, _UP, _UP, _PU, _PU, _PU, _PU, _PU,
+ _PU, XLO, XLO, XLO, XLO, XLO, XLO, _LO,
+ _LO, _LO, _LO, _LO, _LO, _LO, _LO, _LO,
+ _LO, _LO, _LO, _LO, _LO, _LO, _LO, _LO,
+ _LO, _LO, _LO, _PU, _PU, _PU, _PU, _BB, };
+
+const SHORT *_Ctype = &CTypeTable[1];
+
+#define BASE_MAX 36
+static const CHAR digits[] = {"0123456789abcdefghijklmnopqrstuvwxyz"};
+static const CHAR ndigs[BASE_MAX+1] = {
+ 0, 0, 33, 21, 17, 14, 13, 12, 11, 11,
+ 10, 10, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8,
+ 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7 };
+
+ULONG __Stoul (const CHAR *s, CHAR **endptr, INT base);
+
+/******************************************************************************
+
+ @doc INTERNAL
+
+ @internal ULONG | __strlen | string length
+
+ @parm PUCHAR | str | the string.
+
+ @rdesc ULONG | the length of the string.
+
+******************************************************************************/
+ULONG
+__strlen(PUCHAR str)
+{
+ ULONG len = 0;
+
+ if (str == NULL) {
+ return(0);
+ }
+
+ while (str[len] != '\0') {
+ len++;
+ }
+
+ return(len);
+
+} // end of __strlen
+
+
+/******************************************************************************
+
+ @doc INTERNAL
+
+ @internal LONG | __strcmp | compare strings
+
+ @parm PUCHAR | str1 | one string.
+
+ @parm PUCHAR | str2 | another string.
+
+ @rdesc ULONG | the comparison result.
+
+******************************************************************************/
+LONG
+__strcmp(PUCHAR str1, PUCHAR str2)
+{
+ ULONG len = 0;
+
+ if (str1 == str2) {
+ return(0);
+ }
+ if ((str1 == NULL) || (str2 == NULL)) {
+ return(-1);
+ }
+
+ while ((str1[len] == str2[len]) && (str1[len] != '\0') &&
+ (str2[len] != '\0')) {
+ len++;
+ }
+
+ if (str1[len] == str2[len]) {
+ return(0);
+ } else if (str1[len] < str2[len]) {
+ return(-1);
+ } else {
+ return(1);
+ }
+
+} // end of __strcmp
+
+
+/******************************************************************************
+
+ @doc INTERNAL
+
+ @internal LONG | __strncmp | compare strings
+
+ @parm PUCHAR | str1 | one string.
+
+ @parm PUCHAR | str2 | another string.
+
+ @parm ULONG | count | maximum characters to compare
+
+ @rdesc ULONG | the comparison result.
+
+******************************************************************************/
+LONG
+__strncmp(PUCHAR str1, PUCHAR str2, ULONG count)
+{
+ ULONG len = 0;
+
+ if (str1 == str2) {
+ return(0);
+ }
+ if ((str1 == NULL) || (str2 == NULL)) {
+ return(-1);
+ }
+
+ while (count-- && (str1[len] == str2[len]) && (str1[len] != '\0') &&
+ (str2[len] != '\0')) {
+ len++;
+ }
+
+ if (count == 0) {
+ len--;
+ }
+ if (str1[len] == str2[len]) {
+ return(0);
+ } else if (str1[len] < str2[len]) {
+ return(-1);
+ } else {
+ return(1);
+ }
+
+} // end of __strncmp
+
+
+/******************************************************************************
+
+ @doc INTERNAL
+
+ @internal LONG | __strnicmp | compare strings (case insensitive)
+
+ @parm PUCHAR | str1 | one string.
+
+ @parm PUCHAR | str2 | another string.
+
+ @parm ULONG | count | maximum characters to compare
+
+ @rdesc ULONG | the comparison result.
+
+******************************************************************************/
+LONG
+__strnicmp(PUCHAR str1, PUCHAR str2, ULONG count)
+{
+ ULONG len = 0;
+
+ if (str1 == str2) {
+ return(0);
+ }
+ if ((str1 == NULL) || (str2 == NULL)) {
+ return(-1);
+ }
+
+ while (count-- && (str1[len] == str2[len]) && (str1[len] != '\0') &&
+ (str2[len] != '\0')) {
+ len++;
+ }
+
+ if (count == 0) {
+ len--;
+ }
+ if (str1[len] == str2[len]) {
+ return(0);
+ } else if (str1[len] < str2[len]) {
+ return(-1);
+ } else {
+ return(1);
+ }
+
+} // end of __strnicmp
+
+
+
+
+
+/******************************************************************************
+
+ @doc INTERNAL
+
+ @internal PUCHAR | __strncpy | copy strings
+
+ @parm PUCHAR | str1 | one string.
+
+ @parm PUCHAR | str2 | another string.
+
+ @parm ULONG | count | maximum characters to copy
+
+ @rdesc ULONG |
+
+******************************************************************************/
+PUCHAR
+__strncpy(PUCHAR str1, PUCHAR str2, ULONG count)
+{
+ PUCHAR tmp = str1;
+
+ if (str1 && str2 && *str2 && count) {
+ while (count-- && (*str2 != '\0')) {
+ *str1++ = *str2++;
+ }
+ *str1 = '\0';
+ }
+
+
+ return (tmp);
+} // end of __strncpy
+
+
+
+
+/******************************************************************************
+
+ @doc INTERNAL
+
+ @internal PUCHAR | __strcpy | copy strings
+
+ @parm PUCHAR | str1 | one string.
+
+ @parm PUCHAR | str2 | another string.
+
+ @rdesc PUCHAR | the comparison result.
+
+******************************************************************************/
+PUCHAR
+__strcpy(PUCHAR str1, PUCHAR str2)
+{
+ PUCHAR tmp = str1;
+
+ if (str1 && str2 && *str2) {
+ while (*str2 != '\0') {
+ *str1++ = *str2++;
+ }
+ *str1 = *str2;
+ }
+
+ return (tmp);
+} // end of __strcpy
+
+
+
+/******************************************************************************
+
+ @doc INTERNAL
+
+ @internal PUCHAR | __strstr | search for substring with another string
+
+ @parm PUCHAR | str1 | source string.
+
+ @parm PUCHAR | str2 | substring string.
+
+ @rdesc PUCHAR |
+
+******************************************************************************/
+PUCHAR
+__strstr(PUCHAR str1, PUCHAR str2)
+{
+ return (NULL);
+} // end of __strstr
+
+
+
+/******************************************************************************
+
+ @doc INTERNAL
+
+ @internal PUCHAR | __memchr | search for char within buffer[0..count]
+
+ @parm PUCHAR | buffer | starting address.
+
+ @parm CHAR | chr | chr
+
+ @parm ULONG | count | count
+
+ @rdesc PUCHAR |
+
+******************************************************************************/
+PUCHAR
+__memchr(PUCHAR buffer, CHAR chr, ULONG count)
+{
+ ULONG len = 0;
+
+ if (buffer == NULL) {
+ return(NULL);
+ }
+
+ while ((len<count) && (buffer[len] != chr)) {
+ len++;
+ }
+
+ return ((len<count)?(buffer+len):NULL);
+} // end of __memchr
+
+
+
+/******************************************************************************
+
+ @doc INTERNAL
+
+ @internal PUCHAR | __strchr | search for char within a string
+
+ @parm PUCHAR | str1 | source string.
+
+ @parm CHAR | chr | chr
+
+ @rdesc PUCHAR |
+
+******************************************************************************/
+PUCHAR
+__strchr(PUCHAR str1, CHAR chr)
+{
+ ULONG len = 0;
+
+ if (str1 == NULL) {
+ return(NULL);
+ }
+
+ while ((str1[len] != '\0') && (str1[len] != chr)) {
+ len++;
+ }
+
+ return ((str1[len])?(str1+len):NULL);
+} // end of __strchr
+
+
+
+/******************************************************************************
+
+ @doc INTERNAL
+
+ @internal PUCHAR | __strrchr | reverse search for char within a string
+
+ @parm PUCHAR | str1 | source string.
+
+ @parm CHAR | chr | chr
+
+ @rdesc PUCHAR |
+
+******************************************************************************/
+PUCHAR
+__strrchr(PUCHAR str1, CHAR chr)
+{
+ ULONG len = 0;
+
+ return(NULL);
+
+} // end of __strrchr
+
+
+
+/******************************************************************************
+
+ @doc INTERNAL
+
+ @internal PUCHAR | __strlwr | convert a string to lowercase
+
+ @parm PUCHAR | str1 | source string.
+
+ @rdesc PUCHAR |
+
+******************************************************************************/
+PUCHAR
+__strlwr(PUCHAR str1)
+{
+ for( ; str1 != NULL, *str1 != '\0'; str1++ )
+ *str1 = tolower( *str1 );
+
+ return( str1 );
+} // end of __strlwr
+
+ULONG
+__strtoul (const CHAR *s, INT base)
+{
+ return(__Stoul (s, (CHAR **)NULL, base));
+}
+
+ULONG
+__Stoul (const CHAR *s, CHAR **endptr, INT base)
+{
+ const CHAR *sc, *sd;
+ const CHAR *s1, *s2;
+ CHAR sign;
+ LONG n;
+ ULONG x, y;
+
+ for (sc = s; isspace (*sc); ++sc);
+
+ sign = *sc == '-' || *sc == '+' ? *sc++ : '+';
+
+ if (base < 0 || base == 1 || BASE_MAX < base)
+ {
+ if (endptr)
+ *endptr = (CHAR *)s;
+ return( (ULONG)-1 );
+ }
+ else if (base)
+ {
+ if (base == 16 && *sc == '0' && (sc[1] == 'x' || sc[1] == 'X'))
+ sc += 2;
+ }
+ else if (*sc != '0')
+ base = 10;
+ else if (sc[1] == 'x' || sc[1] == 'X')
+ {
+ base = 16;
+ sc += 2;
+ }
+ else
+ base = 8;
+ for (s1 = sc; *sc == '0'; ++sc );
+ x = 0;
+ for (s2 = sc; (sd = memchr (digits, (INT)tolower(*sc), (UINT)base)) != NULL; ++sc)
+ {
+ y = x;
+ x = x * base + (sd - digits);
+ }
+ if (s1 == sc)
+ {
+ if (endptr)
+ *endptr = (CHAR *)s;
+ return( (ULONG)-1 );
+ }
+ n = sc - s2 - ndigs[base];
+ if (n < 0)
+ ;
+ else if (0 < n || x < x - sc[-1] || (x - sc[-1]) / base != y)
+ {
+ // overflow
+ x = 0xFFFFFFFF;
+ }
+ if (sign == '-')
+ x = (ULONG)(0 - x);
+ if (endptr)
+ *endptr = (CHAR *)sc;
+ return(x);
+}
+
+INT
+__isspace (INT c)
+{
+ return(_Ctype[(INT)c] & (_CN | _SP | _XS));
+}
+
+PCHAR
+__vsprintf()
+{
+ return( NULL );
+}
+
+
diff --git a/private/ntos/ndis/digi/pcimac/ansihelp.h b/private/ntos/ndis/digi/pcimac/ansihelp.h
new file mode 100644
index 000000000..c358f7247
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/ansihelp.h
@@ -0,0 +1,109 @@
+#if !BINARY_COMPATIBLE
+// Building for NT
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define __strlen strlen
+#define __strcmp strcmp
+#define __strncmp strncmp
+#define __strnicmp _strnicmp
+#define __strncpy strncpy
+#define __strcpy strcpy
+#define __strstr strstr
+#define __memchr memchr
+#define __strchr strchr
+#define __strrchr strrchr
+#define __strlwr _strlwr
+#define __strtoul strtoul
+#define __isspace isspace
+
+#else
+// Building for Windows
+
+
+#undef tolower
+#undef toupper
+#undef isxdigit
+#undef isdigit
+#undef ctox
+
+#define _tolower(_c) ( (_c)-'A'+'a' )
+#define tolower(_c) ( ((_c) >= 'A' && (_c) <= 'Z') ? _tolower (_c) : (_c) )
+#define toupper(ch) (((ch >= 'a') && (ch <= 'z')) ? ch-'a'+'A':ch)
+#define isxdigit(ch) (((ch >= 'a') && (ch <= 'f')) || ((ch >= 'A') && (ch <= 'F')) || ((ch >= '0') && (ch <= '9')))
+#define isdigit(ch) ((ch >= '0') && (ch <= '9'))
+#define ctox(ch) (((ch >='0') && (ch <= '9')) ? ch-'0': toupper(ch)-'A'+10)
+
+ULONG __strlen(PUCHAR str);
+
+LONG __strcmp(PUCHAR str1, PUCHAR str2);
+
+LONG __strncmp(PUCHAR str1, PUCHAR str2, ULONG count);
+
+LONG __strnicmp(PUCHAR str1, PUCHAR str2, ULONG count);
+
+PUCHAR __strncpy(PUCHAR str1, PUCHAR str2, ULONG count);
+
+PUCHAR __strcpy(PUCHAR str1, PUCHAR str2);
+
+PUCHAR __strstr(PUCHAR str1, PUCHAR str2);
+
+PUCHAR __memchr(PUCHAR buffer, CHAR chr, ULONG count);
+
+PUCHAR __strchr(PUCHAR str1, CHAR chr);
+
+PUCHAR __strrchr(PUCHAR str1, CHAR chr);
+
+PUCHAR __strlwr(PUCHAR str1);
+
+ULONG sprintf(PUCHAR str, PUCHAR format, ...);
+
+ULONG __strtoul (const CHAR *s, INT base);
+
+INT __isspace (INT c);
+
+PCHAR __vsprintf();
+
+NTSTATUS
+RtlAnsiStringToUnicodeString(
+ OUT PUNICODE_STRING DestinationString,
+ IN PANSI_STRING SourceString,
+ IN BOOLEAN AllocateDestinationString
+ );
+
+
+NTSTATUS
+RtlUnicodeStringToAnsiString(
+ OUT PANSI_STRING DestinationString,
+ IN PUNICODE_STRING SourceString,
+ IN BOOLEAN AllocateDestinationString
+ );
+
+VOID
+RtlFreeUnicodeString(
+ IN OUT PUNICODE_STRING UnicodeString
+ );
+
+VOID
+RtlFreeAnsiString(
+ IN OUT PANSI_STRING AnsiString
+ );
+
+
+
+VOID
+RtlInitAnsiString(
+ OUT PANSI_STRING DestinationString,
+ IN PUCHAR SourceString OPTIONAL
+ );
+
+
+VOID
+RtlInitUnicodeString(
+ OUT PUNICODE_STRING DestinationString,
+ IN PWSTR SourceString OPTIONAL
+ );
+
+
+#endif
diff --git a/private/ntos/ndis/digi/pcimac/cm.h b/private/ntos/ndis/digi/pcimac/cm.h
new file mode 100644
index 000000000..4478d0b1e
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/cm.h
@@ -0,0 +1,162 @@
+/*
+ * CM.H - definitions for connection manager
+ */
+
+#ifndef _CM_
+#define _CM_
+
+#include <ndistapi.h>
+#include <cm_pub.h>
+
+/* error codes */
+#define CM_E_SUCC 0 /* success, ok */
+#define CM_E_NOSLOT 1 /* no slot available error */
+#define CM_E_BUSY 2 /* cm context is busy */
+#define CM_E_NOSUCH 3 /* no such object */
+#define CM_E_BADCHAN 4 /* bad channel argument */
+#define CM_E_IDD 5 /* idd command errored */
+#define CM_E_NOMEM 6 /* ran out of memory */
+#define CM_E_NOTIMPL 7 /* functionalit not implemented yet */
+#define CM_E_BADPARAM 8 /* bad parameter */
+#define CM_E_BADSTATE 9 /* bad state */
+#define CM_E_BADUUS 10 /* bad user-to-user signalling packet */
+#define CM_E_BADPORT 11 /* bad nai given */
+
+//
+// q931 switch styles
+//
+#define CM_SWITCHSTYLE_NONE 0 // no style
+#define CM_SWITCHSTYLE_AUTO 1 // auto detect
+#define CM_SWITCHSTYLE_NI1 2 // national isdn 1
+#define CM_SWITCHSTYLE_ATT 3 // at&t 5ess
+#define CM_SWITCHSTYLE_NTI 4 // northern telecom dms100
+#define CM_SWITCHSTYLE_NET3 5 // net3 (europe)
+#define CM_SWITCHSTYLE_1TR6 6 // 1tr6 (german)
+#define CM_SWITCHSTYLE_VN3 7 // vn3 (france)
+#define CM_SWITCHSTYLE_INS64 8 // ins64 (japan)
+
+//
+// local cm def's
+//
+/* map a channel to signaling idd port */
+#define CM_PORT(_chan) ((_chan)->lterm + IDD_PORT_CM0_TX)
+
+/* user to user signaling structure (!must be byte alligned!) */
+#pragma pack(2)
+typedef struct
+{
+ CHAR dst_addr[6]; /* destination address */
+ CHAR src_addr[6]; /* source address */
+ USHORT pkt_type; /* packet type field */
+#define CM_PKT_TYPE 0x5601 /* - private packet type */
+ UCHAR prot_desc; /* protocol descriptor field */
+#define CM_PROT_DESC 0x78 /* - private protoocl descriptor */
+ UCHAR opcode; /* opcode fields */
+#define CM_ASSOC_RQ 0x01 /* - request for chan/conn assoc */
+#define CM_ASSOC_ACK 0x02 /* - assoc ack'ed */
+#define CM_ASSOC_NACK 0x03 /* - assoc not ack'ed */
+ UCHAR cause; /* cause value, to assist in diag */
+#define CM_NO_PROF 0x01 /* - no matching profile */
+#define CM_NO_CONN 0x02 /* - no connection slot avail */
+#define CM_NO_CHAN 0x03 /* - no channel slot avail */
+#define CM_DUP_CONN 0x04 /* - dup conn name */
+ UCHAR conn; /* connection index */
+ UCHAR channum; /* # of channels in connections */
+ UCHAR chan; /* channel index */
+ CHAR lname[24]; /* local profile name */
+ ULONG option_0; // uus option fields
+#define UUS_0_COMPRESSION 0x00004000
+#define COMP_TX_ENA 0x01
+#define COMP_RX_ENA 0x02
+ ULONG option_1;
+ CHAR rname[24]; /* remote profile name */
+ ULONG option_2;
+ ULONG option_3;
+ UCHAR chksum; /* zero checksum field */
+} CM_UUS;
+#pragma pack()
+
+/* C compiler fails go generate odd sized structures!, must defined by self */
+#define CM_UUS_SIZE (sizeof(CM_UUS) - 1)
+
+/* special channel ustates */
+#define CM_US_UNDEF (USHORT)(-1) /* undefined, not known yet */
+#define CM_US_WAIT_CID (USHORT)(-2) /* waiting for a cid */
+#define CM_US_GAVE_UP (USHORT)(-4) /* gave up on this channel */
+#define CM_US_WAIT_CONN 50 /* connected, waiting on other */
+#define CM_US_UUS_SEND 51 /* sending uus now */
+#define CM_US_UUS_OKED 52 /* uus oked by side, wait on other */
+#define CM_US_CONN 53 /* connected */
+
+
+/* CM class operation prototypes */
+INT cm_init(VOID);
+INT cm_term(VOID);
+INT cm_register_idd(VOID* idd);
+INT cm_deregister_idd(VOID* idd);
+
+/* CM object operation prototypes */
+INT cm_create(VOID** cm_1, NDIS_HANDLE AdapterHandle);
+INT cm_destroy(VOID* cm_1);
+INT cm_set_profile(VOID* cm_1, CM_PROF* prof);
+INT cm_get_profile(VOID* cm_1, CM_PROF* prof);
+INT cm_listen(VOID* cm_1);
+INT cm_connect(VOID* cm_1);
+INT cm_disconnect(VOID* cm_1);
+INT cm_get_status(VOID* cm_1, CM_STATUS* stat);
+INT cm_report_frame(VOID* cm_1, BOOL is_rx, CHAR* buf, ULONG len);
+
+/* prototypes for internal functions */
+VOID cm__q931_handler(IDD* idd, USHORT chan, ULONG Reserved, IDD_MSG* msg);
+VOID cm__q931_bchan_handler(VOID* idd, USHORT chan, ULONG RxFrameType, IDD_XMSG* msg);
+VOID cm__q931_cmpl_handler(VOID* idd, USHORT chan, IDD_MSG* msg);
+INT cm__elem_rq(VOID* idd, USHORT port, CHAR* elem, USHORT elem_num);
+INT cm__initiate_conn(CM* cm);
+INT cm__disc_rq(CM_CHAN* chan);
+INT cm__est_rq(CM_CHAN* chan);
+INT cm__est_rsp(CM_CHAN* chan);
+INT cm__est_ignore(PVOID idd, USHORT cid, USHORT lterm);
+INT cm__deactivate_conn(CM* cm, BOOL by_idle_timer);
+INT cm__activate_conn(CM* cm, ULONG CompressionFlag);
+INT cm__bchan_ctrl(CM_CHAN* chan, BOOL turn_on);
+INT cm__bchan_ctrl_comp(CM_CHAN *chan, ULONG CompressionFlag);
+CM_CHAN* cm__map_chan(VOID* idd, USHORT lterm, USHORT cid);
+CM_CHAN* cm__map_bchan_chan(VOID* idd, USHORT port);
+INT cm__ans_est_ind(CM_CHAN* chan, IDD_MSG* msg, VOID* idd, USHORT lterm);
+INT cm__org_cid_ind(CM_CHAN* chan, IDD_MSG* msg);
+INT cm__org_state_ind(CM_CHAN* chan, IDD_MSG* msg);
+INT cm__ans_state_ind(CM_CHAN* chan, IDD_MSG* msg);
+INT cm__org_elem_ind(CM_CHAN* chan, IDD_MSG* msg);
+INT cm__org_data_ind(CM_CHAN* chan, IDD_MSG* msg);
+INT cm__ans_data_ind(CM_CHAN* chan, IDD_MSG* msg);
+UCHAR cm__calc_chksum(VOID* buf_1, INT len);
+CM* cm__get_conn(ULONG conn_index);
+INT cm__get_next_chan(CM_CHAN* chan);
+INT cm__tx_uus_pkt(CM_CHAN *chan, UCHAR opcode, UCHAR cause);
+INT cm__get_bchan(IDD_MSG* msg, USHORT* bchan);
+INT cm__get_type(IDD_MSG* msg, USHORT* type);
+INT cm__get_addr(IDD_MSG* msg, CHAR addr[32]);
+ULONG cm__type2speed(USHORT type);
+UCHAR *cm__q931_elem(VOID* ptr_1, INT len, UCHAR elem);
+INT cm__timer_tick(CM* cm);
+CM_CHAN *cm__chan_alloc(VOID);
+VOID cm__chan_free(CM_CHAN* chan);
+BOOL cm__chan_foreach(BOOL (*func)(), VOID* a1, VOID* a2);
+BOOL cm__inc_chan_num(CM_CHAN* chan, CM_CHAN* ref_chan, ULONG *chan_num);
+BOOL cm__add_chan(CM_CHAN* chan, CM_CHAN* ref_chan, CM* cm);
+CM* cm__find_listen_conn(CHAR* lname, CHAR* rname, CHAR* addr, VOID*);
+VOID ChannelInit(VOID);
+VOID ChannelTerm(VOID);
+VOID cm__ppp_conn(VOID *idd, USHORT port);
+INT WanLineup(VOID* cm_1, NDIS_HANDLE Endpoint);
+INT WanLinedown(VOID* cm_1);
+ULONG EnumCmInSystem(VOID);
+ULONG EnumCmPerAdapter(ADAPTER*);
+INT IoEnumCm(VOID* cmd_1);
+VOID* CmGetMtl(VOID* cm_1);
+UCHAR* GetDstAddr(VOID *cm_1);
+UCHAR* GetSrcAddr(VOID *cm_1);
+VOID CmPollFunction(VOID *a1, ADAPTER *Adapter, VOID *a3, VOID *a4);
+VOID CmSetSwitchStyle(CHAR *SwitchStyle);
+
+#endif /* _CM_ */
diff --git a/private/ntos/ndis/digi/pcimac/cm_chan.c b/private/ntos/ndis/digi/pcimac/cm_chan.c
new file mode 100644
index 000000000..b07b9a52d
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/cm_chan.c
@@ -0,0 +1,106 @@
+/*
+ * CM_CHAN.C - channel allocation (for incoming) code
+ */
+
+#include <ndis.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+
+CM_CHAN *chan_tbl;
+BOOL chan_used[MAX_CHAN_IN_SYSTEM];
+
+
+#pragma NDIS_INIT_FUNCTION(ChannelInit)
+
+//
+// Allocate free channel pool
+//
+VOID
+ChannelInit(VOID)
+{
+ NDIS_PHYSICAL_ADDRESS pa = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
+
+ /* allocate memory object */
+ NdisAllocateMemory((PVOID*)&chan_tbl, sizeof(CM_CHAN) * MAX_CHAN_IN_SYSTEM, 0, pa);
+ if ( chan_tbl == NULL )
+ {
+ D_LOG(D_ALWAYS, ("ChannelInit: memory allocate failed!"));
+ return;
+ }
+ D_LOG(D_ALWAYS, ("ChannelInit: chan_tbl: 0x%x", chan_tbl));
+ NdisZeroMemory (chan_tbl, sizeof(CM_CHAN) * MAX_CHAN_IN_SYSTEM);
+ NdisZeroMemory (chan_used, sizeof(chan_used));
+}
+
+VOID
+ChannelTerm(VOID)
+{
+ /* free memory */
+ NdisFreeMemory(chan_tbl, sizeof(CM_CHAN) * MAX_CHAN_IN_SYSTEM, 0);
+}
+
+/* allocate a channel */
+CM_CHAN*
+cm__chan_alloc(VOID)
+{
+ CM_CHAN *chan = NULL;
+ INT n;
+
+ D_LOG(D_ENTRY, ("cm__chan_alloc: entry"));
+
+ for ( n = 0 ; n < MAX_CHAN_IN_SYSTEM ; n++ )
+ if ( !chan_used[n] )
+ {
+ chan_used[n] = TRUE;
+ chan = chan_tbl + n;
+ break;
+ }
+
+ D_LOG(D_EXIT, ("cm__alloc_chan: exit, chan: 0x%lx", chan));
+ return(chan);
+}
+
+/* free a channel */
+VOID
+cm__chan_free(CM_CHAN *chan)
+{
+ D_LOG(D_ENTRY, ("cm__chan_free: entry, chan: 0x%lx", chan));
+
+ chan_used[chan - chan_tbl] = FALSE;
+}
+
+/* call a callback function for each used channel */
+BOOL
+cm__chan_foreach(BOOL (*func)(), VOID *a1, VOID *a2)
+{
+ INT n;
+ BOOL ret = TRUE;
+
+ D_LOG(D_ENTRY, ("cm__chan_foreach: entry, func: %lx, a1: 0x%lx, a2: 0x%lx", \
+ func, a1, a2));
+
+ for ( n = 0 ; n < MAX_CHAN_IN_SYSTEM ; n++ )
+ if ( chan_used[n] )
+ {
+ CM_CHAN *chan = chan_tbl + n;
+
+ D_LOG(D_ALWAYS, ("cm__chan_foreach: calling for chan# %d, channel: %lx", n, chan));
+
+ ret = (*func)(chan, a1, a2);
+
+ D_LOG(D_ALWAYS, ("cm__chan_foreach: returned %d", ret));
+
+ if ( !ret )
+ break;
+ }
+
+ return(ret);
+}
diff --git a/private/ntos/ndis/digi/pcimac/cm_conn.c b/private/ntos/ndis/digi/pcimac/cm_conn.c
new file mode 100644
index 000000000..66bf2cd8d
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/cm_conn.c
@@ -0,0 +1,323 @@
+/*
+ * CM_CONN.C - connection managment code
+ */
+
+#include <ndis.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+
+/* mark connection as ready to accept calls (listening mode) */
+INT
+cm_listen(VOID *cm_1)
+{
+ CM *cm = (CM*)cm_1;
+ D_LOG(D_ENTRY, ("cm_listen: entry, cm: 0x%lx", cm));
+
+ /* connection must be idle */
+ if ( cm->state != CM_ST_IDLE )
+ return(CM_E_BUSY);
+
+ /* mark & return */
+ cm->dprof = cm->oprof;
+ cm->state = CM_ST_LISTEN;
+ cm->StateChangeFlag = TRUE;
+ cm->PPPToDKF = 0;
+ return(CM_E_SUCC);
+}
+
+/* initiate a connection */
+INT
+cm_connect(VOID *cm_1)
+{
+#define ABORT(_ret) { ret = _ret; goto aborting; }
+ CM *cm = (CM*)cm_1;
+ ULONG n;
+ INT ret = CM_E_SUCC;
+
+ D_LOG(D_ENTRY, ("cm_connect: entry, cm: 0x%lx", cm));
+
+ /* connection must be idle or listening */
+ if ( (cm->state != CM_ST_IDLE) && (cm->state != CM_ST_LISTEN) )
+ return(CM_E_BUSY);
+
+ /* switch connection state to waiting for activation for now */
+ cm->state = CM_ST_WAIT_ACT;
+ cm->StateChangeFlag = TRUE;
+
+ /* copy original profile to dynamic */
+ cm->dprof = cm->oprof;
+
+
+ /* initialize other fields */
+ cm->was_listen = 0;
+ cm->active_chan_num = 0;
+ cm->speed = 0;
+ cm->rx_last_frame_time = cm->tx_last_frame_time = ut_time_now();
+ cm->timeout = cm->rx_last_frame_time;
+ cm->remote_conn_index = 0xff;
+ cm->CauseValue = 0x7F;
+ cm->SignalValue = 0xFF;
+ cm->NoActiveLine = 0;
+ cm->PPPToDKF = 0;
+ NdisZeroMemory(cm->DstAddr, sizeof(cm->DstAddr));
+ NdisZeroMemory(cm->remote_name, sizeof(cm->remote_name));
+
+ /* init & check channel vector */
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++ )
+ {
+ CM_CHAN *chan = cm->dprof.chan_tbl + n;
+
+ /* assign index */
+ chan->num = (USHORT)n;
+ chan->cm = cm;
+ chan->ustate = 0;
+ chan->active = 0;
+ chan->gave_up = 0;
+
+ /* if connection is nailed, channal must be explicit */
+ if ( cm->dprof.nailed && !CM_BCHAN_ASSIGNED(chan->bchan) )
+ ABORT(CM_E_BADCHAN);
+ }
+
+ /* if connection is to be activated by frame, exit here */
+ if ( cm->dprof.frame_activated )
+ return(CM_E_SUCC);
+
+ /* if here, connection has to be activated now! */
+ cm->state = CM_ST_IN_ACT;
+ cm->StateChangeFlag = TRUE;
+ if ( (ret = cm__initiate_conn(cm)) == CM_E_SUCC )
+ return(CM_E_SUCC);
+
+ /* if here, aborting connection */
+ aborting:
+ cm->state = CM_ST_IDLE;
+ cm->StateChangeFlag = TRUE;
+ return(ret);
+}
+
+/* disconnect a connection, back to idle state */
+INT
+cm_disconnect(VOID *cm_1)
+{
+ CM *cm = (CM*)cm_1;
+ ULONG n;
+
+ D_LOG(D_ENTRY, ("cm_disconnect: entry, cm: 0x%lx", cm));
+
+ /* branch on connection state */
+ switch ( cm->state )
+ {
+ case CM_ST_IDLE : /* already idle, do nothing */
+ default :
+ break;
+
+ case CM_ST_LISTEN : /* waiting for a connection, cancel */
+ case CM_ST_WAIT_ACT : /* waiting for activation, cancel */
+ case CM_ST_DEACT : /* deactivated, cancel */
+ cm->state = CM_ST_IDLE;
+ cm->StateChangeFlag = TRUE;
+ break;
+
+ case CM_ST_IN_ACT : /* in activation */
+ case CM_ST_IN_SYNC : /* syncronizing */
+ case CM_ST_ACTIVE : /* is active */
+ case CM_ST_IN_ANS : /* in answering process */
+
+ /* scan channel, issue a disconnect */
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++)
+ {
+ CM_CHAN *chan = cm->dprof.chan_tbl + n;
+
+ /* check is channel is used in this connection */
+ if ( chan->gave_up || !chan->ustate )
+ continue;
+
+ /* disconnect it */
+ cm__disc_rq(chan);
+ chan->cid = 0;
+ }
+
+ /* deactivate connection (not by idle timer) */
+ cm__deactivate_conn(cm, 0);
+ break;
+ }
+
+ return(CM_E_SUCC);
+}
+
+/* initiate a connection waiting for activation */
+INT
+cm__initiate_conn(CM *cm)
+{
+ ULONG n;
+
+ D_LOG(D_ENTRY|DIGIQ931, ("cm__initiate_conn: entry, cm: 0x%lx\n", cm));
+
+ /* if connection is nailed, handle here */
+ if ( cm->dprof.nailed )
+ return(cm__activate_conn(cm, cm->dprof.HWCompression));
+
+ /* if here, connection is on demand, initate call setup on all chans */
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++)
+ {
+ CM_CHAN *chan = cm->dprof.chan_tbl + n;
+ USHORT my_cid = MAKEWORD(chan->num, cm->local_conn_index);
+
+ chan->cid = my_cid;
+ chan->ustate = CM_US_WAIT_CID;
+ chan->timeout = ut_time_now();
+
+
+ cm__est_rq(chan);
+
+ }
+
+ return(CM_E_SUCC);
+}
+
+/* activate a connection */
+INT
+cm__activate_conn(CM *cm, ULONG CompressionFlag)
+{
+ ULONG n;
+
+ D_LOG(D_ENTRY, ("cm__activate_conn: entry, cm: 0x%lx", cm));
+
+ /* mark change of state & time */
+ cm->state = CM_ST_ACTIVE;
+ cm->StateChangeFlag = TRUE;
+ cm->rx_last_frame_time = cm->tx_last_frame_time = cm->timeout = ut_time_now();
+
+ /* scan active channel, notify mtl, etc. */
+ cm->active_chan_num = 0;
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++)
+ {
+ CM_CHAN *chan = cm->dprof.chan_tbl + n;
+
+ /* check is channel is used in this connection */
+ if ( chan->gave_up )
+ continue;
+
+ // Give Compression command for this channel
+ cm__bchan_ctrl_comp(chan, CompressionFlag);
+
+ /* turn channel on (may be redundant in demand connections */
+ cm__bchan_ctrl(chan, 1);
+
+ /* notify mtl of channel */
+ mtl_add_chan(cm->mtl,
+ chan->idd,
+ chan->bchan,
+ chan->speed,
+ cm->ConnectionType);
+
+ /* accumulate */
+ cm->active_chan_num++;
+ }
+
+
+ /* get speed from mtl, tell mtl is connected now! */
+ mtl_get_conn_speed(cm->mtl, &cm->speed);
+
+ return(CM_E_SUCC);
+}
+
+/* deactivate a connection */
+INT
+cm__deactivate_conn(CM *cm, BOOL by_idle_timer)
+{
+ ULONG n;
+
+ D_LOG(D_ENTRY, ("cm__deactivate_conn: entry, cm: 0x%lx", cm));
+
+// DbgPrint ("DeactivateConn\n");
+ /* mark change of state & time */
+ cm->state = CM_ST_DEACT;
+ cm->StateChangeFlag = TRUE;
+ cm->rx_last_frame_time = cm->tx_last_frame_time = cm->timeout = ut_time_now();
+
+ /* tell mtl not connected now */
+ mtl_set_conn_state(cm->mtl, cm->dprof.chan_num, 0);
+
+ /* scan active channel, notify mtl, etc. */
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++)
+ {
+ CM_CHAN *chan = cm->dprof.chan_tbl + n;
+
+ /* check is channel is used in this connection */
+ if ( chan->gave_up )
+ continue;
+
+ /* turn channel off */
+ cm__bchan_ctrl(chan, 0);
+
+ /* notify mtl of channel */
+ mtl_del_chan(cm->mtl, chan->idd, chan->bchan);
+
+ /* clear channel state */
+ chan->ustate = 0;
+ chan->active = 0;
+ }
+
+ /* if connection originated as listening, back to idle here */
+ if ( cm->was_listen )
+ {
+ make_idle:
+ cm->state = CM_ST_IDLE;
+ cm->StateChangeFlag = TRUE;
+ return(CM_E_SUCC);
+ }
+
+ /* if connection is not persistant, back to idle */
+ if ( !cm->dprof.persist )
+ goto make_idle;
+
+ /* if deactivate not by idle timer, back to idle */
+ if ( !by_idle_timer )
+ goto make_idle;
+
+ /* if here, connection reverts to waiting for activation */
+ cm->state = CM_ST_WAIT_ACT;
+ cm->StateChangeFlag = TRUE;
+ return(CM_E_SUCC);
+}
+
+/* calc next channel, not implemented yet */
+INT
+cm__get_next_chan(CM_CHAN *chan)
+{
+ CM *cm = (CM*)chan->cm;
+
+ /* restore modified fields */
+ chan->bchan = cm->oprof.chan_tbl[chan->num].bchan;
+
+ /* step to next channel type */
+ switch ( chan->type )
+ {
+ case CM_CT_D64 :
+ chan->type = CM_CT_D56;
+ break;
+
+ case CM_CT_D56 :
+ chan->type = CM_CT_VOICE;
+ break;
+
+ case CM_CT_VOICE :
+ default:
+ return(CM_E_NOSUCH);
+ }
+
+ /* if here, succ */
+ return(CM_E_SUCC);
+}
+
+
diff --git a/private/ntos/ndis/digi/pcimac/cm_init.c b/private/ntos/ndis/digi/pcimac/cm_init.c
new file mode 100644
index 000000000..57f2d5262
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/cm_init.c
@@ -0,0 +1,488 @@
+/*
+ * CM_INIT.C - initialization code for CM objects
+ */
+
+#include <ndis.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+#include <trc.h>
+#include <io.h>
+#include <tapioid.h>
+
+/* local data structures */
+typedef struct
+{
+ VOID *idd;
+ USHORT lterm;
+ USHORT cid;
+ CM_CHAN *chan;
+} CM_FIND_CHAN;
+
+typedef struct
+{
+ VOID *idd;
+ USHORT bchan;
+ CM_CHAN *chan;
+} CM_FIND_BCHAN;
+
+/* local connection table */
+CM *cm_tbl[MAX_CM_IN_SYSTEM]; /* table of connection managers */
+BOOL cm_used[MAX_CM_IN_SYSTEM]; /* flags for used cm's */
+BOOL cm_terminated = FALSE;
+
+BOOL cm__find_chan(CM_CHAN* chan, CM_FIND_CHAN *fc, VOID* a2);
+BOOL cm__find_bchan(CM_CHAN* chan, CM_FIND_BCHAN *fc, VOID* a2);
+BOOL cm__match_str(CHAR* s1, CHAR* s2);
+
+/* driver global vars */
+extern DRIVER_BLOCK Pcimac;
+
+//
+// added to support the new switch styles
+//
+ULONG SwitchStyle = CM_SWITCHSTYLE_NONE;
+
+
+ULONG
+EnumCmInSystem()
+{
+ ULONG n;
+
+ for (n = 0; n < MAX_CM_IN_SYSTEM; n++)
+ {
+ if (cm_tbl[n] == NULL)
+ break;
+ }
+ return(n);
+}
+
+ULONG
+EnumCmPerAdapter(
+ ADAPTER *Adapter
+ )
+{
+ ULONG n;
+
+ for (n = 0; n < MAX_CM_PER_ADAPTER; n++)
+ {
+ if (Adapter->CmTbl[n] == NULL)
+ break;
+ }
+ return(n);
+}
+
+INT
+IoEnumCm(IO_CMD *cmd)
+{
+ ULONG n;
+
+ cmd->val.enum_cm.num = (USHORT)EnumCmInSystem();
+
+ for (n = 0; n < cmd->val.enum_cm.num; n++)
+ {
+ CM *cm = cm_tbl[n];
+
+ strcpy(cmd->val.enum_cm.name[n], cm->name);
+ cmd->val.enum_cm.tbl[n] = cm;
+ }
+
+ return(0);
+}
+
+VOID*
+CmGetMtl(
+ VOID *cm_1
+ )
+{
+ CM *cm = (CM*)cm_1;
+
+ return(cm->mtl);
+}
+
+
+//
+// added to support the new switch styles
+//
+VOID
+CmSetSwitchStyle(CHAR *StyleName)
+{
+ if (!strcmp(StyleName, "ni1"))
+ SwitchStyle = CM_SWITCHSTYLE_NI1;
+ else if (!strcmp(StyleName, "att"))
+ SwitchStyle = CM_SWITCHSTYLE_ATT;
+ else if (!strcmp(StyleName, "nti"))
+ SwitchStyle = CM_SWITCHSTYLE_NTI;
+ else if (!strcmp(StyleName, "net3"))
+ SwitchStyle = CM_SWITCHSTYLE_NET3;
+ else if (!strcmp(StyleName, "1tr6"))
+ SwitchStyle = CM_SWITCHSTYLE_1TR6;
+ else if (!strcmp(StyleName, "vn3"))
+ SwitchStyle = CM_SWITCHSTYLE_VN3;
+ else if (!strcmp(StyleName, "ins64"))
+ SwitchStyle = CM_SWITCHSTYLE_INS64;
+ else
+ SwitchStyle = CM_SWITCHSTYLE_NONE;
+}
+
+#pragma NDIS_INIT_FUNCTION(cm_init)
+
+/* initialize cm class */
+INT
+cm_init(VOID)
+{
+ NDIS_PHYSICAL_ADDRESS pa = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
+ D_LOG(D_ENTRY, ("cm_init: entry\n"));
+
+ NdisZeroMemory(cm_tbl, sizeof(cm_tbl));
+ NdisZeroMemory(cm_used, sizeof(cm_used));
+
+ ChannelInit();
+
+ return(CM_E_SUCC);
+}
+
+/* terminate cm class */
+cm_term()
+{
+ D_LOG(D_ENTRY, ("cm_term: entry\n"));
+
+ cm_terminated = TRUE;
+
+ // Release Channel Table
+ ChannelTerm();
+
+ return(CM_E_SUCC);
+}
+
+/* register an available idd */
+cm_register_idd(VOID *idd)
+{
+ D_LOG(D_ENTRY, ("cm_register_idd: entry, idd: 0x%lx\n", idd));
+
+ /* add handles to idd cm/bchan receivers (cm1 may failed!) */
+ idd_attach(idd, IDD_PORT_CM0_RX, (VOID*)cm__q931_handler, idd);
+ idd_attach(idd, IDD_PORT_CM1_RX, (VOID*)cm__q931_handler, idd);
+ idd_attach(idd, IDD_PORT_B1_RX, (VOID*)cm__q931_bchan_handler, idd);
+ idd_attach(idd, IDD_PORT_B2_RX, (VOID*)cm__q931_bchan_handler, idd);
+
+ /* ask idp cm to deliver elements */
+ cm__elem_rq(idd, IDD_PORT_CM0_TX, "\x08\x34\x18", 3);
+ cm__elem_rq(idd, IDD_PORT_CM1_TX, "\x08\x34\x18", 3);
+
+ return(CM_E_SUCC);
+}
+
+/* deregister an available idd */
+cm_deregister_idd(VOID *idd)
+{
+ D_LOG(D_ENTRY, ("cm_deregister_idd: entry, idd: 0x%lx\n", idd));
+
+ /* remove handle from idd cm receivers */
+ idd_detach(idd, IDD_PORT_CM0_RX, (VOID*)cm__q931_handler, idd);
+ idd_detach(idd, IDD_PORT_CM1_RX, (VOID*)cm__q931_handler, idd);
+ idd_detach(idd, IDD_PORT_B1_RX, (VOID*)cm__q931_bchan_handler, idd);
+ idd_detach(idd, IDD_PORT_B2_RX, (VOID*)cm__q931_bchan_handler, idd);
+
+ return(CM_E_SUCC);
+}
+
+#pragma NDIS_INIT_FUNCTION(cm_create)
+
+/* create a new cm object */
+cm_create(VOID **ret_cm, NDIS_HANDLE AdapterHandle)
+{
+ NDIS_PHYSICAL_ADDRESS pa = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
+ INT n;
+
+ D_LOG(D_ENTRY, ("cm_create: entry, ret_cm: 0x%lx\n", ret_cm));
+
+ /* allocate memory object */
+ NdisAllocateMemory((PVOID*)ret_cm, sizeof(CM), 0, pa);
+ if ( *ret_cm == NULL )
+ {
+ D_LOG(D_ALWAYS, ("cm_create: memory allocate failed!\n"));
+ NdisWriteErrorLogEntry (AdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0);
+ return(CM_E_NOMEM);
+ }
+ D_LOG(D_ALWAYS, ("cm_create: cm: 0x%x\n", *ret_cm));
+ NdisZeroMemory(*ret_cm, sizeof(CM));
+
+ /* allocate connection out of local table */
+ for ( n = 0 ; n < MAX_CM_IN_SYSTEM ; n++ )
+ if ( !cm_used[n] )
+ break;
+ if ( n >= MAX_CM_IN_SYSTEM )
+ {
+ /* free memory */
+ NdisFreeMemory(*ret_cm, sizeof(CM), 0);
+ return(CM_E_NOSLOT);
+ }
+
+
+ /* initialize */
+ cm_used[n] = 1;
+ cm_tbl[n] = *ret_cm;
+ ((CM*)*ret_cm)->local_conn_index = n;
+
+ /* return */
+ return(CM_E_SUCC);
+}
+
+/* destory a cm object */
+cm_destroy(VOID *cm_1)
+{
+ CM* cm = (CM*)cm_1;
+ D_LOG(D_ENTRY, ("cm_destory: entry, cm: 0x%lx\n", cm));
+
+ cm_used[cm->local_conn_index] = 0;
+ cm_tbl[cm->local_conn_index] = NULL;
+
+ //
+ // disconnect this connection object
+ //
+ cm_disconnect (cm);
+
+// added for dynamic allocation of cm
+ /* free memory */
+ NdisFreeMemory(cm, sizeof(*cm), 0);
+
+ return(CM_E_SUCC);
+}
+
+/* find a channel from an <idd,lterm,cid> */
+CM_CHAN*
+cm__map_chan(VOID* idd, USHORT lterm, USHORT cid)
+{
+ CM *cm;
+ CM_CHAN *chan;
+ ULONG n, m;
+ CM_FIND_CHAN fc;
+
+ D_LOG(D_ENTRY, ("cm__map_chan: entry: idd: 0x%lx, lterm: 0x%x, cid: 0x%lx\n", idd,lterm,cid));
+
+ /* scan incoming channel table first */
+ fc.idd = idd;
+ fc.lterm = lterm;
+ fc.cid = cid;
+ fc.chan = NULL;
+ cm__chan_foreach(cm__find_chan, &fc, NULL);
+ if ( fc.chan )
+ return(fc.chan);
+
+ /* scan connection table */
+ for ( n = 0; n < MAX_CM_IN_SYSTEM ; n++)
+ if ( cm_used[n] )
+ {
+ cm = cm_tbl[n];
+ switch ( cm->state )
+ {
+ case CM_ST_IN_ACT :
+ case CM_ST_IN_SYNC :
+ case CM_ST_ACTIVE :
+ case CM_ST_IN_ANS :
+ for ( m = 0, chan = cm->dprof.chan_tbl ;
+ m < cm->dprof.chan_num ; m++, chan++ )
+ if ( (idd == chan->idd) &&
+ (lterm == chan->lterm) &&
+ (cid == chan->cid) )
+ return(chan);
+ break;
+ }
+ }
+
+ /* if here, failed! */
+ return(NULL);
+}
+
+/* find a bchannel from an <idd,bchan> */
+CM_CHAN*
+cm__map_bchan_chan(VOID *idd, USHORT bchan)
+{
+ CM *cm;
+ CM_CHAN *chan;
+ ULONG n, m;
+ CM_FIND_BCHAN fc;
+
+ D_LOG(D_ENTRY, ("cm__map_bchan_chan: idd: 0x%lx, bchan: 0x%x\n", \
+ idd,bchan));
+
+ /* scan incoming channel table first */
+ fc.idd = idd;
+ fc.bchan = bchan;
+ fc.chan = NULL;
+ cm__chan_foreach(cm__find_bchan, &fc, NULL);
+ if ( fc.chan )
+ return(fc.chan);
+
+ /* scan connection table */
+ for ( n = 0; n < MAX_CM_IN_SYSTEM ; n++)
+ if ( cm_used[n] )
+ {
+ cm = cm_tbl[n];
+ switch ( cm->state )
+ {
+ case CM_ST_IN_ACT :
+ case CM_ST_IN_SYNC :
+ case CM_ST_ACTIVE :
+ case CM_ST_IN_ANS :
+ for ( m = 0, chan = cm->dprof.chan_tbl ;
+ m < cm->dprof.chan_num ; m++, chan++ )
+ if ( (idd == chan->idd) &&
+ (bchan == chan->bchan) &&
+ (chan->ustate >= 10) )
+ return(chan);
+ break;
+ }
+ }
+
+ /* if here, failed! */
+ return(NULL);
+}
+
+/* return connection by index */
+CM*
+cm__get_conn(ULONG index)
+{
+ /* check range */
+ if ( index >= MAX_CM_IN_SYSTEM )
+ return(NULL);
+
+ /* check used */
+ if ( !cm_used[index] )
+ return(NULL);
+
+ /* return it */
+ return(cm_tbl[index]);
+}
+
+/* find a matching listening connection */
+CM*
+cm__find_listen_conn(CHAR *lname, CHAR *rname, CHAR *addr, VOID *Idd)
+{
+ CM *cm;
+ ULONG n;
+
+ D_LOG(D_ENTRY, ("cm__find_listen_conn: entry, lname: [%s], rname: [%s], addr: [%s]\n", \
+ lname, rname, addr));
+
+ /* scan connection table */
+ for ( n = 0; n < MAX_CM_IN_SYSTEM ; n++)
+ {
+ cm = cm_tbl[n];
+ if ( cm_used[n] && (cm->idd == Idd) && (cm->state == CM_ST_LISTEN) )
+ {
+ D_LOG(D_ENTRY, ("cm__find_listen_conn: comparing to: name: [%s], remote_name: [%s]\n", \
+ cm->dprof.name, cm->dprof.remote_name));
+ if ( cm__match_str(cm->dprof.name, rname) &&
+ cm__match_str(cm->dprof.remote_name, lname) )
+ return(cm);
+ }
+ }
+
+ return(NULL);
+}
+
+/* 1 second timer tick, poll active cm's */
+VOID
+CmPollFunction(VOID *a1, ADAPTER *Adapter, VOID *a3, VOID *a4)
+{
+ ULONG n;
+
+ /* if terminated, ignore */
+ if ( cm_terminated )
+ return;
+
+ /* poll active cm's */
+ for ( n = 0; n < MAX_CM_PER_ADAPTER ; n++)
+ {
+ CM *cm = Adapter->CmTbl[n];
+
+ if (cm)
+ {
+ cm__timer_tick(cm);
+ if (cm->PrevState != cm->state || cm->StateChangeFlag == TRUE)
+ {
+ cm->PrevState = cm->state;
+ cm->StateChangeFlag = FALSE;
+ DoTapiStateCheck(cm);
+ }
+ }
+ }
+
+ /* rearm timer */
+ NdisMSetTimer(&Adapter->CmPollTimer, CM_POLL_T);
+}
+
+/* assist routine for finding a channel. stop scan when found */
+BOOL
+cm__find_chan(CM_CHAN *chan, CM_FIND_CHAN *fc, VOID *a2)
+{
+ if ( (chan->idd == fc->idd) && (chan->lterm == fc->lterm) &&
+ (chan->cid == fc->cid) )
+ {
+ fc->chan = chan;
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+/* assist routine for finding a channel by bchan. stop scan when found */
+BOOL
+cm__find_bchan(CM_CHAN *chan, CM_FIND_BCHAN *fc, VOID *a2)
+{
+ if ( (chan->idd == fc->idd) && (chan->bchan == fc->bchan) )
+ {
+ fc->chan = chan;
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+/* match two strings. allow for wild characters */
+BOOL
+cm__match_str(CHAR *s1, CHAR *s2)
+{
+ /* march on strings, process wild characters '*' and '?' */
+ for ( ; *s1 && *s2 ; s1++, s2++ )
+ if ( (*s1 == '*') || (*s2 == '*') )
+ return(TRUE);
+ else if ( (*s1 == '?') || (*s2 == '?') )
+ continue;
+ else if ( *s1 != *s2 )
+ return(FALSE);
+
+ /* if here, atleast one string ended, other must end here */
+ return( (*s1 | *s2) ? FALSE : TRUE );
+}
+
+UCHAR*
+GetDstAddr(
+ VOID *cm_1
+ )
+{
+ CM *cm = (CM*)cm_1;
+
+ return(&cm->DstAddr[0]);
+}
+
+UCHAR*
+GetSrcAddr(
+ VOID *cm_1
+ )
+{
+ CM *cm = (CM*)cm_1;
+
+ return(&cm->SrcAddr[0]);
+}
diff --git a/private/ntos/ndis/digi/pcimac/cm_prof.c b/private/ntos/ndis/digi/pcimac/cm_prof.c
new file mode 100644
index 000000000..be6376c65
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/cm_prof.c
@@ -0,0 +1,51 @@
+/*
+ * CM_PROF.C - profile related code
+ */
+
+#include <ndis.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+
+/* set profile in cm */
+INT
+cm_set_profile(VOID *cm_1, CM_PROF *prof)
+{
+ CM *cm = (CM*)cm_1;
+ D_LOG(D_ENTRY, ("cm_set_prof: entry, cm: 0x%lx, prof: 0x%lx", cm, prof));
+
+ /* connection must be idle to change profile! */
+ if ( cm->state != CM_ST_IDLE )
+ return(CM_E_BUSY);
+
+ /* set & return */
+ cm->oprof = *prof;
+
+ return(CM_E_SUCC);
+}
+
+/* get profile from cm */
+INT
+cm_get_profile(VOID *cm_1, CM_PROF *prof)
+{
+ CM *cm = (CM*)cm_1;
+ D_LOG(D_ENTRY, ("cm_get_prof: entry, cm: 0x%lx, prof: 0x%lx", cm, prof));
+
+ /* connection must has a profile */
+ if ( !cm->oprof.name[0] )
+ return(CM_E_NOSUCH);
+
+ /* set & return */
+ *prof = cm->dprof;
+
+ return(CM_E_SUCC);
+}
+
+
diff --git a/private/ntos/ndis/digi/pcimac/cm_pub.h b/private/ntos/ndis/digi/pcimac/cm_pub.h
new file mode 100644
index 000000000..a58af5eb0
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/cm_pub.h
@@ -0,0 +1,134 @@
+/*
+ * CM_PUB.H - definitions for connection manager
+ */
+
+#ifndef _CM_PUB_
+#define _CM_PUB_
+
+//
+// global cm def's
+//
+/* a channel descriptor */
+typedef struct
+{
+ VOID* idd; /* related idd */
+ USHORT lterm; /* logical terminal in idd */
+ CHAR addr[32]; /* address to used - phone no. */
+
+ USHORT bchan; /* related b channel */
+#define CM_BCHAN_B1 0 /* - b1 */
+#define CM_BCHAN_B2 1 /* - b2 */
+#define CM_BCHAN_ANY 2 /* - any */
+#define CM_BCHAN_NONE 3 /* - no bchannel related */
+#define CM_BCHAN_ASSIGNED(_b) \
+ ((_b) < 3) /* check for 'assigned' b channel */
+
+ USHORT type; /* channel type */
+#define CM_CT_D64 0 /* - digital 64 kbps */
+#define CM_CT_D56 1 /* - digital 56 kbps */
+#define CM_CT_VOICE 2 /* - digital voice/56 kbps */
+ ULONG speed; /* channel speed, in bps */
+
+ USHORT ustate; /* ustate (q.931) of channel */
+ USHORT cid; /* connection id, idp allocated */
+
+ USHORT num; /* channel number within connection */
+ VOID *cm; /* related connection manager */
+
+ UCHAR DstAddr[6]; /* ethernet address of remote side */
+ UCHAR remote_conn_index; /* connection # of remote connection */
+
+ ULONG timeout; /* used for dead-man timeouts */
+
+ BOOL active; /* channel is active? */
+ BOOL gave_up; /* gave-up on channel? */
+
+ ULONG flag; /* general purpose flag */
+} CM_CHAN;
+
+/* a profile descriptor */
+typedef struct
+{
+ BOOL nailed; /* nailed/demand access */
+ BOOL persist; /* connection persistance */
+ BOOL permanent; /* connection is permanent? */
+ BOOL frame_activated; /* connection activate by frame? */
+ BOOL fallback; /* fallback on channels */
+ BOOL HWCompression; // Compression negotiation on/off
+
+ ULONG rx_idle_timer; /* idle timer for rx side */
+ ULONG tx_idle_timer; /* idle timer for tx side */
+
+ USHORT chan_num; /* # of channels requested */
+ CM_CHAN chan_tbl[MAX_CHAN_PER_CONN]; /* requested channel descriptor */
+
+ CHAR name[32]; /* name of this profile */
+ CHAR remote_name[32]; /* name of remote profile */
+} CM_PROF;
+
+/* connection status descriptor */
+typedef struct _CM
+{
+ CHAR name[64]; /* name for this object */
+
+ CHAR LocalAddress[32]; /* address in format NetCard#-Line#-EndPoint */
+
+ USHORT state; /* connection state */
+#define CM_ST_IDLE 0 /* - idle */
+#define CM_ST_WAIT_ACT 1 /* - waiting for frame activation */
+#define CM_ST_IN_ACT 2 /* - in activation */
+#define CM_ST_IN_SYNC 3 /* - in syncronization */
+#define CM_ST_ACTIVE 4 /* - connection is active! */
+#define CM_ST_LISTEN 5 /* - is listening */
+#define CM_ST_IN_ANS 6 /* - in answering process */
+#define CM_ST_DEACT 7 /* - in deactivation process */
+
+ USHORT PrevState; /* used to track event signal states */
+ USHORT StateChangeFlag; /* used to signal state changes */
+
+ CM_PROF dprof; /* related profile - dynamic copy */
+ CM_PROF oprof; /* related profile - original copy */
+
+ BOOL was_listen; /* connection started as a listener? */
+ ULONG active_chan_num; /* # of active channels */
+ ULONG speed; /* connection speed, bps */
+ ULONG ConnectionType; /* 0/1 - ppp/dkf */
+
+ ULONG rx_last_frame_time; /* last time rx frame recorded */
+ ULONG tx_last_frame_time; /* last time tx frame recorded */
+
+ UCHAR local_conn_index; /* local connection # */
+ UCHAR SrcAddr[6]; /* local side ethernet address */
+
+ UCHAR remote_conn_index; /* remote side connection # */
+ UCHAR DstAddr[6]; /* remote side ethernet address */
+ CHAR remote_name[32]; /* name of remote profile */
+
+ ULONG timeout; /* dead-man timeout */
+
+ VOID *mtl; /* related mtl, internal */
+ VOID *idd; /* related idd */
+ VOID *Adapter; /* related adapter, internal */
+
+ VOID *TapiLineInfo; // back pointer to owning line
+
+ NDIS_HANDLE LinkHandle; // assigned during lineup
+
+ ULONG htCall; // tapi's handle to the call
+
+ ULONG TapiCallState; // tapi's call state
+
+ ULONG CallState; // our call state
+
+ ULONG AppSpecific; // app specific storage
+
+ UCHAR CauseValue; // Cause Value in Disc or Rel Messages
+ UCHAR SignalValue; // Signal Value in CallProc or CallProg Messages
+ UCHAR CalledAddress[32]; // Address that was called
+ UCHAR CallingAddress[32]; // Address of caller
+ ULONG PPPToDKF; // Flag to signal a change from PPP to DKF
+ ULONG NoActiveLine; // Flag to indicate when no line is detected
+} CM_STATUS, CM;
+
+#endif /* _CM_PUB_ */
+
diff --git a/private/ntos/ndis/digi/pcimac/cm_q931.c b/private/ntos/ndis/digi/pcimac/cm_q931.c
new file mode 100644
index 000000000..453fe3f84
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/cm_q931.c
@@ -0,0 +1,943 @@
+/*
+ * CM_Q931.C - q931 handling module. mainly outgoing side
+ */
+
+#include <ndis.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+
+extern ULONG SwitchStyle;
+
+/* local assist, copy data into buffer & advance pointer */
+#define adv_ptr(_p, _buf, _len) \
+ { \
+ NdisMoveMemory((_p), _buf, _len); \
+ (_p) += _len; \
+ }
+
+/* format an establish request */
+INT
+cm__est_rq(CM_CHAN *chan)
+{
+ IDD_MSG msg;
+ UCHAR *p;
+
+ D_LOG(D_ENTRY|DIGIQ931, ("cm__est_rq: entry, chan: 0x%lx\n", chan));
+
+ /* clear outgoing message */
+ NdisZeroMemory(&msg, sizeof(msg));
+
+ /* allocate a local buffer */
+ if ( !(msg.bufptr = p = ut_get_buf()) )
+ goto give_up;
+
+ //
+ // added to support the new switch styles
+ // TB 03/14
+ //
+ if (SwitchStyle != CM_SWITCHSTYLE_1TR6)
+ {
+ /* build bearer capabilities element */
+ switch ( chan->type )
+ {
+ case CM_CT_VOICE :
+ adv_ptr(p, ((SwitchStyle == CM_SWITCHSTYLE_NET3) ?
+ "\x04\x03\x80\x90\xA3" :
+ "\x04\x03\x80\x90\xA2"), 5);
+ chan->speed = 56000;
+ break;
+
+ case CM_CT_D56 :
+ adv_ptr(p, "\x04\x04\x88\x90\x21\x8F", 6);
+ chan->speed = 56000;
+ break;
+
+ default :
+ case CM_CT_D64 :
+ adv_ptr(p, "\x04\x02\x88\x90", 4);
+ chan->speed = 64000;
+ break;
+ }
+ }
+
+ /* channel id element */
+ switch ( chan->bchan )
+ {
+ case CM_BCHAN_B1 : adv_ptr(p, "\x18\x01\x89", 3);
+ break;
+ case CM_BCHAN_B2 : adv_ptr(p, "\x18\x01\x8A", 3);
+ break;
+ default :
+ case CM_BCHAN_ANY : adv_ptr(p, "\x18\x01\x83", 3);
+ break;
+ }
+
+ //
+ // added to support the new switch styles
+ // TB 03/14
+ //
+ if (SwitchStyle != CM_SWITCHSTYLE_1TR6
+ && SwitchStyle != CM_SWITCHSTYLE_NET3)
+ {
+ /* called number/address */
+ *p++ = 0x2C;
+ *p++ = strlen(chan->addr);
+ adv_ptr(p, chan->addr, p[-1]);
+ }
+ else
+ {
+ //
+ // added to support the new switch styles
+ // TB 03/14
+ //
+ *p++ = 0x70;
+ *p++ = strlen(chan->addr) + 1;
+ *p++ = (SwitchStyle == CM_SWITCHSTYLE_1TR6) ? 0x81 : 0x80;
+ adv_ptr(p, chan->addr, strlen(chan->addr));
+ }
+
+ //
+ // added for net3 fix
+ // TB 04/13
+ //
+ if (SwitchStyle == CM_SWITCHSTYLE_NET3)
+ *p++ = 0xA1; // Sending Complete
+
+ //
+ // added to support the new switch styles
+ // TB 03/14
+ //
+ if (SwitchStyle == CM_SWITCHSTYLE_1TR6)
+ {
+ *p++ = 0x96;
+ *p++ = 0x01;
+ switch (chan->type)
+ {
+ case CM_CT_VOICE:
+ adv_ptr(p, "\x02\x01\x01", 3);
+ break;
+
+ case CM_CT_D56:
+ case CM_CT_D64:
+ default:
+ adv_ptr(p, "\x02\x07\x00", 3);
+ break;
+ }
+ }
+
+ /* fillin message structure */
+ msg.opcode = Q931_EST_RQ;
+ msg.buflen = p - msg.bufptr;
+ msg.bufid = MAKELONG(chan->cid, 0);
+ chan->cid = 0;
+
+ /* send to idd */
+ if ( idd_send_msg(chan->idd, &msg, (USHORT)CM_PORT(chan),
+ (VOID*)cm__q931_cmpl_handler, chan) != IDD_E_SUCC )
+ {
+ /* failed, give up on channel */
+ give_up:
+ chan->gave_up = 1;
+ ut_free_buf(msg.bufptr);
+ return(CM_E_IDD);
+ }
+
+ D_LOG(D_EXIT|DIGIQ931, ("cm__est_rq: exit\n"));
+ return(CM_E_SUCC);
+}
+
+/* format an establish response */
+INT
+cm__est_rsp(CM_CHAN *chan)
+{
+ IDD_MSG msg;
+
+ D_LOG(D_ENTRY|DIGIQ931, ("cm__est_rsp: entry, chan: 0x%lx\n", chan));
+
+ /* clear outgoing message */
+ NdisZeroMemory(&msg, sizeof(msg));
+
+ /* fillin message structure */
+ msg.opcode = Q931_EST_RSP;
+ msg.bufid = MAKELONG(0, chan->cid);
+ msg.bufptr = ut_get_buf();
+ msg.buflen = 0;
+
+
+ /* send to idd */
+ if (idd_send_msg(chan->idd, &msg, (USHORT)CM_PORT(chan), (VOID*)cm__q931_cmpl_handler, NULL) != IDD_E_SUCC)
+ ut_free_buf(msg.bufptr);
+
+ return(CM_E_SUCC);
+}
+
+/* format a call ignore response */
+INT
+cm__est_ignore(
+ PVOID idd,
+ USHORT cid,
+ USHORT lterm)
+{
+ IDD_MSG msg;
+
+ D_LOG(D_ENTRY|DIGIQ931, ("cm__est_ignore: entry, idd: 0x%lx, cid: 0x%x, lterm: 0x%x\n", idd, cid, lterm));
+
+ /* clear outgoing message */
+ NdisZeroMemory(&msg, sizeof(msg));
+
+ /* fillin message structure */
+ msg.opcode = Q931_EST_IGNORE;
+ msg.bufid = MAKELONG(0, cid);
+ msg.bufptr = ut_get_buf();
+ msg.buflen = 0;
+
+
+ /* send to idd */
+ if (idd_send_msg(idd, &msg, (USHORT)(lterm + IDD_PORT_CM0_TX), (VOID*)cm__q931_cmpl_handler, NULL) != IDD_E_SUCC)
+ ut_free_buf(msg.bufptr);
+
+ return(CM_E_SUCC);
+}
+
+/* format a disconenct request */
+INT
+cm__disc_rq(CM_CHAN *chan)
+{
+ IDD_MSG msg;
+
+ D_LOG(D_ENTRY|DIGIQ931, ("cm__disc_rq: entry, chan: 0x%lx\n", chan));
+
+ /* clear outgoing message */
+ NdisZeroMemory(&msg, sizeof(msg));
+
+ /* fillin message structure */
+ msg.opcode = Q931_REL_RQ;
+ msg.bufid = MAKELONG(0, chan->cid);
+ msg.bufptr = ut_get_buf();
+ msg.buflen = 0;
+
+ /* send to idd */
+ if (idd_send_msg(chan->idd, &msg, (USHORT)CM_PORT(chan), (VOID*)cm__q931_cmpl_handler, NULL) != IDD_E_SUCC)
+ ut_free_buf(msg.bufptr);
+
+
+ /* turn off channel */
+ cm__bchan_ctrl(chan, 0);
+ return(CM_E_SUCC);
+}
+
+/* control data transfer on a bchannel */
+INT
+cm__bchan_ctrl(CM_CHAN *chan, BOOL turn_on)
+{
+ USHORT is_ans, subchan, op;
+ IDD_MSG msg;
+ CM *cm = chan->cm;
+ ULONG IddFramingType = IDD_FRAME_DETECT;
+
+ D_LOG(D_ENTRY|DIGIQ931, ("cm__bchan_ctrl: entry, chan: 0x%lx, turn_on: %d, active: %d\n", \
+ chan,
+ turn_on,
+ chan->active));
+
+ //
+ // check for a redundant operation
+ //
+ if ((!chan->active && !turn_on) ||
+ (chan->active && turn_on))
+ return(CM_E_SUCC);
+
+ /* channel must be assigned */
+ if ( !CM_BCHAN_ASSIGNED(chan->bchan) )
+ return(CM_E_BADCHAN);
+
+ cm__bchan_ctrl_comp( chan, 0 );
+
+ /* find out if on answering side */
+ if ( cm )
+ is_ans = cm->was_listen ? 0x0100 : 0x0000;
+ else
+ is_ans = 0x0100;
+
+ /* map channel type to operation */
+ if ( !turn_on )
+ op = CMD_BCHAN_OFF;
+ else
+ {
+ switch ( chan->type )
+ {
+ case CM_CT_VOICE : op = CMD_BCHAN_VOICE; break;
+ case CM_CT_D56 : op = CMD_BCHAN_56; break;
+ default :
+ case CM_CT_D64 : op = CMD_BCHAN_HDLC; break;
+ }
+
+ chan->speed = cm__type2speed(chan->type);
+ }
+
+ /* build subchannel descriptor */
+ subchan = 0x1717;
+
+ /* build msg */
+ NdisZeroMemory(&msg, sizeof(msg));
+ msg.opcode = op;
+ msg.bufid = MAKELONG(is_ans | chan->bchan | (subchan << 1), 0);
+
+ /* send it */
+ idd_send_msg(chan->idd, &msg, IDD_PORT_CMD_TX, NULL, NULL);
+
+ //
+ // Set rx framing mode
+ //
+ // if channel is being turned off
+ //
+ // channel off - rxmode = IDD_FRAME_DONTCARE
+ //
+ if (!turn_on)
+ IddFramingType = IDD_FRAME_DONTCARE;
+
+ IddSetRxFraming(chan->idd, chan->bchan, IddFramingType);
+
+ /* mark channel active state */
+ chan->active = turn_on;
+
+ return(CM_E_SUCC);
+}
+
+
+/* control data transfer on a bchannel */
+INT
+cm__bchan_ctrl_comp(CM_CHAN *chan, ULONG CompressionFlag)
+{
+ IDD_MSG msg;
+ USHORT Enable = 0;
+
+ D_LOG(D_ENTRY|DIGIQ931, ("cm__bchan_ctrl_comp: entry, chan: 0x%lx, state: %d\n", \
+ chan, CompressionFlag));
+
+ /* channel must be assigned */
+ if ( !CM_BCHAN_ASSIGNED(chan->bchan) )
+ return(CM_E_BADCHAN);
+
+ /* map channel type to operation */
+ if ( CompressionFlag )
+ Enable = COMP_TX_ENA | COMP_RX_ENA;
+
+ /* build msg */
+ NdisZeroMemory(&msg, sizeof(msg));
+ msg.opcode = CMD_COMPRESS;
+ msg.bufid = MAKELONG( chan->bchan | ( Enable << 8 ), 0);
+
+ /* send it */
+ idd_send_msg(chan->idd, &msg, IDD_PORT_CMD_TX, NULL, NULL);
+
+ return(CM_E_SUCC);
+}
+
+
+/* issue an element request to idp cm port */
+INT
+cm__elem_rq(VOID *idd, USHORT port, CHAR *elem_buf, USHORT elem_len)
+{
+ IDD_MSG msg;
+ CHAR *p;
+
+ D_LOG(D_ENTRY|DIGIQ931, ("cm__elem_rq: entry, idd: 0x%lx, port: 0x%d, elem_buf: 0x%lx, elem_len: 0x%d\n", \
+ idd, port, elem_buf, elem_len));
+
+ /* clear outgoing message */
+ NdisZeroMemory(&msg, sizeof(msg));
+
+ /* allocate a local buffer */
+ if ( !(msg.bufptr = p = ut_get_buf()) )
+ return(CM_E_NOMEM);
+
+ /* copy buffer */
+ adv_ptr(p, elem_buf, (INT)elem_len);
+
+ /* fillin message structure */
+ msg.opcode = Q931_ELEM_RQ;
+ msg.buflen = p - msg.bufptr;
+
+ /* send to idd */
+ if ( idd_send_msg(idd, &msg, port,
+ (VOID*)cm__q931_cmpl_handler, NULL) != IDD_E_SUCC )
+ {
+ ut_free_buf(msg.bufptr);
+ return(CM_E_IDD);
+ }
+
+ return(CM_E_SUCC);
+}
+
+/* completion handler for q931 command with attached local buffers */
+VOID
+cm__q931_cmpl_handler(VOID *arg, USHORT port, IDD_MSG *msg)
+{
+ D_LOG(D_ENTRY|DIGIQ931, ("cm__q931_cmpl_handler: arg: 0x%lx, port: 0x%d, msg: 0x%lx\n", \
+ arg, port, msg));
+
+ /* free attached buffer */
+ ut_free_buf(msg->bufptr);
+}
+
+/* handler for q931 events */
+VOID
+cm__q931_handler(IDD *idd, USHORT port, ULONG Reserved, IDD_MSG *msg)
+{
+ USHORT lterm;
+ CM_CHAN *chan;
+ CM *cm;
+ extern BOOL cm_terminated;
+
+ D_LOG(D_ENTRY|DIGIQ931, ("cm__q931_handler: entry, idd: 0x%lx, port: %d, msg: 0x%lx\n", \
+ idd, port, msg));
+ D_LOG(DIGIQ931, ("cm_q931_handler: msg->opcode: 0x%x\n", msg->opcode));
+
+ /* ignore if already terminated */
+ if ( cm_terminated )
+ return;
+
+ /* convert port to logical terminal */
+ lterm = port - IDD_PORT_CM0_RX;
+
+ /* try resolving idd/lterm/cid into a channel */
+ if ( chan = cm__map_chan(idd, lterm, HIWORD(msg->bufid)) )
+ cm = chan->cm;
+ else
+ cm = NULL;
+
+ D_LOG(DIGIQ931, ("cm_q931_handler: chan: 0x%lx, cm: 0x%lx\n", chan, cm));
+
+ //
+ // since q.931 stuff touches this so much it is easier to
+ // copy locally then to keep track of adapter memory access
+ //
+ NdisZeroMemory(idd->RxBuffer, sizeof(idd->RxBuffer));
+ IddGetDataFromAdapter(idd,
+ (PUCHAR)idd->RxBuffer,
+ (PUCHAR)msg->bufptr,
+ (USHORT)MIN(IDP_MAX_RX_BUFFER, msg->buflen));
+
+ msg->bufptr = idd->RxBuffer;
+
+ D_LOG(DIGIQ931, ("cm_q931_handler: msg->opcode: 0x%x", msg->opcode));
+
+ /* switch to message handler */
+ switch ( msg->opcode )
+ {
+ case Q931_EST_IND :
+ D_LOG(DIGIQ931, (" (Q931_EST_IND)\n"));
+ cm__ans_est_ind(chan, (IDD_MSG*)msg, idd, lterm);
+ break;
+
+ case Q931_CID_IND :
+ D_LOG(DIGIQ931, (" (Q931_CID_IND)\n"));
+ cm__org_cid_ind(chan, (IDD_MSG*)msg);
+ break;
+
+ case Q931_P_STATE_IND:
+ D_LOG(DIGIQ931, (" (Q931_P_STATE_IND)\n"));
+ break;
+
+ case Q931_STATE_IND :
+ D_LOG(DIGIQ931, (" (Q931_STATE_IND)\n"));
+ if ( !chan || cm )
+ cm__org_state_ind(chan, (IDD_MSG*)msg);
+ else if ( chan )
+ cm__ans_state_ind(chan, (IDD_MSG*)msg);
+ break;
+
+ case Q931_ELEM_IND :
+ D_LOG(DIGIQ931, (" (Q931_ELEM_IND)\n"));
+ if ( cm && !cm->was_listen )
+ cm__org_elem_ind(chan, (IDD_MSG*)msg);
+ break;
+
+ default :
+ D_LOG(DIGIQ931, (" (Unknown)\n"));
+ break;
+ }
+}
+
+VOID
+cm__ppp_conn(VOID *idd, USHORT port)
+{
+ CM_CHAN *chan;
+ CM *cm;
+ ULONG n, CompressionFlag;
+ IDD_MSG msg1;
+
+ /* try resolving idd/bchan into a channel */
+ if ( !(chan = cm__map_bchan_chan(idd, port)) )
+ return;
+
+ //
+ // if this channel is already connected no need to do this stuff
+ //
+ if (chan->ustate == CM_US_CONN)
+ return;
+
+ //
+ // kill dead man timer for this channel
+ //
+ NdisZeroMemory(&msg1, sizeof(IDD_MSG));
+ msg1.opcode = Q931_CAN_TU10_RQ;
+ msg1.bufptr = ut_get_buf();
+ msg1.buflen = 0;
+ msg1.bufid = MAKELONG(0, chan->cid);
+
+ /* send to idd */
+ if (idd_send_msg(chan->idd, &msg1, (USHORT)CM_PORT(chan), (VOID*)cm__q931_cmpl_handler, NULL) != IDD_E_SUCC)
+ ut_free_buf(msg1.bufptr);
+
+ NdisZeroMemory(chan->DstAddr, sizeof(chan->DstAddr));
+
+ /* last channel, find matching connection/profile */
+ if ( !(cm = cm__find_listen_conn("*", "*", "*", idd)) )
+ {
+ /* none found, reject */
+ D_LOG(DIGIQ931, ("cm__ppp_con: no listener found\n"));
+ return;
+ }
+
+ /* matching connection found!, fillin */
+ D_LOG(DIGIQ931, ("cm__ppp_conn: matching connection: chan: 0x%lx, cm: 0x%lx\n",
+ chan,
+ cm));
+
+ chan->remote_conn_index = 1;
+
+ cm->state = CM_ST_IN_ANS;
+ cm->StateChangeFlag = TRUE;
+ cm->was_listen = TRUE;
+ cm->active_chan_num = 1;
+ cm->remote_conn_index = chan->remote_conn_index;
+ cm->ConnectionType = CM_PPP;
+ NdisMoveMemory(cm->DstAddr, chan->DstAddr, 6);
+ NdisZeroMemory(cm->remote_name, sizeof(cm->remote_name));
+
+ cm->timeout = cm->rx_last_frame_time = cm->tx_last_frame_time =
+ ut_time_now();
+
+ /* accept channel here */
+ chan->ustate = CM_US_UUS_OKED;
+ chan->timeout = ut_time_now();
+ chan->cm = cm;
+
+ /* collect channels info local vector */
+ cm->dprof.chan_num = 0;
+ cm__chan_foreach(cm__add_chan, chan, cm);
+
+ /* init channel fields */
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++)
+ {
+ CM_CHAN *chan1 = cm->dprof.chan_tbl + n;
+
+ chan1->ustate = CM_US_CONN;
+ chan1->timeout = ut_time_now();
+ chan1->num = (USHORT)n;
+ chan1->cm = cm;
+ chan1->active = TRUE;
+ }
+
+ /* make connection active */
+ cm->state = CM_ST_ACTIVE;
+ cm->StateChangeFlag = TRUE;
+
+ // Set compression Flag
+ CompressionFlag = 0;
+
+ cm__activate_conn(cm, CompressionFlag);
+
+ return;
+}
+
+
+/* handler for bchannel data */
+VOID
+cm__q931_bchan_handler(
+ IDD *idd,
+ USHORT port,
+ ULONG RxFrameType,
+ IDD_XMSG *msg
+ )
+{
+ CM_CHAN *chan;
+ IDD_MSG msg1;
+ UCHAR DetectBytes[2];
+ extern BOOL cm_terminated;
+
+ D_LOG(D_ENTRY|DIGIQ931, ("cm__q931_bchan_handler: entry, idd: 0x%lx, port: %d, msg: 0x%lx\n", \
+ idd, port, msg));
+
+ /* ignore if terminated */
+ if ( cm_terminated )
+ return;
+
+ //
+ // check to see if this port is servicing DKF or PPP
+ //
+ if (RxFrameType != IDD_FRAME_DKF)
+ return;
+
+ //
+ // see if this is really uus or dror data
+ // if not uus we don't want to do all of the copying that we
+ // would do for uus
+ //
+ IddGetDataFromAdapter(idd,
+ (PUCHAR)&DetectBytes,
+ (PUCHAR)msg->bufptr,
+ 2);
+
+// NdisMoveMemory((PUCHAR)&DetectBytes, (PUCHAR)msg->bufptr, 2 * sizeof(UCHAR));
+
+ if ( (msg->buflen < 4) || DetectBytes[0] != DKF_UUS_SIG || DetectBytes[1])
+ return;
+
+ //
+ // since uus stuff touches this so much it is easier to
+ // copy locally then to keep track of adapter memory access
+ //
+ NdisZeroMemory(idd->RxBuffer, sizeof(idd->RxBuffer));
+ IddGetDataFromAdapter(idd,
+ (PUCHAR)idd->RxBuffer,
+ (PUCHAR)msg->bufptr,
+ (USHORT)MIN(IDP_MAX_RX_BUFFER, msg->buflen));
+
+ msg->bufptr = idd->RxBuffer;
+
+ D_LOG(DIGIQ931, ("cm__q931_bchan_handler: msg->buflen: 0x%x, DetectByte[0]: 0x%x\n", \
+ msg->buflen, DetectBytes[0]));
+
+ /* try resolving idd/bchan into a channel */
+ if ( !(chan = cm__map_bchan_chan(idd, port)) )
+ return;
+
+ //
+ // make a copy of the message without the header or
+ // fragmentation flags
+ //
+ NdisMoveMemory(&msg1, msg, sizeof(IDD_MSG));
+ msg1.bufptr += 4;
+ msg1.buflen -= 4;
+
+ /* call handler */
+ if ( chan->cm && !((CM*)(chan->cm))->was_listen )
+ cm__org_data_ind(chan, &msg1);
+ else
+ cm__ans_data_ind(chan, &msg1);
+}
+
+/* transmit a uus packet */
+INT
+cm__tx_uus_pkt(CM_CHAN *chan, UCHAR opcode, UCHAR cause)
+{
+ CHAR *p;
+ IDD_MSG msg;
+ CM_UUS *uus;
+ CM *cm = chan->cm;
+
+ /* must have a channel at this time */
+ if ( !CM_BCHAN_ASSIGNED(chan->bchan) )
+ return(CM_E_BADCHAN);
+
+ /* allocate a buffer for uus */
+ if ( !(p = ut_get_buf()) )
+ return(CM_E_NOMEM);
+
+ /* init messages structure */
+ NdisZeroMemory(&msg, sizeof(msg));
+ msg.bufptr = p;
+ msg.buflen = 4 + CM_UUS_SIZE;
+
+ /* build frame header */
+ *p++ = 0x50;
+ *p++ = 0x00;
+ *p++ = 0x00;
+ *p++ = 0x00;
+ uus = (CM_UUS*)p;
+
+ /* init uus */
+ NdisZeroMemory(uus, sizeof(*uus));
+ NdisMoveMemory(uus->dst_addr, "\xff\xff\xff\xff\xff\xff", 6);
+
+ if ( cm )
+ NdisMoveMemory(uus->src_addr, cm->SrcAddr, sizeof(uus->src_addr));
+ uus->pkt_type = CM_PKT_TYPE;
+ uus->prot_desc = CM_PROT_DESC;
+ uus->opcode = opcode;
+ uus->cause = cause;
+ uus->option_0 = 0;
+
+ if (cm)
+ if (cm->dprof.HWCompression)
+ uus->option_0 = UUS_0_COMPRESSION;
+
+ /* install connection fields */
+ uus->conn = cm ? cm->local_conn_index : 0;
+ uus->channum = cm ? (UCHAR)cm->dprof.chan_num : 0;
+ uus->chan = (UCHAR)chan->num;
+ if ( cm )
+ {
+ NdisMoveMemory(uus->lname, cm->dprof.name, sizeof(uus->lname));
+ NdisMoveMemory(uus->rname, cm->dprof.remote_name, sizeof(uus->rname));
+ cm->tx_last_frame_time = ut_time_now();
+ }
+
+ /* calc chksum */
+ uus->chksum = 256 - cm__calc_chksum(uus, CM_UUS_SIZE);
+
+ /* send message to idd */
+ if ( idd_send_msg(chan->idd, &msg, chan->bchan, (VOID*)cm__q931_cmpl_handler, chan)
+ != IDD_E_SUCC )
+ ut_free_buf(msg.bufptr);
+
+ return(CM_E_SUCC);
+}
+
+/* get channel identification out of q931 element buffer */
+INT
+cm__get_bchan(IDD_MSG *msg, USHORT *bchan)
+{
+ UCHAR *elem;
+
+
+ /* locate channel id element */
+ if ( !(elem = cm__q931_elem(msg->bufptr, msg->buflen, 0x18)) )
+ return(CM_E_NOSUCH);
+ else
+ elem++;
+
+ /* verify length */
+ if ( *elem++ != 0x1 )
+ return(CM_E_NOSUCH);
+
+ /* extract b channel */
+ if ( *elem == 0x89 )
+ *bchan = CM_BCHAN_B1;
+ else if ( *elem == 0x8A )
+ *bchan = CM_BCHAN_B2;
+ else
+ return(CM_E_NOSUCH);
+
+ /* if here, succ */
+ return(CM_E_SUCC);
+}
+
+/* get channel type out of q931 element buffer */
+INT
+cm__get_type(IDD_MSG *msg, USHORT *type)
+{
+ UCHAR *elem, elem_len;
+
+ /* locate type element */
+ if ( !(elem = cm__q931_elem(msg->bufptr, msg->buflen, 0x04)) )
+ return(CM_E_NOSUCH);
+ else
+ elem++;
+ elem_len = *elem++;
+
+ //
+ // added to support the new switch styles
+ // TB 03/14
+ //
+ if (SwitchStyle == CM_SWITCHSTYLE_1TR6)
+ {
+ switch (*elem)
+ {
+ case 0x01:
+ *type = CM_CT_VOICE;
+ return(CM_E_SUCC);
+
+ case 0x07:
+ *type = CM_CT_D64;
+ return(CM_E_SUCC);
+
+ default:
+ return(CM_E_BADPARAM);
+ }
+ }
+
+ /* if information transfer type is speech, -> voice */
+ if ( (*elem++ & 0x1F) == 0 )
+ {
+ *type = CM_CT_VOICE;
+ return(CM_E_SUCC);
+ }
+
+ /* trasnfer mode & type must be 64 */
+ if ( (*elem++ & 0x7F) != 0x10 )
+ return(CM_E_BADPARAM);
+
+ /* if end of element here, must be 64 */
+ if ( elem_len == 2 )
+ {
+ *type = CM_CT_D64;
+ return(CM_E_SUCC);
+ }
+
+ /* check for 56 */
+ if ( (elem_len >= 4) &&
+ ((*elem++ & 0x7F) == 0x21) &&
+ ((*elem++ & 0x7F) == 0x0F) )
+ {
+ *type = CM_CT_D56;
+ return(CM_E_SUCC);
+ }
+
+ /* if here, unknown */
+ return(CM_E_BADPARAM);
+}
+
+/* get caller address out of q931 element buffer */
+INT
+cm__get_addr(IDD_MSG *msg, CHAR addr[32])
+{
+ UCHAR *elem, elem_len;
+
+ /* locate type element */
+ if ( !(elem = cm__q931_elem(msg->bufptr, msg->buflen, 0x6C)) )
+ return(CM_E_NOSUCH);
+ else
+ elem++;
+
+// Subtracting 1 looks like a mistake
+// TB 11.09.93
+// if ( (elem_len = *elem++ - 1) > 32 )
+// elem_len = 31;
+ if ( (elem_len = *elem++) > 32 )
+ elem_len = 31;
+
+ if (elem_len < 2)
+ return(CM_E_NOSUCH);
+
+ elem += 2;
+ elem_len -= 2;
+
+ /* copy in & terminate */
+ NdisMoveMemory (addr, elem, elem_len);
+ addr[elem_len] = '\0';
+
+ return(CM_E_SUCC);
+}
+
+/* scan q931 element buffer for a specific element */
+UCHAR*
+cm__q931_elem(VOID *ptr_1, INT len, UCHAR elem)
+{
+ UCHAR *ptr = (UCHAR*)ptr_1;
+ CHAR codeset = 0; /* starting with code set 0 */
+ CHAR prev_codeset; /* saving area for prev. codeset */
+ CHAR locked = 1; /* locked/nonlocked codeset shift */
+
+ /* loop while length left */
+ while ( len > 0 )
+ {
+ /* handle shifting codesets */
+ if ( (*ptr & 0xF0) == 0x90 /*Q931_IE0_SHIFT*/ )
+ {
+ prev_codeset = codeset; /* save current code set */
+ codeset = *ptr & 0x07; /* extract new codeset */
+ locked = !(*ptr & 0x08); /* ... and locking status */
+ ptr++; /* move past shift element */
+ len--;
+ continue;
+ }
+
+ /* check for codeset 0 */
+ if ( codeset != 0 ) /* non codeset0 elements, just skip */
+ {
+ if ( *ptr & 0x80 )
+ {
+ ptr++;
+ len--;
+ }
+ //
+ // added to support the new switch styles
+ // TB 03/14
+ //
+ else if (SwitchStyle == CM_SWITCHSTYLE_1TR6 &&
+ elem == 0x04 &&
+ *ptr == 0x01)
+ {
+ return(ptr);
+ }
+ else
+ {
+ len -= (2 + ptr[1]);
+ ptr += (ptr[1] + 2);
+ }
+
+ if ( !locked )
+ {
+ codeset = prev_codeset;
+ locked = 1;
+ }
+
+ continue; /* move to next element */
+ }
+
+ /* try to match elem from codeset 0 */
+ if ( *ptr & 0x80 ) /* single octet elem? */
+ { /* yes */
+ if ( (((elem & 0xF0) == 0xA0) && (elem == (UCHAR)*ptr)) ||
+ (((elem & 0x80) == 0x80) && (elem == (UCHAR)(*ptr & 0xF0))) )
+ { /* element found */
+ return(ptr);
+ }
+ else
+ {
+ ptr++; /* skip this elem */
+ len--;
+ }
+ }
+ else
+ {
+ if ( *ptr == elem )
+ { /* multi byte elem match */
+ return(ptr);
+ }
+ else
+ {
+ len -= (2 + ptr[1]);
+ ptr += (ptr[1] + 2);
+ }
+ }
+
+ /* resert codeset if not locked */
+ if ( !locked )
+ {
+ codeset = prev_codeset;
+ locked = 1;
+ }
+ }
+
+ /* if here, not found */
+ return(NULL);
+}
+
+/* convert channel type to speed */
+ULONG
+cm__type2speed(USHORT type)
+{
+ switch ( type )
+ {
+ case CM_CT_VOICE :
+ case CM_CT_D56 :
+ return(56000);
+
+ case CM_CT_D64 :
+ default :
+ return(64000);
+ }
+}
diff --git a/private/ntos/ndis/digi/pcimac/cm_stat.c b/private/ntos/ndis/digi/pcimac/cm_stat.c
new file mode 100644
index 000000000..87c11cd69
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/cm_stat.c
@@ -0,0 +1,31 @@
+/*
+ * CM_STAT.C - status related code
+ */
+
+#include <ndis.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+
+/* get status from cm (note that CM == CM_STATUS for now!) */
+INT
+cm_get_status(VOID *cm_1, CM_STATUS *stat)
+{
+ CM* cm = (CM*)cm_1;
+
+ D_LOG(D_ENTRY, ("cm_get_status: entry, cm: 0x%lx, stat: 0x%lx", cm, stat));
+
+ /* set & return */
+ *stat = *cm;
+ return(CM_E_SUCC);
+}
+
+
+
diff --git a/private/ntos/ndis/digi/pcimac/cm_state.c b/private/ntos/ndis/digi/pcimac/cm_state.c
new file mode 100644
index 000000000..646feba1c
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/cm_state.c
@@ -0,0 +1,757 @@
+/*
+ * CM_STATE.C - q931 state managment code
+ */
+
+#include <ndis.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+
+#include <ansihelp.h>
+
+/* (ans) process incoming connections */
+INT
+cm__ans_est_ind(CM_CHAN *chan, IDD_MSG *msg, VOID *idd, USHORT lterm)
+{
+ USHORT bchan, type, cid;
+ INT RetCode;
+
+ D_LOG(D_ENTRY|DIGIQ931, ("cm__ans_est_ind: entry, chan: 0x%lx, msg: 0x%lx\n", \
+ chan, msg));
+
+ cid = HIWORD(msg->bufid);
+
+ /* must not have a channel at this time */
+ if ( chan )
+ {
+ D_LOG(D_ALWAYS|DIGIQ931, ("cm__ans_est_ind: on used channel, ignored!\n"));
+
+ RetCode = CM_E_BADPARAM;
+
+ //
+ // we need to let the adapter know that we are not processing
+ // this incoming call indication
+ //
+ ignored:
+
+ /* answer channel */
+ cm__est_ignore(idd, cid, lterm);
+
+ return(RetCode);
+ }
+
+ /* extract info out of message, must have bchan/type */
+ if ( (cm__get_bchan(msg, &bchan) != CM_E_SUCC) ||
+ (cm__get_type(msg, &type) != CM_E_SUCC) )
+ {
+ D_LOG(D_ALWAYS|DIGIQ931, ("cm__ans_est_ind: bchan or type missing, ignored!\n"));
+
+ RetCode = CM_E_BADPARAM;
+ goto ignored;
+ }
+
+ if ( !CM_BCHAN_ASSIGNED(bchan) )
+ {
+ D_LOG(D_ALWAYS|DIGIQ931, ("cm__ans_est_ind: bchan: %d, unassigned, ignored!\n",\
+ bchan));
+ RetCode = CM_E_BADPARAM;
+ goto ignored;
+ }
+
+ D_LOG(D_ALWAYS|DIGIQ931, ("cm__ans_est_ind: cid: 0x%x, bchan: %d, type: 0x%d\n",\
+ cid, bchan, type));
+
+ /* channel will be answered only if a listening profile exists */
+ if ( !cm__find_listen_conn("*", "*", "*", idd) )
+ {
+ D_LOG(D_ALWAYS|DIGIQ931, ("cm__ans_est_ind: not listening profile, ignored!\n"));
+ RetCode = CM_E_NOSUCH;
+ goto ignored;
+ }
+
+ /* allocate a channel out of incoming channel poll */
+ if ( !(chan = cm__chan_alloc()) )
+ {
+ D_LOG(D_ALWAYS|DIGIQ931, ("cm__ans_est_ind: no channel slot, ignored!\n"));
+ RetCode = CM_E_NOSLOT;
+ goto ignored;
+ }
+
+ /* fillup channel structure */
+ NdisZeroMemory(chan, sizeof(*chan));
+ chan->idd = idd;
+ chan->lterm = lterm;
+ chan->bchan = bchan;
+ chan->type = type;
+ chan->speed = cm__type2speed(type);
+ chan->ustate = CM_US_UNDEF;
+ chan->cid = cid;
+ chan->timeout = ut_time_now();
+
+ /* extract caller address, if present */
+ if ( cm__get_addr(msg, chan->addr) != CM_E_SUCC )
+ __strcpy(chan->addr, "<unknown>");
+
+ D_LOG(D_ALWAYS|DIGIQ931, ("cm__ans_est_ind: caller address is: %s\n", \
+ chan->addr));
+
+ /* answer channel */
+ cm__est_rsp(chan);
+
+ /* return succ */
+ return(CM_E_SUCC);
+}
+
+/* (ans) process state indications */
+INT
+cm__ans_state_ind(CM_CHAN *chan, IDD_MSG *msg)
+{
+ D_LOG(D_ENTRY|DIGIQ931, ("cm__ans_state_ind: entry, chan: 0x%lx, msg: 0x%lx\n", \
+ chan, msg));
+
+ /* log state change */
+ chan->ustate = LOWORD(msg->bufid);
+ D_LOG(D_ALWAYS|DIGIQ931, ("cm__ans_state_ind: ustate: %d\n", chan->ustate));
+
+ /* if changed to U0, has been released */
+ if ( !chan->ustate )
+ {
+ cm__bchan_ctrl(chan, 0);
+ cm__chan_free(chan);
+ return(CM_E_SUCC);
+ }
+
+ /* if changed to U10, just got connected, open data path */
+ if ( chan->ustate == 10 )
+ {
+ cm__bchan_ctrl(chan, 1);
+ chan->timeout = ut_time_now();
+ return(CM_E_SUCC);
+ }
+
+ /* else ignore */
+ return(CM_E_SUCC);
+}
+
+/* (ans) process data indications */
+INT
+cm__ans_data_ind(CM_CHAN *chan, IDD_MSG *msg)
+{
+ CM_UUS *uus;
+ ULONG chan_num, n;
+ UCHAR cause;
+ CM *cm;
+ ULONG CompressionFlag = 0;
+ IDD_MSG msg1;
+
+ D_LOG(D_ENTRY|DIGIQ931, ("cm__ans_data_ind: entry, chan: 0x%lx, msg: 0x%lx\n", \
+ chan, msg));
+
+ /* assign UUS pointer & do some basic checks */
+ uus = (CM_UUS*)msg->bufptr;
+ if ( msg->buflen < CM_UUS_SIZE )
+ return(CM_E_BADUUS);
+
+ if ( (uus->pkt_type != CM_PKT_TYPE) ||
+ (uus->prot_desc != CM_PROT_DESC) ||
+ (cm__calc_chksum(uus, CM_UUS_SIZE) != 0) )
+ return(CM_E_BADUUS);
+
+ /* channel must be atleast connected */
+ if ( chan->ustate < 10 )
+ return(CM_E_BADSTATE);
+
+ /* if channel already accepted assoc, accept again (other side lost) */
+ if ( chan->ustate == CM_US_UUS_OKED )
+ {
+ D_LOG(D_ALWAYS|DIGIQ931, ("cm__ans_data_ind: chan_num->ustate: %d\n", chan->ustate));
+ accept:
+ chan->ustate = CM_US_UUS_OKED;
+ chan->timeout = ut_time_now();
+ cm__tx_uus_pkt(chan, CM_ASSOC_ACK, 0);
+ return(CM_E_SUCC);
+ }
+
+ /* record information from uus */
+ NdisMoveMemory (chan->DstAddr, uus->src_addr, 6);
+
+ chan->remote_conn_index = uus->conn;
+
+ //
+ // kill dead man timer for this channel
+ //
+ NdisZeroMemory(&msg1, sizeof(IDD_MSG));
+ msg1.opcode = Q931_CAN_TU10_RQ;
+ msg1.bufptr = ut_get_buf();
+ msg1.buflen = 0;
+ msg1.bufid = MAKELONG(0, chan->cid);
+
+ /* send to idd */
+ if (idd_send_msg(chan->idd, &msg1, (USHORT)CM_PORT(chan), (VOID*)cm__q931_cmpl_handler, NULL) != IDD_E_SUCC)
+ ut_free_buf(msg1.bufptr);
+
+
+ /* if not last channel, accept */
+ chan_num = 0;
+ cm__chan_foreach(cm__inc_chan_num, chan, &chan_num);
+ if ( (UCHAR)chan_num < uus->channum )
+ {
+ D_LOG(D_ALWAYS|DIGIQ931, ("cm__ans_data_ind: chan_num: %d, uus->channum: %d\n", chan_num, uus->channum));
+ goto accept;
+ }
+
+
+ /* last channel, find matching connection/profile */
+ if ( !(cm = cm__find_listen_conn(uus->lname, uus->rname, chan->addr, chan->idd)) )
+ {
+ /* none found, reject */
+ cause = CM_NO_PROF;
+ D_LOG(D_ALWAYS|DIGIQ931, ("cm__ans_data_ind: rejected, cause: %d\n", cause));
+ cm__tx_uus_pkt(chan, CM_ASSOC_NACK, cause);
+ return(CM_E_NOSUCH);
+ }
+
+ /* matching connection found!, fillin */
+ D_LOG(D_ALWAYS|DIGIQ931, ("cm__ans_data_ind: matching connection: cm: 0x%lx\n", cm));
+
+ cm->state = CM_ST_IN_ANS;
+ cm->StateChangeFlag = TRUE;
+ cm->was_listen = TRUE;
+ cm->active_chan_num = chan_num;
+ cm->remote_conn_index = chan->remote_conn_index;
+ cm->ConnectionType = CM_DKF;
+ NdisMoveMemory(cm->DstAddr, chan->DstAddr, 6);
+ NdisMoveMemory (cm->remote_name, uus->rname, sizeof(cm->remote_name));
+
+ cm->timeout = cm->rx_last_frame_time = cm->tx_last_frame_time =
+ ut_time_now();
+
+ /* accept channel here */
+ chan->ustate = CM_US_UUS_OKED;
+ chan->timeout = ut_time_now();
+ chan->cm = cm;
+ cm__tx_uus_pkt(chan, CM_ASSOC_ACK, 0);
+
+
+ /* collect channels info local vector */
+ cm->dprof.chan_num = 0;
+ cm__chan_foreach(cm__add_chan, chan, cm);
+
+ /* init channel fields */
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++)
+ {
+ CM_CHAN *chan = cm->dprof.chan_tbl + n;
+
+ chan->ustate = CM_US_CONN;
+ chan->timeout = ut_time_now();
+ chan->num = (USHORT)n;
+ chan->cm = cm;
+ chan->active = TRUE;
+ }
+
+ /* make connection active */
+ cm->state = CM_ST_ACTIVE;
+ cm->StateChangeFlag = TRUE;
+
+ // Set compression Flag
+ if (cm->dprof.HWCompression && (uus->option_0 & UUS_0_COMPRESSION))
+ CompressionFlag = 1;
+ else
+ CompressionFlag = 0;
+
+ D_LOG(D_ALWAYS|DIGIQ931, ("cm__ans_data_ind: Activating connection for cm: 0x%lx\n", cm));
+ return(cm__activate_conn(cm, CompressionFlag));
+}
+
+/* (org) new cid indicated on outgoing channel */
+INT
+cm__org_cid_ind(CM_CHAN *chan, IDD_MSG *msg)
+{
+ CM *cm;
+ USHORT conn_num, chan_num, cid;
+
+ D_LOG(D_ENTRY|DIGIQ931, ("cm__org_cid_ind: entry, chan: 0x%lx, msg: 0x%lx\n", \
+ chan, msg));
+
+ /* extract conn_num/chan_num out of param 3, get cid */
+ conn_num = HIBYTE(LOWORD(msg->bufid));
+ chan_num = LOBYTE(LOWORD(msg->bufid));
+ cid = HIWORD(msg->bufid);
+ D_LOG(D_ALWAYS|DIGIQ931, ("cm__org_cid_ind: conn_num: %d, chan_num: %d, cid: 0x%x\n", conn_num, chan_num, cid));
+
+// DbgPrint("cid_ind: conn_num: %d, chan_num: %d, cid: 0x%x\n",
+// conn_num, chan_num, cid);
+
+ /* get related connection */
+ if ( !(cm = cm__get_conn(conn_num)) )
+ {
+// DbgPrint("cid_ind: cm__get_conn failed!\n");
+ return(CM_E_BADPARAM);
+ }
+
+ /* get related channel */
+ if ( chan_num >= cm->dprof.chan_num )
+ {
+// DbgPrint("cid_ind: invalid chan_num!\n");
+ return(CM_E_BADPARAM);
+ }
+ else
+ chan = cm->dprof.chan_tbl + chan_num;
+
+ /* check channel ustate */
+ if ( chan->ustate != CM_US_WAIT_CID )
+ {
+// DbgPrint("cid_ind: invalid ustate (%d)!\n", chan->ustate);
+ return(CM_E_BADSTATE);
+ }
+
+ /* cid == 0, no free slots at idp, simulate state change to 0 */
+ if ( !cid )
+ {
+ cm->NoActiveLine = 1;
+ return(cm__org_state_ind(chan, NULL));
+ }
+
+ /* assign params */
+ chan->ustate = CM_US_UNDEF;
+ chan->cid = cid;
+// DbgPrint("cid_ind: ustate: %d, cid: 0x%x assigned\n", chan->ustate, chan->cid);
+
+ return(CM_E_SUCC);
+}
+
+/* (org) process state indications */
+INT
+cm__org_state_ind(CM_CHAN *chan, IDD_MSG *msg)
+{
+ CM *cm;
+ ULONG n;
+ USHORT gave_up_num, chan_num;
+ ULONG CompressionFlag;
+
+ D_LOG(D_ENTRY|DIGIQ931, ("cm__org_state_ind: entry, chan: 0x%lx, msg: 0x%lx\n", \
+ chan, msg));
+
+ /* check for change of state at protocol level */
+ if ( !chan )
+ {
+ /* not used for now */
+ return(CM_E_NOTIMPL);
+ }
+
+ /* log change */
+ cm = chan->cm;
+
+ chan->ustate = msg ? LOWORD(msg->bufid) : 0;
+
+ D_LOG(DIGIQ931,("cm__org_state_ind: cm 0x%lx, ustate: 0x%x\n", \
+ cm, chan->ustate));
+
+ /* if changed to U0, has been released, may retry connection here */
+ if ( !chan->ustate )
+ {
+ /* turn off bchannel */
+ cm__bchan_ctrl(chan, 0);
+
+ /* if not in activation, this is a fatal error, disconnect */
+ if ( cm->state != CM_ST_IN_ACT )
+ {
+ disc_all:
+
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++ )
+ {
+ CM_CHAN *chan1 = cm->dprof.chan_tbl + n;
+
+ if ( chan1->ustate > 0 )
+ cm__disc_rq(chan1);
+ }
+
+ /* deactivate connection */
+ cm__deactivate_conn(cm, 0);
+
+ return(CM_E_SUCC);
+ }
+
+ /* attampt to retry */
+ if ( !cm->dprof.fallback ||
+ (cm->CauseValue == 0x11 || cm->SignalValue == 0x04) ||
+ (cm__get_next_chan(chan) != CM_E_SUCC) )
+ {
+ chan->ustate = CM_US_GAVE_UP;
+ chan->gave_up = 1;
+ }
+ else
+ {
+ /* if here, retrying */
+ chan->cid = MAKEWORD(chan->num, cm->local_conn_index);
+ chan->ustate = CM_US_WAIT_CID;
+ chan->timeout = ut_time_now();
+
+ cm__est_rq(chan);
+ }
+
+ /* find out how many channels gave up (or connected) */
+ check_chan:
+ for ( n = gave_up_num = 0 ; n < cm->dprof.chan_num ; n++ )
+ if ( cm->dprof.chan_tbl[n].gave_up )
+ gave_up_num++;
+ else if ( cm->dprof.chan_tbl[n].ustate != CM_US_WAIT_CONN )
+ break;
+
+ /* if broke out of loop before hitting chan_num, some channels
+ are still in progress */
+ if ( n < cm->dprof.chan_num )
+ return(CM_E_SUCC);
+
+ /* if all gave up, give up conn */
+ if ( gave_up_num >= cm->dprof.chan_num )
+ {
+ cm__deactivate_conn(cm, 0);
+ return(CM_E_SUCC);
+ }
+
+ /* if here, some channels connected and some gave up, continue */
+ chan_num = cm->dprof.chan_num - gave_up_num;
+
+ /* if fallback set to no, must match */
+ if ( !cm->dprof.fallback && (chan_num != cm->dprof.chan_num) )
+ goto disc_all;
+
+ /* connection enters in_sync state */
+ cm->state = CM_ST_IN_SYNC;
+ cm->StateChangeFlag = TRUE;
+ cm->timeout = ut_time_now();
+
+ /* compact channel table & renumber */
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++ )
+ {
+ CM_CHAN *chan1 = cm->dprof.chan_tbl + n;
+
+ if ( chan1->gave_up )
+ {
+ NdisMoveMemory(cm->dprof.chan_tbl + n,
+ cm->dprof.chan_tbl + n + 1,
+ sizeof(CM_CHAN) * (cm->dprof.chan_num - n - 1));
+ cm->dprof.chan_num--;
+ n--;
+ }
+ }
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++ )
+ cm->dprof.chan_tbl[n].num = (USHORT)n;
+
+ if (cm->ConnectionType == CM_DKF)
+ {
+ //
+ // if this is a uus connnection tx uus frames
+ //
+ /* send initial uus_rq on all active channels */
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++ )
+ {
+ CM_CHAN *chan1 = cm->dprof.chan_tbl + n;
+
+ if ( chan1->gave_up )
+ continue;
+
+ chan1->timeout = ut_time_now();
+ chan1->ustate = CM_US_UUS_SEND;
+
+ cm__tx_uus_pkt(chan1, CM_ASSOC_RQ, 0);
+ }
+ }
+ else
+ {
+ //
+ // if this is a ppp connection mark channels
+ // as being connected and activate the connection
+ //
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++ )
+ {
+ CM_CHAN *chan1 = cm->dprof.chan_tbl + n;
+
+ if ( chan1->gave_up )
+ continue;
+
+ chan1->ustate = CM_US_CONN;
+ chan1->timeout = ut_time_now();
+ chan1->remote_conn_index = 1;
+ }
+ NdisZeroMemory(cm->DstAddr, sizeof(cm->DstAddr));
+ NdisZeroMemory(cm->remote_name, sizeof(cm->remote_name));
+
+ /* make connection active now */
+ cm->state = CM_ST_ACTIVE;
+ cm->StateChangeFlag = TRUE;
+ CompressionFlag = 0;
+
+ return (cm__activate_conn(cm, CompressionFlag));
+ }
+
+ return(CM_E_SUCC);
+ }
+
+ /* if change state to U10 just connected */
+ if ( chan->ustate == 10 )
+ {
+ /* start data transfer on channel */
+ cm__bchan_ctrl(chan, 1);
+ chan->ustate = CM_US_WAIT_CONN;
+ chan->timeout = ut_time_now();
+
+ /* see if all channels are connected, continue as a change to U0 */
+ goto check_chan;
+ }
+}
+
+/* (org) process data indications */
+INT
+cm__org_data_ind(CM_CHAN *chan, IDD_MSG *msg)
+{
+ CM_UUS *uus;
+ CM *cm = chan->cm;
+ ULONG n, first;
+ ULONG CompressionFlag;
+
+ D_LOG(D_ENTRY|DIGIQ931, ("cm__org_data_ind: entry, chan: 0x%lx, msg: 0x%lx\n", \
+ chan, msg));
+
+
+ /* assign UUS pointer & do some basic checks */
+ uus = (CM_UUS*)msg->bufptr;
+ if ( msg->buflen < CM_UUS_SIZE )
+ return(CM_E_BADUUS);
+ if ( (uus->pkt_type != CM_PKT_TYPE) ||
+ (uus->prot_desc != CM_PROT_DESC) ||
+ (cm__calc_chksum(uus, CM_UUS_SIZE) != 0) )
+ return(CM_E_BADUUS);
+
+ /* channel must be atleast connected */
+ if ( chan->ustate < 10 )
+ return(CM_E_BADSTATE);
+
+ /* if is a request, channel is part of a listening conn */
+ if ( uus->opcode == CM_ASSOC_RQ )
+ {
+ cm__tx_uus_pkt(chan, CM_ASSOC_ACK, 0);
+ return(CM_E_SUCC);
+ }
+
+ /* if nack detected, connection is torn down */
+ if ( uus->opcode == CM_ASSOC_NACK )
+ {
+// disc_all:
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++ )
+ {
+ CM_CHAN *chan1 = cm->dprof.chan_tbl + n;
+
+ if ( chan1->ustate > 0 )
+ cm__disc_rq(chan1);
+ }
+
+ /* deactivate connection */
+ cm__deactivate_conn(cm, 0);
+
+ return(CM_E_SUCC);
+ }
+
+ /* if here must be an ack */
+ if ( uus->opcode != CM_ASSOC_ACK )
+ return(CM_E_BADUUS);
+
+ /* if channel already connected and uus ack'ed - ignore */
+ if ( chan->ustate > CM_US_UUS_OKED )
+ return(CM_E_SUCC);
+
+ //
+ // if this flag is set then we originally had a PPP connection
+ // this means that all of the connection stuff is taken care of and
+ // we just need to satisfy the remote ends uus requirements.
+ // there should be only one channel in this case!
+ //
+ if (cm->PPPToDKF)
+ {
+ chan->ustate = CM_US_CONN;
+ NdisMoveMemory (chan->DstAddr, uus->src_addr, 6);
+ NdisMoveMemory(cm->DstAddr, chan->DstAddr, 6);
+ cm->remote_conn_index = cm->dprof.chan_tbl[0].remote_conn_index;
+ NdisMoveMemory(cm->remote_name, uus->lname, sizeof(cm->remote_name));
+ cm->PPPToDKF = 0;
+ return(CM_E_SUCC);
+ }
+
+ /* if here, it is an ack */
+ chan->ustate = CM_US_UUS_OKED;
+ chan->timeout = ut_time_now();
+
+ NdisMoveMemory (chan->DstAddr, uus->src_addr, 6);
+
+ chan->remote_conn_index = uus->conn;
+
+ /* proceed only if all channels ok'ed */
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++ )
+ if ( !cm->dprof.chan_tbl[n].gave_up &&
+ (cm->dprof.chan_tbl[n].ustate != CM_US_UUS_OKED) )
+ return(CM_E_SUCC);
+
+ /* verify all channel got connected to the same eaddr/conn */
+ for ( first = 0 ; first < cm->dprof.chan_num ; first++ )
+ if ( !cm->dprof.chan_tbl[n].gave_up )
+ break;
+
+ /* move all channels to connected state */
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++ )
+ if ( !cm->dprof.chan_tbl[n].gave_up )
+ {
+ cm->dprof.chan_tbl[n].ustate = CM_US_CONN;
+ cm->dprof.chan_tbl[n].timeout = ut_time_now();
+ }
+
+// Hack to get around no cm for all channels < the last channel received
+ NdisMoveMemory(cm->DstAddr, chan->DstAddr, 6);
+
+ /* store some values on a connection level */
+ cm->remote_conn_index = cm->dprof.chan_tbl[first].remote_conn_index;
+ NdisMoveMemory(cm->remote_name, uus->lname, sizeof(cm->remote_name));
+
+ /* make connection active now */
+ cm->state = CM_ST_ACTIVE;
+ cm->StateChangeFlag = TRUE;
+
+ // Set compression Flag
+ if (cm->dprof.HWCompression && (uus->option_0 & UUS_0_COMPRESSION))
+ CompressionFlag = 1;
+ else
+ CompressionFlag = 0;
+
+ return(cm__activate_conn(cm, CompressionFlag));
+}
+
+/* (org) process element indications */
+INT
+cm__org_elem_ind(CM_CHAN *chan, IDD_MSG *msg)
+{
+ USHORT bchan;
+ int auto_disc = 0;
+ CHAR *elem;
+
+ D_LOG(D_ENTRY|DIGIQ931, ("cm__org_elem_ind: entry, chan: 0x%lx, msg: 0x%lx\n", \
+ chan, msg));
+
+ /* must have a valid channel to proceed */
+ if ( !chan )
+ return(CM_E_SUCC);
+
+ /* check if bchannel reported */
+ if ( cm__get_bchan(msg, &bchan) == CM_E_SUCC )
+ {
+ D_LOG(D_ALWAYS|DIGIQ931, ("cm__org_elem_ind: bchan: %d\n", bchan));
+
+ if ( !CM_BCHAN_ASSIGNED(chan->bchan) )
+ auto_disc |= 1;
+ else
+ chan->bchan = bchan;
+ }
+
+ /* scan for cause */
+ if ( (elem = cm__q931_elem(msg->bufptr, msg->buflen, 0x08)) &&
+ (elem[1] >= 2) && !(elem[2] & 0x78) )
+ {
+ static CHAR disc_vals[] = { 0x01, 0x11, 0x12 };
+
+ D_LOG(D_ALWAYS|DIGIQ931, ("cm__org_elem_ind: cause: 0x%x\n", elem[3] & 0x7F));
+
+ if ( __memchr((PUCHAR)disc_vals,(CHAR) elem[3] & 0x7F, (ULONG) sizeof(disc_vals)) )
+ {
+ CM *cm = (CM*)chan->cm;
+
+ cm->CauseValue = elem[3] & 0x7F;
+ auto_disc |= 2;
+ }
+ }
+
+ /* scan for signal */
+ if ( (elem = cm__q931_elem(msg->bufptr, msg->buflen, 0x34)) &&
+ (elem[1] == 1) )
+ {
+// static CHAR signal_vals[] = { 0x00, 0x03, 0x04, 0x0C };
+ static CHAR signal_vals[] = { 0x03, 0x04, 0x0C };
+
+ D_LOG(D_ALWAYS|DIGIQ931, ("cm__org_elem_ind: signal: 0x%x\n", elem[2]));
+
+ if ( __memchr(signal_vals, elem[2], sizeof(signal_vals)) )
+ {
+ CM *cm = (CM*)chan->cm;
+
+ cm->SignalValue = elem[2];
+ auto_disc |= 4;
+ }
+ }
+
+ /* check if need to disconnect */
+ if ( auto_disc )
+ {
+ D_LOG(D_ALWAYS|DIGIQ931, ("cm__org_elem_ind: auto_disc: 0x%x\n", auto_disc));
+ cm__disc_rq(chan);
+ }
+
+ return(CM_E_SUCC);
+}
+
+/* calc a checksum for a buffer */
+UCHAR
+cm__calc_chksum(VOID *buf_1, INT len)
+{
+ UCHAR *buf = (UCHAR *)buf_1;
+ UCHAR sum;
+
+ for ( sum = 0 ; len ; len-- )
+ sum += *buf++;
+
+ return(sum);
+}
+
+/* increment a channel count */
+BOOL
+cm__inc_chan_num(CM_CHAN *chan, CM_CHAN *ref_chan, ULONG *chan_num)
+{
+ /* find if this channel is part of same connection as ref_chan */
+ if ( memcmp(chan->DstAddr, ref_chan->DstAddr, 6) ||
+ (chan->remote_conn_index != ref_chan->remote_conn_index) )
+ return(TRUE);
+
+ /* inrement here */
+ *chan_num += 1;
+ return(TRUE);
+}
+
+/* add a channel to a connection */
+BOOL
+cm__add_chan(CM_CHAN *chan, CM_CHAN *ref_chan, CM *cm)
+{
+ CM_CHAN *chan1;
+
+ /* if connection already full, stop here */
+ if ( cm->dprof.chan_num >= cm->active_chan_num )
+ return(FALSE);
+
+ /* find if this channel is part of same connection as ref_chan */
+ if ( memcmp(chan->DstAddr, ref_chan->DstAddr, 6) ||
+ (chan->remote_conn_index != ref_chan->remote_conn_index) )
+ return(TRUE);
+
+ /* add this channel */
+ chan1 = &cm->dprof.chan_tbl[cm->dprof.chan_num++];
+ *chan1 = *chan;
+ cm__chan_free(chan);
+ return(TRUE);
+}
+
+
+
+
diff --git a/private/ntos/ndis/digi/pcimac/cm_timer.c b/private/ntos/ndis/digi/pcimac/cm_timer.c
new file mode 100644
index 000000000..20ce83bd0
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/cm_timer.c
@@ -0,0 +1,78 @@
+/*
+ * CM_TIMER.C - time code for cm module
+ */
+
+#include <ndis.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+
+/* timer values defined here */
+#define T1 30 /* 30 seconds to leave connection transient state */
+#define T2 4 /* 4 seconds to activate permanent connection */
+
+/* timer tick entry point. called no faster then once a second! */
+INT
+cm__timer_tick(CM *cm)
+{
+ ULONG n;
+ BOOL disc_by_idle_timer = FALSE;
+
+ /* check for dead-man time in transient state */
+ if ( (cm->state == CM_ST_IN_SYNC) || (cm->state == CM_ST_IN_ACT) )
+ {
+ if ( (ut_time_now() - cm->timeout) > T1 )
+ {
+ disc_all:
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++ )
+ if ( !cm->dprof.chan_tbl[n].gave_up )
+ cm__disc_rq(cm->dprof.chan_tbl + n);
+
+ return(cm__deactivate_conn(cm, disc_by_idle_timer));
+ }
+ }
+
+ /* if active now, check for idle timers */
+ if ( cm->state == CM_ST_ACTIVE )
+ {
+ if ( (cm->dprof.rx_idle_timer &&
+ ((ut_time_now() - cm->rx_last_frame_time) > cm->dprof.rx_idle_timer)) ||
+ (cm->dprof.tx_idle_timer &&
+ ((ut_time_now() - cm->tx_last_frame_time) > cm->dprof.tx_idle_timer)) )
+ {
+ disc_by_idle_timer = TRUE;
+ goto disc_all;
+ }
+ }
+
+ /* check if connection has to activate as being permanent */
+ if ( (cm->state == CM_ST_WAIT_ACT) && cm->dprof.permanent )
+ {
+ if ( (ut_time_now() - cm->timeout) > T2 )
+ {
+ cm->state = CM_ST_IN_ACT;
+ cm->timeout = ut_time_now();
+ return(cm__initiate_conn(cm));
+ }
+ }
+
+ /* if in_sync, resend uus on channels requiring it */
+ //
+ // if we are stuck in sync state the resend uus on all channels requiring it
+ // if we are in an ACTIVE state and the PPPToDKF Flag is set we need to send
+ // uus until they acknowledged
+ //
+ if ( cm->state == CM_ST_IN_SYNC || (cm->state == CM_ST_ACTIVE && cm->PPPToDKF))
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++ )
+ if ( cm->dprof.chan_tbl[n].ustate == CM_US_UUS_SEND )
+ cm__tx_uus_pkt(cm->dprof.chan_tbl + n, CM_ASSOC_RQ, 0);
+}
+
+
diff --git a/private/ntos/ndis/digi/pcimac/cnf.h b/private/ntos/ndis/digi/pcimac/cnf.h
new file mode 100644
index 000000000..a897e0b22
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/cnf.h
@@ -0,0 +1,13 @@
+/*
+ * CNF_PUB.H - config module public defs
+ */
+
+/* class operations */
+BOOL cnf_get_long(CHAR* path, CHAR* key,
+ ULONG* ret_val, ULONG def_val);
+BOOL cnf_get_str(CHAR* path, CHAR* key,
+ CHAR* ret_val, ULONG maxlen, CHAR* def_val);
+BOOL cnf_get_multi_str(CHAR* path, CHAR* key,
+ CHAR* store_buf, ULONG store_len,
+ CHAR** str_vec, ULONG str_max, ULONG* str_num,
+ CHAR** def_vec, ULONG def_num);
diff --git a/private/ntos/ndis/digi/pcimac/dgbrip.h b/private/ntos/ndis/digi/pcimac/dgbrip.h
new file mode 100644
index 000000000..0897fb1f3
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/dgbrip.h
@@ -0,0 +1,33 @@
+#ifndef DGBRIP_H
+#define DGBRIP_H
+
+/*++
+*****************************************************************************
+* *
+* This software contains proprietary and confidential information of *
+* *
+* Digi International Inc. *
+* *
+* By accepting transfer of this copy, Recipient agrees to retain this *
+* software in confidence, to prevent disclosure to others, and to make *
+* no use of this software other than that for which it was delivered. *
+* This is an unpublished copyrighted work of Digi International Inc. *
+* Except as permitted by federal law, 17 USC 117, copying is strictly *
+* prohibited. *
+* *
+*****************************************************************************
+++*/
+
+
+typedef enum _DIGI_BRI_COMMAND_
+{
+ BRIOldMethod = LastGeneralID + 1
+} DIGI_BRI_COMMAND;
+
+typedef struct _DIGI_OLD_METHOD_
+{
+ IO_CMD ioCmd;
+} DIGI_OLD_METHOD, *PDIGI_OLD_METHOD;
+
+
+#endif
diff --git a/private/ntos/ndis/digi/pcimac/disp.c b/private/ntos/ndis/digi/pcimac/disp.c
new file mode 100644
index 000000000..8e80ca2bc
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/disp.c
@@ -0,0 +1,105 @@
+/*
+ * DISP.C - debug display routines for NDIS environment
+ */
+
+#include <ndis.h>
+#include <ndiswan.h>
+#include <mydefs.h>
+#include <mytypes.h>
+#include <stdarg.h>
+#include <ansihelp.h>
+#include <util.h>
+#include <adapter.h>
+#include <idd.h>
+#include <cm.h>
+#include <mtl.h>
+#include <trc.h>
+#include <io.h>
+
+#if DBG
+#define DISP_DEBUG 1
+#endif
+
+INT d_level = -1; /* current debug level */
+INT d_mode = 0; /* display mode: 0-dbg, 1-msg */
+INT d_cmplen = 0; /* lenght of filename string for compare */
+CHAR d_filestr[8]; /* filename string for compare */
+NDIS_SPIN_LOCK DebugLock;
+
+VOID
+d_log_init (VOID)
+{
+ NdisAllocateSpinLock (&DebugLock);
+}
+
+VOID
+d_log_term (VOID)
+{
+ NdisFreeSpinLock (&DebugLock);
+}
+
+
+/* check if logging enabled on file,line,level (for now, always on) */
+INT
+d_log_on(CHAR *file, INT line, INT level)
+{
+ CHAR *fname;
+
+ if ( level > d_level )
+ return(0);
+
+ if ( fname = __strrchr(file, '\\') )
+ fname++;
+ else
+ fname = file;
+
+ if(d_cmplen && __strnicmp(fname,d_filestr,d_cmplen))
+ return(0);
+
+ NdisAcquireSpinLock(&DebugLock);
+ DbgPrint("PCIMAC.SYS: ");
+
+ return(1);
+}
+
+/* do output processing for logging */
+VOID
+d_log_out(CHAR* fmt, ...)
+{
+ static CHAR buf[256];
+ va_list marker;
+
+ va_start (marker, fmt);
+#if !BINARY_COMPATIBLE
+ vsprintf (buf, fmt, marker);
+#endif
+ va_end (marker);
+ DbgPrint ("%s\n",buf);
+
+ NdisReleaseSpinLock(&DebugLock);
+
+}
+
+VOID
+InternalSetDebugLevel (INT DebugLevel)
+{
+ d_level = DebugLevel;
+}
+
+
+VOID
+SetDebugLevel (VOID *cmd1)
+{
+ IO_CMD *cmd = (IO_CMD*)cmd1;
+ d_level = (INT)cmd->arg[0];
+ d_cmplen = (INT)cmd->val.dbg_level.cmplen;
+ if(d_cmplen)
+ NdisMoveMemory(d_filestr,cmd->val.dbg_level.filestr,d_cmplen);
+
+ if ( d_level != -1 )
+ {
+ d_mode = d_level / 1000;
+ d_level = d_level % 1000;
+ }
+}
+
diff --git a/private/ntos/ndis/digi/pcimac/disp.h b/private/ntos/ndis/digi/pcimac/disp.h
new file mode 100644
index 000000000..b79bbf5fe
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/disp.h
@@ -0,0 +1,147 @@
+/*
+ * DISP.H - debug display macro's under NDIS
+ */
+
+#ifndef _DISP_
+#define _DISP_
+
+#if !BINARY_COMPATIBLE
+#include "digifile.h"
+#include "memprint.h"
+#else
+#define DbgBreakPoint() {__asm { int 3 };}
+#endif
+
+extern ULONG DigiDebugLevel;
+
+#define DIGIINIT ((ULONG)0x00000001)
+#define DIGISETINFO ((ULONG)0x00000002)
+#define DIGIGETINFO ((ULONG)0x00000004)
+#define DIGIWANINFO ((ULONG)0x00000008)
+#define DIGISXBINFO ((ULONG)0x00000010)
+#define DIGITAPIINFO ((ULONG)0x00000020)
+#define DIGIRECVDATA ((ULONG)0x00000040)
+#define DIGITXDATA ((ULONG)0x00000080)
+#define DIGIRARE ((ULONG)0x00000100)
+#define DIGIWANERR ((ULONG)0x00000200)
+#define DIGIWANERRDATA ((ULONG)0x00000400)
+#define DIGIRXDATA ((ULONG)0x00000800)
+#define DIGIWANOID ((ULONG)0x00010000)
+#define DIGIQ931 ((ULONG)0x00020000)
+#define DIGIIRP ((ULONG)0x00040000)
+#define DIGIWAIT ((ULONG)0x00080000)
+#define DIGITXFRAGDATA ((ULONG)0x00100000)
+#define DIGIRXFRAGDATA ((ULONG)0x00200000)
+#define DIGIIDD ((ULONG)0x00400000)
+#define DIGINEVER ((ULONG)0x00800000)
+#define DIGIATLASFLOW ((ULONG)0x01000000)
+#define DIGIWINISDN ((ULONG)0x02000000)
+#define DIGICALLSTATES ((ULONG)0x04000000)
+#define DIGIMTL ((ULONG)0x08000000)
+#define DIGIFLOW ((ULONG)0x10000000)
+#define DIGIERRORS ((ULONG)0x20000000)
+#define DIGINOTIMPLEMENTED ((ULONG)0x40000000)
+#define DIGIBUGCHECK ((ULONG)0x80000000)
+#define DIGIINFO (DIGIGETINFO | DIGISETINFO)
+
+#if DBG
+
+#define DigiAssert 1
+#if DigiAssert
+#undef ASSERT
+#define ASSERT( STRING ) \
+ if( !(STRING) ) \
+ { \
+ DbgPrint( "ASSERT failed: " #STRING "\nfile: %s, line %d\n", __FILE__, __LINE__ ); \
+ DbgBreakPoint(); \
+ }
+#endif
+
+#define DigiDump(LEVEL,STRING) \
+ do { \
+ ULONG _level = (LEVEL); \
+ if ((DigiDebugLevel & _level) || (_level & DIGINOTIMPLEMENTED)) \
+ { \
+ DbgPrint STRING; \
+ } \
+ if (_level & DIGIBUGCHECK) \
+ { \
+ ASSERT(FALSE); \
+ } \
+ } while (0)
+
+#define DigiDumpData(LEVEL, DATA, LEN) \
+ do \
+ { \
+ ULONG _DataLevel = (LEVEL); \
+ ULONG _i, _k; \
+ ULONG _len = (LEN); \
+ PCHAR _data = (DATA); \
+ \
+ _k = 0; \
+ while( _k <= _len ) \
+ { \
+ if( (_len - _k) > 16 ) \
+ { \
+ for( _i = 0; _i < 16; _i++ ) \
+ { \
+ DigiDump( _DataLevel, ( "%02x ", (_data[_i] & 0xFF)) ); \
+ _k++; \
+ } \
+ \
+ DigiDump( _DataLevel, ( " ") ); \
+ \
+ for( _i = 0; _i < 16; _i++ ) \
+ { \
+ if( _data[_i] >= 0x20 && _data[_i] <= 0x7E ) \
+ DigiDump( _DataLevel, ( "%c",_data[_i]) ); \
+ else \
+ DigiDump( _DataLevel, ( ".") ); \
+ } \
+ DigiDump( _DataLevel, ( "\n") ); \
+ _data += _i; \
+ } \
+ else \
+ { \
+ for( _i = 0; _i < (_len - _k); _i++ ) \
+ { \
+ DigiDump( _DataLevel, ( "%02x ",(_data[_i] & 0xFF)) ); \
+ } \
+ \
+ for( _i = 0; _i < (16 - (_len - _k)); _i++ ) \
+ DigiDump( _DataLevel, ( " ") ); \
+ \
+ DigiDump( _DataLevel, ( " ") ); \
+ \
+ for( _i = 0; _i < (_len - _k); _i++ ) \
+ { \
+ if(_data[_i] >= 0x20 && _data[_i] <= 0x7E) \
+ DigiDump( _DataLevel, ( "%c",_data[_i]) ); \
+ else \
+ DigiDump( _DataLevel, ( ".") ); \
+ } \
+ DigiDump( _DataLevel, ( "\n") ); \
+ break; \
+ } \
+ } \
+ } while ( 0 );
+
+#else
+#define DigiDump(LEVEL,STRING) do {NOTHING;} while (0)
+#define DigiDumpData(LEVEL,DATA,LEN) do {NOTHING;} while (0)
+#endif
+
+/* main macro to be used for logging */
+#define D_LOG(level, args) DigiDump( level, args )
+
+/* log levels */
+#define D_ALWAYS DIGIFLOW
+#define D_ENTRY DIGIFLOW
+#define D_EXIT DIGIFLOW
+#define D_RARE DIGIRARE
+#define D_NEVER DIGINEVER
+
+
+#endif /* _DISP_ */
+
+
diff --git a/private/ntos/ndis/digi/pcimac/event.h b/private/ntos/ndis/digi/pcimac/event.h
new file mode 100644
index 000000000..5f4b55387
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/event.h
@@ -0,0 +1,31 @@
+/*
+ * EVENT.H - IDP Device Driver public header for PCIMAC/ISA
+ */
+
+#ifndef _EVENT_
+#define _EVENT_
+
+typedef struct
+{
+ ULONG Used;
+ struct _CM *cm;
+ ULONG Type;
+ ULONG State;
+ VOID (*Callback)();
+ IRP *Irp;
+} EVENTOBJECT;
+
+#define MAX_EVENTS 10
+
+
+ULONG EventInit (VOID);
+VOID EventTerm (VOID);
+UCHAR EventSet (CM *cm, CMD_EVENT *Event, IRP *Irp);
+VOID EventComplete (IRP *Irp);
+VOID EventCancel (DEVICE_OBJECT *DeviceObject, IRP *Irp);
+VOID StateEventCheck (VOID *cm_1);
+
+#define EVENT_E_SUCC 0
+
+
+#endif /* _EVENT_ */
diff --git a/private/ntos/ndis/digi/pcimac/frame.h b/private/ntos/ndis/digi/pcimac/frame.h
new file mode 100644
index 000000000..44c5cd04b
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/frame.h
@@ -0,0 +1,196 @@
+//
+// to build a version that does not support compression, commen out
+// this define.
+//
+#define COMPRESSION 1
+
+// when we pick up a frame, the coherency layer tells us
+// about the frame...
+// !!!!! NOTE: This is NOT an enumeration !!!!!!
+// Look carefully at the code before you change these values.
+#define FRAME_NOT_COMPRESSED 0
+#define FRAME_IS_FLUSH_FRAME 1
+#define FRAME_NEEDS_DECOMPRESSION 2
+#define FRAME_NEEDS_DECOMPRESSION_FLUSHING 3
+
+//
+// Set LSB if SW compression is ON
+//
+#define COMPRESSION_V1 1
+
+typedef UCHAR FRAME_TYPE;
+typedef UCHAR FRAME_TICKET;
+
+//
+// ISDN pads to 60, so we need 60-14 worth of data
+// before it is worth it to compress it! probably even more than that!
+//
+#define MINIMUM_COMPRESSED_PACKET_SIZE (60-14)
+
+#define COMPRESSED_HAS_REFERENCES 1
+#define COMPRESSED_NO_REFERENCES 2
+#define UNCOMPRESSED 3
+#define COMPRESSED 4 // generic compressed
+
+// BUG BUG should probably read this value from coherency code.
+// we give one byte to coherency
+#define COHERENCY_LENGTH 1
+
+typedef ULONG FRAME_ID;
+
+// !!!! NOTE !!!!
+// TransmittedUncompressed are the number of bytes that the compressor
+// saw BEFORE attempting to compress the data (top end)
+// TransmitCompressed is the bottom end of the compressor which
+// is equal to the amount of bytes the compressor spat out (after compression)
+// This only counts bytes that went THROUGH the compression mechanism
+// Small frames and multi-cast frames (typically) do not get compressed.
+typedef struct COMPRESSION_STATS COMPRESSION_STATS, *PCOMPRESSION_STATS;
+struct COMPRESSION_STATS {
+ ULONG BytesTransmittedUncompressed; // Compression info only
+ ULONG BytesReceivedUncompressed; // Compression info only
+ ULONG BytesTransmittedCompressed; // Compression info only
+ ULONG BytesReceivedCompressed; // Compression info only
+};
+
+typedef struct ASYNC_CONNECTION ASYNC_CONNECTION, *PASYNC_CONNECTION;
+typedef struct ASYNC_FRAME ASYNC_FRAME, *PASYNC_FRAME;
+
+typedef
+VOID
+(*PCOHERENT_DONE_FUNC) (
+ IN PASYNC_CONNECTION pAsyncConnection,
+ IN PASYNC_FRAME pAsyncFrame);
+
+
+struct ASYNC_CONNECTION {
+ // For me..
+ PVOID pAsyncInfo; // Back ptr.
+
+ // For compression
+ ULONG CompressionLength; // Length of Compression struct
+ PVOID CompressionContext; // Ptr to the Compression struct
+
+ COMPRESSION_STATS CompressionStats;
+
+ // For coherency
+ ULONG CoherencyLength; // Length of coherency struct
+ PVOID CoherencyContext; // Ptr to coherency struct
+
+ NDIS_SPIN_LOCK CompMutex; // Non-paged pool mutex
+
+ // These two values hold the size requested by the compression
+ // and coherent modules for their internal structures.
+ ULONG CompressStructSize;
+ ULONG CoherentStructSize;
+
+
+};
+
+struct ASYNC_FRAME {
+//---------------------------------------------------------------------------
+ // !!!!!!!! NOTE !!!!!!!!
+ // The FrameListEntry field must be first to
+ // dequeue things up properly so don't put anything
+ // in front of it or suffer severe crashes.
+ LIST_ENTRY FrameListEntry; // Used to queue up frames from
+ // the soon to be famous frame pool
+ // this frame's ID
+ FRAME_ID FrameID;
+
+ // For Dougie
+ // Should Decompressed Frame can be non-paged??
+ // i.e. Should I queue a worker thred to decompress??
+ UINT DecompressedFrameLength;// Length of decompressed frame
+ PUCHAR DecompressedFrame; // Ptr to the decompressed 'frame'
+ // valid only after decompression
+
+ // NOTE: If the frame is not compressed, the compressed fields
+ // are still valid when passed to Dave.
+ UINT CompressedFrameLength; // Length of compressed frame
+ PUCHAR CompressedFrame; // Ptr to the compressed 'frame'
+ // valid only after compression
+ // or just before decompression
+
+ PNDIS_PACKET CompressionPacket; // Valid just before compression
+ // this is the packet passed down.
+ // Use NdisQueryPacket.
+
+ PASYNC_CONNECTION Connection; // back ptr to connection struct
+
+ // For Coherency
+ PUCHAR CoherencyFrame; // Ptr to coherency frame
+ PCOHERENT_DONE_FUNC CoherentDone; // function ptr to call when done
+ // sending frame
+
+};
+
+// APIs to Compressor
+VOID
+CoherentDeliverFrame(
+ PASYNC_CONNECTION pConnection,
+ PASYNC_FRAME pFrame,
+ FRAME_TYPE FrameType);
+
+VOID
+CoherentGetPipeline(
+ PASYNC_CONNECTION pConnection,
+ PULONG plUnsent);
+
+
+// APIs to Transport/Network layer
+VOID
+CoherentSendFrame(
+ PASYNC_CONNECTION pConnection,
+ PASYNC_FRAME pFrame,
+ FRAME_TYPE FrameType);
+
+
+ULONG
+CoherentSizeOfStruct( );
+
+VOID
+CoherentInitStruct(
+ PVOID pCoherentStruct);
+
+// upcalls API's from Transport/Network layer
+VOID
+CoherentReceiveFrame(
+ PASYNC_CONNECTION pConnection,
+ PASYNC_FRAME pFrame);
+
+VOID
+CoherentDeliverFrameDone(
+ PASYNC_CONNECTION pConnection,
+ PASYNC_FRAME pFrame);
+
+
+
+ULONG
+CompressSizeOfStruct(
+ IN ULONG SendMode, // Compression
+ IN ULONG RecvMode, // Decompression
+ IN ULONG lfsz, // Largest frame size
+ OUT PULONG lcfsz); // Size of compression into buffer
+
+VOID
+CompressInitStruct(
+ ULONG SendMode, // Compression
+ ULONG RecvMode, // Decompression
+ PUCHAR memptr,
+ PNDIS_SPIN_LOCK pMutex); // Must be in non-paged pool
+
+VOID
+CompressFlush(
+ PASYNC_CONNECTION pAsyncConnection);
+
+VOID
+CompressFrame(
+ PASYNC_FRAME pAsyncFrame);
+
+VOID
+DecompressFrame(
+ PASYNC_CONNECTION pAsyncConnection,
+ PASYNC_FRAME pAsyncFrame,
+ BOOLEAN FlushBuffer);
+
diff --git a/private/ntos/ndis/digi/pcimac/idd.h b/private/ntos/ndis/digi/pcimac/idd.h
new file mode 100644
index 000000000..592ee8270
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/idd.h
@@ -0,0 +1,440 @@
+/*
+ * IDD.H - IDP Device Driver header
+ */
+
+#ifndef _IDD_
+#define _IDD_
+
+#include <idd_pub.h>
+
+
+/* idd error codes */
+#define IDD_E_SUCC 0
+#define IDD_E_NOMEM 1
+#define IDD_E_MEMERR 2
+#define IDD_E_NOSUCH 3
+#define IDD_E_NOROOM 4
+#define IDD_E_BADPORT 5
+#define IDD_E_IORERR 6
+#define IDD_E_IOWERR 7
+#define IDD_E_FMAPERR 8
+#define IDD_E_RUNERR 9
+#define IDD_E_PORTMAPERR 10
+#define IDD_E_PORTBINDERR 11
+#define IDD_E_PARTQINIT 12
+#define IDD_E_FAILINSTALL 13
+#define IDD_E_BUSY 14
+#define IDD_E_AREA 15
+
+//
+// Idd receive data framing types
+//
+#define DKF_UUS_SIG 0x50
+#define PPP_SIG_0 0xFF
+#define PPP_SIG_1 0x03
+
+/* IDD ports, rx/tx overlap! */
+#define IDD_PORT_B1_RX 0 /* recieve b1 data */
+#define IDD_PORT_B1_TX 0 /* trasmit b1 data */
+#define IDD_PORT_B2_RX 1 /* recieve b1 data */
+#define IDD_PORT_B2_TX 1 /* trasmit b1 data */
+#define IDD_PORT_U_RX 2 /* receive uart data */
+#define IDD_PORT_U_TX 2 /* trasmit uart data */
+#define IDD_PORT_CMD_RX 3 /* receive control messages */
+#define IDD_PORT_CMD_TX 3 /* trasmit control commands */
+#define IDD_PORT_CM0_RX 4 /* receive connection mgr events */
+#define IDD_PORT_CM0_TX 4 /* transmit connection mgr events */
+#define IDD_PORT_CM1_RX 5 /* ... on secondary tei (opt) */
+#define IDD_PORT_CM1_TX 5 /* ... on secondary tei (opt) */
+
+
+//
+// local idd def's
+//
+/* some max values */
+#define IDD_FNAME_LEN 128 /* size of a filename (path) */
+#define IDD_DEF_SIZE 1000 /* size of definition database */
+#define IDD_MAX_SEND (6*32) /* max # of pending send allowed */
+#define IDD_MAX_RECEIVE (6*32) /* max # of pending receives on adapter*/
+#define IDD_MAX_HAND (6*6) /* max # of receive handles allowed */
+#define IDD_RX_PORTS 6 /* # of recieve ports defined */
+#define IDD_TX_PORTS 6 /* # of transmit ports defined */
+#define IDD_TX_PARTQ 4 /* # of (buffer) partition queues for tx */
+#define IDD_PAGE_NONE (UCHAR)0xFF /* no page arg for idd__cpage */
+#define IDP_MAX_RX_BUFFER 350 /* stupid double buffer buffer */
+
+/* memory banks */
+#define IDD_BANK_BUF 0
+#define IDD_BANK_DATA 1
+#define IDD_BANK_CODE 2
+
+/* representation of physical hardware */
+typedef struct
+{
+ ULONG base_io; /* base i/o address */
+ ULONG base_mem; /* base memory address */
+ CHAR idp_bin[IDD_FNAME_LEN]; /* binary image filename */
+ NDIS_HANDLE fbin; /* idp bin file handle */
+ UINT fbin_len; /* length in bytes of idp bin file */
+} IDD_PHW;
+
+/* virualization of hardware, in os (ndis) terms */
+typedef struct
+{
+ ULONG vbase_io; // virtual i/o base
+ CHAR *vmem; /* virtual address for memory */
+} IDD_VHW;
+
+/* descriptor for a message to be sent on a port */
+typedef struct
+{
+ IDD_MSG msg; /* copy of user's message */
+ VOID (*handler)(); /* user's completion handler */
+ VOID *handler_arg; /* handler's argument */
+} IDD_SMSG;
+
+/* a queue for messages waiting to be sent */
+typedef struct
+{
+ IDD_SMSG *tbl; /* send message table address */
+ INT num; /* # of entries in queue */
+ INT max; /* max # of entries allowed/alloc */
+ INT put; /* put/insert index */
+ INT get; /* get/remove index */
+ NDIS_SPIN_LOCK lock; /* spin lock guarding access */
+} IDD_SENDQ;
+
+/* a descriptor for user's handler for a receiver port */
+typedef struct
+{
+ VOID (*handler)(); /* user's handler */
+ VOID *handler_arg; /* handler's argument */
+} IDD_RHAND;
+
+/* a table of user's handlers on a reciever port */
+typedef struct
+{
+ IDD_RHAND *tbl; /* table of receiver handlers */
+ ULONG RxFrameType; /* current receive framining mode */
+ INT num; /* # of entries in table */
+ INT max; /* max # of entries allowed/alloc */
+ NDIS_SPIN_LOCK lock; /* spin lock guarding access */
+} IDD_RECIT;
+
+/* idp low level (shared memory) command interface structure */
+#pragma pack(2)
+typedef struct
+{
+ UCHAR opcode; /* command opcode */
+#define IDP_L_MAP 0 /* - map a port name to id */
+#define IDP_L_READ 1 /* - read from a port */
+#define IDP_L_WRITE 2 /* - write to a port */
+#define IDP_L_BIND 3 /* - bind a port to a status bit */
+#define IDP_L_UNBIND 4 /* - unbind a port from a status bit */
+#define IDP_L_POLL 5 /* - poll a prot (check for read) */
+#define IDP_L_GET_WBUF 6 /* - get a write buffer */
+#define IDP_L_PUT_RBUF 7 /* - put (free) a read buffer */
+
+ UCHAR status; /* command status */
+#define IDP_S_PEND 0xFF /* - command pending */
+#define IDP_S_EXEC 0xFE /* - command is executing */
+#define IDP_S_OK 0x00 /* - command complted succ */
+#define IDP_S_NOPORT 0x01 /* - no such port error */
+#define IDP_S_NOMSG 0x02 /* - no messages error */
+#define IDP_S_NOBUF 0x03 /* - no local buffer error */
+#define IDP_S_NOBIT 0x04 /* - no status bit left error */
+#define IDP_S_BOUND 0x05 /* - port already bound error */
+#define IDP_S_NOTBOUND 0x06 /* - port not bound error */
+#define IDP_S_TIMEOUT 0x07 /* - command timed out error */
+#define IDP_S_DONE(s) (!(s & 0x80)) /* -command execution done (<0x80) */
+
+ USHORT port_id; /* related port identifier */
+ CHAR port_name[16]; /* related port name */
+ USHORT port_bitpatt; /* related port bit pattern */
+
+ UCHAR res[8]; /* 8 bytes of reserved area */
+
+ USHORT msg_opcode; /* message opcode (type) */
+ USHORT msg_buflen; /* related buffer length */
+ ULONG msg_bufptr; /* related buffer pointer (0=none) */
+ ULONG msg_bufid; /* related buffer id */
+ ULONG msg_param; /* parameter area */
+} IDP_CMD;
+#pragma pack()
+
+
+/* adp low level (shared memory) command interface structure */
+#pragma pack(2)
+typedef struct
+{
+ UCHAR opcode; /* command opcode */
+#define ADP_L_MAP 0 /* - map a port name to id */
+#define ADP_L_READ 1 /* - read from a port */
+#define ADP_L_WRITE 2 /* - write to a port */
+#define ADP_L_BIND 3 /* - bind a port to a status bit */
+#define ADP_L_UNBIND 4 /* - unbind a port from a status bit */
+#define ADP_L_POLL 5 /* - poll a prot (check for read) */
+#define ADP_L_GET_WBUF 6 /* - get a write buffer */
+#define ADP_L_PUT_RBUF 7 /* - put (free) a read buffer */
+
+ UCHAR status; /* command status */
+#define ADP_S_PEND 0xFF /* - command pending */
+#define ADP_S_EXEC 0xFE /* - command is executing */
+#define ADP_S_OK 0x00 /* - command complted succ */
+#define ADP_S_NOPORT 0x01 /* - no such port error */
+#define ADP_S_NOMSG 0x02 /* - no messages error */
+#define ADP_S_NOBUF 0x03 /* - no local buffer error */
+#define ADP_S_NOBIT 0x04 /* - no status bit left error */
+#define ADP_S_BOUND 0x05 /* - port already bound error */
+#define ADP_S_NOTBOUND 0x06 /* - port not bound error */
+#define ADP_S_TIMEOUT 0x07 /* - command timed out error */
+#define ADP_S_DONE(s) (!(s & 0x80)) /* -command execution done (<0x80) */
+
+ USHORT port_id; /* related port identifier */
+ CHAR port_name[8]; /* related port name */
+ USHORT port_bitpatt; /* related port bit pattern */
+
+ USHORT msg_opcode; /* message opcode (type) */
+ USHORT msg_buflen; /* related buffer length */
+ CHAR *msg_bufptr; /* related buffer pointer (0=none) */
+ ULONG msg_bufid; /* related buffer id */
+ ULONG msg_param; /* parameter area */
+} ADP_CMD;
+#pragma pack()
+
+typedef struct tagIDD_LINESTATE
+{
+ ULONG LineActive; /* is this idd's line active */
+ ULONG L1TxState; /* Layer 1 Tx state */
+ ULONG L1RxState; /* Layer 1 Rx state */
+ ULONG L2State; /* Layer 2 State */
+ ULONG L3State; /* Layer 3 State */
+ ULONG L3ServiceState; /* Layer 3 Service State */
+}IDD_LINESTATE;
+
+typedef struct tagIDD_CALLINFO
+{
+ ULONG ChannelsUsed; /* # of bchans used on this idd */
+ ULONG NumLTerms; /* # of lterms 1/2 */
+ VOID* cm[2]; /* cm that is using an lterm */
+}IDD_CALLINFO;
+
+#ifdef DBG
+typedef struct
+{
+ INT Count;
+ ULONG Put;
+ ULONG Get;
+ ULONG TxState;
+ ULONG FragsSinceBegin;
+ ULONG Buffer[32];
+}BUFFER_MANAGER;
+#endif
+
+/* IDD object */
+typedef struct _IDD
+{
+ USHORT state; /* IDD object state */
+#define IDD_S_INIT 0 /* - initial state */
+#define IDD_S_CHECK 1 /* - in check hardware phase */
+#define IDD_S_STARTUP 2 /* - in startup */
+#define IDD_S_RUN 3 /* - now running */
+#define IDD_S_SHUTDOWN 4 /* - in shutdown */
+
+#ifdef DBG
+ BUFFER_MANAGER BufferStuff[4];
+#endif
+
+ ULONG WaitCounter;
+ ULONG MaxWaitCounter;
+
+ USHORT AbortReason;
+
+ NDIS_SPIN_LOCK lock; /* spin lock guarding access to obj */
+
+ NDIS_HANDLE adapter_handle; /* related adapter handle */
+
+ IDD_PHW phw; /* physical hardware */
+ IDD_VHW vhw; /* virtualization of hardware */
+
+ IDD_SENDQ sendq[IDD_TX_PORTS]; /* send queues for tx ports */
+ IDD_SMSG smsg_pool[IDD_MAX_SEND]; /* pool of smsgs for sendqs */
+
+ IDD_RECIT recit[IDD_RX_PORTS]; /* receive table for rx ports */
+ IDD_RHAND rhand_pool[IDD_MAX_HAND]; /* pool or rhand for recit table */
+
+ USHORT rx_port[IDD_RX_PORTS]; /* port id's in idp terms for rx */
+ USHORT tx_port[IDD_TX_PORTS]; /* ... for tx */
+ ULONG rx_buf; /* id for last received (old) buffer from idp */
+ ULONG tx_buf[IDD_TX_PARTQ]; /* (new) tx buffer as idp bufids */
+ USHORT tx_partq[IDD_TX_PORTS]; /* related memory parition queues */
+
+ IDP_CMD volatile *IdpCmd; /* pointer to idp command struct */
+ USHORT volatile *IdpStat; /* pointer to status register */
+ UCHAR volatile *IdpEnv; /* pointer to status register */
+
+ ADP_CMD AdpCmd; /* pointer to adp command struct */
+ USHORT AdpStat; /* pointer to status register */
+
+ SEMA proc_sema; /* processing sema */
+
+ CHAR name[64]; /* name (device name?) */
+ USHORT btype; /* board type idd related to */
+ USHORT bnumber; /* board number of this idd */
+ USHORT bline; /* line index inside board */
+
+ IDD_CALLINFO CallInfo; /* information about active calls */
+
+ IDD_LINESTATE LineState; /* structure of idd state info */
+
+ VOID *res_mem; /* resource mgr handle for memory */
+ VOID *res_io; /* resource mgr handle for i/o */
+
+ ULONG (*CheckIO)(); /* Check Base I/O */
+ ULONG (*CheckMem)(); /* Check Base Mem */
+ VOID (*SetBank)(); /* set memory bank */
+ VOID (*SetPage)(); /* set memory page - or none */
+ VOID (*SetBasemem)(); /* set base memory address */
+ INT (*LoadCode)(); /* load the adapter */
+ ULONG (*PollTx)(); /* poll the adapter for xmits*/
+ ULONG (*PollRx)(); /* poll the adapter for recvs */
+ UCHAR (*Execute)(); /* Execute a command */
+ VOID (*OutToPort)(); /* Write Char to port*/
+ UCHAR (*InFromPort)(); /* Read Char from port*/
+ USHORT (*ApiGetPort)(); /* Get Port ID from adapter*/
+ INT (*ApiBindPort)(); /* Bind a Port to a status bit*/
+ ULONG (*ApiAllocBuffer)(); /* Get a buffer from the adapter*/
+ VOID (*ResetAdapter)(); /* Reset the adapter*/
+ USHORT (*NVRamRead)(); /* Read Adapters NVRam*/
+ VOID (*ChangePage)(); /* Change Memory Page on Adapter*/
+
+ IDD_AREA Area; /* idd area storage */
+
+ VOID *trc; /* related trace object */
+
+ UCHAR DefinitionTable[IDD_DEF_SIZE]; /* init definition database */
+ USHORT DefinitionTableLength; /* length of definition database */
+
+ UCHAR RxBuffer[IDP_MAX_RX_BUFFER]; /* receive storage */
+} IDD;
+
+
+/* IDD object operation prototypes */
+INT idd_create(VOID** ret_idd, USHORT btype);
+INT idd_destroy(VOID* idd_1);
+INT idd_set_base_io(VOID* idd_1, USHORT base_io);
+INT idd_set_base_mem(VOID* idd_1, ULONG base_mem, CHAR* vmem);
+INT idd_set_idp_bin(VOID* idd_1, CHAR* idp_bin);
+INT idd_add_def(IDD *idd, CHAR* name, CHAR* val);
+INT idd_get_nvram(VOID *idd_1, USHORT addr, USHORT* val);
+INT idd_check(VOID* idd_1);
+INT idd_startup(VOID* idd_1);
+INT idd_shutdown(VOID* idd_1);
+ULONG idd_process(IDD* idd, UCHAR TxOnly);
+INT idd_send_msg(VOID* idd_1, IDD_MSG *msg, USHORT port,
+ VOID (*handler)(), VOID* handler_arg);
+INT idd_attach(VOID* idd_1, USHORT port,
+ VOID (*handler)(), VOID* handler_arg);
+INT idd_detach(VOID* idd_1, USHORT port,
+ VOID (*handler)(), VOID* handler_arg);
+CHAR* idd_get_name(VOID* idd_1);
+ULONG idd_get_baseio(VOID* idd_1);
+ULONG idd_get_basemem(VOID* idd_1);
+USHORT idd_get_btype(VOID* idd_1);
+USHORT idd_get_bline(VOID* idd_1);
+VOID* idd_get_trc(VOID *idd_1);
+VOID idd_set_trc(VOID *idd_1, VOID *Trace);
+INT idd_install(NDIS_HANDLE adapter_handle);
+INT idd_remove(NDIS_HANDLE adapter_handle);
+VOID idd_start_timers(VOID* Adapter_1);
+INT idd_reset_area(VOID* idd_1);
+INT idd_get_area(VOID* idd_1, ULONG area_id, VOID(*handler)(), VOID*handler_arg);
+INT idd_get_area_stat(VOID* idd_1, IDD_AREA *IddStat);
+VOID IddSetRxFraming(VOID* idd_1, USHORT port, ULONG FrameType);
+
+VOID IddPollFunction(VOID* a1, VOID* Adapter_1, VOID* a3, VOID* a4);
+VOID LineStateTimerTick(VOID* a1, VOID* Adapter_1, VOID* a3, VOID *a4);
+VOID idd__cmd_handler(IDD *idd, USHORT chan, ULONG Reserved, IDD_MSG* msg);
+VOID DetectFramingHandler(IDD *idd, USHORT chan, ULONG IddRxFrameType, IDD_XMSG *msg);
+
+ULONG EnumIddInSystem(VOID);
+ULONG EnumIddPerAdapter(VOID *Adapter_1);
+IDD* GetIddByIndex(ULONG);
+INT IoEnumIdd(VOID *cmd);
+ULONG idd_init(VOID);
+
+INT IdpLoadCode(IDD* idd);
+INT AdpLoadCode(IDD* idd);
+INT IdpBindPort(IDD* idd, USHORT port, USHORT bitpatt);
+INT AdpBindPort(IDD* idd, USHORT port, USHORT bitpatt);
+INT IdpResetBoard(IDD* idd);
+INT AdpResetBoard(IDD* idd);
+ULONG IdpAllocBuf(IDD*, INT);
+ULONG AdpAllocBuf(IDD*, INT);
+USHORT IdpGetPort(IDD *idd, CHAR name[8]);
+USHORT AdpGetPort(IDD *idd, CHAR name[8]);
+ULONG IdpCheckIO(IDD*);
+ULONG AdpCheckIO(IDD*);
+ULONG IdpCheckMem(IDD*);
+ULONG AdpCheckMem(IDD*);
+
+/* board specific routines */
+VOID IdpPcSetBank(IDD* idd, UCHAR bank, UCHAR run);
+VOID IdpPc4SetBank(IDD* idd, UCHAR bank, UCHAR run);
+VOID IdpMcSetBank(IDD* idd, UCHAR bank, UCHAR run);
+VOID AdpSetBank(IDD* idd, UCHAR bank, UCHAR run);
+VOID IdpPcSetPage(IDD* idd, UCHAR page);
+VOID IdpPc4SetPage(IDD* idd, UCHAR page);
+VOID IdpMcSetPage(IDD* idd, UCHAR page);
+VOID AdpSetPage(IDD* idd, UCHAR page);
+VOID IdpPcSetBasemem(IDD* idd, ULONG basemem);
+VOID IdpPc4SetBasemem(IDD* idd, ULONG basemem);
+VOID IdpMcSetBasemem(IDD* idd, ULONG basemem);
+VOID AdpSetBasemem(IDD* idd, ULONG basemem);
+
+UCHAR IdpInp(IDD* idd, USHORT port);
+UCHAR AdpInp(IDD* idd, USHORT port);
+VOID IdpOutp(IDD* idd, USHORT port, UCHAR val);
+VOID AdpOutp(IDD* idd, USHORT port, UCHAR val);
+ULONG IdpPollTx(IDD* idd);
+ULONG AdpPollTx(IDD* idd);
+ULONG IdpPollRx(IDD* idd);
+ULONG AdpPollRx(IDD* idd);
+UCHAR IdpExec(IDD *idd, UCHAR opcode);
+UCHAR AdpExec(IDD *idd, UCHAR opcode);
+VOID IdpCPage(IDD *idd, UCHAR page);
+VOID AdpCPage(IDD *idd, UCHAR page);
+USHORT IdpNVRead(IDD* idd, USHORT addr);
+USHORT AdpNVRead(IDD* idd, USHORT addr);
+VOID IdpNVWrite(IDD* idd, USHORT addr, USHORT val);
+VOID AdpNVWrite(IDD* idd, USHORT addr, USHORT val);
+VOID IdpNVErase(IDD* idd);
+VOID AdpNVErase(IDD* idd);
+VOID IdpMemset(UCHAR* dst, USHORT val, int size);
+VOID AdpMemset(UCHAR* dst, USHORT val, int size);
+VOID IdpMemcpy(UCHAR* dst, UCHAR* src, int size);
+VOID AdpMemcpy(UCHAR* dst, UCHAR* src, int size);
+USHORT IdpCopyin(IDD* idd, UCHAR* dst, UCHAR* src, USHORT src_len);
+USHORT AdpCopyin(IDD* idd, UCHAR* src, USHORT src_len);
+
+VOID AdpWriteControlBit (IDD *idd, UCHAR Bit, UCHAR Value);
+VOID AdpPutBuffer (IDD *idd, ULONG Destination, PUCHAR Source, USHORT Length);
+VOID AdpGetBuffer (IDD *idd, PUCHAR Destination, ULONG Source, USHORT Length);
+VOID AdpWriteCommandStatus(IDD *idd, UCHAR Value);
+UCHAR AdpReadCommandStatus(IDD *idd);
+VOID AdpSetAddress(IDD *idd, ULONG Address);
+VOID AdpPutUByte(IDD *idd, ULONG Address, UCHAR Value);
+VOID AdpPutUShort(IDD *idd, ULONG Address, USHORT Value);
+VOID AdpPutULong(IDD *idd, ULONG Address, ULONG Value);
+UCHAR AdpGetUByte(IDD *idd, ULONG Address);
+USHORT AdpGetUShort(IDD *idd, ULONG Address);
+ULONG AdpGetULong(IDD *idd, ULONG Address);
+UCHAR AdpReadReceiveStatus(IDD *idd);
+UCHAR IdpGetUByteIO(IDD* idd, USHORT port);
+VOID IdpGetBuffer(IDD* idd, ULONG Bank, ULONG Page, ULONG Address, USHORT Length, PUCHAR Buffer);
+VOID IdpPutUByteIO(IDD* idd, USHORT Port, UCHAR Value);
+VOID IdpPutBuffer(IDD* idd, ULONG Bank, ULONG Page, ULONG Address, USHORT Length, PUCHAR Buffer);
+VOID IddGetDataFromAdapter(VOID *idd_1, PUCHAR Destination, PUCHAR Source, USHORT Length);
+VOID LineStateHandler(VOID* idd_1, ULONG AreaId, CHAR* AreaBuffer, ULONG BufferLen);
+
+#endif /* _IDD_ */
diff --git a/private/ntos/ndis/digi/pcimac/idd_init.c b/private/ntos/ndis/digi/pcimac/idd_init.c
new file mode 100644
index 000000000..54cb548aa
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/idd_init.c
@@ -0,0 +1,894 @@
+/*
+ * IDD_INIT.C - IDD initialization
+ */
+
+#include <ndis.h>
+#include <ndiswan.h>
+#include <ndistapi.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+#include <res.h>
+#include <trc.h>
+#include <io.h>
+
+#include <ansihelp.h>
+
+
+typedef struct
+{
+ NDIS_SPIN_LOCK lock;
+ ULONG NumberOfIddsInSystem;
+ ULONG LastIddPolled;
+ ADAPTER *CurrentAdapter;
+ ADAPTER *LastAdapter;
+ IDD* Idd[MAX_IDD_IN_SYSTEM];
+}IDD_TABLE;
+
+IDD_TABLE GlobalIddTbl;
+
+BOOLEAN IsThisAdapterNext(ADAPTER *Adapter);
+
+/* driver global vars */
+extern DRIVER_BLOCK Pcimac;
+
+ULONG EnumIddInSystem()
+{
+ ULONG NumberOfIddsInSystem;
+
+ NdisAcquireSpinLock(&GlobalIddTbl.lock);
+
+ NumberOfIddsInSystem = GlobalIddTbl.NumberOfIddsInSystem;
+
+ NdisReleaseSpinLock(&GlobalIddTbl.lock);
+
+ return(NumberOfIddsInSystem);
+}
+
+IDD* GetIddByIndex( ULONG Index )
+{
+ IDD *idd;
+
+ NdisAcquireSpinLock(&GlobalIddTbl.lock);
+
+ idd = GlobalIddTbl.Idd[Index];
+
+ NdisReleaseSpinLock(&GlobalIddTbl.lock);
+
+ return(idd);
+}
+
+ULONG
+EnumIddPerAdapter(
+ VOID *Adapter_1
+ )
+{
+ ADAPTER *Adapter = (ADAPTER*)Adapter_1;
+
+ return(Adapter->NumberOfIddOnAdapter);
+}
+
+
+INT
+IoEnumIdd(VOID *cmd_1)
+{
+ ULONG n;
+ IO_CMD *cmd = (IO_CMD*)cmd_1;
+
+ NdisAcquireSpinLock(&GlobalIddTbl.lock);
+
+ cmd->val.enum_idd.num = (USHORT)GlobalIddTbl.NumberOfIddsInSystem;
+
+ for (n = 0; n < GlobalIddTbl.NumberOfIddsInSystem; n++)
+ {
+ IDD *idd;
+
+ idd = cmd->val.enum_idd.tbl[n] = GlobalIddTbl.Idd[n];
+
+ NdisMoveMemory(&cmd->val.enum_idd.name[n],
+ idd->name,
+ sizeof(cmd->val.enum_idd.name[n]));
+ }
+
+ NdisReleaseSpinLock(&GlobalIddTbl.lock);
+
+ return(0);
+}
+
+#pragma NDIS_INIT_FUNCTION(idd_init)
+
+ULONG
+idd_init(VOID)
+{
+ //
+ // clear out idd table
+ //
+ NdisZeroMemory(&GlobalIddTbl, sizeof(IDD_TABLE));
+
+ NdisAllocateSpinLock(&GlobalIddTbl.lock);
+
+ return(IDD_E_SUCC);
+}
+
+#pragma NDIS_INIT_FUNCTION(idd_create)
+
+/* allocate & initialize an idd object */
+INT
+idd_create(VOID **ret_idd, USHORT btype)
+{
+ IDD *idd;
+ INT n;
+ NDIS_PHYSICAL_ADDRESS pa = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
+
+ D_LOG(D_ENTRY, ("idd_create: BoardType: %d\n", btype));
+
+ /* allocate memory object */
+ NdisAllocateMemory((PVOID*)&idd, sizeof(IDD), 0, pa);
+ if ( !idd )
+ {
+ D_LOG(DIGIINIT, ("idd_create: memory allocate failed!\n"));
+ return(IDD_E_NOMEM);
+ }
+
+ NdisAcquireSpinLock(&GlobalIddTbl.lock);
+
+ //
+ // store idd in system idd table
+ //
+ for (n = 0; n < MAX_IDD_IN_SYSTEM; n++)
+ if (!GlobalIddTbl.Idd[n])
+ break;
+
+ if (n >= MAX_IDD_IN_SYSTEM)
+ {
+ //
+ // We are unable to find an empty slot for the IDD object.
+ //
+ /* free memory for idd */
+ NdisFreeMemory(idd, sizeof(*idd), 0);
+
+ NdisReleaseSpinLock(&GlobalIddTbl.lock);
+
+ return(IDD_E_NOROOM);
+ }
+
+ GlobalIddTbl.Idd[n] = idd;
+ GlobalIddTbl.NumberOfIddsInSystem++;
+
+ NdisReleaseSpinLock(&GlobalIddTbl.lock);
+
+ D_LOG(DIGIINIT, ("idd_create: idd: 0x%lx\n", idd));
+ NdisZeroMemory(idd, sizeof(IDD));
+
+ /* setup init state, adapter handle */
+ idd->state = IDD_S_INIT;
+ idd->trc = NULL;
+
+ /* allocate root spinlock */
+ NdisAllocateSpinLock(&idd->lock);
+
+ /* initialize send queues */
+ for( n = 0 ; n < IDD_TX_PORTS ; n++ )
+ {
+ INT max;
+
+ /* initialize queue */
+ idd->sendq[n].max = max = IDD_MAX_SEND / IDD_TX_PORTS;
+
+ idd->sendq[n].tbl = idd->smsg_pool + max * n;
+
+ /* allocate spin lock */
+ NdisAllocateSpinLock(&idd->sendq[n].lock);
+ }
+
+ /* initialize receiver tables */
+ for ( n = 0 ; n < IDD_RX_PORTS ; n++ )
+ {
+ INT max;
+
+ /* initialize table */
+ idd->recit[n].max = max = IDD_MAX_HAND / IDD_RX_PORTS;
+ idd->recit[n].tbl = idd->rhand_pool + max * n;
+
+ /* allocate spin lock */
+ NdisAllocateSpinLock(&idd->recit[n].lock);
+ }
+
+ /* initialize board specific functions */
+ switch ( btype )
+ {
+ case IDD_BT_PCIMAC :
+ idd->SetBank = (VOID*)IdpPcSetBank;
+ idd->SetPage = (VOID*)IdpPcSetPage;
+ idd->SetBasemem = (VOID*)IdpPcSetBasemem;
+ idd->CheckIO = (VOID*)IdpCheckIO;
+ idd->CheckMem = (VOID*)IdpCheckMem;
+ idd->LoadCode = (VOID*)IdpLoadCode;
+ idd->PollTx = (VOID*)IdpPollTx;
+ idd->PollRx = (VOID*)IdpPollRx;
+ idd->Execute = (VOID*)IdpExec;
+ idd->OutToPort = (VOID*)IdpOutp;
+ idd->InFromPort = (VOID*)IdpInp;
+ idd->ApiGetPort = (VOID*)IdpGetPort;
+ idd->ApiBindPort = (VOID*)IdpBindPort;
+ idd->ApiAllocBuffer = (VOID*)IdpAllocBuf;
+ idd->ResetAdapter = (VOID*)IdpResetBoard;
+ idd->NVRamRead = (VOID*)IdpNVRead;
+ idd->ChangePage = (VOID*)IdpCPage;
+ break;
+
+ case IDD_BT_PCIMAC4 :
+ idd->SetBank = (VOID*)IdpPc4SetBank;
+ idd->SetPage = (VOID*)IdpPc4SetPage;
+ idd->SetBasemem = (VOID*)IdpPc4SetBasemem;
+ idd->CheckIO = (VOID*)IdpCheckIO;
+ idd->CheckMem = (VOID*)IdpCheckMem;
+ idd->LoadCode = (VOID*)IdpLoadCode;
+ idd->PollTx = (VOID*)IdpPollTx;
+ idd->PollRx = (VOID*)IdpPollRx;
+ idd->Execute = (VOID*)IdpExec;
+ idd->OutToPort = (VOID*)IdpOutp;
+ idd->InFromPort = (VOID*)IdpInp;
+ idd->ApiGetPort = (VOID*)IdpGetPort;
+ idd->ApiBindPort = (VOID*)IdpBindPort;
+ idd->ApiAllocBuffer = (VOID*)IdpAllocBuf;
+ idd->ResetAdapter = (VOID*)IdpResetBoard;
+ idd->NVRamRead = (VOID*)IdpNVRead;
+ idd->ChangePage = (VOID*)IdpCPage;
+ break;
+
+ case IDD_BT_MCIMAC :
+ idd->SetBank = (VOID*)IdpMcSetBank;
+ idd->SetPage = (VOID*)IdpMcSetPage;
+ idd->SetBasemem = (VOID*)IdpMcSetBasemem;
+ idd->CheckIO = (VOID*)IdpCheckIO;
+ idd->CheckMem = (VOID*)IdpCheckMem;
+ idd->LoadCode = (VOID*)IdpLoadCode;
+ idd->PollTx = (VOID*)IdpPollTx;
+ idd->PollRx = (VOID*)IdpPollRx;
+ idd->Execute = (VOID*)IdpExec;
+ idd->OutToPort = (VOID*)IdpOutp;
+ idd->InFromPort = (VOID*)IdpInp;
+ idd->ApiGetPort = (VOID*)IdpGetPort;
+ idd->ApiBindPort = (VOID*)IdpBindPort;
+ idd->ApiAllocBuffer = (VOID*)IdpAllocBuf;
+ idd->ResetAdapter = (VOID*)IdpResetBoard;
+ idd->NVRamRead = (VOID*)IdpNVRead;
+ idd->ChangePage = (VOID*)IdpCPage;
+ break;
+
+ case IDD_BT_DATAFIREU :
+ case IDD_BT_DATAFIREST:
+ case IDD_BT_DATAFIRE4ST:
+ idd->SetBank = (VOID*)AdpSetBank;
+ idd->SetPage = (VOID*)AdpSetPage;
+ idd->SetBasemem = (VOID*)AdpSetBasemem;
+ idd->CheckIO = (VOID*)AdpCheckIO;
+ idd->CheckMem = (VOID*)AdpCheckMem;
+ idd->LoadCode = (VOID*)AdpLoadCode;
+ idd->PollTx = (VOID*)AdpPollTx;
+ idd->PollRx = (VOID*)AdpPollRx;
+ idd->Execute = (VOID*)AdpExec;
+ idd->OutToPort = (VOID*)AdpOutp;
+ idd->InFromPort = (VOID*)AdpInp;
+ idd->ApiGetPort = (VOID*)AdpGetPort;
+ idd->ApiBindPort = (VOID*)AdpBindPort;
+ idd->ApiAllocBuffer = (VOID*)AdpAllocBuf;
+ idd->ResetAdapter = (VOID*)AdpResetBoard;
+ idd->NVRamRead = (VOID*)AdpNVRead;
+ idd->ChangePage = (VOID*)AdpCPage;
+ break;
+ }
+
+
+ /* init sema */
+ sema_init(&idd->proc_sema);
+
+ //
+ // attach idd frame detection handlers
+ // these must be attached 1st for all data handlers
+ //
+ idd_attach(idd, IDD_PORT_B1_RX, (VOID*)DetectFramingHandler, idd);
+ idd_attach(idd, IDD_PORT_B2_RX, (VOID*)DetectFramingHandler, idd);
+
+ // attach a command handler to get area info from idp
+ idd_attach (idd, IDD_PORT_CMD_RX, (VOID*)idd__cmd_handler, idd);
+
+ /* return address & success */
+ *ret_idd = idd;
+ D_LOG(D_EXIT, ("idd_create: exit\n"));
+ return(IDD_E_SUCC);
+}
+
+/* free idd object */
+INT
+idd_destroy(VOID *idd_1)
+{
+ IDD *idd = (IDD*)idd_1;
+ INT n;
+
+ D_LOG(D_ENTRY, ("idd_destroy: entry, idd: 0x%lx\n", idd));
+
+ // detach command handler from this idd
+ idd_detach (idd, IDD_PORT_CMD_RX, (VOID*)idd__cmd_handler, idd);
+
+ /* perform a shutdown (maybe null) */
+ idd_shutdown(idd);
+
+ /* if file handle for binary file open, close it */
+ if ( idd->phw.fbin )
+ NdisCloseFile(idd->phw.fbin);
+
+ /* free spin locks for send queue */
+ for ( n = 0 ; n < IDD_TX_PORTS ; n++ )
+ NdisFreeSpinLock(&idd->sendq[n].lock);
+
+ /* free spin locks for reciever tables */
+ for ( n = 0 ; n < IDD_RX_PORTS ; n++ )
+ NdisFreeSpinLock(&idd->recit[n].lock);
+
+ /* free resource handles */
+ if ( idd->res_io != NULL)
+ res_destroy(idd->res_io);
+
+ if ( idd->res_mem != NULL)
+ res_destroy(idd->res_mem);
+
+ // free trc object
+ if (idd->trc != NULL)
+ {
+ trc_deregister_idd(idd);
+ trc_destroy (idd->trc);
+ }
+
+ /* term sema */
+ sema_term(&idd->proc_sema);
+
+ /* free spinlock (while allocated!) */
+ NdisFreeSpinLock(&idd->lock);
+
+ NdisAcquireSpinLock(&GlobalIddTbl.lock);
+
+ //
+ // store idd in system idd table
+ //
+ for (n = 0; n < MAX_IDD_IN_SYSTEM; n++)
+ if (GlobalIddTbl.Idd[n] == idd)
+ break;
+
+ if (n < MAX_IDD_IN_SYSTEM)
+ GlobalIddTbl.Idd[n] = NULL;
+
+ GlobalIddTbl.NumberOfIddsInSystem--;
+
+ NdisReleaseSpinLock(&GlobalIddTbl.lock);
+
+ /* free memory for idd */
+ NdisFreeMemory(idd, sizeof(*idd), 0);
+
+
+ /* return success */
+ D_LOG(D_EXIT, ("idd_destroy: exit\n"));
+ return(IDD_E_SUCC);
+}
+
+
+//#ifdef PERADAPTER
+
+VOID
+IddPollFunction(
+ VOID *a1,
+ VOID *Adapter_1,
+ VOID *a3,
+ VOID *a4
+ )
+{
+#define MAX_EVENTS 1000
+ ULONG i, j, EventNum, TotalEventNum = 0;
+ ULONG FirstIdd, NumberOfIddOnAdapter;
+ ADAPTER *Adapter = (ADAPTER*)Adapter_1;
+ IDD *idd;
+
+ //
+ // check to see if there is someone else already polling
+ // an adapter that has the same shared memory window
+ // as this adapter. if someone is then get out so that we
+ // don't burn up this processor waiting for the other to complete
+ // if this adapter is supposed to be the next adapter to be polled
+ // only send him away for awhile, else send him away for normal polling
+ // time
+ //
+ if (CheckInDriverFlag(Adapter))
+ {
+ if (IsThisAdapterNext(Adapter))
+ {
+ //
+ // we want to come back asap
+ //
+ NdisMSetTimer(&Adapter->IddPollTimer, 0);
+ }
+ else
+ {
+ //
+ // we want to come back at our regular time
+ //
+ NdisMSetTimer(&Adapter->IddPollTimer, IDD_POLL_T);
+ }
+ return;
+ }
+
+ SetInDriverFlag(Adapter);
+
+ //
+ // this will be the first idd that we will poll
+ //
+ FirstIdd = Adapter->LastIddPolled;
+
+ //
+ // this will be the number of idds that we will poll
+ //
+ NumberOfIddOnAdapter = Adapter->NumberOfIddOnAdapter;
+
+ do
+ {
+ EventNum = 0;
+
+ //
+ // we will service all of the idd's in the system
+ // first lets do some receives
+ //
+
+ for (i = FirstIdd, j = FirstIdd + NumberOfIddOnAdapter; i < j; i++)
+ {
+ idd = Adapter->IddTbl[i % NumberOfIddOnAdapter];
+
+ if (idd && (idd->state == IDD_S_RUN))
+ EventNum += idd->PollRx(idd);
+ }
+
+
+ //
+ // we will service all of the idd's in the system
+ // now lets do the send queue
+ //
+ for (i = FirstIdd, j = FirstIdd + NumberOfIddOnAdapter; i < j; i++)
+ {
+ idd = Adapter->IddTbl[i % NumberOfIddOnAdapter];
+
+ if (idd && (idd->state == IDD_S_RUN))
+ {
+ EventNum += idd->PollTx(idd);
+ EventNum += idd->PollRx(idd);
+ }
+ }
+
+ TotalEventNum += EventNum;
+
+ } while (EventNum && (TotalEventNum < MAX_EVENTS) );
+
+ //
+ // bump so we start at next idd next time
+ //
+ Adapter->LastIddPolled++;
+
+ if (Adapter->LastIddPolled == NumberOfIddOnAdapter)
+ Adapter->LastIddPolled = 0;
+
+ ClearInDriverFlag(Adapter);
+
+ NdisMSetTimer(&Adapter->IddPollTimer, IDD_POLL_T);
+
+ //
+ // lets go ahead and give some of this data up to the wrapper
+ // hopefully this will keep us from running out of room in our
+ // assembly descriptor table
+ //
+ TryToIndicateMtlReceives(Adapter);
+}
+
+//#endif
+
+BOOLEAN
+IsThisAdapterNext(
+ ADAPTER *Adapter
+ )
+{
+ BOOLEAN ThisIsIt = FALSE;
+
+ NdisAcquireSpinLock(&Pcimac.lock);
+
+ if (Adapter == Pcimac.AdapterTbl[Pcimac.NextAdapterToPoll])
+ ThisIsIt = TRUE;
+
+ NdisReleaseSpinLock(&Pcimac.lock);
+
+ return(ThisIsIt);
+}
+
+
+#ifdef ALLADAPTERS
+VOID
+IddPollFunction(
+ VOID *a1,
+ VOID *Adapter_1,
+ VOID *a3,
+ VOID *a4
+ )
+{
+#define MAX_EVENTS 1000
+ ULONG i, j, EventNum, TotalEventNum = 0;
+ ULONG FirstIdd, NumberOfIddsInSystem;
+ ADAPTER *Adapter = (ADAPTER*)Adapter_1;
+ IDD *idd;
+
+
+ NdisAcquireSpinLock(&GlobalIddTbl.lock);
+
+ GlobalIddTbl.LastAdapter = GlobalIddTbl.CurrentAdapter;
+
+ GlobalIddTbl.CurrentAdapter = Adapter;
+
+ //
+ // this will be the first idd that we will poll
+ //
+ FirstIdd = GlobalIddTbl.LastIddPolled;
+
+ //
+ // this will be the number of idds that we will poll
+ //
+ NumberOfIddsInSystem = GlobalIddTbl.NumberOfIddsInSystem;
+
+ do
+ {
+ EventNum = 0;
+
+ //
+ // we will service all of the idd's in the system
+ // first lets do some receives
+ //
+ for (i = FirstIdd, j = FirstIdd + NumberOfIddsInSystem; i < j; i++)
+ {
+ idd = GlobalIddTbl.Idd[i % NumberOfIddsInSystem];
+
+ if (idd->state == IDD_S_RUN)
+ EventNum += idd->PollRx(idd);
+ }
+
+ //
+ // we will service all of the idd's in the system
+ // now lets do the send queue
+ //
+ for (i = FirstIdd, j = FirstIdd + NumberOfIddsInSystem; i < j; i++)
+ {
+ idd = GlobalIddTbl.Idd[i % NumberOfIddsInSystem];
+
+ if (idd->state == IDD_S_RUN)
+ {
+ EventNum += idd->PollTx(idd);
+ EventNum += idd->PollRx(idd);
+ }
+ }
+
+ TotalEventNum += EventNum;
+
+ } while (EventNum && (TotalEventNum < MAX_EVENTS) );
+
+ GlobalIddTbl.LastIddPolled++;
+
+ if (GlobalIddTbl.LastIddPolled == NumberOfIddsInSystem)
+ GlobalIddTbl.LastIddPolled = 0;
+
+ NdisReleaseSpinLock(&GlobalIddTbl.lock);
+
+ //
+ // lets go ahead and give some of this data up to the wrapper
+ // hopefully this will keep us from running out of room in our
+ // assembly descriptor table
+ //
+// TryToIndicateMtlReceives(Adapter);
+
+ NdisMSetTimer(&Adapter->IddPollTimer, IDD_POLL_T);
+}
+
+#endif
+
+#ifdef OLD
+VOID
+IddPollFunction(
+ VOID *a1,
+ VOID *Adapter_1,
+ VOID *a3,
+ VOID *a4
+ )
+{
+#define MAX_EVENTS 1000
+ ULONG n, EventNum, TotalEventNum = 0;
+
+ ADAPTER *Adapter = (ADAPTER*)Adapter_1;
+
+ do
+ {
+ EventNum = 0;
+
+ //
+ // we will service all of the idd's in the system
+ // first lets do some receives
+ //
+ for (n = 0; n < MAX_IDD_IN_SYSTEM; n++)
+ {
+ IDD *idd = GlobalIddTbl[n];
+
+ if (idd && (idd->state == IDD_S_RUN))
+ EventNum += idd->PollRx(idd);
+ }
+
+ //
+ // we will service all of the idd's in the system
+ // now lets do the send queue
+ //
+ for (n = 0; n < MAX_IDD_IN_SYSTEM; n++)
+ {
+ IDD *idd = GlobalIddTbl[n];
+
+ if (idd && (idd->state == IDD_S_RUN))
+ EventNum += idd->PollTx(idd);
+ }
+
+ TotalEventNum += EventNum;
+
+ } while (EventNum && (TotalEventNum < MAX_EVENTS) );
+
+ //
+ // lets go ahead and give some of this data up to the wrapper
+ // hopefully this will keep us from running out of room in our
+ // assembly descriptor table
+ //
+// TryToIndicateMtlReceives(Adapter);
+
+ NdisMSetTimer(&Adapter->IddPollTimer, IDD_POLL_T);
+}
+#endif
+
+/* get idd name */
+CHAR*
+idd_get_name(VOID *idd_1)
+{
+ IDD *idd = (IDD*)idd_1;
+ return(idd->name);
+}
+
+USHORT
+idd_get_bline(VOID *idd_1)
+{
+ IDD *idd = (IDD*)idd_1;
+ return(idd->bline);
+}
+
+USHORT
+idd_get_btype(VOID *idd_1)
+{
+ IDD *idd = (IDD*)idd_1;
+ return(idd->btype);
+}
+
+VOID*
+idd_get_trc (VOID *idd_1)
+{
+ IDD *idd = (IDD*)idd_1;
+ return(idd->trc);
+}
+
+VOID
+idd_set_trc (VOID *idd_1, TRC* Trace)
+{
+ IDD *idd = (IDD*)idd_1;
+ idd->trc = Trace;
+}
+
+INT
+idd_reset_area (VOID* idd_1)
+{
+ IDD *idd = (IDD*)idd_1;
+
+ idd->Area.area_state = AREA_ST_IDLE;
+
+ return(IDD_E_SUCC);
+}
+
+INT
+idd_get_area_stat (VOID *idd_1, IDD_AREA *IddStat)
+{
+ IDD *idd = (IDD*)idd_1;
+
+ *IddStat = idd->Area;
+
+ return(IDD_E_SUCC);
+}
+
+
+/* get an idd area (really start operation, complete on handler callback) */
+INT
+idd_get_area(VOID *idd_1, ULONG area_id, VOID (*handler)(), VOID *handler_arg)
+{
+ IDD *idd = (IDD*)idd_1;
+ IDD_MSG msg;
+
+ D_LOG(D_ENTRY, ("idd_get_area: entry, idd: 0x%lx, area_id: %ld\n", idd, area_id));
+ D_LOG(D_ENTRY, ("idd_get_area: handler: 0x%lx, handler_arg: 0x%lx\n", handler, handler_arg));
+
+ /* check if area is not busy */
+ if ( idd->Area.area_state == AREA_ST_PEND )
+ return(IDD_E_BUSY);
+
+ /* mark area is pending, store arguments */
+ idd->Area.area_state = AREA_ST_PEND;
+ idd->Area.area_id = area_id;
+ idd->Area.area_idd = idd;
+ idd->Area.area_len = 0;
+ idd->Area.area_handler = handler;
+ idd->Area.area_handler_arg = handler_arg;
+
+ /* issue idd command to get area */
+ NdisZeroMemory(&msg, sizeof(msg));
+ msg.opcode = CMD_DUMP_PARAM;
+ msg.param = msg.bufid = area_id;
+ if ( idd_send_msg(idd, &msg, IDD_PORT_CMD_TX, NULL, NULL) != IDD_E_SUCC )
+ {
+ /* idd op failed! */
+ idd->Area.area_state = AREA_ST_IDLE;
+ return(IDD_E_AREA);
+ }
+
+ /* succ here */
+ return(IDD_E_SUCC);
+}
+
+VOID
+IddSetRxFraming(
+ IDD *idd,
+ USHORT bchan,
+ ULONG FrameType
+ )
+{
+ idd->recit[bchan].RxFrameType = FrameType;
+}
+
+VOID
+DetectFramingHandler(
+ IDD *idd,
+ USHORT port,
+ ULONG RxFrameType,
+ IDD_XMSG *msg
+ )
+{
+ UCHAR DetectBytes[2];
+
+ DigiDump( DIGIQ931, ("DetectFramingHandler: idd = 0x%x, port = 0x%x, RxFrameType = 0x%x, msg = 0x%x\n",
+ idd,
+ port,
+ RxFrameType,
+ msg) );
+
+ if (RxFrameType & IDD_FRAME_DETECT)
+ {
+ //
+ // get detection bytes
+ //
+ IddGetDataFromAdapter(idd,
+ (PUCHAR)&DetectBytes,
+ (PUCHAR)msg->bufptr,
+ 2);
+
+// NdisMoveMemory ((PUCHAR)&DetectBytes, (PUCHAR)msg->bufptr, 2);
+
+ D_LOG(D_ENTRY, ("DetectRxFraming: 0x%x, 0x%x\n",DetectBytes[0], DetectBytes[1]));
+
+ if ((DetectBytes[0] == DKF_UUS_SIG) && (!DetectBytes[1]))
+ idd->recit[port].RxFrameType = IDD_FRAME_DKF;
+
+ else if ((DetectBytes[0] == PPP_SIG_0) && (DetectBytes[1] == PPP_SIG_1))
+ {
+ idd->recit[port].RxFrameType = IDD_FRAME_PPP;
+ cm__ppp_conn(idd, port);
+ }
+ }
+}
+
+VOID
+idd__cmd_handler(IDD *idd, USHORT chan, ULONG Reserved, IDD_MSG *msg)
+{
+ ULONG bytes;
+
+ /* check for show area more/last frames (3/4) */
+ if ( msg->bufid >= 2 )
+ {
+ if ( (idd->Area.area_state == AREA_ST_PEND) &&
+ (idd->Area.area_idd == idd) )
+ {
+ /* copy frame data, as much as possible */
+ bytes = MIN(msg->buflen, (sizeof(idd->Area.area_buf) - idd->Area.area_len));
+
+ IddGetDataFromAdapter(idd,
+ (PUCHAR)idd->Area.area_buf + idd->Area.area_len,
+ (PUCHAR)msg->bufptr,
+ (USHORT)bytes);
+
+// NdisMoveMemory (idd->Area.area_buf + idd->Area.area_len, msg->bufptr, bytes);
+
+ idd->Area.area_len += bytes;
+
+ /* if last, complete */
+ if ( msg->bufid == 3 )
+ {
+ idd->Area.area_state = AREA_ST_DONE;
+ if ( idd->Area.area_handler )
+ (*idd->Area.area_handler)(idd->Area.area_handler_arg,
+ idd->Area.area_id,
+ idd->Area.area_buf,
+ idd->Area.area_len);
+ }
+ }
+ }
+}
+
+#pragma NDIS_INIT_FUNCTION(idd_add_def)
+
+/* add a definition to initialization definition database */
+INT
+idd_add_def(IDD *idd, CHAR *name, CHAR *val)
+{
+ INT name_len = __strlen(name) + 1;
+ INT val_len = __strlen(val) + 1;
+
+ D_LOG(D_ENTRY, ("idd_add_def: entry\n"));
+
+ __strlwr(name);
+
+ __strlwr(val);
+
+ D_LOG(D_ENTRY, ("idd_add_def: name: [%s], val: [%s]\n", name, val));
+ /* check for room */
+
+ if ( (idd->DefinitionTableLength + name_len + val_len) > IDD_DEF_SIZE )
+ {
+ D_LOG(DIGIINIT, ("idd_add_def: no room in definition table!\n"));
+ return(IDD_E_NOROOM);
+ }
+
+ /* enter into table */
+ NdisMoveMemory(idd->DefinitionTable + idd->DefinitionTableLength, name, name_len);
+ idd->DefinitionTableLength += name_len;
+
+ NdisMoveMemory(idd->DefinitionTable + idd->DefinitionTableLength, val, val_len);
+ idd->DefinitionTableLength += val_len;
+
+ /* return success */
+ return(IDD_E_SUCC);
+} // end idd_add_def
+
+#pragma NDIS_INIT_FUNCTION(idd_get_nvram)
+
+/* get an nvram location */
+INT
+idd_get_nvram(VOID *idd_1, USHORT addr, USHORT *val)
+{
+ IDD *idd = (IDD*)idd_1;
+ D_LOG(D_ENTRY, ("idd_get_nvram: entry, idd: 0x%lx, addr: 0x%x\n", idd, addr));
+
+ /* lock card */
+ NdisAcquireSpinLock(&idd->lock);
+
+ /* do the read */
+ *val = idd->NVRamRead(idd, addr);
+
+ /* release card & return */
+ NdisReleaseSpinLock(&idd->lock);
+ D_LOG(D_EXIT, ("idd_get_nvram: exit, val: 0x%x\n", *val));
+ return(IDD_E_SUCC);
+}
diff --git a/private/ntos/ndis/digi/pcimac/idd_io.c b/private/ntos/ndis/digi/pcimac/idd_io.c
new file mode 100644
index 000000000..4f2c64744
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/idd_io.c
@@ -0,0 +1,672 @@
+ /*
+ * IDD_IO.C - do inp/outp ops for idd modules
+ */
+
+#include <ndis.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <idd.h>
+#include <res.h>
+
+typedef union
+{
+ UCHAR uc[4];
+ ULONG ul;
+}ULONG_UNION;
+
+typedef union
+{
+ UCHAR uc[2];
+ USHORT us;
+}USHORT_UNION;
+
+/* output to a port */
+VOID
+IdpOutp(
+ IDD *idd,
+ USHORT port,
+ UCHAR val)
+{
+ NdisRawWritePortUchar((ULONG)idd->vhw.vbase_io + port, val);
+}
+
+/* input from a port */
+UCHAR
+IdpInp(
+ IDD *idd,
+ USHORT port)
+{
+ UCHAR val;
+
+ NdisRawReadPortUchar((ULONG)idd->vhw.vbase_io + port, &val);
+
+ return(val);
+}
+
+/* output to a port */
+VOID
+AdpOutp(
+ IDD *idd,
+ USHORT port,
+ UCHAR val
+ )
+{
+ //
+ // Determine if this is a multi-channel BRI adapter. If so, then
+ // we need to select the correct ADP to reference.
+ //
+ // IMPORTANT NOTE: I can get away with this because we process IDD's
+ // on a per adapter basis. If this ever changes,
+ // then it may be necessary to change what is done
+ // here.
+ //
+ switch( idd->btype )
+ {
+ case IDD_BT_DATAFIRE4ST:
+ //
+ // select the correct BRI channel to access.
+ //
+ NdisRawWritePortUchar( (ULONG)idd->vhw.vbase_io + ADP_REG_ADAPTER_CTRL,
+ idd->bline );
+ break;
+ }
+
+ NdisRawWritePortUchar((ULONG)idd->vhw.vbase_io + port, val);
+} // end AdpOutp
+
+/* input from a port */
+UCHAR
+AdpInp(
+ IDD *idd,
+ USHORT port
+ )
+{
+ UCHAR val;
+
+ //
+ // Determine if this is a multi-channel BRI adapter. If so, then
+ // we need to select the correct ADP to reference.
+ //
+ // IMPORTANT NOTE: I can get away with this because we process IDD's
+ // on a per adapter basis. If this ever changes,
+ // then it may be necessary to change what is done
+ // here.
+ //
+ switch( idd->btype )
+ {
+ case IDD_BT_DATAFIRE4ST:
+ //
+ // select the correct BRI channel to access.
+ //
+ NdisRawWritePortUchar( (ULONG)idd->vhw.vbase_io + ADP_REG_ADAPTER_CTRL,
+ idd->bline );
+ break;
+ }
+
+ NdisRawReadPortUchar((ULONG)idd->vhw.vbase_io + port, &val);
+
+ return(val);
+} // end AdpInp
+
+VOID AdpWriteControlBit( IDD *idd,
+ UCHAR Bit,
+ UCHAR Value )
+/*++
+
+Routine Description:
+
+ Sets bits indicated to specified values.
+
+Arguments:
+
+ Bit - BitMask of which bits are to be set.
+
+ Value - BitMask to be applied to for Bit.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UCHAR OldData, NewData;
+
+ // Read old value.
+ OldData = idd->InFromPort( idd, ADP_REG_CTRL );
+
+ // Set new value
+ NewData = (OldData & Bit) | Value;
+
+// Data &= ~Bit;
+// Data |= (Value ? Bit : 0);
+
+ idd->OutToPort(idd, ADP_REG_CTRL, NewData);
+}
+
+UCHAR
+AdpReadReceiveStatus(
+ IDD *idd
+ )
+{
+ return(AdpGetUByte(idd, ADP_STS_WINDOW));
+}
+
+//
+// this function should be updated to use NdisRawWritePortBufferUshort
+// when the datarat is capable of handling it!!!!
+//
+VOID
+AdpPutBuffer (
+ IDD *idd,
+ ULONG Destination,
+ PUCHAR Source,
+ USHORT Length
+ )
+{
+ USHORT WordLength = Length >> 1;
+ PUCHAR OddData = (PUCHAR)(Source + (Length - 1));
+
+ D_LOG(D_ENTRY, ("AdpPutBuffer: idd: 0x%lx, Destination: 0x%lx, Source: 0x%lx, Length: %d\n", \
+ idd, Destination, Source, Length));
+
+ AdpSetAddress(idd, Destination);
+
+ //
+ // if WordLength has gone to zero with the shift this macro is just a nop
+ //
+ NdisRawWritePortBufferUshort((ULONG)(idd->vhw.vbase_io + ADP_REG_DATA_INC),
+ (PUSHORT)Source,
+ WordLength);
+
+ //
+ // if the length is odd write the last odd byte to adapter
+ //
+ if (Length & 0x0001)
+ NdisRawWritePortUchar((ULONG)idd->vhw.vbase_io + ADP_REG_DATA_INC, *OddData);
+
+#if 0
+ NdisRawWritePortBufferUchar( (ULONG)idd->vhw.vbase_io + ADP_REG_DATA_INC,
+ Source,
+ Length );
+#endif
+}
+
+//
+// this function should be updated to use NdisRawReadPortBufferUshort
+// when the datarat is capable of handling it!!!!
+//
+VOID
+AdpGetBuffer (
+ IDD *idd,
+ PUCHAR Destination,
+ ULONG Source,
+ USHORT Length
+ )
+{
+ USHORT WordLength = Length >> 1;
+ PUCHAR OddData = (PUCHAR)(Destination + (Length - 1));
+
+ D_LOG(D_ENTRY, ("AdpGetBuffer: idd: 0x%lx, Destination: 0x%lx, Source: 0x%lx, Length: %d\n", \
+ idd, Destination, Source, Length));
+
+ AdpSetAddress(idd, Source);
+
+ //
+ // if WordLength has gone to zero with the shift this macro is just a nop
+ //
+ NdisRawReadPortBufferUshort((ULONG)(idd->vhw.vbase_io + ADP_REG_DATA_INC),
+ (PUSHORT)Destination,
+ WordLength);
+
+ //
+ // if the length is odd read the last odd byte from adapter
+ //
+ if (Length & 0x0001)
+ NdisRawReadPortUchar((ULONG)idd->vhw.vbase_io + ADP_REG_DATA_INC, OddData);
+
+// NdisRawReadPortBufferUchar((ULONG)idd->vhw.vbase_io + ADP_REG_DATA_INC,
+// Buffer,
+// Length);
+}
+
+VOID
+AdpPutUByte(
+ IDD *idd,
+ ULONG Address,
+ UCHAR Value
+ )
+{
+ AdpSetAddress(idd, Address);
+ idd->OutToPort(idd, ADP_REG_DATA_INC, Value);
+}
+
+VOID
+AdpPutUShort(
+ IDD *idd,
+ ULONG Address,
+ USHORT Value
+ )
+{
+ USHORT_UNION us;
+
+ us.us = Value;
+ AdpSetAddress(idd, Address);
+ idd->OutToPort(idd, ADP_REG_DATA_INC, us.uc[1]);
+ idd->OutToPort(idd, ADP_REG_DATA_INC, us.uc[0]);
+}
+
+VOID
+AdpPutULong(
+ IDD *idd,
+ ULONG Address,
+ ULONG Value
+ )
+{
+ ULONG_UNION ul;
+
+ ul.ul = Value;
+ AdpSetAddress(idd, Address);
+ idd->OutToPort(idd, ADP_REG_DATA_INC, ul.uc[3]);
+ idd->OutToPort(idd, ADP_REG_DATA_INC, ul.uc[2]);
+ idd->OutToPort(idd, ADP_REG_DATA_INC, ul.uc[1]);
+ idd->OutToPort(idd, ADP_REG_DATA_INC, ul.uc[0]);
+}
+
+UCHAR
+AdpGetUByte(
+ IDD *idd,
+ ULONG Address
+ )
+{
+ UCHAR Value;
+
+ AdpSetAddress(idd, Address);
+
+ Value = idd->InFromPort(idd, ADP_REG_DATA_INC);
+
+ return(Value);
+}
+
+USHORT
+AdpGetUShort(
+ IDD *idd,
+ ULONG Address
+ )
+{
+ USHORT_UNION us;
+
+ AdpSetAddress(idd, Address);
+ us.uc[1] = idd->InFromPort(idd, ADP_REG_DATA_INC);
+ us.uc[0] = idd->InFromPort(idd, ADP_REG_DATA_INC);
+
+ return(us.us);
+}
+
+ULONG
+AdpGetULong(
+ IDD *idd,
+ ULONG Address
+ )
+{
+ ULONG_UNION ul;
+
+ AdpSetAddress(idd, Address);
+ ul.uc[3] = idd->InFromPort(idd, ADP_REG_DATA_INC);
+ ul.uc[2] = idd->InFromPort(idd, ADP_REG_DATA_INC);
+ ul.uc[1] = idd->InFromPort(idd, ADP_REG_DATA_INC);
+ ul.uc[0] = idd->InFromPort(idd, ADP_REG_DATA_INC);
+
+ return(ul.ul);
+}
+
+VOID
+AdpWriteCommandStatus(
+ IDD *idd,
+ UCHAR Value
+ )
+{
+ //
+ // setup the address
+ //
+ AdpSetAddress(idd, ADP_CMD_WINDOW + 1);
+
+ //
+ // put out the value
+ //
+ idd->OutToPort(idd, ADP_REG_DATA_INC, Value);
+}
+
+UCHAR
+AdpReadCommandStatus(
+ IDD *idd
+ )
+{
+ UCHAR Status;
+
+ //
+ // setup the address
+ //
+ AdpSetAddress(idd, ADP_CMD_WINDOW + 1);
+
+ //
+ // get status
+ //
+ Status = idd->InFromPort(idd, ADP_REG_DATA_INC);
+
+ return(Status);
+}
+
+VOID
+AdpSetAddress(
+ IDD *idd,
+ ULONG Address
+ )
+{
+ ULONG_UNION ul;
+
+ //
+ // Look at the heartbeat on the adapter and determine if it is
+ // still beating.
+ //
+ ul.ul = 0x504;
+ idd->OutToPort(idd, ADP_REG_ADDR_LO, ul.uc[0]);
+ idd->OutToPort(idd, ADP_REG_ADDR_MID, ul.uc[1]);
+ idd->OutToPort(idd, ADP_REG_ADDR_HI, ul.uc[2]);
+
+ ul.uc[3] = idd->InFromPort(idd, ADP_REG_DATA_INC);
+ ul.uc[2] = idd->InFromPort(idd, ADP_REG_DATA_INC);
+ ul.uc[1] = idd->InFromPort(idd, ADP_REG_DATA_INC);
+ ul.uc[0] = idd->InFromPort(idd, ADP_REG_DATA_INC);
+
+ D_LOG( D_NEVER, ("Heartbeat: 0x%lx\n", ul.ul) );
+
+ D_LOG(D_NEVER, ("AdpSetAddress: idd: 0x%lx, Address: 0x%lx\n", \
+ idd, Address));
+ //
+ // setup address
+ //
+ ul.ul = Address;
+ idd->OutToPort(idd, ADP_REG_ADDR_LO, ul.uc[0]);
+ idd->OutToPort(idd, ADP_REG_ADDR_MID, ul.uc[1]);
+ idd->OutToPort(idd, ADP_REG_ADDR_HI, ul.uc[2]);
+}
+
+UCHAR
+IdpGetUByteIO(
+ IDD* idd,
+ USHORT port
+ )
+{
+ UCHAR Value;
+
+ Value = idd->InFromPort(idd, port);
+
+ return(Value);
+}
+
+VOID
+IdpGetBuffer(
+ IDD* idd,
+ ULONG Bank,
+ ULONG Page,
+ ULONG Address,
+ USHORT Length,
+ PUCHAR Buffer
+ )
+{
+ //
+ // address from offset 0 on the bank and page described
+ //
+ PUCHAR VirtualAddress = idd->vhw.vmem + Address;
+
+ DbgPrint("IdpGetBuffer: idd: 0x%x, Bank: 0x%x, Page: 0x%x, Address: 0x%x, VirtAddres: 0x%x, Length: 0x%x\n",
+ idd, Bank, Page, Address, VirtualAddress, Length);
+
+
+ if (Length > IDP_RAM_PAGE_SIZE)
+ Length = IDP_RAM_PAGE_SIZE;
+
+ //
+ // set the bank to the desired bank
+ //
+ idd->SetBank(idd, (UCHAR)Bank, 1);
+
+ //
+ // set the page to the desired page
+ //
+ idd->ChangePage(idd, (UCHAR)Page);
+
+ //
+ // get the stuff
+ //
+ NdisMoveFromMappedMemory((PVOID)Buffer, (PVOID)VirtualAddress, Length);
+}
+
+VOID
+IdpPutUByteIO(
+ IDD* idd,
+ USHORT Port,
+ UCHAR Value
+ )
+{
+
+}
+
+VOID
+IdpPutBuffer(
+ IDD* idd,
+ ULONG Bank,
+ ULONG Page,
+ ULONG Address,
+ USHORT Length,
+ PUCHAR Buffer
+ )
+{
+
+}
+
+/*
+ * IDD_MC.C - IDD board specific functions for MCIMAC
+ */
+
+/* set active bank, control reset state */
+VOID
+IdpMcSetBank(IDD *idd, UCHAR bank, UCHAR run)
+{
+ static UCHAR reset_map[] = { 4, 5, 7 };
+ static UCHAR run_map[] = { 0, 1, 3 };
+
+ idd->OutToPort(idd, 1, (UCHAR)(run ? run_map[bank] : reset_map[bank]));
+}
+
+/* set active page, control memory mapping */
+VOID
+IdpMcSetPage(IDD *idd, UCHAR page)
+{
+ if ( page == IDD_PAGE_NONE )
+ idd->OutToPort(idd, 2, 0);
+ else
+ idd->OutToPort(idd, 2, (UCHAR)(0x80 | page));
+}
+
+/* set base memory window, redundent! - already stored by POS */
+VOID
+IdpMcSetBasemem(IDD *idd, ULONG basemem)
+{
+
+}
+
+
+/*
+ * IDD_PC.C - IDD board specific functions for ARIZONA
+ */
+
+/* set active bank, control reset state */
+VOID
+AdpSetBank(IDD *idd, UCHAR bank, UCHAR run)
+{
+
+}
+
+/* set active page, control memory mapping */
+VOID
+AdpSetPage(IDD *idd, UCHAR page)
+{
+
+}
+
+/* set base memory window, redundent! - already stored by POS */
+VOID
+AdpSetBasemem(IDD *idd, ULONG basemem)
+{
+
+}
+
+/*
+ * IDD_PC.C - IDD board specific functions for PCIMAC
+ */
+
+/* set active bank, control reset state */
+VOID
+IdpPcSetBank(IDD *idd, UCHAR bank, UCHAR run)
+{
+ //
+ // reset map means that the reset bit is held in the bank select register
+ //
+ static UCHAR reset_map[] = { 4, 5, 7 };
+
+ //
+ // run map means that the reset bit is not set in the bank select register
+ //
+ static UCHAR run_map[] = { 0, 1, 3 };
+
+ idd->OutToPort(idd, 4, (UCHAR)(run ? run_map[bank] : reset_map[bank]));
+}
+
+/* set active page, control memory mapping */
+VOID
+IdpPcSetPage(IDD *idd, UCHAR page)
+{
+ if ( page == IDD_PAGE_NONE )
+ idd->OutToPort(idd, 5, 0);
+ else
+ idd->OutToPort(idd, 5, (UCHAR)(0x80 | page));
+}
+
+/* set base memory window, over-writes IRQ to 0! */
+VOID
+IdpPcSetBasemem(IDD *idd, ULONG basemem)
+{
+ idd->OutToPort(idd, 6, (UCHAR)(basemem >> 8));
+ idd->OutToPort(idd, 7, (UCHAR)(basemem >> 16));
+}
+
+
+/*
+ * IDD_PC4.C - IDD board specific functions for PCIMAC\4
+ */
+
+/*
+ * set active bank, control reset state
+ *
+ * this routine makes use of the local data attached to the i/o resource.
+ * as local dta is a long, it is used as an image of registers 3,4,x,x
+ */
+VOID
+IdpPc4SetBank(IDD *idd, UCHAR bank, UCHAR run)
+{
+ static UCHAR reset_map[] = { 4, 5, 7 };
+ static UCHAR run_map[] = { 0, 1, 3 };
+ ULONG lreg;
+ UCHAR *reg = (UCHAR*)&lreg;
+ UCHAR val = run ? run_map[bank] : reset_map[bank];
+
+ D_LOG(D_ENTRY, ("idd__pc4_set_bank: entry, idd: 0x%lx, bank: 0x%x, run: 0x%x\n", idd, bank, run));
+
+ /* lock i/o resource, get local data - which is register image */
+ res_own(idd->res_io, idd);
+ res_get_data(idd->res_io, &lreg);
+
+ /* the easy way is to switch on bline & write bline specific code */
+ switch ( idd->bline )
+ {
+ case 0 :
+ reg[0] = (reg[0] & 0xF0) | val;
+ idd->OutToPort(idd, 3, reg[0]);
+ break;
+
+ case 1 :
+ reg[0] = (val << 4) | (reg[0] & 0x0F);
+ idd->OutToPort(idd, 3, reg[0]);
+ break;
+
+ case 2 :
+ reg[1] = (reg[1] & 0xF0) | val;
+ idd->OutToPort(idd, 4, reg[1]);
+ break;
+
+ case 3 :
+ reg[1] = (val << 4) | (reg[1] & 0x0F);
+ idd->OutToPort(idd, 4, reg[1]);
+ break;
+ }
+
+ /* return local data, release resource */
+ res_set_data(idd->res_io, lreg);
+ res_unown(idd->res_io, idd);
+
+ D_LOG(D_EXIT, ("idd__pc4_set_bank: exit\n"));
+}
+
+/* set active page, control memory mapping */
+VOID
+IdpPc4SetPage(IDD *idd, UCHAR page)
+{
+ if ( page == IDD_PAGE_NONE )
+ idd->OutToPort(idd, 5, 0);
+ else
+ idd->OutToPort(idd, 5, (UCHAR)(0x80 | page | (UCHAR)(idd->bline << 5)));
+}
+
+/* set base memory window, over-writes IRQ to 0! */
+VOID
+IdpPc4SetBasemem(IDD *idd, ULONG basemem)
+{
+ idd->OutToPort(idd, 6, (UCHAR)(basemem >> 8));
+ idd->OutToPort(idd, 7, (UCHAR)(basemem >> 16));
+}
+
+
+/*
+ * IDD_MEM.C - some memory handling routines
+ */
+
+
+/* fill a memory block using word moves */
+VOID
+IdpMemset(UCHAR*dst, USHORT val, INT size)
+{
+ D_LOG(D_ENTRY, ("idd__memwset: entry, dst: 0x%lx, val: 0x%x, size: 0x%x\n", dst, val, size));
+
+// for ( size /= sizeof(USHORT) ; size ; size--, dst++ )
+// NdisMoveToMappedMemory((PVOID)dst, (PVOID)&val, sizeof(USHORT));
+ NdisZeroMappedMemory((PVOID)dst, size);
+}
+
+/* copy a memory block using word moves */
+VOID
+IdpMemcpy(UCHAR *dst, UCHAR *src, INT size)
+{
+ D_LOG(D_ENTRY, ("idd__memwcpy: entry, dst: 0x%lx, src: 0x%lx, size: 0x%x\n", dst, src, size));
+
+// for ( size /= sizeof(USHORT) ; size ; size--, dst++, src++ )
+// NdisMoveToMappedMemory((PVOID)dst, (PVOID)src, sizeof(USHORT));
+
+ NdisMoveToMappedMemory((PVOID)dst, (PVOID)src, size);
+}
+
+
+
diff --git a/private/ntos/ndis/digi/pcimac/idd_msg.c b/private/ntos/ndis/digi/pcimac/idd_msg.c
new file mode 100644
index 000000000..d888cff45
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/idd_msg.c
@@ -0,0 +1,168 @@
+/*
+ * IDD_MSG.C - message handling code
+ */
+
+#include <ndis.h>
+#include <mydefs.h>
+#include <mytypes.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <idd.h>
+
+/* send a message down a port. only really queues message for transmittion */
+INT
+idd_send_msg(VOID *idd_1, IDD_MSG *msg, USHORT port, VOID (*handler)(), VOID *handler_arg)
+{
+ IDD *idd = (IDD*)idd_1;
+ INT ret = IDD_E_SUCC;
+ IDD_SENDQ *sq;
+
+ D_LOG((D_ENTRY|DIGIIDD), ("idd_send_msg: entry, idd: 0x%lx, msg: 0x%lx\n",
+ idd, msg));
+ D_LOG((D_ENTRY|DIGIIDD), ("idd_send_msg: port: %u, handler: 0x%lx, handler_arg: 0x%lx\n", \
+ port, handler, handler_arg));
+ D_LOG((D_ENTRY|DIGIIDD), ("idd_send_msg: opcode: 0x%x, buflen: 0x%x, bufptr: 0x%lx\n", \
+ msg->opcode, msg->buflen, msg->bufptr));
+ D_LOG((D_ENTRY|DIGIIDD), ("idd_send_msg: bufid: 0x%x, param: 0x%x\n", \
+ msg->bufid, msg->param));
+
+ /* check port */
+ if ( port >= IDD_TX_PORTS )
+ {
+ D_LOG(DIGIIDD, ("idd_send_msg: invalid port!\n"));
+ return(IDD_E_BADPORT);
+ }
+ sq = idd->sendq + port;
+
+ /* lock port queue */
+ NdisAcquireSpinLock(&sq->lock);
+
+ /* check for space */
+ if ( sq->num >= sq->max )
+ {
+ DbgPrint("sq->num: %d, sq->max: %d\n", sq->num, sq->max);
+ ret = IDD_E_NOROOM;
+ }
+ else
+ {
+ D_LOG( DIGITXFRAGDATA, ("Sending Frag:\n") );
+ DigiDumpData( DIGITXFRAGDATA, msg->bufptr, (msg->buflen & H_TX_LEN_MASK) );
+
+ /* space avail, fill in entry */
+ sq->tbl[sq->put].msg = *msg;
+ sq->tbl[sq->put].handler = handler;
+ sq->tbl[sq->put].handler_arg = handler_arg;
+ /* update queue vars */
+ if ( (sq->put += 1) >= sq->max )
+ sq->put = 0;
+ sq->num++;
+ }
+
+ /* release lock */
+ NdisReleaseSpinLock(&sq->lock);
+
+
+// /* (maybe) trigger processing */
+// if ( ret == IDD_E_SUCC )
+// idd_process(idd, 1);
+
+ if (ret == IDD_E_SUCC)
+ idd->PollTx(idd);
+
+ /* return here */
+ D_LOG(D_EXIT, ("idd_send_msg: exit, ret=0x%x\n", ret));
+ return(ret);
+} // end idd_send_msg
+
+/* attach a user handler to a port */
+//
+INT
+idd_attach(VOID *idd_1, USHORT port, VOID (*handler)(), VOID *handler_arg)
+{
+ INT ret = IDD_E_SUCC;
+ IDD_RECIT *rt;
+ IDD *idd = (IDD*)idd_1;
+
+ D_LOG(D_ENTRY, ("idd_attach: entry, idd: 0x%lx\n", idd));
+ D_LOG(D_ENTRY, ("idd_attach: port: %u, handler: 0x%lx, handler_arg: 0x%lx", \
+ port, handler, handler_arg));
+
+ /* check port */
+ if ( port >= IDD_RX_PORTS )
+ {
+ D_LOG((DIGIIDD|DIGIINIT), ("idd_attach: invalid port!\n"));
+ return(IDD_E_BADPORT);
+ }
+ rt = idd->recit + port;
+
+ /* lock port table */
+ NdisAcquireSpinLock(&rt->lock);
+
+ /* check for space */
+ if ( rt->num >= rt->max )
+ ret = IDD_E_NOROOM;
+ else
+ {
+ /* space avail, fill in entry */
+ rt->tbl[rt->num].handler = handler;
+ rt->tbl[rt->num].handler_arg = handler_arg;
+
+ /* update table vars */
+ rt->num++;
+ }
+
+ /* release lock */
+ NdisReleaseSpinLock(&rt->lock);
+
+ /* return here */
+ D_LOG(D_EXIT, ("idd_attach: exit, ret=0x%x\n", ret));
+ return(ret);
+}
+
+/* detach a user handler to a port */
+INT
+idd_detach(VOID *idd_1, USHORT port, VOID (*handler)(), VOID *handler_arg)
+{
+
+ INT ret = IDD_E_SUCC;
+ IDD_RECIT *rt;
+ INT n;
+ IDD *idd = (IDD*)idd_1;
+
+ D_LOG(D_ENTRY, ("idd_detach: entry, idd: 0x%lx\n", idd));
+ D_LOG(D_ENTRY, ("idd_detach: port: %u, handler: 0x%lx, handler_arg: 0x%lx", \
+ port, handler, handler_arg));
+
+ /* check port */
+ if ( port >= IDD_RX_PORTS )
+ {
+ D_LOG(DIGIIDD, ("idd_detach: invalid port!\n"));
+ return(IDD_E_BADPORT);
+ }
+ rt = idd->recit + port;
+
+ /* lock port table */
+ NdisAcquireSpinLock(&rt->lock);
+
+ /* scan table for handler/handler_arg */
+ for ( n = 0 ; n < rt->num ; n++ )
+ if ( (rt->tbl[n].handler == handler) && (rt->tbl[n].handler_arg == handler_arg) )
+ break;
+ if ( n >= rt->num )
+ ret = IDD_E_NOSUCH;
+ else
+ {
+ /* found, shrink table */
+ NdisMoveMemory(rt->tbl + n, rt->tbl + n + 1, sizeof(rt->tbl[0]) * (rt->num - n - 1));
+ rt->num--;
+ }
+
+ /* release lock */
+ NdisReleaseSpinLock(&rt->lock);
+
+ /* return here */
+ D_LOG(D_EXIT, ("idd_detach: exit, ret=0x%x\n", ret));
+ return(ret);
+}
+
diff --git a/private/ntos/ndis/digi/pcimac/idd_nv.c b/private/ntos/ndis/digi/pcimac/idd_nv.c
new file mode 100644
index 000000000..bda07f281
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/idd_nv.c
@@ -0,0 +1,140 @@
+/*
+ * IDD_NV.C - nvram handling routines
+ */
+
+#include <ndis.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <idd.h>
+#include <res.h>
+
+static USHORT nv_op (IDD*, SHORT, USHORT, USHORT, USHORT);
+static INT nv_clk (IDD*, USHORT);
+
+/* clock one nvram bit in/out */
+static INT
+nv_clk(IDD *idd, USHORT dat)
+{
+ INT ret;
+
+ dat &= 1; /* make sure dat is one bit only */
+
+ idd->OutToPort(idd, 0, (UCHAR)(0x04 | dat)); /* setup data */
+ idd->OutToPort(idd, 0, (UCHAR)(0x06 | dat)); /* clock high */
+ idd->OutToPort(idd, 0, (UCHAR)(0x04 | dat)); /* clock low */
+ ret = idd->InFromPort(idd, 0) & 0x01; /* return out bit */
+
+ return(ret);
+}
+
+/* perform a basic nvram operation */
+static USHORT
+nv_op(IDD *idd, SHORT op, USHORT addr, USHORT val, USHORT has_val)
+{
+ INT n;
+ USHORT word = 0;
+
+ D_LOG(D_ENTRY, ("nv_op: entry, idd: 0x%lx op: %d, addr: 0x%x, val: 0x%x, has_val: %d", \
+ idd, op, addr, val, has_val));
+
+ /* own i/o resource */
+ res_own(idd->res_io, idd);
+
+ /* set CS */
+ idd->OutToPort(idd, 0, 0x4);
+
+ /* if waiting for chip to be done, stay here */
+ if ( op < 0 )
+ {
+ while ( !(idd->InFromPort(idd, 0) & 0x01) )
+ ;
+ /* remove ownership of i/o */
+ res_unown(idd->res_io, idd);
+ return(0);
+ }
+
+ /* clock in SB + opcode */
+ nv_clk(idd, (USHORT)1);
+ nv_clk(idd, (USHORT)(op >> 1));
+ nv_clk(idd, (USHORT)(op & 1));
+
+ /* clock in address */
+ for ( n = 5 ; n >= 0 ; n-- )
+ nv_clk(idd, (USHORT)(addr >> n));
+
+ if ( has_val )
+ {
+ /* clock data/val in/out */
+ for ( n = 15 ; n >= 0 ; n-- )
+ word = (word << 1) | nv_clk(idd, (USHORT)(val >> n));
+ }
+
+ /* remove CS */
+ idd->OutToPort(idd, 0, 0x00);
+
+ /* remove ownership of i/o */
+ res_unown(idd->res_io, idd);
+
+
+ D_LOG(D_EXIT, ("nv_op: exit, word: 0x%x", word));
+ return(word);
+}
+
+/* read a nvram location */
+USHORT
+IdpNVRead(IDD *idd, USHORT addr)
+{
+ /* a basic op */
+ return(nv_op(idd, 2, addr, 0, 1));
+}
+
+
+/* read a nvram location */
+USHORT
+AdpNVRead(IDD *idd, USHORT addr)
+{
+ return(AdpGetUShort(idd, ADP_NVRAM_WINDOW + addr));
+}
+
+/* write a nvram location */
+VOID
+IdpNVWrite(IDD *idd, USHORT addr, USHORT val)
+{
+ /* enable writes */
+ nv_op(idd, 0, 0x30, 0, 0);
+
+ /* do the write */
+ nv_op(idd, 1, addr, val, 1);
+
+ /* wait for part to be done */
+ nv_op(idd, -1, 0, 0, 0);
+}
+
+/* write a nvram location */
+VOID
+AdpNVWrite(IDD *idd, USHORT addr, USHORT val)
+{
+
+}
+
+
+/* erase all nvram */
+VOID
+IdpNVErase(IDD *idd)
+{
+ /* enable writes */
+ nv_op(idd, 0, 0x30, 0, 0);
+
+ /* erase */
+ nv_op(idd, 0, 0x20, 0, 0);
+}
+
+/* erase all nvram */
+VOID
+AdpNVErase(IDD *idd)
+{
+
+}
diff --git a/private/ntos/ndis/digi/pcimac/idd_proc.c b/private/ntos/ndis/digi/pcimac/idd_proc.c
new file mode 100644
index 000000000..eac4e52cd
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/idd_proc.c
@@ -0,0 +1,988 @@
+/*
+ * IDD_PROC.C - do real tx/rx processing
+ */
+
+
+#include <ndis.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+#include <res.h>
+
+#if DBG
+#define AddBufferToList(_idd, _Part, _Buffer) \
+{ \
+ BUFFER_MANAGER *IdpBufferStuff = &(_idd)->BufferStuff[_Part]; \
+ ULONG *PutBuffer = &IdpBufferStuff->Buffer[IdpBufferStuff->Put % 32]; \
+ ASSERT(!*PutBuffer); \
+ *PutBuffer = _Buffer; \
+ IdpBufferStuff->Put++; \
+ IdpBufferStuff->Count++; \
+ ASSERT(IdpBufferStuff->Count < 32); \
+}
+
+#define RemoveBufferFromList(_idd, _Part) \
+{ \
+ BUFFER_MANAGER *IdpBufferStuff = &(_idd)->BufferStuff[_Part]; \
+ ULONG *GetBuffer = &IdpBufferStuff->Buffer[IdpBufferStuff->Get % 32]; \
+ ASSERT(*GetBuffer); \
+ *GetBuffer = 0; \
+ IdpBufferStuff->Get++; \
+ ASSERT(IdpBufferStuff->Count > 0); \
+ IdpBufferStuff->Count--; \
+}
+#endif
+
+/* poll (process) trasmitter side */
+ULONG
+IdpPollTx(IDD *idd)
+{
+ INT n, has_msg;
+ ULONG EventNum = 0;
+ IDD_SMSG smsg;
+ USHORT buf_len = 0, TxFlags = 0, TempUshort;
+ UCHAR status;
+ ULONG msg_bufptr, TempUlong;
+
+ D_LOG(D_NEVER, ("IdpPollTx: entry, idd: 0x%lx\n", idd));
+
+ /* must get semaphore */
+ if ( !sema_get(&idd->proc_sema) )
+ return(IDD_E_SUCC);
+
+ /* lock idd */
+ NdisAcquireSpinLock(&idd->lock);
+
+ if (!GetResourceSem (idd->res_mem))
+ {
+ NdisReleaseSpinLock(&idd->lock);
+ sema_free(&idd->proc_sema);
+ return(IDD_E_SUCC);
+ }
+
+ IdpCPage(idd, 0);
+
+ /* loop on all tx ports */
+ for ( n = 0 ; n < IDD_TX_PORTS ; n++ )
+ {
+ USHORT part = idd->tx_partq[n];
+
+ /* skip non existent ports */
+ if ( !idd->tx_port[n] )
+ continue;
+
+ /* check if port is blocked on a buffer */
+ if ( !idd->tx_buf[part] )
+ {
+ /* try to get a buffer for this partition */
+ IdpCPage(idd, 0);
+
+ TempUlong = (ULONG)(part + 4);
+ NdisMoveToMappedMemory((PVOID)&idd->IdpCmd->msg_param, (PVOID)&TempUlong, sizeof (ULONG));
+
+ status = idd->Execute(idd, IDP_L_GET_WBUF);
+
+ if ( status != IDP_S_OK)
+ {
+ D_LOG( DIGIERRORS, ( "Please contact Kendal Gabel or Rik Logan #1: status=0x%x\n",
+ ((ULONG)status & 0x000000FF)) );
+ continue;
+ }
+
+ /* if here, buffer allocated, register it */
+ NdisMoveFromMappedMemory( (PVOID)&idd->tx_buf[part], (PVOID)&idd->IdpCmd->msg_bufptr, sizeof (ULONG));
+
+#if DBG
+ AddBufferToList(idd, part, idd->tx_buf[part]);
+#endif
+
+ }
+
+ /* check if a message is waiting to be sent on a port */
+ NdisAcquireSpinLock(&idd->sendq[n].lock);
+ if ( has_msg = idd->sendq[n].num )
+ {
+ /* extract message off queue */
+ smsg = idd->sendq[n].tbl[idd->sendq[n].get];
+ if ( ++idd->sendq[n].get >= idd->sendq[n].max )
+ idd->sendq[n].get = 0;
+ idd->sendq[n].num--;
+ }
+ NdisReleaseSpinLock(&idd->sendq[n].lock);
+
+ /* if no message, escape here */
+ if ( !has_msg )
+ continue;
+
+ /* debug print message */
+ D_LOG(DIGIIDD, ("poll_tx: smsg: opcode: 0x%x, buflen: 0x%x, bufptr: 0x%lx\n", \
+ smsg.msg.opcode, smsg.msg.buflen, smsg.msg.bufptr));
+ D_LOG(DIGIIDD, ("poll_tx: bufid: 0x%x, param: 0x%x, handler: 0x%lx, arg: 0x%lx\n", \
+ smsg.msg.bufid, smsg.msg.param, smsg.handler, smsg.handler_arg));
+
+ //
+ // save xmitflags clearing out dkf fragment indicator
+ // they are in most significant nible
+ // Bits - xxxx
+ // ||||__ fragment indicator
+ // |||___ tx flush flag
+ // ||____ !tx end flag
+ // |_____ !tx begin flag
+ //
+ TxFlags = smsg.msg.buflen & TX_FLAG_MASK;
+
+
+#if DBG
+ switch (idd->BufferStuff[part].TxState)
+ {
+ case TX_BEGIN:
+ case TX_END:
+ if (TxFlags & H_TX_N_BEG)
+ {
+ DbgPrint("Missed a begining buffer! idd: 0x%x, part: %d\n", idd, part);
+ DbgPrint("TxFlags: 0x%x, State: 0x%x\n", TxFlags, idd->BufferStuff[part].TxState);
+ DbgBreakPoint();
+ }
+ else if (TxFlags & H_TX_N_END)
+ {
+ idd->BufferStuff[part].TxState = TX_MIDDLE;
+ idd->BufferStuff[part].FragsSinceBegin = 0;
+ }
+ break;
+
+ case TX_MIDDLE:
+ if (TxFlags & H_TX_N_BEG)
+ break;
+ else
+ {
+ DbgPrint("Missed an ending buffer! idd: 0x%x, part: %d\n", idd, part);
+ DbgPrint("TxFlags: 0x%x, State: 0x%x\n", TxFlags, idd->BufferStuff[part].TxState);
+ DbgBreakPoint();
+ }
+ break;
+
+ default:
+ DbgPrint("Unknown State! idd: 0x%x, part: %d\n", idd, part);
+ DbgPrint("TxFlags: 0x%x, State: 0x%x\n", TxFlags, idd->BufferStuff[part].TxState);
+ DbgBreakPoint();
+ idd->BufferStuff[part].TxState = TX_BEGIN;
+ idd->BufferStuff[part].FragsSinceBegin = 0;
+ break;
+ }
+
+ idd->BufferStuff[part].FragsSinceBegin++;
+ if (!(TxFlags & H_RX_N_END))
+ idd->BufferStuff[part].TxState = TX_END;
+
+#endif
+ /* check for buffer, if has one, copyin */
+
+ IdpCPage(idd, 0);
+
+ if( idd->tx_buf[part] == 0 )
+ DbgPrint( "Giving a 0 buffer back in IDP_L_WRITE call!\n" );
+
+ NdisMoveToMappedMemory( (PVOID)&idd->IdpCmd->msg_bufptr,
+ (PVOID)&idd->tx_buf[part],
+ sizeof (ULONG) );
+
+#if DBG
+ RemoveBufferFromList(idd, part);
+#endif
+
+ if ( smsg.msg.bufptr )
+ buf_len = IdpCopyin(idd, (char*)idd->tx_buf[part],
+ smsg.msg.bufptr, smsg.msg.buflen);
+ else
+ buf_len = 0;
+
+ IdpCPage(idd, 0);
+
+ TempUshort = (USHORT)(buf_len | TxFlags);
+ NdisMoveToMappedMemory((PVOID)&idd->IdpCmd->msg_buflen, (PVOID)&TempUshort, sizeof(USHORT));
+
+ /* copy rest of command area */
+ NdisMoveToMappedMemory((PVOID)&idd->IdpCmd->msg_opcode, (PVOID)&smsg.msg.opcode, sizeof(USHORT));
+
+ NdisMoveToMappedMemory((PVOID)&idd->IdpCmd->msg_bufid, (PVOID)&smsg.msg.bufid, sizeof (ULONG));
+
+ TempUlong = (ULONG)(part + 4);
+ NdisMoveToMappedMemory((PVOID)&idd->IdpCmd->msg_param, (PVOID)&TempUlong, sizeof (ULONG));
+
+ NdisMoveToMappedMemory((PVOID)&idd->IdpCmd->port_id, (PVOID)&idd->tx_port[n], sizeof(USHORT));
+
+ /* execute the command, mark an event */
+
+ status = idd->Execute(idd, IDP_L_WRITE);
+
+ EventNum++;
+
+ /* if came back with no buffer, mark it - else store buffer */
+ if ( status != IDP_S_OK )
+ {
+ idd->tx_buf[part] = 0;
+ D_LOG(D_RARE, ("poll_tx: no buffer!, part: %d\n", part));
+ D_LOG( DIGIERRORS, ( "Please contact Kendal Gabel or Rik Logan #2: status=0x%x\n",
+ ((ULONG)status & 0x000000FF)) );
+ }
+ else
+ {
+ NdisMoveFromMappedMemory((PVOID)&msg_bufptr, (PVOID)&idd->IdpCmd->msg_bufptr, sizeof (ULONG));
+
+ if ( msg_bufptr )
+ {
+ idd->tx_buf[part] = msg_bufptr;
+
+#if DBG
+ AddBufferToList(idd, part, idd->tx_buf[part]);
+#endif
+
+ D_LOG(D_RARE, ("poll_tx: new buffer, part: %d, buf: 0x%lx\n", \
+ part, idd->tx_buf[part]));
+ }
+ else
+ {
+ idd->tx_buf[part] = 0;
+ DbgPrint( "Adapter did not return buffer in IDP_L_WRITE\n" );
+ }
+ }
+
+ /* call user's handler */
+ if ( smsg.handler ) {
+ (*smsg.handler)(smsg.handler_arg, n, &smsg);
+ }
+
+ }
+
+ /* unset page, free memory window */
+ IdpCPage(idd, IDD_PAGE_NONE);
+
+ FreeResourceSem (idd->res_mem);
+
+ NdisReleaseSpinLock(&idd->lock);
+
+ sema_free(&idd->proc_sema);
+
+ return(EventNum);
+}
+
+/* poll (process) trasmitter side */
+ULONG
+AdpPollTx(IDD *idd)
+{
+ USHORT buf_len = 0, TxFlags = 0;
+ UCHAR status;
+ ULONG n, part, has_msg, EventNum = 0;
+ IDD_SMSG smsg;
+
+ D_LOG(D_NEVER, ("AdpPollTx: entry, idd: 0x%lx\n", idd));
+
+ /* must get semaphore */
+ if ( !sema_get(&idd->proc_sema) )
+ return(IDD_E_SUCC);
+
+ /* lock idd */
+ NdisAcquireSpinLock(&idd->lock);
+
+ //
+ // Lock access to the I/O ports in case this is a multi-BRI adapter
+ // e.g. DataFire4
+ //
+ if (!GetResourceSem (idd->res_io))
+ {
+ NdisReleaseSpinLock(&idd->lock);
+ sema_free(&idd->proc_sema);
+ return(IDD_E_SUCC);
+ }
+
+ //
+ // for all tx ports
+ //
+ for (n = 0; n < IDD_TX_PORTS; n++)
+ {
+ //
+ // skip non existent ports
+ //
+ if (!idd->tx_port[n])
+ continue;
+
+ //
+ // clear command structure
+ //
+ NdisZeroMemory(&idd->AdpCmd, sizeof(ADP_CMD));
+
+ //
+ // see if port is blocked needing a buffer
+ //
+ if ( !idd->tx_buf[part = idd->tx_partq[n]] )
+ {
+
+ //
+ // fill port id and status bit
+ //
+ idd->AdpCmd.msg_param = (UCHAR)part + 4;
+ //
+ // execute command
+ //
+ status = idd->Execute(idd, ADP_L_GET_WBUF);
+
+ //
+ // if no buffer then go to next port
+ //
+ if (status != ADP_S_OK)
+ {
+ D_LOG( DIGIERRORS, ( "Please contact Kendal Gabel or Rik Logan #1: status=0x%x\n",
+ ((ULONG)status & 0x000000FF)) );
+ continue;
+ }
+
+ //
+ // if here, buffer was allocate, register it
+ //
+ idd->tx_buf[part] = (ULONG)idd->AdpCmd.msg_bufptr;
+
+ }
+
+ //
+ // see if there is a message waiting to be sent
+ //
+ NdisAcquireSpinLock(&idd->sendq[n].lock);
+ if ( has_msg = idd->sendq[n].num )
+ {
+ /* extract message off queue */
+ smsg = idd->sendq[n].tbl[idd->sendq[n].get];
+ if ( ++idd->sendq[n].get >= idd->sendq[n].max )
+ idd->sendq[n].get = 0;
+ idd->sendq[n].num--;
+ }
+ NdisReleaseSpinLock(&idd->sendq[n].lock);
+
+ //
+ // if no message go to next port
+ //
+ if (!has_msg)
+ continue;
+
+ /* debug print message */
+ D_LOG(DIGIIDD, ("AdpPollTx: smsg: opcode: 0x%x, buflen: 0x%x, bufptr: 0x%lx\n", \
+ smsg.msg.opcode, smsg.msg.buflen, smsg.msg.bufptr));
+ D_LOG(DIGIIDD, ("AdpPollTx: bufid: 0x%x, param: 0x%x, handler: 0x%lx, arg: 0x%lx\n", \
+ smsg.msg.bufid, smsg.msg.param, smsg.handler, smsg.handler_arg));
+
+
+ //
+ // save xmitflags clearing out dkf fragment indicator
+ // they are in most significant nible
+ // Bits - xxxx
+ // ||||__ fragment indicator
+ // |||___ tx flush flag
+ // ||____ !tx end flag
+ // |_____ !tx begin flag
+ //
+ TxFlags = smsg.msg.buflen & TX_FLAG_MASK;
+
+ //
+ // see if there is a buffer to be copied
+ //
+ (ULONG)idd->AdpCmd.msg_bufptr = idd->tx_buf[part];
+
+ if ( smsg.msg.bufptr )
+ buf_len = AdpCopyin(idd, smsg.msg.bufptr, smsg.msg.buflen);
+ else
+ buf_len = 0;
+
+ idd->AdpCmd.msg_buflen = buf_len | TxFlags;
+ idd->AdpCmd.msg_opcode = smsg.msg.opcode;
+ idd->AdpCmd.msg_bufid = smsg.msg.bufid;
+ idd->AdpCmd.msg_param = (ULONG)(part + 4);
+ idd->AdpCmd.port_id = idd->tx_port[n];
+
+ status = idd->Execute(idd, ADP_L_WRITE);
+
+ EventNum++;
+
+ if (status != ADP_S_OK)
+ {
+ idd->tx_buf[part] = 0;
+ D_LOG(D_RARE, ("poll_tx: no buffer!, part: %d\n", part));
+ D_LOG( DIGIERRORS, ( "Please contact Kendal Gabel or Rik Logan #2: status=0x%x\n",
+ ((ULONG)status & 0x000000FF)) );
+ }
+ else
+ {
+ if (idd->AdpCmd.msg_bufptr)
+ {
+ idd->tx_buf[part] = (ULONG)idd->AdpCmd.msg_bufptr;
+ D_LOG(D_RARE, ("poll_tx: new buffer, part: %d, buf: 0x%lx\n", \
+ part, idd->tx_buf[part]));
+
+ }
+ }
+ /* call user's handler */
+ if ( smsg.handler )
+ (*smsg.handler)(smsg.handler_arg, n, &smsg);
+ }
+
+ FreeResourceSem (idd->res_io);
+
+ NdisReleaseSpinLock(&idd->lock);
+
+ sema_free(&idd->proc_sema);
+
+ return(EventNum);
+} // end AdpPollTx
+
+/* poll (process) reciever ports */
+ULONG
+IdpPollRx(IDD *idd)
+{
+ INT n, m;
+ USHORT stat, ofs;
+ IDD_XMSG msg;
+ UCHAR status, Page;
+ ULONG TempUlong, EventNum = 0;
+
+ /* must get semaphore */
+ if ( !sema_get(&idd->proc_sema) )
+ return(IDD_E_SUCC);
+
+ /* lock idd */
+ NdisAcquireSpinLock(&idd->lock);
+
+ if (!GetResourceSem (idd->res_mem))
+ {
+ NdisReleaseSpinLock(&idd->lock);
+ sema_free(&idd->proc_sema);
+ return(IDD_E_SUCC);
+ }
+
+ /* get status port */
+ IdpCPage(idd, 0);
+
+ NdisMoveFromMappedMemory((PVOID)&stat, (PVOID)idd->IdpStat, sizeof(USHORT));
+
+ D_LOG(D_NEVER, ("poll_rx: stat: 0x%x (@0x%lx)\n", stat, idd->IdpStat));
+
+ /* make one pass on all rx ports which have a status bit on */
+ for ( n = 0 ; n < IDD_RX_PORTS ; n++, stat >>= 1 )
+ if ( stat & 1 )
+ {
+ //
+ // skip non existent ports
+ //
+ if (!idd->rx_port[n])
+ continue;
+
+ /* install returned read buffer */
+ IdpCPage(idd, 0);
+
+ TempUlong = MAKELONG(HIWORD(idd->rx_buf), 0);
+ NdisMoveToMappedMemory((PVOID)&idd->IdpCmd->msg_bufid, (PVOID)&TempUlong, sizeof (ULONG));
+
+ idd->rx_buf = 0;
+
+ /* install port & execute a read */
+ D_LOG(DIGIIDD, ("poll_rx: index: %d, ReadPort 0x%x\n", n, idd->rx_port[n]));
+
+ NdisMoveToMappedMemory((PVOID)&idd->IdpCmd->port_id, (PVOID)&idd->rx_port[n], sizeof(USHORT));
+
+ status = idd->Execute(idd, IDP_L_READ);
+
+ if ( status != IDP_S_OK )
+ {
+ continue;
+ }
+
+ EventNum++;
+
+ /* copy message out */
+ NdisMoveFromMappedMemory((PVOID)&msg.opcode, (PVOID)&idd->IdpCmd->msg_opcode, sizeof(USHORT));
+
+ NdisMoveFromMappedMemory((PVOID)&msg.buflen, (PVOID)&idd->IdpCmd->msg_buflen, sizeof(USHORT));
+
+ // save receive fragment flags
+ // they are in most significant nible
+ // Bits - xxxx
+ // ||||__ reserved
+ // |||___ reserved
+ // ||____ !rx end flag
+ // |_____ !rx begin flag
+ //
+ msg.FragmentFlags = msg.buflen & RX_FLAG_MASK;
+
+ //
+ // get real buffer length
+ //
+ msg.buflen &= H_RX_LEN_MASK;
+
+ NdisMoveFromMappedMemory((PVOID)&msg.bufptr, (PVOID)&idd->IdpCmd->msg_bufptr, sizeof (ULONG));
+
+ NdisMoveFromMappedMemory((PVOID)&msg.bufid, (PVOID)&idd->IdpCmd->msg_bufid, sizeof (ULONG));
+
+ NdisMoveFromMappedMemory((PVOID)&msg.param, (PVOID)&idd->IdpCmd->msg_param, sizeof (ULONG));
+
+ /* save rx buffer */
+ idd->rx_buf = (ULONG)msg.bufptr;
+ D_LOG(DIGIIDD, ("poll_rx: 0x%x 0x%x %lx %lx %lx\n", \
+ msg.opcode, \
+ msg.buflen, \
+ msg.bufptr, \
+ msg.bufid, \
+ msg.param));
+
+ if ( msg.bufptr)
+ {
+ ofs = LOWORD(msg.bufptr);
+ Page = (UCHAR)(ofs >> 14) & 3;
+#if DBG
+ if (Page > 1 )
+ {
+ DbgPrint("Page changed to %d on idd 0x%lx!\n", Page, idd);
+ DbgBreakPoint();
+ }
+#endif
+ msg.bufptr = idd->vhw.vmem + (ofs & 0x3FFF);
+ IdpCPage(idd, Page);
+ }
+
+ /* loop on rx handler, call user to copyout buffer */
+ for ( m = 0 ; m < idd->recit[n].num ; m++ )
+ (*idd->recit[n].tbl[m].handler)(idd->recit[n].tbl[m].handler_arg,
+ n,
+ idd->recit[n].RxFrameType,
+ &msg);
+ }
+
+ /* unset page, free memory window */
+ IdpCPage(idd, IDD_PAGE_NONE);
+
+ FreeResourceSem (idd->res_mem);
+
+ NdisReleaseSpinLock(&idd->lock);
+
+ sema_free(&idd->proc_sema);
+
+ return(EventNum);
+}
+
+/* poll (process) receiver side */
+ULONG
+AdpPollRx(IDD *idd)
+{
+ INT n, m;
+ UCHAR status;
+ ULONG EventNum = 0;
+ USHORT stat = 0;
+ IDD_XMSG msg;
+
+ /* must get semaphore */
+ if ( !sema_get(&idd->proc_sema) )
+ return(IDD_E_SUCC);
+
+ /* lock idd */
+ NdisAcquireSpinLock(&idd->lock);
+
+ if (!GetResourceSem (idd->res_io))
+ {
+ NdisReleaseSpinLock(&idd->lock);
+ sema_free(&idd->proc_sema);
+ return(IDD_E_SUCC);
+ }
+
+ stat = AdpReadReceiveStatus(idd);
+
+ for( n = 0; stat && (n < IDD_RX_PORTS); n++, stat >>= 1 )
+ if (stat & 1)
+ {
+ //
+ // clear command structure
+ //
+ NdisZeroMemory(&idd->AdpCmd, sizeof(ADP_CMD));
+
+ D_LOG(DIGIIDD, ("poll_rx: index: %d, ReadPort 0x%x\n", n, idd->rx_port[n]));
+ //
+ // return read buffer
+ //
+ idd->AdpCmd.msg_bufid = MAKELONG(HIWORD(idd->rx_buf), 0);
+ idd->rx_buf = 0;
+
+ idd->AdpCmd.port_id = idd->rx_port[n];
+
+ status = idd->Execute(idd, ADP_L_READ);
+
+ if (status != ADP_S_OK)
+ continue;
+
+ EventNum++;
+
+ msg.opcode = idd->AdpCmd.msg_opcode;
+ msg.buflen = idd->AdpCmd.msg_buflen;
+
+ // save receive fragment flags
+ // they are in most significant nible
+ // Bits - xxxx
+ // ||||__ reserved
+ // |||___ reserved
+ // ||____ !rx end flag
+ // |_____ !rx begin flag
+ //
+ msg.FragmentFlags = msg.buflen & RX_FLAG_MASK;
+
+ //
+ // get real buffer length
+ //
+ msg.buflen &= H_RX_LEN_MASK;
+
+ msg.bufptr = (UCHAR*)LOWORD(idd->AdpCmd.msg_bufptr);
+ idd->rx_buf = (ULONG)idd->AdpCmd.msg_bufptr;
+ msg.bufid = idd->AdpCmd.msg_bufid;
+ msg.param = idd->AdpCmd.msg_param;
+
+
+ D_LOG(DIGIIDD, ("AdpPollRx: Opcode: 0x%x, BufLen: 0x%x, BufPtr: 0x%x\n", \
+ msg.opcode, \
+ msg.buflen, \
+ msg.bufptr));
+ D_LOG(DIGIIDD, ("AdpPollRx: FragmentFlags: 0x%x, BufId: 0x%x, Param: 0x%x\n", \
+ msg.FragmentFlags,\
+ msg.bufid, \
+ msg.param));
+
+ /* loop on rx handler, call user to copyout buffer */
+ for ( m = 0 ; m < idd->recit[n].num ; m++ )
+ (*idd->recit[n].tbl[m].handler)(idd->recit[n].tbl[m].handler_arg,
+ n,
+ idd->recit[n].RxFrameType,
+ &msg);
+ }
+
+ FreeResourceSem( idd->res_io );
+
+ NdisReleaseSpinLock(&idd->lock);
+
+ sema_free(&idd->proc_sema);
+
+ return(EventNum);
+} // end AdpPollRx
+
+/* execute an idp command. assumes cpage=0 */
+UCHAR
+IdpExec(IDD *idd, UCHAR opcode)
+{
+ UCHAR status = IDP_S_PEND;
+ ULONG TempWaitCounter;
+
+#if DBG
+ USHORT IdpCounter1 = 0;
+ ULONG IdpCounter2 = 0;
+#endif
+
+ D_LOG(D_ENTRY, ("IdpExec: entry, idd: 0x%lx, opcode=%d\n", idd, opcode));
+
+ /* install opcode, get command started */
+ NdisMoveToMappedMemory((PVOID)&idd->IdpCmd->opcode, (PVOID)&opcode, sizeof(UCHAR));
+
+ NdisMoveToMappedMemory((PVOID)&idd->IdpCmd->status, (PVOID)&status, sizeof(UCHAR));
+
+ status = IDP_S_EXEC;
+
+#if DBG
+ NdisMoveFromMappedMemory((PVOID)&IdpCounter1, (PVOID)(idd->vhw.vmem + 0x804), sizeof(USHORT));
+ NdisMoveFromMappedMemory((PVOID)&IdpCounter2, (PVOID)(idd->vhw.vmem + 0x808), sizeof(ULONG));
+#endif
+
+ idd->WaitCounter = 0;
+
+ while ( idd->state != IDD_S_SHUTDOWN )
+ {
+ NdisMoveFromMappedMemory((PVOID)&TempWaitCounter, (PVOID)(idd->vhw.vmem + 0x80C), sizeof(ULONG));
+ NdisMoveFromMappedMemory((PVOID)&status, (PVOID)&idd->IdpCmd->status, sizeof(UCHAR));
+
+ if ( IDP_S_DONE(status) )
+ break;
+
+ //
+ // wait for 1ms
+ // the ddk says that this function uses milliseconds but it
+ // actually takes microseconds
+ //
+ NdisStallExecution(1000L);
+
+ idd->WaitCounter++;
+ NdisMoveToMappedMemory((PVOID)(idd->vhw.vmem + 0x80C), (PVOID)&idd->WaitCounter, sizeof(ULONG));
+
+ //
+ // this should wait for about one second
+ //
+ if (idd->WaitCounter > 1000)
+ {
+
+ idd->state = IDD_S_SHUTDOWN;
+#if DBG
+ DbgPrint("Shutdown! idd: 0x%lx, Status: 0x%x\n", idd, status);
+ DbgPrint("Original: IdpCounter1: 0x%x, IdpCounter2: 0x%x\n", IdpCounter1, IdpCounter2);
+ NdisMoveFromMappedMemory((PVOID)&IdpCounter1, (PVOID)(idd->vhw.vmem + 0x804), sizeof(USHORT));
+ NdisMoveFromMappedMemory((PVOID)&IdpCounter2, (PVOID)(idd->vhw.vmem + 0x808), sizeof(ULONG));
+ DbgPrint("Current: IdpCounter1: 0x%x, IdpCounter2: 0x%x\n", IdpCounter1, IdpCounter2);
+ NdisMoveFromMappedMemory((PVOID)&status, (PVOID)&idd->IdpCmd->status, sizeof(UCHAR));
+ DbgPrint("CurrentStatus: 0x%x\n",status);
+ DbgBreakPoint();
+#endif
+ break;
+ }
+ else
+ status = IDP_S_EXEC;
+ }
+
+ D_LOG(D_EXIT, ("IdpExec: exit, IdpCmd->status: 0x%x\n", status));
+
+#if DBG
+ if (status && (status != IDP_S_NOBUF)
+ && (status != IDP_S_NOMSG))
+ {
+ USHORT MsgOpcode;
+ USHORT MsgBuflen;
+ UCHAR *MsgBufPtr;
+ ULONG MsgBufId;
+ ULONG MsgParam;
+
+ DbgPrint("Idd 0x%lx error executing opcode: 0x%x, status: 0x%x\n", idd, opcode, status);
+ NdisMoveFromMappedMemory((PVOID)&MsgOpcode, (PVOID)&idd->IdpCmd->msg_opcode, sizeof(USHORT));
+ NdisMoveFromMappedMemory((PVOID)&MsgBuflen, (PVOID)&idd->IdpCmd->msg_buflen, sizeof(USHORT));
+ NdisMoveFromMappedMemory( (PVOID)&MsgBufPtr, (PVOID)&idd->IdpCmd->msg_bufptr, sizeof (ULONG));
+ NdisMoveFromMappedMemory((PVOID)&MsgBufId, (PVOID)&idd->IdpCmd->msg_bufid, sizeof (ULONG));
+ NdisMoveFromMappedMemory((PVOID)&MsgParam, (PVOID)&idd->IdpCmd->msg_param, sizeof (ULONG));
+ DbgPrint("IdpExec: MsgOpcode: 0x%x, MsgBufLen: 0x%x, MsgBufPtr: 0x%x\n", MsgOpcode, MsgBuflen, MsgBufPtr);
+ DbgPrint("IdpExec: MsgBufId: 0x%x, MsgParam: 0x%x\n", MsgBufId, MsgParam);
+ }
+#endif
+
+ if (idd->WaitCounter > idd->MaxWaitCounter)
+ idd->MaxWaitCounter = idd->WaitCounter;
+
+ return(status);
+}
+
+/* execute an Adp command. assumes cpage=0 */
+UCHAR
+AdpExec(IDD *idd, UCHAR opcode)
+{
+ UCHAR status = ADP_S_PEND;
+ ULONG TempWaitCounter;
+
+ //
+ // set opcode
+ //
+ idd->AdpCmd.opcode = opcode;
+
+ D_LOG(D_ENTRY, ("AdpExec: entry, idd: 0x%lx, opcode: %d\n", idd, opcode));
+ D_LOG(D_ENTRY, ("status: 0x%x, port_id: 0x%x", idd->AdpCmd.status, idd->AdpCmd.port_id));
+ D_LOG(D_ENTRY, ("msg_opcode: 0x%x, msg_buflen: 0x%x\n", idd->AdpCmd.msg_opcode, idd->AdpCmd.msg_buflen));
+ D_LOG(D_ENTRY, ("msg_bufptr: 0x%x, msg_bufid: 0x%x\n", idd->AdpCmd.msg_bufptr, idd->AdpCmd.msg_bufid));
+ D_LOG(D_ENTRY, ("msg_param: 0x%x\n", idd->AdpCmd.msg_param));
+
+ //
+ // copy in command buffer
+ //
+ AdpPutBuffer(idd, ADP_CMD_WINDOW, (PUCHAR)&idd->AdpCmd, sizeof(ADP_CMD));
+
+ //
+ // start operation
+ //
+ AdpWriteCommandStatus(idd, ADP_S_PEND);
+
+ idd->WaitCounter = 0;
+
+ while ( idd->state != IDD_S_SHUTDOWN )
+ {
+ TempWaitCounter = AdpGetULong(idd, 0x50C);
+
+ status = AdpReadCommandStatus(idd);
+
+ if ( ADP_S_DONE(status) )
+ break;
+
+ //
+ // wait for 1ms
+ // the ddk says that this function uses milliseconds but it
+ // actually takes microseconds
+ //
+ NdisStallExecution(1000L);
+
+ idd->WaitCounter++;
+ AdpPutULong(idd, 0x50C, idd->WaitCounter);
+
+ //
+ // this should wait for about one second
+ //
+ if (idd->WaitCounter > 1000)
+ {
+ idd->state = IDD_S_SHUTDOWN;
+ idd->AbortReason = AdpGetUShort(idd, ADP_STS_WINDOW + 12);
+ }
+ }
+
+ AdpGetBuffer(idd, (PUCHAR)&idd->AdpCmd, ADP_CMD_WINDOW, sizeof(ADP_CMD));
+
+ if (idd->WaitCounter > idd->MaxWaitCounter)
+ idd->MaxWaitCounter = idd->WaitCounter;
+
+ D_LOG(D_EXIT, ("AdpExec: exit, AdpCmd.status: 0x%x\n", status));
+
+ return(status);
+} // end AdpExec
+
+/* map current idp page in */
+VOID
+IdpCPage(IDD *idd, UCHAR page)
+{
+ D_LOG(D_RARE, ("IdpCPage: entry, idd: 0x%lx, page: 0x%x\n", idd, page));
+
+ /* if page is IDD_PAGE_NONE, idd is releasing ownership of the page */
+ if ( page == IDD_PAGE_NONE )
+ {
+ idd->SetPage(idd, IDD_PAGE_NONE);
+ res_unown(idd->res_mem, idd);
+ }
+ else
+ {
+ page &= 3;
+
+ /* real mapping required, lock memory resource */
+ res_own(idd->res_mem, idd);
+ idd->SetPage(idd, page);
+ }
+}
+
+/* map current Adp page in */
+VOID
+AdpCPage(IDD *idd, UCHAR page)
+{
+
+}
+
+/* copy data from user buffer to idp */
+USHORT
+IdpCopyin(IDD *idd, UCHAR *dst, UCHAR *src, USHORT src_len)
+{
+ USHORT ofs, copylen;
+ UCHAR Page;
+ UINT tot_len, frag_num;
+ IDD_FRAG *frag;
+
+ D_LOG(D_RARE, ("Idpcopyin: entry, idd: 0x%lx, dst: 0x%lx, src: 0x%lx, src_len: 0x%x\n", \
+ idd, dst, src, src_len));
+
+ /* convert destination pointer to address & map in */
+ ofs = LOWORD((long)dst);
+ Page = (UCHAR)(ofs >> 14) & 3;
+
+#if DBG
+ if (Page > 1 )
+ DbgPrint("Page changed to %d on idd 0x%lx!\n", Page, idd);
+#endif
+
+ dst = idd->vhw.vmem + (ofs & 0x3FFF);
+
+ IdpCPage(idd, Page);
+
+ //
+ // mask out various flags to get length to copy
+ //
+ copylen = src_len & H_TX_LEN_MASK;
+
+ /* check for a simple copy, real easy - doit here */
+ if ( !(src_len & TX_FRAG_INDICATOR) )
+ {
+ NdisMoveToMappedMemory (dst, src, copylen);
+ return(copylen);
+ }
+
+ /* if here, its a fragment descriptor */
+ tot_len = 0;
+ frag_num = (copylen) / sizeof(IDD_FRAG);
+ frag = (IDD_FRAG*)src;
+
+ /* copy fragments */
+ for ( ; frag_num ; frag_num--, frag++ )
+ {
+ NdisMoveToMappedMemory (dst, frag->ptr, frag->len);
+ dst += frag->len;
+ tot_len += frag->len;
+ }
+
+ /* read total length */
+ return(tot_len);
+}
+
+/* copy data from user buffer to idp */
+USHORT
+AdpCopyin(IDD *idd, UCHAR *src, USHORT src_len)
+{
+ USHORT Destination, CopyLength;
+ UINT tot_len, frag_num;
+ IDD_FRAG *frag;
+
+ D_LOG(D_RARE, ("Adpcopyin: entry, idd: 0x%lx, src: 0x%lx, src_len: 0x%x\n", \
+ idd, src, src_len));
+
+ /* convert destination pointer to address & map in */
+ Destination = LOWORD(idd->AdpCmd.msg_bufptr);
+
+ //
+ // mask out various flags to get length to copy
+ //
+ CopyLength = src_len & H_TX_LEN_MASK;
+
+ /* check for a simple copy, real easy - doit here */
+ if ( !(src_len & TX_FRAG_INDICATOR) )
+ {
+ AdpPutBuffer(idd, Destination, src, CopyLength);
+ return(CopyLength);
+ }
+
+ /* if here, its a fragment descriptor */
+ tot_len = 0;
+ frag_num = (CopyLength) / sizeof(IDD_FRAG);
+ frag = (IDD_FRAG*)src;
+
+ /* copy fragments */
+ for ( ; frag_num ; frag_num--, frag++ )
+ {
+ AdpPutBuffer(idd, Destination, frag->ptr, frag->len);
+ Destination += frag->len;
+ tot_len += frag->len;
+ }
+
+ /* read total length */
+ return(tot_len);
+} // end AdpCopyin
+
+VOID
+IddGetDataFromAdapter(
+ VOID *idd_1,
+ PUCHAR Destination,
+ PUCHAR Source,
+ USHORT Length
+ )
+{
+ IDD *idd = (IDD*)idd_1;
+
+ if( (idd->btype != IDD_BT_DATAFIREU) &&
+ (idd->btype != IDD_BT_DATAFIREST) &&
+ (idd->btype != IDD_BT_DATAFIRE4ST) )
+ {
+ NdisMoveFromMappedMemory(Destination, Source, Length);
+ }
+ else
+ {
+ AdpGetBuffer(idd, Destination, (ULONG)Source, Length);
+ }
+}
diff --git a/private/ntos/ndis/digi/pcimac/idd_pub.h b/private/ntos/ndis/digi/pcimac/idd_pub.h
new file mode 100644
index 000000000..da43ee2b4
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/idd_pub.h
@@ -0,0 +1,59 @@
+/*
+ * IDD_PUB.H - IDP Device Driver public header for PCIMAC/ISA
+ */
+
+#ifndef _IDD_PUB_
+#define _IDD_PUB_
+
+#define IDD_MAX_AREA 512 /* max size of area got in get_area */
+
+//
+// global idd def's
+//
+/* IDD message descriptor */
+typedef struct
+{
+ USHORT opcode; /* message opcode (type) */
+ USHORT buflen; /* related buffer length */
+ UCHAR *bufptr; /* related buffer pointer (0=none) */
+ ULONG bufid; /* related buffer id */
+ ULONG param; /* parameter area */
+} IDD_MSG;
+
+/* IDD extended message descriptor */
+typedef struct
+{
+ USHORT opcode; /* message opcode (type) */
+ USHORT buflen; /* related buffer length */
+ UCHAR *bufptr; /* related buffer pointer (0=none) */
+ ULONG bufid; /* related buffer id */
+ ULONG param; /* parameter area */
+ USHORT FragmentFlags; /* fragmentation flags */
+} IDD_XMSG;
+
+/* IDD fragment descriptor */
+typedef struct
+{
+ USHORT len; /* fragment length */
+ CHAR *ptr; /* fragment buffer pointer */
+} IDD_FRAG;
+
+typedef struct
+{
+ VOID (*area_handler)(); /* handler for get_area */
+ VOID *area_handler_arg; /* argument for handler */
+
+ ULONG area_state; /* state of last/current get_area command */
+#define AREA_ST_IDLE 0 /* - idle, no area defined */
+#define AREA_ST_PEND 1 /* - pending, get_area in progress */
+#define AREA_ST_DONE 2 /* - done, results ready */
+
+ ULONG area_id; /* area id (number) pend/done */
+
+ VOID *area_idd; /* related idd (from which area is retreived) */
+ UCHAR area_buf[IDD_MAX_AREA]; /* buffer receiving/containing area data */
+ ULONG area_len; /* length of actual data */
+}IDD_AREA;
+
+#endif /* _IDD_PUB_ */
+
diff --git a/private/ntos/ndis/digi/pcimac/idd_run.c b/private/ntos/ndis/digi/pcimac/idd_run.c
new file mode 100644
index 000000000..1ba415857
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/idd_run.c
@@ -0,0 +1,868 @@
+/*
+ * IDD_RUN.C - run (startup) and shutdown idd object
+ */
+
+#include <ndis.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <idd.h>
+#include <res.h>
+
+/* a port descriptor */
+typedef struct
+{
+ char *name; /* port name */
+ INT must; /* mast map this port? */
+} PORT;
+
+/* port tables */
+static PORT api_rx_port_tbl[] =
+{
+ { "b1_rx ", 1 },
+ { "b2_rx ", 1 },
+ { "uart_rx ", 0 },
+ { "tdat ", 1 },
+ { "Cm.0 ", 1 },
+ { "Cm.1 ", 0 },
+ { NULL }
+};
+static PORT api_tx_port_tbl[] =
+{
+ { "b1_tx ", 1 },
+ { "b2_tx ", 1 },
+ { "uart_tx ", 0 },
+ { "cmd ", 1 },
+ { "Q931.0 ", 1 },
+ { "Q931.1 ", 0 },
+ { NULL }
+};
+
+/* partition queue table */
+
+static INT api_tx_partq_tbl[] =
+{
+ 0, // b1_tx --- I don't know if the relationship is correct or not??
+ 1, // b2_tx
+ 2, // uart_tx
+ 3, // cmd
+ 3, // Q931.0
+ 3 // Q931.1
+};
+
+/* local prototypes */
+INT api_setup(IDD* idd);
+INT api_map_ports(IDD* idd);
+INT api_bind_ports(IDD* idd);
+INT api_setup_partq(IDD* idd);
+INT api_alloc_partq(IDD* idd);
+
+#pragma NDIS_INIT_FUNCTION(idd_startup)
+
+/* startup (run) an idd object */
+INT
+idd_startup(VOID *idd_1)
+{
+ IDD *idd = (IDD*)idd_1;
+ INT ret;
+ D_LOG(D_ENTRY, ("idd_startup: entry, idd: 0x%lx\n", idd));
+
+ /* lock idd */
+ NdisAcquireSpinLock(&idd->lock);
+
+ /* mark starting */
+ idd->state = IDD_S_STARTUP;
+
+ switch( idd->btype )
+ {
+ case IDD_BT_PCIMAC:
+ case IDD_BT_PCIMAC4:
+ case IDD_BT_MCIMAC:
+ while(!GetResourceSem (idd->res_mem));
+ break;
+
+ case IDD_BT_DATAFIREU :
+ case IDD_BT_DATAFIREST:
+ case IDD_BT_DATAFIRE4ST:
+ while( !GetResourceSem( idd->res_io ) );
+ break;
+ }
+
+ /* do the startup */
+ if ( (ret = idd->LoadCode(idd)) != IDD_E_SUCC )
+ {
+ /* release idd */
+ switch( idd->btype )
+ {
+ case IDD_BT_PCIMAC:
+ case IDD_BT_PCIMAC4:
+ case IDD_BT_MCIMAC:
+ FreeResourceSem( idd->res_mem );
+ break;
+
+ case IDD_BT_DATAFIREU :
+ case IDD_BT_DATAFIREST:
+ case IDD_BT_DATAFIRE4ST:
+ FreeResourceSem( idd->res_io );
+ break;
+ }
+
+ NdisReleaseSpinLock(&idd->lock);
+ D_LOG(D_EXIT, ("idd_startup: error exit, ret=0x%x\n", ret));
+ return(ret);
+
+ }
+
+ //
+ // stall for a 50 millisecond
+ //
+ NdisStallExecution(50000L);
+
+ /* initialize api level - talks to memory! */
+ ret = api_setup(idd);
+
+ /* change state */
+ idd->state = IDD_S_RUN;
+
+ switch( idd->btype )
+ {
+ case IDD_BT_PCIMAC:
+ case IDD_BT_PCIMAC4:
+ case IDD_BT_MCIMAC:
+ FreeResourceSem( idd->res_mem );
+ break;
+
+ case IDD_BT_DATAFIREU :
+ case IDD_BT_DATAFIREST:
+ case IDD_BT_DATAFIRE4ST:
+ FreeResourceSem( idd->res_io );
+ break;
+ }
+
+ /* release idd */
+ NdisReleaseSpinLock(&idd->lock);
+
+ /* return result */
+ D_LOG(D_EXIT, ("idd_startup: exit, ret=0x%x\n", ret));
+ return(ret);
+}
+
+/* shutdown an idd object, not implemented yet */
+INT
+idd_shutdown(VOID *idd_1)
+{
+ IDD *idd = (IDD*)idd_1;
+ D_LOG(D_ENTRY, ("idd_shutdown: idd: 0x%lx\n", idd));
+
+ idd->state = IDD_S_SHUTDOWN;
+
+ idd->ResetAdapter(idd);
+
+ return(IDD_E_SUCC);
+}
+
+#pragma NDIS_INIT_FUNCTION(IdpLoadCode)
+
+/* load idp code in & run it */
+INT
+IdpLoadCode(IDD *idd)
+{
+ ULONG CurrentTime = 0, TimeOut = 0;
+ USHORT bank, page, n, NumberOfBanks;
+ UCHAR *fbin_data;
+ NDIS_STATUS stat;
+ UCHAR status = IDP_S_PEND;
+ NDIS_PHYSICAL_ADDRESS pa = NDIS_PHYSICAL_ADDRESS_CONST(0xffffffff, 0xffffffff);
+
+ D_LOG(D_ENTRY, ("load_code: entry, idd=0x%lx\n", idd));
+
+ /* setup pointers into shared memory */
+ idd->IdpStat = (USHORT*)(idd->vhw.vmem + IDP_STS_WINDOW);
+ idd->IdpCmd = (IDP_CMD*)(idd->vhw.vmem + IDP_CMD_WINDOW);
+ idd->IdpEnv = (UCHAR*)(idd->vhw.vmem + IDP_ENV_WINDOW);
+
+ /* setup base memory address registers */
+ idd->SetBasemem(idd, idd->phw.base_mem);
+
+ /* while in reset, clear all idp banks/pages */
+ for ( bank = 0 ; bank < 3 ; bank++ )
+ {
+ /* setup bank */
+ idd->SetBank(idd, (UCHAR)bank, 0);
+
+ /* loop on pages */
+ for ( page = 0 ; page < 4 ; page++ )
+ {
+ /* setup page */
+ idd->ChangePage (idd, (UCHAR)page);
+
+ /* zero out (has to be a word fill!) */
+ IdpMemset((UCHAR*)idd->vhw.vmem, 0, 0x4000);
+ }
+ }
+ //free page
+ idd->ChangePage (idd, (UCHAR)IDD_PAGE_NONE);
+
+ /* set idp to code bank, keep in reset */
+ idd->SetBank(idd, IDD_BANK_CODE, 0);
+
+ /* map file data in */
+ NdisMapFile(&stat, (PVOID*)&fbin_data, idd->phw.fbin);
+
+ if ( stat != NDIS_STATUS_SUCCESS )
+ {
+ D_LOG(DIGIIDD, ("load_code: file mapping failed!, stat: 0x%x\n", stat));
+ return(IDD_E_FMAPERR);
+ }
+
+// code to check for filelength greater than 64K
+ if (idd->phw.fbin_len > 0x10000)
+ NumberOfBanks = 2;
+ else
+ NumberOfBanks = 1;
+
+ for (n = 0; n < NumberOfBanks; n++)
+ {
+ /* copy data in (must be a word operation) */
+ for ( page = 0 ; page < 4 ; page++ )
+ {
+ idd->ChangePage(idd, (UCHAR)page);
+
+ IdpMemcpy((UCHAR*)idd->vhw.vmem,
+ (UCHAR*)(fbin_data + (page * 0x4000) + (n * 0x10000)), 0x4000);
+
+// DbgPrint ("Load: Src: 0x%lx, Dst: 0x%lx, Page: %d\n",
+// (fbin_data + (page*0x4000) + (n * 0x10000)), idd->vhw.vmem, page);
+
+ }
+
+ /* set idp to data bank, keep in reset */
+ idd->SetBank(idd, IDD_BANK_DATA, 0);
+ }
+
+ /* map file data out */
+ NdisUnmapFile(idd->phw.fbin);
+
+ /* switch back to buffer bank */
+ idd->ChangePage(idd, 0);
+ idd->SetBank(idd, IDD_BANK_BUF, 0);
+
+ /* add 'no_uart' definition */
+ NdisMoveMemory(idd->DefinitionTable + idd->DefinitionTableLength,
+ "no_uart\0any\0",
+ 12);
+
+ idd->DefinitionTableLength += 12;
+
+ /* load initial environment */
+ NdisMoveToMappedMemory((PVOID)idd->IdpEnv, (PVOID)idd->DefinitionTable, idd->DefinitionTableLength);
+
+ /* install startup byte signal */
+ NdisMoveToMappedMemory((PVOID)&idd->IdpCmd->status, (PVOID)&status, sizeof(UCHAR));
+
+ /* start idp running, wait for 1 second to complete */
+ idd->SetBank(idd, IDD_BANK_BUF, 1);
+
+ while ( !TimeOut )
+ {
+ NdisMoveFromMappedMemory((PVOID)&status, (PVOID)&idd->IdpCmd->status, sizeof(UCHAR));
+
+ if ( !status )
+ break;
+
+ //
+ // stall for a 1 millisecond
+ //
+ NdisStallExecution(1000L);
+
+ //
+ // add 1 millisecond to timeout counter
+ //
+ CurrentTime += 1;
+
+ //
+ // if timeout counter is greater the 2 seconds we have a problem
+ //
+ if ( CurrentTime > 2000)
+ TimeOut = 1;
+ }
+
+ if (TimeOut)
+ {
+ D_LOG((DIGIIDD|DIGIINIT), ("load_code: idp didn't start!\n"));
+
+ idd->state = IDD_S_SHUTDOWN;
+
+ /* unset page, free memory window */
+ idd->ChangePage(idd, IDD_PAGE_NONE);
+
+ return(IDD_E_RUNERR);
+ }
+
+
+ /* unset page, free memory window */
+ idd->ChangePage(idd, IDD_PAGE_NONE);
+
+ /* if here, idp runs now! */
+ D_LOG(D_EXIT, ("load_code: exit, idp running\n"));
+ return(IDD_E_SUCC);
+}
+
+
+#pragma NDIS_INIT_FUNCTION(AdpLoadCode)
+
+/* load idp code in & run it */
+INT
+AdpLoadCode(IDD *idd)
+{
+ UCHAR *Zero;
+ UCHAR *fbin_data, status;
+ NDIS_STATUS stat;
+ ADP_BIN_HEADER *Header;
+ ADP_BIN_BLOCK *Block, *FirstBlock;
+ ULONG CurrentTime = 0, TimeOut = 0;
+ USHORT BlockCount = 0;
+ ULONG n;
+
+ NDIS_PHYSICAL_ADDRESS HighestAcceptableMax = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
+
+ D_LOG(D_ENTRY, ("AdpLoadCode: entry, idd: 0x%lx\n", idd));
+
+ //
+ // Determine if this is a multi-channel BRI adapter. If so, then
+ // we need to select the correct ADP to reference.
+ //
+ switch( idd->btype )
+ {
+ case IDD_BT_DATAFIRE4ST:
+ //
+ // select the correct BRI channel to access.
+ //
+ idd->OutToPort( idd, ADP_REG_ADAPTER_CTRL, idd->bline );
+ break;
+ }
+
+ //
+ // reset the adapter
+ //
+ idd->OutToPort( idd, ADP_REG_CTRL, ADP_RESET_BIT );
+// idd->OutToPort( idd, ADP_REG_CTRL, ADP_RESET_BIT|ADP_HLT_BIT|ADP_PIRQ_BIT );
+// AdpWriteControlBit( idd,
+// ADP_RESET_BIT|ADP_PIRQEN_BIT|ADP_PIRQ_BIT|ADP_HLT_BIT,
+// 0x90);
+
+ //
+ // clear adapter memory
+ //
+ D_LOG(D_ENTRY, ("AdpLoadCode: Clear Memory\n"));
+
+ NdisAllocateMemory( (PVOID*)&Zero,
+ 0xFFFF,
+ 0,
+ HighestAcceptableMax );
+
+
+ NdisZeroMemory(Zero, 0xFFFF);
+
+ for (n = 0; n < ADP_RAM_SIZE; n += 0xFFFF)
+ AdpPutBuffer(idd, n, Zero, (USHORT)0xFFFF);
+
+// NdisFreeMemory(Zero, 0xFFFF, 0);
+
+ //
+ // map file data into memory
+ //
+ NdisMapFile(&stat, (PVOID*)&fbin_data, idd->phw.fbin);
+
+ if ( stat != NDIS_STATUS_SUCCESS )
+ {
+ D_LOG((DIGIINIT|DIGIIDD), ("AdpLoadCode: file mapping failed!, stat: 0x%x\n", stat));
+ return(IDD_E_FMAPERR);
+ }
+
+ //
+ // Get bin file header
+ //
+ (UCHAR*)Header = fbin_data;
+
+ if (Header->Format != ADP_BIN_FORMAT)
+ return(IDD_E_FMAPERR);
+
+ //
+ // Check file size
+ //
+ if (Header->ImageSize > ADP_RAM_SIZE)
+ return(IDD_E_FMAPERR);
+
+ BlockCount = Header->BlockCount;
+ (UCHAR*)FirstBlock = fbin_data + sizeof(ADP_BIN_HEADER);
+
+ for (n = 0; n < BlockCount; n++)
+ {
+#if 0
+ ULONG t;
+#endif
+
+ Block = FirstBlock + n;
+
+ AdpPutBuffer(idd, Block->Address, Block->Data, ADP_BIN_BLOCK_SIZE);
+
+#if 0
+ AdpGetBuffer( idd, Zero, Block->Address, ADP_BIN_BLOCK_SIZE );
+
+ for( t = 0; t < ADP_BIN_BLOCK_SIZE; t++ )
+ {
+ if( Zero[t] != Block->Data[t] )
+ DbgBreakPoint();
+ }
+
+ NdisZeroMemory(Zero, 1024);
+#endif
+ }
+
+ NdisFreeMemory(Zero, 0xFFFF, 0);
+
+ //
+ // unmap file data
+ //
+ NdisUnmapFile(idd->phw.fbin);
+
+ //
+ // add initial enviornment
+ //
+ /* add 'no_uart' definition */
+ NdisMoveMemory(idd->DefinitionTable + idd->DefinitionTableLength, "no_uart\0any\0", 12);
+ idd->DefinitionTableLength += 12;
+
+ D_LOG(D_ENTRY, ("AdpLoadCode: Add Enviornment\n"));
+
+ AdpPutBuffer(idd, ADP_ENV_WINDOW, idd->DefinitionTable, idd->DefinitionTableLength);
+
+ //
+ // write startup byte
+ //
+ AdpWriteCommandStatus(idd, ADP_S_PEND);
+
+ //
+ // release processor from reset
+ //
+ idd->OutToPort( idd, ADP_REG_CTRL, 0 );
+// AdpWriteControlBit( idd, ADP_RESET_BIT, 0 );
+
+ while ( !TimeOut )
+ {
+ status = AdpReadCommandStatus(idd);
+
+ if ( !status )
+ break;
+
+ //
+ // stall for a 1 millisecond
+ //
+ NdisStallExecution(1000L);
+
+ //
+ // add 1 millisecond to timeout counter
+ //
+ CurrentTime += 1;
+
+ //
+ // if timeout counter is greater the 2 seconds we have a problem
+ //
+ if ( CurrentTime > 2000)
+ TimeOut = 1;
+ }
+
+ if (TimeOut)
+ {
+
+ idd->AbortReason = AdpGetUShort( idd,
+ ADP_STS_WINDOW +
+ FIELD_OFFSET(ADP_STATUS, AbortReason) );
+ D_LOG((DIGIINIT|DIGIIDD), ("AdpLodeCode: Adp didn't start! AbortReason = 0x%x(%d)\n",
+ idd->AbortReason,
+ idd->AbortReason));
+ return(IDD_E_RUNERR);
+ }
+
+ /* if here, Adp runs now! */
+ D_LOG(D_EXIT, ("AdpLoadCode: exit, Adp running\n"));
+
+ return(IDD_E_SUCC);
+}
+
+
+#pragma NDIS_INIT_FUNCTION(api_setup)
+
+/* setup idp api related fields */
+INT
+api_setup(IDD *idd)
+{
+ INT ret;
+
+ D_LOG(D_ENTRY, ("api_setup: entry, idd: 0x%lx\n", idd));
+
+ /* map port names */
+ if ( (ret = api_map_ports(idd)) != IDD_E_SUCC )
+ return(ret);
+
+ /* bind ports to status bits */
+ if ( (ret = api_bind_ports(idd)) != IDD_E_SUCC )
+ return(ret);
+
+ /* setup partition queues */
+ if ( (ret = api_setup_partq(idd)) != IDD_E_SUCC )
+ return(ret);
+
+ /* allocate initial buffers off partition queues */
+ if ( (ret = api_alloc_partq(idd)) != IDD_E_SUCC )
+ return(ret);
+ D_LOG(D_EXIT, ("api_setup: exit, success\n"));
+
+ return(IDD_E_SUCC);
+}
+
+#pragma NDIS_INIT_FUNCTION(api_map_ports)
+
+/* map port names to ids */
+INT
+api_map_ports(IDD *idd)
+{
+ INT n;
+
+ D_LOG(D_ENTRY, ("api_map_ports: entry, idd: 0x%lx\n", idd));
+
+ /* map rx ports */
+ for ( n = 0 ; api_rx_port_tbl[n].name ; n++ )
+ {
+ idd->rx_port[n] = idd->ApiGetPort(idd, api_rx_port_tbl[n].name);
+
+ D_LOG((DIGIIDD|DIGIINIT), ("api_map_ports: RxPorts: PortName: %s, PortId: 0x%x\n", api_rx_port_tbl[n].name, idd->rx_port[n]));
+
+ if ( !idd->rx_port[n] && api_rx_port_tbl[n].must )
+ {
+ D_LOG((DIGIINIT|DIGIIDD), ("api_map_ports: failed to map rx port [%s]\n", \
+ api_rx_port_tbl[n].name));
+ return(IDD_E_PORTMAPERR);
+ }
+ }
+
+ /* map tx ports */
+ for ( n = 0 ; api_tx_port_tbl[n].name ; n++ )
+ {
+ idd->tx_port[n] = idd->ApiGetPort(idd, api_tx_port_tbl[n].name);
+
+ D_LOG((DIGIINIT|DIGIIDD), ("api_map_ports: TxPorts: PortName: %s, PortId: 0x%x\n", api_tx_port_tbl[n].name, idd->tx_port[n]));
+
+ if ( !idd->tx_port[n] && api_tx_port_tbl[n].must )
+ {
+ D_LOG((DIGIINIT|DIGIIDD), ("api_map_ports: failed to map tx port [%s]\n", \
+ api_tx_port_tbl[n].name));
+ return(IDD_E_PORTMAPERR);
+ }
+ }
+ return(IDD_E_SUCC);
+}
+
+#pragma NDIS_INIT_FUNCTION(api_bind_ports)
+
+/* bind ports to status bits */
+INT
+api_bind_ports(IDD *idd)
+{
+ INT n;
+
+ D_LOG(D_ENTRY, ("api_bind_ports: entry, idd: 0x%lx\n", idd));
+
+ /* bind rx ports */
+ for ( n = 0 ; api_rx_port_tbl[n].name; n++ )
+ {
+ if (idd->rx_port[n])
+ if ( idd->ApiBindPort(idd, idd->rx_port[n], (USHORT)(1 << n)) < 0 )
+ {
+ D_LOG((DIGIINIT|DIGIIDD), ("api_bind_ports: failed to bind status bit on port [%s]\n", \
+ api_rx_port_tbl[n].name));
+ return(IDD_E_PORTBINDERR);
+ }
+ }
+
+ return(IDD_E_SUCC);
+}
+
+#pragma NDIS_INIT_FUNCTION(api_setup_partq)
+
+/* setup partition queues */
+INT
+api_setup_partq(IDD *idd)
+{
+ INT n;
+
+ D_LOG(D_ENTRY, ("api_setup_partq: entry, idd: 0x%lx\n", idd));
+
+ /* simply copy table */
+ for ( n = 0 ; n < IDD_TX_PORTS ; n++ )
+ idd->tx_partq[n] = api_tx_partq_tbl[n];
+
+ return(IDD_E_SUCC);
+}
+
+#pragma NDIS_INIT_FUNCTION(api_alloc_partq)
+
+/* allocate initial buffers off partition queues */
+INT
+api_alloc_partq(IDD *idd)
+{
+ INT n, part;
+
+ D_LOG(D_ENTRY, ("api_alloc_partq: entry, idd: 0x%lx\n", idd));
+
+ /* scan using partq_tbl as a refrence. allocate only once per partq */
+ for ( n = 0 ; n < IDD_TX_PORTS ; n++ )
+ if ( !idd->tx_buf[part = api_tx_partq_tbl[n]] )
+ {
+ if ( !(idd->tx_buf[part] = idd->ApiAllocBuffer(idd, part)) )
+ {
+ D_LOG((DIGIINIT|DIGIIDD), ("api_alloc_partq: failed to alloc initial buffer, part: %d\n", part));
+ DbgPrint("api_alloc_partq: failed to alloc initial buffer, part: %d\n", part);
+ return(IDD_E_PARTQINIT);
+ }
+#if DBG
+ ASSERT(!idd->BufferStuff[part].Buffer[0]);
+ idd->BufferStuff[part].Buffer[0] = idd->tx_buf[part];
+ idd->BufferStuff[part].Count++;
+ idd->BufferStuff[part].Put++;
+ idd->BufferStuff[part].Get = 0;
+ ASSERT(idd->BufferStuff[part].Count < 32);
+#endif
+ }
+
+ return(IDD_E_SUCC);
+}
+
+#pragma NDIS_INIT_FUNCTION(IdpGetPort)
+
+/* get port id from a name */
+USHORT
+IdpGetPort(IDD *idd, CHAR name[8])
+{
+ UCHAR status;
+ USHORT port_id;
+
+ D_LOG(D_ENTRY, ("IdpGetPort: entry, idd: 0x%lx, name: [%s]\n", idd, name));
+
+ idd->ChangePage(idd, 0);
+
+ /* install target name & execute a map */
+ NdisMoveToMappedMemory ((CHAR *)idd->IdpCmd->port_name, (CHAR *)name, 8);
+
+ status = idd->Execute(idd, IDP_L_MAP);
+
+ NdisMoveFromMappedMemory((PVOID)&port_id, (PVOID)&idd->IdpCmd->port_id, sizeof(USHORT));
+
+ idd->ChangePage(idd, IDD_PAGE_NONE);
+
+ D_LOG(D_EXIT, ("IdpGetPort: exit, port_id: 0x%x\n", port_id));
+
+ return( (status == IDP_S_OK) ? port_id : 0);
+}
+
+#pragma NDIS_INIT_FUNCTION(AdpGetPort)
+
+/* get port id from a name */
+USHORT
+AdpGetPort(IDD *idd, CHAR name[8])
+{
+ UCHAR status;
+ D_LOG(D_ENTRY, ("AdpGetPort: entry, idd: 0x%lx, name: [%s]\n", idd, name));
+
+ //
+ // clear command structure
+ //
+ NdisZeroMemory(&idd->AdpCmd, sizeof(ADP_CMD));
+
+ //
+ // put port name in command structure
+ //
+ NdisMoveMemory((PVOID)&idd->AdpCmd.port_name, name, 8);
+
+ //
+ // execute command
+ //
+ status = idd->Execute(idd, ADP_L_MAP);
+
+ //
+ // check return status
+ //
+ if (status != ADP_S_OK)
+ return(0);
+
+ D_LOG((DIGIINIT|DIGIIDD), ("AdpGetPort: PortId: 0x%x\n", idd->AdpCmd.port_id));
+ //
+ // return port
+ //
+ return(idd->AdpCmd.port_id);
+}
+
+
+#pragma NDIS_INIT_FUNCTION(IdpBindPort)
+
+/* bind a port to a status bit */
+INT
+IdpBindPort(IDD *idd, USHORT port, USHORT bitpatt)
+{
+ UCHAR status;
+
+ D_LOG(D_ENTRY, ("IdpBindPort: entry, idd: 0x%lx, port: 0x%x, bitpatt: 0x%x\n",
+ idd, port, bitpatt));
+
+ idd->ChangePage(idd, 0);
+
+ /* fillup cmd & execute a bind */
+ NdisMoveToMappedMemory((PVOID)&idd->IdpCmd->port_id, (PVOID)&port, sizeof(USHORT));
+ NdisMoveToMappedMemory((PVOID)&idd->IdpCmd->port_bitpatt, (PVOID)&bitpatt, sizeof(USHORT));
+
+ status = idd->Execute(idd, IDP_L_BIND);
+
+ idd->ChangePage(idd, IDD_PAGE_NONE);
+
+ return( (status == IDP_S_OK) ? 0 : -1 );
+}
+
+#pragma NDIS_INIT_FUNCTION(AdpBindPort)
+
+/* bind a port to a status bit */
+INT
+AdpBindPort(IDD *idd, USHORT port, USHORT bitpatt)
+{
+ UCHAR status;
+
+ D_LOG(D_ENTRY, ("AdpBindPort: entry, idd: 0x%lx, port: 0x%x, bitpatt: 0x%x\n",
+ idd, port, bitpatt));
+ //
+ // clear command structure
+ //
+ NdisZeroMemory(&idd->AdpCmd, sizeof(ADP_CMD));
+
+ //
+ // fill port id and status bit
+ //
+ idd->AdpCmd.port_id = port;
+ idd->AdpCmd.port_bitpatt = bitpatt;
+
+ //
+ // execute command
+ //
+ status = idd->Execute(idd, ADP_L_BIND);
+
+ D_LOG((DIGIINIT|DIGIIDD), ("AdpBindPort: ExecuteStatus: 0x%x\n", status));
+
+ if (status != ADP_S_OK)
+ return(1);
+
+ return(0);
+}
+
+
+#pragma NDIS_INIT_FUNCTION(IdpAllocBuf)
+
+/* allocate a buffer off a partition */
+ULONG
+IdpAllocBuf(IDD *idd, INT part)
+{
+ UCHAR status;
+ ULONG msg_bufptr;
+ ULONG temp;
+
+ D_LOG(D_ENTRY, ("IdpAllocBuf: entry, idd: 0x%lx, part: %d\n", idd, part));
+
+ idd->ChangePage(idd, 0);
+
+ /* fillup & execute */
+ temp = (ULONG)(part + 4);
+
+ NdisMoveToMappedMemory ((PVOID)&idd->IdpCmd->msg_param, (PVOID)&temp, sizeof (ULONG));
+
+ status = idd->Execute(idd, IDP_L_GET_WBUF);
+
+ NdisMoveFromMappedMemory((PVOID)&msg_bufptr, (PVOID)&idd->IdpCmd->msg_bufptr, (ULONG)sizeof (ULONG));
+
+ idd->ChangePage(idd, IDD_PAGE_NONE);
+
+ return( (status == IDP_S_OK) ? msg_bufptr : 0 );
+}
+
+#pragma NDIS_INIT_FUNCTION(AdpAllocBuf)
+
+/* allocate a buffer off a partition */
+ULONG
+AdpAllocBuf(IDD *idd, INT part)
+{
+ UCHAR status;
+
+ D_LOG(D_ENTRY, ("AdpAllocBuf: entry, idd: 0x%lx, part: %d\n", idd, part));
+
+ //
+ // clear command structure
+ //
+ NdisZeroMemory(&idd->AdpCmd, sizeof(ADP_CMD));
+
+ //
+ // fill port id and status bit
+ //
+ idd->AdpCmd.msg_param = (UCHAR)part + 4;
+ //
+ // execute command
+ //
+ status = idd->Execute(idd, ADP_L_GET_WBUF);
+
+ D_LOG((DIGIINIT|DIGIIDD), ("AdpAllocBuf: status: 0x%x, BufPtr: 0x%x\n", status, idd->AdpCmd.msg_bufptr));
+
+ return ((status == ADP_S_OK) ? (ULONG)idd->AdpCmd.msg_bufptr : 0);
+}
+
+/* reset idp board */
+INT
+IdpResetBoard(IDD *idd)
+{
+ USHORT bank, page;
+ D_LOG(D_ENTRY, ("reset_board: entry, idd: 0x%lx\n", idd));
+
+ /* while in reset, clear all idp banks/pages */
+ for ( bank = 0 ; bank < 3 ; bank++ )
+ {
+ /* setup bank */
+ idd->SetBank(idd, (UCHAR)bank, 0);
+
+ /* loop on pages */
+ for ( page = 0 ; page < 4 ; page++ )
+ {
+ /* setup page */
+ idd->ChangePage (idd, (UCHAR)page);
+
+ /* zero out (has to be a word fill!) */
+ IdpMemset((UCHAR*)idd->vhw.vmem, 0, 0x4000);
+ }
+ }
+
+ idd->SetBank(idd, IDD_BANK_CODE, 0);
+
+ //free page
+ idd->ChangePage (idd, (UCHAR)IDD_PAGE_NONE);
+
+ return(IDD_E_SUCC);
+}
+
+/* reset idp board */
+INT
+AdpResetBoard(IDD *idd)
+{
+ //
+ // reset the adapter
+ //
+ idd->OutToPort( idd, ADP_REG_CTRL, ADP_RESET_BIT );
+// AdpWriteControlBit(idd, ADP_RESET_BIT, 0x80);
+
+ return(IDD_E_SUCC);
+}
+
diff --git a/private/ntos/ndis/digi/pcimac/io.h b/private/ntos/ndis/digi/pcimac/io.h
new file mode 100644
index 000000000..52530f68d
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/io.h
@@ -0,0 +1,27 @@
+/*
+ * IO.H - include file for all IO modules
+ */
+
+#ifndef _IO_
+#define _IO_
+
+#include <io_pub.h>
+
+// This is only for NT
+#if !BINARY_COMPATIBLE
+
+/* forward for ioctl filter function */
+NTSTATUS PcimacIoctl(DEVICE_OBJECT* DeviceObject, IRP* Irp);
+
+NTSTATUS ExecIrp(IRP *irp, IO_STACK_LOCATION *irpsp);
+
+
+/* ioctl opcode to executing commands */
+#define IO_IOCTL_PCIMAC_EXEC 0x160040/* temp!!! */
+
+INT io_execute(IO_CMD* cmd, VOID *Irp_1);
+
+#endif
+
+
+#endif /* _IO_ */
diff --git a/private/ntos/ndis/digi/pcimac/io_core.c b/private/ntos/ndis/digi/pcimac/io_core.c
new file mode 100644
index 000000000..daa0f0f52
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/io_core.c
@@ -0,0 +1,435 @@
+/*
+ * IO_CORE.C - core routines for IO module
+ */
+
+#include <ndis.h>
+#include <ndiswan.h>
+#include <mydefs.h>
+#include <mytypes.h>
+#include <util.h>
+#include <disp.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+#include <trc.h>
+#include <io.h>
+
+#include <dgatlas.h>
+#include <dgbrip.h>
+
+extern DRIVER_BLOCK Pcimac;
+
+/* store location for prev. ioctl handler */
+extern NTSTATUS (*PrevIoctl)(DEVICE_OBJECT* DeviceObject, IRP* Irp);
+
+/* ioctl filter */
+NTSTATUS
+PcimacIoctl(DEVICE_OBJECT *DeviceObject, IRP *Irp)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
+ NTSTATUS ini_exec_irp(IRP* irp, IO_STACK_LOCATION* irpsp);
+
+ /* must be an ioctl, else pass this one */
+ if ( irpSp->MajorFunction != IRP_MJ_DEVICE_CONTROL )
+ {
+ NdisReleaseSpinLock(&Pcimac.lock);
+
+ return(PrevIoctl(DeviceObject, Irp));
+ }
+
+ /* must be our own private ioctl code */
+
+ switch( irpSp->Parameters.DeviceIoControl.IoControlCode )
+ {
+ case IO_IOCTL_PCIMAC_EXEC:
+ case DIGI_ATLAS_IOCTL:
+ break;
+ }
+
+ /* one of our own, execute */
+ Irp->IoStatus.Information = 0L;
+ ExecIrp(Irp, irpSp);
+
+ /* complete irp */
+ Irp->IoStatus.Status = status;
+ IoSetCancelRoutine (Irp, NULL);
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return(status);
+}
+
+/* execute ioctl irp */
+NTSTATUS
+ExecIrp(IRP *irp, IO_STACK_LOCATION *irpsp)
+{
+ UCHAR *in_buf, *out_buf;
+ ULONG in_len, out_len;
+ NTSTATUS stat;
+
+ /* establish in/out buffers */
+ out_len = irpsp->Parameters.DeviceIoControl.OutputBufferLength;
+ in_len = irpsp->Parameters.DeviceIoControl.InputBufferLength;
+
+
+ /* in/out length must be the same */
+ if ( in_len != out_len )
+ return(STATUS_UNSUCCESSFUL);
+
+ switch( irpsp->Parameters.DeviceIoControl.IoControlCode )
+ {
+ case IO_IOCTL_PCIMAC_EXEC:
+ out_buf = irp->UserBuffer;
+ in_buf = irp->AssociatedIrp.SystemBuffer;
+ /* copy in buffer into output buffer */
+ NdisMoveMemory(out_buf, in_buf, out_len);
+
+ /* execute command in place */
+ if ( (stat = io_execute((IO_CMD*)out_buf,irp)) == IO_E_PENDING)
+ /* event added pend irp */
+ return (STATUS_PENDING);
+ else
+ /* return success */
+ return(STATUS_SUCCESS);
+
+ break;
+
+ case DIGI_ATLAS_IOCTL:
+ {
+ PATLAS_PDU_HEADER Atlas;
+
+ //
+ // We need to decapsulate the DIGI_Opcode wrapper to get to
+ // the IO_CMD
+ //
+
+ out_buf = irp->AssociatedIrp.SystemBuffer;
+ in_buf = irp->AssociatedIrp.SystemBuffer;
+ Atlas = (PATLAS_PDU_HEADER)out_buf;
+
+ switch( Atlas->dwCommand )
+ {
+ case EnumAdapters:
+ {
+ ULONG n, m, NumberOfAdapters;
+ PDIGI_SYSTEM SystemInfo;
+
+ //
+ // We need to let Atlas know about all the adapters
+ // we are controlling.
+ //
+ SystemInfo = (PDIGI_SYSTEM)GET_PAYLOAD(Atlas);
+ NumberOfAdapters = EnumAdaptersInSystem();
+
+ for( n = 0, m = 0; n < NumberOfAdapters; n++ )
+ {
+ ADAPTER *Adapter = GetAdapterByIndex(n);
+
+ if( Adapter )
+ {
+ PDIGI_ADAPTER AtlasAdapterInfo;
+
+ AtlasAdapterInfo = &SystemInfo->Adapters[m];
+
+ AtlasAdapterInfo->dwMemoryAddress = Adapter->BaseMem;
+
+ if( Adapter->BaseMem )
+ AtlasAdapterInfo->dwMemoryRange = 0x4000;
+ else
+ AtlasAdapterInfo->dwMemoryRange = 0;
+
+ AtlasAdapterInfo->dwIOAddress = Adapter->BaseIO;
+ AtlasAdapterInfo->dwIORange = 8;
+
+ AtlasAdapterInfo->dwInterruptNumber = 0;
+ AtlasAdapterInfo->dwDMA = 0;
+
+ AtlasAdapterInfo->dwPersonalities = 1;
+ AtlasAdapterInfo->Personalities[0].dwPersonalityTag = DIGI_PERSONALITY_BRI;
+ AtlasAdapterInfo->Personalities[0].dwId = (DWORD)Adapter;
+
+ NdisMoveMemory( AtlasAdapterInfo->Personalities[0].szDesc,
+ Adapter->Name,
+ BRI_MAX_NAMELEN );
+
+ m++;
+ }
+ }
+
+ SystemInfo->dwAdapters = m;
+
+ irp->IoStatus.Information = out_len;
+ break;
+ } // end case EnumAdapters:
+
+ case BRIOldMethod:
+ {
+ PDIGI_OLD_METHOD OldMethodInfo;
+
+ OldMethodInfo = (PDIGI_OLD_METHOD)GET_PAYLOAD(Atlas);
+
+ //
+ // We decapsulate the Atlas stuff and feed through the
+ // old method of getting this information.
+ //
+ if( (stat = io_execute( &(OldMethodInfo->ioCmd),
+ irp )) == IO_E_PENDING )
+ /* event added pend irp */
+ return (STATUS_PENDING);
+ else
+ {
+ irp->IoStatus.Information = out_len;
+ return(STATUS_SUCCESS);
+ }
+
+ break;
+ }
+ }
+
+ break;
+
+ }
+ }
+
+}
+
+
+/* execute an io command */
+INT
+io_execute(IO_CMD *cmd, VOID *Irp_1)
+{
+ IRP *Irp = (IRP*)Irp_1;
+
+ D_LOG(D_ENTRY, ("io_execute: entry, cmd: 0x%lx\n", cmd));
+
+ /* check signature & version */
+ if ( cmd->sig != IO_CMD_SIG )
+ return(IO_E_BADSIG);
+ if ( (cmd->ver_major != IO_VER_MAJOR) ||
+ (cmd->ver_minor != IO_VER_MINOR) )
+ return(IO_E_BADVER);
+
+ D_LOG(D_ALWAYS, ("io_execute: opcode: 0x%x, cm: 0x%lx, idd: 0x%lx\n", \
+ cmd->opcode, cmd->cm, cmd->idd));
+ D_LOG(D_ALWAYS, ("io_execute: args: 0x%x 0x%x 0x%x 0x%x\n", \
+ cmd->arg[0], cmd->arg[1], cmd->arg[2], cmd->arg[3]));
+
+
+ /* clear status, assume success */
+ cmd->status = IO_E_SUCC;
+
+ /* branch on opcode */
+ switch ( cmd->opcode )
+ {
+
+ case IO_CMD_ENUM_ADAPTERS :
+ cmd->status = IoEnumAdapter(cmd);
+ break;
+
+ case IO_CMD_ENUM_CM:
+ cmd->status = IoEnumCm(cmd);
+ break;
+
+ case IO_CMD_ENUM_IDD :
+ cmd->status = IoEnumIdd(cmd);
+ break;
+
+ case IO_CMD_TRC_RESET :
+ cmd->status = trc_control(cmd->idd,
+ TRC_OP_RESET, (ULONG)cmd->idd);
+ break;
+
+ case IO_CMD_TRC_STOP :
+ cmd->status = trc_control(cmd->idd,
+ TRC_OP_STOP, (ULONG)cmd->idd);
+ break;
+
+ case IO_CMD_TRC_START :
+ cmd->status = trc_control(cmd->idd,
+ TRC_OP_START, (ULONG)cmd->idd);
+ break;
+
+ case IO_CMD_TRC_SET_FILT :
+ cmd->status = trc_control(cmd->idd,
+ TRC_OP_SET_FILTER, cmd->arg[0]);
+ break;
+
+ case IO_CMD_IDD_RESET_AREA :
+ cmd->status = idd_reset_area(cmd->idd);
+ break;
+
+ case IO_CMD_IDD_GET_AREA :
+ cmd->status = idd_get_area(cmd->idd, cmd->arg[0], NULL, NULL);
+ break;
+
+ case IO_CMD_IDD_GET_STAT :
+ cmd->status = idd_get_area_stat(cmd->idd, &cmd->val.IddStat);
+ break;
+
+ case IO_CMD_TRC_CREATE:
+ cmd->status = trc_control(cmd->idd,
+ TRC_OP_CREATE, cmd->arg[0]);
+ break;
+
+ case IO_CMD_TRC_DESTROY:
+ cmd->status = trc_control(cmd->idd,
+ TRC_OP_DESTROY, cmd->arg[0]);
+ break;
+
+ case IO_CMD_TRC_GET_STAT :
+ cmd->status = trc_get_status(idd_get_trc(cmd->idd),
+ &cmd->val.trc_stat);
+ break;
+
+ case IO_CMD_TRC_GET_ENT :
+ cmd->status = trc_get_entry(idd_get_trc(cmd->idd),
+ cmd->arg[0], &cmd->val.trc_ent);
+ break;
+
+ case IO_CMD_DBG_LEVEL :
+ DigiDebugLevel = (INT)(cmd->arg[0]);
+ break;
+
+ case IO_CMD_DO_IDP_CMD:
+ DbgPrint("DoIdpCmd: Cmd: 0x%x\n", cmd->arg[0]);
+ if( cmd->idd && (( ((IDD*)cmd->idd)->btype != IDD_BT_DATAFIREU) &&
+ ( ((IDD*)cmd->idd)->btype != IDD_BT_DATAFIREST) &&
+ ( ((IDD*)cmd->idd)->btype != IDD_BT_DATAFIRE4ST)) )
+ {
+ switch (cmd->arg[0])
+ {
+ case GET_IDP_IO_VALUE:
+ cmd->val.IdpRaw.uc = IdpGetUByteIO(cmd->idd,
+ cmd->val.IdpRaw.us);
+ cmd->status = IO_E_SUCC;
+ break;
+
+
+ case GET_IDP_BUFFER:
+ IdpGetBuffer(cmd->idd,
+ cmd->val.IdpRaw.Bank,
+ cmd->val.IdpRaw.Page,
+ cmd->val.IdpRaw.Address,
+ cmd->val.IdpRaw.Length,
+ cmd->val.IdpRaw.Buffer);
+
+ cmd->status = IO_E_SUCC;
+ break;
+
+ case SET_IDP_IO_VALUE:
+ IdpPutUByteIO(cmd->idd,
+ (USHORT)cmd->val.IdpRaw.Address,
+ cmd->val.IdpRaw.uc);
+ cmd->status = IO_E_SUCC;
+ break;
+
+ case SET_IDP_BUFFER:
+ IdpPutBuffer(cmd->idd,
+ cmd->val.IdpRaw.Bank,
+ cmd->val.IdpRaw.Page,
+ cmd->val.IdpRaw.Address,
+ cmd->val.IdpRaw.Length,
+ cmd->val.IdpRaw.Buffer);
+
+ cmd->status = IO_E_SUCC;
+ break;
+
+ default:
+ cmd->status = IO_E_BADCMD;
+ break;
+ }
+ }
+ else
+ cmd->status = IO_E_BADIDD;
+ break;
+
+ case IO_CMD_DO_ADP_CMD:
+ if( cmd->idd && (( ((IDD*)cmd->idd)->btype == IDD_BT_DATAFIREU) ||
+ ( ((IDD*)cmd->idd)->btype == IDD_BT_DATAFIREST) ||
+ ( ((IDD*)cmd->idd)->btype == IDD_BT_DATAFIRE4ST)) )
+ {
+ switch (cmd->arg[0])
+ {
+ case GET_ADP_UCHAR:
+ cmd->val.AdpRaw.uc = AdpGetUByte(cmd->idd,
+ cmd->val.AdpRaw.Address);
+
+ cmd->status = IO_E_SUCC;
+ break;
+
+ case GET_ADP_USHORT:
+ cmd->val.AdpRaw.us = AdpGetUShort(cmd->idd,
+ cmd->val.AdpRaw.Address);
+
+ cmd->status = IO_E_SUCC;
+ break;
+
+ case GET_ADP_ULONG:
+ cmd->val.AdpRaw.ul = AdpGetULong(cmd->idd,
+ cmd->val.AdpRaw.Address);
+
+ cmd->status = IO_E_SUCC;
+ break;
+
+ case GET_ADP_BUFFER:
+ AdpGetBuffer(cmd->idd,
+ cmd->val.AdpRaw.Buffer,
+ cmd->val.AdpRaw.Address,
+ cmd->val.AdpRaw.Length
+ );
+
+ cmd->status = IO_E_SUCC;
+ break;
+
+ case SET_ADP_UCHAR:
+ AdpPutUByte(cmd->idd,
+ cmd->val.AdpRaw.Address,
+ cmd->val.AdpRaw.uc);
+
+ cmd->status = IO_E_SUCC;
+ break;
+
+ case SET_ADP_USHORT:
+ AdpPutUShort(cmd->idd,
+ cmd->val.AdpRaw.Address,
+ cmd->val.AdpRaw.us);
+
+ cmd->status = IO_E_SUCC;
+ break;
+
+ case SET_ADP_ULONG:
+ AdpPutULong(cmd->idd,
+ cmd->val.AdpRaw.Address,
+ cmd->val.AdpRaw.ul);
+
+ cmd->status = IO_E_SUCC;
+ break;
+
+ case SET_ADP_BUFFER:
+ AdpPutBuffer(cmd->idd,
+ cmd->val.AdpRaw.Address,
+ cmd->val.AdpRaw.Buffer,
+ cmd->val.AdpRaw.Length);
+
+ cmd->status = IO_E_SUCC;
+ break;
+
+ default:
+ cmd->status = IO_E_BADCMD;
+ break;
+ }
+ }
+ else
+ cmd->status = IO_E_BADIDD;
+
+ break;
+
+ default :
+ cmd->status = IO_E_BADCMD;
+ break;
+ }
+
+ /* return status code */
+ return((INT)cmd->status);
+}
diff --git a/private/ntos/ndis/digi/pcimac/io_pub.h b/private/ntos/ndis/digi/pcimac/io_pub.h
new file mode 100644
index 000000000..080fef7fb
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/io_pub.h
@@ -0,0 +1,153 @@
+/*
+ * IO_PUB.H - include file for all IO modules
+ */
+
+#ifndef _IO_PUB_
+#define _IO_PUB_
+
+#define BRI_MAX_NAMELEN 64 /* anything that can be named < 64 chars */
+
+/* error codes */
+#define IO_E_SUCC 0 /* success */
+#define IO_E_NOROOM 1 /* no room in local tables */
+#define IO_E_NOSUCH 2 /* no such object */
+#define IO_E_BADSIG 3 /* bad signature */
+#define IO_E_BADVER 4 /* bad version */
+#define IO_E_BADCMD 5 /* bad command opcode */
+#define IO_E_BADIDD 6
+#define IO_E_BADCM 7
+#define IO_E_PENDING 0xFF /* command is pending */
+
+/* IO commands available listed here */
+#define IO_CMD_ENUM_ADAPTERS 0x100 /* enumerate network interfaces */
+#define IO_CMD_ENUM_IDD 0x101 /* enumerate isdn device drivers */
+#define IO_CMD_ENUM_CM 0x102 /* enumerate connection managers */
+
+#define IO_CMD_TRC_RESET 0x300 /* reset trace */
+#define IO_CMD_TRC_STOP 0x301 /* stop trace */
+#define IO_CMD_TRC_START 0x302 /* start trace */
+#define IO_CMD_TRC_SET_FILT 0x305 /* set filter for trace context */
+#define IO_CMD_TRC_GET_STAT 0x306 /* get status of trace context */
+#define IO_CMD_TRC_GET_ENT 0x307 /* get a trace entry */
+#define IO_CMD_TRC_CREATE 0x30A /* create trc object */
+#define IO_CMD_TRC_DESTROY 0x30B /* destroy trc object */
+
+#define IO_CMD_DO_ADP_CMD 0x400
+#define MAX_ADP_OPERATIONS 8
+#define GET_ADP_UCHAR 1
+#define GET_ADP_USHORT 2
+#define GET_ADP_ULONG 3
+#define GET_ADP_BUFFER 4
+#define SET_ADP_UCHAR 5
+#define SET_ADP_USHORT 6
+#define SET_ADP_ULONG 7
+#define SET_ADP_BUFFER 8
+
+#define IO_CMD_DO_IDP_CMD 0x401
+#define MAX_IDP_OPERATIONS 4
+#define GET_IDP_IO_VALUE 1
+#define GET_IDP_BUFFER 2
+#define SET_IDP_IO_VALUE 3
+#define SET_IDP_BUFFER 4
+
+#define IO_CMD_IDD_GET_AREA 0x900 /* get idd area */
+#define IO_CMD_IDD_RESET_AREA 0x901 /* reset idd area state */
+#define IO_CMD_IDD_GET_STAT 0x902 /* get area state */
+
+#define IO_CMD_DBG_LEVEL 0xF00 /* set debug level */
+
+typedef struct _ENUM_ADAPTERS_
+{
+ USHORT num;
+ ULONG BaseIO[MAX_ADAPTERS_IN_SYSTEM];
+ ULONG BaseMem[MAX_ADAPTERS_IN_SYSTEM];
+ ULONG BoardType[MAX_ADAPTERS_IN_SYSTEM];
+ CHAR Name[MAX_ADAPTERS_IN_SYSTEM][BRI_MAX_NAMELEN];
+ VOID *tbl[MAX_ADAPTERS_IN_SYSTEM];
+} ENUM_ADAPTERS, *PENUM_ADAPTERS;
+
+typedef struct ENUM_CM
+{
+ USHORT num;
+ CHAR name[MAX_CM_IN_SYSTEM][BRI_MAX_NAMELEN];
+ VOID *tbl[MAX_CM_IN_SYSTEM];
+} ENUM_CM, *PENUM_CM;
+
+typedef struct _ENUM_IDD_
+{
+ USHORT num;
+ VOID *tbl[MAX_IDD_IN_SYSTEM];
+ CHAR name[MAX_IDD_IN_SYSTEM][BRI_MAX_NAMELEN];
+} ENUM_IDD, *PENUM_IDD;
+
+typedef struct _DBG_LEVEL_
+{
+ INT cmplen;
+ CHAR filestr[9];
+} DBG_LEVEL, *PDBG_LEVEL;
+
+typedef struct _ADPRAW_
+{
+ UCHAR uc;
+ USHORT us;
+ ULONG ul;
+ ULONG Address;
+ USHORT Length;
+ UCHAR Buffer[ADP_RAM_SIZE];
+} ADPRAW, *PADPRAW;
+
+typedef struct _IDPRAW_
+{
+ UCHAR uc;
+ USHORT us;
+ ULONG ul;
+ USHORT Bank;
+ USHORT Page;
+ ULONG Address;
+ USHORT Length;
+ UCHAR Buffer[IDP_RAM_PAGE_SIZE];
+} IDPRAW, *PIDPRAW;
+
+/* master descriptor structure for ioctl commands to IO module */
+typedef struct
+{
+ ULONG sig; /* identifing signature */
+#define IO_CMD_SIG 0x321B71B7
+
+ USHORT ver_major, ver_minor; /* interface version (curr: 0.1) */
+#define IO_VER_MAJOR 0
+#define IO_VER_MINOR 1
+
+ ULONG opcode; /* command opcode, IO_CMD_* */
+
+ ULONG status; /* completion status, ok: 0 */
+
+ VOID *cm; /* related connection object */
+ VOID *idd; /* related idd */
+ ULONG arg[4]; /* 4 general purpose args */
+
+ union /* opcode specific data */
+ {
+ ENUM_ADAPTERS enum_adapters; /* IO_CMD_ENUM_ADAPTERS */
+
+ ENUM_CM enum_cm; /* IO_CMD_ENUM_MTL */
+
+ ENUM_IDD enum_idd; /* IO_CMD_ENUM_IDD */
+
+ DBG_LEVEL dbg_level;
+
+ CM_STATUS cm_stat; /* IO_CMD_CM_GET_STAT */
+
+ TRC_STATUS trc_stat; /* IO_CMD_TRC_GET_STAT */
+ TRC_ENTRY trc_ent; /* IO_CMD_TRC_GET_ENT */
+ IDD_AREA IddStat; // IO_CMD_GET_IDD_STAT
+
+ ADPRAW AdpRaw;
+
+ IDPRAW IdpRaw;
+ } val;
+
+} IO_CMD;
+
+#endif /* _IO_PUB_ */
+
diff --git a/private/ntos/ndis/digi/pcimac/lanoid.c b/private/ntos/ndis/digi/pcimac/lanoid.c
new file mode 100644
index 000000000..33b3eb476
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/lanoid.c
@@ -0,0 +1,240 @@
+#include <ndis.h>
+#include <ndiswan.h>
+#include <stdio.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <adapter.h>
+#include <util.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+#include <res.h>
+#include <trc.h>
+#include <io.h>
+
+
+#define PCIMAC_MAJOR_VERSION 2
+#define PCIMAC_MINOR_VERSION 0
+
+//
+// Lan OID's
+//
+static UINT SupportedLanOids[] =
+ {
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ OID_802_3_RCV_ERROR_ALIGNMENT,
+ OID_802_3_XMIT_ONE_COLLISION,
+ OID_802_3_XMIT_MORE_COLLISIONS
+ };
+
+#define MAX_SUPPORTED_LAN_OIDS 31
+
+
+
+
+NDIS_STATUS
+LanOidProc(
+ NDIS_HANDLE AdapterContext,
+ NDIS_OID Oid,
+ PVOID InfoBuffer,
+ ULONG InfoBufferLen,
+ PULONG BytesReadWritten,
+ PULONG BytesNeeded
+ )
+{
+ ADAPTER *Adapter = (ADAPTER*)AdapterContext;
+ CM *cm = (CM*)Adapter->CmTbl[0];
+ ULONG GenericULong;
+ USHORT GenericUShort;
+ UCHAR GenericArray[6];
+ UINT MoveBytes = sizeof(ULONG);
+ PVOID MoveSource = (PVOID)(&GenericULong);
+ UINT BytesLeft = InfoBufferLen;
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+ NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady;
+ NDIS_MEDIUM Medium = NdisMedium802_3;
+ ULONG OidType = 0;
+ ULONG Filter;
+
+ switch (Oid)
+ {
+ case OID_802_3_MULTICAST_LIST:
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ MoveBytes = BytesLeft;
+ OidType = 1;
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ MoveBytes = BytesLeft;
+ OidType = 1;
+ NdisMoveMemory(&Filter, InfoBuffer, 4);
+
+ if (Filter & (NDIS_PACKET_TYPE_SOURCE_ROUTING |
+ NDIS_PACKET_TYPE_SMT |
+ NDIS_PACKET_TYPE_MAC_FRAME |
+ NDIS_PACKET_TYPE_FUNCTIONAL |
+ NDIS_PACKET_TYPE_ALL_FUNCTIONAL |
+ NDIS_PACKET_TYPE_GROUP
+ ))
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+
+ case OID_GEN_MAC_OPTIONS:
+ GenericULong = (ULONG)(NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
+ NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
+ NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
+ NDIS_MAC_OPTION_NO_LOOPBACK);
+
+ break;
+
+ case OID_GEN_SUPPORTED_LIST:
+ MoveSource = (PVOID)(SupportedLanOids);
+ MoveBytes = sizeof(SupportedLanOids);
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+ MoveSource = (PVOID)(&HardwareStatus);
+ MoveBytes = sizeof(NDIS_HARDWARE_STATUS);
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+ MoveSource = (PVOID)(&Medium);
+ MoveBytes = sizeof(NDIS_MEDIUM);
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+ GenericULong = (ULONG)1514;
+ break;
+
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+ GenericULong = (ULONG)1500;
+ break;
+
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+ GenericULong = (ULONG)1514;
+ break;
+
+ case OID_GEN_LINK_SPEED:
+ GenericULong = (ULONG)12800;
+ break;
+
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+ GenericULong = (ULONG)(1514 * 16);
+ break;
+
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+ GenericULong = (ULONG)(1514 * 16);
+ break;
+
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+ GenericULong = (ULONG)256;
+ break;
+
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+ GenericULong = (ULONG)256;
+ break;
+
+ case OID_GEN_VENDOR_ID:
+ NdisMoveMemory((PVOID)&GenericULong,
+ cm->SrcAddr,
+ 3);
+
+ GenericULong &= 0xFFFFFF00;
+ GenericULong |= 0x01;
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+ MoveSource = (PVOID)"DigiBoard Pcimac ISDN Adapter.";
+ MoveBytes = strlen("DigiBoard Pcimac ISDN Adapter.");
+ break;
+
+ case OID_GEN_DRIVER_VERSION:
+ GenericUShort = ((USHORT)PCIMAC_MAJOR_VERSION << 8) |
+ PCIMAC_MINOR_VERSION;
+ MoveSource = (PVOID)(&GenericUShort);
+ MoveBytes = sizeof(USHORT);
+ break;
+
+ case OID_802_3_PERMANENT_ADDRESS:
+ NdisMoveMemory((PVOID)GenericArray,
+ cm->SrcAddr,
+ 6);
+ MoveSource = (PVOID)GenericArray;
+ MoveBytes = 6;
+ break;
+
+ case OID_802_3_CURRENT_ADDRESS:
+ NdisMoveMemory((PVOID)GenericArray,
+ cm->SrcAddr,
+ 6);
+ MoveSource = (PVOID)GenericArray;
+ MoveBytes = 6;
+ break;
+
+ case OID_GEN_XMIT_OK:
+ case OID_GEN_RCV_OK:
+ case OID_GEN_XMIT_ERROR:
+ case OID_GEN_RCV_ERROR:
+ case OID_GEN_RCV_NO_BUFFER:
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+ case OID_802_3_XMIT_ONE_COLLISION:
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+ GenericULong = (ULONG)0;
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+ GenericULong = (ULONG)16;
+ break;
+
+ default:
+ StatusToReturn = NDIS_STATUS_INVALID_OID;
+ break;
+ }
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS)
+ {
+ *BytesNeeded = 0;
+ if (MoveBytes > BytesLeft)
+ {
+ *BytesNeeded = MoveBytes;
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+ }
+ else if (OidType == 0)
+ {
+ NdisMoveMemory(InfoBuffer, MoveSource, MoveBytes);
+ (*BytesReadWritten) = MoveBytes;
+ }
+ }
+ return(StatusToReturn);
+}
+
+
diff --git a/private/ntos/ndis/digi/pcimac/makefile b/private/ntos/ndis/digi/pcimac/makefile
new file mode 100644
index 000000000..677d610db
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/digi/pcimac/mtl.h b/private/ntos/ndis/digi/pcimac/mtl.h
new file mode 100644
index 000000000..06d71919c
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/mtl.h
@@ -0,0 +1,306 @@
+/*
+ * MTL.H - include file for all MTL modules
+ */
+
+#ifndef _MTL_
+#define _MTL_
+
+/* some constants values */
+// The value for mtl_max_chan has to be <= the value for
+// cm_max_chan in cm_pub.h
+
+//
+// I set the MTU to a large enough value to allow multi-link,
+// bridging and any other future expansion to occur.
+//
+#define MTL_MAC_MTU 1600 /* mac size mtu, fixed */
+
+#define MTL_IDD_MTU 260 /* idd size mtu, default value */
+
+//
+// a guess at how much receive space we will need this is 1514 * 16 wich seems
+// like alot to me
+//
+#define MTL_RX_BUFS 16 /* # of recieve buffers, must be 2^n */
+
+//
+// max local tx descriptor buffers based on the maximum number of
+// wanpackets we told the wrapper it could send (mydefs.h MAX_WANPACKET_XMITS)
+//
+#define MTL_TX_BUFS 8 /* # of transmit buffers */
+
+//
+// max fragments per packet
+//
+#define MTL_MAX_FRAG 16
+
+//
+// index into buffer where destination ethernet address starts
+//
+#define DST_ADDR_INDEX 0
+
+//
+// index into buffer where source ethernet address starts
+//
+#define SRC_ADDR_INDEX 6
+
+//
+// index into buffer where length of buffer starts
+//
+#define PKT_LEN_INDEX 12
+
+/* mtl error codes */
+#define MTL_E_SUCC 0
+#define MTL_E_NOMEM 1
+#define MTL_E_NOTIMPL 2
+#define MTL_E_NOROOM 3
+#define MTL_E_NOSUCH 4
+
+//
+// local mtl defs
+//
+/* packet receive/transmit assembly/disassembly descriptor */
+typedef struct
+{
+ LIST_ENTRY link;
+ ULONG Queued;
+ ULONG QueueOverRun;
+ UCHAR seq; /* recorded sequence number */
+ UCHAR tot; /* total # of fragments (0 free) */
+ UCHAR num; /* # of fragments received/transmitted */
+ ULONG ttl; /* time to live, in seconds */
+ USHORT len; /* accumulated packet length */
+ struct _MTL *mtl; /* back pointer to mtl */
+ USHORT State; /* State of current large frame */
+ UCHAR* DataPtr; /* current data index into buffer */
+ USHORT MaxRxLength; /* max frame receive length */
+ ULONG MissCount; /* rx miss count */
+ PUCHAR buf;
+} MTL_AS;
+
+typedef struct
+{
+ UCHAR NextFree;
+ NDIS_SPIN_LOCK lock; /* access spinlock */
+ ULONG DKFReceiveError1;
+ ULONG DKFReceiveError2;
+ ULONG DKFReceiveError3;
+ ULONG DKFReceiveError4;
+ ULONG DKFReceiveError5;
+ ULONG PPPReceiveError1;
+ ULONG PPPReceiveError2;
+ ULONG PPPReceiveError3;
+ ULONG PPPReceiveError4;
+ ULONG PPPReceiveError5;
+ ULONG IndicateReceiveError1;
+ ULONG IndicateReceiveError2;
+ ULONG IndicateReceiveError3;
+ ULONG TimeOutReceiveError1;
+ MTL_AS as_tbl[MTL_RX_BUFS];
+ PUCHAR Data;
+}MTL_RX_TBL;
+
+typedef struct
+{
+ LIST_ENTRY head;
+ NDIS_SPIN_LOCK lock;
+} MTL_AS_FIFO;
+
+//
+// Fifo for storing wan packets before fragment processing
+//
+typedef struct
+{
+ LIST_ENTRY head; /* head pointer, head==NULL -> empty */
+ NDIS_SPIN_LOCK lock; /* access lock */
+ ULONG Count;
+ ULONG Max;
+} MTL_WANPACKET_FIFO;
+
+/* idd packet header */
+typedef struct
+{
+ UCHAR sig_tot; /* signature + total fragments */
+ UCHAR seq; /* packet sequence number */
+ USHORT ofs; /* offset of fragment data into packet */
+} MTL_HDR;
+
+//
+// this structure is used for data this is fragmented in the DKF format
+//
+typedef struct
+{
+ IDD_FRAG IddFrag[2]; /* two fragments (hdr+data) required */
+ MTL_HDR MtlHeader; /* header storage */
+} DKF_FRAG;
+
+/* trasmit fragement descriptor */
+//
+// The DKF_FRAG member must be kept at the begining of this structure
+// !!!!!!!!!!!!!! mtl_tx.c relies on this !!!!!!!!!!!!!!!
+//
+typedef struct
+{
+ DKF_FRAG DkfFrag; /* frament descriptor for idd poll_tx */
+ IDD_MSG frag_msg; /* fragments waiting to be sent vector */
+ VOID *frag_idd; /* idd accepting fragments */
+ USHORT frag_bchan; /* destination bchannels */
+ VOID *frag_arg; /* argument to completion function */
+ ULONG FragSent; /* flag to indicate if this frag has been xmitted */
+} MTL_TX_FRAG;
+
+/* trasmit packet descriptor */
+typedef struct
+{
+ LIST_ENTRY TxPacketQueue;
+ NDIS_SPIN_LOCK lock;
+ ULONG InUse; /* this entry is in use */
+ USHORT NumberOfFrags; /* # of fragments in frag_tbl */
+ USHORT NumberOfFragsSent; /* # of fragments already sent */
+ USHORT FragReferenceCount; /* refrence count */
+ UCHAR *frag_buf; /* pointer to real data buffer */
+ NDIS_WAN_PACKET *WanPacket; /* related user packet */
+ struct _MTL *mtl; /* back pointer to mtl */
+ MTL_TX_FRAG frag_tbl[MTL_MAX_FRAG]; /* fragment table (assembled) */
+} MTL_TX_PKT;
+
+/* trasmit packet control table */
+typedef struct
+{
+ LIST_ENTRY head;
+ NDIS_SPIN_LOCK lock; /* access lock */
+ ULONG seq; /* packet sequence number (for next) */
+ ULONG NextFree; /* next available packet */
+ MTL_TX_PKT TxPacketTbl[MTL_TX_BUFS]; /* packet table */
+} MTL_TX_TBL;
+
+/* a channel descriptor */
+typedef struct
+{
+ VOID *idd; /* related idd object */
+ USHORT bchan; /* related channel within idd, b1=0, b2=1 */
+ ULONG speed; /* channel speed in bps */
+ struct _MTL *mtl; /* mtl back pointer */
+} MTL_CHAN;
+
+/* channel table */
+typedef struct
+{
+ MTL_CHAN tbl[MAX_CHAN_PER_CONN]; /* table of channels */
+ USHORT num; /* # of entries used */
+ NDIS_SPIN_LOCK lock; /* access spinlock */
+} MTL_CHAN_TBL;
+
+/* an MTL object */
+typedef struct _MTL
+{
+ ADAPTER *Adapter; /* adapter that owns this mtl */
+
+ NDIS_HANDLE LinkHandle; /* handle from wrapper for this link */
+
+ //statistics
+ ULONG FramesXmitted;
+ ULONG FramesReceived;
+ ULONG BytesXmitted;
+ ULONG BytesReceived;
+
+ NDIS_SPIN_LOCK lock; /* access lock */
+
+ VOID (*rx_handler)(); /* mgr receiver handler routine */
+ VOID *rx_handler_arg; /* ... handler argument */
+
+ VOID (*tx_handler)(); /* mgr transmitter handler routine */
+ VOID *tx_handler_arg; /* ... handler argument */
+
+ USHORT idd_mtu; /* idd max frame size */
+ BOOL is_conn; /* is connected now? */
+
+ ULONG IddTxFrameType; /* 0/1 - PPP/DKF */
+ ULONG IddRxFrameType; /* 0/1 - PPP/DKF */
+
+ MTL_CHAN_TBL chan_tbl; /* the channel table */
+
+ //
+ // Receive table
+ //
+ MTL_RX_TBL rx_tbl;
+
+ //
+ // Receive Completion Fifo
+ //
+ MTL_AS_FIFO RxIndicationFifo;
+
+ //
+ // fifo of wan packets to be transmitted
+ //
+ MTL_WANPACKET_FIFO WanPacketFifo;
+
+ //
+ // transmit table
+ //
+ MTL_TX_TBL tx_tbl;
+
+ //
+ // flag to show
+ //
+ BOOL RecvCompleteScheduled;
+
+ //
+ // backpointer to connection object
+ //
+ VOID *cm;
+
+ SEMA tx_sema; /* transmit processing sema */
+
+ //
+ // wan wrapper information
+ //
+ ULONG MaxSendFrameSize;
+ ULONG MaxRecvFrameSize;
+ ULONG PreamblePadding;
+ ULONG PostamblePadding;
+ ULONG SendFramingBits;
+ ULONG RecvFramingBits;
+ ULONG SendCompressionBits;
+ ULONG RecvCompressionBits;
+
+} MTL;
+
+//
+// public mtl defs
+//
+/* MTL object operations */
+INT mtl_create(VOID** mtl_1, NDIS_HANDLE AdapterHandle);
+INT mtl_destroy(VOID* mtl_1);
+INT mtl_set_rx_handler(VOID* mtl_1, VOID (*handler)(), VOID* handler_arg);
+INT mtl_set_tx_handler(VOID* mtl_1, VOID (*handler)(), VOID* handler_arg);
+INT mtl_set_idd_mtu(VOID* mtl_1, USHORT idd_mtu);
+INT mtl_set_conn_state(VOID* mtl_1, USHORT NumberOfChannels, BOOL is_conn);
+INT mtl_get_conn_speed(VOID* mtl_1, ULONG *speed);
+INT mtl_get_mac_mtu(VOID* mtl_1, ULONG* mtu);
+VOID mtl_tx_packet(VOID* mtl_1, PNDIS_WAN_PACKET pkt);
+INT mtl_add_chan(VOID* mtl_1, VOID* idd, USHORT chan, ULONG speed, ULONG ConnectionType);
+INT mtl_del_chan(VOID* mtl_1, VOID* idd, USHORT chan);
+INT GetStatistics (VOID*, VOID*);
+INT ClearStatistics (VOID*);
+INT MtlSetFramingType (VOID*, ULONG);
+
+
+/* prototypes for internal functions */
+VOID mtl__rx_bchan_handler(MTL_CHAN* chan, USHORT bchan, ULONG RxFrameType, IDD_XMSG* xmsg);
+VOID IndicateRxToWrapper(MTL*);
+VOID mtl__tx_cmpl_handler(MTL_TX_PKT *pkt, USHORT bchan, IDD_MSG* msg);
+VOID mtl__rx_tick(MTL* mtl);
+VOID mtl__tx_tick(MTL* mtl);
+VOID MtlPollFunction(VOID* a1, ADAPTER *Adapter, VOID* a3, VOID* a4);
+VOID MtlRecvCompleteFunction(ADAPTER *Adapter);
+BOOLEAN IsRxIndicationFifoEmpty(MTL*);
+MTL_AS* GetAssemblyFromRxIndicationFifo(MTL*);
+VOID QueueDescriptorForRxIndication(MTL*, MTL_AS*);
+VOID MtlSendCompleteFunction(ADAPTER *Adapter);
+VOID IndicateTxCompletionToWrapper(MTL*);
+VOID MtlFlushWanPacketTxQueue(MTL*);
+VOID mtl__tx_packet(MTL*, NDIS_WAN_PACKET*);
+VOID TryToIndicateMtlReceives(ADAPTER *Adapter);
+
+#endif /* _MTL_ */
diff --git a/private/ntos/ndis/digi/pcimac/mtl_init.c b/private/ntos/ndis/digi/pcimac/mtl_init.c
new file mode 100644
index 000000000..1aa8158fd
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/mtl_init.c
@@ -0,0 +1,195 @@
+/*
+ * MTL_INIT.C - Media Translation Layer, initialization
+ */
+
+#include <ndis.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+
+#pragma NDIS_INIT_FUNCTION(mtl_create)
+
+/* create an mtl object */
+mtl_create(VOID **mtl_1, NDIS_HANDLE AdapterHandle)
+{
+ MTL **ret_mtl = (MTL**)mtl_1;
+ MTL *mtl;
+ INT n;
+ NDIS_PHYSICAL_ADDRESS pa = NDIS_PHYSICAL_ADDRESS_CONST(0xffffffff, 0xffffffff);
+
+ D_LOG(D_ENTRY, ("mtl_create: entry, ret_mtl: 0x%lx\n", ret_mtl));
+
+ //
+ // allocate memory for mtl object
+ //
+ NdisAllocateMemory((PVOID*)&mtl, sizeof(*mtl), 0, pa);
+ if ( !mtl )
+ {
+ D_LOG((DIGIMTL|DIGIINIT), ("mtl_create: memory allocate failed!\n"));
+ NdisWriteErrorLogEntry (AdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0);
+ return(MTL_E_NOMEM);
+ }
+ D_LOG((DIGIMTL|DIGIINIT), ("mtl_create: mtl: 0x%lx\n", mtl));
+ NdisZeroMemory(mtl, sizeof(MTL));
+
+ //
+ // allocate rx table
+ //
+ NdisAllocateMemory((PVOID*)&mtl->rx_tbl.Data, (MTL_RX_BUFS * MTL_MAC_MTU), 0, pa);
+ if ( !mtl->rx_tbl.Data )
+ {
+ D_LOG((DIGIMTL|DIGIINIT), ("mtl_create: RxData memory allocate failed!\n"));
+
+ NdisWriteErrorLogEntry (AdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0);
+
+ /* free memory */
+ NdisFreeMemory(mtl, sizeof(*mtl), 0);
+
+ return(MTL_E_NOMEM);
+ }
+ D_LOG((DIGIMTL|DIGIINIT), ("mtl_create: RxData: 0x%lx\n", mtl->rx_tbl.Data));
+ NdisZeroMemory(mtl->rx_tbl.Data, (MTL_RX_BUFS * MTL_MAC_MTU));
+
+ /* setup some simple fields */
+ mtl->idd_mtu = MTL_IDD_MTU;
+
+ /* allocate spinlock for mtl */
+ NdisAllocateSpinLock(&mtl->lock);
+
+ /* allocate spinlock for channel table */
+ NdisAllocateSpinLock(&mtl->chan_tbl.lock);
+
+ //
+ // create assembly descriptor pointers into rx table
+ //
+ for (n = 0; n < MTL_RX_BUFS; n++)
+ mtl->rx_tbl.as_tbl[n].buf = mtl->rx_tbl.Data + (n * MTL_MAC_MTU);
+
+ NdisAllocateSpinLock(&mtl->rx_tbl.lock);
+
+ //
+ // spinlock for RxIndicationFifo
+ //
+ NdisAllocateSpinLock(&mtl->RxIndicationFifo.lock);
+
+ //
+ // initialize assembly completion fifo
+ //
+ NdisAcquireSpinLock(&mtl->RxIndicationFifo.lock);
+
+ InitializeListHead(&mtl->RxIndicationFifo.head);
+
+ NdisReleaseSpinLock(&mtl->RxIndicationFifo.lock);
+
+ //
+ // tx packet table lock
+ //
+ NdisAllocateSpinLock(&mtl->tx_tbl.lock);
+
+ for (n = 0; n < MTL_TX_BUFS; n++)
+ {
+ MTL_TX_PKT *MtlTxPacket = &mtl->tx_tbl.TxPacketTbl[n];
+
+ NdisAllocateSpinLock(&MtlTxPacket->lock);
+ }
+
+ //
+ // initialize MtlTxPacket Queue
+ //
+ NdisAcquireSpinLock(&mtl->tx_tbl.lock);
+
+ InitializeListHead(&mtl->tx_tbl.head);
+
+ NdisReleaseSpinLock(&mtl->tx_tbl.lock);
+
+ //
+ // Tx WanPacket storage
+ //
+ NdisAllocateSpinLock(&mtl->WanPacketFifo.lock);
+
+ NdisAcquireSpinLock(&mtl->WanPacketFifo.lock);
+
+ InitializeListHead(&mtl->WanPacketFifo.head);
+
+ NdisReleaseSpinLock(&mtl->WanPacketFifo.lock);
+
+ //
+ // setup default wan link fields
+ //
+ mtl->MaxSendFrameSize = MTL_MAC_MTU;
+ mtl->MaxRecvFrameSize = MTL_MAC_MTU;
+ mtl->PreamblePadding = 14;
+ mtl->PostamblePadding = 0;
+ mtl->SendFramingBits = RAS_FRAMING |
+ PPP_FRAMING |
+ MEDIA_NRZ_ENCODING;
+ mtl->RecvFramingBits = RAS_FRAMING |
+ PPP_FRAMING |
+ MEDIA_NRZ_ENCODING;
+ mtl->SendCompressionBits = 0;
+ mtl->RecvCompressionBits = 0;
+
+ /* init sema */
+ sema_init(&mtl->tx_sema);
+
+ /* return success */
+ *ret_mtl = mtl;
+ D_LOG(D_EXIT, ("mtl_create: exit\n"));
+ return(MTL_E_SUCC);
+}
+
+/* destroy an mtl object */
+mtl_destroy(VOID* mtl_1)
+{
+ MTL *mtl = (MTL*)mtl_1;
+ INT n;
+
+ D_LOG(D_ENTRY, ("mtl_destroy: entry, mtl: 0x%lx\n", mtl));
+
+ /* allocate spinlock for mtl */
+ NdisFreeSpinLock(&mtl->lock);
+
+ /* allocate spinlock for channel table */
+ NdisFreeSpinLock(&mtl->chan_tbl.lock);
+
+ /* allocate spin locks for receive table */
+// for ( n = 0 ; n < MTL_RX_BUFS ; n++ )
+// NdisFreeSpinLock(&mtl->rx_tbl.as_tbl[n].lock);
+
+ NdisFreeSpinLock(&mtl->rx_tbl.lock);
+
+ /* allocate spin lock for trasmit table & fifo */
+ NdisFreeSpinLock(&mtl->tx_tbl.lock);
+
+ for (n = 0; n < MTL_TX_BUFS; n++)
+ {
+ MTL_TX_PKT *MtlTxPacket = &mtl->tx_tbl.TxPacketTbl[n];
+
+ NdisFreeSpinLock(&MtlTxPacket->lock);
+ }
+
+ NdisFreeSpinLock(&mtl->WanPacketFifo.lock);
+ NdisFreeSpinLock(&mtl->RxIndicationFifo.lock);
+
+ /* term sema */
+ sema_term(&mtl->tx_sema);
+
+ NdisFreeMemory(mtl->rx_tbl.Data, (MTL_RX_BUFS * MTL_MAC_MTU), 0);
+
+ /* free memory */
+ NdisFreeMemory(mtl, sizeof(*mtl), 0);
+
+ D_LOG(D_EXIT, ("mtl_destroy: exit\n"));
+ return(MTL_E_SUCC);
+}
diff --git a/private/ntos/ndis/digi/pcimac/mtl_rx.c b/private/ntos/ndis/digi/pcimac/mtl_rx.c
new file mode 100644
index 000000000..fdc591c55
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/mtl_rx.c
@@ -0,0 +1,840 @@
+/*
+ * MTL_RX.C - Receive side processing for MTL
+ */
+
+#include <ndis.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+
+/* main handler, called when data arrives at bchannels */
+VOID
+mtl__rx_bchan_handler
+ (
+ MTL_CHAN *chan,
+ USHORT bchan,
+ ULONG IddRxFrameType,
+ IDD_XMSG *msg
+ )
+{
+ MTL *mtl;
+ MTL_HDR hdr;
+ MTL_AS *as;
+ USHORT FragmentFlags, CopyLen;
+ MTL_RX_TBL *RxTable;
+ D_LOG(D_ENTRY, ("mtl__rx_bchan_handler: chan: 0x%lx, bchan: %d, msg: 0x%lx\n", chan, bchan, msg));
+
+ /* assigned mtl using back pointer */
+ mtl = chan->mtl;
+
+ //
+ // acquire the lock fot this mtl
+ //
+ NdisAcquireSpinLock(&mtl->lock);
+
+ /* if not connected, ignore */
+ if ( !mtl->is_conn )
+ {
+ D_LOG(DIGIMTL, ("mtl__rx_bchan_handler: packet on non connected mtl, ignored\n"));
+ goto exit_code;
+ }
+
+ RxTable = &mtl->rx_tbl;
+ D_LOG(D_ENTRY, ("mtl__rx_bchan_handler: mtl: 0x%lx, buflen: %d, bufptr: 0x%lx\n", \
+ mtl, msg->buflen, msg->bufptr));
+ //
+ // if we are in detect mode
+ //
+ if (!mtl->RecvFramingBits)
+ {
+ UCHAR DetectData[3];
+
+ /* extract header, check for fields */
+ IddGetDataFromAdapter(chan->idd,
+ (PUCHAR)&hdr,
+ (PUCHAR)msg->bufptr,
+ sizeof(MTL_HDR));
+
+ DigiDump( DIGIRXFRAGDATA, ("Recv Frag (detect):\n") );
+ DigiDumpData( DIGIRXFRAGDATA, (PUCHAR)&hdr, sizeof(MTL_HDR) );
+
+// NdisMoveMemory ((PUCHAR)&hdr, (PUCHAR)msg->bufptr, sizeof(MTL_HDR));
+
+ //
+ // this is used for inband signalling - ignore it
+ //
+ if (hdr.sig_tot == 0x50)
+ goto exit_code;
+
+ //
+ // if this is dkf we need offset of zero for detection to work
+ //
+ if ( ((hdr.sig_tot & 0xF0) == 0x50) && (hdr.ofs != 0) )
+ goto exit_code;
+
+ //
+ // extract some data from the frame
+ //
+ IddGetDataFromAdapter(chan->idd,
+ (PUCHAR)&DetectData,
+ (PUCHAR)&msg->bufptr[4],
+ 2);
+
+ DigiDump( DIGIRXFRAGDATA, ("Recv Frag (detect con't):\n") );
+ DigiDumpData( DIGIRXFRAGDATA, (PUCHAR)&DetectData, 2 );
+
+// NdisMoveMemory((PUCHAR)&DetectData, (PUCHAR)&msg->bufptr[4], 2);
+
+ D_LOG(DIGIMTL, ("mtl__rx_bchan_handler: hdr: 0x%x 0x%x 0x%x\n", hdr.sig_tot, \
+ hdr.seq, hdr.ofs));
+
+ D_LOG(DIGIMTL, ("mtl__rx_bchan_handler: DetectData: 0x%x 0x%x\n", DetectData[0], DetectData[1]));
+
+ if ( (IddRxFrameType & IDD_FRAME_PPP) ||
+ ((IddRxFrameType & IDD_FRAME_DKF) &&
+ ((DetectData[0] == 0xFF) && (DetectData[1] == 0x03))))
+ {
+ mtl->RecvFramingBits = PPP_FRAMING;
+ mtl->SendFramingBits = PPP_FRAMING;
+ RxTable->NextFree = 0;
+ }
+ else
+ {
+ mtl->RecvFramingBits = RAS_FRAMING;
+ mtl->SendFramingBits = RAS_FRAMING;
+ }
+
+ D_LOG(DIGIMTL, ("mtl__rx_bchan_handler: Deteced WrapperFrameType: 0x%x\n", mtl->RecvFramingBits));
+
+ //
+ // don't pass up detected frame for now
+ //
+ goto exit_code;
+ }
+
+ if (IddRxFrameType & IDD_FRAME_DKF)
+ {
+ D_LOG(DIGIMTL, ("mtl__rx_bchan_handler: Received IddFrameType: DKF\n"));
+
+ /* size of packet has to be atleast as size of header */
+ if ( msg->buflen < sizeof(hdr) )
+ {
+ D_LOG(DIGIMTL, ("mtl__rx_bchan_handler: packet size too small, ignored\n"));
+ RxTable->DKFReceiveError1++;
+ goto exit_code;
+ }
+
+ /* extract header, check for fields */
+ IddGetDataFromAdapter(chan->idd,
+ (PUCHAR)&hdr,
+ (PUCHAR)msg->bufptr,
+ sizeof(MTL_HDR));
+
+ DigiDump( DIGIRXFRAGDATA, ("Recv Frag (DKF hdr):\n") );
+ DigiDumpData( DIGIRXFRAGDATA, (PUCHAR)&hdr, sizeof(MTL_HDR) );
+
+ D_LOG(DIGIMTL, ("mtl__rx_bchan_handler: hdr: 0x%x 0x%x 0x%x\n", hdr.sig_tot, \
+ hdr.seq, hdr.ofs));
+
+ //
+ // if this is not our header of if this is an inband uus
+ // ignore it
+ //
+ if ( (hdr.sig_tot & 0xF0) != 0x50 || hdr.sig_tot == 0x50)
+ {
+ D_LOG(DIGIMTL, ("mtl__rx_bchan_handler: bad header signature, ignored\n"));
+ D_LOG(DIGIMTL, ("mtl__rx_bchan_handler: mtl: 0x%lx, [0]: 0x%x", mtl, hdr.sig_tot));
+ RxTable->DKFReceiveError2++;
+ goto exit_code;
+ }
+
+ if ( (hdr.ofs >= MTL_MAC_MTU) || ((hdr.ofs + msg->buflen - sizeof(hdr)) > MTL_MAC_MTU) )
+ {
+ D_LOG(DIGIMTL, ("mtl__rx_bchan_handler: bad offset/buflen, ignored\n"));
+ D_LOG(DIGIMTL, ("mtl: 0x%lx, Offset: %d, BufferLength: %d\n", mtl, hdr.ofs, msg->buflen));
+ RxTable->DKFReceiveError3++;
+ goto exit_code;
+ }
+
+ NdisAcquireSpinLock(&RxTable->lock);
+
+ /* build pointer to assembly descriptor & lock it */
+ as = RxTable->as_tbl + (hdr.seq % MTL_RX_BUFS);
+
+ //
+ // if this assembly pointer is not free (queued) then
+ // just drop this fragment
+ //
+ if (as->Queued)
+ {
+ D_LOG(DIGIMTL, ("DKFRx: AssemblyQueue Overrun! mtl: 0x%lx, as: 0x%lx, seq: %d\n", \
+ mtl, as, hdr.seq));
+
+ RxTable->DKFReceiveError4++;
+ as->QueueOverRun++;
+ NdisReleaseSpinLock(&RxTable->lock);
+ goto exit_code;
+ }
+
+ /* check for new slot */
+ if ( !as->tot )
+ {
+ new_slot:
+
+ /* new entry, fill-up */
+ as->seq = hdr.seq; /* record sequence number */
+ as->num = 1; /* just received 1'st fragment */
+ as->ttl = 1000; /* time to live init val */
+ as->len = msg->buflen - sizeof(hdr); /* record received length */
+ as->tot = hdr.sig_tot & 0x0F; /* record number of expected fragments */
+
+ /* copy received data into buffer */
+ copy_data:
+ IddGetDataFromAdapter(chan->idd,
+ (PUCHAR)as->buf + hdr.ofs,
+ (PUCHAR)msg->bufptr + sizeof(hdr),
+ (USHORT)(msg->buflen - sizeof(hdr)));
+ DigiDump( DIGIRXFRAGDATA, ("Recv Frag (DKF data):\n") );
+ DigiDumpData( DIGIRXFRAGDATA,
+ (PUCHAR)as->buf + hdr.ofs,
+ (msg->buflen - sizeof(hdr)) );
+
+// NdisMoveMemory (as->buf + hdr.ofs, msg->bufptr + sizeof(hdr), msg->buflen - sizeof(hdr));
+ }
+ else if ( as->seq == hdr.seq )
+ {
+ /* same_seq: */
+
+ /* same sequence number, accumulate */
+ as->num++;
+ as->len += (msg->buflen - sizeof(hdr));
+
+ goto copy_data;
+ }
+ else
+ {
+ /* bad_frag: */
+
+ /*
+ * if this case, an already taken slot is hit, but with a different
+ * sequence number. this indicates a wrap-around in as_tbl. prev
+ * entry is freed and then this fragment is recorded as first
+ */
+ D_LOG(DIGIMTL, ("DKFRx: Bad Fragment! mtl: 0x%lx, as: 0x%lx, as->seq: %d, seq: %d\n", \
+ mtl, as, as->seq, hdr.seq));
+
+ D_LOG(DIGIMTL, ("as->tot: %d, as->num: %d\n", as->tot, as->num));
+
+ RxTable->DKFReceiveError5++;
+ goto new_slot;
+ }
+
+ /* if all fragments recieved for packet, time to mail it up */
+ if ( as->tot == as->num )
+ {
+ D_LOG(DIGIMTL, ("mtl__rx_bchan_handler: pkt mailed up, buf: 0x%lx, len: 0x%x\n", \
+ as->buf, as->len));
+
+ QueueDescriptorForRxIndication(mtl, as);
+
+ //
+ // mark this guy as being queued
+ //
+ as->Queued = 1;
+ }
+
+ /* release assembly descriptor */
+ NdisReleaseSpinLock(&RxTable->lock);
+ }
+ else if (IddRxFrameType & IDD_FRAME_PPP)
+ {
+ D_LOG(DIGIMTL, ("mtl__rx_bchan_handler: Received IddFrameType: PPP\n"));
+
+ NdisAcquireSpinLock(&RxTable->lock);
+
+ /* build pointer to assembly descriptor & lock it */
+ as = RxTable->as_tbl + (RxTable->NextFree % MTL_RX_BUFS);
+
+ //
+ // if this assembly pointer is not free (queued) then
+ // just drop this fragment
+ //
+ if (as->Queued)
+ {
+ D_LOG(DIGIMTL, ("PPPRx: AssemblyQueue Overrun! mtl: 0x%lx, as: 0x%lx, NextFree: %d\n", \
+ mtl, as, RxTable->NextFree));
+
+ as->QueueOverRun++;
+
+ RxTable->PPPReceiveError1++;
+
+ NdisReleaseSpinLock(&RxTable->lock);
+
+ goto exit_code;
+ }
+
+ FragmentFlags = msg->FragmentFlags;
+
+ D_LOG(DIGIMTL, ("mtl__rx_bchan_handler: FragmentFlags: 0x%x, CurrentRxState: 0x%x\n", FragmentFlags, as->State));
+
+ switch (as->State)
+ {
+ case RX_MIDDLE:
+ if (FragmentFlags & H_RX_N_BEG)
+ break;
+
+ as->MissCount++;
+
+ //
+ // missed an end buffer
+ //
+ D_LOG(DIGIMTL, ("mtl__rx_bchan_handler: mtl: 0x%lx, Miss in State: %d, FragmentFlags: 0x%x, MissCount: %d\n", \
+ mtl, as->State, FragmentFlags, as->MissCount));
+
+ RxTable->PPPReceiveError2++;
+
+ goto clearbuffer;
+
+ break;
+
+ case RX_BEGIN:
+ case RX_END:
+ if (FragmentFlags & H_RX_N_BEG)
+ {
+ //
+ // missed a begining buffer
+ //
+ as->MissCount++;
+
+ D_LOG(DIGIMTL, ("mtl__rx_bchan_handler: mtl: 0x%lx, Miss in State: %d, FragmentFlags: 0x%x, MissCount: %d\n", \
+ mtl, as->State, FragmentFlags, as->MissCount));
+
+ RxTable->PPPReceiveError3++;
+
+ goto done;
+ }
+clearbuffer:
+ //
+ // clear rx buffer
+ //
+ NdisZeroMemory(as->buf, sizeof(as->buf));
+
+ //
+ // start data at begin of buffer
+ //
+ as->DataPtr = as->buf;
+
+ //
+ // new buffer
+ //
+ as->len = 0;
+
+ //
+ // set rx state
+ //
+ as->State = RX_MIDDLE;
+
+ //
+ // set time to live
+ //
+ as->ttl = 1000;
+
+ //
+ // there is always only one fragment with PPP
+ // maybe a big one but still only one
+ //
+ as->tot = 1;
+
+ break;
+
+ default:
+ D_LOG(DIGIMTL, ("Invalid PPP Rx State! mtl: 0x%lx, as: 0x%lx State: 0x%x\n", \
+ mtl, as, as->State));
+
+ as->State = RX_BEGIN;
+
+ as->tot = 0;
+
+ as->MissCount++;
+
+ goto done;
+
+ break;
+ }
+
+ //
+ // get the length to be copy
+ //
+ CopyLen = msg->buflen;
+
+
+ D_LOG(DIGIMTL, ("mtl__rx_bchan_handler: CopyLen: %d\n", CopyLen));
+
+ if (FragmentFlags & H_RX_N_END)
+ {
+ //
+ // if this is not the last buffer and length is 0
+ // we are done
+ //
+ if (CopyLen == 0)
+ goto done_copy;
+
+ }
+ else
+ {
+ //
+ // if CopyLen = 0 buffer only contains 2 CRC bytes
+ //
+ if (CopyLen == 0)
+ {
+ goto done_copy;
+ }
+
+ //
+ // buffer contains only 1 CRC byte
+ //
+ else if (CopyLen == (-1 & H_RX_LEN_MASK))
+ {
+ //
+ // previous buffer had a crc byte in it so remove it
+ //
+ as->len -= 1;
+ goto done_copy;
+ }
+
+ //
+ // buffer contains no crc or data bytes
+ //
+ else if (CopyLen == (-2 & H_RX_LEN_MASK))
+ {
+ //
+ // previous buffer had 2 crc bytes in it so remove them
+ //
+ as->len -= 2;
+ goto done_copy;
+ }
+
+ }
+
+ //
+ // if larger than max rx size throw away
+ //
+ if (CopyLen > IDP_MAX_RX_LEN)
+ {
+ //
+ // buffer to big so dump it
+ //
+ as->State = RX_BEGIN;
+
+ as->MissCount++;
+
+ RxTable->PPPReceiveError4++;
+
+ /* mark as free now */
+ as->tot = 0;
+
+ D_LOG(DIGIMTL, ("mtl__rx_bchan_handler: mtl: 0x%lx, RxToLarge: RxSize: %d, MissCount: %d\n", mtl, CopyLen, as->MissCount));
+ goto done;
+ }
+
+ as->len += CopyLen;
+
+ if (as->len > MTL_MAC_MTU)
+ {
+ //
+ // Frame is to big so dump it
+ //
+ as->State = RX_BEGIN;
+
+ RxTable->PPPReceiveError5++;
+
+ as->MissCount++;
+
+ /* mark as free now */
+ as->tot = 0;
+
+ D_LOG(DIGIMTL, ("mtl__rx_bchan_handler: AssembledRxToLarge: mtl: 0x%lx, AsRxSize: %d, MissCount: %d\n", mtl, as->len, as->MissCount));
+ goto done;
+ }
+
+ //
+ // copy the data to rx descriptor
+ //
+ IddGetDataFromAdapter(chan->idd,
+ (PUCHAR)as->DataPtr,
+ (PUCHAR)msg->bufptr,
+ CopyLen);
+ DigiDump( DIGIRXFRAGDATA, ("Recv Frag (PPP):\n") );
+ DigiDumpData( DIGIRXFRAGDATA,
+ (PUCHAR)as->DataPtr,
+ CopyLen );
+
+// NdisMoveMemory(as->DataPtr, msg->bufptr, CopyLen);
+
+ //
+ // update data ptr
+ //
+ as->DataPtr += CopyLen;
+
+
+done_copy:
+ if (!(FragmentFlags & H_RX_N_END))
+ {
+ //
+ // if this is the end of the frame indicate to wrapper
+ //
+ as->State = RX_END;
+
+ RxTable->NextFree++;
+
+ QueueDescriptorForRxIndication(mtl, as);
+
+ //
+ // mark this guy as being queued
+ //
+ as->Queued = 1;
+ }
+
+done:
+ /* release assembly descriptor */
+ NdisReleaseSpinLock(&RxTable->lock);
+ }
+ else
+ D_LOG(DIGIMTL, ("mtl__rx_bchan_handler: Received IddFrameType: ??????!!!!!!\n"));
+
+ //
+ // exit code
+ // release spinlock and return
+ //
+ exit_code:
+
+ NdisReleaseSpinLock(&mtl->lock);
+}
+
+VOID
+IndicateRxToWrapper(
+ MTL *mtl
+ )
+{
+ UCHAR *BufferPtr;
+ USHORT BufferLength = 0;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ ADAPTER *Adapter;
+ MTL_AS *as;
+ MTL_RX_TBL *RxTable;
+
+ NdisAcquireSpinLock(&mtl->lock);
+
+ Adapter = mtl->Adapter;
+ RxTable = &mtl->rx_tbl;
+
+ while (!IsRxIndicationFifoEmpty(mtl))
+ {
+ NdisAcquireSpinLock(&RxTable->lock);
+
+ //
+ // get the next completed rx assembly
+ //
+ as = GetAssemblyFromRxIndicationFifo(mtl);
+
+ if (!as)
+ {
+ D_LOG(DIGIMTL, ("IndicateRx: Got a NULL as from queue! mtl: 0x%lx\n", mtl));
+ RxTable->IndicateReceiveError1++;
+ NdisReleaseSpinLock(&RxTable->lock);
+ goto exit_code;
+ }
+
+
+ //
+ // if this is an old ras frame then we must strip off
+ // the mac header Dst[6] + Src[6] + Length[2]
+ //
+ if (mtl->RecvFramingBits & RAS_FRAMING)
+ {
+ //
+ // pass over the mac header - tommyd does not want to see this
+ //
+ BufferPtr = as->buf + 14;
+
+ //
+ // indicate with the size of the ethernet packet not the received size
+ // this takes care of the old driver that does padding on small frames
+ //
+ BufferLength = as->buf[12];
+ BufferLength = BufferLength << 8;
+ BufferLength += as->buf[13];
+ D_LOG(DIGIMTL, ("IndicateRxToWrapper: WrapperFrameType: RAS\n"));
+ D_LOG(DIGIMTL, ("IndicateRxToWrapper: BufPtr: 0x%lx, BufLen: %d\n", BufferPtr, BufferLength));
+ }
+ else if (mtl->RecvFramingBits & PPP_FRAMING)
+ {
+ //
+ // the received buffer is the data that needs to be inidcated
+ //
+ BufferPtr = as->buf;
+
+ //
+ // the received length is the length that needs to be indicated
+ //
+ BufferLength = as->len;
+ D_LOG(DIGIMTL, ("IndicateRxToWrapper: WrapperFrameType: PPP\n"));
+ D_LOG(DIGIMTL, ("IndicateRxToWrapper: BufPtr: 0x%lx, BufLen: %d\n", BufferPtr, BufferLength));
+ }
+ else
+ {
+ //
+ // unknown framing - what to do what to do
+ // throw it away
+ //
+ D_LOG(DIGIMTL, ("IndicateRxToWrapper: mtl: 0x%lx, Unknown WrapperFramming: 0x%x\n", mtl, mtl->RecvFramingBits));
+ RxTable->IndicateReceiveError2++;
+ as->tot = 0;
+ as->Queued = 0;
+ NdisReleaseSpinLock(&RxTable->lock);
+ goto exit_code;
+ }
+
+ if (BufferLength > MTL_MAC_MTU)
+ {
+ D_LOG(DIGIMTL, ("IndicateRxToWrapper: mtl: 0x%lx, ReceiveLength > MAX ALLOWED (1514): RxLength: %d\n", mtl, as->len));
+ RxTable->IndicateReceiveError3++;
+ as->tot = 0;
+ as->Queued = 0;
+ NdisReleaseSpinLock(&RxTable->lock);
+ goto exit_code;
+ }
+
+ //
+ // send frame up
+ //
+ if (mtl->LinkHandle)
+ {
+ /* release assembly descriptor */
+ NdisReleaseSpinLock(&RxTable->lock);
+
+ NdisReleaseSpinLock(&mtl->lock);
+
+ DigiDump( DIGIRXDATA, ("Indicating Recv Data:\n") );
+ DigiDumpData( DIGIRXDATA, BufferPtr, BufferLength );
+
+ NdisMWanIndicateReceive(&Status,
+ Adapter->Handle,
+ mtl->LinkHandle,
+ BufferPtr,
+ BufferLength);
+
+ NdisAcquireSpinLock(&mtl->lock);
+
+ NdisAcquireSpinLock(&RxTable->lock);
+
+ mtl->RecvCompleteScheduled = 1;
+ }
+
+
+ /* mark as free now */
+ as->tot = 0;
+
+ //
+ // mark this guy as being free
+ //
+ as->Queued = 0;
+
+ /* release assembly descriptor */
+ NdisReleaseSpinLock(&RxTable->lock);
+ }
+
+ //
+ // exit code
+ // release spinlock and return
+ //
+ exit_code:
+
+ NdisReleaseSpinLock(&mtl->lock);
+}
+
+//
+// this function checks all of the mtl's on this adapter to see if
+// the protocols need to be given a chance to do some work
+//
+VOID
+MtlRecvCompleteFunction(
+ ADAPTER *Adapter
+ )
+{
+ ULONG n;
+
+ for ( n = 0; n < MAX_MTL_PER_ADAPTER; n++)
+ {
+ MTL *mtl = Adapter->MtlTbl[n] ;
+
+ //
+ // if this is a valid mtl
+ //
+ if (mtl)
+ {
+ //
+ // get lock for this mtl
+ //
+ NdisAcquireSpinLock(&mtl->lock);
+
+ //
+ // is a receive complete scheduled on a valid link?
+ //
+ if (mtl->RecvCompleteScheduled && mtl->LinkHandle)
+ {
+ //
+ // release the lock
+ //
+ NdisReleaseSpinLock(&mtl->lock);
+
+ NdisMWanIndicateReceiveComplete(Adapter->Handle,
+ mtl->LinkHandle);
+
+ //
+ // reaquire the lock
+ //
+ NdisAcquireSpinLock(&mtl->lock);
+
+ //
+ // clear the schedule flag
+ //
+ mtl->RecvCompleteScheduled = 0;
+ }
+
+ //
+ // release the lock
+ //
+ NdisReleaseSpinLock(&mtl->lock);
+ }
+ }
+}
+
+BOOLEAN
+IsRxIndicationFifoEmpty(
+ MTL *mtl)
+{
+ BOOLEAN Ret = 0;
+
+ NdisAcquireSpinLock(&mtl->RxIndicationFifo.lock);
+
+ Ret = IsListEmpty(&mtl->RxIndicationFifo.head);
+
+ NdisReleaseSpinLock(&mtl->RxIndicationFifo.lock);
+
+ return(Ret);
+
+}
+
+MTL_AS*
+GetAssemblyFromRxIndicationFifo(
+ MTL *mtl
+ )
+{
+ MTL_AS *as = NULL;
+
+ NdisAcquireSpinLock(&mtl->RxIndicationFifo.lock);
+
+ if (!IsListEmpty(&mtl->RxIndicationFifo.head))
+ as = (MTL_AS*)RemoveHeadList(&mtl->RxIndicationFifo.head);
+
+ NdisReleaseSpinLock(&mtl->RxIndicationFifo.lock);
+
+ return(as);
+}
+
+VOID
+QueueDescriptorForRxIndication(
+ MTL *mtl,
+ MTL_AS *as
+ )
+{
+ NdisAcquireSpinLock(&mtl->RxIndicationFifo.lock);
+
+ InsertTailList(&mtl->RxIndicationFifo.head, &as->link);
+
+ NdisReleaseSpinLock(&mtl->RxIndicationFifo.lock);
+}
+
+/* do timer tick processing for rx side */
+VOID
+mtl__rx_tick(MTL *mtl)
+{
+ INT n;
+ MTL_AS *as;
+ MTL_RX_TBL *RxTable = &mtl->rx_tbl;
+
+ //
+ // see if there are any receives to give to wrapper
+ //
+ IndicateRxToWrapper(mtl);
+
+ NdisAcquireSpinLock(&mtl->lock);
+
+ NdisAcquireSpinLock(&RxTable->lock);
+
+ /* scan assembly table */
+ for ( n = 0, as = RxTable->as_tbl ; n < MTL_RX_BUFS ; n++, as++ )
+ {
+ /* update ttl & check */
+ if ( as->tot && !(as->ttl -= 25) )
+ {
+ D_LOG(DIGIMTL, ("mtl__rx_bchan_handler: Pkt Kill ttl = 0: Slot: %d, mtl: 0x%lx\n", n, mtl));
+
+ D_LOG(DIGIMTL, ("AS Timeout! mtl: 0x%lx, as: 0x%lx, as->seq: 0x%x\n", mtl, as, as->seq));
+ D_LOG(DIGIMTL, ("as->tot: %d, as->num: %d", as->tot, as->num));
+
+ RxTable->TimeOutReceiveError1++;
+
+ //
+ // if this guy was queued for indication to wrapper
+ // and was not indicated within a second something is wrong
+ //
+ if (as->Queued)
+ {
+ D_LOG(DIGIMTL, ("AS Timeout while queued for indication! mtl: 0x%lx, as: 0x%lx\n", mtl, as));
+#if DBG
+ DbgBreakPoint();
+#endif
+ }
+
+ as->tot = 0;
+
+ //
+ // mark this guy as being free
+ //
+ as->Queued = 0;
+ }
+ }
+
+ NdisReleaseSpinLock(&RxTable->lock);
+
+ NdisReleaseSpinLock(&mtl->lock);
+}
+
+//
+// see if there are any receives to give to wrapper
+//
+VOID
+TryToIndicateMtlReceives(
+ ADAPTER *Adapter
+ )
+{
+ ULONG n;
+
+ for (n = 0; n < MAX_MTL_PER_ADAPTER; n++)
+ {
+ MTL *mtl = Adapter->MtlTbl[n];
+
+ if (mtl)
+ IndicateRxToWrapper(mtl);
+ }
+}
+
diff --git a/private/ntos/ndis/digi/pcimac/mtl_set.c b/private/ntos/ndis/digi/pcimac/mtl_set.c
new file mode 100644
index 000000000..66f0169d9
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/mtl_set.c
@@ -0,0 +1,228 @@
+/*
+ * MTL_SET.C - set routines for MTL object
+ */
+
+#include <ndis.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+#include <trc.h>
+#include <io.h>
+
+/* set rx handler */
+mtl_set_rx_handler (VOID *mtl_1, VOID (*handler)(), VOID *handler_arg)
+{
+ MTL *mtl = (MTL*)mtl_1;
+
+ D_LOG(D_ENTRY, ("mtl_set_rx_handler: entry, handler: 0x%lx, handler_arg: 0x%lx\n", \
+ handler, handler_arg));
+
+ /* get lock, set, release & return */
+ NdisAcquireSpinLock(&mtl->lock);
+ mtl->rx_handler = handler;
+ mtl->rx_handler_arg = handler_arg;
+ NdisReleaseSpinLock(&mtl->lock);
+ return(MTL_E_SUCC);
+}
+
+/* set tx handler */
+mtl_set_tx_handler(VOID *mtl_1, VOID (*handler)(), VOID *handler_arg)
+{
+ MTL *mtl = (MTL*)mtl_1;
+
+ D_LOG(D_ENTRY, ("mtl_set_tx_handler: entry, handler: 0x%lx, handler_arg: 0x%lx\n", \
+ handler, handler_arg));
+
+ /* get lock, set, release & return */
+ NdisAcquireSpinLock(&mtl->lock);
+ mtl->tx_handler = handler;
+ mtl->tx_handler_arg = handler_arg;
+ NdisReleaseSpinLock(&mtl->lock);
+ return(MTL_E_SUCC);
+}
+
+/* set idd mtu */
+mtl_set_idd_mtu(VOID *mtl_1, USHORT mtu)
+{
+ MTL *mtl = (MTL*)mtl_1;
+
+ D_LOG(D_ENTRY, ("mtl_set_idd_mtu: entry, mtu: 0x%x\n", mtu));
+
+ /* get lock, set, release & return */
+ NdisAcquireSpinLock(&mtl->lock);
+ mtl->idd_mtu = mtu;
+ NdisReleaseSpinLock(&mtl->lock);
+ return(MTL_E_SUCC);
+}
+
+/* set connection state */
+mtl_set_conn_state(
+ VOID *mtl_1,
+ USHORT NumberOfChannels,
+ BOOL is_conn)
+{
+ MTL *mtl = (MTL*)mtl_1;
+ ADAPTER *Adapter = mtl->Adapter;
+ NDIS_PHYSICAL_ADDRESS pa = NDIS_PHYSICAL_ADDRESS_CONST(0xffffffff, 0xffffffff);
+
+ D_LOG(D_ENTRY, ("mtl_set_conn_state: entry, is_conn: %d\n", is_conn));
+
+ /* get lock, set, release & return */
+ NdisAcquireSpinLock(&mtl->lock);
+
+ mtl->is_conn = is_conn;
+
+ //
+ // if we are being notified of a new connection we need to do some stuff
+ //
+ if (is_conn)
+ {
+ mtl->FramesXmitted = 0;
+ mtl->FramesReceived = 0;
+ mtl->BytesXmitted = 0;
+ mtl->BytesReceived = 0;
+ mtl->RecvFramingBits = 0;
+ mtl->tx_tbl.NextFree = 0;
+ mtl->rx_tbl.NextFree = 0;
+ }
+ NdisReleaseSpinLock(&mtl->lock);
+
+ return(MTL_E_SUCC);
+}
+
+/* get connection speed, add channels from chan_tbl */
+mtl_get_conn_speed(VOID *mtl_1, ULONG *speed)
+{
+ MTL *mtl = (MTL*)mtl_1;
+ USHORT n;
+
+ D_LOG(D_ENTRY, ("mtl_get_conn_speed: entry, mtk: 0x%lx, @speed: 0x%lx\n", mtl, speed));
+
+ /* get lock, count, release */
+ NdisAcquireSpinLock(&mtl->chan_tbl.lock);
+ for ( n = 0, *speed = 0 ; n < mtl->chan_tbl.num ; n++ )
+ *speed += mtl->chan_tbl.tbl[n].speed;
+ NdisReleaseSpinLock(&mtl->chan_tbl.lock);
+
+ D_LOG(D_EXIT, ("mtl_get_conn_speed: exit, speed: %ld bps\n", *speed));
+ return(MTL_E_SUCC);
+}
+
+/* get mac mtu on connection */
+mtl_get_mac_mtu(VOID *mtl_1, ULONG *mtu)
+{
+ MTL *mtl = (MTL*)mtl_1;
+
+ D_LOG(D_ENTRY, ("mtl_get_mac_mtu: entry, mtl: 0x%lx, @mtu: 0x%lx\n", mtl, mtu));
+
+ *mtu = MTL_MAC_MTU;
+
+ D_LOG(D_EXIT, ("mtl_get_mac_mtu: exit, mtu: %ld\n", *mtu));
+ return(MTL_E_SUCC);
+}
+
+/* add a channel to channel table */
+mtl_add_chan(VOID *mtl_1, VOID *idd, USHORT bchan, ULONG speed, ULONG ConnectionType)
+{
+ MTL *mtl = (MTL*)mtl_1;
+ INT ret = MTL_E_SUCC;
+ MTL_CHAN *chan;
+ INT n;
+
+ D_LOG(D_ENTRY, ("mtl_add_chan: entry, mtl: 0x%lx, idd: 0x%lx, bchan: %d, speed: 0x%x\n", \
+ mtl, idd, bchan, speed));
+
+ /* lock */
+ NdisAcquireSpinLock(&mtl->chan_tbl.lock);
+
+ /* check for space */
+ if ( mtl->chan_tbl.num >= MAX_CHAN_PER_CONN )
+ ret = MTL_E_NOROOM;
+ else
+ {
+ /* find free slot, MUST find! */
+ for ( chan = mtl->chan_tbl.tbl, n = 0 ; n < MAX_CHAN_PER_CONN ; n++, chan++ )
+ if ( !chan->idd )
+ break;
+ if ( n >= MAX_CHAN_PER_CONN )
+ {
+ D_LOG(DIGIMTL, ("mtl_add_chan: not free slot when num < MAX!\n"));
+ ret = MTL_E_NOROOM;
+ }
+ else
+ {
+ /* slot found, fill it */
+ mtl->chan_tbl.num++;
+
+ if (ConnectionType == CM_DKF)
+ {
+ mtl->IddTxFrameType = IDD_FRAME_DKF;
+ mtl->SendFramingBits = RAS_FRAMING;
+ }
+ else
+ {
+ mtl->IddTxFrameType = IDD_FRAME_PPP;
+ mtl->SendFramingBits = PPP_FRAMING;
+ }
+
+ chan->idd = idd;
+ chan->bchan = bchan;
+ chan->speed = speed;
+ chan->mtl = mtl;
+
+ /* add handler for slot */
+ idd_attach(idd, bchan, (VOID*)mtl__rx_bchan_handler, chan);
+ }
+ }
+
+ /* release & return */
+ NdisReleaseSpinLock(&mtl->chan_tbl.lock);
+ D_LOG(D_EXIT, ("mtl_add_chan: exit, ret: %d\n", ret));
+ return(ret);
+}
+
+/* delete a channel from channel table */
+mtl_del_chan(VOID* mtl_1, VOID* idd, USHORT bchan)
+{
+ MTL *mtl = (MTL*)mtl_1;
+ INT ret = MTL_E_SUCC;
+ MTL_CHAN *chan;
+ INT n;
+
+ D_LOG(D_ENTRY, ("mtl_del_chan: entry, mtl: 0x%lx, idd: 0x%lx, bchan: %d\n", \
+ mtl, idd, bchan));
+
+ /* lock */
+ NdisAcquireSpinLock(&mtl->chan_tbl.lock);
+
+ /* scan table for a match */
+ for ( chan = mtl->chan_tbl.tbl, n = 0 ; n < MAX_CHAN_PER_CONN ; n++, chan++ )
+ if ( (chan->idd == idd) && (chan->bchan == bchan) )
+ break;
+
+ /* check for error */
+ if ( n >= MAX_CHAN_PER_CONN )
+ {
+ D_LOG(DIGIMTL, ("mtl_del_chan: channel not found!\n"));
+ ret = MTL_E_NOSUCH;
+ }
+ else
+ {
+ /* found, delete handler & mark free it */
+ idd_detach(idd, bchan, (VOID*)mtl__rx_bchan_handler, chan);
+ chan->idd = NULL;
+ mtl->chan_tbl.num--;
+ }
+
+ /* release & return */
+ NdisReleaseSpinLock(&mtl->chan_tbl.lock);
+ D_LOG(D_EXIT, ("mtl_del_chan: exit, ret: %d\n", ret));
+ return(ret);
+}
diff --git a/private/ntos/ndis/digi/pcimac/mtl_tick.c b/private/ntos/ndis/digi/pcimac/mtl_tick.c
new file mode 100644
index 000000000..63b178fcf
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/mtl_tick.c
@@ -0,0 +1,47 @@
+/*
+ * MTL_TICK.C - tick (timer) processing for mtl
+ */
+
+#include <ndis.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+
+/* driver global vars */
+extern DRIVER_BLOCK Pcimac;
+
+//
+// mtl polling function
+//
+//
+/* tick process */
+VOID
+MtlPollFunction(VOID *a1, ADAPTER *Adapter, VOID *a3, VOID *a4)
+{
+ ULONG n;
+
+ for (n = 0; n < MAX_MTL_PER_ADAPTER; n++)
+ {
+ MTL *mtl = Adapter->MtlTbl[n];
+
+ if (mtl)
+ {
+ mtl__rx_tick(mtl);
+
+ mtl__tx_tick(mtl);
+
+ MtlRecvCompleteFunction(Adapter);
+
+ MtlSendCompleteFunction(Adapter);
+ }
+ }
+
+ NdisMSetTimer(&Adapter->MtlPollTimer, MTL_POLL_T);
+}
diff --git a/private/ntos/ndis/digi/pcimac/mtl_tx.c b/private/ntos/ndis/digi/pcimac/mtl_tx.c
new file mode 100644
index 000000000..2d3089f9d
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/mtl_tx.c
@@ -0,0 +1,1092 @@
+ /*
+ * MTL_TX.C - trasmit side processing for MTL
+ */
+
+#include <ndis.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+
+extern DRIVER_BLOCK Pcimac;
+
+/* local prototypes */
+BOOLEAN IsWanPacketTxFifoEmpty(MTL*);
+VOID AddToWanPacketTxFifo(MTL*, NDIS_WAN_PACKET*);
+MTL_TX_PKT* GetLocalTxDescriptor(MTL*);
+VOID FreeLocalTxDescriptor(MTL*, MTL_TX_PKT*);
+VOID TryToXmitFrags(MTL*);
+VOID SetTxDescriptorInWanPacket(MTL*,NDIS_WAN_PACKET*,MTL_TX_PKT*);
+VOID CheckWanPacketTimeToLive(MTL *mtl);
+VOID ReleaseTxDescriptor(MTL *mtl, MTL_TX_PKT *MtlTxPacket);
+
+#define IsWanPacketMarkedForCompletion(_WanPacket) \
+ ((_WanPacket)->MacReserved2 == (PVOID)TRUE)
+
+#define ClearTxDescriptorInWanPacket(_WanPacket) \
+ (_WanPacket)->MacReserved1 = (PVOID)NULL
+
+#define ClearReadyToCompleteInWanPacket(_WanPacket) \
+ (_WanPacket)->MacReserved2 = (PVOID)NULL
+
+#define SetTimeToLiveInWanPacket(_WanPacket, _TimeOut) \
+ (_WanPacket)->MacReserved3 = (PVOID)_TimeOut
+
+#define DecrementTimeToLiveForWanPacket(_WanPacket, _Decrement) \
+ (ULONG)((_WanPacket)->MacReserved3) -= (ULONG)_Decrement
+
+#define GetWanPacketTimeToLive(_WanPacket) \
+ (ULONG)((_WanPacket)->MacReserved3)
+
+#define GetTxDescriptorFromWanPacket(_WanPacket) \
+ ((MTL_TX_PKT*)((_WanPacket)->MacReserved1))
+
+#define MarkWanPacketForCompletion(_WanPacket) \
+ (_WanPacket)->MacReserved2 = (PVOID)TRUE
+
+#define SetTxDescriptorInWanPacket(_WanPacket, _TxDescriptor) \
+ (_WanPacket)->MacReserved1 = (PVOID)_TxDescriptor
+
+#define IncrementGlobalCount(_Counter) \
+{ \
+ NdisAcquireSpinLock(&Pcimac.lock); \
+ _Counter++; \
+ NdisReleaseSpinLock(&Pcimac.lock); \
+}
+
+ULONG GlobalSends = 0;
+ULONG GlobalSendsCompleted = 0;
+ULONG MtlSends1 = 0;
+ULONG MtlSends2 = 0;
+ULONG MtlSends3 = 0;
+ULONG MtlSends4 = 0;
+ULONG MtlSends5 = 0;
+
+/* trasmit side timer tick */
+VOID
+mtl__tx_tick(MTL *mtl)
+{
+ D_LOG(D_NEVER, ("mtl__tx_tick: entry, mtl: 0x%lx\n", mtl));
+
+ NdisAcquireSpinLock(&mtl->lock);
+
+ //
+ // try to transmit frags to the adapter
+ //
+ TryToXmitFrags(mtl);
+
+ //
+ // Check time to live on wan packet tx fifo
+ //
+ CheckWanPacketTimeToLive(mtl);
+
+ NdisReleaseSpinLock(&mtl->lock);
+
+}
+
+VOID
+MtlSendCompleteFunction(
+ ADAPTER *Adapter
+ )
+{
+ ULONG n;
+
+ for ( n = 0; n < MAX_MTL_PER_ADAPTER; n++)
+ {
+ MTL *mtl = Adapter->MtlTbl[n] ;
+
+ if (mtl && !IsWanPacketTxFifoEmpty(mtl))
+ {
+ //
+ // try to complete any wan packets ready for completion
+ //
+ IndicateTxCompletionToWrapper(mtl);
+ }
+ }
+}
+
+//
+// process a wan packet for transmition to idd level
+//
+// all packets will stay on one queue and the MacReserved fields will be used
+// to indicate what state the packet is in
+//
+// we will use the MacReserved fields provided in the NdisWanPacket as follows:
+//
+// MacReserved1 - Store a pointer to our local tx descriptor
+// MacReserved2 - This will be a boolean flag that will be set when this packet
+// can be completed (NdisMWanSendComplete)
+// MacReserved3 - This will be the time to live counter for the wanpacket.
+// If it is not completed we will go ahead and complete it.
+//
+// MacReserved4
+//
+VOID
+mtl__tx_packet(
+ MTL *mtl,
+ NDIS_WAN_PACKET *WanPacket
+ )
+{
+ UINT BytesLeftToTx, FragDataLength, FragNumber, FragSize;
+ UINT TotalPacketLength;
+ UCHAR *FragDataPtr;
+ MTL_TX_PKT *MtlTxPacket;
+ MTL_HDR MtlHeader;
+ USHORT TxFlags;
+ ADAPTER *Adapter = mtl->Adapter;
+ PUCHAR MyStartBuffer;
+ CM *cm = (CM*)mtl->cm;
+
+ D_LOG(D_ENTRY, ("mtl_tx_packet: entry, mtl: 0x%lx, WanPacket: 0x%lx\n", mtl, WanPacket));
+
+ NdisAcquireSpinLock(&mtl->lock);
+
+ IncrementGlobalCount(GlobalSends);
+
+ //
+ // queue up the wanpacket
+ //
+ AddToWanPacketTxFifo(mtl, WanPacket);
+
+ //
+ // get a local packet descriptor
+ //
+ MtlTxPacket = GetLocalTxDescriptor(mtl);
+
+ //
+ // make sure this is a valid descriptor
+ //
+ if (!MtlTxPacket)
+ {
+ D_LOG(DIGIMTL, ("mtl__tx_proc: Got a NULL Packet off of Local Descriptor Free List\n"));
+
+ //
+ // grab wan packet fifo lock
+ //
+ NdisAcquireSpinLock(&mtl->WanPacketFifo.lock);
+
+ MarkWanPacketForCompletion(WanPacket);
+
+ //
+ // release the wan packet fifo lock
+ //
+ NdisReleaseSpinLock(&mtl->WanPacketFifo.lock);
+
+ goto exit_code;
+ }
+
+ //
+ // grab wan packet fifo lock
+ //
+ NdisAcquireSpinLock(&mtl->WanPacketFifo.lock);
+
+ SetTxDescriptorInWanPacket(WanPacket, MtlTxPacket);
+
+ //
+ // release the wan packet fifo lock
+ //
+ NdisReleaseSpinLock(&mtl->WanPacketFifo.lock);
+
+ //
+ // grab the descriptor lock
+ //
+ NdisAcquireSpinLock(&MtlTxPacket->lock);
+
+ IncrementGlobalCount(MtlSends1);
+
+ /* if not connected, give up */
+ if ( !mtl->is_conn || cm->PPPToDKF)
+ {
+ D_LOG(DIGIMTL, ("mtl__tx_proc: packet on non-connected mtl, ignored\n"));
+
+ IncrementGlobalCount(MtlSends2);
+
+ goto xmit_error;
+ }
+
+ D_LOG(DIGIMTL, ("mtl__tx_proc: LocalPkt: 0x%lx, WanPkt: 0x%lx, WanPktLen: %d\n", MtlTxPacket, WanPacket, WanPacket->CurrentLength));
+
+ //
+ // get length of wan packet
+ //
+ TotalPacketLength = WanPacket->CurrentLength;
+
+ //
+ // my start buffer is WanPacket->CurrentBuffer - 14
+ //
+ MyStartBuffer = WanPacket->CurrentBuffer - 14;
+
+ if (mtl->SendFramingBits & RAS_FRAMING)
+ {
+ D_LOG(DIGIMTL, ("mtl__tx_proc: Transmit WrapperFrameType: RAS\n"));
+
+ // add dest eaddr
+ // StartBuffer + 0
+ //
+ NdisMoveMemory (MyStartBuffer + DST_ADDR_INDEX,
+ cm->DstAddr,
+ 6);
+
+ //
+ // add source eaddr
+ // StartBuffer + 6
+ //
+ NdisMoveMemory (MyStartBuffer + SRC_ADDR_INDEX,
+ cm->SrcAddr,
+ 6);
+
+ //
+ // add new length to buffer
+ // StartBuffer + 12
+ //
+ MyStartBuffer[12] = TotalPacketLength >> 8;
+ MyStartBuffer[13] = TotalPacketLength & 0xFF;
+
+ //
+ // data now begins at MyStartBuffer
+ //
+ MtlTxPacket->frag_buf = MyStartBuffer;
+
+ //
+ // new transmit length is a mac header larger
+ //
+ TotalPacketLength += 14;
+ }
+ else if (mtl->SendFramingBits & PPP_FRAMING)
+ {
+ D_LOG(DIGIMTL, ("mtl__tx_proc: Transmit WrapperFrameType: PPP\n"));
+
+ //
+ // data now begins at CurrentBuffer
+ //
+ MtlTxPacket->frag_buf = WanPacket->CurrentBuffer;
+ }
+ else
+ {
+ //
+ // unknown framing - what to do what to do
+ //
+ D_LOG(DIGIMTL, ("mtl__tx_proc: Packet sent with uknown framing, ignored\n"));
+
+ IncrementGlobalCount(MtlSends3);
+
+ goto xmit_error;
+ }
+
+
+ if (TotalPacketLength > MTL_MAC_MTU)
+ {
+ D_LOG(DIGIMTL, ("mtl__tx_proc: packet too long, TotalPacketLength: %d\n", TotalPacketLength));
+
+ IncrementGlobalCount(MtlSends4);
+
+ goto xmit_error;
+ }
+
+ /* step 4: calc number of fragments */
+ D_LOG(DIGIMTL, ("mtl__tx_proc: calc frag num, TotalPacketLength: %d\n", TotalPacketLength));
+
+ //
+ // Calculate the number of fragments per link given
+ // the size of data we can give the adapter.
+ //
+ MtlTxPacket->NumberOfFrags = (USHORT)(TotalPacketLength / mtl->chan_tbl.num / mtl->idd_mtu);
+
+ if ( TotalPacketLength != (USHORT)(MtlTxPacket->NumberOfFrags * mtl->chan_tbl.num * mtl->idd_mtu) )
+ MtlTxPacket->NumberOfFrags++;
+
+ MtlTxPacket->NumberOfFrags *= mtl->chan_tbl.num;
+
+ if ( MtlTxPacket->NumberOfFrags > MTL_MAX_FRAG )
+ {
+ D_LOG(DIGIMTL, ("mtl__tx_proc: pkt has too many frags, NumberOfFrags: %d\n", \
+ MtlTxPacket->NumberOfFrags));
+
+ IncrementGlobalCount(MtlSends5);
+
+ goto xmit_error;
+ }
+
+ D_LOG(DIGIMTL, ("mtl__tx_proc: NumberOfFrags: %d\n", MtlTxPacket->NumberOfFrags));
+
+ /* step 5: build generic header */
+ if (mtl->IddTxFrameType & IDD_FRAME_DKF)
+ {
+ MtlHeader.sig_tot = MtlTxPacket->NumberOfFrags | 0x50;
+ MtlHeader.seq = (UCHAR)(mtl->tx_tbl.seq++);
+ MtlHeader.ofs = 0;
+ }
+
+ /* step 6: build fragments */
+
+ //
+ // bytes left to send is initially the packet size
+ //
+ BytesLeftToTx = TotalPacketLength;
+
+ //
+ // FragDataPtr initially points to begining of frag buffer
+ //
+ FragDataPtr = MtlTxPacket->frag_buf;
+
+ //
+ // initial txflags are for a complete frame
+ //
+ TxFlags = 0;
+
+ for ( FragNumber = 0 ; FragNumber < MtlTxPacket->NumberOfFrags ; FragNumber++ )
+ {
+ MTL_TX_FRAG *FragPtr = &MtlTxPacket->frag_tbl[FragNumber];
+ IDD_MSG *FragMsg = &FragPtr->frag_msg;
+ MTL_CHAN *chan;
+
+ /* if it's first channel, establish next fragment size */
+ if ( !(FragNumber % mtl->chan_tbl.num) )
+ FragSize = MIN((BytesLeftToTx / mtl->chan_tbl.num), mtl->idd_mtu);
+
+ /* establish related channel */
+ chan = mtl->chan_tbl.tbl + (FragNumber % mtl->chan_tbl.num);
+
+ /* calc size of this fragment */
+ if ( FragNumber == (USHORT)(MtlTxPacket->NumberOfFrags - 1) )
+ FragDataLength = BytesLeftToTx;
+ else
+ FragDataLength = FragSize;
+
+ D_LOG(DIGIMTL, ("mtl__proc_tx: FragNumber: %d, FragDataPtr: 0x%lx, FragLength: %d\n", \
+ FragNumber, FragDataPtr, FragDataLength));
+
+ if (mtl->IddTxFrameType & IDD_FRAME_DKF)
+ {
+ DKF_FRAG *DkfFrag = &FragPtr->DkfFrag;
+ IDD_FRAG *IddFrag0 = &DkfFrag->IddFrag[0];
+ IDD_FRAG *IddFrag1 = &DkfFrag->IddFrag[1];
+
+ D_LOG(DIGIMTL, ("mtl__tx_proc: Transmit IddFrameType: DKF\n"));
+
+ //
+ // setup fragment descriptor for DKF data
+ //
+ /* setup fragment header */
+ DkfFrag->MtlHeader = MtlHeader;
+
+ /* set pointer to header */
+ IddFrag0->len = sizeof(MTL_HDR);
+ IddFrag0->ptr = (CHAR*)(&DkfFrag->MtlHeader);
+
+ /* set pointer to data */
+ IddFrag1->len = FragDataLength;
+ IddFrag1->ptr = FragDataPtr;
+
+ //
+ // fill idd message
+ //
+ FragMsg->buflen = sizeof(DKF_FRAG) | TX_FRAG_INDICATOR;
+
+ //
+ // this assumes that the DKF_FRAG structure is the first
+ // member of the MTL_TX_FRAG structure !!!!!
+ //
+ FragMsg->bufptr = (UCHAR*)FragPtr;
+ }
+ else
+ {
+ D_LOG(DIGIMTL, ("mtl__tx_proc: Transmit IddFrameType: PPP\n"));
+ //
+ // setup fragment descriptor for ppp frame
+ //
+
+ if (BytesLeftToTx <= mtl->idd_mtu )
+ {
+ //
+ // if all that is left can be sent this is the end
+ //
+ FragMsg->buflen = FragDataLength | TxFlags;
+ }
+ else
+ {
+ //
+ // if there is still more this is not end
+ //
+ FragMsg->buflen = FragDataLength | TxFlags | H_TX_N_END;
+ }
+
+ //
+ // setup data pointer
+ //
+ FragMsg->bufptr = (UCHAR*)FragDataPtr;
+ }
+
+ FragPtr->FragSent = 0;
+ FragPtr->frag_idd = chan->idd;
+ FragPtr->frag_bchan = chan->bchan;
+ FragPtr->frag_arg = MtlTxPacket;
+
+ /* update variables */
+ TxFlags = H_TX_N_BEG;
+ BytesLeftToTx -= FragDataLength;
+ FragDataPtr += FragDataLength;
+ MtlHeader.ofs += FragDataLength;
+ }
+ /* step 7: setup more fields */
+ MtlTxPacket->WanPacket = WanPacket;
+ MtlTxPacket->FragReferenceCount = MtlTxPacket->NumberOfFrags;
+ MtlTxPacket->mtl = mtl;
+ MtlTxPacket->NumberOfFragsSent = 0;
+
+ mtl->FramesXmitted++;
+ mtl->BytesXmitted += TotalPacketLength;
+
+ //
+ // release the lock befor xmitting
+ //
+ NdisReleaseSpinLock(&MtlTxPacket->lock);
+
+ //
+ // put this tx descriptor on list for transmition
+ //
+ NdisAcquireSpinLock(&mtl->tx_tbl.lock);
+
+ InsertTailList(&mtl->tx_tbl.head, &MtlTxPacket->TxPacketQueue);
+
+ NdisReleaseSpinLock(&mtl->tx_tbl.lock);
+
+ //
+ // Try to xmit some frags
+ //
+ TryToXmitFrags(mtl);
+
+ goto exit_code;
+
+ //
+ // error while setting up for transmition
+ //
+ xmit_error:
+
+ ClearTxDescriptorInWanPacket(WanPacket);
+
+ //
+ // free tx descriptor
+ //
+ FreeLocalTxDescriptor(mtl, MtlTxPacket);
+
+ //
+ // free descriptors lock
+ //
+ NdisReleaseSpinLock(&MtlTxPacket->lock);
+
+ //
+ // grab wan packet fifo lock
+ //
+ NdisAcquireSpinLock(&mtl->WanPacketFifo.lock);
+
+ //
+ // mark wan packet for completion
+ //
+ MarkWanPacketForCompletion(WanPacket);
+
+ //
+ // release the wan packet fifo lock
+ //
+ NdisReleaseSpinLock(&mtl->WanPacketFifo.lock);
+
+ //
+ // exit code
+ // release spinlock and return
+ //
+ exit_code:
+
+ NdisReleaseSpinLock(&mtl->lock);
+}
+
+//
+// Try to transmit fragments to idd
+//
+VOID
+TryToXmitFrags(
+ MTL *mtl
+ )
+{
+ LIST_ENTRY *MtlTxPacketQueueHead;
+ MTL_TX_TBL *MtlTxTbl = &mtl->tx_tbl;
+ MTL_TX_PKT *MtlTxPacket;
+ ULONG Ret = IDD_E_SUCC;
+ BOOLEAN WeCanXmit = 1;
+
+ //
+ // get tx table spin lock
+ //
+ NdisAcquireSpinLock(&MtlTxTbl->lock);
+
+ MtlTxPacketQueueHead = &MtlTxTbl->head;
+
+ //
+ // while we can still transmit and we are not at the end of the list
+ //
+ while (WeCanXmit && !IsListEmpty(MtlTxPacketQueueHead))
+ {
+ USHORT n, NumberOfFragsToSend;
+
+ MtlTxPacket = (MTL_TX_PKT*)MtlTxPacketQueueHead->Flink;
+
+ //
+ // get the number of frags we will try to send
+ //
+ NdisAcquireSpinLock(&MtlTxPacket->lock);
+
+ NumberOfFragsToSend = MtlTxPacket->NumberOfFrags;
+
+ NdisReleaseSpinLock(&MtlTxPacket->lock);
+
+ for (n = 0; n < NumberOfFragsToSend; n++)
+ {
+ MTL_TX_FRAG *FragToSend;
+
+ NdisAcquireSpinLock(&MtlTxPacket->lock);
+
+ FragToSend = &MtlTxPacket->frag_tbl[n];
+
+ NdisReleaseSpinLock(&MtlTxPacket->lock);
+
+ //
+ // if this frag has already been sent get the next one
+ //
+ if (FragToSend->FragSent)
+ continue;
+
+ D_LOG(DIGIMTL, ("TryToXmitFrag: mtl: 0x%x\n", mtl));
+ D_LOG(DIGIMTL, ("Next Packet To Xmit: MtlTxPacket: 0x%x\n", MtlTxPacket));
+ D_LOG(DIGIMTL, ("Xmitting Packet: MtlTxPacket: 0x%x\n", MtlTxPacket));
+ D_LOG(DIGIMTL, ("TryToXmitFrag: FragToSend: 0x%x\n", FragToSend));
+ D_LOG(DIGIMTL, ("TryToXmitFrag: Idd: 0x%x, Msg: 0x%x, Bchan: 0x%x, Arg: 0x%x\n", \
+ FragToSend->frag_idd, &FragToSend->frag_msg, \
+ FragToSend->frag_bchan, FragToSend->frag_arg));
+
+ //
+ // Something was ready to send
+ // release all locks before sending
+ //
+ NdisReleaseSpinLock(&MtlTxTbl->lock);
+
+ Ret = idd_send_msg(FragToSend->frag_idd,
+ &FragToSend->frag_msg,
+ FragToSend->frag_bchan,
+ (VOID*)mtl__tx_cmpl_handler,
+ FragToSend->frag_arg);
+
+ //
+ // acquire Tx Tbl fifo lock
+ // exit code expects the lock to be held
+ //
+ NdisAcquireSpinLock(&MtlTxTbl->lock);
+
+ if (Ret == IDD_E_SUCC)
+ {
+ //
+ // this means frag was sent to idd
+ // all locks will be released before next frag is sent
+ //
+
+ //
+ // acquire descriptor lock
+ // exit code expects the lock to be held
+ //
+ NdisAcquireSpinLock(&MtlTxPacket->lock);
+
+ //
+ // message was queued or sent!
+ //
+ MtlTxPacket->NumberOfFragsSent++;
+
+ FragToSend->FragSent++;
+
+ if (MtlTxPacket->NumberOfFragsSent == MtlTxPacket->NumberOfFrags)
+ {
+ //
+ // if things are working ok this guy will be on top
+ //
+ ASSERT((PVOID)MtlTxPacketQueueHead->Flink == (PVOID)MtlTxPacket);
+
+ //
+ // take a guy off of the to be transmitted list
+ //
+ RemoveEntryList(&MtlTxPacket->TxPacketQueue);
+ }
+
+ //
+ // release the lock for this descriptor
+ //
+ NdisReleaseSpinLock(&MtlTxPacket->lock);
+ }
+ else
+ {
+ //
+ // if this frag is not sent to idd
+ // then stop xmitting
+ //
+ WeCanXmit = 0;
+ }
+ }
+
+ }
+
+ //
+ // release the tx tbl fifo lock
+ //
+ NdisReleaseSpinLock(&MtlTxTbl->lock);
+}
+
+/* trasmit completion routine */
+VOID
+mtl__tx_cmpl_handler(
+ MTL_TX_PKT *MtlTxPacket,
+ USHORT port,
+ IDD_MSG *msg
+ )
+{
+ MTL *mtl;
+ PNDIS_WAN_PACKET WanPacket;
+
+ D_LOG(D_ENTRY, ("mtl__tx_cmpl_handler: entry, MtlTxPacket: 0x%lx, port: %d, msg: 0x%lx\n", \
+ MtlTxPacket, port, msg));
+
+ NdisAcquireSpinLock(&MtlTxPacket->lock);
+
+ mtl = MtlTxPacket->mtl;
+
+ //
+ // if this guy was set free from a disconnect while he was
+ // on the idd tx queue. Just throw him away!
+ // if this is not the last reference to the packet get the hell out!!!
+ //
+ if (!MtlTxPacket->InUse || --MtlTxPacket->FragReferenceCount )
+ {
+ NdisReleaseSpinLock(&MtlTxPacket->lock);
+ return;
+ }
+
+ D_LOG(DIGIMTL, ("mtl__tx_cmpl_handler: FragReferenceCount==0, mtl: 0x%lx\n", mtl));
+
+ //
+ // Get hold of PNDIS_WAN_PACKET associated with this descriptor
+ //
+ WanPacket = MtlTxPacket->WanPacket;
+
+ if (!WanPacket)
+ {
+ ASSERT(WanPacket);
+ NdisReleaseSpinLock(&MtlTxPacket->lock);
+ return;
+ }
+
+ ClearTxDescriptorInWanPacket(WanPacket);
+
+ //
+ // return local packet descriptor to free list
+ //
+ FreeLocalTxDescriptor(mtl, MtlTxPacket);
+
+ NdisReleaseSpinLock(&MtlTxPacket->lock);
+
+ //
+ // grab wan packet fifo lock
+ //
+ NdisAcquireSpinLock(&mtl->WanPacketFifo.lock);
+
+ //
+ // mark wan packet as being ready for completion
+ //
+ MarkWanPacketForCompletion(WanPacket);
+
+ //
+ // release the wan packet fifo lock
+ //
+ NdisReleaseSpinLock(&mtl->WanPacketFifo.lock);
+}
+
+//
+// get a local packet descriptor off of the free list
+//
+MTL_TX_PKT*
+GetLocalTxDescriptor(
+ MTL *mtl
+ )
+{
+ MTL_TX_PKT* FreePkt = NULL;
+ MTL_TX_TBL* TxTbl = &mtl->tx_tbl;
+
+ NdisAcquireSpinLock (&mtl->tx_tbl.lock);
+
+ //
+ // get next available freepkt
+ //
+ FreePkt = TxTbl->TxPacketTbl + (TxTbl->NextFree % MTL_TX_BUFS);
+
+ //
+ // if still in use we have a wrap
+ //
+ if (FreePkt->InUse)
+ {
+ ASSERT(!FreePkt->InUse);
+ NdisReleaseSpinLock (&mtl->tx_tbl.lock);
+ return(NULL);
+ }
+
+ //
+ // mark as being used
+ //
+ FreePkt->InUse = 1;
+
+ //
+ // bump pointer to next free
+ //
+ TxTbl->NextFree++;
+
+ NdisReleaseSpinLock (&mtl->tx_tbl.lock);
+
+ return(FreePkt);
+}
+
+//
+// return a local packet descriptor to free pool
+// assumes that the MtlTxPacket lock is held
+//
+VOID
+FreeLocalTxDescriptor(
+ MTL *mtl,
+ MTL_TX_PKT *MtlTxPacket
+ )
+{
+
+ ASSERT(MtlTxPacket->InUse);
+
+ MtlTxPacket->InUse = 0;
+
+ MtlTxPacket->WanPacket = NULL;
+}
+
+//
+// see if wan packet fifo is empty
+//
+BOOLEAN
+IsWanPacketTxFifoEmpty(
+ MTL *mtl
+ )
+{
+ BOOLEAN Result;
+
+ NdisAcquireSpinLock (&mtl->WanPacketFifo.lock);
+
+ Result = IsListEmpty(&mtl->WanPacketFifo.head);
+
+ NdisReleaseSpinLock (&mtl->WanPacketFifo.lock);
+
+ return(Result);
+}
+
+//
+// add a wan packet to the wan packet fifo
+//
+VOID
+AddToWanPacketTxFifo(
+ MTL *mtl,
+ NDIS_WAN_PACKET *WanPacket
+ )
+{
+ MTL_WANPACKET_FIFO *WanPacketFifo = &mtl->WanPacketFifo;
+ PLIST_ENTRY TempQueue;
+
+ D_LOG(D_ENTRY, ("AddToWanPacketTxFifo: mtl: 0x%x, head: 0x%x\n", mtl, WanPacketFifo->head));
+
+ NdisAcquireSpinLock (&WanPacketFifo->lock);
+
+ //
+ // We do a little consistency check and make sure we don't have
+ // have this wan packet allready on the queue.
+ //
+ TempQueue = &WanPacketFifo->head;
+
+#if DBG
+ while( TempQueue->Flink != &WanPacketFifo->head )
+ {
+ NDIS_WAN_PACKET *TempWanPacket;
+ TempWanPacket = CONTAINING_RECORD( TempQueue->Flink,
+ NDIS_WAN_PACKET,
+ WanPacketQueue );
+
+ ASSERT( TempWanPacket != NULL );
+
+ ASSERT( TempWanPacket != WanPacket );
+
+ TempQueue = TempQueue->Flink;
+ }
+#endif
+
+ ClearReadyToCompleteInWanPacket(WanPacket);
+
+ SetTimeToLiveInWanPacket(WanPacket, 5000);
+
+ ClearTxDescriptorInWanPacket(WanPacket);
+
+ InsertTailList(&WanPacketFifo->head, &WanPacket->WanPacketQueue);
+
+ WanPacketFifo->Count++;
+
+ if (WanPacketFifo->Count > WanPacketFifo->Max)
+ WanPacketFifo->Max = WanPacketFifo->Count;
+
+ NdisReleaseSpinLock (&WanPacketFifo->lock);
+}
+
+//
+// indicate xmit completion of wan packet to wrapper
+//
+VOID
+IndicateTxCompletionToWrapper(
+ MTL *mtl
+ )
+{
+ ADAPTER *Adapter = (ADAPTER*)mtl->Adapter;
+ NDIS_WAN_PACKET *WanPacket;
+ LIST_ENTRY *WanPacketFifoHead;
+ MTL_WANPACKET_FIFO *WanPacketFifo = &mtl->WanPacketFifo;
+
+ //
+ // acquire wan packet fifo lock
+ //
+ NdisAcquireSpinLock(&WanPacketFifo->lock);
+
+ //
+ // get head of wan packet fifo
+ //
+ WanPacketFifoHead = &WanPacketFifo->head;
+
+ //
+ // visit the first packet on the tx list
+ //
+ WanPacket = (NDIS_WAN_PACKET*)WanPacketFifoHead->Flink;
+
+ //
+ // if the list is not empty and this packet is ready to be completed
+ //
+ while (((PVOID)WanPacket != (PVOID)WanPacketFifoHead) &&
+ IsWanPacketMarkedForCompletion(WanPacket))
+ {
+
+ WanPacket = (PNDIS_WAN_PACKET)RemoveHeadList(&WanPacketFifo->head);
+
+ WanPacketFifo->Count--;
+
+ if (!WanPacket)
+ break;
+
+ IncrementGlobalCount(GlobalSendsCompleted);
+
+ ClearReadyToCompleteInWanPacket(WanPacket);
+
+ //
+ // release wan packet fifo lock
+ //
+ NdisReleaseSpinLock(&WanPacketFifo->lock);
+
+ NdisMWanSendComplete(Adapter->Handle, WanPacket, NDIS_STATUS_SUCCESS);
+
+ //
+ // acquire wan packet fifo lock
+ //
+ NdisAcquireSpinLock(&WanPacketFifo->lock);
+
+ //
+ // visit the new head of the list
+ //
+ WanPacket = (NDIS_WAN_PACKET*)WanPacketFifoHead->Flink;
+ }
+
+ //
+ // release wan packet fifo lock
+ //
+ NdisReleaseSpinLock(&WanPacketFifo->lock);
+}
+
+VOID
+MtlFlushWanPacketTxQueue(
+ MTL *mtl
+ )
+{
+ LIST_ENTRY *WanPacketFifoHead;
+ MTL_WANPACKET_FIFO *WanPacketFifo = &mtl->WanPacketFifo;
+ NDIS_WAN_PACKET *WanPacket;
+ MTL_TX_PKT *MtlTxPacket;
+
+ //
+ // acquire wan packet fifo lock
+ //
+ NdisAcquireSpinLock(&WanPacketFifo->lock);
+
+ //
+ // get head of wan packet fifo
+ //
+ WanPacketFifoHead = &WanPacketFifo->head;
+
+ //
+ // visit the first packet on the tx list
+ //
+ WanPacket = (NDIS_WAN_PACKET*)WanPacketFifoHead->Flink;
+
+ //
+ // if the wan packet queue is not empty
+ // we need to drain it!
+ //
+ while ((PVOID)WanPacket != (PVOID)WanPacketFifoHead)
+ {
+ //
+ // get the associated MtlTxPacket
+ //
+ if (MtlTxPacket = GetTxDescriptorFromWanPacket(WanPacket))
+ ReleaseTxDescriptor(mtl, MtlTxPacket);
+
+ //
+ // mark wan packet for completion
+ //
+ MarkWanPacketForCompletion(WanPacket);
+
+ //
+ // get the next packet on the list
+ //
+ WanPacket = (NDIS_WAN_PACKET*)(WanPacket->WanPacketQueue).Flink;
+ }
+
+ //
+ // release wan packet fifo lock
+ //
+ NdisReleaseSpinLock(&WanPacketFifo->lock);
+}
+
+//
+// walk through the WanPacketFifo and see if anyone has been sitting there
+// too long! This could happen if there was some kind of xmit failure to
+// the adapter.
+//
+VOID
+CheckWanPacketTimeToLive(
+ MTL *mtl
+ )
+{
+ LIST_ENTRY *WanPacketFifoHead;
+ MTL_WANPACKET_FIFO *WanPacketFifo = &mtl->WanPacketFifo;
+ NDIS_WAN_PACKET *WanPacket;
+// MTL_TX_PKT *MtlTxPacket;
+
+ //
+ // acquire wan packet fifo lock
+ //
+ NdisAcquireSpinLock(&WanPacketFifo->lock);
+
+ //
+ // get head of wan packet fifo
+ //
+ WanPacketFifoHead = &WanPacketFifo->head;
+
+ //
+ // visit the first packet on the tx list
+ //
+ WanPacket = (NDIS_WAN_PACKET*)WanPacketFifoHead->Flink;
+
+ //
+ // if the wan packet is not empty
+ //
+ while ((PVOID)WanPacket != (PVOID)WanPacketFifoHead)
+ {
+
+ //
+ // decrement the count by 25ms
+ //
+ DecrementTimeToLiveForWanPacket(WanPacket, 25);
+
+ //
+ // if the count has gone to zero this guy has
+ // been waiting for more then 1sec so complete him
+ //
+ if (!GetWanPacketTimeToLive(WanPacket))
+ {
+
+// if (IsWanPacketMarkedForCompletion(WanPacket))
+// DbgPrint("PCIMAC.SYS: WanPacket was already marked for completion!\n");
+//
+// //
+// // get the associated MtlTxPacket and free
+// //
+// if (MtlTxPacket = GetTxDescriptorFromWanPacket(WanPacket))
+// ReleaseTxDescriptor(mtl, MtlTxPacket);
+//
+// //
+// // mark the packet for completion
+// //
+// MarkWanPacketForCompletion(WanPacket);
+ }
+
+ //
+ // get the next packet on the list
+ //
+ WanPacket = (NDIS_WAN_PACKET*)(WanPacket->WanPacketQueue).Flink;
+ }
+
+ //
+ // release wan packet fifo lock
+ //
+ NdisReleaseSpinLock(&WanPacketFifo->lock);
+}
+
+VOID
+ReleaseTxDescriptor(
+ MTL *mtl,
+ MTL_TX_PKT *MtlTxPacket
+ )
+{
+ LIST_ENTRY *MtlTxPacketQueueHead;
+ MTL_TX_TBL *MtlTxTbl = &mtl->tx_tbl;
+ MTL_TX_PKT *NextMtlTxPacket;
+
+ //
+ // act like this local descriptor was sent
+ // keeps desriptor table pointers in line
+ //
+ NdisAcquireSpinLock(&MtlTxTbl->lock);
+
+ MtlTxPacketQueueHead = &MtlTxTbl->head;
+
+ //
+ // get the descriptor lock
+ //
+ NdisAcquireSpinLock(&MtlTxPacket->lock);
+
+ //
+ // visit the first packet on the list
+ //
+ NextMtlTxPacket = (MTL_TX_PKT*)MtlTxPacketQueueHead->Flink;
+
+ //
+ // break if the list has been traversed or if we find the packet
+ //
+ while (((PVOID)NextMtlTxPacket != MtlTxPacketQueueHead) && (NextMtlTxPacket != MtlTxPacket))
+ NextMtlTxPacket = (MTL_TX_PKT*)(NextMtlTxPacket->TxPacketQueue).Flink;
+
+ //
+ // if this descriptor is marked for transmition
+ // we should remove it from the tx descriptor list
+ //
+ if (NextMtlTxPacket == MtlTxPacket)
+ RemoveEntryList(&MtlTxPacket->TxPacketQueue);
+
+ FreeLocalTxDescriptor(mtl, MtlTxPacket);
+
+ NdisReleaseSpinLock(&MtlTxPacket->lock);
+
+ NdisReleaseSpinLock(&MtlTxTbl->lock);
+}
diff --git a/private/ntos/ndis/digi/pcimac/mydefs.h b/private/ntos/ndis/digi/pcimac/mydefs.h
new file mode 100644
index 000000000..aa36f8241
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/mydefs.h
@@ -0,0 +1,376 @@
+#ifndef _MYDEFS_
+#define _MYDEFS_
+
+//
+// maximum number of idd's per adapter
+// this is one pcimac/4 adapter
+//
+#define MAX_IDD_PER_ADAPTER 4
+
+//
+// maximum number of conection objects per adapter
+// this is one for each bchannel of a pcimac/4
+//
+#define MAX_CM_PER_ADAPTER 8
+
+// maximum number of mtl objects per adapter
+// this is one for each bchannel of a pcimac/4
+//
+#define MAX_MTL_PER_ADAPTER 8
+
+//
+// number of adapters in system
+//
+#define MAX_ADAPTERS_IN_SYSTEM 8
+
+//
+// maximum number of idd's in system
+// this is 5 pcimac/4 adapters
+//
+#define MAX_IDD_IN_SYSTEM 20
+
+//
+// maximum number of connection objects
+// in system
+// this is 5 pcimac/4 adpaters with a
+// connection object for each bchannel
+//
+#define MAX_CM_IN_SYSTEM 40
+
+//
+// maximum number of mtl objects
+// in system
+// this is 5 pcimac/4 adpaters with a
+// connection object for each bchannel
+//
+#define MAX_MTL_IN_SYSTEM 40
+
+//
+// maximum number of cm channel objects
+// in system
+// this is 5 pcimac/4 adpaters with a
+// connection object for each bchannel
+//
+#define MAX_CHAN_IN_SYSTEM 40
+
+//
+// maximum number of calls that can be made on
+// single line
+//
+//#define MAX_CALL_PER_LINE 2
+#define MAX_CALL_PER_LINE 1
+
+//
+// maximum number of channels supported by an idd
+//
+#define MAX_CHANNELS_PER_IDD 2
+
+//
+// maximum number of channels supported by an idd
+//
+#define MAX_LTERMS_PER_IDD 2
+
+#define MAX_WANPACKET_XMITS 3
+#define MAX_WANPACKET_BUFFERSIZE 1500
+#define MAX_WANPACKET_HEADERPADDING 14
+#define MAX_WANPACKET_TAILPADDING 0
+
+//
+// connection data type's
+//
+#define CM_PPP 0
+#define CM_DKF 1
+
+//
+// maximum number of channels allowed in a single connection
+//
+#define MAX_CHAN_PER_CONN 8
+
+//
+// defines for adapter boardtypes
+//
+#define IDD_BT_PCIMAC 0 /* - ISA, single channel */
+#define IDD_BT_PCIMAC4 1 /* - ISA, four channel */
+#define IDD_BT_MCIMAC 2 /* - MCA, single channel */
+#define IDD_BT_DATAFIREU 3 /* - ISA/U, single channel */
+#define IDD_BT_DATAFIREST 4 /* - ISA/ST, single channel */
+#define IDD_BT_DATAFIRE4ST 5 /* - ISA/ST, four channel */
+
+//
+// Send window size
+//
+#define ISDN_WINDOW_SIZE 10
+
+//
+// Ndis Version Info
+//
+#define NDIS_MAJOR_VER 0x03
+#define NDIS_MINOR_VER 0x00
+
+//
+// OID Switch
+//
+#define OID_GEN_INFO 0x00000000
+#define OID_8023_INFO 0x01000000
+#define OID_WAN_INFO 0x04000000
+#define OID_TAPI_INFO 0x07000000
+
+//
+// idd polling timer value
+//
+#define IDD_POLL_T 25 // 25ms polling frequency (msec)
+
+//
+// cm polling timer
+//
+#define CM_POLL_T 1000 /* 1 second timer */
+
+//
+// mtl polling timer
+//
+#define MTL_POLL_T 25 // 25 ms timer
+
+//
+// flag to indicate this is not a beginning buffer
+//
+#define H_TX_N_BEG 0x8000
+#define H_RX_N_BEG 0x8000
+
+//
+// flag to indicate this is not an ending buffer
+//
+#define H_TX_N_END 0x4000
+#define H_RX_N_END 0x4000
+
+//
+// flag to cause an immediate send of queued tx buffers
+//
+#define H_TX_FLUSH 0x2000
+
+//
+// masks off tx flags to leave the tx length
+//
+#define H_TX_LEN_MASK 0x01FF
+#define H_RX_LEN_MASK 0x01FF
+
+//
+// mask off length leaving rx flags
+//
+#define RX_FLAG_MASK 0xF000
+
+//
+// mask off length and fragment indicator leaving tx flags
+//
+#define TX_FLAG_MASK 0xE000
+
+//
+// indicator that this tx is actually a fragment
+//
+#define TX_FRAG_INDICATOR 0x1000
+
+//
+// states for receive ppp state machine
+//
+#define RX_BEGIN 0
+#define RX_MIDDLE 1
+#define RX_END 2
+
+#ifdef DBG
+//
+// states for tx ppp state machine
+//
+#define TX_BEGIN 0
+#define TX_MIDDLE 1
+#define TX_END 2
+#endif
+
+//
+// idp tx and rx lengths
+//
+#define IDP_MAX_TX_LEN 280
+#define IDP_MAX_RX_LEN 280
+
+//
+// Idd frame type defines
+//
+#define IDD_FRAME_PPP 1 /* raw hdlc frames */
+#define IDD_FRAME_DKF 2 /* dror encapsulated frames */
+#define IDD_FRAME_DONTCARE 4 /* No data can pass yet */
+#define IDD_FRAME_DETECT 8 /* detect bchannel framing */
+
+//
+// ADP Stuff
+//
+
+//
+// ADP Register Defines
+//
+#define ADP_REG_ID 0
+#define ADP_REG_CTRL 1
+#define ADP_REG_ADDR_LO 2
+#define ADP_REG_ADDR_MID 3
+#define ADP_REG_ADDR_HI 4
+#define ADP_REG_DATA 5
+#define ADP_REG_DATA_INC 6
+#define ADP_REG_RESERVE1 7 // Currently unused.
+#define ADP_REG_ADAPTER_CTRL 8
+
+//
+// ADP_REG_ID Bits
+//
+#define ADP_BT_ADP1 0xA1
+#define ADP_BT_ADP4 0xA4
+
+//
+// ADP_REG_CTRL Bits
+//
+#define ADP_RESET_BIT 0x80 // R/W 1 - Holds Adapter in reset
+#define ADP_PIRQ_BIT 0x40 // R 1 - Adapter to PC Interrupt Active
+ // W 1 - Clear Adapter to PC Interrupt
+#define ADP_AIRQ_BIT 0x20 // W 1 - PC to Adapter Interrupt Active
+ // R 0 - PC to Adapter Interrupt seen
+#define ADP_HLT_BIT 0x10 // R/W 1 - Holds Adapter in halt
+#define ADP_PIRQEN_BIT 0x08 // R/W 1 - Enables Adapter to PC Interrupt
+#define ADP_INT_SEL_BITS 0x07 // R/W Adapter to PC Interrupt select
+ // Code IRQ
+ // 000 0 (Disabled)
+ // 001 3
+ // 010 5
+ // 011 7
+ // 100 10
+ // 101 11
+ // 110 12
+ // 111 15
+
+//
+// ADP_REG_ADDR_LO Bits
+//
+// R/W Adapter Memory Address Bits A0..A7
+
+//
+// ADP_REG_ADDR_MID Bits
+//
+// R/W Adapter Memory Address Bits A8..A15
+
+//
+// ADP_REG_ADDR_HI Bits
+//
+// R/W Adapter Memory Address Bits A16..A23
+
+//
+// ADP_REG_DATA Bits
+//
+// R/W Adapter Memory Data Bits D0..D7
+// The 24 bit adapter memory address pointer remains constant
+// after each access to the data register.
+
+//
+// ADP_REG_DATA_INC Bits
+//
+// R/W Adapter Memory Data Bits D0..D7
+// The 24 bit adapter memory address pointer increments by one
+// after each access to the data register.
+
+//
+// ADP_REG_ADAPTER_CTRL Bits
+//
+// The Adapter Control Register is used by the host to determine IRQL
+// status and select a specific channel.
+//
+#define ADP_CSEL_BITS 0x03 // R/W Channel select bits
+ // 00 - select channel 0
+ // 01 - select channel 1
+ // 10 - select channel 2
+ // 11 - select channel 3
+#define ADP_ADAPTER_PIRQL 0xF0 // R replica of the IRQ lines from all
+ // four channel. They are provided
+ // for quick reference and can only
+ // be cleared by accessing the Channel
+ // Control Register.
+
+//
+// Maxium Adapter RAM Size
+//
+#define ADP_RAM_SIZE 0x40000L
+
+//
+// Offset to message to PC pending status windows
+//
+#define ADP_STS_WINDOW 0x500L
+
+//
+// Offset to PC to adapter command window
+//
+#define ADP_CMD_WINDOW 0x510L
+
+//
+// Offset to adapter enviornment window
+//
+#define ADP_ENV_WINDOW 0x540L
+
+//
+// Offset to adapter NVRAM window (copy in adapter memory)
+//
+#define ADP_NVRAM_WINDOW 0x940L
+
+//
+// some Adp bin file stuff
+//
+#define ADP_BIN_BLOCK_SIZE 256
+#define ADP_BIN_FORMAT 1
+
+//
+// Adp Status
+//
+typedef struct
+{
+ UCHAR ReceiveStatus; // 0
+ UCHAR Reserved1; // 1
+ UCHAR MajorVersion; // 2
+ UCHAR MinorVersion; // 3
+ ULONG HeartBeat; // 4
+ ULONG IdleCount; // 8
+ USHORT AbortReason; // 12
+ USHORT SpuriousInterrupt; // 14
+} ADP_STATUS;
+
+//
+// Adp bin file header
+//
+typedef struct
+{
+ USHORT Format;
+ USHORT BlockCount;
+ ULONG ImageSize;
+}ADP_BIN_HEADER;
+
+//
+// Adp bin file data block
+//
+typedef struct
+{
+ ULONG Address;
+ UCHAR Data[ADP_BIN_BLOCK_SIZE];
+}ADP_BIN_BLOCK;
+
+//
+// NVRAM stuff
+//
+#define ADP_NVRAM_MAX 64
+
+typedef struct
+{
+ USHORT NVRamImage[ADP_NVRAM_MAX];
+}ADP_NVRAM;
+
+//
+// IDP Stuff
+//
+
+#define IDP_STS_WINDOW 0x800
+#define IDP_CMD_WINDOW 0x810
+#define IDP_ENV_WINDOW 0x910
+#define IDP_RAM_PAGE_SIZE 0x4000
+
+#endif /* _MYTYPES_ */
+
diff --git a/private/ntos/ndis/digi/pcimac/mytypes.h b/private/ntos/ndis/digi/pcimac/mytypes.h
new file mode 100644
index 000000000..c54295e4f
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/mytypes.h
@@ -0,0 +1,39 @@
+#ifndef _MYTYPES_
+#define _MYTPYES_
+
+#ifndef BOOL
+typedef int BOOL;
+#endif
+
+#ifndef DWORD
+typedef ULONG DWORD;
+#endif
+
+#ifndef WORD
+typedef USHORT WORD;
+#endif
+
+#ifndef BYTE
+typedef UCHAR BYTE;
+#endif
+
+#ifndef NOMINMAX
+
+#ifndef MAX
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#endif /* NOMINMAX */
+
+#define MAKEWORD(a, b) ((WORD)(((BYTE)(a)) | ((WORD)((BYTE)(b))) << 8))
+#define MAKELONG(a, b) ((LONG)(((WORD)(a)) | ((DWORD)((WORD)(b))) << 16))
+#define LOWORD(l) ((WORD)(l))
+#define HIWORD(l) ((WORD)(((DWORD)(l) >> 16) & 0xFFFF))
+#define LOBYTE(w) ((BYTE)(w))
+#define HIBYTE(w) ((BYTE)(((WORD)(w) >> 8) & 0xFF))
+
+#endif /* _MYTYPES_ */
diff --git a/private/ntos/ndis/digi/pcimac/opcodes.h b/private/ntos/ndis/digi/pcimac/opcodes.h
new file mode 100644
index 000000000..3393f7a79
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/opcodes.h
@@ -0,0 +1,152 @@
+/*
+ * OPCODES.H - This file defines opcodes for messages of K_MSG type
+ *
+ * opcodes are assigned to a specific module ans are a 16 bit quantity.
+ * upper 8 bits are designated as the module name. lower 8 bits are a
+ * running index of the messages within a module.
+ */
+
+#ifndef _OPCODES_
+#define _OPCODES_
+
+/* a general purpose macro to extract module name off an opcode */
+#define MOD_NAME(_op) (_op & 0xFF00)
+
+/* module names are defined here */
+#define DCH_MOD 0x100
+#define LAP_MOD 0x200
+#define LAPD_MOD 0x300
+#define Q931_MOD 0x400
+#define MDL_MOD 0x500
+#define UART_MOD 0x600
+#define SER_MOD 0x700
+#define HDLC_MOD 0x800
+#define CMD_MOD 0x900
+
+/* the different modules are defined here */
+#define DCH(_op) (_op | DCH_MOD) /* d channel control */
+#define LAP(_op) (_op | LAP_MOD) /* lap sub-protocol */
+#define LAPD(_op) (_op | LAPD_MOD) /* lap for d channel */
+#define Q931(_op) (_op | Q931_MOD) /* q931 network prot */
+#define MDL(_op) (_op | MDL_MOD) /* mdl protocol */
+#define UART(_op) (_op | UART_MOD) /* uart device driver */
+#define SER(_op) (_op | SER_MOD) /* serial channel device*/
+#define HDLC(_op) (_op | HDLC_MOD) /* hdlc formatter */
+#define CMD(_op) (_op | CMD_MOD) /* command module */
+
+
+/* d channel messages */
+#define DCH_ACT_RQ DCH(1) /* ph activation rq */
+#define DCH_DEACT_RQ DCH(2) /* ph deactivation rq */
+#define DCH_BCH_EN DCH(3) /* enable bch tx/rx */
+#define DCH_BCH_DIS DCH(4) /* disable bch tx/rx */
+#define DCH_FST_IND DCH(5) /* Fx state chg ind */
+#define DCH_DATA_RQ DCH(6) /* request for data send */
+#define DCH_DATA_IND DCH(7) /* new data indication */
+#define DCH_ASSOC_RQ DCH(8) /* assoc tei/sapi with mbx */
+#define DCH_DEASSOC_RQ DCH(9) /* deassoc tei/sapi from mbx */
+#define DCH_ASSOC_CNF DCH(10) /* assoc has succ */
+#define DCH_ASSOC_ERR DCH(11) /* assoc has failed */
+
+/* lap sub-protocol messages */
+#define LAP_MAKE_RQ LAP(1) /* make a new DLC */
+#define LAP_KILL_RQ LAP(2) /* kill a DLC */
+#define LAP_EST_RQ LAP(3) /* establish multi frame rq */
+#define LAP_REL_RQ LAP(4) /* release multi frame request */
+#define LAP_DATA_RQ LAP(5) /* send data request (ack info) */
+#define LAP_UI_RQ LAP(6) /* send unack info request */
+#define LAP_XID_RQ LAP(7) /* send XID info */
+#define LAP_T200_EXP LAP(8) /* internal: t200 expired */
+#define LAP_T203_EXP LAP(9) /* internal: t203 expired */
+#define LAP_QUEUED_UP LAP(10) /* internal: I frame queued up */
+#define LAP_SET_BUSY LAP(11) /* internal: set own busy */
+#define LAP_RESET_BUSY LAP(12) /* internal: reset own busy */
+#define LAP_ACK_PEND LAP(13) /* internal: ack pending */
+#define LAP_EST_IND LAP(14) /* MF establish, other side init*/
+#define LAP_EST_CNF LAP(15) /* MF establish, this side init */
+#define LAP_REL_IND LAP(16) /* MF released, other side init */
+#define LAP_REL_CNF LAP(17) /* MF released, this side init */
+#define LAP_DATA_IND LAP(18) /* data received indication */
+#define LAP_UI_IND LAP(19) /* unack info received ind */
+#define LAP_XID_IND LAP(20) /* XID received indication */
+#define LAP_ERR_IND LAP(21) /* error indication */
+#define LAP_PH_DATA_RQ LAP(22) /* send data down ph */
+#define LAP_PH_DATA_IND LAP(23) /* received data from ph */
+
+/* lap for d channel messages */
+#define LAPD_EST_RQ LAPD(1) /* establish dlc request */
+#define LAPD_EST_CNF LAPD(2) /* establish confirmed */
+#define LAPD_REL_RQ LAPD(3) /* release dlc request */
+#define LAPD_REL_IND LAPD(4) /* dlc release by other side */
+#define LAPD_REL_CNF LAPD(5) /* release confirmed */
+#define LAPD_PROC_IND LAPD(6) /* proceeding indication */
+#define LAPD_DATA_RQ LAPD(7) /* request to send data */
+#define LAPD_DATA_IND LAPD(8) /* new data indication */
+#define LAPD_ERROR_IND LAPD(9) /* error indication */
+
+/* q931 messages */
+#define Q931_EST_RQ Q931(1) /* outgoing conn request */
+#define Q931_EST_IND Q931(2) /* incoming oconn indication */
+#define Q931_EST_CNF Q931(3) /* outgoing conn confirmed */
+#define Q931_EST_RSP Q931(4) /* response to incoming conn */
+#define Q931_REL_RQ Q931(5) /* teardown conn reqeust */
+#define Q931_REL_IND Q931(6) /* teardown indicated by remote */
+#define Q931_REL_CNF Q931(7) /* teardown confired */
+#define Q931_REL_RSP Q931(8) /* respose to teardown */
+#define Q931_DATA_RQ Q931(9) /* send data on a conneciton */
+#define Q931_DATA_IND Q931(10) /* new data received on conn */
+#define Q931_TIMER_EXP Q931(11) /* internal: timer expired */
+#define Q931_RESTART_RQ Q931(12) /* request for line restart */
+#define Q931_RESTART_IND Q931(13) /* indication that line restarts*/
+#define Q931_RESTART_CNF Q931(14) /* confirmation of line restart */
+#define Q931_ERROR_IND Q931(15) /* error indcation */
+#define Q931_CID_IND Q931(16) /* cid indication */
+#define Q931_STATE_IND Q931(17) /* state transition indication */
+#define Q931_ELEM_RQ Q931(18) /* requesting elem notification */
+#define Q931_ELEM_IND Q931(19) /* element indication */
+#define Q931_TSPID_EXP Q931(20) /* internal: spid timer expired */
+#define Q931_P_STATE_IND Q931(21) /* protocol state indications */
+#define Q931_CAN_TU10_RQ Q931(22) /* cancel U10 deadman timer */
+#define Q931_EST_IGNORE Q931(23) /* cm code will ignore this new call */
+
+/* managment data link (mdl) messages */
+#define MDL_ASSIGN_RQ MDL(1) /* assign tei request */
+#define MDL_ASSIGN_CNF MDL(2) /* assign confirmed */
+#define MDL_REMOVE_RQ MDL(3) /* remove tei request */
+#define MDL_REMOVE_IND MDL(4) /* remove tei indicated */
+#define MDL_REMOVE_CNF MDL(5) /* remove tei confirmed */
+#define MDL_ERROR_IND MDL(6) /* error in mdl procedure */
+#define MDL_T202_EXP MDL(7) /* internal: T202 expired */
+
+/* uart device driver */
+#define UART_DATA_RQ UART(1) /* send bytes request */
+#define UART_DATA_IND UART(2) /* recieved bytes indication */
+
+/* serial channel device driver */
+#define SER_CONN_RX SER(1) /* connect receiver */
+#define SER_CONN_TX SER(2) /* connect transmitter */
+#define SER_DISC_RX SER(3) /* disconnect receiver */
+#define SER_DISC_TX SER(4) /* disconnect transmitter */
+
+/* hdlc formatter module */
+#define HDLC_CONN_RX HDLC(1) /* connect receiver */
+#define HDLC_CONN_TX HDLC(2) /* connect transmitter */
+#define HDLC_DISC_RX HDLC(3) /* disconnect receiver */
+#define HDLC_DISC_TX HDLC(4) /* disconnect transmitter */
+
+/* command module */
+#define CMD_TRC_ON CMD(1) /* turn dchan trace on */
+#define CMD_TRC_OFF CMD(2) /* turn dchan trace off */
+#define CMD_BCHAN_OFF CMD(3) /* turn transmission off */
+#define CMD_BCHAN_HDLC CMD(4) /* turn hdlc on a channel */
+#define CMD_BCHAN_56 CMD(5) /* force channel to run 7 bits */
+#define CMD_BCHAN_VOICE CMD(6) /* voice mode b channel */
+#define CMD_ENV_DEF CMD(7) /* env variable defined */
+#define CMD_ENV_UNDEF CMD(8) /* env variable undefined */
+#define CMD_GO CMD(9) /* start execution */
+#define CMD_LOOPBACK CMD(10) /* channel loopback control */
+#define CMD_TRACE_MASK CMD(11) /* set trace/debug mask */
+#define CMD_DUMP_PARAM CMD(12) /* dump parameter block */
+#define CMD_COMPRESS CMD(13) // control B channel compression
+
+#endif /* _OPCODES_ */
diff --git a/private/ntos/ndis/digi/pcimac/pcimac.c b/private/ntos/ndis/digi/pcimac/pcimac.c
new file mode 100644
index 000000000..74b56788c
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/pcimac.c
@@ -0,0 +1,2385 @@
+//
+// Pcimac.c - Main file for pcimac miniport wan driver
+//
+//
+//
+//
+#include <ndis.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <opcodes.h>
+#include <disp.h>
+#include <adapter.h>
+#include <util.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+#include <tapioid.h>
+#include <res.h>
+#include <trc.h>
+#include <io.h>
+
+#include <ansihelp.h>
+
+
+/* driver global vars */
+DRIVER_BLOCK Pcimac;
+
+ULONG DigiDebugLevel = ( DIGIERRORS | DIGIBUGCHECK | DIGIINIT );
+
+ULONG DigiDontLoadDriver = FALSE;
+
+USHORT MCAIOAddressTable[] = { 0x108, 0x118,
+ 0x128, 0x208,
+ 0x228, 0x308,
+ 0x328, 0 };
+
+#if !BINARY_COMPATIBLE
+/* store location for prev. ioctl handler */
+NTSTATUS (*PrevIoctl)(DEVICE_OBJECT* DeviceObject, IRP* Irp) = NULL;
+#endif
+
+/* forward for external name manager */
+VOID BindName(ADAPTER *Adapter, BOOL create);
+
+//VOID RegistryInit (VOID);
+//VOID NdisTapiRequest(PNDIS_STATUS, NDIS_HANDLE, PNDIS_REQUEST);
+
+ULONG
+GetBaseConfigParams(
+ CONFIGPARAM *ConfigParam,
+ CHAR *Key
+ );
+
+
+ULONG
+GetLineConfigParams(
+ CONFIGPARAM *ConfigParam,
+ ULONG LineNumber,
+ CHAR *Key
+ );
+
+ULONG
+GetLTermConfigParams(
+ CONFIGPARAM *ConfigParam,
+ ULONG LineNumber,
+ ULONG LTermNumber,
+ CHAR *Key
+ );
+
+VOID
+IdpGetEaddrFromNvram(
+ IDD *idd,
+ CM *cm,
+ USHORT Line,
+ USHORT LineIndex
+ );
+
+VOID
+AdpGetEaddrFromNvram(
+ IDD *idd,
+ CM *cm,
+ USHORT Line,
+ USHORT LineIndex
+ );
+
+
+NTSTATUS PcimacInitMCA( NDIS_HANDLE AdapterHandle,
+ PULONG BaseIO,
+ PULONG BaseMemory,
+ ULONG SlotNumber );
+
+
+NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath );
+
+/* driver entry point */
+#pragma NDIS_INIT_FUNCTION( DriverEntry )
+NTSTATUS DriverEntry( PDRIVER_OBJECT DriverObject,
+ PUNICODE_STRING RegistryPath )
+/*++
+
+Routine Description:
+
+ Entry point for loading driver.
+
+Arguments:
+
+ DriverObject - Pointer to this drivers object.
+
+ RegistryPath - Pointer to a unicode string which points to this
+ drivers registry entry.
+
+Return Value:
+
+ STATUS_SUCCESS - If the driver was successfully loaded, otherwise,
+ a value which indicates why it wasn't able to load.
+
+
+--*/
+{
+ ULONG RetVal, n, m;
+
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ NDIS_HANDLE NdisWrapperHandle;
+
+ NDIS_MINIPORT_CHARACTERISTICS MiniportChars;
+
+ PWCHAR path;
+ ULONG DebugLevel;
+ ULONG zero = 0;
+ ULONG shouldBreak = 0;
+#if !BINARY_COMPATIBLE
+ ULONG defaultMemPrintFlags=MEM_PRINT_FLAG_FILE;
+
+ RTL_QUERY_REGISTRY_TABLE paramTable[5];
+
+ //
+ // First, read the registry to determine some initial information.
+ //
+ DigiInitMem( 'irbD' );
+
+ if( path = DigiAllocMem( PagedPool,
+ RegistryPath->Length+sizeof(WCHAR) ))
+ {
+ RtlZeroMemory( &paramTable[0], sizeof(paramTable) );
+ RtlZeroMemory( path, RegistryPath->Length+sizeof(WCHAR) );
+ RtlMoveMemory( path, RegistryPath->Buffer, RegistryPath->Length );
+
+ paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ paramTable[0].Name = L"DigiBreakOnEntry";
+ paramTable[0].EntryContext = &shouldBreak;
+ paramTable[0].DefaultType = REG_DWORD;
+ paramTable[0].DefaultData = &zero;
+ paramTable[0].DefaultLength = sizeof(ULONG);
+
+ paramTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ paramTable[1].Name = L"DigiDebugLevel";
+ paramTable[1].EntryContext = &DebugLevel;
+ paramTable[1].DefaultType = REG_DWORD;
+ paramTable[1].DefaultData = &DigiDebugLevel;
+ paramTable[1].DefaultLength = sizeof(ULONG);
+
+ paramTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ paramTable[2].Name = L"DigiPrintFlags";
+ paramTable[2].EntryContext = &DigiPrintFlags;
+ paramTable[2].DefaultType = REG_DWORD;
+ paramTable[2].DefaultData = &defaultMemPrintFlags;
+ paramTable[2].DefaultLength = sizeof(ULONG);
+
+ if( !NT_SUCCESS(RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
+ path,
+ &paramTable[0],
+ NULL, NULL )))
+ {
+ // No, don't break on entry if there isn't anything to over-
+ // ride.
+ shouldBreak = 0;
+
+ // Set debug level to what ever was compiled into the driver.
+ DebugLevel = DigiDebugLevel;
+ }
+
+ }
+
+ DigiDebugLevel = DebugLevel;
+
+ if( shouldBreak )
+ {
+ DbgBreakPoint();
+ }
+
+ if( DigiDontLoadDriver )
+ return( STATUS_CANCELLED );
+
+ MemPrintPreInitSettings( "\\SystemRoot\\digibri.log",
+ (65536 * 8) );
+
+ MemPrintInitialize();
+
+#endif
+
+ NdisZeroMemory(&Pcimac, sizeof(DRIVER_BLOCK));
+
+ /* initialize ndis wrapper */
+ NdisMInitializeWrapper(&NdisWrapperHandle, DriverObject, RegistryPath, NULL);
+
+ /* initialize debug support */
+ D_LOG(DIGIINIT, ("PCIMAC WanMiniport NT Driver, Copyright Digi Intl. Inc, 1992-1994\n"));
+ D_LOG(DIGIINIT, ("DriverObject: 0x%x\n", DriverObject));
+ D_LOG(DIGIINIT, ("RegisteryPath: 0x%x\n", RegistryPath));
+ D_LOG(DIGIINIT, ("WrapperHandle: 0x%x\n", NdisWrapperHandle));
+
+ Pcimac.NdisWrapperHandle = NdisWrapperHandle;
+
+ NdisAllocateSpinLock (&Pcimac.lock);
+
+ /* initialize classes */
+ if ((RetVal = idd_init()) != IDD_E_SUCC)
+ goto exit_idd_error;
+
+ if ((RetVal = cm_init()) != CM_E_SUCC)
+ goto exit_cm_error;
+
+ if ((RetVal = res_init()) != RES_E_SUCC)
+ goto exit_res_error;
+
+ NdisZeroMemory(&MiniportChars,
+ sizeof(NDIS_MINIPORT_CHARACTERISTICS));
+
+ MiniportChars.MajorNdisVersion = NDIS_MAJOR_VER;
+ MiniportChars.MinorNdisVersion = NDIS_MINOR_VER;
+ MiniportChars.Reserved = NDIS_USE_WAN_WRAPPER;
+ MiniportChars.CheckForHangHandler = PcimacCheckForHang;
+ MiniportChars.DisableInterruptHandler = NULL;
+ MiniportChars.EnableInterruptHandler = NULL;
+ MiniportChars.HaltHandler = PcimacHalt;
+ MiniportChars.HandleInterruptHandler = NULL;
+ MiniportChars.InitializeHandler = PcimacInitialize;
+ MiniportChars.ISRHandler = NULL;
+ MiniportChars.QueryInformationHandler = PcimacSetQueryInfo;
+ MiniportChars.ReconfigureHandler = PcimacReconfigure;
+ MiniportChars.ResetHandler = PcimacReset;
+ MiniportChars.WanSendHandler = PcimacSend;
+ MiniportChars.SetInformationHandler = PcimacSetQueryInfo;
+ MiniportChars.WanTransferDataHandler = NULL;
+
+ NdisMRegisterMiniport (NdisWrapperHandle,
+ (PNDIS_MINIPORT_CHARACTERISTICS)&MiniportChars,
+ sizeof(MiniportChars));
+
+ if (!EnumAdaptersInSystem())
+ goto exit_event_error;
+
+ /* initialize ioctl filter */
+#if !BINARY_COMPATIBLE
+ PrevIoctl = DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL];
+ DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PcimacIoctl;
+#endif
+
+ //
+ // get an adapter to create a binding I/O name binding to
+ //
+ for( n = 0; n < MAX_ADAPTERS_IN_SYSTEM; n++ )
+ {
+ ADAPTER *Adapter = Pcimac.AdapterTbl[n];
+
+ if (Adapter)
+ {
+ /* create external name binding */
+ BindName(Adapter, TRUE);
+ break;
+ }
+ }
+
+ //
+ // turn off the trace on all idd's in the system
+ //
+ for (n = 0; n < MAX_ADAPTERS_IN_SYSTEM; n++)
+ {
+ ADAPTER *Adapter = Pcimac.AdapterTbl[n];
+ IDD_MSG msg;
+
+ if (Adapter)
+ {
+ for (m = 0; m < MAX_IDD_PER_ADAPTER; m++)
+ {
+ IDD *idd = Adapter->IddTbl[m];
+
+ if (idd)
+ {
+ /* issue idd command to stop trace */
+ NdisZeroMemory(&msg, sizeof(msg));
+ msg.opcode = CMD_TRC_OFF;
+ idd_send_msg(idd, &msg, IDD_PORT_CMD_TX, NULL, NULL);
+ }
+ }
+ }
+ }
+
+ D_LOG(D_EXIT, ("DriverEntry: exit success!\n"));
+
+ /* if successful here, done */
+ return(STATUS_SUCCESS);
+
+exit_event_error:
+ D_LOG(D_ALWAYS, ("EventError!\n"));
+ res_term();
+
+exit_res_error:
+ D_LOG(D_ALWAYS, ("ResError!\n"));
+ cm_term();
+
+exit_cm_error:
+exit_idd_error:
+ D_LOG(D_ALWAYS, ("CmIddError!\n"));
+
+ NdisFreeSpinLock(&Pcimac.lock);
+
+ NdisTerminateWrapper(Pcimac.NdisWrapperHandle, NULL);
+
+#if !BINARY_COMPATIBLE
+ if( path )
+ {
+ DigiFreeMem(path);
+ }
+
+ MemPrintQuit();
+#endif
+
+ return(NDIS_STATUS_FAILURE);
+}
+
+BOOLEAN
+PcimacCheckForHang(
+ NDIS_HANDLE AdapterContext
+ )
+{
+ ULONG n, IdpCounter = 0;
+ ADAPTER *Adapter = (ADAPTER *)AdapterContext;
+ BOOLEAN ReturnStatus = FALSE;
+
+ D_LOG(D_ENTRY, ("PcimacCheckForHang: Adapter: 0x%lx\n", AdapterContext));
+
+ //
+ // for all idd's that belong to this adpater
+ //
+ for (n = 0; Adapter->IddTbl[n] && n < MAX_IDD_PER_ADAPTER; n++)
+ {
+ IDD *idd = Adapter->IddTbl[n];
+
+ //
+ // see if this idd is dead
+ //
+ if (!idd || idd->state == IDD_S_SHUTDOWN)
+ continue;
+
+ IdpCounter++;
+ }
+
+ //
+ // if there are no idps alive on this adapter tell the wrapper
+ //
+ if (!IdpCounter)
+ ReturnStatus = TRUE;
+
+ D_LOG(D_ALWAYS, ("PcimacCheckForHang: ReturnStatus: %d\n", ReturnStatus));
+
+ return(ReturnStatus);
+}
+
+VOID
+PcimacHalt(
+ NDIS_HANDLE AdapterContext
+ )
+{
+ ULONG n;
+ ADAPTER *Adapter = (ADAPTER*)AdapterContext;
+
+ D_LOG(D_ENTRY, ("PcimacHalt: Adapter: 0x%lx\n", AdapterContext));
+ DbgPrint("PcimacHalt: Adapter: 0x%lx\n", AdapterContext);
+
+ //
+ // destroy cm objects
+ //
+ for (n = 0; n < MAX_CM_PER_ADAPTER; n++)
+ {
+ CM *cm = Adapter->CmTbl[n];
+
+ Adapter->CmTbl[n] = NULL;
+
+ if (cm)
+ cm_destroy(cm);
+ }
+
+ //
+ // destroy mtl objects
+ //
+ for (n = 0; n < MAX_MTL_PER_ADAPTER; n++)
+ {
+ MTL *mtl = Adapter->MtlTbl[n];
+
+ Adapter->MtlTbl[n] = NULL;
+
+ if (mtl)
+ mtl_destroy(mtl);
+ }
+
+ //
+ // destroy idd objects
+ //
+ for (n = 0; n < MAX_IDD_PER_ADAPTER; n++)
+ {
+ IDD *idd = (IDD*)Adapter->IddTbl[n];
+
+ Adapter->IddTbl[n] = NULL;
+
+ if (idd)
+ idd_destroy(idd);
+ }
+
+ /* delete external name binding */
+ BindName(Adapter, FALSE);
+
+ //
+ // deregister adapter
+ //
+ AdapterDestroy(Adapter);
+}
+
+#pragma NDIS_INIT_FUNCTION(PcimacInitialize)
+
+NDIS_STATUS PcimacInitialize( PNDIS_STATUS OpenErrorStatus,
+ PUINT SelectMediumIndex,
+ PNDIS_MEDIUM MediumArray,
+ UINT MediumArraySize,
+ NDIS_HANDLE AdapterHandle,
+ NDIS_HANDLE WrapperConfigurationContext )
+{
+ ADAPTER *Adapter;
+ USHORT BoardType, NumberOfLines, NumberOfLTerms, BoardNumber;
+ ULONG BaseMem, BaseIO, n, m, l, IddStarted = 0;
+ PVOID VBaseMem, VBaseIO;
+ ANSI_STRING AnsiStr;
+ NDIS_STRING NdisStr;
+ CHAR DefName[128];
+ NDIS_STATUS RetVal = NDIS_STATUS_SUCCESS;
+ CONFIGPARAM ConfigParam;
+ NDIS_INTERFACE_TYPE NdisInterfaceType = NdisInterfaceIsa;
+ NDIS_PHYSICAL_ADDRESS MemPhyAddr;
+ NDIS_PHYSICAL_ADDRESS HighestAcceptableMax = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
+
+ D_LOG(D_ENTRY, ("PcimacInitialize: AdapterHandle: 0x%x\n", AdapterHandle));
+
+ for (n = 0; n < MediumArraySize; n++)
+ if (MediumArray[n] == NdisMediumWan)
+ break;
+
+ if (n == MediumArraySize)
+ return(NDIS_STATUS_UNSUPPORTED_MEDIA);
+
+ *SelectMediumIndex = n;
+
+ //
+ // allocate control block for this adapter
+ //
+ NdisAllocateMemory((PVOID*)&Adapter,
+ sizeof(ADAPTER),
+ 0,
+ HighestAcceptableMax);
+ if ( !Adapter)
+ {
+ D_LOG(D_ALWAYS, ("PcimacInitiailize: Adapter memory allocate failed!\n"));
+ return (NDIS_STATUS_ADAPTER_NOT_FOUND);
+ }
+ D_LOG(D_ALWAYS, ("PcimacInitialize: Allocated an Adapter: 0x%lx\n", Adapter));
+ NdisZeroMemory(Adapter, sizeof(ADAPTER));
+
+ //
+ // store adapter in global structure
+ //
+ for (n = 0; n < MAX_ADAPTERS_IN_SYSTEM; n++)
+ {
+ if (!Pcimac.AdapterTbl[n])
+ {
+ Pcimac.AdapterTbl[n] = Adapter;
+ Pcimac.NumberOfAdaptersInSystem++;
+ BoardNumber = (USHORT)n;
+ break;
+ }
+ }
+
+ //
+ // if no room destroy and leave
+ //
+ if (n >= MAX_ADAPTERS_IN_SYSTEM)
+ {
+ D_LOG(D_ALWAYS, ("PcimacInitialize: No room in Adapter Table\n"));
+ NdisFreeMemory(Adapter, sizeof(ADAPTER), 0);
+ return (NDIS_STATUS_ADAPTER_NOT_FOUND);
+ }
+
+ //
+ // set in driver access lock
+ //
+// NdisAllocateSpinLock (&Adapter->InDriverLock);
+
+
+ //
+ // store adapter handle
+ //
+ Adapter->Handle = AdapterHandle;
+
+ //
+ // initialize adapter specific timers
+ //
+ NdisMInitializeTimer(&Adapter->IddPollTimer, Adapter->Handle, IddPollFunction, Adapter);
+ NdisMSetTimer(&Adapter->IddPollTimer, IDD_POLL_T);
+
+ NdisMInitializeTimer(&Adapter->MtlPollTimer, Adapter->Handle, MtlPollFunction, Adapter);
+ NdisMSetTimer(&Adapter->MtlPollTimer, MTL_POLL_T);
+
+ NdisMInitializeTimer(&Adapter->CmPollTimer, Adapter->Handle, CmPollFunction, Adapter);
+ NdisMSetTimer(&Adapter->CmPollTimer, CM_POLL_T);
+
+ ConfigParam.AdapterHandle = AdapterHandle;
+
+ //
+ // Open registry
+ //
+ NdisOpenConfiguration(&RetVal, &ConfigParam.ConfigHandle, WrapperConfigurationContext);
+
+ if (RetVal != NDIS_STATUS_SUCCESS)
+ {
+ D_LOG(D_ALWAYS, ("PcimacInitialize: Error Opening Config: RetVal: 0x%x\n", RetVal));
+ NdisWriteErrorLogEntry (AdapterHandle,
+ NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER,
+ 1,
+ 0);
+ goto InitErrorExit;
+ }
+
+ //
+ // read registry board type
+ //
+ ConfigParam.StringLen = sizeof(ConfigParam.String);
+ ConfigParam.ParamType = NdisParameterString;
+ ConfigParam.MustBePresent = TRUE;
+ if (!GetBaseConfigParams(&ConfigParam, PCIMAC_KEY_BOARDTYPE))
+ goto InitErrorExit;
+
+ if (!__strncmp(ConfigParam.String, "PCIMAC4", 7))
+ BoardType = IDD_BT_PCIMAC4;
+ else if (!__strncmp(ConfigParam.String, "PCIMAC - ISA", 12))
+ BoardType = IDD_BT_PCIMAC;
+ else if (!__strncmp(ConfigParam.String, "PCIMAC - MC", 11))
+ {
+ NdisInterfaceType = NdisInterfaceMca;
+ BoardType = IDD_BT_MCIMAC;
+ }
+ else if (!__strncmp(ConfigParam.String, "DATAFIRE - ISA1U", 16))
+ BoardType = IDD_BT_DATAFIREU;
+ else if (!__strncmp(ConfigParam.String, "DATAFIRE - ISA1ST", 17))
+ BoardType = IDD_BT_DATAFIREST;
+ else if (!__strncmp(ConfigParam.String, "DATAFIRE - ISA4ST", 17))
+ BoardType = IDD_BT_DATAFIRE4ST;
+ else
+ {
+ D_LOG(D_ALWAYS, ("PcimacInitialize: Invalid BoardType: %s\n", ConfigParam.String));
+ goto InitErrorExit;
+ }
+
+ //
+ // save board type
+ //
+ Adapter->BoardType = BoardType;
+
+ //
+ // set miniport attributes (only isa for now)
+ //
+ NdisMSetAttributes( AdapterHandle, Adapter, FALSE, NdisInterfaceType );
+
+ //
+ // read registry base io
+ //
+ ConfigParam.StringLen = 0;
+ ConfigParam.ParamType = NdisParameterInteger;
+ ConfigParam.MustBePresent = TRUE;
+ if (!GetBaseConfigParams(&ConfigParam,PCIMAC_KEY_BASEIO))
+ goto InitErrorExit;
+
+ BaseIO = ConfigParam.Value;
+
+ if( NdisInterfaceType != NdisInterfaceMca )
+ {
+ //
+ // save base I/O for this adapter
+ //
+ Adapter->BaseIO = BaseIO;
+
+ }
+ else
+ {
+ //
+ // Must be a MCA adapter.
+ //
+ // Note, BaseIO should be the slot number for this adapter instance.
+ //
+ RetVal = PcimacInitMCA( AdapterHandle,
+ &Adapter->BaseIO,
+ &Adapter->BaseMem,
+ BaseIO );
+
+ BaseMem = Adapter->BaseMem;
+ BaseIO = Adapter->BaseIO;
+
+ if( RetVal != NDIS_STATUS_SUCCESS )
+ goto InitErrorExit;
+
+ }
+
+ //
+ // register I/O range
+ //
+ RetVal = NdisMRegisterIoPortRange(&VBaseIO,
+ AdapterHandle,
+ BaseIO,
+ 8);
+
+ if (RetVal != NDIS_STATUS_SUCCESS)
+ {
+ NdisWriteErrorLogEntry(AdapterHandle,
+ NDIS_ERROR_CODE_BAD_IO_BASE_ADDRESS,
+ 0);
+ goto InitErrorExit;
+ }
+
+ Adapter->VBaseIO = VBaseIO;
+
+ if( (BoardType != IDD_BT_DATAFIREU) &&
+ (BoardType != IDD_BT_DATAFIREST) &&
+ (BoardType != IDD_BT_DATAFIRE4ST) )
+ {
+ //
+ // This is a PCIMAC family of adapters
+ //
+ //
+ // read registry base mem
+ //
+
+ if( NdisInterfaceType != NdisInterfaceMca )
+ {
+ ConfigParam.StringLen = 0;
+ ConfigParam.ParamType = NdisParameterInteger;
+ ConfigParam.MustBePresent = TRUE;
+ if( !GetBaseConfigParams(&ConfigParam, PCIMAC_KEY_BASEMEM) )
+ goto InitErrorExit;
+
+ BaseMem = ConfigParam.Value;
+
+ //
+ // save base memory for this adapter
+ //
+ Adapter->BaseMem = BaseMem;
+
+ }
+
+ //
+ // since our adapters can share the same base memory we need to
+ // see if we have already mapped this memory range. if we have already
+ // mapped the memory once then save that previous value
+ //
+ for (n = 0; n < MAX_ADAPTERS_IN_SYSTEM; n++)
+ {
+ ADAPTER *PreviousAdapter = Pcimac.AdapterTbl[n];
+
+ //
+ // if this is a valid adapter, this is not the current adapter, and
+ // this adapter has the same shared memory address as the current
+ // adapter, then use this adapters mapped memory for the current
+ // adpaters mapped memory
+ //
+ if (PreviousAdapter &&
+ (PreviousAdapter != Adapter) &&
+ (PreviousAdapter->BaseMem == Adapter->BaseMem))
+ {
+ VBaseMem = PreviousAdapter->VBaseMem;
+ break;
+ }
+ }
+
+ //
+ // if we did not find a previous adapter with this memory range
+ // we need to map this memory range
+ //
+ if (n >= MAX_ADAPTERS_IN_SYSTEM)
+ {
+ //
+ // map our physical memory into virtual memory
+ //
+ NdisSetPhysicalAddressHigh(MemPhyAddr, 0);
+ NdisSetPhysicalAddressLow(MemPhyAddr, BaseMem);
+
+ RetVal = NdisMMapIoSpace(&VBaseMem,
+ AdapterHandle,
+ MemPhyAddr,
+ 0x4000);
+
+ if (RetVal != NDIS_STATUS_SUCCESS)
+ {
+ NdisWriteErrorLogEntry(AdapterHandle,
+ NDIS_ERROR_CODE_RESOURCE_CONFLICT,
+ 0);
+ goto InitErrorExit;
+ }
+
+ Adapter->VBaseMem = VBaseMem;
+ }
+ }
+
+ //
+ // read registry name
+ //
+ NdisZeroMemory(ConfigParam.String, sizeof(ConfigParam.String));
+ ConfigParam.StringLen = sizeof(Adapter->Name);
+ ConfigParam.ParamType = NdisParameterString;
+ ConfigParam.MustBePresent = TRUE;
+ if (!GetBaseConfigParams(&ConfigParam, PCIMAC_KEY_BOARDNAME))
+ goto InitErrorExit;
+
+ NdisMoveMemory( Adapter->Name,
+ ConfigParam.String,
+ ConfigParam.StringLen );
+ //
+ // read the number of lines for this board
+ //
+ ConfigParam.StringLen = 0;
+ ConfigParam.ParamType = NdisParameterInteger;
+ ConfigParam.MustBePresent = TRUE;
+ if (!GetBaseConfigParams(&ConfigParam, PCIMAC_KEY_NUMLINES))
+ NumberOfLines = (BoardType == IDD_BT_PCIMAC4) ? 4 : 1;
+ else
+ NumberOfLines = (USHORT)ConfigParam.Value;
+
+ //
+ // for number of lines
+ //
+ for (n = 0; n < NumberOfLines; n++)
+ {
+ IDD *idd;
+
+ //
+ // Create idd object
+ //
+ if (idd_create(&idd, BoardType) != IDD_E_SUCC)
+ {
+ NdisWriteErrorLogEntry (AdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0);
+
+ goto InitErrorExit;
+ }
+
+ //
+ // store idd in idd table
+ //
+ for (l = 0; l < MAX_IDD_PER_ADAPTER; l++)
+ {
+ if (!Adapter->IddTbl[l])
+ {
+ Adapter->IddTbl[l] = idd;
+ break;
+ }
+ }
+
+ Adapter->NumberOfIddOnAdapter++;
+
+ //
+ // set idd physical base i/o and memory
+ //
+ idd->phw.base_io = BaseIO;
+ idd->phw.base_mem = BaseMem;
+
+ //
+ // set idd virtual base i/o and memory
+ //
+ idd->vhw.vbase_io = (ULONG)VBaseIO;
+ idd->vhw.vmem = VBaseMem;
+
+ //
+ // create an i/o resource manager for this idd
+ //
+ idd->res_io = res_create(RES_CLASS_IO, (ULONG)BaseIO);
+
+ //
+ // create a memory resource manager for this idd
+ //
+ idd->res_mem = res_create(RES_CLASS_MEM, (ULONG)BaseMem);
+ res_set_data(idd->res_mem, (ULONG)VBaseMem);
+
+ //
+ // save adapter handle
+ //
+ idd->adapter_handle = AdapterHandle;
+
+ //
+ // save the board number of this idd
+ //
+ idd->bnumber = BoardNumber;
+
+ //
+ // save the line number of this idd
+ //
+// idd->bline = (USHORT)NumberOfLines - 1 - n;
+ idd->bline = (USHORT)n;
+
+ //
+ // save the board type that this idd belongs to
+ //
+ idd->btype = BoardType;
+
+ if(idd->CheckIO(idd))
+ {
+ NdisWriteErrorLogEntry(AdapterHandle,
+ NDIS_ERROR_CODE_BAD_IO_BASE_ADDRESS,
+ 0);
+ goto InitErrorExit;
+ }
+
+ //
+ // read registry line name
+ //
+ NdisZeroMemory(ConfigParam.String, sizeof(ConfigParam.String));
+ ConfigParam.StringLen = sizeof(idd->name);
+ ConfigParam.ParamType = NdisParameterString;
+ ConfigParam.MustBePresent = TRUE;
+ if (!GetLineConfigParams(&ConfigParam, n, PCIMAC_KEY_LINENAME))
+ goto InitErrorExit;
+
+ sprintf(idd->name, "%s-%s", Adapter->Name, ConfigParam.String);
+
+// NdisMoveMemory(idd->name,
+// ConfigParam.String,
+// ConfigParam.StringLen);
+
+ //
+ // read registry idp file name
+ //
+ NdisZeroMemory(ConfigParam.String, sizeof(ConfigParam.String));
+ ConfigParam.StringLen = sizeof(idd->phw.idp_bin);
+ ConfigParam.ParamType = NdisParameterString;
+ ConfigParam.MustBePresent = TRUE;
+ if (!GetLineConfigParams(&ConfigParam, n, PCIMAC_KEY_IDPFILENAME))
+ goto InitErrorExit;
+
+ NdisMoveMemory(idd->phw.idp_bin,
+ ConfigParam.String,
+ ConfigParam.StringLen);
+
+
+ //
+ // Try to open idp bin file
+ //
+ RtlInitAnsiString(&AnsiStr, idd->phw.idp_bin);
+
+ //
+ // allocate buffer and turn ansi to unicode
+ //
+ RtlAnsiStringToUnicodeString(&NdisStr, &AnsiStr, TRUE);
+
+ NdisOpenFile(&RetVal,
+ &idd->phw.fbin,
+ &idd->phw.fbin_len,
+ &NdisStr,
+ HighestAcceptableMax);
+
+ //
+ // free up unicode string buffer
+ //
+ RtlFreeUnicodeString(&NdisStr);
+
+ if (RetVal != NDIS_STATUS_SUCCESS)
+ {
+ NdisWriteErrorLogEntry(AdapterHandle,
+ NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
+ 0);
+ goto InitErrorExit;
+ }
+
+ //
+ // read registry switch style
+ //
+ NdisZeroMemory(ConfigParam.String, sizeof(ConfigParam.String));
+ ConfigParam.StringLen = 128;
+ ConfigParam.ParamType = NdisParameterString;
+ ConfigParam.MustBePresent = TRUE;
+ if (!GetLineConfigParams(&ConfigParam, n, PCIMAC_KEY_SWITCHSTYLE))
+ goto InitErrorExit;
+
+ //
+ // added to support the new switch styles
+ //
+ CmSetSwitchStyle(ConfigParam.String);
+
+ idd_add_def(idd, "q931.style", ConfigParam.String);
+
+ //
+ // read registry terminal management
+ //
+ NdisZeroMemory(ConfigParam.String, sizeof(ConfigParam.String));
+ ConfigParam.StringLen = 128;
+ ConfigParam.ParamType = NdisParameterString;
+ ConfigParam.MustBePresent = TRUE;
+ if (!GetLineConfigParams(&ConfigParam, n,
+ PCIMAC_KEY_TERMINALMANAGEMENT))
+ goto InitErrorExit;
+
+ idd_add_def(idd, "q931.tm", ConfigParam.String);
+
+ //
+ // read WaitForL3 value
+ //
+ NdisZeroMemory(ConfigParam.String, sizeof(ConfigParam.String));
+ ConfigParam.StringLen = 128;
+ ConfigParam.ParamType = NdisParameterString;
+ ConfigParam.MustBePresent = FALSE;
+ if (!GetLineConfigParams(&ConfigParam, n,
+ PCIMAC_KEY_WAITFORL3))
+ strcpy(ConfigParam.String, "5");
+
+ idd_add_def(idd, "q931.wait_l3", ConfigParam.String);
+
+ //
+ // read registry logical terminals
+ //
+ ConfigParam.StringLen = 0;
+ ConfigParam.ParamType = NdisParameterInteger;
+ ConfigParam.MustBePresent = TRUE;
+ if (!GetLineConfigParams(&ConfigParam, n, PCIMAC_KEY_NUMLTERMS))
+ goto InitErrorExit;
+
+ NumberOfLTerms = (USHORT)ConfigParam.Value;
+
+ if (NumberOfLTerms > 1)
+ idd_add_def(idd, "dual_q931", "any");
+
+ //
+ // store number of lterms that this idd has
+ //
+ idd->CallInfo.NumLTerms = NumberOfLTerms;
+
+ //
+ // for each logical terminal
+ //
+ for (l = 0; l < NumberOfLTerms; l++)
+ {
+ //
+ // read registry tei
+ //
+ NdisZeroMemory(ConfigParam.String, sizeof(ConfigParam.String));
+ ConfigParam.StringLen = 128;
+ ConfigParam.ParamType = NdisParameterString;
+ ConfigParam.MustBePresent = FALSE;
+ if (!GetLTermConfigParams(&ConfigParam, n, l, PCIMAC_KEY_TEI))
+ __strcpy(ConfigParam.String, "127");
+
+ NdisZeroMemory(DefName, sizeof(DefName));
+ sprintf(DefName, "q931.%d.tei", l);
+ idd_add_def(idd, DefName, ConfigParam.String);
+
+ //
+ // read registry spid
+ //
+ NdisZeroMemory(ConfigParam.String, sizeof(ConfigParam.String));
+ ConfigParam.StringLen = 128;
+ ConfigParam.ParamType = NdisParameterString;
+ ConfigParam.MustBePresent = FALSE;
+ if (GetLTermConfigParams(&ConfigParam, n, l, PCIMAC_KEY_SPID))
+ {
+ CHAR TempVal[64];
+ ULONG i, j;
+
+ //
+ // remove any non digits except # & *
+ //
+ NdisZeroMemory(TempVal, sizeof(TempVal));
+
+ for (i = 0, j = 0; i < ConfigParam.StringLen; i++)
+ {
+ if ((ConfigParam.String[i] >= '0' && ConfigParam.String[i] <= '9') ||
+ ConfigParam.String[i] == '*' ||
+ ConfigParam.String[i] == '#')
+ {
+ TempVal[j++] = ConfigParam.String[i];
+ }
+ }
+
+ NdisZeroMemory(DefName, sizeof(DefName));
+ sprintf(DefName, "q931.%d.spid", l);
+ idd_add_def(idd, DefName, TempVal);
+ idd_add_def(idd, "q931.multipoint", "any");
+ }
+
+ //
+ // read registry address
+ //
+ NdisZeroMemory(ConfigParam.String, sizeof(ConfigParam.String));
+ ConfigParam.StringLen = 128;
+ ConfigParam.ParamType = NdisParameterString;
+ ConfigParam.MustBePresent = FALSE;
+ if (GetLTermConfigParams(&ConfigParam, n, l, PCIMAC_KEY_ADDRESS))
+ {
+ CHAR TempVal[64];
+ ULONG i, j;
+
+ //
+ // remove any non digits except # & *
+ //
+ NdisZeroMemory(TempVal, sizeof(TempVal));
+
+ for (i = 0, j = 0; i < ConfigParam.StringLen; i++)
+ {
+ if ((ConfigParam.String[i] >= '0' && ConfigParam.String[i] <= '9') ||
+ ConfigParam.String[i] == '*' ||
+ ConfigParam.String[i] == '#')
+ {
+ TempVal[j++] = ConfigParam.String[i];
+ }
+ }
+
+ NdisZeroMemory(DefName, sizeof(DefName));
+ sprintf(DefName, "q931.%d.addr", l);
+ idd_add_def(idd, DefName, TempVal);
+ }
+
+ //
+ // add code to read generic multistring at the lterm level
+ // Key is "LTermDefinitions" these will be added to
+ // the enviornment database
+ // each string will look like "name=value\0" should
+ // remove "=" and replace with '\0'
+ //
+ }
+
+ //
+ // add code to read generic multistring at the board level
+ // Key is "GenericDefines"
+ // each string will look like "name=value\0" should
+ // remove "=" and replace with '\0'
+ //
+ NdisZeroMemory(ConfigParam.String, sizeof(ConfigParam.String));
+ ConfigParam.StringLen = sizeof(ConfigParam.String);
+ ConfigParam.ParamType = NdisParameterMultiString;
+ ConfigParam.MustBePresent = FALSE;
+ if (GetBaseConfigParams(&ConfigParam, PCIMAC_KEY_GENERICDEFINES))
+ {
+ CHAR Name[50] = {0};
+ CHAR Value[50] = {0};
+ CHAR *StringPointer = ConfigParam.String;
+
+ while (__strlen(StringPointer))
+ {
+ //
+ // copy the name part of the generic define
+ //
+ __strcpy(Name, StringPointer);
+
+ D_LOG(D_ALWAYS, ("PcimacInitialize: GenericDefines: Name: %s\n", Name));
+ //
+ // push pointer over the name
+ //
+ StringPointer += __strlen(StringPointer);
+
+ //
+ // get over the null character
+ //
+ StringPointer += 1;
+
+ //
+ // copy the value part of the generic define
+ //
+ __strcpy(Value, StringPointer);
+ D_LOG(D_ALWAYS, ("PcimacInitialize: GenericDefines: Value: %s\n", Value));
+
+ idd_add_def(idd, Name, Value);
+
+ //
+ // push pointer over the value
+ //
+ StringPointer += __strlen(StringPointer);
+
+ //
+ // get over the null character
+ //
+ StringPointer += 1;
+ }
+ }
+
+ //
+ // startup idd
+ //
+ if (idd_startup(idd) != IDD_E_SUCC)
+ {
+ NdisWriteErrorLogEntry(AdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 2,
+ (ULONG)idd->bnumber,
+ (ULONG)idd->bline);
+ idd_destroy(idd);
+ for (m = 0; m < MAX_IDD_PER_ADAPTER; m++)
+ if (Adapter->IddTbl[m] == idd)
+ Adapter->IddTbl[m] = NULL;
+
+ Adapter->NumberOfIddOnAdapter--;
+ continue;
+ }
+
+ //
+ // register handlers for idd
+ //
+ cm_register_idd(idd);
+
+ IddStarted++;
+ }
+
+ if (!IddStarted)
+ goto InitErrorExit;
+
+
+ for (n = 0; n < IddStarted; n++)
+ {
+ CM *cm;
+ MTL *mtl;
+ IDD *idd;
+
+ idd = Adapter->IddTbl[n];
+
+ //
+ // build two cm's and two mtl's per line
+ //
+ for (l = 0; l < 2; l++)
+ {
+ ULONG m;
+
+ //
+ // Allocate memory for cm object
+ //
+ if (cm_create(&cm, AdapterHandle) != CM_E_SUCC)
+ goto InitErrorExit;
+
+ for (m = 0; m < MAX_CM_PER_ADAPTER; m++)
+ {
+ if (!Adapter->CmTbl[m])
+ {
+ Adapter->CmTbl[m] = cm;
+ break;
+ }
+ }
+
+ //
+ // back pointer to adapter structure
+ //
+ cm->Adapter = Adapter;
+
+ //
+ // pointer to idd that belongs to this cm
+ //
+ cm->idd = idd;
+
+ //
+ // name cm object format: AdapterName-LineName-chan#
+ //
+ sprintf(cm->name,"%s-%d", idd->name, l);
+
+ //
+ // set local address, format: NetCard#-idd#-chan#
+ //
+#if !BINARY_COMPATIBLE
+ sprintf( cm->LocalAddress, "%d-%d-%d",
+ atoi( &Adapter->Name[6] ),
+ (idd->bline * 2) + l,
+ 0 );
+#else
+ sprintf(cm->LocalAddress, "1-%d-%d", (idd->bline * 2) + l, 0);
+#endif
+
+ //
+ // get ethernet addresses for this cm
+ //
+ if( (idd->btype == IDD_BT_DATAFIREU) ||
+ (idd->btype == IDD_BT_DATAFIREST) ||
+ (idd->btype == IDD_BT_DATAFIRE4ST) )
+ AdpGetEaddrFromNvram(idd, cm, (USHORT)n, (USHORT)l);
+ else
+ IdpGetEaddrFromNvram(idd, cm, (USHORT)n, (USHORT)l);
+
+ //
+ // Allocate memory for mtl object
+ //
+ if (mtl_create(&mtl, AdapterHandle) != MTL_E_SUCC)
+ goto InitErrorExit;
+
+ for (m = 0; m < MAX_MTL_PER_ADAPTER; m++)
+ {
+ if (!Adapter->MtlTbl[m])
+ {
+ Adapter->MtlTbl[m] = mtl;
+ break;
+ }
+ }
+
+ //
+ // back pointer to adapter structure
+ //
+ mtl->Adapter = Adapter;
+
+ //
+ // link between cm and mtl
+ //
+ cm->mtl = mtl;
+ mtl->cm = cm;
+ }
+ }
+
+ NdisCloseConfiguration(ConfigParam.ConfigHandle);
+
+ NdisMRegisterAdapterShutdownHandler(
+ AdapterHandle,
+ Adapter,
+ (PVOID)PcimacHalt
+ );
+
+ return (NDIS_STATUS_SUCCESS);
+
+InitErrorExit:
+ NdisCloseConfiguration(ConfigParam.ConfigHandle);
+
+ //
+ // clean up all idd's allocated
+ //
+ for (l = 0; l < MAX_IDD_PER_ADAPTER; l++)
+ {
+ IDD *idd = Adapter->IddTbl[l];
+
+ //
+ // if memory has been mapped release
+ //
+ if (idd)
+ {
+ idd_destroy(idd);
+ Adapter->IddTbl[l] = NULL;
+ }
+ }
+
+ //
+ // clean up all cm's allocated
+ //
+ for (l = 0; l < MAX_CM_PER_ADAPTER; l++)
+ {
+ CM *cm = Adapter->CmTbl[l];
+
+ if (cm)
+ {
+ cm_destroy(cm);
+ Adapter->CmTbl[l] = NULL;
+ }
+ }
+
+ //
+ // clean up all mtl's allocated
+ //
+ for (l = 0; l < MAX_MTL_PER_ADAPTER; l++)
+ {
+ MTL *mtl = Adapter->MtlTbl[l];
+
+ if (mtl)
+ {
+ mtl_destroy(mtl);
+ Adapter->MtlTbl[l] = NULL;
+ }
+ }
+
+ //
+ // clean up adapter block allocated
+ //
+ AdapterDestroy(Adapter);
+
+ return (NDIS_STATUS_ADAPTER_NOT_FOUND);
+} // end PcimacInitialize
+
+NDIS_STATUS
+PcimacSetQueryInfo(
+ NDIS_HANDLE AdapterContext,
+ NDIS_OID Oid,
+ PVOID InfoBuffer,
+ ULONG InfoBufferLen,
+ PULONG BytesReadWritten,
+ PULONG BytesNeeded
+ )
+{
+ ULONG OidType;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ D_LOG(D_ENTRY, ("PcimacSetQueryInfo: Adapter: 0x%lx, Oid: 0x%x\n", AdapterContext, Oid));
+
+ //
+ // get oid type
+ //
+ OidType = Oid & 0xFF000000;
+
+ switch (OidType)
+ {
+ case OID_WAN_INFO:
+ Status = WanOidProc(AdapterContext,
+ Oid,
+ InfoBuffer,
+ InfoBufferLen,
+ BytesReadWritten,
+ BytesNeeded);
+ break;
+
+ case OID_TAPI_INFO:
+ Status = TapiOidProc(AdapterContext,
+ Oid,
+ InfoBuffer,
+ InfoBufferLen,
+ BytesReadWritten,
+ BytesNeeded);
+ break;
+
+
+ case OID_GEN_INFO:
+ case OID_8023_INFO:
+ Status = LanOidProc(AdapterContext,
+ Oid,
+ InfoBuffer,
+ InfoBufferLen,
+ BytesReadWritten,
+ BytesNeeded);
+ break;
+
+ default:
+ Status = NDIS_STATUS_INVALID_OID;
+ break;
+ }
+
+ D_LOG(D_EXIT, ("PcimacSetQueryInfo: Status: 0x%x, BytesReadWritten: %d, BytesNeeded: %d\n", Status, *BytesReadWritten, *BytesNeeded));
+ return(Status);
+}
+
+NDIS_STATUS
+PcimacReconfigure(
+ PNDIS_STATUS OpenErrorStatus,
+ NDIS_HANDLE AdapterContext,
+ NDIS_HANDLE WrapperConfigurationContext
+ )
+{
+ D_LOG(D_ENTRY, ("PcimacReconfigure: Adapter: 0x%lx\n", AdapterContext));
+ //
+ // not supported for now
+ //
+ return(NDIS_STATUS_FAILURE);
+}
+
+NDIS_STATUS
+PcimacReset(
+ PBOOLEAN AddressingReset,
+ NDIS_HANDLE AdapterContext
+ )
+{
+ D_LOG(D_ENTRY, ("PcimacReset: Adapter: 0x%lx\n", AdapterContext));
+
+ return(NDIS_STATUS_HARD_ERRORS);
+}
+
+NDIS_STATUS
+PcimacSend(
+ NDIS_HANDLE MacBindingHandle,
+ NDIS_HANDLE LinkContext,
+ PNDIS_WAN_PACKET WanPacket
+ )
+{
+ MTL *mtl = (MTL*)LinkContext;
+
+ D_LOG(D_ENTRY, ("PcimacSend: Link: 0x%lx\n", mtl));
+
+ /* send packet */
+ mtl__tx_packet(mtl, WanPacket);
+
+ return(NDIS_STATUS_PENDING);
+}
+
+/* create/delete external name binding */
+VOID
+BindName(ADAPTER *Adapter, BOOL create)
+{
+#if !BINARY_COMPATIBLE
+
+#define LINKNAME "\\DosDevices\\PCIMAC0"
+ UNICODE_STRING linkname, devname;
+ NTSTATUS stat;
+ CHAR name[128];
+ ANSI_STRING aname;
+ ANSI_STRING lname;
+
+ if (Adapter)
+ sprintf(name,"\\Device\\%s",Adapter->Name);
+
+ if ( !name )
+ sprintf(name,"\\Device\\Pcimac69");
+
+ D_LOG(D_ENTRY, ("BindName: LinkName: %s, NdisName: %s\n", LINKNAME, name));
+
+ /* convert to unicode string */
+ RtlInitAnsiString(&lname, LINKNAME);
+ stat = RtlAnsiStringToUnicodeString(&linkname, &lname, TRUE);
+
+ /* convert to unicode string */
+ RtlInitAnsiString(&aname, name);
+ stat = RtlAnsiStringToUnicodeString(&devname, &aname, TRUE);
+
+ /* create? */
+ if ( create )
+ {
+ UNICODE_STRING AtlasVName, AtlasVEntry;
+
+ RtlInitAnsiString( &aname, "DigiBRI" );
+ RtlAnsiStringToUnicodeString( &AtlasVName, &aname, TRUE );
+
+ RtlInitAnsiString( &aname, "DgBRIAtlas" );
+ RtlAnsiStringToUnicodeString( &AtlasVEntry, &aname, TRUE );
+
+ stat = DigiRegisterAtlasName( &devname,
+ &AtlasVName,
+ &AtlasVEntry );
+
+ if( NT_ERROR(stat) )
+ stat = IoCreateSymbolicLink (&linkname, &devname);
+
+ RtlFreeUnicodeString( &AtlasVName );
+ RtlFreeUnicodeString( &AtlasVEntry );
+ }
+ else /* delete */
+ stat = IoDeleteSymbolicLink (&linkname);
+
+ D_LOG(D_ENTRY, ("BindName: Operation: 0x%x, stat: 0x%x\n", create, stat));
+
+ RtlFreeUnicodeString(&devname);
+ RtlFreeUnicodeString(&linkname);
+
+#endif
+
+}
+
+//
+// Function commented out for change in how RAS picks up tapi name and address info
+// This will help make the driver more portable.
+//
+//#pragma NDIS_INIT_FUNCTION(RegistryInit)
+//
+//VOID
+//RegistryInit(VOID)
+//{
+// UNICODE_STRING AddressUnicodeString;
+// UNICODE_STRING UnicodeString;
+// ANSI_STRING AnsiString;
+// PWCHAR AddressBuffer;
+// NDIS_PHYSICAL_ADDRESS HighestAcceptableMax = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
+// ULONG l, m;
+//
+// NdisAllocateMemory((PVOID)&AddressBuffer,
+// 1024,
+// 0,
+// HighestAcceptableMax);
+//
+// if (!AddressBuffer)
+// {
+// D_LOG(D_ALWAYS, ("RegistryInit: Memory Allocation Failed!\n"));
+// return;
+// }
+//
+// AddressUnicodeString.MaximumLength = 1024;
+// AddressUnicodeString.Length = 0;
+// NdisZeroMemory(AddressBuffer, 1024);
+// AddressUnicodeString.Buffer = AddressBuffer;
+//
+// //
+// // create tapi devices key
+// //
+// RtlCreateRegistryKey (RTL_REGISTRY_DEVICEMAP, L"Tapi Devices");
+//
+// //
+// // create pcimac service provider key
+// //
+// RtlCreateRegistryKey (RTL_REGISTRY_DEVICEMAP, L"Tapi Devices\\PCIMAC");
+//
+// //
+// // write media type - isdn for us
+// //
+// RtlInitAnsiString(&AnsiString, "ISDN");
+//
+// RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE);
+//
+// RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
+// L"Tapi Devices\\PCIMAC",
+// L"Media Type",
+// REG_SZ,
+// UnicodeString.Buffer,
+// UnicodeString.Length);
+//
+// RtlFreeUnicodeString(&UnicodeString);
+//
+// for (l = 0; l < MAX_ADAPTERS_IN_SYSTEM; l++)
+// {
+// ADAPTER *Adapter = (ADAPTER*)Pcimac.AdapterTbl[l];
+//
+// if (Adapter)
+// {
+// for (m = 0; m < MAX_CM_PER_ADAPTER; m++)
+// {
+// CM *cm = Adapter->CmTbl[m];
+//
+// if (cm)
+// {
+// RtlInitAnsiString(&AnsiString, cm->LocalAddress);
+//
+// RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE);
+//
+// RtlAppendUnicodeStringToString(&AddressUnicodeString, &UnicodeString);
+//
+// AddressUnicodeString.Buffer[AddressUnicodeString.Length + 1] = '\0';
+// AddressUnicodeString.Length += 2;
+//
+// RtlFreeUnicodeString(&UnicodeString);
+// }
+// }
+// }
+// }
+//
+// //
+// // write value
+// //
+// RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
+// L"Tapi Devices\\PCIMAC",
+// L"Address",
+// REG_MULTI_SZ,
+// AddressUnicodeString.Buffer,
+// AddressUnicodeString.Length);
+//
+// NdisFreeMemory(AddressBuffer, 1024, 0);
+//}
+
+#pragma NDIS_INIT_FUNCTION(GetBaseConfigParams)
+
+ULONG
+GetBaseConfigParams(
+ CONFIGPARAM *RetParam,
+ CHAR *Key
+ )
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ NDIS_STRING KeyWord;
+ ANSI_STRING AnsiKey;
+ ULONG n;
+ PNDIS_CONFIGURATION_PARAMETER ConfigParam;
+
+ D_LOG(D_ALWAYS, ("GetBaseConfigParams: Key: %s\n", Key));
+ //
+ // turn passed in key to an ansi string
+ //
+ RtlInitAnsiString(&AnsiKey, Key);
+
+ //
+ // allocate buffer and turn ansi to unicode
+ //
+ RtlAnsiStringToUnicodeString(&KeyWord, &AnsiKey, TRUE);
+
+ NdisReadConfiguration(&Status,
+ &ConfigParam,
+ RetParam->ConfigHandle,
+ &KeyWord,
+ RetParam->ParamType);
+
+ D_LOG(D_ALWAYS, ("GetBaseConfigParams: Status: 0x%x\n", Status));
+ //
+ // free up unicode string buffer
+ //
+ RtlFreeUnicodeString(&KeyWord);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ D_LOG(D_ALWAYS, ("GetBaseConfigParams: Error Reading Config: RetVal: 0x%x\n", Status));
+ if (RetParam->MustBePresent)
+ NdisWriteErrorLogEntry (RetParam->AdapterHandle,
+ NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER,
+ 0);
+ return(0);
+ }
+
+ D_LOG(D_ALWAYS, ("GetBaseConfigParams: StringLength: %d\n", ConfigParam->ParameterData.StringData.Length));
+ switch (ConfigParam->ParameterType)
+ {
+ case NdisParameterString:
+ {
+#if !BINARY_COMPATIBLE
+ ANSI_STRING AnsiRet;
+
+ RtlUnicodeStringToAnsiString(&AnsiRet, &ConfigParam->ParameterData.StringData, TRUE);
+ __strncpy(RetParam->String, AnsiRet.Buffer, AnsiRet.Length);
+ RetParam->StringLen = AnsiRet.Length;
+ RtlFreeAnsiString(&AnsiRet);
+#else
+ RetParam->StringLen = __strlen((PUCHAR)ConfigParam->ParameterData.StringData.Buffer);
+ __strncpy(RetParam->String, (PUCHAR) ConfigParam->ParameterData.StringData.Buffer, RetParam->StringLen);
+#endif
+ D_LOG(D_ALWAYS, ("GetBaseConfigParams: String: %s, Length: %d\n", RetParam->String, RetParam->StringLen));
+
+ break;
+ }
+ case NdisParameterMultiString:
+ D_LOG(D_ALWAYS, ("GetBaseConfigParams: String: %s, Length: %d\n", RetParam->String, RetParam->StringLen));
+
+#if !BINARY_COMPATIBLE
+ for (n = 0; n < RetParam->StringLen && n < ConfigParam->ParameterData.StringData.Length; n++)
+ RetParam->String[n] = (CHAR)ConfigParam->ParameterData.StringData.Buffer[n];
+
+ RetParam->StringLen = n/2;
+
+#else
+ // Ansi
+ for (n = 0; n < RetParam->StringLen && n < ConfigParam->ParameterData.StringData.Length; n++)
+ RetParam->String[n] = ((PUCHAR)ConfigParam->ParameterData.StringData.Buffer)[n];
+
+ RetParam->StringLen = n;
+
+#endif
+ for (n = 0; n < RetParam->StringLen; n++)
+ if (!__strnicmp((CHAR*)&RetParam->String[n], (CHAR*)"=", 1))
+ RetParam->String[n] = '\0';
+ break;
+
+ case NdisParameterInteger:
+ case NdisParameterHexInteger:
+ RetParam->Value = ConfigParam->ParameterData.IntegerData;
+ D_LOG(D_ALWAYS, ("GetBaseConfigParams: Integer: 0x%x\n", RetParam->Value));
+ break;
+
+ default:
+ return(0);
+ }
+ return(1);
+}
+
+#pragma NDIS_INIT_FUNCTION(GetLineConfigParams)
+
+ULONG
+GetLineConfigParams(
+ CONFIGPARAM *RetParam,
+ ULONG LineNumber,
+ CHAR *Key
+ )
+{
+ ULONG n;
+ CHAR LinePath[64];
+ NDIS_STRING KeyWord;
+ ANSI_STRING AnsiKey;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PNDIS_CONFIGURATION_PARAMETER ConfigParam;
+
+ sprintf(LinePath,
+ "%s%d.%s",
+ PCIMAC_KEY_LINE,
+ LineNumber,
+ Key);
+
+ D_LOG(D_ALWAYS, ("GetLineConfigParams: LineNumber: %d, Key: %s\n", LineNumber, Key));
+ //
+ // turn passed in key to an ansi string
+ //
+ RtlInitAnsiString(&AnsiKey, LinePath);
+
+ //
+ // allocate buffer and turn ansi to unicode
+ //
+ RtlAnsiStringToUnicodeString(&KeyWord, &AnsiKey, TRUE);
+
+ NdisReadConfiguration(&Status,
+ &ConfigParam,
+ RetParam->ConfigHandle,
+ &KeyWord,
+ RetParam->ParamType);
+
+ //
+ // free up unicode string buffer
+ //
+ RtlFreeUnicodeString(&KeyWord);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ D_LOG(D_ALWAYS, ("GetLineConfigParams: Error Reading Config: RetVal: 0x%x\n", Status));
+ if (RetParam->MustBePresent)
+ NdisWriteErrorLogEntry (RetParam->AdapterHandle,
+ NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER,
+ 0);
+ return(0);
+ }
+
+ switch (ConfigParam->ParameterType)
+ {
+ case NdisParameterString:
+ {
+#if !BINARY_COMPATIBLE
+ ANSI_STRING AnsiRet;
+
+ RtlUnicodeStringToAnsiString(&AnsiRet, &ConfigParam->ParameterData.StringData, TRUE);
+ __strncpy(RetParam->String, AnsiRet.Buffer, AnsiRet.Length);
+ RetParam->StringLen = AnsiRet.Length;
+ RtlFreeAnsiString(&AnsiRet);
+#else
+ RetParam->StringLen = __strlen((PUCHAR)ConfigParam->ParameterData.StringData.Buffer);
+ __strncpy(RetParam->String, (PUCHAR) ConfigParam->ParameterData.StringData.Buffer, RetParam->StringLen);
+#endif
+
+ D_LOG(D_ALWAYS, ("GetLineConfigParams: String: %s, Length: %d\n", RetParam->String, RetParam->StringLen));
+ break;
+ }
+
+ case NdisParameterMultiString:
+ for (n = 0; n < RetParam->StringLen && n < ConfigParam->ParameterData.StringData.Length; n++)
+ RetParam->String[n] = (CHAR)ConfigParam->ParameterData.StringData.Buffer[n];
+
+ RetParam->StringLen = n/2;
+
+ for (n = 0; n < RetParam->StringLen; n++)
+ if (!__strnicmp((CHAR*)&RetParam->String[n], (CHAR*)"=", 1))
+ RetParam->String[n] = '\0';
+ D_LOG(D_ALWAYS, ("GetBaseConfigParams: String: %s, Length: %d\n", RetParam->String, RetParam->StringLen));
+ break;
+
+ case NdisParameterInteger:
+ case NdisParameterHexInteger:
+ RetParam->Value = ConfigParam->ParameterData.IntegerData;
+ D_LOG(D_ALWAYS, ("GetLineConfigParams: Integer: 0x%x\n", RetParam->Value));
+ break;
+
+ default:
+ return(0);
+ }
+ return(1);
+}
+
+#pragma NDIS_INIT_FUNCTION(GetLTermConfigParams)
+
+ULONG
+GetLTermConfigParams(
+ CONFIGPARAM *RetParam,
+ ULONG LineNumber,
+ ULONG LTermNumber,
+ CHAR *Key
+ )
+{
+ ULONG n;
+ CHAR LTermPath[64];
+ NDIS_STRING KeyWord;
+ ANSI_STRING AnsiKey;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PNDIS_CONFIGURATION_PARAMETER ConfigParam;
+
+ D_LOG(D_ALWAYS, ("GetLTermConfigParams: LineNumber: %d, LTerm: %d, Key: %s\n", LineNumber, LTermNumber, Key));
+
+ sprintf(LTermPath,
+ "%s%d.%s%d.%s",
+ PCIMAC_KEY_LINE,
+ LineNumber,
+ PCIMAC_KEY_LTERM,
+ LTermNumber,
+ Key);
+
+ //
+ // turn passed in key to an ansi string
+ //
+ RtlInitAnsiString(&AnsiKey, LTermPath);
+
+ //
+ // allocate buffer and turn ansi to unicode
+ //
+ RtlAnsiStringToUnicodeString(&KeyWord, &AnsiKey, TRUE);
+
+ NdisReadConfiguration(&Status,
+ &ConfigParam,
+ RetParam->ConfigHandle,
+ &KeyWord,
+ RetParam->ParamType);
+
+ //
+ // free up unicode string buffer
+ //
+ RtlFreeUnicodeString(&KeyWord);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ D_LOG(D_ALWAYS, ("GetLTermConfigParams: Error Reading Config: RetVal: 0x%x\n", Status));
+ if (RetParam->MustBePresent)
+ NdisWriteErrorLogEntry (RetParam->AdapterHandle,
+ NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER,
+ 0);
+ return(0);
+ }
+
+ switch (ConfigParam->ParameterType)
+ {
+ case NdisParameterString:
+ {
+#if !BINARY_COMPATIBLE
+ ANSI_STRING AnsiRet;
+
+ RtlUnicodeStringToAnsiString(&AnsiRet, &ConfigParam->ParameterData.StringData, TRUE);
+ __strncpy(RetParam->String, AnsiRet.Buffer, AnsiRet.Length);
+ RetParam->StringLen = AnsiRet.Length;
+ RtlFreeAnsiString(&AnsiRet);
+#else
+ RetParam->StringLen = __strlen((PUCHAR)ConfigParam->ParameterData.StringData.Buffer);
+ __strncpy(RetParam->String, (PUCHAR) ConfigParam->ParameterData.StringData.Buffer, RetParam->StringLen);
+#endif
+ D_LOG(D_ALWAYS, ("GetLTermConfigParams: String: %s, Length: %d\n", RetParam->String, RetParam->StringLen));
+ break;
+ }
+
+ case NdisParameterMultiString:
+ for (n = 0; n < RetParam->StringLen && n < ConfigParam->ParameterData.StringData.Length; n++)
+ RetParam->String[n] = (CHAR)ConfigParam->ParameterData.StringData.Buffer[n];
+
+ RetParam->StringLen = n/2;
+
+ for (n = 0; n < RetParam->StringLen; n++)
+ if (!__strnicmp((CHAR*)&RetParam->String[n], (CHAR*)"=", 1))
+ RetParam->String[n] = '\0';
+ D_LOG(D_ALWAYS, ("GetLTermConfigParams: String: %s, Length: %d\n", RetParam->String, RetParam->StringLen));
+ break;
+
+ case NdisParameterInteger:
+ case NdisParameterHexInteger:
+ RetParam->Value = ConfigParam->ParameterData.IntegerData;
+ D_LOG(D_ALWAYS, ("GetLTermConfigParams: Integer: 0x%x\n", RetParam->Value));
+ break;
+
+ default:
+ return(0);
+ }
+ return(1);
+}
+
+VOID
+SetInDriverFlag (
+ ADAPTER *Adapter
+ )
+{
+ NdisAcquireSpinLock(&Pcimac.lock);
+
+ Pcimac.InDriverFlag = 1;
+
+ Pcimac.CurrentAdapter = Adapter;
+
+ Pcimac.NextAdapterToPoll++;
+
+ if (Pcimac.NextAdapterToPoll == Pcimac.NumberOfAdaptersInSystem)
+ Pcimac.NextAdapterToPoll = 0;
+
+ NdisReleaseSpinLock(&Pcimac.lock);
+}
+
+VOID
+ClearInDriverFlag (
+ ADAPTER *Adapter
+)
+{
+ NdisAcquireSpinLock(&Pcimac.lock);
+
+ Pcimac.InDriverFlag = 0;
+
+ NdisReleaseSpinLock(&Pcimac.lock);
+}
+
+ULONG
+CheckInDriverFlag (
+ ADAPTER *Adapter
+)
+{
+ ADAPTER *CurrentAdapter;
+ INT RetVal = 0;
+
+ NdisAcquireSpinLock(&Pcimac.lock);
+
+ //
+ // get the current in driver adapter
+ //
+ CurrentAdapter = (ADAPTER*)Pcimac.CurrentAdapter;
+
+ //
+ // if someone is in the driver and they are using the same
+ // shared memory window as the new prospective user send them
+ // away unhappy
+ //
+ if (Pcimac.InDriverFlag && CurrentAdapter && (Adapter->VBaseMem == CurrentAdapter->VBaseMem))
+ RetVal = 1;
+
+ NdisReleaseSpinLock(&Pcimac.lock);
+
+ return(RetVal);
+}
+
+#pragma NDIS_INIT_FUNCTION(IdpGetEaddrFromNvram)
+
+/*
+ * get ethernet address(s) out on nvram & register
+ *
+ * note that line number inside board (bline) argument was added here.
+ * for each idd installed, this function is called to add two ethernet
+ * addresses associated with it (it's two B channels - or it's capability to
+ * handle two connections). All ethernet address are derived from the
+ * single address stored starting at nvram address 8. since the manufecturer
+ * code is the first 3 bytes, we must not modify these bytes. therefor,
+ * addresses are generated by indexing the 4'th byte by bline*2 (need two
+ * address - remember?).
+ */
+VOID
+IdpGetEaddrFromNvram(
+ IDD *idd,
+ CM *cm,
+ USHORT Line,
+ USHORT LineIndex
+ )
+{
+ UCHAR eaddr[6];
+ USHORT nvval;
+
+ /* extract original stored ethernet address */
+ idd_get_nvram(idd, (USHORT)(8), &nvval);
+ eaddr[0] = LOBYTE(nvval);
+ eaddr[1] = HIBYTE(nvval);
+ idd_get_nvram(idd, (USHORT)(9), &nvval);
+ eaddr[2] = LOBYTE(nvval);
+ eaddr[3] = HIBYTE(nvval);
+ idd_get_nvram(idd, (USHORT)(10), &nvval);
+ eaddr[4] = LOBYTE(nvval);
+ eaddr[5] = HIBYTE(nvval);
+
+ /* create derived address and store it */
+ eaddr[3] += (Line * 2) + LineIndex;
+
+ NdisMoveMemory(cm->SrcAddr, eaddr, sizeof(cm->SrcAddr));
+} // end IdpGetEaddrFromNvram
+
+#pragma NDIS_INIT_FUNCTION(AdpGetEaddrFromNvram)
+
+/*
+ * get ethernet address(s) out on nvram & register
+ *
+ * note that line number inside board (bline) argument was added here.
+ * for each idd installed, this function is called to add two ethernet
+ * addresses associated with it (it's two B channels - or it's capability to
+ * handle two connections). All ethernet address are derived from the
+ * single address stored starting at nvram address 8. since the manufecturer
+ * code is the first 3 bytes, we must not modify these bytes. therefor,
+ * addresses are generated by indexing the 4'th byte by bline*2 (need two
+ * address - remember?).
+ */
+VOID
+AdpGetEaddrFromNvram(
+ IDD *idd,
+ CM *cm,
+ USHORT Line,
+ USHORT LineIndex
+ )
+{
+ UCHAR eaddr[6];
+ USHORT nvval;
+
+ //
+ // the MAC address lines at offset 0x950 in the onboard memory
+ // this is NVRAM_WINDOW 0x940 + 0x10
+ //
+ idd_get_nvram(idd, (USHORT)(0x10), &nvval);
+ eaddr[0] = LOBYTE(nvval);
+ eaddr[1] = HIBYTE(nvval);
+ idd_get_nvram(idd, (USHORT)(0x12), &nvval);
+ eaddr[2] = LOBYTE(nvval);
+ eaddr[3] = HIBYTE(nvval);
+ idd_get_nvram(idd, (USHORT)(0x14), &nvval);
+ eaddr[4] = LOBYTE(nvval);
+ eaddr[5] = HIBYTE(nvval);
+
+ /* create derived address and store it */
+ eaddr[3] += (Line * 2) + LineIndex;
+
+ NdisMoveMemory(cm->SrcAddr, eaddr, sizeof(cm->SrcAddr));
+} // end AdpGetEaddrFromNvram
+
+#ifdef OLD
+ULONG
+EnumAdaptersInSystem()
+{
+ ULONG n, NumAdapters = 0;
+
+ for (n = 0; n < MAX_ADAPTERS_IN_SYSTEM; n++)
+ {
+ if (Pcimac.AdapterTbl[n])
+ NumAdapters++;
+ }
+ return(NumAdapters);
+}
+#endif
+
+ULONG
+EnumAdaptersInSystem()
+{
+ ULONG NumAdapters;
+
+ NdisAcquireSpinLock(&Pcimac.lock);
+
+ NumAdapters = Pcimac.NumberOfAdaptersInSystem;
+
+ NdisReleaseSpinLock(&Pcimac.lock);
+
+ return(NumAdapters);
+}
+
+ADAPTER*
+GetAdapterByIndex(
+ ULONG Index
+ )
+{
+ ADAPTER *Adapter;
+
+ NdisAcquireSpinLock(&Pcimac.lock);
+
+ Adapter = Pcimac.AdapterTbl[Index];
+
+ NdisReleaseSpinLock(&Pcimac.lock);
+
+ return(Adapter);
+}
+
+INT
+IoEnumAdapter(VOID *cmd_1)
+{
+ IO_CMD *cmd = (IO_CMD*)cmd_1;
+ ULONG n, m, NumberOfAdapters;
+
+ NumberOfAdapters = cmd->val.enum_adapters.num = (USHORT)EnumAdaptersInSystem();
+
+ for (n = 0, m = 0; n < NumberOfAdapters; n++)
+ {
+ ADAPTER *Adapter = GetAdapterByIndex(n);
+
+ if (Adapter)
+ {
+ cmd->val.enum_adapters.BaseIO[m] = Adapter->BaseIO;
+ cmd->val.enum_adapters.BaseMem[m] = Adapter->BaseMem;
+ cmd->val.enum_adapters.BoardType[m] = Adapter->BoardType;
+ NdisMoveMemory (&cmd->val.enum_adapters.Name[m], Adapter->Name, sizeof(cmd->val.enum_adapters.Name[n]));
+ cmd->val.enum_adapters.tbl[m] = Adapter;
+ m++;
+ }
+ }
+
+ return(0);
+}
+
+VOID
+AdapterDestroy(
+ ADAPTER *Adapter
+ )
+{
+ ULONG n;
+
+ for (n = 0; n < MAX_ADAPTERS_IN_SYSTEM; n++)
+ {
+ if (Adapter == Pcimac.AdapterTbl[n])
+ break;
+ }
+
+ if (n == MAX_ADAPTERS_IN_SYSTEM)
+ return;
+
+ //
+ // stop idd timers
+ //
+ StopTimers(Adapter);
+
+ Pcimac.AdapterTbl[n] = NULL;
+
+ Pcimac.NumberOfAdaptersInSystem--;
+
+ //
+ // if we have successfully mapped our base i/o then we need to release
+ //
+ if (Adapter->VBaseIO)
+ {
+ //
+ // deregister adapters I/O and memory
+ //
+ NdisMDeregisterIoPortRange((NDIS_HANDLE)Adapter->Handle,
+ Adapter->BaseIO,
+ 8,
+ Adapter->VBaseIO);
+ }
+
+ //
+ // if we have successfully mapped our base memory then we need to release
+ //
+ if (Adapter->VBaseMem)
+ {
+ NdisMUnmapIoSpace((NDIS_HANDLE)Adapter->Handle,
+ Adapter->VBaseMem,
+ 0x4000);
+ }
+
+// NdisFreeSpinLock(&Adapter->lock);
+
+ NdisFreeMemory(Adapter, sizeof(ADAPTER), 0);
+}
+
+#pragma NDIS_INIT_FUNCTION(StartTimers)
+
+VOID
+StartTimers(
+ ADAPTER *Adapter
+ )
+{
+ NdisMSetTimer(&Adapter->IddPollTimer, IDD_POLL_T);
+ NdisMSetTimer(&Adapter->MtlPollTimer, MTL_POLL_T);
+ NdisMSetTimer(&Adapter->CmPollTimer, CM_POLL_T);
+}
+
+VOID
+StopTimers(
+ ADAPTER *Adapter
+ )
+{
+ BOOLEAN TimerCanceled;
+
+ NdisMCancelTimer(&Adapter->IddPollTimer, &TimerCanceled);
+ NdisMCancelTimer(&Adapter->MtlPollTimer, &TimerCanceled);
+ NdisMCancelTimer(&Adapter->CmPollTimer, &TimerCanceled);
+}
+
+#pragma NDIS_INIT_FUNCTION(IdpCheckIO)
+
+ULONG
+IdpCheckIO(IDD *idd)
+{
+ ULONG ReturnValue = 1;
+
+ //
+ // check for board at this I/O address
+ //
+ if (idd->btype == IDD_BT_PCIMAC || idd->btype == IDD_BT_PCIMAC4)
+ {
+ UCHAR BoardID;
+
+ BoardID = (idd->InFromPort(idd, 5) & 0x0F);
+
+ if ( ((idd->btype == IDD_BT_PCIMAC) && (BoardID == 0x02)) ||
+ ((idd->btype == IDD_BT_PCIMAC4) && (BoardID == 0x04)))
+ ReturnValue = 0;
+ }
+ else if( idd->btype == IDD_BT_MCIMAC )
+ ReturnValue = 0;
+
+ return(ReturnValue);
+}
+
+#pragma NDIS_INIT_FUNCTION(AdpCheckIO)
+
+ULONG
+AdpCheckIO(IDD *idd)
+{
+ UCHAR BoardId = idd->InFromPort(idd, ADP_REG_ID);
+
+ D_LOG(D_ENTRY, ("AdpCheckIO: entry, idd: 0x%lx BoardType: %d\n", idd, idd->btype));
+
+ D_LOG(D_ALWAYS, ("AdpCheckIO: ADP_REG_ID: %d\n", BoardId));
+
+ switch( idd->btype )
+ {
+ case IDD_BT_DATAFIREU:
+ case IDD_BT_DATAFIREST:
+ if (BoardId != ADP_BT_ADP1)
+ return(1);
+ break;
+
+ case IDD_BT_DATAFIRE4ST:
+ if (BoardId != ADP_BT_ADP4)
+ return(1);
+ break;
+ }
+
+ return( 0 );
+}
+
+#pragma NDIS_INIT_FUNCTION(IdpCheckMem)
+
+ULONG
+IdpCheckMem(IDD *idd)
+{
+ return(0);
+}
+
+#pragma NDIS_INIT_FUNCTION(AdpCheckMem)
+
+ULONG
+AdpCheckMem(IDD *idd)
+{
+ return(0);
+
+}
+
+
+NTSTATUS PcimacInitMCA( NDIS_HANDLE AdapterHandle,
+ PULONG BaseIO,
+ PULONG BaseMemory,
+ ULONG SlotNumber )
+/*++
+
+Routine Description:
+
+ This routine will be called if it is determined the type of bus
+ is MCA. We verify that the controller is actually a DigiBoard
+ PCIMAC controller, read the POS to determine the I/O address and
+ Memory Mapped address, so the initialization process can continue.
+
+Arguments:
+
+ AdapterHandle - Handle passed in the initialization routine. Required
+ so mapping of POS I/O ports can take place.
+
+ BaseIO - Pointer where the adapters base I/O address is passed back.
+
+ BaseMemory - Pointer where the adapters base memory address is passed back.
+
+ SlotNumber - Number indicating what slot this MCA adapter should be in.
+
+Return Value:
+
+ STATUS_SUCCESS - If we were able to complete successfully
+
+ ?? - We were not able to get the information required to continue.
+
+--*/
+{
+#define PcimacPOSID 0x7F9E
+#define MCA_BASE_POS_IO_PORT 0x96
+#define MCA_INFO_POS_IO_PORT 0x100
+
+#define MCA_IO_PORT_MASK 0x0070
+
+ USHORT ActualPosId, POSConfig;
+ USHORT IOPortOffset;
+ ULONG MemoryAddress;
+
+ PVOID VirtualPOSBaseAddress; // Virtual address
+ PVOID VirtualPOSInfoAddress; // Virtual address
+
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ UCHAR OneByte;
+
+ //
+ // We need to read the POS Adapter ID and make sure the controller
+ // is one of ours. Use the Slot number and the POS ID we
+ // installed during configuration from the registry.
+ //
+
+ DigiDump( DIGIINIT, ("Pcimac: PcimacPOSID: 0x%x\n",
+ PcimacPOSID) );
+
+ DigiDump( DIGIINIT, ("--------- SlotNumber: 0x%x\n",
+ SlotNumber) );
+
+ *BaseIO = 0;
+ *BaseMemory = 0;
+
+ Status = NdisMRegisterIoPortRange( &VirtualPOSBaseAddress,
+ AdapterHandle,
+ MCA_BASE_POS_IO_PORT,
+ 1 );
+
+ if( Status != NDIS_STATUS_SUCCESS )
+ {
+ NdisWriteErrorLogEntry(AdapterHandle,
+ NDIS_ERROR_CODE_BAD_IO_BASE_ADDRESS,
+ 0);
+ goto PcimacInitMCAExit;
+ }
+
+ Status = NdisMRegisterIoPortRange( &VirtualPOSInfoAddress,
+ AdapterHandle,
+ MCA_INFO_POS_IO_PORT,
+ 1 );
+
+ if( Status != NDIS_STATUS_SUCCESS )
+ {
+ NdisWriteErrorLogEntry(AdapterHandle,
+ NDIS_ERROR_CODE_BAD_IO_BASE_ADDRESS,
+ 0);
+ goto PcimacInitMCAExit;
+ }
+
+
+ // Enable the POS information for the slot we are interested in.
+ NdisRawWritePortUchar( VirtualPOSBaseAddress, (UCHAR)(SlotNumber + 7) );
+
+ NdisRawReadPortUchar( (PVOID)((ULONG)VirtualPOSInfoAddress + 1),
+ (PUCHAR)&OneByte );
+ ActualPosId = ((USHORT)OneByte << 8);
+ NdisRawReadPortUchar( VirtualPOSInfoAddress, (PUCHAR)&OneByte );
+ ActualPosId |= OneByte;
+
+ DigiDump( DIGIINIT, ("POS Adapter ID = 0x%hx\n", ActualPosId) );
+
+ if( ActualPosId != PcimacPOSID )
+ {
+ NdisWriteErrorLogEntry(AdapterHandle,
+ NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
+ 0);
+ Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+ goto PcimacInitMCAError2;
+ }
+
+ //
+ // Clear the VPD.
+ //
+ NdisRawWritePortUchar( (ULONG)VirtualPOSInfoAddress + 6, 0 );
+
+ NdisRawReadPortUchar( (ULONG)VirtualPOSInfoAddress + 4,
+ (PUCHAR)&OneByte );
+ MemoryAddress = ((ULONG)OneByte << 22);
+ NdisRawReadPortUchar( (ULONG)VirtualPOSInfoAddress + 3,
+ (PUCHAR)&OneByte );
+ MemoryAddress |= ((ULONG)OneByte << 14);
+
+ NdisRawReadPortUchar( (ULONG)VirtualPOSInfoAddress + 2,
+ (PUCHAR)&OneByte );
+ POSConfig = OneByte;
+
+ IOPortOffset = (POSConfig & MCA_IO_PORT_MASK) >> 4;
+
+ DigiDump( DIGIINIT, ("POS config read = 0x%hx\n"
+ " IOPortOffset = 0x%hx, MemoryAddress = 0x%x,"
+ " IOPort = 0x%hx\n",
+ POSConfig, IOPortOffset, MemoryAddress,
+ MCAIOAddressTable[IOPortOffset]) );
+
+ *BaseIO = MCAIOAddressTable[IOPortOffset];
+
+ *BaseMemory = MemoryAddress;
+
+ // Disable the POS information.
+ NdisRawWritePortUchar( VirtualPOSBaseAddress, 0 );
+
+ //
+ // Unmap the POS register
+ //
+
+PcimacInitMCAError2:;
+
+ NdisMDeregisterIoPortRange( AdapterHandle,
+ MCA_INFO_POS_IO_PORT,
+ 1,
+ VirtualPOSInfoAddress );
+
+ NdisMDeregisterIoPortRange( AdapterHandle,
+ MCA_BASE_POS_IO_PORT,
+ 1,
+ VirtualPOSBaseAddress );
+
+PcimacInitMCAExit:;
+
+ return( Status );
+} // end PcimacInitMCA
+
+
+
diff --git a/private/ntos/ndis/digi/pcimac/pcimac.rc b/private/ntos/ndis/digi/pcimac/pcimac.rc
new file mode 100644
index 000000000..9d4532558
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/pcimac.rc
@@ -0,0 +1,28 @@
+#if !BINARY_COMPATIBLE
+#include <winver.h>
+#else
+#include <windows.h>
+#endif
+
+#include <ntverp.h>
+
+#ifdef VER_COMPANYNAME_STR
+#undef VER_COMPANYNAME_STR
+#endif
+#define VER_COMPANYNAME_STR "Digi International Inc."
+
+#define VER_LEGALCOPYRIGHT_YEARS "1992-1996"
+
+#define VER_LEGALCOPYRIGHT_STR "Copyright " VER_LEGALCOPYRIGHT_YEARS ", Digi International Inc. All rights reserved."
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+#define VER_FILEDESCRIPTION_STR "Digi BRI-ISDN Adapter Device Driver"
+#define VER_INTERNALNAME_STR "pcimac.sys"
+#define VER_ORIGINALFILENAME_STR "pcimac.sys"
+
+#define VER_FILEVERSION 2.5.0.3
+#define VER_FILEVERSION_STR "v2.5.0.3 (E)"
+
+#include "common.ver"
+
diff --git a/private/ntos/ndis/digi/pcimac/res.h b/private/ntos/ndis/digi/pcimac/res.h
new file mode 100644
index 000000000..15bd9f5d0
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/res.h
@@ -0,0 +1,52 @@
+/*
+ * RES.H - Resource ownership classe, master include file
+ */
+
+
+#ifndef _RES_
+#define _RES_
+
+/* resource classes */
+#define RES_CLASS_MEM 0
+#define RES_CLASS_IO 1
+
+/* return values */
+#define RES_E_SUCC 0
+#define RES_E_NOMEM 1
+
+// Return Values for GetResourceSem
+#define RES_BUSY 0
+#define RES_FREE 1
+
+/* resource structure */
+typedef struct _RES
+{
+ ULONG class; /* resource class */
+ ULONG id; /* resource id (value) */
+ ULONG data; /* resource attached data */
+
+ ULONG cre_ref; /* creation refrence */
+ ULONG own_ref; /* ownership refrence */
+
+ VOID *owner; /* current owner, NULL == none */
+
+ NDIS_SPIN_LOCK lock; /* scheduling lock */
+
+ SEMA proc_sema; /* processing sema */
+
+} RES;
+
+
+/* operations */
+INT res_init(VOID);
+VOID res_term(VOID);
+RES* res_create(ULONG class, ULONG id);
+INT res_destroy(VOID* res_1);
+VOID res_own(VOID* res_1, VOID *owner);
+VOID res_unown(VOID* res_1, VOID *owner);
+VOID res_get_data(VOID* res_1, ULONG* data);
+VOID res_set_data(VOID* res_1, ULONG data);
+INT GetResourceSem (VOID*);
+VOID FreeResourceSem (VOID*);
+
+#endif /* _RES_ */
diff --git a/private/ntos/ndis/digi/pcimac/res_core.c b/private/ntos/ndis/digi/pcimac/res_core.c
new file mode 100644
index 000000000..892b4f325
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/res_core.c
@@ -0,0 +1,261 @@
+/*
+ * RES_CORE.C - Resource ownership class, implementation
+ *
+ * as defined here, a resource has a class and an id (value). one ULONG
+ * of data may be attached to a resource.
+ *
+ * objects create a reference (handle) to the resource using res_create
+ * and free it using res_destroy. multiple objects may create references
+ * to the same object.
+ *
+ * ownership is aquired using res_own and released using res_unown. if
+ * an object already owns a resource, it may own it again (class keeps
+ * a refrence count). if an object (thread) asks for ownership of an
+ * already owned resource, if is suspended (using NdisAquireSpinLock)
+ */
+
+#include <ndis.h>
+#include <ndiswan.h>
+#include <mydefs.h>
+#include <mytypes.h>
+#include <util.h>
+#include <adapter.h>
+#include <idd.h>
+#include <cm.h>
+#include <mtl.h>
+#include <res.h>
+#include <disp.h>
+
+/* system limits */
+#define MAX_RES 128
+
+/* assists */
+//#define LOCK NdisAcquireSpinLock(&res__lock)
+//#define UNLOCK NdisReleaseSpinLock(&res__lock)
+
+/* global variables */
+NDIS_SPIN_LOCK res__lock; /* management lock */
+RES *res__tbl;
+
+/* initialize support */
+INT
+res_init(VOID)
+{
+ NDIS_PHYSICAL_ADDRESS pa = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
+
+ /* allocate memory object */
+ NdisAllocateMemory((PVOID*)&res__tbl, (sizeof(RES) * MAX_RES), 0, pa);
+ if ( !res__tbl )
+ {
+ D_LOG(D_ALWAYS, ("res_init: memory allocate failed!"));
+ return(RES_E_NOMEM);
+ }
+ D_LOG(D_ALWAYS, ("res_init: res__tbl: 0x%lx", res__tbl));
+
+ NdisZeroMemory (res__tbl, sizeof(RES) * MAX_RES);
+// NdisAllocateSpinLock(&res__lock);
+ return(RES_E_SUCC);
+}
+
+/* terminate support */
+VOID
+res_term(VOID)
+{
+// DbgPrint ("Resource Term: Entry\n");
+// NdisFreeSpinLock(&res__lock);
+ /* free memory */
+ NdisFreeMemory(res__tbl, (sizeof(RES) * MAX_RES), 0);
+}
+
+/* create a (refrence to a ) resource */
+RES*
+res_create(ULONG class, ULONG id)
+{
+ RES *res;
+ INT n;
+
+// LOCK;
+
+// DbgPrint ("Resource Create: class: 0x%x, id: 0x%x\n",class, id);
+// DbgPrint ("IRQL: 0x%x\n",KeGetCurrentIrql());
+ /* scan for a matching slot */
+ for ( n = 0 ; n < MAX_RES ; n++ )
+ {
+ res = res__tbl + n;
+
+ if ( res->cre_ref && (res->class == class) && (res->id == id) )
+ {
+ /* found an already existing resource */
+// DbgPrint ("Resource Create: resource already exists!\n");
+ res->cre_ref++;
+ break;
+ }
+ }
+
+ /* if no such, try to create a new one */
+ if (n >= MAX_RES)
+ for ( n = 0 ; n < MAX_RES ; n++ )
+ {
+ res = res__tbl + n;
+
+ if ( !res->cre_ref )
+ {
+// DbgPrint ("Resource Create: resource created!\n");
+ /* found a free slot, fill */
+ res->cre_ref++;
+ res->class = class;
+ res->id = id;
+ res->data = 0;
+ res->own_ref = 0;
+ NdisAllocateSpinLock(&res->lock);
+ /* init sema */
+ sema_init(&res->proc_sema);
+ break;
+ }
+ }
+
+// UNLOCK;
+// DbgPrint ("Resource Create exit: res: 0x%lx refcount: %d\n",res, res->cre_ref);
+// DbgPrint (": IRQL: 0x%x\n",KeGetCurrentIrql());
+ return(res);
+}
+
+/* free (a refrence to) a resource, return 1 if really destroyed */
+INT
+res_destroy(VOID *res_1)
+{
+ RES *res = (RES*)res_1;
+ INT really = 0;
+
+// LOCK;
+
+// DbgPrint ("Resource Destroy: Entry res: 0x%lx, refcount: %d\n",res, res->cre_ref);
+// DbgPrint (": IRQL: 0x%x\n",KeGetCurrentIrql());
+ /* decrement refrence count, if down to zero, free */
+ res->cre_ref--;
+ if ( !res->cre_ref )
+ {
+ NdisFreeSpinLock(&res->lock);
+ sema_term (&res->proc_sema);
+ really = 1;
+ }
+
+// UNLOCK;
+// DbgPrint ("Resource Destroy: Exit\n");
+// DbgPrint (": IRQL: 0x%x\n",KeGetCurrentIrql());
+ return(really);
+}
+
+/* establish owership for a resource */
+VOID
+res_own(VOID *res_1, VOID *owner)
+{
+ RES *res = (RES*)res_1;
+// LOCK;
+
+// DbgPrint("res_own: enter, res: 0x%lx, owner: 0x%lx, owner ref: %d\n", res, res->owner, res->own_ref);
+// DbgPrint (": IRQL: 0x%x\n",KeGetCurrentIrql());
+
+ /* if not owned, get it */
+ if ( !res->own_ref )
+ {
+ NdisAcquireSpinLock(&res->lock);
+ res->own_ref++;
+ res->owner = owner;
+ goto bye;
+ }
+
+ /* check if already owned by self */
+ if ( res->owner == owner )
+ goto bye;
+
+ /* else we have to wait for it */
+// UNLOCK;
+ NdisAcquireSpinLock(&res->lock);
+// LOCK;
+
+ /* no I have it, fill */
+ res->own_ref++;
+ res->owner = owner;
+
+ bye:
+// UNLOCK;
+// DbgPrint("res_own: exit, res: 0x%lx, owner: 0x%lx, owner ref: %d\n", res, res->owner, res->own_ref);
+// DbgPrint (": IRQL: 0x%x\n",KeGetCurrentIrql());
+ return;
+}
+
+/* release ownership of a resource, it is assumed that owner is releasing */
+VOID
+res_unown(VOID *res_1, VOID *owner)
+{
+ RES *res = (RES*)res_1;
+// LOCK;
+
+// DbgPrint("res_unown: entry, res: 0x%lx, owner: 0x%lx owner ref: %d\n", res, owner, res->own_ref);
+// DbgPrint (": IRQL: 0x%x\n",KeGetCurrentIrql());
+
+ if (!res->own_ref)
+ {
+ /* if free, onwership released */
+// UNLOCK;
+ return;
+ }
+
+ /* decrement ownership count, if not down to zero - still owned */
+ res->own_ref--;
+
+ if ( res->own_ref )
+ {
+// UNLOCK;
+ return;
+ }
+
+ res->owner = NULL;
+
+ NdisReleaseSpinLock(&res->lock);
+
+ /* if free, onwership released */
+// UNLOCK;
+
+// DbgPrint("res_unown: exit, res: 0x%lx, owner ref: %d\n", res, res->own_ref);
+// DbgPrint (": IRQL: 0x%x\n",KeGetCurrentIrql());
+}
+
+
+
+/* get private data for a resource */
+VOID
+res_get_data(VOID *res_1, ULONG *data)
+{
+ RES *res = (RES*)res_1;
+ *data = res->data;
+}
+
+
+/* set private data for a resource */
+VOID
+res_set_data(VOID *res_1, ULONG data)
+{
+ RES *res = (RES*)res_1;
+ res->data = data;
+}
+
+INT
+GetResourceSem (VOID *Resource)
+{
+ RES *res = (RES*)Resource;
+
+ if ( !sema_get(&res->proc_sema) )
+ return(RES_BUSY);
+ else
+ return(RES_FREE);
+}
+
+VOID
+FreeResourceSem (VOID *Resource)
+{
+ RES *res = (RES*)Resource;
+ sema_free(&res->proc_sema);
+}
+
diff --git a/private/ntos/ndis/digi/pcimac/sema.h b/private/ntos/ndis/digi/pcimac/sema.h
new file mode 100644
index 000000000..97e70f200
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/sema.h
@@ -0,0 +1,8 @@
+/*
+ * SEMA.H - simple semaphores
+ */
+
+#ifndef _SEMA_
+#define _SEMA_
+
+#endif /* _SEMA */
diff --git a/private/ntos/ndis/digi/pcimac/sources b/private/ntos/ndis/digi/pcimac/sources
new file mode 100644
index 000000000..edece9873
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/sources
@@ -0,0 +1,74 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=pcimac
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib \
+ ..\lib\*\digifile.lib
+
+!IF 0
+ The order of the following include file paths is important
+!ENDIF
+INCLUDES=..\inc;$(BASEDIR)\private\ntos\inc
+
+C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER -DBINARY_COMPATIBLE=0
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES= \
+ pcimac.c \
+ ansihelp.c \
+ idd_init.c \
+ idd_nv.c \
+ idd_io.c \
+ idd_run.c \
+ idd_proc.c \
+ idd_msg.c \
+ mtl_tx.c \
+ mtl_init.c \
+ mtl_set.c \
+ mtl_rx.c \
+ mtl_tick.c \
+ cm_init.c \
+ cm_prof.c \
+ cm_stat.c \
+ cm_timer.c \
+ cm_state.c \
+ cm_q931.c \
+ cm_conn.c \
+ cm_chan.c \
+ res_core.c \
+ io_core.c \
+ wan_conn.c \
+ trc_core.c \
+ util.c \
+ wanoid.c \
+ tapioid.c \
+ lanoid.c \
+ pcimac.rc
+# disp.c \
+
+
+RELATIVE_DEPTH=..\..
diff --git a/private/ntos/ndis/digi/pcimac/tapioid.c b/private/ntos/ndis/digi/pcimac/tapioid.c
new file mode 100644
index 000000000..f9dd9fa99
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/tapioid.c
@@ -0,0 +1,2535 @@
+//
+// Tapioid.c - File contains all functions that handle NDIS_OID's that
+// come from the connection wrapper.
+//
+//
+//
+//
+#include <ndis.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <adapter.h>
+#include <util.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+#include <res.h>
+#include <trc.h>
+#include <io.h>
+#include <tapioid.h>
+
+#include <ansihelp.h>
+
+
+typedef struct tagOID_DISPATCH
+{
+ ULONG Oid;
+ NDIS_STATUS (*FuncPtr)();
+}OID_DISPATCH;
+
+//
+// Tapi OID's
+//
+static OID_DISPATCH TapiOids[] =
+ {
+ {OID_TAPI_ACCEPT, TSPI_LineAccept},
+ {OID_TAPI_ANSWER, TSPI_LineAnswer},
+ {OID_TAPI_CLOSE, TSPI_LineClose},
+ {OID_TAPI_CLOSE_CALL, TSPI_LineCloseCall},
+ {OID_TAPI_CONDITIONAL_MEDIA_DETECTION, TSPI_LineConditionalMediaDetect},
+ {OID_TAPI_CONFIG_DIALOG, TSPI_LineConfigDialog},
+ {OID_TAPI_DEV_SPECIFIC, TSPI_LineDevSpecific},
+ {OID_TAPI_DIAL, TSPI_LineDial},
+ {OID_TAPI_DROP, TSPI_LineDrop},
+ {OID_TAPI_GET_ADDRESS_CAPS, TSPI_LineGetAddressCaps},
+ {OID_TAPI_GET_ADDRESS_ID, TSPI_LineGetAddressID},
+ {OID_TAPI_GET_ADDRESS_STATUS, TSPI_LineGetAddressStatus},
+ {OID_TAPI_GET_CALL_ADDRESS_ID, TSPI_LineGetCallAddressID},
+ {OID_TAPI_GET_CALL_INFO, TSPI_LineGetCallInfo},
+ {OID_TAPI_GET_CALL_STATUS, TSPI_LineGetCallStatus},
+ {OID_TAPI_GET_DEV_CAPS, TSPI_LineGetDevCaps},
+ {OID_TAPI_GET_DEV_CONFIG, TSPI_LineGetDevConfig},
+ {OID_TAPI_GET_EXTENSION_ID, TSPI_LineGetExtensionID},
+ {OID_TAPI_GET_ID, TSPI_LineGetID},
+ {OID_TAPI_GET_LINE_DEV_STATUS, TSPI_LineGetLineDevStatus},
+ {OID_TAPI_MAKE_CALL, TSPI_LineMakeCall},
+ {OID_TAPI_NEGOTIATE_EXT_VERSION, TSPI_LineNegotiateExtVersion},
+ {OID_TAPI_OPEN, TSPI_LineOpen},
+ {OID_TAPI_PROVIDER_INITIALIZE, TSPI_ProviderInit},
+ {OID_TAPI_PROVIDER_SHUTDOWN, TSPI_ProviderShutdown},
+ {OID_TAPI_SECURE_CALL, TSPI_LineSecureCall},
+ {OID_TAPI_SELECT_EXT_VERSION, TSPI_LineSelectExtVersion},
+ {OID_TAPI_SEND_USER_USER_INFO, TSPI_LineSendUserToUserInfo},
+ {OID_TAPI_SET_APP_SPECIFIC, TSPI_LineSetAppSpecific},
+ {OID_TAPI_SET_CALL_PARAMS, TSPI_LineSetCallParams},
+ {OID_TAPI_SET_DEFAULT_MEDIA_DETECTION, TSPI_LineSetDefaultMediaDetection},
+ {OID_TAPI_SET_DEV_CONFIG, TSPI_LineSetDevConfig},
+ {OID_TAPI_SET_MEDIA_MODE, TSPI_LineSetMediaMode},
+ {OID_TAPI_SET_STATUS_MESSAGES, TSPI_LineSetStatusMessage}
+ };
+
+#define MAX_TAPI_SUPPORTED_OIDS 34
+
+
+VOID
+(*CallStateProc[MAX_STATE][MAX_STATE])(CM*) =
+{
+ //
+ // LINE_ST_IDLE
+ //
+ {
+ NoSignal, // LINE_ST_IDLE
+ NoSignal, // LINE_ST_LISTEN
+ SignalCallProceeding, // LINE_ST_WAITCONN
+ SignalConnectSuccess, // LINE_ST_CONN
+ },
+
+ //
+ // LINE_ST_LISTEN
+ //
+ {
+ SignalListenFailure, // LINE_ST_IDLE
+ NoSignal, // LINE_ST_LISTEN
+ NoSignal, // LINE_ST_WAITCONN
+ SignalListenSuccess // LINE_ST_CONN
+ },
+
+ //
+ // LINE_ST_WAITCONN
+ //
+ {
+ SignalConnectFailure, // LINE_ST_IDLE
+ NoSignal, // LINE_ST_LISTEN
+ SignalCallProceeding, // LINE_ST_WAITCONN
+ SignalConnectSuccess // LINE_ST_CONN
+ },
+
+ //
+ // LINE_ST_CONN
+ //
+ {
+ SignalDisconnect, // LINE_ST_IDLE (only for incoming disconnect)
+ NoSignal, // LINE_ST_LISTEN
+ NoSignal, // LINE_ST_WAITCONN
+ NoSignal // LINE_ST_CONN
+ }
+};
+
+NDIS_STATUS
+TapiOidProc(
+ NDIS_HANDLE AdapterContext,
+ NDIS_OID Oid,
+ PVOID InfoBuffer,
+ ULONG InfoBufferLen,
+ PULONG BytesReadWritten,
+ PULONG BytesNeeded
+ )
+{
+ ADAPTER *Adapter = (ADAPTER*)AdapterContext;
+ ULONG n;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ for (n = 0; n < MAX_TAPI_SUPPORTED_OIDS; n++)
+ {
+ if (Oid == TapiOids[n].Oid)
+ {
+ Status = (*TapiOids[n].FuncPtr)(Adapter, InfoBuffer);
+ return(Status);
+ }
+ }
+ return(NDIS_STATUS_INVALID_OID);
+}
+
+
+NDIS_STATUS
+TSPI_LineAccept(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_ACCEPT TapiBuffer = (PNDIS_TAPI_ACCEPT)InfoBuffer;
+
+ D_LOG(D_ENTRY, ("LineAccept: hdCall: 0x%lx", TapiBuffer->hdCall));
+
+// return(NDIS_STATUS_TAPI_OPERATIONUNAVAIL);
+ return(NDIS_STATUS_SUCCESS);
+
+}
+
+NDIS_STATUS
+TSPI_LineAnswer(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_ANSWER TapiBuffer = (PNDIS_TAPI_ANSWER)InfoBuffer;
+ TAPI_LINE_INFO* TapiLineInfo;
+ CM *cm;
+ CM_PROF *Prof;
+ ULONG Param1 = 0, Param2 = 0, Param3 = 0, m, n;
+
+ D_LOG(D_ENTRY, ("LineAnwser: hdCall: 0x%lx", TapiBuffer->hdCall));
+ //
+ // validate call handle and get call pointer
+ //
+ cm = GetCallFromCallHandle(Adapter, TapiBuffer->hdCall);
+
+ if (cm == NULL)
+ return(NDIS_STATUS_TAPI_INVALCALLHANDLE);
+
+ //
+ // get the profile pointer for this call
+ //
+ Prof = (CM_PROF*)&cm->dprof;
+
+ TapiLineInfo = (TAPI_LINE_INFO*)cm->TapiLineInfo;
+
+ cm->TapiCallState = LINECALLSTATE_CONNECTED;
+
+ //
+ // indicate line event with callstate connected
+ //
+ Param1 = cm->TapiCallState;
+ Param3 = LINEMEDIAMODE_DIGITALDATA;
+ SendLineEvent(Adapter,
+ TapiLineInfo->htLine,
+ cm->htCall,
+ LINE_CALLSTATE,
+ &Param1,
+ &Param2,
+ &Param3);
+
+ mtl_set_conn_state(cm->mtl, Prof->chan_num, 1);
+
+ //
+ // indicate line up to wan wrapper
+ //
+ WanLineup(cm, NULL);
+
+ //
+ // mark idd resources as being in use
+ //
+ for (n = 0; n < Prof->chan_num; n++)
+ {
+ IDD *idd = Prof->chan_tbl[n].idd;
+
+ //
+ // this idd should not be busy yet
+ //
+ if (idd->CallInfo.ChannelsUsed < MAX_CHANNELS_PER_IDD)
+ {
+ //
+ // each idd can support two calls
+ //
+ for (m = 0; m < MAX_CHANNELS_PER_IDD; m++)
+ {
+ if (idd->CallInfo.cm[m] == NULL)
+ {
+ idd->CallInfo.cm[m] = cm;
+ idd->CallInfo.ChannelsUsed++;
+ break;
+ }
+ }
+ }
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineClose(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_CLOSE TapiBuffer = (PNDIS_TAPI_CLOSE)InfoBuffer;
+ TAPI_LINE_INFO* TapiLineInfo;
+ ULONG n;
+ CM *cm;
+
+ D_LOG(D_ENTRY, ("LineClose: hdLine: 0x%lx", TapiBuffer->hdLine));
+
+ //
+ // validate line handle and get line pointer
+ //
+ TapiLineInfo = GetLineFromLineHandle(Adapter, TapiBuffer->hdLine);
+
+ if (TapiLineInfo == NULL)
+ return(NDIS_STATUS_FAILURE);
+
+ //
+ // store lineinfo pointer in line table
+ //
+// for (n = 0; n < MAX_IDD_PER_ADAPTER; n++)
+ for (n = 0; n < MAX_CM_PER_ADAPTER; n++)
+ {
+ if (Adapter->TapiLineInfo[n] == TapiLineInfo)
+ break;
+ }
+
+// if (n == MAX_IDD_PER_ADAPTER)
+ if (n == MAX_CM_PER_ADAPTER)
+ return(NDIS_STATUS_FAILURE);
+
+ Adapter->TapiLineInfo[n] = NULL;
+
+ //
+ // get backpointer to connection object
+ //
+ cm = TapiLineInfo->cm;
+
+ cm->TapiLineInfo = NULL;
+
+ //
+ // if call is active disconnect it
+ //
+ if (cm->TapiCallState != LINECALLSTATE_IDLE)
+ cm_disconnect(cm);
+
+ //
+ // destroy line object
+ //
+ NdisFreeMemory((PVOID)TapiLineInfo,
+ sizeof(TAPI_LINE_INFO),
+ 0);
+
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+TSPI_LineCloseCall(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_CLOSE_CALL TapiBuffer = (PNDIS_TAPI_CLOSE_CALL)InfoBuffer;
+ CM* cm;
+
+ D_LOG(D_ENTRY, ("LineCloseCall: hdCall: 0x%lx", TapiBuffer->hdCall));
+
+ //
+ // validate call handle and get call pointer
+ //
+ cm = GetCallFromCallHandle(Adapter, TapiBuffer->hdCall);
+
+ if (cm == NULL)
+ return(NDIS_STATUS_TAPI_INVALCALLHANDLE);
+
+ //
+ // if call is active disconnect it
+ //
+ if (cm->TapiCallState != LINECALLSTATE_IDLE)
+ cm_disconnect(cm);
+
+ cm->TapiCallState = LINECALLSTATE_IDLE;
+ cm->htCall = (HTAPI_CALL)NULL;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineConditionalMediaDetect(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_CONDITIONAL_MEDIA_DETECTION TapiBuffer = (PNDIS_TAPI_CONDITIONAL_MEDIA_DETECTION)InfoBuffer;
+ TAPI_LINE_INFO* TapiLineInfo;
+
+ D_LOG(D_ENTRY, ("LineConditionalMediaDetect: hdLine: 0x%lx, MediaModes: 0x%x", TapiBuffer->hdLine, TapiBuffer->ulMediaModes));
+
+ //
+ // validate line handle and get line pointer
+ //
+ TapiLineInfo = GetLineFromLineHandle(Adapter, TapiBuffer->hdLine);
+
+ if (TapiLineInfo == NULL)
+ return(NDIS_STATUS_TAPI_INVALLINEHANDLE);
+
+ if (TapiBuffer->ulMediaModes &
+ (TapiLineInfo->MediaModes ^ 0xFFFFFFFF))
+ return(NDIS_STATUS_TAPI_INVALMEDIAMODE);
+
+ if (TapiBuffer->LineCallParams.ulBearerMode &
+ (TapiLineInfo->BearerModes ^ 0xFFFFFFFF))
+ return(NDIS_STATUS_TAPI_RESOURCEUNAVAIL);
+
+ if ((TapiBuffer->LineCallParams.ulMinRate < 56000) ||
+ (TapiBuffer->LineCallParams.ulMaxRate > 64000))
+ return(NDIS_STATUS_TAPI_RESOURCEUNAVAIL);
+
+ if (TapiBuffer->LineCallParams.ulAddressMode != LINEADDRESSMODE_ADDRESSID)
+ return(NDIS_STATUS_TAPI_RESOURCEUNAVAIL);
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineConfigDialog(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_CONFIG_DIALOG TapiBuffer = (PNDIS_TAPI_CONFIG_DIALOG)InfoBuffer;
+
+ D_LOG(D_ENTRY, ("LineConfigDialog: DeviceID: 0x%x", TapiBuffer->ulDeviceID));
+
+ return(NDIS_STATUS_TAPI_OPERATIONUNAVAIL);
+}
+
+NDIS_STATUS
+TSPI_LineDevSpecific(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_DEV_SPECIFIC TapiBuffer = (PNDIS_TAPI_DEV_SPECIFIC)InfoBuffer;
+ TAPI_LINE_INFO* TapiLineInfo;
+
+ D_LOG(D_ENTRY, ("LineDevSpecific: hdLine: 0x%lx, hdCall: 0x%lx, AddressID: 0x%x", \
+ TapiBuffer->hdLine, TapiBuffer->hdCall, TapiBuffer->ulAddressID));
+ //
+ // validate line handle and get line pointer
+ //
+ TapiLineInfo = GetLineFromLineHandle(Adapter, TapiBuffer->hdLine);
+
+ if (TapiLineInfo == NULL)
+ return(NDIS_STATUS_TAPI_INVALLINEHANDLE);
+
+ return(NDIS_STATUS_TAPI_OPERATIONUNAVAIL);
+}
+
+NDIS_STATUS
+TSPI_LineDial(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_DIAL TapiBuffer = (PNDIS_TAPI_DIAL)InfoBuffer;
+ CM_PROF* Prof;
+ CM* cm;
+
+ D_LOG(D_ENTRY, ("LineDial: hdCall: 0x%lx", TapiBuffer->hdCall));
+
+ //
+ // validate call handle and get call pointer
+ //
+ cm = GetCallFromCallHandle(Adapter, TapiBuffer->hdCall);
+
+ if (cm == NULL)
+ return(NDIS_STATUS_TAPI_INVALCALLHANDLE);
+
+ if (cm->TapiCallState != LINECALLSTATE_IDLE)
+ return(NDIS_STATUS_TAPI_INVALCALLSTATE);
+
+ //
+ // check address size if zero return error
+ //
+ if (TapiBuffer->ulDestAddressSize == 0)
+ return(NDIS_STATUS_TAPI_INVALADDRESS);
+
+ //
+ // get profile for this call
+ //
+ Prof = (CM_PROF*)&cm->oprof;
+
+ //
+ // parse address and put in cm
+ //
+ StashAddress(Prof, TapiBuffer->ulDestAddressSize, TapiBuffer->szDestAddress);
+
+ //
+ // get a line to call on
+ //
+ if (FindAndStashIdd(cm, Prof))
+ return(NDIS_STATUS_TAPI_RESOURCEUNAVAIL);
+
+ //
+ // set initial line state
+ //
+ cm->CallState = CALL_ST_WAITCONN;
+
+ //
+ // figure out call type
+ //
+ cm->ConnectionType = CM_PPP;
+
+ //
+ // attempt call
+ //
+ cm_connect(cm);
+
+ cm->TapiCallState = LINECALLSTATE_PROCEEDING;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineDrop(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_DROP TapiBuffer = (PNDIS_TAPI_DROP)InfoBuffer;
+ TAPI_LINE_INFO* TapiLineInfo;
+ CM* cm;
+ CM_PROF *Prof;
+
+ D_LOG(D_ENTRY, ("LineDrop: hdCall: 0x%lx", TapiBuffer->hdCall));
+
+ //
+ // validate call handle and get call pointer
+ //
+ cm = GetCallFromCallHandle(Adapter, TapiBuffer->hdCall);
+
+ if (cm == NULL)
+ return(NDIS_STATUS_TAPI_INVALCALLHANDLE);
+
+ //
+ // get line info pointer
+ //
+ TapiLineInfo = (TAPI_LINE_INFO*)cm->TapiLineInfo;
+
+ if (TapiLineInfo == NULL)
+ return(NDIS_STATUS_TAPI_INVALLINEHANDLE);
+
+ cm->CallState = CALL_ST_IDLE;
+
+ //
+ // disconnect the call
+ //
+ if (cm->TapiCallState != LINECALLSTATE_DISCONNECTED &&
+ cm->TapiCallState != LINECALLSTATE_BUSY)
+ cm_disconnect(cm);
+
+ //
+ // indicate linedown to wan wrapper
+ //
+ if (cm->LinkHandle)
+ WanLinedown(cm);
+
+ //
+ // send call state to idle
+ //
+ cm->TapiCallState = LINECALLSTATE_IDLE;
+
+ //
+ // if this was a listening Line reissue a listen
+ //
+ if (TapiLineInfo->TapiLineWasListening)
+ {
+ Prof = (CM_PROF*)&cm->oprof;
+ SetDefaultListenProf(Prof, GetIDFromLine(Adapter, TapiLineInfo));
+ cm_listen(cm);
+ cm->CallState = CALL_ST_LISTEN;
+ }
+
+ FreeIddCallResources(cm);
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineGetAddressCaps(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_GET_ADDRESS_CAPS TapiBuffer = (PNDIS_TAPI_GET_ADDRESS_CAPS)InfoBuffer;
+ LINE_ADDRESS_CAPS* AddressCaps = &TapiBuffer->LineAddressCaps;
+ ULONG AddressLength, AvailMem;
+ CM *cm;
+
+ D_LOG(D_ENTRY, ("LineGetAddressCaps: DeviceID: 0x%x", TapiBuffer->ulDeviceID));
+ //
+ // Validate extension
+ //
+ VALIDATE_EXTENSION(TapiBuffer->ulExtVersion);
+
+ //
+ // only support two addresss per line
+ //
+ if (TapiBuffer->ulAddressID > MAX_CALL_PER_LINE)
+ return(NDIS_STATUS_TAPI_INVALADDRESSID);
+
+ //
+ // get conn object that is or would be attached to this line
+ //
+// cm = GetCmFromDeviceID (Adapter,
+// TapiBuffer->ulDeviceID,
+// TapiBuffer->ulAddressID);
+ cm = GetCmFromDeviceID (Adapter,
+ TapiBuffer->ulDeviceID);
+
+ if (cm == NULL)
+ return(NDIS_STATUS_TAPI_INVALADDRESSID);
+
+ //
+ // validate structure size
+ //
+ AddressLength = __strlen(cm->LocalAddress) + 1;
+ AddressCaps->ulNeededSize = sizeof(LINE_ADDRESS_CAPS) + AddressLength;
+ AddressCaps->ulUsedSize = sizeof(LINE_ADDRESS_CAPS);
+
+ AvailMem = AddressCaps->ulTotalSize - AddressCaps->ulUsedSize;
+
+ if (AvailMem > 0)
+ {
+ ULONG SizeToCopy = (((ULONG)AvailMem > AddressLength) ?
+ AddressLength : AvailMem);
+
+ NdisMoveMemory(((LPSTR)AddressCaps) + AddressCaps->ulUsedSize,
+ cm->LocalAddress, SizeToCopy);
+
+ AddressCaps->ulAddressSize = SizeToCopy;
+ AddressCaps->ulAddressOffset = AddressCaps->ulUsedSize;
+ AddressCaps->ulUsedSize += SizeToCopy;
+ AvailMem -= SizeToCopy;
+ }
+
+ //
+ // fill structure
+ //
+ AddressCaps->ulLineDeviceID = TapiBuffer->ulDeviceID;
+
+ AddressCaps->ulDevSpecificSize = 0;
+ AddressCaps->ulDevSpecificOffset = 0;
+
+ AddressCaps->ulAddressSharing = LINEADDRESSSHARING_PRIVATE;
+ AddressCaps->ulAddressStates = LINEADDRESSSTATE_OTHER |
+ LINEADDRESSSTATE_INUSEZERO |
+ LINEADDRESSSTATE_INUSEONE |
+ LINEADDRESSSTATE_NUMCALLS;
+
+ AddressCaps->ulCallInfoStates = LINECALLINFOSTATE_CALLERID |
+ LINECALLINFOSTATE_CALLEDID;
+
+ AddressCaps->ulCallerIDFlags = LINECALLPARTYID_ADDRESS |
+ LINECALLPARTYID_UNAVAIL;
+
+ AddressCaps->ulCalledIDFlags = LINECALLPARTYID_ADDRESS |
+ LINECALLPARTYID_UNAVAIL;
+
+ AddressCaps->ulConnectedIDFlags = LINECALLPARTYID_UNAVAIL;
+
+ AddressCaps->ulRedirectionIDFlags = LINECALLPARTYID_UNAVAIL;
+
+ AddressCaps->ulRedirectingIDFlags = LINECALLPARTYID_UNAVAIL;
+
+ AddressCaps->ulCallStates = LINECALLSTATE_IDLE |
+ LINECALLSTATE_OFFERING |
+// LINECALLSTATE_BUSY |
+ LINECALLSTATE_CONNECTED |
+ LINECALLSTATE_PROCEEDING |
+ LINECALLSTATE_DISCONNECTED |
+ LINECALLSTATE_SPECIALINFO |
+ LINECALLSTATE_UNKNOWN;
+
+ AddressCaps->ulDialToneModes = LINEDIALTONEMODE_UNAVAIL;
+
+ AddressCaps->ulBusyModes = LINEBUSYMODE_UNAVAIL;
+
+ AddressCaps->ulSpecialInfo = LINESPECIALINFO_UNAVAIL;
+
+ AddressCaps->ulDisconnectModes = LINEDISCONNECTMODE_UNKNOWN;
+
+ AddressCaps->ulMaxNumActiveCalls = 1;
+ AddressCaps->ulMaxNumOnHoldCalls = 0;
+ AddressCaps->ulMaxNumOnHoldPendingCalls = 0;
+ AddressCaps->ulMaxNumConference = 0;
+ AddressCaps->ulMaxNumTransConf = 0;
+
+ AddressCaps->ulAddrCapFlags = LINEADDRCAPFLAGS_DIALED;
+
+ AddressCaps->ulCallFeatures = LINECALLFEATURE_ANSWER |
+ LINECALLFEATURE_DIAL |
+ LINECALLFEATURE_DROP;
+
+ AddressCaps->ulRemoveFromConfCaps = 0;
+ AddressCaps->ulRemoveFromConfState = 0;
+ AddressCaps->ulTransferModes = 0;
+ AddressCaps->ulParkModes = 0;
+
+ AddressCaps->ulForwardModes = 0;
+ AddressCaps->ulMaxForwardEntries = 0;
+ AddressCaps->ulMaxSpecificEntries = 0;
+ AddressCaps->ulMinFwdNumRings = 0;
+ AddressCaps->ulMaxFwdNumRings = 0;
+
+ AddressCaps->ulMaxCallCompletions = 0;
+ AddressCaps->ulCallCompletionConds = 0;
+ AddressCaps->ulCallCompletionModes = 0;
+ AddressCaps->ulNumCompletionMessages = 0;
+ AddressCaps->ulCompletionMsgTextEntrySize = 0;
+ AddressCaps->ulCompletionMsgTextSize = 0;
+ AddressCaps->ulCompletionMsgTextOffset = 0;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineGetAddressID(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_GET_ADDRESS_ID TapiBuffer = (PNDIS_TAPI_GET_ADDRESS_ID)InfoBuffer;
+ TAPI_LINE_INFO* TapiLineInfo;
+ CM *cm;
+ UCHAR *LocalAddress;
+
+ D_LOG(D_ENTRY, ("LineGetAddressID: hdLine: 0x%lx, AddressMode: 0x%x", TapiBuffer->hdLine, TapiBuffer->ulAddressMode));
+
+ //
+ // validate line handle and get line pointer
+ //
+ TapiLineInfo = GetLineFromLineHandle(Adapter, TapiBuffer->hdLine);
+
+ if (TapiLineInfo == NULL)
+ return(NDIS_STATUS_TAPI_INVALLINEHANDLE);
+
+ cm = TapiLineInfo->cm;
+
+ LocalAddress = cm->LocalAddress;
+
+ //
+ // return address id
+ //
+ if (__strncmp(LocalAddress, TapiBuffer->szAddress, TapiBuffer->ulAddressSize))
+ return(NDIS_STATUS_TAPI_INVALADDRESS);
+
+ TapiBuffer->ulAddressID = 0;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineGetAddressStatus(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_GET_ADDRESS_STATUS TapiBuffer = (PNDIS_TAPI_GET_ADDRESS_STATUS)InfoBuffer;
+ LINE_ADDRESS_STATUS* AddrStatus = &TapiBuffer->LineAddressStatus;
+ TAPI_LINE_INFO* TapiLineInfo;
+ CM *cm;
+
+ D_LOG(D_ENTRY, ("LineGetAddressStatus: hdLine: 0x%lx, ulAddressID: 0x%x", TapiBuffer->hdLine, TapiBuffer->ulAddressID));
+
+ //
+ // validate line handle and get line pointer
+ //
+ TapiLineInfo = GetLineFromLineHandle(Adapter, TapiBuffer->hdLine);
+
+ if (TapiLineInfo == NULL)
+ return(NDIS_STATUS_TAPI_INVALLINEHANDLE);
+
+// if (TapiBuffer->ulAddressID > 1)
+// return(NDIS_STATUS_TAPI_INVALADDRESSID);
+
+ if (TapiBuffer->ulAddressID != 0)
+ return(NDIS_STATUS_TAPI_INVALADDRESSID);
+
+ AddrStatus->ulNeededSize = sizeof(LINE_ADDRESS_STATUS);
+
+ if (AddrStatus->ulNeededSize > AddrStatus->ulTotalSize)
+ return(NDIS_STATUS_TAPI_STRUCTURETOOSMALL);
+
+// cm = (CM*)TapiLineInfo->cm[TapiBuffer->ulAddressID];
+ cm = (CM*)TapiLineInfo->cm;
+
+ AddrStatus->ulUsedSize = AddrStatus->ulNeededSize;
+
+ AddrStatus->ulNumInUse = 1;
+
+ if (cm->TapiCallState == LINECALLSTATE_CONNECTED)
+ {
+ AddrStatus->ulNumActiveCalls = 1;
+ AddrStatus->ulAddressFeatures = 0;
+ }
+ else
+ {
+ AddrStatus->ulNumActiveCalls = 0;
+ AddrStatus->ulAddressFeatures = LINEADDRFEATURE_MAKECALL;
+ }
+
+ AddrStatus->ulNumOnHoldCalls = 0;
+ AddrStatus->ulNumOnHoldPendCalls = 0;
+ AddrStatus->ulNumRingsNoAnswer = 0;
+ AddrStatus->ulForwardNumEntries = 0;
+ AddrStatus->ulForwardSize = 0;
+ AddrStatus->ulForwardOffset = 0;
+ AddrStatus->ulTerminalModesSize = 0;
+ AddrStatus->ulTerminalModesOffset = 0;
+ AddrStatus->ulDevSpecificSize = 0;
+ AddrStatus->ulDevSpecificOffset = 0;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineGetCallAddressID(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_GET_CALL_ADDRESS_ID TapiBuffer = (PNDIS_TAPI_GET_CALL_ADDRESS_ID)InfoBuffer;
+ TAPI_LINE_INFO* TapiLineInfo;
+ CM *cm;
+
+ D_LOG(D_ENTRY, ("LineGetCallAddressID: hdCall: 0x%lx", TapiBuffer->hdCall));
+
+ //
+ // validate call handle and get call pointer
+ //
+ cm = GetCallFromCallHandle(Adapter, TapiBuffer->hdCall);
+
+ if (cm == NULL)
+ return(NDIS_STATUS_TAPI_INVALCALLHANDLE);
+
+ TapiLineInfo = cm->TapiLineInfo;
+
+ if (TapiLineInfo == NULL)
+ return(NDIS_STATUS_TAPI_INVALCALLHANDLE);
+
+ if( TapiLineInfo->cm != cm )
+ return(NDIS_STATUS_TAPI_INVALLINEHANDLE);
+
+ TapiBuffer->ulAddressID = 0;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineGetCallInfo(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_GET_CALL_INFO TapiBuffer = (PNDIS_TAPI_GET_CALL_INFO)InfoBuffer;
+ LINE_CALL_INFO* CallInfo = &TapiBuffer->LineCallInfo;
+ TAPI_LINE_INFO* TapiLineInfo;
+ CM* cm;
+
+ D_LOG(D_ENTRY, ("LineGetCallInfo: hdCall: 0x%lx", TapiBuffer->hdCall));
+
+ //
+ // validate call handle and get call pointer
+ //
+ cm = GetCallFromCallHandle(Adapter, TapiBuffer->hdCall);
+
+ if (cm == NULL)
+ return(NDIS_STATUS_TAPI_INVALCALLHANDLE);
+
+ //
+ // get line handle
+ //
+ TapiLineInfo = cm->TapiLineInfo;
+
+ if (TapiLineInfo == NULL)
+ return(NDIS_STATUS_TAPI_INVALCALLHANDLE);
+
+ //
+ // validate structure size
+ //
+ CallInfo->ulNeededSize = sizeof(LINE_CALL_INFO);
+ CallInfo->ulUsedSize = 0;
+
+ if (CallInfo->ulNeededSize > CallInfo->ulTotalSize)
+ return(NDIS_STATUS_TAPI_STRUCTURETOOSMALL);
+
+ CallInfo->ulUsedSize = sizeof(LINE_CALL_INFO);
+
+ CallInfo->hLine = (ULONG)TapiLineInfo;
+ CallInfo->ulLineDeviceID = GetIDFromLine(Adapter, TapiLineInfo);
+
+ if (TapiLineInfo->cm != cm)
+ return(NDIS_STATUS_TAPI_INVALCALLHANDLE);
+
+ CallInfo->ulAddressID = 0;
+
+ D_LOG(D_ENTRY, ("LineGetCallInfo: AddressId: %d", CallInfo->ulAddressID));
+
+ CallInfo->ulBearerMode = TapiLineInfo->CurBearerMode;
+ CallInfo->ulRate = cm->speed;
+ CallInfo->ulMediaMode = TapiLineInfo->CurMediaMode;
+
+ CallInfo->ulAppSpecific = cm->AppSpecific;
+ CallInfo->ulCallID = 0;
+ CallInfo->ulRelatedCallID = 0;
+ CallInfo->ulCallParamFlags = 0;
+ CallInfo->ulCallStates = LINECALLSTATE_IDLE |
+ LINECALLSTATE_OFFERING |
+// LINECALLSTATE_BUSY |
+ LINECALLSTATE_CONNECTED |
+ LINECALLSTATE_DISCONNECTED |
+ LINECALLSTATE_SPECIALINFO |
+ LINECALLSTATE_UNKNOWN;
+
+
+ CallInfo->DialParams.ulDialPause = 0;
+ CallInfo->DialParams.ulDialSpeed = 0;
+ CallInfo->DialParams.ulDigitDuration = 0;
+ CallInfo->DialParams.ulWaitForDialtone = 0;
+
+ CallInfo->ulOrigin = (cm->was_listen) ? LINECALLORIGIN_EXTERNAL : LINECALLORIGIN_OUTBOUND;
+ CallInfo->ulReason = LINECALLREASON_UNAVAIL;
+ CallInfo->ulCompletionID = 0;
+
+ CallInfo->ulCountryCode = 0;
+ CallInfo->ulTrunk = (ULONG)-1;
+
+ //
+ // this should actually fill in called and
+ // calling address fields. we don't do this
+ // very well right now so I will defer this.
+ //
+ CallInfo->ulCallerIDFlags = LINECALLPARTYID_UNAVAIL;
+ CallInfo->ulCallerIDSize = 0;
+ CallInfo->ulCallerIDOffset = 0;
+ CallInfo->ulCallerIDNameSize = 0;
+ CallInfo->ulCallerIDNameOffset = 0;
+
+ CallInfo->ulCalledIDFlags = LINECALLPARTYID_UNAVAIL;
+ CallInfo->ulCalledIDSize = 0;
+ CallInfo->ulCalledIDOffset = 0;
+ CallInfo->ulCalledIDNameSize = 0;
+ CallInfo->ulCalledIDNameOffset = 0;
+
+ CallInfo->ulConnectedIDFlags = LINECALLPARTYID_UNAVAIL;
+ CallInfo->ulConnectedIDSize = 0;
+ CallInfo->ulConnectedIDOffset = 0;
+ CallInfo->ulConnectedIDNameSize = 0;
+ CallInfo->ulConnectedIDNameOffset = 0;
+
+ CallInfo->ulRedirectionIDFlags = LINECALLPARTYID_UNAVAIL;
+ CallInfo->ulRedirectionIDSize = 0;
+ CallInfo->ulRedirectionIDOffset = 0;
+ CallInfo->ulRedirectionIDNameSize = 0;
+ CallInfo->ulRedirectionIDNameOffset = 0;
+
+ CallInfo->ulRedirectingIDFlags = LINECALLPARTYID_UNAVAIL;
+ CallInfo->ulRedirectingIDSize = 0;
+ CallInfo->ulRedirectingIDOffset = 0;
+ CallInfo->ulRedirectingIDNameSize = 0;
+ CallInfo->ulRedirectingIDNameOffset = 0;
+
+ CallInfo->ulDisplaySize = 0;
+ CallInfo->ulDisplayOffset = 0;
+
+ CallInfo->ulUserUserInfoSize = 0;
+ CallInfo->ulUserUserInfoOffset = 0;
+
+ CallInfo->ulHighLevelCompSize = 0;
+ CallInfo->ulHighLevelCompOffset = 0;
+
+ CallInfo->ulLowLevelCompSize = 0;
+ CallInfo->ulLowLevelCompOffset = 0;
+
+ CallInfo->ulChargingInfoSize = 0;
+ CallInfo->ulChargingInfoOffset = 0;
+
+ CallInfo->ulTerminalModesSize = 0;
+ CallInfo->ulTerminalModesOffset = 0;
+
+ CallInfo->ulDevSpecificSize = 0;
+ CallInfo->ulDevSpecificOffset = 0;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineGetCallStatus(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_GET_CALL_STATUS TapiBuffer = (PNDIS_TAPI_GET_CALL_STATUS)InfoBuffer;
+ LINE_CALL_STATUS *CallStatus = &TapiBuffer->LineCallStatus;
+ CM *cm;
+
+ D_LOG(D_ENTRY, ("LineGetCallStatus: hdCall: 0x%lx", TapiBuffer->hdCall));
+
+ //
+ // validate call handle and get call pointer
+ //
+ cm = GetCallFromCallHandle(Adapter, TapiBuffer->hdCall);
+
+ if (cm == NULL)
+ return(NDIS_STATUS_TAPI_INVALCALLHANDLE);
+
+ CallStatus->ulNeededSize = CallStatus->ulUsedSize = sizeof(LINE_CALL_STATUS);
+
+ CallStatus->ulCallState = cm->TapiCallState;
+
+ //
+ // fill the mode depending on the call state
+ // this should be done more intelligently
+ // i could find out more about why the call failed
+ // maybe later
+ //
+ switch (cm->TapiCallState)
+ {
+ case LINECALLSTATE_IDLE:
+ CallStatus->ulCallStateMode = 0;
+ CallStatus->ulCallFeatures = LINECALLFEATURE_DIAL;
+ break;
+
+ case LINECALLSTATE_CONNECTED:
+ CallStatus->ulCallStateMode = 0;
+ CallStatus->ulCallFeatures = LINECALLFEATURE_DROP;
+ break;
+
+ case LINECALLSTATE_OFFERING:
+ CallStatus->ulCallStateMode = 0;
+ CallStatus->ulCallFeatures = LINECALLFEATURE_ANSWER;
+ break;
+
+ case LINECALLSTATE_DISCONNECTED:
+ if (cm->CauseValue == 0x11 || cm->SignalValue == 0x04)
+ CallStatus->ulCallStateMode = LINEDISCONNECTMODE_BUSY;
+ else
+ CallStatus->ulCallStateMode = LINEDISCONNECTMODE_NOANSWER;
+ break;
+
+ case LINECALLSTATE_BUSY:
+ CallStatus->ulCallStateMode = LINEBUSYMODE_UNAVAIL;
+ break;
+
+ case LINECALLSTATE_SPECIALINFO:
+ if (cm->NoActiveLine)
+ CallStatus->ulCallStateMode = LINESPECIALINFO_NOCIRCUIT;
+ break;
+ }
+
+ CallStatus->ulDevSpecificSize = 0;
+ CallStatus->ulDevSpecificOffset = 0;
+
+ D_LOG(D_ENTRY, ("LineGetCallStatus: CallState: 0x%x, CallStateMode: 0x%x", CallStatus->ulCallState, CallStatus->ulCallStateMode));
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineGetDevCaps(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_GET_DEV_CAPS TapiBuffer = (PNDIS_TAPI_GET_DEV_CAPS)InfoBuffer;
+ ULONG ulProviderInfoSize, ulLineNameSize, ulTotalSize;
+ LINE_DEV_CAPS* DevCaps = &TapiBuffer->LineDevCaps;
+ ULONG AvailMem, LocalID;
+ CHAR LineName[32], ProviderName[32];
+
+
+ D_LOG(D_ENTRY, ("LineGetDevCaps: DeviceID: 0x%x", TapiBuffer->ulDeviceID));
+
+ //
+ // validate device ID
+ //
+
+ LocalID = TapiBuffer->ulDeviceID - Adapter->TapiBaseID;
+
+ //
+ // save size of buffer
+ //
+ ulTotalSize = DevCaps->ulTotalSize;
+
+ //
+ // clear buffer so all default params will be zero
+ //
+ NdisZeroMemory(DevCaps, ulTotalSize);
+
+ //
+ // restore total size
+ //
+ DevCaps->ulTotalSize = ulTotalSize;
+
+ DevCaps->ulUsedSize = sizeof(LINE_DEV_CAPS);
+
+//
+// Changed to support the new way that RAS is building TAPI names and
+// address's.
+//
+// sprintf(ProviderName,"DigiBoard Pcimac");
+// ulProviderInfoSize = __strlen(ProviderName) + 1;
+
+ // Provider info is of the following format
+ // <media name>\0<device name>\0
+ // where - media name is - ISDN,
+ // device name is - Digiboard PCIMAC
+ //
+#define MEDIA_STR "ISDN"
+#define PROVIDER_STR "Pcimac"
+ sprintf(ProviderName,"%s%c%s%c", MEDIA_STR, '\0', PROVIDER_STR, '\0');
+ ulProviderInfoSize = __strlen(MEDIA_STR) + __strlen(PROVIDER_STR) + 2 ;
+
+ //
+ // should fill local id with something meaningfull
+ //
+ sprintf(LineName, "%s-%s%d", Adapter->Name,"Line", LocalID);
+ ulLineNameSize = __strlen(LineName) + 1;
+
+ DevCaps->ulNeededSize = DevCaps->ulUsedSize +
+ ulProviderInfoSize +
+ ulLineNameSize;
+
+ AvailMem = DevCaps->ulTotalSize - DevCaps->ulUsedSize;
+
+ //
+ // fill provider info
+ //
+ if (AvailMem > 0)
+ {
+ ULONG SizeToCopy = (((ULONG)AvailMem > ulProviderInfoSize) ?
+ ulProviderInfoSize : AvailMem);
+
+ NdisMoveMemory(((LPSTR)DevCaps) + DevCaps->ulUsedSize,
+ ProviderName, SizeToCopy);
+
+ DevCaps->ulProviderInfoSize = SizeToCopy;
+ DevCaps->ulProviderInfoOffset = DevCaps->ulUsedSize;
+ DevCaps->ulUsedSize += SizeToCopy;
+ AvailMem -= SizeToCopy;
+ }
+
+ //
+ // fill line name info
+ //
+ if (AvailMem != 0)
+ {
+
+ ULONG SizeToCopy = (((ULONG)AvailMem > ulLineNameSize) ?
+ ulLineNameSize : AvailMem);
+
+ NdisMoveMemory(((LPSTR)DevCaps) + DevCaps->ulUsedSize,
+ Adapter->Name, SizeToCopy);
+
+ DevCaps->ulLineNameSize = SizeToCopy;
+ DevCaps->ulLineNameOffset = DevCaps->ulUsedSize;
+ DevCaps->ulUsedSize += SizeToCopy;
+ AvailMem -= SizeToCopy;
+ }
+
+ DevCaps->ulPermanentLineID = (ULONG)Adapter;
+ DevCaps->ulStringFormat = STRINGFORMAT_ASCII;
+ DevCaps->ulAddressModes = LINEADDRESSMODE_ADDRESSID;
+ DevCaps->ulNumAddresses = MAX_CALL_PER_LINE;
+ DevCaps->ulBearerModes = LINEBEARERMODE_VOICE |
+ LINEBEARERMODE_DATA;
+ DevCaps->ulMaxRate = 64000;
+ DevCaps->ulMediaModes = LINEMEDIAMODE_DIGITALDATA |
+ LINEMEDIAMODE_UNKNOWN;
+
+ DevCaps->ulMaxNumActiveCalls = MAX_CALL_PER_LINE;
+ DevCaps->ulLineStates = LINEDEVSTATE_CONNECTED |
+ LINEDEVSTATE_DISCONNECTED |
+ LINEDEVSTATE_OPEN |
+ LINEDEVSTATE_CLOSE |
+ LINEDEVSTATE_NUMCALLS |
+ LINEDEVSTATE_REINIT |
+ LINEDEVSTATE_INSERVICE |
+ LINEDEVSTATE_OUTOFSERVICE;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineGetDevConfig(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_GET_DEV_CONFIG TapiBuffer = (PNDIS_TAPI_GET_DEV_CONFIG)InfoBuffer;
+
+ D_LOG(D_ENTRY, ("LineGetDevConfig: DeviceID: 0x%x", TapiBuffer->ulDeviceID));
+
+ return(NDIS_STATUS_TAPI_OPERATIONUNAVAIL);
+}
+
+NDIS_STATUS
+TSPI_LineGetExtensionID(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_GET_EXTENSION_ID TapiBuffer = (PNDIS_TAPI_GET_EXTENSION_ID)InfoBuffer;
+
+ D_LOG(D_ENTRY, ("LineGetExtensionID: DeviceID: 0x%x", TapiBuffer->ulDeviceID));
+
+ //
+ // validate device ID
+ //
+ return(NDIS_STATUS_TAPI_OPERATIONUNAVAIL);
+}
+
+NDIS_STATUS
+TSPI_LineGetID(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_GET_ID TapiBuffer = (PNDIS_TAPI_GET_ID)InfoBuffer;
+ CHAR *DeviceClass = ((CHAR*)TapiBuffer) + TapiBuffer->ulDeviceClassOffset;
+ VAR_STRING *DeviceID = &TapiBuffer->DeviceID;
+ ULONG AvailMem, StringLength;
+ PVOID VarStringOffset;
+ TAPI_LINE_INFO* TapiLineInfo;
+ CM *cm;
+
+ D_LOG(D_ENTRY, ("LineGetID: Select: 0x%x, hdLine: 0x%lx, AddressID: 0x%x, hdCall: 0x%lx", \
+ TapiBuffer->ulSelect, TapiBuffer->hdLine, TapiBuffer->ulAddressID, TapiBuffer->hdCall));
+
+ switch (TapiBuffer->ulSelect)
+ {
+ case LINECALLSELECT_LINE:
+ //
+ // validate line handle and get line pointer
+ //
+ TapiLineInfo = GetLineFromLineHandle(Adapter, TapiBuffer->hdLine);
+
+ if (TapiLineInfo == NULL)
+ return(NDIS_STATUS_TAPI_INVALLINEHANDLE);
+
+ if (!__strnicmp(DeviceClass, "tapi/line", TapiBuffer->ulDeviceClassSize))
+ {
+ AvailMem = DeviceID->ulTotalSize - sizeof(VAR_STRING);
+ StringLength = (AvailMem > 4) ? 4 : AvailMem;
+ DeviceID->ulNeededSize = sizeof(VAR_STRING) + 4;
+ DeviceID->ulUsedSize = sizeof(VAR_STRING) + StringLength;
+ DeviceID->ulStringFormat = STRINGFORMAT_BINARY;
+ DeviceID->ulStringSize = StringLength;
+
+ VarStringOffset = ((CHAR*)&TapiBuffer->DeviceID) + sizeof(VAR_STRING);
+ NdisMoveMemory(VarStringOffset, &TapiLineInfo->LineID, StringLength);
+ DeviceID->ulStringOffset = sizeof(VAR_STRING);
+ return(NDIS_STATUS_SUCCESS);
+ }
+ break;
+
+ case LINECALLSELECT_ADDRESS:
+ if (TapiBuffer->ulAddressID > 1)
+ return(NDIS_STATUS_TAPI_INVALADDRESSID);
+ break;
+
+ case LINECALLSELECT_CALL:
+ //
+ // validate call handle and get call pointer
+ //
+ cm = GetCallFromCallHandle(Adapter, TapiBuffer->hdCall);
+
+ if (cm == NULL)
+ return(NDIS_STATUS_TAPI_INVALCALLHANDLE);
+
+ if (cm->TapiCallState != LINECALLSTATE_CONNECTED)
+ return(NDIS_STATUS_TAPI_INVALCALLHANDLE);
+
+ if (!__strnicmp(DeviceClass, "ndis", TapiBuffer->ulDeviceClassSize))
+ {
+ AvailMem = DeviceID->ulTotalSize - sizeof(VAR_STRING);
+ StringLength = (AvailMem > 4) ? 4 : AvailMem;
+ DeviceID->ulNeededSize = sizeof(VAR_STRING) + 4;
+ DeviceID->ulUsedSize = sizeof(VAR_STRING) + StringLength;
+ DeviceID->ulStringFormat = STRINGFORMAT_BINARY;
+ DeviceID->ulStringSize = StringLength;
+
+ VarStringOffset = ((CHAR*)TapiBuffer) + sizeof(NDIS_TAPI_GET_ID);
+ NdisMoveMemory(VarStringOffset, &cm->htCall, StringLength);
+ DeviceID->ulStringOffset = sizeof(VAR_STRING);
+ D_LOG(D_ALWAYS, ("LineGetID: Cookie: 0x%x", (ULONG)*(((CHAR*)TapiBuffer) + sizeof(NDIS_TAPI_GET_ID))));
+ return(NDIS_STATUS_SUCCESS);
+ }
+ }
+ return(NDIS_STATUS_TAPI_INVALDEVICECLASS);
+}
+
+NDIS_STATUS
+TSPI_LineGetLineDevStatus(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_GET_LINE_DEV_STATUS TapiBuffer = (PNDIS_TAPI_GET_LINE_DEV_STATUS)InfoBuffer;
+ TAPI_LINE_INFO *TapiLineInfo;
+ LINE_DEV_STATUS *DevStatus = (LINE_DEV_STATUS*)&TapiBuffer->LineDevStatus;
+ CM *cm;
+
+ D_LOG(D_ENTRY, ("LineGetLineDevStatus: hdLine: 0x%lx", TapiBuffer->hdLine));
+
+ //
+ // validate line handle and get line pointer
+ //
+ TapiLineInfo = GetLineFromLineHandle(Adapter, TapiBuffer->hdLine);
+
+ if (TapiLineInfo == NULL)
+ return(NDIS_STATUS_TAPI_INVALLINEHANDLE);
+
+ DevStatus->ulNeededSize = 0;
+ DevStatus->ulUsedSize = sizeof (LINE_DEV_STATUS);
+
+ cm = (CM*)TapiLineInfo->cm;
+
+ if (cm->TapiCallState == LINECALLSTATE_CONNECTED)
+ DevStatus->ulNumActiveCalls++;
+
+ DevStatus->ulNumOnHoldCalls = 0;
+ DevStatus->ulNumOnHoldPendCalls = 0;
+ DevStatus->ulLineFeatures = LINEFEATURE_MAKECALL;
+ DevStatus->ulNumCallCompletions = 0;
+ DevStatus->ulRingMode = 0;
+
+ DevStatus->ulRoamMode = 0;
+
+ if (TapiLineInfo->TapiLineState == LINEDEVSTATE_INSERVICE)
+ {
+ DevStatus->ulDevStatusFlags = LINEDEVSTATUSFLAGS_CONNECTED |
+ LINEDEVSTATUSFLAGS_INSERVICE;
+ DevStatus->ulSignalLevel = 0xFFFF;
+ DevStatus->ulBatteryLevel = 0xFFFF;
+ }
+ else
+ {
+ DevStatus->ulDevStatusFlags = 0;
+ DevStatus->ulSignalLevel = 0;
+ DevStatus->ulBatteryLevel = 0;
+ }
+
+ DevStatus->ulTerminalModesSize = 0;
+ DevStatus->ulTerminalModesOffset = 0;
+
+ DevStatus->ulDevSpecificSize = 0;
+ DevStatus->ulDevSpecificOffset = 0;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineMakeCall(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_MAKE_CALL TapiBuffer = (PNDIS_TAPI_MAKE_CALL)InfoBuffer;
+ TAPI_LINE_INFO* TapiLineInfo;
+ LINE_CALL_PARAMS* CallParams = (LINE_CALL_PARAMS*)&TapiBuffer->LineCallParams;
+ CM_PROF* Prof;
+ PUCHAR DialAddress;
+ CM* cm = NULL;
+ INT Ret, n;
+ ULONG ChannelsFilled;
+
+ D_LOG(D_ENTRY, ("LineMakeCall: hdLine: 0x%lx, htCall: 0x%lx", \
+ TapiBuffer->hdLine, TapiBuffer->htCall));
+
+ //
+ // validate line handle and get line pointer
+ //
+ TapiLineInfo = GetLineFromLineHandle(Adapter, TapiBuffer->hdLine);
+
+ if (TapiLineInfo == NULL)
+ return(NDIS_STATUS_TAPI_INVALLINEHANDLE);
+
+ //
+ // get a device to call on
+ //
+ if (TapiBuffer->bUseDefaultLineCallParams)
+ cm = (CM*)TapiLineInfo->cm;
+ else
+ {
+ if (CallParams->ulAddressMode == LINEADDRESSMODE_ADDRESSID)
+ {
+ if (CallParams->ulAddressID < MAX_CALL_PER_LINE)
+ cm = (CM*)TapiLineInfo->cm;
+ else
+ return(NDIS_STATUS_TAPI_INVALADDRESSID);
+
+ }
+// else if (CallParams->ulAddressMode == LINEADDRESSMODE_DIALABLEADDR)
+ else
+ {
+ cm = (CM*)TapiLineInfo->cm;
+
+ if (__strncmp(cm->LocalAddress,
+ ((PUCHAR)CallParams) + CallParams->ulOrigAddressOffset,
+ CallParams->ulOrigAddressSize))
+ return(NDIS_STATUS_TAPI_INVALADDRESS);
+ }
+// else
+// return(NDIS_STATUS_TAPI_INVALADDRESS);
+ }
+
+ if (cm == NULL)
+ return(NDIS_STATUS_TAPI_INVALADDRESS);
+
+ Prof = &cm->oprof;
+
+ //
+ // set default calling profile
+ //
+ SetDefaultCallingProf(Prof, GetIDFromLine(Adapter, TapiLineInfo));
+
+ if (!TapiBuffer->bUseDefaultLineCallParams)
+ {
+ //
+ // check address size if zero return error
+ //
+ if (TapiBuffer->ulDestAddressSize == 0)
+ return(NDIS_STATUS_TAPI_INVALADDRESS);
+
+ //
+ // check media mode and make sure we support it
+ //
+ if (CallParams->ulMediaMode &
+ (TapiLineInfo->MediaModes ^ 0xFFFFFFFF))
+ return(NDIS_STATUS_TAPI_INVALMEDIAMODE);
+
+ TapiLineInfo->CurMediaMode = CallParams->ulMediaMode;
+
+ //
+ // check bearer mode and make sure we support it
+ //
+ if (CallParams->ulBearerMode &
+ (TapiLineInfo->BearerModes ^ 0xFFFFFFFF))
+ return(NDIS_STATUS_TAPI_RESOURCEUNAVAIL);
+
+ TapiLineInfo->CurBearerMode = CallParams->ulBearerMode;
+
+ //
+ // check min-max rate
+ //
+ if ((CallParams->ulMinRate < 56000) ||
+ (CallParams->ulMaxRate > (8 * 64000)))
+ return(NDIS_STATUS_TAPI_RESOURCEUNAVAIL);
+
+ //
+ // how many channels is this for
+ //
+ Prof->chan_num = (USHORT)(CallParams->ulMaxRate / 64000);
+
+ if (CallParams->ulMaxRate > (ULONG)(Prof->chan_num * 64000))
+ Prof->chan_num++;
+
+ //
+ // figure out what the connection is for
+ // right now assume all single channel connections are PPP
+ //
+ if (Prof->chan_num == 1)
+ cm->ConnectionType = CM_PPP;
+ else
+ cm->ConnectionType = CM_DKF;
+
+ //
+ // if max and min are equal set fallback to off
+ //
+ if (CallParams->ulMinRate == CallParams->ulMaxRate)
+ Prof->fallback = 0;
+
+ //
+ // we need to set these params for all channels involved
+ //
+ for (n = 0; n < Prof->chan_num; n++)
+ {
+ //
+ // from bearer mode and min-max rate set channel type
+ //
+ if (CallParams->ulBearerMode & LINEBEARERMODE_VOICE)
+ Prof->chan_tbl[n].type = 2;
+ else
+ {
+ if ( 1 == (CallParams->ulMaxRate / (64000 * Prof->chan_num)))
+ Prof->chan_tbl[n].type = 0;
+ else
+ Prof->chan_tbl[n].type = 1;
+ }
+
+ //
+ // accept any bchannel that the switch will give us
+ //
+ Prof->chan_tbl[n].bchan = 2;
+ }
+ }
+
+ //
+ // get a line to call on
+ //
+ ChannelsFilled = FindAndStashIdd(cm, Prof);
+
+ D_LOG(D_ALWAYS, ("LineMakeCall: ChannelsFilled %d", ChannelsFilled));
+ //
+ // if there are no channels available we should report an error
+ //
+ if (!ChannelsFilled)
+ return(NDIS_STATUS_TAPI_INUSE);
+
+ if (ChannelsFilled < Prof->chan_num)
+ {
+ if(Prof->fallback)
+ Prof->chan_num = (USHORT)ChannelsFilled;
+ else
+ {
+ FreeIddCallResources(cm);
+ return(NDIS_STATUS_TAPI_INUSE);
+ }
+ }
+
+ //
+ // get pointer to dial address
+ //
+ DialAddress = ((PUCHAR)TapiBuffer) + TapiBuffer->ulDestAddressOffset;
+
+ //
+ // parse address and put in cm
+ //
+ StashAddress(Prof, TapiBuffer->ulDestAddressSize, DialAddress);
+
+ //
+ // set initial line state
+ //
+ cm->CallState = CALL_ST_WAITCONN;
+
+ //
+ // save tapi's call handle
+ //
+ cm->htCall = TapiBuffer->htCall;
+
+ //
+ // clear out link handle
+ //
+ cm->LinkHandle = NULL;
+
+ //
+ // clear the PPPToRas Flag
+ //
+ cm->PPPToDKF = 0;
+
+ //
+ // return our call handle
+ //
+ TapiBuffer->hdCall = (HDRV_CALL)cm;
+
+ D_LOG(D_ENTRY, ("LineMakeCall: hdLine: 0x%lx", TapiLineInfo));
+
+ cm->TapiCallState = LINECALLSTATE_PROCEEDING;
+
+ //
+ // attempt call
+ //
+ D_LOG(D_ALWAYS, ("LineMakeCall"));
+
+ Ret = cm_connect(cm);
+
+ D_LOG(D_EXIT, ("LineMakeCall: Ret: 0x%x", Ret));
+
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineNegotiateExtVersion(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_NEGOTIATE_EXT_VERSION TapiBuffer = (PNDIS_TAPI_NEGOTIATE_EXT_VERSION)InfoBuffer;
+
+ D_LOG(D_ENTRY, ("LineNegotiateExtVersion: DeviceID: 0x%x", TapiBuffer->ulDeviceID));
+
+ return(NDIS_STATUS_TAPI_OPERATIONUNAVAIL);
+}
+
+NDIS_STATUS
+TSPI_LineOpen(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_OPEN TapiBuffer = (PNDIS_TAPI_OPEN)InfoBuffer;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ TAPI_LINE_INFO* TapiLineInfo;
+ NDIS_PHYSICAL_ADDRESS HighestAcceptableMax = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
+ CM *cm;
+ ULONG n;
+
+ D_LOG(D_ENTRY, ("LineOpen: DeviceID: 0x%x, htLine: 0x%lx", \
+ TapiBuffer->ulDeviceID, TapiBuffer->htLine));
+
+ //
+ // verify device id
+ //
+ cm = GetCmFromDeviceID(Adapter, TapiBuffer->ulDeviceID);
+
+ if (cm == NULL)
+ return(NDIS_STATUS_FAILURE);
+
+ Status = NdisAllocateMemory((PVOID)&TapiLineInfo,
+ sizeof(TAPI_LINE_INFO),
+ 0,
+ HighestAcceptableMax);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ return(NDIS_STATUS_TAPI_RESOURCEUNAVAIL);
+
+ NdisZeroMemory(TapiLineInfo, sizeof(TAPI_LINE_INFO));
+
+ //
+ // store lineinfo pointer in line table
+ //
+ for (n = 0; n < MAX_CM_PER_ADAPTER; n++)
+ {
+ if (Adapter->TapiLineInfo[n] == NULL)
+ break;
+ }
+ if (n == MAX_CM_PER_ADAPTER)
+ return(NDIS_STATUS_FAILURE);
+
+ D_LOG(D_ENTRY, ("LineOpen: hdLine: 0x%lx", TapiLineInfo));
+
+ TapiBuffer->hdLine = (ULONG)TapiLineInfo;
+
+ TapiLineInfo->cm = cm;
+ cm->TapiLineInfo = TapiLineInfo;
+ cm->CallState = CALL_ST_IDLE;
+
+ Adapter->TapiLineInfo[n] = TapiLineInfo;
+
+ TapiLineInfo->LineID = TapiBuffer->ulDeviceID;
+
+ TapiLineInfo->Adapter = Adapter;
+
+ TapiLineInfo->idd = cm->idd;
+
+ TapiLineInfo->htLine = TapiBuffer->htLine;
+
+ TapiLineInfo->MediaModes = LINEMEDIAMODE_DIGITALDATA |
+ LINEMEDIAMODE_UNKNOWN;
+
+ TapiLineInfo->BearerModes = LINEBEARERMODE_VOICE |
+ LINEBEARERMODE_DATA;
+
+ TapiLineInfo->TapiLineState = LINEDEVSTATE_INSERVICE |
+ LINEDEVSTATE_OPEN;
+
+ D_LOG(D_ENTRY, ("LineOpen: hdLine: 0x%lx", TapiBuffer->hdLine));
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_ProviderInit(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_PROVIDER_INITIALIZE TapiBuffer = (PNDIS_TAPI_PROVIDER_INITIALIZE)InfoBuffer;
+
+ D_LOG(D_ENTRY, ("ProviderInit: Adapter: 0x%x, IDBase: 0x%x", Adapter, TapiBuffer->ulDeviceIDBase));
+
+ //
+ // save our Base ID
+ //
+ Adapter->TapiBaseID = TapiBuffer->ulDeviceIDBase;
+
+ //
+ // enumerate the number of lines for this adapter
+ // and return
+ //
+// TapiBuffer->ulNumLineDevs = EnumIddPerAdapter(Adapter);
+ TapiBuffer->ulNumLineDevs = EnumCmPerAdapter(Adapter);
+
+ //
+ // return our provider ID
+ //
+ TapiBuffer->ulProviderID = (ULONG)Adapter;
+
+ D_LOG(D_ALWAYS, ("NumLines: 0x%x, ProviderID: 0x%x", \
+ TapiBuffer->ulNumLineDevs, TapiBuffer->ulProviderID));
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_ProviderShutdown(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_PROVIDER_SHUTDOWN TapiBuffer = (PNDIS_TAPI_PROVIDER_SHUTDOWN)InfoBuffer;
+ ULONG n;
+
+ D_LOG(D_ENTRY, ("ProviderShutdown"));
+
+ for (n = 0; Adapter->CmTbl[n] && n < MAX_CM_PER_ADAPTER; n++)
+ {
+ CM* cm = Adapter->CmTbl[n];
+
+ //
+ // complete all outstanding async events
+ // terminate all calls
+ // close any open lines
+ //
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineSecureCall(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_SECURE_CALL TapiBuffer = (PNDIS_TAPI_SECURE_CALL)InfoBuffer;
+
+ D_LOG(D_ENTRY, ("LineSecureCall: hdCall: 0x%lx", TapiBuffer->hdCall));
+
+ return(NDIS_STATUS_TAPI_OPERATIONUNAVAIL);
+}
+
+NDIS_STATUS
+TSPI_LineSelectExtVersion(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_SELECT_EXT_VERSION TapiBuffer = (PNDIS_TAPI_SELECT_EXT_VERSION)InfoBuffer;
+ TAPI_LINE_INFO* TapiLineInfo;
+
+ D_LOG(D_ENTRY, ("LineSelectExtVersion: hdLine: 0x%lx", TapiBuffer->hdLine));
+
+ //
+ // validate line handle and get line pointer
+ //
+ TapiLineInfo = GetLineFromLineHandle(Adapter, TapiBuffer->hdLine);
+
+ if (TapiLineInfo == NULL)
+ return(NDIS_STATUS_TAPI_INVALLINEHANDLE);
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineSendUserToUserInfo(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_SEND_USER_USER_INFO TapiBuffer = (PNDIS_TAPI_SEND_USER_USER_INFO)InfoBuffer;
+
+ D_LOG(D_ENTRY, ("LineSendUserToUserInfo: hdCall: 0x%lx", TapiBuffer->hdCall));
+
+ return(NDIS_STATUS_TAPI_OPERATIONUNAVAIL);
+}
+
+NDIS_STATUS
+TSPI_LineSetAppSpecific(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_SET_APP_SPECIFIC TapiBuffer = (PNDIS_TAPI_SET_APP_SPECIFIC)InfoBuffer;
+ CM *cm;
+
+ D_LOG(D_ENTRY, ("LineSetAppSpecific: hdCall: 0x%lx", TapiBuffer->hdCall));
+
+ //
+ // validate call handle and get call pointer
+ //
+ cm = GetCallFromCallHandle(Adapter, TapiBuffer->hdCall);
+
+ if (cm == NULL)
+ return(NDIS_STATUS_TAPI_INVALCALLHANDLE);
+
+ cm->AppSpecific = TapiBuffer->ulAppSpecific;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineSetCallParams(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_SET_CALL_PARAMS TapiBuffer = (PNDIS_TAPI_SET_CALL_PARAMS)InfoBuffer;
+ CM *cm;
+
+ D_LOG(D_ENTRY, ("LineSetCallParams: hdCall: 0x%lx", TapiBuffer->hdCall));
+ D_LOG(D_ENTRY, ("BearerMode: 0x%x, MinRate: 0x%x, MaxRate: 0x%x", \
+ TapiBuffer->ulBearerMode, TapiBuffer->ulMinRate, TapiBuffer->ulMaxRate));
+
+ //
+ // validate call handle and get call pointer
+ //
+ cm = GetCallFromCallHandle(Adapter, TapiBuffer->hdCall);
+
+ if (cm == NULL)
+ return(NDIS_STATUS_TAPI_INVALCALLHANDLE);
+
+ //
+ // should set some profile things here
+ //
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineSetDefaultMediaDetection(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION TapiBuffer = (PNDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION)InfoBuffer;
+ TAPI_LINE_INFO* TapiLineInfo;
+ CM *cm;
+ CM_PROF *Prof;
+
+ D_LOG(D_ENTRY, ("LineSetDefaultMediaDetection: hdLine: 0x%lx, MediaModes: 0x%x", TapiBuffer->hdLine, TapiBuffer->ulMediaModes));
+
+ //
+ // validate line handle and get line pointer
+ //
+ TapiLineInfo = GetLineFromLineHandle(Adapter, TapiBuffer->hdLine);
+
+ if (TapiLineInfo == NULL)
+ return(NDIS_STATUS_TAPI_INVALLINEHANDLE);
+
+ //
+ // check for supported media mode
+ //
+// if (TapiBuffer->ulMediaModes != LINEMEDIAMODE_DIGITALDATA)
+// return(NDIS_STATUS_TAPI_INVALMEDIAMODE);
+
+ cm = TapiLineInfo->cm;
+ Prof = &cm->oprof;
+
+ cm->CallState = CALL_ST_LISTEN;
+
+ SetDefaultListenProf(Prof, GetIDFromLine(Adapter, TapiLineInfo));
+
+ //
+ // issue a listen
+ //
+ cm_listen(cm);
+
+ TapiLineInfo->TapiLineWasListening = 1;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineSetDevConfig(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_SET_DEV_CONFIG TapiBuffer = (PNDIS_TAPI_SET_DEV_CONFIG)InfoBuffer;
+
+ D_LOG(D_ENTRY, ("LineSetDevConfig: DeviceID: 0x%x", TapiBuffer->ulDeviceID));
+
+ return(NDIS_STATUS_TAPI_OPERATIONUNAVAIL);
+}
+
+NDIS_STATUS
+TSPI_LineSetMediaMode(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_SET_MEDIA_MODE TapiBuffer = (PNDIS_TAPI_SET_MEDIA_MODE)InfoBuffer;
+ CM *cm;
+
+ D_LOG(D_ENTRY, ("LineSetMediaMode: hdCall: 0x%lx, MediaMode: 0x%x", TapiBuffer->hdCall, TapiBuffer->ulMediaMode));
+
+ //
+ // validate call handle and get call pointer
+ //
+ cm = GetCallFromCallHandle(Adapter, TapiBuffer->hdCall);
+
+ if (cm == NULL)
+ return(NDIS_STATUS_TAPI_INVALCALLHANDLE);
+
+ if (TapiBuffer->ulMediaMode != LINEMEDIAMODE_DIGITALDATA) // if mode is not digital
+ return (NDIS_STATUS_TAPI_INVALMEDIAMODE);
+ else
+ return (NDIS_STATUS_SUCCESS);
+
+ //return(NDIS_STATUS_TAPI_OPERATIONUNAVAIL);
+}
+
+NDIS_STATUS
+TSPI_LineSetStatusMessage(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_SET_STATUS_MESSAGES TapiBuffer = (PNDIS_TAPI_SET_STATUS_MESSAGES)InfoBuffer;
+ TAPI_LINE_INFO* TapiLineInfo;
+
+ D_LOG(D_ENTRY, ("LineSetStatusMessage: hdLine: 0x%lx", TapiBuffer->hdLine));
+ D_LOG(D_ENTRY, ("LineStates: 0x%x, AddressStates: 0x%x", TapiBuffer->ulLineStates, TapiBuffer->ulAddressStates));
+
+ //
+ // validate line handle and get line pointer
+ //
+ TapiLineInfo = GetLineFromLineHandle(Adapter, TapiBuffer->hdLine);
+
+ if (TapiLineInfo == NULL)
+ return(NDIS_STATUS_TAPI_INVALLINEHANDLE);
+
+ TapiLineInfo->LineStates = TapiBuffer->ulLineStates;
+ TapiLineInfo->AddressStates = TapiBuffer->ulAddressStates;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+TAPI_LINE_INFO*
+GetLineFromLineHandle(
+ ADAPTER* Adapter,
+ HDRV_LINE hdLine
+ )
+{
+ ULONG n;
+ CM* cm;
+
+ for (n = 0; Adapter->CmTbl[n] && n < MAX_CM_PER_ADAPTER; n++)
+ {
+ cm = Adapter->CmTbl[n];
+
+ if (cm->TapiLineInfo == (TAPI_LINE_INFO*)hdLine)
+ break;
+ }
+ if (n >= MAX_CM_PER_ADAPTER)
+ return(NULL);
+
+ return((TAPI_LINE_INFO*)hdLine);
+}
+
+CM*
+GetCallFromCallHandle(
+ ADAPTER* Adapter,
+ HDRV_CALL hdCall
+ )
+{
+ ULONG n;
+ CM* cm;
+
+ for (n = 0; n < MAX_CM_PER_ADAPTER; n++)
+ {
+ cm = (CM*)Adapter->CmTbl[n];
+
+ if (cm == (CM*)hdCall)
+ break;
+ }
+ if (n == MAX_CM_PER_ADAPTER)
+ return(NULL);
+
+ return((CM*)hdCall);
+}
+
+IDD*
+GetIddFromDeviceID(
+ ADAPTER* Adapter,
+ ULONG DeviceID
+ )
+{
+ ULONG LocalID;
+
+ LocalID = DeviceID - Adapter->TapiBaseID;
+
+ return (Adapter->IddTbl[LocalID]);
+}
+
+
+ULONG GetIDFromLine( ADAPTER *Adapter,
+ TAPI_LINE_INFO *TapiLineInfo )
+{
+ ULONG n;
+
+ for (n = 0; n < MAX_CM_PER_ADAPTER; n++)
+ {
+ CM *cm = Adapter->CmTbl[n];
+
+ if (TapiLineInfo->cm == cm)
+ break;
+ }
+ return(Adapter->TapiBaseID + n);
+}
+
+CM* GetCmFromDeviceID( ADAPTER *Adapter,
+ ULONG DeviceID )
+{
+ ULONG LocalID;
+
+ LocalID = DeviceID - Adapter->TapiBaseID;
+
+ return (Adapter->CmTbl[LocalID]);
+}
+
+VOID
+DoTapiStateCheck(CM* cm)
+{
+ TAPI_LINE_INFO* TapiLineInfo = cm->TapiLineInfo;
+
+ D_LOG(D_ENTRY, ("DoTapiStateCheck: Line: 0x%lx, call: 0x%lx", TapiLineInfo, cm));
+
+ if (TapiLineInfo != NULL)
+ {
+ ULONG NewState = CALL_ST_DONTCARE;
+
+ if ((NewState = GetCallState(cm)) != CALL_ST_DONTCARE)
+ {
+ D_LOG(D_ENTRY, ("CallState: 0x%x, NewState: 0x%x", cm->CallState, NewState));
+ (*CallStateProc[cm->CallState][NewState])(cm);
+ cm->CallState = NewState;
+ }
+ }
+}
+
+ULONG
+GetCallState(
+ CM *cm
+ )
+{
+ switch (cm->state)
+ {
+ case CM_ST_IDLE:
+ return(CALL_ST_IDLE);
+
+ case CM_ST_LISTEN:
+ return(CALL_ST_LISTEN);
+
+ case CM_ST_ACTIVE:
+ return(CALL_ST_CONN);
+
+ case CM_ST_WAIT_ACT:
+ case CM_ST_IN_ACT:
+ case CM_ST_IN_SYNC:
+ return(CALL_ST_WAITCONN);
+ }
+ return(CALL_ST_DONTCARE);
+}
+
+VOID
+SignalCallProceeding(
+ CM *cm
+ )
+{
+ ADAPTER *Adapter = (ADAPTER*)cm->Adapter;
+ TAPI_LINE_INFO *TapiLineInfo = (TAPI_LINE_INFO*)cm->TapiLineInfo;
+ ULONG Param1 = 0, Param2 = 0, Param3 = 0;
+
+ D_LOG(D_ENTRY, ("SignalCallProceeding: Line: 0x%lx, call: 0x%lx", TapiLineInfo, cm));
+ cm->TapiCallState = LINECALLSTATE_PROCEEDING;
+
+ //
+ // indicate callstate event call connected
+ //
+ Param1 = cm->TapiCallState;
+ SendLineEvent(Adapter,
+ TapiLineInfo->htLine,
+ cm->htCall,
+ LINE_CALLSTATE,
+ &Param1,
+ &Param2,
+ &Param3);
+}
+
+VOID
+SignalListenFailure(
+ CM *cm
+ )
+{
+ ADAPTER *Adapter = (ADAPTER*)cm->Adapter;
+ TAPI_LINE_INFO *TapiLineInfo = (TAPI_LINE_INFO*)cm->TapiLineInfo;
+ CM_PROF *Prof = &cm->oprof;
+ ULONG Param1 = 0, Param2 = 0, Param3 = 0;
+
+ D_LOG(D_ENTRY, ("SignalListenFailure: hdLine: 0x%lx, hdCall: 0x%lx", TapiLineInfo, cm));
+
+ FreeIddCallResources(cm);
+
+ cm->TapiCallState = LINECALLSTATE_IDLE;
+
+ //
+ // signal callstate event call idle
+ //
+ Param1 = cm->TapiCallState;
+ SendLineEvent(Adapter,
+ TapiLineInfo->htLine,
+ cm->htCall,
+ LINE_CALLSTATE,
+ &Param1,
+ &Param2,
+ &Param3);
+
+ SetDefaultListenProf(Prof, GetIDFromLine(Adapter, TapiLineInfo));
+ cm_listen(cm);
+ cm->CallState = CALL_ST_LISTEN;
+}
+
+VOID
+SignalListenSuccess(
+ CM *cm
+ )
+{
+ ADAPTER *Adapter = (ADAPTER*)cm->Adapter;
+ TAPI_LINE_INFO *TapiLineInfo = (TAPI_LINE_INFO*)cm->TapiLineInfo;
+ ULONG Param1 = 0, Param2 = 0, Param3 = 0;
+
+ D_LOG(D_ENTRY, ("SignalListenSuccess: hdLine: 0x%lx, hdcall: 0x%lx", TapiLineInfo, cm));
+
+ cm->TapiCallState = LINECALLSTATE_OFFERING;
+
+ //
+ // indicate line_newcall
+ //
+ Param1 = (ULONG)cm;
+ SendLineEvent(Adapter,
+ TapiLineInfo->htLine,
+ (ULONG)NULL,
+ LINE_NEWCALL,
+ &Param1,
+ &Param2,
+ &Param3);
+
+ cm->htCall = Param2;
+
+ D_LOG(D_ENTRY, ("SignalListenSuccess: Got 0x%lx as htCall from TAPI", cm->htCall));
+
+ //
+ // indicate callstate event call offering
+ //
+ Param1 = cm->TapiCallState;
+ Param2 = 0;
+ Param3 = LINEMEDIAMODE_DIGITALDATA;
+ SendLineEvent(Adapter,
+ TapiLineInfo->htLine,
+ cm->htCall,
+ LINE_CALLSTATE,
+ &Param1,
+ &Param2,
+ &Param3);
+}
+
+VOID
+SignalConnectFailure(
+ CM *cm
+ )
+{
+ ADAPTER *Adapter = (ADAPTER*)cm->Adapter;
+ TAPI_LINE_INFO *TapiLineInfo = (TAPI_LINE_INFO*)cm->TapiLineInfo;
+ ULONG CauseValue = (ULONG)cm->CauseValue;
+ ULONG SignalValue = (ULONG)cm->SignalValue;
+ CM_PROF *Prof = &cm->oprof;
+ ULONG Param1 = 0, Param2 = 0, Param3 = 0;
+
+ D_LOG(D_ENTRY, ("SignalConnectFailure: hdLine: 0x%lx, hdCall: 0x%lx", TapiLineInfo, cm));
+
+
+ FreeIddCallResources(cm);
+
+ //
+ // if this is set then the isdn line is not active
+ //
+ if (cm->NoActiveLine)
+ cm->TapiCallState = LINECALLSTATE_SPECIALINFO;
+ else
+ cm->TapiCallState = LINECALLSTATE_DISCONNECTED;
+
+ D_LOG(D_ALWAYS, ("SignalConnectFailure: CallState: 0x%x", cm->TapiCallState));
+//
+// currently gurdeep is only supporting the disconnect state
+// we will give busy notification in getcallstatus with the
+// disconnect mode
+//
+// else
+// {
+// //
+// // if this was a busy line
+// //
+// if (CauseValue == 0x11 || SignalValue == 0x04)
+// cm->TapiCallState = LINECALLSTATE_BUSY;
+// else
+// cm->TapiCallState = LINECALLSTATE_DISCONNECTED;
+// }
+
+ //
+ // indicate callstate event
+ //
+ Param1 = cm->TapiCallState;
+ SendLineEvent(Adapter,
+ TapiLineInfo->htLine,
+ cm->htCall,
+ LINE_CALLSTATE,
+ &Param1,
+ &Param2,
+ &Param3);
+}
+
+VOID
+SignalConnectSuccess(
+ CM *cm
+ )
+{
+ ADAPTER *Adapter = (ADAPTER*)cm->Adapter;
+ TAPI_LINE_INFO *TapiLineInfo = (TAPI_LINE_INFO*)cm->TapiLineInfo;
+ ULONG Param1 = 0, Param2 = 0, Param3 = 0;
+ CM_PROF *Prof = (CM_PROF*)&cm->dprof;
+
+ D_LOG(D_ENTRY, ("SignalConnectSuccess: hdLine: 0x%lx, hdCall: 0x%lx", TapiLineInfo, cm));
+ cm->TapiCallState = LINECALLSTATE_CONNECTED;
+
+ mtl_set_conn_state(cm->mtl, Prof->chan_num, 1);
+
+ //
+ // indicate line up to wan wrapper
+ //
+ WanLineup(cm, NULL);
+
+ //
+ // indicate callstate event call connected
+ //
+ Param1 = cm->TapiCallState;
+ SendLineEvent(Adapter,
+ TapiLineInfo->htLine,
+ cm->htCall,
+ LINE_CALLSTATE,
+ &Param1,
+ &Param2,
+ &Param3);
+}
+
+VOID
+SignalDisconnect(
+ CM *cm
+ )
+{
+ ADAPTER *Adapter = (ADAPTER*)cm->Adapter;
+ TAPI_LINE_INFO *TapiLineInfo = (TAPI_LINE_INFO*)cm->TapiLineInfo;
+ CM_PROF *Prof = &cm->oprof;
+ ULONG Param1 = 0, Param2 = 0, Param3 = 0;
+
+ D_LOG(D_ENTRY, ("SignalDisconnect: hdLine: 0x%lx, hdCall: 0x%lx", TapiLineInfo, cm));
+
+ cm->TapiCallState = LINECALLSTATE_DISCONNECTED;
+
+ FreeIddCallResources(cm);
+
+ //
+ // indicate callstate event call disconnected
+ //
+ Param1 = cm->TapiCallState;
+ Param3 = LINEMEDIAMODE_DIGITALDATA;
+ SendLineEvent(Adapter,
+ TapiLineInfo->htLine,
+ cm->htCall,
+ LINE_CALLSTATE,
+ &Param1,
+ &Param2,
+ &Param3);
+
+}
+
+VOID
+NoSignal(
+ CM *cm
+ )
+{
+ ADAPTER *Adapter = (ADAPTER*)cm->Adapter;
+ TAPI_LINE_INFO *TapiLineInfo = (TAPI_LINE_INFO*)cm->TapiLineInfo;
+ ULONG Param1 = 0, Param2 = 0, Param3 = 0;
+
+ D_LOG(D_ENTRY, ("NoSignal: hdLine: 0x%lx, hdCall: 0x%lx", TapiLineInfo, cm));
+
+}
+
+
+//
+// Send async line event to connection wrapper
+//
+VOID
+SendLineEvent(
+ ADAPTER *Adapter,
+ HTAPI_LINE htLine,
+ HTAPI_CALL htCall,
+ ULONG ulMsg,
+ PULONG Param1,
+ PULONG Param2,
+ PULONG Param3
+ )
+{
+ NDIS_TAPI_EVENT LineEvent;
+
+ LineEvent.htLine = htLine;
+ LineEvent.htCall = htCall;
+ LineEvent.ulMsg = ulMsg;
+ LineEvent.ulParam1 = *Param1;
+ LineEvent.ulParam2 = *Param2;
+ LineEvent.ulParam3 = *Param3;
+
+ D_LOG(D_ENTRY, ("SendLineEvent: TapiLine: 0x%lx, TapiCall: 0x%lx", htLine, htCall));
+
+
+ NdisMIndicateStatus(Adapter->Handle,
+ NDIS_STATUS_TAPI_INDICATION,
+ &LineEvent,
+ sizeof(NDIS_TAPI_EVENT));
+
+ NdisMIndicateStatusComplete(Adapter->Handle);
+
+ //
+ // stuff to work with conn wrapper without wan wrapper
+ //
+// NdisTapiIndicateStatus(Adapter,
+// &LineEvent,
+// sizeof(NDIS_TAPI_EVENT));
+
+ *Param1 = LineEvent.ulParam1;
+ *Param2 = LineEvent.ulParam2;
+ *Param3 = LineEvent.ulParam3;
+}
+
+
+//
+// set default params for outgoing call
+//
+VOID
+SetDefaultCallingProf(
+ CM_PROF *Profile,
+ ULONG DeviceID)
+{
+ CHAR ProfileName[24];
+
+ D_LOG(D_ENTRY, ("SetDefaultCallingProfile: Profile: 0x%lx, DeviceID: %d", Profile, DeviceID));
+
+ Profile->nailed = 0;
+ Profile->persist = 0;
+ Profile->permanent = 0;
+ Profile->frame_activated = 0;
+ Profile->fallback = 1;
+ Profile->HWCompression = 0;
+ Profile->rx_idle_timer = 0;
+ Profile->tx_idle_timer = 0;
+ Profile->chan_num = 1;
+ Profile->chan_tbl[0].lterm = 0;
+ Profile->chan_tbl[0].bchan = 2;
+ Profile->chan_tbl[0].type = 0;
+ Profile->chan_tbl[0].idd = NULL;
+ sprintf(ProfileName,"Connect%d",DeviceID);
+ NdisMoveMemory(Profile->name, ProfileName, strlen(Profile->name) + 1);
+ sprintf(ProfileName, "*");
+ NdisMoveMemory(Profile->remote_name, ProfileName, strlen(Profile->remote_name) + 1);
+}
+
+//
+// set default params for outgoing call
+//
+VOID
+SetDefaultListenProf(
+ CM_PROF *Profile,
+ ULONG DeviceID)
+{
+ CHAR ProfileName[24];
+
+ D_LOG(D_ENTRY, ("SetDefaultListenProfile: Profile: 0x%lx, DeviceID: %d", Profile, DeviceID));
+
+ Profile->nailed = 0;
+ Profile->persist = 0;
+ Profile->permanent = 0;
+ Profile->frame_activated = 0;
+ Profile->fallback = 1;
+ Profile->HWCompression = 0;
+ Profile->rx_idle_timer = 0;
+ Profile->tx_idle_timer = 0;
+ Profile->chan_num = 1;
+ Profile->chan_tbl[0].lterm = 0;
+ Profile->chan_tbl[0].bchan = 2;
+ Profile->chan_tbl[0].type = 0;
+ Profile->chan_tbl[0].idd = NULL;
+ sprintf(ProfileName,"Listen%d",DeviceID);
+ NdisMoveMemory(Profile->name, ProfileName, __strlen(Profile->name) + 1);
+ sprintf(ProfileName, "*");
+ NdisMoveMemory(Profile->remote_name, ProfileName, __strlen(Profile->remote_name) + 1);
+}
+
+//
+// parse address and store in profile
+//
+VOID
+StashAddress(
+ CM_PROF *Profile,
+ ULONG AddressLength,
+ PUCHAR Address
+ )
+{
+ ULONG TempAddressLen, AddressToParseLen, i, j;
+ UCHAR Temp[128], AddressToParse[128];
+ UCHAR *ChanDelim, *TempAddress;
+ USHORT n;
+
+ TempAddressLen = AddressLength;
+
+ NdisMoveMemory(Temp, Address, AddressLength);
+
+ TempAddress = Temp;
+
+ for (n = 0; n < Profile->chan_num; n++)
+ {
+ //
+ // : is the delimiter between channel address
+ //
+ if ( (ChanDelim = __strchr(TempAddress, ':')) == NULL)
+ {
+ AddressToParseLen = TempAddressLen;
+ NdisMoveMemory(AddressToParse, TempAddress, AddressToParseLen);
+ }
+ else
+ {
+ AddressToParseLen = ChanDelim - TempAddress;
+ NdisMoveMemory (AddressToParse, TempAddress, AddressToParseLen);
+ (PUCHAR)TempAddress = ChanDelim + 1;
+ }
+
+ NdisZeroMemory(Profile->chan_tbl[n].addr, sizeof(Profile->chan_tbl[n].addr));
+
+ //
+ // only digits, *, or # are allowed in dialing number
+ //
+ for (i = 0, j = 0; i < AddressToParseLen; i++)
+ if (isdigit(AddressToParse[i]) ||
+ (AddressToParse[i] == '*') ||
+ (AddressToParse[i] == '#'))
+ Profile->chan_tbl[n].addr[j++] = AddressToParse[i];
+ }
+}
+
+VOID
+FreeIddCallResources(
+ CM *cm
+ )
+{
+ IDD *idd;
+ ULONG n, m;
+
+
+ for (n = 0; n < MAX_IDD_IN_SYSTEM; n++)
+ {
+ idd = GetIddByIndex(n);
+
+ for (m = 0; m < MAX_CHANNELS_PER_IDD; m++)
+ {
+ if (idd && (idd->CallInfo.cm[m] == cm))
+ {
+ idd->CallInfo.cm[m] = NULL;
+ idd->CallInfo.ChannelsUsed--;
+ }
+ }
+ }
+}
+
+//
+// check this cm's idd to see if in use
+// if available mark usage and exit
+// if not return error
+//
+ULONG
+FindAndStashIdd(
+ CM *cm,
+ CM_PROF *Profile
+ )
+{
+ ULONG m, ChannelsNeeded, ChannelsFound, ChannelsFilled;
+ IDD *idd;
+
+
+ ChannelsNeeded = Profile->chan_num;
+ ChannelsFound = ChannelsFilled = 0;
+
+ //
+ // first check the idd that we own
+ //
+ idd = (IDD*)cm->idd;
+
+ ChannelsFound = GetChannelsFromIdd(idd, cm, ChannelsFilled, ChannelsNeeded);
+
+ ChannelsFilled = ChannelsFound;
+
+ ChannelsNeeded -= ChannelsFound;
+
+ //
+ // we need to check other idd's to see if we can steal some channels
+ // this will go away when Microsoft does multilink
+ //
+ if (ChannelsNeeded)
+ {
+ for (m = 0; m < MAX_IDD_IN_SYSTEM; m++)
+ {
+ IDD *idd = GetIddByIndex(m);
+
+ if (idd && ChannelsNeeded)
+ {
+ ChannelsFound = GetChannelsFromIdd(idd,
+ cm,
+ ChannelsFilled,
+ ChannelsNeeded);
+
+ ChannelsFilled += ChannelsFound;
+
+ ChannelsNeeded -= ChannelsFound;
+ }
+ else
+ break;
+ }
+ }
+
+ return(ChannelsFilled);
+}
+
+ULONG
+GetChannelsFromIdd (
+ IDD* idd,
+ CM* cm,
+ ULONG BeginChannel,
+ ULONG ChannelsNeeded
+ )
+{
+ ULONG n, m, ChannelsFilled;
+ CM_PROF *Profile = (CM_PROF*)&cm->oprof;
+
+
+ ChannelsFilled = 0;
+
+ NdisAcquireSpinLock(&idd->lock);
+
+ for (n = BeginChannel; n < BeginChannel + ChannelsNeeded; n++)
+ {
+ //
+ // if not all channels have been used
+ //
+ if (idd->CallInfo.ChannelsUsed < MAX_CHANNELS_PER_IDD)
+ {
+ for (m = 0; m < MAX_CHANNELS_PER_IDD; m++)
+ {
+ if (idd->CallInfo.cm[m] == NULL)
+ {
+ idd->CallInfo.cm[m] = cm;
+ idd->CallInfo.ChannelsUsed++;
+ if (idd->CallInfo.NumLTerms < MAX_LTERMS_PER_IDD)
+ Profile->chan_tbl[n].lterm = 0;
+ else
+ Profile->chan_tbl[n].lterm = (USHORT)m;
+ Profile->chan_tbl[n].idd = idd;
+ ChannelsFilled++;
+ break;
+ }
+ }
+ }
+ }
+
+ NdisReleaseSpinLock(&idd->lock);
+ return(ChannelsFilled);
+}
diff --git a/private/ntos/ndis/digi/pcimac/tapioid.h b/private/ntos/ndis/digi/pcimac/tapioid.h
new file mode 100644
index 000000000..f42f601ef
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/tapioid.h
@@ -0,0 +1,440 @@
+//
+// Tapioid.h - file contains defs and protos for tapioid.c
+//
+//
+//
+//
+
+//
+// internal line states
+//
+#define CALL_ST_IDLE 0
+#define CALL_ST_LISTEN 1
+#define CALL_ST_WAITCONN 2
+#define CALL_ST_CONN 3
+#define CALL_ST_DONTCARE 0xFFFFFFFF
+#define MAX_STATE 4
+#define PCIMAC_SPI_VER 0x00000000
+
+//
+// structure for tapi used line information
+//
+typedef struct tagTAPI_LINE
+{
+ //
+ // id of this line
+ //
+ ULONG LineID;
+
+ //
+ // tapi's handle for this line
+ //
+ HTAPI_LINE htLine;
+
+ //
+ // pointers to connection objects
+ // these are our tapi call handles
+ //
+// VOID *cm[MAX_CALL_PER_LINE];
+ VOID *cm;
+
+ //
+ // async completion id
+ //
+ ULONG ulRequestPendingID;
+
+ //
+ // media modes supportd
+ //
+ ULONG MediaModes;
+
+ //
+ // bearer modes supported
+ //
+ ULONG BearerModes;
+
+ //
+ // line states
+ //
+ ULONG LineStates;
+
+ //
+ // address states
+ //
+ ULONG AddressStates;
+
+ //
+ // media mode currently being monitored
+ //
+ ULONG CurMediaMode;
+
+ //
+ // bearer mode of current call
+ //
+ ULONG CurBearerMode;
+
+ //
+ // line state
+ //
+ ULONG TapiLineState;
+
+ //
+ // line status
+ //
+ ULONG TapiLineStatus;
+
+ //
+ // the idd for this line
+ //
+ VOID *idd;
+
+ //
+ // the adapter for this line
+ //
+ VOID *Adapter;
+
+ //
+ // listening flag
+ //
+ ULONG TapiLineWasListening;
+
+}TAPI_LINE_INFO;
+
+
+#define VALIDATE_EXTENSION(version)
+
+NDIS_STATUS
+TSPI_LineAccept(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineAnswer(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineClose(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineCloseCall(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineConditionalMediaDetect(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineConfigDialog(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineDevSpecific(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineDial(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineDrop(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineGetAddressCaps(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineGetAddressID(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineGetAddressStatus(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineGetCallAddressID(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineGetCallInfo(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineGetCallStatus(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineGetDevCaps(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineGetDevConfig(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineGetExtensionID(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineGetID(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineGetLineDevStatus(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineMakeCall(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineNegotiateExtVersion(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineOpen(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_ProviderInit(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_ProviderShutdown(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineSecureCall(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineSelectExtVersion(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineSendUserToUserInfo(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineSetAppSpecific(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineSetCallParams(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineSetDefaultMediaDetection(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineSetDevConfig(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineSetMediaMode(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineSetStatusMessage(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+VOID
+SignalCallProceeding(
+ CM *cm
+ );
+
+VOID
+SignalListenFailure(
+ CM *cm
+ );
+
+VOID
+SignalListenSuccess(
+ CM *cm
+ );
+
+VOID
+SignalConnectFailure(
+ CM *cm
+ );
+
+VOID
+SignalConnectSuccess(
+ CM *cm
+ );
+
+VOID
+SignalDisconnect(
+ CM *cm
+ );
+
+VOID
+NoSignal(
+ CM *cm
+ );
+
+IDD*
+GetIddFromDeviceID(
+ ADAPTER* Adapter,
+ ULONG DeviceID
+ );
+
+CM*
+GetCallFromCallHandle(
+ ADAPTER* Adapter,
+ HDRV_CALL hdCall
+ );
+
+TAPI_LINE_INFO*
+GetLineFromLineHandle(
+ ADAPTER* Adapter,
+ HDRV_LINE hdLine
+ );
+
+ULONG
+GetIDFromLine(
+ ADAPTER *Adapter,
+ TAPI_LINE_INFO *TapiLineInfo
+ );
+
+VOID
+DoTapiStateCheck(
+ CM* cm
+ );
+
+ULONG
+GetCallState(
+ CM *cm
+ );
+
+VOID
+SendLineEvent(
+ ADAPTER *Adapter,
+ HTAPI_LINE htLine,
+ HTAPI_CALL htCall,
+ ULONG ulMsg,
+ PULONG Param1,
+ PULONG Param2,
+ PULONG Param3
+ );
+
+VOID
+SetDefaultCallingProf(
+ CM_PROF *Profile,
+ ULONG DeviceID
+ );
+
+VOID
+SetDefaultListenProf(
+ CM_PROF *Profile,
+ ULONG DeviceID
+ );
+
+VOID
+StashAddress(
+ CM_PROF *Profile,
+ ULONG AddressLength,
+ PUCHAR Address
+ );
+
+VOID
+FreeIddCallResources(
+ CM *cm
+ );
+
+ULONG
+FindAndStashIdd(
+ CM *cm,
+ CM_PROF *Profile
+ );
+
+//CM*
+//GetCmFromDeviceID(
+// ADAPTER *Adapter,
+// ULONG DeviceID,
+// ULONG AddressID
+// );
+
+CM*
+GetCmFromDeviceID(
+ ADAPTER *Adapter,
+ ULONG DeviceID
+ );
+
+ULONG
+GetChannelsFromIdd (
+ IDD* idd,
+ CM* cm,
+ ULONG BeginChannel,
+ ULONG ChannelsNeeded
+ );
+
diff --git a/private/ntos/ndis/digi/pcimac/trc.h b/private/ntos/ndis/digi/pcimac/trc.h
new file mode 100644
index 000000000..05224c24f
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/trc.h
@@ -0,0 +1,71 @@
+/*
+ * TRC.H - include file for all TRC modules
+ */
+
+#ifndef _TRC_
+#define _TRC_
+
+#include <trc_pub.h>
+
+/* a trace context */
+typedef struct _TRC
+{
+ TRC_STATUS stat; /* status record */
+
+ TRC_ENTRY *ent_tbl; /* entry table (circ. buffer) */
+ ULONG ent_put; /* put pointer */
+ ULONG ent_get; /* get pointer */
+ ULONG ent_num; /* # of entries */
+ ULONG ent_seq; /* sequence # next to use */
+ ULONG create_ref; /* object creation reference */
+ ULONG start_ref; /* object start reference count */
+ IDD *idd; /* idd back pointer */
+} TRC;
+
+/* TRC class operations */
+INT trc_init(ULONG);
+INT trc_term(VOID);
+INT trc_register_idd(VOID* idd);
+INT trc_deregister_idd(VOID* idd);
+
+/* TRC context (object) operations */
+INT trc_create(VOID** ret_trc, ULONG depth);
+INT trc_destroy(VOID* trc);
+INT trc_control(VOID* idd, ULONG op, ULONG arg);
+INT trc_get_status(VOID* trc, TRC_STATUS* stat);
+INT trc_get_entry(VOID* trc, ULONG seq, TRC_ENTRY* ent);
+
+/* trace control opcodes */
+#define TRC_OP_RESET 0 /* reset trace */
+#define TRC_OP_STOP 1 /* stop tracing */
+#define TRC_OP_START 2 /* start tracing */
+
+#define TRC_OP_ADD_IDD 3 /* add idd to trace context */
+ /* arg: idd or NULL for all */
+#define TRC_OP_DEL_IDD 4 /* remove idd from trace context */
+ /* arg: idd or NULL for all */
+#define TRC_OP_SET_FILTER 5 /* set filter for tracing */
+ /* arg: filter type */
+#define TRC_OP_RESET_AREA 6 /* reset area state to idle */
+#define TRC_OP_CREATE 7 /* create trc object */
+#define TRC_OP_DESTROY 8 /* destroy trc object */
+
+/* error codes */
+#define TRC_E_SUCC 0 /* success */
+#define TRC_E_IDD 1 /* idd operation failed */
+#define TRC_E_NOMEM 2 /* not enough memory */
+#define TRC_E_NOSUCH 3 /* no such error */
+#define TRC_E_NOROOM 4 /* no room in a table */
+#define TRC_E_PARAM 5 /* parameter error */
+#define TRC_E_BUSY 6 /* trace context area busy */
+
+/*
+ * TRC_LOC.H - Line trace module, local definitions
+ */
+
+/* prototypes for internal functions */
+VOID trc__cmd_handler(VOID *idd_1, USHORT chan, ULONG Reserved, IDD_MSG *msg);
+INT trc__filter(ULONG filter, CHAR* data, ULONG len);
+
+
+#endif /* _TRC_ */
diff --git a/private/ntos/ndis/digi/pcimac/trc_core.c b/private/ntos/ndis/digi/pcimac/trc_core.c
new file mode 100644
index 000000000..4c802ec8c
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/trc_core.c
@@ -0,0 +1,357 @@
+/*
+ * TRC_CORE.C - trace core module
+ */
+
+#include <ndis.h>
+#include <ndiswan.h>
+#include <mydefs.h>
+#include <mytypes.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+#include <trc.h>
+#include <disp.h>
+
+/* local trace context table (NULL=free) */
+
+#define CheckNULLTrace(Trace) \
+ { \
+ if (Trace == NULL) \
+ break; \
+ }
+
+
+/* register an available idd */
+INT
+trc_register_idd(VOID *idd)
+{
+ IDD_MSG msg;
+
+ D_LOG(D_ENTRY, ("trc_register_idd: entry, idd: 0x%lx", idd));
+
+ /* add handle to idd command receiver */
+ if ( idd_attach(idd, IDD_PORT_CMD_RX, (VOID*)trc__cmd_handler, idd) != IDD_E_SUCC )
+ return(TRC_E_IDD);
+
+ /* issue idd command to stop trace */
+ NdisZeroMemory(&msg, sizeof(msg));
+ msg.opcode = CMD_TRC_OFF;
+ if ( idd_send_msg(idd, &msg, IDD_PORT_CMD_TX, NULL, NULL) != IDD_E_SUCC )
+ return(TRC_E_IDD);
+
+ return(TRC_E_SUCC);
+}
+
+/* deregister an available idd */
+INT
+trc_deregister_idd(VOID *idd)
+{
+ IDD_MSG msg;
+
+ D_LOG(D_ENTRY, ("trc_deregister_idd: entry, idd: 0x%lx", idd));
+
+ /* issue idd command to stop trace */
+ NdisZeroMemory(&msg, sizeof(msg));
+ msg.opcode = CMD_TRC_OFF;
+ if ( idd_send_msg(idd, &msg, IDD_PORT_CMD_TX, NULL, NULL) != IDD_E_SUCC )
+ return(TRC_E_IDD);
+
+ /* remove handle from idd command receiver */
+ if ( idd_detach(idd, IDD_PORT_CMD_RX, (VOID*)trc__cmd_handler, idd) != IDD_E_SUCC )
+ return(TRC_E_IDD);
+ else
+ return(TRC_E_SUCC);
+}
+
+/* create a trace object */
+INT
+trc_create(VOID **trc_1, ULONG depth)
+{
+ TRC **ret_trc = (TRC**)trc_1;
+ NDIS_PHYSICAL_ADDRESS pa = NDIS_PHYSICAL_ADDRESS_CONST(0xffffffff, 0xffffffff);
+ TRC *trc;
+
+ D_LOG(D_ENTRY, ("trc_create: entry, ret_trc: 0x%lx, depth: %ld", ret_trc, depth));
+
+ /* allocate memory object */
+ NdisAllocateMemory((PVOID*)&trc, sizeof(*trc), 0, pa);
+ if ( !trc )
+ {
+ mem_alloc_failed:
+ D_LOG(D_ALWAYS, ("trc_create: memory allocate failed!"));
+ return(TRC_E_NOMEM);
+ }
+ D_LOG(D_ALWAYS, ("trc_create: trc: 0x%lx", trc));
+ NdisZeroMemory(trc, sizeof(*trc));
+
+ /* allocate buffer memory */
+ NdisAllocateMemory((PVOID*)&trc->ent_tbl, sizeof(TRC_ENTRY) * depth,
+ 0, pa);
+ if ( !trc->ent_tbl )
+ goto mem_alloc_failed;
+ D_LOG(D_ALWAYS, ("trc_create: trc->ent_tbl: 0x%lx", trc->ent_tbl));
+ NdisZeroMemory(trc->ent_tbl, sizeof(TRC_ENTRY) * depth);
+
+ /* setup initial field values */
+ trc->stat.state = TRC_ST_STOP;
+ trc->stat.filter = TRC_FT_NONE;
+ trc->stat.depth = depth;
+
+ /* return succ */
+ *ret_trc = trc;
+ return(TRC_E_SUCC);
+}
+
+/* delte a trace object */
+INT
+trc_destroy(VOID *trc_1)
+{
+ TRC *trc = (TRC*)trc_1;
+
+ D_LOG(D_ENTRY, ("trc_destroy: entry, trc: 0x%lx", trc));
+
+ /* free memory */
+ NdisFreeMemory(trc->ent_tbl, sizeof(TRC_ENTRY) * trc->stat.depth, 0);
+ NdisFreeMemory(trc, sizeof(*trc), 0);
+
+ return(TRC_E_SUCC);
+}
+
+/* perform a trace control function */
+INT
+trc_control(VOID *idd, ULONG op, ULONG arg)
+{
+ IDD_MSG msg;
+ TRC *trc;
+ INT ret;
+
+
+ trc = idd_get_trc(idd);
+
+ D_LOG(D_ENTRY, ("trc_control: idd: 0x%lx trc: 0x%lx, op: 0x%x, arg: 0x%x", idd, trc, op, arg));
+
+ /* branch on opcode */
+ switch ( op )
+ {
+ case TRC_OP_CREATE:
+ D_LOG(D_ENTRY, ("trc_control: CreateTrace"));
+ // if no trace object for this idd yet
+ if (trc == NULL)
+ {
+ //create trace object
+ if ((ret = trc_create(&trc, arg)) != TRC_E_SUCC)
+ return(TRC_E_IDD);
+
+ // register trace for this idd
+ if ((ret = trc_register_idd (idd)) != TRC_E_SUCC)
+ {
+ trc_destroy(trc);
+ return(TRC_E_IDD);
+ }
+
+ idd_set_trc (idd, trc);
+
+ // set ref count
+ trc->create_ref = 0;
+
+ // set backpointer
+ trc->idd = idd;
+ }
+ // inc ref count
+ trc->create_ref++;
+ break;
+
+ case TRC_OP_DESTROY:
+ D_LOG(D_ENTRY, ("trc_control: DestroyTrace"));
+
+ // if trc == NULL break;
+ CheckNULLTrace (trc);
+
+ // dec ref count
+ if (--trc->create_ref)
+ break;
+
+ trc_deregister_idd(idd);
+ trc_destroy(trc);
+ idd_set_trc(idd, NULL);
+ break;
+
+ case TRC_OP_RESET :
+ D_LOG(D_ENTRY, ("trc_control: ResetTrace"));
+ // if trc == NULL break;
+ CheckNULLTrace (trc);
+
+ trc->stat.state = TRC_ST_STOP;
+ trc->stat.entries = trc->stat.seq_1st = 0;
+ trc->ent_put = trc->ent_get = trc->ent_num = trc->ent_seq = 0;
+ break;
+
+ case TRC_OP_STOP :
+ D_LOG(D_ENTRY, ("trc_control: StopTrace"));
+ // if trc == NULL break;
+ CheckNULLTrace (trc);
+
+ // check start flag
+ if (--trc->start_ref)
+ break;
+
+ trc->stat.state = TRC_ST_STOP;
+
+ /* issue idd command to stop trace */
+ NdisZeroMemory(&msg, sizeof(msg));
+ msg.opcode = CMD_TRC_OFF;
+ if ( idd_send_msg((VOID*)arg, &msg, IDD_PORT_CMD_TX, NULL, NULL) != IDD_E_SUCC )
+ return(TRC_E_IDD);
+ break;
+
+ case TRC_OP_START :
+ D_LOG(D_ENTRY, ("trc_control: StartTrace"));
+ // if trc == NULL break;
+ CheckNULLTrace (trc);
+
+ trc->stat.state = TRC_ST_RUN;
+
+ // check start flag
+ if (trc->start_ref++)
+ break;
+
+
+ /* issue idd command to start trace */
+ NdisZeroMemory(&msg, sizeof(msg));
+ msg.opcode = CMD_TRC_ON;
+ if ( idd_send_msg((VOID*)arg, &msg, IDD_PORT_CMD_TX, NULL, NULL) != IDD_E_SUCC )
+ return(TRC_E_IDD);
+ break;
+
+ case TRC_OP_SET_FILTER :
+ D_LOG(D_ENTRY, ("trc_control: SetTraceFilter"));
+ // if trc == NULL break;
+ CheckNULLTrace (trc);
+
+ trc->stat.filter = arg;
+ break;
+
+ default :
+ return(TRC_E_PARAM);
+ }
+
+ /* if here, was successful */
+ return(TRC_E_SUCC);
+}
+
+/* get status of a trace context */
+INT
+trc_get_status(VOID *trc_1, TRC_STATUS *stat)
+{
+ TRC *trc = (TRC*)trc_1;
+
+ D_LOG(D_ENTRY, ("trc_get_status: entry, trc: 0x%lx, stat: 0x%lx", trc, stat));
+
+ // if no obect exit
+ if (trc == NULL)
+ return (TRC_E_NOSUCH);
+
+ *stat = trc->stat;
+ stat->entries = trc->ent_num;
+ stat->seq_1st = trc->ent_seq;
+
+ return(TRC_E_SUCC);
+}
+
+/* get an entry by sequence number */
+INT
+trc_get_entry(VOID *trc_1, ULONG seq, TRC_ENTRY *ent)
+{
+ TRC *trc = (TRC*)trc_1;
+ ULONG n, index;
+
+ D_LOG(D_ENTRY, ("trc_get_entry: entry, trc: 0x%lx, seq: %ld, ent: 0x%lx", \
+ trc, seq, ent));
+
+ // if no obect exit
+ if (trc == NULL)
+ return(TRC_E_NOSUCH);
+
+ /* find requested sequence number, temp!!!, using search! */
+ for ( n = 0 ; n < trc->ent_num ; n++ )
+ {
+ index = (trc->ent_get + n) % trc->stat.depth;
+ if ( trc->ent_tbl[index].seq == seq )
+ {
+ /* found */
+ *ent = trc->ent_tbl[index];
+ return(TRC_E_SUCC);
+ }
+ }
+ /* if here not found */
+ return(TRC_E_NOSUCH);
+}
+
+/* handler for trace and dump area data packets */
+VOID
+trc__cmd_handler(VOID *idd_1, USHORT chan, ULONG Reserved, IDD_MSG *msg)
+{
+ TRC *trc;
+ TRC_ENTRY *ent;
+ IDD *idd = (IDD*)idd_1;
+
+
+ D_LOG(D_ENTRY, ("trc__cmd_handler: idd: %lx, chan: %d, msg: %lx", \
+ idd, chan, msg));
+ D_LOG(D_ENTRY, ("trc__cmd_handler: opcode: 0x%x, buflen: 0x%x, bufptr: %lx", \
+ msg->opcode, msg->buflen, msg->bufptr));
+ D_LOG(D_ENTRY, ("trc__cmd_handler: bufid: %lx, param: 0x%x", \
+ msg->bufid, msg->param));
+
+
+ // Get the trace object for this idd
+ trc = idd_get_trc(idd);
+
+ // if no obect exit
+ if (trc == NULL || msg->bufid >= 2)
+ return;
+
+ /* if here it is a trace frame. param is rx/tx attribute */
+ /* establish entry to insert into & update vars */
+
+ /* check if trace enabled */
+ if ( trc->stat.state == TRC_ST_STOP )
+ return;
+
+ D_LOG(D_ALWAYS, ("trc__cmd_handler: trc: %lx", trc));
+ /* check if frame filters in */
+ if ( !trc__filter(trc->stat.filter, msg->bufptr, msg->buflen) )
+ return;
+
+ /* frames needs to be buffered, establish entry pointer */
+ ent = trc->ent_tbl + trc->ent_put;
+ trc->ent_put = (trc->ent_put + 1) % trc->stat.depth;
+ if ( trc->ent_num < trc->stat.depth )
+ trc->ent_num++;
+
+ /* fill up entry */
+ ent->seq = trc->ent_seq++;
+ KeQuerySystemTime(&ent->time_stamp);
+ ent->attr = msg->bufid;
+ ent->org_len = msg->buflen;
+ ent->len = MIN(msg->buflen, sizeof(ent->data));
+ IddGetDataFromAdapter(idd,
+ (PUCHAR)ent->data,
+ (PUCHAR)msg->bufptr,
+ (USHORT)ent->len);
+// NdisMoveMemory (ent->data, msg->bufptr, ent->len);
+}
+
+/* filter trace frame */
+INT
+trc__filter(ULONG filter, CHAR *buf, ULONG len)
+{
+ D_LOG(D_ENTRY, ("trc__filter: entry, filter: %ld, buf: 0x%lx, len: %ld",\
+ filter, buf, len));
+
+ /* not implemented, all frames filter in */
+ return(1);
+}
diff --git a/private/ntos/ndis/digi/pcimac/trc_pub.h b/private/ntos/ndis/digi/pcimac/trc_pub.h
new file mode 100644
index 000000000..67655fcf1
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/trc_pub.h
@@ -0,0 +1,49 @@
+/*
+ * TRC_PUB.H - include file for all TRC modules
+ */
+
+#ifndef _TRC_PUB_
+#define _TRC_PUB_
+
+/* max values & constants */
+#define TRC_MAX_IDD 40 /* of number of idd's (lines) supported */
+#define TRC_MAX_DATA 256 /* max size of frame data buffered */
+
+/* status of trace buffer as reported to user */
+typedef struct
+{
+ ULONG state; /* state of trace */
+#define TRC_ST_STOP 0 /* - is stopped */
+#define TRC_ST_RUN 1 /* - is running */
+
+ ULONG filter; /* active filter type */
+#define TRC_FT_NONE 0 /* - no filter, all frames buffered */
+#define TRC_FT_L2 1 /* - only l2 frames accepted */
+#define TRC_FT_L3 2 /* - only l3 frames accepted */
+
+ ULONG depth; /* depth of trace buffer */
+
+
+ ULONG entries; /* # of entries in buffer now */
+ ULONG seq_1st; /* sequence number of first frame in buffer */
+
+} TRC_STATUS;
+
+/* descriptor for a trace entry */
+typedef struct
+{
+ ULONG seq; /* sequence number for frame */
+ LARGE_INTEGER time_stamp; /* some sort of timing information */
+
+ ULONG attr; /* attribute word */
+#define TRC_AT_RX 0 /* - received frame */
+#define TRC_AT_TX 1 /* - transmit frame */
+
+ ULONG org_len; /* original frame length */
+ ULONG len; /* length of buffered data */
+ UCHAR data[TRC_MAX_DATA]; /* frame data */
+
+} TRC_ENTRY;
+
+#endif /* _TRC_PUB_ */
+
diff --git a/private/ntos/ndis/digi/pcimac/util.c b/private/ntos/ndis/digi/pcimac/util.c
new file mode 100644
index 000000000..448afe990
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/util.c
@@ -0,0 +1,146 @@
+/*
+ * UTIL.C - some utility functions
+ */
+
+#include <ndis.h>
+#include <mydefs.h>
+#include <mytypes.h>
+#include <util.h>
+
+// Total Memory Allocated
+ULONG TotalMemory = 0;
+
+/* constants */
+#define BUF_SIZE 512
+
+#if !BINARY_COMPATIBLE
+/* get current time, in seconds */
+ULONG
+ut_time_now(VOID)
+{
+ LARGE_INTEGER curr_time;
+ LARGE_INTEGER sec;
+ static LARGE_INTEGER base = {0, 0};
+ static BOOL first_call = TRUE;
+
+ /* get current system time */
+ KeQuerySystemTime(&curr_time);
+
+ /* on first call, store base */
+ if ( first_call )
+ {
+ base = curr_time;
+ first_call = FALSE;
+ }
+ /* make relative to base */
+ curr_time.QuadPart -= base.QuadPart;
+
+ /* convert to seconds */
+ sec.QuadPart = curr_time.QuadPart/10000000L;
+
+ /* return as a ULONG */
+ return((ULONG)sec.LowPart);
+}
+#else
+/* get current time, in seconds */
+ULONG
+ut_time_now(VOID)
+{
+ ULONG seconds;
+ static BOOL first_call = TRUE;
+
+ static ULONG base = 0;
+ ULONG curr_time;
+
+
+ // BUGBUG - Have to get real time somehow
+
+ curr_time = base + 1;
+
+ /* on first call, store base */
+ if ( first_call )
+ {
+ base = curr_time;
+ first_call = FALSE;
+ }
+
+ /* make relative to base */
+ seconds = curr_time - base;
+
+ /* return as a ULONG */
+ return(seconds);
+}
+#endif
+
+/* allocate a buffer */
+CHAR*
+ut_get_buf(VOID)
+{
+ CHAR *ret;
+
+ NDIS_PHYSICAL_ADDRESS pa = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
+
+ NdisAllocateMemory((PVOID*)&ret, BUF_SIZE, 0, pa);
+
+ return(ret);
+}
+
+/* free buffer */
+VOID
+ut_free_buf(CHAR *buf)
+{
+ if ( buf )
+ NdisFreeMemory(buf, BUF_SIZE, 0);
+}
+
+/* init */
+VOID
+sema_init(SEMA *s)
+{
+ s->signalled = FALSE;
+ NdisAllocateSpinLock (&s->lock);
+}
+
+VOID
+sema_term(SEMA *s)
+{
+ s->signalled = FALSE;
+ NdisFreeSpinLock (&s->lock);
+}
+
+/* try to get semaphore */
+BOOL
+sema_get(SEMA *s)
+{
+ BOOL ret;
+// KIRQL NewIrql, OldIrql;
+
+// NewIrql = HIGH_LEVEL;
+
+// KeRaiseIrql (NewIrql, &OldIrql);
+
+ NdisAcquireSpinLock (&s->lock);
+
+ if ( !s->signalled )
+ ret = s->signalled = TRUE;
+ else
+ ret = FALSE;
+
+ NdisReleaseSpinLock (&s->lock);
+
+// KeLowerIrql (OldIrql);
+
+ return(ret);
+}
+
+/* free semaphore */
+VOID
+sema_free(SEMA *s)
+{
+ NdisAcquireSpinLock (&s->lock);
+
+ s->signalled = FALSE;
+
+ NdisReleaseSpinLock (&s->lock);
+}
+
diff --git a/private/ntos/ndis/digi/pcimac/util.h b/private/ntos/ndis/digi/pcimac/util.h
new file mode 100644
index 000000000..629c49a71
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/util.h
@@ -0,0 +1,27 @@
+/*
+ * UTIL.H - utility module header
+ */
+
+#ifndef _UTIL_
+#define _UTIL_
+
+/* data structure */
+typedef struct
+{
+ BOOL signalled;
+ NDIS_SPIN_LOCK lock;
+} SEMA;
+
+/* prototypes */
+VOID sema_init(SEMA* s);
+VOID sema_term(SEMA* s);
+BOOL sema_get(SEMA* s);
+VOID sema_free(SEMA* s);
+
+ULONG ut_time_now(VOID);
+CHAR *ut_get_buf(VOID);
+VOID ut_free_buf(CHAR* buf);
+
+/* macros */
+
+#endif /* _UTIL_ */
diff --git a/private/ntos/ndis/digi/pcimac/wan_conn.c b/private/ntos/ndis/digi/pcimac/wan_conn.c
new file mode 100644
index 000000000..16172d1ce
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/wan_conn.c
@@ -0,0 +1,122 @@
+/*
+ * WAN_CONN.C - routines for ras connection and disconnection
+ */
+
+#include <ndis.h>
+#include <ndiswan.h>
+#include <mydefs.h>
+#include <mytypes.h>
+#include <util.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+#include <tapioid.h>
+#include <disp.h>
+
+
+INT
+WanLineup(VOID *cm_1, NDIS_HANDLE Endpoint)
+{
+ CM *cm = (CM*)cm_1;
+ ADAPTER *Adapter = cm->Adapter;
+ NDIS_MAC_LINE_UP ISDNLineUp;
+ MTL *mtl = (MTL*)cm->mtl;
+ TAPI_LINE_INFO *TapiLineInfo = (TAPI_LINE_INFO*)(cm->TapiLineInfo);
+ ULONG LinkSpeed;
+
+ D_LOG(D_ENTRY, ("WanLineup: entry, cm: 0x%lx", cm));
+
+ //
+ // Get the connection speed and fill
+ //
+ mtl_get_conn_speed (mtl, &LinkSpeed);
+
+ D_LOG(D_ALWAYS, ("cm_wanlineup: ConnectSpeed: [%d]", LinkSpeed));
+
+ ISDNLineUp.LinkSpeed = LinkSpeed / 100;
+
+ //
+ // fill line quality
+ //
+ ISDNLineUp.Quality = NdisWanReliable;
+
+ //
+ // fill send windows
+ //
+ ISDNLineUp.SendWindow = MAX_WANPACKET_XMITS;
+
+ //
+ // fill the connection wrapper id
+ // this will need to change (i'm not clear on what is needed here)
+ //
+ if (Endpoint)
+ ISDNLineUp.ConnectionWrapperID = Endpoint;
+ else
+ ISDNLineUp.ConnectionWrapperID = (NDIS_HANDLE)cm->htCall;
+
+ //
+ // fill the link context
+ //
+ ISDNLineUp.NdisLinkHandle = (NDIS_HANDLE)mtl;
+
+ //
+ // clear out link handle since this lineup is for a new connection
+ // will get back a link handle from wrapper
+ //
+ ISDNLineUp.NdisLinkContext = (NDIS_HANDLE)mtl->LinkHandle = NULL;
+
+ //
+ // Tell the wan wrapper that the connection is now up.
+ // We have a new link speed, frame size, quality of service.
+ //
+ NdisMIndicateStatus(
+ (NDIS_HANDLE)Adapter->Handle,
+ NDIS_STATUS_WAN_LINE_UP, // General Status
+ (PVOID)&ISDNLineUp, // Specific Status (baud rate in 100bps)
+ sizeof(ISDNLineUp));
+
+ NdisMIndicateStatusComplete(Adapter->Handle);
+
+ //
+ // save new link handle
+ //
+ cm->LinkHandle = mtl->LinkHandle = ISDNLineUp.NdisLinkContext;
+
+ return(CM_E_SUCC);
+}
+
+INT
+WanLinedown(VOID *cm_1)
+{
+ CM *cm = (CM*)cm_1;
+ ADAPTER *Adapter = cm->Adapter;
+ NDIS_MAC_LINE_DOWN ISDNLineDown;
+ MTL *mtl = (MTL*)cm->mtl;
+
+ D_LOG(D_ENTRY, ("cm_wanlinedown: entry, cm: 0x%lx", cm));
+
+ ISDNLineDown.NdisLinkContext = mtl->LinkHandle;
+
+ NdisMIndicateStatus(
+ (NDIS_HANDLE)Adapter->Handle,
+ NDIS_STATUS_WAN_LINE_DOWN, // General Status
+ (PVOID)&ISDNLineDown, // Specific Status (baud rate in 100bps)
+ sizeof(ISDNLineDown));
+
+ NdisMIndicateStatusComplete(Adapter->Handle);
+
+ //
+ // clear out link handles
+ //
+ cm->LinkHandle = mtl->LinkHandle = NULL;
+
+ //
+ // flush the mtl's wan packet queue
+ //
+ MtlFlushWanPacketTxQueue(mtl);
+
+ return(CM_E_SUCC);
+}
+
+
diff --git a/private/ntos/ndis/digi/pcimac/wanoid.c b/private/ntos/ndis/digi/pcimac/wanoid.c
new file mode 100644
index 000000000..a3cb1241a
--- /dev/null
+++ b/private/ntos/ndis/digi/pcimac/wanoid.c
@@ -0,0 +1,226 @@
+#include <ndis.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <adapter.h>
+#include <util.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+#include <res.h>
+#include <trc.h>
+#include <io.h>
+
+#include <ansihelp.h>
+
+
+//
+// Wan OID's
+//
+static UINT SupportedWanOids[] =
+ {
+ OID_WAN_PERMANENT_ADDRESS,
+ OID_WAN_CURRENT_ADDRESS,
+ OID_WAN_QUALITY_OF_SERVICE,
+ OID_WAN_PROTOCOL_TYPE,
+ OID_WAN_MEDIUM_SUBTYPE,
+ OID_WAN_HEADER_FORMAT,
+ OID_WAN_GET_INFO,
+ OID_WAN_SET_LINK_INFO,
+ OID_WAN_GET_LINK_INFO,
+ OID_WAN_GET_COMP_INFO,
+ OID_WAN_SET_COMP_INFO,
+ };
+
+#define MAX_SUPPORTED_WAN_OIDS 11
+
+
+
+
+NDIS_STATUS
+WanOidProc(
+ NDIS_HANDLE AdapterContext,
+ NDIS_OID Oid,
+ PVOID InfoBuffer,
+ ULONG InfoBufferLen,
+ PULONG BytesReadWritten,
+ PULONG BytesNeeded
+ )
+{
+ NDIS_WAN_MEDIUM_SUBTYPE Medium = NdisWanMediumIsdn;
+ NDIS_WAN_HEADER_FORMAT HeaderFormat = NdisWanHeaderNative;
+ NDIS_WAN_QUALITY WanQuality = NdisWanReliable;
+ ADAPTER *Adapter = (ADAPTER*)AdapterContext;
+ PNDIS_WAN_INFO pWanInfo;
+ PNDIS_WAN_SET_LINK_INFO pLinkSetInfo;
+ PNDIS_WAN_GET_LINK_INFO pLinkGetInfo;
+ NDIS_PHYSICAL_ADDRESS HighestAcceptableMax = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
+ MTL* mtl;
+ CM* cm;
+ ULONG n, NumIddPerAdapter;
+
+ switch (Oid)
+ {
+ case OID_WAN_PERMANENT_ADDRESS:
+ case OID_WAN_CURRENT_ADDRESS:
+ if (InfoBufferLen < 6)
+ {
+ *BytesNeeded = 6;
+ return(NDIS_STATUS_INVALID_LENGTH);
+ }
+
+ cm = (CM*)Adapter->CmTbl[0];
+
+ NdisMoveMemory(InfoBuffer,
+ (PVOID)cm->SrcAddr,
+ 6);
+
+ *BytesNeeded = 0;
+ *BytesReadWritten = 6;
+ break;
+
+ case OID_WAN_QUALITY_OF_SERVICE:
+ NdisMoveMemory(InfoBuffer,
+ (PVOID)(&WanQuality),
+ sizeof(NDIS_WAN_QUALITY));
+ *BytesNeeded = 0;
+ *BytesReadWritten = sizeof(NDIS_WAN_QUALITY);
+ break;
+
+ case OID_WAN_PROTOCOL_TYPE:
+ break;
+
+ case OID_WAN_MEDIUM_SUBTYPE:
+ NdisMoveMemory(InfoBuffer,
+ (PVOID)(&Medium),
+ sizeof(NDIS_WAN_MEDIUM_SUBTYPE));
+ *BytesNeeded = 0;
+ *BytesReadWritten = sizeof(NDIS_WAN_MEDIUM_SUBTYPE);
+ break;
+
+ case OID_WAN_HEADER_FORMAT:
+ NdisMoveMemory(InfoBuffer,
+ (PVOID)(&HeaderFormat),
+ sizeof(NDIS_WAN_HEADER_FORMAT));
+ *BytesNeeded = 0;
+ *BytesReadWritten = sizeof(NDIS_WAN_HEADER_FORMAT);
+ break;
+
+ case OID_WAN_GET_INFO:
+ pWanInfo = (PNDIS_WAN_INFO)InfoBuffer;
+
+ NumIddPerAdapter = EnumIddPerAdapter(Adapter);
+ pWanInfo->Endpoints = 2 * NumIddPerAdapter;
+ pWanInfo->MemoryFlags = 0;
+ pWanInfo->HighestAcceptableAddress = HighestAcceptableMax;
+ pWanInfo->MaxTransmit = MAX_WANPACKET_XMITS;
+ pWanInfo->MaxFrameSize = MAX_WANPACKET_BUFFERSIZE;
+ pWanInfo->HeaderPadding = MAX_WANPACKET_HEADERPADDING;
+ pWanInfo->TailPadding = MAX_WANPACKET_TAILPADDING;
+ pWanInfo->FramingBits = RAS_FRAMING |
+ PPP_FRAMING |
+ PPP_COMPRESS_PROTOCOL_FIELD |
+ MEDIA_NRZ_ENCODING |
+ TAPI_PROVIDER;
+ pWanInfo->DesiredACCM = 0;
+ *BytesNeeded = 0;
+ *BytesReadWritten = sizeof(NDIS_WAN_INFO);
+ break;
+
+ case OID_WAN_SET_LINK_INFO:
+ //
+ // get pointer to link set info
+ //
+ pLinkSetInfo = (PNDIS_WAN_SET_LINK_INFO)InfoBuffer;
+
+ //
+ // get mtl (Link Context)
+ //
+ mtl = (MTL*)pLinkSetInfo->NdisLinkHandle;
+
+ if (!mtl->is_conn)
+ return (NDIS_STATUS_INVALID_DATA);
+
+ mtl->MaxSendFrameSize = pLinkSetInfo->MaxSendFrameSize;
+ mtl->MaxRecvFrameSize = pLinkSetInfo->MaxRecvFrameSize;
+ if (pLinkSetInfo->SendFramingBits)
+ mtl->SendFramingBits = pLinkSetInfo->SendFramingBits;
+ mtl->RecvFramingBits = pLinkSetInfo->RecvFramingBits;
+ mtl->SendCompressionBits = pLinkSetInfo->SendCompressionBits;
+ mtl->RecvCompressionBits = pLinkSetInfo->RecvCompressionBits;
+ D_LOG(DIGIWANOID, ("SetLinkInfo: mtl: 0x%lx\n",mtl));
+ D_LOG(DIGIWANOID, ("SendFramingBits: 0x%x\n", mtl->SendFramingBits));
+ D_LOG(DIGIWANOID, ("RecvFramingBits: 0x%x\n", mtl->RecvFramingBits));
+ *BytesNeeded = 0;
+ *BytesReadWritten = sizeof(NDIS_WAN_SET_LINK_INFO);
+
+ //
+ // get cm (connection context)
+ //
+ cm = (CM*)mtl->cm;
+
+ //
+ // if this connection was originally a PPP connection
+ // and now framing has been backed off to RAS we need to
+ // do some uus negotiation
+ //
+ if ((cm->ConnectionType == CM_PPP) &&
+ (mtl->SendFramingBits & RAS_FRAMING))
+ {
+ //
+ // set flag that will block transmits on this mtl
+ //
+ cm->PPPToDKF = 1;
+
+ //
+ // for all channels (better only be one but???) do uus
+ //
+ for (n = 0; n < cm->dprof.chan_num; n++)
+ {
+ cm->dprof.chan_tbl[n].ustate = CM_US_UUS_SEND;
+ cm__tx_uus_pkt(cm->dprof.chan_tbl + n, CM_ASSOC_RQ, 0);
+ }
+ mtl->IddTxFrameType = IDD_FRAME_DKF;
+ }
+
+ break;
+
+ case OID_WAN_GET_LINK_INFO:
+ //
+ // get pointer to link set info
+ //
+ pLinkGetInfo = (PNDIS_WAN_GET_LINK_INFO)InfoBuffer;
+
+ //
+ // get mtl (Link Context)
+ //
+ mtl = (MTL*)pLinkGetInfo->NdisLinkHandle;
+
+ if (!mtl->is_conn)
+ return (NDIS_STATUS_INVALID_DATA);
+
+ pLinkGetInfo->MaxSendFrameSize = mtl->MaxSendFrameSize;
+ pLinkGetInfo->MaxRecvFrameSize = mtl->MaxRecvFrameSize;
+ pLinkGetInfo->HeaderPadding = mtl->PreamblePadding;
+ pLinkGetInfo->TailPadding = mtl->PostamblePadding;
+ pLinkGetInfo->SendFramingBits = mtl->SendFramingBits;
+ pLinkGetInfo->RecvFramingBits = mtl->RecvFramingBits;
+ pLinkGetInfo->SendCompressionBits = mtl->SendCompressionBits;
+ pLinkGetInfo->RecvCompressionBits = mtl->RecvCompressionBits;
+ D_LOG(DIGIWANOID, ("GetLinkInfo: mtl: 0x%lx\n",mtl));
+ D_LOG(DIGIWANOID, ("SendFramingBits: 0x%x\n", mtl->SendFramingBits));
+ D_LOG(DIGIWANOID, ("RecvFramingBits: 0x%x\n", mtl->RecvFramingBits));
+ *BytesNeeded = 0;
+ *BytesReadWritten = sizeof(NDIS_WAN_GET_LINK_INFO);
+ break;
+
+ case OID_WAN_GET_COMP_INFO:
+ case OID_WAN_SET_COMP_INFO:
+ return(NDIS_STATUS_INVALID_OID);
+
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
diff --git a/private/ntos/ndis/dirs b/private/ntos/ndis/dirs
new file mode 100644
index 000000000..e7ffae833
--- /dev/null
+++ b/private/ntos/ndis/dirs
@@ -0,0 +1,62 @@
+!IF 0
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ dirs
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS= \
+ ndis40 \
+ ndiswan \
+ pcn \
+ dc21x4 \
+ \
+ \
+ detect \
+ \
+ ieepro \
+ elnk16 \
+ elnkii \
+ elnk3 \
+ elnkmc \
+ ibmtok \
+ ibmtok2i \
+ lance \
+ loop \
+ lt200 \
+ madge \
+ ndistapi \
+ ne1000 \
+ ne2000 \
+ ne3200 \
+ \
+ digi \
+ \
+ sonic \
+ \
+ \
+ ubnei \
+ wd \
+ htdsu \
+
+
+
+OPTIONAL_DIRS= \
+ \
+ \
+ testprot
diff --git a/private/ntos/ndis/elnk16/elnk16.c b/private/ntos/ndis/elnk16/elnk16.c
new file mode 100644
index 000000000..36fdbc0bb
--- /dev/null
+++ b/private/ntos/ndis/elnk16/elnk16.c
@@ -0,0 +1,35 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ elnk16.c
+
+Abstract:
+
+ This is the main file for the Etherlink 16 Ethernet adapter.
+ This driver conforms to the NDIS 3.0 interface.
+
+Author:
+
+ Johnson R. Apacible (JohnsonA) 10-June-1991
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+
+--*/
+
+#include "..\elnkmc\elnk.c"
+#include "..\elnkmc\send.c"
+#include "..\elnkmc\reset.c"
+#include "..\elnkmc\transfer.c"
+#include "..\elnkmc\interrup.c"
+#include "..\elnkmc\request.c"
+#include "..\elnkmc\loopback.c"
+#include "..\elnkmc\packet.c"
+#include "..\elnkmc\command.c"
diff --git a/private/ntos/ndis/elnk16/elnk16.ini b/private/ntos/ndis/elnk16/elnk16.ini
new file mode 100644
index 000000000..883d5cd5b
--- /dev/null
+++ b/private/ntos/ndis/elnk16/elnk16.ini
@@ -0,0 +1,21 @@
+//
+// Valid values for
+//
+// IrqLevel are 3, 5, 7, 9, 10, 11, 12, and 15
+// WindowSize are 16, 32, 48, 64
+// WindowBase are C0000, C8000, D0000, D8000
+// IoBase are 200, 210, 220, 230, 240, 250, 260, 280, 2A0, 2B0,
+// 2C0, 2D0, 2E0, 300, 310, 320, 330, 340, 350, 360,
+// 380, 390, 3A0, 3E0
+// Tranceiver are External and Internal
+// ZeroWaitState are Enabled and Diabled (ZWS will not work on all machines)
+//
+
+[ELNK16]
+ IrqLevel = 5
+ WindowSize = 16
+ WindowBase = D0000
+ IoBase = 200
+ Transceiver = External
+ ZeroWaitState = Disabled
+
diff --git a/private/ntos/ndis/elnk16/elnk16.rc b/private/ntos/ndis/elnk16/elnk16.rc
new file mode 100644
index 000000000..502e08793
--- /dev/null
+++ b/private/ntos/ndis/elnk16/elnk16.rc
@@ -0,0 +1,39 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "3Com Etherlink 16 network driver"
+#define VER_INTERNALNAME_STR "ELNK16.SYS"
+#define VER_ORIGINALFILENAME_STR "ELNK16.SYS"
+
+#include "common.ver"
+
diff --git a/private/ntos/ndis/elnk16/makefile b/private/ntos/ndis/elnk16/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/elnk16/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/elnk16/sources b/private/ntos/ndis/elnk16/sources
new file mode 100644
index 000000000..637e47084
--- /dev/null
+++ b/private/ntos/ndis/elnk16/sources
@@ -0,0 +1,45 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=elnk16
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+INCLUDES=.;..\elnkmc;..\..\inc;..\..\..\inc
+
+SOURCES=elnk16.rc \
+ elnk16.c
+
+
+RELATIVE_DEPTH=..\..
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+
+
diff --git a/private/ntos/ndis/elnk16/switch.h b/private/ntos/ndis/elnk16/switch.h
new file mode 100644
index 000000000..8853f8911
--- /dev/null
+++ b/private/ntos/ndis/elnk16/switch.h
@@ -0,0 +1,42 @@
+
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ switch.h
+
+Abstract:
+
+ determines whether we are building the Elnkmc or the Elnk16.
+
+Author:
+
+ Johnson R. Apacible (JohnsonA) 9-June-1991
+
+Environment:
+
+ This driver is expected to work in DOS and NT at the equivalent
+ of kernel mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+
+--*/
+
+#ifndef _ELNKSWITCH_
+#define _ELNKSWITCH_
+//
+// Build for the Etherlink 16
+//
+#define ELNKMC 0
+#endif // _ELNKSWITCH
+
diff --git a/private/ntos/ndis/elnk3/card.c b/private/ntos/ndis/elnk3/card.c
new file mode 100644
index 000000000..ba8e26d9f
--- /dev/null
+++ b/private/ntos/ndis/elnk3/card.c
@@ -0,0 +1,1321 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ card.c
+
+Abstract:
+
+ Ndis 3.0 MAC driver for the 3Com Etherlink III
+
+Author:
+
+ Brian Lieuallen BrianLie 09/22/92
+
+Environment:
+
+ Kernel Mode Operating Systems : NT
+
+Revision History:
+
+ Portions borrowed from ELNK3 driver by
+ Earle R. Horton (EarleH)
+
+
+
+
+--*/
+
+
+
+#include <ndis.h>
+#include <efilter.h>
+
+#include "debug.h"
+
+
+#include "elnk3hrd.h"
+#include "elnk3sft.h"
+#include "elnk3.h"
+
+#include "keywords.h"
+
+
+#pragma NDIS_INIT_FUNCTION(Elnk3FindIsaBoards)
+#pragma NDIS_INIT_FUNCTION(Elnk3ActivateIsaBoard)
+#pragma NDIS_INIT_FUNCTION(ReadStationAddress)
+#pragma NDIS_INIT_FUNCTION(ELNK3WriteIDSequence)
+#pragma NDIS_INIT_FUNCTION(ELNK3ContentionTest)
+#pragma NDIS_INIT_FUNCTION(Elnk3GetEisaResources)
+#pragma NDIS_INIT_FUNCTION(CardEnable)
+#pragma NDIS_INIT_FUNCTION(CardTest)
+#pragma NDIS_INIT_FUNCTION(ELNK3ReadEEProm)
+#pragma NDIS_INIT_FUNCTION(Elnk3ProgramEEProm)
+#pragma NDIS_INIT_FUNCTION(Elnk3WriteEEProm)
+#pragma NDIS_INIT_FUNCTION(Elnk3WaitEEPromNotBusy)
+
+
+BOOLEAN
+CardTest (
+ OUT PELNK3_ADAPTER pAdapter
+ )
+/*++
+
+ Routine Description:
+
+
+ Arguments:
+
+
+ Return Value:
+
+
+--*/
+{
+
+ IF_INIT_LOUD (DbgPrint("Elnk3: CardTest(): Entered\n");)
+
+
+ if (!ReadStationAddress(pAdapter)) {
+ return FALSE;
+ }
+
+
+ if (!CardEnable(pAdapter)) {
+ return FALSE;
+ }
+
+
+ return TRUE;
+}
+
+
+BOOLEAN
+CardEnable(
+ IN PELNK3_ADAPTER pAdapter
+ )
+/*++
+
+Routine Description:
+
+ This routine enables the card hardware and sets the dma channel and
+ interrupts number by writing to the Cards option register
+
+Arguments:
+
+Return Value:
+
+Note:
+
+ This should not be called before the registry is read and the Dma
+ and interrupt info is in place.
+
+--*/
+
+{
+
+ USHORT Temp;
+ UINT i;
+ ULONG Limit;
+ USHORT AddressConfig;
+ USHORT RevisionLevel;
+
+
+ IF_INIT_LOUD(DbgPrint("ELNK3: CardEnable\n");)
+
+
+ CardReset(pAdapter);
+
+ ELNK3_SELECT_WINDOW(pAdapter,WNO_FIFO);
+
+ ELNK3ReadAdapterUshort(pAdapter,PORT_FREE_RX_BYTES,&pAdapter->RxFifoSize);
+
+
+ //
+ // Set the station address
+
+ ELNK3_SELECT_WINDOW(pAdapter,WNO_STATIONADDRESS);
+
+ for (i=0;i<3;i++) {
+ Temp=pAdapter->StationAddress[i*2] | (((USHORT)pAdapter->StationAddress[i*2+1])<<8);
+ ELNK3WriteAdapterUshort(pAdapter,(i*2),Temp);
+ }
+
+ //
+ // Read address config register to find out transceiver type
+ //
+ ELNK3_SELECT_WINDOW(pAdapter,WNO_SETUP);
+
+ ELNK3ReadAdapterUshort(pAdapter,PORT_CfgAddress,&AddressConfig);
+
+ ELNK3_SELECT_WINDOW(pAdapter,WNO_DIAGNOSTICS);
+
+ IF_INIT_LOUD(DbgPrint("ELNK3: Address config register is %04x\n",AddressConfig);)
+
+ if ((AddressConfig >> 14) == 0) {
+ //
+ // Enable link beat on TP
+ //
+ if (pAdapter->EEpromSoftwareInfo & LINK_BEAT_DISABLED) {
+
+ IF_INIT_LOUD(DbgPrint("ELNK3: CardEnable: NOT Enabling link beat on 10 Base-T\n");)
+
+ ELNK3WriteAdapterUshort(pAdapter,PORT_MEDIA_TYPE, MEDIA_JABBER);
+
+ } else {
+
+ IF_INIT_LOUD(DbgPrint("ELNK3: CardEnable: Enabling link beat on 10 Base-T\n");)
+
+ ELNK3WriteAdapterUshort(pAdapter,PORT_MEDIA_TYPE,MEDIA_LINK_BEAT | MEDIA_JABBER);
+
+ }
+
+ }
+
+ ELNK3ReadAdapterUshort(pAdapter,PORT_NET_DIAG,&RevisionLevel);
+
+ RevisionLevel= ((RevisionLevel & 0x1e) >> 1);
+
+ pAdapter->RevisionLevel=(UCHAR)RevisionLevel;
+
+ ELNK3_SELECT_WINDOW(pAdapter,WNO_OPERATING);
+
+ //
+ // Test to see if the interrupt works or not
+ //
+ ELNK3_COMMAND(pAdapter,EC_ACKNOWLEDGE_INTERRUPT,0xff);
+ ELNK3_COMMAND(pAdapter,EC_SET_INTERRUPT_MASK,EC_INT_INTERRUPT_REQUESTED);
+ ELNK3_COMMAND(pAdapter,EC_SET_READ_ZERO_MASK,0xff);
+
+ pAdapter->InitInterrupt=FALSE;
+
+ pAdapter->AdapterInitializing=TRUE;
+
+ ELNK3_COMMAND(pAdapter,EC_REQUEST_INTERRUPT,0);
+
+ Limit=2000;
+
+ while ((--Limit>0) && (!pAdapter->InitInterrupt)) {
+ NdisStallExecution(10);
+ }
+
+ pAdapter->AdapterInitializing=FALSE;
+
+ //
+ // Did it time out or did we get an interrupt
+ //
+ if (Limit==0) {
+ IF_INIT_LOUD(DbgPrint("ELNK3: Did not receive interrupt\n");)
+ return FALSE;
+ }
+
+ ELNK3_COMMAND(pAdapter,EC_RX_RESET,0);
+ ELNK3_WAIT_NOT_BUSY(pAdapter);
+
+
+
+// ELNK3_COMMAND(pAdapter,EC_RX_ENABLE,0);
+// ELNK3_COMMAND(pAdapter,EC_TX_ENABLE,0);
+
+ if ((AddressConfig >> 14) == 3) {
+ //
+ // turn on 10base2 converter
+ //
+ IF_INIT_LOUD(DbgPrint("ELNK3: CardEnable: Turning on 10base2 converter\n");)
+
+ ELNK3_COMMAND(pAdapter,EC_START_COAX_XCVR,0);
+
+ NdisStallExecution(800);
+ }
+
+
+
+ pAdapter->CurrentInterruptMask=EC_INT_RX_EARLY |
+ EC_INT_TX_COMPLETE |
+ EC_INT_RX_COMPLETE |
+ EC_INT_TX_AVAILABLE |
+ EC_INT_ADAPTER_FAILURE |
+ EC_INT_INTERRUPT_REQUESTED;
+
+ ELNK3_COMMAND(pAdapter,EC_SET_INTERRUPT_MASK,pAdapter->CurrentInterruptMask);
+ ELNK3_COMMAND(pAdapter,EC_SET_READ_ZERO_MASK,pAdapter->CurrentInterruptMask);
+
+
+ IF_INIT_LOUD(DbgPrint("ELNK3: Adapter initialized correctly\n");)
+ return TRUE;
+}
+
+
+
+BOOLEAN
+CardReInit(
+ IN PELNK3_ADAPTER pAdapter
+ )
+
+{
+ USHORT FifoStatus;
+ USHORT FreeFifoBytes;
+
+ ELNK3_SELECT_WINDOW(pAdapter,WNO_DIAGNOSTICS);
+
+ ELNK3ReadAdapterUshort(pAdapter,PORT_FIFO_DIAG,&FifoStatus);
+
+ ELNK3_SELECT_WINDOW(pAdapter,WNO_OPERATING);
+
+ if (FifoStatus & RX_UNDERRUN) {
+ IF_LOUD(DbgPrint("ELNK3: Receive Underrun\n");)
+
+ ELNK3_COMMAND(pAdapter,EC_RX_RESET,0);
+ ELNK3_WAIT_NOT_BUSY(pAdapter);
+
+ ELNK3_COMMAND(pAdapter,EC_RX_ENABLE,0);
+
+ ELNK3_COMMAND(pAdapter, EC_SET_RX_FILTER, pAdapter->RxFilter);
+ }
+
+ if (FifoStatus & TX_OVERRUN) {
+
+ ELNK3ReadAdapterUshort(pAdapter,PORT_TxFree,&FreeFifoBytes);
+
+ IF_LOUD(DbgPrint("ELNK3: Transmit Overrun - Bytesfree=%d\n",FreeFifoBytes);)
+
+
+ ELNK3_COMMAND(pAdapter,EC_TX_RESET,0);
+ ELNK3_WAIT_NOT_BUSY(pAdapter);
+
+ ELNK3_COMMAND(pAdapter,EC_TX_ENABLE,0);
+ }
+
+
+ return TRUE;
+
+}
+
+
+VOID
+CardReStart(
+ IN PELNK3_ADAPTER pAdapter
+ )
+
+{
+
+ IF_LOUD(DbgPrint("ELNK3: CardRestart\n");)
+
+ //
+ // put the filter back
+ //
+ ELNK3_COMMAND(pAdapter, EC_SET_RX_FILTER, 0);
+
+
+ ELNK3_COMMAND(pAdapter,EC_SET_READ_ZERO_MASK,0x00);
+
+ pAdapter->CurrentInterruptMask=EC_INT_RX_EARLY |
+ EC_INT_TX_COMPLETE |
+ EC_INT_RX_COMPLETE |
+ EC_INT_TX_AVAILABLE |
+ EC_INT_ADAPTER_FAILURE |
+ EC_INT_INTERRUPT_REQUESTED;
+
+ ELNK3_COMMAND(pAdapter,EC_SET_INTERRUPT_MASK,pAdapter->CurrentInterruptMask);
+
+
+
+ //
+ // Reset and re-enable the receiver
+ //
+ ELNK3_COMMAND(pAdapter,EC_RX_RESET,0);
+ ELNK3_WAIT_NOT_BUSY(pAdapter);
+
+ ELNK3_COMMAND(pAdapter,EC_RX_ENABLE,0);
+
+
+ //
+ // reset and restart the transmitter
+ //
+ ELNK3_COMMAND(pAdapter,EC_TX_RESET,0);
+ ELNK3_WAIT_NOT_BUSY(pAdapter);
+
+ ELNK3_COMMAND(pAdapter,EC_TX_ENABLE,0);
+
+ ELNK3_COMMAND(pAdapter,EC_SET_TX_START,pAdapter->TxStartThreshold & 0x7ff);
+
+ //
+ // clear all pending interrupts
+ //
+ ELNK3_COMMAND(pAdapter,EC_ACKNOWLEDGE_INTERRUPT,0xff);
+
+ //
+ // reset the receive buffer info
+ //
+ pAdapter->CurrentPacket=0;
+
+ pAdapter->TransContext[0].BytesAlreadyRead=0;
+ pAdapter->TransContext[0].PacketLength=0;
+
+ pAdapter->TransContext[1].BytesAlreadyRead=0;
+ pAdapter->TransContext[1].PacketLength=0;
+}
+
+
+VOID
+CardReStartDone(
+ IN PELNK3_ADAPTER pAdapter
+ )
+
+{
+
+ IF_LOUD(DbgPrint("ELNK3: CardRestartDone\n");)
+
+ ELNK3_COMMAND(pAdapter,EC_SET_READ_ZERO_MASK,0xff);
+ //
+ // put the filter back
+ //
+ ELNK3_COMMAND(pAdapter, EC_SET_RX_FILTER, pAdapter->RxFilter);
+
+ return;
+}
+
+
+VOID
+CardReset(
+ IN PELNK3_ADAPTER pAdapter
+ )
+/*++
+
+ Routine Description:
+
+
+ Arguments:
+
+
+ Return Value:
+
+
+--*/
+{
+
+ IF_INIT_LOUD(DbgPrint("ELNK3: Reset Card\n");)
+
+ //
+ // Mask everything
+ //
+ ELNK3_COMMAND(pAdapter,EC_SET_INTERRUPT_MASK,0);
+
+ //
+ // Clear all interrupt reasons
+ //
+ ELNK3_COMMAND(pAdapter,EC_ACKNOWLEDGE_INTERRUPT,0xff);
+
+
+ ELNK3_COMMAND(pAdapter,EC_RX_RESET,0);
+ ELNK3_WAIT_NOT_BUSY(pAdapter);
+
+ ELNK3_COMMAND(pAdapter,EC_TX_RESET,0);
+ ELNK3_WAIT_NOT_BUSY(pAdapter);
+}
+
+
+
+
+BOOLEAN
+ReadStationAddress(
+ OUT PELNK3_ADAPTER pAdapter
+ )
+/*++
+
+ Routine Description:
+ Read the station address from the PROM
+
+ Arguments:
+
+
+ Return Value:
+
+
+--*/
+
+{
+
+ UINT i,Sum;
+ USHORT Temp;
+
+ Sum=0;
+
+ IF_INIT_LOUD( DbgPrint("Elnk3: The Station address is ");)
+
+ ELNK3_SELECT_WINDOW(pAdapter,0);
+
+
+ //
+ // Read the eeprom software info to see if we need
+ // to enable link beat of not
+ //
+ pAdapter->EEpromSoftwareInfo=ELNK3ReadEEProm(
+ pAdapter,
+ (UCHAR)EEPROM_SOFTWARE_INFO
+ );
+
+
+
+ for (i=0;i<3;i++) {
+ Temp=ELNK3ReadEEProm(
+ pAdapter,
+ (UCHAR)i
+ );
+
+
+ pAdapter->PermanentAddress[i*2] = Temp>>8;
+ pAdapter->PermanentAddress[i*2+1] = Temp & 0x00ff;
+ IF_INIT_LOUD( DbgPrint(" %04X",Temp);)
+ }
+
+ //
+ // Put the product id value back in the eeprom data register
+ //
+ ELNK3ReadEEProm(
+ pAdapter,
+ (UCHAR)EEPROM_PRODUCT_ID
+ );
+
+
+
+
+ //
+ // Copy in permanent address if necessary
+ //
+
+ if (!(pAdapter->StationAddress[0] |
+ pAdapter->StationAddress[1] |
+ pAdapter->StationAddress[2] |
+ pAdapter->StationAddress[3] |
+ pAdapter->StationAddress[4] |
+ pAdapter->StationAddress[5])) {
+
+ ETH_COPY_NETWORK_ADDRESS(pAdapter->StationAddress,
+ pAdapter->PermanentAddress
+ );
+ }
+
+
+ IF_INIT_LOUD( DbgPrint("\n");)
+
+
+ return TRUE;
+}
+
+
+
+
+
+UINT
+Elnk3FindIsaBoards(
+ IN PMAC_BLOCK pMacBlock
+ )
+
+{
+
+ PVOID IdPort=pMacBlock->TranslatedIdPort;
+ UINT i;
+ USHORT ProductId;
+
+
+ if (pMacBlock->IsaAdaptersFound != 0) {
+
+ IF_INIT_LOUD(DbgPrint("Elnk3: FindIsaBorads: called again\n");)
+
+ return pMacBlock->IsaAdaptersFound;
+ }
+
+ IF_INIT_LOUD(DbgPrint("Elnk3: FindIsaBorads: called, first time\n");)
+
+ //
+ // Untag all adapters
+ //
+
+ ELNK3WriteIDSequence( IdPort );
+
+ NdisRawWritePortUchar(IdPort, IDCMD_SET_TAG+0);
+
+ //
+ // We find all the ISA boards in the system and tag them
+ // We note each ones configured I/O base, so that
+ // we can reset all of the ones not configured as EISA
+ //
+
+ for (i=0; i<7 ; i++) {
+
+ //
+ // Get the cards' attention
+ //
+ ELNK3WriteIDSequence( IdPort );
+
+ //
+ // See if there any cards out there
+ //
+ if ( ELNK3ContentionTest( IdPort, EE_MANUFACTURER_CODE ) == EISA_MANUFACTURER_ID ) {
+ //
+ // we found at least one
+ //
+ ELNK3ContentionTest( IdPort, EE_TCOM_NODE_ADDR_WORD0 );
+ ELNK3ContentionTest( IdPort, EE_TCOM_NODE_ADDR_WORD1 );
+ ELNK3ContentionTest( IdPort, EE_TCOM_NODE_ADDR_WORD2 );
+
+ //
+ // This one won the contention battle
+ // Get it's i/o base and irq from the eeprom
+ //
+
+ ProductId=ELNK3ContentionTest( IdPort, EE_VULCAN_PROD_ID );
+
+ ProductId&=0xf0ff;
+
+ if (ProductId == 0x9050) {
+ //
+ // This one is a elnk3 adapter
+ //
+ pMacBlock->IsaCards[i].AddressConfigRegister=
+ ELNK3ContentionTest( IdPort, EE_ADDR_CONFIGURATION );
+
+ pMacBlock->IsaCards[i].IOPort= 0x200 + ((pMacBlock->IsaCards[i].AddressConfigRegister & 0x1f)<<4);
+
+ } else {
+ //
+ // We found a 3Com card that is not an elnk3.
+ // We will set the base address, to make it look like an EISA
+ // one so that code below will leave it alone
+ //
+ IF_INIT_LOUD(DbgPrint("Elnk3: Found non-elnk3 during contention ProductId=%04x\n",ProductId);)
+
+ pMacBlock->IsaCards[i].IOPort=0x3f0;
+ }
+
+ pMacBlock->IsaCards[i].Tagged=TRUE;
+ //
+ // Tag it so it don't bother us again
+ //
+ NdisRawWritePortUchar(IdPort, IDCMD_SET_TAG+(i+1));
+
+
+ IF_INIT_LOUD(DbgPrint("ELNK3: Found Elnk3 card #%d, io=%04x\n",
+ i,
+ pMacBlock->IsaCards[i].IOPort
+ );)
+
+
+ } else {
+ //
+ // No more elnk3 cards
+ //
+ break;
+ }
+ }
+
+
+ //
+ // Now all of the ISA adapters have been found and tagged
+ // We now go through and reset all of the ones that are
+ // not configured as EISA.
+ //
+
+ for (i=0; i<7 ; i++) {
+
+ //
+ // Get the cards' attention
+ //
+ ELNK3WriteIDSequence( IdPort );
+
+ //
+ // If it is not configured as eisa reset it
+ //
+ if ((pMacBlock->IsaCards[i].IOPort != 0x03f0) && pMacBlock->IsaCards[i].Tagged) {
+
+ IF_INIT_LOUD(DbgPrint("ELNK3: Reseting Elnk3 card #%d\n",i);)
+
+ //
+ // Put the others back to sleep
+ //
+ NdisRawWritePortUchar(IdPort, IDCMD_TEST_TAG+(i+1));
+
+ //
+ // Reset this one
+ //
+ NdisRawWritePortUchar(IdPort, IDCMD_RESET);
+
+ NdisStallExecution(500);
+
+ } else {
+#if DBG
+ if (pMacBlock->IsaCards[i].Tagged) {
+
+ IF_INIT_LOUD(DbgPrint("ELNK3: NOT Reseting EISA configured Elnk3 card #%d\n",i);)
+ }
+#endif
+ }
+
+ }
+
+ //
+ // Now we go and find the adapters for real.
+ //
+
+ //
+ // Untag all adapters
+ //
+
+ ELNK3WriteIDSequence( IdPort );
+
+ NdisRawWritePortUchar(IdPort, IDCMD_SET_TAG+0);
+
+
+ for (i=0; i<7 ; i++) {
+
+ //
+ // Get the cards' attention
+ //
+ ELNK3WriteIDSequence( IdPort );
+
+ //
+ // See if there any cards out there
+ //
+ if ( ELNK3ContentionTest( IdPort, EE_MANUFACTURER_CODE ) == EISA_MANUFACTURER_ID ) {
+
+ //
+ // we found at least one
+ //
+ ELNK3ContentionTest( IdPort, EE_TCOM_NODE_ADDR_WORD0 );
+ ELNK3ContentionTest( IdPort, EE_TCOM_NODE_ADDR_WORD1 );
+ ELNK3ContentionTest( IdPort, EE_TCOM_NODE_ADDR_WORD2 );
+
+ //
+ // This one won the contention battle
+ // Get it's i/o base and irq from the eeprom
+ //
+
+ ProductId=ELNK3ContentionTest( IdPort, EE_VULCAN_PROD_ID );
+
+ ProductId&=0xf0ff;
+
+ if (ProductId == 0x9050) {
+ //
+ // This one is a elnk3 adapter
+ //
+
+ pMacBlock->IsaCards[i].AddressConfigRegister=
+ ELNK3ContentionTest( IdPort, EE_ADDR_CONFIGURATION );
+
+ pMacBlock->IsaCards[i].ResourceConfigRegister=
+ ELNK3ContentionTest( IdPort, EE_RESOURCE_CONFIGURATION );
+
+
+ pMacBlock->IsaCards[i].IOPort= 0x200 + ((pMacBlock->IsaCards[i].AddressConfigRegister & 0x1f)<<4);
+ pMacBlock->IsaCards[i].Irq=pMacBlock->IsaCards[i].ResourceConfigRegister >> 12;
+
+ if (pMacBlock->IsaCards[i].IOPort == 0x03f0) {
+ //
+ // This one is configured as EISA. Mark it as active
+ // so it will be ignored
+ //
+ IF_INIT_LOUD(DbgPrint("ELNK3: Found Elnk3 ISA configed as EISA\n");)
+
+ pMacBlock->IsaCards[i].Active=TRUE;
+ }
+
+ } else {
+ //
+ // We found a 3Com card that is not an elnk3.
+ // We will set the base address, to make it look like an EISA
+ // one so that code below will leave it alone
+ //
+ IF_INIT_LOUD(DbgPrint("Elnk3: Found non-elnk3 during contention ProductId=%04x\n",ProductId);)
+
+ pMacBlock->IsaCards[i].IOPort=0x3f0;
+
+ pMacBlock->IsaCards[i].Active=TRUE;
+ }
+
+
+ //
+ // Tag it so it don't bother us again
+ //
+ NdisRawWritePortUchar(IdPort, IDCMD_SET_TAG+(i+1));
+
+
+ IF_INIT_LOUD(DbgPrint("ELNK3: Found Elnk3 card #%d, io=%04x, irq=%d\n",
+ i,
+ pMacBlock->IsaCards[i].IOPort,
+ pMacBlock->IsaCards[i].Irq
+ );)
+
+ //
+ // One more found
+ //
+ pMacBlock->IsaAdaptersFound++;
+
+ } else {
+ //
+ // No more elnk3 cards
+ //
+ break;
+ }
+ }
+
+ return pMacBlock->IsaAdaptersFound;
+
+}
+
+
+BOOLEAN
+Elnk3ActivateIsaBoard(
+ IN PMAC_BLOCK pMacBlock,
+ IN PELNK3_ADAPTER pAdapter,
+ IN NDIS_HANDLE AdapterHandle,
+ IN PUCHAR TranslatedIoBase,
+ IN ULONG ConfigIoBase,
+ IN OUT PULONG Irq,
+ IN ULONG Transceiver,
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+
+{
+
+ PVOID IdPort=pMacBlock->TranslatedIdPort;
+ UINT i;
+ USHORT AddressConfig;
+ USHORT ResourceConfig;
+
+ for (i=0; i<pMacBlock->IsaAdaptersFound; i++) {
+ //
+ // Search our table for a card that matches the I/O base passed
+ // in from the registry
+ //
+
+ if ((pMacBlock->IsaCards[i].IOPort == ConfigIoBase)
+ &&
+ (pMacBlock->IsaCards[i].Irq==*Irq)
+ &&
+ ((pMacBlock->IsaCards[i].AddressConfigRegister>>14) == (USHORT)Transceiver)
+ &&
+ (!pMacBlock->IsaCards[i].Active)) {
+ //
+ // Everything matched and it is not currently active
+ //
+
+ IF_LOUD(DbgPrint("ELNK3: Found Match-Activating ISA card # %d at %04x\n",i,ConfigIoBase);)
+ //
+ // Found one, Now get the cards' attention
+ //
+
+ ELNK3WriteIDSequence( IdPort );
+
+ //
+ // Put the others back to sleep
+ //
+ NdisRawWritePortUchar(IdPort, IDCMD_TEST_TAG+(i+1));
+
+ //
+ // Activate it at the its configured base.
+ //
+ NdisRawWritePortUchar(IdPort,IDCMD_ACTIVATE + ((ConfigIoBase-0x200) >> 4));
+
+ //
+ // this one is in use now
+ //
+ pMacBlock->IsaCards[i].Active=TRUE;
+
+ //
+ // enable the IRQ drivers
+ //
+ NdisRawWritePortUchar(
+ TranslatedIoBase+PORT_CfgControl,
+ CCR_ENABLE
+ );
+
+ return TRUE;
+ }
+ }
+
+ IF_LOUD(DbgPrint("ELNK3: Did not find an adapter that matched i/O base %04x\n",ConfigIoBase);)
+
+ //
+ // Did not find a match, So now we activate the first unused
+ // card at the address supplied in the registry.
+ //
+ if ((*Irq != 0) && (Transceiver != 2)) {
+ //
+ // The irq and transceiver parameters are present,
+ // so we will reprogram the card to make them match
+ //
+
+ for (i=0; i<pMacBlock->IsaAdaptersFound; i++) {
+ //
+ // Search our table for a card that has not been activated
+ //
+
+ if ((!pMacBlock->IsaCards[i].Active)) {
+
+ IF_LOUD(DbgPrint("ELNK3: Reconfiguring ISA card # %d to %04x, %d, %d\n",i,ConfigIoBase,*Irq,Transceiver);)
+
+ //
+ // Found one, Now get the cards' attention
+ //
+
+ ELNK3WriteIDSequence( IdPort );
+
+ //
+ // Put the others back to sleep
+ //
+ NdisRawWritePortUchar(IdPort, IDCMD_TEST_TAG+(i+1));
+
+ //
+ // Activate where we want it
+ //
+ NdisRawWritePortUchar((PUCHAR)IdPort,IDCMD_ACTIVATE + ((ConfigIoBase-0x200) >> 4));
+
+ //
+ // in use now
+ //
+ pMacBlock->IsaCards[i].Active=TRUE;
+
+ //
+ // set the transceiver bits in the address config register
+ //
+ NdisRawReadPortUshort(
+ TranslatedIoBase+PORT_CfgAddress,
+ &AddressConfig
+ );
+
+ //
+ // only want the change the transceiver bits and io base
+ //
+ AddressConfig &= 0x3fc0;
+
+ AddressConfig |= (Transceiver << 14) | ((ConfigIoBase - 0x200) >> 4);
+
+ NdisRawWritePortUshort(
+ TranslatedIoBase+PORT_CfgAddress,
+ AddressConfig
+ );
+
+ //
+ // set the irq number in resources config register
+ //
+ ResourceConfig=((USHORT)*Irq << 12) | 0x0f00;
+
+
+ NdisRawWritePortUshort(
+ TranslatedIoBase+PORT_CfgResource,
+ ResourceConfig
+ );
+
+ //
+ // enable the IRQ drivers
+ //
+ NdisRawWritePortUchar(
+ TranslatedIoBase+PORT_CfgControl,
+ CCR_ENABLE
+ );
+
+
+ //
+ // Program the eeprom to match the registry
+ //
+ Elnk3ProgramEEProm(
+ pAdapter,
+ AddressConfig,
+ ResourceConfig
+ );
+
+ return TRUE;
+ }
+ }
+
+ //
+ // Did not find any un activated cards
+ //
+ IF_LOUD(DbgPrint("ELNK3: Did not find an un activated adapter\n");)
+
+ return FALSE;
+
+ } else {
+ //
+ // the irq and/or transceiver values were missing from the registry.
+ // Activate the card where the eeprom says it should be.
+ //
+ IF_LOUD(DbgPrint("Elnk3: irq and transceiver values missing\n");)
+
+ for (i=0; i<pMacBlock->IsaAdaptersFound; i++) {
+ //
+ // Search our table for a card that has not been activated
+ //
+ if ((pMacBlock->IsaCards[i].IOPort == ConfigIoBase)
+ &&
+ (!pMacBlock->IsaCards[i].Active)) {
+
+ IF_LOUD(DbgPrint("ELNK3: Activating ISA card # %d at %04x\n",i,ConfigIoBase);)
+
+ //
+ // Found one, Now get the cards' attention
+ //
+
+ ELNK3WriteIDSequence( IdPort );
+
+ //
+ // Put the others back to sleep
+ //
+ NdisRawWritePortUchar(IdPort, IDCMD_TEST_TAG+(i+1));
+
+ //
+ // Activate where we want it
+ //
+ NdisRawWritePortUchar((PUCHAR)IdPort,IDCMD_ACTIVATE + ((ConfigIoBase-0x200) >> 4));
+
+ //
+ // enable the IRQ drivers
+ //
+ NdisRawWritePortUchar(
+ TranslatedIoBase+PORT_CfgControl,
+ CCR_ENABLE
+ );
+
+ //
+ // in use now
+ //
+ pMacBlock->IsaCards[i].Active=TRUE;
+
+ *Irq=pMacBlock->IsaCards[i].Irq;
+
+ IF_INIT_LOUD(DbgPrint("Elnk3: Missing IRQ is now %d\n",*Irq);)
+
+ {
+ NDIS_CONFIGURATION_PARAMETER Value;
+ NDIS_STATUS Status;
+ NDIS_STRING IrqKeyword = INTERRUPT;
+ NDIS_STRING TransceiverKeyword = TRANSCEIVER;
+ NDIS_HANDLE ConfigHandle = NULL;
+
+ //
+ // Open the configuration database.
+ //
+ NdisOpenConfiguration(
+ &Status,
+ &ConfigHandle,
+ ConfigurationHandle);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ return(FALSE);
+ }
+
+ Value.ParameterType = NdisParameterInteger;
+ Value.ParameterData.IntegerData = *Irq;
+ NdisWriteConfiguration(
+ &Status,
+ ConfigHandle,
+ &IrqKeyword,
+ &Value);
+
+ Value.ParameterType = NdisParameterInteger;
+ Value.ParameterData.IntegerData =
+ pMacBlock->IsaCards[i].AddressConfigRegister>>14;
+ NdisWriteConfiguration(
+ &Status,
+ ConfigHandle,
+ &TransceiverKeyword,
+ &Value);
+
+ NdisCloseConfiguration(ConfigHandle);
+ }
+
+ return TRUE;
+ }
+ }
+
+ //
+ // Did not find any un activated cards
+ //
+ IF_LOUD(DbgPrint("ELNK3: Did not find an un activated adapter\n");)
+
+ return FALSE;
+ }
+}
+
+
+VOID
+Elnk3ProgramEEProm(
+ PELNK3_ADAPTER pAdapter,
+ USHORT AddressConfig,
+ USHORT ResourceConfig
+ )
+
+{
+ USHORT Temp;
+ USHORT CheckSum;
+
+ Elnk3WriteEEProm(
+ pAdapter,
+ EE_ADDR_CONFIGURATION,
+ AddressConfig
+ );
+
+ Elnk3WriteEEProm(
+ pAdapter,
+ EE_RESOURCE_CONFIGURATION,
+ ResourceConfig
+ );
+
+ Temp=ELNK3ReadEEProm(
+ pAdapter,
+ EE_SOFTWARE_CONFIG_INFO
+ );
+
+ CheckSum=((AddressConfig>>8) ^ (AddressConfig & 0x00ff));
+
+ CheckSum= CheckSum ^ (ResourceConfig >> 8);
+ CheckSum= CheckSum ^ (ResourceConfig & 0x00ff);
+
+ CheckSum= CheckSum ^ (Temp >> 8);
+ CheckSum= CheckSum ^ (Temp & 0x00ff);
+
+ Temp=ELNK3ReadEEProm(
+ pAdapter,
+ EE_CHECK_SUM
+ );
+
+ Elnk3WriteEEProm(
+ pAdapter,
+ EE_CHECK_SUM,
+ (USHORT)((Temp & 0xff00) | (CheckSum & 0x00ff))
+ );
+
+}
+
+
+
+
+VOID
+ELNK3WriteIDSequence(
+ IN PVOID IdPort
+ )
+/*++
+
+Routine Description:
+
+ Writes the magic EtherLink III wake up sequence to a port.
+
+ This puts all uninitialized EtherLink III cards on the bus in the ID_CMD
+ state.
+
+ Must be called with exclusive access to all 1x0h ports, where x is any
+ hex digit.
+
+
+Arguments:
+
+
+Return Value:
+
+
+
+--*/
+
+
+{
+ USHORT outval;
+ UINT i;
+
+ NdisRawWritePortUchar(IdPort,0);
+ NdisRawWritePortUchar(IdPort,0);
+
+
+ for ( outval = 0xff, i = 255 ; i-- ; ) {
+ NdisRawWritePortUchar(IdPort,outval);
+ outval <<= 1;
+ if ( ( outval & 0x0100 ) != 0 ){
+ outval ^= 0xCF;
+ }
+ }
+}
+
+
+
+
+USHORT
+ELNK3ContentionTest(
+ IN PVOID IdPort,
+ IN UCHAR EEPromWord
+ )
+{
+
+ UCHAR data;
+ USHORT result;
+ UINT i;
+
+ NdisRawWritePortUchar((PUCHAR)IdPort,IDCMD_READ_PROM + EEPromWord);
+
+
+ /*
+ 3COM's detection code has a 400 microsecond delay here.
+ */
+ NdisStallExecution(400);
+
+ for ( i = 16, result = 0 ; i-- ; ) {
+ result <<= 1;
+ NdisRawReadPortUchar(IdPort,&data);
+ result += (data & 1);
+ }
+ return (result);
+}
+
+
+
+
+
+
+
+
+
+
+
+USHORT
+ELNK3ReadEEProm(
+ IN PELNK3_ADAPTER Adapter,
+ IN UCHAR EEPromWord
+)
+{
+ USHORT result;
+ ULONG Limit=10;
+
+ // Issue an EEPROM read command.
+
+ NdisRawWritePortUchar(Adapter->PortOffsets[PORT_EECmd],(UCHAR)(IDCMD_READ_PROM+EEPromWord));
+
+ //
+ // Spin until the EEPROM busy bit goes off.
+ //
+ Elnk3WaitEEPromNotBusy(Adapter);
+
+ //
+ // Fetch the data from the EEPROM data register.
+ //
+ ELNK3ReadAdapterUshort(Adapter,PORT_EEData,&result);
+
+ return ( result );
+}
+
+VOID
+Elnk3WriteEEProm(
+ IN PELNK3_ADAPTER pAdapter,
+ IN UCHAR EEPromWord,
+ IN USHORT Value
+ )
+
+{
+ Elnk3WaitEEPromNotBusy(pAdapter);
+
+ //
+ // put the data in the data register
+ //
+ ELNK3WriteAdapterUshort(pAdapter,PORT_EEData,Value);
+
+ //
+ // enable erase and write
+ //
+ ELNK3WriteAdapterUchar(pAdapter,PORT_EECmd,(UCHAR)EE_COMMAND_EW_ENABLE);
+
+ Elnk3WaitEEPromNotBusy(pAdapter);
+
+ //
+ // erase the register
+ //
+ ELNK3WriteAdapterUchar(pAdapter,PORT_EECmd,(UCHAR)EE_COMMAND_ERASE+EEPromWord);
+
+ Elnk3WaitEEPromNotBusy(pAdapter);
+
+ //
+ // enable erase and write again
+ //
+ ELNK3WriteAdapterUchar(pAdapter,PORT_EECmd,(UCHAR)EE_COMMAND_EW_ENABLE);
+
+ Elnk3WaitEEPromNotBusy(pAdapter);
+
+ //
+ // Now write the data
+ //
+ ELNK3WriteAdapterUchar(pAdapter,PORT_EECmd,(UCHAR)EE_COMMAND_WRITE+EEPromWord);
+
+ Elnk3WaitEEPromNotBusy(pAdapter);
+
+}
+
+VOID
+Elnk3WaitEEPromNotBusy(
+ PELNK3_ADAPTER Adapter
+ )
+
+{
+
+ USHORT result;
+ ULONG Limit;
+ //
+ // Spin until the EEPROM busy bit goes off.
+ //
+ Limit=100;
+
+ ELNK3ReadAdapterUshort(Adapter,PORT_EECmd,&result);
+
+ while ((--Limit>0) && ( (result & EE_BUSY) != 0)) {
+
+ NdisStallExecution(1000);
+ ELNK3ReadAdapterUshort(Adapter,PORT_EECmd,&result);
+
+ }
+
+#if DBG
+ if (Limit == 0) {
+
+ IF_LOUD(DbgPrint("Elnk3: time out waiting for eeprom to not be busy\n");)
+
+ }
+#endif
+
+}
+
+
+VOID
+Elnk3GetEisaResources(
+ IN PELNK3_ADAPTER pAdapter,
+ IN OUT PULONG Irq
+ )
+
+{
+ USHORT Config;
+
+ ELNK3_SELECT_WINDOW(pAdapter, WNO_SETUP);
+
+ ELNK3ReadAdapterUshort(pAdapter,PORT_CfgResource,&Config);
+
+ IF_LOUD(DbgPrint("Elnk3: Eisa Irq is %d\n",Config>>12);)
+
+ *Irq=Config>>12;
+
+}
+
+
+#ifdef IO_DBG
+USHORT ELNK3_READ_PORT_USHORT( PVOID Adapter, ULONG Offset )
+{
+ USHORT data;
+ data = READ_PORT_USHORT((PUSHORT)((PELNK3_ADAPTER)Adapter)->PortOffsets[Offset]);
+ IF_IO_LOUD(DbgPrint("read ushort %x from port %x\n", data, Offset );)
+ return data;
+}
+USHORT ELNK3_READ_PORT_USHORT_DIRECT( PVOID Offset )
+{
+ USHORT data;
+ data = READ_PORT_USHORT((PUSHORT)Offset);
+ IF_IO_LOUD(DbgPrint("read ushort %x from port %x\n", data, Offset );)
+ return data;
+}
+#endif
+
diff --git a/private/ntos/ndis/elnk3/config.c b/private/ntos/ndis/elnk3/config.c
new file mode 100644
index 000000000..3b8744842
--- /dev/null
+++ b/private/ntos/ndis/elnk3/config.c
@@ -0,0 +1,514 @@
+ /*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ config.c
+
+Abstract:
+
+ Ndis 3.0 MAC driver for the 3Com Etherlink III
+
+
+Author:
+ Brian Lieuallen (BrianLie) 07/02/92
+
+Environment:
+
+ Kernel Mode Operating Systems : NT
+
+Revision History:
+
+ Portions borrowed from ELNK3 driver by
+ Earle R. Horton (EarleH)
+
+
+
+--*/
+
+
+
+#include <ndis.h>
+//#include <efilter.h>
+
+#include "debug.h"
+
+
+#include "elnk3hrd.h"
+#include "elnk3sft.h"
+#include "elnk3.h"
+
+#include "keywords.h"
+
+
+#pragma NDIS_INIT_FUNCTION(Elnk3ReadRegistry)
+
+
+
+NDIS_STATUS
+Elnk3ReadRegistry(
+ IN PELNK3_ADAPTER pAdapter,
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+
+{
+ NDIS_HANDLE ConfigHandle = NULL;
+ PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
+ NDIS_STRING MaxMulticastListStr = MAX_MULTICAST_LIST;
+ NDIS_STRING IOAddressStr = IOADDRESS;
+ NDIS_STRING BusTypeStr = BUS_TYPE;
+ NDIS_STRING InterruptStr = INTERRUPT;
+ NDIS_STRING TransceiverStr = TRANSCEIVER;
+ NDIS_STRING ReceiveMethodStr = NDIS_STRING_CONST("ReceiveMethod");
+ NDIS_STRING ThresholdStr = NDIS_STRING_CONST("ThresholdTarget");
+ NDIS_STRING IdPortAddressStr = NDIS_STRING_CONST("IdPortBaseAddress");
+ NDIS_STRING TxThresholdStr = NDIS_STRING_CONST("EarlyTransmitThreshold");
+ NDIS_STRING TxThresholdIncStr = NDIS_STRING_CONST("EarlyTransmitThresholdIncrement");
+ NDIS_STRING CardTypeStr = NDIS_STRING_CONST("CardType");
+
+ BOOLEAN ConfigError = FALSE;
+ ULONG ConfigErrorValue = 0;
+
+ NDIS_MCA_POS_DATA McaData;
+
+ NDIS_STATUS Status;
+
+ UINT i;
+ //
+ // These are used when calling Elnk3RegisterAdapter.
+ //
+
+ ULONG TxThreshold = 384;
+ ULONG TxThresholdInc = 256;
+
+ ULONG ThresholdTarget = 400;
+ ELNK3_ADAPTER_TYPE AdapterType = 0;
+ UINT IoBaseAddr = 0x300;
+ UINT BusNumber = 0;
+ NDIS_INTERFACE_TYPE BusType = Eisa;
+ UINT ChannelNumber = 0;
+ ULONG InterruptNumber = 0;
+ PUCHAR NetworkAddress;
+ UINT Length;
+ UINT IdPortBaseAddr = 0x110;
+
+ NDIS_EISA_FUNCTION_INFORMATION EisaData;
+
+ NDIS_INTERRUPT_MODE InterruptMode=NdisInterruptLatched;
+
+ ULONG Transceiver = 2;
+
+ TxThreshold = 128;
+ TxThresholdInc = 64;
+
+ pAdapter->ReceiveMethod=0;
+
+ pAdapter->EarlyReceiveHandler=Elnk3IndicatePackets2;
+ pAdapter->ReceiveCompleteHandler=Elnk3IndicatePackets2;
+
+ NdisOpenConfiguration(
+ &Status,
+ &ConfigHandle,
+ ConfigurationHandle);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ return(Status);
+ }
+
+ //
+ // Read Adapter Type (determine if this is a 3c589 PCMCIA card)
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &CardTypeStr,
+ NdisParameterInteger);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ AdapterType = (UINT)(ReturnedValue->ParameterData.IntegerData);
+ pAdapter->CardType = AdapterType;
+ }
+
+ //
+ // Read network address
+ //
+ NdisReadNetworkAddress(
+ &Status,
+ &NetworkAddress,
+ &Length,
+ ConfigHandle);
+ if (Status==NDIS_STATUS_SUCCESS)
+ {
+ for (i = 0; i < 6; i++)
+ {
+ pAdapter->StationAddress[i]=NetworkAddress[i];
+ }
+ }
+
+ //
+ // Read receive method
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &ReceiveMethodStr,
+ NdisParameterHexInteger);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ pAdapter->ReceiveMethod=ReturnedValue->ParameterData.IntegerData;
+
+ if ((ReturnedValue->ParameterData.IntegerData) == 1)
+ {
+ //
+ // Change to alternate
+ //
+ IF_LOUD(DbgPrint("ELNK3: Using alternate receive method\n");)
+
+ pAdapter->EarlyReceiveHandler=Elnk3EarlyReceive;
+ pAdapter->ReceiveCompleteHandler=Elnk3IndicatePackets;
+ }
+ else
+ {
+ pAdapter->ReceiveMethod=0;
+
+ pAdapter->EarlyReceiveHandler=Elnk3IndicatePackets2;
+ pAdapter->ReceiveCompleteHandler=Elnk3IndicatePackets2;
+ }
+ }
+
+ //
+ // Read Threshold point
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &ThresholdStr,
+ NdisParameterHexInteger);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ ThresholdTarget=ReturnedValue->ParameterData.IntegerData;
+ }
+
+
+ //
+ // Read TX Threshold start point
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &TxThresholdStr,
+ NdisParameterHexInteger);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ TxThreshold=ReturnedValue->ParameterData.IntegerData;
+ }
+
+ //
+ // Read TX Threshold start point increment
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &TxThresholdIncStr,
+ NdisParameterHexInteger);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ TxThresholdInc=ReturnedValue->ParameterData.IntegerData;
+ }
+
+ //
+ // Read Id port Address
+ //
+ if (AdapterType != ELNK3_3C589)
+ {
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &IdPortAddressStr,
+ NdisParameterHexInteger);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ IdPortBaseAddr = (ReturnedValue->ParameterData.IntegerData);
+
+ //
+ // Confirm value
+ //
+ if (IdPortBaseAddr < 0x100 ||
+ IdPortBaseAddr > 0x1f0 ||
+ ((IdPortBaseAddr & 0x0f) != 0))
+ {
+ //
+ // Error
+ //
+ goto Fail00;
+ }
+ }
+ }
+
+ //
+ // Read interrupt number
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &InterruptStr,
+ NdisParameterHexInteger);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ InterruptNumber = (CCHAR)(ReturnedValue->ParameterData.IntegerData);
+ }
+
+ //
+ // Read tranceiver type
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &TransceiverStr,
+ NdisParameterHexInteger);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ Transceiver = (ReturnedValue->ParameterData.IntegerData);
+ }
+
+ //
+ // Read BusType type
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &BusTypeStr,
+ NdisParameterHexInteger);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ BusType = (ReturnedValue->ParameterData.IntegerData);
+ }
+
+ if (BusType == Isa)
+ {
+ //
+ // Bus type ISA must be a 3c509.
+ //
+ if (AdapterType != ELNK3_3C589)
+ AdapterType=ELNK3_3C509;
+
+ //
+ // Read I/O Address
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &IOAddressStr,
+ NdisParameterHexInteger);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ IoBaseAddr = (ReturnedValue->ParameterData.IntegerData);
+
+ //
+ // Confirm value
+ //
+ if (IoBaseAddr < 0x200 ||
+ IoBaseAddr > 0x3e0 ||
+ ((IoBaseAddr & 0x0f) != 0))
+ {
+ //
+ // If the user is going to bother to give us a base address it
+ // had better be valid
+ //
+ goto Fail00;
+ }
+ }
+ else if (pAdapter->CardType == ELNK3_3C589)
+ {
+ // PCMCIA Adapter MUST get something for IRQ keyword
+ // otherwise there is I/O allocated to this adapter
+ //
+ goto Fail00;
+ }
+ }
+ else
+ {
+ if (BusType == MicroChannel)
+ {
+ //
+ // Bus type MCA must be a 3c529
+ //
+ AdapterType=ELNK3_3C529;
+
+ NdisReadMcaPosInformation(
+ &Status,
+ ConfigurationHandle,
+ &ChannelNumber,
+ &McaData);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Info read failed
+ //
+ IF_LOUD(DbgPrint("Elnk3: Failed to read POS information for card, slot# %d\n",ChannelNumber);)
+ goto Fail00;
+ }
+
+ if ((McaData.AdapterId != ELNK3_3C529_TP_MCA_ID) &&
+ (McaData.AdapterId != ELNK3_3C529_COMBO_MCA_ID) &&
+ (McaData.AdapterId != ELNK3_3C529_BNC_MCA_ID) &&
+ (McaData.AdapterId != ELNK3_3C529_TPCOAX_MCA_ID) &&
+ (McaData.AdapterId != ELNK3_3C529_TPONLY_MCA_ID))
+ {
+ //
+ // Not an Elnk3 adapter in this position
+ //
+ IF_LOUD(DbgPrint("Elnk3: The card found is not an ELNK3\n");)
+ goto Fail00;
+ }
+
+ if (!(McaData.PosData1 & 0x01))
+ {
+ //
+ // Bit 0 is set if the adapter is enabled
+ //
+ IF_LOUD(DbgPrint("Elnk3: The elnk3 is not enabled\n");)
+ goto Fail00;
+ }
+
+ //
+ // We have found an 3c529 in the specified slot
+ //
+ InterruptNumber=McaData.PosData4 & 0x0f;
+ IoBaseAddr=((McaData.PosData3 & 0xfc) << 8) + 0x200;
+
+ //
+ // The NIUps has a level triggered interrupt, as compared to
+ // the other two which do not
+ //
+ InterruptMode=NdisInterruptLevelSensitive;
+ }
+ else
+ {
+ if (BusType == Eisa)
+ {
+ //
+ // It's an eisa bus, Two possiblities, 3c579 or 3c509.
+ //
+ // Initialize the EisaData with garbage, in case the EISA
+ // config doesn't return any function information.
+ //
+ EisaData.CompressedId = 0xf00df00d;
+ EisaData.MinorRevision = 0xca;
+ EisaData.MajorRevision = 0xfe;
+
+ NdisReadEisaSlotInformation(
+ &Status,
+ ConfigurationHandle,
+ &ChannelNumber,
+ &EisaData);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // If the call worked, but the EisaData didn't change,
+ // we'll just assume that the card is a 3c579. If the
+ // EisaData did change, then we check to make sure it's
+ // an Elnk3.
+ //
+ if (((EisaData.CompressedId == 0xf00df00d) &&
+ (EisaData.MinorRevision = 0xca) &&
+ (EisaData.MajorRevision = 0xfe)) ||
+ ((EisaData.CompressedId & 0xf0ffffff) == ELNK3_EISA_ID))
+ {
+ AdapterType=ELNK3_3C579;
+
+ IoBaseAddr=(ChannelNumber<<12);
+
+ goto CloseConfig;
+ }
+ else
+ {
+ IF_LOUD(DbgPrint("ELNK3: The card found is not an ELNK3 id=%0lx\n",EisaData.CompressedId);)
+ }
+ }
+ else
+ {
+ //
+ // Info read failed
+ //
+ IF_LOUD(DbgPrint("ELNK3: Failed to get Eisa config information for card, bus# %d slot# %d\n",BusNumber,ChannelNumber);)
+ }
+
+ //
+ // Does not seem to be an EISA card, try for an ISA
+ //
+ AdapterType=ELNK3_3C509;
+
+ //
+ // Read I/O Address
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &IOAddressStr,
+ NdisParameterHexInteger);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ IoBaseAddr = (ReturnedValue->ParameterData.IntegerData);
+
+ //
+ // Confirm value
+ //
+ if (IoBaseAddr < 0x200 ||
+ IoBaseAddr > 0x3e0 ||
+ ((IoBaseAddr & 0x0f) != 0))
+ {
+ //
+ // Error
+ //
+ goto Fail00;
+ }
+ }
+ }
+ }
+ }
+
+CloseConfig:
+
+
+ NdisCloseConfiguration(ConfigHandle);
+
+ pAdapter->TxStartThreshold = (USHORT)TxThreshold;
+ pAdapter->TxStartThresholdInc = (USHORT)TxThresholdInc;
+
+ pAdapter->IdPortBaseAddr = IdPortBaseAddr;
+ pAdapter->IoPortBaseAddr = IoBaseAddr;
+
+ pAdapter->ThresholdTarget = ThresholdTarget;
+ pAdapter->IrqLevel = InterruptNumber;
+ pAdapter->InterruptMode = InterruptMode;
+ pAdapter->CardType = AdapterType;
+
+ pAdapter->Transceiver = Transceiver;
+
+ IF_LOUD( DbgPrint( "\n\nElnk3: Registering adapter \n"
+ "Elnk3: I/O base addr 0x%lx\n"
+ "Elnk3: Interrupt number %d\n\n",
+ IoBaseAddr,
+ InterruptNumber);)
+
+
+ return(NDIS_STATUS_SUCCESS);
+
+Fail00:
+
+ NdisCloseConfiguration(ConfigHandle);
+ return(NDIS_STATUS_FAILURE);
+}
diff --git a/private/ntos/ndis/elnk3/debug.h b/private/ntos/ndis/elnk3/debug.h
new file mode 100644
index 000000000..da849a12c
--- /dev/null
+++ b/private/ntos/ndis/elnk3/debug.h
@@ -0,0 +1,133 @@
+
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ debug.h
+
+Abstract:
+
+ It contains the various debug definitions and macros used in displaying
+ debugging information on the kernel debugger.
+
+Author:
+
+
+Environment:
+
+ Kernel Mode Operating Systems : NT
+
+Revision History:
+
+
+--*/
+
+
+#if DBG
+
+typedef struct _DEBUG_STATS {
+
+ ULONG TotalInterrupts;
+ ULONG TxCompIntCount;
+ ULONG TxAvailIntCount;
+ ULONG TxCompleted;
+
+ ULONG RxCompIntCount;
+ ULONG RxEarlyIntCount;
+ ULONG PacketIndicated;
+ ULONG IndicationCompleted;
+ ULONG TransferDataCount;
+ ULONG IndicateWithDataReady;
+ ULONG BadReceives;
+ ULONG SecondEarlyReceive;
+ ULONG BroadcastsRejected;
+
+ } DEBUG_STATS, *PDEBUG_STATUS;
+
+typedef struct _LOG_ENTRY {
+ UCHAR Letter1;
+ UCHAR Letter2;
+ USHORT Data;
+ } LOG_ENTRY, *PLOG_ENTRY;
+
+
+#define ELNK3_MAX_LOG_SIZE 128
+
+extern ULONG Elnk3LogArray[];
+extern ULONG ElnkLogPointer;
+
+
+#define IF_ELNK3DEBUG(f) if (Elnk3DebugFlag & (f))
+extern ULONG Elnk3DebugFlag;
+
+#define ELNK3_DEBUG_LOUD 0x00000001 // debugging info
+#define ELNK3_DEBUG_VERY_LOUD 0x00000002 // excessive debugging info
+#define ELNK3_DEBUG_IO 0x00000004 // debug I/O port access
+
+#define ELNK3_DEBUG_INIT 0x00000100 // init debugging info
+#define ELNK3_DEBUG_SEND 0x00000200 // init debugging info
+#define ELNK3_DEBUG_RCV 0x00000400
+#define ELNK3_DEBUG_REQ 0x00000800
+
+#define ELNK3_DEBUG_LOG 0x00001000
+
+#define ELNK3_DEBUG_INIT_BREAK 0x80000000 // break at DriverEntry
+#define ELNK3_DEBUG_INIT_FAIL 0x40000000 // fail driver load
+
+//
+// Macro for deciding whether to dump lots of debugging information.
+//
+
+#define IF_LOUD(A) IF_ELNK3DEBUG( ELNK3_DEBUG_LOUD ) { A }
+#define IF_VERY_LOUD(A) IF_ELNK3DEBUG( ELNK3_DEBUG_VERY_LOUD ) { A }
+#define IF_IO_LOUD(A) IF_ELNK3DEBUG( ELNK3_DEBUG_IO ) { A }
+#define IF_INIT_LOUD(A) IF_ELNK3DEBUG( ELNK3_DEBUG_INIT ) { A }
+#define IF_SEND_LOUD(A) IF_ELNK3DEBUG( ELNK3_DEBUG_SEND ) { A }
+#define IF_RCV_LOUD(A) IF_ELNK3DEBUG( ELNK3_DEBUG_RCV ) { A }
+#define IF_REQ_LOUD(A) IF_ELNK3DEBUG( ELNK3_DEBUG_REQ ) { A }
+
+
+#define IF_LOG(c1,c2,data) { \
+ if (Elnk3DebugFlag & ELNK3_DEBUG_LOG) { \
+ Elnk3LogArray[ElnkLogPointer]=((ULONG)(data)<<16) | ((c1)<<8) | (c2); \
+ ElnkLogPointer=(ElnkLogPointer+1)% ELNK3_MAX_LOG_SIZE; \
+ Elnk3LogArray[ElnkLogPointer]=0; \
+ } \
+ }
+#if 0
+
+#define IF_LOG(c1,c2,data) { \
+ \
+ if (Elnk3DebugFlag & ELNK3_DEBUG_LOG) { \
+ Elnk3LogArray[ElnkLogPointer].Letter1=(c2); \
+ Elnk3LogArray[ElnkLogPointer].Letter2=(c1); \
+ Elnk3LogArray[ElnkLogPointer].Data =(USHORT)(data); \
+ ElnkLogPointer=(ElnkLogPointer+1)% ELNK3_MAX_LOG_SIZE; \
+ \
+ Elnk3LogArray[ElnkLogPointer].Letter1=0; \
+ Elnk3LogArray[ElnkLogPointer].Letter2=0; \
+ Elnk3LogArray[ElnkLogPointer].Data =0; \
+ } \
+ }
+#endif
+
+#define DEBUG_STAT(x) ((x)++)
+
+
+#else
+
+#define IF_LOUD(A)
+#define IF_VERY_LOUD(A)
+#define IF_IO_LOUD(A)
+#define IF_INIT_LOUD(A)
+#define IF_SEND_LOUD(A)
+#define IF_RCV_LOUD(A)
+#define IF_REQ_LOUD(A)
+
+#define DEBUG_STAT(x)
+
+#define IF_LOG(c1,c2,data)
+
+#endif
diff --git a/private/ntos/ndis/elnk3/elnk3.c b/private/ntos/ndis/elnk3/elnk3.c
new file mode 100644
index 000000000..3bb2caaf1
--- /dev/null
+++ b/private/ntos/ndis/elnk3/elnk3.c
@@ -0,0 +1,174 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ Elnk3.c
+
+Abstract:
+
+ Ndis 3.0 MAC driver for the 3Com Etherlink III
+
+Author:
+
+ Brian Lieuallen BrianLie 07/21/92
+
+Environment:
+
+ Kernel Mode Operating Systems : NT, Chicago
+
+Revision History:
+
+ Portions borrowed from ELNK3 driver by
+ Earle R. Horton (EarleH)
+
+
+--*/
+
+
+
+#include <ndis.h>
+//#include <efilter.h>
+
+#include "debug.h"
+
+
+#include "elnk3hrd.h"
+#include "elnk3sft.h"
+#include "elnk3.h"
+
+VOID
+Elnk3ResetCompleteOpens(
+ IN PELNK3_ADAPTER pAdapter
+ );
+
+
+//
+// This constant is used for places where NdisAllocateMemory
+// needs to be called and the HighestAcceptableAddress does
+// not matter.
+//
+
+NDIS_PHYSICAL_ADDRESS HighestAcceptableMax =
+ NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
+
+
+
+
+
+
+
+
+
+
+
+
+BOOLEAN
+Elnk3CheckForHang(
+ IN NDIS_HANDLE Context
+ )
+/*++
+
+Routine Description:
+
+ This routine is called to WakeUp the driver. It has to functions.
+
+Arguments:
+
+ DeferredContext - will be a pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNK3_ADAPTER pAdapter = ((PELNK3_ADAPTER)Context);
+ BOOLEAN Hung;
+
+
+ IF_VERY_LOUD(DbgPrint("WakeUpTimer: entered\n");)
+
+ Hung=FALSE;
+
+
+
+ return Hung;
+
+}
+
+
+
+
+
+
+NDIS_STATUS
+Elnk3Reset(
+ OUT PBOOLEAN AddressResetting,
+ IN NDIS_HANDLE MacBindingHandle
+ )
+
+/*++
+
+Routine Description:
+
+ NDIS function.
+
+Arguments:
+
+ See NDIS 3.0 spec.
+
+--*/
+
+{
+ PELNK3_ADAPTER pAdapter = MacBindingHandle;
+
+ IF_LOUD(DbgPrint("ELNK3: Reset() Called\n");)
+
+ CardReStart(pAdapter);
+ CardReStartDone(pAdapter);
+
+#if 0
+
+ IF_LOUD(
+ DbgPrint("\nELNK3: Stats\n"
+ " Total Interrupts = %7d\n"
+ " EarlyReceiveInterrupts = %7d\n"
+ " RecieveCompInterrutps = %7d\n"
+ " TransmitCompInterrupts = %7d\n"
+ " TransmitAvailInterrupts = %7d\n"
+ " TransmitCompleted = %7d\n"
+ " Recevice Indications = %7d\n"
+ " Indication with data = %7d\n"
+ " Indications Complete = %7d\n"
+ " TransferData calls = %7d\n"
+ " SecondEarlyReceive = %7d\n"
+ " Broadcasts rejected = %7d\n"
+ " Bad receives = %7d\n\n",
+ pAdapter->Stats.TotalInterrupts,
+ pAdapter->Stats.RxEarlyIntCount,
+ pAdapter->Stats.RxCompIntCount,
+ pAdapter->Stats.TxCompIntCount,
+ pAdapter->Stats.TxAvailIntCount,
+ pAdapter->Stats.TxCompleted,
+ pAdapter->Stats.PacketIndicated,
+ pAdapter->Stats.IndicateWithDataReady,
+ pAdapter->Stats.IndicationCompleted,
+ pAdapter->Stats.TransferDataCount,
+ pAdapter->Stats.SecondEarlyReceive,
+ pAdapter->Stats.BroadcastsRejected,
+ pAdapter->Stats.BadReceives);
+
+ NdisZeroMemory(&pAdapter->Stats,sizeof(DEBUG_STATS));
+ )
+
+#endif
+
+ *AddressResetting=TRUE;
+
+ return NDIS_STATUS_SUCCESS;
+
+
+}
diff --git a/private/ntos/ndis/elnk3/elnk3.h b/private/ntos/ndis/elnk3/elnk3.h
new file mode 100644
index 000000000..5a2770edf
--- /dev/null
+++ b/private/ntos/ndis/elnk3/elnk3.h
@@ -0,0 +1,424 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ Elnk3.h
+
+Abstract:
+
+ Ndis 3.0 MAC driver for the 3Com Etherlink III
+
+Author:
+
+ Brian Lieuallen BrianLie 07/21/92
+
+Environment:
+
+ Kernel Mode Operating Systems : NT
+
+Revision History:
+
+ Portions borrowed from ELNK3 driver by
+ Earle R. Horton (EarleH)
+
+
+--*/
+
+
+
+
+
+#define STATIC static
+
+
+//
+// This constant is used for places where NdisAllocateMemory
+// needs to be called and the HighestAcceptableAddress does
+// not matter.
+//
+
+extern NDIS_PHYSICAL_ADDRESS HighestAcceptableMax;
+
+//
+// NDIS 3.0 entry functions
+//
+
+BOOLEAN
+Elnk3CheckForHang(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+
+
+NDIS_STATUS
+Elnk3QueryInformation(
+ IN NDIS_HANDLE MiniportContext,
+ IN NDIS_OID Oid,
+ IN PVOID InfoBuffer,
+ IN ULONG BytesLeft,
+ OUT PULONG BytesNeeded,
+ OUT PULONG BytesWritten
+ );
+
+
+
+NDIS_STATUS
+Elnk3SetInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ );
+
+NDIS_STATUS
+Elnk3Initialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ );
+
+VOID
+Elnk3Halt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+
+VOID
+Elnk3Shutdown(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+
+NDIS_STATUS
+Elnk3Reset(
+ OUT PBOOLEAN AddressResetting,
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+
+
+
+NDIS_STATUS
+Elnk3MacSend(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_PACKET pPacket,
+ IN UINT Flags
+ );
+
+NDIS_STATUS
+Elnk3TransferData(
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+ );
+
+
+
+NDIS_STATUS
+Elnk3Reconfigure(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE ConfigurationHanel
+ );
+
+
+
+
+
+
+VOID
+Elnk3AdjustMaxLookAhead(
+ IN PELNK3_ADAPTER pAdapter
+ );
+
+
+
+
+
+//
+// Contained in Interrup.c
+//
+
+VOID
+Elnk3Isr(
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueDpc,
+ IN NDIS_HANDLE Context
+ );
+
+
+
+VOID
+Elnk3IsrDpc(
+ IN NDIS_HANDLE DeferredContext // will be a pointer to the adapter block
+ );
+
+
+
+VOID
+Elnk3EnableInterrupts(
+ IN NDIS_HANDLE Context
+ );
+
+
+VOID
+Elnk3DisableInterrupts(
+ IN NDIS_HANDLE Context
+ );
+
+
+
+
+//
+// Contained in CARD.C
+//
+
+BOOLEAN
+CardTest (
+ OUT PELNK3_ADAPTER pAdapter
+ );
+
+
+
+//
+// Contained in send.c
+//
+
+
+PNDIS_PACKET
+RemovePacketFromQueue(
+ IN PPACKET_QUEUE pQueue
+ );
+
+
+BOOLEAN
+MovePacketToCard(
+ IN PELNK3_ADAPTER pAdapter
+ );
+
+
+//
+// Contained in receive.c
+//
+
+BOOLEAN
+CheckForReceives(
+ IN PELNK3_ADAPTER pAdapter
+ );
+
+
+
+//
+// Contained in config.c
+//
+
+NDIS_STATUS
+Elnk3ReadRegistry(
+ IN PELNK3_ADAPTER pAdapter,
+ IN NDIS_HANDLE ConfigurationHandle
+ );
+
+
+BOOLEAN
+CardEnable(
+ IN PELNK3_ADAPTER pAdapter
+ );
+
+
+BOOLEAN
+CardReInit(
+ IN PELNK3_ADAPTER pAdapter
+ );
+
+VOID
+CardReset(
+ IN PELNK3_ADAPTER pAdapter
+ );
+
+
+//
+// Elnk3 starts here
+//
+
+
+
+
+
+
+BOOLEAN
+HandleXmtInterrupts(
+ PELNK3_ADAPTER pAdapter
+ );
+
+BOOLEAN
+Elnk3EarlyReceive(
+ PELNK3_ADAPTER pAdapter
+ );
+
+
+BOOLEAN
+Elnk3IndicatePackets(
+ PELNK3_ADAPTER pAdapter
+ );
+
+BOOLEAN
+Elnk3IndicatePackets2(
+ PELNK3_ADAPTER pAdapter
+ );
+
+
+
+
+BOOLEAN
+CardInit(
+ IN PELNK3_ADAPTER pAdapter
+ );
+
+
+
+
+UINT
+Elnk3FindIsaBoards(
+ IN PMAC_BLOCK pMacBlock
+ );
+
+BOOLEAN
+Elnk3ActivateIsaBoard(
+ IN PMAC_BLOCK pMacBlock,
+ IN PELNK3_ADAPTER pAdapter,
+ IN NDIS_HANDLE AdapterHandle,
+ IN PUCHAR TranslatedIoBase,
+ IN ULONG ConfigIoBase,
+ IN OUT PULONG Irq,
+ IN ULONG Transceiver,
+ IN NDIS_HANDLE ConfigurationHandle
+ );
+
+
+VOID
+Elnk3EnableIsaBoard(
+ PVOID TranslatedIoBase
+ );
+
+
+
+VOID
+Elnk3GetEisaResources(
+ IN PELNK3_ADAPTER pAdapter,
+ IN OUT PULONG Irq
+ );
+
+
+VOID
+CardReStart(
+ IN PELNK3_ADAPTER pAdapter
+ );
+
+VOID
+CardReStartDone(
+ IN PELNK3_ADAPTER pAdapter
+ );
+
+
+VOID
+Elnk3AdjustMaxLookAhead(
+ IN PELNK3_ADAPTER Adapter
+ );
+
+BOOLEAN
+ReadStationAddress(
+ OUT PELNK3_ADAPTER pNewAdapt
+ );
+
+
+USHORT
+CardSetMulticast(
+ PELNK3_ADAPTER pAdapter
+ );
+
+
+BOOLEAN
+CardInit(
+ IN PELNK3_ADAPTER pAdapter
+ );
+
+VOID
+ELNK3WriteIDSequence(
+ IN PVOID IdPort
+ );
+
+USHORT
+ELNK3ContentionTest(
+ IN PVOID IdPort,
+ IN UCHAR EEPromWord
+ );
+
+USHORT
+ELNK3ReadEEProm(
+ IN PELNK3_ADAPTER Adapter,
+ IN UCHAR EEPromWord
+ );
+
+VOID
+Elnk3ProgramEEProm(
+ PELNK3_ADAPTER Adapter,
+ USHORT AddressConfig,
+ USHORT ResourceConfig
+ );
+
+VOID
+Elnk3WriteEEProm(
+ IN PELNK3_ADAPTER Adatper,
+ IN UCHAR EEPromWord,
+ IN USHORT Value
+ );
+
+VOID
+Elnk3WaitEEPromNotBusy(
+ PELNK3_ADAPTER pAdapter
+ );
+
+NDIS_STATUS
+Elnk3Init3C589(
+ IN OUT PELNK3_ADAPTER Adapter
+ );
+
+NDIS_STATUS
+Elnk3InitializeAdapter(
+ IN PMAC_BLOCK pMac,
+ IN PELNK3_ADAPTER pAdapter,
+ IN NDIS_HANDLE ConfigurationHandle
+ );
+
+
+NDIS_STATUS
+Elnk3AllocateBuffers(
+ IN PELNK3_ADAPTER pAdapter,
+ IN NDIS_HANDLE NdisAdapterHandle,
+ BOOLEAN Allocate
+ );
+
+
+VOID
+Elnk3InitAdapterBlock(
+ IN PELNK3_ADAPTER pAdapter
+ );
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+
diff --git a/private/ntos/ndis/elnk3/elnk3.rc b/private/ntos/ndis/elnk3/elnk3.rc
new file mode 100644
index 000000000..6c380821e
--- /dev/null
+++ b/private/ntos/ndis/elnk3/elnk3.rc
@@ -0,0 +1,39 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "3Com Etherlink III network driver"
+#define VER_INTERNALNAME_STR "ELNK3.SYS"
+#define VER_ORIGINALFILENAME_STR "ELNK3.SYS"
+
+#include "common.ver"
+
diff --git a/private/ntos/ndis/elnk3/elnk3hrd.h b/private/ntos/ndis/elnk3/elnk3hrd.h
new file mode 100644
index 000000000..d84c39841
--- /dev/null
+++ b/private/ntos/ndis/elnk3/elnk3hrd.h
@@ -0,0 +1,549 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ elnk3hrd.h
+
+Abstract:
+
+ Ndis 3.0 MAC driver for the 3Com Etherlink III
+
+
+Author:
+
+ Brian Lieuallen BrianLie 08/21/92
+
+Environment:
+
+ Kernel Mode Operating Systems : NT
+
+Revision History:
+
+ Portions borrowed from ELNK3 driver by
+ Earle R. Horton (EarleH)
+
+
+--*/
+
+
+#define ELNK3_ETHERNET_HEADER_SIZE 14
+#define ELNK3_MAX_FRAME_SIZE 1514
+
+
+#define ELNK3_MAX_LOOKAHEAD_SIZE 1500
+
+
+
+typedef struct _ETHERNET_HEADER {
+ UCHAR Destination[6];
+ UCHAR Source[6];
+ UCHAR EthLength[2];
+ } ETHERNET_HEADER, *PETHERNET_HEADER;
+
+
+
+typedef struct _NIC_RCV_HEADER {
+ ETHERNET_HEADER EthHeader;
+ UCHAR LookAheadData[1500];
+ } NIC_RCV_HEADER, *PNIC_RCV_HEADER;
+
+//
+// EhterTypes
+//
+
+#define XNS_FRAME_TYPE 0x0600
+#define IP_FRAME_TYPE 0x0800
+#define IPX_FRAME_TYPE 0x8137
+
+
+typedef struct _XNSHDR {
+ UCHAR Ether[ELNK3_ETHERNET_HEADER_SIZE];
+ USHORT Checksum;
+ UCHAR Size[2];
+ } XNSHDR, PXNSHDR;
+
+typedef struct _IPHRD {
+ UCHAR Ether[ELNK3_ETHERNET_HEADER_SIZE];
+ USHORT Type;
+ UCHAR Size[2];
+ } IPHDR, PIPHDR;
+
+typedef struct _IPXHDR {
+ UCHAR Ether[ELNK3_ETHERNET_HEADER_SIZE];
+ USHORT Checksum;
+ UCHAR Size[2];
+ } IPXHDR, PIPXHDR;
+
+
+
+
+typedef struct _BUFFDESC {
+ ULONG CardOffset;
+ PNDIS_PACKET pPacket;
+ } BUFFDESC, *PBUFFDESC;
+
+
+
+
+typedef enum _ELNK3_ADAPTER_TYPE {
+ ELNK3_3C509,
+ ELNK3_3C579,
+ ELNK3_3C529,
+ ELNK3_3C589
+ } ELNK3_ADAPTER_TYPE, PELNK3_ADAPTER_TYPE;
+
+
+#define ELNK3_3C529_TP_MCA_ID 0x627c
+#define ELNK3_3C529_BNC_MCA_ID 0x627d
+#define ELNK3_3C529_COMBO_MCA_ID 0x61db
+#define ELNK3_3C529_TPCOAX_MCA_ID 0x62f6
+#define ELNK3_3C529_TPONLY_MCA_ID 0x62f7
+
+#define ELNK3_EISA_ID 0x90506d50
+
+#define ELNK3_3C579_EISA_ID 0x92506d50
+#define ELNK3_3C509_EISA_ID 0x90506d50
+
+
+/* :ts=4 this file uses 4 space tab stops */
+
+/*
+ Hardware equates for the EtherLink III network adapter.
+
+ Adapted from
+
+ "3C509 and 3C509-TP Adapters Technical Reference Guide"
+ Manual Part No. 8369-00
+ 3COM Corporation
+
+ */
+
+/*
+ When the adapter is in the ID_CMD state, the following writes to
+ the ID port are interpreted as commands.
+ */
+
+
+
+
+
+
+#define IDCMD_WAIT 0x00 /* Go to ID_WAIT state, actually 0 to 0x7f */
+#define IDCMD_READ_PROM 0x80 /* Read EEPROM word n, n is last six bits */
+ /* of command */
+#define IDCMD_RESET 0xC0 /* Global reset, same as power on reset */
+#define IDCMD_SET_TAG 0xD0 /* Set Adapter tag to value in last 3 bits */
+#define IDCMD_TEST_TAG 0xD8 /* Test Adapter tag by value in last 3 bits */
+#define MAXTAG 7
+#define IDCMD_ACTIVATE 0xE0 /* Activate adapter, writing last 5 bits */
+ /* into Address Configuration register */
+#define IDCMD_ACTIVATE_FF 0xFF /* Activate adapter using preconfigured */
+ /* I/O base address */
+/*
+ Default configuration values for the EtherLink III adapter.
+ */
+
+#define DEFAULT_ID_PORT 0x00000110 /* A port (maybe) not being used by */
+ /* anything else in an ISA machine */
+/*
+ Card EEPROM configuration, as shipped.
+ */
+#define DEFAULT_IO_PORT (PVOID)0x300
+#define DEFAULT_IRQ 10
+#define DEFAULT_TRANSCEIVER TRANSCEIVER_BNC /* For the 3C509-TP, this will */
+ /* be TRANSCEIVER_TP */
+
+// AdaptP->MulticastListMax
+//
+// the maximum number of different multicast addresses that
+// may be specified to this adapter (the list is global for
+// all protocols).
+
+#define DEFAULT_MULTICASTLISTMAX 16
+
+
+/*
+ EEPROM data structure.
+ */
+
+#define EEPROM_NODE_ADDRESS_0 0
+#define EEPROM_NODE_ADDRESS_1 1
+#define EEPROM_NODE_ADDRESS_2 2
+
+#define EEPROM_PRODUCT_ID 3
+
+#define EEPROM_MANUFACTURING_DATE 4
+#define EEPROM_MANUFACTURING_DATA1 5
+#define EEPROM_MANUFACTURING_DATA2 6
+#define EEPROM_MANUFACTURER_CODE 7
+
+#define EEPROM_ADDRESS_CONFIGURATION 8
+#define EEPROM_RESOURCE_CONFIGURATION 9
+
+#define EEPROM_OEM_NODE_0 10
+#define EEPROM_OEM_NODE_1 11
+#define EEPROM_OEM_NODE_2 12
+
+#define EEPROM_SOFTWARE_INFO 13
+
+#define EEPROM_RESERVED 14
+
+#define EEPROM_CHECKSUM 15
+
+#define EEPROM_NETWORK_MANAGEMENT_DATA_0 16
+
+//
+// eeprom software info bits
+//
+#define LINK_BEAT_DISABLED (1<<14)
+
+
+
+/*
+ Address configuration register.
+ */
+
+typedef union ELNK3_Address_Configuration_Register{
+ struct{
+ USHORT eacf_iobase : 5;
+ USHORT eacf_reserved : 3;
+ USHORT eacf_ROMbase : 4;
+ USHORT eacf_ROMsize : 2;
+ USHORT eacf_XCVR : 2;
+ };
+ USHORT eacf_contents;
+}ELNK3_Address_Configuration_Register, *PELNK3_Address_Configuration_Register;
+
+
+/*
+ EtherLink III configuration control register.
+ */
+
+#define CCR_ENABLE_BIT 0
+#define CCR_RESET_BIT 2
+
+#define CCR_ENABLE ( 1 << CCR_ENABLE_BIT )
+#define CCR_RESET ( 1 << CCR_RESET_BIT )
+/*
+ Transceiver configuration as stored in Address Configuration Register.
+ */
+
+#define TRANSCEIVER_TP 0 /* Twisted pair transceiver enabled. */
+#define TRANSCEIVER_EXTERNAL 1 /* AUI port enabled, using ext. trans. */
+#define TRANSCEIVER_RESERVED 2 /* reserved - undefined */
+#define TRANSCEIVER_BNC 3 /* BNC transceiver enabled */
+#define TRANSCEIVER_UNDEFINED TRANSCEIVER_RESERVED
+ /* Handy dandy undefined transceiver value */
+
+/*
+ Conversion from eacf_iobase to I/O port used.
+ */
+#define IOBASE_EISA 0x31 /* EISA mode slot-specific I/O address */
+
+typedef union EISA_IO_Address {
+ struct{
+ USHORT eia_port : 12;
+ USHORT eia_slot : 4;
+ };
+ USHORT eia_contents;
+}EISA_IO_Address, *PEISA_IO_Address;
+
+#define EISA_Window_0_Address 0xC80 /* Window zero is always mapped here */
+ /* on an EISA machine configured */
+ /* adapter */
+
+/*
+ IOBaseAddress for an EtherLink III configured for EISA operation and installed
+ in an EISA slot is the slotnumber times 1000h.
+ */
+#define EISA_SlotNumber_To_IOBase(x) ((x) * 0x1000)
+
+#define EACF_IOBASE_TO_ISA_IOBASE(x) ( ( (x) << 4 ) + 0x200 )
+#define ISA_IOBASE_TO_EACF_IOBASE(x) ( ( (x) - 0x200 ) >> 4 )
+
+/*
+ Elnk III resource configuration register.
+ */
+
+typedef union ELNK3_Resource_Configuration_Register{
+ struct{
+ USHORT ercf_reserved : 8;
+ USHORT ercf_reserved_F : 4;
+ USHORT ercf_IRQ : 4;
+ };
+ USHORT ercf_contents;
+}ELNK3_Resource_Configuration_Register, *PELNK3_Resource_Configuration_Register;
+
+/*
+ Format of command word written to ELNK III command register.
+ */
+
+typedef union ELNK3_Command{
+ struct{
+ USHORT ec_arg : 11;
+ USHORT ec_command : 5;
+ };
+ USHORT ec_contents;
+}ELNK3_Command,*PELNK3_Command;
+
+#define EC_GLOBAL_RESET 0
+#define EC_SELECT_WINDOW 1
+#define EC_START_COAX_XCVR 2
+#define EC_RX_DISABLE 3
+#define EC_RX_ENABLE 4
+#define EC_RX_RESET 5
+
+#define EC_RX_DISCARD_TOP_PACKET 8
+#define EC_TX_ENABLE 9
+#define EC_TX_DISABLE 10
+#define EC_TX_RESET 11
+
+#define EC_REQUEST_INTERRUPT 12
+
+#define EC_INT_LATCH 0x01
+#define EC_INT_ADAPTER_FAILURE 0x02
+#define EC_INT_TX_COMPLETE 0x04
+#define EC_INT_TX_AVAILABLE 0x08
+#define EC_INT_RX_COMPLETE 0x10
+#define EC_INT_RX_EARLY 0x20
+#define EC_INT_INTERRUPT_REQUESTED 0x40
+#define EC_INT_UPDATE_STATISTICS 0x80
+
+#define EC_ACKNOWLEDGE_INTERRUPT 13
+#define EC_SET_INTERRUPT_MASK 14
+#define EC_SET_READ_ZERO_MASK 15
+
+#define EC_SET_RX_EARLY 17
+#define EC_SET_TX_AVAILIBLE 18
+#define EC_SET_TX_START 19
+
+#define EC_SET_RX_FILTER 16
+
+#define EC_FILTER_ADDRESS 1
+#define EC_FILTER_GROUP 2
+#define EC_FILTER_BROADCAST 4
+#define EC_FILTER_PROMISCUOUS 8
+
+//
+// Window Numbers
+//
+#define WNO_SETUP 0 // setup/configuration
+#define WNO_OPERATING 1 // operating set
+#define WNO_STATIONADDRESS 2 // station address setup/read
+#define WNO_FIFO 3 // FIFO management
+#define WNO_DIAGNOSTICS 4 // diagnostics
+#define WNO_READABLE 5 // registers set by commands
+#define WNO_STATISTICS 6 // statistics
+//
+// Port offsets, Window 1
+//
+#define PORT_CmdStatus 0x0E // command/status
+#define PORT_TxFree 0x0C // free transmit bytes
+#define PORT_TxStatus 0x0B // transmit status (byte)
+#define PORT_Timer 0x0A // latency timer (byte)
+#define PORT_RxStatus 0x08 // receive status
+#define PORT_RxFIFO 0x00 // RxFIFO read
+#define PORT_TxFIFO 0x00 // TxFIFO write
+//
+// Port offsets, Window 0
+//
+#define PORT_EEData 0x0C // EEProm data register
+#define PORT_EECmd 0x0A // EEProm command register
+#define PORT_CfgResource 0x08 // resource configuration
+#define PORT_CfgAddress 0x06 // address configuration
+#define PORT_CfgControl 0x04 // configuration control
+#define PORT_ProductID 0x02 // product id (EISA)
+#define PORT_Manufacturer 0x00 // Manufacturer code (EISA)
+//
+// Port offsets, Window 2
+//
+#define PORT_SA0_1 0x00 // station address bytes 0,1
+#define PORT_SA2_3 0x02 // station address bytes 2,3
+#define PORT_SA4_5 0x04 // station address bytes 4,5
+
+//
+// port offsets, window 3
+//
+#define PORT_FREE_RX_BYTES 0x0a
+
+//
+//
+// Port Offsets window 4
+//
+#define PORT_FIFO_DIAG 0x04
+
+#define RX_UNDERRUN 0x2000
+#define TX_OVERRUN 0x0400
+
+
+#define PORT_MEDIA_TYPE 0x0a
+
+#define MEDIA_LINK_BEAT 0x0080
+#define MEDIA_JABBER 0x0040
+#define MEDIA_SQE 0x0008
+
+
+#define PORT_NET_DIAG 0x06
+
+
+
+//
+// board identification codes
+//
+#define EISA_MANUFACTURER_ID 0x6D50 // EISA manufacturer code
+
+#define ISAID_BNC 0x9050 // Product ID for ISA TP board
+#define ISAID_TP 0x9051 // Product ID for ISA coax board
+#define EISAID 0x9052 // Product ID for EISA board
+#define PCMCIAID 0x9058 // Product ID for PCMCIA board (3C589)
+
+//...so far the list is 5090=ISA 3C509-TP (TP/AUI), 5091h=ISA 3C509 (BNC/AUI),
+// 5092h=EISA 3C579-TP (TP/AUI) and 5092h=EISA 3C579 (BNC/AUI). other
+// bottom nibbles will likely be assigned to TP-only/combo/whatever
+// else marketting thinks up...
+
+#define PRODUCT_ID_MASK 0xF0FF // Mask off revision nibble
+
+#define MCAID_BNC 0x627C // MCA Adapter ID: BNC/AUI
+#define MCAID_TP 0x627D // MCA Adapter ID: TP/AUI
+#define MCAID_COMBO 0x61DB // MCA Adapter ID: Combo (future)
+#define MCAID_TPCOAX 0x62F6 // MCA Adapter ID: TP/COAX (future)
+#define MCAID_TPONLY 0x62F7 // MCA Adapter ID: TP only (future)
+
+/*
+ Note: This is referred to as POS2 in 3COM's MCA Technical Reference Addendum
+ for the EtherLink III.
+ */
+#define POS1_CDEN 1 // Card enable bit in POS2 register
+
+/*
+ Note: This is referred to as POS4 in 3COM's MCA Technical Reference Addendum
+ for the EtherLink III.
+ */
+#define POS3_TO_IOBASE(x) ((((x) << 8) & 0xFC00) | 0x0200)
+//
+// EEProm access
+//
+#define EE_COMMAND_EW_ENABLE 0x30
+#define EE_COMMAND_ERASE 0xc0
+#define EE_COMMAND_WRITE 0x40
+#define EE_COMMAND_READ 0x80
+
+#define EE_BUSY 0x8000 // EEProm busy bit in EECmd
+#define EE_TCOM_NODE_ADDR_WORD0 0x00
+#define EE_TCOM_NODE_ADDR_WORD1 0x1
+#define EE_TCOM_NODE_ADDR_WORD2 0x2
+#define EE_VULCAN_PROD_ID 0x3
+#define EE_MANUFACTURING_DATA 0x4
+#define EE_SERIAL_NUMBER_WORD0 0x5
+#define EE_SERIAL_NUMBER_WORD1 0x6
+#define EE_MANUFACTURER_CODE 0x7
+#define EE_ADDR_CONFIGURATION 0x8
+#define EE_RESOURCE_CONFIGURATION 0x9
+#define EE_OEM_NODE_ADDR_WORD0 0xA
+#define EE_OEM_NODE_ADDR_WORD1 0xB
+#define EE_OEM_NODE_ADDR_WORD2 0xC
+#define EE_SOFTWARE_CONFIG_INFO 0xD
+#define EE_CHECK_SUM 0xF
+
+#define MIN_IO_BASE_ADDR 0x200
+#define MAX_IO_BASE_ADDR 0x3F0
+#define REGISTER_SET_SIZE 0x10
+
+
+#define RX_STATUS_INCOMPLETE 0x8000
+#define RX_STATUS_ERROR 0x4000
+
+#define RX_STATUS_OVERRUN 0x08
+#define RX_STATUS_RUNT 0x0b
+
+#define TX_STATUS_COMPLETE 0x80
+#define TX_STATUS_INTERRUPT 0x40
+#define TX_STATUS_JABBER 0x20
+#define TX_STATUS_UNDERRUN 0x10
+#define TX_STATUS_MAX_COLLISION 0x08
+#define TX_STATUS_TX_OVERFLOW 0x04
+
+
+#define ELNK3_PACKET_COMPLETE(_RcvStatus) (!(((_RcvStatus) & RX_STATUS_INCOMPLETE)))
+
+#define DWORDS_FROM_BYTES(_status) ((_status) >> 2)
+
+#define BYTES_IN_FIFO(_status) ((ULONG)((_status) & 0x7ff))
+
+#define BYTES_IN_FIFO_DW(_status) ((ULONG)((_status) & 0x7fc))
+
+#define ELNK3_ROUND_TO_DWORD(x) (((x)+3) & 0xfffffffc)
+
+#ifdef NDIS_NT
+
+#ifndef IO_DBG
+#define ELNK3_READ_PORT_USHORT(_pAdapt,offset) \
+ READ_PORT_USHORT((PUSHORT)(_pAdapt)->PortOffsets[(offset)]);
+
+#define ELNK3_READ_PORT_USHORT_DIRECT(offset) \
+ READ_PORT_USHORT((PUSHORT)(offset));
+#else
+USHORT ELNK3_READ_PORT_USHORT( PVOID Adapter, ULONG Offset );
+USHORT ELNK3_READ_PORT_USHORT_DIRECT( PVOID Offset );
+#endif
+
+#else
+
+#define ELNK3_READ_PORT_USHORT(_pAdapt,offset) \
+ inpw((_pAdapt)->PortOffsets[(offset)]);
+
+#define ELNK3_READ_PORT_USHORT_DIRECT(offset) \
+ inpw((offset));
+
+#endif
+
+#define ELNK3_COMMAND(_p,_c,_d) \
+ IF_IO_LOUD(DbgPrint("Writing command %d.%d\n", (USHORT)(_c), (USHORT)(_d));) \
+ NdisRawWritePortUshort((_p)->PortOffsets[PORT_CmdStatus], ((USHORT)(_c)<<11) | (_d))
+
+
+#define ELNK3_SELECT_WINDOW(_p,_w) \
+ ELNK3_COMMAND(_p,(EC_SELECT_WINDOW),_w)
+
+#define ELNK3_READ_STATUS(_pAdapt,_pData) \
+ NdisRawReadPortUshort((_pAdapt)->PortOffsets[PORT_CmdStatus],(_pData)); \
+ IF_IO_LOUD(DbgPrint("Read status %x\n", *(PUSHORT)(_pData));)
+
+#define ELNK3_WAIT_NOT_BUSY(_pAdapt) { \
+ \
+ USHORT Status; \
+ ULONG Limit=1000; \
+ \
+ Status=ELNK3_READ_PORT_USHORT((_pAdapt),PORT_CmdStatus); \
+ \
+ while ((Status & 0x1000) && (--Limit>0)) { \
+ \
+ Status=ELNK3_READ_PORT_USHORT((_pAdapt),PORT_CmdStatus); \
+ } \
+ \
+ }
+
+
+#define ELNK3WriteAdapterUchar(Adapter,PortOffset,UcharToWrite)\
+ IF_IO_LOUD(DbgPrint("Writing uchar %x to port %x\n", (UCHAR)(UcharToWrite), (PortOffset));) \
+ NdisRawWritePortUchar((Adapter)->PortOffsets[PortOffset],(UcharToWrite))
+
+
+#define ELNK3WriteAdapterUshort(Adapter,PortOffset,UshortToWrite)\
+ IF_IO_LOUD(DbgPrint("Writing ushort %x to port %x\n", (USHORT)(UshortToWrite), (PortOffset));) \
+ NdisRawWritePortUshort((Adapter)->PortOffsets[PortOffset],(UshortToWrite))
+
+
+#define ELNK3ReadAdapterUchar(Adapter,PortOffset,PUcharToRead)\
+ NdisRawReadPortUchar((Adapter)->PortOffsets[PortOffset],(PUcharToRead)); \
+ IF_IO_LOUD(DbgPrint("Read uchar %x from port %x\n", *(PUCHAR)(PUcharToRead), (PortOffset));) \
+
+
+#define ELNK3ReadAdapterUshort(Adapter,PortOffset,PUshortToRead)\
+ NdisRawReadPortUshort((Adapter)->PortOffsets[PortOffset],(PUshortToRead)); \
+ IF_IO_LOUD(DbgPrint("Read ushort %x from port %x\n", *(PUSHORT)(PUshortToRead), (PortOffset));) \
+
+
diff --git a/private/ntos/ndis/elnk3/elnk3sft.h b/private/ntos/ndis/elnk3/elnk3sft.h
new file mode 100644
index 000000000..7f557a12a
--- /dev/null
+++ b/private/ntos/ndis/elnk3/elnk3sft.h
@@ -0,0 +1,361 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ elnk3sft.h
+
+Abstract:
+
+ Ndis 3.0 MAC driver for the 3Com Etherlink III
+
+Author:
+
+ Brian Lieuallen BrianLie 07/21/92
+
+Environment:
+
+ Kernel Mode Operating Systems : NT
+
+Revision History:
+
+ Portions borrowed from ELNK3 driver by
+ Earle R. Horton (EarleH)
+
+
+--*/
+
+
+
+
+
+
+
+
+#define DEFAULT_MULTICAST_SIZE 16
+#define DEFAULT_RECEIVE_BUFFER_SIZE 238
+
+
+#define ELNK3_NDIS_MAJOR_VERSION 3
+#define ELNK3_NDIS_MINOR_VERSION 0
+
+#define TIMER_ARRAY_SIZE 4
+
+#define ELNK3_LENGTH_OF_ADDRESS 6
+
+
+//
+// Macros
+//
+#define MACRO_ASSERTALL() { \
+ ASSERT ( sizeof(CHAR) = 1 ); \
+ ASSERT ( sizeof(UCHAR) = 1 ); \
+ ASSERT ( sizeof(USHORT) = 2 ); \
+ ASSERT ( sizeof(UINT) = 4 ); \
+ ASSERT ( sizeof(ULONG) = 4 ); \
+ }
+
+//
+// The main MAC block structure allocated and initialized once
+//
+
+typedef struct _ELNK3_ISA_DESCRIPTION {
+ USHORT AddressConfigRegister;
+ USHORT ResourceConfigRegister;
+ USHORT IOPort;
+ USHORT Irq;
+ BOOLEAN Tagged;
+ BOOLEAN Active;
+ } ELNK3_ISA_DESCRIPTION, *PELNK3_ISA_DESCRIPTION;
+
+
+
+typedef struct _MAC_BLOCK {
+
+ //
+ // Translated ID port Address
+ //
+
+ PUCHAR TranslatedIdPort;
+
+ ELNK3_ISA_DESCRIPTION IsaCards[7];
+
+ UCHAR IsaAdaptersFound;
+
+} MAC_BLOCK, * PMAC_BLOCK;
+
+
+typedef struct _PACKET_QUEUE {
+ PNDIS_PACKET QIn;
+ PNDIS_PACKET QOut;
+ } PACKET_QUEUE, *PPACKET_QUEUE;
+
+
+
+typedef struct _TRANSFERDATA_CONTEXT {
+ struct _ELNK3_ADAPTER *pAdapter;
+ ULONG PacketLength;
+ ULONG BytesAlreadyRead;
+
+ PNIC_RCV_HEADER LookAhead;
+
+ PNDIS_PACKET LoopBackPacket;
+
+ PNDIS_PACKET Stack;
+
+ ULONG pad[2];
+
+ } TRANSFERDATA_CONTEXT, *PTRANSFERDATA_CONTEXT;
+
+
+
+
+
+typedef
+BOOLEAN
+(*ELNK3_RECEIVE_HANDLER)(
+ struct _ELNK3_ADAPTER *pAdapter
+ );
+
+
+
+
+//
+// One of these structures per adapter registered.
+//
+
+typedef struct _ELNK3_ADAPTER {
+
+ PVOID PortOffsets[16];
+
+ //
+ // Xmit queues stuff
+ //
+
+ ELNK3_RECEIVE_HANDLER EarlyReceiveHandler;
+ ELNK3_RECEIVE_HANDLER ReceiveCompleteHandler;
+
+ ULONG XmtCompleted;
+
+
+ //
+ // Recieve stuff
+ //
+ UINT CurrentPacket;
+
+ UCHAR CurrentInterruptMask;
+
+ TRANSFERDATA_CONTEXT TransContext[2];
+
+
+ //
+ // Elnk3 stuff
+ //
+
+ UCHAR AdapterStatus;
+
+ UINT WakeUpErrorCount;
+
+ BOOLEAN RejectBroadcast;
+
+ BOOLEAN InitInterrupt;
+
+ //
+ // NDIS Interrupt information
+ //
+
+ NDIS_MINIPORT_INTERRUPT NdisInterrupt;
+ NDIS_INTERRUPT_MODE InterruptMode;
+ BOOLEAN AdapterInitializing;
+
+ //
+ // NDIS wrapper information.
+ //
+
+ NDIS_HANDLE NdisAdapterHandle; // returned from NdisRegisterAdapter
+
+ //
+ // Registry information
+ //
+ ULONG Transceiver;
+
+ UINT IoPortBaseAddr;
+ PVOID TranslatedIoBase;
+
+
+ ELNK3_ADAPTER_TYPE CardType;
+ ULONG IrqLevel;
+ ULONG ReceiveMethod;
+
+ UCHAR StationAddress[ELNK3_LENGTH_OF_ADDRESS]; // filled in at init time
+
+ UCHAR PermanentAddress[ELNK3_LENGTH_OF_ADDRESS]; // filled in at init time
+
+ USHORT EEpromSoftwareInfo;
+
+ ULONG FramesXmitGood; // Good Frames Transmitted
+ ULONG FramesRcvGood; // Good Frames Received
+ ULONG FramesXmitBad; // Bad Frames Transmitted
+ ULONG FramesXmitOneCollision; // Frames Transmitted with one collision
+ ULONG FramesXmitManyCollisions; // Frames Transmitted with > 1 collision
+ ULONG FrameAlignmentErrors; // FAE errors counted
+ ULONG CrcErrors; // CRC errors counted
+ ULONG MissedPackets; // missed packet counted
+
+
+ //
+ // Look Ahead information.
+ //
+
+ ULONG MaxLookAhead;
+ ULONG EarlyReceiveThreshold;
+ ULONG LatencyAdjustment;
+ ULONG LookAheadLatencyAdjustment;
+ LONG FirstEarlyThreshold;
+ ULONG LowWaterMark;
+ ULONG ThresholdTarget;
+
+ ULONG AverageLatency;
+ ULONG IdPortBaseAddr;
+
+ USHORT TxStartThreshold;
+ USHORT TxStartThresholdInc;
+
+ ULONG RxMinimumThreshold;
+ ULONG RxFifoSize;
+ UINT NdisRxFilter;
+ UCHAR RxFilter;
+ UCHAR RevisionLevel;
+ ULONG RxHiddenBytes;
+
+ BOOLEAN IdPortOwner;
+
+ //
+ // Adapter specific Infomation
+ //
+
+
+ UCHAR WakeUpState;
+ BOOLEAN AdapterFailed;
+
+
+
+ ULONG TimerValues[TIMER_ARRAY_SIZE];
+ ULONG CurrentTimerValue;
+
+
+#if DBG
+
+ DEBUG_STATS Stats;
+
+#endif
+
+
+
+} ELNK3_ADAPTER, * PELNK3_ADAPTER;
+
+#define STATUS_REINIT_REQUESTED 0x0001
+#define STATUS_RESET_INITIATED 0x0002
+#define STATUS_RESET_IN_PROGRESS 0x0004
+#define STATUS_MOVING_TO_CARD 0x0008
+#define STATUS_SEND_BLOCK_USED 0x0010
+#define STATUS_INITIALIZING 0x0020
+#define STATUS_SHUTDOWN 0x0040
+
+//
+// What we map into the reserved section of a packet.
+// Cannot be more than 16 bytes (see ASSERT in send.c).
+//
+
+
+#define NdisRequestClose 1
+#define NdisRequestRequest 2
+#define NdisRequestReset1 3
+#define NdisRequestReset2 4
+
+
+#define SEND_STATUS_LOOPBACK 0x01
+#define SEND_STATUS_FAILED 0x02
+#define SEND_STATUS_BUFFER_USED 0x04
+#define SEND_STATUS_ABORTED 0x08
+#define SEND_STATUS_ONE_COLLISION 0x10
+#define SEND_STATUS_MANY_COLLISIONS 0x20
+
+#define SEND_STATUS_SMALL_PACKET 0x40
+
+
+typedef struct _PACKET_RESERVED {
+ PNDIS_PACKET Next; // used to link in the queues (4 bytes)
+ union {
+ struct {
+
+ USHORT PacketLength;
+ UCHAR Status;
+
+ } Send;
+
+ struct {
+
+ USHORT ByteOffset;
+ USHORT BytesToTransfer;
+
+ } TransData;
+ } u;
+
+ } PACKET_RESERVED, * PPACKET_RESERVED;
+
+
+
+//
+// These appear in the status field of MAC_RESERVED; they are
+// used because there is not enough room for a full NDIS_HANDLE.
+//
+
+#define RESERVED_SUCCESS ((USHORT)0)
+#define RESERVED_FAILURE ((USHORT)1)
+
+//
+// Retrieve the MAC_RESERVED structure from a packet.
+//
+
+#define PACKET_RESERVED(Packet) ((PPACKET_RESERVED)((Packet)->MacReserved))
+
+#define ADD_PACKET_TO_QUEUE(pQueue,pPacket) { \
+ \
+ PACKET_RESERVED(pPacket)->Next = NULL; \
+ if ((pQueue)->QOut==NULL) { \
+ \
+ (pQueue)->QOut=pPacket; \
+ \
+ } else { \
+ \
+ PACKET_RESERVED((pQueue)->QIn)->Next=pPacket; \
+ } \
+ \
+ (pQueue)->QIn=pPacket; \
+ \
+ }
+
+#define INIT_PACKET_QUEUE(pQueue) { \
+ (pQueue)->QIn=NULL; \
+ (pQueue)->QOut=NULL; \
+ }
+
+#define QUEUE_EMPTY(pQueue) ((pQueue)->QOut==NULL)
+
+#define PEEK_QUEUE(pQueue) (pQueue)->QOut
+
+#define NEXT_PACKET(pQueue) (pQueue)->QOut=PACKET_RESERVED((pQueue)->QOut)->Next;
+
+
+
+#define DEFAULT_MULTICASTLISTMAX 16
+
+
+
+
+typedef struct _SYNC_CONTEXT {
+ ULONG Value;
+ PELNK3_ADAPTER pAdapter;
+ } SYNC_CONTEXT, *PSYNC_CONTEXT;
diff --git a/private/ntos/ndis/elnk3/init.c b/private/ntos/ndis/elnk3/init.c
new file mode 100644
index 000000000..a20c96a8d
--- /dev/null
+++ b/private/ntos/ndis/elnk3/init.c
@@ -0,0 +1,897 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ init.c
+
+Abstract:
+
+ Ndis 3.0 MAC driver for the 3Com Etherlink III
+
+
+Author:
+
+ Brian Lieuallen (BrianLie) 12/14/92
+
+
+Environment:
+
+ Kernel Mode Operating Systems : NT
+
+Revision History:
+
+ Portions borrowed from ELNK3 driver by
+ Earle R. Horton (EarleH)
+
+
+--*/
+
+
+
+#include <ndis.h>
+
+//#include <efilter.h>
+
+#include "debug.h"
+
+#include "elnk3hrd.h"
+#include "elnk3sft.h"
+#include "elnk3.h"
+
+#if defined(ALLOC_PRAGMA)
+#pragma NDIS_INIT_FUNCTION(DriverEntry)
+#pragma NDIS_INIT_FUNCTION(Elnk3Initialize)
+#pragma NDIS_INIT_FUNCTION(Elnk3InitializeAdapter)
+#pragma NDIS_INIT_FUNCTION(Elnk3Init3C589)
+#endif
+
+
+#if DBG
+
+ULONG Elnk3DebugFlag;
+ULONG Elnk3LogArray[ELNK3_MAX_LOG_SIZE+16];
+ULONG ElnkLogPointer;
+
+#endif
+
+MAC_BLOCK MacBlock = {0};
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+
+/*++
+
+Routine Description:
+
+ This is the transfer address of the driver. It initializes all the
+ appropriate variables used and calls NdisInitializeWrapper() and
+ NdisRegisterMac().
+
+
+Arguments:
+
+Return Value:
+
+ Indicates the success or failure of the initialization.
+
+--*/
+
+{
+ NDIS_STATUS InitStatus;
+ NDIS_MINIPORT_CHARACTERISTICS Characteristics;
+ NDIS_HANDLE WrapperHandle;
+
+
+
+#if DBG
+
+ Elnk3DebugFlag = 0;
+ Elnk3DebugFlag|= ELNK3_DEBUG_LOG;
+// Elnk3DebugFlag|= ELNK3_DEBUG_LOUD;
+// Elnk3DebugFlag|= ELNK3_DEBUG_VERY_LOUD;
+// Elnk3DebugFlag|= ELNK3_DEBUG_INIT;
+// Elnk3DebugFlag|= ELNK3_DEBUG_IO;
+// Elnk3DebugFlag|= ELNK3_DEBUG_REQ;
+// Elnk3DebugFlag|= ELNK3_DEBUG_RCV;
+// Elnk3DebugFlag|= ELNK3_DEBUG_SEND;
+// Elnk3DebugFlag|= ELNK3_DEBUG_INIT_BREAK;
+
+
+#endif
+
+ IF_INIT_LOUD(DbgPrint("Elnk3: DriverEntry\n");)
+#if DBG
+ if (Elnk3DebugFlag & ELNK3_DEBUG_INIT_BREAK) DbgBreakPoint();
+ if (Elnk3DebugFlag & ELNK3_DEBUG_INIT_FAIL) return STATUS_UNSUCCESSFUL;
+#endif
+
+ NdisMInitializeWrapper(
+ &WrapperHandle,
+ DriverObject,
+ RegistryPath,
+ NULL
+ );
+
+
+
+ //
+ // Prepare to call NdisRegisterMac.
+ //
+
+ Characteristics.MajorNdisVersion = ELNK3_NDIS_MAJOR_VERSION;
+ Characteristics.MinorNdisVersion = ELNK3_NDIS_MINOR_VERSION;
+ Characteristics.Reserved = 0;
+ Characteristics.CheckForHangHandler = Elnk3CheckForHang;
+
+// Characteristics.DisableInterruptHandler = Elnk3DisableInterrupts;
+// Characteristics.EnableInterruptHandler = Elnk3EnableInterrupts;
+ Characteristics.DisableInterruptHandler = NULL;
+ Characteristics.EnableInterruptHandler = NULL;
+
+ Characteristics.SendHandler = Elnk3MacSend;
+ Characteristics.TransferDataHandler = Elnk3TransferData;
+ Characteristics.ResetHandler = Elnk3Reset;
+ Characteristics.SetInformationHandler = Elnk3SetInformation;
+ Characteristics.QueryInformationHandler = Elnk3QueryInformation;
+ Characteristics.InitializeHandler = Elnk3Initialize;
+ Characteristics.HaltHandler = Elnk3Halt;
+ Characteristics.ISRHandler = Elnk3Isr;
+ Characteristics.HandleInterruptHandler = Elnk3IsrDpc;
+ Characteristics.ReconfigureHandler = Elnk3Reconfigure;
+
+ InitStatus=NdisMRegisterMiniport(
+ WrapperHandle,
+ &Characteristics,
+ sizeof(Characteristics)
+ );
+
+
+#if DBG
+
+ if (InitStatus != NDIS_STATUS_SUCCESS) {
+
+ IF_LOUD(DbgPrint("Elnk3: NdisMRegisterMiniport failed with code 0x%x\n", InitStatus );)
+
+ } else {
+
+ IF_INIT_LOUD (DbgPrint("Elnk3: NdisMRegisterMiniport succeeded\n" );)
+
+
+ }
+
+#endif
+
+ return InitStatus;
+
+}
+
+
+
+
+
+
+NDIS_STATUS
+Elnk3Initialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE AdapterHandle,
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+/*++
+Routine Description:
+
+ This is the Elnk3 MacAddAdapter routine. The system calls this routine
+ to add support for particular UB adapter. This routine extracts
+ configuration information from the configuration data base and registers
+ the adapter with NDIS.
+
+
+Arguments:
+
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS - Adapter was successfully added.
+ NDIS_STATUS_FAILURE - Adapter was not added
+
+--*/
+{
+
+ PELNK3_ADAPTER pAdapter;
+ NDIS_STATUS status;
+
+
+
+
+ *OpenErrorStatus=NDIS_STATUS_SUCCESS;
+
+ IF_LOUD (DbgPrint("ELNK3: Initialize\n");)
+
+ //
+ // Scan the media list for our media type (802.3)
+ //
+
+ *SelectedMediumIndex =(UINT) -1;
+
+ while (MediumArraySize > 0) {
+
+ if (MediumArray[--MediumArraySize] == NdisMedium802_3 ) {
+
+ *SelectedMediumIndex = MediumArraySize;
+
+ break;
+ }
+ }
+
+
+ if (*SelectedMediumIndex == -1) {
+
+ return NDIS_STATUS_UNSUPPORTED_MEDIA;
+
+ }
+
+
+
+ status = NdisAllocateMemory(
+ (PVOID *)&pAdapter,
+ sizeof(ELNK3_ADAPTER),
+ 0,
+ HighestAcceptableMax
+ );
+
+ if (status != NDIS_STATUS_SUCCESS) {
+
+ IF_LOUD (DbgPrint("Elnk3AddAdapter():NdisAllocateMemory() failed\n");)
+
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ NdisZeroMemory(pAdapter,sizeof(ELNK3_ADAPTER));
+
+ pAdapter->NdisAdapterHandle=AdapterHandle;
+
+ //
+ // Read Registery information into Adapter structure
+ //
+
+ if (Elnk3ReadRegistry(pAdapter,ConfigurationHandle)==NDIS_STATUS_SUCCESS) {
+ //
+ // We got the registry info try to register the adpater
+ //
+
+ if (Elnk3InitializeAdapter(
+ &MacBlock,
+ pAdapter,
+ ConfigurationHandle)== NDIS_STATUS_SUCCESS) {
+
+
+ return NDIS_STATUS_SUCCESS;
+
+ }
+
+ } else {
+
+ IF_LOUD(DbgPrint("Failed to get config info, probably bad Slot number\n");)
+
+ }
+
+ //
+ // We failed to register the adapter for some reason, so free the
+ // memory for the adapter block and return failure
+
+ NdisFreeMemory(pAdapter,
+ sizeof(ELNK3_ADAPTER),
+ 0);
+
+ return NDIS_STATUS_FAILURE;
+
+}
+
+
+
+
+NDIS_STATUS
+Elnk3InitializeAdapter(
+ IN PMAC_BLOCK pMac,
+ IN PELNK3_ADAPTER pAdapter,
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Called when a new adapter should be registered.
+ Initializes the adapter block, and calls NdisRegisterAdapter().
+
+Arguments:
+
+ AdapterName - The name that the system will refer to the adapter by.
+ Others - Adapter-specific parameters as defined in defaults.h.
+
+Return Value:
+
+ Indicates the success or failure of the registration.
+
+--*/
+
+{
+ NDIS_STATUS Status;
+ NDIS_INTERFACE_TYPE InterfaceType;
+ UINT i;
+ PVOID TranslatedIdPort=NULL;
+
+
+ Elnk3InitAdapterBlock(pAdapter);
+
+ //
+ // Initialize various elments in the Adapter Structure;
+ //
+
+ if ((pAdapter->CardType==ELNK3_3C509) ||
+ ((pAdapter->CardType==ELNK3_3C589))) {
+
+ InterfaceType = NdisInterfaceIsa;
+
+ } else {
+
+ if (pAdapter->CardType==ELNK3_3C579) {
+
+ InterfaceType = NdisInterfaceEisa;
+
+ } else {
+
+ InterfaceType = NdisInterfaceMca;
+ }
+
+ }
+
+ NdisMSetAttributes(
+ pAdapter->NdisAdapterHandle,
+ pAdapter,
+ FALSE,
+ InterfaceType
+ );
+
+ if ((pMac->TranslatedIdPort==0) && (pAdapter->CardType==ELNK3_3C509)) {
+
+ IF_INIT_LOUD(DbgPrint("Elnk3: First ISA card claiming Id port\n");)
+
+ Status=NdisMRegisterIoPortRange(
+ &TranslatedIdPort,
+ pAdapter->NdisAdapterHandle,
+ pAdapter->IdPortBaseAddr,
+ 1
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ IF_INIT_LOUD(DbgPrint("Elnk3: First ISA card claiming Id port---FAILED\n");)
+
+ goto fail0;
+
+ }
+
+
+ pAdapter->IdPortOwner=TRUE;
+
+ pMac->TranslatedIdPort=TranslatedIdPort;
+
+ //
+ // See if there are any boards around
+ //
+ Elnk3FindIsaBoards(pMac);
+ }
+
+ Status=NdisMRegisterIoPortRange(
+ &pAdapter->TranslatedIoBase,
+ pAdapter->NdisAdapterHandle,
+ pAdapter->IoPortBaseAddr,
+ 16
+ );
+
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ IF_INIT_LOUD(DbgPrint("Elnk3: Failed to register i/o ports\n");)
+
+ goto fail1;
+
+ }
+
+ //
+ // Compute the portaddresses now so we don't have to
+ // do it on each port access
+ //
+ for (i=0;i<16;i++) {
+
+ pAdapter->PortOffsets[i]=(PUCHAR)pAdapter->TranslatedIoBase+i;
+
+ }
+
+
+
+
+
+ if (pAdapter->CardType==ELNK3_3C509) {
+ //
+ // Lets try to find a card at the address specified
+ //
+ // Note: this service may change the I/O base aquired
+ // from the registry. This will happen if we can't
+ // find a match.
+ //
+
+ if (!Elnk3ActivateIsaBoard(
+ pMac,
+ pAdapter,
+ pAdapter->NdisAdapterHandle,
+ pAdapter->TranslatedIoBase,
+ pAdapter->IoPortBaseAddr,
+ &pAdapter->IrqLevel,
+ pAdapter->Transceiver,
+ ConfigurationHandle
+ )) {
+
+ NdisWriteErrorLogEntry(
+ pAdapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_BAD_IO_BASE_ADDRESS,
+ 8,
+ pAdapter->IoPortBaseAddr,
+ pMac->IsaCards[0].IOPort,
+ pMac->IsaCards[1].IOPort,
+ pMac->IsaCards[2].IOPort,
+ pMac->IsaCards[3].IOPort,
+ pMac->IsaCards[4].IOPort,
+ pMac->IsaCards[5].IOPort,
+ pMac->IsaCards[6].IOPort
+ );
+
+ Status=NDIS_STATUS_ADAPTER_NOT_FOUND;
+
+ goto fail2;
+ }
+
+ }
+
+
+
+ else if (pAdapter->CardType==ELNK3_3C579) {
+ //
+ // Get the Irq from the eisa adapter since the 3com
+ // CFG put the interrupt information in the second
+ // function of the EISA info instead of making it
+ // a sub function.
+ //
+
+ Elnk3GetEisaResources(
+ pAdapter,
+ &pAdapter->IrqLevel
+ );
+ }
+
+ else if (pAdapter->CardType==ELNK3_3C589)
+ {
+ Status = Elnk3Init3C589( pAdapter);
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ IF_INIT_LOUD(DbgPrint("Elnk3: Failed to initialize 3C589\n");)
+
+ goto fail1;
+ }
+ }
+
+
+ //
+ // Allocate the Send, LookAhead and LoopBack buffers
+ //
+ Status=Elnk3AllocateBuffers(
+ pAdapter,
+ pAdapter->NdisAdapterHandle,
+ TRUE
+ );
+
+
+ if (Status!=NDIS_STATUS_SUCCESS) {
+
+ goto fail2;
+ }
+
+
+ //
+ // Make sure the card is inactive
+ //
+ CardReset(pAdapter);
+
+ pAdapter->AdapterInitializing=TRUE;
+
+
+
+ //
+ // Set up the interrupt handlers.
+ //
+
+ NdisZeroMemory (&pAdapter->NdisInterrupt, sizeof(NDIS_MINIPORT_INTERRUPT) );
+
+ Status=NdisMRegisterInterrupt(
+ &pAdapter->NdisInterrupt, // interrupt info str
+ pAdapter->NdisAdapterHandle, // NDIS adapter handle
+ (UINT)pAdapter->IrqLevel, // vector or int number
+ (UINT)pAdapter->IrqLevel, // level or priority
+ TRUE,
+ FALSE, // NOT shared
+ pAdapter->InterruptMode
+ );
+
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ IF_LOUD (DbgPrint("ELNK3: NdisInitializeInterruptFailed\n");)
+ NdisWriteErrorLogEntry(
+ pAdapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_INTERRUPT_CONNECT,
+ 1,
+ (ULONG)pAdapter->IrqLevel
+ );
+
+
+ goto fail3;
+ }
+
+
+ //
+ // Perform card tests.
+ //
+ if (!CardTest(pAdapter) ) {
+
+ IF_LOUD ( DbgPrint("ELNK3: CardTest() failed, game over\n");)
+
+ NdisWriteErrorLogEntry(
+ pAdapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
+ 2,
+ (ULONG)pAdapter->IrqLevel,
+ (ULONG)pAdapter->IoPortBaseAddr
+ );
+
+
+ Status = NDIS_STATUS_FAILURE;
+ goto fail4;
+ }
+
+ // register a shutdown handler for this card
+ NdisMRegisterAdapterShutdownHandler(
+ pAdapter->NdisAdapterHandle, // miniport handle.
+ pAdapter, // shutdown context.
+ Elnk3Shutdown // shutdown handler.
+ );
+
+ CardReStart(pAdapter);
+ CardReStartDone(pAdapter);
+
+ IF_LOUD (DbgPrint("Elnk3: Elnk3InitializeAdapter() Succeeded\n");)
+
+ return NDIS_STATUS_SUCCESS;
+
+
+ //
+ // IF WE ARE HERE SOME INITIALIZATION FAILURE OCCURRED
+ //
+
+
+ //
+ // Code to unwind what has already been set up when a part of
+ // initialization fails, which is jumped into at various
+ // points based on where the failure occured. Jumping to
+ // a higher-numbered failure point will execute the code
+ // for that block and all lower-numbered ones.
+ //
+
+
+fail4:
+
+ NdisMDeregisterInterrupt(&pAdapter->NdisInterrupt);
+
+
+fail3:
+
+ Elnk3AllocateBuffers(
+ pAdapter,
+ pAdapter->NdisAdapterHandle,
+ FALSE
+ );
+
+fail2:
+
+ NdisMDeregisterIoPortRange(
+ pAdapter->NdisAdapterHandle,
+ pAdapter->IoPortBaseAddr,
+ 16,
+ pAdapter->TranslatedIoBase
+ );
+
+
+
+fail1:
+
+ if (pAdapter->IdPortOwner) {
+
+ IF_INIT_LOUD(DbgPrint("Elnk3: Id port owner going away\n");)
+
+ NdisMDeregisterIoPortRange(
+ pAdapter->NdisAdapterHandle,
+ pAdapter->IdPortBaseAddr,
+ 1,
+ pMac->TranslatedIdPort
+ );
+
+
+
+ pMac->TranslatedIdPort=0;
+ }
+
+fail0:
+
+ IF_LOUD (DbgPrint("Elnk3RegisterAdapter() Failed\n");)
+ return Status;
+}
+
+
+
+
+
+NDIS_STATUS
+Elnk3AllocateBuffers(
+ IN PELNK3_ADAPTER pAdapter,
+ IN NDIS_HANDLE NdisAdapterHandle,
+ BOOLEAN Allocate
+ )
+
+{
+ NDIS_STATUS Status;
+
+
+ if (Allocate) {
+
+ //
+ // Allocate the memory to hold the loopback indication
+ //
+
+ Status=NdisAllocateMemory(
+ (PVOID *)(&pAdapter->TransContext[0].LookAhead),
+ 4096,
+ 0,
+ HighestAcceptableMax
+ );
+
+ if (Status!=NDIS_STATUS_SUCCESS) {
+ goto Fail0000;
+ }
+
+ pAdapter->TransContext[1].LookAhead=
+ (PNIC_RCV_HEADER)((PUCHAR)pAdapter->TransContext[0].LookAhead+2048);
+
+ IF_INIT_LOUD(DbgPrint("ELNK3: Lookahead->%08lx\n",pAdapter->TransContext[0].LookAhead);)
+
+
+
+ return NDIS_STATUS_SUCCESS;
+
+ }
+
+
+ NdisFreeMemory(
+ pAdapter->TransContext[0].LookAhead,
+ 4096,
+ 0
+ );
+
+
+
+Fail0000:
+
+ return NDIS_STATUS_RESOURCES;
+
+}
+
+
+
+VOID
+Elnk3InitAdapterBlock(
+ IN PELNK3_ADAPTER pAdapter
+ )
+
+{
+ UINT i;
+
+
+ //
+ // BUGBUG: This could probably be smaller, but NBF doesn't currently set a
+ // lookahead size
+ //
+
+ pAdapter->MaxLookAhead=60 ; //ELNK3_MAX_LOOKAHEAD_SIZE;
+
+ Elnk3AdjustMaxLookAhead(pAdapter);
+
+ for (i=0; i<TIMER_ARRAY_SIZE; i++) {
+ pAdapter->TimerValues[i]=25;
+ }
+
+ pAdapter->TransContext[0].pAdapter = pAdapter;
+ pAdapter->TransContext[1].pAdapter = pAdapter;
+
+
+ if (pAdapter->CardType==ELNK3_3C529) {
+ //
+ // MCA card does not hide bytes
+ //
+ pAdapter->RxHiddenBytes=0;
+
+ } else {
+ //
+ // ISA hides 16
+ //
+ pAdapter->RxHiddenBytes=16;
+ }
+
+ pAdapter->RxMinimumThreshold=8;
+
+ //
+ // Set the minimum amount that needs to be in the fifo
+ // before we draw out some of an incomplete packet
+ //
+ pAdapter->LowWaterMark=64;
+
+
+ return;
+}
+
+
+VOID
+Elnk3Shutdown(
+ IN NDIS_HANDLE MiniportHandle
+ )
+{
+ PELNK3_ADAPTER pAdapter=MiniportHandle;
+
+ IF_INIT_LOUD(DbgPrint("Elnk3: Shutdown\n");)
+
+ //
+ // It's time to rock and roll
+ //
+ CardReStart(pAdapter);
+}
+
+VOID
+Elnk3Halt(
+ IN NDIS_HANDLE MiniportHandle
+ )
+{
+
+ PELNK3_ADAPTER pAdapter=MiniportHandle;
+
+ IF_INIT_LOUD(DbgPrint("Elnk3: Halt\n");)
+ //
+ // It's time to rock and roll
+ //
+ CardReStart(pAdapter);
+
+ NdisMDeregisterInterrupt(&pAdapter->NdisInterrupt);
+
+ if (pAdapter->IdPortOwner) {
+
+ IF_INIT_LOUD(DbgPrint("Elnk3: Id port owner going away\n");)
+
+ NdisMDeregisterIoPortRange(
+ pAdapter->NdisAdapterHandle,
+ pAdapter->IdPortBaseAddr,
+ 1,
+ MacBlock.TranslatedIdPort
+ );
+
+ MacBlock.TranslatedIdPort=0;
+ }
+
+
+ NdisMDeregisterIoPortRange(
+ pAdapter->NdisAdapterHandle,
+ pAdapter->IoPortBaseAddr,
+ 16,
+ pAdapter->TranslatedIoBase
+ );
+
+ Elnk3AllocateBuffers(
+ pAdapter,
+ pAdapter->NdisAdapterHandle,
+ FALSE
+ );
+
+
+ NdisFreeMemory(
+ pAdapter,
+ sizeof(ELNK3_ADAPTER),
+ 0
+ );
+}
+
+
+NDIS_STATUS
+Elnk3Reconfigure(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+
+{
+
+ IF_INIT_LOUD(DbgPrint("Elnk3: Reconfigure\n");)
+
+ return NDIS_STATUS_NOT_SUPPORTED;
+
+
+}
+
+
+NDIS_STATUS
+Elnk3Init3C589(
+ IN OUT PELNK3_ADAPTER pAdapter
+ )
+
+{
+ ELNK3_Address_Configuration_Register acr;
+ ELNK3_Resource_Configuration_Register rcr;
+ USHORT i, window;
+ NDIS_STATUS Status;
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ ELNK3ReadAdapterUshort ( pAdapter , PORT_CmdStatus , &window );
+ window &= 0xE000; // Current window - high 3 bits
+
+ ELNK3_SELECT_WINDOW( pAdapter, WNO_SETUP );
+
+ //
+ // init address configuration
+ //
+ acr.eacf_contents = 0;
+
+ if ( pAdapter->Transceiver == TRANSCEIVER_BNC ) {
+ acr.eacf_XCVR = TRANSCEIVER_BNC;
+ }
+
+ ELNK3WriteAdapterUshort(pAdapter,PORT_CfgAddress,acr.eacf_contents);
+
+ // Believe it or not, to make the 3C589 (not 3C589B) the IRQ have to be set
+ // to 3 (it can be anything - the card must be told 3).
+ rcr.ercf_contents = 0;
+ // rcr.ercf_IRQ = (USHORT)pAdapter->IrqLevel;
+ rcr.ercf_IRQ = 3;
+ rcr.ercf_reserved_F = 0xF;
+ ELNK3WriteAdapterUshort(pAdapter,PORT_CfgResource,rcr.ercf_contents);
+
+ // read in product ID
+ i = ELNK3ReadEEProm( pAdapter, EEPROM_PRODUCT_ID );
+ ELNK3WriteAdapterUshort( pAdapter, PORT_ProductID, i );
+
+ // Enable the adapter by setting the bit in the configuration control register
+ ELNK3WriteAdapterUchar(pAdapter,PORT_CfgControl,CCR_ENABLE);
+
+ // restore to whatever it used to be
+ ELNK3_SELECT_WINDOW( pAdapter, window);
+
+ return (Status);
+
+}
+
+
diff --git a/private/ntos/ndis/elnk3/interrup.c b/private/ntos/ndis/elnk3/interrup.c
new file mode 100644
index 000000000..d357eb7a1
--- /dev/null
+++ b/private/ntos/ndis/elnk3/interrup.c
@@ -0,0 +1,418 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ interrup.c
+
+Abstract:
+
+ Ndis 3.0 MAC driver for the 3Com Etherlink III
+
+Author:
+
+ Brian Lieuallen (BrianLie) 07/02/92
+
+Environment:
+
+ Kernel Mode Operating Systems : NT
+
+Revision History:
+
+ Portions borrowed from ELNK3 driver by
+ Earle R. Horton (EarleH)
+
+
+
+--*/
+
+
+
+
+#include <ndis.h>
+#include <efilter.h>
+
+#include "debug.h"
+
+
+#include "elnk3hrd.h"
+#include "elnk3sft.h"
+#include "elnk3.h"
+
+
+VOID
+CompleteRequests(
+ IN PELNK3_ADAPTER pAdapter
+ );
+
+VOID
+ELNK3MaskClearInterrupt(
+ IN PELNK3_ADAPTER pAdapter,
+ IN UCHAR Mask
+ );
+
+VOID
+ELNK3UnmaskInterrupt(
+ IN PELNK3_ADAPTER pAdapter,
+ IN UCHAR Mask
+ );
+
+
+
+VOID
+Elnk3Isr(
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueDpc,
+ IN NDIS_HANDLE Context
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ ServiceContext - pointer to the adapter object
+
+Return Value:
+
+ TRUE, if the DPC is to be executed, otherwise FALSE.
+
+--*/
+
+{
+ PELNK3_ADAPTER pAdapter = ((PELNK3_ADAPTER)Context);
+ USHORT InterruptReason;
+
+ *InterruptRecognized=TRUE;
+ *QueueDpc=TRUE;
+
+
+ InterruptReason=ELNK3_READ_PORT_USHORT(pAdapter,PORT_CmdStatus);
+
+ if ((InterruptReason & 0x01)==0) {
+ //
+ // The ISR has run with out an interrupt present on the card, Hmm
+ //
+ // This was added because the AST manhatton seems to run the ISR on
+ // muliple processors for a given interrupt
+ //
+
+ IF_LOUD(DbgPrint("Elnk3: Isr bit 0 clear %04x adapter=%08lx\n",InterruptReason,pAdapter);)
+
+ *InterruptRecognized=FALSE;
+ *QueueDpc=FALSE;
+ return;
+ }
+
+ if (pAdapter->AdapterInitializing) {
+ IF_INIT_LOUD (DbgPrint("Elnk3: ISR called during init\n");)
+ pAdapter->InitInterrupt=TRUE;
+
+ ELNK3_COMMAND(pAdapter,EC_ACKNOWLEDGE_INTERRUPT,EC_INT_INTERRUPT_REQUESTED | 1);
+
+ *QueueDpc=FALSE;
+
+ return;
+ }
+
+
+
+ //
+ // needed for level triggered MCA cards
+ //
+ ELNK3_COMMAND(pAdapter,EC_SET_INTERRUPT_MASK, 0x00 );
+
+ ELNK3_COMMAND(pAdapter,EC_ACKNOWLEDGE_INTERRUPT, 1);
+
+ return;
+}
+
+
+
+VOID
+Elnk3IsrDpc(
+ IN NDIS_HANDLE Context
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PELNK3_ADAPTER pAdapter = ((PELNK3_ADAPTER)Context);
+ UCHAR InterruptReason;
+ USHORT TimerValue;
+ ULONG Latency;
+ UINT LoopLimit=10;
+
+
+
+ DEBUG_STAT(pAdapter->Stats.TotalInterrupts);
+
+ //
+ // Read the timer port to keep track of latencies
+ //
+ TimerValue=ELNK3_READ_PORT_USHORT(pAdapter,PORT_Timer);
+
+ if ((UCHAR)TimerValue==0xff) {
+ //
+ // The timer has maxed out. We will just use the last
+ // average to hopefully keep things in line.
+ //
+
+ TimerValue=(UCHAR)pAdapter->AverageLatency;
+ }
+
+ pAdapter->TimerValues[pAdapter->CurrentTimerValue]=(UCHAR)TimerValue;
+
+ pAdapter->CurrentTimerValue= (pAdapter->CurrentTimerValue+1) % TIMER_ARRAY_SIZE;
+
+ IF_LOG(0x11,0x11,(TimerValue & 0xff)<<2);
+
+
+ InterruptReason=(UCHAR)ELNK3_READ_PORT_USHORT(pAdapter,PORT_CmdStatus);
+
+ while (((InterruptReason & pAdapter->CurrentInterruptMask) != 0)
+ &&
+ ((--LoopLimit) != 0)) {
+
+
+ IF_LOG(0x11,0x22,InterruptReason);
+
+ if (InterruptReason & EC_INT_ADAPTER_FAILURE) {
+
+ IF_LOUD(
+ DbgPrint("ELNK3: Adapter Failed\n");
+ DbgBreakPoint();
+ )
+
+ //
+ // No more interrupts
+ //
+ ELNK3_COMMAND(pAdapter,EC_SET_READ_ZERO_MASK,0x00);
+
+ //
+ // Clear what ever is there now
+ //
+ ELNK3_COMMAND(pAdapter,EC_ACKNOWLEDGE_INTERRUPT, 0xff);
+
+ //
+ // Something is messed up so no point in handling any thing
+ //
+ InterruptReason=0;
+
+ //
+ // Get the reinit code to run
+ //
+ pAdapter->AdapterStatus |= STATUS_REINIT_REQUESTED;
+ }
+
+ //
+ // Interrupts are basically grouped into two catagories
+ // Recieve and xmit
+ //
+
+ if ((InterruptReason & (EC_INT_TX_COMPLETE)) ) {
+
+ IF_VERY_LOUD (DbgPrint("Handle xmit int\n");)
+
+ DEBUG_STAT(pAdapter->Stats.TxCompIntCount);
+
+
+ HandleXmtInterrupts(pAdapter);
+
+ NdisMSendResourcesAvailable(pAdapter->NdisAdapterHandle);
+
+ } else {
+
+ if ((InterruptReason & (EC_INT_RX_EARLY | EC_INT_RX_COMPLETE)) ) {
+
+ if (InterruptReason & (EC_INT_RX_COMPLETE) ) {
+
+ //
+ // Rx complete will be clear when we handle the interrupt
+ //
+ DEBUG_STAT(pAdapter->Stats.RxCompIntCount);
+
+ (*pAdapter->ReceiveCompleteHandler)(pAdapter);
+
+ } else {
+
+ DEBUG_STAT(pAdapter->Stats.RxEarlyIntCount);
+
+ //
+ // dismiss the rx early int
+ //
+ ELNK3_COMMAND(pAdapter,EC_ACKNOWLEDGE_INTERRUPT,EC_INT_RX_EARLY );
+
+ (*pAdapter->EarlyReceiveHandler)(pAdapter);
+ }
+
+
+ } else {
+
+ if ((InterruptReason & (EC_INT_TX_AVAILABLE)) ) {
+
+ ELNK3_COMMAND(pAdapter,EC_ACKNOWLEDGE_INTERRUPT,EC_INT_TX_AVAILABLE );
+
+ DEBUG_STAT(pAdapter->Stats.TxAvailIntCount);
+
+ NdisMSendResourcesAvailable(pAdapter->NdisAdapterHandle);
+
+ } else {
+
+ if ((InterruptReason & (EC_INT_INTERRUPT_REQUESTED)) ) {
+ //
+ // Dismiss the user requested interrupt
+ //
+ IF_SEND_LOUD(DbgPrint("Elnk3: Requested interrupt\n");)
+
+ ELNK3_COMMAND(pAdapter, EC_ACKNOWLEDGE_INTERRUPT, EC_INT_INTERRUPT_REQUESTED);
+
+ }
+ }
+ }
+ }
+
+
+ InterruptReason=(UCHAR)ELNK3_READ_PORT_USHORT(pAdapter,PORT_CmdStatus);
+
+ } // while (interrupt reasons)
+
+ //
+ // Unmask interrupts
+ //
+
+ ELNK3_COMMAND(pAdapter,EC_SET_INTERRUPT_MASK,pAdapter->CurrentInterruptMask);
+
+
+ //
+ // We calculate the latency average from the last four
+ // DPC latencies every four DPC runs
+ //
+
+ if (pAdapter->CurrentTimerValue == 0) {
+
+ Latency=((ULONG)pAdapter->TimerValues[0] +
+ pAdapter->TimerValues[1] +
+ pAdapter->TimerValues[2] +
+ pAdapter->TimerValues[3])/4;
+
+ //
+ // The latency is dword times and we want byte times
+ //
+
+ pAdapter->AverageLatency=Latency;
+
+ Latency<<=2;
+
+ if ((pAdapter->EarlyReceiveThreshold-pAdapter->RxMinimumThreshold) < Latency) {
+
+ pAdapter->LookAheadLatencyAdjustment=pAdapter->RxMinimumThreshold & 0x7fc;
+ pAdapter->LatencyAdjustment=Latency+pAdapter->RxHiddenBytes;
+ } else {
+
+ pAdapter->LookAheadLatencyAdjustment=pAdapter->EarlyReceiveThreshold-Latency & 0x7fc;
+ pAdapter->LatencyAdjustment=Latency+pAdapter->RxHiddenBytes;
+ }
+
+ IF_LOG(0xcc,0xcc,Latency);
+
+ }
+
+
+
+ //
+ // See if the card needs to restarted
+ //
+ if (pAdapter->AdapterStatus & STATUS_REINIT_REQUESTED ) {
+ IF_LOUD(DbgPrint("Elnk3: Handling pending request\n");)
+
+ //
+ // It's time to rock and roll
+ //
+ CardReStart(pAdapter);
+
+
+ CardReStartDone(pAdapter);
+
+ //
+ // Done re-initializing
+ //
+ pAdapter->AdapterStatus &= ~STATUS_REINIT_REQUESTED;
+
+
+ }
+
+
+
+#if DBG
+ InterruptReason=(UCHAR)ELNK3_READ_PORT_USHORT(pAdapter,PORT_CmdStatus);
+
+ IF_LOG(0x11,0x33,InterruptReason);
+#endif
+}
+
+#if 0
+
+VOID
+Elnk3EnableInterrupts(
+ IN NDIS_HANDLE Context
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PELNK3_ADAPTER pAdapter=Context;
+
+// IF_INIT_LOUD(DbgPrint("Elnk3: EnableInterrupts\n");)
+
+ ELNK3_COMMAND(pAdapter,EC_SET_INTERRUPT_MASK,pAdapter->CurrentInterruptMask);
+
+}
+
+
+VOID
+Elnk3DisableInterrupts(
+ IN NDIS_HANDLE Context
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PELNK3_ADAPTER pAdapter=Context;
+
+// IF_INIT_LOUD(DbgPrint("Elnk3: DisableInterrupts\n");)
+
+ ELNK3_COMMAND(pAdapter,EC_SET_INTERRUPT_MASK, 0x00);
+
+}
+
+#endif
diff --git a/private/ntos/ndis/elnk3/keywords.h b/private/ntos/ndis/elnk3/keywords.h
new file mode 100644
index 000000000..f820aa5c6
--- /dev/null
+++ b/private/ntos/ndis/elnk3/keywords.h
@@ -0,0 +1,56 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ keywords.h
+
+Abstract:
+
+ Contains all Ndis2 and Ndis3 mac-specific keywords.
+
+Author:
+
+ Bob Noradki
+
+Environment:
+
+ This driver is expected to work in DOS, OS2 and NT at the equivalent
+ of kernal mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+
+
+--*/
+#ifndef NDIS2
+#define NDIS2 0
+#endif
+
+#if NDIS2
+
+#define IOADDRESS NDIS_STRING_CONST("IOBASE")
+#define INTERRUPT NDIS_STRING_CONST("INTERRUPT")
+#define MAX_MULTICAST_LIST NDIS_STRING_CONST("MAXMULTICAST")
+#define NETWORK_ADDRESS NDIS_STRING_CONST("NETADDRESS")
+#define BUS_TYPE NDIS_STRING_CONST("BusType")
+#define TRANSCEIVER NDIS_STRING_CONST("Transceiver")
+
+#else // NDIS3
+
+#define IOADDRESS NDIS_STRING_CONST("IoBaseAddress")
+#define INTERRUPT NDIS_STRING_CONST("InterruptNumber")
+#define MAX_MULTICAST_LIST NDIS_STRING_CONST("MaximumMulticastList")
+#define NETWORK_ADDRESS NDIS_STRING_CONST("NetworkAddress")
+#define BUS_TYPE NDIS_STRING_CONST("BusType")
+#define TRANSCEIVER NDIS_STRING_CONST("Transceiver")
+
+#endif
diff --git a/private/ntos/ndis/elnk3/makefile b/private/ntos/ndis/elnk3/makefile
new file mode 100644
index 000000000..677d610db
--- /dev/null
+++ b/private/ntos/ndis/elnk3/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/elnk3/receive.c b/private/ntos/ndis/elnk3/receive.c
new file mode 100644
index 000000000..2acd4d6a9
--- /dev/null
+++ b/private/ntos/ndis/elnk3/receive.c
@@ -0,0 +1,1722 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ receive.c
+
+Abstract:
+
+ Ndis 3.0 MAC driver for the 3Com Etherlink III
+
+
+ FYI: The ELNK III behaves maginally if it is overflowing.
+
+ A note to the curious:
+
+ This module supports two different methods of handling received frames.
+
+ Method 0: the default method, basically tries to keep the stinking 2k
+ receive fifo as empty as possible. In order to do this, it needs to
+ port i/o the data into system memory and then copy from this system
+ memory to packets during transferdata. Obviously it would be best to
+ not have this memory copy.
+
+ Method 1: tries to avoid the memory copy by port i/o'ing straigth
+ into the packet buffers during transfer data. The problem with method
+ is that by the time you indicate the frame up, their is going to be
+ about 1300 bytes sitting in fifo from this packet. This obviously
+ means that if the total latency to transfer data port i/o'ing is
+ more than ~700 byte times, you are going to under run the next packet.
+ The more protocol's bound, the more delay.
+
+ Method zero is the best at avoiding underruns, but you pay a price in
+ the extra memory copy. An offsetting factor in addition to the fewer
+ overruns is that it appears that pending transferdata and later completing
+ it adds a fair amount of overhead to the code path.
+
+ Another interesting thing is that on MP machines the speed that you
+ can port i/o is signifigantly reduced do to contention for the bus
+ from the other processor(s). This increases the danger of overflowing.
+ Also, depending on how RISC platforms, deal with ISA boards and ports,
+ I think there is also a risk here of slower port i/o'ing.
+
+ As long as DPC latencies are fairly low and constant, either method will
+ work OK. The problem occures when the DPC latency increases. Like up around
+ a millisecond. In looking at this occurance it looks like the DPC is getting
+ stuck behind the HD DPC. If you get an 1ms latency you are almost assured of
+ overflowing if you are receiving full size frames back to back.
+
+
+ Bascially I believe that method 0 is the most solid and likely to
+ work on varied platforms.
+
+ If only 3Com had not been so cheap and had put another 2k in the fifo.
+
+ You should also take note that the asic on the isa and EISA cards have
+ a problem with loosing there place in the fifo. This is delt with in the
+ packet discard code. It also seems the these boards will also falsly detect
+ an adapter failure on the receive side.
+
+ Also, according to the 3com specs it is not possible for the card to
+ have both the packet incomplete bit set and receive error bit set
+ at the same time, but I have seen this happen. I suspect that this
+ is related to the above asic problem
+
+ Another neat feature of the card is that when it is overflowing it
+ has a tendancy to concatenate frames together to form really large
+ frames. When the frame completes it is marked with an error in the
+ receive status.
+
+
+
+
+
+Author:
+
+ Brian Lieuallen (BrianLie) 12/14/92
+
+Environment:
+
+ Kernel Mode Operating Systems : NT
+
+Revision History:
+
+ Portions borrowed from ELNK3 driver by
+ Earle R. Horton (EarleH)
+
+
+--*/
+
+
+
+#include <ndis.h>
+//#include <efilter.h>
+
+#include "debug.h"
+
+
+#include "elnk3hrd.h"
+#include "elnk3sft.h"
+#include "elnk3.h"
+
+
+VOID
+Elnk3DiscardIfBroadcast(
+ IN PELNK3_ADAPTER pAdapter,
+ IN PTRANSFERDATA_CONTEXT TransDataContext
+ );
+
+
+
+
+BOOLEAN
+Elnk3QuickPacketTest(
+ IN PNIC_RCV_HEADER Frame,
+ IN UINT NdisFilter
+ );
+
+
+
+ULONG
+Elnk3GuessFrameSize(
+ IN PNIC_RCV_HEADER Frame,
+ IN ULONG BytesNow
+ );
+
+
+BOOLEAN
+Elnk3IndicateLoopbackPacket(
+ IN PELNK3_ADAPTER pAdapter,
+ IN PNDIS_PACKET Packet
+ );
+
+
+
+VOID
+Elnk3TransferDataCompletion(
+ PTRANSFERDATA_CONTEXT TransDataContext
+ );
+
+
+VOID
+Elnk3DiscardPacketSync(
+ IN PTRANSFERDATA_CONTEXT TransDataContext
+ );
+
+BOOLEAN
+Elnk3CheckFifoSync(
+ IN PTRANSFERDATA_CONTEXT TransDataContext
+ );
+
+
+
+
+BOOLEAN
+Elnk3IndicatePackets2(
+ PELNK3_ADAPTER pAdapter
+ )
+/*++
+
+ Routine Description:
+ This routine Indicates all of the packets in the ring one at a time
+
+ Arguments:
+
+
+ Return Value:
+
+--*/
+
+{
+
+ USHORT RcvStatus;
+ ULONG AdditionalData;
+ ULONG GoodReceives=0;
+ ULONG BadReceives=0;
+
+ BOOLEAN Indicated=FALSE;
+
+ UINT CurrentPacket;
+ UINT NextPacket;
+ USHORT InterruptReason;
+ ULONG PossibleLength;
+
+
+ PTRANSFERDATA_CONTEXT TransDataContext;
+ PTRANSFERDATA_CONTEXT AltTransDataContext;
+
+
+ CurrentPacket=pAdapter->CurrentPacket;
+
+ TransDataContext= &pAdapter->TransContext[CurrentPacket];
+
+ if ((TransDataContext->BytesAlreadyRead == 0) && pAdapter->RejectBroadcast) {
+ //
+ // First interrupt for this packet
+ //
+ Elnk3DiscardIfBroadcast(
+ pAdapter,
+ TransDataContext
+ );
+ }
+
+
+ RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus);
+
+ IF_LOG(0xdc,0xdc,TransDataContext->BytesAlreadyRead);
+
+ IF_RCV_LOUD(DbgPrint("ELNK3: IndicatePackets RX status=%04x\n",RcvStatus);)
+
+ while ((BYTES_IN_FIFO(RcvStatus) > pAdapter->LowWaterMark ) ||
+ !(RcvStatus & RX_STATUS_INCOMPLETE)) {
+
+ //
+ // There is a completed packet or some data from a yet to be completed
+ // packet
+ //
+ if (ELNK3_PACKET_COMPLETE(RcvStatus) || (RcvStatus & RX_STATUS_ERROR)) {
+ //
+ // The packet has completed
+ //
+ if (!(RcvStatus & RX_STATUS_ERROR)) {
+
+ //
+ // The packet completed with out error
+ //
+
+ //
+ // Get the total packet length by adding the number of bytes still
+ // in the fifo to the number already taken out
+ //
+ TransDataContext->PacketLength=BYTES_IN_FIFO(RcvStatus);
+
+ TransDataContext->PacketLength+=TransDataContext->BytesAlreadyRead;
+
+ IF_LOG(0xdc,0x01,TransDataContext->PacketLength);
+
+ //
+ // Have we read all of the packet in already?
+ //
+ if (TransDataContext->PacketLength <= 1514) {
+ //
+ // It is a valid length
+ //
+ if (TransDataContext->PacketLength > TransDataContext->BytesAlreadyRead) {
+ //
+ // No, Need this much more
+ // The data in the fifo is padded to a dword boundary
+ //
+ AdditionalData=ELNK3_ROUND_TO_DWORD(TransDataContext->PacketLength)-TransDataContext->BytesAlreadyRead;
+
+ IF_LOG(0xad,0x01,AdditionalData);
+
+ //
+ // Go and get the rest
+ //
+ NdisRawReadPortBufferUlong(
+ pAdapter->PortOffsets[PORT_RxFIFO],
+ (PULONG)(((PUCHAR)TransDataContext->LookAhead)+TransDataContext->BytesAlreadyRead),
+ (AdditionalData>>2)
+ );
+
+ IF_RCV_LOUD(DbgPrint("IP: Da=%d Ad=%d\n",TransDataContext->BytesAlreadyRead, AdditionalData);)
+
+ //
+ // Now we have this much
+ //
+ TransDataContext->BytesAlreadyRead+=AdditionalData;
+
+ }
+ }
+
+ //
+ // Now discard the packet before indicating
+ //
+
+ Elnk3DiscardPacketSync(TransDataContext);
+
+ pAdapter->FramesRcvGood+=1;
+
+
+ //
+ // See if any data from the next packet is in the fifo
+ //
+ // If there is any data then it will go in the other unused buffer
+ //
+ NextPacket=(CurrentPacket+1) % 2;
+
+ AltTransDataContext= &pAdapter->TransContext[NextPacket];
+
+ RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus);
+
+ AdditionalData=BYTES_IN_FIFO_DW(RcvStatus);
+
+
+ //
+ // Go and get the data
+ //
+ while ((AdditionalData >= (pAdapter->LowWaterMark*2))
+ &&
+ (AdditionalData+AltTransDataContext->BytesAlreadyRead<=1514)
+ &&
+ !(RcvStatus & RX_STATUS_ERROR)) {
+
+
+ IF_LOG(0xaf,0x00,RcvStatus & 0xc7fc);
+
+ NdisRawReadPortBufferUlong(
+ pAdapter->PortOffsets[PORT_RxFIFO],
+ (PULONG)((PUCHAR)AltTransDataContext->LookAhead+AltTransDataContext->BytesAlreadyRead),
+ (AdditionalData >> 2)
+ );
+
+ AltTransDataContext->BytesAlreadyRead += AdditionalData;
+
+ RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus);
+
+ AdditionalData=BYTES_IN_FIFO_DW(RcvStatus);
+
+ }
+
+
+ //
+ // It seems that some asic's will generate an adapter failure
+ // when there really isn't one. Just to be safe we will check
+ // now. Since we have port i/o the whole packet now we will
+ // check. Better to not indicate a bad packet than to loose a
+ // good one
+ //
+ InterruptReason=ELNK3_READ_PORT_USHORT(pAdapter,PORT_CmdStatus);
+
+ if ((TransDataContext->PacketLength <=1514)
+ &&
+ (TransDataContext->PacketLength >= 14)
+ &&
+ !(InterruptReason & EC_INT_ADAPTER_FAILURE)) {
+
+ //
+ // The packet seems to be OK
+ // Subtract the header length(14) from the packet length
+ //
+ TransDataContext->PacketLength-=ELNK3_ETHERNET_HEADER_SIZE;
+
+ GoodReceives++;
+
+ NdisMEthIndicateReceive(
+ pAdapter->NdisAdapterHandle,
+ TransDataContext,
+ (PUCHAR)&TransDataContext->LookAhead->EthHeader,
+ ELNK3_ETHERNET_HEADER_SIZE,
+ TransDataContext->LookAhead->LookAheadData,
+ TransDataContext->PacketLength,
+ TransDataContext->PacketLength
+ );
+
+ DEBUG_STAT(pAdapter->Stats.PacketIndicated);
+
+ Indicated=TRUE;
+
+ } else {
+
+ IF_RCV_LOUD(DbgPrint("ELNK3: IndicatePacket: bad size or adapter failed -> not idicated\n");)
+
+ }
+
+ } else {
+ //
+ // The packet completed with some sort of error, just
+ // discard it
+ //
+
+ IF_RCV_LOUD(DbgPrint("ELNK3: IndicatePackets: error %04x\n", RcvStatus & 0xf800);)
+ IF_LOG(0xff,0xff,RcvStatus & 0xf800);
+
+ Elnk3DiscardPacketSync(TransDataContext);
+
+ pAdapter->MissedPackets++;
+
+
+ //
+ // This will be the next packet that we are using
+ //
+ NextPacket=(CurrentPacket+1) % 2;
+
+ AltTransDataContext= &pAdapter->TransContext[NextPacket];
+
+ DEBUG_STAT(pAdapter->Stats.BadReceives);
+
+ } // if (!(RcvStatus & RX_STATUS_ERROR))
+
+ //
+ // Re-initialize the info for this buffer
+ //
+ TransDataContext->BytesAlreadyRead=0;
+// TransDataContext->PacketLength=0;
+
+
+ //
+ // Switch buffers now. The one we are switching to may already
+ // have data in it from above.
+ //
+// pAdapter->CurrentPacket=NextPacket;
+ CurrentPacket=NextPacket;
+
+ //
+ // Update the pointer
+ //
+
+ TransDataContext=AltTransDataContext;
+
+
+ } // if (packet complete)
+
+ //
+ // The packet in the fifo is not complete yet.
+ // If there is enough data in the fifo copy it out now
+ // to reduce the chance of overflow
+ //
+
+ RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus);
+
+ if ((BYTES_IN_FIFO_DW(RcvStatus) >= pAdapter->LowWaterMark)
+ &&
+ (BYTES_IN_FIFO_DW(RcvStatus)+TransDataContext->BytesAlreadyRead<=1514)
+ &&
+ ((RcvStatus & RX_STATUS_INCOMPLETE))
+ &&
+ !(RcvStatus & RX_STATUS_ERROR)) {
+
+ IF_LOG(0xdc,0xea,(RcvStatus & 0xc7fc));
+
+ NdisRawReadPortBufferUlong(
+ pAdapter->PortOffsets[PORT_RxFIFO],
+ (PULONG)((PUCHAR)TransDataContext->LookAhead+TransDataContext->BytesAlreadyRead),
+ ((RcvStatus & 0x7fc) >> 2)
+ );
+
+ TransDataContext->BytesAlreadyRead += BYTES_IN_FIFO_DW(RcvStatus);
+
+ }
+
+
+
+
+ //
+ // if the receiver should happen to fail we might
+ // not ever exit this loop. The receiver should
+ // only fail if we read past our packet in the
+ // fifo
+ //
+
+ InterruptReason=ELNK3_READ_PORT_USHORT(pAdapter,PORT_CmdStatus);
+
+ if (InterruptReason & EC_INT_ADAPTER_FAILURE) {
+
+ IF_LOUD(
+ DbgPrint("Elnk3: Adapter failed\n");
+ DbgBreakPoint();
+ )
+
+ break;
+ }
+
+ //
+ // get a new receive for the logic up top
+ //
+ RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus);
+
+
+ } // While (!complete and > 64 bytes in fifo
+
+
+
+
+
+ //
+ // Figure out where to set the early receive threshold depending
+ // how much of the packet we have so far
+ //
+
+ if (TransDataContext->BytesAlreadyRead > 16) {
+
+ PossibleLength=Elnk3GuessFrameSize(TransDataContext->LookAhead,
+ TransDataContext->BytesAlreadyRead);
+
+ IF_RCV_LOUD(DbgPrint("Elnk3: Possible length is %d\n",PossibleLength);)
+
+ if (PossibleLength > pAdapter->LatencyAdjustment) {
+ //
+ // There is enough time to set the threshold before
+ // the packet passes the new threshold
+ //
+
+ IF_LOG(0xef,0x02,((PossibleLength)-pAdapter->LatencyAdjustment) & 0x7ff);
+ ELNK3_COMMAND(pAdapter,EC_SET_RX_EARLY, ((PossibleLength)-pAdapter->LatencyAdjustment) & 0x7fc);
+
+ }
+
+
+ } else {
+ //
+ // Set rx early to catch the front of the packet
+ //
+ IF_LOG(0xef,0x03,(pAdapter->LookAheadLatencyAdjustment));
+ ELNK3_COMMAND(pAdapter,EC_SET_RX_EARLY, (pAdapter->LookAheadLatencyAdjustment) );
+ }
+
+ //
+ // save this so we know where we are
+ //
+ pAdapter->CurrentPacket=CurrentPacket;
+
+ if (Indicated) {
+
+ DEBUG_STAT(pAdapter->Stats.IndicationCompleted);
+
+
+ NdisMEthIndicateReceiveComplete(pAdapter->NdisAdapterHandle);
+ }
+
+#if DBG
+ RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus);
+
+ IF_LOG(0xdc,0xdd,RcvStatus & 0xc7ff);
+#endif
+
+ return TRUE;
+}
+
+
+
+
+
+
+
+
+
+
+VOID
+Elnk3DiscardPacketSync(
+ IN PTRANSFERDATA_CONTEXT TransDataContext
+ )
+/*++
+
+Routine Description:
+
+ Discard tap packet in receive fifo
+
+Arguments:
+
+
+Notes:
+
+ We do this as a sync with interrupt routine because the discard
+ command does not complete with in the time it takes the I/O command
+ to complete. Since another command cannot be issued during the time
+ that one is in progress we must do this to protect our selves against
+ the mask command issued in the ISR.
+
+--*/
+
+{
+
+ PELNK3_ADAPTER pAdapter=TransDataContext->pAdapter;
+ ULONG RcvStatus;
+ ULONG Sum;
+ ULONG FreeBytes;
+
+
+ ELNK3_COMMAND(pAdapter, EC_RX_DISCARD_TOP_PACKET, 0);
+
+ //
+ // An interesting thing to do at raised IRQL.
+ // Unfortuanly I don't really see an alternative
+ // The wait appears to be very short any way
+ //
+ ELNK3_WAIT_NOT_BUSY(pAdapter);
+
+ RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus);
+
+ if (RcvStatus & RX_STATUS_INCOMPLETE) {
+ //
+ // If the status is incomplete then we need to check
+ // to make sure that the fifo is not fucked up with a
+ // packet lost in it. To find out we read the
+ // the number of free bytes out of page 3 and add
+ // the number of bytes received from the RX status.
+ // If this value isn't with in 100 of the total
+ // fifo size then we conclude that is screwed up
+ // and we reset the receiver
+ //
+
+ ELNK3_SELECT_WINDOW(pAdapter,WNO_FIFO);
+
+ FreeBytes=ELNK3_READ_PORT_USHORT(pAdapter,PORT_FREE_RX_BYTES);
+
+ ELNK3_SELECT_WINDOW(pAdapter,WNO_OPERATING);
+
+
+ Sum=(BYTES_IN_FIFO(RcvStatus) + FreeBytes);
+
+ if ((Sum + 90 < pAdapter->RxFifoSize)
+ ||
+ ((pAdapter->RxFifoSize==FreeBytes) && (BYTES_IN_FIFO(RcvStatus)!=0))) {
+
+ BOOLEAN FifoBad;
+
+ IF_LOG(0xde,0xad,0xffff);
+
+ IF_RCV_LOUD(DbgPrint("ELNK3: RX fifo problem used=%d free=%d size=%d\n",RcvStatus & 0x7ff,FreeBytes, pAdapter->RxFifoSize);)
+
+ //
+ // Looks like the fifo is messed up, try it again
+ // syncronized with interrupts
+ //
+ FifoBad=NdisMSynchronizeWithInterrupt(
+ &pAdapter->NdisInterrupt,
+ Elnk3CheckFifoSync,
+ TransDataContext
+ );
+
+ if (FifoBad) {
+ //
+ // It's fucked up. Reset the receiver
+ //
+ ELNK3_COMMAND(pAdapter,EC_RX_RESET,0);
+
+ ELNK3_WAIT_NOT_BUSY(pAdapter);
+
+ ELNK3_COMMAND(pAdapter,EC_RX_ENABLE,0);
+
+ ELNK3_COMMAND(pAdapter, EC_SET_RX_FILTER, pAdapter->RxFilter);
+ }
+ }
+ }
+}
+
+
+BOOLEAN
+Elnk3CheckFifoSync(
+ IN PTRANSFERDATA_CONTEXT TransDataContext
+ )
+/*++
+
+Routine Description:
+
+ Check the fifo's state to try to determine if a packet
+ is lost in it. We do this syncronized with interrupts
+ to reduce the chance of interrupt occuring between the
+ port reads.
+
+Arguments:
+
+
+Notes:
+
+
+--*/
+
+{
+
+ PELNK3_ADAPTER pAdapter=TransDataContext->pAdapter;
+ ULONG RcvStatus;
+ ULONG Sum;
+ ULONG FreeBytes;
+
+ RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus);
+
+ if (!(RcvStatus & RX_STATUS_INCOMPLETE)) {
+ //
+ // It's completed now
+ //
+ return FALSE;
+ }
+
+ ELNK3_SELECT_WINDOW(pAdapter,WNO_FIFO);
+
+ FreeBytes=ELNK3_READ_PORT_USHORT(pAdapter,PORT_FREE_RX_BYTES);
+
+ ELNK3_SELECT_WINDOW(pAdapter,WNO_OPERATING);
+
+ Sum=(BYTES_IN_FIFO(RcvStatus) + FreeBytes);
+
+#if DBG
+ if ((Sum + 90 < pAdapter->RxFifoSize)
+ ||
+ ((pAdapter->RxFifoSize==FreeBytes) && (BYTES_IN_FIFO(RcvStatus)!=0))) {
+
+ IF_LOUD(DbgPrint("ELNK3: RX fifo problem used=%d free=%d size=%d\n",RcvStatus & 0x7ff,FreeBytes, pAdapter->RxFifoSize);)
+ }
+#endif
+
+ return ((Sum + 90 < pAdapter->RxFifoSize)
+ ||
+ ((pAdapter->RxFifoSize==FreeBytes) && (BYTES_IN_FIFO(RcvStatus)!=0)));
+
+
+
+
+}
+
+
+NDIS_STATUS
+Elnk3TransferData(
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+ )
+
+/*++
+
+Routine Description:
+
+ NDIS function.
+
+Arguments:
+
+ see NDIS 3.0 spec.
+
+Notes:
+
+ The receive context is a pointer to a structure that describes the packet
+
+--*/
+
+{
+ UINT BytesLeft, BytesNow, BytesWanted;
+ PNDIS_BUFFER CurBuffer;
+ PUCHAR BufStart;
+ UINT BufLen;
+ ULONG DataAvailible;
+
+ PUCHAR pBuffer;
+
+
+ PTRANSFERDATA_CONTEXT TransDataContext= ((PTRANSFERDATA_CONTEXT)MacReceiveContext);
+ PELNK3_ADAPTER pAdapter = MacBindingHandle;
+
+
+
+ IF_LOG(0xDD,0xdd,TransDataContext->PacketLength);
+
+ IF_RCV_LOUD(DbgPrint("Elnk3: Transferdata: bo=%d bt=%d\n",ByteOffset, BytesToTransfer);)
+
+ DEBUG_STAT(pAdapter->Stats.TransferDataCount);
+
+
+
+ if (ByteOffset+BytesToTransfer > TransDataContext->PacketLength) {
+ //
+ // Adjust the amount of data the protocol wants
+ //
+
+ IF_LOUD(DbgPrint("Elnk3: TD() Protocol asked for too much data bo=%d btt=%d pl=%d Da=%d\n",
+ ByteOffset,
+ BytesToTransfer,
+ TransDataContext->PacketLength
+ );)
+
+ if (TransDataContext->PacketLength > ByteOffset) {
+
+ BytesToTransfer = TransDataContext->PacketLength - ByteOffset;
+
+ } else {
+ //
+ // the offset is past the packet length, bad protocol bad
+ //
+ *BytesTransferred = 0;
+
+ return NDIS_STATUS_SUCCESS;
+
+ }
+ }
+
+ DataAvailible=TransDataContext->BytesAlreadyRead;
+
+ if (DataAvailible < (TransDataContext->PacketLength+ELNK3_ETHERNET_HEADER_SIZE)) {
+ //
+ // We haven't read all of the data out of the fifo yet, so
+ // let our transfer data completetion handler do it
+ //
+ // See how much data there is to transfer.
+ //
+
+ PACKET_RESERVED(Packet)->u.TransData.ByteOffset = ByteOffset;
+ PACKET_RESERVED(Packet)->u.TransData.BytesToTransfer = BytesToTransfer;
+
+ PACKET_RESERVED(Packet)->Next=TransDataContext->Stack;
+
+ TransDataContext->Stack=Packet;
+
+ return NDIS_STATUS_PENDING;
+
+ }
+
+ //
+ // The whole packet fit in the lookahead data, so copy it out
+ // right now
+ //
+
+
+
+
+ BytesWanted = BytesToTransfer;
+
+ IF_RCV_LOUD(DbgPrint("TD: bo=%d bt=%d ps=%d\n",ByteOffset, BytesToTransfer, TransDataContext->PacketLength);)
+
+
+
+ BytesLeft = BytesWanted;
+
+ //
+ // Get a pointer to the begining of the data to be copied.
+ // The 14 byte header is handled by lookahead element
+ //
+ pBuffer=TransDataContext->LookAhead->LookAheadData+ByteOffset;
+
+ NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, NULL);
+
+ if (BytesLeft > 0) {
+
+ while (1) {
+
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufStart, &BufLen);
+
+ //
+ // See how much data to read into this buffer.
+ //
+
+ BytesNow= BufLen < BytesLeft ? BufLen : BytesLeft;
+
+ NdisMoveMemory(
+ BufStart,
+ pBuffer,
+ BytesNow
+ );
+
+
+ pBuffer += BytesNow;
+
+ BytesLeft -= BytesNow;
+
+
+ //
+ // Is the transfer done now?
+ //
+
+ if (BytesLeft == 0) {
+
+ break;
+ }
+
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+
+ if (CurBuffer == (PNDIS_BUFFER)NULL) {
+
+ break;
+ }
+ }
+ }
+
+ *BytesTransferred = BytesWanted - BytesLeft;
+
+ return NDIS_STATUS_SUCCESS;
+
+}
+
+
+
+
+
+
+BOOLEAN
+Elnk3EarlyReceive(
+ PELNK3_ADAPTER pAdapter
+ )
+/*++
+
+ Routine Description:
+ This routine Indicates all of the packets in the ring one at a time
+
+ Arguments:
+
+
+ Return Value:
+
+--*/
+
+{
+
+ ULONG PacketLength;
+ USHORT RcvStatus;
+ ULONG DataAvailible;
+ UINT PossibleLength;
+
+
+ PTRANSFERDATA_CONTEXT TransDataContext= &pAdapter->TransContext[0];
+
+
+ DataAvailible=TransDataContext->BytesAlreadyRead;
+
+
+ if (DataAvailible == 0) {
+
+ //
+ // First early receive get the lookahead and set the second early receive
+ //
+ // With any luck the packet will complete and the packet complete
+ // interrupt will mask the this early receive thus reducing the effective
+ // delay in processing the interrupt
+ //
+ // If not then this routine will run again and kill some time reading
+ // in data from the card. This should happen to often and when it
+ // does we should not have missed by much. The data that we do copy
+ // will most likely be used any way so not much will be lost.
+ //
+
+ RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus);
+
+ PacketLength=BYTES_IN_FIFO_DW(RcvStatus);
+
+
+ NdisRawReadPortBufferUlong(
+ pAdapter->PortOffsets[PORT_RxFIFO],
+ (PULONG)((PUCHAR)TransDataContext->LookAhead+DataAvailible),
+ (PacketLength >> 2)
+ );
+
+ TransDataContext->BytesAlreadyRead += PacketLength;
+
+
+
+ IF_LOG(0xee,0x01,PacketLength);
+
+
+ PossibleLength=Elnk3GuessFrameSize(TransDataContext->LookAhead,
+ TransDataContext->BytesAlreadyRead);
+
+
+ IF_RCV_LOUD(DbgPrint("Elnk3: Possible length is %d\n",PossibleLength);)
+
+
+
+ if (PossibleLength-pAdapter->RxMinimumThreshold > (UINT)pAdapter->LatencyAdjustment) {
+
+ ELNK3_COMMAND(pAdapter,EC_SET_RX_EARLY, ((PossibleLength)-pAdapter->LatencyAdjustment) & 0x7ff);
+ IF_LOG(0xef,0x01,((PossibleLength)-pAdapter->LatencyAdjustment) & 0x7ff);
+ }
+
+
+ RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus);
+
+ if (!(RcvStatus & RX_STATUS_INCOMPLETE)) {
+ //
+ // The packet completed while we were reading it in
+ //
+ Elnk3IndicatePackets(pAdapter);
+ }
+
+ } else {
+
+ RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus);
+
+ IF_LOG(0xee,0x02,BYTES_IN_FIFO(RcvStatus));
+
+ //
+ // Second early receive, Copy data until it completes
+ // and then call indicatepackets
+ //
+ while ((RcvStatus & RX_STATUS_INCOMPLETE) && !(RcvStatus & RX_STATUS_ERROR)) {
+
+ IF_LOG(0xee,0x03,RcvStatus & 0xc7fc);
+
+ if (BYTES_IN_FIFO_DW(RcvStatus) >= 32) {
+
+ NdisRawReadPortBufferUlong(
+ pAdapter->PortOffsets[PORT_RxFIFO],
+ (PULONG)((PUCHAR)TransDataContext->LookAhead+TransDataContext->BytesAlreadyRead),
+ 32 >> 2
+ );
+
+ TransDataContext->BytesAlreadyRead += 32;
+ }
+
+ RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus);
+ }
+
+ Elnk3IndicatePackets(pAdapter);
+
+
+ DEBUG_STAT(pAdapter->Stats.SecondEarlyReceive);
+ }
+
+ return TRUE;
+
+}
+
+
+BOOLEAN
+Elnk3IndicatePackets(
+ PELNK3_ADAPTER pAdapter
+ )
+/*++
+
+ Routine Description:
+ This routine Indicates all of the packets in the ring one at a time
+
+ Arguments:
+
+
+ Return Value:
+
+--*/
+
+{
+
+ ULONG LookAheadSize;
+ USHORT RcvStatus;
+ ULONG DataAvailible;
+ ULONG AdditionalData;
+ ULONG GoodReceives=0;
+ ULONG BadReceives=0;
+ ULONG PossibleLength;
+
+
+
+ PTRANSFERDATA_CONTEXT TransDataContext= &pAdapter->TransContext[0];
+
+
+ RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus);
+
+ IF_LOG(0xdc,0xdc,RcvStatus & 0xc7ff);
+
+ IF_RCV_LOUD(DbgPrint("ELNK3: IndicatePackets RX status=%04x\n",RcvStatus);)
+
+
+ do {
+
+ while (!(RcvStatus & RX_STATUS_INCOMPLETE)) {
+
+ if (!(RcvStatus & RX_STATUS_ERROR)) {
+
+ TransDataContext->PacketLength=BYTES_IN_FIFO(RcvStatus);
+
+ DataAvailible=TransDataContext->BytesAlreadyRead;
+
+ TransDataContext->PacketLength+=DataAvailible;
+
+ IF_LOG(0xdc,0x01,TransDataContext->PacketLength);
+
+ if ((TransDataContext->PacketLength<=1514) &&
+ (TransDataContext->PacketLength >= 14)) {
+
+ //
+ // The packet seems to be OK
+ // Subtract the header length(14) from the packet length
+ //
+
+ TransDataContext->PacketLength-=ELNK3_ETHERNET_HEADER_SIZE;
+
+ //
+ // Lookahead is the smaller of Packetsize and the current lookahead size
+ //
+ LookAheadSize=TransDataContext->PacketLength < pAdapter->MaxLookAhead ?
+ TransDataContext->PacketLength : pAdapter->MaxLookAhead;
+
+
+ if (LookAheadSize+ELNK3_ETHERNET_HEADER_SIZE > DataAvailible) {
+ //
+ // We did not get an early receive for this packet.
+ // Most likly it is a small packet that is less than our threshold.
+ // Or the latency is too great
+ //
+ AdditionalData=ELNK3_ROUND_TO_DWORD(LookAheadSize+ELNK3_ETHERNET_HEADER_SIZE)-DataAvailible;
+
+ IF_LOG(0xad,0x01,AdditionalData);
+
+ NdisRawReadPortBufferUlong(
+ pAdapter->PortOffsets[PORT_RxFIFO],
+ (PULONG)(((PUCHAR)TransDataContext->LookAhead)+DataAvailible),
+ (AdditionalData>>2)
+ );
+
+ IF_RCV_LOUD(DbgPrint("Elnk3: Indicate: Da=%d Ad=%d\n",DataAvailible, AdditionalData);)
+
+ TransDataContext->BytesAlreadyRead+=AdditionalData;
+
+ } else {
+ //
+ // The lookahead data is waiting for us, so just go ahead and indicate.
+ //
+ DEBUG_STAT(pAdapter->Stats.IndicateWithDataReady);
+
+ }
+
+
+ GoodReceives++;
+
+ IF_RCV_LOUD(DbgPrint("Elnk3: Indicate: ls=%d pl=%d\n", LookAheadSize, TransDataContext->PacketLength);)
+
+ TransDataContext->Stack=NULL;
+
+ NdisMEthIndicateReceive(
+ pAdapter->NdisAdapterHandle,
+ TransDataContext,
+ (PUCHAR)&TransDataContext->LookAhead->EthHeader,
+ ELNK3_ETHERNET_HEADER_SIZE,
+ TransDataContext->LookAhead->LookAheadData,
+ LookAheadSize,
+ TransDataContext->PacketLength
+ );
+
+ DEBUG_STAT(pAdapter->Stats.PacketIndicated);
+
+ if (TransDataContext->Stack!=NULL) {
+ //
+ // at least one protocol called transferdata
+ //
+ Elnk3TransferDataCompletion(
+ TransDataContext
+ );
+
+ }
+
+
+
+ } else {
+
+ IF_RCV_LOUD(DbgPrint("ELNK3: (Packet>1514) || (error in packet) -> not idicated\n");)
+
+ }
+
+ } else {
+
+ IF_RCV_LOUD(DbgPrint("ELNK3: IndicatePackets: error %04x\n", RcvStatus & 0xf800);)
+ IF_LOG(0xff,0xff,0xffff);
+
+ DEBUG_STAT(pAdapter->Stats.BadReceives);
+
+ }
+
+ Elnk3DiscardPacketSync(TransDataContext);
+
+ pAdapter->FramesRcvGood+=GoodReceives;
+
+
+ TransDataContext->BytesAlreadyRead=0;
+
+
+ RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus);
+
+ } // while complete
+
+
+ DEBUG_STAT(pAdapter->Stats.IndicationCompleted);
+
+ NdisMEthIndicateReceiveComplete(pAdapter->NdisAdapterHandle);
+
+ RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus);
+
+ //
+ // See if there is a lookahead's worth of data from the next yet
+ //
+ if ( BYTES_IN_FIFO_DW(RcvStatus) > pAdapter->EarlyReceiveThreshold) {
+
+ if ( BYTES_IN_FIFO_DW(RcvStatus) > 1200 && (RcvStatus & RX_STATUS_INCOMPLETE)) {
+ //
+ // There is alot of data in the fifo, but the packet has not completed yet.
+ // In order to try to prevent an over flow, lets empty now
+ //
+ IF_LOG(0xdc,0xeb,RcvStatus & 0xc7fc);
+
+ NdisRawReadPortBufferUlong(
+ pAdapter->PortOffsets[PORT_RxFIFO],
+ (PULONG)((PUCHAR)TransDataContext->LookAhead+TransDataContext->BytesAlreadyRead),
+ BYTES_IN_FIFO_DW(RcvStatus) >> 2
+ );
+
+ TransDataContext->BytesAlreadyRead += BYTES_IN_FIFO_DW(RcvStatus);
+
+ } else {
+
+ IF_LOG(0xdc,0xea,RcvStatus & 0xc7fc);
+
+ NdisRawReadPortBufferUlong(
+ pAdapter->PortOffsets[PORT_RxFIFO],
+ (PULONG)((PUCHAR)TransDataContext->LookAhead+TransDataContext->BytesAlreadyRead),
+ pAdapter->EarlyReceiveThreshold >> 2
+ );
+
+ TransDataContext->BytesAlreadyRead += pAdapter->EarlyReceiveThreshold;
+ }
+
+ }
+
+ //
+ // In the time it took to port i/o in the lookahead data the packet may
+ // have completed
+ //
+
+ } while (!(RcvStatus & RX_STATUS_INCOMPLETE));
+
+
+
+ //
+ // At this point there is either 0 or EarlyReceiveThreshold bytes in the buffer
+ //
+
+ if (TransDataContext->BytesAlreadyRead > 16) {
+
+ PossibleLength=Elnk3GuessFrameSize(TransDataContext->LookAhead,
+ TransDataContext->BytesAlreadyRead);
+
+ IF_RCV_LOUD(DbgPrint("Elnk3: Possible length is %d\n",PossibleLength);)
+
+ if (PossibleLength > pAdapter->LatencyAdjustment) {
+ //
+ // There is enough time to set the threshold before
+ // the packet passes the new threshold
+ //
+
+ IF_LOG(0xef,0x02,((PossibleLength)-pAdapter->LatencyAdjustment) & 0x7ff);
+ ELNK3_COMMAND(pAdapter,EC_SET_RX_EARLY, ((PossibleLength)-pAdapter->LatencyAdjustment) & 0x7fc);
+
+ }
+
+
+ } else {
+ //
+ // Set rx early to catch the front of the packet
+ //
+ IF_LOG(0xef,0x02,(pAdapter->LookAheadLatencyAdjustment));
+ ELNK3_COMMAND(pAdapter,EC_SET_RX_EARLY, (pAdapter->LookAheadLatencyAdjustment) );
+ }
+
+
+
+
+#if DBG
+
+ RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus);
+
+ IF_LOG(0xdc,0xdd,RcvStatus & 0xc7ff);
+#endif
+
+
+ return TRUE;
+}
+
+
+
+
+
+
+ULONG
+Elnk3GuessFrameSize(
+ IN PNIC_RCV_HEADER Frame,
+ IN ULONG BytesNow
+ )
+/*++
+
+ Routine Description:
+
+ This rountine endevers to determine the size of the packet
+ from the packet header.
+
+ This scheme was borrowed from 3com's ndis 2 driver
+
+ Arguments:
+
+
+ Return Value:
+
+--*/
+
+{
+
+ ULONG PossibleLength;
+
+
+ PossibleLength=(Frame->EthHeader.EthLength[0]<<8)+
+ Frame->EthHeader.EthLength[1];
+
+
+ //
+ // Is it 802.3
+ //
+ if (PossibleLength < 0x600 ) {
+ //
+ // Looks to an 802.3 frame
+ //
+ return (PossibleLength+14);
+ }
+
+ //
+ // Xns, IP, IPX ?
+ //
+
+ if (PossibleLength==XNS_FRAME_TYPE ||
+ PossibleLength==IP_FRAME_TYPE ||
+ PossibleLength==IPX_FRAME_TYPE ) {
+
+ PossibleLength=(Frame->LookAheadData[2]<<8)+
+ Frame->LookAheadData[3]+14;
+
+ } else {
+ //
+ // Not one we recognise
+ //
+ return 1514;
+ }
+
+
+ if (PossibleLength<=1514 && PossibleLength>=BytesNow) {
+ //
+ // Looks reasonable
+ //
+ return PossibleLength;
+
+ } else {
+ //
+ // Don't look like we got the length, just go with max
+ //
+ return 1514;
+ }
+
+
+}
+
+
+
+VOID
+Elnk3DiscardIfBroadcast(
+ IN PELNK3_ADAPTER pAdapter,
+ IN PTRANSFERDATA_CONTEXT TransDataContext
+ )
+
+{
+ USHORT RcvStatus;
+
+
+ RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus);
+
+ while (BYTES_IN_FIFO_DW(RcvStatus) > 8) {
+
+ IF_LOG(0xaf,0xff,BYTES_IN_FIFO_DW(RcvStatus));
+
+#if DBG
+ if (TransDataContext->BytesAlreadyRead != 0) {
+ DbgPrint("Elnk3: FindNextPacket called with BytesAlreadyRead != 0\n");
+ DbgBreakPoint();
+ }
+#endif
+
+ NdisRawReadPortBufferUlong(
+ pAdapter->PortOffsets[PORT_RxFIFO],
+ (PULONG)((PUCHAR)TransDataContext->LookAhead),
+ (8 >> 2)
+ );
+
+ TransDataContext->BytesAlreadyRead = 8;
+
+ if (ETH_IS_BROADCAST(&TransDataContext->LookAhead->EthHeader.Destination[0])) {
+
+ //
+ // We don't want this one so, we discard it now
+ //
+
+ Elnk3DiscardPacketSync(TransDataContext);
+
+
+ DEBUG_STAT(pAdapter->Stats.BroadcastsRejected);
+
+
+ //
+ // No bytes anymore
+ //
+ TransDataContext->BytesAlreadyRead = 0;
+
+ //
+ // we chucked it, see what the next one holds in store for us
+ //
+ RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus);
+
+ continue;
+
+ }
+
+
+ //
+ // We need to indicate it
+ //
+
+ break;
+
+ }
+}
+
+
+
+
+
+VOID
+Elnk3TransferDataCompletion(
+ PTRANSFERDATA_CONTEXT TransDataContext
+ )
+
+{
+
+ PELNK3_ADAPTER pAdapter;
+ PNDIS_PACKET Packet;
+ PNDIS_BUFFER CurBuffer;
+ PUCHAR BufferAddress;
+ ULONG BufferLength;
+ ULONG DataAvailible;
+ ULONG OffsetInLookAhead;
+ ULONG BytesLeft;
+ ULONG BytesNow;
+ ULONG ByteOffset;
+ ULONG BytesToTransfer;
+ ULONG AdditionalData;
+
+
+
+ pAdapter=TransDataContext->pAdapter;
+ //
+ // See if more than one binding called transferdata
+ //
+ if (PACKET_RESERVED(TransDataContext->Stack)->Next==NULL) {
+ //
+ // just one, just port io into the ndis buffer
+ //
+ IF_RCV_LOUD(DbgPrint("Elnk3: TransComp: One transferdata call\n");)
+
+ Packet=TransDataContext->Stack;
+
+
+ //
+ // See just what this protocol wants
+ //
+ BytesToTransfer = PACKET_RESERVED(Packet)->u.TransData.BytesToTransfer;
+
+ ByteOffset = PACKET_RESERVED(Packet)->u.TransData.ByteOffset;
+
+ IF_RCV_LOUD(DbgPrint("Elnk3: TransComp: bo=%d bt=%d\n",ByteOffset,BytesToTransfer);)
+
+
+
+
+ BytesLeft=BytesToTransfer;
+
+ OffsetInLookAhead=ByteOffset+ELNK3_ETHERNET_HEADER_SIZE;
+
+ NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, NULL);
+
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufferAddress, &BufferLength);
+
+ DataAvailible=TransDataContext->BytesAlreadyRead;
+
+ IF_RCV_LOUD(DbgPrint("Elnk3: TransComp: DataAvailible=%d offset=%d\n",DataAvailible,OffsetInLookAhead);)
+
+ //
+ // copy the data out of the lookahead buffer
+ //
+ // Note, that this loop assumes that whole packet does not fit
+ // in the lookahead data. If it does TransferData does not pend
+ // and this routine is not called. This is a problem because
+ // we read data out of the fifo in multiples of dwords and we
+ // get padding bytes in our data availible count
+ //
+
+ if (OffsetInLookAhead > DataAvailible) {
+ //
+ // The byte offset is past the lookahead data.
+ // We need to port some more stuff out of the fifo
+ // to get to where the data is that we want
+ //
+
+ NdisRawReadPortBufferUchar(
+ pAdapter->PortOffsets[PORT_RxFIFO],
+ (PUCHAR)((PUCHAR)TransDataContext->LookAhead+TransDataContext->BytesAlreadyRead),
+ OffsetInLookAhead - DataAvailible
+ );
+
+ TransDataContext->BytesAlreadyRead+=(OffsetInLookAhead - DataAvailible);
+
+ } else {
+ //
+ // the byteoffset is with in the lookahead data
+ // copy it to the ndis buffer
+ //
+
+
+ while (OffsetInLookAhead < DataAvailible) {
+ //
+ // Need to copy some of lookeahead into protocol packet
+ //
+
+ BytesNow= BufferLength < (DataAvailible-OffsetInLookAhead) ?
+ BufferLength : (DataAvailible-OffsetInLookAhead);
+
+ IF_RCV_LOUD(DbgPrint("Elnk3: TransComp: lookahead bn=%d offset=%d\n",BytesNow,OffsetInLookAhead);)
+
+
+ NdisMoveMemory(
+ BufferAddress,
+ (PUCHAR)TransDataContext->LookAhead+OffsetInLookAhead,
+ BytesNow
+ );
+
+ BytesLeft-=BytesNow;
+
+ OffsetInLookAhead+=BytesNow;
+
+ BufferAddress+=BytesNow;
+
+ BufferLength-=BytesNow;
+
+ if (BufferLength==0) {
+
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+
+ if (CurBuffer==NULL) {
+
+ break;
+ }
+
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufferAddress, &BufferLength);
+ }
+
+ }
+ }
+
+ //
+ // port i/o in the rest of the packet into the protocols packet
+ //
+
+ while (BytesLeft > 0) {
+
+ BytesNow= BufferLength < BytesLeft ?
+ BufferLength : BytesLeft;
+
+ IF_RCV_LOUD(DbgPrint("Elnk3: TransComp: bl=%d bn=%d\n",BytesLeft,BytesNow);)
+ IF_LOG(0xad,0xd1,BytesNow);
+
+ NdisRawReadPortBufferUlong(
+ pAdapter->PortOffsets[PORT_RxFIFO],
+ (PULONG)BufferAddress,
+ BytesNow>>2
+ );
+
+ if (BytesNow & 3) {
+
+ NdisRawReadPortBufferUchar(
+ pAdapter->PortOffsets[PORT_RxFIFO],
+ (PUCHAR)((PUCHAR)BufferAddress+(BytesNow & 0xfffffffc)),
+ BytesNow & 3
+ );
+ }
+
+ BytesLeft-=BytesNow;
+
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+
+ if (CurBuffer == NULL) {
+
+ break;
+ }
+
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufferAddress, &BufferLength);
+
+ }
+
+
+ NdisMTransferDataComplete(
+ pAdapter->NdisAdapterHandle,
+ Packet,
+ NDIS_STATUS_SUCCESS,
+ BytesToTransfer
+ );
+
+
+
+
+ return ;
+ }
+
+
+ //
+ // More than one protocol wants the packet.
+ // We will port i/o the whole thing to one of our buffers
+ // and then copy the data into the protocols packets
+ //
+
+ IF_RCV_LOUD(DbgPrint("Elnk3: TransComp: Multiple transferdata calls\n");)
+
+ while ((Packet=TransDataContext->Stack) != NULL) {
+
+ TransDataContext->Stack=PACKET_RESERVED(Packet)->Next;
+
+ //
+ // See just what this protocol wants
+ //
+ BytesToTransfer = PACKET_RESERVED(Packet)->u.TransData.BytesToTransfer;
+
+ ByteOffset = PACKET_RESERVED(Packet)->u.TransData.ByteOffset;
+
+ IF_RCV_LOUD(DbgPrint("Elnk3: TransComp: bo=%d bt=%d\n",ByteOffset,BytesToTransfer);)
+
+
+ IF_RCV_LOUD(DbgPrint("TD: bo=%d bt=%d ps=%d\n",ByteOffset, BytesToTransfer, TransDataContext->PacketLength);)
+
+
+ //
+ // We got this much so far
+ //
+ DataAvailible=TransDataContext->BytesAlreadyRead;
+
+
+ //
+ // See if the whole thing has been removed from the fifo
+ //
+ if (DataAvailible < (TransDataContext->PacketLength+ELNK3_ETHERNET_HEADER_SIZE)) {
+ //
+ // Get the rest of the data from the fifo
+ //
+
+ AdditionalData=ELNK3_ROUND_TO_DWORD((TransDataContext->PacketLength+ELNK3_ETHERNET_HEADER_SIZE)-DataAvailible);
+
+ NdisRawReadPortBufferUlong(
+ pAdapter->PortOffsets[PORT_RxFIFO],
+ (PULONG)((PUCHAR)TransDataContext->LookAhead+DataAvailible),
+ AdditionalData>>2
+ );
+
+ IF_LOG(0xad,0x02,AdditionalData);
+
+ IF_RCV_LOUD(DbgPrint("Elnk3: TransComp: Da=%d Ad=%d\n",DataAvailible, AdditionalData);)
+
+ TransDataContext->BytesAlreadyRead+=AdditionalData;
+
+ }
+
+
+
+ BytesLeft = BytesToTransfer;
+
+
+ OffsetInLookAhead=ByteOffset;
+
+
+ NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, NULL);
+
+ while (BytesLeft > 0) {
+
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufferAddress, &BufferLength);
+
+ //
+ // See how much data to read into this buffer.
+ //
+
+ BytesNow= BufferLength < BytesLeft ? BufferLength : BytesLeft;
+
+ //
+ // Note: the LookAheadData element of the structure handles the
+ // 14 byte header discrepency
+ //
+ NdisMoveMemory(
+ BufferAddress,
+ TransDataContext->LookAhead->LookAheadData+OffsetInLookAhead,
+ BytesNow
+ );
+
+
+ OffsetInLookAhead += BytesNow;
+
+ BytesLeft -= BytesNow;
+
+
+ //
+ // Is the transfer done now?
+ //
+
+ if (BytesLeft == 0) {
+
+ break;
+ }
+
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+
+ if (CurBuffer == (PNDIS_BUFFER)NULL) {
+
+ break;
+ }
+
+ }
+
+
+
+ NdisMTransferDataComplete(
+ pAdapter->NdisAdapterHandle,
+ Packet,
+ NDIS_STATUS_SUCCESS,
+ BytesToTransfer
+ );
+
+
+
+
+
+ } // while packets
+
+
+
+
+ return;
+
+}
diff --git a/private/ntos/ndis/elnk3/request.c b/private/ntos/ndis/elnk3/request.c
new file mode 100644
index 000000000..a267b3da9
--- /dev/null
+++ b/private/ntos/ndis/elnk3/request.c
@@ -0,0 +1,839 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ request.c
+
+Abstract:
+
+ Ndis 3.0 MAC driver for the 3Com Etherlink III
+
+ This file handles NdisRequest. The module was for the most part extracted
+ from the elnkii driver
+
+Author:
+
+ Brian Lieuallen (BrianLie) 07/02/92
+
+Environment:
+
+ Kernel Mode Operating Systems : NT
+
+Revision History:
+
+ Portions borrowed from ELNK3 driver by
+ Earle R. Horton (EarleH)
+
+
+--*/
+
+
+
+
+
+#include <ndis.h>
+//#include <efilter.h>
+
+#include "debug.h"
+
+
+#include "elnk3hrd.h"
+#include "elnk3sft.h"
+#include "elnk3.h"
+
+
+
+
+
+
+NDIS_STATUS
+Elnk3FilterChangeAction(
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+
+
+
+
+//
+// If you add to this, make sure to add the
+// a case in Elnk3FillInGlobalData() and in
+// Elnk3QueryGlobalStatistics() if global
+// information only or
+// Elnk3QueryProtocolStatistics() if it is
+// protocol queriable information.
+//
+STATIC UINT Elnk3GlobalSupportedOids[] = {
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ OID_802_3_RCV_ERROR_ALIGNMENT,
+ OID_802_3_XMIT_ONE_COLLISION,
+ OID_802_3_XMIT_MORE_COLLISIONS
+ };
+
+
+
+
+
+
+NDIS_STATUS
+Elnk3QueryInformation(
+ IN NDIS_HANDLE MiniportContext,
+ IN NDIS_OID Oid,
+ IN PVOID InfoBuffer,
+ IN ULONG BytesLeft,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+ )
+
+/*++
+
+Routine Description:
+
+ The Elnk3QueryProtocolInformation process a Query request for
+ NDIS_OIDs that are specific to a binding about the MAC. Note that
+ some of the OIDs that are specific to bindings are also queryable
+ on a global basis. Rather than recreate this code to handle the
+ global queries, I use a flag to indicate if this is a query for the
+ global data or the binding specific data.
+
+Arguments:
+
+ Adapter - a pointer to the adapter.
+
+ Oid - the NDIS_OID to process.
+
+ PlaceInInfoBuffer - a pointer into the NdisRequest->InformationBuffer
+ into which store the result of the query.
+
+ BytesLeft - the number of bytes left in the InformationBuffer.
+
+ BytesNeeded - If there is not enough room in the information buffer
+ then this will contain the number of bytes needed to complete the
+ request.
+
+ BytesWritten - a pointer to the number of bytes written into the
+ InformationBuffer.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NDIS_MEDIUM Medium = NdisMedium802_3;
+ ULONG GenericULong = 0;
+ USHORT GenericUShort = 0;
+ UCHAR GenericArray[6];
+
+ PELNK3_ADAPTER pAdapter=MiniportContext;
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ //
+ // Common variables for pointing to result of query
+ //
+
+ PVOID MoveSource;
+ ULONG MoveBytes;
+
+ NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady;
+
+ //
+ // General Algorithm:
+ //
+ // Switch(Request)
+ // Get requested information
+ // Store results in a common variable.
+ // Copy result in common variable to result buffer.
+ //
+
+ //
+ // Make sure that ulong is 4 bytes. Else GenericULong must change
+ // to something of size 4.
+ //
+ ASSERT(sizeof(ULONG) == 4);
+
+ MoveSource = (PVOID)(&GenericULong);
+ MoveBytes = sizeof(GenericULong);
+
+
+
+ IF_REQ_LOUD(DbgPrint("ELNK3: QueryProtocol %08lx\n",Oid);)
+
+
+ //
+ // Switch on request type
+ //
+
+ switch (Oid) {
+
+ case OID_GEN_MAC_OPTIONS:
+
+ if (pAdapter->ReceiveMethod==1) {
+
+ GenericULong = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
+ NDIS_MAC_OPTION_NO_LOOPBACK ;
+
+ } else {
+
+ GenericULong = ( NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
+ NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
+ NDIS_MAC_OPTION_NO_LOOPBACK);
+ }
+
+
+ break;
+
+ case OID_GEN_SUPPORTED_LIST:
+
+
+ MoveSource = (PVOID)(Elnk3GlobalSupportedOids);
+ MoveBytes = sizeof(Elnk3GlobalSupportedOids);
+
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+
+ HardwareStatus = NdisHardwareStatusReady;
+
+
+ MoveSource = (PVOID)(&HardwareStatus);
+ MoveBytes = sizeof(NDIS_HARDWARE_STATUS);
+
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+
+ MoveSource = (PVOID) (&Medium);
+ MoveBytes = sizeof(NDIS_MEDIUM);
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+
+ GenericULong = ELNK3_MAX_LOOKAHEAD_SIZE;
+
+ break;
+
+
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+
+ GenericULong = (ULONG)(1514 - 14);
+
+ break;
+
+
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+
+ GenericULong = (ULONG)(1514);
+ break;
+
+
+ case OID_GEN_LINK_SPEED:
+
+ GenericULong = (ULONG)(100000);
+ break;
+
+
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+
+ GenericULong = 2048;
+ break;
+
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+
+ GenericULong = 2048;
+ break;
+
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+
+ GenericULong = 1514;
+
+ break;
+
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+
+ GenericULong = 1514;
+ break;
+
+ case OID_GEN_VENDOR_ID:
+
+ NdisMoveMemory(
+ (PVOID)&GenericULong,
+ pAdapter->PermanentAddress,
+ 3
+ );
+ GenericULong &= 0xFFFFFF00;
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+
+ MoveSource = (PVOID)"ELNK3 Ethernet Adapter.";
+ MoveBytes = 24;
+
+ break;
+
+ case OID_GEN_DRIVER_VERSION:
+
+ GenericUShort = ((USHORT)ELNK3_NDIS_MAJOR_VERSION << 8) |
+ ELNK3_NDIS_MINOR_VERSION;
+
+ MoveSource = (PVOID)(&GenericUShort);
+ MoveBytes = sizeof(GenericUShort);
+ break;
+
+
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+
+ GenericULong = (ULONG)(pAdapter->MaxLookAhead);
+
+
+
+ IF_REQ_LOUD(DbgPrint("Querying LookAhead: %d\n,GenericULong");)
+
+ break;
+
+ case OID_802_3_PERMANENT_ADDRESS:
+
+ IF_REQ_LOUD(DbgPrint("Querying Permanent address\n");)
+
+ NdisMoveMemory((PCHAR)GenericArray,
+ pAdapter->PermanentAddress,
+ ELNK3_LENGTH_OF_ADDRESS);
+
+ MoveSource = (PVOID)(GenericArray);
+ MoveBytes = sizeof(pAdapter->PermanentAddress);
+ break;
+
+
+ case OID_802_3_CURRENT_ADDRESS:
+
+ IF_REQ_LOUD(DbgPrint("Querying Current address\n");)
+
+ NdisMoveMemory(
+ (PCHAR)GenericArray,
+ pAdapter->StationAddress,
+ ELNK3_LENGTH_OF_ADDRESS
+ );
+
+ MoveSource = (PVOID)(GenericArray);
+ MoveBytes = sizeof(pAdapter->StationAddress);
+ break;
+
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+
+ GenericULong = (ULONG) DEFAULT_MULTICAST_SIZE;
+
+ break;
+
+ case OID_GEN_XMIT_OK:
+
+ GenericULong = pAdapter->FramesXmitGood;
+
+ break;
+
+ case OID_GEN_RCV_OK:
+
+ GenericULong = pAdapter->FramesRcvGood;
+
+ break;
+
+ case OID_GEN_XMIT_ERROR:
+
+ GenericULong = pAdapter->FramesXmitBad;
+
+ break;
+
+ case OID_GEN_RCV_ERROR:
+
+ GenericULong = pAdapter->CrcErrors;
+
+ break;
+
+ case OID_GEN_RCV_NO_BUFFER:
+
+ GenericULong = (UINT)(pAdapter->MissedPackets);
+
+ break;
+
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+
+ GenericULong = (UINT)pAdapter->FrameAlignmentErrors;
+
+ break;
+
+ case OID_802_3_XMIT_ONE_COLLISION:
+
+ GenericULong = (UINT)pAdapter->FramesXmitOneCollision;
+
+ break;
+
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+
+ GenericULong = (UINT)pAdapter->FramesXmitManyCollisions;
+
+ break;
+
+
+
+ default:
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if ((StatusToReturn == NDIS_STATUS_SUCCESS) &&
+ (Oid != OID_802_3_MULTICAST_LIST)) {
+
+ if (MoveBytes > BytesLeft) {
+
+ //
+ // Not enough room in InformationBuffer. Punt
+ //
+
+ *BytesNeeded = MoveBytes;
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ } else {
+
+ //
+ // Store result.
+ //
+
+ NdisMoveMemory(InfoBuffer, MoveSource, MoveBytes);
+
+ (*BytesWritten) = MoveBytes;
+
+ }
+ }
+
+
+#if DBG
+
+ if (StatusToReturn != NDIS_STATUS_SUCCESS) {
+
+ IF_REQ_LOUD(DbgPrint("Out QueryInfo oid=%08lx failed\n",Oid);)
+ }
+#endif
+
+
+ IF_VERY_LOUD( DbgPrint("Out QueryProtocol\n");)
+
+ return StatusToReturn;
+
+}
+
+
+NDIS_STATUS
+Elnk3SetInformation(
+ IN NDIS_HANDLE MiniportContext,
+ IN NDIS_OID Oid,
+ IN PVOID InfoBuffer,
+ IN ULONG BytesLeft,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ )
+
+/*++
+
+Routine Description:
+
+ The Elnk3SetInformation is used by Elnk3Request to set information
+ about the MAC.
+
+Arguments:
+
+ Adapter - A pointer to the adapter.
+
+ Open - A pointer to an open instance.
+
+ NdisRequest - A structure which contains the request type (Set),
+ an array of operations to perform, and an array for holding
+ the results of the operations.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+ //
+ // General Algorithm:
+ //
+ // Verify length
+ // Switch(Request)
+ // Process Request
+ //
+
+ //
+ // Variables for a particular request
+ //
+
+ PELNK3_ADAPTER pAdapter=MiniportContext;
+
+ UINT OidLength;
+
+ //
+ // Variables for holding the new values to be used.
+ //
+
+ ULONG LookAhead;
+ ULONG Filter;
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+
+ IF_REQ_LOUD( DbgPrint("ELNK3: SetInfo %08lx %0d\n",(UINT)Oid,BytesLeft);)
+
+ //
+ // Get Oid and Length of request
+ //
+
+
+ OidLength = BytesLeft;
+
+ switch (Oid) {
+
+
+ case OID_802_3_MULTICAST_LIST:
+
+ //
+ // Verify length
+ //
+
+ if ((OidLength % ELNK3_LENGTH_OF_ADDRESS) != 0){
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ *BytesRead = 0;
+ *BytesNeeded = 0;
+
+ break;
+
+ }
+
+#if DBG
+ {
+ UINT j;
+ PUCHAR Address;
+
+ Address=InfoBuffer;
+
+ for (j=0; j<(OidLength / ELNK3_LENGTH_OF_ADDRESS); j++) {
+
+ IF_REQ_LOUD(DbgPrint(" %02x-%02x-%02x-%02x-%02x-%02x\n",
+ Address[j*6],
+ Address[j*6+1],
+ Address[j*6+2],
+ Address[j*6+3],
+ Address[j*6+4],
+ Address[j*6+5]);)
+ }
+ }
+#endif
+
+ break;
+
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ //
+ // Verify length
+ //
+
+ if (OidLength != 4 ) {
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ *BytesRead = 0;
+ *BytesNeeded = 0;
+
+ break;
+
+ }
+
+
+
+ NdisMoveMemory(&Filter, InfoBuffer, 4);
+
+
+ StatusToReturn=Elnk3FilterChangeAction(
+ Filter,
+ pAdapter
+ );
+
+
+
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ //
+ // Verify length
+ //
+ if (OidLength != 4) {
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ *BytesRead = 0;
+ *BytesNeeded = 0;
+
+ break;
+
+ }
+
+ NdisMoveMemory(
+ &LookAhead,
+ InfoBuffer,
+ 4
+ );
+
+ IF_REQ_LOUD(DbgPrint("Setting LookAhead: %d\n",LookAhead);)
+
+
+ if (LookAhead <= ELNK3_MAX_LOOKAHEAD_SIZE) {
+
+ pAdapter->MaxLookAhead=LookAhead;
+ Elnk3AdjustMaxLookAhead(pAdapter);
+
+
+ } else {
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ }
+
+ break;
+
+
+ case OID_GEN_PROTOCOL_OPTIONS:
+
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ break;
+
+
+ default:
+
+ StatusToReturn = NDIS_STATUS_INVALID_OID;
+
+ *BytesRead = 0;
+ *BytesNeeded = 0;
+
+ break;
+
+ }
+
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS) {
+
+ *BytesRead = BytesLeft;
+ *BytesNeeded = 0;
+
+ }
+
+
+#if DBG
+
+ if (StatusToReturn != NDIS_STATUS_SUCCESS) {
+
+ IF_REQ_LOUD(DbgPrint("Out SetInfo oid=%08lx failed\n",Oid);)
+ }
+#endif
+
+ return StatusToReturn;
+
+}
+
+
+
+
+VOID
+Elnk3AdjustMaxLookAhead(
+ IN PELNK3_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine finds the open with the maximum lookahead value and
+ stores that in the adapter block.
+
+Arguments:
+
+ Adapter - A pointer to the adapter block.
+
+Returns:
+
+ None.
+
+--*/
+{
+ ULONG CurrentMax;
+
+ if (Adapter->MaxLookAhead < 60 ) {
+
+ Adapter->MaxLookAhead =60;
+
+ }
+
+
+ CurrentMax=Adapter->MaxLookAhead;
+
+ if (Adapter->ReceiveMethod==1) {
+
+ Adapter->EarlyReceiveThreshold=ELNK3_ROUND_TO_DWORD((CurrentMax+
+ ELNK3_ETHERNET_HEADER_SIZE)
+ & 0x7ff);
+ } else {
+
+ Adapter->EarlyReceiveThreshold=Adapter->ThresholdTarget & 0x7fc;
+ }
+
+
+ IF_REQ_LOUD(DbgPrint("ELNK3: Setting LookAhead: %d Threshold: %d\n", CurrentMax, Adapter->EarlyReceiveThreshold);)
+
+
+}
+
+
+NDIS_STATUS
+Elnk3FilterChangeAction(
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when an address is added to
+ the filter that wasn't referenced by any other open binding.
+
+Arguments:
+
+ NewFilterClasses - A bit mask that should be put on the card telling
+ which packet types to accept.
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened.
+
+Return Value:
+
+ Status of the change (successful or pending).
+
+
+--*/
+
+{
+ PELNK3_ADAPTER pAdapter = MacBindingHandle;
+
+ UCHAR NewFilter=0;
+
+ IF_REQ_LOUD(DbgPrint("ELNK3: FilterChangeAction called %08lx\n",NewFilterClasses);)
+
+ if (NewFilterClasses & ~(NDIS_PACKET_TYPE_DIRECTED |
+ NDIS_PACKET_TYPE_MULTICAST |
+ NDIS_PACKET_TYPE_ALL_MULTICAST |
+ NDIS_PACKET_TYPE_BROADCAST |
+ NDIS_PACKET_TYPE_PROMISCUOUS )) {
+
+ IF_REQ_LOUD(DbgPrint("ELNK3: protocol set bogus filter\n");)
+ return NDIS_STATUS_NOT_SUPPORTED;
+ }
+
+
+ if (NewFilterClasses & NDIS_PACKET_TYPE_DIRECTED) {
+ IF_REQ_LOUD(DbgPrint("ELNK3: FilterChangeAction: directed\n");)
+ NewFilter|=EC_FILTER_ADDRESS;
+ }
+
+ if (NewFilterClasses & NDIS_PACKET_TYPE_MULTICAST ) {
+ IF_REQ_LOUD(DbgPrint("ELNK3: FilterChangeAction: multicast\n");)
+ NewFilter|=EC_FILTER_GROUP;
+ }
+
+ if (NewFilterClasses & NDIS_PACKET_TYPE_ALL_MULTICAST) {
+ IF_REQ_LOUD(DbgPrint("ELNK3: FilterChangeAction: all multicast\n");)
+ NewFilter|=EC_FILTER_GROUP;
+ }
+
+ if (NewFilterClasses & NDIS_PACKET_TYPE_BROADCAST) {
+ IF_REQ_LOUD(DbgPrint("ELNK3: FilterChangeAction: broadcast\n");)
+ NewFilter|=EC_FILTER_BROADCAST;
+ }
+
+ if (NewFilterClasses & NDIS_PACKET_TYPE_PROMISCUOUS) {
+ IF_REQ_LOUD(DbgPrint("ELNK3: FilterChangeAction: promiscuous\n");)
+ NewFilter|=EC_FILTER_PROMISCUOUS;
+ }
+
+
+ pAdapter->RejectBroadcast=FALSE;
+
+ if (NewFilterClasses & NDIS_PACKET_TYPE_MULTICAST) {
+ //
+ // The multicast bit is set so the card receives every thing
+ // that is not directed
+ //
+ if ((NewFilterClasses & (NDIS_PACKET_TYPE_BROADCAST |
+ NDIS_PACKET_TYPE_PROMISCUOUS))==0) {
+ //
+ // We want multicast but not broadcast and we aren't
+ // in promiscuous mode
+ //
+ pAdapter->RejectBroadcast=TRUE;
+ }
+ }
+
+
+
+
+ pAdapter->NdisRxFilter=NewFilterClasses;
+
+ pAdapter->RxFilter=NewFilter;
+
+ ELNK3_COMMAND(pAdapter, EC_SET_RX_FILTER, NewFilter);
+
+ return NDIS_STATUS_SUCCESS;
+
+
+}
diff --git a/private/ntos/ndis/elnk3/send.c b/private/ntos/ndis/elnk3/send.c
new file mode 100644
index 000000000..b76cf8beb
--- /dev/null
+++ b/private/ntos/ndis/elnk3/send.c
@@ -0,0 +1,292 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ send.c
+
+Abstract:
+
+ Ndis 3.0 MAC driver for the 3Com Etherlink III
+
+
+Author:
+
+ Brian Lieuallen (BrianLie) 12/14/92
+
+
+Environment:
+
+ Kernel Mode Operating Systems : NT
+
+Revision History:
+
+ Portions borrowed from ELNK3 driver by
+ Earle R. Horton (EarleH)
+
+
+
+--*/
+
+
+
+#include <ndis.h>
+#include <efilter.h>
+
+
+#include "debug.h"
+
+
+#include "elnk3hrd.h"
+#include "elnk3sft.h"
+#include "elnk3.h"
+
+
+
+
+
+
+
+
+
+
+NDIS_STATUS
+Elnk3MacSend(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_PACKET Packet,
+ IN UINT Flags
+ )
+/*++
+
+Routine Description:
+ MacSend
+
+
+Arguments:
+ See NDIS 3.0 spec
+
+Return Value:
+
+
+--*/
+
+
+ {
+ PELNK3_ADAPTER pAdapter = MacBindingHandle;
+ UINT PacketLength;
+ BOOLEAN Retry=FALSE;
+ ULONG FreeFifoBytes;
+ ULONG PadBuffer=0;
+
+ IF_SEND_LOUD(DbgPrint("MacSend called Packets\n");)
+
+ NdisQueryPacket(Packet, NULL, NULL, NULL, &PacketLength);
+
+ //
+ // Here we check to make sure the packet meets some size constraints
+ //
+
+ if (PacketLength < 14 || PacketLength > 1514) {
+
+ IF_LOUD(DbgPrint("MovePacketToCard: Packet too long or too short\n");)
+
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ //
+ // See if there is enough room in the fifo to send it now.
+ //
+ FreeFifoBytes=ELNK3_READ_PORT_USHORT(pAdapter,PORT_TxFree);
+
+ if ((FreeFifoBytes) < ELNK3_ROUND_TO_DWORD(PacketLength)+4) {
+ //
+ // Nope, Ask for a transmit availible interrupt when there is
+ //
+ ELNK3_COMMAND(pAdapter, EC_SET_TX_AVAILIBLE, ELNK3_ROUND_TO_DWORD(PacketLength)+4);
+
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ do {
+
+
+ UCHAR XmitStatus;
+ PNDIS_BUFFER CurBuffer;
+ PUCHAR BufferAddress;
+ UINT Len;
+ ULONG Pad;
+ PVOID Port=pAdapter->PortOffsets[PORT_TxFIFO];
+
+
+
+ NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, NULL);
+
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufferAddress, &Len);
+
+
+ //
+ // Write out the length and a pad word
+ //
+
+ NdisRawWritePortUlong(Port,(PacketLength & 0x7ff));
+
+ while (1) {
+
+ NdisRawWritePortBufferUlong(
+ (ULONG)Port,
+ (PULONG)BufferAddress,
+ Len >> 2
+ );
+
+
+ if ((Len & 3) != 0) {
+
+ NdisRawWritePortBufferUchar(
+ Port,
+ BufferAddress+(Len & 0xfffffffc),
+ (Len & 3)
+ );
+
+ }
+
+
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+
+ if (CurBuffer==NULL) {
+ //
+ // done
+ //
+ break;
+ }
+
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufferAddress, &Len);
+
+ }
+
+ Pad=(ELNK3_ROUND_TO_DWORD(PacketLength) - PacketLength);
+
+ if (Pad != 0) {
+
+ NdisRawWritePortBufferUchar(
+ (ULONG)Port,
+ (PUCHAR)&PadBuffer,
+ Pad
+ );
+
+
+ }
+
+
+ Retry=FALSE;
+
+ //
+ // Check the status, if it underan then it would be set now
+ //
+ ELNK3ReadAdapterUchar(pAdapter,PORT_TxStatus,&XmitStatus);
+
+ if ((XmitStatus & TX_STATUS_COMPLETE) && (XmitStatus & TX_STATUS_UNDERRUN)) {
+ //
+ // The transmitter under-ran. Restart it and try again
+ //
+
+ IF_LOG(0xaa,0xcc, PacketLength);
+
+ HandleXmtInterrupts(pAdapter);
+
+ Retry=TRUE;
+
+ }
+
+
+ } while (Retry);
+
+ //
+ // we sent something
+ //
+ NdisMSendResourcesAvailable(pAdapter->NdisAdapterHandle);
+
+ return NDIS_STATUS_SUCCESS;
+
+}
+
+
+
+BOOLEAN
+HandleXmtInterrupts(
+ PELNK3_ADAPTER pAdapter
+ )
+{
+ UCHAR XmitStatus;
+
+
+
+ ELNK3ReadAdapterUchar(pAdapter,PORT_TxStatus,&XmitStatus);
+
+ IF_LOUD (DbgPrint("ELNK3: HandleXmitInts: Status=%02x\n",XmitStatus);)
+
+ if (XmitStatus != 0) {
+ //
+ // pop the tx status
+ //
+ ELNK3WriteAdapterUchar(pAdapter,PORT_TxStatus,0);
+
+ if ((XmitStatus & TX_STATUS_JABBER)
+ ||
+ (XmitStatus & TX_STATUS_UNDERRUN)) {
+ //
+ // If it is one of these then it the xmiter needs to be reset
+ //
+ ELNK3_COMMAND(pAdapter,EC_TX_RESET,0);
+ ELNK3_WAIT_NOT_BUSY(pAdapter);
+
+ ELNK3_COMMAND(pAdapter,EC_TX_ENABLE,0);
+
+ //
+ // Could use a better message, But...
+ //
+//
+// Commented out so as not to alarm people with random events
+// in the registry.
+//
+// NdisWriteErrorLogEntry(
+// pAdapter->NdisAdapterHandle,
+// NDIS_ERROR_CODE_TIMEOUT,
+// 3,
+// pAdapter->FramesXmitGood,
+// pAdapter->TxStartThreshold,
+// pAdapter->TxStartThresholdInc
+// );
+
+ if ((XmitStatus & TX_STATUS_UNDERRUN)) {
+ //
+ // Underrun bump up the threshold
+ //
+ pAdapter->TxStartThreshold+=pAdapter->TxStartThresholdInc;
+
+ if (pAdapter->TxStartThreshold > 2040) {
+
+ pAdapter->TxStartThreshold=2040;
+ }
+ }
+
+ ELNK3_COMMAND(pAdapter,EC_SET_TX_START,(USHORT)pAdapter->TxStartThreshold & 0x7ff);
+
+ } else {
+ //
+ // Otherwise the xmitter just needs to be restarted
+ //
+
+ ELNK3_COMMAND(pAdapter,EC_TX_ENABLE,0);
+ }
+
+ pAdapter->FramesXmitBad++;
+ }
+
+
+ IF_SEND_LOUD (DbgPrint("HandleXmitInts: Exit\n");)
+
+ return TRUE;
+}
diff --git a/private/ntos/ndis/elnk3/sources b/private/ntos/ndis/elnk3/sources
new file mode 100644
index 000000000..eec91287c
--- /dev/null
+++ b/private/ntos/ndis/elnk3/sources
@@ -0,0 +1,51 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=elnk3
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER
+
+INCLUDES=..\..\inc
+
+SOURCES= send.c\
+ receive.c\
+ interrup.c\
+ config.c\
+ init.c\
+ elnk3.c\
+ card.c\
+ request.c \
+ elnk3.rc
+
+
+
+RELATIVE_DEPTH=..\..
+
+MSC_WARNING_LEVEL=/W3 /WX
diff --git a/private/ntos/ndis/elnkii.new/card.c b/private/ntos/ndis/elnkii.new/card.c
new file mode 100644
index 000000000..cbbfd6d60
--- /dev/null
+++ b/private/ntos/ndis/elnkii.new/card.c
@@ -0,0 +1,3155 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ card.c
+
+Abstract:
+
+ Card-specific functions for the NDIS 3.0 Etherlink II driver.
+
+Author:
+
+ Adam Barr (adamba) 30-Jul-1990
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ Adam Barr (adamba) 28-Aug-1990
+ - moved the SyncXXX() functions to sync.c
+
+
+--*/
+
+#include <ndis.h>
+#include "elnkhrd.h"
+#include "elnksft.h"
+
+
+//
+// The amount of data to transfer in one programmed I/O burst
+// (should be 8 or 16).
+//
+
+#define DMA_BURST_SIZE 16
+
+#if DBG
+UCHAR PrevBurstSize = 0;
+UCHAR PrevPrevBurstSize = 0;
+#endif
+
+
+//
+// Array to hold multicast address list.
+//
+
+CHAR Addresses[DEFAULT_MULTICASTLISTMAX][ETH_LENGTH_OF_ADDRESS] = {0};
+
+
+
+#pragma NDIS_INIT_FUNCTION(CardGetMemBaseAddr)
+
+PUCHAR CardGetMemBaseAddr(
+ IN PELNKII_ADAPTER pAdapter,
+ OUT PBOOLEAN pfCardPresent,
+ OUT PBOOLEAN pfIoBaseCorrect
+)
+
+/*++
+
+Routine Description:
+
+ Checks that the I/O base address is correct and returns
+ the memory base address. For cards that are not set up
+ for memory mapped mode, it will only check the I/O base
+ address, and return NULL if it is not correct.
+
+Arguments:
+
+ pAdapter - pointer to the adapter block.
+
+ CardPresent - Returns FALSE if the card does not appear
+ to be present in the machine.
+
+ IoBaseCorrect - Returns TRUE if the jumper matches the
+ configured I/O base address.
+
+Return Value:
+
+ The memory base address for memory mapped systems.
+
+--*/
+
+{
+ static PVOID IoBases[] = { (PVOID)0x2e0, (PVOID)0x2a0,
+ (PVOID)0x280, (PVOID)0x250,
+ (PVOID)0x350, (PVOID)0x330,
+ (PVOID)0x310, (PVOID)0x300 };
+ static PVOID MemBases[] = { (PVOID)0xc8000, (PVOID)0xcc000,
+ (PVOID)0xd8000, (PVOID)0xdc000 };
+ UCHAR BaseConfig;
+ UCHAR Tmp;
+ UCHAR MemConfig;
+
+
+ //
+ // Read in the Base Configuration Register.
+ //
+ NdisRawReadPortUchar(pAdapter->MappedGaBaseAddr + GA_IO_BASE, &Tmp);
+
+ //
+ // Make sure that only one bit in Tmp is on.
+ //
+ if ((Tmp != 0) && ((Tmp & (Tmp - 1)) == 0))
+ {
+ *pfCardPresent = TRUE;
+ }
+ else
+ {
+ *pfCardPresent = FALSE;
+
+ return(NULL);
+ }
+
+ //
+ // Make sure the correct bit is on for pAdapter->IoBaseAddr.
+ //
+ BaseConfig = 0;
+
+ while (!(Tmp & 1))
+ {
+ Tmp >>= 1;
+
+ ++BaseConfig;
+
+ if (BaseConfig == 8)
+ return(NULL);
+ }
+
+ if (IoBases[BaseConfig] != pAdapter->IoBaseAddr)
+ {
+ //
+ // Probably the jumper is wrong.
+ //
+ *pfIoBaseCorrect = FALSE;
+
+ return(NULL);
+
+ }
+ else
+ {
+ *pfIoBaseCorrect = TRUE;
+ }
+
+ //
+ // For non-memory-mapped cards, there is nothing else to check.
+ //
+ if (!pAdapter->MemMapped)
+ return(NULL);
+
+ //
+ // Now read in the PROM configuration register.
+ //
+ NdisRawReadPortUchar(pAdapter->MappedGaBaseAddr + GA_MEM_BASE, &Tmp);
+
+ //
+ // See which bit is on, minus 4.
+ //
+ MemConfig = 0;
+
+ while (!(Tmp & 0x10))
+ {
+ Tmp >>= 1;
+
+ ++MemConfig;
+
+ if (MemConfig == 4)
+ return(NULL);
+ }
+
+ //
+ // Based on the bit, look up MemBaseAddr in the table.
+ //
+ pAdapter->MemMapped = TRUE;
+
+ return(MemBases[MemConfig]);
+}
+
+
+#pragma NDIS_INIT_FUNCTION(CardReadEthernetAddress)
+
+VOID CardReadEthernetAddress(
+ IN PELNKII_ADAPTER pAdapter
+)
+
+/*++
+
+Routine Description:
+
+ Reads in the Ethernet address from the Etherlink II PROM.
+
+Arguments:
+
+ pAdapter - pointer to the adapter block.
+
+Return Value:
+
+ The address is stored in pAdapter->PermanentAddress, and StationAddress if it
+ is currently zero.
+
+--*/
+
+{
+ UINT i;
+
+ //
+ // Window the PROM into the NIC ports.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_CONTROL,
+ CTRL_PROM_SEL | CTRL_BNC
+ );
+
+ //
+ // Read in the station address.
+ //
+ for (i = 0; i < ETH_LENGTH_OF_ADDRESS; i++)
+ {
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + i,
+ &pAdapter->PermanentAddress[i]
+ );
+ }
+
+ IF_LOUD( DbgPrint(" [ %x-%x-%x-%x-%x-%x ]\n",
+ pAdapter->PermanentAddress[0],
+ pAdapter->PermanentAddress[1],
+ pAdapter->PermanentAddress[2],
+ pAdapter->PermanentAddress[3],
+ pAdapter->PermanentAddress[4],
+ pAdapter->PermanentAddress[5]);)
+
+ //
+ // Window the NIC registers into the NIC ports.
+ //
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_CONTROL,
+ CTRL_GA_SEL | CTRL_BNC
+ );
+
+ if
+ (
+ (pAdapter->StationAddress[0] == 0x00) &&
+ (pAdapter->StationAddress[1] == 0x00) &&
+ (pAdapter->StationAddress[2] == 0x00) &&
+ (pAdapter->StationAddress[3] == 0x00) &&
+ (pAdapter->StationAddress[4] == 0x00) &&
+ (pAdapter->StationAddress[5] == 0x00)
+ )
+ {
+ pAdapter->StationAddress[0] = pAdapter->PermanentAddress[0];
+ pAdapter->StationAddress[1] = pAdapter->PermanentAddress[1];
+ pAdapter->StationAddress[2] = pAdapter->PermanentAddress[2];
+ pAdapter->StationAddress[3] = pAdapter->PermanentAddress[3];
+ pAdapter->StationAddress[4] = pAdapter->PermanentAddress[4];
+ pAdapter->StationAddress[5] = pAdapter->PermanentAddress[5];
+ }
+}
+
+
+BOOLEAN CardSetup(
+ IN PELNKII_ADAPTER pAdapter
+)
+
+/*++
+
+Routine Description:
+
+ Sets up the card, using the sequence given in the Etherlink II
+ technical reference.
+
+Arguments:
+
+ pAdapter - pointer to the adapter block, which must be initialized.
+
+Return Value:
+
+ TRUE if successful.
+
+--*/
+
+{
+ UINT i;
+ UINT Filter;
+ UCHAR IntConfig;
+ UCHAR Tmp;
+
+ //
+ // First set up the Gate Array.
+ //
+
+ //
+ // Toggle the reset bit.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_CONTROL,
+ CTRL_RESET | CTRL_BNC
+ );
+ NdisRawWritePortUchar(pAdapter->MappedGaBaseAddr + GA_CONTROL, 0x00);
+ NdisRawWritePortUchar(pAdapter->MappedGaBaseAddr + GA_CONTROL, CTRL_BNC);
+
+ //
+ // Set up the bits in the Control Register that don't change.
+ //
+ pAdapter->GaControlBits = pAdapter->ExternalTransceiver ?
+ CTRL_DIX : CTRL_BNC;
+
+ if (DMA_BURST_SIZE == 16)
+ pAdapter->GaControlBits |= CTRL_DB_SEL;
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_CONTROL,
+ pAdapter->GaControlBits
+ );
+
+ //
+ // Set Page Start and Page Stop to match the NIC registers.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_PAGE_START,
+ pAdapter->NicPageStart
+ );
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_PAGE_STOP,
+ pAdapter->NicPageStop
+ );
+
+ //
+ // Select which interrupt to use.
+ //
+ IntConfig = 0x04; // set bit in position 2
+ IntConfig <<= pAdapter->InterruptNumber; // move it to 4 through 7
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_INT_DMA_CONFIG,
+ IntConfig
+ );
+
+ //
+ // Choose between 8- and 16-byte programmed I/O bursts.
+ //
+ if (DMA_BURST_SIZE == 8)
+ {
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_DRQ_TIMER,
+ DQTR_8_BYTE
+ );
+ }
+ else
+ {
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_DRQ_TIMER,
+ DQTR_16_BYTE
+ );
+ }
+
+ //
+ // Initialize these to a correct value for an 8K card.
+ //
+ NdisRawWritePortUchar(pAdapter->MappedGaBaseAddr + GA_DMA_ADDR_MSB, 0x20);
+ NdisRawWritePortUchar(pAdapter->MappedGaBaseAddr + GA_DMA_ADDR_LSB, 0x00);
+
+ //
+ // Set up the Configuration register.
+ //
+ if (pAdapter->MemMapped)
+ {
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_CONFIG,
+ GACFR_TC_MASK | GACFR_RAM_SEL | GACFR_MEM_BANK1
+ );
+ }
+ else
+ {
+ NdisRawWritePortUchar
+ (
+ pAdapter->MappedGaBaseAddr + GA_CONFIG,
+ GACFR_TC_MASK
+ );
+ }
+
+ //
+ // Now set up NIC registers.
+ //
+
+ //
+ // Write to and read from CR to make sure it is there.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_COMMAND,
+ CR_STOP | CR_NO_DMA | CR_PAGE0
+ );
+
+ NdisRawReadPortUchar(pAdapter->MappedIoBaseAddr + NIC_COMMAND, &Tmp);
+
+ if (Tmp != (CR_STOP | CR_NO_DMA | CR_PAGE0))
+ return(FALSE);
+
+ //
+ // Set up the registers in the correct sequence.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_DATA_CONFIG,
+ DCR_BYTE_WIDE | DCR_NORMAL | DCR_FIFO_8_BYTE
+ );
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr + NIC_RMT_COUNT_MSB, 0);
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr + NIC_RMT_COUNT_LSB, 0);
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_RCV_CONFIG,
+ pAdapter->NicReceiveConfig
+ );
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_XMIT_CONFIG,
+ TCR_LOOPBACK
+ );
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_BOUNDARY,
+ pAdapter->NicPageStart
+ );
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_PAGE_START,
+ pAdapter->NicPageStart
+ );
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_PAGE_STOP,
+ pAdapter->NicPageStop
+ );
+
+ pAdapter->Current = pAdapter->NicPageStart + (UCHAR)1;
+ pAdapter->NicNextPacket = pAdapter->NicPageStart + (UCHAR)1;
+ pAdapter->BufferOverflow = FALSE;
+
+ //
+ // Clear all
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_STATUS,
+ 0xff
+ );
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_MASK,
+ pAdapter->NicInterruptMask
+ );
+
+
+ //
+ // Move to page 1 to write the station address and
+ // multicast registers.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_COMMAND,
+ CR_STOP | CR_NO_DMA | CR_PAGE1
+ );
+
+ for (i = 0; i < ETH_LENGTH_OF_ADDRESS; i++)
+ {
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + (NIC_PHYS_ADDR+i),
+ pAdapter->StationAddress[i]
+ );
+ }
+
+ Filter = pAdapter->PacketFilter;
+
+ for (i = 0; i < 8; i++)
+ {
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + (NIC_MC_ADDR+i),
+ (UCHAR)((Filter & NDIS_PACKET_TYPE_ALL_MULTICAST) ?
+ 0xff : pAdapter->NicMulticastRegs[i])
+ );
+ }
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_CURRENT,
+ pAdapter->Current
+ );
+
+
+ //
+ // move back to page 0 and start the card...
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr+NIC_COMMAND,
+ CR_STOP | CR_NO_DMA | CR_PAGE0
+ );
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr+NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE0
+ );
+
+ //
+ // ... but it is still in loopback mode.
+ //
+ return(TRUE);
+}
+
+BOOLEAN SyncCardStop(
+ IN PVOID SynchronizeContext
+)
+
+/*++
+
+Routine Description:
+
+ Sets the NIC_COMMAND register to stop the card.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ Ignored.
+
+--*/
+
+{
+ PELNKII_ADAPTER pAdapter = ((PELNKII_ADAPTER)SynchronizeContext);
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_COMMAND,
+ CR_STOP | CR_NO_DMA
+ );
+
+ return(FALSE);
+}
+
+
+
+VOID CardStop(
+ IN PELNKII_ADAPTER pAdapter
+)
+
+/*++
+
+Routine Description:
+
+ Stops the card.
+
+Arguments:
+
+ pAdapter - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UINT i;
+ UCHAR Tmp;
+
+ //
+ // Turn on the STOP bit in the Command register.
+ //
+ NdisMSynchronizeWithInterrupt(
+ &pAdapter->Interrupt,
+ SyncCardStop,
+ pAdapter
+ );
+
+ //
+ // Clear the Remote Byte Count register so that ISR_RESET
+ // will come on.
+ //
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr + NIC_RMT_COUNT_MSB, 0);
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr + NIC_RMT_COUNT_LSB, 0);
+
+
+ //
+ // Wait for ISR_RESET, but only for 1.6 milliseconds (as
+ // described in the March 1991 8390 addendum), since that
+ // is the maximum time for a software reset to occur.
+ //
+ //
+ for (i = 0; i < 4; i++)
+ {
+ NdisRawReadPortUchar(pAdapter->MappedIoBaseAddr + NIC_INTR_STATUS, &Tmp);
+ if (Tmp & ISR_RESET)
+ break;
+
+ NdisStallExecution(500);
+ }
+
+ if (i == 4)
+ {
+ IF_LOUD( DbgPrint("RESET\n");)
+ IF_LOG( ElnkiiLog('R');)
+ }
+
+
+ //
+ // Put the card in loopback mode, then start it.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_XMIT_CONFIG,
+ TCR_LOOPBACK
+ );
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_COMMAND,
+ CR_START | CR_NO_DMA
+ );
+
+ //
+ // At this point the card is still in loopback mode.
+ //
+}
+
+
+BOOLEAN CardReset(
+ IN PELNKII_ADAPTER pAdapter
+)
+
+/*++
+
+Routine Description:
+
+ Resets the card.
+
+Arguments:
+
+ pAdapter - pointer to the adapter block
+
+Return Value:
+
+ TRUE if everything is OK.
+
+--*/
+
+{
+ //
+ // Stop the chip.
+ //
+ CardStop(pAdapter);
+
+ //
+ // CardSetup() does a software reset.
+ //
+ if (!CardSetup(pAdapter))
+ {
+ NdisWriteErrorLogEntry(
+ pAdapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 2,
+ cardReset,
+ ELNKII_ERRMSG_CARD_SETUP
+ );
+
+ return(FALSE);
+ }
+
+ //
+ // Start the chip.
+ //
+ CardStart(pAdapter);
+
+ return(TRUE);
+}
+
+#pragma NDIS_INIT_FUNCTION(DelayComplete)
+
+VOID DelayComplete(
+ IN PVOID SystemSpecific1,
+ IN PVOID TimerExpired,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+{
+ UNREFERENCED_PARAMETER(SystemSpecific1);
+ UNREFERENCED_PARAMETER(SystemSpecific2);
+ UNREFERENCED_PARAMETER(SystemSpecific3);
+
+ *((BOOLEAN *)TimerExpired)=TRUE;
+}
+
+
+
+#pragma NDIS_INIT_FUNCTION(CardTest)
+
+BOOLEAN CardTest(
+ IN PELNKII_ADAPTER pAdapter
+)
+
+/*++
+
+Routine Description:
+
+ Tests the card. Follows the tests described in section 12 of
+ the 8390 Data Sheet.
+
+Arguments:
+
+ pAdapter - pointer to the adapter block, which must be initialized
+ and set up.
+
+Return Value:
+
+ TRUE if everything is OK.
+
+--*/
+
+{
+#define TEST_LEN 60
+#define MAGIC_NUM 0x92
+
+ UINT FirstTest;
+ UINT SecondTest;
+ UINT i;
+ UCHAR TSRResult;
+ UCHAR RSRResult;
+ UCHAR CrcBuf[4];
+ BOOLEAN FinalResult = TRUE;
+ UCHAR TestSrcBuf[256];
+ UCHAR TestDestBuf[256];
+ PUCHAR CurTestLoc;
+ UCHAR Tmp;
+
+ static NDIS_MINIPORT_TIMER Timer = {0};
+ BOOLEAN TimerExpired = FALSE;
+
+ BOOLEAN dummy; //for return from NdisMCancelTimer
+
+ //
+ // These arrays are indexed by FirstTest.
+ //
+
+ static UCHAR TCRValues[3] = { TCR_NIC_LBK, TCR_SNI_LBK, TCR_COAX_LBK };
+ static UCHAR TSRCDHWanted[3] = { TSR_NO_CDH, TSR_NO_CDH, 0x00 };
+ static UCHAR TSRCRSWanted[3] = { TSR_NO_CARRIER, 0x00, 0x00 };
+ static UCHAR FIFOWanted[4] = { LSB(TEST_LEN+4), MSB(TEST_LEN+4),
+ MSB(TEST_LEN+4), MAGIC_NUM };
+
+
+ //
+ // These arrays are indexed by SecondTest.
+ //
+
+ static BOOLEAN GoodCrc[3] = { TRUE, FALSE, FALSE };
+ static BOOLEAN GoodAddress[3] = { TRUE, TRUE, FALSE };
+ static UCHAR RSRWanted[3] = { RSR_PACKET_OK, RSR_CRC_ERROR, RSR_PACKET_OK };
+
+ static UCHAR TestPacket[TEST_LEN] = {0}; // a dummy packet.
+ static UCHAR NullAddress[ETH_LENGTH_OF_ADDRESS] = { 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00 };
+
+
+ //
+ // First construct TestPacket.
+ //
+
+ ELNKII_MOVE_MEM(TestPacket, pAdapter->StationAddress, ETH_LENGTH_OF_ADDRESS);
+ ELNKII_MOVE_MEM(TestPacket+ETH_LENGTH_OF_ADDRESS, pAdapter->StationAddress, ETH_LENGTH_OF_ADDRESS);
+ TestPacket[2*ETH_LENGTH_OF_ADDRESS] = 0x00;
+ TestPacket[2*ETH_LENGTH_OF_ADDRESS+1] = 0x00;
+ TestPacket[TEST_LEN-1] = MAGIC_NUM;
+
+
+ //
+ // Set up the DCR for loopback operation.
+ //
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_DATA_CONFIG,
+ DCR_BYTE_WIDE | DCR_LOOPBACK | DCR_FIFO_8_BYTE);
+
+
+ //
+ // Set the RCR to reject all packets.
+ //
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_RCV_CONFIG, 0x00);
+
+
+ //
+ // First round of tests -- different loopback modes
+ //
+
+ for (FirstTest = 0; FirstTest < 2; ++FirstTest) {
+
+ //
+ // Stop the card.
+ //
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_COMMAND,
+ CR_STOP | CR_NO_DMA | CR_PAGE0);
+
+
+ //
+ // Set up the TCR for the appropriate loopback mode.
+ //
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_XMIT_CONFIG, 0x00);
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_XMIT_CONFIG, TCRValues[FirstTest]);
+
+
+ //
+ // Restart the card.
+ //
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE0);
+
+
+ //
+ // Now copy down TestPacket and start the transmission.
+ //
+
+ CardCopyDownBuffer(pAdapter, TestPacket, 0, 0, TEST_LEN);
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_XMIT_START, pAdapter->NicXmitStart);
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_XMIT_COUNT_MSB, MSB(TEST_LEN));
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_XMIT_COUNT_LSB, LSB(TEST_LEN));
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_COMMAND,
+ CR_START | CR_XMIT | CR_NO_DMA);
+
+
+ //
+ // Wait for the transmission to complete, for about a second.
+ //
+
+ {
+ UINT i;
+ i=0;
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_STATUS, &Tmp);
+ while (!(Tmp & (ISR_XMIT | ISR_XMIT_ERR))) {
+
+ if (++i > 100) {
+ IF_TEST( DbgPrint("F%d: TEST reset timed out\n", FirstTest);)
+ FinalResult = FALSE;
+ goto FinishTest;
+ }
+
+ NdisStallExecution(11000);
+ NdisRawReadPortUchar(pAdapter->MappedIoBaseAddr+NIC_INTR_STATUS, &Tmp);
+ }
+ }
+
+ //
+ // WAIT FOR CHIP TO STABILIZE
+ // Write to and read from CR to make sure it is there.
+ // Bug#4267 - WFW
+ //
+
+ {
+ UINT i;
+ for (i = 0; i < 2000; ++i) {
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_COMMAND, CR_STOP | CR_NO_DMA | CR_PAGE0);
+ NdisRawReadPortUchar(pAdapter->MappedIoBaseAddr+NIC_COMMAND, &Tmp);
+ if (Tmp != (CR_STOP | CR_NO_DMA | CR_PAGE0)) {
+ NdisStallExecution(1000);
+ } else {
+ break;
+ }
+ }
+ }
+
+
+ //
+ // Acknowledge the interrupt.
+ //
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_INTR_STATUS,
+ ISR_XMIT | ISR_XMIT_ERR);
+
+
+ //
+ // Check that the CRS and CDH bits are set correctly.
+ //
+
+ NdisRawReadPortUchar(pAdapter->MappedIoBaseAddr+NIC_XMIT_STATUS, &TSRResult);
+
+ if ((TSRResult & TSR_NO_CARRIER) != TSRCRSWanted[FirstTest]) {
+
+ IF_TEST(DbgPrint("F%d: Incorrect CRS value: %x\n", FirstTest, TSRResult);)
+
+ FinalResult = FALSE;
+
+ goto FinishTest;
+
+ }
+
+ if ((TSRResult & TSR_NO_CDH) != TSRCDHWanted[FirstTest]) {
+
+ //
+ // the spec says CDH won't go on for TCR_COAX_LBK, but it does
+ //
+
+ if (TCRValues[FirstTest] != TCR_COAX_LBK) {
+
+ IF_TEST( DbgPrint("F%d: Incorrect CDH value: %x\n", FirstTest,TSRResult);)
+
+ FinalResult = FALSE;
+
+ goto FinishTest;
+
+ }
+
+ }
+
+
+ //
+ // For the Loopback to Coax test the RSR and FIFO
+ // can't be trusted, so skip them.
+ //
+
+ if (TCRValues[FirstTest] == TCR_COAX_LBK) {
+
+ continue;
+
+ }
+
+
+ //
+ // Check that the CRC error happened (it should).
+ //
+
+ NdisRawReadPortUchar(pAdapter->MappedIoBaseAddr+NIC_RCV_STATUS, &RSRResult);
+
+ if (!(RSRResult & RSR_CRC_ERROR)) {
+
+ IF_TEST( DbgPrint("F%d: No CRC error: %x\n", FirstTest, RSRResult);)
+
+ FinalResult = FALSE;
+
+ goto FinishTest;
+
+ }
+
+
+ //
+ // Check that the right values are in the FIFO.
+ //
+
+ for (i=0; i<4; i++) {
+
+ NdisRawReadPortUchar(pAdapter->MappedIoBaseAddr+NIC_FIFO, &Tmp);
+ if (Tmp != FIFOWanted[i]) {
+
+ IF_TEST( DbgPrint("F%d: Bad FIFO value: %d\n", FirstTest, i);)
+
+ FinalResult = FALSE;
+
+ goto FinishTest;
+
+ }
+
+ }
+
+
+ //
+ // Flush the rest of the FIFO.
+ //
+
+ for (i=0; i<4; i++) {
+
+ NdisRawReadPortUchar(pAdapter->MappedIoBaseAddr+NIC_FIFO, &Tmp);
+
+ }
+
+ }
+
+
+ //
+ // Stop the card.
+ //
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_COMMAND,
+ CR_STOP | CR_NO_DMA | CR_PAGE0);
+
+
+ //
+ // Set the TCR for internal loopback.
+ //
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_XMIT_CONFIG, 0x00);
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_XMIT_CONFIG,
+ TCR_INHIBIT_CRC | TCR_NIC_LBK);
+
+ //
+ // Restart the card.
+ //
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE0);
+
+
+
+ //
+ // Second round of tests -- CRC and Address recognition logic
+ //
+
+ for (SecondTest = 0; SecondTest < 3; ++SecondTest) {
+
+ //
+ // See if the destination address should be valid.
+ //
+
+ if (GoodAddress[SecondTest]) {
+
+ ELNKII_MOVE_MEM(TestPacket, pAdapter->StationAddress, ETH_LENGTH_OF_ADDRESS);
+
+ } else {
+
+ ELNKII_MOVE_MEM(TestPacket, NullAddress, ETH_LENGTH_OF_ADDRESS);
+
+ }
+
+
+ //
+ // Copy down TestPacket.
+ //
+
+ CardCopyDownBuffer(pAdapter, TestPacket, 0, 0, TEST_LEN);
+
+
+ //
+ // Copy down a good or bad CRC, as needed.
+ //
+
+ CardGetPacketCrc(TestPacket, TEST_LEN, CrcBuf);
+
+ if (!GoodCrc[SecondTest]) {
+
+ CrcBuf[0] = (UCHAR)(CrcBuf[0] ^ 0xff); // intentionally make it bad
+
+ }
+
+ CardCopyDownBuffer(pAdapter, CrcBuf, 0, TEST_LEN, 4);
+
+
+ //
+ // Start the transmission.
+ //
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_XMIT_START, pAdapter->NicXmitStart);
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_XMIT_COUNT_MSB, MSB(TEST_LEN+4));
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_XMIT_COUNT_LSB, LSB(TEST_LEN+4));
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_COMMAND,
+ CR_START | CR_XMIT | CR_NO_DMA);
+
+
+ //
+ // Wait for the transmission to complete, for about a second.
+ //
+
+ TimerExpired=FALSE;
+
+ NdisMInitializeTimer(
+ &Timer,
+ pAdapter->MiniportAdapterHandle,
+ DelayComplete,
+ &TimerExpired
+ );
+
+ NdisMSetTimer(&Timer, 1000);
+
+ NdisRawReadPortUchar(pAdapter->MappedIoBaseAddr+NIC_INTR_STATUS, &Tmp);
+ while (!(Tmp & (ISR_XMIT | ISR_XMIT_ERR))) {
+
+ if (TimerExpired) {
+
+ IF_TEST( DbgPrint("F%d: TEST reset timed out\n", FirstTest);)
+
+ FinalResult = FALSE;
+
+ goto FinishTest;
+
+ }
+
+ NdisRawReadPortUchar(pAdapter->MappedIoBaseAddr+NIC_INTR_STATUS, &Tmp);
+
+ }
+
+ //
+ //MUST Cancel the unexpired timer
+ //
+
+ NdisMCancelTimer(&Timer, &dummy);
+
+ //
+ // Acknowledge the interrupt.
+ //
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_INTR_STATUS,
+ ISR_XMIT | ISR_XMIT_ERR);
+
+
+ //
+ // Check that RSR is as expected.
+ //
+
+ NdisRawReadPortUchar(pAdapter->MappedIoBaseAddr+NIC_RCV_STATUS, &RSRResult);
+
+ if ((UCHAR)(RSRResult & (RSR_PACKET_OK | RSR_CRC_ERROR)) !=
+ RSRWanted[SecondTest]) {
+
+ IF_TEST( DbgPrint("S%d: Bad RSR: wanted %x got %x\n", SecondTest,
+ RSRWanted[SecondTest], RSRResult);)
+
+ FinalResult = FALSE;
+
+ goto FinishTest;
+
+ }
+
+ }
+
+
+
+ //
+ // Third round of tests - copying data to and from the card.
+ //
+
+ //
+ // First put data in the buffer.
+ //
+
+ for (i=0; i<256; i++) {
+
+ TestSrcBuf[i] = (UCHAR)(256-i);
+
+ }
+
+ //
+ // Loop through all the card memory in 256-byte pieces.
+ //
+
+ for (CurTestLoc = 0; CurTestLoc < (PUCHAR)0x2000; CurTestLoc += 256) {
+
+ //
+ // Copy the data down (have to play around with buffer
+ // numbers and offsets to put it in the right place).
+ //
+
+ CardCopyDownBuffer(pAdapter, TestSrcBuf,
+ (XMIT_BUF)((ULONG)CurTestLoc / TX_BUF_SIZE),
+ (ULONG)CurTestLoc % TX_BUF_SIZE, 256);
+
+ //
+ // Clear the destination buffer and read it back.
+ //
+
+ for (i=0; i<256; i++) {
+
+ TestDestBuf[i] = 77;
+
+ }
+
+ CardCopyUp(pAdapter, TestDestBuf,
+ pAdapter->XmitStart + (ULONG)CurTestLoc, 256);
+
+ //
+ // Make sure that the data matches.
+ //
+
+ for (i=0; i<256; i++) {
+
+ if (TestSrcBuf[i] != TestDestBuf[i]) {
+
+ IF_TEST( DbgPrint("T: Bad data at %lx\n", (ULONG)(CurTestLoc+i));)
+
+ FinalResult = FALSE;
+
+ goto FinishTest;
+
+ }
+
+ }
+
+ }
+
+
+
+ //
+ // FinishTest: jump here to exit the tests cleanly.
+ //
+
+FinishTest:
+
+ //
+ // Stop the card.
+ //
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_COMMAND,
+ CR_STOP | CR_NO_DMA | CR_PAGE0);
+
+
+ //
+ // Restore DCR, RCR, and TCR.
+ //
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_DATA_CONFIG,
+ DCR_BYTE_WIDE | DCR_NORMAL | DCR_FIFO_8_BYTE);
+
+ //
+ // (clear these two to be safe)
+ //
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_RMT_COUNT_MSB, 0);
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_RMT_COUNT_LSB, 0);
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_RCV_CONFIG, pAdapter->NicReceiveConfig);
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_XMIT_CONFIG, TCR_LOOPBACK);
+
+ //
+ // The reconfiguring of the config registers can cause the xmit to complete
+ // if the test was a failure. Therefore, we pause here to allow the xmit
+ // to complete so that we can ACK it below - leaving the card in a valid state.
+ //
+
+ NdisStallExecution(50000);
+
+ //
+ // Acknowledge any interrupts that are floating around.
+ //
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_INTR_STATUS, 0xff);
+
+
+ //
+ // Start the card, but stay in loopback mode.
+ //
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE0);
+
+
+
+ return FinalResult;
+}
+
+
+
+
+BOOLEAN CardCopyDownPacket(
+ IN PELNKII_ADAPTER pAdapter,
+ IN PNDIS_PACKET Packet,
+ IN XMIT_BUF XmitBufferNum,
+ OUT UINT *Length
+)
+
+/*++
+
+Routine Description:
+
+ Copies the packet Packet down starting at the beginning of
+ transmit buffer XmitBufferNum, fills in Length to be the
+ length of the packet. It uses memory mapping or programmed
+ I/O as appropriate.
+
+Arguments:
+
+ pAdapter - pointer to the adapter block
+ Packet - the packet to copy down
+ XmitBufferNum - the transmit buffer number
+
+Return Value:
+
+ Length - the length of the data in the packet in bytes.
+ TRUE if the transfer completed with no problems.
+
+--*/
+
+{
+ PUCHAR CurAddress;
+ PUCHAR BufAddress;
+ UINT CurLength;
+ UINT Len;
+ PNDIS_BUFFER CurBuffer;
+ UINT TmpLen;
+ UINT BurstSize;
+ UCHAR GaStatus;
+
+ //
+ // Is the card memory mapped?
+ //
+ if (pAdapter->MemMapped)
+ {
+ //
+ // Memory mapped, just copy each buffer over.
+ //
+ NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, NULL);
+
+ CurAddress = pAdapter->XmitStart + XmitBufferNum * TX_BUF_SIZE;
+
+ CurLength = 0;
+
+ while (CurBuffer)
+ {
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufAddress, &Len);
+
+ ELNKII_MOVE_MEM_TO_SHARED_RAM(CurAddress, BufAddress, Len);
+
+ CurAddress += Len;
+
+ CurLength += Len;
+
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+ }
+
+ *Length = CurLength;
+ }
+ else
+ {
+ //
+ // Programmed I/O, have to transfer the data.
+ //
+ NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, NULL);
+
+ CurAddress = (PUCHAR)0x2000 + XmitBufferNum * TX_BUF_SIZE;
+
+ CurLength = 0;
+
+ while (CurBuffer)
+ {
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufAddress, &Len);
+
+ if (Len == 0)
+ {
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+ continue;
+ }
+
+ //
+ // Set up the Gate Array for programmed I/O transfer.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_DMA_ADDR_MSB,
+ MSB((ULONG)CurAddress)
+ );
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_DMA_ADDR_LSB,
+ LSB((ULONG)CurAddress)
+ );
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_CONTROL,
+ (UCHAR)((CTRL_START | CTRL_DIR_DOWN) | pAdapter->GaControlBits)
+ );
+
+
+ //
+ // First transfer multiples of DMA_BURST_SIZE.
+ //
+ TmpLen = Len;
+ BurstSize = DMA_BURST_SIZE;
+
+ while (TmpLen >= BurstSize)
+ {
+ if ((ULONG)BufAddress & 0x01)
+ {
+ NdisRawWritePortBufferUchar(
+ pAdapter->MappedGaBaseAddr + GA_REG_FILE_MSB,
+ (PUCHAR)BufAddress,
+ BurstSize
+ );
+ }
+ else
+ {
+ NdisRawWritePortBufferUshort(
+ pAdapter->MappedGaBaseAddr + GA_REG_FILE_MSB,
+ (PUSHORT)BufAddress,
+ BurstSize / 2
+ );
+ }
+
+
+ TmpLen -= BurstSize;
+
+ BufAddress += BurstSize;
+
+ //
+ // Wait for the Gate Array FIFO to be ready.
+ //
+ do
+ {
+ NdisRawReadPortUchar(pAdapter->MappedGaBaseAddr+GA_STATUS, &GaStatus);
+
+ if (GaStatus & (STREG_UNDERFLOW | STREG_OVERFLOW))
+ {
+#if DBG
+ DbgPrint("DATA PORT READY ERROR IN ELNKII - CCDP\n");
+ DbgPrint("\tStatus = 0x%x, BurstSize = 0x%x, PrevBurstSize = 0x%x\n",
+ GaStatus, BurstSize, PrevBurstSize);
+#endif
+
+ NdisWriteErrorLogEntry(
+ pAdapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ cardCopyDownPacket,
+ ELNKII_ERRMSG_DATA_PORT_READY
+ );
+
+ return(FALSE);
+ }
+
+ } while (!(GaStatus & STREG_DP_READY));
+
+#if DBG
+ PrevBurstSize = (UCHAR)BurstSize;
+#endif
+ }
+
+ //
+ // Now copy the last bit as UCHARs.
+ //
+ NdisRawWritePortBufferUchar(
+ pAdapter->MappedGaBaseAddr + GA_REG_FILE_MSB,
+ BufAddress,
+ TmpLen
+ );
+
+ do
+ {
+ NdisRawReadPortUchar(
+ pAdapter->MappedGaBaseAddr + GA_STATUS,
+ &GaStatus
+ );
+
+ if (GaStatus & (STREG_UNDERFLOW | STREG_OVERFLOW))
+ {
+#if DBG
+ DbgPrint("DATA PORT READY ERROR IN ELNKII - CCDPII\n");
+ DbgPrint("\tStatus = 0x%x, BurstSize = 0x%x, PrevBurstSize = 0x%x\n",
+ GaStatus, BurstSize, PrevBurstSize);
+#endif
+
+ NdisWriteErrorLogEntry(
+ pAdapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ cardCopyDownPacket,
+ ELNKII_ERRMSG_DATA_PORT_READY
+ );
+
+ return FALSE;
+ }
+
+ } while (!(GaStatus & STREG_DP_READY));
+
+
+#if DBG
+ PrevBurstSize = (UCHAR)TmpLen;
+#endif
+
+ //
+ // Done, turn off the start bit...
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_CONTROL,
+ (UCHAR)(CTRL_STOP | pAdapter->GaControlBits)
+ );
+
+ //
+ // ... and wait for DMA_IN_PROGRESS to go off,
+ // indicating end of flush.
+ //
+ do
+ {
+ NdisRawReadPortUchar(
+ pAdapter->MappedGaBaseAddr + GA_STATUS,
+ &GaStatus
+ );
+ } while (GaStatus & STREG_IN_PROG);
+
+ CurAddress += Len;
+
+ CurLength += Len;
+
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+ }
+
+ *Length = CurLength;
+ }
+
+ return(TRUE);
+}
+
+
+BOOLEAN CardCopyDownBuffer(
+ IN PELNKII_ADAPTER pAdapter,
+ IN PUCHAR SourceBuffer,
+ IN XMIT_BUF XmitBufferNum,
+ IN UINT Offset,
+ IN UINT Length
+)
+
+/*++
+
+Routine Description:
+
+ Copies down one character buffer (rather than an
+ entire packet), starting at offset Offset, for Length
+ bytes. It uses memory mapping or programmed I/O as
+ appropriate. This function is used for blanking the padding
+ at the end of short packets and also for loopback testing.
+
+Arguments:
+
+ pAdapter - pointer to the adapter block
+ SourceBuffer - the source data to be copied down
+ XmitBufferNum - the transmit buffer number
+ Offset - the offset from the start of the transmit buffer
+ Length - the number of bytes to blank out
+
+Return Value:
+
+ Length - the length of the data in the packet in bytes.
+ TRUE if the transfer completed with no problems.
+
+--*/
+
+{
+ PUCHAR CurAddress;
+ UINT TmpLen;
+ UINT ThisTime;
+ UCHAR GaStatus;
+
+ if (pAdapter->MemMapped)
+ {
+ //
+ // Memory mapped, just copy over SourceBuffer.
+ //
+ CurAddress = pAdapter->XmitStart + XmitBufferNum * TX_BUF_SIZE + Offset;
+
+ ELNKII_MOVE_MEM_TO_SHARED_RAM(CurAddress, SourceBuffer, Length);
+ }
+ else
+ {
+ //
+ // Programmed I/O, have to transfer the data.
+ //
+ CurAddress = (PUCHAR)0x2000 + XmitBufferNum*TX_BUF_SIZE + Offset;
+
+ //
+ // Set up the Gate Array for programmed I/O transfer.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_DMA_ADDR_MSB,
+ MSB((ULONG)CurAddress)
+ );
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_DMA_ADDR_LSB,
+ LSB((ULONG)CurAddress)
+ );
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_CONTROL,
+ (UCHAR)((CTRL_START | CTRL_DIR_DOWN) | pAdapter->GaControlBits)
+ );
+
+ //
+ // Copy the data down in DMA_BURST_SIZE bursts.
+ //
+ TmpLen = Length;
+
+ while (TmpLen > 0)
+ {
+ ThisTime = (TmpLen >= DMA_BURST_SIZE) ? DMA_BURST_SIZE : TmpLen;
+
+ NdisRawWritePortBufferUchar(
+ pAdapter->MappedGaBaseAddr + GA_REG_FILE_MSB,
+ SourceBuffer,
+ ThisTime
+ );
+
+ TmpLen -= ThisTime;
+
+ SourceBuffer += ThisTime;
+
+ //
+ // Wait for the Gate Array FIFO to be ready.
+ //
+ do
+ {
+ NdisRawReadPortUchar(
+ pAdapter->MappedGaBaseAddr + GA_STATUS,
+ &GaStatus
+ );
+
+ if (GaStatus & (STREG_UNDERFLOW | STREG_OVERFLOW))
+ {
+#if DBG
+ DbgPrint("DATA PORT READY ERROR IN ELNKII - CCDB\n");
+ DbgPrint(
+ "\tStatus = 0x%x, BurstSize = 0x%x, "
+ "PrevBurstSize = 0x%x\n",
+ GaStatus,
+ ThisTime,
+ PrevBurstSize
+ );
+#endif
+
+ NdisWriteErrorLogEntry(
+ pAdapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ cardCopyDownBuffer,
+ ELNKII_ERRMSG_DATA_PORT_READY
+ );
+
+ return(FALSE);
+ }
+ } while (!(GaStatus & STREG_DP_READY));
+
+#if DBG
+ PrevBurstSize = (UCHAR)ThisTime;
+#endif
+ }
+
+ //
+ // Done, turn off the start bit..
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_CONTROL,
+ (UCHAR)(CTRL_STOP | pAdapter->GaControlBits)
+ );
+
+ //
+ // ... and wait for DMA_IN_PROGRESS to go off,
+ // indicating end of flush.
+ //
+
+ do
+ {
+ NdisRawReadPortUchar(
+ pAdapter->MappedGaBaseAddr + GA_STATUS,
+ &GaStatus
+ );
+ } while (GaStatus & STREG_IN_PROG);
+ }
+
+#if DBG
+ IF_ELNKIIDEBUG( ELNKII_DEBUG_TRACK_PACKET_LENS )
+ {
+ if (Offset == 18 && Length == 42)
+ {
+ UINT i;
+
+ for (i = 0; i < 20; i++)
+ {
+ SourceBuffer[i] = ' ';
+ }
+ }
+ }
+#endif
+
+ return(TRUE);
+}
+
+
+
+
+BOOLEAN CardCopyUp(
+ IN PELNKII_ADAPTER pAdapter,
+ IN PUCHAR Target,
+ IN PUCHAR Source,
+ IN UINT Length
+)
+
+/*++
+
+Routine Description:
+
+ Copies data from the card to memory. It uses memory mapping
+ or programmed I/O as appropriate.
+
+Arguments:
+
+ pAdapter - pointer to the adapter block
+ Target - the target address
+ Source - the source address (on the card)
+ Length - the number of bytes to copy
+
+Return Value:
+
+ TRUE if the transfer completed with no problems.
+
+--*/
+
+{
+ UINT TmpLen;
+ UINT BurstSize;
+ UCHAR GaStatus;
+
+ if (Length == 0)
+ return(TRUE);
+
+ if (pAdapter->MemMapped)
+ {
+ //
+ // Memory mapped, just copy the data over.
+ //
+ ELNKII_MOVE_SHARED_RAM_TO_MEM(Target, Source, Length);
+ }
+ else
+ {
+ //
+ // Programmed I/O, have to transfer the data.
+ //
+
+ //
+ // Adjust the address to be a card address.
+ //
+ Source -= ((ULONG)pAdapter->XmitStart - 0x2000);
+
+ //
+ // Set up the Gate Array for programmed I/O transfer.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_DMA_ADDR_MSB,
+ MSB((ULONG)Source)
+ );
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_DMA_ADDR_LSB,
+ LSB((ULONG)Source)
+ );
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_CONTROL,
+ (UCHAR)((CTRL_START | CTRL_DIR_UP) | pAdapter->GaControlBits)
+ );
+
+
+ //
+ // First copy multiples of DMA_BURST_SIZE as USHORTs.
+ //
+ TmpLen = Length;
+ BurstSize = DMA_BURST_SIZE;
+
+ //
+ // Before doing this, transfer one byte if needed to
+ // align on a USHORT boundary.
+ //
+ while (TmpLen >= BurstSize)
+ {
+ //
+ // First wait for the Gate Array FIFO to be ready.
+ //
+ do
+ {
+ NdisRawReadPortUchar(
+ pAdapter->MappedGaBaseAddr + GA_STATUS,
+ &GaStatus
+ );
+
+ if (GaStatus & (STREG_UNDERFLOW | STREG_OVERFLOW))
+ {
+#if DBG
+ DbgPrint("DATA PORT READY ERROR IN ELNKII - CCU\n");
+ DbgPrint(
+ "\tStatus = 0x%x, BurstSize = 0x%x, "
+ "PrevBurstSize = 0x%x\n",
+ GaStatus,
+ PrevBurstSize,
+ PrevPrevBurstSize
+ );
+#endif
+
+ NdisWriteErrorLogEntry(
+ pAdapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ cardCopyUp,
+ ELNKII_ERRMSG_DATA_PORT_READY
+ );
+
+ return(FALSE);
+ }
+ } while (!(GaStatus & STREG_DP_READY));
+
+
+ if ((ULONG)Target & 0x01)
+ {
+ //
+ // This is the first burst, and it starts on
+ // an odd boundary.
+ //
+ NdisRawReadPortBufferUchar(
+ pAdapter->MappedGaBaseAddr + GA_REG_FILE_MSB,
+ (PUCHAR)Target,
+ BurstSize
+ );
+
+ TmpLen -= BurstSize;
+ Target += BurstSize;
+
+#if DBG
+ PrevPrevBurstSize = PrevBurstSize;
+ PrevBurstSize = (UCHAR)BurstSize;
+#endif
+ }
+ else
+ {
+ NdisRawReadPortBufferUshort(
+ pAdapter->MappedGaBaseAddr + GA_REG_FILE_MSB,
+ (PUSHORT)Target,
+ BurstSize / 2
+ );
+
+ TmpLen -= BurstSize;
+ Target += BurstSize;
+
+
+#if DBG
+ PrevPrevBurstSize = PrevBurstSize;
+ PrevBurstSize = (UCHAR)BurstSize;
+#endif
+ }
+ }
+
+ //
+ // Now copy the last bit of data as UCHARs.
+ //
+ do
+ {
+ NdisRawReadPortUchar(
+ pAdapter->MappedGaBaseAddr + GA_STATUS,
+ &GaStatus
+ );
+
+ if (GaStatus & (STREG_UNDERFLOW | STREG_OVERFLOW))
+ {
+#if DBG
+ DbgPrint("DATA PORT READY ERROR IN ELNKII - CCUII\n");
+ DbgPrint(
+ "\tStatus = 0x%x, BurstSize = 0x%x, "
+ "PrevBurstSize = 0x%x\n",
+ GaStatus,
+ BurstSize,
+ PrevBurstSize
+ );
+#endif
+
+ NdisWriteErrorLogEntry(
+ pAdapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ cardCopyUp,
+ ELNKII_ERRMSG_DATA_PORT_READY
+ );
+
+ return(FALSE);
+ }
+ } while (!(GaStatus & STREG_DP_READY));
+
+ NdisRawReadPortBufferUchar(
+ pAdapter->MappedGaBaseAddr + GA_REG_FILE_MSB,
+ Target,
+ TmpLen
+ );
+
+ //
+ // Done, turn off the start bit.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_CONTROL,
+ (UCHAR)(CTRL_STOP | pAdapter->GaControlBits)
+ );
+ }
+
+ return(TRUE);
+}
+
+ULONG
+CardComputeCrc(
+ IN PUCHAR Buffer,
+ IN UINT Length
+ )
+
+/*++
+
+Routine Description:
+
+ Runs the AUTODIN II CRC algorithm on buffer Buffer of
+ length Length.
+
+Arguments:
+
+ Buffer - the input buffer
+ Length - the length of Buffer
+
+Return Value:
+
+ The 32-bit CRC value.
+
+Note:
+
+ This is adapted from the comments in the assembly language
+ version in _GENREQ.ASM of the DWB NE1000/2000 driver.
+
+--*/
+
+{
+ ULONG Crc;
+ ULONG Carry;
+ UINT i;
+ UINT j;
+ UCHAR CurByte;
+
+ Crc = 0xffffffff;
+
+ for (i = 0; i < Length; i++)
+ {
+ CurByte = Buffer[i];
+
+ for (j = 0; j < 8; j++)
+ {
+ Carry = ((Crc & 0x80000000) ? 1 : 0) ^ (CurByte & 0x01);
+
+ Crc <<= 1;
+
+ CurByte >>= 1;
+
+ if (Carry)
+ Crc = (Crc ^ 0x04c11db6) | Carry;
+
+ }
+ }
+
+ return(Crc);
+}
+
+
+#pragma NDIS_INIT_FUNCTION(CardGetPacketCrc)
+
+VOID CardGetPacketCrc(
+ IN PUCHAR Buffer,
+ IN UINT Length,
+ OUT UCHAR Crc[4]
+)
+
+/*++
+
+Routine Description:
+
+ For a given Buffer, computes the packet CRC for it.
+ It uses CardComputeCrc to determine the CRC value, then
+ inverts the order and value of all the bits (I don't
+ know why this is necessary).
+
+Arguments:
+
+ Buffer - the input buffer
+ Length - the length of Buffer
+
+Return Value:
+
+ The CRC will be stored in Crc.
+
+--*/
+
+{
+ static UCHAR InvertBits[16] = { 0x0, 0x8, 0x4, 0xc,
+ 0x2, 0xa, 0x6, 0xe,
+ 0x1, 0x9, 0x5, 0xd,
+ 0x3, 0xb, 0x7, 0xf };
+ ULONG CrcValue;
+ UCHAR Tmp;
+ UINT i;
+
+ //
+ // First compute the CRC.
+ //
+ CrcValue = CardComputeCrc(Buffer, Length);
+
+
+ //
+ // Now invert the bits in the result.
+ //
+ for (i = 0; i < 4; i++)
+ {
+ Tmp = ((PUCHAR)&CrcValue)[3-i];
+
+ Crc[i] = (UCHAR)((InvertBits[Tmp >> 4] +
+ (InvertBits[Tmp & 0xf] << 4)) ^ 0xff);
+ }
+}
+
+
+VOID
+CardGetMulticastBit(
+ IN UCHAR Address[ETH_LENGTH_OF_ADDRESS],
+ OUT UCHAR * Byte,
+ OUT UCHAR * Value
+ )
+
+/*++
+
+Routine Description:
+
+ For a given multicast address, returns the byte and bit in
+ the card multicast registers that it hashes to. Calls
+ CardComputeCrc() to determine the CRC value.
+
+Arguments:
+
+ Address - the address
+ Byte - the byte that it hashes to
+ Value - will have a 1 in the relevant bit
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Crc;
+ UINT BitNumber;
+
+ //
+ // First compute the CRC.
+ //
+ Crc = CardComputeCrc(Address, ETH_LENGTH_OF_ADDRESS);
+
+
+ //
+ // The bit number is now in the 6 most significant bits of CRC.
+ //
+ BitNumber = (UINT)((Crc >> 26) & 0x3f);
+
+ *Byte = (UCHAR)(BitNumber / 8);
+ *Value = (UCHAR)((UCHAR)1 << (BitNumber % 8));
+}
+
+VOID CardFillMulticastRegs(
+ IN PELNKII_ADAPTER pAdapter
+)
+
+/*++
+
+Routine Description:
+
+ Erases and refills the card multicast registers. Used when
+ an address has been deleted and all bits must be recomputed.
+
+Arguments:
+
+ pAdapter - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UINT i;
+ UCHAR Byte;
+ UCHAR Bit;
+
+ //
+ // First turn all bits off.
+ //
+ for (i = 0; i < 8; i++)
+ pAdapter->NicMulticastRegs[i] = 0;
+
+ //
+ // Now turn on the bit for each address in the multicast list.
+ //
+ for ( ; i > 0; )
+ {
+ i--;
+
+ CardGetMulticastBit(Addresses[i], &Byte, &Bit);
+
+ pAdapter->NicMulticastRegs[Byte] |= Bit;
+ }
+}
+
+
+VOID CardStartXmit(
+ IN PELNKII_ADAPTER pAdapter
+)
+
+/*++
+
+Routine Description:
+
+ Sets the NIC_COMMAND register to start a transmission.
+ The transmit buffer number is taken from pAdapter->CurBufXmitting
+ and the length from pAdapter->PacketLens[pAdapter->CurBufXmitting].
+
+Arguments:
+
+ pAdapter - pointer to the adapter block
+
+Return Value:
+
+ TRUE if the power has failed.
+
+--*/
+
+{
+ XMIT_BUF XmitBufferNum = pAdapter->CurBufXmitting;
+ UINT Length = pAdapter->PacketLens[XmitBufferNum];
+ UCHAR Tmp;
+
+ //
+ // Prepare the NIC registers for transmission.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_XMIT_START,
+ (UCHAR)(pAdapter->NicXmitStart + (UCHAR)(XmitBufferNum * BUFS_PER_TX))
+ );
+
+ //
+ // Pad the length to 60 (plus CRC will be 64) if needed.
+ //
+
+ if (Length < 60)
+ Length = 60;
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_XMIT_COUNT_MSB,
+ MSB(Length)
+ );
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_XMIT_COUNT_LSB,
+ LSB(Length)
+ );
+
+ //
+ // Start transmission, check for power failure first.
+ //
+ NdisRawReadPortUchar(pAdapter->MappedIoBaseAddr + NIC_COMMAND, &Tmp);
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_COMMAND,
+ CR_START | CR_XMIT | CR_NO_DMA
+ );
+
+ IF_LOG( ElnkiiLog('x');)
+}
+
+
+BOOLEAN SyncCardGetXmitStatus(
+ IN PVOID SynchronizeContext
+)
+
+/*++
+
+Routine Description:
+
+ Gets the value of the "transmit status" NIC register and stores
+ it in pAdapter->XmitStatus.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER pAdapter = (PELNKII_ADAPTER)SynchronizeContext;
+
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_XMIT_STATUS,
+ &pAdapter->XmitStatus
+ );
+
+ return(FALSE);
+}
+
+
+BOOLEAN SyncCardGetCurrent(
+ IN PVOID SynchronizeContext
+)
+
+/*++
+
+Routine Description:
+
+ Gets the value of the CURRENT NIC register and stores
+ it in pAdapter->Current.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER pAdapter = ((PELNKII_ADAPTER)SynchronizeContext);
+
+ //
+ // Have to go to page 1 to read this register.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE1
+ );
+
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_CURRENT,
+ &pAdapter->Current
+ );
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE0
+ );
+
+ return(FALSE);
+}
+
+VOID CardSetBoundary(
+ IN PELNKII_ADAPTER pAdapter
+)
+
+/*++
+
+Routine Description:
+
+ Sets the value of the "boundary" NIC register to one behind
+ pAdapter->NicNextPacket, to prevent packets from being received
+ on top of un-indicated ones.
+
+Arguments:
+
+ pAdapter - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Have to be careful with "one behind NicNextPacket" when
+ // NicNextPacket is the first buffer in receive area.
+ //
+ if (pAdapter->NicNextPacket == pAdapter->NicPageStart)
+ {
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_BOUNDARY,
+ (UCHAR)(pAdapter->NicPageStop - (UCHAR)1)
+ );
+ }
+ else
+ {
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_BOUNDARY,
+ (UCHAR)(pAdapter->NicNextPacket - (UCHAR)1)
+ );
+ }
+}
+
+
+BOOLEAN SyncCardSetReceiveConfig(
+ IN PELNKII_ADAPTER pAdapter
+)
+
+/*++
+
+Routine Description:
+
+ Sets the value of the "receive configuration" NIC register to
+ the value of pAdapter->NicReceiveConfig.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_RCV_CONFIG,
+ pAdapter->NicReceiveConfig
+ );
+
+ return(FALSE);
+}
+
+
+BOOLEAN SyncCardSetAllMulticast(
+ IN PELNKII_ADAPTER pAdapter
+)
+
+/*++
+
+Routine Description:
+
+ Turns on all the bits in the multicast register. Used when
+ the card must receive all multicast packets.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UINT i;
+
+ //
+ // Have to move to page 1 to set these registers.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE1
+ );
+
+ for (i = 0; i < 8; i++)
+ {
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + (NIC_MC_ADDR + i),
+ 0xff
+ );
+ }
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE0
+ );
+
+ return(FALSE);
+}
+
+
+BOOLEAN SyncCardCopyMulticastRegs(
+ IN PELNKII_ADAPTER pAdapter
+)
+
+/*++
+
+Routine Description:
+
+ Sets the eight bytes in the card multicast registers.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UINT i;
+
+ //
+ // Have to move to page 1 to set these registers.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE1
+ );
+
+ for (i = 0; i < 8; i++)
+ {
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + (NIC_MC_ADDR + i),
+ pAdapter->NicMulticastRegs[i]
+ );
+ }
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE0
+ );
+
+ return(FALSE);
+
+}
+
+BOOLEAN
+SyncCardSetInterruptMask(
+ IN PVOID SynchronizeContext
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the "interrupt mask" register of the NIC to the value of
+ pAdapter->NicInterruptMask.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER pAdapter = ((PELNKII_ADAPTER)SynchronizeContext);
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_MASK,
+ pAdapter->NicInterruptMask
+ );
+
+ return(FALSE);
+}
+
+
+BOOLEAN SyncCardAcknowledgeReceive(
+ IN PVOID SynchronizeContext
+)
+
+/*++
+
+Routine Description:
+
+ Sets the "packet received" bit in the NIC interrupt status register,
+ which re-enables interrupts of that type.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER pAdapter = ((PELNKII_ADAPTER)SynchronizeContext);
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_STATUS,
+ ISR_RCV
+ );
+
+ //
+ // Interrupts were previously blocked in the interrupt handler.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_MASK,
+ pAdapter->NicInterruptMask
+ );
+
+ return(FALSE);
+}
+
+
+BOOLEAN SyncCardAcknowledgeOverflow(
+ IN PVOID SynchronizeContext
+)
+
+/*++
+
+Routine Description:
+
+ Sets the "buffer overflow" bit in the NIC interrupt status register,
+ which re-enables interrupts of that type.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER pAdapter = ((PELNKII_ADAPTER)SynchronizeContext);
+ UCHAR InterruptStatus;
+
+ CardGetInterruptStatus(pAdapter, &InterruptStatus);
+
+ if (InterruptStatus & ISR_RCV_ERR)
+ SyncCardUpdateCounters(pAdapter);
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_STATUS,
+ ISR_OVERFLOW
+ );
+
+ return(FALSE);
+}
+
+
+BOOLEAN SyncCardAcknowledgeTransmit(
+ IN PVOID SynchronizeContext
+)
+
+/*++
+
+Routine Description:
+
+ Sets the "packet transmitted" bit in the NIC interrupt status register,
+ which re-enables interrupts of that type.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER pAdapter = ((PELNKII_ADAPTER)SynchronizeContext);
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_STATUS,
+ ISR_XMIT | ISR_XMIT_ERR
+ );
+
+ //
+ // Interrupts were previously blocked in the interrupt handler.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_MASK,
+ pAdapter->NicInterruptMask
+ );
+
+ return(FALSE);
+}
+
+
+BOOLEAN SyncCardAckAndGetCurrent(
+ IN PVOID SynchronizeContext
+ )
+
+/*++
+
+Routine Description:
+
+ Performs the functions of SyncCardAcknowledgeReceive followed by
+ SyncCardGetCurrent (since the two are always called
+ one after the other).
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER pAdapter = ((PELNKII_ADAPTER)SynchronizeContext);
+
+ //
+ // SyncCardAcknowledgeReceive.
+ //
+
+#ifdef i386
+
+ __asm cli
+
+#endif
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_STATUS,
+ ISR_RCV
+ );
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_MASK,
+ pAdapter->NicInterruptMask
+ );
+
+#ifdef i386
+
+ __asm sti
+
+#endif
+
+ //
+ // SyncCardGetCurrent.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE1
+ );
+
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_CURRENT,
+ &pAdapter->Current
+ );
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE0
+ );
+
+ return(FALSE);
+}
+
+
+BOOLEAN SyncCardGetXmitStatusAndAck(
+ IN PVOID SynchronizeContext
+)
+
+/*++
+
+Routine Description:
+
+ Performs the functions of SyncCardGetXmitStatus followed by
+ SyncCardAcknowledgeTransmit (since the two are always
+ called one after the other).
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER pAdapter = ((PELNKII_ADAPTER)SynchronizeContext);
+
+ //
+ // SyncCardGetXmitStatus.
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_XMIT_STATUS,
+ &pAdapter->XmitStatus
+ );
+
+ //
+ // SyncCardAcknowledgeTransmit.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_STATUS,
+ ISR_XMIT | ISR_XMIT_ERR
+ );
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_MASK,
+ pAdapter->NicInterruptMask
+ );
+
+ return(FALSE);
+}
+
+
+BOOLEAN SyncCardUpdateCounters(
+ IN PVOID SynchronizeContext
+)
+
+/*++
+
+Routine Description:
+
+ Updates the values of the three counters (frame alignment errors,
+ CRC errors, and missed packets).
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER pAdapter = ((PELNKII_ADAPTER)SynchronizeContext);
+ UCHAR Tmp;
+
+ NdisRawReadPortUchar(pAdapter->MappedIoBaseAddr + NIC_FAE_ERR_CNTR, &Tmp);
+ pAdapter->FrameAlignmentErrors += Tmp;
+
+ NdisRawReadPortUchar(pAdapter->MappedIoBaseAddr + NIC_CRC_ERR_CNTR, &Tmp);
+ pAdapter->CrcErrors += Tmp;
+
+ NdisRawReadPortUchar(pAdapter->MappedIoBaseAddr + NIC_MISSED_CNTR, &Tmp);
+ pAdapter->MissedPackets += Tmp;
+
+ return(FALSE);
+}
+
+BOOLEAN SyncCardHandleOverflow(
+ IN PVOID SynchronizeContext
+)
+
+/*++
+
+Routine Description:
+
+ Sets all the flags for dealing with a receive overflow, stops the card
+ and acknowledges all outstanding interrupts.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER pAdapter = (PELNKII_ADAPTER)SynchronizeContext;
+ UCHAR InterruptStatus;
+
+ IF_LOG( ElnkiiLog('F');)
+
+ //
+ // This is a copy of CardStop(). This is changed in minor ways since
+ // we are already synchornized with interrupts.
+ //
+
+ //
+ // Turn on the STOP bit in the Command register.
+ //
+ SyncCardStop(pAdapter);
+
+ //
+ // Wait for ISR_RESET, but only for 1.6 milliseconds (as
+ // described in the March 1991 8390 addendum), since that
+ // is the maximum time for a software reset to occur.
+ //
+ //
+ NdisStallExecution(2000);
+
+ //
+ // Save whether we were transmitting to avoid a timing problem
+ // where an indication resulted in a send.
+ //
+ if (!(pAdapter->InterruptStatus & (ISR_XMIT | ISR_XMIT_ERR)))
+ {
+ CardGetInterruptStatus(pAdapter, &InterruptStatus);
+ if (!(InterruptStatus & (ISR_XMIT | ISR_XMIT_ERR)))
+ {
+ pAdapter->OverflowRestartXmitDpc = pAdapter->TransmitInterruptPending;
+
+ IF_LOUD(DbgPrint("ORXD=%x\n", pAdapter->OverflowRestartXmitDpc);)
+ }
+ }
+
+ //
+ // Clear the Remote Byte Count register so that ISR_RESET
+ // will come on.
+ //
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr + NIC_RMT_COUNT_MSB, 0);
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr + NIC_RMT_COUNT_LSB, 0);
+
+ //
+ // According to National Semiconductor, the next check is necessary
+ // See Step 5. of the overflow process
+ //
+ // NOTE: The setting of variables to check if the transmit has completed
+ // cannot be done here because anything in the ISR has already been ack'ed
+ // inside the main DPC. Thus, the setting of the variables, described in
+ // the Handbook was moved to the main DPC.
+ //
+ // Continued: If you did the check here, you will doubly transmit most
+ // packets that happened to be on the card when the overflow occurred.
+ //
+
+ //
+ // Put the card in loopback mode, then start it.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_XMIT_CONFIG,
+ TCR_LOOPBACK
+ );
+
+ //
+ // Start the card. This does not Undo the loopback mode.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_COMMAND,
+ CR_START | CR_NO_DMA
+ );
+
+ return(FALSE);
+}
+
+
+
+#if DBG
+//
+// Following function is for debug stuff.
+//
+VOID ElnkiiDisplayStatus(
+ PELNKII_ADAPTER pAdapter
+)
+{
+ //
+ // NIC registers that we can read.
+ //
+ UCHAR NicXmitStatus; // NIC_XMIT_STATUS
+ UCHAR NicFifo; // NIC_FIFO
+ UCHAR NicInterruptStatus; // NIC_INTR_STATUS
+ UCHAR NicCurrent; // NIC_CURRENT
+ UCHAR NicReceiveStatus; // NIC_RCV_STATUS
+ UCHAR NicFrameErrorCounter; // NIC_FAE_ERR_CNTR
+ UCHAR NicCrcErrorCounter; // NIC_CRC_ERR_CNTR
+ UCHAR NicMissedCounter; // NIC_MISSED_CNTR
+
+ //
+ // Gate-Array registers that we can read.
+ //
+ UCHAR GaPageStart; // GA_PAGE_START
+ UCHAR GaPageStop; // GA_PAGE_STOP
+ UCHAR GaDrqTimer; // GA_DRQ_TIMER
+ UCHAR GaIoBase; // GA_IO_BASE
+ UCHAR GaMemoryBase; // GA_MEM_BASE
+ UCHAR GaConfig; // GA_CONFIG
+ UCHAR GaControl; // GA_CONTROL
+ UCHAR GaStatus; // GA_STATUS
+ UCHAR GaIntDmaConfig; // GA_INT_DMA_CONFIG
+ UCHAR GaDmaAddressMsb; // GA_DMA_ADDR_MSB
+ UCHAR GaDmaAddressLsb; // GA_DMA_ADDR_LSB
+ UCHAR GaRegFileAccessMsb; // GA_REG_FILE_MSB
+ UCHAR GaRegFileAccessLsb; // GA_REG_FILE_LSB
+
+ //
+ // Get the NIC xmit status
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_XMIT_STATUS,
+ &NicXmitStatus
+ );
+
+ //
+ // Display NIC status information.
+ //
+ DbgPrint(
+ "NIC_XMIT_STATUS: TSR_XMIT_OK - %x\n"
+ " TSR_COLLISION - %x\n"
+ " TSR_ABORTED - %x\n"
+ " TSR_NO_CARRIER - %x\n"
+ " TSR_NO_CDH - %x\n",
+ NicXmitStatus & TSR_XMIT_OK,
+ NicXmitStatus & TSR_COLLISION,
+ NicXmitStatus & TSR_ABORTED,
+ NicXmitStatus & TSR_NO_CARRIER,
+ NicXmitStatus & TSR_NO_CDH
+ );
+
+ //
+ // Get the nic fifo
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_FIFO,
+ &NicFifo
+ );
+
+ DbgPrint("NIC_FIFO: %x\n", NicFifo);
+
+ //
+ // Get the nic interrupt status
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_STATUS,
+ &NicInterruptStatus
+ );
+
+ DbgPrint(
+ "NIC_INTR_STATUS: ISR_EMPTY - %x\n"
+ " ISR_RCV - %x\n"
+ " ISR_XMIT - %x\n"
+ " ISR_RCV_ERR - %x\n"
+ " ISR_XMIT_ERR - %x\n"
+ " ISR_OVERFLOW - %x\n"
+ " ISR_COUNTER - %x\n"
+ " ISR_RESET - %x\n",
+ NicInterruptStatus & ISR_EMPTY,
+ NicInterruptStatus & ISR_RCV,
+ NicInterruptStatus & ISR_XMIT,
+ NicInterruptStatus & ISR_RCV_ERR,
+ NicInterruptStatus & ISR_XMIT_ERR,
+ NicInterruptStatus & ISR_OVERFLOW,
+ NicInterruptStatus & ISR_COUNTER,
+ NicInterruptStatus & ISR_RESET
+ );
+
+
+ //
+ // Get the nic current
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_CURRENT,
+ &NicCurrent
+ );
+
+ DbgPrint("NIC_CURRENT: %x\n", NicCurrent);
+
+ //
+ // Get the nic receive status
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_RCV_STATUS,
+ &NicReceiveStatus
+ );
+
+
+ DbgPrint(
+ "NIC_RCV_STATUS: RSR_PACKET_OK - %x\n"
+ " RSR_CRC_ERROR - %x\n"
+ " RSR_MULTICAST - %x\n"
+ " RSR_DISABLED - %x\n",
+ " RSR_DEFERRING - %x\n",
+ NicReceiveStatus & RSR_PACKET_OK,
+ NicReceiveStatus & RSR_CRC_ERROR,
+ NicReceiveStatus & RSR_MULTICAST,
+ NicReceiveStatus & RSR_DISABLED,
+ NicReceiveStatus & RSR_DEFERRING
+ );
+
+ //
+ // Get the nic frame error counter
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_FAE_ERR_CNTR,
+ &NicFrameErrorCounter
+ );
+
+ DbgPrint("NIC_FAE_ERR_CNTR: %x\n", NicFrameErrorCounter);
+
+ //
+ // Get the nic crc error counter
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_CRC_ERR_CNTR,
+ &NicCrcErrorCounter
+ );
+
+ DbgPrint("NIC_CRC_ERR_CNTR: %x\n", NicCrcErrorCounter);
+
+ //
+ // Get the nic missed counter
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_MISSED_CNTR,
+ &NicMissedCounter
+ );
+
+ DbgPrint("NIC_MISSED_CNTR: %x\n", NicMissedCounter);
+
+ //
+ // Get the GA page start.
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + GA_PAGE_START,
+ &GaPageStart
+ );
+
+ DbgPrint("GA_PAGE_START: %x\n", GaPageStart);
+
+
+ //
+ // Get the GA page stop.
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + GA_PAGE_STOP,
+ &GaPageStop
+ );
+
+ DbgPrint("GA_PAGE_STOP: %x\n", GaPageStop);
+
+ //
+ // Get the GA drq timer
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + GA_DRQ_TIMER,
+ &GaDrqTimer
+ );
+
+ DbgPrint(
+ "GA_DRQ_TIMER: DQTR_16_BYTE - %x\n"
+ " DQTR_8_BYTE - %x\n",
+ GaDrqTimer == DQTR_16_BYTE,
+ GaDrqTimer == DQTR_8_BYTE
+ );
+
+ //
+ // Get the GA io base
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + GA_IO_BASE,
+ &GaIoBase
+ );
+
+ DbgPrint("GA_IO_BASE: %x\n", GaIoBase);
+
+ //
+ // Get the GA memory base
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + GA_MEM_BASE,
+ &GaMemoryBase
+ );
+
+ DbgPrint("GA_MEM_BASE: %x\n", GaMemoryBase);
+
+ //
+ // Get the GA config
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + GA_CONFIG,
+ &GaConfig
+ );
+
+ DbgPrint(
+ "GA_CONFIG: GACFR_TC_MASK - %x\n"
+ " GACFR_RAM_SEL - %x\n"
+ " GACFR_MEM_BANK1 - %x\n",
+ GaConfig & GACFR_TC_MASK,
+ GaConfig & GACFR_RAM_SEL,
+ GaConfig & GACFR_MEM_BANK1
+ );
+
+ //
+ // Get the GA control
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + GA_CONTROL,
+ &GaControl
+ );
+
+ DbgPrint(
+ "GA_CONTROL: CTRL_START - %x\n"
+ " CTRL_STOP - %x\n"
+ " CTRL_DIR_DOWN - %x\n"
+ " CTRL_DIR_UP - %x\n"
+ " CTRL_DB_SEL - %x\n"
+ " CTRL_PROM_SEL - %x\n"
+ " CTRL_GA_SEL - %x\n"
+ " CTRL_BNC - %x\n"
+ " CTRL_DIX - %x\n"
+ " CTRL_RESET - %x\n",
+ GaControl & CTRL_START,
+ !(GaControl & CTRL_STOP),
+ GaControl & CTRL_DIR_DOWN,
+ !(GaControl & CTRL_DIR_UP),
+ GaControl & CTRL_DB_SEL,
+ GaControl & CTRL_PROM_SEL,
+ !(GaControl & CTRL_PROM_SEL),
+ GaControl & CTRL_BNC,
+ !(GaControl & CTRL_DIX),
+ GaControl & CTRL_RESET
+ );
+
+
+ //
+ // Get the GA status
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + GA_STATUS,
+ &GaStatus
+ );
+
+ DbgPrint(
+ "GA_STATUS: STREG_DP_READY - %x\n"
+ " STREG_UNDERFLOW - %x\n"
+ " STREG_OVERFLOW - %x\n"
+ " STREG_IN_PROG - %x\n",
+ GaStatus & STREG_DP_READY,
+ GaStatus & STREG_UNDERFLOW,
+ GaStatus & STREG_OVERFLOW,
+ GaStatus & STREG_IN_PROG
+ );
+
+ //
+ // Get the GA interrupt dma config
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + GA_INT_DMA_CONFIG,
+ &GaIntDmaConfig
+ );
+
+ DbgPrint("GA_INT_DMA_CONFIG: %x\n", GaIntDmaConfig);
+
+ //
+ // Get the GA dma address msb
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + GA_DMA_ADDR_MSB,
+ &GaDmaAddressMsb
+ );
+
+ DbgPrint("GA_DMA_ADDR_MSB: %x\n", GaDmaAddressMsb);
+
+ //
+ // Get the GA dma address lsb
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + GA_DMA_ADDR_LSB,
+ &GaDmaAddressLsb
+ );
+
+ DbgPrint("GA_DMA_ADDR_LSB: %x\n", GaDmaAddressLsb);
+
+ //
+ // Get the GA register file access msb
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + GA_REG_FILE_MSB,
+ &GaRegFileAccessMsb
+ );
+
+ DbgPrint("GA_REG_FILE_MSB: %x\n", GaRegFileAccessMsb);
+
+ //
+ // Get the GA register file access lsb
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + GA_REG_FILE_LSB,
+ &GaRegFileAccessLsb
+ );
+
+ DbgPrint("GA_REG_FILE_LSB: %x\n", GaRegFileAccessLsb);
+
+}
+
+#endif
diff --git a/private/ntos/ndis/elnkii.new/elnkhrd.h b/private/ntos/ndis/elnkii.new/elnkhrd.h
new file mode 100644
index 000000000..0774c8204
--- /dev/null
+++ b/private/ntos/ndis/elnkii.new/elnkhrd.h
@@ -0,0 +1,811 @@
+ /*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ elnkhrd.h
+
+Abstract:
+
+ The main program for an Etherlink II MAC driver.
+
+Author:
+
+ Anthony V. Ercolano (tonye) creation-date 19-Jun-1990 (Driver model)
+
+ Orginal Elnkii code by AdamBa.
+
+Environment:
+
+ This driver is expected to work in DOS, OS2 and NT at the equivalent
+ of kernal mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+ Dec-1991 by Sean Selitrennikoff - Conversion of AdamBa's code to TonyE Model
+
+
+--*/
+
+#ifndef _ELNKIIHARDWARE_
+#define _ELNKIIHARDWARE_
+
+// pAdapter->IoBaseAddr
+//
+// must match the setting of I/O Base Address jumper on
+// the card. Choices are 0x300, 0x310, 0x330, 0x350, 0x250,
+// 0x280, 0x2a0, and 0x2e0.
+
+#define DEFAULT_IOBASEADDR (PVOID)0x300
+
+
+
+// pAdapter->ExternalTransceiver
+//
+// whether you are using thick Ethernet cable attached to the
+// DIX port, or thin Ethernet attached to the BNC port. This
+// will probably be TRUE.
+
+#define DEFAULT_EXTERNALTRANSCEIVER FALSE
+
+
+
+// pAdapter->InterruptNumber
+//
+// the interrupt number the board is using. Choices are 2, 3,
+// 4, or 5; some of these are used by other NT drivers.
+
+#define DEFAULT_INTERRUPTNUMBER 3
+
+
+
+// pAdapter->MemMapped
+//
+// whether to use memory mapping for data transfer, or programmed
+// I/O. If it is TRUE, the Memory base address jumper must be
+// moved from its default "Disable" setting.
+
+#define DEFAULT_MEMMAPPED FALSE
+
+
+
+// pAdapter->MulticastListMax
+//
+// the maximum number of different multicast addresses that
+// may be specified to this adapter (the list is global for
+// all protocols).
+
+#define DEFAULT_MULTICASTLISTMAX 16
+
+
+//
+// Offsets from pAdapter->MappedIoBaseAddr of the ports used to access
+// the 8390 NIC registers.
+//
+// The names in parenthesis are the abbreviations by which
+// the registers are referred to in the 8390 data sheet.
+//
+// Some of the offsets appear more than once
+// because they have have relevant page 0 and page 1 values,
+// or they are different registers when read than they are
+// when written. The notation MSB indicates that only the
+// MSB can be set for this register, the LSB is assumed 0.
+//
+
+#define NIC_COMMAND 0x0 // (CR)
+#define NIC_PAGE_START 0x1 // (PSTART) MSB, write-only
+#define NIC_PHYS_ADDR 0x1 // (PAR0) page 1
+#define NIC_PAGE_STOP 0x2 // (PSTOP) MSB, write-only
+#define NIC_BOUNDARY 0x3 // (BNRY) MSB
+#define NIC_XMIT_START 0x4 // (TPSR) MSB, write-only
+#define NIC_XMIT_STATUS 0x4 // (TSR) read-only
+#define NIC_XMIT_COUNT_LSB 0x5 // (TBCR0) write-only
+#define NIC_XMIT_COUNT_MSB 0x6 // (TBCR1) write-only
+#define NIC_FIFO 0x6 // (FIFO) read-only
+#define NIC_INTR_STATUS 0x7 // (ISR)
+#define NIC_CURRENT 0x7 // (CURR) page 1
+#define NIC_MC_ADDR 0x8 // (MAR0) page 1
+#define NIC_RMT_COUNT_LSB 0xa // (RBCR0) write-only
+#define NIC_RMT_COUNT_MSB 0xb // (RBCR1) write-only
+#define NIC_RCV_CONFIG 0xc // (RCR) write-only
+#define NIC_RCV_STATUS 0xc // (RSR) read-only
+#define NIC_XMIT_CONFIG 0xd // (TCR) write-only
+#define NIC_FAE_ERR_CNTR 0xd // (CNTR0) read-only
+#define NIC_DATA_CONFIG 0xe // (DCR) write-only
+#define NIC_CRC_ERR_CNTR 0xe // (CNTR1) read-only
+#define NIC_INTR_MASK 0xf // (IMR) write-only
+#define NIC_MISSED_CNTR 0xf // (CNTR2) read-only
+
+
+//
+// Constants for the NIC_COMMAND register.
+//
+// Start/stop the card, start transmissions, and select
+// which page of registers was seen through the ports.
+//
+
+#define CR_STOP (UCHAR)0x01 // reset the card
+#define CR_START (UCHAR)0x02 // start the card
+#define CR_XMIT (UCHAR)0x04 // begin transmission
+#define CR_NO_DMA (UCHAR)0x20 // stop remote DMA
+
+#define CR_PS0 (UCHAR)0x40 // low bit of page number
+#define CR_PS1 (UCHAR)0x80 // high bit of page number
+#define CR_PAGE0 (UCHAR)0x00 // select page 0
+#define CR_PAGE1 CR_PS0 // select page 1
+#define CR_PAGE2 CR_PS1 // select page 2
+
+
+//
+// Constants for the NIC_XMIT_STATUS register.
+//
+// Indicate the result of a packet transmission.
+//
+
+#define TSR_XMIT_OK (UCHAR)0x01 // transmit with no errors
+#define TSR_COLLISION (UCHAR)0x04 // collided at least once
+#define TSR_ABORTED (UCHAR)0x08 // too many collisions
+#define TSR_NO_CARRIER (UCHAR)0x10 // carrier lost
+#define TSR_NO_CDH (UCHAR)0x40 // no collision detect heartbeat
+
+
+//
+// Constants for the NIC_INTR_STATUS register.
+//
+// Indicate the cause of an interrupt.
+//
+
+#define ISR_EMPTY (UCHAR)0x00 // no bits set in the ISR
+#define ISR_RCV (UCHAR)0x01 // packet received with no errors
+#define ISR_XMIT (UCHAR)0x02 // packet transmitted with no errors
+#define ISR_RCV_ERR (UCHAR)0x04 // error on packet reception
+#define ISR_XMIT_ERR (UCHAR)0x08 // error on packet transmission
+#define ISR_OVERFLOW (UCHAR)0x10 // receive buffer overflow
+#define ISR_COUNTER (UCHAR)0x20 // MSB set on tally counter
+#define ISR_RESET (UCHAR)0x80 // (not an interrupt) card is reset
+
+
+//
+// Constants for the NIC_RCV_CONFIG register.
+//
+// Configure what type of packets are received.
+//
+
+#define RCR_REJECT_ERR (UCHAR)0x00 // reject error packets
+#define RCR_BROADCAST (UCHAR)0x04 // receive broadcast packets
+#define RCR_MULTICAST (UCHAR)0x08 // receive multicast packets
+#define RCR_ALL_PHYS (UCHAR)0x10 // receive ALL directed packets
+
+
+//
+// Constants for the NIC_RCV_STATUS register.
+//
+// Indicate the status of a received packet.
+//
+// These are also used to interpret the status byte in the
+// packet header of a received packet.
+//
+
+#define RSR_PACKET_OK (UCHAR)0x01 // packet received with no errors
+#define RSR_CRC_ERROR (UCHAR)0x02 // packet received with CRC error
+#define RSR_MULTICAST (UCHAR)0x20 // packet received was multicast
+#define RSR_DISABLED (UCHAR)0x40 // received is disabled
+#define RSR_DEFERRING (UCHAR)0x80 // receiver is deferring
+
+
+//
+// Constants for the NIC_XMIT_CONFIG register.
+//
+// Configures how packets are transmitted.
+//
+
+#define TCR_NO_LOOPBACK (UCHAR)0x00 // normal operation
+#define TCR_LOOPBACK (UCHAR)0x02 // loopback (set when NIC is stopped)
+
+#define TCR_INHIBIT_CRC (UCHAR)0x01 // inhibit appending of CRC
+
+#define TCR_NIC_LBK (UCHAR)0x02 // loopback through the NIC
+#define TCR_SNI_LBK (UCHAR)0x04 // loopback through the SNI
+#define TCR_COAX_LBK (UCHAR)0x06 // loopback to the coax
+
+
+//
+// Constants for the NIC_DATA_CONFIG register.
+//
+// Set data transfer sizes.
+//
+
+#define DCR_BYTE_WIDE (UCHAR)0x00 // byte-wide DMA transfers
+#define DCR_WORD_WIDE (UCHAR)0x01 // word-wide DMA transfers
+
+#define DCR_LOOPBACK (UCHAR)0x00 // loopback mode (TCR must be set)
+#define DCR_NORMAL (UCHAR)0x08 // normal operation
+
+#define DCR_FIFO_8_BYTE (UCHAR)0x40 // 8-byte FIFO threshhold
+
+
+//
+// Constants for the NIC_INTR_MASK register.
+//
+// Configure which ISR settings actually cause interrupts.
+//
+
+#define IMR_RCV (UCHAR)0x01 // packet received with no errors
+#define IMR_XMIT (UCHAR)0x02 // packet transmitted with no errors
+#define IMR_RCV_ERR (UCHAR)0x04 // error on packet reception
+#define IMR_XMIT_ERR (UCHAR)0x08 // error on packet transmission
+#define IMR_OVERFLOW (UCHAR)0x10 // receive buffer overflow
+#define IMR_COUNTER (UCHAR)0x20 // MSB set on tally counter
+
+
+
+//
+// Offsets from pAdapter->MappedGabaseAddr (which is pAdapter->MappedIoBaseAddr+0x400)
+// of the ports used to access the Elnkii Gate Array registers.
+//
+// The names in parenthesis are the abbreviations by which
+// the registers are referred to in the Elnkii Technical
+// Reference.
+//
+
+#define GA_PAGE_START 0x0 // (PSTR) MSB
+#define GA_PAGE_STOP 0x1 // (PSPR) MSB
+#define GA_DRQ_TIMER 0x2 // (DQTR)
+#define GA_IO_BASE 0x3 // (BCFR) read-only
+#define GA_MEM_BASE 0x4 // (PCFR) read-only
+#define GA_CONFIG 0x5 // (GACFR)
+#define GA_CONTROL 0x6 // (CTRL)
+#define GA_STATUS 0x7 // (STREG) read-only
+#define GA_INT_DMA_CONFIG 0x8 // (IDCFR)
+#define GA_DMA_ADDR_MSB 0x9 // (DAMSB)
+#define GA_DMA_ADDR_LSB 0xa // (DALSB)
+#define GA_REG_FILE_MSB 0xe // (RFMSB)
+#define GA_REG_FILE_LSB 0xf // (RFLSB)
+
+
+//
+// Constants for the GA_DRQ_TIMER register.
+//
+
+#define DQTR_16_BYTE (UCHAR)0x10 // 16-byte programmed I/O bursts
+#define DQTR_8_BYTE (UCHAR)0x08 // 8-byte programmed I/O bursts
+
+
+//
+// Constants for the GA_CONFIG register.
+//
+
+#define GACFR_TC_MASK (UCHAR)0x40 // block DMA complete interrupts
+#define GACFR_RAM_SEL (UCHAR)0x08 // allow memory-mapped mode
+#define GACFR_MEM_BANK1 (UCHAR)0x01 // select window for 8K buffer
+
+
+//
+// Constants for the GA_CONTROL register.
+//
+
+#define CTRL_START (UCHAR)0x80 // start the DMA controller
+#define CTRL_STOP (UCHAR)0x00 // stop the DMA controller
+
+#define CTRL_DIR_DOWN (UCHAR)0x40 // system->board transfers
+#define CTRL_DIR_UP (UCHAR)0x00 // board->system transfers
+
+#define CTRL_DB_SEL (UCHAR)0x20 // connect FIFOs serially
+
+#define CTRL_PROM_SEL (UCHAR)0x04 // window PROM into GaAddr ports
+#define CTRL_GA_SEL (UCHAR)0x00 // window GA into GaAddr ports
+
+#define CTRL_BNC (UCHAR)0x02 // internal transceiver
+#define CTRL_DIX (UCHAR)0x00 // external transceiver
+
+#define CTRL_RESET (UCHAR)0x01 // emulate power up reset
+
+
+//
+// Constants for the GA_STATUS register.
+//
+
+#define STREG_DP_READY (UCHAR)0x80 // ready for programmed I/O transfer
+#define STREG_UNDERFLOW (UCHAR)0x40 // register file underflow
+#define STREG_OVERFLOW (UCHAR)0x20 // register file overflow
+#define STREG_IN_PROG (UCHAR)0x08 // programmed I/O in progress
+
+
+
+//++
+//
+// VOID
+// CardStart(
+// IN PELNKII_ADAPTER pAdapter
+// )
+//
+//
+// Routine Description:
+//
+// Starts the card.
+//
+// Arguments:
+//
+// pAdapter - pointer to the adapter block
+//
+// Return Value:
+//
+// None.
+//
+//--
+ //
+ // Assume that the card has been stopped as in CardStop.
+ //
+
+#define CardStart(pAdapter) \
+ NdisRawWritePortUchar( \
+ pAdapter->MappedIoBaseAddr + NIC_XMIT_CONFIG, \
+ TCR_NO_LOOPBACK \
+ )
+
+
+
+//++
+//
+// VOID
+// CardSetAllMulticast(
+// IN PELNKII_ADAPTER pAdapter
+// )
+//
+// Routine Description:
+//
+// Enables every bit in the card multicast bit mask.
+// Calls SyncCardSetAllMulticast.
+//
+// Arguments:
+//
+// pAdapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardSetAllMulticast(pAdapter) \
+ NdisMSynchronizeWithInterrupt( \
+ &(pAdapter)->Interrupt, \
+ SyncCardSetAllMulticast, \
+ (PVOID)(pAdapter) \
+ )
+
+
+//++
+//
+// VOID
+// CardCopyMulticastRegs(
+// IN PELNKII_ADAPTER pAdapter
+// )
+//
+// Routine Description:
+//
+// Writes out the entire multicast bit mask to the card from
+// pAdapter->NicMulticastRegs. Calls SyncCardCopyMulticastRegs.
+//
+// Arguments:
+//
+// pAdapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardCopyMulticastRegs(pAdapter) \
+ NdisMSynchronizeWithInterrupt( \
+ &(pAdapter)->Interrupt, \
+ SyncCardCopyMulticastRegs, \
+ (PVOID)(pAdapter) \
+ )
+
+
+
+//++
+//
+// VOID
+// CardGetInterruptStatus(
+// IN PELNKII_ADAPTER pAdapter,
+// OUT PUCHAR InterrupStatus
+// )
+//
+// Routine Description:
+//
+// Reads the interrupt status (ISR) register from the card. Only
+// called at IRQL INTERRUPT_LEVEL.
+//
+// Arguments:
+//
+// pAdapter - The adapter block.
+//
+// InterruptStatus - Returns the value of ISR.
+//
+// Return Value:
+//
+//--
+
+#define CardGetInterruptStatus(pAdapter,InterruptStatus) \
+ NdisRawReadPortUchar( \
+ (pAdapter)->MappedIoBaseAddr + NIC_INTR_STATUS, \
+ (InterruptStatus) \
+ )
+
+
+//++
+//
+// VOID
+// CardSetReceiveConfig(
+// IN PELNKII_ADAPTER pAdapter
+// )
+//
+// Routine Description:
+//
+// Sets the receive configuration (RCR) register on the card.
+// The value used is pAdapter->NicReceiveConfig. Calls
+// SyncCardSetReceiveConfig.
+//
+// Arguments:
+//
+// pAdapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardSetReceiveConfig(pAdapter) \
+ NdisMSynchronizeWithInterrupt( \
+ &(pAdapter)->Interrupt, \
+ SyncCardSetReceiveConfig, \
+ (PVOID)(pAdapter) \
+ )
+
+
+//++
+//
+// VOID
+// CardBlockInterrupts(
+// IN PELNKII_ADAPTER pAdapter
+// )
+//
+// Routine Description:
+//
+// Blocks all interrupts from the card by clearing the
+// interrupt mask (IMR) register. Only called from
+// IRQL INTERRUPT_LEVEL.
+//
+// Arguments:
+//
+// pAdapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardBlockInterrupts(pAdapter) \
+ NdisRawWritePortUchar((pAdapter)->MappedIoBaseAddr + NIC_INTR_MASK, 0)
+
+
+//++
+//
+// VOID
+// CardUnblockInterrupts(
+// IN PELNKII_ADAPTER pAdapter
+// )
+//
+// Routine Description:
+//
+// Unblocks all interrupts from the card by setting the
+// interrupt mask (IMR) register. Only called from IRQL
+// INTERRUPT_LEVEL.
+//
+// Arguments:
+//
+// pAdapter- The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardUnblockInterrupts(pAdapter) \
+ NdisRawWritePortUchar( \
+ (pAdapter)->MappedIoBaseAddr + NIC_INTR_MASK, \
+ (pAdapter)->NicInterruptMask \
+ )
+
+
+//++
+//
+// VOID
+// CardDisableReceiveInterrupt(
+// IN PELNKII_ADAPTER pAdapter
+// )
+//
+// Routine Description:
+//
+// Turns off the receive bit in pAdapter->NicInterruptMask.
+// This function is only called when CardBlockInterrupts have
+// been called; it ensures that receive interrupts are not
+// reenabled until CardEnableReceiveInterrupt is called, even
+// if CardUnblockInterrupts is called.
+//
+// Arguments:
+//
+// pAdapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardDisableReceiveInterrupt(pAdapter) \
+ (pAdapter)->NicInterruptMask &= (UCHAR)~IMR_RCV
+
+
+//++
+//
+// VOID
+// CardEnableReceiveInterrupt(
+// IN PELNKII_ADAPTER pAdapter
+// )
+//
+// Routine Description:
+//
+// Reenables receive interrupts by setting the receive bit ibn
+// pAdapter->NicInterruptMask, and also writes the new value to
+// the card. Calls SyncCardSetInterruptMask.
+//
+// Arguments:
+//
+// pAdapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardEnableReceiveInterrupt(pAdapter) \
+ (pAdapter)->NicInterruptMask |= (UCHAR)IMR_RCV, \
+ NdisMSynchronizeWithInterrupt( \
+ &(pAdapter)->Interrupt, \
+ SyncCardSetInterruptMask, \
+ (PVOID)(pAdapter) \
+ )
+
+//++
+//
+// VOID
+// CardAcknowledgeReceiveInterrupt(
+// IN PELNKII_ADAPTER pAdapter
+// )
+//
+// Routine Description:
+//
+// Acknowledges a receive interrupt by setting the bit in
+// the interrupt status (ISR) register. Calls
+// SyncCardAcknowledgeReceive.
+//
+// Arguments:
+//
+// pAdapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardAcknowledgeReceiveInterrupt(pAdapter) \
+ NdisMSynchronizeWithInterrupt( \
+ &(pAdapter)->Interrupt, \
+ SyncCardAcknowledgeReceive, \
+ (PVOID)(pAdapter) \
+ )
+
+
+//++
+//
+// VOID
+// CardAcknowledgeOverflowInterrupt(
+// IN PELNKII_ADAPTER pAdapter
+// )
+//
+// Routine Description:
+//
+// Acknowledges an overflow interrupt by setting the bit in
+// the interrupt status (ISR) register. Calls
+// SyncCardAcknowledgeOverflow.
+//
+// Arguments:
+//
+// pAdapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardAcknowledgeOverflowInterrupt(pAdapter) \
+ NdisMSynchronizeWithInterrupt( \
+ &(pAdapter)->Interrupt, \
+ SyncCardAcknowledgeOverflow, \
+ (PVOID)(pAdapter) \
+ )
+
+
+//++
+//
+// VOID
+// CardAcknowledgeTransmitInterrupt(
+// IN PELNKII_ADAPTER pAdapter
+// )
+//
+// Routine Description:
+//
+// Acknowledges a transmit interrupt by setting the bit in
+// the interrupt status (ISR) register. Calls
+// SyncCardAcknowledgeTransmit.
+//
+// Arguments:
+//
+// pAdapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardAcknowledgeTransmitInterrupt(pAdapter) \
+ NdisMSynchronizeWithInterrupt( \
+ &(pAdapter)->Interrupt, \
+ SyncCardAcknowledgeTransmit, \
+ (PVOID)(pAdapter) \
+ )
+
+
+//++
+//
+// VOID
+// CardAcknowledgeCounterInterrupt(
+// IN PELNKII_ADAPTER pAdapter
+// )
+//
+// Routine Description:
+//
+// Acknowledges a counter interrupt by setting the bit in
+// the interrupt status (ISR) register.
+//
+// Arguments:
+//
+// pAdapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardAcknowledgeCounterInterrupt(pAdapter) \
+ NdisRawWritePortUchar( \
+ (pAdapter)->MappedIoBaseAddr + NIC_INTR_STATUS, \
+ ISR_COUNTER \
+ )
+
+
+//++
+//
+// VOID
+// CardAckAndGetCurrent(
+// IN PELNKII_ADAPTER pAdapter
+// )
+//
+// Routine Description:
+//
+// Performs the function of CardAcknowledgeReceive followed by
+// CardGetCurrent (since the two are always called
+// one after the other). Calls SyncCardAckAndGetCurrent.
+//
+// Arguments:
+//
+// pAdapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardAckAndGetCurrent(pAdapter) \
+ NdisMSynchronizeWithInterrupt( \
+ &(pAdapter)->Interrupt, \
+ SyncCardAckAndGetCurrent, \
+ (PVOID)(pAdapter) \
+ )
+
+
+//++
+//
+// VOID
+// CardGetXmitStatusAndAck(
+// IN PELNKII_ADAPTER pAdapter
+// )
+//
+// Routine Description:
+//
+// Performs the function of CardGetXmitStatus followed by
+// CardAcknowledgeTransmit (since the two are always called
+// one after the other). Calls SyncCardGetXmitStatusAndAck.
+//
+// Arguments:
+//
+// pAdapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardGetXmitStatusAndAck(pAdapter) \
+ NdisMSynchronizeWithInterrupt( \
+ &(pAdapter)->Interrupt, \
+ SyncCardGetXmitStatusAndAck, \
+ (PVOID)(pAdapter) \
+ )
+
+
+//++
+//
+// VOID
+// CardUpdateCounters(
+// IN PELNKII_ADAPTER pAdapter
+// )
+//
+// Routine Description:
+//
+// Updates the values of the three counters (frame alignment
+// errors, CRC errors, and missed packets) by reading in their
+// current values from the card and adding them to the ones
+// stored in the pAdapter structure. Calls SyncCardUpdateCounters.
+//
+// Arguments:
+//
+// pAdapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardUpdateCounters(pAdapter) \
+ NdisMSynchronizeWithInterrupt( \
+ &(pAdapter)->Interrupt, \
+ SyncCardUpdateCounters, \
+ (PVOID)(pAdapter) \
+ )
+
+
+#endif // _ELNKIIHARDWARE_
diff --git a/private/ntos/ndis/elnkii.new/elnkii.c b/private/ntos/ndis/elnkii.new/elnkii.c
new file mode 100644
index 000000000..2d17a1e35
--- /dev/null
+++ b/private/ntos/ndis/elnkii.new/elnkii.c
@@ -0,0 +1,1825 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ elnkii.c
+
+Abstract:
+
+ This is the main file for the Etherlink II
+ Ethernet controller. This driver conforms to the NDIS 3.1 interface.
+
+ The idea for handling loopback and sends simultaneously is largely
+ adapted from the EtherLink II NDIS driver by Adam Barr.
+
+Author:
+
+ Anthony V. Ercolano (Tonye) 20-Jul-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+ Dec 1991 by Sean Selitrennikoff - Modified Elnkii code by AdamBa to
+ fit into the model by TonyE.
+
+ 12/15/94 [kyleb] Converted to miniport.
+
+--*/
+
+#include <ndis.h>
+#include "elnkhrd.h"
+#include "elnksft.h"
+#include "keywords.h"
+
+#if DBG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+
+#if DBG
+
+ULONG ElnkiiDebugFlag = ELNKII_DEBUG_LOUD;
+
+//
+// Debug tracing definitions
+//
+#define ELNKII_LOG_SIZE 256
+
+UCHAR ElnkiiLogBuffer[ELNKII_LOG_SIZE] = {0};
+UINT ElnkiiLogLoc = 0;
+
+VOID ElnkiiLog(UCHAR c)
+{
+ ElnkiiLogBuffer[ElnkiiLogLoc++] = c;
+ ElnkiiLogBuffer[(ElnkiiLogLoc + 4) % ELNKII_LOG_SIZE] = '\0';
+
+ if (ElnkiiLogLoc >= ELNKII_LOG_SIZE)
+ ElnkiiLogLoc = 0;
+}
+#endif
+
+//
+// This constant is used for places where NdisAllocateMemory
+// needs to be called and the HighestAcceptableAddress does
+// not matter.
+//
+
+static const NDIS_PHYSICAL_ADDRESS HighestAcceptableMax =
+ NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
+
+
+//
+// The global MAC block.
+//
+
+DRIVER_BLOCK ElnkiiMiniportBlock = {0};
+
+//
+// List of supported OIDs for this miniport.
+//
+STATIC UINT ElnkiiSupportedOids[] =
+{
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ OID_802_3_RCV_ERROR_ALIGNMENT,
+ OID_802_3_XMIT_ONE_COLLISION,
+ OID_802_3_XMIT_MORE_COLLISIONS
+};
+
+
+//
+// Determines whether failing the initial card test will prevent
+// the adapter from being registered.
+//
+
+#ifdef CARD_TEST
+
+BOOLEAN InitialCardTest = TRUE;
+
+#else // CARD_TEST
+
+BOOLEAN InitialCardTest = FALSE;
+
+#endif // CARD_TEST
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+#pragma NDIS_INIT_FUNCTION(DriverEntry)
+
+
+
+NTSTATUS DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+)
+
+/*++
+
+Routine Description:
+
+ This is the transfer address of the driver. It initializes
+ ElnkiiMacBlock and calls NdisInitializeWrapper() and
+ NdisRegisterMac().
+
+Arguments:
+
+Return Value:
+
+ Indicates the success or failure of the initialization.
+
+--*/
+
+{
+ NDIS_HANDLE NdisWrapperHandle; // Handle referring the wrapper to
+ // this driver.
+ PDRIVER_BLOCK pNewMac; // Pointer to global information about
+ // this driver.
+ NDIS_STATUS Status; // Holds the status of NDIS functions.
+
+ //
+ // Characteristics table for the miniport.
+ //
+ NDIS_MINIPORT_CHARACTERISTICS ElnkiiChar;
+
+
+#if DBG
+
+ ElnkiiDebugFlag = ELNKII_DEBUG_LOUD;
+ __asm int 3
+
+#endif
+
+
+ //
+ // Initialize some locals.
+ //
+ pNewMac = &ElnkiiMiniportBlock;
+
+ //
+ // Pass the wrapper a pointer to the device object.
+ //
+ NdisMInitializeWrapper(
+ &NdisWrapperHandle,
+ DriverObject,
+ RegistryPath,
+ NULL
+ );
+
+ //
+ // Save info about this miniport.
+ //
+ pNewMac->NdisWrapperHandle = NdisWrapperHandle;
+ pNewMac->AdapterQueue = (PELNKII_ADAPTER)NULL;
+
+ //
+ // Initialize the miniport's characteristics table.
+ //
+ ElnkiiChar.MajorNdisVersion = ELNKII_NDIS_MAJOR_VERSION;
+ ElnkiiChar.MinorNdisVersion = ELNKII_NDIS_MINOR_VERSION;
+ ElnkiiChar.CheckForHangHandler = ElnkiiCheckForHang;
+ ElnkiiChar.ReconfigureHandler = NULL;
+ ElnkiiChar.InitializeHandler = ElnkiiInitialize;
+
+ ElnkiiChar.DisableInterruptHandler = ElnkiiDisableInterrupt;
+ ElnkiiChar.EnableInterruptHandler = ElnkiiEnableInterrupt;
+ ElnkiiChar.HaltHandler = ElnkiiHalt;
+ ElnkiiChar.HandleInterruptHandler = ElnkiiHandleInterrupt;
+ ElnkiiChar.ISRHandler = ElnkiiIsr;
+ ElnkiiChar.QueryInformationHandler = ElnkiiQueryInformation;
+ ElnkiiChar.ResetHandler = ElnkiiReset;
+ ElnkiiChar.SendHandler = ElnkiiSend;
+ ElnkiiChar.SetInformationHandler = ElnkiiSetInformation;
+ ElnkiiChar.TransferDataHandler = ElnkiiTransferData;
+
+ //
+ // Register the miniport with the wrapper.
+ //
+ Status = NdisMRegisterMiniport(
+ NdisWrapperHandle,
+ &ElnkiiChar,
+ sizeof(ElnkiiChar)
+ );
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ IF_LOUD(DbgPrint("NdisMRegisterMiniport failed with code 0x%x\n", Status);)
+
+ NdisTerminateWrapper(NdisWrapperHandle, NULL);
+ return(Status);
+ }
+
+ IF_LOUD( DbgPrint( "NdisMRegisterMiniport succeeded\n" );)
+ IF_LOUD( DbgPrint("Adapter Initialization Complete\n");)
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+#pragma NDIS_INIT_FUNCTION(ReadBaseIoAddress)
+
+
+VOID ReadBaseIoAddress(
+ OUT PNDIS_STATUS pStatus,
+ OUT PVOID *ppIoBaseAddress,
+ IN NDIS_HANDLE hConfig,
+ IN NDIS_HANDLE MiniportAdapterHandle
+)
+{
+ #define MAX_POSSIBLE_BASE_ADDRESSES 8
+
+ PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
+
+ NDIS_STRING IOAddressStr = IOBASE;
+ NDIS_STATUS Status;
+ UINT c;
+ PVOID PossibleIoBases[] = { (PVOID)0x2e0, (PVOID)0x2a0,
+ (PVOID)0x280, (PVOID)0x250,
+ (PVOID)0x350, (PVOID)0x330,
+ (PVOID)0x310, (PVOID)0x300 };
+
+ //
+ // Read the I/O base address.
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ hConfig,
+ &IOAddressStr,
+ NdisParameterHexInteger
+ );
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ //
+ // We read an address from the registry.
+ //
+ *ppIoBaseAddress = (PVOID)ReturnedValue->ParameterData.IntegerData;
+
+ //
+ // Verify the I/O base address.
+ //
+ for (c = 0; c < MAX_POSSIBLE_BASE_ADDRESSES; c++)
+ {
+ if (*ppIoBaseAddress == PossibleIoBases[c])
+ break;
+ }
+
+ //
+ // Is the base address that we read valid?
+ //
+ if (MAX_POSSIBLE_BASE_ADDRESSES == c)
+ {
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
+ 1,
+ (ULONG)*ppIoBaseAddress
+ );
+
+ *pStatus = NDIS_STATUS_FAILURE;
+ }
+ }
+ else
+ {
+ //
+ // No address was read, use the default.
+ //
+ *pStatus = NDIS_STATUS_SUCCESS;
+ }
+
+ #undef MAX_POSSIBLE_BASE_ADDRESS
+}
+
+#pragma NDIS_INIT_FUNCTION(ReadInterruptNumber)
+
+VOID ReadInterruptNumber(
+ OUT PNDIS_STATUS pStatus,
+ OUT PCCHAR pInterruptNumber,
+ IN NDIS_HANDLE hConfig,
+ IN NDIS_HANDLE MiniportAdapterHandle
+)
+{
+ #define MAX_INTERRUPT_VALUES 4
+
+ PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
+
+ NDIS_STRING InterruptStr = INTERRUPT;
+ CCHAR InterruptValues[] = { 2, 3, 4, 5 };
+ NDIS_STATUS Status;
+ UINT c;
+
+ //
+ // Read the interrupt number from the registry.
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ hConfig,
+ &InterruptStr,
+ NdisParameterHexInteger
+ );
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ //
+ // We read an entry from the registry.
+ //
+ *pInterruptNumber = (CCHAR)ReturnedValue->ParameterData.IntegerData;
+
+ //
+ // Verify the interrupt number.
+ //
+ for (c = 0; c < MAX_INTERRUPT_VALUES; c++)
+ {
+ if (*pInterruptNumber == InterruptValues[c])
+ break;
+ }
+
+ if (MAX_INTERRUPT_VALUES == c)
+ {
+ //
+ // See if this works!!!!
+ //
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
+ 1,
+ *pInterruptNumber
+ );
+
+ *pStatus = NDIS_STATUS_FAILURE;
+ }
+ }
+ else
+ {
+ //
+ // No interrupt number was read, use the default.
+ //
+ *pStatus = NDIS_STATUS_SUCCESS;
+ }
+}
+
+NDIS_STATUS ElnkiiRegisterAdapter(
+ IN PELNKII_ADAPTER pAdapter,
+ IN NDIS_HANDLE ConfigurationHandle
+)
+{
+ UINT c;
+ BOOLEAN fCardPresent;
+ BOOLEAN fIoBaseCorrect;
+ NDIS_STATUS Status;
+
+ //
+ // Verify that NumBuffers <= MAX_XMIT_BUFS
+ //
+ if (pAdapter->NumBuffers > MAX_XMIT_BUFS)
+ return(NDIS_STATUS_RESOURCES);
+
+ //
+ // Inform the wrapper of the physical attributes of this adapter.
+ //
+ NdisMSetAttributes(
+ pAdapter->MiniportAdapterHandle,
+ (NDIS_HANDLE)pAdapter,
+ FALSE,
+ NdisInterfaceIsa
+ );
+
+ //
+ // Register the port addresses.
+ //
+ Status = NdisMRegisterIoPortRange(
+ (PVOID)(&(pAdapter->MappedIoBaseAddr)),
+ pAdapter->MiniportAdapterHandle,
+ (ULONG)pAdapter->IoBaseAddr,
+ 0x10
+ );
+ if (NDIS_STATUS_SUCCESS != Status)
+ goto fail1;
+
+ //
+ // Register the gate array addresses.
+ //
+ Status = NdisMRegisterIoPortRange(
+ (PVOID)&pAdapter->MappedGaBaseAddr,
+ pAdapter->MiniportAdapterHandle,
+ (ULONG)pAdapter->IoBaseAddr + 0x400,
+ 0x10
+ );
+ if (NDIS_STATUS_SUCCESS != Status)
+ goto fail2;
+
+ //
+ // Map the memory mapped portion of the card.
+ //
+ // If the pAdapter->MemMapped is FALSE, CardGetMemBaseAddr wil not
+ // return the actual MemBaseAddr, but it will still return
+ // CardPresent and IoBaseCorrect.
+ //
+ pAdapter->MemBaseAddr = CardGetMemBaseAddr(
+ pAdapter,
+ &fCardPresent,
+ &fIoBaseCorrect
+ );
+ if (!fCardPresent)
+ {
+ //
+ // The card does not seem to be there.
+ //
+ NdisWriteErrorLogEntry(
+ pAdapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
+ 0
+ );
+
+ Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+
+ goto fail1;
+ }
+
+ if (!fIoBaseCorrect)
+ {
+ //
+ // The card is there, but the I/O base address jumper is
+ // not where we expect it to be.
+ //
+ NdisWriteErrorLogEntry(
+ pAdapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_BAD_IO_BASE_ADDRESS,
+ 0
+ );
+
+ Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+
+ goto fail1;
+ }
+
+ if (pAdapter->MemMapped && (NULL == pAdapter->MemBaseAddr))
+ {
+ //
+ // The card does not appear to be mapped.
+ //
+ pAdapter->MemMapped = FALSE;
+ }
+
+ //
+ // For memory-mapped operation, map the card's transmit/receive
+ // area into memory space. For programmed I/O, we will refer
+ // to transmit/receive memory in terms of offsets in the card's
+ // 32K address space; for an 8K card this is always the second
+ // 8K piece, starting at 0x2000.
+ //
+ if (pAdapter->MemMapped)
+ {
+ NDIS_PHYSICAL_ADDRESS PhysicalAddress;
+
+ NdisSetPhysicalAddressHigh(PhysicalAddress, 0);
+ NdisSetPhysicalAddressLow(PhysicalAddress, (ULONG)pAdapter->MemBaseAddr);
+
+ Status = NdisMMapIoSpace(
+ (PVOID *)(&pAdapter->XmitStart),
+ pAdapter->MiniportAdapterHandle,
+ PhysicalAddress,
+ 0x2000
+ );
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ NdisWriteErrorLogEntry(
+ pAdapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_RESOURCE_CONFLICT,
+ 0
+ );
+
+ goto fail2;
+ }
+ }
+ else
+ {
+ //
+ // Programmed I/O
+ //
+ pAdapter->XmitStart = (PUCHAR)0x2000;
+ }
+
+ //
+ // For the NicXXX fields, always use the addressing system
+ // starting at 0x2000 (or 0x20, since they contain the MSB only).
+ //
+ pAdapter->NicXmitStart = 0x20;
+
+ //
+ // The start of the receive space.
+ //
+ pAdapter->PageStart = pAdapter->XmitStart +
+ (pAdapter->NumBuffers * TX_BUF_SIZE);
+ pAdapter->NicPageStart = pAdapter->NicXmitStart +
+ (UCHAR)(pAdapter->NumBuffers * BUFS_PER_TX);
+
+ //
+ // The end of the receive space.
+ //
+ pAdapter->PageStop = pAdapter->XmitStart + 0x2000;
+ pAdapter->NicPageStop = pAdapter->NicXmitStart + (UCHAR)0x20;
+
+ //
+ // Initialize the receive variables.
+ //
+ pAdapter->NicReceiveConfig = RCR_REJECT_ERR;
+
+ //
+ // Initialize the transmit buffer control.
+ //
+ pAdapter->CurBufXmitting = (XMIT_BUF)-1;
+ pAdapter->BufferOverflow = FALSE;
+ pAdapter->OverflowRestartXmitDpc = FALSE;
+
+ //
+ // Mark the buffers as empty.
+ //
+ for (c = 0; c < pAdapter->NumBuffers; c++ )
+ pAdapter->BufferStatus[c] = EMPTY;
+
+ //
+ // The transmit and loopback queues start out empty.
+ // Alredy done since the structure is zero'd out.
+ //
+
+ //
+ // Clear the tally counters.
+ // Already done since the structure is zero'd out.
+ //
+
+ //
+ // Read the Ethernet address off of the PROM.
+ //
+ CardReadEthernetAddress(pAdapter);
+
+ //
+ // Initialize the NIC and Gate Array registers.
+ //
+ pAdapter->NicInterruptMask = IMR_RCV |
+ IMR_XMIT |
+ IMR_XMIT_ERR |
+ IMR_OVERFLOW;
+
+ //
+ // Link us on to the chain of adapters for this miniport.
+ //
+ pAdapter->pNextElnkiiAdapter = ElnkiiMiniportBlock.AdapterQueue;
+ ElnkiiMiniportBlock.AdapterQueue = pAdapter;
+
+ //
+ // Turn off the card.
+ //
+ SyncCardStop(pAdapter);
+
+ //
+ // Set flag to ignore interrupts.
+ //
+ pAdapter->InCardTest = TRUE;
+
+ //
+ // Initialize the interrupt.
+ //
+ Status = NdisMRegisterInterrupt(
+ &pAdapter->Interrupt,
+ pAdapter->MiniportAdapterHandle,
+ pAdapter->InterruptNumber,
+ pAdapter->InterruptNumber,
+ FALSE,
+ FALSE,
+ NdisInterruptLatched
+ );
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ NdisWriteErrorLogEntry(
+ pAdapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_INTERRUPT_CONNECT,
+ 0
+ );
+
+ goto fail3;
+ }
+
+ IF_LOUD( DbgPrint("Interrupt Connected\n"); )
+
+ //
+ // Initialize the card.
+ //
+ if (!CardSetup(pAdapter))
+ {
+ //
+ // The NIC could not be initialized.
+ //
+ NdisWriteErrorLogEntry(
+ pAdapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
+ 0
+ );
+
+ Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+
+ goto fail4;
+ }
+
+ //
+ // Perform card tests.
+ //
+ if (!CardTest(pAdapter))
+ {
+ //
+ // The tests failed, InitialCardTest determines whether this
+ // causes the whole initialization to fail.
+ //
+ if (InitialCardTest)
+ {
+ NdisWriteErrorLogEntry(
+ pAdapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 0
+ );
+
+ Status = NDIS_STATUS_DEVICE_FAILED;
+
+ goto fail4;
+ }
+ }
+
+ //
+ // Normal mode now.
+ //
+ pAdapter->InCardTest = FALSE;
+
+ //
+ // Start the card.
+ //
+ CardStart(pAdapter);
+
+ return(NDIS_STATUS_SUCCESS);
+
+fail4:
+ //
+ // Deregister the interrupt.
+ //
+ NdisMDeregisterInterrupt(&pAdapter->Interrupt);
+
+fail3:
+ //
+ // Take us out of the AdapterQueue.
+ //
+ if (ElnkiiMiniportBlock.AdapterQueue == pAdapter)
+ {
+ ElnkiiMiniportBlock.AdapterQueue = pAdapter->pNextElnkiiAdapter;
+ }
+ else
+ {
+ PELNKII_ADAPTER pTmp = ElnkiiMiniportBlock.AdapterQueue;
+
+ while (pTmp->pNextElnkiiAdapter != pAdapter)
+ {
+ pTmp = pTmp->pNextElnkiiAdapter;
+ }
+
+ pTmp->pNextElnkiiAdapter = pTmp->pNextElnkiiAdapter->pNextElnkiiAdapter;
+ }
+
+ //
+ // We already enabled the interrupt on the card, so turn it off.
+ //
+ NdisRawWritePortUchar(pAdapter->MappedGaBaseAddr + GA_INT_DMA_CONFIG, 0x00);
+
+fail2:
+
+ if (NULL != pAdapter->MappedIoBaseAddr)
+ {
+ //
+ // Deregister the base I/O port range.
+ //
+ NdisMDeregisterIoPortRange(
+ pAdapter->MiniportAdapterHandle,
+ (ULONG)pAdapter->IoBaseAddr,
+ 0x10,
+ pAdapter->MappedIoBaseAddr
+ );
+ }
+
+ if (NULL != pAdapter->MappedGaBaseAddr)
+ {
+ //
+ // Deregister the gate array I/O port range.
+ //
+ NdisMDeregisterIoPortRange(
+ pAdapter->MiniportAdapterHandle,
+ (ULONG)pAdapter->IoBaseAddr + 0x400,
+ 0x10,
+ pAdapter->MappedGaBaseAddr
+ );
+ }
+
+fail1:
+
+ return(Status);
+}
+
+#pragma NDIS_INIT_FUNCTION(ElnkiiInitialize)
+
+NDIS_STATUS ElnkiiInitialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE ConfigurationHandle
+)
+{
+ PELNKII_ADAPTER pAdapter; // Pointer to the new adapter.
+ NDIS_HANDLE hConfig; // Handle for reading the registry.
+ ULONG NetAddressLength; // Number of bytes in the address.
+ PVOID NetAddress; // The network address that the adapter
+ // should use instead of the burned
+ // in default address.
+ NDIS_STATUS Status;
+ UINT c; // Temporary count variable.
+
+ //
+ // TRUE if there is a configuration error.
+ //
+ BOOLEAN ConfigError;
+
+ //
+ // A special value to log concerning the error.
+ //
+ ULONG ConfigErrorValue;
+
+
+ //
+ // Value read from the registry.
+ //
+ PNDIS_CONFIGURATION_PARAMETER ReturnedValue; // Value read from registry.
+
+ //
+ // String names of the parameters that will be
+ // read from the registry.
+ //
+ NDIS_STRING MaxMulticastListStr = MAXMULTICAST;
+ NDIS_STRING NetworkAddressStr = NETWORK_ADDRESS;
+ NDIS_STRING MemoryMappedStr = MEMORYMAPPED;
+ NDIS_STRING TransceiverStr = TRANSCEIVER;
+
+#if NDIS2
+ NDIS_STRING ExternalStr = NDIS_STRING_CONST("EXTERNAL");
+#endif
+
+ //
+ // These are used when calling ElnkiiRegisterAdapter.
+ //
+ PVOID IoBaseAddress;
+ CCHAR InterruptNumber;
+ BOOLEAN ExternalTransceiver;
+ BOOLEAN MemMapped;
+ UINT MaxMulticastList;
+
+ //
+ // Initialize some locals.
+ //
+ ConfigError = FALSE;
+ ConfigErrorValue = 0;
+
+ IoBaseAddress = DEFAULT_IOBASEADDR;
+ InterruptNumber = DEFAULT_INTERRUPTNUMBER;
+ ExternalTransceiver = DEFAULT_EXTERNALTRANSCEIVER;
+ MemMapped = DEFAULT_MEMMAPPED;
+ MaxMulticastList = DEFAULT_MULTICASTLISTMAX;
+
+ //
+ // Search for the 802.3 medium type in the given array.
+ //
+ for
+ (
+ c = 0;
+ c < MediumArraySize;
+ c++
+ )
+ {
+ //
+ // If we find it, stop looking.
+ //
+ if (NdisMedium802_3 == MediumArray[c])
+ break;
+ }
+
+ //
+ // Did we find our medium?
+ //
+ if (c == MediumArraySize)
+ return(NDIS_STATUS_UNSUPPORTED_MEDIA);
+
+ //
+ // Save the index of the type to return to wrapper.
+ //
+ *SelectedMediumIndex = c;
+
+ //
+ // Allocate some memory for the adapter block.
+ //
+ Status = NdisAllocateMemory(
+ (PVOID *)&pAdapter,
+ sizeof(ELNKII_ADAPTER),
+ 0,
+ HighestAcceptableMax
+ );
+ if (NDIS_STATUS_SUCCESS != Status)
+ return(Status);
+
+ //
+ // Initialize the adapter block.
+ //
+ NdisZeroMemory(pAdapter, sizeof(ELNKII_ADAPTER));
+
+ //
+ // Open the configuration space.
+ //
+ NdisOpenConfiguration(&Status, &hConfig, ConfigurationHandle);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ NdisFreeMemory(pAdapter, sizeof(ELNKII_ADAPTER), 0);
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // Read the base I/O address.
+ //
+ ReadBaseIoAddress(&Status, &IoBaseAddress, hConfig, MiniportAdapterHandle);
+ if (NDIS_STATUS_SUCCESS != Status)
+ return(Status);
+
+ //
+ // Read the interrupt number.
+ //
+ ReadInterruptNumber(
+ &Status,
+ &InterruptNumber,
+ hConfig,
+ MiniportAdapterHandle
+ );
+ if (NDIS_STATUS_SUCCESS != Status)
+ return(Status);
+
+
+#if !NDIS2
+ //
+ // Read the MaxMulticastList
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ hConfig,
+ &MaxMulticastListStr,
+ NdisParameterInteger
+ );
+
+ if (NDIS_STATUS_SUCCESS == Status)
+ MaxMulticastList = ReturnedValue->ParameterData.IntegerData;
+
+#endif
+
+#if NDIS_NT
+ //
+ // Read Memory Mapped information.
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ hConfig,
+ &MemoryMappedStr,
+ NdisParameterHexInteger
+ );
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ MemMapped =
+ (ReturnedValue->ParameterData.IntegerData == 0) ? FALSE : TRUE;
+ }
+
+#endif
+
+#if NDIS2
+ //
+ // Read NDIS2 transceiver type.
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ hConfig,
+ &TransceiverStr,
+ NdisParameterString
+ );
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ if (NdisEqualString(&ReturnedValue->ParameterData.StringData, &ExternalStr, 1))
+ ExternalTransceiver = TRUE;
+ }
+
+#else
+ //
+ // Read NDIS3 transceiver type.
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ hConfig,
+ &TransceiverStr,
+ NdisParameterInteger
+ );
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ ExternalTransceiver =
+ (ReturnedValue->ParameterData.IntegerData == 1) ? TRUE : FALSE;
+ }
+#endif
+
+
+ //
+ // Read network address.
+ //
+ NdisReadNetworkAddress(
+ &Status,
+ &NetAddress,
+ &NetAddressLength,
+ hConfig
+ );
+ if
+ (
+ (ETH_LENGTH_OF_ADDRESS == NetAddressLength) &&
+ (NDIS_STATUS_SUCCESS == Status)
+ )
+ {
+ //
+ // We have a valid ethernet address, save it.
+ //
+ ETH_COPY_NETWORK_ADDRESS(pAdapter->StationAddress, NetAddress);
+ }
+
+
+ //
+ // Close the configuration space.
+ //
+ NdisCloseConfiguration(hConfig);
+
+ IF_LOUD( DbgPrint(
+ "Registering adapter # buffers %ld, "
+ "I/O base address 0x%lx, interrupt number %ld,"
+ "external %c, memory mapped %c, max multicast %ld\n",
+ DEFAULT_NUMBUFFERS,
+ IoBaseAddress,
+ InterruptNumber,
+ ExternalTransceiver ? 'Y' : 'N',
+ MemMapped ? 'Y' : 'N',
+ DEFAULT_MULTICASTLISTMAX
+ );)
+
+ //
+ // Set up the parameters.
+ //
+ pAdapter->NumBuffers = DEFAULT_NUMBUFFERS;
+ pAdapter->IoBaseAddr = IoBaseAddress;
+ pAdapter->ExternalTransceiver = ExternalTransceiver;
+ pAdapter->InterruptNumber = InterruptNumber;
+ pAdapter->MemMapped = MemMapped;
+ pAdapter->MulticastListMax = MaxMulticastList;
+ pAdapter->MiniportAdapterHandle = MiniportAdapterHandle;
+
+ //
+ // Register the adapter.
+ //
+ Status = ElnkiiRegisterAdapter(pAdapter, ConfigurationHandle);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ NdisFreeMemory(pAdapter, sizeof(ELNKII_ADAPTER), 0);
+
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ IF_LOUD(DbgPrint("ElnkiiRegisterAdapter succeeded\n");)
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+
+
+NDIS_STATUS ElnkiiQueryInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+)
+/*++
+
+Routine Description:
+
+ The ElnkiiQueryInformation processes a query request for NDIS_OIDs that
+ are specific about the Driver.
+
+Arguments:
+
+ MiniportAdapterContext - A pointer to the adapter.
+ Oid - The NDIS_OID to process.
+ InformationBuffer - A pointer to the NdisRequest->InformationBuffer
+ into which we store the result of the query.
+ InformationBufferLength - Number of bytes in the information buffer.
+ BytesWritten - A pointer to the number of bytes written into
+ the InformationBuffer.
+ BytesNeeded - If there is not enough room in the information
+ buffer then this will contain the number of
+ bytes needed to complete the request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ //
+ // Poiter to the adapter structure.
+ //
+ PELNKII_ADAPTER pAdapter = (PELNKII_ADAPTER)MiniportAdapterContext;
+
+ //
+ // General Algorithm:
+ //
+ // Switch (Request)
+ // Get requested information
+ // Store results in a common variable
+ // default:
+ // Try protocol query information
+ // If that fails, fail query
+ //
+ // Copy result in common variable to result buffer.
+ //
+ // Finish processing
+ //
+
+ UINT BytesLeft = InformationBufferLength;
+ PUCHAR InfoBuffer = (PUCHAR)InformationBuffer;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady;
+ NDIS_MEDIUM Medium = NdisMedium802_3;
+
+ ULONG GenericULong;
+ USHORT GenericUShort;
+ UCHAR GenericArray[6];
+ UINT MoveBytes = sizeof(ULONG);
+ PVOID MoveSource = (PVOID)&GenericULong;
+
+ //
+ // Make sure that in is 4 bytes. Else GenericULong must change
+ // to something of size 4.
+ //
+ ASSERT(sizeof(ULONG) == 4);
+
+ //
+ // Switch on request type.
+ //
+ switch (Oid)
+ {
+ case OID_GEN_MAC_OPTIONS:
+ GenericULong = (ULONG)(NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
+ NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
+ NDIS_MAC_OPTION_NO_LOOPBACK);
+
+ if (!pAdapter->MemMapped)
+ GenericULong |= NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA;
+
+ break;
+
+ case OID_GEN_SUPPORTED_LIST:
+ MoveSource = (PVOID)ElnkiiSupportedOids;
+ MoveBytes = sizeof(ElnkiiSupportedOids);
+
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+ HardwareStatus = NdisHardwareStatusReady;
+ MoveSource = (PVOID)&HardwareStatus;
+ MoveBytes = sizeof(NDIS_HARDWARE_STATUS);
+
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+ MoveSource = (PVOID)&Medium;
+ MoveBytes = sizeof(NDIS_MEDIUM);
+
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+
+ GenericULong = ELNKII_MAX_LOOKAHEAD;
+
+ break;
+
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+
+ GenericULong = (ULONG)(1514 - ELNKII_HEADER_SIZE);
+
+ break;
+
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+
+ GenericULong = (ULONG)1514;
+
+ break;
+
+ case OID_GEN_LINK_SPEED:
+
+ GenericULong = (ULONG)100000;
+
+ break;
+
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+
+ GenericULong = (ULONG)(pAdapter->NumBuffers * TX_BUF_SIZE);
+
+ break;
+
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+
+ GenericULong = (ULONG)0x2000;
+ GenericULong -= (pAdapter->NumBuffers *
+ ((TX_BUF_SIZE / 256) + 1) * 256);
+
+ //
+ // Subtract off receive buffer overhead
+ //
+ {
+ ULONG TmpUlong = GenericULong / 256;
+
+ TmpUlong *= 4;
+
+ GenericULong -= TmpUlong;
+ }
+
+ //
+ // Round to nearest 256 bytes
+ //
+ GenericULong = (GenericULong / 256) * 256;
+
+ break;
+
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+
+ GenericULong = (ULONG)TX_BUF_SIZE;
+
+ break;
+
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+
+ GenericULong = (ULONG)256;
+
+ break;
+
+ case OID_GEN_VENDOR_ID:
+
+ NdisMoveMemory(
+ (PVOID)(&GenericULong),
+ pAdapter->PermanentAddress,
+ 3
+ );
+
+ GenericULong &= 0xFFFFFF00;
+
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+
+ MoveSource = (PVOID)"Etherlink II Adapter.";
+ MoveBytes = 22;
+
+ break;
+
+ case OID_GEN_DRIVER_VERSION:
+
+ GenericUShort = ((USHORT)ELNKII_NDIS_MAJOR_VERSION << 8) |
+ ELNKII_NDIS_MINOR_VERSION;
+
+ MoveSource = (PVOID)&GenericUShort;
+ MoveBytes = sizeof(GenericUShort);
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ GenericULong = (ULONG)(pAdapter->MaxLookAhead);
+
+ break;
+
+ case OID_802_3_PERMANENT_ADDRESS:
+ ELNKII_MOVE_MEM((PCHAR)GenericArray,
+ pAdapter->PermanentAddress,
+ ETH_LENGTH_OF_ADDRESS);
+
+ MoveSource = (PVOID)GenericArray;
+ MoveBytes = sizeof(pAdapter->PermanentAddress);
+ break;
+
+ case OID_802_3_CURRENT_ADDRESS:
+
+ ELNKII_MOVE_MEM((PCHAR)GenericArray,
+ pAdapter->StationAddress,
+ ETH_LENGTH_OF_ADDRESS);
+
+ MoveSource = (PVOID)GenericArray;
+ MoveBytes = sizeof(pAdapter->StationAddress);
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+
+ GenericULong = (ULONG)pAdapter->MulticastListMax;
+
+ break;
+
+ case OID_GEN_XMIT_OK:
+
+ GenericULong = (UINT)pAdapter->FramesXmitGood;
+
+ break;
+
+ case OID_GEN_RCV_OK:
+
+ GenericULong = (UINT)pAdapter->FramesRcvGood;
+
+ break;
+
+ case OID_GEN_XMIT_ERROR:
+
+ GenericULong = (UINT)pAdapter->FramesXmitBad;
+
+ break;
+
+ case OID_GEN_RCV_ERROR:
+
+ GenericULong = (UINT)pAdapter->CrcErrors;
+
+ case OID_GEN_RCV_NO_BUFFER:
+
+ GenericULong = (UINT)pAdapter->MissedPackets;
+
+ break;
+
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+
+ GenericULong = (UINT)pAdapter->FrameAlignmentErrors;
+
+ break;
+
+ case OID_802_3_XMIT_ONE_COLLISION:
+
+ GenericULong = (UINT)pAdapter->FramesXmitOneCollision;
+
+ break;
+
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+
+ GenericULong = (UINT)pAdapter->FramesXmitManyCollisions;
+
+ break;
+
+ default:
+
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ if (MoveBytes > BytesLeft)
+ {
+ //
+ // Not enough room in InformationBuffer.
+ //
+ *BytesNeeded = MoveBytes;
+
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ }
+ else
+ {
+ //
+ // Store the result.
+ //
+ ELNKII_MOVE_MEM(InfoBuffer, MoveSource, MoveBytes);
+
+ (*BytesWritten) += MoveBytes;
+ }
+ }
+
+ return(Status);
+}
+
+
+
+NDIS_STATUS DispatchSetPacketFilter(
+ IN PELNKII_ADAPTER pAdapter
+)
+
+/*++
+
+Routine Description:
+
+ Sets the appropriate bits in the adapter filters
+ and modifies the card Receive Configuration Register if needed.
+
+Arguments:
+
+ pAdapter - Pointer to the adapter block
+
+Return Value:
+
+ The final status (always NDIS_STATUS_SUCCESS).
+
+Notes:
+
+ - Note that to receive all multicast packets the multicast
+ registers on the card must be filled with 1's. To be
+ promiscuous that must be done as well as setting the
+ promiscuous physical flag in the RCR. This must be done
+ as long as ANY protocol bound to this adapter has their
+ filter set accordingly.
+
+--*/
+
+
+{
+ UINT PacketFilter;
+
+ //
+ // See what has to be put on the card.
+ //
+ if
+ (
+ pAdapter->PacketFilter &
+ (NDIS_PACKET_TYPE_ALL_MULTICAST | NDIS_PACKET_TYPE_PROMISCUOUS)
+ )
+ {
+ //
+ // Need "all multicast" now.
+ //
+ CardSetAllMulticast(pAdapter);
+ }
+ else
+ {
+ //
+ // No longer need "all multicast".
+ //
+ DispatchSetMulticastAddressList(pAdapter);
+ }
+
+ //
+ // The multicast bit in the RCR should be on if ANY protocol wants
+ // multicast/all multicast packets (or is promiscuous).
+ //
+ if
+ (
+ pAdapter->PacketFilter &
+ (NDIS_PACKET_TYPE_ALL_MULTICAST |
+ NDIS_PACKET_TYPE_MULTICAST |
+ NDIS_PACKET_TYPE_PROMISCUOUS)
+ )
+ {
+ pAdapter->NicReceiveConfig |= RCR_MULTICAST;
+ }
+ else
+ {
+ pAdapter->NicReceiveConfig &= ~RCR_MULTICAST;
+ }
+
+ //
+ // The promiscuous physical bit in the RCR should be on if ANY
+ // protocol wants to be promiscuous.
+ //
+ if (pAdapter->PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS)
+ pAdapter->NicReceiveConfig |= RCR_ALL_PHYS;
+ else
+ pAdapter->NicReceiveConfig &= ~RCR_ALL_PHYS;
+
+
+ //
+ // The broadcast bit in the RCR should be on if ANY protocol wants
+ // broadcast packets (or is promiscuous).
+ //
+ if
+ (
+ pAdapter->PacketFilter &
+ (NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_PROMISCUOUS)
+ )
+ {
+ pAdapter->NicReceiveConfig |= RCR_BROADCAST;
+ }
+ else
+ {
+ pAdapter->NicReceiveConfig &= ~RCR_BROADCAST;
+ }
+
+ CardSetReceiveConfig(pAdapter);
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+
+NDIS_STATUS DispatchSetMulticastAddressList(
+ IN PELNKII_ADAPTER pAdapter
+)
+
+/*++
+
+Routine Description:
+
+ Sets the multicast list for this open
+
+Arguments:
+
+ AdaptP - Pointer to the adapter block
+
+Return Value:
+
+Implementation Note:
+
+ When invoked, we are to make it so that the multicast list in the filter
+ package becomes the multicast list for the adapter. To do this, we
+ determine the required contents of the NIC multicast registers and
+ update them.
+
+
+--*/
+{
+
+ //
+ // Update the local copy of the NIC multicast regs
+ // and copy them to the NIC
+ //
+
+ CardFillMulticastRegs(pAdapter);
+
+ CardCopyMulticastRegs(pAdapter);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+
+NDIS_STATUS ElnkiiSetInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+)
+/*++
+
+Routine Description:
+
+ The ElnkiiSetInformation is used by ElnkiiRequest to set information
+ about the MAC.
+
+Arguments:
+
+ MiniportAdapterContext - Context registered with the wrapper, actually
+ a pointer to the adapter information.
+ Oid - The OID to set.
+ InformationBuffer - Holds the new data for the OID.
+ InformationBufferLength - Length of the InformationBuffer.
+ BytesRead - If the call is successful, returns the number
+ of bytes read from InformationBuffer.
+ BytesNeeded - If there is not enough data in InformationBuffer
+ to satisfy the OID, returns the amount of
+ storage needed.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ //
+ // Pointer to the adapter structure.
+ //
+ PELNKII_ADAPTER pAdapter = (PELNKII_ADAPTER)MiniportAdapterContext;
+
+ //
+ // General Algorithm:
+ //
+ // Verify length
+ // Switch(Request)
+ // Process Request
+ //
+ UINT BytesLeft = InformationBufferLength;
+ PUCHAR InfoBuffer = (PUCHAR)InformationBuffer;
+
+ //
+ // Variables for a particular request.
+ //
+ UINT OidLength;
+
+ //
+ // Variables for holding the new value to be used.
+ //
+ ULONG LookAhead;
+ ULONG Filter;
+
+ //
+ // Status of the operation.
+ //
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ //
+ // Get Oid and Length of request
+ //
+ OidLength = BytesLeft;
+
+ switch (Oid)
+ {
+ case OID_802_3_MULTICAST_LIST:
+ //
+ // Verify length
+ //
+ if ((OidLength % ETH_LENGTH_OF_ADDRESS) != 0)
+ {
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ *BytesRead = 0;
+ *BytesNeeded = 0;
+
+ break;
+ }
+
+ NdisMoveMemory(pAdapter->MulticastAddresses, InfoBuffer, OidLength);
+
+ //
+ // If we are currently receiving all multicast or
+ // we are in promiscuous then we DO NOT call this,
+ // or it will reset thoes settings.
+ //
+ if
+ (
+ !(pAdapter->PacketFilter & (NDIS_PACKET_TYPE_ALL_MULTICAST |
+ NDIS_PACKET_TYPE_PROMISCUOUS))
+ )
+ {
+ Status = DispatchSetMulticastAddressList(pAdapter);
+ }
+ else
+ {
+ //
+ // Our list of multicast addresses is kept by the wrapper.
+ //
+ Status = NDIS_STATUS_SUCCESS;
+ }
+
+ break;
+
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ //
+ // Verify length
+ //
+ if (OidLength != 4 )
+ {
+ Status = NDIS_STATUS_INVALID_LENGTH;
+
+ *BytesRead = 0;
+ *BytesNeeded = 0;
+
+ break;
+
+ }
+
+ ELNKII_MOVE_MEM(&Filter, InfoBuffer, 4);
+
+ //
+ // Verify bits
+ //
+ if
+ (
+ Filter &
+ (NDIS_PACKET_TYPE_SOURCE_ROUTING |
+ NDIS_PACKET_TYPE_SMT |
+ NDIS_PACKET_TYPE_MAC_FRAME |
+ NDIS_PACKET_TYPE_FUNCTIONAL |
+ NDIS_PACKET_TYPE_ALL_FUNCTIONAL |
+ NDIS_PACKET_TYPE_GROUP)
+ )
+ {
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+
+ *BytesRead = 4;
+ *BytesNeeded = 0;
+
+ break;
+
+ }
+
+ pAdapter->PacketFilter = Filter;
+ Status = DispatchSetPacketFilter(pAdapter);
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ //
+ // Verify length
+ //
+
+ if (OidLength != 4)
+ {
+ Status = NDIS_STATUS_INVALID_LENGTH;
+
+ *BytesRead = 0;
+ *BytesNeeded = 0;
+
+ break;
+ }
+
+ //
+ // Store the new value.
+ //
+ ELNKII_MOVE_MEM(&LookAhead, InfoBuffer, 4);
+
+ if (LookAhead <= ELNKII_MAX_LOOKAHEAD)
+ pAdapter->MaxLookAhead = LookAhead;
+ else
+ Status = NDIS_STATUS_INVALID_LENGTH;
+
+ break;
+
+ default:
+
+ Status = NDIS_STATUS_INVALID_OID;
+
+ *BytesRead = 0;
+ *BytesNeeded = 0;
+
+ break;
+ }
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ *BytesRead = BytesLeft;
+ *BytesNeeded = 0;
+ }
+
+ return(Status);
+}
+
+
+VOID ElnkiiHalt(
+ IN NDIS_HANDLE MiniportAdapterContext
+)
+{
+ PELNKII_ADAPTER pAdapter;
+
+ //
+ // Get a pointer to our adapter information.
+ //
+ pAdapter = (PELNKII_ADAPTER)MiniportAdapterContext;
+
+ //
+ // Stop the card.
+ //
+ CardStop(pAdapter);
+
+ //
+ // Disconnect the interrupt line.
+ //
+ NdisMDeregisterInterrupt(&pAdapter->Interrupt);
+
+ //
+ // Pause, waiting for any DPC stuff to clear.
+ //
+ NdisStallExecution(250000);
+
+ NdisMDeregisterIoPortRange(
+ pAdapter->MiniportAdapterHandle,
+ (ULONG)pAdapter->IoBaseAddr,
+ 0x10,
+ pAdapter->MappedIoBaseAddr
+ );
+
+ NdisMDeregisterIoPortRange(
+ pAdapter->MiniportAdapterHandle,
+ (ULONG)pAdapter->IoBaseAddr + 0x400,
+ 0x10,
+ pAdapter->MappedGaBaseAddr
+ );
+
+ //
+ // Remove the adapter from the global queue of adapters.
+ //
+ if (ElnkiiMiniportBlock.AdapterQueue == pAdapter)
+ {
+ ElnkiiMiniportBlock.AdapterQueue = pAdapter->pNextElnkiiAdapter;
+ }
+ else
+ {
+ PELNKII_ADAPTER pTmp = ElnkiiMiniportBlock.AdapterQueue;
+
+ while (pTmp->pNextElnkiiAdapter != pAdapter)
+ {
+ pTmp = pTmp->pNextElnkiiAdapter;
+ }
+
+ pTmp->pNextElnkiiAdapter = pTmp->pNextElnkiiAdapter->pNextElnkiiAdapter;
+ }
+
+ //
+ // Free up the memory.
+ //
+ NdisFreeMemory(pAdapter, sizeof(ELNKII_ADAPTER), 0);
+
+ return;
+}
+
+
+
+NDIS_STATUS ElnkiiReset(
+ OUT PBOOLEAN pfAddressingReset,
+ IN NDIS_HANDLE MiniportAdapterContext
+)
+
+/*++
+
+Routine Description:
+
+ NDIS function.
+
+Arguments:
+
+ See NDIS 3.0 spec.
+
+--*/
+
+{
+ PELNKII_ADAPTER pAdapter = (PELNKII_ADAPTER)MiniportAdapterContext;
+ UINT c;
+
+ //
+ // Clear the values for transmits, they will be reset after the
+ // the reset is completed.
+ //
+ pAdapter->NextBufToFill = 0;
+ pAdapter->NextBufToXmit = 0;
+ pAdapter->CurBufXmitting = (XMIT_BUF)-1;
+
+ pAdapter->XmitQueue = NULL;
+ pAdapter->XmitQTail = NULL;
+
+ //
+ // Mark the buffers as empty.
+ //
+ for (c = 0; c < pAdapter->NumBuffers; c++)
+ pAdapter->BufferStatus[c] = EMPTY;
+
+ //
+ // Physically reset the card.
+ //
+ pAdapter->NicInterruptMask = IMR_RCV | IMR_XMIT | IMR_XMIT_ERR | IMR_OVERFLOW;
+
+ return(CardReset(pAdapter) ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE);
+}
+
diff --git a/private/ntos/ndis/elnkii.new/elnkii.rc b/private/ntos/ndis/elnkii.new/elnkii.rc
new file mode 100644
index 000000000..73b14edf9
--- /dev/null
+++ b/private/ntos/ndis/elnkii.new/elnkii.rc
@@ -0,0 +1,39 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "3Com Etherlink II and II/16 network driver"
+#define VER_INTERNALNAME_STR "ELNKII.SYS"
+#define VER_ORIGINALFILENAME_STR "ELNKII.SYS"
+
+#include "common.ver"
+
diff --git a/private/ntos/ndis/elnkii.new/elnksft.h b/private/ntos/ndis/elnkii.new/elnksft.h
new file mode 100644
index 000000000..003d4216f
--- /dev/null
+++ b/private/ntos/ndis/elnkii.new/elnksft.h
@@ -0,0 +1,824 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ elnksft.h
+
+Abstract:
+
+ The main header for an Etherlink II MAC driver.
+
+Author:
+
+ Anthony V. Ercolano (tonye) creation-date 19-Jun-1990 (Driver Model)
+
+ Adam Barr (adamba) - original Elnkii code.
+
+Environment:
+
+ This driver is expected to work in DOS, OS2 and NT at the equivalent
+ of kernal mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+ Dec-1991 by Sean Selitrennikoff - Fit AdamBa's code into TonyE's model
+
+
+--*/
+
+#ifndef _ELNKIISFT_
+#define _ELNKIISFT_
+
+#define ELNKII_NDIS_MAJOR_VERSION 3
+#define ELNKII_NDIS_MINOR_VERSION 0
+
+//
+// This macro is used along with the flags to selectively
+// turn on debugging.
+//
+
+#if DBG
+
+#define IF_ELNKIIDEBUG(f) if (ElnkiiDebugFlag & (f))
+extern ULONG ElnkiiDebugFlag;
+
+#define ELNKII_DEBUG_LOUD 0x00000001 // debugging info
+#define ELNKII_DEBUG_VERY_LOUD 0x00000002 // excessive debugging info
+#define ELNKII_DEBUG_LOG 0x00000004 // enable ElnkiiLog
+#define ELNKII_DEBUG_CHECK_DUP_SENDS 0x00000008 // check for duplicate sends
+#define ELNKII_DEBUG_TRACK_PACKET_LENS 0x00000010 // track directed packet lens
+#define ELNKII_DEBUG_WORKAROUND1 0x00000020 // drop DFR/DIS packets
+#define ELNKII_DEBUG_CARD_BAD 0x00000040 // dump data if CARD_BAD
+#define ELNKII_DEBUG_CARD_TESTS 0x00000080 // print reason for failing
+
+
+
+//
+// Macro for deciding whether to dump lots of debugging information.
+//
+
+#define IF_LOUD(A) IF_ELNKIIDEBUG( ELNKII_DEBUG_LOUD ) { A }
+#define IF_VERY_LOUD(A) IF_ELNKIIDEBUG( ELNKII_DEBUG_VERY_LOUD ) { A }
+
+
+#else
+
+#define IF_LOUD(A)
+#define IF_VERY_LOUD(A)
+
+#endif
+
+
+//
+// Whether to use the ElnkiiLog
+//
+
+#if DBG
+
+#define IF_LOG(A) IF_ELNKIIDEBUG( ELNKII_DEBUG_LOG ) { A }
+extern VOID ElnkiiLog(UCHAR);
+
+#else
+
+#define IF_LOG(A)
+
+#endif
+
+
+//
+// Whether to do loud init failure
+//
+
+#if DBG
+#define IF_INIT(A) A
+#else
+#define IF_INIT(A)
+#endif
+
+
+//
+// Whether to do loud card test failures
+//
+
+#if DBG
+#define IF_TEST(A) IF_ELNKIIDEBUG( ELNKII_DEBUG_CARD_TESTS ) { A }
+#else
+#define IF_TEST(A)
+#endif
+
+
+
+
+//
+// Macros for services that differ between DOS and NT, we may consider adding these
+// into the NDIS spec.
+//
+
+
+//
+// AdaptP->NumBuffers
+//
+// controls the number of transmit buffers on the packet.
+// Choices are 1 or 2.
+//
+
+#define DEFAULT_NUMBUFFERS 2
+
+
+#define ELNKII_MOVE_MEM_TO_SHARED_RAM(dest,src,size) \
+ NdisMoveToMappedMemory(dest, src, size)
+
+#define ELNKII_MOVE_SHARED_RAM_TO_MEM(dest,src,size) \
+ NdisMoveFromMappedMemory(dest, src, size)
+
+
+
+#define ELNKII_MOVE_MEM(dest,src,size) NdisMoveMemory(dest,src,size)
+
+//
+// The status of transmit buffers.
+//
+
+typedef enum { EMPTY, FILLING, FULL } BUFFER_STATUS;
+
+
+//
+// Type of an interrupt.
+//
+
+typedef enum { RECEIVE = 0x01,
+ TRANSMIT = 0x02,
+ OVERFLOW = 0x04,
+ COUNTER = 0x08,
+ UNKNOWN = 0x10} INTERRUPT_TYPE;
+
+//
+// Result of ElnkiiIndicate[Loopback]Packet().
+//
+
+typedef enum { INDICATE_OK, SKIPPED, ABORT, CARD_BAD } INDICATE_STATUS;
+
+
+//
+// Number of bytes in an ethernet header
+//
+
+#define ELNKII_HEADER_SIZE 14
+
+//
+// Number of bytes allowed in a lookahead (max)
+//
+
+#define ELNKII_MAX_LOOKAHEAD (252 - ELNKII_HEADER_SIZE)
+
+
+
+//
+// Maximum number of transmit buffers on the card.
+//
+
+#define MAX_XMIT_BUFS 2
+
+
+//
+// A transmit buffer (usually 0 or 1).
+//
+
+typedef UINT XMIT_BUF;
+
+
+//
+// Number of 256-byte buffers in a transmit buffer.
+//
+
+#define BUFS_PER_TX 6
+
+
+//
+// Size of a single transmit buffer.
+//
+
+#define TX_BUF_SIZE (BUFS_PER_TX*256)
+
+
+
+//
+// Only have one of these structures.
+//
+
+typedef struct _DRIVER_BLOCK
+{
+ //
+ // Returned from NdisMInitializeWrapper.
+ //
+ NDIS_HANDLE NdisWrapperHandle;
+
+ //
+ // Adapters registered for this miniport.
+ //
+ struct _ELNKII_ADAPTER *AdapterQueue;
+}
+ DRIVER_BLOCK,
+ *PDRIVER_BLOCK;
+
+
+
+//
+// One of these structures per adapter registered.
+//
+
+typedef struct _ELNKII_ADAPTER
+{
+ //
+ // Handle given by the wrapper for calling NDIS functions.
+ //
+ NDIS_HANDLE MiniportAdapterHandle;
+
+ //
+ // Miniport's interrupt object.
+ //
+ NDIS_MINIPORT_INTERRUPT Interrupt;
+
+ //
+ // Used by the DriverBlock->AdapterQueue
+ //
+ struct _ELNKII_ADAPTER *pNextElnkiiAdapter;
+
+ //
+ // This is a count of the number of receives that have been
+ // indicated in a row. This is used to limit the number
+ // of sequential receives so that one can periodically check
+ // for transmit complete interrupts.
+ //
+ ULONG ReceivePacketCount;
+
+ //
+ // Configuration information
+ //
+
+ UINT NumBuffers; // Number of buffers in this adapter.
+ PVOID IoBaseAddr; // Physical address of the IoBaseAddress.
+ CHAR InterruptNumber; // Interrupt number adapter is using.
+ UINT MulticastListMax; // Number of multicast address that
+ // this adapter is to support.
+ PVOID MemBaseAddr; // Actually read off the card.
+ BOOLEAN ExternalTransceiver; // Is the external transceiver in use?
+ BOOLEAN MemMapped; // Actually read off the card
+ BOOLEAN InCardTest; // Are we testing the card?
+ PUCHAR MappedIoBaseAddr;
+ PUCHAR MappedGaBaseAddr;
+
+ //
+ // Transmit queue.
+ //
+
+ PNDIS_PACKET XmitQueue; // packets waiting to be transmitted
+ PNDIS_PACKET XmitQTail;
+
+ //
+ // Transmit information.
+ //
+
+ XMIT_BUF NextBufToFill; // where to copy next packet to
+ XMIT_BUF NextBufToXmit; // valid if CurBufXmitting is -1
+ XMIT_BUF CurBufXmitting; // -1 if none is
+ BOOLEAN TransmitInterruptPending; // transmitting, but DPC not yet queued
+ BOOLEAN OverflowRestartXmitDpc; // transmitting, but DPC not yet queued
+ BUFFER_STATUS BufferStatus[MAX_XMIT_BUFS];
+ PNDIS_PACKET Packets[MAX_XMIT_BUFS]; // as passed to MacSend
+ UINT PacketLens[MAX_XMIT_BUFS];
+ PUCHAR XmitStart; // start of card transmit area
+ PUCHAR PageStart; // start of card receive area
+ PUCHAR PageStop; // end of card receive area
+ UCHAR NicXmitStart; // MSB, LSB assumed 0
+ UCHAR NicPageStart; // MSB, LSB assumed 0
+ UCHAR NicPageStop; // MSB, LSB assumed 0
+ UCHAR GaControlBits; // values for xsel and dbsel bits
+ BOOLEAN TransmitTimeOut; // Set to TRUE if a packet was sent
+ // but no transmit interrupt was
+ // received within 2 seconds.
+
+ //
+ // Receive information
+ //
+
+ UCHAR NicNextPacket; // MSB, LSB assumed 0
+ UCHAR Current; // MSB, LSB assumed 0 (last known value)
+ UCHAR XmitStatus; // status of last transmit
+
+ //
+ // These are for the current packet being indicated.
+ //
+
+ UCHAR PacketHeader[4]; // the NIC appended header
+ UCHAR Lookahead[252]; // the first 252 bytes of the packet
+ UINT PacketLen; // the overall length of the packet
+ PUCHAR PacketHeaderLocation;
+
+
+ //
+ // Operational information.
+ //
+
+ UCHAR StationAddress[ETH_LENGTH_OF_ADDRESS]; // filled in at init time
+ UCHAR PermanentAddress[ETH_LENGTH_OF_ADDRESS]; // filled in at init time
+ BOOLEAN BufferOverflow; // does an overflow need to be handled
+
+ //
+ // TRUE if the driver needs to call NdisMEthIndicateReceiveComplete.
+ //
+ BOOLEAN IndicateReceiveDone;
+
+ //
+ // Statistics used by Set/QueryInformation.
+ //
+
+ ULONG FramesXmitGood; // Good Frames Transmitted
+ ULONG FramesRcvGood; // Good Frames Received
+ ULONG FramesXmitBad; // Bad Frames Transmitted
+ ULONG FramesXmitOneCollision; // Frames Transmitted with one collision
+ ULONG FramesXmitManyCollisions; // Frames Transmitted with > 1 collision
+ ULONG FrameAlignmentErrors; // FAE errors counted
+ ULONG CrcErrors; // CRC errors counted
+ ULONG MissedPackets; // missed packet counted
+
+ //
+ // Pointer to the filter database for the MAC.
+ //
+ UCHAR NicMulticastRegs[8]; // contents of card MC registers
+
+ UCHAR NicReceiveConfig; // contents of NIC RCR
+ UCHAR NicInterruptMask; // contents of NIC IMR
+
+
+ //
+ // Look Ahead information.
+ //
+ ULONG MaxLookAhead;
+
+ //
+ // NOTE:
+ // new stuff that i have added.
+ //
+
+ //
+ // InterruptStatus tracks interrupt sources that still need to be
+ // serviced, it is the logical OR of all card interrupts that have been
+ // received and not processed and cleared.
+ // (see also INTERRUPT_TYPE definition above)
+ //
+ UINT InterruptStatus;
+
+ //
+ // Current packet filter in use.
+ //
+ ULONG PacketFilter;
+
+ //
+ // List of multicast addresses in use.
+ //
+ CHAR MulticastAddresses[DEFAULT_MULTICASTLISTMAX][ETH_LENGTH_OF_ADDRESS];
+}
+ ELNKII_ADAPTER,
+ *PELNKII_ADAPTER;
+
+//
+// Macros to extract high and low bytes of a word.
+//
+
+#define MSB(Value) ((UCHAR)(((Value) >> 8) & 0xff))
+#define LSB(Value) ((UCHAR)((Value) & 0xff))
+
+
+
+//
+// What we map into the reserved section of a packet.
+// Cannot be more than 16 bytes (see ASSERT in elnkii.c).
+//
+
+typedef struct _MAC_RESERVED
+{
+ PNDIS_PACKET NextPacket; // used to link in the queues (4 bytes)
+} MAC_RESERVED, * PMAC_RESERVED;
+
+
+//
+// Retrieve the MAC_RESERVED structure from a packet.
+//
+
+#define RESERVED(Packet) ((PMAC_RESERVED)((Packet)->MacReserved))
+
+
+//
+// Procedures which log errors.
+//
+
+typedef enum _ELNKII_PROC_ID
+{
+ openAdapter,
+ cardReset,
+ cardCopyDownPacket,
+ cardCopyDownBuffer,
+ cardCopyUp
+}
+ ELNKII_PROC_ID;
+
+
+#define ELNKII_ERRMSG_CARD_SETUP (ULONG)0x01
+#define ELNKII_ERRMSG_DATA_PORT_READY (ULONG)0x02
+#define ELNKII_ERRMSG_MAX_OPENS (ULONG)0x03
+#define ELNKII_ERRMSG_HANDLE_XMIT_COMPLETE (ULONG)0x04
+
+
+//++
+//
+// XMIT_BUF
+// NextBuf(
+// IN PELNKII_ADAPTER AdaptP,
+// IN XMIT_BUF XmitBuf
+// )
+//
+// Routine Description:
+//
+// NextBuf "increments" a transmit buffer number. The next
+// buffer is returned; the number goes back to 0 when it
+// reaches AdaptP->NumBuffers.
+//
+// Arguments:
+//
+// AdaptP - The adapter block.
+// XmitBuf - The current transmit buffer number.
+//
+// Return Value:
+//
+// The next transmit buffer number.
+//
+//--
+
+#define NextBuf(AdaptP, XmitBuf) \
+ ((XMIT_BUF)(((XmitBuf) + 1) % (AdaptP)->NumBuffers))
+
+
+
+/*++
+Routine Description:
+
+ Determines the type of the interrupt on the card. The order of
+ importance is overflow, then receive, then transmit complete.
+ Counter MSB is handled first since it is simple.
+
+Arguments:
+
+
+Return Value:
+
+ The type of the interrupt
+
+--*/
+
+#define CardGetInterruptType(_pAdapter, _InterruptStatus, _InterruptType) \
+{ \
+ if (_InterruptStatus & ISR_COUNTER) \
+ { \
+ _InterruptType = COUNTER; \
+ } \
+ else if (_InterruptStatus & ISR_OVERFLOW ) \
+ { \
+ SyncCardUpdateCounters(_pAdapter); \
+ _InterruptType = OVERFLOW; \
+ } \
+ else if (_InterruptStatus & (ISR_XMIT | ISR_XMIT_ERR)) \
+ { \
+ _InterruptType = TRANSMIT; \
+ } \
+ else if (_InterruptStatus & ISR_RCV) \
+ { \
+ _InterruptType = RECEIVE; \
+ } \
+ else if (_InterruptStatus & ISR_RCV_ERR) \
+ { \
+ SyncCardUpdateCounters(_pAdapter); \
+ _InterruptType = RECEIVE; \
+ } \
+ else \
+ { \
+ _InterruptType = UNKNOWN; \
+ } \
+}
+
+
+//
+// Prototypes for functions in elnkii.c
+//
+
+VOID ElnkiiHalt(
+ IN NDIS_HANDLE MiniportAdapterContext
+);
+
+
+NDIS_STATUS ElnkiiInitialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE ConfigurationHandle
+);
+
+NDIS_STATUS ElnkiiQueryInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+);
+
+NDIS_STATUS ElnkiiReset(
+ OUT PBOOLEAN pfAddressingReset,
+ IN NDIS_HANDLE MiniportAdapterContext
+);
+
+NDIS_STATUS ElnkiiSetInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+);
+
+VOID ReadInterruptNumber(
+ OUT PNDIS_STATUS pStatus,
+ OUT PCCHAR pInterruptNumber,
+ IN NDIS_HANDLE hConfig,
+ IN NDIS_HANDLE MiniportAdapterHandle
+);
+
+VOID ReadBaseIoAddress(
+ OUT PNDIS_STATUS pStatus,
+ OUT PVOID *ppIoBaseAddress,
+ IN NDIS_HANDLE hConfig,
+ IN NDIS_HANDLE MiniportAdapterHandle
+);
+
+NDIS_STATUS ElnkiiInitialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE ConfigurationHandle
+);
+
+NDIS_STATUS ElnkiiQueryInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+);
+
+NDIS_STATUS ElnkiiSetInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+);
+
+VOID ElnkiiHalt(
+ IN NDIS_HANDLE MiniportAdapterContext
+);
+
+NDIS_STATUS ElnkiiReset(
+ OUT PBOOLEAN pfAddressingReset,
+ IN NDIS_HANDLE MiniportAdapterContext
+);
+
+NDIS_STATUS DispatchSetMulticastAddressList(
+ IN PELNKII_ADAPTER pAdapter
+);
+
+
+//
+// Prototypes for functions in interrup.c
+//
+
+VOID ElnkiiDisableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+);
+
+VOID ElnkiiEnableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+);
+
+VOID ElnkiiHandleInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+);
+
+VOID ElnkiiIsr(
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueDpc,
+ IN PVOID Context
+);
+
+BOOLEAN ElnkiiCheckForHang(
+ IN NDIS_HANDLE MiniportAdapterContext
+);
+
+//
+// Prototypes for functions in send.c
+//
+
+NDIS_STATUS ElnkiiSend(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET Packet,
+ IN UINT Flags
+);
+
+VOID OctogmetusceratorRevisited(
+ IN PELNKII_ADAPTER pAdapter
+);
+
+VOID ElnkiiXmitDpc(
+ IN PELNKII_ADAPTER pAdapter
+);
+
+//
+// Prototypes for functions in rcv.c
+//
+
+NDIS_STATUS ElnkiiTransferData(
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+);
+
+BOOLEAN ElnkiiRcvDpc(
+ IN PELNKII_ADAPTER pAdapter
+);
+
+
+//
+// Prototypes for functions in card.c
+//
+
+BOOLEAN SyncCardSetAllMulticast(
+ IN PVOID SynchronizeContext
+);
+
+BOOLEAN SyncCardSetReceiveConfig(
+ IN PVOID SynchronizeContext
+);
+
+BOOLEAN SyncCardCopyMulticastRegs(
+ IN PVOID SynchronizeContext
+);
+
+PUCHAR CardGetMemBaseAddr(
+ IN PELNKII_ADAPTER pAdapter,
+ OUT PBOOLEAN pfCardPresent,
+ OUT PBOOLEAN pfIoBaseCorrect
+);
+
+VOID CardReadEthernetAddress(
+ IN PELNKII_ADAPTER pAdapter
+);
+
+BOOLEAN SyncCardStop(
+ IN PVOID SynchronizeContext
+);
+
+VOID DelayComplete(
+ IN PVOID SystemSpecific1,
+ IN PVOID TimerExpired,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+);
+
+BOOLEAN CardTest(
+ IN PELNKII_ADAPTER pAdapter
+);
+
+BOOLEAN CardCopyDownBuffer(
+ IN PELNKII_ADAPTER pAdapter,
+ IN PUCHAR SourceBuffer,
+ IN XMIT_BUF XmitBufferNum,
+ IN UINT Offset,
+ IN UINT Length
+);
+
+BOOLEAN CardCopyUp(
+ IN PELNKII_ADAPTER pAdapter,
+ IN PUCHAR Target,
+ IN PUCHAR Source,
+ IN UINT Length
+);
+
+VOID CardGetPacketCrc(
+ IN PUCHAR Buffer,
+ IN UINT Length,
+ OUT UCHAR Crc[4]
+);
+
+BOOLEAN SyncCardStop(
+ IN PVOID SynchronizeContext
+);
+
+BOOLEAN SyncCardUpdateCounters(
+ IN PVOID SynchronizeContext
+);
+
+BOOLEAN SyncCardStop(
+ IN PVOID SynchronizeContext
+);
+
+
+
+BOOLEAN CardSetup(
+ IN PELNKII_ADAPTER pAdapter
+);
+
+
+VOID CardFillMulticastRegs(
+ IN PELNKII_ADAPTER pAdapter
+);
+
+VOID CardStop(
+ IN PELNKII_ADAPTER pAdapter
+);
+
+BOOLEAN CardReset(
+ IN PELNKII_ADAPTER pAdapter
+);
+
+
+BOOLEAN SyncCardGetXmitStatus(
+ IN PVOID SynchronizeContext
+);
+
+BOOLEAN SyncCardGetCurrent(
+ IN PVOID SynchronizeContext
+);
+
+BOOLEAN SyncCardHandleOverflow(
+ IN PVOID SynchronizeContext
+);
+
+VOID CardSetBoundary(
+ IN PELNKII_ADAPTER pAdapter
+);
+
+BOOLEAN CardReset(
+ IN PELNKII_ADAPTER pAdapter
+);
+
+BOOLEAN SyncCardAcknowledgeOverflow(
+ IN PVOID SynchronizeContext
+);
+
+
+VOID CardStartXmit(
+ IN PELNKII_ADAPTER pAdapter
+);
+
+BOOLEAN CardCopyDownPacket(
+ IN PELNKII_ADAPTER pAdapter,
+ IN PNDIS_PACKET Packet,
+ IN XMIT_BUF XmitBufferNum,
+ OUT UINT * Length
+);
+
+
+#if DBG
+VOID ElnkiiDisplayStatus(
+ PELNKII_ADAPTER pAdapter
+);
+
+#endif
+
+
+
+#endif // ELNKIISFT
+
+
+
+
+
+
+
diff --git a/private/ntos/ndis/elnkii.new/interrup.c b/private/ntos/ndis/elnkii.new/interrup.c
new file mode 100644
index 000000000..73d12bb6f
--- /dev/null
+++ b/private/ntos/ndis/elnkii.new/interrup.c
@@ -0,0 +1,395 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ interrup.c
+
+Abstract:
+
+ This is a part of the driver for the National Semiconductor ElnkII
+ Ethernet controller. It contains the interrupt-handling routines.
+ This driver conforms to the NDIS 3.0 interface.
+
+ The overall structure and much of the code is taken from
+ the Lance NDIS driver by Tony Ercolano.
+
+Author:
+
+ Sean Selitrennikoff (seanse) Dec-1991
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+--*/
+
+#include <ndis.h>
+#include "elnkhrd.h"
+#include "elnksft.h"
+
+
+#if DBG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+
+
+#if DBG
+
+#define ELNKII_LOG_SIZE 256
+UCHAR ElnkiiLogSaveBuffer[ELNKII_LOG_SIZE]={0};
+BOOLEAN ElnkiiLogSave = FALSE;
+UINT ElnkiiLogSaveLoc = 0;
+UINT ElnkiiLogSaveLeft = 0;
+
+extern VOID ElnkiiLog(UCHAR c);
+
+#endif
+
+
+VOID ElnkiiEnableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+)
+{
+ PELNKII_ADAPTER pAdapter = (PELNKII_ADAPTER)MiniportAdapterContext;
+
+ IF_LOG(ElnkiiLog('P');)
+
+ CardUnblockInterrupts(pAdapter);
+}
+
+VOID ElnkiiDisableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+)
+{
+ PELNKII_ADAPTER pAdapter = (PELNKII_ADAPTER)MiniportAdapterContext;
+
+ IF_LOG(ElnkiiLog('p');)
+
+ CardBlockInterrupts(pAdapter);
+}
+
+
+
+VOID ElnkiiIsr(
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueDpc,
+ IN PVOID Context
+)
+
+/*++
+
+Routine Description:
+
+ This is the interrupt handler which is registered with the operating
+ system. Only one interrupt is handled at one time, even if several
+ are pending (i.e. transmit complete and receive).
+
+Arguments:
+
+ ServiceContext - pointer to the adapter object
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PELNKII_ADAPTER pAdapter = (PELNKII_ADAPTER)Context;
+
+ IF_LOG( ElnkiiLog('i');)
+
+ IF_VERY_LOUD(DbgPrint("ELNKII: ElnkiiIsr entered\n");)
+
+ //
+ // If we are testing the card then ignore the interrupt.
+ //
+ if (pAdapter->InCardTest)
+ {
+ IF_LOG( ElnkiiLog('I'); )
+
+ *InterruptRecognized = FALSE;
+ *QueueDpc = FALSE;
+
+ IF_VERY_LOUD(DbgPrint("ELNKII: ElnkiiIsr exiting (CardTest)\n");)
+
+ return;
+ }
+
+ //
+ // Force the INT signal from the chip low. When the
+ // interrupt is acknowledged interrupts will be unblocked,
+ // which will cause a rising edge on the interrupt line
+ // if there is another interrupt pending on the card.
+ //
+ CardBlockInterrupts(pAdapter);
+
+ IF_LOG( ElnkiiLog('I');)
+
+ *InterruptRecognized = TRUE;
+ *QueueDpc = TRUE;
+
+ IF_VERY_LOUD(DbgPrint("ELNKII: ElnkiiIsr exiting\n");)
+}
+
+
+
+VOID ElnkiiHandleInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+)
+/*++
+
+Routine Description:
+
+ This is the deffered processing routine for interrupts, it examines the
+ 'InterruptStatus' to determine what deffered processing is necessary
+ and dispatches control to the Rcv and Xmt handlers.
+
+Arguments:
+
+Return Value:
+
+ NONE.
+
+--*/
+{
+ //
+ // Adapter to process.
+ //
+ PELNKII_ADAPTER pAdapter = (PELNKII_ADAPTER)MiniportAdapterContext;
+
+ UCHAR InterruptStatus; // Most recent port value read.
+ INTERRUPT_TYPE InterruptType; // Interrupt type currently being
+ // processed.
+ IF_LOG(ElnkiiLog('d');)
+ IF_VERY_LOUD(DbgPrint("ELNKII: ElnkiiHandleInterrupt entered\n");)
+
+ //
+ // Get the interrupt bits and save them
+ //
+ CardGetInterruptStatus(pAdapter, &InterruptStatus);
+ pAdapter->InterruptStatus |= InterruptStatus;
+
+ if (InterruptStatus != ISR_EMPTY)
+ {
+ //
+ // Acknowledge the interrupts.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_STATUS,
+ InterruptStatus
+ );
+ }
+
+ //
+ // Return the type of the most important interrupt waiting on the card.
+ // Order of importance is COUNTER, OVERFLOW, TRANSMIT, and RECEIVE.
+ //
+ CardGetInterruptType(pAdapter, InterruptStatus, InterruptType);
+
+ while (InterruptType != UNKNOWN)
+ {
+ //
+ // Handle interrupts
+ //
+ switch (InterruptType)
+ {
+ case COUNTER:
+ //
+ // One of the counters' MSB has been set, read in all
+ // the values just to be sure (and then exit below).
+ //
+ IF_VERY_LOUD(DbgPrint("C\n");)
+
+ SyncCardUpdateCounters(pAdapter);
+
+ //
+ // Clear the COUNTER interrupt bit.
+ //
+ pAdapter->InterruptStatus &= ~ISR_COUNTER;
+
+ IF_VERY_LOUD(DbgPrint("c\n");)
+
+ break;
+
+ case OVERFLOW:
+
+ //
+ // Overflow interrupts are handled as part of a receive
+ // interrupt, so set a flag and then pretend to be a
+ // receive, in case there is no receive already being handled.
+ //
+ pAdapter->BufferOverflow = TRUE;
+
+ IF_VERY_LOUD(DbgPrint("O\n");)
+
+ //
+ // Clear the OVERFLOW interrupt bit.
+ //
+ pAdapter->InterruptStatus &= ~ISR_OVERFLOW;
+
+ case RECEIVE:
+
+ IF_LOG( ElnkiiLog('R');)
+ IF_VERY_LOUD(DbgPrint("R\n");)
+
+ //
+ // Allow the receive dpc to handle it.
+ //
+ if (ElnkiiRcvDpc(pAdapter))
+ {
+ //
+ // Clear the receive interrupt bits.
+ //
+ pAdapter->InterruptStatus &= ~(ISR_RCV | ISR_RCV_ERR);
+ }
+
+ IF_LOG(ElnkiiLog('r');)
+ IF_VERY_LOUD(DbgPrint("r\n");)
+
+ if (!(pAdapter->InterruptStatus & (ISR_XMIT | ISR_XMIT_ERR)))
+ break;
+
+ case TRANSMIT:
+
+ IF_LOG( ElnkiiLog('X');)
+ IF_VERY_LOUD(DbgPrint("X\n");)
+
+ ASSERT(!pAdapter->OverflowRestartXmitDpc);
+
+ //
+ // Get the status of the transmit.
+ //
+ SyncCardGetXmitStatus(pAdapter);
+
+ pAdapter->TransmitTimeOut = FALSE;
+
+ //
+ // We are no longer expecting an interrupt.
+ //
+ pAdapter->TransmitInterruptPending = FALSE;
+
+ //
+ // Handle transmit errors.
+ //
+ if (pAdapter->InterruptStatus & ISR_XMIT_ERR)
+ OctogmetusceratorRevisited(pAdapter);
+
+ //
+ // Handle transmit errors.
+ //
+ if (pAdapter->InterruptStatus & ISR_XMIT)
+ ElnkiiXmitDpc(pAdapter);
+
+ //
+ // Clear the TRANSMIT interrupt bits.
+ //
+ pAdapter->InterruptStatus &= ~(ISR_XMIT | ISR_XMIT_ERR);
+
+ IF_VERY_LOUD(DbgPrint("x\n");)
+
+ break;
+
+ default:
+ //
+ // Create a rising edge on the interrupt line.
+ //
+ IF_LOUD(DbgPrint("ELNKII: Unhandled interrupt type: %x\n", InterruptType);)
+
+ break;
+ }
+
+ //
+ // Get any new interrupts.
+ //
+ CardGetInterruptStatus(pAdapter, &InterruptStatus);
+ if (InterruptStatus != ISR_EMPTY)
+ {
+ //
+ // Acknowledge the interrupt.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_STATUS,
+ InterruptStatus
+ );
+ }
+
+ //
+ // Save the interrupt status.
+ //
+ pAdapter->InterruptStatus |= InterruptStatus;
+
+ //
+ // Get the next interrupt to process.
+ //
+ CardGetInterruptType(pAdapter, InterruptStatus, InterruptType);
+ }
+
+ IF_LOG(ElnkiiLog('D');)
+ IF_VERY_LOUD(DbgPrint("ELNKII: ElnkiiHandleInterrupt exiting\n");)
+}
+
+
+BOOLEAN ElnkiiCheckForHang(
+ IN NDIS_HANDLE MiniportAdapterContext
+)
+
+/*+++
+
+ Description:
+ This routine checks the transmit queue every 2 seconds.
+ If a transmit interrupt was not received in the last two seconds
+ and there is a transmit in progress then we complete the transmit.
+
+ Returns:
+ BOOLEAN
+
+ Histroy:
+ 1/2/95 [kyleb] created.
+
+---*/
+
+{
+ PELNKII_ADAPTER pAdapter = (PELNKII_ADAPTER)MiniportAdapterContext;
+
+ if (pAdapter->TransmitTimeOut && (pAdapter->CurBufXmitting != -1))
+ {
+ IF_LOUD(DbgPrint("ELNKII: Card died!, Attempting to restart\n");)
+ pAdapter->TransmitTimeOut = FALSE;
+
+ return(TRUE);
+ }
+ else
+ {
+ if (pAdapter->CurBufXmitting != -1)
+ pAdapter->TransmitTimeOut = TRUE;
+ }
+} //** ElnkiiCheckForHang()
+
+
+UINT ElnkiiCompareMemory(
+ IN PUCHAR String1,
+ IN PUCHAR String2,
+ IN UINT Length
+)
+{
+ UINT i;
+
+ for (i = 0; i < Length; i++)
+ {
+ if (String1[i] != String2[i])
+ return((UINT)-1);
+ }
+
+ return(0);
+}
+
+
+
diff --git a/private/ntos/ndis/elnkii.new/keywords.h b/private/ntos/ndis/elnkii.new/keywords.h
new file mode 100644
index 000000000..b035a04ea
--- /dev/null
+++ b/private/ntos/ndis/elnkii.new/keywords.h
@@ -0,0 +1,56 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ keywords.h
+
+Abstract:
+
+ Contains all Ndis2 and Ndis3 mac-specific keywords.
+
+Author:
+
+ Bob Noradki
+
+Environment:
+
+ This driver is expected to work in DOS, OS2 and NT at the equivalent
+ of kernal mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+
+
+--*/
+#ifndef NDIS2
+#define NDIS2 0
+#endif
+
+#if NDIS2
+
+#define IOBASE NDIS_STRING_CONST("IOADDRESS")
+#define INTERRUPT NDIS_STRING_CONST("INTERRUPT")
+#define MAXMULTICAST NDIS_STRING_CONST("MAXMULTICASTLIST")
+#define NETWORK_ADDRESS NDIS_STRING_CONST("NETADDRESS")
+#define MEMORYMAPPED NDIS_STRING_CONST("MEMORYMAPPED")
+#define TRANSCEIVER NDIS_STRING_CONST("TRANSCEIVER")
+
+#else // NDIS3
+
+#define IOBASE NDIS_STRING_CONST("IoBaseAddress")
+#define INTERRUPT NDIS_STRING_CONST("InterruptNumber")
+#define MAXMULTICAST NDIS_STRING_CONST("MaximumMulticastList")
+#define NETWORK_ADDRESS NDIS_STRING_CONST("NetworkAddress")
+#define MEMORYMAPPED NDIS_STRING_CONST("MemoryMapped")
+#define TRANSCEIVER NDIS_STRING_CONST("Transceiver")
+
+#endif
diff --git a/private/ntos/ndis/elnkii.new/makefile b/private/ntos/ndis/elnkii.new/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/elnkii.new/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/elnkii.new/rcv.c b/private/ntos/ndis/elnkii.new/rcv.c
new file mode 100644
index 000000000..ab092dcfc
--- /dev/null
+++ b/private/ntos/ndis/elnkii.new/rcv.c
@@ -0,0 +1,893 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ rcv.c
+
+Abstract:
+
+
+Author:
+
+ 12/20/94 kyleb Created.
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+--*/
+
+#include <ndis.h>
+#include "elnkhrd.h"
+#include "elnksft.h"
+
+#if DBG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+
+//
+// This is used to pad short packets.
+//
+
+static UCHAR BlankBuffer[60] = " ";
+
+#if DBG
+
+#define ELNKII_LOG_SIZE 256
+extern UCHAR ElnkiiLogSaveBuffer[ELNKII_LOG_SIZE];
+extern BOOLEAN ElnkiiLogSave;
+extern UINT ElnkiiLogSaveLoc;
+extern UINT ElnkiiLogSaveLeft;
+
+extern VOID ElnkiiLog(UCHAR c);
+
+#endif
+
+NDIS_STATUS ElnkiiTransferData(
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+)
+{
+ UINT BytesLeft;
+ UINT BytesNow;
+ UINT BytesWanted;
+ PUCHAR CurCardLoc;
+ PNDIS_BUFFER CurBuffer;
+ PUCHAR BufStart;
+ UINT BufLen;
+ UINT BufOff;
+ UINT Copied;
+ UINT CurOff;
+ PELNKII_ADAPTER pAdapter = (PELNKII_ADAPTER)MiniportReceiveContext;
+
+ //
+ // Add the packet header onto the offset
+ //
+ ByteOffset += ELNKII_HEADER_SIZE;
+
+ //
+ // See how much data there is to transfer.
+ //
+ if (ByteOffset + BytesToTransfer > pAdapter->PacketLen)
+ {
+ if (pAdapter->PacketLen < ByteOffset)
+ {
+ *BytesTransferred = 0;
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ BytesWanted = pAdapter->PacketLen - ByteOffset;
+ }
+ else
+ {
+ BytesWanted = BytesToTransfer;
+ }
+
+ BytesLeft = BytesWanted;
+
+ //
+ // Determine where the copying should start.
+ //
+ CurCardLoc = pAdapter->PacketHeaderLocation + ByteOffset;
+
+ if (CurCardLoc > pAdapter->PageStop)
+ CurCardLoc -= (pAdapter->PageStop - pAdapter->PageStart);
+
+ //
+ // Get the location to copy into.
+ //
+ NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, NULL);
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufStart, &BufLen);
+
+ BufOff = 0;
+
+ //
+ // If we are using programmed I/O and part of the data is in
+ // the lookahead buffer then get it out of there.
+ // It's faster.
+ //
+ if (!pAdapter->MemMapped && (ByteOffset < pAdapter->MaxLookAhead))
+ {
+ UINT BytesLeftLookAhead;
+ PUCHAR CurBufLoc;
+ UINT TotalCopied = 0;
+
+ //
+ // Is the whole packet in the lookahead buffer?
+ //
+ BytesLeftLookAhead = (BytesWanted > pAdapter->MaxLookAhead) ?
+ pAdapter->MaxLookAhead : BytesWanted;
+
+ //
+ // Figure in the offset.
+ //
+ BytesLeftLookAhead -= ByteOffset;
+ CurBufLoc = pAdapter->Lookahead + ByteOffset;
+
+ //
+ // Copy the lookahead data into the supplied buffer(s).
+ //
+ while (BytesLeftLookAhead != 0)
+ {
+ //
+ // See how much data we can read into this buffer.
+ //
+ if (BufLen > BytesLeftLookAhead)
+ BytesNow = BytesLeftLookAhead;
+ else
+ BytesNow = BufLen;
+
+ //
+ // Copy the data from the lookahead buffer into
+ // the supplied buffer.
+ //
+ ELNKII_MOVE_MEM(BufStart, CurBufLoc, BytesNow);
+
+ //
+ // Update the number of bytes left to copy and
+ // the current position in the lookahead buffer.
+ //
+ CurBufLoc += BytesNow;
+ BytesLeftLookAhead -= BytesNow;
+ BytesLeft -= BytesNow;
+
+ //
+ // Update the current card location.
+ // We need to check if this wraps around in the
+ // transmit buffer.
+ //
+ CurCardLoc += BytesNow;
+ if (CurCardLoc >= pAdapter->PageStop)
+ {
+ CurCardLoc = pAdapter->PageStart +
+ (CurCardLoc - pAdapter->PageStop);
+ }
+
+ //
+ // Do we need to move to the next buffer?
+ //
+ BufOff += BytesNow;
+ if (BufOff == BufLen)
+ {
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+
+ if (CurBuffer == (PNDIS_BUFFER)NULL)
+ break;
+
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufStart, &BufLen);
+
+ BufOff = 0;
+ }
+ }
+
+ //
+ // If there are no more buffers then skip the rest.
+ //
+ if (NULL == CurBuffer)
+ goto exit1;
+ }
+
+ //
+ // Loop, filling each buffer in the packet until there
+ // are no more buffers or the data has all been copied.
+ //
+ while (BytesLeft > 0)
+ {
+ //
+ // See how much data to read into this buffer.
+ //
+
+ if ((BufLen - BufOff) > BytesLeft)
+ BytesNow = BytesLeft;
+ else
+ BytesNow = (BufLen - BufOff);
+
+ //
+ // See if the data for this buffer wraps around the end
+ // of the receive buffers (if so filling this buffer
+ // will use two iterations of the loop).
+ //
+ if (CurCardLoc + BytesNow > pAdapter->PageStop)
+ BytesNow = pAdapter->PageStop - CurCardLoc;
+
+ //
+ // Copy up the data.
+ //
+ if (!CardCopyUp(pAdapter, BufStart + BufOff, CurCardLoc, BytesNow))
+ {
+ *BytesTransferred = BytesWanted - BytesLeft;
+
+ NdisWriteErrorLogEntry(
+ pAdapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 1,
+ 0x2
+ );
+
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // Update offsets and counts.
+ //
+ CurCardLoc += BytesNow;
+ BytesLeft -= BytesNow;
+
+ //
+ // Is the transfer done now?
+ //
+ if (BytesLeft == 0)
+ break;
+
+ //
+ // Wrap around the end of the receive buffers?
+ //
+ if (CurCardLoc == pAdapter->PageStop)
+ CurCardLoc = pAdapter->PageStart;
+
+ //
+ // Was the end of this packet buffer reached?
+ //
+ BufOff += BytesNow;
+
+ if (BufOff == BufLen)
+ {
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+
+ if (CurBuffer == (PNDIS_BUFFER)NULL)
+ break;
+
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufStart, &BufLen);
+
+ BufOff = 0;
+ }
+ }
+
+exit1:
+ *BytesTransferred = BytesWanted - BytesLeft;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+INDICATE_STATUS ElnkiiIndicatePacket(
+ IN PELNKII_ADAPTER pAdapter
+)
+{
+ UINT PacketLength;
+ PUCHAR IndicateBuffer;
+ UINT IndicateLength;
+ UCHAR PossibleNextPacket1;
+ UCHAR PossibleNextPacket2;
+
+ //
+ // Check if the next packet byte agress with the length, as
+ // described on p. A-3 of the Etherlink II Technical Reference.
+ // The start of the packet plus the MSB of the length must
+ // be equal to the start of the next packet minus one or two.
+ // Otherwise the header is considered corrupted, and the
+ // card must be reset.
+ //
+ PossibleNextPacket1 =
+ pAdapter->NicNextPacket + pAdapter->PacketHeader[3] + (UCHAR)1;
+
+ if (PossibleNextPacket1 >= pAdapter->NicPageStop)
+ PossibleNextPacket1 -= (pAdapter->NicPageStop - pAdapter->NicPageStart);
+
+ if (PossibleNextPacket1 != pAdapter->PacketHeader[1])
+ {
+ PossibleNextPacket2 = PossibleNextPacket1+(UCHAR)1;
+
+ if (PossibleNextPacket2 == pAdapter->NicPageStop)
+ PossibleNextPacket2 = pAdapter->NicPageStart;
+
+ if (PossibleNextPacket2 != pAdapter->PacketHeader[1])
+ {
+ IF_LOUD(DbgPrint("ELNKII: First CARD_BAD check failed\n");)
+ return(SKIPPED);
+ }
+ }
+
+ if
+ (
+ (pAdapter->PacketHeader[1] < pAdapter->NicPageStart) ||
+ (pAdapter->PacketHeader[1] > pAdapter->NicPageStop)
+ )
+ {
+ IF_LOUD(DbgPrint("ELNKII: Second CARD_BAD check failed\n");)
+ return(SKIPPED);
+ }
+
+ //
+ // Sanity check the length.
+ //
+ PacketLength =
+ pAdapter->PacketHeader[2] + pAdapter->PacketHeader[3] * 256 - 4;
+ if (PacketLength > 1514)
+ {
+ IF_LOUD(DbgPrint("ELNKII: Third CARD_BAD check failed\n");)
+ return(SKIPPED);
+ }
+
+
+#if DBG
+
+ IF_ELNKIIDEBUG( ELNKII_DEBUG_WORKAROUND1 )
+ {
+ //
+ // Now check for the high order 2 bits being set, as described
+ // on page A-2 of the Etherlink II Technical Reference. If either
+ // of the two high order bits is set in the receive status byte
+ // in the packet header, the packet should be skipped (but
+ // the adapter does not need to be reset).
+ //
+ if (pAdapter->PacketHeader[0] & (RSR_DISABLED | RSR_DEFERRING))
+ {
+ IF_LOUD (DbgPrint("H");)
+
+ return(SKIPPED);
+ }
+ }
+#endif
+
+ //
+ // Determine the amount to indicate.
+ //
+ IndicateLength = (PacketLength > pAdapter->MaxLookAhead) ?
+ pAdapter->MaxLookAhead :
+ PacketLength;
+
+ //
+ // Save the packet length and initialize the InidcateBuffer.
+ //
+ pAdapter->PacketLen = PacketLength;
+ IndicateBuffer = NULL;
+
+ //
+ // For programmed I/O we need to copy up the lookahead data
+ // into a buffer.
+ //
+ if (!pAdapter->MemMapped)
+ {
+ if
+ (
+ !CardCopyUp(
+ pAdapter,
+ pAdapter->Lookahead,
+ pAdapter->PacketHeaderLocation,
+ IndicateLength + ELNKII_HEADER_SIZE
+ )
+ )
+ {
+ NdisWriteErrorLogEntry(
+ pAdapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 1,
+ 0x1
+ );
+
+ return(SKIPPED);
+ }
+
+ IndicateBuffer = pAdapter->Lookahead;
+ }
+ else
+ {
+ //
+ // For memory mapped I/O we just create a lookahead buffer
+ // from the shared memory.
+ //
+ NdisCreateLookaheadBufferFromSharedMemory(
+ pAdapter->PacketHeaderLocation,
+ IndicateLength,
+ &IndicateBuffer
+ );
+ }
+
+ //
+ // Indicate the lookahead buffer.
+ //
+ if (IndicateBuffer != NULL)
+ {
+ pAdapter->FramesRcvGood++;
+
+ if (IndicateLength < ELNKII_HEADER_SIZE)
+ {
+ //
+ // Runt packet
+ //
+ NdisMEthIndicateReceive(
+ pAdapter->MiniportAdapterHandle,
+ (NDIS_HANDLE)pAdapter,
+ IndicateBuffer,
+ IndicateLength,
+ NULL,
+ 0,
+ 0,
+ );
+ }
+ else
+ {
+ //
+ // Regular packet.
+ //
+ NdisMEthIndicateReceive(
+ pAdapter->MiniportAdapterHandle,
+ (NDIS_HANDLE)pAdapter,
+ IndicateBuffer,
+ ELNKII_HEADER_SIZE,
+ (PCHAR)(IndicateBuffer + ELNKII_HEADER_SIZE),
+ IndicateLength - ELNKII_HEADER_SIZE,
+ PacketLength - ELNKII_HEADER_SIZE
+ );
+ }
+
+ //
+ // Free up resources.
+ //
+ if (pAdapter->MemMapped)
+ NdisDestroyLookaheadBufferFromSharedMemory(IndicateBuffer);
+
+ //
+ // Done with the receive.
+ //
+ pAdapter->IndicateReceiveDone = TRUE;
+ }
+ else
+ {
+ //
+ // This is very bad!
+ //
+#if DBG
+ DbgPrint("ELNKII: Invalid indication buffer in ElnkiiIndicatePacket!\n");
+#endif
+
+ //
+ // Skip the packet since we could not indicate it.
+ //
+ return(SKIPPED);
+ }
+
+ return(INDICATE_OK);
+}
+
+BOOLEAN
+ElnkiiPacketOK(
+ IN PELNKII_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Reads a packet off the card -- checking if the CRC is good. This is
+ a workaround for a bug where bytes in the data portion of the packet
+ are shifted either left or right by two in some weird 8390 cases.
+
+ This routine is a combination of Ne2000TransferData (to copy up data
+ from the card), CardCalculateCrc and CardCalculatePacketCrc.
+
+Arguments:
+
+ Adapter - pointer to the adapter block.
+
+Return Value:
+
+ TRUE if the packet seems ok, else false.
+
+--*/
+
+{
+
+ //
+ // Length of the packet
+ //
+ UINT PacketLength;
+
+ //
+ // Guess at where the packet is located
+ //
+ PUCHAR PacketLocation;
+
+ //
+ // Header Validation Variables
+ //
+ BOOLEAN FrameAlign;
+ PUCHAR PacketRcvStatus;
+ PUCHAR NextPacket;
+ PUCHAR PacketLenLo;
+ PUCHAR PacketLenHi;
+ PUCHAR ReceiveDestAddrLo;
+ UINT FrameAlignCount;
+ UCHAR OldPacketLenHi;
+ UCHAR TempPacketHeader[6];
+ PUCHAR BeginPacketHeader;
+
+ //
+ // First copy up the four-byte header the card attaches
+ // plus first two bytes of the data packet (which contain
+ // the destination address of the packet). We use the extra
+ // two bytes in case the packet was shifted right 1 or 2 bytes
+ //
+ PacketLocation = Adapter->PageStart +
+ 256*(Adapter->NicNextPacket-Adapter->NicPageStart);
+
+ if (!CardCopyUp(Adapter, TempPacketHeader, PacketLocation, 6)) {
+
+ return FALSE;
+
+ }
+ PacketLocation += 4;
+
+ //
+ // Validate the header
+ //
+ FrameAlignCount = 0;
+ BeginPacketHeader = TempPacketHeader;
+
+ //
+ // Sometimes the Ne2000 will misplace a packet and shift the
+ // entire packet and header by a byte, either up by 1 or 2 bytes.
+ // This loop will look for the packet in the expected place,
+ // and then shift up in an effort to find the packet.
+ //
+ do {
+
+ //
+ // Set where we think the packet is
+ //
+ PacketRcvStatus = BeginPacketHeader;
+ NextPacket = BeginPacketHeader + 1;
+ PacketLenLo = BeginPacketHeader + 2;
+ PacketLenHi = BeginPacketHeader + 3;
+ OldPacketLenHi = *PacketLenHi;
+ ReceiveDestAddrLo = BeginPacketHeader + 4;
+ FrameAlign = FALSE;
+
+ //
+ // Check if the status makes sense as is.
+ //
+ if (*PacketRcvStatus & 0x05E){
+
+ FrameAlign = TRUE;
+
+ } else if ((*PacketRcvStatus & RSR_MULTICAST) // If a multicast packet
+ && (!FrameAlignCount) // and hasn't been aligned
+ && !(*ReceiveDestAddrLo & 1) // and lsb is set on dest addr
+ ){
+
+ FrameAlign = TRUE;
+
+ } else {
+
+ //
+ // Compare high and low address bytes. If the same, the low
+ // byte may have been copied into the high byte.
+ //
+
+ if (*PacketLenLo == *PacketLenHi){
+
+ //
+ // Save the old packetlenhi
+ //
+ OldPacketLenHi = *PacketLenHi;
+
+ //
+ // Compute new packet length
+ //
+ *PacketLenHi = *NextPacket - Adapter->NicNextPacket - 1;
+
+ if (*PacketLenHi < 0) {
+
+ *PacketLenHi = (Adapter->NicPageStop - Adapter->NicNextPacket) +
+ (*NextPacket - Adapter->NicPageStart) - 1;
+
+ }
+
+ if (*PacketLenLo > 0xFC) {
+
+ *PacketLenHi++;
+ }
+
+ }
+
+ PacketLength = (*PacketLenLo) + ((*PacketLenHi)*256) - 4;
+
+ //
+ // Does it make sense?
+ //
+ if ((PacketLength > 1514) || (PacketLength < 60)){
+
+ //
+ // Bad length. Restore the old packetlenhi
+ //
+ *PacketLenHi = OldPacketLenHi;
+
+ FrameAlign = TRUE;
+
+ }
+
+ //
+ // Did we recover the frame?
+ //
+ if (!FrameAlign && ((*NextPacket < Adapter->NicPageStart) ||
+ (*NextPacket > Adapter->NicPageStop))) {
+
+ IF_LOUD( DbgPrint ("Packet address invalid in HeaderValidation\n"); )
+
+ FrameAlign = TRUE;
+
+ }
+
+ }
+
+ //
+ // FrameAlignment - if first time through, shift packetheader right 1 or 2 bytes.
+ // If second time through, shift it back to where it was and let it through.
+ // This compensates for a known bug in the 8390D chip.
+ //
+ if (FrameAlign){
+
+ switch (FrameAlignCount){
+
+ case 0:
+
+ BeginPacketHeader++;
+ PacketLocation++;
+ break;
+
+ case 1:
+
+ BeginPacketHeader--;
+ PacketLocation--;
+ break;
+
+ }
+
+ FrameAlignCount++;
+
+ }
+
+ } while ( (FrameAlignCount < 2) && FrameAlign );
+
+ //
+ // Now grab the packet header information
+ //
+ Adapter->PacketHeader[0] = *BeginPacketHeader;
+ BeginPacketHeader++;
+ Adapter->PacketHeader[1] = *BeginPacketHeader;
+ BeginPacketHeader++;
+ Adapter->PacketHeader[2] = *BeginPacketHeader;
+ BeginPacketHeader++;
+ Adapter->PacketHeader[3] = *BeginPacketHeader;
+
+ //
+ // Packet length is in bytes 3 and 4 of the header.
+ //
+ Adapter->PacketHeaderLocation = PacketLocation;
+ PacketLength = (Adapter->PacketHeader[2]) + ((Adapter->PacketHeader[3])*256) - 4;
+
+ //
+ // Sanity check the packet
+ //
+ if ((PacketLength > 1514) || (PacketLength < 60)){
+
+ if ((Adapter->PacketHeader[1] < Adapter->NicPageStart) ||
+ (Adapter->PacketHeader[1] > Adapter->NicPageStop)) {
+
+ //
+ // Return TRUE here since IndicatePacket will notice the error
+ // and handle it correctly.
+ //
+ return(TRUE);
+
+ }
+
+ return(FALSE);
+
+ }
+
+ return(TRUE);
+}
+
+BOOLEAN ElnkiiRcvDpc(
+ IN PELNKII_ADAPTER pAdapter
+)
+{
+ PMAC_RESERVED Reserved;
+ INDICATE_STATUS IndicateStatus;
+ BOOLEAN Done = TRUE;
+
+ //
+ // Do nothing if a RECEIVE is already being handled.
+ //
+ IF_VERY_LOUD(DbgPrint("ELNKII: ElnkiiRcvDpc entered\n");)
+
+ //
+ // By default don't indicate the receive.
+ //
+ pAdapter->IndicateReceiveDone = FALSE;
+
+ //
+ // Handle overflow.
+ //
+ if (pAdapter->BufferOverflow)
+ SyncCardHandleOverflow(pAdapter);
+
+ //
+ // At this point, receive interrupts are disabled.
+ //
+ SyncCardGetCurrent(pAdapter);
+
+ for (; ; )
+ {
+ if (pAdapter->InterruptStatus & ISR_RCV_ERR)
+ {
+ IF_LOUD(DbgPrint("RE\n");)
+
+ //
+ // Skip the packet.
+ //
+ SyncCardGetCurrent(pAdapter);
+ pAdapter->NicNextPacket = pAdapter->Current;
+
+ CardSetBoundary(pAdapter);
+
+ break;
+ }
+
+ if (pAdapter->Current == pAdapter->NicNextPacket)
+ {
+ //
+ // Make sure there are no more packets.
+ //
+ SyncCardGetCurrent(pAdapter);
+ if (pAdapter->Current == pAdapter->NicNextPacket)
+ break;
+ }
+
+ //
+ // A packet was found on the card, indicate it.
+ //
+ pAdapter->ReceivePacketCount++;
+
+ //
+ // Verify that the packet is not corrupt.
+ //
+ if (ElnkiiPacketOK(pAdapter))
+ {
+ //
+ // Indicate the packet to the wrapper.
+ //
+ IndicateStatus = ElnkiiIndicatePacket(pAdapter);
+ }
+ else
+ {
+ //
+ // Packet is corrupt, skip it.
+ //
+ IF_LOUD(DbgPrint("ELNKII: Packet did not pass OK check\n");)
+
+ IndicateStatus = SKIPPED;
+ }
+
+ //
+ // (IndicateStatus == SKIPPED) is OK, just move to next packet.
+ //
+ if (SKIPPED == IndicateStatus)
+ {
+ SyncCardGetCurrent(pAdapter);
+ pAdapter->NicNextPacket = pAdapter->Current;
+ }
+ else
+ {
+ //
+ // Free the space used by packet on card.
+ //
+ pAdapter->NicNextPacket = pAdapter->PacketHeader[1];
+ }
+
+ //
+ // This will set BOUNDARY to one behind NicNextPacket.
+ //
+ CardSetBoundary(pAdapter);
+
+ if (pAdapter->ReceivePacketCount > 10)
+ {
+ //
+ // Give transmit interrupts a chance
+ //
+ Done = FALSE;
+ pAdapter->ReceivePacketCount = 0;
+ break;
+ }
+ }
+
+ //
+ // See if a buffer overflow occured previously.
+ //
+ if (pAdapter->BufferOverflow)
+ {
+ //
+ // ... and set a flag to restart the card after receiving
+ // a packet.
+ //
+ pAdapter->BufferOverflow = FALSE;
+
+ SyncCardAcknowledgeOverflow(pAdapter);
+
+ //
+ // Undo loopback mode.
+ //
+ CardStart(pAdapter);
+
+ IF_LOG(ElnkiiLog('f');)
+
+ //
+ // Check if transmission needs to be queued or not.
+ //
+ if
+ (
+ pAdapter->OverflowRestartXmitDpc &&
+ (pAdapter->CurBufXmitting != -1)
+ )
+ {
+ IF_LOUD(DbgPrint("ELNKII: Queueing xmit in RcvDpc\n");)
+
+ pAdapter->OverflowRestartXmitDpc = FALSE;
+ pAdapter->TransmitInterruptPending = TRUE;
+ pAdapter->TransmitTimeOut = FALSE;
+
+ CardStartXmit(pAdapter);
+ }
+ }
+
+ //
+ // Finally, indicate ReceiveComplete to all
+ // protocols which received packets.
+ //
+ if (pAdapter->IndicateReceiveDone)
+ {
+ NdisMEthIndicateReceiveComplete(pAdapter->MiniportAdapterHandle);
+
+ pAdapter->IndicateReceiveDone = FALSE;
+ }
+
+ IF_VERY_LOUD(DbgPrint("ELNKII: ElnkiiRcvDpc exiting\n");)
+
+ return(Done);
+}
+
+
+
diff --git a/private/ntos/ndis/elnkii.new/send.c b/private/ntos/ndis/elnkii.new/send.c
new file mode 100644
index 000000000..1eaa4e283
--- /dev/null
+++ b/private/ntos/ndis/elnkii.new/send.c
@@ -0,0 +1,455 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ send.c
+
+Abstract:
+
+
+Author:
+
+ 12/20/94 kyleb Created.
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+--*/
+
+#include <ndis.h>
+#include "elnkhrd.h"
+#include "elnksft.h"
+
+#if DBG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+
+//
+// This is used to pad short packets.
+//
+
+static UCHAR BlankBuffer[60] = " ";
+
+#if DBG
+
+#define ELNKII_LOG_SIZE 256
+extern UCHAR ElnkiiLogSaveBuffer[ELNKII_LOG_SIZE];
+extern BOOLEAN ElnkiiLogSave;
+extern UINT ElnkiiLogSaveLoc;
+extern UINT ElnkiiLogSaveLeft;
+
+extern VOID ElnkiiLog(UCHAR c);
+
+#endif
+
+
+
+VOID ElnkiiDoNextSend(
+ IN PELNKII_ADAPTER pAdapter
+)
+
+/*++
+
+Routine Description:
+
+ Copies packets from the transmit queue to the board and starts
+ transmission as long as there is data waiting. Must be called
+ with Lock held.
+
+Arguments:
+
+ pAdapter - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_PACKET Packet; // Packet to process.
+ XMIT_BUF TmpBuf; // Current destination transmit buffer.
+
+ IF_LOG(ElnkiiLog('s');)
+
+ //
+ // Check if we have enough resources and a packet to process.
+ //
+ while
+ (
+ (pAdapter->XmitQueue != NULL) &&
+ (EMPTY == pAdapter->BufferStatus[pAdapter->NextBufToFill])
+ )
+ {
+ //
+ // Take a packet off of the transmit queue.
+ //
+ IF_VERY_LOUD(DbgPrint("ELNKII: Removing 0x%x, New Head is 0x%x\n", pAdapter->XmitQueue, RESERVED(pAdapter->XmitQueue)->NextPacket);)
+
+ //
+ // Set starting location
+ //
+ TmpBuf = pAdapter->NextBufToFill;
+
+ //
+ // Remove the packet from the queue.
+ //
+ Packet = pAdapter->XmitQueue;
+ pAdapter->XmitQueue = RESERVED(Packet)->NextPacket;
+ if (Packet == pAdapter->XmitQTail)
+ pAdapter->XmitQTail = NULL;
+
+ //
+ // Store the packet in the packet list.
+ //
+ pAdapter->Packets[TmpBuf] = Packet;
+
+ //
+ // Update the next free buffer.
+ //
+ pAdapter->NextBufToFill = NextBuf(pAdapter, TmpBuf);
+
+ //
+ // Copy down the data.
+ //
+ CardCopyDownPacket(
+ pAdapter,
+ Packet,
+ TmpBuf,
+ &pAdapter->PacketLens[TmpBuf]
+ );
+
+ //
+ // Pad short packets with blanks.
+ //
+ if (pAdapter->PacketLens[TmpBuf] < 60)
+ {
+ CardCopyDownBuffer(
+ pAdapter,
+ BlankBuffer,
+ TmpBuf,
+ pAdapter->PacketLens[TmpBuf],
+ 60 - pAdapter->PacketLens[TmpBuf]
+ );
+ }
+
+ //
+ // Set the buffer status.
+ //
+ pAdapter->BufferStatus[TmpBuf] = FULL;
+
+ //
+ // See whether to start the transmission.
+ //
+ if (pAdapter->CurBufXmitting != -1)
+ continue;
+
+ if (pAdapter->NextBufToXmit != TmpBuf)
+ continue;
+
+ //
+ // Start transmission.
+ //
+ pAdapter->CurBufXmitting = pAdapter->NextBufToXmit;
+
+ //
+ // If we are handling an overflow, then we need to let
+ // the overflow handler send this packet....
+ //
+ if (pAdapter->BufferOverflow)
+ {
+ pAdapter->OverflowRestartXmitDpc = TRUE;
+
+ IF_LOUD(DbgPrint("O\n");)
+ }
+ else
+ {
+ //
+ // This is used to check if stopping the chip prevented
+ // a transmit complete interrupt from coming through
+ // (it is cleared in the ISR if a transmit DPC is queued).
+ //
+ pAdapter->TransmitInterruptPending = TRUE;
+
+ CardStartXmit(pAdapter);
+ }
+ }
+}
+
+
+
+VOID OctogmetusceratorRevisited(
+ IN PELNKII_ADAPTER pAdapter
+)
+
+/*++
+
+Routine Description:
+
+ Recovers the card from a transmit error.
+
+Arguments:
+
+ ppAdapter - pointer to the pAdapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IF_LOUD(DbgPrint("ELNKII: Octogmetuscerator called!");)
+
+ //
+ // Ack the interrupt, if needed.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_STATUS,
+ ISR_XMIT_ERR
+ );
+
+ //
+ // Stop the card.
+ //
+ SyncCardStop(pAdapter);
+
+ //
+ // Wait up to 1.6 msfor any receives to finish.
+ //
+ NdisStallExecution(2000);
+
+ //
+ // Place the card in loopback mode.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_XMIT_CONFIG,
+ TCR_LOOPBACK
+ );
+
+ //
+ // Start the card in loopback mode.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_COMMAND,
+ CR_START | CR_NO_DMA
+ );
+
+ //
+ // Get out of loopback mode and start the card.
+ //
+ CardStart(pAdapter);
+
+ //
+ // If there was a packet waiting to get sent, send it.
+ //
+ if (pAdapter->CurBufXmitting != -1)
+ {
+ pAdapter->TransmitInterruptPending = TRUE;
+ CardStartXmit(pAdapter);
+ }
+}
+
+
+NDIS_STATUS ElnkiiSend(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET Packet,
+ IN UINT Flags
+)
+
+/*++
+
+Routine Description:
+
+ The ElnkiiSend request instructs a driver to transmit a
+ packet through the adapter onto the medium.
+
+Arguments:
+
+ MiniportAdapterContext - Context registered with the wrapper, really
+ a pointer to the adapter block.
+
+ Packet - A pointer to a descriptor for the packet that
+ is to be transmitted.
+
+ Flags - Optional send flags.
+
+Notes:
+
+--*/
+
+{
+ PELNKII_ADAPTER pAdapter = (PELNKII_ADAPTER)MiniportAdapterContext;
+
+ IF_LOG( ElnkiiLog('D');)
+
+ //
+ // Put Packet on queue to hit the pipe.
+ //
+ IF_VERY_LOUD( DbgPrint("Putting 0x%x on, after 0x%x\n", Packet, pAdapter->XmitQTail); )
+
+ if (pAdapter->XmitQueue == NULL)
+ pAdapter->XmitQueue = Packet;
+ else
+ RESERVED(pAdapter->XmitQTail)->NextPacket = Packet;
+
+ RESERVED(Packet)->NextPacket = NULL;
+ pAdapter->XmitQTail = Packet;
+
+ //
+ // Process the next send.
+ //
+ ElnkiiDoNextSend(pAdapter);
+
+ return(NDIS_STATUS_PENDING);
+}
+
+
+VOID ElnkiiXmitDpc(
+ IN PELNKII_ADAPTER pAdapter
+)
+
+/*++
+
+Routine Description:
+
+ This is the real interrupt handler for a transmit complete interrupt.
+ ElnkiiInterrupt queues a call to it. It calls ElnkiiHandleXmitComplete.
+
+ NOTE : Called with the spinlock held!! and returns with it released!!!
+
+Arguments:
+
+ pAdapter - A pointer to the adapter block.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ XMIT_BUF TmpBuf; // Buffer to transmit.
+ NDIS_STATUS Status; // Completion status.
+ PNDIS_PACKET Packet; // Packet that was transmitted.
+ UINT c; // Counter variable.
+
+ IF_VERY_LOUD(DbgPrint("ELNKII: ElnkiiXmitDpc entered\n");)
+ IF_LOG(ElnkiiLog('C');)
+
+ pAdapter->TransmitTimeOut = FALSE;
+
+ //
+ // Are we actually transmitting a packet?
+ //
+ if (pAdapter->CurBufXmitting == -1)
+ {
+ IF_LOUD(DbgPrint("ELNKII: ElnkiiXmitDpc called with nothing to transmit!\n");)
+
+ NdisWriteErrorLogEntry(
+ pAdapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 1,
+ ELNKII_ERRMSG_HANDLE_XMIT_COMPLETE
+ );
+
+ return;
+ }
+
+ //
+ // Get the status of the transmit.
+ //
+ SyncCardGetXmitStatus(pAdapter);
+
+ //
+ // Statistics
+ //
+ if (pAdapter->XmitStatus & TSR_XMIT_OK)
+ {
+ pAdapter->FramesXmitGood++;
+
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ else
+ {
+ pAdapter->FramesXmitBad++;
+
+ Status = NDIS_STATUS_FAILURE;
+ }
+
+ //
+ // Ack the send.
+ //
+ NdisMSendComplete(
+ pAdapter->MiniportAdapterHandle,
+ pAdapter->Packets[pAdapter->CurBufXmitting],
+ Status
+ );
+
+ //
+ // Mark the current transmit as done.
+ //
+ pAdapter->Packets[pAdapter->CurBufXmitting] = (PNDIS_PACKET)NULL;
+ pAdapter->BufferStatus[pAdapter->CurBufXmitting] = EMPTY;
+ TmpBuf = NextBuf(pAdapter, pAdapter->CurBufXmitting);
+ pAdapter->NextBufToXmit = TmpBuf;
+
+ //
+ // See what to do next.
+ //
+ switch (pAdapter->BufferStatus[TmpBuf])
+ {
+ case FULL:
+ //
+ // The next packet is ready to go -- only happens with
+ // more than one transmit buffer.
+ //
+ IF_VERY_LOUD(DbgPrint("ELNKII: Next packet ready to go\n");)
+
+ //
+ // Start the transmission and check for more.
+ //
+ pAdapter->CurBufXmitting = TmpBuf;
+
+ IF_LOG(ElnkiiLog('2');)
+
+ //
+ // This is used to check if stopping the chip prevented
+ // a transmit complete interrupt from coming through
+ // (it is cleared in the ISR if a transmit DPC is queued).
+ //
+ pAdapter->TransmitInterruptPending = TRUE;
+
+ IF_LOG(ElnkiiLog('6');)
+
+ CardStartXmit(pAdapter);
+
+ break;
+
+ case EMPTY:
+ //
+ // No packet is read to transmit.
+ //
+ IF_VERY_LOUD(DbgPrint("ELNKII: Next packet empty\n");)
+
+ pAdapter->CurBufXmitting = (XMIT_BUF)-1;
+
+ break;
+ }
+
+ //
+ // Start next send.
+ //
+ ElnkiiDoNextSend(pAdapter);
+
+ IF_VERY_LOUD(DbgPrint("ELNKII: ElnkiiXmitDpc exiting\n");)
+}
+
diff --git a/private/ntos/ndis/elnkii.new/sources b/private/ntos/ndis/elnkii.new/sources
new file mode 100644
index 000000000..d0b9d3218
--- /dev/null
+++ b/private/ntos/ndis/elnkii.new/sources
@@ -0,0 +1,49 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=elnkii
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER
+LINKER_FLAGS=$(LINKER_FLAGS) /ALIGN:16
+
+INCLUDES=..\..\inc
+
+SOURCES=elnkii.c \
+ interrup.c \
+ card.c \
+ send.c \
+ rcv.c \
+ elnkii.rc
+
+RELATIVE_DEPTH=..\..
+
+MSC_WARNING_LEVEL=/W3 /WX
+
diff --git a/private/ntos/ndis/elnkii/card.c b/private/ntos/ndis/elnkii/card.c
new file mode 100644
index 000000000..093e8fb95
--- /dev/null
+++ b/private/ntos/ndis/elnkii/card.c
@@ -0,0 +1,2780 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ card.c
+
+Abstract:
+
+ Card-specific functions for the NDIS 3.0 Etherlink II driver.
+
+Author:
+
+ Adam Barr (adamba) 30-Jul-1990
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ Adam Barr (adamba) 28-Aug-1990
+ - moved the SyncXXX() functions to sync.c
+
+
+--*/
+
+#include <ndis.h>
+#include <efilter.h>
+#include "elnkhrd.h"
+#include "elnksft.h"
+
+
+//
+// The amount of data to transfer in one programmed I/O burst
+// (should be 8 or 16).
+//
+
+#define DMA_BURST_SIZE 16
+
+#if DBG
+UCHAR PrevBurstSize = 0;
+UCHAR PrevPrevBurstSize = 0;
+#endif
+
+
+//
+// Array to hold multicast address list.
+//
+
+CHAR Addresses[DEFAULT_MULTICASTLISTMAX][ETH_LENGTH_OF_ADDRESS] = {0};
+
+
+
+#pragma NDIS_INIT_FUNCTION(CardGetMemBaseAddr)
+
+PUCHAR
+CardGetMemBaseAddr(
+ IN PELNKII_ADAPTER AdaptP,
+ OUT PBOOLEAN CardPresent,
+ OUT PBOOLEAN IoBaseCorrect
+ )
+
+/*++
+
+Routine Description:
+
+ Checks that the I/O base address is correct and returns
+ the memory base address. For cards that are not set up
+ for memory mapped mode, it will only check the I/O base
+ address, and return NULL if it is not correct.
+
+Arguments:
+
+ AdaptP - pointer to the adapter block.
+
+ CardPresent - Returns FALSE if the card does not appear
+ to be present in the machine.
+
+ IoBaseCorrect - Returns TRUE if the jumper matches the
+ configured I/O base address.
+
+Return Value:
+
+ The memory base address for memory mapped systems.
+
+--*/
+
+{
+ static PVOID IoBases[] = { (PVOID)0x2e0, (PVOID)0x2a0,
+ (PVOID)0x280, (PVOID)0x250,
+ (PVOID)0x350, (PVOID)0x330,
+ (PVOID)0x310, (PVOID)0x300 };
+ static PVOID MemBases[] = { (PVOID)0xc8000, (PVOID)0xcc000,
+ (PVOID)0xd8000, (PVOID)0xdc000 };
+ UCHAR BaseConfig, Tmp, MemConfig;
+
+
+ //
+ // Read in the Base Configuration Register.
+ //
+
+ NdisRawReadPortUchar(AdaptP->MappedGaBaseAddr+GA_IO_BASE, &Tmp);
+
+ //
+ // Make sure that only one bit in Tmp is on.
+ //
+
+ if ((Tmp != 0) && ((Tmp & (Tmp-1)) == 0)) {
+
+ *CardPresent = TRUE;
+
+ } else {
+
+ *CardPresent = FALSE;
+ return NULL;
+
+ }
+
+
+ //
+ // Make sure the correct bit is on for AdaptP->IoBaseAddr.
+ //
+
+ BaseConfig = 0;
+
+ while (!(Tmp & 1)) {
+
+ Tmp >>= 1;
+
+ ++BaseConfig;
+
+ if (BaseConfig == 8) {
+
+ return NULL;
+
+ }
+
+ }
+
+ if (IoBases[BaseConfig] != AdaptP->IoBaseAddr) {
+
+ //
+ // Probably the jumper is wrong.
+ //
+
+ *IoBaseCorrect = FALSE;
+ return NULL;
+
+ } else {
+
+ *IoBaseCorrect = TRUE;
+
+ }
+
+
+ //
+ // For non-memory-mapped cards, there is nothing else to check.
+ //
+
+ if (!AdaptP->MemMapped) {
+
+ return NULL;
+
+ }
+
+
+ //
+ // Now read in the PROM configuration register.
+ //
+
+ NdisRawReadPortUchar(AdaptP->MappedGaBaseAddr+GA_MEM_BASE, &Tmp);
+
+
+ //
+ // See which bit is on, minus 4.
+ //
+
+ MemConfig = 0;
+
+ while (!(Tmp & 0x10)) {
+
+ Tmp >>= 1;
+
+ ++MemConfig;
+
+ if (MemConfig == 4) {
+
+ return NULL;
+
+ }
+
+ }
+
+
+ //
+ // Based on the bit, look up MemBaseAddr in the table.
+ //
+
+ AdaptP->MemMapped = TRUE;
+
+ return MemBases[MemConfig];
+}
+
+
+#pragma NDIS_INIT_FUNCTION(CardReadEthernetAddress)
+
+VOID
+CardReadEthernetAddress(
+ IN PELNKII_ADAPTER AdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ Reads in the Ethernet address from the Etherlink II PROM.
+
+Arguments:
+
+ AdaptP - pointer to the adapter block.
+
+Return Value:
+
+ The address is stored in AdaptP->PermanentAddress, and StationAddress if it
+ is currently zero.
+
+--*/
+
+{
+ UINT i;
+
+ //
+ // Window the PROM into the NIC ports.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_CONTROL, CTRL_PROM_SEL | CTRL_BNC);
+
+
+ //
+ // Read in the station address.
+ //
+
+ for (i=0; i<ETH_LENGTH_OF_ADDRESS; i++) {
+
+ NdisRawReadPortUchar(AdaptP->MappedIoBaseAddr+i, &AdaptP->PermanentAddress[i]);
+
+ }
+
+ IF_LOUD( DbgPrint(" [ %x-%x-%x-%x-%x-%x ]\n",
+ AdaptP->PermanentAddress[0],
+ AdaptP->PermanentAddress[1],
+ AdaptP->PermanentAddress[2],
+ AdaptP->PermanentAddress[3],
+ AdaptP->PermanentAddress[4],
+ AdaptP->PermanentAddress[5]);)
+
+ //
+ // Window the NIC registers into the NIC ports.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_CONTROL, CTRL_GA_SEL | CTRL_BNC);
+
+ if ((AdaptP->StationAddress[0] == 0x00) &&
+ (AdaptP->StationAddress[1] == 0x00) &&
+ (AdaptP->StationAddress[2] == 0x00) &&
+ (AdaptP->StationAddress[3] == 0x00) &&
+ (AdaptP->StationAddress[4] == 0x00) &&
+ (AdaptP->StationAddress[5] == 0x00)) {
+
+ AdaptP->StationAddress[0] = AdaptP->PermanentAddress[0];
+ AdaptP->StationAddress[1] = AdaptP->PermanentAddress[1];
+ AdaptP->StationAddress[2] = AdaptP->PermanentAddress[2];
+ AdaptP->StationAddress[3] = AdaptP->PermanentAddress[3];
+ AdaptP->StationAddress[4] = AdaptP->PermanentAddress[4];
+ AdaptP->StationAddress[5] = AdaptP->PermanentAddress[5];
+
+ }
+
+}
+
+
+BOOLEAN
+CardSetup(
+ IN PELNKII_ADAPTER AdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ Sets up the card, using the sequence given in the Etherlink II
+ technical reference.
+
+Arguments:
+
+ AdaptP - pointer to the adapter block, which must be initialized.
+
+Return Value:
+
+ TRUE if successful.
+
+--*/
+
+{
+ UINT i;
+ UINT Filter;
+ UCHAR IntConfig;
+ UCHAR Tmp;
+
+
+ //
+ // First set up the Gate Array.
+ //
+
+ //
+ // Toggle the reset bit.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_CONTROL, CTRL_RESET | CTRL_BNC);
+ NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_CONTROL, 0x00);
+ NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_CONTROL, CTRL_BNC);
+
+
+ //
+ // Set up the bits in the Control Register that don't change.
+ //
+
+ AdaptP->GaControlBits = AdaptP->ExternalTransceiver ? CTRL_DIX : CTRL_BNC;
+
+ if (DMA_BURST_SIZE == 16) {
+
+ AdaptP->GaControlBits |= CTRL_DB_SEL;
+
+ }
+
+ NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_CONTROL, AdaptP->GaControlBits);
+
+
+
+
+ //
+ // Set Page Start and Page Stop to match the NIC registers.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_PAGE_START, AdaptP->NicPageStart);
+ NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_PAGE_STOP, AdaptP->NicPageStop);
+
+
+
+
+
+ //
+ // Select which interrupt to use.
+ //
+
+ IntConfig = 0x04; // set bit in position 2
+ IntConfig <<= AdaptP->InterruptNumber; // move it to 4 through 7
+ NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_INT_DMA_CONFIG, IntConfig);
+
+
+
+
+ //
+ // Choose between 8- and 16-byte programmed I/O bursts.
+ //
+
+ if (DMA_BURST_SIZE == 8) {
+
+ NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_DRQ_TIMER, DQTR_8_BYTE);
+
+ } else {
+
+ NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_DRQ_TIMER, DQTR_16_BYTE);
+
+ }
+
+
+
+
+ //
+ // Initialize these to a correct value for an 8K card.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_DMA_ADDR_MSB, 0x20);
+ NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_DMA_ADDR_LSB, 0x00);
+
+
+
+
+ //
+ // Set up the Configuration register.
+ //
+
+ if (AdaptP->MemMapped) {
+
+ NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_CONFIG,
+ GACFR_TC_MASK | GACFR_RAM_SEL | GACFR_MEM_BANK1);
+
+ } else {
+
+ NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_CONFIG, GACFR_TC_MASK);
+
+ }
+
+
+
+ //
+ // Now set up NIC registers.
+ //
+
+ //
+ // Write to and read from CR to make sure it is there.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND, CR_STOP | CR_NO_DMA | CR_PAGE0);
+ NdisRawReadPortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND, &Tmp);
+
+ if (Tmp != (CR_STOP | CR_NO_DMA | CR_PAGE0)) {
+
+ return FALSE;
+
+ }
+
+
+
+
+
+ //
+ // Set up the registers in the correct sequence.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_DATA_CONFIG,
+ DCR_BYTE_WIDE | DCR_NORMAL | DCR_FIFO_8_BYTE);
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_RMT_COUNT_MSB, 0);
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_RMT_COUNT_LSB, 0);
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_RCV_CONFIG, AdaptP->NicReceiveConfig);
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_CONFIG, TCR_LOOPBACK);
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_BOUNDARY, AdaptP->NicPageStart);
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_PAGE_START, AdaptP->NicPageStart);
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_PAGE_STOP, AdaptP->NicPageStop);
+
+ AdaptP->Current = AdaptP->NicPageStart + (UCHAR)1;
+ AdaptP->NicNextPacket = AdaptP->NicPageStart + (UCHAR)1;
+ AdaptP->BufferOverflow = FALSE;
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_STATUS, 0xff); // clear all
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_MASK, AdaptP->NicInterruptMask);
+
+
+ //
+ // Move to page 1 to write the station address and
+ // multicast registers.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
+ CR_STOP | CR_NO_DMA | CR_PAGE1);
+
+ for (i=0; i<ETH_LENGTH_OF_ADDRESS; i++) {
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+(NIC_PHYS_ADDR+i),
+ AdaptP->StationAddress[i]);
+
+ }
+
+ Filter = ETH_QUERY_FILTER_CLASSES(AdaptP->FilterDB);
+
+ for (i=0; i<8; i++) {
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+(NIC_MC_ADDR+i),
+ (UCHAR)((Filter & NDIS_PACKET_TYPE_ALL_MULTICAST)
+ ? 0xff : AdaptP->NicMulticastRegs[i]));
+
+ }
+
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_CURRENT, AdaptP->Current);
+
+
+ //
+ // move back to page 0 and start the card...
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
+ CR_STOP | CR_NO_DMA | CR_PAGE0);
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE0);
+
+
+ //
+ // ... but it is still in loopback mode.
+ //
+
+ return TRUE;
+}
+
+VOID
+CardStop(
+ IN PELNKII_ADAPTER AdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ Stops the card.
+
+Arguments:
+
+ AdaptP - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UINT i;
+ UCHAR Tmp;
+
+ //
+ // Turn on the STOP bit in the Command register.
+ //
+
+ NdisSynchronizeWithInterrupt(
+ &(AdaptP)->NdisInterrupt,
+ (PVOID)SyncCardStop,
+ (PVOID)AdaptP
+ );
+
+
+ //
+ // Clear the Remote Byte Count register so that ISR_RESET
+ // will come on.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_RMT_COUNT_MSB, 0);
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_RMT_COUNT_LSB, 0);
+
+
+ //
+ // Wait for ISR_RESET, but only for 1.6 milliseconds (as
+ // described in the March 1991 8390 addendum), since that
+ // is the maximum time for a software reset to occur.
+ //
+ //
+
+ for (i=0; i<4; i++) {
+
+ NdisRawReadPortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_STATUS, &Tmp);
+ if (Tmp & ISR_RESET) {
+
+ break;
+
+ }
+
+
+ NdisStallExecution(500);
+
+ }
+
+
+
+ if (i == 4) {
+
+ IF_LOUD( DbgPrint("RESET\n");)
+ IF_LOG( ElnkiiLog('R');)
+
+ }
+
+
+ //
+ // Put the card in loopback mode, then start it.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_CONFIG, TCR_LOOPBACK);
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND, CR_START | CR_NO_DMA);
+
+ //
+ // At this point the card is still in loopback mode.
+ //
+
+}
+
+VOID DelayComplete(
+ IN PVOID SystemSpecific1,
+ IN PVOID TimerExpired,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+{
+ UNREFERENCED_PARAMETER(SystemSpecific1);
+ UNREFERENCED_PARAMETER(SystemSpecific2);
+ UNREFERENCED_PARAMETER(SystemSpecific3);
+
+ *((BOOLEAN *)TimerExpired)=TRUE;
+}
+
+
+#pragma NDIS_INIT_FUNCTION(CardTest)
+
+BOOLEAN
+CardTest(
+ IN PELNKII_ADAPTER AdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ Tests the card. Follows the tests described in section 12 of
+ the 8390 Data Sheet.
+
+Arguments:
+
+ AdaptP - pointer to the adapter block, which must be initialized
+ and set up.
+
+Return Value:
+
+ TRUE if everything is OK.
+
+--*/
+
+{
+#define TEST_LEN 60
+#define MAGIC_NUM 0x92
+
+ UINT FirstTest, SecondTest, i;
+ UCHAR TSRResult, RSRResult;
+ UCHAR CrcBuf[4];
+ BOOLEAN FinalResult = TRUE;
+ UCHAR TestSrcBuf[256], TestDestBuf[256];
+ PUCHAR CurTestLoc;
+ UCHAR Tmp;
+
+ static NDIS_TIMER Timer = {0};
+ BOOLEAN TimerExpired=FALSE;
+ BOOLEAN dummy; //for return from NdisCancelTimer
+
+ //
+ // These arrays are indexed by FirstTest.
+ //
+
+ static UCHAR TCRValues[3] = { TCR_NIC_LBK, TCR_SNI_LBK, TCR_COAX_LBK };
+ static UCHAR TSRCDHWanted[3] = { TSR_NO_CDH, TSR_NO_CDH, 0x00 };
+ static UCHAR TSRCRSWanted[3] = { TSR_NO_CARRIER, 0x00, 0x00 };
+ static UCHAR FIFOWanted[4] = { LSB(TEST_LEN+4), MSB(TEST_LEN+4),
+ MSB(TEST_LEN+4), MAGIC_NUM };
+
+
+ //
+ // These arrays are indexed by SecondTest.
+ //
+
+ static BOOLEAN GoodCrc[3] = { TRUE, FALSE, FALSE };
+ static BOOLEAN GoodAddress[3] = { TRUE, TRUE, FALSE };
+ static UCHAR RSRWanted[3] = { RSR_PACKET_OK, RSR_CRC_ERROR, RSR_PACKET_OK };
+
+ static UCHAR TestPacket[TEST_LEN] = {0}; // a dummy packet.
+ static UCHAR NullAddress[ETH_LENGTH_OF_ADDRESS] = { 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00 };
+
+
+ //
+ // First construct TestPacket.
+ //
+
+ ELNKII_MOVE_MEM(TestPacket, AdaptP->StationAddress, ETH_LENGTH_OF_ADDRESS);
+ ELNKII_MOVE_MEM(TestPacket+ETH_LENGTH_OF_ADDRESS, AdaptP->StationAddress, ETH_LENGTH_OF_ADDRESS);
+ TestPacket[2*ETH_LENGTH_OF_ADDRESS] = 0x00;
+ TestPacket[2*ETH_LENGTH_OF_ADDRESS+1] = 0x00;
+ TestPacket[TEST_LEN-1] = MAGIC_NUM;
+
+
+ //
+ // Set up the DCR for loopback operation.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_DATA_CONFIG,
+ DCR_BYTE_WIDE | DCR_LOOPBACK | DCR_FIFO_8_BYTE);
+
+
+ //
+ // Set the RCR to reject all packets.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_RCV_CONFIG, 0x00);
+
+
+ //
+ // First round of tests -- different loopback modes
+ //
+
+ for (FirstTest = 0; FirstTest < 2; ++FirstTest) {
+
+ //
+ // Stop the card.
+ //
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
+ CR_STOP | CR_NO_DMA | CR_PAGE0);
+
+
+ //
+ // Set up the TCR for the appropriate loopback mode.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_CONFIG, 0x00);
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_CONFIG, TCRValues[FirstTest]);
+
+
+ //
+ // Restart the card.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE0);
+
+
+ //
+ // Now copy down TestPacket and start the transmission.
+ //
+
+ CardCopyDownBuffer(AdaptP, TestPacket, 0, 0, TEST_LEN);
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_START, AdaptP->NicXmitStart);
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_COUNT_MSB, MSB(TEST_LEN));
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_COUNT_LSB, LSB(TEST_LEN));
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
+ CR_START | CR_XMIT | CR_NO_DMA);
+
+
+ //
+ // Wait for the transmission to complete, for about a second.
+ //
+
+ {
+ UINT i;
+ i=0;
+ NdisRawReadPortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_STATUS, &Tmp);
+ while (!(Tmp & (ISR_XMIT | ISR_XMIT_ERR))) {
+
+ if (++i > 100) {
+ IF_TEST( DbgPrint("F%d: TEST reset timed out\n", FirstTest);)
+ FinalResult = FALSE;
+ goto FinishTest;
+ }
+
+ NdisStallExecution(11000);
+ NdisRawReadPortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_STATUS, &Tmp);
+ }
+ }
+
+ //
+ // WAIT FOR CHIP TO STABILIZE
+ // Write to and read from CR to make sure it is there.
+ // Bug#4267 - WFW
+ //
+
+ {
+ UINT i;
+ for (i = 0; i < 2000; ++i) {
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND, CR_STOP | CR_NO_DMA | CR_PAGE0);
+ NdisRawReadPortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND, &Tmp);
+ if (Tmp != (CR_STOP | CR_NO_DMA | CR_PAGE0)) {
+ NdisStallExecution(1000);
+ } else {
+ break;
+ }
+ }
+ }
+
+
+ //
+ // Acknowledge the interrupt.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_STATUS,
+ ISR_XMIT | ISR_XMIT_ERR);
+
+
+ //
+ // Check that the CRS and CDH bits are set correctly.
+ //
+
+ NdisRawReadPortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_STATUS, &TSRResult);
+
+ if ((TSRResult & TSR_NO_CARRIER) != TSRCRSWanted[FirstTest]) {
+
+ IF_TEST(DbgPrint("F%d: Incorrect CRS value: %x\n", FirstTest, TSRResult);)
+
+ FinalResult = FALSE;
+
+ goto FinishTest;
+
+ }
+
+ if ((TSRResult & TSR_NO_CDH) != TSRCDHWanted[FirstTest]) {
+
+ //
+ // the spec says CDH won't go on for TCR_COAX_LBK, but it does
+ //
+
+ if (TCRValues[FirstTest] != TCR_COAX_LBK) {
+
+ IF_TEST( DbgPrint("F%d: Incorrect CDH value: %x\n", FirstTest,TSRResult);)
+
+ FinalResult = FALSE;
+
+ goto FinishTest;
+
+ }
+
+ }
+
+
+ //
+ // For the Loopback to Coax test the RSR and FIFO
+ // can't be trusted, so skip them.
+ //
+
+ if (TCRValues[FirstTest] == TCR_COAX_LBK) {
+
+ continue;
+
+ }
+
+
+ //
+ // Check that the CRC error happened (it should).
+ //
+
+ NdisRawReadPortUchar(AdaptP->MappedIoBaseAddr+NIC_RCV_STATUS, &RSRResult);
+
+ if (!(RSRResult & RSR_CRC_ERROR)) {
+
+ IF_TEST( DbgPrint("F%d: No CRC error: %x\n", FirstTest, RSRResult);)
+
+ FinalResult = FALSE;
+
+ goto FinishTest;
+
+ }
+
+
+ //
+ // Check that the right values are in the FIFO.
+ //
+
+ for (i=0; i<4; i++) {
+
+ NdisRawReadPortUchar(AdaptP->MappedIoBaseAddr+NIC_FIFO, &Tmp);
+ if (Tmp != FIFOWanted[i]) {
+
+ IF_TEST( DbgPrint("F%d: Bad FIFO value: %d\n", FirstTest, i);)
+
+ FinalResult = FALSE;
+
+ goto FinishTest;
+
+ }
+
+ }
+
+
+ //
+ // Flush the rest of the FIFO.
+ //
+
+ for (i=0; i<4; i++) {
+
+ NdisRawReadPortUchar(AdaptP->MappedIoBaseAddr+NIC_FIFO, &Tmp);
+
+ }
+
+ }
+
+
+ //
+ // Stop the card.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
+ CR_STOP | CR_NO_DMA | CR_PAGE0);
+
+
+ //
+ // Set the TCR for internal loopback.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_CONFIG, 0x00);
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_CONFIG,
+ TCR_INHIBIT_CRC | TCR_NIC_LBK);
+
+ //
+ // Restart the card.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE0);
+
+
+
+ //
+ // Second round of tests -- CRC and Address recognition logic
+ //
+
+ for (SecondTest = 0; SecondTest < 3; ++SecondTest) {
+
+ //
+ // See if the destination address should be valid.
+ //
+
+ if (GoodAddress[SecondTest]) {
+
+ ELNKII_MOVE_MEM(TestPacket, AdaptP->StationAddress, ETH_LENGTH_OF_ADDRESS);
+
+ } else {
+
+ ELNKII_MOVE_MEM(TestPacket, NullAddress, ETH_LENGTH_OF_ADDRESS);
+
+ }
+
+
+ //
+ // Copy down TestPacket.
+ //
+
+ CardCopyDownBuffer(AdaptP, TestPacket, 0, 0, TEST_LEN);
+
+
+ //
+ // Copy down a good or bad CRC, as needed.
+ //
+
+ CardGetPacketCrc(TestPacket, TEST_LEN, CrcBuf);
+
+ if (!GoodCrc[SecondTest]) {
+
+ CrcBuf[0] = (UCHAR)(CrcBuf[0] ^ 0xff); // intentionally make it bad
+
+ }
+
+ CardCopyDownBuffer(AdaptP, CrcBuf, 0, TEST_LEN, 4);
+
+
+ //
+ // Start the transmission.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_START, AdaptP->NicXmitStart);
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_COUNT_MSB, MSB(TEST_LEN+4));
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_COUNT_LSB, LSB(TEST_LEN+4));
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
+ CR_START | CR_XMIT | CR_NO_DMA);
+
+
+ //
+ // Wait for the transmission to complete, for about a second.
+ //
+
+ TimerExpired=FALSE;
+
+ NdisInitializeTimer(&Timer, DelayComplete, &TimerExpired);
+ NdisSetTimer(&Timer, 1000);
+
+ NdisRawReadPortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_STATUS, &Tmp);
+ while (!(Tmp & (ISR_XMIT | ISR_XMIT_ERR))) {
+
+ if (TimerExpired) {
+
+ IF_TEST( DbgPrint("F%d: TEST reset timed out\n", FirstTest);)
+
+ FinalResult = FALSE;
+
+ goto FinishTest;
+
+ }
+
+ NdisRawReadPortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_STATUS, &Tmp);
+
+ }
+
+ //
+ //MUST Cancel the unexpired timer
+ //
+
+ NdisCancelTimer(&Timer,&dummy);
+
+ //
+ // Acknowledge the interrupt.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_STATUS,
+ ISR_XMIT | ISR_XMIT_ERR);
+
+
+ //
+ // Check that RSR is as expected.
+ //
+
+ NdisRawReadPortUchar(AdaptP->MappedIoBaseAddr+NIC_RCV_STATUS, &RSRResult);
+
+ if ((UCHAR)(RSRResult & (RSR_PACKET_OK | RSR_CRC_ERROR)) !=
+ RSRWanted[SecondTest]) {
+
+ IF_TEST( DbgPrint("S%d: Bad RSR: wanted %x got %x\n", SecondTest,
+ RSRWanted[SecondTest], RSRResult);)
+
+ FinalResult = FALSE;
+
+ goto FinishTest;
+
+ }
+
+ }
+
+
+
+ //
+ // Third round of tests - copying data to and from the card.
+ //
+
+ //
+ // First put data in the buffer.
+ //
+
+ for (i=0; i<256; i++) {
+
+ TestSrcBuf[i] = (UCHAR)(256-i);
+
+ }
+
+ //
+ // Loop through all the card memory in 256-byte pieces.
+ //
+
+ for (CurTestLoc = 0; CurTestLoc < (PUCHAR)0x2000; CurTestLoc += 256) {
+
+ //
+ // Copy the data down (have to play around with buffer
+ // numbers and offsets to put it in the right place).
+ //
+
+ CardCopyDownBuffer(AdaptP, TestSrcBuf,
+ (XMIT_BUF)((ULONG)CurTestLoc / TX_BUF_SIZE),
+ (ULONG)CurTestLoc % TX_BUF_SIZE, 256);
+
+ //
+ // Clear the destination buffer and read it back.
+ //
+
+ for (i=0; i<256; i++) {
+
+ TestDestBuf[i] = 77;
+
+ }
+
+ CardCopyUp(AdaptP, TestDestBuf,
+ AdaptP->XmitStart + (ULONG)CurTestLoc, 256);
+
+ //
+ // Make sure that the data matches.
+ //
+
+ for (i=0; i<256; i++) {
+
+ if (TestSrcBuf[i] != TestDestBuf[i]) {
+
+ IF_TEST( DbgPrint("T: Bad data at %lx\n", (ULONG)(CurTestLoc+i));)
+
+ FinalResult = FALSE;
+
+ goto FinishTest;
+
+ }
+
+ }
+
+ }
+
+
+
+ //
+ // FinishTest: jump here to exit the tests cleanly.
+ //
+
+FinishTest:
+
+ //
+ // Stop the card.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
+ CR_STOP | CR_NO_DMA | CR_PAGE0);
+
+
+ //
+ // Restore DCR, RCR, and TCR.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_DATA_CONFIG,
+ DCR_BYTE_WIDE | DCR_NORMAL | DCR_FIFO_8_BYTE);
+
+ //
+ // (clear these two to be safe)
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_RMT_COUNT_MSB, 0);
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_RMT_COUNT_LSB, 0);
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_RCV_CONFIG, AdaptP->NicReceiveConfig);
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_CONFIG, TCR_LOOPBACK);
+
+ //
+ // The reconfiguring of the config registers can cause the xmit to complete
+ // if the test was a failure. Therefore, we pause here to allow the xmit
+ // to complete so that we can ACK it below - leaving the card in a valid state.
+ //
+
+ NdisStallExecution(50000);
+
+ //
+ // Acknowledge any interrupts that are floating around.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_STATUS, 0xff);
+
+
+ //
+ // Start the card, but stay in loopback mode.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE0);
+
+
+
+ return FinalResult;
+}
+
+
+BOOLEAN
+CardReset(
+ IN PELNKII_ADAPTER AdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ Resets the card.
+
+Arguments:
+
+ AdaptP - pointer to the adapter block
+
+Return Value:
+
+ TRUE if everything is OK.
+
+--*/
+
+{
+ CardStop(AdaptP);
+
+ //
+ // CardSetup() does a software reset.
+ //
+
+ if (!CardSetup(AdaptP)) {
+
+ NdisWriteErrorLogEntry(
+ AdaptP->NdisAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 2,
+ cardReset,
+ ELNKII_ERRMSG_CARD_SETUP
+ );
+
+ return FALSE;
+
+ }
+
+ CardStart(AdaptP);
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+CardCopyDownPacket(
+ IN PELNKII_ADAPTER AdaptP,
+ IN PNDIS_PACKET Packet,
+ IN XMIT_BUF XmitBufferNum,
+ OUT UINT * Length
+ )
+
+/*++
+
+Routine Description:
+
+ Copies the packet Packet down starting at the beginning of
+ transmit buffer XmitBufferNum, fills in Length to be the
+ length of the packet. It uses memory mapping or programmed
+ I/O as appropriate.
+
+Arguments:
+
+ AdaptP - pointer to the adapter block
+ Packet - the packet to copy down
+ XmitBufferNum - the transmit buffer number
+
+Return Value:
+
+ Length - the length of the data in the packet in bytes.
+ TRUE if the transfer completed with no problems.
+
+--*/
+
+{
+ PUCHAR CurAddress, BufAddress;
+ UINT CurLength, Len;
+ PNDIS_BUFFER CurBuffer;
+ UINT TmpLen, BurstSize;
+ UCHAR GaStatus;
+
+ if (AdaptP->MemMapped) {
+
+ //
+ // Memory mapped, just copy each buffer over.
+ //
+
+ NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, NULL);
+
+ CurAddress = AdaptP->XmitStart + XmitBufferNum*TX_BUF_SIZE;
+
+ CurLength = 0;
+
+ while (CurBuffer) {
+
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufAddress, &Len);
+
+ ELNKII_MOVE_MEM_TO_SHARED_RAM(CurAddress, BufAddress, Len);
+
+ CurAddress += Len;
+
+ CurLength += Len;
+
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+
+ }
+
+ *Length = CurLength;
+
+ } else {
+
+ //
+ // Programmed I/O, have to transfer the data.
+ //
+
+ NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, NULL);
+
+ CurAddress = (PUCHAR)0x2000 + XmitBufferNum*TX_BUF_SIZE;
+
+ CurLength = 0;
+
+ NdisAcquireSpinLock(&AdaptP->Lock);
+
+ while (CurBuffer) {
+
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufAddress, &Len);
+
+ if (Len == 0) {
+
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+
+ continue;
+
+ }
+
+ //
+ // Set up the Gate Array for programmed I/O transfer.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_DMA_ADDR_MSB,
+ MSB((ULONG)CurAddress));
+
+ NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_DMA_ADDR_LSB,
+ LSB((ULONG)CurAddress));
+
+ NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_CONTROL,
+ (UCHAR)((CTRL_START | CTRL_DIR_DOWN) | AdaptP->GaControlBits));
+
+
+ //
+ // First transfer multiples of DMA_BURST_SIZE.
+ //
+
+ TmpLen = Len;
+ BurstSize = DMA_BURST_SIZE;
+
+ while (TmpLen >= BurstSize) {
+
+ if ((ULONG)BufAddress & 0x01) {
+
+ NdisRawWritePortBufferUchar(
+ AdaptP->MappedGaBaseAddr+GA_REG_FILE_MSB,
+ (PUCHAR)BufAddress,
+ BurstSize
+ );
+
+ } else {
+
+ NdisRawWritePortBufferUshort(
+ AdaptP->MappedGaBaseAddr+GA_REG_FILE_MSB,
+ (PUSHORT)BufAddress,
+ BurstSize/2
+ );
+
+ }
+
+
+ TmpLen -= BurstSize;
+
+ BufAddress += BurstSize;
+
+ //
+ // Wait for the Gate Array FIFO to be ready.
+ //
+
+ do {
+
+ NdisRawReadPortUchar(AdaptP->MappedGaBaseAddr+GA_STATUS, &GaStatus);
+
+ if (GaStatus & (STREG_UNDERFLOW | STREG_OVERFLOW)) {
+#if DBG
+ DbgPrint("DATA PORT READY ERROR IN ELNKII - CCDP\n");
+ DbgPrint("\tStatus = 0x%x, BurstSize = 0x%x, PrevBurstSize = 0x%x\n",
+ GaStatus, BurstSize, PrevBurstSize);
+#endif
+
+ NdisWriteErrorLogEntry(
+ AdaptP->NdisAdapterHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ cardCopyDownPacket,
+ ELNKII_ERRMSG_DATA_PORT_READY
+ );
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+ return FALSE;
+
+ }
+
+ } while (!(GaStatus & STREG_DP_READY));
+
+#if DBG
+ PrevBurstSize = (UCHAR)BurstSize;
+#endif
+
+ }
+
+ //
+ // Now copy the last bit as UCHARs.
+ //
+
+ NdisRawWritePortBufferUchar(
+ AdaptP->MappedGaBaseAddr+GA_REG_FILE_MSB,
+ BufAddress, TmpLen);
+
+ do {
+
+ NdisRawReadPortUchar(AdaptP->MappedGaBaseAddr+GA_STATUS, &GaStatus);
+
+ if (GaStatus & (STREG_UNDERFLOW | STREG_OVERFLOW)) {
+#if DBG
+ DbgPrint("DATA PORT READY ERROR IN ELNKII - CCDPII\n");
+ DbgPrint("\tStatus = 0x%x, BurstSize = 0x%x, PrevBurstSize = 0x%x\n",
+ GaStatus, BurstSize, PrevBurstSize);
+#endif
+
+ NdisWriteErrorLogEntry(
+ AdaptP->NdisAdapterHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ cardCopyDownPacket,
+ ELNKII_ERRMSG_DATA_PORT_READY
+ );
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+ return FALSE;
+ }
+
+ } while (!(GaStatus & STREG_DP_READY));
+
+
+#if DBG
+ PrevBurstSize = (UCHAR)TmpLen;
+#endif
+
+ //
+ // Done, turn off the start bit...
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_CONTROL,
+ (UCHAR)(CTRL_STOP | AdaptP->GaControlBits));
+
+ //
+ // ... and wait for DMA_IN_PROGRESS to go off,
+ // indicating end of flush.
+ //
+
+ do {
+
+ NdisRawReadPortUchar(AdaptP->MappedGaBaseAddr+GA_STATUS, &GaStatus);
+
+ } while (GaStatus & STREG_IN_PROG);
+
+
+ CurAddress += Len;
+
+ CurLength += Len;
+
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+
+ }
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+ *Length = CurLength;
+
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+CardCopyDownBuffer(
+ IN PELNKII_ADAPTER AdaptP,
+ IN PUCHAR SourceBuffer,
+ IN XMIT_BUF XmitBufferNum,
+ IN UINT Offset,
+ IN UINT Length
+ )
+
+/*++
+
+Routine Description:
+
+ Copies down one character buffer (rather than an
+ entire packet), starting at offset Offset, for Length
+ bytes. It uses memory mapping or programmed I/O as
+ appropriate. This function is used for blanking the padding
+ at the end of short packets and also for loopback testing.
+
+Arguments:
+
+ AdaptP - pointer to the adapter block
+ SourceBuffer - the source data to be copied down
+ XmitBufferNum - the transmit buffer number
+ Offset - the offset from the start of the transmit buffer
+ Length - the number of bytes to blank out
+
+Return Value:
+
+ Length - the length of the data in the packet in bytes.
+ TRUE if the transfer completed with no problems.
+
+--*/
+
+{
+ PUCHAR CurAddress;
+ UINT TmpLen, ThisTime;
+ UCHAR GaStatus;
+
+ if (AdaptP->MemMapped) {
+
+ //
+ // Memory mapped, just copy over SourceBuffer.
+ //
+
+ CurAddress = AdaptP->XmitStart + XmitBufferNum*TX_BUF_SIZE + Offset;
+
+ ELNKII_MOVE_MEM_TO_SHARED_RAM(CurAddress, SourceBuffer, Length);
+
+ } else {
+
+ //
+ // Programmed I/O, have to transfer the data.
+ //
+
+ CurAddress = (PUCHAR)0x2000 + XmitBufferNum*TX_BUF_SIZE + Offset;
+
+ //
+ // Set up the Gate Array for programmed I/O transfer.
+ //
+
+ NdisAcquireSpinLock(&AdaptP->Lock);
+
+ NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_DMA_ADDR_MSB,
+ MSB((ULONG)CurAddress));
+
+ NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_DMA_ADDR_LSB,
+ LSB((ULONG)CurAddress));
+
+ NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_CONTROL,
+ (UCHAR)((CTRL_START | CTRL_DIR_DOWN) | AdaptP->GaControlBits));
+
+
+ //
+ // Copy the data down in DMA_BURST_SIZE bursts.
+ //
+
+ TmpLen = Length;
+
+ while (TmpLen > 0) {
+
+ ThisTime = (TmpLen >= DMA_BURST_SIZE) ? DMA_BURST_SIZE : TmpLen;
+
+ NdisRawWritePortBufferUchar(
+ AdaptP->MappedGaBaseAddr+GA_REG_FILE_MSB,
+ SourceBuffer, ThisTime);
+
+
+ TmpLen -= ThisTime;
+
+ SourceBuffer += ThisTime;
+
+ //
+ // Wait for the Gate Array FIFO to be ready.
+ //
+
+ do {
+
+ NdisRawReadPortUchar(AdaptP->MappedGaBaseAddr+GA_STATUS, &GaStatus);
+
+ if (GaStatus & (STREG_UNDERFLOW | STREG_OVERFLOW)) {
+#if DBG
+ DbgPrint("DATA PORT READY ERROR IN ELNKII - CCDB\n");
+ DbgPrint("\tStatus = 0x%x, BurstSize = 0x%x, PrevBurstSize = 0x%x\n",
+ GaStatus, ThisTime, PrevBurstSize);
+#endif
+
+ NdisWriteErrorLogEntry(
+ AdaptP->NdisAdapterHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ cardCopyDownBuffer,
+ ELNKII_ERRMSG_DATA_PORT_READY
+ );
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+ return FALSE;
+
+ }
+
+ } while (!(GaStatus & STREG_DP_READY));
+
+#if DBG
+ PrevBurstSize = (UCHAR)ThisTime;
+#endif
+
+ }
+
+ //
+ // Done, turn off the start bit..
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_CONTROL,
+ (UCHAR)(CTRL_STOP | AdaptP->GaControlBits));
+
+ //
+ // ... and wait for DMA_IN_PROGRESS to go off,
+ // indicating end of flush.
+ //
+
+ do {
+
+ NdisRawReadPortUchar(AdaptP->MappedGaBaseAddr+GA_STATUS, &GaStatus);
+
+ } while (GaStatus & STREG_IN_PROG);
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+ }
+
+#if DBG
+ IF_ELNKIIDEBUG( ELNKII_DEBUG_TRACK_PACKET_LENS ) {
+
+ if (Offset == 18 && Length == 42) {
+ UINT i;
+ for (i=0; i<20; i++) {
+ SourceBuffer[i] = ' ';
+ }
+ }
+
+ }
+#endif
+
+ return TRUE;
+}
+
+
+
+
+BOOLEAN
+CardCopyUp(
+ IN PELNKII_ADAPTER AdaptP,
+ IN PUCHAR Target,
+ IN PUCHAR Source,
+ IN UINT Length
+ )
+
+/*++
+
+Routine Description:
+
+ Copies data from the card to memory. It uses memory mapping
+ or programmed I/O as appropriate.
+
+Arguments:
+
+ AdaptP - pointer to the adapter block
+ Target - the target address
+ Source - the source address (on the card)
+ Length - the number of bytes to copy
+
+Return Value:
+
+ TRUE if the transfer completed with no problems.
+
+--*/
+
+{
+ UINT TmpLen, BurstSize;
+ UCHAR GaStatus;
+
+ if (Length == 0) {
+
+ return TRUE;
+
+ }
+
+ if (AdaptP->MemMapped) {
+
+ //
+ // Memory mapped, just copy the data over.
+ //
+
+ ELNKII_MOVE_SHARED_RAM_TO_MEM(Target, Source, Length);
+
+ } else { // programmed I/O
+
+ //
+ // Programmed I/O, have to transfer the data.
+ //
+
+ //
+ // Adjust the address to be a card address.
+ //
+
+ Source -= ((ULONG)AdaptP->XmitStart - 0x2000);
+
+ //
+ // Set up the Gate Array for programmed I/O transfer.
+ //
+
+ NdisAcquireSpinLock(&AdaptP->Lock);
+
+ NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_DMA_ADDR_MSB, MSB((ULONG)Source));
+ NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_DMA_ADDR_LSB, LSB((ULONG)Source));
+ NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_CONTROL,
+ (UCHAR)((CTRL_START | CTRL_DIR_UP) | AdaptP->GaControlBits));
+
+
+ //
+ // First copy multiples of DMA_BURST_SIZE as USHORTs.
+ //
+
+ TmpLen = Length;
+ BurstSize = DMA_BURST_SIZE;
+
+ //
+ // Before doing this, transfer one byte if needed to
+ // align on a USHORT boundary.
+ //
+
+ while (TmpLen >= BurstSize) {
+
+ //
+ // First wait for the Gate Array FIFO to be ready.
+ //
+
+ do {
+
+ NdisRawReadPortUchar(AdaptP->MappedGaBaseAddr+GA_STATUS, &GaStatus);
+
+ if (GaStatus & (STREG_UNDERFLOW | STREG_OVERFLOW)) {
+
+#if DBG
+ DbgPrint("DATA PORT READY ERROR IN ELNKII - CCU\n");
+ DbgPrint("\tStatus = 0x%x, BurstSize = 0x%x, PrevBurstSize = 0x%x\n",
+ GaStatus, PrevBurstSize, PrevPrevBurstSize);
+#endif
+
+ NdisWriteErrorLogEntry(
+ AdaptP->NdisAdapterHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ cardCopyUp,
+ ELNKII_ERRMSG_DATA_PORT_READY
+ );
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+ return FALSE;
+
+ }
+
+ } while (!(GaStatus & STREG_DP_READY));
+
+
+ if ((ULONG)Target & 0x01) {
+
+ //
+ // This is the first burst, and it starts on
+ // an odd boundary.
+ //
+
+ NdisRawReadPortBufferUchar(
+ AdaptP->MappedGaBaseAddr+GA_REG_FILE_MSB,
+ (PUCHAR)Target,
+ BurstSize);
+
+ TmpLen -= BurstSize;
+ Target += BurstSize;
+
+
+#if DBG
+ PrevPrevBurstSize = PrevBurstSize;
+ PrevBurstSize = (UCHAR)BurstSize;
+#endif
+
+ } else {
+
+
+ NdisRawReadPortBufferUshort(
+ AdaptP->MappedGaBaseAddr+GA_REG_FILE_MSB,
+ (PUSHORT)Target, BurstSize/2);
+
+ TmpLen -= BurstSize;
+ Target += BurstSize;
+
+
+#if DBG
+ PrevPrevBurstSize = PrevBurstSize;
+ PrevBurstSize = (UCHAR)BurstSize;
+#endif
+
+ }
+
+ }
+
+ //
+ // Now copy the last bit of data as UCHARs.
+ //
+
+ do {
+
+ NdisRawReadPortUchar(AdaptP->MappedGaBaseAddr+GA_STATUS, &GaStatus);
+
+ if (GaStatus & (STREG_UNDERFLOW | STREG_OVERFLOW)) {
+#if DBG
+ DbgPrint("DATA PORT READY ERROR IN ELNKII - CCUII\n");
+ DbgPrint("\tStatus = 0x%x, BurstSize = 0x%x, PrevBurstSize = 0x%x\n",
+ GaStatus, BurstSize, PrevBurstSize);
+#endif
+
+ NdisWriteErrorLogEntry(
+ AdaptP->NdisAdapterHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ cardCopyUp,
+ ELNKII_ERRMSG_DATA_PORT_READY
+ );
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+ return FALSE;
+
+ }
+
+ } while (!(GaStatus & STREG_DP_READY));
+
+ NdisRawReadPortBufferUchar(
+ AdaptP->MappedGaBaseAddr+GA_REG_FILE_MSB,
+ Target, TmpLen);
+
+
+ //
+ // Done, turn off the start bit.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_CONTROL,
+ (UCHAR)(CTRL_STOP | AdaptP->GaControlBits));
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+ }
+
+ return TRUE;
+
+}
+
+ULONG
+CardComputeCrc(
+ IN PUCHAR Buffer,
+ IN UINT Length
+ )
+
+/*++
+
+Routine Description:
+
+ Runs the AUTODIN II CRC algorithm on buffer Buffer of
+ length Length.
+
+Arguments:
+
+ Buffer - the input buffer
+ Length - the length of Buffer
+
+Return Value:
+
+ The 32-bit CRC value.
+
+Note:
+
+ This is adapted from the comments in the assembly language
+ version in _GENREQ.ASM of the DWB NE1000/2000 driver.
+
+--*/
+
+{
+ ULONG Crc, Carry;
+ UINT i, j;
+ UCHAR CurByte;
+
+ Crc = 0xffffffff;
+
+ for (i = 0; i < Length; i++) {
+
+ CurByte = Buffer[i];
+
+ for (j = 0; j < 8; j++) {
+
+ Carry = ((Crc & 0x80000000) ? 1 : 0) ^ (CurByte & 0x01);
+
+ Crc <<= 1;
+
+ CurByte >>= 1;
+
+ if (Carry) {
+
+ Crc = (Crc ^ 0x04c11db6) | Carry;
+
+ }
+
+ }
+
+ }
+
+ return Crc;
+
+}
+
+#pragma NDIS_INIT_FUNCTION(CardGetPacketCrc)
+
+VOID
+CardGetPacketCrc(
+ IN PUCHAR Buffer,
+ IN UINT Length,
+ OUT UCHAR Crc[4]
+ )
+
+/*++
+
+Routine Description:
+
+ For a given Buffer, computes the packet CRC for it.
+ It uses CardComputeCrc to determine the CRC value, then
+ inverts the order and value of all the bits (I don't
+ know why this is necessary).
+
+Arguments:
+
+ Buffer - the input buffer
+ Length - the length of Buffer
+
+Return Value:
+
+ The CRC will be stored in Crc.
+
+--*/
+
+{
+ static UCHAR InvertBits[16] = { 0x0, 0x8, 0x4, 0xc,
+ 0x2, 0xa, 0x6, 0xe,
+ 0x1, 0x9, 0x5, 0xd,
+ 0x3, 0xb, 0x7, 0xf };
+ ULONG CrcValue;
+ UCHAR Tmp;
+ UINT i;
+
+ //
+ // First compute the CRC.
+ //
+
+ CrcValue = CardComputeCrc(Buffer, Length);
+
+
+ //
+ // Now invert the bits in the result.
+ //
+
+ for (i=0; i<4; i++) {
+
+ Tmp = ((PUCHAR)&CrcValue)[3-i];
+
+ Crc[i] = (UCHAR)((InvertBits[Tmp >> 4] +
+ (InvertBits[Tmp & 0xf] << 4)) ^ 0xff);
+
+ }
+
+}
+
+
+VOID
+CardGetMulticastBit(
+ IN UCHAR Address[ETH_LENGTH_OF_ADDRESS],
+ OUT UCHAR * Byte,
+ OUT UCHAR * Value
+ )
+
+/*++
+
+Routine Description:
+
+ For a given multicast address, returns the byte and bit in
+ the card multicast registers that it hashes to. Calls
+ CardComputeCrc() to determine the CRC value.
+
+Arguments:
+
+ Address - the address
+ Byte - the byte that it hashes to
+ Value - will have a 1 in the relevant bit
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Crc;
+ UINT BitNumber;
+
+ //
+ // First compute the CRC.
+ //
+
+ Crc = CardComputeCrc(Address, ETH_LENGTH_OF_ADDRESS);
+
+
+ //
+ // The bit number is now in the 6 most significant bits of CRC.
+ //
+
+ BitNumber = (UINT)((Crc >> 26) & 0x3f);
+
+ *Byte = (UCHAR)(BitNumber / 8);
+ *Value = (UCHAR)((UCHAR)1 << (BitNumber % 8));
+}
+
+VOID
+CardFillMulticastRegs(
+ IN PELNKII_ADAPTER AdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ Erases and refills the card multicast registers. Used when
+ an address has been deleted and all bits must be recomputed.
+
+Arguments:
+
+ AdaptP - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UINT i;
+ UCHAR Byte, Bit;
+ NDIS_STATUS Status;
+
+
+ //
+ // First turn all bits off.
+ //
+
+ for (i=0; i<8; i++) {
+
+ AdaptP->NicMulticastRegs[i] = 0;
+
+ }
+
+ NdisAcquireSpinLock(&AdaptP->Lock);
+
+ EthQueryGlobalFilterAddresses(
+ &Status,
+ AdaptP->FilterDB,
+ DEFAULT_MULTICASTLISTMAX * ETH_LENGTH_OF_ADDRESS,
+ &i,
+ Addresses
+ );
+
+
+ ASSERT(Status == NDIS_STATUS_SUCCESS);
+
+ //
+ // Now turn on the bit for each address in the multicast list.
+ //
+
+ for ( ; i > 0; ) {
+
+ i--;
+
+ CardGetMulticastBit(Addresses[i], &Byte, &Bit);
+
+ AdaptP->NicMulticastRegs[Byte] |= Bit;
+
+ }
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+}
+
+
+
+
+
+
+
+
+BOOLEAN
+SyncCardStop(
+ IN PVOID SynchronizeContext
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the NIC_COMMAND register to stop the card.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ TRUE if the power has failed.
+
+--*/
+
+{
+ PELNKII_ADAPTER AdaptP = ((PELNKII_ADAPTER)SynchronizeContext);
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND, CR_STOP | CR_NO_DMA);
+
+ return FALSE;
+}
+
+VOID
+CardStartXmit(
+ IN PELNKII_ADAPTER AdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the NIC_COMMAND register to start a transmission.
+ The transmit buffer number is taken from AdaptP->CurBufXmitting
+ and the length from AdaptP->PacketLens[AdaptP->CurBufXmitting].
+
+Arguments:
+
+ AdaptP - pointer to the adapter block
+
+Return Value:
+
+ TRUE if the power has failed.
+
+--*/
+
+{
+ XMIT_BUF XmitBufferNum = AdaptP->CurBufXmitting;
+ UINT Length = AdaptP->PacketLens[XmitBufferNum];
+
+
+ //
+ // Prepare the NIC registers for transmission.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_START,
+ (UCHAR)(AdaptP->NicXmitStart + (UCHAR)(XmitBufferNum*BUFS_PER_TX)));
+
+ //
+ // Pad the length to 60 (plus CRC will be 64) if needed.
+ //
+
+ if (Length < 60) {
+
+ Length = 60;
+
+ }
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_COUNT_MSB, MSB(Length));
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_COUNT_LSB, LSB(Length));
+
+ //
+ // Start transmission, check for power failure first.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
+ CR_START | CR_XMIT | CR_NO_DMA);
+
+
+ IF_LOG( ElnkiiLog('x');)
+
+}
+
+BOOLEAN
+SyncCardGetXmitStatus(
+ IN PVOID SynchronizeContext
+ )
+
+/*++
+
+Routine Description:
+
+ Gets the value of the "transmit status" NIC register and stores
+ it in AdaptP->XmitStatus.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER AdaptP = ((PELNKII_ADAPTER)SynchronizeContext);
+
+ NdisRawReadPortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_STATUS, &AdaptP->XmitStatus);
+
+ return FALSE;
+
+}
+
+BOOLEAN
+SyncCardGetCurrent(
+ IN PVOID SynchronizeContext
+ )
+
+/*++
+
+Routine Description:
+
+ Gets the value of the CURRENT NIC register and stores
+ it in AdaptP->Current.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER AdaptP = ((PELNKII_ADAPTER)SynchronizeContext);
+
+ //
+ // Have to go to page 1 to read this register.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE1);
+
+ NdisRawReadPortUchar(AdaptP->MappedIoBaseAddr+NIC_CURRENT, &AdaptP->Current);
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE0);
+
+ return FALSE;
+
+}
+
+VOID
+CardSetBoundary(
+ IN PELNKII_ADAPTER AdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the value of the "boundary" NIC register to one behind
+ AdaptP->NicNextPacket, to prevent packets from being received
+ on top of un-indicated ones.
+
+Arguments:
+
+ AdaptP - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Have to be careful with "one behin NicNextPacket" when
+ // NicNextPacket is the first buffer in receive area.
+ //
+
+ if (AdaptP->NicNextPacket == AdaptP->NicPageStart) {
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_BOUNDARY,
+ (UCHAR)(AdaptP->NicPageStop-(UCHAR)1));
+
+ } else {
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_BOUNDARY,
+ (UCHAR)(AdaptP->NicNextPacket-(UCHAR)1));
+
+ }
+
+}
+
+BOOLEAN
+SyncCardSetReceiveConfig(
+ IN PVOID SynchronizeContext
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the value of the "receive configuration" NIC register to
+ the value of AdaptP->NicReceiveConfig.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER AdaptP = ((PELNKII_ADAPTER)SynchronizeContext);
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_RCV_CONFIG, AdaptP->NicReceiveConfig);
+
+ return FALSE;
+
+}
+
+BOOLEAN
+SyncCardSetAllMulticast(
+ IN PVOID SynchronizeContext
+ )
+
+/*++
+
+Routine Description:
+
+ Turns on all the bits in the multicast register. Used when
+ the card must receive all multicast packets.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER AdaptP = ((PELNKII_ADAPTER)SynchronizeContext);
+ UINT i;
+
+ //
+ // Have to move to page 1 to set these registers.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE1);
+
+ for (i=0; i<8; i++) {
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+(NIC_MC_ADDR+i), 0xff);
+
+ }
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE0);
+
+ return FALSE;
+
+}
+
+BOOLEAN
+SyncCardCopyMulticastRegs(
+ IN PVOID SynchronizeContext
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the eight bytes in the card multicast registers.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER AdaptP = ((PELNKII_ADAPTER)SynchronizeContext);
+ UINT i;
+
+ //
+ // Have to move to page 1 to set these registers.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE1);
+
+ for (i=0; i<8; i++) {
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+(NIC_MC_ADDR+i),
+ AdaptP->NicMulticastRegs[i]);
+
+ }
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE0);
+
+ return FALSE;
+
+}
+
+BOOLEAN
+SyncCardSetInterruptMask(
+ IN PVOID SynchronizeContext
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the "interrupt mask" register of the NIC to the value of
+ AdaptP->NicInterruptMask.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER AdaptP = ((PELNKII_ADAPTER)SynchronizeContext);
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_MASK, AdaptP->NicInterruptMask);
+
+ return FALSE;
+
+}
+
+BOOLEAN
+SyncCardAcknowledgeReceive(
+ IN PVOID SynchronizeContext
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the "packet received" bit in the NIC interrupt status register,
+ which re-enables interrupts of that type.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER AdaptP = ((PELNKII_ADAPTER)SynchronizeContext);
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_STATUS, ISR_RCV);
+
+ //
+ // Interrupts were previously blocked in the interrupt handler.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_MASK, AdaptP->NicInterruptMask);
+
+ return FALSE;
+
+}
+
+BOOLEAN
+SyncCardAcknowledgeOverflow(
+ IN PVOID SynchronizeContext
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the "buffer overflow" bit in the NIC interrupt status register,
+ which re-enables interrupts of that type.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER AdaptP = ((PELNKII_ADAPTER)SynchronizeContext);
+ UCHAR InterruptStatus;
+
+ CardGetInterruptStatus(AdaptP, &InterruptStatus);
+
+ if (InterruptStatus & ISR_RCV_ERR) {
+
+ SyncCardUpdateCounters(AdaptP);
+
+ }
+
+ NdisRawWritePortUchar(
+ AdaptP->MappedIoBaseAddr+NIC_INTR_STATUS,
+ ISR_OVERFLOW
+ );
+
+ return FALSE;
+
+}
+
+BOOLEAN
+SyncCardAcknowledgeTransmit(
+ IN PVOID SynchronizeContext
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the "packet transmitted" bit in the NIC interrupt status register,
+ which re-enables interrupts of that type.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER AdaptP = ((PELNKII_ADAPTER)SynchronizeContext);
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_STATUS, ISR_XMIT | ISR_XMIT_ERR);
+
+ //
+ // Interrupts were previously blocked in the interrupt handler.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_MASK, AdaptP->NicInterruptMask);
+
+ return FALSE;
+
+}
+
+BOOLEAN
+SyncCardAckAndGetCurrent(
+ IN PVOID SynchronizeContext
+ )
+
+/*++
+
+Routine Description:
+
+ Performs the functions of SyncCardAcknowledgeReceive followed by
+ SyncCardGetCurrent (since the two are always called
+ one after the other).
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER AdaptP = ((PELNKII_ADAPTER)SynchronizeContext);
+
+ //
+ // SyncCardAcknowledgeReceive.
+ //
+
+#ifdef i386
+
+ _asm {
+ cli
+ }
+
+#endif
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_STATUS, ISR_RCV);
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_MASK, AdaptP->NicInterruptMask);
+
+#ifdef i386
+
+ _asm {
+ sti
+ }
+
+#endif
+
+ //
+ // SyncCardGetCurrent.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE1);
+
+ NdisRawReadPortUchar(AdaptP->MappedIoBaseAddr+NIC_CURRENT, &AdaptP->Current);
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE0);
+
+ return FALSE;
+
+}
+
+BOOLEAN
+SyncCardGetXmitStatusAndAck(
+ IN PVOID SynchronizeContext
+ )
+
+/*++
+
+Routine Description:
+
+ Performs the functions of SyncCardGetXmitStatus followed by
+ SyncCardAcknowledgeTransmit (since the two are always
+ called one after the other).
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER AdaptP = ((PELNKII_ADAPTER)SynchronizeContext);
+
+ //
+ // SyncCardGetXmitStatus.
+ //
+
+ NdisRawReadPortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_STATUS, &AdaptP->XmitStatus);
+
+ //
+ // SyncCardAcknowledgeTransmit.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_STATUS, ISR_XMIT | ISR_XMIT_ERR);
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_MASK, AdaptP->NicInterruptMask);
+
+ return FALSE;
+
+}
+
+BOOLEAN
+SyncCardUpdateCounters(
+ IN PVOID SynchronizeContext
+ )
+
+/*++
+
+Routine Description:
+
+ Updates the values of the three counters (frame alignment errors,
+ CRC errors, and missed packets).
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER AdaptP = ((PELNKII_ADAPTER)SynchronizeContext);
+ UCHAR Tmp;
+
+ NdisRawReadPortUchar(AdaptP->MappedIoBaseAddr+NIC_FAE_ERR_CNTR, &Tmp);
+ AdaptP->FrameAlignmentErrors += Tmp;
+
+ NdisRawReadPortUchar(AdaptP->MappedIoBaseAddr+NIC_CRC_ERR_CNTR, &Tmp);
+ AdaptP->CrcErrors += Tmp;
+
+ NdisRawReadPortUchar(AdaptP->MappedIoBaseAddr+NIC_MISSED_CNTR, &Tmp);
+ AdaptP->MissedPackets += Tmp;
+
+ return FALSE;
+
+}
+
+BOOLEAN
+SyncCardHandleOverflow(
+ IN PVOID SynchronizeContext
+ )
+
+/*++
+
+Routine Description:
+
+ Sets all the flags for dealing with a receive overflow, stops the card
+ and acknowledges all outstanding interrupts.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER AdaptP = ((PELNKII_ADAPTER)SynchronizeContext);
+
+ IF_LOG( ElnkiiLog('F');)
+
+
+ //
+ // This is a copy of CardStop(). This is changed in minor ways since
+ // we are already synchornized with interrupts.
+ //
+
+ //
+ // Turn on the STOP bit in the Command register.
+ //
+
+ SyncCardStop(AdaptP);
+
+ //
+ // Wait for ISR_RESET, but only for 1.6 milliseconds (as
+ // described in the March 1991 8390 addendum), since that
+ // is the maximum time for a software reset to occur.
+ //
+ //
+
+ NdisStallExecution(2000);
+
+
+ //
+ // Clear the Remote Byte Count register so that ISR_RESET
+ // will come on.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_RMT_COUNT_MSB, 0);
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_RMT_COUNT_LSB, 0);
+
+
+ //
+ // According to National Semiconductor, the next check is necessary
+ // See Step 5. of the overflow process
+ //
+ // NOTE: The setting of variables to check if the transmit has completed
+ // cannot be done here because anything in the ISR has already been ack'ed
+ // inside the main DPC. Thus, the setting of the variables, described in
+ // the Handbook was moved to the main DPC.
+ //
+ // Continued: If you did the check here, you will doubly transmit most
+ // packets that happened to be on the card when the overflow occurred.
+ //
+
+ //
+ // Put the card in loopback mode, then start it.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_CONFIG, TCR_LOOPBACK);
+
+ //
+ // Start the card. This does not Undo the loopback mode.
+ //
+
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND, CR_START | CR_NO_DMA);
+
+ return FALSE;
+
+}
diff --git a/private/ntos/ndis/elnkii/elnkhrd.h b/private/ntos/ndis/elnkii/elnkhrd.h
new file mode 100644
index 000000000..c07fa02e6
--- /dev/null
+++ b/private/ntos/ndis/elnkii/elnkhrd.h
@@ -0,0 +1,780 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ elnkhrd.h
+
+Abstract:
+
+ The main program for an Etherlink II MAC driver.
+
+Author:
+
+ Anthony V. Ercolano (tonye) creation-date 19-Jun-1990 (Driver model)
+
+ Orginal Elnkii code by AdamBa.
+
+Environment:
+
+ This driver is expected to work in DOS, OS2 and NT at the equivalent
+ of kernal mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+ Dec-1991 by Sean Selitrennikoff - Conversion of AdamBa's code to TonyE Model
+
+
+--*/
+
+#ifndef _ELNKIIHARDWARE_
+#define _ELNKIIHARDWARE_
+
+// AdaptP->IoBaseAddr
+//
+// must match the setting of I/O Base Address jumper on
+// the card. Choices are 0x300, 0x310, 0x330, 0x350, 0x250,
+// 0x280, 0x2a0, and 0x2e0.
+
+#define DEFAULT_IOBASEADDR (PVOID)0x300
+
+
+
+// AdaptP->ExternalTransceiver
+//
+// whether you are using thick Ethernet cable attached to the
+// DIX port, or thin Ethernet attached to the BNC port. This
+// will probably be TRUE.
+
+#define DEFAULT_EXTERNALTRANSCEIVER FALSE
+
+
+
+// AdaptP->InterruptNumber
+//
+// the interrupt number the board is using. Choices are 2, 3,
+// 4, or 5; some of these are used by other NT drivers.
+
+#define DEFAULT_INTERRUPTNUMBER 3
+
+
+
+// AdaptP->MemMapped
+//
+// whether to use memory mapping for data transfer, or programmed
+// I/O. If it is TRUE, the Memory base address jumper must be
+// moved from its default "Disable" setting.
+
+#define DEFAULT_MEMMAPPED FALSE
+
+
+
+// AdaptP->MaxOpens
+//
+// the maximum number of protocols that may be bound to this
+// adapter at one time.
+
+#define DEFAULT_MAXOPENS 4
+
+
+
+// AdaptP->MulticastListMax
+//
+// the maximum number of different multicast addresses that
+// may be specified to this adapter (the list is global for
+// all protocols).
+
+#define DEFAULT_MULTICASTLISTMAX 8
+
+
+//
+// Offsets from AdaptP->MappedIoBaseAddr of the ports used to access
+// the 8390 NIC registers.
+//
+// The names in parenthesis are the abbreviations by which
+// the registers are referred to in the 8390 data sheet.
+//
+// Some of the offsets appear more than once
+// because they have have relevant page 0 and page 1 values,
+// or they are different registers when read than they are
+// when written. The notation MSB indicates that only the
+// MSB can be set for this register, the LSB is assumed 0.
+//
+
+#define NIC_COMMAND 0x0 // (CR)
+#define NIC_PAGE_START 0x1 // (PSTART) MSB, write-only
+#define NIC_PHYS_ADDR 0x1 // (PAR0) page 1
+#define NIC_PAGE_STOP 0x2 // (PSTOP) MSB, write-only
+#define NIC_BOUNDARY 0x3 // (BNRY) MSB
+#define NIC_XMIT_START 0x4 // (TPSR) MSB, write-only
+#define NIC_XMIT_STATUS 0x4 // (TSR) read-only
+#define NIC_XMIT_COUNT_LSB 0x5 // (TBCR0) write-only
+#define NIC_XMIT_COUNT_MSB 0x6 // (TBCR1) write-only
+#define NIC_FIFO 0x6 // (FIFO) read-only
+#define NIC_INTR_STATUS 0x7 // (ISR)
+#define NIC_CURRENT 0x7 // (CURR) page 1
+#define NIC_MC_ADDR 0x8 // (MAR0) page 1
+#define NIC_RMT_COUNT_LSB 0xa // (RBCR0) write-only
+#define NIC_RMT_COUNT_MSB 0xb // (RBCR1) write-only
+#define NIC_RCV_CONFIG 0xc // (RCR) write-only
+#define NIC_RCV_STATUS 0xc // (RSR) read-only
+#define NIC_XMIT_CONFIG 0xd // (TCR) write-only
+#define NIC_FAE_ERR_CNTR 0xd // (CNTR0) read-only
+#define NIC_DATA_CONFIG 0xe // (DCR) write-only
+#define NIC_CRC_ERR_CNTR 0xe // (CNTR1) read-only
+#define NIC_INTR_MASK 0xf // (IMR) write-only
+#define NIC_MISSED_CNTR 0xf // (CNTR2) read-only
+
+
+//
+// Constants for the NIC_COMMAND register.
+//
+// Start/stop the card, start transmissions, and select
+// which page of registers was seen through the ports.
+//
+
+#define CR_STOP (UCHAR)0x01 // reset the card
+#define CR_START (UCHAR)0x02 // start the card
+#define CR_XMIT (UCHAR)0x04 // begin transmission
+#define CR_NO_DMA (UCHAR)0x20 // stop remote DMA
+
+#define CR_PS0 (UCHAR)0x40 // low bit of page number
+#define CR_PS1 (UCHAR)0x80 // high bit of page number
+#define CR_PAGE0 (UCHAR)0x00 // select page 0
+#define CR_PAGE1 CR_PS0 // select page 1
+#define CR_PAGE2 CR_PS1 // select page 2
+
+
+//
+// Constants for the NIC_XMIT_STATUS register.
+//
+// Indicate the result of a packet transmission.
+//
+
+#define TSR_XMIT_OK (UCHAR)0x01 // transmit with no errors
+#define TSR_COLLISION (UCHAR)0x04 // collided at least once
+#define TSR_ABORTED (UCHAR)0x08 // too many collisions
+#define TSR_NO_CARRIER (UCHAR)0x10 // carrier lost
+#define TSR_NO_CDH (UCHAR)0x40 // no collision detect heartbeat
+
+
+//
+// Constants for the NIC_INTR_STATUS register.
+//
+// Indicate the cause of an interrupt.
+//
+
+#define ISR_EMPTY (UCHAR)0x00 // no bits set in the ISR
+#define ISR_RCV (UCHAR)0x01 // packet received with no errors
+#define ISR_XMIT (UCHAR)0x02 // packet transmitted with no errors
+#define ISR_RCV_ERR (UCHAR)0x04 // error on packet reception
+#define ISR_XMIT_ERR (UCHAR)0x08 // error on packet transmission
+#define ISR_OVERFLOW (UCHAR)0x10 // receive buffer overflow
+#define ISR_COUNTER (UCHAR)0x20 // MSB set on tally counter
+#define ISR_RESET (UCHAR)0x80 // (not an interrupt) card is reset
+
+
+//
+// Constants for the NIC_RCV_CONFIG register.
+//
+// Configure what type of packets are received.
+//
+
+#define RCR_REJECT_ERR (UCHAR)0x00 // reject error packets
+#define RCR_BROADCAST (UCHAR)0x04 // receive broadcast packets
+#define RCR_MULTICAST (UCHAR)0x08 // receive multicast packets
+#define RCR_ALL_PHYS (UCHAR)0x10 // receive ALL directed packets
+
+
+//
+// Constants for the NIC_RCV_STATUS register.
+//
+// Indicate the status of a received packet.
+//
+// These are also used to interpret the status byte in the
+// packet header of a received packet.
+//
+
+#define RSR_PACKET_OK (UCHAR)0x01 // packet received with no errors
+#define RSR_CRC_ERROR (UCHAR)0x02 // packet received with CRC error
+#define RSR_MULTICAST (UCHAR)0x20 // packet received was multicast
+#define RSR_DISABLED (UCHAR)0x40 // received is disabled
+#define RSR_DEFERRING (UCHAR)0x80 // receiver is deferring
+
+
+//
+// Constants for the NIC_XMIT_CONFIG register.
+//
+// Configures how packets are transmitted.
+//
+
+#define TCR_NO_LOOPBACK (UCHAR)0x00 // normal operation
+#define TCR_LOOPBACK (UCHAR)0x02 // loopback (set when NIC is stopped)
+
+#define TCR_INHIBIT_CRC (UCHAR)0x01 // inhibit appending of CRC
+
+#define TCR_NIC_LBK (UCHAR)0x02 // loopback through the NIC
+#define TCR_SNI_LBK (UCHAR)0x04 // loopback through the SNI
+#define TCR_COAX_LBK (UCHAR)0x06 // loopback to the coax
+
+
+//
+// Constants for the NIC_DATA_CONFIG register.
+//
+// Set data transfer sizes.
+//
+
+#define DCR_BYTE_WIDE (UCHAR)0x00 // byte-wide DMA transfers
+#define DCR_WORD_WIDE (UCHAR)0x01 // word-wide DMA transfers
+
+#define DCR_LOOPBACK (UCHAR)0x00 // loopback mode (TCR must be set)
+#define DCR_NORMAL (UCHAR)0x08 // normal operation
+
+#define DCR_FIFO_8_BYTE (UCHAR)0x40 // 8-byte FIFO threshhold
+
+
+//
+// Constants for the NIC_INTR_MASK register.
+//
+// Configure which ISR settings actually cause interrupts.
+//
+
+#define IMR_RCV (UCHAR)0x01 // packet received with no errors
+#define IMR_XMIT (UCHAR)0x02 // packet transmitted with no errors
+#define IMR_RCV_ERR (UCHAR)0x04 // error on packet reception
+#define IMR_XMIT_ERR (UCHAR)0x08 // error on packet transmission
+#define IMR_OVERFLOW (UCHAR)0x10 // receive buffer overflow
+#define IMR_COUNTER (UCHAR)0x20 // MSB set on tally counter
+
+
+
+//
+// Offsets from AdaptP->MappedGabaseAddr (which is AdaptP->MappedIoBaseAddr+0x400)
+// of the ports used to access the Elnkii Gate Array registers.
+//
+// The names in parenthesis are the abbreviations by which
+// the registers are referred to in the Elnkii Technical
+// Reference.
+//
+
+#define GA_PAGE_START 0x0 // (PSTR) MSB
+#define GA_PAGE_STOP 0x1 // (PSPR) MSB
+#define GA_DRQ_TIMER 0x2 // (DQTR)
+#define GA_IO_BASE 0x3 // (BCFR) read-only
+#define GA_MEM_BASE 0x4 // (PCFR) read-only
+#define GA_CONFIG 0x5 // (GACFR)
+#define GA_CONTROL 0x6 // (CTRL)
+#define GA_STATUS 0x7 // (STREG) read-only
+#define GA_INT_DMA_CONFIG 0x8 // (IDCFR)
+#define GA_DMA_ADDR_MSB 0x9 // (DAMSB)
+#define GA_DMA_ADDR_LSB 0xa // (DALSB)
+#define GA_REG_FILE_MSB 0xe // (RFMSB)
+#define GA_REG_FILE_LSB 0xf // (RFLSB)
+
+
+//
+// Constants for the GA_DRQ_TIMER register.
+//
+
+#define DQTR_16_BYTE (UCHAR)0x10 // 16-byte programmed I/O bursts
+#define DQTR_8_BYTE (UCHAR)0x08 // 8-byte programmed I/O bursts
+
+
+//
+// Constants for the GA_CONFIG register.
+//
+
+#define GACFR_TC_MASK (UCHAR)0x40 // block DMA complete interrupts
+#define GACFR_RAM_SEL (UCHAR)0x08 // allow memory-mapped mode
+#define GACFR_MEM_BANK1 (UCHAR)0x01 // select window for 8K buffer
+
+
+//
+// Constants for the GA_CONTROL register.
+//
+
+#define CTRL_START (UCHAR)0x80 // start the DMA controller
+#define CTRL_STOP (UCHAR)0x00 // stop the DMA controller
+
+#define CTRL_DIR_DOWN (UCHAR)0x40 // system->board transfers
+#define CTRL_DIR_UP (UCHAR)0x00 // board->system transfers
+
+#define CTRL_DB_SEL (UCHAR)0x20 // connect FIFOs serially
+
+#define CTRL_PROM_SEL (UCHAR)0x04 // window PROM into GaAddr ports
+#define CTRL_GA_SEL (UCHAR)0x00 // window GA into GaAddr ports
+
+#define CTRL_BNC (UCHAR)0x02 // internal transceiver
+#define CTRL_DIX (UCHAR)0x00 // external transceiver
+
+#define CTRL_RESET (UCHAR)0x01 // emulate power up reset
+
+
+//
+// Constants for the GA_STATUS register.
+//
+
+#define STREG_DP_READY (UCHAR)0x80 // ready for programmed I/O transfer
+#define STREG_UNDERFLOW (UCHAR)0x40 // register file underflow
+#define STREG_OVERFLOW (UCHAR)0x20 // register file overflow
+#define STREG_IN_PROG (UCHAR)0x08 // programmed I/O in progress
+
+
+
+//++
+//
+// VOID
+// CardStart(
+// IN PELNKII_ADAPTER AdaptP
+// )
+//
+//
+// Routine Description:
+//
+// Starts the card.
+//
+// Arguments:
+//
+// AdaptP - pointer to the adapter block
+//
+// Return Value:
+//
+// None.
+//
+//--
+ //
+ // Assume that the card has been stopped as in CardStop.
+ //
+
+#define CardStart(AdaptP) \
+ NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_CONFIG, TCR_NO_LOOPBACK)
+
+
+
+//++
+//
+// VOID
+// CardSetAllMulticast(
+// IN PELNKII_ADAPTER AdaptP
+// )
+//
+// Routine Description:
+//
+// Enables every bit in the card multicast bit mask.
+// Calls SyncCardSetAllMulticast.
+//
+// Arguments:
+//
+// AdaptP - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardSetAllMulticast(AdaptP) \
+ NdisSynchronizeWithInterrupt(&(AdaptP)->NdisInterrupt, \
+ SyncCardSetAllMulticast, (PVOID)(AdaptP))
+
+
+//++
+//
+// VOID
+// CardCopyMulticastRegs(
+// IN PELNKII_ADAPTER AdaptP
+// )
+//
+// Routine Description:
+//
+// Writes out the entire multicast bit mask to the card from
+// AdaptP->NicMulticastRegs. Calls SyncCardCopyMulticastRegs.
+//
+// Arguments:
+//
+// AdaptP - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardCopyMulticastRegs(AdaptP) \
+ NdisSynchronizeWithInterrupt(&(AdaptP)->NdisInterrupt, \
+ SyncCardCopyMulticastRegs, (PVOID)(AdaptP))
+
+
+
+//++
+//
+// VOID
+// CardGetInterruptStatus(
+// IN PELNKII_ADAPTER AdaptP,
+// OUT PUCHAR InterrupStatus
+// )
+//
+// Routine Description:
+//
+// Reads the interrupt status (ISR) register from the card. Only
+// called at IRQL INTERRUPT_LEVEL.
+//
+// Arguments:
+//
+// AdaptP - The adapter block.
+//
+// InterruptStatus - Returns the value of ISR.
+//
+// Return Value:
+//
+//--
+
+#define CardGetInterruptStatus(AdaptP,InterruptStatus) \
+ NdisRawReadPortUchar((AdaptP)->MappedIoBaseAddr+NIC_INTR_STATUS, (InterruptStatus))
+
+
+//++
+//
+// VOID
+// CardSetReceiveConfig(
+// IN PELNKII_ADAPTER AdaptP
+// )
+//
+// Routine Description:
+//
+// Sets the receive configuration (RCR) register on the card.
+// The value used is AdaptP->NicReceiveConfig. Calls
+// SyncCardSetReceiveConfig.
+//
+// Arguments:
+//
+// AdaptP - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardSetReceiveConfig(AdaptP) \
+ NdisSynchronizeWithInterrupt(&(AdaptP)->NdisInterrupt, \
+ SyncCardSetReceiveConfig, (PVOID)(AdaptP))
+
+
+//++
+//
+// VOID
+// CardBlockInterrupts(
+// IN PELNKII_ADAPTER AdaptP
+// )
+//
+// Routine Description:
+//
+// Blocks all interrupts from the card by clearing the
+// interrupt mask (IMR) register. Only called from
+// IRQL INTERRUPT_LEVEL.
+//
+// Arguments:
+//
+// AdaptP - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardBlockInterrupts(AdaptP) \
+ NdisRawWritePortUchar((AdaptP)->MappedIoBaseAddr+NIC_INTR_MASK, 0)
+
+
+//++
+//
+// VOID
+// CardUnblockInterrupts(
+// IN PELNKII_ADAPTER AdaptP
+// )
+//
+// Routine Description:
+//
+// Unblocks all interrupts from the card by setting the
+// interrupt mask (IMR) register. Only called from IRQL
+// INTERRUPT_LEVEL.
+//
+// Arguments:
+//
+// AdaptP - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardUnblockInterrupts(AdaptP) \
+ NdisRawWritePortUchar( \
+ (AdaptP)->MappedIoBaseAddr+NIC_INTR_MASK, \
+ (AdaptP)->NicInterruptMask)
+
+
+//++
+//
+// VOID
+// CardDisableReceiveInterrupt(
+// IN PELNKII_ADAPTER AdaptP
+// )
+//
+// Routine Description:
+//
+// Turns off the receive bit in AdaptP->NicInterruptMask.
+// This function is only called when CardBlockInterrupts have
+// been called; it ensures that receive interrupts are not
+// reenabled until CardEnableReceiveInterrupt is called, even
+// if CardUnblockInterrupts is called.
+//
+// Arguments:
+//
+// AdaptP - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardDisableReceiveInterrupt(AdaptP) \
+ (AdaptP)->NicInterruptMask &= (UCHAR)~IMR_RCV
+
+
+//++
+//
+// VOID
+// CardEnableReceiveInterrupt(
+// IN PELNKII_ADAPTER AdaptP
+// )
+//
+// Routine Description:
+//
+// Reenables receive interrupts by setting the receive bit ibn
+// AdaptP->NicInterruptMask, and also writes the new value to
+// the card. Calls SyncCardSetInterruptMask.
+//
+// Arguments:
+//
+// AdaptP - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardEnableReceiveInterrupt(AdaptP) \
+ (AdaptP)->NicInterruptMask |= (UCHAR)IMR_RCV, \
+ NdisSynchronizeWithInterrupt(&(AdaptP)->NdisInterrupt, \
+ SyncCardSetInterruptMask, (PVOID)(AdaptP))
+
+//++
+//
+// VOID
+// CardAcknowledgeReceiveInterrupt(
+// IN PELNKII_ADAPTER AdaptP
+// )
+//
+// Routine Description:
+//
+// Acknowledges a receive interrupt by setting the bit in
+// the interrupt status (ISR) register. Calls
+// SyncCardAcknowledgeReceive.
+//
+// Arguments:
+//
+// AdaptP - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardAcknowledgeReceiveInterrupt(AdaptP) \
+ NdisSynchronizeWithInterrupt(&(AdaptP)->NdisInterrupt, \
+ SyncCardAcknowledgeReceive, (PVOID)(AdaptP))
+
+
+//++
+//
+// VOID
+// CardAcknowledgeOverflowInterrupt(
+// IN PELNKII_ADAPTER AdaptP
+// )
+//
+// Routine Description:
+//
+// Acknowledges an overflow interrupt by setting the bit in
+// the interrupt status (ISR) register. Calls
+// SyncCardAcknowledgeOverflow.
+//
+// Arguments:
+//
+// AdaptP - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardAcknowledgeOverflowInterrupt(AdaptP) \
+ NdisSynchronizeWithInterrupt(&(AdaptP)->NdisInterrupt, \
+ SyncCardAcknowledgeOverflow, (PVOID)(AdaptP))
+
+
+//++
+//
+// VOID
+// CardAcknowledgeTransmitInterrupt(
+// IN PELNKII_ADAPTER AdaptP
+// )
+//
+// Routine Description:
+//
+// Acknowledges a transmit interrupt by setting the bit in
+// the interrupt status (ISR) register. Calls
+// SyncCardAcknowledgeTransmit.
+//
+// Arguments:
+//
+// AdaptP - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardAcknowledgeTransmitInterrupt(AdaptP) \
+ NdisSynchronizeWithInterrupt(&(AdaptP)->NdisInterrupt, \
+ SyncCardAcknowledgeTransmit, (PVOID)(AdaptP))
+
+
+//++
+//
+// VOID
+// CardAcknowledgeCounterInterrupt(
+// IN PELNKII_ADAPTER AdaptP
+// )
+//
+// Routine Description:
+//
+// Acknowledges a counter interrupt by setting the bit in
+// the interrupt status (ISR) register.
+//
+// Arguments:
+//
+// AdaptP - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardAcknowledgeCounterInterrupt(AdaptP) \
+ NdisRawWritePortUchar((AdaptP)->MappedIoBaseAddr+NIC_INTR_STATUS, ISR_COUNTER)
+
+
+//++
+//
+// VOID
+// CardAckAndGetCurrent(
+// IN PELNKII_ADAPTER AdaptP
+// )
+//
+// Routine Description:
+//
+// Performs the function of CardAcknowledgeReceive followed by
+// CardGetCurrent (since the two are always called
+// one after the other). Calls SyncCardAckAndGetCurrent.
+//
+// Arguments:
+//
+// AdaptP - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardAckAndGetCurrent(AdaptP) \
+ NdisSynchronizeWithInterrupt(&(AdaptP)->NdisInterrupt, \
+ SyncCardAckAndGetCurrent, (PVOID)(AdaptP))
+
+
+//++
+//
+// VOID
+// CardGetXmitStatusAndAck(
+// IN PELNKII_ADAPTER AdaptP
+// )
+//
+// Routine Description:
+//
+// Performs the function of CardGetXmitStatus followed by
+// CardAcknowledgeTransmit (since the two are always called
+// one after the other). Calls SyncCardGetXmitStatusAndAck.
+//
+// Arguments:
+//
+// AdaptP - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardGetXmitStatusAndAck(AdaptP) \
+ NdisSynchronizeWithInterrupt(&(AdaptP)->NdisInterrupt, \
+ SyncCardGetXmitStatusAndAck, (PVOID)(AdaptP))
+
+
+//++
+//
+// VOID
+// CardUpdateCounters(
+// IN PELNKII_ADAPTER AdaptP
+// )
+//
+// Routine Description:
+//
+// Updates the values of the three counters (frame alignment
+// errors, CRC errors, and missed packets) by reading in their
+// current values from the card and adding them to the ones
+// stored in the AdaptP structure. Calls SyncCardUpdateCounters.
+//
+// Arguments:
+//
+// AdaptP - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardUpdateCounters(AdaptP) \
+ NdisSynchronizeWithInterrupt(&(AdaptP)->NdisInterrupt, \
+ SyncCardUpdateCounters, (PVOID)(AdaptP))
+
+
+#endif // _ELNKIIHARDWARE_
diff --git a/private/ntos/ndis/elnkii/elnkii.c b/private/ntos/ndis/elnkii/elnkii.c
new file mode 100644
index 000000000..7ba830bc1
--- /dev/null
+++ b/private/ntos/ndis/elnkii/elnkii.c
@@ -0,0 +1,4010 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ elnkii.c
+
+Abstract:
+
+ This is the main file for the Etherlink II
+ Ethernet controller. This driver conforms to the NDIS 3.1 interface.
+
+ The idea for handling loopback and sends simultaneously is largely
+ adapted from the EtherLink II NDIS driver by Adam Barr.
+
+Author:
+
+ Anthony V. Ercolano (Tonye) 20-Jul-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+ Dec 1991 by Sean Selitrennikoff - Modified Elnkii code by AdamBa to
+ fit into the model by TonyE.
+
+--*/
+
+#include <ndis.h>
+#include <efilter.h>
+#include "elnkhrd.h"
+#include "elnksft.h"
+#include "keywords.h"
+
+#if DBG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+
+#if DBG
+
+extern ULONG ElnkiiSendsCompletedForReset;
+ULONG ElnkiiDebugFlag=ELNKII_DEBUG_LOG;
+extern ULONG ElnkiiSendsCompletedForReset;
+
+#endif
+
+//
+// This constant is used for places where NdisAllocateMemory
+// needs to be called and the HighestAcceptableAddress does
+// not matter.
+//
+
+static const NDIS_PHYSICAL_ADDRESS HighestAcceptableMax =
+ NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
+
+
+//
+// The global MAC block.
+//
+
+MAC_BLOCK ElnkiiMacBlock={0};
+
+
+
+//
+// If you add to this, make sure to add the
+// a case in ElnkiiFillInGlobalData() and in
+// ElnkiiQueryGlobalStatistics() if global
+// information only or
+// ElnkiiQueryProtocolStatistics() if it is
+// protocol queriable information.
+//
+STATIC UINT ElnkiiGlobalSupportedOids[] = {
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ OID_802_3_RCV_ERROR_ALIGNMENT,
+ OID_802_3_XMIT_ONE_COLLISION,
+ OID_802_3_XMIT_MORE_COLLISIONS
+ };
+
+//
+// If you add to this, make sure to add the
+// a case in ElnkiiQueryGlobalStatistics() and in
+// ElnkiiQueryProtocolInformation()
+//
+STATIC UINT ElnkiiProtocolSupportedOids[] = {
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE
+ };
+
+
+
+
+
+
+
+
+//
+// Determines whether failing the initial card test will prevent
+// the adapter from being registered.
+//
+
+#ifdef CARD_TEST
+
+BOOLEAN InitialCardTest = TRUE;
+
+#else // CARD_TEST
+
+BOOLEAN InitialCardTest = FALSE;
+
+#endif // CARD_TEST
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+
+#pragma NDIS_INIT_FUNCTION(DriverEntry)
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+
+/*++
+
+Routine Description:
+
+ This is the transfer address of the driver. It initializes
+ ElnkiiMacBlock and calls NdisInitializeWrapper() and
+ NdisRegisterMac().
+
+Arguments:
+
+Return Value:
+
+ Indicates the success or failure of the initialization.
+
+--*/
+
+{
+ NDIS_HANDLE NdisWrapperHandle;
+ PMAC_BLOCK NewMacP = &ElnkiiMacBlock;
+ NDIS_STATUS Status;
+ NDIS_STRING MacName = NDIS_STRING_CONST("Elnkii");
+
+ //
+ // Ensure that the MAC_RESERVED structure will fit in the
+ // MacReserved section of a packet.
+ //
+
+ ASSERT(sizeof(MAC_RESERVED) <= sizeof(((PNDIS_PACKET)NULL)->MacReserved));
+
+
+ //
+ // Pass the wrapper a pointer to the device object.
+ //
+
+ NdisInitializeWrapper(&NdisWrapperHandle,
+ DriverObject,
+ RegistryPath,
+ NULL
+ );
+
+ //
+ // Set up the driver object.
+ //
+
+ NewMacP->DriverObject = DriverObject;
+
+ NdisAllocateSpinLock(&NewMacP->SpinLock);
+
+ NewMacP->NdisWrapperHandle = NdisWrapperHandle;
+ NewMacP->Unloading = FALSE;
+ NewMacP->AdapterQueue = (PELNKII_ADAPTER)NULL;
+
+
+ //
+ // Prepare to call NdisRegisterMac.
+ //
+
+ NewMacP->MacCharacteristics.MajorNdisVersion = ELNKII_NDIS_MAJOR_VERSION;
+ NewMacP->MacCharacteristics.MinorNdisVersion = ELNKII_NDIS_MINOR_VERSION;
+ NewMacP->MacCharacteristics.OpenAdapterHandler = ElnkiiOpenAdapter;
+ NewMacP->MacCharacteristics.CloseAdapterHandler = ElnkiiCloseAdapter;
+ NewMacP->MacCharacteristics.SendHandler = ElnkiiSend;
+ NewMacP->MacCharacteristics.TransferDataHandler = ElnkiiTransferData;
+ NewMacP->MacCharacteristics.ResetHandler = ElnkiiReset;
+ NewMacP->MacCharacteristics.RequestHandler = ElnkiiRequest;
+ NewMacP->MacCharacteristics.QueryGlobalStatisticsHandler =
+ ElnkiiQueryGlobalStatistics;
+ NewMacP->MacCharacteristics.UnloadMacHandler = ElnkiiUnload;
+ NewMacP->MacCharacteristics.AddAdapterHandler = ElnkiiAddAdapter;
+ NewMacP->MacCharacteristics.RemoveAdapterHandler = ElnkiiRemoveAdapter;
+
+ NewMacP->MacCharacteristics.Name = MacName;
+
+ NdisRegisterMac(&Status,
+ &NewMacP->NdisMacHandle,
+ NdisWrapperHandle,
+ (NDIS_HANDLE)&ElnkiiMacBlock,
+ &NewMacP->MacCharacteristics,
+ sizeof(NewMacP->MacCharacteristics));
+
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ //
+ // NdisRegisterMac failed.
+ //
+
+ NdisFreeSpinLock(&NewMacP->SpinLock);
+ NdisTerminateWrapper(NdisWrapperHandle,
+ (PVOID) NULL
+ );
+ IF_LOUD( DbgPrint( "NdisRegisterMac failed with code 0x%x\n", Status );)
+ return Status;
+ }
+
+
+ IF_LOUD( DbgPrint( "NdisRegisterMac succeeded\n" );)
+
+ IF_LOUD( DbgPrint("Adapter Initialization Complete\n");)
+
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+#pragma NDIS_INIT_FUNCTION(ElnkiiAddAdapter)
+
+NDIS_STATUS
+ElnkiiAddAdapter(
+ IN NDIS_HANDLE MacMacContext,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING AdapterName
+ )
+/*++
+Routine Description:
+
+ This is the ElinkII MacAddAdapter routine. The system calls this routine
+ to add support for a particular ElinkII adapter. This routine extracts
+ configuration information from the configuration data base and registers
+ the adapter with NDIS.
+
+Arguments:
+
+ See Ndis3.0 spec...
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS - Adapter was successfully added.
+ NDIS_STATUS_FAILURE - Adapter was not added, also MAC deregistered.
+
+--*/
+{
+ PELNKII_ADAPTER NewAdaptP;
+
+ NDIS_HANDLE ConfigHandle;
+ PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
+ NDIS_STRING IOAddressStr = IOBASE;
+ NDIS_STRING InterruptStr = INTERRUPT;
+ NDIS_STRING MaxMulticastListStr = MAXMULTICAST;
+ NDIS_STRING NetworkAddressStr = NETWORK_ADDRESS;
+ NDIS_STRING MemoryMappedStr = MEMORYMAPPED;
+ NDIS_STRING TransceiverStr = TRANSCEIVER;
+
+#if NDIS2
+ NDIS_STRING EXTERNALStr = NDIS_STRING_CONST("EXTERNAL");
+#endif
+
+ BOOLEAN ConfigError = FALSE;
+ ULONG ConfigErrorValue = 0;
+ ULONG Length;
+ PVOID NetAddress;
+
+ NDIS_STATUS Status;
+
+
+ //
+ // These are used when calling ElnkiiRegisterAdapter.
+ //
+
+ PVOID IoBaseAddr;
+ CCHAR InterruptNumber;
+ BOOLEAN ExternalTransceiver;
+ BOOLEAN MemMapped;
+ UINT MaxMulticastList;
+
+ //
+ // Set default values.
+ //
+
+ IoBaseAddr = DEFAULT_IOBASEADDR;
+ InterruptNumber = DEFAULT_INTERRUPTNUMBER;
+ ExternalTransceiver = DEFAULT_EXTERNALTRANSCEIVER;
+ MemMapped = DEFAULT_MEMMAPPED;
+ MaxMulticastList = DEFAULT_MULTICASTLISTMAX;
+
+ //
+ // Allocate memory for the adapter block now.
+ //
+
+ Status = NdisAllocateMemory( (PVOID *)&NewAdaptP, sizeof(ELNKII_ADAPTER), 0, HighestAcceptableMax);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ return(Status);
+
+ }
+
+ NdisZeroMemory (NewAdaptP,
+ sizeof(ELNKII_ADAPTER)
+ );
+
+ NdisOpenConfiguration(
+ &Status,
+ &ConfigHandle,
+ ConfigurationHandle
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NdisFreeMemory(NewAdaptP, sizeof(ELNKII_ADAPTER), 0);
+
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ //
+ // Read I/O Address
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &IOAddressStr,
+ NdisParameterHexInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ IoBaseAddr = (PVOID)(ReturnedValue->ParameterData.IntegerData);
+
+ }
+
+ //
+ // Confirm value
+ //
+
+ {
+ UCHAR Count;
+
+ static PVOID IoBases[] = { (PVOID)0x2e0, (PVOID)0x2a0,
+ (PVOID)0x280, (PVOID)0x250,
+ (PVOID)0x350, (PVOID)0x330,
+ (PVOID)0x310, (PVOID)0x300 };
+
+ for (Count = 0 ; Count < 8; Count++) {
+
+ if (IoBaseAddr == IoBases[Count]) {
+
+ break;
+
+ }
+
+ }
+
+ if (Count == 8) {
+
+ //
+ // Error
+ //
+
+ ConfigError = TRUE;
+ ConfigErrorValue = (ULONG)IoBaseAddr;
+
+ goto RegisterAdapter;
+ }
+
+ }
+
+
+ //
+ // Read interrupt number
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &InterruptStr,
+ NdisParameterHexInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ InterruptNumber = (CCHAR)(ReturnedValue->ParameterData.IntegerData);
+
+ }
+
+
+ //
+ // Confirm value
+ //
+
+ {
+ UCHAR Count;
+
+ static CCHAR InterruptValues[] = { 2, 3, 4, 5 };
+
+ for (Count = 0 ; Count < 4; Count++) {
+
+ if (InterruptNumber == InterruptValues[Count]) {
+
+ break;
+
+ }
+
+ }
+
+ if (Count == 4) {
+
+ //
+ // Error
+ //
+
+ ConfigError = TRUE;
+ ConfigErrorValue = InterruptNumber;
+
+ goto RegisterAdapter;
+ }
+
+ }
+
+#if !NDIS2
+ //
+ // Read MaxMulticastList
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &MaxMulticastListStr,
+ NdisParameterInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ MaxMulticastList = ReturnedValue->ParameterData.IntegerData;
+
+ }
+#endif
+
+#if NDIS_NT
+ //
+ // Read Memory Mapped
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &MemoryMappedStr,
+ NdisParameterHexInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ MemMapped = (ReturnedValue->ParameterData.IntegerData == 0)?FALSE:TRUE;
+
+ }
+
+#endif
+
+#if NDIS2
+ //
+ // Read Transceiver
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &TransceiverStr,
+ NdisParameterString
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ if (NdisEqualString (&ReturnedValue->ParameterData.StringData, &EXTERNALStr, 1 )) {
+ ExternalTransceiver = TRUE;
+ }
+
+ }
+
+#else // NDIS3
+ //
+ // Read Transceiver
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &TransceiverStr,
+ NdisParameterInteger
+ );
+
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ ExternalTransceiver = (ReturnedValue->ParameterData.IntegerData == 1)?TRUE:FALSE;
+
+ }
+
+#endif
+
+ //
+ // Read net address
+ //
+
+ NdisReadNetworkAddress(
+ &Status,
+ &NetAddress,
+ &Length,
+ ConfigHandle
+ );
+
+ if ((Length == ETH_LENGTH_OF_ADDRESS) && (Status == NDIS_STATUS_SUCCESS)) {
+
+ ETH_COPY_NETWORK_ADDRESS(
+ NewAdaptP->StationAddress,
+ NetAddress
+ );
+
+ }
+
+RegisterAdapter:
+
+ NdisCloseConfiguration(ConfigHandle);
+
+ IF_LOUD( DbgPrint( "Registering adapter # buffers %ld, "
+ "I/O base addr 0x%lx, max opens %ld, interrupt number %ld, "
+ "external %c, memory mapped %c, max multicast %ld\n",
+ DEFAULT_NUMBUFFERS, IoBaseAddr, DEFAULT_MAXOPENS,
+ InterruptNumber,
+ ExternalTransceiver ? 'Y' : 'N',
+ MemMapped ? 'Y' : 'N',
+ DEFAULT_MULTICASTLISTMAX );)
+
+
+
+ //
+ // Set up the parameters.
+ //
+
+ NewAdaptP->NumBuffers = DEFAULT_NUMBUFFERS;
+ NewAdaptP->IoBaseAddr = IoBaseAddr;
+ NewAdaptP->ExternalTransceiver = ExternalTransceiver;
+ NewAdaptP->InterruptNumber = InterruptNumber;
+ NewAdaptP->MemMapped = MemMapped;
+ NewAdaptP->MaxOpens = DEFAULT_MAXOPENS;
+ NewAdaptP->MulticastListMax = MaxMulticastList;
+
+ if (ElnkiiRegisterAdapter(NewAdaptP,
+ ConfigurationHandle,
+ AdapterName,
+ ConfigError,
+ ConfigErrorValue
+ ) != NDIS_STATUS_SUCCESS) {
+
+
+
+ //
+ // ElnkiiRegisterAdapter failed.
+ //
+
+ NdisFreeMemory(NewAdaptP, sizeof(ELNKII_ADAPTER), 0);
+ return NDIS_STATUS_FAILURE;
+ }
+
+
+
+ IF_LOUD( DbgPrint( "ElnkiiRegisterAdapter succeeded\n" );)
+
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+NDIS_STATUS
+ElnkiiRegisterAdapter(
+ IN PELNKII_ADAPTER NewAdaptP,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING AdapterName,
+ IN BOOLEAN ConfigError,
+ IN ULONG ConfigErrorValue
+ )
+
+/*++
+
+Routine Description:
+
+ Called when a new adapter should be registered. It allocates space for
+ the adapter and open blocks, initializes the adapters block, and
+ calls NdisRegisterAdapter().
+
+Arguments:
+
+ NewAdaptP - The adapter structure.
+
+ ConfigurationHandle - Handle passed to MacAddAdapter.
+
+ AdapterName - Pointer to the name for this adapter.
+
+ ConfigError - Was there an error during configuration reading.
+
+ ConfigErrorValue - Value to log if there is an error.
+
+Return Value:
+
+ Indicates the success or failure of the registration.
+
+--*/
+
+{
+ UINT i;
+ BOOLEAN CardPresent, IoBaseCorrect;
+
+ NDIS_STATUS status; //general purpose return from NDIS calls
+ PNDIS_ADAPTER_INFORMATION AdapterInformation; // needed to register adapter
+
+ //
+ // check that NumBuffers <= MAX_XMIT_BUFS
+ //
+
+ if (NewAdaptP->NumBuffers > MAX_XMIT_BUFS) {
+
+ status = NDIS_STATUS_RESOURCES;
+
+ goto fail1;
+
+ }
+
+ NewAdaptP->OpenQueue = (PELNKII_OPEN)NULL;
+ NewAdaptP->CloseQueue = (PELNKII_OPEN)NULL;
+
+ //
+ // The adapter is initialized, register it with NDIS.
+ // This must occur before interrupts are enabled since the
+ // InitializeInterrupt routine requires the NdisAdapterHandle
+ //
+
+ //
+ // Set up the AdapterInformation structure; zero it
+ // first in case it is extended later.
+ //
+
+ status = NdisAllocateMemory( (PVOID *)&AdapterInformation,
+ sizeof(NDIS_ADAPTER_INFORMATION) +
+ sizeof(NDIS_PORT_DESCRIPTOR),
+ 0,
+ HighestAcceptableMax
+ );
+
+ if (status != NDIS_STATUS_SUCCESS) {
+
+ return(status);
+
+ }
+
+ NdisZeroMemory (AdapterInformation,
+ sizeof(NDIS_ADAPTER_INFORMATION) +
+ sizeof(NDIS_PORT_DESCRIPTOR)
+ );
+
+ AdapterInformation->AdapterType = NdisInterfaceIsa;
+ AdapterInformation->NumberOfPortDescriptors = 2;
+ AdapterInformation->PortDescriptors[0].InitialPort = (ULONG)NewAdaptP->IoBaseAddr;
+ AdapterInformation->PortDescriptors[0].NumberOfPorts = 0x10;
+ AdapterInformation->PortDescriptors[0].PortOffset = (PVOID *)(&(NewAdaptP->MappedIoBaseAddr));
+ AdapterInformation->PortDescriptors[1].InitialPort = (ULONG)NewAdaptP->IoBaseAddr + 0x400;
+ AdapterInformation->PortDescriptors[1].NumberOfPorts = 0x10;
+ AdapterInformation->PortDescriptors[1].PortOffset = (PVOID *)(&(NewAdaptP->MappedGaBaseAddr));
+
+
+ if ((status = NdisRegisterAdapter(&NewAdaptP->NdisAdapterHandle,
+ ElnkiiMacBlock.NdisMacHandle,
+ (NDIS_HANDLE)NewAdaptP,
+ ConfigurationHandle,
+ AdapterName,
+ AdapterInformation))
+ != NDIS_STATUS_SUCCESS) {
+
+ //
+ // NdisRegisterAdapter failed.
+ //
+
+
+ NdisFreeMemory(AdapterInformation,
+ sizeof(NDIS_ADAPTER_INFORMATION) +
+ sizeof(NDIS_PORT_DESCRIPTOR),
+ 0
+ );
+
+ goto fail2;
+ }
+
+ NdisFreeMemory(AdapterInformation,
+ sizeof(NDIS_ADAPTER_INFORMATION) +
+ sizeof(NDIS_PORT_DESCRIPTOR),
+ 0
+ );
+
+ //
+ // Allocate the Spin lock.
+ //
+ NdisAllocateSpinLock(&NewAdaptP->Lock);
+
+ if (ConfigError) {
+
+ //
+ // Log Error and exit.
+ //
+
+ NdisWriteErrorLogEntry(
+ NewAdaptP->NdisAdapterHandle,
+ NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
+ 1,
+ ConfigErrorValue
+ );
+
+ goto fail3;
+
+ }
+
+ //
+ // Initialize Pending information
+ //
+ NewAdaptP->PendQueue = (PELNKII_PEND_DATA)NULL;
+ NewAdaptP->PendQTail = (PELNKII_PEND_DATA)NULL;
+ NewAdaptP->PendOp = (PELNKII_PEND_DATA)NULL;
+ NewAdaptP->DeferredDpc = (PVOID)HandlePendingOperations;
+
+ //
+ // Initialize References.
+ //
+ NewAdaptP->References = 0;
+
+ NdisInitializeTimer(&(NewAdaptP->DeferredTimer),
+ NewAdaptP->DeferredDpc,
+ NewAdaptP);
+
+ //
+ // Map the memory mapped portion of the card.
+ //
+ // If NewAdaptP->MemMapped is FALSE, CardGetMemBaseAddr will not
+ // return the actual MemBaseAddr, but it will still return
+ // CardPresent and IoBaseCorrect.
+ //
+ //
+
+ NewAdaptP->MemBaseAddr = CardGetMemBaseAddr(NewAdaptP,
+ &CardPresent,
+ &IoBaseCorrect
+ );
+
+ if (!CardPresent) {
+
+ //
+ // The card does not seem to be there, fail silently.
+ //
+
+ NdisWriteErrorLogEntry(
+ NewAdaptP->NdisAdapterHandle,
+ NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
+ 0
+ );
+
+ status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+
+ goto fail3;
+
+ }
+
+ if (!IoBaseCorrect) {
+
+ //
+ // The card is there, but the I/O base address jumper
+ // is not where we expect it to be.
+ //
+
+
+ NdisWriteErrorLogEntry(
+ NewAdaptP->NdisAdapterHandle,
+ NDIS_ERROR_CODE_BAD_IO_BASE_ADDRESS,
+ 0
+ );
+
+ status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+
+ goto fail3;
+
+ }
+
+ if (NewAdaptP->MemMapped && (NewAdaptP->MemBaseAddr == NULL)) {
+
+ //
+ // The card appears to not be mapped.
+ //
+
+ NewAdaptP->MemMapped = FALSE;
+
+ }
+
+ //
+ // For memory-mapped operation, map the card's transmit/receive
+ // area into memory space. For programmed I/O, we will refer
+ // to transmit/receive memory in terms of offsets in the
+ // card's 32K address space; for an 8K card this is always
+ // the second 8K piece, starting at 0x2000.
+ //
+
+ if (NewAdaptP->MemMapped) {
+
+ NDIS_PHYSICAL_ADDRESS PhysicalAddress;
+
+ NdisSetPhysicalAddressHigh(PhysicalAddress, 0);
+ NdisSetPhysicalAddressLow(PhysicalAddress, (ULONG)(NewAdaptP->MemBaseAddr));
+
+ NdisMapIoSpace(
+ &status,
+ (PVOID *)(&NewAdaptP->XmitStart),
+ NewAdaptP->NdisAdapterHandle,
+ PhysicalAddress,
+ 0x2000);
+
+ if (status != NDIS_STATUS_SUCCESS) {
+
+ NdisWriteErrorLogEntry(
+ NewAdaptP->NdisAdapterHandle,
+ NDIS_ERROR_CODE_RESOURCE_CONFLICT,
+ 0
+ );
+
+ goto fail3;
+
+ }
+
+ } else {
+
+ NewAdaptP->XmitStart = (PUCHAR)0x2000;
+
+ }
+
+
+ //
+ // For the NicXXX fields, always use the addressing system
+ // starting at 0x2000 (or 0x20, since they contain the MSB only).
+ //
+
+ NewAdaptP->NicXmitStart = 0x20;
+
+
+ //
+ // The start of the receive space.
+ //
+
+ NewAdaptP->PageStart = NewAdaptP->XmitStart +
+ (NewAdaptP->NumBuffers * TX_BUF_SIZE);
+
+ NewAdaptP->NicPageStart = NewAdaptP->NicXmitStart +
+ (UCHAR)(NewAdaptP->NumBuffers * BUFS_PER_TX);
+
+
+ //
+ // The end of the receive space.
+ //
+
+ NewAdaptP->PageStop = NewAdaptP->XmitStart + 0x2000;
+ NewAdaptP->NicPageStop = NewAdaptP->NicXmitStart + (UCHAR)0x20;
+
+
+
+ //
+ // Initialize the receive variables.
+ //
+
+ NewAdaptP->NicReceiveConfig = RCR_REJECT_ERR;
+ NewAdaptP->ReceiveInProgress = FALSE;
+
+ //
+ // Initialize the transmit buffer control.
+ //
+
+ NewAdaptP->CurBufXmitting = -1;
+ NewAdaptP->TransmitInterruptPending = FALSE;
+ NewAdaptP->BufferOverflow = FALSE;
+ NewAdaptP->OverflowRestartXmitDpc = FALSE;
+
+ for (i=0; i<NewAdaptP->NumBuffers; i++) {
+
+ NewAdaptP->BufferStatus[i] = EMPTY;
+
+ }
+
+ NewAdaptP->ResetInProgress = FALSE;
+ NewAdaptP->TransmitInterruptPending = FALSE;
+
+ NewAdaptP->WakeUpFoundTransmit = FALSE;
+
+ //
+ // Clear Interrupt Information
+ //
+
+ NewAdaptP->ElnkiiHandleXmitCompleteRunning = FALSE;
+
+
+ //
+ // The transmit and loopback queues start out empty.
+ //
+ // Already done since structure is zero'd out.
+ //
+
+ //
+ // Clear the tally counters.
+ //
+ // Already done since structure is zero'd out.
+ //
+
+ //
+ // Read the Ethernet address off of the PROM.
+ //
+
+ CardReadEthernetAddress(NewAdaptP);
+
+
+ //
+ // Initialize Filter Database
+ //
+ if (!EthCreateFilter( NewAdaptP->MulticastListMax,
+ ElnkiiChangeMulticastAddresses,
+ ElnkiiChangeFilterClasses,
+ ElnkiiCloseAction,
+ NewAdaptP->StationAddress,
+ &NewAdaptP->Lock,
+ &NewAdaptP->FilterDB
+ )) {
+
+
+ NdisWriteErrorLogEntry(
+ NewAdaptP->NdisAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+
+ status = NDIS_STATUS_FAILURE;
+
+ goto fail4;
+
+ }
+
+ //
+ // Now initialize the NIC and Gate Array registers.
+ //
+
+ NewAdaptP->NicInterruptMask =
+ IMR_RCV | IMR_XMIT | IMR_XMIT_ERR | IMR_OVERFLOW;
+
+
+ //
+ // Link us on to the chain of adapters for this MAC.
+ //
+
+ NewAdaptP->MacBlock = &ElnkiiMacBlock;
+
+ NdisAcquireSpinLock(&ElnkiiMacBlock.SpinLock);
+
+ NewAdaptP->NextAdapter = ElnkiiMacBlock.AdapterQueue;
+ ElnkiiMacBlock.AdapterQueue = NewAdaptP;
+
+ NdisReleaseSpinLock(&ElnkiiMacBlock.SpinLock);
+
+ //
+ // Turn Off the card.
+ //
+
+ SyncCardStop(NewAdaptP);
+
+ //
+ // Set flag to ignore interrupts
+ //
+
+ NewAdaptP->InCardTest = TRUE;
+
+ //
+ // Connect to interrupt
+ //
+
+ NdisInitializeInterrupt(&status, // status of call
+ &NewAdaptP->NdisInterrupt, // interrupt info str
+ NewAdaptP->NdisAdapterHandle, // NDIS adapter handle
+ ElnkiiInterruptHandler, // ptr to ISR
+ NewAdaptP, // context for ISR, DPC
+ ElnkiiInterruptDpc, // ptr to int DPC
+ NewAdaptP->InterruptNumber, // vector
+ NewAdaptP->InterruptNumber, // level
+ FALSE, // NOT shared
+ NdisInterruptLatched // InterruptMode
+ );
+
+ if (status != NDIS_STATUS_SUCCESS) {
+
+ //
+ // The NIC could not be written to.
+ //
+
+ NdisWriteErrorLogEntry(
+ NewAdaptP->NdisAdapterHandle,
+ NDIS_ERROR_CODE_INTERRUPT_CONNECT,
+ 0
+ );
+
+ goto fail6;
+
+ }
+
+ if (!CardSetup(NewAdaptP)) {
+
+ //
+ // The NIC could not be written to.
+ //
+
+ NdisWriteErrorLogEntry(
+ NewAdaptP->NdisAdapterHandle,
+ NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
+ 0
+ );
+
+ status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+
+ goto fail7;
+ }
+
+
+ //
+ // Perform card tests.
+ //
+
+ if (!CardTest(NewAdaptP)) {
+
+ //
+ // The tests failed, InitialCardTest determines whether
+ // this causes the whole initialization to fail.
+ //
+
+ if (InitialCardTest) {
+
+ NdisWriteErrorLogEntry(
+ NewAdaptP->NdisAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 0
+ );
+
+ status = NDIS_STATUS_DEVICE_FAILED;
+
+ goto fail7;
+
+ }
+
+ }
+
+ //
+ // Normal mode now
+ //
+
+ NewAdaptP->InCardTest = FALSE;
+
+ NdisInitializeTimer(&NewAdaptP->InterruptTimer,
+ (PVOID)ElnkiiInterruptDpc,
+ NewAdaptP
+ );
+
+ //
+ // Initialize the wake up timer to catch transmits that
+ // don't interrupt when complete. It fires continuously
+ // every two seconds, and we check if there are any
+ // uncompleted sends from the previous two-second
+ // period.
+ //
+
+ NewAdaptP->WakeUpDpc = (PVOID)ElnkiiWakeUpDpc;
+
+ NdisInitializeTimer(&NewAdaptP->WakeUpTimer,
+ (PVOID)(NewAdaptP->WakeUpDpc),
+ NewAdaptP );
+
+ NdisSetTimer(
+ &NewAdaptP->WakeUpTimer,
+ 2000
+ );
+
+ NewAdaptP->Removed = FALSE;
+
+ IF_LOUD( DbgPrint("Interrupt Connected\n");)
+
+
+ //
+ // Initialization completed successfully.
+ //
+
+ IF_LOUD( DbgPrint(" [ Elnkii ] : OK");)
+
+ return NDIS_STATUS_SUCCESS;
+
+
+
+ //
+ // Code to unwind what has already been set up when a part of
+ // initialization fails, which is jumped into at various
+ // points based on where the failure occured. Jumping to
+ // a higher-numbered failure point will execute the code
+ // for that block and all lower-numbered ones.
+ //
+
+fail7:
+ NdisRemoveInterrupt(&NewAdaptP->NdisInterrupt);
+
+fail6:
+ NdisAcquireSpinLock(&ElnkiiMacBlock.SpinLock);
+
+ //
+ // Take us out of the AdapterQueue.
+ //
+
+ if (ElnkiiMacBlock.AdapterQueue == NewAdaptP) {
+
+ ElnkiiMacBlock.AdapterQueue = NewAdaptP->NextAdapter;
+
+ } else {
+
+ PELNKII_ADAPTER TmpAdaptP = ElnkiiMacBlock.AdapterQueue;
+
+ while (TmpAdaptP->NextAdapter != NewAdaptP) {
+
+ TmpAdaptP = TmpAdaptP->NextAdapter;
+
+ }
+
+ TmpAdaptP->NextAdapter = TmpAdaptP->NextAdapter->NextAdapter;
+ }
+
+ NdisReleaseSpinLock(&ElnkiiMacBlock.SpinLock);
+
+ EthDeleteFilter(NewAdaptP->FilterDB);
+
+fail4:
+
+ //
+ // We already enabled the interrupt on the card, so
+ // turn it off.
+ //
+
+ NdisRawWritePortUchar(NewAdaptP->MappedGaBaseAddr+GA_INT_DMA_CONFIG, 0x00);
+
+ if (NewAdaptP->MemMapped) {
+
+ NdisUnmapIoSpace(
+ NewAdaptP->NdisAdapterHandle,
+ NewAdaptP->XmitStart,
+ 0x2000);
+
+ }
+
+fail3:
+ NdisDeregisterAdapter(NewAdaptP->NdisAdapterHandle);
+ NdisFreeSpinLock(&NewAdaptP->Lock);
+
+fail2:
+
+fail1:
+
+ return status;
+}
+
+
+NDIS_STATUS
+ElnkiiOpenAdapter(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT NDIS_HANDLE * MacBindingHandle,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_HANDLE MacAdapterContext,
+ IN UINT OpenOptions,
+ IN PSTRING AddressingInformation OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ NDIS function. It initializes the open block and links it in
+ the appropriate lists.
+
+Arguments:
+
+ See NDIS 3.0 spec.
+
+--*/
+
+{
+ PELNKII_ADAPTER AdaptP = ((PELNKII_ADAPTER)MacAdapterContext);
+ PELNKII_OPEN NewOpenP;
+ NDIS_STATUS Status;
+
+ //
+ // Don't use extended error or OpenOptions for Elnkii
+ //
+
+ UNREFERENCED_PARAMETER(OpenOptions);
+
+ *OpenErrorStatus=NDIS_STATUS_SUCCESS;
+
+ IF_LOUD( DbgPrint("In Open Adapter\n");)
+
+ //
+ // Scan the media list for our media type (802.3)
+ //
+
+ *SelectedMediumIndex = (UINT)-1;
+
+ while (MediumArraySize > 0) {
+
+ if (MediumArray[--MediumArraySize] == NdisMedium802_3 ) {
+
+ *SelectedMediumIndex = MediumArraySize;
+
+ break;
+ }
+ }
+
+
+ if (*SelectedMediumIndex == -1) {
+
+ return NDIS_STATUS_UNSUPPORTED_MEDIA;
+
+ }
+
+ //
+ // Allocate memory for the open.
+ //
+
+
+ Status = NdisAllocateMemory((PVOID *)&NewOpenP, sizeof(ELNKII_OPEN), 0, HighestAcceptableMax);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NdisWriteErrorLogEntry(
+ AdaptP->NdisAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+
+ return(NDIS_STATUS_RESOURCES);
+
+ }
+
+ NdisZeroMemory(NewOpenP, sizeof(ELNKII_OPEN));
+
+ //
+ // Link this open to the appropriate lists.
+ //
+
+ NdisAcquireSpinLock(&AdaptP->Lock);
+
+ AdaptP->References++;
+
+ if ((AdaptP->OpenQueue == NULL) && (AdaptP->CloseQueue == NULL)) {
+
+ //
+ // The first open on this adapter.
+ //
+
+ CardStart(AdaptP);
+
+ }
+
+ NewOpenP->NextOpen = AdaptP->OpenQueue;
+ AdaptP->OpenQueue = NewOpenP;
+
+ if (AdaptP->ResetInProgress || !EthNoteFilterOpenAdapter(
+ AdaptP->FilterDB,
+ NewOpenP,
+ NdisBindingContext,
+ &NewOpenP->NdisFilterHandle
+ )) {
+
+ AdaptP->References--;
+
+ AdaptP->OpenQueue = NewOpenP->NextOpen;
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+ NdisFreeMemory(NewOpenP, sizeof(ELNKII_OPEN), 0);
+
+ NdisWriteErrorLogEntry(
+ AdaptP->NdisAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ //
+ // Set up the open block.
+ //
+
+ NewOpenP->Adapter = AdaptP;
+ NewOpenP->MacBlock = AdaptP->MacBlock;
+ NewOpenP->NdisBindingContext = NdisBindingContext;
+ NewOpenP->AddressingInformation = AddressingInformation;
+
+ //
+ // set the Request Queue empty
+ //
+
+
+ NewOpenP->Closing = FALSE;
+ NewOpenP->LookAhead = ELNKII_MAX_LOOKAHEAD;
+
+ AdaptP->MaxLookAhead = ELNKII_MAX_LOOKAHEAD;
+
+ NewOpenP->ReferenceCount = 1;
+
+ *MacBindingHandle = (NDIS_HANDLE)NewOpenP;
+
+ ELNKII_DO_DEFERRED(AdaptP);
+
+ IF_LOUD( DbgPrint("Out Open Adapter\n");)
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+VOID
+ElnkiiAdjustMaxLookAhead(
+ IN PELNKII_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine finds the open with the maximum lookahead value and
+ stores that in the adapter block.
+
+Arguments:
+
+ Adapter - A pointer to the adapter block.
+
+Returns:
+
+ None.
+
+--*/
+{
+ ULONG CurrentMax = 0;
+ PELNKII_OPEN CurrentOpen;
+
+ CurrentOpen = Adapter->OpenQueue;
+
+ while (CurrentOpen != NULL) {
+
+ if (CurrentOpen->LookAhead > CurrentMax) {
+
+ CurrentMax = CurrentOpen->LookAhead;
+
+ }
+
+ CurrentOpen = CurrentOpen->NextOpen;
+ }
+
+ if (CurrentMax == 0) {
+
+ CurrentMax = ELNKII_MAX_LOOKAHEAD;
+
+ }
+
+ Adapter->MaxLookAhead = CurrentMax;
+
+}
+
+NDIS_STATUS
+ElnkiiCloseAdapter(
+ IN NDIS_HANDLE MacBindingHandle
+ )
+
+/*++
+
+Routine Description:
+
+ NDIS function. Unlinks the open block and frees it.
+
+Arguments:
+
+ See NDIS 3.0 spec.
+
+--*/
+
+{
+ PELNKII_OPEN OpenP = ((PELNKII_OPEN)MacBindingHandle);
+ PELNKII_ADAPTER AdaptP = OpenP->Adapter;
+ PELNKII_OPEN TmpOpenP;
+ NDIS_STATUS StatusToReturn;
+
+ NdisAcquireSpinLock(&AdaptP->Lock);
+
+ if (OpenP->Closing) {
+
+ //
+ // The open is already being closed.
+ //
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+ return NDIS_STATUS_CLOSING;
+ }
+
+ AdaptP->References++;
+
+ OpenP->ReferenceCount++;
+
+ //
+ // Remove this open from the list for this adapter.
+ //
+
+ if (OpenP == AdaptP->OpenQueue) {
+
+ AdaptP->OpenQueue = OpenP->NextOpen;
+
+ } else {
+
+ TmpOpenP = AdaptP->OpenQueue;
+
+ while (TmpOpenP->NextOpen != OpenP) {
+
+ TmpOpenP = TmpOpenP->NextOpen;
+
+ }
+
+ TmpOpenP->NextOpen = OpenP->NextOpen;
+ }
+
+ //
+ // Remove from Filter package to block all receives.
+ //
+
+ StatusToReturn = EthDeleteFilterOpenAdapter(
+ AdaptP->FilterDB,
+ OpenP->NdisFilterHandle,
+ NULL
+ );
+
+ //
+ // If the status is successful that merely implies that
+ // we were able to delete the reference to the open binding
+ // from the filtering code. If we have a successful status
+ // at this point we still need to check whether the reference
+ // count to determine whether we can close.
+ //
+ //
+ // The delete filter routine can return a "special" status
+ // that indicates that there is a current NdisIndicateReceive
+ // on this binding. See below.
+ //
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS) {
+
+ //
+ // Check whether the reference count is two. If
+ // it is then we can get rid of the memory for
+ // this open.
+ //
+ // A count of two indicates one for this routine
+ // and one for the filter which we *know* we can
+ // get rid of.
+ //
+
+ if (OpenP->ReferenceCount != 2) {
+
+ //
+ // We are not the only reference to the open. Remove
+ // it from the open list and delete the memory.
+ //
+
+
+ OpenP->Closing = TRUE;
+
+ //
+ // Account for this routines reference to the open
+ // as well as reference because of the original open.
+ //
+
+ OpenP->ReferenceCount -= 2;
+
+ //
+ // Change the status to indicate that we will
+ // be closing this later.
+ //
+
+ StatusToReturn = NDIS_STATUS_PENDING;
+
+ } else {
+
+ OpenP->ReferenceCount -= 2;
+
+ }
+
+ } else if (StatusToReturn == NDIS_STATUS_PENDING) {
+
+ OpenP->Closing = TRUE;
+
+ //
+ // Account for this routines reference to the open
+ // as well as reference because of the original open.
+ //
+
+ OpenP->ReferenceCount -= 2;
+
+ } else if (StatusToReturn == NDIS_STATUS_CLOSING_INDICATING) {
+
+ //
+ // When we have this status it indicates that the filtering
+ // code was currently doing an NdisIndicateReceive. It
+ // would not be wise to delete the memory for the open at
+ // this point. The filtering code will call our close action
+ // routine upon return from NdisIndicateReceive and that
+ // action routine will decrement the reference count for
+ // the open.
+ //
+
+ OpenP->Closing = TRUE;
+
+ //
+ // This status is private to the filtering routine. Just
+ // tell the caller the the close is pending.
+ //
+
+ StatusToReturn = NDIS_STATUS_PENDING;
+
+ //
+ // Account for this routines reference to the open.
+ //
+
+ OpenP->ReferenceCount--;
+
+ } else {
+
+ //
+ // Account for this routines reference to the open.
+ //
+
+ OpenP->ReferenceCount--;
+
+ }
+
+ //
+ // See if this is the last reference to this open.
+ //
+
+ if (OpenP->ReferenceCount == 0) {
+
+ //
+ // Check if the MaxLookAhead needs adjustment.
+ //
+
+ if (OpenP->LookAhead == AdaptP->MaxLookAhead) {
+
+ ElnkiiAdjustMaxLookAhead(AdaptP);
+
+ }
+
+ //
+ // Done, free the open.
+ //
+
+ NdisFreeMemory(OpenP, sizeof(ELNKII_OPEN), 0);
+
+ if ((AdaptP->OpenQueue == NULL ) && (AdaptP->CloseQueue == NULL)) {
+
+ //
+ // We can disable the card.
+ //
+
+ CardStop(AdaptP);
+
+ }
+
+ } else {
+
+ //
+ // Add it to the close list
+ //
+
+ OpenP->NextOpen = AdaptP->CloseQueue;
+ AdaptP->CloseQueue = OpenP;
+
+ //
+ // Will get removed when count drops to zero.
+ //
+
+ StatusToReturn = NDIS_STATUS_PENDING;
+
+ }
+
+
+ ELNKII_DO_DEFERRED(AdaptP);
+
+ return(StatusToReturn);
+
+}
+
+NDIS_STATUS
+ElnkiiRequest(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allows a protocol to query and set information
+ about the MAC.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to PELNKII_OPEN.
+
+ NdisRequest - A structure which contains the request type (Set or
+ Query), an array of operations to perform, and an array for holding
+ the results of the operations.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ PELNKII_OPEN Open = (PELNKII_OPEN)(MacBindingHandle);
+ PELNKII_ADAPTER Adapter = (Open->Adapter);
+
+ IF_LOUD( DbgPrint("In Request\n");)
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ //
+ // Ensure that the open does not close while in this function.
+ //
+
+ Open->ReferenceCount++;
+
+ Adapter->References++;
+
+ //
+ // Process request
+ //
+
+ if (Open->Closing) {
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ StatusToReturn = NDIS_STATUS_CLOSING;
+
+ } else if (NdisRequest->RequestType == NdisRequestQueryInformation) {
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ StatusToReturn = ElnkiiQueryInformation(Adapter, Open, NdisRequest);
+
+ } else if (NdisRequest->RequestType == NdisRequestSetInformation) {
+
+
+ //
+ // Make sure Adapter is in a valid state.
+ //
+
+ //
+ // All requests are rejected during a reset.
+ //
+
+ if (Adapter->ResetInProgress) {
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ } else {
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ StatusToReturn = ElnkiiSetInformation(Adapter,Open,NdisRequest);
+
+ }
+
+ } else {
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ StatusToReturn = NDIS_STATUS_NOT_RECOGNIZED;
+
+ }
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ --Open->ReferenceCount;
+
+ ELNKII_DO_DEFERRED(Adapter);
+
+ IF_LOUD( DbgPrint("Out Request\n");)
+
+ return(StatusToReturn);
+
+}
+
+NDIS_STATUS
+ElnkiiQueryProtocolInformation(
+ IN PELNKII_ADAPTER Adapter,
+ IN PELNKII_OPEN Open,
+ IN NDIS_OID Oid,
+ IN BOOLEAN GlobalMode,
+ IN PVOID InfoBuffer,
+ IN UINT BytesLeft,
+ OUT PUINT BytesNeeded,
+ OUT PUINT BytesWritten
+)
+
+/*++
+
+Routine Description:
+
+ The ElnkiiQueryProtocolInformation process a Query request for
+ NDIS_OIDs that are specific to a binding about the MAC. Note that
+ some of the OIDs that are specific to bindings are also queryable
+ on a global basis. Rather than recreate this code to handle the
+ global queries, I use a flag to indicate if this is a query for the
+ global data or the binding specific data.
+
+Arguments:
+
+ Adapter - a pointer to the adapter.
+
+ Open - a pointer to the open instance.
+
+ Oid - the NDIS_OID to process.
+
+ GlobalMode - Some of the binding specific information is also used
+ when querying global statistics. This is a flag to specify whether
+ to return the global value, or the binding specific value.
+
+ PlaceInInfoBuffer - a pointer into the NdisRequest->InformationBuffer
+ into which store the result of the query.
+
+ BytesLeft - the number of bytes left in the InformationBuffer.
+
+ BytesNeeded - If there is not enough room in the information buffer
+ then this will contain the number of bytes needed to complete the
+ request.
+
+ BytesWritten - a pointer to the number of bytes written into the
+ InformationBuffer.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NDIS_MEDIUM Medium = NdisMedium802_3;
+ ULONG GenericULong;
+ USHORT GenericUShort;
+ UCHAR GenericArray[6];
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ //
+ // Common variables for pointing to result of query
+ //
+
+ PVOID MoveSource = (PVOID)(&GenericULong);
+ ULONG MoveBytes = sizeof(GenericULong);
+ UINT Filter;
+
+ NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady;
+
+ //
+ // General Algorithm:
+ //
+ // Switch(Request)
+ // Get requested information
+ // Store results in a common variable.
+ // Copy result in common variable to result buffer.
+ //
+
+ //
+ // Make sure that ulong is 4 bytes. Else GenericULong must change
+ // to something of size 4.
+ //
+ ASSERT(sizeof(ULONG) == 4);
+
+ IF_LOUD( DbgPrint("In QueryProtocol\n");)
+
+ //
+ // Make sure no changes occur while processing.
+ //
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ //
+ // Switch on request type
+ //
+
+ switch (Oid) {
+
+ case OID_GEN_MAC_OPTIONS:
+
+ GenericULong = (ULONG)(NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
+ NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
+ NDIS_MAC_OPTION_NO_LOOPBACK
+ );
+
+ if (!Adapter->MemMapped) {
+
+ GenericULong |= NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA;
+
+ }
+
+ break;
+
+ case OID_GEN_SUPPORTED_LIST:
+
+ if (!GlobalMode) {
+
+ MoveSource = (PVOID)(ElnkiiProtocolSupportedOids);
+ MoveBytes = sizeof(ElnkiiProtocolSupportedOids);
+
+ } else {
+
+ MoveSource = (PVOID)(ElnkiiGlobalSupportedOids);
+ MoveBytes = sizeof(ElnkiiGlobalSupportedOids);
+
+ }
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+
+
+ if (Adapter->ResetInProgress) {
+
+ HardwareStatus = NdisHardwareStatusReset;
+
+ } else
+ HardwareStatus = NdisHardwareStatusReady;
+
+
+ MoveSource = (PVOID)(&HardwareStatus);
+ MoveBytes = sizeof(NDIS_HARDWARE_STATUS);
+
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+
+ MoveSource = (PVOID) (&Medium);
+ MoveBytes = sizeof(NDIS_MEDIUM);
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+
+ GenericULong = ELNKII_MAX_LOOKAHEAD;
+
+ break;
+
+
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+
+ GenericULong = (ULONG)(1514 - ELNKII_HEADER_SIZE);
+
+ break;
+
+
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+
+ GenericULong = (ULONG)(1514);
+
+ break;
+
+
+ case OID_GEN_LINK_SPEED:
+
+ GenericULong = (ULONG)(100000);
+
+ break;
+
+
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+
+ GenericULong = (ULONG)(Adapter->NumBuffers * TX_BUF_SIZE);
+
+ break;
+
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+
+ GenericULong = (ULONG)0x2000;
+ GenericULong -= (Adapter->NumBuffers * ((TX_BUF_SIZE / 256) + 1) * 256);
+
+ //
+ // Subtract off receive buffer overhead
+ //
+ {
+ ULONG TmpUlong = GenericULong / 256;
+
+ TmpUlong *= 4;
+
+ GenericULong -= TmpUlong;
+
+ }
+
+ //
+ // Round to nearest 256 bytes
+ //
+ GenericULong = (GenericULong / 256) * 256;
+
+ break;
+
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+
+ GenericULong = (ULONG)(TX_BUF_SIZE);
+
+ break;
+
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+
+ GenericULong = (ULONG)(256);
+
+ break;
+
+ case OID_GEN_VENDOR_ID:
+
+ NdisMoveMemory(
+ (PVOID)(&GenericULong),
+ Adapter->PermanentAddress,
+ 3
+ );
+
+ GenericULong &= 0xFFFFFF00;
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+
+ MoveSource = (PVOID)"Etherlink II Adapter.";
+ MoveBytes = 22;
+
+ break;
+
+ case OID_GEN_DRIVER_VERSION:
+
+ GenericUShort = ((USHORT)ELNKII_NDIS_MAJOR_VERSION << 8) |
+ ELNKII_NDIS_MINOR_VERSION;
+
+ MoveSource = (PVOID)(&GenericUShort);
+ MoveBytes = sizeof(GenericUShort);
+ break;
+
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ if (GlobalMode) {
+
+ Filter = ETH_QUERY_FILTER_CLASSES(Adapter->FilterDB);
+
+ GenericULong = (ULONG)(Filter);
+
+ } else {
+
+ Filter = ETH_QUERY_PACKET_FILTER(Adapter->FilterDB,
+ Open->NdisFilterHandle);
+
+ GenericULong = (ULONG)(Filter);
+
+ }
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ if ( GlobalMode ) {
+
+ GenericULong = (ULONG)(Adapter->MaxLookAhead);
+
+ } else {
+
+ GenericULong = Open->LookAhead;
+
+ }
+
+ break;
+
+ case OID_802_3_PERMANENT_ADDRESS:
+ ELNKII_MOVE_MEM((PCHAR)GenericArray,
+ Adapter->PermanentAddress,
+ ETH_LENGTH_OF_ADDRESS);
+
+ MoveSource = (PVOID)(GenericArray);
+ MoveBytes = sizeof(Adapter->PermanentAddress);
+ break;
+
+
+ case OID_802_3_CURRENT_ADDRESS:
+
+ ELNKII_MOVE_MEM((PCHAR)GenericArray,
+ Adapter->StationAddress,
+ ETH_LENGTH_OF_ADDRESS);
+
+ MoveSource = (PVOID)(GenericArray);
+ MoveBytes = sizeof(Adapter->StationAddress);
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+
+ {
+ UINT NumAddresses;
+
+
+ if (GlobalMode) {
+
+ NumAddresses = ETH_NUMBER_OF_GLOBAL_FILTER_ADDRESSES(Adapter->FilterDB);
+
+ if ((NumAddresses * ETH_LENGTH_OF_ADDRESS) > BytesLeft) {
+
+ *BytesNeeded = (NumAddresses * ETH_LENGTH_OF_ADDRESS);
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ break;
+
+ }
+
+ EthQueryGlobalFilterAddresses(
+ &StatusToReturn,
+ Adapter->FilterDB,
+ BytesLeft,
+ &NumAddresses,
+ InfoBuffer
+ );
+
+ *BytesWritten = NumAddresses * ETH_LENGTH_OF_ADDRESS;
+
+ //
+ // Should not be an error since we held the spinlock
+ // nothing should have changed.
+ //
+
+ ASSERT(StatusToReturn == NDIS_STATUS_SUCCESS);
+
+ } else {
+
+ NumAddresses = EthNumberOfOpenFilterAddresses(
+ Adapter->FilterDB,
+ Open->NdisFilterHandle
+ );
+
+ if ((NumAddresses * ETH_LENGTH_OF_ADDRESS) > BytesLeft) {
+
+ *BytesNeeded = (NumAddresses * ETH_LENGTH_OF_ADDRESS);
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ break;
+
+ }
+
+ EthQueryOpenFilterAddresses(
+ &StatusToReturn,
+ Adapter->FilterDB,
+ Open->NdisFilterHandle,
+ BytesLeft,
+ &NumAddresses,
+ InfoBuffer
+ );
+
+ //
+ // Should not be an error since we held the spinlock
+ // nothing should have changed.
+ //
+
+ ASSERT(StatusToReturn == NDIS_STATUS_SUCCESS);
+
+ *BytesWritten = NumAddresses * ETH_LENGTH_OF_ADDRESS;
+
+ }
+
+ }
+
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+
+ GenericULong = (ULONG) (Adapter->MulticastListMax);
+
+ break;
+
+
+
+ default:
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if ((StatusToReturn == NDIS_STATUS_SUCCESS) &&
+ (Oid != OID_802_3_MULTICAST_LIST)) {
+
+ if (MoveBytes > BytesLeft) {
+
+ //
+ // Not enough room in InformationBuffer. Punt
+ //
+
+ *BytesNeeded = MoveBytes;
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ } else {
+
+ //
+ // Store result.
+ //
+
+ ELNKII_MOVE_MEM(InfoBuffer, MoveSource, MoveBytes);
+
+ (*BytesWritten) += MoveBytes;
+
+ }
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ IF_LOUD( DbgPrint("Out QueryProtocol\n");)
+
+ return(StatusToReturn);
+}
+
+NDIS_STATUS
+ElnkiiQueryInformation(
+ IN PELNKII_ADAPTER Adapter,
+ IN PELNKII_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest
+ )
+/*++
+
+Routine Description:
+
+ The ElnkiiQueryInformation is used by ElnkiiRequest to query information
+ about the MAC.
+
+Arguments:
+
+ Adapter - A pointer to the adapter.
+
+ Open - A pointer to a particular open instance.
+
+ NdisRequest - A structure which contains the request type (Query),
+ an array of operations to perform, and an array for holding
+ the results of the operations.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+ UINT BytesWritten = 0;
+ UINT BytesNeeded = 0;
+ UINT BytesLeft = NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength;
+ PUCHAR InfoBuffer = (PUCHAR)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+
+ IF_LOUD( DbgPrint("In QueryInfor\n");)
+
+ StatusToReturn = ElnkiiQueryProtocolInformation(
+ Adapter,
+ Open,
+ NdisRequest->DATA.QUERY_INFORMATION.Oid,
+ FALSE,
+ InfoBuffer,
+ BytesLeft,
+ &BytesNeeded,
+ &BytesWritten
+ );
+
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesWritten = BytesWritten;
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = BytesNeeded;
+
+ IF_LOUD( DbgPrint("Out QueryInfor\n");)
+
+ return(StatusToReturn);
+}
+
+NDIS_STATUS
+ElnkiiSetInformation(
+ IN PELNKII_ADAPTER Adapter,
+ IN PELNKII_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest
+ )
+/*++
+
+Routine Description:
+
+ The ElnkiiSetInformation is used by ElnkiiRequest to set information
+ about the MAC.
+
+Arguments:
+
+ Adapter - A pointer to the adapter.
+
+ Open - A pointer to an open instance.
+
+ NdisRequest - A structure which contains the request type (Set),
+ an array of operations to perform, and an array for holding
+ the results of the operations.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+ //
+ // General Algorithm:
+ //
+ // Verify length
+ // Switch(Request)
+ // Process Request
+ //
+
+ UINT BytesRead = 0;
+ UINT BytesNeeded = 0;
+ UINT BytesLeft = NdisRequest->DATA.SET_INFORMATION.InformationBufferLength;
+ PUCHAR InfoBuffer = (PUCHAR)(NdisRequest->DATA.SET_INFORMATION.InformationBuffer);
+
+ //
+ // Variables for a particular request
+ //
+
+ NDIS_OID Oid;
+ UINT OidLength;
+
+ //
+ // Variables for holding the new values to be used.
+ //
+
+ ULONG LookAhead;
+ ULONG Filter;
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+
+ IF_LOUD( DbgPrint("In SetInfo\n");)
+
+ //
+ // Get Oid and Length of request
+ //
+
+ Oid = NdisRequest->DATA.SET_INFORMATION.Oid;
+
+ OidLength = BytesLeft;
+
+ switch (Oid) {
+
+
+ case OID_802_3_MULTICAST_LIST:
+
+ //
+ // Verify length
+ //
+
+ if ((OidLength % ETH_LENGTH_OF_ADDRESS) != 0){
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ break;
+
+ }
+
+ StatusToReturn = ElnkiiSetMulticastAddresses(
+ Adapter,
+ Open,
+ NdisRequest,
+ (UINT)(OidLength / ETH_LENGTH_OF_ADDRESS),
+ (PVOID)InfoBuffer
+ );
+
+ break;
+
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ //
+ // Verify length
+ //
+
+ if (OidLength != 4 ) {
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ break;
+
+ }
+
+ ELNKII_MOVE_MEM(&Filter, InfoBuffer, 4);
+
+ //
+ // Verify bits
+ //
+
+ if (Filter & (NDIS_PACKET_TYPE_SOURCE_ROUTING |
+ NDIS_PACKET_TYPE_SMT |
+ NDIS_PACKET_TYPE_MAC_FRAME |
+ NDIS_PACKET_TYPE_FUNCTIONAL |
+ NDIS_PACKET_TYPE_ALL_FUNCTIONAL |
+ NDIS_PACKET_TYPE_GROUP
+ )) {
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 4;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ break;
+
+ }
+
+ StatusToReturn = ElnkiiSetPacketFilter(Adapter,
+ Open,
+ NdisRequest,
+ Filter);
+
+
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ //
+ // Verify length
+ //
+
+ if (OidLength != 4) {
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ break;
+
+ }
+
+ ELNKII_MOVE_MEM(&LookAhead, InfoBuffer, 4);
+
+ if (LookAhead <= ELNKII_MAX_LOOKAHEAD) {
+
+ if (LookAhead > Adapter->MaxLookAhead) {
+
+ Adapter->MaxLookAhead = LookAhead;
+
+ Open->LookAhead = LookAhead;
+
+ } else {
+
+ if ((Open->LookAhead == Adapter->MaxLookAhead) &&
+ (LookAhead < Open->LookAhead)) {
+
+ Open->LookAhead = LookAhead;
+
+ ElnkiiAdjustMaxLookAhead(Adapter);
+
+ } else {
+
+ Open->LookAhead = LookAhead;
+
+ }
+
+ }
+
+
+ } else {
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ }
+
+ break;
+
+ case OID_GEN_PROTOCOL_OPTIONS:
+
+ if (OidLength != 4) {
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ break;
+
+ }
+
+ ELNKII_MOVE_MEM(&Open->ProtOptionFlags, InfoBuffer, 4);
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ break;
+
+ default:
+
+ StatusToReturn = NDIS_STATUS_INVALID_OID;
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ break;
+
+ }
+
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS) {
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = BytesLeft;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ }
+
+
+ IF_LOUD( DbgPrint("Out SetInfo\n");)
+
+ return(StatusToReturn);
+}
+
+
+STATIC
+NDIS_STATUS
+ElnkiiSetPacketFilter(
+ IN PELNKII_ADAPTER Adapter,
+ IN PELNKII_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT PacketFilter
+ )
+
+/*++
+
+Routine Description:
+
+ The ElnkiiSetPacketFilter request allows a protocol to control the types
+ of packets that it receives from the MAC.
+
+Arguments:
+
+ Adapter - A pointer to the adapter structure.
+
+ Open - A pointer to the open block giving the request.
+
+ NdisRequest - The NDIS_REQUEST with the set packet filter command in it.
+
+ PacketFilter - A bit mask that contains flags that correspond to specific
+ classes of received packets. If a particular bit is set in the mask,
+ then packet reception for that class of packet is enabled. If the
+ bit is clear, then packets that fall into that class are not received
+ by the client. A single exception to this rule is that if the promiscuous
+ bit is set, then the client receives all packets on the network, regardless
+ of the state of the other flags.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ //
+ // Keeps track of the *MAC's* status. The status will only be
+ // reset if the filter change action routine is called.
+ //
+ NDIS_STATUS StatusOfFilterChange = NDIS_STATUS_SUCCESS;
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ IF_LOUD( DbgPrint("In SetFilter\n");)
+
+ if (!Adapter->ResetInProgress) {
+
+ if (!Open->Closing) {
+
+ //
+ // Increment the open while it is going through the filtering
+ // routines.
+ //
+
+ Open->ReferenceCount++;
+
+ StatusOfFilterChange = EthFilterAdjust(
+ Adapter->FilterDB,
+ Open->NdisFilterHandle,
+ NdisRequest,
+ PacketFilter,
+ TRUE
+ );
+
+ Open->ReferenceCount--;
+
+ } else {
+
+ StatusOfFilterChange = NDIS_STATUS_CLOSING;
+
+ }
+
+ } else {
+
+ StatusOfFilterChange = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ IF_LOUD( DbgPrint("Out SetFilter\n");)
+
+ return StatusOfFilterChange;
+}
+
+
+
+
+STATIC
+NDIS_STATUS
+ElnkiiSetMulticastAddresses(
+ IN PELNKII_ADAPTER Adapter,
+ IN PELNKII_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT NumAddresses,
+ IN CHAR AddressList[][ETH_LENGTH_OF_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ This function calls into the filter package in order to set the
+ multicast address list for the card to the specified list.
+
+Arguments:
+
+ Adapter - A pointer to the adapter block.
+
+ Open - A pointer to the open block submitting the request.
+
+ NdisRequest - The NDIS_REQUEST with the set multicast address list command
+ in it.
+
+ NumAddresses - A count of the number of addresses in the addressList.
+
+ AddressList - An array of multicast addresses that this open instance
+ wishes to accept.
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+ //
+ // Keeps track of the *MAC's* status. The status will only be
+ // reset if the filter change action routine is called.
+ //
+ NDIS_STATUS StatusOfFilterChange = NDIS_STATUS_SUCCESS;
+
+ IF_LOUD( DbgPrint("In SetMulticast\n");)
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ if (!Adapter->ResetInProgress) {
+
+ if (!Open->Closing) {
+
+ //
+ // Increment the open while it is going through the filtering
+ // routines.
+ //
+
+ Open->ReferenceCount++;
+
+ StatusOfFilterChange = EthChangeFilterAddresses(
+ Adapter->FilterDB,
+ Open->NdisFilterHandle,
+ NdisRequest,
+ NumAddresses,
+ AddressList,
+ TRUE
+ );
+
+ Open->ReferenceCount--;
+
+ } else {
+
+ StatusOfFilterChange = NDIS_STATUS_CLOSING;
+
+ }
+
+ } else {
+
+ StatusOfFilterChange = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ IF_LOUD( DbgPrint("Out SetMulticast\n");)
+
+ return StatusOfFilterChange;
+}
+
+
+
+NDIS_STATUS
+ElnkiiFillInGlobalData(
+ IN PELNKII_ADAPTER Adapter,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ This routine completes a GlobalStatistics request. It is critical that
+ if information is needed from the Adapter->* fields, they have been
+ updated before this routine is called.
+
+Arguments:
+
+ Adapter - A pointer to the Adapter.
+
+ NdisRequest - A structure which contains the request type (Global
+ Query), an array of operations to perform, and an array for holding
+ the results of the operations.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ //
+ // General Algorithm:
+ //
+ // Switch(Request)
+ // Get requested information
+ // Store results in a common variable.
+ // default:
+ // Try protocol query information
+ // If that fails, fail query.
+ //
+ // Copy result in common variable to result buffer.
+ // Finish processing
+
+ UINT BytesWritten = 0;
+ UINT BytesNeeded = 0;
+ UINT BytesLeft = NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength;
+ PUCHAR InfoBuffer = (PUCHAR)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ //
+ // This variable holds result of query
+ //
+
+ ULONG GenericULong;
+ UINT MoveBytes = sizeof(UINT) * 2 + sizeof(NDIS_OID);
+
+ //
+ // Make sure that int is 4 bytes. Else GenericULong must change
+ // to something of size 4.
+ //
+ ASSERT(sizeof(UINT) == 4);
+
+
+ StatusToReturn = ElnkiiQueryProtocolInformation(
+ Adapter,
+ NULL,
+ NdisRequest->DATA.QUERY_INFORMATION.Oid,
+ TRUE,
+ InfoBuffer,
+ BytesLeft,
+ &BytesNeeded,
+ &BytesWritten
+ );
+
+ if (StatusToReturn == NDIS_STATUS_NOT_SUPPORTED) {
+
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ //
+ // Switch on request type
+ //
+
+ switch (NdisRequest->DATA.QUERY_INFORMATION.Oid) {
+
+ case OID_GEN_XMIT_OK:
+
+ GenericULong = (UINT)(Adapter->FramesXmitGood);
+
+ break;
+
+ case OID_GEN_RCV_OK:
+
+ GenericULong = (UINT)(Adapter->FramesRcvGood);
+
+ break;
+
+ case OID_GEN_XMIT_ERROR:
+
+ GenericULong = (UINT)(Adapter->FramesXmitBad);
+
+ break;
+
+ case OID_GEN_RCV_ERROR:
+
+ GenericULong = (UINT)(Adapter->CrcErrors);
+
+ break;
+
+ case OID_GEN_RCV_NO_BUFFER:
+
+ GenericULong = (UINT)(Adapter->MissedPackets);
+
+ break;
+
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+
+ GenericULong = (UINT)(Adapter->FrameAlignmentErrors);
+
+ break;
+
+ case OID_802_3_XMIT_ONE_COLLISION:
+
+ GenericULong = (UINT)(Adapter->FramesXmitOneCollision);
+
+ break;
+
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+
+ GenericULong = (UINT)(Adapter->FramesXmitManyCollisions);
+
+ break;
+
+
+ default:
+
+ StatusToReturn = NDIS_STATUS_INVALID_OID;
+
+ break;
+
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ //
+ // Check to make sure there is enough room in the
+ // buffer to store the result.
+ //
+
+ if (BytesLeft >= sizeof(ULONG)) {
+
+ //
+ // Store the result.
+ //
+
+ ELNKII_MOVE_MEM(
+ (PVOID)InfoBuffer,
+ (PVOID)(&GenericULong),
+ sizeof(ULONG)
+ );
+
+ BytesWritten += sizeof(ULONG);
+
+ }
+
+ }
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesWritten = BytesWritten;
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = BytesNeeded;
+
+ return(StatusToReturn);
+}
+
+NDIS_STATUS
+ElnkiiQueryGlobalStatistics(
+ IN NDIS_HANDLE MacAdapterContext,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ The ElnkiiQueryGlobalStatistics is used by the protocol to query
+ global information about the MAC.
+
+Arguments:
+
+ MacAdapterContext - The value associated with the adapter that is being
+ opened when the MAC registered the adapter with NdisRegisterAdapter.
+
+ NdisRequest - A structure which contains the request type (Query),
+ an array of operations to perform, and an array for holding
+ the results of the operations.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+ //
+ // General Algorithm:
+ //
+ //
+ // Check if a request is going to pend...
+ // If so, pend the entire operation.
+ //
+ // Else
+ // Fill in the request block.
+ //
+ //
+
+ PELNKII_ADAPTER Adapter = (PELNKII_ADAPTER)(MacAdapterContext);
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ //
+ // Check if a request is valid and going to pend...
+ // If so, pend the entire operation.
+ //
+
+
+ //
+ // Switch on request type
+ //
+
+ switch (NdisRequest->DATA.QUERY_INFORMATION.Oid) {
+ case OID_GEN_SUPPORTED_LIST:
+ case OID_GEN_HARDWARE_STATUS:
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+ case OID_GEN_MAC_OPTIONS:
+ case OID_GEN_PROTOCOL_OPTIONS:
+ case OID_GEN_LINK_SPEED:
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+ case OID_GEN_VENDOR_ID:
+ case OID_GEN_VENDOR_DESCRIPTION:
+ case OID_GEN_DRIVER_VERSION:
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ case OID_802_3_PERMANENT_ADDRESS:
+ case OID_802_3_CURRENT_ADDRESS:
+ case OID_GEN_XMIT_OK:
+ case OID_GEN_RCV_OK:
+ case OID_GEN_XMIT_ERROR:
+ case OID_GEN_RCV_ERROR:
+ case OID_GEN_RCV_NO_BUFFER:
+ case OID_802_3_MULTICAST_LIST:
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+ case OID_802_3_XMIT_ONE_COLLISION:
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+
+ break;
+
+ default:
+
+ StatusToReturn = NDIS_STATUS_INVALID_OID;
+
+ break;
+ }
+
+ NdisInterlockedAddUlong(&Adapter->References, 1, &Adapter->Lock);
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS) {
+
+ StatusToReturn = ElnkiiFillInGlobalData(Adapter, NdisRequest);
+
+ }
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ ELNKII_DO_DEFERRED(Adapter);
+
+ return(StatusToReturn);
+}
+
+VOID
+ElnkiiUnload(
+ IN NDIS_HANDLE MacMacContext
+ )
+
+/*++
+
+Routine Description:
+
+ ElnkiiUnload is called when the MAC is to unload itself.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS InitStatus;
+
+ UNREFERENCED_PARAMETER(MacMacContext);
+
+ NdisDeregisterMac(
+ &InitStatus,
+ ElnkiiMacBlock.NdisMacHandle
+ );
+
+ NdisFreeSpinLock(&ElnkiiMacBlock.SpinLock);
+
+ NdisTerminateWrapper(
+ ElnkiiMacBlock.NdisWrapperHandle,
+ (PVOID) NULL
+ );
+
+ return;
+}
+
+VOID
+ElnkiiRemoveAdapter(
+ IN PVOID MacAdapterContext
+ )
+/*++
+
+Routine Description:
+
+ ElnkiiRemoveAdapter removes an adapter previously registered
+ with NdisRegisterAdapter.
+
+Arguments:
+
+ MacAdapterContext - The context value that the MAC passed
+ to NdisRegisterAdapter; actually as pointer to an
+ ELNKII_ADAPTER.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PELNKII_ADAPTER Adapter;
+
+ Adapter = PELNKII_ADAPTER_FROM_CONTEXT_HANDLE(MacAdapterContext);
+
+ Adapter->Removed = TRUE;
+
+ ASSERT(Adapter->OpenQueue == (PELNKII_OPEN)NULL);
+
+ //
+ // There are no opens left, so remove ourselves.
+ //
+
+ //
+ // Take us out of the AdapterQueue.
+ //
+
+ NdisAcquireSpinLock(&ElnkiiMacBlock.SpinLock);
+
+ if (ElnkiiMacBlock.AdapterQueue == Adapter) {
+
+ ElnkiiMacBlock.AdapterQueue = Adapter->NextAdapter;
+
+ } else {
+
+ PELNKII_ADAPTER TmpAdaptP = ElnkiiMacBlock.AdapterQueue;
+
+ while (TmpAdaptP->NextAdapter != Adapter) {
+
+ TmpAdaptP = TmpAdaptP->NextAdapter;
+
+ }
+
+ TmpAdaptP->NextAdapter = TmpAdaptP->NextAdapter->NextAdapter;
+ }
+
+ NdisReleaseSpinLock(&ElnkiiMacBlock.SpinLock);
+
+ if (Adapter->MemMapped) {
+
+ NdisUnmapIoSpace(
+ Adapter->NdisAdapterHandle,
+ Adapter->XmitStart,
+ 0x2000);
+
+ }
+
+ {
+ BOOLEAN Canceled;
+ NdisCancelTimer(&Adapter->WakeUpTimer, &Canceled);
+
+ if (!Canceled) {
+ NdisStallExecution(500000);
+ }
+ }
+
+ EthDeleteFilter(Adapter->FilterDB);
+
+ NdisRemoveInterrupt(&Adapter->NdisInterrupt);
+
+ NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
+
+ NdisFreeSpinLock(&Adapter->Lock);
+
+ NdisFreeMemory(Adapter, sizeof(ELNKII_ADAPTER), 0);
+
+}
+
+
+
+NDIS_STATUS
+ElnkiiReset(
+ IN NDIS_HANDLE MacBindingHandle
+ )
+
+/*++
+
+Routine Description:
+
+ NDIS function.
+
+Arguments:
+
+ See NDIS 3.0 spec.
+
+--*/
+
+{
+ PELNKII_OPEN OpenP = ((PELNKII_OPEN)MacBindingHandle);
+ PELNKII_OPEN TmpOpenP;
+ PELNKII_ADAPTER AdaptP = OpenP->Adapter;
+ NDIS_STATUS Status;
+
+
+ if (OpenP->Closing) {
+
+ return(NDIS_STATUS_CLOSING);
+
+ }
+
+ NdisAcquireSpinLock(&AdaptP->Lock);
+
+ //
+ // Ensure that the open does not close while in this function.
+ //
+
+ OpenP->ReferenceCount++;
+
+ AdaptP->References++;
+
+
+ //
+ // Check that nobody is resetting this adapter, block others.
+ //
+
+ if (AdaptP->ResetInProgress) {
+
+ --OpenP->ReferenceCount;
+
+ AdaptP->References--;
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+ return NDIS_STATUS_RESET_IN_PROGRESS;
+ }
+
+ //
+ // Indicate Reset Start
+ //
+
+ TmpOpenP = AdaptP->OpenQueue;
+
+ while (TmpOpenP != (PELNKII_OPEN)NULL) {
+
+ PELNKII_OPEN NextOpen;
+
+ AddRefWhileHoldingSpinLock(AdaptP, TmpOpenP);
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+ NdisIndicateStatus(TmpOpenP->NdisBindingContext,
+ NDIS_STATUS_RESET_START,
+ NULL,
+ 0
+ );
+
+ NdisAcquireSpinLock(&AdaptP->Lock);
+
+ NextOpen = TmpOpenP->NextOpen;
+
+ TmpOpenP->ReferenceCount--;
+
+ TmpOpenP = NextOpen;
+ }
+
+ //
+ // Set Reset Flag
+ //
+
+ AdaptP->ResetInProgress = TRUE;
+ AdaptP->NextResetStage = NONE;
+
+ //
+ // Needed in case the reset pends somewhere along the line.
+ //
+
+ AdaptP->ResetOpen = OpenP;
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+ //
+ // This will take things from here.
+ //
+
+ Status = ElnkiiStage2Reset(AdaptP);
+
+ NdisAcquireSpinLock(&AdaptP->Lock);
+
+ --OpenP->ReferenceCount;
+
+ ELNKII_DO_DEFERRED(AdaptP);
+
+ return(Status);
+
+}
+
+NDIS_STATUS
+ElnkiiStage2Reset(
+ PELNKII_ADAPTER AdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ The second stage of a reset.
+ It removes all requests on the pend queue.
+ ElnkiiStage3Reset will be called when CurBufXmitting goes to -1.
+
+Arguments:
+
+ AdaptP - The adapter being reset.
+
+Return Value:
+
+ NDIS_STATUS_PENDING if the card is currently transmitting.
+ The result of ElnkiiStage3Reset otherwise.
+
+--*/
+
+{
+ NDIS_STATUS Status;
+ PELNKII_PEND_DATA Op;
+ PELNKII_OPEN TmpOpen;
+
+ NdisAcquireSpinLock(&AdaptP->Lock);
+
+ AdaptP->References++;
+
+ //
+ // kill the pend queue.
+ //
+
+ while (AdaptP->PendQueue != (PELNKII_PEND_DATA)NULL) {
+
+ Op = AdaptP->PendQueue;
+
+ AdaptP->PendQueue = Op->Next;
+
+ TmpOpen = Op->Open;
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+ Status = NDIS_STATUS_REQUEST_ABORTED;
+
+ if ((Op->RequestType != NdisRequestClose) &&
+ (Op->RequestType != NdisRequestGeneric1)) { // Not a close Request
+
+ NdisCompleteRequest(Op->Open->NdisBindingContext,
+ PNDIS_REQUEST_FROM_PELNKII_PEND_DATA(Op),
+ NDIS_STATUS_REQUEST_ABORTED);
+
+ }
+
+ //
+ // This will call NdisCompleteClose if necessary.
+ //
+
+ NdisAcquireSpinLock(&AdaptP->Lock);
+
+ --TmpOpen->ReferenceCount;
+ }
+
+ if (AdaptP->CurBufXmitting != -1) {
+
+ //
+ // ElnkiiHandleXmitComplete will call ElnkiiStage3Reset.
+ //
+
+ AdaptP->NextResetStage = XMIT_STOPPED;
+
+ AdaptP->References--;
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+ return NDIS_STATUS_PENDING;
+
+ }
+
+ AdaptP->References--;
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+ return ElnkiiStage3Reset(AdaptP);
+
+}
+
+NDIS_STATUS
+ElnkiiStage3Reset(
+ PELNKII_ADAPTER AdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ The third stage of a reset. When called, CurBufXmitting has
+ gone to -1. ElnkiiStage4Reset is called when call the
+ transmit buffers are emptied (i.e. any threads that were
+ filling them have finished).
+
+Arguments:
+
+ AdaptP - The adapter being reset.
+
+Return Value:
+
+ NDIS_STATUS_PENDING if there are still transmit buffers being filled.
+ The result of ElnkiiStage4Reset otherwise.
+
+--*/
+
+{
+ UINT i;
+
+ NdisAcquireSpinLock(&AdaptP->Lock);
+
+ AdaptP->References++;
+
+ //
+ // Reset these for afterwards.
+ //
+
+ AdaptP->NextBufToFill = 0;
+
+ AdaptP->NextBufToXmit = 0;
+
+
+ //
+ // Make sure all buffer filling operations are done.
+ //
+
+ for (i=0; i<AdaptP->NumBuffers; i++) {
+
+ if (AdaptP->BufferStatus[i] != EMPTY) {
+
+ //
+ // ElnkiiSend or ElnkiiCopyAndSend will call ElnkiiStage4Reset.
+ //
+
+ AdaptP->NextResetStage = BUFFERS_EMPTY;
+
+ AdaptP->References--;
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+ return NDIS_STATUS_PENDING;
+ }
+ }
+
+ AdaptP->References--;
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+ return ElnkiiStage4Reset(AdaptP);
+}
+
+NDIS_STATUS
+ElnkiiStage4Reset(
+ PELNKII_ADAPTER AdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ The fourth stage of a reset. When called, the last transmit
+ buffer has been marked empty. At this point the reset can
+ proceed.
+
+Arguments:
+
+ AdaptP - The adapter being reset.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if the reset of the card succeeds.
+ NDIS_STATUS_FAILURE otherwise.
+
+--*/
+{
+ UINT i;
+ PNDIS_PACKET CurPacket;
+ PMAC_RESERVED Reserved;
+ PELNKII_OPEN TmpOpenP;
+ NDIS_STATUS Status;
+
+
+ //
+ // Complete any packets that are waiting in transmit buffers,
+ // but are not in the loopback queue.
+ //
+
+ NdisAcquireSpinLock(&AdaptP->Lock);
+
+ AdaptP->References++;
+
+ for (i=0; i<AdaptP->NumBuffers; i++) {
+
+ if (AdaptP->Packets[i] != (PNDIS_PACKET)NULL) {
+
+ Reserved = RESERVED(AdaptP->Packets[i]);
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+#if DBG
+ ElnkiiSendsCompletedForReset++;
+#endif
+
+ TmpOpenP = Reserved->Open;
+
+ NdisCompleteSend(Reserved->Open->NdisBindingContext,
+ AdaptP->Packets[i],
+ NDIS_STATUS_REQUEST_ABORTED);
+
+ NdisAcquireSpinLock(&AdaptP->Lock);
+
+ --TmpOpenP->ReferenceCount;
+
+ AdaptP->Packets[i] = (PNDIS_PACKET)NULL;
+ }
+ }
+
+
+ //
+ // Kill any packets waiting in the transmit queue,
+ // but are not in the loopback queue.
+ //
+
+ while ((CurPacket = AdaptP->XmitQueue) != (PNDIS_PACKET)NULL) {
+
+ Reserved = RESERVED(CurPacket);
+
+ AdaptP->XmitQueue = Reserved->NextPacket;
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+#if DBG
+ ElnkiiSendsCompletedForReset++;
+#endif
+
+ TmpOpenP = Reserved->Open;
+
+ NdisCompleteSend(Reserved->Open->NdisBindingContext,
+ CurPacket,
+ NDIS_STATUS_REQUEST_ABORTED);
+
+ NdisAcquireSpinLock(&AdaptP->Lock);
+
+ --TmpOpenP->ReferenceCount;
+ }
+
+
+ //
+ // Now kill everything in the loopback queue.
+ //
+
+ while ((CurPacket = AdaptP->LoopbackQueue) != (PNDIS_PACKET)NULL) {
+
+ Reserved = RESERVED(CurPacket);
+
+ AdaptP->LoopbackQueue = Reserved->NextPacket;
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+#if DBG
+ ElnkiiSendsCompletedForReset++;
+#endif
+
+ TmpOpenP = Reserved->Open;
+
+ NdisCompleteSend(Reserved->Open->NdisBindingContext,
+ CurPacket,
+ NDIS_STATUS_REQUEST_ABORTED);
+
+ NdisAcquireSpinLock(&AdaptP->Lock);
+
+ --TmpOpenP->ReferenceCount;
+ }
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+ //
+ // Wait for packet reception to stop -- this might happen if we
+ // really blaze through the reset code before the ReceiveDpc gets
+ // a chance to run.
+ //
+
+ while (AdaptP->ReceiveInProgress) {
+
+ NdisStallExecution(10000);
+ }
+
+ //
+ // Physically reset the card.
+ //
+
+ AdaptP->NicInterruptMask =
+ IMR_RCV | IMR_XMIT | IMR_XMIT_ERR | IMR_OVERFLOW;
+
+ Status = CardReset(AdaptP) ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE;
+
+
+ //
+ // Set the "resetting" flag back to FALSE.
+ //
+
+ NdisAcquireSpinLock(&AdaptP->Lock);
+
+ AdaptP->ResetInProgress = FALSE;
+
+ //
+ // Indicate the reset complete to all the protocols.
+ //
+
+
+ TmpOpenP = AdaptP->OpenQueue;
+
+ while (TmpOpenP != (PELNKII_OPEN)NULL) {
+
+ PELNKII_OPEN NextOpen;
+
+ AddRefWhileHoldingSpinLock(AdaptP, TmpOpenP);
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NdisIndicateStatus(TmpOpenP->NdisBindingContext,
+ NDIS_STATUS_CLOSED,
+ NULL,
+ 0
+ );
+
+ }
+
+ NdisIndicateStatus(TmpOpenP->NdisBindingContext,
+ NDIS_STATUS_RESET_END,
+ &Status,
+ sizeof(Status)
+ );
+
+ NdisIndicateStatusComplete(TmpOpenP->NdisBindingContext);
+
+ NdisAcquireSpinLock(&AdaptP->Lock);
+
+ NextOpen = TmpOpenP->NextOpen;
+
+ TmpOpenP->ReferenceCount--;
+
+ TmpOpenP = NextOpen;
+ }
+
+ AdaptP->References--;
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+ return Status;
+}
+
+VOID
+ElnkiiResetStageDone(
+ PELNKII_ADAPTER AdaptP,
+ RESET_STAGE StageDone
+ )
+
+/*++
+
+Routine Description:
+
+ Indicates that a stage in the reset is done. Called by
+ routines that the reset pended waiting for, to indicate
+ that they are done. A central clearing house for determining
+ what the next stage is and calling the appropriate routine.
+ If a stage completes before it is being pended on, then
+ StageDone will not equal AdaptP->NextResetStage and no
+ action will be taken.
+
+Arguments:
+
+ AdaptP - The adapter being reset.
+ StageDone - The stage that was just completed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS Status;
+ UINT i;
+
+
+ //
+ // Make sure this is the stage that was being waited on.
+ //
+
+ if (AdaptP->NextResetStage != StageDone) {
+ return;
+ }
+
+
+ switch (StageDone) {
+
+ case MULTICAST_RESET:
+ Status = ElnkiiStage2Reset(AdaptP);
+ break;
+
+ case XMIT_STOPPED:
+ Status = ElnkiiStage3Reset(AdaptP);
+ break;
+
+ case BUFFERS_EMPTY:
+
+ //
+ // Only continue if this is the last buffer waited for.
+ //
+
+ NdisAcquireSpinLock(&AdaptP->Lock);
+
+ AdaptP->References++;
+
+ for (i=0; i<AdaptP->NumBuffers; i++) {
+
+ if (AdaptP->BufferStatus[i] != EMPTY) {
+
+ AdaptP->References--;
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+ return;
+
+ }
+
+ }
+
+ AdaptP->References--;
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+ Status = ElnkiiStage4Reset(AdaptP);
+
+ break;
+
+ }
+
+ if (Status != NDIS_STATUS_PENDING) {
+
+ NdisCompleteReset(
+ AdaptP->ResetOpen->NdisBindingContext,
+ Status);
+
+ NdisAcquireSpinLock(&AdaptP->Lock);
+
+ --AdaptP->ResetOpen->ReferenceCount;
+
+ } else {
+
+ NdisAcquireSpinLock(&AdaptP->Lock);
+
+ }
+
+ ELNKII_DO_DEFERRED(AdaptP);
+}
+
+
+STATIC
+NDIS_STATUS
+ElnkiiChangeMulticastAddresses(
+ IN UINT OldFilterCount,
+ IN CHAR OldAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN UINT NewFilterCount,
+ IN CHAR NewAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when a particular filter
+ class is first used or last cleared.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+
+ OldFilterCount - The number of addresses that used to be on the card.
+
+ OldAddresses - A list of all the addresses that used to be on the card.
+
+ NewFilterCount - The number of addresses that should now be on the card.
+
+ NewAddresses - A list of addresses that should be put on the card.
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to ELNKII_OPEN.
+
+ NdisRequest - The request which submitted the filter change.
+ Must use when completing this request with the NdisCompleteRequest
+ service, if the MAC completes this request asynchronously.
+
+ Set - If true the change resulted from a set, otherwise the
+ change resulted from a open closing.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+
+
+ PELNKII_ADAPTER Adapter = PELNKII_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+ PELNKII_PEND_DATA PendOp = PELNKII_PEND_DATA_FROM_PNDIS_REQUEST(NdisRequest);
+ UINT Filter;
+
+ //
+ // The open that made this request.
+ //
+ PELNKII_OPEN Open = PELNKII_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ //
+ // Holds the status that should be returned to the filtering package.
+ //
+ NDIS_STATUS StatusOfAdd;
+
+ UNREFERENCED_PARAMETER(OldFilterCount);
+ UNREFERENCED_PARAMETER(OldAddresses);
+ UNREFERENCED_PARAMETER(NewFilterCount);
+ UNREFERENCED_PARAMETER(NewAddresses);
+
+ if (NdisRequest == NULL) {
+
+ NdisRequest = &(Open->CloseAddressRequest);
+ PendOp = PELNKII_PEND_DATA_FROM_PNDIS_REQUEST(NdisRequest);
+
+ }
+
+ //
+ // Check to see if the device is already resetting. If it is
+ // then reject this add.
+ //
+
+ if (Adapter->ResetInProgress) {
+
+ StatusOfAdd = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ }
+ else
+ {
+ //
+ // Verify that the global filter is not all multicast
+ // or promiscuous modes. Otherwise adding a multicast
+ // address will reset the mode.
+ //
+ Filter = ETH_QUERY_FILTER_CLASSES(Adapter->FilterDB);
+ if ((Filter & NDIS_PACKET_TYPE_ALL_MULTICAST) ||
+ (Filter & NDIS_PACKET_TYPE_PROMISCUOUS)
+ )
+ {
+ return(NDIS_STATUS_SUCCESS);
+ }
+
+ PendOp->Open = Open;
+
+ //
+ // We need to add this to the hardware multicast filtering.
+ // So pend an operation to do it.
+ //
+
+ //
+ // Add one to reference count, to be subtracted when the
+ // operation get completed.
+ //
+
+ PendOp->Open->ReferenceCount++;
+ PendOp->RequestType = Set ?
+ NdisRequestGeneric3 : // Means SetMulticastAddresses
+ NdisRequestClose ; // Means CloseMulticast
+ PendOp->Next = NULL;
+
+
+ if (Adapter->PendQueue == (PELNKII_PEND_DATA)NULL) {
+
+ Adapter->PendQueue = Adapter->PendQTail = PendOp;
+
+ } else {
+
+ Adapter->PendQTail->Next = PendOp;
+ Adapter->PendQTail = PendOp;
+
+ }
+
+
+ StatusOfAdd = NDIS_STATUS_PENDING;
+
+ }
+
+ return StatusOfAdd;
+
+}
+
+STATIC
+NDIS_STATUS
+ElnkiiChangeFilterClasses(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when an address is added to
+ the filter that wasn't referenced by any other open binding.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ OldFilterClasses - A bit mask that is currently on the card telling
+ which packet types to accept.
+
+ NewFilterClasses - A bit mask that should be put on the card telling
+ which packet types to accept.
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to ELNKII_OPEN.
+
+ NdisRequest - The NDIS_REQUEST which submitted the filter change command.
+
+ Set - A flag telling if the command is a result of a close or not.
+
+Return Value:
+
+ Status of the change (successful or pending).
+
+
+--*/
+
+{
+
+ PELNKII_ADAPTER Adapter = PELNKII_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+ PELNKII_PEND_DATA PendOp = PELNKII_PEND_DATA_FROM_PNDIS_REQUEST(NdisRequest);
+
+ //
+ // The open that made this request.
+ //
+ PELNKII_OPEN Open = PELNKII_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ //
+ // Holds the status that should be returned to the filtering package.
+ //
+ NDIS_STATUS StatusOfAdd;
+
+
+ UNREFERENCED_PARAMETER(OldFilterClasses);
+ UNREFERENCED_PARAMETER(NewFilterClasses);
+
+ if (NdisRequest == NULL) {
+
+ NdisRequest = &(Open->CloseFilterRequest);
+ PendOp = PELNKII_PEND_DATA_FROM_PNDIS_REQUEST(NdisRequest);
+
+ }
+
+ //
+ // Check to see if the device is already resetting. If it is
+ // then reject this add.
+ //
+
+ if (Adapter->ResetInProgress) {
+
+ StatusOfAdd = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ } else {
+
+ PendOp->Open = Open;
+
+ //
+ // We need to add this to the hardware multicast filtering.
+ // So queue a request.
+ //
+
+ PendOp->Open->ReferenceCount++;
+ PendOp->RequestType = Set ?
+ NdisRequestGeneric2 : // Means SetPacketFilter
+ NdisRequestGeneric1 ; // Means CloseFilter
+ PendOp->Next = NULL;
+
+ if (Adapter->PendQueue == (PELNKII_PEND_DATA)NULL) {
+
+ Adapter->PendQueue = Adapter->PendQTail = PendOp;
+
+ } else {
+
+ Adapter->PendQTail->Next = PendOp;
+ Adapter->PendQTail = PendOp;
+
+ }
+
+ StatusOfAdd = NDIS_STATUS_PENDING;
+
+ }
+
+ return StatusOfAdd;
+
+}
+
+STATIC
+VOID
+ElnkiiCloseAction(
+ IN NDIS_HANDLE MacBindingHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when a particular binding
+ was closed while it was indicating through NdisIndicateReceive
+
+ All this routine needs to do is to decrement the reference count
+ of the binding.
+
+ NOTE: This routine assumes that it is called with the lock acquired.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to ELNKII_OPEN.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+
+ PELNKII_OPEN_FROM_BINDING_HANDLE(MacBindingHandle)->ReferenceCount--;
+
+}
diff --git a/private/ntos/ndis/elnkii/elnkii.rc b/private/ntos/ndis/elnkii/elnkii.rc
new file mode 100644
index 000000000..73b14edf9
--- /dev/null
+++ b/private/ntos/ndis/elnkii/elnkii.rc
@@ -0,0 +1,39 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "3Com Etherlink II and II/16 network driver"
+#define VER_INTERNALNAME_STR "ELNKII.SYS"
+#define VER_ORIGINALFILENAME_STR "ELNKII.SYS"
+
+#include "common.ver"
+
diff --git a/private/ntos/ndis/elnkii/elnksft.h b/private/ntos/ndis/elnkii/elnksft.h
new file mode 100644
index 000000000..8715159c6
--- /dev/null
+++ b/private/ntos/ndis/elnkii/elnksft.h
@@ -0,0 +1,1295 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ elnksft.h
+
+Abstract:
+
+ The main header for an Etherlink II MAC driver.
+
+Author:
+
+ Anthony V. Ercolano (tonye) creation-date 19-Jun-1990 (Driver Model)
+
+ Adam Barr (adamba) - original Elnkii code.
+
+Environment:
+
+ This driver is expected to work in DOS, OS2 and NT at the equivalent
+ of kernal mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+ Dec-1991 by Sean Selitrennikoff - Fit AdamBa's code into TonyE's model
+
+
+--*/
+
+#ifndef _ELNKIISFT_
+#define _ELNKIISFT_
+
+#define ELNKII_NDIS_MAJOR_VERSION 3
+#define ELNKII_NDIS_MINOR_VERSION 0
+
+//
+// This macro is used along with the flags to selectively
+// turn on debugging.
+//
+
+#if DBG
+
+#define IF_ELNKIIDEBUG(f) if (ElnkiiDebugFlag & (f))
+extern ULONG ElnkiiDebugFlag;
+
+#define ELNKII_DEBUG_LOUD 0x00000001 // debugging info
+#define ELNKII_DEBUG_VERY_LOUD 0x00000002 // excessive debugging info
+#define ELNKII_DEBUG_LOG 0x00000004 // enable ElnkiiLog
+#define ELNKII_DEBUG_CHECK_DUP_SENDS 0x00000008 // check for duplicate sends
+#define ELNKII_DEBUG_TRACK_PACKET_LENS 0x00000010 // track directed packet lens
+#define ELNKII_DEBUG_WORKAROUND1 0x00000020 // drop DFR/DIS packets
+#define ELNKII_DEBUG_CARD_BAD 0x00000040 // dump data if CARD_BAD
+#define ELNKII_DEBUG_CARD_TESTS 0x00000080 // print reason for failing
+
+
+
+//
+// Macro for deciding whether to dump lots of debugging information.
+//
+
+#define IF_LOUD(A) IF_ELNKIIDEBUG( ELNKII_DEBUG_LOUD ) { A }
+#define IF_VERY_LOUD(A) IF_ELNKIIDEBUG( ELNKII_DEBUG_VERY_LOUD ) { A }
+
+
+#else
+
+#define IF_LOUD(A)
+#define IF_VERY_LOUD(A)
+
+#endif
+
+
+//
+// Whether to use the ElnkiiLog
+//
+
+#if DBG
+
+#define IF_LOG(A) IF_ELNKIIDEBUG( ELNKII_DEBUG_LOG ) { A }
+extern VOID ElnkiiLog(UCHAR);
+
+#else
+
+#define IF_LOG(A)
+
+#endif
+
+
+//
+// Whether to do loud init failure
+//
+
+#if DBG
+#define IF_INIT(A) A
+#else
+#define IF_INIT(A)
+#endif
+
+
+//
+// Whether to do loud card test failures
+//
+
+#if DBG
+#define IF_TEST(A) IF_ELNKIIDEBUG( ELNKII_DEBUG_CARD_TESTS ) { A }
+#else
+#define IF_TEST(A)
+#endif
+
+
+
+
+//
+// Macros for services that differ between DOS and NT, we may consider adding these
+// into the NDIS spec.
+//
+
+
+//
+// AdaptP->NumBuffers
+//
+// controls the number of transmit buffers on the packet.
+// Choices are 1 or 2.
+//
+
+#define DEFAULT_NUMBUFFERS 2
+
+
+#define ELNKII_MOVE_MEM_TO_SHARED_RAM(dest,src,size) \
+ NdisMoveToMappedMemory(dest, src, size)
+
+#define ELNKII_MOVE_SHARED_RAM_TO_MEM(dest,src,size) \
+ NdisMoveFromMappedMemory(dest, src, size)
+
+
+
+#define ELNKII_MOVE_MEM(dest,src,size) NdisMoveMemory(dest,src,size)
+
+
+
+
+
+
+//
+// A broadcast address (for comparing with other addresses).
+//
+
+extern UCHAR ElnkiiBroadcastAddress[];
+
+
+//
+// The status of transmit buffers.
+//
+
+typedef enum { EMPTY, FILLING, FULL } BUFFER_STATUS;
+
+
+//
+// Type of an interrupt.
+//
+
+typedef enum { RECEIVE = 0x01,
+ TRANSMIT = 0x02,
+ OVERFLOW = 0x04,
+ COUNTER = 0x08,
+ UNKNOWN = 0x10} INTERRUPT_TYPE;
+
+//
+// Result of ElnkiiIndicate[Loopback]Packet().
+//
+
+typedef enum { INDICATE_OK, SKIPPED, ABORT, CARD_BAD } INDICATE_STATUS;
+
+
+//
+// Stages in a reset.
+//
+
+typedef enum { NONE, MULTICAST_RESET, XMIT_STOPPED, BUFFERS_EMPTY } RESET_STAGE;
+
+
+
+//
+// Number of bytes in an ethernet header
+//
+
+#define ELNKII_HEADER_SIZE 14
+
+//
+// Number of bytes allowed in a lookahead (max)
+//
+
+#define ELNKII_MAX_LOOKAHEAD (252 - ELNKII_HEADER_SIZE)
+
+
+
+//
+// Maximum number of transmit buffers on the card.
+//
+
+#define MAX_XMIT_BUFS 2
+
+
+//
+// A transmit buffer (usually 0 or 1).
+//
+
+typedef SHORT XMIT_BUF;
+
+
+//
+// Number of 256-byte buffers in a transmit buffer.
+//
+
+#define BUFS_PER_TX 6
+
+
+//
+// Size of a single transmit buffer.
+//
+
+#define TX_BUF_SIZE (BUFS_PER_TX*256)
+
+
+
+//
+// Only have one of these structures.
+//
+
+typedef struct _MAC_BLOCK {
+
+ //
+ // NDIS wrapper information.
+ //
+
+ NDIS_HANDLE NdisMacHandle; // returned from NdisRegisterMac
+ NDIS_HANDLE NdisWrapperHandle; // returned from NdisInitializeWrapper
+ NDIS_MAC_CHARACTERISTICS MacCharacteristics;
+
+ //
+ // Adapters registered for this MAC.
+ //
+
+ struct _ELNKII_ADAPTER * AdapterQueue;
+ NDIS_SPIN_LOCK SpinLock; // guards NumAdapter and AdapterQueue
+
+ PDRIVER_OBJECT DriverObject;
+
+ BOOLEAN Unloading;
+
+} MAC_BLOCK, * PMAC_BLOCK;
+
+
+//
+// Used to contain a queued operation.
+//
+
+typedef struct _ELNKII_PEND_DATA {
+ struct _ELNKII_PEND_DATA * Next;
+ struct _ELNKII_OPEN * Open;
+ NDIS_REQUEST_TYPE RequestType;
+} ELNKII_PEND_DATA, * PELNKII_PEND_DATA;
+
+//
+// This macro will return a pointer to the reserved area of
+// a PNDIS_REQUEST.
+//
+#define PELNKII_PEND_DATA_FROM_PNDIS_REQUEST(Request) \
+ ((PELNKII_PEND_DATA)((PVOID)((Request)->MacReserved)))
+
+//
+// This macros returns the enclosing NdisRequest.
+//
+#define PNDIS_REQUEST_FROM_PELNKII_PEND_DATA(PendOp)\
+ ((PNDIS_REQUEST)((PVOID)(PendOp)))
+
+
+
+
+
+//
+// One of these structures per adapter registered.
+//
+
+typedef struct _ELNKII_ADAPTER {
+
+ //
+ // Spin lock for adapter structure
+ //
+ NDIS_SPIN_LOCK Lock;
+
+
+ //
+ // NDIS wrapper information.
+ //
+
+ NDIS_HANDLE NdisAdapterHandle; // returned from NdisRegisterAdapter
+ NDIS_INTERRUPT NdisInterrupt; // interrupt info used by wrapper
+
+ //
+ // Links with our MAC.
+ //
+
+ PMAC_BLOCK MacBlock;
+ struct _ELNKII_ADAPTER * NextAdapter; // used by MacBlock->AdapterQueue
+
+ //
+ // Opens for this adapter.
+ //
+
+ struct _ELNKII_OPEN * OpenQueue;
+
+ //
+ // Opens for this adapter that are waiting for closes to finish.
+ //
+
+ struct _ELNKII_OPEN * CloseQueue;
+
+ //
+ // Number of references to the adapter.
+ //
+ ULONG References;
+
+ ULONG ReceivePacketCount;
+
+ //
+ // Configuration information
+ //
+
+ UINT NumBuffers;
+ PVOID IoBaseAddr;
+ PVOID MemBaseAddr; // actually read off the card
+ UINT MaxOpens;
+ CHAR InterruptNumber;
+ BOOLEAN ExternalTransceiver;
+ BOOLEAN MemMapped; // actually read off the card
+ BOOLEAN InCardTest;
+ UINT MulticastListMax;
+ PUCHAR MappedIoBaseAddr;
+ PUCHAR MappedGaBaseAddr;
+
+ //
+ // InterruptReg tracks interrupt sources that still need to be serviced,
+ // it is the logical OR of all card interrupts that have been received and not
+ // processed and cleared. (see also INTERRUPT_TYPE definition in elnkii.h)
+ //
+ UINT InterruptReg;
+
+ BOOLEAN ElnkiiHandleXmitCompleteRunning;
+ UCHAR TimeoutCount;
+
+ //
+ // Transmit queue.
+ //
+
+ PNDIS_PACKET XmitQueue; // packets waiting to be transmitted
+ PNDIS_PACKET XmitQTail;
+
+ //
+ // Transmit information.
+ //
+
+ XMIT_BUF NextBufToFill; // where to copy next packet to
+ XMIT_BUF NextBufToXmit; // valid if CurBufXmitting is -1
+ XMIT_BUF CurBufXmitting; // -1 if none is
+ BOOLEAN TransmitInterruptPending; // transmitting, but DPC not yet queued
+ BOOLEAN OverflowRestartXmitDpc; // transmitting, but DPC not yet queued
+ BUFFER_STATUS BufferStatus[MAX_XMIT_BUFS];
+ PNDIS_PACKET Packets[MAX_XMIT_BUFS]; // as passed to MacSend
+ UINT PacketLens[MAX_XMIT_BUFS];
+ PUCHAR XmitStart; // start of card transmit area
+ PUCHAR PageStart; // start of card receive area
+ PUCHAR PageStop; // end of card receive area
+ UCHAR NicXmitStart; // MSB, LSB assumed 0
+ UCHAR NicPageStart; // MSB, LSB assumed 0
+ UCHAR NicPageStop; // MSB, LSB assumed 0
+ UCHAR GaControlBits; // values for xsel and dbsel bits
+
+ //
+ // Receive information
+ //
+
+ UCHAR NicNextPacket; // MSB, LSB assumed 0
+ UCHAR Current; // MSB, LSB assumed 0 (last known value)
+ UCHAR XmitStatus; // status of last transmit
+
+ //
+ // These are for the current packet being indicated.
+ //
+
+ UCHAR PacketHeader[4]; // the NIC appended header
+ UCHAR Lookahead[252]; // the first 252 bytes of the packet
+ UINT PacketLen; // the overall length of the packet
+
+ //
+ // Operational information.
+ //
+
+ UCHAR StationAddress[ETH_LENGTH_OF_ADDRESS]; // filled in at init time
+ UCHAR PermanentAddress[ETH_LENGTH_OF_ADDRESS]; // filled in at init time
+ BOOLEAN BufferOverflow; // does an overflow need to be handled
+ BOOLEAN ReceiveInProgress; // to prevent reentering indications
+
+ //
+ // Statistics used by Set/QueryInformation.
+ //
+
+ ULONG FramesXmitGood; // Good Frames Transmitted
+ ULONG FramesRcvGood; // Good Frames Received
+ ULONG FramesXmitBad; // Bad Frames Transmitted
+ ULONG FramesXmitOneCollision; // Frames Transmitted with one collision
+ ULONG FramesXmitManyCollisions; // Frames Transmitted with > 1 collision
+ ULONG FrameAlignmentErrors; // FAE errors counted
+ ULONG CrcErrors; // CRC errors counted
+ ULONG MissedPackets; // missed packet counted
+
+ //
+ // Reset information.
+ //
+
+ BOOLEAN ResetInProgress; // TRUE during a reset
+ RESET_STAGE NextResetStage; // where in the reset we are
+ struct _ELNKII_OPEN * ResetOpen; // who called ElnkiiReset
+
+
+
+ //
+ // Pointer to the filter database for the MAC.
+ //
+ PETH_FILTER FilterDB;
+
+ UCHAR NicMulticastRegs[8]; // contents of card MC registers
+ UINT ByteToWrite; // temp storage
+
+ UCHAR NicReceiveConfig; // contents of NIC RCR
+ UCHAR NicInterruptMask; // contents of NIC IMR
+
+
+ //
+ // Look Ahead information.
+ //
+
+ ULONG MaxLookAhead;
+
+
+ //
+ // Loopback information
+ //
+
+ PNDIS_PACKET LoopbackQueue; // queue of packets to loop back
+ PNDIS_PACKET LoopbackQTail;
+ PNDIS_PACKET LoopbackPacket; // current one we are looping back
+
+ //
+ // Pending operations
+ //
+
+ PELNKII_PEND_DATA PendQueue; // List of operations to complete
+ PELNKII_PEND_DATA PendQTail;
+ PELNKII_PEND_DATA PendOp; // Outstanding operation
+
+
+ NDIS_TIMER DeferredTimer;
+ PVOID DeferredDpc;
+
+ NDIS_TIMER InterruptTimer; // handles hung transmit and loopbacks to self
+
+ PVOID WakeUpDpc;
+ NDIS_TIMER WakeUpTimer;
+ BOOLEAN WakeUpFoundTransmit;
+
+ BOOLEAN Removed;
+
+} ELNKII_ADAPTER, * PELNKII_ADAPTER;
+
+
+
+
+//
+// Given a MacBindingHandle this macro returns a pointer to the
+// ELNKII_ADAPTER.
+//
+#define PELNKII_ADAPTER_FROM_BINDING_HANDLE(Handle) \
+ (((PELNKII_OPEN)(Handle))->Adapter)
+
+//
+// Given a MacContextHandle return the PELNKII_ADAPTER
+// it represents.
+//
+#define PELNKII_ADAPTER_FROM_CONTEXT_HANDLE(Handle) \
+ ((PELNKII_ADAPTER)(Handle))
+
+//
+// Given a pointer to a ELNKII_ADAPTER return the
+// proper MacContextHandle.
+//
+#define CONTEXT_HANDLE_FROM_PELNKII_ADAPTER(Ptr) \
+ ((NDIS_HANDLE)(Ptr))
+
+
+
+
+//
+// Macros to extract high and low bytes of a word.
+//
+
+#define MSB(Value) ((UCHAR)(((Value) >> 8) & 0xff))
+#define LSB(Value) ((UCHAR)((Value) & 0xff))
+
+
+//
+// One of these per open on an adapter.
+//
+
+typedef struct _ELNKII_OPEN {
+
+ //
+ // NDIS wrapper information.
+ //
+
+ NDIS_HANDLE NdisBindingContext; // passed to MacOpenAdapter
+ PSTRING AddressingInformation; // not used currently
+
+ //
+ // Links to our adapter.
+ //
+
+ PELNKII_ADAPTER Adapter;
+ struct _ELNKII_OPEN * NextOpen;
+
+ //
+ // Links to our MAC.
+ //
+
+ PMAC_BLOCK MacBlock; // faster than using AdapterBlock->MacBlock
+
+
+ //
+ // Index of this adapter in the filter database.
+ //
+ NDIS_HANDLE NdisFilterHandle;
+
+ //
+ // Indication information
+ //
+
+ UINT LookAhead;
+
+ //
+ // Reset/Close information.
+ //
+
+ UINT ReferenceCount; // number of reasons this open can't close
+ BOOLEAN Closing; // is a close pending
+
+ NDIS_REQUEST CloseFilterRequest; // Holds Requests for pending close op
+ NDIS_REQUEST CloseAddressRequest;// Holds Requests for pending close op
+
+ UINT ProtOptionFlags;
+
+} ELNKII_OPEN, * PELNKII_OPEN;
+
+
+//
+// This macro returns a pointer to a PELNKII_OPEN given a MacBindingHandle.
+//
+#define PELNKII_OPEN_FROM_BINDING_HANDLE(Handle) \
+ ((PELNKII_OPEN)(Handle))
+
+//
+// This macro returns a NDIS_HANDLE from a PELNKII_OPEN
+//
+#define BINDING_HANDLE_FROM_PELNKII_OPEN(Open) \
+ ((NDIS_HANDLE)(Open))
+
+
+
+
+
+
+typedef struct _ELNKII_REQUEST_RESERVED {
+ PNDIS_REQUEST Next; // Next NDIS_REQUEST in chain for this binding
+ ULONG OidsLeft; // Number of Oids left to process
+ PUCHAR BufferPointer; // Next available byte in information buffer
+} ELNKII_REQUEST_RESERVED, *PELNKII_REQUEST_RESERVED;
+
+
+
+// A MACRO to return a pointer to the reserved portion of an NDIS request
+#define PELNKII_RESERVED_FROM_REQUEST(Request) \
+ ((PELNKII_REQUEST_RESERVED)((Request)->MacReserved)
+
+
+//
+// What we map into the reserved section of a packet.
+// Cannot be more than 16 bytes (see ASSERT in elnkii.c).
+//
+
+typedef struct _MAC_RESERVED {
+ PNDIS_PACKET NextPacket; // used to link in the queues (4 bytes)
+ PELNKII_OPEN Open; // open that called ElnkiiSend (4 bytes)
+ BOOLEAN Loopback; // is this a loopback packet (1 byte)
+} MAC_RESERVED, * PMAC_RESERVED;
+
+
+//
+// These appear in the status field of MAC_RESERVED; they are
+// used because there is not enough room for a full NDIS_HANDLE.
+//
+
+#define RESERVED_SUCCESS ((USHORT)0)
+#define RESERVED_FAILURE ((USHORT)1)
+
+
+//
+// Retrieve the MAC_RESERVED structure from a packet.
+//
+
+#define RESERVED(Packet) ((PMAC_RESERVED)((Packet)->MacReserved))
+
+
+//
+// Procedures which log errors.
+//
+
+typedef enum _ELNKII_PROC_ID {
+ openAdapter,
+ cardReset,
+ cardCopyDownPacket,
+ cardCopyDownBuffer,
+ cardCopyUp
+} ELNKII_PROC_ID;
+
+
+#define ELNKII_ERRMSG_CARD_SETUP (ULONG)0x01
+#define ELNKII_ERRMSG_DATA_PORT_READY (ULONG)0x02
+#define ELNKII_ERRMSG_MAX_OPENS (ULONG)0x03
+#define ELNKII_ERRMSG_HANDLE_XMIT_COMPLETE (ULONG)0x04
+
+
+//++
+//
+// XMIT_BUF
+// NextBuf(
+// IN PELNKII_ADAPTER AdaptP,
+// IN XMIT_BUF XmitBuf
+// )
+//
+// Routine Description:
+//
+// NextBuf "increments" a transmit buffer number. The next
+// buffer is returned; the number goes back to 0 when it
+// reaches AdaptP->NumBuffers.
+//
+// Arguments:
+//
+// AdaptP - The adapter block.
+// XmitBuf - The current transmit buffer number.
+//
+// Return Value:
+//
+// The next transmit buffer number.
+//
+//--
+
+#define NextBuf(AdaptP, XmitBuf) \
+ ((XMIT_BUF)(((XmitBuf)+1)%(AdaptP)->NumBuffers))
+
+
+
+
+
+
+
+//
+// This macro will act a "epilogue" to every routine in the
+// *interface*. It will check whether any requests need
+// to defer their processing. It will also decrement the reference
+// count on the adapter. If the reference count is zero and there
+// is deferred work to do it will insert the interrupt processing
+// routine in the DPC queue.
+//
+// Note that we don't need to include checking for blocked receives
+// since blocked receives imply that there will eventually be an
+// interrupt.
+//
+// NOTE: This macro assumes that it is called with the lock acquired.
+//
+//
+#define ELNKII_DO_DEFERRED(Adapter) \
+{ \
+ PELNKII_ADAPTER _A = (Adapter); \
+ _A->References--; \
+ if ((!_A->References) && \
+ (_A->ResetInProgress || \
+ (_A->PendQueue != NULL) || \
+ (_A->CloseQueue != NULL))) {\
+ NdisReleaseSpinLock(&_A->Lock); \
+ NdisSetTimer(&_A->DeferredTimer, 1);\
+ } else if ((_A->XmitQueue != NULL) && \
+ (_A->BufferStatus[_A->NextBufToFill] == EMPTY)) {\
+ ElnkiiCopyAndSend(_A); \
+ NdisReleaseSpinLock(&_A->Lock); \
+ } else { \
+ NdisReleaseSpinLock(&_A->Lock); \
+ } \
+}
+
+
+
+
+//
+// Declarations for functions in elnkii.c.
+//
+
+NDIS_STATUS
+ElnkiiRegisterAdapter(
+ IN PELNKII_ADAPTER NewAdaptP,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING AdapterName,
+ IN BOOLEAN ConfigError,
+ IN ULONG ConfigErrorValue
+ );
+
+
+BOOLEAN
+ElnkiiInterruptHandler(
+ IN PVOID ServiceContext // will be a pointer to the adapter block
+ );
+
+VOID
+ElnkiiInterruptDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+VOID
+ElnkiiXmitInterruptDpc(
+ IN PELNKII_ADAPTER AdaptP
+ );
+
+
+BOOLEAN
+ElnkiiRcvInterruptDpc(
+ IN PELNKII_ADAPTER AdaptP
+ );
+
+VOID
+ElnkiiWakeUpDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+NDIS_STATUS
+ElnkiiOpenAdapter(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT NDIS_HANDLE * MacBindingHandle,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_HANDLE MacAdapterContext,
+ IN UINT OpenOptions,
+ IN PSTRING AddressingInformation OPTIONAL
+ );
+
+
+NDIS_STATUS
+ElnkiiCloseAdapter(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+VOID
+ElnkiiAdjustMaxLookAhead(
+ IN PELNKII_ADAPTER Adapter
+ );
+
+BOOLEAN
+ElnkiiAddReference(
+ IN PELNKII_OPEN OpenP
+ );
+
+NDIS_STATUS
+ElnkiiReset(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+NDIS_STATUS
+ElnkiiRequest(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+NDIS_STATUS
+ElnkiiQueryInformation(
+ IN PELNKII_ADAPTER Adapter,
+ IN PELNKII_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+NDIS_STATUS
+ElnkiiSetInformation(
+ IN PELNKII_ADAPTER Adapter,
+ IN PELNKII_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+NDIS_STATUS
+ElnkiiSetMulticastAddresses(
+ IN PELNKII_ADAPTER Adapter,
+ IN PELNKII_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT NumAddresses,
+ IN CHAR AddressList[][ETH_LENGTH_OF_ADDRESS]
+ );
+
+NDIS_STATUS
+ElnkiiSetPacketFilter(
+ IN PELNKII_ADAPTER Adapter,
+ IN PELNKII_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT PacketFilter
+ );
+
+NDIS_STATUS
+ElnkiiQueryGlobalStatistics(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+VOID
+ElnkiiUnload(
+ IN NDIS_HANDLE MacMacContext
+ );
+
+NDIS_STATUS
+ElnkiiAddAdapter(
+ IN NDIS_HANDLE NdisMacContext,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING AdapterName
+ );
+
+VOID
+ElnkiiRemoveAdapter(
+ IN PVOID MacAdapterContext
+ );
+
+VOID
+ElnkiiInterruptDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+NDIS_STATUS
+ElnkiiStage1Reset(
+ PELNKII_ADAPTER AdaptP
+ );
+
+
+NDIS_STATUS
+ElnkiiStage2Reset(
+ PELNKII_ADAPTER AdaptP
+ );
+
+
+NDIS_STATUS
+ElnkiiStage3Reset(
+ PELNKII_ADAPTER AdaptP
+ );
+
+
+NDIS_STATUS
+ElnkiiStage4Reset(
+ PELNKII_ADAPTER AdaptP
+ );
+
+
+VOID
+ElnkiiResetStageDone(
+ PELNKII_ADAPTER AdaptP,
+ RESET_STAGE StageDone
+ );
+
+
+NDIS_STATUS
+ElnkiiChangeMulticastAddresses(
+ IN UINT OldFilterCount,
+ IN CHAR OldAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN UINT NewFilterCount,
+ IN CHAR NewAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+NDIS_STATUS
+ElnkiiChangeFilterClasses(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+
+VOID
+ElnkiiCloseAction(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+
+//
+// functions in interrup.c
+//
+
+INDICATE_STATUS
+ElnkiiIndicateLoopbackPacket(
+ IN PELNKII_ADAPTER AdaptP,
+ IN PNDIS_PACKET Packet
+ );
+
+UINT
+ElnkiiCopyOver(
+ OUT PUCHAR Buf, // destination
+ IN PNDIS_PACKET Packet, // source packet
+ IN UINT Offset, // offset in packet
+ IN UINT Length // number of bytes to copy
+ );
+
+
+INDICATE_STATUS
+ElnkiiIndicatePacket(
+ IN PELNKII_ADAPTER AdaptP
+ );
+
+
+NDIS_STATUS
+ElnkiiTransferData(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+//
+// Declarations for functions in pend.c
+//
+
+VOID
+HandlePendingOperations(
+ IN PVOID SystemSpecific1,
+ IN PVOID DeferredContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+NDIS_STATUS
+DispatchSetPacketFilter(
+ IN PELNKII_ADAPTER AdaptP
+ );
+
+
+NDIS_STATUS
+DispatchSetMulticastAddressList(
+ IN PELNKII_ADAPTER AdaptP
+ );
+
+
+//
+// Declarations for functions in send.c.
+//
+
+
+NDIS_STATUS
+ElnkiiSend(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_PACKET Packet
+ );
+
+VOID
+ElnkiiCopyAndSend(
+ IN PELNKII_ADAPTER AdaptP
+ );
+
+
+
+
+
+//++
+//
+// VOID
+// AddRefWhileHoldingSpinLock(
+// IN PELNKII_ADAPTER AdaptP,
+// IN PELNKII_OPEN OpenP
+// )
+//
+// Routine Description:
+//
+// Adds a reference to an open. Similar to AddReference, but
+// called with AdaptP->Lock held.
+//
+// Arguments:
+//
+// AdaptP - The adapter block of OpenP.
+// OpenP - The open block that is being referenced.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define AddRefWhileHoldingSpinLock(AdaptP, OpenP) { \
+ ++((OpenP)->ReferenceCount); \
+}
+
+//
+// Declarations of functions in card.c.
+//
+
+
+PUCHAR
+CardGetMemBaseAddr(
+ IN PELNKII_ADAPTER AdaptP,
+ OUT PBOOLEAN CardPresent,
+ OUT PBOOLEAN IoBaseCorrect
+ );
+
+
+VOID
+CardReadEthernetAddress(
+ IN PELNKII_ADAPTER AdaptP
+ );
+
+
+BOOLEAN
+CardSetup(
+ IN PELNKII_ADAPTER AdaptP
+ );
+
+
+VOID
+CardStop(
+ IN PELNKII_ADAPTER AdaptP
+ );
+
+
+BOOLEAN
+CardTest(
+ IN PELNKII_ADAPTER AdaptP
+ );
+
+
+BOOLEAN
+CardReset(
+ IN PELNKII_ADAPTER AdaptP
+ );
+
+
+BOOLEAN
+CardCopyDownPacket(
+ IN PELNKII_ADAPTER AdaptP,
+ IN PNDIS_PACKET Packet,
+ IN XMIT_BUF XmitBufferNum,
+ OUT UINT * Length
+ );
+
+
+BOOLEAN
+CardCopyDownBuffer(
+ IN PELNKII_ADAPTER AdaptP,
+ IN PUCHAR SourceBuffer,
+ IN XMIT_BUF XmitBufferNum,
+ IN UINT Offset,
+ IN UINT Length
+ );
+
+
+BOOLEAN
+CardCopyUp(
+ IN PELNKII_ADAPTER AdaptP,
+ IN PUCHAR Target,
+ IN PUCHAR Source,
+ IN UINT Length
+ );
+
+
+ULONG
+CardComputeCrc(
+ IN PUCHAR Buffer,
+ IN UINT Length
+ );
+
+
+VOID
+CardGetPacketCrc(
+ IN PUCHAR Buffer,
+ IN UINT Length,
+ OUT UCHAR Crc[4]
+ );
+
+
+VOID
+CardGetMulticastBit(
+ IN UCHAR Address[ETH_LENGTH_OF_ADDRESS],
+ OUT UCHAR * Byte,
+ OUT UCHAR * Value
+ );
+
+
+VOID
+CardFillMulticastRegs(
+ IN PELNKII_ADAPTER AdaptP
+ );
+
+
+
+VOID
+CardSetBoundary(
+ IN PELNKII_ADAPTER AdaptP
+ );
+
+
+VOID
+CardStartXmit(
+ IN PELNKII_ADAPTER AdaptP
+ );
+
+
+
+//
+// These are the functions that are defined in sync.c and
+// are meant to be called through NdisSynchronizeWithInterrupt().
+//
+
+
+BOOLEAN
+SyncCardStop(
+ IN PVOID SynchronizeContext
+ );
+
+
+BOOLEAN
+SyncCardGetXmitStatus(
+ IN PVOID SynchronizeContext
+ );
+
+
+BOOLEAN
+SyncCardGetCurrent(
+ IN PVOID SynchronizeContext
+ );
+
+
+BOOLEAN
+SyncCardSetReceiveConfig(
+ IN PVOID SynchronizeContext
+ );
+
+
+BOOLEAN
+SyncCardSetAllMulticast(
+ IN PVOID SynchronizeContext
+ );
+
+
+BOOLEAN
+SyncCardCopyMulticastRegs(
+ IN PVOID SynchronizeContext
+ );
+
+
+BOOLEAN
+SyncCardSetInterruptMask(
+ IN PVOID SynchronizeContext
+ );
+
+
+BOOLEAN
+SyncCardAcknowledgeReceive(
+ IN PVOID SynchronizeContext
+ );
+
+
+BOOLEAN
+SyncCardAcknowledgeOverflow(
+ IN PVOID SynchronizeContext
+ );
+
+
+BOOLEAN
+SyncCardAcknowledgeTransmit(
+ IN PVOID SynchronizeContext
+ );
+
+
+BOOLEAN
+SyncCardAckAndGetCurrent(
+ IN PVOID SynchronizeContext
+ );
+
+
+BOOLEAN
+SyncCardGetXmitStatusAndAck(
+ IN PVOID SynchronizeContext
+ );
+
+
+BOOLEAN
+SyncCardUpdateCounters(
+ IN PVOID SynchronizeContext
+ );
+
+
+BOOLEAN
+SyncCardHandleOverflow(
+ IN PVOID SynchronizeContext
+ );
+
+
+/*++
+
+Routine Description:
+
+ Determines the type of the interrupt on the card. The order of
+ importance is overflow, then receive, then transmit complete.
+ Counter MSB is handled first since it is simple.
+
+Arguments:
+
+ AdaptP - pointer to the adapter block
+
+ InterruptStatus - Current Interrupt Status.
+
+Return Value:
+
+ The type of the interrupt
+
+--*/
+
+#define CardGetInterruptType(_A, _I, _R) \
+{ \
+ if (_I & ISR_COUNTER) { \
+ _R = COUNTER; \
+ } else if (_I & ISR_OVERFLOW ) { \
+ SyncCardUpdateCounters(_A); \
+ _R = OVERFLOW; \
+ } else if (_I & ISR_RCV) { \
+ if (_A->ReceivePacketCount < 10) { \
+ _R = RECEIVE; \
+ } else { \
+ _A->ReceivePacketCount=0; \
+ if (_I & (ISR_XMIT|ISR_XMIT_ERR)) { \
+ _R = TRANSMIT; \
+ } else { \
+ _R = RECEIVE; \
+ } \
+ } \
+ } else { \
+ _A->ReceivePacketCount=0; \
+ if (_I & (ISR_XMIT|ISR_XMIT_ERR)) { \
+ _R = TRANSMIT; \
+ } else if (_I & ISR_RCV_ERR) { \
+ SyncCardUpdateCounters(_A); \
+ _R = RECEIVE; \
+ } else { \
+ _R = UNKNOWN; \
+ } \
+ } \
+}
+
+#endif // ELNKIISFT
+
+
+
+
+
+
+
diff --git a/private/ntos/ndis/elnkii/interrup.c b/private/ntos/ndis/elnkii/interrup.c
new file mode 100644
index 000000000..109d5efc9
--- /dev/null
+++ b/private/ntos/ndis/elnkii/interrup.c
@@ -0,0 +1,2426 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ interrup.c
+
+Abstract:
+
+ This is a part of the driver for the National Semiconductor ElnkII
+ Ethernet controller. It contains the interrupt-handling routines.
+ This driver conforms to the NDIS 3.0 interface.
+
+ The overall structure and much of the code is taken from
+ the Lance NDIS driver by Tony Ercolano.
+
+Author:
+
+ Sean Selitrennikoff (seanse) Dec-1991
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+--*/
+
+#include <ndis.h>
+#include <efilter.h>
+#include "elnkhrd.h"
+#include "elnksft.h"
+
+
+#if DBG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+#if DBG
+extern ULONG ElnkiiSendsCompletedAfterPendOk;
+extern ULONG ElnkiiSendsCompletedAfterPendFail;
+#endif
+
+
+UCHAR ElnkiiBroadcastAddress[ETH_LENGTH_OF_ADDRESS] =
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+
+//
+// This is used to pad short packets.
+//
+
+static UCHAR BlankBuffer[60] = " ";
+
+
+#if DBG
+ULONG ElnkiiSendsIssued = 0;
+ULONG ElnkiiSendsFailed = 0;
+ULONG ElnkiiSendsPended = 0;
+ULONG ElnkiiSendsCompletedImmediately = 0;
+ULONG ElnkiiSendsCompletedAfterPendOk = 0;
+ULONG ElnkiiSendsCompletedAfterPendFail = 0;
+ULONG ElnkiiSendsCompletedForReset = 0;
+#endif
+
+
+#if DBG
+
+#define ELNKII_LOG_SIZE 256
+UCHAR ElnkiiLogBuffer[ELNKII_LOG_SIZE]={0};
+UCHAR ElnkiiLogSaveBuffer[ELNKII_LOG_SIZE]={0};
+UINT ElnkiiLogLoc = 0;
+BOOLEAN ElnkiiLogSave = FALSE;
+UINT ElnkiiLogSaveLoc = 0;
+UINT ElnkiiLogSaveLeft = 0;
+
+extern
+VOID
+ElnkiiLog(UCHAR c) {
+
+ ElnkiiLogBuffer[ElnkiiLogLoc++] = c;
+
+ ElnkiiLogBuffer[(ElnkiiLogLoc + 4) % ELNKII_LOG_SIZE] = '\0';
+
+ if (ElnkiiLogLoc >= ELNKII_LOG_SIZE) ElnkiiLogLoc = 0;
+}
+
+#endif
+
+
+#if DBG
+
+#define PACKET_LIST_SIZE 256
+
+static PNDIS_PACKET PacketList[PACKET_LIST_SIZE] = {0};
+static PacketListSize = 0;
+
+VOID
+AddPacketToList(
+ PELNKII_ADAPTER Adapter,
+ PNDIS_PACKET NewPacket
+ )
+{
+ INT i;
+
+ UNREFERENCED_PARAMETER(Adapter);
+
+ for (i=0; i<PacketListSize; i++) {
+
+ if (PacketList[i] == NewPacket) {
+
+ DbgPrint("dup send of %lx\n", NewPacket);
+
+ }
+
+ }
+
+ PacketList[PacketListSize] = NewPacket;
+
+ ++PacketListSize;
+
+}
+
+VOID
+RemovePacketFromList(
+ PELNKII_ADAPTER Adapter,
+ PNDIS_PACKET OldPacket
+ )
+{
+ INT i;
+
+ UNREFERENCED_PARAMETER(Adapter);
+
+ for (i=0; i<PacketListSize; i++) {
+
+ if (PacketList[i] == OldPacket) {
+
+ break;
+
+ }
+
+ }
+
+ if (i == PacketListSize) {
+
+ DbgPrint("bad remove of %lx\n", OldPacket);
+
+ } else {
+
+ --PacketListSize;
+
+ PacketList[i] = PacketList[PacketListSize];
+
+ }
+
+}
+
+#endif // DBG
+
+
+
+BOOLEAN
+ElnkiiInterruptHandler(
+ IN PVOID ServiceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This is the interrupt handler which is registered with the operating
+ system. Only one interrupt is handled at one time, even if several
+ are pending (i.e. transmit complete and receive).
+
+Arguments:
+
+ ServiceContext - pointer to the adapter object
+
+Return Value:
+
+ TRUE, if the DPC is to be executed, otherwise FALSE.
+
+--*/
+
+{
+ PELNKII_ADAPTER AdaptP = ((PELNKII_ADAPTER)ServiceContext);
+
+ IF_LOG( ElnkiiLog('i');)
+ IF_LOUD( DbgPrint("In ElnkISR\n");)
+
+ IF_VERY_LOUD( DbgPrint( "ElnkiiInterruptHandler entered\n" );)
+
+ if (AdaptP->InCardTest) {
+
+ //
+ // Ignore these random interrupts
+ //
+
+ IF_LOG( ElnkiiLog('I'); )
+ return(FALSE);
+
+ }
+
+ //
+ // Force the INT signal from the chip low. When the
+ // interrupt is acknowledged interrupts will be unblocked,
+ // which will cause a rising edge on the interrupt line
+ // if there is another interrupt pending on the card.
+ //
+
+ IF_LOUD( DbgPrint( " blocking interrupts\n" ); )
+
+ CardBlockInterrupts(AdaptP);
+
+ IF_LOG( ElnkiiLog('I'); )
+
+ return(TRUE);
+
+}
+
+VOID
+ElnkiiInterruptDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+/*++
+
+Routine Description:
+
+ This is the deffered processing routine for interrupts, it examines the
+ 'InterruptReg' to determine what deffered processing is necessary
+ and dispatches control to the Rcv and Xmt handlers.
+
+Arguments:
+ SystemSpecific1, SystemSpecific2, SystemSpecific3 - not used
+ InterruptContext - a handle to the adapter block.
+
+Return Value:
+
+ NONE.
+
+--*/
+{
+ PELNKII_ADAPTER AdaptP = ((PELNKII_ADAPTER)InterruptContext);
+
+ UCHAR InterruptStatus;
+ INTERRUPT_TYPE InterruptType;
+
+ UNREFERENCED_PARAMETER(SystemSpecific1);
+ UNREFERENCED_PARAMETER(SystemSpecific2);
+ UNREFERENCED_PARAMETER(SystemSpecific3);
+
+ IF_LOUD( DbgPrint("==>IntDpc\n");)
+
+ NdisDprAcquireSpinLock(&AdaptP->Lock);
+
+ AdaptP->References++;
+
+ //
+ // Get the interrupt bits
+ //
+
+ CardGetInterruptStatus(AdaptP, &InterruptStatus);
+
+ if (InterruptStatus != ISR_EMPTY) {
+
+ NdisRawWritePortUchar((AdaptP)->MappedIoBaseAddr+NIC_INTR_STATUS, InterruptStatus);
+
+ //
+ // InterruptStatus bits are used to dispatch to correct DPC and then cleared.
+ //
+
+ CardGetInterruptType(AdaptP,InterruptStatus, InterruptType);
+
+ } else {
+
+ InterruptType = UNKNOWN;
+
+ }
+
+
+ do {
+
+ while ((InterruptType != UNKNOWN) ||
+ ((AdaptP->LoopbackQueue != NULL) &&
+ !(AdaptP->ReceiveInProgress || AdaptP->ResetInProgress))) {
+
+ //
+ // Handle interrupts
+ //
+
+ switch (InterruptType) {
+
+ case COUNTER:
+ //
+ // One of the counters' MSB has been set, read in all
+ // the values just to be sure (and then exit below).
+ //
+
+ IF_LOUD( DbgPrint("DPC got COUNTER\n"); )
+
+ SyncCardUpdateCounters((PVOID)AdaptP);
+
+ InterruptStatus &= ~ISR_COUNTER; //clear the COUNTER interrupt bit.
+
+ break;
+
+ case OVERFLOW:
+
+ //
+ // Overflow interrupts are handled as part of a receive
+ // interrupt, so set a flag and then pretend to be a
+ // receive, in case there is no receive already being handled.
+ //
+
+ AdaptP->BufferOverflow = TRUE;
+
+ //
+ // Check if a send completed before the overflow came in.
+ //
+
+ if (AdaptP->TransmitInterruptPending &&
+ !(InterruptStatus & (ISR_XMIT | ISR_XMIT_ERR))) {
+
+ IF_LOG( ElnkiiLog('|');)
+
+ InterruptStatus |= ISR_XMIT;
+
+ AdaptP->OverflowRestartXmitDpc = FALSE;
+
+ }
+
+ IF_LOUD( DbgPrint("Overflow Int\n"); )
+ IF_VERY_LOUD( DbgPrint( " overflow interrupt\n" ); )
+
+ InterruptStatus &= ~ISR_OVERFLOW;
+
+
+ case RECEIVE:
+
+ //
+ // For receives, call this to ensure that another interrupt
+ // won't happen until the driver is ready.
+ //
+
+ IF_LOG( ElnkiiLog('R');)
+ IF_LOUD( DbgPrint("DPC got RCV\n"); )
+
+ if (!AdaptP->ReceiveInProgress) {
+
+ if (ElnkiiRcvInterruptDpc(AdaptP)) {
+
+ InterruptStatus &= ~(ISR_RCV | ISR_RCV_ERR);
+
+ }
+
+ } else {
+
+ //
+ // We can do this because the DPC in the RcvDpc will
+ // handle all the interrupts.
+ //
+
+ InterruptStatus &= ~(ISR_RCV | ISR_RCV_ERR);
+
+ }
+
+ break;
+
+ case TRANSMIT:
+
+ IF_LOG( ElnkiiLog('X');)
+
+#if DBG
+
+ ElnkiiLogSave = FALSE;
+
+#endif
+
+ //
+ // Acknowledge transmit interrupt now, because of MP systems we
+ // can get an interrupt from a receive that will look like a
+ // transmit interrupt because we haven't cleared the bit in the
+ // ISR. We are not concerned about multiple Receive interrupts
+ // since the receive handler guards against being entered twice.
+ //
+ // Since only one transmit interrupt can be pending at a time
+ // we know that no-one else can enter here now...
+ //
+ //
+ // This puts the result of the transmit in AdaptP->XmitStatus.
+ // SyncCardGetXmitStatus(AdaptP);
+ //
+
+ IF_LOUD( DbgPrint( " acking transmit interrupt\n" ); )
+
+ SyncCardGetXmitStatus(AdaptP);
+
+ AdaptP->WakeUpFoundTransmit = FALSE;
+
+ //
+ // This may be false if the card is currently handling an
+ // overflow and will restart the Dpc itself.
+ //
+ //
+ // If overflow handling then clear the transmit interrupt
+ //
+
+ ASSERT(!AdaptP->OverflowRestartXmitDpc);
+
+ if (AdaptP->ElnkiiHandleXmitCompleteRunning) {
+
+#if DBG
+ DbgBreakPoint();
+#endif
+
+ } else {
+
+ AdaptP->TransmitInterruptPending = FALSE;
+
+ ElnkiiXmitInterruptDpc(AdaptP);
+
+ }
+
+ IF_LOUD( DbgPrint( "DPC got XMIT\n" ); )
+
+ InterruptStatus &= ~(ISR_XMIT|ISR_XMIT_ERR);
+
+ break;
+
+ default:
+
+ //
+ // Create a rising edge on the interrupt line.
+ //
+
+ IF_LOUD( DbgPrint( "unhandled interrupt type: %x", InterruptType); )
+
+ break;
+ }
+
+ //
+ // Handle loopback
+ //
+
+ if ((AdaptP->LoopbackQueue != NULL) &&
+ !(AdaptP->ReceiveInProgress || AdaptP->ResetInProgress)) {
+
+ ElnkiiRcvInterruptDpc(AdaptP);
+
+ }
+
+ CardGetInterruptType(AdaptP,InterruptStatus, InterruptType);
+
+ }
+
+ CardGetInterruptStatus(AdaptP, &InterruptStatus);
+
+ if (InterruptStatus != ISR_EMPTY) {
+
+ NdisRawWritePortUchar((AdaptP)->MappedIoBaseAddr+NIC_INTR_STATUS, InterruptStatus);
+
+ }
+
+ CardGetInterruptType(AdaptP,InterruptStatus,InterruptType);
+
+ } while (InterruptType != UNKNOWN); // ISR says there's nothing left to do.
+
+ //
+ // Turn the IMR back on.
+ //
+
+ IF_LOUD( DbgPrint( " unblocking interrupts\n" ); )
+
+ AdaptP->NicInterruptMask = IMR_RCV | IMR_XMIT_ERR | IMR_XMIT | IMR_OVERFLOW;
+
+ CardUnblockInterrupts(AdaptP);
+
+ ELNKII_DO_DEFERRED(AdaptP);
+
+ IF_LOUD( DbgPrint("<==IntDpc\n");)
+
+}
+
+
+BOOLEAN
+ElnkiiRcvInterruptDpc(
+ IN PELNKII_ADAPTER AdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ This is the real interrupt handler for receive/overflow interrupt.
+ The ElnkiiInterruptDpc calls it directly. It calls ElnkiiHandleReceive
+ if that function is not already executing (since it runs at DPC, this
+ would only be happening on a multiprocessor system (i.e. later DPC calls
+ will not run until previous ones are complete on a particular processor)).
+
+ NOTE: Called with the lock held!!!
+
+Arguments:
+
+ DeferredContext - A pointer to the adapter block.
+
+Return Value:
+
+ TRUE if done with all receives, else FALSE
+
+--*/
+
+{
+ PELNKII_OPEN TmpOpen;
+ PNDIS_PACKET LPacket;
+ PMAC_RESERVED Reserved;
+ BOOLEAN TransmitInterruptWasPending = FALSE;
+ INDICATE_STATUS IndicateStatus = INDICATE_OK;
+ BOOLEAN Done = TRUE;
+
+ //
+ // Do nothing if a RECEIVE is already being handled.
+ //
+
+ IF_LOUD( DbgPrint( "ElnkiiRcvInterruptDpc entered\n" );)
+
+ AdaptP->ReceiveInProgress = TRUE;
+
+ //
+ // At this point receive interrupts are disabled.
+ //
+
+ if (!AdaptP->ResetInProgress && AdaptP->BufferOverflow) {
+
+ NdisSynchronizeWithInterrupt(
+ &(AdaptP->NdisInterrupt),
+ (PVOID)SyncCardHandleOverflow,
+ (PVOID)AdaptP
+ );
+
+ }
+
+ //
+ // Loop
+ //
+
+ SyncCardGetCurrent(AdaptP);
+
+ while (!AdaptP->ResetInProgress) {
+
+ if (AdaptP->Current != AdaptP->NicNextPacket) {
+
+ AdaptP->LoopbackPacket = (PNDIS_PACKET)NULL;
+
+ AdaptP->ReceivePacketCount++;
+
+ NdisDprReleaseSpinLock(&AdaptP->Lock);
+
+ IndicateStatus = ElnkiiIndicatePacket(AdaptP);
+
+ NdisDprAcquireSpinLock(&AdaptP->Lock);
+
+ if (IndicateStatus == CARD_BAD) {
+
+ IF_LOG( ElnkiiLog('W');)
+
+ AdaptP->NicInterruptMask = IMR_XMIT | IMR_XMIT_ERR | IMR_OVERFLOW ;
+
+ CardReset(AdaptP);
+
+ break;
+
+ }
+
+ //
+ // Free the space used by packet on card.
+ //
+
+ AdaptP->NicNextPacket = AdaptP->PacketHeader[1];
+
+ //
+ // This will set BOUNDARY to one behind NicNextPacket.
+ //
+
+ CardSetBoundary(AdaptP);
+
+ if (AdaptP->ReceivePacketCount > 10) {
+
+ //
+ // Give transmit interrupts a chance
+ //
+
+ Done = FALSE;
+ AdaptP->ReceivePacketCount = 0;
+ break;
+
+ }
+
+ } else {
+
+ SyncCardGetCurrent(AdaptP);
+
+ if (AdaptP->Current == AdaptP->NicNextPacket) {
+
+ //
+ // End of loop -- no more packets
+ //
+
+ break;
+
+ }
+
+ }
+
+ }
+
+
+ if (AdaptP->BufferOverflow) {
+
+ IF_VERY_LOUD( DbgPrint( " overflow\n" ); )
+
+ AdaptP->BufferOverflow = FALSE;
+
+ NdisSynchronizeWithInterrupt( &(AdaptP->NdisInterrupt),
+ (PVOID)SyncCardAcknowledgeOverflow,
+ (PVOID)AdaptP );
+
+ //
+ // Undo loopback mode
+ //
+
+ CardStart(AdaptP);
+
+ IF_LOG ( ElnkiiLog('f');)
+
+ //
+ // Check if transmission needs to be queued or not
+ //
+
+ if (AdaptP->OverflowRestartXmitDpc && (AdaptP->CurBufXmitting != -1)) {
+
+ IF_LOG( ElnkiiLog('?');)
+
+ AdaptP->OverflowRestartXmitDpc = FALSE;
+
+ AdaptP->WakeUpFoundTransmit = FALSE;
+
+ AdaptP->TransmitInterruptPending = TRUE;
+
+ CardStartXmit(AdaptP);
+
+ }
+
+ }
+
+ //
+ // Now handle loopback packets.
+ //
+
+ IF_LOUD( DbgPrint( " checking loopback queue\n" );)
+
+ while (AdaptP->LoopbackQueue && !AdaptP->ResetInProgress) {
+
+ //
+ // Take the first packet off the loopback queue...
+ //
+
+ LPacket = AdaptP->LoopbackQueue;
+
+ Reserved = RESERVED(LPacket);
+
+ AdaptP->LoopbackQueue = RESERVED(AdaptP->LoopbackQueue)->NextPacket;
+
+ AdaptP->LoopbackPacket = LPacket;
+
+ AdaptP->FramesXmitGood++;
+
+ //
+ // Save this, since once we complete the send
+ // Reserved is no longer valid.
+ //
+
+ TmpOpen = Reserved->Open;
+
+#if DBG
+ IF_ELNKIIDEBUG( ELNKII_DEBUG_CHECK_DUP_SENDS ) {
+
+ RemovePacketFromList(AdaptP, LPacket);
+
+ }
+
+ ElnkiiSendsCompletedAfterPendOk++;
+#endif
+
+ //
+ // ... and indicate it.
+ //
+
+ NdisDprReleaseSpinLock(&AdaptP->Lock);
+
+ ElnkiiIndicateLoopbackPacket(AdaptP, AdaptP->LoopbackPacket);
+
+ //
+ // Complete the packet send.
+ //
+
+ NdisCompleteSend(
+ Reserved->Open->NdisBindingContext,
+ LPacket,
+ NDIS_STATUS_SUCCESS
+ );
+
+
+ NdisDprAcquireSpinLock(&AdaptP->Lock);
+
+ TmpOpen->ReferenceCount--;
+ }
+
+ //
+ // All receives are now done. Allow the receive indicator to run again.
+ //
+
+ AdaptP->ReceiveInProgress = FALSE;
+
+ if (AdaptP->ResetInProgress) {
+
+ return Done;
+
+ }
+
+ IF_LOUD( DbgPrint( " clearing ReceiveInProgress\n" );)
+
+ NdisDprReleaseSpinLock(&AdaptP->Lock);
+
+ //
+ // Finally, indicate ReceiveComplete to all protocols which received packets
+ //
+
+ EthFilterIndicateReceiveComplete(AdaptP->FilterDB);
+
+ NdisDprAcquireSpinLock(&AdaptP->Lock);
+
+ IF_LOUD( DbgPrint( "ElnkiiRcvInterruptDpc exiting\n" );)
+
+ return(Done);
+
+}
+
+VOID
+ElnkiiXmitInterruptDpc(
+ IN PELNKII_ADAPTER AdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ This is the real interrupt handler for a transmit complete interrupt.
+ ElnkiiInterrupt queues a call to it. It calls ElnkiiHandleXmitComplete.
+
+ NOTE : Called with the spinlock held!! and returns with it released!!!
+
+Arguments:
+
+ AdaptP - A pointer to the adapter block.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ XMIT_BUF TmpBuf;
+
+ PNDIS_PACKET Packet;
+ PMAC_RESERVED Reserved;
+ PELNKII_OPEN TmpOpen;
+
+ IF_VERY_LOUD( DbgPrint( "ElnkiiXmitInterruptDpc entered\n" );)
+
+ AdaptP->WakeUpFoundTransmit = FALSE;
+
+ IF_LOG( ElnkiiLog('C');)
+
+ AdaptP->ElnkiiHandleXmitCompleteRunning = TRUE;
+
+ if (AdaptP->CurBufXmitting == -1)
+ {
+ AdaptP->ElnkiiHandleXmitCompleteRunning = FALSE;
+
+ return;
+ }
+
+ //
+ // CurBufXmitting is not -1, which means nobody else
+ // will touch it.
+ //
+ Packet = AdaptP->Packets[AdaptP->CurBufXmitting];
+
+ ASSERT(Packet != (PNDIS_PACKET)NULL);
+
+ Reserved = RESERVED(Packet);
+
+ IF_LOUD( DbgPrint( "packet is 0x%lx\n", Packet );)
+
+#if DBG
+
+ if ((AdaptP->XmitStatus & TSR_XMIT_OK) == 0) {
+ IF_LOG(ElnkiiLog('E');)
+ IF_LOG(ElnkiiLog((UCHAR)AdaptP->XmitStatus);)
+ }
+
+ IF_ELNKIIDEBUG( ELNKII_DEBUG_CHECK_DUP_SENDS ) {
+ RemovePacketFromList(AdaptP, Packet);
+ }
+
+#endif
+
+
+ if (!Reserved->Loopback) {
+
+
+ //
+ // Complete the send if it is not to be loopbacked.
+ //
+
+ if (AdaptP->XmitStatus & TSR_XMIT_OK) {
+
+ AdaptP->FramesXmitGood++;
+
+#if DBG
+ ElnkiiSendsCompletedAfterPendOk++;
+
+#endif
+
+ } else {
+
+ AdaptP->FramesXmitBad++;
+
+#if DBG
+ ElnkiiSendsCompletedAfterPendFail++;
+#endif
+
+ }
+
+ //
+ // Save this, since once we complete the send
+ // Reserved is no longer valid.
+ //
+
+ TmpOpen = Reserved->Open;
+
+ IF_LOG( ElnkiiLog('p');)
+
+ NdisDprReleaseSpinLock(&AdaptP->Lock);
+
+ NdisCompleteSend(Reserved->Open->NdisBindingContext,
+ Packet,
+ AdaptP->XmitStatus & TSR_XMIT_OK ?
+ NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE);
+
+ NdisDprAcquireSpinLock(&AdaptP->Lock);
+
+ TmpOpen->ReferenceCount--;
+
+ } else {
+
+ //
+ // Put it on the loopback queue
+ //
+
+ if (AdaptP->LoopbackQueue == (PNDIS_PACKET)NULL) {
+
+ AdaptP->LoopbackQueue = Packet;
+ AdaptP->LoopbackQTail = Packet;
+
+ } else {
+
+ RESERVED(AdaptP->LoopbackQTail)->NextPacket = Packet;
+ AdaptP->LoopbackQTail = Packet;
+
+ }
+
+ Reserved->NextPacket = (PNDIS_PACKET)NULL;
+
+ }
+
+ //
+ // Mark the current transmit as done.
+ //
+
+ AdaptP->Packets[AdaptP->CurBufXmitting] = (PNDIS_PACKET)NULL;
+
+ AdaptP->BufferStatus[AdaptP->CurBufXmitting] = EMPTY;
+
+ TmpBuf = NextBuf(AdaptP, AdaptP->CurBufXmitting);
+
+ //
+ // See what to do next.
+ //
+
+ switch (AdaptP->BufferStatus[TmpBuf]) {
+
+
+ case FULL:
+
+ //
+ // The next packet is ready to go -- only happens with
+ // more than one transmit buffer.
+ //
+
+ IF_LOUD( DbgPrint( " next packet ready to go\n" );)
+
+ if (AdaptP->ResetInProgress) {
+
+ //
+ // A reset just started, abort.
+ //
+
+ AdaptP->CurBufXmitting = -1;
+
+ AdaptP->BufferStatus[TmpBuf] = EMPTY; // to ack the reset
+
+ AdaptP->ElnkiiHandleXmitCompleteRunning = FALSE;
+
+ NdisDprReleaseSpinLock(&AdaptP->Lock);
+
+ ElnkiiResetStageDone(AdaptP, XMIT_STOPPED);
+
+ NdisDprAcquireSpinLock(&AdaptP->Lock);
+
+ } else {
+
+ //
+ // Start the transmission and check for more.
+ //
+
+ AdaptP->CurBufXmitting = TmpBuf;
+
+ IF_LOG( ElnkiiLog('2');)
+
+#if DBG
+
+ ElnkiiLogSave = TRUE;
+ ElnkiiLogSaveLeft = 20;
+
+#endif
+
+ AdaptP->ElnkiiHandleXmitCompleteRunning = FALSE;
+
+ //
+ // If we are currently handling an overflow, then we need to let
+ // the overflow handler send this packet...
+ //
+
+ if (AdaptP->BufferOverflow) {
+
+ AdaptP->OverflowRestartXmitDpc = TRUE;
+
+ IF_LOG( ElnkiiLog('O');)
+
+ } else {
+
+ //
+ // This is used to check if stopping the chip prevented
+ // a transmit complete interrupt from coming through (it
+ // is cleared in the ISR if a transmit DPC is queued).
+ //
+
+ AdaptP->TransmitInterruptPending = TRUE;
+
+ CardStartXmit(AdaptP);
+
+ }
+
+ ElnkiiCopyAndSend(AdaptP);
+
+ }
+
+ break;
+
+
+ case FILLING:
+
+ //
+ // The next packet will be started when copying down is finished.
+ //
+
+ IF_LOUD( DbgPrint( " next packet filling\n" );)
+
+ AdaptP->CurBufXmitting = -1;
+
+ AdaptP->NextBufToXmit = TmpBuf;
+
+ //
+ // If AdaptP->NextBufToFill is not TmpBuf, this
+ // will check to make sure NextBufToFill is not
+ // waiting to be filled.
+ //
+
+ AdaptP->ElnkiiHandleXmitCompleteRunning = FALSE;
+
+ ElnkiiCopyAndSend(AdaptP);
+
+ break;
+
+
+ case EMPTY:
+
+ //
+ // No packet is ready to transmit.
+ //
+
+ IF_LOUD( DbgPrint( " next packet empty\n" );)
+
+ if (AdaptP->ResetInProgress) {
+
+ //
+ // A reset has just started, exit.
+ //
+
+ AdaptP->CurBufXmitting = -1;
+
+ AdaptP->ElnkiiHandleXmitCompleteRunning = FALSE;
+
+ NdisDprReleaseSpinLock(&AdaptP->Lock);
+
+ ElnkiiResetStageDone(AdaptP, XMIT_STOPPED);
+
+ NdisDprAcquireSpinLock(&AdaptP->Lock);
+
+ break;
+
+ }
+
+
+ if (AdaptP->XmitQueue != (PNDIS_PACKET)NULL) {
+
+ //
+ // Take the packet off the head of the queue.
+ //
+ // There will be a packet on the queue with
+ // BufferStatus[TmpBuf] == EMPTY only when we
+ // have only one transmit buffer.
+ //
+
+ IF_LOUD( DbgPrint( " transmit queue not empty\n" );)
+
+ Packet = AdaptP->XmitQueue;
+
+ AdaptP->XmitQueue = RESERVED(AdaptP->XmitQueue)->NextPacket;
+
+
+ //
+ // At this point, NextBufToFill should equal TmpBuf.
+ //
+
+ AdaptP->NextBufToFill = NextBuf(AdaptP, TmpBuf);
+
+
+ //
+ // Set this now, to avoid having to get spinlock between
+ // copying and transmission start.
+ //
+
+ AdaptP->BufferStatus[TmpBuf] = FULL;
+
+ AdaptP->Packets[TmpBuf] = Packet;
+ AdaptP->CurBufXmitting = TmpBuf;
+
+ IF_LOG( ElnkiiLog('3');)
+
+#if DBG
+
+ ElnkiiLogSave = TRUE;
+ ElnkiiLogSaveLeft = 20;
+
+#endif
+
+ NdisDprReleaseSpinLock(&AdaptP->Lock);
+
+
+ //
+ // Copy down the data, pad short packets with blanks.
+ //
+
+ (VOID)CardCopyDownPacket(AdaptP, Packet, TmpBuf,
+ &AdaptP->PacketLens[TmpBuf]);
+
+ if (AdaptP->PacketLens[TmpBuf] < 60) {
+
+ (VOID)CardCopyDownBuffer(
+ AdaptP,
+ BlankBuffer,
+ TmpBuf,
+ AdaptP->PacketLens[TmpBuf],
+ 60-AdaptP->PacketLens[TmpBuf]
+ );
+
+ }
+
+
+ NdisDprAcquireSpinLock(&AdaptP->Lock);
+
+ AdaptP->ElnkiiHandleXmitCompleteRunning = FALSE;
+
+ //
+ // If we are currently handling an overflow, then we need to let
+ // the overflow handler send this packet...
+ //
+
+ if (AdaptP->BufferOverflow) {
+
+ AdaptP->OverflowRestartXmitDpc = TRUE;
+
+ IF_LOG( ElnkiiLog('O');)
+
+ } else {
+
+ //
+ // This is used to check if stopping the chip prevented
+ // a transmit complete interrupt from coming through (it
+ // is cleared in the ISR if a transmit DPC is queued).
+ //
+
+ AdaptP->TransmitInterruptPending = TRUE;
+
+ CardStartXmit(AdaptP);
+
+ }
+
+ //
+ // It makes no sense to call ElnkiiCopyAndSend because
+ // there is only one transmit buffer, and it was just
+ // filled.
+ //
+
+ } else {
+
+ //
+ // No packets are waiting on the transmit queue.
+ //
+
+ AdaptP->CurBufXmitting = -1;
+
+ AdaptP->NextBufToXmit = TmpBuf;
+
+ AdaptP->ElnkiiHandleXmitCompleteRunning = FALSE;
+
+ }
+
+ break;
+
+ default:
+
+ AdaptP->ElnkiiHandleXmitCompleteRunning = FALSE;
+
+ }
+
+ IF_VERY_LOUD( DbgPrint( "ElnkiiXmitInterruptDpc exiting\n" );)
+
+}
+
+INDICATE_STATUS
+ElnkiiIndicateLoopbackPacket(
+ IN PELNKII_ADAPTER AdaptP,
+ IN PNDIS_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ Indicates an NDIS_format packet to the protocols. This is used
+ for indicating packets from the loopback queue.
+
+Arguments:
+
+ AdaptP - pointer to the adapter block
+ Packet - the packet to be indicated
+
+Return Value:
+
+ SKIPPED if it is a run packet
+ INDICATE_OK otherwise.
+
+--*/
+
+{
+ UINT IndicateLen;
+ UINT PacketLen;
+
+ //
+ // Indicate up to 252 bytes.
+ //
+
+ NdisQueryPacket(Packet,
+ NULL,
+ NULL,
+ NULL,
+ &PacketLen
+ );
+
+ if (PacketLen < ETH_LENGTH_OF_ADDRESS) {
+
+ //
+ // A runt packet.
+ //
+
+ return SKIPPED;
+
+ }
+
+ IndicateLen = (PacketLen > AdaptP->MaxLookAhead) ?
+ AdaptP->MaxLookAhead : PacketLen;
+
+ //
+ // Copy the lookahead data into a contiguous buffer.
+ //
+
+ ElnkiiCopyOver(AdaptP->Lookahead,
+ Packet,
+ 0,
+ IndicateLen
+ );
+
+ if (IndicateLen < ELNKII_HEADER_SIZE) {
+
+ //
+ // Must have at least the address
+ //
+
+ if (IndicateLen > 5) {
+
+ //
+ // Runt packet
+ //
+
+ EthFilterIndicateReceive(
+ AdaptP->FilterDB,
+ (NDIS_HANDLE)AdaptP,
+ (PCHAR)AdaptP->Lookahead,
+ AdaptP->Lookahead,
+ IndicateLen,
+ NULL,
+ 0,
+ 0
+ );
+ }
+
+ } else {
+
+ //
+ // Indicate packet
+ //
+
+ EthFilterIndicateReceive(
+ AdaptP->FilterDB,
+ (NDIS_HANDLE)AdaptP,
+ (PCHAR)AdaptP->Lookahead,
+ AdaptP->Lookahead,
+ ELNKII_HEADER_SIZE,
+ AdaptP->Lookahead + ELNKII_HEADER_SIZE,
+ IndicateLen - ELNKII_HEADER_SIZE,
+ PacketLen - ELNKII_HEADER_SIZE
+ );
+ }
+
+ return INDICATE_OK;
+}
+
+UINT
+ElnkiiCopyOver(
+ OUT PUCHAR Buf, // destination
+ IN PNDIS_PACKET Packet, // source packet
+ IN UINT Offset, // offset in packet
+ IN UINT Length // number of bytes to copy
+ )
+
+/*++
+
+Routine Description:
+
+ Copies bytes from a packet into a buffer. Used to copy data
+ out of a packet during loopback indications.
+
+Arguments:
+
+ Buf - the destination buffer
+ Packet - the source packet
+ Offset - the offset in the packet to start copying at
+ Length - the number of bytes to copy
+
+Return Value:
+
+ The actual number of bytes copied; will be less than Length if
+ the packet length is less than Offset+Length.
+
+--*/
+
+{
+ PNDIS_BUFFER CurBuffer;
+ UINT BytesCopied;
+ PUCHAR BufVA;
+ UINT BufLen;
+ UINT ToCopy;
+ UINT CurOffset;
+
+
+ BytesCopied = 0;
+
+ //
+ // First find a spot Offset bytes into the packet.
+ //
+
+ CurOffset = 0;
+
+ NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, NULL);
+
+ while (CurBuffer != (PNDIS_BUFFER)NULL) {
+
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufVA, &BufLen);
+
+ if (CurOffset + BufLen > Offset) {
+
+ break;
+
+ }
+
+ CurOffset += BufLen;
+
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+
+ }
+
+
+ //
+ // See if the end of the packet has already been passed.
+ //
+
+ if (CurBuffer == (PNDIS_BUFFER)NULL) {
+
+ return 0;
+
+ }
+
+
+ //
+ // Now copy over Length bytes.
+ //
+
+ BufVA += (Offset - CurOffset);
+
+ BufLen -= (Offset - CurOffset);
+
+ for (;;) {
+
+ ToCopy = (BytesCopied+BufLen > Length) ? Length - BytesCopied : BufLen;
+
+ ELNKII_MOVE_MEM(Buf+BytesCopied, BufVA, ToCopy);
+
+ BytesCopied += ToCopy;
+
+
+ if (BytesCopied == Length) {
+
+ return BytesCopied;
+
+ }
+
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+
+ if (CurBuffer == (PNDIS_BUFFER)NULL) {
+
+ break;
+
+ }
+
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufVA, &BufLen);
+
+ }
+
+ return BytesCopied;
+
+}
+
+INDICATE_STATUS
+ElnkiiIndicatePacket(
+ IN PELNKII_ADAPTER AdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ Indicates the first packet on the card to the protocols.
+
+Arguments:
+
+ AdaptP - pointer to the adapter block.
+
+Return Value:
+
+ CARD_BAD if the card should be reset;
+ INDICATE_OK otherwise.
+
+--*/
+
+{
+ UINT PacketLen;
+ PUCHAR PacketLoc;
+ PUCHAR IndicateBuf;
+ UINT IndicateLen;
+ UCHAR PossibleNextPacket1, PossibleNextPacket2;
+
+
+ //
+ // First copy up the four-byte header the card attaches.
+ //
+
+ PacketLoc = AdaptP->PageStart +
+ 256*(AdaptP->NicNextPacket-AdaptP->NicPageStart);
+
+
+ if (!CardCopyUp(AdaptP, AdaptP->PacketHeader, PacketLoc, 4))
+ return(CARD_BAD);
+
+ //
+ // Check if the next packet byte agress with the length, as
+ // described on p. A-3 of the Etherlink II Technical Reference.
+ // The start of the packet plus the MSB of the length must
+ // be equal to the start of the next packet minus one or two.
+ // Otherwise the header is considered corrupted, and the
+ // card must be reset.
+ //
+
+ PossibleNextPacket1 =
+ AdaptP->NicNextPacket + AdaptP->PacketHeader[3] + (UCHAR)1;
+
+ if (PossibleNextPacket1 >= AdaptP->NicPageStop) {
+
+ PossibleNextPacket1 -= (AdaptP->NicPageStop - AdaptP->NicPageStart);
+
+ }
+
+ if (PossibleNextPacket1 != AdaptP->PacketHeader[1]) {
+
+ PossibleNextPacket2 = PossibleNextPacket1+(UCHAR)1;
+
+ if (PossibleNextPacket2 == AdaptP->NicPageStop) {
+
+ PossibleNextPacket2 = AdaptP->NicPageStart;
+
+ }
+
+ if (PossibleNextPacket2 != AdaptP->PacketHeader[1]) {
+
+ IF_LOUD(DbgPrint("F");)
+
+ if ((AdaptP->PacketHeader[1] < AdaptP->NicPageStart) ||
+ (AdaptP->PacketHeader[1] >= AdaptP->NicPageStop)) {
+
+ //
+ // We return CARD_BAD because the Dpc will set the NicNextPacket
+ // pointer based on the PacketHeader[1] value if we return
+ // SKIPPED.
+ //
+
+ return(CARD_BAD);
+
+ }
+
+ return SKIPPED;
+ }
+
+ }
+
+#if DBG
+
+ IF_ELNKIIDEBUG( ELNKII_DEBUG_WORKAROUND1 ) {
+ //
+ // Now check for the high order 2 bits being set, as described
+ // on page A-2 of the Etherlink II Technical Reference. If either
+ // of the two high order bits is set in the receive status byte
+ // in the packet header, the packet should be skipped (but
+ // the adapter does not need to be reset).
+ //
+
+ if (AdaptP->PacketHeader[0] & (RSR_DISABLED|RSR_DEFERRING)) {
+
+ IF_LOUD (DbgPrint("H");)
+
+ return SKIPPED;
+
+ }
+
+ }
+
+#endif
+
+ //
+ // Packet length is in bytes 3 and 4 of the header.
+ //
+ PacketLen = AdaptP->PacketHeader[2] + AdaptP->PacketHeader[3] * 256;
+ if (0 == PacketLen)
+ {
+ //
+ // Packet with no data...
+ //
+ IndicateLen = 0;
+ }
+ else
+ {
+ //
+ // Don't count the header.
+ //
+ PacketLen -= 4;
+
+ //
+ // See how much to indicate (252 bytes max).
+ //
+ IndicateLen = PacketLen < AdaptP->MaxLookAhead ?
+ PacketLen : AdaptP->MaxLookAhead;
+ }
+
+ //
+ // Save the length with the adapter block.
+ //
+ AdaptP->PacketLen = PacketLen;
+
+ //
+ // if not memory mapped, have to copy the lookahead data up first.
+ //
+ if (!AdaptP->MemMapped)
+ {
+ if (!CardCopyUp(AdaptP, AdaptP->Lookahead, PacketLoc + 4, IndicateLen))
+ return(CARD_BAD);
+
+ IndicateBuf = AdaptP->Lookahead;
+ }
+ else
+ {
+ if (IndicateLen != 0)
+ {
+ NdisCreateLookaheadBufferFromSharedMemory(
+ (PVOID)(PacketLoc + 4),
+ IndicateLen,
+ &IndicateBuf
+ );
+ }
+ }
+
+ if (IndicateBuf != NULL)
+ {
+ AdaptP->FramesRcvGood++;
+
+ if (IndicateLen < ELNKII_HEADER_SIZE)
+ {
+ //
+ // Indicate packet
+ //
+ EthFilterIndicateReceive(
+ AdaptP->FilterDB,
+ (NDIS_HANDLE)AdaptP,
+ (PCHAR)IndicateBuf,
+ IndicateBuf,
+ IndicateLen,
+ NULL,
+ 0,
+ 0
+ );
+ }
+ else
+ {
+ //
+ // Indicate packet
+ //
+ EthFilterIndicateReceive(
+ AdaptP->FilterDB,
+ (NDIS_HANDLE)AdaptP,
+ (PCHAR)IndicateBuf,
+ IndicateBuf,
+ ELNKII_HEADER_SIZE,
+ IndicateBuf + ELNKII_HEADER_SIZE,
+ IndicateLen - ELNKII_HEADER_SIZE,
+ PacketLen - ELNKII_HEADER_SIZE
+ );
+ }
+
+ if (AdaptP->MemMapped && (IndicateLen != 0))
+ {
+ NdisDestroyLookaheadBufferFromSharedMemory(IndicateBuf);
+ }
+ }
+
+ return(INDICATE_OK);
+}
+
+NDIS_STATUS
+ElnkiiTransferData(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ )
+
+/*++
+
+Routine Description:
+
+ NDIS function.
+
+Arguments:
+
+ see NDIS 3.0 spec.
+
+Notes:
+
+ - The MacReceiveContext will be a pointer to the open block for
+ the packet.
+ - The LoopbackPacket field in the adapter block will be NULL if this
+ is a call for a normal packet, otherwise it will be set to point
+ to the loopback packet.
+
+--*/
+
+{
+ UINT BytesLeft, BytesNow, BytesWanted;
+ PUCHAR CurCardLoc;
+ PNDIS_BUFFER CurBuffer;
+ PUCHAR BufVA, BufStart;
+ UINT BufLen, BufOff, Copied;
+ UINT CurOff;
+ PELNKII_ADAPTER AdaptP = ((PELNKII_ADAPTER)MacReceiveContext);
+
+ UNREFERENCED_PARAMETER(MacBindingHandle);
+
+ //
+ // Determine whether this was a loopback indication.
+ //
+
+ ByteOffset += ELNKII_HEADER_SIZE;
+
+ if (AdaptP->LoopbackPacket != (PNDIS_PACKET)NULL) {
+
+ //
+ // Yes, have to copy data from AdaptP->LoopbackPacket into Packet.
+ //
+
+ NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, NULL);
+
+ CurOff = ByteOffset;
+
+ while (CurBuffer != (PNDIS_BUFFER)NULL) {
+
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufVA, &BufLen);
+
+ Copied =
+ ElnkiiCopyOver(BufVA, AdaptP->LoopbackPacket, CurOff, BufLen);
+
+ CurOff += Copied;
+
+ if (Copied < BufLen) {
+
+ break;
+
+ }
+
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+
+ }
+
+ //
+ // We are done, return.
+ //
+
+
+ *BytesTransferred = CurOff - ByteOffset;
+ if (*BytesTransferred > BytesToTransfer) {
+ *BytesTransferred = BytesToTransfer;
+ }
+
+ return NDIS_STATUS_SUCCESS;
+
+ }
+
+
+ //
+ // This was NOT a loopback packet, get the data off the card.
+ //
+
+ //
+ // See how much data there is to transfer.
+ //
+
+ if (ByteOffset+BytesToTransfer > AdaptP->PacketLen) {
+
+ BytesWanted = AdaptP->PacketLen - ByteOffset;
+
+ } else {
+
+ BytesWanted = BytesToTransfer;
+
+ }
+
+ BytesLeft = BytesWanted;
+
+
+ //
+ // Determine where the copying should start.
+ //
+
+ CurCardLoc = AdaptP->PageStart +
+ 256*(AdaptP->NicNextPacket-AdaptP->NicPageStart) +
+ 4 + ByteOffset;
+
+ if (CurCardLoc > AdaptP->PageStop) {
+
+ CurCardLoc = CurCardLoc - (AdaptP->PageStop - AdaptP->PageStart);
+
+ }
+
+
+ NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, NULL);
+
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufStart, &BufLen);
+
+ BufOff = 0;
+
+ //
+ // Loop, filling each buffer in the packet until there
+ // are no more buffers or the data has all been copied.
+ //
+
+ while (BytesLeft > 0) {
+
+ //
+ // See how much data to read into this buffer.
+ //
+
+ if ((BufLen-BufOff) > BytesLeft) {
+
+ BytesNow = BytesLeft;
+
+ } else {
+
+ BytesNow = (BufLen - BufOff);
+
+ }
+
+
+ //
+ // See if the data for this buffer wraps around the end
+ // of the receive buffers (if so filling this buffer
+ // will use two iterations of the loop).
+ //
+
+ if (CurCardLoc + BytesNow > AdaptP->PageStop) {
+
+ BytesNow = AdaptP->PageStop - CurCardLoc;
+
+ }
+
+
+ //
+ // Copy up the data.
+ //
+
+ if (!CardCopyUp(AdaptP, BufStart+BufOff, CurCardLoc, BytesNow))
+ {
+ *BytesTransferred = BytesWanted - BytesLeft;
+
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ CurCardLoc += BytesNow;
+
+ BytesLeft -= BytesNow;
+
+
+ //
+ // Is the transfer done now?
+ //
+
+ if (BytesLeft == 0) {
+
+ break;
+
+ }
+
+
+ //
+ // Wrap around the end of the receive buffers?
+ //
+
+ if (CurCardLoc == AdaptP->PageStop) {
+
+ CurCardLoc = AdaptP->PageStart;
+
+ }
+
+
+ //
+ // Was the end of this packet buffer reached?
+ //
+
+ BufOff += BytesNow;
+
+ if (BufOff == BufLen) {
+
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+
+ if (CurBuffer == (PNDIS_BUFFER)NULL) {
+
+ break;
+
+ }
+
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufStart, &BufLen);
+
+ BufOff = 0;
+
+ }
+
+ }
+
+
+ *BytesTransferred = BytesWanted - BytesLeft;
+
+ return NDIS_STATUS_SUCCESS;
+
+}
+
+
+
+
+
+
+
+
+
+
+NDIS_STATUS
+ElnkiiSend(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ NDIS function.
+
+Arguments:
+
+ See NDIS 3.0 spec.
+
+Notes:
+
+
+--*/
+
+{
+ PELNKII_OPEN OpenP = ((PELNKII_OPEN)MacBindingHandle);
+ PELNKII_ADAPTER AdaptP = OpenP->Adapter;
+ PMAC_RESERVED Reserved = RESERVED(Packet);
+
+ //
+ // First Buffer
+ //
+ PNDIS_BUFFER FirstBuffer;
+
+ //
+ // Virtual address of first buffer
+ //
+ PVOID BufferVA;
+
+ //
+ // Length of the first buffer
+ //
+ UINT Length;
+
+
+ NdisAcquireSpinLock(&AdaptP->Lock);
+
+#if DBG
+ ElnkiiSendsIssued++;
+#endif
+
+ //
+ // Ensure that the open won't close during this function.
+ //
+
+ if (OpenP->Closing) {
+
+#if DBG
+ ElnkiiSendsFailed++;
+#endif
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+ return NDIS_STATUS_CLOSING;
+ }
+
+ //
+ // All requests are rejected during a reset.
+ //
+
+ if (AdaptP->ResetInProgress) {
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+#if DBG
+ ElnkiiSendsFailed++;
+#endif
+
+ return NDIS_STATUS_RESET_IN_PROGRESS;
+
+ }
+
+ OpenP->ReferenceCount++;
+
+ AdaptP->References++;
+
+ //
+ // Set up the MacReserved section of the packet.
+ //
+
+ Reserved->Open = (PELNKII_OPEN)MacBindingHandle;
+ Reserved->NextPacket = (PNDIS_PACKET)NULL;
+
+#if DBG
+ IF_ELNKIIDEBUG( ELNKII_DEBUG_CHECK_DUP_SENDS ) {
+
+ AddPacketToList(AdaptP, Packet);
+
+ }
+#endif
+
+ //
+ // Set Reserved->Loopback.
+ //
+
+ NdisQueryPacket(Packet, NULL, NULL, &FirstBuffer, NULL);
+
+ //
+ // Get VA of first buffer
+ //
+
+ NdisQueryBuffer(
+ FirstBuffer,
+ &BufferVA,
+ &Length
+ );
+
+ if (OpenP->ProtOptionFlags & NDIS_PROT_OPTION_NO_LOOPBACK){
+
+ Reserved->Loopback = FALSE;
+
+ } else{
+
+ Reserved->Loopback = EthShouldAddressLoopBack(AdaptP->FilterDB, BufferVA);
+
+ }
+
+ //
+ // Put it on the loopback queue only. All packets go through the
+ // loopback queue first, and then on to the xmit queue.
+ //
+
+ IF_LOG( ElnkiiLog('D');)
+
+#if DBG
+ ElnkiiSendsPended++;
+#endif
+
+
+ //
+ // We do not OpenP->ReferenceCount-- because that will be done when
+ // then send completes.
+ //
+
+ //
+ // Put Packet on queue to hit the wire.
+ //
+
+ IF_VERY_LOUD( DbgPrint("Putting 0x%x on, after 0x%x\n",Packet,AdaptP->XmitQTail); )
+
+ if (AdaptP->XmitQueue != NULL) {
+
+ RESERVED(AdaptP->XmitQTail)->NextPacket = Packet;
+
+ AdaptP->XmitQTail = Packet;
+
+ } else {
+
+ AdaptP->XmitQueue = Packet;
+
+ AdaptP->XmitQTail = Packet;
+
+ }
+
+ Reserved->NextPacket = NULL;
+
+ ELNKII_DO_DEFERRED(AdaptP);
+
+ return NDIS_STATUS_PENDING;
+}
+
+UINT
+ElnkiiCompareMemory(
+ IN PUCHAR String1,
+ IN PUCHAR String2,
+ IN UINT Length
+ )
+{
+ UINT i;
+
+ for (i=0; i<Length; i++) {
+ if (String1[i] != String2[i]) {
+ return (UINT)(-1);
+ }
+ }
+ return 0;
+}
+
+VOID
+ElnkiiCopyAndSend(
+ IN PELNKII_ADAPTER AdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ Copies packets from the transmit queue to the board and starts
+ transmission as long as there is data waiting. Must be called
+ with Lock held.
+
+Arguments:
+
+ AdaptP - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ XMIT_BUF TmpBuf1;
+ PNDIS_PACKET Packet;
+
+
+ //
+ // Loop as long as there is data on the transmit queue
+ // and space for it on the card.
+ //
+
+ while ((AdaptP->BufferStatus[TmpBuf1=AdaptP->NextBufToFill] == EMPTY) &&
+ (AdaptP->XmitQueue != NULL)) {
+
+ //
+ // Take the packet off of the transmit queue.
+ //
+
+ IF_VERY_LOUD( DbgPrint("Removing 0x%x, New Head is 0x%x\n",Packet,RESERVED(Packet)->NextPacket); )
+
+ Packet = AdaptP->XmitQueue;
+
+ AdaptP->XmitQueue = RESERVED(Packet)->NextPacket;
+
+ AdaptP->BufferStatus[TmpBuf1] = FILLING;
+
+ AdaptP->Packets[TmpBuf1] = Packet;
+
+ AdaptP->NextBufToFill = NextBuf(AdaptP, TmpBuf1);
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+
+ //
+ // copy down the data, pad short packets with blanks.
+ //
+
+ (VOID)CardCopyDownPacket(AdaptP, Packet, TmpBuf1,
+ &AdaptP->PacketLens[TmpBuf1]);
+
+ if (AdaptP->PacketLens[TmpBuf1] < 60) {
+
+ (VOID)CardCopyDownBuffer(
+ AdaptP,
+ BlankBuffer,
+ TmpBuf1,
+ AdaptP->PacketLens[TmpBuf1],
+ 60 - AdaptP->PacketLens[TmpBuf1]);
+ }
+
+ NdisAcquireSpinLock(&AdaptP->Lock);
+
+ if (AdaptP->ResetInProgress)
+ {
+ PELNKII_OPEN TmpOpen = (PELNKII_OPEN)((RESERVED(Packet)->Open));
+
+ //
+ // A reset just started, abort.
+ //
+ //
+ AdaptP->BufferStatus[TmpBuf1] = EMPTY; // to ack the reset
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+ //
+ // Complete the send.
+ //
+ NdisCompleteSend(
+ RESERVED(Packet)->Open->NdisBindingContext,
+ Packet,
+ NDIS_STATUS_SUCCESS
+ );
+
+ ElnkiiResetStageDone(AdaptP, BUFFERS_EMPTY);
+
+ NdisAcquireSpinLock(&AdaptP->Lock);
+
+ TmpOpen->ReferenceCount--;
+
+ return;
+ }
+
+ AdaptP->BufferStatus[TmpBuf1] = FULL;
+
+
+ //
+ // See whether to start the transmission.
+ //
+
+ if (AdaptP->CurBufXmitting != -1) {
+
+ //
+ // Another transmit is still in progress.
+ //
+
+ continue;
+ }
+
+ if (AdaptP->NextBufToXmit != TmpBuf1) {
+
+ //
+ // A packet ahead of us is being copied down, this
+ // transmission can't be started now.
+ //
+
+ continue;
+ }
+
+ //
+ // OK to start transmission.
+ //
+
+ AdaptP->CurBufXmitting = AdaptP->NextBufToXmit;
+
+
+ IF_LOG( ElnkiiLog('4');)
+
+#if DBG
+
+ ElnkiiLogSave = TRUE;
+ ElnkiiLogSaveLeft = 20;
+
+#endif
+
+ //
+ // If we are currently handling an overflow, then we need to let
+ // the overflow handler send this packet...
+ //
+
+ if (AdaptP->BufferOverflow) {
+
+ AdaptP->OverflowRestartXmitDpc = TRUE;
+
+ IF_LOG( ElnkiiLog('O');)
+
+ } else {
+
+ //
+ // This is used to check if stopping the chip prevented
+ // a transmit complete interrupt from coming through (it
+ // is cleared in the ISR if a transmit DPC is queued).
+ //
+
+ AdaptP->TransmitInterruptPending = TRUE;
+
+ CardStartXmit(AdaptP);
+
+ }
+
+ }
+
+}
+
+
+VOID
+ElnkiiWakeUpDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID Context,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+
+/*++
+
+Routine Description:
+
+ This DPC routine is queued every 2 seconds to check on the
+ transmit queue. If a transmit interrupt was not received
+ in the last two seconds and there is a transmit in progress,
+ then we complete the transmit.
+
+Arguments:
+
+ Context - Really a pointer to the adapter.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PELNKII_ADAPTER AdaptP = (PELNKII_ADAPTER)Context;
+ XMIT_BUF TmpBuf;
+ PMAC_RESERVED Reserved;
+ PELNKII_OPEN TmpOpen;
+ PNDIS_PACKET Packet;
+ PNDIS_PACKET NextPacket;
+
+ UNREFERENCED_PARAMETER(SystemSpecific1);
+ UNREFERENCED_PARAMETER(SystemSpecific2);
+ UNREFERENCED_PARAMETER(SystemSpecific3);
+
+ NdisDprAcquireSpinLock(&AdaptP->Lock);
+
+ if ((AdaptP->WakeUpFoundTransmit) &&
+ (AdaptP->CurBufXmitting != -1))
+ {
+ //
+ // We had a transmit pending the last time we ran,
+ // and it has not been completed...we need to complete
+ // it now.
+
+ AdaptP->TransmitInterruptPending = FALSE;
+ AdaptP->WakeUpFoundTransmit = FALSE;
+
+ IF_LOG( ElnkiiLog('K');)
+
+ //
+ // We log the first 5 of these.
+ //
+ if (AdaptP->TimeoutCount < 5)
+ {
+ NdisWriteErrorLogEntry(
+ AdaptP->NdisAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 2,
+ 0x3,
+ AdaptP->TimeoutCount
+ );
+ }
+
+ AdaptP->TimeoutCount++;
+
+#if DBG
+
+ ELNKII_MOVE_MEM(ElnkiiLogSaveBuffer, ElnkiiLogBuffer, ELNKII_LOG_SIZE);
+
+ ElnkiiLogSave = FALSE;
+ ElnkiiLogSaveLoc = ElnkiiLogLoc;
+
+#endif
+
+ //
+ // We stop and start the card, then queue a DPC to
+ // handle the receive.
+ //
+
+ CardStop(AdaptP);
+
+ Packet = AdaptP->Packets[AdaptP->CurBufXmitting];
+
+ AdaptP->Packets[AdaptP->CurBufXmitting] = (PNDIS_PACKET)NULL;
+
+ AdaptP->BufferStatus[AdaptP->CurBufXmitting] = EMPTY;
+
+ TmpBuf = NextBuf(AdaptP, AdaptP->CurBufXmitting);
+
+ //
+ // Set this so that we don't access the packets
+ // somewhere else.
+ //
+ AdaptP->CurBufXmitting = -1;
+
+ //
+ // Abort all sends
+ //
+ while (Packet != NULL) {
+
+ Reserved = RESERVED(Packet);
+
+ TmpOpen = Reserved->Open;
+
+ NdisDprReleaseSpinLock(&AdaptP->Lock);
+
+ NdisCompleteSend(
+ TmpOpen->NdisBindingContext,
+ Packet,
+ NDIS_STATUS_SUCCESS
+ );
+
+ NdisDprAcquireSpinLock(&AdaptP->Lock);
+
+ TmpOpen->ReferenceCount--;
+
+ //
+ // Get next packet
+ //
+
+ if (AdaptP->BufferStatus[TmpBuf] == FULL) {
+
+ Packet = AdaptP->Packets[TmpBuf];
+
+ AdaptP->Packets[TmpBuf] = NULL;
+
+ AdaptP->BufferStatus[TmpBuf] = EMPTY;
+
+ TmpBuf = NextBuf(AdaptP, TmpBuf);
+
+ } else {
+
+ break;
+
+ }
+
+ }
+
+ //
+ // Set send variables correctly.
+ //
+ AdaptP->NextBufToXmit = TmpBuf;
+
+
+
+ Packet = AdaptP->XmitQueue;
+
+ AdaptP->XmitQueue = NULL;
+
+ while (Packet != NULL) {
+
+ Reserved = RESERVED(Packet);
+
+ //
+ // Remove the packet from the queue.
+ //
+
+ NextPacket = Reserved->NextPacket;
+
+ TmpOpen = Reserved->Open;
+
+ NdisDprReleaseSpinLock(&AdaptP->Lock);
+
+ NdisCompleteSend(
+ TmpOpen->NdisBindingContext,
+ Packet,
+ NDIS_STATUS_SUCCESS
+ );
+
+ NdisDprAcquireSpinLock(&AdaptP->Lock);
+
+ TmpOpen->ReferenceCount--;
+
+ Packet = NextPacket;
+
+ }
+
+ //
+ // Restart the card
+ //
+
+ CardStart(AdaptP);
+
+ NdisDprReleaseSpinLock(&AdaptP->Lock);
+
+ } else {
+
+ if (AdaptP->CurBufXmitting != -1) {
+
+ AdaptP->WakeUpFoundTransmit = TRUE;
+
+ IF_LOG( ElnkiiLog('L');)
+
+ }
+
+ NdisDprReleaseSpinLock(&AdaptP->Lock);
+
+
+ }
+
+ //
+ // Fire off another Dpc to execute after 2 seconds
+ //
+
+ NdisSetTimer(
+ &AdaptP->WakeUpTimer,
+ 2000
+ );
+
+}
+
diff --git a/private/ntos/ndis/elnkii/keywords.h b/private/ntos/ndis/elnkii/keywords.h
new file mode 100644
index 000000000..b035a04ea
--- /dev/null
+++ b/private/ntos/ndis/elnkii/keywords.h
@@ -0,0 +1,56 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ keywords.h
+
+Abstract:
+
+ Contains all Ndis2 and Ndis3 mac-specific keywords.
+
+Author:
+
+ Bob Noradki
+
+Environment:
+
+ This driver is expected to work in DOS, OS2 and NT at the equivalent
+ of kernal mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+
+
+--*/
+#ifndef NDIS2
+#define NDIS2 0
+#endif
+
+#if NDIS2
+
+#define IOBASE NDIS_STRING_CONST("IOADDRESS")
+#define INTERRUPT NDIS_STRING_CONST("INTERRUPT")
+#define MAXMULTICAST NDIS_STRING_CONST("MAXMULTICASTLIST")
+#define NETWORK_ADDRESS NDIS_STRING_CONST("NETADDRESS")
+#define MEMORYMAPPED NDIS_STRING_CONST("MEMORYMAPPED")
+#define TRANSCEIVER NDIS_STRING_CONST("TRANSCEIVER")
+
+#else // NDIS3
+
+#define IOBASE NDIS_STRING_CONST("IoBaseAddress")
+#define INTERRUPT NDIS_STRING_CONST("InterruptNumber")
+#define MAXMULTICAST NDIS_STRING_CONST("MaximumMulticastList")
+#define NETWORK_ADDRESS NDIS_STRING_CONST("NetworkAddress")
+#define MEMORYMAPPED NDIS_STRING_CONST("MemoryMapped")
+#define TRANSCEIVER NDIS_STRING_CONST("Transceiver")
+
+#endif
diff --git a/private/ntos/ndis/elnkii/makefile b/private/ntos/ndis/elnkii/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/elnkii/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/elnkii/pend.c b/private/ntos/ndis/elnkii/pend.c
new file mode 100644
index 000000000..b2d343852
--- /dev/null
+++ b/private/ntos/ndis/elnkii/pend.c
@@ -0,0 +1,440 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ pend.c
+
+Abstract:
+
+ Multicast and filter functions for the NDIS 3.0 Etherlink II driver.
+
+Author:
+
+ Adam Barr (adamba) 30-Jul-1990
+ Aaron Ogus (aarono) 27-Sep-1991
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+
+ Aaron Ogus (aarono) 27-Sep-1991
+ Changes to NdisRequest() format required changes to pending operations
+ Sean Selitrennikoff (seanse) Dec-1991
+ Changes to meet standard model for NDIS drivers.
+
+--*/
+
+#include <ndis.h>
+#include <efilter.h>
+#include "elnkhrd.h"
+#include "elnksft.h"
+
+
+VOID
+HandlePendingOperations(
+ IN PVOID SystemSpecific1,
+ IN PVOID DeferredContext, // will be a pointer to the adapter block
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+
+/*++
+
+Routine Description:
+
+ Called by pending functions to process elements on the
+ pending queue.
+
+Arguments:
+
+ DeferredContext - will be a pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER AdaptP = ((PELNKII_ADAPTER)DeferredContext);
+ PELNKII_PEND_DATA PendOp;
+ PELNKII_OPEN TmpOpen;
+ NDIS_STATUS Status;
+
+ UNREFERENCED_PARAMETER(SystemSpecific1);
+ UNREFERENCED_PARAMETER(SystemSpecific2);
+ UNREFERENCED_PARAMETER(SystemSpecific3);
+
+ NdisAcquireSpinLock(&AdaptP->Lock);
+
+ AdaptP->References++;
+
+ //
+ // If an operation is being dispatched or a reset is running, exit.
+ //
+
+ if ((!AdaptP->ResetInProgress) && (AdaptP->PendOp == NULL)) {
+
+ for (;;) {
+
+ //
+ // We hold SpinLock here.
+ //
+
+ if (AdaptP->PendQueue != NULL) {
+
+ //
+ // Take the request off the queue and dispatch it.
+ //
+
+ PendOp = AdaptP->PendQueue;
+
+ AdaptP->PendQueue = PendOp->Next;
+
+ if (PendOp == AdaptP->PendQTail) {
+
+ AdaptP->PendQTail = NULL;
+
+ }
+
+ AdaptP->PendOp = PendOp;
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+ Status = ((PendOp->RequestType == NdisRequestClose) ||
+ (PendOp->RequestType == NdisRequestGeneric3)) ?
+ DispatchSetMulticastAddressList(AdaptP) :
+ DispatchSetPacketFilter(AdaptP);
+
+ TmpOpen = PendOp->Open;
+
+ if ((PendOp->RequestType != NdisRequestGeneric1) &&
+ (PendOp->RequestType != NdisRequestClose)) { // Close Adapter
+
+
+ //
+ // Complete it since it previously pended.
+ //
+
+ NdisCompleteRequest(PendOp->Open->NdisBindingContext,
+ PNDIS_REQUEST_FROM_PELNKII_PEND_DATA(PendOp),
+ Status);
+
+ }
+
+ //
+ // This will call CompleteClose if necessary.
+ //
+
+ NdisAcquireSpinLock(&AdaptP->Lock);
+
+ TmpOpen->ReferenceCount--;
+
+ if (AdaptP->ResetInProgress) {
+
+ //
+ // We have to stop processing requests.
+ //
+
+ break; // jump to BREAK_LOCATION
+ }
+
+ } else {
+
+ break; // jump to BREAK_LOCATION
+
+ }
+ }
+
+ //
+ // BREAK_LOCATION
+ //
+ // Hold Lock here.
+ //
+
+ AdaptP->PendOp = NULL;
+
+ if (AdaptP->ResetInProgress) {
+
+ //
+ // Exited due to a reset, indicate that the DPC
+ // handler is done for now.
+ //
+
+ AdaptP->References--;
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+ ElnkiiResetStageDone(AdaptP, MULTICAST_RESET);
+
+ return;
+ }
+
+ }
+
+ if (AdaptP->CloseQueue != NULL) {
+
+ PELNKII_OPEN OpenP;
+ PELNKII_OPEN TmpOpenP;
+ PELNKII_OPEN PrevOpenP;
+
+ //
+ // Check for an open that may have closed
+ //
+
+ OpenP = AdaptP->CloseQueue;
+ PrevOpenP = NULL;
+
+ while (OpenP != NULL) {
+
+ if (OpenP->ReferenceCount > 0) {
+
+ OpenP = OpenP->NextOpen;
+ PrevOpenP = OpenP;
+
+ continue;
+
+ }
+
+#if DBG
+
+ if (!OpenP->Closing) {
+
+ DbgPrint("BAD CLOSE: %d\n", OpenP->ReferenceCount);
+
+ DbgBreakPoint();
+
+ OpenP = OpenP->NextOpen;
+ PrevOpenP = OpenP;
+
+ continue;
+
+ }
+
+#endif
+
+
+ //
+ // The last reference is completed; a previous call to ElnkiiCloseAdapter
+ // will have returned NDIS_STATUS_PENDING, so things must be finished
+ // off now.
+ //
+
+ //
+ // Check if MaxLookAhead needs adjusting.
+ //
+
+ if (OpenP->LookAhead == AdaptP->MaxLookAhead) {
+
+ ElnkiiAdjustMaxLookAhead(AdaptP);
+
+ }
+
+ NdisReleaseSpinLock(&AdaptP->Lock);
+
+ NdisCompleteCloseAdapter (OpenP->NdisBindingContext, NDIS_STATUS_SUCCESS);
+
+ NdisAcquireSpinLock(&AdaptP->Lock);
+
+ //
+ // Remove from close list
+ //
+
+ if (PrevOpenP != NULL) {
+
+ PrevOpenP->NextOpen = OpenP->NextOpen;
+
+ } else {
+
+ AdaptP->CloseQueue = OpenP->NextOpen;
+ }
+
+ //
+ // Go to next one
+ //
+
+ TmpOpenP = OpenP;
+ OpenP = OpenP->NextOpen;
+
+ NdisFreeMemory(TmpOpenP, sizeof(ELNKII_OPEN), 0);
+
+ }
+
+ if ((AdaptP->CloseQueue == NULL) && (AdaptP->OpenQueue == NULL)) {
+
+ //
+ // We can stop the card.
+ //
+
+ CardStop(AdaptP);
+
+ }
+
+ }
+
+ ELNKII_DO_DEFERRED(AdaptP);
+
+}
+
+NDIS_STATUS
+DispatchSetPacketFilter(
+ IN PELNKII_ADAPTER AdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the appropriate bits in the adapter filters
+ and modifies the card Receive Configuration Register if needed.
+
+Arguments:
+
+ AdaptP - Pointer to the adapter block
+
+Return Value:
+
+ The final status (always NDIS_STATUS_SUCCESS).
+
+Notes:
+
+ - Note that to receive all multicast packets the multicast
+ registers on the card must be filled with 1's. To be
+ promiscuous that must be done as well as setting the
+ promiscuous physical flag in the RCR. This must be done
+ as long as ANY protocol bound to this adapter has their
+ filter set accordingly.
+
+--*/
+
+
+{
+ UINT PacketFilter;
+
+ PacketFilter = ETH_QUERY_FILTER_CLASSES(AdaptP->FilterDB);
+
+ //
+ // See what has to be put on the card.
+ //
+
+ if (PacketFilter & (NDIS_PACKET_TYPE_ALL_MULTICAST | NDIS_PACKET_TYPE_PROMISCUOUS)) {
+
+ //
+ // need "all multicast" now.
+ //
+
+ CardSetAllMulticast(AdaptP); // fills it with 1's
+
+ } else {
+
+ //
+ // No longer need "all multicast".
+ //
+
+ DispatchSetMulticastAddressList(AdaptP);
+
+ }
+
+
+ //
+ // The multicast bit in the RCR should be on if ANY protocol wants
+ // multicast/all multicast packets (or is promiscuous).
+ //
+
+ if (PacketFilter & (NDIS_PACKET_TYPE_ALL_MULTICAST |
+ NDIS_PACKET_TYPE_MULTICAST |
+ NDIS_PACKET_TYPE_PROMISCUOUS)) {
+
+ AdaptP->NicReceiveConfig |= RCR_MULTICAST;
+
+ } else {
+
+ AdaptP->NicReceiveConfig &= ~RCR_MULTICAST;
+
+ }
+
+
+ //
+ // The promiscuous physical bit in the RCR should be on if ANY
+ // protocol wants to be promiscuous.
+ //
+
+ if (PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS) {
+
+ AdaptP->NicReceiveConfig |= RCR_ALL_PHYS;
+
+ } else {
+
+ AdaptP->NicReceiveConfig &= ~RCR_ALL_PHYS;
+
+ }
+
+
+ //
+ // The broadcast bit in the RCR should be on if ANY protocol wants
+ // broadcast packets (or is promiscuous).
+ //
+
+ if (PacketFilter & (NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_PROMISCUOUS)) {
+
+ AdaptP->NicReceiveConfig |= RCR_BROADCAST;
+
+ } else {
+
+ AdaptP->NicReceiveConfig &= ~RCR_BROADCAST;
+
+ }
+
+
+ CardSetReceiveConfig(AdaptP);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+
+NDIS_STATUS
+DispatchSetMulticastAddressList(
+ IN PELNKII_ADAPTER AdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the multicast list for this open
+
+Arguments:
+
+ AdaptP - Pointer to the adapter block
+
+Return Value:
+
+Implementation Note:
+
+ When invoked, we are to make it so that the multicast list in the filter
+ package becomes the multicast list for the adapter. To do this, we
+ determine the required contents of the NIC multicast registers and
+ update them.
+
+
+--*/
+{
+
+ //
+ // Update the local copy of the NIC multicast regs and copy them to the NIC
+ //
+
+ CardFillMulticastRegs(AdaptP);
+
+ CardCopyMulticastRegs(AdaptP);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
diff --git a/private/ntos/ndis/elnkii/sources b/private/ntos/ndis/elnkii/sources
new file mode 100644
index 000000000..7ec0c29cc
--- /dev/null
+++ b/private/ntos/ndis/elnkii/sources
@@ -0,0 +1,45 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=elnkii
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+INCLUDES=..\..\inc
+
+SOURCES=elnkii.c \
+ interrup.c\
+ card.c\
+ pend.c \
+ elnkii.rc
+
+RELATIVE_DEPTH=..\..
+
+MSC_WARNING_LEVEL=/W3 /WX
+
diff --git a/private/ntos/ndis/elnkmc/82586.h b/private/ntos/ndis/elnkmc/82586.h
new file mode 100644
index 000000000..81eb34f22
--- /dev/null
+++ b/private/ntos/ndis/elnkmc/82586.h
@@ -0,0 +1,367 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ 82586.h
+
+Abstract:
+
+ Hardware specific values for the 82586 chip.
+
+Author:
+
+ Johnson R. Apacible (JohnsonA) 24-February-1992
+
+Environment:
+
+ This driver is expected to work in DOS and NT at the equivalent
+ of kernal mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+
+--*/
+
+#ifndef _I82586_
+#define _I82586_
+//
+// Transmit Buffer Descriptor
+//
+
+typedef struct _TRANSMIT_BUFFER_DESCRIPTOR {
+ USHORT Length;
+ USHORT NextTbdOffset;
+ ULONG BufferOffset;
+} TRANSMIT_BUFFER_DESCRIPTOR, *PTRANSMIT_BUFFER_DESCRIPTOR;
+
+//
+// TBD Bits
+//
+
+#define TBD_END_OF_LIST 0x8000
+
+//
+// transmit block
+//
+typedef struct _TRANSMIT_CB {
+ USHORT Status;
+ USHORT Command;
+ USHORT NextCbOffset;
+ USHORT TbdOffset;
+ UCHAR Destination[ETH_LENGTH_OF_ADDRESS];
+ USHORT Length;
+ TRANSMIT_BUFFER_DESCRIPTOR Tbd;
+} TRANSMIT_CB, *PTRANSMIT_CB;
+
+
+//
+// 82586 Setup Command Block Parameters
+//
+
+typedef struct _SETUP_CB {
+ UCHAR StationAddress[ETH_LENGTH_OF_ADDRESS];
+} SETUP_CB, *PSETUP_CB;
+
+
+//
+// 82586 Config Command Block Parameters
+//
+
+typedef struct _CONFIG_CB {
+ USHORT Parameter1;
+ USHORT Parameter2;
+ USHORT Parameter3;
+ USHORT Parameter4;
+ USHORT Parameter5;
+ USHORT Parameter6;
+} CONFIG_CB, *PCONFIG_CB;
+
+
+//
+// Configuration bits
+//
+
+#define PARM1_FIFO_LIMIT 0x0600
+#define DEFAULT_PARM1 PARM1_FIFO_LIMIT | 0x000C
+#define DEFAULT_PARM2 0x2600 // this is 2600 if external loopback is off, A600 if on
+#define DEFAULT_PARM3 0x6000
+#define DEFAULT_PARM4 0xF200
+#define DEFAULT_PARM5 0x0002 // 0002 if dont xmit on no CRS, 000A if Xmit
+#define DEFAULT_PARM6 0x0040
+
+//
+// Parameter 5
+//
+
+#define CONFIG_PROMISCUOUS 0x0001
+#define CONFIG_BROADCAST 0x0002
+#define CONFIG_INTERNAL 0x8800
+
+
+//
+// 82586 Multicast Command Block Parameters
+//
+
+typedef struct _MULTICAST_CB {
+ USHORT McCount;
+ UCHAR MulticastID[ELNK_MAXIMUM_MULTICAST][ETH_LENGTH_OF_ADDRESS];
+} MULTICAST_CB, *PMULTICAST_CB;
+
+
+//
+// Generic Command Block
+//
+
+typedef struct _NON_TRANSMIT_CB {
+
+ USHORT Status;
+ USHORT Command;
+ USHORT NextCbOffset;
+ union {
+ MULTICAST_CB Multicast;
+ CONFIG_CB Config;
+ SETUP_CB Setup;
+ } Parm;
+
+} NON_TRANSMIT_CB, *PNON_TRANSMIT_CB;
+
+
+
+// Command Block Status Bits
+//
+
+#define CB_STATUS_COMPLETE 0x8000
+#define CB_STATUS_BUSY 0x4000
+#define CB_STATUS_SUCCESS 0x2000
+#define CB_STATUS_ABORTED 0x1000
+#define CB_STATUS_FREE 0x0000
+#define CB_STATUS_MASK 0xF000
+
+
+//
+// Additional bit definition for transmits
+//
+
+#define TRANSMIT_STATUS_NO_CARRIER ((USHORT)0x0400)
+#define TRANSMIT_STATUS_NO_CLEAR_TO_SEND ((USHORT)0x0200)
+#define TRANSMIT_STATUS_DMA_UNDERRUN ((USHORT)0x0100)
+#define TRANSMIT_STATUS_TRANSMIT_DEFERRED ((USHORT)0x0080)
+#define TRANSMIT_STATUS_SQE_TEST ((USHORT)0x0040)
+#define TRANSMIT_STATUS_MAXIMUM_COLLISIONS ((USHORT)0x0020)
+#define TRANSMIT_STATUS_COLLISION_MASK ((USHORT)0x000F)
+#define TRANSMIT_STATUS_FATALERROR_MASK (TRANSMIT_STATUS_NO_CARRIER | \
+ TRANSMIT_STATUS_NO_CLEAR_TO_SEND | \
+ TRANSMIT_STATUS_DMA_UNDERRUN | \
+ TRANSMIT_STATUS_MAXIMUM_COLLISIONS)
+
+
+//
+// Command Block Command Bits
+//
+
+#define CB_COMMAND_END_OF_LIST 0x8000
+#define CB_COMMAND_SUSPEND 0x4000
+#define CB_COMMAND_INTERRUPT 0x2000
+#define CB_COMMAND_MASK 0x0007
+
+
+//
+// Commands
+//
+
+#define CB_NOP 0x0000
+#define CB_SETUP 0x0001
+#define CB_CONFIG 0x0002
+#define CB_MULTICAST 0x0003
+#define CB_TRANSMIT 0x0004
+
+
+//
+// System Configuration Pointer (SCP)
+//
+
+typedef struct _SCP {
+ USHORT Dummy;
+ USHORT SysBus;
+ USHORT XXX[2];
+ USHORT IscpOffset;
+ USHORT IscpBase;
+} SCP, *PSCP;
+
+
+//
+// Intermediate SCP (ISCP)
+//
+
+typedef struct ISCP {
+ USHORT Busy;
+ USHORT ScbOffset;
+ ULONG ScbBaseAddress;
+} ISCP, *PISCP;
+
+
+//
+// 82586 SCB
+//
+
+typedef struct _SCB {
+ USHORT Status;
+ USHORT Command;
+ USHORT CommandListOffset;
+ USHORT RFAOffset;
+ USHORT CrcErrors;
+ USHORT AlignmentErrors;
+ USHORT ResourceErrors;
+ USHORT OverrunErrors;
+} SCB, *PSCB;
+
+
+//
+// Scb Status Bits
+//
+
+#define SCB_STATUS_COMMAND_COMPLETE 0x8000
+#define SCB_STATUS_FRAME_RECEIVED 0x4000
+#define SCB_STATUS_CU_STOPPED 0x2000
+#define SCB_STATUS_RU_STOPPED 0x1000
+#define SCB_STATUS_CUS_MASK 0x0700
+#define SCB_STATUS_RUS_MASK 0x0070
+#define SCB_STATUS_INT_MASK 0xF000
+
+//
+// CU Status
+//
+
+#define CUS_IDLE 0x0000
+#define CUS_SUSPENDED 0x0100
+#define CUS_ACTIVE 0x0200
+
+
+//
+// RU Status
+//
+
+#define RUS_IDLE 0x0000
+#define RUS_SUSPENDED 0x0010
+#define RUS_NO_RESOURCES 0x0020
+#define RUS_NOT_USED 0x0030
+#define RUS_READY 0x0040
+
+
+//
+// Scb Command Bits
+//
+
+#define SCB_COMMAND_ACK_CX 0x8000
+#define SCB_COMMAND_ACK_FR 0x4000
+#define SCB_COMMAND_ACK_CNA 0x2000
+#define SCB_COMMAND_ACK_RNR 0x1000
+#define SCB_COMMAND_CUC_MASK 0x0700
+#define SCB_COMMAND_RESET 0x0080
+#define SCB_COMMAND_RUC_MASK 0x0070
+#define SCB_COMMAND_ENABLE_INTERRUPTS 0xF000
+
+
+// CU Command
+
+#define CUC_NOP 0x0000
+#define CUC_START 0x0100
+#define CUC_RESUME 0x0200
+#define CUC_SUSPEND 0x0300
+#define CUC_ABORT 0x0400
+
+
+//
+// RU Command
+//
+
+#define RUC_NCP 0x0000
+#define RUC_START 0x0010
+#define RUC_RESUME 0x0020
+#define RUC_SUSPEND 0x0030
+#define RUC_ABORT 0x0040
+
+
+
+
+//
+// Receive Buffer Descriptor
+//
+
+typedef struct _RECEIVE_BUFFER_DESCRIPTOR {
+ USHORT Status;
+ USHORT NextRbdOffset;
+ ULONG BufferOffset;
+ USHORT Size;
+} RECEIVE_BUFFER_DESCRIPTOR, *PRECEIVE_BUFFER_DESCRIPTOR;
+
+
+//
+// RBD Status Bits
+//
+
+#define RBD_STATUS_END_OF_FRAME 0x8000
+#define RBD_STATUS_ACT_COUNT_VALID 0x4000
+#define RBD_STATUS_ACT_COUNT_MASK 0x3FFF
+#define RBD_END_OF_LIST 0x8000
+
+//
+// Receive Frame Descriptor
+//
+
+typedef struct _RECEIVE_FRAME_DESCRIPTOR {
+ USHORT Status;
+ USHORT Command;
+ USHORT NextRfdOffset;
+ USHORT RbdOffset;
+ UCHAR Destination[ETH_LENGTH_OF_ADDRESS];
+ UCHAR Source[ETH_LENGTH_OF_ADDRESS];
+ USHORT Length;
+ RECEIVE_BUFFER_DESCRIPTOR Rbd;
+} RECEIVE_FRAME_DESCRIPTOR, *PRECEIVE_FRAME_DESCRIPTOR;
+
+
+//
+// RFD Status bits
+//
+
+#define RFD_STATUS_FRAME_STORED 0x8000
+#define RFD_STATUS_CONSUMED 0x4000
+#define RFD_STATUS_SUCCESS 0x2000
+#define RFD_STATUS_CRC_ERROR 0x0800
+#define RFD_STATUS_ALIGNMENT_ERROR 0x0400
+#define RFD_STATUS_NO_RESOURCE 0x0200
+#define RFD_STATUS_DMA_OVERRUN 0x0100
+#define RFD_STATUS_TOO_SHORT 0x0080
+#define RFD_STATUS_NO_EOF 0x0040
+
+//
+// RFD Command bits
+//
+
+#define RFD_COMMAND_END_OF_LIST 0x8000
+#define RFD_COMMAND_SUSPEND 0x4000
+
+//
+// Location of card data structures (Offsets from base of shared memory)
+//
+
+#define OFFSET_SCP 0xFFF4
+#define OFFSET_ISCP 0xFFE0
+#define OFFSET_SCB 0xFFC0
+#define OFFSET_SCBSTAT OFFSET_SCB
+#define OFFSET_SCBCMD OFFSET_SCB + sizeof(USHORT)
+#define OFFSET_SCB_CB OFFSET_SCBCMD + sizeof(USHORT)
+#define OFFSET_SCB_RD OFFSET_SCB_CB + sizeof(USHORT)
+#define OFFSET_MULTICAST OFFSET_SCB - sizeof(NON_TRANSMIT_CB)
+
+#endif // _I82586_
diff --git a/private/ntos/ndis/elnkmc/command.c b/private/ntos/ndis/elnkmc/command.c
new file mode 100644
index 000000000..e813eadec
--- /dev/null
+++ b/private/ntos/ndis/elnkmc/command.c
@@ -0,0 +1,607 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ command.c
+
+Abstract:
+
+ This file contains the code for managing Command Blocks on the
+ EtherLink's Command Queue.
+
+Author:
+
+ Johnson R. Apacible (JohnsonA) 09-June-1991
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+
+//
+// So we can trace things...
+//
+#define STATIC
+
+#include <efilter.h>
+#include <elnkhw.h>
+#include <elnksw.h>
+
+
+BOOLEAN
+ElnkSyncStartCommandBlock(
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ This function is used to synchronize with the ISR the starting of a
+ command block.
+
+Arguments:
+
+ see NDIS 3.0 spec.
+
+Notes:
+
+ returns TRUE on success, else FALSE.
+
+--*/
+{
+ PELNK_ADAPTER Adapter = (PELNK_ADAPTER)Context;
+
+ IF_LOG('x');
+
+ WRITE_ADAPTER_REGISTER(
+ Adapter,
+ OFFSET_SCB_CB,
+ Adapter->TransmitInfo[Adapter->CommandToStart].CbOffset
+ );
+
+ WRITE_ADAPTER_REGISTER(
+ Adapter,
+ OFFSET_SCBCMD,
+ CUC_START
+ );
+
+ ELNK_CA;
+
+ return(TRUE);
+
+}
+
+VOID
+ElnkAssignPacketToCommandBlock(
+ IN PELNK_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet,
+ IN UINT CbIndex
+ )
+
+/*++
+
+Routine Description:
+
+ Given a packet and a pointer to a Command Block, assign all of the
+ buffers in the packet to Command Block.
+
+Arguments:
+
+ Adapter - The adapter that the packets are coming through.
+
+ Packet - The packet whose buffers are to be assigned
+ ring entries.
+
+ CbIndex - The index of the Command Block to receive the
+ packet's buffers.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Points to the reserved portion of the packet.
+ //
+ PELNK_RESERVED Reserved = PELNK_RESERVED_FROM_PACKET(Packet);
+
+ //
+ // Pointer to the actual transmit command block
+ //
+ PTRANSMIT_CB TransmitBlock = Adapter->TransmitInfo[CbIndex].CommandBlock;
+
+ //
+ // index for for loop
+ //
+ UINT i;
+
+ //
+ // Points to the current ndis buffer being walked.
+ //
+ PNDIS_BUFFER SourceBuffer;
+
+
+ //
+ // The total amount of data in the ndis packet.
+ //
+ UINT TotalVirtualLength;
+
+ //
+ // The virtual address of data in the current ndis buffer.
+ //
+ PVOID SourceData;
+
+ //
+ // The length in bytes of data of the current ndis buffer.
+ //
+ UINT SourceLength;
+
+ //
+ // The number of ndis buffers in the packet.
+ //
+ UINT NdisBufferCount;
+
+ //
+ // We record the owning packet information in the ring packet packet
+ // structure.
+ //
+
+ Adapter->TransmitInfo[CbIndex].OwningPacket = Packet;
+ Adapter->TransmitInfo[CbIndex].NextCommand = ELNK_EMPTY;
+ Adapter->TransmitInfo[CbIndex].OwningOpenBinding = NULL;
+
+ //
+ // Initialize the various fields of the Command Block.
+ //
+
+ NdisWriteRegisterUshort(&TransmitBlock->Status, CB_STATUS_FREE);
+ NdisWriteRegisterUshort(&TransmitBlock->NextCbOffset, ELNK_NULL);
+ NdisWriteRegisterUshort(&TransmitBlock->Command, CB_TRANSMIT);
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ &NdisBufferCount,
+ &SourceBuffer,
+ &TotalVirtualLength
+ );
+
+ NdisQueryBuffer(
+ SourceBuffer,
+ &SourceData,
+ &SourceLength
+ );
+
+ ASSERT(SourceLength >= ELNK_HEADER_SIZE);
+
+#if 1
+
+ //
+ // Fill in fields of TFD
+ //
+
+ ELNK_MOVE_MEMORY_TO_SHARED_RAM(
+ &TransmitBlock->Destination[0],
+ SourceData,
+ ETH_LENGTH_OF_ADDRESS
+ );
+
+ SourceData = (PVOID)((PUCHAR)SourceData + 2 * ETH_LENGTH_OF_ADDRESS);
+ SourceLength -= 2 * ETH_LENGTH_OF_ADDRESS + sizeof(USHORT);
+
+ NdisWriteRegisterUshort(&TransmitBlock->Length,
+ (USHORT)(*((USHORT UNALIGNED *)SourceData))
+ );
+
+ SourceData = (PVOID)((PUCHAR)SourceData + sizeof(USHORT));
+
+ if (SourceLength == 0) {
+
+ NdisBufferCount--;
+
+ NdisGetNextBuffer(
+ SourceBuffer,
+ &SourceBuffer
+ );
+
+ NdisQueryBuffer(
+ SourceBuffer,
+ &SourceData,
+ &SourceLength
+ );
+
+ }
+
+#endif
+
+ {
+
+ //
+ // Fill in the adapter buffer with the data from the users
+ // buffers.
+ //
+
+ PVOID CurrentDestination = Adapter->TransmitInfo[CbIndex].Buffer;
+
+ for (
+ i = NdisBufferCount;
+ i;
+ i--
+ ) {
+
+ if (SourceLength) {
+ ELNK_MOVE_MEMORY_TO_SHARED_RAM(
+ CurrentDestination,
+ SourceData,
+ SourceLength
+ );
+ }
+
+ CurrentDestination = (PCHAR)CurrentDestination + SourceLength;
+
+ if (i > 1) {
+
+ NdisGetNextBuffer(
+ SourceBuffer,
+ &SourceBuffer
+ );
+
+ NdisQueryBuffer(
+ SourceBuffer,
+ &SourceData,
+ &SourceLength
+ );
+
+ }
+
+ }
+
+ //
+ // If the packet is less than the minimum Ethernet
+ // packet size, then clear the remaining part of
+ // the buffer up to the minimum packet size.
+ //
+
+ if (TotalVirtualLength < MINIMUM_ETHERNET_PACKET_SIZE) {
+
+ NdisZeroMappedMemory(
+ CurrentDestination,
+ MINIMUM_ETHERNET_PACKET_SIZE - TotalVirtualLength
+ );
+
+ TotalVirtualLength = MINIMUM_ETHERNET_PACKET_SIZE;
+
+ }
+
+ NdisWriteRegisterUshort(
+ &TransmitBlock->Tbd.Length,
+ (USHORT)((TotalVirtualLength - ELNK_HEADER_SIZE) | TBD_END_OF_LIST)
+ );
+
+ }
+
+ Reserved->CommandBlockIndex = CbIndex;
+
+}
+
+VOID
+ElnkSubmitCommandBlock(
+ IN PELNK_ADAPTER Adapter,
+ IN UINT CbIndex
+ )
+
+/*++
+
+Routine Description:
+
+ Submit a complete Command Block for execution by the Elnk.
+
+ NOTE: This routine assumes that it is called with the lock held.
+
+Arguments:
+
+ Adapter - The adapter that points to the ring entry structures.
+
+ CbIndex - Holds the index of the Command Block to be submitted.
+
+Return Value:
+
+ None.
+
+*--*/
+
+{
+ //
+ // Pointer to the most recently submitted Command Block.
+ //
+
+ PTRANSMIT_CB CommandBlock = Adapter->TransmitInfo[CbIndex].CommandBlock;
+
+ //
+ // Index of last command submitted
+ //
+
+ UINT PreviousCommandBlock = Adapter->LastPendingCommand;
+
+ USHORT Command;
+
+ IF_LOG('s');
+
+ //
+ // Set the Command Block to be the last command block
+ //
+
+ NdisReadRegisterUshort(&CommandBlock->Command, &Command);
+ NdisWriteRegisterUshort(
+ &CommandBlock->Command,
+ (USHORT)(Command |(CB_COMMAND_END_OF_LIST | CB_COMMAND_INTERRUPT))
+ );
+
+ if ELNKDEBUG DPrint2("Submit: Command Block = %x\n",(Command |(CB_COMMAND_END_OF_LIST | CB_COMMAND_INTERRUPT)));
+
+ //
+ // Initialize our command timeout flag.
+ //
+
+ Adapter->TransmitInfo[CbIndex].Timeout = FALSE;
+
+ //
+ // Initialize the next command pointer
+ //
+
+ Adapter->TransmitInfo[CbIndex].NextCommand = ELNK_EMPTY;
+
+ //
+ // Update the pointer to the most recently submitted Command Block.
+ //
+
+ Adapter->LastPendingCommand = CbIndex;
+
+ if (PreviousCommandBlock == ELNK_EMPTY) {
+
+ if ELNKDEBUG DPrint1("Request sent\n");
+ if (Adapter->FirstPendingCommand == ELNK_EMPTY ) {
+
+ Adapter->FirstPendingCommand = CbIndex;
+
+ }
+
+ ELNK_WAIT;
+
+ Adapter->CommandToStart = CbIndex;
+
+ NdisSynchronizeWithInterrupt(
+ &(Adapter->Interrupt),
+ (PVOID)ElnkSyncStartCommandBlock,
+ (PVOID)(Adapter)
+ );
+
+ } else {
+
+ //
+ // Queue the request
+ //
+
+ if ELNKDEBUG DPrint1("Request queued\n");
+ Adapter->TransmitInfo[PreviousCommandBlock].NextCommand = CbIndex;
+
+ }
+
+}
+
+VOID
+ElnkSubmitCommandBlockAndWait(
+ IN PELNK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Submit a command block and wait till it's done. This is done for
+ setups and configurations.
+
+ NOTE: This routine assumes that it is called with the lock held.
+
+Arguments:
+
+ Adapter - The adapter that points to the ring entry structures.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UINT i;
+ USHORT Status;
+
+ //
+ // The value of our scb
+ //
+
+ USHORT Command;
+
+ //
+ // Points to our transmit CB
+ //
+
+ PNON_TRANSMIT_CB CommandBlock = Adapter->MulticastBlock;
+
+ //
+ // Set the Command Block to be the last command block
+ //
+
+ IF_LOG('W');
+
+ NdisReadRegisterUshort(&CommandBlock->Command, &Command);
+ NdisWriteRegisterUshort(&CommandBlock->Command, (USHORT)(Command | CB_COMMAND_END_OF_LIST));
+ NdisWriteRegisterUshort(&CommandBlock->Status, CB_STATUS_FREE);
+
+
+ if ELNKDEBUG
+ DPrint2("Command Block requested = %x\n",Command | CB_COMMAND_END_OF_LIST);
+
+
+ ELNK_WAIT;
+
+ Adapter->CommandToStart = Adapter->NumberOfTransmitBuffers;
+
+ NdisSynchronizeWithInterrupt(
+ &(Adapter->Interrupt),
+ (PVOID)ElnkSyncStartCommandBlock,
+ (PVOID)(Adapter)
+ );
+
+ ELNK_WAIT;
+
+ for (i = 0; i <= 20000 ; i++ ) {
+ NdisReadRegisterUshort(&CommandBlock->Status, &Status);
+ if (Status & CB_STATUS_COMPLETE) {
+ break;
+ }
+ NdisStallExecution(50);
+ }
+}
+
+BOOLEAN
+ElnkAcquireCommandBlock(
+ IN PELNK_ADAPTER Adapter,
+ OUT PUINT CbIndex
+ )
+
+/*++
+
+Routine Description:
+
+ Sees if a Command Block is available and if so returns its index.
+
+ NOTE: This routine assumes that the lock is held.
+
+Arguments:
+
+ Adapter - The adapter that points to the ring entry structures.
+
+ CbIndex - will receive an index to a Command Block if one is
+ available. This value is unpredicable if there is not a free
+ Command Block.
+
+Return Value:
+
+ Returns FALSE if there are no free Command Blocks.
+
+--*/
+
+{
+
+ if ELNKDEBUG DPrint1("acquire CB\n");
+
+ {
+
+ if (Adapter->NumberOfAvailableCommandBlocks) {
+
+ //
+ // Return the Command Block pointer.
+ //
+
+ *CbIndex = Adapter->NextCommandBlock;
+
+ //
+ // Update the head of the Command Queue.
+ //
+
+ Adapter->NextCommandBlock++;
+
+ if (Adapter->NextCommandBlock >= Adapter->NumberOfTransmitBuffers) {
+
+ Adapter->NextCommandBlock = 0;
+
+ }
+
+ //
+ // Update number of available Command Blocks.
+ //
+
+ Adapter->NumberOfAvailableCommandBlocks--;
+
+ return TRUE;
+
+ } else {
+
+ Adapter->StageOpen = FALSE;
+ return FALSE;
+
+ }
+
+ }
+
+}
+
+VOID
+ElnkRelinquishCommandBlock(
+ IN PELNK_ADAPTER Adapter,
+ IN UINT CbIndex
+ )
+
+/*++
+
+Routine Description:
+
+ Relinquish the Command Block resource. If this is a "public"
+ Command Block, then update the TransmitQueue. If this is a
+ "private" Command Block, then free its memory.
+
+ NOTE: This routine assumes that the lock is held.
+
+Arguments:
+
+ Adapter - The adapter that owns the Command Block.
+
+ CbIndex - The index of the Command Block to relinquish.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PTRANSMIT_CB CommandBlock = Adapter->TransmitInfo[CbIndex].CommandBlock;
+
+ //
+ // Point the adapter's first pending command to the
+ // next command on the command queue.
+ //
+
+ if ELNKDEBUG DPrint1("relinquish CB\n");
+ Adapter->FirstPendingCommand = Adapter->TransmitInfo[CbIndex].NextCommand;
+
+ //
+ // If this is the last pending command block, then we
+ // can nuke the adapter's last pending command pointer.
+ //
+
+ if (CbIndex == Adapter->LastPendingCommand) {
+
+ Adapter->LastPendingCommand = ELNK_EMPTY;
+
+ }
+
+ NdisWriteRegisterUshort(&CommandBlock->NextCbOffset, ELNK_NULL);
+ NdisWriteRegisterUshort(&CommandBlock->Status, CB_STATUS_FREE);
+
+ Adapter->NumberOfAvailableCommandBlocks++;
+}
diff --git a/private/ntos/ndis/elnkmc/elnk.c b/private/ntos/ndis/elnkmc/elnk.c
new file mode 100644
index 000000000..4170dc9d3
--- /dev/null
+++ b/private/ntos/ndis/elnkmc/elnk.c
@@ -0,0 +1,2071 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ Elnk.c
+
+Abstract:
+
+ This is the main file for the 3Com Etherlink/MC and Etherlink 16
+ Ethernet adapters. This driver conforms to the NDIS 3.0 interface.
+
+Author:
+
+ Johnson R. Apacible (JohnsonA) 10-June-1991
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+
+//
+// So we can trace things...
+//
+#define STATIC
+
+#include <efilter.h>
+#include <elnkhw.h>
+#include <elnksw.h>
+#include "keywords.h"
+
+//
+// Globals
+//
+
+NDIS_PHYSICAL_ADDRESS HighestAcceptableMax =
+ NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
+
+NDIS_HANDLE ElnkMacHandle;
+LIST_ENTRY ElnkAdapterList;
+NDIS_SPIN_LOCK ElnkAdapterListLock;
+NDIS_HANDLE ElnkNdisWrapperHandle;
+
+PDRIVER_OBJECT ElnkDriverObject;
+
+STATIC
+BOOLEAN
+ElnkInitialInit(
+ IN PELNK_ADAPTER Adapter,
+ IN UINT ElnkInterruptVector
+ );
+
+STATIC
+NDIS_STATUS
+ElnkOpenAdapter(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT NDIS_HANDLE *MacBindingHandle,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_HANDLE MacAdapterContext,
+ IN UINT OpenOptions,
+ IN PSTRING AddressingInformation OPTIONAL
+ );
+
+VOID
+Elnk16GenerateIdPattern(
+ IN PELNK_ADAPTER Adapter
+ );
+
+STATIC
+NDIS_STATUS
+ElnkCloseAdapter(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+extern
+VOID
+ElnkQueueRequest(
+ IN PELNK_ADAPTER Adapter,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+STATIC
+NDIS_STATUS
+ElnkReset(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+VOID
+ElnkUnloadMac(
+ IN NDIS_HANDLE MacMacContext
+ );
+
+VOID
+ElnkRemoveAdapter(
+ IN NDIS_HANDLE MacAdapterContext
+ );
+
+NDIS_STATUS
+ElnkAddAdapter(
+ IN NDIS_HANDLE MacMacContext,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING DeviceName
+ );
+
+STATIC
+VOID
+ElnkCloseAction(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+VOID
+InitializeAdapterVariables(
+ IN PELNK_ADAPTER Adapter
+ );
+
+VOID
+ResetAdapterVariables(
+ IN PELNK_ADAPTER Adapter
+ );
+
+VOID
+ElnkDeleteAdapterMemory(
+ IN PELNK_ADAPTER Adapter
+ );
+
+BOOLEAN
+ElnkAllocateAdapterMemory(
+ IN PELNK_ADAPTER Adapter
+ );
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+
+#pragma NDIS_INIT_FUNCTION(DriverEntry)
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This is the primary initialization routine for the Elnk driver.
+ It is simply responsible for the intializing the wrapper and registering
+ the MAC. It then calls a system and architecture specific routine that
+ will initialize and register each adapter.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+Return Value:
+
+ The status of the operation.
+
+--*/
+
+{
+
+ //
+ // Receives the status of the NdisRegisterMac operation.
+ //
+ NDIS_STATUS Status;
+ NDIS_HANDLE NdisWrapperHandle;
+
+#if ELNKMC
+ static NDIS_STRING MacName = NDIS_STRING_CONST("ELNKMC");
+ #if NDIS_WIN
+ UCHAR pIds[sizeof (EISA_MCA_ADAPTER_IDS) + sizeof (USHORT)];
+ #endif
+#else
+ static NDIS_STRING MacName = NDIS_STRING_CONST("ELNK16");
+#endif
+
+ char Tmp[sizeof(NDIS_MAC_CHARACTERISTICS)];
+ PNDIS_MAC_CHARACTERISTICS ElnkChar = (PNDIS_MAC_CHARACTERISTICS)Tmp;
+
+
+#if NDIS_WIN
+#if ELNKMC
+ ((PEISA_MCA_ADAPTER_IDS)pIds)->nEisaAdapters=0;
+ ((PEISA_MCA_ADAPTER_IDS)pIds)->nMcaAdapters=1;
+ *(PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray)=ELNKMC_ADAPTER_ID;
+ (PVOID) DriverObject = (PVOID) pIds;
+#endif
+#endif
+
+ //
+ // Initialize the wrapper.
+ //
+
+ NdisInitializeWrapper(
+ &NdisWrapperHandle,
+ DriverObject,
+ RegistryPath,
+ NULL
+ );
+
+
+ ElnkDriverObject = DriverObject;
+ ElnkNdisWrapperHandle = NdisWrapperHandle;
+ //
+ // Initialize the MAC characteristics for the call to
+ // NdisRegisterMac.
+ //
+
+ ElnkChar->MajorNdisVersion = ELNK_NDIS_MAJOR_VERSION;
+ ElnkChar->MinorNdisVersion = ELNK_NDIS_MINOR_VERSION;
+ ElnkChar->OpenAdapterHandler = ElnkOpenAdapter;
+ ElnkChar->CloseAdapterHandler = ElnkCloseAdapter;
+ ElnkChar->RequestHandler = ElnkRequest;
+ ElnkChar->SendHandler = ElnkSend;
+ ElnkChar->TransferDataHandler = ElnkTransferData;
+ ElnkChar->ResetHandler = ElnkReset;
+ ElnkChar->QueryGlobalStatisticsHandler = ElnkQueryGlobalStatistics;
+ ElnkChar->UnloadMacHandler = ElnkUnloadMac;
+ ElnkChar->AddAdapterHandler = ElnkAddAdapter;
+ ElnkChar->RemoveAdapterHandler = ElnkRemoveAdapter;
+ ElnkChar->Name = MacName;
+
+ //
+ // Initialize Globals
+ //
+
+ InitializeListHead(&ElnkAdapterList);
+ NdisAllocateSpinLock(&ElnkAdapterListLock);
+
+ NdisRegisterMac(
+ &Status,
+ &ElnkMacHandle,
+ NdisWrapperHandle,
+ NULL,
+ ElnkChar,
+ sizeof(*ElnkChar)
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ if ELNKDEBUG DPrint1("Elnk: NdisRegisterMac failed\n");
+
+ NdisFreeSpinLock(&ElnkAdapterListLock);
+ NdisTerminateWrapper(NdisWrapperHandle, NULL);
+ return NDIS_STATUS_FAILURE;
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+
+}
+
+#if ELNKMC
+
+#pragma NDIS_INIT_FUNCTION(ElnkmcRegisterAdapter)
+
+NDIS_STATUS
+ElnkmcRegisterAdapter(
+ IN NDIS_HANDLE NdisMacHandle,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING DeviceName,
+ IN UINT ElnkInterruptVector,
+ IN NDIS_PHYSICAL_ADDRESS ElnkSharedRam,
+ IN USHORT ElnkIOBase,
+ IN PUCHAR CurrentAddress,
+ IN UINT MaximumMulticastAddresses,
+ IN UINT MaximumOpenAdapters,
+ IN BOOLEAN ConfigError,
+ IN NDIS_STATUS ConfigErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ This routine (and its interface) are not portable. They are
+ defined by the OS and the architecture.
+
+ This routine is responsible for the allocation of the datastructures
+ for the driver as well as any hardware specific details necessary
+ to talk with the device.
+
+Arguments:
+
+ NdisMacHandle - The handle given back to the mac from ndis when
+ the mac registered itself.
+
+ ConfigurationHandle - Handle passed to MacAddAdapter.
+
+ DeviceName - The string containing the name to give to the device
+ adapter. This name is preallocated by the caller and cannot be
+ reused until the adapter is unloaded.
+
+ ElnkInterruptVector - The interrupt vector to used for the adapter.
+
+ ElnkSharedRam - address of the card RAM to be mapped.
+
+ ElnkIOBase - base address of the card port I/O addresses.
+
+ CurrentAddress - the alternative address to be used by the card. If NULL,
+ the BIA is used.
+
+ MaximumMulticastAddresses - The maximum number of multicast
+ addresses to filter at any one time.
+
+ MaximumOpenAdapters - The maximum number of opens at any one time.
+
+ ConfigError - Was there a configuration error
+
+ ConfigErrorCode - The NDIS_ERROR_CODE to log as the error.
+
+Return Value:
+
+ Returns false if anything occurred that prevents the initialization
+ of the adapter.
+
+--*/
+
+{
+
+ //
+ // Pointer for the adapter root.
+ //
+ PELNK_ADAPTER Adapter;
+
+ //
+ // status of various calls
+ //
+
+ NDIS_STATUS Status;
+
+ //
+ // adapter information
+ //
+ NDIS_ADAPTER_INFORMATION AdapterInformation;
+
+ //
+ // Allocate the Adapter block.
+ //
+
+ Status = ELNK_ALLOC_PHYS(&Adapter, sizeof(ELNK_ADAPTER));
+
+ if ( Status == NDIS_STATUS_SUCCESS ) {
+
+ NdisZeroMemory(
+ Adapter,
+ sizeof(ELNK_ADAPTER)
+ );
+
+
+ Adapter->NdisMacHandle = NdisMacHandle;
+
+ //
+ // Should an alternative address be used?
+ //
+
+ if (CurrentAddress != NULL) {
+ Adapter->AddressChanged = TRUE;
+ ETH_COPY_NETWORK_ADDRESS(
+ Adapter->CurrentAddress,
+ CurrentAddress
+ );
+ } else {
+ Adapter->AddressChanged = FALSE;
+ }
+
+ //
+ // Set the port addresses.
+ //
+
+ Adapter->IoBase = ElnkIOBase;
+ Adapter->CurrentCsr = CSR_DEFAULT;
+
+ Adapter->IsExternal = TRUE;
+
+ Adapter->CardOffset = 0xC000;
+ Adapter->SharedRamSize = 16;
+ Adapter->SharedRamPhys = NdisGetPhysicalAddressLow(ElnkSharedRam);
+ Adapter->InterruptVector = ElnkInterruptVector;
+
+ Adapter->NumberOfTransmitBuffers =
+ ELNKMC_NUMBER_OF_TRANSMIT_BUFFERS;
+ Adapter->NumberOfReceiveBuffers =
+ ELNKMC_NUMBER_OF_RECEIVE_BUFFERS;
+
+ Adapter->MemoryIsMapped = FALSE;
+
+ //
+ // Initialize the interrupt.
+ //
+
+ InitializeListHead(&Adapter->OpenBindings);
+ InitializeListHead(&Adapter->CloseList);
+
+ Adapter->IsrLevel = (KIRQL)(HIGH_LEVEL - ElnkInterruptVector);
+ InitializeAdapterVariables(Adapter);
+ ResetAdapterVariables(Adapter);
+
+
+ //
+ // We can start the chip. We may not
+ // have any bindings to indicate to but this
+ // is unimportant.
+ //
+
+ NdisZeroMemory(&AdapterInformation, sizeof(NDIS_ADAPTER_INFORMATION));
+
+ AdapterInformation.DmaChannel = 0;
+ AdapterInformation.Master = FALSE;
+ AdapterInformation.AdapterType = NdisInterfaceMca;
+ AdapterInformation.PhysicalMapRegistersNeeded = 0;
+ AdapterInformation.MaximumPhysicalMapping = 0;
+ AdapterInformation.NumberOfPortDescriptors = 1;
+ AdapterInformation.PortDescriptors[0].InitialPort = (ULONG)(Adapter->IoBase);
+ AdapterInformation.PortDescriptors[0].NumberOfPorts = 0x10;
+ AdapterInformation.PortDescriptors[0].PortOffset = NULL;
+
+ if (NdisRegisterAdapter(
+ &Adapter->NdisAdapterHandle,
+ Adapter->NdisMacHandle,
+ Adapter,
+ ConfigurationHandle,
+ DeviceName,
+ &AdapterInformation
+ ) != NDIS_STATUS_SUCCESS) {
+
+ ElnkLogError(
+ Adapter,
+ registerAdapter,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+ if ELNKDEBUG DPrint1("ElnkmcRegisterAdapter: NdisRegisterAdapter failed\n");
+ ELNK_FREE_PHYS(Adapter);
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ if (ConfigError) {
+
+ ElnkLogError(
+ Adapter,
+ registerAdapter,
+ ConfigErrorCode,
+ 0
+ );
+
+ NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
+
+ ELNK_FREE_PHYS(Adapter);
+
+ return(NDIS_STATUS_FAILURE);
+
+ }
+
+ //
+ // Allocate adapter structures
+ //
+
+ if (!ElnkAllocateAdapterMemory(Adapter)) {
+
+ ElnkLogError(
+ Adapter,
+ registerAdapter,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+ if ELNKDEBUG DPrint1("ElnkRegisterAdapter - unsuccessful memory allocation\n");
+
+ NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
+ ELNK_FREE_PHYS(Adapter);
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ NdisInitializeTimer(
+ &Adapter->DeadmanTimer,
+ (PVOID) ElnkDeadmanDpc,
+ (PVOID) Adapter
+ );
+
+ NdisInitializeTimer(
+ &Adapter->DeferredTimer,
+ (PVOID) ElnkStandardInterruptDpc,
+ (PVOID) Adapter
+ );
+
+ NdisAllocateSpinLock(&Adapter->Lock);
+
+ //
+ // Get station address
+ //
+ ElnkGetStationAddress(Adapter);
+
+ //
+ // Check for validity of the address
+ //
+ if (((Adapter->NetworkAddress[0] == 0xFF) &&
+ (Adapter->NetworkAddress[1] == 0xFF) &&
+ (Adapter->NetworkAddress[2] == 0xFF) &&
+ (Adapter->NetworkAddress[3] == 0xFF) &&
+ (Adapter->NetworkAddress[4] == 0xFF) &&
+ (Adapter->NetworkAddress[5] == 0xFF)) ||
+ ((Adapter->NetworkAddress[0] == 0x00) &&
+ (Adapter->NetworkAddress[1] == 0x00) &&
+ (Adapter->NetworkAddress[2] == 0x00) &&
+ (Adapter->NetworkAddress[3] == 0x00) &&
+ (Adapter->NetworkAddress[4] == 0x00) &&
+ (Adapter->NetworkAddress[5] == 0x00)))
+ {
+ ElnkLogError(
+ Adapter,
+ startChip,
+ NDIS_ERROR_CODE_INVALID_VALUE_FROM_ADAPTER,
+ 0);
+
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // Do the initial init first so we can get the adapter's address
+ // before creating the filter DB.
+ //
+ Adapter->FilterDB = NULL;
+
+ if (!EthCreateFilter(
+ MaximumMulticastAddresses,
+ ElnkChangeAddresses,
+ ElnkChangeClass,
+ ElnkCloseAction,
+ Adapter->CurrentAddress,
+ &Adapter->Lock,
+ &Adapter->FilterDB
+ )) {
+
+ ElnkLogError(
+ Adapter,
+ registerAdapter,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+ if ELNKDEBUG
+ DPrint1("ElnkRegisterAdapter - unsuccessful filter create.\n");
+
+ NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
+ NdisFreeSpinLock(&Adapter->Lock);
+ ELNK_FREE_PHYS(Adapter);
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ if (!ElnkInitialInit(Adapter, ElnkInterruptVector))
+ {
+ EthDeleteFilter(Adapter->FilterDB);
+ NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
+ NdisFreeSpinLock(&Adapter->Lock);
+ ELNK_FREE_PHYS(Adapter);
+
+ return NDIS_STATUS_FAILURE;
+ }
+ else
+ {
+ //
+ // Record it in the global adapter list.
+ //
+
+ NdisInterlockedInsertTailList(&ElnkAdapterList,
+ &Adapter->AdapterList,
+ &ElnkAdapterListLock
+ );
+ return NDIS_STATUS_SUCCESS;
+
+ }
+
+
+ } else {
+
+ if ELNKDEBUG DPrint1("ElnkRegisterAdapter - failed allocation of adapter block.\n");
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+}
+#else
+
+
+#pragma NDIS_INIT_FUNCTION(Elnk16RegisterAdapter)
+
+NDIS_STATUS
+Elnk16RegisterAdapter(
+ IN NDIS_HANDLE NdisMacHandle,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING DeviceName,
+ IN UINT InterruptVector,
+ IN NDIS_PHYSICAL_ADDRESS WinBase,
+ IN UINT WindowSize,
+ IN USHORT IoBase,
+ IN BOOLEAN IsExternal,
+ IN BOOLEAN ZwsEnabled,
+ IN PUCHAR CurrentAddress,
+ IN UINT MaximumMulticastAddresses,
+ IN UINT MaximumOpenAdapters,
+ IN BOOLEAN ConfigError,
+ IN NDIS_STATUS ConfigErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ This routine (and its interface) are not portable. They are
+ defined by the OS and the architecture.
+
+ This routine is responsible for the allocation of the datastructures
+ for the driver as well as any hardware specific details necessary
+ to talk with the device.
+
+Arguments:
+
+ NdisMacHandle - The handle given back to the mac from ndis when
+ the mac registered itself.
+
+ ConfigurationHandle - Handle passed to MacAddAdapter.
+
+ DeviceName - The string containing the name to give to the device
+ adapter. This name is preallocated by the caller and cannot be
+ reused until the adapter is unloaded.
+
+ InterruptVector - The interrupt vector to used for the adapter.
+
+ WinBase - Base address of card window.
+
+ WindowSize - Size of card window.
+
+ IoBase - address of I/O base register.
+
+ IsExternal - are we using the external transceiver?
+
+ ZwsEnable - should Zero Wait Status be enabled
+
+ CurrentAddress - the alternative address to be used by the card. If NULL,
+ the BIA is used.
+
+ MaximumMulticastAddresses - The maximum number of multicast
+ addresses to filter at any one time.
+
+ MaximumOpenAdapters - The maximum number of opens at any one time.
+
+ ConfigError - Was there a configuration error
+
+ ConfigErrorCode - The NDIS_ERROR_CODE to log as the error.
+
+Return Value:
+
+ Returns NDIS_STATUS_FAILURE if anything occurred that prevents the initialization
+ of the adapter.
+
+--*/
+
+{
+
+ //
+ // Pointer for the adapter root.
+ //
+ PELNK_ADAPTER Adapter;
+
+ //
+ // status of various calls
+ //
+
+ NDIS_STATUS Status;
+
+ //
+ // adapter information
+ //
+ NDIS_ADAPTER_INFORMATION AdapterInformation;
+
+ //
+ // Allocate the Adapter block.
+ //
+
+ Status = ELNK_ALLOC_PHYS(&Adapter, sizeof(ELNK_ADAPTER));
+
+ if ( Status == NDIS_STATUS_SUCCESS ) {
+
+ NdisZeroMemory(
+ Adapter,
+ sizeof(ELNK_ADAPTER)
+ );
+
+ Adapter->NdisMacHandle = NdisMacHandle;
+
+ //
+ // Should an alternative address be used?
+ //
+
+ if (CurrentAddress != NULL) {
+ Adapter->AddressChanged = TRUE;
+ ETH_COPY_NETWORK_ADDRESS(
+ Adapter->CurrentAddress,
+ CurrentAddress
+ );
+ } else {
+ Adapter->AddressChanged = FALSE;
+ }
+
+ //
+ // Set the port addresses.
+ //
+
+ Adapter->IoBase = IoBase;
+ Adapter->CurrentCsr = CSR_DEFAULT;
+
+ Adapter->SharedRamPhys = NdisGetPhysicalAddressLow(WinBase);
+ Adapter->SharedRamSize = WindowSize;
+
+ //
+ // Allocate memory for all of the adapter structures.
+ //
+
+ Adapter->MemoryIsMapped = FALSE;
+
+ //
+ // Initialize the interrupt.
+ //
+
+ InitializeListHead(&Adapter->OpenBindings);
+ InitializeListHead(&Adapter->CloseList);
+
+ Adapter->IsrLevel = (KIRQL)(HIGH_LEVEL - InterruptVector);
+ Adapter->InterruptVector = (UINT) InterruptVector;
+
+ //
+ // We can start the chip. We may not
+ // have any bindings to indicate to but this
+ // is unimportant.
+ //
+
+ NdisZeroMemory(&AdapterInformation, sizeof(NDIS_ADAPTER_INFORMATION));
+
+ AdapterInformation.DmaChannel = 0;
+ AdapterInformation.Master = FALSE;
+ AdapterInformation.AdapterType = NdisInterfaceIsa;
+ AdapterInformation.PhysicalMapRegistersNeeded = 0;
+ AdapterInformation.MaximumPhysicalMapping = 0;
+ AdapterInformation.NumberOfPortDescriptors = 1;
+ AdapterInformation.PortDescriptors[0].InitialPort = (ULONG)(Adapter->IoBase);
+ AdapterInformation.PortDescriptors[0].NumberOfPorts = 0x10;
+ AdapterInformation.PortDescriptors[0].PortOffset = NULL;
+
+ if (NdisRegisterAdapter(
+ &Adapter->NdisAdapterHandle,
+ Adapter->NdisMacHandle,
+ Adapter,
+ ConfigurationHandle,
+ DeviceName,
+ &AdapterInformation
+ ) != NDIS_STATUS_SUCCESS) {
+
+ ElnkLogError(
+ Adapter,
+ registerAdapter,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+
+ if ELNKDEBUG DPrint1("Elnk16RegisterAdapter: NdisRegisterAdapter failed\n");
+ ELNK_FREE_PHYS(Adapter);
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ if (ConfigError) {
+
+ ElnkLogError(
+ Adapter,
+ registerAdapter,
+ ConfigErrorCode,
+ 0
+ );
+
+ NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
+
+ ELNK_FREE_PHYS(Adapter);
+
+ return(NDIS_STATUS_FAILURE);
+
+ }
+
+ //
+ // Verify the Configuration of the hardware
+ //
+
+ if (!Elnk16ConfigureAdapter(
+ Adapter,
+ IsExternal,
+ ZwsEnabled
+ )) {
+
+ ElnkLogError(
+ Adapter,
+ registerAdapter,
+ NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
+ 0
+ );
+
+ NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
+ ELNK_FREE_PHYS(Adapter);
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // Allocate adapter structures
+ //
+
+ if (!ElnkAllocateAdapterMemory(Adapter)) {
+
+ ElnkLogError(
+ Adapter,
+ registerAdapter,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+ if ELNKDEBUG DPrint1("ElnkRegisterAdapter - unsuccessful memory allocation\n");
+
+ NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
+ ELNK_FREE_PHYS(Adapter);
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ InitializeAdapterVariables(Adapter);
+ ResetAdapterVariables(Adapter);
+
+ NdisInitializeTimer(
+ &Adapter->DeadmanTimer,
+ (PVOID) ElnkDeadmanDpc,
+ (PVOID) Adapter
+ );
+
+ NdisInitializeTimer(
+ &Adapter->DeferredTimer,
+ (PVOID) ElnkStandardInterruptDpc,
+ (PVOID) Adapter
+ );
+
+ NdisAllocateSpinLock(&Adapter->Lock);
+
+ //
+ // Get station address
+ //
+ ElnkGetStationAddress(Adapter);
+
+ //
+ // Check for validity of the address
+ //
+ if (((Adapter->NetworkAddress[0] == 0xFF) &&
+ (Adapter->NetworkAddress[1] == 0xFF) &&
+ (Adapter->NetworkAddress[2] == 0xFF) &&
+ (Adapter->NetworkAddress[3] == 0xFF) &&
+ (Adapter->NetworkAddress[4] == 0xFF) &&
+ (Adapter->NetworkAddress[5] == 0xFF)) ||
+ ((Adapter->NetworkAddress[0] == 0x00) &&
+ (Adapter->NetworkAddress[1] == 0x00) &&
+ (Adapter->NetworkAddress[2] == 0x00) &&
+ (Adapter->NetworkAddress[3] == 0x00) &&
+ (Adapter->NetworkAddress[4] == 0x00) &&
+ (Adapter->NetworkAddress[5] == 0x00)))
+ {
+ ElnkLogError(
+ Adapter,
+ startChip,
+ NDIS_ERROR_CODE_INVALID_VALUE_FROM_ADAPTER,
+ 0);
+
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ if (!EthCreateFilter(
+ MaximumMulticastAddresses,
+ ElnkChangeAddresses,
+ ElnkChangeClass,
+ ElnkCloseAction,
+ Adapter->CurrentAddress,
+ &Adapter->Lock,
+ &Adapter->FilterDB
+ )) {
+
+ ElnkLogError(
+ Adapter,
+ registerAdapter,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+ if ELNKDEBUG
+ DPrint1("ElnkRegisterAdapter - unsuccessful filter create.\n");
+ ElnkDeleteAdapterMemory(Adapter);
+
+ NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
+ NdisFreeSpinLock(&Adapter->Lock);
+ ELNK_FREE_PHYS(Adapter);
+ return NDIS_STATUS_FAILURE;
+ }
+
+ if (!ElnkInitialInit(
+ Adapter,
+ Adapter->InterruptVector
+ )) {
+
+ EthDeleteFilter(Adapter->FilterDB);
+ ElnkDeleteAdapterMemory(Adapter);
+
+ NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
+ NdisFreeSpinLock(&Adapter->Lock);
+ ELNK_FREE_PHYS(Adapter);
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ //
+ // Record it in the global adapter list.
+ //
+
+ NdisInterlockedInsertTailList(&ElnkAdapterList,
+ &Adapter->AdapterList,
+ &ElnkAdapterListLock
+ );
+ return NDIS_STATUS_SUCCESS;
+
+ } else {
+
+ if ELNKDEBUG DPrint1("ElnkRegisterAdapter - unsuccessful allocation of adapter block.\n");
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+}
+#endif
+
+#pragma NDIS_INIT_FUNCTION(ElnkAllocateAdapterMemory)
+
+BOOLEAN
+ElnkAllocateAdapterMemory(
+ IN PELNK_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine is responsible for the allocation of the datastructures
+ for the Adapter structure.
+
+Arguments:
+
+ Adapter - the adapter structure to allocate for.
+
+Return Value:
+
+ Returns false if we cannot allocate memory.
+
+
+--*/
+{
+
+ NDIS_STATUS Status;
+
+ //
+ // add 1 for multicast block
+ //
+
+ Status = ELNK_ALLOC_PHYS(
+ &Adapter->TransmitInfo,
+ sizeof(ELNK_TRANSMIT_INFO) *
+ (Adapter->NumberOfTransmitBuffers + 1)
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ ElnkLogError(
+ Adapter,
+ allocateAdapterMemory,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+ ElnkDeleteAdapterMemory(Adapter);
+ return(FALSE);
+ }
+
+ Status = ELNK_ALLOC_PHYS(
+ &Adapter->ReceiveInfo,
+ sizeof(ELNK_RECEIVE_INFO) *
+ Adapter->NumberOfReceiveBuffers
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ ElnkLogError(
+ Adapter,
+ allocateAdapterMemory,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 1
+ );
+ ElnkDeleteAdapterMemory(Adapter);
+ return(FALSE);
+ }
+ return(TRUE);
+}
+
+
+VOID
+ElnkDeleteAdapterMemory(
+ IN PELNK_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine is responsible for the deallocation of the datastructures
+ for the Adapter structure.
+
+Arguments:
+
+ Adapter - the adapter structure to deallocate for.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ if (Adapter->TransmitInfo != NULL) {
+ ELNK_FREE_PHYS(Adapter->TransmitInfo);
+ }
+
+ if (Adapter->ReceiveInfo != NULL) {
+ ELNK_FREE_PHYS(Adapter->ReceiveInfo);
+
+ }
+}
+
+#pragma NDIS_INIT_FUNCTION(InitializeAdapterVariables)
+
+VOID
+InitializeAdapterVariables(
+ IN PELNK_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine is initializes the adapter variables.
+
+Arguments:
+
+ Adapter - the adapter structure to initialize
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // No long necessary -- we zero structure out and this routine is
+ // only called at initialinit time.
+ //
+ // Adapter->OpenCount = 0;
+ //
+
+ Adapter->References = 1;
+ Adapter->ResetInProgress = FALSE;
+ Adapter->ResettingOpen = NULL;
+ Adapter->OldParameterField = DEFAULT_PARM5;
+ Adapter->FirstOpen = TRUE;
+ Adapter->FirstReset = TRUE;
+ Adapter->DoingProcessing = FALSE;
+ Adapter->ProcessingRequests = FALSE;
+ Adapter->StatisticsField = 0x12345678;
+
+ //
+ // Packet counts
+ //
+ // No long necessary -- we zero structure out and this routine is
+ // only called at initialinit time.
+ //
+ // Adapter->GoodTransmits = 0;
+ // Adapter->GoodReceives = 0;
+
+ //
+ // Count of transmit errors
+ //
+ // No long necessary -- we zero structure out and this routine is
+ // only called at initialinit time.
+ //
+ // Adapter->RetryFailure = 0;
+ // Adapter->LostCarrier = 0;
+ // Adapter->UnderFlow = 0;
+ // Adapter->NoClearToSend = 0;
+ // Adapter->Deferred = 0;
+ // Adapter->OneRetry = 0;
+ // Adapter->MoreThanOneRetry = 0;
+
+ //
+ // Count of receive errors
+ //
+ // No long necessary -- we zero structure out and this routine is
+ // only called at initialinit time.
+ //
+ // Adapter->FrameTooShort = 0;
+ // Adapter->NoEofDetected = 0;
+}
+
+
+VOID
+ResetAdapterVariables(
+ IN PELNK_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine resets the adapter variables to their post reset value
+
+Arguments:
+
+ Adapter - the adapter structure whose elements are to be reset
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Adapter->TransmitsQueued = 0;
+ Adapter->FirstRequest = NULL;
+ Adapter->LastRequest = NULL;
+ Adapter->FirstPendingCommand = ELNK_EMPTY;
+ Adapter->LastPendingCommand = ELNK_EMPTY;
+ Adapter->NextCommandBlock = 0;
+
+ Adapter->NumberOfAvailableCommandBlocks =
+ Adapter->NumberOfTransmitBuffers;
+
+ Adapter->FirstLoopBack = NULL;
+ Adapter->LastLoopBack = NULL;
+ Adapter->FirstFinishTransmit = NULL;
+ Adapter->LastFinishTransmit = NULL;
+ Adapter->StageOpen = TRUE;
+ Adapter->AlreadyProcessingStage = FALSE;
+ Adapter->FirstStagePacket = NULL;
+ Adapter->LastStagePacket = NULL;
+}
+
+
+STATIC
+NDIS_STATUS
+ElnkOpenAdapter(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT NDIS_HANDLE *MacBindingHandle,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_HANDLE MacAdapterContext,
+ IN UINT OpenOptions,
+ IN PSTRING AddressingInformation OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to create an open instance of an adapter, in effect
+ creating a binding between an upper-level module and the MAC module over
+ the adapter.
+
+Arguments:
+
+ MacBindingHandle - A pointer to a location in which the MAC stores
+ a context value that it uses to represent this binding.
+
+ SelectedMediumIndex - Index in MediumArray of the medium type that
+ the MAC wishes to be viewed as.
+
+ MediumArray - Array of medium types which a protocol supports.
+
+ MediumArraySize - Number of elements in MediumArray.
+
+ NdisBindingContext - A value to be recorded by the MAC and passed as
+ context whenever an indication is delivered by the MAC for this binding.
+
+ MacAdapterContext - The value associated with the adapter that is being
+ opened when the MAC registered the adapter with NdisRegisterAdapter.
+
+ OpenOptions - bit mask.
+
+ AddressingInformation - An optional pointer to a variable length string
+ containing hardware-specific information that can be used to program the
+ device. (This is not used by this MAC.)
+
+Return Value:
+
+ The function value is the status of the operation. If the MAC does not
+ complete this request synchronously, the value would be
+ NDIS_STATUS_PENDING.
+
+
+--*/
+
+{
+
+
+ //
+ // The ELNK_ADAPTER that this open binding should belong too.
+ //
+ PELNK_ADAPTER Adapter;
+
+ //
+ // for index
+ //
+
+ UINT i;
+
+ //
+ // return status
+ //
+
+ NDIS_STATUS Status;
+
+ //
+ // Pointer to the space allocated for the binding.
+ //
+ PELNK_OPEN NewOpen;
+
+ //
+ // Pointer to the reserved portion of ndisrequest
+ //
+ PELNK_REQUEST_RESERVED Reserved;
+
+ //
+ // Holds the status that should be returned to the caller.
+ //
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+ OpenErrorStatus; AddressingInformation; OpenOptions;
+
+ //
+ // If we are being removed, don't allow new opens.
+ //
+
+ Adapter = PELNK_ADAPTER_FROM_CONTEXT_HANDLE(MacAdapterContext);
+
+ NdisInterlockedAddUlong(&Adapter->References, 1, &Adapter->Lock);
+
+ //
+ // Search for the medium type (802.3)
+ //
+
+ for (i = 0; i < MediumArraySize; i++){
+ if (MediumArray[i] == NdisMedium802_3){
+ break;
+ }
+ }
+
+ if (i == MediumArraySize){
+ NdisAcquireSpinLock(&Adapter->Lock);
+ StatusToReturn = NDIS_STATUS_UNSUPPORTED_MEDIA;
+ goto OpenDoDeferred;
+ }
+
+ *SelectedMediumIndex = i;
+
+
+ //
+ // Allocate the space for the open binding. Fill in the fields.
+ //
+
+ Status = ELNK_ALLOC_PHYS(&NewOpen, sizeof(ELNK_OPEN));
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ StatusToReturn = NDIS_STATUS_RESOURCES;
+ goto OpenDoDeferred;
+
+ }
+
+ *MacBindingHandle = BINDING_HANDLE_FROM_PELNK_OPEN(NewOpen);
+ InitializeListHead(&NewOpen->OpenList);
+ NewOpen->NdisBindingContext = NdisBindingContext;
+ NewOpen->References = 1;
+ NewOpen->BindingShuttingDown = FALSE;
+ NewOpen->OwningAdapter = Adapter;
+ NewOpen->ProtOptionFlags = 0;
+
+ NewOpen->OpenCloseRequest.RequestType = NdisRequestOpen;
+ Reserved = PELNK_RESERVED_FROM_REQUEST(&NewOpen->OpenCloseRequest);
+ Reserved->OpenBlock = NewOpen;
+ Reserved->Next = (PNDIS_REQUEST)NULL;
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ ElnkQueueRequest(Adapter, &NewOpen->OpenCloseRequest);
+
+ StatusToReturn = NDIS_STATUS_PENDING;
+
+ //
+ // Fire off the timer for the next state.
+ //
+
+ if (Adapter->FirstOpen) {
+
+ Adapter->FirstOpen = FALSE;
+
+ NdisSetTimer(
+ &Adapter->DeadmanTimer,
+ 2000
+ );
+ }
+
+OpenDoDeferred:
+ ELNK_DO_DEFERRED(Adapter);
+ return StatusToReturn;
+}
+
+STATIC
+NDIS_STATUS
+ElnkCloseAdapter(
+ IN NDIS_HANDLE MacBindingHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine causes the MAC to close an open handle (binding).
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality it is a PELNK_OPEN.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+
+{
+ //
+ // Elnk Adapter this open belongs to
+ //
+ PELNK_ADAPTER Adapter;
+
+ //
+ // Pointer to the space allocated for the binding
+ //
+ PELNK_OPEN Open;
+
+ //
+ // Status to return to the caller
+ //
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ Adapter = PELNK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ //
+ // Hold the lock while we update the reference counts for the
+ // adapter and the open.
+ //
+
+ Open = PELNK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ //
+ // Don't do anything if it's closing
+ //
+
+ if (!Open->BindingShuttingDown) {
+
+ PELNK_REQUEST_RESERVED Reserved = PELNK_RESERVED_FROM_REQUEST(&Open->OpenCloseRequest);
+
+ Open->OpenCloseRequest.RequestType = NdisRequestClose;
+ Reserved->OpenBlock = Open;
+ Reserved->Next = (PNDIS_REQUEST)NULL;
+
+ Open->References++;
+
+ ElnkQueueRequest(Adapter, &Open->OpenCloseRequest);
+
+ //
+ // Remove the creation reference.
+ //
+ Open->References--;
+
+ StatusToReturn = NDIS_STATUS_PENDING;
+
+ } else {
+
+ StatusToReturn = NDIS_STATUS_CLOSING;
+
+ }
+
+ //
+ // This macro assumes it is called with the lock held,
+ // and releases it.
+ //
+
+ ELNK_DO_DEFERRED(Adapter);
+ return StatusToReturn;
+
+}
+
+
+extern
+VOID
+ElnkUnloadMac(
+ IN NDIS_HANDLE MacMacContext
+ )
+
+/*++
+
+Routine Description:
+
+ ElnkUnload is called when the MAC is to unload itself.
+
+Arguments:
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS InitStatus;
+
+ //
+ // If the list is empty, or we just emptied it,
+ // then unload ourselves.
+ //
+
+ ASSERT(IsListEmpty(&ElnkAdapterList));
+
+ NdisFreeSpinLock(&ElnkAdapterListLock);
+
+ NdisDeregisterMac(
+ &InitStatus,
+ ElnkMacHandle
+ );
+
+
+
+ NdisTerminateWrapper(
+ ElnkNdisWrapperHandle,
+ NULL
+ );
+
+ return;
+}
+
+
+#pragma NDIS_INIT_FUNCTION(ElnkAddAdapter)
+
+#if ELNKMC
+
+extern
+NDIS_STATUS
+ElnkAddAdapter(
+ IN NDIS_HANDLE MacMacContext,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING AdapterName
+ )
+
+/*++
+
+Routine Description:
+
+ ElnkAddAdapter adds an adapter to the list supported
+ by this MAC.
+
+Arguments:
+
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_PENDING
+
+--*/
+
+{
+ NDIS_HANDLE ConfigHandle;
+ NDIS_STATUS Status;
+ NDIS_STRING NetAddrStr = NETWORK_ADDRESS;
+ UINT ChannelNumber = 0;
+ UINT InterruptLevel;
+ USHORT IoBase;
+ ULONG RamBase;
+ NDIS_PHYSICAL_ADDRESS PhysicalAddress;
+ NDIS_MCA_POS_DATA McaData;
+ UCHAR NetworkAddress[ETH_LENGTH_OF_ADDRESS];
+ PUCHAR CurrentAddress = NULL;
+ ULONG Length;
+ PVOID NetAddress;
+
+ BOOLEAN ConfigError = FALSE;
+ NDIS_STATUS ConfigErrorCode;
+
+ NdisOpenConfiguration(
+ &Status,
+ &ConfigHandle,
+ ConfigurationHandle
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ return NDIS_STATUS_FAILURE;
+ }
+
+ NdisReadMcaPosInformation(
+ &Status,
+ ConfigurationHandle,
+ &ChannelNumber,
+ &McaData
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ ConfigError = TRUE;
+ ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION;
+ goto RegisterAdapter;
+
+ }
+
+ //
+ // Interpret POS data
+ //
+
+ switch ((McaData.PosData1 & REG1_IO_BASE_MASK)>>1) {
+ case 0x00:
+ IoBase = 0x0300;
+ break;
+
+ case 0x01:
+ IoBase = 0x1300;
+ break;
+
+ case 0x02:
+ IoBase = 0x2300;
+ break;
+
+ case 0x03:
+ IoBase = 0x3300;
+ break;
+ }
+
+ switch ((McaData.PosData1 & REG1_RAM_BASE_MASK)>>3) {
+ case 0x00:
+ RamBase = 0x0C0000;
+ break;
+
+ case 0x01:
+ RamBase = 0x0C8000;
+ break;
+
+ case 0x02:
+ RamBase = 0x0D0000;
+ break;
+
+ case 0x03:
+ RamBase = 0x0D8000;
+ break;
+ }
+
+ switch ((McaData.PosData1 & REG1_INTERRUPT_LEVEL_MASK)>>6) {
+ case 0x00:
+ InterruptLevel = 12;
+ break;
+
+ case 0x01:
+ InterruptLevel = 7;
+ break;
+
+ case 0x02:
+ InterruptLevel = 3;
+ break;
+
+ case 0x03:
+ InterruptLevel = 9;
+ break;
+ }
+
+ //
+ // Read net address
+ //
+
+ NdisReadNetworkAddress(
+ &Status,
+ &NetAddress,
+ &Length,
+ ConfigHandle
+ );
+
+ if ((Length == ETH_LENGTH_OF_ADDRESS) && (Status == NDIS_STATUS_SUCCESS)) {
+
+ ETH_COPY_NETWORK_ADDRESS(
+ NetworkAddress,
+ NetAddress
+ );
+
+ CurrentAddress = NetworkAddress;
+ }
+
+RegisterAdapter:
+
+ NdisSetPhysicalAddressHigh(PhysicalAddress, 0);
+ NdisSetPhysicalAddressLow(PhysicalAddress, RamBase);
+
+ Status = ElnkmcRegisterAdapter(
+ ElnkMacHandle,
+ ConfigurationHandle,
+ AdapterName,
+ InterruptLevel,
+ PhysicalAddress,
+ IoBase,
+ CurrentAddress,
+ ELNK_MAXIMUM_MULTICAST,
+ 32,
+ ConfigError,
+ ConfigErrorCode
+ );
+
+ NdisCloseConfiguration(ConfigHandle);
+ return Status;
+}
+
+#else
+extern
+NDIS_STATUS
+ElnkAddAdapter(
+ IN NDIS_HANDLE MacMacContext,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING AdapterName
+ )
+
+/*++
+
+Routine Description:
+
+ ElnkAddAdapter adds an adapter to the list supported
+ by this MAC.
+
+Arguments:
+
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_PENDING
+
+--*/
+
+{
+ NDIS_HANDLE ConfigHandle;
+ NDIS_STATUS Status;
+ PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
+
+ NDIS_STRING NetAddrStr = NETWORK_ADDRESS;
+ NDIS_STRING TransStr = NDIS_STRING_CONST("Transceiver");
+ NDIS_STRING InterruptStr = NDIS_STRING_CONST("InterruptNumber");
+ NDIS_STRING IoPortStr = IOBASE;
+ NDIS_STRING RamBaseStr = NDIS_STRING_CONST("MemoryMappedBaseAddress");
+ NDIS_STRING ZWStr = NDIS_STRING_CONST("ZeroWaitState");
+ NDIS_STRING RamSizeStr = NDIS_STRING_CONST("MemoryMappedSize");
+
+ USHORT IoBase;
+ UINT InterruptVector;
+ BOOLEAN IsExternal;
+ BOOLEAN ZwsEnabled;
+ ULONG WindowBase;
+ NDIS_PHYSICAL_ADDRESS PhysicalAddress;
+ UINT WindowSize;
+ UCHAR NetworkAddress[ETH_LENGTH_OF_ADDRESS];
+ PUCHAR CurrentAddress = NULL;
+ ULONG Length;
+ PVOID NetAddress;
+
+
+ BOOLEAN ConfigError = FALSE;
+ NDIS_STATUS ConfigErrorCode;
+
+ NdisOpenConfiguration(
+ &Status,
+ &ConfigHandle,
+ ConfigurationHandle
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ return NDIS_STATUS_FAILURE;
+ }
+
+ //
+ // Read net address
+ //
+
+ NdisReadNetworkAddress(
+ &Status,
+ &NetAddress,
+ &Length,
+ ConfigHandle
+ );
+
+ if ((Length == ETH_LENGTH_OF_ADDRESS) && (Status == NDIS_STATUS_SUCCESS)) {
+
+ ETH_COPY_NETWORK_ADDRESS(
+ NetworkAddress,
+ NetAddress
+ );
+
+ CurrentAddress = NetworkAddress;
+ }
+
+#if NDIS_NT
+ //
+ // Let's get the interrupt number
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &InterruptStr,
+ NdisParameterInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+ InterruptVector = ReturnedValue->ParameterData.IntegerData;
+ } else {
+ InterruptVector = ELNK16_DEFAULT_INTERRUPT_VECTOR;
+ }
+
+ {
+ UCHAR i;
+ static UINT Interrupts[] = {3,5,7,9,10,11,12,15};
+
+ for (i=0; i < 8; i++) {
+
+ if (Interrupts[i] == InterruptVector) {
+
+ break;
+
+ }
+
+ }
+
+ if (i == 8) {
+
+ ConfigError = TRUE;
+ ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION;
+ goto RegisterAdapter;
+
+ }
+
+ }
+#endif // NDIS_NT
+
+ //
+ // Get the Io Port
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &IoPortStr,
+ NdisParameterHexInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+ IoBase = (USHORT) ReturnedValue->ParameterData.IntegerData;
+ } else {
+ IoBase = ELNK16_DEFAULT_IOBASE;
+ }
+
+
+ {
+ UINT i;
+
+ for (i=0x200; i < 0x3f0; i += 0x10) {
+
+ if ((i == 0x270) ||
+// (i == 0x290) ||
+ (i == 0x2f0) ||
+ (i == 0x370) ||
+ (i == 0x3b0) ||
+ (i == 0x3c0) ||
+ (i == 0x3d0)) {
+
+ continue;
+ }
+
+ if (i == IoBase) {
+
+ break;
+
+ }
+
+ }
+
+ if (i != IoBase) {
+
+ ConfigError = TRUE;
+ ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION;
+ goto RegisterAdapter;
+
+ }
+
+ }
+
+#if NDIS_NT
+ //
+ // Get the RamBase
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &RamBaseStr,
+ NdisParameterHexInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+ WindowBase = ReturnedValue->ParameterData.IntegerData;
+ } else {
+ WindowBase = ELNK16_DEFAULT_WINBASE;
+ }
+
+ if ((WindowBase < 0xC0000) ||
+ (WindowBase > 0xDFFFF) ||
+ ((WindowBase & 0x3FFF) != 0x0)) {
+
+ ConfigError = TRUE;
+ ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION;
+ goto RegisterAdapter;
+
+ }
+
+ //
+ // Let's get the size of the Window
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &RamSizeStr,
+ NdisParameterHexInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+ WindowSize = ReturnedValue->ParameterData.IntegerData;
+ } else {
+ WindowSize = ELNK16_DEFAULT_WINDOW_SIZE;
+ }
+
+ //
+ // Convert to local method
+ //
+
+ WindowSize = WindowSize >> 10;
+
+ if ((WindowSize != 16) &&
+ (WindowSize != 32) &&
+ (WindowSize != 48) &&
+ (WindowSize != 64)) {
+
+ ConfigError = TRUE;
+ ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION;
+ goto RegisterAdapter;
+
+ }
+
+
+ //
+ // Are we using External Transceiver?
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &TransStr,
+ NdisParameterInteger
+ );
+
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ IsExternal = (ReturnedValue->ParameterData.IntegerData == 1)?TRUE:FALSE;
+
+ } else {
+
+ IsExternal = TRUE;
+
+ }
+
+ //
+ // Do we want to enable Zero wait state
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &ZWStr,
+ NdisParameterInteger
+ );
+
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ ZwsEnabled = (ReturnedValue->ParameterData.IntegerData == 1)?TRUE:FALSE;
+
+ } else {
+
+ ZwsEnabled = TRUE;
+
+ }
+#endif // NDIS_NT
+
+#if NDIS_WIN
+ // use defaults for now. We will read these values from eeprom.
+ InterruptVector = ELNK16_DEFAULT_INTERRUPT_VECTOR;
+ WindowBase = ELNK16_DEFAULT_WINBASE;
+ WindowSize = ELNK16_DEFAULT_WINDOW_SIZE;
+ IsExternal = TRUE;
+ ZwsEnabled = TRUE;
+#endif // NDIS_WIN
+
+
+RegisterAdapter:
+
+ NdisSetPhysicalAddressHigh(PhysicalAddress, 0);
+ NdisSetPhysicalAddressLow(PhysicalAddress, WindowBase);
+
+ Status = Elnk16RegisterAdapter(
+ ElnkMacHandle,
+ ConfigurationHandle,
+ AdapterName,
+ InterruptVector,
+ PhysicalAddress,
+ WindowSize,
+ IoBase,
+ IsExternal,
+ ZwsEnabled,
+ CurrentAddress,
+ ELNK_MAXIMUM_MULTICAST,
+ 32,
+ ConfigError,
+ ConfigErrorCode
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ if ELNKDEBUG DPrint1("Elnk16AddAdapter: Elnk16RegisterAdapter failed\n");
+ }
+ NdisCloseConfiguration(ConfigHandle);
+ return Status;
+}
+#endif
+
+
+extern
+VOID
+ElnkRemoveAdapter(
+ IN NDIS_HANDLE MacAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ ElnkRemoveAdapter removes an adapter previously registered
+ with NdisRegisterAdapter.
+
+Arguments:
+
+ MacAdapterContext - The context value that the MAC passed
+ to NdisRegisterAdapter; actually as pointer to a
+ ELNK_ADAPTER.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNK_ADAPTER Adapter;
+ BOOLEAN Cancelled;
+
+ Adapter = PELNK_ADAPTER_FROM_CONTEXT_HANDLE(MacAdapterContext);
+
+ ASSERT(Adapter->OpenCount == 0);
+
+ //
+ // There are no opens left, so remove ourselves.
+ //
+
+
+
+ NdisCancelTimer(&Adapter->DeadmanTimer,&Cancelled);
+
+ NdisRemoveInterrupt(&Adapter->Interrupt);
+
+ EthDeleteFilter(Adapter->FilterDB);
+
+ NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
+
+ NdisFreeSpinLock(&Adapter->Lock);
+
+ NdisAcquireSpinLock(&ElnkAdapterListLock);
+
+ RemoveEntryList(&Adapter->AdapterList);
+
+ NdisReleaseSpinLock(&ElnkAdapterListLock);
+
+ ELNK_FREE_PHYS(Adapter);
+
+#if !ELNKMC
+ //
+ // Put the card in START state. This leaves the
+ // card in the same state as a hardware powerup.
+ // This guarantees that the card is in a known workable
+ // state if an additional AddAdapter is issued before the
+ // power has been cycled. Otherwise, the AddAdapter fails.
+ //
+
+ // Go to Run state
+ NdisRawWritePortUchar(ELNK16_ID_PORT,0x00);
+ Elnk16GenerateIdPattern(Adapter);
+ NdisRawWritePortUchar(ELNK16_ID_PORT,0x00);
+
+ // Go to Reset state
+ Elnk16GenerateIdPattern(Adapter);
+
+ // Go to IoLoad state
+ Elnk16GenerateIdPattern(Adapter);
+
+ // Go to Config state
+ NdisRawWritePortUchar(ELNK16_ID_PORT,(UCHAR)0xFF);
+
+ // Reset the card, which leaves the card in Start state
+ NdisRawWritePortUchar(ELNK16_ICR,ICR_RESET);
+#endif
+
+ return;
+}
diff --git a/private/ntos/ndis/elnkmc/elnkhw.h b/private/ntos/ndis/elnkmc/elnkhw.h
new file mode 100644
index 000000000..bec2e0414
--- /dev/null
+++ b/private/ntos/ndis/elnkmc/elnkhw.h
@@ -0,0 +1,315 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ elnkhw.h
+
+Abstract:
+
+ Hardware specific values for the 3Com Etherlink/MC and Etherlink 16
+ NDIS 3.0 driver.
+
+Author:
+
+ Johnson R. Apacible (JohnsonA) 9-June-1991
+
+Environment:
+
+ This driver is expected to work in DOS and NT at the equivalent
+ of kernel mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+
+--*/
+
+#ifndef _ELNKHARDWARE_
+#define _ELNKHARDWARE_
+#include <switch.h>
+
+#define MINIMUM_ETHERNET_PACKET_SIZE ((UINT)60) //64 if FCS included
+#define MAXIMUM_ETHERNET_PACKET_SIZE ((UINT)1514)
+#define ELNK_OFFSET_TO_NEXT_BUFFER ((UINT)1520)
+#define MAXIMUM_CARD_ADDRESS 0xffffff
+
+#if ELNKMC
+
+#define ELNKMC_ADAPTER_ID 0x6042
+
+//
+// Elnkmc defaults
+//
+#define ELNKMC_NUMBER_OF_RECEIVE_BUFFERS ((UINT)8)
+#define ELNKMC_NUMBER_OF_TRANSMIT_BUFFERS ((UINT)2)
+#define ELNKMC_MULTICAST_BLOCK_INDEX ELNKMC_NUMBER_OF_TRANSMIT_BUFFERS
+#else
+//
+// Elnk16 Defaults
+//
+#define ELNK16_DEFAULT_IOBASE 0x300
+#define ELNK16_DEFAULT_INTERRUPT_VECTOR 5
+#define ELNK16_DEFAULT_WINBASE 0xD0000
+#define ELNK16_DEFAULT_WINDOW_SIZE 0x8000
+
+//
+// Number of receive and transmit buffers for the different Etherlink 16
+// configurations
+//
+
+#define ELNK16_16K_TRANSMITS ((UINT)2)
+#define ELNK16_16K_RECEIVES ((UINT)8)
+#define ELNK16_32K_TRANSMITS ((UINT)5)
+#define ELNK16_32K_RECEIVES ((UINT)16)
+#define ELNK16_48K_TRANSMITS ((UINT)7)
+#define ELNK16_48K_RECEIVES ((UINT)24)
+#define ELNK16_64K_TRANSMITS ((UINT)10)
+#define ELNK16_64K_RECEIVES ((UINT)32)
+#endif
+
+//
+// Common Card Registers, these are offsets from Adapter->IoBase
+//
+#define ELNK_STATION_ID 0x00
+#define ELNK_CSR 0x06
+
+#if ELNKMC
+//
+// Elnkmc Card Register
+//
+#define ELNKMC_REVISION_LEVEL 0x07
+#else
+//
+// Elnk16 Card Registers, these are offsets from Adapter->IoBase
+//
+#define ELNK16_3COM 0x00
+#define ELNK16_INTCLR 0x0A
+#define ELNK16_CAR 0x0B
+#define ELNK16_ROM_CONFIG 0x0D
+#define ELNK16_RAM_CONFIG 0x0E
+#define ELNK16_ICR 0x0F
+
+//
+// Etherlink 16 ID Port
+//
+#define ELNK16_ID_PORT 0x100
+#endif // ELNKMC
+
+//
+// CSR bits
+//
+#define CSR_BANK_SELECT_MASK 0x03
+#define CSR_INTEN 0x04
+#define CSR_INT_ACTIVE 0x08
+#define CSR_LOOP_BACK_ENABLE 0x20
+#define CSR_CA 0x40
+#define CSR_RESET 0x80
+
+//
+// ROMCR bits
+//
+#define ROMCR_BNC 0x80
+
+#if ELNKMC
+//
+// Elnkmc CSR Values
+//
+#define CSR_DEFAULT CSR_BANK_SELECT_MASK |\
+ CSR_INTEN |\
+ CSR_RESET
+#else
+
+//
+// Elnk16 CSR Values
+//
+#define CSR_DEFAULT CSR_INTEN |\
+ CSR_RESET
+//
+// Elnk16 ICR Values
+//
+#define ICR_RESET 0x10
+
+#endif
+
+//
+// Our buffer sizes.
+//
+// These are *not* configurable. Portions of the code assumes
+// that these buffers can contain *any* legal Ethernet packet.
+//
+
+#define ELNK_SIZE_OF_RECEIVE_BUFFERS (MAXIMUM_ETHERNET_PACKET_SIZE)
+
+//
+// Miscellaneous Constants
+//
+#define ELNK_NULL ((USHORT)0xffff)
+#define ELNK_EMPTY ((UINT)0xffff)
+#define ELNK_IMMEDIATE_DATA_LENGTH ((UINT)64)
+#define ELNK_MAXIMUM_MULTICAST 16
+
+//
+// Miscellaneous macros
+//
+
+#define WRITE_ADAPTER_REGISTER(_Adapter, _Offset, _Value) \
+ NdisWriteRegisterUshort((PUSHORT)((_Adapter)->SharedRam + \
+ (_Offset) - (_Adapter)->CardOffset), (_Value))
+
+#define READ_ADAPTER_REGISTER(_Adapter, _Offset, _pValue) \
+ NdisReadRegisterUshort((PUSHORT) ((_Adapter)->SharedRam + \
+ (_Offset) - (_Adapter->CardOffset)), (_pValue))
+
+//
+// read and writes from ports
+//
+
+#define ELNK_READ_UCHAR(_Adapter, _Offset, _pValue) \
+ NdisReadPortUchar( \
+ (_Adapter)->NdisAdapterHandle,\
+ (ULONG)((_Adapter)->IoBase+(_Offset)), \
+ (PUCHAR)(_pValue) \
+ )
+
+#define ELNK_WRITE_UCHAR(_Adapter, _Offset, _Value) \
+ NdisWritePortUchar( \
+ (_Adapter)->NdisAdapterHandle, \
+ (ULONG)((_Adapter)->IoBase+(_Offset)), \
+ (UCHAR) (_Value) \
+ )
+
+#if ELNKMC
+#define ELNKMC_READ_POS(_Offset) \
+ READ_PORT_UCHAR( \
+ (PUCHAR)(_Offset) \
+ )
+
+#define ELNKMC_WRITE_POS(_Offset, _Value) \
+ WRITE_PORT_UCHAR( \
+ (PUCHAR) (_Offset), \
+ (UCHAR) (_Value) \
+ )
+#endif
+
+#define ELNK_DISABLE_INTERRUPT { \
+ Adapter->CurrentCsr &= ~CSR_INTEN; \
+ ELNK_WRITE_UCHAR(Adapter, ELNK_CSR, Adapter->CurrentCsr); \
+}
+
+#define ELNK_ENABLE_INTERRUPT { \
+ Adapter->CurrentCsr |= CSR_INTEN; \
+ ELNK_WRITE_UCHAR(Adapter, ELNK_CSR, Adapter->CurrentCsr); \
+}
+
+
+//
+// This pauses execution until a pending command to the adapter
+// has been accepted by the 586
+//
+#define ELNK_WAIT { \
+ UINT _i; \
+ USHORT _ScbCmd; \
+ for (_i = 0; _i <= 20000 ; _i++ ) { \
+ READ_ADAPTER_REGISTER(Adapter, OFFSET_SCBCMD, &_ScbCmd);\
+ if (_ScbCmd == 0) { \
+ break; \
+ } \
+ NdisStallExecution(50); \
+ } \
+}
+
+#if ELNKMC
+//
+// This is the Etherlink/MC Channel Attention macro and is how we
+// interrupt the card. We need a 500ns delay between the 2 writes.
+//
+#define ELNK_CA { \
+ ELNK_WRITE_UCHAR(Adapter, ELNK_CSR, Adapter->CurrentCsr | CSR_CA); \
+ NdisStallExecution(1); \
+ ELNK_WRITE_UCHAR(Adapter, ELNK_CSR, Adapter->CurrentCsr); \
+ }
+#else
+//
+// This is the Channel Attention macro and is how we interrupt the card.
+//
+#define ELNK_CA ELNK_WRITE_UCHAR(Adapter, ELNK16_CAR, 0x00)
+#endif
+
+//
+// Get the card address given the host address
+//
+#define ELNK_GET_CARD_ADDRESS(_Adapter, _Virtual) (USHORT) \
+ ((ULONG)(_Virtual) - (ULONG)((_Adapter)->SharedRam) + (_Adapter)->CardOffset)
+
+//
+// Get the host offset given card address
+//
+#define ELNK_GET_HOST_ADDRESS(_Adapter, _CardAddress) ((PUCHAR) \
+ ((_Adapter)->SharedRam) + (_CardAddress) - (_Adapter)->CardOffset)
+
+#include <82586.h>
+
+//
+// MCA stuff for the Etherlink/MC card
+//
+#if ELNKMC
+
+//
+// Use this register to select which channel (slot) is being configured
+//
+#define POS_CHANNEL_SELECT 0x96
+
+//
+// or this with the channel number to select new channel
+//
+#define POS_NEW_CHANNEL_CODE 0x08
+
+//
+// each card has an ID that can be used to identify it
+//
+#define POS_CARD_ID_1 0x100
+#define POS_CARD_ID_2 0x101
+
+//
+// Etherlink MCA card ID
+//
+#define ELNKMC_CARD_ID_1 ((UCHAR)0x42)
+#define ELNKMC_CARD_ID_2 ((UCHAR)0x60)
+
+
+//
+// Card specific registers
+//
+#define POS_CARD_REGISTER_1 0x102
+#define POS_CARD_REGISTER_2 0x103
+
+//
+// register one bits
+//
+#define REG1_CARD_ENABLE 0x01
+#define REG1_IO_BASE_MASK 0x06
+#define REG1_RAM_BASE_MASK 0x18
+#define REG1_ON_BOARD_TRANSCEIVER 0x20
+#define REG1_INTERRUPT_LEVEL_MASK 0xC0
+
+//
+// register 2 (used for setting system interrupt level)
+//
+#define REG2_INTERRUPT_LEVEL_MASK 0x0F
+
+//
+// Misc defines
+//
+#define MCA_MAX_NUMBER_OF_CHANNELS 0x08
+#endif
+
+#endif // _ELNKHARDWARE_
+
diff --git a/private/ntos/ndis/elnkmc/elnkmc.rc b/private/ntos/ndis/elnkmc/elnkmc.rc
new file mode 100644
index 000000000..72800209e
--- /dev/null
+++ b/private/ntos/ndis/elnkmc/elnkmc.rc
@@ -0,0 +1,39 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "3Com Etherlink MC network driver"
+#define VER_INTERNALNAME_STR "ELNKMC.SYS"
+#define VER_ORIGINALFILENAME_STR "ELNKMC.SYS"
+
+#include "common.ver"
+
diff --git a/private/ntos/ndis/elnkmc/elnksw.h b/private/ntos/ndis/elnkmc/elnksw.h
new file mode 100644
index 000000000..ac3ddd587
--- /dev/null
+++ b/private/ntos/ndis/elnkmc/elnksw.h
@@ -0,0 +1,973 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ elnksw.h
+
+Abstract:
+
+ Software specific values for the 3Com EtherLink/MC NDIS 3.0 driver.
+
+Author:
+
+ Johnson R. Apacible (JohnsonA) 9-June-1991
+
+Environment:
+
+ This driver is expected to work in DOS and NT at the equivalent
+ of kernel mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+ Modified for new Ndis 3.0 JohnsonA Jan-1992
+
+--*/
+
+#ifndef _ELNKSOFTWARE_
+#define _ELNKSOFTWARE_
+
+#define ELNK_NDIS_MAJOR_VERSION 3
+#define ELNK_NDIS_MINOR_VERSION 0
+#define ELNK_BOGUS_OPEN ((PVOID)0x00000001)
+
+//
+// Max time for command blocks (in seconds)
+//
+#define ELNK_TIMEOUT 2
+
+#define ELNKDEBUG (0)
+
+#if DBG
+
+extern UCHAR Log[256];
+extern UCHAR LogPlace;
+#define IF_LOG(A) { Log[LogPlace] = (A); Log[(LogPlace+2) % 255] = 0; \
+ LogPlace = (LogPlace+1) % 255; }
+
+#define DPrint1(fmt) DbgPrint(fmt)
+#define DPrint2(fmt,v1) DbgPrint(fmt,v1)
+#define DPrint3(fmt,v1,v2) DbgPrint(fmt,v1,v2)
+#define DPrint4(fmt,v1,v2,v3) DbgPrint(fmt,v1,v2,v3)
+#else
+
+#define IF_LOG(A)
+#define DPrint1(fmt)
+#define DPrint2(fmt,v1)
+#define DPrint3(fmt,v1,v2)
+#define DPrint4(fmt,v1,v2,v3)
+#endif
+
+//
+// ZZZ These macros are peculiar to NT.
+//
+
+extern NDIS_PHYSICAL_ADDRESS HighestAcceptableMax;
+
+#define ELNK_ALLOC_PHYS(_pbuffer, _length) NdisAllocateMemory( \
+ (PVOID*)(_pbuffer), \
+ (_length), \
+ 0, \
+ HighestAcceptableMax)
+
+#define ELNK_FREE_PHYS(_buffer) NdisFreeMemory((_buffer), 0, 0)
+
+#define ELNK_MOVE_MEMORY(Destination,Source,Length) NdisMoveMemory(Destination,Source,Length)
+
+#define ELNK_MOVE_MEMORY_TO_SHARED_RAM(Destination,Source,Length) NdisMoveToMappedMemory(Destination,Source,Length)
+#define ELNK_MOVE_SHARED_RAM_TO_MEMORY(Destination,Source,Length) NdisMoveFromMappedMemory(Destination,Source,Length)
+
+
+
+//
+// Size of the ethernet header
+//
+
+#define ELNK_HEADER_SIZE 14
+
+//
+// Size of a lookahead buffer in a lookback packet
+//
+#define ELNK_SIZE_OF_LOOKAHEAD 256
+
+//
+// Associated information for transmit blocks
+//
+
+typedef struct _ELNK_TRANSMIT_INFO {
+
+ //
+ // pointer to the actual command block
+ //
+ PTRANSMIT_CB CommandBlock;
+
+ //
+ // This contains the physical address offset of the Command Block.
+ //
+ USHORT CbOffset;
+
+ //
+ // Pointer to the transmit buffer
+ //
+ PVOID Buffer;
+
+ //
+ // Offset of buffer
+ //
+ USHORT BufferOffset;
+
+ //
+ // This contains the virtual address of the next pending command.
+ //
+ UINT NextCommand;
+
+ //
+ // Points to the packet from which data is being transmitted
+ // through this Command Block.
+ //
+ PNDIS_PACKET OwningPacket;
+
+ //
+ // This points to the owning open binding if this is a private
+ // Command Block. Otherwise (this is a public Command Block)
+ // this field is NULL.
+ //
+ struct _ELNK_OPEN *OwningOpenBinding;
+
+ //
+ // Timed out flag for this command block
+ //
+ BOOLEAN Timeout;
+
+} ELNK_TRANSMIT_INFO, *PELNK_TRANSMIT_INFO;
+
+
+//
+// In addition to the Receive Entry fields which the Elnk
+// defines, we need some additional fields for our own purposes.
+// To ensure that these fields are properly aligned (and to
+// ensure that the actual Receive Entry is properly aligned)
+// we'll defined a Super Receive Entry. This structure will
+// contain a "normal" Elnk Receive Entry plus some additional
+// fields.
+//
+typedef struct _ELNK_RECEIVE_INFO {
+
+ //
+ // Pointer to actual receive frame buffer
+ //
+ PRECEIVE_FRAME_DESCRIPTOR Rfd;
+
+ //
+ // This contains the physical address of the above Receive Entry.
+ //
+ USHORT RfdOffset;
+
+ //
+ // Offset of buffer
+ //
+ USHORT BufferOffset;
+
+ //
+ // This contains the virtual address of this Receive Entry's
+ // frame buffer.
+ //
+ PVOID Buffer;
+
+ //
+ // This contains the Index of the
+ // Receive Entry in the Receive Queue.
+ //
+ UINT NextRfdIndex;
+
+} ELNK_RECEIVE_INFO, *PELNK_RECEIVE_INFO;
+
+
+//
+// This record type is inserted into the MacReserved portion
+// of the packet header when the packet is going through the
+// staged allocation of buffer space prior to the actual send.
+//
+typedef struct _ELNK_RESERVED {
+
+ //
+ // Points to the next packet in the chain of queued packets
+ // being allocated, loopbacked, or waiting for the finish
+ // of transmission.
+ //
+ // The packet will either be on the stage list for allocation,
+ // the loopback list for loopback processing, on an adapter
+ // wide doubly linked list (see below) for post transmission
+ // processing.
+ //
+ // We always keep the packet on a list so that in case the
+ // the adapter is closing down or resetting, all the packets
+ // can easily be located and "canceled".
+ //
+ PNDIS_PACKET Next;
+
+ //
+ // This field holds the binding handle of the open binding
+ // that submitted this packet for send.
+ //
+ NDIS_HANDLE MacBindingHandle;
+
+ //
+ // Gives the index of the Command Block as well as the
+ // command block to packet structure.
+ //
+ UINT CommandBlockIndex;
+
+ BOOLEAN SuccessfulTransmit;
+ BOOLEAN Loopback;
+
+} ELNK_RESERVED,*PELNK_RESERVED;
+
+//
+// This macro will return a pointer to the Elnk reserved portion
+// of a packet given a pointer to a packet.
+//
+#define PELNK_RESERVED_FROM_PACKET(Packet) \
+ ((PELNK_RESERVED)((Packet)->MacReserved))
+
+//
+// This structure is used in the MacReserved field of
+// an NDIS_REQUEST_BLOCK, passed in during multicast
+// address/packet filter operations.
+//
+
+typedef struct _ELNK_REQUEST_RESERVED {
+ PNDIS_REQUEST Next;
+ struct _ELNK_OPEN * OpenBlock;
+} _ELNK_REQUEST_RESERVED, * PELNK_REQUEST_RESERVED;
+
+//
+// This macro will return a pointer to the sonic reserved portion
+// of a request given a pointer to the request.
+//
+#define PELNK_RESERVED_FROM_REQUEST(Request) \
+ ((PELNK_REQUEST_RESERVED)((PVOID)((Request)->MacReserved)))
+
+//
+// XXX
+//
+
+typedef struct _ELNK_ADAPTER {
+
+ //
+ // These fields point to the various hw structures
+ //
+ USHORT IoBase;
+
+ PUCHAR SharedRam;
+ ULONG SharedRamPhys;
+ UINT SharedRamSize;
+
+ PSCP Scp;
+ PISCP Iscp;
+ PSCB Scb;
+
+ //
+ // offset address in card
+ //
+ USHORT CardOffset;
+
+ //
+ // Current value for CSR port
+ //
+ UCHAR CurrentCsr;
+
+ PNON_TRANSMIT_CB MulticastBlock;
+
+ //
+ // Number of Xmit and receive buffers
+ //
+ UINT NumberOfTransmitBuffers;
+ UINT NumberOfReceiveBuffers;
+
+ //
+ // The network address from the hardware.
+ //
+ CHAR NetworkAddress[ETH_LENGTH_OF_ADDRESS];
+ CHAR CurrentAddress[ETH_LENGTH_OF_ADDRESS];
+
+ //
+ // Pointers to the request queue
+ //
+
+ PNDIS_REQUEST FirstRequest;
+ PNDIS_REQUEST LastRequest;
+
+ //
+ // Pointer to the Receive Queue.
+ //
+ UINT ReceiveHead;
+ UINT ReceiveTail;
+
+ //
+ // Index of Command block to start in the function ElnkSyncStartCommand
+ //
+ UINT CommandToStart;
+
+ //
+ // Index of ReceiveBlock for the function ElnkSyncStartReceive
+ //
+ UINT RfdOffset;
+
+ //
+ // Do we need to call NdisIndicateReceiveComplete
+ //
+ BOOLEAN IndicatedAPacket;
+
+ //
+ // Did we have to restart the RU?
+ //
+ BOOLEAN RuRestarted;
+
+ //
+ // Flag telling if memory is currently mapped or not.
+ //
+ BOOLEAN MemoryIsMapped;
+
+ //
+ // This boolean is used as a gate to ensure that only one thread
+ // of execution is actually processing interrupts or some other
+ // source of deferred processing.
+ //
+ BOOLEAN DoingProcessing;
+
+ //
+ // We are processing requests
+ //
+ BOOLEAN ProcessingRequests;
+
+ //
+ // Did a close result in callbacks from the filter package
+ //
+ BOOLEAN CloseResultedInChanges;
+
+ //
+ // Is True right after a reset but becomes false after the first open
+ //
+ BOOLEAN FirstReset;
+
+ //
+ // Is True before the card is first opened
+ //
+ BOOLEAN FirstOpen;
+
+ //
+ // Should we use an alternative address?
+ //
+ BOOLEAN AddressChanged;
+
+ //
+ // Is the transceiver external
+ //
+ BOOLEAN IsExternal;
+
+ //
+ // Did we get an interrupt for no apparent reason?
+ //
+ BOOLEAN EmptyInterrupt;
+
+ //
+ // Did we miss an interrupt (the card never generated it)
+ //
+ BOOLEAN MissedInterrupt;
+
+ //
+ // Keeps a reference count on the current number of uses of
+ // this adapter block. Uses is defined to be the number of
+ // routines currently within the "external" interface.
+ //
+ UINT References;
+
+ //
+ // Pointer to the Receive Queue.
+ //
+ PRECEIVE_FRAME_DESCRIPTOR ReceiveQueue;
+
+ //
+ // Pointer to the Command Queue.
+ //
+ PTRANSMIT_CB TransmitQueue;
+
+ //
+ // Number of available Command Blocks in the Command Queue.
+ //
+ UINT NumberOfAvailableCommandBlocks;
+
+ //
+ // Pointer to the next available Command Block.
+ //
+ UINT NextCommandBlock;
+
+ //
+ // Pointer to the next command to complete execution.
+ //
+ UINT FirstPendingCommand;
+
+ //
+ // Pointer to the most recently submitted command.
+ //
+ UINT LastPendingCommand;
+
+
+ //
+ // Pointers to the loopback list.
+ //
+ PNDIS_PACKET FirstLoopBack;
+ PNDIS_PACKET LastLoopBack;
+
+ //
+ // Pointer to the first transmitting packet that is actually
+ // sending, or done with the living on the loopback queue.
+ //
+ PNDIS_PACKET FirstFinishTransmit;
+
+ //
+ // Pointer to the last transmitting packet that is actually
+ // sending, or done with the living on the loopback queue.
+ //
+ PNDIS_PACKET LastFinishTransmit;
+
+ //
+ // The following fields are used to implement the stage allocation
+ // for sending packets.
+ //
+
+ BOOLEAN StageOpen;
+
+ BOOLEAN AlreadyProcessingStage;
+
+ PNDIS_PACKET FirstStagePacket;
+ PNDIS_PACKET LastStagePacket;
+
+ //
+ // Flag that when enabled lets routines know that a reset
+ // is in progress.
+ //
+ BOOLEAN ResetInProgress;
+
+ BOOLEAN SendInterrupt;
+ BOOLEAN ReceiveInterrupt;
+ UCHAR NoInterrupts;
+
+ //
+ // Pointer to the binding that initiated the reset. This
+ // will be null if the reset is initiated by the MAC itself.
+ //
+ struct _ELNK_OPEN *ResettingOpen;
+
+ //
+ // Statistics!!!
+ //
+
+ ULONG StatisticsField;
+
+ //
+ // Packet counts
+ //
+
+ UINT GoodTransmits;
+ UINT GoodReceives;
+ UINT TransmitsQueued;
+
+ //
+ // Count of transmit errors
+ //
+
+ UINT RetryFailure;
+ UINT LostCarrier;
+ UINT UnderFlow;
+ UINT NoClearToSend;
+ UINT Deferred;
+ UINT OneRetry;
+ UINT MoreThanOneRetry;
+
+ //
+ // Count of receive errors
+ //
+
+ UINT FrameTooShort;
+ UINT NoEofDetected;
+
+ USHORT OldParameterField;
+
+ //
+ // Open Count
+ //
+ UINT OpenCount;
+
+ //
+ // List head for all open bindings for this adapter.
+ //
+ LIST_ENTRY OpenBindings;
+
+ //
+ // List head for all opens that had outstanding references
+ // when an attempt was made to close them.
+ //
+ LIST_ENTRY CloseList;
+
+ //
+ // List head for link to adapter chain
+ //
+ LIST_ENTRY AdapterList;
+
+ //
+ // Spinlock to protect fields in this structure..
+ //
+ NDIS_SPIN_LOCK Lock;
+
+ //
+ // Handle given by NDIS when the MAC registered itself.
+ //
+ NDIS_HANDLE NdisMacHandle;
+
+ //
+ // Handle given by NDIS when the adapter was registered.
+ //
+ NDIS_HANDLE NdisAdapterHandle;
+
+ //
+ // Used for padding short packets
+ //
+ UCHAR PaddingBuffer[MINIMUM_ETHERNET_PACKET_SIZE];
+
+ //
+ // Holds the interrupt object for this adapter.
+ //
+ NDIS_INTERRUPT Interrupt;
+
+ //
+ // This ndis timer object will be used to drive the wakeup call
+ //
+ NDIS_TIMER DeadmanTimer;
+
+ //
+ // This ndis timer object will be used to drive the deferred routine
+ //
+ NDIS_TIMER DeferredTimer;
+
+ //
+ // The dispatch level of the card
+ //
+ KIRQL IsrLevel;
+
+ //
+ // InterruptNumber used by the card
+ //
+ UINT InterruptVector;
+
+ //
+ // Pointer to the filter database for the MAC.
+ //
+ PETH_FILTER FilterDB;
+
+ //
+ // Contains information associated with the transmit and receive buffers
+ //
+ PELNK_TRANSMIT_INFO TransmitInfo;
+ PELNK_RECEIVE_INFO ReceiveInfo;
+
+ //
+ // Buffer for holding loopback packets
+ //
+ UCHAR Loopback[ELNK_SIZE_OF_LOOKAHEAD];
+
+ //
+ // We need this for multicast address changes during resets
+ //
+ UCHAR PrivateMulticastBuffer[ELNK_MAXIMUM_MULTICAST][ETH_LENGTH_OF_ADDRESS];
+
+} ELNK_ADAPTER,*PELNK_ADAPTER;
+
+//
+// Given a MacBindingHandle this macro returns a pointer to the
+// ELNK_ADAPTER.
+//
+#define PELNK_ADAPTER_FROM_BINDING_HANDLE(Handle) \
+ (((PELNK_OPEN)(Handle))->OwningAdapter)
+
+//
+// Given a MacContextHandle return the PELNK_ADAPTER
+// it represents.
+//
+#define PELNK_ADAPTER_FROM_CONTEXT_HANDLE(Handle) \
+ ((PELNK_ADAPTER)(Handle))
+
+//
+// Given a pointer to a ELNK_ADAPTER return the
+// proper MacContextHandle.
+//
+#define CONTEXT_HANDLE_FROM_PELNK_ADAPTER(Ptr) \
+ ((NDIS_HANDLE)(Ptr))
+
+//
+// One of these structures is created on each MacOpenAdapter.
+//
+typedef struct _ELNK_OPEN {
+
+ //
+ // Linking structure for all of the open bindings of a particular
+ // adapter.
+ //
+ LIST_ENTRY OpenList;
+
+ //
+ // The Adapter that requested this open binding.
+ //
+ PELNK_ADAPTER OwningAdapter;
+
+ //
+ // Handle of this adapter in the filter database.
+ //
+ NDIS_HANDLE NdisFilterHandle;
+
+ //
+ // Given by NDIS when the adapter was opened.
+ //
+ NDIS_HANDLE NdisBindingContext;
+
+ UINT References;
+
+ //
+ // A flag indicating that this binding is in the process of closing.
+ //
+ BOOLEAN BindingShuttingDown;
+
+ //
+ // An NdisRequest Structure used for opening or closing
+ //
+ NDIS_REQUEST OpenCloseRequest;
+
+ UINT ProtOptionFlags;
+
+} ELNK_OPEN,*PELNK_OPEN;
+
+//
+// This macro returns a pointer to a PELNK_OPEN given a MacBindingHandle.
+//
+#define PELNK_OPEN_FROM_BINDING_HANDLE(Handle) \
+ ((PELNK_OPEN)(Handle))
+
+//
+// This macro returns a NDIS_HANDLE from a PELNK_OPEN
+//
+#define BINDING_HANDLE_FROM_PELNK_OPEN(Open) \
+ ((NDIS_HANDLE)(Open))
+
+//
+// This macro will act a "epilogue" to every routine in the
+// *interface*. It will check whether there any requests needed
+// to defer there processing. It will also decrement the reference
+// count on the adapter. If the reference count is zero and there
+// is deferred work to do it will call the deferred processing handler.
+//
+// NOTE: This macro assumes that it is called with the lock acquired.
+//
+// ZZZ This routine is NT specific.
+//
+#define ELNK_DO_DEFERRED(Adapter) \
+{ \
+ PELNK_ADAPTER _A = (Adapter); \
+ _A->References--; \
+ if ((_A->References == 1) && \
+ (_A->ResetInProgress || \
+ _A->FirstLoopBack || \
+ (!IsListEmpty(&_A->CloseList)))) { \
+ NdisReleaseSpinLock(&_A->Lock); \
+ NdisSetTimer(&_A->DeferredTimer,0); \
+ } else { \
+ NdisReleaseSpinLock(&_A->Lock); \
+ } \
+}
+
+//
+// Uniquely defines the location of the error
+//
+
+typedef enum _ELNK_PROC_ID {
+ initialInit,
+ startChip,
+ registerAdapter,
+ addAdapter,
+ allocateAdapterMemory,
+ submitCommandBlock,
+ submitCommandBlockandWait,
+ fireOffNextCb,
+ deadmanDpc
+} ELNK_PROC_ID;
+
+//
+// We define the external interfaces to the Elnk driver.
+// These routines are only external to permit separate
+// compilation. Given a truely fast compiler they could
+// all reside in a single file and be static.
+//
+
+extern
+NDIS_STATUS
+ElnkTransferData(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+extern
+NDIS_STATUS
+ElnkSend(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_PACKET Packet
+ );
+
+
+extern
+VOID
+ElnkStagedAllocation(
+ IN PELNK_ADAPTER Adapter
+ );
+
+extern
+VOID
+ElnkCopyFromBufferToPacket(
+ IN PCHAR Buffer,
+ IN UINT BytesToCopy,
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ OUT PUINT BytesCopied
+ );
+
+extern
+VOID
+ElnkCopyFromPacketToBuffer(
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ IN UINT BytesToCopy,
+ OUT PCHAR Buffer,
+ OUT PUINT BytesCopied
+ );
+
+extern
+VOID
+ElnkProcessLoopback(
+ IN PELNK_ADAPTER Adapter
+ );
+
+extern
+VOID
+ElnkProcessRequestQueue(
+ IN PELNK_ADAPTER Adapter
+ );
+
+extern
+VOID
+ElnkPutPacketOnFinishTrans(
+ IN PELNK_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet
+ );
+
+extern
+VOID
+ElnkGetStationAddress(
+ IN PELNK_ADAPTER Adapter
+ );
+
+extern
+VOID
+ElnkStopChip(
+ IN PELNK_ADAPTER Adapter
+ );
+
+extern
+BOOLEAN
+ElnkStartAdapters(
+ IN NDIS_HANDLE NdisMacHandle
+ );
+
+extern
+BOOLEAN
+ElnkIsr(
+ IN PVOID Context
+ );
+
+#if ELNKMC
+extern
+NDIS_STATUS
+ElnkmcRegisterAdapter(
+ IN NDIS_HANDLE NdisMacHandle,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING DeviceName,
+ IN UINT InterruptVector,
+ IN NDIS_PHYSICAL_ADDRESS ElnkSharedMemory,
+ IN USHORT IoBase,
+ IN PUCHAR CurrentAddress,
+ IN UINT MaximumMulticastAddresses,
+ IN UINT MaximumOpenAdapters,
+ IN BOOLEAN ConfigError,
+ IN NDIS_STATUS ConfigErrorCode
+ );
+
+#else
+extern
+NDIS_STATUS
+Elnk16RegisterAdapter(
+ IN NDIS_HANDLE NdisMacHandle,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING DeviceName,
+ IN UINT InterruptVector,
+ IN NDIS_PHYSICAL_ADDRESS WinBase,
+ IN UINT WindowSize,
+ IN USHORT IoBase,
+ IN BOOLEAN IsExternal,
+ IN BOOLEAN ZwsEnabled,
+ IN PUCHAR CurrentAddress,
+ IN UINT MaximumMulticastAddresses,
+ IN UINT MaximumOpenAdapters,
+ IN BOOLEAN ConfigError,
+ IN NDIS_STATUS ConfigErrorCode
+ );
+
+BOOLEAN
+Elnk16ConfigureAdapter(
+ IN PELNK_ADAPTER Adapter,
+ IN BOOLEAN IsExternal,
+ IN BOOLEAN ZwsEnabled
+ );
+#endif
+
+extern
+VOID
+ElnkStandardInterruptDpc(
+ IN PKDPC Dpc,
+ IN PVOID Context,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+
+extern
+BOOLEAN
+ElnkInterruptSynch(
+ IN PVOID Context
+ );
+
+extern
+BOOLEAN
+ElnkAcquireCommandBlock(
+ IN PELNK_ADAPTER Adapter,
+ OUT PUINT CbIndex
+ );
+
+extern
+VOID
+ElnkRelinquishCommandBlock(
+ IN PELNK_ADAPTER Adapter,
+ IN UINT CbIndex
+ );
+
+extern
+VOID
+ElnkAssignPacketToCommandBlock(
+ IN PELNK_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet,
+ IN UINT CbIndex
+ );
+
+extern
+VOID
+ElnkSubmitCommandBlock(
+ IN PELNK_ADAPTER Adapter,
+ IN UINT CbIndex
+ );
+
+extern
+VOID
+ElnkStartChip(
+ IN PELNK_ADAPTER Adapter,
+ IN PELNK_RECEIVE_INFO ReceiveInfo
+ );
+
+extern
+VOID
+ElnkStartAdapterReset(
+ IN PELNK_ADAPTER Adapter
+ );
+
+VOID
+ElnkSubmitCommandBlockAndWait(
+ IN PELNK_ADAPTER Adapter
+ );
+
+VOID
+ElnkDeadmanDpc(
+ IN PVOID SystemSpecifc1,
+ IN PVOID Context,
+ IN PVOID SystemSpecifc2,
+ IN PVOID SystemSpecifc3
+ );
+
+VOID
+SetupForReset(
+ IN PELNK_ADAPTER Adapter,
+ IN PELNK_OPEN Open
+ );
+
+extern
+NDIS_STATUS
+ElnkRequest(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+extern
+NDIS_STATUS
+ElnkQueryGlobalStatistics(
+ IN NDIS_HANDLE MacAdapterContext,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+extern
+NDIS_STATUS
+ElnkChangeClass(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+extern
+NDIS_STATUS
+ElnkChangeAddresses(
+ IN UINT OldAddressCount,
+ IN CHAR OldAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN UINT NewAddressCount,
+ IN CHAR NewAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+BOOLEAN
+ElnkSyncStartCommandBlock(
+ IN PVOID Context
+ );
+
+#define ElnkLogError(_Adapt, _ProcId, _ErrCode, _Spec1) \
+ NdisWriteErrorLogEntry((_Adapt)->NdisAdapterHandle, (_ErrCode), 2, \
+ (_ProcId), (_Spec1))
+
+#endif // _ELNKSOFTWARE_
diff --git a/private/ntos/ndis/elnkmc/interrup.c b/private/ntos/ndis/elnkmc/interrup.c
new file mode 100644
index 000000000..ff125fe3e
--- /dev/null
+++ b/private/ntos/ndis/elnkmc/interrup.c
@@ -0,0 +1,1981 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ interrup.c
+
+Abstract:
+
+ This module contains the interrupt-processing code for the 3Com
+ Etherlink/MC and Etherlink/16 NDIS 3.0 driver.
+
+Author:
+
+ Johnson R. Apacible (JohnsonA) 10-June-1991
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+
+//
+// So we can trace things...
+//
+#define STATIC
+
+#include <efilter.h>
+#include <Elnkhw.h>
+#include <Elnksw.h>
+
+#if DBG
+
+ULONG ElnkIsrs = 0;
+
+UCHAR Log[256] = {0};
+UCHAR LogPlace = 0;
+
+#endif
+
+//
+// external Globals
+//
+
+extern NDIS_HANDLE ElnkMacHandle;
+extern LIST_ENTRY ElnkAdapterList;
+extern NDIS_SPIN_LOCK ElnkAdapterListLock;
+
+extern
+VOID
+ElnkProcessRequestQueue(
+ IN PELNK_ADAPTER Adapter
+ );
+
+STATIC
+VOID
+RelinquishReceivePacket(
+ IN PELNK_ADAPTER Adapter,
+ IN PRECEIVE_FRAME_DESCRIPTOR CurrentEntry
+ );
+
+STATIC
+BOOLEAN
+ElnkProcessReceiveInterrupts(
+ IN PELNK_ADAPTER Adapter
+ );
+
+STATIC
+VOID
+ElnkProcessCommandInterrupts(
+ IN PELNK_ADAPTER Adapter
+ );
+
+STATIC
+VOID
+ElnkProcessMulticastInterrupts(
+ IN PELNK_ADAPTER Adapter
+ );
+
+STATIC
+VOID
+ElnkFireOffNextCb(
+ IN PELNK_ADAPTER Adapter,
+ IN UINT CbIndex
+ );
+
+
+VOID
+ElnkSyncEnableInterrupt(
+ PVOID SyncContext
+ )
+
+/*++
+
+Routine Description:
+
+ Routine for re-enabling interrupts. Called with NdisSynchronizeWithInterrupt
+ to guarantee exclusiveness to the port.
+
+Arguments:
+
+ SyncContext - Really a pointer to the adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNK_ADAPTER Adapter = (PELNK_ADAPTER)SyncContext;
+
+ ELNK_ENABLE_INTERRUPT;
+
+}
+
+#if ELNKMC
+BOOLEAN
+ElnkIsr(
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ Interrupt service routine for the Elnkmc. It's main job is
+ to get the value of the System Doorbell Register and record the
+ changes in the adapters own list of interrupt reasons.
+
+Arguments:
+
+ Context - Really a pointer to the adapter.
+
+Return Value:
+
+ Returns true if the interrupt really was from our Elnk.
+
+--*/
+
+{
+
+ //
+ // Will hold the value from the System Doorbell Register.
+ //
+ USHORT ScbStatus;
+ USHORT ScbCmd;
+
+ //
+ // Holds the pointer to the adapter.
+ //
+ PELNK_ADAPTER Adapter = Context;
+
+ READ_ADAPTER_REGISTER(Adapter, OFFSET_SCBSTAT, &ScbStatus);
+
+ //
+ // Check to see if this is indeed an Elnk interrupt
+ //
+
+ IF_LOG('i');
+
+#if DBG
+ ElnkIsrs++;
+#endif
+
+ if ((ScbStatus & RUS_READY) && Adapter->RuRestarted) {
+
+ //
+ // We have completed restarting the RU
+ //
+ IF_LOG('g');
+
+ Adapter->RuRestarted = FALSE;
+
+ }
+
+ Adapter->MissedInterrupt = FALSE;
+
+ if (ScbCmd = (USHORT)(ScbStatus & SCB_STATUS_INT_MASK)) {
+
+ BOOLEAN Status;
+
+ //
+ // It's our interrupt.
+ //
+
+ //
+ // Or the SCB status value into the adapter version of
+ // the value.
+ //
+
+ //
+ // Initial Reset here
+ //
+
+ if (Adapter->FirstReset) {
+
+ //
+ // No DPC needed
+ //
+
+ Status = FALSE;
+
+ //
+ // ACK interrupts
+ //
+
+ WRITE_ADAPTER_REGISTER(
+ Adapter,
+ OFFSET_SCBCMD,
+ ScbCmd
+ );
+
+
+ ELNK_CA;
+
+ } else {
+
+ ELNK_DISABLE_INTERRUPT;
+
+ Status = TRUE;
+
+ }
+
+ IF_LOG((UCHAR)(ScbStatus >> 8));
+ IF_LOG('I');
+
+ return Status;
+
+ } else {
+
+ Adapter->EmptyInterrupt = TRUE;
+ IF_LOG('I');
+ return TRUE;
+
+ }
+
+}
+#else
+
+BOOLEAN
+ElnkIsr(
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ Interrupt service routine for the Elnk16. It's main job is
+ to get the value of the System Doorbell Register and record the
+ changes in the adapters own list of interrupt reasons.
+
+Arguments:
+
+ Context - Really a pointer to the adapter.
+
+Return Value:
+
+ Returns true if the interrupt really was from our Elnk.
+
+--*/
+
+{
+
+ //
+ // Will hold the value from the System Doorbell Register.
+ //
+ USHORT ScbStatus;
+ USHORT ScbCmd;
+ UCHAR CurrentCsr;
+
+ //
+ // Holds the pointer to the adapter.
+ //
+ PELNK_ADAPTER Adapter = Context;
+
+#if DBG
+ ElnkIsrs++;
+#endif
+
+ READ_ADAPTER_REGISTER(Adapter, OFFSET_SCBSTAT, &ScbStatus);
+
+ //
+ // Check to see if this is indeed an Elnk interrupt
+ //
+
+ ELNK_READ_UCHAR(
+ Adapter,
+ ELNK_CSR,
+ &CurrentCsr
+ );
+
+ //
+ // See if interrupt is latched
+ //
+
+ if (CurrentCsr & 0x08) {
+
+ //
+ // Unlatch
+ //
+
+ ELNK_WRITE_UCHAR(
+ Adapter,
+ ELNK16_INTCLR,
+ 0xff
+ );
+
+ }
+
+ if ((ScbStatus & RUS_READY) && Adapter->RuRestarted) {
+
+ //
+ // We have completed restarting the RU
+ //
+ IF_LOG('g');
+
+ Adapter->RuRestarted = FALSE;
+
+ }
+
+ Adapter->MissedInterrupt = FALSE;
+
+ if (ScbCmd = (USHORT)(ScbStatus & SCB_STATUS_INT_MASK)) {
+
+ BOOLEAN Status;
+
+ //
+ // It's our interrupt.
+ //
+
+ //
+ // Or the SCB status value into the adapter version of
+ // the value.
+ //
+
+ //
+ // Initial Reset here
+ //
+ if (Adapter->FirstReset) {
+
+ Status = FALSE;
+
+ //
+ // Ack Interrupt
+ //
+
+ WRITE_ADAPTER_REGISTER(
+ Adapter,
+ OFFSET_SCBCMD,
+ ScbCmd
+ );
+
+
+ ELNK_CA;
+
+ } else {
+
+ Status = TRUE;
+
+ ELNK_DISABLE_INTERRUPT;
+
+ }
+
+ return Status;
+
+ } else {
+
+ return FALSE;
+
+ }
+
+}
+#endif
+
+
+VOID
+ElnkStandardInterruptDpc(
+ IN PKDPC Dpc,
+ IN PVOID Context,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+
+/*++
+
+Routine Description:
+
+ This DPC routine is queued by the interrupt service routine
+ and other routines within the driver that notice that
+ some deferred processing needs to be done. It's main
+ job is to call the interrupt processing code.
+
+Arguments:
+
+ DPC - The control object associated with this routine.
+
+ Context - Really a pointer to the adapter.
+
+ SystemArgument1(2) - Neither of these arguments used.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Context is actually our adapter
+ //
+ PELNK_ADAPTER Adapter = (PELNK_ADAPTER) Context;
+
+ //
+ // Holds a value of IMaskInterrupt.
+ //
+ USHORT IMask = 0;
+ USHORT IMaskTemp = 0;
+
+ //
+ // Currently running command block
+ //
+
+ PTRANSMIT_CB CommandBlock;
+ USHORT CardStatus;
+
+ UNREFERENCED_PARAMETER(Dpc);
+ UNREFERENCED_PARAMETER(SystemArgument1);
+ UNREFERENCED_PARAMETER(SystemArgument2);
+
+ //
+ // Loop until there are no more processing sources.
+ //
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ if (Adapter->DoingProcessing) {
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ return;
+
+ }
+
+ //
+ // We're busy.
+ //
+
+ Adapter->DoingProcessing = TRUE;
+
+
+ //
+ // We do this to make sure that the card will not generate any interrupts while
+ // the DPC is running. This is to ensure against a short interrupt errata on
+ // 486 B and C stepping chips.
+ //
+ ELNK_DISABLE_INTERRUPT;
+
+ IF_LOG('d');
+
+ if (Adapter->EmptyInterrupt) {
+
+ //
+ // There is a problem where we get an interrupt that is empty, due to
+ // acking a command complete interrupt for a previously finished command
+ // and the adapter using the ack to also ack a command
+ // that has just completed. So, we simulate a command complete interrupt.
+ //
+
+ Adapter->EmptyInterrupt = FALSE;
+ IMask = SCB_STATUS_COMMAND_COMPLETE;
+
+ }
+
+ for (;;)
+ {
+ if (!(IMask & (SCB_STATUS_FRAME_RECEIVED |
+ SCB_STATUS_CU_STOPPED |
+ SCB_STATUS_COMMAND_COMPLETE |
+ SCB_STATUS_RU_STOPPED))
+ )
+ {
+ READ_ADAPTER_REGISTER(Adapter, OFFSET_SCBSTAT, &IMaskTemp);
+ if ((IMaskTemp & RUS_READY) && Adapter->RuRestarted)
+ {
+ //
+ // We have completed restarting the RU
+ //
+ IF_LOG('G');
+
+ Adapter->RuRestarted = FALSE;
+
+ }
+
+ IMaskTemp &= SCB_STATUS_INT_MASK;
+
+ if (IMaskTemp != 0)
+ {
+ IF_LOG('X');
+ IF_LOG((UCHAR)(IMaskTemp >> 8));
+
+ ELNK_WAIT;
+
+ //
+ // Ack interrupt
+ //
+ WRITE_ADAPTER_REGISTER(Adapter, OFFSET_SCBCMD, IMaskTemp);
+
+ ELNK_CA;
+
+ IMask |= IMaskTemp;
+ }
+ }
+
+ //
+ // Get status for current command block
+ //
+
+ if (Adapter->FirstPendingCommand != ELNK_EMPTY)
+ {
+ CommandBlock = (PTRANSMIT_CB)
+ Adapter->TransmitInfo[Adapter->FirstPendingCommand].CommandBlock;
+
+ NdisReadRegisterUshort(&CommandBlock->Status, &CardStatus);
+ }
+ else
+ {
+ CardStatus = CB_STATUS_FREE;
+ }
+
+ //
+ // Check the interrupt source and other reasons
+ // for processing. If there are no reasons to
+ // process then exit this loop.
+ //
+
+ if ((IMask & (SCB_STATUS_FRAME_RECEIVED |
+ SCB_STATUS_CU_STOPPED |
+ SCB_STATUS_COMMAND_COMPLETE)) ||
+ ((CardStatus != CB_STATUS_FREE) && !(CardStatus & CB_STATUS_BUSY)) ||
+ ((IMask & SCB_STATUS_RU_STOPPED) && !Adapter->RuRestarted) ||
+ Adapter->FirstLoopBack ||
+ (Adapter->ResetInProgress && (Adapter->References == 1)) ||
+ (!Adapter->AlreadyProcessingStage &&
+ Adapter->FirstStagePacket &&
+ Adapter->StageOpen )) {
+
+ Adapter->References++;
+
+ } else {
+
+ break;
+
+ }
+
+ //
+ // Note that the following code depends on the fact that
+ // code above left the spinlock held.
+ //
+
+ //
+ // If we have a reset in progress and the adapters reference
+ // count is 1 (meaning no routine is in the interface and
+ // we are the only "active" interrupt processing routine) then
+ // it is safe to start the reset.
+ //
+
+ if (Adapter->ResetInProgress && (Adapter->References == 2)) {
+
+ ElnkStartAdapterReset(Adapter);
+
+ Adapter->References--;
+
+ break;
+ }
+
+ //
+ // Check the interrupt vector and see if there are any
+ // more receives to process. After we process any
+ // other interrupt source we always come back to the top
+ // of the loop to check if any more receive packets have
+ // come in. This is to lessen the probability that we
+ // drop a receive.
+ //
+
+ if ((IMask & SCB_STATUS_FRAME_RECEIVED) ||
+ ((IMask & SCB_STATUS_RU_STOPPED) && !Adapter->RuRestarted)) {
+
+ BOOLEAN Clear;
+
+ Clear = ElnkProcessReceiveInterrupts(Adapter);
+
+ if (Clear) {
+
+ IMask &= ~(SCB_STATUS_FRAME_RECEIVED | SCB_STATUS_RU_STOPPED);
+
+ }
+
+ }
+
+ //
+ // Process the command complete interrupts if there are any.
+ //
+
+ do
+ {
+ if (Adapter->FirstPendingCommand != ELNK_EMPTY)
+ {
+ CommandBlock = (PTRANSMIT_CB)
+ Adapter->TransmitInfo[Adapter->FirstPendingCommand].CommandBlock;
+
+ NdisReadRegisterUshort(&CommandBlock->Status, &CardStatus);
+
+ if (!(CardStatus & CB_STATUS_BUSY) &&
+ (CardStatus != CB_STATUS_FREE)
+ )
+ {
+ IMask &= ~(SCB_STATUS_COMMAND_COMPLETE | SCB_STATUS_CU_STOPPED);
+ ElnkProcessCommandInterrupts(Adapter);
+ }
+ else
+ {
+ IMask &= ~(SCB_STATUS_COMMAND_COMPLETE | SCB_STATUS_CU_STOPPED);
+ IF_LOG('y');
+ IF_LOG((UCHAR)Adapter->FirstPendingCommand);
+ break;
+ }
+ }
+ else
+ {
+ IMask &= ~(SCB_STATUS_COMMAND_COMPLETE | SCB_STATUS_CU_STOPPED);
+ IF_LOG('Y');
+ break;
+ }
+
+ //
+ // Loop if the RU is stopped, processing all completed command
+ // interrupts, until the list is empty. Otherwise we could lose
+ // track of the completed ones.
+ //
+
+ } while ((IMask & (SCB_STATUS_COMMAND_COMPLETE | SCB_STATUS_CU_STOPPED)) &&
+ ( IMask & SCB_STATUS_RU_STOPPED ));
+
+
+ //
+ // Only try to push a packet through the stage queues
+ // if somebody else isn't already doing it and
+ // there is some hope of moving some packets
+ // ahead.
+ //
+
+ if (!Adapter->AlreadyProcessingStage &&
+ Adapter->FirstStagePacket &&
+ Adapter->StageOpen
+ ) {
+
+ ElnkStagedAllocation(Adapter);
+
+ }
+
+ //
+ // Process the loopback queue.
+ //
+ // NOTE: Incase anyone ever figures out how to make this
+ // loop more reentriant, special care needs to be taken that
+ // loopback packets and regular receive packets are NOT being
+ // indicated at the same time. While the filter indication
+ // routines can handle this, I doubt that the transport can.
+ //
+
+ ElnkProcessLoopback(Adapter);
+
+ //
+ // NOTE: This code assumes that the above code left
+ // the spinlock acquired.
+ //
+ // Bottom of the interrupt processing loop. Another dpc
+ // could be coming in at this point to process interrupts.
+ // We clear the flag that says we're processing interrupts
+ // so that some invocation of the DPC can grab it and process
+ // any further interrupts.
+ //
+
+ Adapter->References--;
+
+ if ((IMask & SCB_STATUS_RU_STOPPED) && (Adapter->RuRestarted)) {
+
+
+ //
+ // Bail out. We have restarted the RU and don't want to
+ // accidentally start it again. There is a timing problem
+ // where a really fast CPU could make it back to the top of
+ // the loop and find the RU_STOPPED still set since the
+ // adapter has not restarted it. This causes the code to
+ // re-start the adapter again, which results in a ton of
+ // dropped packets.
+ //
+
+ break;
+
+ }
+ }
+
+ //
+ // If there are any opens on the closing list and their
+ // reference counts are zero then complete the close and
+ // delete them from the list.
+ //
+
+ if ( !IsListEmpty(&Adapter->CloseList) ) {
+
+ PELNK_OPEN Open;
+
+ Open = CONTAINING_RECORD(
+ Adapter->CloseList.Flink,
+ ELNK_OPEN,
+ OpenList
+ );
+
+ if ( Open->References == 0 ) {
+
+ //
+ // Indicate that the close has completed.
+ //
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteCloseAdapter(
+ Open->NdisBindingContext,
+ NDIS_STATUS_SUCCESS
+ );
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ //
+ // Now we need to check if this close was on the pending queue. If
+ // it was, then we need to restart the pending queue processing.
+ //
+
+ if (Adapter->FirstRequest) {
+
+ PELNK_REQUEST_RESERVED Reserved =
+ PELNK_RESERVED_FROM_REQUEST(Adapter->FirstRequest);
+
+ if (Adapter->FirstRequest->RequestType == NdisRequestClose) {
+
+ //
+ // So far so good, now check the open.
+ //
+
+ if (Open == Reserved->OpenBlock) {
+
+ //
+ // This is the one. First remove it and then call to
+ // process.
+ //
+
+ Adapter->FirstRequest = Reserved->Next;
+
+ ElnkProcessRequestQueue(Adapter);
+
+ }
+ }
+ }
+
+ //
+ // Take this guy off of the OPEN list.
+ //
+
+ RemoveEntryList(&Open->OpenList);
+
+ //
+ // Free this guy.
+ //
+
+ ELNK_FREE_PHYS(Open);
+
+ --Adapter->OpenCount;
+ }
+ }
+
+ //
+ // The only way to get out of the loop (via the break above) is
+ // while we're still holding the spin lock.
+ //
+
+ Adapter->DoingProcessing = FALSE;
+
+ //
+ // Enable interrupts
+ //
+
+ NdisSynchronizeWithInterrupt(
+ &Adapter->Interrupt,
+ (PVOID)ElnkSyncEnableInterrupt,
+ (PVOID)Adapter
+ );
+
+ IF_LOG('D');
+
+ if (Adapter->IndicatedAPacket) {
+
+ Adapter->IndicatedAPacket = FALSE;
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ EthFilterIndicateReceiveComplete(Adapter->FilterDB);
+
+ } else {
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ }
+
+}
+
+STATIC
+BOOLEAN
+ElnkProcessReceiveInterrupts(
+ IN PELNK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Process the packets that have finished receiving.
+
+ NOTE: This routine assumes that no other thread of execution
+ is processing receives!
+
+ NOTE: Called with the lock held!!!
+
+Arguments:
+
+ Adapter - The adapter to indicate to.
+
+Return Value:
+
+ Whether to clear the receive interrupt or not.
+
+--*/
+
+{
+
+ //
+ // We don't get here unless there was a receive. Loop through
+ // the receive blocks starting at the last known block owned by
+ // the hardware.
+ //
+ // Examine each receive block for errors.
+ //
+ // We keep an array whose elements are indexed by the block
+ // index of the receive blocks. The arrays elements are the
+ // virtual addresses of the buffers pointed to by each block.
+ //
+ // After we find a packet we give the routine that process the
+ // packet through the filter, the buffers virtual address (which
+ // is always the lookahead size) and as the MAC Context the
+ // index to the receive block.
+ //
+
+ //
+ // The receive Info structure
+ //
+ PELNK_RECEIVE_INFO ReceiveInfo = &Adapter->ReceiveInfo[Adapter->ReceiveHead];
+
+ //
+ // Pointer to the receive block being examined.
+ //
+ PRECEIVE_FRAME_DESCRIPTOR CurrentEntry = ReceiveInfo->Rfd;
+
+ //
+ // TRUE if we need to restart the chip (if we ran out of
+ // receive entries).
+ //
+ BOOLEAN RestartChip;
+
+ //
+ // Length of received packet
+ //
+ UINT PacketLength;
+
+ PUCHAR LookaheadBuffer;
+ PUCHAR MediaHeaderBuffer;
+
+ ULONG ReceivePacketCount = 0;
+
+ if ELNKDEBUG DPrint1("ReceiveInterrupt\n");
+
+ IF_LOG('r');
+
+ for (;;) {
+
+ USHORT CardStatus;
+
+ Adapter->ReceiveInterrupt = TRUE;
+
+ //
+ // Check to see whether we own the packet. If
+ // we don't then simply return to the caller.
+ //
+
+ NdisReadRegisterUshort(&CurrentEntry->Status, &CardStatus);
+
+ if ((CardStatus & 0xbfff) == CB_STATUS_FREE) {
+
+ USHORT OldScbStat;
+
+ //
+ // See if the adapter needs to be restarted.
+ //
+
+ READ_ADAPTER_REGISTER(
+ Adapter,
+ OFFSET_SCBSTAT,
+ &OldScbStat
+ );
+
+ RestartChip = (BOOLEAN) (!(OldScbStat & RUS_READY));
+
+
+ if (RestartChip) {
+
+ if ELNKDEBUG DPrint1("*** RU restarted ***\n");
+ //
+ // We've exhausted all Receive Blocks. Now we
+ // must restart the adapter.
+ //
+
+ IF_LOG('1');
+
+ ElnkStartChip(
+ Adapter,
+ &Adapter->ReceiveInfo[Adapter->ReceiveHead]
+ );
+
+ IF_LOG('R');
+ return(FALSE);
+
+ }
+
+ IF_LOG('R');
+
+ return TRUE;
+
+ } else if (ReceivePacketCount > 10) {
+
+ IF_LOG('E');
+ IF_LOG('R');
+
+ return FALSE;
+
+ } else if ((CardStatus & RFD_STATUS_SUCCESS) == 0) {
+
+ //
+ // We have an error in the packet. Record
+ // the details of the error.
+ //
+
+ //
+ // Just get these 2 errors. The rest of the receive error
+ // counts can be obtained directly from the SCB.
+ //
+
+ if (CardStatus & RFD_STATUS_TOO_SHORT) {
+
+ Adapter->FrameTooShort++;
+
+ } else if (CardStatus & RFD_STATUS_NO_EOF) {
+
+ Adapter->NoEofDetected++;
+
+ }
+
+ //
+ // Give the packet back to the hardware.
+ //
+
+ IF_LOG('P');
+
+ RelinquishReceivePacket(
+ Adapter,
+ CurrentEntry
+ );
+
+ if (Adapter->ReceiveHead == Adapter->NumberOfReceiveBuffers) {
+
+ Adapter->ReceiveHead = 0;
+
+ }
+
+ ReceivePacketCount++;
+
+ //
+ // The receive Info structure
+ //
+
+ ReceiveInfo = &Adapter->ReceiveInfo[Adapter->ReceiveHead];
+
+ //
+ // Pointer to the receive block being examined.
+ //
+
+ CurrentEntry = ReceiveInfo->Rfd;
+
+ } else {
+
+ //
+ // We've found a good packet. Prepare the parameters
+ // for indication, then indicate.
+ //
+
+ //
+ // Check just before we do indications that we aren't
+ // resetting.
+ //
+
+ Adapter->GoodReceives++;
+
+ if (Adapter->ResetInProgress) {
+
+ IF_LOG('%');
+
+ return TRUE;
+ }
+
+ IF_LOG('p');
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ if ELNKDEBUG DPrint3("Head = %d Tail = %d\n",
+ Adapter->ReceiveHead,
+ Adapter->ReceiveTail
+ );
+
+ NdisReadRegisterUshort(&CurrentEntry->Rbd.Status, &CardStatus);
+
+ PacketLength = CardStatus & 0x3fff;
+
+ NdisCreateLookaheadBufferFromSharedMemory(
+ (PVOID)(&(CurrentEntry->Destination)),
+ 14,
+ &MediaHeaderBuffer
+ );
+
+ if (MediaHeaderBuffer == NULL) {
+
+ goto SkipIndication;
+
+ }
+
+ if (PacketLength > 0) {
+
+ NdisCreateLookaheadBufferFromSharedMemory(
+ (PVOID)(ReceiveInfo->Buffer),
+ PacketLength,
+ &LookaheadBuffer
+ );
+
+ if (LookaheadBuffer == NULL) {
+
+ NdisDestroyLookaheadBufferFromSharedMemory(MediaHeaderBuffer);
+ goto SkipIndication;
+
+ }
+
+ }
+
+ if (PacketLength > 0) {
+
+ if (!(PacketLength > MAXIMUM_ETHERNET_PACKET_SIZE - 14)) {
+
+ if ELNKDEBUG DPrint2("Receive is being indicated. Buffer = %lx\n",ReceiveInfo->Buffer);
+ if ELNKDEBUG DPrint2("Receive: Size of packet = %d\n",PacketLength);
+
+ EthFilterIndicateReceive(
+ Adapter->FilterDB,
+ (NDIS_HANDLE)(((ULONG)ReceiveInfo->Buffer) | 1),
+ MediaHeaderBuffer,
+ MediaHeaderBuffer,
+ ELNK_HEADER_SIZE,
+ LookaheadBuffer,
+ PacketLength,
+ PacketLength
+ );
+
+ }
+
+ } else {
+
+ EthFilterIndicateReceive(
+ Adapter->FilterDB,
+ (NDIS_HANDLE)(((ULONG)ReceiveInfo->Buffer) | 1),
+ MediaHeaderBuffer,
+ MediaHeaderBuffer,
+ ELNK_HEADER_SIZE,
+ NULL,
+ 0,
+ 0
+ );
+
+
+ }
+
+ NdisDestroyLookaheadBufferFromSharedMemory(MediaHeaderBuffer);
+
+ if (PacketLength > 0) {
+
+ NdisDestroyLookaheadBufferFromSharedMemory(LookaheadBuffer);
+
+ }
+
+SkipIndication:
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ //
+ // Give the packet back to the hardware.
+ //
+
+ RelinquishReceivePacket(Adapter, CurrentEntry);
+
+ //
+ // Advance to the next block.
+ //
+
+ Adapter->IndicatedAPacket = TRUE;
+
+ Adapter->ReceiveHead++;
+
+ if (Adapter->ReceiveHead == Adapter->NumberOfReceiveBuffers) {
+
+ Adapter->ReceiveHead = 0;
+
+ }
+
+ ReceivePacketCount++;
+
+ //
+ // The receive Info structure
+ //
+
+ ReceiveInfo = &Adapter->ReceiveInfo[Adapter->ReceiveHead];
+
+ //
+ // Pointer to the receive block being examined.
+ //
+
+ CurrentEntry = ReceiveInfo->Rfd;
+
+ }
+
+ }
+
+}
+
+STATIC
+VOID
+RelinquishReceivePacket(
+ IN PELNK_ADAPTER Adapter,
+ IN PRECEIVE_FRAME_DESCRIPTOR CurrentEntry
+ )
+
+/*++
+
+Routine Description:
+
+ Give a receive block back to the hardware.
+
+ NOTE: Called with lock held!!!
+
+Arguments:
+
+ Adapter - The adapter that the block belongs to.
+
+ CurrentEntry - Pointer to the receive block to relinquish
+ to the adapter.
+
+Return Value:
+
+ TRUE - If all Recieve Blocks are exhausted and the adapter
+ must be restarted.
+
+ FALSE - If the adapter does not need to be restarted.
+
+--*/
+
+{
+ //
+ // Receive Info structure for last pending receive block
+ //
+ PELNK_RECEIVE_INFO ReceiveInfo =
+ &Adapter->ReceiveInfo[Adapter->ReceiveTail];
+
+ //
+ // Pointer to last receive block in the queue.
+ //
+ PRECEIVE_FRAME_DESCRIPTOR LastEntry = ReceiveInfo->Rfd;
+
+ //
+ // Ensure the current block is *not* free.
+ //
+
+ ASSERT(CurrentEntry->Status != CB_STATUS_FREE);
+
+ //
+ // Chain the current block onto the tail of the Receive Queue.
+ //
+
+ NdisWriteRegisterUshort(
+ &CurrentEntry->Status,
+ CB_STATUS_FREE
+ );
+
+ NdisWriteRegisterUshort(
+ &CurrentEntry->Command,
+ (USHORT) (RFD_COMMAND_END_OF_LIST | RFD_COMMAND_SUSPEND)
+ );
+
+#if 0
+ NdisWriteRegisterUshort(
+ &CurrentEntry->Rbd.Size,
+ (USHORT) MAXIMUM_ETHERNET_PACKET_SIZE | RBD_END_OF_LIST
+ );
+#endif
+
+ //
+ // Update the previous last rfd's pointers
+ //
+
+#if 0
+ NdisWriteRegisterUshort(
+ &LastEntry->Rbd.Size,
+ (USHORT) MAXIMUM_ETHERNET_PACKET_SIZE
+ );
+#endif
+
+ NdisWriteRegisterUshort(
+ &LastEntry->Command,
+ CB_STATUS_FREE
+ );
+
+ //
+ // Update the queue tail.
+ //
+
+ Adapter->ReceiveTail++;
+
+ if (Adapter->ReceiveTail == Adapter->NumberOfReceiveBuffers) {
+
+ Adapter->ReceiveTail = 0;
+
+ }
+
+}
+
+STATIC
+VOID
+ElnkProcessCommandInterrupts(
+ IN PELNK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Process the Command Complete interrupts.
+
+ NOTE: This routine assumes that it is being executed in a
+ single thread of execution.
+
+ NOTE: Called with the lock held!!!
+
+Arguments:
+
+ Adapter - The adapter that was sent from.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ //
+ // Pointer to command block being processed.
+ //
+ PTRANSMIT_CB CurrentCommandBlock;
+
+ //
+ // Holds whether the packet successfully transmitted or not.
+ //
+ BOOLEAN Successful = TRUE;
+
+ //
+ // Pointer to the packet that started this transmission.
+ //
+ PNDIS_PACKET OwningPacket;
+
+ //
+ // Points to the reserved part of the OwningPacket.
+ //
+ PELNK_RESERVED Reserved;
+
+ //
+ // The type of command block
+ //
+ UINT CurrentCommand;
+
+ //
+ // Status of the current command block
+ //
+ USHORT CardStatus;
+
+ //
+ // Get hold of the first transmitted packet.
+ //
+
+ if ELNKDEBUG DPrint1("CommandInterrupt: received\n");
+
+ //
+ // First we check that this is a packet that was transmitted
+ // but not already processed. Recall that this routine
+ // will be called repeatedly until this tests false, Or we
+ // hit a packet that we don't completely own.
+ //
+
+ ASSERT (Adapter->FirstPendingCommand != ELNK_EMPTY);
+
+ CurrentCommandBlock = (PTRANSMIT_CB)
+ Adapter->TransmitInfo[Adapter->FirstPendingCommand].CommandBlock;
+
+ NdisReadRegisterUshort(
+ &CurrentCommandBlock->Status,
+ &CardStatus
+ );
+
+ ASSERT((!(CardStatus & CB_STATUS_BUSY) &&
+ (CardStatus != CB_STATUS_FREE)));
+
+ NdisReadRegisterUshort(
+ &CurrentCommandBlock->Command,
+ &CurrentCommand
+ );
+
+ CurrentCommand &= CB_COMMAND_MASK;
+
+ if (CurrentCommand == 0) {
+
+ //
+ // Hummmm.. This seems to appear only when the cable isn't
+ // plugged into the adapter.
+ //
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_INVALID_VALUE_FROM_ADAPTER,
+ 0
+ );
+
+ return;
+ }
+
+ Adapter->SendInterrupt = TRUE;
+
+ if (CurrentCommand == CB_TRANSMIT) {
+
+ if ELNKDEBUG DPrint1("ProcessCmd: This is a xmit\n");
+
+ //
+ // The current command block is from a transmit.
+ //
+
+ //
+ // Get a pointer to the owning packet and the reserved part of
+ // the packet.
+ //
+
+ OwningPacket = Adapter->TransmitInfo[Adapter->FirstPendingCommand].OwningPacket;
+
+ Reserved = PELNK_RESERVED_FROM_PACKET(OwningPacket);
+
+ //
+ // If there was an error transmitting this
+ // packet, update our error counters.
+ //
+
+ if ((CardStatus & CB_STATUS_SUCCESS) == 0) {
+
+ if ELNKDEBUG DPrint2("CI:ERROR IN SEND Status = %x\n",CardStatus);
+
+ if (CardStatus &
+ TRANSMIT_STATUS_MAXIMUM_COLLISIONS) {
+
+ Adapter->RetryFailure++;
+
+ } else if (CardStatus &
+ TRANSMIT_STATUS_NO_CARRIER) {
+
+ Adapter->LostCarrier++;
+
+ } else if (CardStatus &
+ TRANSMIT_STATUS_NO_CLEAR_TO_SEND) {
+
+ Adapter->NoClearToSend++;
+
+ } else if (CardStatus &
+ TRANSMIT_STATUS_DMA_UNDERRUN) {
+
+ Adapter->UnderFlow++;
+
+ }
+
+ Successful = FALSE;
+
+ } else {
+
+ if ELNKDEBUG DPrint1("CI:SEND OK\n");
+
+ Adapter->GoodTransmits++;
+
+ if (CardStatus & TRANSMIT_STATUS_TRANSMIT_DEFERRED) {
+
+ Adapter->Deferred++;
+
+ } else if ((CardStatus & TRANSMIT_STATUS_COLLISION_MASK) == 1) {
+
+ Adapter->OneRetry++;
+
+ } else if ((CardStatus & TRANSMIT_STATUS_COLLISION_MASK) > 1) {
+
+ Adapter->MoreThanOneRetry++;
+
+ }
+
+ }
+
+ //
+ // Remove packet from transmit queue
+ //
+
+ if (!Reserved->Next) {
+
+ Adapter->LastFinishTransmit = NULL;
+
+ }
+
+ Adapter->FirstFinishTransmit = Reserved->Next;
+
+ if (!Reserved->Loopback) {
+
+ //
+ // The binding that is submitting this packet.
+ //
+ PELNK_OPEN Open =
+ PELNK_OPEN_FROM_BINDING_HANDLE(Reserved->MacBindingHandle);
+
+ IF_LOG('C');
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteSend(
+ Open->NdisBindingContext,
+ OwningPacket,
+ ((Successful)?(NDIS_STATUS_SUCCESS):(NDIS_STATUS_FAILURE))
+ );
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ //
+ // We reduce the count by one because of the reference
+ // added for the queued packet.
+ //
+
+ Open->References--;
+
+ } else {
+
+ //
+ // Record status of send and put it on the loopback queue.
+ //
+
+ IF_LOG('L');
+
+ Reserved->SuccessfulTransmit = Successful;
+
+ if (!Adapter->FirstLoopBack) {
+
+ Adapter->FirstLoopBack = OwningPacket;
+
+ } else {
+
+ PELNK_RESERVED_FROM_PACKET(Adapter->LastLoopBack)->Next = OwningPacket;
+
+ }
+
+ Reserved->Next = NULL;
+ Adapter->LastLoopBack = OwningPacket;
+
+ }
+
+ //
+ // Fire Off Next Command in Queue
+ //
+ ElnkFireOffNextCb(
+ Adapter,
+ Adapter->FirstPendingCommand
+ );
+
+ //
+ // Release the command block.
+ //
+ ElnkRelinquishCommandBlock(Adapter, Adapter->FirstPendingCommand);
+
+ //
+ // Since we've given back a command block we should
+ // open stage if it was closed and we are not resetting.
+ //
+
+ if ((!Adapter->StageOpen) && (!Adapter->ResetInProgress)) {
+
+ Adapter->StageOpen = TRUE;
+
+ }
+
+ } else {
+
+ UINT oldCommand = Adapter->FirstPendingCommand;
+
+ //
+ // The current command block is not from a transmit.
+ // Indicate completion to whoever initiated this command.
+ //
+
+ if ELNKDEBUG DPrint1("Processing multicast interrupts\n");
+
+ ElnkProcessMulticastInterrupts(Adapter);
+
+ //
+ // Fire Off Next Command in Queue
+ //
+
+ ElnkFireOffNextCb(
+ Adapter,
+ Adapter->FirstPendingCommand
+ );
+
+ //
+ // Update pointers and reinitialize the NextCommand field since
+ // for multicast blocks, this field doesn't get reinitialized when
+ // reused.
+ //
+
+ Adapter->FirstPendingCommand =
+ Adapter->TransmitInfo[oldCommand].NextCommand;
+
+ //
+ // If this is the last pending command block, then we
+ // can nuke the adapter's last pending command pointer.
+ //
+
+ if (Adapter->FirstPendingCommand == ELNK_EMPTY) {
+
+ Adapter->LastPendingCommand = ELNK_EMPTY;
+
+ }
+
+ }
+
+ return;
+}
+
+
+STATIC
+VOID
+ElnkProcessMulticastInterrupts(
+ IN PELNK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Process the Command Complete interrupts.
+
+ NOTE: Called with lock held!!!
+
+Arguments:
+
+ Adapter - The adapter that was sent from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PELNK_TRANSMIT_INFO CbInfo =
+ &Adapter->TransmitInfo[Adapter->FirstPendingCommand];
+
+ //
+ // This one did not timeout
+ //
+
+ Adapter->TransmitInfo[Adapter->FirstPendingCommand].Timeout = FALSE;
+
+ //
+ // Was this from a set?
+ //
+
+ if (CbInfo->OwningOpenBinding == NULL) {
+
+ PNDIS_REQUEST Request;
+ PELNK_REQUEST_RESERVED Reserved;
+ PELNK_OPEN Open;
+
+ Request = Adapter->FirstRequest;
+
+ if (Request == NULL) {
+
+ //
+ // Bogus interrupt. Ignore it
+ //
+
+ return;
+
+ }
+
+ Reserved = PELNK_RESERVED_FROM_REQUEST(Request);
+ Open = Reserved->OpenBlock;
+
+ Adapter->FirstRequest = Reserved->Next;
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteRequest(
+ Open->NdisBindingContext,
+ Request,
+ NDIS_STATUS_SUCCESS);
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ Open->References--;
+
+ //
+ // Now continue processing requests if needed.
+ //
+
+ ElnkProcessRequestQueue(Adapter);
+
+ } else if (CbInfo->OwningOpenBinding != ELNK_BOGUS_OPEN) {
+
+ //
+ // This is from a Close request -- dereference the count
+ //
+
+ CbInfo->OwningOpenBinding->References--;
+
+ }
+}
+
+STATIC
+VOID
+ElnkFireOffNextCb(
+ IN PELNK_ADAPTER Adapter,
+ IN UINT CbIndex
+ )
+
+/*++
+
+Routine Description:
+
+ Process Next Command Block.
+
+ NOTE: This routine assumes that it is being executed in a
+ single thread of execution.
+
+Arguments:
+
+ Adapter - The adapter that was sent from.
+
+ CbIndex - Index of the current command block.
+
+Return Value:
+
+ None.
+
+--*/
+
+
+{
+ UINT NextCb;
+
+ if ((NextCb = Adapter->TransmitInfo[CbIndex].NextCommand) != ELNK_EMPTY) {
+
+ //
+ // Initialize our command timeout flag.
+ //
+ Adapter->TransmitInfo[CbIndex].Timeout = FALSE;
+
+ if ELNKDEBUG DPrint1("Next CB Fired\n");
+
+ Adapter->CommandToStart = NextCb;
+
+ ELNK_WAIT;
+
+ NdisSynchronizeWithInterrupt(
+ &(Adapter->Interrupt),
+ (PVOID)ElnkSyncStartCommandBlock,
+ (PVOID)(Adapter)
+ );
+
+ }
+}
+
+
+BOOLEAN
+ElnkCheckForHang(
+ IN PELNK_ADAPTER Adapter
+ )
+
+/*++
+
+ Note:
+ This routine is called with the spinlock held.
+
+--*/
+{
+ BOOLEAN HungStatus = FALSE;
+
+ if ( !Adapter->DoingProcessing &&
+ !Adapter->ResetInProgress &&
+ !Adapter->SendInterrupt &&
+ !Adapter->ReceiveInterrupt ) {
+
+ //
+ // If we're here then we're not handling an interrupt and
+ // we're not resetting the adapter and we haven't got
+ // a send or receive interrupt. If we hit these conditions
+ // 10 times then we'll reset the adapter.
+ //
+
+ if ( Adapter->NoInterrupts++ < 10 ) {
+
+ return FALSE;
+ }
+
+ //
+ // We're hung, force a reset.
+ //
+
+ HungStatus = TRUE;
+ }
+
+ //
+ // We either got an interrupt or we're resetting.
+ //
+
+ Adapter->NoInterrupts = 0;
+ Adapter->SendInterrupt = FALSE;
+ Adapter->ReceiveInterrupt = FALSE;
+
+ return HungStatus;
+}
+
+
+
+VOID
+ElnkDeadmanDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID Context,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+
+/*++
+
+Routine Description:
+
+ This DPC routine is queued every 2 seconds to check on the
+ head of the command block queue. It will fire off the
+ queue if the head has been sleeping on the job for more
+ than 2 seconds. It will fire off another dpc after doing the
+ check.
+
+Arguments:
+
+ Context - Really a pointer to the adapter.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ //
+ // Now that we're done handling the interrupt,
+ // let's see if the first pending command has
+ // timed-out. If so, kick the adapter in the ass.
+ //
+
+ PELNK_ADAPTER Adapter = Context;
+
+ PTRANSMIT_CB CommandBlock;
+ USHORT CardStatus;
+
+ //
+ // Blow this off if there's nothing waiting to complete.
+ // Also blow it off if this command block is not waiting
+ // for the adapter.
+ //
+
+ UNREFERENCED_PARAMETER(SystemSpecific1);
+ UNREFERENCED_PARAMETER(SystemSpecific2);
+ UNREFERENCED_PARAMETER(SystemSpecific3);
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ if (Adapter->FirstPendingCommand != ELNK_NULL) {
+
+ PELNK_TRANSMIT_INFO TransmitInfo =
+ &Adapter->TransmitInfo[Adapter->FirstPendingCommand];
+
+ //
+ // See if the command block has timed-out.
+ //
+
+ if( TransmitInfo->Timeout ) {
+
+ TransmitInfo->Timeout = FALSE;
+
+ if ELNKDEBUG DPrint2("Elnk: Card dead, attempting to restart. Context = %lx\n",Adapter);
+
+ CommandBlock = (PTRANSMIT_CB)
+ Adapter->TransmitInfo[Adapter->FirstPendingCommand].CommandBlock;
+
+ NdisReadRegisterUshort(
+ &CommandBlock->Status,
+ &CardStatus
+ );
+
+ if (!(CardStatus & CB_STATUS_BUSY) &&
+ (CardStatus != CB_STATUS_FREE) &&
+ (!Adapter->MissedInterrupt)) {
+
+ //
+ // There appears to be a bug where a previous acking of
+ // a command complete, also acks a command that just
+ // finished on the card. In this case, either we get an
+ // empty interrupt (which is handled in the ISR) or an
+ // entire interrupt is missed. The first seems to happen
+ // with relative frequency on MP Pentium machines under very
+ // heavy stress, the second happens on the same configuration
+ // about once every 5 minutes of stress. In the second case
+ // we simulate an interrupt as we do in the ISR and
+ // we queue a DPC to handle the completed transmit here.
+ //
+
+ Adapter->EmptyInterrupt = TRUE;
+ Adapter->MissedInterrupt = TRUE;
+ NdisSetTimer(&(Adapter->DeferredTimer), 1);
+
+ } else {
+
+ //
+ // Do a reset -- Either we failed twice to start this
+ // command block, or the command block has never completed.
+ // In either case a hard reset of the card is necessary.
+ //
+
+ if (!Adapter->ResetInProgress) {
+
+ Adapter->FirstReset = TRUE;
+
+ SetupForReset(
+ Adapter,
+ NULL
+ );
+
+ if (!Adapter->DoingProcessing) {
+
+ ELNK_DISABLE_INTERRUPT;
+
+ //
+ // Increment the reference count to block the DPC from running
+ // the reset code too.
+ //
+
+ Adapter->References++;
+
+ ElnkStartAdapterReset(Adapter);
+
+ Adapter->References--;
+
+ NdisSynchronizeWithInterrupt(
+ &Adapter->Interrupt,
+ (PVOID)ElnkSyncEnableInterrupt,
+ (PVOID)Adapter
+ );
+
+ }
+
+ }
+
+ }
+
+ } else {
+
+ //
+ // Mark first command as timed out.
+ //
+
+ TransmitInfo->Timeout = TRUE;
+
+ }
+
+ }
+
+ //
+ // Check for hang.
+ //
+
+ if ( ElnkCheckForHang(Adapter) ) {
+
+ //
+ // We've waited long enough.
+ // SetUp the chip for reset
+ //
+
+ Adapter->FirstReset = TRUE;
+
+ SetupForReset(
+ Adapter,
+ NULL
+ );
+
+ ELNK_DISABLE_INTERRUPT;
+
+ //
+ // Increment the reference count to block the DPC from running
+ // the reset code too.
+ //
+
+ Adapter->References++;
+
+ ElnkStartAdapterReset(Adapter);
+
+ Adapter->References--;
+
+ NdisSynchronizeWithInterrupt(
+ &Adapter->Interrupt,
+ (PVOID)ElnkSyncEnableInterrupt,
+ (PVOID)Adapter
+ );
+ }
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ //
+ // Fire off another Dpc to execute after 1 second
+ //
+
+ NdisSetTimer(
+ &Adapter->DeadmanTimer,
+ 1000
+ );
+}
diff --git a/private/ntos/ndis/elnkmc/keywords.h b/private/ntos/ndis/elnkmc/keywords.h
new file mode 100644
index 000000000..e0dc08811
--- /dev/null
+++ b/private/ntos/ndis/elnkmc/keywords.h
@@ -0,0 +1,47 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ keywords.h
+
+Abstract:
+
+ Contains all Ndis2 and Ndis3 mac-specific keywords.
+
+Author:
+
+ Bob Noradki
+
+Environment:
+
+ This driver is expected to work in DOS, OS2 and NT at the equivalent
+ of kernal mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+
+
+--*/
+#ifndef NDIS2
+#define NDIS2 0
+#endif
+
+#if NDIS2
+
+#define NETWORK_ADDRESS NDIS_STRING_CONST("NETADDRESS")
+#define IOBASE NDIS_STRING_CONST("IOBASE")
+
+#else // NDIS3
+
+#define NETWORK_ADDRESS NDIS_STRING_CONST("NetworkAddress")
+#define IOBASE NDIS_STRING_CONST("IoBaseAddress")
+#endif
diff --git a/private/ntos/ndis/elnkmc/loopback.c b/private/ntos/ndis/elnkmc/loopback.c
new file mode 100644
index 000000000..afef5e7b6
--- /dev/null
+++ b/private/ntos/ndis/elnkmc/loopback.c
@@ -0,0 +1,282 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ loopback.c
+
+Abstract:
+
+ The routines here indicate packets on the loopback queue and are
+ responsible for inserting and removing packets from the loopback
+ queue and the send finishing queue.
+
+Author:
+
+ Johnson R. Apacible (JohnsonA) 10-Jul-1991
+
+Environment:
+
+ Operates at dpc level - or the equivalent on os2 and dos.
+
+Revision History:
+
+--*/
+
+#include <ndis.h>
+
+//
+// So we can trace things...
+//
+#define STATIC
+
+#include <efilter.h>
+#include <elnkhw.h>
+#include <elnksw.h>
+
+
+VOID
+ElnkProcessLoopback(
+ IN PELNK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is responsible for indicating *one* packet on
+ the loopback queue either completing it or moving on to the
+ finish send queue.
+
+ NOTE: Called with the lock held!!!
+
+Arguments:
+
+ Adapter - The adapter whose loopback queue we are processing.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if (Adapter->FirstLoopBack) {
+
+ //
+ // Packet at the head of the loopback list.
+ //
+ PNDIS_PACKET PacketToMove;
+
+ //
+ // The reserved portion of the above packet.
+ //
+ PELNK_RESERVED Reserved;
+
+ //
+ // The first buffer in the ndis packet to be loopbacked.
+ //
+ PNDIS_BUFFER FirstBuffer;
+
+ //
+ // The total amount of user data in the packet to be
+ // loopbacked.
+ //
+ UINT TotalPacketLength;
+
+ //
+ // Eventually the address of the data to be indicated
+ // to the transport.
+ //
+ PVOID BufferAddress;
+
+ //
+ // Eventually the length of the data to be indicated
+ // to the transport.
+ //
+ UINT BufferLength;
+
+ PELNK_OPEN Open;
+
+ PacketToMove = Adapter->FirstLoopBack;
+
+ Reserved = PELNK_RESERVED_FROM_PACKET(PacketToMove);
+
+ //
+ // Remove packet from loopback queue
+ //
+
+ if (!Reserved->Next) {
+
+ Adapter->LastLoopBack = NULL;
+
+ }
+
+ Adapter->FirstLoopBack = Reserved->Next;
+
+ Adapter->IndicatedAPacket = TRUE;
+
+ Open = PELNK_OPEN_FROM_BINDING_HANDLE(Reserved->MacBindingHandle);
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ //
+ // See if we need to copy the data from the packet
+ // into the loopback buffer.
+ //
+ // We need to copy to the local loopback buffer if
+ // the first buffer of the packet is less than the
+ // minimum loopback size AND the first buffer isn't
+ // the total packet.
+ //
+
+ NdisQueryPacket(
+ PacketToMove,
+ NULL,
+ NULL,
+ &FirstBuffer,
+ &TotalPacketLength
+ );
+
+ NdisQueryBuffer(
+ FirstBuffer,
+ &BufferAddress,
+ &BufferLength
+ );
+
+ if ((BufferLength < ELNK_SIZE_OF_LOOKAHEAD) &&
+ (BufferLength != TotalPacketLength)) {
+
+ ElnkCopyFromPacketToBuffer(
+ PacketToMove,
+ 0,
+ ELNK_SIZE_OF_LOOKAHEAD,
+ Adapter->Loopback,
+ &BufferLength
+ );
+
+ BufferAddress = Adapter->Loopback;
+
+ }
+
+ //
+ // Indicate the packet to every open binding
+ // that could want it.
+ //
+
+ if ELNKDEBUG DPrint1("Loopback: indicating receive\n");
+
+ if (BufferLength < ELNK_HEADER_SIZE) {
+
+ //
+ // Must have at least an address
+ //
+
+ if (BufferLength > 5) {
+
+ EthFilterIndicateReceive(
+ Adapter->FilterDB,
+ PacketToMove,
+ ((PCHAR)BufferAddress),
+ BufferAddress,
+ BufferLength,
+ NULL,
+ 0,
+ 0
+ );
+
+ }
+
+ } else {
+
+ EthFilterIndicateReceive(
+ Adapter->FilterDB,
+ PacketToMove,
+ ((PCHAR)BufferAddress),
+ BufferAddress,
+ ELNK_HEADER_SIZE,
+ ((PUCHAR)BufferAddress) + ELNK_HEADER_SIZE,
+ BufferLength - ELNK_HEADER_SIZE,
+ TotalPacketLength - ELNK_HEADER_SIZE
+ );
+
+ }
+
+ NdisCompleteSend(
+ Open->NdisBindingContext,
+ PacketToMove,
+ ((Reserved->SuccessfulTransmit)?
+ (NDIS_STATUS_SUCCESS):(NDIS_STATUS_FAILURE))
+ );
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ //
+ // We can decrement the reference count since it is the one left
+ // from when we submitted the packet.
+ //
+
+ Open->References--;
+
+ }
+
+}
+
+VOID
+ElnkPutPacketOnFinishTrans(
+ IN PELNK_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ Put the packet on the adapter wide queue for packets that
+ are transmitting.
+
+ NOTE: This routine assumes that the lock is held.
+
+ NOTE: By definition any packet given to this routine is ready
+ to complete.
+
+Arguments:
+
+ Adapter - The adapter that contains the queue.
+
+ Packet - The packet to be put on the queue.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PELNK_RESERVED Reserved = PELNK_RESERVED_FROM_PACKET(Packet);
+
+ if (Adapter->LastFinishTransmit) {
+
+ PELNK_RESERVED LastReserved =
+ PELNK_RESERVED_FROM_PACKET(Adapter->LastFinishTransmit);
+
+ LastReserved->Next = Packet;
+
+ }
+
+ Reserved->Next = NULL;
+
+ Adapter->LastFinishTransmit = Packet;
+
+ if (!Adapter->FirstFinishTransmit) {
+
+ Adapter->FirstFinishTransmit = Packet;
+
+ }
+
+ Adapter->TransmitsQueued--;
+
+}
+
diff --git a/private/ntos/ndis/elnkmc/makefile b/private/ntos/ndis/elnkmc/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/elnkmc/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/elnkmc/packet.c b/private/ntos/ndis/elnkmc/packet.c
new file mode 100644
index 000000000..8a2836e38
--- /dev/null
+++ b/private/ntos/ndis/elnkmc/packet.c
@@ -0,0 +1,437 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ packet.c
+
+Abstract:
+
+ This module contains code to copy from ndis packets to ndis packets,
+ and also to copy from ndis packets to a buffer.
+
+Author:
+
+ Johnson R. Apacible (JohnsonA) 9-June-1991
+
+Environment:
+
+ Works in kernal mode, but is not important that it does.
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+
+//
+// So we can trace things...
+//
+#define STATIC
+
+#include <efilter.h>
+#include <elnkhw.h>
+#include <elnksw.h>
+
+
+VOID
+ElnkCopyFromPacketToBuffer(
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ IN UINT BytesToCopy,
+ OUT PCHAR Buffer,
+ OUT PUINT BytesCopied
+ )
+
+/*++
+
+Routine Description:
+
+ Copy from an ndis packet into a buffer.
+
+Arguments:
+
+ Packet - The packet to copy from.
+
+ Offset - The offset from which to start the copy.
+
+ BytesToCopy - The number of bytes to copy from the packet.
+
+ Buffer - The destination of the copy.
+
+ BytesCopied - The number of bytes actually copied. Can be less then
+ BytesToCopy if the packet is shorter than BytesToCopy.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ //
+ // Holds the number of ndis buffers comprising the packet.
+ //
+ UINT NdisBufferCount;
+
+ //
+ // Points to the buffer from which we are extracting data.
+ //
+ PNDIS_BUFFER CurrentBuffer;
+
+ //
+ // Holds the virtual address of the current buffer.
+ //
+ PVOID VirtualAddress;
+
+ //
+ // Holds the length of the current buffer of the packet.
+ //
+ UINT CurrentLength;
+
+ //
+ // Keep a local variable of BytesCopied so we aren't referencing
+ // through a pointer.
+ //
+ UINT LocalBytesCopied = 0;
+
+ //
+ // Take care of boundary condition of zero length copy.
+ //
+
+ *BytesCopied = 0;
+ if (!BytesToCopy) return;
+
+ //
+ // Get the first buffer.
+ //
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ &NdisBufferCount,
+ &CurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet.
+ //
+
+ if (!NdisBufferCount) {
+ return;
+ }
+
+ NdisQueryBuffer(
+ CurrentBuffer,
+ &VirtualAddress,
+ &CurrentLength
+ );
+
+ while (LocalBytesCopied < BytesToCopy) {
+
+ if (!CurrentLength) {
+
+ NdisGetNextBuffer(
+ CurrentBuffer,
+ &CurrentBuffer
+ );
+
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.
+ //
+
+ if (!CurrentBuffer) {
+ break;
+ }
+
+ NdisQueryBuffer(
+ CurrentBuffer,
+ &VirtualAddress,
+ &CurrentLength
+ );
+
+ continue;
+
+ }
+
+ //
+ // Try to get us up to the point to start the copy.
+
+
+ if (Offset) {
+
+ if (Offset > CurrentLength) {
+
+ //
+ // What we want isn't in this buffer.
+ //
+
+ Offset -= CurrentLength;
+ CurrentLength = 0;
+ continue;
+
+ } else {
+
+ VirtualAddress = (PCHAR)VirtualAddress + Offset;
+ CurrentLength -= Offset;
+ Offset = 0;
+
+ }
+
+ }
+
+ //
+ // Copy the data.
+ //
+
+
+ {
+
+ //
+ // Holds the amount of data to move.
+ //
+ UINT AmountToMove;
+
+ AmountToMove =
+ ((CurrentLength <= (BytesToCopy - LocalBytesCopied))?
+ (CurrentLength):(BytesToCopy - LocalBytesCopied));
+
+ ELNK_MOVE_MEMORY_TO_SHARED_RAM(
+ Buffer,
+ VirtualAddress,
+ AmountToMove
+ );
+
+ Buffer = (PCHAR)Buffer + AmountToMove;
+ VirtualAddress = (PCHAR)VirtualAddress + AmountToMove;
+
+ LocalBytesCopied += AmountToMove;
+ CurrentLength -= AmountToMove;
+
+ }
+
+ }
+
+ *BytesCopied = LocalBytesCopied;
+
+}
+
+VOID
+ElnkCopyFromBufferToPacket(
+ IN PCHAR Buffer,
+ IN UINT BytesToCopy,
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ OUT PUINT BytesCopied
+ )
+
+/*++
+
+Routine Description:
+
+ Copy from a buffer into an ndis packet.
+
+Arguments:
+
+ Buffer - The packet to copy from.
+
+ Offset - The offset from which to start the copy.
+
+ BytesToCopy - The number of bytes to copy from the buffer.
+
+ Packet - The destination of the copy.
+
+ BytesCopied - The number of bytes actually copied. Will be less
+ than BytesToCopy if the packet is not large enough.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ //
+ // Holds the count of the number of ndis buffers comprising the
+ // destination packet.
+ //
+ UINT DestinationBufferCount;
+
+ //
+ // Points to the buffer into which we are putting data.
+ //
+ PNDIS_BUFFER DestinationCurrentBuffer;
+
+ //
+ // Points to the location in Buffer from which we are extracting data.
+ //
+ PUCHAR SourceCurrentAddress;
+
+ //
+ // Holds the virtual address of the current destination buffer.
+ //
+ PVOID DestinationVirtualAddress;
+
+ //
+ // Holds the length of the current destination buffer.
+ //
+ UINT DestinationCurrentLength;
+
+ //
+ // Keep a local variable of BytesCopied so we aren't referencing
+ // through a pointer.
+ //
+ UINT LocalBytesCopied = 0;
+
+
+ //
+ // Take care of boundary condition of zero length copy.
+ //
+
+ *BytesCopied = 0;
+ if (!BytesToCopy) {
+ return;
+ }
+
+ //
+ // Get the first buffer of the destination.
+ //
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ &DestinationBufferCount,
+ &DestinationCurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet.
+ //
+
+ if (!DestinationBufferCount) {
+ return;
+ }
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+
+ //
+ // Set up the source address.
+ //
+
+ SourceCurrentAddress = Buffer;
+
+
+ while (LocalBytesCopied < BytesToCopy) {
+
+ //
+ // Check to see whether we've exhausted the current destination
+ // buffer. If so, move onto the next one.
+ //
+
+ if (!DestinationCurrentLength) {
+
+ NdisGetNextBuffer(
+ DestinationCurrentBuffer,
+ &DestinationCurrentBuffer
+ );
+
+ if (!DestinationCurrentBuffer) {
+
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.)
+ //
+
+ break;
+
+ }
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+
+ continue;
+
+ }
+
+ //
+ // Try to get us up to the point to start the copy.
+ //
+
+ if (Offset) {
+
+ if (Offset > DestinationCurrentLength) {
+
+ //
+ // What we want isn't in this buffer.
+ //
+
+ Offset -= DestinationCurrentLength;
+ DestinationCurrentLength = 0;
+ continue;
+
+ } else {
+
+ DestinationVirtualAddress = (PCHAR)DestinationVirtualAddress
+ + Offset;
+ DestinationCurrentLength -= Offset;
+ Offset = 0;
+
+ }
+
+ }
+
+
+ //
+ // Copy the data.
+ //
+
+ {
+
+ //
+ // Holds the amount of data to move.
+ //
+ UINT AmountToMove;
+
+ //
+ // Holds the amount desired remaining.
+ //
+ UINT Remaining = BytesToCopy - LocalBytesCopied;
+
+
+ AmountToMove = DestinationCurrentLength;
+
+ AmountToMove = ((Remaining < AmountToMove)?
+ (Remaining):(AmountToMove));
+
+ ELNK_MOVE_SHARED_RAM_TO_MEMORY(
+ DestinationVirtualAddress,
+ SourceCurrentAddress,
+ AmountToMove
+ );
+
+ SourceCurrentAddress += AmountToMove;
+ LocalBytesCopied += AmountToMove;
+ DestinationCurrentLength -= AmountToMove;
+
+ }
+
+ }
+
+ *BytesCopied = LocalBytesCopied;
+}
+
diff --git a/private/ntos/ndis/elnkmc/request.c b/private/ntos/ndis/elnkmc/request.c
new file mode 100644
index 000000000..6a678961c
--- /dev/null
+++ b/private/ntos/ndis/elnkmc/request.c
@@ -0,0 +1,1859 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ request.c
+
+Abstract:
+
+ This file contains code to implement MacRequest and
+ MacQueryGlobalStatistics. This driver conforms to the
+ NDIS 3.0 interface.
+
+Author:
+
+ Johnson R. Apacible (JohnsonA) 10-June-1991
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+
+//
+// So we can trace things...
+//
+#define STATIC
+
+#include <efilter.h>
+#include <Elnkhw.h>
+#include <Elnksw.h>
+
+extern
+BOOLEAN
+ChangeClassDispatch(
+ IN PELNK_ADAPTER Adapter,
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN PELNK_OPEN Open,
+ IN BOOLEAN Set
+ );
+
+extern
+VOID
+ChangeAddressDispatch(
+ IN PELNK_ADAPTER Adapter,
+ IN UINT AddressCount,
+ IN CHAR Addresses[][ETH_LENGTH_OF_ADDRESS],
+ IN PELNK_OPEN Open,
+ IN BOOLEAN Set
+ );
+
+extern
+NDIS_STATUS
+ElnkQueryInformation(
+ IN PELNK_ADAPTER Adapter,
+ IN PELNK_OPEN Open,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN UINT InformationBufferLength,
+ IN PUINT BytesWritten,
+ IN PUINT BytesNeeded
+ );
+
+extern
+NDIS_STATUS
+ElnkSetInformation(
+ IN PELNK_ADAPTER Adapter,
+ IN PELNK_OPEN Open,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN INT InformationBufferLength,
+ OUT PUINT BytesRead,
+ OUT PUINT BytesNeeded
+ );
+
+extern
+VOID
+ElnkQueueRequest(
+ IN PELNK_ADAPTER Adapter,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+extern
+VOID
+ElnkProcessRequestQueue(
+ IN PELNK_ADAPTER Adapter
+ );
+
+VOID
+ElnkRemoveAdapter(
+ IN NDIS_HANDLE MacAdapterContext
+ );
+
+
+extern
+NDIS_STATUS
+ElnkChangeClass(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when a particular filter
+ class is first used or last cleared.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ OldFilterClasses - The values of the class filter before it
+ was changed.
+
+ NewFilterClasses - The current value of the class filter
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to ELNK_OPEN.
+
+ NdisRequest - the change filter request from the protocol.
+
+ Set - If true the change resulted from a set, otherwise the
+ change resulted from an open closing.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+
+
+ PELNK_ADAPTER Adapter = PELNK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ //
+ // The open that made this request.
+ //
+ PELNK_OPEN Open = PELNK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ //
+ // Holds the change that should be returned to the filtering package.
+ //
+ NDIS_STATUS StatusOfChange;
+
+ NdisRequest;
+
+ if (Adapter->ResetInProgress) {
+
+ StatusOfChange = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ } else {
+
+ //
+ // The whole purpose of this routine is to determine whether
+ // the filtering changes need to result in the hardware being
+ // reset.
+ //
+
+ ASSERT(OldFilterClasses != NewFilterClasses);
+
+
+ if (ChangeClassDispatch(Adapter,
+ OldFilterClasses,
+ NewFilterClasses,
+ Open,
+ Set
+ )) {
+
+
+ StatusOfChange = NDIS_STATUS_PENDING;
+
+ } else {
+
+ StatusOfChange = NDIS_STATUS_SUCCESS;
+
+ }
+
+ }
+
+ return StatusOfChange;
+
+}
+
+BOOLEAN
+ChangeClassDispatch(
+ IN PELNK_ADAPTER Adapter,
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN PELNK_OPEN Open,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ Reconfigures the adapter.
+
+Arguments:
+
+ Adapter - The adapter.
+
+ OldFilterClasses - The values of the class filter before it
+ was changed.
+
+ NewFilterClasses - The current value of the class filter
+
+ Set - TRUE if this is due to a set.
+
+Return Value:
+
+ TRUE, if we need to fill in a command block. FALSE, otherwise.
+
+--*/
+
+{
+
+ //
+ // Status to return
+ //
+ BOOLEAN StatusToReturn = FALSE;
+
+ //
+ // Default Value
+ //
+ USHORT NewParameterField = DEFAULT_PARM5;
+
+ OldFilterClasses;
+
+ if (NewFilterClasses & (NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_ALL_MULTICAST)) {
+
+ NewParameterField |= CONFIG_PROMISCUOUS;
+
+ } else {
+
+ if (NewFilterClasses & NDIS_PACKET_TYPE_BROADCAST) {
+
+ NewParameterField &= ~CONFIG_BROADCAST;
+
+ }
+
+ }
+
+ if (Adapter->OldParameterField != NewParameterField) {
+
+ IF_LOG('+');
+
+ Adapter->OldParameterField = NewParameterField;
+
+ NdisWriteRegisterUshort(
+ &Adapter->MulticastBlock->Command,
+ CB_CONFIG
+ );
+
+ NdisWriteRegisterUshort(
+ &Adapter->MulticastBlock->Status,
+ CB_STATUS_FREE
+ );
+
+ NdisWriteRegisterUshort(
+ &Adapter->MulticastBlock->Parm.Config.Parameter1,
+ DEFAULT_PARM1
+ );
+
+ NdisWriteRegisterUshort(
+ &Adapter->MulticastBlock->Parm.Config.Parameter2,
+ DEFAULT_PARM2
+ );
+
+ NdisWriteRegisterUshort(
+ &Adapter->MulticastBlock->Parm.Config.Parameter3,
+ DEFAULT_PARM3
+ );
+
+ NdisWriteRegisterUshort(
+ &Adapter->MulticastBlock->Parm.Config.Parameter4,
+ DEFAULT_PARM4
+ );
+
+ NdisWriteRegisterUshort(
+ &Adapter->MulticastBlock->Parm.Config.Parameter5,
+ NewParameterField
+ );
+
+ NdisWriteRegisterUshort(
+ &Adapter->MulticastBlock->Parm.Config.Parameter6,
+ DEFAULT_PARM6
+ );
+
+
+ //
+ // if this was not from an ndisrequest, then we need to store the
+ // open somewhere
+ //
+
+ if (!Set) {
+ Adapter->TransmitInfo[
+ Adapter->NumberOfTransmitBuffers].OwningOpenBinding = Open;
+
+ Adapter->CloseResultedInChanges = TRUE;
+
+ } else {
+ Adapter->TransmitInfo[
+ Adapter->NumberOfTransmitBuffers].OwningOpenBinding = NULL;
+
+ ElnkSubmitCommandBlock(Adapter, Adapter->NumberOfTransmitBuffers);
+ }
+
+
+ StatusToReturn = TRUE;
+
+ }
+
+ return(StatusToReturn);
+
+}
+
+
+extern
+NDIS_STATUS
+ElnkChangeAddresses(
+ IN UINT OldAddressCount,
+ IN CHAR OldAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN UINT NewAddressCount,
+ IN CHAR NewAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when the multicast address
+ list has changed.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ OldAddressCount - The number of addresses in OldAddresses.
+
+ OldAddresses - The old multicast address list.
+
+ NewAddressCount - The number of addresses in NewAddresses.
+
+ NewAddresses - The new multicast address list.
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to ELNK_OPEN.
+
+ RequestHandle - A value supplied by the NDIS interface that the MAC
+ must use when completing this request with the NdisCompleteRequest
+ service, if the MAC completes this request asynchronously.
+
+ Set - If true the change resulted from a set, otherwise the
+ change resulted from a open closing.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+
+
+ PELNK_ADAPTER Adapter = PELNK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ //
+ // The open that made this request.
+ //
+ PELNK_OPEN Open = PELNK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ //
+ // Holds the change that should be returned to the filtering package.
+ //
+ NDIS_STATUS StatusOfChange;
+
+ OldAddressCount; OldAddresses; NdisRequest; Set;
+
+ if (Adapter->ResetInProgress) {
+
+ StatusOfChange = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ } else {
+
+ //
+ // The whole purpose of this routine is to determine whether
+ // the filtering changes need to result in the hardware being
+ // reset.
+ //
+
+ //
+ // We are referencing this open
+ //
+
+ ChangeAddressDispatch(
+ Adapter,
+ NewAddressCount,
+ NewAddresses,
+ Open,
+ Set
+ );
+
+ StatusOfChange = NDIS_STATUS_PENDING;
+
+ }
+
+ return StatusOfChange;
+
+}
+
+extern
+VOID
+ChangeAddressDispatch(
+ IN PELNK_ADAPTER Adapter,
+ IN UINT AddressCount,
+ IN CHAR Addresses[][ETH_LENGTH_OF_ADDRESS],
+ IN PELNK_OPEN Open,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ Changes the multicast address list of the adapter.
+
+Arguments:
+
+ Adapter - The adapter.
+
+ AddressCount - The number of addresses in Addresses
+
+ Addresses - The new multicast address list.
+
+Return Value:
+
+
+--*/
+
+{
+
+ UINT i, j;
+
+ IF_LOG('-');
+
+ //
+ // Setup the command block.
+ //
+
+ for (i = 0 ; i < AddressCount; i++ ) {
+
+ for (j = 0; j < ETH_LENGTH_OF_ADDRESS; j++) {
+
+ NdisWriteRegisterUchar(
+ &Adapter->MulticastBlock->Parm.Multicast.MulticastID[i][j],
+ Addresses[i][j]
+ );
+ }
+ }
+
+ NdisWriteRegisterUshort(
+ &Adapter->MulticastBlock->Parm.Multicast.McCount,
+ (USHORT)(AddressCount * ETH_LENGTH_OF_ADDRESS)
+ );
+
+ NdisWriteRegisterUshort(
+ &Adapter->MulticastBlock->Status,
+ CB_STATUS_FREE
+ );
+
+ NdisWriteRegisterUshort(
+ &Adapter->MulticastBlock->Command,
+ CB_MULTICAST
+ );
+
+ //
+ // if this was not from an ndisrequest, then we need to store the
+ // open somewhere
+ //
+
+ if (!Set) {
+ Adapter->TransmitInfo[
+ Adapter->NumberOfTransmitBuffers].OwningOpenBinding = Open;
+
+ Adapter->CloseResultedInChanges = TRUE;
+
+ } else {
+ Adapter->TransmitInfo[
+ Adapter->NumberOfTransmitBuffers].OwningOpenBinding = NULL;
+ //
+ // Now that we're set up, let's do it!
+ //
+
+ if (Adapter->FirstReset) {
+
+ ElnkSubmitCommandBlockAndWait(Adapter);
+
+ } else {
+
+ ElnkSubmitCommandBlock(Adapter, Adapter->NumberOfTransmitBuffers);
+
+ }
+ }
+
+}
+
+
+STATIC
+VOID
+ElnkCloseAction(
+ IN NDIS_HANDLE MacBindingHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when a particular binding
+ was closed while it was indicating through NdisIndicateReceive
+
+ All this routine needs to do is to decrement the reference count
+ of the binding.
+
+ NOTE: This routine assumes that it is called with the lock acquired.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to ELNK_OPEN.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ PELNK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle)->References--;
+}
+
+
+
+NDIS_STATUS
+ElnkRequest(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ The ElnkRequest function handles general requests from the
+ protocol. Currently these include SetInformation and
+ QueryInformation, more may be added in the future.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to ELNK_OPEN.
+
+ NdisRequest - A structure describing the request. In the case
+ of asynchronous completion, this pointer will be used to
+ identify the request that is completing.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+
+{
+ //
+ // This holds the status we will return.
+ //
+
+ NDIS_STATUS StatusOfRequest;
+
+ //
+ // Points to the adapter that this request is coming through.
+ //
+ PELNK_ADAPTER Adapter;
+
+ //
+ // Pts to the reserved section of the request
+ //
+ PELNK_REQUEST_RESERVED Reserved = PELNK_RESERVED_FROM_REQUEST(NdisRequest);
+
+ Adapter = PELNK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ if (!Adapter->ResetInProgress) {
+
+ PELNK_OPEN Open;
+
+ Open = PELNK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ if (!Open->BindingShuttingDown) {
+
+ switch (NdisRequest->RequestType) {
+
+ case NdisRequestSetInformation:
+ case NdisRequestQueryInformation:
+
+ //
+ // This is a valid request, queue it.
+ //
+
+ Open->References++;
+
+ Reserved->OpenBlock = Open;
+ Reserved->Next = (PNDIS_REQUEST)NULL;
+
+ ElnkQueueRequest (Adapter, NdisRequest);
+
+ StatusOfRequest = NDIS_STATUS_PENDING;
+ break;
+
+ default:
+
+ //
+ // Unknown request
+ //
+
+ StatusOfRequest = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+
+ }
+
+ } else {
+
+ StatusOfRequest = NDIS_STATUS_CLOSING;
+
+ }
+
+ } else {
+
+ StatusOfRequest = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ }
+
+ //
+ // This macro assumes it is called with the lock held,
+ // and releases it.
+ //
+
+ ELNK_DO_DEFERRED(Adapter);
+ return StatusOfRequest;
+}
+
+extern
+VOID
+ElnkQueueRequest(
+ IN PELNK_ADAPTER Adapter,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ ElnkQueueRequest takes an NDIS_REQUEST and ensures that it
+ gets processed and completed. It processes the
+ request immediately if nothing else is in progress, otherwise
+ it queues it for later processing.
+
+ THIS ROUTINE IS CALLED WITH THE SPINLOCK HELD.
+
+Arguments:
+
+ Adapter - The adapter that the request is for.
+
+ NdisRequest - The NDIS_REQUEST structure describing the request.
+ The ElnkReserved section is partially filled in, except
+ for the queueing and current offset fields.
+
+Return Value:
+
+ NDIS_STATUS_PENDING if the request was queued.
+ Otherwise, the return code from ElnkProcessRequestQueue.
+ This will be NDIS_STATUS_PENDING if the request was queued
+ to the adapter, otherwise the status of the request.
+
+
+--*/
+
+{
+
+ //
+ // Queue the request.
+ //
+
+ if (Adapter->FirstRequest != (PNDIS_REQUEST)NULL) {
+
+ //
+ // Something else on the queue, just queue it.
+ //
+
+ PELNK_RESERVED_FROM_REQUEST(Adapter->LastRequest)->Next = NdisRequest;
+ Adapter->LastRequest = NdisRequest;
+
+ } else {
+
+ //
+ // The queue if empty, so nothing is in progress.
+ //
+
+ Adapter->FirstRequest = NdisRequest;
+ Adapter->LastRequest = NdisRequest;
+
+ ElnkProcessRequestQueue(Adapter);
+
+ }
+}
+
+extern
+VOID
+ElnkProcessRequestQueue(
+ IN PELNK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ ElnkProcessRequestQueue takes the requests on the queue
+ and processes them as much as possible. It will complete
+ any requests that it fully processes. It will stop when
+ the queue is empty or it finds a request that has to pend.
+
+ THIS ROUTINE IS CALLED WITH THE LOCK HELD.
+
+Arguments:
+
+ Adapter - The adapter that the request is for.
+
+Return Value:
+
+ NDIS_STATUS_PENDING (probably should be VOID...)
+
+
+--*/
+{
+ PNDIS_REQUEST Request;
+ PELNK_REQUEST_RESERVED Reserved;
+ PELNK_OPEN Open;
+ NDIS_STATUS Status;
+
+ //
+ // Only one request can be processed at one time
+ //
+
+ if (Adapter->ProcessingRequests) {
+
+ return;
+
+ } else {
+
+ Adapter->ProcessingRequests = TRUE;
+
+ }
+
+ Request = Adapter->FirstRequest;
+
+ for (;;) {
+
+ //
+ // Loop until we exit, which happens when a
+ // request pends, or we empty the queue.
+ //
+
+ if ((Request == (PNDIS_REQUEST)NULL) || Adapter->ResetInProgress) {
+
+ break;
+ }
+
+ Reserved = PELNK_RESERVED_FROM_REQUEST(Request);
+
+ switch (Request->RequestType) {
+
+ case NdisRequestClose:
+
+ Adapter->CloseResultedInChanges = FALSE;
+
+ Open = Reserved->OpenBlock;
+
+ Status = EthDeleteFilterOpenAdapter(
+ Adapter->FilterDB,
+ Open->NdisFilterHandle,
+ NULL
+ );
+
+
+ //
+ // If the status is successful that merely implies that
+ // we were able to delete the reference to the open binding
+ // from the filtering code.
+ //
+ // The delete filter routine can return a "special" status
+ // that indicates that there is a current NdisIndicateReceive
+ // on this binding. See below.
+ //
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ //
+ // Account for the filter's reference to this open.
+ //
+
+ Open->References--;
+
+ } else if (Status == NDIS_STATUS_PENDING) {
+
+ //
+ // When the request completes we will dereference the
+ // open to account for the filter package's reference.
+ //
+
+ } else if (Status == NDIS_STATUS_CLOSING_INDICATING) {
+
+ //
+ // When we have this status it indicates that the filtering
+ // code was currently doing an NdisIndicateReceive. Our
+ // close action routine will get called when the filter
+ // is done with us, we remove the reference there.
+ //
+
+ Status = NDIS_STATUS_PENDING;
+
+ } else {
+
+ ASSERT(0);
+
+ }
+
+ if (Adapter->CloseResultedInChanges) {
+
+ //
+ // This means that we have to submit the command that was
+ // formed from the close callbacks.
+ //
+ ElnkSubmitCommandBlock(Adapter, Adapter->NumberOfTransmitBuffers);
+
+ }
+
+ //
+ // This flag prevents further requests on this binding.
+ //
+
+ Open->BindingShuttingDown = TRUE;
+
+ //
+ // Remove the reference kept for the fact that we
+ // had something queued.
+ //
+
+ Open->References--;
+
+ //
+ // Remove the open from the open list and put it on
+ // the closing list. This list is checked after every
+ // request, and when the reference count goes to zero
+ // the close is completed.
+ //
+
+ RemoveEntryList(&Open->OpenList);
+ InsertTailList(&Adapter->CloseList,&Open->OpenList);
+
+ break;
+
+ case NdisRequestOpen:
+
+ Open = Reserved->OpenBlock;
+
+ IF_LOG('O');
+
+ if (!EthNoteFilterOpenAdapter(
+ Open->OwningAdapter->FilterDB,
+ Open,
+ Open->NdisBindingContext,
+ &Open->NdisFilterHandle
+ )) {
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteOpenAdapter(
+ Open->NdisBindingContext,
+ NDIS_STATUS_FAILURE,
+ 0);
+
+ ELNK_FREE_PHYS(Open);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ } else {
+
+ //
+ // Everything has been filled in. Synchronize access to the
+ // adapter block and link the new open adapter in and increment
+ // the opens reference count to account for the fact that the
+ // filter routines have a "reference" to the open.
+ //
+
+ InsertTailList(&Adapter->OpenBindings,&Open->OpenList);
+ Adapter->OpenCount++;
+ Open->References++;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteOpenAdapter(
+ Open->NdisBindingContext,
+ NDIS_STATUS_SUCCESS,
+ 0);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ }
+
+ //
+ // Set this, since we want to continue processing
+ // the queue.
+ //
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ break;
+
+ case NdisRequestQueryInformation:
+
+ Status = ElnkQueryInformation(
+ Adapter,
+ Reserved->OpenBlock,
+ Request->DATA.QUERY_INFORMATION.Oid,
+ Request->DATA.QUERY_INFORMATION.InformationBuffer,
+ Request->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &(Request->DATA.QUERY_INFORMATION.BytesWritten),
+ &(Request->DATA.QUERY_INFORMATION.BytesNeeded)
+ );
+
+ break;
+
+ case NdisRequestQueryStatistics:
+
+ IF_LOG('1');
+
+ Status = ElnkQueryInformation(
+ Adapter,
+ (PELNK_OPEN)NULL,
+ Request->DATA.QUERY_INFORMATION.Oid,
+ Request->DATA.QUERY_INFORMATION.InformationBuffer,
+ Request->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &(Request->DATA.QUERY_INFORMATION.BytesWritten),
+ &(Request->DATA.QUERY_INFORMATION.BytesNeeded)
+ );
+
+ break;
+
+ case NdisRequestSetInformation:
+
+ IF_LOG('2');
+
+ Status = ElnkSetInformation(
+ Adapter,
+ Reserved->OpenBlock,
+ Request->DATA.SET_INFORMATION.Oid,
+ Request->DATA.SET_INFORMATION.InformationBuffer,
+ Request->DATA.SET_INFORMATION.InformationBufferLength,
+ &(Request->DATA.SET_INFORMATION.BytesRead),
+ &(Request->DATA.SET_INFORMATION.BytesNeeded));
+
+ break;
+
+ }
+
+ //
+ // see if operation pended
+ //
+
+ if (Status == NDIS_STATUS_PENDING) {
+
+ Adapter->ProcessingRequests = FALSE;
+
+ return;
+
+ }
+
+
+ //
+ // If we fall through here, we are done with this request.
+ //
+
+ Adapter->FirstRequest = Reserved->Next;
+
+ if (Request->RequestType == NdisRequestQueryStatistics) {
+
+ Adapter->References++;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteQueryStatistics(
+ Adapter->NdisAdapterHandle,
+ Request,
+ Status
+ );
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ Adapter->References--;
+
+ } else if ((Request->RequestType == NdisRequestQueryInformation) ||
+ (Request->RequestType == NdisRequestSetInformation)) {
+
+ Open = Reserved->OpenBlock;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteRequest(
+ Open->NdisBindingContext,
+ Request,
+ Status
+ );
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ Open->References--;
+
+ }
+
+ Request = Adapter->FirstRequest;
+
+ //
+ // Now loop and continue on with the next request.
+ //
+
+ }
+
+ Adapter->ProcessingRequests = FALSE;
+
+}
+
+
+extern
+NDIS_STATUS
+ElnkSetInformation(
+ IN PELNK_ADAPTER Adapter,
+ IN PELNK_OPEN Open,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN INT InformationBufferLength,
+ OUT PUINT BytesRead,
+ OUT PUINT BytesNeeded
+ )
+
+/*++
+
+Routine Description:
+
+ ElnkSetInformation handles a set operation for a
+ single OID.
+
+Arguments:
+
+ Adapter - The adapter that the set is for.
+
+ Open - a pointer to the open instance.
+
+ Oid - the NDIS_OID to process.
+
+ InformationBuffer - a pointer into the
+ NdisRequest->InformationBuffer into which contains the value to be set
+
+ InformationBufferLength - a pointer to the number of bytes in the
+ InformationBuffer.
+
+ BytesRead - Number of bytes read.
+
+ BytesNeeded - Number of bytes needed to satisfy this request.
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_PENDING
+ NDIS_STATUS_INVALID_LENGTH
+ NDIS_STATUS_INVALID_OID
+
+--*/
+
+{
+
+ NDIS_STATUS Status;
+ ULONG PacketFilter;
+ ULONG LookAheadBufferSize;
+ //
+ // Now check for the most common OIDs
+ //
+
+ *BytesNeeded = 0;
+
+ switch (Oid) {
+
+ case OID_802_3_MULTICAST_LIST:
+
+ if (InformationBufferLength % ETH_LENGTH_OF_ADDRESS != 0) {
+
+ //
+ // The data must be a multiple of the Ethernet
+ // address size.
+ //
+
+ *BytesNeeded = ETH_LENGTH_OF_ADDRESS;
+ return NDIS_STATUS_INVALID_DATA;
+
+ }
+
+ //
+ // Now call the filter package to set up the addresses.
+ //
+
+ Status = EthChangeFilterAddresses(
+ Adapter->FilterDB,
+ Open->NdisFilterHandle,
+ (PNDIS_REQUEST)NULL,
+ InformationBufferLength / ETH_LENGTH_OF_ADDRESS,
+ InformationBuffer,
+ TRUE
+ );
+
+ *BytesRead = InformationBufferLength;
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ if (InformationBufferLength != 4) {
+
+ *BytesNeeded = 4;
+ return NDIS_STATUS_INVALID_DATA;
+
+ }
+
+ //
+ // Now call the filter package to set the packet filter.
+ //
+
+ NdisMoveMemory ((PVOID)&PacketFilter, InformationBuffer, sizeof(ULONG));
+
+
+ //
+ // Verify bits
+ //
+
+ if (PacketFilter & (NDIS_PACKET_TYPE_SOURCE_ROUTING |
+ NDIS_PACKET_TYPE_SMT |
+ NDIS_PACKET_TYPE_MAC_FRAME |
+ NDIS_PACKET_TYPE_FUNCTIONAL |
+ NDIS_PACKET_TYPE_ALL_FUNCTIONAL |
+ NDIS_PACKET_TYPE_GROUP
+ )) {
+
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+
+ *BytesRead = 4;
+ *BytesNeeded = 0;
+
+ break;
+
+ }
+
+ Status = EthFilterAdjust(
+ Adapter->FilterDB,
+ Open->NdisFilterHandle,
+ (PNDIS_REQUEST)NULL,
+ PacketFilter,
+ TRUE
+ );
+
+ *BytesRead = InformationBufferLength;
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ if (InformationBufferLength != 4) {
+
+ *BytesNeeded = 4;
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ break;
+
+ }
+
+ *BytesRead = 4;
+
+ NdisMoveMemory(&LookAheadBufferSize,
+ InformationBuffer,
+ sizeof(ULONG));
+
+
+
+ if (LookAheadBufferSize <= (MAXIMUM_ETHERNET_PACKET_SIZE - ELNK_HEADER_SIZE)) {
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ } else {
+
+ Status = NDIS_STATUS_INVALID_DATA;
+ }
+
+ break;
+
+ case OID_GEN_PROTOCOL_OPTIONS:
+ if (InformationBufferLength != 4) {
+
+ *BytesNeeded = 4;
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ NdisMoveMemory(&Open->ProtOptionFlags, InformationBuffer, 4);
+
+ *BytesRead = 4;
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+
+ default:
+
+ Status = NDIS_STATUS_INVALID_OID;
+ break;
+
+ }
+
+ return Status;
+}
+
+
+
+STATIC
+NDIS_STATUS
+ElnkQueryInformation(
+ IN PELNK_ADAPTER Adapter,
+ IN PELNK_OPEN Open,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN UINT InformationBufferLength,
+ OUT PUINT BytesWritten,
+ OUT PUINT BytesNeeded
+)
+
+/*++
+
+Routine Description:
+
+ The ElnkQueryProtocolInformation process a Query request for
+ NDIS_OIDs that are specific to a binding about the MAC. Note that
+ some of the OIDs that are specific to bindings are also queryable
+ on a global basis. Rather than recreate this code to handle the
+ global queries, I use a flag to indicate if this is a query for the
+ global data or the binding specific data.
+
+Arguments:
+
+ Adapter - a pointer to the adapter.
+
+ Open - a pointer to the open instance. If null, then return
+ global statistics.
+
+ Oid - the NDIS_OID to process.
+
+ InformationBuffer - a pointer into the
+ NdisRequest->InformationBuffer into which store the result of the query.
+
+ InformationBufferLength - a pointer to the number of bytes left in the
+ InformationBuffer.
+
+ BytesWritten - a pointer to the number of bytes written into the
+ InformationBuffer.
+
+ BytesNeeded - If there is not enough room in the information buffer
+ then this will contain the number of bytes needed to complete the
+ request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+static
+NDIS_OID ElnkGlobalSupportedOids[] = {
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+ OID_GEN_RCV_CRC_ERROR,
+ OID_GEN_TRANSMIT_QUEUE_LENGTH,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ OID_802_3_RCV_ERROR_ALIGNMENT,
+ OID_802_3_XMIT_ONE_COLLISION,
+ OID_802_3_XMIT_MORE_COLLISIONS,
+ OID_802_3_XMIT_DEFERRED,
+ OID_802_3_XMIT_MAX_COLLISIONS,
+ OID_802_3_RCV_OVERRUN,
+ OID_802_3_XMIT_UNDERRUN,
+ OID_802_3_XMIT_HEARTBEAT_FAILURE,
+ OID_802_3_XMIT_TIMES_CRS_LOST
+ };
+
+static
+NDIS_OID ElnkProtocolSupportedOids[] = {
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE
+ };
+
+
+ NDIS_MEDIUM Medium = NdisMedium802_3;
+ UINT GenericUlong;
+ USHORT GenericUShort;
+ UCHAR GenericArray[6];
+ UINT MulticastAddresses;
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ //
+ // Common variables for pointing to result of query
+ //
+
+ PVOID MoveSource = (PVOID)(&GenericUlong);
+ ULONG MoveBytes = sizeof(GenericUlong);
+ USHORT TmpUshort;
+
+ NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady;
+
+ *BytesWritten = 0;
+ *BytesNeeded = 0;
+
+ //
+ // Switch on request type
+ //
+
+ switch(Oid){
+
+ case OID_GEN_MAC_OPTIONS:
+
+ GenericUlong = (ULONG)(NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
+ NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
+ NDIS_MAC_OPTION_NO_LOOPBACK
+ );
+
+ break;
+
+ case OID_GEN_SUPPORTED_LIST:
+
+ if (Open == NULL) {
+ MoveSource = (PVOID)(ElnkGlobalSupportedOids);
+ MoveBytes = sizeof(ElnkGlobalSupportedOids);
+ } else {
+ MoveSource = (PVOID)(ElnkProtocolSupportedOids);
+ MoveBytes = sizeof(ElnkProtocolSupportedOids);
+ }
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+
+
+ if (Adapter->ResetInProgress){
+
+ HardwareStatus = NdisHardwareStatusReset;
+
+ } else if (Adapter->FirstReset) {
+
+ HardwareStatus = NdisHardwareStatusInitializing;
+
+ } else {
+
+ HardwareStatus = NdisHardwareStatusReady;
+
+ }
+
+
+ MoveSource = (PVOID)(&HardwareStatus);
+ MoveBytes = sizeof(NDIS_HARDWARE_STATUS);
+
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+
+ MoveSource = (PVOID) (&Medium);
+ MoveBytes = sizeof(NDIS_MEDIUM);
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+
+ GenericUlong = (ULONG) MAXIMUM_ETHERNET_PACKET_SIZE - ELNK_HEADER_SIZE;
+
+ break;
+
+
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+
+ GenericUlong = (ULONG) MAXIMUM_ETHERNET_PACKET_SIZE;
+
+ break;
+
+
+
+ case OID_GEN_LINK_SPEED:
+
+ //
+ // 10 Mbps
+ //
+
+ GenericUlong = (ULONG)100000;
+
+ break;
+
+
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+
+ GenericUlong = (ULONG) MAXIMUM_ETHERNET_PACKET_SIZE *
+ Adapter->NumberOfTransmitBuffers;
+
+ break;
+
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+
+ GenericUlong = (ULONG) MAXIMUM_ETHERNET_PACKET_SIZE *
+ Adapter->NumberOfReceiveBuffers;
+
+ break;
+
+
+#if ELNKMC
+
+ case OID_GEN_VENDOR_ID:
+
+ NdisMoveMemory(
+ (PVOID)&GenericUlong,
+ Adapter->NetworkAddress,
+ 3
+ );
+ GenericUlong &= 0xFFFFFF00;
+ MoveSource = (PVOID)(&GenericUlong);
+ MoveBytes = sizeof(GenericUlong);
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+
+ MoveSource = (PVOID)"ElnkMC Adapter";
+ MoveBytes = 15;
+ break;
+
+#else
+
+ case OID_GEN_VENDOR_ID:
+
+ NdisMoveMemory(
+ (PVOID)&GenericUlong,
+ Adapter->NetworkAddress,
+ 3
+ );
+ GenericUlong &= 0xFFFFFF00;
+ GenericUlong != 0x01;
+ MoveSource = (PVOID)(&GenericUlong);
+ MoveBytes = sizeof(GenericUlong);
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+
+ MoveSource = (PVOID)"Elnk16 Adapter";
+ MoveBytes = 15;
+ break;
+
+#endif
+
+ case OID_GEN_DRIVER_VERSION:
+
+ GenericUShort = (USHORT)0x0300;
+
+ MoveSource = (PVOID)(&GenericUShort);
+ MoveBytes = sizeof(GenericUShort);
+ break;
+
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ if (Open != NULL) {
+
+ GenericUlong = (ULONG)(ETH_QUERY_PACKET_FILTER(
+ Adapter->FilterDB,
+ Open->NdisFilterHandle
+ ));
+ } else {
+
+ GenericUlong = (ULONG)ETH_QUERY_FILTER_CLASSES(
+ Adapter->FilterDB
+ );
+
+ }
+
+ break;
+
+ case OID_802_3_PERMANENT_ADDRESS:
+
+ ETH_COPY_NETWORK_ADDRESS(
+ (PCHAR)GenericArray,
+ Adapter->NetworkAddress
+ );
+
+ MoveSource = (PVOID)(GenericArray);
+ MoveBytes = ETH_LENGTH_OF_ADDRESS;
+ break;
+
+ case OID_802_3_CURRENT_ADDRESS:
+
+ ETH_COPY_NETWORK_ADDRESS(
+ (PCHAR)GenericArray,
+ Adapter->CurrentAddress
+ );
+
+ MoveSource = (PVOID)(GenericArray);
+ MoveBytes = ETH_LENGTH_OF_ADDRESS;
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+
+ if (Open == NULL) {
+
+ NDIS_STATUS Status;
+ EthQueryGlobalFilterAddresses(
+ &Status,
+ Adapter->FilterDB,
+ InformationBufferLength,
+ &MulticastAddresses,
+ (PVOID)InformationBuffer);
+
+ MoveSource = (PVOID)InformationBuffer;
+ MoveBytes = MulticastAddresses * ETH_LENGTH_OF_ADDRESS;
+
+ } else {
+
+ NDIS_STATUS Status;
+ EthQueryOpenFilterAddresses(
+ &Status,
+ Adapter->FilterDB,
+ Open->NdisFilterHandle,
+ InformationBufferLength,
+ &MulticastAddresses,
+ (PVOID)InformationBuffer);
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+ MoveSource = (PVOID)InformationBuffer;
+ MoveBytes = MulticastAddresses * ETH_LENGTH_OF_ADDRESS;
+ } else {
+ MoveSource = (PVOID)InformationBuffer;
+ MoveBytes = ETH_LENGTH_OF_ADDRESS *
+ EthNumberOfOpenFilterAddresses(
+ Adapter->FilterDB,
+ Open->NdisFilterHandle);
+ }
+
+ }
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+
+ GenericUlong = (ULONG) ELNK_MAXIMUM_MULTICAST;
+
+ break;
+
+ default:
+
+ if (Open != NULL) {
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+
+ }
+
+ switch(Oid){
+
+ case OID_GEN_XMIT_OK:
+ GenericUlong = (ULONG) Adapter->GoodTransmits;
+ break;
+
+ case OID_GEN_RCV_OK:
+ GenericUlong = (ULONG) Adapter->GoodReceives;
+ break;
+
+ case OID_GEN_XMIT_ERROR:
+ GenericUlong = (ULONG) (Adapter->RetryFailure +
+ Adapter->LostCarrier +
+ Adapter->UnderFlow +
+ Adapter->NoClearToSend);
+ break;
+
+ case OID_GEN_RCV_ERROR:
+ NdisReadRegisterUshort(&Adapter->Scb->CrcErrors, &GenericUlong);
+ NdisReadRegisterUshort(&Adapter->Scb->AlignmentErrors, &TmpUshort);
+ GenericUlong += TmpUshort;
+ NdisReadRegisterUshort(&Adapter->Scb->ResourceErrors, &TmpUshort);
+ GenericUlong += TmpUshort;
+ NdisReadRegisterUshort(&Adapter->Scb->OverrunErrors, &TmpUshort);
+ GenericUlong += TmpUshort;
+ GenericUlong += Adapter->FrameTooShort + Adapter->NoEofDetected;
+ break;
+
+ case OID_GEN_RCV_NO_BUFFER:
+ NdisReadRegisterUshort(&Adapter->Scb->ResourceErrors, &GenericUlong);
+ break;
+
+ case OID_GEN_RCV_CRC_ERROR:
+ NdisReadRegisterUshort(&Adapter->Scb->CrcErrors, &GenericUlong);
+ break;
+
+ case OID_GEN_TRANSMIT_QUEUE_LENGTH:
+ GenericUlong = (ULONG) Adapter->TransmitsQueued;
+ break;
+
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+ NdisReadRegisterUshort(&Adapter->Scb->AlignmentErrors, &GenericUlong);
+ break;
+
+ case OID_802_3_XMIT_ONE_COLLISION:
+ GenericUlong = (ULONG) Adapter->OneRetry;
+ break;
+
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+ GenericUlong = (ULONG) Adapter->MoreThanOneRetry;
+ break;
+
+ case OID_802_3_XMIT_DEFERRED:
+ GenericUlong = (ULONG) Adapter->Deferred;
+ break;
+
+ case OID_802_3_XMIT_MAX_COLLISIONS:
+ GenericUlong = (ULONG) Adapter->RetryFailure;
+ break;
+
+ case OID_802_3_RCV_OVERRUN:
+ NdisReadRegisterUshort(&Adapter->Scb->OverrunErrors, &GenericUlong);
+ break;
+
+ case OID_802_3_XMIT_UNDERRUN:
+ GenericUlong = (ULONG) Adapter->UnderFlow;
+ break;
+
+ case OID_802_3_XMIT_HEARTBEAT_FAILURE:
+ GenericUlong = (ULONG) Adapter->NoClearToSend;
+ break;
+
+ case OID_802_3_XMIT_TIMES_CRS_LOST:
+ GenericUlong = (ULONG) Adapter->LostCarrier;
+ break;
+
+ default:
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+
+ }
+
+ }
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS) {
+
+ if (MoveBytes > InformationBufferLength) {
+
+ //
+ // Not enough room in InformationBuffer. Punt
+ //
+
+ *BytesNeeded = MoveBytes;
+
+ StatusToReturn = NDIS_STATUS_BUFFER_TOO_SHORT;
+
+ } else {
+
+ //
+ // Copy result into InformationBuffer
+ //
+
+ *BytesWritten = MoveBytes;
+ if (MoveBytes > 0) {
+ ELNK_MOVE_MEMORY(
+ InformationBuffer,
+ MoveSource,
+ MoveBytes
+ );
+ }
+ }
+ }
+
+ return(StatusToReturn);
+}
+
+
+extern
+NDIS_STATUS
+ElnkQueryGlobalStatistics(
+ IN NDIS_HANDLE MacAdapterContext,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ ElnkQueryGlobalStatistics handles a per-adapter query
+ for statistics. It is similar to ElnkQueryInformation,
+ which is per-binding.
+
+Arguments:
+
+ MacAdapterContext - The context value that the MAC passed
+ to NdisRegisterAdapter; actually as pointer to a
+ ELNK_ADAPTER.
+
+ NdisRequest - Describes the query request.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_PENDING
+
+--*/
+
+{
+
+ //
+ // This holds the status we will return.
+ //
+
+ NDIS_STATUS StatusOfRequest;
+
+ //
+ // Points to the adapter that this request is coming through.
+ //
+ PELNK_ADAPTER Adapter = (PELNK_ADAPTER)MacAdapterContext;
+
+ PELNK_REQUEST_RESERVED Reserved = PELNK_RESERVED_FROM_REQUEST(NdisRequest);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ if (!Adapter->ResetInProgress) {
+
+ switch (NdisRequest->RequestType) {
+
+ case NdisRequestQueryStatistics:
+
+ //
+ // Valid request.
+ //
+
+ Reserved->OpenBlock = (PELNK_OPEN)NULL;
+ Reserved->Next = (PNDIS_REQUEST)NULL;
+
+ ElnkQueueRequest (Adapter, NdisRequest);
+
+ StatusOfRequest = NDIS_STATUS_PENDING;
+ break;
+
+ default:
+
+ //
+ // Unknown request
+ //
+
+ StatusOfRequest = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+
+ }
+
+ } else {
+
+ StatusOfRequest = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ }
+
+
+ //
+ // This macro assumes it is called with the lock held,
+ // and releases it.
+ //
+
+ ELNK_DO_DEFERRED(Adapter);
+ return StatusOfRequest;
+}
diff --git a/private/ntos/ndis/elnkmc/reset.c b/private/ntos/ndis/elnkmc/reset.c
new file mode 100644
index 000000000..7a4925fba
--- /dev/null
+++ b/private/ntos/ndis/elnkmc/reset.c
@@ -0,0 +1,2331 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ reset.c
+
+Abstract:
+
+ This is the file containing the reset code for the 3Com Etherlink/MC
+ and Etherlink 16 Ethernet adapter. This driver conforms to the
+ NDIS 3.0 interface.
+
+Author:
+
+ Johnson R. Apacible (JohnsonA) 10-June-1991
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+
+//
+// So we can trace things...
+//
+
+#include <efilter.h>
+#include <elnkhw.h>
+#include <elnksw.h>
+
+
+#define STATIC
+
+STATIC
+VOID
+ElnkAbortPendingQueue(
+ IN PELNK_ADAPTER Adapter,
+ IN BOOLEAN AbortOpens
+ );
+
+STATIC
+VOID
+ElnkSetConfigurationBlock(
+ IN PELNK_ADAPTER Adapter
+ );
+
+STATIC
+BOOLEAN
+SetConfigurationBlockAndInit(
+ IN PELNK_ADAPTER Adapter
+ );
+
+
+STATIC
+VOID
+SetupSharedMemory(
+ IN PELNK_ADAPTER Adapter
+ );
+
+STATIC
+BOOLEAN
+ElnkPowerUpInit(
+ IN PELNK_ADAPTER Adapter
+ );
+
+extern
+VOID
+ChangeAddressDispatch(
+ IN PELNK_ADAPTER Adapter,
+ IN UINT AddressCount,
+ IN CHAR Addresses[][ETH_LENGTH_OF_ADDRESS],
+ IN PELNK_OPEN Open,
+ IN BOOLEAN Set
+ );
+
+STATIC
+BOOLEAN
+ElnkInitialInit(
+ IN PELNK_ADAPTER Adapter,
+ IN UINT ElnkInterruptVector
+ );
+
+
+STATIC
+VOID
+DoResetIndications(
+ IN PELNK_ADAPTER Adapter,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+ResetAdapterVariables(
+ IN PELNK_ADAPTER Adapter
+ );
+
+VOID
+Elnk16GenerateIdPattern(
+ IN PELNK_ADAPTER Adapter
+ );
+
+//
+// Common Elnkmc and Elnk16 routines
+//
+
+BOOLEAN
+ElnkSyncStartReceive(
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ This function is used to synchronize with the ISR the starting of a
+ receive unit.
+
+Arguments:
+
+ see NDIS 3.0 spec.
+
+Notes:
+
+ returns TRUE on success, else FALSE.
+
+--*/
+{
+ PELNK_ADAPTER Adapter = (PELNK_ADAPTER)Context;
+
+ IF_LOG('w');
+
+ WRITE_ADAPTER_REGISTER(
+ Adapter,
+ OFFSET_SCB_RD,
+ (USHORT)(Adapter->RfdOffset)
+ );
+
+ WRITE_ADAPTER_REGISTER(
+ Adapter,
+ OFFSET_SCBCMD,
+ RUC_START
+ );
+
+ ELNK_CA;
+
+ Adapter->RuRestarted = TRUE;
+
+ return(TRUE);
+
+}
+
+BOOLEAN
+ElnkSyncAbort(
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ This function is used to synchronize with the ISR the starting of a
+ abort of a command block.
+
+Arguments:
+
+ see NDIS 3.0 spec.
+
+Notes:
+
+ returns TRUE on success, else FALSE.
+
+--*/
+{
+ PELNK_ADAPTER Adapter = (PELNK_ADAPTER)Context;
+
+ WRITE_ADAPTER_REGISTER(
+ Adapter,
+ OFFSET_SCBCMD,
+ CUC_ABORT | RUC_ABORT
+ );
+
+ ELNK_CA;
+
+ return(TRUE);
+
+}
+
+BOOLEAN
+ElnkSyncReset(
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ This function is used to synchronize with the ISR the starting of a
+ reset command block.
+
+Arguments:
+
+ see NDIS 3.0 spec.
+
+Notes:
+
+ returns TRUE on success, else FALSE.
+
+--*/
+{
+ PELNK_ADAPTER Adapter = (PELNK_ADAPTER)Context;
+
+ WRITE_ADAPTER_REGISTER(
+ Adapter,
+ OFFSET_SCBCMD,
+ SCB_COMMAND_RESET
+ );
+
+ ELNK_CA;
+
+ return(TRUE);
+
+}
+
+
+STATIC
+NDIS_STATUS
+ElnkReset(
+ IN NDIS_HANDLE MacBindingHandle
+ )
+
+/*++
+
+Routine Description:
+
+ The ElnkReset request instructs the MAC to issue a hardware reset
+ to the network adapter. The MAC also resets its software state. See
+ the description of NdisReset for a detailed description of this request.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to ELNK_OPEN.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+
+{
+ //
+ // Holds the status that should be returned to the caller.
+ //
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_PENDING;
+
+ PELNK_ADAPTER Adapter =
+ PELNK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ //
+ // Hold the locks while we update the reference counts on the
+ // adapter and the open.
+ //
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ if (!Adapter->ResetInProgress)
+ {
+ PELNK_OPEN Open = PELNK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ if (!Open->BindingShuttingDown)
+ {
+ Open->References++;
+
+ SetupForReset(
+ Adapter,
+ PELNK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle)
+ );
+
+ Open->References--;
+ }
+ else
+ {
+ StatusToReturn = NDIS_STATUS_CLOSING;
+ }
+ }
+ else
+ {
+ Adapter->References--;
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ return(NDIS_STATUS_RESET_IN_PROGRESS);
+ }
+
+ ELNK_DO_DEFERRED(Adapter);
+
+ return(StatusToReturn);
+}
+
+
+
+STATIC
+VOID
+ElnkSetConfigurationBlock(
+ IN PELNK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine simply fills the configuration block
+ with the information necessary for initialization.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired OR that only a single thread of execution is accessing
+ the particular adapter.
+
+Arguments:
+
+ Adapter - The adapter which holds the initialization block
+ to initialize.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+
+ UINT PacketFilters;
+ UINT i;
+
+ PCONFIG_CB Configuration;
+
+ Configuration = &Adapter->MulticastBlock->Parm.Config;
+
+ NdisZeroMappedMemory(
+ (PUCHAR)Configuration,
+ sizeof(CONFIG_CB)
+ );
+
+ //
+ // Setup default configuration values
+ //
+
+ Adapter->OldParameterField = DEFAULT_PARM5;
+
+ //
+ // Set up the address filtering.
+ //
+ // First get hold of the combined packet filter.
+ //
+ if (Adapter->FilterDB != NULL) {
+ PacketFilters = ETH_QUERY_FILTER_CLASSES(Adapter->FilterDB);
+ } else {
+ PacketFilters = 0;
+ }
+
+//
+// this code was removed as it isn't necessary and causes the cards to
+// not be able to send packets unless the packet filter is changed.
+//
+#if 0
+
+ if (PacketFilters & NDIS_PACKET_TYPE_PROMISCUOUS) {
+
+ //
+ // If one binding is promiscuous there is no point in
+ // setting up any other filtering. Every packet is
+ // going to be accepted by the hardware.
+ //
+
+ Adapter->OldParameterField |= CONFIG_PROMISCUOUS;
+
+ } else if (PacketFilters & NDIS_PACKET_TYPE_ALL_MULTICAST) {
+
+ //
+ // Simulate All Multicast
+ //
+
+ Adapter->OldParameterField |= CONFIG_PROMISCUOUS;
+
+ } else if (PacketFilters & NDIS_PACKET_TYPE_BROADCAST) {
+
+ //
+ // Enable broadcast packets.
+ //
+
+ Adapter->OldParameterField &= ~CONFIG_BROADCAST;
+
+ }
+
+ if (!Adapter->IsExternal) {
+
+ Adapter->OldParameterField |= CONFIG_INTERNAL;
+
+ }
+
+ //
+ // see if we need to change adapter default configuration
+ //
+
+ NdisWriteRegisterUshort(&Configuration->Parameter1, DEFAULT_PARM1);
+ NdisWriteRegisterUshort(&Configuration->Parameter2, DEFAULT_PARM2);
+ NdisWriteRegisterUshort(&Configuration->Parameter3, DEFAULT_PARM3);
+ NdisWriteRegisterUshort(&Configuration->Parameter4, DEFAULT_PARM4);
+ NdisWriteRegisterUshort(&Configuration->Parameter6, DEFAULT_PARM6);
+
+ NdisWriteRegisterUshort(
+ &Configuration->Parameter5,
+ Adapter->OldParameterField
+ );
+
+ NdisWriteRegisterUshort(&Adapter->MulticastBlock->Status, CB_STATUS_FREE);
+ NdisWriteRegisterUshort(&Adapter->MulticastBlock->Command, CB_CONFIG);
+ NdisWriteRegisterUshort(&Adapter->MulticastBlock->NextCbOffset, ELNK_NULL);
+
+ ElnkSubmitCommandBlockAndWait(Adapter);
+#endif
+ //
+ // Do Individual Address Setup
+ //
+
+ NdisWriteRegisterUshort(&Adapter->MulticastBlock->Status, CB_STATUS_FREE);
+ NdisWriteRegisterUshort(&Adapter->MulticastBlock->Command, CB_SETUP);
+ NdisWriteRegisterUshort(&Adapter->MulticastBlock->NextCbOffset, ELNK_NULL);
+
+ for (i = 0; i < ETH_LENGTH_OF_ADDRESS; i++) {
+ NdisWriteRegisterUchar(
+ &Adapter->MulticastBlock->Parm.Setup.StationAddress[i],
+ Adapter->CurrentAddress[i]
+ );
+ }
+
+ ElnkSubmitCommandBlockAndWait(Adapter);
+
+ //
+ // Now Query the Multicast Addresses
+ //
+
+ if (PacketFilters & NDIS_PACKET_TYPE_MULTICAST) {
+
+ UINT NumberOfMulticastAddresses;
+ NDIS_STATUS Status;
+
+ EthQueryGlobalFilterAddresses(
+ &Status,
+ Adapter->FilterDB,
+ ETH_LENGTH_OF_ADDRESS * ELNK_MAXIMUM_MULTICAST,
+ &NumberOfMulticastAddresses,
+ Adapter->PrivateMulticastBuffer
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+ ChangeAddressDispatch(
+ Adapter,
+ NumberOfMulticastAddresses,
+ Adapter->PrivateMulticastBuffer,
+ ELNK_BOGUS_OPEN,
+ TRUE
+ );
+
+ }
+
+ }
+
+}
+
+VOID
+ElnkStartAdapterReset(
+ IN PELNK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This is the first phase of resetting the adapter hardware.
+
+ It makes the following assumptions:
+
+ 1) That the hardware has been stopped.
+
+ 2) That it can not be preempted.
+
+ 3) That no other adapter activity can occur.
+
+ When this routine is finished all of the adapter information
+ will be as if the driver was just initialized.
+
+ Spinlock assumed held.
+
+Arguments:
+
+ Adapter - The adapter whose hardware is to be reset.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ //
+ // Go through the various transmit lists and abort every packet.
+ //
+
+ {
+
+ UINT i;
+ PNDIS_PACKET Packet;
+ PELNK_RESERVED Reserved;
+ PELNK_OPEN Open;
+ PNDIS_PACKET Next;
+
+ for (
+ i = 0;
+ i < 3;
+ i++
+ ) {
+
+ switch (i) {
+
+ case 0:
+ Next = Adapter->FirstLoopBack;
+ break;
+ case 1:
+ Next = Adapter->FirstFinishTransmit;
+ break;
+
+ case 2:
+ Next = Adapter->FirstStagePacket;
+ break;
+
+ }
+
+
+ while (Next) {
+
+ Packet = Next;
+ Reserved = PELNK_RESERVED_FROM_PACKET(Packet);
+ Next = Reserved->Next;
+ Open =
+ PELNK_OPEN_FROM_BINDING_HANDLE(Reserved->MacBindingHandle);
+
+ //
+ // The completion of the packet is one less reason
+ // to keep the open around.
+ //
+
+ ASSERT(Open->References);
+
+ Open->References--;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteSend(
+ Open->NdisBindingContext,
+ Packet,
+ NDIS_STATUS_REQUEST_ABORTED
+ );
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ }
+
+ }
+
+ }
+
+ SetConfigurationBlockAndInit(Adapter);
+
+}
+
+STATIC
+BOOLEAN
+SetConfigurationBlockAndInit(
+ IN PELNK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ It is this routines responsibility to make sure that the
+ Configuration block is filled and the adapter is initialized
+ *but not* started.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired OR that only a single thread of execution is working
+ with this particular adapter.
+
+Arguments:
+
+ Adapter - The adapter whose hardware is to be initialized.
+
+Return Value:
+
+ TRUE is reset successful, FALSE otherwise.
+
+--*/
+{
+
+ BOOLEAN StatusOfReset = FALSE;
+
+ //
+ // We have 2 ways of doing reset, one for initial power up
+ // and the other when we have already setup the scb
+ //
+
+ ResetAdapterVariables(Adapter);
+
+ StatusOfReset = ElnkPowerUpInit(Adapter);
+
+ if (StatusOfReset) {
+
+ //
+ // Setup the shared memory structures
+ //
+
+ SetupSharedMemory(Adapter);
+
+ //
+ // Fill in the adapter's initialization block.
+ //
+
+ ElnkSetConfigurationBlock(Adapter);
+
+ ELNK_ENABLE_INTERRUPT;
+
+ DoResetIndications(Adapter, NDIS_STATUS_SUCCESS);
+
+ if (!Adapter->FirstReset) {
+
+ NdisSetTimer(
+ &Adapter->DeadmanTimer,
+ 5000
+ );
+
+ } else {
+
+ Adapter->FirstReset = FALSE;
+ }
+
+ } else {
+
+ DoResetIndications(Adapter, NDIS_STATUS_FAILURE);
+
+ }
+
+ return(StatusOfReset);
+}
+
+
+VOID
+ElnkStartChip(
+ IN PELNK_ADAPTER Adapter,
+ IN PELNK_RECEIVE_INFO ReceiveInfo
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to start an already initialized Elnk.
+
+Arguments:
+
+ Adapter - The adapter for the Elnk to start.
+
+ ReceiveInfo - Pointer to the first receive entry to be
+ used by the adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // If the memory is not mapped, then we can do nothing
+ //
+
+ if (!Adapter->MemoryIsMapped) {
+
+ return;
+
+ }
+
+ //
+ // Start the receive unit
+ //
+
+ Adapter->RfdOffset = ReceiveInfo->RfdOffset;
+
+ ELNK_WAIT;
+
+ NdisSynchronizeWithInterrupt(
+ &(Adapter->Interrupt),
+ (PVOID)ElnkSyncStartReceive,
+ (PVOID)(Adapter)
+ );
+
+ ELNK_WAIT;
+}
+
+VOID
+ElnkStopChip(
+ IN PELNK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to stop the Elnk.
+
+Arguments:
+
+ Adapter - The Elnk adapter to stop.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UCHAR CurrentCsr;
+
+ //
+ // If the adapter has previously been reset, we need to stop both the
+ // CU and the RU
+ //
+
+ if (!Adapter->FirstReset) {
+
+ NdisSynchronizeWithInterrupt(
+ &(Adapter->Interrupt),
+ (PVOID)ElnkSyncAbort,
+ (PVOID)(Adapter)
+ );
+
+ }
+
+ ELNK_READ_UCHAR(
+ Adapter,
+ ELNK_CSR,
+ &CurrentCsr
+ );
+
+ ELNK_WRITE_UCHAR(
+ Adapter,
+ ELNK_CSR,
+ CurrentCsr & ~CSR_INTEN
+ );
+}
+
+STATIC
+BOOLEAN
+ElnkPowerUpInit(
+ IN PELNK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the card and reads and sets relevant
+ information from and to the 82586.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired OR that only a single thread of execution is working
+ with this particular adapter.
+
+Arguments:
+
+ Adapter - The adapter whose hardware is to be initialized.
+
+Return Value:
+
+ TRUE is reset successful, FALSE otherwise.
+
+--*/
+{
+ NDIS_STATUS Status;
+ NDIS_PHYSICAL_ADDRESS PhysicalAddress;
+
+ //
+ // Get station address
+ //
+
+ ElnkGetStationAddress(
+ Adapter
+ );
+
+ //
+ // Check for validity of the address
+ //
+ if (((Adapter->NetworkAddress[0] == 0xFF) &&
+ (Adapter->NetworkAddress[1] == 0xFF) &&
+ (Adapter->NetworkAddress[2] == 0xFF) &&
+ (Adapter->NetworkAddress[3] == 0xFF) &&
+ (Adapter->NetworkAddress[4] == 0xFF) &&
+ (Adapter->NetworkAddress[5] == 0xFF)) ||
+ ((Adapter->NetworkAddress[0] == 0x00) &&
+ (Adapter->NetworkAddress[1] == 0x00) &&
+ (Adapter->NetworkAddress[2] == 0x00) &&
+ (Adapter->NetworkAddress[3] == 0x00) &&
+ (Adapter->NetworkAddress[4] == 0x00) &&
+ (Adapter->NetworkAddress[5] == 0x00)))
+ {
+ ElnkLogError(
+ Adapter,
+ startChip,
+ NDIS_ERROR_CODE_INVALID_VALUE_FROM_ADAPTER,
+ 0);
+
+ return(FALSE);
+ }
+ //
+ // Do Memory Mapping
+ //
+
+ if (!Adapter->MemoryIsMapped) {
+
+ NdisSetPhysicalAddressHigh(PhysicalAddress, 0);
+ NdisSetPhysicalAddressLow(PhysicalAddress, Adapter->SharedRamPhys);
+
+ NdisMapIoSpace(
+ &Status,
+ (PVOID *)(&Adapter->SharedRam),
+ Adapter->NdisAdapterHandle,
+ PhysicalAddress,
+ Adapter->SharedRamSize * 1024
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ ElnkLogError(
+ Adapter,
+ startChip,
+ NDIS_ERROR_CODE_RESOURCE_CONFLICT,
+ 0
+ );
+
+ return(FALSE);
+
+ }
+
+ Adapter->MemoryIsMapped = TRUE;
+
+ }
+
+ //
+ // everything must be in a single 64K segment
+ //
+
+ Adapter->Scp = (PSCP) ELNK_GET_HOST_ADDRESS(Adapter, OFFSET_SCP);
+
+ Adapter->Iscp = (PISCP) ELNK_GET_HOST_ADDRESS(Adapter, OFFSET_ISCP);
+
+ Adapter->Scb = (PSCB) ELNK_GET_HOST_ADDRESS(Adapter, OFFSET_SCB);
+
+ Adapter->MulticastBlock = (PNON_TRANSMIT_CB)
+ ELNK_GET_HOST_ADDRESS(Adapter, OFFSET_MULTICAST);
+
+ Adapter->TransmitQueue = (PTRANSMIT_CB) Adapter->SharedRam;
+
+ Adapter->ReceiveQueue = (PRECEIVE_FRAME_DESCRIPTOR) (
+ (PUCHAR)(Adapter->TransmitQueue) +
+ Adapter->NumberOfTransmitBuffers *
+ (sizeof(TRANSMIT_CB) +
+ ELNK_OFFSET_TO_NEXT_BUFFER));
+
+ if ELNKDEBUG {
+ DPrint2("Shared Ram = %lx\n",Adapter->SharedRam);
+ DPrint2("Scp = %lx\n",Adapter->Scp);
+ DPrint2("IScp = %lx\n",Adapter->Iscp);
+ DPrint2("Scb = %lx\n",Adapter->Scb);
+ DPrint2("MulticastBlock = %lx\n",Adapter->MulticastBlock);
+ DPrint2("****** Adapter = %lx\n",Adapter);
+ }
+
+#if ELNKMC
+ //
+ // Reset Chip
+ //
+
+ ELNK_WRITE_UCHAR(
+ Adapter,
+ ELNK_CSR,
+ CSR_RESET |
+ CSR_BANK_SELECT_MASK
+ );
+
+ NdisStallExecution(1000);
+
+ ELNK_WRITE_UCHAR(
+ Adapter,
+ ELNK_CSR,
+ CSR_BANK_SELECT_MASK |
+ CSR_INTEN
+ );
+
+ //
+ // Do a Channel Attention to wake up card. When card wakes up, it will
+ // be very hungry and will try to get its food from the reset vector at
+ // location offset + 3FF6 for the address of the ISCP
+ //
+
+ //
+ // Setup the Reset vector First
+ //
+
+ NdisWriteRegisterUshort(&Adapter->Scp->SysBus, 0);
+ NdisWriteRegisterUshort(&Adapter->Scp->IscpBase, 0);
+ NdisWriteRegisterUshort(
+ &Adapter->Scp->IscpOffset,
+ OFFSET_ISCP
+ );
+
+
+ //
+ // Setup the ISCP
+ //
+
+ NdisWriteRegisterUlong(&Adapter->Iscp->ScbBaseAddress, 0);
+
+ NdisWriteRegisterUshort(
+ &Adapter->Iscp->ScbOffset,
+ OFFSET_SCB
+ );
+
+ NdisWriteRegisterUshort(&Adapter->Iscp->Busy, 0x01);
+
+
+ //
+ // Put the Scb in a known state
+ //
+
+ NdisWriteRegisterUshort(&Adapter->Scb->Status, CB_STATUS_FREE);
+ NdisWriteRegisterUshort(&Adapter->Scb->Command, 0);
+ NdisWriteRegisterUshort(&Adapter->Scb->CommandListOffset, ELNK_NULL);
+ NdisWriteRegisterUshort(&Adapter->Scb->RFAOffset, ELNK_NULL);
+ NdisWriteRegisterUshort(&Adapter->Scb->CrcErrors, 0);
+ NdisWriteRegisterUshort(&Adapter->Scb->AlignmentErrors, 0);
+ NdisWriteRegisterUshort(&Adapter->Scb->ResourceErrors, 0);
+ NdisWriteRegisterUshort(&Adapter->Scb->OverrunErrors, 0);
+
+ //
+ // Do Channel Attention
+ //
+
+ ELNK_CA;
+#else
+
+ //
+ // Setup the Reset vector First
+ //
+
+ NdisWriteRegisterUshort(&Adapter->Scp->SysBus, 0);
+ NdisWriteRegisterUshort(&Adapter->Scp->IscpBase, 0);
+ NdisWriteRegisterUshort(
+ &Adapter->Scp->IscpOffset,
+ OFFSET_ISCP
+ );
+
+
+ //
+ // Setup the ISCP
+ //
+
+ NdisWriteRegisterUlong(&Adapter->Iscp->ScbBaseAddress, 0);
+
+ NdisWriteRegisterUshort(
+ &Adapter->Iscp->ScbOffset,
+ OFFSET_SCB
+ );
+
+ NdisWriteRegisterUshort(&Adapter->Iscp->Busy, 0x01);
+
+
+ //
+ // Put the Scb in a known state
+ //
+
+ NdisWriteRegisterUshort(&Adapter->Scb->Status, CB_STATUS_FREE);
+ NdisWriteRegisterUshort(&Adapter->Scb->Command, 0);
+ NdisWriteRegisterUshort(&Adapter->Scb->CommandListOffset, ELNK_NULL);
+ NdisWriteRegisterUshort(&Adapter->Scb->RFAOffset, ELNK_NULL);
+ NdisWriteRegisterUshort(&Adapter->Scb->CrcErrors, 0);
+ NdisWriteRegisterUshort(&Adapter->Scb->AlignmentErrors, 0);
+ NdisWriteRegisterUshort(&Adapter->Scb->ResourceErrors, 0);
+ NdisWriteRegisterUshort(&Adapter->Scb->OverrunErrors, 0);
+
+ //
+ // Reset Chip
+ //
+
+ ELNK_WRITE_UCHAR(
+ Adapter,
+ ELNK_CSR,
+ CSR_RESET
+ );
+
+ NdisStallExecution(1000);
+
+ ELNK_WRITE_UCHAR(
+ Adapter,
+ ELNK_CSR,
+ CSR_INTEN
+ );
+
+ //
+ // Do a Channel Attention to wake up card. When card wakes up, it will
+ // be very hungry and will try to get its food from the reset vector at
+ // location offset + 3FF6 for the address of the ISCP
+ //
+
+ ELNK_WRITE_UCHAR(
+ Adapter,
+ ELNK_CSR,
+ CSR_DEFAULT
+ );
+ //
+ // Do Channel Attention
+ //
+
+ ELNK_CA;
+#endif
+ return(TRUE);
+
+}
+
+STATIC
+VOID
+DoResetIndications(
+ IN PELNK_ADAPTER Adapter,
+ IN NDIS_STATUS Status
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by SetConfigurationBlockAndInit to perform any
+ indications which need to be done after a reset. Note that
+ this routine will be called after either a successful reset
+ or a failed reset.
+
+Arguments:
+
+ Adapter - The adapter whose hardware has been initialized.
+
+ Status - The status of the reset to send to the protocol(s).
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // This will point (possibly null) to the open that
+ // initiated the reset.
+ //
+ PELNK_OPEN ResettingOpen;
+
+ //
+ // We save off the open that caused this reset incase
+ // we get *another* reset while we're indicating the
+ // last reset is done.
+ //
+
+ ResettingOpen = Adapter->ResettingOpen;
+
+ //
+ // We need to signal every open binding that the
+ // reset is complete. We increment the reference
+ // count on the open binding while we're doing indications
+ // so that the open can't be deleted out from under
+ // us while we're indicating (recall that we can't own
+ // the lock during the indication).
+ //
+
+ {
+
+ PELNK_OPEN Open;
+ PLIST_ENTRY CurrentLink;
+
+ CurrentLink = Adapter->OpenBindings.Flink;
+
+ while (CurrentLink != &Adapter->OpenBindings) {
+
+ Open = CONTAINING_RECORD(
+ CurrentLink,
+ ELNK_OPEN,
+ OpenList
+ );
+
+ Open->References++;
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Reset failed. Notify of death
+ //
+
+
+ NdisIndicateStatus(
+ Open->NdisBindingContext,
+ NDIS_STATUS_CLOSED,
+ NULL,
+ 0
+ );
+ }
+
+ NdisIndicateStatus(
+ Open->NdisBindingContext,
+ NDIS_STATUS_RESET_END,
+ &Status,
+ sizeof(Status)
+ );
+
+ NdisIndicateStatusComplete(Open->NdisBindingContext);
+
+ Open->References--;
+
+ CurrentLink = CurrentLink->Flink;
+
+ }
+
+ //
+ // Look to see which open initiated the reset.
+ //
+ // If the reset was initiated for some obscure hardware
+ // reason that can't be associated with a particular
+ // open (e.g. memory error on receiving a packet) then
+ // we won't have an initiating request so we can't
+ // indicate. (The ResettingOpen pointer will be
+ // NULL in this case.)
+ //
+
+ if (ResettingOpen) {
+
+ NdisCompleteReset(
+ ResettingOpen->NdisBindingContext,
+ Status
+ );
+
+ ResettingOpen->References--;
+
+ }
+
+ }
+
+ Adapter->ResetInProgress = FALSE;
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ //
+ // Process any Opens that may have been queued in the meantime
+ //
+ ElnkStartChip(Adapter, &Adapter->ReceiveInfo[Adapter->ReceiveHead]);
+ ElnkProcessRequestQueue(Adapter);
+
+ } else {
+
+ //
+ // Abort everything
+ //
+ ElnkAbortPendingQueue(Adapter, TRUE);
+
+ }
+
+}
+
+
+STATIC
+VOID
+ElnkAbortPendingQueue(
+ IN PELNK_ADAPTER Adapter,
+ IN BOOLEAN AbortOpens
+ )
+
+/*++
+
+Routine Description:
+
+ This routine aborts all stuff in the pending queue.
+
+ NOTE: This routine must be called with the lock acquired.
+
+Arguments:
+
+ Adapter - The adapter whose hardware is to be initialized.
+
+ AbortOpens - Should Open requests be aborted.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PNDIS_REQUEST CurrentRequest;
+ PNDIS_REQUEST * CurrentNextLocation;
+ PELNK_OPEN TmpOpen;
+
+ PELNK_REQUEST_RESERVED Reserved;
+
+ //
+ // If there is a close at the top of the queue, then
+ // it may be in two states:
+ //
+ // 1- Has interrupted, and the InterruptDpc got the
+ // interrupt out of Adapter->IsrValue before we zeroed it.
+ //
+ // 2- Has interrupted, but we zeroed Adapter->IsrValue
+ // before it read it, OR has not yet interrupted.
+ //
+ // In case 1, the interrupt will be processed and the
+ // close will complete without our intervention. In
+ // case 2, the open will not complete. In that case
+ // the CAM will have been updated for that open, so
+ // all that remains is for us to dereference the open
+ // as would have been done in the interrupt handler.
+ //
+ // Closes that are not at the top of the queue we
+ // leave in place; when we restart the queue after
+ // the reset, they will get processed.
+ //
+
+ CurrentRequest = Adapter->FirstRequest;
+
+ if (CurrentRequest) {
+
+ Reserved = PELNK_RESERVED_FROM_REQUEST(CurrentRequest);
+
+ //
+ // If the first request is a close, take it off the
+ // queue, and "complete" it.
+ //
+
+ if (CurrentRequest->RequestType == NdisRequestClose) {
+ Adapter->FirstRequest = Reserved->Next;
+ --(Reserved->OpenBlock)->References;
+ CurrentRequest = Adapter->FirstRequest;
+ }
+
+ CurrentNextLocation = &(Adapter->FirstRequest);
+
+ while (CurrentRequest) {
+
+ Reserved = PELNK_RESERVED_FROM_REQUEST(CurrentRequest);
+
+ if (CurrentRequest->RequestType == NdisRequestClose) {
+
+ CurrentNextLocation = &(Reserved->Next);
+
+ } else if (CurrentRequest->RequestType == NdisRequestOpen) {
+
+ if (AbortOpens) {
+
+ //
+ // Complete the open
+ //
+
+ TmpOpen = Reserved->OpenBlock;
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteOpenAdapter(
+ TmpOpen->NdisBindingContext,
+ NDIS_STATUS_FAILURE,
+ 0);
+
+ ELNK_FREE_PHYS(TmpOpen);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ //
+ // Remove it from the list
+ //
+
+ *CurrentNextLocation = Reserved->Next;
+
+ } else {
+
+ //
+ // Skip the open
+ //
+
+ CurrentNextLocation = &(Reserved->Next);
+
+ }
+
+ } else {
+
+ //
+ // Not a close, remove it from the list and
+ // fail it.
+ //
+
+ *CurrentNextLocation = Reserved->Next;
+ TmpOpen = Reserved->OpenBlock;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteRequest(
+ TmpOpen->NdisBindingContext,
+ CurrentRequest,
+ NDIS_STATUS_REQUEST_ABORTED
+ );
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ TmpOpen->References--;
+
+ }
+
+ CurrentRequest = *CurrentNextLocation;
+
+ }
+
+ }
+}
+
+STATIC
+VOID
+SetupForReset(
+ IN PELNK_ADAPTER Adapter,
+ IN PELNK_OPEN Open
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to fill in the who and why a reset is
+ being set up as well as setting the appropriate fields in the
+ adapter.
+
+ NOTE: This routine must be called with the lock acquired.
+
+Arguments:
+
+ Adapter - The adapter whose hardware is to be initialized.
+
+ Open - A (possibly NULL) pointer to an Elnk open structure.
+ The reason it could be null is if the adapter is initiating the
+ reset on its own.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ BOOLEAN Cancelled;
+
+ //
+ // Stop our deadman timer
+ //
+
+ NdisCancelTimer(&Adapter->DeadmanTimer, &Cancelled);
+
+ //
+ // Shut down the chip. We won't be doing any more work until
+ // the reset is complete.
+ //
+
+ ElnkStopChip(Adapter);
+
+ //
+ // We need to signal every open binding that the
+ // reset has started. We increment the reference
+ // count on the open binding while we're doing indications
+ // so that the open can't be deleted out from under
+ // us while we're indicating (recall that we can't own
+ // the lock during the indication).
+ //
+
+ Adapter->CurrentCsr = CSR_DEFAULT;
+
+ {
+
+ PELNK_OPEN Open;
+ PLIST_ENTRY CurrentLink;
+
+ CurrentLink = Adapter->OpenBindings.Flink;
+
+ while (CurrentLink != &Adapter->OpenBindings) {
+
+ Open = CONTAINING_RECORD(
+ CurrentLink,
+ ELNK_OPEN,
+ OpenList
+ );
+
+ Open->References++;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisIndicateStatus(
+ Open->NdisBindingContext,
+ NDIS_STATUS_RESET_START,
+ NULL,
+ 0
+ );
+
+ NdisIndicateStatusComplete(Open->NdisBindingContext);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ Open->References--;
+
+ CurrentLink = CurrentLink->Flink;
+
+ }
+
+ }
+
+ Adapter->ResetInProgress = TRUE;
+
+ //
+ // Shut down all of the transmit queues so that the
+ // transmit portion of the chip will eventually calm down.
+ //
+
+ Adapter->StageOpen = FALSE;
+
+ ElnkAbortPendingQueue(Adapter, FALSE);
+
+ Adapter->ResettingOpen = Open;
+
+ //
+ // If there is a valid open we should up the reference count
+ // so that the open can't be deleted before we indicate that
+ // their request is finished.
+ //
+
+ if (Open) {
+
+ Open->References++;
+
+ }
+
+}
+
+
+VOID
+ElnkGetStationAddress(
+ IN PELNK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine gets the network address from the hardware.
+
+Arguments:
+
+ Adapter - Where to store the network address.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+#if !ELNKMC
+ //
+ // Select card address
+ //
+
+ ELNK_WRITE_UCHAR(
+ Adapter,
+ ELNK_CSR,
+ 0x01
+ );
+#endif
+
+ ELNK_READ_UCHAR(
+ Adapter,
+ ELNK_STATION_ID,
+ &Adapter->NetworkAddress[0]
+ );
+
+ ELNK_READ_UCHAR(
+ Adapter,
+ ELNK_STATION_ID + 1,
+ &Adapter->NetworkAddress[1]
+ );
+
+ ELNK_READ_UCHAR(
+ Adapter,
+ ELNK_STATION_ID + 2 ,
+ &Adapter->NetworkAddress[2]
+ );
+ ELNK_READ_UCHAR(
+ Adapter,
+ ELNK_STATION_ID + 3,
+ &Adapter->NetworkAddress[3]
+ );
+ ELNK_READ_UCHAR(
+ Adapter,
+ ELNK_STATION_ID + 4,
+ &Adapter->NetworkAddress[4]
+ );
+ ELNK_READ_UCHAR(
+ Adapter,
+ ELNK_STATION_ID + 5,
+ &Adapter->NetworkAddress[5]
+ );
+
+ if ELNKDEBUG {
+ UINT i;
+ for (i=0;i<6;i++) {
+ DPrint2("%x-",(UCHAR)Adapter->NetworkAddress[i]);
+ }
+ DPrint1("\n");
+ }
+
+ //
+ // if no new address is specified, use the BIA
+ //
+
+ if (!Adapter->AddressChanged) {
+
+ ETH_COPY_NETWORK_ADDRESS(
+ Adapter->CurrentAddress,
+ Adapter->NetworkAddress
+ );
+
+ }
+}
+
+#pragma NDIS_INIT_FUNCTION(ElnkInitialInit)
+
+
+BOOLEAN
+ElnkInitialInit(
+ IN PELNK_ADAPTER Adapter,
+ IN UINT ElnkInterruptVector
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets up the initial init of the driver.
+
+Arguments:
+
+ Adapter - The adapter for the hardware.
+
+ ElnkInterruptVector - Interrupt number used by the card.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS Status;
+
+ //
+ // stop the chip
+ //
+
+ ElnkStopChip(Adapter);
+
+ NdisInitializeInterrupt(
+ &Status,
+ &Adapter->Interrupt,
+ Adapter->NdisAdapterHandle,
+ ElnkIsr,
+ Adapter,
+ ElnkStandardInterruptDpc,
+ ElnkInterruptVector,
+ ElnkInterruptVector,
+ FALSE,
+#if ELNKMC
+ (NdisInterruptLevelSensitive)
+#else
+ (NdisInterruptLatched)
+#endif
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ if (!SetConfigurationBlockAndInit(Adapter)) {
+
+ if ELNKDEBUG DPrint1("Error configurating block and initializing...\n");
+ ElnkLogError(
+ Adapter,
+ initialInit,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 0
+ );
+ NdisRemoveInterrupt(&Adapter->Interrupt);
+ return FALSE;
+
+ }
+
+
+ } else {
+
+ if ELNKDEBUG DPrint1("Elnk: Unsuccessful connect to interrupt\n");
+ ElnkLogError(
+ Adapter,
+ initialInit,
+ NDIS_ERROR_CODE_INTERRUPT_CONNECT,
+ (ULONG) ElnkInterruptVector
+ );
+ return(FALSE);
+
+ }
+
+ return(TRUE);
+
+}
+
+
+STATIC
+VOID
+SetupSharedMemory(
+ IN PELNK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes and organizes the
+
+ - Command List
+
+ - Receive Frame Area
+
+Arguments:
+
+ Adapter - The adapter to allocate memory for.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ //
+ // Pointer to a Receive Entry. Used while initializing
+ // the Receive Queue.
+ //
+ PRECEIVE_FRAME_DESCRIPTOR CurrentReceiveEntry;
+
+ //
+ // Pointer to a Command Block. Used while initializing
+ // the Command Queue.
+ //
+ PTRANSMIT_CB CurrentCommandBlock;
+
+ //
+ // for loop variables
+ //
+ UINT i;
+
+ if ELNKDEBUG DPrint1("Allocating Command Blocks\n");
+
+ //
+ // Put the Command Blocks into a known state.
+ //
+
+ for(
+ i = 0, CurrentCommandBlock = Adapter->TransmitQueue;
+ i < Adapter->NumberOfTransmitBuffers;
+ i++
+ ) {
+
+ NdisZeroMappedMemory(
+ (PUCHAR)CurrentCommandBlock,
+ sizeof(TRANSMIT_CB)
+ );
+
+ Adapter->TransmitInfo[i].NextCommand = ELNK_EMPTY;
+ Adapter->TransmitInfo[i].OwningPacket = NULL;
+ Adapter->TransmitInfo[i].OwningOpenBinding = NULL;
+
+ Adapter->TransmitInfo[i].CommandBlock = CurrentCommandBlock;
+ Adapter->TransmitInfo[i].CbOffset = ELNK_GET_CARD_ADDRESS(
+ Adapter,
+ CurrentCommandBlock
+ );
+
+ Adapter->TransmitInfo[i].Buffer = CurrentCommandBlock + 1;
+
+ Adapter->TransmitInfo[i].BufferOffset = ELNK_GET_CARD_ADDRESS(
+ Adapter,
+ Adapter->TransmitInfo[i].Buffer
+ );
+
+ ASSERT(Adapter->TransmitInfo[i].BufferOffset ==
+ (Adapter->TransmitInfo[i].CbOffset + sizeof(TRANSMIT_CB))
+ );
+
+ NdisWriteRegisterUshort(
+ &CurrentCommandBlock->TbdOffset,
+ ELNK_GET_CARD_ADDRESS(Adapter, &CurrentCommandBlock->Tbd)
+ );
+
+
+ //
+ // ELNK_NULL is non-zero
+ //
+
+ NdisWriteRegisterUshort(
+ &CurrentCommandBlock->NextCbOffset,
+ ELNK_NULL
+ );
+
+ NdisWriteRegisterUshort(
+ &CurrentCommandBlock->Tbd.NextTbdOffset,
+ ELNK_NULL
+ );
+
+ NdisWriteRegisterUlong(
+ &CurrentCommandBlock->Tbd.BufferOffset,
+ Adapter->TransmitInfo[i].BufferOffset
+ );
+
+ if ELNKDEBUG DPrint4("cb address = %x offset = %x buff = %x\n",
+ CurrentCommandBlock,
+ Adapter->TransmitInfo[i].CbOffset,
+ Adapter->TransmitInfo[i].BufferOffset
+ );
+
+
+ CurrentCommandBlock = (PTRANSMIT_CB)((PUCHAR)Adapter->TransmitInfo[i].Buffer +
+ ELNK_OFFSET_TO_NEXT_BUFFER);
+
+ }
+
+
+ //
+ // The multicast transmitinfo is the nth + 1 where n is the number
+ // of transmit buffers.
+ //
+
+ //
+ // Fill in the multicast Block
+ //
+
+ NdisZeroMappedMemory(
+ (PUCHAR)Adapter->MulticastBlock,
+ sizeof(NON_TRANSMIT_CB)
+ );
+
+ Adapter->TransmitInfo[Adapter->NumberOfTransmitBuffers].NextCommand =
+ ELNK_EMPTY;
+ Adapter->TransmitInfo[Adapter->NumberOfTransmitBuffers].OwningPacket = NULL;
+ Adapter->TransmitInfo[Adapter->NumberOfTransmitBuffers].OwningOpenBinding = NULL;
+
+ Adapter->TransmitInfo[Adapter->NumberOfTransmitBuffers].CommandBlock =
+ (PTRANSMIT_CB) Adapter->MulticastBlock;
+
+ Adapter->TransmitInfo[Adapter->NumberOfTransmitBuffers].CbOffset = OFFSET_MULTICAST;
+
+ Adapter->TransmitInfo[Adapter->NumberOfTransmitBuffers].Buffer = NULL;
+
+ Adapter->TransmitInfo[Adapter->NumberOfTransmitBuffers].BufferOffset = ELNK_NULL;
+
+ NdisWriteRegisterUshort(
+ &Adapter->MulticastBlock->NextCbOffset,
+ ELNK_NULL
+ );
+
+ if ELNKDEBUG DPrint1("Allocating receive buffers\n");
+
+ //
+ // Allocate the receive buffers and attach them to the Receive
+ // Queue entries.
+ //
+
+ for(
+ i = 0, CurrentReceiveEntry = (PRECEIVE_FRAME_DESCRIPTOR) Adapter->ReceiveQueue;
+ i < Adapter->NumberOfReceiveBuffers;
+ i++
+ ) {
+
+ NdisZeroMemory(
+ &Adapter->ReceiveInfo[i],
+ sizeof(ELNK_RECEIVE_INFO)
+ );
+
+ NdisZeroMappedMemory(
+ (PUCHAR)CurrentReceiveEntry,
+ sizeof(RECEIVE_FRAME_DESCRIPTOR)
+ );
+
+
+ if ELNKDEBUG DPrint2("Rfd = %x",CurrentReceiveEntry);
+
+ Adapter->ReceiveInfo[i].Rfd = CurrentReceiveEntry;
+ Adapter->ReceiveInfo[i].RfdOffset = ELNK_GET_CARD_ADDRESS(
+ Adapter,
+ CurrentReceiveEntry
+ );
+
+ if ELNKDEBUG DPrint2(" Offset = %x",Adapter->ReceiveInfo[i].RfdOffset);
+
+ NdisWriteRegisterUshort(
+ &Adapter->ReceiveInfo[i].Rfd->RbdOffset,
+ ELNK_GET_CARD_ADDRESS(Adapter,&CurrentReceiveEntry->Rbd)
+ );
+
+ Adapter->ReceiveInfo[i].NextRfdIndex =
+ (i+1) % Adapter->NumberOfReceiveBuffers;
+ Adapter->ReceiveInfo[i].Buffer = CurrentReceiveEntry + 1;
+
+ Adapter->ReceiveInfo[i].BufferOffset = ELNK_GET_CARD_ADDRESS(
+ Adapter,
+ Adapter->ReceiveInfo[i].Buffer
+ );
+
+ if ELNKDEBUG DPrint2(" Buffer Offset = %x\n",Adapter->ReceiveInfo[i].BufferOffset);
+
+ CurrentReceiveEntry = (PRECEIVE_FRAME_DESCRIPTOR)
+ ((PUCHAR) Adapter->ReceiveInfo[i].Buffer +
+ ELNK_OFFSET_TO_NEXT_BUFFER);
+
+ }
+
+ if ELNKDEBUG DPrint1("initializing links\n");
+
+ for(
+ i = 0;
+ i < Adapter->NumberOfReceiveBuffers;
+ i++
+ ) {
+
+ UINT Next = Adapter->ReceiveInfo[i].NextRfdIndex;
+
+ //
+ // Fill the Receive Buffer Descriptor
+ //
+
+ CurrentReceiveEntry = Adapter->ReceiveInfo[i].Rfd;
+
+ NdisWriteRegisterUlong(
+ &CurrentReceiveEntry->Rbd.BufferOffset,
+ Adapter->ReceiveInfo[i].BufferOffset
+ );
+
+ NdisWriteRegisterUshort(
+ &CurrentReceiveEntry->Rbd.Size,
+ (USHORT) (MAXIMUM_ETHERNET_PACKET_SIZE | RBD_END_OF_LIST)
+ );
+
+ NdisWriteRegisterUshort(
+ &CurrentReceiveEntry->Rbd.Status,
+ (USHORT) 0
+ );
+
+#if 0
+
+ NdisWriteRegisterUshort(
+ &CurrentReceiveEntry->Rbd.NextRbdOffset,
+ Adapter->ReceiveInfo[Next].Rfd->RbdOffset
+ );
+
+#endif
+
+ NdisWriteRegisterUshort(
+ &CurrentReceiveEntry->Rbd.NextRbdOffset,
+ ELNK_NULL
+ );
+
+ //
+ // Fill the Receive Frame Descriptor
+ //
+
+ NdisWriteRegisterUshort(
+ &CurrentReceiveEntry->NextRfdOffset,
+ Adapter->ReceiveInfo[Next].RfdOffset
+ );
+ }
+
+ //
+ // initialize the last descriptor
+ //
+
+ NdisWriteRegisterUshort(
+ &CurrentReceiveEntry->Command,
+ RFD_COMMAND_END_OF_LIST | RFD_COMMAND_SUSPEND
+ );
+
+#if 0
+ NdisWriteRegisterUshort(
+ &CurrentReceiveEntry->Rbd.Size,
+ (USHORT) MAXIMUM_ETHERNET_PACKET_SIZE | RBD_END_OF_LIST
+ );
+#endif
+
+ //
+ // reset pointers
+ //
+
+ Adapter->ReceiveHead = 0;
+ Adapter->ReceiveTail = Adapter->NumberOfReceiveBuffers - 1;
+}
+
+
+#if !ELNKMC
+
+BOOLEAN AlreadyGeneratedPattern = FALSE;
+
+#pragma NDIS_INIT_FUNCTION(Elnk16ConfigureAdapter)
+
+BOOLEAN
+Elnk16ConfigureAdapter(
+ IN PELNK_ADAPTER Adapter,
+ IN BOOLEAN IsExternal,
+ IN BOOLEAN ZwsEnabled
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to setup the card registers for the correct
+ configuration
+
+Arguments:
+
+ Adapter - adapter to configure.
+ IsExternal - are we using External transceiver?
+ ZwsEnabled - should zero wait state be enabled?
+
+Return Value:
+
+ Returns true if configuration was done.
+
+--*/
+{
+ if (!AlreadyGeneratedPattern) {
+
+ //
+ // Initialize State
+ //
+
+ NdisWritePortUchar(
+ Adapter->NdisAdapterHandle,
+ ELNK16_ID_PORT,
+ 0x00
+ );
+
+ Elnk16GenerateIdPattern(Adapter);
+
+ //
+ // Go to run state
+ //
+
+ NdisWritePortUchar(
+ Adapter->NdisAdapterHandle,
+ ELNK16_ID_PORT,
+ 0x00
+ );
+
+ AlreadyGeneratedPattern = TRUE;
+
+ }
+
+#if 0
+
+ //
+ // Go to reset state
+ //
+
+ Elnk16GenerateIdPattern(Adapter);
+
+ //
+ // Go to IoLoad state
+ //
+
+ Elnk16GenerateIdPattern(Adapter);
+
+ //
+ // Set I/O base address
+ //
+
+ {
+ USHORT IdPort;
+ IdPort = (USHORT) (Adapter->IoBase - 0x200);
+ if (IdPort > 0) {
+
+ IdPort = IdPort >> 4 ;
+ }
+ NdisWritePortUchar(
+ Adapter->NdisAdapterHandle,
+ ELNK16_ID_PORT,
+ (UCHAR)IdPort
+ );
+
+ }
+
+#endif
+
+ //
+ // Now in the configuration state
+ //
+
+ //
+ // Check if we have a card present...
+ //
+
+ {
+ UCHAR Port1;
+ UCHAR Port2;
+ UCHAR Port3;
+ UCHAR Port4;
+ UCHAR Port5;
+ UCHAR Port6;
+
+ //
+ // Select 3Com signature. We should get *3COM* in ascii
+ //
+
+ ELNK_WRITE_UCHAR(Adapter, ELNK_CSR, 0x00);
+
+ ELNK_READ_UCHAR(Adapter, ELNK16_3COM, &Port1);
+ ELNK_READ_UCHAR(Adapter, ELNK16_3COM + 1, &Port2);
+ ELNK_READ_UCHAR(Adapter, ELNK16_3COM + 2, &Port3);
+ ELNK_READ_UCHAR(Adapter, ELNK16_3COM + 3, &Port4);
+ ELNK_READ_UCHAR(Adapter, ELNK16_3COM + 4, &Port5);
+ ELNK_READ_UCHAR(Adapter, ELNK16_3COM + 5, &Port6);
+
+ if (!((Port1 == '*') &&
+ (Port2 == '3') &&
+ (Port3 == 'C') &&
+ (Port4 == 'O') &&
+ (Port5 == 'M') &&
+ (Port6 == '*'))) {
+
+ return(FALSE);
+
+ }
+
+ }
+
+
+#if NDIS_NT
+
+ switch (Adapter->SharedRamSize) {
+ case 16:
+ Adapter->CardOffset = 0xC000;
+ Adapter->NumberOfTransmitBuffers = ELNK16_16K_TRANSMITS;
+ Adapter->NumberOfReceiveBuffers = ELNK16_16K_RECEIVES;
+ break;
+ case 32:
+ Adapter->CardOffset = 0x8000;
+ Adapter->NumberOfTransmitBuffers = ELNK16_32K_TRANSMITS;
+ Adapter->NumberOfReceiveBuffers = ELNK16_32K_RECEIVES;
+ break;
+ case 48:
+ Adapter->CardOffset = 0x4000;
+ Adapter->NumberOfTransmitBuffers = ELNK16_48K_TRANSMITS;
+ Adapter->NumberOfReceiveBuffers = ELNK16_48K_RECEIVES;
+ break;
+ case 64:
+ Adapter->CardOffset = 0;
+ Adapter->NumberOfTransmitBuffers = ELNK16_64K_TRANSMITS;
+ Adapter->NumberOfReceiveBuffers = ELNK16_64K_RECEIVES;
+ break;
+ }
+
+ //
+ // Save transceiver type
+ //
+
+ Adapter->IsExternal = IsExternal;
+
+
+
+
+#if 0
+
+ //
+ // Set Transceiver type
+ //
+
+ {
+ UCHAR PortValue;
+ if (IsExternal) {
+ PortValue = 0x00;
+ } else {
+ PortValue = 0x80;
+ }
+
+ ELNK_WRITE_UCHAR(Adapter, ELNK16_ROM_CONFIG, PortValue);
+
+ }
+
+ //
+ // Set window base address
+ //
+
+ {
+ UCHAR PortValue;
+ switch (Adapter->SharedRamPhys) {
+ case 0xC0000:
+ PortValue = 0;
+ break;
+ case 0xC8000:
+ PortValue = 0x08;
+ break;
+ case 0xD0000:
+ PortValue = 0x10;
+ break;
+ case 0xD8000:
+ PortValue = 0x18;
+ break;
+ }
+
+
+
+ //
+ // Set ZWS value
+ //
+
+ if (ZwsEnabled) {
+ PortValue |= 0x80;
+ }
+
+ ELNK_WRITE_UCHAR(Adapter, ELNK16_RAM_CONFIG, PortValue);
+
+ }
+
+ //
+ // Set interrupt number
+ //
+
+ ELNK_WRITE_UCHAR(Adapter, ELNK16_ICR, (UCHAR)Adapter->InterruptVector);
+
+ //
+ // Go to the run state
+ //
+
+ Elnk16GenerateIdPattern(Adapter);
+
+#endif
+
+#endif NDIS_NT
+
+#if NDIS_WIN
+{
+ UCHAR Temp;
+ // Transceiver type
+ ELNK_READ_UCHAR(Adapter, ELNK16_ROM_CONFIG, &Temp);
+ Adapter->IsExternal = (Temp & ROMCR_BNC) ? 0 : 1;
+ DPrint2("Temp = %x ",Temp);
+ DPrint2("Adapter->IsExternal = %x\n",Adapter->IsExternal);
+
+ // Interrupt number
+ ELNK_READ_UCHAR(Adapter, ELNK16_ICR, &Temp);
+ Adapter->InterruptVector = (UINT)(Temp & 0x0F);
+ DPrint2("Temp = %x ",Temp);
+ DPrint2("Adapter->InterruptVector = %x\n",Adapter->InterruptVector);
+
+ // MM Base & Size
+ ELNK_READ_UCHAR(Adapter, ELNK16_RAM_CONFIG, &Temp);
+ if (Temp & 0x20) {
+ Adapter->SharedRamSize = 64;
+ switch (Temp & 0x0F) {
+ case 0x00:
+ Adapter->SharedRamPhys = 0xF00000;
+ break;
+ case 0x01:
+ Adapter->SharedRamPhys = 0xF20000;
+ break;
+ case 0x02:
+ Adapter->SharedRamPhys = 0xF40000;
+ break;
+ case 0x03:
+ Adapter->SharedRamPhys = 0xF60000;
+ break;
+ default:
+ Adapter->SharedRamPhys = 0xF80000;
+ break;
+ }
+ } else {
+
+ switch (Temp & 0x03) {
+ case 0x00:
+ Adapter->SharedRamSize = 16;
+ break;
+ case 0x01:
+ Adapter->SharedRamSize = 32;
+ break;
+ case 0x02:
+ Adapter->SharedRamSize = 48;
+ break;
+ default:
+ Adapter->SharedRamSize = 64;
+ break;
+ }
+
+ switch (Temp & 0x18) {
+ case 0x00:
+ Adapter->SharedRamPhys = 0x0C0000;
+ break;
+ case 0x08:
+ Adapter->SharedRamPhys = 0x0C8000;
+ break;
+ case 0x10:
+ Adapter->SharedRamPhys = 0x0D0000;
+ break;
+ default:
+ Adapter->SharedRamPhys = 0x0D8000;
+ break;
+ }
+
+ }
+
+ switch (Adapter->SharedRamSize) {
+ case 16:
+ Adapter->CardOffset = 0xC000;
+ Adapter->NumberOfTransmitBuffers = ELNK16_16K_TRANSMITS;
+ Adapter->NumberOfReceiveBuffers = ELNK16_16K_RECEIVES;
+ break;
+ case 32:
+ Adapter->CardOffset = 0x8000;
+ Adapter->NumberOfTransmitBuffers = ELNK16_32K_TRANSMITS;
+ Adapter->NumberOfReceiveBuffers = ELNK16_32K_RECEIVES;
+ break;
+ case 48:
+ Adapter->CardOffset = 0x4000;
+ Adapter->NumberOfTransmitBuffers = ELNK16_48K_TRANSMITS;
+ Adapter->NumberOfReceiveBuffers = ELNK16_48K_RECEIVES;
+ break;
+ case 64:
+ Adapter->CardOffset = 0;
+ Adapter->NumberOfTransmitBuffers = ELNK16_64K_TRANSMITS;
+ Adapter->NumberOfReceiveBuffers = ELNK16_64K_RECEIVES;
+ break;
+ }
+
+ DPrint2("Temp = %x ",Temp);
+ DPrint2("Adapter->SharedRamSize = %x\n",Adapter->SharedRamSize);
+ DPrint2("Adapter->SharedRamPhys = %x\n",Adapter->SharedRamPhys);
+ DPrint2("Adapter->CardOffset = %x\n",Adapter->CardOffset);
+ DPrint2("Adapter->NumberOfTransmitBuffers = %x\n",Adapter->NumberOfTransmitBuffers);
+ DPrint2("Adapter->NumberOfReceiveBuffers = %x\n",Adapter->NumberOfReceiveBuffers);
+
+ // ZWS not needed
+}
+#endif // NDIS_WIN
+
+ return(TRUE);
+}
+
+VOID
+Elnk16GenerateIdPattern(
+ IN PELNK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will write the ID pattern to port 0x100h.
+
+Arguments:
+
+ Adapter - Context of the adapter
+
+Return Value:
+ None.
+
+--*/
+
+{
+
+ UCHAR Value;
+ UINT i;
+
+ Value = 0xff;
+ Adapter;
+
+ for (i = 0 ; i < 255 ; i++) {
+
+ NdisWritePortUchar(
+ Adapter->NdisAdapterHandle,
+ ELNK16_ID_PORT,
+ Value
+ );
+
+ if (Value & 0x80) {
+
+ Value = (UCHAR) (Value << 1);
+ Value ^= 0xe7;
+
+ } else {
+
+ Value = (UCHAR) (Value << 1);
+
+ }
+
+ }
+
+ return;
+}
+
+#endif // !ELNKMC
+
+
diff --git a/private/ntos/ndis/elnkmc/send.c b/private/ntos/ndis/elnkmc/send.c
new file mode 100644
index 000000000..d0e32d3e5
--- /dev/null
+++ b/private/ntos/ndis/elnkmc/send.c
@@ -0,0 +1,340 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ send.c
+
+Abstract:
+
+ This file contains the code for putting a packet through the
+ staged allocation for transmission.
+
+ This is a process of
+
+ 1) Calculating the what would need to be done to the
+ packet so that the packet can be transmitted on the hardware.
+
+ 2) Potentially allocating adapter buffers and copying user data
+ to those buffers so that the packet data is transmitted under
+ the hardware constraints.
+
+ 3) Allocating enough hardware ring entries so that the packet
+ can be transmitted.
+
+ 4) Relinquish those ring entries to the hardware.
+
+Author:
+
+ Johnson R. Apacible (JohnsonA) 9-June-1991
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+--*/
+
+#include <ndis.h>
+
+//
+// So we can trace things...
+//
+#define STATIC
+
+#include <efilter.h>
+#include <elnkhw.h>
+#include <elnksw.h>
+
+
+NDIS_STATUS
+ElnkSend(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ The ElnkSend request instructs a MAC to transmit a packet through
+ the adapter onto the medium.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to ELNK_OPEN.
+
+ Packet - A pointer to a descriptor for the packet that is to be
+ transmitted.
+
+Return Value:
+ The function value is the status of the operation.
+--*/
+
+{
+
+ //
+ // Holds the status that should be returned to the caller.
+ //
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_PENDING;
+
+ //
+ // Pointer to the adapter.
+ //
+ PELNK_ADAPTER Adapter;
+
+ if ELNKDEBUG DPrint2("ElnkSend Packet = %x\n",Packet);
+
+ Adapter = PELNK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ if (!Adapter->ResetInProgress) {
+
+ PELNK_OPEN Open;
+
+ Open = PELNK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ if (!Open->BindingShuttingDown) {
+
+ UINT TotalPacketSize;
+
+ //
+ // Increment the references on the open while we are
+ // accessing it in the interface.
+ //
+
+ Open->References++;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ //
+ // It is reasonable to do a quick check and fail if the packet
+ // is larger than the maximum an ethernet can handle.
+ //
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ NULL,
+ NULL,
+ &TotalPacketSize
+ );
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ if ((!TotalPacketSize) ||
+ (TotalPacketSize > MAXIMUM_ETHERNET_PACKET_SIZE)) {
+ Open->References--;
+ StatusToReturn = NDIS_STATUS_RESOURCES;
+
+ } else {
+
+ PELNK_RESERVED Reserved = PELNK_RESERVED_FROM_PACKET(Packet);
+ PNDIS_BUFFER FirstBuffer;
+ PUCHAR BufferVA;
+ UINT Length;
+
+ //
+ // Set Reserved->Loopback.
+ //
+
+ NdisQueryPacket(Packet, NULL, NULL, &FirstBuffer, NULL);
+
+ //
+ // Get VA of first buffer
+ //
+
+ NdisQueryBuffer(
+ FirstBuffer,
+ (PVOID *)&BufferVA,
+ &Length
+ );
+
+ if (Open->ProtOptionFlags & NDIS_PROT_OPTION_NO_LOOPBACK){
+ Reserved->Loopback = FALSE;
+ } else {
+ Reserved->Loopback = EthShouldAddressLoopBack(Adapter->FilterDB, BufferVA);
+ }
+
+ Reserved->MacBindingHandle = MacBindingHandle;
+
+ //
+ // Put on the stage queue.
+ //
+
+ if (!Adapter->LastStagePacket) {
+
+ Adapter->FirstStagePacket = Packet;
+
+ } else {
+
+ PELNK_RESERVED_FROM_PACKET(Adapter->LastStagePacket)->Next = Packet;
+
+ }
+
+ Adapter->LastStagePacket = Packet;
+
+ Reserved->Next = NULL;
+
+ Adapter->TransmitsQueued++;
+
+ //
+ // Only try to push it through the stage queues
+ // if somebody else isn't already doing it and
+ // there is some hope of moving some packets
+ // ahead.
+ //
+
+ while (!Adapter->AlreadyProcessingStage &&
+ Adapter->FirstStagePacket &&
+ Adapter->StageOpen
+ ) {
+
+ ElnkStagedAllocation(Adapter);
+
+ }
+
+ }
+
+ //
+ // We leave the reference for the pending send.
+ //
+
+ } else {
+
+ StatusToReturn = NDIS_STATUS_CLOSING;
+
+ }
+
+ } else {
+
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ }
+
+ ELNK_DO_DEFERRED(Adapter);
+ return StatusToReturn;
+}
+
+VOID
+ElnkStagedAllocation(
+ IN PELNK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine attempts to take a packet through a stage of allocation.
+
+Arguments:
+
+ Adapter - The adapter that the packets are coming through.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UINT CbIndex;
+
+ PNDIS_PACKET FirstPacket = Adapter->FirstStagePacket;
+
+ if ELNKDEBUG DPrint1("StagedAllocation\n");
+ //
+ // For each stage, we check to see that it is open,
+ // that somebody else isn't already processing,
+ // and that there is some work from the previous
+ // stage to do.
+ //
+
+ ASSERT (Adapter->StageOpen &&
+ !Adapter->AlreadyProcessingStage &&
+ Adapter->FirstStagePacket);
+
+ //
+ // If we successfully acquire a command block, this
+ // is the index to it.
+ //
+
+ Adapter->AlreadyProcessingStage = TRUE;
+
+ //
+ // We look to see if there is an available Command Block.
+ // If there isn't then stage 2 will close.
+ //
+
+ IF_LOG('p');
+
+ if (ElnkAcquireCommandBlock(
+ Adapter,
+ &CbIndex
+ )) {
+
+ IF_LOG('a');
+
+ //
+ // Remove from queue
+ //
+
+ Adapter->FirstStagePacket = PELNK_RESERVED_FROM_PACKET(FirstPacket)->Next;
+
+ if (!Adapter->FirstStagePacket) {
+
+ Adapter->LastStagePacket = NULL;
+
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ //
+ // We have a command block. Assign all packet
+ // buffers to the command block.
+ //
+
+ ElnkAssignPacketToCommandBlock(
+ Adapter,
+ FirstPacket,
+ CbIndex
+ );
+
+ //
+ // We need exclusive access to the Command Queue so
+ // that we can move this packet on to the next stage.
+ //
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ ElnkPutPacketOnFinishTrans(
+ Adapter,
+ FirstPacket
+ );
+
+ ElnkSubmitCommandBlock(
+ Adapter,
+ CbIndex
+ );
+
+ Adapter->AlreadyProcessingStage = FALSE;
+
+ } else {
+
+ Adapter->AlreadyProcessingStage = FALSE;
+ Adapter->StageOpen = FALSE;
+
+ IF_LOG('P');
+
+ return;
+
+ }
+
+ IF_LOG('P');
+
+}
+
diff --git a/private/ntos/ndis/elnkmc/sources b/private/ntos/ndis/elnkmc/sources
new file mode 100644
index 000000000..3dc8e88c4
--- /dev/null
+++ b/private/ntos/ndis/elnkmc/sources
@@ -0,0 +1,50 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=elnkmc
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+INCLUDES=..\..\inc;..\..\..\inc
+
+SOURCES=elnk.c \
+ reset.c \
+ request.c \
+ send.c \
+ packet.c \
+ transfer.c \
+ loopback.c \
+ command.c \
+ interrup.c \
+ elnkmc.rc
+
+RELATIVE_DEPTH=..\..
+
+MSC_WARNING_LEVEL=/W3 /WX
+
diff --git a/private/ntos/ndis/elnkmc/switch.h b/private/ntos/ndis/elnkmc/switch.h
new file mode 100644
index 000000000..4bb715ab9
--- /dev/null
+++ b/private/ntos/ndis/elnkmc/switch.h
@@ -0,0 +1,39 @@
+
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ switch.h
+
+Abstract:
+
+ determines whether we are building the Elnkmc or the Elnk16.
+
+Author:
+
+ Johnson R. Apacible (JohnsonA) 9-June-1991
+
+Environment:
+
+ This driver is expected to work in DOS and NT at the equivalent
+ of kernel mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+
+--*/
+
+#ifndef _ELNKSWITCH_
+#define _ELNKSWITCH_
+#define ELNKMC 1
+#endif // _ELNKSWITCH
+
diff --git a/private/ntos/ndis/elnkmc/transfer.c b/private/ntos/ndis/elnkmc/transfer.c
new file mode 100644
index 000000000..ee7cb7524
--- /dev/null
+++ b/private/ntos/ndis/elnkmc/transfer.c
@@ -0,0 +1,167 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ transfer.c
+
+Abstract:
+
+ This file contains the code to implement the MacTransferData
+ API for the ndis 3.0 interface.
+
+Author:
+
+ Johnson R. Apacible (JohnsonA) 10-Jul-1991
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+
+//
+// So we can trace things...
+//
+#define STATIC
+
+#include <efilter.h>
+#include <elnkhw.h>
+#include <elnksw.h>
+
+
+NDIS_STATUS
+ElnkTransferData(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ )
+
+/*++
+
+Routine Description:
+
+ A protocol calls the ElnkTransferData request (indirectly via
+ NdisTransferData) from within its Receive event handler
+ to instruct the MAC to copy the contents of the received packet
+ a specified paqcket buffer.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality this is a pointer to ELNK_OPEN.
+
+ MacReceiveContext - The context value passed by the MAC on its call
+ to NdisIndicateReceive. The MAC can use this value to determine
+ which packet, on which adapter, is being received.
+
+ ByteOffset - An unsigned integer specifying the offset within the
+ received packet at which the copy is to begin. If the entire packet
+ is to be copied, ByteOffset must be zero.
+
+ BytesToTransfer - An unsigned integer specifying the number of bytes
+ to copy. It is legal to transfer zero bytes; this has no effect. If
+ the sum of ByteOffset and BytesToTransfer is greater than the size
+ of the received packet, then the remainder of the packet (starting from
+ ByteOffset) is transferred, and the trailing portion of the receive
+ buffer is not modified.
+
+ Packet - A pointer to a descriptor for the packet storage into which
+ the MAC is to copy the received packet.
+
+ BytesTransfered - A pointer to an unsigned integer. The MAC writes
+ the actual number of bytes transferred into this location. This value
+ is not valid if the return status is STATUS_PENDING.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+
+{
+
+ PELNK_ADAPTER Adapter;
+
+ NDIS_STATUS StatusToReturn;
+
+ Adapter = PELNK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ if (!Adapter->ResetInProgress) {
+
+ PELNK_OPEN Open = PELNK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ if (!Open->BindingShuttingDown) {
+
+ Open->References++;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ //
+ // The MacReceive context can be either of two things.
+ //
+ // If the low bit is != 1 then it is a pointer to the users
+ // ndis packet. It would typically be the packet when the
+ // packet has been delivered via loopback.
+ //
+ // If the value has a 1 in the low bit, then it is a pointer
+ // to a receive buffer. Bit 0 must be masked-out before this
+ // pointer can be used.
+ //
+
+ if (!((UINT)MacReceiveContext & 1)) {
+
+ NdisCopyFromPacketToPacket(
+ Packet,
+ 0,
+ BytesToTransfer,
+ (PNDIS_PACKET)((PVOID)MacReceiveContext),
+ ByteOffset + ELNK_HEADER_SIZE,
+ BytesTransferred
+ );
+
+ } else {
+
+
+ ElnkCopyFromBufferToPacket(
+ (PCHAR)((ULONG)MacReceiveContext & ~1L) + ByteOffset,
+ BytesToTransfer,
+ Packet,
+ 0,
+ BytesTransferred
+ );
+
+ }
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Open->References--;
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ } else {
+
+ StatusToReturn = NDIS_STATUS_REQUEST_ABORTED;
+
+ }
+
+ } else {
+
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ }
+
+ ELNK_DO_DEFERRED(Adapter);
+ return StatusToReturn;
+}
diff --git a/private/ntos/ndis/htdsu/card.c b/private/ntos/ndis/htdsu/card.c
new file mode 100644
index 000000000..eb62fba71
--- /dev/null
+++ b/private/ntos/ndis/htdsu/card.c
@@ -0,0 +1,722 @@
+/***************************************************************************\
+|* Copyright (c) 1994 Microsoft Corporation *|
+|* Developed for Microsoft by TriplePoint, Inc. Beaverton, Oregon *|
+|* *|
+|* This file is part of the HT Communications DSU41 WAN Miniport Driver. *|
+\***************************************************************************/
+#include "version.h"
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Module Name:
+
+ card.c
+
+Abstract:
+
+ This module implements the low-level hardware control functions used by
+ the NDIS Minport driver on the HT DSU41 controller. You will need to
+ replace this module with the control functions required to support your
+ hardware.
+ CardIdentify()
+ CardDoCommand()
+ CardInitialize()
+ CardLineConfig()
+ CardLineDisconnect()
+ CardLineDisconnect()
+ CardPrepareTransmit()
+ CardGetReceiveInfo()
+ CardDialNumber()
+
+ This driver conforms to the NDIS 3.0 Miniport interface.
+
+Author:
+
+ Larry Hattery - TriplePoint, Inc. (larryh@tpi.com) Jun-94
+
+Environment:
+
+ Windows NT 3.5 kernel mode Miniport driver or equivalent.
+
+Revision History:
+
+---------------------------------------------------------------------------*/
+
+#define __FILEID__ 2 // Unique file ID for error logging
+
+#include "htdsu.h"
+
+
+NDIS_STATUS
+CardIdentify(
+ IN PHTDSU_ADAPTER Adapter
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This routine will attempt to verify that the controller is located in
+ memory where the driver has been configured to expect it.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_ADAPTER_NOT_FOUND
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("CardIdentify")
+
+ NDIS_STATUS Status;
+
+ /*
+ // These values are read from the adapter to make sure this driver will
+ // work with the firmware on the adapter.
+ */
+ USHORT CoProcessorId;
+ USHORT CoProcessorVersion;
+ USHORT DsuId;
+ USHORT DsuVersion;
+
+ DBG_ENTER(Adapter);
+
+ /*
+ // Read the configuration values from the card.
+ */
+ CoProcessorId = READ_REGISTER_USHORT(&Adapter->AdapterRam->CoProcessorId);
+ CoProcessorVersion = READ_REGISTER_USHORT(&Adapter->AdapterRam->CoProcessorVersion);
+ DsuId = READ_REGISTER_USHORT(&Adapter->AdapterRam->DsuId);
+ DsuVersion = READ_REGISTER_USHORT(&Adapter->AdapterRam->DsuVersion);
+
+ /*
+ // Make sure these values are what we expect.
+ */
+ if ((CoProcessorId == HTDSU_COPROCESSOR_ID) &&
+ (CoProcessorVersion >= HTDSU_COPROCESSOR_VERSION) &&
+ ((DsuId & 0x00FF) == HTDSU_DSU_ID) &&
+ (DsuVersion >= HTDSU_DSU_VERSION))
+ {
+ /*
+ // Record the number of lines on this adapter.
+ */
+ Adapter->NumLineDevs = HTDSU_NUM_LINKS;
+ if ((DsuId & 0xFF00) == 0)
+ {
+ --Adapter->NumLineDevs;
+ }
+ DBG_NOTICE(Adapter,("NumLineDevs=%d\n",Adapter->NumLineDevs));
+
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ else
+ {
+ DBG_ERROR(Adapter,("Adapter not found or invalid firmware:\n"
+ "CoProcessorId = %Xh\n"
+ "CoProcessorVersion = %Xh\n"
+ "DsuId = %Xh\n"
+ "DsuVersion = %Xh\n",
+ CoProcessorId,
+ CoProcessorVersion,
+ DsuId,
+ DsuVersion
+ ));
+
+ Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+ /*
+ // Log error message and return.
+ */
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
+ 7,
+ CoProcessorId,
+ CoProcessorVersion,
+ DsuId,
+ DsuVersion,
+ Status,
+ __FILEID__,
+ __LINE__
+ );
+ }
+
+ DBG_LEAVE(Adapter);
+
+ return (Status);
+}
+
+
+NDIS_STATUS
+CardDoCommand(
+ IN PHTDSU_ADAPTER Adapter,
+ IN USHORT CardLine, /* HTDSU_CMD_LINE1 or HTDSU_CMD_LINE2 */
+ IN USHORT CommandValue
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This routine routine will execute a command on the card after making
+ sure the previous command has completed properly.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ CardLine _ Specifies which line to use for the transmit (HTDSU_LINEx_ID).
+
+ CommandValue _ HTDSU_CMD_??? command to be executed.
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_HARD_ERRORS
+
+---------------------------------------------------------------------------*/
+{
+ DBG_FUNC("CardDoCommand")
+
+ ULONG TimeOut = 0;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,("Line=%d, Command=%04X, LineStatus=%Xh\n",
+ CardLine, CommandValue,
+ READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine1)
+ ));
+
+ /*
+ // Wait for command register to go idle - but don't wait too long.
+ // If we timeout here, there's gotta be something wrong with the adapter.
+ */
+ while ((READ_REGISTER_USHORT(&Adapter->AdapterRam->Command) !=
+ HTDSU_CMD_NOP) ||
+ (READ_REGISTER_USHORT(&Adapter->AdapterRam->CoProcessorId) !=
+ HTDSU_COPROCESSOR_ID))
+ {
+ if (TimeOut++ > HTDSU_SELFTEST_TIMEOUT)
+ {
+ DBG_ERROR(Adapter,("Timeout waiting for %04X command to clear\n",
+ READ_REGISTER_USHORT(&Adapter->AdapterRam->Command)));
+ /*
+ // Ask for reset, and disable interrupts until we get it.
+ */
+ Adapter->NeedReset = TRUE;
+ Adapter->InterruptEnableFlag = HTDSU_INTR_DISABLE;
+ CardDisableInterrupt(Adapter);
+
+ return (NDIS_STATUS_HARD_ERRORS);
+ }
+ NdisStallExecution(_100_MICROSECONDS);
+ }
+ DBG_NOTICE(Adapter,("Timeout=%d waiting to submit %04X\n",
+ TimeOut, CommandValue));
+
+ /*
+ // Before starting a reset command, we clear the the co-processor ID
+ // which then gets set to the proper value when the reset is complete.
+ */
+ if (CommandValue == HTDSU_CMD_RESET)
+ {
+ WRITE_REGISTER_USHORT(&Adapter->AdapterRam->CoProcessorId, 0);
+ }
+
+ /*
+ // Send the command to the adapter.
+ */
+ WRITE_REGISTER_USHORT(
+ &Adapter->AdapterRam->Command,
+ (USHORT) (CommandValue + CardLine)
+ );
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+CardInitialize(
+ IN PHTDSU_ADAPTER Adapter,
+ IN BOOLEAN PerformSelfTest
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This routine will attempt to initialize the controller, but will not
+ enable transmits or receives.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ PerformSelfTest _ TRUE if caller wants to run selftest diagnostics.
+ This normally takes about 4 seconds to complete, so you
+ wouldn't want to do it every time you start up.
+
+Return Values:
+
+ NDIS_STATUS_HARD_ERRORS
+ NDIS_STATUS_SUCCESS
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("CardInitialize")
+
+ NDIS_STATUS Status;
+
+ USHORT SelfTestStatus;
+
+ UINT TimeOut;
+
+ DBG_ENTER(Adapter);
+
+ /*
+ // First we make sure the adapter is where we think it is.
+ */
+ Status = CardIdentify(Adapter);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ return (Status);
+ }
+
+ /*
+ // Reset the hardware to make sure we're in a known state.
+ */
+ Status = CardDoCommand(Adapter, 0, HTDSU_CMD_RESET);
+
+ if (PerformSelfTest)
+ {
+ /*
+ // Wait for the reset to complete before starting the self-test.
+ // Then issue the self-test command to see if the adapter firmware
+ // is happy with the situation.
+ */
+ Status = CardDoCommand(Adapter, 0, HTDSU_CMD_SELFTEST);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DBG_ERROR(Adapter,("Failed HTDSU_CMD_RESET\n"));
+ /*
+ // Log error message and return.
+ */
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 3,
+ Status,
+ __FILEID__,
+ __LINE__
+ );
+ return (Status);
+ }
+
+ /*
+ // Wait for the self test to complete, but don't wait forever.
+ */
+ TimeOut = 0;
+ while (Status == NDIS_STATUS_SUCCESS &&
+ READ_REGISTER_USHORT(&Adapter->AdapterRam->Command) !=
+ HTDSU_CMD_NOP)
+ {
+ if (TimeOut++ > HTDSU_SELFTEST_TIMEOUT)
+ {
+ DBG_ERROR(Adapter,("Timeout waiting for SELFTEST to complete\n"));
+ Status = NDIS_STATUS_HARD_ERRORS;
+ }
+ else
+ {
+ NdisStallExecution(_100_MICROSECONDS);
+ }
+ }
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DBG_ERROR(Adapter,("Failed HTDSU_CMD_SELFTEST\n"));
+ /*
+ // Log error message and return.
+ */
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 3,
+ Status,
+ __FILEID__,
+ __LINE__
+ );
+ return (Status);
+ }
+
+ /*
+ // Verify that self test was successful.
+ */
+ SelfTestStatus = READ_REGISTER_USHORT(&Adapter->AdapterRam->SelfTestStatus);
+ if (SelfTestStatus != 0 && SelfTestStatus != HTDSU_SELFTEST_OK)
+ {
+ DBG_ERROR(Adapter,("Failed HTDSU_CMD_SELFTEST (Status=%X)\n",
+ SelfTestStatus));
+ /*
+ // Log error message and return.
+ */
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 3,
+ SelfTestStatus,
+ __FILEID__,
+ __LINE__
+ );
+ return (NDIS_STATUS_HARD_ERRORS);
+ }
+ }
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+VOID
+CardLineConfig(
+ IN PHTDSU_ADAPTER Adapter,
+ IN USHORT CardLine /* HTDSU_CMD_LINE1 or HTDSU_CMD_LINE2 */
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This routine will ready the controller to send and receive packets.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ CardLine _ Specifies which line to use for the transmit (HTDSU_LINEx_ID).
+
+Return Values:
+
+ None
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("CardLineConfig")
+
+ USHORT ClockCommand;
+ USHORT LineCommand;
+
+ DBG_ENTER(Adapter);
+
+ ASSERT((CardLine==HTDSU_CMD_LINE1) || (CardLine==HTDSU_CMD_LINE2));
+
+ /*
+ // Configure the line for HDLC framing and for leased or dialup mode.
+ */
+ if (Adapter->LineType == HTDSU_LINEMODE_LEASED)
+ {
+ ClockCommand = HTDSU_CMD_INTERNAL_TX_CLOCK;
+ LineCommand = HTDSU_CMD_LEASED_LINE;
+ }
+ else
+ {
+ ClockCommand = HTDSU_CMD_DDS_TX_CLOCK;
+ LineCommand = HTDSU_CMD_DIALUP_LINE;
+ }
+
+ CardDoCommand(Adapter, CardLine, ClockCommand);
+ CardDoCommand(Adapter, CardLine, HTDSU_CMD_HDLC_PROTOCOL);
+ CardDoCommand(Adapter, CardLine, LineCommand);
+ CardDoCommand(Adapter, CardLine, Adapter->LineRate);
+
+ /*
+ // Clear any pending interrupts.
+ */
+ CardDoCommand(Adapter, 0, HTDSU_CMD_CLEAR_INTERRUPT);
+ CardClearInterrupt(Adapter);
+
+ DBG_LEAVE(Adapter);
+}
+
+
+VOID
+CardLineDisconnect(
+ IN PHTDSU_ADAPTER Adapter,
+ IN USHORT CardLine /* HTDSU_CMD_LINE1 or HTDSU_CMD_LINE2 */
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This routine will disconnect any call currently on the line.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ CardLine _ Specifies which line to use for the transmit (HTDSU_LINEx_ID).
+
+Return Values:
+
+ None
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("CardLineDisconnect")
+
+ DBG_ENTER(Adapter);
+
+ ASSERT((CardLine==HTDSU_CMD_LINE1) || (CardLine==HTDSU_CMD_LINE2));
+
+ /*
+ // Disconnect the line and reconfigure the line for next time.
+ */
+ CardDoCommand(Adapter, CardLine, HTDSU_CMD_DISCONNECT);
+ CardLineConfig(Adapter, CardLine);
+
+ DBG_LEAVE(Adapter);
+}
+
+
+VOID
+CardPrepareTransmit(
+ IN PHTDSU_ADAPTER Adapter,
+ IN USHORT CardLine, /* HTDSU_CMD_LINE1 or HTDSU_CMD_LINE2 */
+ IN USHORT BytesToSend
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This routine will write the packet header information into the
+ transmit buffer. This assumes that the controller has notified the
+ driver that the transmit buffer is empty.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ CardLine _ Specifies which line to use for the transmit (HTDSU_LINEx_ID).
+
+ BytesToSend _ Number of bytes to transmit.
+
+Return Values:
+
+ None
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("CardPrepareTransmit")
+
+ DBG_ENTER(Adapter);
+
+ ASSERT((CardLine==HTDSU_CMD_LINE1) || (CardLine==HTDSU_CMD_LINE2));
+ ASSERT(READ_REGISTER_USHORT(&Adapter->AdapterRam->TxDataEmpty));
+ ASSERT(BytesToSend > 0);
+
+ /*
+ // Tell the adapter how many bytes are to be sent, and which line to use.
+ */
+ WRITE_REGISTER_USHORT(
+ &Adapter->AdapterRam->TxBuffer.Address,
+ (USHORT) (CardLine - HTDSU_CMD_LINE1)
+ );
+ WRITE_REGISTER_USHORT(
+ &Adapter->AdapterRam->TxBuffer.Length,
+ BytesToSend
+ );
+
+ /*
+ // Mark the end of packet and end of packet list.
+ */
+ WRITE_REGISTER_USHORT(
+ &Adapter->AdapterRam->TxBuffer.Data[(BytesToSend+1)/sizeof(USHORT)],
+ HTDSU_DATA_TERMINATOR
+ );
+ WRITE_REGISTER_USHORT(
+ &Adapter->AdapterRam->TxBuffer.Data[(BytesToSend+3)/sizeof(USHORT)],
+ HTDSU_DATA_TERMINATOR
+ );
+
+ DBG_LEAVE(Adapter);
+}
+
+
+VOID
+CardGetReceiveInfo(
+ IN PHTDSU_ADAPTER Adapter,
+ OUT PUSHORT CardLine, /* HTDSU_CMD_LINE1 or HTDSU_CMD_LINE2 */
+ OUT PUSHORT BytesReceived,
+ OUT PUSHORT RxErrors
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This routine will retrieve the packet header information from the
+ receive buffer. This assumes that the controller has notified the
+ driver that a packet has been received.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ CardLine _ Specifies which line the packet was received on (HTDSU_LINEx_ID).
+
+ BytesReceived _ Number of bytes received.
+
+ RxErrors _ Receive error flags non-zero if packet has errors.
+
+Return Values:
+
+ None
+
+---------------------------------------------------------------------------*/
+{
+ DBG_FUNC("CardGetReceiveInfo")
+
+ USHORT Length;
+
+ DBG_ENTER(Adapter);
+
+ /*
+ // This should be true if we're here, but there are race conditions
+ // on hangup where I've seen this condition hit.
+ */
+ if (READ_REGISTER_USHORT(&Adapter->AdapterRam->RxDataAvailable) == 0)
+ {
+ *RxErrors = 0;
+ *BytesReceived = 0;
+ *CardLine = HTDSU_CMD_LINE1; // Don't return a bad line #
+ }
+ else
+ {
+ /*
+ // The length field tells us how many bytes are in the packet, and
+ // the most significant bit tells us whether the packet has a CRC error.
+ */
+ Length = READ_REGISTER_USHORT(&Adapter->AdapterRam->RxBuffer.Length);
+ *BytesReceived = Length & ~HTDSU_CRC_ERROR;
+ *RxErrors = Length & HTDSU_CRC_ERROR;
+
+ /*
+ // The least significant nibble of the address tells us what line the
+ // packet was received on -- at least it better...
+ */
+ *CardLine = (READ_REGISTER_USHORT(
+ &Adapter->AdapterRam->RxBuffer.Address) &
+ 0x000F) + HTDSU_CMD_LINE1;
+
+ if ((*CardLine != HTDSU_CMD_LINE1) && (*CardLine != HTDSU_CMD_LINE2))
+ {
+ *RxErrors |= HTDSU_RX_ERROR;
+ *CardLine = HTDSU_CMD_LINE1; // Don't return a bad line #
+ }
+ else if (*BytesReceived > HTDSU_MAX_PACKET_SIZE)
+ {
+ *RxErrors |= HTDSU_RX_ERROR;
+ }
+ }
+
+ DBG_LEAVE(Adapter);
+}
+
+
+VOID
+CardDialNumber(
+ IN PHTDSU_ADAPTER Adapter,
+ IN USHORT CardLine, /* HTDSU_CMD_LINE1 or HTDSU_CMD_LINE2 */
+ IN PUCHAR DialString,
+ IN ULONG DialStringLength
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ Place a dial string on the adapter and start the dialing sequence.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ CardLine _ Specifies which line to use for the transmit (HTDSU_LINEx_ID).
+
+ DialString _ A pointer to an ASCII null-terminated string of digits.
+
+ DialStringLength _ Number of bytes in dial string.
+
+Return Values:
+
+ None
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("CardDialNumber")
+
+ UINT Index;
+ UINT NumDigits;
+
+ PUSHORT DialRam;
+
+ DBG_ENTER(Adapter);
+
+ ASSERT(READ_REGISTER_USHORT(&Adapter->AdapterRam->TxDataEmpty));
+ ASSERT(READ_REGISTER_USHORT(&Adapter->AdapterRam->Command) == HTDSU_CMD_NOP);
+
+ /*
+ // Copy the digits to be dialed onto the adapter.
+ // The adapter interprets phone numbers as high byte is valid digit,
+ // low byte is ignored, the last digit gets bit 15 set.
+ */
+ DialRam = (PUSHORT) &Adapter->AdapterRam->TxBuffer;
+
+ for (NumDigits = Index = 0; Index < DialStringLength && *DialString; Index++)
+ {
+ if ((*DialString >= '0') && (*DialString <= '9'))
+ {
+ WRITE_REGISTER_USHORT(
+ DialRam,
+ (USHORT) ((*DialString - '0') << 8)
+ );
+ DialRam++;
+
+ /*
+ // Make sure dial string is within the limit of the adapter.
+ */
+ if (++NumDigits >= HTDSU_MAX_DIALING_DIGITS)
+ {
+ break;
+ }
+ }
+ DialString++;
+ }
+
+ /*
+ // Set the MSB in the last digit.
+ */
+ DialRam--;
+ WRITE_REGISTER_USHORT(
+ DialRam,
+ (USHORT) (READ_REGISTER_USHORT(DialRam) | 0x8000)
+ );
+
+ /*
+ // Initiate the dial sequence.
+ */
+ CardDoCommand(Adapter, CardLine, HTDSU_CMD_DIAL);
+
+ DBG_LEAVE(Adapter);
+}
+
diff --git a/private/ntos/ndis/htdsu/card.h b/private/ntos/ndis/htdsu/card.h
new file mode 100644
index 000000000..fe618d439
--- /dev/null
+++ b/private/ntos/ndis/htdsu/card.h
@@ -0,0 +1,521 @@
+/***************************************************************************\
+|* Copyright (c) 1994 Microsoft Corporation *|
+|* Developed for Microsoft by TriplePoint, Inc. Beaverton, Oregon *|
+|* *|
+|* This file is part of the HT Communications DSU41 WAN Miniport Driver. *|
+\***************************************************************************/
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Module Name:
+
+ card.h
+
+Abstract:
+
+ This module defines the hardware specific structures and values used to
+ control the HT DSU41. You will need to replace this module with the
+ control functions required to support your hardware.
+
+ This driver conforms to the NDIS 3.0 miniport interface.
+
+Author:
+
+ Larry Hattery - TriplePoint, Inc. (larryh@tpi.com) Jun-94
+
+Environment:
+
+ Include this file at the top of each module in the Miniport driver.
+
+Revision History:
+
+---------------------------------------------------------------------------*/
+
+#ifndef _CARD_H
+#define _CARD_H
+
+/*
+// Maximum number of outstanding transmits allowed. Actually, the driver
+// must queue all transmits internally if they can't be placed on the adapter.
+*/
+#define HTDSU_MAX_TRANSMITS 1
+
+/*
+// Maximum packet size allowed by the adapter -- must be restricted to
+// 1500 bytes at this point, and must also allow for frames at least 32
+// bytes longer.
+*/
+#define HTDSU_MAX_PACKET_SIZE 1532
+#define HTDSU_MAX_FRAME_SIZE (HTDSU_MAX_PACKET_SIZE - 32)
+
+/*
+// WAN packets don't have a MAC header.
+*/
+#define HTDSU_MAC_HEADER_SIZE 0
+
+/*
+// The WAN miniport driver must indicate the entire packet when it is received.
+*/
+#define HTDSU_MAX_LOOKAHEAD (HTDSU_MAX_PACKET_SIZE - HTDSU_MAC_HEADER_SIZE)
+
+/*
+// Media link speed in bits per second.
+*/
+#define HTDSU_LINK_SPEED 57600 // bits per second
+
+/*
+// The maximum number of digits allowed to be in a dialing sequence.
+*/
+#define HTDSU_MAX_DIALING_DIGITS 32
+
+/*
+// These time out values depend on the card firmware and media contraints.
+// We should see a dial tone within 5 seconds,
+// We should then see an answer within at most 30 seconds.
+// When a call arrives, it should be accepted within 5 seconds.
+// And after it is answer, we should get a connect within 2 seconds.
+*/
+#define HTDSU_NO_DIALTONE_TIMEOUT 5000 // 5 seconds
+#define HTDSU_NO_ANSWER_TIMEOUT 40000 // 40 seconds
+#define HTDSU_NO_ACCEPT_TIMEOUT 5000 // 5 seconds
+#define HTDSU_NO_CONNECT_TIMEOUT 2000 // 2 seconds
+#define HTDSU_NO_CLOSECALL_TIMEOUT 2000 // 2 seconds
+
+/*
+// Turn on structure packing to make sure these data structures stay
+// aligned with the hardware.
+*/
+#include <pshpack1.h>
+
+/*
+// Both the transmit and receive buffers have this same format on the card.
+*/
+typedef struct _HTDSU_BUFFER
+{
+ /*
+ // The least significant nibble of the Address field specifies
+ // which line the data is associated with (0 = line 1, 1 = line 2).
+ // The most significant nibbles are used for sequencing information
+ // if line multiplexing is used (NOT SUPPORTED BY THIS DRIVER).
+ */
+# define HTDSU_LINE1_ID 0
+# define HTDSU_LINE2_ID 1
+ USHORT Address;
+
+ /*
+ // The length of the Data field in bytes.
+ // MSB of length field will be set if the HDLC framing detects a
+ // CRC error on any received packet.
+ */
+# define HTDSU_RX_ERROR 0x1000
+# define HTDSU_CRC_ERROR 0x8000
+ USHORT Length;
+
+ /*
+ // The Data field holds the data to be transmitted, or the data just
+ // received on the line. The data must be terminated with a 0x1616.
+ // Note that the data will be padded to an even byte count by the
+ // DSU firmware on incoming frames, and the driver will pad the outgoing
+ // frames so that the terminator is word aligned. Only 'Length' bytes
+ // will actually be transmitted on the line however.
+ */
+# define HTDSU_DATA_SIZE (2016 - (2 * sizeof(USHORT)))
+# define HTDSU_DATA_TERMINATOR 0x1616
+# define HTDSU_DATA_ODDBYTE_MASK 0xFF00
+ USHORT Data[HTDSU_DATA_SIZE/sizeof(USHORT)];
+
+} HTDSU_BUFFER, *PHTDSU_BUFFER;
+
+/*
+// This structure can be overlaid onto the DSU41 adapter memory for
+// easy access to the hardware registers and data buffers.
+// THIS ONLY WORKS IF THE COMPILER SUPPORTS STRUCTURE PACKING ON 16 BIT BOUNDRY.
+*/
+typedef struct _HTDSU_REGISTERS
+{
+ /* 0x000 - 0x7DF
+ // The transmit buffer will hold a single packet.
+ */
+ HTDSU_BUFFER TxBuffer;
+
+ /* 0x7E0 - 0xFBF
+ // The receive buffer may hold more than one packet at a time.
+ */
+ HTDSU_BUFFER RxBuffer;
+
+ /* 0xFC0 - 0xFD5
+ // Reserved hardware registers.
+ */
+ USHORT Reserved1[0x0B];
+
+ /* 0xFD6
+ // This register will be set to 1 by the interrupt handler to tell
+ // the hardware to clear the current interrupt from the adapter.
+ */
+ USHORT InterruptClear;
+
+ /* 0xFD8, 0xFDA
+ // When using transparent mode on line 1 or 2, these registers tell the
+ // adapter how many bytes are interrupt the CPU.
+ // (NOT SUPPORTED BY THIS DRIVER).
+ */
+ USHORT Rx2Length;
+ USHORT Rx1Length;
+
+ /* 0xFDC
+ // This register will be set to 1 when the adapter receives a frame
+ // from the remote unit. The driver must reset this register to zero
+ // after it has copied the frame from the adapter's RxBuffer.
+ */
+ USHORT RxDataAvailable;
+
+ /* 0xFDE
+ // This register will be set to 1 when the adapter copies the frame
+ // from the TxBuffer to its internal buffer. The driver must reset
+ // this register to zero after it fills the TxBuffer and places the
+ // termination flag at the end.
+ */
+ USHORT TxDataEmpty;
+
+ /* 0xFE0
+ // The drivers uses this register to tell the adapter to perform various
+ // actions. The adapter will reset this register to zero when the
+ // command completes.
+ */
+# define HTDSU_CMD_NOP 0x0000
+# define HTDSU_CMD_ANSWER 0x0100
+# define HTDSU_CMD_DIAL 0x0200
+# define HTDSU_CMD_DISCONNECT 0x0300
+# define HTDSU_CMD_SELFTEST 0x0400
+# define HTDSU_CMD_CLEAR_ERRORS 0x0500
+# define HTDSU_CMD_LOCAL_LOOPBACK 0x0600
+# define HTDSU_CMD_LINE_LOOPBACK 0x0700
+# define HTDSU_CMD_REMOTE_LOOPBACK 0x0800
+# define HTDSU_CMD_REMOTETP_LOOPBACK 0x0900
+# define HTDSU_CMD_STOP_LOOPBACK 0x0A00
+# define HTDSU_CMD_LEASED_LINE 0x0B00
+# define HTDSU_CMD_DIALUP_LINE 0x0C00
+# define HTDSU_CMD_RX_BIT_SLIP 0x0D00
+# define HTDSU_CMD_DDS_TX_CLOCK 0x0E00
+# define HTDSU_CMD_INTERNAL_TX_CLOCK 0x0E10
+# define HTDSU_CMD_CLEAR_INTERRUPT 0x0F00
+# define HTDSU_CMD_FORCE_ERROR 0x1000
+# define HTDSU_CMD_RESET 0x1100
+# define HTDSU_CMD_HT_PROTOCOL 0x1200
+# define HTDSU_CMD_NO_PROTOCOL 0x1210
+# define HTDSU_CMD_HDLC_PROTOCOL 0x1220
+# define HTDSU_CMD_TX_RATE_MAX 0x1400
+# define HTDSU_CMD_TX_RATE_57600 0x1410
+# define HTDSU_CMD_TX_RATE_38400 0x1420
+# define HTDSU_CMD_TX_RATE_19200 0x1430
+# define HTDSU_CMD_TX_RATE_9600 0x1440
+# define HTDSU_CMD_LINE1 0x0001
+# define HTDSU_CMD_LINE2 0x0002
+ USHORT Command;
+
+ /* 0xFE2, 0xFE4
+ // The InterruptEnable register provides control over which adapter events
+ // will signal an interrupt to the CPU. The InterruptStatus register is
+ // used by the driver to determine the cause of an interrupt.
+ */
+# define HTDSU_INTR_DISABLE 0x0000
+# define HTDSU_INTR_RX_FULL2 0x0001
+# define HTDSU_INTR_RX_FULL1 0x0002
+# define HTDSU_INTR_RX_PACKET2 0x0004
+# define HTDSU_INTR_RX_PACKET1 0x0008
+# define HTDSU_INTR_NO_SIGNAL2 0x0010
+# define HTDSU_INTR_NO_SIGNAL1 0x0020
+# define HTDSU_INTR_DISCONNECTED2 0x0040
+# define HTDSU_INTR_DISCONNECTED1 0x0080
+# define HTDSU_INTR_CONNECTED2 0x0100
+# define HTDSU_INTR_CONNECTED1 0x0200
+# define HTDSU_INTR_RINGING2 0x0400
+# define HTDSU_INTR_RINGING1 0x0800
+# define HTDSU_INTR_TX_PACKET2 0x1000
+# define HTDSU_INTR_TX_PACKET1 0x2000
+# define HTDSU_INTR_TX_EMPTY2 0x4000
+# define HTDSU_INTR_TX_EMPTY1 0x8000
+# define HTDSU_INTR_ALL_LINE1 (HTDSU_INTR_RX_FULL1 | \
+ HTDSU_INTR_RX_PACKET1 | \
+ HTDSU_INTR_TX_PACKET1 | \
+ HTDSU_INTR_NO_SIGNAL1 | \
+ HTDSU_INTR_DISCONNECTED1 | \
+ HTDSU_INTR_CONNECTED1 | \
+ HTDSU_INTR_RINGING1)
+# define HTDSU_INTR_ALL_LINE2 (HTDSU_INTR_RX_FULL2 | \
+ HTDSU_INTR_RX_PACKET2 | \
+ HTDSU_INTR_TX_PACKET2 | \
+ HTDSU_INTR_NO_SIGNAL2 | \
+ HTDSU_INTR_DISCONNECTED2 | \
+ HTDSU_INTR_CONNECTED2 | \
+ HTDSU_INTR_RINGING2)
+ USHORT InterruptEnable;
+ USHORT InterruptStatus;
+
+ /* 0xFE6, 0xFE8
+ // The StatusLine registers are used by the driver to determine the
+ // current state of the associated phone line.
+ */
+# define HTDSU_STATUS_LOCAL_LOOPBACK 0x0001
+# define HTDSU_STATUS_CO_LOOPBACK 0x0002
+# define HTDSU_STATUS_REMOTE_LOOPBACK 0x0008
+# define HTDSU_STATUS_LINE_LOOPBACK 0x0010
+# define HTDSU_STATUS_OUT_OF_FRAME 0x0020
+# define HTDSU_STATUS_OUT_OF_SERVICE 0x0040
+# define HTDSU_STATUS_NO_SIGNAL 0x0080
+# define HTDSU_STATUS_NO_CURRENT 0x0100
+# define HTDSU_STATUS_NO_DIAL_TONE 0x0200
+# define HTDSU_STATUS_ON_LINE 0x0400
+# define HTDSU_STATUS_NO_ANSWER 0x0800
+# define HTDSU_STATUS_CARRIER_DETECT 0x1000
+# define HTDSU_STATUS_RINGING 0x2000
+# define HTDSU_STATUS_REMOTE_RESPONSE 0x4000
+ USHORT StatusLine1;
+ USHORT StatusLine2;
+
+ /* 0xFEA, 0xFEC
+ // The error counter registers are used when running the command:
+ // HTDSU_CMD_REMOTETP_LOOPBACK. The counters are incremented if a
+ // test pattern error is detected, and they are reset when the test
+ // is terminated.
+ */
+#define HTDSU_ERROR_COPROCESSOR 0x0800
+#define HTDSU_ERROR_DSU2 0x1000
+#define HTDSU_ERROR_DSU1 0x2000
+#define HTDSU_ERROR_LOW_BYTE 0x4000
+#define HTDSU_ERROR_HIGH_BYTE 0x8000
+ USHORT ErrorsLine1;
+ USHORT ErrorsLine2;
+
+ /* 0xFEE
+ // The adapter firmware sets test SelfTestStatus register if it detects
+ // an error during the HTDSU_CMD_SELFTEST command. Otherwise this register
+ // is reset to zero.
+ */
+#define HTDSU_SELFTEST_OK (HTDSU_ERROR_HIGH_BYTE | \
+ HTDSU_ERROR_LOW_BYTE | \
+ HTDSU_ERROR_COPROCESSOR)
+#define HTDSU_SELFTEST_TIMEOUT 40000 // 4 seconds.
+ USHORT SelfTestStatus;
+
+ /* 0xFF0
+ // Reserved hardware register.
+ */
+ USHORT Reserved2;
+
+ /* 0xFF2
+ // DSU serial number.
+ */
+ USHORT SerialNumber;
+
+ /* 0xFF4
+ // Co-processor firmware checksum.
+ */
+ USHORT CoProcessorCheckSum;
+
+ /* 0xFF6
+ // DSU firmware checksum.
+ */
+ USHORT DsuCheckSum;
+
+ /* 0xFF8
+ // Co-processor firmware version.
+ */
+# define HTDSU_COPROCESSOR_VERSION 0x0340
+ USHORT CoProcessorVersion;
+
+ /* 0xFFA
+ // DSU firmware version.
+ */
+# define HTDSU_DSU_VERSION 0x0013
+ USHORT DsuVersion;
+
+ /* 0xFFC
+ // DSU hardware ID.
+ */
+# define HTDSU_DSU_ID 0x0050
+ USHORT DsuId;
+
+ /* 0xFFE
+ // Co-processor ID.
+ */
+# define HTDSU_COPROCESSOR_ID 0x0060
+ USHORT CoProcessorId;
+
+} HTDSU_REGISTERS, * PHTDSU_REGISTERS;
+
+
+/*
+// Turn off structure packing.
+*/
+#include <poppack.h>
+
+/*
+// The adapter memory structure must be sized the same as the hardware!
+*/
+#define HTDSU_MEMORY_SIZE sizeof(HTDSU_REGISTERS)
+
+/*
+// Enable the currently accepted interrupts on the adapter.
+*/
+#define CardEnableInterrupt(Adapter) \
+ {WRITE_REGISTER_USHORT(&Adapter->AdapterRam->InterruptEnable, \
+ Adapter->InterruptEnableFlag);}
+
+/*
+// Disable all interrupts on the adapter.
+*/
+#define CardDisableInterrupt(Adapter) \
+ {WRITE_REGISTER_USHORT(&Adapter->AdapterRam->InterruptEnable, \
+ HTDSU_INTR_DISABLE);}
+
+/*
+// Clear all the current interrupts on the adapter.
+*/
+#define CardClearInterrupt(Adapter) \
+ {WRITE_REGISTER_USHORT(&Adapter->AdapterRam->InterruptClear, 1);}
+
+/*
+// Return TRUE if all interrupts are disabled on the adapter.
+*/
+#define CardAreInterruptsDisabled(Adapter) \
+ (READ_REGISTER_USHORT(&Adapter->AdapterRam->InterruptEnable) == \
+ HTDSU_INTR_DISABLE)
+
+/*
+// Return the current interrupt status from the adapter.
+*/
+#define CardGetInterrupt(Adapter) \
+ (READ_REGISTER_USHORT(&Adapter->AdapterRam->InterruptStatus))
+
+/*
+// Start sending the current packet out.
+*/
+#define CardStartTransmit(Adapter) \
+ {WRITE_REGISTER_USHORT(&Adapter->AdapterRam->TxDataEmpty, 0);}
+
+/*
+// Return non-zero if transmit buffer is empty
+*/
+#define CardTransmitEmpty(Adapter) \
+ (READ_REGISTER_USHORT(&Adapter->AdapterRam->TxDataEmpty))
+
+/*
+// Tell the adapter we're done with the packet just received.
+*/
+#define CardReceiveAvailable(Adapter) \
+ (READ_REGISTER_USHORT(&Adapter->AdapterRam->RxDataAvailable))
+
+/*
+// Tell the adapter we're done with the packet just received.
+*/
+#define CardReceiveComplete(Adapter) \
+ {WRITE_REGISTER_USHORT(&Adapter->AdapterRam->RxDataAvailable, 0);}
+
+/*
+// Tell the adapter to pick up the line.
+*/
+#define CardLineAnswer(Adapter, CardLine) \
+ CardDoCommand(Adapter, CardLine, HTDSU_CMD_ANSWER)
+
+/*
+// Return non-zero if remote unit has responded to ring from this line.
+*/
+#define CardStatusRingBack(Adapter, CardLine) \
+ ((CardLine == HTDSU_CMD_LINE1) ? \
+ (READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine1) & \
+ HTDSU_STATUS_REMOTE_RESPONSE) : \
+ (READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine2) & \
+ HTDSU_STATUS_REMOTE_RESPONSE) \
+ )
+
+/*
+// Return non-zero if this phone line is ringing.
+*/
+#define CardStatusRinging(Adapter, CardLine) \
+ ((CardLine == HTDSU_CMD_LINE1) ? \
+ (READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine1) & \
+ HTDSU_STATUS_RINGING) : \
+ (READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine2) & \
+ HTDSU_STATUS_RINGING) \
+ )
+
+/*
+// Return non-zero if this line has detected a carrier signal.
+*/
+#define CardStatusCarrierDetect(Adapter, CardLine) \
+ ((CardLine == HTDSU_CMD_LINE1) ? \
+ (READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine1) & \
+ HTDSU_STATUS_CARRIER_DETECT) : \
+ (READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine2) & \
+ HTDSU_STATUS_CARRIER_DETECT) \
+ )
+
+/*
+// Return non-zero if the number we dialed on this line did not answer.
+*/
+#define CardStatusNoAnswer(Adapter, CardLine) \
+ ((CardLine == HTDSU_CMD_LINE1) ? \
+ (READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine1) & \
+ HTDSU_STATUS_NO_ANSWER) : \
+ (READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine2) & \
+ HTDSU_STATUS_NO_ANSWER) \
+ )
+
+/*
+// Return non-zero if the selected line is ready to use.
+*/
+#define CardStatusOnLine(Adapter, CardLine) \
+ ((CardLine == HTDSU_CMD_LINE1) ? \
+ (READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine1) & \
+ HTDSU_STATUS_ON_LINE) : \
+ (READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine2) & \
+ HTDSU_STATUS_ON_LINE) \
+ )
+
+/*
+// Return non-zero if no dial tone is present on this line.
+*/
+#define CardStatusNoDialTone(Adapter, CardLine) \
+ ((CardLine == HTDSU_CMD_LINE1) ? \
+ (READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine1) & \
+ HTDSU_STATUS_NO_DIAL_TONE) : \
+ (READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine2) & \
+ HTDSU_STATUS_NO_DIAL_TONE) \
+ )
+
+/*
+// Return non-zero if this line has no sealing current.
+*/
+#define CardStatusNoCurrent(Adapter, CardLine) \
+ ((CardLine == HTDSU_CMD_LINE1) ? \
+ (READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine1) & \
+ HTDSU_STATUS_NO_CURRENT) : \
+ (READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine2) & \
+ HTDSU_STATUS_NO_CURRENT) \
+ )
+
+/*
+// Return non-zero if this line has no signal present.
+*/
+#define CardStatusNoSignal(Adapter, CardLine) \
+ ((CardLine == HTDSU_CMD_LINE1) ? \
+ (READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine1) & \
+ HTDSU_STATUS_NO_SIGNAL) : \
+ (READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine2) & \
+ HTDSU_STATUS_NO_SIGNAL) \
+ )
+
+/*
+// Return non-zero if this line has been placed out of service by the switch.
+*/
+#define CardStatusOutOfService(Adapter, CardLine) \
+ ((CardLine == HTDSU_CMD_LINE1) ? \
+ (READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine1) & \
+ HTDSU_STATUS_OUT_OF_SERVICE) : \
+ (READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine2) & \
+ HTDSU_STATUS_OUT_OF_SERVICE) \
+ )
+
+#endif // _CARD_H
+
diff --git a/private/ntos/ndis/htdsu/debug.c b/private/ntos/ndis/htdsu/debug.c
new file mode 100644
index 000000000..846e51737
--- /dev/null
+++ b/private/ntos/ndis/htdsu/debug.c
@@ -0,0 +1,112 @@
+/***************************************************************************\
+|* Copyright (c) 1994 Microsoft Corporation *|
+|* Developed for Microsoft by TriplePoint, Inc. Beaverton, Oregon *|
+|* *|
+|* This file is part of the HT Communications DSU41 WAN Miniport Driver. *|
+\***************************************************************************/
+#include "version.h"
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Module Name:
+
+ debug.c
+
+Abstract:
+
+ This module contains code to support driver debugging.
+
+Author:
+
+ Larry Hattery - TriplePoint, Inc. (larryh@tpi.com) Jun-94
+
+Environment:
+
+ Development only.
+
+Revision History:
+
+---------------------------------------------------------------------------*/
+
+#include <ndis.h>
+
+#if DBG
+
+
+VOID
+DbgPrintData(
+ IN PUCHAR Data,
+ IN UINT NumBytes,
+ IN ULONG Offset
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Routine Description:
+
+ Dumps data to the debug display formated in hex and ascii for easy viewing.
+ Used for debug output only. It is not compiled into the retail version.
+
+Arguments:
+
+ Data Buffer of data to be displayed
+
+ NumBytes Number of bytes to display
+
+ Offset Beginning offset to be displayed before each line
+
+Return Value:
+
+ None
+
+---------------------------------------------------------------------------*/
+
+{
+ UINT i,j;
+
+ for (i = 0; i < NumBytes; i += 16)
+ {
+ DbgPrint("%04lx: ", i + Offset);
+
+ /*
+ // Output the hex bytes
+ */
+ for (j = i; j < (i+16); j++)
+ {
+ if (j < NumBytes)
+ {
+ DbgPrint("%02x ",(UINT)((UCHAR)*(Data+j)));
+ }
+ else
+ {
+ DbgPrint(" ");
+ }
+ }
+
+ DbgPrint(" ");
+
+ /*
+ // Output the ASCII bytes
+ */
+ for (j = i; j < (i+16); j++)
+ {
+ if (j < NumBytes)
+ {
+ char c = *(Data+j);
+
+ if (c < ' ' || c > 'Z')
+ {
+ c = '.';
+ }
+ DbgPrint("%c", (UINT)c);
+ }
+ else
+ {
+ DbgPrint(" ");
+ }
+ }
+ DbgPrint("\n");
+ }
+}
+
+#endif
+
diff --git a/private/ntos/ndis/htdsu/debug.h b/private/ntos/ndis/htdsu/debug.h
new file mode 100644
index 000000000..5f3c6c581
--- /dev/null
+++ b/private/ntos/ndis/htdsu/debug.h
@@ -0,0 +1,137 @@
+/***************************************************************************\
+|* Copyright (c) 1994 Microsoft Corporation *|
+|* Developed for Microsoft by TriplePoint, Inc. Beaverton, Oregon *|
+|* *|
+|* This file is part of the HT Communications DSU41 WAN Miniport Driver. *|
+\***************************************************************************/
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Module Name:
+
+ debug.h
+
+Abstract:
+
+ This file contains generic debug macros for driver development.
+ If (DBG == 0) no code is generated; Otherwise macros will expand.
+
+Author:
+
+ Larry Hattery - TriplePoint, Inc. (larryh@tpi.com) Jun-94
+
+Environment:
+
+ Development Only.
+
+ debug.c must be linked into the driver code to support output.
+
+Revision History:
+
+---------------------------------------------------------------------------*/
+
+#ifndef _DEBUG_H
+#define _DEBUG_H
+
+/*
+// DEBUG FLAG DEFINITIONS
+*/
+
+#define DBG_ERROR_ON 0x0001L /* Display DBG_ERROR messages */
+#define DBG_WARNING_ON 0x0002L /* Display DBG_WARNING messages */
+#define DBG_NOTICE_ON 0x0004L /* Display DBG_NOTICE messages */
+#define DBG_TRACE_ON 0x0008L /* Display ENTER/TRACE/LEAVE messages */
+#define DBG_REQUEST_ON 0x0010L /* Enable set/query request display */
+#define DBG_PARAMS_ON 0x0020L /* Enable function parameter display */
+#define DBG_HEADERS_ON 0x0040L /* Enable Tx/Rx MAC header display */
+#define DBG_PACKETS_ON 0x0080L /* Enable Tx/Rx packet display */
+#define DBG_FILTER1_ON 0x0100L /* Display DBG_FILTER 1 messages */
+#define DBG_FILTER2_ON 0x0200L /* Display DBG_FILTER 2 messages */
+#define DBG_FILTER3_ON 0x0400L /* Display DBG_FILTER 3 messages */
+#define DBG_FILTER4_ON 0x0800L /* Display DBG_FILTER 4 messages */
+#define DBG_BREAK_ON 0x1000L /* Enable breakpoints */
+#define DBG_TAPICALL_ON 0x4000L /* Enable TAPI call state messages */
+#define DBG_HWTEST_ON 0x8000L /* Enable hardware self-test */
+
+extern VOID
+DbgPrintData(
+ IN PUCHAR Data,
+ IN UINT NumBytes,
+ IN ULONG Offset
+ );
+
+extern VOID NTAPI DbgBreakPoint(VOID);
+
+#if defined(DBG) && (DBG != 0)
+
+/*
+// A - is a pointer to the adapter structure
+// S - is a parenthesised printf string
+// e.g. DBG_PRINT(Adap,("ERR=%d",err));
+// F - is a function name
+// e.g. DBG_FUNC("FunctionName")
+// C - is a C conditional
+// e.g. ASSERT(a <= b)
+*/
+
+# define BREAKPOINT DbgBreakPoint()
+
+# define STATIC
+
+# define DBG_FUNC(F) static const char __FUNC__[] = F;
+
+# define DBG_BREAK(A) {if ((A)->DbgFlags & DBG_BREAK_ON) BREAKPOINT;}
+
+// WARNING DBG_PRINT(A,S) (A) can be NULL!!!
+# define DBG_PRINT(A,S) {DbgPrint("%s---%s @ %s:%d\n",(A)?(A)->DbgID:"?",__FUNC__,__FILE__,__LINE__);DbgPrint S;}
+
+# define DBG_ENTER(A) {if ((A)->DbgFlags & DBG_TRACE_ON) \
+ {DbgPrint("%s>>>%s\n",(A)->DbgID,__FUNC__);}}
+
+# define DBG_TRACE(A) {if ((A)->DbgFlags & DBG_TRACE_ON) \
+ {DbgPrint("%s---%s:%d\n",(A)->DbgID,__FUNC__,__LINE__);}}
+
+# define DBG_LEAVE(A) {if ((A)->DbgFlags & DBG_TRACE_ON) \
+ {DbgPrint("%s<<<%s\n",(A)->DbgID,__FUNC__);}}
+
+# define DBG_ERROR(A,S) {if ((A)->DbgFlags & DBG_ERROR_ON) \
+ {DbgPrint("%s---%s: ERROR: ",(A)->DbgID,__FUNC__);DbgPrint S;}}
+
+# define DBG_WARNING(A,S) {if ((A)->DbgFlags & DBG_WARNING_ON) \
+ {DbgPrint("%s---%s: WARNING: ",(A)->DbgID,__FUNC__);DbgPrint S;}}
+
+# define DBG_NOTICE(A,S) {if ((A)->DbgFlags & DBG_NOTICE_ON) \
+ {DbgPrint("%s---%s: NOTICE: ",(A)->DbgID,__FUNC__);DbgPrint S;}}
+
+# define DBG_FILTER(A,M,S){if ((A)->DbgFlags & (M)) \
+ {DbgPrint("%s---%s: ",(A)->DbgID,__FUNC__);DbgPrint S;}}
+
+# define DBG_DISPLAY(S) {DbgPrint("?---%s: ",__FUNC__); DbgPrint S;}
+
+#ifdef ASSERT
+#undef ASSERT
+#endif
+#define ASSERT(C) if (!(C)) { \
+ DbgPrint("!---%s: ASSERT(%s) FAILED!\n%s #%d\n", \
+ __FUNC__, #C, __FILE__, __LINE__); \
+ BREAKPOINT; \
+ }
+#else
+
+# define BREAKPOINT
+# define STATIC static
+# define DBG_FUNC(F)
+# define DBG_BREAK
+# define DBG_PRINT(A,S)
+# define DBG_ENTER(A)
+# define DBG_TRACE(A)
+# define DBG_LEAVE(A)
+# define DBG_ERROR(A,S)
+# define DBG_WARNING(A,S)
+# define DBG_NOTICE(A,S)
+# define DBG_FILTER(A,M,S)
+# define DBG_DISPLAY(S)
+
+#endif
+
+#endif
diff --git a/private/ntos/ndis/htdsu/htdsu.c b/private/ntos/ndis/htdsu/htdsu.c
new file mode 100644
index 000000000..a1a48258d
--- /dev/null
+++ b/private/ntos/ndis/htdsu/htdsu.c
@@ -0,0 +1,1395 @@
+/***************************************************************************\
+|* Copyright (c) 1994 Microsoft Corporation *|
+|* Developed for Microsoft by TriplePoint, Inc. Beaverton, Oregon *|
+|* *|
+|* This file is part of the HT Communications DSU41 WAN Miniport Driver. *|
+\***************************************************************************/
+#include "version.h"
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Module Name:
+
+ htdsu.c
+
+Abstract:
+
+ This module contains the DriverEntry() routine, which is the first
+ routine called when the driver is loaded into memory. The Miniport
+ initialization and termination routines are also implemented here:
+ MiniportInitialize()
+ MiniportHalt()
+
+ This driver conforms to the NDIS 3.0 Miniport interface.
+
+Author:
+
+ Larry Hattery - TriplePoint, Inc. (larryh@tpi.com) Jun-94
+
+Environment:
+
+ Windows NT 3.5 kernel mode Miniport driver or equivalent.
+
+Revision History:
+
+---------------------------------------------------------------------------*/
+
+#define __FILEID__ 1 // Unique file ID for error logging
+
+#include "htdsu.h"
+
+/*
+// This is defined here to avoid including all of ntddk.h which cannot
+// normally be included by a miniport driver.
+*/
+extern
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlUnicodeStringToAnsiString(
+ PANSI_STRING out,
+ PUNICODE_STRING in,
+ BOOLEAN allocate
+ );
+
+/*
+// Receives the context value representing the Miniport wrapper
+// as returned from NdisMInitializeWrapper.
+*/
+static NDIS_HANDLE
+NdisWrapperHandle = NULL;
+
+/*
+// This constant is used for places where NdisAllocateMemory needs to be
+// called and the HighestAcceptableAddress does not matter.
+*/
+static NDIS_PHYSICAL_ADDRESS
+HighestAcceptableAddress = NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
+
+/*
+// This is used to assign a unique instance number to each adapter.
+*/
+static UCHAR
+HtDsuAdapterCount = 0;
+
+/*
+// Tell the compiler which routines can be unloaded after initialization.
+*/
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+#pragma NDIS_INIT_FUNCTION(DriverEntry)
+
+/*
+// Tell the compiler which routines can be paged out.
+// These can never be called from interrupt or DPC level!
+*/
+NDIS_STATUS
+HtDsuInitialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ );
+#pragma NDIS_PAGABLE_FUNCTION(HtDsuInitialize)
+
+NDIS_STATUS
+HtDsuRegisterAdapter(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PSTRING AddressList
+ );
+#pragma NDIS_PAGABLE_FUNCTION(HtDsuRegisterAdapter)
+
+VOID
+HtDsuHalt(
+ IN PHTDSU_ADAPTER Adapter
+ );
+#pragma NDIS_PAGABLE_FUNCTION(HtDsuHalt)
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ The DriverEntry routine is the main entry point for the driver.
+ It is responsible for the initializing the Miniport wrapper and
+ registering the driver with the Miniport wrapper.
+
+Parameters:
+
+ DriverObject _ Pointer to driver object created by the system.
+
+ RegistryPath _ Pointer to registery path name used to read registry
+ parameters.
+
+Return Values:
+
+ STATUS_SUCCESS
+ STATUS_UNSUCCESSFUL
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtDsuDriverEntry")
+
+ /*
+ // Receives the status of the NdisMWanRegisterMiniport operation.
+ */
+ NDIS_STATUS Status;
+
+ /*
+ // Characteristics table passed to NdisMWanRegisterMiniport.
+ */
+ NDIS_WAN_MINIPORT_CHARACTERISTICS HtDsuChar;
+
+#if DBG
+ DbgPrint("?>>>%s: Build Date:"__DATE__" Time:"__TIME__"\n",__FUNC__);
+#endif
+
+ /*
+ // Initialize the Miniport wrapper - THIS MUST BE THE FIRST NDIS CALL.
+ */
+ NdisMInitializeWrapper(
+ &NdisWrapperHandle,
+ DriverObject,
+ RegistryPath,
+ NULL
+ );
+
+ /*
+ // Initialize the characteristics table, exporting the Miniport's entry
+ // points to the Miniport wrapper.
+ */
+ HtDsuChar.MajorNdisVersion = NDIS_MAJOR_VERSION;
+ HtDsuChar.MinorNdisVersion = NDIS_MINOR_VERSION;
+ HtDsuChar.Reserved = NDIS_USE_WAN_WRAPPER;
+
+ HtDsuChar.CheckForHangHandler = HtDsuCheckForHang;
+ HtDsuChar.DisableInterruptHandler = HtDsuDisableInterrupt;
+ HtDsuChar.EnableInterruptHandler = HtDsuEnableInterrupt;
+ HtDsuChar.HaltHandler = HtDsuHalt;
+ HtDsuChar.HandleInterruptHandler = HtDsuHandleInterrupt;
+ HtDsuChar.InitializeHandler = HtDsuInitialize;
+ HtDsuChar.ISRHandler = HtDsuISR;
+ HtDsuChar.QueryInformationHandler = HtDsuQueryInformation;
+ HtDsuChar.ReconfigureHandler = NULL; // Hardware not reconfigurable
+ HtDsuChar.ResetHandler = HtDsuReset;
+ HtDsuChar.WanSendHandler = HtDsuWanSend;
+ HtDsuChar.SetInformationHandler = HtDsuSetInformation;
+ HtDsuChar.TransferDataHandler = NULL; // Not used by WAN drivers
+
+ /*
+ // Register the driver with the Miniport wrapper.
+ */
+ Status = NdisMRegisterMiniport(
+ NdisWrapperHandle,
+ (PNDIS_MINIPORT_CHARACTERISTICS) &HtDsuChar,
+ sizeof(HtDsuChar)
+ );
+
+ /*
+ // The driver will not load if this call fails.
+ // The system will log the error for us.
+ */
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DBG_DISPLAY(("ERROR: NdisMRegisterMiniport Status=%Xh\n",Status));
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+
+NDIS_STATUS
+HtDsuInitialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ The MiniportInitialize request is called to have the Miniport driver
+ initialize the adapter.
+
+ No other request will be outstanding on the Miniport when this routine
+ is called. No other request will be submitted to the Miniport until
+ the operation is completed.
+
+ The wrapper will supply an array containing a list of the media types
+ that it supports. The Miniport driver reads this array and returns
+ the index of the media type that the wrapper should treat her as.
+ If the Miniport driver is impersonating a media type that is different
+ from the true media type, this must be done completely transparently to
+ the wrapper.
+
+ If the Miniport driver cannot find a media type supported by both it
+ and the wrapper, it returns NDIS_STATUS_UNSUPPORTED_MEDIA.
+
+ The status value NDIS_STATUS_OPEN_ERROR has a special meaning. It
+ indicates that the OpenErrorStatus parameter has returned a valid status
+ which the wrapper can examine to obtain more information about the error.
+
+ This routine is called with interrupts enabled, and a call to MiniportISR
+ will occur if the adapter generates any interrupts. During this routine
+ MiniportDisableInterrupt and MiniportEnableInterrupt will not be called,
+ so it is the responsibility of the Miniport driver to acknowledge and
+ clear any interrupts generated.
+
+Parameters:
+
+ OpenErrorStatus _ Returns more information about the reason for the
+ failure. Currently, the only values defined match those
+ specified as Open Error Codes in Appendix B of the IBM
+ Local Area Network Technical Reference.
+
+ SelectedMediumIndex _ Returns the index in MediumArray of the medium type
+ that the Miniport driver wishes to be viewed as.
+ Note that even though the NDIS interface may complete
+ this request asynchronously, it must return this
+ index on completion of this function.
+
+ MediumArray _ An array of medium types which the wrapper supports.
+
+ MediumArraySize _ The number of elements in MediumArray.
+
+ MiniportAdapterHandle _ A handle identifying the Miniport. The Miniport
+ driver must supply this handle in future requests
+ that refer to the Miniport.
+
+ WrapperConfigurationContext _ The handle used for calls to NdisOpenConfiguration,
+ and the routines in section 4 of this document.
+
+Return Values:
+
+ NDIS_STATUS_ADAPTER_NOT_FOUND
+ NDIS_STATUS_FAILURE
+ NDIS_STATUS_NOT_ACCEPTED
+ NDIS_STATUS_OPEN_ERROR
+ NDIS_STATUS_RESOURCES
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_UNSUPPORTED_MEDIA
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtDsuInitialize")
+
+ /*
+ // Holds the status result returned from an NDIS function call.
+ */
+ NDIS_STATUS Status;
+
+ /*
+ // Pointer to our newly allocated adapter.
+ */
+ PHTDSU_ADAPTER Adapter;
+
+ /*
+ // The handle for reading from the registry.
+ */
+ NDIS_HANDLE ConfigHandle;
+
+ /*
+ // The value read from the registry.
+ */
+ PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
+
+ UINT index;
+
+ /*
+ // Define all the parameters that will be read.
+ */
+ NDIS_STRING RamBaseString = HTDSU_PARAM_RAMBASE_STRING;
+ ULONG RamBaseAddress = 0;
+
+ NDIS_STRING InterruptString = HTDSU_PARAM_INTERRUPT_STRING;
+ CCHAR InterruptNumber = 0;
+
+ NDIS_STRING LineTypeString = HTDSU_PARAM_LINETYPE_STRING;
+ CCHAR LineType = 0;
+
+ NDIS_STRING LineRateString = HTDSU_PARAM_LINERATE_STRING;
+ USHORT LineRate = 0;
+
+ NDIS_STRING MediaTypeString = HTDSU_PARAM_MEDIATYPE_STRING;
+ ANSI_STRING MediaType;
+
+ NDIS_STRING DeviceNameString = HTDSU_PARAM_DEVICENAME_STRING;
+ ANSI_STRING DeviceName;
+
+ NDIS_STRING AddressListString = HTDSU_PARAM_ADDRLIST_STRING;
+ ANSI_STRING AddressList;
+
+#if DBG
+ NDIS_STRING DbgFlagsString = HTDSU_PARAM_DBGFLAGS_STRING;
+ ULONG DbgFlags = 0;
+#endif
+
+ /*
+ // Search the MediumArray for the WAN media type.
+ */
+ for (index = 0; index < MediumArraySize; index++)
+ {
+ if (MediumArray[index] == NdisMediumWan)
+ {
+ break;
+ }
+ }
+
+ /*
+ // Return if no supported medium is found.
+ */
+ if (index >= MediumArraySize)
+ {
+ DBG_DISPLAY(("ERROR: No medium found (array=%X,size=%d)\n",
+ MediumArray, MediumArraySize));
+ /*
+ // Log error message and exit.
+ */
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
+ 3,
+ index,
+ __FILEID__,
+ __LINE__
+ );
+ return NDIS_STATUS_UNSUPPORTED_MEDIA;
+ }
+
+ /*
+ // Save the selected medium type.
+ */
+ *SelectedMediumIndex = index;
+
+ /*
+ // Open the configuration registry so we can get our config values.
+ */
+ NdisOpenConfiguration(
+ &Status,
+ &ConfigHandle,
+ WrapperConfigurationContext
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DBG_DISPLAY(("ERROR: NdisOpenConfiguration failed (Status=%X)\n",Status));
+ /*
+ // Log error message and exit.
+ */
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
+ 3,
+ Status,
+ __FILEID__,
+ __LINE__
+ );
+ return NDIS_STATUS_FAILURE;
+ }
+
+ /********************************************************************
+ // Get InterruptNumber for this adapter.
+ */
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &InterruptString,
+ NdisParameterInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ InterruptNumber = (CCHAR)(ReturnedValue->ParameterData.IntegerData);
+ }
+ else
+ {
+ DBG_DISPLAY(("ERROR: NdisReadConfiguration(InterruptNumber) failed (Status=%X)\n",Status));
+ /*
+ // Log error message and exit.
+ */
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER,
+ 3,
+ Status,
+ __FILEID__,
+ __LINE__
+ );
+ NdisCloseConfiguration(ConfigHandle);
+ return NDIS_STATUS_FAILURE;
+ }
+
+ /*
+ // Make sure the interrupt IRQ is valid.
+ */
+ if ((InterruptNumber != HTDSU_PARAM_IRQ03) &&
+ (InterruptNumber != HTDSU_PARAM_IRQ04) &&
+ (InterruptNumber != HTDSU_PARAM_IRQ10) &&
+ (InterruptNumber != HTDSU_PARAM_IRQ11) &&
+ (InterruptNumber != HTDSU_PARAM_IRQ12) &&
+ (InterruptNumber != HTDSU_PARAM_IRQ15))
+ {
+ DBG_DISPLAY(("ERROR: Invalid InterruptNumber=%d)\n",InterruptNumber));
+ /*
+ // Log error message and exit.
+ */
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
+ 3,
+ InterruptNumber,
+ __FILEID__,
+ __LINE__
+ );
+ NdisCloseConfiguration(ConfigHandle);
+ return NDIS_STATUS_FAILURE;
+ }
+
+ /********************************************************************
+ // Get RambaseAddress for this adapter.
+ */
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &RamBaseString,
+ NdisParameterHexInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ RamBaseAddress = (ULONG)(ReturnedValue->ParameterData.IntegerData);
+ }
+ else
+ {
+ DBG_DISPLAY(("ERROR: NdisReadConfiguration(RamBaseAddress) failed (Status=%X)\n",Status));
+ /*
+ // Log error message and exit.
+ */
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER,
+ 3,
+ Status,
+ __FILEID__,
+ __LINE__
+ );
+ NdisCloseConfiguration(ConfigHandle);
+ return NDIS_STATUS_FAILURE;
+ }
+
+ /*
+ // Make sure the RambaseAddress is valid.
+ */
+ if ((RamBaseAddress != HTDSU_PARAM_RAMBASE1) &&
+ (RamBaseAddress != HTDSU_PARAM_RAMBASE2) &&
+ (RamBaseAddress != HTDSU_PARAM_RAMBASE3) &&
+ (RamBaseAddress != HTDSU_PARAM_RAMBASE4))
+ {
+ DBG_DISPLAY(("ERROR: Invalid RamBaseAddress=%Xh\n",RamBaseAddress));
+ /*
+ // Log error message and exit.
+ */
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
+ 3,
+ RamBaseAddress,
+ __FILEID__,
+ __LINE__
+ );
+ NdisCloseConfiguration(ConfigHandle);
+ return NDIS_STATUS_FAILURE;
+ }
+
+ /********************************************************************
+ // Get MediaType for this adapter.
+ // The MediaType and DeviceName values are used to construct the
+ // ProviderInfo strings required by HtTapiGetDevCaps.
+ */
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &MediaTypeString,
+ NdisParameterString
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ RtlUnicodeStringToAnsiString(
+ &MediaType,
+ &(ReturnedValue->ParameterData.StringData),
+ TRUE
+ );
+ }
+ else
+ {
+ DBG_DISPLAY(("ERROR: NdisReadConfiguration(MediaType) failed (Status=%X)\n",Status));
+ /*
+ // Log error message and exit.
+ */
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER,
+ 3,
+ Status,
+ __FILEID__,
+ __LINE__
+ );
+ NdisCloseConfiguration(ConfigHandle);
+ return NDIS_STATUS_FAILURE;
+ }
+
+ /********************************************************************
+ // Get DeviceName for this adapter.
+ // The MediaType and DeviceName values are used to construct the
+ // ProviderInfo strings required by HtTapiGetDevCaps.
+ */
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &DeviceNameString,
+ NdisParameterString
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ RtlUnicodeStringToAnsiString(
+ &DeviceName,
+ &(ReturnedValue->ParameterData.StringData),
+ TRUE
+ );
+ }
+ else
+ {
+ DBG_DISPLAY(("ERROR: NdisReadConfiguration(DeviceName) failed (Status=%X)\n",Status));
+ /*
+ // Log error message and exit.
+ */
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER,
+ 3,
+ Status,
+ __FILEID__,
+ __LINE__
+ );
+ NdisCloseConfiguration(ConfigHandle);
+ return NDIS_STATUS_FAILURE;
+ }
+
+ /********************************************************************
+ // Get AddressList for this adapter.
+ */
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &AddressListString,
+ NdisParameterString
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ RtlUnicodeStringToAnsiString(
+ &AddressList,
+ &(ReturnedValue->ParameterData.StringData),
+ TRUE
+ );
+ }
+ else
+ {
+ DBG_DISPLAY(("ERROR: NdisReadConfiguration(AddressList) failed (Status=%X)\n",Status));
+ /*
+ // Log error message and exit.
+ */
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER,
+ 3,
+ Status,
+ __FILEID__,
+ __LINE__
+ );
+ NdisCloseConfiguration(ConfigHandle);
+ return NDIS_STATUS_FAILURE;
+ }
+
+#ifdef USE_LEASED_LINE
+ /********************************************************************
+ // Get LineType for this adapter.
+ */
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &LineTypeString,
+ NdisParameterInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ LineType = (CCHAR)(ReturnedValue->ParameterData.IntegerData);
+ }
+ else
+ {
+ DBG_DISPLAY(("ERROR: NdisReadConfiguration(LineType) failed (Status=%X)\n",Status));
+ LineType = HTDSU_LINEMODE_DIALUP;
+ }
+
+ /*
+ // Make sure the LineType is valid.
+ */
+ if ((LineType != HTDSU_LINEMODE_LEASED) &&
+ (LineType != HTDSU_LINEMODE_DIALUP))
+ {
+ DBG_DISPLAY(("ERROR: Invalid LineType=%d\n",LineType));
+ /*
+ // Log error message and exit.
+ */
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
+ 3,
+ LineType,
+ __FILEID__,
+ __LINE__
+ );
+ NdisCloseConfiguration(ConfigHandle);
+ return NDIS_STATUS_FAILURE;
+ }
+#else
+ LineType = HTDSU_LINEMODE_DIALUP;
+#endif // USE_LEASED_LINE
+
+ /********************************************************************
+ // Get LineRate for this adapter.
+ */
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &LineRateString,
+ NdisParameterInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ LineRate = (USHORT)(ReturnedValue->ParameterData.IntegerData);
+ }
+ else
+ {
+ DBG_DISPLAY(("ERROR: NdisReadConfiguration(LineRate) failed (Status=%X)\n",Status));
+ LineRate = 1;
+ }
+
+ /*
+ // Make sure the LineRate is valid.
+ */
+ LineRate = HTDSU_CMD_TX_RATE_MAX + (LineRate << 4);
+ if ((LineRate != HTDSU_CMD_TX_RATE_MAX) &&
+ (LineRate != HTDSU_CMD_TX_RATE_57600) &&
+ (LineRate != HTDSU_CMD_TX_RATE_38400) &&
+ (LineRate != HTDSU_CMD_TX_RATE_19200) &&
+ (LineRate != HTDSU_CMD_TX_RATE_9600))
+ {
+ DBG_DISPLAY(("ERROR: Invalid LineRate=%d\n",LineRate));
+ /*
+ // Log error message and exit.
+ */
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
+ 3,
+ LineRate,
+ __FILEID__,
+ __LINE__
+ );
+ NdisCloseConfiguration(ConfigHandle);
+ return NDIS_STATUS_FAILURE;
+ }
+
+#if DBG
+ /********************************************************************
+ // Get DbgFlags for this adapter.
+ */
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &DbgFlagsString,
+ NdisParameterHexInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ DbgFlags = (ULONG)(ReturnedValue->ParameterData.IntegerData);
+ }
+ else
+ {
+ DbgFlags = 0;
+ }
+#endif
+
+ /*
+ // Close the configuration registry - we're done with it.
+ */
+ NdisCloseConfiguration(ConfigHandle);
+
+ /*
+ // Allocate memory for the adapter information structure.
+ */
+ Status = NdisAllocateMemory(
+ (PVOID *)&Adapter,
+ sizeof(*Adapter),
+ 0,
+ HighestAcceptableAddress
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DBG_DISPLAY(("ERROR: NdisAllocateMemory(Size=%d) failed (Status=%X)\n",
+ sizeof(*Adapter), Status));
+ /*
+ // Log error message and exit.
+ */
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 3,
+ Status,
+ __FILEID__,
+ __LINE__
+ );
+ return NDIS_STATUS_FAILURE;
+ }
+
+ /*
+ // Init the adapter structure values to NULL.
+ */
+ NdisZeroMemory (Adapter, sizeof(*Adapter));
+
+ /*
+ // Assign a unique ID to this adapter instance.
+ */
+ Adapter->InstanceNumber = ++HtDsuAdapterCount;
+
+ /*
+ // We use the adapter id number in debug messages to help when debugging
+ // with multiple adapters.
+ */
+#if DBG
+ Adapter->DbgID[0] = (0x0F & HtDsuAdapterCount) + '0';
+ Adapter->DbgID[1] = 0;
+ Adapter->DbgFlags = DbgFlags;
+#endif
+
+ DBG_DISPLAY(("HTDSU41(Adap=%08Xh,Ram=%05lXh,RamSiz=%04Xh,BufSiz=%04Xh,IRQ=%d)\n",
+ Adapter, RamBaseAddress, HTDSU_MEMORY_SIZE,
+ sizeof(HTDSU_BUFFER), InterruptNumber));
+
+ /*
+ // Make sure the adapter memory structure is sized properly.
+ */
+ ASSERT(sizeof(HTDSU_BUFFER) == 2016);
+ ASSERT(HTDSU_MEMORY_SIZE == 4096);
+
+ /*
+ // Save the config parameters in the adapter structure.
+ */
+ Adapter->MiniportAdapterHandle = MiniportAdapterHandle;
+ Adapter->InterruptNumber = InterruptNumber;
+ Adapter->LineType = LineType;
+ Adapter->LineRate = LineRate;
+ Adapter->MemorySize = HTDSU_MEMORY_SIZE;
+ NdisSetPhysicalAddressLow(Adapter->PhysicalAddress, RamBaseAddress);
+ NdisSetPhysicalAddressHigh(Adapter->PhysicalAddress, 0);
+
+ /*
+ // Construct the "MediaType\0DeviceName" string for use by TAPI.
+ */
+ strcpy(Adapter->ProviderInfo, MediaType.Buffer);
+ strcpy(Adapter->ProviderInfo + MediaType.Length + 1, DeviceName.Buffer);
+ DBG_NOTICE(Adapter, ("Media=%s Device=%s\n",
+ Adapter->ProviderInfo,
+ &Adapter->ProviderInfo[MediaType.Length + 1]
+ ));
+ Adapter->ProviderInfoSize = MediaType.Length + 1 + DeviceName.Length + 1;
+
+ /*
+ // Now it's time to initialize the hardware resources.
+ */
+ Status = HtDsuRegisterAdapter(Adapter, &AddressList);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ HtDsuHalt(Adapter);
+ }
+
+ DBG_DISPLAY(("RETURN: Status=%Xh\n",Status));
+
+ return Status;
+}
+
+
+NDIS_STATUS
+HtDsuRegisterAdapter(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PSTRING AddressList
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This function is called when a new adapter is being registered. It
+ initializes the adapter information structure, allocate any resources
+ needed by the adapter/driver, registers with the wrapper, and initializes
+ the physical adapter.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ AddressList _ This is a list of MULTI_SZ strings which are to be assigned
+ to each link for use by TAPI HtTapiGetAddressCaps.
+
+Return Values:
+
+ NDIS_STATUS_ADAPTER_NOT_FOUND
+ NDIS_STATUS_FAILURE
+ NDIS_STATUS_NOT_ACCEPTED
+ NDIS_STATUS_OPEN_ERROR
+ NDIS_STATUS_RESOURCES
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_UNSUPPORTED_MEDIA
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtDsuRegisterAdapter")
+
+ /*
+ // Holds the status result returned from an NDIS function call.
+ */
+ NDIS_STATUS Status;
+
+ DBG_ENTER(Adapter);
+
+ /*
+ // Initialize the WAN information structure to match the capabilities of
+ // the adapter.
+ */
+ Adapter->WanInfo.MaxFrameSize = HTDSU_MAX_FRAME_SIZE;
+ Adapter->WanInfo.MaxTransmit = HTDSU_MAX_TRANSMITS;
+
+ /*
+ // Since we copy the packets to/from adapter RAM, no padding information is
+ // needed in the WAN packets we get. We can just use adapter RAM as needed.
+ */
+ Adapter->WanInfo.HeaderPadding = 0;
+ Adapter->WanInfo.TailPadding = 0;
+
+ /*
+ // This value indicates how many point to point connections are allowed
+ // per WAN link. Currently, the WAN wrapper only supports 1 line per link.
+ */
+ Adapter->WanInfo.Endpoints = 1;
+
+ /*
+ // Transmits and received are copied to/from adapter RAM so cached memory
+ // can be used for packet allocation and we don't really care if it's
+ // physically contiguous or not, as long as it's virtually contiguous.
+ */
+ Adapter->WanInfo.MemoryFlags = 0;
+ Adapter->WanInfo.HighestAcceptableAddress = HighestAcceptableAddress;
+
+ /*
+ // We only support point to point framing, and we don't need to see the
+ // address or control fields. The TAPI_PROVIDER bit is set to indicate
+ // that we can accept the TAPI OID requests.
+ */
+ Adapter->WanInfo.FramingBits = PPP_FRAMING |
+ PPP_COMPRESS_ADDRESS_CONTROL |
+ PPP_COMPRESS_PROTOCOL_FIELD |
+ TAPI_PROVIDER;
+ /*
+ // This value is ignored by this driver, but its default behavior is such
+ // that all these control bytes would appear to be handled transparently.
+ */
+ Adapter->WanInfo.DesiredACCM = 0;
+
+ /*
+ // Inform the wrapper of the physical attributes of this adapter.
+ // This must be called before any NdisMRegister functions!
+ // This call also associates the MiniportAdapterHandle with this Adapter.
+ */
+ NdisMSetAttributes(
+ Adapter->MiniportAdapterHandle,
+ (NDIS_HANDLE)Adapter,
+ FALSE, // Not a BusMaster
+ NdisInterfaceIsa
+ );
+
+ /*
+ // Map the adapter's physical location into the system address space.
+ */
+ Status = NdisMMapIoSpace(
+ &Adapter->VirtualAddress,
+ Adapter->MiniportAdapterHandle,
+ Adapter->PhysicalAddress,
+ Adapter->MemorySize
+ );
+ DBG_NOTICE(Adapter, ("NdisMMapIoSpace(\n"
+ "VirtualAddress =%Xh\n"
+ "MiniportAdapterHandle=%Xh\n"
+ "PhysicalAddress =%X:%Xh\n"
+ "MemorySize =%Xh\n",
+ Adapter->VirtualAddress,
+ Adapter->MiniportAdapterHandle,
+ Adapter->PhysicalAddress,
+ Adapter->MemorySize
+ ));
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DBG_ERROR(Adapter,("NdisMMapIoSpace failed (status=%Xh)\n",Status));
+ /*
+ // Log error message and exit.
+ */
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 3,
+ Status,
+ __FILEID__,
+ __LINE__
+ );
+ goto EarlyOut;
+ }
+
+ Adapter->AdapterRam = (PHTDSU_REGISTERS) Adapter->VirtualAddress;
+
+ /*
+ // This is how we protect the driver from being re-entered when
+ // it's not safe to do so. Such as on a timer thread. Normally,
+ // the wrapper provides protection from re-entrancy, so SpinLocks
+ // are not needed. However, if your adapter requires asynchronous
+ // timer support routines, you will have to provide your own
+ // synchronization.
+ */
+ NdisAllocateSpinLock(&Adapter->Lock);
+
+ /*
+ // Set both the transmit busy and transmit idle lists to empty.
+ */
+ InitializeListHead(&Adapter->TransmitIdleList);
+ InitializeListHead(&Adapter->TransmitBusyList);
+
+ /*
+ // Initialize the interrupt - it can be disabled, but cannot be shared.
+ */
+ Status = NdisMRegisterInterrupt(
+ &Adapter->Interrupt,
+ Adapter->MiniportAdapterHandle,
+ Adapter->InterruptNumber,
+ Adapter->InterruptNumber,
+ FALSE, /* We don't need a call to the ISR */
+ FALSE, /* Interrupt is not sharable */
+ NdisInterruptLatched
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DBG_ERROR(Adapter,("NdisMRegisterInterrupt failed (status=%Xh)\n",Status));
+ /*
+ // Log error message and exit.
+ */
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_INTERRUPT_CONNECT,
+ 3,
+ Status,
+ __FILEID__,
+ __LINE__
+ );
+ goto EarlyOut;
+ }
+
+ /*
+ // Try to initialize the adapter hardware.
+ */
+#if DBG
+ Status = CardInitialize(Adapter,
+ (BOOLEAN) ((Adapter->DbgFlags & DBG_HWTEST_ON) ?
+ TRUE : FALSE));
+#else
+ Status = CardInitialize(Adapter, FALSE);
+#endif
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DBG_ERROR(Adapter,("CardInitialize failed (status=%Xh)\n",Status));
+ /*
+ // Error message was already logged.
+ */
+ goto EarlyOut;
+ }
+
+ /*
+ // Initialize the adapter link structures.
+ */
+ LinkInitialize(Adapter, AddressList);
+
+#ifdef USE_LEASED_LINE
+ if (Adapter->LineType == HTDSU_LINEMODE_LEASED)
+ {
+ /*
+ // Go ahead and allocate the lines and indicate them as up so we can
+ // work with leased line mode.
+ */
+ PHTDSU_LINK Link;
+
+ if (CardStatusOnLine(Adapter, HTDSU_CMD_LINE1))
+ {
+ Link = LinkAllocate(Adapter, NULL, HTDSU_LINE1_ID);
+ LinkLineUp(Link);
+ }
+ if ((Adapter->NumLineDevs == HTDSU_NUM_LINKS) &&
+ CardStatusOnLine(Adapter, HTDSU_CMD_LINE2))
+ {
+ Link = LinkAllocate(Adapter, NULL, HTDSU_LINE2_ID);
+ LinkLineUp(Link);
+ }
+ }
+#endif // USE_LEASED_LINE
+
+EarlyOut:
+
+ DBG_LEAVE(Adapter);
+
+ return Status;
+}
+
+
+VOID
+HtDsuHalt(
+ IN PHTDSU_ADAPTER Adapter
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ The MiniportHalt request is used to halt the adapter such that it is
+ no longer functioning. The Miniport driver should stop the adapter
+ and deregister all of its resources before returning from this routine.
+
+ It is not necessary for the Miniport to complete all outstanding
+ requests and no other requests will be submitted to the Miniport
+ until the operation is completed.
+
+ Interrupts are enabled during the call to this routine.
+
+Parameters:
+
+ MiniportAdapterContext _ The adapter handle passed to NdisMSetAttributes
+ during MiniportInitialize.
+
+Return Values:
+
+ None.
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtDsuHalt")
+
+ /*
+ // We use this message to make sure TAPI is cleaned up.
+ */
+ NDIS_TAPI_PROVIDER_SHUTDOWN TapiShutDown;
+
+ DBG_ENTER(Adapter);
+
+ /*
+ // Make sure all the lines are hungup and indicated.
+ // This should already be the case, but let's be sure.
+ */
+ TapiShutDown.ulRequestID = OID_TAPI_PROVIDER_SHUTDOWN;
+ HtTapiProviderShutdown(Adapter, &TapiShutDown);
+
+ /*
+ // Disconnect the interrupt line.
+ */
+ if (*(PULONG)&(Adapter->Interrupt))
+ {
+ NdisMDeregisterInterrupt(&Adapter->Interrupt);
+ }
+
+ /*
+ // Unmap the adapter memory from the system.
+ */
+ if (Adapter->VirtualAddress != NULL)
+ {
+ NdisMUnmapIoSpace(
+ Adapter->MiniportAdapterHandle,
+ Adapter->VirtualAddress,
+ Adapter->MemorySize
+ );
+ }
+
+ /*
+ // Free the lock we aquired at startup.
+ */
+ if (*(PULONG)&(Adapter->Lock))
+ {
+ // FIXME - the latest version of NDIS does not define NdisFreeSpinLock
+ // NdisFreeSpinLock(&Adapter->Lock);
+ }
+
+ DBG_LEAVE(Adapter);
+
+ /*
+ // Free adapter instance.
+ */
+ --HtDsuAdapterCount;
+ NdisFreeMemory(Adapter, sizeof(*Adapter), 0);
+}
+
+#ifdef RECONFIGURE_SUPPORTED
+
+
+NDIS_STATUS
+HtDsuReconfigure(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ IN PHTDSU_ADAPTER Adapter,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This routine is called to have the Miniport reconfigure the adapter
+ to the new parameters available via the NDIS configuration routines.
+ Used to support plug and play adapters and software configurable
+ adapters, which may have the parameters changed during runtime. If
+ the Miniport driver does not support dynamic reconfiguration, then
+ the entry for W_RECONFIGURE_HANDLER in the NDIS_WIDGET_CHARACTERISTICS
+ should be NULL.
+
+ No other request will be outstanding on the Miniport when this routine
+ is called. No other request will be submitted to the Miniport until
+ the operation is completed.
+
+ The status value NDIS_STATUS_OPEN_ERROR has a special meaning. It
+ indicates that the OpenErrorStatus parameter has returned a valid
+ status which the wrapper can examine to obtain more information about
+ the error.
+
+ This routine is called with interrupts enabled, and a call to MiniportISR
+ will occur if the adapter generates any interrupts. As long as this
+ routine is executing MiniportDisableInterrupt and MiniportEnableInterrupt
+ will not be called, so it is the responsibility of the Miniport driver
+ to acknowledge and clear any interrupts generated.
+
+Parameters:
+
+ OpenErrorStatus _ Returns more information about the reason for the
+ failure. Currently, the only values defined match
+ those specified as Open Error Codes in Appendix B
+ of the IBM Local Area Network Technical Reference.
+
+ MiniportAdapterContext _ The adapter handle passed to NdisMSetAttributes
+ during MiniportInitialize.
+
+ WrapperConfigurationContext _ The handle to use for calls to
+ NdisOpenConfiguration, and the routines
+ in section 4 of this document.
+
+Return Values:
+
+ NDIS_STATUS_FAILURE
+ NDIS_STATUS_NOT_ACCEPTED
+ NDIS_STATUS_SUCCESS
+
+---------------------------------------------------------------------------*/
+
+{
+ return (NDIS_STATUS_NOT_ACCEPTED);
+}
+
+#endif // RECONFIGURE_SUPPORTED
+
+
+NDIS_STATUS
+HtDsuReset(
+ OUT PBOOLEAN AddressingReset,
+ IN PHTDSU_ADAPTER Adapter
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ The MiniportReset request instructs the Miniport driver to issue a
+ hardware reset to the network adapter. The Miniport driver also
+ resets its software state.
+
+ The MiniportReset request may also reset the parameters of the adapter.
+ If a hardware reset of the adapter resets the current station address
+ to a value other than what it is currently configured to, the Miniport
+ driver automatically restores the current station address following the
+ reset. Any multicast or functional addressing masks reset by the
+ hardware do not have to be reprogrammed by the Miniport.
+ NOTE: This is change from the NDIS 3.0 driver specification. If the
+ multicast or functional addressing information, the packet filter, the
+ lookahead size, and so on, needs to be restored, the Miniport indicates
+ this with setting the flag AddressingReset to TRUE.
+
+ It is not necessary for the Miniport to complete all outstanding requests
+ and no other requests will be submitted to the Miniport until the
+ operation is completed. Also, the Miniport does not have to signal
+ the beginning and ending of the reset with NdisMIndicateStatus.
+ NOTE: These are different than the NDIS 3.0 driver specification.
+
+ The Miniport driver must complete the original request, if the orginal
+ call to MiniportReset return NDIS_STATUS_PENDING, by calling
+ NdisMResetComplete.
+
+ If the underlying hardware does not provide a reset function under
+ software control, then this request completes abnormally with
+ NDIS_STATUS_NOT_RESETTABLE. If the underlying hardware attempts a
+ reset and finds recoverable errors, the request completes successfully
+ with NDIS_STATUS_SOFT_ERRORS. If the underlying hardware resets and,
+ in the process, finds nonrecoverable errors, the request completes
+ successfully with the status NDIS_STATUS_HARD_ERRORS. If the
+ underlying hardware reset is accomplished without any errors,
+ the request completes successfully with the status NDIS_STATUS_SUCCESS.
+
+ Interrupts are in any state during this call.
+
+Parameters:
+
+ MiniportAdapterContext _ The adapter handle passed to NdisMSetAttributes
+ during MiniportInitialize.
+
+ AddressingReset _ The Miniport indicates if the wrapper needs to call
+ MiniportSetInformation to restore the addressing
+ information to the current values by setting this
+ value to TRUE.
+
+Return Values:
+
+ NDIS_STATUS_HARD_ERRORS
+ NDIS_STATUS_NOT_ACCEPTED
+ NDIS_STATUS_NOT_RESETTABLE
+ NDIS_STATUS_PENDING
+ NDIS_STATUS_SOFT_ERRORS
+ NDIS_STATUS_SUCCESS
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtDsuReset")
+
+ /*
+ // Holds the status result returned from an NDIS function call.
+ */
+ NDIS_STATUS Status;
+
+ DBG_ENTER(Adapter);
+ DBG_BREAK(Adapter);
+
+ if (Adapter->NeedReset)
+ {
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ /*
+ // Make sure TAPI is aware of the state change so it can do the
+ // right things.
+ */
+ HtTapiResetHandler(Adapter);
+
+ /*
+ // Attempt to issue a software reset on the adapter.
+ // It will only fail if the hardware is hung forever.
+ */
+ Adapter->NeedReset = FALSE;
+ Status = CardInitialize(Adapter, FALSE);
+
+ /*
+ // If anything gose wrong here, it's very likely an unrecoverable
+ // hardware failure. So we'll just shut this thing down for good.
+ */
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DBG_ERROR(Adapter,("RESET Failed\n"));
+ Status = NDIS_STATUS_HARD_ERRORS;
+ }
+ else
+ {
+ /*
+ // If there were lines open, we must reset them back to
+ // LINECALLSTATE_IDLE, and configure them for use.
+ */
+ if (Adapter->NumOpens)
+ {
+ if (Adapter->NumOpens == 1)
+ {
+ CardLineConfig(Adapter, HTDSU_CMD_LINE1);
+ HtTapiCallStateHandler(Adapter,
+ GET_LINK_FROM_LINKINDEX(Adapter, 0),
+ LINECALLSTATE_IDLE,
+ 0);
+ Adapter->InterruptEnableFlag |= HTDSU_INTR_ALL_LINE1;
+ }
+ if (Adapter->NumOpens == 2)
+ {
+ CardLineConfig(Adapter, HTDSU_CMD_LINE2);
+ HtTapiCallStateHandler(Adapter,
+ GET_LINK_FROM_LINKINDEX(Adapter, 1),
+ LINECALLSTATE_IDLE,
+ 0);
+ Adapter->InterruptEnableFlag |= HTDSU_INTR_ALL_LINE2;
+ }
+ CardEnableInterrupt(Adapter);
+ }
+
+ DBG_WARNING(Adapter,("RESET Complete\n"));
+ *AddressingReset = TRUE;
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+ }
+ else
+ {
+ DBG_WARNING(Adapter, ("RESET Not Needed\n"));
+ }
+
+ DBG_LEAVE(Adapter);
+
+ return (Status);
+}
diff --git a/private/ntos/ndis/htdsu/htdsu.h b/private/ntos/ndis/htdsu/htdsu.h
new file mode 100644
index 000000000..d0fa6f175
--- /dev/null
+++ b/private/ntos/ndis/htdsu/htdsu.h
@@ -0,0 +1,931 @@
+/***************************************************************************\
+|* Copyright (c) 1994 Microsoft Corporation *|
+|* Developed for Microsoft by TriplePoint, Inc. Beaverton, Oregon *|
+|* *|
+|* This file is part of the HT Communications DSU41 WAN Miniport Driver. *|
+\***************************************************************************/
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Module Name:
+
+ htdsu.h
+
+Abstract:
+
+ This module defines the software structures and values used to support
+ the NDIS Minport driver on the HT DSU41 controller. It's a good place
+ to look when your trying to figure out how the driver structures are
+ related to each other.
+
+ This driver conforms to the NDIS 3.0 Miniport interface.
+
+Author:
+
+ Larry Hattery - TriplePoint, Inc. (larryh@tpi.com) Jun-94
+
+Environment:
+
+ Include this file at the top of each module in the Miniport driver.
+
+Revision History:
+
+---------------------------------------------------------------------------*/
+
+#ifndef _HTDSU_H
+#define _HTDSU_H
+
+/*
+// NDIS_MINIPORT_DRIVER must be defined before the NDIS include files.
+// Normally, it is defined on the command line by setting the C_DEFINES
+// variable in the sources build file.
+*/
+#include <ndis.h>
+#include <ndiswan.h>
+#include <pshpack1.h> // Force packing on variable length structures
+# include <ndistapi.h>
+#include <poppack.h>
+#include <string.h>
+
+/*
+// Include everything here so the driver modules can just include this
+// file and get all they need.
+*/
+#include "debug.h"
+#include "card.h"
+#include "keywords.h"
+
+/*
+// This constant is the maximum NdisStallExecution time allowed to be used
+// in an NDIS driver. If you need longer delays, you must wrap the call
+// in a loop.
+*/
+#define _100_MICROSECONDS 100
+
+/*
+// The link speeds we support.
+*/
+#define _64KBPS 64000
+#define _56KBPS 57600
+
+/*
+// How many logical links does this driver support. Actually, this driver
+// defines logical links to be 1:1 with physical links. You are free to
+// model them however is appropriate for your adapter.
+*/
+#define HTDSU_NUM_LINKS 2
+
+/*
+// In this driver, there is only one TAPI line device per link structure.
+*/
+#define HTDSU_TAPI_NUM_LINES HTDSU_NUM_LINKS
+
+/*
+// There is only one TAPI address ID per line device (zero based).
+*/
+#define HTDSU_TAPI_NUM_ADDRESSES 1
+#define HTDSU_TAPI_ADDRESSID 0
+
+/*
+// There is only one TAPI call per address/line instance.
+*/
+#define HTDSU_TAPI_NUM_CALLS 1
+
+/*
+// This version number is used by the NDIS_TAPI_NEGOTIATE_EXT_VERSION request.
+// It is not used by this driver or the current NDISTAPI release.
+*/
+#define HTDSU_TAPI_EXT_VERSION 0x00010000
+
+/*
+// The line mode can be leased or dial-up. In leased mode we can present the
+// WAN wrapper with a LINE_UP indication so it can use the connection without
+// the TAPI interface. In dialup mode, we need to present a TAPI service
+// provider interface so RAS or something else can select the phone number.
+// Currently, this driver only supports a single line adapter, but it has
+// been written to allow the addition of a second line if the adapter becomes
+// available.
+*/
+typedef enum _HTDSU_LINE_MODE
+{
+ HTDSU_LINEMODE_DIALUP,
+ HTDSU_LINEMODE_LEASED
+
+} HTDSU_LINE_MODE;
+
+/*
+// This structure contains all the link information maintained by the
+// Miniport driver. It encompasses both the TAPI and WAN connections.
+*/
+typedef struct _HTDSU_LINK
+{
+ /* 000
+ // Pointer back to the Adapter data structure so we can get at it
+ // when passed a pointer to this structure in NdisMWanSend().
+ */
+ struct _HTDSU_ADAPTER *Adapter;
+
+ /* 004
+ // This is used to select which card channel the link is associated with.
+ */
+ USHORT CardLine;
+
+ /* 006
+ // This is a zero based index used to assign TAPI device ID to the
+ // link based on TAPI DeviceIdBase assigned to this driver.
+ */
+ USHORT LinkIndex;
+
+ /* 008
+ // Remember what mode the line was set to.
+ */
+ HTDSU_LINE_MODE LineMode;
+
+ /* 00C
+ // The WAN wrapper supplied handle to be used on Miniport calls
+ // such as NdisMWanIndicateReceive().
+ */
+ NDIS_HANDLE NdisLinkContext;
+
+ /* 010
+ // The Connection wrapper supplied handle for use when indicating
+ // TAPI LINE_EVENT's.
+ */
+ HTAPI_LINE htLine;
+
+ /* 014
+ // The Connection wrapper supplied handle for use when indicating
+ // TAPI LINECALLSTATE events.
+ */
+ HTAPI_CALL htCall;
+
+ /* 018
+ // The current TAPI LINEDEVSTATE of the associated with the link.
+ */
+ ULONG DevState; // Current state
+ ULONG DevStatesCaps; // Events currently supported
+ ULONG DevStatesMask; // Events currently enabled
+
+ /* 024
+ // The current TAPI LINEADDRESSSTATE of the associated with the link.
+ */
+ ULONG AddressState; // Current state
+ ULONG AddressStatesCaps; // Events currently supported
+ ULONG AddressStatesMask; // Events currently enabled
+
+ /* 030
+ // The current TAPI LINECALLSTATE of the associated with the link.
+ */
+ ULONG CallState; // Current state
+ ULONG CallStatesCaps; // Events currently supported
+ ULONG CallStatesMask; // Events currently enabled
+
+ /* 03C
+ // The current TAPI media mode(s) supported by the card.
+ */
+ ULONG MediaMode; // Current state
+ ULONG MediaModesCaps; // Events currently supported
+ ULONG MediaModesMask; // Events currently enabled
+
+ /* 048
+ // TAPI line address is assigned during installation and saved in the
+ // registry. It is read from the registry and saved here at init time.
+ */
+ CHAR LineAddress[0x14];
+
+ /* 05C
+ // The speed provided by the link in bits per second. This value is
+ // passed up by the Miniport during the LINE_UP indication.
+ */
+ ULONG LinkSpeed;
+
+ /* 060
+ // The quality of service provided by the link. This value is passed
+ // up by the Miniport during the LINE_UP indication.
+ */
+ NDIS_WAN_QUALITY Quality;
+
+ /* 064
+ // The number of rings detected in the current ring sequence.
+ */
+ USHORT RingCount;
+
+ /* 066
+ // The number of packets that should be sent before pausing to wait
+ // for an acknowledgement. This value is passed up by the Miniport
+ // during the LINE_UP indication.
+ */
+ USHORT SendWindow;
+
+ /* 068
+ // The number of packets currently queued for transmission on this link.
+ */
+ ULONG NumTxQueued;
+
+ /* 06C
+ // Set TRUE if link is being closed.
+ */
+ BOOLEAN Closing;
+
+ /* 06D
+ // Set TRUE if call is being closed.
+ */
+ BOOLEAN CallClosing;
+
+ /* 070
+ // The current settings associated with this link as passed in via
+ // the OID_WAN_SET_LINK_INFO request.
+ */
+ NDIS_WAN_SET_LINK_INFO WanLinkInfo;
+
+ /*
+ // This timer is used to keep track of the call state when a call is
+ // coming in or going out.
+ */
+ NDIS_MINIPORT_TIMER CallTimer;
+
+} HTDSU_LINK, *PHTDSU_LINK;
+
+/*
+// Use this macro to determine if a link structure pointer is really valid.
+*/
+#define IS_VALID_LINK(Adapter, Link) \
+ (Link && Link->Adapter == Adapter)
+
+/*
+// Use this macro to get a pointer to a link structure from a CardLine ID.
+*/
+#define GET_LINK_FROM_CARDLINE(Adapter, CardLine) \
+ &(Adapter->WanLinkArray[CardLine-HTDSU_CMD_LINE1])
+
+/*
+// Use this macro to get a pointer to a link structure from a LinkIndex.
+*/
+#define GET_LINK_FROM_LINKINDEX(Adapter, LinkIndex) \
+ &(Adapter->WanLinkArray[LinkIndex])
+
+/*
+// Use this macro to get a pointer to a link structure from a TAPI DeviceID.
+*/
+#define GET_LINK_FROM_DEVICEID(Adapter, ulDeviceID) \
+ &(Adapter->WanLinkArray[ulDeviceID - Adapter->DeviceIdBase]); \
+ ASSERT(ulDeviceID >= Adapter->DeviceIdBase); \
+ ASSERT(ulDeviceID < Adapter->DeviceIdBase+Adapter->NumLineDevs)
+
+#define GET_DEVICEID_FROM_LINK(Adapter, Link) \
+ (Link->LinkIndex + Adapter->DeviceIdBase)
+
+/*
+// Use this macro to get a pointer to a link structure from a TAPI line handle.
+*/
+#define GET_LINK_FROM_HDLINE(Adapter, hdLine) \
+ (PHTDSU_LINK) \
+ (((PHTDSU_LINK) (hdLine) == &(Adapter->WanLinkArray[0])) ? (hdLine) : \
+ ((PHTDSU_LINK) (hdLine) == &(Adapter->WanLinkArray[1])) ? (hdLine) : 0)
+
+/*
+// Use this macro to get a pointer to a link structure from a TAPI call handle.
+*/
+#define GET_LINK_FROM_HDCALL(Adapter, hdCall) \
+ (PHTDSU_LINK) \
+ (((PHTDSU_LINK) (hdCall) == &(Adapter->WanLinkArray[0])) ? (hdCall) : \
+ ((PHTDSU_LINK) (hdCall) == &(Adapter->WanLinkArray[1])) ? (hdCall) : 0)
+
+/*
+// This structure contains all the information about a single adapter
+// instance this Miniport driver is controlling.
+*/
+typedef struct _HTDSU_ADAPTER
+{
+#if DBG
+ /* 000
+ // Debug flags control how much debug is displayed in the checked version.
+ */
+ ULONG DbgFlags;
+ UCHAR DbgID[4];
+#endif
+
+ /* 008
+ // This is the handle given by the wrapper for calling ndis
+ // functions.
+ */
+ NDIS_HANDLE MiniportAdapterHandle;
+
+ /* 00C
+ // Spinlock to protect fields in this structure..
+ */
+ NDIS_SPIN_LOCK Lock;
+
+ /* 014
+ // Lets us know when a transmit is in progress.
+ */
+ BOOLEAN TransmitInProgress;
+
+ /* 018
+ // Packets waiting to be sent when the controller is available.
+ */
+ LIST_ENTRY TransmitIdleList;
+
+ /* 020
+ // Packets currently submitted to the controller waiting for completion.
+ */
+ LIST_ENTRY TransmitBusyList;
+
+ /* 028
+ // Physical address where adapter memory is jumpered to.
+ */
+ NDIS_PHYSICAL_ADDRESS PhysicalAddress;
+
+ /* 030
+ // System address where the adapter memory is mapped to.
+ */
+ PVOID VirtualAddress;
+
+ /* 034
+ // Overlay the adapter memory structure on the virtual address
+ // where we've mapped it into system I/O (memory) space.
+ */
+ PHTDSU_REGISTERS AdapterRam;
+
+ /* 038
+ // How much memory is on the adapter.
+ */
+ USHORT MemorySize;
+
+ /* 03A
+ // Currently enabled interrupts
+ */
+ USHORT InterruptEnableFlag;
+
+ /* 03C
+ // Currently pending interrupts
+ */
+ USHORT InterruptStatusFlag;
+
+ /* 03E
+ // Interrupt number this adapter is using.
+ */
+ CHAR InterruptNumber;
+
+ /* 03F
+ // A unique instance number to be used to generate a unique
+ // WAN permanent address (not really permanent, but it's unique).
+ */
+ CHAR InstanceNumber;
+
+ /* 040
+ // Set TRUE if something goes terribly wrong with the hardware.
+ */
+ BOOLEAN NeedReset;
+
+ /* 041
+ // Set TRUE when the DPC is entered, and reset to FALSE when it leaves.
+ */
+ BOOLEAN InTheDpcHandler;
+
+ /* 042
+ // Specifies whether line is to be treated as a leased WAN line
+ // or a dialup TAPI line.
+ */
+ USHORT LineType;
+
+ /* 044
+ // The DSU41 has only one line, DSU42 has two.
+ */
+ UINT NumLineDevs;
+
+ /* 048
+ // The ulDeviceIDBase field passed in the PROVIDER_INIT request informs a miniport of the zero-based
+ // starting index that the Connection Wrapper will use when referring to a single adapter’s line devices by
+ // index. For example, if a ulDeviceIDBase of two is specified and the adapter supports three line devices,
+ // then the Connection Wrapper will use the identifiers two, three, and four to refer to the adapter’s three
+ // devices.
+ */
+ ULONG DeviceIdBase;
+
+ /* 04C
+ // The number of line open calls currently on this adapter.
+ */
+ UINT NumOpens;
+
+ /* 050
+ // NDIS interrupt control structure.
+ */
+ NDIS_MINIPORT_INTERRUPT Interrupt;
+
+ /*
+ // Specifies whether what speed the line is to be configured to.
+ */
+ USHORT LineRate;
+
+ /*
+ // WAN info structure.
+ */
+ NDIS_WAN_INFO WanInfo;
+
+ /*
+ // This holds the TAPI ProviderInfo string returned from HtTapiGetDevCaps
+ // This is two null terminated strings packed end to end.
+ */
+ CHAR ProviderInfo[48]; // This size is the max allowed by RAS
+ USHORT ProviderInfoSize; // Size in bytes of both strings.
+
+ /*
+ // WAN/TAPI link managment object for each connection we support.
+ */
+ HTDSU_LINK WanLinkArray[HTDSU_NUM_LINKS];
+
+ /*
+ // This contains the name of our TAPI configuration DLL which is read
+ // from the registry during initialization. The name of the DLL and
+ // its path will be saved in the registry during installation.
+ */
+ CHAR ConfigDLLName[128];
+
+} HTDSU_ADAPTER, * PHTDSU_ADAPTER;
+
+
+/***************************************************************************
+// These routines are defined in htdsu.c
+*/
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+NDIS_STATUS
+HtDsuInitialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ );
+
+NDIS_STATUS
+HtDsuRegisterAdapter(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PSTRING AddressList
+ );
+
+VOID
+HtDsuHalt(
+ IN PHTDSU_ADAPTER Adapter
+ );
+
+NDIS_STATUS
+HtDsuReconfigure(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ IN PHTDSU_ADAPTER Adapter,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ );
+
+NDIS_STATUS
+HtDsuReset(
+ OUT PBOOLEAN AddressingReset,
+ IN PHTDSU_ADAPTER Adapter
+ );
+
+/***************************************************************************
+// These routines are defined in interrup.c
+*/
+extern BOOLEAN
+HtDsuCheckForHang(
+ IN PHTDSU_ADAPTER Adapter
+ );
+
+extern VOID
+HtDsuDisableInterrupt(
+ IN PHTDSU_ADAPTER Adapter
+ );
+
+extern VOID
+HtDsuEnableInterrupt(
+ IN PHTDSU_ADAPTER Adapter
+ );
+
+extern VOID
+HtDsuISR(
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueMiniportHandleInterrupt,
+ IN PHTDSU_ADAPTER Adapter
+ );
+
+VOID
+HtDsuHandleInterrupt(
+ IN PHTDSU_ADAPTER Adapter
+ );
+
+VOID
+HtDsuPollAdapter(
+ IN PVOID SystemSpecific1,
+ IN PHTDSU_ADAPTER Adapter,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+/***************************************************************************
+// These routines are defined in receive.c
+*/
+VOID
+HtDsuReceivePacket(
+ IN PHTDSU_ADAPTER Adapter
+ );
+
+/***************************************************************************
+// These routines are defined in request.c
+*/
+NDIS_STATUS
+HtDsuQueryInformation(
+ IN PHTDSU_ADAPTER Adapter,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+ );
+
+NDIS_STATUS
+HtDsuSetInformation(
+ IN PHTDSU_ADAPTER Adapter,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ );
+
+/***************************************************************************
+// These routines are defined in send.c
+*/
+NDIS_STATUS
+HtDsuWanSend(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PHTDSU_LINK Link,
+ IN PNDIS_WAN_PACKET Packet
+ );
+
+VOID
+HtDsuTransmitComplete(
+ IN PHTDSU_ADAPTER Adapter
+ );
+
+/***************************************************************************
+// These routines are defined in card.c
+*/
+NDIS_STATUS
+CardIdentify(
+ IN PHTDSU_ADAPTER Adapter
+ );
+
+NDIS_STATUS
+CardDoCommand(
+ IN PHTDSU_ADAPTER Adapter,
+ IN USHORT CardLine,
+ IN USHORT CommandValue
+ );
+
+NDIS_STATUS
+CardInitialize(
+ IN PHTDSU_ADAPTER Adapter,
+ IN BOOLEAN PerformSelfTest
+ );
+
+VOID
+CardLineConfig(
+ IN PHTDSU_ADAPTER Adapter,
+ IN USHORT CardLine
+ );
+
+VOID
+CardLineDisconnect(
+ IN PHTDSU_ADAPTER Adapter,
+ IN USHORT CardLine
+ );
+
+VOID
+CardPrepareTransmit(
+ IN PHTDSU_ADAPTER Adapter,
+ IN USHORT CardLine,
+ IN USHORT Length
+ );
+
+VOID
+CardGetReceiveInfo(
+ IN PHTDSU_ADAPTER Adapter,
+ OUT PUSHORT CardLine,
+ OUT PUSHORT BytesReceived,
+ OUT PUSHORT Status
+ );
+
+VOID
+CardDialNumber(
+ IN PHTDSU_ADAPTER Adapter,
+ IN USHORT CardLine,
+ IN PUCHAR DialString,
+ IN ULONG DialStringLength
+ );
+
+/***************************************************************************
+// These routines are defined in link.c
+*/
+VOID
+LinkInitialize(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PSTRING AddressList
+ );
+
+PHTDSU_LINK
+LinkAllocate(
+ IN PHTDSU_ADAPTER Adapter,
+ IN HTAPI_LINE htLine,
+ IN USHORT LinkIndex
+ );
+
+VOID
+LinkRelease(
+ IN PHTDSU_LINK Link
+ );
+
+VOID
+LinkLineUp(
+ IN PHTDSU_LINK Link
+ );
+
+VOID
+LinkLineDown(
+ IN PHTDSU_LINK Link
+ );
+
+VOID
+LinkLineError(
+ IN PHTDSU_LINK Link,
+ IN ULONG Errors
+ );
+
+/***************************************************************************
+// These routines are defined in tapi.c
+*/
+NDIS_STATUS
+HtTapiQueryInformation(
+ IN PHTDSU_ADAPTER Adapter,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+ );
+
+NDIS_STATUS
+HtTapiSetInformation(
+ IN PHTDSU_ADAPTER Adapter,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ );
+
+NDIS_STATUS
+HtTapiConfigDialog(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_CONFIG_DIALOG Request
+ );
+
+NDIS_STATUS
+HtTapiDevSpecific(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_DEV_SPECIFIC Request
+ );
+
+NDIS_STATUS
+HtTapiGetAddressCaps(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_GET_ADDRESS_CAPS Request
+ );
+
+NDIS_STATUS
+HtTapiGetAddressID(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_GET_ADDRESS_ID Request
+ );
+
+NDIS_STATUS
+HtTapiGetAddressStatus(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_GET_ADDRESS_STATUS Request
+ );
+
+NDIS_STATUS
+HtTapiGetCallAddressID(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_GET_CALL_ADDRESS_ID Request
+ );
+
+NDIS_STATUS
+HtTapiGetCallInfo(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_GET_CALL_INFO Request
+ );
+
+NDIS_STATUS
+HtTapiGetCallStatus(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_GET_CALL_STATUS Request
+ );
+
+NDIS_STATUS
+HtTapiGetDevCaps(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_GET_DEV_CAPS Request
+ );
+
+NDIS_STATUS
+HtTapiGetDevConfig(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_GET_DEV_CONFIG Request
+ );
+
+NDIS_STATUS
+HtTapiGetExtensionID(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_GET_EXTENSION_ID Request
+ );
+
+NDIS_STATUS
+HtTapiGetID(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_GET_ID Request
+ );
+
+NDIS_STATUS
+HtTapiGetLineDevStatus(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_GET_LINE_DEV_STATUS Request
+ );
+
+NDIS_STATUS
+HtTapiMakeCall(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_MAKE_CALL Request
+ );
+
+NDIS_STATUS
+HtTapiNegotiateExtVersion(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_NEGOTIATE_EXT_VERSION Request
+ );
+
+NDIS_STATUS
+HtTapiOpen(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_OPEN Request
+ );
+
+NDIS_STATUS
+HtTapiProviderInitialize(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_PROVIDER_INITIALIZE Request
+ );
+
+NDIS_STATUS
+HtTapiAccept(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_ACCEPT Request
+ );
+
+NDIS_STATUS
+HtTapiAnswer(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_ANSWER Request
+ );
+
+NDIS_STATUS
+HtTapiClose(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_CLOSE Request
+ );
+
+NDIS_STATUS
+HtTapiCloseCall(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_CLOSE_CALL Request
+ );
+
+NDIS_STATUS
+HtTapiConditionalMediaDetection(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_CONDITIONAL_MEDIA_DETECTION Request
+ );
+
+NDIS_STATUS
+HtTapiDial(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_DIAL Request
+ );
+
+NDIS_STATUS
+HtTapiDrop(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_DROP Request
+ );
+
+NDIS_STATUS
+HtTapiProviderShutdown(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_PROVIDER_SHUTDOWN Request
+ );
+
+NDIS_STATUS
+HtTapiSecureCall(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_SECURE_CALL Request
+ );
+
+NDIS_STATUS
+HtTapiSelectExtVersion(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_SELECT_EXT_VERSION Request
+ );
+
+NDIS_STATUS
+HtTapiSendUserUserInfo(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_SEND_USER_USER_INFO Request
+ );
+
+NDIS_STATUS
+HtTapiSetAppSpecific(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_SET_APP_SPECIFIC Request
+ );
+
+NDIS_STATUS
+HtTapiSetCallParams(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_SET_CALL_PARAMS Request
+ );
+
+NDIS_STATUS
+HtTapiSetDefaultMediaDetection(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION Request
+ );
+
+NDIS_STATUS
+HtTapiSetDevConfig(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_SET_DEV_CONFIG Request
+ );
+
+NDIS_STATUS
+HtTapiSetMediaMode(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_SET_MEDIA_MODE Request
+ );
+
+NDIS_STATUS
+HtTapiSetStatusMessages(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_SET_STATUS_MESSAGES Request
+ );
+
+VOID
+HtTapiAddressStateHandler(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PHTDSU_LINK Link,
+ IN ULONG AddressState
+ );
+
+VOID
+HtTapiCallStateHandler(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PHTDSU_LINK Link,
+ IN ULONG CallState,
+ IN ULONG StateParam
+ );
+
+VOID
+HtTapiLineDevStateHandler(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PHTDSU_LINK Link,
+ IN ULONG LineDevState
+ );
+
+VOID
+HtTapiResetHandler(
+ IN PHTDSU_ADAPTER Adapter
+ );
+
+VOID
+HtTapiCallTimerHandler(
+ IN PVOID SystemSpecific1,
+ IN PHTDSU_LINK Link,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+#endif // _HTDSU_H
+
diff --git a/private/ntos/ndis/htdsu/htdsu.rc b/private/ntos/ndis/htdsu/htdsu.rc
new file mode 100644
index 000000000..c18ad93fc
--- /dev/null
+++ b/private/ntos/ndis/htdsu/htdsu.rc
@@ -0,0 +1,9 @@
+#include <winver.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+
+#include "version.h"
+#include <common.ver>
+
diff --git a/private/ntos/ndis/htdsu/interrup.c b/private/ntos/ndis/htdsu/interrup.c
new file mode 100644
index 000000000..fad79ce79
--- /dev/null
+++ b/private/ntos/ndis/htdsu/interrup.c
@@ -0,0 +1,656 @@
+/***************************************************************************\
+|* Copyright (c) 1994 Microsoft Corporation *|
+|* Developed for Microsoft by TriplePoint, Inc. Beaverton, Oregon *|
+|* *|
+|* This file is part of the HT Communications DSU41 WAN Miniport Driver. *|
+\***************************************************************************/
+#include "version.h"
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Module Name:
+
+ interrup.c
+
+Abstract:
+
+ This module contains the Miniport interrupt processing routines:
+ MiniportCheckForHang()
+ MiniportDisableInterrupt()
+ MiniportEnableInterrupt()
+ MiniportISR()
+ MiniportHandleInterrupt()
+
+ This driver conforms to the NDIS 3.0 Miniport interface.
+
+Author:
+
+ Larry Hattery - TriplePoint, Inc. (larryh@tpi.com) Jun-94
+
+Environment:
+
+ Windows NT 3.5 kernel mode Miniport driver or equivalent.
+
+Revision History:
+
+---------------------------------------------------------------------------*/
+
+#define __FILEID__ 3 // Unique file ID for error logging
+
+#include "htdsu.h"
+
+
+BOOLEAN
+HtDsuCheckForHang(
+ IN PHTDSU_ADAPTER Adapter
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ The MiniportCheckForHang request is used by the wrapper to periodically
+ have the miniport check if the adapter appears hung.
+
+ The Miniport driver should do nothing more than check the internal state
+ and return if the adapter is hung. The wrapper will then attempt to
+ recover the adapter by calling MiniportReset.
+
+ This routine will be called once every two seconds.
+
+ Interrupts will be in any state when called.
+
+Parameters:
+
+ MiniportAdapterContext _ The handle returned from MiniportInitialize.
+
+Return Values:
+
+ TRUE if the driver believes that the underlying hardware is hung,
+ FALSE otherwise.
+
+---------------------------------------------------------------------------*/
+
+{
+ return (Adapter->NeedReset);
+}
+
+
+VOID
+HtDsuDisableInterrupt(
+ IN PHTDSU_ADAPTER Adapter
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ The MiniportDisableInterrupt request is used to disable the adapter
+ from generating any interrupts. Typically this is done by writing a
+ mask which disables the adapter from generating hardware interrupts.
+
+ If the underlying hardware does not support enabling and disabling
+ interrupts, the Miniport driver will have to register a MiniportISR
+ with the wrapper, and the Miniport driver will have to acknowledge
+ and save the interrupt information from within the interrupt service
+ routine.
+
+ This routine may be called any time interrupts are enabled. If the
+ underlying hardware is required to be in a certain state for this
+ routine to execute correctly, the Miniport driver must encapsulate
+ all portions of the driver which violate the state and which may be
+ called when interrupts are enabled, with a function and call the
+ function through the NdisMSynchronizeWithInterrupt service.
+
+ Interrupts will be in any state when called.
+
+Parameters:
+
+ MiniportAdapterContext _ The adapter handle passed to NdisMSetAttributes
+ during MiniportInitialize.
+
+Return Values:
+
+ None.
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtDsuDisableInterrupt")
+
+ /*
+ // Save the current interrupt status on the card.
+ */
+ USHORT InterruptStatus = CardGetInterrupt(Adapter);
+
+// DBG_ENTER(Adapter);
+
+ /*
+ // Disable the interrupt at the card after saving the current state
+ // of the InterruptStatus register -- which will be reset by the clear
+ // interrupt command.
+ */
+ Adapter->InterruptStatusFlag |= InterruptStatus;
+ CardClearInterrupt(Adapter);
+ CardDisableInterrupt(Adapter);
+
+ DBG_NOTICE(Adapter, ("IntrStatus=%Xh LineStatus=%Xh\n",
+ InterruptStatus,
+ READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine1)
+ ));
+
+// DBG_LEAVE(Adapter);
+}
+
+
+VOID
+HtDsuEnableInterrupt(
+ IN PHTDSU_ADAPTER Adapter
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ The MiniportEnableInterrupt request is used to enable the adapter for
+ generating any interrupts. Typically this is done by writing a mask
+ which will reenable adapter interrupts.
+
+ If the underlying hardware does not support enabling and disabling
+ interrupts, the Miniport driver will have to register a MiniportISR
+ with the wrapper, and the Miniport driver will have to acknowledge
+ and save the interrupt information from within the interrupt service
+ routine.
+
+ Interrupts will be in any state when called.
+
+Parameters:
+
+ MiniportAdapterContext _ The adapter handle passed to NdisMSetAttributes
+ during MiniportInitialize.
+
+Return Values:
+
+ None.
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtDsuEnableInterrupt")
+
+ /*
+ // Save the current interrupt status on the card.
+ */
+ USHORT InterruptStatus = CardGetInterrupt(Adapter);
+
+// DBG_ENTER(Adapter);
+
+ CardEnableInterrupt(Adapter);
+
+ DBG_NOTICE(Adapter, ("IntrStatus=%Xh LineStatus=%Xh\n",
+ InterruptStatus,
+ READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine1)
+ ));
+
+// DBG_LEAVE(Adapter);
+}
+
+
+
+VOID
+HtDsuISR(
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueMiniportHandleInterrupt,
+ IN PHTDSU_ADAPTER Adapter
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ The MiniportISR request is called if the adapter generates an
+ interrupt when there is an outstanding call to MiniportInitialize
+ or to MiniportReconfigure, if the Miniport driver supports sharing
+ its interrupt line with another adapter, or if the Miniport driver
+ specifies that the routine must be called for every interrupt (See
+ NdisMRegisterInterrupt's RequestIsr and SharedInterrupt parameters).
+
+ This routine runs immediately after an interrupt, at very high priority,
+ and is subject to all the limitations of the interrupt service routine
+ in the NDIS 3.0 specification. The driver should do as little work as
+ possible in this routine. It should return TRUE in the parameter
+ InterruptRecognized if it recognizes the interrupt as belonging to its
+ adapter, or FALSE otherwise. It should return TRUE in the parameter
+ QueueMiniportHandleInterrupt if it needs a call to MiniportHandleInterrupt
+ at a lower priority to complete the handling of the interrupt, or FALSE
+ otherwise.
+
+ Note that a Dpc will not be queued if the Miniport is currently executing
+ in any of the following routines: MiniportHalt, MiniportInitialize,
+ MiniportReconfigure.
+
+Parameters:
+
+ InterruptRecognized _ If the Miniport is sharing an interrupt line, it
+ should set this parameter to TRUE if the Miniport
+ driver recognizes that the interrupt came from the
+ adapter it is supporting.
+
+ QueueMiniportHandleInterrupt _ If the Miniport driver is sharing an
+ interrupt line, it sets this parameter to
+ TRUE if the driver needs to have
+ MiniportHandleInterrupt called.
+
+ MiniportAdapterContext _ The adapter handle passed to NdisMSetAttributes
+ during MiniportInitialize.
+
+Return Values:
+
+ None.
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtDsuISR")
+
+ /*
+ // Save the current interrupt status on the card.
+ */
+ USHORT InterruptStatus;
+
+ DBG_ENTER(Adapter);
+
+ /*
+ // This routine should never be called after initialization since we
+ // support the Enable/Disable Interrupt routines.
+ */
+ if (InterruptStatus = CardGetInterrupt(Adapter))
+ {
+ /*
+ // The adapter prevents the failure case where additional status
+ // bits could be set between the time we read the InterruptStatus
+ // and it is reset by the clear interrupt command...
+ */
+ CardClearInterrupt(Adapter);
+ Adapter->InterruptStatusFlag |= InterruptStatus;
+
+ /*
+ // The card generated an interrupt, we need to service it only if we are
+ // interested in it. In either case it must be dismissed from the card.
+ */
+ *InterruptRecognized = TRUE;
+ *QueueMiniportHandleInterrupt = TRUE;
+ }
+ else
+ {
+ /*
+ // It's not our interrupt, so we don't need to service anything.
+ */
+ *InterruptRecognized = FALSE;
+ }
+
+ DBG_NOTICE(Adapter, ("IntrStatus=%Xh LineStatus=%Xh\n",
+ InterruptStatus,
+ READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine1)
+ ));
+
+ DBG_LEAVE(Adapter);
+}
+
+
+VOID
+HtDsuHandleInterrupt(
+ IN PHTDSU_ADAPTER Adapter
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ The MiniportHandleInterrupt routine is called from within a wrapper
+ deferred processing routine, and is used to process the reason an
+ interrupt was generated. The Miniport driver should handle all
+ outstanding interrupts and start any new operations.
+
+ Interrupts will be disabled during the call to this routine.
+
+Parameters:
+
+ MiniportAdapterContext _ The adapter handle passed to NdisMSetAttributes
+ during MiniportInitialize.
+
+Return Values:
+
+ None.
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtDsuHandleInterrupt")
+
+ /*
+ // A pointer to our link information structure.
+ */
+ PHTDSU_LINK Link;
+
+ UINT TimeOut;
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->InTheDpcHandler = TRUE;
+
+ DBG_ENTER(Adapter);
+
+ /*
+ // Loop thru here until all the interrupts are handled.
+ // This should not be allowed to take more than a few mili-seconds.
+ // If it does, the checked kernel will trap, and you'll have to
+ // find a way to leave the DPC early and handle the rest during
+ // the next pass.
+ */
+ while (Adapter->InterruptStatusFlag)
+ {
+ /********************************************************************
+ // Do we have a packet waiting in the adapter?
+ */
+ if (Adapter->InterruptStatusFlag & (HTDSU_INTR_RX_PACKET1 |
+ HTDSU_INTR_RX_PACKET2))
+ {
+ DBG_NOTICE(Adapter,("HTDSU_INTR_RX_PACKET\n"));
+
+ Adapter->InterruptStatusFlag &= ~(HTDSU_INTR_RX_PACKET1 |
+ HTDSU_INTR_RX_PACKET2);
+ HtDsuReceivePacket(Adapter);
+ }
+
+ /********************************************************************
+ // Has the packet been transmitted?
+ // Actually, this just means that the DSU firmware has moved the
+ // packet from our buffer area to its own buffer to be transmitted.
+ // It won't have actually completed until HTDSU_INTR_TX_EMPTY.
+ */
+ if (Adapter->InterruptStatusFlag & (HTDSU_INTR_TX_PACKET1 |
+ HTDSU_INTR_TX_PACKET2))
+ {
+ DBG_NOTICE(Adapter,("HTDSU_INTR_TX_PACKET\n"));
+
+ Adapter->InterruptStatusFlag &= ~(HTDSU_INTR_TX_PACKET1 |
+ HTDSU_INTR_TX_PACKET2);
+ HtDsuTransmitComplete(Adapter);
+ }
+
+ /********************************************************************
+ // Does somebody want to chat?
+ */
+ if (Adapter->InterruptStatusFlag & HTDSU_INTR_RINGING1)
+ {
+ DBG_NOTICE(Adapter,("HTDSU_INTR_RINGING1\n"));
+
+ Adapter->InterruptStatusFlag &= ~HTDSU_INTR_RINGING1;
+
+ /*
+ // CAVEAT: Normally you don't want to stall execution in your
+ // DPC because locks are held and no other threads will run.
+ // However, I have seen some hardware/firmware anomallies
+ // on the answering side where we get here before the signal
+ // is established, so I double check here by waiting up to 100MS.
+ */
+ TimeOut = 0;
+ while (!CardStatusRinging(Adapter, HTDSU_CMD_LINE1) ||
+ CardStatusNoSignal(Adapter, HTDSU_CMD_LINE1))
+ {
+ if (TimeOut++ > 1000)
+ {
+ DBG_ERROR(Adapter,("Timeout waiting for SIGNAL on line 1\n"));
+ break;
+ }
+ else
+ {
+ NdisStallExecution(_100_MICROSECONDS);
+ }
+ }
+
+ if (TimeOut != 0)
+ {
+ DBG_WARNING(Adapter, ("Ring1 signal delay=%d*100us\n", TimeOut));
+ }
+
+ /*
+ // Make sure the ring is still asserted or it may
+ // just be noise from the cable being unplugged.
+ */
+ if (CardStatusRinging(Adapter, HTDSU_CMD_LINE1))
+ {
+ Link = GET_LINK_FROM_CARDLINE(Adapter, HTDSU_CMD_LINE1);
+ HtTapiLineDevStateHandler(Adapter, Link, LINEDEVSTATE_RINGING);
+ }
+ else
+ {
+ DBG_WARNING(Adapter, ("Ring1 lost - status=%Xh\n",
+ READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine1)));
+ }
+ }
+ if (Adapter->InterruptStatusFlag & HTDSU_INTR_RINGING2)
+ {
+ DBG_NOTICE(Adapter,("HTDSU_INTR_RINGING2\n"));
+
+ Adapter->InterruptStatusFlag &= ~HTDSU_INTR_RINGING2;
+
+ TimeOut = 0;
+ while (!CardStatusRinging(Adapter, HTDSU_CMD_LINE2) ||
+ CardStatusNoSignal(Adapter, HTDSU_CMD_LINE2))
+ {
+ if (TimeOut++ > 100)
+ {
+ DBG_ERROR(Adapter,("Timeout waiting for SIGNAL on line 2\n"));
+ break;
+ }
+ else
+ {
+ NdisStallExecution(_100_MICROSECONDS);
+ }
+ }
+
+ if (TimeOut != 0)
+ {
+ DBG_WARNING(Adapter, ("Ring2 signal delay=%d*100us\n", TimeOut));
+ }
+
+ if (CardStatusRinging(Adapter, HTDSU_CMD_LINE2))
+ {
+ Link = GET_LINK_FROM_CARDLINE(Adapter, HTDSU_CMD_LINE2);
+ HtTapiLineDevStateHandler(Adapter, Link, LINEDEVSTATE_RINGING);
+ }
+ else
+ {
+ DBG_WARNING(Adapter, ("Ring2 lost - status=%Xh\n",
+ READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine2)));
+ }
+ }
+
+ /********************************************************************
+ // Do we have a connection being established?
+ */
+ if (Adapter->InterruptStatusFlag & HTDSU_INTR_CONNECTED1)
+ {
+
+ DBG_NOTICE(Adapter,("HTDSU_INTR_CONNECTED1\n"));
+
+ Adapter->InterruptStatusFlag &= ~HTDSU_INTR_CONNECTED1;
+
+ /*
+ // CAVEAT: Normally you don't want to stall execution in your
+ // DPC because locks are held and no other threads will run.
+ // However, I have seen some hardware/firmware anomallies
+ // on the calling side where we get here before the carrier
+ // is established, so I double check here by waiting up to 100MS.
+ */
+ TimeOut = 0;
+ while (!CardStatusCarrierDetect(Adapter, HTDSU_CMD_LINE1) ||
+ !CardStatusOnLine(Adapter, HTDSU_CMD_LINE1))
+ {
+ if (TimeOut++ > 1000)
+ {
+ DBG_ERROR(Adapter,("Timeout waiting for CARRIER/LINE 1\n"));
+ break;
+ }
+ else
+ {
+ NdisStallExecution(_100_MICROSECONDS);
+ }
+ }
+
+ if (TimeOut != 0)
+ {
+ DBG_WARNING(Adapter, ("Connect1 carrier delay=%d*100us\n", TimeOut));
+ }
+
+ /*
+ // Make sure the connection is accompanied by a carrier and
+ // an online status, Otherwise, it's probably just cable bounce.
+ */
+ if (CardStatusCarrierDetect(Adapter, HTDSU_CMD_LINE1) &&
+ CardStatusOnLine(Adapter, HTDSU_CMD_LINE1))
+ {
+ Link = GET_LINK_FROM_CARDLINE(Adapter, HTDSU_CMD_LINE1);
+ HtTapiLineDevStateHandler(Adapter, Link, LINEDEVSTATE_CONNECTED);
+ }
+ else
+ {
+ DBG_WARNING(Adapter, ("Connect1 but not ready - status=%X\n",
+ READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine1)));
+ }
+ }
+ if (Adapter->InterruptStatusFlag & HTDSU_INTR_CONNECTED2)
+ {
+ DBG_NOTICE(Adapter,("HTDSU_INTR_CONNECTED2\n"));
+
+ Adapter->InterruptStatusFlag &= ~HTDSU_INTR_CONNECTED2;
+
+ TimeOut = 0;
+ while (!CardStatusCarrierDetect(Adapter, HTDSU_CMD_LINE2) ||
+ !CardStatusOnLine(Adapter, HTDSU_CMD_LINE2))
+ {
+ if (TimeOut++ > 1000)
+ {
+ DBG_ERROR(Adapter,("Timeout waiting for CARRIER/LINE 2\n"));
+ break;
+ }
+ else
+ {
+ NdisStallExecution(_100_MICROSECONDS);
+ }
+ }
+
+ if (TimeOut != 0)
+ {
+ DBG_WARNING(Adapter, ("Connect2 carrier delay=%d*100us\n", TimeOut));
+ }
+
+ if (CardStatusCarrierDetect(Adapter, HTDSU_CMD_LINE2) &&
+ CardStatusOnLine(Adapter, HTDSU_CMD_LINE2))
+ {
+ Link = GET_LINK_FROM_CARDLINE(Adapter, HTDSU_CMD_LINE2);
+ HtTapiLineDevStateHandler(Adapter, Link, LINEDEVSTATE_CONNECTED);
+ }
+ else
+ {
+ DBG_WARNING(Adapter, ("Connect2 but not ready - status=%X\n",
+ READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine2)));
+ }
+ }
+
+ /********************************************************************
+ // Did the other guy hung up on us? -- how rude...
+ */
+ if (Adapter->InterruptStatusFlag & HTDSU_INTR_DISCONNECTED1)
+ {
+ DBG_NOTICE(Adapter,("HTDSU_INTR_DISCONNECTED1\n"));
+
+ Adapter->InterruptStatusFlag &= ~HTDSU_INTR_DISCONNECTED1;
+
+ Link = GET_LINK_FROM_CARDLINE(Adapter, HTDSU_CMD_LINE1);
+ HtTapiLineDevStateHandler(Adapter, Link, LINEDEVSTATE_DISCONNECTED);
+ }
+ if (Adapter->InterruptStatusFlag & HTDSU_INTR_DISCONNECTED2)
+ {
+ DBG_NOTICE(Adapter,("HTDSU_INTR_DISCONNECTED2\n"));
+
+ Adapter->InterruptStatusFlag &= ~HTDSU_INTR_DISCONNECTED2;
+
+ Link = GET_LINK_FROM_CARDLINE(Adapter, HTDSU_CMD_LINE2);
+ HtTapiLineDevStateHandler(Adapter, Link, LINEDEVSTATE_DISCONNECTED);
+ }
+
+ /********************************************************************
+ // Has the transmitter gone idle? Ask me if I care...
+ */
+ if (Adapter->InterruptStatusFlag & (HTDSU_INTR_TX_EMPTY1 |
+ HTDSU_INTR_TX_EMPTY2))
+ {
+ DBG_NOTICE(Adapter,("HTDSU_INTR_TX_EMPTY\n"));
+
+ Adapter->InterruptStatusFlag &= ~(HTDSU_INTR_TX_EMPTY1 |
+ HTDSU_INTR_TX_EMPTY2);
+ }
+
+ /********************************************************************
+ // Maybe somebody unplugged the phone line?
+ */
+ if (Adapter->InterruptStatusFlag & HTDSU_INTR_NO_SIGNAL1)
+ {
+ DBG_NOTICE(Adapter,("HTDSU_INTR_NO_SIGNAL1\n"));
+
+ Adapter->InterruptStatusFlag &= ~HTDSU_INTR_NO_SIGNAL1;
+
+ Link = GET_LINK_FROM_CARDLINE(Adapter, HTDSU_CMD_LINE1);
+ HtTapiLineDevStateHandler(Adapter, Link, LINEDEVSTATE_OUTOFSERVICE);
+ }
+ if (Adapter->InterruptStatusFlag & HTDSU_INTR_NO_SIGNAL2)
+ {
+ DBG_NOTICE(Adapter,("HTDSU_INTR_NO_SIGNAL2\n"));
+
+ Adapter->InterruptStatusFlag &= ~HTDSU_INTR_NO_SIGNAL2;
+
+ Link = GET_LINK_FROM_CARDLINE(Adapter, HTDSU_CMD_LINE2);
+ HtTapiLineDevStateHandler(Adapter, Link, LINEDEVSTATE_OUTOFSERVICE);
+ }
+
+ /********************************************************************
+ // What about a receive buffer overrun? -- This better never happen!
+ // However, if it does, we'll shut this sucker off til it's reset.
+ */
+ if (Adapter->InterruptStatusFlag & HTDSU_INTR_RX_FULL1)
+ {
+ DBG_ERROR(Adapter,("HTDSU_INTR_RX_FULL1\n"));
+
+ Adapter->InterruptStatusFlag &= ~HTDSU_INTR_RX_FULL1;
+
+ /*
+ // Ask for reset, and disable interrupts until we get it.
+ */
+ Adapter->NeedReset = TRUE;
+ Adapter->InterruptEnableFlag = HTDSU_INTR_DISABLE;
+
+ Link = GET_LINK_FROM_CARDLINE(Adapter, HTDSU_CMD_LINE1);
+ LinkLineError(Link, WAN_ERROR_BUFFEROVERRUN);
+ HtTapiLineDevStateHandler(Adapter, Link, LINEDEVSTATE_DISCONNECTED);
+ }
+ if (Adapter->InterruptStatusFlag & HTDSU_INTR_RX_FULL2)
+ {
+ DBG_ERROR(Adapter,("HTDSU_INTR_RX_FULL2\n"));
+
+ Adapter->InterruptStatusFlag &= ~HTDSU_INTR_RX_FULL2;
+
+ Adapter->NeedReset = TRUE;
+ Adapter->InterruptEnableFlag = HTDSU_INTR_DISABLE;
+
+ Link = GET_LINK_FROM_CARDLINE(Adapter, HTDSU_CMD_LINE2);
+ LinkLineError(Link, WAN_ERROR_BUFFEROVERRUN);
+ HtTapiLineDevStateHandler(Adapter, Link, LINEDEVSTATE_DISCONNECTED);
+ }
+ }
+ DBG_LEAVE(Adapter);
+
+ Adapter->InTheDpcHandler = FALSE;
+ NdisReleaseSpinLock(&Adapter->Lock);
+}
+
diff --git a/private/ntos/ndis/htdsu/keywords.h b/private/ntos/ndis/htdsu/keywords.h
new file mode 100644
index 000000000..bb25cc7bd
--- /dev/null
+++ b/private/ntos/ndis/htdsu/keywords.h
@@ -0,0 +1,77 @@
+/***************************************************************************\
+|* Copyright (c) 1994 Microsoft Corporation *|
+|* Developed for Microsoft by TriplePoint, Inc. Beaverton, Oregon *|
+|* *|
+|* This file is part of the HT Communications DSU41 WAN Miniport Driver. *|
+\***************************************************************************/
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Module Name:
+
+ keywords.h
+
+Abstract:
+
+ This file contains the driver keyword parameters used in the registry.
+
+Author:
+
+ Larry Hattery - TriplePoint, Inc. (larryh@tpi.com) Jun-94
+
+Environment:
+
+ Include this file in the module parsing the driver configuration
+ parameters.
+
+Revision History:
+
+---------------------------------------------------------------------------*/
+
+#ifndef _KEYWORD_H
+#define _KEYWORD_H
+
+/*
+// The following parameter values are written to the configuration
+// registry during installation and setup, and they are validated
+// by the driver when the adapter is initialized.
+*/
+#define HTDSU_PARAM_IRQ03 03
+#define HTDSU_PARAM_IRQ04 04
+#define HTDSU_PARAM_IRQ10 10
+#define HTDSU_PARAM_IRQ11 11
+#define HTDSU_PARAM_IRQ12 12
+#define HTDSU_PARAM_IRQ15 15
+
+#define HTDSU_PARAM_RAMBASE1 (0x000D0000)
+#define HTDSU_PARAM_RAMBASE2 (0x000E0000)
+#define HTDSU_PARAM_RAMBASE3 (0x000DF000)
+#define HTDSU_PARAM_RAMBASE4 (0x000CF000)
+
+#define HTDSU_PARAM_INTERRUPT_STRING NDIS_STRING_CONST("InterruptNumber")
+#define HTDSU_PARAM_RAMBASE_STRING NDIS_STRING_CONST("RamBaseAddress")
+#define HTDSU_PARAM_MEDIATYPE_STRING NDIS_STRING_CONST("MediaType")
+#define HTDSU_PARAM_ADDRLIST_STRING NDIS_STRING_CONST("AddressList")
+#define HTDSU_PARAM_DEVICENAME_STRING NDIS_STRING_CONST("DeviceName")
+#define HTDSU_PARAM_LINETYPE_STRING NDIS_STRING_CONST("LineType")
+#define HTDSU_PARAM_LINERATE_STRING NDIS_STRING_CONST("LineRate")
+
+#if DBG
+#define HTDSU_PARAM_DBGFLAGS_STRING NDIS_STRING_CONST("DebugFlags")
+#endif
+
+/*
+// Returned from an OID_GEN_VENDOR_ID HtDsuQueryInformation request.
+// The vendor's assigned ethernet vendor code should be used if possible.
+*/
+#define HTDSU_VENDOR_ID "HTC"
+
+/*
+// Returned from an OID_GEN_VENDOR_DESCRIPTION HtDsuQueryInformation request.
+// This is an arbitrary string which may be used by upper layers to present
+// a user friendly description of the adapter.
+*/
+#define HTDSU_VENDOR_DESCRPTION "HT Communications 56kbps Digital Modem"
+
+#endif
+
diff --git a/private/ntos/ndis/htdsu/link.c b/private/ntos/ndis/htdsu/link.c
new file mode 100644
index 000000000..1983c07dd
--- /dev/null
+++ b/private/ntos/ndis/htdsu/link.c
@@ -0,0 +1,587 @@
+/***************************************************************************\
+|* Copyright (c) 1994 Microsoft Corporation *|
+|* Developed for Microsoft by TriplePoint, Inc. Beaverton, Oregon *|
+|* *|
+|* This file is part of the HT Communications DSU41 WAN Miniport Driver. *|
+\***************************************************************************/
+#include "version.h"
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Module Name:
+
+ link.c
+
+Abstract:
+
+ This module contains the WAN Miniport link management routines. All
+ information about the state of the link is stored in the Link structure.
+ LinkInitialize()
+ LinkAllocate()
+ LinkRelease()
+ LinkLineUp()
+ LinkLineDown()
+ LinkLineError()
+
+ This driver conforms to the NDIS 3.0 Miniport interface.
+
+Author:
+
+ Larry Hattery - TriplePoint, Inc. (larryh@tpi.com) Jun-94
+
+Environment:
+
+ Windows NT 3.5 kernel mode Miniport driver or equivalent.
+
+Revision History:
+
+---------------------------------------------------------------------------*/
+
+#define __FILEID__ 4 // Unique file ID for error logging
+
+#include "htdsu.h"
+
+
+VOID
+LinkInitialize(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PSTRING AddressList
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This routine initializes the Link structures within the Adapter
+ structure. We use the link structure to hold all the information about
+ a connection, whether the connection is made via TAPI calls or is a
+ leased line WAN connection.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ AddressList _ This is a list of MULTI_SZ strings which are to be assigned
+ to each link for use by TAPI HtTapiGetAddressCaps.
+
+Return Values:
+
+ None.
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("LinkInitialize")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ /*
+ // Index into the link array.
+ */
+ USHORT LinkIndex;
+
+ /*
+ // A pointer to the RAS/TAPI line address assigned to each link.
+ */
+ PUCHAR LineAddress = AddressList->Buffer;
+
+ DBG_ENTER(Adapter);
+
+ ASSERT(Adapter->NumLineDevs <= HTDSU_NUM_LINKS);
+
+ /*
+ // Go through and initialize each link.
+ */
+ for (LinkIndex = 0; LinkIndex < HTDSU_NUM_LINKS; ++LinkIndex)
+ {
+ Link = GET_LINK_FROM_LINKINDEX(Adapter, LinkIndex);
+
+ /*
+ // Initially, the link is not allocated to anyone and these fields
+ // must be reset.
+ // We can assume the entire Adapter structure is zeroed to begin with.
+ */
+ ASSERT(Link->Adapter == (PHTDSU_ADAPTER)0);
+ ASSERT(Link->htLine == (HTAPI_LINE)0);
+ ASSERT(Link->htCall == (HTAPI_CALL)0);
+ ASSERT(Link->NdisLinkContext == NULL);
+
+ /*
+ // Setup the static features of the link.
+ */
+ Link->CardLine = LinkIndex + HTDSU_CMD_LINE1;
+ Link->LinkIndex = LinkIndex;
+ Link->LinkSpeed = _56KBPS;
+ Link->LineMode = HTDSU_LINEMODE_DIALUP;
+ Link->MediaModesCaps = LINEMEDIAMODE_DIGITALDATA;
+ Link->Quality = NdisWanErrorControl;
+
+ /*
+ // If we run off the end of the address list, we just point at the
+ // null terminator for the other addresses. This might happen if
+ // some of the lines were not configured for use with RAS/TAPI.
+ */
+ strcpy(Link->LineAddress, LineAddress);
+ LineAddress += strlen(LineAddress) + 1;
+ if ((LineAddress - AddressList->Buffer) >= AddressList->Length)
+ {
+ --LineAddress;
+ }
+
+ DBG_NOTICE(Adapter,("LineAddress=<%s>\n",Link->LineAddress));
+
+ /*
+ // Initialize the TAPI event capabilities supported by the link.
+ */
+ Link->DevStatesCaps = LINEDEVSTATE_RINGING |
+ LINEDEVSTATE_CONNECTED |
+ LINEDEVSTATE_DISCONNECTED |
+ LINEDEVSTATE_OUTOFSERVICE |
+ LINEDEVSTATE_OPEN |
+ LINEDEVSTATE_CLOSE;
+ Link->AddressStatesCaps = 0;
+ Link->CallStatesCaps = LINECALLSTATE_IDLE |
+ LINECALLSTATE_OFFERING |
+ LINECALLSTATE_ACCEPTED |
+ LINECALLSTATE_DIALING |
+ LINECALLSTATE_BUSY |
+ LINECALLSTATE_CONNECTED |
+ LINECALLSTATE_PROCEEDING |
+ LINECALLSTATE_DISCONNECTED;
+ /*
+ // We use this timer to keep track of incoming and outgoing call
+ // status, and to provide timeouts for certain call states.
+ */
+ NdisMInitializeTimer(
+ &Link->CallTimer,
+ Adapter->MiniportAdapterHandle,
+ HtTapiCallTimerHandler,
+ Link
+ );
+ }
+ DBG_LEAVE(Adapter);
+}
+
+
+PHTDSU_LINK
+LinkAllocate(
+ IN PHTDSU_ADAPTER Adapter,
+ IN HTAPI_LINE htLine,
+ IN USHORT LinkIndex
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This routine allocates a specific Link structure and passes back a
+ pointer which can be used by the driver to access the link.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Connection _ The TAPI connection handle to be associated with the link.
+
+ LinkIndex _ The specific link structure being allocated.
+
+Return Values:
+
+ A pointer to allocated link information structure, NULL if not allocated.
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("LinkAllocate")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ DBG_ENTER(Adapter);
+
+ Link = GET_LINK_FROM_LINKINDEX(Adapter, LinkIndex);
+
+ if (Link->Adapter == (PHTDSU_ADAPTER) 0)
+ {
+ /*
+ // We use the Adapter field to flag whether the link has been allocated.
+ // The htLine field is used to associate this link with the TAPI
+ // connection wrapper. Reset all the state information for this link.
+ */
+ Link->Adapter = Adapter;
+ Link->htLine = htLine;
+ Link->RingCount = 0;
+ Link->DevState = 0;
+ Link->DevStatesMask = 0; // Default to indicate no line events
+ Link->AddressState = 0;
+ Link->AddressStatesMask = 0; // Default to indicate no address events
+ Link->CallState = 0;
+ Link->CallStatesMask = Link->CallStatesCaps;
+ Link->MediaMode = Link->MediaModesCaps;
+ Link->MediaModesMask = 0;
+ Link->Closing = FALSE;
+ Link->CallClosing = FALSE;
+
+ /*
+ // Initialize the default link information structure. It may be
+ // changed later by MiniportSetInformation.
+ */
+ Link->WanLinkInfo.NdisLinkHandle = Link;
+ Link->WanLinkInfo.MaxSendFrameSize = Adapter->WanInfo.MaxFrameSize;
+ Link->WanLinkInfo.MaxRecvFrameSize = Adapter->WanInfo.MaxFrameSize;
+ Link->WanLinkInfo.SendFramingBits = Adapter->WanInfo.FramingBits;
+ Link->WanLinkInfo.RecvFramingBits = Adapter->WanInfo.FramingBits;
+ Link->WanLinkInfo.SendACCM = Adapter->WanInfo.DesiredACCM;
+ Link->WanLinkInfo.RecvACCM = Adapter->WanInfo.DesiredACCM;
+ }
+ else
+ {
+ /*
+ // The requested link has already been allocated.
+ */
+ Link = NULL;
+ }
+
+ DBG_LEAVE(Adapter);
+
+ return (Link);
+}
+
+
+VOID
+LinkRelease(
+ IN PHTDSU_LINK Link
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This routine releases a specific Link structure and makes it available
+ for future allocation. It is assumed that the caller has closed any
+ associated connection and notified TAPI and WAN with a LINE_DOWN.
+
+Parameters:
+
+ Link _ A pointer to the link information structure to be released.
+
+Return Values:
+
+ None.
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("LinkRelease")
+ DBG_ENTER(Link->Adapter);
+
+ Link->Adapter = (PHTDSU_ADAPTER)0;
+ Link->htLine = (HTAPI_LINE)0;
+ Link->htCall = (HTAPI_CALL)0;
+ Link->NdisLinkContext = NULL;
+}
+
+
+VOID
+LinkLineUp(
+ IN PHTDSU_LINK Link
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This routine marks a link as connected and sends a LINE_UP indication to
+ the WAN wrapper.
+
+ A line up indication is generated when a new link becomes active. Prior
+ to this the MAC will accept frames and may let them succeed or fail, but
+ it is unlikely that they will actually be received by any remote. During
+ this state protocols are encouraged to reduce their timers and retry
+ counts so as to quickly fail any outgoing connection attempts.
+
+ NOTE: This indication must be sent to the WAN wrapper prior to returning
+ from the OID_TAPI_ANSWER request, and prior to indicating the
+ LINECALLSTATE_CONNECTED to the connection wrapper. Otherwise, the
+ connection wrapper client might attempt to send data to the WAN wrapper
+ before it is aware of the line.
+
+ The status code for the line up indication is NDIS_STATUS_WAN_LINE_UP.
+ The format of the StatusBuffer for this code is:
+
+ typedef struct _NDIS_MAC_LINE_UP
+ {
+ IN ULONG LinkSpeed;
+ IN NDIS_WAN_QUALITY Quality;
+ IN USHORT SendWindow;
+ IN NDIS_HANDLE ConnectionWrapperID;
+ IN NDIS_HANDLE NdisLinkHandle;
+ OUT NDIS_HANDLE NdisLinkContext;
+
+ } NDIS_MAC_LINE_UP, *PNDIS_MAC_LINE_UP;
+
+ LinkSpeed _ The speed of the link, in 100 bps units.
+
+ Quality _ The quality of the new line.
+
+ SendWindow _ The recommended send window, i.e., the number of packets
+ that should be given to the adapter before pausing to wait
+ for an acknowledgement. Some devices achieve higher
+ throughput if they have several packets to send at once;
+ others are especially unreliable. A value of 0 indicates
+ no recommendation.
+
+ ConnectionWrapperID _ The MAC supplied handle by which this line will be
+ known to the connection wrapper clients. This must
+ be a unique handle across all drivers using the
+ connection wrapper, so typically htCall should be
+ used to gaurantee it is unique. This must be the
+ same value returned from the OID_TAPI_GETID request
+ for the “ndis” device class. Refer to the
+ Connection Wrapper Interface Specification for
+ further details. If not using the connection
+ wrapper, the value is 0.
+
+ NdisLinkHandle _ The MAC supplied handle passed down in future Miniport
+ calls (such as MiniportSend) for this link. Typically,
+ the MAC will provide a pointer to its control block for
+ that link. The value must be unique, for the first
+ LINE_UP for that link. Subsequent LINE_UPs may be
+ called if line characteristics change. When subsequent
+ LINE_UP calls are made, the MiniportLinkHandle must be
+ filled with the value returned on the first LINE_UP call.
+
+ NdisLinkContext _ The WAN wrapper supplied handle to be used in future
+ Miniport calls (such as MiniportReceive) to the wrapper.
+ The WAN wrapper will provide a unique handle for every
+ unique LINE_UP. The MiniportLinkHandle must be 0 if
+ this is the first LINE_UP. It must contain the value
+ returned on the first LINE_UP for subsequent LINE_UP
+ calls.
+
+Parameters:
+
+ Link _ A pointer to our link information structure, on which this LINE_UP
+ indication is being made.
+
+Return Values:
+
+ None.
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("LinkLineUp")
+
+ NDIS_MAC_LINE_UP LineUpInfo;
+
+ DBG_ENTER(Link->Adapter);
+
+ /*
+ // Initialize the LINE_UP event packet.
+ */
+ LineUpInfo.LinkSpeed = Link->LinkSpeed / 100;
+ LineUpInfo.Quality = Link->Quality;
+ LineUpInfo.SendWindow = Link->SendWindow;
+ LineUpInfo.ConnectionWrapperID = (NDIS_HANDLE) Link->htCall;
+ LineUpInfo.NdisLinkHandle = Link;
+ LineUpInfo.NdisLinkContext = Link->NdisLinkContext;
+
+ /*
+ // Indicate the event to the WAN wrapper.
+ */
+ NdisMIndicateStatus(Link->Adapter->MiniportAdapterHandle,
+ NDIS_STATUS_WAN_LINE_UP,
+ &LineUpInfo,
+ sizeof(LineUpInfo)
+ );
+
+ /*
+ // Save the WAN wrapper link context for use when indicating received
+ // packets and errors.
+ */
+ Link->NdisLinkContext = LineUpInfo.NdisLinkContext;
+
+ DBG_NOTICE(Link->Adapter,
+ ("MAC_LINE_UP: LinkHandle=%Xh NdisHandle=%Xh WrapperID=%Xh\n",
+ LineUpInfo.NdisLinkHandle,
+ LineUpInfo.NdisLinkContext,
+ LineUpInfo.ConnectionWrapperID
+ ));
+
+ DBG_LEAVE(Link->Adapter);
+}
+
+
+VOID
+LinkLineDown(
+ IN PHTDSU_LINK Link
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This routine marks a link as disconnected and sends a LINE_DOWN
+ indication to the WAN wrapper.
+
+ A line down indication is generated when a link goes down. Protocols
+ should again reduce their timers and retry counts until the next line
+ up indication.
+
+ The status code for the line down indication is NDIS_STATUS_WAN_LINE_DOWN.
+ The format of the StatusBuffer for this code is:
+
+ typedef struct _NDIS_MAC_LINE_DOWN
+ {
+ IN NDIS_HANDLE NdisLinkContext;
+
+ } NDIS_MAC_LINE_DOWN, *PNDIS_MAC_LINE_DOWN;
+
+ MiniportLinkContext _ Value returned in NDIS_WAN_LINE_UP.
+
+Parameters:
+
+ Link _ A pointer to our link information structure, on which this LINE_DOWN
+ indication is being made.
+
+Return Values:
+
+ None.
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("LinkLineDown")
+
+ NDIS_MAC_LINE_DOWN LineDownInfo;
+
+ DBG_ENTER(Link->Adapter);
+
+ /*
+ // We can't allow indications to NULL...
+ */
+ if (Link->NdisLinkContext)
+ {
+ DBG_NOTICE(Link->Adapter,
+ ("MAC_LINE_DOWN: NdisHandle=%Xh\n",
+ Link->NdisLinkContext
+ ));
+
+ /*
+ // Setup the LINE_DOWN event packet and indicate the event to the
+ // WAN wrapper.
+ */
+ LineDownInfo.NdisLinkContext = Link->NdisLinkContext;
+
+ NdisMIndicateStatus(Link->Adapter->MiniportAdapterHandle,
+ NDIS_STATUS_WAN_LINE_DOWN,
+ &LineDownInfo,
+ sizeof(LineDownInfo)
+ );
+ /*
+ // The line is down, so there's no more context for receives.
+ */
+ Link->NdisLinkContext = NULL;
+ Link->CallClosing = FALSE;
+ }
+
+ DBG_LEAVE(Link->Adapter);
+}
+
+
+VOID
+LinkLineError(
+ IN PHTDSU_LINK Link,
+ IN ULONG Errors
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This routine is used to indicate to the WAN wrapper that a partial
+ packet was received from the remote end. The NDIS_STATUS_WAN_FRAGMENT
+ indication is used to notify WAN wrapper.
+
+ A fragment indication indicates that a partial packet was received from
+ the remote. The protocol is encouraged to send frames to the remote that
+ will notify it of this situation, rather than waiting for a timeout to
+ occur.
+
+ The status code for the fragment indication is NDIS_STATUS_WAN_FRAGMENT.
+ The format of the StatusBuffer for this code is:
+
+ typedef struct _NDIS_MAC_FRAGMENT
+ {
+ IN NDIS_HANDLE NdisLinkContext;
+ IN ULONG Errors;
+
+ } NDIS_MAC_FRAGMENT, *PNDIS_MAC_FRAGMENT;
+
+ NdisLinkContext _ Value returned in NDIS_WAN_LINE_UP.
+
+ Errors _ A bit field set to one or more bits indicating the reason the
+ fragment was received. If no direct mapping from the WAN medium
+ error to one of the six errors listed below exists, choose the
+ most apropriate error:
+
+ WAN_ERROR_CRC
+ WAN_ERROR_FRAMING
+ WAN_ERROR_HARDWAREOVERRUN
+ WAN_ERROR_BUFFEROVERRUN
+ WAN_ERROR_TIMEOUT
+ WAN_ERROR_ALIGNMENT
+
+ NOTE: The WAN wrapper keeps track of dropped packets by counting the
+ number of fragment indications on the link.
+
+Parameters:
+
+ Link _ A pointer to our link information structure, on which this error
+ was encountered.
+
+Return Values:
+
+ None.
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("LinkLineError")
+
+ NDIS_MAC_FRAGMENT FragmentInfo;
+
+ /*
+ // We can't allow indications to NULL...
+ */
+ if (Link->NdisLinkContext)
+ {
+ DBG_ENTER(Link->Adapter);
+
+ DBG_NOTICE(Link->Adapter,
+ ("MAC_LINE_ERROR: NdisHandle=%Xh Errors=%Xh\n",
+ Link->NdisLinkContext,
+ Errors
+ ));
+
+ /*
+ // Setup the FRAGMENT event packet and indicate it to the WAN wrapper.
+ */
+ FragmentInfo.NdisLinkContext = Link->NdisLinkContext;
+ FragmentInfo.Errors = Errors;
+
+ NdisMIndicateStatus(Link->Adapter->MiniportAdapterHandle,
+ NDIS_STATUS_WAN_FRAGMENT,
+ &FragmentInfo,
+ sizeof(FragmentInfo)
+ );
+
+ DBG_LEAVE(Link->Adapter);
+ }
+}
+
diff --git a/private/ntos/ndis/htdsu/makefile b/private/ntos/ndis/htdsu/makefile
new file mode 100644
index 000000000..58189757d
--- /dev/null
+++ b/private/ntos/ndis/htdsu/makefile
@@ -0,0 +1,7 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the driver components of the Windows NT DDK
+#
+
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/htdsu/oemsetnt.inf b/private/ntos/ndis/htdsu/oemsetnt.inf
new file mode 100644
index 000000000..6b3a7882e
--- /dev/null
+++ b/private/ntos/ndis/htdsu/oemsetnt.inf
@@ -0,0 +1,1241 @@
+;***********************************************************************
+; HT Communications DSU41/42 56kbps Digital Modem WindowsNT Setup File.
+;***********************************************************************
+[Identification]
+ OptionType = NetAdapter
+
+;***********************************************************************
+;
+;***********************************************************************
+[PlatformsSupported]
+ ISA
+ EISA
+ "Jazz-Internal Bus"
+
+;***********************************************************************
+;
+;***********************************************************************
+[Options]
+ HTDSU41
+; HTDSU42 FIXME - The HTDSU42 does not yet support HDLC framing
+
+;***********************************************************************
+;
+;***********************************************************************
+[FileConstants]
+ InfName = "OEMHTDSU.INF"
+ UtilityInf = "UTILITY.INF"
+ ParamInf = "NCPARAM.INF"
+ subroutineinf = "SUBROUTN.INF"
+ SoftwareType = "driver"
+ Exit_Code = 0
+ NetEventDLL = "%SystemRoot%\System32\netevent.dll"
+ IoLogMsgDLL = "%SystemRoot%\System32\IoLogMsg.dll"
+ Manufacturer = "HT Communications"
+ ProductMajorVersion = "3"
+ ProductMinorVersion = "1"
+ ProductVersion = $(ProductMajorVersion)"."$(ProductMinorVersion)
+ ProductSoftwareName = "HTDSU41"
+ ProductSoftwareImagePath = "\SystemRoot\System32\drivers\HTDSU41.sys"
+ NetRuleSoftwareType = "HTDSU41Sys HTDSU41Driver"
+ NetRuleSoftwareUse = $(SoftwareType)
+ NetRuleSoftwareBindForm = """HTDSU41Sys"" yes no container"
+ NetRuleSoftwareClass = {"HTDSU41Driver basic"}
+ NetRuleSoftwareBindable = {"HTDSU41Driver HTDSU41Adapter non exclusive 100"}
+ ProductHardwareName = "HTDSU41"
+ NetRuleHardwareBindForm = " yes yes container"
+ NetRuleHardwareHTDSU41Type = "HTDSU41 HTDSU41Adapter"
+ NetRuleHardwareHTDSU41Class = {"HTDSU41Adapter basic"}
+ BindableHTDSU41Txt = {"HTDSU41Driver HTDSU41Adapter non exclusive 100"}
+ DeviceMap = "HARDWARE\DEVICEMAP"
+ TapiDevices = "TAPI DEVICES"
+ TapiDeviceKey = $(ProductHardwareName)
+ TapiMediaType = "Sw56_"
+ ProductKeyName = $(!NTN_SoftwareBase)"\"$(Manufacturer)"\"+
+ $(ProductSoftwareName)"\CurrentVersion"
+ ParamKeyName = $(!NTN_ServiceBase)"\"$(ProductHardwareName)+
+ "\Parameters"
+
+; FIXME - default to dialup line mode = 0 -- leased line = 1
+; In dialup mode we need to write the parameters so RAS/TAPI will bind to us
+; In leased mode we need to write the parameters so NDIS/WAN will bind to us
+; Right now this file only supports dialup mode - leased line changes are needed
+ LineType = 0
+
+; FIXME - Set to zero before release
+ DebugFlags = 0
+
+ RAM_Addr_List = {851968, 917504, 913408, 847872}
+ IRQ_List = {15, 12, 11, 10, 4, 3}
+
+; Default here is 1=57.6kbps 0=max 2=38.4k 3=19.2k 4=9.6k
+ Rate_Strings = {"Max kbps", "57.6 kbps", "38.4 kbps", "19.2 kpbs", "9.6 kbps"}
+ Line_Rates = {0, 1, 2, 3, 4}
+ LineRate = 0
+
+;***********************************************************************
+;
+;***********************************************************************
+[GeneralConstants]
+ from = ""
+ to = ""
+ ExitCodeOk = 0
+ ExitCodeCancel = 1
+ ExitCodeFatal = 2
+ KeyNull = ""
+ MAXIMUM_ALLOWED = 33554432
+ RegistryErrorIndex = NO_ERROR
+ KeyProduct = ""
+ KeyParameters = ""
+ TRUE = 1
+ FALSE = 0
+ NoTitle = 0
+ ExitState = "Active"
+ OldVersionExisted = $(FALSE)
+ DriverPath = $(!STF_NTPATH)\drivers
+
+;***********************************************************************
+;
+;***********************************************************************
+[Date]
+ Now = {} ? $(!LIBHANDLE) GetSystemDate
+
+;***********************************************************************
+;
+;***********************************************************************
+[Identify]
+ Read-Syms Identification
+ Set Status = STATUS_SUCCESSFUL
+ Set Identifier = $(OptionType)
+ Set Media = #("Source Media Descriptions", 1, 1)
+ Return $(Status) $(Identifier) $(Media)
+
+;***********************************************************************
+;
+;***********************************************************************
+[ReturnOptions]
+ Set Status = STATUS_FAILED
+ Set OptionList = {}
+ Set OptionTextList = {}
+ Set LanguageList = ^(LanguagesSupported, 1)
+
+ IfContains(i) $($0) in $(LanguageList)
+ IfStr(i) $($1) == ""
+ GoTo SetOptions
+ EndIf
+ Set PlatformList = ^(PlatformsSupported, 1)
+ IfContains(i) $($1) in $(PlatformList)
+ GoTo SetOptions
+ Else
+ Set Status = STATUS_NOTSUPPORTED
+ GoTo ExitReturnOptions
+ EndIf
+ Else
+ Set Status = STATUS_NOLANGUAGE
+ GoTo ExitReturnOptions
+ EndIf
+
+SetOptions = +
+ Set OptionList = ^(Options, 1)
+ Set OptionTextList = ^(OptionsText$($0), 1)
+ Set Status = STATUS_SUCCESSFUL
+
+ExitReturnOptions = +
+ Return $(Status) $(OptionList) $(OptionTextList)
+
+;***********************************************************************
+;
+;***********************************************************************
+[InstallOption]
+ Set Status = STATUS_FAILED
+ Set Option = $($1)
+ Set SrcDir = $($2)
+ Set RasDir = $($2)
+ Set AddCopy = $($3)
+ Set DoCopy = $($4)
+ Set DoConfig = $($5)
+ Set LanguageList = ^(LanguagesSupported, 1)
+
+ IfContains(i) $($0) NOT-IN $(LanguageList)
+ Return STATUS_NOLANGUAGE
+ EndIf
+ ;
+ ; FIXME - make sure this flag is disabled before shipping
+ ;
+ Set OldDebugControl = $(!DebugOutputControl)
+; Set !DebugOutputControl = 1
+
+ Set-Subst LF = "\n"
+
+ Read-Syms GeneralConstants
+ Read-Syms FileConstants
+ Read-Syms DialogConstants$(!STF_LANGUAGE)
+
+ IfStr(i) $(!NTN_Origination) == "NCPA"
+ Set Continue = $(OK)
+ EndIf
+
+ Read-Syms FileConstants$(!STF_LANGUAGE)
+ Detect Date
+ Set-Title $(FunctionTitle)$(Option)
+
+ Set to = Begin
+ Set from = Begin
+ Set CommonStatus = STATUS_SUCCESSFUL
+
+ EndWait
+
+;***********************************************************************
+;
+;***********************************************************************
+Begin = +
+ Set ActivateDetection = FALSE
+ IfStr(i) $(!NTN_InstallMode) == deinstall
+ Set StartLabel = RemoveAdapter
+ Else-IfStr(i) $(!NTN_InstallMode) == Update
+ Set StartLabel = UpgradeSoftware
+ Else-IfStr(i) $(!NTN_InstallMode) == bind
+ Set StartLabel = BindingAdapter
+ Else-IfStr(i) $(!NTN_InstallMode) == configure
+ Set StartLabel = ConfigureAdapter
+ Set ActivateDetection = TRUE
+ Set CommonStatus = STATUS_REBOOT
+ IfStr(i) $(ProductKeyName) == $(!NTN_RegBase)
+ Debug-Output $(InfName)": Cannot configure the EtherWORKS 3 driver software."
+ Shell $(UtilityInf),RegistryErrorString,CANNOT_CONFIGURE_SOFTWARE
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output $(InfName)": ShellCode error: cannot get an error string."
+ GoTo ShellCodeError
+ EndIf
+ Set Error = $($R0)
+ Set from = end
+ Set to = end
+ GoTo NonFatalInfo
+ EndIf
+ Else
+ Set StartLabel = InstallAdapter
+ Set ActivateDetection = TRUE
+ Set OEM_ABANDON_OPTIONS = {}
+ Set OEM_ABANDON_SOFTWARE = FALSE
+ Set OEM_ABANDON_ON = TRUE
+ EndIf
+
+ Debug-Output $(InfName)": =================================================="
+ Debug-Output $(InfName)": STF_CWDIR is: "$(!STF_CWDIR)
+ Debug-Output $(InfName)": STF_LANGUAGE is: "$(!STF_LANGUAGE)
+ Debug-Output $(InfName)": Option is: "$(Option)
+ Debug-Output $(InfName)": !STF_NCDETECT is: "$(!STF_NCDETECT)
+ Debug-Output $(InfName)": !STF_NCOPTION is: "$(!STF_NCOPTION)
+ Debug-Output $(InfName)": !STF_NCDETCARD is: "$(!STF_NCDETCARD)
+ Debug-Output $(InfName)": !STF_NCDETINFO is: "$(!STF_NCDETINFO)
+ Debug-Output $(InfName)": =================================================="
+
+ Set DetectedCard = FALSE
+ IfStr(i) $(ActivateDetection) != TRUE
+ GoTo $(StartLabel)
+ EndIf
+
+ Debug-Output $(InfName)": Calling Param_SetDefaults"
+ Shell $(ParamInf) Param_SetDefaults {}
+
+ Shell $(ParamInf) HexListFromDecList $(RAM_Addr_List)
+ Set RAM_Hex_List = $($R0)
+
+ IfStr(i) $(!STF_NCDETECT) == YES
+ IfStr(i) $(!STF_NCOPTION) == $(Option)
+ Set DetectedCard = TRUE
+ Debug-Output $(InfName)": Setting DetectedCard to TRUE"
+ EndIf
+ EndIf
+
+ Shell "" DebugConfiguration "After parameter querying"
+ Set from = FatalError
+ Set to = FatalError
+ GoTo $(StartLabel)
+
+;***********************************************************************
+;
+;***********************************************************************
+InstallAdapter = +
+ OpenRegKey $(!REG_H_LOCAL) "" $(ProductKeyName) $(MAXIMUM_ALLOWED) KeyProduct
+ IfStr $(KeyProduct) != $(KeyNull)
+ CloseRegKey $(KeyProduct)
+ IfStr(i) !(NTN_RegBase) == $(ProductKeyName)
+ Shell $(UtilityInf), VerExistedDlg, $(ProductSoftwareTitle),+
+ $(ProductVersion)
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output $(InfName)": ShellCode error: cannot get an error string."
+ GoTo ShellCodeError
+ EndIf
+ GoTo end
+ Else
+ Shell $(UtilityInf), CardExistedDlg
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output $(InfName)": ShellCode error: cannot get an error string."
+ GoTo ShellCodeError
+ EndIf
+ IfStr(i) $($R1) != "OK"
+ Set CommonStatus = STATUS_USERCANCEL
+ GoTo end
+ EndIf
+ Set OldVersionExisted = $(TRUE)
+ EndIf
+ EndIf
+
+ Set CurrParamSettings = {}
+ IfStr(i) $(DetectedCard) != TRUE
+ GoTo AdapterSetup
+ EndIf
+
+ StartWait
+ Shell $(ParamInf) Param_QueryCard $(!STF_NCDETCARD)
+ EndWait
+
+ IfStr(i) $($R0) != STATUS_SUCCESSFUL
+ GoTo AdapterSetup
+ EndIf
+
+ Set DetectedParams = $($R1)
+ Debug-Output $(InfName)": Calling Param_SetDefaults to merge detected params"
+ Shell $(ParamInf) Param_SetDefaults $(DetectedParams)
+ GoTo AdapterSetup
+
+;***********************************************************************
+;
+;***********************************************************************
+ConfigureAdapter = +
+ IfStr $(KeyProduct) == $(KeyNull)
+ OpenRegKey $(!REG_H_LOCAL) "" $(!NTN_RegBase) $(MAXIMUM_ALLOWED) KeyProduct
+ IfStr $(KeyProduct) == $(KeyNull)
+ Set RegistryErrorIndex = CANNOT_FIND_COMPONENT_SERVICE
+ Debug-Output $(InfName)": Cannot find component product key"
+ GoTo FatalRegistry
+ EndIf
+ EndIf
+
+ Debug-Output $(InfName)": Shelling to FindService"
+ Shell $(UtilityInf) FindService, $(KeyProduct)
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output $(InfName)": FindService shell failure"
+ GoTo ShellCodeError
+ EndIf
+ IfStr(i) $($R0) != NO_ERROR
+ Debug-Output $(InfName)": FindService Shell error: "$($R0)
+ GoTo FatalRegistry
+ EndIf
+
+ Set KeyParameters = $($R2)
+ CloseRegKey $($R1)
+ IfStr $(KeyParameters) == $(KeyNull)
+ Set RegistryErrorIndex = CANNOT_FIND_COMPONENT_SERVICE
+ Debug-Output $(InfName)": Cannot find component service"
+ GoTo FatalRegistry
+ EndIf
+
+ Set OldVersionExisted = $(TRUE)
+ Set ValueName = ""
+ Set ValueData = ""
+ Set ValueStr = ""
+ Set ValueList = {}
+ EnumRegValue $(KeyParameters) ValueList
+ ForListDo $(ValueList)
+ Set ValueItem = $($)
+ Set ValueName = *($(ValueItem),1)
+ Set ValueData = *($(ValueItem),4)
+ Debug-Output $(InfName)": "$(ValueName)"="$(ValueData)
+ IfStr(i) $(ValueName) == "AddressList"
+ Set TapiAddressList = $(ValueData)
+ Else-IfStr(i) $(ValueName) == "RamBaseAddress"
+ Set RamBaseAddress = $(ValueData)
+ Else-IfStr(i) $(ValueName) == "InterruptNumber"
+ Set InterruptNumber = $(ValueData)
+ Else-IfStr(i) $(ValueName) == "LineType"
+ Set LineType = $(ValueData)
+ Else-IfStr(i) $(ValueName) == "LineRate"
+ Set LineRate = $(ValueData)
+ Else-IfStr(i) $(ValueName) == "BusNumber"
+ Set BusNumber = $(ValueData)
+ Else-IfStr(i) $(ValueName) == "BusType"
+ Set BusType = $(ValueData)
+ EndIf
+ EndForListDo
+ Shell $(ParamInf) Param_SaveValues
+ Set CurrParamSettings = $($R0)
+
+;***********************************************************************
+;
+;***********************************************************************
+AdapterSetup = +
+ Shell "" DebugConfiguration "before displaying dialog"
+ Set from = AdapterOptions
+ Set InterruptNumber = *($(IRQ_List), ~($(IRQ_List),$(InterruptNumber)))
+ Set RAM_Hex_Value = *($(RAM_Hex_List), ~($(RAM_Addr_List),$(RamBaseAddress)))
+ Set RateString = *($(Rate_Strings), ~($(Line_Rates),$(LineRate)))
+ Shell $(ParamInf) Param_ParameterConfidence
+ IfStr(i) $($R0) != STATUS_SUCCESSFUL
+ Debug-Output $(InfName)": parameter confidence too low to bypass configuration"
+ GoTo AdapterOptions
+ EndIf
+ IfStr(i) $(DetectedCard) == TRUE
+ IfStr(i) $(!STF_INSTALL_MODE) != CUSTOM
+ GoTo AdapterVerify
+ EndIf
+ EndIf
+
+;***********************************************************************
+;
+;***********************************************************************
+AdapterOptions = +
+ Read-Syms FileDependentDlg$(!STF_LANGUAGE)
+ UI Start "InputDlg"
+ IfStr(i) $(DLGEVENT) == "CONTINUE"
+ Set InterruptNumber = $(Combo1Out)
+ Set RAM_Hex_Value = $(Combo2Out)
+ Set RamBaseAddress = *($(RAM_Addr_List), ~($(RAM_Hex_List),$(RAM_Hex_Value)))
+ Set RateString = $(Combo3Out)
+ Set LineRate = *($(Line_Rates), ~($(Rate_Strings),$(RateString)))
+ ui pop 1
+ Else-IfStr(i) $(DLGEVENT) == "BACK"
+ Set CommonStatus = STATUS_USERCANCEL
+ Debug-Output $(InfName)": Action: exit. Bye."
+ ui pop 1
+ GoTo end
+ Else
+ Debug-Output $(InfName)": Action: unknown. Bye."
+ ui pop 1
+ GoTo end
+ EndIf
+ IfStr(i) $(!STF_NCDETINFO) == {}
+ Shell $(UtilityInf),GetBusTypeDialog,$(ProductHardware$(Option)Description) $(BusType) $(BusNumber)
+ ifInt $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output $(InfName)": ShellCode error."
+ GoTo ShellCodeError
+ EndIf
+ Set BusType = $($R1)
+ Set BusNumber = $($R2)
+ Else
+ Set BusType = *($(!STF_NCDETINFO),5)
+ Set BusNumber = *($(!STF_NCDETINFO),6)
+ EndIf
+
+;***********************************************************************
+;
+;***********************************************************************
+AdapterVerify = +
+ Shell "" DebugConfiguration "after running dialog"
+ IfStr(i) $(DetectedCard) != TRUE
+ Shell $(ParamInf) Param_SaveValues
+ Set NewParamSettings = $($R0)
+ IfStr(i) $(CurrParamSettings) == {}
+ Set DiffParamSettings = $(NewParamSettings)
+ Else
+ Shell $(ParamInf) Param_DiffValues $(CurrParamSettings)
+ Set DiffParamSettings = $($R0)
+ EndIf
+ Debug-Output $(InfName)": Calling Param_VerifyResources"
+ Shell $(ParamInf) Param_VerifyResources $(DiffParamSettings)
+ IfStr(i) $($R0) == STATUS_SUCCESSFUL
+ Debug-Output $(InfName)": Param_VerifyResources succeeded"
+ GoTo SkipOptions
+ EndIf
+ Else
+ Set CardVerifyIndex = $(!STF_NCDETCARD)
+ Debug-Output $(InfName)": Calling Param_VerifyCard"
+ Shell $(ParamInf) Param_VerifyCard $(!STF_NCDETCARD)
+ IfStr(i) $($R0) == STATUS_SUCCESSFUL
+ Debug-Output $(InfName)": Param_VerifyCard succeeded"
+ GoTo SkipOptions
+ EndIf
+ EndIf
+
+ Set from = AdapterOptions
+ Set to = SkipOptions
+ Shell $(UtilityInf),RegistryErrorString,VERIFY_WARNING
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output $(InfName)": ShellCode error: cannot get an error string."
+ GoTo ShellCodeError
+ EndIf
+ Set Error = $($R0)
+ GoTo WarningMsg
+
+;***********************************************************************
+;
+;***********************************************************************
+SkipOptions =+
+ IfInt $(OldVersionExisted) == $(TRUE)
+ IfStr(i) $(!NTN_InstallMode) == configure
+ GoTo WriteParameters
+ EndIf
+ EndIf
+ StartWait
+ IfInt $(OldVersionExisted) == $(FALSE)
+ IfStr(i) $(!NTN_InstallMode) == "install"
+ IfStr(i) $(DoCopy) == "YES"
+ Shell $(UtilityInf), DoAskSource, $(!STF_CWDDIR), $(SrcDir) YES
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ GoTo ShellCodeError
+ Else-IfStr(i) $($R0) == STATUS_FAILED
+ Shell $(UtilityInf) RegistryErrorString "ASK_SOURCE_FAIL"
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ GoTo ShellCodeError
+ EndIf
+ Set Error = $($R0)
+ GoTo FatalError
+ Else-IfStr(i) $($R0) == STATUS_USERCANCEL
+ GoTo SuccessfulOption
+ EndIf
+ Set SrcDir = $($R1)
+ EndIf
+
+ Install "Install-Option"
+ IfStr(i) $(STF_INSTALL_OUTCOME) != STF_SUCCESS
+ Shell $(UtilityInf) RegistryErrorString "UNABLE_COPY_FILE"
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ GoTo ShellCodeError
+ EndIf
+ Set Error = $($R0)
+ GoTo FatalError
+ EndIf
+ EndIf
+
+ Shell $(UtilityInf), AddSoftwareComponent, $(Manufacturer), +
+ $(ProductSoftwareName), +
+ $(ProductSoftwareName), +
+ $(ProductSoftwareTitle), $(STF_CONTEXTINFNAME), +
+ $(ProductSoftwareImagePath), "kernelautostart", "NDIS", {}, "",+
+ $(NetEventDLL)
+ Set OEM_ABANDON_SOFTWARE = TRUE
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output $(InfName)": ShellCode error"
+ GoTo ShellCodeError
+ EndIf
+ Set RegistryErrorIndex = $($R0)
+ Set KeyProduct = $($R1)
+ Set SoftNetRulesKey = $($R2)
+ CloseRegKey $($R3)
+ CloseRegKey $($R4)
+ CloseRegKey $($R5)
+
+ IfStr(i) $(RegistryErrorIndex) != NO_ERROR
+ EndWait
+ Debug-Output $(InfName)": Registry error: add software components"
+ CloseRegKey $(KeyProduct)
+ CloseRegKey $(SoftNetRulesKey)
+ GoTo FatalRegistry
+ EndIf
+
+ Set NewValueList = {{SoftwareType,$(NoTitle),$(!REG_VT_SZ),$(SoftwareType)},+
+ {MajorVersion,$(NoTitle),$(!REG_VT_DWORD),$(ProductMajorVersion)},+
+ {MinorVersion,$(NoTitle),$(!REG_VT_DWORD),$(ProductMinorVersion)},+
+ {Title,$(NoTitle),$(!REG_VT_SZ),$(ProductSoftwareTitle)},+
+ {Description,$(NoTitle),$(!REG_VT_SZ),$(ProductSoftwareDescription)},+
+ {ServiceName,$(NoTitle),$(!REG_VT_SZ),$(ProductSoftwareName)},+
+ {InstallDate,$(NoTitle),$(!REG_VT_DWORD),*($(Now),1)}}
+ Shell $(UtilityInf), AddValueList, $(KeyProduct), $(NewValueList)
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output $(InfName)": ShellCode error."
+ GoTo ShellCodeError
+ EndIf
+ Set RegistryErrorIndex = $($R0)
+ IfStr(i) $(RegistryErrorIndex) != NO_ERROR
+ EndWait
+ Debug-Output $(InfName)": Registry error: add value list."
+ CloseRegKey $(KeyProduct)
+ CloseRegKey $(SoftNetRulesKey)
+ GoTo FatalRegistry
+ EndIf
+
+ Set NewValueList = {{type,$(NoTitle),$(!REG_VT_SZ),$(NetRuleSoftwareType)},+
+ {use,$(NoTitle),$(!REG_VT_SZ),$(NetRuleSoftwareUse)}, +
+ {bindform,$(NoTitle),$(!REG_VT_SZ),$(NetRuleSoftwareBindForm)}, +
+ {class,$(NoTitle),$(!REG_VT_MULTI_SZ),$(NetRuleSoftwareClass)}, +
+ {bindable,$(NoTitle),$(!REG_VT_MULTI_SZ),$(Bindable$(Option)Txt)}, +
+ {InfOption,$(NoTitle),$(!REG_VT_SZ),$(Option)}}
+ Shell $(UtilityInf), AddValueList, $(SoftNetRulesKey), $(NewValueList)
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output $(InfName)": ShellCode error."
+ GoTo ShellCodeError
+ EndIf
+ Set RegistryErrorIndex = $($R0)
+ CloseRegKey $(KeyProduct)
+ CloseRegKey $(SoftNetRulesKey)
+ IfStr(i) $(RegistryErrorIndex) != NO_ERROR
+ EndWait
+ Debug-Output $(InfName)": Resgitry error: add value list."
+ GoTo FatalRegistry
+ EndIf
+ EndIf
+
+ Shell $(UtilityInf), AddHardwareComponent, $(ProductHardwareName),$(STF_CONTEXTINFNAME),$(ProductKeyName)
+ IfInt $($R4) != -1
+ Set OEM_ABANDON_OPTIONS = >($(OEM_ABANDON_OPTIONS), $(!NTN_SoftwareBase)"\Microsoft\Windows NT\CurrentVersion\NetworkCards\"$($R4))
+ EndIf
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output $(InfName)": Cannot add hardware component"
+ GoTo ShellCodeError
+ EndIf
+ Set RegistryErrorIndex = $($R0)
+ IfStr(i) $(RegistryErrorIndex) != NO_ERROR
+ EndWait
+ Debug-Output $(InfName)": Registry error: add hardware component"
+ CloseRegKey $($R1)
+ CloseRegKey $($R2)
+ CloseRegKey $($R3)
+ GoTo FatalRegistry
+ EndIf
+
+ Set KeyParameters = $($R3)
+ Set KeyAdapterRules = $($R2)
+ Set AdapterNumber = $($R4)
+ Set NewValueList = {{Manufacturer,$(NoTitle),$(!REG_VT_SZ),$(Manufacturer)},+
+ {Title,$(NoTitle),$(!REG_VT_SZ),"["$($R4)"] "$(ProductHardware$(Option)Title)},+
+ {Description,$(NoTitle),$(!REG_VT_SZ),$(ProductHardware$(Option)Description)},+
+ {ProductName,$(NoTitle),$(!REG_VT_SZ),$(ProductHardwareName)},+
+ {ServiceName,$(NoTitle),$(!REG_VT_SZ),$($R5)},+
+ {InstallDate,$(NoTitle),$(!REG_VT_DWORD),*($(Now),1)}}
+ Shell $(UtilityInf), AddValueList, $($R1), $(NewValueList)
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output $(InfName)": ShellCode error"
+ GoTo ShellCodeError
+ EndIf
+ CloseRegKey $($R1)
+
+;;; You need one address entry in the list for each channel on your device.
+;;; FIXME - at this point RAS requires there to be one logical line per address
+;;; FIXME - so the address (channel) number is ignored and the line number is used
+ Set TapiAddressList = {$(AdapterNumber)"-1-0"}
+ IfStr(i) $(Option) == HTDSU42
+ Set TapiAddressList = >($(TapiAddressList),$(AdapterNumber)"-2-0")
+ EndIf
+
+ Set TempProdName = """"$(ProductHardwareName)$(AdapterNumber)""""
+ Set TempBindForm = $(TempProdName)$(NetRuleHardwareBindForm)
+ Set NewValueList = {{type,$(NoTitle),$(!REG_VT_SZ),$(NetRuleHardware$(Option)Type)},+
+ {bindform,$(NoTitle),$(!REG_VT_SZ),$(TempBindForm)}, +
+ {class,$(NoTitle),$(!REG_VT_MULTI_SZ),$(NetRuleHardware$(Option)Class)}, +
+ {InfOption,$(NoTitle),$(!REG_VT_SZ),$(Option)}}
+ Shell $(UtilityInf), AddValueList, $(KeyAdapterRules), $(NewValueList)
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output $(InfName)": ShellCode error."
+ GoTo ShellCodeError
+ EndIf
+ Set RegistryErrorIndex = $($R0)
+ IfStr(i) $(RegistryErrorIndex) != NO_ERROR
+ EndWait
+ Debug-Output $(InfName)": Resgitry error: add value list."
+ CloseRegKey $(KeyParameters)
+ CloseRegKey $(KeyAdapterRules)
+ GoTo FatalRegistry
+ EndIf
+ CloseRegKey $(KeyAdapterRules)
+
+ GoTo WriteParameters
+
+;***********************************************************************
+;
+;***********************************************************************
+WriteParameters = +
+ Set NewValueList = {+
+ {AddressList,$(NoTitle),$(!REG_VT_MULTI_SZ),$(TapiAddressList)},+
+ {BusNumber,$(NoTitle),$(!REG_VT_DWORD),$(BusNumber)},+
+ {BusType,$(NoTitle),$(!REG_VT_DWORD),$(BusType)},+
+ {DeviceName,$(NoTitle),$(!REG_VT_SZ),$(ProductHardwareName)},+
+ {InterruptNumber,$(NoTitle),$(!REG_VT_DWORD),$(InterruptNumber)},+
+ {LineType,$(NoTitle),$(!REG_VT_DWORD),$(LineType)},+
+ {LineRate,$(NoTitle),$(!REG_VT_DWORD),$(LineRate)},+
+ {MediaType,$(NoTitle),$(!REG_VT_SZ),$(TapiMediaType)},+
+ {RamBaseAddress,$(NoTitle),$(!REG_VT_DWORD),$(RamBaseAddress)}+
+ }
+;;; {DebugFlags,$(NoTitle),$(!REG_VT_DWORD),$(DebugFlags)},+
+ Shell $(UtilityInf), AddValueList, $(KeyParameters), $(NewValueList)
+ CloseRegKey $(KeyParameters)
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output $(InfName)": ShellCode error."
+ GoTo ShellCodeError
+ EndIf
+ Set RegistryErrorIndex = $($R0)
+ IfStr(i) $(RegistryErrorIndex) != NO_ERROR
+ Debug-Output $(InfName)": Registry error: Add value list"
+ GoTo FatalRegistry
+ EndIf
+ ;
+ ; Create the HARDWARE\DEVICEMAP\TAPI DEVICES\HTDSU41 key
+ ;
+ OpenRegKey $(!REG_H_LOCAL) "" "HARDWARE\DEVICEMAP" $(MAXIMUM_ALLOWED) BaseKey
+ shell "" HtCreateRegKey $(BaseKey) "TAPI DEVICES\HTDSU41"
+ IfStr(i) $($R0) != NO_ERROR
+ Debug-Output $(InfName)": Error creating registry key!"
+ GoTo FatalRegistry
+ EndIf
+ Set TapiDeviceKey = $($R1)
+ Set NewValueList = {+
+ {Address,$(NoTitle),$(!REG_VT_MULTI_SZ),$(TapiAddressList)},+
+ {"Media Type",$(NoTitle),$(!REG_VT_SZ),$(TapiMediaType)}}
+ Shell $(UtilityInf), AddValueList, $(TapiDeviceKey), $(NewValueList)
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output $(InfName)": ShellCode error."
+ GoTo ShellCodeError
+ EndIf
+ Set RegistryErrorIndex = $($R0)
+ IfStr(i) $(RegistryErrorIndex) != NO_ERROR
+ Debug-Output $(InfName)": Registry error: Add value list"
+ GoTo FatalRegistry
+ EndIf
+ CloseRegKey $(TapiDeviceKey)
+ CloseRegKey $(BaseKey)
+ ;
+ ; if RAS is not installed, then shell ras setup INF file to install RAS
+ ; else invoke RAS to allow user to configure RAS for Switch56.
+ ;
+ Read-Syms InvokeRasDlg$(!STF_LANGUAGE)
+ Shell "oemnsvra.inf" CheckRasInstalled
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output $(InfName)": Error Shelling the RAS INF file oemnsvra.inf"
+ Shell "subroutn.inf" SetupMessage, $(!STF_LANGUAGE), +
+ "STATUS", $(InvokeRasError)
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ GoTo ShellCodeError
+ EndIf
+ GoTo SuccessfulOption
+ EndIf
+ Set RasInstalled = $($R0)
+ Debug-Output $(InfName)": Is RAS Installed? "$(RasInstalled)
+ ;
+ ; display a message to the user that RAS setup will now be invoked
+ ;
+ IfStr(i) $(RasInstalled) == FALSE
+ Shell "subroutn.inf" SetupMessage, $(!STF_LANGUAGE), "STATUS", +
+ $(InvokeRasSetupMsg)
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ GoTo SuccessfulOption
+ EndIf
+ Else
+ Shell "subroutn.inf" SetupMessage, $(!STF_LANGUAGE), "STATUS", +
+ $(InvokeRasConfigMsg)
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ GoTo SuccessfulOption
+ EndIf
+ EndIf
+ ;
+ ; If this is a reconfiguration, skip the automatic call to RAS setup.
+ ;
+ IfInt $(OldVersionExisted) == $(TRUE)
+ IfStr(i) $(!NTN_InstallMode) == configure
+ GoTo SuccessfulOption
+ EndIf
+ EndIf
+ ;
+ ; Set the flags based on whether this is an IDW installation
+ ;
+ IfStr(i) $(!STF_IDW) == TRUE
+ Set AddCopy = NO
+ Set DoCopy = NO
+ Set DoConfig = NO
+ Else
+ Set AddCopy = YES
+ Set DoCopy = YES
+ Set DoConfig = YES
+ EndIf
+ ;
+ ; change the global install mode flag to configure if RAS is already installed
+ ;
+ Set SaveNTN_InstallMode = $(!NTN_InstallMode)
+ IfStr(i) $(RasInstalled) == TRUE
+ Set !NTN_InstallMode = configure
+ Else
+ Set !NTN_InstallMode = install
+ EndIf
+ ;
+ ; Override the default drive\directory selection so user can choose..
+ ;
+ Set SaveSTF_SRCDIR_OVERRIDE = $(!STF_SRCDIR_OVERRIDE)
+ Set !STF_SRCDIR_OVERRIDE = ""
+ Set RasDir = "A:\"$(!STF_PLATFORM)
+ ;
+ ; now invoke RAS setup to do the right thing
+ ;
+ Debug-Output $(InfName)": Shelling to RAS:"
+ Shell "oemnsvra.inf" InstallOption $(!STF_LANGUAGE) "RAS" $(RasDir) $(AddCopy) $(DoCopy) $(DoConfig)
+ Debug-Output $(InfName)": Back from RAS: ShellCode="$($ShellCode)
+ ;
+ ; Restore the global install flags.
+ ;
+ Set !NTN_InstallMode = $(SaveNTN_InstallMode)
+ Set !STF_SRCDIR_OVERRIDE = $(SaveSTF_SRCDIR_OVERRIDE)
+ ;
+ ; Check for RAS errors.
+ ;
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output $(InfName)": Error Shelling the RAS INF file oemnsvra.inf"
+ Shell "subroutn.inf" SetupMessage, $(!STF_LANGUAGE), "STATUS", +
+ $(InvokeRasError)
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output $(InfName)": Cannot run SetupMessage: ShellCode="$($ShellCode)
+ GoTo ShellCodeError
+ EndIf
+ GoTo SuccessfulOption
+ EndIf
+ ;
+ ; If RAS reports no change, warn the user that the driver may not
+ ; be configured properly.
+ ;
+ IfStr(i) $($R0) == STATUS_NO_EFFECT
+ Shell "subroutn.inf" SetupMessage, $(!STF_LANGUAGE), "STATUS", +
+ $(InvokeRasAgainMsg)
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ GoTo SuccessfulOption
+ EndIf
+ EndIf
+
+ Set CommonStatus = $($R0)
+
+ GoTo SuccessfulOption
+
+;***********************************************************************
+;
+;***********************************************************************
+BindingAdapter =+
+ Set Error = "Binding: Sorry, not yet implemented."
+ GoTo FatalError
+
+;***********************************************************************
+;
+;***********************************************************************
+RemoveAdapter = +
+ IfStr(i) $(ProductKeyName) == $(!NTN_RegBase)
+ Shell $(UtilityInf), RemoveSoftwareComponent, $(Manufacturer), +
+ $(ProductSoftwareName)
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output $(InfName)": ShellCode error"
+ GoTo ShellCodeError
+ EndIf
+ Set RegistryErrorIndex = $($R0)
+ IfStr(i) $(RegistryErrorIndex) != NO_ERROR
+ GoTo FatalRegistry
+ EndIf
+ Else
+ Shell $(UtilityInf), RemoveHardwareComponent, $(Manufacturer), +
+ $(ProductSoftwareName), $(!NTN_RegBase)
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output $(InfName)": ShellCode error"
+ GoTo ShellCodeError
+ EndIf
+ Set RegistryErrorIndex = $($R0)
+ IfStr(i) $(RegistryErrorIndex) != NO_ERROR
+ GoTo FatalRegistry
+ EndIf
+ EndIf
+ GoTo end
+
+;***********************************************************************
+;
+;***********************************************************************
+UpgradeSoftware = +
+ IfStr(i) $(ProductKeyName) == $(!NTN_RegBase)
+ OpenRegKey $(!REG_H_LOCAL) "" $(ProductKeyName) $(MAXIMUM_ALLOWED) KeyProduct
+ IfStr $(KeyProduct) != $(KeyNull)
+ GetRegValue $(KeyProduct),"MajorVersion", VersionInfo
+ Set Version = *($(VersionInfo), 4)
+ Shell $(UtilityInf), GetInfFileNameFromRegistry, $(KeyProduct)
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output $(InfName)": ShellCode error"
+ GoTo ShellCodeError
+ EndIf
+ Set !UG_Filename = $($R0)
+ IfStr(i) $(!UG_Filename) != ""
+ install "Install-Update"
+ IfStr(i) $(STF_INSTALL_OUTCOME) != STF_SUCCESS
+ GoTo FatalError
+ EndIf
+ EndIf
+ SetRegValue $(KeyProduct) {MajorVersion,$(NoTitle),$(!REG_VT_SZ),$(ProductMajorVersion)}
+ SetRegValue $(KeyProduct) {MinorVersion,$(NoTitle),$(!REG_VT_SZ),$(ProductMinorVersion)}
+ IfInt $(Version) != $(ProductVersion)
+ EndIf
+ CloseRegKey $(KeyProduct)
+ Else
+ GoTo FatalRegistry
+ EndIf
+ Else
+ OpenRegKey $(!REG_H_LOCAL) "" $(!NTN_RegBase) +
+ $(MAXIMUM_ALLOWED) NetworkCardKey
+ IfStr(i) $(NetworkCardKey) != $(KeyNull)
+ GetRegValue $(NetworkCardKey),"ServiceName", ServiceNameInfo
+ Set ServiceName = *($(ServiceNameInfo), 4)
+ OpenRegKey $(NetworkCardKey) "" "NetRules" +
+ $(MAXIMUM_ALLOWED) NetRuleKey
+ IfStr(i) $(NetRuleKey) != $(KeyNull)
+ Else
+ GoTo FatalRegistry
+ EndIf
+ CloseRegKey $(NetRules)
+ CloseRegKey $(NetworkCardKey)
+ Else
+ GoTo FatalRegistry
+ EndIf
+ OpenRegKey $(!REG_H_LOCAL) "" +
+ $(!NTN_ServiceBase)"\"$(ServiceName) +
+ $(MAXIMUM_ALLOWED) ServiceKey
+ IfStr(i) $(ServiceKey) != $(KeyNull)
+ CloseRegKey $(ServiceKey)
+ Else
+ GoTo FatalRegistry
+ EndIf
+ EndIf
+ GoTo end
+
+;***********************************************************************
+;
+;***********************************************************************
+SuccessfulOption = +
+ GoTo end
+
+;***********************************************************************
+;
+;***********************************************************************
+Abandon = +
+ ForListDo $(OEM_ABANDON_OPTIONS)
+ Shell $(UtilityInf), RemoveHardwareComponent, $(Manufacturer), +
+ $(ProductSoftwareName), $($)
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output $(InfName)": ShellCode error"
+ GoTo ShellCodeError
+ EndIf
+ Set RegistryErrorIndex = $($R0)
+ IfStr(i) $(RegistryErrorIndex) != NO_ERROR
+ GoTo FatalRegistry
+ EndIf
+ EndForListDo
+ IfStr(i) $(OEM_ABANDON_SOFTWARE) == TRUE
+ Shell $(UtilityInf), RemoveSoftwareComponent, $(Manufacturer), +
+ $(ProductSoftwareName), FALSE
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output $(InfName)": ShellCode error"
+ GoTo ShellCodeError
+ EndIf
+ Set RegistryErrorIndex = $($R0)
+ IfStr(i) $(RegistryErrorIndex) != NO_ERROR
+ GoTo FatalRegistry
+ EndIf
+ EndIf
+ GoTo end
+
+;***********************************************************************
+;
+;***********************************************************************
+WarningMsg = +
+ Shell $(subroutineinf) SetupMessage, $(!STF_LANGUAGE), "WARNING", $(Error)
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ GoTo ShellCodeError
+ EndIf
+ IfStr(i) $($R1) == "OK"
+ GoTo $(to)
+ Else-IfStr(i) $($R1) == "CANCEL"
+ GoTo $(from)
+ EndIf
+ GoTo end
+
+;***********************************************************************
+;
+;***********************************************************************
+NonFatalInfo = +
+ Set Severity = STATUS
+ Set CommonStatus = STATUS_USERCANCEL
+ IfStr(i) $(Error) == ""
+ Set Severity = NONFATAL
+ Shell $(UtilityInf) RegistryErrorString "SETUP_FAIL"
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ GoTo ShellCodeError
+ EndIf
+ Set Error = $($R0)
+ EndIf
+ Shell $(subroutineinf) SetupMessage, $(!STF_LANGUAGE), $(Severity), $(Error)
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ GoTo ShellCodeError
+ EndIf
+ IfStr(i) $($R1) == "OK"
+ GoTo $(from)
+ EndIf
+ GoTo end
+
+;***********************************************************************
+;
+;***********************************************************************
+FatalRegistry = +
+ Shell $(UtilityInf) RegistryErrorString $(RegistryErrorIndex)
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ GoTo ShellCodeError
+ EndIf
+ Set Error = $($R0)
+ GoTo FatalError
+
+;***********************************************************************
+;
+;***********************************************************************
+FatalDetect = +
+ Shell $(UtilityInf),RegistryErrorString,CANNOT_DETECT
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output $(InfName)": ShellCode error: cannot get an error string."
+ GoTo ShellCodeError
+ EndIf
+ Set Error = $($R0)
+ GoTo FatalError
+
+;***********************************************************************
+;
+;***********************************************************************
+FatalError = +
+ IfStr(i) $(Error) == ""
+ Shell $(UtilityInf) RegistryErrorString "SETUP_FAIL"
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ GoTo ShellCodeError
+ EndIf
+ Set Error = $($R0)
+ EndIf
+ Shell $(subroutineinf) SetupMessage, $(!STF_LANGUAGE), "FATAL", $(Error)
+ IfInt $($ShellCode) != $(!SHELL_CODE_OK)
+ GoTo ShellCodeError
+ EndIf
+ GoTo SetFailed
+
+;***********************************************************************
+;
+;***********************************************************************
+ShellCodeError = +
+ Set DlgType = "MessageBox"
+ Set STF_MB_TITLE = $(ShellCodeErrorTitle)
+ Set STF_MB_TEXT = $(ShellCodeErrorText)
+ Set STF_MB_TYPE = 1
+ Set STF_MB_ICON = 3
+ Set STF_MB_DEF = 1
+ UI Start "Error Message"
+ GoTo SetFailed
+
+;***********************************************************************
+;
+;***********************************************************************
+SetFailed = +
+ Set CommonStatus = STATUS_FAILED
+ IfStr(i) $(OEM_ABANDON_ON) == TRUE
+ Set OEM_ABANDON_ON = FALSE
+ GoTo Abandon
+ EndIf
+ GoTo end
+
+;***********************************************************************
+;
+;***********************************************************************
+end = +
+ Set !DebugOutputControl = $(OldDebugControl)
+ Return $(CommonStatus)
+
+;***********************************************************************
+;
+;***********************************************************************
+[HtCreateRegKey]
+ Debug-Output $(InfName)": Entering [HtCreateRegKey]"
+ Set ECR_Result = NO_ERROR
+ Set ECR_BaseKeyHandle = $($0)
+ Set ECR_NewPath = $($1)
+ Set KeyNull = ""
+ Set MAXIMUM_ALLOWED = 33554432
+
+ Debug-Output $(InfName)": HtCreateRegKey - ECR_BaseKeyHandle = "$(ECR_BaseKeyHandle)
+ Debug-Output $(InfName)": ECR_NewPath = "$(ECR_NewPath)
+ Debug-Output $(InfName)": MAXIMUM_ALLOWED = "$(MAXIMUM_ALLOWED)
+ Debug-Output $(InfName)": KeyNull = "$(KeyNull)
+
+ OpenRegKey $(ECR_BaseKeyHandle) "" $(ECR_NewPath) $(MAXIMUM_ALLOWED) +
+ ECR_BaseKey
+ Debug-Output $(InfName)": ECR_BaseKey = "$(ECR_BaseKey)
+ Debug-Output $(InfName)": OpenRegKey returned "$($R0)
+ IfStr $(ECR_BaseKey) == $(KeyNull)
+ Debug-Output $(InfName)": ECR_BaseKey == KeyNull"
+ Else
+ Debug-Output $(InfName)": ECR_BaseKey != KeyNull"
+ Set ECR_KeyHandle = $(ECR_BaseKey)
+ GoTo ECR_Return
+ EndIf
+
+ Set ECR_TmpPath = ""
+ Split-String $(ECR_NewPath) "\" ECR_PList
+ Debug-Output $(InfName)": ECR_PList = "$(ECR_PList)
+ ForListDo $(ECR_PList)
+ IfStr(i) $($) != "\"
+ IfInt $(#) == 1
+ Set ECR_TmpPath = $($)
+ Else
+ Set ECR_TmpPath = $(ECR_TmpPath)"\"$($)
+ EndIf
+ Debug-Output $(InfName)": Determining if "$(ECR_TmpPath)" exists"
+ OpenRegKey $(ECR_BaseKeyHandle) "" $(ECR_TmpPath) $(MAXIMUM_ALLOWED) ECR_BaseKey
+ IfStr $(ECR_BaseKey) == $(KeyNull)
+ Debug-Output $(InfName)": Creating "$(ECR_TmpPath)
+ CreateRegKey $(ECR_BaseKeyHandle) {$(ECR_TmpPath),0,GenericClass} "" $(MAXIMUM_ALLOWED) "" ECR_KeyHandle
+ IfStr(i) $(ECR_KeyHandle) == $(KeyNull)
+ Set ECR_Result = $($R0)
+ GoTo ECR_Return
+ EndIf
+ EndIf
+ EndIf
+ EndForListDo
+ECR_Return = +
+ Return $(ECR_Result) $(ECR_KeyHandle)
+
+;***********************************************************************
+;
+;***********************************************************************
+[DebugConfiguration]
+ Debug-Output $(!p:InfName)": **CONFIGURATION STATE: "$($0)
+ Debug-Output $(!p:InfName)": InterruptNumber is "$(!p:InterruptNumber)
+ Debug-Output $(!p:InfName)": RamBaseAddress is "$(!p:RamBaseAddress)
+ Debug-Output $(!p:InfName)": LineType is "$(!p:LineType)
+ Debug-Output $(!p:InfName)": LineRate is "$(!p:LineRate)
+ Return
+
+;***********************************************************************
+;
+;***********************************************************************
+[Install-Option]
+ Set STF_VITAL = ""
+ IfStr(i) $(AddCopy) == "YES"
+ AddSectionFilesToCopyList Files-$(Option) $(SrcDir) $(!STF_WINDOWSSYSPATH)\drivers
+ EndIf
+ IfStr(i) $(DoCopy) == "YES"
+ Set !STF_NCPA_FLUSH_COPYLIST = TRUE
+ CopyFilesInCopyList
+ EndIf
+ Exit
+
+;***********************************************************************
+;
+;***********************************************************************
+[Install-Update]
+ Set STF_VITAL = ""
+ Set STF_OVERWRITE = "VERIFYSOURCEOLDER"
+ AddSectionFilesToCopyList Files-$(Option) $(SrcDir) $(!STF_WINDOWSSYSPATH)\drivers
+ AddSectionFilesToCopyList Files-Inf $(SrcDir) $(!STF_WINDOWSSYSPATH)
+ Set !STF_NCPA_FLUSH_COPYLIST = TRUE
+ CopyFilesInCopyList
+ Exit
+
+;***********************************************************************
+;
+;***********************************************************************
+[Source Media Descriptions]
+ 1 = "Windows NT Setup Disk #1" , TAGFILE = HTDSU41.SYS
+
+;***********************************************************************
+;
+;***********************************************************************
+[ProductType]
+ STF_PRODUCT = Winnt
+ STF_PLATFORM = I386
+
+;***********************************************************************
+;
+;***********************************************************************
+[Files-Inf]
+ 1, oemsetup.inf, SIZE=1000, RENAME=$(!UG_Filename)
+
+;***********************************************************************
+;
+;***********************************************************************
+[Files-HTDSU41]
+ 1, HTDSU41.SYS, SIZE=65536
+
+;***********************************************************************
+;
+;***********************************************************************
+[LanguagesSupported]
+ ENG
+
+;***********************************************************************
+;
+;***********************************************************************
+[OptionsTextENG]
+ HTDSU41 = "HT Communications DSU41"
+; HTDSU42 = "HT Communications DSU42"
+
+;***********************************************************************
+;
+;***********************************************************************
+[FileConstantsENG]
+ ProCaption = "Windows NT Setup"
+ ProCancel = "Cancel"
+ ProCancelMsg = "Windows NT Networking is not correctly installed. "+
+ "Are you sure you want to cancel copying files?"
+ ProCancelCap = "Network Setup Message"
+ ProText1 = "Copying:"
+ ProText2 = "To:"
+
+ FunctionTitleHTDSU41 = "HT Communications DSU41 Card Setup"
+ ProductSoftwareDescription = "HT Communications DSU41 Driver"
+ ProductHardwareHTDSU41Description = "HT Communications DSU41"
+ ProductSoftwareTitle = "HT Communications DSU41 Driver"
+ ProductHardwareHTDSU41Title = "HT Communications DSU41 Adapter"
+
+ ShellCodeErrorTitle = "Error: "$(FunctionTitle)$(Option))
+ ShellCodeErrorText = "Shell Code Error."
+
+;***********************************************************************
+;
+;***********************************************************************
+[DialogConstantsENG]
+ Help = "&Help"
+ Exit = "Cancel"
+ OK = "OK"
+ HelpContext = ""
+ Continue = "Continue"
+ Cancel = "Cancel"
+
+;***********************************************************************
+;
+;***********************************************************************
+[FileDependentDlgENG]
+ DlgType = "MultiCombo"
+ DlgTemplate = "WD"
+ Caption = $(FunctionTitle)$(Option)
+
+ Combo1Label = "&IRQ Level:"
+ Combo1List = $(IRQ_List)
+ Combo1Out = $(InterruptNumber)
+
+ Combo2Label = "&RAM Base Address:"
+ Combo2List = $(RAM_Hex_List)
+ Combo2Out = $(RAM_Hex_Value)
+
+ Combo3Label = "&Transmit Rate:"
+ Combo3List = $(Rate_Strings)
+ Combo3Out = $(RateString)
+
+ ComboListItemsIn = {Combo1List, Combo2List, Combo3List}
+ ComboListItemsOut = {Combo1Out, Combo2Out, Combo3Out}
+ EditTextIn = ""
+ EditTextLim = ""
+ CBOptionsGreyed = {}
+ NotifyFields = {NO, NO, NO}
+; HelpContext = $(!IDH_DB_OEMNAD1_INS)
+
+;***********************************************************************
+;
+;***********************************************************************
+[InvokeRasDlgENG]
+ InvokeRasSetupMsg = "HT Communications DSU41 setup is complete. "+
+ "Remote Access Services (RAS) must now be installed. "+
+ "Please configure the HTDSU41Sw56 ports in RAS "+
+ "setup to enable you to use RAS over the HTDSU41."
+ InvokeRasConfigMsg = "HT Communications DSU41 setup is complete. "+
+ "Remote Access Services (RAS) setup must now be invoked. "+
+ "Please configure the HTDSU41Sw56 ports in RAS "+
+ "setup to enable you to use RAS over the HTDSU41."
+ InvokeRasAgainMsg = "HT Communications DSU41 setup is NOT complete! "+
+ "Remote Access Services (RAS) is not configured to use a "+
+ "HTDSU41Sw56 port. You must configure at least one HTDSU41Sw56 "+
+ "port in RAS setup now, or you will have reconfigure the adapter "+
+ "before running RAS configuration again later."
+ InvokeRasError = "HT Communications DSU41 setup encountered an error "+
+ "while invoking the RAS setup INF file (OEMNSVRA.INF). "+
+ "Please make sure that the file is present in the "+
+ "System32 directory and is the proper file."
+
diff --git a/private/ntos/ndis/htdsu/receive.c b/private/ntos/ndis/htdsu/receive.c
new file mode 100644
index 000000000..08ddb1ab9
--- /dev/null
+++ b/private/ntos/ndis/htdsu/receive.c
@@ -0,0 +1,199 @@
+/***************************************************************************\
+|* Copyright (c) 1994 Microsoft Corporation *|
+|* Developed for Microsoft by TriplePoint, Inc. Beaverton, Oregon *|
+|* *|
+|* This file is part of the HT Communications DSU41 WAN Miniport Driver. *|
+\***************************************************************************/
+#include "version.h"
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Module Name:
+
+ receive.c
+
+Abstract:
+
+ This module contains the Miniport packet receive routines.
+
+ This driver conforms to the NDIS 3.0 Miniport interface.
+
+Author:
+
+ Larry Hattery - TriplePoint, Inc. (larryh@tpi.com) Jun-94
+
+Environment:
+
+ Windows NT 3.5 kernel mode Miniport driver or equivalent.
+
+Revision History:
+
+---------------------------------------------------------------------------*/
+
+#define __FILEID__ 6 // Unique file ID for error logging
+
+#include "htdsu.h"
+
+
+VOID
+HtDsuReceivePacket(
+ IN PHTDSU_ADAPTER Adapter
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Routine Description:
+
+ This routine is called from HtDsuHandleInterrupt to handle a
+ packet receive interrupt. We enter here with interrupts enabled
+ on the adapter and the processor, but the Adapter->Lock is held.
+
+ We examine the adapter memory beginning where the adapter would have
+ stored the next packet.
+ As we find each good packet it is passed up to the protocol stack.
+ This code assumes that the receive buffer holds a single packet.
+
+ NOTE: The Adapter->Lock must be held before calling this routine.
+
+Arguments:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+Return Value:
+
+ None.
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtDsuReceivePacket")
+
+ NDIS_STATUS Status;
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ /*
+ // Holds the card line number on which the packet is received.
+ */
+ USHORT CardLine;
+
+ /*
+ // How many bytes were received in this packet.
+ */
+ USHORT BytesReceived;
+
+ /*
+ // Non-zero if there were any errors detected in the packet.
+ */
+ USHORT RxErrors;
+
+ DBG_ENTER(Adapter);
+
+ /*
+ // If the packet is good, we pass it up to the protocol stack.
+ // We just drop bad packets with no indication sent.
+ */
+ CardGetReceiveInfo(Adapter, &CardLine, &BytesReceived, &RxErrors);
+
+ /*
+ // Don't send any bad packets to the wrapper, just indicate the error.
+ */
+ if (RxErrors)
+ {
+ DBG_WARNING(Adapter, ("RxError=%Xh on line %d\n",RxErrors, CardLine));
+
+ Link = GET_LINK_FROM_CARDLINE(Adapter, CardLine);
+
+ if (RxErrors & HTDSU_CRC_ERROR)
+ {
+ LinkLineError(Link, WAN_ERROR_CRC);
+ }
+ else
+ {
+ LinkLineError(Link, WAN_ERROR_FRAMING);
+ }
+ }
+ else if (BytesReceived)
+ {
+#if DBG
+ if (Adapter->DbgFlags & (DBG_PACKETS_ON | DBG_HEADERS_ON))
+ {
+ DbgPrint("Rx:%03X:",BytesReceived);
+ if (Adapter->DbgFlags & DBG_PACKETS_ON)
+ DbgPrintData((PUCHAR)&(Adapter->AdapterRam->RxBuffer), BytesReceived+8, 0);
+ else
+ DbgPrintData((PUCHAR)&(Adapter->AdapterRam->RxBuffer), 0x10, 0);
+ }
+#endif
+ /*
+ // Is there someone up there who cares?
+ */
+ Link = GET_LINK_FROM_CARDLINE(Adapter, CardLine);
+
+ if (Link->NdisLinkContext == NULL)
+ {
+ DBG_WARNING(Adapter, ("Packet recvd on disconnected line #%d",CardLine));
+ }
+ else
+ {
+ /*
+ // We have to copy the data to a system buffer so it can be
+ // accessed one byte at a time by the protocols.
+ // The adapter memory only supports word wide access.
+ */
+ {
+ // FIXME - can I use this much stack space?
+ USHORT TempBuf[HTDSU_MAX_PACKET_SIZE / sizeof(USHORT) + 1];
+
+ READ_REGISTER_BUFFER_USHORT(
+ &Adapter->AdapterRam->RxBuffer.Data[0],
+ &TempBuf[0],
+ (UINT)((BytesReceived + 1) / sizeof(USHORT))
+ );
+
+ /*
+ // Spec sez we have to release the spinlock before calling
+ // up to indiciate the packet.
+ */
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisMWanIndicateReceive(
+ &Status,
+ Adapter->MiniportAdapterHandle,
+ Link->NdisLinkContext,
+ (PUCHAR) TempBuf,
+ BytesReceived
+ );
+ }
+
+ /*
+ // Indicate receive complete if we had any that were accepted.
+ */
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ NdisMWanIndicateReceiveComplete(
+ Adapter->MiniportAdapterHandle,
+ Link->NdisLinkContext
+ );
+ }
+ else
+ {
+ DBG_WARNING(Adapter,("NdisMWanIndicateReceive returned error 0x%X\n",
+ Status));
+ }
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ }
+ }
+
+ /*
+ // Tell the adapter we have processed this packet so it can re-use the
+ // buffer.
+ */
+ CardReceiveComplete(Adapter);
+
+ DBG_LEAVE(Adapter);
+}
+
diff --git a/private/ntos/ndis/htdsu/request.c b/private/ntos/ndis/htdsu/request.c
new file mode 100644
index 000000000..7f9dd80c1
--- /dev/null
+++ b/private/ntos/ndis/htdsu/request.c
@@ -0,0 +1,661 @@
+/***************************************************************************\
+|* Copyright (c) 1994 Microsoft Corporation *|
+|* Developed for Microsoft by TriplePoint, Inc. Beaverton, Oregon *|
+|* *|
+|* This file is part of the HT Communications DSU41 WAN Miniport Driver. *|
+\***************************************************************************/
+#include "version.h"
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Module Name:
+
+ request.c
+
+Abstract:
+
+ This module implements the NDIS request routines for the Miniport driver.
+ MiniportQueryInformation()
+ MiniportSetInformation()
+
+ This driver conforms to the NDIS 3.0 Miniport interface.
+
+Author:
+
+ Larry Hattery - TriplePoint, Inc. (larryh@tpi.com) Jun-94
+
+Environment:
+
+ Windows NT 3.5 kernel mode Miniport driver or equivalent.
+
+Revision History:
+
+---------------------------------------------------------------------------*/
+
+#define __FILEID__ 5 // Unique file ID for error logging
+
+#include "htdsu.h"
+
+/*
+// The following is a list of all the possible NDIS QuereyInformation requests
+// that might be directed to the miniport.
+// Comment out any that are not supported by this driver.
+*/
+static const NDIS_OID SupportedOidArray[] =
+{
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_LOOKAHEAD,
+
+ OID_WAN_MEDIUM_SUBTYPE,
+ OID_WAN_GET_INFO,
+ OID_WAN_PERMANENT_ADDRESS,
+ OID_WAN_CURRENT_ADDRESS,
+ OID_WAN_GET_LINK_INFO,
+ OID_WAN_SET_LINK_INFO,
+#ifdef FUTURE_OIDS
+ OID_WAN_QUALITY_OF_SERVICE,
+ OID_WAN_PROTOCOL_TYPE,
+ OID_WAN_HEADER_FORMAT,
+ OID_WAN_LINE_COUNT,
+ OID_WAN_GET_BRIDGE_INFO,
+ OID_WAN_SET_BRIDGE_INFO,
+ OID_WAN_GET_COMP_INFO,
+ OID_WAN_SET_COMP_INFO,
+#endif // FUTURE_OIDS
+ 0
+};
+
+#if DBG
+
+/*
+// Make sure the following list is in the same order as the list above!
+*/
+static char *SupportedOidNames[] =
+{
+ "OID_GEN_HARDWARE_STATUS",
+ "OID_GEN_MEDIA_SUPPORTED",
+ "OID_GEN_MEDIA_IN_USE",
+ "OID_GEN_MAXIMUM_LOOKAHEAD",
+ "OID_GEN_MAXIMUM_FRAME_SIZE",
+ "OID_GEN_MAXIMUM_TOTAL_SIZE",
+ "OID_GEN_MAC_OPTIONS",
+ "OID_GEN_LINK_SPEED",
+ "OID_GEN_TRANSMIT_BUFFER_SPACE",
+ "OID_GEN_RECEIVE_BUFFER_SPACE",
+ "OID_GEN_TRANSMIT_BLOCK_SIZE",
+ "OID_GEN_RECEIVE_BLOCK_SIZE",
+ "OID_GEN_VENDOR_ID",
+ "OID_GEN_VENDOR_DESCRIPTION",
+ "OID_GEN_DRIVER_VERSION",
+ "OID_GEN_CURRENT_LOOKAHEAD",
+
+ "OID_WAN_MEDIUM_SUBTYPE",
+ "OID_WAN_GET_INFO",
+ "OID_WAN_PERMANENT_ADDRESS",
+ "OID_WAN_CURRENT_ADDRESS",
+ "OID_WAN_GET_LINK_INFO",
+ "OID_WAN_SET_LINK_INFO",
+#ifdef FUTURE_OIDS
+ "OID_WAN_QUALITY_OF_SERVICE",
+ "OID_WAN_PROTOCOL_TYPE",
+ "OID_WAN_HEADER_FORMAT",
+ "OID_WAN_LINE_COUNT",
+ "OID_WAN_GET_BRIDGE_INFO",
+ "OID_WAN_SET_BRIDGE_INFO",
+ "OID_WAN_GET_COMP_INFO",
+ "OID_WAN_SET_COMP_INFO",
+#endif // FUTURE_OIDS
+ "OID_UNKNOWN"
+};
+
+#define NUM_OID_ENTRIES (sizeof(SupportedOidArray) / sizeof(SupportedOidArray[0]))
+
+/*
+// This debug routine will lookup the printable name for the selected OID.
+*/
+char *
+HtGetOidString(NDIS_OID Oid)
+{
+ UINT i;
+
+ for (i = 0; i < NUM_OID_ENTRIES-1; i++)
+ {
+ if (SupportedOidArray[i] == Oid)
+ {
+ break;
+ }
+ }
+ return(SupportedOidNames[i]);
+}
+
+#endif // DBG
+
+/*
+// Returned from an OID_WAN_PERMANENT_ADDRESS HtDsuQueryInformation request.
+// The WAN wrapper wants the miniport to return a unique address for this
+// adapter. This is used as an ethernet address presented to the protocols.
+// The least significant bit of the first byte must not be a 1, or it could
+// be interpreted as an ethernet multicast address. If the vendor has an
+// assigned ethernet vendor code (the first 3 bytes), they should be used
+// to assure that the address does not conflict with another vendor's address.
+// The last digit is replaced during the call with the adapter instance number.
+*/
+static UCHAR HtDsuWanAddress[6] = {'H','t','D','s','u','0'};
+
+/*
+// Returned from an OID_GEN_VENDOR_ID HtDsuQueryInformation request.
+// Again, the vendor's assigned ethernet vendor code should be used if possible.
+*/
+static UCHAR HtDsuVendorID[4] = HTDSU_VENDOR_ID;
+
+/*
+// Returned from an OID_GEN_VENDOR_DESCRIPTION HtDsuQueryInformation request.
+// This is an arbitrary string which may be used by upper layers to present
+// a user friendly description of the adapter.
+*/
+static UCHAR HtDsuVendorDescription[] = HTDSU_VENDOR_DESCRPTION;
+
+
+NDIS_STATUS
+HtDsuQueryInformation(
+ IN PHTDSU_ADAPTER Adapter,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ The MiniportQueryInformation request allows the inspection of the
+ Miniport driver's capabilities and current status.
+
+ If the Miniport does not complete the call immediately (by returning
+ NDIS_STATUS_PENDING), it must call NdisMQueryInformationComplete to
+ complete the call. The Miniport controls the buffers pointed to by
+ InformationBuffer, BytesWritten, and BytesNeeded until the request
+ completes.
+
+ No other requests will be submitted to the Miniport driver until
+ this request has been completed.
+
+ Note that the wrapper will intercept all queries of the following OIDs:
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_802_5_CURRENT_FUNCTIONAL,
+ OID_802_3_MULTICAST_LIST,
+ OID_FDDI_LONG_MULTICAST_LIST,
+ OID_FDDI_SHORT_MULTICAST_LIST.
+
+ Interrupts are in any state during this call.
+
+Parameters:
+
+ MiniportAdapterContext _ The adapter handle passed to NdisMSetAttributes
+ during MiniportInitialize.
+
+ Oid _ The OID. (See section 7.4 of the NDIS 3.0 specification for a
+ complete description of OIDs.)
+
+ InformationBuffer _ The buffer that will receive the information.
+ (See section 7.4 of the NDIS 3.0 specification
+ for a description of the length required for each
+ OID.)
+
+ InformationBufferLength _ The length in bytes of InformationBuffer.
+
+ BytesWritten _ Returns the number of bytes written into
+ InformationBuffer.
+
+ BytesNeeded _ This parameter returns the number of additional bytes
+ needed to satisfy the OID.
+
+Return Values:
+
+ NDIS_STATUS_INVALID_DATA
+ NDIS_STATUS_INVALID_LENGTH
+ NDIS_STATUS_INVALID_OID
+ NDIS_STATUS_NOT_ACCEPTED
+ NDIS_STATUS_NOT_SUPPORTED
+ NDIS_STATUS_PENDING
+ NDIS_STATUS_RESOURCES
+ NDIS_STATUS_SUCCESS
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtDsuQueryInformation")
+
+ /*
+ // Holds the status result returned by this function.
+ */
+ NDIS_STATUS Status = NDIS_STATUS_NOT_SUPPORTED;
+
+ /*
+ // Pointer to driver data to be copied back to caller's InformationBuffer
+ */
+ PVOID SourceBuffer;
+
+ /*
+ // Number of bytes to be copied from driver.
+ */
+ ULONG SourceBufferLength;
+
+ /*
+ // Most return values are long integers, so this is used to hold the
+ // return value of a constant or computed result.
+ */
+ ULONG GenericUlong = 0;
+
+ /*
+ // Like above, only short.
+ */
+ USHORT GenericUshort;
+
+ /*
+ // If this is a TAPI OID, pass it on over.
+ */
+ if ((Oid & 0xFFFFFF00L) == (OID_TAPI_ACCEPT & 0xFFFFFF00L))
+ {
+ Status = HtTapiQueryInformation(Adapter,
+ Oid,
+ InformationBuffer,
+ InformationBufferLength,
+ BytesWritten,
+ BytesNeeded
+ );
+ return (Status);
+ }
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter,DBG_REQUEST_ON,
+ ("(OID=%s=%08x)\n\t\tInfoLength=%d InfoBuffer=%Xh\n",
+ HtGetOidString(Oid),Oid,
+ InformationBufferLength,
+ InformationBuffer
+ ));
+
+ /*
+ // Initialize these once, since this is the majority of cases.
+ */
+ SourceBuffer = &GenericUlong;
+ SourceBufferLength = sizeof(ULONG);
+
+ /*
+ // Determine which OID is being requested and do the right thing.
+ // Refer to section 7.4 of the NDIS 3.0 specification for a complete
+ // description of OIDs and their return values.
+ */
+ switch (Oid)
+ {
+ case OID_GEN_HARDWARE_STATUS:
+ GenericUlong = Adapter->NeedReset ?
+ NdisHardwareStatusNotReady :
+ NdisHardwareStatusReady;
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+ GenericUlong = NdisMediumWan;
+ break;
+
+ case OID_GEN_MEDIA_IN_USE:
+ GenericUlong = NdisMediumWan;
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+ GenericUlong = HTDSU_MAX_LOOKAHEAD;
+ break;
+
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+ GenericUlong = HTDSU_MAX_FRAME_SIZE;
+ break;
+
+ case OID_GEN_LINK_SPEED:
+ GenericUlong = HTDSU_LINK_SPEED;
+ break;
+
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+ GenericUlong = HTDSU_MAX_PACKET_SIZE;
+ break;
+
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+ GenericUlong = HTDSU_MAX_PACKET_SIZE;
+ break;
+
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+ GenericUlong = HTDSU_MAX_PACKET_SIZE;
+ break;
+
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+ GenericUlong = HTDSU_MAX_PACKET_SIZE;
+ break;
+
+ case OID_GEN_VENDOR_ID:
+ SourceBuffer = HtDsuVendorID;
+ SourceBufferLength = sizeof(HtDsuVendorID);
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+ SourceBuffer = HtDsuVendorDescription;
+ SourceBufferLength = strlen(HtDsuVendorDescription) + 1;
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ GenericUlong = HTDSU_MAX_LOOKAHEAD;
+ break;
+
+ case OID_GEN_MAC_OPTIONS:
+ GenericUlong = NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
+ NDIS_MAC_OPTION_NO_LOOPBACK |
+ NDIS_MAC_OPTION_TRANSFERS_NOT_PEND;
+ break;
+
+ case OID_GEN_DRIVER_VERSION:
+ GenericUshort = (NDIS_MAJOR_VERSION << 8) + NDIS_MINOR_VERSION;
+ SourceBuffer = &GenericUshort;
+ SourceBufferLength = sizeof(USHORT);
+ break;
+
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+ GenericUlong = HTDSU_MAX_PACKET_SIZE;
+ break;
+
+ case OID_WAN_MEDIUM_SUBTYPE:
+ GenericUlong = NdisWanMediumSW56K;
+ break;
+
+ case OID_WAN_GET_INFO:
+ SourceBuffer = &Adapter->WanInfo;
+ SourceBufferLength = sizeof(NDIS_WAN_INFO);
+ break;
+
+ case OID_WAN_PERMANENT_ADDRESS:
+ case OID_WAN_CURRENT_ADDRESS:
+ HtDsuWanAddress[5] = Adapter->InstanceNumber + '0';
+ SourceBuffer = HtDsuWanAddress;
+ SourceBufferLength = sizeof(HtDsuWanAddress);
+ break;
+
+ case OID_WAN_GET_LINK_INFO:
+ {
+ /*
+ // The first field in the info buffer is a MiniportLinkContext
+ // which is really a pointer to an entry in our link information.
+ // If this aint so, bail out...
+ */
+ PHTDSU_LINK Link = (PHTDSU_LINK)
+ (((PNDIS_WAN_SET_LINK_INFO)InformationBuffer)->NdisLinkHandle);
+
+ if (!IS_VALID_LINK(Adapter, Link))
+ {
+ SourceBufferLength = 0;
+ Status = NDIS_STATUS_INVALID_DATA;
+ break;
+ }
+
+ DBG_NOTICE(Adapter,("Returning:\n"
+ "NdisLinkHandle = %08lX\n"
+ "MaxSendFrameSize = %08lX\n"
+ "MaxRecvFrameSize = %08lX\n"
+ "SendFramingBits = %08lX\n"
+ "RecvFramingBits = %08lX\n"
+ "SendACCM = %08lX\n"
+ "RecvACCM = %08lX\n",
+ Link->WanLinkInfo.NdisLinkHandle ,
+ Link->WanLinkInfo.MaxSendFrameSize ,
+ Link->WanLinkInfo.MaxRecvFrameSize ,
+ Link->WanLinkInfo.SendFramingBits ,
+ Link->WanLinkInfo.RecvFramingBits ,
+ Link->WanLinkInfo.SendACCM ,
+ Link->WanLinkInfo.RecvACCM ));
+
+ SourceBuffer = &(Link->WanLinkInfo);
+ SourceBufferLength = sizeof(NDIS_WAN_GET_LINK_INFO);
+ }
+ break;
+
+ default:
+ /*
+ // Unknown OID
+ */
+ Status = NDIS_STATUS_INVALID_OID;
+ SourceBufferLength = 0;
+ break;
+ }
+
+ /*
+ // Now we copy the data into the caller's buffer if there's enough room,
+ // otherwise, we report the error and tell em how much we need.
+ */
+ if (SourceBufferLength > InformationBufferLength)
+ {
+ *BytesNeeded = SourceBufferLength;
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ }
+ else if (SourceBufferLength)
+ {
+ NdisMoveMemory(InformationBuffer,
+ SourceBuffer,
+ SourceBufferLength
+ );
+ *BytesNeeded = *BytesWritten = SourceBufferLength;
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ else
+ {
+ *BytesNeeded = *BytesWritten = 0;
+ }
+ DBG_FILTER(Adapter,DBG_REQUEST_ON,
+ ("RETURN: Status=%Xh Needed=%d Written=%d\n",
+ Status, *BytesNeeded, *BytesWritten));
+ DBG_LEAVE(Adapter);
+
+ return (Status);
+}
+
+
+NDIS_STATUS
+HtDsuSetInformation(
+ IN PHTDSU_ADAPTER Adapter,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ The MiniportSetInformation request allows for control of the Miniport
+ by changing information maintained by the Miniport driver.
+
+ Any of the settable NDIS Global Oids may be used. (see section 7.4 of
+ the NDIS 3.0 specification for a complete description of the NDIS Oids.)
+
+ If the Miniport does not complete the call immediately (by returning
+ NDIS_STATUS_PENDING), it must call NdisMSetInformationComplete to
+ complete the call. The Miniport controls the buffers pointed to by
+ InformationBuffer, BytesRead, and BytesNeeded until the request completes.
+
+ Interrupts are in any state during the call, and no other requests will
+ be submitted to the Miniport until this request is completed.
+
+Parameters:
+
+ MiniportAdapterContext _ The adapter handle passed to NdisMSetAttributes
+ during MiniportInitialize.
+
+ Oid _ The OID. (See section 7.4 of the NDIS 3.0 specification for
+ a complete description of OIDs.)
+
+ InformationBuffer _ The buffer that will receive the information.
+ (See section 7.4 of the NDIS 3.0 specification for
+ a description of the length required for each OID.)
+
+ InformationBufferLength _ The length in bytes of InformationBuffer.
+
+ BytesRead_ Returns the number of bytes read from InformationBuffer.
+
+ BytesNeeded _ This parameter returns the number of additional bytes
+ expected to satisfy the OID.
+
+Return Values:
+
+ NDIS_STATUS_INVALID_DATA
+ NDIS_STATUS_INVALID_LENGTH
+ NDIS_STATUS_INVALID_OID
+ NDIS_STATUS_NOT_ACCEPTED
+ NDIS_STATUS_NOT_SUPPORTED
+ NDIS_STATUS_PENDING
+ NDIS_STATUS_RESOURCES
+ NDIS_STATUS_SUCCESS
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtDsuSetInformation")
+
+ /*
+ // Holds the status result returned by this function.
+ */
+ NDIS_STATUS Status;
+
+ /*
+ // If this is a TAPI OID, pass it on over.
+ */
+ if ((Oid & 0xFFFFFF00L) == (OID_TAPI_ACCEPT & 0xFFFFFF00L))
+ {
+ Status = HtTapiSetInformation(Adapter,
+ Oid,
+ InformationBuffer,
+ InformationBufferLength,
+ BytesRead,
+ BytesNeeded
+ );
+ return (Status);
+ }
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter,DBG_REQUEST_ON,
+ ("(OID=%s=%08x)\n\t\tInfoLength=%d InfoBuffer=%Xh\n",
+ HtGetOidString(Oid),Oid,
+ InformationBufferLength,
+ InformationBuffer
+ ));
+
+ /*
+ // Assume no extra bytes are needed.
+ */
+ ASSERT(BytesRead && BytesNeeded);
+ *BytesRead = 0;
+ *BytesNeeded = 0;
+
+ /*
+ // Determine which OID is being requested and do the right thing.
+ */
+ switch (Oid)
+ {
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ /*
+ // WAN drivers always indicate the entire packet regardless of the
+ // lookahead size. So this request should be politely ignored.
+ */
+ DBG_NOTICE(Adapter,("OID_GEN_CURRENT_LOOKAHEAD: set=%d expected=%d\n",
+ *(PULONG) InformationBuffer, HTDSU_MAX_LOOKAHEAD));
+ ASSERT(InformationBufferLength == sizeof(ULONG));
+ *BytesNeeded = *BytesRead = sizeof(ULONG);
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+
+ case OID_WAN_SET_LINK_INFO:
+
+ if (InformationBufferLength == sizeof(NDIS_WAN_SET_LINK_INFO))
+ {
+ /*
+ // The first field in the info buffer is a MiniportLinkContext
+ // which is really a pointer to an entry in our WanLinkArray.
+ // If this aint so, bail out...
+ */
+ PHTDSU_LINK Link = (PHTDSU_LINK)
+ (((PNDIS_WAN_SET_LINK_INFO)InformationBuffer)->NdisLinkHandle);
+
+ if (Link == NULL)
+ {
+ Status = NDIS_STATUS_INVALID_DATA;
+ break;
+ }
+
+ ASSERT(Link->WanLinkInfo.NdisLinkHandle == Link);
+ ASSERT(Link->WanLinkInfo.MaxSendFrameSize <= Adapter->WanInfo.MaxFrameSize);
+ ASSERT(Link->WanLinkInfo.MaxRecvFrameSize <= Adapter->WanInfo.MaxFrameSize);
+ ASSERT(!(Link->WanLinkInfo.SendFramingBits & ~Adapter->WanInfo.FramingBits));
+ ASSERT(!(Link->WanLinkInfo.RecvFramingBits & ~Adapter->WanInfo.FramingBits));
+
+ /*
+ // Copy the data into our WanLinkInfo sturcture.
+ */
+ NdisMoveMemory(&(Link->WanLinkInfo),
+ InformationBuffer,
+ InformationBufferLength
+ );
+ *BytesRead = sizeof(NDIS_WAN_SET_LINK_INFO);
+ Status = NDIS_STATUS_SUCCESS;
+
+ DBG_NOTICE(Adapter,("\n setting expected\n"
+ "NdisLinkHandle = %08lX=?=%08lX\n"
+ "MaxSendFrameSize = %08lX=?=%08lX\n"
+ "MaxRecvFrameSize = %08lX=?=%08lX\n"
+ "SendFramingBits = %08lX=?=%08lX\n"
+ "RecvFramingBits = %08lX=?=%08lX\n"
+ "SendACCM = %08lX=?=%08lX\n"
+ "RecvACCM = %08lX=?=%08lX\n",
+ Link->WanLinkInfo.NdisLinkHandle , Link,
+ Link->WanLinkInfo.MaxSendFrameSize , Adapter->WanInfo.MaxFrameSize,
+ Link->WanLinkInfo.MaxRecvFrameSize , Adapter->WanInfo.MaxFrameSize,
+ Link->WanLinkInfo.SendFramingBits , Adapter->WanInfo.FramingBits,
+ Link->WanLinkInfo.RecvFramingBits , Adapter->WanInfo.FramingBits,
+ Link->WanLinkInfo.SendACCM , Adapter->WanInfo.DesiredACCM,
+ Link->WanLinkInfo.RecvACCM , Adapter->WanInfo.DesiredACCM));
+ }
+ else
+ {
+ DBG_WARNING(Adapter, ("OID_WAN_SET_LINK_INFO: Invalid size:%d expected:%d\n",
+ InformationBufferLength, sizeof(NDIS_WAN_SET_LINK_INFO)));
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ }
+ *BytesNeeded = sizeof(NDIS_WAN_SET_LINK_INFO);
+ break;
+
+ default:
+ /*
+ // Unknown OID
+ */
+ Status = NDIS_STATUS_INVALID_OID;
+ break;
+ }
+ DBG_FILTER(Adapter,DBG_REQUEST_ON,
+ ("RETURN: Status=%Xh Needed=%d Read=%d\n",
+ Status, *BytesNeeded, *BytesRead));
+ DBG_LEAVE(Adapter);
+
+ return (Status);
+}
+
diff --git a/private/ntos/ndis/htdsu/send.c b/private/ntos/ndis/htdsu/send.c
new file mode 100644
index 000000000..575983bf0
--- /dev/null
+++ b/private/ntos/ndis/htdsu/send.c
@@ -0,0 +1,502 @@
+/***************************************************************************\
+|* Copyright (c) 1994 Microsoft Corporation *|
+|* Developed for Microsoft by TriplePoint, Inc. Beaverton, Oregon *|
+|* *|
+|* This file is part of the HT Communications DSU41 WAN Miniport Driver. *|
+\***************************************************************************/
+#include "version.h"
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Module Name:
+
+ send.c
+
+Abstract:
+
+ This module contains the Miniport packet send routines.
+
+ This driver conforms to the NDIS 3.0 Miniport interface.
+
+Author:
+
+ Larry Hattery - TriplePoint, Inc. (larryh@tpi.com) Jun-94
+
+Environment:
+
+ Windows NT 3.5 kernel mode Miniport driver or equivalent.
+
+Revision History:
+
+---------------------------------------------------------------------------*/
+
+#define __FILEID__ 7 // Unique file ID for error logging
+
+#include "htdsu.h"
+
+
+STATIC
+BOOLEAN
+QueueForTransmit(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_WAN_PACKET Packet
+ );
+
+STATIC
+VOID
+HtDsuTransmitFrame(
+ IN PHTDSU_ADAPTER Adapter
+ );
+
+
+NDIS_STATUS
+HtDsuWanSend(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PHTDSU_LINK Link,
+ IN PNDIS_WAN_PACKET Packet
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ The Ndis(M)WanSend instructs a WAN driver to transmit a packet through the
+ adapter onto the medium.
+
+ Ownership of both the packet descriptor and the packet data is transferred
+ to the WAN driver until the request is completed, either synchronously or
+ asynchronously. If the WAN driver returns a status other than
+ NDIS_STATUS_PENDING, then the request is complete, and ownership of the
+ packet immediately reverts to the protocol. If the WAN driver returns
+ NDIS_STATUS_PENDING, then the WAN driver must later indicate completion
+ of the request by calling Ndis(M)WanSendComplete.
+
+ The WAN driver should NOT return a status of NDIS_STATUS_RESOURCES to
+ indicate that there are not enough resources available to process the
+ transmit. Instead, the miniport should queue the send for a later time
+ or lower the MaxTransmits value.
+
+ The WAN miniport can NOT call NdisMSendResourcesAvailable.
+
+ The packet passed in Ndis(M)WanSend will contain simple HDLC PPP framing
+ if PPP framing is set. For SLIP or RAS framing, the packet contains only
+ the data portion with no framing whatsoever.
+
+ A WAN driver must NOT provide software loopback or promiscuous mode
+ loopback. Both of these are fully provided for in the WAN wrapper.
+
+ NOTE: The MacReservedx section as well as the WanPacketQueue section of
+ the NDIS_WAN_PACKET is fully available for use by the WAN driver.
+
+ Interrupts are in any state during this routine.
+
+Parameters:
+
+ MacBindingHandle _ The handle to be passed to NdisMWanSendComplete().
+
+ NdisLinkHandle _ The Miniport link handle passed to NDIS_LINE_UP
+
+ WanPacket _ A pointer to the NDIS_WAN_PACKET strucutre. The structure
+ contains a pointer to a contiguous buffer with guaranteed
+ padding at the beginning and end. The driver may manipulate
+ the buffer in any way.
+
+ typedef struct _NDIS_WAN_PACKET
+ {
+ LIST_ENTRY WanPacketQueue;
+ PUCHAR CurrentBuffer;
+ ULONG CurrentLength;
+ PUCHAR StartBuffer;
+ PUCHAR EndBuffer;
+ PVOID ProtocolReserved1;
+ PVOID ProtocolReserved2;
+ PVOID ProtocolReserved3;
+ PVOID ProtocolReserved4;
+ PVOID MacReserved1; // Link
+ PVOID MacReserved2; // MacBindingHandle
+ PVOID MacReserved3;
+ PVOID MacReserved4;
+
+ } NDIS_WAN_PACKET, *PNDIS_WAN_PACKET;
+
+ The available header padding is simply CurrentBuffer-StartBuffer.
+ The available tail padding is EndBuffer-(CurrentBuffer+CurrentLength).
+
+Return Values:
+
+ NDIS_STATUS_INVALID_DATA
+ NDIS_STATUS_INVALID_LENGTH
+ NDIS_STATUS_INVALID_OID
+ NDIS_STATUS_NOT_ACCEPTED
+ NDIS_STATUS_NOT_SUPPORTED
+ NDIS_STATUS_PENDING
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_FAILURE
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtDsuWanSend")
+
+ /*
+ // The link is associated with the adapter with a back pointer.
+ */
+ PHTDSU_ADAPTER Adapter = Link->Adapter;
+
+ /*
+ // Tells us how many bytes are to be transmitted.
+ */
+ UINT BytesToSend = Packet->CurrentLength;
+
+ /*
+ // Holds the status that should be returned to the caller.
+ */
+ NDIS_STATUS StatusToReturn;
+
+ DBG_ENTER(Adapter);
+
+ /*
+ // We grab the spin lock on entry so we don't accidently stomp on
+ // some data structure being twiddled with by the DPC or another
+ // client thread.
+ */
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ /*
+ // Make sure the packet size is something we can deal with.
+ */
+ if ((BytesToSend == 0) || (BytesToSend > HTDSU_MAX_PACKET_SIZE))
+ {
+ DBG_ERROR(Adapter,("Bad packet size = %d\n",BytesToSend));
+ StatusToReturn = NDIS_STATUS_FAILURE;
+ }
+ /*
+ // Return if line is not connected.
+ */
+ else if (!CardStatusOnLine(Adapter, Link->CardLine))
+ {
+ DBG_ERROR(Adapter, ("Line Disconnected\n"));
+ StatusToReturn = NDIS_STATUS_FAILURE;
+ }
+ /*
+ // Return if line has been closed.
+ */
+ else if (Link->Closing || Link->CallClosing)
+ {
+ DBG_ERROR(Adapter, ("Link Closed\n"));
+ StatusToReturn = NDIS_STATUS_FAILURE;
+ }
+ else
+ {
+ /*
+ // We have to accept the frame if possible, I just want to know
+ // if somebody has lied to us...
+ */
+ if (BytesToSend > Link->WanLinkInfo.MaxSendFrameSize)
+ {
+ DBG_WARNING(Adapter,("Packet size=%d > %d\n",
+ BytesToSend, Link->WanLinkInfo.MaxSendFrameSize));
+ }
+
+ /*
+ // We'll need to use these when the transmit completes.
+ */
+ Packet->MacReserved1 = (PVOID) Link;
+ Packet->MacReserved2 = (PVOID) MacBindingHandle;
+
+ /*
+ // Place the packet in the transmit list.
+ */
+ ++Link->NumTxQueued;
+ if (QueueForTransmit(Adapter, Packet))
+ {
+ /*
+ // The queue was empty so we've gotta kick start it.
+ // Once it's going, it runs off the DPC.
+ */
+ HtDsuTransmitFrame(Adapter);
+ }
+ StatusToReturn = NDIS_STATUS_PENDING;
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ DBG_LEAVE(Adapter);
+
+ return StatusToReturn;
+}
+
+
+STATIC
+BOOLEAN
+QueueForTransmit(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_WAN_PACKET Packet
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Routine Description:
+
+ This routine places the packet on the transmit queue. If the queue was
+ empty to begin with TRUE is returned so the caller can kick start the
+ transmiter.
+
+ NOTE: The Adapter->Lock must be held before calling this routine.
+
+Arguments:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Packet _ The packet that is to be transmitted.
+
+Return Value:
+
+ TRUE if this is the only entry in the list; FALSE otherwise.
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("QueueForTransmit")
+
+ /*
+ // Note if the list is empty to begin with.
+ */
+ BOOLEAN ListWasEmpty;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON, ("(Packet=0x%08x)\n", Packet));
+
+ /*
+ // Place the packet on the transmit queue.
+ */
+ ListWasEmpty = IsListEmpty(&Adapter->TransmitIdleList);
+ InsertTailList(&Adapter->TransmitIdleList, &Packet->WanPacketQueue);
+
+ DBG_LEAVE(Adapter);
+
+ return (ListWasEmpty);
+}
+
+
+STATIC
+VOID
+HtDsuTransmitFrame(
+ IN PHTDSU_ADAPTER Adapter
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Routine Description:
+
+ This routine removes an entry from the TransmitIdleList and places the
+ packet on the adapter and starts transmision. The packet is then placed
+ on the TransmitBusyList to await a transmit complete interrupt.
+
+ NOTE: The Adapter->Lock must be held before calling this routine.
+
+Arguments:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+Return Value:
+
+ None.
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtDsuTransmitFrame")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ /*
+ // Holds the packet being transmitted.
+ */
+ PNDIS_WAN_PACKET Packet;
+
+ /*
+ // Tells us how many bytes are to be transmitted.
+ */
+ USHORT BytesToSend;
+
+ DBG_ENTER(Adapter);
+
+ /*
+ // This might be called when no packets are queued!
+ */
+ if (!IsListEmpty(&Adapter->TransmitIdleList) &&
+ !(Adapter->TransmitInProgress))
+ {
+ Adapter->TransmitInProgress = TRUE;
+
+ /*
+ // The TransmitIdleList contains a list of packets waiting to be
+ // transmitted.
+ */
+ Packet = (PNDIS_WAN_PACKET)RemoveHeadList(&Adapter->TransmitIdleList);
+ DBG_FILTER(Adapter,DBG_PARAMS_ON,("(Packet=0x%08x)\n",Packet));
+
+ Link = (PHTDSU_LINK) Packet->MacReserved1;
+
+ BytesToSend = (USHORT) Packet->CurrentLength;
+
+ /*
+ // Move the packet data into our mapped memory buffer on the card.
+ */
+ WRITE_REGISTER_BUFFER_USHORT(
+ &Adapter->AdapterRam->TxBuffer.Data[0],
+ (PUSHORT) &Packet->CurrentBuffer[0],
+ (UINT)((BytesToSend + 1) / sizeof(USHORT))
+ );
+
+ /*
+ // Set the address, length, and closing flag.
+ */
+ CardPrepareTransmit(Adapter, Link->CardLine, BytesToSend);
+
+#if DBG
+ if (Adapter->DbgFlags & (DBG_PACKETS_ON | DBG_HEADERS_ON))
+ {
+ DbgPrint("Tx:%03X:", BytesToSend);
+ if (Adapter->DbgFlags & DBG_PACKETS_ON)
+ DbgPrintData((PUCHAR)&(Adapter->AdapterRam->TxBuffer), BytesToSend+8, 0);
+ else
+ DbgPrintData((PUCHAR)&(Adapter->AdapterRam->TxBuffer), 0x10, 0);
+ }
+#endif
+ /*
+ // Insert packet into busy queue while the adapter is sending it out.
+ */
+ InsertTailList(&Adapter->TransmitBusyList, &Packet->WanPacketQueue);
+
+ /*
+ // Tell the adapter to send the packet out.
+ */
+ CardStartTransmit(Adapter);
+ }
+
+ DBG_LEAVE(Adapter);
+}
+
+
+VOID
+HtDsuTransmitComplete(
+ IN PHTDSU_ADAPTER Adapter
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Routine Description:
+
+ This routine is called by HtDsuHandleInterrupt() to handle a transmit
+ complete interrupt. We enter here with interrupts disabled at the adapter,
+ but the Adapter->Lock is held. We walk the TransmitBusyList to find all
+ the transmits that have completed.
+
+ NOTE: The Adapter->Lock must be held before calling this routine.
+
+Arguments:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+Return Value:
+
+ None.
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtDsuTransmitComplete")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ /*
+ // Holds the packet that's just been transmitted.
+ */
+ PNDIS_WAN_PACKET Packet;
+
+ DBG_ENTER(Adapter);
+
+ /*
+ // Since we're here, the must be a packet on the busy list,
+ // and the adapter better be done with it.
+ */
+ ASSERT(CardTransmitEmpty(Adapter));
+ if (!IsListEmpty(&Adapter->TransmitBusyList) &&
+ CardTransmitEmpty(Adapter))
+ {
+ ASSERT(Adapter->TransmitInProgress);
+
+ /*
+ // Remove the transmit from the transmit list
+ */
+ Packet = (PNDIS_WAN_PACKET)RemoveHeadList(&Adapter->TransmitBusyList);
+
+ Link = (PHTDSU_LINK) Packet->MacReserved1;
+
+ /*
+ // Indicate send complete to the wrapper, and we can't hold the
+ // spin lock when we relinquish control or we may dead-lock.
+ */
+ DBG_TRACE(Adapter);
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisMWanSendComplete(
+ Link->Adapter->MiniportAdapterHandle,
+ Packet,
+ NDIS_STATUS_SUCCESS
+ );
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ /*
+ // If this is the last transmit queued on this link, and it has
+ // been closed, close the link and notify the protocol that the
+ // link has been closed.
+ */
+ if (--Link->NumTxQueued == 0)
+ {
+ if (Link->CallClosing)
+ {
+ HtTapiCallStateHandler(Adapter, Link, LINECALLSTATE_IDLE, 0);
+ }
+ else if (Link->Closing)
+ {
+ HtTapiLineDevStateHandler(Adapter, Link, LINEDEVSTATE_CLOSE);
+ LinkRelease(Link);
+ }
+
+ /*
+ // Indicate close complete to the wrapper.
+ // Again, let go of the spin lock!
+ */
+ NdisReleaseSpinLock(&Adapter->Lock);
+ NdisMSetInformationComplete(
+ Adapter->MiniportAdapterHandle,
+ NDIS_STATUS_SUCCESS
+ );
+ NdisAcquireSpinLock(&Adapter->Lock);
+ }
+
+ DBG_TRACE(Adapter);
+
+ /*
+ // We're all done with the controller now.
+ */
+ Adapter->TransmitInProgress = FALSE;
+ }
+
+ /*
+ // Call HtDsuTransmitFrame() to start any other pending transmits.
+ */
+ HtDsuTransmitFrame(Adapter);
+
+ DBG_LEAVE(Adapter);
+}
+
diff --git a/private/ntos/ndis/htdsu/sources b/private/ntos/ndis/htdsu/sources
new file mode 100644
index 000000000..d25544860
--- /dev/null
+++ b/private/ntos/ndis/htdsu/sources
@@ -0,0 +1,53 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=htdsu41
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib $(BASEDIR)\public\sdk\lib\*\libc.lib
+
+INCLUDES=..\..\inc
+
+C_DEFINES=/DNDIS_MINIPORT_DRIVER
+
+SOURCES= htdsu.c \
+ card.c \
+ interrup.c \
+ link.c \
+ request.c \
+ receive.c \
+ send.c \
+ tapi.c \
+ debug.c \
+ htdsu.rc
+
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+RELATIVE_DEPTH=..\..
+
+#
+# Sources file for DDK
+#
+
diff --git a/private/ntos/ndis/htdsu/tapi.c b/private/ntos/ndis/htdsu/tapi.c
new file mode 100644
index 000000000..f1622edda
--- /dev/null
+++ b/private/ntos/ndis/htdsu/tapi.c
@@ -0,0 +1,5001 @@
+/***************************************************************************\
+|* Copyright (c) 1994 Microsoft Corporation *|
+|* Developed for Microsoft by TriplePoint, Inc. Beaverton, Oregon *|
+|* *|
+|* This file is part of the HT Communications DSU41 WAN Miniport Driver. *|
+\***************************************************************************/
+#include "version.h"
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Module Name:
+
+ tapi.c
+
+Abstract:
+
+ This module contains all the Miniport TAPI OID processing routines. It
+ is called by the MiniportSetInformation and MiniportQueryInformation
+ routines to handle the TAPI OIDs.
+
+ This driver conforms to the NDIS 3.0 Miniport interface and provides
+ extensions to support Telephonic Services.
+
+Author:
+
+ Larry Hattery - TriplePoint, Inc. (larryh@tpi.com) Jun-94
+
+Environment:
+
+ Windows NT 3.5 kernel mode Miniport driver or equivalent.
+
+Revision History:
+
+---------------------------------------------------------------------------*/
+
+#define __FILEID__ 8 // Unique file ID for error logging
+
+#include "htdsu.h"
+
+# define TAPI_DEVICECLASS_NAME "tapi/line"
+# define TAPI_DEVICECLASS_ID 1
+# define NDIS_DEVICECLASS_NAME "ndis"
+# define NDIS_DEVICECLASS_ID 2
+
+/*
+// The following is a list of all the possible TAPI OIDs.
+*/
+const NDIS_OID TapiSupportedArray[] =
+{
+/*
+// REQUIRED TAPI SPECIFIC OIDS
+*/
+ OID_TAPI_ANSWER,
+ OID_TAPI_CLOSE,
+ OID_TAPI_CLOSE_CALL,
+ OID_TAPI_CONDITIONAL_MEDIA_DETECTION,
+ OID_TAPI_DROP,
+ OID_TAPI_GET_ADDRESS_CAPS,
+ OID_TAPI_GET_ADDRESS_ID,
+ OID_TAPI_GET_ADDRESS_STATUS,
+ OID_TAPI_GET_CALL_ADDRESS_ID,
+ OID_TAPI_GET_CALL_INFO,
+ OID_TAPI_GET_CALL_STATUS,
+ OID_TAPI_GET_DEV_CAPS,
+ OID_TAPI_GET_DEV_CONFIG,
+ OID_TAPI_GET_EXTENSION_ID,
+ OID_TAPI_GET_ID,
+ OID_TAPI_GET_LINE_DEV_STATUS,
+ OID_TAPI_MAKE_CALL,
+ OID_TAPI_OPEN,
+ OID_TAPI_PROVIDER_INITIALIZE,
+ OID_TAPI_PROVIDER_SHUTDOWN,
+ OID_TAPI_SET_APP_SPECIFIC,
+ OID_TAPI_SET_CALL_PARAMS,
+ OID_TAPI_SET_DEFAULT_MEDIA_DETECTION,
+ OID_TAPI_SET_DEV_CONFIG,
+ OID_TAPI_SET_MEDIA_MODE,
+ OID_TAPI_SET_STATUS_MESSAGES,
+/*
+// OPTIONAL TAPI SPECIFIC OIDS
+*/
+ OID_TAPI_ACCEPT,
+ OID_TAPI_CONFIG_DIALOG,
+ OID_TAPI_DEV_SPECIFIC,
+ OID_TAPI_DIAL,
+ OID_TAPI_NEGOTIATE_EXT_VERSION,
+ OID_TAPI_SECURE_CALL,
+ OID_TAPI_SELECT_EXT_VERSION,
+ OID_TAPI_SEND_USER_USER_INFO,
+};
+
+#if DBG
+
+/*
+// Make sure the following list is in the same order as the list above!
+*/
+char *TapiSupportedNames[] =
+{
+/*
+// REQUIRED TAPI SPECIFIC OIDS
+*/
+ "OID_TAPI_ANSWER",
+ "OID_TAPI_CLOSE",
+ "OID_TAPI_CLOSE_CALL",
+ "OID_TAPI_CONDITIONAL_MEDIA_DETECTION",
+ "OID_TAPI_DROP",
+ "OID_TAPI_GET_ADDRESS_CAPS",
+ "OID_TAPI_GET_ADDRESS_ID",
+ "OID_TAPI_GET_ADDRESS_STATUS",
+ "OID_TAPI_GET_CALL_ADDRESS_ID",
+ "OID_TAPI_GET_CALL_INFO",
+ "OID_TAPI_GET_CALL_STATUS",
+ "OID_TAPI_GET_DEV_CAPS",
+ "OID_TAPI_GET_DEV_CONFIG",
+ "OID_TAPI_GET_EXTENSION_ID",
+ "OID_TAPI_GET_ID",
+ "OID_TAPI_GET_LINE_DEV_STATUS",
+ "OID_TAPI_MAKE_CALL",
+ "OID_TAPI_OPEN",
+ "OID_TAPI_PROVIDER_INITIALIZE",
+ "OID_TAPI_PROVIDER_SHUTDOWN",
+ "OID_TAPI_SET_APP_SPECIFIC",
+ "OID_TAPI_SET_CALL_PARAMS",
+ "OID_TAPI_SET_DEFAULT_MEDIA_DETECTION",
+ "OID_TAPI_SET_DEV_CONFIG",
+ "OID_TAPI_SET_MEDIA_MODE",
+ "OID_TAPI_SET_STATUS_MESSAGES",
+/*
+// OPTIONAL TAPI SPECIFIC OIDS
+*/
+ "OID_TAPI_ACCEPT",
+ "OID_TAPI_CONFIG_DIALOG",
+ "OID_TAPI_DEV_SPECIFIC",
+ "OID_TAPI_DIAL",
+ "OID_TAPI_NEGOTIATE_EXT_VERSION",
+ "OID_TAPI_SECURE_CALL",
+ "OID_TAPI_SELECT_EXT_VERSION",
+ "OID_TAPI_SEND_USER_USER_INFO",
+
+ "OID_TAPI_UNKNOWN"
+};
+
+#define NUM_OID_ENTRIES (sizeof(TapiSupportedArray) / sizeof(TapiSupportedArray[0]))
+
+/*
+// This debug routine will lookup the printable name for the selected OID.
+*/
+char *
+HtTapiGetOidString(NDIS_OID Oid)
+{
+ UINT i;
+
+ for (i = 0; i < NUM_OID_ENTRIES-1; i++)
+ {
+ if (TapiSupportedArray[i] == Oid)
+ {
+ break;
+ }
+ }
+ return(TapiSupportedNames[i]);
+}
+
+#endif // DBG
+
+
+NDIS_STATUS
+HtTapiQueryInformation(
+ IN PHTDSU_ADAPTER Adapter,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ The HtTapiQueryInformation request allows for inspection of the TAPI
+ portion of the driver's capabilities and current line status.
+
+ If the Miniport does not complete the call immediately (by returning
+ NDIS_STATUS_PENDING), it must call NdisMQueryInformationComplete to
+ complete the call. The Miniport controls the buffers pointed to by
+ InformationBuffer, BytesWritten, and BytesNeeded until the request
+ completes.
+
+ No other requests will be submitted to the Miniport driver until
+ this request has been completed.
+
+ Interrupts are in any state during this call.
+
+Parameters:
+
+ MiniportAdapterContext _ The adapter handle passed to NdisMSetAttributes
+ during MiniportInitialize.
+
+ Oid _ The OID. (See section 2.2.1 of the Extensions to NDIS 3.0 Miniports
+ to support Telephonic Services specification for a complete
+ description of the OIDs.)
+
+ InformationBuffer _ The buffer that will receive the information.
+
+ InformationBufferLength _ The length in bytes of InformationBuffer.
+
+ BytesWritten _ Returns the number of bytes written into
+ InformationBuffer.
+
+ BytesNeeded _ This parameter returns the number of additional bytes
+ needed to satisfy the OID.
+
+Return Values:
+
+ NDIS_STATUS_INVALID_DATA
+ NDIS_STATUS_INVALID_LENGTH
+ NDIS_STATUS_INVALID_OID
+ NDIS_STATUS_NOT_ACCEPTED
+ NDIS_STATUS_NOT_SUPPORTED
+ NDIS_STATUS_PENDING
+ NDIS_STATUS_RESOURCES
+ NDIS_STATUS_SUCCESS
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiQueryInformation")
+
+ /*
+ // Assume the worst, and initialize to handle failure.
+ */
+ NDIS_STATUS Status = NDIS_STATUS_INVALID_LENGTH;
+ ULONG NumBytesNeeded = 0;
+ ULONG NumBytesWritten = 0;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter,DBG_REQUEST_ON,
+ ("(OID=%s=%08x)\n\t\tInfoLength=%d InfoBuffer=%Xh\n",
+ HtTapiGetOidString(Oid),Oid,
+ InformationBufferLength,
+ InformationBuffer
+ ));
+
+ /*
+ // Determine which OID is being requested and do the right thing.
+ // The switch code will just call the approriate service function
+ // to do the real work, so there's not much to worry about here.
+ */
+ switch (Oid)
+ {
+ case OID_TAPI_CONFIG_DIALOG: // OPTIONAL
+ if(InformationBufferLength < sizeof(NDIS_TAPI_CONFIG_DIALOG))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_CONFIG_DIALOG);
+ break;
+ }
+ NumBytesWritten = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiConfigDialog(Adapter,
+ (PNDIS_TAPI_CONFIG_DIALOG) InformationBuffer);
+ break;
+
+ case OID_TAPI_DEV_SPECIFIC: // OPTIONAL
+ if(InformationBufferLength < sizeof(NDIS_TAPI_DEV_SPECIFIC))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_DEV_SPECIFIC);
+ break;
+ }
+ NumBytesWritten = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiDevSpecific(Adapter,
+ (PNDIS_TAPI_DEV_SPECIFIC) InformationBuffer);
+ break;
+
+ case OID_TAPI_GET_ADDRESS_CAPS:
+ if(InformationBufferLength < sizeof(NDIS_TAPI_GET_ADDRESS_CAPS))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_GET_ADDRESS_CAPS);
+ break;
+ }
+ NumBytesWritten = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiGetAddressCaps(Adapter,
+ (PNDIS_TAPI_GET_ADDRESS_CAPS) InformationBuffer);
+ break;
+
+ case OID_TAPI_GET_ADDRESS_ID:
+ if(InformationBufferLength < sizeof(NDIS_TAPI_GET_ADDRESS_ID))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_GET_ADDRESS_ID);
+ break;
+ }
+ NumBytesWritten = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiGetAddressID(Adapter,
+ (PNDIS_TAPI_GET_ADDRESS_ID) InformationBuffer);
+ break;
+
+ case OID_TAPI_GET_ADDRESS_STATUS:
+ if(InformationBufferLength < sizeof(NDIS_TAPI_GET_ADDRESS_STATUS))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_GET_ADDRESS_STATUS);
+ break;
+ }
+ NumBytesWritten = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiGetAddressStatus(Adapter,
+ (PNDIS_TAPI_GET_ADDRESS_STATUS) InformationBuffer);
+ break;
+
+ case OID_TAPI_GET_CALL_ADDRESS_ID:
+ if(InformationBufferLength < sizeof(NDIS_TAPI_GET_CALL_ADDRESS_ID))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_GET_CALL_ADDRESS_ID);
+ break;
+ }
+ NumBytesWritten = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiGetCallAddressID(Adapter,
+ (PNDIS_TAPI_GET_CALL_ADDRESS_ID) InformationBuffer);
+ break;
+
+ case OID_TAPI_GET_CALL_INFO:
+ if(InformationBufferLength < sizeof(NDIS_TAPI_GET_CALL_INFO))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_GET_CALL_INFO);
+ break;
+ }
+ NumBytesWritten = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiGetCallInfo(Adapter,
+ (PNDIS_TAPI_GET_CALL_INFO) InformationBuffer);
+ break;
+
+ case OID_TAPI_GET_CALL_STATUS:
+ if(InformationBufferLength < sizeof(NDIS_TAPI_GET_CALL_STATUS))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_GET_CALL_STATUS);
+ break;
+ }
+ NumBytesWritten = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiGetCallStatus(Adapter,
+ (PNDIS_TAPI_GET_CALL_STATUS) InformationBuffer);
+ break;
+
+ case OID_TAPI_GET_DEV_CAPS:
+ if(InformationBufferLength < sizeof(NDIS_TAPI_GET_DEV_CAPS))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_GET_DEV_CAPS);
+ break;
+ }
+ NumBytesWritten = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiGetDevCaps(Adapter,
+ (PNDIS_TAPI_GET_DEV_CAPS) InformationBuffer);
+ break;
+
+ case OID_TAPI_GET_DEV_CONFIG:
+ if(InformationBufferLength < sizeof(NDIS_TAPI_GET_DEV_CONFIG))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_GET_DEV_CONFIG);
+ break;
+ }
+ NumBytesWritten = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiGetDevConfig(Adapter,
+ (PNDIS_TAPI_GET_DEV_CONFIG) InformationBuffer);
+ break;
+
+ case OID_TAPI_GET_EXTENSION_ID:
+ if(InformationBufferLength < sizeof(NDIS_TAPI_GET_EXTENSION_ID))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_GET_EXTENSION_ID);
+ break;
+ }
+ NumBytesWritten = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiGetExtensionID(Adapter,
+ (PNDIS_TAPI_GET_EXTENSION_ID) InformationBuffer);
+ break;
+
+ case OID_TAPI_GET_ID:
+ if(InformationBufferLength < sizeof(NDIS_TAPI_GET_ID))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_GET_ID);
+ break;
+ }
+ NumBytesWritten = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiGetID(Adapter,
+ (PNDIS_TAPI_GET_ID) InformationBuffer);
+ break;
+
+ case OID_TAPI_GET_LINE_DEV_STATUS:
+ if(InformationBufferLength < sizeof(NDIS_TAPI_GET_LINE_DEV_STATUS))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_GET_LINE_DEV_STATUS);
+ break;
+ }
+ NumBytesWritten = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiGetLineDevStatus(Adapter,
+ (PNDIS_TAPI_GET_LINE_DEV_STATUS) InformationBuffer);
+ break;
+
+ case OID_TAPI_MAKE_CALL:
+ if(InformationBufferLength < sizeof(NDIS_TAPI_MAKE_CALL))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_MAKE_CALL);
+ break;
+ }
+ NumBytesWritten = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiMakeCall(Adapter,
+ (PNDIS_TAPI_MAKE_CALL) InformationBuffer);
+ break;
+
+ case OID_TAPI_NEGOTIATE_EXT_VERSION:// OPTIONAL
+ if(InformationBufferLength < sizeof(NDIS_TAPI_NEGOTIATE_EXT_VERSION))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_NEGOTIATE_EXT_VERSION);
+ break;
+ }
+ NumBytesWritten = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiNegotiateExtVersion(Adapter,
+ (PNDIS_TAPI_NEGOTIATE_EXT_VERSION) InformationBuffer);
+ break;
+
+ case OID_TAPI_OPEN:
+ if(InformationBufferLength < sizeof(NDIS_TAPI_OPEN))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_OPEN);
+ break;
+ }
+ NumBytesWritten = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiOpen(Adapter,
+ (PNDIS_TAPI_OPEN) InformationBuffer);
+ break;
+
+ case OID_TAPI_PROVIDER_INITIALIZE:
+ if(InformationBufferLength < sizeof(OID_TAPI_PROVIDER_INITIALIZE))
+ {
+ NumBytesNeeded = sizeof(OID_TAPI_PROVIDER_INITIALIZE);
+ break;
+ }
+ NumBytesWritten = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiProviderInitialize(Adapter,
+ (PNDIS_TAPI_PROVIDER_INITIALIZE) InformationBuffer);
+ break;
+
+ default:
+ /*
+ // Unknown OID
+ */
+ Status = NDIS_STATUS_INVALID_OID;
+ break;
+ }
+
+ /*
+ // Fill in the size fields before we leave as indicated by the
+ // status we are returning.
+ */
+ if (Status == NDIS_STATUS_INVALID_LENGTH)
+ {
+ *BytesNeeded = NumBytesNeeded;
+ *BytesWritten = 0;
+ }
+ else
+ {
+ *BytesNeeded = *BytesWritten = NumBytesWritten;
+ }
+ DBG_FILTER(Adapter,DBG_REQUEST_ON,
+ ("RETURN: Status=%Xh Needed=%d Written=%d\n",
+ Status, *BytesNeeded, *BytesWritten));
+
+ DBG_LEAVE(Adapter);
+
+ return (Status);
+}
+
+
+NDIS_STATUS
+HtTapiSetInformation(
+ IN PHTDSU_ADAPTER Adapter,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ The HtTapiQueryInformation request allows for control of the TAPI
+ portion of the driver's settings and current line status.
+
+ If the Miniport does not complete the call immediately (by returning
+ NDIS_STATUS_PENDING), it must call NdisMSetInformationComplete to
+ complete the call. The Miniport controls the buffers pointed to by
+ InformationBuffer, BytesRead, and BytesNeeded until the request completes.
+
+ Interrupts are in any state during the call, and no other requests will
+ be submitted to the Miniport until this request is completed.
+
+Parameters:
+
+ MiniportAdapterContext _ The adapter handle passed to NdisMSetAttributes
+ during MiniportInitialize.
+
+ Oid _ The OID. (See section 2.2.2 of the Extensions to NDIS 3.0 Miniports
+ to support Telephonic Services specification for a complete
+ description of the OIDs.)
+
+ InformationBuffer _ The buffer that will receive the information.
+
+ InformationBufferLength _ The length in bytes of InformationBuffer.
+
+ BytesRead_ Returns the number of bytes read from InformationBuffer.
+
+ BytesNeeded _ This parameter returns the number of additional bytes
+ expected to satisfy the OID.
+
+Return Values:
+
+ NDIS_STATUS_INVALID_DATA
+ NDIS_STATUS_INVALID_LENGTH
+ NDIS_STATUS_INVALID_OID
+ NDIS_STATUS_NOT_ACCEPTED
+ NDIS_STATUS_NOT_SUPPORTED
+ NDIS_STATUS_PENDING
+ NDIS_STATUS_RESOURCES
+ NDIS_STATUS_SUCCESS
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiSetInformation")
+
+ /*
+ // Assume the worst, and initialize to handle failure.
+ */
+ NDIS_STATUS Status = NDIS_STATUS_INVALID_LENGTH;
+ ULONG NumBytesNeeded = 0;
+ ULONG NumBytesRead = 0;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter,DBG_REQUEST_ON,
+ ("(OID=%s=%08x)\n\t\tInfoLength=%d InfoBuffer=%Xh\n",
+ HtTapiGetOidString(Oid),Oid,
+ InformationBufferLength,
+ InformationBuffer
+ ));
+
+ /*
+ // Determine which OID is being requested and do the right thing.
+ // The switch code will just call the approriate service function
+ // to do the real work, so there's not much to worry about here either.
+ */
+ switch (Oid)
+ {
+ case OID_TAPI_ACCEPT: // OPTIONAL
+ if (InformationBufferLength < sizeof(NDIS_TAPI_ACCEPT))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_ACCEPT);
+ break;
+ }
+ NumBytesRead = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiAccept(Adapter,
+ (PNDIS_TAPI_ACCEPT) InformationBuffer);
+ break;
+
+ case OID_TAPI_ANSWER:
+ if (InformationBufferLength < sizeof(NDIS_TAPI_ANSWER))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_ANSWER);
+ break;
+ }
+ NumBytesRead = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiAnswer(Adapter,
+ (PNDIS_TAPI_ANSWER) InformationBuffer);
+ break;
+
+ case OID_TAPI_CLOSE:
+ if (InformationBufferLength < sizeof(NDIS_TAPI_CLOSE))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_CLOSE);
+ break;
+ }
+ NumBytesRead = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiClose(Adapter,
+ (PNDIS_TAPI_CLOSE) InformationBuffer);
+ break;
+
+ case OID_TAPI_CLOSE_CALL:
+ if (InformationBufferLength < sizeof(NDIS_TAPI_CLOSE_CALL))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_CLOSE_CALL);
+ break;
+ }
+ NumBytesRead = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiCloseCall(Adapter,
+ (PNDIS_TAPI_CLOSE_CALL) InformationBuffer);
+ break;
+
+ case OID_TAPI_CONDITIONAL_MEDIA_DETECTION:
+ if (InformationBufferLength < sizeof(NDIS_TAPI_CONDITIONAL_MEDIA_DETECTION))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_CONDITIONAL_MEDIA_DETECTION);
+ break;
+ }
+ NumBytesRead = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiConditionalMediaDetection(Adapter,
+ (PNDIS_TAPI_CONDITIONAL_MEDIA_DETECTION) InformationBuffer);
+ break;
+
+ case OID_TAPI_DIAL: // OPTIONAL
+ if (InformationBufferLength < sizeof(NDIS_TAPI_DIAL))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_DIAL);
+ break;
+ }
+ NumBytesRead = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiDial(Adapter,
+ (PNDIS_TAPI_DIAL) InformationBuffer);
+ break;
+
+ case OID_TAPI_DROP:
+ if (InformationBufferLength < sizeof(NDIS_TAPI_DROP))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_DROP);
+ break;
+ }
+ NumBytesRead = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiDrop(Adapter,
+ (PNDIS_TAPI_DROP) InformationBuffer);
+ break;
+
+ case OID_TAPI_PROVIDER_SHUTDOWN:
+ if (InformationBufferLength < sizeof(NDIS_TAPI_PROVIDER_SHUTDOWN))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_PROVIDER_SHUTDOWN);
+ break;
+ }
+ NumBytesRead = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiProviderShutdown(Adapter,
+ (PNDIS_TAPI_PROVIDER_SHUTDOWN) InformationBuffer);
+ break;
+
+ case OID_TAPI_SECURE_CALL: // OPTIONAL
+ if (InformationBufferLength < sizeof(NDIS_TAPI_SECURE_CALL))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_SECURE_CALL);
+ break;
+ }
+ NumBytesRead = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiSecureCall(Adapter,
+ (PNDIS_TAPI_SECURE_CALL) InformationBuffer);
+ break;
+
+ case OID_TAPI_SELECT_EXT_VERSION: // OPTIONAL
+ if (InformationBufferLength < sizeof(NDIS_TAPI_SELECT_EXT_VERSION))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_SELECT_EXT_VERSION);
+ break;
+ }
+ NumBytesRead = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiSelectExtVersion(Adapter,
+ (PNDIS_TAPI_SELECT_EXT_VERSION) InformationBuffer);
+ break;
+
+ case OID_TAPI_SEND_USER_USER_INFO: // OPTIONAL
+ if (InformationBufferLength < sizeof(NDIS_TAPI_SEND_USER_USER_INFO))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_SEND_USER_USER_INFO);
+ break;
+ }
+ NumBytesRead = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiSendUserUserInfo(Adapter,
+ (PNDIS_TAPI_SEND_USER_USER_INFO) InformationBuffer);
+ break;
+
+ case OID_TAPI_SET_APP_SPECIFIC:
+ if (InformationBufferLength < sizeof(NDIS_TAPI_SET_APP_SPECIFIC))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_SET_APP_SPECIFIC);
+ break;
+ }
+ NumBytesRead = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiSetAppSpecific(Adapter,
+ (PNDIS_TAPI_SET_APP_SPECIFIC) InformationBuffer);
+ break;
+
+ case OID_TAPI_SET_CALL_PARAMS:
+ if (InformationBufferLength < sizeof(NDIS_TAPI_SET_CALL_PARAMS))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_SET_CALL_PARAMS);
+ break;
+ }
+ NumBytesRead = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiSetCallParams(Adapter,
+ (PNDIS_TAPI_SET_CALL_PARAMS) InformationBuffer);
+ break;
+
+ case OID_TAPI_SET_DEFAULT_MEDIA_DETECTION:
+ if (InformationBufferLength < sizeof(NDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION);
+ break;
+ }
+ NumBytesRead = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiSetDefaultMediaDetection(Adapter,
+ (PNDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION) InformationBuffer);
+ break;
+
+ case OID_TAPI_SET_DEV_CONFIG:
+ if (InformationBufferLength < sizeof(NDIS_TAPI_SET_DEV_CONFIG))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_SET_DEV_CONFIG);
+ break;
+ }
+ NumBytesRead = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiSetDevConfig(Adapter,
+ (PNDIS_TAPI_SET_DEV_CONFIG) InformationBuffer);
+ break;
+
+ case OID_TAPI_SET_MEDIA_MODE:
+ if (InformationBufferLength < sizeof(NDIS_TAPI_SET_MEDIA_MODE))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_SET_MEDIA_MODE);
+ break;
+ }
+ NumBytesRead = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiSetMediaMode(Adapter,
+ (PNDIS_TAPI_SET_MEDIA_MODE) InformationBuffer);
+ break;
+
+ case OID_TAPI_SET_STATUS_MESSAGES:
+ if (InformationBufferLength < sizeof(NDIS_TAPI_SET_STATUS_MESSAGES))
+ {
+ NumBytesNeeded = sizeof(NDIS_TAPI_SET_STATUS_MESSAGES);
+ break;
+ }
+ NumBytesRead = NumBytesNeeded = InformationBufferLength;
+ Status = HtTapiSetStatusMessages(Adapter,
+ (PNDIS_TAPI_SET_STATUS_MESSAGES) InformationBuffer);
+ break;
+
+ default:
+ Status = NDIS_STATUS_INVALID_OID;
+ break;
+ }
+
+ /*
+ // Fill in the size fields before we leave as indicated by the
+ // status we are returning.
+ */
+ if (Status == NDIS_STATUS_INVALID_LENGTH)
+ {
+ *BytesNeeded = NumBytesNeeded;
+ *BytesRead = 0;
+ }
+ else
+ {
+ *BytesNeeded = *BytesRead = NumBytesRead;
+ }
+ DBG_FILTER(Adapter,DBG_REQUEST_ON,
+ ("RETURN: Status=%Xh Needed=%d Read=%d\n",
+ Status, *BytesNeeded, *BytesRead));
+
+ DBG_LEAVE(Adapter);
+
+ return (Status);
+}
+
+
+NDIS_STATUS
+HtTapiGetID(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_GET_ID Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request returns a device ID for the specified device class
+ associated with the selected line, address or call.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_GET_ID
+ {
+ IN ULONG ulRequestID;
+ IN HDRV_LINE hdLine;
+ IN ULONG ulAddressID;
+ IN HDRV_CALL hdCall;
+ IN ULONG ulSelect;
+ IN ULONG ulDeviceClassSize;
+ IN ULONG ulDeviceClassOffset;
+ OUT VAR_STRING DeviceID;
+
+ } NDIS_TAPI_GET_ID, *PNDIS_TAPI_GET_ID;
+
+ typedef struct _VAR_STRING
+ {
+ ULONG ulTotalSize;
+ ULONG ulNeededSize;
+ ULONG ulUsedSize;
+
+ ULONG ulStringFormat;
+ ULONG ulStringSize;
+ ULONG ulStringOffset;
+
+ } VAR_STRING, *PVAR_STRING;
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_FAILURE
+ NDIS_STATUS_TAPI_INVALDEVICECLASS
+ NDIS_STATUS_TAPI_INVALLINEHANDLE
+ NDIS_STATUS_TAPI_INVALADDRESSID
+ NDIS_STATUS_TAPI_INVALCALLHANDLE
+ NDIS_STATUS_TAPI_OPERATIONUNAVAIL
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiGetID")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ /*
+ // Remember which device class is being requested.
+ */
+ UINT DeviceClass;
+
+ /*
+ // A pointer to the requested device ID, and its size in bytes.
+ */
+ PUCHAR IDPtr;
+ UINT IDLength;
+ ULONG DeviceID;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("hdLine=%Xh\n"
+ "ulAddressID=%d\n"
+ "hdCall=%Xh\n"
+ "ulSelect=%Xh\n"
+ "ulDeviceClassSize=%d\n"
+ "ulDeviceClassOffset=%Xh\n",
+ Request->hdLine,
+ Request->ulAddressID,
+ Request->hdCall,
+ Request->ulSelect,
+ Request->ulDeviceClassSize,
+ Request->ulDeviceClassOffset
+ ));
+ /*
+ // Make sure this is a tapi/line or ndis request.
+ */
+ if (_strnicmp((PCHAR) Request + Request->ulDeviceClassOffset,
+ NDIS_DEVICECLASS_NAME, Request->ulDeviceClassSize) == 0)
+ {
+ DeviceClass = NDIS_DEVICECLASS_ID;
+ }
+ else if (_strnicmp((PCHAR) Request + Request->ulDeviceClassOffset,
+ TAPI_DEVICECLASS_NAME, Request->ulDeviceClassSize) == 0)
+ {
+ DeviceClass = TAPI_DEVICECLASS_ID;
+ }
+ else
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALDEVICECLASS\n"));
+ return (NDIS_STATUS_TAPI_INVALDEVICECLASS);
+ }
+
+ /*
+ // Find the link structure associated with the request/deviceclass.
+ */
+ if (Request->ulSelect == LINECALLSELECT_LINE)
+ {
+ Link = GET_LINK_FROM_HDLINE(Adapter, Request->hdLine);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALLINEHANDLE\n"));
+ return (NDIS_STATUS_TAPI_INVALLINEHANDLE);
+ }
+ if (DeviceClass == TAPI_DEVICECLASS_ID)
+ {
+ /*
+ // TAPI just wants the ulDeviceID for this line.
+ */
+ DeviceID = (ULONG) GET_DEVICEID_FROM_LINK(Adapter, Link);
+ IDLength = sizeof(DeviceID);
+ IDPtr = (PUCHAR) &DeviceID;
+ }
+ else // UNSUPPORTED DEVICE CLASS
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALDEVICECLASS\n"));
+ return (NDIS_STATUS_TAPI_INVALDEVICECLASS);
+ }
+ }
+ else if (Request->ulSelect == LINECALLSELECT_ADDRESS)
+ {
+ Link = GET_LINK_FROM_HDLINE(Adapter, Request->hdLine);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALLINEHANDLE\n"));
+ return (NDIS_STATUS_TAPI_INVALLINEHANDLE);
+ }
+
+ if (Request->ulAddressID >= HTDSU_TAPI_NUM_ADDRESSES)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALADDRESSID\n"));
+ return (NDIS_STATUS_TAPI_INVALADDRESSID);
+ }
+
+ /*
+ // Currently, there is no defined return value for this case...
+ // This is just a place holder for future extensions.
+ */
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALDEVICECLASS\n"));
+ return (NDIS_STATUS_TAPI_INVALDEVICECLASS);
+ }
+ else if (Request->ulSelect == LINECALLSELECT_CALL)
+ {
+ Link = GET_LINK_FROM_HDCALL(Adapter, Request->hdCall);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALCALLHANDLE\n"));
+ return (NDIS_STATUS_TAPI_INVALCALLHANDLE);
+ }
+ if (DeviceClass == NDIS_DEVICECLASS_ID)
+ {
+ /*
+ // This must match ConnectionWrapperID used in LINE_UP event!
+ */
+ DeviceID = (ULONG) Link->htCall;
+ IDLength = sizeof(DeviceID);
+ IDPtr = (PUCHAR) &DeviceID;
+ }
+ else // UNSUPPORTED DEVICE CLASS
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALDEVICECLASS\n"));
+ return (NDIS_STATUS_TAPI_INVALDEVICECLASS);
+ }
+ }
+ else
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_FAILURE\n"));
+ return (NDIS_STATUS_FAILURE);
+ }
+
+ DBG_NOTICE(Adapter, ("GETID-%d=%Xh\n",Request->ulSelect,DeviceID));
+
+ /*
+ // Now we need to adjust the variable field to place the device ID.
+ */
+ Request->DeviceID.ulNeededSize = sizeof(VAR_STRING) + IDLength;
+ if (Request->DeviceID.ulTotalSize >= Request->DeviceID.ulNeededSize)
+ {
+ Request->DeviceID.ulUsedSize = Request->DeviceID.ulNeededSize;
+ Request->DeviceID.ulStringFormat = STRINGFORMAT_BINARY;
+ Request->DeviceID.ulStringSize = IDLength;
+ Request->DeviceID.ulStringOffset = sizeof(VAR_STRING);
+
+ /*
+ // Now we return the requested ID value.
+ */
+ NdisMoveMemory(
+ (PCHAR) &Request->DeviceID + sizeof(VAR_STRING),
+ IDPtr,
+ IDLength
+ );
+ }
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+HtTapiGetDevConfig(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_GET_DEV_CONFIG Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request returns a data structure object, the contents of which are
+ specific to the line (miniport) and device class, giving the current
+ configuration of a device associated one-to-one with the line device.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_GET_DEV_CONFIG
+ {
+ IN ULONG ulRequestID;
+ IN ULONG ulDeviceID;
+ IN ULONG ulDeviceClassSize;
+ IN ULONG ulDeviceClassOffset;
+ OUT VAR_STRING DeviceConfig;
+
+ } NDIS_TAPI_GET_DEV_CONFIG, *PNDIS_TAPI_GET_DEV_CONFIG;
+
+ typedef struct _VAR_STRING
+ {
+ ULONG ulTotalSize;
+ ULONG ulNeededSize;
+ ULONG ulUsedSize;
+
+ ULONG ulStringFormat;
+ ULONG ulStringSize;
+ ULONG ulStringOffset;
+
+ } VAR_STRING, *PVAR_STRING;
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_TAPI_INVALDEVICECLASS
+ NDIS_STATUS_TAPI_NODRIVER
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiGetDevConfig")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ /*
+ // Remember which device class is being requested.
+ */
+ UINT DeviceClass;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("ulDeviceID=%d\n"
+ "ulDeviceClassSize=%d\n"
+ "ulDeviceClassOffset=%Xh\n",
+ Request->ulDeviceID,
+ Request->ulDeviceClassSize,
+ Request->ulDeviceClassOffset
+ ));
+ /*
+ // Make sure this is a tapi/line or ndis request.
+ */
+ if (_strnicmp((PCHAR) Request + Request->ulDeviceClassOffset,
+ NDIS_DEVICECLASS_NAME, Request->ulDeviceClassSize) == 0)
+ {
+ DeviceClass = NDIS_DEVICECLASS_ID;
+ }
+ else if (_strnicmp((PCHAR) Request + Request->ulDeviceClassOffset,
+ TAPI_DEVICECLASS_NAME, Request->ulDeviceClassSize) == 0)
+ {
+ DeviceClass = TAPI_DEVICECLASS_ID;
+ }
+ else
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALDEVICECLASS\n"));
+ return (NDIS_STATUS_TAPI_INVALDEVICECLASS);
+ }
+
+ /*
+ // This request must be associated with a line device.
+ */
+ Link = GET_LINK_FROM_DEVICEID(Adapter, Request->ulDeviceID);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_NODRIVER\n"));
+ return (NDIS_STATUS_TAPI_NODRIVER);
+ }
+
+ /*
+ // Now we need to adjust the variable field to place the requested device
+ // configuration.
+ */
+# define SIZEOF_DEVCONFIG sizeof(ULONG)
+ Request->DeviceConfig.ulNeededSize = sizeof(VAR_STRING) + SIZEOF_DEVCONFIG;
+ if (Request->DeviceConfig.ulTotalSize >= Request->DeviceConfig.ulNeededSize)
+ {
+ Request->DeviceConfig.ulUsedSize = Request->DeviceConfig.ulNeededSize;
+ Request->DeviceConfig.ulStringFormat = STRINGFORMAT_BINARY;
+ Request->DeviceConfig.ulStringSize = SIZEOF_DEVCONFIG;
+ Request->DeviceConfig.ulStringOffset = sizeof(VAR_STRING);
+
+ /*
+ // There are currently no return values defined for this case.
+ // This is just a place holder for future extensions.
+ */
+ *((ULONG *) ((PCHAR) &Request->DeviceConfig + sizeof(VAR_STRING))) =
+ 0xDEADBEEF;
+ }
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+HtTapiSetDevConfig(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_SET_DEV_CONFIG Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request restores the configuration of a device associated one-to-one
+ with the line device from an “” data structure previously obtained using
+ OID_TAPI_GET_DEV_CONFIG. The contents of this data structure are specific
+ to the line (miniport) and device class.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_SET_DEV_CONFIG
+ {
+ IN ULONG ulRequestID;
+ IN ULONG ulDeviceID;
+ IN ULONG ulDeviceClassSize;
+ IN ULONG ulDeviceClassOffset;
+ IN ULONG ulDeviceConfigSize;
+ IN UCHAR DeviceConfig[1];
+
+ } NDIS_TAPI_SET_DEV_CONFIG, *PNDIS_TAPI_SET_DEV_CONFIG;
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_TAPI_INVALDEVICECLASS
+ NDIS_STATUS_TAPI_INVALPARAM
+ NDIS_STATUS_TAPI_NODRIVER
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiSetDevConfig")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ /*
+ // Remember which device class is being requested.
+ */
+ UINT DeviceClass;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("ulDeviceID=%d\n"
+ "ulDeviceClassSize=%d\n"
+ "ulDeviceClassOffset=%d\n"
+ "ulDeviceConfigSize=%d\n",
+ Request->ulDeviceID,
+ Request->ulDeviceClassSize,
+ Request->ulDeviceClassOffset,
+ Request->ulDeviceConfigSize
+ ));
+ /*
+ // Make sure this is a tapi/line or ndis request.
+ */
+ if (_strnicmp((PCHAR) Request + Request->ulDeviceClassOffset,
+ NDIS_DEVICECLASS_NAME, Request->ulDeviceClassSize) == 0)
+ {
+ DeviceClass = NDIS_DEVICECLASS_ID;
+ }
+ else if (_strnicmp((PCHAR) Request + Request->ulDeviceClassOffset,
+ TAPI_DEVICECLASS_NAME, Request->ulDeviceClassSize) == 0)
+ {
+ DeviceClass = TAPI_DEVICECLASS_ID;
+ }
+ else
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALDEVICECLASS\n"));
+ return (NDIS_STATUS_TAPI_INVALDEVICECLASS);
+ }
+
+ /*
+ // This request must be associated with a line device.
+ */
+ Link = GET_LINK_FROM_DEVICEID(Adapter, Request->ulDeviceID);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_NODRIVER\n"));
+ return (NDIS_STATUS_TAPI_NODRIVER);
+ }
+
+ /*
+ // Make sure this configuration is the proper size.
+ */
+ if (Request->ulDeviceConfigSize != SIZEOF_DEVCONFIG)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALPARAM\n"));
+ return (NDIS_STATUS_TAPI_INVALPARAM);
+ }
+
+ /*
+ // Retore the configuration information returned by HtTapiGetDevConfig.
+ //
+ // There are currently no configuration values defined this case.
+ // This is just a place holder for future extensions.
+ */
+ if (*((ULONG *) ((PCHAR) Request->DeviceConfig)) != 0xDEADBEEF)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALPARAM\n"));
+ return (NDIS_STATUS_TAPI_INVALPARAM);
+ }
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+HtTapiConfigDialog(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_CONFIG_DIALOG Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request retrieves the name of a user-mode dynamic link library that
+ can be loaded and called to configure the specified device. The
+ configuration DLL shall export the following function by name:
+
+ LONG WINAPI
+ ConfigDialog(
+ IN HWND hwndOwner,
+ IN ULONG ulDeviceID,
+ IN LPCSTR lpszDeviceClass
+ );
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_CONFIG_DIALOG
+ {
+ IN ULONG ulRequestID;
+ IN ULONG ulDeviceID;
+ IN ULONG ulDeviceClassSize;
+ IN ULONG ulDeviceClassOffset;
+ IN ULONG ulLibraryNameTotalSize;
+ OUT ULONG ulLibraryNameNeededSize;
+ OUT CHAR szLibraryName[1];
+
+ } NDIS_TAPI_CONFIG_DIALOG, *PNDIS_TAPI_CONFIG_DIALOG;
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_TAPI_INVALDEVICECLASS
+ NDIS_STATUS_STRUCTURETOOSMALL
+ NDIS_STATUS_TAPI_NODRIVER
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiConfigDialog")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ /*
+ // Remember which device class is being requested.
+ */
+ UINT DeviceClass;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("ulDeviceID=%d\n"
+ "ulDeviceClassSize=%d\n"
+ "ulDeviceClassOffset=%Xh\n"
+ "ulLibraryNameTotalSize=%d\n",
+ Request->ulDeviceID,
+ Request->ulDeviceClassSize,
+ Request->ulDeviceClassOffset,
+ Request->ulLibraryNameTotalSize
+ ));
+ /*
+ // Make sure this is a tapi/line or ndis request.
+ */
+ if (_strnicmp((PCHAR) Request + Request->ulDeviceClassOffset,
+ NDIS_DEVICECLASS_NAME, Request->ulDeviceClassSize) == 0)
+ {
+ DeviceClass = NDIS_DEVICECLASS_ID;
+ }
+ else if (_strnicmp((PCHAR) Request + Request->ulDeviceClassOffset,
+ TAPI_DEVICECLASS_NAME, Request->ulDeviceClassSize) == 0)
+ {
+ DeviceClass = TAPI_DEVICECLASS_ID;
+ }
+ else
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALDEVICECLASS\n"));
+ return (NDIS_STATUS_TAPI_INVALDEVICECLASS);
+ }
+
+ /*
+ // This request must be associated with a line device.
+ */
+ Link = GET_LINK_FROM_DEVICEID(Adapter, Request->ulDeviceID);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_NODRIVER\n"));
+ return (NDIS_STATUS_TAPI_NODRIVER);
+ }
+
+ /*
+ // Copy the name of our configuration DLL which we read from the registry
+ // during startup, and which was placed there during installation.
+ //
+ // This driver does not provide a configuration DLL.
+ // This is just a place holder for future extensions.
+ */
+ Request->ulLibraryNameNeededSize = strlen(Adapter->ConfigDLLName) + 1;
+ if (Request->ulLibraryNameTotalSize < Request->ulLibraryNameNeededSize)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_STRUCTURETOOSMALL\n"));
+ return (NDIS_STATUS_TAPI_STRUCTURETOOSMALL);
+ }
+ NdisMoveMemory(
+ Request->szLibraryName,
+ Adapter->ConfigDLLName,
+ Request->ulLibraryNameNeededSize
+ );
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+HtTapiDevSpecific(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_DEV_SPECIFIC Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request is used as a general extension mechanism to enable miniports
+ to provide access to features not described in other operations. The meaning
+ of the extensions are device-specific, and taking advantage of these
+ extensions requires the application to be fully aware of them.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_DEV_SPECIFIC
+ {
+ IN ULONG ulRequestID;
+ IN HDRV_LINE hdLine;
+ IN ULONG ulAddressID;
+ IN HDRV_CALL hdCall;
+ IN OUT ULONG ulParamsSize;
+ IN OUT UCHAR Params[1];
+
+ } NDIS_TAPI_DEV_SPECIFIC, *PNDIS_TAPI_DEV_SPECIFIC;
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_FAILURE
+ NDIS_STATUS_TAPI_OPERATIONUNAVAIL
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiDevSpecific")
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("hdLine=%Xh\n"
+ "ulAddressID=%d\n"
+ "hdCall=%Xh\n"
+ "ulParamsSize=%d\n"
+ "Params=%Xh\n",
+ Request->hdLine,
+ Request->ulAddressID,
+ Request->hdCall,
+ Request->ulParamsSize,
+ Request->Params
+ ));
+ /*
+ // You can do what ever you want here, so long as the application
+ // agrees with you.
+ */
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_TAPI_OPERATIONUNAVAIL);
+}
+
+
+NDIS_STATUS
+HtTapiGetAddressID(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_GET_ADDRESS_ID Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request returns the address ID associated with address in a different
+ format on the specified line.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_GET_ADDRESS_ID
+ {
+ IN ULONG ulRequestID;
+ IN HDRV_LINE hdLine;
+ OUT ULONG ulAddressID;
+ IN ULONG ulAddressMode;
+ IN ULONG ulAddressSize;
+ IN CHAR szAddress[1];
+
+ } NDIS_TAPI_GET_ADDRESS_ID, *PNDIS_TAPI_GET_ADDRESS_ID;
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_FAILURE
+ NDIS_STATUS_TAPI_INVALLINEHANDLE
+ NDIS_STATUS_TAPI_RESOURCEUNAVAIL
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiGetAddressID")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("hdLine=%Xh\n"
+ "ulAddressMode=%Xh\n"
+ "ulAddressSize=%d\n"
+ "szAddress=%Xh\n",
+ Request->hdLine,
+ Request->ulAddressMode,
+ Request->ulAddressSize,
+ Request->szAddress
+ ));
+ /*
+ // This request must be associated with a line device.
+ */
+ Link = GET_LINK_FROM_HDLINE(Adapter, Request->hdLine);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALLINEHANDLE\n"));
+ return (NDIS_STATUS_TAPI_INVALLINEHANDLE);
+ }
+
+ /*
+ // The spec sez it has to be this mode! Otherwise, we already know
+ // that the address ID is (0..N-1).
+ */
+ if (Request->ulAddressMode != LINEADDRESSMODE_DIALABLEADDR)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_FAILURE\n"));
+ return (NDIS_STATUS_FAILURE);
+ }
+
+ /*
+ // Make sure we have enough room set aside for this address string.
+ */
+ if (Request->ulAddressSize > sizeof(Link->LineAddress)-1)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_RESOURCEUNAVAIL\n"));
+ return (NDIS_STATUS_TAPI_RESOURCEUNAVAIL);
+ }
+
+ /*
+ // You may need to search each link to find the associated Address.
+ // However, this adapter has only one address per link so it's an
+ // easy task.
+ */
+ Request->ulAddressID = HTDSU_TAPI_ADDRESSID;
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+HtTapiGetAddressCaps(
+ PHTDSU_ADAPTER Adapter,
+ PNDIS_TAPI_GET_ADDRESS_CAPS Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request queries the specified address on the specified line device
+ to determine its telephony capabilities.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_GET_ADDRESS_CAPS
+ {
+ IN ULONG ulRequestID;
+ IN ULONG ulDeviceID;
+ IN ULONG ulAddressID;
+ IN ULONG ulExtVersion;
+ OUT LINE_ADDRESS_CAPS LineAddressCaps;
+
+ } NDIS_TAPI_GET_ADDRESS_CAPS, *PNDIS_TAPI_GET_ADDRESS_CAPS;
+
+ typedef struct _LINE_ADDRESS_CAPS
+ {
+ ULONG ulTotalSize;
+ ULONG ulNeededSize;
+ ULONG ulUsedSize;
+
+ ULONG ulLineDeviceID;
+
+ ULONG ulAddressSize;
+ ULONG ulAddressOffset;
+
+ ULONG ulDevSpecificSize;
+ ULONG ulDevSpecificOffset;
+
+ ULONG ulAddressSharing;
+ ULONG ulAddressStates;
+ ULONG ulCallInfoStates;
+ ULONG ulCallerIDFlags;
+ ULONG ulCalledIDFlags;
+ ULONG ulConnectedIDFlags;
+ ULONG ulRedirectionIDFlags;
+ ULONG ulRedirectingIDFlags;
+ ULONG ulCallStates;
+ ULONG ulDialToneModes;
+ ULONG ulBusyModes;
+ ULONG ulSpecialInfo;
+ ULONG ulDisconnectModes;
+
+ ULONG ulMaxNumActiveCalls;
+ ULONG ulMaxNumOnHoldCalls;
+ ULONG ulMaxNumOnHoldPendingCalls;
+ ULONG ulMaxNumConference;
+ ULONG ulMaxNumTransConf;
+
+ ULONG ulAddrCapFlags;
+ ULONG ulCallFeatures;
+ ULONG ulRemoveFromConfCaps;
+ ULONG ulRemoveFromConfState;
+ ULONG ulTransferModes;
+ ULONG ulParkModes;
+
+ ULONG ulForwardModes;
+ ULONG ulMaxForwardEntries;
+ ULONG ulMaxSpecificEntries;
+ ULONG ulMinFwdNumRings;
+ ULONG ulMaxFwdNumRings;
+
+ ULONG ulMaxCallCompletions;
+ ULONG ulCallCompletionConds;
+ ULONG ulCallCompletionModes;
+ ULONG ulNumCompletionMessages;
+ ULONG ulCompletionMsgTextEntrySize;
+ ULONG ulCompletionMsgTextSize;
+ ULONG ulCompletionMsgTextOffset;
+
+ } LINE_ADDRESS_CAPS, *PLINE_ADDRESS_CAPS;
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_TAPI_INVALADDRESSID
+ NDIS_STATUS_TAPI_INCOMPATIBLEEXTVERSION
+ NDIS_STATUS_TAPI_NODRIVER
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiGetAddressCaps")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ /*
+ // Length of the address string assigned to this line device.
+ */
+ UINT AddressLength;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("ulDeviceID=%d\n"
+ "ulAddressID=%d\n"
+ "ulExtVersion=%Xh\n",
+ Request->ulDeviceID,
+ Request->ulAddressID,
+ Request->ulExtVersion
+ ));
+ /*
+ // Make sure the address is within range - we only support one per line.
+ */
+ if (Request->ulAddressID >= HTDSU_TAPI_NUM_ADDRESSES)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALADDRESSID\n"));
+ return (NDIS_STATUS_TAPI_INVALADDRESSID);
+ }
+
+ /*
+ // Make sure we are speaking the same language.
+ */
+#ifdef NDISTAPI_BUG_FIXED
+ if (Request->ulExtVersion != 0 &&
+ Request->ulExtVersion != HTDSU_TAPI_EXT_VERSION)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INCOMPATIBLEEXTVERSION\n"));
+ return (NDIS_STATUS_TAPI_INCOMPATIBLEEXTVERSION);
+ }
+#endif
+
+ /*
+ // This request must be associated with a line device.
+ */
+ Link = GET_LINK_FROM_DEVICEID(Adapter, Request->ulDeviceID);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_NODRIVER\n"));
+ return (NDIS_STATUS_TAPI_NODRIVER);
+ }
+
+#ifndef NDISTAPI_BUG_FIXED
+ Request->LineAddressCaps.ulNeededSize =
+ Request->LineAddressCaps.ulUsedSize = sizeof(Request->LineAddressCaps);
+#endif
+
+ Request->LineAddressCaps.ulLineDeviceID = Request->ulDeviceID;
+
+ /*
+ // RASTAPI requires the "I L A" be placed in the Address field at the end
+ // of this structure. Where:
+ // I = The device intance assigned to this adapter in the registry
+ // \LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkCards\I
+ // L = The device line number associated with this line (1..NumLines)
+ // A = The address (channel) to be used on this line (0..NumAddresses-1)
+ */
+ AddressLength = strlen(Link->LineAddress) + 1;
+ Request->LineAddressCaps.ulNeededSize += AddressLength;
+ if (Request->LineAddressCaps.ulNeededSize <= Request->LineAddressCaps.ulTotalSize)
+ {
+ Request->LineAddressCaps.ulAddressSize = AddressLength;
+ Request->LineAddressCaps.ulAddressOffset = sizeof(Request->LineAddressCaps);
+ NdisMoveMemory((PUCHAR) &Request->LineAddressCaps +
+ Request->LineAddressCaps.ulAddressOffset,
+ Link->LineAddress,
+ AddressLength
+ );
+ Request->LineAddressCaps.ulUsedSize += AddressLength;
+ }
+
+ /*
+ // Return the various address capabilites for the adapter.
+ */
+ Request->LineAddressCaps.ulAddressSharing = LINEADDRESSSHARING_PRIVATE;
+ Request->LineAddressCaps.ulAddressStates = Link->AddressStatesCaps;
+ Request->LineAddressCaps.ulCallStates = Link->CallStatesCaps;
+ Request->LineAddressCaps.ulDialToneModes = LINEDIALTONEMODE_NORMAL;
+ Request->LineAddressCaps.ulSpecialInfo = LINESPECIALINFO_UNAVAIL;
+ Request->LineAddressCaps.ulDisconnectModes =
+ LINEDISCONNECTMODE_NORMAL |
+ LINEDISCONNECTMODE_UNKNOWN |
+ LINEDISCONNECTMODE_BUSY |
+ LINEDISCONNECTMODE_NOANSWER;
+ /*
+ // This device does not support conference calls, transfers, or holds.
+ */
+ Request->LineAddressCaps.ulMaxNumActiveCalls = 1;
+ Request->LineAddressCaps.ulMaxNumTransConf = 1;
+ Request->LineAddressCaps.ulAddrCapFlags =
+ Link->LineMode == HTDSU_LINEMODE_LEASED ? 0 : LINEADDRCAPFLAGS_DIALED;
+ Request->LineAddressCaps.ulCallFeatures =
+ LINECALLFEATURE_ACCEPT |
+ LINECALLFEATURE_ANSWER |
+ LINECALLFEATURE_COMPLETECALL |
+ LINECALLFEATURE_DIAL |
+ LINECALLFEATURE_DROP;
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+HtTapiGetAddressStatus(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_GET_ADDRESS_STATUS Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request queries the specified address for its current status.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_GET_ADDRESS_STATUS
+ {
+ IN ULONG ulRequestID;
+ IN HDRV_LINE hdLine;
+ IN ULONG ulAddressID;
+ OUT LINE_ADDRESS_STATUS LineAddressStatus;
+
+ } NDIS_TAPI_GET_ADDRESS_STATUS, *PNDIS_TAPI_GET_ADDRESS_STATUS;
+
+ typedef struct _LINE_ADDRESS_STATUS
+ {
+ ULONG ulTotalSize;
+ ULONG ulNeededSize;
+ ULONG ulUsedSize;
+
+ ULONG ulNumInUse;
+ ULONG ulNumActiveCalls;
+ ULONG ulNumOnHoldCalls;
+ ULONG ulNumOnHoldPendCalls;
+ ULONG ulAddressFeatures;
+
+ ULONG ulNumRingsNoAnswer;
+ ULONG ulForwardNumEntries;
+ ULONG ulForwardSize;
+ ULONG ulForwardOffset;
+
+ ULONG ulTerminalModesSize;
+ ULONG ulTerminalModesOffset;
+
+ ULONG ulDevSpecificSize;
+ ULONG ulDevSpecificOffset;
+
+ } LINE_ADDRESS_STATUS, *PLINE_ADDRESS_STATUS;
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_FAILURE
+ NDIS_STATUS_TAPI_INVALLINEHANDLE
+ NDIS_STATUS_TAPI_INVALADDRESSID
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiGetAddressStatus")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("hdLine=%Xh\n"
+ "ulAddressID=%d\n",
+ Request->hdLine,
+ Request->ulAddressID
+ ));
+ /*
+ // This request must be associated with a line device.
+ */
+ Link = GET_LINK_FROM_HDLINE(Adapter, Request->hdLine);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALLINEHANDLE\n"));
+ return (NDIS_STATUS_TAPI_INVALLINEHANDLE);
+ }
+
+ /*
+ // Make sure the address is within range - we only support one per line.
+ */
+ if (Request->ulAddressID >= HTDSU_TAPI_NUM_ADDRESSES)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALADDRESSID\n"));
+ return (NDIS_STATUS_TAPI_INVALADDRESSID);
+ }
+
+#ifndef NDISTAPI_BUG_FIXED
+ Request->LineAddressStatus.ulNeededSize =
+ Request->LineAddressStatus.ulUsedSize = sizeof(Request->LineAddressStatus);
+#endif
+
+ /*
+ // Return the current status information for the line.
+ */
+ Request->LineAddressStatus.ulNumInUse =
+ Link->CallState == LINECALLSTATE_IDLE ? 0 : 1;
+ Request->LineAddressStatus.ulNumActiveCalls =
+ Link->CallState == LINECALLSTATE_IDLE ? 0 : 1;
+ Request->LineAddressStatus.ulAddressFeatures =
+ Link->CallState == LINECALLSTATE_IDLE ?
+ LINEADDRFEATURE_MAKECALL : 0;
+ Request->LineAddressStatus.ulNumRingsNoAnswer = 999;
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+HtTapiGetCallAddressID(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_GET_CALL_ADDRESS_ID Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request retrieves the address ID for the indicated call.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_GET_CALL_ADDRESS_ID
+ {
+ IN ULONG ulRequestID;
+ IN HDRV_CALL hdCall;
+ OUT ULONG ulAddressID;
+
+ } NDIS_TAPI_GET_CALL_ADDRESS_ID, *PNDIS_TAPI_GET_CALL_ADDRESS_ID;
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_FAILURE
+ NDIS_STATUS_TAPI_INVALCALLHANDLE
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiGetCallAddressID")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("hdCall=%Xh\n",
+ Request->hdCall
+ ));
+ /*
+ // This request must be associated with a call.
+ */
+ Link = GET_LINK_FROM_HDCALL(Adapter, Request->hdCall);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALCALLHANDLE\n"));
+ return (NDIS_STATUS_TAPI_INVALCALLHANDLE);
+ }
+
+ /*
+ // Return the address ID associated with this call.
+ */
+ Request->ulAddressID = HTDSU_TAPI_ADDRESSID;
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+HtTapiGetCallInfo(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_GET_CALL_INFO Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request returns detailed information about the specified call.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_GET_CALL_INFO
+ {
+ IN ULONG ulRequestID;
+ IN HDRV_CALL hdCall;
+ OUT LINE_CALL_INFO LineCallInfo;
+
+ } NDIS_TAPI_GET_CALL_INFO, *PNDIS_TAPI_GET_CALL_INFO;
+
+ typedef struct _LINE_CALL_INFO
+ {
+ ULONG ulTotalSize;
+ ULONG ulNeededSize;
+ ULONG ulUsedSize;
+
+ ULONG hLine;
+ ULONG ulLineDeviceID;
+ ULONG ulAddressID;
+
+ ULONG ulBearerMode;
+ ULONG ulRate;
+ ULONG ulMediaMode;
+
+ ULONG ulAppSpecific;
+ ULONG ulCallID;
+ ULONG ulRelatedCallID;
+ ULONG ulCallParamFlags;
+ ULONG ulCallStates;
+
+ ULONG ulMonitorDigitModes;
+ ULONG ulMonitorMediaModes;
+ LINE_DIAL_PARAMS DialParams;
+
+ ULONG ulOrigin;
+ ULONG ulReason;
+ ULONG ulCompletionID;
+ ULONG ulNumOwners;
+ ULONG ulNumMonitors;
+
+ ULONG ulCountryCode;
+ ULONG ulTrunk;
+
+ ULONG ulCallerIDFlags;
+ ULONG ulCallerIDSize;
+ ULONG ulCallerIDOffset;
+ ULONG ulCallerIDNameSize;
+ ULONG ulCallerIDNameOffset;
+
+ ULONG ulCalledIDFlags;
+ ULONG ulCalledIDSize;
+ ULONG ulCalledIDOffset;
+ ULONG ulCalledIDNameSize;
+ ULONG ulCalledIDNameOffset;
+
+ ULONG ulConnectedIDFlags;
+ ULONG ulConnectedIDSize;
+ ULONG ulConnectedIDOffset;
+ ULONG ulConnectedIDNameSize;
+ ULONG ulConnectedIDNameOffset;
+
+ ULONG ulRedirectionIDFlags;
+ ULONG ulRedirectionIDSize;
+ ULONG ulRedirectionIDOffset;
+ ULONG ulRedirectionIDNameSize;
+ ULONG ulRedirectionIDNameOffset;
+
+ ULONG ulRedirectingIDFlags;
+ ULONG ulRedirectingIDSize;
+ ULONG ulRedirectingIDOffset;
+ ULONG ulRedirectingIDNameSize;
+ ULONG ulRedirectingIDNameOffset;
+
+ ULONG ulAppNameSize;
+ ULONG ulAppNameOffset;
+
+ ULONG ulDisplayableAddressSize;
+ ULONG ulDisplayableAddressOffset;
+
+ ULONG ulCalledPartySize;
+ ULONG ulCalledPartyOffset;
+
+ ULONG ulCommentSize;
+ ULONG ulCommentOffset;
+
+ ULONG ulDisplaySize;
+ ULONG ulDisplayOffset;
+
+ ULONG ulUserUserInfoSize;
+ ULONG ulUserUserInfoOffset;
+
+ ULONG ulHighLevelCompSize;
+ ULONG ulHighLevelCompOffset;
+
+ ULONG ulLowLevelCompSize;
+ ULONG ulLowLevelCompOffset;
+
+ ULONG ulChargingInfoSize;
+ ULONG ulChargingInfoOffset;
+
+ ULONG ulTerminalModesSize;
+ ULONG ulTerminalModesOffset;
+
+ ULONG ulDevSpecificSize;
+ ULONG ulDevSpecificOffset;
+
+ } LINE_CALL_INFO, *PLINE_CALL_INFO;
+
+ typedef struct _LINE_DIAL_PARAMS
+ {
+ ULONG ulDialPause;
+ ULONG ulDialSpeed;
+ ULONG ulDigitDuration;
+ ULONG ulWaitForDialtone;
+
+ } LINE_DIAL_PARAMS, *PLINE_DIAL_PARAMS;
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_FAILURE
+ NDIS_STATUS_TAPI_INVALCALLHANDLE
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiGetCallInfo")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("hdCall=%Xh\n",
+ Request->hdCall
+ ));
+ /*
+ // This request must be associated with a call.
+ */
+ Link = GET_LINK_FROM_HDCALL(Adapter, Request->hdCall);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALCALLHANDLE\n"));
+ return (NDIS_STATUS_TAPI_INVALCALLHANDLE);
+ }
+
+#ifndef NDISTAPI_BUG_FIXED
+ Request->LineCallInfo.ulNeededSize =
+ Request->LineCallInfo.ulUsedSize = sizeof(Request->LineCallInfo);
+#endif
+
+ /*
+ // We don't expect user user info.
+ */
+ ASSERT(Request->LineCallInfo.ulUserUserInfoSize == 0);
+
+ /*
+ // The link has all the call information we need to return.
+ */
+ Request->LineCallInfo.hLine = (ULONG) Link;
+ Request->LineCallInfo.ulLineDeviceID = GET_DEVICEID_FROM_LINK(Adapter, Link);
+ Request->LineCallInfo.ulAddressID = HTDSU_TAPI_ADDRESSID;
+
+ Request->LineCallInfo.ulBearerMode = LINEBEARERMODE_DATA;
+ Request->LineCallInfo.ulRate = Link->LinkSpeed;
+ Request->LineCallInfo.ulMediaMode = Link->MediaModesMask;
+
+ Request->LineCallInfo.ulCallParamFlags = LINECALLPARAMFLAGS_IDLE;
+ Request->LineCallInfo.ulCallStates = Link->CallStatesMask;
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+HtTapiGetCallStatus(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_GET_CALL_STATUS Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request returns detailed information about the specified call.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_GET_CALL_STATUS
+ {
+ IN ULONG ulRequestID;
+ IN HDRV_CALL hdCall;
+ OUT LINE_CALL_STATUS LineCallStatus;
+
+ } NDIS_TAPI_GET_CALL_STATUS, *PNDIS_TAPI_GET_CALL_STATUS;
+
+ typedef struct _LINE_CALL_STATUS
+ {
+ ULONG ulTotalSize;
+ ULONG ulNeededSize;
+ ULONG ulUsedSize;
+
+ ULONG ulCallState;
+ ULONG ulCallStateMode;
+ ULONG ulCallPrivilege;
+ ULONG ulCallFeatures;
+
+ ULONG ulDevSpecificSize;
+ ULONG ulDevSpecificOffset;
+
+ } LINE_CALL_STATUS, *PLINE_CALL_STATUS;
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_FAILURE
+ NDIS_STATUS_TAPI_INVALCALLHANDLE
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiGetCallStatus")
+
+ /*
+ // Holds the status result returned this function.
+ */
+ NDIS_STATUS Status;
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("hdCall=%Xh\n",
+ Request->hdCall
+ ));
+ /*
+ // This request must be associated with a call.
+ */
+ Link = GET_LINK_FROM_HDCALL(Adapter, Request->hdCall);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALCALLHANDLE\n"));
+ return (NDIS_STATUS_TAPI_INVALCALLHANDLE);
+ }
+
+#ifndef NDISTAPI_BUG_FIXED
+ Request->LineCallStatus.ulNeededSize =
+ Request->LineCallStatus.ulUsedSize = sizeof(Request->LineCallStatus);
+#endif
+
+ /*
+ // The link has all the call information.
+ */
+ Request->LineCallStatus.ulCallPrivilege = LINECALLPRIVILEGE_OWNER;
+ Request->LineCallStatus.ulCallState = Link->CallState;
+
+ /*
+ // Tag CallStateMode with appropriate value for the current CallState.
+ */
+ if (Link->CallState == LINECALLSTATE_DIALTONE)
+ {
+ Request->LineCallStatus.ulCallStateMode = LINEDIALTONEMODE_NORMAL;
+ }
+ else if (Link->CallState == LINECALLSTATE_BUSY)
+ {
+ Request->LineCallStatus.ulCallStateMode = LINEBUSYMODE_STATION;
+ }
+ else if (Link->CallState == LINECALLSTATE_DISCONNECTED)
+ {
+ /*
+ // We need to query/save the line status to find out what happened.
+ */
+ if (CardStatusNoAnswer(Adapter, Link->CardLine))
+ {
+ Request->LineCallStatus.ulCallStateMode = LINEDISCONNECTMODE_NOANSWER;
+ }
+ else if (CardStatusNoDialTone(Adapter, Link->CardLine))
+ {
+ Request->LineCallStatus.ulCallStateMode = LINEDISCONNECTMODE_BUSY;
+ }
+ else
+ {
+ Request->LineCallStatus.ulCallStateMode = LINEDISCONNECTMODE_UNKNOWN;
+ }
+ }
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+HtTapiGetDevCaps(
+ PHTDSU_ADAPTER Adapter,
+ PNDIS_TAPI_GET_DEV_CAPS Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request queries a specified line device to determine its telephony
+ capabilities. The returned information is valid for all addresses on the
+ line device.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_GET_DEV_CAPS
+ {
+ IN ULONG ulRequestID;
+ IN ULONG ulDeviceID;
+ IN ULONG ulExtVersion;
+ OUT LINE_DEV_CAPS LineDevCaps;
+
+ } NDIS_TAPI_GET_DEV_CAPS, *PNDIS_TAPI_GET_DEV_CAPS;
+
+ typedef struct _LINE_DEV_CAPS
+ {
+ ULONG ulTotalSize;
+ ULONG ulNeededSize;
+ ULONG ulUsedSize;
+
+ ULONG ulProviderInfoSize;
+ ULONG ulProviderInfoOffset;
+
+ ULONG ulSwitchInfoSize;
+ ULONG ulSwitchInfoOffset;
+
+ ULONG ulPermanentLineID;
+ ULONG ulLineNameSize;
+ ULONG ulLineNameOffset;
+ ULONG ulStringFormat;
+
+ ULONG ulAddressModes;
+ ULONG ulNumAddresses;
+ ULONG ulBearerModes;
+ ULONG ulMaxRate;
+ ULONG ulMediaModes;
+
+ ULONG ulGenerateToneModes;
+ ULONG ulGenerateToneMaxNumFreq;
+ ULONG ulGenerateDigitModes;
+ ULONG ulMonitorToneMaxNumFreq;
+ ULONG ulMonitorToneMaxNumEntries;
+ ULONG ulMonitorDigitModes;
+ ULONG ulGatherDigitsMinTimeout;
+ ULONG ulGatherDigitsMaxTimeout;
+
+ ULONG ulMedCtlDigitMaxListSize;
+ ULONG ulMedCtlMediaMaxListSize;
+ ULONG ulMedCtlToneMaxListSize;
+ ULONG ulMedCtlCallStateMaxListSize;
+
+ ULONG ulDevCapFlags;
+ ULONG ulMaxNumActiveCalls;
+ ULONG ulAnswerMode;
+ ULONG ulRingModes;
+ ULONG ulLineStates;
+
+ ULONG ulUUIAcceptSize;
+ ULONG ulUUIAnswerSize;
+ ULONG ulUUIMakeCallSize;
+ ULONG ulUUIDropSize;
+ ULONG ulUUISendUserUserInfoSize;
+ ULONG ulUUICallInfoSize;
+
+ LINE_DIAL_PARAMS MinDialParams;
+ LINE_DIAL_PARAMS MaxDialParams;
+ LINE_DIAL_PARAMS DefaultDialParams;
+
+ ULONG ulNumTerminals;
+ ULONG ulTerminalCapsSize;
+ ULONG ulTerminalCapsOffset;
+ ULONG ulTerminalTextEntrySize;
+ ULONG ulTerminalTextSize;
+ ULONG ulTerminalTextOffset;
+
+ ULONG ulDevSpecificSize;
+ ULONG ulDevSpecificOffset;
+
+ } LINE_DEV_CAPS, *PLINE_DEV_CAPS;
+
+ typedef struct _LINE_DIAL_PARAMS
+ {
+ ULONG ulDialPause;
+ ULONG ulDialSpeed;
+ ULONG ulDigitDuration;
+ ULONG ulWaitForDialtone;
+
+ } LINE_DIAL_PARAMS, *PLINE_DIAL_PARAMS;
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_TAPI_NODRIVER
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiGetDevCaps")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("ulDeviceID=%d\n"
+ "ulExtVersion=%Xh\n"
+ "LineDevCaps=%Xh\n",
+ Request->ulDeviceID,
+ Request->ulExtVersion,
+ &Request->LineDevCaps
+ ));
+ /*
+ // This request must be associated with a line device.
+ */
+ Link = GET_LINK_FROM_DEVICEID(Adapter, Request->ulDeviceID);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_NODRIVER\n"));
+ return (NDIS_STATUS_TAPI_NODRIVER);
+ }
+
+#ifndef NDISTAPI_BUG_FIXED
+ Request->LineDevCaps.ulNeededSize =
+ Request->LineDevCaps.ulUsedSize = sizeof(Request->LineDevCaps);
+#endif
+
+ /*
+ // The driver numbers lines sequentially from 1, so this will always
+ // be the same number.
+ */
+ Request->LineDevCaps.ulPermanentLineID = Link->CardLine;
+
+ /*
+ // RASTAPI requires the "MediaType\0DeviceName" be placed in the
+ // ProviderInfo field at the end of this structure.
+ */
+ Request->LineDevCaps.ulNeededSize += Adapter->ProviderInfoSize;
+ if (Request->LineDevCaps.ulNeededSize <= Request->LineDevCaps.ulTotalSize)
+ {
+ Request->LineDevCaps.ulProviderInfoSize = Adapter->ProviderInfoSize;
+ Request->LineDevCaps.ulProviderInfoOffset = sizeof(Request->LineDevCaps);
+ NdisMoveMemory((PUCHAR) &Request->LineDevCaps +
+ Request->LineDevCaps.ulProviderInfoOffset,
+ Adapter->ProviderInfo,
+ Adapter->ProviderInfoSize
+ );
+ Request->LineDevCaps.ulUsedSize += Adapter->ProviderInfoSize;
+ }
+ Request->LineDevCaps.ulStringFormat = STRINGFORMAT_ASCII;
+
+ /*
+ // This device is a switched 56kb line for digital data only.
+ */
+ Request->LineDevCaps.ulAddressModes = LINEADDRESSMODE_ADDRESSID |
+ LINEADDRESSMODE_DIALABLEADDR;
+ Request->LineDevCaps.ulNumAddresses = 1;
+ Request->LineDevCaps.ulBearerModes = LINEBEARERMODE_DATA;
+ Request->LineDevCaps.ulMaxRate = Link->LinkSpeed;
+ Request->LineDevCaps.ulMediaModes = Link->MediaModesCaps;
+
+ /*
+ // Each line on the DSU only supports a single call.
+ */
+ Request->LineDevCaps.ulDevCapFlags = LINEDEVCAPFLAGS_CLOSEDROP;
+ Request->LineDevCaps.ulMaxNumActiveCalls = 1;
+ Request->LineDevCaps.ulAnswerMode = LINEANSWERMODE_DROP;
+ Request->LineDevCaps.ulRingModes = 1;
+ Request->LineDevCaps.ulLineStates = Link->DevStatesCaps;
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+HtTapiGetExtensionID(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_GET_EXTENSION_ID Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request returns the extension ID that the miniport supports for the
+ indicated line device.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_GET_EXTENSION_ID
+ {
+ IN ULONG ulRequestID;
+ IN ULONG ulDeviceID;
+ OUT LINE_EXTENSION_ID LineExtensionID;
+
+ } NDIS_TAPI_GET_EXTENSION_ID, *PNDIS_TAPI_GET_EXTENSION_ID;
+
+ typedef struct _LINE_EXTENSION_ID
+ {
+ ULONG ulExtensionID0;
+ ULONG ulExtensionID1;
+ ULONG ulExtensionID2;
+ ULONG ulExtensionID3;
+
+ } LINE_EXTENSION_ID, *PLINE_EXTENSION_ID;
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_TAPI_NODRIVER
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiGetExtensionID")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("ulDeviceID=%d\n",
+ Request->ulDeviceID
+ ));
+ /*
+ // This request must be associated with a line device.
+ */
+ Link = GET_LINK_FROM_DEVICEID(Adapter, Request->ulDeviceID);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_NODRIVER\n"));
+ return (NDIS_STATUS_TAPI_NODRIVER);
+ }
+
+ /*
+ // This driver does not support any extensions, so we return zeros.
+ */
+ Request->LineExtensionID.ulExtensionID0 = 0;
+ Request->LineExtensionID.ulExtensionID1 = 0;
+ Request->LineExtensionID.ulExtensionID2 = 0;
+ Request->LineExtensionID.ulExtensionID3 = 0;
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+HtTapiGetLineDevStatus(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_GET_LINE_DEV_STATUS Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request queries the specified open line device for its current status.
+ The information returned is global to all addresses on the line.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_GET_LINE_DEV_STATUS
+ {
+ IN ULONG ulRequestID;
+ IN HDRV_LINE hdLine;
+ OUT LINE_DEV_STATUS LineDevStatus;
+
+ } NDIS_TAPI_GET_LINE_DEV_STATUS, *PNDIS_TAPI_GET_LINE_DEV_STATUS;
+
+ typedef struct _LINE_DEV_STATUS
+ {
+ ULONG ulTotalSize;
+ ULONG ulNeededSize;
+ ULONG ulUsedSize;
+
+ ULONG ulNumOpens;
+ ULONG ulOpenMediaModes;
+ ULONG ulNumActiveCalls;
+ ULONG ulNumOnHoldCalls;
+ ULONG ulNumOnHoldPendCalls;
+ ULONG ulLineFeatures;
+ ULONG ulNumCallCompletions;
+ ULONG ulRingMode;
+ ULONG ulSignalLevel;
+ ULONG ulBatteryLevel;
+ ULONG ulRoamMode;
+
+ ULONG ulDevStatusFlags;
+
+ ULONG ulTerminalModesSize;
+ ULONG ulTerminalModesOffset;
+
+ ULONG ulDevSpecificSize;
+ ULONG ulDevSpecificOffset;
+
+ } LINE_DEV_STATUS, *PLINE_DEV_STATUS;
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_TAPI_INVALLINEHANDLE
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiGetLineDevStatus")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("hdLine=%Xh\n",
+ Request->hdLine
+ ));
+ /*
+ // This request must be associated with a line device.
+ */
+ Link = GET_LINK_FROM_HDLINE(Adapter, Request->hdLine);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALLINEHANDLE\n"));
+ return (NDIS_STATUS_TAPI_INVALLINEHANDLE);
+ }
+
+#ifndef NDISTAPI_BUG_FIXED
+ Request->LineDevStatus.ulNeededSize =
+ Request->LineDevStatus.ulUsedSize = sizeof(Request->LineDevStatus);
+#endif
+
+ /*
+ // Return the current line status information.
+ */
+ Request->LineDevStatus.ulNumActiveCalls;
+ Link->CallState == LINECALLSTATE_IDLE ? 0 : 1;
+ Request->LineDevStatus.ulLineFeatures;
+ Link->CallState == LINECALLSTATE_IDLE ?
+ LINEFEATURE_MAKECALL : 0;
+ Request->LineDevStatus.ulRingMode =
+ Link->DevState == LINEDEVSTATE_RINGING ? 1: 0;
+ Request->LineDevStatus.ulDevStatusFlags =
+ Link->DevState == LINEDEVSTATE_CONNECTED ?
+ LINEDEVSTATUSFLAGS_INSERVICE | LINEDEVSTATUSFLAGS_CONNECTED : 0;
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+HtTapiMakeCall(
+ PHTDSU_ADAPTER Adapter,
+ PNDIS_TAPI_MAKE_CALL Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request places a call on the specified line to the specified
+ destination address. Optionally, call parameters can be specified if
+ anything but default call setup parameters are requested.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_MAKE_CALL
+ {
+ IN ULONG ulRequestID;
+ IN HDRV_LINE hdLine;
+ IN HTAPI_CALL htCall;
+ OUT HDRV_CALL hdCall;
+ IN ULONG ulDestAddressSize;
+ IN ULONG ulDestAddressOffset;
+ IN BOOLEAN bUseDefaultLineCallParams;
+ IN LINE_CALL_PARAMS LineCallParams;
+
+ } NDIS_TAPI_MAKE_CALL, *PNDIS_TAPI_MAKE_CALL;
+
+ typedef struct _LINE_CALL_PARAMS // Defaults:
+ {
+ ULONG ulTotalSize; // ---------
+
+ ULONG ulBearerMode; // voice
+ ULONG ulMinRate; // (3.1kHz)
+ ULONG ulMaxRate; // (3.1kHz)
+ ULONG ulMediaMode; // interactiveVoice
+
+ ULONG ulCallParamFlags; // 0
+ ULONG ulAddressMode; // addressID
+ ULONG ulAddressID; // (any available)
+
+ LINE_DIAL_PARAMS DialParams; // (0, 0, 0, 0)
+
+ ULONG ulOrigAddressSize; // 0
+ ULONG ulOrigAddressOffset;
+ ULONG ulDisplayableAddressSize;
+ ULONG ulDisplayableAddressOffset;
+
+ ULONG ulCalledPartySize; // 0
+ ULONG ulCalledPartyOffset;
+
+ ULONG ulCommentSize; // 0
+ ULONG ulCommentOffset;
+
+ ULONG ulUserUserInfoSize; // 0
+ ULONG ulUserUserInfoOffset;
+
+ ULONG ulHighLevelCompSize; // 0
+ ULONG ulHighLevelCompOffset;
+
+ ULONG ulLowLevelCompSize; // 0
+ ULONG ulLowLevelCompOffset;
+
+ ULONG ulDevSpecificSize; // 0
+ ULONG ulDevSpecificOffset;
+
+ } LINE_CALL_PARAMS, *PLINE_CALL_PARAMS;
+
+ typedef struct _LINE_DIAL_PARAMS
+ {
+ ULONG ulDialPause;
+ ULONG ulDialSpeed;
+ ULONG ulDigitDuration;
+ ULONG ulWaitForDialtone;
+
+ } LINE_DIAL_PARAMS, *PLINE_DIAL_PARAMS;
+
+Return Values:
+
+ NDIS_STATUS_TAPI_ADDRESSBLOCKED
+ NDIS_STATUS_TAPI_BEARERMODEUNAVAIL
+ NDIS_STATUS_TAPI_CALLUNAVAIL
+ NDIS_STATUS_TAPI_DIALBILLING
+ NDIS_STATUS_TAPI_DIALQUIET
+ NDIS_STATUS_TAPI_DIALDIALTONE
+ NDIS_STATUS_TAPI_DIALPROMPT
+ NDIS_STATUS_TAPI_INUSE
+ NDIS_STATUS_TAPI_INVALADDRESSMODE
+ NDIS_STATUS_TAPI_INVALBEARERMODE
+ NDIS_STATUS_TAPI_INVALMEDIAMODE
+ NDIS_STATUS_TAPI_INVALLINESTATE
+ NDIS_STATUS_TAPI_INVALRATE
+ NDIS_STATUS_TAPI_INVALLINEHANDLE
+ NDIS_STATUS_TAPI_INVALADDRESS
+ NDIS_STATUS_TAPI_INVALADDRESSID
+ NDIS_STATUS_TAPI_INVALCALLPARAMS
+ NDIS_STATUS_RESOURCES
+ NDIS_STATUS_TAPI_OPERATIONUNAVAIL
+ NDIS_STATUS_FAILURE
+ NDIS_STATUS_TAPI_RESOURCEUNAVAIL
+ NDIS_STATUS_TAPI_RATEUNAVAIL
+ NDIS_STATUS_TAPI_USERUSERINFOTOOBIG
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiMakeCall")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("hdLine=%Xh\n"
+ "htCall=%Xh\n"
+ "ulDestAddressSize=%d\n"
+ "ulDestAddressOffset=%Xh\n"
+ "bUseDefaultLineCallParams=%d\n"
+ "LineCallParams=%Xh\n",
+ Request->hdLine,
+ Request->htCall,
+ Request->ulDestAddressSize,
+ Request->ulDestAddressOffset,
+ Request->bUseDefaultLineCallParams,
+ Request->LineCallParams
+ ));
+ /*
+ // This request must be associated with a line device.
+ */
+ Link = GET_LINK_FROM_HDLINE(Adapter, Request->hdLine);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALLINEHANDLE\n"));
+ return (NDIS_STATUS_TAPI_INVALLINEHANDLE);
+ }
+
+ /*
+ // We should be idle when this call comes down, but if we're out of
+ // state for seom reason, don't let this go any further.
+ */
+ if (Link->CallState != LINECALLSTATE_IDLE)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INUSE\n"));
+ return (NDIS_STATUS_TAPI_INUSE);
+ }
+
+ /*
+ // Currently, the defaultCallParams feature is not used by RASTAPI.
+ // Normally, you would save the default params passed into
+ // OID_TAPI_SET_CALL_PARAM and apply them here.
+ */
+ ASSERT(Request->bUseDefaultLineCallParams == FALSE);
+
+ /*
+ // We don't expect user user info.
+ */
+ ASSERT(Request->LineCallParams.ulUserUserInfoSize == 0);
+
+ /*
+ // We gotta make sure the line is in the right state before attempt.
+ */
+ if (Link->LineMode != HTDSU_LINEMODE_DIALUP ||
+ CardStatusNoSignal(Adapter, Link->CardLine) ||
+ CardStatusOutOfService(Adapter, Link->CardLine) ||
+ CardStatusCarrierDetect(Adapter, Link->CardLine))
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_OPERATIONUNAVAIL\n"));
+ return (NDIS_STATUS_TAPI_OPERATIONUNAVAIL);
+ }
+
+ /*
+ // Remember the TAPI call connection handle.
+ */
+ Link->htCall = Request->htCall;
+
+ /*
+ // Since we only allow one call per line, we use the same handle.
+ */
+ Request->hdCall = (HDRV_CALL)Link;
+
+ /*
+ // Dial the number if it's available, otherwise it may come via
+ // OID_TAPI_DIAL. Be aware the the phone number format may be
+ // different for other applications. I'm assuming an ASCII digits
+ // string.
+ */
+ if (Request->ulDestAddressSize)
+ {
+ PUCHAR DialString = ((PUCHAR)Request) + Request->ulDestAddressOffset;
+
+ DBG_NOTICE(Adapter,("Dialing: '%s'\n",DialString));
+
+ HtTapiCallStateHandler(Adapter, Link,
+ LINECALLSTATE_DIALTONE, LINEDIALTONEMODE_NORMAL);
+ CardDialNumber(Adapter,
+ Link->CardLine,
+ DialString,
+ Request->ulDestAddressSize
+ );
+ /*
+ // We should see a HTDSU_NO_DIAL_TONE within 5 seconds if the
+ // call will not go through.
+ */
+ HtTapiCallStateHandler(Adapter, Link, LINECALLSTATE_DIALING, 0);
+ NdisMSetTimer(&Link->CallTimer, HTDSU_NO_DIALTONE_TIMEOUT);
+ }
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+HtTapiNegotiateExtVersion(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_NEGOTIATE_EXT_VERSION Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request returns the highest extension version number the service
+ provider is willing to operate under for this device given the range of
+ possible extension versions.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_NEGOTIATE_EXT_VERSION
+ {
+ IN ULONG ulRequestID;
+ IN ULONG ulDeviceID;
+ IN ULONG ulLowVersion;
+ IN ULONG ulHighVersion;
+ OUT ULONG ulExtVersion;
+ } NDIS_TAPI_NEGOTIATE_EXT_VERSION, *PNDIS_TAPI_NEGOTIATE_EXT_VERSION;
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_TAPI_INCOMPATIBLEEXTVERSION
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiNegotiateExtVersion")
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("ulDeviceID=%d\n"
+ "ulLowVersion=%Xh\n"
+ "ulHighVersion=%Xh\n",
+ Request->ulDeviceID,
+ Request->ulLowVersion,
+ Request->ulHighVersion
+ ));
+ /*
+ // Make sure the miniport's version number is within the allowable
+ // range requested by the caller. We ignore the ulDeviceID because
+ // the version information applies to all devices on this adapter.
+ */
+ if (HTDSU_TAPI_EXT_VERSION < Request->ulLowVersion ||
+ HTDSU_TAPI_EXT_VERSION > Request->ulHighVersion)
+ {
+ DBG_WARNING(Adapter, ("NDIS_STATUS_TAPI_INCOMPATIBLEEXTVERSION\n"));
+ return (NDIS_STATUS_TAPI_INCOMPATIBLEEXTVERSION);
+ }
+
+ /*
+ // Looks like we're compatible, so tell the caller what we expect.
+ */
+ Request->ulExtVersion = HTDSU_TAPI_EXT_VERSION;
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+HtTapiOpen(
+ PHTDSU_ADAPTER Adapter,
+ PNDIS_TAPI_OPEN Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This function opens the line device whose device ID is given, returning
+ the miniport’s handle for the device. The miniport must retain the
+ Connection Wrapper's handle for the device for use in subsequent calls to
+ the LINE_EVENT callback procedure.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request - A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_OPEN
+ {
+ IN ULONG ulRequestID;
+ IN ULONG ulDeviceID;
+ IN HTAPI_LINE htLine;
+ OUT HDRV_LINE hdLine;
+
+ } NDIS_TAPI_OPEN, *PNDIS_TAPI_OPEN;
+
+Return Values:
+
+ NDIS_STATUS_PENDING
+ NDIS_STATUS_TAPI_ALLOCATED
+ NDIS_STATUS_TAPI_NODRIVER
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiOpen")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("ulDeviceID=%d\n"
+ "htLine=%Xh\n",
+ Request->ulDeviceID,
+ Request->htLine
+ ));
+ /*
+ // This request must be associated with a line device.
+ */
+ Link = GET_LINK_FROM_DEVICEID(Adapter, Request->ulDeviceID);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_NODRIVER\n"));
+ return (NDIS_STATUS_TAPI_NODRIVER);
+ }
+
+ /*
+ // Make sure the requested line device is not already in use.
+ */
+ Link = LinkAllocate(Adapter, Request->htLine,
+ (USHORT) (Link->CardLine-HTDSU_CMD_LINE1));
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_ALLOCATED\n"));
+ return (NDIS_STATUS_TAPI_ALLOCATED);
+ }
+
+ /*
+ // Tell the wrapper the line context and set the line/call state.
+ */
+ Request->hdLine = (HDRV_LINE)Link;
+ HtTapiLineDevStateHandler(Adapter, Link, LINEDEVSTATE_OPEN);
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+HtTapiProviderInitialize(
+ PHTDSU_ADAPTER Adapter,
+ PNDIS_TAPI_PROVIDER_INITIALIZE Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request initializes the TAPI portion of the miniport.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_PROVIDER_INITIALIZE
+ {
+ IN ULONG ulRequestID;
+ IN ULONG ulDeviceIDBase;
+ OUT ULONG ulNumLineDevs;
+ OUT ULONG ulProviderID;
+
+ } NDIS_TAPI_PROVIDER_INITIALIZE, *PNDIS_TAPI_PROVIDER_INITIALIZE;
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_RESOURCES
+ NDIS_STATUS_FAILURE
+ NDIS_STATUS_TAPI_RESOURCEUNAVAIL
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiProviderInitialize")
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("ulDeviceIDBase=%d\n",
+ Request->ulDeviceIDBase
+ ));
+ /*
+ // Save the device ID base value.
+ */
+ Adapter->DeviceIdBase = Request->ulDeviceIDBase;
+
+ /*
+ // Return the number of DSU lines. Assumes the miniport has initialized,
+ // self-tested, etc.
+ */
+ Request->ulNumLineDevs = Adapter->NumLineDevs;
+
+ /*
+ // Before completing the PROVIDER_INIT request, the miniport should fill
+ // in the ulNumLineDevs field of the request with the number of line
+ // devices supported by the adapter. The miniport should also set the
+ // ulProviderID field to a unique (per adapter) value. (There is no
+ // method currently in place to guarantee unique ulProviderID values,
+ // so we use the virtual address of our adapter structure.)
+ */
+ Request->ulProviderID = (ULONG)Adapter;
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+HtTapiAccept(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_ACCEPT Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request accepts the specified offered call. It may optionally send
+ the specified user-to-user information to the calling party.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_ACCEPT
+ {
+ IN ULONG ulRequestID;
+ IN HDRV_CALL hdCall;
+ IN ULONG ulUserUserInfoSize;
+ IN UCHAR UserUserInfo[1];
+
+ } NDIS_TAPI_ACCEPT, *PNDIS_TAPI_ACCEPT;
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_FAILURE
+ NDIS_STATUS_TAPI_INVALCALLHANDLE
+ NDIS_STATUS_TAPI_OPERATIONUNAVAIL
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiAccept")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("hdCall=%Xh\n"
+ "ulUserUserInfoSize=%d\n"
+ "UserUserInfo=%Xh\n",
+ Request->hdCall,
+ Request->ulUserUserInfoSize,
+ Request->UserUserInfo
+ ));
+ /*
+ // This request must be associated with a call.
+ */
+ Link = GET_LINK_FROM_HDCALL(Adapter, Request->hdCall);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALCALLHANDLE\n"));
+ return (NDIS_STATUS_TAPI_INVALCALLHANDLE);
+ }
+
+ /*
+ // We don't expect user user info.
+ */
+ ASSERT(Request->ulUserUserInfoSize == 0);
+
+ /*
+ // Note that the call has been accepted, we should see and answer soon.
+ */
+ HtTapiCallStateHandler(Adapter, Link, LINECALLSTATE_ACCEPTED, 0);
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+HtTapiAnswer(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_ANSWER Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request answers the specified offering call. It may optionally send
+ the specified user-to-user information to the calling party.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_ANSWER
+ {
+ IN ULONG ulRequestID;
+ IN HDRV_CALL hdCall;
+ IN ULONG ulUserUserInfoSize;
+ IN UCHAR UserUserInfo[1];
+
+ } NDIS_TAPI_ANSWER, *PNDIS_TAPI_ANSWER;
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_TAPI_INVALCALLHANDLE
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiAnswer")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("hdCall=%Xh\n"
+ "ulUserUserInfoSize=%d\n"
+ "UserUserInfo=%Xh\n",
+ Request->hdCall,
+ Request->ulUserUserInfoSize,
+ Request->UserUserInfo
+ ));
+ /*
+ // This request must be associated with a call.
+ */
+ Link = GET_LINK_FROM_HDCALL(Adapter, Request->hdCall);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALCALLHANDLE\n"));
+ return (NDIS_STATUS_TAPI_INVALCALLHANDLE);
+ }
+
+ /*
+ // We don't expect user user info.
+ */
+ ASSERT(Request->ulUserUserInfoSize == 0);
+
+ /*
+ // Tell the adapter to pick up the line, and wait for a connect interrupt.
+ */
+ CardLineAnswer(Adapter, Link->CardLine);
+ NdisMSetTimer(&Link->CallTimer, HTDSU_NO_CONNECT_TIMEOUT);
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+HtTapiClose(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_CLOSE Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request closes the specified open line device after completing or
+ aborting all outstanding calls and asynchronous requests on the device.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_CLOSE
+ {
+ IN ULONG ulRequestID;
+ IN HDRV_LINE hdLine;
+
+ } NDIS_TAPI_CLOSE, *PNDIS_TAPI_CLOSE;
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_PENDING
+ NDIS_STATUS_TAPI_INVALLINEHANDLE
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiClose")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ /*
+ // The results of this call.
+ */
+ NDIS_STATUS Status;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("hdLine=%Xh\n",
+ Request->hdLine
+ ));
+ /*
+ // This request must be associated with a line device.
+ */
+ Link = GET_LINK_FROM_HDLINE(Adapter, Request->hdLine);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALLINEHANDLE\n"));
+ return (NDIS_STATUS_TAPI_INVALLINEHANDLE);
+ }
+
+ /*
+ // Mark the link as closing, so no more packets will be accepted,
+ // and when the last transmit is complete, the link will be closed.
+ */
+ if (Link->NumTxQueued)
+ {
+ Status = NDIS_STATUS_PENDING;
+ Link->Closing = TRUE;
+ }
+ else
+ {
+ HtTapiLineDevStateHandler(Adapter, Link, LINEDEVSTATE_CLOSE);
+ LinkRelease(Link);
+ Status = NDIS_STATUS_SUCCESS;
+ }
+
+ DBG_LEAVE(Adapter);
+
+ return (Status);
+}
+
+
+NDIS_STATUS
+HtTapiCloseCall(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_CLOSE_CALL Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request deallocates the call after completing or aborting all
+ outstanding asynchronous requests on the call.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_CLOSE_CALL
+ {
+ IN ULONG ulRequestID;
+ IN HDRV_CALL hdCall;
+
+ } NDIS_TAPI_CLOSE_CALL, *PNDIS_TAPI_CLOSE_CALL;
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_TAPI_INVALCALLHANDLE
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiCloseCall")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ /*
+ // The results of this call.
+ */
+ NDIS_STATUS Status;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("hdCall=%Xh\n",
+ Request->hdCall
+ ));
+ /*
+ // This request must be associated with a call.
+ */
+ Link = GET_LINK_FROM_HDCALL(Adapter, Request->hdCall);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALCALLHANDLE\n"));
+ return (NDIS_STATUS_TAPI_INVALCALLHANDLE);
+ }
+
+ /*
+ // Mark the link as closing, so no more packets will be accepted,
+ // and when the last transmit is complete, the link will be closed.
+ */
+ if (Link->NumTxQueued)
+ {
+ Link->CallClosing = TRUE;
+ Status = NDIS_STATUS_PENDING;
+ }
+ else
+ {
+ HtTapiCallStateHandler(Adapter, Link, LINECALLSTATE_IDLE, 0);
+ Status = NDIS_STATUS_SUCCESS;
+ }
+
+ DBG_LEAVE(Adapter);
+
+ return (Status);
+}
+
+
+NDIS_STATUS
+HtTapiConditionalMediaDetection(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_CONDITIONAL_MEDIA_DETECTION Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request is invoked by the Connection Wrapper whenever a client
+ application uses LINEMAPPER as the dwDeviceID in the lineOpen function
+ to request that lines be scanned to find one that supports the desired
+ media mode(s) and call parameters. The Connection Wrapper scans based on
+ the union of the desired media modes and the other media modes currently
+ being monitored on the line, to give the miniport the opportunity to
+ indicate if it cannot simultaneously monitor for all of the requested
+ media modes. If the miniport can monitor for the indicated set of media
+ modes AND support the capabilities indicated in CallParams, it replies
+ with a “success” inidication. It leaves the active media monitoring modes
+ for the line unchanged.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_CONDITIONAL_MEDIA_DETECTION
+ {
+ IN ULONG ulRequestID;
+ IN HDRV_LINE hdLine;
+ IN ULONG ulMediaModes;
+ IN LINE_CALL_PARAMS LineCallParams;
+
+ } NDIS_TAPI_CONDITIONAL_MEDIA_DETECTION, *PNDIS_TAPI_CONDITIONAL_MEDIA_DETECTION;
+
+ typedef struct _LINE_CALL_PARAMS // Defaults:
+ {
+ ULONG ulTotalSize; // ---------
+
+ ULONG ulBearerMode; // voice
+ ULONG ulMinRate; // (3.1kHz)
+ ULONG ulMaxRate; // (3.1kHz)
+ ULONG ulMediaMode; // interactiveVoice
+
+ ULONG ulCallParamFlags; // 0
+ ULONG ulAddressMode; // addressID
+ ULONG ulAddressID; // (any available)
+
+ LINE_DIAL_PARAMS DialParams; // (0, 0, 0, 0)
+
+ ULONG ulOrigAddressSize; // 0
+ ULONG ulOrigAddressOffset;
+ ULONG ulDisplayableAddressSize;
+ ULONG ulDisplayableAddressOffset;
+
+ ULONG ulCalledPartySize; // 0
+ ULONG ulCalledPartyOffset;
+
+ ULONG ulCommentSize; // 0
+ ULONG ulCommentOffset;
+
+ ULONG ulUserUserInfoSize; // 0
+ ULONG ulUserUserInfoOffset;
+
+ ULONG ulHighLevelCompSize; // 0
+ ULONG ulHighLevelCompOffset;
+
+ ULONG ulLowLevelCompSize; // 0
+ ULONG ulLowLevelCompOffset;
+
+ ULONG ulDevSpecificSize; // 0
+ ULONG ulDevSpecificOffset;
+
+ } LINE_CALL_PARAMS, *PLINE_CALL_PARAMS;
+
+ typedef struct _LINE_DIAL_PARAMS
+ {
+ ULONG ulDialPause;
+ ULONG ulDialSpeed;
+ ULONG ulDigitDuration;
+ ULONG ulWaitForDialtone;
+
+ } LINE_DIAL_PARAMS, *PLINE_DIAL_PARAMS;
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_TAPI_INVALLINEHANDLE
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiConditionalMediaDetection")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("hdLine=%Xh\n"
+ "ulMediaModes=%Xh\n"
+ "LineCallParams=%Xh\n",
+ Request->hdLine,
+ Request->ulMediaModes,
+ &Request->LineCallParams
+ ));
+ /*
+ // This request must be associated with a line device.
+ */
+ Link = GET_LINK_FROM_HDLINE(Adapter, Request->hdLine);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALLINEHANDLE\n"));
+ return (NDIS_STATUS_TAPI_INVALLINEHANDLE);
+ }
+
+ /*
+ // We don't expect user user info.
+ */
+ ASSERT(Request->LineCallParams.ulUserUserInfoSize == 0);
+
+ /*
+ // I pretty much ignore all this since this adapter only supports
+ // digital data. If your adapter supports different medias or
+ // voice and data, you will need to save the necessary paramters.
+ */
+ Link->MediaModesMask = Request->ulMediaModes;
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+HtTapiDial(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_DIAL Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request dials the specified dialable number on the specified call.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_DIAL
+ {
+ IN ULONG ulRequestID;
+ IN HDRV_CALL hdCall;
+ IN ULONG ulDestAddressSize;
+ IN CHAR szDestAddress[1];
+
+ } NDIS_TAPI_DIAL, *PNDIS_TAPI_DIAL;
+
+Return Values:
+
+ NDIS_STATUS_TAPI_INVALCALLHANDLE
+ NDIS_STATUS_TAPI_OPERATIONUNAVAIL
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiDial")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("hdCall=%Xh\n"
+ "ulDestAddressSize=%d\n"
+ "szDestAddress=%Xh\n",
+ Request->hdCall,
+ Request->ulDestAddressSize,
+ Request->szDestAddress
+ ));
+ /*
+ // This request must be associated with a call.
+ */
+ Link = GET_LINK_FROM_HDCALL(Adapter, Request->hdCall);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALCALLHANDLE\n"));
+ return (NDIS_STATUS_TAPI_INVALCALLHANDLE);
+ }
+
+ /*
+ // RASTAPI only places calls through the MAKE_CALL interface.
+ */
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_TAPI_OPERATIONUNAVAIL);
+}
+
+
+NDIS_STATUS
+HtTapiDrop(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_DROP Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request drops or disconnects the specified call. User-to-user
+ information can optionally be transmitted as part of the call disconnect.
+ This function can be called by the application at any time. When
+ OID_TAPI_DROP returns with success, the call should be idle.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_DROP
+ {
+ IN ULONG ulRequestID;
+ IN HDRV_CALL hdCall;
+ IN ULONG ulUserUserInfoSize;
+ IN UCHAR UserUserInfo[1];
+
+ } NDIS_TAPI_DROP, *PNDIS_TAPI_DROP;
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_TAPI_INVALCALLHANDLE
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiDrop")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("hdCall=%Xh\n"
+ "ulUserUserInfoSize=%d\n"
+ "UserUserInfo=%Xh\n",
+ Request->hdCall,
+ Request->ulUserUserInfoSize,
+ Request->UserUserInfo
+ ));
+ /*
+ // This request must be associated with a call.
+ */
+ Link = GET_LINK_FROM_HDCALL(Adapter, Request->hdCall);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALCALLHANDLE\n"));
+ return (NDIS_STATUS_TAPI_INVALCALLHANDLE);
+ }
+
+ /*
+ // We don't expect user user info.
+ */
+ ASSERT(Request->ulUserUserInfoSize == 0);
+
+ /*
+ // The user wants to disconnect, so make it happen cappen.
+ */
+ HtTapiCallStateHandler(Adapter, Link,
+ LINECALLSTATE_DISCONNECTED, LINEDISCONNECTMODE_NORMAL);
+
+ /*
+ // Under some conditions, we may not get a CLOSE_CALL, so the
+ // line would be left unusable if we don't timeout and force a
+ // close call condition.
+ */
+ NdisMSetTimer(&Link->CallTimer, HTDSU_NO_CLOSECALL_TIMEOUT);
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+HtTapiProviderShutdown(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_PROVIDER_SHUTDOWN Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request shuts down the miniport. The miniport should terminate any
+ activities it has in progress.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_PROVIDER_SHUTDOWN
+ {
+ IN ULONG ulRequestID;
+
+ } NDIS_TAPI_PROVIDER_SHUTDOWN, *PNDIS_TAPI_PROVIDER_SHUTDOWN;
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiProviderShutdown")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ /*
+ // Used to interate over the links.
+ */
+ USHORT LinkIndex;
+
+ DBG_ENTER(Adapter);
+
+ /*
+ // Hangup all of the lines.
+ */
+ for (LinkIndex = 0; LinkIndex < Adapter->NumLineDevs; LinkIndex++)
+ {
+ Link = GET_LINK_FROM_LINKINDEX(Adapter, LinkIndex);
+
+ if (Link->Adapter)
+ {
+ /*
+ // Force the call to drop
+ */
+ if (Link->CallState != LINECALLSTATE_IDLE)
+ {
+ CardLineDisconnect(Adapter, Link->CardLine);
+ }
+
+ /*
+ // Indicate LINE_DOWN status and release the link structure.
+ */
+ LinkLineDown(Link);
+ LinkRelease(Link);
+ }
+ }
+ Adapter->NumOpens = 0;
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+HtTapiSecureCall(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_SECURE_CALL Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request secures the call from any interruptions or interference that
+ may affect the call’s media stream.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_SECURE_CALL
+ {
+ IN ULONG ulRequestID;
+ IN HDRV_CALL hdCall;
+
+ } NDIS_TAPI_SECURE_CALL, *PNDIS_TAPI_SECURE_CALL;
+
+Return Values:
+
+ NDIS_STATUS_TAPI_INVALCALLHANDLE
+ NDIS_STATUS_TAPI_OPERATIONUNAVAIL
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiSecureCall")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("hdCall=%Xh\n",
+ Request->hdCall
+ ));
+ /*
+ // This request must be associated with a call.
+ */
+ Link = GET_LINK_FROM_HDCALL(Adapter, Request->hdCall);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALCALLHANDLE\n"));
+ return (NDIS_STATUS_TAPI_INVALCALLHANDLE);
+ }
+
+ /*
+ // RASTAPI has no support for this feature yet.
+ */
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_TAPI_OPERATIONUNAVAIL);
+}
+
+
+NDIS_STATUS
+HtTapiSelectExtVersion(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_SELECT_EXT_VERSION Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request selects the indicated extension version for the indicated
+ line device. Subsequent requests operate according to that extension
+ version.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_SELECT_EXT_VERSION
+ {
+ IN ULONG ulRequestID;
+ IN HDRV_LINE hdLine;
+ IN ULONG ulExtVersion;
+
+ } NDIS_TAPI_SELECT_EXT_VERSION, *PNDIS_TAPI_SELECT_EXT_VERSION;
+
+Return Values:
+
+ NDIS_STATUS_TAPI_INVALLINEHANDLE
+ NDIS_STATUS_TAPI_OPERATIONUNAVAIL
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiSelectExtVersion")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("hdLine=%Xh\n"
+ "ulExtVersion=%Xh\n",
+ Request->hdLine,
+ Request->ulExtVersion
+ ));
+ /*
+ // This request must be associated with a line device.
+ */
+ Link = GET_LINK_FROM_HDLINE(Adapter, Request->hdLine);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALLINEHANDLE\n"));
+ return (NDIS_STATUS_TAPI_INVALLINEHANDLE);
+ }
+
+ /*
+ // NDISTAPI does not support this feature yet.
+ */
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_TAPI_OPERATIONUNAVAIL);
+}
+
+
+NDIS_STATUS
+HtTapiSendUserUserInfo(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_SEND_USER_USER_INFO Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request sends user-to-user information to the remote party on the
+ specified call.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_SEND_USER_USER_INFO
+ {
+ IN ULONG ulRequestID;
+ IN HDRV_CALL hdCall;
+ IN ULONG ulUserUserInfoSize;
+ IN UCHAR UserUserInfo[1];
+
+ } NDIS_TAPI_SEND_USER_USER_INFO, *PNDIS_TAPI_SEND_USER_USER_INFO;
+
+Return Values:
+
+ NDIS_STATUS_TAPI_INVALCALLHANDLE
+ NDIS_STATUS_TAPI_OPERATIONUNAVAIL
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiSendUserUserInfo")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("hdCall=%Xh\n"
+ "ulUserUserInfoSize=%d\n"
+ "UserUserInfo=%Xh\n",
+ Request->hdCall,
+ Request->ulUserUserInfoSize,
+ Request->UserUserInfo
+ ));
+ /*
+ // This request must be associated with a call.
+ */
+ Link = GET_LINK_FROM_HDCALL(Adapter, Request->hdCall);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALCALLHANDLE\n"));
+ return (NDIS_STATUS_TAPI_INVALCALLHANDLE);
+ }
+
+ /*
+ // We don't expect user user info.
+ */
+ ASSERT(Request->ulUserUserInfoSize == 0);
+
+ /*
+ // If your adapter has support for this feature, or uses it like
+ // ISDN, you need to find all occurances of ulUserUserInfoSize.
+ // It is included in a number of service provider calls.
+ */
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_TAPI_OPERATIONUNAVAIL);
+}
+
+
+NDIS_STATUS
+HtTapiSetAppSpecific(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_SET_APP_SPECIFIC Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request sets the application-specific field of the specified call’s
+ LINECALLINFO structure.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_SET_APP_SPECIFIC
+ {
+ IN ULONG ulRequestID;
+ IN HDRV_CALL hdCall;
+ IN ULONG ulAppSpecific;
+
+ } NDIS_TAPI_SET_APP_SPECIFIC, *PNDIS_TAPI_SET_APP_SPECIFIC;
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_FAILURE
+ NDIS_STATUS_TAPI_INVALCALLHANDLE
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiSetAppSpecific")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("hdCall=%Xh\n"
+ "ulAppSpecific=%d\n",
+ Request->hdCall,
+ Request->ulAppSpecific
+ ));
+ /*
+ // This request must be associated with a call.
+ */
+ Link = GET_LINK_FROM_HDCALL(Adapter, Request->hdCall);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALCALLHANDLE\n"));
+ return (NDIS_STATUS_TAPI_INVALCALLHANDLE);
+ }
+
+ /*
+ // You can do what ever you want here, so long as the application
+ // agrees with you.
+ */
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_TAPI_OPERATIONUNAVAIL);
+}
+
+
+NDIS_STATUS
+HtTapiSetCallParams(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_SET_CALL_PARAMS Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request sets certain call parameters for an existing call.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_SET_CALL_PARAMS
+ {
+ IN ULONG ulRequestID;
+ IN HDRV_CALL hdCall;
+ IN ULONG ulBearerMode;
+ IN ULONG ulMinRate;
+ IN ULONG ulMaxRate;
+ IN BOOLEAN bSetLineDialParams;
+ IN LINE_DIAL_PARAMS LineDialParams;
+
+ } NDIS_TAPI_SET_CALL_PARAMS, *PNDIS_TAPI_SET_CALL_PARAMS;
+
+ typedef struct _LINE_DIAL_PARAMS
+ {
+ ULONG ulDialPause;
+ ULONG ulDialSpeed;
+ ULONG ulDigitDuration;
+ ULONG ulWaitForDialtone;
+
+ } LINE_DIAL_PARAMS, *PLINE_DIAL_PARAMS;
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_FAILURE
+ NDIS_STATUS_TAPI_INVALCALLHANDLE
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiSetCallParams")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("hdCall=%Xh\n"
+ "ulBearerMode=%Xh\n",
+ "ulMinRate=%d\n",
+ "ulMaxRate=%d\n",
+ "bSetLineDialParams=%d\n",
+ "LineDialParams=%Xh\n",
+ Request->hdCall,
+ Request->ulBearerMode,
+ Request->ulMinRate,
+ Request->ulMaxRate,
+ Request->bSetLineDialParams,
+ Request->LineDialParams
+ ));
+ /*
+ // This request must be associated with a call.
+ */
+ Link = GET_LINK_FROM_HDCALL(Adapter, Request->hdCall);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALCALLHANDLE\n"));
+ return (NDIS_STATUS_TAPI_INVALCALLHANDLE);
+ }
+
+ /*
+ // RASTAPI only places calls through the MAKE_CALL interface.
+ // So there's nothing to do here for the time being.
+ */
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+HtTapiSetDefaultMediaDetection(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request informs the miniport of the new set of media modes to detect
+ for the indicated line (replacing any previous set).
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION
+ {
+ IN ULONG ulRequestID;
+ IN HDRV_LINE hdLine;
+ IN ULONG ulMediaModes;
+
+ } NDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION, *PNDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION;
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_TAPI_INVALLINEHANDLE
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiSetDefaultMediaDetection")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("hdLine=%Xh\n"
+ "ulMediaModes=%Xh\n",
+ Request->hdLine,
+ Request->ulMediaModes
+ ));
+ /*
+ // This request must be associated with a line device.
+ */
+ Link = GET_LINK_FROM_HDLINE(Adapter, Request->hdLine);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALLINEHANDLE\n"));
+ return (NDIS_STATUS_TAPI_INVALLINEHANDLE);
+ }
+
+ /*
+ // Set the media modes mask and make sure the adapter is ready to
+ // accept incoming calls. If you can detect different medias, you
+ // will need to notify the approriate interface for the media detected.
+ */
+ Link->MediaModesMask = Request->ulMediaModes;
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+HtTapiSetMediaMode(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_SET_MEDIA_MODE Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request changes a call’s media mode as stored in the call’s
+ LINE_CALL_INFO structure.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_SET_MEDIA_MODE
+ {
+ IN ULONG ulRequestID;
+ IN HDRV_CALL hdCall;
+ IN ULONG ulMediaMode;
+
+ } NDIS_TAPI_SET_MEDIA_MODE, *PNDIS_TAPI_SET_MEDIA_MODE;
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_FAILURE
+ NDIS_STATUS_TAPI_INVALCALLHANDLE
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiSetMediaMode")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("hdCall=%Xh\n"
+ "ulMediaMode=%Xh\n",
+ Request->hdCall,
+ Request->ulMediaMode
+ ));
+ /*
+ // This request must be associated with a call.
+ */
+ Link = GET_LINK_FROM_HDCALL(Adapter, Request->hdCall);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALCALLHANDLE\n"));
+ return (NDIS_STATUS_TAPI_INVALCALLHANDLE);
+ }
+
+ /*
+ // If you can detect different medias, you will need to setup to use
+ // the selected media here.
+ */
+ Link->MediaModesMask = Request->ulMediaMode;
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+HtTapiSetStatusMessages(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PNDIS_TAPI_SET_STATUS_MESSAGES Request
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This request enables the Connection Wrapper to specify which notification
+ messages the miniport should generate for events related to status changes
+ for the specified line or any of its addresses. By default, address and
+ line status reporting is initially disabled for a line.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Request _ A pointer to the NDIS_TAPI request structure for this call.
+
+ typedef struct _NDIS_TAPI_SET_STATUS_MESSAGES
+ {
+ IN ULONG ulRequestID;
+ IN HDRV_LINE hdLine;
+ IN ULONG ulLineStates;
+ IN ULONG ulAddressStates;
+
+ } NDIS_TAPI_SET_STATUS_MESSAGES, *PNDIS_TAPI_SET_STATUS_MESSAGES;
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_TAPI_INVALLINEHANDLE
+ NDIS_STATUS_TAPI_INVALLINESTATE
+ NDIS_STATUS_TAPI_INVALADDRESSSTATE
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiSetStatusMessages")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("hdLine=%Xh\n"
+ "ulLineStates=%Xh\n"
+ "ulAddressStates=%Xh\n",
+ Request->hdLine,
+ Request->ulLineStates,
+ Request->ulAddressStates
+ ));
+ /*
+ // This request must be associated with a line device.
+ */
+ Link = GET_LINK_FROM_HDLINE(Adapter, Request->hdLine);
+ if (Link == NULL)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALLINEHANDLE\n"));
+ return (NDIS_STATUS_TAPI_INVALLINEHANDLE);
+ }
+
+ /*
+ // Make sure the line settings are all within the supported list.
+ */
+ if (Request->ulLineStates & ~Link->DevStatesCaps)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALLINESTATE\n"));
+ return (NDIS_STATUS_TAPI_INVALLINESTATE);
+ }
+
+ /*
+ // Make sure the address settings are all within the supported list.
+ */
+ if (Request->ulAddressStates & ~Link->AddressStatesCaps)
+ {
+ DBG_WARNING(Adapter, ("Returning NDIS_STATUS_TAPI_INVALADDRESSSTATE\n"));
+ return (NDIS_STATUS_TAPI_INVALADDRESSSTATE);
+ }
+
+ /*
+ // Save the new event notification masks so we will only indicate the
+ // appropriate events.
+ */
+ Link->DevStatesMask = Request->ulLineStates;
+ Link->AddressStatesMask = Request->ulAddressStates;
+
+ DBG_LEAVE(Adapter);
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+VOID
+HtTapiCallStateHandler(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PHTDSU_LINK Link,
+ IN ULONG CallState,
+ IN ULONG StateParam
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This routine will indicate the given LINECALLSTATE to the Connection
+ wrapper if the event has been enabled by the wrapper. Otherwise the state
+ information is saved, but no indication is made.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Link _ A pointer to our link information structure for the selected
+ line device.
+
+ CallState _ The LINECALLSTATE event to be posted to TAPI/WAN.
+
+ StateParam _ This value depends on the event being posted, and some
+ events will pass in zero if they don't use this parameter.
+
+Return Values:
+
+ None
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiCallStateHandler")
+
+ /*
+ // The event structure passed to the connection wrapper.
+ */
+ NDIS_TAPI_EVENT CallEvent;
+
+ /*
+ // Flag tells whether call time-out routine was cancelled.
+ */
+ BOOLEAN TimerCancelled;
+
+ DBG_ENTER(Adapter);
+ DBG_FILTER(Adapter, DBG_PARAMS_ON,
+ ("OldState=%Xh "
+ "NewState=%Xh\n",
+ Link->CallState,
+ CallState
+ ));
+ /*
+ // Cancel any call time-outs events associated with this link.
+ */
+ NdisMCancelTimer(&Link->CallTimer, &TimerCancelled);
+
+ /*
+ // Init the optional parameters. They will be set as needed below.
+ */
+ CallEvent.ulParam2 = StateParam;
+ CallEvent.ulParam3 = Link->MediaMode;
+
+ /*
+ // OUTGOING) The expected sequence of events for outgoing calls is:
+ // LINECALLSTATE_IDLE, LINECALLSTATE_DIALTONE, LINECALLSTATE_DIALING,
+ // LINECALLSTATE_PROCEEDING, (LINECALLSTATE_RINGBACK | LINECALLSTATE_BUSY),
+ // LINECALLSTATE_CONNECTED, LINECALLSTATE_DISCONNECTED, LINECALLSTATE_IDLE
+ //
+ // INCOMING) The expected sequence of events for incoming calls is:
+ // LINECALLSTATE_IDLE, LINECALLSTATE_OFFERING, LINECALLSTATE_ACCEPTED,
+ // LINECALLSTATE_CONNECTED, LINECALLSTATE_DISCONNECTED, LINECALLSTATE_IDLE
+ //
+ // Under certain failure conditions, these sequences may be violated.
+ // So I used ASSERTs to verify the normal state transitions which will
+ // cause a debug break point if an unusual transition is detected.
+ */
+ switch (CallState)
+ {
+ case LINECALLSTATE_IDLE:
+ DBG_FILTER(Adapter, DBG_TAPICALL_ON,
+ ("LINECALLSTATE_IDLE line=0x%x call=0x%x\n",
+ Link->CardLine, Link->htCall));
+ /*
+ // Make sure that an idle line is disconnected.
+ */
+ if (Link->CallState &&
+ Link->CallState != LINECALLSTATE_IDLE &&
+ Link->CallState != LINECALLSTATE_DISCONNECTED)
+ {
+ DBG_WARNING(Adapter, ("Disconnecting Line=%d\n",Link->CardLine));
+ HtTapiCallStateHandler(Adapter, Link,
+ LINECALLSTATE_DISCONNECTED, LINEDISCONNECTMODE_UNKNOWN);
+ }
+ Link->RingCount = 0;
+ break;
+
+ case LINECALLSTATE_DIALTONE:
+ DBG_FILTER(Adapter, DBG_TAPICALL_ON,
+ ("LINECALLSTATE_DIALTONE line=0x%x call=0x%x\n",
+ Link->CardLine, Link->htCall));
+ ASSERT(Link->CallState == LINECALLSTATE_IDLE);
+ break;
+
+ case LINECALLSTATE_DIALING:
+ DBG_FILTER(Adapter, DBG_TAPICALL_ON,
+ ("LINECALLSTATE_DIALING line=0x%x call=0x%x\n",
+ Link->CardLine, Link->htCall));
+ ASSERT(Link->CallState == LINECALLSTATE_DIALTONE);
+ break;
+
+ case LINECALLSTATE_PROCEEDING:
+ DBG_FILTER(Adapter, DBG_TAPICALL_ON,
+ ("LINECALLSTATE_PROCEEDING line=0x%x call=0x%x\n",
+ Link->CardLine, Link->htCall));
+ ASSERT(Link->CallState == LINECALLSTATE_DIALING);
+ LinkLineUp(Link);
+ break;
+
+ case LINECALLSTATE_RINGBACK:
+ DBG_FILTER(Adapter, DBG_TAPICALL_ON,
+ ("LINECALLSTATE_RINGBACK line=0x%x call=0x%x\n",
+ Link->CardLine, Link->htCall));
+ ASSERT(Link->CallState == LINECALLSTATE_PROCEEDING);
+ break;
+
+ case LINECALLSTATE_BUSY:
+ DBG_FILTER(Adapter, DBG_TAPICALL_ON,
+ ("LINECALLSTATE_BUSY line=0x%x call=0x%x\n",
+ Link->CardLine, Link->htCall));
+ ASSERT(Link->CallState == LINECALLSTATE_DIALING);
+ break;
+
+ case LINECALLSTATE_CONNECTED:
+ DBG_FILTER(Adapter, DBG_TAPICALL_ON,
+ ("LINECALLSTATE_CONNECTED line=0x%x call=0x%x\n",
+ Link->CardLine, Link->htCall));
+ ASSERT(Link->CallState == LINECALLSTATE_PROCEEDING ||
+ Link->CallState == LINECALLSTATE_ACCEPTED);
+ break;
+
+ case LINECALLSTATE_DISCONNECTED:
+ DBG_FILTER(Adapter, DBG_TAPICALL_ON,
+ ("LINECALLSTATE_DISCONNECTED line=0x%x call=0x%x\n",
+ Link->CardLine, Link->htCall));
+ CardLineDisconnect(Adapter, Link->CardLine);
+ LinkLineDown(Link);
+ break;
+
+ case LINECALLSTATE_OFFERING:
+ DBG_FILTER(Adapter, DBG_TAPICALL_ON,
+ ("LINECALLSTATE_OFFERING line=0x%x call=0x%x\n",
+ Link->CardLine, Link->htCall));
+ ASSERT(Link->CallState == LINECALLSTATE_IDLE);
+ LinkLineUp(Link);
+ NdisMSetTimer(&Link->CallTimer, HTDSU_NO_ACCEPT_TIMEOUT);
+ break;
+
+ case LINECALLSTATE_ACCEPTED:
+ DBG_FILTER(Adapter, DBG_TAPICALL_ON,
+ ("LINECALLSTATE_ACCEPTED line=0x%x call=0x%x\n",
+ Link->CardLine, Link->htCall));
+ ASSERT(Link->CallState == LINECALLSTATE_OFFERING);
+ break;
+ }
+ /*
+ // Change the current CallState and notify the connection wrapper if it
+ // wants to know about this event.
+ */
+ if (Link->CallState != CallState)
+ {
+ Link->CallState = CallState;
+ if (Link->CallStatesMask & CallState)
+ {
+ CallEvent.htLine = Link->htLine;
+ CallEvent.htCall = Link->htCall;
+ CallEvent.ulMsg = LINE_CALLSTATE;
+ CallEvent.ulParam1 = CallState;
+ NdisMIndicateStatus(
+ Adapter->MiniportAdapterHandle,
+ NDIS_STATUS_TAPI_INDICATION,
+ &CallEvent,
+ sizeof(CallEvent)
+ );
+ DBG_NOTICE(Adapter, ("LINE_CALLSTATE:\n"
+ "htLine=%Xh\n"
+ "htCall=%Xh\n",
+ Link->htLine,
+ Link->htCall
+ ));
+ }
+ else
+ {
+ DBG_NOTICE(Adapter, ("CallState Event=%Xh is not enabled\n", CallState));
+ }
+ }
+
+ DBG_LEAVE(Adapter);
+}
+
+
+VOID
+HtTapiAddressStateHandler(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PHTDSU_LINK Link,
+ IN ULONG AddressState
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This routine will indicate the given LINEADDRESSSTATE to the Connection
+ wrapper if the event has been enabled by the wrapper. Otherwise the state
+ information is saved, but no indication is made.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Link _ A pointer to our link information structure for the selected
+ line device.
+
+ AddressState _ The LINEADDRESSSTATE event to be posted to TAPI/WAN.
+
+Return Values:
+
+ None
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiAddressStateHandler")
+
+ /*
+ // The event structure passed to the connection wrapper.
+ */
+ NDIS_TAPI_EVENT Event;
+
+ DBG_ENTER(Adapter);
+
+ if (Link->AddressStatesMask & AddressState)
+ {
+ Event.htLine = Link->htLine;
+ Event.htCall = Link->htCall;
+ Event.ulMsg = LINE_CALLSTATE;
+ Event.ulParam1 = AddressState;
+ Event.ulParam2 = 0;
+ Event.ulParam3 = 0;
+
+ /*
+ // We really don't have much to do here with this adapter.
+ // And RASTAPI doesn't accept these events anyway...
+ */
+ switch (AddressState)
+ {
+ case LINEADDRESSSTATE_INUSEZERO:
+ break;
+
+ case LINEADDRESSSTATE_INUSEONE:
+ break;
+ }
+ NdisMIndicateStatus(
+ Adapter->MiniportAdapterHandle,
+ NDIS_STATUS_TAPI_INDICATION,
+ &Event,
+ sizeof(Event)
+ );
+ }
+ else
+ {
+ DBG_NOTICE(Adapter, ("AddressState Event=%Xh is not enabled\n", AddressState));
+ }
+
+ DBG_LEAVE(Adapter);
+}
+
+
+VOID
+HtTapiLineDevStateHandler(
+ IN PHTDSU_ADAPTER Adapter,
+ IN PHTDSU_LINK Link,
+ IN ULONG LineDevState
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This routine will indicate the given LINEDEVSTATE to the Connection wrapper
+ if the event has been enabled by the wrapper. Otherwise the state
+ information is saved, but no indication is made.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+ Link _ A pointer to our link information structure for the selected
+ line device.
+
+ LineDevState _ The LINEDEVSTATE event to be posted to TAPI/WAN.
+
+Return Values:
+
+ None
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiLineDevStateHandler")
+
+ /*
+ // The event structure passed to the connection wrapper.
+ */
+ NDIS_TAPI_EVENT LineEvent;
+ NDIS_TAPI_EVENT CallEvent;
+
+ /*
+ // The line state change may cause a call state change as well.
+ */
+ ULONG NewCallState = 0;
+ ULONG StateParam = 0;
+
+ DBG_ENTER(Adapter);
+
+ LineEvent.ulParam2 = 0;
+ LineEvent.ulParam3 = 0;
+
+ /*
+ // Handle the line state transition as needed.
+ */
+ switch (LineDevState)
+ {
+ case LINEDEVSTATE_RINGING:
+ LineEvent.ulParam2 = 1; // only one RingMode
+ if ((LineEvent.ulParam3 = ++Link->RingCount) == 1)
+ {
+ NewCallState = LINECALLSTATE_OFFERING;
+ }
+ break;
+
+ case LINEDEVSTATE_CONNECTED:
+ NewCallState = LINECALLSTATE_CONNECTED;
+ break;
+
+ case LINEDEVSTATE_DISCONNECTED:
+ if (Link->CallState != LINECALLSTATE_IDLE &&
+ Link->CallState != LINECALLSTATE_DISCONNECTED)
+ {
+ NewCallState = LINECALLSTATE_DISCONNECTED;
+ StateParam = LINEDISCONNECTMODE_NORMAL;
+ }
+ break;
+
+ case LINEDEVSTATE_OUTOFSERVICE:
+ if (Link->CallState != LINECALLSTATE_IDLE &&
+ Link->CallState != LINECALLSTATE_DISCONNECTED)
+ {
+ NewCallState = LINECALLSTATE_DISCONNECTED;
+ StateParam = LINEDISCONNECTMODE_UNKNOWN;
+ }
+ break;
+
+ case LINEDEVSTATE_OPEN:
+ /*
+ // Make sure the line is configured for dialing when we open up.
+ // Then enable the interrupts we're interested in now.
+ */
+ if (Link->CardLine == HTDSU_CMD_LINE1)
+ {
+ Adapter->InterruptEnableFlag |= HTDSU_INTR_ALL_LINE1;
+ }
+ else
+ {
+ Adapter->InterruptEnableFlag |= HTDSU_INTR_ALL_LINE2;
+ }
+ ++Adapter->NumOpens;
+ CardLineConfig(Adapter, Link->CardLine);
+ CardEnableInterrupt(Adapter);
+ NewCallState = LINECALLSTATE_IDLE;
+ break;
+
+ case LINEDEVSTATE_CLOSE:
+ /*
+ // This must not be called until all transmits have been dequeued
+ // and ack'd. Otherwise the wrapper will hang waiting for transmit
+ // request to complete.
+ */
+ if (Link->CardLine == HTDSU_CMD_LINE1)
+ {
+ Adapter->InterruptEnableFlag &= ~HTDSU_INTR_ALL_LINE1;
+ }
+ else
+ {
+ Adapter->InterruptEnableFlag &= ~HTDSU_INTR_ALL_LINE2;
+ }
+ CardEnableInterrupt(Adapter);
+ --Adapter->NumOpens;
+ NewCallState = LINECALLSTATE_IDLE;
+ break;
+ }
+ Link->DevState = LineDevState;
+
+ /*
+ // If this is the first indication of an incoming call, we need to
+ // let TAPI know about it so we can get a htCall handle associated
+ // with it.
+ */
+ if (NewCallState == LINECALLSTATE_OFFERING)
+ {
+ CallEvent.htLine = Link->htLine;
+ CallEvent.htCall = (HTAPI_CALL)0;
+ CallEvent.ulMsg = LINE_NEWCALL;
+ CallEvent.ulParam1 = (ULONG) Link;
+ CallEvent.ulParam2 = 0;
+ CallEvent.ulParam3 = 0;
+
+ NdisMIndicateStatus(
+ Adapter->MiniportAdapterHandle,
+ NDIS_STATUS_TAPI_INDICATION,
+ &CallEvent,
+ sizeof(CallEvent)
+ );
+ Link->htCall = (HTAPI_CALL)CallEvent.ulParam2;
+ DBG_NOTICE(Adapter, ("NEW_CALL htCall=%Xh\n",Link->htCall));
+ }
+
+ /*
+ // Tell TAPI what's going on here, if she cares.
+ */
+ if (Link->DevStatesMask & LineDevState)
+ {
+ LineEvent.htLine = Link->htLine;
+ LineEvent.htCall = Link->htCall;
+ LineEvent.ulMsg = LINE_LINEDEVSTATE;
+ LineEvent.ulParam1 = LineDevState;
+
+ NdisMIndicateStatus(
+ Adapter->MiniportAdapterHandle,
+ NDIS_STATUS_TAPI_INDICATION,
+ &LineEvent,
+ sizeof(LineEvent)
+ );
+ }
+ else
+ {
+ DBG_NOTICE(Adapter, ("LineDevEvent %Xh is not enabled\n", LineDevState));
+ }
+
+ /*
+ // Tell TAPI what this event does to any call that may be in progress.
+ */
+ if (NewCallState)
+ {
+ HtTapiCallStateHandler(Adapter, Link, NewCallState, StateParam);
+ }
+
+ DBG_LEAVE(Adapter);
+}
+
+
+VOID
+HtTapiResetHandler(
+ IN PHTDSU_ADAPTER Adapter
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This rouine is called by the MiniportReset routine after the hardware
+ has been reset due to some failure detection. We need to make sure the
+ line and call state information is conveyed properly to the connection
+ wrapper.
+
+Parameters:
+
+ Adapter _ A pointer ot our adapter information structure.
+
+Return Values:
+
+ None
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiResetHandler")
+
+ /*
+ // A pointer to our link information structure for the selected line device.
+ */
+ PHTDSU_LINK Link;
+
+ DBG_ENTER(Adapter);
+
+ /*
+ // Force disconnect on both lines.
+ */
+ Link = GET_LINK_FROM_CARDLINE(Adapter, HTDSU_CMD_LINE1);
+ HtTapiLineDevStateHandler(Adapter, Link, LINEDEVSTATE_DISCONNECTED);
+
+ if (Adapter->NumLineDevs == HTDSU_NUM_LINKS)
+ {
+ Link = GET_LINK_FROM_CARDLINE(Adapter, HTDSU_CMD_LINE2);
+ HtTapiLineDevStateHandler(Adapter, Link, LINEDEVSTATE_DISCONNECTED);
+ }
+
+ DBG_LEAVE(Adapter);
+}
+
+
+VOID
+HtTapiCallTimerHandler(
+ IN PVOID SystemSpecific1,
+ IN PHTDSU_LINK Link,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Functional Description:
+
+ This routine is called when the CallTimer timeout occurs. It will
+ handle the event according to the current CallState and make the
+ necessary indications and changes to the call state.
+
+Parameters:
+
+ Link _ A pointer to our link information structure on which a call event
+ is in progress.
+
+Return Values:
+
+ None
+
+---------------------------------------------------------------------------*/
+
+{
+ DBG_FUNC("HtTapiCallTimerHandler")
+
+ PHTDSU_ADAPTER Adapter = Link->Adapter;
+
+ DBG_ENTER(Adapter);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ switch (Link->CallState)
+ {
+ case LINECALLSTATE_DIALING:
+ if (CardStatusNoDialTone(Adapter, Link->CardLine))
+ {
+ LinkLineError(Link, WAN_ERROR_TIMEOUT);
+ HtTapiCallStateHandler(Adapter, Link,
+ LINECALLSTATE_DISCONNECTED, LINEDISCONNECTMODE_BUSY);
+ }
+ else
+ {
+ /*
+ // We got a signal, so dialing must be proceeding
+ */
+ HtTapiCallStateHandler(Adapter, Link, LINECALLSTATE_PROCEEDING, 0);
+ NdisMSetTimer(&Link->CallTimer, HTDSU_NO_ANSWER_TIMEOUT);
+ }
+ break;
+
+ case LINECALLSTATE_PROCEEDING:
+ if (CardStatusNoAnswer(Adapter, Link->CardLine) ||
+ !CardStatusCarrierDetect(Adapter, Link->CardLine) ||
+ !CardStatusOnLine(Adapter, Link->CardLine))
+ {
+ /*
+ // We did not get answer, so hangup and abort the call.
+ */
+ LinkLineError(Link, WAN_ERROR_TIMEOUT);
+ HtTapiCallStateHandler(Adapter, Link,
+ LINECALLSTATE_DISCONNECTED, LINEDISCONNECTMODE_NOANSWER);
+ }
+ break;
+
+ case LINECALLSTATE_OFFERING:
+ /*
+ // We did not get an accept or answer, so hangup and abort the call.
+ */
+ LinkLineError(Link, WAN_ERROR_TIMEOUT);
+ HtTapiCallStateHandler(Adapter, Link,
+ LINECALLSTATE_DISCONNECTED, LINEDISCONNECTMODE_NOANSWER);
+ break;
+
+ case LINECALLSTATE_ACCEPTED:
+ /*
+ // We did not get connected after answer, so hangup and abort the call.
+ */
+ LinkLineError(Link, WAN_ERROR_TIMEOUT);
+ HtTapiCallStateHandler(Adapter, Link,
+ LINECALLSTATE_DISCONNECTED, LINEDISCONNECTMODE_NOANSWER);
+ break;
+
+ case LINECALLSTATE_DISCONNECTED:
+ /*
+ // We did not get CloseCall after DropCall, so force a close.
+ */
+ HtTapiCallStateHandler(Adapter, Link, LINECALLSTATE_IDLE, 0);
+ break;
+
+ default:
+ DBG_WARNING(Adapter, ("TIMEOUT in CallState=%Xh\n",Link->CallState));
+ break;
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ DBG_LEAVE(Adapter);
+}
+
diff --git a/private/ntos/ndis/htdsu/version.h b/private/ntos/ndis/htdsu/version.h
new file mode 100644
index 000000000..9a3367cff
--- /dev/null
+++ b/private/ntos/ndis/htdsu/version.h
@@ -0,0 +1,62 @@
+/***************************************************************************\
+|* Copyright (c) 1994 Microsoft Corporation *|
+|* Developed for Microsoft by TriplePoint, Inc. Beaverton, Oregon *|
+|* *|
+|* This file is part of the HT Communications DSU41 WAN Miniport Driver. *|
+\***************************************************************************/
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Module Name:
+
+ version.h
+
+Abstract:
+
+ This file contains version definitions for the Miniport driver file.
+
+Author:
+
+ Larry Hattery - TriplePoint, Inc. (larryh@tpi.com) Jun-94
+
+Environment:
+
+ Include this file at the top of each module in the driver to make sure
+ each module gets rebuilt when the version changes.
+
+Revision History:
+
+---------------------------------------------------------------------------*/
+
+#ifndef _VERSION_H
+#define _VERSION_H
+
+/*
+// Used to add version information to driver file header.
+*/
+#define VER_COMPANYNAME_STR "Microsoft Corporation"
+#define VER_FILEDESCRIPTION_STR "NDIS 3.0 WAN Miniport Driver for Windows NT"
+#define VER_FILEVERSION_STR "1.20"
+#define VER_INTERNALNAME_STR "htdsu41.sys"
+#define VER_LEGALCOPYRIGHT_STR "Copyright \251 1994 " VER_COMPANYNAME_STR
+#define VER_ORIGINALFILENAME_STR VER_INTERNALNAME_STR
+#undef VER_PRODUCTNAME_STR
+#define VER_PRODUCTNAME_STR "HT Communications 56 kbps Digital Modem"
+#undef VER_PRODUCTVERSION_STR
+#define VER_PRODUCTVERSION_STR "DSU41 Digital Modem PC Card"
+
+/*
+// Used to report driver version number.
+*/
+#define HTDSU_MAJOR_VERSION 0x01 // Make sure you change above too
+#define HTDSU_MINOR_VERSION 0x20
+
+/*
+// Used when registering MAC with NDIS wrapper.
+// i.e. What NDIS version do we expect.
+*/
+#define NDIS_MAJOR_VERSION 0x03
+#define NDIS_MINOR_VERSION 0x00
+
+#endif
+
diff --git a/private/ntos/ndis/ibmtok/ibmtok.c b/private/ntos/ndis/ibmtok/ibmtok.c
new file mode 100644
index 000000000..30e4da708
--- /dev/null
+++ b/private/ntos/ndis/ibmtok/ibmtok.c
@@ -0,0 +1,5906 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ibmtok.c
+
+Abstract:
+
+ This is the main file for the IBM Token-Ring 16/4 Adapter.
+ This driver conforms to the NDIS 3.0 interface.
+
+ The overall structure and much of the code is taken from
+ the Lance NDIS driver by Tony Ercolano.
+
+Author:
+
+ Anthony V. Ercolano (Tonye) 20-Jul-1990
+ Adam Barr (adamba) 15-Feb-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent.
+
+Revision History:
+
+ Sean Selitrennikoff -- 9/15/91:
+ Added code to handle Microchannel with PC I/O bus handling.
+ Fixed bugs.
+ Sean Selitrennikoff -- 10/15/91:
+ Converted to Ndis 3.0 spec.
+ George Joy -- 12/1/91
+ Changed for compilation under DOS as well as NT
+ Sean Selitrennikoff -- 1/8/92:
+ Added error logging
+ Brian E. Moore -- 8/8/95
+ Added AutoRingSpeed Support for the PCMCIA token-ring III card.
+
+ Sanjay Deshpande -- 11/22/95
+ PCMCIA MMIO and RAM is read from registry always .... no default values
+--*/
+
+
+#include <ndis.h>
+
+
+#include <tfilter.h>
+#include <tokhrd.h>
+#include <toksft.h>
+
+#include "keywords.h"
+
+//
+// This constant is used for places where NdisAllocateMemory
+// needs to be called and the HighestAcceptableAddress does
+// not matter.
+//
+
+const NDIS_PHYSICAL_ADDRESS HighestAcceptableMax =
+ NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
+
+
+//
+// If you add to this, make sure to add the
+// a case in IbmtokFillInGlobalData() and in
+// IbmtokQueryGlobalStatistics()
+//
+static const UINT IbmtokGlobalSupportedOids[] = {
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+ OID_802_5_PERMANENT_ADDRESS,
+ OID_802_5_CURRENT_ADDRESS,
+ OID_802_5_CURRENT_FUNCTIONAL,
+ OID_802_5_CURRENT_GROUP,
+ OID_802_5_LAST_OPEN_STATUS,
+ OID_802_5_CURRENT_RING_STATUS,
+ OID_802_5_CURRENT_RING_STATE,
+ OID_802_5_LINE_ERRORS,
+ OID_802_5_LOST_FRAMES
+ };
+
+//
+// If you add to this, make sure to add the
+// a case in IbmtokQueryGlobalStatistics() and in
+// IbmtokQueryProtocolInformation()
+//
+static const UINT IbmtokProtocolSupportedOids[] = {
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_802_5_PERMANENT_ADDRESS,
+ OID_802_5_CURRENT_ADDRESS,
+ OID_802_5_CURRENT_FUNCTIONAL,
+ OID_802_5_CURRENT_GROUP
+ };
+
+
+//
+// On a development build, don't define functions as static
+// so we can set breakpoints on them.
+//
+
+
+#if DEVL
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+
+#if DBG
+INT IbmtokDbg = 0;
+#define LOG 1
+#else
+#define LOG 0
+#endif
+
+
+//
+// Get from configuration file.
+//
+
+#define MAX_MULTICAST_ADDRESS ((UINT)16)
+#define MAX_ADAPTERS ((UINT)4)
+
+
+//
+// This macro determines if the directed address
+// filtering in the CAM is actually necessary given
+// the current filter.
+//
+#define CAM_DIRECTED_SIGNIFICANT(_Filter) \
+ ((((_Filter) & NDIS_PACKET_TYPE_DIRECTED) && \
+ (!((_Filter) & NDIS_PACKET_TYPE_PROMISCUOUS))) ? 1 : 0)
+
+
+//
+// This macro determines if the multicast filtering in
+// the CAM are actually necessary given the current filter.
+//
+#define CAM_MULTICAST_SIGNIFICANT(_Filter) \
+ ((((_Filter) & NDIS_PACKET_TYPE_MULTICAST) && \
+ (!((_Filter) & (NDIS_PACKET_TYPE_ALL_MULTICAST | \
+ NDIS_PACKET_TYPE_PROMISCUOUS)))) ? 1 : 0)
+
+
+STATIC
+NDIS_STATUS
+IbmtokOpenAdapter(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT NDIS_HANDLE *MacBindingHandle,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_HANDLE MacAdapterContext,
+ IN UINT OpenOptions,
+ IN PSTRING AddressingInformation OPTIONAL
+ );
+
+STATIC
+NDIS_STATUS
+IbmtokCloseAdapter(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+
+STATIC
+NDIS_STATUS
+IbmtokRequest(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+STATIC
+NDIS_STATUS
+IbmtokQueryInformation(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN PIBMTOK_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+
+STATIC
+NDIS_STATUS
+IbmtokSetInformation(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN PIBMTOK_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+STATIC
+NDIS_STATUS
+IbmtokQueryGlobalStatistics(
+ IN NDIS_HANDLE MacAdapterContext,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+NDIS_STATUS
+IbmtokAddAdapter(
+ IN NDIS_HANDLE MacMacContext,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING AdaptName
+ );
+
+VOID
+IbmtokRemoveAdapter(
+ IN PVOID MacAdapterContext
+ );
+
+STATIC
+NDIS_STATUS
+IbmtokSetPacketFilter(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN PIBMTOK_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT PacketFilter
+ );
+
+STATIC
+NDIS_STATUS
+IbmtokSetGroupAddress(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN PIBMTOK_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest,
+ IN PUCHAR Address
+ );
+
+STATIC
+NDIS_STATUS
+IbmtokChangeFunctionalAddress(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN PIBMTOK_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest,
+ IN PUCHAR Address
+ );
+
+STATIC
+NDIS_STATUS
+IbmtokReset(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+STATIC
+NDIS_STATUS
+IbmtokTest(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+STATIC
+NDIS_STATUS
+IbmtokChangeFilter(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+STATIC
+NDIS_STATUS
+IbmtokChangeAddress(
+ IN TR_FUNCTIONAL_ADDRESS OldFunctionalAddress,
+ IN TR_FUNCTIONAL_ADDRESS NewFunctionalAddress,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+STATIC
+NDIS_STATUS
+IbmtokChangeGroupAddress(
+ IN TR_FUNCTIONAL_ADDRESS OldGroupAddress,
+ IN TR_FUNCTIONAL_ADDRESS NewGroupAddress,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+STATIC
+BOOLEAN
+IbmtokHardwareDetails(
+ IN PIBMTOK_ADAPTER Adapter
+ );
+
+STATIC
+NDIS_STATUS
+IbmtokRegisterAdapter(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING DeviceName,
+ IN BOOLEAN McaCard,
+ IN BOOLEAN ConfigError
+ );
+
+STATIC
+VOID
+SetInitializeVariables(
+ IN PIBMTOK_ADAPTER Adapter
+ );
+
+VOID
+SetResetVariables(
+ IN PIBMTOK_ADAPTER Adapter
+ );
+
+extern
+VOID
+IbmtokStartAdapterReset(
+ IN PIBMTOK_ADAPTER Adapter
+ );
+
+STATIC
+VOID
+IbmtokCloseAction(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+STATIC
+VOID
+IbmtokSetupRegistersAndInit(
+ IN PIBMTOK_ADAPTER Adapter
+ );
+
+STATIC
+NDIS_STATUS
+IbmtokInitialInit(
+ IN PIBMTOK_ADAPTER Adapter
+ );
+
+VOID
+IbmtokUnload(
+ IN NDIS_HANDLE MacMacContext
+ );
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+#pragma NDIS_INIT_FUNCTION(DriverEntry)
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+/*++
+
+Routine Description:
+
+ This is the primary initialization routine for the ibmtok driver.
+ It is simply responsible for the intializing the wrapper and registering
+ the MAC. It then calls a system and architecture specific routine that
+ will initialize and register each adapter.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+Return Value:
+
+ The status of the operation.
+
+--*/
+
+{
+
+
+ //
+ // Receives the status of the NdisRegisterMac operation.
+ //
+ NDIS_STATUS InitStatus;
+ PIBMTOK_MAC IbmtokMac;
+ NDIS_HANDLE NdisWrapperHandle;
+ char Tmp[sizeof(NDIS_MAC_CHARACTERISTICS)];
+ PNDIS_MAC_CHARACTERISTICS IbmtokChar = (PNDIS_MAC_CHARACTERISTICS)(PVOID)Tmp;
+ NDIS_STRING MacName = NDIS_STRING_CONST("IbmTok");
+
+#if NDIS_WIN
+ UCHAR pIds[sizeof (EISA_MCA_ADAPTER_IDS) + 2 * sizeof (USHORT)];
+#endif
+
+#if NDIS_WIN
+ ((PEISA_MCA_ADAPTER_IDS)pIds)->nEisaAdapters=0;
+ ((PEISA_MCA_ADAPTER_IDS)pIds)->nMcaAdapters=2;
+ *((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 0)=IBMTOK1_ADAPTER_ID;
+ *((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 1)=IBMTOK2_ADAPTER_ID;
+ (PVOID) DriverObject = (PVOID) pIds;
+#endif
+
+ //
+ // Initialize the wrapper.
+ //
+
+ NdisInitializeWrapper(
+ &NdisWrapperHandle,
+ DriverObject,
+ RegistryPath,
+ NULL
+ );
+
+ //
+ // Now allocate memory for our global structure.
+ //
+
+ InitStatus = IBMTOK_ALLOC_PHYS(&IbmtokMac, sizeof(IBMTOK_MAC));
+
+ if (InitStatus != NDIS_STATUS_SUCCESS) {
+
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ IbmtokMac->NdisWrapperHandle = NdisWrapperHandle;
+
+ //
+ // Initialize the MAC characteristics for the call to
+ // NdisRegisterMac.
+ //
+
+
+ IbmtokChar->MajorNdisVersion = IBMTOK_NDIS_MAJOR_VERSION;
+ IbmtokChar->MinorNdisVersion = IBMTOK_NDIS_MINOR_VERSION;
+ IbmtokChar->OpenAdapterHandler = (OPEN_ADAPTER_HANDLER) IbmtokOpenAdapter;
+ IbmtokChar->CloseAdapterHandler = (CLOSE_ADAPTER_HANDLER) IbmtokCloseAdapter;
+ IbmtokChar->RequestHandler = IbmtokRequest;
+ IbmtokChar->SendHandler = IbmtokSend;
+ IbmtokChar->TransferDataHandler = IbmtokTransferData;
+ IbmtokChar->ResetHandler = IbmtokReset;
+ IbmtokChar->UnloadMacHandler = IbmtokUnload;
+ IbmtokChar->QueryGlobalStatisticsHandler = IbmtokQueryGlobalStatistics;
+ IbmtokChar->AddAdapterHandler = IbmtokAddAdapter;
+ IbmtokChar->RemoveAdapterHandler = IbmtokRemoveAdapter;
+
+ IbmtokChar->Name = MacName;
+
+ NdisRegisterMac(
+ &InitStatus,
+ &IbmtokMac->NdisMacHandle,
+ NdisWrapperHandle,
+ (PVOID)IbmtokMac,
+ IbmtokChar,
+ sizeof(*IbmtokChar)
+ );
+
+ if (InitStatus != NDIS_STATUS_SUCCESS) {
+
+ NdisTerminateWrapper(NdisWrapperHandle, NULL);
+
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ return NDIS_STATUS_SUCCESS;
+
+}
+
+
+
+#pragma NDIS_INIT_FUNCTION(IbmtokRegisterAdapter)
+
+STATIC
+NDIS_STATUS
+IbmtokRegisterAdapter(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING DeviceName,
+ IN BOOLEAN McaCard,
+ IN BOOLEAN ConfigError
+ )
+
+/*++
+
+Routine Description:
+
+ This routine (and its interface) are not portable. They are
+ defined by the OS, the architecture, and the particular IBMTOK
+ implementation.
+
+ This routine is responsible for the allocation of the datastructures
+ for the driver as well as any hardware specific details necessary
+ to talk with the device.
+
+Arguments:
+
+ Adapter - Pointer to the adapter block.
+
+ ConfigurationHandle - Handle passed to MacAddAdapter, to be passed to
+ NdisRegisterAdapter.
+
+ DeviceName - Name of this adapter.
+
+ McaCard - This is an MCA bus.
+
+ ConfigError - TRUE if a configuration error was found earlier.
+
+Return Value:
+
+ Returns NDIS_STATUS_SUCCESS if everything goes ok, else
+ if anything occurred that prevents the initialization
+ of the adapter it returns an appropriate NDIS error.
+
+--*/
+
+{
+
+ NDIS_STATUS Status;
+
+ //
+ // Holds information needed when registering the adapter.
+ //
+
+ NDIS_ADAPTER_INFORMATION AdapterInformation;
+
+ // We put in this assertion to make sure that ushort are 2 bytes.
+ // if they aren't then the initialization block definition needs
+ // to be changed.
+ //
+ // Also all of the logic that deals with status registers assumes
+ // that control registers are only 2 bytes.
+ //
+
+ ASSERT(sizeof(USHORT) == 2);
+
+ //
+ // Get the interrupt number and MMIO address.
+ //
+
+ //
+ // Set the adapter state.
+ //
+
+ SetInitializeVariables(Adapter);
+
+ SetResetVariables(Adapter);
+
+ //
+ // Set up the AdapterInformation structure; zero it
+ // first in case it is extended later.
+ //
+
+ IBMTOK_ZERO_MEMORY (&AdapterInformation, sizeof(NDIS_ADAPTER_INFORMATION));
+ AdapterInformation.AdapterType = (McaCard ? NdisInterfaceMca : NdisInterfaceIsa);
+ AdapterInformation.NumberOfPortDescriptors = 1;
+ AdapterInformation.PortDescriptors[0].InitialPort = Adapter->IbmtokPortAddress;
+ AdapterInformation.PortDescriptors[0].NumberOfPorts = 4;
+
+ //
+ // Register the adapter with Ndis.
+ //
+
+ Status = NdisRegisterAdapter(
+ &Adapter->NdisAdapterHandle,
+ Adapter->NdisMacHandle,
+ Adapter,
+ ConfigurationHandle,
+ DeviceName,
+ &AdapterInformation
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ return(Status);
+
+ }
+
+ if (ConfigError) {
+
+ //
+ // Error and quit
+ //
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
+ 0
+ );
+
+ NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
+
+ return(NDIS_STATUS_FAILURE);
+
+ }
+
+
+
+ if (!IbmtokHardwareDetails(Adapter)) {
+
+ NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
+ return NDIS_STATUS_ADAPTER_NOT_FOUND;
+
+ }
+
+
+ //
+ // Reset the card to put it in a valid state.
+ //
+
+ if (Adapter->SharedRamPaging) {
+
+ WRITE_ADAPTER_REGISTER(Adapter, SRPR_LOW, 0xc0);
+
+ }
+
+ //
+ // OK, do the reset as detailed in the Tech Ref...
+ //
+
+ WRITE_ADAPTER_PORT(Adapter, RESET_LATCH, 0);
+
+ NdisStallExecution(50000);
+
+ WRITE_ADAPTER_PORT(Adapter, RESET_RELEASE, 0);
+
+ //
+ // Initialize the interrupt.
+ //
+
+ NdisAllocateSpinLock(&Adapter->InterruptLock);
+
+ NdisInitializeInterrupt(
+ &Status,
+ &Adapter->Interrupt,
+ Adapter->NdisAdapterHandle,
+ IbmtokISR,
+ Adapter,
+ IbmtokDPC,
+ Adapter->InterruptLevel,
+ Adapter->InterruptLevel,
+ FALSE,
+ (Adapter->UsingPcIoBus)?NdisInterruptLatched:
+ NdisInterruptLevelSensitive
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS){
+
+ //
+ // Set up the Adapter variables. (We have to do the
+ // initial init to get the network address before we
+ // create the filter DB.)
+ //
+ if (IbmtokInitialInit(Adapter) != NDIS_STATUS_SUCCESS) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
+ 2,
+ registerAdapter,
+ IBMTOK_ERRMSG_NOT_FOUND
+ );
+
+ NdisRemoveInterrupt(&Adapter->Interrupt);
+
+ NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
+ NdisFreeSpinLock(&(Adapter->Lock));
+ return NDIS_STATUS_ADAPTER_NOT_FOUND;
+
+ } else {
+
+ if (!TrCreateFilter(
+ IbmtokChangeAddress,
+ IbmtokChangeGroupAddress,
+ IbmtokChangeFilter,
+ IbmtokCloseAction,
+ Adapter->NetworkAddress,
+ &Adapter->Lock,
+ &Adapter->FilterDB
+ )) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ registerAdapter,
+ IBMTOK_ERRMSG_CREATE_DB
+ );
+
+ NdisRemoveInterrupt(&Adapter->Interrupt);
+ NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
+ NdisFreeSpinLock(&(Adapter->Lock));
+ return NDIS_STATUS_RESOURCES;
+
+ } else {
+
+ //
+ // Initialize the wake up timer to catch interrupts that
+ // don't complete. It fires continuously
+ // every thirty seconds, and we check if there are any
+ // uncompleted operations from the previous two-second
+ // period.
+ //
+
+ Adapter->WakeUpDpc = (PVOID)IbmtokWakeUpDpc;
+
+ NdisInitializeTimer(&Adapter->WakeUpTimer,
+ (PVOID)(Adapter->WakeUpDpc),
+ Adapter );
+
+ NdisSetTimer(
+ &Adapter->WakeUpTimer,
+ 30000
+ );
+
+ NdisRegisterAdapterShutdownHandler(
+ Adapter->NdisAdapterHandle,
+ (PVOID)Adapter,
+ IbmtokShutdown
+ );
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+ }
+
+ } else {
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_INTERRUPT_CONNECT,
+ 2,
+ registerAdapter,
+ IBMTOK_ERRMSG_INIT_INTERRUPT
+ );
+
+ NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
+ NdisFreeSpinLock(&(Adapter->Lock));
+ return(Status);
+ }
+
+}
+
+
+#pragma NDIS_INIT_FUNCTION(SetInitializeVariables)
+
+STATIC
+VOID
+SetInitializeVariables(
+ IN PIBMTOK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes all the variables in the Adapter
+ structure that should only be set during adapter initialization
+ (i.e. not during a reset).
+
+Arguments:
+
+ Adapter - The adapter for the hardware.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ InitializeListHead(&Adapter->OpenBindings);
+ InitializeListHead(&Adapter->CloseList);
+ InitializeListHead(&Adapter->CloseDuringResetList);
+
+ NdisAllocateSpinLock(&Adapter->Lock);
+
+ //
+ // If this is not true, then uncomment below
+ //
+
+ ASSERT(FALSE == (BOOLEAN)0);
+
+ // Adapter->HandleSrbRunning = FALSE;
+ // Adapter->HandleArbRunning = FALSE;
+
+ // Adapter->OpenInProgress = FALSE;
+
+ Adapter->AdapterNotOpen = TRUE;
+ Adapter->NotAcceptingRequests = TRUE;
+
+ // Adapter->ResetInProgress = FALSE;
+ // Adapter->ResettingOpen = NULL;
+ // Adapter->ResetInterruptAllowed = FALSE;
+ // Adapter->ResetInterruptHasArrived = FALSE;
+
+ // Adapter->BringUp = FALSE;
+
+ //
+ // Note: These assume that the SAP info will not
+ // take up more than 218 bytes. This is ok, for now, since
+ // we open the card with 0 SAPs allowed.
+ //
+
+ Adapter->ReceiveBufferLength = 256;
+ Adapter->NumberOfTransmitBuffers = 1;
+
+ //
+ // Note: The following fields are set in the interrupt handler after
+ // the card tells us if the ring is 16 or 4 Mbps.
+ //
+ //
+ // TransmitBufferLength
+ // NumberOfReceiveBuffers
+ // MaximumTransmittablePacket
+ //
+
+ // Adapter->IsrpDeferredBits = 0;
+
+ Adapter->FirstInitialization = TRUE;
+
+ // Adapter->OutstandingAsbFreeRequest = FALSE;
+}
+
+
+VOID
+SetResetVariables(
+ IN PIBMTOK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes all the variables in the Adapter
+ structure that are set both during an initialization and
+ after a reset.
+
+Arguments:
+
+ Adapter - The adapter for the hardware.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ Adapter->FirstTransmit = NULL;
+ Adapter->LastTransmit = NULL;
+ Adapter->FirstWaitingForAsb = NULL;
+ Adapter->LastWaitingForAsb = NULL;
+ Adapter->TransmittingPacket = NULL;
+
+ IBMTOK_ZERO_MEMORY(Adapter->CorrelatorArray,
+ sizeof(PNDIS_PACKET) * MAX_COMMAND_CORRELATOR);
+
+ Adapter->PendQueue = NULL;
+ Adapter->EndOfPendQueue = NULL;
+
+ Adapter->SrbAvailable = TRUE;
+ Adapter->AsbAvailable = TRUE;
+
+ Adapter->IsrpBits = 0;
+ Adapter->IsrpLowBits = 0;
+
+ Adapter->NextCorrelatorToComplete = 0;
+ Adapter->ReceiveWaitingForAsbList = (USHORT)-1;
+ Adapter->ReceiveWaitingForAsbEnd = (USHORT)-1;
+ Adapter->UseNextAsbForReceive = TRUE;
+}
+
+#pragma NDIS_INIT_FUNCTION(IbmtokInitialInit)
+
+NDIS_STATUS
+IbmtokInitialInit(
+ IN PIBMTOK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets up the initial init of the driver.
+
+Arguments:
+
+ Adapter - The adapter for the hardware.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ USHORT RegValue;
+ UINT Time = 50; // Number of 100 milliseconds to delay while waiting
+ // for the card to initialize.
+
+
+
+ IbmtokSetupRegistersAndInit(Adapter);
+
+ //
+ // Delay execution for 5 seconds to give the ring
+ // time to initialize.
+ //
+
+ while((!Adapter->BringUp) && (Time != 0)){
+
+ NdisStallExecution(100000);
+
+ Time--;
+
+ }
+
+ if (!Adapter->BringUp){
+
+ return(NDIS_STATUS_ADAPTER_NOT_FOUND);
+
+ } else {
+
+ //
+ // Do remaining initialization.
+ //
+
+ USHORT WrbOffset;
+ PSRB_BRING_UP_RESULT BringUpSrb;
+ PUCHAR EncodedAddress;
+ UCHAR Value1, Value2;
+
+ READ_ADAPTER_REGISTER(Adapter, WRBR_LOW, &Value1);
+ READ_ADAPTER_REGISTER(Adapter, WRBR_HIGH, &Value2);
+
+ WrbOffset = (((USHORT)Value1) << 8) + (USHORT)Value2;
+
+ Adapter->InitialWrbOffset = WrbOffset;
+
+#if DBG
+ if (IbmtokDbg) {
+
+ DbgPrint("IBMTOK: Initial Offset = 0x%x\n", WrbOffset);
+
+ }
+#endif
+
+ BringUpSrb = (PSRB_BRING_UP_RESULT)
+ (Adapter->SharedRam + WrbOffset);
+
+ NdisReadRegisterUshort(&(BringUpSrb->ReturnCode), &RegValue);
+
+ if (RegValue != 0x0000) {
+
+ if (RegValue == 0x30){
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
+ 0x32,
+ handleSrbSsb,
+ IBMTOK_ERRMSG_BRINGUP_FAILURE
+ );
+
+
+ return(NDIS_STATUS_ADAPTER_NOT_FOUND);
+
+ } else {
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 3,
+ handleSrbSsb,
+ IBMTOK_ERRMSG_BRINGUP_FAILURE,
+ (ULONG)RegValue
+ );
+
+ return(NDIS_STATUS_ADAPTER_NOT_FOUND);
+
+
+ }
+
+ } else {
+
+ Adapter->FirstInitialization = FALSE;
+ Adapter->BringUp = TRUE;
+
+ }
+
+ NdisReadRegisterUchar(&(BringUpSrb->InitStatus), &RegValue);
+
+// The following routine assumes that the AutoRingSpeed keyword is set in
+// the registry. If the adapter doesn't support RingSpeedListen, turn off flag.
+
+
+ if (!(RegValue & RINGSPEEDLISTEN)) {
+
+ Adapter->RingSpeedListen = FALSE;
+
+#if DBG
+ if (IbmtokDbg) DbgPrint("IBMTOK: Adapter doesn't support Ring Speed Listen.\n");
+#endif
+
+ }
+
+ if (RegValue & 0x01) {
+
+#if DBG
+ if (IbmtokDbg) DbgPrint("IBMTOK: 16 Mbps\n");
+#endif
+
+ Adapter->Running16Mbps = TRUE;
+
+ } else {
+
+ Adapter->Running16Mbps = FALSE;
+
+ }
+
+ //
+ // ZZZ: This code assumes that there is no shared ram paging and
+ // that the MappedSharedRam is all that is available.
+ //
+
+
+#if DBG
+ if (IbmtokDbg) DbgPrint( "IBMTOK: shared RAM size is %x (%d)\n", Adapter->MappedSharedRam, Adapter->MappedSharedRam );
+#endif
+ if (Adapter->MappedSharedRam > 0x2000){
+
+ ULONG RamAvailable;
+ UCHAR NumTransmitBuffers = (UCHAR)Adapter->NumberOfTransmitBuffers;
+
+ //
+ // 2096 is the amount of shared ram that is current sucked
+ // up by the areas found on page 7-27 of the Tech. Ref.
+ //
+ //
+
+ RamAvailable = Adapter->MappedSharedRam;
+
+ if (Adapter->MappedSharedRam == 0x10000){
+
+ //
+ // Subtract an extra 8K to account for when we map
+ // MMIO space to the top 8K of RAM.
+ //
+
+ RamAvailable = RamAvailable - 2096 - 0x2000;
+
+ } else {
+
+ RamAvailable = RamAvailable - 1584;
+
+ }
+#if DBG
+ if (IbmtokDbg) DbgPrint( "IBMTOK: RAM available is %x (%d)\n", RamAvailable, RamAvailable );
+#endif
+
+ //
+ // The card has more than 8K of ram, so adjust
+ // transmit buffer size to abuse this.
+ //
+
+ if (Adapter->Running16Mbps) {
+
+ //
+ // Use the maximum allowed
+ //
+
+ Adapter->TransmitBufferLength = Adapter->Max16MbpsDhb;
+#if DBG
+ if (IbmtokDbg) DbgPrint( "IBMTOK: 16 MB ring. Transmit buffer length is %x (%d)\n", Adapter->TransmitBufferLength, Adapter->TransmitBufferLength );
+#endif
+
+ } else {
+
+ //
+ // Use the maximum allowed
+ //
+ Adapter->TransmitBufferLength = Adapter->Max4MbpsDhb;
+#if DBG
+ if (IbmtokDbg) DbgPrint( "IBMTOK: 4 MB ring. Transmit buffer length is %x (%d)\n", Adapter->TransmitBufferLength, Adapter->TransmitBufferLength );
+#endif
+
+ }
+
+ //
+ // First we subtract off buffer space for receiving the
+ // maximum sized packet that can be on the wire. This is
+ // the *minimum* number of receive buffers and may be
+ // modified below if the transmit space does not take up
+ // the rest.
+ //
+
+#if DBG
+ if (IbmtokDbg) DbgPrint( "IBMTOK: Receive buffer length is %x (%d)\n", Adapter->ReceiveBufferLength, Adapter->ReceiveBufferLength );
+#endif
+ if (RamAvailable < Adapter->TransmitBufferLength) {
+
+ //
+ // There is not enough buffer space for even a single maximum
+ // sized frame. So, just divide the buffer space into two
+ // equally sized areas -- receive and transmit.
+ //
+
+ Adapter->NumberOfReceiveBuffers = (USHORT)((RamAvailable / 2) /
+ Adapter->ReceiveBufferLength)
+ + 1;
+#if DBG
+ if (IbmtokDbg) DbgPrint( "IBMTOK: RAM too small. # receive buffers is %x (%d)\n", Adapter->NumberOfReceiveBuffers, Adapter->NumberOfReceiveBuffers );
+#endif
+
+ } else {
+
+ Adapter->NumberOfReceiveBuffers = (USHORT)(Adapter->TransmitBufferLength /
+ Adapter->ReceiveBufferLength) + 1;
+#if DBG
+ if (IbmtokDbg) DbgPrint( "IBMTOK: RAM large enough. # receive buffers is %x (%d)\n", Adapter->NumberOfReceiveBuffers, Adapter->NumberOfReceiveBuffers );
+#endif
+
+ }
+
+ RamAvailable = RamAvailable -
+ (Adapter->NumberOfReceiveBuffers * Adapter->ReceiveBufferLength);
+#if DBG
+ if (IbmtokDbg) {
+ DbgPrint( "IBMTOK: RAM available for transmit is %x (%d)\n", RamAvailable, RamAvailable );
+ DbgPrint( "IBMTOK: # transmit buffers is %x (%d)\n", NumTransmitBuffers, NumTransmitBuffers );
+ }
+#endif
+
+ if (Adapter->TransmitBufferLength > (RamAvailable / NumTransmitBuffers)) {
+
+ if ((RamAvailable / NumTransmitBuffers) < 0x1000) {
+
+ Adapter->TransmitBufferLength = 0x800;
+
+ } else if ((RamAvailable / NumTransmitBuffers) < 0x2000) {
+
+ Adapter->TransmitBufferLength = 0x1000;
+
+ } else if ((RamAvailable / NumTransmitBuffers) < 0x4000) {
+
+ Adapter->TransmitBufferLength = 0x2000;
+
+ } else {
+
+ Adapter->TransmitBufferLength = 0x4000;
+
+ }
+
+#if DBG
+ if (IbmtokDbg) DbgPrint( "IBMTOK: RAM too small. Transmit buffer length is %x (%d)\n", Adapter->TransmitBufferLength, Adapter->TransmitBufferLength );
+#endif
+ }
+
+
+ //
+ // If computed value is greater than the value that the
+ // registry allows, then use the registry value.
+ //
+
+#if DBG
+ if (IbmtokDbg) DbgPrint( "IBMTOK: Original max transmit length is %x (%d)\n", Adapter->MaxTransmittablePacket, Adapter->MaxTransmittablePacket );
+#endif
+ if (Adapter->TransmitBufferLength > Adapter->MaxTransmittablePacket) {
+
+ Adapter->TransmitBufferLength = Adapter->MaxTransmittablePacket;
+#if DBG
+ if (IbmtokDbg) DbgPrint( "IBMTOK: Max too small. Transmit buffer length is %x (%d)\n", Adapter->TransmitBufferLength, Adapter->TransmitBufferLength );
+#endif
+
+ }
+
+ Adapter->MaxTransmittablePacket = Adapter->TransmitBufferLength - 6;
+#if DBG
+ if (IbmtokDbg) DbgPrint( "IBMTOK: New max transmit length is %x (%d)\n", Adapter->MaxTransmittablePacket, Adapter->MaxTransmittablePacket );
+#endif
+
+ //
+ // Remove space taken up by transmit buffers.
+ //
+
+ RamAvailable = RamAvailable - ((ULONG)NumTransmitBuffers *
+ (ULONG)Adapter->TransmitBufferLength);
+
+ //
+ // Add in any left over space for receive buffers.
+ //
+
+ Adapter->NumberOfReceiveBuffers += (USHORT)(RamAvailable /
+ Adapter->ReceiveBufferLength);
+#if DBG
+ if (IbmtokDbg) DbgPrint( "IBMTOK: New # receive buffers is %x (%d)\n", Adapter->NumberOfReceiveBuffers, Adapter->NumberOfReceiveBuffers );
+#endif
+
+ } else {
+
+ Adapter->TransmitBufferLength = 0x800;
+ Adapter->NumberOfTransmitBuffers = 1;
+#if DBG
+ if (IbmtokDbg) {
+ DbgPrint( "IBMTOK: Only 8K shared RAM. Transmit buffer length is %x (%d)\n", Adapter->TransmitBufferLength, Adapter->TransmitBufferLength );
+ DbgPrint( "IBMTOK: Transmit buffer length is %x (%d)\n", Adapter->TransmitBufferLength, Adapter->TransmitBufferLength );
+ }
+#endif
+
+ //
+ // There is only 8K of buffer space, which is not enough space for
+ // receiving and transmitting packets on even a 4Mbit ring. So,
+ // use some reasonable values for transmit and receive space.
+ //
+
+ // If computed value is greater than the value that the
+ // registry allows, then use the registry value.
+ //
+
+#if DBG
+ if (IbmtokDbg) DbgPrint( "IBMTOK: Original max transmit length is %x (%d)\n", Adapter->MaxTransmittablePacket, Adapter->MaxTransmittablePacket );
+#endif
+ if (Adapter->TransmitBufferLength > Adapter->MaxTransmittablePacket) {
+
+ Adapter->TransmitBufferLength = Adapter->MaxTransmittablePacket;
+#if DBG
+ if (IbmtokDbg) DbgPrint( "IBMTOK: Max too small. Transmit buffer length is %x (%d)\n", Adapter->TransmitBufferLength, Adapter->TransmitBufferLength );
+#endif
+
+ }
+
+ Adapter->MaxTransmittablePacket = Adapter->TransmitBufferLength - 6;
+
+ Adapter->NumberOfReceiveBuffers = 15;
+#if DBG
+ if (IbmtokDbg) {
+ DbgPrint( "IBMTOK: New max transmit length is %x (%d)\n", Adapter->MaxTransmittablePacket, Adapter->MaxTransmittablePacket );
+ DbgPrint( "IBMTOK: # receive buffers is %x (%d)\n", Adapter->NumberOfReceiveBuffers, Adapter->NumberOfReceiveBuffers );
+ }
+#endif
+
+ }
+
+#if DBG
+ if (IbmtokDbg) {
+ DbgPrint("IBMTOK: Space: 0x%x, # Rcv: 0x%x, TransmitSize: 0x%x\n",
+ Adapter->RrrLowValue,
+ Adapter->NumberOfReceiveBuffers,
+ Adapter->MaxTransmittablePacket
+ );
+ }
+#endif
+
+ NdisReadRegisterUshort(&(BringUpSrb->EncodedAddressPointer), &RegValue);
+
+ EncodedAddress = (PUCHAR)
+ SRAM_PTR_TO_PVOID(Adapter,RegValue);
+
+ IBMTOK_MOVE_FROM_MAPPED_MEMORY(Adapter->PermanentNetworkAddress, EncodedAddress,
+ TR_LENGTH_OF_ADDRESS);
+
+
+ if ((Adapter->NetworkAddress[0] == 0x00) &&
+ (Adapter->NetworkAddress[1] == 0x00) &&
+ (Adapter->NetworkAddress[2] == 0x00) &&
+ (Adapter->NetworkAddress[3] == 0x00) &&
+ (Adapter->NetworkAddress[4] == 0x00) &&
+ (Adapter->NetworkAddress[5] == 0x00)) {
+
+
+ IBMTOK_MOVE_FROM_MAPPED_MEMORY(Adapter->NetworkAddress, EncodedAddress,
+ TR_LENGTH_OF_ADDRESS);
+ }
+
+ //
+ // If required, we have to zero the upper section
+ // of the Shared RAM now.
+ //
+ //
+ // THIS DOESN'T WORK! It hangs the system while
+ // zeroing the first address. (One gets an infinite number of
+ // hardware interrupts w/o any reason)
+ //
+
+#if 0
+ if (Adapter->UpperSharedRamZero) {
+
+ PUCHAR ZeroPointer;
+ UINT i;
+ PUCHAR OldSharedRam;
+ NDIS_PHYSICAL_ADDRESS PhysicalAddress;
+
+#if DBG
+ if (IbmtokDbg) DbgPrint("IBMTOK: Zeroing Memory\n");
+#endif
+
+
+ if (Adapter->MappedSharedRam < 0x10000) {
+
+ //
+ // This portion of memory is not currently mapped, so do it.
+ //
+
+ OldSharedRam = Adapter->SharedRam;
+
+ NdisSetPhysicalAddressHigh(PhysicalAddress, 0);
+ NdisSetPhysicalAddressLow(PhysicalAddress, (Adapter->RrrLowValue << 12) + (0x10000 - 512));
+
+ NdisMapIoSpace(
+ &Status,
+ &(Adapter->SharedRam),
+ Adapter->NdisAdapterHandle,
+ PhysicalAddress,
+ 512);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_RESOURCE_CONFLICT,
+ 0
+ );
+
+ return(Status);
+
+ }
+
+ }
+
+ if (Adapter->SharedRamPaging){
+
+ SETUP_SRPR(Adapter, SHARED_RAM_ZERO_OFFSET);
+
+#if DBG
+ if (IbmtokDbg) DbgPrint("IBMTOK: Shared RAM paging enabled\n");
+#endif
+
+ ZeroPointer =
+ SHARED_RAM_ADDRESS(Adapter,
+ SHARED_RAM_LOW_BITS(SHARED_RAM_ZERO_OFFSET));
+
+ } else {
+
+ if (Adapter->MappedSharedRam < 0x10000) {
+
+ //
+ // No offset for this portion, since we just mapped it.
+ //
+ //
+
+ ZeroPointer = SHARED_RAM_ADDRESS(Adapter, 0);
+
+ } else {
+
+ ZeroPointer =
+ SHARED_RAM_ADDRESS(Adapter, SHARED_RAM_ZERO_OFFSET);
+
+ }
+
+ }
+
+ for (i=0; i<SHARED_RAM_ZERO_LENGTH; i++) {
+
+ NdisWriteRegisterUchar(&(ZeroPointer[i]), 0x00);
+
+ }
+
+ if (Adapter->MappedSharedRam < 0x10000) {
+
+ //
+ // Unmap it
+ //
+
+ NdisUnmapIoSpace(Adapter->NdisAdapterHandle,
+ Adapter->SharedRam,
+ 512);
+
+ Adapter->SharedRam = OldSharedRam;
+
+ }
+
+ }
+#endif
+
+
+ //
+ // Now set the timer to the maximum...we still need it
+ // as a card heartbeat.
+ //
+
+ WRITE_ADAPTER_REGISTER(Adapter, TVR_HIGH, 0xff);
+
+ return NDIS_STATUS_SUCCESS;
+
+ }
+
+}
+
+
+#pragma NDIS_PAGABLE_FUNCTION(IbmtokOpenAdapter)
+
+STATIC
+NDIS_STATUS
+IbmtokOpenAdapter(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT NDIS_HANDLE *MacBindingHandle,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_HANDLE MacAdapterContext,
+ IN UINT OpenOptions,
+ IN PSTRING AddressingInformation OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ OpenErrorStatus - Returns more information about the error status. In
+ this card it is not used, since this code returns either success or
+ pending, no failure is possible.
+
+ This routine is used to create an open instance of an adapter, in effect
+ creating a binding between an upper-level module and the MAC module over
+ the adapter.
+
+Arguments:
+
+ OpenErrorStatus - Returns more information about the error status. In
+ this card it is not used, since this code returns either success or
+ pending, no failure is possible.
+
+ MacBindingHandle - A pointer to a location in which the MAC stores
+ a context value that it uses to represent this binding.
+
+
+ SelectedMediumIndex - An index into the MediumArray of the medium
+ typedef that the MAC wishes to viewed as.
+
+ MediumArray - An array of medium types which the protocol supports.
+
+ MediumArraySize - The number of elements in MediumArray.
+
+ NdisBindingContext - A value to be recorded by the MAC and passed as
+ context whenever an indication is delivered by the MAC for this binding.
+
+ MacAdapterContext - The value associated with the adapter that is being
+ opened when the MAC registered the adapter with NdisRegisterAdapter.
+
+ IN UINT OpenOptions,
+
+ AddressingInformation - An optional pointer to a variable length string
+ containing hardware-specific information that can be used to program the
+ device. (This is not used by this MAC.)
+
+Return Value:
+
+ The function value is the status of the operation. If the MAC does not
+ complete this request synchronously, the value would be
+ NDIS_STATUS_PENDING.
+
+
+--*/
+
+{
+
+ //
+ // The IBMTOK_ADAPTER that this open binding should belong too.
+ //
+ PIBMTOK_ADAPTER Adapter;
+
+ //
+ // Holds the status that should be returned to the caller.
+ //
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ //
+ // Pointer to the space allocated for the binding.
+ //
+ PIBMTOK_OPEN NewOpen;
+
+ //
+ // Generic loop variable
+ //
+ UINT i;
+
+
+ UNREFERENCED_PARAMETER(AddressingInformation);
+
+ *OpenErrorStatus = (NDIS_STATUS)0;
+
+ //
+ // Search for the medium type (token ring)
+ //
+
+ for(i=0; i < MediumArraySize; i++){
+
+ if (MediumArray[i] == NdisMedium802_5){
+
+ break;
+
+ }
+
+ }
+
+ if (i == MediumArraySize){
+
+ return(NDIS_STATUS_UNSUPPORTED_MEDIA);
+
+ }
+
+ *SelectedMediumIndex = i;
+
+ Adapter = PIBMTOK_ADAPTER_FROM_CONTEXT_HANDLE(MacAdapterContext);
+
+ NdisInterlockedAddUlong((PULONG)&Adapter->References, 1, &Adapter->Lock);
+
+ //
+ // Allocate the space for the open binding. Fill in the fields.
+ //
+
+ if (IBMTOK_ALLOC_PHYS(&NewOpen, sizeof(IBMTOK_OPEN)) ==
+ NDIS_STATUS_SUCCESS){
+
+ *MacBindingHandle = BINDING_HANDLE_FROM_PIBMTOK_OPEN(NewOpen);
+ InitializeListHead(&NewOpen->OpenList);
+ NewOpen->NdisBindingContext = NdisBindingContext;
+ NewOpen->References = 0;
+ NewOpen->BindingShuttingDown = FALSE;
+ NewOpen->OwningIbmtok = Adapter;
+ NewOpen->OpenPending = FALSE;
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ if (!TrNoteFilterOpenAdapter(
+ NewOpen->OwningIbmtok->FilterDB,
+ NewOpen,
+ NdisBindingContext,
+ &NewOpen->NdisFilterHandle
+ )) {
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ openAdapter,
+ IBMTOK_ERRMSG_OPEN_DB
+ );
+
+ IBMTOK_FREE_PHYS(NewOpen, sizeof(IBMTOK_OPEN));
+
+ StatusToReturn = NDIS_STATUS_FAILURE;
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ } else {
+
+ //
+ // Everything has been filled in. Synchronize access to the
+ // adapter block and link the new open adapter in and increment
+ // the opens reference count to account for the fact that the
+ // filter routines have a "reference" to the open.
+ //
+
+ NewOpen->LookAhead = IBMTOK_MAX_LOOKAHEAD;
+
+ Adapter->LookAhead = IBMTOK_MAX_LOOKAHEAD;
+
+ InsertTailList(&Adapter->OpenBindings,&NewOpen->OpenList);
+ NewOpen->References++;
+
+ //
+ // Now see if the adapter is currently open.
+ //
+
+ if (Adapter->AdapterNotOpen) {
+
+ //
+ // The adapter is not open, so this has to pend.
+ //
+ NewOpen->OpenPending = TRUE;
+
+ StatusToReturn = NDIS_STATUS_PENDING;
+
+ if (!Adapter->OpenInProgress) {
+
+ //
+ // Fill in the SRB for the open if this is the first
+ // one for the card.
+ //
+
+ PSRB_OPEN_ADAPTER OpenSrb;
+
+ IF_LOG('o');
+
+ Adapter->OpenInProgress = TRUE;
+ Adapter->CurrentRingState = NdisRingStateOpening;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ OpenSrb = (PSRB_OPEN_ADAPTER)
+ (Adapter->SharedRam + Adapter->InitialWrbOffset);
+
+ IBMTOK_ZERO_MAPPED_MEMORY(OpenSrb, sizeof(SRB_OPEN_ADAPTER));
+
+ NdisWriteRegisterUchar(
+ (PUCHAR)&OpenSrb->Command,
+ SRB_CMD_OPEN_ADAPTER);
+
+ NdisWriteRegisterUshort(
+ (PUSHORT)&OpenSrb->OpenOptions,
+ (USHORT)(OPEN_CONTENDER |
+ (Adapter->RingSpeedListen ?
+ OPEN_REMOTE_PROGRAM_LOAD :
+ 0))
+ );
+
+ for (i=0; i < TR_LENGTH_OF_ADDRESS; i++) {
+ NdisWriteRegisterUchar((PCHAR)&OpenSrb->NodeAddress[i],
+ Adapter->NetworkAddress[i]
+ );
+ }
+
+ WRITE_IBMSHORT(OpenSrb->ReceiveBufferNum,
+ Adapter->NumberOfReceiveBuffers);
+ WRITE_IBMSHORT(OpenSrb->ReceiveBufferLen,
+ Adapter->ReceiveBufferLength);
+
+ WRITE_IBMSHORT(OpenSrb->TransmitBufferLen,
+ Adapter->TransmitBufferLength);
+ NdisWriteRegisterUchar(
+ (PUCHAR)&OpenSrb->TransmitBufferNum,
+ (UCHAR)Adapter->NumberOfTransmitBuffers);
+
+ WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET,
+ ISRA_HIGH_COMMAND_IN_SRB);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ }
+
+ }
+
+ }
+
+ } else {
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ openAdapter,
+ IBMTOK_ERRMSG_ALLOC_MEM
+ );
+
+ return(NDIS_STATUS_RESOURCES);
+
+ }
+
+
+
+
+ //
+ // This macro assumes it is called with the lock held,
+ // and releases it.
+ //
+
+ IBMTOK_DO_DEFERRED(Adapter);
+ return StatusToReturn;
+}
+
+
+VOID
+IbmtokAdjustMaxLookAhead(
+ IN PIBMTOK_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine finds the open with the maximum lookahead value and
+ stores that in the adapter block.
+
+Arguments:
+
+ Adapter - A pointer to the adapter block.
+
+Returns:
+
+ None.
+
+--*/
+{
+ ULONG CurrentMax = 0;
+ PLIST_ENTRY CurrentLink;
+ PIBMTOK_OPEN TempOpen;
+
+ CurrentLink = Adapter->OpenBindings.Flink;
+
+ while (CurrentLink != &(Adapter->OpenBindings)){
+
+ TempOpen = CONTAINING_RECORD(
+ CurrentLink,
+ IBMTOK_OPEN,
+ OpenList
+ );
+
+ if (TempOpen->LookAhead > CurrentMax) {
+
+ CurrentMax = TempOpen->LookAhead;
+
+ }
+
+ CurrentLink = CurrentLink->Flink;
+
+ }
+
+ if (CurrentMax == 0) {
+
+ CurrentMax = IBMTOK_MAX_LOOKAHEAD;
+
+ }
+
+ Adapter->LookAhead = CurrentMax;
+
+}
+
+STATIC
+NDIS_STATUS
+IbmtokCloseAdapter(
+ IN NDIS_HANDLE MacBindingHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine causes the MAC to close an open handle (binding).
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality it is a PIBMTOK_OPEN.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+
+{
+
+ PIBMTOK_ADAPTER Adapter;
+ PIBMTOK_OPEN Open;
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ Adapter = PIBMTOK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+ Open = PIBMTOK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ //
+ // Hold the lock while we update the reference counts for the
+ // adapter and the open.
+ //
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ if (!Open->BindingShuttingDown) {
+
+ Open->References++;
+
+ StatusToReturn = TrDeleteFilterOpenAdapter(
+ Adapter->FilterDB,
+ Open->NdisFilterHandle,
+ NULL
+ );
+
+ //
+ // If the status is successful that merely implies that
+ // we were able to delete the reference to the open binding
+ // from the filtering code. If we have a successful status
+ // at this point we still need to check whether the reference
+ // count to determine whether we can close.
+ //
+ //
+ // The delete filter routine can return a "special" status
+ // that indicates that there is a current NdisIndicateReceive
+ // on this binding.
+ //
+
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Check whether the reference count is two. If
+ // it is then we can get rid of the memory for
+ // this open.
+ //
+ // A count of two indicates one for this routine
+ // and one for the filter which we *know* we can
+ // get rid of.
+ //
+
+ if (Open->References == 2) {
+
+ RemoveEntryList(&Open->OpenList);
+
+ //
+ // We are the only reference to the open. Remove
+ // it from the open list and delete the memory.
+ //
+
+ RemoveEntryList(&Open->OpenList);
+
+ if (Open->LookAhead == Adapter->LookAhead) {
+
+ IbmtokAdjustMaxLookAhead(Adapter);
+
+ }
+
+ IBMTOK_FREE_PHYS(Open,sizeof(IBMTOK_OPEN));
+
+ } else {
+
+ Open->BindingShuttingDown = TRUE;
+
+ //
+ // Remove the open from the open list and put it on
+ // the closing list.
+ //
+
+ RemoveEntryList(&Open->OpenList);
+ InsertTailList(&Adapter->CloseList,&Open->OpenList);
+
+ //
+ // Account for this routines reference to the open
+ // as well as reference because of the filtering.
+ //
+
+ Open->References -= 2;
+
+ //
+ // Change the status to indicate that we will
+ // be closing this later.
+ //
+
+ StatusToReturn = NDIS_STATUS_PENDING;
+
+ }
+
+ }
+ else if (StatusToReturn == NDIS_STATUS_PENDING)
+ {
+ //
+ // If it pended, there may be
+ // operations queued.
+ //
+ if (Adapter->CardType == IBM_TOKEN_RING_PCMCIA)
+ {
+ //
+ // Check if the card is still in the machine
+ //
+ ULONG AdapterId;
+ ULONG PcIoBusId = 0x5049434f;
+ UINT j;
+ UCHAR TmpUchar;
+
+ AdapterId = 0;
+
+ for (j = 0; j < 16; j += 2)
+ {
+ READ_ADAPTER_REGISTER(
+ Adapter,
+ CHANNEL_IDENTIFIER + (16 + j),
+ &TmpUchar
+ );
+
+ AdapterId = (AdapterId << 4) + (TmpUchar & 0x0f);
+ }
+
+ if (AdapterId != PcIoBusId)
+ {
+ Adapter->InvalidValue = TRUE;
+#if DBG
+ if (IbmtokDbg)
+ DbgPrint("IBMTOK: Card was removed or undocked\n");
+#endif
+ }
+ else
+ {
+ Adapter->InvalidValue = FALSE;
+ }
+ }
+
+ if (Adapter->InvalidValue)
+ {
+ IbmtokAbortPending (Adapter, STATUS_SUCCESS);
+ }
+ else
+ {
+ IbmtokProcessSrbRequests(Adapter);
+ }
+
+ //
+ // Now start closing down this open.
+ //
+
+ Open->BindingShuttingDown = TRUE;
+
+ //
+ // Remove the open from the open list and put it on
+ // the closing list.
+ //
+
+ RemoveEntryList(&Open->OpenList);
+ InsertTailList(&Adapter->CloseList,&Open->OpenList);
+
+ //
+ // Account for this routines reference to the open
+ // as well as reference because of the filtering.
+ //
+
+ Open->References -= 2;
+
+ } else if (StatusToReturn == NDIS_STATUS_CLOSING_INDICATING) {
+
+ //
+ // When we have this status it indicates that the filtering
+ // code was currently doing an NdisIndicateReceive. It
+ // would not be wise to delete the memory for the open at
+ // this point. The filtering code will call our close action
+ // routine upon return from NdisIndicateReceive and that
+ // action routine will decrement the reference count for
+ // the open.
+ //
+
+ Open->BindingShuttingDown = TRUE;
+
+ //
+ // This status is private to the filtering routine. Just
+ // tell the caller the the close is pending.
+ //
+
+ StatusToReturn = NDIS_STATUS_PENDING;
+
+ //
+ // Remove the open from the open list and put it on
+ // the closing list.
+ //
+
+ RemoveEntryList(&Open->OpenList);
+ InsertTailList(&Adapter->CloseList,&Open->OpenList);
+
+ //
+ // Account for this routines reference to the open.
+ //
+
+ Open->References--;
+
+ } else if (StatusToReturn == NDIS_STATUS_RESET_IN_PROGRESS) {
+
+ Open->BindingShuttingDown = TRUE;
+
+ //
+ // Remove the open from the open list and put it on
+ // the closing list.
+ //
+
+ RemoveEntryList(&Open->OpenList);
+ InsertTailList(&Adapter->CloseDuringResetList,&Open->OpenList);
+
+
+ //
+ // Account for this routines reference to the open.
+ //
+
+ Open->References--;
+
+ StatusToReturn = NDIS_STATUS_PENDING;
+
+ } else {
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ IBMTOK_ERRMSG_INVALID_STATUS,
+ 1
+ );
+
+ }
+
+ } else {
+
+ StatusToReturn = NDIS_STATUS_CLOSING;
+
+ }
+
+
+ //
+ // This macro assumes it is called with the lock held,
+ // and releases it.
+ //
+
+ IBMTOK_DO_DEFERRED(Adapter);
+ return StatusToReturn;
+
+}
+
+STATIC
+NDIS_STATUS
+IbmtokRequest(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ The IbmtokRequest allows a protocol to query and set information
+ about the MAC.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to IBMTOK_OPEN.
+
+ NdisRequest - A structure which contains the request type (Set or
+ Query), an array of operations to perform, and an array for holding
+ the results of the operations.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ PIBMTOK_ADAPTER Adapter = PIBMTOK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+ PIBMTOK_OPEN Open = PIBMTOK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ NdisAcquireSpinLock(&(Adapter->Lock));
+
+ Adapter->References++;
+
+ //
+ // Process request
+ //
+
+ if (NdisRequest->RequestType == NdisRequestQueryInformation) {
+
+ StatusToReturn = IbmtokQueryInformation(Adapter, Open, NdisRequest);
+
+ } else if (NdisRequest->RequestType == NdisRequestSetInformation) {
+
+
+ //
+ // Make sure Adapter is in a valid state.
+ //
+
+ if (Adapter->Unplugged) {
+
+ StatusToReturn = NDIS_STATUS_DEVICE_FAILED;
+
+ } else if (!Adapter->NotAcceptingRequests) {
+
+ //
+ // Make sure the open instance is valid
+ //
+
+ if (!Open->BindingShuttingDown) {
+
+ StatusToReturn = IbmtokSetInformation(Adapter,Open,NdisRequest);
+
+ } else {
+
+ StatusToReturn = NDIS_STATUS_CLOSING;
+
+ }
+
+ } else {
+
+ if (Adapter->ResetInProgress) {
+
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ } else if (Adapter->AdapterNotOpen) {
+
+ StatusToReturn = NDIS_STATUS_FAILURE;
+
+ } else {
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ IBMTOK_ERRMSG_INVALID_STATE,
+ 3
+ );
+
+ }
+ }
+ } else {
+
+ StatusToReturn = NDIS_STATUS_NOT_RECOGNIZED;
+
+ }
+
+ IBMTOK_DO_DEFERRED(Adapter);
+
+ return(StatusToReturn);
+
+}
+
+STATIC
+NDIS_STATUS
+IbmtokQueryProtocolInformation(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN PIBMTOK_OPEN Open,
+ IN NDIS_OID Oid,
+ IN BOOLEAN GlobalMode,
+ IN PVOID InfoBuffer,
+ IN UINT BytesLeft,
+ OUT PUINT BytesNeeded,
+ OUT PUINT BytesWritten
+)
+
+/*++
+
+Routine Description:
+
+ The IbmtokQueryProtocolInformation process a Query request for
+ NDIS_OIDs that are specific to a binding about the MAC. Note that
+ some of the OIDs that are specific to bindings are also queryable
+ on a global basis. Rather than recreate this code to handle the
+ global queries, I use a flag to indicate if this is a query for the
+ global data or the binding specific data.
+
+Arguments:
+
+ Adapter - a pointer to the adapter.
+
+ Open - a pointer to the open instance.
+
+ Oid - the NDIS_OID to process.
+
+ GlobalMode - Some of the binding specific information is also used
+ when querying global statistics. This is a flag to specify whether
+ to return the global value, or the binding specific value.
+
+ InfoBuffer - a pointer into the NdisRequest->InformationBuffer
+ into which store the result of the query.
+
+ BytesLeft - the number of bytes left in the InformationBuffer.
+
+ BytesNeeded - If there is not enough room in the information buffer
+ then this will contain the number of bytes needed to complete the
+ request.
+
+ BytesWritten - a pointer to the number of bytes written into the
+ InformationBuffer.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NDIS_MEDIUM Medium = NdisMedium802_5;
+ ULONG GenericULong;
+ USHORT GenericUShort;
+ UCHAR GenericArray[6];
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ //
+ // Common variables for pointing to result of query
+ //
+
+ PVOID MoveSource = (PVOID)(&GenericULong);
+ ULONG MoveBytes = sizeof(GenericULong);
+
+ NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady;
+
+ //
+ // General Algorithm:
+ //
+ // Switch(Request)
+ // Get requested information
+ // Store results in a common variable.
+ // Copy result in common variable to result buffer.
+ //
+
+ //
+ // Switch on request type
+ //
+
+ switch (Oid) {
+
+ case OID_GEN_MAC_OPTIONS:
+
+ GenericULong = (ULONG)(NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
+ NDIS_MAC_OPTION_RECEIVE_SERIALIZED
+ );
+
+ break;
+
+ case OID_GEN_SUPPORTED_LIST:
+
+ if (!GlobalMode){
+ MoveSource = (PVOID)(IbmtokProtocolSupportedOids);
+ MoveBytes = sizeof(IbmtokProtocolSupportedOids);
+ } else {
+ MoveSource = (PVOID)(IbmtokGlobalSupportedOids);
+ MoveBytes = sizeof(IbmtokGlobalSupportedOids);
+ }
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+
+
+ if (Adapter->ResetInProgress){
+
+ HardwareStatus = NdisHardwareStatusReset;
+
+ } else if ((Adapter->FirstInitialization) ||
+ (Adapter->OpenInProgress)){
+
+ HardwareStatus = NdisHardwareStatusInitializing;
+
+ } else if (Adapter->NotAcceptingRequests){
+
+ HardwareStatus = NdisHardwareStatusNotReady;
+
+ } else
+ HardwareStatus = NdisHardwareStatusReady;
+
+
+ MoveSource = (PVOID)(&HardwareStatus);
+ MoveBytes = sizeof(NDIS_HARDWARE_STATUS);
+
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+
+ MoveSource = (PVOID) (&Medium);
+ MoveBytes = sizeof(NDIS_MEDIUM);
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+
+ GenericULong = IBMTOK_MAX_LOOKAHEAD;
+
+ break;
+
+
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+
+ GenericULong = (ULONG)(Adapter->MaxTransmittablePacket);
+
+ if (Oid == OID_GEN_MAXIMUM_FRAME_SIZE) {
+
+ //
+ // For the receive frame size, we subtract the minimum
+ // header size from the number.
+ //
+
+ GenericULong -= 14;
+ }
+
+ break;
+
+
+ case OID_GEN_LINK_SPEED:
+
+ GenericULong = (ULONG)(Adapter->Running16Mbps? 160000 : 40000);
+
+ break;
+
+
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+
+ GenericULong = (ULONG)(Adapter->NumberOfTransmitBuffers *
+ Adapter->TransmitBufferLength);
+
+ break;
+
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+
+ GenericULong = (ULONG)(Adapter->NumberOfReceiveBuffers *
+ Adapter->ReceiveBufferLength);
+
+ break;
+
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+
+ GenericULong = (ULONG)(Adapter->TransmitBufferLength);
+
+ break;
+
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+
+ GenericULong = (ULONG)(Adapter->ReceiveBufferLength);
+
+ break;
+
+ case OID_GEN_VENDOR_ID:
+
+ NdisMoveMemory(
+ (PVOID)&GenericULong,
+ Adapter->PermanentNetworkAddress,
+ 3
+ );
+ GenericULong &= 0xFFFFFF00;
+
+ if (Adapter->UsingPcIoBus) {
+
+ GenericULong |= 0x01;
+
+ }
+
+ MoveSource = (PVOID)(&GenericULong);
+ MoveBytes = sizeof(GenericULong);
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+
+ if (Adapter->UsingPcIoBus){
+ MoveSource = (PVOID)"Ibm Token Ring Network Card for PC I/O bus.";
+ MoveBytes = 44;
+ } else {
+ MoveSource = (PVOID)"Ibm Token Ring Network Card for MCA bus.";
+ MoveBytes = 41;
+ }
+ break;
+
+ case OID_GEN_DRIVER_VERSION:
+
+ GenericUShort = (USHORT)((IBMTOK_NDIS_MAJOR_VERSION << 8) | IBMTOK_NDIS_MINOR_VERSION);
+
+ MoveSource = (PVOID)(&GenericUShort);
+ MoveBytes = sizeof(GenericUShort);
+ break;
+
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ if (GlobalMode) {
+
+ GenericULong = (ULONG)(Adapter->CurrentPacketFilter);
+
+ } else {
+
+ GenericULong = (ULONG)(TR_QUERY_PACKET_FILTER(
+ Adapter->FilterDB,
+ Open->NdisFilterHandle));
+
+ }
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ if (!GlobalMode){
+
+ GenericULong = Open->LookAhead;
+
+ } else {
+
+ PLIST_ENTRY CurrentLink;
+ PIBMTOK_OPEN TempOpen;
+
+ CurrentLink = Adapter->OpenBindings.Flink;
+
+ GenericULong = 0;
+
+ while (CurrentLink != &(Adapter->OpenBindings)){
+
+ TempOpen = CONTAINING_RECORD(
+ CurrentLink,
+ IBMTOK_OPEN,
+ OpenList
+ );
+
+ if (TempOpen->LookAhead > GenericULong) {
+
+ GenericULong = TempOpen->LookAhead;
+
+ if (GenericULong == IBMTOK_MAX_LOOKAHEAD) {
+
+ break;
+
+ }
+ }
+
+ CurrentLink = CurrentLink->Flink;
+
+ }
+
+ }
+
+ break;
+
+ case OID_802_5_PERMANENT_ADDRESS:
+
+ TR_COPY_NETWORK_ADDRESS((PCHAR)GenericArray,
+ Adapter->PermanentNetworkAddress);
+
+ MoveSource = (PVOID)(GenericArray);
+ MoveBytes = sizeof(Adapter->PermanentNetworkAddress);
+
+ break;
+
+ case OID_802_5_CURRENT_ADDRESS:
+
+ TR_COPY_NETWORK_ADDRESS((PCHAR)GenericArray,
+ Adapter->NetworkAddress);
+
+ MoveSource = (PVOID)(GenericArray);
+ MoveBytes = sizeof(Adapter->NetworkAddress);
+
+ break;
+
+ case OID_802_5_CURRENT_FUNCTIONAL:
+
+ if (!GlobalMode){
+
+ GenericULong = TR_QUERY_FILTER_BINDING_ADDRESS(
+ Adapter->FilterDB,
+ Open->NdisFilterHandle);
+
+ } else {
+
+ GenericULong = Adapter->CurrentCardFunctional & 0xffffffff;
+
+ }
+
+ //
+ // Now we need to reverse the crazy thing.
+ //
+
+ GenericULong = (ULONG)(
+ ((GenericULong >> 24) & 0xFF) |
+ ((GenericULong >> 8) & 0xFF00) |
+ ((GenericULong << 8) & 0xFF0000) |
+ ((GenericULong << 24) & 0xFF000000)
+ );
+
+ break;
+
+ case OID_802_5_CURRENT_GROUP:
+
+ GenericULong = Adapter->CurrentCardGroup & 0xffffffff;
+
+ //
+ // Now we need to reverse the crazy thing.
+ //
+
+ GenericULong = (ULONG)(
+ ((GenericULong >> 24) & 0xFF) |
+ ((GenericULong >> 8) & 0xFF00) |
+ ((GenericULong << 8) & 0xFF0000) |
+ ((GenericULong << 24) & 0xFF000000)
+ );
+
+ break;
+
+ default:
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS){
+
+ if (MoveBytes > BytesLeft){
+
+ //
+ // Not enough room in InformationBuffer. Punt
+ //
+
+ *BytesNeeded = MoveBytes;
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ } else {
+
+ //
+ // Store result.
+ //
+
+ IBMTOK_MOVE_MEMORY(InfoBuffer, MoveSource, MoveBytes);
+
+ (*BytesWritten) += MoveBytes;
+
+ }
+ }
+
+ return(StatusToReturn);
+}
+
+STATIC
+NDIS_STATUS
+IbmtokQueryInformation(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN PIBMTOK_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest
+ )
+/*++
+
+Routine Description:
+
+ The IbmtokQueryInformation is used by IbmtokRequest to query information
+ about the MAC.
+
+Arguments:
+
+ Adapter - A pointer to the adapter.
+
+ Open - A pointer to a particular open instance.
+
+ NdisRequest - A structure which contains the request type (Query),
+ an array of operations to perform, and an array for holding
+ the results of the operations.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+ UINT BytesWritten = 0;
+ UINT BytesNeeded = 0;
+ UINT BytesLeft = NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength;
+ PUCHAR InfoBuffer = (PUCHAR)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+
+ StatusToReturn = IbmtokQueryProtocolInformation(
+ Adapter,
+ Open,
+ NdisRequest->DATA.QUERY_INFORMATION.Oid,
+ FALSE,
+ InfoBuffer,
+ BytesLeft,
+ &BytesNeeded,
+ &BytesWritten
+ );
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesWritten = BytesWritten;
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = BytesNeeded;
+
+ return(StatusToReturn);
+}
+
+STATIC
+NDIS_STATUS
+IbmtokSetInformation(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN PIBMTOK_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest
+ )
+/*++
+
+Routine Description:
+
+ The IbmtokSetInformation is used by IbmtokRequest to set information
+ about the MAC.
+
+Arguments:
+
+ Adapter - A pointer to the adapter.
+
+ Open - A pointer to an open instance.
+
+ NdisRequest - A structure which contains the request type (Set),
+ an array of operations to perform, and an array for holding
+ the results of the operations.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+ //
+ // General Algorithm:
+ //
+ // Verify length
+ // Switch(Request)
+ // Process Request
+ //
+
+ UINT BytesNeeded = 0;
+ UINT BytesLeft = NdisRequest->DATA.SET_INFORMATION.InformationBufferLength;
+ PUCHAR InfoBuffer = (PUCHAR)(NdisRequest->DATA.SET_INFORMATION.InformationBuffer);
+
+ //
+ // Variables for the request
+ //
+
+ NDIS_OID Oid;
+ UINT OidLength;
+
+ //
+ // Variables for holding the new values to be used.
+ //
+
+ ULONG LookAhead;
+ ULONG Filter;
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+
+ //
+ // Get Oid and Length of request
+ //
+
+ Oid = NdisRequest->DATA.SET_INFORMATION.Oid;
+
+ OidLength = BytesLeft;
+
+ //
+ // Verify length
+ //
+
+ if (OidLength != 4){
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ return(StatusToReturn);
+ }
+
+ switch (Oid) {
+
+ case OID_802_5_CURRENT_FUNCTIONAL:
+
+ StatusToReturn = IbmtokChangeFunctionalAddress(
+ Adapter,
+ Open,
+ NdisRequest,
+ InfoBuffer
+ );
+
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ IBMTOK_MOVE_MEMORY(&Filter, InfoBuffer, 4);
+
+ StatusToReturn = IbmtokSetPacketFilter(Adapter,
+ Open,
+ NdisRequest,
+ Filter);
+
+ break;
+
+ case OID_802_5_CURRENT_GROUP:
+
+ StatusToReturn = IbmtokSetGroupAddress(
+ Adapter,
+ Open,
+ NdisRequest,
+ InfoBuffer
+ );
+
+ break;
+
+
+ case OID_GEN_PROTOCOL_OPTIONS:
+
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ IBMTOK_MOVE_MEMORY(&LookAhead, InfoBuffer, 4);
+
+ if (LookAhead <= IBMTOK_MAX_LOOKAHEAD) {
+
+ if (LookAhead > Adapter->LookAhead) {
+
+ Open->LookAhead = LookAhead;
+
+ Adapter->LookAhead = LookAhead;
+
+ } else {
+
+ if ((Open->LookAhead == Adapter->LookAhead) &&
+ (LookAhead < Open->LookAhead)) {
+
+ Open->LookAhead = LookAhead;
+
+ IbmtokAdjustMaxLookAhead(Adapter);
+
+ } else {
+
+ Open->LookAhead = LookAhead;
+
+ }
+
+ }
+
+ } else {
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ }
+
+ break;
+
+ default:
+
+ StatusToReturn = NDIS_STATUS_INVALID_OID;
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ break;
+ }
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS){
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = OidLength;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ }
+
+
+
+ return(StatusToReturn);
+}
+
+STATIC
+NDIS_STATUS
+IbmtokSetPacketFilter(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN PIBMTOK_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT PacketFilter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes the stages necessary to implement changing
+ the packets that a protocol receives from the MAC.
+
+Arguments:
+
+ Adapter - A pointer to the Adapter.
+
+ Open - A pointer to the open instance.
+
+ NdisRequest - A pointer to the request submitting the set command.
+
+ PacketFilter - A bit mask that contains flags that correspond to specific
+ classes of received packets. If a particular bit is set in the mask,
+ then packet reception for that class of packet is enabled. If the
+ bit is clear, then packets that fall into that class are not received
+ by the client. A single exception to this rule is that if the promiscuous
+ bit is set, then the client receives all packets on the network, regardless
+ of the state of the other flags.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+ //
+ // Keeps track of the *MAC's* status. The status will only be
+ // reset if the filter change action routine is called.
+ //
+ NDIS_STATUS StatusOfFilterChange = NDIS_STATUS_SUCCESS;
+
+ //
+ // Verify bits
+ //
+
+ if (PacketFilter & (NDIS_PACKET_TYPE_SOURCE_ROUTING |
+ NDIS_PACKET_TYPE_MULTICAST |
+ NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_ALL_MULTICAST |
+ NDIS_PACKET_TYPE_SMT |
+ NDIS_PACKET_TYPE_MAC_FRAME
+ )) {
+
+ return(NDIS_STATUS_NOT_SUPPORTED);
+
+ }
+
+ //
+ // Increment the open while it is going through the filtering
+ // routines.
+ //
+
+ Open->References++;
+
+ StatusOfFilterChange = TrFilterAdjust(
+ Adapter->FilterDB,
+ Open->NdisFilterHandle,
+ NdisRequest,
+ PacketFilter,
+ TRUE
+ );
+ Open->References--;
+
+ if (StatusOfFilterChange == NDIS_STATUS_PENDING) {
+
+ //
+ // If it pended, it will be in the pend
+ // queue so we should start that up.
+ //
+
+ IbmtokProcessSrbRequests(Adapter);
+
+ }
+
+ return StatusOfFilterChange;
+}
+
+STATIC
+NDIS_STATUS
+IbmtokChangeFunctionalAddress(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN PIBMTOK_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest,
+ IN PUCHAR Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes the stages necessary to implement changing
+ the packets that a protocol receives from the MAC.
+
+
+ Note: The spin lock must be held before entering this routine.
+
+Arguments:
+
+ Adapter - A pointer to the Adapter.
+
+ Open - A pointer to the open instance.
+
+ NdisRequest - A pointer to the request submitting the set command.
+
+ Address - The new functional address.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+ //
+ // Keeps track of the *MAC's* status. The status will only be
+ // reset if the address change action routine is called.
+ //
+ NDIS_STATUS StatusOfChange = NDIS_STATUS_SUCCESS;
+
+ //
+ // Increment the open while it is going through the filtering
+ // routines.
+ //
+
+ Open->References++;
+
+ StatusOfChange = TrChangeFunctionalAddress(
+ Open->OwningIbmtok->FilterDB,
+ Open->NdisFilterHandle,
+ NdisRequest,
+ Address,
+ TRUE
+ );
+
+ Open->References--;
+
+ if (StatusOfChange == NDIS_STATUS_PENDING) {
+
+ //
+ // If it pended, it will be in the pend
+ // queue so we should start that up.
+ //
+
+ IbmtokProcessSrbRequests(Adapter);
+
+ }
+
+ return StatusOfChange;
+}
+
+STATIC
+NDIS_STATUS
+IbmtokSetGroupAddress(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN PIBMTOK_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest,
+ IN PUCHAR Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes the stages necessary to implement changing
+ the packets that a protocol receives from the MAC.
+
+
+ Note: The spin lock must be held before entering this routine.
+
+Arguments:
+
+ Adapter - A pointer to the Adapter.
+
+ Open - A pointer to the open instance.
+
+ NdisRequest - A pointer to the request submitting the set command.
+
+ Address - The new group address.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+ //
+ // Keeps track of the *MAC's* status. The status will only be
+ // reset if the address change action routine is called.
+ //
+ NDIS_STATUS StatusOfChange = NDIS_STATUS_SUCCESS;
+
+ //
+ // Increment the open while it is going through the filtering
+ // routines.
+ //
+
+ Open->References++;
+
+ StatusOfChange = TrChangeGroupAddress(
+ Open->OwningIbmtok->FilterDB,
+ Open->NdisFilterHandle,
+ NdisRequest,
+ Address,
+ TRUE
+ );
+
+ Open->References--;
+
+ if (StatusOfChange == NDIS_STATUS_PENDING) {
+
+ //
+ // If it pended, it will be in the pend
+ // queue so we should start that up.
+ //
+
+ IbmtokProcessSrbRequests(Adapter);
+
+ }
+
+ return StatusOfChange;
+}
+
+NDIS_STATUS
+IbmtokFillInGlobalData(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ This routine completes a GlobalStatistics request. It is critical that
+ if information is needed from the Adapter->* fields, they have been
+ updated before this routine is called.
+
+Arguments:
+
+ Adapter - A pointer to the Adapter.
+
+ NdisRequest - A structure which contains the request type (Global
+ Query), an array of operations to perform, and an array for holding
+ the results of the operations.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ //
+ // General Algorithm:
+ //
+ // Switch(Request)
+ // Get requested information
+ // Store results in a common variable.
+ // default:
+ // Try protocol query information
+ // If that fails, fail query.
+ //
+ // Copy result in common variable to result buffer.
+ // Finish processing
+
+ UINT BytesWritten = 0;
+ UINT BytesNeeded = 0;
+ UINT BytesLeft = NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength;
+ PUCHAR InfoBuffer = (PUCHAR)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ //
+ // This variable holds result of query
+ //
+
+ ULONG GenericULong;
+ ULONG MoveBytes = sizeof(ULONG) * 2 + sizeof(NDIS_OID);
+
+
+ StatusToReturn = IbmtokQueryProtocolInformation(
+ Adapter,
+ NULL,
+ NdisRequest->DATA.QUERY_INFORMATION.Oid,
+ TRUE,
+ InfoBuffer,
+ BytesLeft,
+ &BytesNeeded,
+ &BytesWritten
+ );
+
+
+ if (StatusToReturn == NDIS_STATUS_NOT_SUPPORTED){
+
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ //
+ // Switch on request type
+ //
+
+ switch (NdisRequest->DATA.QUERY_INFORMATION.Oid) {
+
+ case OID_GEN_XMIT_OK:
+
+ GenericULong = (ULONG)(Adapter->FramesTransmitted);
+
+ break;
+
+ case OID_GEN_RCV_OK:
+
+ GenericULong = (ULONG)(Adapter->FramesReceived);
+
+ break;
+
+ case OID_GEN_XMIT_ERROR:
+
+ GenericULong = (ULONG)(Adapter->FrameTransmitErrors);
+
+ break;
+
+ case OID_GEN_RCV_ERROR:
+
+ GenericULong = (ULONG)(Adapter->FrameReceiveErrors);
+
+ break;
+
+ case OID_GEN_RCV_NO_BUFFER:
+
+ GenericULong = (ULONG)(Adapter->ReceiveCongestionCount);
+
+ break;
+
+ case OID_802_5_LINE_ERRORS:
+
+ GenericULong = (ULONG)(Adapter->LineErrors);
+
+ break;
+
+ case OID_802_5_LOST_FRAMES:
+
+ GenericULong = (ULONG)(Adapter->LostFrames);
+
+ break;
+
+ case OID_802_5_LAST_OPEN_STATUS:
+
+ GenericULong = (ULONG)(NDIS_STATUS_TOKEN_RING_OPEN_ERROR |
+ (NDIS_STATUS)(Adapter->OpenErrorCode));
+
+ break;
+
+ case OID_802_5_CURRENT_RING_STATUS:
+
+ GenericULong = (ULONG)(Adapter->LastNotifyStatus);
+
+ break;
+
+ case OID_802_5_CURRENT_RING_STATE:
+
+ GenericULong = (ULONG)(Adapter->CurrentRingState);
+
+ break;
+
+ default:
+
+ StatusToReturn = NDIS_STATUS_INVALID_OID;
+
+ break;
+
+ }
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS){
+
+ //
+ // Check to make sure there is enough room in the
+ // buffer to store the result.
+ //
+
+ if (BytesLeft >= sizeof(ULONG)) {
+
+ //
+ // Store the result.
+ //
+
+ IBMTOK_MOVE_MEMORY(
+ (PVOID)InfoBuffer,
+ (PVOID)(&GenericULong),
+ sizeof(ULONG)
+ );
+
+ BytesWritten += sizeof(ULONG);
+
+ } else {
+
+ BytesNeeded = sizeof(ULONG) - BytesLeft;
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ }
+
+ }
+
+ }
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesWritten = BytesWritten;
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = BytesNeeded;
+
+ return(StatusToReturn);
+}
+
+STATIC
+NDIS_STATUS
+IbmtokQueryGlobalStatistics(
+ IN NDIS_HANDLE MacAdapterContext,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ The IbmtokQueryGlobalStatistics is used by the protocol to query
+ global information about the MAC.
+
+Arguments:
+
+ MacAdapterContext - The value associated with the adapter that is being
+ opened when the MAC registered the adapter with NdisRegisterAdapter.
+
+ NdisRequest - A structure which contains the request type (Query),
+ an array of operations to perform, and an array for holding
+ the results of the operations.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+ //
+ // General Algorithm:
+ //
+ //
+ // Check if a request is going to pend...
+ // If so, pend the entire operation.
+ //
+ // Else
+ // Fill in the request block.
+ //
+ //
+
+ PIBMTOK_ADAPTER Adapter = PIBMTOK_ADAPTER_FROM_CONTEXT_HANDLE(MacAdapterContext);
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ //
+ // Check if a request is valid and going to pend...
+ // If so, pend the entire operation.
+ //
+
+ NdisInterlockedAddUlong((PULONG)&Adapter->References, 1 ,&(Adapter->Lock));
+
+ //
+ // Switch on request type
+ //
+
+ switch (NdisRequest->DATA.QUERY_INFORMATION.Oid) {
+ case OID_GEN_SUPPORTED_LIST:
+ case OID_GEN_HARDWARE_STATUS:
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+ case OID_GEN_MAC_OPTIONS:
+ case OID_GEN_LINK_SPEED:
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+ case OID_GEN_VENDOR_ID:
+ case OID_GEN_VENDOR_DESCRIPTION:
+ case OID_GEN_DRIVER_VERSION:
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ case OID_802_5_CURRENT_GROUP:
+ case OID_802_5_LAST_OPEN_STATUS:
+ case OID_802_5_CURRENT_RING_STATUS:
+ case OID_802_5_CURRENT_RING_STATE:
+ case OID_802_5_PERMANENT_ADDRESS:
+ case OID_802_5_CURRENT_ADDRESS:
+ case OID_802_5_CURRENT_FUNCTIONAL:
+ break;
+
+ case OID_GEN_XMIT_OK:
+ case OID_GEN_RCV_OK:
+ case OID_GEN_XMIT_ERROR:
+ case OID_GEN_RCV_ERROR:
+ case OID_GEN_RCV_NO_BUFFER:
+ case OID_802_5_LINE_ERRORS:
+ case OID_802_5_LOST_FRAMES:
+
+ StatusToReturn = NDIS_STATUS_PENDING;
+
+ break;
+
+ default:
+
+ StatusToReturn = NDIS_STATUS_INVALID_OID;
+
+ break;
+ }
+
+ if (StatusToReturn == NDIS_STATUS_PENDING) {
+
+ //
+ // Build a pending operation
+ //
+
+ PIBMTOK_PEND_DATA PendOp = PIBMTOK_PEND_DATA_FROM_PNDIS_REQUEST(NdisRequest);
+
+ PendOp->Next = NULL;
+ PendOp->COMMAND.NDIS.STATISTICS.ReadLogPending = FALSE;
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ if (Adapter->PendQueue == NULL){
+
+ Adapter->PendQueue = Adapter->EndOfPendQueue = PendOp;
+
+ } else {
+
+ Adapter->EndOfPendQueue->Next = PendOp;
+
+ }
+
+
+ //
+ // It is now in the pend
+ // queue so we should start that up.
+ //
+
+ IbmtokProcessSrbRequests(Adapter);
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ //
+ // Defer subtracting from Adapter->Reference until the
+ // request completes (see IbmtokFinishPendQueueOp()).
+ //
+
+ return(StatusToReturn);
+
+ }
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS){
+
+ StatusToReturn = IbmtokFillInGlobalData(Adapter, NdisRequest);
+
+ }
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ IBMTOK_DO_DEFERRED(Adapter);
+
+ return(StatusToReturn);
+}
+
+STATIC
+NDIS_STATUS
+IbmtokReset(
+ IN NDIS_HANDLE MacBindingHandle
+ )
+
+/*++
+
+Routine Description:
+
+ The IbmtokReset request instructs the MAC to issue a hardware reset
+ to the network adapter. The MAC also resets its software state. See
+ the description of NdisReset for a detailed description of this request.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to IBMTOK_OPEN.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+
+{
+
+ //
+ // Holds the status that should be returned to the caller.
+ //
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_PENDING;
+
+ PIBMTOK_ADAPTER Adapter =
+ PIBMTOK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ PIBMTOK_OPEN Open;
+
+ //
+ // Hold the locks while we update the reference counts on the
+ // adapter and the open.
+ //
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Open = PIBMTOK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ Adapter->References++;
+
+ if (Adapter->ResetInProgress) {
+
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ } else if (Adapter->AdapterNotOpen) {
+
+ StatusToReturn = NDIS_STATUS_FAILURE;
+
+ } else {
+
+ if (!Open->BindingShuttingDown) {
+
+ Open->References++;
+ IbmtokSetupForReset(
+ Adapter,
+ PIBMTOK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle)
+ );
+ Open->References--;
+
+ } else {
+
+ StatusToReturn = NDIS_STATUS_CLOSING;
+
+ }
+
+ }
+
+ //
+ // This macro assumes it is called with the lock held,
+ // and releases it.
+ //
+
+ IBMTOK_DO_DEFERRED(Adapter);
+ return StatusToReturn;
+
+}
+
+STATIC
+NDIS_STATUS
+IbmtokChangeFilter(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when a particular filter
+ class is first used or last cleared.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ OldFilterClasses - The values of the class filter before it
+ was changed.
+
+ NewFilterClasses - The current value of the class filter
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to IBMTOK_OPEN.
+
+ Set - If true the change resulted from a set, otherwise the
+ change resulted from a open closing.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+
+ PIBMTOK_ADAPTER Adapter = PIBMTOK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ //
+ // The open that made this request.
+ //
+ PIBMTOK_OPEN Open = PIBMTOK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ //
+ // Holds the change that should be returned to the filtering package.
+ //
+ NDIS_STATUS StatusOfChange;
+
+ if (NdisRequest == NULL) {
+
+ NdisRequest = &(Open->CloseRequestChangeFilter);
+
+ NdisRequest->RequestType = NdisRequestClose;
+
+
+ }
+
+
+ if (Adapter->ResetInProgress) {
+
+ StatusOfChange = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ } else {
+
+ //
+ // The whole purpose of this routine is to determine whether
+ // the filtering changes need to result in the hardware being
+ // reset.
+ //
+
+ ASSERT(OldFilterClasses != NewFilterClasses);
+
+#if DBG
+ if (IbmtokDbg) DbgPrint("IBMTOK: Change filter\n");
+#endif
+
+ if (NewFilterClasses &
+ (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_SOURCE_ROUTING)) {
+
+ //
+ // The adapter cannot support promiscuous mode, or
+ // source routing which implies promiscuous.
+ //
+
+ StatusOfChange = NDIS_STATUS_FAILURE;
+
+ } else {
+
+ //
+ // Queue this request.
+ //
+
+ PIBMTOK_PEND_DATA PendOp = PIBMTOK_PEND_DATA_FROM_PNDIS_REQUEST(NdisRequest);
+
+ //
+ // Store open block.
+ //
+
+ PendOp->COMMAND.NDIS.SET_FILTER.Open = Open;
+
+ //
+ // Hold new Filter value
+ //
+
+ if (PendOp->RequestType == NdisRequestClose){
+
+ PendOp->COMMAND.NDIS.CLOSE.NewFilterValue = NewFilterClasses;
+
+ } else {
+
+ PendOp->COMMAND.NDIS.SET_FILTER.NewFilterValue = NewFilterClasses;
+
+ }
+
+
+ //
+ // Insert into queue.
+ //
+
+ PendOp->Next = NULL;
+
+ if (Adapter->PendQueue == NULL) {
+
+ Adapter->PendQueue = Adapter->EndOfPendQueue = PendOp;
+
+ } else {
+
+ Adapter->EndOfPendQueue->Next = PendOp;
+
+ }
+
+ Open->References++;
+
+ StatusOfChange = NDIS_STATUS_PENDING;
+
+
+ }
+
+ }
+
+ return StatusOfChange;
+
+}
+
+STATIC
+NDIS_STATUS
+IbmtokChangeAddress(
+ IN TR_FUNCTIONAL_ADDRESS OldFunctionalAddress,
+ IN TR_FUNCTIONAL_ADDRESS NewFunctionalAddress,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when an address is added to
+ the filter that wasn't referenced by any other open binding.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ OldFunctionalAddress - The previous functional address.
+
+ NewFunctionalAddress - The new functional address.
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to IBMTOK_OPEN.
+
+ NdisRequest - A pointer to the Request that submitted the set command.
+
+ Set - If true the change resulted from a set, otherwise the
+ change resulted from a open closing.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+
+ PIBMTOK_ADAPTER Adapter = PIBMTOK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ //
+ // Holds the status that should be returned to the filtering package.
+ //
+ NDIS_STATUS StatusOfChange;
+
+ //
+ // The open that made this request.
+ //
+ PIBMTOK_OPEN Open = PIBMTOK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+#if DBG
+ if (IbmtokDbg) {
+ DbgPrint("IBMTOK: Queueing:\n");
+ DbgPrint(" Req : 0x%x\n", NdisRequest);
+ DbgPrint(" Old : 0x%x\n", OldFunctionalAddress);
+ DbgPrint(" New : 0x%x\n", NewFunctionalAddress);
+ }
+#endif
+
+ // Check to see if the device is already resetting. If it is
+ // then reject this change.
+ //
+
+ if (NdisRequest == NULL) {
+
+ NdisRequest = &(Open->CloseRequestChangeAddress);
+
+ NdisRequest->RequestType = NdisRequestGeneric2; // Close, set address
+
+ }
+
+
+ if (Adapter->ResetInProgress) {
+
+#if DBG
+ if (IbmtokDbg) {
+ DbgPrint("IBMTOK: ResetInProgress\n\n");
+ }
+#endif
+
+ StatusOfChange = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ } else {
+
+ //
+ // Queue this request.
+ //
+
+ PIBMTOK_PEND_DATA PendOp = PIBMTOK_PEND_DATA_FROM_PNDIS_REQUEST(NdisRequest);
+
+
+ //
+ // Store open block.
+ //
+
+ PendOp->COMMAND.NDIS.SET_ADDRESS.Open = Open;
+
+ //
+ // Hold new Address value
+ //
+
+ PendOp->COMMAND.NDIS.SET_ADDRESS.NewAddressValue = NewFunctionalAddress;
+
+
+ //
+ // Insert into queue.
+ //
+
+ PendOp->Next = NULL;
+
+ if (Adapter->PendQueue == NULL) {
+
+ Adapter->PendQueue = Adapter->EndOfPendQueue = PendOp;
+
+ } else {
+
+ Adapter->EndOfPendQueue->Next = PendOp;
+
+ }
+
+ Open->References++;
+
+ StatusOfChange = NDIS_STATUS_PENDING;
+
+ }
+
+ return StatusOfChange;
+
+}
+
+STATIC
+NDIS_STATUS
+IbmtokChangeGroupAddress(
+ IN TR_FUNCTIONAL_ADDRESS OldGroupAddress,
+ IN TR_FUNCTIONAL_ADDRESS NewGroupAddress,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when a group address is to
+ be changed.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ OldGroupAddress - The previous group address.
+
+ NewGroupAddress - The new group address.
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to IBMTOK_OPEN.
+
+ NdisRequest - A pointer to the Request that submitted the set command.
+
+ Set - If true the change resulted from a set, otherwise the
+ change resulted from a open closing.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+
+ PIBMTOK_ADAPTER Adapter = PIBMTOK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ //
+ // Holds the status that should be returned to the filtering package.
+ //
+ NDIS_STATUS StatusOfChange;
+
+ //
+ // The open that made this request.
+ //
+ PIBMTOK_OPEN Open = PIBMTOK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+
+ if (NdisRequest == NULL) {
+
+ NdisRequest = &(Open->CloseRequestChangeGroupAddress);
+
+ NdisRequest->RequestType = NdisRequestGeneric3; // Close, set group address
+
+ }
+
+
+ //
+ // Check to see if the device is already resetting. If it is
+ // then reject this change.
+ //
+
+ if (Adapter->ResetInProgress) {
+
+ StatusOfChange = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ } else {
+
+ //
+ // Queue this request.
+ //
+
+ PIBMTOK_PEND_DATA PendOp = PIBMTOK_PEND_DATA_FROM_PNDIS_REQUEST(NdisRequest);
+
+
+ //
+ // Store open block.
+ //
+
+ PendOp->COMMAND.NDIS.SET_ADDRESS.Open = Open;
+
+ //
+ // Hold new Address value
+ //
+
+ PendOp->COMMAND.NDIS.SET_ADDRESS.NewAddressValue = NewGroupAddress;
+
+
+ //
+ // Insert into queue.
+ //
+
+ PendOp->Next = NULL;
+
+ if (Adapter->PendQueue == NULL) {
+
+ Adapter->PendQueue = Adapter->EndOfPendQueue = PendOp;
+
+ } else {
+
+ Adapter->EndOfPendQueue->Next = PendOp;
+
+ }
+
+ Open->References++;
+
+ StatusOfChange = NDIS_STATUS_PENDING;
+
+ }
+
+ return StatusOfChange;
+
+}
+
+STATIC
+VOID
+IbmtokCloseAction(
+ IN NDIS_HANDLE MacBindingHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when a particular binding
+ was closed while it was indicating through NdisIndicateReceive
+
+ All this routine needs to do is to decrement the reference count
+ of the binding.
+
+ NOTE: This routine assumes that it is called with the lock acquired.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to IBMTOK_OPEN.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+
+ PIBMTOK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle)->References--;
+
+}
+
+extern
+VOID
+IbmtokStartAdapterReset(
+ IN PIBMTOK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This is the first phase of resetting the adapter hardware.
+
+ It makes the following assumptions:
+
+ 1) That the hardware has been stopped.
+
+ 2) That it can not be preempted.
+
+ 3) That no other adapter activity can occur.
+
+ When this routine is finished all of the adapter information
+ will be as if the driver was just initialized.
+
+Arguments:
+
+ Adapter - The adapter whose hardware is to be reset.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ //
+ // Disable these so no pending interrupts
+ // will fire.
+ //
+ CLEAR_ISRP_BITS(Adapter);
+
+ //
+ // OK, do the reset as detailed in the Tech Ref...
+ //
+
+ WRITE_ADAPTER_PORT(Adapter, RESET_LATCH, 0);
+
+ NdisStallExecution(50000);
+
+ WRITE_ADAPTER_PORT(Adapter, RESET_RELEASE, 0);
+
+ //
+ // Have to write this now to enable Shared RAM paging.
+ //
+ if (Adapter->SharedRamPaging) {
+
+ WRITE_ADAPTER_REGISTER(Adapter, SRPR_LOW, 0xc0);
+
+ }
+
+
+ if (Adapter->CardType == IBM_TOKEN_RING_PCMCIA)
+ {
+ UINT Nibble0;
+ UINT Nibble1;
+ UINT Nibble2;
+ UINT Nibble3;
+ ULONG MmioAddress;
+
+ //
+ // Configure the card to match registry
+ // Use the Default MMIO value here (this never changes from system to system)
+ //
+ MmioAddress = Adapter->MmioAddress;
+
+ //
+ // Nibble 0 - ROM address
+ //
+ Nibble0 = NIBBLE_0 | ((UINT)(MmioAddress >> 16 ) & 0x0F);
+
+ //
+ // Nibble 1 - ROM address, INT 0
+ //
+ Nibble1 = NIBBLE_1 | ((UINT)(MmioAddress >> 12) & 0x0F);
+
+ //
+ // Nibble 2 - INT1, F ROS, SRAM, S RST
+ //
+ Nibble2 = NIBBLE_2 | DEFAULT_NIBBLE_2;
+
+ //
+ // Nibble 3 - Ring Speed, RAM size, Prim/Alt
+ //
+ Nibble3 = NIBBLE_3;
+
+ if (Adapter->RingSpeed == 16)
+ {
+ Nibble3 |= RING_SPEED_16_MPS;
+ }
+ else
+ {
+ Nibble3 |= RING_SPEED_4_MPS;
+ }
+
+ switch (Adapter->RamSize)
+ {
+ case 0x10000:
+ Nibble3 |= SHARED_RAM_64K;
+ break;
+
+ case 0x8000:
+ Nibble3 |= SHARED_RAM_32K;
+ break;
+
+ case 0x4000:
+ Nibble3 |= SHARED_RAM_16K;
+ break;
+
+ case 0x2000:
+ Nibble3 |= SHARED_RAM_8K;
+ break;
+ }
+
+ // if ( Adapter->IbmtokPortAddress == PRIMARY_ADAPTER_OFFSET)
+ // {
+ // Nibble3 |= PRIMARY;
+ // }
+ // else
+ // {
+ // Nibble3 |= ALTERNATE;
+ // }
+
+ //
+ // Write everything to the Token-Ring Controller Configuration Register
+ //
+ WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_2, Nibble0);
+ WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_1, Nibble0);
+
+ WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_2, Nibble1);
+ WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_1, Nibble1);
+
+ WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_2, Nibble2);
+ WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_1, Nibble2);
+
+ WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_2, Nibble3);
+ WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_1, Nibble3);
+
+ WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_2, RELEASE_TR_CONTROLLER);
+ WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_1, RELEASE_TR_CONTROLLER);
+
+ WRITE_ADAPTER_REGISTER(Adapter, RRR_LOW, Adapter->RrrLowValue);
+ }
+ else if (Adapter->UsingPcIoBus)
+ {
+ //
+ // If this is a PC I/O Bus....
+ // Set up the shared RAM to be right after the MMIO.
+ //
+ WRITE_ADAPTER_REGISTER(Adapter, RRR_LOW, Adapter->RrrLowValue);
+ }
+
+
+ //
+ // Allow the reset complete interrupt to be
+ // serviced correctly.
+ //
+ if (Adapter->CardType != IBM_TOKEN_RING_PCMCIA)
+ {
+ SET_INTERRUPT_RESET_FLAG(Adapter);
+ }
+ else
+ {
+ UCHAR Temp;
+
+ //
+ // disable interrupts on the card,
+ // since we don't trust ndissyncint to work
+ //
+ READ_ADAPTER_REGISTER(Adapter, ISRP_LOW, &Temp);
+
+ WRITE_ADAPTER_REGISTER(
+ Adapter,
+ ISRP_LOW,
+ (UCHAR)(Temp & (~(ISRP_LOW_NO_CHANNEL_CHECK | ISRP_LOW_INTERRUPT_ENABLE)))
+ );
+
+ //
+ // Set the reset flag
+ //
+ Adapter->ResetInterruptAllowed = TRUE;
+
+ //
+ // reenable interrupts on the card
+ //
+ WRITE_ADAPTER_REGISTER(
+ Adapter,
+ ISRP_LOW,
+ ISRP_LOW_NO_CHANNEL_CHECK | ISRP_LOW_INTERRUPT_ENABLE
+ );
+ }
+
+ //
+ // Enable card interrupts to get the reset interrupt.
+ //
+
+ WRITE_ADAPTER_REGISTER(Adapter, ISRP_LOW,
+ ISRP_LOW_NO_CHANNEL_CHECK | ISRP_LOW_INTERRUPT_ENABLE);
+
+
+ //
+ // The remaining processing is done in the
+ // interrupt handler.
+ //
+
+
+
+ //
+ // OK, now abort pending requests before we nuke
+ // everything.
+ //
+
+ NdisDprAcquireSpinLock (&Adapter->Lock);
+
+ IbmtokAbortSends (Adapter, NDIS_STATUS_REQUEST_ABORTED);
+
+ NdisDprReleaseSpinLock (&Adapter->Lock);
+
+}
+
+extern
+VOID
+IbmtokFinishAdapterReset(
+ IN PIBMTOK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Called by HandleResetStaging when the last piece
+ of the adapter reset is complete and normal
+ operation can resume.
+
+ Called with the lock held and returns with it held.
+
+Arguments:
+
+ Adapter - The adapter that the reset is for.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY CurrentLink;
+ PIBMTOK_OPEN TempOpen;
+
+
+ SetResetVariables(Adapter);
+
+ if (Adapter->UnpluggedResetInProgress) {
+ Adapter->UnpluggedResetInProgress = FALSE;
+ Adapter->Unplugged = FALSE;
+ Adapter->LobeWireFaultIndicated = FALSE;
+ }
+
+ Adapter->ResetInProgress = FALSE;
+ Adapter->ResetInterruptAllowed = FALSE;
+ Adapter->ResetInterruptHasArrived = FALSE;
+ Adapter->NotAcceptingRequests = FALSE;
+
+ //
+ // Get any interrupts that have been deferred
+ // while NotAcceptingRequests was TRUE.
+ //
+ IbmtokForceAdapterInterrupt(Adapter);
+
+ if (Adapter->ResettingOpen != NULL) {
+
+ PIBMTOK_OPEN ResettingOpen = Adapter->ResettingOpen;
+
+ //
+ // Indicate reset complete to everybody
+ //
+
+ CurrentLink = Adapter->OpenBindings.Flink;
+
+ while (CurrentLink != &(Adapter->OpenBindings)){
+
+ TempOpen = CONTAINING_RECORD(
+ CurrentLink,
+ IBMTOK_OPEN,
+ OpenList
+ );
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisIndicateStatus(TempOpen->NdisBindingContext,
+ NDIS_STATUS_RESET_END,
+ NULL,
+ 0
+ );
+
+ NdisIndicateStatusComplete(TempOpen->NdisBindingContext);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ CurrentLink = CurrentLink->Flink;
+
+ }
+
+ //
+ // Decrement the reference count that was incremented
+ // in SetupForReset.
+ //
+ ResettingOpen->References--;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteReset(
+ ResettingOpen->NdisBindingContext,
+ NDIS_STATUS_SUCCESS
+ );
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ }
+
+}
+
+#pragma NDIS_INIT_FUNCTION(IbmtokSetupRegistersAndInit)
+
+STATIC
+VOID
+IbmtokSetupRegistersAndInit(
+ IN PIBMTOK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ It is this routines responsibility to make sure that the
+ initialization block is filled and the chip is initialized
+ *but not* started.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired OR that only a single thread of execution is working
+ with this particular adapter.
+
+Arguments:
+
+ Adapter - The adapter whose hardware is to be initialized.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ //
+ // Enable card interrupts to get the reset interrupt.
+ //
+
+ WRITE_ADAPTER_REGISTER(Adapter, ISRP_LOW,
+ ISRP_LOW_NO_CHANNEL_CHECK | ISRP_LOW_INTERRUPT_ENABLE);
+
+ //
+ // Set the timer to 10 milliseconds...this seems to
+ // be necessary for proper operation (according to
+ // ChandanC).
+ //
+
+ WRITE_ADAPTER_REGISTER(Adapter, TVR_HIGH, 0x01);
+
+
+ //
+ // Start the timer and set it to reload, but not to
+ // interrupt us (TCR_LOW_INTERRUPT_MASK is off). This
+ // will still cause bit 4 in the ISRP Low to go on,
+ // but it won't cause an interrupt.
+ //
+
+#if 0
+ WRITE_ADAPTER_REGISTER(Adapter, TCR_LOW,
+// TCR_LOW_INTERRUPT_MASK |
+ TCR_LOW_RELOAD_TIMER | TCR_LOW_COUNTER_ENABLE);
+#endif
+ WRITE_ADAPTER_REGISTER(Adapter, TCR_LOW, 0);
+
+
+
+ //
+ // If this is a PC I/O Bus...
+ // Set up the shared RAM to be right after the MMIO.
+ //
+
+ if (Adapter->UsingPcIoBus)
+ {
+ WRITE_ADAPTER_REGISTER(Adapter, RRR_LOW, Adapter->RrrLowValue);
+ }
+ else if (Adapter->CardType == IBM_TOKEN_RING_PCMCIA)
+ {
+ WRITE_ADAPTER_REGISTER(Adapter, RRR_LOW, (UCHAR)(Adapter->Ram >> 12));
+ }
+
+
+ //
+ // The remaining initialization processing is done in
+ // the interrupt handler.
+ //
+
+}
+
+
+STATIC
+VOID
+IbmtokSetupForReset(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN PIBMTOK_OPEN Open
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to fill in the who and why a reset is
+ being set up as well as setting the appropriate fields in the
+ adapter.
+
+ NOTE: This routine must be called with the lock acquired.
+
+Arguments:
+
+ Adapter - The adapter whose hardware is to be initialized.
+
+ Open - A (possibly NULL) pointer to an sonic open structure.
+ The reason it could be null is if the adapter is initiating the
+ reset on its own.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Notify of reset start
+ //
+
+ PLIST_ENTRY CurrentLink;
+ PIBMTOK_OPEN TempOpen;
+
+ if (Open != NULL) {
+
+ CurrentLink = Adapter->OpenBindings.Flink;
+
+ while (CurrentLink != &(Adapter->OpenBindings)){
+
+ TempOpen = CONTAINING_RECORD(
+ CurrentLink,
+ IBMTOK_OPEN,
+ OpenList
+ );
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisIndicateStatus(TempOpen->NdisBindingContext,
+ NDIS_STATUS_RESET_START,
+ NULL,
+ 0
+ );
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ CurrentLink = CurrentLink->Flink;
+
+ }
+ }
+
+
+ Adapter->ResetInProgress = TRUE;
+ Adapter->NotAcceptingRequests = TRUE;
+
+ Adapter->ResettingOpen = Open;
+
+ //
+ // This will go to 1 when StartAdapterReset is called.
+ //
+ Adapter->CurrentResetStage = 0;
+
+ //
+ // If there is a valid open we should up the reference count
+ // so that the open can't be deleted before we indicate that
+ // their request is finished.
+ //
+
+ if (Open != NULL) {
+
+ Open->References++;
+
+ }
+
+}
+
+
+#pragma NDIS_INIT_FUNCTION(IbmtokAddAdapter)
+
+NDIS_STATUS
+IbmtokAddAdapter(
+ IN NDIS_HANDLE MacMacContext,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING AdapterName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to initialize each adapter card/chip.
+
+Arguments:
+
+ see NDIS 3.0 spec...
+
+Return Value:
+
+
+ NDIS_STATUS_SUCCESS - Adapter was successfully added.
+ NDIS_STATUS_FAILURE - Adapter was not added, also MAC deregistered.
+
+--*/
+
+{
+ PIBMTOK_ADAPTER Adapter;
+
+ NDIS_HANDLE ConfigHandle;
+ PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
+ NDIS_STRING CardTypeStr = NDIS_STRING_CONST("CardType");
+ NDIS_STRING BusTypeStr = NDIS_STRING_CONST("BusType");
+ NDIS_STRING IOAddressStr = IOADDRESS;
+ NDIS_STRING NetworkAddressStr = NETWORK_ADDRESS;
+ NDIS_STRING PacketSizeStr = MAXPACKETSIZE;
+ NDIS_STRING TokenReleaseStr = TOKEN_RELEASE;
+
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ BOOLEAN PrimaryAdapter = TRUE;
+ BOOLEAN ConfigError = FALSE;
+ BOOLEAN McaCard = FALSE;
+
+ UINT SlotNumber;
+ NDIS_MCA_POS_DATA McaData;
+
+ PVOID NetAddress;
+ ULONG Length;
+
+ //
+ // Allocate the Adapter block.
+ //
+
+ if (IBMTOK_ALLOC_PHYS(&Adapter, sizeof(IBMTOK_ADAPTER)) !=
+ NDIS_STATUS_SUCCESS
+ )
+ {
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ IBMTOK_ZERO_MEMORY(Adapter, sizeof(IBMTOK_ADAPTER));
+
+ Adapter->MaxTransmittablePacket = 17960;
+ Adapter->CurrentRingState = NdisRingStateClosed;
+
+ Adapter->NdisMacHandle = ((PIBMTOK_MAC)MacMacContext)->NdisMacHandle;
+
+ NdisOpenConfiguration(
+ &Status,
+ &ConfigHandle,
+ ConfigurationHandle
+ );
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ IBMTOK_FREE_PHYS(Adapter, sizeof(IBMTOK_ADAPTER));
+
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // Determine the type of the card;
+ // IBM_TOKEN_RING_ISA, IBM_TOKEN_RING_PCMCIA.
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &CardTypeStr,
+ NdisParameterInteger
+ );
+ if (NDIS_STATUS_SUCCESS == Status)
+ Adapter->CardType = (UINT)ReturnedValue->ParameterData.IntegerData;
+
+ //
+ // Read Bus Type
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &BusTypeStr,
+ NdisParameterHexInteger
+ );
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ if (ReturnedValue->ParameterData.IntegerData ==
+ (ULONG)NdisInterfaceMca)
+ {
+ McaCard = TRUE;
+ }
+ }
+
+ //
+ // Get I/O Address
+ //
+
+ if (McaCard)
+ {
+ //
+ // Get I/O Address from Mca Pos info.
+ //
+ NdisReadMcaPosInformation(
+ &Status,
+ ConfigurationHandle,
+ &SlotNumber,
+ &McaData
+ );
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ ConfigError = TRUE;
+ goto RegisterAdapter;
+ }
+
+ //
+ // Now interperet the data
+ //
+ switch (McaData.PosData2 & 0x1)
+ {
+ case 0x00:
+ Adapter->IbmtokPortAddress = PRIMARY_ADAPTER_OFFSET;
+ break;
+
+ case 0x01:
+ Adapter->IbmtokPortAddress = ALTERNATE_ADAPTER_OFFSET;
+ break;
+
+ }
+ }
+ else if (IBM_TOKEN_RING_PCMCIA == Adapter->CardType)
+ {
+ //
+ // Read I/O Address.
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &IOAddressStr,
+ NdisParameterHexInteger
+ );
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ Adapter->IbmtokPortAddress =
+ (ULONG)ReturnedValue->ParameterData.IntegerData;
+ }
+ }
+ else
+ {
+ //
+ // Read I/O Address
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &IOAddressStr,
+ NdisParameterInteger
+ );
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ PrimaryAdapter =
+ (ReturnedValue->ParameterData.IntegerData == 1) ? TRUE : FALSE;
+ }
+
+ if (PrimaryAdapter)
+ {
+ Adapter->IbmtokPortAddress = PRIMARY_ADAPTER_OFFSET;
+ }
+ else
+ {
+ Adapter->IbmtokPortAddress = ALTERNATE_ADAPTER_OFFSET;
+ }
+ }
+
+ // if IBM_TOKEN_RING_16_4_CREDIT_CARD_ADAPTER, read in bunch of stuff
+ // like mmio, ringspeed, interrupt, ramsize, so we can set the card to match
+ //
+ if (IBM_TOKEN_RING_PCMCIA == Adapter->CardType)
+ {
+ // The following strings were changed to match the correct Registry entries
+
+ // NDIS_STRING AttributeAddressStr1 = NDIS_STRING_CONST("PCCARDAttributeMemoryAddress");
+ // NDIS_STRING AttributeAddressStr2 = NDIS_STRING_CONST("PCCARDAttributeMemoryAddress_1");
+ // NDIS_STRING AttributeSizeStr1 = NDIS_STRING_CONST("PCCARDAttributeMemorySize");
+ // NDIS_STRING AttributeSizeStr2 = NDIS_STRING_CONST("PCCARDAttributeMemorySize_1");
+
+ NDIS_STRING AttributeAddressStr1 = NDIS_STRING_CONST("MemoryMappedBaseAddress");
+ NDIS_STRING AttributeAddressStr2 = NDIS_STRING_CONST("MemoryMappedBaseAddress_1");
+ NDIS_STRING AttributeSizeStr1 = NDIS_STRING_CONST("MemoryMappedSize");
+ NDIS_STRING AttributeSizeStr2 = NDIS_STRING_CONST("MemoryMappedSize_1");
+ NDIS_STRING RingSpeedStr = NDIS_STRING_CONST("RingSpeed");
+ NDIS_STRING InterruptNumberStr = NDIS_STRING_CONST("InterruptNumber");
+ NDIS_STRING AutoRingSpeedStr = NDIS_STRING_CONST("AutoRingSpeed");
+ ULONG BaseAddress;
+ ULONG Size;
+
+ //
+ // Get the memory mapped I/O attribute window.
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &AttributeAddressStr1,
+ NdisParameterInteger
+ );
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ //
+ // Save the memory mapped io base address.
+ //
+ BaseAddress = (ULONG)ReturnedValue->ParameterData.IntegerData;
+ }
+ else
+ {
+ //
+ // BAD BAD BAD
+ //
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
+ 1,
+ 0x11111111
+ );
+
+ ConfigError = TRUE;
+ goto RegisterAdapter;
+ }
+
+ //
+ // Get the size of the memory mapped I/O attribute window.
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &AttributeSizeStr1,
+ NdisParameterInteger
+ );
+
+ //
+ // Save the size of the memory mapped io space.
+ //
+ Size = (ULONG)ReturnedValue->ParameterData.IntegerData;
+
+ if ((Status != NDIS_STATUS_SUCCESS) || (Size != 0x2000))
+ {
+ //
+ // BAD BAD BAD
+ //
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
+ 1,
+ 0x22222222
+ );
+
+ ConfigError = TRUE;
+ goto RegisterAdapter;
+ }
+
+ //
+ // Save the memory mapped address in the adapter block.
+ //
+ Adapter->MmioAddress = BaseAddress;
+
+ //
+ // Get the shared ram attribute window.
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &AttributeAddressStr2,
+ NdisParameterInteger
+ );
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ BaseAddress = (ULONG)ReturnedValue->ParameterData.IntegerData;
+ }
+ else
+ {
+ //
+ // BAD BAD BAD
+ //
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
+ 1,
+ 0x33333333
+ );
+
+ ConfigError = TRUE;
+ goto RegisterAdapter;
+ }
+
+ //
+ // Get the size of the shared ram attribute window.
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &AttributeSizeStr2,
+ NdisParameterInteger
+ );
+
+ Size = (ULONG)ReturnedValue->ParameterData.IntegerData;
+
+ if ((Status != NDIS_STATUS_SUCCESS) ||
+ ((Size != 0x2000) && (Size != 0x4000) &&
+ (Size != 0x8000) && (Size != 0x10000))
+ )
+ {
+ //
+ // BAD BAD BAD
+ //
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
+ 1,
+ 0x44444444
+ );
+
+ ConfigError = TRUE;
+ goto RegisterAdapter;
+ }
+
+ Adapter->RamSize = Size;
+ Adapter->Ram = BaseAddress;
+
+ //
+ // Find out ring speed
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &RingSpeedStr,
+ NdisParameterInteger
+ );
+ if (NDIS_STATUS_SUCCESS == Status)
+ Adapter->RingSpeed = ReturnedValue->ParameterData.IntegerData;
+
+ //
+ // Determine if Ring Speed Listen is desired BEM PCMCIA card
+ //
+
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &AutoRingSpeedStr,
+ NdisParameterInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ Adapter->RingSpeedListen = (BOOLEAN) ReturnedValue->ParameterData.IntegerData;
+
+ }
+
+ //
+ // Get the interrupt level.
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &InterruptNumberStr,
+ NdisParameterInteger
+ );
+ if (NDIS_STATUS_SUCCESS == Status)
+ Adapter->InterruptLevel = ReturnedValue->ParameterData.IntegerData;
+
+#if DBG
+ if (IbmtokDbg)
+ {
+ DbgPrint("MMIO = %x\n", Adapter->MmioAddress);
+ DbgPrint("RAM = %x\n",Adapter->Ram);
+ DbgPrint("RAMSIZE = %x\n", Adapter->RamSize);
+ DbgPrint("RINGSPEED = %d\n", Adapter->RingSpeed);
+ DbgPrint("IO Base = %x\n", Adapter->IbmtokPortAddress);
+ DbgPrint("INT = %x\n", Adapter->InterruptLevel);
+ }
+#endif
+ }
+
+ //
+ // Read PacketSize
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &PacketSizeStr,
+ NdisParameterInteger
+ );
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ Adapter->MaxTransmittablePacket =
+ ReturnedValue->ParameterData.IntegerData;
+ }
+
+ //
+ // Read net address
+ //
+ NdisReadNetworkAddress(
+ &Status,
+ &NetAddress,
+ &Length,
+ ConfigHandle
+ );
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (Length == TR_LENGTH_OF_ADDRESS)
+ {
+ TR_COPY_NETWORK_ADDRESS(
+ Adapter->NetworkAddress,
+ NetAddress
+ );
+ }
+ else if (Length != 0)
+ {
+ ConfigError = TRUE;
+ goto RegisterAdapter;
+ }
+ }
+
+ //
+ // Read token release
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &TokenReleaseStr,
+ NdisParameterInteger
+ );
+
+ Adapter->EarlyTokenRelease = TRUE;
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (ReturnedValue->ParameterData.IntegerData == 0)
+ {
+ Adapter->EarlyTokenRelease = FALSE;
+ }
+ }
+
+RegisterAdapter:
+
+ NdisCloseConfiguration(ConfigHandle);
+
+ Status = IbmtokRegisterAdapter(
+ Adapter,
+ ConfigurationHandle,
+ AdapterName,
+ McaCard,
+ ConfigError
+ );
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ IBMTOK_FREE_PHYS(Adapter, sizeof(IBMTOK_ADAPTER));
+ }
+
+ return(Status);
+}
+
+
+
+VOID
+IbmtokRemoveAdapter(
+ IN PVOID MacAdapterContext
+ )
+
+
+/*++
+
+Routine Description:
+
+ This routine is called when an adapter is to be removed.
+
+Arguments:
+
+ MacAdapterContext - Pointer to global list of adapter blocks.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PIBMTOK_ADAPTER Adapter;
+ BOOLEAN Canceled;
+
+ Adapter = PIBMTOK_ADAPTER_FROM_CONTEXT_HANDLE(MacAdapterContext);
+
+ //
+ // There are no opens left, so remove ourselves.
+ //
+
+ NdisDeregisterAdapterShutdownHandler(Adapter->NdisAdapterHandle);
+
+ NdisCancelTimer(&Adapter->WakeUpTimer, &Canceled);
+
+ if ( !Canceled ) {
+
+ NdisStallExecution(500000);
+ }
+
+ NdisRemoveInterrupt(&(Adapter->Interrupt));
+
+ NdisUnmapIoSpace(Adapter->NdisAdapterHandle,
+ Adapter->SharedRam,
+ (Adapter->MappedSharedRam == 0x10000) ?
+ 0x8000 :
+ Adapter->MappedSharedRam
+ );
+
+ TrDeleteFilter(Adapter->FilterDB);
+
+ NdisFreeSpinLock(&Adapter->Lock);
+
+ NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
+
+ IBMTOK_FREE_PHYS(Adapter, sizeof(IBMTOK_ADAPTER));
+
+ return;
+
+}
+
+
+VOID
+IbmtokShutdown(
+ IN PVOID ShutdownContext
+ )
+
+/*++
+
+Routine Description:
+
+ Turns off the card during a powerdown of the system.
+
+Arguments:
+
+ ShutdownContext - Really a pointer to the adapter structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIBMTOK_ADAPTER Adapter = (PIBMTOK_ADAPTER)(ShutdownContext);
+
+ //
+ // Set the flag
+ //
+
+ Adapter->NotAcceptingRequests = TRUE;
+
+ //
+ // Shutdown the card gracefully if we can, else submit a reset to remove it.
+ //
+
+ if ((Adapter->SrbAvailable) && (Adapter->SrbAddress != 0)) {
+
+ PSRB_CLOSE_ADAPTER CloseSrb = (PSRB_CLOSE_ADAPTER)Adapter->SrbAddress;
+
+ //
+ // Mask off all interrupts
+ //
+ WRITE_ADAPTER_REGISTER(Adapter, ISRP_LOW, ISRP_LOW_NO_CHANNEL_CHECK);
+
+ //
+ // Fill in the SRB for the close.
+ //
+
+ IBMTOK_ZERO_MAPPED_MEMORY(CloseSrb, sizeof(SRB_CLOSE_ADAPTER));
+
+ NdisWriteRegisterUchar((PUCHAR)&CloseSrb->Command, SRB_CMD_CLOSE_ADAPTER);
+
+ WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET, ISRA_HIGH_COMMAND_IN_SRB);
+
+ } else {
+
+ //
+ // Set the reset latch and leave it. This should turn the card
+ // off and it will be removed from the ring, but is not as graceful
+ // as actually removing ourselves as above.
+ //
+
+ WRITE_ADAPTER_PORT(Adapter, RESET_LATCH, 0);
+
+ }
+}
+
+
+VOID
+IbmtokUnload(
+ IN NDIS_HANDLE MacMacContext
+ )
+
+/*++
+
+Routine Description:
+
+ IbmtokUnload is called when the MAC is to unload itself.
+
+Arguments:
+
+ MacMacContext - nothing.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS InitStatus;
+
+ UNREFERENCED_PARAMETER(MacMacContext);
+
+ NdisDeregisterMac(
+ &InitStatus,
+ ((PIBMTOK_MAC)MacMacContext)->NdisMacHandle
+ );
+
+ NdisTerminateWrapper(
+ ((PIBMTOK_MAC)MacMacContext)->NdisWrapperHandle,
+ NULL
+ );
+
+ return;
+}
+
+#pragma NDIS_INIT_FUNCTION(IbmtokHardwareDetails)
+
+STATIC
+BOOLEAN
+IbmtokHardwareDetails(
+ IN PIBMTOK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine gets the MMIO address and interrupt level.
+ It also maps the MMIO and Shared RAM.
+
+Arguments:
+
+ Adapter - Where to store the network address.
+
+Return Value:
+
+ TRUE if successful.
+
+--*/
+
+{
+
+ NDIS_STATUS Status;
+
+ //
+ // Holds the value read from the SWITCH_READ_1 port.
+ //
+ UCHAR SwitchRead1;
+
+ //
+ // Holds the value read from the SWITCH_READ_2 port in
+ // the Microchannel Bus.
+ //
+ UCHAR SwitchRead2;
+
+ //
+ // Holds the physical address of the MMIO region.
+ //
+ ULONG MmioAddress;
+
+ NDIS_PHYSICAL_ADDRESS PhysicalAddress;
+
+ //
+ // The interrupt level;
+ //
+ UINT InterruptLevel;
+
+ //
+ // The RRR bits indicating the Shared RAM size:
+ // 0 = 8K, 1 = 16K, 2 = 32K, 3 = 64K.
+ //
+ UCHAR SharedRamBits;
+
+ //
+ // The actual size of Shared RAM from RRR bits 2,3 in
+ // the PC I/O Bus adapter.
+ //
+ UINT RrrSharedRamSize;
+
+ //
+ // Common variable for storing total Shared RAM Size.
+ //
+ UINT SharedRamSize;
+
+ //
+ // The actual address of Shared RAM from the SWITCH_READ_2
+ // port in the Microchannel adapter.
+ //
+ UINT McaSharedRam;
+
+ //
+ // The boundary needed for the Shared RAM mapping.
+ //
+ UCHAR BoundaryNeeded;
+
+ //
+ // The value read from the Shared RAM paging byte of
+ // the AIP.
+ //
+ UCHAR AipSharedRamPaging;
+
+ UCHAR RegValue;
+
+ if (IBM_TOKEN_RING_PCMCIA == Adapter->CardType)
+ {
+ UINT Nibble0;
+ UINT Nibble1;
+ UINT Nibble2;
+ UINT Nibble3;
+
+ //
+ // Configure the card to match registry
+ // Use the Default MMIO value here
+ // (this never changes from system to system)
+ //
+ MmioAddress = Adapter->MmioAddress;
+
+ //
+ // Nibble 0 - ROM address
+ //
+ Nibble0 = NIBBLE_0 | ( ( UINT )( MmioAddress >> 16 ) & 0x0F );
+
+ //
+ // Nibble 1 - ROM address, INT 0
+ //
+ Nibble1 = NIBBLE_1 | ( ( UINT )( MmioAddress >> 12) & 0x0F );
+
+ //
+ // Nibble 2 - INT1, F ROS, SRAM, S RST
+ //
+ Nibble2 = NIBBLE_2 | DEFAULT_NIBBLE_2;
+
+ //
+ // Nibble 3 - Ring Speed, RAM size, Prim/Alt
+ //
+ Nibble3 = NIBBLE_3;
+
+ if (Adapter->RingSpeed == 16)
+ {
+ Nibble3 |= RING_SPEED_16_MPS;
+ }
+ else
+ {
+ Nibble3 |= RING_SPEED_4_MPS;
+ }
+
+ switch (Adapter->RamSize)
+ {
+ case 0x10000:
+ Nibble3 |= SHARED_RAM_64K;
+ break;
+
+ case 0x8000:
+ Nibble3 |= SHARED_RAM_32K;
+ break;
+
+ case 0x4000:
+ Nibble3 |= SHARED_RAM_16K;
+ break;
+
+ case 0x2000:
+ Nibble3 |= SHARED_RAM_8K;
+ break;
+ }
+
+ if ( Adapter->IbmtokPortAddress == PRIMARY_ADAPTER_OFFSET)
+ {
+ Nibble3 |= PRIMARY;
+ }
+ else
+ {
+ Nibble3 |= ALTERNATE;
+ }
+
+#if DBG
+ if (IbmtokDbg)
+ {
+ DbgPrint("Nibble0 = %x\n",Nibble0);
+ DbgPrint("Nibble1 = %x\n",Nibble1);
+ DbgPrint("Nibble2 = %x\n",Nibble2);
+ DbgPrint("Nibble3 = %x\n",Nibble3);
+ }
+#endif
+ //
+ // Write everything to the Token-Ring
+ // Controller Configuration Register
+ //
+ WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_1, Nibble0);
+ WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_1, Nibble1);
+ WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_1, Nibble2);
+ WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_1, Nibble3);
+ WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_1, RELEASE_TR_CONTROLLER);
+
+ //
+ // Use the MMIO provided by ConfigMgr here
+ //
+ MmioAddress = Adapter->MmioAddress;
+
+ NdisSetPhysicalAddressHigh(PhysicalAddress, 0);
+ NdisSetPhysicalAddressLow(PhysicalAddress, MmioAddress);
+
+ NdisMapIoSpace(
+ &Status,
+ (PVOID *)&(Adapter->MmioRegion),
+ Adapter->NdisAdapterHandle,
+ PhysicalAddress,
+ 0x2000
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_RESOURCE_CONFLICT,
+ 0
+ );
+
+ return(FALSE);
+ }
+
+ {
+ //
+ // Will hold the Adapter ID as read from the card.
+ //
+ ULONG AdapterId[3];
+
+ //
+ // What AdapterId should contain for a PC I/O bus card.
+ //
+ static ULONG PcIoBusId[3] = { 0x5049434f, 0x36313130, 0x39393020 };
+
+ //
+ // What AdapterId should contain for a Micro Channel card.
+ //
+ static ULONG MicroChannelId[3] = { 0x4d415253, 0x36335834, 0x35313820 };
+
+ //
+ // Loop counters.
+ //
+ UINT i, j;
+
+ UCHAR TmpUchar;
+
+ for (i = 0; i < 3; i++)
+ {
+ AdapterId[i] = 0;
+
+ for (j = 0; j < 16; j += 2)
+ {
+ ULONG Port;
+
+ Port = CHANNEL_IDENTIFIER + (i * 16) + j;
+ READ_ADAPTER_REGISTER(
+ Adapter,
+ Port,
+ &TmpUchar
+ );
+
+ AdapterId[i] = (AdapterId[i] << 4) + (TmpUchar & 0x0f);
+ }
+ }
+
+ if ((AdapterId[0] == PcIoBusId[0]) &&
+ (AdapterId[1] == PcIoBusId[1]) &&
+ (AdapterId[2] == PcIoBusId[2])
+ )
+ {
+ Adapter->UsingPcIoBus = TRUE;
+ }
+ else
+ {
+ //
+ // Unknown channel type.
+ //
+ NdisUnmapIoSpace(
+ Adapter->NdisAdapterHandle,
+ Adapter->MmioRegion,
+ 0x2000
+ );
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_BAD_IO_BASE_ADDRESS,
+ 0
+ );
+
+ return(FALSE);
+ }
+ }
+
+ NdisSetPhysicalAddressHigh(PhysicalAddress, 0);
+ NdisSetPhysicalAddressLow(PhysicalAddress, Adapter->Ram);
+
+ NdisMapIoSpace(
+ &Status,
+ (PVOID *)&(Adapter->SharedRam),
+ Adapter->NdisAdapterHandle,
+ PhysicalAddress,
+ Adapter->RamSize
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ NdisUnmapIoSpace(
+ Adapter->NdisAdapterHandle,
+ Adapter->MmioRegion,
+ 0x2000
+ );
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_RESOURCE_CONFLICT,
+ 0
+ );
+
+ return(FALSE);
+ }
+
+ Adapter->SharedRamPaging = FALSE;
+ Adapter->MappedSharedRam = Adapter->RamSize;
+ Adapter->RrrLowValue = (UCHAR)(Adapter->Ram >> 12);
+ WRITE_ADAPTER_REGISTER(Adapter, RRR_LOW, Adapter->RrrLowValue);
+
+
+#if DBG
+ if (IbmtokDbg)
+ {
+ DbgPrint ("mmio in hw = %x\n",Adapter->MmioAddress);
+ DbgPrint ("mmio in adapter = %x\n",Adapter->MmioRegion);
+ DbgPrint ("Adapter->SharedRam = %x\n",Adapter->SharedRam);
+ DbgPrint ("Adapter->Ram = %x\n",Adapter->Ram);
+ DbgPrint ("DEFAULT_RAM = %x\n",DEFAULT_RAM);
+ {
+ UCHAR Fred;
+ READ_ADAPTER_REGISTER(Adapter, RRR_LOW, &Fred);
+ DbgPrint("RRR_LOW = %x\n",Fred);
+ READ_ADAPTER_REGISTER(Adapter, RRR_HIGH, &Fred);
+ DbgPrint("RRR_HIGH = %x\n",Fred);
+ }
+ }
+#endif
+ }
+ else
+ {
+ //
+ // SwitchRead1 contains the interrupt code in the low 2 bits,
+ // and bits 18 through 13 of the MMIO address in the high
+ // 6 bits.
+ //
+
+ READ_ADAPTER_PORT(Adapter, SWITCH_READ_1, &SwitchRead1);
+
+ //
+ // SwitchRead2 contains Bit 19 of the MMIO address in the
+ // low bit. It is always 1 for PC I/O Bus and possibly 0
+ // for the Microchannel bus
+ //
+
+ READ_ADAPTER_PORT(Adapter, SWITCH_READ_2, &SwitchRead2);
+
+ //
+ // To compute MmioAddress, we mask off the low 2 bits of
+ // SwitchRead1, shift it out by 11 (so that the high 6 bits
+ // are moved to the right place), and add in the 19th bit value.
+ //
+
+ MmioAddress = ((SwitchRead1 & 0xfc) << 11) | ((SwitchRead2 & 1) << 19);
+
+ NdisSetPhysicalAddressHigh(PhysicalAddress, 0);
+ NdisSetPhysicalAddressLow(PhysicalAddress, MmioAddress);
+
+ NdisMapIoSpace(
+ &Status,
+ (PVOID *)&(Adapter->MmioRegion),
+ Adapter->NdisAdapterHandle,
+ PhysicalAddress,
+ 0x2000);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_RESOURCE_CONFLICT,
+ 0
+ );
+
+ return(FALSE);
+
+ }
+
+
+ //
+ // Now we have mapped the MMIO, look at the AIP. First
+ // determine the channel identifier.
+ //
+
+ {
+ //
+ // Will hold the Adapter ID as read from the card.
+ //
+ ULONG AdapterId[3];
+
+ //
+ // What AdapterId should contain for a PC I/O bus card.
+ //
+ static ULONG PcIoBusId[3] = { 0x5049434f, 0x36313130, 0x39393020 };
+
+ //
+ // What AdapterId should contain for a Micro Channel card.
+ //
+ static ULONG MicroChannelId[3] = { 0x4d415253, 0x36335834, 0x35313820 };
+
+ //
+ // Loop counters.
+ //
+ UINT i, j;
+
+ UCHAR TmpUchar;
+
+ //
+ // Read in AdapterId.
+ //
+ // Turns out that the bytes which identify the card are stored
+ // in a very odd manner. There are 48 bytes on the card. The
+ // even numbered bytes contain 4 bits of the card signature.
+ //
+
+ for (i=0; i<3; i++) {
+
+ AdapterId[i] = 0;
+
+ for (j=0; j<16; j+=2) {
+
+ READ_ADAPTER_REGISTER(Adapter,
+ CHANNEL_IDENTIFIER + (i*16 + j),
+ &TmpUchar
+ );
+
+ AdapterId[i] = (AdapterId[i] << 4) + (TmpUchar & 0x0F);
+
+
+ }
+
+ }
+
+ if ((AdapterId[0] == PcIoBusId[0]) &&
+ (AdapterId[1] == PcIoBusId[1]) &&
+ (AdapterId[2] == PcIoBusId[2])) {
+
+ Adapter->UsingPcIoBus = TRUE;
+
+ } else if ((AdapterId[0] == MicroChannelId[0]) &&
+ (AdapterId[1] == MicroChannelId[1]) &&
+ (AdapterId[2] == MicroChannelId[2])) {
+
+ Adapter->UsingPcIoBus = FALSE;
+
+ } else {
+
+ //
+ // Unknown channel type.
+ //
+
+
+ NdisUnmapIoSpace(Adapter->NdisAdapterHandle,
+ Adapter->MmioRegion,
+ 0x2000);
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_BAD_IO_BASE_ADDRESS,
+ 0
+ );
+
+ return FALSE;
+
+ }
+
+ }
+
+ //
+ // We can read the network address from the AIP but we won't,
+ // we read it from the bring-up SRB instead.
+ //
+
+ //
+ // Read the RRR High to get the Shared RAM size (we are
+ // only interested in bits 2 and 3).
+ //
+
+ READ_ADAPTER_REGISTER(Adapter, RRR_HIGH, &SharedRamBits);
+
+ SharedRamBits = ((SharedRamBits & 0x0c) >> 2);
+
+ if (Adapter->UsingPcIoBus) {
+
+ //
+ // Here we have to tell the Adapter where Shared RAM is
+ // going to be. To do this we first find the lowest
+ // address it could be at, and then advance the address
+ // such that it falls on a correct page boudary.
+ //
+
+
+ //
+ // To get value to put in RRR Low, which indicates where
+ // the Shared RAM is mapped, we first compute the lowest
+ // possible value, which is right after the MMIO region.
+ // We take the high six bits of SwitchRead and shift
+ // them right one (so bits 18-13 of the address are in
+ // bits 6-1), then we turn on bit 7 to indicate that bit
+ // 19 of the address is on, and leave bit 0 zero since
+ // it must be.
+ //
+
+ Adapter->RrrLowValue = (UCHAR)
+ ((((SwitchRead1 & 0xfc) >> 1) | 0x80) + 0x02);
+
+ //
+ // We now have to move up to a memory boundary
+ // based on the value of SharedRamBits; 0 (8K) = 16K boundary,
+ // 1 (16K) = 16K boundary, 2 (32K) = 32K boundary, and
+ // 3 (64K) = 64K Boundary. Remember that the way the
+ // address bits are shifted over in RrrLowValue, bit 1
+ // is really bit 13 of the final address (turning it on
+ // adds 8K), bit 2 if bit 14, etc. We compute Boundary
+ // Needed in this frame of reference.
+ //
+
+ switch (SharedRamBits) {
+
+ case 0:
+ case 1:
+
+ //
+ // 8K or 16K needs a 16K boundary.
+ //
+
+ RrrSharedRamSize = (SharedRamBits == 0) ? 0x2000 : 0x4000;
+ BoundaryNeeded = 0x04;
+ break;
+
+ case 2:
+
+ //
+ // 32K needs a 32K boundary.
+ //
+
+ RrrSharedRamSize = 0x8000;
+ BoundaryNeeded = 0x08;
+ break;
+
+ case 3:
+
+ //
+ // 64K needs a 64K boundary.
+ //
+
+ RrrSharedRamSize = 0x10000;
+ BoundaryNeeded = 0x10;
+ break;
+
+ }
+
+
+ //
+ // If RrrLowValue is not on the proper boundary, move it
+ // forward until it is.
+ //
+
+ if (Adapter->RrrLowValue & (BoundaryNeeded-1)) {
+
+ Adapter->RrrLowValue = (UCHAR)
+ ((Adapter->RrrLowValue & ~(BoundaryNeeded-1)) + BoundaryNeeded);
+
+ }
+
+ Adapter->MappedSharedRam = SharedRamSize = RrrSharedRamSize;
+
+ NdisSetPhysicalAddressHigh(PhysicalAddress, 0);
+ NdisSetPhysicalAddressLow(PhysicalAddress, Adapter->RrrLowValue << 12);
+
+ NdisMapIoSpace(&Status,
+ (PVOID *)&(Adapter->SharedRam),
+ Adapter->NdisAdapterHandle,
+ PhysicalAddress,
+ RrrSharedRamSize
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NdisUnmapIoSpace(Adapter->NdisAdapterHandle,
+ Adapter->MmioRegion,
+ 0x2000);
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_RESOURCE_CONFLICT,
+ 0
+ );
+
+ return(FALSE);
+
+ }
+
+ } else {
+
+ //
+ // Using Microchannel
+ //
+ // No need to set Adapter->RrrLowValue since it is not
+ // used in the Microchannel adapter.
+ //
+
+ switch (SharedRamBits){
+ case 0:
+ SharedRamSize = 0x2000;
+ break;
+ case 1:
+ SharedRamSize = 0x4000;
+ break;
+ case 2:
+ SharedRamSize = 0x8000;
+ break;
+ case 3:
+ SharedRamSize = 0x10000;
+ break;
+ }
+
+ McaSharedRam = ((SwitchRead2 & 0xfe) << 12);
+
+ NdisSetPhysicalAddressHigh(PhysicalAddress, 0);
+ NdisSetPhysicalAddressLow(PhysicalAddress, McaSharedRam);
+
+ NdisMapIoSpace(&Status,
+ (PVOID *)&(Adapter->SharedRam),
+ Adapter->NdisAdapterHandle,
+ PhysicalAddress,
+ SharedRamSize);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NdisUnmapIoSpace(Adapter->NdisAdapterHandle,
+ Adapter->MmioRegion,
+ 0x2000);
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_RESOURCE_CONFLICT,
+ 0
+ );
+
+ return(FALSE);
+
+ }
+
+ Adapter->MappedSharedRam = SharedRamSize;
+
+ }
+
+
+
+ //
+ // Get the interrupt level...note that a switch being
+ // "off" shows up as a 1, "on" is 0.
+ //
+
+ switch (SwitchRead1 & 0x03) {
+
+ case 0: InterruptLevel = 2; break;
+ case 1: InterruptLevel = 3; break;
+ case 2: InterruptLevel = (Adapter->UsingPcIoBus)?6:10; break;
+ case 3: InterruptLevel = (Adapter->UsingPcIoBus)?7:11; break;
+
+ }
+
+ Adapter->InterruptLevel = InterruptLevel;
+
+ //
+ // Now determine how much memory the adapter has, and
+ // whether to use Shared RAM paging.
+ //
+
+ Adapter->UpperSharedRamZero = FALSE;
+
+ READ_ADAPTER_REGISTER(Adapter, TOTAL_ADAPTER_RAM, &RegValue);
+
+ RegValue &= 0x0F;
+
+ switch (RegValue) {
+
+ //
+ // These values are described on page 7-26 of the
+ // Technical Reference.
+ //
+
+ case 0xf:
+
+ Adapter->TotalSharedRam = SharedRamSize;
+ break;
+
+ case 0xe:
+
+ Adapter->TotalSharedRam = 0x2000;
+ break;
+
+ case 0xd:
+
+ Adapter->TotalSharedRam = 0x4000;
+ break;
+
+ case 0xc:
+
+ Adapter->TotalSharedRam = 0x8000;
+ break;
+
+ case 0xb:
+
+ Adapter->TotalSharedRam = 0x10000;
+
+ Adapter->UpperSharedRamZero = TRUE;
+ break;
+
+ case 0xa:
+
+ Adapter->TotalSharedRam = 0x10000;
+ break;
+
+ default:
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
+ 3,
+ hardwareDetails,
+ IBMTOK_ERRMSG_UNSUPPORTED_RAM,
+ (ULONG)RegValue
+ );
+
+ NdisUnmapIoSpace(Adapter->NdisAdapterHandle,
+ Adapter->MmioRegion,
+ 0x2000);
+
+ if (Adapter->UsingPcIoBus) {
+ NdisUnmapIoSpace(
+ Adapter->NdisAdapterHandle,
+ Adapter->SharedRam,
+ SharedRamSize);
+ } else {
+ NdisUnmapIoSpace(
+ Adapter->NdisAdapterHandle,
+ Adapter->SharedRam,
+ SharedRamSize);
+ }
+
+ return FALSE;
+
+ }
+
+ //
+ // Only allow Shared RAM paging if we have 16K selected
+ // on SharedRamSize, 64K of total adapter memory, and it is allowed
+ // as specified on p. 7-26 of the Technical Reference.
+ //
+
+ READ_ADAPTER_REGISTER(Adapter, SHARED_RAM_PAGING, &AipSharedRamPaging);
+#if 0
+ if (SharedRamSize == 0x4000 &&
+ Adapter->TotalSharedRam == 0x10000 &&
+ (AipSharedRamPaging == 0xe || AipSharedRamPaging == 0xc)) {
+
+ Adapter->SharedRamPaging = TRUE;
+
+ } else {
+
+ Adapter->SharedRamPaging = FALSE;
+
+ }
+#else
+ Adapter->SharedRamPaging = FALSE;
+#endif
+ }
+
+
+ //
+ // Read in the maximum sizes allowed for DHBs based on
+ // the speed of the adapter (which we don't know yet).
+ //
+
+ READ_ADAPTER_REGISTER(Adapter, MAX_4_MBPS_DHB, &RegValue);
+
+ RegValue &= 0x0F;
+
+ switch (RegValue) {
+
+ case 0xf:
+ default:
+
+ Adapter->Max4MbpsDhb = 2048;
+ break;
+
+ case 0xe:
+
+ Adapter->Max4MbpsDhb = 4096;
+ break;
+
+ case 0xd:
+
+ Adapter->Max4MbpsDhb = 4464;
+ break;
+
+ }
+
+ READ_ADAPTER_REGISTER(Adapter, MAX_16_MBPS_DHB, &RegValue);
+
+ RegValue &= 0x0F;
+
+ switch (RegValue) {
+
+ case 0xf:
+ default:
+
+ Adapter->Max16MbpsDhb = 2048;
+ break;
+
+ case 0xe:
+
+ Adapter->Max16MbpsDhb = 4096;
+ break;
+
+ case 0xd:
+
+ Adapter->Max16MbpsDhb = 8192;
+ break;
+
+ case 0xc:
+
+ Adapter->Max16MbpsDhb = 16384;
+ break;
+
+ case 0xb:
+
+ Adapter->Max16MbpsDhb = 17960;
+ break;
+
+ }
+
+
+ return TRUE;
+
+}
diff --git a/private/ntos/ndis/ibmtok/ibmtok.rc b/private/ntos/ndis/ibmtok/ibmtok.rc
new file mode 100644
index 000000000..ef5e6e0fb
--- /dev/null
+++ b/private/ntos/ndis/ibmtok/ibmtok.rc
@@ -0,0 +1,39 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "IBM Token Ring 4, 16, 16/4 and 16/4A network driver"
+#define VER_INTERNALNAME_STR "IBMTOK.SYS"
+#define VER_ORIGINALFILENAME_STR "IBMTOK.SYS"
+
+#include "common.ver"
+
diff --git a/private/ntos/ndis/ibmtok/interrup.c b/private/ntos/ndis/ibmtok/interrup.c
new file mode 100644
index 000000000..eb406b02a
--- /dev/null
+++ b/private/ntos/ndis/ibmtok/interrup.c
@@ -0,0 +1,4855 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ interrup.c
+
+Abstract:
+
+ This is a part of the driver for the IBM IBMTOK
+ Token-ring controller. It contains the interrupt-handling routines.
+ This driver conforms to the NDIS 3.0 interface.
+
+ The overall structure and much of the code is taken from
+ the Lance NDIS driver by Tony Ercolano.
+
+Author:
+
+ Adam Barr (adamba) 16-Jan-1991
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent.
+
+Revision History:
+
+ Sean Selitrennikoff - 10/91
+ Fixed synchronization bugs.
+
+ Sean Selitrennikoff - 10/15/91
+ Converted to Ndis 3.0
+
+ Sean Selitrennikoff - 1/8/92
+ Added error logging
+
+ Brian E. Moore - 9/7/94
+ Added PCMCIA support
+
+--*/
+
+#pragma optimize("",off)
+
+#include <ndis.h>
+
+
+#include <tfilter.h>
+#include <tokhrd.h>
+#include <toksft.h>
+
+
+#if DEVL
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+#if DBG
+extern INT IbmtokDbg;
+#endif
+
+//
+// This section contains all the functions and definitions for
+// doing logging of input and output to/from the card.
+//
+
+#if LOG
+
+//
+// Place in the circular buffer.
+//
+UCHAR IbmtokLogPlace;
+
+//
+// Circular buffer for storing log information.
+//
+UCHAR IbmtokLog[256];
+
+#endif
+
+VOID
+SetResetVariables(
+ IN PIBMTOK_ADAPTER Adapter
+ );
+
+STATIC
+VOID
+IbmtokHandleSrbSsb(
+ IN PIBMTOK_ADAPTER Adapter
+ );
+
+STATIC
+VOID
+IbmtokHandleArbAsb(
+ IN PIBMTOK_ADAPTER Adapter
+ );
+
+
+STATIC
+VOID
+HandleResetStaging(
+ IN PIBMTOK_ADAPTER Adapter
+ );
+
+STATIC
+BOOLEAN
+IbmtokSynchGetSrbSsbBits(
+ IN PVOID Context
+ );
+
+STATIC
+BOOLEAN
+IbmtokSynchGetArbAsbBits(
+ IN PVOID Context
+ );
+
+STATIC
+VOID
+PutPacketOnWaitingForAsb(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet
+ );
+
+STATIC
+PNDIS_PACKET
+RemoveTransmitFromSrb(
+ IN PIBMTOK_ADAPTER Adapter,
+ OUT PBOOLEAN PacketRemoved
+ );
+
+STATIC
+VOID
+SetupTransmitFrameSrb(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet
+ );
+
+STATIC
+VOID
+SetupTransmitStatusAsb(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet
+ );
+
+STATIC
+VOID
+GetAdapterStatisticsFromSrb(
+ PIBMTOK_ADAPTER Adapter
+ );
+
+STATIC
+VOID
+GetAdapterErrorsFromSrb(
+ PIBMTOK_ADAPTER Adapter
+ );
+
+
+STATIC
+NDIS_STATUS
+StartPendQueueOp(
+ IN PIBMTOK_ADAPTER Adapter
+ );
+
+STATIC
+NDIS_STATUS
+FinishSetOperation(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN PIBMTOK_PEND_DATA PendOp
+ );
+
+
+STATIC
+BOOLEAN
+FinishPendQueueOp(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN BOOLEAN Successful
+ );
+
+STATIC
+NDIS_STATUS
+SetAdapterFunctionalAddress(
+ IN PIBMTOK_ADAPTER Adapter
+ );
+
+STATIC
+VOID
+SetupFunctionalSrb(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN TR_FUNCTIONAL_ADDRESS FunctionalAddress
+ );
+
+STATIC
+NDIS_STATUS
+SetAdapterGroupAddress(
+ IN PIBMTOK_ADAPTER Adapter
+ );
+
+STATIC
+VOID
+SetupGroupSrb(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN TR_FUNCTIONAL_ADDRESS FunctionalAddress
+ );
+
+STATIC
+VOID
+SetupReceivedDataAsb(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN SRAM_PTR ReceiveBuffer
+ );
+
+
+//
+// These macros are used to set the SRPR correctly.
+//
+#define SET_SRB_SRPR(Adapter) \
+ if (Adapter->SharedRamPaging) { \
+ WRITE_ADAPTER_REGISTER(Adapter, SRPR_LOW, Adapter->SrbSrprLow) \
+ }
+
+#define SET_SSB_SRPR(Adapter) \
+ if (Adapter->SharedRamPaging) { \
+ WRITE_ADAPTER_REGISTER(Adapter, SRPR_LOW, Adapter->SsbSrprLow) \
+ }
+
+#define SET_ARB_SRPR(Adapter) \
+ if (Adapter->SharedRamPaging) { \
+ WRITE_ADAPTER_REGISTER(Adapter, SRPR_LOW, Adapter->ArbSrprLow) \
+ }
+
+#define SET_ASB_SRPR(Adapter) \
+ if (Adapter->SharedRamPaging) { \
+ WRITE_ADAPTER_REGISTER(Adapter, SRPR_LOW, Adapter->AsbSrprLow) \
+ }
+
+
+
+typedef struct _IBMTOK_SYNCH_CONTEXT {
+
+ //
+ // Pointer to the ibmtok adapter for which interrupts are
+ // being synchronized.
+ //
+ PIBMTOK_ADAPTER Adapter;
+
+ //
+ // Points to the variable on to which the relevant
+ // interrupt bits should be ORed.
+ //
+ PVOID Local;
+
+} IBMTOK_SYNCH_CONTEXT, * PIBMTOK_SYNCH_CONTEXT;
+
+//
+// This macro is to synchronize execution with interrupts. It
+// gets the stored value of the SRB/SSB bits and clears the
+// old value.
+//
+#define GET_SRB_SSB_BITS(A,L) \
+{ \
+ PIBMTOK_ADAPTER _A = A; \
+ IBMTOK_SYNCH_CONTEXT _C; \
+ _C.Adapter = _A; \
+ _C.Local = (PVOID)(L); \
+ NdisSynchronizeWithInterrupt( \
+ &(_A->Interrupt), \
+ (PVOID) IbmtokSynchGetSrbSsbBits, \
+ &_C \
+ ); \
+}
+
+//
+// This macro is to synchronize execution with interrupts. It
+// gets the stored value of the ARB/ASB bits and clears the
+// old value.
+//
+#define GET_ARB_ASB_BITS(A,L) \
+{ \
+ PIBMTOK_ADAPTER _A = A; \
+ IBMTOK_SYNCH_CONTEXT _C; \
+ _C.Adapter = _A; \
+ _C.Local = (PVOID)(L); \
+ NdisSynchronizeWithInterrupt( \
+ &(_A->Interrupt), \
+ (PVOID) IbmtokSynchGetArbAsbBits, \
+ &_C \
+ ); \
+}
+
+
+//++
+//
+// PNDIS_PACKET
+// FindPacketGivenCorrelator(
+// IN PIBMTOK_ADAPTER Adapter,
+// IN UCHAR CommandCorrelator
+// )
+//
+//
+// Routine Description:
+//
+// This looks a packet up on the command correlator array.
+//
+// This routine should be called with the spinlock held.
+//
+// Arguments:
+//
+// Adapter - The adapter that this packet is coming through.
+//
+// CommandCorrelator - The command correlator to search based on.
+//
+// Return Value:
+//
+// The packet if found, NULL otherwise.
+//
+//--
+
+#define FindPacketGivenCorrelator(_Adapter, _CommandCorrelator) \
+ ((_Adapter)->CorrelatorArray[_CommandCorrelator])
+
+
+STATIC
+BOOLEAN
+IbmtokSynchGetSrbSsbBits(
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used by the normal interrupt processing routine
+ to synchronize with interrupts from the card. It will or
+ the value of the stored SRB/SSB bits into the other passed address
+ in the context and clear the stored value.
+
+Arguments:
+
+ Context - This is really a pointer to a record type peculiar
+ to this routine. The record contains a pointer to the adapter
+ and a pointer to an address in which to place the contents
+ of the ISRP.
+
+Return Value:
+
+ Always returns true.
+
+--*/
+
+{
+ PIBMTOK_SYNCH_CONTEXT C = (PIBMTOK_SYNCH_CONTEXT)Context;
+
+ *((PUCHAR)C->Local) = (C->Adapter->IsrpBits) &
+ (ISRP_HIGH_SRB_RESPONSE | ISRP_HIGH_SSB_RESPONSE);
+
+ C->Adapter->IsrpBits = (C->Adapter->IsrpBits) &
+ (~(ISRP_HIGH_SRB_RESPONSE | ISRP_HIGH_SSB_RESPONSE));
+
+ return TRUE;
+}
+
+ULONG PCMCIAStall = 0;
+
+STATIC
+BOOLEAN
+IbmtokSynchGetArbAsbBits(
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used by the normal interrupt processing routine
+ to synchronize with interrupts from the card. It will or
+ the value of the stored ARB/ASB bits into the other passed address
+ in the context and clear the stored value.
+
+Arguments:
+
+ Context - This is really a pointer to a record type peculiar
+ to this routine. The record contains a pointer to the adapter
+ and a pointer to an address in which to place the contents
+ of the ISRP.
+Return Value:
+
+ Always returns true.
+
+--*/
+
+{
+ PIBMTOK_SYNCH_CONTEXT C = (PIBMTOK_SYNCH_CONTEXT)Context;
+ UCHAR Test,i;
+IF_LOG('*');
+
+ if (C->Adapter->CardType == IBM_TOKEN_RING_PCMCIA)
+ {
+ NdisStallExecution(PCMCIAStall);
+ }
+
+ *((PUCHAR)C->Local) = (C->Adapter->IsrpBits) &
+ (ISRP_HIGH_ARB_COMMAND | ISRP_HIGH_ASB_FREE);
+
+ C->Adapter->IsrpBits = (C->Adapter->IsrpBits) &
+ (~(ISRP_HIGH_ARB_COMMAND | ISRP_HIGH_ASB_FREE));
+
+ return TRUE;
+}
+
+extern
+BOOLEAN
+IbmtokSynchSetReset(
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the SET_INTERRUPT_RESET_FLAG macro.
+ It sets the ResetInterruptAllowed flag to TRUE.
+
+Arguments:
+
+ Context - A pointer to the Adapter structure.
+
+Return Value:
+
+ Always returns true.
+
+--*/
+
+{
+ PIBMTOK_ADAPTER Adapter = (PIBMTOK_ADAPTER)Context;
+
+ Adapter->ResetInterruptAllowed = TRUE;
+
+ return TRUE;
+}
+
+extern
+BOOLEAN
+IbmtokSynchClearIsrpBits(
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the CLEAR_ISRP_BITS macro.
+ It clears the SRB/SSB and ARB/ASB bits. This is used
+ when a reset has started to prevent a previously
+ queued interrupt handler to come in and start
+ playing with an adapter that is being reset.
+
+Arguments:
+
+ Context - A pointer to the Adapter structure.
+
+Return Value:
+
+ Always returns true.
+
+--*/
+
+{
+ PIBMTOK_ADAPTER Adapter = (PIBMTOK_ADAPTER)Context;
+
+ Adapter->IsrpBits = 0;
+
+ return TRUE;
+}
+
+extern
+BOOLEAN
+IbmtokISR(
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ Interrupt service routine for the token-ring card. It's main job is
+ to get the value of ISR and record the changes in the
+ adapters own list of interrupt reasons.
+
+Arguments:
+
+ Context - Really a pointer to the adapter.
+
+Return Value:
+
+ Returns true if the card ISR is non-zero.
+
+--*/
+
+{
+
+ //
+ // Holds the pointer to the adapter.
+ //
+ PIBMTOK_ADAPTER Adapter = Context;
+
+ //
+ // Holds the value of the ISRP High
+ //
+ UCHAR IsrpHigh;
+
+ READ_ADAPTER_REGISTER(Adapter, ISRP_HIGH, &IsrpHigh);
+
+ if (!Adapter->BringUp)
+ {
+ Adapter->ContinuousIsrs++;
+
+ if (Adapter->ContinuousIsrs == 0xFF)
+ {
+ //
+ // We seemed to be confused since the DPCs aren't getting in.
+ // Shutdown and exit.
+ //
+#if DBG
+ if (IbmtokDbg)
+ DbgPrint("IBMTOK: Continuous ISRs received\n");
+#endif
+
+ WRITE_ADAPTER_PORT(Adapter, RESET_LATCH, 0);
+
+ return(FALSE);
+ }
+ }
+
+
+#if DBG
+ if (IbmtokDbg) DbgPrint("ISRP High: %x\n", IsrpHigh);
+#endif
+
+ IF_LOG('i');
+
+ //
+ // Acknowledge all the interrupts we got in IsrpHigh.
+ //
+ WRITE_ADAPTER_REGISTER(Adapter, ISRP_HIGH_RESET, (UCHAR)(~IsrpHigh));
+
+ //
+ // If the adapter is not accepting requests, ignore everything
+ // but SRB_RESPONSE interrupts, saving any others until
+ // NotAcceptingRequests goes to FALSE (note that we have
+ // already turned off ALL bits in ISRP_HIGH).
+ //
+ if (Adapter->NotAcceptingRequests)
+ {
+ Adapter->IsrpDeferredBits |= (IsrpHigh & (~ISRP_HIGH_SRB_RESPONSE));
+
+ IsrpHigh &= ISRP_HIGH_SRB_RESPONSE;
+ }
+ else
+ {
+ //
+ // Put the deferred bits back on (after the first time
+ // through they will be 0).
+ //
+ IsrpHigh |= Adapter->IsrpDeferredBits;
+
+ Adapter->IsrpDeferredBits = 0;
+ }
+
+ //
+ // Now store the bits for the DPC.
+ //
+ Adapter->IsrpBits |= IsrpHigh;
+
+ //
+ // If this is the reset interrupt, set the flag.
+ //
+ if (Adapter->ResetInterruptAllowed)
+ {
+ Adapter->ResetInterruptHasArrived = TRUE;
+ }
+
+ if (Adapter->FirstInitialization)
+ {
+ USHORT WrbOffset;
+ PSRB_BRING_UP_RESULT BringUpSrb;
+ UCHAR Value1, Value2;
+ USHORT RegValue;
+
+ READ_ADAPTER_REGISTER(Adapter, WRBR_LOW, &Value1);
+ READ_ADAPTER_REGISTER(Adapter, WRBR_HIGH, &Value2);
+
+ WrbOffset = (((USHORT)Value1) << 8) + (USHORT)Value2;
+
+ if (WrbOffset & 0x1)
+ {
+ //
+ // Mis-aligned WRB, fail to load
+ //
+ if (Adapter->UsingPcIoBus)
+ {
+ WRITE_ADAPTER_PORT(Adapter, INTERRUPT_RELEASE_ISA_ONLY, 1);
+ }
+
+ return(FALSE);
+ }
+
+ Adapter->InitialWrbOffset = WrbOffset;
+
+ BringUpSrb = (PSRB_BRING_UP_RESULT)(Adapter->SharedRam + WrbOffset);
+
+ NdisReadRegisterUshort(&(BringUpSrb->ReturnCode), &RegValue);
+
+ if (RegValue == 0x0000)
+ {
+ Adapter->BringUp = TRUE;
+ }
+
+ //
+ // If we are using the PC I/O Bus then we have to re-enable
+ // interrupts because the card is blocking all other interrupts
+ //
+ if (Adapter->UsingPcIoBus)
+ {
+ WRITE_ADAPTER_PORT(Adapter, INTERRUPT_RELEASE_ISA_ONLY, 1);
+ }
+
+ IF_LOG('I');
+
+ //
+ // no DPC for the first init.
+ //
+ return(FALSE);
+ }
+
+ //
+ // If we are using the PC I/O Bus then we have to re-enable
+ // interrupts because the card is blocking all other interrupts
+ //
+ if (Adapter->UsingPcIoBus)
+ {
+ WRITE_ADAPTER_PORT(Adapter, INTERRUPT_RELEASE_ISA_ONLY, 1);
+ }
+
+ if (IsrpHigh == 0x0)
+ {
+ //
+ // This means that the interrupt was generated from the IsrpLow
+ // and needs to be cleared.
+ //
+ READ_ADAPTER_REGISTER(Adapter, ISRP_LOW, &IsrpHigh);
+
+ //
+ // Mask off the bits we need.
+ //
+ IsrpHigh &= 0x1C;
+
+ Adapter->IsrpLowBits = IsrpHigh;
+
+ //
+ // Acknowledge all the interrupts we got in IsrpLow.
+ //
+ WRITE_ADAPTER_REGISTER(Adapter, ISRP_LOW_RESET, (UCHAR)(~IsrpHigh));
+ }
+
+ IF_LOG('I');
+
+ if (Adapter->IsrpBits != 0)
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+extern
+VOID
+IbmtokDPC(
+ IN PVOID SystemSpecific1,
+ IN PVOID Context,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+
+/*++
+
+Routine Description:
+
+ This DPC routine is queued by Ndis after interrupt service routine
+ has run. It's main job is to call the interrupt processing code.
+
+Arguments:
+
+ SystemSpecific1 - Not used.
+
+ Context - Really a pointer to the adapter.
+
+ SystemArgument1(2) - Neither of these arguments used.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIBMTOK_ADAPTER Adapter = (PIBMTOK_ADAPTER)Context;
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ Adapter->ContinuousIsrs = 0;
+
+ IF_LOG('d');
+
+ if (Adapter->IsrpLowBits)
+ {
+ Adapter->IsrpLowBits = 0;
+ }
+
+ if ((Adapter->IsrpBits & (ISRP_HIGH_ARB_COMMAND | ISRP_HIGH_ASB_FREE)) &&
+ (!Adapter->HandleArbRunning))
+ {
+ IbmtokHandleArbAsb(Adapter);
+
+ NdisDprAcquireSpinLock(&(Adapter->Lock));
+ }
+
+ if ((Adapter->IsrpBits & (ISRP_HIGH_SRB_RESPONSE | ISRP_HIGH_SSB_RESPONSE)) &&
+ (!Adapter->HandleSrbRunning))
+ {
+ IbmtokHandleSrbSsb(Adapter);
+ }
+ else
+ {
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+ }
+
+#if DBG
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+ IF_LOG('D');
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+#endif
+}
+
+extern
+VOID
+IbmtokHandleSrbSsb(
+ IN PIBMTOK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the DPC routine
+ and other routines within the driver that notice that
+ some deferred processing needs to be done. It's main
+ job is to call the interrupt processing code.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE LOCK HELD!! AND RETURNS
+ WITH IT RELEASED!!
+
+Arguments:
+
+ Adapter - A pointer to the adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UCHAR IsrpHigh;
+ UCHAR TmpUchar;
+ USHORT TmpUshort;
+ UCHAR Temp;
+ UINT Nibble3;
+
+ IF_LOG('h');
+
+ Adapter->References++;
+
+ if (Adapter->ResetInProgress)
+ {
+ if (Adapter->ResetInterruptHasArrived)
+ {
+ //
+ // This is the interrupt after a reset,
+ // continue things along.
+ //
+ HandleResetStaging(Adapter);
+
+ IBMTOK_DO_DEFERRED(Adapter);
+
+ return;
+ }
+ }
+
+ //
+ // If ResetInProgress is TRUE but this is an old
+ // interrupt, proceed as usual (once the reset
+ // actually starts, GET_SRB_SSB_BITS will return
+ // nothing so no work will get done).
+ //
+ Adapter->HandleSrbRunning = TRUE;
+
+ if (Adapter->CardType != IBM_TOKEN_RING_PCMCIA)
+ {
+ GET_SRB_SSB_BITS(Adapter, &IsrpHigh);
+ }
+ else
+ {
+ //
+ // disable interrupts on the card,
+ // since we don't trust ndissyncint to work
+ //
+ READ_ADAPTER_REGISTER(Adapter, ISRP_LOW, &Temp);
+
+ WRITE_ADAPTER_REGISTER(
+ Adapter,
+ ISRP_LOW,
+ Temp & ~(ISRP_LOW_NO_CHANNEL_CHECK | ISRP_LOW_INTERRUPT_ENABLE));
+
+ //
+ // update arb_asb
+ //
+ IsrpHigh = (Adapter->IsrpBits) & (ISRP_HIGH_SRB_RESPONSE | ISRP_HIGH_SSB_RESPONSE);
+ Adapter->IsrpBits = (Adapter->IsrpBits) & (~(ISRP_HIGH_SRB_RESPONSE | ISRP_HIGH_SSB_RESPONSE));
+
+ //
+ // reenable interrupts on the card
+ //
+ WRITE_ADAPTER_REGISTER(
+ Adapter,
+ ISRP_LOW,
+ ISRP_LOW_NO_CHANNEL_CHECK | ISRP_LOW_INTERRUPT_ENABLE);
+ }
+
+ while (IsrpHigh & (ISRP_HIGH_SRB_RESPONSE | ISRP_HIGH_SSB_RESPONSE))
+ {
+ IF_LOG((UCHAR)(Adapter->OpenInProgress));
+
+ if (Adapter->Unplugged && !Adapter->UnpluggedResetInProgress)
+ {
+ //
+ // Do, nothing. This is most likely a stale interrupt. We
+ // wait until we get a ring status interrupt telling us that
+ // the cable is plugged in.
+ //
+ break;
+ }
+
+ if (IsrpHigh & ISRP_HIGH_SRB_RESPONSE)
+ {
+ if (Adapter->OpenInProgress)
+ {
+ //
+ // Handle the result of the DIR.OPEN.ADAPTER command.
+ //
+ PSRB_OPEN_RESPONSE OpenResponseSrb;
+ PIBMTOK_OPEN Open;
+ PLIST_ENTRY CurrentLink;
+ UCHAR ReturnCode;
+
+ OpenResponseSrb = (PSRB_OPEN_RESPONSE)
+ (Adapter->SharedRam + Adapter->InitialWrbOffset);
+
+ NdisReadRegisterUchar(&(OpenResponseSrb->ReturnCode), &ReturnCode);
+
+#if DBG
+ if (IbmtokDbg)
+ DbgPrint("IBMTOK: OPEN, Return code = %x, at %lx\n",
+ ReturnCode,
+ OpenResponseSrb);
+#endif
+
+//
+ if (ReturnCode == 0x0)
+ {
+ NdisDprReleaseSpinLock(&(Adapter->Lock));
+
+ if (Adapter->SharedRamPaging)
+ {
+ NdisReadRegisterUshort(&(OpenResponseSrb->SrbPointer), &TmpUshort);
+
+ TmpUshort = IBMSHORT_TO_USHORT(TmpUshort);
+
+ Adapter->SrbAddress = SHARED_RAM_ADDRESS(Adapter,
+ SHARED_RAM_LOW_BITS(TmpUshort));
+ Adapter->SrbSrprLow = (UCHAR)(TmpUshort >> 14);
+
+
+ NdisReadRegisterUshort(&(OpenResponseSrb->SsbPointer), &TmpUshort);
+
+ TmpUshort = IBMSHORT_TO_USHORT(TmpUshort);
+
+ Adapter->SsbAddress = SHARED_RAM_ADDRESS(Adapter,
+ SHARED_RAM_LOW_BITS(TmpUshort));
+ Adapter->SsbSrprLow = (UCHAR)(TmpUshort >> 14);
+
+
+ NdisReadRegisterUshort(&(OpenResponseSrb->ArbPointer), &TmpUshort);
+
+ TmpUshort = IBMSHORT_TO_USHORT(TmpUshort);
+
+ Adapter->ArbAddress = SHARED_RAM_ADDRESS(Adapter,
+ SHARED_RAM_LOW_BITS(TmpUshort));
+ Adapter->ArbSrprLow = (UCHAR)(TmpUshort >> 14);
+
+
+ NdisReadRegisterUshort(&(OpenResponseSrb->AsbPointer), &TmpUshort);
+
+ TmpUshort = IBMSHORT_TO_USHORT(TmpUshort);
+
+ Adapter->AsbAddress = SHARED_RAM_ADDRESS(Adapter,
+ SHARED_RAM_LOW_BITS(TmpUshort));
+ Adapter->AsbSrprLow = (UCHAR)(TmpUshort >> 14);
+ }
+ else
+ {
+ NdisReadRegisterUshort(&(OpenResponseSrb->SrbPointer), &TmpUshort);
+ Adapter->SrbAddress = SRAM_PTR_TO_PVOID(Adapter, TmpUshort);
+
+ NdisReadRegisterUshort(&(OpenResponseSrb->SsbPointer), &TmpUshort);
+ Adapter->SsbAddress = SRAM_PTR_TO_PVOID(Adapter, TmpUshort);
+
+ NdisReadRegisterUshort(&(OpenResponseSrb->ArbPointer), &TmpUshort);
+ Adapter->ArbAddress = SRAM_PTR_TO_PVOID(Adapter, TmpUshort);
+
+ NdisReadRegisterUshort(&(OpenResponseSrb->AsbPointer), &TmpUshort);
+ Adapter->AsbAddress = SRAM_PTR_TO_PVOID(Adapter, TmpUshort);
+ }
+
+ if (((ULONG)Adapter->SrbAddress >
+ (ULONG)(Adapter->SharedRam + Adapter->MappedSharedRam)) ||
+ ((ULONG)Adapter->SsbAddress >
+ (ULONG)(Adapter->SharedRam + Adapter->MappedSharedRam)) ||
+ ((ULONG)Adapter->ArbAddress >
+ (ULONG)(Adapter->SharedRam + Adapter->MappedSharedRam)) ||
+ ((ULONG)Adapter->AsbAddress >
+ (ULONG)(Adapter->SharedRam + Adapter->MappedSharedRam)))
+ {
+ //
+ // Something is definitely wrong. Fail!
+ //
+ goto OpenFailed;
+ }
+
+#if DBG
+ if (IbmtokDbg)
+ {
+ USHORT TmpUshort1;
+ USHORT TmpUshort2;
+ USHORT TmpUshort3;
+ USHORT TmpUshort4;
+ NdisReadRegisterUshort(&(OpenResponseSrb->SrbPointer), &TmpUshort1);
+ NdisReadRegisterUshort(&(OpenResponseSrb->SsbPointer), &TmpUshort2);
+ NdisReadRegisterUshort(&(OpenResponseSrb->ArbPointer), &TmpUshort3);
+ NdisReadRegisterUshort(&(OpenResponseSrb->AsbPointer), &TmpUshort4);
+ DbgPrint("IBMTOK: Offsets: SRB %x SSB %x ARB %x ASB %x\n",
+ IBMSHORT_TO_USHORT(TmpUshort1),
+ IBMSHORT_TO_USHORT(TmpUshort2),
+ IBMSHORT_TO_USHORT(TmpUshort3),
+ IBMSHORT_TO_USHORT(TmpUshort4));
+ }
+#endif
+
+ //
+ // Now we have to start worrying about synchronization.
+ //
+ NdisDprAcquireSpinLock(&(Adapter->Lock));
+
+ Adapter->CurrentRingState = NdisRingStateOpened;
+ Adapter->OpenInProgress = FALSE;
+ Adapter->OpenErrorCode = 0;
+ Adapter->AdapterNotOpen = FALSE;
+ Adapter->NotAcceptingRequests = FALSE;
+
+ //
+ // Complete all opens that pended during this operation.
+ //
+ CurrentLink = Adapter->OpenBindings.Flink;
+
+ while (CurrentLink != &(Adapter->OpenBindings))
+ {
+ Open = CONTAINING_RECORD(CurrentLink, IBMTOK_OPEN, OpenList);
+ if (Open->OpenPending)
+ {
+ Open->OpenPending = FALSE;
+ NdisDprReleaseSpinLock(&(Adapter->Lock));
+
+ NdisCompleteOpenAdapter(
+ Open->NdisBindingContext,
+ NDIS_STATUS_SUCCESS,
+ 0);
+
+ NdisDprAcquireSpinLock(&(Adapter->Lock));
+ }
+
+ CurrentLink = CurrentLink->Flink;
+ }
+
+ //
+ // Get any interrupts that have been deferred
+ // while NotAcceptingRequests was TRUE.
+ //
+ IbmtokForceAdapterInterrupt(Adapter);
+ }
+ else
+ {
+ //
+ // Open Failed!
+ //
+ // Here is where I check the return code from the Open and see if it
+ // indicates an incorrect ring speed. If it does, I change the ring speed
+ // and reissue the OpenAdapter. BEM
+ //
+ NdisReadRegisterUshort(
+ &(OpenResponseSrb->ErrorCode),
+ &(TmpUshort));
+
+ //
+ // If a catastrophic error and a frequency error and we want ring speed listen
+ // and the number of retries > 0, bail out. We have already tried a different
+ // speed
+ //
+ if ((ReturnCode == 0x07) && // catastrophic error
+ (TmpUshort == 0x2400) && // frequency error
+ Adapter->RingSpeedListen && // we want ring speed listen
+ (Adapter->RingSpeedRetries == 0)) // have not tried before
+ {
+#if DBG
+ if (IbmtokDbg)
+ DbgPrint("IBMTOK: Incorrect Ring Speed, Changing.\n");
+#endif
+ //
+ //
+ // Change the ring speed
+ //
+
+ if (Adapter->Running16Mbps == TRUE)
+ Adapter->Running16Mbps == FALSE;
+ else
+ Adapter->Running16Mbps == TRUE;
+
+ Nibble3 = NIBBLE_3;
+
+ if (Adapter->RingSpeed == 16)
+ { // swap speeds
+ Nibble3 |= RING_SPEED_4_MPS;
+ }
+ else
+ {
+ Nibble3 |= RING_SPEED_16_MPS;
+ }
+
+ switch (Adapter->RamSize)
+ {
+ case 0x10000:
+ Nibble3 |= SHARED_RAM_64K;
+ break;
+ case 0x8000:
+ Nibble3 |= SHARED_RAM_32K;
+ break;
+ case 0x4000:
+ Nibble3 |= SHARED_RAM_16K;
+ break;
+ case 0x2000:
+ Nibble3 |= SHARED_RAM_8K;
+ break;
+ }
+
+ WRITE_ADAPTER_PORT(Adapter, SWITCH_READ_1, Nibble3);
+
+ //
+ // Now to reissue the Open Adapter SRB with the necessary changes.
+ //
+ // Reset these fields in the SRB for the Open Adapter.
+ //
+ OpenResponseSrb->ReturnCode = 0xFE;
+ OpenResponseSrb->ErrorCode = 0x0000;
+
+ // DbgBreakPoint();
+ //
+ // Tell the adapter to handle the change.
+ //
+ WRITE_ADAPTER_REGISTER(
+ Adapter,
+ ISRA_HIGH_SET,
+ ISRA_HIGH_COMMAND_IN_SRB);
+
+ Adapter->RingSpeedRetries++; // first retry
+
+ // end of check for incorrect ring speed
+ }
+ else
+ {
+OpenFailed:
+#if DBG
+ if (IbmtokDbg)
+ {
+ DbgPrint("IBMTOK: Open failed!\n");
+ }
+#endif
+ //
+ // Now we have to start worrying about synchronization.
+ //
+ Adapter->CurrentRingState = NdisRingStateOpenFailure;
+ Adapter->OpenInProgress = FALSE;
+ NdisReadRegisterUshort(
+ &(OpenResponseSrb->ErrorCode),
+ &(Adapter->OpenErrorCode));
+ Adapter->OpenErrorCode = IBMSHORT_TO_USHORT(Adapter->OpenErrorCode);
+ Adapter->AdapterNotOpen = TRUE;
+ Adapter->NotAcceptingRequests = TRUE;
+
+ //
+ // Fail all opens that pended during this operation.
+ //
+ CurrentLink = Adapter->OpenBindings.Flink;
+
+ while (CurrentLink != &(Adapter->OpenBindings))
+ {
+ Open = CONTAINING_RECORD(
+ CurrentLink,
+ IBMTOK_OPEN,
+ OpenList);
+
+ if (Open->OpenPending)
+ {
+ Open->OpenPending = FALSE;
+
+ NdisDprReleaseSpinLock(&(Adapter->Lock));
+
+ NdisCompleteOpenAdapter(
+ Open->NdisBindingContext,
+ NDIS_STATUS_OPEN_FAILED,
+ NDIS_STATUS_TOKEN_RING_OPEN_ERROR |
+ (NDIS_STATUS)(Adapter->OpenErrorCode));
+
+ NdisDprAcquireSpinLock(&(Adapter->Lock));
+
+ CurrentLink = CurrentLink->Flink;
+
+ RemoveEntryList(&(Open->OpenList));
+
+ IBMTOK_FREE_PHYS(Open, sizeof(IBMTOK_OPEN));
+
+ Adapter->References--;
+ }
+ else
+ {
+ //
+ // Note: All opens are pending, otherwise the
+ // adapter would have already been open.
+ //
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+#if DBG
+ if (IbmtokDbg)
+ DbgPrint("IBMTOK: SRB Response\n");
+#endif
+ IF_LOG('>');
+
+ if (Adapter->TransmittingPacket != (PNDIS_PACKET)NULL)
+ {
+ BOOLEAN PacketRemoved;
+
+ //
+ // Happens if the transmit failed.
+ //
+ (PVOID)RemoveTransmitFromSrb(Adapter, &PacketRemoved);
+
+ //
+ // If the packet was successfully removed, then
+ // start the next command.
+ //
+ // This will release the spin lock.
+ //
+ if (PacketRemoved)
+ {
+ //
+ // SrbAvailable will still be FALSE here,
+ // as required.
+ //
+ SetupSrbCommand(Adapter);
+ }
+ }
+ else if (!Adapter->SrbAvailable)
+ {
+ PSRB_GENERIC GenericSrb = (PSRB_GENERIC)Adapter->SrbAddress;
+ UCHAR ReturnCode;
+
+ //
+ // Another command in progress, complete it unless
+ // it was an INTERRUPT command.
+ //
+ NdisReadRegisterUchar(&(GenericSrb->ReturnCode), &ReturnCode);
+
+ IF_LOG('N');
+
+ NdisReadRegisterUchar(&(GenericSrb->Command), &TmpUchar);
+
+ if (TmpUchar != SRB_CMD_INTERRUPT)
+ {
+ if ((TmpUchar != SRB_CMD_READ_LOG) &&
+ (TmpUchar != SRB_CMD_SET_FUNCTIONAL_ADDRESS) &&
+ (TmpUchar != SRB_CMD_SET_GROUP_ADDRESS) &&
+ (TmpUchar != SRB_CMD_DLC_STATISTICS))
+ {
+ //
+ // We have an invalid response. Log an error an exit.
+ //
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_INVALID_VALUE_FROM_ADAPTER,
+ 3,
+ handleSrbSsb,
+ IBMTOK_ERRMSG_INVALID_CMD,
+ (ULONG)TmpUchar);
+ }
+ else
+ {
+ //
+ // This interrupt had to come from a pended op.
+ //
+ ASSERT(Adapter->PendData != NULL);
+
+ if (Adapter->PendData->RequestType == NdisRequestGeneric1)
+ {
+ //
+ // If no request, it came as a result of the
+ // card overflowing a counter and then we
+ // submitted the correcting operation.
+ //
+ if (ReturnCode == 0x00)
+ {
+ if (Adapter->PendData->COMMAND.MAC.ReadLogPending)
+ {
+ //
+ // We are getting an SRB_CMD_READ_LOG from
+ // we sent as a result to a RING_STATUS_CHANGE.
+ //
+ GetAdapterErrorsFromSrb(Adapter);
+ }
+ else
+ {
+ //
+ // We are getting an SRB_CMD_DLC_STATISTICS from
+ // we sent as a result to a DLC_STATUS.
+ //
+ GetAdapterStatisticsFromSrb(Adapter);
+ }
+ }
+
+ //
+ // Free up pend operation.
+ //
+ IBMTOK_FREE_PHYS(Adapter->PendData, sizeof(IBMTOK_PEND_DATA));
+
+ Adapter->PendData = NULL;
+
+ //
+ // Fire off next command.
+ //
+ SetupSrbCommand(Adapter);
+ }
+ else
+ {
+ //
+ // This is the result of a pending op from Ndis.
+ //
+ if (FinishPendQueueOp(
+ Adapter,
+ (BOOLEAN)(ReturnCode == 0x00 ? TRUE : FALSE)))
+ {
+
+ //
+ // Fire off next command.
+ //
+ SetupSrbCommand(Adapter);
+ }
+ }
+ }
+ }
+ else
+ {
+ SetupSrbCommand(Adapter);
+ }
+ }
+ else
+ {
+ //
+ // Nothing to do -- we get here when an SRB_FREE_REQUEST
+ // comes through after the ARB to transfer the data has
+ // already come through.
+ //
+ }
+ }
+ }
+
+ if (IsrpHigh & ISRP_HIGH_SSB_RESPONSE)
+ {
+ //
+ // This has to be a transmit completing since
+ // that is the only operation we do that pends.
+ //
+ PSSB_TRANSMIT_COMPLETE ResponseSsb =
+ (PSSB_TRANSMIT_COMPLETE)Adapter->SsbAddress;
+
+ NdisReadRegisterUchar(&(ResponseSsb->Command), &TmpUchar);
+
+ if (TmpUchar == SRB_CMD_TRANSMIT_DIR_FRAME)
+ {
+ UCHAR CorrelatorInSrb;
+ NDIS_STATUS SendStatus;
+ UCHAR SrbReturnCode;
+
+ //
+ // Initialize this to one less since the loop starts by
+ // incrementing it.
+ //
+ UCHAR CurrentCorrelator = (UCHAR)
+ ((Adapter->NextCorrelatorToComplete +
+ (MAX_COMMAND_CORRELATOR-1)) %
+ MAX_COMMAND_CORRELATOR);
+
+ NdisReadRegisterUchar(&(ResponseSsb->CommandCorrelator), &CorrelatorInSrb);
+
+ //
+ // Have to loop to complete since supposedly one
+ // of these can indicate multiple completing sends.
+ //
+
+ //
+ // Figure out what the return code should be.
+ //
+ NdisReadRegisterUchar(&(ResponseSsb->ReturnCode), &SrbReturnCode);
+
+ if (SrbReturnCode == 0x00)
+ {
+ SendStatus = NDIS_STATUS_SUCCESS;
+ }
+ else if (SrbReturnCode == 0x22)
+ {
+ //
+ // Check the frame status.
+ //
+ UCHAR FrameStatus;
+ UCHAR HighAc;
+ UCHAR LowAc;
+
+ NdisReadRegisterUchar(&(ResponseSsb->ErrorFrameStatus), &FrameStatus);
+ HighAc = GET_FRAME_STATUS_HIGH_AC(FrameStatus);
+ LowAc = GET_FRAME_STATUS_LOW_AC(FrameStatus);
+
+ if (HighAc != LowAc ||
+ (HighAc != AC_NOT_RECOGNIZED))
+ {
+ SendStatus = NDIS_STATUS_NOT_RECOGNIZED;
+ }
+ else
+ {
+ SendStatus = NDIS_STATUS_SUCCESS;
+ }
+
+#if DBG
+ if (IbmtokDbg) DbgPrint("IBMTOK: Send failed, code %x err %x\n",
+ SrbReturnCode,
+ FrameStatus);
+#endif
+
+ }
+ else
+ {
+ SendStatus = NDIS_STATUS_FAILURE;
+#if DBG
+ if (IbmtokDbg) DbgPrint("IBMTOK: Send failed, code %x\n",
+ SrbReturnCode);
+#endif
+ }
+
+ NdisDprReleaseSpinLock(&(Adapter->Lock));
+
+ do
+ {
+ PNDIS_PACKET TransmitPacket;
+ PIBMTOK_RESERVED Reserved;
+ PIBMTOK_OPEN Open;
+
+ CurrentCorrelator = (UCHAR)((CurrentCorrelator + 1) %
+ MAX_COMMAND_CORRELATOR);
+
+ //
+ // Complete the transmit.
+ //
+ TransmitPacket =
+ FindPacketGivenCorrelator(Adapter, CurrentCorrelator);
+
+ if (TransmitPacket == (PNDIS_PACKET)NULL)
+ {
+#if DBG
+ if (IbmtokDbg) DbgPrint("IBMTOK: Missing %d to complete, %d to %d\n",
+ CurrentCorrelator,
+ Adapter->NextCorrelatorToComplete,
+ CorrelatorInSrb);
+#endif
+ continue;
+ }
+
+ RemovePacketFromCorrelatorArray(Adapter, TransmitPacket);
+
+ Reserved = PIBMTOK_RESERVED_FROM_PACKET(TransmitPacket);
+
+ Open =
+ PIBMTOK_OPEN_FROM_BINDING_HANDLE(Reserved->MacBindingHandle);
+
+ //
+ // If doing LOOPBACK, this should really be a check
+ // of ReadyToComplete etc.
+ //
+#ifdef CHECK_DUP_SENDS
+ {
+ VOID IbmtokRemovePacketFromList(PIBMTOK_ADAPTER, PNDIS_PACKET);
+ IbmtokRemovePacketFromList(Adapter, TransmitPacket);
+ }
+#endif
+
+ if (SendStatus == NDIS_STATUS_SUCCESS)
+ {
+ Adapter->FramesTransmitted++;
+ }
+ else
+ {
+ Adapter->FrameTransmitErrors++;
+ }
+
+ NdisCompleteSend(
+ Open->NdisBindingContext,
+ Reserved->Packet,
+ SendStatus);
+
+ //
+ // Decrement the reference count for the open.
+ //
+#if DBG
+ NdisDprAcquireSpinLock(&(Adapter->Lock));
+ IF_LOG('C');
+ NdisDprReleaseSpinLock(&(Adapter->Lock));
+#endif
+ NdisInterlockedAddUlong((PULONG)&Open->References, (UINT)-1, &Adapter->Lock);
+
+ } while (CurrentCorrelator != CorrelatorInSrb);
+
+ NdisDprAcquireSpinLock(&(Adapter->Lock));
+
+ Adapter->SendTimeout = FALSE;
+
+ Adapter->NextCorrelatorToComplete =
+ (UCHAR)((CurrentCorrelator + 1) % MAX_COMMAND_CORRELATOR);
+
+ //
+ // We know that SrbAvailable is FALSE...
+ //
+ IF_LOG('<');
+
+ SetupSrbCommand(Adapter);
+ }
+ else
+ {
+ //
+ // Nothing else should pend!!
+ //
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_INVALID_VALUE_FROM_ADAPTER,
+ 3,
+ handleSrbSsb,
+ IBMTOK_ERRMSG_INVALID_CMD,
+ (ULONG)TmpUchar);
+
+#if DBG
+ if (IbmtokDbg) DbgPrint("IBMTOK: Error! Got Cmd %x\n",TmpUchar);
+#endif
+ }
+
+ WRITE_ADAPTER_REGISTER(
+ Adapter,
+ ISRA_HIGH_SET,
+ ISRA_HIGH_SSB_FREE);
+ }
+
+ if (Adapter->CardType != IBM_TOKEN_RING_PCMCIA)
+ {
+ GET_SRB_SSB_BITS(Adapter, &IsrpHigh);
+ }
+ else
+ {
+ //
+ // disable interrupts on the card, since we don't trust ndissyncint to work
+ //
+ READ_ADAPTER_REGISTER(Adapter, ISRP_LOW, &Temp);
+
+ WRITE_ADAPTER_REGISTER(
+ Adapter,
+ ISRP_LOW,
+ Temp & (~(ISRP_LOW_NO_CHANNEL_CHECK | ISRP_LOW_INTERRUPT_ENABLE) ) );
+
+ //
+ // update arb_asb
+ //
+ IsrpHigh = (Adapter->IsrpBits) & (ISRP_HIGH_SRB_RESPONSE | ISRP_HIGH_SSB_RESPONSE);
+ Adapter->IsrpBits = (Adapter->IsrpBits) & (~(ISRP_HIGH_SRB_RESPONSE | ISRP_HIGH_SSB_RESPONSE));
+
+ //
+ // reenable interrupts on the card
+ //
+ WRITE_ADAPTER_REGISTER(
+ Adapter,
+ ISRP_LOW,
+ ISRP_LOW_NO_CHANNEL_CHECK | ISRP_LOW_INTERRUPT_ENABLE);
+ }
+ }
+
+ Adapter->HandleSrbRunning = FALSE;
+
+ IF_LOG('H');
+
+ //
+ // This macro assumes it is called with the lock held,
+ // and releases it.
+ //
+ IBMTOK_DO_DEFERRED(Adapter);
+}
+
+extern
+VOID
+IbmtokHandleArbAsb(
+ IN PIBMTOK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the DPC
+ and other routines within the driver that notice that
+ some deferred processing needs to be done. It's main
+ job is to call the interrupt processing code.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE LOCK HELD!! AND RETURNS WITH
+ THE LOCK REALEASED!!
+
+Arguments:
+
+ Adapter - A pointer to the adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UCHAR IsrpHigh;
+
+ PARB_TRANSMIT_DATA_REQUEST TransmitDataArb;
+
+ PARB_RECEIVED_DATA ReceivedDataArb;
+
+ PNDIS_PACKET TransmitPacket;
+
+ SRAM_PTR ReceiveBufferPointer;
+
+ PRECEIVE_BUFFER ReceiveBuffer;
+
+ UINT PacketLength, DummyBytesCopied;
+
+ BOOLEAN FreedSrb;
+
+ PIBMTOK_RESERVED Reserved;
+
+ PUCHAR DhbAddress;
+
+ UINT PacketSize, LookaheadSize;
+
+ PUCHAR FrameData;
+
+ ULONG HeaderLength;
+
+ UCHAR TmpUchar;
+
+ USHORT TmpUshort;
+
+ PUCHAR LookaheadBuffer;
+
+ UCHAR Temp;
+
+ Adapter->References++;
+
+ Adapter->HandleArbRunning = TRUE;
+
+ IF_LOG('j');
+
+ if (Adapter->CardType != IBM_TOKEN_RING_PCMCIA)
+ {
+ GET_ARB_ASB_BITS(Adapter, &IsrpHigh);
+ }
+ else
+ {
+ //
+ // disable interrupts on the card, since we don't trust ndissyncint to work
+ //
+ READ_ADAPTER_REGISTER(Adapter, ISRP_LOW, &Temp);
+
+ WRITE_ADAPTER_REGISTER(
+ Adapter,
+ ISRP_LOW,
+ Temp & (~(ISRP_LOW_NO_CHANNEL_CHECK | ISRP_LOW_INTERRUPT_ENABLE) ) );
+
+ //
+ // update arb_asb
+ //
+ IsrpHigh = (Adapter->IsrpBits) & (ISRP_HIGH_ARB_COMMAND | ISRP_HIGH_ASB_FREE);
+ Adapter->IsrpBits = (Adapter->IsrpBits) & (~(ISRP_HIGH_ARB_COMMAND | ISRP_HIGH_ASB_FREE));
+
+ //
+ // reenable interrupts on the card
+ //
+ WRITE_ADAPTER_REGISTER(
+ Adapter,
+ ISRP_LOW,
+ ISRP_LOW_NO_CHANNEL_CHECK | ISRP_LOW_INTERRUPT_ENABLE);
+ }
+
+ while (IsrpHigh & (ISRP_HIGH_ARB_COMMAND | ISRP_HIGH_ASB_FREE))
+ {
+ if (IsrpHigh & ISRP_HIGH_ARB_COMMAND)
+ {
+ NdisReadRegisterUchar(&((PARB_GENERIC)Adapter->ArbAddress)->Command, &TmpUchar);
+
+ switch (TmpUchar)
+ {
+ case ARB_CMD_DLC_STATUS:
+#if DBG
+ if (IbmtokDbg)
+ {
+ NdisReadRegisterUshort(
+ &((PARB_DLC_STATUS)Adapter->ArbAddress)->Status, &TmpUshort);
+ DbgPrint("IBMTOK: DLC Status %x\n",
+ IBMSHORT_TO_USHORT(TmpUshort));
+ }
+#endif
+
+ WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET,
+ ISRA_HIGH_ARB_FREE);
+
+ IF_LOG('#');
+
+ //
+ // If it is a counter overflow, we need to queue a
+ // DLC.STATISTICS command.
+ //
+ NdisReadRegisterUshort(
+ &((PARB_RING_STATUS_CHANGE)Adapter->ArbAddress)->NetworkStatus,
+ &TmpUshort);
+
+ if (IBMSHORT_TO_USHORT(TmpUshort) & 0x0040 )
+ {
+ //
+ // Build a pending operation. It will get run ASAP
+ // by ProcessSrbCommand.
+ //
+ PIBMTOK_PEND_DATA PendOp;
+
+ if (IBMTOK_ALLOC_PHYS(&PendOp,sizeof(IBMTOK_PEND_DATA)) !=
+ NDIS_STATUS_SUCCESS)
+ {
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ handleSrbSsb,
+ IBMTOK_ERRMSG_ALLOC_MEM);
+
+ break;
+ }
+
+ PendOp->Next = NULL;
+ PendOp->RequestType = NdisRequestGeneric1;
+ PendOp->COMMAND.MAC.ReadLogPending = FALSE;
+
+ if (Adapter->PendQueue == NULL)
+ {
+ Adapter->PendQueue = Adapter->EndOfPendQueue = PendOp;
+ }
+ else
+ {
+ //
+ // Put this operation on the front, so it can
+ // correct the error quickly.
+ //
+ PendOp->Next = Adapter->PendQueue;
+ Adapter->PendQueue = PendOp;
+ }
+
+ //
+ // It is now in the pend
+ // queue so we should start that up.
+ //
+ IbmtokProcessSrbRequests(Adapter);
+ }
+
+ break;
+
+ case ARB_CMD_RECEIVED_DATA:
+
+#if DBG
+ if (IbmtokDbg)
+ DbgPrint("IBMTOK: Received data\n");
+#endif
+ IF_LOG('r');
+
+ if (Adapter->Unplugged && !Adapter->UnpluggedResetInProgress)
+ {
+ //
+ // Do, nothing. This is most likely a stale interrupt. We
+ // wait until we get a ring status interrupt telling us that
+ // the cable is plugged in.
+ //
+ break;
+ }
+
+ ReceivedDataArb = (PARB_RECEIVED_DATA)Adapter->ArbAddress;
+
+ NdisReadRegisterUshort(&(ReceivedDataArb->ReceiveBuffer), &ReceiveBufferPointer);
+
+ //
+ // Prepare for indication.
+ //
+ Adapter->IndicatedReceiveBuffer = ReceiveBufferPointer;
+
+ ReceiveBuffer = (PRECEIVE_BUFFER)
+ ((PUCHAR)SRAM_PTR_TO_PVOID(Adapter, ReceiveBufferPointer) + 2);
+
+ NdisReadRegisterUshort(&(ReceivedDataArb->FrameLength), &PacketSize);
+
+ PacketSize = IBMSHORT_TO_USHORT(PacketSize);
+
+ NdisReadRegisterUshort(&(ReceiveBuffer->BufferLength), &LookaheadSize);
+
+ LookaheadSize = IBMSHORT_TO_USHORT(LookaheadSize);
+
+ WRITE_ADAPTER_REGISTER(
+ Adapter,
+ ISRA_HIGH_SET,
+ ISRA_HIGH_ARB_FREE);
+
+#if DBG
+ if (IbmtokDbg)
+ DbgPrint("IBMTOK: indicate len %d, lookahead %d\n", PacketSize, LookaheadSize);
+#endif
+
+ //
+ // Calculate how big the header is for this
+ // packet.
+ //
+ FrameData = ReceiveBuffer->FrameData;
+
+ NdisReadRegisterUchar(&FrameData[8], &TmpUchar);
+
+ if (TmpUchar & 0x80)
+ {
+ //
+ // Source routing bit is on in source address.
+ //
+ NdisReadRegisterUchar(&FrameData[14], &TmpUchar);
+ HeaderLength = (TmpUchar & 0x1f) + 14;
+ }
+ else
+ {
+ HeaderLength = 14;
+ }
+
+ Adapter->IndicatedHeaderLength = (USHORT)HeaderLength;
+
+ Adapter->FramesReceived++;
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ //
+ // Call into the filter package to do the
+ // indication.
+ //
+ if (LookaheadSize < HeaderLength)
+ {
+ //
+ // Must at least have an address
+ //
+ if (LookaheadSize >= TR_LENGTH_OF_ADDRESS)
+ {
+ NdisCreateLookaheadBufferFromSharedMemory(
+ (PVOID)FrameData,
+ LookaheadSize,
+ &LookaheadBuffer);
+
+ if (LookaheadBuffer != NULL)
+ {
+ //
+ // Runt Packet
+ //
+ TrFilterIndicateReceive(
+ Adapter->FilterDB,
+ (NDIS_HANDLE)ReceiveBuffer, // context
+ LookaheadBuffer, // header
+ LookaheadSize, // header length
+ NULL, // lookahead
+ 0, // lookahead length
+ 0);
+
+ NdisDestroyLookaheadBufferFromSharedMemory(LookaheadBuffer);
+ }
+ }
+ }
+ else
+ {
+ NdisCreateLookaheadBufferFromSharedMemory(
+ (PVOID)FrameData,
+ LookaheadSize,
+ &LookaheadBuffer);
+
+ if (LookaheadBuffer != NULL)
+ {
+ TrFilterIndicateReceive(
+ Adapter->FilterDB,
+ (NDIS_HANDLE)ReceiveBuffer, // context
+ LookaheadBuffer, // header
+ HeaderLength, // header length
+ LookaheadBuffer + HeaderLength, // lookahead
+ LookaheadSize - HeaderLength, // lookahead length
+ PacketSize - HeaderLength);
+
+ NdisDestroyLookaheadBufferFromSharedMemory(LookaheadBuffer);
+ }
+ }
+
+ TrFilterIndicateReceiveComplete( Adapter->FilterDB );
+
+ //
+ // Now worry about the ASB.
+ //
+ NdisDprAcquireSpinLock(&(Adapter->Lock));
+
+ //
+ // Set response in ASB, if possible, else queue the response
+ //
+ if (Adapter->AsbAvailable)
+ {
+ Adapter->AsbAvailable = FALSE;
+
+ Adapter->UseNextAsbForReceive = FALSE;
+
+ SetupReceivedDataAsb(Adapter, ReceiveBufferPointer);
+ WRITE_ADAPTER_REGISTER(
+ Adapter,
+ ISRA_HIGH_SET,
+ ISRA_HIGH_RESPONSE_IN_ASB);
+
+ //
+ // LOOPBACK HERE!!
+ //
+ }
+ else
+ {
+#if DBG
+ if (IbmtokDbg) DbgPrint("W_ASB R\n");
+#endif
+ if (Adapter->ReceiveWaitingForAsbEnd == (USHORT)(-1))
+ {
+ Adapter->ReceiveWaitingForAsbList = ReceiveBufferPointer;
+ }
+ else
+ {
+ PVOID PEnd;
+
+ PEnd = SRAM_PTR_TO_PVOID(
+ Adapter,
+ Adapter->ReceiveWaitingForAsbEnd);
+
+ NdisWriteRegisterUshort(PEnd, ReceiveBufferPointer);
+ }
+
+ Adapter->ReceiveWaitingForAsbEnd = ReceiveBufferPointer;
+
+ if (!(Adapter->OutstandingAsbFreeRequest))
+ {
+ Adapter->OutstandingAsbFreeRequest = TRUE;
+
+ WRITE_ADAPTER_REGISTER(
+ Adapter,
+ ISRA_HIGH_SET,
+ ISRA_HIGH_ASB_FREE_REQUEST);
+
+ IF_LOG('a');
+ }
+ }
+
+ break;
+
+ case ARB_CMD_RING_STATUS_CHANGE:
+ {
+ USHORT RingStatus;
+ NDIS_STATUS NotifyStatus = 0;
+
+ NdisReadRegisterUshort(
+ &((PARB_RING_STATUS_CHANGE)Adapter->ArbAddress)->NetworkStatus,
+ &RingStatus);
+
+ RingStatus = IBMSHORT_TO_USHORT(RingStatus);
+#if DBG
+ if (IbmtokDbg)
+ DbgPrint("IBMTOK: Ring Status %x\n", RingStatus);
+#endif
+
+ WRITE_ADAPTER_REGISTER(
+ Adapter,
+ ISRA_HIGH_SET,
+ ISRA_HIGH_ARB_FREE);
+
+ //
+ // If it is a counter overflow, we need to queue a
+ // DIR.READ.LOG command.
+ //
+ if (RingStatus & 0x0080)
+ {
+ //
+ // Build a pending operation. It will get run ASAP
+ // by ProcessSrbCommand.
+ //
+ PIBMTOK_PEND_DATA PendOp;
+
+ if (IBMTOK_ALLOC_PHYS(&PendOp,sizeof(IBMTOK_PEND_DATA)) !=
+ NDIS_STATUS_SUCCESS)
+ {
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ handleSrbSsb,
+ IBMTOK_ERRMSG_ALLOC_MEM);
+
+ break;
+ }
+
+ PendOp->Next = NULL;
+ PendOp->RequestType = NdisRequestGeneric1;
+ PendOp->COMMAND.MAC.ReadLogPending = TRUE;
+
+ if (Adapter->PendQueue == NULL)
+ {
+ Adapter->PendQueue = Adapter->EndOfPendQueue = PendOp;
+
+ }
+ else
+ {
+ //
+ // Put this operation on the front, so it can
+ // correct the error quickly.
+ //
+ PendOp->Next = Adapter->PendQueue;
+ Adapter->PendQueue = PendOp;
+ }
+
+ //
+ // It is now in the pend
+ // queue so we should start that up.
+ // Returns with lock released
+ //
+ IbmtokProcessSrbRequests(Adapter);
+ }
+
+ if (RingStatus & 0x0020)
+ {
+ //
+ // Ring Recovery
+ //
+ NotifyStatus |= NDIS_RING_RING_RECOVERY;
+ }
+
+ if (RingStatus & 0x0040)
+ {
+ //
+ // Single Station
+ //
+ NotifyStatus |= NDIS_RING_SINGLE_STATION;
+ }
+
+ if (RingStatus & 0x0080)
+ {
+ //
+ // Counter Overflow
+ //
+ NotifyStatus |= NDIS_RING_COUNTER_OVERFLOW;
+ }
+
+ if (RingStatus & 0x0100)
+ {
+ //
+ // Remove received
+ //
+ NotifyStatus |= NDIS_RING_REMOVE_RECEIVED;
+ }
+
+ if (RingStatus & 0x0400)
+ {
+ //
+ // Auto-removal
+ //
+ NotifyStatus |= NDIS_RING_AUTO_REMOVAL_ERROR;
+ }
+
+ if (RingStatus & 0x0800)
+ {
+ //
+ // Lobe wire fault
+ //
+ NotifyStatus |= NDIS_RING_LOBE_WIRE_FAULT;
+ }
+
+ if (RingStatus & 0x1000)
+ {
+ //
+ // Transmit Beacon
+ //
+ NotifyStatus |= NDIS_RING_TRANSMIT_BEACON;
+ }
+
+ if (RingStatus & 0x2000)
+ {
+ //
+ // Soft error
+ //
+ NotifyStatus |= NDIS_RING_SOFT_ERROR;
+ }
+
+ if (RingStatus & 0x4000)
+ {
+ //
+ // Hard error
+ //
+ NotifyStatus |= NDIS_RING_HARD_ERROR;
+ }
+
+ if (RingStatus & 0x8000)
+ {
+ //
+ // Signal loss
+ //
+ NotifyStatus |= NDIS_RING_SIGNAL_LOSS;
+ }
+
+ if (NotifyStatus != 0)
+ {
+ PLIST_ENTRY CurrentLink;
+ PIBMTOK_OPEN TempOpen;
+
+ //
+ // Indicate Status to all opens
+ //
+ CurrentLink = Adapter->OpenBindings.Flink;
+
+ while (CurrentLink != &(Adapter->OpenBindings)){
+
+ TempOpen = CONTAINING_RECORD(
+ CurrentLink,
+ IBMTOK_OPEN,
+ OpenList);
+
+ TempOpen->References++;
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ NdisIndicateStatus(
+ TempOpen->NdisBindingContext,
+ NDIS_STATUS_RING_STATUS,
+ (PVOID)&NotifyStatus,
+ sizeof(NotifyStatus));
+
+ NdisIndicateStatusComplete(TempOpen->NdisBindingContext);
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ CurrentLink = CurrentLink->Flink;
+
+ TempOpen->References--;
+ }
+
+ Adapter->LastNotifyStatus = NotifyStatus;
+ }
+
+ //
+ // Handle a cable being unplugged
+ //
+ if ((RingStatus & 0x5000) == 0x5000)
+ {
+ // receive and transmit beacon
+
+ //
+ // Ok, the cable has been unplugged. We now abort all
+ // outstanding sends, etc.
+ //
+
+ Adapter->Unplugged = TRUE;
+
+ IbmtokAbortPending(Adapter, NDIS_STATUS_DEVICE_FAILED);
+
+ if ((RingStatus & 0x800) == 0x800)
+ {
+ Adapter->LobeWireFaultIndicated = TRUE;
+ }
+ }
+ else if ((RingStatus & 0x0020) &&
+ !(RingStatus & 0x4000) &&
+ (Adapter->Unplugged) &&
+ (!Adapter->UnpluggedResetInProgress))
+ {
+ //
+ // Reset the adapter to remove all stale information
+ //
+ Adapter->UnpluggedResetInProgress = TRUE;
+
+ IbmtokSetupForReset(Adapter, NULL);
+
+ IbmtokHandleDeferred(Adapter);
+ }
+ }
+
+ break;
+
+ case ARB_CMD_TRANSMIT_DATA_REQUEST:
+#if DBG
+ if (IbmtokDbg) DbgPrint("IBMTOK: Transmit data\n");
+#endif
+ if (Adapter->Unplugged && !Adapter->UnpluggedResetInProgress)
+ {
+ //
+ // Do, nothing. This is most likely a stale interrupt. We
+ // wait until we get a ring status interrupt telling us that
+ // the cable is plugged in.
+ //
+ break;
+ }
+
+ TransmitDataArb =
+ (PARB_TRANSMIT_DATA_REQUEST)Adapter->ArbAddress;
+
+ //
+ // First see if we have to assign the command correlator.
+ //
+ NdisReadRegisterUchar(&(TransmitDataArb->CommandCorrelator), &TmpUchar);
+
+ TransmitPacket = FindPacketGivenCorrelator(Adapter, TmpUchar);
+
+ if (TransmitPacket == NULL)
+ {
+ BOOLEAN PacketRemoved;
+
+ //
+ // Have to take the correlator out of the SRB
+ // ourselves. This means that the SRB must still
+ // be occupied by the request for this transmit.
+ //
+ ASSERT(!Adapter->SrbAvailable);
+
+ FreedSrb = FALSE;
+
+ //
+ // This call will remove the packet from the SRB.
+ //
+ TransmitPacket =
+ RemoveTransmitFromSrb(Adapter, &PacketRemoved);
+
+ //
+ // This will be NULL if there was an error in
+ // the transmit command, but in that case why
+ // are we getting this ARB request?? Just exit.
+ // The WakeUpDpc will reset the card if it is hosed.
+ //
+ if ((TransmitPacket == (PNDIS_PACKET)NULL) || !PacketRemoved)
+ {
+ break;
+ }
+ }
+ else
+ {
+ FreedSrb = FALSE;
+
+ Reserved =
+ PIBMTOK_RESERVED_FROM_PACKET(TransmitPacket);
+ }
+
+ NdisDprReleaseSpinLock(&(Adapter->Lock));
+
+ //
+ // Fill in the AC and FC bytes.
+ //
+ NdisReadRegisterUshort(&(TransmitDataArb->DhbPointer), &TmpUshort);
+
+ DhbAddress = (PUCHAR)SRAM_PTR_TO_PVOID(Adapter,TmpUshort);
+
+ WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET,
+ ISRA_HIGH_ARB_FREE);
+
+
+ //
+ // Now copy the data down from TransmitPacket.
+ //
+ NdisQueryPacket(
+ TransmitPacket,
+ NULL,
+ NULL,
+ NULL,
+ &PacketLength);
+
+ IbmtokCopyFromPacketToBuffer(
+ TransmitPacket,
+ 0,
+ PacketLength,
+ (PCHAR)DhbAddress,
+ &DummyBytesCopied);
+
+
+ //
+ // Now worry about the ASB.
+ //
+ NdisDprAcquireSpinLock(&(Adapter->Lock));
+
+ IF_LOG('c');
+
+ //
+ // Set response in ASB, if available, else queue response
+ //
+ if (Adapter->AsbAvailable)
+ {
+ Adapter->AsbAvailable = FALSE;
+
+ Adapter->UseNextAsbForReceive = TRUE;
+
+ SetupTransmitStatusAsb(Adapter, TransmitPacket);
+ WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET,
+ ISRA_HIGH_RESPONSE_IN_ASB);
+
+ //
+ // LOOPBACK HERE!!
+ //
+ }
+ else
+ {
+#if DBG
+ if (IbmtokDbg) DbgPrint("W_ASB T\n");
+#endif
+
+ PutPacketOnWaitingForAsb(Adapter, TransmitPacket);
+
+ if (!(Adapter->OutstandingAsbFreeRequest))
+ {
+ Adapter->OutstandingAsbFreeRequest = TRUE;
+
+ WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET,
+ ISRA_HIGH_ASB_FREE_REQUEST);
+
+ IF_LOG('a');
+ }
+
+ //
+ // FINAL RETURNCODE CHECK HERE!
+ //
+ }
+
+ //
+ // If we freed up the SRB, queue the next command
+ // if there is one.
+ // Returns with lock released
+ //
+ if (FreedSrb)
+ {
+ IbmtokProcessSrbRequests(Adapter);
+ }
+
+ break;
+
+ default:
+
+ WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET,
+ ISRA_HIGH_ARB_FREE);
+ break;
+
+ }
+ }
+
+ if (IsrpHigh & ISRP_HIGH_ASB_FREE)
+ {
+ BOOLEAN ReceiveNeedsAsb = FALSE;
+ BOOLEAN TransmitNeedsAsb = FALSE;
+
+ //
+ // Check whether we have stuff to do.
+ //
+ IF_LOG('A');
+
+ if (Adapter->Unplugged && !Adapter->UnpluggedResetInProgress)
+ {
+ //
+ // Do, nothing. This is most likely a stale interrupt. We
+ // wait until we get a ring status interrupt telling us that
+ // the cable is plugged in.
+ //
+ break;
+ }
+
+ ASSERT(Adapter->AsbAvailable == FALSE);
+
+ ASSERT(Adapter->OutstandingAsbFreeRequest == TRUE);
+
+ if (Adapter->ReceiveWaitingForAsbList != (USHORT)-1)
+ {
+ ReceiveNeedsAsb = TRUE;
+ }
+
+ if (Adapter->FirstWaitingForAsb != NULL)
+ {
+ TransmitNeedsAsb = TRUE;
+ }
+
+ if (ReceiveNeedsAsb && (!TransmitNeedsAsb || Adapter->UseNextAsbForReceive))
+ {
+
+ SRAM_PTR ReceiveBufferPointer;
+ PVOID PFront;
+
+#if DBG
+ if (IbmtokDbg) DbgPrint("ASB R\n");
+#endif
+ IF_LOG('R');
+
+ //
+ // Save ReceiveWaitingForAsb so we can release
+ // the spinlock.
+ //
+ ReceiveBufferPointer = Adapter->ReceiveWaitingForAsbList;
+
+ if (Adapter->ReceiveWaitingForAsbList == Adapter->ReceiveWaitingForAsbEnd)
+ {
+ Adapter->ReceiveWaitingForAsbList = (USHORT)-1;
+
+ Adapter->ReceiveWaitingForAsbEnd = (USHORT)-1;
+ }
+ else
+ {
+ PFront = SRAM_PTR_TO_PVOID(Adapter,ReceiveBufferPointer);
+
+ NdisReadRegisterUshort(
+ ((PUSHORT)PFront),
+ &(Adapter->ReceiveWaitingForAsbList));
+ }
+
+ Adapter->AsbAvailable = FALSE;
+
+ Adapter->UseNextAsbForReceive = FALSE;
+
+ //
+ // Fill in the ASB and submit it.
+ //
+ SetupReceivedDataAsb(Adapter, ReceiveBufferPointer);
+
+ if (TransmitNeedsAsb)
+ {
+ WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET,
+ ISRA_HIGH_RESPONSE_IN_ASB | ISRA_HIGH_ASB_FREE_REQUEST);
+ }
+ else
+ {
+ Adapter->OutstandingAsbFreeRequest = FALSE;
+ WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET,
+ ISRA_HIGH_RESPONSE_IN_ASB);
+ }
+ }
+ else if (TransmitNeedsAsb)
+ {
+ PNDIS_PACKET AsbPacket = Adapter->FirstWaitingForAsb;
+ PIBMTOK_RESERVED Reserved = PIBMTOK_RESERVED_FROM_PACKET(AsbPacket);
+
+#if DBG
+ if (IbmtokDbg) DbgPrint("ASB T\n");
+#endif
+ IF_LOG('T');
+
+ //
+ // Take the packet off of WaitingForAsb;
+ //
+ Adapter->FirstWaitingForAsb = Reserved->Next;
+
+ Adapter->AsbAvailable = FALSE;
+
+ Adapter->UseNextAsbForReceive = TRUE;
+
+ //
+ // Now fill in the ASB and fire it off.
+ //
+ SetupTransmitStatusAsb(Adapter, AsbPacket);
+
+ if (ReceiveNeedsAsb || (Adapter->FirstWaitingForAsb != NULL))
+ {
+ WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET,
+ ISRA_HIGH_RESPONSE_IN_ASB | ISRA_HIGH_ASB_FREE_REQUEST);
+ }
+ else
+ {
+ Adapter->OutstandingAsbFreeRequest = FALSE;
+ WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET,
+ ISRA_HIGH_RESPONSE_IN_ASB);
+ }
+
+ //
+ // LOOPBACK HERE!!
+ //
+ }
+ else
+ {
+
+#if DBG
+ if (IbmtokDbg) DbgPrint("ASB -\n");
+#endif
+
+ Adapter->AsbAvailable = TRUE;
+ }
+ }
+
+ if (Adapter->CardType != IBM_TOKEN_RING_PCMCIA)
+ {
+ GET_ARB_ASB_BITS(Adapter, &IsrpHigh);
+ }
+ else
+ {
+ //
+ // disable interrupts on the card, since we don't trust ndissyncint to work
+ //
+ READ_ADAPTER_REGISTER(Adapter, ISRP_LOW, &Temp);
+
+ WRITE_ADAPTER_REGISTER(Adapter, ISRP_LOW,
+ Temp & (~(ISRP_LOW_NO_CHANNEL_CHECK | ISRP_LOW_INTERRUPT_ENABLE) ) );
+
+ //
+ // update arb_asb
+ //
+ IsrpHigh = (Adapter->IsrpBits) & (ISRP_HIGH_ARB_COMMAND | ISRP_HIGH_ASB_FREE);
+ Adapter->IsrpBits = (Adapter->IsrpBits) & (~(ISRP_HIGH_ARB_COMMAND | ISRP_HIGH_ASB_FREE));
+
+ //
+ // reenable interrupts on the card
+ //
+ WRITE_ADAPTER_REGISTER(Adapter, ISRP_LOW,
+ ISRP_LOW_NO_CHANNEL_CHECK | ISRP_LOW_INTERRUPT_ENABLE);
+ }
+ }
+
+ Adapter->HandleArbRunning = FALSE;
+
+ IF_LOG('J');
+
+ //
+ // This macro assumes it is called with the lock held,
+ // and releases it.
+ //
+ IBMTOK_DO_DEFERRED(Adapter);
+}
+
+STATIC
+VOID
+CleanupResetFailure(
+ IN PIBMTOK_ADAPTER Adapter,
+ PNDIS_STATUS IndicateStatus,
+ IN ULONG FailureCode,
+ IN ULONG ResetStage
+ )
+
+/*++
+
+Routine Description:
+
+ Clean up if a reset fails partway through. Called
+ from HandleResetStaging.
+
+ Called with the lock held and returns with it held.
+
+Arguments:
+
+ Adapter - The adapter that the reset is for.
+
+ IndicateStatus - Status to indicate to the protocols, or NULL.
+
+ FailureCode - A code to include in the error log.
+
+ ResetStage - The stage of the reset where the failure occured.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PLIST_ENTRY CurrentLink;
+ PIBMTOK_OPEN TempOpen;
+
+ if (!Adapter->UnpluggedResetInProgress)
+ {
+ //
+ // signal failure....
+ //
+ Adapter->CurrentRingState = NdisRingStateRingFailure;
+
+ //
+ // Indicate Status to all opens
+ //
+ CurrentLink = Adapter->OpenBindings.Flink;
+
+ while (CurrentLink != &(Adapter->OpenBindings))
+ {
+ TempOpen = CONTAINING_RECORD(CurrentLink, IBMTOK_OPEN, OpenList);
+
+ TempOpen->References++;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ if (IndicateStatus)
+ {
+ NdisIndicateStatus(TempOpen->NdisBindingContext,
+ NDIS_STATUS_CLOSED,
+ IndicateStatus,
+ sizeof(NDIS_STATUS));
+ }
+ else
+ {
+ NdisIndicateStatus(TempOpen->NdisBindingContext,
+ NDIS_STATUS_CLOSED,
+ NULL,
+ 0);
+ }
+
+ NdisIndicateStatusComplete(TempOpen->NdisBindingContext);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ CurrentLink = CurrentLink->Flink;
+
+ TempOpen->References--;
+ }
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 4,
+ handleResetStaging,
+ IBMTOK_ERRMSG_BRINGUP_FAILURE,
+ FailureCode,
+ ResetStage);
+ }
+ else
+ {
+ //
+ // Set this to false, we will try again later.
+ //
+ Adapter->LobeWireFaultIndicated = TRUE;
+ Adapter->UnpluggedResetInProgress = FALSE;
+ }
+
+ //
+ // Set Abort
+ //
+ Adapter->CurrentResetStage = 4;
+
+ SetResetVariables(Adapter);
+
+ Adapter->OpenInProgress = FALSE;
+ Adapter->NotAcceptingRequests = TRUE;
+
+ Adapter->ResetInProgress = FALSE;
+ Adapter->ResetInterruptAllowed = FALSE;
+ Adapter->ResetInterruptHasArrived = FALSE;
+
+ if (Adapter->ResettingOpen != NULL)
+ {
+ PIBMTOK_OPEN Open = Adapter->ResettingOpen;
+
+ //
+ // Decrement the reference count that was incremented
+ // in SetupForReset.
+ //
+ Open->References--;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteReset(Open->NdisBindingContext, NDIS_STATUS_FAILURE);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ }
+}
+
+STATIC
+VOID
+HandleResetStaging(
+ IN PIBMTOK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Handles the next stage of the transmit interrupt,
+ knowing that an SRB interrupt just came through.
+
+ Called with the lock held and returns with it held.
+
+Arguments:
+
+ Adapter - The adapter that the reset is for.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ USHORT TmpUshort;
+ UCHAR TmpUchar;
+
+ switch (Adapter->CurrentResetStage)
+ {
+ case 1:
+ {
+ //
+ // The adapter just finished being reset.
+ //
+ USHORT WrbOffset;
+ PSRB_BRING_UP_RESULT BringUpSrb;
+ PSRB_OPEN_ADAPTER OpenSrb;
+ UCHAR Value1, Value2;
+
+#if DBG
+if (IbmtokDbg) DbgPrint("IBMTOK: RESET done\n");
+#endif
+
+ READ_ADAPTER_REGISTER(Adapter, WRBR_LOW, &Value1);
+ READ_ADAPTER_REGISTER(Adapter, WRBR_HIGH, &Value2);
+
+ WrbOffset = (USHORT)(((USHORT)Value1) << 8) + (USHORT)Value2;
+
+ Adapter->InitialWrbOffset = WrbOffset;
+
+ BringUpSrb = (PSRB_BRING_UP_RESULT)(Adapter->SharedRam + WrbOffset);
+
+ NdisReadRegisterUshort(&(BringUpSrb->ReturnCode), &TmpUshort);
+
+ if (TmpUshort != 0x0000)
+ {
+ CleanupResetFailure (Adapter, NULL, TmpUshort, 1);
+ break;
+ }
+
+ //
+ // Now set up the open SRB request.
+ //
+ OpenSrb = (PSRB_OPEN_ADAPTER)
+ (Adapter->SharedRam + Adapter->InitialWrbOffset);
+
+ IBMTOK_ZERO_MAPPED_MEMORY(OpenSrb, sizeof(SRB_OPEN_ADAPTER));
+
+ NdisWriteRegisterUchar(&(OpenSrb->Command), SRB_CMD_OPEN_ADAPTER);
+ NdisWriteRegisterUshort(&(OpenSrb->OpenOptions),
+ (USHORT)(OPEN_CONTENDER |
+ (Adapter->EarlyTokenRelease ?
+ 0 :
+ OPEN_MODIFIED_TOKEN_RELEASE)));
+
+ NdisMoveToMappedMemory((PCHAR)OpenSrb->NodeAddress,
+ Adapter->NetworkAddress,
+ TR_LENGTH_OF_ADDRESS);
+
+ WRITE_IBMSHORT(OpenSrb->ReceiveBufferNum,
+ Adapter->NumberOfReceiveBuffers);
+ WRITE_IBMSHORT(OpenSrb->ReceiveBufferLen,
+ Adapter->ReceiveBufferLength);
+
+ WRITE_IBMSHORT(OpenSrb->TransmitBufferLen,
+ Adapter->TransmitBufferLength);
+
+ NdisWriteRegisterUchar(&(OpenSrb->TransmitBufferNum),
+ (UCHAR)Adapter->NumberOfTransmitBuffers);
+
+ Adapter->CurrentResetStage = 2;
+
+ WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET,
+ ISRA_HIGH_COMMAND_IN_SRB | ISRA_HIGH_SRB_FREE_REQUEST);
+
+ IF_LOG('1');
+
+ break;
+ }
+
+ case 2:
+ {
+ //
+ // Handle the result of the DIR.OPEN.ADAPTER command.
+ //
+ PSRB_OPEN_RESPONSE OpenResponseSrb;
+
+#if DBG
+if (IbmtokDbg) DbgPrint("IBMTOK: OPEN done\n");
+#endif
+
+ OpenResponseSrb = (PSRB_OPEN_RESPONSE)
+ (Adapter->SharedRam + Adapter->InitialWrbOffset);
+
+ NdisReadRegisterUchar(&(OpenResponseSrb->ReturnCode), &TmpUchar);
+
+ if (TmpUchar != 0)
+ {
+ NDIS_STATUS IndicateStatus;
+
+ NdisReadRegisterUshort(&(OpenResponseSrb->ErrorCode),
+ &(Adapter->OpenErrorCode));
+ Adapter->OpenErrorCode = IBMSHORT_TO_USHORT(Adapter->OpenErrorCode);
+ IndicateStatus =
+ NDIS_STATUS_TOKEN_RING_OPEN_ERROR |
+ (NDIS_STATUS)(Adapter->OpenErrorCode);
+
+ CleanupResetFailure (Adapter, &IndicateStatus, Adapter->OpenErrorCode, 2);
+ break;
+ }
+
+ IF_LOG('2');
+
+#if DBG
+ NdisReadRegisterUchar(&(OpenResponseSrb->ReturnCode),&TmpUchar);
+ if (IbmtokDbg) DbgPrint("IBMTOK: RESET OPEN, Return code = %x, at %lx\n",
+ TmpUchar,
+ OpenResponseSrb);
+#endif
+
+ NdisReadRegisterUshort(&(OpenResponseSrb->SrbPointer), &TmpUshort);
+ Adapter->SrbAddress = SRAM_PTR_TO_PVOID(Adapter,TmpUshort);
+
+ NdisReadRegisterUshort(&(OpenResponseSrb->SsbPointer), &TmpUshort);
+ Adapter->SsbAddress = SRAM_PTR_TO_PVOID(Adapter,TmpUshort);
+
+ NdisReadRegisterUshort(&(OpenResponseSrb->ArbPointer), &TmpUshort);
+ Adapter->ArbAddress = SRAM_PTR_TO_PVOID(Adapter,TmpUshort);
+
+ NdisReadRegisterUshort(&(OpenResponseSrb->AsbPointer), &TmpUshort);
+ Adapter->AsbAddress = SRAM_PTR_TO_PVOID(Adapter,TmpUshort);
+
+#if DBG
+if (IbmtokDbg)
+{
+ USHORT TmpUshort1;
+ USHORT TmpUshort2;
+ USHORT TmpUshort3;
+ USHORT TmpUshort4;
+ NdisReadRegisterUshort(&(OpenResponseSrb->SrbPointer), &TmpUshort1);
+ NdisReadRegisterUshort(&(OpenResponseSrb->SsbPointer), &TmpUshort2);
+ NdisReadRegisterUshort(&(OpenResponseSrb->ArbPointer), &TmpUshort3);
+ NdisReadRegisterUshort(&(OpenResponseSrb->AsbPointer), &TmpUshort4);
+ DbgPrint("IBMTOK: Offsets: SRB %x SSB %x ARB %x ASB %x\n",
+ IBMSHORT_TO_USHORT(TmpUshort1),
+ IBMSHORT_TO_USHORT(TmpUshort2),
+ IBMSHORT_TO_USHORT(TmpUshort3),
+ IBMSHORT_TO_USHORT(TmpUshort4));
+}
+#endif
+
+ //
+ // Now queue a SET.FUNCT.ADDRESS command if needed.
+ //
+ Adapter->CurrentCardFunctional = (TR_FUNCTIONAL_ADDRESS)0;
+
+ if (SetAdapterFunctionalAddress(Adapter) == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // This means that the command did not have to be
+ // queued, so we are done with this step.
+ //
+ if (SetAdapterGroupAddress(Adapter) == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // This one did not pend either, we are done.
+ //
+ IbmtokFinishAdapterReset(Adapter);
+ }
+ else
+ {
+ Adapter->CurrentResetStage = 4;
+
+ WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET,
+ ISRA_HIGH_COMMAND_IN_SRB | ISRA_HIGH_SRB_FREE_REQUEST);
+ }
+ }
+ else
+ {
+ Adapter->CurrentResetStage = 3;
+
+ WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET,
+ ISRA_HIGH_COMMAND_IN_SRB | ISRA_HIGH_SRB_FREE_REQUEST);
+ }
+
+ break;
+ }
+
+ case 3:
+ {
+ //
+ // The SET.FUNCT.ADDRESS command finished.
+ //
+ PSRB_GENERIC GenericSrb = (PSRB_GENERIC)Adapter->SrbAddress;
+ UCHAR ReturnCode;
+
+ NdisReadRegisterUchar(&(GenericSrb->ReturnCode), &ReturnCode);
+
+ IF_LOG('3');
+
+#if DBG
+if (IbmtokDbg) DbgPrint("IBMTOK: SET FUNCT done\n");
+#endif
+ if (ReturnCode == 0x00)
+ {
+ if (SetAdapterGroupAddress(Adapter) == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // This one did not pend, the dishes are done.
+ //
+ IbmtokFinishAdapterReset(Adapter);
+ }
+ else
+ {
+ Adapter->CurrentResetStage = 4;
+
+ WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET,
+ ISRA_HIGH_COMMAND_IN_SRB | ISRA_HIGH_SRB_FREE_REQUEST);
+ }
+ }
+ else if (ReturnCode != 0xfe)
+ {
+ CleanupResetFailure (Adapter, NULL, (ULONG)ReturnCode, 3);
+ }
+
+ break;
+ }
+
+ case 4:
+ {
+ //
+ // The SET.GROUP.ADDRESS command finished.
+ //
+ PSRB_GENERIC GenericSrb = (PSRB_GENERIC)Adapter->SrbAddress;
+ UCHAR ReturnCode;
+
+ NdisReadRegisterUchar(&(GenericSrb->ReturnCode), &ReturnCode);
+
+ IF_LOG('4');
+
+#if DBG
+if (IbmtokDbg) DbgPrint("IBMTOK: SET GROUP done\n");
+#endif
+ if (ReturnCode == 0x00)
+ {
+ IbmtokFinishAdapterReset(Adapter);
+ }
+ else if (ReturnCode != 0xfe)
+ {
+ CleanupResetFailure (Adapter, NULL, (ULONG)ReturnCode, 4);
+ }
+
+ break;
+ }
+ }
+}
+
+STATIC
+PNDIS_PACKET
+RemoveTransmitFromSrb(
+ IN PIBMTOK_ADAPTER Adapter,
+ OUT PBOOLEAN PacketRemoved
+ )
+
+/*++
+
+Routine Description:
+
+ Cleans a transmit out of the SRB if one was there.
+
+ NOTE : Should be called with the spinlock held!!!
+
+Arguments:
+
+ Adapter - The adapter that this packet is coming through.
+
+ PacketRemoved - TRUE if the packet was removed from the SRB.
+
+Return Value:
+
+ The packet removed.
+
+--*/
+
+{
+ PNDIS_PACKET TransmitPacket;
+ PIBMTOK_RESERVED Reserved;
+ UCHAR TmpUchar;
+ PSRB_TRANSMIT_DIR_FRAME TransmitSrb =
+ (PSRB_TRANSMIT_DIR_FRAME)Adapter->SrbAddress;
+
+
+ NdisReadRegisterUchar(&(TransmitSrb->ReturnCode), &TmpUchar);
+
+ if (TmpUchar == 0xfe)
+ {
+ //
+ // The TRANSMIT command was just put in the SRB, and
+ // the adapter has not yet had time to process it.
+ // We return now before setting SrbAvailable to TRUE,
+ // so the command is left to be processed.
+ //
+ // NOTE: If this happens on a call from inside the
+ // ARB_TRANSMIT_DATA interrupt handler, we will fail
+ // on an assertion when we return NULL.
+ //
+ *PacketRemoved = FALSE;
+
+ return (PNDIS_PACKET)NULL;
+ }
+
+ //
+ // if there was a packet in there, put it in
+ // the correlator array.
+ //
+ TransmitPacket = Adapter->TransmittingPacket;
+
+ Adapter->TransmittingPacket = (PNDIS_PACKET)NULL;
+
+ if (TransmitPacket == NULL)
+ {
+ *PacketRemoved = FALSE;
+
+ return(NULL);
+ }
+
+ //
+ // This will be TRUE whatever happens next.
+ //
+ *PacketRemoved = TRUE;
+
+ Reserved = PIBMTOK_RESERVED_FROM_PACKET(TransmitPacket);
+
+ //
+ // Check that the return code is OK.
+ //
+ if (TmpUchar != 0xff)
+ {
+ PIBMTOK_OPEN Open = PIBMTOK_OPEN_FROM_BINDING_HANDLE(Reserved->MacBindingHandle);
+ //
+ // Fail the transmit.
+ //
+
+ //
+ // If doing LOOPBACK, this should really be a check
+ // of ReadyToComplete etc.
+ //
+#if DBG
+if (IbmtokDbg) {
+ UCHAR TmpUchar1, TmpUchar2;
+ NdisReadRegisterUchar(&TransmitSrb->ReturnCode, &TmpUchar1);
+ NdisReadRegisterUchar(&TransmitSrb->Command, &TmpUchar2);
+ DbgPrint("IBMTOK: Transmit failed in SRB: %x for %x\n", TmpUchar1, TmpUchar2);
+}
+#endif
+
+#ifdef CHECK_DUP_SENDS
+ {
+ VOID IbmtokRemovePacketFromList(PIBMTOK_ADAPTER, PNDIS_PACKET);
+ IbmtokRemovePacketFromList(Adapter, TransmitPacket);
+ }
+#endif
+
+ Adapter->FrameTransmitErrors++;
+
+ NdisReleaseSpinLock(&(Adapter->Lock));
+
+ NdisCompleteSend(Open->NdisBindingContext, Reserved->Packet, NDIS_STATUS_FAILURE);
+
+ NdisAcquireSpinLock(&(Adapter->Lock));
+
+ Adapter->SendTimeout = FALSE;
+
+ //
+ // Decrement the reference count for the open.
+ //
+ Open->References--;
+
+ //
+ // This will cause an assertion failure if we were
+ // called from the ARB_TRANSMIT_DATA handler.
+ //
+ return (PNDIS_PACKET)NULL;
+ }
+
+ //
+ // Put the packet in the correlator array.
+ //
+ Reserved->CorrelatorAssigned = TRUE;
+ NdisReadRegisterUchar(&(TransmitSrb->CommandCorrelator), &(Reserved->CommandCorrelator));
+
+ PutPacketInCorrelatorArray(Adapter, TransmitPacket);
+
+ return TransmitPacket;
+}
+
+VOID
+SetupSrbCommand(
+ IN PIBMTOK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Fills in the SRB with the next request. It first checks
+ if there is a pended request outstanding, then
+ handles any queued transmits.
+
+ Called with the spinlock held.
+
+ NOTE: Should be called with Adapter->SrbAvailable == FALSE.
+
+Arguments:
+
+ Adapter - The Adapter to process interrupts for.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if (Adapter->PendQueue != NULL)
+ {
+ //
+ // This will copy the appropriate info out of the
+ // pend queue.
+ //
+ if (StartPendQueueOp(Adapter) == NDIS_STATUS_PENDING)
+ {
+ //
+ // Indicate the SRB command.
+ //
+ WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET,
+ ISRA_HIGH_COMMAND_IN_SRB);
+
+ return;
+ }
+ }
+
+ //
+ // If we reach here, the pend queue was empty or
+ // else StartPendQueueOp drained the entire queue
+ // without an operation needing the SRB.
+ //
+ if (Adapter->FirstTransmit != NULL)
+ {
+ //
+ // Remove the packet from the queue.
+ //
+ PNDIS_PACKET TransmitPacket = Adapter->FirstTransmit;
+
+ PIBMTOK_RESERVED Reserved =
+ PIBMTOK_RESERVED_FROM_PACKET(TransmitPacket);
+
+ Adapter->FirstTransmit = Reserved->Next;
+
+ Adapter->TransmittingPacket = TransmitPacket;
+
+ //
+ // set up the send - this sets the packet equal
+ // to Adapter->TransmittingPacket;
+ //
+ SetupTransmitFrameSrb(Adapter, TransmitPacket);
+
+ //
+ // Indicate the SRB command.
+ //
+
+ WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET,
+ ISRA_HIGH_COMMAND_IN_SRB);
+ }
+ else
+ {
+ Adapter->SrbAvailable = TRUE;
+ }
+}
+
+extern
+VOID
+IbmtokForceAdapterInterrupt(
+ IN PIBMTOK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This forces an adapter interrupt by queueing an
+ INTERRUPT SRB.
+
+ This is called with the spinlock held, and also
+ Adapter->SrbAvailable must be TRUE.
+
+Arguments:
+
+ Adapter - The Adapter to force the interrupt on.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PSRB_INTERRUPT InterruptSrb =
+ (PSRB_INTERRUPT)Adapter->SrbAddress;
+
+ ASSERT(Adapter->SrbAvailable);
+
+ Adapter->SrbAvailable = FALSE;
+
+ NdisWriteRegisterUchar(&(InterruptSrb->Command), SRB_CMD_INTERRUPT);
+ NdisWriteRegisterUchar(&(InterruptSrb->ReturnCode), 0xfe);
+
+ WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET,
+ ISRA_HIGH_COMMAND_IN_SRB);
+
+ IF_LOG('O');
+
+}
+
+STATIC
+VOID
+SetupTransmitFrameSrb(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets up the SRB for a TRANSMIT.DIR.FRAME.
+
+Arguments:
+
+ Adapter - The adapter that this packet is coming through.
+
+ Packet - The packet that is being sent.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSRB_TRANSMIT_DIR_FRAME TransmitSrb =
+ (PSRB_TRANSMIT_DIR_FRAME)Adapter->SrbAddress;
+
+ UNREFERENCED_PARAMETER(Packet);
+
+ NdisWriteRegisterUchar(&(TransmitSrb->Command), SRB_CMD_TRANSMIT_DIR_FRAME);
+ NdisWriteRegisterUchar(&(TransmitSrb->CommandCorrelator), 0x00);
+ NdisWriteRegisterUchar(&(TransmitSrb->ReturnCode), 0xfe); // will change to 0xff or error
+ NdisWriteRegisterUshort(&(TransmitSrb->StationId), USHORT_TO_IBMSHORT(0x00));
+
+ IF_LOG('x');
+}
+
+STATIC
+VOID
+SetupTransmitStatusAsb(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets up the ASB for a response from
+ a TRANSMIT.DATA.REQUEST.
+
+Arguments:
+
+ Adapter - The adapter that this packet is coming through.
+
+ Packet - The packet that has been copied down.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PASB_TRANSMIT_DATA_STATUS TransmitDataAsb;
+ UINT PacketLength;
+ PIBMTOK_RESERVED Reserved = PIBMTOK_RESERVED_FROM_PACKET(Packet);
+
+ NdisQueryPacket(Packet, NULL, NULL, NULL, &PacketLength);
+
+ TransmitDataAsb = (PASB_TRANSMIT_DATA_STATUS)
+ Adapter->AsbAddress;
+
+ NdisWriteRegisterUchar(&(TransmitDataAsb->Command), SRB_CMD_TRANSMIT_DIR_FRAME);
+ NdisWriteRegisterUchar(&(TransmitDataAsb->CommandCorrelator),
+ Reserved->CommandCorrelator);
+ NdisWriteRegisterUchar(&(TransmitDataAsb->ReturnCode), 0x00);
+ NdisWriteRegisterUshort(&(TransmitDataAsb->FrameLength),
+ USHORT_TO_IBMSHORT(PacketLength));
+
+ IF_LOG('X');
+
+}
+
+STATIC
+VOID
+SetupAdapterStatisticsSrb(
+ IN PIBMTOK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets up the SRB for a DLC.STATISTICS.
+
+Arguments:
+
+ Adapter - A pointer to the adapter.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PSRB_DLC_STATS StatsSrb = (PSRB_DLC_STATS)(Adapter->SrbAddress);
+
+ NdisWriteRegisterUchar(&(StatsSrb->Command), SRB_CMD_DLC_STATISTICS);
+ NdisWriteRegisterUshort(&(StatsSrb->StationId), USHORT_TO_IBMSHORT(0x00));
+ NdisWriteRegisterUchar((PUCHAR)(&(StatsSrb->ReturnCode)), 0x80); // Resets counters
+
+}
+
+STATIC
+VOID
+GetAdapterStatisticsFromSrb(
+ PIBMTOK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads the statistics after a DLC.STATISTICS has completed
+ and stores the results in the adapter structure.
+
+Arguments:
+
+ Adapter - A pointer to the adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSRB_DLC_STATS StatsSrb = (PSRB_DLC_STATS)(Adapter->SrbAddress);
+ PDLC_COUNTERS Counters;
+ USHORT TmpUshort;
+ UCHAR TmpUchar;
+
+ NdisReadRegisterUshort(&StatsSrb->CountersOffset, &TmpUshort);
+ Counters = (PDLC_COUNTERS) (((PUCHAR)(Adapter->SrbAddress)) +
+ IBMSHORT_TO_USHORT(TmpUshort));
+
+ NdisReadRegisterUshort(&Counters->TransmitCount, &TmpUshort);
+ Adapter->FramesTransmitted += IBMSHORT_TO_USHORT(TmpUshort);
+ NdisReadRegisterUshort(&Counters->ReceiveCount, &TmpUshort);
+ Adapter->FramesReceived += IBMSHORT_TO_USHORT(TmpUshort);
+ NdisReadRegisterUchar(&Counters->TransmitErrors, &TmpUchar);
+ Adapter->FrameTransmitErrors += TmpUchar;
+ NdisReadRegisterUchar(&Counters->ReceiveErrors, &TmpUchar);
+ Adapter->FrameReceiveErrors += TmpUchar;
+
+}
+
+STATIC
+VOID
+GetAdapterErrorsFromSrb(
+ PIBMTOK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads the statistics after a DIR.READ.LOG has completed
+ and stores the results in the adapter structure.
+
+Arguments:
+
+ Adapter - A pointer to the adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSRB_READ_LOG ReadLogSrb = (PSRB_READ_LOG)(Adapter->SrbAddress);
+ ULONG TmpUchar;
+
+ NdisReadRegisterUchar(&ReadLogSrb->LineErrors, &TmpUchar);
+ Adapter->LineErrors += TmpUchar;
+ NdisReadRegisterUchar(&ReadLogSrb->InternalErrors, &TmpUchar);
+ Adapter->InternalErrors += TmpUchar;
+ NdisReadRegisterUchar(&ReadLogSrb->BurstErrors, &TmpUchar);
+ Adapter->BurstErrors += TmpUchar;
+ NdisReadRegisterUchar(&ReadLogSrb->AcErrors, &TmpUchar);
+ Adapter->AcErrors += TmpUchar;
+ NdisReadRegisterUchar(&ReadLogSrb->AbortDelimeters, &TmpUchar);
+ Adapter->AbortDelimeters += TmpUchar;
+ NdisReadRegisterUchar(&ReadLogSrb->LostFrames, &TmpUchar);
+ Adapter->LostFrames += TmpUchar;
+ NdisReadRegisterUchar(&ReadLogSrb->ReceiveCongestionCount, &TmpUchar);
+ Adapter->ReceiveCongestionCount += TmpUchar;
+ NdisReadRegisterUchar(&ReadLogSrb->FrameCopiedErrors, &TmpUchar);
+ Adapter->FrameCopiedErrors += TmpUchar;
+ NdisReadRegisterUchar(&ReadLogSrb->FrequencyErrors, &TmpUchar);
+ Adapter->FrequencyErrors += TmpUchar;
+ NdisReadRegisterUchar(&ReadLogSrb->TokenErrors, &TmpUchar);
+ Adapter->TokenErrors += TmpUchar;
+}
+
+STATIC
+VOID
+SetupAdapterErrorsSrb(
+ PIBMTOK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets up the SRB for a DIR.READ.LOG command.
+
+Arguments:
+
+ Adapter - A pointer to the adapter.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PSRB_READ_LOG ReadLogSrb = (PSRB_READ_LOG)(Adapter->SrbAddress);
+
+ NdisWriteRegisterUchar(&(ReadLogSrb->Command), SRB_CMD_READ_LOG);
+}
+
+STATIC
+NDIS_STATUS
+StartPendQueueOp(
+ IN PIBMTOK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine goes through the pending queue until it
+ is empty or it finds a request that requires an SRB
+ command and hence pends.
+
+ NOTE: This routine is called with the lock held and
+ returns with it held.
+
+Arguments:
+
+ Adapter - The adapter that the queue should be checked for.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS - If the queue was drained completely.
+ NDIS_STATUS_PENDING - If a request required the SRB.
+
+--*/
+
+{
+ //
+ // Holds the operation on the head of the queue
+ // (we know it is not empty).
+ //
+ PIBMTOK_PEND_DATA PendOp;
+
+ //
+ // Holds status temporarily.
+ //
+ NDIS_STATUS RequestStatus;
+
+ while (Adapter->PendQueue != NULL)
+ {
+ //
+ // First take the head operation off the queue.
+ //
+ PendOp = Adapter->PendQueue;
+
+ Adapter->PendQueue = Adapter->PendQueue->Next;
+
+ if (Adapter->PendQueue == NULL)
+ {
+ //
+ // We have just emptied the list.
+ //
+ Adapter->EndOfPendQueue = NULL;
+ }
+
+ if (PendOp->RequestType == NdisRequestGeneric1)
+ {
+ //
+ // The pended operation is a result of the card having
+ // a counter overflow, and now we need to send the command.
+ //
+ if (PendOp->COMMAND.MAC.ReadLogPending)
+ {
+ //
+ // A DIR.READ.LOG command is needed.
+ //
+ SetupAdapterErrorsSrb(Adapter);
+ }
+ else
+ {
+ //
+ // A DLC.STATISTICS command is needed.
+ //
+ SetupAdapterStatisticsSrb(Adapter);
+ }
+
+ //
+ // Issue adapter command.
+ //
+ WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET,
+ ISRA_HIGH_COMMAND_IN_SRB);
+
+ RequestStatus = NDIS_STATUS_PENDING;
+ }
+ else
+ {
+ switch (PendOp->RequestType)
+ {
+ case NdisRequestSetInformation:
+
+ //
+ // It's a set filter or set address command.
+ //
+ if ((PNDIS_REQUEST_FROM_PIBMTOK_PEND_DATA(PendOp))->DATA.SET_INFORMATION.Oid ==
+ OID_GEN_CURRENT_PACKET_FILTER)
+ {
+ //
+ // It's a set filter command.
+ //
+ Adapter->OldPacketFilter = Adapter->CurrentPacketFilter;
+
+ Adapter->CurrentPacketFilter =
+ PendOp->COMMAND.NDIS.SET_FILTER.NewFilterValue;
+
+ RequestStatus = SetAdapterFunctionalAddress(Adapter);
+ }
+ else
+ {
+ //
+ // It's a set address command.
+ //
+#if DBG
+ if (IbmtokDbg)
+ {
+ DbgPrint("IBMTOK: Starting Command\n");
+ }
+#endif
+
+ if ((PNDIS_REQUEST_FROM_PIBMTOK_PEND_DATA(PendOp))->DATA.SET_INFORMATION.Oid ==
+ OID_802_5_CURRENT_FUNCTIONAL)
+ {
+ Adapter->CurrentFunctionalAddress =
+ PendOp->COMMAND.NDIS.SET_ADDRESS.NewAddressValue;
+
+ RequestStatus = SetAdapterFunctionalAddress(Adapter);
+ }
+ else
+ {
+ Adapter->CurrentGroupAddress =
+ PendOp->COMMAND.NDIS.SET_ADDRESS.NewAddressValue;
+
+ RequestStatus = SetAdapterGroupAddress(Adapter);
+ }
+ }
+
+ break;
+
+ case NdisRequestClose:
+
+ //
+ // It's a set filter command.
+ //
+ Adapter->OldPacketFilter = Adapter->CurrentPacketFilter;
+
+ Adapter->CurrentPacketFilter =
+ PendOp->COMMAND.NDIS.CLOSE.NewFilterValue;
+
+ RequestStatus = SetAdapterFunctionalAddress(Adapter);
+
+ break;
+
+ case NdisRequestGeneric2:
+
+ //
+ // It's a set address command.
+ //
+ Adapter->CurrentFunctionalAddress =
+ PendOp->COMMAND.NDIS.SET_ADDRESS.NewAddressValue;
+
+
+ RequestStatus = SetAdapterFunctionalAddress(Adapter);
+
+ break;
+
+
+ case NdisRequestGeneric3:
+
+ //
+ // It's a set address command.
+ //
+ Adapter->CurrentGroupAddress =
+ PendOp->COMMAND.NDIS.SET_ADDRESS.NewAddressValue;
+
+
+ RequestStatus = SetAdapterGroupAddress(Adapter);
+
+ break;
+
+
+ case NdisRequestQueryStatistics:
+
+ //
+ // We know it's a request for statistics.
+ //
+ RequestStatus = NDIS_STATUS_PENDING;
+
+ SetupAdapterErrorsSrb(Adapter);
+
+ PendOp->COMMAND.NDIS.STATISTICS.ReadLogPending = TRUE;
+
+ //
+ // Issue adapter command.
+ //
+ WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET,
+ ISRA_HIGH_COMMAND_IN_SRB);
+
+ break;
+
+ default:
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 3,
+ IBMTOK_ERRMSG_BAD_OP,
+ 1,
+ PendOp->RequestType);
+ }
+ }
+
+ if (RequestStatus == NDIS_STATUS_PENDING)
+ {
+ //
+ // Set this up for when the request completes.
+ //
+ Adapter->PendData = PendOp;
+
+ return NDIS_STATUS_PENDING;
+ }
+ else if (RequestStatus == NDIS_STATUS_SUCCESS)
+ {
+ PIBMTOK_OPEN TmpOpen;
+
+ switch (PendOp->RequestType)
+ {
+ case NdisRequestSetInformation:
+
+ //
+ // Complete the request.
+ //
+ TmpOpen = PendOp->COMMAND.NDIS.SET_FILTER.Open;
+
+ NdisReleaseSpinLock(&(Adapter->Lock));
+
+ NdisCompleteRequest(
+ PendOp->COMMAND.NDIS.SET_FILTER.Open->NdisBindingContext,
+ PNDIS_REQUEST_FROM_PIBMTOK_PEND_DATA(PendOp),
+ NDIS_STATUS_SUCCESS);
+
+ NdisAcquireSpinLock(&(Adapter->Lock));
+
+ Adapter->RequestTimeout = FALSE;
+
+ TmpOpen->References--;
+
+ break;
+
+ case NdisRequestClose:
+
+ PendOp->COMMAND.NDIS.CLOSE.Open->References--;
+ break;
+
+ case NdisRequestGeneric2:
+ case NdisRequestGeneric3:
+
+ PendOp->COMMAND.NDIS.SET_ADDRESS.Open->References--;
+ break;
+
+ case NdisRequestQueryStatistics:
+
+ NdisReleaseSpinLock(&(Adapter->Lock));
+
+ NdisCompleteQueryStatistics(
+ Adapter->NdisMacHandle,
+ PNDIS_REQUEST_FROM_PIBMTOK_PEND_DATA(PendOp),
+ NDIS_STATUS_SUCCESS);
+
+ NdisAcquireSpinLock(&(Adapter->Lock));
+
+ Adapter->RequestTimeout = FALSE;
+
+ Adapter->References--;
+
+ break;
+
+ default:
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 3,
+ startPendQueueOp,
+ IBMTOK_ERRMSG_BAD_OP,
+ PendOp->RequestType);
+ }
+ }
+ else
+ {
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 3,
+ startPendQueueOp,
+ IBMTOK_ERRMSG_INVALID_STATUS,
+ RequestStatus);
+ }
+ }
+
+ //
+ // We drained the entire queue without pending.
+ //
+ return NDIS_STATUS_SUCCESS;
+}
+
+STATIC
+BOOLEAN
+FinishPendQueueOp(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN BOOLEAN Successful
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when an SRB command completes.
+ It calles CompleteRequest if needed and does any other
+ cleanup required.
+
+ NOTE: This routine is called with the lock held and
+ returns with it held.
+
+ NOTE: This routine assumes that the pended operation to
+ be completed was specifically requested by the protocol
+ and, thus, that PendData->Request != NULL.
+
+Arguments:
+
+ Adapter - The adapter that the queue should be checked for.
+
+ Successful - Was the SRB command completed successfully.
+
+Return Value:
+
+ TRUE if the operation was completed, FALSE if another command
+ was submitted to the card to complete the operation.
+
+--*/
+
+{
+ PIBMTOK_PEND_DATA PendOp = Adapter->PendData;
+
+ ASSERT(PendOp != NULL);
+
+ switch (PendOp->RequestType)
+ {
+ case NdisRequestQueryStatistics:
+ //
+ // It was a request for global statistics.
+ //
+ if (Successful)
+ {
+ NDIS_STATUS StatusToReturn;
+
+ //
+ // Grab the data
+ //
+ GetAdapterErrorsFromSrb(Adapter);
+
+ //
+ // Fill in NdisRequest InformationBuffer
+ //
+ StatusToReturn = IbmtokFillInGlobalData(
+ Adapter,
+ PNDIS_REQUEST_FROM_PIBMTOK_PEND_DATA(PendOp));
+
+ //
+ // Complete statistics call
+ //
+ Adapter->PendData = NULL;
+
+ NdisReleaseSpinLock(&(Adapter->Lock));
+
+ NdisCompleteQueryStatistics(
+ Adapter->NdisMacHandle,
+ PNDIS_REQUEST_FROM_PIBMTOK_PEND_DATA(PendOp),
+ StatusToReturn);
+
+ NdisAcquireSpinLock(&(Adapter->Lock));
+
+ Adapter->RequestTimeout = FALSE;
+
+ Adapter->References--;
+ }
+ else
+ {
+ //
+ // Complete statistics call
+ //
+ Adapter->PendData = NULL;
+
+ NdisReleaseSpinLock(&(Adapter->Lock));
+
+ NdisCompleteQueryStatistics(
+ Adapter->NdisMacHandle,
+ PNDIS_REQUEST_FROM_PIBMTOK_PEND_DATA(PendOp),
+ NDIS_STATUS_FAILURE);
+
+ NdisAcquireSpinLock(&(Adapter->Lock));
+
+ Adapter->RequestTimeout = FALSE;
+
+ Adapter->References--;
+ }
+
+ break;
+
+ case NdisRequestSetInformation:
+
+
+ //
+ // It was a request for address change.
+ //
+#if DBG
+ if (IbmtokDbg)
+ {
+ if (Successful)
+ {
+ DbgPrint("IBMTOK: SUCCESS\n\n");
+ }
+ else
+ {
+ DbgPrint("IBMTOK: FAILURE\n\n");
+ }
+ }
+#endif
+
+ if (Successful)
+ {
+ PIBMTOK_OPEN TmpOpen;
+
+ //
+ // complete the operation.
+ //
+ if (PNDIS_REQUEST_FROM_PIBMTOK_PEND_DATA(Adapter->PendData)->DATA.SET_INFORMATION.Oid ==
+ OID_802_5_CURRENT_GROUP)
+ {
+ //
+ // Store new group address
+ //
+ Adapter->CurrentCardGroup = Adapter->CurrentGroupAddress;
+ }
+
+ Adapter->PendData = NULL;
+
+ TmpOpen = PendOp->COMMAND.NDIS.SET_FILTER.Open;
+
+ NdisReleaseSpinLock(&(Adapter->Lock));
+
+ NdisCompleteRequest(
+ PendOp->COMMAND.NDIS.SET_FILTER.Open->NdisBindingContext,
+ PNDIS_REQUEST_FROM_PIBMTOK_PEND_DATA(PendOp),
+ NDIS_STATUS_SUCCESS);
+
+ NdisAcquireSpinLock(&(Adapter->Lock));
+
+ Adapter->RequestTimeout = FALSE;
+
+ TmpOpen->References--;
+ }
+ else
+ {
+ //
+ // complete the operation.
+ //
+ PIBMTOK_OPEN TmpOpen;
+
+ Adapter->PendData = NULL;
+
+ TmpOpen = PendOp->COMMAND.NDIS.SET_FILTER.Open;
+
+ NdisReleaseSpinLock(&(Adapter->Lock));
+
+ NdisCompleteRequest(
+ PendOp->COMMAND.NDIS.SET_FILTER.Open->NdisBindingContext,
+ PNDIS_REQUEST_FROM_PIBMTOK_PEND_DATA(PendOp),
+ NDIS_STATUS_FAILURE);
+
+ NdisAcquireSpinLock(&(Adapter->Lock));
+
+ Adapter->RequestTimeout = FALSE;
+
+ TmpOpen->References--;
+ }
+
+ break;
+
+ case NdisRequestClose:
+ case NdisRequestGeneric2:
+ case NdisRequestGeneric3:
+
+ PendOp->COMMAND.NDIS.CLOSE.Open->References--;
+
+ break;
+ }
+
+ //
+ // Now finish up unsuccessful operations based on the type.
+ //
+ // NOTE: If we ever have cleanup for successful operations,
+ // we probably have to copy that code into the
+ // 'RequestStatus == NDIS_STATUS_SUCCESS' section
+ // in the function above.
+ //
+ if (!Successful)
+ {
+ switch (PendOp->RequestType)
+ {
+ case NdisRequestSetInformation:
+
+ //
+ // We know it was a set filter or set address.
+ //
+ if ((PNDIS_REQUEST_FROM_PIBMTOK_PEND_DATA(PendOp))->DATA.SET_INFORMATION.Oid ==
+ OID_GEN_CURRENT_PACKET_FILTER)
+ {
+ //
+ // It was a set filter.
+ //
+ Adapter->CurrentPacketFilter = Adapter->OldPacketFilter;
+
+ Adapter->CurrentCardFunctional = (TR_FUNCTIONAL_ADDRESS)0;
+ }
+ else
+ {
+ //
+ // It was a set address.
+ //
+ Adapter->CurrentFunctionalAddress = (TR_FUNCTIONAL_ADDRESS)0;
+ }
+
+ break;
+
+ case NdisRequestQueryStatistics:
+
+ break;
+
+ case NdisRequestClose:
+ case NdisRequestGeneric2:
+ case NdisRequestGeneric3:
+
+ break;
+
+ default:
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 3,
+ finishPendQueueOp,
+ IBMTOK_ERRMSG_BAD_OP,
+ PendOp->RequestType);
+
+ break;
+ }
+ }
+
+ return(TRUE);
+}
+
+STATIC
+NDIS_STATUS
+SetAdapterFunctionalAddress(
+ IN PIBMTOK_ADAPTER Adapter
+ )
+
+
+/*++
+
+Routine Description:
+
+ This routine checks the functional address on the adapter
+ against what it should be given the current packet filter
+ and functional address specified, and queues an update
+ if necessary.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ Adapter - The adapter to check.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS - If no change is necessary.
+ NDIS_STATUS_PENDING - If the change was queued.
+
+
+--*/
+{
+ //
+ // The new value we compute for the functional address that
+ // should be on the card.
+ //
+ TR_FUNCTIONAL_ADDRESS NewCardFunctional;
+
+ //
+ // Holds the value to be returned.
+ //
+ NDIS_STATUS StatusOfSet;
+
+ //
+ // Used if ALL_MULTICAST is selected.
+ //
+ ULONG AllFunctionalAddress = 0x7fffffff;
+
+ //
+ // First calculate what the new functional address
+ // should be.
+ //
+
+#if DBG
+ if (IbmtokDbg)
+ {
+ DbgPrint("IBMTOK: Current packet filter : 0x%x\n", Adapter->CurrentPacketFilter);
+ }
+#endif
+
+ if (Adapter->CurrentPacketFilter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL)
+ {
+ //
+ // We have to set all the bits in the address.
+ //
+ NewCardFunctional = AllFunctionalAddress;
+ }
+ else if (Adapter->CurrentPacketFilter & NDIS_PACKET_TYPE_FUNCTIONAL)
+ {
+ NewCardFunctional = Adapter->CurrentFunctionalAddress;
+ }
+ else
+ {
+ NewCardFunctional = (TR_FUNCTIONAL_ADDRESS)0;
+ }
+
+#if DBG
+ if (IbmtokDbg)
+ {
+ DbgPrint("IBMTOK: NewFunc is 0x%x\n", NewCardFunctional);
+ }
+#endif
+
+ //
+ // Now queue it up if needed.
+ //
+ if (NewCardFunctional == Adapter->CurrentCardFunctional)
+ {
+#if DBG
+ if (IbmtokDbg)
+ {
+ DbgPrint("IBMTOK: SUCCESS\n\n");
+ }
+#endif
+ StatusOfSet = NDIS_STATUS_SUCCESS;
+ }
+ else
+ {
+ SetupFunctionalSrb(Adapter, NewCardFunctional);
+ Adapter->CurrentCardFunctional = NewCardFunctional;
+
+ StatusOfSet = NDIS_STATUS_PENDING;
+ }
+
+ return StatusOfSet;
+}
+
+STATIC
+VOID
+SetupFunctionalSrb(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN TR_FUNCTIONAL_ADDRESS FunctionalAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets up the SRB for a DIR.SET.FUNCT.Address.
+
+Arguments:
+
+ Adapter - The adapter that this packet is coming through.
+
+ FunctionalAddress - The address to set up.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Used to set up the SRB request.
+ //
+ PSRB_SET_FUNCT_ADDRESS FunctSrb =
+ (PSRB_SET_FUNCT_ADDRESS)Adapter->SrbAddress;
+
+ //
+ // Used to hold the functional address temporarily.
+ //
+ UCHAR TempAddress[4];
+
+ //
+ // Used to copy down the functional address.
+ //
+ UINT i;
+
+ NdisWriteRegisterUchar(&(FunctSrb->Command), SRB_CMD_SET_FUNCTIONAL_ADDRESS);
+ NdisWriteRegisterUchar(&(FunctSrb->ReturnCode), 0xfe);
+
+ //
+ // Have to worry about setting the functional address
+ // since it is not aligned correctly.
+ //
+ IBMTOK_STORE_ULONG(TempAddress, FunctionalAddress);
+
+ for (i = 0; i < 4; i++)
+ {
+ NdisWriteRegisterUchar(&(FunctSrb->FunctionalAddress[i]), TempAddress[i]);
+ }
+}
+
+STATIC
+NDIS_STATUS
+SetAdapterGroupAddress(
+ IN PIBMTOK_ADAPTER Adapter
+ )
+
+
+/*++
+
+Routine Description:
+
+ This routine takes the value in Adapter->CurrentGroupAddress and
+ puts it out to the card.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ Adapter - The adapter to check.
+
+Return Value:
+
+ NDIS_STATUS_PENDING - If the change was queued.
+
+
+--*/
+{
+ //
+ // Holds the value to be returned.
+ //
+ SetupGroupSrb(Adapter, Adapter->CurrentGroupAddress);
+
+ return NDIS_STATUS_PENDING;
+}
+
+STATIC
+VOID
+SetupGroupSrb(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN TR_FUNCTIONAL_ADDRESS GroupAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets up the SRB for a DIR.SET.GROUP.ADDRESS.
+
+Arguments:
+
+ Adapter - The adapter that this packet is coming through.
+
+ GroupAddress - The address to set up.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Used to set up the SRB request.
+ //
+ PSRB_SET_GROUP_ADDRESS GroupSrb = (PSRB_SET_GROUP_ADDRESS)Adapter->SrbAddress;
+
+ //
+ // Used to hold the group address temporarily.
+ //
+ UCHAR TempAddress[4];
+
+ //
+ // Used to copy down the group address.
+ //
+ UINT i;
+
+
+ NdisWriteRegisterUchar(&(GroupSrb->Command), SRB_CMD_SET_GROUP_ADDRESS);
+ NdisWriteRegisterUchar(&(GroupSrb->ReturnCode), 0xfe);
+
+ //
+ // Have to worry about setting the group address
+ // since it is not aligned correctly.
+ //
+ IBMTOK_STORE_ULONG(TempAddress, GroupAddress);
+
+ for (i = 0; i < 4; i++)
+ {
+ NdisWriteRegisterUchar(&(GroupSrb->GroupAddress[i]), TempAddress[i]);
+ }
+}
+
+STATIC
+VOID
+SetupReceivedDataAsb(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN SRAM_PTR ReceiveBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets up the ASB for a response from
+ a RECEIVED.DATA ARB.
+
+Arguments:
+
+ Adapter - The adapter that this packet is coming through.
+
+ ReceiveBuffer - The first receive buffer in the frame.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PASB_RECEIVED_DATA_STATUS ReceivedDataAsb;
+
+ ReceivedDataAsb = (PASB_RECEIVED_DATA_STATUS)
+ Adapter->AsbAddress;
+
+ NdisWriteRegisterUchar(&(ReceivedDataAsb->Command), ARB_CMD_RECEIVED_DATA);
+ NdisWriteRegisterUchar(&(ReceivedDataAsb->ReturnCode), 0x00);
+ NdisWriteRegisterUshort(&(ReceivedDataAsb->StationId), 0x0000);
+ NdisWriteRegisterUshort(&(ReceivedDataAsb->ReceiveBuffer), ReceiveBuffer);
+}
+
+STATIC
+VOID
+PutPacketOnWaitingForAsb(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This queues a packet on the Waiting To Copy queue.
+ It is called and returns with the spinlock held.
+
+Arguments:
+
+ Adapter - The adapter that this packet is coming through.
+
+ Packet - The packet that is to be transmitted.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Points to the MAC reserved portion of this packet. This
+ // interpretation of the reserved section is only valid during
+ // the allocation phase of the packet.
+ //
+ PIBMTOK_RESERVED Reserved = PIBMTOK_RESERVED_FROM_PACKET(Packet);
+
+
+ ASSERT(sizeof(IBMTOK_RESERVED) <= sizeof(Packet->MacReserved));
+
+ if (Adapter->FirstWaitingForAsb == NULL)
+ {
+ Adapter->FirstWaitingForAsb = Packet;
+ }
+ else
+ {
+ PIBMTOK_RESERVED_FROM_PACKET(Adapter->FirstWaitingForAsb)->Next = Packet;
+ }
+
+ Adapter->LastWaitingForAsb = Packet;
+
+ Reserved->Next = NULL;
+}
+extern
+VOID
+IbmtokHandleDeferred(
+ IN PIBMTOK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles any pending resets and closes.
+ It is called during interrupt processing and also at
+ the end of every routine if needed.
+
+ NOTE: This routine is called with the spinlock held
+ and returns with it held.
+
+Arguments:
+
+ Adapter - The adapter to check deferred processing on.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIBMTOK_OPEN Open;
+
+ //
+ // Note that the following code depends on the fact that
+ // code above left the spinlock held.
+ //
+
+ //
+ // We will only come in here if the adapter's reference
+ // count is zero, so if a reset is in progress then we
+ // can start the reset.
+ //
+
+ //
+ // Make sure we don't start it twice!!
+ //
+ Adapter->References++;
+
+ if (Adapter->ResetInProgress && Adapter->CurrentResetStage == 0)
+ {
+ Adapter->CurrentResetStage = 1;
+
+ NdisReleaseSpinLock(&(Adapter->Lock));
+
+ IbmtokStartAdapterReset(Adapter);
+
+ NdisAcquireSpinLock(&(Adapter->Lock));
+ }
+
+ if (!Adapter->ResetInProgress && !IsListEmpty(&(Adapter->CloseDuringResetList)))
+ {
+ //
+ // Status of the Filter delete call.
+ //
+ NDIS_STATUS Status;
+
+ Open = CONTAINING_RECORD(
+ Adapter->CloseDuringResetList.Flink,
+ IBMTOK_OPEN,
+ OpenList);
+
+ Open->References++;
+#if DBG
+ if (IbmtokDbg) DbgPrint("IBMTOK: Calling TrDelete\n");
+#endif
+
+ Status = TrDeleteFilterOpenAdapter(
+ Adapter->FilterDB,
+ Open->NdisFilterHandle,
+ NULL);
+
+#if DBG
+ if (IbmtokDbg) DbgPrint("IBMTOK: TrDelete returned\n");
+#endif
+
+ //
+ // If the status is successful that merely implies that
+ // we were able to delete the reference to the open binding
+ // from the filtering code. If we have a successful status
+ // at this point we still need to check whether the reference
+ // count to determine whether we can close.
+ //
+ //
+ // The delete filter routine can return a "special" status
+ // that indicates that there is a current NdisIndicateReceive
+ // on this binding.
+ //
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Check whether the reference count is two. If
+ // it is then we can get rid of the memory for
+ // this open.
+ //
+ // A count of two indicates one for this routine
+ // and one for the filter which we *know* we can
+ // get rid of.
+ //
+ if (Open->References == 2)
+ {
+ //
+ // We are the only reference to the open. Remove
+ // it from the list and delete the memory.
+ //
+ RemoveEntryList(&Open->OpenList);
+
+ //
+ // Complete the close here.
+ //
+ if (Adapter->LookAhead == Open->LookAhead)
+ {
+ IbmtokAdjustMaxLookAhead(Adapter);
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteCloseAdapter(
+ Open->NdisBindingContext,
+ NDIS_STATUS_SUCCESS);
+
+ IBMTOK_FREE_PHYS(Open,sizeof(IBMTOK_OPEN));
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ }
+ else
+ {
+ //
+ // Remove the open from the list and put it on
+ // the closing list.
+ //
+ RemoveEntryList(&Open->OpenList);
+
+ InsertTailList(&Adapter->CloseList,&Open->OpenList);
+
+ //
+ // Account for this routines reference to the open
+ // as well as reference because of the filtering.
+ //
+ Open->References -= 2;
+ }
+ }
+ else if (Status == NDIS_STATUS_PENDING)
+ {
+ //
+ // If it pended, there may be
+ // operations queued.
+ // Returns with lock released
+ //
+ IbmtokProcessSrbRequests(Adapter);
+
+ //
+ // Now start closing down this open.
+ //
+ Open->BindingShuttingDown = TRUE;
+
+ //
+ // Remove the open from the open list and put it on
+ // the closing list.
+ //
+ RemoveEntryList(&Open->OpenList);
+ InsertTailList(&Adapter->CloseList,&Open->OpenList);
+
+ //
+ // Account for this routines reference to the open
+ // as well as reference because of the filtering.
+ //
+ Open->References -= 2;
+ }
+ else
+ {
+ //
+ // We should not get RESET_IN_PROGRESS or any other types.
+ //
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 3,
+ handleDeferred,
+ IBMTOK_ERRMSG_INVALID_STATUS,
+ Status);
+ }
+ }
+
+ //
+ // If there are any opens on the closing list and their
+ // reference counts are zero then complete the close and
+ // delete them from the list.
+ //
+ //
+ if (!IsListEmpty(&(Adapter->CloseList))){
+
+ Open = CONTAINING_RECORD(
+ Adapter->CloseList.Flink,
+ IBMTOK_OPEN,
+ OpenList);
+
+ if (!Open->References)
+ {
+ if (Adapter->LookAhead == Open->LookAhead)
+ {
+ IbmtokAdjustMaxLookAhead(Adapter);
+ }
+
+ NdisReleaseSpinLock(&(Adapter->Lock));
+
+ NdisCompleteCloseAdapter(
+ Open->NdisBindingContext,
+ NDIS_STATUS_SUCCESS);
+
+ NdisAcquireSpinLock(&(Adapter->Lock));
+ RemoveEntryList(&(Open->OpenList));
+ IBMTOK_FREE_PHYS(Open, sizeof(IBMTOK_OPEN));
+ }
+ }
+
+ Adapter->References--;
+}
+
+extern
+VOID
+IbmtokAbortPending(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN NDIS_STATUS AbortStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine aborts any pending requests, and calls
+ IbmtokAbortSends to abort any pending sends.
+
+ NOTE: This routine is called with the spinlock held
+ and returns with it held.
+
+Arguments:
+
+ Adapter - The adapter to abort.
+
+ AbortStatus - The status to complete requests with.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIBMTOK_OPEN Open;
+ PIBMTOK_PEND_DATA PendOp;
+
+ while (Adapter->PendQueue)
+ {
+ //
+ // Holds the operation on the head of the queue
+ //
+ PendOp = Adapter->PendQueue;
+
+ Adapter->PendQueue = Adapter->PendQueue->Next;
+
+ if (Adapter->PendQueue == NULL)
+ {
+ //
+ // We have just emptied the list.
+ //
+ Adapter->EndOfPendQueue = NULL;
+ }
+
+ switch (PendOp->RequestType)
+ {
+ case NdisRequestSetInformation:
+
+ //
+ // Complete the request.
+ //
+ Open = PendOp->COMMAND.NDIS.SET_FILTER.Open;
+
+ NdisDprReleaseSpinLock(&(Adapter->Lock));
+
+ NdisCompleteRequest(
+ Open->NdisBindingContext,
+ PNDIS_REQUEST_FROM_PIBMTOK_PEND_DATA(PendOp),
+ AbortStatus);
+
+ NdisDprAcquireSpinLock(&(Adapter->Lock));
+
+ Adapter->RequestTimeout = FALSE;
+
+ Open->References--;
+
+ break;
+
+ case NdisRequestClose:
+
+ PendOp->COMMAND.NDIS.CLOSE.Open->References--;
+ break;
+
+ case NdisRequestGeneric1:
+
+ //
+ // Submitted by the driver
+ //
+ IBMTOK_FREE_PHYS(PendOp, sizeof(IBMTOK_PEND_DATA));
+ Adapter->PendData = NULL;
+ break;
+
+ case NdisRequestGeneric2:
+ case NdisRequestGeneric3:
+
+ //
+ // Changes in address and filters due to a close
+ //
+ PendOp->COMMAND.NDIS.SET_ADDRESS.Open->References--;
+ break;
+
+
+ case NdisRequestQueryStatistics:
+
+ NdisDprReleaseSpinLock(&(Adapter->Lock));
+
+ NdisCompleteQueryStatistics(
+ Adapter->NdisMacHandle,
+ PNDIS_REQUEST_FROM_PIBMTOK_PEND_DATA(PendOp),
+ AbortStatus);
+
+ NdisDprAcquireSpinLock(&(Adapter->Lock));
+
+ Adapter->RequestTimeout = FALSE;
+
+ Adapter->References--;
+
+ break;
+ }
+ }
+
+ IbmtokAbortSends (Adapter, AbortStatus);
+}
+
+extern
+VOID
+IbmtokAbortSends(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN NDIS_STATUS AbortStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine aborts any pending sends.
+
+ NOTE: This routine is called with the spinlock held
+ and returns with it held.
+
+Arguments:
+
+ Adapter - The adapter to abort.
+
+ AbortStatus - The status to complete requests with.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIBMTOK_OPEN Open;
+ PNDIS_PACKET TransmitPacket;
+ PIBMTOK_RESERVED Reserved;
+ UINT i;
+
+ //
+ // First the packet in the SRB.
+ //
+ if (Adapter->TransmittingPacket != NULL)
+ {
+ TransmitPacket = Adapter->TransmittingPacket;
+ Adapter->TransmittingPacket = NULL;
+
+ Reserved = PIBMTOK_RESERVED_FROM_PACKET(TransmitPacket);
+ Open = PIBMTOK_OPEN_FROM_BINDING_HANDLE(Reserved->MacBindingHandle);
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteSend(Open->NdisBindingContext, TransmitPacket, AbortStatus);
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+ Open->References--;
+ }
+
+ //
+ // Then any that are queued up waiting to be given to the card.
+ //
+ while (Adapter->FirstTransmit)
+ {
+ TransmitPacket = Adapter->FirstTransmit;
+
+ Reserved = PIBMTOK_RESERVED_FROM_PACKET(TransmitPacket);
+ Adapter->FirstTransmit = Reserved->Next;
+
+ Open = PIBMTOK_OPEN_FROM_BINDING_HANDLE(Reserved->MacBindingHandle);
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteSend(
+ Open->NdisBindingContext,
+ TransmitPacket,
+ AbortStatus);
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+ Open->References--;
+ }
+
+ //
+ // Finally, the Correlator array (this will include any
+ // packets on WaitingForAsb).
+ //
+
+ for (i = 0; i < MAX_COMMAND_CORRELATOR; i++)
+ {
+ TransmitPacket = Adapter->CorrelatorArray[i];
+
+ if (TransmitPacket != NULL)
+ {
+ RemovePacketFromCorrelatorArray (Adapter, TransmitPacket);
+
+ Reserved = PIBMTOK_RESERVED_FROM_PACKET(TransmitPacket);
+ Open = PIBMTOK_OPEN_FROM_BINDING_HANDLE(Reserved->MacBindingHandle);
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteSend(
+ Open->NdisBindingContext,
+ Reserved->Packet,
+ AbortStatus);
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+ Open->References--;
+ }
+ }
+
+ Adapter->FirstWaitingForAsb = NULL;
+}
+
+VOID
+IbmtokWakeUpDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID Context,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+
+/*++
+
+Routine Description:
+
+ This DPC routine is queued every 2 seconds to check on the
+ queues. If an interrupt was not received
+ in the last two seconds and there should have been one,
+ then we abort all operations.
+
+Arguments:
+
+ Context - Really a pointer to the adapter.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PIBMTOK_ADAPTER Adapter = (PIBMTOK_ADAPTER)Context;
+
+ UNREFERENCED_PARAMETER(SystemSpecific1);
+ UNREFERENCED_PARAMETER(SystemSpecific2);
+ UNREFERENCED_PARAMETER(SystemSpecific3);
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ if ((Adapter->SendTimeout &&
+ ((Adapter->TransmittingPacket != NULL) ||
+ (Adapter->FirstTransmit != NULL))) ||
+ (Adapter->RequestTimeout && (Adapter->PendQueue != NULL)))
+ {
+ //
+ // We had a pending operation the last time we ran,
+ // and it has not been completed...we need to complete
+ // it now.
+ Adapter->NotAcceptingRequests = TRUE;
+
+ Adapter->SendTimeout = FALSE;
+ Adapter->RequestTimeout = FALSE;
+
+ //
+ // Complete any pending requests or sends.
+ //
+ IbmtokAbortPending(Adapter, STATUS_REQUEST_ABORTED);
+
+ Adapter->WakeUpErrorCount++;
+ IbmtokSetupForReset(Adapter, NULL);
+
+ IbmtokHandleDeferred(Adapter);
+ }
+ else
+ {
+ if ((Adapter->TransmittingPacket != NULL) ||
+ (Adapter->FirstTransmit != NULL))
+ {
+ Adapter->SendTimeout = TRUE;
+ }
+
+ if (Adapter->PendQueue != NULL)
+ {
+ Adapter->RequestTimeout = TRUE;
+ }
+ }
+
+ //
+ // If we've been unplugged, and there is not a reset in
+ // progress, try one.
+ //
+ if ((Adapter->LobeWireFaultIndicated) &&
+ (!Adapter->UnpluggedResetInProgress))
+ {
+ Adapter->UnpluggedResetInProgress = TRUE;
+
+ IbmtokSetupForReset(Adapter, NULL);
+
+ IbmtokHandleDeferred(Adapter);
+ }
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ //
+ // Fire off another Dpc to execute after 30 seconds
+ //
+ NdisSetTimer(&Adapter->WakeUpTimer, 30000);
+}
+
diff --git a/private/ntos/ndis/ibmtok/keywords.h b/private/ntos/ndis/ibmtok/keywords.h
new file mode 100644
index 000000000..0e3217834
--- /dev/null
+++ b/private/ntos/ndis/ibmtok/keywords.h
@@ -0,0 +1,54 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ keywords.h
+
+Abstract:
+
+ Contains all Ndis2 and Ndis3 mac-specific keywords.
+
+Author:
+
+ Bob Noradki
+
+Environment:
+
+ This driver is expected to work in DOS, OS2 and NT at the equivalent
+ of kernal mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+
+
+--*/
+#ifndef NDIS2
+#define NDIS2 0
+#endif
+
+#if NDIS2
+
+#define SLOTNUMBER NDIS_STRING_CONST("SLOTNUMBER")
+#define MAXPACKETSIZE NDIS_STRING_CONST("MAXPACKETSIZE")
+#define IOADDRESS NDIS_STRING_CONST("IOBASE")
+#define NETWORK_ADDRESS NDIS_STRING_CONST("NETADDRESS")
+#define TOKEN_RELEASE NDIS_STRING_CONST("EARLYTOKENRELEASE")
+
+#else // NDIS3
+
+#define SLOTNUMBER NDIS_STRING_CONST("SlotNumber")
+#define MAXPACKETSIZE NDIS_STRING_CONST("MaximumPacketSize")
+#define IOADDRESS NDIS_STRING_CONST("IoBaseAddress")
+#define NETWORK_ADDRESS NDIS_STRING_CONST("NetworkAddress")
+#define TOKEN_RELEASE NDIS_STRING_CONST("EarlyTokenRelease")
+
+#endif
diff --git a/private/ntos/ndis/ibmtok/makefile b/private/ntos/ndis/ibmtok/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/ibmtok/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/ibmtok/packet.c b/private/ntos/ndis/ibmtok/packet.c
new file mode 100644
index 000000000..dcff44c34
--- /dev/null
+++ b/private/ntos/ndis/ibmtok/packet.c
@@ -0,0 +1,732 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ transfer.c
+
+Abstract:
+
+ This module contains code to copy from ndis packets to ndis packets,
+ and also to copy from ndis packets to a buffer.
+
+Author:
+
+ Anthony V. Ercolano (Tonye) 12-Sept-1990
+
+Environment:
+
+ Works in kernel mode, but is not important that it does.
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+
+#include <tfilter.h>
+#include <tokhrd.h>
+#include <toksft.h>
+
+
+extern
+VOID
+IbmtokCopyFromPacketToBuffer(
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ IN UINT BytesToCopy,
+ OUT PCHAR Buffer,
+ OUT PUINT BytesCopied
+ )
+
+/*++
+
+Routine Description:
+
+ Copy from an ndis packet into a buffer.
+
+Arguments:
+
+ Packet - The packet to copy from.
+
+ Offset - The offset from which to start the copy.
+
+ BytesToCopy - The number of bytes to copy from the packet.
+
+ Buffer - The destination of the copy.
+
+ BytesCopied - The number of bytes actually copied. Can be less then
+ BytesToCopy if the packet is shorter than BytesToCopy.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ //
+ // Holds the number of ndis buffers comprising the packet.
+ //
+ UINT NdisBufferCount;
+
+ //
+ // Points to the buffer from which we are extracting data.
+ //
+ PNDIS_BUFFER CurrentBuffer;
+
+ //
+ // Holds the virtual address of the current buffer.
+ //
+ PVOID VirtualAddress;
+
+ //
+ // Holds the length of the current buffer of the packet.
+ //
+ UINT CurrentLength;
+
+ //
+ // Keep a local variable of BytesCopied so we aren't referencing
+ // through a pointer.
+ //
+ UINT LocalBytesCopied = 0;
+
+ //
+ // Take care of boundary condition of zero length copy.
+ //
+
+ *BytesCopied = 0;
+ if (!BytesToCopy) return;
+
+ //
+ // Get the first buffer.
+ //
+
+ NdisQueryPacket(Packet,
+ NULL,
+ &NdisBufferCount,
+ &CurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet.
+ //
+
+ if (!NdisBufferCount) return;
+
+ NdisQueryBuffer(CurrentBuffer, &VirtualAddress, &CurrentLength);
+
+ while (LocalBytesCopied < BytesToCopy) {
+
+ if (!CurrentLength) {
+
+ NdisGetNextBuffer(
+ CurrentBuffer,
+ &CurrentBuffer
+ );
+
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.
+ //
+
+ if (CurrentBuffer == NULL) break;
+
+ NdisQueryBuffer(CurrentBuffer, &VirtualAddress, &CurrentLength);
+ continue;
+
+ }
+
+ //
+ // Try to get us up to the point to start the copy.
+ //
+
+ if (Offset) {
+
+ if (Offset > CurrentLength) {
+
+ //
+ // What we want isn't in this buffer.
+ //
+
+ Offset -= CurrentLength;
+ CurrentLength = 0;
+ continue;
+
+ } else {
+
+ VirtualAddress = (PCHAR)VirtualAddress + Offset;
+ CurrentLength -= Offset;
+ Offset = 0;
+
+ }
+
+ }
+
+ //
+ // Copy the data.
+ //
+
+
+ {
+
+ //
+ // Holds the amount of data to move.
+ //
+ UINT AmountToMove;
+
+ AmountToMove =
+ ((CurrentLength <= (BytesToCopy - LocalBytesCopied))?
+ (CurrentLength):(BytesToCopy - LocalBytesCopied));
+
+ IBMTOK_MOVE_TO_MAPPED_MEMORY(
+ Buffer,
+ VirtualAddress,
+ AmountToMove
+ );
+
+ Buffer = (PCHAR)Buffer + AmountToMove;
+ VirtualAddress = (PCHAR)VirtualAddress + AmountToMove;
+
+ LocalBytesCopied += AmountToMove;
+ CurrentLength -= AmountToMove;
+
+ }
+
+ }
+
+ *BytesCopied = LocalBytesCopied;
+
+}
+
+extern
+VOID
+IbmtokCopyFromBufferToPacket(
+ IN PCHAR Buffer,
+ IN UINT BytesToCopy,
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ OUT PUINT BytesCopied
+ )
+
+/*++
+
+Routine Description:
+
+ Copy from a buffer into an ndis packet.
+
+Arguments:
+
+ Buffer - The packet to copy from.
+
+ Offset - The offset from which to start the copy.
+
+ BytesToCopy - The number of bytes to copy from the buffer.
+
+ Packet - The destination of the copy.
+
+ BytesCopied - The number of bytes actually copied. Will be less
+ than BytesToCopy if the packet is not large enough.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ //
+ // Holds the count of the number of ndis buffers comprising the
+ // destination packet.
+ //
+ UINT DestinationBufferCount;
+
+ //
+ // Points to the buffer into which we are putting data.
+ //
+ PNDIS_BUFFER DestinationCurrentBuffer;
+
+ //
+ // Points to the location in Buffer from which we are extracting data.
+ //
+ PUCHAR SourceCurrentAddress;
+
+ //
+ // Holds the virtual address of the current destination buffer.
+ //
+ PVOID DestinationVirtualAddress;
+
+ //
+ // Holds the length of the current destination buffer.
+ //
+ UINT DestinationCurrentLength;
+
+ //
+ // Keep a local variable of BytesCopied so we aren't referencing
+ // through a pointer.
+ //
+ UINT LocalBytesCopied = 0;
+
+
+ //
+ // Take care of boundary condition of zero length copy.
+ //
+
+ *BytesCopied = 0;
+ if (!BytesToCopy) return;
+
+ //
+ // Get the first buffer of the destination.
+ //
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ &DestinationBufferCount,
+ &DestinationCurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet.
+ //
+
+ if (!DestinationBufferCount) return;
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+
+ //
+ // Set up the source address.
+ //
+
+ SourceCurrentAddress = Buffer;
+
+
+ while (LocalBytesCopied < BytesToCopy) {
+
+ //
+ // Check to see whether we've exhausted the current destination
+ // buffer. If so, move onto the next one.
+ //
+
+ if (!DestinationCurrentLength) {
+
+ NdisGetNextBuffer(
+ DestinationCurrentBuffer,
+ &DestinationCurrentBuffer
+ );
+
+ if (DestinationCurrentBuffer == NULL) {
+
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.)
+ //
+
+ break;
+
+ }
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+
+ continue;
+
+ }
+
+ //
+ // Try to get us up to the point to start the copy.
+ //
+
+ if (Offset) {
+
+ if (Offset > DestinationCurrentLength) {
+
+ //
+ // What we want isn't in this buffer.
+ //
+
+ Offset -= DestinationCurrentLength;
+ DestinationCurrentLength = 0;
+ continue;
+
+ } else {
+
+ DestinationVirtualAddress = (PCHAR)DestinationVirtualAddress
+ + Offset;
+ DestinationCurrentLength -= Offset;
+ Offset = 0;
+
+ }
+
+ }
+
+
+ //
+ // Copy the data.
+ //
+
+ {
+
+ //
+ // Holds the amount of data to move.
+ //
+ UINT AmountToMove;
+
+ //
+ // Holds the amount desired remaining.
+ //
+ UINT Remaining = BytesToCopy - LocalBytesCopied;
+
+
+ AmountToMove = DestinationCurrentLength;
+
+ AmountToMove = ((Remaining < AmountToMove)?
+ (Remaining):(AmountToMove));
+
+ IBMTOK_MOVE_FROM_MAPPED_MEMORY(
+ DestinationVirtualAddress,
+ SourceCurrentAddress,
+ AmountToMove
+ );
+
+ SourceCurrentAddress += AmountToMove;
+ LocalBytesCopied += AmountToMove;
+ DestinationCurrentLength -= AmountToMove;
+
+ }
+
+ }
+
+ *BytesCopied = LocalBytesCopied;
+
+
+}
+
+extern
+VOID
+IbmtokCopyFromPacketToPacket(
+ IN PNDIS_PACKET Destination,
+ IN UINT DestinationOffset,
+ IN UINT BytesToCopy,
+ IN PNDIS_PACKET Source,
+ IN UINT SourceOffset,
+ OUT PUINT BytesCopied
+ )
+
+/*++
+
+Routine Description:
+
+ Copy from an ndis packet to an ndis packet.
+
+Arguments:
+
+ Destination - The packet should be copied in to.
+
+ DestinationOffset - The offset from the beginning of the packet
+ into which the data should start being placed.
+
+ BytesToCopy - The number of bytes to copy from the source packet.
+
+ Source - The ndis packet from which to copy data.
+
+ SourceOffset - The offset from the start of the packet from which
+ to start copying data.
+
+ BytesCopied - The number of bytes actually copied from the source
+ packet. This can be less than BytesToCopy if the source or destination
+ packet is too short.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ //
+ // Holds the count of the number of ndis buffers comprising the
+ // destination packet.
+ //
+ UINT DestinationBufferCount;
+
+ //
+ // Holds the count of the number of ndis buffers comprising the
+ // source packet.
+ //
+ UINT SourceBufferCount;
+
+ //
+ // Points to the buffer into which we are putting data.
+ //
+ PNDIS_BUFFER DestinationCurrentBuffer;
+
+ //
+ // Points to the buffer from which we are extracting data.
+ //
+ PNDIS_BUFFER SourceCurrentBuffer;
+
+ //
+ // Holds the virtual address of the current destination buffer.
+ //
+ PVOID DestinationVirtualAddress;
+
+ //
+ // Holds the virtual address of the current source buffer.
+ //
+ PVOID SourceVirtualAddress;
+
+ //
+ // Holds the length of the current destination buffer.
+ //
+ UINT DestinationCurrentLength;
+
+ //
+ // Holds the length of the current source buffer.
+ //
+ UINT SourceCurrentLength;
+
+ //
+ // Keep a local variable of BytesCopied so we aren't referencing
+ // through a pointer.
+ //
+ UINT LocalBytesCopied = 0;
+
+ //
+ // Take care of boundary condition of zero length copy.
+ //
+
+ *BytesCopied = 0;
+ if (!BytesToCopy) return;
+
+ //
+ // Get the first buffer of the destination.
+ //
+
+ NdisQueryPacket(
+ Destination,
+ NULL,
+ &DestinationBufferCount,
+ &DestinationCurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet.
+ //
+
+ if (!DestinationBufferCount) return;
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+
+ //
+ // Get the first buffer of the source.
+ //
+
+ NdisQueryPacket(
+ Source,
+ NULL,
+ &SourceBufferCount,
+ &SourceCurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet.
+ //
+
+ if (!SourceBufferCount) return;
+
+ NdisQueryBuffer(
+ SourceCurrentBuffer,
+ &SourceVirtualAddress,
+ &SourceCurrentLength
+ );
+
+ while (LocalBytesCopied < BytesToCopy) {
+
+ //
+ // Check to see whether we've exhausted the current destination
+ // buffer. If so, move onto the next one.
+ //
+
+ if (!DestinationCurrentLength) {
+
+ NdisGetNextBuffer(
+ DestinationCurrentBuffer,
+ &DestinationCurrentBuffer
+ );
+
+ if (DestinationCurrentBuffer == NULL) {
+
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.)
+ //
+
+ break;
+
+ }
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+ continue;
+
+ }
+
+
+ //
+ // Check to see whether we've exhausted the current source
+ // buffer. If so, move onto the next one.
+ //
+
+ if (!SourceCurrentLength) {
+
+ NdisGetNextBuffer(
+ SourceCurrentBuffer,
+ &SourceCurrentBuffer
+ );
+
+ if (SourceCurrentBuffer == NULL) {
+
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.)
+ //
+
+ break;
+
+ }
+
+ NdisQueryBuffer(
+ SourceCurrentBuffer,
+ &SourceVirtualAddress,
+ &SourceCurrentLength
+ );
+ continue;
+
+ }
+
+ //
+ // Try to get us up to the point to start the copy.
+ //
+
+ if (DestinationOffset) {
+
+ if (DestinationOffset > DestinationCurrentLength) {
+
+ //
+ // What we want isn't in this buffer.
+ //
+
+ DestinationOffset -= DestinationCurrentLength;
+ DestinationCurrentLength = 0;
+ continue;
+
+ } else {
+
+ DestinationVirtualAddress = (PCHAR)DestinationVirtualAddress
+ + DestinationOffset;
+ DestinationCurrentLength -= DestinationOffset;
+ DestinationOffset = 0;
+
+ }
+
+ }
+
+ //
+ // Try to get us up to the point to start the copy.
+ //
+
+ if (SourceOffset) {
+
+ if (SourceOffset > SourceCurrentLength) {
+
+ //
+ // What we want isn't in this buffer.
+ //
+
+ SourceOffset -= SourceCurrentLength;
+ SourceCurrentLength = 0;
+ continue;
+
+ } else {
+
+ SourceVirtualAddress = (PCHAR)SourceVirtualAddress
+ + SourceOffset;
+ SourceCurrentLength -= SourceOffset;
+ SourceOffset = 0;
+
+ }
+
+ }
+
+ //
+ // Copy the data.
+ //
+
+ {
+
+ //
+ // Holds the amount of data to move.
+ //
+ UINT AmountToMove;
+
+ //
+ // Holds the amount desired remaining.
+ //
+ UINT Remaining = BytesToCopy - LocalBytesCopied;
+
+ AmountToMove =
+ ((SourceCurrentLength <= DestinationCurrentLength)?
+ (SourceCurrentLength):(DestinationCurrentLength));
+
+ AmountToMove = ((Remaining < AmountToMove)?
+ (Remaining):(AmountToMove));
+
+ IBMTOK_MOVE_MEMORY(
+ DestinationVirtualAddress,
+ SourceVirtualAddress,
+ AmountToMove
+ );
+
+ DestinationVirtualAddress =
+ (PCHAR)DestinationVirtualAddress + AmountToMove;
+ SourceVirtualAddress =
+ (PCHAR)SourceVirtualAddress + AmountToMove;
+
+ LocalBytesCopied += AmountToMove;
+ SourceCurrentLength -= AmountToMove;
+ DestinationCurrentLength -= AmountToMove;
+
+ }
+
+ }
+
+ *BytesCopied = LocalBytesCopied;
+
+}
diff --git a/private/ntos/ndis/ibmtok/send.c b/private/ntos/ndis/ibmtok/send.c
new file mode 100644
index 000000000..a6cbddfb0
--- /dev/null
+++ b/private/ntos/ndis/ibmtok/send.c
@@ -0,0 +1,322 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ send.c
+
+Abstract:
+
+ This file contains the code for putting a packet through the
+ staged allocation for transmission.
+
+ This is a process of
+
+ 1) Calculating the what would need to be done to the
+ packet so that the packet can be transmitted on the hardware.
+
+ 2) Potentially allocating adapter buffers and copying user data
+ to those buffers so that the packet data is transmitted under
+ the hardware constraints.
+
+ 3) Allocating enough hardware ring entries so that the packet
+ can be transmitted.
+
+ 4) Relinquish thos ring entries to the hardware.
+
+ The overall structure and most of the code is taken from
+ the Lance driver by Tony Ercolano.
+
+Author:
+
+ Anthony V. Ercolano (Tonye) 12-Sept-1990
+ Adam Barr (adamba) 16-Nov-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent.
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+
+#include <tfilter.h>
+#include <tokhrd.h>
+#include <toksft.h>
+
+
+#if DEVL
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+#if DBG
+extern INT IbmtokDbg;
+
+extern UCHAR Packets[5][64];
+extern UCHAR NextPacket;
+#endif
+
+
+
+#ifdef CHECK_DUP_SENDS
+
+//
+// CHECK_DUP_SENDS enables checking ownership of packets, to
+// make sure we are not given the same packet twice, or
+// complete the same packet twice.
+//
+
+#define PACKET_LIST_SIZE 50
+
+PNDIS_PACKET IbmtokPacketList[PACKET_LIST_SIZE];
+IbmtokPacketListSize = 0;
+IbmtokPacketsAdded = 0;
+IbmtokPacketsRemoved = 0;
+
+VOID
+IbmtokAddPacketToList(
+ PIBMTOK_ADAPTER Adapter,
+ PNDIS_PACKET NewPacket
+ )
+{
+ INT i;
+
+++IbmtokPacketsAdded;
+
+ for (i=0; i<IbmtokPacketListSize; i++) {
+
+ if (IbmtokPacketList[i] == NewPacket) {
+
+ DbgPrint("IBMTOK: dup send of %lx\n", NewPacket);
+
+ }
+
+ }
+
+ IbmtokPacketList[IbmtokPacketListSize] = NewPacket;
+ ++IbmtokPacketListSize;
+
+}
+
+VOID
+IbmtokRemovePacketFromList(
+ PIBMTOK_ADAPTER Adapter,
+ PNDIS_PACKET OldPacket
+ )
+{
+ INT i;
+
+++IbmtokPacketsRemoved;
+
+ for (i=0; i<IbmtokPacketListSize; i++) {
+
+ if (IbmtokPacketList[i] == OldPacket) {
+
+ break;
+
+ }
+
+ }
+
+ if (i == IbmtokPacketListSize) {
+
+ DbgPrint("IBMTOK: bad remove of %lx\n", OldPacket);
+
+ } else {
+
+ --IbmtokPacketListSize;
+ IbmtokPacketList[i] = IbmtokPacketList[IbmtokPacketListSize];
+
+ }
+
+}
+#endif // CHECK_DUP_SENDS
+
+
+extern
+NDIS_STATUS
+IbmtokSend(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ The IbmtokSend request instructs a MAC to transmit a packet through
+ the adapter onto the medium.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to IBMTOK_OPEN.
+
+ Packet - A pointer to a descriptor for the packet that is to be
+ transmitted.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+
+{
+
+ //
+ // Holds the status that should be returned to the caller.
+ //
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_PENDING;
+
+ //
+ // Pointer to the adapter.
+ //
+ PIBMTOK_ADAPTER Adapter;
+
+ ULONG PacketLength;
+
+ Adapter = PIBMTOK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ NULL,
+ NULL,
+ &PacketLength
+ );
+
+ //
+ // Check that the packet will go on the wire. Note: I do not
+ // check that we have enough receive space to receive a packet
+ // of this size -- it is up to a protocol to work this out.
+ //
+
+ if ((PacketLength < 14) ||
+ (PacketLength > Adapter->MaxTransmittablePacket)) {
+
+ return(NDIS_STATUS_INVALID_PACKET);
+
+ }
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ Adapter->References++;
+
+ if (Adapter->Unplugged) {
+
+ StatusToReturn = NDIS_STATUS_DEVICE_FAILED;
+
+ } else if (!Adapter->NotAcceptingRequests) {
+
+ PIBMTOK_OPEN Open;
+ PIBMTOK_RESERVED Reserved = PIBMTOK_RESERVED_FROM_PACKET(Packet);
+
+ Open = PIBMTOK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ if (!Open->BindingShuttingDown) {
+
+ //
+ // We do not have to increment the open count. Since we hold
+ // the lock for the entire function we cannot have the open
+ // removed out from under us.
+ //
+
+ //
+ // NOTE NOTE NOTE !!!!!!
+ //
+ // There is an assumption in the code that no pointer
+ // (which are really handles) to an ndis packet will have
+ // its low bit set. (Always have even byte alignment.)
+ //
+
+ ASSERT(!((UINT)Packet & 1));
+
+ //
+ // ALL packets go on the wire (loopback is done
+ // by the card).
+ //
+#ifdef CHECK_DUP_SENDS
+ IbmtokAddPacketToList(Adapter, Packet);
+#endif
+
+ Reserved->MacBindingHandle = MacBindingHandle;
+ Reserved->Packet = Packet;
+
+ if (Adapter->FirstTransmit == NULL) {
+
+ Adapter->FirstTransmit = Packet;
+
+ } else {
+
+ PIBMTOK_RESERVED_FROM_PACKET(Adapter->LastTransmit)->Next = Packet;
+
+ }
+
+ Adapter->LastTransmit = Packet;
+
+ Reserved->Next = NULL;
+
+ //
+ // Increment the reference on the open since it
+ // will be leaving this packet around on the transmit
+ // queues.
+ //
+
+ Open->References++;
+
+ //
+ // This will send the transmit SRB command
+ // if the SRB is available.
+ //
+
+ IbmtokProcessSrbRequests(
+ Adapter
+ );
+
+ } else {
+
+ StatusToReturn = NDIS_STATUS_CLOSING;
+
+ }
+
+ } else {
+
+ if (Adapter->ResetInProgress) {
+
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ } else if (Adapter->AdapterNotOpen) {
+
+ StatusToReturn = NDIS_STATUS_FAILURE;
+
+ } else {
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ IBMTOK_ERRMSG_INVALID_STATE,
+ 2
+ );
+
+ }
+
+ }
+
+
+ //
+ // This macro assumes it is called with the lock held,
+ // and releases it.
+ //
+
+ IBMTOK_DO_DEFERRED(Adapter);
+ return StatusToReturn;
+}
+
diff --git a/private/ntos/ndis/ibmtok/sources b/private/ntos/ndis/ibmtok/sources
new file mode 100644
index 000000000..1ee4f3023
--- /dev/null
+++ b/private/ntos/ndis/ibmtok/sources
@@ -0,0 +1,48 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis2
+
+TARGETNAME=ibmtok
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+C_DEFINES=$(C_DEFINES)
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+INCLUDES=..\inc;..\..\inc
+
+SOURCES=ibmtok.c \
+ interrup.c \
+ send.c \
+ packet.c \
+ transfer.c \
+ ibmtok.rc
+
+RELATIVE_DEPTH=..\..
+
+MSC_WARNING_LEVEL=/W3 /WX
+
diff --git a/private/ntos/ndis/ibmtok/tokhrd.h b/private/ntos/ndis/ibmtok/tokhrd.h
new file mode 100644
index 000000000..ab0721177
--- /dev/null
+++ b/private/ntos/ndis/ibmtok/tokhrd.h
@@ -0,0 +1,667 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ tokhrd.h
+
+Abstract:
+
+ The hardware-related definitions for the IBMTOK drivers.
+
+
+Author:
+
+ Anthony V. Ercolano (tonye) creation-date 19-Jun-1990
+ Adam Barr (adamba) 18-Feb-1991
+
+Environment:
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+ Sean Selitrennikoff - 9/??/91
+ Added/Changed definitions to allow for Microchannel cards too.
+
+
+--*/
+
+#ifndef _IBMTOKHARDWARE_
+#define _IBMTOKHARDWARE_
+
+//
+// Types of adapters this driver can work with
+//
+#define IBM_TOKEN_RING_PCMCIA 1
+
+//
+// Initialization Status Flag Bit Settings
+//
+
+#define RINGSPEEDLISTEN 0x40
+
+//
+// Token-Ring Controller Configuration Register control bits
+// Used by IBM_TOKEN_RING_16_4_CREDIT_CARD_ADAPTER
+//
+// #define DEFAULT_MMIO 0xD4000
+// #define DEFAULT_RAM 0xD6
+#define DEFAULT_MMIO 0xC2000
+#define DEFAULT_RAM 0xD0
+
+#define SHARED_RAM_64K 0xC
+#define SHARED_RAM_32K 0x8
+#define SHARED_RAM_16K 0x4
+#define SHARED_RAM_8K 0x0
+
+#define RING_SPEED_16_MPS 0x2
+#define RING_SPEED_4_MPS 0x0
+
+#define PRIMARY 0x0
+#define ALTERNATE 0x1
+
+#define DEFAULT_NIBBLE_2 0x6
+
+#define NIBBLE_0 0x00
+#define NIBBLE_1 0x10
+#define NIBBLE_2 0x20
+#define NIBBLE_3 0x30
+#define RELEASE_TR_CONTROLLER 0x40
+
+
+//
+// IBM Token Ring Adapter IDs
+//
+
+#define IBMTOK1_ADAPTER_ID 0xE000
+#define IBMTOK2_ADAPTER_ID 0xE001
+
+//
+// Start of I/O ports based on which adapter it is.
+//
+
+#define PRIMARY_ADAPTER_OFFSET 0xa20
+#define ALTERNATE_ADAPTER_OFFSET 0xa24
+
+//
+// Offsets from above of the actual ports used.
+//
+
+#define SWITCH_READ_1 0x000
+#define RESET_LATCH 0x001
+#define SWITCH_READ_2 0x002
+#define RESET_RELEASE 0x002
+#define INTERRUPT_RELEASE_ISA_ONLY 0x003
+
+
+//
+// Registers in the MMIO. These are in the Attachment
+// Control Area, which starts at offset 0x1e00 of the ACA.
+//
+
+#define RRR_LOW 0x1e00
+#define RRR_HIGH 0x1e01
+#define WRBR_LOW 0x1e02
+#define WRBR_HIGH 0x1e03
+#define ISRP_LOW 0x1e08
+#define ISRP_LOW_RESET 0x1e28
+#define ISRP_LOW_SET 0x1e48
+#define ISRP_HIGH 0x1e09
+#define ISRP_HIGH_RESET 0x1e29
+#define ISRA_LOW 0x1e0a
+#define ISRA_HIGH 0x1e0b
+#define ISRA_HIGH_SET 0x1e4b
+#define TCR_LOW 0x1e0c
+#define TCR_HIGH 0x1e0d
+#define TVR_LOW 0x1e0e
+#define TVR_HIGH 0x1e0f
+#define SRPR_LOW 0x1e18
+#define SRPR_HIGH 0x1e19
+
+
+//
+// These are registers in the AIP (aka the ID PROM),
+// which starts at offset 0x1f00 of the ACA.
+//
+
+#define CHANNEL_IDENTIFIER 0x1f30
+#define TOTAL_ADAPTER_RAM 0x1fa6
+#define SHARED_RAM_PAGING 0x1fa8
+#define MAX_4_MBPS_DHB 0x1faa
+#define MAX_16_MBPS_DHB 0x1fac
+
+
+//
+// Bits in the ISRA Low (even) register.
+//
+
+#define ISRA_LOW_TIMER_INTERRUPT 0x40
+#define ISRA_LOW_INTERRUPT_MASK 0x01
+
+//
+// Bits in the ISRA High (odd) register.
+//
+
+#define ISRA_HIGH_COMMAND_IN_SRB 0x20
+#define ISRA_HIGH_RESPONSE_IN_ASB 0x10
+#define ISRA_HIGH_SRB_FREE_REQUEST 0x08
+#define ISRA_HIGH_ASB_FREE_REQUEST 0x04
+#define ISRA_HIGH_ARB_FREE 0x02
+#define ISRA_HIGH_SSB_FREE 0x01
+
+//
+// Bits in the ISRP Low (even) register.
+//
+
+#define ISRP_LOW_NO_CHANNEL_CHECK 0x80
+#define ISRP_LOW_INTERRUPT_ENABLE 0x40
+
+//
+// Bits in the ISRP High (odd) register.
+//
+
+#define ISRP_HIGH_ADAPTER_CHECK 0x40
+#define ISRP_HIGH_SRB_RESPONSE 0x20
+#define ISRP_HIGH_ASB_FREE 0x10
+#define ISRP_HIGH_ARB_COMMAND 0x08
+#define ISRP_HIGH_SSB_RESPONSE 0x04
+
+//
+// Bits in the TCR Low (even) register.
+//
+
+#define TCR_LOW_INTERRUPT_MASK 0x80
+#define TCR_LOW_RELOAD_TIMER 0x40
+#define TCR_LOW_COUNTER_ENABLE 0x20
+
+
+#define WRITE_ADAPTER_REGISTER(a, r, v) \
+ NdisWriteRegisterUchar((PUCHAR)((a)->MmioRegion + (r)), (UCHAR)(v))
+
+#define READ_ADAPTER_REGISTER(a, r, v) \
+ NdisReadRegisterUchar((PUCHAR)(a)->MmioRegion + (r), (PUCHAR)(v))
+
+
+#define WRITE_ADAPTER_PORT(a, p, v) \
+ NdisWritePortUchar((a)->NdisAdapterHandle, (ULONG)((a)->IbmtokPortAddress + (p)), (UCHAR)(v))
+
+#define READ_ADAPTER_PORT(a, p, v) \
+ NdisReadPortUchar((a)->NdisAdapterHandle, (ULONG)(a)->IbmtokPortAddress + (p), (PUCHAR)(v))
+
+
+
+//
+// An IBMSHORT is a short that is in IBM byte ordering,
+// with the high and low bytes reversed.
+//
+
+typedef USHORT IBMSHORT;
+
+
+//
+// NOTE: These are dangerous because s appears twice in them.
+//
+
+#define READ_IBMSHORT(s) (USHORT)((((PUCHAR)&s)[0] << 8) + ((PUCHAR)&s)[1])
+#define WRITE_IBMSHORT(s, val) {\
+ USHORT _tmp; \
+ _tmp = (USHORT)((((val) >> 8) & 0xff) | (((val) & 0xff) << 8)); \
+ NdisWriteRegisterUshort((PUSHORT)&s, _tmp); \
+}
+#define USHORT_TO_IBMSHORT(val) (IBMSHORT)((((val) >> 8) & 0xff) | \
+ (((val) & 0xff) << 8))
+#define IBMSHORT_TO_USHORT(val) (USHORT)((((val) >> 8) & 0xff) | \
+ (((val) & 0xff) << 8))
+
+
+//
+// An SRAM_PTR is a pointer into the Shared RAM on the adapter.
+// It uses the IBM byte ordering.
+//
+
+typedef IBMSHORT SRAM_PTR;
+
+#define NULL_SRAM_PTR ((SRAM_PTR)0x0000)
+
+#define SRAM_PTR_TO_PVOID(a, p) \
+ ((PVOID)((a)->SharedRam + IBMSHORT_TO_USHORT(p)))
+
+#define SHARED_RAM_ADDRESS(a, p) \
+ ((PVOID)((a)->SharedRam + ((ULONG)(p))))
+
+
+//
+// Macros to deal with the frame status field.
+//
+
+#define GET_FRAME_STATUS_HIGH_AC(Fs) ((UCHAR)(((Fs) & 0xc0) >> 6))
+#define GET_FRAME_STATUS_LOW_AC(Fs) ((UCHAR)(((Fs) & 0x0c) >> 2))
+
+#define AC_NOT_RECOGNIZED 0x00
+#define AC_INVALID 0x01
+#define AC_NOT_COPIED 0x10
+#define AC_COPIED 0x11
+
+
+//
+// Some adapters have to have the upper section of the
+// Shared RAM zeroed out after initialization.
+//
+
+#define SHARED_RAM_ZERO_OFFSET ((PVOID)0xfe00)
+#define SHARED_RAM_ZERO_LENGTH 0x0200
+
+
+//
+// The highest command correlator used by the adapter
+// transmit logic.
+//
+
+#define MAX_COMMAND_CORRELATOR 128
+
+
+//
+// This macro is used to set up the SRPR depending on
+// the given address (should only be called if it is
+// known that the adapter supports Shared RAM Paging!!).
+//
+
+#define SETUP_SRPR(Adapter, Address) \
+ WRITE_ADAPTER_REGISTER((Adapter), SRPR_LOW, ((ULONG)(Address) >> 14))
+
+
+//
+// This macro retrieves the part of an address that
+// is used once SETUP_SRPR has been called.
+//
+
+#define SHARED_RAM_LOW_BITS(Address) \
+ ((ULONG)(Address) & 0x3fff)
+
+
+//
+// This macro determines if an address will fit on a
+// single Shared RAM page. It makes sure that the beginning
+// and end of the sequence have the same high two bits.
+//
+
+#define SINGLE_SHARED_RAM_PAGE(Address, Length) \
+ (((ULONG)(Address) & 0xc000) == (((ULONG)(Address)+(Length)-1) & 0xc000))
+
+
+
+//
+// Various structures which are read after the adapter
+// is reset.
+//
+
+typedef struct _ADAPTER_ADDRESS {
+ UCHAR NodeAddress[6];
+ UCHAR GroupAddress[4];
+ UCHAR FunctionalAddress[4];
+} ADAPTER_ADDRESS, * PADAPTER_ADDRESS;
+
+
+typedef struct _ADAPTER_PARAMETERS {
+ UCHAR PhysicalAddress[4];
+ UCHAR NaunNodeAddress[6];
+ UCHAR NaunPhysicalAddress[4];
+ UCHAR LastPoolAddress[6];
+ UCHAR Reserved1[2];
+ IBMSHORT TransmitAccessPriority;
+ IBMSHORT SourceClassAuthorization;
+ IBMSHORT LastAttentionCode;
+ UCHAR LastSourceAddress[6];
+ IBMSHORT LastBeaconType;
+ IBMSHORT LastMajorVector;
+ IBMSHORT RingStatus;
+ IBMSHORT SoftErrorTimer;
+ IBMSHORT FrontEndError;
+ IBMSHORT LocalRingNumber;
+ IBMSHORT MonitorErrorCode;
+ IBMSHORT BeaconTransmitType;
+ IBMSHORT BeaconReceiveType;
+ IBMSHORT FrameCorrelator;
+ UCHAR BeaconNaun[6];
+ UCHAR Reserved2[4];
+ UCHAR BeaconPhysicalAddress[4];
+} ADAPTER_PARAMETERS, * PADAPTER_PARAMETERS;
+
+
+typedef struct _SRB_BRING_UP_RESULT {
+ UCHAR Command;
+ UCHAR InitStatus;
+ UCHAR Reserved1[4];
+ IBMSHORT ReturnCode;
+ SRAM_PTR EncodedAddressPointer;
+ SRAM_PTR LevelAddressPointer;
+ SRAM_PTR AdapterAddressPointer; // points to ADAPTER_ADDRESS
+ SRAM_PTR ParameterAddressPointer; // points to ADAPTER_PARAMETERS
+ SRAM_PTR MacBufferPointer;
+} SRB_BRING_UP_RESULT, * PSRB_BRING_UP_RESULT;
+
+
+
+
+//
+// Structure of the System Request Block as defined
+// for various commands.
+//
+
+typedef struct _SRB_GENERIC {
+ UCHAR Command;
+ UCHAR Reserved1[1];
+ UCHAR ReturnCode;
+} SRB_GENERIC, * PSRB_GENERIC;
+
+
+//
+// Values for the SRB Command field.
+//
+
+#define SRB_CMD_CLOSE_ADAPTER 0x04
+#define SRB_CMD_INTERRUPT 0x00
+#define SRB_CMD_MODIFY_OPEN_PARMS 0x01
+#define SRB_CMD_OPEN_ADAPTER 0x03
+#define SRB_CMD_CLOSE_ADAPTER 0x04
+#define SRB_CMD_READ_LOG 0x08
+#define SRB_CMD_RESTORE_OPEN_PARMS 0x02
+#define SRB_CMD_SET_FUNCTIONAL_ADDRESS 0x07
+#define SRB_CMD_SET_GROUP_ADDRESS 0x06
+#define SRB_CMD_TRANSMIT_DIR_FRAME 0x0a
+#define SRB_CMD_DLC_STATISTICS 0x1e
+
+
+typedef struct _SRB_OPEN_ADAPTER {
+ UCHAR Command;
+ UCHAR Reserved1[7];
+ IBMSHORT OpenOptions;
+ UCHAR NodeAddress[6];
+ UCHAR GroupAddress[4];
+ UCHAR FunctionalAddress[4];
+ IBMSHORT ReceiveBufferNum;
+ IBMSHORT ReceiveBufferLen;
+ IBMSHORT TransmitBufferLen;
+ UCHAR TransmitBufferNum;
+ UCHAR Reserved2[1];
+ UCHAR DlcValues[10];
+ UCHAR ProductId[18];
+} SRB_OPEN_ADAPTER, * PSRB_OPEN_ADAPTER;
+
+
+typedef struct _SRB_CLOSE_ADAPTER {
+ UCHAR Command;
+ UCHAR Reserved1;
+ UCHAR ReturnCode;
+} SRB_CLOSE_ADAPTER, * PSRB_CLOSE_ADAPTER;
+
+
+//
+// Bit values for the OpenOptions field (these are
+// reversed to be in IBMSHORT format).
+//
+
+#define OPEN_LOOPBACK 0x0080
+#define OPEN_DISABLE_HARD_ERROR 0x0040
+#define OPEN_DISABLE_SOFT_ERROR 0x0020
+#define OPEN_PASS_ADAPTER_MAC 0x0010
+#define OPEN_PASS_ATTENTION_MAC 0x0008
+#define OPEN_CONTENDER 0x0001
+#define OPEN_PASS_BEACON_MAC 0x8000
+#define OPEN_MODIFIED_TOKEN_RELEASE 0x1000
+#define OPEN_REMOTE_PROGRAM_LOAD 0x2000
+
+
+typedef struct _SRB_OPEN_RESPONSE {
+ UCHAR Command;
+ UCHAR Reserved1[1];
+ UCHAR ReturnCode;
+ UCHAR Reserved2[3];
+ IBMSHORT ErrorCode;
+ SRAM_PTR AsbPointer;
+ SRAM_PTR SrbPointer;
+ SRAM_PTR ArbPointer;
+ SRAM_PTR SsbPointer;
+} SRB_OPEN_RESPONSE, * PSRB_OPEN_RESPONSE;
+
+
+typedef struct _SRB_TRANSMIT_DIR_FRAME {
+ UCHAR Command;
+ UCHAR CommandCorrelator;
+ UCHAR ReturnCode;
+ UCHAR Reserved1[1];
+ IBMSHORT StationId;
+} SRB_TRANSMIT_DIR_FRAME, * PSRB_TRANSMIT_DIR_FRAME;
+
+
+typedef struct _SRB_SET_FUNCT_ADDRESS {
+ UCHAR Command;
+ UCHAR Reserved1[1];
+ UCHAR ReturnCode;
+ UCHAR Reserved2[3];
+ //
+ // Making this a TR_FUNCTIONAL_ADDRESS would cause
+ // the compiler to insert two bytes for alignment.
+ //
+ UCHAR FunctionalAddress[4];
+} SRB_SET_FUNCT_ADDRESS, * PSRB_SET_FUNCT_ADDRESS;
+
+
+typedef struct _SRB_SET_GROUP_ADDRESS {
+ UCHAR Command;
+ UCHAR Reserved1[1];
+ UCHAR ReturnCode;
+ UCHAR Reserved2[3];
+ //
+ // Making this a TR_FUNCTIONAL_ADDRESS would cause
+ // the compiler to insert two bytes for alignment.
+ //
+ UCHAR GroupAddress[4];
+} SRB_SET_GROUP_ADDRESS, * PSRB_SET_GROUP_ADDRESS;
+
+
+typedef struct _SRB_INTERRUPT {
+ UCHAR Command;
+ UCHAR Reserved1[1];
+ UCHAR ReturnCode;
+} SRB_INTERRUPT, * PSRB_INTERRUPT;
+
+
+typedef struct _SRB_READ_LOG {
+ UCHAR Command;
+ UCHAR Reserved1[1];
+ UCHAR ReturnCode;
+ UCHAR Reserved2[3];
+ UCHAR LineErrors;
+ UCHAR InternalErrors;
+ UCHAR BurstErrors;
+ UCHAR AcErrors;
+ UCHAR AbortDelimeters;
+ UCHAR Reserved3[1];
+ UCHAR LostFrames;
+ UCHAR ReceiveCongestionCount;
+ UCHAR FrameCopiedErrors;
+ UCHAR FrequencyErrors;
+ UCHAR TokenErrors;
+ UCHAR Reserved4[3];
+} SRB_READ_LOG, * PSRB_READ_LOG;
+
+
+typedef struct _SRB_DLC_STATS{
+ UCHAR Command;
+ UCHAR Reserved1;
+ UCHAR ReturnCode;
+ UCHAR Reserved2;
+ IBMSHORT StationId;
+ IBMSHORT CountersOffset;
+ IBMSHORT HeaderAddr;
+ UCHAR ResetOption;
+}SRB_DLC_STATS, *PSRB_DLC_STATS;
+
+
+typedef struct _DLC_COUNTERS{
+ IBMSHORT TransmitCount;
+ IBMSHORT ReceiveCount;
+ UCHAR TransmitErrors;
+ UCHAR ReceiveErrors;
+ IBMSHORT T1Expires;
+ UCHAR ReceivedCommand;
+ UCHAR SentCommand;
+ UCHAR PrimaryState;
+ UCHAR SecondaryState;
+ UCHAR SendState;
+ UCHAR ReceiveState;
+ UCHAR LastReceivedNr;
+}DLC_COUNTERS, *PDLC_COUNTERS;
+
+
+
+
+//
+// Structure of the Adapter Request Block as defined
+// for various commands.
+//
+
+typedef struct _ARB_GENERIC {
+ UCHAR Command;
+} ARB_GENERIC, * PARB_GENERIC;
+
+
+//
+// Values for the ARB Command field.
+//
+
+#define ARB_CMD_DLC_STATUS 0x83
+#define ARB_CMD_RECEIVED_DATA 0x81
+#define ARB_CMD_RING_STATUS_CHANGE 0x84
+#define ARB_CMD_TRANSMIT_DATA_REQUEST 0x82
+
+
+typedef struct _ARB_RING_STATUS_CHANGE {
+ UCHAR Command;
+ UCHAR Reserved1[5];
+ IBMSHORT NetworkStatus;
+} ARB_RING_STATUS_CHANGE, * PARB_RING_STATUS_CHANGE;
+
+
+typedef struct _ARB_DLC_STATUS {
+ UCHAR Command;
+ UCHAR Reserved1[3];
+ IBMSHORT StationId;
+ IBMSHORT Status;
+ UCHAR FrmrData[5];
+ UCHAR AccessPriority;
+ UCHAR RemoteAddress[6];
+ UCHAR RemoteRsapValue;
+} ARB_DLC_STATUS, * PARB_DLC_STATUS;
+
+
+typedef struct _ARB_TRANSMIT_DATA_REQUEST {
+ UCHAR Command;
+ UCHAR CommandCorrelator;
+ UCHAR Reserved1[2];
+ IBMSHORT StationId;
+ SRAM_PTR DhbPointer;
+} ARB_TRANSMIT_DATA_REQUEST, * PARB_TRANSMIT_DATA_REQUEST;
+
+
+typedef struct _ARB_RECEIVED_DATA {
+ UCHAR Command;
+ UCHAR Reserved1[3];
+ IBMSHORT StationId;
+ SRAM_PTR ReceiveBuffer; // points to a RECEIVE_BUFFER
+ UCHAR LanHeaderLength;
+ UCHAR DlcHeaderLength;
+ IBMSHORT FrameLength;
+ UCHAR MessageType;
+} ARB_RECEIVED_DATA, * PARB_RECEIVED_DATA;
+
+
+typedef struct _RECEIVE_BUFFER {
+ //
+ // Leave out the first two reserved bytes.
+ //
+ SRAM_PTR NextBuffer;
+ UCHAR Reserved2[1];
+ UCHAR ReceiveFs;
+ IBMSHORT BufferLength;
+ UCHAR FrameData[1];
+} RECEIVE_BUFFER, * PRECEIVE_BUFFER;
+
+
+
+
+//
+// Structure of the Adapter Status Block as defined
+// for various commands.
+//
+
+typedef struct _ASB_GENERIC {
+ UCHAR Command;
+ UCHAR Reserved1[1];
+ UCHAR ReturnCode;
+} ASB_GENERIC, * PASB_GENERIC;
+
+
+//
+// The ASB Command field takes the same values as the
+// ARB Command field.
+//
+
+typedef struct _ASB_TRANSMIT_DATA_STATUS {
+ UCHAR Command;
+ UCHAR CommandCorrelator;
+ UCHAR ReturnCode;
+ UCHAR Reserved1[1];
+ IBMSHORT StationId;
+ IBMSHORT FrameLength;
+ UCHAR Reserved2[2];
+} ASB_TRANSMIT_DATA_STATUS, * PASB_TRANSMIT_DATA_STATUS;
+
+
+typedef struct _ASB_RECEIVED_DATA_STATUS {
+ UCHAR Command;
+ UCHAR Reserved1[1];
+ UCHAR ReturnCode;
+ UCHAR Reserved2[1];
+ IBMSHORT StationId;
+ SRAM_PTR ReceiveBuffer;
+} ASB_RECEIVED_DATA_STATUS, * PASB_RECEIVED_DATA_STATUS;
+
+
+
+
+//
+// Structure of the System Status Block as defined
+// for various commands.
+//
+
+typedef struct _SSB_GENERIC {
+ UCHAR Command;
+} SSB_GENERIC, * PSSB_GENERIC;
+
+
+//
+// The SSB Command field takes the same values as the
+// SRB Command field.
+//
+
+typedef struct _SSB_TRANSMIT_COMPLETE {
+ UCHAR Command;
+ UCHAR CommandCorrelator;
+ UCHAR ReturnCode;
+ UCHAR Reserved1[1];
+ IBMSHORT StationId;
+ UCHAR ErrorFrameStatus;
+} SSB_TRANSMIT_COMPLETE, * PSSB_TRANSMIT_COMPLETE;
+
+
+
+#endif // _IBMTOKHARDWARE_
diff --git a/private/ntos/ndis/ibmtok/toksft.h b/private/ntos/ndis/ibmtok/toksft.h
new file mode 100644
index 000000000..5f120c1d9
--- /dev/null
+++ b/private/ntos/ndis/ibmtok/toksft.h
@@ -0,0 +1,1373 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ toksft.h
+
+Abstract:
+
+ The main header for a IBMTOK NDIS driver.
+
+ The overall structure is taken from the Lance driver
+ by Tony Ercolano.
+
+Author:
+
+ Anthony V. Ercolano (tonye) creation-date 19-Jun-1990
+ Adam Barr (adamba) 20-Nov-1990
+
+Environment:
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+
+--*/
+
+#ifndef _IBMTOKSFT_
+#define _IBMTOKSFT_
+
+
+#define IBMTOK_NDIS_MAJOR_VERSION 3
+#define IBMTOK_NDIS_MINOR_VERSION 0
+
+#if DBG
+#define LOG 1
+#else
+#define LOG 0
+#endif
+
+#if LOG
+
+//
+// Place in the circular buffer.
+//
+extern UCHAR IbmtokLogPlace;
+
+//
+// Circular buffer for storing log information.
+//
+extern UCHAR IbmtokLog[];
+
+#define IF_LOG(A) {IbmtokLog[IbmtokLogPlace] = (A); \
+ IbmtokLog[(IbmtokLogPlace+3) % 255] = '.'; \
+ IbmtokLogPlace = (IbmtokLogPlace+1) % 255; }
+
+#else
+
+#define IF_LOG(A)
+
+#endif
+
+extern const NDIS_PHYSICAL_ADDRESS HighestAcceptableMax;
+
+#define IBMTOK_ALLOC_PHYS(pp,s) NdisAllocateMemory((PVOID *)(pp),(s),0,HighestAcceptableMax)
+#define IBMTOK_FREE_PHYS(p,s) NdisFreeMemory((PVOID)(p),(s),0)
+#define IBMTOK_MOVE_MEMORY(Destination,Source,Length) NdisMoveMemory((PVOID)(Destination),(PVOID)(Source),Length)
+#define IBMTOK_ZERO_MEMORY(Destination,Length) NdisZeroMemory((PVOID)(Destination),Length)
+#define IBMTOK_MOVE_TO_MAPPED_MEMORY(Destination,Source,Length) NdisMoveToMappedMemory((PVOID)(Destination),(PVOID)(Source),Length)
+#define IBMTOK_MOVE_FROM_MAPPED_MEMORY(Destination,Source,Length) NdisMoveFromMappedMemory((PVOID)(Destination),(PVOID)(Source),Length)
+#define IBMTOK_ZERO_MAPPED_MEMORY(Destination,Length) NdisZeroMappedMemory((PVOID)(Destination),Length)
+#define IBMTOK_STORE_ULONG(Destination,Source)\
+{\
+ PUCHAR _D = (PUCHAR)(Destination);\
+ ULONG _S = (ULONG)(Source);\
+ _D[0] = (UCHAR)(_S >> 24);\
+ _D[1] = (UCHAR)(_S >> 16);\
+ _D[2] = (UCHAR)(_S >> 8);\
+ _D[3] = (UCHAR)(_S);\
+}
+
+
+typedef struct _IBMTOK_MAC {
+
+ //
+ // The handle returned by NdisInitializeWrapper.
+ //
+
+ NDIS_HANDLE NdisWrapperHandle;
+
+ //
+ // The handle returned by NdisRegisterMac.
+ //
+
+ NDIS_HANDLE NdisMacHandle;
+
+} IBMTOK_MAC, *PIBMTOK_MAC;
+
+
+
+//
+// This record type is inserted into the MacReserved portion
+// of the packet header when the packet is going through the
+// staged allocation of buffer space prior to the actual send.
+//
+typedef struct _IBMTOK_RESERVED {
+
+ //
+ // Points to the next packet in the chain of queued packets
+ // waiting for the SRB or the ASB.
+ //
+ // The packet will start out on the Transmit queue,
+ // then move to TransmittingPacket when its transmit is
+ // in the SRB. When the correlator is assigned it is placed
+ // in CorrelatorArray (where the Next field is not used),
+ // and at that time may also be in WaitingForAsb if it
+ // needs the ASB to acknowledge the copying down of the
+ // transmit data. Packets are completed out of the
+ // CorrelatorArray.
+ //
+ //
+ PNDIS_PACKET Next;
+
+ //
+ // This field holds the binding handle of the open binding
+ // that submitted this packet for send.
+ //
+ NDIS_HANDLE MacBindingHandle;
+
+ //
+ // This field holds the pointer to the packet so that when
+ // the send finnaly completes it can be used to indicate to
+ // the protocol.
+ //
+ PNDIS_PACKET Packet;
+
+ //
+ // TRUE if a command correlator has been assigned for this
+ // packet.
+ //
+ BOOLEAN CorrelatorAssigned;
+
+ //
+ // The value of the adapter-assigned command correlator.
+ //
+ UCHAR CommandCorrelator;
+
+} IBMTOK_RESERVED,*PIBMTOK_RESERVED;
+
+
+//
+// This macro will return a pointer to the reserved portion
+// of a packet given a pointer to a packet.
+//
+#define PIBMTOK_RESERVED_FROM_PACKET(Packet) \
+ ((PIBMTOK_RESERVED)((PVOID)((Packet)->MacReserved)))
+
+
+
+//
+// This structure is inserted into the MacReserved section of the
+// NDIS_REQUEST for operations that must pend. Note: the sizeof
+// this structure must be less than or equal to 16 bytes.
+//
+// The flags are broken down as follows....
+//
+// Type == IBMTOK_PEND_MAC for requests submitted by the MAC to clear card errors.
+// ReadLogPending == TRUE if the MAC submitted a DIR.READ.LOG command.
+// ReadLogPending == FALSE if the MAC submitted DLC.STATISTICS.
+//
+// Type == IBMTOK_PEND_NDIS_CLOSE for request submitted thru Ndis.
+// Open, the open that submitted the Ndis request.
+//
+// Type == IBMTOK_PEND_NDIS_SET_FILTER for request submitted thru Ndis.
+// Open, the open that submitted the Ndis request.
+//
+// Type == IBMTOK_PEND_NDIS_STATISTICS for request submitted thru Ndis.
+// ReadLogPending, Boolean if the DIR.READ.LOG command was submitted.
+//
+//
+//
+typedef struct _IBMTOK_PEND_DATA{
+
+ //
+ // Points to the next request in the chain of queued packets
+ // waiting for the SRB.
+ //
+ // The request will start out on the PendQueue,
+ // then move to front of the queue when its operation is
+ // in the SRB.
+ //
+ //
+ struct _IBMTOK_PEND_DATA * Next;
+
+
+ union _COMMAND{
+
+ struct _MAC{
+
+ //
+ // Whether the statistics command was a
+ // DIR.READ.LOG or DLC.STATISTICS
+ //
+
+ UINT ReadLogPending;
+
+ }MAC;
+
+ union _NDIS{
+
+ struct _CLOSE{
+
+ //
+ // This field holds the open instance which submitted the
+ // request.
+ //
+
+ struct _IBMTOK_OPEN *Open;
+
+ //
+ // This field holds the new filter value.
+ //
+
+ UINT NewFilterValue;
+
+
+ }CLOSE;
+
+
+ struct _SET_FILTER{
+
+ //
+ // The first two fields of SET_FILTER and SET_ADDRESS need
+ // to align so that the processing in FinishSetOperation
+ // is easier.
+ //
+
+
+ //
+ // This field holds the open instance which submitted the
+ // request.
+ //
+
+ struct _IBMTOK_OPEN *Open;
+
+ //
+ // This field holds the new filter value.
+ //
+
+ UINT NewFilterValue;
+
+ }SET_FILTER;
+
+
+ struct _SET_ADDRESS{
+
+ //
+ // The first two fields of SET_FILTER and SET_ADDRESS need
+ // to align so that the processing in FinishSetOperation
+ // is easier.
+ //
+
+
+ //
+ // This field holds the open instance which submitted the
+ // request.
+ //
+
+ struct _IBMTOK_OPEN *Open;
+
+ //
+ // This field holds the new address value.
+ //
+
+ TR_FUNCTIONAL_ADDRESS NewAddressValue;
+
+ }SET_ADDRESS;
+
+
+ struct _STATISTICS{
+
+ //
+ // Pointer into NdisRequest at the New filter value.
+ //
+
+ BOOLEAN ReadLogPending;
+
+
+ }STATISTICS;
+
+ }NDIS;
+
+ }COMMAND;
+
+ //
+ // Buffer to fill in Reserved section so that the next field overlaps
+ // with the RequestType in the NdisRequest.
+ //
+
+ ULONG Buffer;
+
+
+ NDIS_REQUEST_TYPE RequestType;
+
+
+}IBMTOK_PEND_DATA, *PIBMTOK_PEND_DATA;
+
+//
+// This macro will return a pointer to the reserved area of
+// a PNDIS_REQUEST.
+//
+#define PIBMTOK_PEND_DATA_FROM_PNDIS_REQUEST(Request) \
+ ((PIBMTOK_PEND_DATA)((PVOID)((Request)->MacReserved)))
+
+//
+// This macros returns the enclosing NdisRequest.
+//
+#define PNDIS_REQUEST_FROM_PIBMTOK_PEND_DATA(PendOp)\
+ ((PNDIS_REQUEST)((PVOID)(PendOp)))
+
+//
+// Define Maximum number of bytes a protocol can read during a
+// receive data indication.
+//
+#define IBMTOK_MAX_LOOKAHEAD 240
+
+
+typedef struct _IBMTOK_ADAPTER {
+
+ //
+ // Holds the interrupt object for this adapter.
+ //
+ NDIS_INTERRUPT Interrupt;
+
+ //
+ // Flag to tell if the ISR removed the interrupt.
+ //
+ UCHAR ContinuousIsrs;
+
+ PVOID WakeUpDpc;
+ NDIS_TIMER WakeUpTimer;
+ BOOLEAN SendTimeout;
+ BOOLEAN RequestTimeout;
+ UCHAR WakeUpErrorCount;
+
+ //
+ // Defines whether the adapter is an ISA or PCMCIA adapter.
+ //
+ UINT CardType;
+
+ //
+ // Boolean to turn on/off early token release
+ //
+ BOOLEAN EarlyTokenRelease;
+
+ //
+ // Flag to indicate that the card initialized.
+ //
+ BOOLEAN BringUp;
+
+ //
+ // Spinlock for the interrupt.
+ //
+ NDIS_SPIN_LOCK InterruptLock;
+
+ //
+ // The interrupt level as read from the card.
+ //
+ UINT InterruptLevel;
+
+ //
+ // Is the adapter running at 16 Mbps (versus 4 Mbps).
+ //
+ BOOLEAN Running16Mbps;
+
+ //
+ // Is the adapter using the PC I/O Bus (versus MicroChannel).
+ //
+ BOOLEAN UsingPcIoBus;
+
+ //
+ // Does the upper 512 bytes of the shared RAM have to
+ // be zeroed after initialization.
+ //
+ BOOLEAN UpperSharedRamZero;
+
+ //
+ // Are we using Shared RAM paging.
+ //
+ BOOLEAN SharedRamPaging;
+
+ //
+ // The size of the RAM on the adapter.
+ //
+ ULONG TotalSharedRam;
+
+ //
+ // The amount of Shared RAM to be mapped in.
+ //
+ ULONG MappedSharedRam;
+
+ //
+ // The maximum size of a DHB at 4 Mbps.
+ //
+ USHORT Max4MbpsDhb;
+
+ //
+ // The maximum size of a DHB at 16 Mbps.
+ //
+ USHORT Max16MbpsDhb;
+
+ //
+ // Value of the RRR Low register (address of Shared Ram).
+ //
+ UCHAR RrrLowValue;
+
+// The following fields are accessed by the ISR and must be aligned to the
+// minimum granularity of the architecture on which it runs
+
+#if defined(_ALPHA_)
+
+ union {
+ UQUAD _ForceQuadwordAlignment;
+ struct {
+
+#endif // defined(_ALPHA_)
+
+ //
+ // These variables are used to hold bits stored in the ISR
+ // and read in the DPC.
+ //
+ UCHAR IsrpBits;
+
+ //
+ // These hold ISR bits whose processing is delayed because
+ // the adapter is not accepting requests.
+ //
+ UCHAR IsrpDeferredBits;
+
+ //
+ // Any Error conditions found in the IsrpLow register
+ //
+ UCHAR IsrpLowBits;
+
+#if defined(_ALPHA_)
+
+ };
+ };
+
+#endif // defined(_ALPHA_)
+
+// End of ISR access fields
+
+ //
+ // This boolean is used as a gate to ensure that only one thread
+ // of execution is actually processing SRB interrupts
+ //
+ BOOLEAN HandleSrbRunning;
+
+ //
+ // This boolean is used as a gate to ensure that only one thread
+ // of execution is actually processing SRB interrupts
+ //
+ BOOLEAN HandleArbRunning;
+
+ //
+ // The network address in use.
+ //
+ CHAR NetworkAddress[TR_LENGTH_OF_ADDRESS];
+
+ //
+ // The network address from the hardware.
+ //
+ CHAR PermanentNetworkAddress[TR_LENGTH_OF_ADDRESS];
+
+ //
+ // Pointer to the beginning of the IBMTOK ports.
+ //
+ ULONG IbmtokPortAddress;
+
+ //
+ // Keeps a reference count on the current number of uses of
+ // this adapter block. Uses is defined to be the number of
+ // routines currently within the "external" interface.
+ //
+ UINT References;
+
+ //
+ // List head for all open bindings for this adapter.
+ //
+ LIST_ENTRY OpenBindings;
+
+ //
+ // List head for all opens that had outstanding references
+ // when an attempt was made to close them.
+ //
+ LIST_ENTRY CloseList;
+
+ //
+ // List head for all opens that were attempted to be closed
+ // during a reset.
+ LIST_ENTRY CloseDuringResetList;
+
+ //
+ // Spinlock to protect fields in this structure..
+ //
+ NDIS_SPIN_LOCK Lock;
+
+ //
+ // Handle given by NDIS when the MAC registered itself.
+ //
+ NDIS_HANDLE NdisMacHandle;
+
+ //
+ // Handle given by NDIS when the adapter was registered.
+ //
+ NDIS_HANDLE NdisAdapterHandle;
+
+ //
+ // Pointer to the filter database for the MAC.
+ //
+ PTR_FILTER FilterDB;
+
+ //
+ // Holds queued Pending operations.
+ //
+ PIBMTOK_PEND_DATA PendQueue;
+
+ //
+ // Last pending operation on queue.
+ //
+ PIBMTOK_PEND_DATA EndOfPendQueue;
+
+ //
+ // Pointer to the pended operation that is currently executing.
+ //
+ PIBMTOK_PEND_DATA PendData;
+
+ //
+ // The current packet filter.
+ //
+ UINT CurrentPacketFilter;
+
+ //
+ // The old packet filter (in case of failure to set to a new filter).
+ //
+ UINT OldPacketFilter;
+
+ //
+ // The current functional address requested.
+ //
+ TR_FUNCTIONAL_ADDRESS CurrentFunctionalAddress;
+
+ //
+ // The functional address on the card (may differ
+ // from CurrentFunctionalAddress if ALL_MULTICAST
+ // is selected).
+ //
+ TR_FUNCTIONAL_ADDRESS CurrentCardFunctional;
+
+ //
+ // The current group address requested.
+ //
+ TR_FUNCTIONAL_ADDRESS CurrentGroupAddress;
+
+ //
+ // The group address on the card
+ //
+ TR_FUNCTIONAL_ADDRESS CurrentCardGroup;
+
+ //
+ // The address that the MMIO is mapped to.
+ //
+ PUCHAR MmioRegion;
+
+ //
+ // The address that the Shared RAM is mapped to.
+ //
+ PUCHAR SharedRam;
+
+ //
+ // Initial offset of WRB in Shared RAM (contains location
+ // of bring-up SRB).
+ //
+ USHORT InitialWrbOffset;
+
+ //
+ // Addresses of the Shared RAM structures.
+ //
+ PVOID SrbAddress;
+ PVOID SsbAddress;
+ PVOID ArbAddress;
+ PVOID AsbAddress;
+
+ //
+ // For Shared RAM Paging mode, the SRPR Low value needed
+ // to talk to each of the Shared RAM structures.
+ //
+ UCHAR SrbSrprLow;
+ UCHAR SsbSrprLow;
+ UCHAR ArbSrprLow;
+ UCHAR AsbSrprLow;
+
+ //
+ // Is the SRB available.
+ //
+ BOOLEAN SrbAvailable;
+
+ //
+ // Is the ASB available.
+ //
+ BOOLEAN AsbAvailable;
+
+ //
+ // The next correlator number which we think we should
+ // be completing the send for.
+ //
+ UCHAR NextCorrelatorToComplete;
+
+ //
+ // Points to the packet being transmitted if TransmitInSrb
+ // is TRUE.
+ //
+ PNDIS_PACKET TransmittingPacket;
+
+ //
+ // The receive buffer that is waiting for the ASB.
+ //
+ SRAM_PTR ReceiveWaitingForAsbList;
+
+ //
+ // A SRAM_PTR to the last receive buffer waiting for
+ // the ASB to indicate completion.
+ //
+ SRAM_PTR ReceiveWaitingForAsbEnd;
+
+
+ //
+ // The receive buffer that the transfer data should
+ // begin at (used during receive indications).
+ //
+ SRAM_PTR IndicatedReceiveBuffer;
+
+ //
+ // Length of the header for this received indication.
+ //
+ USHORT IndicatedHeaderLength;
+
+ //
+ // Should the ASB be used for a receive next.
+ //
+ BOOLEAN UseNextAsbForReceive;
+
+ //
+ // The number of transmit buffers.
+ //
+ USHORT NumberOfTransmitBuffers;
+
+ //
+ // The size of the transmit buffers.
+ //
+ USHORT TransmitBufferLength;
+
+ //
+ // The size of the maximum packet transmittable.
+ //
+ UINT MaxTransmittablePacket;
+
+ //
+ // The number of receive buffers.
+ //
+ USHORT NumberOfReceiveBuffers;
+
+ //
+ // The size of the receive buffers.
+ //
+ USHORT ReceiveBufferLength;
+
+ //
+ // Pointers to the first and last packets at a particular stage
+ // of allocation. All packets in transmit are linked
+ // via there next field.
+ //
+ // Can only be accessed when the adapter lock
+ // is held.
+ //
+ PNDIS_PACKET FirstTransmit;
+ PNDIS_PACKET LastTransmit;
+
+ PNDIS_PACKET FirstWaitingForAsb;
+ PNDIS_PACKET LastWaitingForAsb;
+
+ //
+ // Holds counter return by DLC.STATISTICS command.
+ //
+
+ UINT FramesTransmitted;
+ UINT FramesReceived;
+ UINT FrameTransmitErrors;
+ UINT FrameReceiveErrors;
+
+
+ //
+ // Holds counter returned by the DIR.READ.LOG command.
+ //
+ UINT LineErrors;
+ UINT InternalErrors;
+ UINT BurstErrors;
+ UINT AcErrors;
+ UINT AbortDelimeters;
+ UINT LostFrames;
+ UINT ReceiveCongestionCount;
+ UINT FrameCopiedErrors;
+ UINT FrequencyErrors;
+ UINT TokenErrors;
+
+ //
+ // Holds number of different types of RING.STATUS.CHANGE
+ // indications.
+ //
+ UINT SignalLoss;
+ UINT HardError;
+ UINT SoftError;
+ UINT TransmitBeacon;
+ UINT LobeWireFault;
+ UINT AutoRemovalError;
+ UINT RemoveReceived;
+ UINT CounterOverflow;
+ UINT SingleStation;
+ UINT RingRecovery;
+
+ //
+ // Last ring status indicated to protocols.
+ //
+ NDIS_STATUS LastNotifyStatus;
+
+ //
+ // Current state of the ring.
+ //
+ NDIS_802_5_RING_STATE CurrentRingState;
+
+ //
+ // Flag that when enabled lets routines know that a reset
+ // is in progress.
+ //
+ BOOLEAN ResetInProgress;
+
+ //
+ // The progress of the reset.
+ //
+ UINT CurrentResetStage;
+
+ //
+ // LookAhead information
+ //
+
+ ULONG LookAhead;
+
+ //
+ // TRUE when the ISR is expecting the next interrupt to
+ // be the one following adapter reset.
+ //
+ BOOLEAN ResetInterruptAllowed;
+
+ //
+ // TRUE when ISR gets the reset interrupt.
+ //
+ BOOLEAN ResetInterruptHasArrived;
+
+ //
+ // Pointer to the binding that initiated the reset. This
+ // will be null if the reset is initiated by the MAC itself.
+ //
+ struct _IBMTOK_OPEN *ResettingOpen;
+
+ //
+ // Will be true the first time that the hardware is initialized
+ // by the driver initialization.
+ //
+ BOOLEAN FirstInitialization;
+
+ //
+ // Will be true if the adapter is not yet opened.
+ //
+ BOOLEAN AdapterNotOpen;
+
+ //
+ // Will be true if the driver is being opened.
+ //
+ BOOLEAN OpenInProgress;
+
+ //
+ // TRUE if ResetInProgress or OpenInProgress is TRUE.
+ //
+ BOOLEAN NotAcceptingRequests;
+
+ //
+ // Last Error Code.
+ //
+ USHORT OpenErrorCode;
+
+ //
+ // TRUE if we get a ring status indicating the cable is unplugged.
+ //
+ BOOLEAN Unplugged;
+
+ //
+ // TRUE if we are doing a reset after the cable was unplugged
+ // to try to reenter the ring.
+ //
+ BOOLEAN UnpluggedResetInProgress;
+
+ //
+ // TRUE if we have gotten a lobe wire fault indication,
+ // meaning the adapter is closed.
+ //
+ BOOLEAN LobeWireFaultIndicated;
+
+ //
+ // TRUE if there exists an outstanding ASB_FREE_REQUEST
+ //
+ BOOLEAN OutstandingAsbFreeRequest;
+
+ //
+ // The command correlator array (put this at the end since
+ // it is so big).
+ //
+ PNDIS_PACKET CorrelatorArray[MAX_COMMAND_CORRELATOR];
+
+ //
+ // IBM_TOKEN_RING_16_4_CREDIT_CARD_ADAPTER specific
+ // keywords
+ //
+ UINT RingSpeed;
+ ULONG Ram;
+ UINT RamSize;
+ ULONG MmioAddress;
+ BOOLEAN InvalidValue;
+ BOOLEAN RingSpeedListen;
+ ULONG RingSpeedRetries;
+
+} IBMTOK_ADAPTER,*PIBMTOK_ADAPTER;
+
+
+//
+// Given a MacBindingHandle this macro returns a pointer to the
+// IBMTOK_ADAPTER.
+//
+#define PIBMTOK_ADAPTER_FROM_BINDING_HANDLE(Handle) \
+ (((PIBMTOK_OPEN)((PVOID)(Handle)))->OwningIbmtok)
+
+
+//
+// Given a MacContextHandle return the PIBMTOK_ADAPTER
+// it represents.
+//
+#define PIBMTOK_ADAPTER_FROM_CONTEXT_HANDLE(Handle) \
+ ((PIBMTOK_ADAPTER)((PVOID)(Handle)))
+
+
+//
+// Given a pointer to a IBMTOK_ADAPTER return the
+// proper MacContextHandle.
+//
+#define CONTEXT_HANDLE_FROM_PIBMTOK_ADAPTER(Ptr) \
+ ((NDIS_HANDLE)((PVOID)(Ptr)))
+
+
+//
+// One of these structures is created on each MacOpenAdapter.
+//
+typedef struct _IBMTOK_OPEN {
+
+ //
+ // Linking structure for all of the open bindings of a particular
+ // adapter.
+ //
+ LIST_ENTRY OpenList;
+
+ //
+ // The Adapter that requested this open binding.
+ //
+ PIBMTOK_ADAPTER OwningIbmtok;
+
+ //
+ // Handle of this adapter in the filter database.
+ //
+ NDIS_HANDLE NdisFilterHandle;
+
+ //
+ // Given by NDIS when the adapter was opened.
+ //
+ NDIS_HANDLE NdisBindingContext;
+
+ //
+ // Counter of all the different reasons that a open binding
+ // couldn't be closed. This would be incremented each time
+ // for:
+ //
+ // While a particular interface routine is accessing this open
+ //
+ // During an indication.
+ //
+ // When the open causes a reset.
+ //
+ // A packet currently being sent.
+ //
+ // (Basically the above two mean any time the open has left
+ // some processing around to be accomplished later.)
+ //
+ // This field should only be accessed when the adapter lock is held.
+ //
+ UINT References;
+
+ //
+ // Minimum Number of bytes for a lookahead.
+ //
+ UINT LookAhead;
+
+ //
+ // A flag indicating that the open has pended.
+ //
+ BOOLEAN OpenPending;
+
+ //
+ // A flag indicating that this binding is in the process of closing.
+ //
+ BOOLEAN BindingShuttingDown;
+
+
+ //
+ // A bogus NdisRequest to queue operations during a close.
+ //
+ NDIS_REQUEST CloseRequestChangeFilter;
+ NDIS_REQUEST CloseRequestChangeAddress;
+ NDIS_REQUEST CloseRequestChangeGroupAddress;
+
+} IBMTOK_OPEN,*PIBMTOK_OPEN;
+
+
+//
+// procedures which do error logging
+//
+
+typedef enum _IBMTOK_PROC_ID{
+ registerAdapter,
+ openAdapter,
+ hardwareDetails,
+ handleResetStaging,
+ handleSrbSsb,
+ startPendQueueOp,
+ finishPendQueueOp,
+ handleDeferred,
+ ibmtokDpc
+}IBMTOK_PROC_ID;
+
+//
+// Error log values
+//
+
+#define IBMTOK_ERRMSG_NOT_FOUND (ULONG)0x01
+#define IBMTOK_ERRMSG_CREATE_DB (ULONG)0x02
+#define IBMTOK_ERRMSG_INIT_INTERRUPT (ULONG)0x03
+#define IBMTOK_ERRMSG_OPEN_DB (ULONG)0x04
+#define IBMTOK_ERRMSG_ALLOC_MEM (ULONG)0x05
+#define IBMTOK_ERRMSG_UNSUPPORTED_RAM (ULONG)0x06
+#define IBMTOK_ERRMSG_BRINGUP_FAILURE (ULONG)0x07
+#define IBMTOK_ERRMSG_INVALID_CMD (ULONG)0x08
+#define IBMTOK_ERRMSG_BAD_OP (ULONG)0x09
+#define IBMTOK_ERRMSG_INVALID_STATUS (ULONG)0x0A
+#define IBMTOK_ERRMSG_INVALID_STATE (ULONG)0x0B
+#define IBMTOK_ERRMSG_ISRP_LOW_ERROR (ULONG)0x0C
+
+//
+// This macro returns a pointer to a PIBMTOK_OPEN given a MacBindingHandle.
+//
+#define PIBMTOK_OPEN_FROM_BINDING_HANDLE(Handle) \
+ ((PIBMTOK_OPEN)((PVOID)Handle))
+
+
+//
+// This macro returns a NDIS_HANDLE from a PIBMTOK_OPEN
+//
+#define BINDING_HANDLE_FROM_PIBMTOK_OPEN(Open) \
+ ((NDIS_HANDLE)((PVOID)Open))
+
+
+//
+// This macro will act a "epilogue" to every routine in the
+// *interface*. It will check whether there any requests needed
+// to defer there processing. It will also decrement the reference
+// count on the adapter. If the reference count is zero and there
+// is deferred work to do it will insert the interrupt processing
+// routine in the DPC queue.
+//
+// Note that we don't need to include checking for blocked receives
+// since blocked receives imply that there will eventually be an
+// interrupt.
+//
+// NOTE: This macro assumes that it is called with the lock acquired.
+//
+#define IBMTOK_DO_DEFERRED(Adapter) \
+{ \
+ PIBMTOK_ADAPTER _A = (Adapter); \
+ _A->References--; \
+ if ((!_A->References) && \
+ (_A->ResetInProgress || \
+ (!IsListEmpty(&_A->CloseList)))) { \
+ IbmtokHandleDeferred(_A); \
+ NdisReleaseSpinLock(&_A->Lock); \
+ } else { \
+ NdisReleaseSpinLock(&_A->Lock); \
+ } \
+}
+
+
+//++
+//
+// VOID
+// SET_INTERRUPT_RESET_FLAG(
+// IN PIBMTOK_ADAPTER Adapter,
+// )
+//
+//
+// Routine Description:
+//
+// This routine uses NdisSynchronizeWithInterrupt to call the
+// IbmtokSynchSetReset, which sets the ResetInterruptAllowed
+// flag in the adapter structure. This is set after the
+// adapter is reset to allow the interrupt indicating the
+// end of the reset to come through (since all others
+// should be blocked during the reset).
+//
+// Arguments:
+//
+// Adapter - The adapter to set the flag for.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define SET_INTERRUPT_RESET_FLAG(A) \
+{ \
+ PIBMTOK_ADAPTER _A = A; \
+ NdisSynchronizeWithInterrupt( \
+ &_A->Interrupt, \
+ (PVOID) IbmtokSynchSetReset, \
+ (PVOID)_A \
+ ); \
+}
+
+
+//
+// This macro is to clear the SRB/SSB and ARB/ASB bits
+// used by the interrupt handlers.
+//
+
+#define CLEAR_ISRP_BITS(A) \
+{ \
+ PIBMTOK_ADAPTER _A = A; \
+ NdisSynchronizeWithInterrupt( \
+ &_A->Interrupt, \
+ (PVOID) IbmtokSynchClearIsrpBits, \
+ (PVOID)_A \
+ ); \
+}
+
+
+
+//
+// VOID
+// IbmtokProcessSrbRequests(
+// IN PIBMTOK_ADAPTER Adapter
+// )
+// /*++
+//
+// Routine Description:
+//
+// Check if the SRB is available, if so queue the next
+// request on it. Preferably, it is called when it is known
+// that there is something on the queue.
+//
+// NOTE: THIS IS CALLED WITH THE LOCK HELD!!!
+//
+// NOTE: THIS MUST BE CALLED WITH Adapter->SrbAvailable == TRUE !!!!!
+//
+// Arguments:
+//
+// Adapter - The Adapter to process interrupts for.
+//
+// Return Value:
+//
+// None.
+//
+// --*/
+//
+
+#define IbmtokProcessSrbRequests(_Adapter) \
+{ \
+ if (_Adapter->SrbAvailable) { \
+ (_Adapter)->SrbAvailable = FALSE;\
+ SetupSrbCommand(_Adapter); \
+ } \
+}
+
+
+// VOID
+// PutPacketInCorrelatorArray(
+// IN PIBMTOK_ADAPTER Adapter,
+// IN PNDIS_PACKET Packet
+// )
+//
+// /*++
+//
+// Routine Description:
+//
+// This inserts a packet in the correlator array, based
+// on the value of its command correlator.
+//
+// Arguments:
+//
+// Adapter - The adapter that this packet is coming through.
+//
+// Packet - The packet that is to be inserted.
+//
+// Return Value:
+//
+// None.
+//
+// --*/
+//
+#define PutPacketInCorrelatorArray( _Adapter, _Packet) \
+{ \
+ PIBMTOK_RESERVED _Reserved = PIBMTOK_RESERVED_FROM_PACKET(_Packet); \
+ ASSERT(_Reserved->CorrelatorAssigned); \
+ ASSERT((_Adapter)->CorrelatorArray[_Reserved->CommandCorrelator] == (PNDIS_PACKET)NULL); \
+ (_Adapter)->CorrelatorArray[_Reserved->CommandCorrelator] = (_Packet); \
+}
+
+
+
+// STATIC
+// VOID
+// RemovePacketFromCorrelatorArray(
+// IN PIBMTOK_ADAPTER Adapter,
+// IN PNDIS_PACKET Packet
+// )
+//
+// /*++
+//
+// Routine Description:
+//
+// This deletes a packet in the correlator array, based
+// on the value of its command correlator.
+//
+// Arguments:
+//
+// Adapter - The adapter that this packet is coming through.
+//
+// Packet - The packet that is to be removed.
+//
+// Return Value:
+//
+// None.
+//
+// --*/
+//
+#define RemovePacketFromCorrelatorArray(_Adapter, _Packet) \
+{ \
+ PIBMTOK_RESERVED _Reserved = PIBMTOK_RESERVED_FROM_PACKET(_Packet); \
+ ASSERT(_Reserved->CorrelatorAssigned); \
+ _Reserved->CorrelatorAssigned = FALSE; \
+ (_Adapter)->CorrelatorArray[_Reserved->CommandCorrelator] = (PNDIS_PACKET)NULL; \
+}
+
+
+
+
+
+//
+// We define the external interfaces to the ibmtok driver.
+// These routines are only external to permit separate
+// compilation. Given a truely fast compiler they could
+// all reside in a single file and be static.
+//
+
+
+extern
+VOID
+IbmtokAdjustMaxLookAhead(
+ IN PIBMTOK_ADAPTER Adapter
+ );
+
+
+extern
+VOID
+IbmtokDPC(
+ IN PVOID SystemSpecific1,
+ IN PVOID Context,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+
+extern
+VOID
+SetupSrbCommand(
+ IN PIBMTOK_ADAPTER Adapter
+ );
+
+extern
+VOID
+IbmtokWakeUpDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID Context,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+
+extern
+BOOLEAN
+IbmtokISR(
+ IN PVOID Context
+ );
+
+extern
+VOID
+IbmtokHandleDeferred(
+ IN PIBMTOK_ADAPTER Adapter
+ );
+
+extern
+NDIS_STATUS
+IbmtokSetPacketFilter(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN PIBMTOK_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT PacketFilter
+ );
+
+extern
+NDIS_STATUS
+IbmtokChangeFunctionalAddress(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN PIBMTOK_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest,
+ IN PUCHAR Address
+ );
+
+extern
+NDIS_STATUS
+IbmtokFillInGlobalData(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+
+extern
+VOID
+IbmtokForceAdapterInterrupt(
+ IN PIBMTOK_ADAPTER Adapter
+ );
+
+extern
+VOID
+IbmtokSetupForReset(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN PIBMTOK_OPEN Open
+ );
+
+extern
+VOID
+IbmtokStartAdapterReset(
+ IN PIBMTOK_ADAPTER Adapter
+ );
+
+extern
+VOID
+IbmtokFinishAdapterReset(
+ IN PIBMTOK_ADAPTER Adapter
+ );
+
+extern
+BOOLEAN
+IbmtokSynchSetReset(
+ IN PVOID Context
+ );
+
+extern
+VOID
+IbmtokAbortPending(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN NDIS_STATUS AbortStatus
+ );
+
+extern
+VOID
+IbmtokAbortSends(
+ IN PIBMTOK_ADAPTER Adapter,
+ IN NDIS_STATUS AbortStatus
+ );
+
+extern
+BOOLEAN
+IbmtokSynchClearIsrpBits(
+ IN PVOID Context
+ );
+
+extern
+NDIS_STATUS
+IbmtokTransferData(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+extern
+NDIS_STATUS
+IbmtokSend(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_PACKET Packet
+ );
+
+extern
+VOID
+IbmtokCopyFromPacketToBuffer(
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ IN UINT BytesToCopy,
+ OUT PCHAR Buffer,
+ OUT PUINT BytesCopied
+ );
+
+extern
+VOID
+IbmtokCopyFromBufferToPacket(
+ IN PCHAR Buffer,
+ IN UINT BytesToCopy,
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ OUT PUINT BytesCopied
+ );
+
+extern
+VOID
+IbmtokCopyFromPacketToPacket(
+ IN PNDIS_PACKET Destination,
+ IN UINT DestinationOffset,
+ IN UINT BytesToCopy,
+ IN PNDIS_PACKET Source,
+ IN UINT SourceOffset,
+ OUT PUINT BytesCopied
+ );
+
+extern
+VOID
+IbmtokShutdown(
+ IN PVOID ShutdownContext
+ );
+
+#endif // _IBMTOKSFT_
+
diff --git a/private/ntos/ndis/ibmtok/transfer.c b/private/ntos/ndis/ibmtok/transfer.c
new file mode 100644
index 000000000..8ae9da411
--- /dev/null
+++ b/private/ntos/ndis/ibmtok/transfer.c
@@ -0,0 +1,412 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ transfer.c
+
+Abstract:
+
+ This file contains the code to implement the MacTransferData
+ API for the ndis 3.0 interface.
+
+Author:
+
+ Anthony V. Ercolano (Tonye) 12-Sept-1990
+ Adam Barr (adamba) 15-Mar-1991
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent.
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+
+#include <tfilter.h>
+#include <tokhrd.h>
+#include <toksft.h>
+
+
+extern
+NDIS_STATUS
+IbmtokTransferData(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ )
+
+/*++
+
+Routine Description:
+
+ A protocol calls the IbmtokTransferData request (indirectly via
+ NdisTransferData) from within its Receive event handler
+ to instruct the MAC to copy the contents of the received packet
+ a specified packet buffer.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality this is a pointer to IBMTOK.
+
+ MacReceiveContext - The context value passed by the MAC on its call
+ to NdisIndicateReceive. The MAC can use this value to determine
+ which packet, on which adapter, is being received.
+
+ ByteOffset - An unsigned integer specifying the offset within the
+ received packet at which the copy is to begin. If the entire packet
+ is to be copied, ByteOffset must be zero.
+
+ BytesToTransfer - An unsigned integer specifying the number of bytes
+ to copy. It is legal to transfer zero bytes; this has no effect. If
+ the sum of ByteOffset and BytesToTransfer is greater than the size
+ of the received packet, then the remainder of the packet (starting from
+ ByteOffset) is transferred, and the trailing portion of the receive
+ buffer is not modified.
+
+ Packet - A pointer to a descriptor for the packet storage into which
+ the MAC is to copy the received packet.
+
+ BytesTransfered - A pointer to an unsigned integer. The MAC writes
+ the actual number of bytes transferred into this location. This value
+ is not valid if the return status is STATUS_PENDING.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+
+{
+
+ PIBMTOK_ADAPTER Adapter;
+
+ NDIS_STATUS StatusToReturn;
+
+ Adapter = PIBMTOK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ if (!Adapter->NotAcceptingRequests) {
+
+ PIBMTOK_OPEN Open = PIBMTOK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ if (!Open->BindingShuttingDown) {
+
+ //
+ // The code in this section is quite similar to the
+ // code in CopyFromPacketToPacket. It could easily go
+ // into its own routine, except that it is not likely
+ // to be used in any other implementation.
+ //
+ SRAM_PTR SourceReceiveBuffer =
+ Adapter->IndicatedReceiveBuffer;
+
+ //
+ // Holds the count of the number of ndis buffers comprising
+ // the destination packet.
+ //
+ UINT DestinationBufferCount;
+
+ //
+ // Points to the buffer into which we are putting data.
+ //
+ PNDIS_BUFFER DestinationCurrentBuffer;
+
+ //
+ // Holds the virtual address of the current destination
+ // buffer.
+ //
+ PVOID DestinationVirtualAddress;
+
+ //
+ // Holds the virtual address of the current source buffer.
+ //
+ PRECEIVE_BUFFER SourceBufferAddress;
+
+ //
+ // Holds the address of the data in the current source buffer.
+ //
+ PVOID SourceVirtualAddress;
+
+ //
+ // Holds the length of the current destination buffer.
+ //
+ UINT DestinationCurrentLength;
+
+ //
+ // Holds the length of the current source buffer.
+ //
+ UINT SourceCurrentLength;
+
+ //
+ // Keep a local variable of BytesTransferred so we aren't
+ // referencing through a pointer.
+ //
+ UINT LocalBytesTransferred = 0;
+
+ USHORT PortValue;
+
+ Open->References++;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ *BytesTransferred = 0;
+
+ ASSERT(sizeof(UINT) >= 2);
+ ASSERT(sizeof(UINT) == sizeof(NDIS_HANDLE));
+
+ //
+ // Get the first buffer of the destination.
+ //
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ &DestinationBufferCount,
+ &DestinationCurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet.
+ //
+
+ if (DestinationBufferCount != 0) {
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+
+ //
+ // Get the information for the first buffer of the source.
+ //
+
+ SourceBufferAddress = (PRECEIVE_BUFFER)
+ ((PUCHAR)SRAM_PTR_TO_PVOID(Adapter,
+ SourceReceiveBuffer) + 2);
+
+ //
+ // Adjust the address and length to account for the
+ // header for this frame.
+ //
+
+ SourceVirtualAddress =
+ SourceBufferAddress->FrameData +
+ Adapter->IndicatedHeaderLength;
+
+ NdisReadRegisterUshort(&SourceBufferAddress->BufferLength,
+ &PortValue
+ );
+
+ SourceCurrentLength = IBMSHORT_TO_USHORT(PortValue) -
+ Adapter->IndicatedHeaderLength;
+
+
+
+ //
+ // Take care of boundary condition of zero length copy.
+ //
+
+ while (LocalBytesTransferred < BytesToTransfer) {
+
+ //
+ // Check to see whether we've exhausted the current
+ // destination buffer. If so, move onto the next one.
+ //
+
+ if (!DestinationCurrentLength) {
+
+ NdisGetNextBuffer(
+ DestinationCurrentBuffer,
+ &DestinationCurrentBuffer
+ );
+
+ if (!DestinationCurrentBuffer) {
+
+ //
+ // We've reached the end of the packet. We
+ // return with what we've done so far. (Which
+ // must be shorter than requested.)
+ //
+
+ break;
+
+ }
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+ continue;
+
+ }
+
+
+ //
+ // Check to see whether we've exhausted the current
+ // source buffer. If so, move onto the next one.
+ //
+
+ if (!SourceCurrentLength) {
+
+ NdisReadRegisterUshort(
+ &SourceBufferAddress->NextBuffer,
+ &SourceReceiveBuffer
+ );
+
+ if (SourceReceiveBuffer == NULL_SRAM_PTR) {
+
+ //
+ // We've reached the end of the frame. We
+ // return with what we've done so far. (Which
+ // must be shorter than requested.)
+ //
+
+ break;
+
+ }
+
+ SourceBufferAddress = (PRECEIVE_BUFFER)
+ SRAM_PTR_TO_PVOID(Adapter, SourceReceiveBuffer);
+
+ SourceVirtualAddress =
+ (PVOID)SourceBufferAddress->FrameData;
+
+ NdisReadRegisterUshort(
+ &SourceBufferAddress->BufferLength,
+ &SourceCurrentLength
+ );
+
+ SourceCurrentLength = IBMSHORT_TO_USHORT(
+ SourceCurrentLength
+ );
+
+ continue;
+
+ }
+
+ //
+ // Try to get us up to the point to start the copy.
+ //
+
+ if (ByteOffset) {
+
+ if (ByteOffset > SourceCurrentLength) {
+
+ //
+ // What we want isn't in this buffer.
+ //
+
+ ByteOffset -= SourceCurrentLength;
+ SourceCurrentLength = 0;
+ continue;
+
+ } else {
+
+ SourceVirtualAddress =
+ (PCHAR)SourceVirtualAddress + ByteOffset;
+ SourceCurrentLength -= ByteOffset;
+ ByteOffset = 0;
+
+ }
+
+ }
+
+ //
+ // Copy the data.
+ //
+
+ {
+
+ //
+ // Holds the amount of data to move.
+ //
+ UINT AmountToMove;
+
+ //
+ // Holds the amount desired remaining.
+ //
+ UINT Remaining = BytesToTransfer
+ - LocalBytesTransferred;
+
+ AmountToMove =
+ ((SourceCurrentLength <= DestinationCurrentLength)?
+ (SourceCurrentLength):(DestinationCurrentLength));
+
+ AmountToMove = ((Remaining < AmountToMove)?
+ (Remaining):(AmountToMove));
+
+ IBMTOK_MOVE_FROM_MAPPED_MEMORY(
+ DestinationVirtualAddress,
+ SourceVirtualAddress,
+ AmountToMove
+ );
+
+ DestinationVirtualAddress =
+ (PCHAR)DestinationVirtualAddress + AmountToMove;
+ SourceVirtualAddress =
+ (PCHAR)SourceVirtualAddress + AmountToMove;
+
+ LocalBytesTransferred += AmountToMove;
+ SourceCurrentLength -= AmountToMove;
+ DestinationCurrentLength -= AmountToMove;
+
+ }
+
+ }
+
+ *BytesTransferred = LocalBytesTransferred;
+
+ }
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Open->References--;
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ } else {
+
+ StatusToReturn = NDIS_STATUS_REQUEST_ABORTED;
+
+ }
+
+ } else {
+
+ if (Adapter->ResetInProgress) {
+
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ } else if (Adapter->OpenInProgress) {
+
+ StatusToReturn = NDIS_STATUS_FAILURE;
+
+ } else {
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ IBMTOK_ERRMSG_INVALID_STATE,
+ 1
+ );
+
+ }
+
+ }
+
+ IBMTOK_DO_DEFERRED(Adapter);
+ return StatusToReturn;
+}
diff --git a/private/ntos/ndis/ibmtok2e/command.c b/private/ntos/ndis/ibmtok2e/command.c
new file mode 100644
index 000000000..3705e163d
--- /dev/null
+++ b/private/ntos/ndis/ibmtok2e/command.c
@@ -0,0 +1,1811 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ command.c
+
+Abstract:
+
+ This file contains the code for managing command and transmit blocks on
+ the TOK162's queues. It is based loosely on the NE3200 driver.
+
+Author:
+
+ Kevin Martin(KevinMa) 04-Jan-1993
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+
+--*/
+
+#include <tok162sw.h>
+
+VOID
+TOK162SendCommandBlock(
+ PTOK162_ADAPTER Adapter,
+ PTOK162_SUPER_COMMAND_BLOCK CommandBlock
+ );
+
+extern
+NDIS_STATUS
+TOK162ChangeAddress(
+ OUT PTOK162_ADAPTER Adapter,
+ IN ULONG Address,
+ IN NDIS_OID Oid,
+ IN USHORT Command,
+ IN BOOLEAN Set
+ );
+
+
+VOID
+TOK162SubmitCommandBlock(
+ IN PTOK162_ADAPTER Adapter,
+ IN PTOK162_SUPER_COMMAND_BLOCK CommandBlock
+ )
+
+/*++
+
+Routine Description:
+
+ Submit a complete Command Block for execution by the TOK162.
+
+ NOTE: This routine assumes that it is called with the lock held.
+
+Arguments:
+
+ Adapter - The adapter that points to the ring entry structures.
+
+ CommandBlock - Holds the pointer to the Command Block to be
+ submitted.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Pointer to the most recently submitted Command Block.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK PreviousCommandBlock;
+
+ //
+ // Timestamp the command block.
+ //
+ CommandBlock->Timeout = FALSE;
+ CommandBlock->Hardware.State = TOK162_STATE_WAIT_FOR_ADAPTER;
+
+ //
+ // If the adapter is currently executing a command add this to
+ // the end of the waiting list. Otherwise submit this command to the card.
+ //
+ if (Adapter->CommandOnCard != NULL) {
+
+ //
+ // Pend this command
+ //
+ PreviousCommandBlock = Adapter->WaitingCommandTail;
+ Adapter->WaitingCommandTail = CommandBlock;
+
+ //
+ // Check if there are any other pendings. If not, we are
+ // the first pending. If there are others, tack this one on
+ // the end.
+ //
+ if (PreviousCommandBlock == NULL) {
+
+ Adapter->WaitingCommandHead = CommandBlock;
+
+ } else {
+
+ PreviousCommandBlock->NextCommand = CommandBlock;
+
+ }
+
+ } else {
+
+ //
+ // Set this command as the active one
+ //
+ Adapter->CommandOnCard = CommandBlock;
+
+ //
+ // send the command out to the card
+ //
+ TOK162SendCommandBlock(Adapter,CommandBlock);
+
+ }
+
+}
+
+VOID
+TOK162AcquireCommandBlock(
+ IN PTOK162_ADAPTER Adapter,
+ OUT PTOK162_SUPER_COMMAND_BLOCK * CommandBlock
+ )
+
+/*++
+
+Routine Description:
+
+ Gets the command block.
+
+ NOTE: This routine assumes that the lock is held.
+
+Arguments:
+
+ Adapter - The adapter that points to the ring entry structures.
+
+ CommandBlock - Will receive a pointer to a Command Block.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Pointer to the command block to be returned.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK temp;
+
+ //
+ // This is a pointer to the Command Block.
+ //
+ temp = Adapter->CommandQueue + Adapter->NextCommandBlock;
+
+ ASSERT(Adapter->NumberOfAvailableCommandBlocks > 0);
+
+ //
+ // Decrement the number of available command blocks
+ //
+ Adapter->NumberOfAvailableCommandBlocks--;
+
+ //
+ // Initialize the Command Block.
+ //
+ NdisZeroMemory(
+ temp,
+ sizeof(TOK162_SUPER_COMMAND_BLOCK)
+ );
+
+ //
+ // There aren't any linked command blocks right now.
+ //
+ temp->Hardware.NextPending = TOK162_NULL;
+
+ //
+ // Increment to next command block
+ //
+ if (Adapter->NextCommandBlock == (TOK162_NUMBER_OF_CMD_BLOCKS - 1)) {
+
+ Adapter->NextCommandBlock = 0;
+
+ } else {
+
+ Adapter->NextCommandBlock++;
+
+ }
+
+ //
+ // Return the Command Block pointer.
+ //
+ *CommandBlock = temp;
+
+}
+
+
+VOID
+TOK162RelinquishCommandBlock(
+ IN PTOK162_ADAPTER Adapter,
+ IN PTOK162_SUPER_COMMAND_BLOCK CommandBlock
+ )
+
+/*++
+
+Routine Description:
+
+ Relinquish the Command Block resource.
+
+ NOTE: This routine assumes that the lock is held.
+
+Arguments:
+
+ Adapter - The adapter that owns the Command Block.
+
+ CommandBlock - The Command Block to relinquish.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // If there is a waiting chain of commands -- submit the first one
+ //
+ if (Adapter->WaitingCommandHead != NULL) {
+
+ //
+ // Mark the next one as the active one.
+ //
+ Adapter->CommandOnCard = Adapter->WaitingCommandHead;
+
+ //
+ // Update the waiting command head.
+ //
+ Adapter->WaitingCommandHead =
+ Adapter->WaitingCommandHead->NextCommand;
+
+ //
+ // Update the waiting command tail pointer
+ //
+ if (Adapter->WaitingCommandHead == NULL) {
+
+ Adapter->WaitingCommandTail = NULL;
+
+ }
+
+ //
+ // Send out the new command
+ //
+ TOK162SendCommandBlock(Adapter,Adapter->CommandOnCard);
+
+ } else {
+
+ //
+ // No commands on the card. We're done for now.
+ //
+ Adapter->CommandOnCard = NULL;
+
+ }
+
+ //
+ // Free the command block
+ //
+ CommandBlock->Hardware.State = TOK162_STATE_FREE;
+ CommandBlock->NextCommand = NULL;
+
+ //
+ // Increment the number of available command blocks
+ //
+ Adapter->NumberOfAvailableCommandBlocks++;
+
+}
+
+
+void
+TOK162SendCommandBlock(
+ IN PTOK162_ADAPTER Adapter,
+ IN PTOK162_SUPER_COMMAND_BLOCK CommandBlock
+ )
+{
+/*++
+
+Routine Description:
+
+ Submits the command block passed in to the card.
+
+Arguments:
+
+ Adapter - The adapter that owns the Command Block.
+
+ CommandBlock - The command/transmit block to submit.
+
+Return Value:
+
+ None.
+
+--*/
+
+ //
+ // First figure out the SCB, based on the command
+ //
+ Adapter->Scb->Command = CommandBlock->Hardware.CommandCode;
+
+ switch(Adapter->Scb->Command) {
+
+ //
+ // These are the Immediate Data commands. Close doesn't care what
+ // is passed, however.
+ //
+ case CMD_DMA_CLOSE:
+ case CMD_DMA_SET_GRP_ADDR:
+ case CMD_DMA_SET_FUNC_ADDR:
+
+ //
+ // The parameter is set according to the ImmediateData field of
+ // the command block.
+ //
+ Adapter->Scb->Parm1 =
+ HIGH_WORD(CommandBlock->Hardware.ImmediateData);
+
+ Adapter->Scb->Parm2 =
+ LOW_WORD(CommandBlock->Hardware.ImmediateData);
+
+ break;
+
+ //
+ // The rest use a pointer.
+ //
+ case CMD_DMA_OPEN:
+ case CMD_DMA_READ_ERRLOG:
+ case CMD_DMA_READ:
+ case CMD_DMA_IMPL_ENABLE:
+
+ //
+ // The parameter is set according to the ParmPointer field of
+ // the command block.
+ //
+ Adapter->Scb->Parm1 =
+ HIGH_WORD(CommandBlock->Hardware.ParmPointer);
+
+ Adapter->Scb->Parm2 =
+ LOW_WORD(CommandBlock->Hardware.ParmPointer);
+
+ break;
+
+ }
+
+ //
+ // Mark the command block as executing
+ //
+ CommandBlock->Hardware.State = TOK162_STATE_EXECUTING;
+
+ //
+ // Display the SCB on the debugger
+ //
+ EXTRA_LOUD_DEBUG(DbgPrint("IBMTOK2E!SCB going out is %x,%x,%x\n",
+ Adapter->Scb->Command,
+ Adapter->Scb->Parm1,
+ Adapter->Scb->Parm2);)
+
+ //
+ // Download the SCB to the card
+ //
+ TOK162DownLoadScb(Adapter);
+
+ //
+ // Finally, send the command out to the card
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_COMMAND,
+ EXECUTE_SCB_COMMAND
+ );
+
+}
+
+
+void
+TOK162UpLoadSsb(
+ IN PTOK162_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ Reads the Ssb from the card and stores it in the Adapter structure
+
+Arguments:
+
+ Adapter - The adapter that has info in the Ssb.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // First set the address register on the card to point to the Ssb
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_ADDRESS,
+ Adapter->CommunicationOffset + COMMUNICATION_SSB_OFFSET
+ );
+
+ //
+ // Now read the Ssb from the card starting with the command
+ //
+ READ_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA_AUTO_INC,
+ &Adapter->Ssb->Command
+ );
+
+ //
+ // Now read the first parameter of the Ssb
+ //
+ READ_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA_AUTO_INC,
+ &Adapter->Ssb->Status1
+ );
+
+ //
+ // Now read the second parameter of the Ssb
+ //
+ READ_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA_AUTO_INC,
+ &Adapter->Ssb->Status2
+ );
+
+ //
+ // Now read the second parameter of the Ssb
+ //
+ READ_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA_AUTO_INC,
+ &Adapter->Ssb->Status3
+ );
+}
+
+
+void
+TOK162DownLoadScb(
+ IN PTOK162_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ Sends the readied SCB to the card
+
+Arguments:
+
+ Adapter - The adapter that owns the Command Block.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // First set the address register on the card to point to the SCB
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_ADDRESS,
+ Adapter->CommunicationOffset
+ );
+
+ //
+ // Now write the SCB to the card starting with the command
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA_AUTO_INC,
+ Adapter->Scb->Command
+ );
+
+ //
+ // Now write the first parameter of the SCB
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA_AUTO_INC,
+ Adapter->Scb->Parm1
+ );
+
+ //
+ // Now write the first parameter of the SCB
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA_AUTO_INC,
+ Adapter->Scb->Parm2
+ );
+
+}
+
+
+void
+TOK162DownLoadReceiveList(
+ IN PTOK162_ADAPTER Adapter,
+ IN PTOK162_SUPER_RECEIVE_LIST RcvList
+ )
+/*++
+
+Routine Description:
+
+ Writes a receive list to the adapter
+
+Arguments:
+
+ Adapter - The adapter that owns the Command Block.
+ RcvList - Receive List to be written to the adapter
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // First set the address register on the card to point to correct
+ // receive list.
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_ADDRESS,
+ RcvList->AdapterOffset
+ );
+
+ //
+ // Write the size of the buffer
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA_AUTO_INC,
+ Adapter->ReceiveBufferSize
+ );
+
+ //
+ // Now write high part of the buffer address
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA_AUTO_INC,
+ HIGH_WORD(NdisGetPhysicalAddressLow(RcvList->ReceiveBufferPhysical))
+ );
+
+ //
+ // Now write the low part of the buffer address
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA_AUTO_INC,
+ LOW_WORD(NdisGetPhysicalAddressLow(RcvList->ReceiveBufferPhysical))
+ );
+
+ //
+ // Now write the Receive List CSTAT to the card
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA_AUTO_INC,
+ RcvList->Hardware.CSTAT
+ );
+
+}
+
+
+void
+TOK162UpLoadReceiveList(
+ IN PTOK162_ADAPTER Adapter,
+ OUT PTOK162_SUPER_RECEIVE_LIST RcvList
+ )
+/*++
+
+Routine Description:
+
+ Reads a receive list from the adapter
+
+Arguments:
+
+ Adapter - The adapter that owns the Command Block.
+ RcvList - Receive List to be read
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Dummy variable to hold the address of the buffer, which won't change
+ //
+ USHORT Dummy;
+
+ //
+ // First set the address register on the card to point to correct
+ // receive list.
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_ADDRESS,
+ RcvList->AdapterOffset
+ );
+
+ //
+ // Read the size of the buffer
+ //
+ READ_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA_AUTO_INC,
+ &(RcvList->Hardware.FrameSize)
+ );
+
+ //
+ // Read the high part of the buffer address
+ //
+ READ_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA_AUTO_INC,
+ &Dummy
+ );
+
+ //
+ // Read the low part of the buffer address
+ //
+ READ_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA_AUTO_INC,
+ &Dummy
+ );
+
+ //
+ // Now read the Receive List CSTAT
+ //
+ READ_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA_AUTO_INC,
+ &RcvList->Hardware.CSTAT
+ );
+
+}
+
+extern
+NDIS_STATUS
+TOK162SetInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ )
+
+/*++
+
+Routine Description:
+
+ TOK162SetInformation handles a set operation for a
+ single OID.
+
+Arguments:
+
+ MiniportAdapterContext - The adapter that the set is for.
+
+ BytesNeeded - If there is not enough data in OvbBuffer
+ to satisfy the OID, returns the amount of storage needed.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_PENDING
+ NDIS_STATUS_INVALID_LENGTH
+ NDIS_STATUS_INVALID_OID
+
+--*/
+
+{
+ //
+ // Pointer to the TOK162 adapter structure.
+ //
+ PTOK162_ADAPTER Adapter =
+ PTOK162_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ //
+ // Return value from NDIS calls
+ //
+ NDIS_STATUS Status;
+
+ //
+ // Temporary storage for the packet filter
+ //
+ ULONG TempFilter;
+
+ //
+ // Process request based on the OID
+ //
+ switch (Oid) {
+
+ case OID_802_5_CURRENT_FUNCTIONAL:
+
+ if (InformationBufferLength != TR_LENGTH_OF_FUNCTIONAL) {
+
+ //
+ // The data must be a multiple of the functional
+ // address size.
+ //
+
+ Status = NDIS_STATUS_INVALID_DATA;
+
+ }
+
+ //
+ // Save the address away
+ //
+ NdisMoveMemory(&Adapter->FunctionalAddress,
+ InformationBuffer,
+ InformationBufferLength
+ );
+
+ //
+ // Need to reverse it
+ //
+ Adapter->FunctionalAddress =
+ BYTE_SWAP_ULONG(Adapter->FunctionalAddress);
+
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Functional Address is now %x\n",
+ Adapter->FunctionalAddress);)
+
+ //
+ // Now call the filter package to set up the address if the
+ // functional address has been set in the packet filter.
+ //
+ if (Adapter->CurrentPacketFilter & NDIS_PACKET_TYPE_FUNCTIONAL) {
+
+ Status = TOK162ChangeAddress(
+ Adapter,
+ Adapter->FunctionalAddress,
+ Oid,
+ CMD_DMA_SET_FUNC_ADDR,
+ TRUE
+ );
+
+ //
+ // Nothing changed with the card, so return SUCCESS
+ //
+ } else {
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ }
+
+ //
+ // Set number of bytes read
+ //
+ *BytesRead = TR_LENGTH_OF_FUNCTIONAL;
+
+ break;
+
+ case OID_802_5_CURRENT_GROUP:
+
+ //
+ // Group addresses and Functional addresses are the same length.
+ //
+ if (InformationBufferLength != TR_LENGTH_OF_FUNCTIONAL) {
+
+ //
+ // The data must be a multiple of the group
+ // address size.
+ //
+ Status = NDIS_STATUS_INVALID_DATA;
+
+ }
+
+ //
+ // Save the address away
+ //
+ NdisMoveMemory(&Adapter->GroupAddress,
+ InformationBuffer,
+ InformationBufferLength
+ );
+
+
+ //
+ // Need to reverse it
+ //
+ Adapter->GroupAddress =
+ BYTE_SWAP_ULONG(Adapter->GroupAddress);
+
+ //
+ // Now call the filter package to set up the address if group
+ // addresses have been set in the packet filter.
+ //
+ if ((Adapter->CurrentPacketFilter & NDIS_PACKET_TYPE_GROUP) != 0) {
+
+ Status = TOK162ChangeAddress(
+ Adapter,
+ Adapter->GroupAddress,
+ Oid,
+ CMD_DMA_SET_GRP_ADDR,
+ TRUE
+ );
+ } else {
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ }
+
+ //
+ // Set number of bytes read
+ //
+ *BytesRead = TR_LENGTH_OF_FUNCTIONAL;
+
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ //
+ // Make sure the new packet filter is the correct size (length)
+ //
+ if (InformationBufferLength != 4) {
+
+ Status = NDIS_STATUS_INVALID_DATA;
+
+ }
+
+ //
+ // Make sure packet filter is valid
+ //
+ TempFilter = *(PULONG)(InformationBuffer);
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!GEN_CURRENT_PACKET_FILTER = %x\n",TempFilter);)
+
+ //
+ // Make sure the new filter is not something we don't support
+ //
+ if (TempFilter & (NDIS_PACKET_TYPE_MULTICAST |
+ NDIS_PACKET_TYPE_ALL_MULTICAST |
+ NDIS_PACKET_TYPE_SMT |
+ NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_MAC_FRAME
+ )) {
+
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+
+ *BytesRead = 4;
+ *BytesNeeded = 0;
+
+ break;
+ }
+
+ //
+ // We have a good packet filter, so save it.
+ //
+ Adapter->CurrentPacketFilter = TempFilter;
+
+ //
+ // This is a filter we can deal with. Go change the functional
+ // and group addresses based on the filter.
+ //
+ Status = TOK162ChangeFuncGroup(Adapter);
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ //
+ // We don't change anything, but we accept any value.
+ //
+ *BytesRead = 4;
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ break;
+
+ //
+ // We got an OID that is not settable.
+ //
+ default:
+
+ Status = NDIS_STATUS_INVALID_OID;
+ break;
+ }
+
+ //
+ // If we have a request pending as a result of any work we've done,
+ // mark it.
+ //
+ if (Status == NDIS_STATUS_PENDING) {
+
+ Adapter->RequestInProgress = TRUE;
+
+ }
+
+ return Status;
+}
+
+extern
+NDIS_STATUS
+TOK162ChangeAddress(
+ OUT PTOK162_ADAPTER Adapter,
+ IN ULONG Address,
+ IN NDIS_OID Oid,
+ IN USHORT Command,
+ IN BOOLEAN Set
+ )
+/*++
+
+Routine Description:
+
+ TOK162ChangeAddress will submit a command for either a group or
+ functional address, based on what is passed in.
+
+Arguments:
+
+ Adapter - Structure representing the current adapter
+
+ Address - The ULONG address to send to the card
+
+ Oid - Current Oid (Either functional or group)
+
+ Command - Command to send to card
+
+ Set - Whether to mark the command as a set. If we need to change two
+ addresses (ChangeFuncGroup) as the result of one Oid, we will
+ only do a completion for the one with the set. In the normal
+ case of one address being set, Set will always be TRUE.
+
+Return Value:
+
+ NDIS_STATUS_PENDING
+
+--*/
+{
+ //
+ // Command block pointer
+ //
+ PTOK162_SUPER_COMMAND_BLOCK CommandBlock;
+
+ //
+ // Set the adapter Oid to the current Oid
+ //
+ Adapter->Oid = Oid;
+
+ //
+ // Get a command block
+ //
+ TOK162AcquireCommandBlock(Adapter,
+ &CommandBlock
+ );
+
+ //
+ // Set the command block based on the parameters passed in
+ //
+ CommandBlock->Set = Set;
+ CommandBlock->NextCommand = NULL;
+ CommandBlock->Hardware.Status = 0;
+ CommandBlock->Hardware.NextPending = TOK162_NULL;
+ CommandBlock->Hardware.CommandCode = Command;
+ CommandBlock->Hardware.ImmediateData = Address;
+
+ //
+ // Display the address about to be set on the debugger.
+ //
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Address being set is %lx\n",
+ CommandBlock->Hardware.ImmediateData);)
+
+ //
+ // Indicate that a request is in progress
+ //
+ Adapter->RequestInProgress = TRUE;
+
+ //
+ // Make this request be in progress.
+ //
+ TOK162SubmitCommandBlock(Adapter, CommandBlock);
+
+ //
+ // Complete the request when the interrupt comes in.
+ //
+ return NDIS_STATUS_PENDING;
+}
+
+
+NDIS_STATUS
+TOK162QueryInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+)
+
+/*++
+
+Routine Description:
+
+ The TOK162QueryInformation process a Query request for specific
+ NDIS_OIDs
+
+Arguments:
+
+ MiniportAdapterContext - a pointer to the adapter.
+
+ Oid - the NDIS_OID to process.
+
+ InformationBuffer - a pointer into the
+ NdisRequest->InformationBuffer into which
+ we store the result of the query
+
+ InformationBufferLength - a pointer to the number of bytes left in the
+ InformationBuffer.
+
+ BytesWritten - a pointer to the number of bytes written into
+ the InformationBuffer.
+
+ BytesNeeded - If there is not enough room in the information
+ buffer this will contain the number of bytes
+ needed to complete the request.
+
+Return Value:
+
+ The function value is the status of the operation.(NDIS_STATUS_PENDING)
+
+--*/
+
+{
+ //
+ // Command block used for the request.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK CommandBlock;
+
+ //
+ // Adapter structure for the current card
+ //
+ PTOK162_ADAPTER Adapter =
+ PTOK162_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ //
+ // If we are in the middle of a reset, return this fact
+ //
+ if (Adapter->ResetInProgress == TRUE) {
+
+ return(NDIS_STATUS_RESET_IN_PROGRESS);
+
+ }
+
+ //
+ // Save the information passed in
+ //
+ Adapter->BytesWritten = BytesWritten;
+
+ Adapter->BytesNeeded = BytesNeeded;
+
+ Adapter->Oid = Oid;
+
+ Adapter->InformationBuffer = InformationBuffer;
+
+ Adapter->InformationBufferLength = InformationBufferLength;
+
+ //
+ // Get a command block
+ //
+ TOK162AcquireCommandBlock(Adapter,
+ &CommandBlock
+ );
+
+ //
+ // Notify that this is from a set
+ //
+ CommandBlock->Set = TRUE;
+
+ //
+ // Setup the common fields of the command block.
+ //
+ CommandBlock->NextCommand = NULL;
+ CommandBlock->Hardware.Status = 0;
+ CommandBlock->Hardware.NextPending = TOK162_NULL;
+
+ //
+ // Figure out the specific command based on the OID
+ //
+ switch(Oid) {
+
+ //
+ // If the permanent address is requested, we need to read from
+ // the adapter at the permanent address offset.
+ //
+ case OID_802_5_PERMANENT_ADDRESS:
+
+ //
+ // Fill in the adapter buffer area with the information to
+ // obtain the permanent address.
+ //
+ Adapter->AdapterBuf->DataCount = 0x0006;
+
+ Adapter->AdapterBuf->DataAddress = Adapter->UniversalAddress;
+
+ //
+ // Set the command block for the read adapter command.
+ //
+ CommandBlock->Hardware.CommandCode = CMD_DMA_READ;
+
+ CommandBlock->Hardware.ParmPointer =
+ NdisGetPhysicalAddressLow(Adapter->AdapterBufPhysical);
+
+ break;
+
+ //
+ // For any of the current addresses (functional, group, network)
+ // we will want to read the current addresses as the adapter has
+ // them recorded.
+ //
+ case OID_802_5_CURRENT_FUNCTIONAL:
+ case OID_802_5_CURRENT_GROUP:
+ case OID_802_5_CURRENT_ADDRESS:
+
+ //
+ // Set up the adapter buffer to get the current addresses.
+ //
+ Adapter->AdapterBuf->DataCount = 0x000e;
+
+ Adapter->AdapterBuf->DataAddress = Adapter->AdapterAddresses;
+
+ //
+ // Set the command block for the read adapter command.
+ //
+ CommandBlock->Hardware.CommandCode = CMD_DMA_READ;
+
+ CommandBlock->Hardware.ParmPointer =
+ NdisGetPhysicalAddressLow(Adapter->AdapterBufPhysical);
+
+ break;
+
+ //
+ // For any other OID, we read the errorlog to help make sure we
+ // don't get a counter overflow and lose information.
+ //
+ default:
+
+ //
+ // Set the command block for a read error log command.
+ //
+ CommandBlock->Hardware.CommandCode = CMD_DMA_READ_ERRLOG;
+
+ CommandBlock->Hardware.ParmPointer =
+ NdisGetPhysicalAddressLow(Adapter->ErrorLogPhysical);
+
+ break;
+ }
+
+ //
+ // Now that we're set up, let's do it!
+ //
+ Adapter->RequestInProgress = TRUE;
+
+ //
+ // Submit the command to the card
+ //
+ TOK162SubmitCommandBlock(Adapter,
+ CommandBlock
+ );
+
+ //
+ // Complete the request when the interrupt comes in.
+ //
+
+ return NDIS_STATUS_PENDING;
+}
+
+VOID
+TOK162FinishQueryInformation(
+ IN PTOK162_ADAPTER Adapter
+)
+
+/*++
+
+Routine Description:
+
+ The TOK162FinishQueryInformation finish processing a Query request for
+ NDIS_OIDs that are specific about the Driver.
+
+Arguments:
+
+ Adapter - a pointer to the adapter.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+//
+// The list of Oid's that we support with this driver.
+//
+static
+NDIS_OID TOK162GlobalSupportedOids[] = {
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+ OID_GEN_RCV_CRC_ERROR,
+ OID_GEN_TRANSMIT_QUEUE_LENGTH,
+ OID_802_5_PERMANENT_ADDRESS,
+ OID_802_5_CURRENT_ADDRESS,
+ OID_802_5_CURRENT_FUNCTIONAL,
+ OID_802_5_CURRENT_GROUP,
+ OID_802_5_LAST_OPEN_STATUS,
+ OID_802_5_LINE_ERRORS,
+ OID_802_5_LOST_FRAMES,
+ OID_802_5_BURST_ERRORS,
+ OID_802_5_FRAME_COPIED_ERRORS,
+ OID_802_5_TOKEN_ERRORS
+ };
+
+ //
+ // Variable to keep track of the bytes written out.
+ //
+ PUINT BytesWritten = Adapter->BytesWritten;
+
+ //
+ // Variable to keep track of the bytes needed
+ //
+ PUINT BytesNeeded = Adapter->BytesNeeded;
+
+ //
+ // The actual Oid that just finished.
+ //
+ NDIS_OID Oid = Adapter->Oid;
+
+ //
+ // Result buffer.
+ //
+ PVOID InformationBuffer = Adapter->InformationBuffer;
+
+ //
+ // Length of result buffer.
+ //
+ UINT InformationBufferLength = Adapter->InformationBufferLength;
+
+ //
+ // The medium supported by this driver.
+ //
+ NDIS_MEDIUM Medium = NdisMedium802_5;
+
+ //
+ // Generic repository for ULONG results
+ //
+ UINT GenericUlong;
+
+ //
+ // Generic repository for USHORT results
+ //
+ USHORT GenericUShort;
+
+ //
+ // Generic repository for character array results
+ //
+ UCHAR GenericArray[6];
+
+ //
+ // Pointer to source of result Common variables for pointing to result of query
+ //
+ PVOID MoveSource = (PVOID)(&GenericUlong);
+
+ //
+ // Number of bytes to be moved, defaulting to the size of a ULONG.
+ //
+ ULONG MoveBytes = sizeof(ULONG);
+
+ //
+ // Hardware Status
+ //
+ NDIS_HARDWARE_STATUS HardwareStatus;
+
+ //
+ // Return value of NDIS calls
+ //
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ //
+ // Initialize bytes written and bytes needed
+ //
+ *BytesWritten = 0;
+ *BytesNeeded = 0;
+
+ //
+ // Switch on the Oid
+ //
+ switch(Oid){
+
+ //
+ // The MAC options represents the options our driver supports/needs.
+ //
+ case OID_GEN_MAC_OPTIONS:
+
+ //
+ // We don't pend transfers, we need help on loopback,
+ // we copy lookahead data, and we have serialized receives.
+ //
+ GenericUlong = (ULONG)(NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
+ //NDIS_MAC_OPTION_NO_LOOPBACK |
+ NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
+ NDIS_MAC_OPTION_RECEIVE_SERIALIZED
+ );
+
+ break;
+
+ //
+ // We return the list of Oid's we support (list above)
+ //
+ case OID_GEN_SUPPORTED_LIST:
+
+ //
+ // Point to the beginning of the list.
+ //
+ MoveSource = (PVOID)(TOK162GlobalSupportedOids);
+
+ //
+ // We have to move the whole list.
+ //
+ MoveBytes = sizeof(TOK162GlobalSupportedOids);
+
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+
+ //
+ // If we have a reset in progress, the hardware status is
+ // set to reset. Otherwise, we return that we are ready.
+ //
+ if (Adapter->ResetInProgress) {
+
+ HardwareStatus = NdisHardwareStatusReset;
+
+ } else {
+
+ HardwareStatus = NdisHardwareStatusReady;
+
+ }
+
+ //
+ // Set the pointer to the HardwareStatus variable
+ //
+ MoveSource = (PVOID)(&HardwareStatus);
+
+ //
+ // Move the size of hardware status bytes
+ //
+ MoveBytes = sizeof(NDIS_HARDWARE_STATUS);
+
+ break;
+
+ //
+ // Simply indicate that we support TokenRing.
+ //
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+
+ MoveSource = (PVOID) (&Medium);
+ MoveBytes = sizeof(NDIS_MEDIUM);
+ break;
+
+ //
+ // The maximum lookahead, current lookahead, and frame size are
+ // static and are equal to the maximum frame size minus the header
+ // size.
+ //
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+
+ GenericUlong = Adapter->ReceiveBufferSize - TOK162_HEADER_SIZE;
+ break;
+
+ //
+ // Total sizes are easier because we don't have to subtract out the
+ // header size.
+ //
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+ GenericUlong = Adapter->ReceiveBufferSize;
+ break;
+
+
+ //
+ // Link speed is either 4MBPS or 16MBPS depending on which we're
+ // running on.
+ //
+ case OID_GEN_LINK_SPEED:
+
+ GenericUlong = (Adapter->Running16Mbps == TRUE) ? (ULONG)160000 :
+ (ULONG)40000;
+
+ break;
+
+
+ //
+ // Transmit buffer space is found by multiplying the size of the
+ // transmit buffers (same as receive buffer size) by the number
+ // of transmit lists.
+ //
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+
+ GenericUlong = (ULONG)Adapter->ReceiveBufferSize *
+ TRANSMIT_LIST_COUNT;
+
+ break;
+
+ //
+ // Receive buffer space is equal to multiplying the size of receive
+ // buffers by the number of receive lists.
+ //
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+
+ GenericUlong = (ULONG) Adapter->ReceiveBufferSize *
+ RECEIVE_LIST_COUNT;
+
+ break;
+
+
+ //
+ // The vendor ID is calculated by ANDing the current network address
+ // with 0xFFFFFF00.
+ //
+ case OID_GEN_VENDOR_ID:
+
+ //
+ // Get the current network address.
+ //
+ NdisMoveMemory(
+ (PVOID)&GenericUlong,
+ Adapter->NetworkAddress,
+ 3
+ );
+ GenericUlong &= 0xFFFFFF00;
+
+ MoveSource = (PVOID)(&GenericUlong);
+
+ MoveBytes = sizeof(GenericUlong);
+
+ break;
+
+ //
+ // Return our vendor string
+ //
+ case OID_GEN_VENDOR_DESCRIPTION:
+
+ MoveSource = (PVOID)"IBM Busmaster EISA TokenRing Adapter ";
+
+ MoveBytes = 30;
+
+ break;
+
+ //
+ // Return our version (3.00) number
+ //
+ case OID_GEN_DRIVER_VERSION:
+
+ GenericUShort = (USHORT)0x0300;
+
+ MoveSource = (PVOID)(&GenericUShort);
+
+ MoveBytes = sizeof(GenericUShort);
+
+ break;
+
+ //
+ // Return the permanent address
+ //
+ case OID_802_5_PERMANENT_ADDRESS:
+
+ TR_COPY_NETWORK_ADDRESS(
+ (PCHAR)GenericArray,
+ Adapter->NetworkAddress
+ );
+
+ MoveSource = (PVOID)(GenericArray);
+
+ MoveBytes = TR_LENGTH_OF_ADDRESS;
+
+ break;
+
+ //
+ // Return the current address.
+ //
+ case OID_802_5_CURRENT_ADDRESS:
+
+ TR_COPY_NETWORK_ADDRESS(
+ (PCHAR)GenericArray,
+ Adapter->CurrentAddress
+ );
+
+ MoveSource = (PVOID)(GenericArray);
+
+ MoveBytes = TR_LENGTH_OF_ADDRESS;
+
+ break;
+
+ //
+ // Return the current functional address.
+ //
+ case OID_802_5_CURRENT_FUNCTIONAL:
+
+ //
+ // Get the address stored in the adapter structure
+ //
+ GenericUlong = (ULONG)Adapter->FunctionalAddress;
+
+ //
+ // Now we need to reverse the crazy thing.
+ //
+ GenericUlong = BYTE_SWAP_ULONG(GenericUlong);
+
+ break;
+
+ //
+ // Return the current group address.
+ //
+ case OID_802_5_CURRENT_GROUP:
+
+ //
+ // Get the address stored in the adapter structure
+ //
+ GenericUlong = (ULONG)Adapter->GroupAddress;
+
+ //
+ // Now we need to reverse the crazy thing.
+ //
+ GenericUlong = BYTE_SWAP_ULONG(GenericUlong);
+
+ break;
+
+ //
+ // Return the number of good transmits
+ //
+ case OID_GEN_XMIT_OK:
+
+ GenericUlong = (ULONG) Adapter->GoodTransmits;
+
+ break;
+
+ //
+ // Return the number of good receives
+ //
+ case OID_GEN_RCV_OK:
+
+ GenericUlong = (ULONG) Adapter->GoodReceives;
+
+ break;
+
+ //
+ // Return the number of transmit errors
+ //
+ case OID_GEN_XMIT_ERROR:
+
+ GenericUlong = (ULONG) Adapter->BadTransmits;
+
+ break;
+
+ //
+ // Return the number of receive errors
+ //
+ case OID_GEN_RCV_ERROR:
+
+ GenericUlong = (ULONG) 0;
+
+ break;
+
+ //
+ // Return the number of congestion errors that have occurred
+ //
+ case OID_GEN_RCV_NO_BUFFER:
+
+ GenericUlong = (ULONG) Adapter->ReceiveCongestionError;
+
+ break;
+
+ //
+ // Return the number of CRC errors (receives)
+ //
+ case OID_GEN_RCV_CRC_ERROR:
+
+ GenericUlong = (ULONG) 0;
+
+ break;
+
+ //
+ // Return the current transmit queue length
+ //
+ case OID_GEN_TRANSMIT_QUEUE_LENGTH:
+
+ GenericUlong = (ULONG) Adapter->TransmitsQueued;
+
+ break;
+
+ //
+ // Return the number of Line errors
+ //
+ case OID_802_5_LINE_ERRORS:
+
+ GenericUlong = (ULONG) Adapter->LineError;
+
+ break;
+
+ //
+ // Return the number of Lost Frames
+ //
+ case OID_802_5_LOST_FRAMES:
+
+ GenericUlong = (ULONG) Adapter->LostFrameError;
+
+ break;
+
+ //
+ // Return the number of Burst errors
+ //
+ case OID_802_5_BURST_ERRORS:
+
+ GenericUlong = (ULONG) Adapter->BurstError;
+
+ break;
+
+ //
+ // Return the number of Frame Copied Errors
+ //
+ case OID_802_5_FRAME_COPIED_ERRORS:
+
+ GenericUlong = (ULONG) Adapter->FrameCopiedError;
+
+ break;
+
+ //
+ // Return the number of Token errors
+ //
+ case OID_802_5_TOKEN_ERRORS:
+
+ GenericUlong = (ULONG) Adapter->TokenError;
+
+ break;
+ //
+ // Must be an unsupported Oid
+ //
+ default:
+
+ Status = NDIS_STATUS_INVALID_OID;
+
+ break;
+ }
+
+
+ //
+ // If there weren't any errors, copy the bytes indicated above.
+ //
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ //
+ // Make sure we don't have too much to move. If so, return an error.
+ //
+ if (MoveBytes > InformationBufferLength) {
+
+ //
+ // Not enough room in InformationBuffer. Punt
+ //
+
+ *BytesNeeded = MoveBytes;
+
+ Status = NDIS_STATUS_INVALID_LENGTH;
+
+ //
+ // Do the copy
+ //
+ } else {
+
+ *BytesWritten = MoveBytes;
+
+ if (MoveBytes > 0) {
+
+ NdisMoveMemory(
+ InformationBuffer,
+ MoveSource,
+ MoveBytes
+ );
+ }
+ }
+ }
+
+ //
+ // We're finished with the request.
+ //
+ Adapter->RequestInProgress = FALSE;
+
+ //
+ // Indicate the result to the protocol(s)
+ //
+ NdisMQueryInformationComplete(
+ Adapter->MiniportAdapterHandle,
+ Status
+ );
+
+ return;
+}
+
+
+NDIS_STATUS
+TOK162ChangeFuncGroup(
+ IN PTOK162_ADAPTER Adapter
+)
+/*++
+
+Routine Description:
+
+ The TOK162ChangeFuncGroup modifies the appropriate adapter
+ address (functional, group, or both). This routine submits two command
+ blocks representing one call to the system. Therefore, only the group
+ address change performs a status indication (the Set variable).
+
+Arguments:
+
+ Adapter - a pointer to the adapter.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ //
+ // Address to be set. Used for both functional and group addresses.
+ //
+ ULONG Address;
+
+ //
+ // Variable to hold the return value of NDIS calls
+ //
+ NDIS_STATUS Status;
+
+ //
+ // First check the functional address status, including the all
+ // functional address.
+ //
+ if ((Adapter->CurrentPacketFilter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL) != 0) {
+
+ Address = 0x7FFFFFFF;
+
+ } else if ((Adapter->CurrentPacketFilter & NDIS_PACKET_TYPE_FUNCTIONAL) != 0) {
+
+ Address = Adapter->FunctionalAddress;
+
+ } else {
+
+ Address = 0;
+
+ }
+
+ //
+ // Change the functional address on the card.
+ //
+ Status = TOK162ChangeAddress(
+ Adapter,
+ Address,
+ OID_802_5_CURRENT_FUNCTIONAL,
+ CMD_DMA_SET_FUNC_ADDR,
+ FALSE
+ );
+
+ //
+ // Now check the group address status
+ //
+ if ((Adapter->CurrentPacketFilter & NDIS_PACKET_TYPE_GROUP) != 0) {
+
+ Address = Adapter->GroupAddress;
+
+ } else {
+
+ Address = 0;
+
+ }
+
+ //
+ // Change the group address on the card.
+ //
+ Status = TOK162ChangeAddress(
+ Adapter,
+ Address,
+ OID_802_5_CURRENT_GROUP,
+ CMD_DMA_SET_GRP_ADDR,
+ TRUE
+ );
+
+ return(Status);
+}
diff --git a/private/ntos/ndis/ibmtok2e/interrup.c b/private/ntos/ndis/ibmtok2e/interrup.c
new file mode 100644
index 000000000..0cb455acd
--- /dev/null
+++ b/private/ntos/ndis/ibmtok2e/interrup.c
@@ -0,0 +1,1501 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ interrup.c
+
+Abstract:
+
+ This module contains the interrupt-processing code for the
+ TOK162 NDIS 3.0 driver.
+
+Author:
+
+ Kevin Martin (KevinMa) 26-Jan-1994
+
+Environment:
+
+ Kernel Mode.
+
+Revision History:
+
+--*/
+
+#include <tok162sw.h>
+
+VOID
+TOK162ProcessReceiveInterrupts(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+VOID
+TOK162ProcessCommandInterrupts(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+
+VOID
+TOK162Isr(
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueDpc,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ Interrupt service routine for the TOK162. Used only during init.
+ The NdisMRegisterInterrupt() call (reset.c) specified not to call the
+ ISR for every interrupt. The DPC is called directly instead.
+
+Arguments:
+
+ Interrupt - Interrupt object for the TOK162.
+
+ Context - Really a pointer to the adapter.
+
+Return Value:
+
+ Returns true if the interrupt really was from the TOK162 and whether the
+ wrapper should queue a DPC.
+
+--*/
+
+{
+
+ //
+ // Holds the pointer to the adapter structure.
+ //
+ PTOK162_ADAPTER Adapter = Context;
+
+ //
+ // Holds IsrpHigh with some bits masked off.
+ //
+ USHORT Sif;
+
+ //
+ // Indicate that an interrupt has occurred
+ //
+ VERY_LOUD_DEBUG(DbgPrint("TOK162E!ISR\n");)
+
+ //
+ // Read the adapter interrupt register
+ //
+ READ_ADAPTER_USHORT(Adapter,PORT_OFFSET_STATUS,&Sif);
+
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!SIF = %x\n",Sif);)
+
+ //
+ // Check if this is our interrupt. If it is, set flag indicating that the
+ // interrupt is recognized. Otherwise indicate that the interrupt is not
+ // ours.
+ //
+ if ((Sif & STATUS_SYSTEM_INTERRUPT) != 0) {
+
+ *InterruptRecognized = TRUE;
+
+ } else {
+
+ *InterruptRecognized = FALSE;
+
+ }
+
+ //
+ // Mask off the interrupt type portion of the register.
+ //
+ Sif = (UCHAR) (Sif & STATUS_INT_CODE_MASK);
+
+ //
+ // If we have a command, then it is the open or an error has occurred.
+ // Indicate that the Ssb can be cleared after the open info has been
+ // obtained.
+ //
+ if (Sif == STATUS_INT_CODE_CMD_STATUS) {
+
+ TOK162UpLoadSsb(Adapter);
+
+ Adapter->SsbCommand = Adapter->Ssb->Command;
+ Adapter->SsbStatus1 = Adapter->Ssb->Status1;
+
+ if (Adapter->SsbCommand == CMD_DMA_OPEN) {
+
+ Adapter->InitialOpenComplete = TRUE;
+
+ }
+ }
+
+ //
+ // Enable updating of the SSB
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_STATUS,
+ ENABLE_SSB_UPDATE
+ );
+
+
+ *QueueDpc = FALSE;
+
+}
+
+
+VOID
+TOK162DeferredTimer(
+ IN PVOID SystemSpecific1,
+ IN PTOK162_ADAPTER Adapter,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+/*++
+
+Routine Description:
+
+ Just an entry point to distinguish between a timer call and the wrapper
+ calling the DPC directly.
+
+Arguments:
+
+ Adapter - pointer to current adapter
+
+ The rest are not used, but simply passed on
+
+Return Value:
+
+ None
+
+--*/
+{
+ //
+ // Indicate that a timer has expired.
+ //
+ VERY_LOUD_DEBUG(DbgPrint("TOK162E!Deferred Timer called\n");)
+
+ //
+ // Call the standard DPC handler.
+ //
+ TOK162HandleInterrupt(Adapter);
+}
+
+
+VOID
+TOK162HandleInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ Main routine for processing interrupts.
+
+Arguments:
+
+ Adapter - The Adapter to process interrupts for.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Pointer to the TOK162 adapter structure.
+ //
+ PTOK162_ADAPTER Adapter = ((PTOK162_ADAPTER)MiniportAdapterContext);
+
+ //
+ // Holds the value of the status register
+ //
+ USHORT IMask = 0;
+
+ //
+ // Holds the interrupt type value
+ //
+ USHORT IType = 0;
+
+ //
+ // Hold value to write to adapter for receives/transmits
+ //
+ USHORT RcvXmtContinue;
+
+
+ //
+ // Boolean to indicate receive processing
+ //
+ BOOLEAN DoReceives;
+
+ //
+ // Boolean to indicate transmit processing
+ //
+ BOOLEAN DoTransmits;
+
+ //
+ // If any receive interrupts are processed, we have to indicate that
+ // the receive work has been completed after all interrupts have been
+ // processed.
+ //
+ BOOLEAN IndicateReceiveComplete = FALSE;
+
+ //
+ // Indicate that the DPC routine has been called.
+ //
+ EXTRA_LOUD_DEBUG(DbgPrint("IBMTOK2E!DPC was just called\n");)
+
+ //
+ // Loop through processing interrupts until we have processed them all.
+ //
+ while (TRUE) {
+
+ //
+ // Assume no transmits or receives
+ //
+ DoReceives = FALSE;
+ DoTransmits = FALSE;
+
+ //
+ // Read the adapter interrupt register
+ //
+ READ_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_STATUS,
+ &IMask
+ );
+
+ //
+ // If this is not our interrupt, end DPC processing
+ //
+ if ((IMask & STATUS_SYSTEM_INTERRUPT) == 0) {
+
+ break;
+
+ }
+
+ //
+ // Figure out the interrupt according to the spec.
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_COMMAND,
+ CMD_PIO_RESET_RCV_XMT
+ );
+
+ //
+ // Read the adapter interrupt register again
+ //
+ READ_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_STATUS,
+ &IMask
+ );
+
+ //
+ // Get the Ssb from the Adapter
+ //
+ TOK162UpLoadSsb(Adapter);
+
+ //
+ // Record pertinent information about the interrupt as this
+ // card/chipset only allows one interrupt to be indicated by
+ // the card at a time.
+ //
+ Adapter->SsbCommand = Adapter->Ssb->Command;
+ Adapter->SsbStatus1 = Adapter->Ssb->Status1;
+ Adapter->SsbStatus2 = Adapter->Ssb->Status2;
+ Adapter->SsbStatus3 = Adapter->Ssb->Status3;
+
+
+ IType = (UCHAR) (IMask & STATUS_INT_CODE_MASK);
+
+ //
+ // Indicate the type of interrupt to the debugger.
+ //
+ EXTRA_LOUD_DEBUG(DbgPrint("IBMTOK2E!New IMask is %x\n",IMask);)
+
+ //
+ // Process the interrupt based on the type of interrupt.
+ //
+ switch(IType) {
+
+ //
+ // Ring state or command interrupt
+ //
+ case STATUS_INT_CODE_RING:
+ case STATUS_INT_CODE_CMD_STATUS:
+
+ if(IType == STATUS_INT_CODE_RING) {
+
+ //
+ // If we have a soft error, it is possible that the
+ // card has become overrun with receives. Therefore, the
+ // TOK162ProcessRingInterrupts will return TRUE in this
+ // case to allow us to call ProcessReceiveInterrupts().
+ // In all other cases, TOK162ProcessRingInterrupts() will
+ // return FALSE.
+ //
+ if (TOK162ProcessRingInterrupts(Adapter) == TRUE) {
+
+ DoReceives = TRUE;
+
+ }
+
+ } else {
+
+ //
+ // If there is a command structure that has been sent to the
+ // adapter, then we will process that command. Otherwise, we
+ // simply return.
+ //
+ if (Adapter->CommandOnCard != NULL) {
+
+ //
+ // Process the active command.
+ //
+ TOK162ProcessCommandInterrupts(Adapter);
+
+ }
+
+ }
+
+ //
+ // Read the adapter interrupt register again
+ //
+ READ_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_STATUS,
+ &IMask
+ );
+
+ //
+ // Dismiss the interrupt, allowing the SSB to be updated.
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_STATUS,
+ ENABLE_SSB_UPDATE
+ );
+
+ //
+ // Were there any receive interrupts indicated
+ //
+ if ((IMask & STATUS_RECEIVE_FRAME_COMPLETE) == 0) {
+
+ DoReceives = TRUE;
+
+ }
+
+ //
+ // Were there any transmit interrupts indicated
+ //
+ if ((IMask & STATUS_TRANSMIT_FRAME_COMPLETE) == 0) {
+
+ DoTransmits = TRUE;
+
+ }
+
+ break;
+
+ case STATUS_INT_CODE_FRAME_STATUS:
+
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_COMMAND,
+ CMD_PIO_RESET_RCV_XMT
+ );
+
+ //
+ // Read the adapter interrupt register again
+ //
+ READ_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_STATUS,
+ &IMask
+ );
+
+ //
+ // Were there any receive interrupts indicated
+ //
+ if ((IMask & STATUS_RECEIVE_FRAME_COMPLETE) == 0) {
+
+ DoReceives = TRUE;
+
+ }
+
+ //
+ // Were there any transmit interrupts indicated
+ //
+ if ((IMask & STATUS_TRANSMIT_FRAME_COMPLETE) == 0) {
+
+ DoTransmits = TRUE;
+
+ }
+
+ break;
+
+ }
+
+ //
+ // Reset value to be sent out
+ //
+ RcvXmtContinue = 0;
+
+ //
+ // Do the continue on the card.
+ //
+ if ((DoReceives == TRUE) && (DoTransmits == TRUE)) {
+
+ RcvXmtContinue = CMD_PIO_RECEIVE_COMPLETE |
+ CMD_PIO_TRANSMIT_COMPLETE |
+ CMD_PIO_RESET_SYSTEM;
+
+ } else if (DoReceives == TRUE) {
+
+ RcvXmtContinue = CMD_PIO_RECEIVE_COMPLETE |
+ CMD_PIO_RESET_SYSTEM;
+
+ } else if (DoTransmits == TRUE) {
+
+ RcvXmtContinue = CMD_PIO_TRANSMIT_COMPLETE |
+ CMD_PIO_RESET_SYSTEM;
+
+ }
+
+ if (RcvXmtContinue != 0) {
+
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_COMMAND,
+ RcvXmtContinue
+ );
+
+ }
+
+ //
+ // Check to see if we have a receive
+ //
+ if (DoReceives == TRUE) {
+
+ //
+ // Process the receive
+ //
+ TOK162ProcessReceiveInterrupts(Adapter);
+
+
+ }
+
+ //
+ // Check to see if we have a transmit
+ //
+ if (DoTransmits == TRUE) {
+
+ //
+ // Process the transmit(s)
+ //
+ TOK162ProcessTransmitInterrupts(Adapter);
+
+ }
+
+ }
+
+ //
+ // If we processed any receive interrupts, IndicateReceiveComplete() will
+ // be set to TRUE. In this case, we need to indicate that all receives
+ // are complete.
+ //
+ if (Adapter->DoReceiveComplete) {
+
+ //
+ // Indicate to the debugger that we are doing the complete.
+ //
+ EXTRA_LOUD_DEBUG(DbgPrint("IBMTOK2E!Doing the indicate complete on the receive\n");)
+
+ //
+ // Call the Token Ring Filter to indicate the receive complete.
+ //
+ NdisMTrIndicateReceiveComplete(Adapter->MiniportAdapterHandle);
+ Adapter->DoReceiveComplete = FALSE;
+
+ }
+
+ //
+ // Indicate to the debugger that we are ending DPC processing.
+ //
+ EXTRA_LOUD_DEBUG(DbgPrint("IBMTOK2E!Ending DPC processing\n");)
+
+}
+
+
+VOID
+TOK162ProcessReceiveInterrupts(
+ IN PTOK162_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Process the packets that have finished receiving.
+
+ NOTE: This routine assumes that no other thread of execution
+ is processing receives!
+
+Arguments:
+
+ Adapter - The adapter to indicate to.
+
+Return Value:
+
+ Whether to clear interrupt or not
+
+--*/
+
+{
+
+ //
+ // We don't get here unless there was a receive. Loop through
+ // the receive blocks starting at the last known block owned by
+ // the hardware.
+ //
+ // After we find a packet we give the routine that process the
+ // packet through the filter, the buffers virtual address (which
+ // is always the lookahead size) and as the MAC Context the
+ // index to the receive block.
+ //
+
+ //
+ // Pointer to the receive block being examined.
+ //
+ PTOK162_SUPER_RECEIVE_LIST CurrentEntry = Adapter->ReceiveQueueCurrent;
+
+ //
+ // Used during receiveindicate to let the filter know the header size
+ // of the given buffer.
+ //
+ USHORT HeaderSize;
+
+ //
+ // Used to indicate the total size of the frame to the filter.
+ //
+ USHORT FrameSize;
+
+ //
+ // Points to the beginning of the received buffer. Used to determine the
+ // size of the frame header (source routing).
+ //
+ PUCHAR Temp;
+
+ //
+ // Log the fact that we are processing a receive.
+ //
+ IF_LOG('m');
+
+ //
+ // Continue processing receives until we have exhausted them.
+ //
+ while (TRUE) {
+
+ IF_LOG('k');
+ //
+ // Get the receive list info from the card for the current entry
+ //
+ TOK162UpLoadReceiveList(Adapter,CurrentEntry);
+
+ IF_LOG('K');
+ //
+ // Send the receive status byte to the debugger.
+ //
+ EXTRA_LOUD_DEBUG(DbgPrint("IBMTOK2E!Receive CSTAT == %x\n",
+ CurrentEntry->Hardware.CSTAT);)
+
+ //
+ // Check to see if CSTAT has been changed indicating
+ // the receive entry has been modified
+ //
+ if (((CurrentEntry->Hardware.CSTAT & RECEIVE_CSTAT_VALID) == 0) &&
+ ((CurrentEntry->Hardware.CSTAT & 0x4000) != 0)) {
+
+ CURRENT_DEBUG(DbgPrint("IBMTOK2E!Receive DPC\n");)
+
+ //
+ // Make sure the adapter and the system are in synch.
+ //
+ NdisFlushBuffer(CurrentEntry->FlushBuffer, FALSE);
+
+ //
+ // Get a pointer to the first byte of the current receive buffer.
+ //
+ Temp = (PUCHAR)CurrentEntry->ReceiveBuffer;
+
+ //
+ // If the source routing bit is on, figure out the size of the
+ // MAC Frame header. Otherwise, the size is set to the default
+ // of 14 (decimal).
+ //
+ HeaderSize = 14;
+
+ if (Temp[8] & 0x80) {
+
+ //
+ // Source routing bit is on in source address, so calculate
+ // the frame header size.
+ //
+ HeaderSize = (Temp[14] & 0x1f) + 14;
+
+ }
+
+ //
+ // Save the received header size.
+ //
+ Adapter->SizeOfReceivedHeader = HeaderSize;
+
+ //
+ // Record the fact that we had a good receive.
+ //
+ Adapter->GoodReceives++;
+
+ //
+ // Get the frame size of this buffer.
+ //
+ FrameSize = CurrentEntry->Hardware.FrameSize;
+
+ //
+ // Indicate the frame size to the debugger
+ //
+ EXTRA_LOUD_DEBUG(DbgPrint("IBMTOK2E!Frame size is %u\n",
+ FrameSize);)
+
+ //
+ // If the frame that we have been passed has an invalid length
+ // (less than the reported header size) then we need to check
+ // if the frame size is larger than the default address length.
+ //
+ if (FrameSize >= HeaderSize) {
+
+ //
+ // We have a 'normal' packet. Indicate this to the debugger
+ //
+ EXTRA_LOUD_DEBUG(DbgPrint("IBMTOK2E!Doing receive indicate\n");)
+
+ //
+ // Do the indication to the filter.
+ //
+ NdisMTrIndicateReceive(
+ Adapter->MiniportAdapterHandle,
+ (NDIS_HANDLE)(
+ ((PUCHAR)(CurrentEntry->ReceiveBuffer))+HeaderSize),
+ CurrentEntry->ReceiveBuffer,
+ (UINT)HeaderSize,
+ ((PUCHAR)CurrentEntry->ReceiveBuffer) + HeaderSize,
+ FrameSize - HeaderSize,
+ FrameSize - HeaderSize
+ );
+
+ Adapter->DoReceiveComplete = TRUE;
+
+
+ } else {
+
+ //
+ // If the frame size is greater than or equal to the length
+ // of an address (network address, 12 bytes) then we can
+ // indicate it as a runt packet to the filter. Otherwise,
+ // we ignore the received buffer.
+ //
+ if (FrameSize >= TOK162_LENGTH_OF_ADDRESS) {
+
+ //
+ // Indicate this is a runt packet to the debugger
+ //
+ VERY_LOUD_DEBUG(DbgPrint(
+ "IBMTOK2E!Doing receive indicate for a runt\n");)
+
+ //
+ // Indicate the packet to the filter.
+ //
+ NdisMTrIndicateReceive(
+ Adapter->MiniportAdapterHandle,
+ (NDIS_HANDLE)(
+ ((PUCHAR)(CurrentEntry->ReceiveBuffer)) + HeaderSize),
+ (PUCHAR)Temp,
+ (UINT)FrameSize,
+ NULL,
+ 0,
+ 0
+ );
+
+ Adapter->DoReceiveComplete = TRUE;
+
+ }
+
+ }
+
+ //
+ // Mark the receive list as processed and able to receive another
+ // buffer.
+ //
+ CurrentEntry->Hardware.CSTAT = RECEIVE_CSTAT_REQUEST_RESET;
+
+ //
+ // Reset the buffer size
+ //
+ CurrentEntry->Hardware.FrameSize = Adapter->ReceiveBufferSize;
+
+ //
+ // Download the receive list to the card (updated)
+ //
+ TOK162DownLoadReceiveList(Adapter,CurrentEntry);
+
+ //
+ // Move to the next entry to see if there are more to process.
+ //
+ CurrentEntry = CurrentEntry->NextEntry;
+
+ //
+ // Tell adapter we are accepting more receives
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_COMMAND,
+ ENABLE_RECEIVE_VALID
+ );
+
+ } else {
+
+
+ //
+ // Record the receive list entry following the last good
+ // entry as the starting point for the next time receives
+ // are processed.
+ //
+ Adapter->ReceiveQueueCurrent = CurrentEntry;
+
+ //
+ // Log that we are leaving the receive processing
+ //
+ IF_LOG('M');
+
+ //
+ // Tell adapter we are accepting more receives
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_COMMAND,
+ ENABLE_RECEIVE_VALID
+ );
+
+ return;
+
+ }
+
+ }
+}
+
+
+VOID
+TOK162ProcessCommandInterrupts(
+ IN PTOK162_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Process the Command Complete interrupts.
+
+ NOTE: This routine assumes that it is being executed in a
+ single thread of execution.
+
+Arguments:
+
+ Adapter - The adapter that was sent from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Pointer to command block being processed.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK CurrentCommandBlock = Adapter->CommandOnCard;
+
+ //
+ // Status variable
+ //
+ NDIS_STATUS Status;
+
+ //
+ // NetCard Address Block
+ //
+ PTOK162_ADDRESSBLOCK Addresses;
+
+ //
+ // Process the command based on the command code.
+ //
+ switch(CurrentCommandBlock->Hardware.CommandCode) {
+
+ case CMD_DMA_READ:
+
+ //
+ // We are processing a read command. The read command is
+ // generated by a query request.
+ //
+ // Indicate we are processing a read command to the
+ // debugger.
+ //
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!DPC for read adapter called\n");)
+
+ // Get a pointer to the block of memory set aside for the
+ // read command.
+ //
+ Addresses = (PTOK162_ADDRESSBLOCK)Adapter->AdapterBuf;
+
+ //
+ // Check the Oid to see if we are after the permanent card
+ // address or the current addresses.
+ //
+ if (Adapter->Oid == OID_802_5_PERMANENT_ADDRESS) {
+ //
+ // Update the permanent node address
+ //
+ NdisMoveMemory(
+ Adapter->NetworkAddress,
+ Addresses->NodeAddress,
+ 6
+ );
+
+ } else {
+
+ //
+ // Update the current network address
+ //
+ NdisMoveMemory(
+ (UNALIGNED PUCHAR)Adapter->CurrentAddress,
+ Addresses->NodeAddress,
+ 6
+ );
+
+
+ //
+ // Update the current group address
+ //
+ NdisMoveMemory(
+ (UNALIGNED PUCHAR)&(Adapter->GroupAddress),
+ Addresses->GroupAddress,
+ 4
+ );
+
+ //
+ // The address on the card is "backwards" and must be
+ // byte-swapped and word-swapped for us to store.
+ //
+ Adapter->GroupAddress =
+ BYTE_SWAP_ULONG((ULONG)(Adapter->GroupAddress));
+
+ //
+ // Update the current functional address
+ //
+ NdisMoveMemory(
+ (UNALIGNED PUCHAR)&(Adapter->FunctionalAddress),
+ Addresses->FunctionalAddress,
+ 4
+ );
+
+ //
+ // The address on the card is "backwards" and must be
+ // byte-swapped and word-swapped for us to store.
+ //
+ Adapter->FunctionalAddress =
+ BYTE_SWAP_ULONG(Adapter->FunctionalAddress);
+
+ }
+
+ //
+ // Finish the query and relenquish the command block
+ //
+ TOK162FinishQueryInformation(Adapter);
+ TOK162RelinquishCommandBlock(Adapter, CurrentCommandBlock);
+
+ break;
+
+ case CMD_DMA_OPEN:
+
+ //
+ // An open command is generated during a reset command. The
+ // initial open is called during adapter initialization and
+ // no DPC is generated.
+ //
+ // Indicate we are processing an open to the debugger.
+ //
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Processing the open command.\n");)
+
+ //
+ // Check to see if the open succeeded.
+ //
+ if ((Adapter->SsbStatus1 & OPEN_COMPLETION_MASK_RESULT)
+ != OPEN_RESULT_ADAPTER_OPEN) {
+
+ //
+ // The open failed. Set the current ring state and set the
+ // return variable to NDIS_STATUS_FAILURE.
+ //
+ Adapter->CurrentRingState = NdisRingStateOpenFailure;
+ Status = NDIS_STATUS_FAILURE;
+
+ //
+ // Indicate to the wrapper the result of the open/receive for
+ // the original reset request.
+ //
+ TOK162DoResetIndications(Adapter, Status);
+
+ //
+ // Display the error code on the debugger.
+ //
+ VERY_LOUD_DEBUG(DbgPrint(
+ "IBMTOK2E!Error on the open - %x\n",Adapter->SsbStatus1);)
+
+ } else {
+
+ //
+ // The open succeeded. Set the current ring state and set the
+ // return variable to NDIS_STATUS_SUCCESS.
+ //
+ Adapter->CurrentRingState = NdisRingStateOpened;
+ Status = NDIS_STATUS_SUCCESS;
+
+ //
+ // Indicate to the wrapper the result of the open/receive for
+ // the original reset request.
+ //
+ TOK162DoResetIndications(Adapter, Status);
+
+ //
+ // Now send out the receive command. Display the fact that
+ // DoReceive is being called on the debugger.
+ //
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Doing the receive\n");)
+
+ //
+ // Check if the receive command succeeded. If not, set the
+ // return variable to NDIS_STATUS_FAILURE. It is currently
+ // set to NDIS_STATUS_SUCCESS, so no change is necessary
+ // if the receive command succeeds.
+ //
+ if (DoTheReceive(Adapter) == FALSE) {
+
+ Status = NDIS_STATUS_FAILURE;
+
+ }
+
+ }
+
+ //
+ // Relinquish the command block associcated with this open.
+ //
+ TOK162RelinquishCommandBlock(Adapter, CurrentCommandBlock);
+
+ break;
+
+ case CMD_DMA_READ_ERRLOG:
+
+ LOUD_DEBUG(DbgPrint("IBMTOK2E!DPC for read errorlog called\n");)
+
+ //
+ // Record the values for the error counters
+ //
+ Adapter->ReceiveCongestionError +=
+ Adapter->ErrorLog->ReceiveCongestionError;
+ Adapter->LineError += Adapter->ErrorLog->LineError;
+ Adapter->LostFrameError += Adapter->ErrorLog->LostFrameError;
+ Adapter->BurstError += Adapter->ErrorLog->BurstError;
+ Adapter->FrameCopiedError += Adapter->ErrorLog->FrameCopiedError;
+ Adapter->TokenError += Adapter->ErrorLog->TokenError;
+ Adapter->InternalError += Adapter->ErrorLog->InternalError;
+ Adapter->ARIFCIError += Adapter->ErrorLog->ARIFCIError;
+ Adapter->AbortDelimeter += Adapter->ErrorLog->AbortDelimeter;
+ Adapter->DMABusError += Adapter->ErrorLog->DMABusError;
+
+ //
+ // Indicate the values to the debugger
+ //
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!CongestionErrors = %u\n",
+ Adapter->ErrorLog->ReceiveCongestionError);)
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!LineErrors = %u\n",
+ Adapter->ErrorLog->LineError);)
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!LostFrameErrors = %u\n",
+ Adapter->ErrorLog->LostFrameError);)
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!BurstErrors = %u\n",
+ Adapter->ErrorLog->BurstError);)
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!FrameCopiedErrors = %u\n",
+ Adapter->ErrorLog->FrameCopiedError);)
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!TokenErrors = %u\n",
+ Adapter->ErrorLog->TokenError);)
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!InternalErrors = %u\n",
+ Adapter->ErrorLog->InternalError);)
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!ARIFCIErrors = %u\n",
+ Adapter->ErrorLog->ARIFCIError);)
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!AbortDelimeters = %u\n",
+ Adapter->ErrorLog->AbortDelimeter);)
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!DMABusErrors = %u\n",
+ Adapter->ErrorLog->DMABusError);)
+
+ //
+ //
+ //
+ if (Adapter->RequestInProgress) {
+
+ TOK162FinishQueryInformation(Adapter);
+
+ }
+
+ //
+ // Relinquish the command block associated with this
+ // readadapterlog.
+ //
+ TOK162RelinquishCommandBlock(Adapter, CurrentCommandBlock);
+
+ break;
+
+
+ default:
+
+ //
+ // Did this command come from a set information request?
+ //
+ if (CurrentCommandBlock->Set) {
+
+ //
+ // Relinquish the command block.
+ //
+ TOK162RelinquishCommandBlock(Adapter, CurrentCommandBlock);
+
+ //
+ // Mark the current request state as complete.
+ //
+ Adapter->RequestInProgress = FALSE;
+
+ //
+ // Inform the wrapper the request has been completed.
+ //
+ NdisMSetInformationComplete(
+ Adapter->MiniportAdapterHandle,
+ NDIS_STATUS_SUCCESS);
+
+ //
+ // Not from a set. If this is the unique case of where a group
+ // address and a functional address had to be set to satisfy a
+ // packet filter change command (two commands for one), then we
+ // will only do an indication on the last one. The first one,
+ // however, still needs to have the command block associated
+ // with it relinquished.
+ //
+ } else if ((CurrentCommandBlock->Hardware.CommandCode == CMD_DMA_SET_GRP_ADDR) ||
+ (CurrentCommandBlock->Hardware.CommandCode == CMD_DMA_SET_FUNC_ADDR)) {
+
+ TOK162RelinquishCommandBlock(Adapter, CurrentCommandBlock);
+
+ }
+
+ break;
+ }
+
+}
+
+
+VOID
+TOK162ProcessTransmitInterrupts(
+ IN PTOK162_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Process the Transmit Complete interrupts.
+
+ NOTE: This routine assumes that it is being executed in a
+ single thread of execution.
+
+Arguments:
+
+ Adapter - The adapter the transmit was sent from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Pointer to the transmit list started this transmission.
+ //
+ PTOK162_SUPER_TRANSMIT_LIST Transmit;
+
+ //
+ // Pointer to the packet that started this transmission.
+ //
+ PNDIS_PACKET Packet;
+
+ //
+ // Holds CSTAT variable for transmit
+ //
+ USHORT Cstat;
+
+ //
+ // Status variable
+ //
+ NDIS_STATUS Status;
+
+ //
+ // Log that we entered transmit dpc processing
+ //
+ IF_LOG('a');
+
+ //
+ // Loop until we are done
+ //
+ while (TRUE) {
+
+ Transmit = Adapter->ActiveTransmitHead;
+
+ if(Transmit == NULL) {
+
+ //
+ // Log that we are leaving due to no more transmits to process
+ //
+ IF_LOG('A');
+ return;
+
+ }
+
+ //
+ // We are processing another transmit
+ //
+ IF_LOG('B');
+
+ //
+ // Get the result of the transmit
+ //
+ //
+ // First set the address register on the card to point to correct
+ // transmit list.
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_ADDRESS,
+ (Transmit->FirstEntry * 8) + COMMUNICATION_XMT_OFFSET + 6
+ );
+
+ //
+ // Now read the Transmit List CSTAT
+ //
+ READ_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA,
+ &Cstat
+ );
+
+ //
+ // Display the completion status for the transmit entry on the debugger.
+ //
+ VERY_LOUD_DEBUG(DbgPrint(
+ "IBMTOK2E!Csat for the transmit is %x\n",Cstat);)
+
+ //
+ // If the valid bit is not zero, leave
+ //
+ if ((Cstat & TRANSMIT_CSTAT_VALID) != 0) {
+
+ //
+ // Restart the transmits
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_COMMAND,
+ ENABLE_TRANSMIT_VALID
+ );
+
+ //
+ // Log valid bit not zero
+ //
+ IF_LOG('P');
+
+ return;
+
+ }
+
+ //
+ // If the frame is not complete (no bit set), return.
+ //
+ if ((Cstat & TRANSMIT_CSTAT_FRAME_COMPLETE) == 0) {
+
+ //
+ // Restart the transmits
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_COMMAND,
+ ENABLE_TRANSMIT_VALID
+ );
+
+ //
+ // Log frame complete bit not set
+ //
+ IF_LOG('Q');
+
+ return;
+
+ }
+
+ //
+ // Get packet info.
+ //
+ Packet = Transmit->Packet;
+
+ //
+ // Give up the current transmit
+ //
+ //
+ // Increase the number of available transmit blocks
+ //
+ Adapter->NumberOfAvailableTransmitBlocks++;
+
+ //
+ // Move the active pointer to the next active transmit
+ //
+ Adapter->ActiveTransmitHead = Transmit->NextActive;
+
+ //
+ // Clear up next pointer
+ //
+ Transmit->NextActive = NULL;
+
+ //
+ // Check if there was an error on the transmit. Set Status and increment
+ // appropriate counter.
+ //
+ if ((Cstat & TRANSMIT_CSTAT_XMIT_ERROR) != 0) {
+
+ Adapter->BadTransmits++;
+ Status = NDIS_STATUS_FAILURE;
+ CURRENT_DEBUG(DbgPrint("IBMTOK2E!Bad Transmit DPC\n");)
+
+ } else {
+
+ Adapter->GoodTransmits++;
+ Status = NDIS_STATUS_SUCCESS;
+ CURRENT_DEBUG(DbgPrint("IBMTOK2E!Good Transmit DPC\n");)
+ }
+
+ //
+ // Check if the packet has map register associated
+ //
+ if (Transmit->UsedBuffer == FALSE) {
+
+ //
+ // Pointer to the current NDIS_BUFFER
+ //
+ PNDIS_BUFFER CurrentBuffer;
+
+ //
+ // Index to map register
+ //
+ UINT CurMapRegister;
+
+ //
+ // Transmit is finished, so release the physical mappings
+ //
+ NdisQueryPacket(
+ Transmit->Packet,
+ NULL,
+ NULL,
+ &CurrentBuffer,
+ NULL
+ );
+
+ //
+ // Set the first map register
+ //
+ CurMapRegister = Transmit->FirstEntry;
+
+ //
+ // Loop through all the buffers releasing the map registers
+ //
+ while (CurrentBuffer != NULL) {
+
+ //
+ // Free the current map register
+ //
+ NdisMCompleteBufferPhysicalMapping(
+ Adapter->MiniportAdapterHandle,
+ CurrentBuffer,
+ CurMapRegister
+ );
+
+ //
+ // Move to next map register
+ //
+ CurMapRegister++;
+
+ CurMapRegister %= TRANSMIT_ENTRIES;
+
+ //
+ // Move to next buffer
+ //
+ NdisGetNextBuffer(
+ CurrentBuffer,
+ &CurrentBuffer
+ );
+
+ }
+
+ }
+
+ //
+ // Indicate to the filter than the send has been completed.
+ //
+ IF_LOG('C');
+
+ NdisMSendComplete(
+ Adapter->MiniportAdapterHandle,
+ Packet,
+ Status
+ );
+
+ //
+ // Restart the transmits
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_COMMAND,
+ ENABLE_TRANSMIT_VALID
+ );
+
+ }
+}
+
+BOOLEAN
+TOK162ProcessRingInterrupts(
+ IN PTOK162_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ Process ring status interrupts.
+
+Arguments:
+
+ Adapter - The adapter registering the ring interrupt
+
+Return Value:
+
+ FALSE - Don't need to process receives as a result of the ring condition
+ TRUE - Need to process receives
+
+--*/
+{
+ //
+ // Holds the return status value
+ //
+ ULONG RingStatus;
+
+ //
+ // Command block variable used if we need to read the errorlog due to
+ // an overflow condition.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK CommandBlock;
+
+ //
+ // Return value for the function. Assume we don't need to process
+ // receives.
+ //
+ BOOLEAN SoftError = FALSE;
+ VERY_LOUD_DEBUG(DbgPrint(
+ "IBMTOK2E!Doing ring processing -%04x\n",Adapter->SsbStatus1);)
+
+ //
+ // Determine the reason for the ring interrupt.
+ //
+ if (Adapter->SsbStatus1 & RING_STATUS_SIGNAL_LOSS) {
+ RingStatus = NDIS_RING_SIGNAL_LOSS;
+ } else if (Adapter->SsbStatus1 & RING_STATUS_HARD_ERROR) {
+ RingStatus = NDIS_RING_HARD_ERROR;
+ } else if (Adapter->SsbStatus1 & RING_STATUS_SOFT_ERROR) {
+ //
+ // If we have a soft error, we should check the receives.
+ //
+ RingStatus = NDIS_RING_SOFT_ERROR;
+ SoftError = TRUE;
+ } else if (Adapter->SsbStatus1 & RING_STATUS_XMIT_BEACON) {
+ RingStatus = NDIS_RING_TRANSMIT_BEACON;
+ } else if (Adapter->SsbStatus1 & RING_STATUS_LOBE_WIRE_FAULT) {
+ RingStatus = NDIS_RING_LOBE_WIRE_FAULT;
+ } else if (Adapter->SsbStatus1 & RING_STATUS_AUTO_REMOVE_1) {
+ RingStatus = NDIS_RING_AUTO_REMOVAL_ERROR;
+ } else if (Adapter->SsbStatus1 & RING_STATUS_REMOVE_RECEIVED) {
+ RingStatus = NDIS_RING_REMOVE_RECEIVED;
+ } else if (Adapter->SsbStatus1 & RING_STATUS_OVERFLOW) {
+ RingStatus = NDIS_RING_COUNTER_OVERFLOW;
+ } else if (Adapter->SsbStatus1 & RING_STATUS_SINGLESTATION) {
+ RingStatus = NDIS_RING_SINGLE_STATION;
+ } else if (Adapter->SsbStatus1 & RING_STATUS_RINGRECOVERY) {
+ RingStatus = NDIS_RING_RING_RECOVERY;
+ } else {
+ RingStatus = 0;
+ }
+
+ //
+ // Display the ring status that we will be indicating to the filter on
+ // the debugger.
+ //
+ VERY_LOUD_DEBUG(DbgPrint(
+ "IBMTOK2E!Indicating ring status - %lx\n",RingStatus);)
+
+ //
+ // Indicate to the filter the ring status.
+ //
+ NdisMIndicateStatus(
+ Adapter->MiniportAdapterHandle,
+ NDIS_STATUS_RING_STATUS,
+ &RingStatus,
+ sizeof(ULONG)
+ );
+
+ //
+ // Tell the filter that we have completed the ring status.
+ //
+ NdisMIndicateStatusComplete(Adapter->MiniportAdapterHandle);
+
+ //
+ // If a counter has overflowed, we need to read the stats from
+ // the adapter to clear this condition.
+ //
+ if ((Adapter->SsbStatus1 & RING_STATUS_OVERFLOW) != 0) {
+
+
+ //
+ // Get a command block.
+ //
+ TOK162AcquireCommandBlock(Adapter,
+ &CommandBlock
+ );
+
+
+ //
+ // Set up the command block for a read_error_log command.
+ //
+ CommandBlock->Set = FALSE;
+ CommandBlock->NextCommand = NULL;
+ CommandBlock->Hardware.Status = 0;
+ CommandBlock->Hardware.NextPending = TOK162_NULL;
+ CommandBlock->Hardware.CommandCode = CMD_DMA_READ_ERRLOG;
+ CommandBlock->Hardware.ParmPointer =
+ NdisGetPhysicalAddressLow(Adapter->ErrorLogPhysical);
+
+ //
+ // Submit the command to the card.
+ //
+ TOK162SubmitCommandBlock(Adapter,
+ CommandBlock
+ );
+
+ }
+
+ //
+ // Return whether processreceiveinterrupts needs to be called.
+ //
+ return(SoftError);
+
+}
diff --git a/private/ntos/ndis/ibmtok2e/makefile b/private/ntos/ndis/ibmtok2e/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/ibmtok2e/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/ibmtok2e/reset.c b/private/ntos/ndis/ibmtok2e/reset.c
new file mode 100644
index 000000000..85294e9c8
--- /dev/null
+++ b/private/ntos/ndis/ibmtok2e/reset.c
@@ -0,0 +1,1937 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ reset.c
+
+Abstract:
+
+ This is the file containing the reset code for the IBM Token Ring 16/4 II
+ ISA adapter. This driver conforms to the NDIS 3.0 Miniport interface.
+
+Author:
+
+ Kevin Martin (KevinMa) 1-Feb-1994
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+--*/
+
+#include <tok162sw.h>
+
+#pragma NDIS_INIT_FUNCTION(TOK162InitialInit)
+
+//
+// Global data for the driver
+//
+TOK162_GLOBAL_DATA TOK162Globals;
+
+//
+// Declarations for functions private to this file.
+//
+extern
+VOID
+TOK162ProcessRequestQueue(
+ IN PTOK162_ADAPTER Adapter,
+ IN BOOLEAN StatisticsUpdated
+ );
+
+
+VOID
+TOK162WriteInitializationBlock(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+VOID
+TOK162SetInitializationBlock(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+VOID
+TOK162SetInitializationBlockAndInit(
+ IN PTOK162_ADAPTER Adapter,
+ OUT PNDIS_STATUS Status
+ );
+
+NDIS_STATUS
+TOK162ChangeCurrentAddress(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+VOID
+TOK162ResetCommandBlocks(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+BOOLEAN
+CheckResetResults(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+NDIS_STATUS
+CheckInitResults(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+VOID
+TOK162GetAdapterOffsets(
+ IN PTOK162_ADAPTER Adapter
+ );
+VOID
+TOK162ResetReceiveQueue(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+VOID
+TOK162AbortSend(
+ IN PTOK162_ADAPTER Adapter,
+ IN PTOK162_SUPER_TRANSMIT_LIST Transmit
+ );
+
+BOOLEAN
+TOK162InitialInit(
+ IN PTOK162_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets up the initial init of the driver.
+
+Arguments:
+
+ Adapter - The adapter structure for the hardware.
+
+Return Value:
+
+ TRUE if successful, FALSE if not.
+
+--*/
+
+{
+ //
+ // Holds status returned from NDIS calls.
+ //
+ NDIS_STATUS Status;
+
+ //
+ // First we make sure that the device is stopped.
+ //
+ TOK162DisableInterrupt(Adapter);
+
+ //
+ // Set flags indicating we are doing the initial init
+ //
+ Adapter->InitialInit = TRUE;
+ Adapter->ResetState = InitialInit;
+ Adapter->InitialOpenComplete = FALSE;
+
+ //
+ // Initialize the interrupt.
+ //
+ Status = NdisMRegisterInterrupt(
+ &Adapter->Interrupt,
+ Adapter->MiniportAdapterHandle,
+ Adapter->InterruptLevel,
+ Adapter->InterruptLevel,
+ FALSE,
+ FALSE,
+ NdisInterruptLevelSensitive
+ );
+
+ //
+ // Report the status of the interrupt registering to the debugger
+ //
+ VERY_LOUD_DEBUG(DbgPrint(
+ "IBMTOK2E!Status from Registering Interrupt %u - %u\n",Adapter->InterruptLevel,Status);)
+
+ //
+ // If the register interrupt call failed, set level to 0 and
+ // return. This will prevent a deregister with a null Interrupt
+ // structure.
+ //
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ Adapter->InterruptLevel = 0;
+ return FALSE;
+
+ }
+
+ //
+ // Initialize the open command to zeros
+ //
+ NdisZeroMemory(Adapter->Open,sizeof(OPEN_COMMAND));
+
+ //
+ // Set up the Open command block
+ //
+
+ //
+ // Set the options
+ //
+ Adapter->Open->Options = BYTE_SWAP(OPEN_OPTION_CONTENDER);
+
+ //
+ // Set the receive and transmit list counts, along with buffer size
+ //
+ Adapter->Open->ReceiveListCount = BYTE_SWAP(RECEIVE_LIST_COUNT);
+ Adapter->Open->TransmitListCount = BYTE_SWAP(TRANSMIT_ENTRIES);
+ Adapter->Open->BufferSize = BYTE_SWAP(OPEN_BUFFER_SIZE);
+
+ //
+ // Make sure the adapter can handle one entire frame
+ //
+ Adapter->Open->TransmitBufCountMin =
+ (Adapter->ReceiveBufferSize / (OPEN_BUFFER_SIZE - 8)) + 1;
+
+ Adapter->Open->TransmitBufCountMax = Adapter->Open->TransmitBufCountMin;
+
+ //
+ // Reset the adapter
+ //
+ TOK162ResetAdapter(Adapter);
+
+ //
+ // Reenable interrupts
+ //
+ TOK162EnableInterrupt(Adapter);
+
+ //
+ // Go through the reset stages
+ //
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Calling TOK162ResetHandler\n");)
+
+ TOK162ResetHandler(NULL,Adapter,NULL,NULL);
+
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Back from TOK162ResetHandler\n");)
+
+ //
+ // The initial init is over.
+ //
+ Adapter->InitialInit = FALSE;
+
+ //
+ // Check the reset status and return TRUE if successful, FALSE if not.
+ //
+ if (Adapter->ResetResult == NDIS_STATUS_SUCCESS) {
+
+ return TRUE;
+
+ } else {
+
+ return FALSE;
+
+ }
+
+}
+
+
+VOID
+TOK162EnableAdapter(
+ IN NDIS_HANDLE Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to start an already initialized TOK162.
+
+Arguments:
+
+ Context - The adapter for the TOK162.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Pointer to an adapter structure. Makes Context (passed in value)
+ // a structure we can deal with.
+ //
+ PTOK162_ADAPTER Adapter = (PTOK162_ADAPTER)Context;
+
+ //
+ // Enable the adapter
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_ADAPTER_ENABLE,
+ 0x2525
+ );
+
+}
+
+
+VOID
+TOK162EnableInterrupt(
+ IN NDIS_HANDLE Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to turn on the interrupt mask.
+
+Arguments:
+
+ Context - The adapter for the TOK162.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Pointer to an adapter structure. Makes Context (passed in value)
+ // a structure we can deal with.
+ //
+ PTOK162_ADAPTER Adapter = (PTOK162_ADAPTER)Context;
+
+ //
+ // Enable further interrupts.
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_SWITCH_INT_ENABLE,
+ 0x2525
+ );
+
+}
+
+VOID
+TOK162DisableInterrupt(
+ IN NDIS_HANDLE Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to turn off the interrupt mask.
+
+Arguments:
+
+ Context - The adapter for the TOK162.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Pointer to an adapter structure. Makes Context (passed in value)
+ // a structure we can deal with.
+ //
+ PTOK162_ADAPTER Adapter = (PTOK162_ADAPTER)Context;
+
+ //
+ // Disable the adapter interrupt.
+ //
+ WRITE_ADAPTER_USHORT(
+ Adapter,
+ PORT_OFFSET_SWITCH_INT_DISABLE,
+ 0x2525
+ );
+
+}
+
+
+VOID
+TOK162ResetAdapter(
+ IN PTOK162_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to reset the adapter.
+
+Arguments:
+
+ Adapter - The TOK162 adapter to reset.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Mark the current ring state as closed (we are going to be removed
+ // from the ring by doing the reset).
+ //
+
+ Adapter->CurrentRingState = NdisRingStateClosed;
+
+ //
+ // Set the adapter address register to 0000 as per the spec.
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_ADDRESS,
+ 0x0000
+ );
+
+ //
+ // This is very simple with this adapter. We simply issue a reset
+ // command right here and this will stop the chip.
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_ADAPTER_RESET,
+ 0x2525
+ );
+
+ //
+ // Allow the adapter to finish completing the reset
+ //
+ NdisStallExecution(500);
+
+ //
+ // Enable the adapter to allow us to access the adapter's registers.
+ //
+ TOK162EnableAdapter(Adapter);
+}
+
+VOID
+TOK162SetInitializationBlock(
+ IN PTOK162_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine simply fills the Initialization block
+ with the information necessary for initialization.
+
+ NOTE: this routine assumes a single thread of execution is accessing
+ the particular adapter.
+
+Arguments:
+
+ Adapter - The adapter which holds the initialization block
+ to initialize.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ //
+ // Pointer to the initialization block
+ //
+ PADAPTER_INITIALIZATION Initialization = Adapter->InitializationBlock;
+
+ //
+ // Initialize the init block to zeros
+ //
+ NdisZeroMemory(
+ Initialization,
+ sizeof(ADAPTER_INITIALIZATION)
+ );
+
+ //
+ // Set the initializtion options as follows:
+ // Reserved bit must be on
+ // DMA Burst mode (versus cyclical) for the SSB/SCB
+ // DMA Burst mode (versus cyclical) for the xmit/rcv lists
+ // DMA Burst mode (versus cyclical) for the xmit/rcv status
+ // DMA Burst mode (versus cyclical) for the receive buffers
+ // DMA Burst mode (versus cyclical) for the transmit buffers
+ // Don't allow Early Token Release
+ //
+ Initialization->Options = INIT_OPTIONS_RESERVED |
+ INIT_OPTIONS_RECEIVE_BURST |
+ INIT_OPTIONS_XMIT_BURST |
+ INIT_OPTIONS_DISABLE_ETR;
+
+ //
+ // If we are running at 16MBPS, OR in this fact.
+ //
+ if (Adapter->Running16Mbps == TRUE) {
+
+ Initialization->Options |= INIT_OPTIONS_SPEED_16;
+
+ }
+
+ //
+ // Set the receive and transmit burst sizes to the max.
+ //
+ Initialization->ReceiveBurstSize = TOK162_BURST_SIZE;
+ Initialization->TransmitBurstSize = TOK162_BURST_SIZE;
+
+ //
+ // Set the DMA retries (values found in TOK162HW.H)
+ //
+ Initialization->DMAAbortThresholds = TOK162_DMA_RETRIES;
+
+ //
+ // Set the pointers to the DMA Test Area
+ //
+ Initialization->DMATestAddressHigh = HIGH_WORD(
+ NdisGetPhysicalAddressLow(Adapter->DmaTestPhysical));
+
+ Initialization->DMATestAddressLow = LOW_WORD(
+ NdisGetPhysicalAddressLow(Adapter->DmaTestPhysical));
+}
+
+
+VOID
+TOK162SetInitializationBlockAndInit(
+ IN PTOK162_ADAPTER Adapter,
+ OUT PNDIS_STATUS Status
+ )
+
+/*++
+
+Routine Description:
+
+ It is this routine's responsibility to make sure that the
+ Initialization block is filled and the adapter is initialized
+ and started.
+
+Arguments:
+
+ Adapter - The adapter whose hardware is to be initialized.
+ Status - Result of the Init
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ //
+ // Simple iterative variable to keep track of the number of retries.
+ //
+ USHORT Retries;
+
+ //
+ // Check to make sure Reset went OK
+ //
+ if (Adapter->InitialInit == TRUE) {
+
+ Retries = 0;
+
+ while ((CheckResetResults(Adapter) == FALSE) && (Retries++ < 3)) {
+
+ TOK162ResetAdapter(Adapter);
+
+ }
+
+ if (Retries == 3) {
+
+ *Status = NDIS_STATUS_DEVICE_FAILED;
+
+ return;
+
+ }
+
+ }
+
+ //
+ // Reset the receive queue, the command block queue, and the transmit
+ // queue.
+ //
+ TOK162ResetCommandBlocks(Adapter);
+ TOK162ResetVariables(Adapter);
+
+ //
+ // Fill in the adapter's initialization block.
+ //
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Setting init block\n");)
+
+ TOK162SetInitializationBlock(Adapter);
+
+ //
+ // Write the initialization sequence to the adapter
+ //
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Writing Init block to adapter\n");)
+
+ TOK162WriteInitializationBlock(Adapter);
+
+ //
+ // Check the results
+ //
+ if (Adapter->InitialInit == TRUE) {
+
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Checking init results\n");)
+
+ *Status = CheckInitResults(Adapter);
+
+ }
+
+ return;
+
+}
+
+
+VOID
+TOK162ResetHandler(
+ IN PVOID SystemSpecific1,
+ IN PTOK162_ADAPTER Adapter,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+
+/*++
+
+Routine Description:
+
+ Continue the reset given the current reset state (Adapter->ResetState).
+
+Arguments:
+ SystemSpecific1 - Not used.
+ Adapter - The adapter whose hardware is being reset.
+ SystemSpecific2 - Not used.
+ SystemSpecific3 - Not used.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Holds the return value from NDIS calls.
+ //
+ NDIS_STATUS Status;
+
+ //
+ // Variable for the number of retries.
+ //
+ USHORT Retries;
+
+ //
+ // Holds the result of the receive command.
+ //
+ BOOLEAN ReceiveResult;
+
+ //
+ // Initialize retries to 0.
+ //
+ Retries = 0;
+
+ //
+ // Cancel the reset timer
+ //
+ NdisMCancelTimer(&(Adapter->ResetTimer),&ReceiveResult);
+
+ //
+ // Based on the current Adapter->ResetState, proceed with the reset.
+ //
+ switch(Adapter->ResetState) {
+
+ //
+ // The initialinit case means we are at the beginning and do not
+ // run off of interrupts. Everything is polled and we continue until
+ // we are finished with the reset, successful or not.
+ //
+ case InitialInit:
+
+ //
+ // For up to 3 times, try to init the chipset.
+ //
+ do {
+
+ TOK162SetInitializationBlockAndInit(Adapter,&Status);
+ Retries++;
+
+ } while ((Status != NDIS_STATUS_SUCCESS) && (Retries < 3));
+
+ //
+ // If everything went ok, get the adapter information offsets
+ // and do the open/receive combo.
+ //
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ //
+ // Get the communication area offset
+ //
+ READ_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_ADDRESS,
+ &Adapter->CommunicationOffset
+ );
+
+ //
+ // Mask off the low bits as they don't count
+ //
+ Adapter->CommunicationOffset &= 0xF000;
+
+ TOK162GetAdapterOffsets(Adapter);
+
+ //
+ // Do the open and if successful wait for the receive to
+ // complete (Status is already set to successful). If
+ // there was a problem, though, we need to set the error
+ // code.
+ //
+ VERY_LOUD_DEBUG(DbgPrint("Calling do the open\n");)
+
+ if (DoTheOpen(Adapter) != TRUE) {
+
+ Status = NDIS_STATUS_FAILURE;
+
+ } else {
+
+ DoTheReceive(Adapter);
+
+ }
+
+ }
+
+ //
+ // Do the reset indications
+ //
+ TOK162DoResetIndications(Adapter,Status);
+
+ break;
+
+ //
+ // CheckReset is the first stage of a non-init reset. Because of
+ // the retry mechanism, CheckReset and CheckResetRetry have the same
+ // entry point logically with the exception of the resetting of the
+ // retry variable.
+ //
+
+ case CheckReset:
+
+ Adapter->ResetRetries = 0;
+
+ case CheckResetRetry:
+
+ //
+ // Increment the retry count
+ //
+ Adapter->ResetRetries++;
+
+ //
+ // See if we have gone too long.
+ // If we have gone for 5 seconds without the reset
+ // going true, reset the adapter again. Ten seconds is
+ // the breaking point to actually return an error condition.
+ //
+ if (Adapter->ResetRetries == 100) {
+
+ TOK162ResetAdapter(Adapter);
+
+ NdisMSetTimer(&(Adapter->ResetTimer),
+ 100
+ );
+
+ return;
+
+ } else if (Adapter->ResetRetries > 200) {
+
+ //
+ // Do the reset indications.
+ //
+ TOK162DoResetIndications(Adapter,NDIS_STATUS_FAILURE);
+ return;
+
+ }
+
+ //
+ // Check the result of the reset command. If it fails,
+ // set the state to CheckResetRetry.
+ //
+ if (CheckResetResults(Adapter) == FALSE) {
+
+ Adapter->ResetState = CheckResetRetry;
+
+ //
+ // If success, move to the next state (DoTheInit)
+ //
+ } else {
+
+ Adapter->InitRetries = 0;
+
+ VERY_LOUD_DEBUG(DbgPrint(
+ "IBMTOK2E!Moving to the init stage\n");)
+
+ Adapter->ResetState = DoTheInit;
+
+ }
+
+ //
+ // Set the timer for the reset and leave this timer routine.
+ //
+ NdisMSetTimer(&(Adapter->ResetTimer),
+ 100
+ );
+
+ return;
+ break;
+
+ //
+ // DoTheInit sends the initialization block out to the card, and
+ // sets the next state to CheckInit.
+ //
+ case DoTheInit:
+
+ Adapter->ResetState = CheckInit;
+
+ //
+ // Send the init block out to the adapter
+ //
+ TOK162SetInitializationBlockAndInit(Adapter,
+ &Adapter->ResetResult);
+
+ //
+ // Set the timer for the reset and leave this timer routine.
+ //
+ NdisMSetTimer(&(Adapter->ResetTimer),
+ 50
+ );
+
+ return;
+ break;
+
+ //
+ // The CheckInit stage looks at the init results. If successful,
+ // the open command is issued and the regular interrupt handler
+ // will take care of the rest. If unsuccessful, the retry count
+ // is incremented and we wait until either the init results return
+ // successful or the retry count expires.
+ //
+ case CheckInit:
+
+ //
+ // Increment the retry count
+ //
+ Adapter->InitRetries++;
+
+ //
+ // If we have expired the retry count, do the indications
+ //
+ if (Adapter->InitRetries > 200) {
+
+ TOK162DoResetIndications(Adapter,NDIS_STATUS_FAILURE);
+ return;
+
+ }
+
+ //
+ // Check the result of the init.
+ //
+ Adapter->ResetResult = CheckInitResults(Adapter);
+
+ //
+ // If we were successful, move to the next stage.
+ //
+ if (Adapter->ResetResult == NDIS_STATUS_SUCCESS) {
+
+ Adapter->ResetState = DoOpen;
+ }
+
+ NdisMSetTimer(&(Adapter->ResetTimer),
+ 50
+ );
+
+ return;
+ break;
+
+ case DoOpen:
+
+ DoTheOpen(Adapter);
+
+ return;
+
+ }
+
+}
+
+VOID
+TOK162DoResetIndications(
+ IN PTOK162_ADAPTER Adapter,
+ IN NDIS_STATUS Status
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by TOK162ResetDpc to perform any
+ indications which need to be done after a reset. Note that
+ this routine will be called after either a successful reset
+ or a failed reset.
+
+Arguments:
+
+ Adapter - The adapter whose hardware has been initialized.
+
+ Status - The status of the reset to send to the protocol(s).
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ //
+ // If we have a bad result, we stop the chip and do the indication
+ // back to the protocol(s).
+ //
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ LOUD_DEBUG(DbgPrint("IBMTOK2E!Reset failed\n");)
+
+ //
+ // Stop the chip
+ //
+ TOK162ResetAdapter(Adapter);
+
+ //
+ // Reset has failed, errorlog an entry.
+ //
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 0
+ );
+
+ } else {
+
+ LOUD_DEBUG(DbgPrint("IBMTOK2E!Reset succeeded\n");)
+
+ }
+
+ //
+ // If this is during the initial init, just set the adapter variable.
+ //
+ if (Adapter->InitialInit == TRUE) {
+
+ Adapter->ResetResult = Status;
+
+ //
+ // Otherwise, send the status back to the protocol(s).
+ //
+ } else {
+
+ NdisMResetComplete(
+ Adapter->MiniportAdapterHandle,
+ Status,
+ TRUE
+ );
+
+ }
+
+ //
+ // We are no longer resetting the adapter.
+ //
+ Adapter->ResetInProgress = FALSE;
+
+}
+
+extern
+NDIS_STATUS
+TOK162SetupForReset(
+ IN PTOK162_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to write the resetting interrupt to the
+ token ring card, and then set up a timer to do the initialization
+ sequence under DPC.
+
+ NOTE: This routine must be called with the lock acquired.
+
+Arguments:
+
+ Adapter - The adapter whose hardware is to be initialized.
+
+Return Value:
+
+ Status of the reset process (always PENDING).
+
+--*/
+{
+ //
+ // The reset is now in progres.
+ //
+ Adapter->ResetInProgress = TRUE;
+
+ //
+ // Shut down the chip. We won't be doing any more work until
+ // the reset is complete.
+ //
+ TOK162ResetAdapter(Adapter);
+
+ //
+ // Set the timer for the dpc routine. The wait is for 100 milliseconds.
+ //
+ NdisMSetTimer(&(Adapter->ResetTimer),
+ 500
+ );
+
+ //
+ // Indicate the reset is pending
+ //
+ return NDIS_STATUS_PENDING;
+}
+
+
+VOID
+TOK162ResetVariables(
+ IN PTOK162_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets variables to their proper value after a reset.
+
+Arguments:
+
+ Adapter - Adapter we are resetting.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Reset the command queue and block variables
+ //
+ Adapter->CommandOnCard = NULL;
+ Adapter->WaitingCommandHead = NULL;
+ Adapter->WaitingCommandTail = NULL;
+ Adapter->NextCommandBlock = 0;
+ Adapter->NumberOfAvailableCommandBlocks = TOK162_NUMBER_OF_CMD_BLOCKS;
+
+ //
+ // Reset the transmit queue and block variables
+ //
+ Adapter->ActiveTransmitHead = NULL;
+ Adapter->ActiveTransmitTail = NULL;
+ Adapter->AvailableTransmit = Adapter->TransmitQueue;
+ Adapter->TransmitsQueued = 0;
+ Adapter->AdapterTransmitIndex = 0;
+ Adapter->TotalSends = 0;
+ Adapter->RegularPackets = 0;
+ Adapter->ConstrainPackets = 0;
+ Adapter->NumberOfAvailableTransmitBlocks = TRANSMIT_LIST_COUNT;
+
+ CURRENT_DEBUG(DbgPrint("Sends = %u\n",Adapter->TotalSends);)
+
+ CURRENT_DEBUG(DbgPrint("Regular Packets = %u\n",
+ Adapter->RegularPackets);)
+
+ CURRENT_DEBUG(DbgPrint("Constrained Packets = %u\n",
+ Adapter->ConstrainPackets);)
+
+ //
+ // No receive complete is necessary
+ //
+ Adapter->DoReceiveComplete = FALSE;
+
+}
+
+
+VOID
+TOK162ResetCommandBlocks(
+ IN PTOK162_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets command block elements to their proper value after
+ a reset.
+
+Arguments:
+
+ Adapter - Adapter we are resetting.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Pointer to a Command Block. Used while initializing
+ // the Command Queue.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK CurrentCommandBlock;
+
+ //
+ // Pointer to a Transmit List. Used while initializing
+ // the Transmit Queue.
+ //
+ PTOK162_SUPER_TRANSMIT_LIST CurrentTransmit;
+
+ //
+ // Simple iteration variable.
+ //
+ UINT i;
+
+ //
+ // Abort all pending transmits
+ //
+ CurrentTransmit = Adapter->ActiveTransmitHead;
+
+ while (CurrentTransmit != NULL) {
+
+ TOK162AbortSend(Adapter,CurrentTransmit);
+
+ CurrentTransmit = CurrentTransmit->NextActive;
+
+ }
+
+ //
+ // Put the transmit queue into a known state
+ //
+ for (i = 0, CurrentTransmit = Adapter->TransmitQueue;
+ i < TRANSMIT_LIST_COUNT;
+ i++, CurrentTransmit++
+ ) {
+
+ CurrentTransmit->Timeout = FALSE;
+
+ }
+
+ //
+ // Put the command queue into a known state
+ //
+ for (i = 0, CurrentCommandBlock = Adapter->CommandQueue;
+ i < TOK162_NUMBER_OF_CMD_BLOCKS;
+ i++, CurrentCommandBlock++
+ ) {
+
+ CurrentCommandBlock->Hardware.State = TOK162_STATE_FREE;
+ CurrentCommandBlock->NextCommand = NULL;
+ CurrentCommandBlock->CommandBlockIndex = (USHORT)i;
+ CurrentCommandBlock->Timeout = FALSE;
+ }
+}
+
+
+
+BOOLEAN
+CheckResetResults(PTOK162_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine checks the current state of the reset command and returns
+ whether the reset was successful.
+
+Arguments:
+
+ Adapter - Adapter we are resetting.
+
+Return Value:
+
+ TRUE if reset is successful, FALSE if not.
+
+--*/
+{
+ //
+ // Count of the total delay waiting for the chip to give results
+ //
+ UINT TotalDelay;
+
+ //
+ // Indicating if we can break out of a loop by having definitive results.
+ //
+ BOOLEAN Complete;
+
+ //
+ // Variable holding value of the status.
+ //
+ USHORT Value;
+
+ //
+ // Return value, TRUE or FALSE.
+ //
+ BOOLEAN Success;
+
+ //
+ // Initialize the variables.
+ //
+ Complete = FALSE;
+ TotalDelay = 0;
+ Success = FALSE;
+
+ //
+ // If we are running in a DPC, we don't want to check more than once
+ //
+ if (Adapter->InitialInit == FALSE) {
+
+ Complete = TRUE;
+
+ }
+
+ //
+ // Loop until Complete is TRUE.
+ //
+ do {
+
+ //
+ // First get the status
+ //
+ READ_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_STATUS,
+ &Value
+ );
+
+ VERY_LOUD_DEBUG(DbgPrint("CheckResetResults - %x\n",Value);)
+ //
+ // Check for Initialize
+ //
+ if ((Value & STATUS_INIT_INITIALIZE) != 0) {
+
+ //
+ // Mask off the Test and Error Bits
+ //
+ Value = Value & 0x00FF;
+ Value = Value & ~STATUS_INIT_INITIALIZE;
+
+
+ //
+ // Check test and error to see if they are zero. If so,
+ // we are done and successful.
+ //
+ if ((Value & (STATUS_INIT_TEST | STATUS_INIT_ERROR)) == 0) {
+
+ Complete = TRUE;
+ Success = TRUE;
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Returning True\n");)
+
+ }
+
+ //
+ // If init isn't set but test and error are, we are done but
+ // have failed.
+ //
+ } else if ((Value & (STATUS_INIT_TEST | STATUS_INIT_ERROR)) ==
+ (STATUS_INIT_TEST | STATUS_INIT_ERROR)) {
+
+ Complete = TRUE;
+ Success = FALSE;
+
+ }
+
+ //
+ // If we aren't done yet, then we need to sleep for a while and
+ // try again.
+ //
+ if (Complete == FALSE) {
+
+ NdisStallExecution(50000);
+ TotalDelay += 50000;
+
+ }
+
+ //
+ // If we have gone past the total time allowed or we have completed,
+ // then we end. Otherwise we loop again.
+ //
+ } while ((TotalDelay < 5000000) && (Complete == FALSE));
+
+ //
+ // Return success/failure.
+ //
+ return(Success);
+}
+
+
+
+NDIS_STATUS
+CheckInitResults(PTOK162_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine checks the current state of the init command and returns
+ whether the init was successful.
+
+Arguments:
+
+ Adapter - Adapter we are resetting.
+
+Return Value:
+
+ TRUE if init is successful, FALSE if not.
+
+--*/
+{
+
+ //
+ // Count of the total delay waiting for the chip to give results
+ //
+ UINT TotalDelay;
+
+ //
+ // Indicating if we can break out of a loop by having definitive results.
+ //
+ BOOLEAN Complete;
+
+ //
+ // Variable holding value of the status.
+ //
+ USHORT Value;
+
+ //
+ // Return value, TRUE or FALSE.
+ //
+ BOOLEAN Success;
+
+ //
+ // Initialize the variables.
+ //
+ Complete = FALSE;
+ TotalDelay = 0;
+ Success = FALSE;
+
+ //
+ // If we are running in a DPC, we don't want to check more than once
+ //
+ if (Adapter->InitialInit == FALSE) {
+
+ Complete = TRUE;
+
+ }
+
+ //
+ // Loop until Complete == TRUE
+ //
+ do {
+
+ //
+ // First get the status
+ //
+ READ_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_STATUS,
+ &Value
+ );
+ VERY_LOUD_DEBUG(DbgPrint("CheckInitResults - %x\n",Value);)
+ //
+ // Check for Initialize, Test, and Error to be correct
+ //
+ if ((Value & (STATUS_INIT_INITIALIZE | STATUS_INIT_TEST)) == 0) {
+
+ //
+ // Check Error Bit
+ //
+ Complete = TRUE;
+
+ if ((Value & STATUS_INIT_ERROR) != 0) {
+
+ Success = FALSE;
+
+ } else {
+
+ Success = TRUE;
+
+ }
+ }
+
+ //
+ // If we aren't finished (Complete), Stall and try again.
+ //
+ if (Complete == FALSE) {
+
+ NdisStallExecution(10000);
+ TotalDelay += 10000;
+
+ }
+
+ } while ((TotalDelay < 10000000) && (Complete == FALSE));
+
+ //
+ // If we are successful, return STATUS_SUCCESS
+ //
+ if (Success == TRUE) {
+
+ return(NDIS_STATUS_SUCCESS);
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Returning Success\n");)
+
+ } else {
+
+ return(NDIS_STATUS_FAILURE);
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Returning Failure\n");)
+
+ }
+}
+
+
+BOOLEAN
+DoTheOpen(
+ PTOK162_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine acquires and submits the open command. If called during the
+ initial init, the result of the open command is polled.
+
+Arguments:
+
+ Adapter - Adapter we are opening.
+
+Return Value:
+
+ TRUE if open is successful, FALSE if not.
+
+--*/
+{
+ //
+ // Result of open for polling (initialinit) mode
+ //
+ USHORT Result;
+
+ //
+ // Command block used for the open.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK Command;
+
+ //
+ // Change the ring state
+ //
+ Adapter->CurrentRingState = NdisRingStateOpening;
+
+ //
+ // Initialize the group and functional addresses. These will be set
+ // after the reset has finished.
+ //
+ Adapter->Open->GroupAddress = 0;
+ Adapter->Open->FunctionalAddress = 0;
+
+ //
+ // Set the address the adapter should enter the ring with.
+ //
+ NdisMoveMemory(
+ Adapter->Open->NodeAddress,
+ Adapter->CurrentAddress,
+ TOK162_LENGTH_OF_ADDRESS
+ );
+
+ //
+ // Acquire a command block
+ //
+ TOK162AcquireCommandBlock(Adapter,
+ &Command
+ );
+
+ //
+ // Set up the command block for the open
+ //
+ Command->Hardware.CommandCode = CMD_DMA_OPEN;
+ Command->Hardware.ParmPointer =
+ NdisGetPhysicalAddressLow(Adapter->OpenPhysical);
+
+ //
+ // Issue the command to the controller
+ //
+ TOK162SubmitCommandBlock(Adapter,
+ Command
+ );
+
+ //
+ // During initialinit we have to poll for completion of the open. This
+ // is because there is no way to pend the initial init.
+ //
+ if (Adapter->InitialInit == TRUE) {
+
+ //
+ // Poll until the SSB contains an open.
+ //
+ while (Adapter->InitialOpenComplete == FALSE) {
+
+ NdisStallExecution(5000);
+
+ }
+
+ //
+ // Get the result of the open.
+ //
+ Result = Adapter->SsbStatus1 & OPEN_COMPLETION_MASK_RESULT;
+
+ //
+ // Return the command block
+ //
+ TOK162RelinquishCommandBlock(Adapter,
+ Command
+ );
+
+ //
+ // Figure out the error code
+ //
+ if (Result == OPEN_RESULT_ADAPTER_OPEN) {
+
+ //
+ // Set the current ring state
+ //
+ Adapter->CurrentRingState = NdisRingStateOpened;
+
+ //
+ // Return TRUE
+ //
+ return(TRUE);
+
+ } else {
+
+ //
+ // Set the current ring state
+ //
+ Adapter->CurrentRingState = NdisRingStateOpenFailure;
+
+ //
+ // Return FALSE
+ //
+ return(FALSE);
+
+ }
+
+ }
+
+ return(TRUE);
+
+}
+
+
+BOOLEAN
+DoTheReceive(
+ PTOK162_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine submits the receive command to the current adapter.
+
+Arguments:
+
+ Adapter - Adapter we are submitting the receive.
+
+Return Value:
+
+ TRUE
+
+--*/
+{
+
+ //
+ // Reset the receive queue on the card
+ //
+ TOK162ResetReceiveQueue(Adapter);
+
+ //
+ // Start all of the receive/tranmsit actions
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_COMMAND,
+ START_ALL_IO
+ );
+
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Returning from DoTheReceive\n");)
+
+ return(TRUE);
+
+}
+
+
+VOID
+TOK162WriteInitializationBlock(
+ PTOK162_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine writes the initialization block to the adapter
+
+Arguments:
+
+ Adapter - Adapter we are initializing
+
+Return Value:
+
+ None
+
+--*/
+{
+ //
+ // Simple index variable.
+ //
+ USHORT i;
+
+ //
+ // Pointer to the current value in the initialization block
+ //
+ PUSHORT val;
+
+ //
+ // Set the address of the adapter to 0x0200.
+ //
+ WRITE_ADAPTER_USHORT(Adapter,PORT_OFFSET_ADDRESS,0x0200);
+
+ //
+ // Write out the initialization bytes
+ //
+ val = (PUSHORT)Adapter->InitializationBlock;
+
+ for (i = 0;
+ i < (sizeof(ADAPTER_INITIALIZATION)/2);
+ i++,val++) {
+
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA_AUTO_INC,
+ *val
+ );
+
+ NdisStallExecution(20);
+ }
+
+ //
+ // Issue the command to the adapter
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_COMMAND,
+ EXECUTE_SCB_COMMAND
+ );
+
+}
+
+
+VOID
+TOK162GetAdapterOffsets(
+ IN PTOK162_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine gets the offsets into adapter memory of adapter
+ parameter lists.
+
+Arguments:
+
+ Adapter - Adapter we are obtaining info from
+
+Return Value:
+
+ None
+
+--*/
+{
+ //
+ // Pointer to command block used to get information from the adapter.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK CommandBlock;
+
+ //
+ // Auxilary pointer to a USHORT used to save info in correct part
+ // of the adapter structure.
+ PUSHORT pAux;
+
+ //
+ // We'll use DMA to get these. A little trickier, but I haven't found
+ // a way to get around it. We'll do the polling inside here, during the
+ // initial init.
+ //
+
+ //
+ // First get a command block
+ //
+ TOK162AcquireCommandBlock(Adapter,&CommandBlock);
+
+ //
+ // Inidcate this is not from a set
+ //
+ CommandBlock->Set = FALSE;
+
+ //
+ // Setup the common fields of the command block.
+ //
+ CommandBlock->NextCommand = NULL;
+ CommandBlock->Hardware.Status = 0;
+ CommandBlock->Hardware.NextPending = TOK162_NULL;
+
+ //
+ // Fill in the adapter buffer area with the information to
+ // obtain the permanent address.
+ //
+ Adapter->AdapterBuf->DataCount = BYTE_SWAP(0x000A);
+
+ Adapter->AdapterBuf->DataAddress = BYTE_SWAP(0x0a00);
+
+ //
+ // Set the command block for the read adapter command.
+ //
+ CommandBlock->Hardware.CommandCode = CMD_DMA_READ;
+
+ CommandBlock->Hardware.ParmPointer =
+ NdisGetPhysicalAddressLow(Adapter->AdapterBufPhysical);
+
+ //
+ // Get the pointers for READ.ADAPTER
+ //
+ TOK162SubmitCommandBlock(Adapter,CommandBlock);
+ NdisStallExecution(5000);
+
+ //
+ // Wait for the command to complete.
+ //
+ while(Adapter->Ssb->Command != CMD_DMA_READ) {
+
+ NdisStallExecution(5000);
+
+ }
+
+ pAux = (PUSHORT)(Adapter->AdapterBuf);
+
+ Adapter->UniversalAddress = *(pAux++);
+ Adapter->MicrocodeLevel = *(pAux++);
+ Adapter->AdapterAddresses = *(pAux++);
+ Adapter->AdapterParms = *(pAux++);
+ Adapter->MacBuffer = *pAux++;
+
+ //
+ // Allow the ssb to be updated further
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_STATUS,
+ ENABLE_SSB_UPDATE
+ );
+
+ //
+ // Give up the command block
+ //
+ TOK162RelinquishCommandBlock(Adapter,CommandBlock);
+
+}
+
+
+
+VOID
+TOK162ResetReceiveQueue(
+ IN PTOK162_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine resets the receive queue structures to their initialized
+ state. Most fields don't change and don't need to be updated, otherwise
+ the initreceivequeue function would be called.
+
+Arguments:
+
+ Adapter - Adapter whose receive queue is being reset
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Simple iterative variable.
+ //
+ USHORT i;
+
+ //
+ // Pointer to the current receive entry.
+ //
+ PTOK162_SUPER_RECEIVE_LIST CurrentReceiveEntry;
+
+ //
+ // Adapter offset variable for receive lists
+ //
+ USHORT AdapterOffset;
+
+ //
+ // Set pointer to current receive list to queue head
+ //
+ Adapter->ReceiveQueueCurrent = Adapter->ReceiveQueue;
+
+ //
+ // Initialize the adapter offset to the beginning of the
+ // receive lists on the adapter.
+ //
+ AdapterOffset = Adapter->CommunicationOffset + COMMUNICATION_RCV_OFFSET;
+
+ LOUD_DEBUG(DbgPrint("IBMTOK2E!Resetting receive queue\n");)
+
+ //
+ // For each receive list, reset and download
+ //
+ for (i = 0, CurrentReceiveEntry = Adapter->ReceiveQueue;
+ i < Adapter->NumberOfReceiveBuffers;
+ i++, CurrentReceiveEntry++
+ ) {
+
+ //
+ // Flush the flush buffers
+ //
+ NdisFlushBuffer(CurrentReceiveEntry->FlushBuffer, FALSE);
+
+ //
+ // Set the CSTAT to indicate this buffer is free
+ //
+ CurrentReceiveEntry->Hardware.CSTAT = RECEIVE_CSTAT_REQUEST_RESET;
+
+ //
+ // Set the size of the buffer
+ //
+ CurrentReceiveEntry->Hardware.FrameSize =
+ Adapter->ReceiveBufferSize;
+
+ //
+ // Set the adapter offset for this list
+ //
+ CurrentReceiveEntry->AdapterOffset = AdapterOffset;
+
+ //
+ // Download the receive list
+ //
+ TOK162DownLoadReceiveList(Adapter,CurrentReceiveEntry);
+
+ //
+ // Move to the next list on the card
+ //
+ AdapterOffset += 8;
+
+ }
+
+}
+
+VOID
+TOK162AbortSend(
+ IN PTOK162_ADAPTER Adapter,
+ IN PTOK162_SUPER_TRANSMIT_LIST Transmit
+ )
+/*++
+
+Routine Description:
+
+ This routine aborts the transmit block that was passed in.
+
+Arguments:
+
+ Adapter - Adapter whose receive queue is being reset
+ Transmit - Transmit to be aborted.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // If we used map registers we need to do the completion on them.
+ //
+ if (Transmit->UsedBuffer == FALSE) {
+
+ //
+ // Pointer to the current buffer we are looking at.
+ //
+ PNDIS_BUFFER CurrentBuffer;
+
+ //
+ // Map register to complete
+ //
+ UINT CurMapRegister;
+
+ //
+ // The transmit is being aborted, so we can release
+ // the physical mapping used for it.
+ //
+
+ NdisQueryPacket(
+ Transmit->Packet,
+ NULL,
+ NULL,
+ &CurrentBuffer,
+ NULL
+ );
+
+ //
+ // Get the starting map register for this buffer.
+ //
+ CurMapRegister = Transmit->FirstEntry;
+
+ //
+ // Loop until there aren't any more buffers.
+ //
+ while (CurrentBuffer) {
+
+ //
+ // Release the current map register.
+ //
+ NdisMCompleteBufferPhysicalMapping(
+ Adapter->MiniportAdapterHandle,
+ CurrentBuffer,
+ CurMapRegister
+ );
+
+ //
+ // Move to the next map register.
+ //
+ ++CurMapRegister;
+
+ if (CurMapRegister == TRANSMIT_ENTRIES) {
+
+ CurMapRegister = 0;
+
+ }
+
+ //
+ // Move to the next buffer
+ //
+ NdisGetNextBuffer(
+ CurrentBuffer,
+ &CurrentBuffer
+ );
+
+ }
+
+ }
+
+ //
+ // Indicate to the protocol(s) that this send has been aborted
+ //
+ NdisMSendComplete(
+ Adapter->MiniportAdapterHandle,
+ Transmit->Packet,
+ NDIS_STATUS_REQUEST_ABORTED
+ );
+
+}
diff --git a/private/ntos/ndis/ibmtok2e/send.c b/private/ntos/ndis/ibmtok2e/send.c
new file mode 100644
index 000000000..1ab043868
--- /dev/null
+++ b/private/ntos/ndis/ibmtok2e/send.c
@@ -0,0 +1,740 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ send.c
+
+Abstract:
+
+ This file contains the code for putting a packet through the
+ staged allocation for transmission.
+
+Author:
+
+ Kevin Martin(KevinMa) 20-Dec-1993
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+
+--*/
+
+#include <tok162sw.h>
+
+
+
+NDIS_STATUS
+TOK162ConstrainPacket(
+ IN PTOK162_ADAPTER Adapter,
+ OUT PTOK162_SUPER_TRANSMIT_LIST TransmitBlock,
+ IN PNDIS_BUFFER SourceBuffer,
+ IN UINT NdisBufferCount,
+ IN UINT TotalVirtualLength
+ );
+
+
+VOID
+TOK162DownLoadPacket(
+ IN PTOK162_ADAPTER Adapter,
+ IN PTOK162_SUPER_TRANSMIT_LIST TransmitBlock,
+ IN PNDIS_BUFFER CurrentBuffer
+ );
+
+
+NDIS_STATUS
+TOK162Send(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET Packet,
+ IN UINT Flags
+ )
+
+/*++
+
+Routine Description:
+
+ The TOK162Send request instructs a Miniport to transmit a packet through
+ the adapter onto the medium.
+
+Arguments:
+
+ MiniportAdapterContext - The context value returned by the Miniport when
+ the adapter was initialized. In reality, it is
+ a pointer to TOK162_ADAPTER.
+
+ Packet - A pointer to a descriptor for the packet that is
+ to be transmitted.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ //
+ // Pointer to the adapter.
+ //
+ PTOK162_ADAPTER Adapter =
+ PTOK162_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ //
+ // Pointer to transmit block
+ //
+ PTOK162_SUPER_TRANSMIT_LIST temp;
+
+ //
+ // The number of NDIS buffers in the entire packet.
+ //
+ UINT NdisBufferCount;
+
+ //
+ // The total amount of data in the ndis packet.
+ //
+ UINT TotalDataLength;
+
+ //
+ // Points to the current ndis buffer being walked.
+ //
+ PNDIS_BUFFER CurrentBuffer;
+
+ //
+ // Aux pointer to number of available transmit blocks
+ //
+ PUINT AvailBlocks;
+
+ //
+ // log send called
+ //
+ IF_LOG('h');
+
+ //
+ // Get original count
+ //
+ AvailBlocks = &Adapter->NumberOfAvailableTransmitBlocks;
+
+ //
+ // See if we have any transmits available
+ //
+ if (*AvailBlocks > 0) {
+
+ (*AvailBlocks)--;
+
+ temp = Adapter->AvailableTransmit;
+
+ Adapter->AvailableTransmit = temp->NextEntry;
+
+ temp->NextActive = NULL;
+
+ //
+ // Timestamp the transmit block
+ //
+ temp->Timeout = FALSE;
+
+ //
+ // If the adapter is currently executing a transmit, add this to the
+ // end of the waiting list. Otherwise, download it.
+ //
+ if (Adapter->ActiveTransmitHead != NULL) {
+
+ Adapter->ActiveTransmitTail->NextActive = temp;
+ Adapter->ActiveTransmitTail = temp;
+
+ } else {
+
+ Adapter->ActiveTransmitHead = temp;
+ Adapter->ActiveTransmitTail = temp;
+
+ }
+
+ //
+ // Another transmit is being queued
+ //
+ Adapter->TransmitsQueued++;
+
+ //
+ // Number of sends since last reset increments by one
+ //
+ Adapter->TotalSends++;
+
+ //
+ // Assign the packet to the block
+ //
+ temp->Packet = Packet;
+
+ //
+ // Figure out if we need to constrain the packet.
+ //
+ NdisQueryPacket(
+ Packet,
+ &temp->NumberOfBuffers,
+ &NdisBufferCount,
+ &CurrentBuffer,
+ &TotalDataLength
+ );
+
+ //
+ // See if the packet exceeds MAX_BUFFERS_PER_TRANSMIT or is too short.
+ // We will have to constrain in either event.
+ //
+ if ( (temp->NumberOfBuffers <= MAX_BUFFERS_PER_TRANSMIT) &&
+ (TotalDataLength >= MINIMUM_TOKENRING_PACKET_SIZE) ) {
+
+ //
+ // Need to constrain the packet, increment the counter
+ //
+ TOK162DownLoadPacket(Adapter,temp,CurrentBuffer);
+
+ //
+ // log leaving send
+ //
+ IF_LOG('H');
+
+ //
+ // We are pending.
+ //
+ return(NDIS_STATUS_PENDING);
+
+ } else {
+
+ //
+ // Need to constrain the packet, increment the counter
+ //
+ TOK162ConstrainPacket(Adapter,
+ temp,
+ CurrentBuffer,
+ NdisBufferCount,
+ TotalDataLength
+ );
+
+ //
+ // log leaving send
+ //
+ IF_LOG('H');
+
+ //
+ // We are pending.
+ //
+ return(NDIS_STATUS_PENDING);
+
+ }
+
+ //
+ // If no transmit block was available, return RESOURCE error
+ //
+ } else {
+
+ //
+ // log resource error
+ //
+ IF_LOG('*');
+
+ //
+ // Restart the transmits
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_COMMAND,
+ ENABLE_TRANSMIT_VALID
+ );
+
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+}
+
+
+//
+// Put this code inline to save the overhead of the function call.
+//
+#ifdef _X86_
+__inline
+#endif
+NDIS_STATUS
+TOK162ConstrainPacket(
+ IN PTOK162_ADAPTER Adapter,
+ OUT PTOK162_SUPER_TRANSMIT_LIST TransmitBlock,
+ IN PNDIS_BUFFER SourceBuffer,
+ IN UINT NdisBufferCount,
+ IN UINT TotalVirtualLength
+ )
+
+/*++
+
+Routine Description:
+
+ Given a packet and if necessary attempt to acquire adapter
+ buffer resources so that the packet meets TOK162 hardware
+ constraints.
+
+Arguments:
+
+ Adapter - The adapter the packet is coming through.
+
+ Packet - The packet whose buffers are to be constrained.
+ The packet reserved section is filled with information
+ detailing how the packet needs to be adjusted.
+
+ CommandBlock - Command block describing the packet to be sent.
+
+Return Value:
+
+ Status - SUCCESS.
+
+--*/
+
+{
+
+ //
+ // Will point into the virtual address space addressed
+ // by the adapter buffer if one was successfully allocated.
+ //
+ PCHAR CurrentDestination;
+
+ //
+ // Will hold the total amount of data copied to the
+ // adapter buffer.
+ //
+ UINT TotalDataMoved = 0;
+
+ //
+ // Points to the virtual address of the source buffers data.
+ //
+ PVOID SourceData;
+
+ //
+ // Will point to the number of bytes of data in the source
+ // buffer.
+ //
+ UINT SourceLength;
+
+ //
+ // Log that we entered TOK162ConstrainPacket
+ //
+ IF_LOG('g');
+
+ //
+ // Set transmit block to show we constrained.
+ //
+ TransmitBlock->UsedBuffer = TRUE;
+
+ //
+ // Set the first entry variable
+ //
+ TransmitBlock->FirstEntry = Adapter->AdapterTransmitIndex;
+ CURRENT_DEBUG(DbgPrint("Constrain FirstEntry = %u\n",TransmitBlock->FirstEntry);)
+
+ //
+ // Fill in the buffer with the data from the users buffers.
+ //
+ CurrentDestination = (PVOID)TransmitBlock->TransmitBuffer;
+
+ //
+ // Loop through the packet copying the data into the constrain buffer
+ //
+ while (TRUE) {
+
+ //
+ // Get info on the current buffer
+ //
+ NdisQueryBuffer(
+ SourceBuffer,
+ &SourceData,
+ &SourceLength
+ );
+
+ //
+ // Copy the current buffer to the constrain buffer
+ //
+ NdisMoveMemory(
+ CurrentDestination,
+ SourceData,
+ SourceLength
+ );
+
+ //
+ // Adjust pointers
+ //
+ CurrentDestination = (PCHAR)CurrentDestination + SourceLength;
+
+ TotalDataMoved += SourceLength;
+
+ //
+ // Get the next buffer from the packet
+ //
+ NdisGetNextBuffer(
+ SourceBuffer,
+ &SourceBuffer
+ );
+
+ if (SourceBuffer == NULL) {
+
+ break;
+
+ }
+
+ }
+
+ //
+ // If the packet is less than the minimum TokenRing
+ // packet size, then clear the remaining part of
+ // the buffer up to the minimum packet size.
+ //
+ if (TotalVirtualLength < MINIMUM_TOKENRING_PACKET_SIZE) {
+
+ NdisZeroMemory(
+ CurrentDestination,
+ MINIMUM_TOKENRING_PACKET_SIZE - TotalVirtualLength
+ );
+
+ }
+
+ //
+ // Make sure packet is flushed
+ //
+ NdisFlushBuffer(TransmitBlock->FlushBuffer, TRUE);
+
+
+ //
+ // Set the adapter entry for this transmit
+ //
+ TransmitBlock->FirstEntry = Adapter->AdapterTransmitIndex;
+
+ //
+ // Write out the transmit, starting with the address register
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_ADDRESS,
+ (Adapter->AdapterTransmitIndex * 8) + COMMUNICATION_XMT_OFFSET
+ );
+
+ //
+ // Now write out the transmit list itself, starting with the buffer size
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA_AUTO_INC,
+ (USHORT)TotalVirtualLength
+ );
+
+ //
+ // Now the address, high and low
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA_AUTO_INC,
+ HIGH_WORD(
+ NdisGetPhysicalAddressLow(TransmitBlock->TransmitBufferPhysical))
+ );
+
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA_AUTO_INC,
+ LOW_WORD(
+ NdisGetPhysicalAddressLow(TransmitBlock->TransmitBufferPhysical))
+ );
+
+ //
+ // Finally the CSTAT
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA_AUTO_INC,
+ TRANSMIT_CSTAT_REQUEST
+ );
+
+ //
+ // Start this transmit
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_COMMAND,
+ ENABLE_TRANSMIT_VALID
+ );
+
+ //
+ // Update the index
+ //
+ Adapter->AdapterTransmitIndex++;
+
+ if (Adapter->AdapterTransmitIndex == TRANSMIT_ENTRIES) {
+
+ Adapter->AdapterTransmitIndex = 0;
+
+ }
+
+ //
+ // Log that we are leaving TOK162ConstrainPacket
+ //
+ IF_LOG('G');
+
+ return(NDIS_STATUS_SUCCESS);
+
+}
+
+
+//
+// Put this code inline to save the overhead of the function call.
+//
+#ifdef _X86_
+__inline
+#endif
+VOID
+TOK162DownLoadPacket(
+ IN PTOK162_ADAPTER Adapter,
+ IN PTOK162_SUPER_TRANSMIT_LIST TransmitBlock,
+ IN PNDIS_BUFFER CurrentBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ Given a packet and if necessary attempt to acquire adapter
+ buffer resources so that the packet meets TOK162 hardware
+ constraints.
+
+Arguments:
+
+ Adapter - The adapter the packet is coming through.
+
+ Packet - The packet whose buffers are to be constrained.
+ The packet reserved section is filled with information
+ detailing how the packet needs to be adjusted.
+
+ CommandBlock - Command block describing the packet to be sent.
+
+Return Value:
+
+ Status - SUCCESS.
+
+--*/
+
+{
+ //
+ // map register for buffers
+ //
+ register UINT CurMapRegister;
+
+ //
+ // Array to hold the physical segments
+ //
+ NDIS_PHYSICAL_ADDRESS_UNIT PhysSegArray[MAX_BUFFERS_PER_TRANSMIT];
+
+ //
+ // Count of physical segments in one buffer
+ //
+ UINT BufferPhysicalSegments;
+
+ //
+ // Auxilary pointer to downloadarray
+ //
+ PTOK162_TRANSMIT_LIST Aux;
+
+ //
+ // Iterative variable
+ //
+ UINT i;
+
+ //
+ // Count variable
+ //
+ USHORT Count;
+
+ //
+ // Variable for indexing
+ //
+ USHORT Index;
+
+ //
+ // Log downloadpacket entered
+ //
+ IF_LOG('i');
+
+ //
+ // Show that we aren't constraining
+ //
+ TransmitBlock->UsedBuffer = FALSE;
+
+ //
+ // Set the first entry as the current index
+ //
+ TransmitBlock->FirstEntry = Adapter->AdapterTransmitIndex;
+ CURRENT_DEBUG(DbgPrint("TransmitBlock->FirstEntry = %u\n",
+ TransmitBlock->FirstEntry);)
+
+ //
+ // Set the first map register
+ //
+ CurMapRegister = Adapter->AdapterTransmitIndex;
+
+ //
+ // Variable that keeps track of array entries used.
+ //
+ Count = 0;
+
+ //
+ // Initialize download array pointer
+ //
+ Aux = &Adapter->DownLoadArray[0];
+
+ //
+ // Loop through all of the buffers
+ //
+ while (CurrentBuffer != NULL) {
+
+
+ NdisMStartBufferPhysicalMapping(
+ Adapter->MiniportAdapterHandle,
+ CurrentBuffer,
+ CurMapRegister,
+ TRUE,
+ PhysSegArray,
+ &BufferPhysicalSegments
+ );
+
+ //
+ // Go to the next map register
+ //
+ CurMapRegister++;
+
+ if (CurMapRegister == TRANSMIT_ENTRIES) {
+
+ CurMapRegister = 0;
+
+ }
+
+ //
+ // Make sure buffers are in sync
+ //
+ NdisFlushBuffer(CurrentBuffer, TRUE);
+
+ //
+ // Calculate the individual segment entries
+ //
+ for (i = 0; i < BufferPhysicalSegments; i++) {
+
+ Aux->FrameSize = PhysSegArray[i].Length;
+
+ Aux->CSTAT = TRANSMIT_CSTAT_VALID;
+
+ Aux->PhysicalAddress =
+ NdisGetPhysicalAddressLow(PhysSegArray[i].PhysicalAddress);
+
+ Count++;
+ Aux++;
+
+ }
+
+ //
+ // Get the next buffer
+ //
+ NdisGetNextBuffer(
+ CurrentBuffer,
+ &CurrentBuffer
+ );
+
+ }
+
+ //
+ // Mark start of the frame
+ //
+ Adapter->DownLoadArray[0].CSTAT |= (TRANSMIT_CSTAT_SOF |
+ TRANSMIT_CSTAT_FI);
+
+ //
+ // Mark end of frame
+ //
+ Adapter->DownLoadArray[Count-1].CSTAT |= TRANSMIT_CSTAT_EOF;
+
+ //
+ // Initialize the auxilary variables
+ //
+ Aux = &Adapter->DownLoadArray[0];
+ Index = Adapter->AdapterTransmitIndex;
+
+ //
+ // First set the address register on the card to point to correct
+ // transmit list.
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_ADDRESS,
+ (Index * 8) + COMMUNICATION_XMT_OFFSET
+ );
+
+ //
+ // Loop through and download the packet
+ //
+ for(i = 0; i < Count; i++, Aux++) {
+
+ //
+ // Write the size of the buffer
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA_AUTO_INC,
+ Aux->FrameSize
+ );
+
+ //
+ // Now write high part of the buffer address
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA_AUTO_INC,
+ HIGH_WORD(Aux->PhysicalAddress)
+ );
+
+ //
+ // Now write the low part of the buffer address
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA_AUTO_INC,
+ LOW_WORD(Aux->PhysicalAddress)
+ );
+
+ //
+ // Now write the Transmit List CSTAT to the card
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA_AUTO_INC,
+ Aux->CSTAT
+ );
+
+ Index++;
+
+ //
+ // Check for wrap
+ //
+ if (Index == TRANSMIT_ENTRIES) {
+
+ Index = 0;
+
+ //
+ // Reset the address register on the adapter
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_ADDRESS,
+ (USHORT)COMMUNICATION_XMT_OFFSET
+ );
+
+ }
+
+ }
+
+ //
+ // Set the adapter index variable
+ //
+ Adapter->AdapterTransmitIndex = Index;
+
+ //
+ // Restart the transmits
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_COMMAND,
+ ENABLE_TRANSMIT_VALID
+ );
+
+ //
+ // Log downloadpacket exited
+ //
+ IF_LOG('I');
+
+}
diff --git a/private/ntos/ndis/ibmtok2e/sources b/private/ntos/ndis/ibmtok2e/sources
new file mode 100644
index 000000000..0af9448ce
--- /dev/null
+++ b/private/ntos/ndis/ibmtok2e/sources
@@ -0,0 +1,53 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=ibmtok2e
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER
+
+INCLUDES=inc;..\..\inc;..\..\..\inc
+
+SOURCES=
+
+i386_SOURCES= command.c \
+ interrup.c \
+ tok162.c \
+ reset.c \
+ send.c \
+ tok162.rc
+
+MIPS_SOURCES=
+
+ALPHA_SOURCES=
+
+RELATIVE_DEPTH=..\..
+
+MSC_WARNING_LEVEL=/W3 /WX
diff --git a/private/ntos/ndis/ibmtok2e/tok162.c b/private/ntos/ndis/ibmtok2e/tok162.c
new file mode 100644
index 000000000..e95747b30
--- /dev/null
+++ b/private/ntos/ndis/ibmtok2e/tok162.c
@@ -0,0 +1,2145 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ TOK162.c
+
+Abstract:
+
+ This is the main file for the IBM Token-Ring 16/4 Adapter II.
+ This driver conforms to the NDIS 3.0 Miniport interface.
+
+Author:
+
+ Kevin Martin (KevinMa) 27-Jan-1994
+
+Environment:
+
+ Kernel Mode.
+
+Revision History:
+
+--*/
+
+
+#include <TOK162sw.h>
+
+#pragma optimize("",off)
+#pragma NDIS_INIT_FUNCTION(TOK162Initialize)
+
+//
+// If debug messages and logging is wanted, set the DBG environment variable.
+//
+#if DBG
+
+//
+// Variable which indicates the level of debugging messages. Values are
+// defined below.
+//
+UCHAR Tok162Debug = 0x0;
+
+//
+// Pointer to the logging table. The table is allocated when the adapter
+// memory is allocated.
+//
+PUCHAR Tok162Log;
+
+//
+// Index pointer for the logging macro.
+//
+USHORT Tok162LogPlace = 0;
+
+#endif
+
+//
+// Function declarations for functions private to this file.
+//
+BOOLEAN
+TOK162AllocateAdapterMemory(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+/*++
+
+Routine Description:
+
+ This is the primary initialization routine for the TOK162 driver.
+ It is simply responsible for the intializing the wrapper and registering
+ the MAC. It then calls a system and architecture specific routine that
+ will initialize and register each adapter.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+Return Value:
+
+ The status of the operation.
+
+--*/
+
+{
+ //
+ // Receives the status of the NdisMRegisterMiniport operation.
+ //
+ NDIS_STATUS Status;
+
+ //
+ // Handle for our driver given to us by the wrapper.
+ //
+ NDIS_HANDLE NdisWrapperHandle;
+
+ //
+ // Miniport driver characteristics
+ //
+ char Tmp[sizeof(NDIS_MINIPORT_CHARACTERISTICS)];
+
+ PNDIS_MINIPORT_CHARACTERISTICS TOK162Char =
+ (PNDIS_MINIPORT_CHARACTERISTICS)(PVOID)Tmp;
+
+ //
+ // Initialize the wrapper.
+ //
+ NdisMInitializeWrapper(
+ &NdisWrapperHandle,
+ DriverObject,
+ RegistryPath,
+ NULL
+ );
+
+ //
+ // Initialize the Miniport characteristics for the call to
+ // NdisRegisterMac.
+ //
+ TOK162Char->MajorNdisVersion = TOK162_NDIS_MAJOR_VERSION;
+ TOK162Char->MinorNdisVersion = TOK162_NDIS_MINOR_VERSION;
+
+ //
+ // Define the entry points into this driver for the wrapper.
+ //
+ TOK162Char->CheckForHangHandler = TOK162CheckForHang;
+ TOK162Char->DisableInterruptHandler = TOK162DisableInterrupt;
+ TOK162Char->EnableInterruptHandler = TOK162EnableInterrupt;
+ TOK162Char->HaltHandler = TOK162Halt;
+ TOK162Char->HandleInterruptHandler = TOK162HandleInterrupt;
+ TOK162Char->InitializeHandler = TOK162Initialize;
+ TOK162Char->ISRHandler = TOK162Isr;
+ TOK162Char->QueryInformationHandler = TOK162QueryInformation;
+
+ //
+ // We don't support reconfigure so we pass a null.
+ //
+ TOK162Char->ReconfigureHandler = NULL;
+ TOK162Char->ResetHandler = TOK162Reset;
+ TOK162Char->SendHandler = TOK162Send;
+ TOK162Char->SetInformationHandler = TOK162SetInformation;
+ TOK162Char->TransferDataHandler = TOK162TransferData;
+
+ //
+ // Register the driver.
+ //
+ Status = NdisMRegisterMiniport(
+ NdisWrapperHandle,
+ TOK162Char,
+ sizeof(*TOK162Char)
+ );
+
+ //
+ // If everything went ok, return STATUS_SUCCESS
+ //
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ return STATUS_SUCCESS;
+
+ }
+
+ //
+ // We can only get here if something went wrong with registering
+ // the miniport or *all* of the adapters.
+ //
+ NdisTerminateWrapper(NdisWrapperHandle, NULL);
+ return STATUS_UNSUCCESSFUL;
+}
+
+
+NDIS_STATUS
+TOK162RegisterAdapter(
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PUCHAR CurrentAddress,
+ IN UINT PortAddress,
+ IN UINT InterruptLevel,
+ IN ULONG MaxFrameSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine (and its interface) are not portable. They are
+ defined by the OS, the architecture, and the particular TOK162
+ implementation.
+
+ This routine is responsible for the allocation of the datastructures
+ for the driver as well as any hardware specific details necessary
+ to talk with the device.
+
+Arguments:
+
+ ConfigurationHandle - Handle passed to NdisRegisterAdapter.
+ MiniportAdapterHandle - Handle received from
+ CurrentAddress - The network address found in the registry
+ PortAddress - The starting i/o port address found in the
+ registry
+
+Return Value:
+
+ Returns NDIS_STATUS_SUCCESS if everything goes ok, else
+ if anything occurred that prevents the initialization
+ of the adapter it returns an appropriate NDIS error.
+
+--*/
+
+{
+ //
+ // Holds the configuration info
+ //
+ UCHAR Config;
+
+ //
+ // Holds the value returned by NDIS calls.
+ //
+ NDIS_STATUS Status;
+
+ //
+ // Holds information needed when registering the adapter.
+ //
+ PTOK162_ADAPTER Adapter;
+
+ // We put in this assertion to make sure that ushort are 2 bytes.
+ // if they aren't then the initialization block definition needs
+ // to be changed.
+ //
+ ASSERT(sizeof(TOK162_PHYSICAL_ADDRESS) == 4);
+
+ //
+ // Allocate the Adapter memory
+ //
+ TOK162_ALLOC_PHYS(&Status, &Adapter, sizeof(TOK162_ADAPTER));
+
+ //
+ //
+ //
+ //
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ //
+ // Allocation went ok, so zero out the memory
+ //
+
+ NdisZeroMemory(
+ Adapter,
+ sizeof(TOK162_ADAPTER)
+ );
+
+ //
+ // Assign the handle and io port address base
+ //
+ Adapter->MiniportAdapterHandle = MiniportAdapterHandle;
+
+ //
+ // Set the interrupt level
+ //
+ Adapter->InterruptLevel = InterruptLevel;
+
+ //
+ // Notify the wrapper of our attributes
+ //
+ NdisMSetAttributes(
+ MiniportAdapterHandle,
+ (NDIS_HANDLE)Adapter,
+ TRUE,
+ NdisInterfaceEisa
+ );
+
+ //
+ // Register our shutdown handler.
+ //
+
+ NdisMRegisterAdapterShutdownHandler(
+ Adapter->MiniportAdapterHandle, // miniport handle.
+ Adapter, // shutdown context.
+ TOK162Shutdown // shutdown handler.
+ );
+
+ //
+ // Get the system configuration byte.
+ //
+ Status = NdisMRegisterIoPortRange(
+ (PVOID *)(&(Adapter->PortIOAddress)),
+ MiniportAdapterHandle,
+ PortAddress + 0x0c86,
+ 0x20
+ );
+
+ //
+ // Now read in the byte
+ //
+ READ_ADAPTER_UCHAR(Adapter,
+ 0,
+ &Config
+ );
+
+ //
+ // We don't need the io port anymore
+ //
+ NdisMDeregisterIoPortRange(Adapter->MiniportAdapterHandle,
+ PortAddress + 0x0c86,
+ 0x20,
+ Adapter->PortIOAddress
+ );
+
+
+ //
+ // Get the link speed and set the buffer size
+ //
+ if (Config & 0x10) {
+
+ Adapter->Running16Mbps = TRUE;
+ Adapter->ReceiveBufferSize = RECEIVE_LIST_BUFFER_SIZE_16;
+
+ } else {
+
+ Adapter->Running16Mbps = FALSE;
+ Adapter->ReceiveBufferSize = RECEIVE_LIST_BUFFER_SIZE_4;
+
+ }
+
+ //
+ // Set receive buffersize based on what the user passed us
+ //
+ if (MaxFrameSize != 0) {
+
+ Adapter->ReceiveBufferSize = (USHORT)MaxFrameSize;
+
+ }
+
+ //
+ // Set PortIOBase
+ //
+ Adapter->PortIOBase = PortAddress;
+
+ //
+ // Set the receive, transmit, and command buffer and block
+ // information.
+ //
+ Adapter->NumberOfReceiveBuffers = RECEIVE_LIST_COUNT;
+ Adapter->NumberOfAvailableTransmitBlocks = TRANSMIT_LIST_COUNT;
+ Adapter->NumberOfAvailableCommandBlocks = TOK162_NUMBER_OF_CMD_BLOCKS;
+
+ //
+ // Set the address the adapter should enter the ring with.
+ //
+ NdisMoveMemory(
+ Adapter->CurrentAddress,
+ CurrentAddress,
+ TOK162_LENGTH_OF_ADDRESS
+ );
+
+ //
+ // Register our port usage
+ //
+ Status = NdisMRegisterIoPortRange(
+ (PVOID *)(&(Adapter->PortIOAddress)),
+ MiniportAdapterHandle,
+ Adapter->PortIOBase,
+ 0x10
+ );
+
+ //
+ // If there was a problem with the registration, free the memory
+ // associated with the adapter and return resource error
+ //
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ goto ErrorLevel1;
+
+ }
+
+ //
+ // Allocate the map registers
+ //
+ Status = NdisMAllocateMapRegisters(
+ Adapter->MiniportAdapterHandle,
+ 0,
+ TRUE,
+ TRANSMIT_ENTRIES,
+ Adapter->ReceiveBufferSize
+ );
+
+ //
+ // If there were any problems, return resources error.
+ //
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ goto ErrorLevel2;
+
+ }
+
+ //
+ // Allocate memory for all of the adapter structures
+ //
+ if (TOK162AllocateAdapterMemory(Adapter) != TRUE) {
+
+ goto ErrorLevel3;
+
+ }
+
+ //
+ // Reset the variables associated with the adapter
+ //
+ TOK162ResetVariables(Adapter);
+
+ //
+ // Initialize deferred and reset timers
+ //
+ NdisMInitializeTimer(
+ &Adapter->DeferredTimer,
+ Adapter->MiniportAdapterHandle,
+ (PVOID) TOK162DeferredTimer,
+ (PVOID) Adapter
+ );
+
+ NdisMInitializeTimer(
+ &Adapter->ResetTimer,
+ Adapter->MiniportAdapterHandle,
+ (PVOID) TOK162ResetHandler,
+ (PVOID) Adapter
+ );
+
+ //
+ // Initialize the adapter
+ //
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Calling InitialInit\n");)
+
+ if (TOK162InitialInit(
+ Adapter
+ ) == FALSE) {
+
+ //
+ // Deregister the interrupt and return sources to wrapper. Initial
+ // Init will set the interrupt level to 0 if the registerinterrupt
+ // call was the reason initial init failed.
+ //
+ if (Adapter->InterruptLevel != 0) {
+
+ NdisMDeregisterInterrupt(&Adapter->Interrupt);
+
+ }
+
+ goto ErrorLevel3;
+
+
+ }
+
+ //
+ // Display success to the debugger.
+ //
+ VERY_LOUD_DEBUG(DbgPrint(
+ "IBMTOK2E!Returning TRUE from RegisterAdapter\n");)
+
+ return NDIS_STATUS_SUCCESS;
+
+//
+// ErrorLeve3 level indicates that we need to deregister the map registers
+// and deallocate the adapter-related allocated memory.
+//
+ErrorLevel3:
+
+ NdisMFreeMapRegisters(Adapter->MiniportAdapterHandle);
+ TOK162DeleteAdapterMemory(Adapter);
+
+//
+// ErrorLevel2 indicates that we need to deregister the IO Port Range.
+//
+ErrorLevel2:
+
+ NdisMDeregisterIoPortRange(Adapter->MiniportAdapterHandle,
+ Adapter->PortIOBase,
+ 0x10,
+ Adapter->PortIOAddress
+ );
+
+
+//
+// ErrorLevel1 indicates that we need to free the memory allocated
+// for the adapter structure. Log that register adapter failed.
+//
+ErrorLevel1:
+
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+
+ VERY_LOUD_DEBUG(DbgPrint(
+ "IBMTOK2E!Returning FALSE from RegisterAdapter\n");)
+
+ TOK162_FREE_PHYS(Adapter);
+ return NDIS_STATUS_RESOURCES;
+
+}
+
+
+extern
+NDIS_STATUS
+TOK162Initialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to initialize each adapter card/chip.
+
+Arguments:
+
+ OpenErrorStatus - Token Ring Adapter Open Status
+ SelectedMediumIndex - Medium used for transmission (Token Ring)
+ MediumArray - Array of mediums supported by wrapper
+ MiniportAdapterHandle - Adapter Handle
+ ConfigurationHandle - Configuration Handle
+
+Return Value:
+
+ Result of registering this adapter.
+
+--*/
+
+{
+ //
+ // Handle returned by NdisOpenConfiguration
+ //
+ NDIS_HANDLE ConfigHandle;
+
+ //
+ // Simple indexing variable
+ //
+ ULONG i;
+
+ //
+ // Buffer to copy the passed in network address.
+ //
+ UCHAR NetworkAddress[TOK162_LENGTH_OF_ADDRESS];
+
+ //
+ // Receives address of the network address string in the registry
+ //
+ PVOID NetAddress;
+
+ //
+ // Length of above network address string
+ //
+ ULONG Length;
+
+ //
+ // Description string constants found in registry
+ //
+ NDIS_STRING IOAddressStr = NDIS_STRING_CONST("IOBaseAddress");
+ NDIS_STRING MaxFrameStr = NDIS_STRING_CONST("MAXFRAMESIZE");
+
+ //
+ // Return value from NDIS calls
+ //
+ NDIS_STATUS Status;
+
+ //
+ // Variable holding value returned by NdisReadConfiguration
+ //
+ PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
+
+ //
+ // Eisa Slot adapter is in.
+ //
+ UINT EisaSlot;
+
+ //
+ // Eisa Function information variable
+ //
+ NDIS_EISA_FUNCTION_INFORMATION EisaInformation;
+
+ //
+ // Keep maxframesize
+ //
+ ULONG MaxFrameSize;
+
+ //
+ // Cache Alignment variable
+ //
+ ULONG Alignment;
+
+
+
+
+
+ //
+ // Search for the medium type (802.5)
+ //
+ for (i = 0; i < MediumArraySize; i++){
+
+
+ if (MediumArray[i] == NdisMedium802_5){
+ break;
+
+ }
+
+ }
+
+ //
+ // See if Token Ring is supported by the wrapper
+ //
+ if (i == MediumArraySize) {
+
+ return NDIS_STATUS_UNSUPPORTED_MEDIA;
+
+ }
+
+ //
+ // Tell wrapper the index in the medium array we're using
+ //
+ *SelectedMediumIndex = i;
+
+ //
+ // Get access to the configuration information
+ //
+ NdisOpenConfiguration(
+ &Status,
+ &ConfigHandle,
+ ConfigurationHandle
+ );
+
+ //
+ // If there was an error, return with the error code.
+ //
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ return Status;
+
+ }
+
+ //
+ // Read net address from the configuration info.
+ //
+ NdisReadNetworkAddress(
+ &Status,
+ &NetAddress,
+ &Length,
+ ConfigHandle
+ );
+
+ //
+ // Make sure the call worked and the address returned is of valid length
+ //
+ if ((Length == TOK162_LENGTH_OF_ADDRESS) &&
+ (Status == NDIS_STATUS_SUCCESS)) {
+
+ NdisMoveMemory(
+ NetworkAddress,
+ NetAddress,
+ TOK162_LENGTH_OF_ADDRESS
+ );
+
+ //
+ // If not, set the current address to all 0's, forcing the adapter
+ // to use the permanent address as the current address.
+ //
+ } else {
+
+ NdisZeroMemory(
+ NetworkAddress,
+ TOK162_LENGTH_OF_ADDRESS
+ );
+
+ }
+
+ //
+ // Read the EISA Slot information to get the interrupt and port
+ // address
+ //
+ NdisReadEisaSlotInformation(
+ &Status,
+ ConfigurationHandle,
+ &EisaSlot,
+ &EisaInformation
+ );
+
+ //
+ // Get the max frame size if indicated by user
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &MaxFrameStr,
+ NdisParameterInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ MaxFrameSize = (ULONG)(ReturnedValue->ParameterData.IntegerData);
+
+ Alignment = NdisGetCacheFillSize();
+
+ if ( Alignment < sizeof(ULONG) ) {
+
+ Alignment = sizeof(ULONG);
+ }
+
+ MaxFrameSize = (MaxFrameSize + (Alignment - 1)) & ~(Alignment - 1);
+
+ if ((MaxFrameSize > RECEIVE_LIST_BUFFER_SIZE_16) ||
+ (MaxFrameSize < RECEIVE_LIST_BUFFER_SIZE_4)) {
+
+ MaxFrameSize = 0;
+
+ }
+
+ } else {
+
+ MaxFrameSize = 0;
+
+ }
+
+ //
+ // We're done with the configuration info.
+ //
+ NdisCloseConfiguration(ConfigHandle);
+
+ //
+ // Go register this adapter.
+ //
+ Status = TOK162RegisterAdapter(
+ ConfigurationHandle,
+ MiniportAdapterHandle,
+ NetworkAddress,
+ EisaSlot << 12,
+ EisaInformation.EisaIrq[0].ConfigurationByte.Interrupt,
+ MaxFrameSize
+ );
+
+ //
+ // Return the value TOK162RegisterAdapter returned
+ //
+ return Status;
+}
+
+
+BOOLEAN
+TOK162AllocateAdapterMemory(
+ IN PTOK162_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine allocates memory for:
+
+ - DMA Test Area
+
+ - SCB
+
+ - SSB
+
+ - ErrorLog Block
+
+ - ReadAdapter Block
+
+ - Initialization Block
+
+ - Open Command Block
+
+ - Command Queue
+
+ - Transmit Command Queue
+
+ - Transmit Buffers
+
+ - Flush Buffer Pool
+
+ - Receive Queue
+
+ - Receive Buffers
+
+ - Receive Flush Buffers
+
+Arguments:
+
+ Adapter - The adapter to allocate memory for.
+
+Return Value:
+
+ Returns FALSE if some memory needed for the adapter could not
+ be allocated.
+
+--*/
+
+{
+ //
+ // Pointer to a Super Receive List. Used while initializing
+ // the Receive Queue.
+ //
+ PTOK162_SUPER_RECEIVE_LIST CurrentReceiveEntry;
+
+ //
+ // Pointer to a Super Transmit List. Used while initializing
+ // the Transmit Queue.
+ //
+ PTOK162_SUPER_TRANSMIT_LIST CurrentTransmitEntry;
+
+ //
+ // Pointer to a Command Block. Used while initializing
+ // the Command Queue.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK CurrentCommandBlock;
+
+ //
+ // Simple iteration variable.
+ //
+ UINT i;
+
+ //
+ // Status of allocation
+ //
+ NDIS_STATUS Status;
+
+#if DBG
+ //
+ // If debugging is specified, we need to allocate the trace log
+ // buffer.
+ //
+
+ TOK162_ALLOC_PHYS(&Status, &Tok162Log, LOG_SIZE);
+
+#endif
+ //
+ // Allocate the DMA Test Area
+ //
+
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Allocating DMA Test\n");)
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ 256,
+ FALSE,
+ (PVOID *) &Adapter->DmaTest,
+ &Adapter->DmaTestPhysical
+ );
+
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Address of DMA Test Area is %lx\n",
+ (ULONG)Adapter->DmaTest);)
+
+ //
+ // If the Dma Test ARea could not be allocated, a NULL pointer is
+ // returned.
+ //
+ if (Adapter->DmaTest == NULL) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Allocate the SCB
+ //
+
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Allocating SCB\n");)
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(SCB) + 8,
+ FALSE,
+ (PVOID *) &Adapter->Scb,
+ &Adapter->ScbPhysical
+ );
+
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Address of SCB is %lx - %lx\n",
+ (ULONG)Adapter->Scb,
+ NdisGetPhysicalAddressLow(Adapter->ScbPhysical));)
+
+ //
+ // If the Scb could not be allocated, a NULL pointer will have been
+ // returned.
+ //
+ if (Adapter->Scb == NULL) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Allocate the SSB
+ //
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Allocating SSB\n");)
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(SSB) + 8,
+ FALSE,
+ (PVOID *) &Adapter->Ssb,
+ &Adapter->SsbPhysical
+ );
+
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Address of SSB is %lx - %lx\n",
+ (ULONG)Adapter->Ssb,
+ NdisGetPhysicalAddressLow(Adapter->SsbPhysical));)
+
+ //
+ // If the Ssb could not be allocated, a NULL pointer will have been
+ // returned.
+ //
+ if (Adapter->Ssb == NULL) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Allocate the ErrorLog Block
+ //
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Allocating ErrorLog Block\n");)
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(TOK162_ERRORLOG) + 8,
+ FALSE,
+ (PVOID *) &Adapter->ErrorLog,
+ &Adapter->ErrorLogPhysical
+ );
+
+ //
+ // If the ErrorLog could not be allocated, a NULL pointer will have been
+ // returned.
+ //
+ if (Adapter->ErrorLog == NULL) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Allocate the ReadAdapter Buffer
+ //
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Allocating ReadAdapterBuffer\n");)
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ 4096,
+ FALSE,
+ (PVOID *) &Adapter->AdapterBuf,
+ &Adapter->AdapterBufPhysical
+ );
+
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Address of ReadAdapterBuf is %lx\n",(ULONG)Adapter->AdapterBuf);)
+
+ //
+ // If the ReadAdapter Buffer could not be allocated, a NULL
+ // pointer will have been returned.
+ //
+ if (Adapter->AdapterBuf == NULL) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Allocate the Initialization Block
+ //
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Allocating Initialization Block\n");)
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(ADAPTER_INITIALIZATION) + 8,
+ FALSE,
+ (PVOID *) &Adapter->InitializationBlock,
+ &Adapter->InitializationBlockPhysical
+ );
+
+ //
+ // If the Initialization Block could not be allocated, a NULL pointer
+ // will have been returned.
+ //
+ if (Adapter->InitializationBlock == NULL) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Allocate the Open Command Block
+ //
+
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Allocating Open Command\n");)
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(OPEN_COMMAND) + 8,
+ FALSE,
+ (PVOID *) &Adapter->Open,
+ &Adapter->OpenPhysical
+ );
+
+ VERY_LOUD_DEBUG(DbgPrint(
+ "IBMTOK2E!Address of Open Command is %lx\n",(ULONG)Adapter->Open);)
+
+ //
+ // If the Open Command Block could not be allocated, a NULL pointer
+ // will have been returned.
+ //
+ if (Adapter->Open == NULL) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Allocate the command block queue
+ //
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Allocating Command Block Queue\n");)
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(TOK162_SUPER_COMMAND_BLOCK) * (TOK162_NUMBER_OF_CMD_BLOCKS+1),
+ FALSE,
+ (PVOID *) &Adapter->CommandQueue,
+ &Adapter->CommandQueuePhysical
+ );
+
+ //
+ // If the Command Block Queue could not be allocated, a NULL pointer
+ // will have been returned.
+ //
+ if (Adapter->CommandQueue == NULL) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Initialize the command block queue command blocks
+ //
+ for (i = 0, CurrentCommandBlock = Adapter->CommandQueue;
+ i < TOK162_NUMBER_OF_CMD_BLOCKS;
+ i++, CurrentCommandBlock++
+ ) {
+
+ //
+ // Set the state of this command block to free, the
+ // NextPending pointer and Next pointer to null, and
+ // the command timeout state to FALSE
+ //
+ CurrentCommandBlock->Hardware.State = TOK162_STATE_FREE;
+ CurrentCommandBlock->Hardware.NextPending = TOK162_NULL;
+ CurrentCommandBlock->NextCommand = NULL;
+ CurrentCommandBlock->Timeout = FALSE;
+
+ //
+ // Set the index of this command block
+ //
+ CurrentCommandBlock->CommandBlockIndex = (USHORT)i;
+
+ }
+
+ //
+ // Allocate Flush Buffer Pool
+ //
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Allocating Flush Buffer Pool\n");)
+
+ NdisAllocateBufferPool(
+ &Status,
+ (PVOID*)&Adapter->FlushBufferPoolHandle,
+ Adapter->NumberOfReceiveBuffers + TRANSMIT_LIST_COUNT
+ );
+
+ //
+ // If there was a problem allocating the flush buffer pool,
+ // write out an errorlog entry, delete the allocated adapter memory,
+ // and return FALSE
+ //
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Allocate the Transmit Queue.
+ //
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Allocating Transmit Queue\n");)
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(TOK162_SUPER_TRANSMIT_LIST) *
+ TRANSMIT_LIST_COUNT + 1,
+ FALSE,
+ (PVOID*)&Adapter->TransmitQueue,
+ &Adapter->TransmitQueuePhysical
+ );
+
+ //
+ // If the Transmit Queue could not be allocated, a NULL pointer will
+ // have been returned.
+ //
+ if (Adapter->TransmitQueue == NULL) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Initialize the transmit queue entries. First zero out the entire
+ // queue memory.
+ //
+ NdisZeroMemory(
+ Adapter->TransmitQueue,
+ sizeof(TOK162_SUPER_TRANSMIT_LIST) * TRANSMIT_LIST_COUNT
+ );
+
+ //
+ // Allocate the transmit buffers and attach them to the Transmit
+ // Queue entries.
+ //
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Allocating Transmit Buffers\n");)
+
+ for (i = 0, CurrentTransmitEntry = Adapter->TransmitQueue;
+ i < TRANSMIT_LIST_COUNT;
+ i++, CurrentTransmitEntry++
+ ) {
+
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!TransmitEntry[%d] = %08x\n",i,
+ CurrentTransmitEntry);)
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ Adapter->ReceiveBufferSize+8,
+ TRUE,
+ &CurrentTransmitEntry->TransmitBuffer,
+ &CurrentTransmitEntry->TransmitBufferPhysical
+ );
+
+ //
+ // Build flush buffers
+ //
+ NdisAllocateBuffer(
+ &Status,
+ &CurrentTransmitEntry->FlushBuffer,
+ Adapter->FlushBufferPoolHandle,
+ CurrentTransmitEntry->TransmitBuffer,
+ Adapter->ReceiveBufferSize+8
+ );
+
+ //
+ // Initialize receive lists
+ //
+ NdisFlushBuffer(CurrentTransmitEntry->FlushBuffer, TRUE);
+
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Transmit Buffer is %08x\n",CurrentTransmitEntry->TransmitBuffer);)
+
+ //
+ // If the current buffer could not be allocated, write the errorlog
+ // entry, delete allocated adapter memory, and return FALSE
+ //
+ if (!CurrentTransmitEntry->TransmitBuffer) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Create a circular list of transmit buffers. For every one but the
+ // last, set the forward pointer to the next entry. The last entry
+ // has to point to the first entry (queue head).
+ //
+ if (i != (TRANSMIT_LIST_COUNT - 1)) {
+
+ CurrentTransmitEntry->NextEntry = (PTOK162_SUPER_TRANSMIT_LIST)(
+ (PUCHAR)(Adapter->TransmitQueue) +
+ (i+1) * (sizeof(TOK162_SUPER_TRANSMIT_LIST)));
+
+
+ } else {
+
+ CurrentTransmitEntry->NextEntry = Adapter->TransmitQueue;
+
+ }
+
+ }
+
+ //
+ // Allocate the Receive Queue.
+ //
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Allocating Receive Queue\n");)
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(TOK162_SUPER_RECEIVE_LIST) *
+ (Adapter->NumberOfReceiveBuffers+1),
+ FALSE,
+ (PVOID*)&Adapter->ReceiveQueue,
+ &Adapter->ReceiveQueuePhysical
+ );
+
+ //
+ // If the Receive Queue could not be allocated, a NULL pointer will
+ // have been returned.
+ //
+ if (Adapter->ReceiveQueue == NULL) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Initialize the receieve queue entries. First zero out the entire
+ // queue memory.
+ //
+ NdisZeroMemory(
+ Adapter->ReceiveQueue,
+ sizeof(TOK162_SUPER_RECEIVE_LIST) * Adapter->NumberOfReceiveBuffers
+ );
+
+ //
+ // Allocate the receive buffers and attach them to the Receive
+ // Queue entries.
+ //
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Allocating Receive Buffers\n");)
+
+ for (i = 0, CurrentReceiveEntry = Adapter->ReceiveQueue;
+ i < Adapter->NumberOfReceiveBuffers;
+ i++, CurrentReceiveEntry++
+ ) {
+
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!ReceiveEntry[%d] = %08x\n",i,
+ CurrentReceiveEntry);)
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ Adapter->ReceiveBufferSize+8,
+ TRUE,
+ &CurrentReceiveEntry->ReceiveBuffer,
+ &CurrentReceiveEntry->ReceiveBufferPhysical
+ );
+
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Receive Buffer is %08x\n",CurrentReceiveEntry->ReceiveBuffer);)
+
+ //
+ // If the current buffer could not be allocated, write the errorlog
+ // entry, delete allocated adapter memory, and return FALSE
+ //
+ if (!CurrentReceiveEntry->ReceiveBuffer) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Build flush buffers
+ //
+ NdisAllocateBuffer(
+ &Status,
+ &CurrentReceiveEntry->FlushBuffer,
+ Adapter->FlushBufferPoolHandle,
+ CurrentReceiveEntry->ReceiveBuffer,
+ Adapter->ReceiveBufferSize
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Initialize receive lists
+ //
+ NdisFlushBuffer(CurrentReceiveEntry->FlushBuffer, FALSE);
+
+ //
+ // Set the CSTAT to indicate this buffer is free
+ //
+ CurrentReceiveEntry->Hardware.CSTAT = RECEIVE_CSTAT_REQUEST_RESET;
+
+ //
+ // Set the size of the buffer
+ //
+ CurrentReceiveEntry->Hardware.FrameSize =
+ Adapter->ReceiveBufferSize;
+
+ //
+ // Create a circular list of receive buffers. For every one but the
+ // last, set the forward pointer to the next entry. The last entry
+ // has to point to the first entry (queue head).
+ //
+ if (i != (Adapter->NumberOfReceiveBuffers - 1)) {
+
+ CurrentReceiveEntry->NextEntry = (PTOK162_SUPER_RECEIVE_LIST)(
+ (PUCHAR)(Adapter->ReceiveQueue) +
+ (i+1) * (sizeof(TOK162_SUPER_RECEIVE_LIST)));
+
+ } else {
+
+ CurrentReceiveEntry->NextEntry = Adapter->ReceiveQueue;
+
+ }
+ }
+
+ //
+ // If we made it this far, everything is ok. Return TRUE.
+ //
+ return TRUE;
+
+}
+
+
+VOID
+TOK162DeleteAdapterMemory(
+ IN PTOK162_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deallocates memory for:
+
+ - DMA Test Area
+
+ - SCB
+
+ - SSB
+
+ - ErrorLog Block
+
+ - ReadAdapter Block
+
+ - Initialization Block
+
+ - Open Command Block
+
+ - Command Queue
+
+ - Transmit Command Queue
+
+ - Transmit Buffers
+
+ - Flush Buffer Pool
+
+ - Receive Queue
+
+ - Receive Buffers
+
+ - Receive Flush Buffers
+
+Arguments:
+
+ Adapter - The adapter to deallocate memory for.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Display to the debugger where we are
+ //
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!In delete adapter memory\n");)
+
+ //
+ // Free the Dma Test Area
+ //
+ if (Adapter->DmaTest) {
+
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Freeing Dma Test Area\n");)
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ 256,
+ FALSE,
+ Adapter->DmaTest,
+ Adapter->DmaTestPhysical
+ );
+
+ }
+
+ //
+ // Free the SCB
+ //
+ if (Adapter->Scb) {
+
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Freeing SCB\n");)
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(SCB) + 8,
+ FALSE,
+ Adapter->Scb,
+ Adapter->ScbPhysical
+ );
+
+ }
+
+ //
+ // Free the SSB
+ //
+ if (Adapter->Ssb) {
+
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Freeing SSB - %x %x\n",Adapter->Ssb,
+ Adapter->SsbPhysical);)
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(SSB) + 8,
+ FALSE,
+ Adapter->Ssb,
+ Adapter->SsbPhysical
+ );
+
+ }
+
+ //
+ // Free the errorlog block
+ //
+ if (Adapter->ErrorLog) {
+
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Freeing ErrorLog - %x\n",
+ Adapter->ErrorLog);)
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(TOK162_ERRORLOG) + 8,
+ FALSE,
+ Adapter->ErrorLog,
+ Adapter->ErrorLogPhysical
+ );
+
+ }
+
+ //
+ // Free the read adapter block
+ //
+ if (Adapter->AdapterBuf) {
+
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Freeing Read Adapter Block\n");)
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ 4096,
+ FALSE,
+ Adapter->AdapterBuf,
+ Adapter->AdapterBufPhysical
+ );
+
+ }
+
+ //
+ // Free the initialization block
+ //
+ if (Adapter->InitializationBlock) {
+
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Freeing Initialization Block\n");)
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(ADAPTER_INITIALIZATION) + 8,
+ FALSE,
+ Adapter->InitializationBlock,
+ Adapter->InitializationBlockPhysical
+ );
+
+ }
+
+ //
+ // Free the open command block
+ //
+ if (Adapter->Open) {
+
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Freeing Open Block - %x\n",Adapter->Open);)
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(OPEN_COMMAND) + 8,
+ FALSE,
+ Adapter->Open,
+ Adapter->OpenPhysical
+ );
+
+ }
+
+ //
+ // Free the command queue
+ //
+ if (Adapter->CommandQueue) {
+
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Freeing CommandQueue\n");)
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(TOK162_SUPER_COMMAND_BLOCK) *
+ (TOK162_NUMBER_OF_CMD_BLOCKS + 1),
+ FALSE,
+ Adapter->CommandQueue,
+ Adapter->CommandQueuePhysical
+ );
+
+ }
+
+ //
+ // Free the transmit queue and transmit buffers
+ //
+ if (Adapter->TransmitQueue) {
+
+ //
+ // Pointer to current Transmit Entry being deallocated.
+ //
+ PTOK162_SUPER_TRANSMIT_LIST CurrentTransmitEntry;
+
+ //
+ // Simple iteration counter.
+ //
+ UINT i;
+
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Freeing TransmitCommandQueue\n");)
+
+ for (i = 0, CurrentTransmitEntry = Adapter->TransmitQueue;
+ i < TRANSMIT_LIST_COUNT;
+ i++, CurrentTransmitEntry++
+ ) {
+
+ if (CurrentTransmitEntry->TransmitBuffer) {
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ Adapter->ReceiveBufferSize,
+ TRUE,
+ CurrentTransmitEntry->TransmitBuffer,
+ CurrentTransmitEntry->TransmitBufferPhysical
+ );
+
+ }
+
+ }
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(TOK162_SUPER_RECEIVE_LIST) * TRANSMIT_LIST_COUNT,
+ FALSE,
+ Adapter->TransmitQueue,
+ Adapter->TransmitQueuePhysical
+ );
+
+ }
+
+ //
+ // Free the receive queue, receive buffers, and flush buffers
+ //
+ if (Adapter->ReceiveQueue) {
+
+ //
+ // Pointer to current Receive Entry being deallocated.
+ //
+ PTOK162_SUPER_RECEIVE_LIST CurrentReceiveEntry;
+
+ //
+ // Simple iteration counter.
+ //
+ UINT i;
+
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Freeing ReceiveCommandQueue\n");)
+
+ for (i = 0, CurrentReceiveEntry = Adapter->ReceiveQueue;
+ i < Adapter->NumberOfReceiveBuffers;
+ i++, CurrentReceiveEntry++
+ ) {
+
+ if (CurrentReceiveEntry->ReceiveBuffer) {
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ Adapter->ReceiveBufferSize,
+ TRUE,
+ CurrentReceiveEntry->ReceiveBuffer,
+ CurrentReceiveEntry->ReceiveBufferPhysical
+ );
+
+
+ if (CurrentReceiveEntry->FlushBuffer) {
+ NdisFreeBuffer(
+ CurrentReceiveEntry->FlushBuffer
+ );
+ }
+ }
+
+ }
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(TOK162_SUPER_RECEIVE_LIST) *
+ Adapter->NumberOfReceiveBuffers,
+ FALSE,
+ Adapter->ReceiveQueue,
+ Adapter->ReceiveQueuePhysical
+ );
+
+ }
+
+ //
+ // Free the flush buffer pool handle
+ //
+ if (Adapter->FlushBufferPoolHandle) {
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Freeing BufferPool\n");)
+ NdisFreeBufferPool(
+ Adapter->FlushBufferPoolHandle
+ );
+ }
+
+}
+
+
+extern
+VOID
+TOK162Halt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ TOK162Halt removes an adapter previously initialized.
+
+Arguments:
+
+ MiniportAdapterContext - The context value that the Miniport returned
+ from Tok162Initialize; actually is pointer to
+ a TOK162_ADAPTER.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Pointer to an adapter structure. Makes Context (passed in value)
+ // a structure we can deal with.
+ //
+ PTOK162_ADAPTER Adapter =
+ PTOK162_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ //
+ // Don't allow any more processing internally
+ //
+ // Adapter->ResetInProgress = TRUE;
+
+ //
+ // Shut down the chip.
+ //
+ TOK162DisableInterrupt(Adapter);
+
+ //
+ // Return resources to the wrapper
+ //
+ NdisMDeregisterInterrupt(&Adapter->Interrupt);
+
+ NdisMDeregisterIoPortRange(Adapter->MiniportAdapterHandle,
+ Adapter->PortIOBase,
+ 0x30,
+ Adapter->PortIOAddress
+ );
+
+ NdisMFreeMapRegisters(Adapter->MiniportAdapterHandle);
+
+ //
+ // Free the allocated memory for the adapter-related structures
+ //
+ TOK162DeleteAdapterMemory(Adapter);
+
+ //
+ // Finally, free the allocated memory for the adapter structure itself
+ //
+ TOK162_FREE_PHYS(Adapter);
+
+}
+
+
+extern
+VOID
+TOK162Shutdown(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ TOK162Shutdown-- removes an adapter previously initialized.
+
+Arguments:
+
+ MiniportAdapterContext - The context value that the Miniport returned
+ from Tok162Initialize; actually is pointer to
+ a TOK162_ADAPTER.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Pointer to an adapter structure. Makes Context (passed in value)
+ // a structure we can deal with.
+ //
+
+ PTOK162_ADAPTER Adapter =
+ PTOK162_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ //
+ // Reset the chip to get us off the ring.
+ //
+ TOK162ResetAdapter(Adapter);
+
+}
+
+
+NDIS_STATUS
+TOK162Reset(
+ OUT PBOOLEAN AddressingReset,
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+/*++
+
+Routine Description:
+
+ The TOK162Reset request instructs the Miniport to issue a hardware reset
+ to the network adapter. The driver also resets its software state. See
+ the description of NdisMReset for a detailed description of this request.
+
+Arguments:
+
+ MiniportAdapterContext - Pointer to the adapter structure.
+
+Return Value:
+
+ The function value is the status of the operation.
+--*/
+
+{
+ //
+ // Pointer to an adapter structure. Makes Context (passed in value)
+ // a structure we can deal with.
+ //
+ PTOK162_ADAPTER Adapter =
+ PTOK162_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ LOUD_DEBUG(DbgPrint("IBMTOK2E!Reset called\n");)
+
+ //
+ // Log reset called
+ //
+ IF_LOG('R');
+
+ //
+ // Make sure we aren't already doing a reset.
+ //
+ if (Adapter->ResetInProgress == FALSE) {
+
+ Adapter->ResetInProgress = TRUE;
+
+ //
+ // Set to first state
+ //
+ Adapter->ResetState = CheckReset;
+
+ //
+ // Do the reset and return pending
+ //
+ TOK162SetupForReset(
+ Adapter
+ );
+
+ return NDIS_STATUS_PENDING;
+
+ } else {
+
+ //
+ // If we are doing a reset currently, return this fact.
+ //
+ return NDIS_STATUS_RESET_IN_PROGRESS;
+
+ }
+
+}
+
+
+BOOLEAN
+TOK162CheckForHang(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the wrapper to determine if the adapter
+ is hung.
+
+Arguments:
+
+ Context - Really a pointer to the adapter.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ //
+ // Pointer to an adapter structure. Makes Context (passed in value)
+ // a structure we can deal with.
+ //
+ PTOK162_ADAPTER Adapter =
+ PTOK162_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ //
+ // Variable pointing to the outstanding command. Used to make the
+ // code easier to read (could use Adapter->CommandOnCard).
+ //
+ PTOK162_SUPER_COMMAND_BLOCK FirstPendingCommand = Adapter->CommandOnCard;
+
+ //
+ // Variable pointing to the outstanding transmit. Used to make the
+ // code easier to read (could use Adapter->TransmitOnCard).
+ //
+
+ //
+ // If we're in the middle of a reset, just return false
+ //
+ if (Adapter->ResetInProgress == TRUE) {
+
+ return FALSE;
+
+ }
+
+ //
+ // First see if there is a command outstanding
+ //
+ if (FirstPendingCommand != NULL) {
+
+ //
+ // See if the command block has timed-out.
+ //
+ if (FirstPendingCommand->Timeout) {
+
+ //
+ // See if we have given it enough time
+ //
+ if ( FirstPendingCommand->TimeoutCount >= 40) {
+
+ LOUD_DEBUG(DbgPrint("IBMTOK2E!Returning True from checkforhang\n");)
+ return TRUE;
+
+ } else {
+
+ FirstPendingCommand->TimeoutCount++;
+
+ }
+
+ } else {
+
+ //
+ // Mark the current command as timed out and get the clock
+ // rolling.
+ //
+ FirstPendingCommand->Timeout = TRUE;
+ FirstPendingCommand->TimeoutCount = 0;
+
+ }
+
+ }
+
+ //
+ // If we got here, we aren't hung.
+ //
+ return FALSE;
+}
+
+
+NDIS_STATUS
+TOK162TransferData(
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+ )
+
+/*++
+
+Routine Description:
+
+ A protocol calls the TOK162TransferData request (indirectly via
+ NdisTransferData) from within its Receive event handler
+ to instruct the Miniport to copy the contents of the received packet
+ a specified packet buffer.
+
+Arguments:
+
+ MiniportAdapterContext - The context value returned by the driver when the
+ adapter was initialized. In reality this is a
+ pointer to TOK162_ADAPTER.
+
+ MiniportReceiveContext - The context value passed by the driver on its
+ call to NdisMIndicateReceive. The driver can
+ use this value to determine which packet, on
+ which adapter, is being received.
+
+ ByteOffset - An unsigned integer specifying the offset within
+ the received packet at which the copy is to begin.
+ If the entire packet is to be copied,
+ ByteOffset must be zero.
+
+ BytesToTransfer - An unsigned integer specifying the number of
+ bytes to copy. It is legal to transfer zero
+ bytes; this has no effect. If the sum of
+ ByteOffset and BytesToTransfer is greater than
+ the size of the received packet, then the
+ remainder of the packet (starting from
+ ByteOffset) is transferred, and the trailing
+ portion of the receive buffer is not modified.
+
+ Packet - A pointer to a descriptor for the packet storage
+ into which the MAC is to copy the received packet.
+
+ BytesTransfered - A pointer to an unsigned integer. The miniport
+ writes the actual number of bytes transferred
+ into this location. This value is not valid if
+ the return status is STATUS_PENDING.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+
+ //
+ // Pointer to an adapter structure. Makes Context (passed in value)
+ // a structure we can deal with.
+ //
+ PTOK162_ADAPTER Adapter =
+ PTOK162_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ //
+ // Holds the count of the number of ndis buffers comprising the
+ // destination packet.
+ //
+ UINT DestinationBufferCount;
+
+ //
+ // Points to the buffer into which we are putting data.
+ //
+ PNDIS_BUFFER DestinationCurrentBuffer;
+
+ //
+ // Points to the location in Buffer from which we are extracting data.
+ //
+ PUCHAR SourceCurrentAddress;
+
+ //
+ // Holds the virtual address of the current destination buffer.
+ //
+ PVOID DestinationVirtualAddress;
+
+ //
+ // Holds the length of the current destination buffer.
+ //
+ UINT DestinationCurrentLength;
+
+ //
+ // Keep a local variable of BytesTransferred so we aren't referencing
+ // through a pointer.
+ //
+ UINT LocalBytesTransferred = 0;
+
+ //
+ // Display where we are on the debugger
+ //
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Transfer Data called\n");)
+
+ //
+ // Display number of bytes to transfer on the debugger
+ //
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Copying %u bytes\n",BytesToTransfer);)
+
+ //
+ // Initialize the number of bytes transferred to 0
+ //
+ *BytesTransferred = 0;
+
+ //
+ // If we don't have any more to transfer, we're done
+ //
+ if (BytesToTransfer == 0) {
+
+ return NDIS_STATUS_SUCCESS;
+
+ }
+
+ //
+ // Get the first buffer of the destination.
+ //
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ &DestinationBufferCount,
+ &DestinationCurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet. If so, we are done.
+ //
+ if (DestinationBufferCount == 0) {
+
+ return NDIS_STATUS_SUCCESS;
+
+ }
+
+ //
+ // Get information on the buffer.
+ //
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+
+ //
+ // Set up the source address.
+ //
+ SourceCurrentAddress = (PCHAR)(MiniportReceiveContext) + ByteOffset;
+
+ //
+ // Do the actual transfer from source to destination
+ //
+ while (LocalBytesTransferred < BytesToTransfer) {
+
+ //
+ // Check to see whether we've exhausted the current destination
+ // buffer. If so, move onto the next one.
+ //
+ if (!DestinationCurrentLength) {
+
+ NdisGetNextBuffer(
+ DestinationCurrentBuffer,
+ &DestinationCurrentBuffer
+ );
+
+ if (!DestinationCurrentBuffer) {
+
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.)
+ //
+
+ break;
+
+ }
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+
+ continue;
+
+ }
+
+ //
+ // Copy the data.
+ //
+ {
+ //
+ // Holds the amount of data to move.
+ //
+ UINT AmountToMove;
+
+ //
+ // Holds the amount desired remaining.
+ //
+ UINT Remaining = BytesToTransfer - LocalBytesTransferred;
+
+
+ AmountToMove = DestinationCurrentLength;
+
+ AmountToMove = ((Remaining < AmountToMove)?
+ (Remaining):(AmountToMove));
+
+ NdisMoveMemory(
+ DestinationVirtualAddress,
+ SourceCurrentAddress,
+ AmountToMove
+ );
+
+ //
+ // Update pointers and counters
+ //
+ SourceCurrentAddress += AmountToMove;
+ LocalBytesTransferred += AmountToMove;
+ DestinationCurrentLength -= AmountToMove;
+
+ }
+
+ }
+
+ //
+ // Indicate how many bytes were transferred
+ //
+ *BytesTransferred = LocalBytesTransferred;
+
+ //
+ // Display total bytes transferred on debugger
+ //
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Total bytes transferred = %x\n",
+ *BytesTransferred);)
+
+ return NDIS_STATUS_SUCCESS;
+
+}
diff --git a/private/ntos/ndis/ibmtok2e/tok162.rc b/private/ntos/ndis/ibmtok2e/tok162.rc
new file mode 100644
index 000000000..edf65f261
--- /dev/null
+++ b/private/ntos/ndis/ibmtok2e/tok162.rc
@@ -0,0 +1,38 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "IBM Token Ring Busmaster EISA Network Driver"
+#define VER_INTERNALNAME_STR "IBMTOK2E.SYS"
+#define VER_ORIGINALFILENAME_STR "IBMTOK2E.SYS"
+
+#include "common.ver"
diff --git a/private/ntos/ndis/ibmtok2e/tok162hw.h b/private/ntos/ndis/ibmtok2e/tok162hw.h
new file mode 100644
index 000000000..1e9017b8b
--- /dev/null
+++ b/private/ntos/ndis/ibmtok2e/tok162hw.h
@@ -0,0 +1,950 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ tokhrd.h
+
+Abstract:
+
+ The hardware-related definitions for the IBM Token-Ring 16/4 II
+ ISA driver.
+
+Author:
+
+ Kevin Martin (kevinma) 1-Feb-1994
+
+Environment:
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ References to "IBM Spec" refer to the IBM "Supplement to the LAN
+ Technical Reference (Token-Ring Network 16/4 Adapter II)" Specification.
+ The document number is - SD21-052-00.
+
+ References to "IBM Eisa Spec" refer to the IBM "Final Software Interface
+ Description For The EISA Busmaster Token Ring Adapter"
+ The document number is - H54/002?
+
+ References to "TI Spec" refer to the Texas Instruments "TMS380 Second-
+ Generation Token Ring" User's Guide. The document number is - SPWU005.
+
+Revision History:
+
+--*/
+
+//
+// Pack everything on word boundaries
+//
+#include <pshpack2.h>
+
+//
+// Define "Physical Addresses" which are ULONG in size. The card
+// wants physical addresses.
+//
+typedef ULONG TOK162_PHYSICAL_ADDRESS, *PTOK162_PHYSICAL_ADDRESS;
+
+//
+// The length of an address (network) is 6 bytes
+//
+#define TOK162_LENGTH_OF_ADDRESS 6
+
+//
+// Define a NULL pointer
+//
+#define TOK162_NULL ((TOK162_PHYSICAL_ADDRESS)(-1L))
+
+//
+// Default number of command blocks
+//
+#define TOK162_NUMBER_OF_CMD_BLOCKS 4
+
+//
+// Burst size for transmit and receive DMA. A zero tells the adapter to
+// use the size of the transfer as the burst size.
+//
+// IBM Eisa Spec, Page 36
+
+#define TOK162_BURST_SIZE 0
+
+//
+// Number of retries to attempt after a DMA error
+//
+#define TOK162_DMA_RETRIES 0x0303
+
+//
+// Minimum packet size for a valid transfer/receive
+//
+#define MINIMUM_TOKENRING_PACKET_SIZE 32
+
+//
+// Default packet header size
+//
+#define TOK162_HEADER_SIZE 32
+
+//
+// TOK162 Receive/Command Block States
+//
+#define TOK162_STATE_FREE ((USHORT)0x0000)
+#define TOK162_STATE_EXECUTING ((USHORT)0x0001)
+#define TOK162_STATE_WAIT_FOR_ADAPTER ((USHORT)0x0002)
+
+//
+// Offsets from above of the actual ports used.
+//
+// IBM Eisa Spec, Page 13.
+//
+#define PORT_OFFSET_DATA 0x0000
+#define PORT_OFFSET_DATA_AUTO_INC 0x0002
+#define PORT_OFFSET_ADDRESS 0x0004
+#define PORT_OFFSET_STATUS 0x0006
+#define PORT_OFFSET_COMMAND 0x0006
+#define PORT_OFFSET_ADAPTER_RESET 0x0008
+#define PORT_OFFSET_ADAPTER_ENABLE 0x000A
+#define PORT_OFFSET_SWITCH_INT_DISABLE 0x000C
+#define PORT_OFFSET_SWITCH_INT_ENABLE 0x000E
+
+//
+// Macro to write a ULONG variable to a register on the adapter
+//
+#define WRITE_ADAPTER_ULONG(a, p, v) \
+ NdisRawWritePortUshort((ULONG) (a)->PortIOAddress + (p), \
+ (ULONG) (v))
+
+//
+// Macro to read a ULONG variable from a register on the adapter
+//
+#define READ_ADAPTER_ULONG(a, p, v) \
+ NdisRawReadPortUshort((ULONG) (a)->PortIOAddress + (p), \
+ (PULONG) (v))
+
+//
+// Macro to write a USHORT variable to a register on the adapter
+//
+#define WRITE_ADAPTER_USHORT(a, p, v) \
+ NdisRawWritePortUshort((ULONG) (a)->PortIOAddress + (p), \
+ (USHORT) (v))
+
+//
+// Macro to read a USHORT variable from a register on the adapter
+//
+#define READ_ADAPTER_USHORT(a, p, v) \
+ NdisRawReadPortUshort((ULONG) (a)->PortIOAddress + (p), \
+ (PUSHORT) (v))
+
+//
+// Macro to write a CHAR variable to a register on the adapter
+//
+#define WRITE_ADAPTER_UCHAR(a, p, v) \
+ NdisRawWritePortUchar((ULONG)(a)->PortIOAddress + (p), \
+ (UCHAR)(v))
+
+//
+// Macro to read a ULONG variable from a register on the adapter
+//
+#define READ_ADAPTER_UCHAR(a, p, v) \
+ NdisRawReadPortUchar((ULONG)(a)->PortIOAddress + (p), \
+ (PUCHAR)(v))
+
+//
+// Masks for the command register
+//
+// IBM Eisa Spec, Pages 13-15.
+//
+#define CMD_PIO_INTERRUPT 0x8000
+#define CMD_PIO_RECEIVE_COMPLETE 0x4000
+#define CMD_PIO_SSB_CLEAR 0x2000
+#define CMD_PIO_EXECUTE 0x1000
+#define CMD_PIO_SCB_REQUEST 0x0800
+#define CMD_PIO_TRANSMIT_COMPLETE 0x0400
+#define CMD_PIO_RCV_VALID 0x0200
+#define CMD_PIO_XMIT_VALID 0x0100
+#define CMD_PIO_RESET_SYSTEM 0x0080
+#define CMD_PIO_RESET_RCV_XMT 0x0000
+
+//
+// Common mask combinations
+//
+#define EXECUTE_SCB_COMMAND 0x9080 // int+exec+resetsysint
+#define ENABLE_SSB_UPDATE 0xA000 // int+ssbclear
+#define ENABLE_RECEIVE_VALID 0x8280 // int+rcvvalid+resetsysint
+#define ENABLE_TRANSMIT_VALID 0x8180 // int+xmtvalid+resetsysint
+#define START_ALL_IO 0xC680 // int+rcvfrmcomp+
+ // xmtfrmcomp+rcvvalid+
+ // resetsysint
+
+//
+// Masks for the status register.
+//
+// IBM Eisa Spec, Pages 15-17.
+//
+#define STATUS_ADAPTER_INTERRUPT 0x8000
+#define STATUS_RECEIVE_FRAME_COMPLETE 0x4000
+#define STATUS_TRANSMIT_FRAME_COMPLETE 0x0400
+#define STATUS_RECEIVE_VALID 0x0200
+#define STATUS_TRANSMIT_VALID 0x0100
+#define STATUS_SYSTEM_INTERRUPT 0x0080
+//
+// Masks for adapter interrupts.
+//
+// IBM Eisa Spec, Pages 16-17.
+//
+#define STATUS_INT_CODE_MASK 0x000F
+#define STATUS_INT_CODE_CHECK 0x0000
+#define STATUS_INT_CODE_IMPL 0x0002
+#define STATUS_INT_CODE_RING 0x0004
+#define STATUS_INT_CODE_SCB_CLEAR 0x0006
+#define STATUS_INT_CODE_CMD_STATUS 0x0008
+#define STATUS_INT_CODE_FRAME_STATUS 0x000E
+
+//
+// DMA Command Values
+//
+// IBM Eisa Spec, Page 41.
+//
+#define CMD_DMA_OPEN 0x0003
+#define CMD_DMA_XMIT 0x0004
+#define CMD_DMA_XMIT_HALT 0x0005
+#define CMD_DMA_RCV 0x0006
+#define CMD_DMA_CLOSE 0x0007
+#define CMD_DMA_SET_GRP_ADDR 0x0008
+#define CMD_DMA_SET_FUNC_ADDR 0x0009
+#define CMD_DMA_READ_ERRLOG 0x000A
+#define CMD_DMA_READ 0x000B
+#define CMD_DMA_IMPL_ENABLE 0x000C
+#define CMD_DMA_START_STOP_TRACE 0x000D
+
+//
+// System Command Block structure.
+//
+// IBM Eisa Spec, Page 21.
+//
+typedef struct _SCB {
+
+ //
+ // Command to be submitted to the card.
+ //
+ USHORT Command;
+
+ //
+ // Parameter USHORTs, different for different commands.
+ //
+ USHORT Parm1;
+ USHORT Parm2;
+
+} SCB, *PSCB;
+
+//
+// Generic System Status Block Structure.
+//
+// IBM Eisa Spec, Page 22.
+//
+typedef struct _SSB {
+
+ //
+ // Command for which status is returned.
+ //
+ USHORT Command;
+
+ //
+ // Status USHORTs, different for different commands
+ //
+ USHORT Status1;
+ USHORT Status2;
+ USHORT Status3;
+
+} SSB, *PSSB;
+
+//
+// Ring Status SSB #defines and structure
+//
+// IBM Spec, Page 22-25.
+//
+typedef struct _SSB_RING_STATUS {
+
+ //
+ // Command code, will be SSB_CMD_RING_STATUS
+ //
+ USHORT Command;
+
+ //
+ // Ring Status code, as defined below.
+ //
+ USHORT RingStatus;
+
+ //
+ // Last two not used.
+ //
+ USHORT Reserved1;
+ USHORT Reserved2;
+
+} SSB_RING_STATUS,*PSSB_RING_STATUS;
+
+#define SSB_CMD_RING_STATUS 0x0100
+
+#define RING_STATUS_SIGNAL_LOSS 0x8000
+#define RING_STATUS_HARD_ERROR 0x4000
+#define RING_STATUS_SOFT_ERROR 0x2000
+#define RING_STATUS_XMIT_BEACON 0x1000
+#define RING_STATUS_LOBE_WIRE_FAULT 0x0800
+#define RING_STATUS_AUTO_REMOVE_1 0x0400
+#define RING_STATUS_REMOVE_RECEIVED 0x0100
+#define RING_STATUS_OVERFLOW 0x0080
+#define RING_STATUS_SINGLESTATION 0x0040
+#define RING_STATUS_RINGRECOVERY 0x0020
+
+//
+// Command Reject Status SSB #defines and structure
+//
+// IBM Eisa Spec, Pages 25-26.
+//
+typedef struct _SSB_CMD_REJECT_STATUS {
+
+ //
+ // Command code, will be SSB_CMD_COMMAND_REJECT_STATUS
+ //
+ USHORT Command;
+
+ //
+ // Reason for rejection, as defined below.
+ //
+ USHORT Reason;
+
+ //
+ // Command that was rejected.
+ //
+ USHORT SCBCommand;
+
+ //
+ // Not used.
+ //
+ USHORT Reserved;
+
+} SSB_CMD_REJECT_STATUS, *PSSB_CMD_REJECT_STATUS;
+
+#define SSB_CMD_COMMAND_REJECT_STATUS 0x0200
+
+#define CMD_REJECT_STATUS_BAD_CMD 0x0080
+#define CMD_REJECT_STATUS_BAD_ADDR 0x0040
+#define CMD_REJECT_STATUS_BAD_OPEN 0x0020
+#define CMD_REJECT_STATUS_BAD_CLOSED 0x0010
+#define CMD_REJECT_STATUS_BAD_SAME 0x0008
+
+//
+// Adapter Check Port information, structure and defines
+//
+// IBM Eisa Spec, Pages 28-31.
+//
+
+//
+// Offsets within the adapter memory where the values for the check can
+// be obtained.
+//
+// IBM Spec, Page 18.
+//
+#define ADAPTER_CHECK_PORT_OFFSET_BASE 0x05E0
+#define ADAPTER_CHECK_PORT_OFFSET_PARM0 0x05E2
+#define ADAPTER_CHECK_PORT_OFFSET_PARM1 0x05E4
+#define ADAPTER_CHECK_PORT_OFFSET_PARM2 0x05E6
+
+//
+// Structure that can be used to gather all of the adapter check information.
+//
+typedef struct _ADAPTER_CHECK {
+
+ //
+ // USHORT indicating why the adapter check occurred. Reasons are defined
+ // below.
+ //
+ USHORT Check;
+
+ //
+ // The parameters are used based on the reason above. Please see the spec
+ // as to what the different parameters are for the given reason.
+ //
+ USHORT Parm0;
+ USHORT Parm1;
+ USHORT Parm2;
+
+} ADAPTER_CHECK, *PADAPTER_CHECK;
+
+#define ADAPTER_CHECK_DMA_ABORT_READ 0x4000
+#define ADAPTER_CHECK_DMA_ABORT_WRITE 0x2000
+#define ADAPTER_CHECK_ILLEGAL_OPCODE 0x1000
+#define ADAPTER_CHECK_PARITY_ERR 0x0800
+#define ADAPTER_CHECK_PARITY_ERR_EXT 0x0400
+#define ADAPTER_CHECK_PARITY_ERR_SIM 0x0200 // System Interface Master
+#define ADAPTER_CHECK_PARITY_ERR_PHM 0x0100 // Protocol Handler Master
+#define ADAPTER_CHECK_PARITY_ERR_RR 0x0080 // Ring Receive
+#define ADAPTER_CHECK_PARITY_ERR_RXMT 0x0040 // Ring Transmit
+#define ADAPTER_CHECK_RING_UNDERRUN 0x0020
+#define ADAPTER_CHECK_RING_OVERRUN 0x0010
+#define ADAPTER_CHECK_INVALID_INT 0x0008
+#define ADAPTER_CHECK_INVALID_ERR_INT 0x0004
+#define ADAPTER_CHECK_INVALID_XOP 0x0002
+#define ADAPTER_CHECK_PROGRAM_CHECK 0x0001
+
+//
+// Initialization Structure.
+//
+// IBM Eisa Spec, Pages 33-40.
+//
+
+//
+// This structure needs to be packed on a two-byte boundary or the
+// SCB pointer will be off during the loop that sends the initialization
+// bytes to the card.
+//
+
+typedef struct _ADAPTER_INITIALIZATION {
+
+ //
+ // Initialization options as defined below
+ //
+ USHORT Options;
+
+ //
+ // Reserved USHORTs
+ //
+ USHORT Reserved1;
+ USHORT Reserved2;
+ USHORT Reserved3;
+
+ //
+ // Size of DMA bursts on receives
+ //
+ USHORT ReceiveBurstSize;
+
+ //
+ // Size of DMA bursts on transmits
+ //
+ USHORT TransmitBurstSize;
+
+ //
+ // Number of retries on DMA errors before giving up
+ //
+ USHORT DMAAbortThresholds;
+
+ //
+ // Pointer to the DMA Test area, used by the adapter as a scratch area
+ // during init.
+ //
+ USHORT DMATestAddressHigh;
+ USHORT DMATestAddressLow;
+
+} ADAPTER_INITIALIZATION, *PADAPTER_INITIALIZATION;
+
+//
+// Initialization options
+//
+#define INIT_OPTIONS_RESERVED 0x8000
+#define INIT_OPTIONS_RECEIVE_BURST 0x0200
+#define INIT_OPTIONS_RECEIVE_CYCLE 0x0000
+#define INIT_OPTIONS_XMIT_BURST 0x0100
+#define INIT_OPTIONS_XMIT_CYCLE 0x0000
+#define INIT_OPTIONS_SPEED_16 0x0040
+#define INIT_OPTIONS_SPEED_4 0x0000
+#define INIT_OPTIONS_DISABLE_ETR 0x0020
+#define INIT_OPTIONS_ENABLE_ETR 0x0000
+
+//
+// Starting address on card of where to write the init block
+//
+// IBM Eisa Spec, Page 37.
+//
+#define INIT_ADAPTER_PORT_OFFSET 0x0200
+
+//
+// Value to write to the command register after the init block has been
+// downloaded.
+//
+#define INIT_ADAPTER_INTERRUPT 0x9080
+
+//
+// Bit masks for initialization results.
+//
+// IBM Eisa Spec, Page 37.
+//
+#define STATUS_INIT_INITIALIZE 0x0040
+#define STATUS_INIT_TEST 0x0020
+#define STATUS_INIT_ERROR 0x0010
+
+//
+// Bring-Up Error Codes
+//
+// IBM Eisa Spec, Pages 37-40.
+//
+#define BRING_UP_ERR_INIT_TEST 0x0000
+#define BRING_UP_ERR_CRC 0x0001
+#define BRING_UP_ERR_RAM 0x0002
+#define BRING_UP_ERR_INSTRUCTION_TEST 0x0003
+#define BRING_UP_ERR_INT_TEST 0x0004
+#define BRING_UP_ERR_PROTOCOL_HANDLER 0x0005
+#define BRING_UP_ERR_SYSTEM_INTERFACE_REG 0x0006
+
+//
+// Initialize Error Codes
+//
+// IBM Eisa Spec, Pages 37-40.
+//
+#define INITIALIZE_ERR_PARM_LEN 0x0001
+#define INITIALIZE_ERR_INV_OPTIONS 0x0002
+#define INITIALIZE_ERR_INV_RCV_BURST 0x0003
+#define INITIALIZE_ERR_INV_XMIT_BURST 0x0004
+#define INITIALIZE_ERR_INV_DMA_ABORT 0x0005
+#define INITIALIZE_ERR_INV_DMA 0x0006
+#define INITIALIZE_ERR_IO_PARITY 0x0008
+#define INITIALIZE_ERR_DMA_TIMEOUT 0x0009
+#define INITIALIZE_ERR_DMA_PARITY 0x000A
+#define INITIALIZE_ERR_DMA_BUS 0x000B
+#define INITIALIZE_ERR_DMA_DATA 0x000C
+#define INITIALIZE_ERR_ADAPTER_CHECK 0x000D
+
+//
+// TOK162 ErrorLog structure.
+//
+// IBM Eisa Spec, Page 65.
+//
+typedef struct _TOK162_ERRORLOG {
+
+ //
+ // These are error count fields. The adapter resets the internal
+ // counters after they are read into this structure.
+ //
+ UCHAR LineError;
+ UCHAR InternalError;
+ UCHAR BurstError;
+ UCHAR ARIFCIError;
+ UCHAR AbortDelimeter;
+ UCHAR Reserved1;
+ UCHAR LostFrameError;
+ UCHAR ReceiveCongestionError;
+ UCHAR FrameCopiedError;
+ UCHAR Reserved2;
+ UCHAR TokenError;
+ UCHAR Reserved3;
+ UCHAR DMABusError;
+ UCHAR Reserved4;
+
+} TOK162_ERRORLOG, *PTOK162_ERRORLOG;
+
+//
+// TOK162 Read Adapter Log structure. Used to get permanent address, current
+// addresses (network, group, functional), the microcode level, and the MAC
+// buffer.
+//
+// IBM Eisa Spec, Pages 66-69.
+//
+typedef struct _TOK162_READADAPTERBUF {
+
+ //
+ // Number of bytes to be read from the adapter
+ //
+ USHORT DataCount;
+
+ //
+ // Offset for buffer
+ //
+ USHORT DataAddress;
+
+ //
+ // Buffer space
+ //
+ UCHAR BufferSpace[68-6];
+
+} TOK162_READADAPTERBUF, *PTOK162_READADAPTERBUF;
+
+//
+// TOK162 Receive List
+//
+// IBM Eisa Spec, Pages 57-59.
+//
+typedef struct _TOK162_RECEIVE_LIST {
+
+ //
+ // This is the total size of the received frame.
+ //
+ USHORT FrameSize;
+
+ //
+ // List entry characteristics
+ //
+ USHORT CSTAT;
+
+} TOK162_RECEIVE_LIST, *PTOK162_RECEIVE_LIST;
+
+//
+// Receive and Transmit buffer sizes, depending on the ring speed.
+//
+// IBM Eisa Spec, Pages 6-7.
+//
+#define RECEIVE_LIST_BUFFER_SIZE_4 4500
+#define RECEIVE_LIST_BUFFER_SIZE_16 17986
+
+//
+// Receive CSTAT bit masks
+//
+// IBM Spec, Pages 38-39.
+//
+#define RECEIVE_CSTAT_REQUEST_RESET 0x8800 // Valid bit + frame int
+#define RECEIVE_CSTAT_VALID 0x8000 // Valid bit
+
+//
+// Transmit list entry. This is exactly like the receive list entry.
+//
+// IBM Eisa Spec, Pages 50-51.
+//
+typedef struct _TOK162_TRANSMIT_LIST {
+
+ //
+ // This is the total size of the transmit frame.
+ //
+ USHORT FrameSize;
+
+ //
+ // This is the address of the buffer associated. IBM Format.
+ //
+ ULONG PhysicalAddress;
+
+ //
+ // List entry characteristics
+ //
+ USHORT CSTAT;
+
+} TOK162_TRANSMIT_LIST, *PTOK162_TRANSMIT_LIST;
+
+//
+// Number of transmit array entries on adapter
+//
+#define TRANSMIT_ENTRIES 15
+
+//
+// Transmit CSTAT bit masks
+//
+#define TRANSMIT_CSTAT_REQUEST 0xB800 // valid,sof,eof,fint
+#define TRANSMIT_CSTAT_XMIT_ERROR 0x0400 // error bit
+#define TRANSMIT_CSTAT_FI 0x0800 // frame interrupt
+#define TRANSMIT_CSTAT_SOF 0x2000 // start of frame
+#define TRANSMIT_CSTAT_EOF 0x1000 // end of frame
+#define TRANSMIT_CSTAT_VALID 0x8000 // valid
+#define TRANSMIT_CSTAT_FRAME_COMPLETE 0x4000 // complete
+//
+// Communication Area Offsets
+//
+#define COMMUNICATION_SCB_OFFSET 0x0000
+#define COMMUNICATION_SSB_OFFSET 0x0008
+#define COMMUNICATION_RCV_OFFSET 0x0010
+#define COMMUNICATION_XMT_OFFSET 0x0010 + RECEIVE_LIST_COUNT * 8
+
+//
+// TOK162 Command Block. Contains all of the fields necessary to support
+// both commands and transmits.
+//
+typedef struct _TOK162_COMMAND_BLOCK {
+
+ //
+ // This is the state of this Command Block.
+ //
+ USHORT State;
+
+ //
+ // This is the status of this Command Block.
+ //
+ USHORT Status;
+
+ //
+ // This is the physical address of the next Command Block
+ // to be executed. If this address == -1, then there are
+ // no more commands to be executed.
+ //
+ UNALIGNED TOK162_PHYSICAL_ADDRESS NextPending;
+
+ //
+ // This is the TOK162 Command Code.
+ //
+ USHORT CommandCode;
+
+ //
+ // Pointer used by different commands
+ //
+ ULONG ParmPointer;
+
+ //
+ // This is the immediate data to be used by all commands
+ // other than transmit.
+ //
+ ULONG ImmediateData;
+
+} TOK162_COMMAND_BLOCK, *PTOK162_COMMAND_BLOCK;
+
+//
+// command and result structures
+//
+
+//
+// Open command structure. Submitted to the card to insert the system in
+// the Token Ring.
+//
+// IBM Eisa Spec, Pages 42-48.
+//
+typedef struct _OPEN_COMMAND {
+
+ //
+ // Open options. Defined below.
+ //
+ USHORT Options;
+
+ //
+ // Address to insert ourselves into the ring under.
+ //
+ UCHAR NodeAddress[6];
+
+ //
+ // Group address adapter should respond to.
+ //
+ ULONG GroupAddress;
+
+ //
+ // Functional address adapter should respond to.
+ //
+ ULONG FunctionalAddress;
+
+ //
+ // Number of receive lists
+ //
+ USHORT ReceiveListCount;
+
+ //
+ // Number of transmit lists.
+ //
+ USHORT TransmitListCount;
+
+ //
+ // Adapter buffer size.
+ //
+ USHORT BufferSize;
+
+ //
+ // Unused.
+ //
+ USHORT Reserved1;
+ USHORT Reserved2;
+
+ //
+ // Minimum number of buffers to reserve for transmits
+ //
+ UCHAR TransmitBufCountMin;
+
+ //
+ // Maximum number of buffers to reserve for transmits
+ //
+ UCHAR TransmitBufCountMax;
+
+ //
+ // Pointer to the system product ID
+ //
+ ULONG ProdIDAddress;
+
+} OPEN_COMMAND, *POPEN_COMMAND;
+
+#define OPEN_OPTION_PASS_BEACON_FRAMES 0x0080
+#define OPEN_OPTION_DISABLE_DMA_TIMEOUT 0x0040
+#define OPEN_OPTION_ENABLE_DMA_TIMEOUT 0x0000
+#define OPEN_OPTION_WRAP_INTERFACE 0x8000
+#define OPEN_OPTION_DISABLE_HARD_ERROR 0x4000
+#define OPEN_OPTION_ENABLE_HARD_ERROR 0x0000
+#define OPEN_OPTION_DISABLE_SOFT_ERROR 0x2000
+#define OPEN_OPTION_ENABLE_SOFT_ERROR 0x0000
+#define OPEN_OPTION_PASS_ADAPTER_FRAMES 0x1000
+#define OPEN_OPTION_PASS_ATTENTION_FRAMES 0x0800
+#define OPEN_OPTION_PAD_ROUTING_FIELD 0x0400
+#define OPEN_OPTION_FRAME_HOLD 0x0200
+#define OPEN_OPTION_CONTENDER 0x0100
+
+//
+// Values to set the open parameters to
+//
+#define OPEN_BUFFER_SIZE 1024
+
+//
+// Open completion structure (SSB)
+//
+// IBM Eisa Spec, Pages 46-48.
+//
+typedef struct _OPEN_COMPLETION {
+
+ //
+ // Better be CMD_DMA_OPEN.
+ //
+ USHORT Command;
+
+ //
+ // Completion code. Bitmasks defined below.
+ //
+ USHORT Completion;
+
+ //
+ // Not used.
+ //
+ USHORT Reserved1;
+ USHORT Reserved2;
+
+} OPEN_COMPLETION, *POPEN_COMPLETION;
+
+#define OPEN_COMPLETION_MASK_PHASE 0x00F0
+#define OPEN_COMPLETION_MASK_ERROR 0x000F
+#define OPEN_COMPLETION_MASK_RESULT 0xFF00
+
+#define OPEN_COMPLETION_PHASE_LOBE 0x0010
+#define OPEN_COMPLETION_PHASE_INSERTION 0x0020
+#define OPEN_COMPLETION_PHASE_VERIFY 0x0030
+#define OPEN_COMPLETION_PHASE_RING 0x0040
+#define OPEN_COMPLETION_PHASE_PARMS 0x0050
+
+#define OPEN_COMPLETION_ERROR_FUNCTION 0x0001
+#define OPEN_COMPLETION_ERROR_SIGLOSS 0x0002
+#define OPEN_COMPLETION_ERROR_TIMEOUT 0x0005
+#define OPEN_COMPLETION_ERROR_RINGFAIL 0x0006
+#define OPEN_COMPLETION_ERROR_RINGBEACON 0x0007
+#define OPEN_COMPLETION_ERROR_DUPLICATE 0x0008
+#define OPEN_COMPLETION_ERROR_REQPARMS 0x0009
+#define OPEN_COMPLETION_ERROR_REMOVE_REC 0x000A
+#define OPEN_COMPLETION_ERROR_IMPL_REC 0x000B
+#define OPEN_COMPLETION_ERROR_DUPMOD 0x000C
+
+#define OPEN_RESULT_ADAPTER_OPEN 0x8000
+#define OPEN_RESULT_NODE_ADDR_ERROR 0x4000
+#define OPEN_RESULT_LIST_SIZE_ERROR 0x2000
+#define OPEN_RESULT_BUF_SIZE_ERROR 0x1000
+#define OPEN_RESULT_EXT_RAM_ERROR 0x0800
+#define OPEN_RESULT_XMIT_CNT_ERROR 0x0400
+#define OPEN_RESULT_OPEN_ERROR 0x0200
+
+//
+// TOK162 Address Block
+//
+// IBM Spec, Page 33.
+//
+typedef struct _TOK162_ADDRESSBLOCK {
+
+ //
+ // The node address. Used for both the current address and the permanent
+ // address (depending on the read call).
+ //
+ UCHAR NodeAddress[6];
+
+ //
+ // The current group address.
+ //
+ UCHAR GroupAddress[4];
+
+ //
+ // The current functional address.
+ //
+ UCHAR FunctionalAddress[4];
+
+} TOK162_ADDRESSBLOCK, *PTOK162_ADDRESSBLOCK;
+
+//
+// The adapter requires many of the WORD values and almost all of the
+// DWORD values to be in IBM format, versus Intel Format. The difference
+// between the two is as follows:
+//
+// If you are storing the value 0x1234, a word value, memory would look like:
+//
+// --------- ---------
+// | | | |
+// Intel | 34 | | 12 |
+// | | | |
+// --------- ---------
+// Address 100 101
+//
+//
+// --------- ---------
+// | | | |
+// IBM | 12 | | 34 |
+// | | | |
+// --------- ---------
+// Address 100 101
+//
+//
+// If you are storing the value 0x12345678, a dword value, memory would look
+// like:
+//
+// --------- --------- --------- ---------
+// | | | | | | | |
+// Intel | 78 | | 56 | | 34 | | 12 |
+// | | | | | | | |
+// --------- --------- --------- ---------
+// Address 100 101
+//
+//
+// --------- --------- --------- ---------
+// | | | | | | | |
+// IBM | 12 | | 34 | | 56 | | 78 |
+// | | | | | | | |
+// --------- --------- --------- ---------
+// Address 100 101
+//
+//
+// To convert "Intel" WORDs and DWORDs to "IBM" format, the following macros
+// are used.
+//
+
+//
+// Macro to byte swap a word.
+//
+#define BYTE_SWAP(_word) (\
+ (USHORT) (((_word) >> 8) | ((_word) << 8)) )
+
+//
+// Macro to byte swap a word.
+//
+#define WORD_SWAP(_dword) (\
+ (ULONG) (((_dword) >> 16) | ((_dword) << 16)) )
+
+//
+// Macro to get low byte of a word.
+//
+#define LOW_BYTE(_word) (\
+ (UCHAR) ((_word) & 0x00FF) )
+
+//
+// Macro to get high byte of a word.
+//
+#define HIGH_BYTE(_word) (\
+ (UCHAR) (((_word) >> 8) & 0x00FF) )
+
+//
+// Macro to get low word of a dword.
+//
+#define LOW_WORD(_dword) (\
+ (USHORT) ((_dword) & 0x0000FFFF) )
+
+//
+// Macro to get high word of a dword.
+//
+#define HIGH_WORD(_dword) (\
+ (USHORT) (((_dword) >> 16) & 0x0000FFFF) )
+
+//
+// Macro to create a dword from two words.
+//
+#define MAKE_LONG(_highword,_lowword) (\
+ (ULONG) ((((ULONG)_highword) << 16) + _lowword))
+
+//
+// Macro to byte swap a dword.
+//
+#define BYTE_SWAP_ULONG(_ulong) (\
+ (ULONG)((ULONG)(BYTE_SWAP(LOW_WORD(_ulong)) << 16) + \
+ BYTE_SWAP(HIGH_WORD(_ulong))))
+
+//
+// End the packing
+//
+#include <poppack.h>
diff --git a/private/ntos/ndis/ibmtok2e/tok162pr.h b/private/ntos/ndis/ibmtok2e/tok162pr.h
new file mode 100644
index 000000000..2bb3066a2
--- /dev/null
+++ b/private/ntos/ndis/ibmtok2e/tok162pr.h
@@ -0,0 +1,314 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ tok162pr.h
+
+Abstract:
+
+ The procedure declarations for the IBM Token-Ring 16/4 II
+ ISA driver.
+
+Author:
+
+ Kevin Martin (kevinma) 1-Feb-1994
+
+Environment:
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+
+--*/
+
+#ifndef _TOK162PROC_
+#define _TOK162PROC_
+
+//
+// We define the external interfaces to the TOK162 driver.
+// These routines are only external to permit separate
+// compilation. Given a truely fast compiler they could
+// all reside in a single file and be static.
+//
+
+extern
+VOID
+TOK162DisableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+extern
+VOID
+TOK162EnableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+extern
+VOID
+TOK162Halt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+extern
+VOID
+TOK162Shutdown(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+extern
+VOID
+TOK162HandleInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+extern
+BOOLEAN
+TOK162InitialInit(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+extern
+NDIS_STATUS
+TOK162Initialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ );
+
+extern
+NDIS_STATUS
+TOK162QueryInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+ );
+
+extern
+NDIS_STATUS
+TOK162SetInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ );
+
+extern
+VOID
+TOK162Isr(
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueDpc,
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+extern
+NDIS_STATUS
+TOK162Reset(
+ OUT PBOOLEAN AddressingReset,
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+extern
+NDIS_STATUS
+TOK162TransferData(
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+ );
+
+extern
+NDIS_STATUS
+TOK162Send(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET Packet,
+ IN UINT Flags
+ );
+
+VOID
+TOK162FinishQueryInformation(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+extern
+NDIS_STATUS
+TOK162RegisterAdapter(
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PUCHAR CurrentAddress,
+ IN UINT PortAddress,
+ IN UINT InterruptLevel,
+ IN ULONG MaxFrameSize
+ );
+
+extern
+VOID
+TOK162AcquireCommandBlock(
+ IN PTOK162_ADAPTER Adapter,
+ OUT PTOK162_SUPER_COMMAND_BLOCK * CommandBlock
+ );
+
+extern
+BOOLEAN
+TOK162AcquireTransmitBlock(
+ IN PTOK162_ADAPTER Adapter,
+ OUT PTOK162_SUPER_COMMAND_BLOCK * CommandBlock
+ );
+
+extern
+VOID
+TOK162RelinquishCommandBlock(
+ IN PTOK162_ADAPTER Adapter,
+ IN PTOK162_SUPER_COMMAND_BLOCK CommandBlock
+ );
+
+extern
+VOID
+TOK162SubmitCommandBlock(
+ IN PTOK162_ADAPTER Adapter,
+ IN PTOK162_SUPER_COMMAND_BLOCK CommandBlock
+ );
+
+extern
+VOID
+TOK162DoAdapterReset(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+extern
+NDIS_STATUS
+TOK162SetupForReset(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+BOOLEAN
+TOK162CheckForHang(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+VOID
+TOK162ResetVariables(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+VOID
+TOK162ResetHandler(
+ IN PVOID SystemSpecific1,
+ IN PTOK162_ADAPTER Adapter,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+VOID
+TOK162DeferredTimer(
+ IN PVOID SystemSpecific1,
+ IN PTOK162_ADAPTER Adapter,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+extern
+NDIS_STATUS
+TOK162GetAdapterConfiguration(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+extern
+VOID
+TOK162ResetAdapter(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+BOOLEAN
+DoTheOpen(
+ PTOK162_ADAPTER Adapter
+ );
+
+BOOLEAN
+DoTheReceive(
+ PTOK162_ADAPTER Adapter
+ );
+
+extern
+NDIS_STATUS
+TOK162ChangeFuncGroup(
+ IN PTOK162_ADAPTER Adapter
+);
+
+
+BOOLEAN
+TOK162InitializeTransmitQueue(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+VOID
+TOK162ResetTimer(
+ IN PVOID SystemSpecific1,
+ IN PTOK162_ADAPTER Adapter,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+VOID
+TOK162DoResetIndications(
+ IN PTOK162_ADAPTER Adapter,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+TOK162ProcessTransmitInterrupts(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+extern
+BOOLEAN
+TOK162ProcessRingInterrupts(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+extern
+VOID
+TOK162DeleteAdapterMemory(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+void
+TOK162DownLoadScb(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+void
+TOK162UpLoadSsb(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+void
+TOK162DownLoadReceiveList(
+ IN PTOK162_ADAPTER Adapter,
+ IN PTOK162_SUPER_RECEIVE_LIST RcvList
+ );
+
+void
+TOK162UpLoadReceiveList(
+ IN PTOK162_ADAPTER Adapter,
+ OUT PTOK162_SUPER_RECEIVE_LIST RcvList
+ );
+
+#endif //_TOK162PROC_
diff --git a/private/ntos/ndis/ibmtok2e/tok162sw.h b/private/ntos/ndis/ibmtok2e/tok162sw.h
new file mode 100644
index 000000000..280edb786
--- /dev/null
+++ b/private/ntos/ndis/ibmtok2e/tok162sw.h
@@ -0,0 +1,738 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ tok162sw.h
+
+Abstract:
+
+ The hardware-related definitions for the IBM Token-Ring 16/4 II
+ ISA driver.
+
+Author:
+
+ Kevin Martin (kevinma) 1-Feb-1994
+
+Environment:
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+#include <tok162hw.h>
+
+//
+// Debugging flags.
+//
+#if DBG
+
+//
+// Degrees of debugging output. Can be OR'd in any combination.
+//
+#define TOK162_DEBUG_LOUD 0x1
+#define TOK162_DEBUG_VERY_LOUD 0x2
+#define TOK162_DEBUG_EXTRA_LOUD 0x4
+#define TOK162_DEBUG_CURRENT 0x8
+
+//
+// The degree of debugging output being displayed on the debugger currently.
+// Defined in TOK162.C.
+//
+extern UCHAR Tok162Debug;
+
+//
+// Macros that decide on the debugging based on Tok162Debug.
+//
+#define LOUD_DEBUG(A) if (Tok162Debug & TOK162_DEBUG_LOUD) { A ; }
+#define VERY_LOUD_DEBUG(A) if (Tok162Debug & TOK162_DEBUG_VERY_LOUD) { A ; }
+#define EXTRA_LOUD_DEBUG(A) if (Tok162Debug & TOK162_DEBUG_EXTRA_LOUD) { A ; }
+#define CURRENT_DEBUG(A) if (Tok162Debug & TOK162_DEBUG_CURRENT) { A ; }
+
+//
+// The size of the logging array
+//
+#define LOG_SIZE 256
+
+//
+// Pointer for the logging array. Allocated in TOK162.C
+// (AllocateAdapterMemory)
+//
+extern PUCHAR Tok162Log;
+
+//
+// The current index into the logging array.
+//
+extern USHORT Tok162LogPlace;
+
+//
+// Logging macro.
+//
+#define IF_LOG(ch) { Tok162Log[Tok162LogPlace] = (ch); \
+ Tok162LogPlace = (Tok162LogPlace + 1) % LOG_SIZE; }
+
+#else // if dbg
+
+//
+// Make sure all of the debugging and logging calls resolve to NULL
+//
+#define LOUD_DEBUG(A)
+#define VERY_LOUD_DEBUG(A)
+#define EXTRA_LOUD_DEBUG(A)
+#define CURRENT_DEBUG(A)
+
+#define IF_LOG(ch) { }
+
+#endif // if dbg
+
+//
+// Version constants for this driver
+//
+#define TOK162_NDIS_MAJOR_VERSION 3
+#define TOK162_NDIS_MINOR_VERSION 0
+
+//
+// Macro to allocate physical memory.
+//
+#define TOK162_ALLOC_PHYS(_Status, _pBuffer, _Length) \
+{ \
+ NDIS_PHYSICAL_ADDRESS MinusOne = NDIS_PHYSICAL_ADDRESS_CONST (-1, -1); \
+ *(_Status) = NdisAllocateMemory( \
+ (PVOID*)(_pBuffer), \
+ (_Length), \
+ 0, \
+ MinusOne); \
+}
+
+//
+// Macro to free physical memory previously allocated.
+//
+#define TOK162_FREE_PHYS(_Buffer) NdisFreeMemory((_Buffer), 0, 0)
+
+//
+// Enumeration for the reset stages.
+//
+enum ResetStates{InitialInit,
+ CheckReset,
+ CheckResetRetry,
+ DoTheInit,
+ CheckInit,
+ CheckInitRetry,
+ DoOpen
+ };
+
+//
+// Adapter structure is defined further down.
+//
+struct _TOK162_ADAPTER;
+
+//
+// This structure defines the global data needed by the driver.
+//
+typedef struct _TOK162_GLOBAL_DATA {
+
+ //
+ // Spinlock to protect fields in this structure.
+ //
+ NDIS_SPIN_LOCK Lock;
+
+ //
+ // Chain of Adapters
+ //
+ LIST_ENTRY AdapterList;
+
+ //
+ // Handle to our Mac
+ //
+ NDIS_HANDLE TOK162MacHandle;
+
+ //
+ // Handle for NdisTerminateWrapper
+ //
+ NDIS_HANDLE TOK162NdisWrapperHandle;
+
+ //
+ // Driver object
+ //
+ PDRIVER_OBJECT TOK162DriverObject;
+
+} TOK162_GLOBAL_DATA, *PTOK162_GLOBAL_DATA;
+
+//
+// In addition to the Command Block fields which the TOK162HW.H
+// defines, we need some additional fields for our own purposes.
+// To ensure that these fields are properly aligned (and to
+// ensure that the actual Command Block is properly aligned)
+// we'll defined a Super Command Block. This structure will
+// contain a "normal" TOK162 Command Block plus some additional
+// fields. This structure is used for both commands and transmits.
+//
+typedef struct _TOK162_SUPER_COMMAND_BLOCK {
+
+ //
+ // The actual TOK162 Command Block.
+ //
+ TOK162_COMMAND_BLOCK Hardware;
+
+ //
+ // This contains the virtual address of the next pending command.
+ //
+ struct _TOK162_SUPER_COMMAND_BLOCK *NextCommand;
+
+ //
+ // Is this from a set
+ //
+ BOOLEAN Set;
+
+ //
+ // If this is a public (adapter-wide) command block, then
+ // this will contain this block's index into the adapter's
+ // command queue.
+ //
+ USHORT CommandBlockIndex;
+
+ //
+ // This field is used to timestamp the command blocks
+ // as they are placed into the command queue. If a
+ // block fails to execute, the adapter will get a kick in the ass to
+ // start it up again.
+ //
+ BOOLEAN Timeout;
+
+ //
+ // Count of the number of times we have retried a command.
+ //
+ UCHAR TimeoutCount;
+
+} TOK162_SUPER_COMMAND_BLOCK, *PTOK162_SUPER_COMMAND_BLOCK;
+
+//
+// In addition to the Receive Entry fields which the TOK162HW.H
+// defines, we need some additional fields for our own purposes.
+// To ensure that these fields are properly aligned (and to
+// ensure that the actual Receive Entry is properly aligned)
+// we'll defined a Super Receive Entry. This structure will
+// contain a "normal" TOK162 Receive Entry plus some additional
+// fields.
+//
+typedef struct _TOK162_SUPER_RECEIVE_LIST {
+
+ //
+ // The actual TOK162 Receive List.
+ //
+ TOK162_RECEIVE_LIST Hardware;
+
+ //
+ // This contains the virtual address of this Receive List's
+ // frame buffer.
+ //
+ PVOID ReceiveBuffer;
+ NDIS_PHYSICAL_ADDRESS ReceiveBufferPhysical;
+
+ //
+ // This contains the virtual address of the next
+ // Receive List in the Receive Queue.
+ //
+ struct _TOK162_SUPER_RECEIVE_LIST *NextEntry;
+
+ //
+ // Points to an Mdl which points to this buffer
+ //
+ PNDIS_BUFFER FlushBuffer;
+
+ //
+ // Offset in adapter for this receive list
+ //
+ USHORT AdapterOffset;
+
+} TOK162_SUPER_RECEIVE_LIST, *PTOK162_SUPER_RECEIVE_LIST;
+
+//
+// The number of receive lists/buffers
+//
+#define RECEIVE_LIST_COUNT 3
+
+//
+// In addition to the Transmit Entry fields which the TOK162HW.H
+// defines, we need some additional fields for our own purposes.
+// To ensure that these fields are properly aligned (and to
+// ensure that the actual Transmit Entry is properly aligned)
+// we'll defined a Super Transmit Entry. This structure will
+// contain a "normal" TOK162 Transmit Entry plus some additional
+// fields.
+//
+typedef struct _TOK162_SUPER_TRANSMIT_LIST {
+
+ //
+ // The actual TOK162 Receive List.
+ //
+ TOK162_TRANSMIT_LIST Hardware;
+
+ //
+ // This contains the virtual address of this Transmit List's
+ // frame buffer.
+ //
+ PVOID TransmitBuffer;
+ NDIS_PHYSICAL_ADDRESS TransmitBufferPhysical;
+
+ //
+ // This contains the virtual address of the next
+ // Transmit List in the Transmit Queue.
+ //
+ struct _TOK162_SUPER_TRANSMIT_LIST *NextEntry;
+
+ //
+ // This contains the virtual address of the next
+ // active Transmit List in the active Transmit Queue.
+ //
+ struct _TOK162_SUPER_TRANSMIT_LIST *NextActive;
+
+ //
+ // Packet associated with this list
+ //
+ PNDIS_PACKET Packet;
+
+ //
+ // Timeout watch
+ //
+ BOOLEAN Timeout;
+
+ //
+ // Count of the number of times we have retried a command.
+ //
+ UCHAR TimeoutCount;
+
+ //
+ // First adapter entry on board.
+ //
+ USHORT FirstEntry;
+
+ //
+ // Number of NDIS Buffers.
+ //
+ UINT NumberOfBuffers;
+
+ //
+ // Number of Map Registers Used
+ //
+ UINT NumberOfMapRegisters;
+
+ //
+ // Boolean indicating whether the above buffer was used
+ //
+ BOOLEAN UsedBuffer;
+
+ //
+ // flush buffer
+ //
+ PNDIS_BUFFER FlushBuffer;
+
+} TOK162_SUPER_TRANSMIT_LIST, *PTOK162_SUPER_TRANSMIT_LIST;
+
+//
+// The number of transmit lists and the number of adapter entries we
+// reserve for transmits. The product of these numbers must be equal
+// to TRANSMIT_ENTRIES as defined in tok162hw.h.
+//
+#define TRANSMIT_LIST_COUNT 3
+#define MAX_BUFFERS_PER_TRANSMIT 5
+
+//
+// Adapter Structure
+//
+typedef struct _TOK162_ADAPTER {
+
+ //
+ // Handle given by NDIS when the miniport was initialized.
+ //
+ NDIS_HANDLE MiniportAdapterHandle;
+
+ //
+ // Interrupt pointers and variables for the adapter
+ //
+ NDIS_MINIPORT_INTERRUPT Interrupt;
+ USHORT InterruptLevel;
+
+ //
+ // Are we running at 16Mbps?
+ //
+ BOOLEAN Running16Mbps;
+
+ //
+ // Pointers for the System Command Block for the adapter
+ //
+ PSCB Scb;
+ NDIS_PHYSICAL_ADDRESS ScbPhysical;
+
+ //
+ // Pointers for the System Status Block for the adapter
+ //
+ PSSB Ssb;
+ NDIS_PHYSICAL_ADDRESS SsbPhysical;
+
+ //
+ // Offset in adapter memory of the communication block
+ //
+ USHORT CommunicationOffset;
+
+ //
+ // Command queue and related variables
+ //
+ PTOK162_SUPER_COMMAND_BLOCK CommandQueue;
+ NDIS_PHYSICAL_ADDRESS CommandQueuePhysical;
+
+ //
+ // Index to next command block
+ //
+ UINT NextCommandBlock;
+
+ //
+ // Number of command blocks available for use
+ //
+ UINT NumberOfAvailableCommandBlocks;
+
+ //
+ // Active command.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK CommandOnCard;
+
+ //
+ // First pending command.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK WaitingCommandHead;
+
+ //
+ // Last pending command.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK WaitingCommandTail;
+
+ //
+ // Current packet filter on adapter
+ //
+ UINT CurrentPacketFilter;
+
+ //
+ // Is there an outstanding request
+ //
+ BOOLEAN RequestInProgress;
+
+ //
+ // Number of bytes needed and written.
+ //
+ PUINT BytesWritten;
+ PUINT BytesNeeded;
+
+ //
+ // Current Oid processing.
+ //
+ NDIS_OID Oid;
+
+ //
+ // Buffer and length of buffer used for doing query/set info calls.
+ //
+ PVOID InformationBuffer;
+ UINT InformationBufferLength;
+
+ //
+ // Current interrupt value
+ //
+ USHORT InterruptMask;
+
+ //
+ // Command that caused the interrupt
+ //
+ USHORT SsbCommand;
+
+ //
+ // The status variables that are saved as the result of an interrupt
+ //
+ USHORT SsbStatus1;
+ USHORT SsbStatus2;
+ USHORT SsbStatus3;
+
+ //
+ // The I/O Base address of the adapter.
+ //
+ ULONG PortIOBase;
+ PVOID PortIOAddress;
+
+ //
+ // Pointers and variables for the Open block for the adapter
+ //
+ POPEN_COMMAND Open;
+ NDIS_PHYSICAL_ADDRESS OpenPhysical;
+
+ //
+ // The network address for the adapter and the current one being used.
+ //
+ CHAR NetworkAddress[TOK162_LENGTH_OF_ADDRESS];
+ CHAR CurrentAddress[TOK162_LENGTH_OF_ADDRESS];
+
+ //
+ // Functional and Group Addresses for the adapter
+ //
+ ULONG FunctionalAddress;
+ ULONG GroupAddress;
+
+ //
+ // Pointer to the Receive Queue.
+ //
+ PTOK162_SUPER_RECEIVE_LIST ReceiveQueue;
+ NDIS_PHYSICAL_ADDRESS ReceiveQueuePhysical;
+
+ //
+ // Pointer to the current receive list
+ //
+ PTOK162_SUPER_RECEIVE_LIST ReceiveQueueCurrent;
+
+ //
+ // Number of frame header bytes in the buffer.
+ //
+ USHORT SizeOfReceivedHeader;
+
+ //
+ // Count of the receive buffers
+ //
+ UINT NumberOfReceiveBuffers;
+
+ //
+ // Size of the receive buffer, based on the ring speed.
+ //
+ USHORT ReceiveBufferSize;
+
+ //
+ // The receive flush buffer pool handle
+ //
+ PNDIS_HANDLE FlushBufferPoolHandle;
+
+ //
+ // Indicator for receive complete
+ //
+ BOOLEAN DoReceiveComplete;
+
+ //
+ // Pointer to the Transmit Queue.
+ //
+ PTOK162_SUPER_TRANSMIT_LIST TransmitQueue;
+ NDIS_PHYSICAL_ADDRESS TransmitQueuePhysical;
+
+ //
+ // Spinlock for transmits
+ //
+ NDIS_SPIN_LOCK TransmitLock;
+
+ //
+ // Pointer to the head of the waiting transmit queue.
+ //
+ PTOK162_SUPER_TRANSMIT_LIST AvailableTransmit;
+
+ //
+ // Pointers for the active transmit queue.
+ //
+ PTOK162_SUPER_TRANSMIT_LIST ActiveTransmitHead;
+ PTOK162_SUPER_TRANSMIT_LIST ActiveTransmitTail;
+
+ //
+ // Array of transmit entries
+ //
+ TOK162_TRANSMIT_LIST DownLoadArray[MAX_BUFFERS_PER_TRANSMIT];
+
+ //
+ // Next available adapter transmit slot
+ //
+ USHORT AdapterTransmitIndex;
+ USHORT TransmitCount;
+
+ //
+ // Count of the transmit blocks
+ //
+ UINT NumberOfAvailableTransmitBlocks;
+
+ //
+ // Flag that when enabled lets routines know that a reset
+ // is in progress.
+ //
+ BOOLEAN ResetInProgress;
+
+ //
+ // Are we doing the initial initialization?
+ //
+ BOOLEAN InitialInit;
+
+ //
+ // Has the initial open completed?
+ //
+ BOOLEAN InitialOpenComplete;
+
+ //
+ // Has the initial receive command been sent
+ //
+ BOOLEAN InitialReceiveSent;
+
+ //
+ // Reset State
+ //
+ USHORT ResetState;
+
+ //
+ // Variables to keep track of the number of retries attempted during
+ // a reset
+ //
+ USHORT ResetRetries;
+ USHORT InitRetries;
+
+ //
+ // Result of Reset command
+ //
+ NDIS_STATUS ResetResult;
+
+ //
+ // Offsets into adapter memory for different structures.
+ // These are obtained at initialization time and the values
+ // are read using the READ.ADAPTER DMA command.
+ //
+ USHORT UniversalAddress;
+ USHORT MicrocodeLevel;
+ USHORT AdapterAddresses;
+ USHORT AdapterParms;
+ USHORT MacBuffer;
+
+ //
+ // Buffer for READ.ERROR.LOG
+ //
+ PTOK162_ERRORLOG ErrorLog;
+ NDIS_PHYSICAL_ADDRESS ErrorLogPhysical;
+
+ //
+ // Buffer for READ.ADAPTER for node addresses. If more info is needed
+ // in the future, this will have to be changed as the current addresses
+ // are being stored here (func,node,group)
+ //
+ PTOK162_READADAPTERBUF AdapterBuf;
+ NDIS_PHYSICAL_ADDRESS AdapterBufPhysical;
+
+ //
+ // Counters to hold the various number of errors/statistics for both
+ // reception and transmission.
+ //
+ UINT ReceiveCongestionError;
+ UINT LineError;
+ UINT LostFrameError;
+ UINT BurstError;
+ UINT FrameCopiedError;
+ UINT TokenError;
+ UINT InternalError;
+ UINT ARIFCIError;
+ UINT AbortDelimeter;
+ UINT DMABusError;
+ ULONG TotalSends;
+ ULONG RegularPackets;
+ ULONG ConstrainPackets;
+
+ //
+ // Packet counts
+ //
+ UINT GoodTransmits;
+ UINT GoodReceives;
+ UINT TransmitsQueued;
+ UINT BadTransmits;
+ UINT BadReceives;
+
+ //
+ // Timer objects for TOK162InterruptHandler and TOK162ResetHandler
+ //
+ NDIS_MINIPORT_TIMER DeferredTimer;
+ NDIS_MINIPORT_TIMER ResetTimer;
+
+ //
+ // Holds number of different types of RING.STATUS.CHANGE
+ // indications.
+ //
+ UINT SignalLoss;
+ UINT HardError;
+ UINT SoftError;
+ UINT TransmitBeacon;
+ UINT LobeWireFault;
+ UINT AutoRemovalError;
+ UINT RemoveReceived;
+ UINT CounterOverflow;
+ UINT SingleStation;
+ UINT RingRecovery;
+
+ //
+ // Current state of the ring.
+ //
+ NDIS_802_5_RING_STATE CurrentRingState;
+
+ //
+ // Pointer to the initialization block
+ //
+ PADAPTER_INITIALIZATION InitializationBlock;
+ NDIS_PHYSICAL_ADDRESS InitializationBlockPhysical;
+
+ //
+ // Pointer to the initialization Dma Test block
+ //
+ PADAPTER_INITIALIZATION DmaTest;
+ NDIS_PHYSICAL_ADDRESS DmaTestPhysical;
+
+ //
+ // This points to the next adapter registered for the same Miniport
+ //
+ LIST_ENTRY AdapterList;
+
+} TOK162_ADAPTER,*PTOK162_ADAPTER;
+
+//
+// Given a MiniportContextHandle return the PTOK162_ADAPTER
+// it represents.
+//
+#define PTOK162_ADAPTER_FROM_CONTEXT_HANDLE(Handle) \
+ ((PTOK162_ADAPTER)(Handle))
+
+//
+// Define our block of global data. The actual data resides in TOK162.C.
+//
+extern TOK162_GLOBAL_DATA TOK162Globals;
+
+//
+// This record type is inserted into the MiniportReserved portion
+// of the packet header when the packet is going through the
+// staged allocation of buffer space prior to the actual send.
+//
+typedef struct _TOK162_RESERVED {
+
+ //
+ // Pointer to next packet. We use this as our queueing mechanism.
+ //
+ PNDIS_PACKET NextEntry;
+
+ //
+ // Reserved section of this structure.
+ //
+ UCHAR BufferIndex;
+ UCHAR FirstEntry;
+ UCHAR NumberBuffers;
+ UCHAR Reserved;
+
+
+} TOK162_RESERVED,*PTOK162_RESERVED;
+
+//
+// This macro will return a pointer to the TOK162 reserved portion
+// of a packet given a pointer to a packet.
+//
+#define PTOK162_RESERVED_FROM_PACKET(Packet) \
+ ((PTOK162_RESERVED)((Packet)->MiniportReserved))
+
+#include <tok162pr.h>
diff --git a/private/ntos/ndis/ibmtok2i/command.c b/private/ntos/ndis/ibmtok2i/command.c
new file mode 100644
index 000000000..7b139ed3d
--- /dev/null
+++ b/private/ntos/ndis/ibmtok2i/command.c
@@ -0,0 +1,715 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ command.c
+
+Abstract:
+
+ This file contains the code for managing command and transmit blocks on
+ the TOK162's queues. It is based loosely on the NE3200 driver.
+
+Author:
+
+ Kevin Martin(KevinMa) 04-Jan-1993
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+
+--*/
+
+#include <tok162sw.h>
+
+VOID
+TOK162SendCommandBlock(
+ PTOK162_ADAPTER Adapter,
+ PTOK162_SUPER_COMMAND_BLOCK CommandBlock
+ );
+
+
+VOID
+TOK162SubmitCommandBlock(
+ IN PTOK162_ADAPTER Adapter,
+ IN PTOK162_SUPER_COMMAND_BLOCK CommandBlock
+ )
+
+/*++
+
+Routine Description:
+
+ Submit a complete Command Block for execution by the TOK162.
+
+Arguments:
+
+ Adapter - The adapter that points to the ring entry structures.
+
+ CommandBlock - Holds the pointer to the Command Block to be
+ submitted.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Pointer to the most recently submitted Command Block.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK PreviousCommandBlock;
+
+ // Ensure that our command block is on an even boundary.
+ //
+ ASSERT(!(NdisGetPhysicalAddressLow(CommandBlock->Self) & 1));
+
+ //
+ // Timestamp the command block.
+ //
+ CommandBlock->Timeout = FALSE;
+ CommandBlock->Hardware.State = TOK162_STATE_WAIT_FOR_ADAPTER;
+
+ //
+ // If the adapter is currently executing a command add this to
+ // the end of the waiting list. Otherwise submit this command to the card.
+ //
+ if (Adapter->CommandOnCard != NULL) {
+
+ //
+ // Pend this command
+ //
+ IF_LOG('i');
+
+ PreviousCommandBlock = Adapter->WaitingCommandTail;
+ Adapter->WaitingCommandTail = CommandBlock;
+
+ //
+ // Check if there are any other pendings. If not, we are
+ // the first pending. If there are others, tack this one on
+ // the end.
+ //
+ if (PreviousCommandBlock == NULL) {
+
+ Adapter->WaitingCommandHead = CommandBlock;
+
+ } else {
+
+ PreviousCommandBlock->NextCommand = CommandBlock;
+
+ }
+
+ } else {
+
+ //
+ // Set this command as the active one
+ //
+ Adapter->CommandOnCard = CommandBlock;
+
+ //
+ // Log that we are sending the command to the card
+ //
+ IF_LOG('I');
+
+ //
+ // send the command out to the card
+ //
+ TOK162SendCommandBlock(Adapter,CommandBlock);
+
+ }
+
+}
+
+VOID
+TOK162SubmitTransmitBlock(
+ IN PTOK162_ADAPTER Adapter,
+ IN PTOK162_SUPER_COMMAND_BLOCK CommandBlock
+ )
+
+/*++
+
+Routine Description:
+
+ Submit a complete Command Block for execution by the TOK162.
+
+Arguments:
+
+ Adapter - The adapter that points to the ring entry structures.
+
+ CommandBlock - Holds the pointer to the transmit block to be
+ submitted.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Pointer to the most recently submitted Transmit Block.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK PreviousCommandBlock;
+
+ // Ensure that our command block is on an even boundary.
+ //
+ ASSERT(!(NdisGetPhysicalAddressLow(CommandBlock->Self) & 1));
+
+ //
+ // Timestamp the transmit block.
+ //
+ CommandBlock->Timeout = FALSE;
+ CommandBlock->Hardware.State = TOK162_STATE_WAIT_FOR_ADAPTER;
+
+ //
+ // If the adapter is currently executing a transmit add this to
+ // the end of the waiting list. Otherwise submit this transmit to
+ // the card.
+ //
+ if (Adapter->TransmitOnCard != NULL) {
+
+ //
+ // Log that we have to pend the transmit
+ IF_LOG('w');
+
+ //
+ // Pend this transmit
+ //
+ PreviousCommandBlock = Adapter->WaitingTransmitTail;
+ Adapter->WaitingTransmitTail = CommandBlock;
+
+ //
+ // Check if there are any other pendings
+ //
+ if (PreviousCommandBlock == NULL) {
+
+ Adapter->WaitingTransmitHead = CommandBlock;
+
+ } else {
+
+ PreviousCommandBlock->NextCommand = CommandBlock;
+
+ }
+
+ } else {
+
+ //
+ // Mark this transmit as the active one.
+ //
+ Adapter->TransmitOnCard = CommandBlock;
+
+ //
+ // Log that we are sending the transmit over the wire
+ //
+ IF_LOG('W');
+
+ //
+ // send the transmit to the card
+ //
+ TOK162SendCommandBlock(Adapter,CommandBlock);
+
+ }
+
+}
+
+BOOLEAN
+TOK162AcquireTransmitBlock(
+ IN PTOK162_ADAPTER Adapter,
+ OUT PTOK162_SUPER_COMMAND_BLOCK * CommandBlock
+ )
+
+/*++
+
+Routine Description:
+
+ Sees if a Transmit Block is available and if so returns its index.
+
+Arguments:
+
+ Adapter - The adapter that has the transmit queue
+
+ CommandBlock - Will receive a pointer to a Command Block if one is
+ available.
+
+Return Value:
+
+ Returns FALSE if there are no free Command Blocks.
+
+--*/
+
+{
+
+ //
+ // Pointer to the available transmit block
+ //
+ PTOK162_SUPER_COMMAND_BLOCK temp;
+
+ //
+ // Get a pointer to the Transmit Block.
+ //
+ temp = Adapter->TransmitQueue + Adapter->NextTransmitBlock;
+
+ //
+ // If there aren't any available transmits, we return FALSE
+ //
+ if (Adapter->NumberOfAvailableTransmitBlocks == 0) {
+
+ //
+ // Log that there weren't any available
+ //
+ IF_LOG('x');
+
+ return FALSE;
+
+ }
+
+ //
+ // Decrement the number of available transit blocks.
+ //
+ Adapter->NumberOfAvailableTransmitBlocks--;
+
+ //
+ // Initialize the Transmit Command Block.
+ //
+ temp->Hardware.NextPending = TOK162_NULL;
+ temp->CommandBlock = FALSE;
+
+ //
+ // Increment to next transmit command block
+ //
+ if (Adapter->NextTransmitBlock == (Adapter->NumberOfTransmitLists - 1)) {
+
+ Adapter->NextTransmitBlock = 0;
+
+ } else {
+
+ Adapter->NextTransmitBlock++;
+ }
+
+ //
+ // Return the transmit block pointer.
+ //
+ *CommandBlock = temp;
+
+ //
+ // Log that we returned a transmit block.
+ //
+ IF_LOG('X');
+
+ return(TRUE);
+
+}
+
+VOID
+TOK162AcquireCommandBlock(
+ IN PTOK162_ADAPTER Adapter,
+ OUT PTOK162_SUPER_COMMAND_BLOCK * CommandBlock
+ )
+
+/*++
+
+Routine Description:
+
+ Gets the command block.
+
+Arguments:
+
+ Adapter - The adapter that points to the ring entry structures.
+
+ CommandBlock - Will receive a pointer to a Command Block.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Pointer to the command block to be returned.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK temp;
+
+ //
+ // This is a pointer to the Command Block.
+ //
+ temp = Adapter->CommandQueue + Adapter->NextCommandBlock;
+
+ ASSERT(Adapter->NumberOfAvailableCommandBlocks > 0);
+
+ IF_LOG('l');
+
+ //
+ // Decrement the number of available command blocks
+ //
+ Adapter->NumberOfAvailableCommandBlocks--;
+
+ //
+ // Initialize the Command Block.
+ //
+ NdisZeroMemory(
+ temp,
+ sizeof(TOK162_SUPER_COMMAND_BLOCK)
+ );
+
+ //
+ // There aren't any linked command blocks right now.
+ //
+ temp->Hardware.NextPending = TOK162_NULL;
+
+ //
+ // This is a command block and not a transmit block
+ //
+ temp->CommandBlock = TRUE;
+
+ //
+ // Set the self-referential pointer.
+ //
+ NdisSetPhysicalAddressLow(
+ temp->Self,
+ NdisGetPhysicalAddressLow(Adapter->CommandQueuePhysical) +
+ Adapter->NextCommandBlock * sizeof(TOK162_SUPER_COMMAND_BLOCK)
+ );
+
+ //
+ // Increment to next command block
+ //
+ if (Adapter->NextCommandBlock == (TOK162_NUMBER_OF_CMD_BLOCKS - 1)) {
+
+ Adapter->NextCommandBlock = 0;
+
+ } else {
+
+ Adapter->NextCommandBlock++;
+
+ }
+
+ //
+ // Return the Command Block pointer.
+ //
+ *CommandBlock = temp;
+
+ //
+ // Log that we returned a command block
+ //
+ IF_LOG('L');
+
+}
+
+
+VOID
+TOK162RelinquishCommandBlock(
+ IN PTOK162_ADAPTER Adapter,
+ IN PTOK162_SUPER_COMMAND_BLOCK CommandBlock
+ )
+
+/*++
+
+Routine Description:
+
+ Relinquish the Command Block resource.
+
+Arguments:
+
+ Adapter - The adapter that owns the Command Block.
+
+ CommandBlock - The Command Block to relinquish.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // If there is a waiting chain of commands -- submit the first one
+ //
+ if (Adapter->WaitingCommandHead != NULL) {
+
+ //
+ // Log that we found pending commands
+ //
+ IF_LOG('j');
+
+ //
+ // Mark the next one as the active one.
+ //
+ Adapter->CommandOnCard = Adapter->WaitingCommandHead;
+
+ //
+ // Update the waiting command head.
+ //
+ Adapter->WaitingCommandHead =
+ Adapter->WaitingCommandHead->NextCommand;
+
+ //
+ // Update the waiting command tail pointer
+ //
+ if (Adapter->WaitingCommandHead == NULL) {
+
+ Adapter->WaitingCommandTail = NULL;
+
+ }
+
+ //
+ // Send out the new command
+ //
+ TOK162SendCommandBlock(Adapter,Adapter->CommandOnCard);
+
+ } else {
+
+ //
+ // Indicate that the queue was empty.
+ //
+ IF_LOG('J');
+
+ //
+ // No commands on the card. We're done for now.
+ //
+ Adapter->CommandOnCard = NULL;
+
+ }
+
+ //
+ // Free the command block
+ //
+ CommandBlock->Hardware.State = TOK162_STATE_FREE;
+ CommandBlock->NextCommand = NULL;
+
+ //
+ // Increment the number of available command blocks
+ //
+ Adapter->NumberOfAvailableCommandBlocks++;
+
+}
+
+
+VOID
+TOK162RelinquishTransmitBlock(
+ IN PTOK162_ADAPTER Adapter,
+ IN PTOK162_SUPER_COMMAND_BLOCK CommandBlock
+ )
+
+/*++
+
+Routine Description:
+
+ Relinquish the Transmit Command Block resource.
+
+Arguments:
+
+ Adapter - The adapter that owns the Command Block.
+
+ CommandBlock - The transmit block to relinquish.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // If there is a waiting chain of commands -- submit the first one
+ //
+ if (Adapter->WaitingTransmitHead != NULL) {
+
+ //
+ // Log that there is a waiting send.
+ //
+ IF_LOG('y');
+
+ //
+ // Update the queue pointers
+ //
+ Adapter->TransmitOnCard = Adapter->WaitingTransmitHead;
+
+ Adapter->WaitingTransmitHead =
+ Adapter->WaitingTransmitHead->NextCommand;
+
+ if (Adapter->WaitingTransmitHead == NULL) {
+
+ Adapter->WaitingTransmitTail = NULL;
+
+ }
+
+ //
+ // Submit this command to the card.
+ //
+ TOK162SendCommandBlock(Adapter,Adapter->TransmitOnCard);
+
+ } else {
+
+ //
+ // Log that the waiting queue was empty.
+ //
+ IF_LOG('Y');
+
+ //
+ // We are done with submits
+ //
+ Adapter->TransmitOnCard = NULL;
+
+ }
+
+ //
+ // Free the transmit block
+ //
+ CommandBlock->Hardware.State = TOK162_STATE_FREE;
+ CommandBlock->NextCommand = NULL;
+
+ //
+ // Increment the number of available transmit blocks
+ //
+ Adapter->NumberOfAvailableTransmitBlocks++;
+
+ //
+ // Decrement the number of queued transmit blocks
+ //
+ Adapter->TransmitsQueued--;
+
+}
+
+
+void
+TOK162SendCommandBlock(
+ IN PTOK162_ADAPTER Adapter,
+ IN PTOK162_SUPER_COMMAND_BLOCK CommandBlock
+ )
+{
+/*++
+
+Routine Description:
+
+ Submits the command block passed in to the card.
+
+Arguments:
+
+ Adapter - The adapter that owns the Command Block.
+
+ CommandBlock - The command/transmit block to submit.
+
+Return Value:
+
+ None.
+
+--*/
+
+ //
+ // This is the "execution" variable for the SCB. The standard is to just
+ // send the interrupt adapter, execute, and don't reset the
+ // adapter-to-system interrupt bits. The initial init open command will
+ // add in the scb clear bit.
+ ULONG ScbExecute = EXECUTE_SCB_COMMAND;
+
+ //
+ // First figure out the SCB, based on the command
+ //
+ Adapter->Scb->Command = CommandBlock->Hardware.CommandCode;
+
+ switch(Adapter->Scb->Command) {
+
+ //
+ // We have a transmit.
+ //
+ case CMD_DMA_XMIT:
+
+ //
+ // Point the Scb to the transmit list
+ //
+ Adapter->Scb->Parm1 =
+ BYTE_SWAP(HIGH_WORD(CommandBlock->PhysicalTransmitEntry));
+
+ Adapter->Scb->Parm2 =
+ BYTE_SWAP(LOW_WORD(CommandBlock->PhysicalTransmitEntry));
+
+ break;
+
+ //
+ // These are the Immediate Data commands. Close doesn't care what
+ // is passed, however.
+ //
+ case CMD_DMA_CLOSE:
+ case CMD_DMA_SET_GRP_ADDR:
+ case CMD_DMA_SET_FUNC_ADDR:
+
+ //
+ // The parameter is set according to the ImmediateData field of
+ // the command block.
+ //
+ Adapter->Scb->Parm1 =
+ BYTE_SWAP(HIGH_WORD(CommandBlock->Hardware.ImmediateData));
+
+ Adapter->Scb->Parm2 =
+ BYTE_SWAP(LOW_WORD(CommandBlock->Hardware.ImmediateData));
+
+ break;
+
+ //
+ // The rest use a pointer.
+ //
+
+ //
+ // In the case of an open, we have to check to see if this is part
+ // of the initial init. If so, we need to get the SCB Clear bit
+ // set so we have proper timing for the receieve command. After
+ // that decision has been made, the open command is treated like
+ // any other pointer command.
+ //
+ case CMD_DMA_OPEN:
+
+ if (Adapter->InitialInit == TRUE) {
+
+ ScbExecute |= CMD_PIO_SCB_REQUEST;
+
+ }
+
+ case CMD_DMA_READ_ERRLOG:
+ case CMD_DMA_READ:
+ case CMD_DMA_RCV:
+ case CMD_DMA_IMPL_ENABLE:
+
+ //
+ // The parameter is set according to the ParmPointer field of
+ // the command block.
+ //
+ Adapter->Scb->Parm1 =
+ BYTE_SWAP(HIGH_WORD(CommandBlock->Hardware.ParmPointer));
+
+ Adapter->Scb->Parm2 =
+ BYTE_SWAP(LOW_WORD(CommandBlock->Hardware.ParmPointer));
+
+ break;
+
+ }
+
+ //
+ // Mark the command block as executing
+ //
+ CommandBlock->Hardware.State = TOK162_STATE_EXECUTING;
+
+ //
+ // Log that we are sending an SCB to the card.
+ //
+ IF_LOG('Z');
+
+ //
+ // Display the SCB on the debugger
+ //
+ EXTRA_LOUD_DEBUG(DbgPrint("SCB going out is %x,%x,%x\n",
+ Adapter->Scb->Command,
+ Adapter->Scb->Parm1,
+ Adapter->Scb->Parm2);)
+
+ //
+ // Finally, send the command out to the card
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_COMMAND,
+ ScbExecute
+ );
+
+}
diff --git a/private/ntos/ndis/ibmtok2i/interrup.c b/private/ntos/ndis/ibmtok2i/interrup.c
new file mode 100644
index 000000000..8db43f373
--- /dev/null
+++ b/private/ntos/ndis/ibmtok2i/interrup.c
@@ -0,0 +1,1376 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ interrup.c
+
+Abstract:
+
+ This module contains the interrupt-processing code for the
+ TOK162 NDIS 3.0 driver.
+
+Author:
+
+ Kevin Martin (KevinMa) 26-Jan-1994
+
+Environment:
+
+ Kernel Mode.
+
+Revision History:
+
+--*/
+
+#include <tok162sw.h>
+
+VOID
+TOK162ProcessReceiveInterrupts(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+VOID
+TOK162ProcessCommandInterrupts(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+
+VOID
+TOK162Isr(
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueDpc,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ Interrupt service routine for the TOK162. Used only during init.
+ The NdisMRegisterInterrupt() call (reset.c) specified not to call the
+ ISR for every interrupt. The DPC is called directly instead.
+
+Arguments:
+
+ Interrupt - Interrupt object for the TOK162.
+
+ Context - Really a pointer to the adapter.
+
+Return Value:
+
+ Returns true if the interrupt really was from the TOK162 and whether the
+ wrapper should queue a DPC.
+
+--*/
+
+{
+
+ //
+ // Holds the pointer to the adapter structure.
+ //
+ PTOK162_ADAPTER Adapter = Context;
+
+ //
+ // Holds IsrpHigh with some bits masked off.
+ //
+ USHORT Sif;
+
+ //
+ // Indicate that an interrupt has occurred (internal logging and
+ // debug print's).
+ //
+ VERY_LOUD_DEBUG(DbgPrint("TOK162!ISR\n");)
+ IF_LOG('o');
+
+ //
+ // Read the adapter interrupt register
+ //
+ READ_ADAPTER_USHORT(Adapter,PORT_OFFSET_STATUS,&Sif);
+
+ //
+ // Check if this is our interrupt. If it is, set flag indicating that the
+ // interrupt is recognized. Otherwise indicate that the interrupt is not
+ // ours.
+ //
+ if ((Sif & STATUS_SYSTEM_INTERRUPT) != 0) {
+
+ *InterruptRecognized = TRUE;
+
+ } else {
+
+ *InterruptRecognized = FALSE;
+
+ }
+
+ //
+ // Mask off the interrupt type portion of the register.
+ //
+ Sif = (UCHAR) (Sif & STATUS_INT_CODE_MASK);
+
+ //
+ // If this is a receive, go ahead and do the DPC. This allows us to keep
+ // in synch with the card concerning the receive list index. Also, for a
+ // a receive there is no need to allow the SSB to be updated as the DPC
+ // routine will do this for us. If it isn't a receive, we need to indicate
+ // that no DPC is necessary and we also allow the SSB to be updated.
+ //
+ if (Sif == STATUS_INT_CODE_RECEIVE_STATUS) {
+
+ IF_LOG('p');
+
+ *QueueDpc = TRUE;
+
+ //
+ // If we have a command, then it is the open or an error has occurred.
+ // Indicate that the Ssb can be cleared after the open info has been
+ // obtained.
+ //
+ } else if (Sif == STATUS_INT_CODE_CMD_STATUS) {
+
+ if (Adapter->Ssb->Command == CMD_DMA_OPEN) {
+
+ Adapter->SsbStatus1 = Adapter->Ssb->Status1;
+ Adapter->InitialOpenComplete = TRUE;
+
+ }
+
+ //
+ // Enable updating of the SSB
+ //
+ IF_LOG('z');
+
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_STATUS,
+ ENABLE_SSB_UPDATE
+ );
+
+
+ *QueueDpc = FALSE;
+
+ //
+ // If we get the SCB clear interrupt, then we can do the receive command.
+ //
+ } else if (Sif == STATUS_INT_CODE_SCB_CLEAR) {
+
+ DoTheReceive(Adapter);
+ Adapter->InitialReceiveSent = TRUE;
+
+ } else {
+
+ //
+ // Enable updating of the SSB
+ //
+ IF_LOG('z');
+
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_STATUS,
+ ENABLE_SSB_UPDATE
+ );
+
+ *QueueDpc = FALSE;
+
+ }
+
+ //
+ // Indicate the ISR routine has ended.
+ //
+ IF_LOG('O');
+}
+
+
+VOID
+TOK162DeferredTimer(
+ IN PVOID SystemSpecific1,
+ IN PTOK162_ADAPTER Adapter,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+/*++
+
+Routine Description:
+
+ Just an entry point to distinguish between a timer call and the wrapper
+ calling the DPC directly.
+
+Arguments:
+
+ Adapter - pointer to current adapter
+
+ The rest are not used, but simply passed on
+
+Return Value:
+
+ None
+
+--*/
+{
+ //
+ // Indicate that a timer has expired.
+ //
+ VERY_LOUD_DEBUG(DbgPrint("TOK162!Deferred Timer called\n");)
+
+ //
+ // Call the standard DPC handler.
+ //
+ TOK162HandleInterrupt(Adapter);
+}
+
+
+VOID
+TOK162HandleInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ Main routine for processing interrupts.
+
+Arguments:
+
+ Adapter - The Adapter to process interrupts for.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Pointer to the TOK162 adapter structure.
+ //
+ PTOK162_ADAPTER Adapter = ((PTOK162_ADAPTER)MiniportAdapterContext);
+
+ //
+ // Holds the value of the interrupt type
+ //
+ USHORT IMask = 0;
+
+ //
+ // If any receive interrupts are processed, we have to indicate that
+ // the receive work has been completed after all interrupts have been
+ // processed.
+ //
+ BOOLEAN IndicateReceiveComplete = FALSE;
+
+ //
+ // Indicate that the DPC routine has been called.
+ //
+ EXTRA_LOUD_DEBUG(DbgPrint("TOK162!DPC was just called\n");)
+ IF_LOG('r');
+
+ //
+ // Loop through processing interrupts until we have processed them all.
+ //
+ while (TRUE) {
+
+ //
+ // Read the adapter interrupt register
+ //
+ READ_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_STATUS,
+ &IMask
+ );
+
+ //
+ // If this is not our interrupt, end DPC processing
+ //
+ if ((IMask & STATUS_SYSTEM_INTERRUPT) == 0) {
+
+ //
+ // Indicate that we received a bad interrupt and break
+ // out of the loop.
+ //
+ IF_LOG('a');
+
+ break;
+
+ } else {
+
+ //
+ // Indicatate that the interrupt was found to be ours.
+ //
+ IF_LOG('A');
+
+ //
+ // Record pertinent information about the interrupt as this
+ // card/chipset only allows one interrupt to be indicated by
+ // the card at a time.
+ //
+ Adapter->SsbCommand = Adapter->Ssb->Command;
+ Adapter->SsbStatus1 = Adapter->Ssb->Status1;
+ Adapter->SsbStatus2 = Adapter->Ssb->Status2;
+ Adapter->SsbStatus3 = Adapter->Ssb->Status3;
+
+ }
+
+ //
+ // Figure out the type of interrupt
+ //
+ IMask = (UCHAR) (IMask & STATUS_INT_CODE_MASK);
+
+ //
+ // Indicate the type of interrupt to the debugger.
+ //
+ EXTRA_LOUD_DEBUG(DbgPrint("TOK162!New IMask is %x\n",IMask);)
+
+ //
+ // Process the interrupt based on the type of interrupt.
+ //
+ switch(IMask) {
+
+ case STATUS_INT_CODE_RING:
+
+ //
+ // We have a ring status change. Log this fact.
+ //
+ IF_LOG('b');
+
+ //
+ // If we have a soft error, it is possible that the
+ // card has become overrun with receives. Therefore, the
+ // TOK162ProcessRingInterrupts will return TRUE in this
+ // case to allow us to call ProcessReceiveInterrupts().
+ // In all other cases, TOK162ProcessRingInterrupts() will
+ // return FALSE.
+ //
+ if (TOK162ProcessRingInterrupts(Adapter) == TRUE) {
+
+ TOK162ProcessReceiveInterrupts(Adapter);
+
+ //
+ // Indicate that we did process receives during this
+ // DPC.
+ //
+ IndicateReceiveComplete = TRUE;
+
+ }
+
+ break;
+
+ case STATUS_INT_CODE_RECEIVE_STATUS:
+
+ //
+ // We have a receive interrupt. Log this fact.
+ //
+ IF_LOG('c');
+
+ //
+ // Process the interrupt.
+ //
+ TOK162ProcessReceiveInterrupts(Adapter);
+
+ //
+ // Indicate that we did process a receive during this
+ // DPC.
+ //
+ IndicateReceiveComplete = TRUE;
+
+ break;
+
+ case STATUS_INT_CODE_XMIT_STATUS:
+
+ //
+ // We have a transmit interrupt. Log this fact.
+ //
+ IF_LOG('d');
+
+ //
+ // Process the transmit.
+ //
+ TOK162ProcessTransmitInterrupts(Adapter);
+
+ break;
+
+ case STATUS_INT_CODE_CMD_STATUS:
+
+ //
+ // We have a command interrupt to process. Log this fact.
+ //
+ IF_LOG('e');
+
+ //
+ // If there is a command structure that has been sent to the
+ // adapter, then we will process that command. Otherwise, we
+ // simply return.
+ //
+ if (Adapter->CommandOnCard != NULL) {
+
+ //
+ // Process the active command.
+ //
+ TOK162ProcessCommandInterrupts(Adapter);
+
+ }
+ break;
+
+ default:
+
+ //
+ // The interrupt type is not one that we know (illegal value).
+ // Indicate this to the debugger.
+ //
+ LOUD_DEBUG(DbgPrint("TOK162!Int Command %x, %x\n",Adapter->SsbCommand,
+ Adapter->SsbStatus1);)
+
+ break;
+
+ }
+
+ //
+ // Indicate that we are about to dismiss the interrupt.
+ //
+ IF_LOG('z');
+
+ //
+ // Dismiss the interrupt, allowing the SSB to be updated.
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_STATUS,
+ ENABLE_SSB_UPDATE
+ );
+
+ }
+
+ //
+ // If we processed any receive interrupts, IndicateReceiveComplete() will
+ // be set to TRUE. In this case, we need to indicate that all receives
+ // are complete.
+ //
+ if (IndicateReceiveComplete) {
+
+ //
+ // Indicate to the debugger that we are doing the complete.
+ //
+ EXTRA_LOUD_DEBUG(DbgPrint("TOK162!Doing the indicate complete on the receive\n");)
+
+ //
+ // Call the Token Ring Filter to indicate the receive complete.
+ //
+ NdisMTrIndicateReceiveComplete(Adapter->MiniportAdapterHandle);
+
+ }
+
+ //
+ // Log and indicate to the debugger that we are ending DPC processing.
+ //
+ IF_LOG('R');
+ EXTRA_LOUD_DEBUG(DbgPrint("TOK162!Ending DPC processing\n");)
+
+}
+
+
+VOID
+TOK162ProcessReceiveInterrupts(
+ IN PTOK162_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Process the packets that have finished receiving.
+
+ NOTE: This routine assumes that no other thread of execution
+ is processing receives!
+
+Arguments:
+
+ Adapter - The adapter to indicate to.
+
+Return Value:
+
+ Whether to clear interrupt or not
+
+--*/
+
+{
+
+ //
+ // We don't get here unless there was a receive. Loop through
+ // the receive blocks starting at the last known block owned by
+ // the hardware.
+ //
+ // After we find a packet we give the routine that process the
+ // packet through the filter, the buffers virtual address (which
+ // is always the lookahead size) and as the MAC Context the
+ // index to the receive block.
+ //
+
+ //
+ // Pointer to the receive block being examined.
+ //
+ PTOK162_SUPER_RECEIVE_LIST CurrentEntry = Adapter->ReceiveQueueCurrent;
+
+ //
+ // Used during receiveindicate to let the filter know the header size
+ // of the given buffer.
+ //
+ USHORT HeaderSize;
+
+ //
+ // Used to indicate the total size of the frame to the filter.
+ //
+ USHORT FrameSize;
+
+ //
+ // Points to the beginning of the received buffer. Used to determine the
+ // size of the frame header (source routing).
+ //
+ PUCHAR Temp;
+
+ //
+ // Log the fact that we are processing a receive.
+ //
+ IF_LOG('C');
+
+ //
+ // Continue processing receives until we have exhausted them.
+ //
+ while (TRUE) {
+
+ //
+ // Ensure that our Receive Entry is on an even boundary.
+ //
+ ASSERT(!(NdisGetPhysicalAddressLow(CurrentEntry->Self) & 1));
+
+ //
+ // Send the receive status byte to the debugger.
+ //
+ EXTRA_LOUD_DEBUG(DbgPrint(
+ "TOK162!Receive CSTAT == %x\n",CurrentEntry->Hardware.CSTAT);)
+
+ //
+ // Check to see if CSTAT has been changed indicating
+ // the receive entry has been modified
+ //
+ if (CurrentEntry->Hardware.CSTAT & RECEIVE_CSTAT_VALID) {
+
+ //
+ // Record the receive list entry following the last good
+ // entry as the starting point for the next time receives
+ // are processed.
+ //
+ Adapter->ReceiveQueueCurrent = CurrentEntry;
+
+ //
+ // Tell the adapter to allow more receives.
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_COMMAND,
+ ENABLE_RECEIVE_VALID
+ );
+
+ return;
+
+ }
+
+ //
+ // Get a pointer to the first byte of the current receive buffer.
+ //
+ Temp = (PUCHAR)CurrentEntry->ReceiveBuffer;
+
+ //
+ // If the source routing bit is on, figure out the size of the
+ // MAC Frame header. Otherwise, the size is set to the default
+ // of 14 (decimal).
+ //
+ HeaderSize = 14;
+
+
+ if (Temp[8] & 0x80) {
+
+ //
+ // Source routing bit is on in source address, so calculate
+ // the frame header size.
+ //
+ HeaderSize = (Temp[14] & 0x1f) + 14;
+
+ }
+
+ //
+ // Save the received header size.
+ //
+ Adapter->SizeOfReceivedHeader = HeaderSize;
+
+ //
+ // Record the fact that we had a good receive.
+ //
+ Adapter->GoodReceives++;
+
+ //
+ // Make sure the adapter and the system are in synch.
+ //
+ NdisFlushBuffer(CurrentEntry->FlushBuffer, FALSE);
+
+ //
+ // Get the frame size of this buffer.
+ //
+ FrameSize = BYTE_SWAP(CurrentEntry->Hardware.FrameSize);
+
+ //
+ // Indicate the frame size to the debugger
+ //
+ EXTRA_LOUD_DEBUG(DbgPrint("TOK162!Frame size is %u\n",
+ FrameSize);)
+
+ //
+ // If the frame that we have been passed has an invalid length
+ // (less than the reported header size) then we need to check
+ // if the frame size is larger than the default address length.
+ //
+ if (FrameSize >= HeaderSize) {
+
+ //
+ // We have a 'normal' packet. Indicate this to the debugger
+ // and log it.
+ EXTRA_LOUD_DEBUG(DbgPrint("TOK162!Doing receive indicate\n");)
+ IF_LOG('q');
+
+ //
+ // Do the indication to the filter.
+ //
+ NdisMTrIndicateReceive(
+ Adapter->MiniportAdapterHandle,
+ (NDIS_HANDLE)(
+ ((PUCHAR)(CurrentEntry->ReceiveBuffer))+HeaderSize),
+ CurrentEntry->ReceiveBuffer,
+ (UINT)HeaderSize,
+ ((PUCHAR)CurrentEntry->ReceiveBuffer) + HeaderSize,
+ FrameSize - HeaderSize,
+ FrameSize - HeaderSize
+ );
+
+ } else {
+
+ //
+ // If the frame size is greater than or equal to the length
+ // of an address (network address, 12 bytes) then we can
+ // indicate it as a runt packet to the filter. Otherwise,
+ // we ignore the received buffer.
+ //
+ if (FrameSize >= TOK162_LENGTH_OF_ADDRESS) {
+
+ //
+ // Indicate this is a runt packet to the debugger
+ //
+ VERY_LOUD_DEBUG(DbgPrint(
+ "TOK162!Doing receive indicate for a runt\n");)
+
+ //
+ // Indicate the packet to the filter.
+ //
+ NdisMTrIndicateReceive(
+ Adapter->MiniportAdapterHandle,
+ (NDIS_HANDLE)(
+ ((PUCHAR)(CurrentEntry->ReceiveBuffer)) + HeaderSize),
+ (PUCHAR)Temp,
+ (UINT)FrameSize,
+ NULL,
+ 0,
+ 0
+ );
+
+ }
+
+ }
+
+ //
+ // Mark the receive list as processed and able to receive another
+ // buffer.
+ //
+ CurrentEntry->Hardware.CSTAT = RECEIVE_CSTAT_REQUEST_RESET;
+
+ //
+ // Move to the next entry to see if there are more to process.
+ //
+ CurrentEntry = CurrentEntry->NextEntry;
+
+ //
+ // Log the fact that we are telling the card to send us more receives.
+ //
+ IF_LOG('Q');
+
+ //
+ // Tell the card that we are ready to process more receives.
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_COMMAND,
+ ENABLE_RECEIVE_VALID
+ );
+
+ }
+
+}
+
+
+VOID
+TOK162ProcessCommandInterrupts(
+ IN PTOK162_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Process the Command Complete interrupts.
+
+ NOTE: This routine assumes that it is being executed in a
+ single thread of execution.
+
+Arguments:
+
+ Adapter - The adapter that was sent from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Pointer to command block being processed.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK CurrentCommandBlock = Adapter->CommandOnCard;
+
+ //
+ // Status variable
+ //
+ NDIS_STATUS Status;
+
+ //
+ // NetCard Address Block
+ //
+ PTOK162_ADDRESSBLOCK Addresses;
+ //
+ // Ensure that the Command Block is on an even boundary.
+ //
+ ASSERT(!(NdisGetPhysicalAddressLow(CurrentCommandBlock->Self) & 1));
+
+ //
+ // Log the fact that we are processing a command interrupt.
+ //
+ IF_LOG('E');
+
+ //
+ // Process the command based on the command code.
+ //
+ switch(CurrentCommandBlock->Hardware.CommandCode) {
+
+ case CMD_DMA_READ:
+
+ //
+ // We are processing a read command. The read command is
+ // generated by a query request.
+ //
+ // Indicate we are processing a read command to the
+ // debugger.
+ //
+ VERY_LOUD_DEBUG(DbgPrint("TOK162!DPC for read adapter called\n");)
+
+ // Get a pointer to the block of memory set aside for the
+ // read command.
+ //
+ Addresses = (PTOK162_ADDRESSBLOCK)Adapter->AdapterBuf;
+
+ //
+ // Check the Oid to see if we are after the permanent card
+ // address or the current addresses.
+ //
+ if (Adapter->Oid == OID_802_5_PERMANENT_ADDRESS) {
+ //
+ // Update the permanent node address
+ //
+ NdisMoveMemory(
+ Adapter->NetworkAddress,
+ Addresses->NodeAddress,
+ 6
+ );
+
+ } else {
+
+ //
+ // Update the current network address
+ //
+ NdisMoveMemory(
+ (UNALIGNED PUCHAR)Adapter->CurrentAddress,
+ Addresses->NodeAddress,
+ 6);
+ }
+
+ //
+ // Finish the query and relenquish the command block
+ //
+ TOK162FinishQueryInformation(Adapter);
+ TOK162RelinquishCommandBlock(Adapter, CurrentCommandBlock);
+
+ break;
+
+ case CMD_DMA_OPEN:
+
+ //
+ // An open command is generated during a reset command. The
+ // initial open is called during adapter initialization and
+ // no DPC is generated.
+ //
+ // Indicate we are processing an open to the debugger.
+ //
+ VERY_LOUD_DEBUG(DbgPrint("TOK162!Processing the open command.\n");)
+
+ //
+ // Relinquish the command block associcated with this open.
+ //
+ TOK162RelinquishCommandBlock(Adapter, CurrentCommandBlock);
+
+ //
+ // Check to see if the open succeeded.
+ //
+ if ((Adapter->SsbStatus1 & OPEN_COMPLETION_MASK_RESULT)
+ != OPEN_RESULT_ADAPTER_OPEN) {
+
+ //
+ // The open failed. Set the current ring state and set the
+ // return variable to NDIS_STATUS_FAILURE.
+ //
+ Adapter->CurrentRingState = NdisRingStateOpenFailure;
+ Adapter->OpenErrorCode = Adapter->SsbStatus1;
+ Status = NDIS_STATUS_FAILURE;
+
+ //
+ // Display the error code on the debugger.
+ //
+ VERY_LOUD_DEBUG(DbgPrint(
+ "TOK162!Error on the open - %x\n",Adapter->SsbStatus1);)
+
+ } else {
+
+ //
+ // The open succeeded. Set the current ring state and set the
+ // return variable to NDIS_STATUS_SUCCESS.
+ //
+ Adapter->CurrentRingState = NdisRingStateOpened;
+ Adapter->OpenErrorCode = 0;
+ Status = NDIS_STATUS_SUCCESS;
+
+ //
+ // Now send out the receive command. Display the fact that
+ // DoReceive is being called on the debugger.
+ //
+ VERY_LOUD_DEBUG(DbgPrint("Doing the receive\n");)
+
+ //
+ // Check if the receive command succeeded. If not, set the
+ // return variable to NDIS_STATUS_FAILURE. It is currently
+ // set to NDIS_STATUS_SUCCESS, so no change is necessary
+ // if the receive command succeeds.
+ //
+ if (DoTheReceive(Adapter) == FALSE) {
+
+ Status = NDIS_STATUS_FAILURE;
+
+ }
+
+ }
+
+ //
+ // Indicate to the wrapper the result of the open/receive for
+ // the original reset request.
+ //
+ TOK162DoResetIndications(Adapter, Status);
+ break;
+
+ case CMD_DMA_READ_ERRLOG:
+
+ LOUD_DEBUG(DbgPrint("TOK162!DPC for read errorlog called\n");)
+
+ //
+ // Record the values for the error counters
+ //
+ Adapter->ReceiveCongestionError +=
+ Adapter->ErrorLog->ReceiveCongestionError;
+
+ Adapter->LineError += Adapter->ErrorLog->LineError;
+
+ Adapter->LostFrameError += Adapter->ErrorLog->LostFrameError;
+
+ Adapter->BurstError += Adapter->ErrorLog->BurstError;
+
+ Adapter->FrameCopiedError += Adapter->ErrorLog->FrameCopiedError;
+
+ Adapter->TokenError += Adapter->ErrorLog->TokenError;
+
+ Adapter->InternalError += Adapter->ErrorLog->InternalError;
+
+ Adapter->ARIFCIError += Adapter->ErrorLog->ARIFCIError;
+
+ Adapter->AbortDelimeter += Adapter->ErrorLog->AbortDelimeter;
+
+ Adapter->DMABusError += Adapter->ErrorLog->DMABusError;
+
+ //
+ // Indicate the values to the debugger
+ //
+ VERY_LOUD_DEBUG(DbgPrint("TOK162!CongestionErrors = %u\n",
+ Adapter->ErrorLog->ReceiveCongestionError);)
+
+ VERY_LOUD_DEBUG(DbgPrint("TOK162!LineErrors = %u\n",
+ Adapter->ErrorLog->LineError);)
+
+ VERY_LOUD_DEBUG(DbgPrint("TOK162!LostFrameErrors = %u\n",
+ Adapter->ErrorLog->LostFrameError);)
+
+ VERY_LOUD_DEBUG(DbgPrint("TOK162!BurstErrors = %u\n",
+ Adapter->ErrorLog->BurstError);)
+
+ VERY_LOUD_DEBUG(DbgPrint("TOK162!FrameCopiedErrors = %u\n",
+ Adapter->ErrorLog->FrameCopiedError);)
+
+ VERY_LOUD_DEBUG(DbgPrint("TOK162!TokenErrors = %u\n",
+ Adapter->ErrorLog->TokenError);)
+
+ VERY_LOUD_DEBUG(DbgPrint("TOK162!InternalErrors = %u\n",
+ Adapter->ErrorLog->InternalError);)
+
+ VERY_LOUD_DEBUG(DbgPrint("TOK162!ARIFCIErrors = %u\n",
+ Adapter->ErrorLog->ARIFCIError);)
+
+ VERY_LOUD_DEBUG(DbgPrint("TOK162!AbortDelimeters = %u\n",
+ Adapter->ErrorLog->AbortDelimeter);)
+
+ VERY_LOUD_DEBUG(DbgPrint("TOK162!DMABusErrors = %u\n",
+ Adapter->ErrorLog->DMABusError);)
+
+ //
+ // If a query for information generated this interrupt, finish
+ // the query.
+ //
+ if (Adapter->RequestInProgress) {
+
+ TOK162FinishQueryInformation(Adapter);
+
+ }
+
+ //
+ // Relinquish the command block associated with this
+ // readadapterlog.
+ //
+ TOK162RelinquishCommandBlock(Adapter, CurrentCommandBlock);
+
+ break;
+
+
+ default:
+
+ //
+ // Did this command come from a set information request?
+ //
+ if (CurrentCommandBlock->Set) {
+
+ //
+ // Relinquish the command block.
+ //
+ TOK162RelinquishCommandBlock(Adapter, CurrentCommandBlock);
+
+ //
+ // Mark the current request state as complete.
+ //
+ Adapter->RequestInProgress = FALSE;
+
+ //
+ // Inform the wrapper the request has been completed.
+ //
+ NdisMSetInformationComplete(
+ Adapter->MiniportAdapterHandle,
+ NDIS_STATUS_SUCCESS);
+
+ //
+ // Not from a set. If this is the unique case of where a group
+ // address and a functional address had to be set to satisfy a
+ // packet filter change command (two commands for one), then we
+ // will only do an indication on the last one. The first one,
+ // however, still needs to have the command block associated
+ // with it relinquished.
+ //
+ } else if ((CurrentCommandBlock->Hardware.CommandCode == CMD_DMA_SET_GRP_ADDR) ||
+ (CurrentCommandBlock->Hardware.CommandCode == CMD_DMA_SET_FUNC_ADDR)) {
+
+ TOK162RelinquishCommandBlock(Adapter, CurrentCommandBlock);
+
+ }
+
+ break;
+ }
+
+}
+
+
+VOID
+TOK162ProcessTransmitInterrupts(
+ IN PTOK162_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Process the Transmit Complete interrupts.
+
+ NOTE: This routine assumes that it is being executed in a
+ single thread of execution.
+
+Arguments:
+
+ Adapter - The adapter the transmit was sent from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Pointer to command block being processed.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK CurrentCommandBlock = Adapter->TransmitOnCard;
+
+ //
+ // Pointer to the packet that started this transmission.
+ //
+ PNDIS_PACKET OwningPacket;
+
+ //
+ // Points to the reserved part of the OwningPacket.
+ //
+ PTOK162_RESERVED Reserved;
+
+ //
+ // Holds CSTAT variable for transmit
+ //
+ USHORT Cstat;
+
+ //
+ // Status variable
+ //
+ NDIS_STATUS Status;
+
+ //
+ // Ensure that the Command Block is on an even boundary.
+ //
+ ASSERT(!(NdisGetPhysicalAddressLow(CurrentCommandBlock->Self) & 1));
+
+ //
+ // Log the fact that we are processing a transmit interrupt
+ //
+ IF_LOG('D');
+
+ //
+ // Check if there is any reason to continue with the process. It is
+ // possible during a reset that not all of the transmits had completed.
+ // The reset path takes care of aborting all sends that didn't complete
+ // so we don't want to process anything during a reset. In the general
+ // case we don't want to process any transmit that doesn't have an
+ // associated command block.
+ //
+ if ((CurrentCommandBlock == NULL) ||
+ (Adapter->ResetInProgress == TRUE)) {
+
+ //
+ // Log the fact that we received a possibly bogus transmit interrupt.
+ //
+ IF_LOG('p');
+ return;
+
+ }
+
+ //
+ // Get a pointer to the owning packet and the reserved part of
+ // the packet.
+ //
+ OwningPacket = CurrentCommandBlock->OwningPacket;
+ Reserved = PTOK162_RESERVED_FROM_PACKET(OwningPacket);
+
+ //
+ // Check if this packet was constrained.
+ //
+ if (CurrentCommandBlock->UsedTOK162Buffer == FALSE) {
+ //
+ // Pointer to the current NDIS_BUFFER that we need to do the
+ // completemapregister on.
+ //
+ PNDIS_BUFFER CurrentBuffer;
+
+ //
+ // Index to the map register being freed.
+ //
+ UINT CurMapRegister;
+
+ //
+ // The transmit is finished, so we can release
+ // the physical mapping used for it.
+ //
+ NdisQueryPacket(
+ OwningPacket,
+ NULL,
+ NULL,
+ &CurrentBuffer,
+ NULL
+ );
+
+ //
+ // Compute the first map register used by this transmit.
+ //
+ CurMapRegister = CurrentCommandBlock->CommandBlockIndex *
+ Adapter->TransmitThreshold;
+
+ //
+ // Loop through the NDIS_BUFFERs until there are no more.
+ //
+ while (CurrentBuffer != NULL) {
+
+ //
+ // Free the current map register.
+ //
+ NdisMCompleteBufferPhysicalMapping(
+ Adapter->MiniportAdapterHandle,
+ CurrentBuffer,
+ CurMapRegister
+ );
+
+ //
+ // Move to the next map register.
+ //
+ ++CurMapRegister;
+
+ //
+ // Get the next NDIS_BUFFER
+ //
+ NdisGetNextBuffer(
+ CurrentBuffer,
+ &CurrentBuffer
+ );
+
+ }
+
+ }
+
+ //
+ // If there was an error transmitting this
+ // packet, update our error counters.
+ //
+ Cstat = CurrentCommandBlock->Hardware.TransmitEntry.CSTAT;
+
+ //
+ // Display the completion status for the transmit entry on the debugger.
+ //
+ VERY_LOUD_DEBUG(DbgPrint(
+ "TOK162!Csat for the command block is %x\n",Cstat);)
+
+ //
+ // Check if there was an error on the transmit. Set Status and increment
+ // appropriate counter.
+ //
+ if ((Cstat & TRANSMIT_CSTAT_XMIT_ERROR) != 0) {
+
+ Adapter->BadTransmits++;
+ Status = NDIS_STATUS_FAILURE;
+
+ } else {
+
+ Adapter->GoodTransmits++;
+ Status = NDIS_STATUS_SUCCESS;
+
+ }
+
+ //
+ // Release the command block.
+ //
+ TOK162RelinquishTransmitBlock(Adapter, CurrentCommandBlock);
+
+ //
+ // Indicate to the filter than the send has been completed.
+ //
+ NdisMSendComplete(
+ Adapter->MiniportAdapterHandle,
+ OwningPacket,
+ Status
+ );
+
+}
+
+
+
+BOOLEAN
+TOK162ProcessRingInterrupts(
+ IN PTOK162_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ Process ring status interrupts.
+
+Arguments:
+
+ Adapter - The adapter registering the ring interrupt
+
+Return Value:
+
+ FALSE - Don't need to process receives as a result of the ring condition
+ TRUE - Need to process receives
+
+--*/
+{
+ //
+ // Holds the return status value
+ //
+ ULONG RingStatus;
+
+ //
+ // Command block variable used if we need to read the errorlog due to
+ // an overflow condition.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK CommandBlock;
+
+ //
+ // Return value for the function. Assume we don't need to process
+ // receives.
+ //
+ BOOLEAN SoftError = FALSE;
+
+ //
+ // Log that we are processing a ring DPC. Display the ring interrupt
+ // information on the debugger.
+ //
+ IF_LOG('B');
+ VERY_LOUD_DEBUG(DbgPrint(
+ "TOK162!Doing ring processing -%04x\n",Adapter->SsbStatus1);)
+
+ //
+ // Initialize Ring Status to 0
+ //
+ RingStatus = 0;
+
+ //
+ // Determine the reason for the ring interrupt.
+ //
+ if (Adapter->SsbStatus1 & RING_STATUS_SIGNAL_LOSS) {
+
+ RingStatus |= NDIS_RING_SIGNAL_LOSS;
+
+ } else if (Adapter->SsbStatus1 & RING_STATUS_HARD_ERROR) {
+
+ RingStatus |= NDIS_RING_HARD_ERROR;
+
+ } else if (Adapter->SsbStatus1 & RING_STATUS_SOFT_ERROR) {
+
+ //
+ // If we have a soft error, we should check the receives.
+ //
+ RingStatus |= NDIS_RING_SOFT_ERROR;
+ SoftError = TRUE;
+
+ } else if (Adapter->SsbStatus1 & RING_STATUS_XMIT_BEACON) {
+
+ RingStatus |= NDIS_RING_TRANSMIT_BEACON;
+
+ } else if (Adapter->SsbStatus1 & RING_STATUS_LOBE_WIRE_FAULT) {
+
+ RingStatus |= NDIS_RING_LOBE_WIRE_FAULT;
+
+ } else if (Adapter->SsbStatus1 & RING_STATUS_AUTO_REMOVE_1) {
+
+ RingStatus |= NDIS_RING_AUTO_REMOVAL_ERROR;
+
+ } else if (Adapter->SsbStatus1 & RING_STATUS_REMOVE_RECEIVED) {
+
+ RingStatus |= NDIS_RING_REMOVE_RECEIVED;
+
+ } else if (Adapter->SsbStatus1 & RING_STATUS_OVERFLOW) {
+
+ RingStatus |= NDIS_RING_COUNTER_OVERFLOW;
+
+ } else if (Adapter->SsbStatus1 & RING_STATUS_SINGLESTATION) {
+
+ RingStatus |= NDIS_RING_SINGLE_STATION;
+
+ } else if (Adapter->SsbStatus1 & RING_STATUS_RINGRECOVERY) {
+
+ RingStatus |= NDIS_RING_RING_RECOVERY;
+
+ }
+
+ //
+ // Display the ring status that we will be indicating to the filter on
+ // the debugger.
+ //
+ VERY_LOUD_DEBUG(DbgPrint(
+ "TOK162!Indicating ring status - %lx\n",RingStatus);)
+
+ //
+ // Save the current status for query purposes.
+ //
+ Adapter->LastNotifyStatus = RingStatus;
+
+ //
+ // Indicate to the filter the ring status.
+ //
+ NdisMIndicateStatus(
+ Adapter->MiniportAdapterHandle,
+ NDIS_STATUS_RING_STATUS,
+ &RingStatus,
+ sizeof(ULONG)
+ );
+
+ //
+ // Tell the filter that we have completed the ring status.
+ //
+ NdisMIndicateStatusComplete(Adapter->MiniportAdapterHandle);
+
+ //
+ // If a counter has overflowed, we need to read the stats from
+ // the adapter to clear this condition.
+ //
+ if ((Adapter->SsbStatus1 & RING_STATUS_OVERFLOW) != 0) {
+
+
+ //
+ // Get a command block.
+ //
+ TOK162AcquireCommandBlock(Adapter,
+ &CommandBlock
+ );
+
+
+ //
+ // Set up the command block for a read_error_log command.
+ //
+ CommandBlock->Set = FALSE;
+ CommandBlock->NextCommand = NULL;
+ CommandBlock->Hardware.Status = 0;
+ CommandBlock->Hardware.NextPending = TOK162_NULL;
+ CommandBlock->Hardware.CommandCode = CMD_DMA_READ_ERRLOG;
+ CommandBlock->Hardware.ParmPointer =
+ NdisGetPhysicalAddressLow(Adapter->ErrorLogPhysical);
+
+ //
+ // Submit the command to the card.
+ //
+ TOK162SubmitCommandBlock(Adapter,
+ CommandBlock
+ );
+
+ }
+
+ //
+ // Return whether processreceiveinterrupts needs to be called.
+ //
+ return(SoftError);
+
+}
+
diff --git a/private/ntos/ndis/ibmtok2i/log.txt b/private/ntos/ndis/ibmtok2i/log.txt
new file mode 100644
index 000000000..b56b48d52
--- /dev/null
+++ b/private/ntos/ndis/ibmtok2i/log.txt
@@ -0,0 +1,77 @@
+a - Not our Interrupt interrup.c
+A - Our Interrupt interrup.c
+
+b - Ring Status Interrupt interrup.c
+B - Ring Status DPC interrup.c
+
+c - Receive Interrupt interrup.c
+C - Receive DPC interrup.c
+
+d - Transmit Interrupt interrup.c
+D - Transmit DPC interrup.c
+
+e - Command Interrupt interrup.c
+E - Command DPC interrup.c
+
+f -
+F - Receive Command Failed reset.c
+
+g - DoTheOpen Entered reset.c
+G - DoTheOpen Exited reset.c
+
+h - Open succeeded reset.c
+H - Open failed reset.c
+
+i - Command Block Pended command.c
+I - Command Block Sent command.c
+
+j - Command Block Relinquished, queue not empty command.c
+J - Command Block Relinquished, queue empty command.c
+
+k -
+K -
+
+l - Acquire Command Block Entered command.c
+L - Acquire Command Block Exited command.c
+
+m -
+M -
+
+n - TransferData Entered tok162.c
+N - TransferData Exited tok162.c
+
+o - ISR called interrup.c
+O - ISR leaving interrup.c
+
+p - ISR is for Receive interrup.c
+P -
+
+q - Indicate Receive interrup.c
+Q - Receive Valid Interrupt Issued interrup.c
+
+r - Entering DPC interrup.c
+R - Leaving DPC interrup.c
+
+s - Send Entered send.c
+S - Send Exited send.c
+
+t - Tramsmit Packet Entered send.c
+T - Transmit Packet Exited send.c
+
+u - Transmit Packet Exited Resources send.c
+U - Transmit Packet Exited Error send.c
+
+v - Transmit Constrain Entered send.c
+V - Transmit Constrain Exited send.c
+
+w - Transmit Command Pended command.c
+W - Transmit Command Sent command.c
+
+x - No Transmit Blocks Available command.c
+X - Transmit Block allocated command.c
+
+y - Transmit Block Relinquished, queue not empty command.c
+Y - Transmit Block Relinquished, queue empty command.c
+
+z - SSB Update interrup.c, reset.c
+Z - Execute SCB command.c, reset.c
diff --git a/private/ntos/ndis/ibmtok2i/makefile b/private/ntos/ndis/ibmtok2i/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/ibmtok2i/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/ibmtok2i/request.c b/private/ntos/ndis/ibmtok2i/request.c
new file mode 100644
index 000000000..a5dcbfd7d
--- /dev/null
+++ b/private/ntos/ndis/ibmtok2i/request.c
@@ -0,0 +1,1346 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ request.c
+
+Abstract:
+
+ This file contains code to implement MiniportQueryInformation and
+ MiniportSetInformation. This driver conforms to the
+ NDIS 3.0 Miniport interface.
+
+Author:
+
+ Kevin Martin (KevinMa) 27-Jan-1994
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+
+--*/
+
+#include <tok162sw.h>
+
+extern
+NDIS_STATUS
+TOK162ChangeAddress(
+ OUT PTOK162_ADAPTER Adapter,
+ IN ULONG Address,
+ IN NDIS_OID Oid,
+ IN USHORT Command,
+ IN BOOLEAN Set
+ );
+
+extern
+NDIS_STATUS
+TOK162SetInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ )
+
+/*++
+
+Routine Description:
+
+ TOK162SetInformation handles a set operation for a
+ single OID.
+
+Arguments:
+
+ MiniportAdapterContext - The adapter that the set is for.
+
+ BytesNeeded - If there is not enough data in OvbBuffer
+ to satisfy the OID, returns the amount of storage needed.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_PENDING
+ NDIS_STATUS_INVALID_LENGTH
+ NDIS_STATUS_INVALID_OID
+
+--*/
+
+{
+ //
+ // Pointer to the TOK162 adapter structure.
+ //
+ PTOK162_ADAPTER Adapter =
+ PTOK162_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ //
+ // Return value from NDIS calls
+ //
+ NDIS_STATUS Status;
+
+ //
+ // Temporary storage for the packet filter
+ //
+ ULONG TempFilter;
+
+ //
+ // If we are in the middle of a reset, return this fact
+ //
+ if (Adapter->ResetInProgress == TRUE) {
+
+ return(NDIS_STATUS_RESET_IN_PROGRESS);
+
+ }
+
+ //
+ // Process request based on the OID
+ //
+ switch (Oid) {
+
+ case OID_802_5_CURRENT_FUNCTIONAL:
+
+ if (InformationBufferLength != TR_LENGTH_OF_FUNCTIONAL) {
+
+ //
+ // The data must be a multiple of the functional
+ // address size.
+ //
+
+ Status = NDIS_STATUS_INVALID_DATA;
+
+ }
+
+ //
+ // Save the address away
+ //
+ NdisMoveMemory(&Adapter->FunctionalAddress,
+ InformationBuffer,
+ InformationBufferLength
+ );
+
+ //
+ // Need to reverse it
+ //
+ Adapter->FunctionalAddress =
+ BYTE_SWAP_ULONG(Adapter->FunctionalAddress);
+
+ VERY_LOUD_DEBUG(DbgPrint("Functional Address is now %08x\n",
+ Adapter->FunctionalAddress);)
+
+ //
+ // Now call the filter package to set up the address if the
+ // functional address has been set in the packet filter.
+ //
+ if (!(Adapter->CurrentPacketFilter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL) &&
+ (Adapter->CurrentPacketFilter & NDIS_PACKET_TYPE_FUNCTIONAL)
+ )
+ {
+ Status = TOK162ChangeAddress(
+ Adapter,
+ Adapter->FunctionalAddress,
+ Oid,
+ CMD_DMA_SET_FUNC_ADDR,
+ TRUE
+ );
+
+ //
+ // Nothing changed with the card, so return SUCCESS
+ //
+ } else {
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ }
+
+ //
+ // Set number of bytes read
+ //
+ *BytesRead = TR_LENGTH_OF_FUNCTIONAL;
+
+ break;
+
+ case OID_802_5_CURRENT_GROUP:
+
+ //
+ // Group addresses and Functional addresses are the same length.
+ //
+ if (InformationBufferLength != TR_LENGTH_OF_FUNCTIONAL) {
+
+ //
+ // The data must be a multiple of the group
+ // address size.
+ //
+ Status = NDIS_STATUS_INVALID_DATA;
+
+ }
+
+ //
+ // Save the address away
+ //
+ NdisMoveMemory(&Adapter->GroupAddress,
+ InformationBuffer,
+ InformationBufferLength
+ );
+
+
+ //
+ // Need to reverse it
+ //
+ Adapter->GroupAddress =
+ BYTE_SWAP_ULONG(Adapter->GroupAddress);
+
+ //
+ // Now call the filter package to set up the address if group
+ // addresses have been set in the packet filter.
+ //
+ if ((Adapter->CurrentPacketFilter & NDIS_PACKET_TYPE_GROUP) != 0) {
+
+ Status = TOK162ChangeAddress(
+ Adapter,
+ Adapter->GroupAddress,
+ Oid,
+ CMD_DMA_SET_GRP_ADDR,
+ TRUE
+ );
+ } else {
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ }
+
+ //
+ // Set number of bytes read
+ //
+ *BytesRead = TR_LENGTH_OF_FUNCTIONAL;
+
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ //
+ // Make sure the new packet filter is the correct size (length)
+ //
+ if (InformationBufferLength != 4) {
+
+ Status = NDIS_STATUS_INVALID_DATA;
+
+ }
+
+ //
+ //
+ TempFilter = *(PULONG)(InformationBuffer);
+ LOUD_DEBUG(DbgPrint("GEN_CURRENT_PACKET_FILTER = %x\n",TempFilter);)
+
+ //
+ // Make sure the new filter is not something we don't support
+ //
+ if (TempFilter & (NDIS_PACKET_TYPE_MULTICAST |
+ NDIS_PACKET_TYPE_ALL_MULTICAST |
+ NDIS_PACKET_TYPE_SMT |
+ NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_MAC_FRAME
+ )) {
+
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+
+ *BytesRead = 4;
+ *BytesNeeded = 0;
+
+ break;
+ }
+
+ if (Adapter->CurrentPacketFilter != TempFilter) {
+
+ Adapter->CurrentPacketFilter = TempFilter;
+
+ //
+ // This is a filter we can deal with. Go change the functional
+ // and group addresses based on the filter.
+ //
+ Status = TOK162ChangeFuncGroup(Adapter);
+
+ } else {
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ *BytesRead = 4;
+ *BytesNeeded = 0;
+
+ }
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ //
+ // We don't change anything, but we accept any value.
+ //
+ *BytesRead = 4;
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ break;
+
+ //
+ // We got an OID that is not settable.
+ //
+ default:
+
+ Status = NDIS_STATUS_INVALID_OID;
+ break;
+ }
+
+ //
+ // If we have a request pending as a result of any work we've done,
+ // mark it.
+ //
+ if (Status == NDIS_STATUS_PENDING) {
+
+ Adapter->RequestInProgress = TRUE;
+
+ }
+
+ return Status;
+}
+
+extern
+NDIS_STATUS
+TOK162ChangeAddress(
+ OUT PTOK162_ADAPTER Adapter,
+ IN ULONG Address,
+ IN NDIS_OID Oid,
+ IN USHORT Command,
+ IN BOOLEAN Set
+ )
+/*++
+
+Routine Description:
+
+ TOK162ChangeAddress will submit a command for either a group or
+ functional address, based on what is passed in.
+
+Arguments:
+
+ Adapter - Structure representing the current adapter
+
+ Address - The ULONG address to send to the card
+
+ Oid - Current Oid (Either functional or group)
+
+ Command - Command to send to card
+
+ Set - Whether to mark the command as a set. If we need to change two
+ addresses (ChangeFuncGroup) as the result of one Oid, we will
+ only do a completion for the one with the set. In the normal
+ case of one address being set, Set will always be TRUE.
+
+Return Value:
+
+ NDIS_STATUS_PENDING
+
+--*/
+{
+ //
+ // Command block pointer
+ //
+ PTOK162_SUPER_COMMAND_BLOCK CommandBlock;
+
+ //
+ // Set the adapter Oid to the current Oid
+ //
+ Adapter->Oid = Oid;
+
+ //
+ // Get a command block
+ //
+ TOK162AcquireCommandBlock(Adapter,
+ &CommandBlock
+ );
+
+ //
+ // Set the command block based on the parameters passed in
+ //
+ CommandBlock->Set = Set;
+ CommandBlock->NextCommand = NULL;
+ CommandBlock->Hardware.Status = 0;
+ CommandBlock->Hardware.NextPending = TOK162_NULL;
+ CommandBlock->Hardware.CommandCode = Command;
+ CommandBlock->Hardware.ImmediateData = Address;
+
+ //
+ // Display the address about to be set on the debugger.
+ //
+ LOUD_DEBUG(DbgPrint("Address being set is %08x\n",
+ CommandBlock->Hardware.ImmediateData);)
+
+ //
+ // Indicate that a request is in progress
+ //
+ Adapter->RequestInProgress = TRUE;
+
+ //
+ // Make this request be in progress.
+ //
+ TOK162SubmitCommandBlock(Adapter, CommandBlock);
+
+ //
+ // Complete the request when the interrupt comes in.
+ //
+ return NDIS_STATUS_PENDING;
+}
+
+
+NDIS_STATUS
+TOK162QueryInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+)
+
+/*++
+
+Routine Description:
+
+ The TOK162QueryInformation process a Query request for specific
+ NDIS_OIDs
+
+Arguments:
+
+ MiniportAdapterContext - a pointer to the adapter.
+
+ Oid - the NDIS_OID to process.
+
+ InformationBuffer - a pointer into the
+ NdisRequest->InformationBuffer into which
+ we store the result of the query
+
+ InformationBufferLength - a pointer to the number of bytes left in the
+ InformationBuffer.
+
+ BytesWritten - a pointer to the number of bytes written into
+ the InformationBuffer.
+
+ BytesNeeded - If there is not enough room in the information
+ buffer this will contain the number of bytes
+ needed to complete the request.
+
+Return Value:
+
+ The function value is the status of the operation.(NDIS_STATUS_PENDING)
+
+--*/
+
+{
+ //
+ // Command block used for the request.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK CommandBlock;
+
+ //
+ // Adapter structure for the current card
+ //
+ PTOK162_ADAPTER Adapter =
+ PTOK162_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ NDIS_STATUS Status = NDIS_STATUS_PENDING;
+
+ //
+ // If we are in the middle of a reset, return this fact
+ //
+ if (Adapter->ResetInProgress == TRUE)
+ {
+ return(NDIS_STATUS_RESET_IN_PROGRESS);
+ }
+
+ //
+ // Save the information passed in
+ //
+ Adapter->BytesWritten = BytesWritten;
+
+ Adapter->BytesNeeded = BytesNeeded;
+
+ Adapter->Oid = Oid;
+
+ Adapter->InformationBuffer = InformationBuffer;
+
+ Adapter->InformationBufferLength = InformationBufferLength;
+
+ //
+ // Figure out the specific command based on the OID
+ //
+ switch(Oid)
+ {
+ case OID_802_5_CURRENT_FUNCTIONAL:
+
+ if (InformationBufferLength != TR_LENGTH_OF_FUNCTIONAL)
+ {
+ //
+ // The data must be a multiple of the functional
+ // address size.
+ //
+ Status = NDIS_STATUS_INVALID_DATA;
+ }
+ else
+ {
+ //
+ // Save the address away
+ //
+ NdisMoveMemory(
+ InformationBuffer,
+ &Adapter->FunctionalAddress,
+ InformationBufferLength);
+
+ Status = NDIS_STATUS_SUCCESS;
+ }
+
+ break;
+
+ case OID_802_5_CURRENT_GROUP:
+
+ if (InformationBufferLength != TR_LENGTH_OF_FUNCTIONAL)
+ {
+ //
+ // The data must be a multiple of the group
+ // address size.
+ //
+ Status = NDIS_STATUS_INVALID_DATA;
+ }
+ else
+ {
+ //
+ // Save the address away
+ //
+ NdisMoveMemory(
+ InformationBuffer,
+ &Adapter->GroupAddress,
+ InformationBufferLength);
+
+ Status = NDIS_STATUS_SUCCESS;
+ }
+
+ break;
+
+ //
+ // If the permanent address is requested, we need to read from
+ // the adapter at the permanent address offset.
+ //
+ case OID_802_5_PERMANENT_ADDRESS:
+
+ //
+ // Get a command block
+ //
+ TOK162AcquireCommandBlock(Adapter, &CommandBlock);
+
+ //
+ // Notify that this is from a set
+ //
+ CommandBlock->Set = TRUE;
+
+ //
+ // Setup the common fields of the command block.
+ //
+ CommandBlock->NextCommand = NULL;
+ CommandBlock->Hardware.Status = 0;
+ CommandBlock->Hardware.NextPending = TOK162_NULL;
+
+ //
+ // Fill in the adapter buffer area with the information to
+ // obtain the permanent address.
+ //
+ Adapter->AdapterBuf->DataCount = BYTE_SWAP(0x0006);
+
+ Adapter->AdapterBuf->DataAddress =
+ BYTE_SWAP(Adapter->UniversalAddress);
+
+ //
+ // Set the command block for the read adapter command.
+ //
+ CommandBlock->Hardware.CommandCode = CMD_DMA_READ;
+
+ CommandBlock->Hardware.ParmPointer =
+ NdisGetPhysicalAddressLow(Adapter->AdapterBufPhysical);
+
+ break;
+
+ //
+ // For any of the current addresses (functional, group, network)
+ // we will want to read the current addresses as the adapter has
+ // them recorded.
+ //
+ case OID_802_5_CURRENT_ADDRESS:
+
+ //
+ // Get a command block
+ //
+ TOK162AcquireCommandBlock(Adapter, &CommandBlock);
+
+ //
+ // Notify that this is from a set
+ //
+ CommandBlock->Set = TRUE;
+
+ //
+ // Setup the common fields of the command block.
+ //
+ CommandBlock->NextCommand = NULL;
+ CommandBlock->Hardware.Status = 0;
+ CommandBlock->Hardware.NextPending = TOK162_NULL;
+
+ //
+ // Set up the adapter buffer to get the current addresses.
+ //
+ Adapter->AdapterBuf->DataCount = BYTE_SWAP(0x000e);
+
+ Adapter->AdapterBuf->DataAddress =
+ BYTE_SWAP(Adapter->AdapterAddresses);
+
+ //
+ // Set the command block for the read adapter command.
+ //
+ CommandBlock->Hardware.CommandCode = CMD_DMA_READ;
+
+ CommandBlock->Hardware.ParmPointer =
+ NdisGetPhysicalAddressLow(Adapter->AdapterBufPhysical);
+
+ break;
+
+ //
+ // For any other OID, we read the errorlog to help make sure we
+ // don't get a counter overflow and lose information.
+ //
+ default:
+
+ //
+ // Get a command block
+ //
+ TOK162AcquireCommandBlock(Adapter, &CommandBlock);
+
+ //
+ // Notify that this is from a set
+ //
+ CommandBlock->Set = TRUE;
+
+ //
+ // Setup the common fields of the command block.
+ //
+ CommandBlock->NextCommand = NULL;
+ CommandBlock->Hardware.Status = 0;
+ CommandBlock->Hardware.NextPending = TOK162_NULL;
+
+ //
+ // Set the command block for a read error log command.
+ //
+ CommandBlock->Hardware.CommandCode = CMD_DMA_READ_ERRLOG;
+
+ CommandBlock->Hardware.ParmPointer =
+ NdisGetPhysicalAddressLow(Adapter->ErrorLogPhysical);
+
+ break;
+ }
+
+ //
+ // If we need to process the command block...
+ //
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ //
+ // Now that we're set up, let's do it!
+ //
+ Adapter->RequestInProgress = TRUE;
+
+ //
+ // Submit the command to the card
+ //
+ TOK162SubmitCommandBlock(Adapter, CommandBlock);
+ }
+
+ return(Status);
+}
+
+VOID
+TOK162FinishQueryInformation(
+ IN PTOK162_ADAPTER Adapter
+)
+
+/*++
+
+Routine Description:
+
+ The TOK162FinishQueryInformation finish processing a Query request for
+ NDIS_OIDs that are specific about the Driver.
+
+Arguments:
+
+ Adapter - a pointer to the adapter.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+//
+// The list of Oid's that we support with this driver.
+//
+static
+NDIS_OID TOK162GlobalSupportedOids[] = {
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+ OID_GEN_RCV_CRC_ERROR,
+ OID_GEN_TRANSMIT_QUEUE_LENGTH,
+ OID_802_5_PERMANENT_ADDRESS,
+ OID_802_5_CURRENT_ADDRESS,
+ OID_802_5_CURRENT_FUNCTIONAL,
+ OID_802_5_CURRENT_GROUP,
+ OID_802_5_LAST_OPEN_STATUS,
+ OID_802_5_CURRENT_RING_STATUS,
+ OID_802_5_CURRENT_RING_STATE,
+ OID_802_5_LINE_ERRORS,
+ OID_802_5_LOST_FRAMES,
+ OID_802_5_BURST_ERRORS,
+ OID_802_5_FRAME_COPIED_ERRORS,
+ OID_802_5_TOKEN_ERRORS
+ };
+
+ //
+ // Variable to keep track of the bytes written out.
+ //
+ PUINT BytesWritten = Adapter->BytesWritten;
+
+ //
+ // Variable to keep track of the bytes needed
+ //
+ PUINT BytesNeeded = Adapter->BytesNeeded;
+
+ //
+ // The actual Oid that just finished.
+ //
+ NDIS_OID Oid = Adapter->Oid;
+
+ //
+ // Result buffer.
+ //
+ PVOID InformationBuffer = Adapter->InformationBuffer;
+
+ //
+ // Length of result buffer.
+ //
+ UINT InformationBufferLength = Adapter->InformationBufferLength;
+
+ //
+ // The medium supported by this driver.
+ //
+ NDIS_MEDIUM Medium = NdisMedium802_5;
+
+ //
+ // Generic repository for ULONG results
+ //
+ UINT GenericUlong;
+
+ //
+ // Generic repository for USHORT results
+ //
+ USHORT GenericUShort;
+
+ //
+ // Generic repository for character array results
+ //
+ UCHAR GenericArray[6];
+
+ //
+ // Pointer to source of result Common variables for pointing to result of query
+ //
+ PVOID MoveSource = (PVOID)(&GenericUlong);
+
+ //
+ // Number of bytes to be moved, defaulting to the size of a ULONG.
+ //
+ ULONG MoveBytes = sizeof(ULONG);
+
+ //
+ // Hardware Status
+ //
+ NDIS_HARDWARE_STATUS HardwareStatus;
+
+ //
+ // Return value of NDIS calls
+ //
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ //
+ // Initialize bytes written and bytes needed
+ //
+ *BytesWritten = 0;
+ *BytesNeeded = 0;
+
+ //
+ // Switch on the Oid
+ //
+ switch(Oid){
+
+ //
+ // The MAC options represents the options our driver supports/needs.
+ //
+ case OID_GEN_MAC_OPTIONS:
+
+ //
+ // We don't pend transfers.
+ // we copy lookahead data, and we have serialized receives.
+ //
+ GenericUlong = (ULONG)(NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
+ NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
+ NDIS_MAC_OPTION_RECEIVE_SERIALIZED
+ );
+
+ break;
+
+ //
+ // We return the list of Oid's we support (list above)
+ //
+ case OID_GEN_SUPPORTED_LIST:
+
+ //
+ // Point to the beginning of the list.
+ //
+ MoveSource = (PVOID)(TOK162GlobalSupportedOids);
+
+ //
+ // We have to move the whole list.
+ //
+ MoveBytes = sizeof(TOK162GlobalSupportedOids);
+
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+
+ //
+ // If we have a reset in progress, the hardware status is
+ // set to reset. Otherwise, we return that we are ready.
+ //
+ if (Adapter->ResetInProgress) {
+
+ HardwareStatus = NdisHardwareStatusReset;
+
+ } else {
+
+ HardwareStatus = NdisHardwareStatusReady;
+
+ }
+
+ //
+ // Set the pointer to the HardwareStatus variable
+ //
+ MoveSource = (PVOID)(&HardwareStatus);
+
+ //
+ // Move the size of hardware status bytes
+ //
+ MoveBytes = sizeof(NDIS_HARDWARE_STATUS);
+
+ break;
+
+ //
+ // Simply indicate that we support TokenRing.
+ //
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+
+ MoveSource = (PVOID) (&Medium);
+ MoveBytes = sizeof(NDIS_MEDIUM);
+ break;
+
+ //
+ // The maximum lookahead, current lookahead, and frame size are
+ // static and are equal to the maximum frame size minus the header
+ // size.
+ //
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ GenericUlong = Adapter->ReceiveBufferSize - TOK162_HEADER_SIZE;
+ break;
+
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+
+ GenericUlong = Adapter->ReceiveBufferSize - 14;
+ break;
+
+ //
+ // Total sizes are easier because we don't have to subtract out the
+ // header size.
+ //
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+ GenericUlong = Adapter->ReceiveBufferSize;
+ break;
+
+
+ //
+ // Link speed is either 4MBPS or 16MBPS depending on which we're
+ // running on.
+ //
+ case OID_GEN_LINK_SPEED:
+
+ GenericUlong = (Adapter->Running16Mbps == TRUE) ? (ULONG)160000 :
+ (ULONG)40000;
+
+ break;
+
+
+ //
+ // Transmit buffer space is found by multiplying the size of the
+ // transmit buffers (same as receive buffer size) by the number
+ // of transmit lists.
+ //
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+
+ GenericUlong = (ULONG)Adapter->ReceiveBufferSize *
+ Adapter->NumberOfTransmitLists;
+
+ break;
+
+ //
+ // Receive buffer space is equal to multiplying the size of receive
+ // buffers by the number of receive lists.
+ //
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+
+ GenericUlong = (ULONG)Adapter->ReceiveBufferSize *
+ RECEIVE_LIST_COUNT;
+
+ break;
+
+
+ //
+ // The vendor ID is calculated by ANDing the current network address
+ // with 0xFFFFFF00.
+ //
+ case OID_GEN_VENDOR_ID:
+
+ //
+ // Get the current network address.
+ //
+ GenericUlong = 0;
+ NdisMoveMemory(
+ (PVOID)&GenericUlong,
+ Adapter->CurrentAddress,
+ 3
+ );
+ GenericUlong &= 0xFFFFFF00;
+
+ MoveSource = (PVOID)(&GenericUlong);
+
+ MoveBytes = sizeof(GenericUlong);
+
+ break;
+
+ //
+ // Return our vendor string
+ //
+ case OID_GEN_VENDOR_DESCRIPTION:
+
+ MoveSource = (PVOID)"IBM TokenRing 16/4 II Adapter ";
+
+ MoveBytes = 30;
+
+ break;
+
+ //
+ // Return our version (3.10) number
+ //
+ case OID_GEN_DRIVER_VERSION:
+
+ GenericUShort = (USHORT)0x0300;
+
+ MoveSource = (PVOID)(&GenericUShort);
+
+ MoveBytes = sizeof(GenericUShort);
+
+ break;
+
+ //
+ // Return the permanent address
+ //
+ case OID_802_5_PERMANENT_ADDRESS:
+
+ TR_COPY_NETWORK_ADDRESS(
+ (PCHAR)GenericArray,
+ Adapter->NetworkAddress
+ );
+
+ MoveSource = (PVOID)(GenericArray);
+
+ MoveBytes = TR_LENGTH_OF_ADDRESS;
+
+ break;
+
+ //
+ // Return the current address.
+ //
+ case OID_802_5_CURRENT_ADDRESS:
+
+ TR_COPY_NETWORK_ADDRESS(
+ (PCHAR)GenericArray,
+ Adapter->CurrentAddress
+ );
+
+ MoveSource = (PVOID)(GenericArray);
+
+ MoveBytes = TR_LENGTH_OF_ADDRESS;
+
+ break;
+
+ //
+ // Return the current functional address.
+ //
+ case OID_802_5_CURRENT_FUNCTIONAL:
+
+ //
+ // Get the address stored in the adapter structure
+ //
+ GenericUlong = (ULONG)Adapter->FunctionalAddress;
+
+ //
+ // Now we need to reverse the crazy thing.
+ //
+ GenericUlong = BYTE_SWAP_ULONG(GenericUlong);
+
+ break;
+
+ //
+ // Return the current group address.
+ //
+ case OID_802_5_CURRENT_GROUP:
+
+ //
+ // Get the address stored in the adapter structure
+ //
+ GenericUlong = (ULONG)Adapter->GroupAddress;
+
+ //
+ // Now we need to reverse the crazy thing.
+ //
+ GenericUlong = BYTE_SWAP_ULONG(GenericUlong);
+
+ break;
+
+ //
+ // Return the number of good transmits
+ //
+ case OID_GEN_XMIT_OK:
+
+ GenericUlong = (ULONG) Adapter->GoodTransmits;
+
+ break;
+
+ //
+ // Return the number of good receives
+ //
+ case OID_GEN_RCV_OK:
+
+ GenericUlong = (ULONG) Adapter->GoodReceives;
+
+ break;
+
+ //
+ // Return the number of transmit errors
+ //
+ case OID_GEN_XMIT_ERROR:
+
+ GenericUlong = (ULONG) Adapter->BadTransmits;
+
+ break;
+
+ //
+ // Return the number of receive errors
+ //
+ case OID_GEN_RCV_ERROR:
+
+ GenericUlong = (ULONG) 0;
+
+ break;
+
+ //
+ // Return the number of congestion errors that have occurred
+ //
+ case OID_GEN_RCV_NO_BUFFER:
+
+ GenericUlong = (ULONG) Adapter->ReceiveCongestionError;
+
+ break;
+
+ //
+ // Return the number of CRC errors (receives)
+ //
+ case OID_GEN_RCV_CRC_ERROR:
+
+ GenericUlong = (ULONG) 0;
+
+ break;
+
+ //
+ // Return the current transmit queue length
+ //
+ case OID_GEN_TRANSMIT_QUEUE_LENGTH:
+
+ GenericUlong = (ULONG) Adapter->TransmitsQueued;
+
+ break;
+
+ //
+ // Return the number of Line errors
+ //
+ case OID_802_5_LINE_ERRORS:
+
+ GenericUlong = (ULONG) Adapter->LineError;
+
+ break;
+
+ //
+ // Return the last ring status.
+ //
+ case OID_802_5_CURRENT_RING_STATUS:
+
+ GenericUlong = (ULONG)Adapter->LastNotifyStatus;
+
+ break;
+
+ //
+ // Return the current ring state.
+ //
+ case OID_802_5_CURRENT_RING_STATE:
+
+ GenericUlong = (ULONG)Adapter->CurrentRingState;
+
+ break;
+
+ //
+ // Last open error code.
+ //
+ case OID_802_5_LAST_OPEN_STATUS:
+
+ GenericUlong = (ULONG)(NDIS_STATUS_TOKEN_RING_OPEN_ERROR |
+ (NDIS_STATUS)Adapter->OpenErrorCode);
+
+ break;
+
+ //
+ // Return the number of Lost Frames
+ //
+ case OID_802_5_LOST_FRAMES:
+
+ GenericUlong = (ULONG) Adapter->LostFrameError;
+
+ break;
+
+ //
+ // Return the number of Burst errors
+ //
+ case OID_802_5_BURST_ERRORS:
+
+ GenericUlong = (ULONG) Adapter->BurstError;
+
+ break;
+
+ //
+ // Return the number of Frame Copied Errors
+ //
+ case OID_802_5_FRAME_COPIED_ERRORS:
+
+ GenericUlong = (ULONG) Adapter->FrameCopiedError;
+
+ break;
+
+ //
+ // Return the number of Token errors
+ //
+ case OID_802_5_TOKEN_ERRORS:
+
+ GenericUlong = (ULONG) Adapter->TokenError;
+
+ break;
+ //
+ // Must be an unsupported Oid
+ //
+ default:
+
+ Status = NDIS_STATUS_INVALID_OID;
+
+ break;
+ }
+
+
+ //
+ // If there weren't any errors, copy the bytes indicated above.
+ //
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ //
+ // Make sure we don't have too much to move. If so, return an error.
+ //
+ if (MoveBytes > InformationBufferLength) {
+
+ //
+ // Not enough room in InformationBuffer. Punt
+ //
+
+ *BytesNeeded = MoveBytes;
+
+ Status = NDIS_STATUS_INVALID_LENGTH;
+
+ //
+ // Do the copy
+ //
+ } else {
+
+ *BytesWritten = MoveBytes;
+
+ if (MoveBytes > 0) {
+
+ NdisMoveMemory(
+ InformationBuffer,
+ MoveSource,
+ MoveBytes
+ );
+ }
+ }
+ }
+
+ //
+ // We're finished with the request.
+ //
+ Adapter->RequestInProgress = FALSE;
+
+ //
+ // Indicate the result to the protocol(s)
+ //
+ NdisMQueryInformationComplete(
+ Adapter->MiniportAdapterHandle,
+ Status
+ );
+
+ return;
+}
+
+
+NDIS_STATUS
+TOK162ChangeFuncGroup(
+ IN PTOK162_ADAPTER Adapter
+)
+/*++
+
+Routine Description:
+
+ The TOK162ChangeFuncGroup modifies the appropriate adapter
+ address (functional, group, or both). This routine submits two command
+ blocks representing one call to the system. Therefore, only the group
+ address change performs a status indication (the Set variable).
+
+Arguments:
+
+ Adapter - a pointer to the adapter.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ //
+ // Address to be set. Used for both functional and group addresses.
+ //
+ ULONG Address;
+
+ //
+ // Variable to hold the return value of NDIS calls
+ //
+ NDIS_STATUS Status;
+
+ //
+ // First check the functional address status, including the all
+ // functional address.
+ //
+ if ((Adapter->CurrentPacketFilter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL) != 0) {
+
+ Address = 0x7FFFFFFF;
+
+ } else if ((Adapter->CurrentPacketFilter & NDIS_PACKET_TYPE_FUNCTIONAL) != 0) {
+
+ Address = Adapter->FunctionalAddress;
+
+ } else {
+
+ Address = 0;
+
+ }
+
+ //
+ // Change the functional address on the card.
+ //
+ Status = TOK162ChangeAddress(
+ Adapter,
+ Address,
+ OID_802_5_CURRENT_FUNCTIONAL,
+ CMD_DMA_SET_FUNC_ADDR,
+ FALSE
+ );
+
+ //
+ // Now check the group address status
+ //
+ if ((Adapter->CurrentPacketFilter & NDIS_PACKET_TYPE_GROUP) != 0) {
+
+ Address = Adapter->GroupAddress;
+
+ } else {
+
+ Address = 0;
+
+ }
+
+ //
+ // Change the group address on the card.
+ //
+ Status = TOK162ChangeAddress(
+ Adapter,
+ Address,
+ OID_802_5_CURRENT_GROUP,
+ CMD_DMA_SET_GRP_ADDR,
+ TRUE
+ );
+
+ return(Status);
+}
diff --git a/private/ntos/ndis/ibmtok2i/reset.c b/private/ntos/ndis/ibmtok2i/reset.c
new file mode 100644
index 000000000..ca967de06
--- /dev/null
+++ b/private/ntos/ndis/ibmtok2i/reset.c
@@ -0,0 +1,1918 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ reset.c
+
+Abstract:
+
+ This is the file containing the reset code for the IBM Token Ring 16/4 II
+ ISA adapter. This driver conforms to the NDIS 3.0 Miniport interface.
+
+Author:
+
+ Kevin Martin (KevinMa) 1-Feb-1994
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+--*/
+
+#include <tok162sw.h>
+
+#pragma NDIS_INIT_FUNCTION(TOK162InitialInit)
+
+//
+// Declarations for functions private to this file.
+//
+extern
+VOID
+TOK162ProcessRequestQueue(
+ IN PTOK162_ADAPTER Adapter,
+ IN BOOLEAN StatisticsUpdated
+ );
+
+VOID
+TOK162WriteInitializationBlock(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+VOID
+TOK162SetInitializationBlock(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+VOID
+TOK162SetInitializationBlockAndInit(
+ IN PTOK162_ADAPTER Adapter,
+ OUT PNDIS_STATUS Status
+ );
+
+NDIS_STATUS
+TOK162ChangeCurrentAddress(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+VOID
+TOK162ResetCommandBlocks(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+BOOLEAN
+CheckResetResults(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+NDIS_STATUS
+CheckInitResults(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+VOID
+TOK162GetAdapterOffsets(
+ IN PTOK162_ADAPTER Adapter
+ );
+VOID
+TOK162ResetReceiveQueue(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+VOID
+TOK162AbortSend(
+ IN PTOK162_ADAPTER Adapter,
+ IN PTOK162_SUPER_COMMAND_BLOCK CurrentCommandBlock
+ );
+
+extern
+void
+TOK162SendCommandBlock(
+ IN PTOK162_ADAPTER Adapter,
+ IN PTOK162_SUPER_COMMAND_BLOCK CommandBlock
+ );
+
+
+
+
+BOOLEAN
+TOK162InitialInit(
+ IN PTOK162_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets up the initial init of the driver.
+
+Arguments:
+
+ Adapter - The adapter structure for the hardware.
+
+Return Value:
+
+ TRUE if successful, FALSE if not.
+
+--*/
+
+{
+ //
+ // Holds status returned from NDIS calls.
+ //
+ NDIS_STATUS Status;
+
+ //
+ // First we make sure that the device is stopped.
+ //
+ TOK162DisableInterrupt(Adapter);
+
+ //
+ // Set flags indicating we are doing the initial init
+ //
+ Adapter->InitialInit = TRUE;
+ Adapter->ResetState = InitialInit;
+ Adapter->InitialOpenComplete = FALSE;
+ Adapter->InitialReceiveSent = FALSE;
+ Adapter->ResetInProgress = TRUE;
+
+ //
+ // Initialize the interrupt.
+ //
+ Status = NdisMRegisterInterrupt(
+ &Adapter->Interrupt,
+ Adapter->MiniportAdapterHandle,
+ Adapter->InterruptLevel,
+ Adapter->InterruptLevel,
+ FALSE,
+ FALSE,
+ NdisInterruptLatched
+ );
+
+ //
+ // Report the status of the interrupt registering to the debugger
+ //
+ VERY_LOUD_DEBUG(DbgPrint(
+ "IBMTOK2I!Status from Registering Interrupt -%u was %u\n",
+ Adapter->InterruptLevel,
+ Status);)
+
+ //
+ // If the interrupt register failed, mark the interrupt level at 0 so
+ // we know not to do a deregister.
+ //
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ Adapter->InterruptLevel = 0;
+ return FALSE;
+
+ }
+
+ //
+ // Initialize the open command to zeros
+ //
+ NdisZeroMemory(Adapter->Open,sizeof(OPEN_COMMAND));
+
+ //
+ // Set up the Open command block
+ //
+
+ //
+ // Set the options
+ //
+ Adapter->Open->Options = OPEN_OPTION_CONTENDER;
+
+ //
+ // Set the receive and transmit list sizes as well as the buffer size
+ //
+ Adapter->Open->ReceiveListSize = BYTE_SWAP(OPEN_RECEIVE_LIST_SIZE);
+ Adapter->Open->TransmitListSize = BYTE_SWAP(OPEN_TRANSMIT_LIST_SIZE);
+ Adapter->Open->BufferSize = BYTE_SWAP(OPEN_BUFFER_SIZE);
+
+ //
+ // Make sure the adapter can handle one entire frame
+ //
+ Adapter->Open->TransmitBufCountMin =
+ (Adapter->ReceiveBufferSize / OPEN_BUFFER_SIZE) + 1;
+
+ Adapter->Open->TransmitBufCountMax = Adapter->Open->TransmitBufCountMin;
+
+ //
+ // Reset the adapter
+ //
+ TOK162ResetAdapter(Adapter);
+
+ //
+ // Reenable interrupts
+ //
+ TOK162EnableInterrupt(Adapter);
+
+ //
+ // Go through the reset stages
+ //
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2I!Calling TOK162ResetHandler\n");)
+
+ TOK162ResetHandler(NULL,Adapter,NULL,NULL);
+
+ VERY_LOUD_DEBUG(DbgPrint("IBMTOK2I!Back from TOK162ResetHandler\n");)
+
+ //
+ // The Initial init is done.
+ //
+ Adapter->InitialInit = FALSE;
+
+ //
+ // Check the reset status and return TRUE if successful, FALSE if not.
+ //
+ if (Adapter->ResetResult == NDIS_STATUS_SUCCESS) {
+
+ return TRUE;
+
+ } else {
+
+ return FALSE;
+
+ }
+
+}
+
+
+VOID
+TOK162EnableAdapter(
+ IN NDIS_HANDLE Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to start an already initialized TOK162.
+
+Arguments:
+
+ Context - The adapter for the TOK162.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Pointer to an adapter structure. Makes Context (passed in value)
+ // a structure we can deal with.
+ //
+ PTOK162_ADAPTER Adapter = (PTOK162_ADAPTER)Context;
+
+ //
+ // Enable the adapter
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_ADAPTER_ENABLE,
+ 0x2525
+ );
+
+}
+
+
+VOID
+TOK162EnableInterrupt(
+ IN NDIS_HANDLE Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to turn on the interrupt mask.
+
+Arguments:
+
+ Context - The adapter for the TOK162.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Pointer to an adapter structure. Makes Context (passed in value)
+ // a structure we can deal with.
+ //
+ PTOK162_ADAPTER Adapter = (PTOK162_ADAPTER)Context;
+
+ //
+ // Enable further interrupts.
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_SWITCH_INT_ENABLE,
+ 0x2525
+ );
+
+}
+
+VOID
+TOK162DisableInterrupt(
+ IN NDIS_HANDLE Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to turn off the interrupt mask.
+
+Arguments:
+
+ Context - The adapter for the TOK162.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Pointer to an adapter structure. Makes Context (passed in value)
+ // a structure we can deal with.
+ //
+ PTOK162_ADAPTER Adapter = (PTOK162_ADAPTER)Context;
+
+ //
+ // Disable the adapter interrupt.
+ //
+ WRITE_ADAPTER_USHORT(
+ Adapter,
+ PORT_OFFSET_SWITCH_INT_DISABLE,
+ 0x2525
+ );
+
+}
+
+VOID
+TOK162ResetAdapter(
+ IN PTOK162_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to reset the adapter.
+
+Arguments:
+
+ Adapter - The TOK162 adapter to reset.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Mark the current ring state as closed (we are going to be removed
+ // from the ring by doing the reset).
+ //
+
+ Adapter->CurrentRingState = NdisRingStateClosed;
+
+ //
+ // This is very simple with this adapter. We simply issue a reset
+ // command right here and this will stop the chip.
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_ADAPTER_RESET,
+ 0x2525
+ );
+
+ //
+ // Allow the adapter to finish completing the reset
+ //
+ NdisStallExecution(50);
+
+ //
+ // Enable the adapter to allow us to access the adapter's registers.
+ //
+ TOK162EnableAdapter(Adapter);
+
+ //
+ // Allow the adapter to finish completing the reset
+ //
+ NdisStallExecution(50);
+
+}
+
+VOID
+TOK162SetInitializationBlock(
+ IN PTOK162_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine simply fills the Initialization block
+ with the information necessary for initialization.
+
+ NOTE: this routine assumes a single thread of execution is accessing
+ the particular adapter.
+
+Arguments:
+
+ Adapter - The adapter which holds the initialization block
+ to initialize.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ //
+ // Pointer to the initialization block
+ //
+ PADAPTER_INITIALIZATION Initialization = Adapter->InitializationBlock;
+
+ //
+ // Initialize the init block to zeros
+ //
+ NdisZeroMemory(
+ Initialization,
+ sizeof(ADAPTER_INITIALIZATION)
+ );
+
+ //
+ // Set the initializtion options as follows:
+ // Reserved bit must be on
+ // DMA Burst mode (versus cyclical) for the SSB/SCB
+ // DMA Burst mode (versus cyclical) for the xmit/rcv lists
+ // DMA Burst mode (versus cyclical) for the xmit/rcv status
+ // DMA Burst mode (versus cyclical) for the receive buffers
+ // DMA Burst mode (versus cyclical) for the transmit buffers
+ // Don't allow Early Token Release
+ //
+ Initialization->Options = INIT_OPTIONS_RESERVED |
+ INIT_OPTIONS_SCBSSB_BURST |
+ INIT_OPTIONS_LIST_BURST |
+ INIT_OPTIONS_LIST_STATUS_BURST |
+ INIT_OPTIONS_RECEIVE_BURST |
+ INIT_OPTIONS_XMIT_BURST |
+ INIT_OPTIONS_DISABLE_ETR;
+
+ //
+ // If we are running at 16MBPS, OR in this fact.
+ //
+ if (Adapter->Running16Mbps == TRUE) {
+
+ Initialization->Options |= INIT_OPTIONS_SPEED_16;
+
+ }
+
+ //
+ // Set the receive and transmit burst sizes to the max.
+ //
+ Initialization->ReceiveBurstSize = TOK162_BURST_SIZE;
+ Initialization->TransmitBurstSize = TOK162_BURST_SIZE;
+
+ //
+ // Set the DMA retries (values found in TOK162HW.H)
+ //
+ Initialization->DMAAbortThresholds = TOK162_DMA_RETRIES;
+
+ //
+ // Set the pointers to the SCB and SSB blocks.
+ //
+ Initialization->SCBHigh = HIGH_WORD(
+ NdisGetPhysicalAddressLow(Adapter->ScbPhysical));
+
+ Initialization->SCBLow = LOW_WORD(
+ NdisGetPhysicalAddressLow(Adapter->ScbPhysical));
+
+ Initialization->SSBHigh = HIGH_WORD(
+ NdisGetPhysicalAddressLow(Adapter->SsbPhysical));
+
+ Initialization->SSBLow = LOW_WORD(
+ NdisGetPhysicalAddressLow(Adapter->SsbPhysical));
+}
+
+
+VOID
+TOK162SetInitializationBlockAndInit(
+ IN PTOK162_ADAPTER Adapter,
+ OUT PNDIS_STATUS Status
+ )
+
+/*++
+
+Routine Description:
+
+ It is this routine's responsibility to make sure that the
+ Initialization block is filled and the adapter is initialized
+ and started.
+
+Arguments:
+
+ Adapter - The adapter whose hardware is to be initialized.
+ Status - Result of the Init
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ //
+ // Simple iterative variable to keep track of the number of retries.
+ //
+ USHORT Retries;
+
+ //
+ // Check to make sure Reset went OK
+ //
+ if (Adapter->InitialInit == TRUE) {
+
+ Retries = 0;
+
+ while ((CheckResetResults(Adapter) == FALSE) && (Retries++ < 3)) {
+
+ TOK162ResetAdapter(Adapter);
+
+ }
+
+ if (Retries == 3) {
+
+ *Status = NDIS_STATUS_DEVICE_FAILED;
+
+ return;
+
+ }
+
+ }
+
+ //
+ // Reset the receive queue, the command block queue, and the transmit
+ // queue.
+ //
+ TOK162ResetReceiveQueue(Adapter);
+ TOK162ResetCommandBlocks(Adapter);
+ TOK162ResetVariables(Adapter);
+
+ //
+ // Fill in the adapter's initialization block.
+ //
+ VERY_LOUD_DEBUG(DbgPrint("TOK162!Setting init block\n");)
+
+ TOK162SetInitializationBlock(Adapter);
+
+ //
+ // Write the initialization sequence to the adapter
+ //
+ VERY_LOUD_DEBUG(DbgPrint("TOK162!Writing Init block to adapter\n");)
+
+ TOK162WriteInitializationBlock(Adapter);
+
+ //
+ // Check the results
+ //
+ if (Adapter->InitialInit == TRUE) {
+
+ VERY_LOUD_DEBUG(DbgPrint("TOK162!Checking init results\n");)
+
+ *Status = CheckInitResults(Adapter);
+
+ }
+
+ return;
+
+}
+
+
+VOID
+TOK162ResetHandler(
+ IN PVOID SystemSpecific1,
+ IN PTOK162_ADAPTER Adapter,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+
+/*++
+
+Routine Description:
+
+ Continue the reset given the current reset state (Adapter->ResetState).
+
+Arguments:
+ SystemSpecific1 - Not used.
+ Adapter - The adapter whose hardware is being reset.
+ SystemSpecific2 - Not used.
+ SystemSpecific3 - Not used.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Holds the return value from NDIS calls.
+ //
+ NDIS_STATUS Status;
+
+ //
+ // Variable for the number of retries.
+ //
+ USHORT Retries;
+
+ //
+ // Holds the result of the receive command.
+ //
+ BOOLEAN ReceiveResult;
+
+ //
+ // Initialize retries to 0.
+ //
+ Retries = 0;
+
+ //
+ // Cancel the reset timer
+ //
+ NdisMCancelTimer(&(Adapter->ResetTimer),&ReceiveResult);
+
+ //
+ // Based on the current Adapter->ResetState, proceed with the reset.
+ //
+ switch(Adapter->ResetState) {
+
+ //
+ // The initialinit case means we are at the beginning and do not
+ // run off of interrupts. Everything is polled and we continue until
+ // we are finished with the reset, successful or not.
+ //
+ case InitialInit:
+
+ //
+ // For up to 3 times, try to init the chipset.
+ //
+ do {
+
+ TOK162SetInitializationBlockAndInit(Adapter,&Status);
+ Retries++;
+
+ } while ((Status != NDIS_STATUS_SUCCESS) && (Retries < 3));
+
+ //
+ // If everything went ok, get the adapter information offsets
+ // and do the open/receive combo.
+ //
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ TOK162GetAdapterOffsets(Adapter);
+
+ //
+ // Do the open and if successful wait for the receive to
+ // complete (Status is already set to successful). If
+ // there was a problem, though, we need to set the error
+ // code.
+ //
+ if (DoTheOpen(Adapter) != TRUE) {
+
+ Status = NDIS_STATUS_FAILURE;
+
+ } else {
+
+ while (Adapter->InitialReceiveSent == FALSE) {
+
+ NdisStallExecution(500);
+
+ }
+
+ }
+
+ }
+
+ //
+ // Do the reset indications
+ //
+ TOK162DoResetIndications(Adapter,Status);
+
+ break;
+
+ //
+ // CheckReset is the first stage of a non-init reset. Because of
+ // the retry mechanism, CheckReset and CheckResetRetry have the same
+ // entry point logically with the exception of the resetting of the
+ // retry variable.
+ //
+
+ case CheckReset:
+
+ Adapter->ResetRetries = 0;
+
+ case CheckResetRetry:
+
+ //
+ // Increment the retry count
+ //
+ Adapter->ResetRetries++;
+
+ //
+ // See if we have gone too long.
+ // If we have gone for 5 seconds without the reset
+ // going true, reset the adapter again. Ten seconds is
+ // the breaking point to actually return an error condition.
+ //
+ if (Adapter->ResetRetries == 200) {
+
+ TOK162ResetAdapter(Adapter);
+
+ NdisMSetTimer(&(Adapter->ResetTimer),
+ 100
+ );
+
+ return;
+
+ } else if (Adapter->ResetRetries > 400) {
+
+ //
+ // Do the reset indications.
+ //
+ TOK162DoResetIndications(Adapter,NDIS_STATUS_FAILURE);
+ return;
+
+ }
+
+ //
+ // Check the result of the reset command. If it fails,
+ // set the state to CheckResetRetry.
+ //
+ if (CheckResetResults(Adapter) == FALSE) {
+
+ Adapter->ResetState = CheckResetRetry;
+
+ //
+ // If success, move to the next state (DoTheInit)
+ //
+ } else {
+
+ //
+ // We haven't had any retries of the init yet.
+ //
+ Adapter->InitRetries = 0;
+
+ VERY_LOUD_DEBUG(DbgPrint(
+ "TOK162!Moving to the init stage - %u\n",Adapter->ResetRetries);)
+
+ Adapter->ResetState = DoTheInit;
+
+ }
+
+ //
+ // Set the timer for the reset and leave this timer routine.
+ //
+ NdisMSetTimer(&(Adapter->ResetTimer),
+ 50
+ );
+
+ return;
+ break;
+
+ //
+ // DoTheInit sends the initialization block out to the card, and
+ // sets the next state to CheckInit.
+ //
+ case DoTheInit:
+
+ Adapter->ResetState = CheckInit;
+
+ //
+ // Send the init block out to the adapter
+ //
+ TOK162SetInitializationBlockAndInit(Adapter,
+ &Adapter->ResetResult);
+
+ //
+ // Set the timer for the reset and leave this timer routine.
+ //
+ NdisMSetTimer(&(Adapter->ResetTimer),
+ 200
+ );
+
+ return;
+ break;
+
+ //
+ // The CheckInit stage looks at the init results. If successful,
+ // the open command is issued and the regular interrupt handler
+ // will take care of the rest. If unsuccessful, the retry count
+ // is incremented and we wait until either the init results return
+ // successful or the retry count expires.
+ //
+ case CheckInit:
+
+ //
+ // Increment the retry count
+ //
+ Adapter->InitRetries++;
+
+ //
+ // If we have expired the retry count, do the indications
+ //
+ if (Adapter->InitRetries > 400) {
+
+ VERY_LOUD_DEBUG(DbgPrint("TOK162!Initialization failed\n");)
+ TOK162DoResetIndications(Adapter,NDIS_STATUS_FAILURE);
+ return;
+
+ }
+
+ //
+ // Check the result of the init.
+ //
+ Adapter->ResetResult = CheckInitResults(Adapter);
+
+ //
+ // If we were successful, issue the open command.
+ //
+ if (Adapter->ResetResult == NDIS_STATUS_SUCCESS) {
+
+ VERY_LOUD_DEBUG(DbgPrint("TOK162!Calling do the open\n");)
+ DoTheOpen(Adapter);
+
+ return;
+
+ //
+ // If not successful, start the timer and end this timer routine.
+ //
+ } else {
+
+ NdisMSetTimer(&(Adapter->ResetTimer),
+ 50
+ );
+
+ }
+
+ return;
+ break;
+ }
+
+}
+
+VOID
+TOK162DoResetIndications(
+ IN PTOK162_ADAPTER Adapter,
+ IN NDIS_STATUS Status
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by TOK162ResetDpc to perform any
+ indications which need to be done after a reset. Note that
+ this routine will be called after either a successful reset
+ or a failed reset.
+
+Arguments:
+
+ Adapter - The adapter whose hardware has been initialized.
+
+ Status - The status of the reset to send to the protocol(s).
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ //
+ // Although it should never happen, if we get called when there
+ // isn't a reset in progress, just return.
+ //
+ if (Adapter->ResetInProgress == FALSE) {
+
+ return;
+
+ }
+
+ //
+ // If we have a bad result, we stop the chip and do the indication
+ // back to the protocol(s).
+ //
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ LOUD_DEBUG(DbgPrint("TOK162!Reset failed\n");)
+
+ //
+ // Stop the chip
+ //
+ TOK162ResetAdapter(Adapter);
+
+ //
+ // Reset has failed, errorlog an entry.
+ //
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 0
+ );
+
+ }
+
+ //
+ // We are no longer resetting the adapter.
+ //
+ Adapter->ResetInProgress = FALSE;
+
+ //
+ // If this is during the initial init, just set the adapter variable.
+ //
+ if (Adapter->InitialInit == TRUE) {
+
+ Adapter->ResetResult = Status;
+
+ //
+ // Otherwise, send the status back to the protocol(s).
+ //
+ } else {
+
+ NdisMResetComplete(
+ Adapter->MiniportAdapterHandle,
+ Status,
+ TRUE
+ );
+
+ }
+
+
+}
+
+extern
+NDIS_STATUS
+TOK162SetupForReset(
+ IN PTOK162_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to write the resetting interrupt to the
+ token ring card, and then set up a timer to do the initialization
+ sequence under DPC.
+
+Arguments:
+
+ Adapter - The adapter whose hardware is to be initialized.
+
+Return Value:
+
+ Status of the reset process (always PENDING).
+
+--*/
+{
+ //
+ // The reset is now in progres.
+ //
+ Adapter->ResetInProgress = TRUE;
+
+ //
+ // Shut down the chip. We won't be doing any more work until
+ // the reset is complete.
+ //
+ TOK162ResetAdapter(Adapter);
+
+ //
+ // Set the timer for the dpc routine. The wait is for 100 milliseconds.
+ //
+ NdisMSetTimer(&(Adapter->ResetTimer),
+ 500
+ );
+
+
+ //
+ // Indicate the reset is pending
+ //
+ return NDIS_STATUS_PENDING;
+}
+
+
+VOID
+TOK162ResetVariables(
+ IN PTOK162_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets variables to their proper value after a reset.
+
+Arguments:
+
+ Adapter - Adapter we are resetting.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Reset the command queue and block variables
+ //
+ Adapter->CommandOnCard = NULL;
+ Adapter->WaitingCommandHead = NULL;
+ Adapter->WaitingCommandTail = NULL;
+ Adapter->NumberOfAvailableCommandBlocks = TOK162_NUMBER_OF_CMD_BLOCKS;
+ Adapter->NextCommandBlock = 0;
+
+ //
+ // Reset the transmit queue and block variables
+ //
+ Adapter->TransmitOnCard = NULL;
+ Adapter->WaitingTransmitHead = NULL;
+ Adapter->WaitingTransmitTail = NULL;
+ Adapter->NumberOfAvailableTransmitBlocks =
+ Adapter->NumberOfTransmitLists;
+ Adapter->NextTransmitBlock = 0;
+ Adapter->TransmitsQueued = 0;
+}
+
+
+VOID
+TOK162ResetCommandBlocks(
+ IN PTOK162_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets command block elements to their proper value after
+ a reset.
+
+Arguments:
+
+ Adapter - Adapter we are resetting.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Pointer to a Command Block. Used while initializing
+ // the Command Queue.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK CurrentCommandBlock;
+
+ //
+ // Simple iteration variable.
+ //
+ UINT i;
+
+ //
+ // Abort all pending transmits
+ //
+ CurrentCommandBlock = Adapter->TransmitOnCard;
+
+ while (CurrentCommandBlock != NULL) {
+
+ TOK162AbortSend(Adapter,CurrentCommandBlock);
+ CurrentCommandBlock = CurrentCommandBlock->NextCommand;
+
+ }
+
+ //
+ // Put the Transmit Blocks into a known state.
+ //
+ for (i = 0, CurrentCommandBlock = Adapter->TransmitQueue;
+ i < Adapter->NumberOfTransmitLists;
+ i++, CurrentCommandBlock++
+ ) {
+
+ CurrentCommandBlock->Hardware.State = TOK162_STATE_FREE;
+ CurrentCommandBlock->NextCommand = NULL;
+ CurrentCommandBlock->CommandBlock = FALSE;
+ CurrentCommandBlock->CommandBlockIndex = (USHORT)i;
+ CurrentCommandBlock->Timeout = FALSE;
+ }
+
+ //
+ // Now do the same for the command queue.
+ //
+ for (i = 0, CurrentCommandBlock = Adapter->CommandQueue;
+ i < TOK162_NUMBER_OF_CMD_BLOCKS;
+ i++, CurrentCommandBlock++
+ ) {
+
+ CurrentCommandBlock->Hardware.State = TOK162_STATE_FREE;
+ CurrentCommandBlock->NextCommand = NULL;
+ CurrentCommandBlock->CommandBlock = TRUE;
+ CurrentCommandBlock->CommandBlockIndex = (USHORT)i;
+ CurrentCommandBlock->Timeout = FALSE;
+ }
+}
+
+
+
+BOOLEAN
+CheckResetResults(PTOK162_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine checks the current state of the reset command and returns
+ whether the reset was successful.
+
+Arguments:
+
+ Adapter - Adapter we are resetting.
+
+Return Value:
+
+ TRUE if reset is successful, FALSE if not.
+
+--*/
+{
+ //
+ // Count of the total delay waiting for the chip to give results
+ //
+ UINT TotalDelay;
+
+ //
+ // Indicating if we can break out of a loop by having definitive results.
+ //
+ BOOLEAN Complete;
+
+ //
+ // Variable holding value of the status.
+ //
+ USHORT Value;
+
+ //
+ // Return value, TRUE or FALSE.
+ //
+ BOOLEAN Success;
+
+ //
+ // Initialize the variables.
+ //
+ Complete = FALSE;
+ TotalDelay = 0;
+ Success = FALSE;
+
+ //
+ // If we are running in a DPC, we don't want to check more than once
+ //
+ if (Adapter->InitialInit == FALSE) {
+
+ Complete = TRUE;
+
+ }
+
+ //
+ // Loop until Complete is TRUE.
+ //
+ do {
+
+ //
+ // First get the status
+ //
+ READ_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_STATUS,
+ &Value
+ );
+
+
+ //
+ // Check for Initialize
+ //
+ if ((Value & STATUS_INIT_INITIALIZE) != 0) {
+
+ //
+ // Mask off the Test and Error Bits
+ //
+ Value = Value & 0x00FF;
+ Value = Value & ~STATUS_INIT_INITIALIZE;
+
+
+ //
+ // Check test and error to see if they are zero. If so,
+ // we are done and successful.
+ //
+ if ((Value & (STATUS_INIT_TEST | STATUS_INIT_ERROR)) == 0) {
+
+ Complete = TRUE;
+ Success = TRUE;
+ VERY_LOUD_DEBUG(DbgPrint("TOK162!Returning True\n");)
+
+ }
+
+ //
+ // If init isn't set but test and error are, we are done but
+ // have failed.
+ //
+ } else if ((Value & (STATUS_INIT_TEST | STATUS_INIT_ERROR)) ==
+ (STATUS_INIT_TEST | STATUS_INIT_ERROR)) {
+
+ Complete = TRUE;
+ Success = FALSE;
+
+ }
+
+ //
+ // If we aren't done yet, then we need to sleep for a while and
+ // try again.
+ //
+ if (Complete == FALSE) {
+
+ NdisStallExecution(500000);
+ TotalDelay += 500000;
+
+ }
+
+ //
+ // If we have gone past the total time allowed or we have completed,
+ // then we end. Otherwise we loop again.
+ //
+ } while ((TotalDelay < 5000000) && (Complete == FALSE));
+
+ //
+ // Return success/failure.
+ //
+ return(Success);
+}
+
+
+
+NDIS_STATUS
+CheckInitResults(PTOK162_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine checks the current state of the init command and returns
+ whether the init was successful.
+
+Arguments:
+
+ Adapter - Adapter we are resetting.
+
+Return Value:
+
+ TRUE if init is successful, FALSE if not.
+
+--*/
+{
+
+ //
+ // Count of the total delay waiting for the chip to give results
+ //
+ UINT TotalDelay;
+
+ //
+ // Indicating if we can break out of a loop by having definitive results.
+ //
+ BOOLEAN Complete;
+
+ //
+ // Variable holding value of the status.
+ //
+ USHORT Value;
+
+ //
+ // Return value, TRUE or FALSE.
+ //
+ BOOLEAN Success;
+
+ //
+ // Initialize the variables.
+ //
+ Complete = FALSE;
+ TotalDelay = 0;
+ Success = FALSE;
+
+ //
+ // If we are running in a DPC, we don't want to check more than once
+ //
+ if (Adapter->InitialInit == FALSE) {
+
+ Complete = TRUE;
+
+ }
+
+ //
+ // Loop until Complete == TRUE
+ //
+ do {
+
+ //
+ // First get the status
+ //
+ READ_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_STATUS,
+ &Value
+ );
+
+ //
+ // Check for Initialize, Test, and Error to be correct
+ //
+ if ((Value & (STATUS_INIT_INITIALIZE | STATUS_INIT_TEST)) == 0) {
+
+ //
+ // Check Error Bit
+ //
+ Complete = TRUE;
+
+ if ((Value & STATUS_INIT_ERROR) != 0) {
+
+ Success = FALSE;
+
+ } else {
+
+ Success = TRUE;
+
+ }
+ }
+
+ //
+ // If we aren't finished (Complete), Stall and try again.
+ //
+ if (Complete == FALSE) {
+
+ NdisStallExecution(100000);
+ TotalDelay += 100000;
+
+ }
+
+ } while ((TotalDelay < 10000000) && (Complete == FALSE));
+
+ //
+ // Display the values of the SCB and SSB to the debugger. After init
+ // the SCB should be 0000E2C18BD4 and the SSB should be FFFFD7D1D9C5D4C3.
+ //
+ LOUD_DEBUG(DbgPrint("TOK162!SCB Value after init = %04x%04x%04x\n",
+ Adapter->Scb->Command,
+ Adapter->Scb->Parm1,
+ Adapter->Scb->Parm2);)
+
+ //
+ // If we are successful, return STATUS_SUCCESS
+ //
+ if (Success == TRUE) {
+
+ VERY_LOUD_DEBUG(DbgPrint("TOK162!Returning Success\n");)
+ return(NDIS_STATUS_SUCCESS);
+
+ } else {
+
+ VERY_LOUD_DEBUG(DbgPrint("TOK162!Returning Failure\n");)
+ return(NDIS_STATUS_FAILURE);
+
+ }
+}
+
+
+BOOLEAN
+DoTheOpen(
+ PTOK162_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine acquires and submits the open command. If called during the
+ initial init, the result of the open command is polled.
+
+Arguments:
+
+ Adapter - Adapter we are opening.
+
+Return Value:
+
+ TRUE if open is successful, FALSE if not.
+
+--*/
+{
+ //
+ // Result of open for polling (initialinit) mode
+ //
+ USHORT Result;
+
+ //
+ // Command block used for the open.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK Command;
+
+ //
+ // Log DoTheOpen entered
+ //
+ IF_LOG('g');
+
+ //
+ // Change the ring state
+ //
+ Adapter->CurrentRingState = NdisRingStateOpening;
+
+ //
+ // Initialize the group and functional addresses. These will be set
+ // after the reset has finished.
+ //
+ Adapter->Open->GroupAddress = 0;
+ Adapter->Open->FunctionalAddress = 0;
+
+ //
+ // Set the address the adapter should enter the ring with.
+ //
+ NdisMoveMemory(
+ Adapter->Open->NodeAddress,
+ Adapter->CurrentAddress,
+ TOK162_LENGTH_OF_ADDRESS
+ );
+
+ //
+ // Acquire a command block
+ //
+ TOK162AcquireCommandBlock(Adapter,
+ &Command
+ );
+
+ //
+ // Set up the command block for the open
+ //
+ Command->Hardware.CommandCode = CMD_DMA_OPEN;
+ Command->Hardware.ParmPointer =
+ NdisGetPhysicalAddressLow(Adapter->OpenPhysical);
+
+ //
+ // Issue the command to the controller
+ //
+ TOK162SubmitCommandBlock(Adapter,
+ Command
+ );
+
+ //
+ // During initialinit we have to poll for completion of the open. This
+ // is because there is no way to pend the initial init.
+ //
+ if (Adapter->InitialInit == TRUE) {
+
+ //
+ // Poll until the SSB contains an open.
+ //
+ while (Adapter->InitialOpenComplete == FALSE) {
+
+ NdisStallExecution(5000);
+
+ }
+
+ //
+ // Get the result of the open.
+ //
+ Result = Adapter->SsbStatus1 & OPEN_COMPLETION_MASK_RESULT;
+
+ //
+ // Return the command block
+ //
+ TOK162RelinquishCommandBlock(Adapter,
+ Command
+ );
+
+ //
+ // Figure out the error code
+ //
+ if (Result == OPEN_RESULT_ADAPTER_OPEN) {
+
+ //
+ // Log open successful
+ //
+ IF_LOG('h');
+
+ //
+ // Set the current ring state
+ //
+ Adapter->CurrentRingState = NdisRingStateOpened;
+
+ //
+ // Return TRUE
+ //
+ return(TRUE);
+
+ } else {
+
+ //
+ // Log open unsuccessful
+ //
+ IF_LOG('H');
+
+ //
+ // Set the current ring state
+ //
+ Adapter->CurrentRingState = NdisRingStateOpenFailure;
+
+ //
+ // Return FALSE
+ //
+ return(FALSE);
+
+ }
+
+ }
+
+ //
+ // Log DoTheOpen exited.
+ //
+ IF_LOG('G');
+
+ return(TRUE);
+
+}
+
+
+BOOLEAN
+DoTheReceive(
+ PTOK162_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine submits the receive command to the current adapter.
+
+Arguments:
+
+ Adapter - Adapter we are submitting the receive.
+
+Return Value:
+
+ TRUE
+
+--*/
+{
+ //
+ // Command block used for the open.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK Command;
+
+ //
+ // Dismiss the interrupt, allowing the SSB to be updated.
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_STATUS,
+ ENABLE_SSB_UPDATE
+ );
+
+ //
+ // Acquire a command block
+ //
+ TOK162AcquireCommandBlock(Adapter,
+ &Command
+ );
+
+ //
+ // Set up the command block for the receive
+ //
+ Command->Hardware.CommandCode = CMD_DMA_RCV;
+
+ Command->Hardware.ParmPointer =
+ NdisGetPhysicalAddressLow(Adapter->ReceiveQueuePhysical);
+
+ //
+ // Issue the command to the controller
+ //
+ TOK162SubmitCommandBlock(Adapter,
+ Command
+ );
+
+ //
+ // Return the command block
+ //
+ TOK162RelinquishCommandBlock(Adapter,
+ Command
+ );
+
+ VERY_LOUD_DEBUG(DbgPrint("TOK162!Returning from DoTheReceive\n");)
+
+ return(TRUE);
+
+}
+
+
+VOID
+TOK162WriteInitializationBlock(
+ PTOK162_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine writes the initialization block to the adapter
+
+Arguments:
+
+ Adapter - Adapter we are initializing
+
+Return Value:
+
+ None
+
+--*/
+{
+ //
+ // Simple index variable.
+ //
+ USHORT i;
+
+ //
+ // Pointer to the current value in the initialization block
+ //
+ PUSHORT val;
+
+ //
+ // Set the address of the adapter to 0x0200.
+ //
+ WRITE_ADAPTER_USHORT(Adapter,PORT_OFFSET_ADDRESS,0x0200);
+
+ //
+ // Write out the initialization bytes
+ //
+ val = (PUSHORT)Adapter->InitializationBlock;
+
+ for (i = 0;
+ i < (sizeof(ADAPTER_INITIALIZATION)/2);
+ i++,val++) {
+
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA_AUTO_INC,
+ *val
+ );
+
+ NdisStallExecution(10);
+
+ }
+
+ //
+ // Issue the command to the adapter
+ //
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_COMMAND,
+ EXECUTE_SCB_COMMAND
+ );
+
+}
+
+
+VOID
+TOK162GetAdapterOffsets(
+ IN PTOK162_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine gets the offsets into adapter memory of adapter
+ parameter lists.
+
+Arguments:
+
+ Adapter - Adapter we are obtaining info from
+
+Return Value:
+
+ None
+
+--*/
+{
+ //
+ // Get the pointers for READ.ADAPTER
+ //
+
+ WRITE_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_ADDRESS,
+ 0x0A00
+ );
+
+ //
+ // Get the universal address offset
+ //
+ READ_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA_AUTO_INC,
+ &Adapter->UniversalAddress
+ );
+
+ VERY_LOUD_DEBUG(DbgPrint("TOK162!Universal address offset is %x\n",
+ Adapter->UniversalAddress);)
+
+ //
+ // Get the microcode level offset
+ //
+ READ_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA_AUTO_INC,
+ &Adapter->MicrocodeLevel
+ );
+
+ //
+ // Get the current addresses (network, functional, group) offset
+ //
+ READ_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA_AUTO_INC,
+ &Adapter->AdapterAddresses
+ );
+
+ VERY_LOUD_DEBUG(DbgPrint("TOK162!Adapter addresses offset is %x\n",
+ Adapter->AdapterAddresses);)
+
+ //
+ // Get the adapter parameters offset
+ //
+ READ_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA_AUTO_INC,
+ &Adapter->AdapterParms
+ );
+
+
+ //
+ // Get the adapter Mac Buffer offset
+ //
+ READ_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_DATA_AUTO_INC,
+ &Adapter->MacBuffer
+ );
+
+}
+
+
+VOID
+TOK162ResetReceiveQueue(
+ IN PTOK162_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine resets the receive queue structures to their initialized
+ state. Most fields don't change and don't need to be updated, otherwise
+ the initreceivequeue function would be called.
+
+Arguments:
+
+ Adapter - Adapter whose receive queue is being reset
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Simple iterative variable.
+ //
+ USHORT i;
+
+ //
+ // Pointer to the current receive entry.
+ //
+ PTOK162_SUPER_RECEIVE_LIST CurrentReceiveEntry;
+
+ //
+ // Set pointer to current receive list to queue head
+ //
+ Adapter->ReceiveQueueCurrent = Adapter->ReceiveQueue;
+
+ //
+ // For each receive list, reset the cstat and flush buffers
+ //
+ for (i = 0, CurrentReceiveEntry = Adapter->ReceiveQueue;
+ i < Adapter->NumberOfReceiveBuffers;
+ i++, CurrentReceiveEntry++
+ ) {
+
+ //
+ // Flush the flush buffers
+ //
+ NdisFlushBuffer(CurrentReceiveEntry->FlushBuffer, FALSE);
+
+ //
+ // Reset the CSTAT to allow this receive buffer to be re-used.
+ //
+ CurrentReceiveEntry->Hardware.CSTAT = RECEIVE_CSTAT_REQUEST_RESET;
+
+ }
+
+}
+
+
+VOID
+TOK162AbortSend(
+ IN PTOK162_ADAPTER Adapter,
+ OUT PTOK162_SUPER_COMMAND_BLOCK CurrentCommandBlock
+ )
+/*++
+
+Routine Description:
+
+ This routine aborts the transmit block that was passed in.
+
+Arguments:
+
+ Adapter - Adapter whose receive queue is being reset
+ CurrentCommandBlock - Transmit to be aborted.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Pointer to the packet that started this transmission.
+ //
+ PNDIS_PACKET OwningPacket = CurrentCommandBlock->OwningPacket;
+
+ //
+ // If we used map registers we need to do the completion on them.
+ //
+ if (CurrentCommandBlock->UsedTOK162Buffer == FALSE) {
+
+ //
+ // Pointer to the current buffer we are looking at.
+ //
+ PNDIS_BUFFER CurrentBuffer;
+
+ //
+ // Map register to complete
+ //
+ UINT CurMapRegister;
+
+ //
+ // The transmit is being aborted, so we can release
+ // the physical mapping used for it.
+ //
+
+ NdisQueryPacket(
+ OwningPacket,
+ NULL,
+ NULL,
+ &CurrentBuffer,
+ NULL
+ );
+
+ //
+ // Get the starting map register for this buffer.
+ //
+ CurMapRegister = CurrentCommandBlock->CommandBlockIndex *
+ Adapter->TransmitThreshold;
+
+ //
+ // Loop until there aren't any more buffers.
+ //
+ while (CurrentBuffer) {
+
+ //
+ // Release the current map register.
+ //
+ NdisMCompleteBufferPhysicalMapping(
+ Adapter->MiniportAdapterHandle,
+ CurrentBuffer,
+ CurMapRegister
+ );
+
+ //
+ // Move to the next map register.
+ //
+ ++CurMapRegister;
+
+ //
+ // Move to the next buffer
+ //
+ NdisGetNextBuffer(
+ CurrentBuffer,
+ &CurrentBuffer
+ );
+
+ }
+
+ }
+}
diff --git a/private/ntos/ndis/ibmtok2i/send.c b/private/ntos/ndis/ibmtok2i/send.c
new file mode 100644
index 000000000..d360bc596
--- /dev/null
+++ b/private/ntos/ndis/ibmtok2i/send.c
@@ -0,0 +1,706 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ send.c
+
+Abstract:
+
+ This file contains the code for putting a packet through the
+ staged allocation for transmission.
+
+Author:
+
+ Kevin Martin(KevinMa) 20-Dec-1993
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+
+--*/
+
+#include <tok162sw.h>
+
+
+NDIS_STATUS
+TOK162ConstrainPacket(
+ IN PTOK162_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet,
+ OUT PTOK162_SUPER_COMMAND_BLOCK CommandBlock
+ );
+
+NDIS_STATUS
+TOK162TransmitPacket(
+ IN PTOK162_ADAPTER Adapter,
+ PNDIS_PACKET FirstPacket
+ );
+
+#if DBG
+VOID
+PrintTransmitEntry(
+ IN PTOK162_SUPER_COMMAND_BLOCK TransmitBlock
+ );
+#endif
+
+NDIS_STATUS
+TOK162Send(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET Packet,
+ IN UINT Flags
+ )
+
+/*++
+
+Routine Description:
+
+ The TOK162Send request instructs a Miniport to transmit a packet through
+ the adapter onto the medium.
+
+Arguments:
+
+ MiniportAdapterContext - The context value returned by the Miniport when
+ the adapter was initialized. In reality, it is
+ a pointer to TOK162_ADAPTER.
+
+ Packet - A pointer to a descriptor for the packet that is
+ to be transmitted.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ //
+ // Pointer to the adapter.
+ //
+ PTOK162_ADAPTER Adapter =
+ PTOK162_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ //
+ // Status returned from TOK162TransmitPacket.
+ //
+ NDIS_STATUS Status;
+
+ //
+ // Points to the MAC reserved portion of this packet. This
+ // interpretation of the reserved section is only valid during
+ // the allocation phase of the packet.
+ //
+ PTOK162_RESERVED Reserved = PTOK162_RESERVED_FROM_PACKET(Packet);
+
+ //
+ // The number of ndis buffers in the packet.
+ //
+ UINT NdisBufferCount;
+
+ //
+ // The number of physical buffers in the entire packet.
+ //
+ UINT PhysicalBufferCount;
+
+ //
+ // The total amount of data contained within the ndis packet.
+ //
+ UINT TotalVirtualLength;
+
+ //
+ // Log the fact that we are entering TOK162Send.
+ //
+ IF_LOG('s');
+
+ ASSERT(sizeof(TOK162_RESERVED) <= sizeof(Packet->MiniportReserved));
+
+ //
+ // If we are in the middle of a reset, return this fact
+ //
+ if (Adapter->ResetInProgress == TRUE) {
+
+ return(NDIS_STATUS_RESET_IN_PROGRESS);
+
+ }
+
+ //
+ // Determine if and how much adapter space would need to be allocated
+ // to meet hardware constraints.
+ //
+ NdisQueryPacket(
+ Packet,
+ &PhysicalBufferCount,
+ &NdisBufferCount,
+ NULL,
+ &TotalVirtualLength
+ );
+
+ //
+ // See if the packet exceeds TOK162_MAXIMUM_BLOCKS_PER_PACKET.
+ // Keep in mind that if the total virtual packet length is less than
+ // MINIMUM_TOKENRING_PACKET_SIZE then we'll have to chain on an
+ // additional buffer to pad the packet out to the minimum size.
+ //
+ if ((PhysicalBufferCount > Adapter->TransmitThreshold) ||
+ (TotalVirtualLength < MINIMUM_TOKENRING_PACKET_SIZE)) {
+
+ Reserved->NdisBuffersToMove = NdisBufferCount;
+
+ } else {
+
+ Reserved->NdisBuffersToMove = 0;
+ }
+
+ //
+ // See if we can send it now.
+ //
+ Status = TOK162TransmitPacket(Adapter, Packet);
+
+ //
+ // Log the fact that we are leaving TOK162Send
+ //
+ IF_LOG('S');
+
+ return Status;
+}
+
+
+NDIS_STATUS
+TOK162TransmitPacket(
+ IN PTOK162_ADAPTER Adapter,
+ PNDIS_PACKET FirstPacket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine attempts to take a packet through a stage of allocation.
+
+Arguments:
+
+ Adapter - The adapter that the packets are coming through.
+
+ FirstPacket - Packet to be sent.
+
+Return Value:
+
+ NDIS_STATUS_RESOURCES - if there are not enough resources
+ NDIS_STATUS_PENDING - if sending.
+
+--*/
+
+{
+ //
+ // Status
+ //
+ NDIS_STATUS Status;
+
+ //
+ // If we successfully acquire a command block, this
+ // is a pointer to it.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK CommandBlock;
+
+ //
+ // Points to the reserved portion of the packet.
+ //
+ PTOK162_RESERVED Reserved = PTOK162_RESERVED_FROM_PACKET(FirstPacket);
+
+ //
+ // Pointer to the TOK162 data block descriptor being filled.
+ //
+ UNALIGNED PTOK162_DATA_BLOCK DataBlock;
+
+ //
+ // The total amount of data in the ndis packet.
+ //
+ UINT TotalDataLength;
+
+ //
+ // The number of ndis buffers in the packet.
+ //
+ UINT NdisBufferCount;
+
+ //
+ // Points to the current ndis buffer being walked.
+ //
+ PNDIS_BUFFER CurrentBuffer;
+
+
+ //
+ // Log the fact we are in TOK162TransmitPacket.
+ //
+ IF_LOG('t');
+
+ //
+ // See if there is a free transmit block
+ //
+ if (TOK162AcquireTransmitBlock(
+ Adapter,
+ &CommandBlock
+ )) {
+
+ // We have a command block.
+ // Initialize the general fields of the Command Block.
+ //
+ CommandBlock->OwningPacket = FirstPacket;
+ CommandBlock->NextCommand = NULL;
+ CommandBlock->Hardware.Status = 0;
+ CommandBlock->Hardware.NextPending = TOK162_NULL;
+ CommandBlock->Hardware.CommandCode = CMD_DMA_XMIT;
+
+ //
+ // Check to see if we need to constrain the packet
+ //
+ if (PTOK162_RESERVED_FROM_PACKET(
+ FirstPacket)->NdisBuffersToMove != 0) {
+
+ //
+ // Now we merge the packet into a buffer
+ //
+ Status = TOK162ConstrainPacket(Adapter,
+ FirstPacket,
+ CommandBlock
+ );
+
+ //
+ // Otherwise, we will use the map registers and send the packet out
+ // as is.
+ //
+ } else {
+
+ //
+ // Array to hold the physical segments
+ //
+ NDIS_PHYSICAL_ADDRESS_UNIT PhysicalSegmentArray[TOK162_MAX_SG];
+
+ //
+ // Number of physical segments in the buffer
+ //
+ UINT BufferPhysicalSegments;
+
+ //
+ // map register to use for this buffer
+ //
+ UINT CurMapRegister;
+
+ //
+ // Iteration variable
+ //
+ UINT i;
+
+ //
+ // Assume we will be successful
+ //
+ Status = NDIS_STATUS_SUCCESS;
+
+ //
+ // Get the first buffer as well as the number of ndis buffers in
+ // the packet.
+ //
+ NdisQueryPacket(
+ FirstPacket,
+ NULL,
+ &NdisBufferCount,
+ &CurrentBuffer,
+ &TotalDataLength
+ );
+
+ //
+ // Each packet is sent out complete and is not chained.
+ //
+ CommandBlock->Hardware.TransmitEntry.ForwardPointer = 0xFFFFFFFF;
+
+ //
+ // Let the card know this buffer is ready to send.
+ //
+ CommandBlock->Hardware.TransmitEntry.CSTAT =
+ TRANSMIT_CSTAT_REQUEST;
+
+ //
+ // We didn't have to constrain.
+ //
+ CommandBlock->UsedTOK162Buffer = FALSE;
+
+ //
+ // Store the frame size.
+ //
+ CommandBlock->Hardware.TransmitEntry.FrameSize =
+ BYTE_SWAP((USHORT)TotalDataLength);
+
+ //
+ // Get the first map register to use
+ //
+ CurMapRegister = CommandBlock->CommandBlockIndex *
+ Adapter->TransmitThreshold;
+
+ //
+ // Go through all of the buffers in the packet getting
+ // the actual physical buffers from each MDL.
+ //
+ DataBlock = (UNALIGNED PTOK162_DATA_BLOCK)
+ &(CommandBlock->Hardware.TransmitEntry.DataCount1);
+
+ while (CurrentBuffer != NULL) {
+
+ NdisMStartBufferPhysicalMapping(
+ Adapter->MiniportAdapterHandle,
+ CurrentBuffer,
+ CurMapRegister,
+ TRUE,
+ PhysicalSegmentArray,
+ &BufferPhysicalSegments
+ );
+
+ CurMapRegister++;
+
+ //
+ // Store segments into command block
+ //
+ for (i = 0; i < BufferPhysicalSegments ; i++) {
+ DataBlock->Size =
+ BYTE_SWAP((USHORT)PhysicalSegmentArray[i].Length + 0x8000);
+
+ DataBlock->IBMPhysicalAddress = BYTE_SWAP_ULONG(
+ NdisGetPhysicalAddressLow(PhysicalSegmentArray[i].PhysicalAddress));
+
+ LOUD_DEBUG(DbgPrint("Address set is %08x\n",DataBlock->IBMPhysicalAddress);)
+
+ DataBlock++;
+ }
+
+ //
+ // Make sure the buffer, if cached, is updated in memory
+ //
+ NdisFlushBuffer(CurrentBuffer, TRUE);
+
+ //
+ // Get the next buffer
+ //
+ NdisGetNextBuffer(
+ CurrentBuffer,
+ &CurrentBuffer
+ );
+
+
+ }
+
+ //
+ // We'll be one past the last entry, so move back
+ //
+ DataBlock--;
+
+ //
+ // Strip off the high bit (already byte_swapped) to let the card
+ // know this is the last entry.
+ //
+ DataBlock->Size &= 0xFF7F;
+ }
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ //
+ // Indicate that we have one more transmit queued
+ //
+ Adapter->TransmitsQueued++;
+
+ //
+ // Display the send structure on the debugger
+ //
+ EXTRA_LOUD_DEBUG(PrintTransmitEntry(CommandBlock);)
+
+ //
+ // Submit the transmit block to be sent out
+ //
+ TOK162SubmitTransmitBlock(
+ Adapter,
+ CommandBlock
+ );
+
+ } else {
+
+ //
+ // Log the fact that we have an unsuccessful transmit setup
+ // and return the error code.
+ //
+ IF_LOG('U');
+ return(Status);
+
+ }
+
+ //
+ // No transmit block was available.
+ //
+ } else {
+
+ //
+ // Log the fact that we couldn't get a transmit block and return
+ // RESOURCES error.
+ //
+ IF_LOG('u');
+ return(NDIS_STATUS_RESOURCES);
+
+ }
+
+ //
+ // Log that we are leaving TOK162TransmitPacket
+ //
+ IF_LOG('T');
+ LOUD_DEBUG(DbgPrint("Transmit is now set to pending\n");)
+
+ //
+ // Indicate the send has pended.
+ //
+ return(NDIS_STATUS_PENDING);
+
+}
+
+NDIS_STATUS
+TOK162ConstrainPacket(
+ IN PTOK162_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet,
+ OUT PTOK162_SUPER_COMMAND_BLOCK CommandBlock
+ )
+
+/*++
+
+Routine Description:
+
+ Given a packet and if necessary attempt to acquire adapter
+ buffer resources so that the packet meets TOK162 hardware/MAC.BIN
+ contraints.
+
+Arguments:
+
+ Adapter - The adapter the packet is coming through.
+
+ Packet - The packet whose buffers are to be constrained.
+ The packet reserved section is filled with information
+ detailing how the packet needs to be adjusted.
+
+ CommandBlock - Command block describing the packet to be sent.
+
+Return Value:
+
+ Status - SUCCESS.
+
+--*/
+
+{
+
+ //
+ // Pointer to the reserved section of the packet to be contrained.
+ //
+ PTOK162_RESERVED Reserved = PTOK162_RESERVED_FROM_PACKET(Packet);
+
+ //
+ // Will point into the virtual address space addressed
+ // by the adapter buffer if one was successfully allocated.
+ //
+ PCHAR CurrentDestination;
+
+ //
+ // Will hold the total amount of data copied to the
+ // adapter buffer.
+ //
+ UINT TotalDataMoved = 0;
+
+ //
+ // Will point to the current source buffer.
+ //
+ PNDIS_BUFFER SourceBuffer;
+
+ //
+ // Points to the virtual address of the source buffers data.
+ //
+ PVOID SourceData;
+
+ //
+ // Will point to the number of bytes of data in the source
+ // buffer.
+ //
+ UINT SourceLength;
+
+ //
+ // The total amount of data contained within the ndis packet.
+ //
+ UINT TotalVirtualLength;
+
+ //
+ // Simple iteration variable.
+ //
+ INT i;
+
+ //
+ // Log that we entered TOK162ConstrainPacket
+ //
+ IF_LOG('v');
+
+ //
+ // Indicate that we are using this buffer
+ //
+ CommandBlock->UsedTOK162Buffer = TRUE;
+
+ //
+ // Get info on the data to be transmitted.
+ //
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ NULL,
+ &SourceBuffer,
+ &TotalVirtualLength
+ );
+
+ NdisQueryBuffer(
+ SourceBuffer,
+ &SourceData,
+ &SourceLength
+ );
+
+ //
+ // There is no link to this transmit list, and
+ // this list is ready to send.
+ //
+ CommandBlock->Hardware.TransmitEntry.ForwardPointer = 0xFFFFFFFF;
+ CommandBlock->Hardware.TransmitEntry.CSTAT = TRANSMIT_CSTAT_REQUEST;
+
+ //
+ // Set frame size to total virtual length of the packet.
+ //
+ CommandBlock->Hardware.TransmitEntry.FrameSize =
+ BYTE_SWAP(TotalVirtualLength);
+
+ //
+ // Set data count to frame size
+ //
+ CommandBlock->Hardware.TransmitEntry.DataCount1 =
+ CommandBlock->Hardware.TransmitEntry.FrameSize;
+
+ //
+ // Set the address to the buffer associated with this transmit block
+ //
+ CommandBlock->Hardware.TransmitEntry.PhysicalAddress1=BYTE_SWAP_ULONG(
+ NdisGetPhysicalAddressLow(CommandBlock->TOK162BufferPhysicalAddress));
+
+ //
+ // Make sure count fields for the second and third entries are 0.
+ //
+ CommandBlock->Hardware.TransmitEntry.DataCount2 = 0x00000000;
+ CommandBlock->Hardware.TransmitEntry.DataCount3 = 0x00000000;
+
+ //
+ // Fill in the buffer with the data from the users buffers.
+ //
+ CurrentDestination = (PVOID)CommandBlock->TOK162BufferAddress;
+
+ for (
+ i = Reserved->NdisBuffersToMove;
+ i;
+ i--
+ ) {
+
+ NdisMoveMemory(
+ CurrentDestination,
+ SourceData,
+ SourceLength
+ );
+
+ CurrentDestination = (PCHAR)CurrentDestination + SourceLength;
+
+ TotalDataMoved += SourceLength;
+
+ if (i > 1) {
+
+ NdisGetNextBuffer(
+ SourceBuffer,
+ &SourceBuffer
+ );
+
+ NdisQueryBuffer(
+ SourceBuffer,
+ &SourceData,
+ &SourceLength
+ );
+
+ }
+
+ }
+
+ //
+ // If the packet is less than the minimum TokenRing
+ // packet size, then clear the remaining part of
+ // the buffer up to the minimum packet size.
+ //
+ if (TotalVirtualLength < MINIMUM_TOKENRING_PACKET_SIZE) {
+
+ NdisZeroMemory(
+ CurrentDestination,
+ MINIMUM_TOKENRING_PACKET_SIZE - TotalVirtualLength
+ );
+
+ }
+
+
+ //
+ // Make sure the card and the system are in sync.
+ //
+ // The following was removed on 1/26/95 because it causes a hang
+ // on MIPs machines.
+ //
+ // NdisFlushBuffer(CommandBlock->FlushBuffer,TRUE);
+
+ //
+ // Log that we are leaving TOK162ConstrainPacket
+ //
+ IF_LOG('V');
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+#if DBG
+VOID
+PrintTransmitEntry(
+ IN PTOK162_SUPER_COMMAND_BLOCK TransmitBlock
+ )
+/*++
+
+Routine Description:
+
+ This routine displays a transmit list on the debug screen
+
+Arguments:
+
+ CommandBlock - Pointer to the command block with the transmit list
+
+Return Value:
+
+ None.
+--*/
+
+{
+
+ //
+ // Pointer to the transmit list portion of the transmit block.
+ //
+ TOK162_TRANSMIT_LIST Transmit = TransmitBlock->Hardware.TransmitEntry;
+
+ //
+ // Display all of the information about the send on the debugger.
+ //
+ DbgPrint("Forward Pointer = %08lx\n",Transmit.ForwardPointer);
+ DbgPrint("CSTAT = %x\n" ,Transmit.CSTAT);
+ DbgPrint("Frame Size = %04x\n" ,Transmit.FrameSize);
+ DbgPrint("DataCount1 = %04x\n" ,Transmit.DataCount1);
+ DbgPrint("DataAddress1 = %08lx\n",Transmit.PhysicalAddress1);
+ DbgPrint("DataCount2 = %04x\n" ,Transmit.DataCount2);
+ DbgPrint("DataAddress2 = %08lx\n",Transmit.PhysicalAddress2);
+ DbgPrint("DataCount3 = %04x\n" ,Transmit.DataCount3);
+ DbgPrint("DataAddress3 = %08lx\n",Transmit.PhysicalAddress3);
+
+}
+#endif
diff --git a/private/ntos/ndis/ibmtok2i/sources b/private/ntos/ndis/ibmtok2i/sources
new file mode 100644
index 000000000..9e402e3a4
--- /dev/null
+++ b/private/ntos/ndis/ibmtok2i/sources
@@ -0,0 +1,48 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=ibmtok2i
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER
+
+INCLUDES=inc;..\..\inc;..\..\..\inc
+
+SOURCES=command.c \
+ interrup.c \
+ tok162.c \
+ request.c \
+ reset.c \
+ send.c \
+ tok162.rc
+
+RELATIVE_DEPTH=..\..
+
+MSC_WARNING_LEVEL=/W3 /WX
diff --git a/private/ntos/ndis/ibmtok2i/tok162.c b/private/ntos/ndis/ibmtok2i/tok162.c
new file mode 100644
index 000000000..dce952707
--- /dev/null
+++ b/private/ntos/ndis/ibmtok2i/tok162.c
@@ -0,0 +1,2504 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ TOK162.c
+
+Abstract:
+
+ This is the main file for the IBM Token-Ring 16/4 Adapter II.
+ This driver conforms to the NDIS 3.0 Miniport interface.
+
+Author:
+
+ Kevin Martin (KevinMa) 27-Jan-1994
+
+Environment:
+
+ Kernel Mode.
+
+Revision History:
+
+--*/
+
+
+#include <TOK162sw.h>
+
+#pragma NDIS_INIT_FUNCTION(TOK162Initialize)
+
+//
+// If debug messages and logging is wanted, set the DBG environment variable.
+//
+#if DBG
+
+//
+// Variable which indicates the level of debugging messages. Values are
+// defined below.
+//
+UCHAR Tok162Debug = 0;
+
+//
+// Pointer to the logging table. The table is allocated when the adapter
+// memory is allocated.
+//
+PUCHAR Tok162Log;
+
+//
+// Index pointer for the logging macro.
+//
+USHORT Tok162LogPlace = 0;
+
+#endif
+
+//
+// Function declarations for functions private to this file.
+//
+BOOLEAN
+TOK162AllocateAdapterMemory(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+/*++
+
+Routine Description:
+
+ This is the primary initialization routine for the TOK162 driver.
+ It is simply responsible for the intializing the wrapper and registering
+ the MAC. It then calls a system and architecture specific routine that
+ will initialize and register each adapter.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+Return Value:
+
+ The status of the operation.
+
+--*/
+
+{
+ //
+ // Receives the status of the NdisMRegisterMiniport operation.
+ //
+ NDIS_STATUS Status;
+
+ //
+ // Handle for our driver given to us by the wrapper.
+ //
+ NDIS_HANDLE NdisWrapperHandle;
+
+ //
+ // Miniport driver characteristics
+ //
+ char Tmp[sizeof(NDIS_MINIPORT_CHARACTERISTICS)];
+
+ PNDIS_MINIPORT_CHARACTERISTICS TOK162Char =
+ (PNDIS_MINIPORT_CHARACTERISTICS)(PVOID)Tmp;
+
+ //
+ // Initialize the wrapper.
+ //
+ NdisMInitializeWrapper(
+ &NdisWrapperHandle,
+ DriverObject,
+ RegistryPath,
+ NULL
+ );
+
+ //
+ // Initialize the Miniport characteristics for the call to
+ // NdisRegisterMac.
+ //
+ TOK162Char->MajorNdisVersion = TOK162_NDIS_MAJOR_VERSION;
+ TOK162Char->MinorNdisVersion = TOK162_NDIS_MINOR_VERSION;
+
+ //
+ // Define the entry points into this driver for the wrapper.
+ //
+ TOK162Char->CheckForHangHandler = TOK162CheckForHang;
+ TOK162Char->DisableInterruptHandler = TOK162DisableInterrupt;
+ TOK162Char->EnableInterruptHandler = TOK162EnableInterrupt;
+ TOK162Char->HaltHandler = TOK162Halt;
+ TOK162Char->HandleInterruptHandler = TOK162HandleInterrupt;
+ TOK162Char->InitializeHandler = TOK162Initialize;
+ TOK162Char->ISRHandler = TOK162Isr;
+ TOK162Char->QueryInformationHandler = TOK162QueryInformation;
+
+ //
+ // We don't support reconfigure so we pass a null.
+ //
+ TOK162Char->ReconfigureHandler = NULL;
+ TOK162Char->ResetHandler = TOK162Reset;
+ TOK162Char->SendHandler = TOK162Send;
+ TOK162Char->SetInformationHandler = TOK162SetInformation;
+ TOK162Char->TransferDataHandler = TOK162TransferData;
+
+ //
+ // Register the driver.
+ //
+ Status = NdisMRegisterMiniport(
+ NdisWrapperHandle,
+ TOK162Char,
+ sizeof(*TOK162Char)
+ );
+
+ //
+ // If everything went ok, return STATUS_SUCCESS
+ //
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ return STATUS_SUCCESS;
+
+ }
+
+ //
+ // We can only get here if something went wrong with registering
+ // the miniport or *all* of the adapters.
+ //
+ NdisTerminateWrapper(NdisWrapperHandle, NULL);
+ return STATUS_UNSUCCESSFUL;
+
+}
+
+
+NDIS_STATUS
+TOK162RegisterAdapter(
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PUCHAR CurrentAddress,
+ IN UINT PortAddress,
+ IN ULONG MaxFrameSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine (and its interface) are not portable. They are
+ defined by the OS, the architecture, and the particular TOK162
+ implementation.
+
+ This routine is responsible for the allocation of the datastructures
+ for the driver as well as any hardware specific details necessary
+ to talk with the device.
+
+Arguments:
+
+ ConfigurationHandle - Handle passed to NdisRegisterAdapter.
+ MiniportAdapterHandle - Handle received from
+ CurrentAddress - The network address found in the registry
+ PortAddress - The starting i/o port address found in the
+ registry
+
+Return Value:
+
+ Returns NDIS_STATUS_SUCCESS if everything goes ok, else
+ if anything occurred that prevents the initialization
+ of the adapter it returns an appropriate NDIS error.
+
+--*/
+
+{
+
+ //
+ // Holds the value returned by NDIS calls.
+ //
+ NDIS_STATUS Status;
+
+ //
+ // Holds information needed when registering the adapter.
+ //
+ PTOK162_ADAPTER Adapter;
+
+ // We put in this assertion to make sure that ushort are 2 bytes.
+ // if they aren't then the initialization block definition needs
+ // to be changed.
+ //
+ ASSERT(sizeof(TOK162_PHYSICAL_ADDRESS) == 4);
+
+ //
+ // Allocate the Adapter memory
+ //
+ TOK162_ALLOC_PHYS(&Status, &Adapter, sizeof(TOK162_ADAPTER));
+
+ //
+ // If everything went ok (Status == NDIS_STATUS_SUCCESS), zero the
+ // memory, and then assign values that we know to the adapter structure.
+ //
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ //
+ // The allocation didn't work, so return an error indicating resource
+ // problems.
+ //
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ NdisZeroMemory(
+ Adapter,
+ sizeof(TOK162_ADAPTER)
+ );
+
+ //
+ // Assign the handle and io port address base
+ //
+ Adapter->MiniportAdapterHandle = MiniportAdapterHandle;
+ Adapter->PortIOBase = PortAddress;
+
+ //
+ // Set the receive, transmit, and command buffer and block
+ // information.
+ //
+ Adapter->NumberOfReceiveBuffers = RECEIVE_LIST_COUNT;
+ Adapter->NumberOfTransmitLists = TRANSMIT_LIST_COUNT;
+
+ Adapter->NumberOfAvailableCommandBlocks =
+ TOK162_NUMBER_OF_CMD_BLOCKS;
+
+ //
+ // Set the address the adapter should enter the ring with.
+ //
+ NdisMoveMemory(
+ Adapter->CurrentAddress,
+ CurrentAddress,
+ TOK162_LENGTH_OF_ADDRESS
+ );
+
+ //
+ // Notify the wrapper of our attributes
+ //
+ NdisMSetAttributes(
+ MiniportAdapterHandle,
+ (NDIS_HANDLE)Adapter,
+ TRUE,
+ NdisInterfaceIsa
+ );
+
+ //
+ // Register our shutdown handler.
+ //
+
+ NdisMRegisterAdapterShutdownHandler(
+ Adapter->MiniportAdapterHandle, // miniport handle.
+ Adapter, // shutdown context.
+ TOK162Shutdown // shutdown handler.
+ );
+
+ //
+ // Register our port usage
+ //
+ Status = NdisMRegisterIoPortRange(
+ (PVOID *)(&(Adapter->PortIOAddress)),
+ MiniportAdapterHandle,
+ Adapter->PortIOBase,
+ 0x10
+ );
+
+ //
+ // If there was a problem with the registration, free the memory
+ // associated with the adapter and return resource error
+ //
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ goto Error1Exit;
+
+ }
+
+ //
+ // Obtain all of the other adapter parameters
+ //
+ Status = TOK162GetAdapterConfiguration(Adapter);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ goto Error1Exit;
+
+ }
+
+ if (MaxFrameSize != 0) {
+
+ Adapter->ReceiveBufferSize = (USHORT)MaxFrameSize;
+
+ }
+
+
+ //
+ // Allocate the map registers
+ //
+ Status = NdisMAllocateMapRegisters(
+ Adapter->MiniportAdapterHandle,
+ Adapter->ConfigurationBlock.DMAChannel,
+ FALSE,
+ Adapter->NumberOfTransmitLists *
+ Adapter->TransmitThreshold,
+ Adapter->ReceiveBufferSize
+ );
+
+ //
+ // If there were any problems, return resources error.
+ //
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ goto Error2Exit;
+
+ }
+
+ //
+ // Allocate memory for all of the adapter structures
+ //
+ if (TOK162AllocateAdapterMemory(Adapter) == FALSE) {
+
+ //
+ // We get here if the allocateadaptermemory call fails. All we
+ // can do is log the resource problem, display the fact that the
+ // register failed, and return resources.
+ //
+
+ goto Error3Exit;
+
+ }
+
+ //
+ // The allocation succeeded.
+ // Reset the variables associated with the adapter
+ //
+ TOK162ResetVariables(Adapter);
+
+ //
+ // Initialize deferred and reset timers
+ //
+ NdisMInitializeTimer(
+ &Adapter->DeferredTimer,
+ Adapter->MiniportAdapterHandle,
+ (PVOID) TOK162DeferredTimer,
+ (PVOID) Adapter
+ );
+
+ NdisMInitializeTimer(
+ &Adapter->ResetTimer,
+ Adapter->MiniportAdapterHandle,
+ (PVOID) TOK162ResetHandler,
+ (PVOID) Adapter
+ );
+
+ //
+ // Initialize the adapter
+ //
+ VERY_LOUD_DEBUG(DbgPrint("TOK162!Calling InitialInit\n");)
+
+ if (TOK162InitialInit(Adapter) == FALSE) {
+
+ //
+ // If there was an error (FALSE), write the log entry, and
+ // free up all of the resources.
+ //
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
+ 0
+ );
+
+ //
+ // Return resources to the wrapper
+ //
+ if (Adapter->InterruptLevel != 0) {
+
+ NdisMDeregisterInterrupt(&Adapter->Interrupt);
+
+ }
+
+ goto Error3Exit;
+
+ }
+
+ //
+ // Display success to the debugger.
+ //
+ VERY_LOUD_DEBUG(DbgPrint(
+ "TOK162!Returning TRUE from RegisterAdapter\n");)
+
+ return NDIS_STATUS_SUCCESS;
+
+//
+// Error3Exit level indicates that we need to deregister the map registers
+// and deallocate the adapter-related allocated memory.
+//
+Error3Exit:
+
+ NdisMFreeMapRegisters(Adapter->MiniportAdapterHandle);
+ TOK162DeleteAdapterMemory(Adapter);
+
+//
+// Error2Exit level indicates that we need to deregister the IO Port Range.
+//
+Error2Exit:
+
+ NdisMDeregisterIoPortRange(Adapter->MiniportAdapterHandle,
+ Adapter->PortIOBase,
+ 0x30,
+ Adapter->PortIOAddress
+ );
+
+
+//
+// Error1Exit level indicates that we need to free the memory allocated
+// for the adapter structure. Log that register adapter failed.
+//
+Error1Exit:
+
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+
+ VERY_LOUD_DEBUG(DbgPrint(
+ "TOK162!Returning FALSE from RegisterAdapter\n");)
+
+ TOK162_FREE_PHYS(Adapter);
+ return NDIS_STATUS_RESOURCES;
+
+}
+
+
+extern
+NDIS_STATUS
+TOK162GetAdapterConfiguration(
+ IN PTOK162_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine obtains all of the settings from the adapter
+
+Arguments:
+
+ Adapter - Current Adapter structure
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if allocation of structure is successful.
+ NDIS_STATUS_RESOURCES if not.
+
+--*/
+{
+ //
+ // Holds value of the switches registers
+ //
+ PADAPTERSWITCHES Switches;
+
+ //
+ // Variable used to obtain the switches.
+ //
+ USHORT temp;
+
+ //
+ // Read in the switches registers from the adapter
+ //
+ READ_ADAPTER_USHORT(Adapter,
+ PORT_OFFSET_SWITCH_INT_DISABLE,
+ &temp
+ );
+
+ Switches = (PADAPTERSWITCHES)&temp;
+
+ //
+ // Display the value of the switches on the debugger.
+ //
+ VERY_LOUD_DEBUG(DbgPrint("TOK162!Switches are: %X\n",temp);)
+
+ //
+ // Display the individual values of the switches. These values are
+ // the values of the switches, not actual values that the switches
+ // represent (i.e. - interrupt 9 will be seen as 00, the switch
+ // positions representing interrupt 9).
+ //
+ VERY_LOUD_DEBUG(DbgPrint(
+ "TOK162!Reserved - %x\n", Switches->Reserved);)
+ VERY_LOUD_DEBUG(DbgPrint(
+ "TOK162!Setting AdapterMode - %x\n", Switches->AdapterMode);)
+ VERY_LOUD_DEBUG(DbgPrint(
+ "TOK162!Setting Waitstate - %x\n", Switches->WaitState);)
+ VERY_LOUD_DEBUG(DbgPrint(
+ "TOK162!Setting RPL - %x\n", Switches->RPL);)
+ VERY_LOUD_DEBUG(DbgPrint(
+ "TOK162!Setting RPL/IO Address - %x\n",Switches->RPL_PIO_Address);)
+ VERY_LOUD_DEBUG(DbgPrint(
+ "TOK162!Setting RingSpeed - %02x\n", Switches->RingSpeed);)
+ VERY_LOUD_DEBUG(DbgPrint(
+ "TOK162!Setting UTP/STP - %x\n", Switches->UTP_STP);)
+ VERY_LOUD_DEBUG(DbgPrint(
+ "TOK162!Setting DMA - %u\n", Switches->DMA);)
+ VERY_LOUD_DEBUG(DbgPrint(
+ "TOK162!Setting Interrupt - %u\n", Switches->IntRequest);)
+
+ //
+ // Get the adapter mode
+ //
+ if (Switches->AdapterMode == SW_ADAPTERMODE_NORMAL) {
+
+ Adapter->ConfigurationBlock.AdapterMode = CFG_ADAPTERMODE_NORMAL;
+
+ } else {
+
+ Adapter->ConfigurationBlock.AdapterMode = CFG_ADAPTERMODE_TEST;
+
+ }
+
+ //
+ // Get the adatper wait state setting.
+ //
+ if (Switches->WaitState == SW_WAITSTATE_NORMAL) {
+
+ Adapter->ConfigurationBlock.WaitState = CFG_WAITSTATE_NORMAL;
+
+ } else {
+
+ Adapter->ConfigurationBlock.WaitState = CFG_WAITSTATE_FAST;
+
+ }
+
+ //
+ // Check if Remote Program Load (RPL) is set. If it is, get the
+ // RPL Address.
+ //
+ if (Switches->RPL == SW_RPL_ENABLE) {
+
+ Adapter->ConfigurationBlock.RPL = TRUE;
+
+ switch(Switches->RPL_PIO_Address) {
+
+ case SW_PIO_ADDR_8:
+
+ Adapter->ConfigurationBlock.RPLAddress = CFG_RPLADDR_C0000;
+ break;
+
+ case SW_PIO_ADDR_C:
+
+ Adapter->ConfigurationBlock.RPLAddress = CFG_RPLADDR_C4000;
+ break;
+
+ case SW_PIO_ADDR_A:
+
+ Adapter->ConfigurationBlock.RPLAddress = CFG_RPLADDR_C8000;
+ break;
+
+ case SW_PIO_ADDR_E:
+
+ Adapter->ConfigurationBlock.RPLAddress = CFG_RPLADDR_CC000;
+ break;
+
+ case SW_PIO_ADDR_9:
+
+ Adapter->ConfigurationBlock.RPLAddress = CFG_RPLADDR_D0000;
+ break;
+
+ case SW_PIO_ADDR_D:
+
+ Adapter->ConfigurationBlock.RPLAddress = CFG_RPLADDR_D4000;
+ break;
+
+ case SW_PIO_ADDR_B:
+
+ Adapter->ConfigurationBlock.RPLAddress = CFG_RPLADDR_D8000;
+ break;
+
+ case SW_PIO_ADDR_F:
+
+ Adapter->ConfigurationBlock.RPLAddress = CFG_RPLADDR_DC000;
+ break;
+
+ }
+
+ } else {
+
+ //
+ // RPL is not enabled. Record this fact and zero out the RPL address.
+ //
+ Adapter->ConfigurationBlock.RPL = FALSE;
+ Adapter->ConfigurationBlock.RPLAddress = 0x0000;
+
+ }
+
+
+ //
+ // Get the ring speed.
+ //
+ if (Switches->RingSpeed == SW_RINGSPEED_4) {
+
+ //
+ // If the adapter is running at 4MBPS, set the ring speed
+ // value, allow up to 3 scatter-gathers per transmit, and
+ // set the receive buffer size (the max for the ring at this
+ // speed).
+ //
+ Adapter->ConfigurationBlock.RingSpeed = CFG_RINGSPEED_4;
+
+ Adapter->TransmitThreshold = 3;
+
+ Adapter->Running16Mbps = FALSE;
+
+ Adapter->ReceiveBufferSize = RECEIVE_LIST_BUFFER_SIZE_4;
+
+ } else {
+
+ //
+ // If the adapter is running at 16MBPS, set the ring speed
+ // value, allow up to 2 scatter-gathers per transmit, and
+ // set the receive buffer size (the max for the ring at this
+ // speed).
+ //
+ Adapter->ConfigurationBlock.RingSpeed = CFG_RINGSPEED_16;
+
+ Adapter->TransmitThreshold = 1;
+
+ Adapter->Running16Mbps = TRUE;
+
+ Adapter->ReceiveBufferSize = RECEIVE_LIST_BUFFER_SIZE_16;
+ }
+
+
+ //
+ // Get the connector type
+ //
+ if (Switches->UTP_STP == SW_UTP) {
+
+ Adapter->ConfigurationBlock.UTPorSTP = CFG_MEDIATYPE_UTP;
+
+ } else {
+
+ Adapter->ConfigurationBlock.UTPorSTP = CFG_MEDIATYPE_STP;
+
+ }
+
+ //
+ // Get the DMA channel in use.
+ //
+ switch(Switches->DMA) {
+
+ case SW_DMA_5:
+
+ Adapter->ConfigurationBlock.DMAChannel = CFG_DMACHANNEL_5;
+ break;
+
+ case SW_DMA_6:
+
+ Adapter->ConfigurationBlock.DMAChannel = CFG_DMACHANNEL_6;
+ break;
+
+ case SW_DMA_7:
+
+ Adapter->ConfigurationBlock.DMAChannel = CFG_DMACHANNEL_7;
+ break;
+
+ }
+
+ //
+ // Get the interrupt level.
+ //
+ switch(Switches->IntRequest) {
+
+ case SW_INT_9:
+
+ Adapter->InterruptLevel = CFG_INT_9;
+ break;
+
+ case SW_INT_10:
+
+ Adapter->InterruptLevel = CFG_INT_10;
+ break;
+
+ case SW_INT_11:
+
+ Adapter->InterruptLevel = CFG_INT_11;
+ break;
+
+ case SW_INT_15:
+
+ Adapter->InterruptLevel = CFG_INT_15;
+ break;
+
+ }
+
+ //
+ // Return that we succeeded.
+ //
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+extern
+NDIS_STATUS
+TOK162Initialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to initialize each adapter card/chip.
+
+Arguments:
+
+ OpenErrorStatus - Token Ring Adapter Open Status
+ SelectedMediumIndex - Medium used for transmission (Token Ring)
+ MediumArray - Array of mediums supported by wrapper
+ MiniportAdapterHandle - Adapter Handle
+ ConfigurationHandle - Configuration Handle
+
+Return Value:
+
+ Result of registering this adapter.
+
+--*/
+
+{
+ //
+ // Handle returned by NdisOpenConfiguration
+ //
+ NDIS_HANDLE ConfigHandle;
+
+ //
+ // Simple indexing variable
+ //
+ ULONG i;
+
+ //
+ // Buffer to copy the passed in network address.
+ //
+ UCHAR NetworkAddress[TOK162_LENGTH_OF_ADDRESS];
+
+ //
+ // Receives address of the network address string in the registry
+ //
+ PVOID NetAddress;
+
+ //
+ // Length of above network address string
+ //
+ ULONG Length;
+
+ //
+ // Beginning port address for this adapter
+ //
+ ULONG PortAddress;
+
+ //
+ // Variable holding value returned by NdisReadConfiguration
+ //
+ PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
+
+ //
+ // Description string constants found in registry
+ //
+ NDIS_STRING IOAddressStr = NDIS_STRING_CONST("IOBaseAddress");
+ NDIS_STRING MaxFrameStr = NDIS_STRING_CONST("MAXFRAMESIZE");
+
+ //
+ // Return value from NDIS calls
+ //
+ NDIS_STATUS Status;
+
+ //
+ // Value to be passed along as MaxFrameSize
+ //
+ ULONG MaxFrameSize;
+
+ //
+ // Cache-Alignment variable
+ //
+ ULONG Alignment;
+
+ //
+ // Search for the medium type (802.5)
+ //
+ for (i = 0; i < MediumArraySize; i++){
+
+
+ if (MediumArray[i] == NdisMedium802_5){
+ break;
+
+ }
+
+ }
+
+ //
+ // See if Token Ring is supported by the wrapper
+ //
+ if (i == MediumArraySize) {
+
+ return NDIS_STATUS_UNSUPPORTED_MEDIA;
+
+ }
+
+ //
+ // Tell wrapper the index in the medium array we're using
+ //
+ *SelectedMediumIndex = i;
+
+ //
+ // Get access to the configuration information
+ //
+ NdisOpenConfiguration(
+ &Status,
+ &ConfigHandle,
+ ConfigurationHandle
+ );
+
+ //
+ // If there was an error, return with the error code.
+ //
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ return Status;
+
+ }
+
+ //
+ // Read net address from the configuration info.
+ //
+ NdisReadNetworkAddress(
+ &Status,
+ &NetAddress,
+ &Length,
+ ConfigHandle
+ );
+
+ //
+ // Make sure the call worked and the address returned is of valid length
+ //
+ if ((Length == TOK162_LENGTH_OF_ADDRESS) &&
+ (Status == NDIS_STATUS_SUCCESS)) {
+
+ NdisMoveMemory(
+ NetworkAddress,
+ NetAddress,
+ TOK162_LENGTH_OF_ADDRESS
+ );
+
+ //
+ // If not, set the current address to all 0's, forcing the adapter
+ // to use the permanent address as the current address.
+ //
+ } else {
+
+ NdisZeroMemory(
+ NetworkAddress,
+ TOK162_LENGTH_OF_ADDRESS
+ );
+
+ }
+
+ //
+ // Get the port address from the configuration info.
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &IOAddressStr,
+ NdisParameterHexInteger
+ );
+
+ PortAddress = ReturnedValue->ParameterData.IntegerData;
+
+ //
+ // Get the max frame size if indicated by user
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &MaxFrameStr,
+ NdisParameterInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ MaxFrameSize = (ULONG)(ReturnedValue->ParameterData.IntegerData);
+
+ Alignment = NdisGetCacheFillSize();
+
+ if ( Alignment < sizeof(ULONG) ) {
+
+ Alignment = sizeof(ULONG);
+ }
+
+ MaxFrameSize = (MaxFrameSize + (Alignment - 1)) & ~(Alignment - 1);
+
+ if ((MaxFrameSize > RECEIVE_LIST_BUFFER_SIZE_16) ||
+ (MaxFrameSize < RECEIVE_LIST_BUFFER_SIZE_4)) {
+
+ MaxFrameSize = 0;
+
+ }
+
+ } else {
+
+ MaxFrameSize = 0;
+
+ }
+
+ //
+ // We're done with the configuration info.
+ //
+ NdisCloseConfiguration(ConfigHandle);
+
+ //
+ // Go register this adapter.
+ //
+ Status = TOK162RegisterAdapter(
+ ConfigurationHandle,
+ MiniportAdapterHandle,
+ NetworkAddress,
+ PortAddress,
+ MaxFrameSize
+ );
+
+ //
+ // Return the value TOK162RegisterAdapter returned
+ //
+ return Status;
+
+}
+
+
+BOOLEAN
+TOK162AllocateAdapterMemory(
+ IN PTOK162_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine allocates memory for:
+
+ - SCB
+
+ - SSB
+
+ - ErrorLog Block
+
+ - ReadAdapter Block
+
+ - Initialization Block
+
+ - Open Command Block
+
+ - Command Queue
+
+ - Transmit Command Queue
+
+ - Transmit Buffers
+
+ - Flush Buffer Pool
+
+ - Receive Queue
+
+ - Receive Buffers
+
+ - Receive Flush Buffers
+
+Arguments:
+
+ Adapter - The adapter to allocate memory for.
+
+Return Value:
+
+ Returns FALSE if some memory needed for the adapter could not
+ be allocated.
+
+--*/
+
+{
+ //
+ // Pointer to a Super Receive List. Used while initializing
+ // the Receive Queue.
+ //
+ PTOK162_SUPER_RECEIVE_LIST CurrentReceiveEntry;
+
+ //
+ // Pointer to a Command Block. Used while initializing
+ // the Command Queue.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK CurrentCommandBlock;
+
+ //
+ // Simple iteration variable.
+ //
+ UINT i;
+
+ //
+ // Status of allocation
+ //
+ NDIS_STATUS Status;
+
+#if DBG
+
+ //
+ // If debugging is specified, we need to allocate the trace log
+ // buffer.
+ //
+
+ NDIS_PHYSICAL_ADDRESS ndp;
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ LOG_SIZE,
+ FALSE,
+ (PVOID *)&Tok162Log,
+ &ndp);
+#endif
+ //
+ // Allocate the SCB
+ //
+
+ VERY_LOUD_DEBUG(DbgPrint("Allocating SCB\n");)
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(SCB) + 8,
+ FALSE,
+ (PVOID *) &Adapter->Scb,
+ &Adapter->ScbPhysical
+ );
+
+ VERY_LOUD_DEBUG(DbgPrint("Address of SCB is %lx\n",(ULONG)Adapter->Scb);)
+
+ //
+ // If the Scb could not be allocated, a NULL pointer will have been
+ // returned.
+ //
+ if (Adapter->Scb == NULL) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Allocate the SSB
+ //
+ VERY_LOUD_DEBUG(DbgPrint("Allocating SSB\n");)
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(SSB) + 8,
+ FALSE,
+ (PVOID *) &Adapter->Ssb,
+ &Adapter->SsbPhysical
+ );
+
+ VERY_LOUD_DEBUG(DbgPrint("Address of SSB is %lx\n",(ULONG)Adapter->Ssb);)
+
+ //
+ // If the Ssb could not be allocated, a NULL pointer will have been
+ // returned.
+ //
+ if (Adapter->Ssb == NULL) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Allocate the ErrorLog Block
+ //
+ VERY_LOUD_DEBUG(DbgPrint("Allocating ErrorLog Block\n");)
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(TOK162_ERRORLOG) + 8,
+ FALSE,
+ (PVOID *) &Adapter->ErrorLog,
+ &Adapter->ErrorLogPhysical
+ );
+
+ //
+ // If the ErrorLog could not be allocated, a NULL pointer will have been
+ // returned.
+ //
+ if (Adapter->ErrorLog == NULL) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Allocate the ReadAdapter Buffer
+ //
+ VERY_LOUD_DEBUG(DbgPrint("Allocating ReadAdapterBuffer\n");)
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ 4096,
+ FALSE,
+ (PVOID *) &Adapter->AdapterBuf,
+ &Adapter->AdapterBufPhysical
+ );
+
+ VERY_LOUD_DEBUG(DbgPrint("Address of ReadAdapterBuf is %lx\n",(ULONG)Adapter->AdapterBuf);)
+
+ //
+ // If the ReadAdapter Buffer could not be allocated, a NULL
+ // pointer will have been returned.
+ //
+ if (Adapter->AdapterBuf == NULL) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Allocate the Initialization Block
+ //
+ VERY_LOUD_DEBUG(DbgPrint("Allocating Initialization Block\n");)
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(ADAPTER_INITIALIZATION) + 8,
+ FALSE,
+ (PVOID *) &Adapter->InitializationBlock,
+ &Adapter->InitializationBlockPhysical
+ );
+
+ //
+ // If the Initialization Block could not be allocated, a NULL pointer
+ // will have been returned.
+ //
+ if (Adapter->InitializationBlock == NULL) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Allocate the Open Command Block
+ //
+
+ VERY_LOUD_DEBUG(DbgPrint("Allocating Open Command\n");)
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(OPEN_COMMAND) + 8,
+ FALSE,
+ (PVOID *) &Adapter->Open,
+ &Adapter->OpenPhysical
+ );
+
+ VERY_LOUD_DEBUG(DbgPrint(
+ "Address of Open Command is %lx\n",(ULONG)Adapter->Open);)
+
+ //
+ // If the Open Command Block could not be allocated, a NULL pointer
+ // will have been returned.
+ //
+ if (Adapter->Open == NULL) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Allocate the command block queue
+ //
+ VERY_LOUD_DEBUG(DbgPrint("Allocating Command Block Queue\n");)
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(TOK162_SUPER_COMMAND_BLOCK) * (TOK162_NUMBER_OF_CMD_BLOCKS+1),
+ FALSE,
+ (PVOID *) &Adapter->CommandQueue,
+ &Adapter->CommandQueuePhysical
+ );
+
+ //
+ // If the Command Block Queue could not be allocated, a NULL pointer
+ // will have been returned.
+ //
+ if (Adapter->CommandQueue == NULL) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Initialize the command block queue command blocks
+ //
+ for (i = 0, CurrentCommandBlock = Adapter->CommandQueue;
+ i < TOK162_NUMBER_OF_CMD_BLOCKS;
+ i++, CurrentCommandBlock++
+ ) {
+
+ //
+ // Set the state of this command block to free, the
+ // NextPending pointer and Next pointer to null, and
+ // the command timeout state to FALSE
+ //
+ CurrentCommandBlock->Hardware.State = TOK162_STATE_FREE;
+ CurrentCommandBlock->Hardware.NextPending = TOK162_NULL;
+ CurrentCommandBlock->NextCommand = NULL;
+ CurrentCommandBlock->Timeout = FALSE;
+
+ //
+ // Set the Self pointer of the command block
+ //
+ NdisSetPhysicalAddressHigh (CurrentCommandBlock->Self, 0);
+ NdisSetPhysicalAddressLow(
+ CurrentCommandBlock->Self,
+ NdisGetPhysicalAddressLow(Adapter->CommandQueuePhysical) +
+ i * sizeof(TOK162_SUPER_COMMAND_BLOCK));
+
+ //
+ // This is a command block and not a transmit command block
+ //
+ CurrentCommandBlock->CommandBlock = TRUE;
+
+ //
+ // Set the index of this command block
+ //
+ CurrentCommandBlock->CommandBlockIndex = (USHORT)i;
+
+ }
+
+ //
+ // Allocate Flush Buffer Pool
+ //
+ VERY_LOUD_DEBUG(DbgPrint("Allocating Flush Buffer Pool\n");)
+
+ NdisAllocateBufferPool(
+ &Status,
+ (PVOID*)&Adapter->FlushBufferPoolHandle,
+ Adapter->NumberOfReceiveBuffers + Adapter->NumberOfTransmitLists
+ );
+
+ //
+ // If there was a problem allocating the flush buffer pool,
+ // write out an errorlog entry, delete the allocated adapter memory,
+ // and return FALSE
+ //
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Allocate the Transmit Command Queue.
+ //
+ VERY_LOUD_DEBUG(DbgPrint("Allocating Transmit Command Block Queue\n");)
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(TOK162_SUPER_COMMAND_BLOCK) *
+ (Adapter->NumberOfTransmitLists+1),
+ FALSE,
+ (PVOID*)&Adapter->TransmitQueue,
+ &Adapter->TransmitQueuePhysical
+ );
+
+
+ //
+ // If the Transmit Block Queue could not be allocated, a NULL pointer
+ // will have been returned.
+ //
+ if (Adapter->TransmitQueue == NULL) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Initialize the transmit command queue
+ //
+ if (TOK162InitializeTransmitQueue(Adapter) == FALSE) {
+
+ return FALSE;
+ }
+
+ //
+ // Allocate the Receive Queue.
+ //
+ VERY_LOUD_DEBUG(DbgPrint("Allocating Receive Queue\n");)
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(TOK162_SUPER_RECEIVE_LIST) *
+ (Adapter->NumberOfReceiveBuffers+1),
+ FALSE,
+ (PVOID*)&Adapter->ReceiveQueue,
+ &Adapter->ReceiveQueuePhysical
+ );
+
+ //
+ // If the Receive Queue could not be allocated, a NULL pointer will
+ // have been returned.
+ //
+ if (Adapter->ReceiveQueue == NULL) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Initialize the receieve queue entries. First zero out the entire
+ // queue memory.
+ //
+ NdisZeroMemory(
+ Adapter->ReceiveQueue,
+ sizeof(TOK162_SUPER_RECEIVE_LIST) * Adapter->NumberOfReceiveBuffers
+ );
+
+ //
+ // Allocate the receive buffers and attach them to the Receive
+ // Queue entries.
+ //
+ VERY_LOUD_DEBUG(DbgPrint("Allocating Receive Buffers\n");)
+
+ for (i = 0, CurrentReceiveEntry = Adapter->ReceiveQueue;
+ i < Adapter->NumberOfReceiveBuffers;
+ i++, CurrentReceiveEntry++
+ ) {
+
+ VERY_LOUD_DEBUG(DbgPrint("ReceiveEntry[%d] = %08x\n",i,
+ CurrentReceiveEntry);)
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ Adapter->ReceiveBufferSize+8,
+ TRUE,
+ &CurrentReceiveEntry->ReceiveBuffer,
+ &CurrentReceiveEntry->ReceiveBufferPhysical
+ );
+
+ VERY_LOUD_DEBUG(DbgPrint("Receive Buffer is %08x\n",CurrentReceiveEntry->ReceiveBuffer);)
+
+ //
+ // If the current buffer could not be allocated, write the errorlog
+ // entry, delete allocated adapter memory, and return FALSE
+ //
+ if (!CurrentReceiveEntry->ReceiveBuffer) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Build flush buffers
+ //
+ NdisAllocateBuffer(
+ &Status,
+ &CurrentReceiveEntry->FlushBuffer,
+ Adapter->FlushBufferPoolHandle,
+ CurrentReceiveEntry->ReceiveBuffer,
+ Adapter->ReceiveBufferSize
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Initialize receive lists
+ //
+ NdisFlushBuffer(CurrentReceiveEntry->FlushBuffer, FALSE);
+
+ //
+ // Set the CSTAT to indicate this buffer is free
+ //
+ CurrentReceiveEntry->Hardware.CSTAT = RECEIVE_CSTAT_REQUEST_RESET;
+
+ //
+ // Set the size of the buffer
+ //
+ CurrentReceiveEntry->Hardware.DataCount1 =
+ BYTE_SWAP(Adapter->ReceiveBufferSize);
+
+ //
+ // Set the address of the buffer
+ //
+ CurrentReceiveEntry->Hardware.PhysicalAddress1 = BYTE_SWAP_ULONG(
+ NdisGetPhysicalAddressLow(
+ CurrentReceiveEntry->ReceiveBufferPhysical));
+
+ //
+ // Set the self-referencing pointer
+ //
+ NdisSetPhysicalAddressHigh (CurrentReceiveEntry->Self, 0);
+ NdisSetPhysicalAddressLow(
+ CurrentReceiveEntry->Self,
+ NdisGetPhysicalAddressLow(Adapter->ReceiveQueuePhysical) +
+ i * sizeof(TOK162_SUPER_RECEIVE_LIST));
+
+ //
+ // Create a circular list of receive buffers. For every one but the
+ // last, set the forward pointer to the next entry. The last entry
+ // has to point to the first entry (queue head).
+ //
+ if (i != (Adapter->NumberOfReceiveBuffers - 1)) {
+
+ CurrentReceiveEntry->Hardware.ForwardPointer = BYTE_SWAP_ULONG(
+ NdisGetPhysicalAddressLow(Adapter->ReceiveQueuePhysical) +
+ (i + 1) * sizeof(TOK162_SUPER_RECEIVE_LIST));
+
+ CurrentReceiveEntry->NextEntry = (PTOK162_SUPER_RECEIVE_LIST)(
+ (PUCHAR)(Adapter->ReceiveQueue) +
+ (i+1) * (sizeof(TOK162_SUPER_RECEIVE_LIST)));
+
+ } else {
+
+ CurrentReceiveEntry->Hardware.ForwardPointer = BYTE_SWAP_ULONG(
+ NdisGetPhysicalAddressLow(Adapter->ReceiveQueuePhysical)
+ );
+
+ CurrentReceiveEntry->NextEntry = Adapter->ReceiveQueue;
+
+ }
+
+ }
+
+ //
+ // If we made it this far, everything is ok. Return TRUE.
+ //
+ return TRUE;
+
+}
+
+
+VOID
+TOK162DeleteAdapterMemory(
+ IN PTOK162_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deallocates memory for:
+
+ - SCB
+
+ - SSB
+
+ - ErrorLog Block
+
+ - ReadAdapter Block
+
+ - Initialization Block
+
+ - Open Command Block
+
+ - Command Queue
+
+ - Transmit Command Queue
+
+ - Transmit Buffers
+
+ - Flush Buffer Pool
+
+ - Receive Queue
+
+ - Receive Buffers
+
+ - Receive Flush Buffers
+
+Arguments:
+
+ Adapter - The adapter to deallocate memory for.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Pointer to a command block used to initialize the command blocks
+ // and the transmit command blocks.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK CommandBlock;
+
+ //
+ // Iteration variable
+ //
+ USHORT i;
+
+ //
+ // Display to the debugger where we are
+ //
+ VERY_LOUD_DEBUG(DbgPrint("In delete adapter memory\n");)
+
+ //
+ // Free the SCB
+ //
+ if (Adapter->Scb != NULL) {
+
+ VERY_LOUD_DEBUG(DbgPrint("Freeing SCB\n");)
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(SCB) + 8,
+ FALSE,
+ Adapter->Scb,
+ Adapter->ScbPhysical
+ );
+
+ }
+
+ //
+ // Free the SSB
+ //
+ if (Adapter->Ssb != NULL) {
+
+ VERY_LOUD_DEBUG(DbgPrint("Freeing SSB - %x %x\n",Adapter->Ssb,
+ Adapter->SsbPhysical);)
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(SSB) + 8,
+ FALSE,
+ Adapter->Ssb,
+ Adapter->SsbPhysical
+ );
+
+ }
+
+ //
+ // Free the errorlog block
+ //
+ if (Adapter->ErrorLog != NULL) {
+
+ VERY_LOUD_DEBUG(DbgPrint("Freeing ErrorLog - %x\n",
+ Adapter->ErrorLog);)
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(TOK162_ERRORLOG) + 8,
+ FALSE,
+ Adapter->ErrorLog,
+ Adapter->ErrorLogPhysical
+ );
+
+ }
+
+ //
+ // Free the read adapter block
+ //
+ if (Adapter->AdapterBuf != NULL) {
+
+ VERY_LOUD_DEBUG(DbgPrint("Freeing Read Adapter Block\n");)
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ 4096,
+ FALSE,
+ Adapter->AdapterBuf,
+ Adapter->AdapterBufPhysical
+ );
+
+ }
+
+ //
+ // Free the initialization block
+ //
+ if (Adapter->InitializationBlock != NULL) {
+
+ VERY_LOUD_DEBUG(DbgPrint("Freeing Initialization Block\n");)
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(ADAPTER_INITIALIZATION) + 8,
+ FALSE,
+ Adapter->InitializationBlock,
+ Adapter->InitializationBlockPhysical
+ );
+
+ }
+
+ //
+ // Free the open command block
+ //
+ if (Adapter->Open != NULL) {
+
+ VERY_LOUD_DEBUG(DbgPrint("Freeing Open Block - %x\n",Adapter->Open);)
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(OPEN_COMMAND) + 8,
+ FALSE,
+ Adapter->Open,
+ Adapter->OpenPhysical
+ );
+
+ }
+
+ //
+ // Free the command queue
+ //
+ if (Adapter->CommandQueue != NULL) {
+
+ VERY_LOUD_DEBUG(DbgPrint("Freeing CommandQueue\n");)
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(TOK162_SUPER_COMMAND_BLOCK) *
+ (TOK162_NUMBER_OF_CMD_BLOCKS + 1),
+ FALSE,
+ Adapter->CommandQueue,
+ Adapter->CommandQueuePhysical
+ );
+
+ }
+
+ //
+ // Free the transmit command queue, transmit buffers, and flush buffers
+ //
+ if (Adapter->TransmitQueue != NULL) {
+
+ VERY_LOUD_DEBUG(DbgPrint("Freeing TransmitQueue\n");)
+
+ //
+ // First the buffers
+ //
+ for (i = 0, CommandBlock = Adapter->TransmitQueue;
+ i < Adapter->NumberOfTransmitLists;
+ i++,CommandBlock++
+ ) {
+
+ if (CommandBlock->TOK162BufferAddress != ((ULONG)NULL)) {
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ Adapter->ReceiveBufferSize,
+ FALSE,
+ (PVOID)(CommandBlock->TOK162BufferAddress),
+ CommandBlock->TOK162BufferPhysicalAddress
+ );
+
+ }
+
+ if (CommandBlock->FlushBuffer != NULL) {
+
+ NdisFreeBuffer(
+ CommandBlock->FlushBuffer
+ );
+
+ }
+
+ }
+
+ //
+ // Now the queue itself
+ //
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(TOK162_SUPER_COMMAND_BLOCK) *
+ Adapter->NumberOfTransmitLists,
+ FALSE,
+ Adapter->TransmitQueue,
+ Adapter->TransmitQueuePhysical
+ );
+
+ }
+
+ //
+ // Free the receive queue, receive buffers, and flush buffers
+ //
+ if (Adapter->ReceiveQueue != NULL) {
+
+ //
+ // Pointer to current Receive Entry being deallocated.
+ //
+ PTOK162_SUPER_RECEIVE_LIST CurrentReceiveEntry;
+
+ //
+ // Simple iteration counter.
+ //
+ UINT i;
+
+ VERY_LOUD_DEBUG(DbgPrint("Freeing ReceiveCommandQueue\n");)
+
+ for (i = 0, CurrentReceiveEntry = Adapter->ReceiveQueue;
+ i < Adapter->NumberOfReceiveBuffers;
+ i++, CurrentReceiveEntry++
+ ) {
+
+ if (CurrentReceiveEntry->ReceiveBuffer) {
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ Adapter->ReceiveBufferSize,
+ TRUE,
+ CurrentReceiveEntry->ReceiveBuffer,
+ CurrentReceiveEntry->ReceiveBufferPhysical
+ );
+
+
+ if (CurrentReceiveEntry->FlushBuffer != NULL) {
+
+ NdisFreeBuffer(
+ CurrentReceiveEntry->FlushBuffer
+ );
+
+ }
+ }
+
+ }
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(TOK162_SUPER_RECEIVE_LIST) *
+ Adapter->NumberOfReceiveBuffers,
+ FALSE,
+ Adapter->ReceiveQueue,
+ Adapter->ReceiveQueuePhysical
+ );
+
+ }
+
+ //
+ // Free the flush buffer pool handle
+ //
+ if (Adapter->FlushBufferPoolHandle) {
+
+ VERY_LOUD_DEBUG(DbgPrint("Freeing BufferPool\n");)
+
+ NdisFreeBufferPool(
+ Adapter->FlushBufferPoolHandle
+ );
+
+ }
+
+}
+
+
+extern
+VOID
+TOK162Halt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ TOK162Halt removes an adapter previously initialized.
+
+Arguments:
+
+ MiniportAdapterContext - The context value that the Miniport returned
+ from Tok162Initialize; actually is pointer to
+ a TOK162_ADAPTER.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Pointer to an adapter structure. Makes Context (passed in value)
+ // a structure we can deal with.
+ //
+ PTOK162_ADAPTER Adapter =
+ PTOK162_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ //
+ // Shut down the chip.
+ //
+ TOK162DisableInterrupt(Adapter);
+
+ //
+ // Return resources to the wrapper
+ //
+ NdisMDeregisterInterrupt(&Adapter->Interrupt);
+
+ NdisMDeregisterIoPortRange(Adapter->MiniportAdapterHandle,
+ Adapter->PortIOBase,
+ 0x30,
+ Adapter->PortIOAddress
+ );
+
+ NdisMFreeMapRegisters(Adapter->MiniportAdapterHandle);
+
+ //
+ // Free the allocated memory for the adapter-related structures
+ //
+ TOK162DeleteAdapterMemory(Adapter);
+
+ //
+ // Finally, free the allocated memory for the adapter structure itself
+ //
+ TOK162_FREE_PHYS(Adapter);
+
+}
+
+
+extern
+VOID
+TOK162Shutdown(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ TOK162Shutdown-- removes an adapter previously initialized.
+
+Arguments:
+
+ MiniportAdapterContext - The context value that the Miniport returned
+ from Tok162Initialize; actually is pointer to
+ a TOK162_ADAPTER.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Pointer to an adapter structure. Makes Context (passed in value)
+ // a structure we can deal with.
+ //
+
+ PTOK162_ADAPTER Adapter =
+ PTOK162_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ //
+ // Simply remove ourselves from the ring by doing a reset of the
+ // adapter.
+ //
+ TOK162ResetAdapter(Adapter);
+
+}
+
+
+NDIS_STATUS
+TOK162Reset(
+ OUT PBOOLEAN AddressingReset,
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+/*++
+
+Routine Description:
+
+ The TOK162Reset request instructs the Miniport to issue a hardware reset
+ to the network adapter. The driver also resets its software state. See
+ the description of NdisMReset for a detailed description of this request.
+
+Arguments:
+
+ MiniportAdapterContext - Pointer to the adapter structure.
+
+Return Value:
+
+ The function value is the status of the operation.
+--*/
+
+{
+ //
+ // Pointer to an adapter structure. Makes Context (passed in value)
+ // a structure we can deal with.
+ //
+ PTOK162_ADAPTER Adapter =
+ PTOK162_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+#if DBG
+ Tok162Debug = 0x08;
+#endif
+
+ VERY_LOUD_DEBUG(DbgPrint("Reset called\n");)
+
+ //
+ // Make sure we aren't already doing a reset.
+ //
+ if (Adapter->ResetInProgress == FALSE) {
+
+ Adapter->ResetInProgress = TRUE;
+
+ Adapter->ResetState = CheckReset;
+
+ TOK162SetupForReset(
+ Adapter
+ );
+
+ return NDIS_STATUS_PENDING;
+
+ } else {
+
+ //
+ // If we are doing a reset currently, return this fact.
+ //
+ return NDIS_STATUS_RESET_IN_PROGRESS;
+
+ }
+
+}
+
+
+BOOLEAN
+TOK162CheckForHang(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the wrapper to determine if the adapter
+ is hung.
+
+Arguments:
+
+ Context - Really a pointer to the adapter.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ //
+ // Pointer to an adapter structure. Makes Context (passed in value)
+ // a structure we can deal with.
+ //
+ PTOK162_ADAPTER Adapter =
+ PTOK162_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ //
+ // Variable pointing to the outstanding command. Used to make the
+ // code easier to read (could use Adapter->CommandOnCard).
+ //
+ PTOK162_SUPER_COMMAND_BLOCK FirstPendingCommand = Adapter->CommandOnCard;
+
+ //
+ // Variable pointing to the outstanding transmit. Used to make the
+ // code easier to read (could use Adapter->TransmitOnCard).
+ //
+ PTOK162_SUPER_COMMAND_BLOCK FirstPendingTransmit =
+ Adapter->TransmitOnCard;
+
+ //
+ // If we're in the middle of a reset, just return false
+ //
+ if (Adapter->ResetInProgress == TRUE) {
+
+ return FALSE;
+
+ }
+
+ //
+ // First see if there is a command outstanding
+ //
+ if (FirstPendingCommand != NULL) {
+
+ //
+ // See if the command block has timed-out.
+ //
+ if (FirstPendingCommand->Timeout) {
+
+ //
+ // See if we have given it enough time
+ //
+ if ( FirstPendingCommand->TimeoutCount >= 40) {
+
+ LOUD_DEBUG(DbgPrint("Returning True from checkforhang\n");)
+ return TRUE;
+
+ } else {
+
+ FirstPendingCommand->TimeoutCount++;
+
+ }
+
+ } else {
+
+ //
+ // Mark the current command as timed out and get the clock
+ // rolling.
+ //
+ FirstPendingCommand->Timeout = TRUE;
+ FirstPendingCommand->TimeoutCount = 0;
+
+ }
+
+ }
+
+ //
+ // Check if there is an outstanding transmit
+ //
+ if (FirstPendingTransmit != NULL) {
+
+ //
+ // See if the transmit has timed-out.
+ //
+ if (FirstPendingTransmit->Timeout) {
+
+ //
+ // See if we have given it enough time
+ //
+ if ( FirstPendingTransmit->TimeoutCount >= 40) {
+
+ //
+ // Give up, the card appears dead.
+ //
+ return TRUE;
+
+ } else {
+
+ FirstPendingTransmit->TimeoutCount++;
+
+ }
+
+ } else {
+
+ //
+ // Set outstanding transmit to timeout and start the clock
+ // rolling.
+ //
+ FirstPendingTransmit->Timeout = TRUE;
+ FirstPendingTransmit->TimeoutCount = 0;
+
+ }
+
+ }
+
+ //
+ // If we got here, we aren't hung.
+ //
+ return FALSE;
+}
+
+
+NDIS_STATUS
+TOK162TransferData(
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+ )
+
+/*++
+
+Routine Description:
+
+ A protocol calls the TOK162TransferData request (indirectly via
+ NdisTransferData) from within its Receive event handler
+ to instruct the Miniport to copy the contents of the received packet
+ a specified packet buffer.
+
+Arguments:
+
+ MiniportAdapterContext - The context value returned by the driver when the
+ adapter was initialized. In reality this is a
+ pointer to TOK162_ADAPTER.
+
+ MiniportReceiveContext - The context value passed by the driver on its
+ call to NdisMIndicateReceive. The driver can
+ use this value to determine which packet, on
+ which adapter, is being received.
+
+ ByteOffset - An unsigned integer specifying the offset within
+ the received packet at which the copy is to begin.
+ If the entire packet is to be copied,
+ ByteOffset must be zero.
+
+ BytesToTransfer - An unsigned integer specifying the number of
+ bytes to copy. It is legal to transfer zero
+ bytes; this has no effect. If the sum of
+ ByteOffset and BytesToTransfer is greater than
+ the size of the received packet, then the
+ remainder of the packet (starting from
+ ByteOffset) is transferred, and the trailing
+ portion of the receive buffer is not modified.
+
+ Packet - A pointer to a descriptor for the packet storage
+ into which the MAC is to copy the received packet.
+
+ BytesTransfered - A pointer to an unsigned integer. The miniport
+ writes the actual number of bytes transferred
+ into this location. This value is not valid if
+ the return status is STATUS_PENDING.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+
+ //
+ // Pointer to an adapter structure. Makes Context (passed in value)
+ // a structure we can deal with.
+ //
+ PTOK162_ADAPTER Adapter =
+ PTOK162_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ //
+ // Holds the count of the number of ndis buffers comprising the
+ // destination packet.
+ //
+ UINT DestinationBufferCount;
+
+ //
+ // Points to the buffer into which we are putting data.
+ //
+ PNDIS_BUFFER DestinationCurrentBuffer;
+
+ //
+ // Points to the location in Buffer from which we are extracting data.
+ //
+ PUCHAR SourceCurrentAddress;
+
+ //
+ // Holds the virtual address of the current destination buffer.
+ //
+ PVOID DestinationVirtualAddress;
+
+ //
+ // Holds the length of the current destination buffer.
+ //
+ UINT DestinationCurrentLength;
+
+ //
+ // Keep a local variable of BytesTransferred so we aren't referencing
+ // through a pointer.
+ //
+ UINT LocalBytesTransferred = 0;
+
+ //
+ // Display where we are on the debugger and log where we are.
+ //
+ LOUD_DEBUG(DbgPrint("TOK162!Transfer Data called\n");)
+ IF_LOG('n');
+
+ //
+ // Display number of bytes to transfer on the debugger
+ //
+ VERY_LOUD_DEBUG(DbgPrint("Copying %u bytes\n",BytesToTransfer);)
+
+ //
+ // Initialize the number of bytes transferred to 0
+ //
+ *BytesTransferred = 0;
+
+ //
+ // If we don't have any more to transfer, we're done
+ //
+ if (BytesToTransfer == 0) {
+
+ return NDIS_STATUS_SUCCESS;
+
+ }
+
+ //
+ // Get the first buffer of the destination.
+ //
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ &DestinationBufferCount,
+ &DestinationCurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet. If so, we are done.
+ //
+ if (DestinationBufferCount == 0) {
+
+ return NDIS_STATUS_SUCCESS;
+
+ }
+
+ //
+ // Get information on the buffer.
+ //
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+
+ //
+ // Set up the source address.
+ //
+ SourceCurrentAddress = (PCHAR)(MiniportReceiveContext) + ByteOffset;
+
+ //
+ // Do the actual transfer from source to destination
+ //
+ while (LocalBytesTransferred < BytesToTransfer) {
+
+ //
+ // Check to see whether we've exhausted the current destination
+ // buffer. If so, move onto the next one.
+ //
+ if (!DestinationCurrentLength) {
+
+ NdisGetNextBuffer(
+ DestinationCurrentBuffer,
+ &DestinationCurrentBuffer
+ );
+
+ if (!DestinationCurrentBuffer) {
+
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.)
+ //
+
+ break;
+
+ }
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+
+ continue;
+
+ }
+
+ //
+ // Copy the data.
+ //
+ {
+ //
+ // Holds the amount of data to move.
+ //
+ UINT AmountToMove;
+
+ //
+ // Holds the amount desired remaining.
+ //
+ UINT Remaining = BytesToTransfer - LocalBytesTransferred;
+
+
+ AmountToMove = DestinationCurrentLength;
+
+ AmountToMove = ((Remaining < AmountToMove)?
+ (Remaining):(AmountToMove));
+
+ NdisMoveMemory(
+ DestinationVirtualAddress,
+ SourceCurrentAddress,
+ AmountToMove
+ );
+
+ //
+ // Update pointers and counters
+ //
+ SourceCurrentAddress += AmountToMove;
+ LocalBytesTransferred += AmountToMove;
+ DestinationCurrentLength -= AmountToMove;
+
+ }
+
+ }
+
+ //
+ // Indicate how many bytes were transferred
+ //
+ *BytesTransferred = LocalBytesTransferred;
+
+ //
+ // Display total bytes transferred on debugger
+ //
+ VERY_LOUD_DEBUG(DbgPrint("Total bytes transferred = %x\n",
+ *BytesTransferred);)
+
+
+ //
+ // Log the fact that we are leaving transferdata
+ //
+ IF_LOG('N');
+
+ return NDIS_STATUS_SUCCESS;
+
+}
+
+
+BOOLEAN
+TOK162InitializeTransmitQueue(
+ IN PTOK162_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the transmit queue
+
+Arguments:
+
+ Adapter - Current Adapter structure
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Local pointer to command blocks
+ //
+ PTOK162_SUPER_COMMAND_BLOCK CurrentCommandBlock;
+
+ //
+ // Counter variable
+ //
+ USHORT i;
+
+ //
+ // Status variable
+ //
+ NDIS_STATUS Status;
+
+ //
+ // Initialize the Adapter structure fields associate with transmit lists
+ //
+ Adapter->NextTransmitBlock = 0;
+ Adapter->NumberOfAvailableTransmitBlocks =
+ Adapter->NumberOfTransmitLists;
+
+ //
+ // Zero the memory of the transmit queue
+ //
+ NdisZeroMemory(
+ Adapter->TransmitQueue,
+ sizeof(TOK162_SUPER_COMMAND_BLOCK) * Adapter->NumberOfTransmitLists
+ );
+
+ //
+ // Put the Transmit Command Blocks into a known state.
+ //
+ for (i = 0, CurrentCommandBlock = Adapter->TransmitQueue;
+ i < Adapter->NumberOfTransmitLists;
+ i++, CurrentCommandBlock++
+ ) {
+
+ //
+ // Set the next command pointer to NULL
+ //
+ CurrentCommandBlock->NextCommand = NULL;
+
+ //
+ // Set the self-referential pointer
+ //
+ NdisSetPhysicalAddressHigh (CurrentCommandBlock->Self, 0);
+ NdisSetPhysicalAddressLow(
+ CurrentCommandBlock->Self,
+ NdisGetPhysicalAddressLow(Adapter->TransmitQueuePhysical) +
+ i * sizeof(TOK162_SUPER_COMMAND_BLOCK));
+
+ CurrentCommandBlock->PhysicalTransmitEntry =
+ NdisGetPhysicalAddressLow(CurrentCommandBlock->Self);
+
+ //
+ // This is a transmit block, not a command block
+ //
+ CurrentCommandBlock->CommandBlock = FALSE;
+
+ //
+ // Set the index and the timeout values
+ //
+ CurrentCommandBlock->CommandBlockIndex = i;
+ CurrentCommandBlock->Timeout = FALSE;
+
+ //
+ // Initialize the hardware portion of the command block.
+ // Set the state to free and next pending to NULL.
+ //
+ CurrentCommandBlock->Hardware.State = TOK162_STATE_FREE;
+ CurrentCommandBlock->Hardware.NextPending = TOK162_NULL;
+
+ //
+ // Allocate the transmit buffer associated with this transmit
+ // list entry
+ //
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ Adapter->ReceiveBufferSize + 8,
+ FALSE,
+ &((PVOID)CurrentCommandBlock->TOK162BufferAddress),
+ &CurrentCommandBlock->TOK162BufferPhysicalAddress
+ );
+
+ LOUD_DEBUG(DbgPrint("XMITBuffer %u = %lx %lx\n",i,
+ CurrentCommandBlock->TOK162BufferAddress,
+ NdisGetPhysicalAddressLow(
+ CurrentCommandBlock->TOK162BufferPhysicalAddress));)
+
+ //
+ // If the allocation failed, write the errorlog and return FALSE
+ //
+ if (CurrentCommandBlock->TOK162BufferAddress == (ULONG)NULL) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+
+ return FALSE;
+
+ }
+
+//
+// Remove the following section because it isn't needed. Flush buffers on
+// transmits appear to be causing hangs on mips machines.
+//
+#if 0
+ //
+ // Build flush buffers
+ //
+ NdisAllocateBuffer(
+ &Status,
+ &CurrentCommandBlock->FlushBuffer,
+ Adapter->FlushBufferPoolHandle,
+ (PVOID)CurrentCommandBlock->TOK162BufferAddress,
+ Adapter->ReceiveBufferSize
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ return FALSE;
+
+ }
+#endif
+ }
+
+ //
+ // If we got here, everything is ok. Return TRUE.
+ //
+ return TRUE;
+
+}
diff --git a/private/ntos/ndis/ibmtok2i/tok162.rc b/private/ntos/ndis/ibmtok2i/tok162.rc
new file mode 100644
index 000000000..f211525d9
--- /dev/null
+++ b/private/ntos/ndis/ibmtok2i/tok162.rc
@@ -0,0 +1,38 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "IBM Token Ring 16/4 Adapter II ISA Network Driver"
+#define VER_INTERNALNAME_STR "IBMTOK2I.SYS"
+#define VER_ORIGINALFILENAME_STR "IBMTOK2I.SYS"
+
+#include "common.ver"
diff --git a/private/ntos/ndis/ibmtok2i/tok162hw.h b/private/ntos/ndis/ibmtok2i/tok162hw.h
new file mode 100644
index 000000000..d0cf26ab3
--- /dev/null
+++ b/private/ntos/ndis/ibmtok2i/tok162hw.h
@@ -0,0 +1,1382 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ tokhrd.h
+
+Abstract:
+
+ The hardware-related definitions for the IBM Token-Ring 16/4 II
+ ISA driver.
+
+Author:
+
+ Kevin Martin (kevinma) 1-Feb-1994
+
+Environment:
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ References to "IBM Spec" refer to the IBM "Supplement to the LAN
+ Technical Reference (Token-Ring Network 16/4 Adapter II)" Specification.
+ The document number is - SD21-052-00.
+
+ References to "TI Spec" refer to the Texas Instruments "TMS380 Second-
+ Generation Token Ring" User's Guide. The document number is - SPWU005.
+
+Revision History:
+
+--*/
+
+//
+// Pack everything on word boundaries
+//
+#include <pshpack2.h>
+
+//
+// Define "Physical Addresses" which are ULONG in size. The card
+// wants physical addresses.
+//
+typedef ULONG TOK162_PHYSICAL_ADDRESS, *PTOK162_PHYSICAL_ADDRESS;
+
+
+//
+// The length of an address (network) is 6 bytes
+//
+#define TOK162_LENGTH_OF_ADDRESS 6
+
+//
+// Define a NULL pointer
+//
+#define TOK162_NULL ((TOK162_PHYSICAL_ADDRESS)(-1L))
+
+//
+// Default number of command blocks
+//
+#define TOK162_NUMBER_OF_CMD_BLOCKS 4
+
+//
+// Burst size for transmit and receive DMA. A zero tells the adapter to
+// use the size of the transfer as the burst size.
+//
+// IBM Spec, Page 21
+
+#define TOK162_BURST_SIZE 0
+
+//
+// Number of retries to attempt after a DMA error
+//
+#define TOK162_DMA_RETRIES 0x0303
+
+//
+// Minimum packet size for a valid transfer/receive
+//
+#define MINIMUM_TOKENRING_PACKET_SIZE 32
+
+//
+// Default packet header size
+//
+#define TOK162_HEADER_SIZE 32
+
+//
+// TOK162 Receive/Command Block States
+//
+#define TOK162_STATE_FREE ((USHORT)0x0000)
+#define TOK162_STATE_EXECUTING ((USHORT)0x0001)
+#define TOK162_STATE_WAIT_FOR_ADAPTER ((USHORT)0x0002)
+
+//
+// Start of I/O ports based on switch settings.
+//
+// IBM Spec, Page 9.
+//
+#define BASE_OPTION_ZERO 0x86A0
+#define BASE_OPTION_ONE 0xC6A0
+#define BASE_OPTION_TWO 0xA6A0
+#define BASE_OPTION_THREE 0xE6A0
+#define BASE_OPTION_FOUR 0x96A0
+#define BASE_OPTION_FIVE 0xD6A0
+#define BASE_OPTION_SIX 0xB6A0
+#define BASE_OPTION_SEVEN 0xF6A0
+
+//
+// Offsets from above of the actual ports used.
+//
+// IBM Spec, Page 4.
+//
+#define PORT_OFFSET_DATA 0x0000
+#define PORT_OFFSET_DATA_AUTO_INC 0x0002
+#define PORT_OFFSET_ADDRESS 0x0004
+#define PORT_OFFSET_STATUS 0x0006
+#define PORT_OFFSET_COMMAND 0x0006
+#define PORT_OFFSET_ADAPTER_RESET 0x0008
+#define PORT_OFFSET_ADAPTER_ENABLE 0x000A
+#define PORT_OFFSET_SWITCH_INT_DISABLE 0x000C
+#define PORT_OFFSET_SWITCH_INT_ENABLE 0x000E
+
+//
+// Macro to write a ULONG variable to a register on the adapter
+//
+#define WRITE_ADAPTER_ULONG(a, p, v) \
+ NdisRawWritePortUshort((ULONG) (a)->PortIOAddress + (p), \
+ (ULONG) (v))
+
+//
+// Macro to read a ULONG variable from a register on the adapter
+//
+#define READ_ADAPTER_ULONG(a, p, v) \
+ NdisRawReadPortUshort((ULONG) (a)->PortIOAddress + (p), \
+ (PULONG) (v))
+
+//
+// Macro to write a USHORT variable to a register on the adapter
+//
+#define WRITE_ADAPTER_USHORT(a, p, v) \
+ NdisRawWritePortUshort((ULONG) (a)->PortIOAddress + (p), \
+ (USHORT) (v))
+
+//
+// Macro to read a USHORT variable from a register on the adapter
+//
+#define READ_ADAPTER_USHORT(a, p, v) \
+ NdisRawReadPortUshort((ULONG) (a)->PortIOAddress + (p), \
+ (PUSHORT) (v))
+
+//
+// Macro to write a CHAR variable to a register on the adapter
+//
+#define WRITE_ADAPTER_UCHAR(a, p, v) \
+ NdisRawWritePortUchar((ULONG)(a)->PortIOAddress + (p), \
+ (UCHAR)(v))
+
+//
+// Macro to read a ULONG variable from a register on the adapter
+//
+#define READ_ADAPTER_UCHAR(a, p, v) \
+ NdisRawReadPortUchar((ULONG)(a)->PortIOAddress + (p), \
+ (PUCHAR)(v))
+
+//
+// Masks for the command register
+//
+// IBM Spec, Pages 5-6.
+//
+#define CMD_PIO_INTERRUPT 0x8000
+#define CMD_PIO_RESET 0x4000
+#define CMD_PIO_SSB_CLEAR 0x2000
+#define CMD_PIO_EXECUTE 0x1000
+#define CMD_PIO_SCB_REQUEST 0x0800
+#define CMD_PIO_RCV_CONTINUE 0x0400
+#define CMD_PIO_RCV_VALID 0x0200
+#define CMD_PIO_XMIT_VALID 0x0100
+#define CMD_PIO_RESET_SYSTEM 0x0080
+
+//
+// Common mask combinations
+//
+#define EXECUTE_SCB_COMMAND 0x9080 // int+exec+resetsysint
+#define ENABLE_SSB_UPDATE 0xA000 // int+ssbclear
+#define ENABLE_RECEIVE_VALID 0x8200 // int+rcvvalid
+
+//
+// Masks for the status register.
+//
+// IBM Spec, Pages 6-7.
+//
+#define STATUS_ADAPTER_INTERRUPT 0x8000
+#define STATUS_SYSTEM_INTERRUPT 0x0080
+
+//
+// Masks for adapter interrupts.
+//
+// IBM Spec, Page 7.
+//
+#define STATUS_INT_CODE_MASK 0x000F
+#define STATUS_INT_CODE_CHECK 0x0000
+#define STATUS_INT_CODE_IMPL 0x0002
+#define STATUS_INT_CODE_RING 0x0004
+#define STATUS_INT_CODE_SCB_CLEAR 0x0006
+#define STATUS_INT_CODE_CMD_STATUS 0x0008
+#define STATUS_INT_CODE_RECEIVE_STATUS 0x000A
+#define STATUS_INT_CODE_XMIT_STATUS 0x000C
+
+//
+// My Mask for System Interrupts
+//
+#define MASK_ADAPTER_CHECK 0x0001
+#define MASK_RING_STATUS 0x0002
+#define MASK_SCB_CLEAR 0x0004
+#define MASK_COMMAND_STATUS 0x0008
+#define MASK_RECEIVE_STATUS 0x0010
+#define MASK_TRANSMIT_STATUS 0x0020
+
+
+//
+// Adapter switch structure. The switches determine the configuration of the
+// card.
+//
+// IBM Spec, Page 8.
+//
+typedef struct _ADAPTERSWITCHES {
+
+ //
+ // Connector Type.
+ //
+ USHORT UTP_STP:1;
+
+ //
+ // Token Ring Speed
+ //
+ USHORT RingSpeed:1;
+
+ //
+ // DMA Channel
+ //
+ USHORT DMA:2;
+
+ //
+ // Is Remote Program Load enabled?
+ //
+ USHORT RPL:1;
+
+ //
+ // Adapter mode, test or normal
+ //
+ USHORT AdapterMode:1;
+
+ //
+ // Adapter wait state
+ //
+ USHORT WaitState:1;
+
+ //
+ // Interrupt Request Level
+ //
+ USHORT IntRequest:2;
+
+ //
+ // RPL address (if RPL enabled) or adapter I/O base address
+ //
+ USHORT RPL_PIO_Address:3;
+
+ //
+ // Not used.
+ //
+ USHORT Reserved:4;
+} ADAPTERSWITCHES,*PADAPTERSWITCHES;
+
+//
+// #defines for the I/O Address switches
+//
+// IBM Spec, Page 9.
+//
+#define SW_PIO_ADDR_8 0x00
+#define SW_PIO_ADDR_C 0x01
+#define SW_PIO_ADDR_A 0x02
+#define SW_PIO_ADDR_E 0x03
+#define SW_PIO_ADDR_9 0x04
+#define SW_PIO_ADDR_D 0x05
+#define SW_PIO_ADDR_B 0x06
+#define SW_PIO_ADDR_F 0x07
+
+//
+// #defines for the interrupt request level
+//
+// IBM Spec, Page 9.
+//
+#define SW_INT_9 0x00
+#define SW_INT_11 0x01
+#define SW_INT_10 0x02
+#define SW_INT_15 0x03
+
+//
+// #defines for the wait state.
+//
+// IBM Spec, Page 9.
+//
+#define SW_WAITSTATE_NORMAL 0x00
+#define SW_WAITSTATE_FAST 0x01
+
+//
+// #defines for the adapter mode.
+//
+// IBM Spec, Page 10.
+//
+#define SW_ADAPTERMODE_NORMAL 0x00
+#define SW_ADAPTERMODE_TEST 0x01
+
+//
+// #defines for RPL
+//
+// IBM Spec, Page 10.
+//
+#define SW_RPL_DISABLE 0x00
+#define SW_RPL_ENABLE 0x01
+
+//
+// #defines for the DMA channel
+//
+// IBM Spec, Page 10.
+//
+#define SW_DMA_5 0x00
+#define SW_DMA_7 0x01
+#define SW_DMA_6 0x02
+
+//
+// #defines for the ring speed.
+//
+// IBM Spec, Page 10.
+//
+#define SW_RINGSPEED_4 0x00
+#define SW_RINGSPEED_16 0x01
+
+//
+// #defines for the connector interface.
+//
+// IBM Spec, Page 10.
+//
+#define SW_STP 0x00
+#define SW_UTP 0x01
+
+//
+// DMA Command Values
+//
+// IBM Spec, Page 25.
+//
+#define CMD_DMA_OPEN 0x0300
+#define CMD_DMA_XMIT 0x0400
+#define CMD_DMA_XMIT_HALT 0x0500
+#define CMD_DMA_RCV 0x0600
+#define CMD_DMA_CLOSE 0x0700
+#define CMD_DMA_SET_GRP_ADDR 0x0800
+#define CMD_DMA_SET_FUNC_ADDR 0x0900
+#define CMD_DMA_READ_ERRLOG 0x0A00
+#define CMD_DMA_READ 0x0B00
+#define CMD_DMA_IMPL_ENABLE 0x0C00
+#define CMD_DMA_START_STOP_TRACE 0x0D00
+
+//
+// System Command Block structure.
+//
+// IBM Spec, Pages 13-14.
+//
+typedef struct _SCB {
+
+ //
+ // Command to be submitted to the card.
+ //
+ USHORT Command;
+
+ //
+ // Parameter USHORTs, different for different commands.
+ //
+ USHORT Parm1;
+ USHORT Parm2;
+
+} SCB, *PSCB;
+
+//
+// Generic System Status Block Structure.
+//
+// IBM Spec, Page 15.
+//
+typedef struct _SSB {
+
+ //
+ // Command for which status is returned.
+ //
+ USHORT Command;
+
+ //
+ // Status USHORTs, different for different commands
+ //
+ USHORT Status1;
+ USHORT Status2;
+ USHORT Status3;
+
+} SSB, *PSSB;
+
+//
+// Ring Status SSB #defines and structure
+//
+// IBM Spec, Page 15-16.
+//
+typedef struct _SSB_RING_STATUS {
+
+ //
+ // Command code, will be SSB_CMD_RING_STATUS
+ //
+ USHORT Command;
+
+ //
+ // Ring Status code, as defined below.
+ //
+ USHORT RingStatus;
+
+ //
+ // Last two not used.
+ //
+ USHORT Reserved1;
+ USHORT Reserved2;
+
+} SSB_RING_STATUS,*PSSB_RING_STATUS;
+
+#define SSB_CMD_RING_STATUS 0x0100
+
+#define RING_STATUS_OVERFLOW 0x8000
+#define RING_STATUS_SINGLESTATION 0x4000
+#define RING_STATUS_RINGRECOVERY 0x2000
+#define RING_STATUS_SIGNAL_LOSS 0x0080
+#define RING_STATUS_HARD_ERROR 0x0040
+#define RING_STATUS_SOFT_ERROR 0x0020
+#define RING_STATUS_XMIT_BEACON 0x0010
+#define RING_STATUS_LOBE_WIRE_FAULT 0x0008
+#define RING_STATUS_AUTO_REMOVE_1 0x0004
+#define RING_STATUS_REMOVE_RECEIVED 0x0001
+
+//
+// Command Reject Status SSB #defines and structure
+//
+typedef struct _SSB_CMD_REJECT_STATUS {
+
+ //
+ // Command code, will be SSB_CMD_COMMAND_REJECT_STATUS
+ //
+ USHORT Command;
+
+ //
+ // Reason for rejection, as defined below.
+ //
+ USHORT Reason;
+
+ //
+ // Command that was rejected.
+ //
+ USHORT SCBCommand;
+
+ //
+ // Not used.
+ //
+ USHORT Reserved;
+
+} SSB_CMD_REJECT_STATUS, *PSSB_CMD_REJECT_STATUS;
+
+#define SSB_CMD_COMMAND_REJECT_STATUS 0x0200
+
+#define CMD_REJECT_STATUS_BAD_CMD 0x0080
+#define CMD_REJECT_STATUS_BAD_ADDR 0x0040
+#define CMD_REJECT_STATUS_BAD_OPEN 0x0020
+#define CMD_REJECT_STATUS_BAD_CLOSED 0x0010
+#define CMD_REJECT_STATUS_BAD_SAME 0x0008
+
+//
+// Adapter Check Port information, structure and defines
+//
+// IBM Spec, Pages 18-19.
+//
+
+//
+// Offsets within the adapter memory where the values for the check can
+// be obtained.
+//
+// IBM Spec, Page 18.
+//
+#define ADAPTER_CHECK_PORT_OFFSET_BASE 0x05E0
+#define ADAPTER_CHECK_PORT_OFFSET_PARM0 0x05E2
+#define ADAPTER_CHECK_PORT_OFFSET_PARM1 0x05E4
+#define ADAPTER_CHECK_PORT_OFFSET_PARM2 0x05E6
+
+//
+// Structure that can be used to gather all of the adapter check information.
+//
+typedef struct _ADAPTER_CHECK {
+
+ //
+ // USHORT indicating why the adapter check occurred. Reasons are defined
+ // below.
+ //
+ USHORT Check;
+
+ //
+ // The parameters are used based on the reason above. Please see the spec
+ // as to what the different parameters are for the given reason.
+ //
+ USHORT Parm0;
+ USHORT Parm1;
+ USHORT Parm2;
+
+} ADAPTER_CHECK, *PADAPTER_CHECK;
+
+#define ADAPTER_CHECK_DMA_ABORT_READ 0x4000
+#define ADAPTER_CHECK_DMA_ABORT_WRITE 0x2000
+#define ADAPTER_CHECK_ILLEGAL_OPCODE 0x1000
+#define ADAPTER_CHECK_PARITY_ERR 0x0800
+#define ADAPTER_CHECK_PARITY_ERR_EXT 0x0400
+#define ADAPTER_CHECK_PARITY_ERR_SIM 0x0200 // System Interface Master
+#define ADAPTER_CHECK_PARITY_ERR_PHM 0x0100 // Protocol Handler Master
+#define ADAPTER_CHECK_PARITY_ERR_RR 0x0080 // Ring Receive
+#define ADAPTER_CHECK_PARITY_ERR_RXMT 0x0040 // Ring Transmit
+#define ADAPTER_CHECK_RING_UNDERRUN 0x0020
+#define ADAPTER_CHECK_RING_OVERRUN 0x0010
+#define ADAPTER_CHECK_INVALID_INT 0x0008
+#define ADAPTER_CHECK_INVALID_ERR_INT 0x0004
+#define ADAPTER_CHECK_INVALID_XOP 0x0002
+#define ADAPTER_CHECK_PROGRAM_CHECK 0x0001
+
+//
+// Initialization Structure.
+//
+// IBM Spec, Pages 19-25.
+//
+
+//
+// This structure needs to be packed on a two-byte boundary or the
+// SCB pointer will be off during the loop that sends the initialization
+// bytes to the card.
+//
+
+typedef struct _ADAPTER_INITIALIZATION {
+
+ //
+ // Initialization options as defined below
+ //
+ USHORT Options;
+
+ //
+ // Reserved USHORTs
+ //
+ USHORT Reserved1;
+ USHORT Reserved2;
+ USHORT Reserved3;
+
+ //
+ // Size of DMA bursts on receives
+ //
+ USHORT ReceiveBurstSize;
+
+ //
+ // Size of DMA bursts on transmits
+ //
+ USHORT TransmitBurstSize;
+
+ //
+ // Number of retries on DMA errors before giving up
+ //
+ USHORT DMAAbortThresholds;
+
+ //
+ // Pointer to the SCB (physical pointer), split into two words
+ // because we are writing them to the adaper in words
+ //
+ USHORT SCBHigh;
+ USHORT SCBLow;
+
+ //
+ // Pointer to the SSB (physical pointer), split into words because
+ // we are writing them to the adapter in words
+ //
+ USHORT SSBHigh;
+ USHORT SSBLow;
+
+} ADAPTER_INITIALIZATION, *PADAPTER_INITIALIZATION;
+
+//
+// Initialization options
+//
+#define INIT_OPTIONS_RESERVED 0x8000
+#define INIT_OPTIONS_SCBSSB_BURST 0x1000
+#define INIT_OPTIONS_SCBSSB_CYCLE 0x0000
+#define INIT_OPTIONS_LIST_BURST 0x0800
+#define INIT_OPTIONS_LIST_CYCLE 0x0000
+#define INIT_OPTIONS_LIST_STATUS_BURST 0x0400
+#define INIT_OPTIONS_LIST_STATUS_CYCLE 0x0000
+#define INIT_OPTIONS_RECEIVE_BURST 0x0200
+#define INIT_OPTIONS_RECEIVE_CYCLE 0x0000
+#define INIT_OPTIONS_XMIT_BURST 0x0100
+#define INIT_OPTIONS_XMIT_CYCLE 0x0000
+#define INIT_OPTIONS_SPEED_16 0x0040
+#define INIT_OPTIONS_SPEED_4 0x0000
+#define INIT_OPTIONS_DISABLE_ETR 0x0020
+#define INIT_OPTIONS_ENABLE_ETR 0x0000
+
+//
+// Starting address on card of where to write the init block
+//
+// IBM Spec, Page 22.
+//
+#define INIT_ADAPTER_PORT_OFFSET 0x0200
+
+//
+// Value to write to the command register after the init block has been
+// downloaded.
+//
+#define INIT_ADAPTER_INTERRUPT 0x9080
+
+//
+// Bit masks for initialization results.
+//
+// IBM Spec, Page 23.
+//
+#define STATUS_INIT_INITIALIZE 0x0040
+#define STATUS_INIT_TEST 0x0020
+#define STATUS_INIT_ERROR 0x0010
+
+//
+// Bring-Up Error Codes
+//
+// IBM Spec, Pages 23-24
+//
+#define BRING_UP_ERR_INIT_TEST 0x0000
+#define BRING_UP_ERR_CRC 0x0001
+#define BRING_UP_ERR_RAM 0x0002
+#define BRING_UP_ERR_INSTRUCTION_TEST 0x0003
+#define BRING_UP_ERR_INT_TEST 0x0004
+#define BRING_UP_ERR_PROTOCOL_HANDLER 0x0005
+#define BRING_UP_ERR_SYSTEM_INTERFACE_REG 0x0006
+
+//
+// Initialize Error Codes
+//
+// IBM Spec, Page 24.
+//
+#define INITIALIZE_ERR_PARM_LEN 0x0001
+#define INITIALIZE_ERR_INV_OPTIONS 0x0002
+#define INITIALIZE_ERR_INV_RCV_BURST 0x0003
+#define INITIALIZE_ERR_INV_XMIT_BURST 0x0004
+#define INITIALIZE_ERR_INV_DMA_ABORT 0x0005
+#define INITIALIZE_ERR_INV_SCB 0x0006
+#define INITIALIZE_ERR_INV_SSB 0x0007
+#define INITIALIZE_ERR_DMA_TIMEOUT 0x0009
+#define INITIALIZE_ERR_DMA_BUS 0x000B
+#define INITIALIZE_ERR_DMA_DATA 0x000C
+#define INITIALIZE_ERR_ADAPTER_CHECK 0x000D
+
+//
+// Recommended burst sizes.
+//
+// IBM Spec, Page 25.
+//
+#define DEFAULT_BURST_SIZE_FAST 0x004C
+#define DEFAULT_BURST_SIZE_NORMAL 0x0040
+
+//
+// TOK162 ErrorLog structure.
+//
+// IBM Spec, Page 35.
+//
+typedef struct _TOK162_ERRORLOG {
+
+ //
+ // These are error count fields. The adapter resets the internal
+ // counters after they are read into this structure.
+ //
+ UCHAR LineError;
+ UCHAR InternalError;
+ UCHAR BurstError;
+ UCHAR ARIFCIError;
+ UCHAR AbortDelimeter;
+ UCHAR Reserved1;
+ UCHAR LostFrameError;
+ UCHAR ReceiveCongestionError;
+ UCHAR FrameCopiedError;
+ UCHAR Reserved2;
+ UCHAR TokenError;
+ UCHAR Reserved3;
+ UCHAR DMABusError;
+ UCHAR Reserved4;
+
+} TOK162_ERRORLOG, *PTOK162_ERRORLOG;
+
+//
+// TOK162 Read Adapter Log structure. Used to get permanent address, current
+// addresses (network, group, functional), the microcode level, and the MAC
+// buffer.
+//
+// IBM Spec, Pages 32-33.
+//
+typedef struct _TOK162_READADAPTERBUF {
+
+ //
+ // Number of bytes to be read from the adapter
+ //
+ USHORT DataCount;
+
+ //
+ // Offset for buffer
+ //
+ USHORT DataAddress;
+
+ //
+ // Buffer space
+ //
+ UCHAR BufferSpace[68-6];
+
+} TOK162_READADAPTERBUF, *PTOK162_READADAPTERBUF;
+
+//
+// TOK162 Address Block
+//
+// IBM Spec, Page 33.
+//
+typedef struct _TOK162_ADDRESSBLOCK {
+
+ //
+ // The node address. Used for both the current address and the permanent
+ // address (depending on the read call).
+ //
+ UCHAR NodeAddress[6];
+
+ //
+ // The current group address.
+ //
+ UCHAR GroupAddress[4];
+
+ //
+ // The current functional address.
+ //
+ UCHAR FunctionalAddress[4];
+
+} TOK162_ADDRESSBLOCK, *PTOK162_ADDRESSBLOCK;
+
+//
+// TOK162 Receive List
+//
+// IBM Spec, Pages 36-40.
+//
+typedef struct _TOK162_RECEIVE_LIST {
+
+ //
+ // This is the physical address of the next entry
+ // in the Receive Ring.
+ //
+ TOK162_PHYSICAL_ADDRESS ForwardPointer;
+
+ //
+ // List entry characteristics
+ //
+ USHORT CSTAT;
+
+ //
+ // This is the total size of the received frame.
+ //
+ USHORT FrameSize;
+
+ //
+ // This is the length (in bytes) of the buffer associated. IBM Format.
+ //
+ USHORT DataCount1;
+
+ //
+ // This is the address of the buffer associated. IBM Format.
+ //
+ ULONG PhysicalAddress1;
+
+ //
+ // This is the length (in bytes) of this block. Stored in IBM format
+ //
+ USHORT DataCount2;
+
+ //
+ // This is the physical address of this block. Stored in IBM Format
+ //
+ ULONG PhysicalAddress2;
+
+ //
+ // This is the length (in bytes) of this block. Stored in IBM format
+ //
+ USHORT DataCount3;
+
+ //
+ // This is the physical address of this block. Stored in IBM Format
+ //
+ ULONG PhysicalAddress3;
+
+ //
+ // This is the length (in bytes) of this block. Stored in IBM format
+ //
+ USHORT DataCount4;
+
+ //
+ // This is the physical address of this block. Stored in IBM Format
+ //
+ ULONG PhysicalAddress4;
+
+ //
+ // This is the length (in bytes) of this block. Stored in IBM format
+ //
+ USHORT DataCoun5;
+
+ //
+ // This is the physical address of this block. Stored in IBM Format
+ //
+ ULONG PhysicalAddress5;
+
+ //
+ // This is the length (in bytes) of this block. Stored in IBM format
+ //
+ USHORT DataCount6;
+
+ //
+ // This is the physical address of this block. Stored in IBM Format
+ //
+ ULONG PhysicalAddress6;
+
+ //
+ // This is the length (in bytes) of this block. Stored in IBM format
+ //
+ USHORT DataCount7;
+
+ //
+ // This is the physical address of this block. Stored in IBM Format
+ //
+ ULONG PhysicalAddress7;
+
+ //
+ // This is the length (in bytes) of this block. Stored in IBM format
+ //
+ USHORT DataCount8;
+
+ //
+ // This is the physical address of this block. Stored in IBM Format
+ //
+ ULONG PhysicalAddress8;
+
+ //
+ // This is the length (in bytes) of this block. Stored in IBM format
+ //
+ USHORT DataCount9;
+
+ //
+ // This is the physical address of this block. Stored in IBM Format
+ //
+ ULONG PhysicalAddress9;
+
+} TOK162_RECEIVE_LIST, *PTOK162_RECEIVE_LIST;
+
+//
+// Receive and Transmit buffer sizes, depending on the ring speed.
+//
+// IBM Spec, Page 13.
+//
+#define RECEIVE_LIST_BUFFER_SIZE_4 4500
+#define RECEIVE_LIST_BUFFER_SIZE_16 17986
+
+//
+// The number of receive lists/buffers
+//
+#define RECEIVE_LIST_COUNT 3
+
+//
+// Receive CSTAT bit masks
+//
+// IBM Spec, Pages 38-39.
+//
+#define RECEIVE_CSTAT_REQUEST_RESET 0x0088 // Valid bit + frame int
+#define RECEIVE_CSTAT_VALID 0x0080 // Valid bit
+
+//
+// Transmit list entry. This is exactly like the receive list entry.
+//
+// IBM Spec, Pages 46-55.
+//
+typedef struct _TOK162_TRANSMIT_LIST {
+
+ //
+ // This is the physical address of the next entry
+ // in the Transmit Chain.
+ //
+ TOK162_PHYSICAL_ADDRESS ForwardPointer;
+
+ //
+ // List entry characteristics. IBM Format.
+ //
+ USHORT CSTAT;
+
+ //
+ // This is the total size of the received frame. IBM Format.
+ //
+ USHORT FrameSize;
+
+ //
+ // This is the length (in bytes) of this block. Stored in IBM format
+ //
+ USHORT DataCount1;
+
+ //
+ // This is the physical address of this block. Stored in IBM Format
+ //
+ TOK162_PHYSICAL_ADDRESS PhysicalAddress1;
+
+ //
+ // This is the length (in bytes) of this block. Stored in IBM format
+ //
+ USHORT DataCount2;
+
+ //
+ // This is the physical address of this block. Stored in IBM Format
+ //
+ TOK162_PHYSICAL_ADDRESS PhysicalAddress2;
+
+ //
+ // This is the length (in bytes) of this block. Stored in IBM format
+ //
+ USHORT DataCount3;
+
+ //
+ // This is the physical address of this block. Stored in IBM Format
+ //
+ TOK162_PHYSICAL_ADDRESS PhysicalAddress3;
+
+ //
+ // This is the length (in bytes) of this block. Stored in IBM format
+ //
+ USHORT DataCount4;
+
+ //
+ // This is the physical address of this block. Stored in IBM Format
+ //
+ TOK162_PHYSICAL_ADDRESS PhysicalAddress4;
+
+ //
+ // This is the length (in bytes) of this block. Stored in IBM format
+ //
+ USHORT DataCoun5;
+
+ //
+ // This is the physical address of this block. Stored in IBM Format
+ //
+ TOK162_PHYSICAL_ADDRESS PhysicalAddress5;
+
+ //
+ // This is the length (in bytes) of this block. Stored in IBM format
+ //
+ USHORT DataCount6;
+
+ //
+ // This is the physical address of this block. Stored in IBM Format
+ //
+ TOK162_PHYSICAL_ADDRESS PhysicalAddress6;
+
+ //
+ // This is the length (in bytes) of this block. Stored in IBM format
+ //
+ USHORT DataCount7;
+
+ //
+ // This is the physical address of this block. Stored in IBM Format
+ //
+ TOK162_PHYSICAL_ADDRESS PhysicalAddress7;
+
+ //
+ // This is the length (in bytes) of this block. Stored in IBM format
+ //
+ USHORT DataCount8;
+
+ //
+ // This is the physical address of this block. Stored in IBM Format
+ //
+ TOK162_PHYSICAL_ADDRESS PhysicalAddress8;
+
+ //
+ // This is the length (in bytes) of this block. Stored in IBM format
+ //
+ USHORT DataCount9;
+
+ //
+ // This is the physical address of this block. Stored in IBM Format
+ //
+ TOK162_PHYSICAL_ADDRESS PhysicalAddress9;
+
+} TOK162_TRANSMIT_LIST, *PTOK162_TRANSMIT_LIST;
+
+//
+// The number of transmit lists
+//
+#define TRANSMIT_LIST_COUNT 0x0002
+
+//
+// The maximum number of transmit list scatter-gathers
+//
+#define TOK162_MAX_SG 0x0003
+
+//
+// Transmit CSTAT bit masks
+//
+#define TRANSMIT_CSTAT_REQUEST 0x00B0
+#define TRANSMIT_CSTAT_XMIT_ERROR 0x0004
+
+//
+// TOK162 Command Block. Contains all of the fields necessary to support
+// both commands and transmits.
+//
+typedef struct _TOK162_COMMAND_BLOCK {
+
+ //
+ // Transmit List Entry
+ //
+ TOK162_TRANSMIT_LIST TransmitEntry;
+
+ //
+ // This is the state of this Command Block.
+ //
+ USHORT State;
+
+ //
+ // This is the status of this Command Block.
+ //
+ USHORT Status;
+
+ //
+ // This is the physical address of the next Command Block
+ // to be executed. If this address == -1, then there are
+ // no more commands to be executed.
+ //
+ UNALIGNED TOK162_PHYSICAL_ADDRESS NextPending;
+
+ //
+ // This is the TOK162 Command Code.
+ //
+ USHORT CommandCode;
+
+ //
+ // Pointer used by different commands
+ //
+ ULONG ParmPointer;
+
+ //
+ // This is the immediate data to be used by all commands
+ // other than transmit.
+ //
+ ULONG ImmediateData;
+
+} TOK162_COMMAND_BLOCK, *PTOK162_COMMAND_BLOCK;
+
+
+//
+// Data block pointer
+// Used only to reference the different fields of the transmit list entry.
+// Allows code to access the transmit list entries in a for loop rather than
+// having code for each specific entry.
+//
+// Must be packed on a 2 byte boundary.
+//
+typedef struct _TOK162_DATA_BLOCK {
+
+ //
+ // size of the block. IBM format.
+ //
+ USHORT Size;
+
+ //
+ // physical pointer to the buffer. IBM format.
+ //
+ TOK162_PHYSICAL_ADDRESS IBMPhysicalAddress;
+
+} TOK162_DATA_BLOCK,*PTOK162_DATA_BLOCK;
+
+//
+// Numerical values for switches
+// (e.g. - Interrupt 5 instead of 00 [switch value])
+//
+// IBM Spec, Pages 8-10.
+//
+
+//
+// Adapter mode values
+//
+#define CFG_ADAPTERMODE_NORMAL 0x0000
+#define CFG_ADAPTERMODE_TEST 0x0001
+
+//
+// Wait state values
+//
+#define CFG_WAITSTATE_NORMAL 0x0000
+#define CFG_WAITSTATE_FAST 0x0001
+
+//
+// DMA channel values
+//
+#define CFG_DMACHANNEL_5 0x0005
+#define CFG_DMACHANNEL_6 0x0006
+#define CFG_DMACHANNEL_7 0x0007
+
+//
+// Connector type values
+//
+#define CFG_MEDIATYPE_STP 0x0000
+#define CFG_MEDIATYPE_UTP 0x0001
+
+//
+// Adapter interrupt values
+//
+#define CFG_INT_9 0x0009
+#define CFG_INT_10 0x000A
+#define CFG_INT_11 0x000B
+#define CFG_INT_15 0x000F
+
+//
+// RPL address values
+//
+#define CFG_RPLADDR_C0000 0xC0000
+#define CFG_RPLADDR_C4000 0xC4000
+#define CFG_RPLADDR_C8000 0xC8000
+#define CFG_RPLADDR_CC000 0xCC000
+#define CFG_RPLADDR_D0000 0xD0000
+#define CFG_RPLADDR_D4000 0xD4000
+#define CFG_RPLADDR_D8000 0xD8000
+#define CFG_RPLADDR_DC000 0xDC000
+
+//
+// Ring speed values
+//
+#define CFG_RINGSPEED_4 0x0004
+#define CFG_RINGSPEED_16 0x0010
+
+//
+// command and result structures
+//
+
+//
+// Open command structure. Submitted to the card to insert the system in
+// the Token Ring.
+//
+// IBM Spec, Pages 27-32.
+//
+typedef struct _OPEN_COMMAND {
+
+ //
+ // Open options. Defined below.
+ //
+ USHORT Options;
+
+ //
+ // Address to insert ourselves into the ring under.
+ //
+ UCHAR NodeAddress[6];
+
+ //
+ // Group address adapter should respond to.
+ //
+ ULONG GroupAddress;
+
+ //
+ // Functional address adapter should respond to.
+ //
+ ULONG FunctionalAddress;
+
+ //
+ // Size of the receive list structure
+ //
+ USHORT ReceiveListSize;
+ //
+ // Size of the transmit list structure
+ //
+ USHORT TransmitListSize;
+
+ //
+ // Adapter buffer size.
+ //
+ USHORT BufferSize;
+
+ //
+ // Unused.
+ //
+ USHORT Reserved1;
+ USHORT Reserved2;
+
+ //
+ // Minimum number of buffers to reserve for transmits
+ //
+ UCHAR TransmitBufCountMin;
+
+ //
+ // Maximum number of buffers to reserve for transmits
+ //
+ UCHAR TransmitBufCountMax;
+
+ //
+ // Pointer to the system product ID
+ //
+ ULONG ProdIDAddress;
+
+} OPEN_COMMAND, *POPEN_COMMAND;
+
+#define OPEN_OPTION_PASS_BEACON_FRAMES 0x8000
+#define OPEN_OPTION_DISABLE_DMA_TIMEOUT 0x4000
+#define OPEN_OPTION_ENABLE_DMA_TIMEOUT 0x0000
+#define OPEN_OPTION_WRAP_INTERFACE 0x0080
+#define OPEN_OPTION_DISABLE_HARD_ERROR 0x0040
+#define OPEN_OPTION_ENABLE_HARD_ERROR 0x0000
+#define OPEN_OPTION_DISABLE_SOFT_ERROR 0x0020
+#define OPEN_OPTION_ENABLE_SOFT_ERROR 0x0000
+#define OPEN_OPTION_PASS_ADAPTER_FRAMES 0x0010
+#define OPEN_OPTION_PASS_ATTENTION_FRAMES 0x0008
+#define OPEN_OPTION_PAD_ROUTING_FIELD 0x0004
+#define OPEN_OPTION_FRAME_HOLD 0x0002
+#define OPEN_OPTION_CONTENDER 0x0001
+
+//
+// Values to set the open parameters to
+//
+#define OPEN_RECEIVE_LIST_SIZE 0x000e
+#define OPEN_TRANSMIT_LIST_SIZE 0x001A
+#define OPEN_BUFFER_SIZE 512
+
+//
+// Open completion structure (SSB)
+//
+// IBM Spec, Pages 31-32.
+//
+typedef struct _OPEN_COMPLETION {
+
+ //
+ // Better be CMD_DMA_OPEN.
+ //
+ USHORT Command;
+
+ //
+ // Completion code. Bitmasks defined below.
+ //
+ USHORT Completion;
+
+ //
+ // Not used.
+ //
+ USHORT Reserved1;
+ USHORT Reserved2;
+
+} OPEN_COMPLETION, *POPEN_COMPLETION;
+
+#define OPEN_COMPLETION_MASK_PHASE 0xF000
+#define OPEN_COMPLETION_MASK_ERROR 0x0F00
+#define OPEN_COMPLETION_MASK_RESULT 0x00FF
+
+#define OPEN_COMPLETION_PHASE_LOBE 0x1000
+#define OPEN_COMPLETION_PHASE_INSERTION 0x2000
+#define OPEN_COMPLETION_PHASE_VERIFY 0x3000
+#define OPEN_COMPLETION_PHASE_RING 0x4000
+#define OPEN_COMPLETION_PHASE_PARMS 0x5000
+
+#define OPEN_COMPLETION_ERROR_FUNCTION 0x0100
+#define OPEN_COMPLETION_ERROR_SIGLOSS 0x0200
+#define OPEN_COMPLETION_ERROR_TIMEOUT 0x0500
+#define OPEN_COMPLETION_ERROR_RINGFAIL 0x0600
+#define OPEN_COMPLETION_ERROR_RINGBEACON 0x0700
+#define OPEN_COMPLETION_ERROR_DUPLICATE 0x0800
+#define OPEN_COMPLETION_ERROR_REQPARMS 0x0900
+#define OPEN_COMPLETION_ERROR_REMOVE_REC 0x0A00
+#define OPEN_COMPLETION_ERROR_IMPL_REC 0x0B00
+#define OPEN_COMPLETION_ERROR_DUPMOD 0x0C00
+
+#define OPEN_RESULT_ADAPTER_OPEN 0x0080
+#define OPEN_RESULT_NODE_ADDR_ERROR 0x0040
+#define OPEN_RESULT_LIST_SIZE_ERROR 0x0020
+#define OPEN_RESULT_BUF_SIZE_ERROR 0x0010
+#define OPEN_RESULT_EXT_RAM_ERROR 0x0008
+#define OPEN_RESULT_XMIT_CNT_ERROR 0x0004
+#define OPEN_RESULT_OPEN_ERROR 0x0002
+
+//
+// The adapter requires many of the WORD values and almost all of the
+// DWORD values to be in IBM format, versus Intel Format. The difference
+// between the two is as follows:
+//
+// If you are storing the value 0x1234, a word value, memory would look like:
+//
+// --------- ---------
+// | | | |
+// Intel | 34 | | 12 |
+// | | | |
+// --------- ---------
+// Address 100 101
+//
+//
+// --------- ---------
+// | | | |
+// IBM | 12 | | 34 |
+// | | | |
+// --------- ---------
+// Address 100 101
+//
+//
+// If you are storing the value 0x12345678, a dword value, memory would look
+// like:
+//
+// --------- --------- --------- ---------
+// | | | | | | | |
+// Intel | 78 | | 56 | | 34 | | 12 |
+// | | | | | | | |
+// --------- --------- --------- ---------
+// Address 100 101
+//
+//
+// --------- --------- --------- ---------
+// | | | | | | | |
+// IBM | 12 | | 34 | | 56 | | 78 |
+// | | | | | | | |
+// --------- --------- --------- ---------
+// Address 100 101
+//
+//
+// To convert "Intel" WORDs and DWORDs to "IBM" format, the following macros
+// are used.
+//
+
+//
+// Macro to byte swap a word.
+//
+#define BYTE_SWAP(_word) (\
+ (USHORT) (((_word) >> 8) | ((_word) << 8)) )
+
+//
+// Macro to byte swap a word.
+//
+#define WORD_SWAP(_dword) (\
+ (ULONG) (((_dword) >> 16) | ((_dword) << 16)) )
+
+//
+// Macro to get low byte of a word.
+//
+#define LOW_BYTE(_word) (\
+ (UCHAR) ((_word) & 0x00FF) )
+
+//
+// Macro to get high byte of a word.
+//
+#define HIGH_BYTE(_word) (\
+ (UCHAR) (((_word) >> 8) & 0x00FF) )
+
+//
+// Macro to get low word of a dword.
+//
+#define LOW_WORD(_dword) (\
+ (USHORT) ((_dword) & 0x0000FFFF) )
+
+//
+// Macro to get high word of a dword.
+//
+#define HIGH_WORD(_dword) (\
+ (USHORT) (((_dword) >> 16) & 0x0000FFFF) )
+
+//
+// Macro to create a dword from two words.
+//
+#define MAKE_LONG(_highword,_lowword) (\
+ (ULONG) ((((ULONG)_highword) << 16) + _lowword))
+
+//
+// Macro to byte swap a dword.
+//
+#define BYTE_SWAP_ULONG(_ulong) (\
+ (ULONG)((ULONG)(BYTE_SWAP(LOW_WORD(_ulong)) << 16) + \
+ BYTE_SWAP(HIGH_WORD(_ulong))))
+
+//
+// End the packing
+//
+#include <poppack.h>
diff --git a/private/ntos/ndis/ibmtok2i/tok162pr.h b/private/ntos/ndis/ibmtok2i/tok162pr.h
new file mode 100644
index 000000000..1875cdd23
--- /dev/null
+++ b/private/ntos/ndis/ibmtok2i/tok162pr.h
@@ -0,0 +1,315 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ tok162pr.h
+
+Abstract:
+
+ The procedure declarations for the IBM Token-Ring 16/4 II
+ ISA driver.
+
+Author:
+
+ Kevin Martin (kevinma) 1-Feb-1994
+
+Environment:
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+
+--*/
+
+#ifndef _TOK162PROC_
+#define _TOK162PROC_
+
+//
+// We define the external interfaces to the TOK162 driver.
+// These routines are only external to permit separate
+// compilation. Given a truely fast compiler they could
+// all reside in a single file and be static.
+//
+
+extern
+VOID
+TOK162DisableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+extern
+VOID
+TOK162EnableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+extern
+VOID
+TOK162Halt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+extern
+VOID
+TOK162Shutdown(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+extern
+VOID
+TOK162HandleInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+extern
+BOOLEAN
+TOK162InitialInit(
+ IN PTOK162_ADAPTER Adapter
+ );
+extern
+NDIS_STATUS
+TOK162Initialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ );
+
+extern
+NDIS_STATUS
+TOK162QueryInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+ );
+
+extern
+NDIS_STATUS
+TOK162SetInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ );
+
+extern
+VOID
+TOK162Isr(
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueDpc,
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+extern
+NDIS_STATUS
+TOK162Reset(
+ OUT PBOOLEAN AddressingReset,
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+extern
+NDIS_STATUS
+TOK162TransferData(
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+ );
+
+extern
+NDIS_STATUS
+TOK162Send(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET Packet,
+ IN UINT Flags
+ );
+
+extern
+VOID
+TOK162CopyFromBufferToPacket(
+ IN PCHAR Buffer,
+ IN UINT BytesToCopy,
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ OUT PUINT BytesCopied
+ );
+
+
+VOID
+TOK162FinishQueryInformation(
+ IN PTOK162_ADAPTER Adapter
+);
+
+extern
+NDIS_STATUS
+TOK162RegisterAdapter(
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PUCHAR CurrentAddress,
+ IN UINT PortAddress,
+ IN ULONG MaxFrameSize
+ );
+
+extern
+VOID
+TOK162AcquireCommandBlock(
+ IN PTOK162_ADAPTER Adapter,
+ OUT PTOK162_SUPER_COMMAND_BLOCK * CommandBlock
+ );
+
+extern
+BOOLEAN
+TOK162AcquireTransmitBlock(
+ IN PTOK162_ADAPTER Adapter,
+ OUT PTOK162_SUPER_COMMAND_BLOCK * CommandBlock
+ );
+
+extern
+VOID
+TOK162RelinquishCommandBlock(
+ IN PTOK162_ADAPTER Adapter,
+ IN PTOK162_SUPER_COMMAND_BLOCK CommandBlock
+ );
+
+extern
+VOID
+TOK162SubmitCommandBlock(
+ IN PTOK162_ADAPTER Adapter,
+ IN PTOK162_SUPER_COMMAND_BLOCK CommandBlock
+ );
+
+extern
+VOID
+TOK162DoAdapterReset(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+extern
+NDIS_STATUS
+TOK162SetupForReset(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+BOOLEAN
+TOK162CheckForHang(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+VOID
+TOK162ResetVariables(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+VOID
+TOK162ResetHandler(
+ IN PVOID SystemSpecific1,
+ IN PTOK162_ADAPTER Adapter,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+VOID
+TOK162DeferredTimer(
+ IN PVOID SystemSpecific1,
+ IN PTOK162_ADAPTER Adapter,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+
+extern
+NDIS_STATUS
+TOK162GetAdapterConfiguration(
+ IN PTOK162_ADAPTER Adapter
+ );
+extern
+VOID
+TOK162ResetAdapter(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+BOOLEAN
+DoTheOpen(
+ PTOK162_ADAPTER Adapter
+ );
+
+BOOLEAN
+DoTheReceive(
+ PTOK162_ADAPTER Adapter
+ );
+
+extern
+NDIS_STATUS
+TOK162ChangeFuncGroup(
+ IN PTOK162_ADAPTER Adapter
+);
+
+
+BOOLEAN
+TOK162InitializeTransmitQueue(
+ IN PTOK162_ADAPTER Adapter
+ );
+VOID
+TOK162ResetTimer(
+ IN PVOID SystemSpecific1,
+ IN PTOK162_ADAPTER Adapter,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+VOID
+TOK162DoResetIndications(
+ IN PTOK162_ADAPTER Adapter,
+ IN NDIS_STATUS Status
+ );
+
+BOOLEAN
+TOK162AcquireTransmitBlock(
+ IN PTOK162_ADAPTER Adapter,
+ OUT PTOK162_SUPER_COMMAND_BLOCK * CommandBlock
+ );
+
+VOID
+TOK162RelinquishTransmitBlock(
+ IN PTOK162_ADAPTER Adapter,
+ IN PTOK162_SUPER_COMMAND_BLOCK CommandBlock
+ );
+
+VOID
+TOK162SubmitTransmitBlock(
+ IN PTOK162_ADAPTER Adapter,
+ IN PTOK162_SUPER_COMMAND_BLOCK CommandBlock
+ );
+VOID
+TOK162ProcessTransmitInterrupts(
+ IN PTOK162_ADAPTER Adapter
+ );
+extern
+BOOLEAN
+TOK162ProcessRingInterrupts(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+extern
+VOID
+TOK162DeleteAdapterMemory(
+ IN PTOK162_ADAPTER Adapter
+ );
+
+#endif //_TOK162PROC_
diff --git a/private/ntos/ndis/ibmtok2i/tok162sw.h b/private/ntos/ndis/ibmtok2i/tok162sw.h
new file mode 100644
index 000000000..8f431b6b1
--- /dev/null
+++ b/private/ntos/ndis/ibmtok2i/tok162sw.h
@@ -0,0 +1,699 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ tok162sw.h
+
+Abstract:
+
+ The hardware-related definitions for the IBM Token-Ring 16/4 II
+ ISA driver.
+
+Author:
+
+ Kevin Martin (kevinma) 1-Feb-1994
+
+Environment:
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+#include <tok162hw.h>
+
+//
+// Temporary #define for debugging regardless of DBG flag
+//
+#define MYDBGPRINT DbgPrint;
+
+//
+// Debugging flags.
+//
+#if DBG
+
+//
+// Degrees of debugging output. Can be OR'd in any combination.
+//
+#define TOK162_DEBUG_LOUD 0x1
+#define TOK162_DEBUG_VERY_LOUD 0x2
+#define TOK162_DEBUG_EXTRA_LOUD 0x4
+
+//
+// The degree of debugging output being displayed on the debugger currently.
+// Defined in TOK162.C.
+//
+extern UCHAR Tok162Debug;
+
+//
+// Macros that decide on the debugging based on Tok162Debug.
+//
+#define LOUD_DEBUG(A) if (Tok162Debug & TOK162_DEBUG_LOUD) { A ; }
+#define VERY_LOUD_DEBUG(A) if (Tok162Debug & TOK162_DEBUG_VERY_LOUD) { A ; }
+#define EXTRA_LOUD_DEBUG(A) if (Tok162Debug & TOK162_DEBUG_EXTRA_LOUD) { A ; }
+#define CURRENT_DEBUG(A) if (Tok162Debug & 8) { A ; }
+
+//
+// The size of the logging array
+//
+#define LOG_SIZE 256
+
+//
+// Pointer for the logging array. Allocated in TOK162.C
+// (AllocateAdapterMemory)
+//
+extern PUCHAR Tok162Log;
+
+//
+// The current index into the logging array.
+//
+extern USHORT Tok162LogPlace;
+
+//
+// Logging macro.
+//
+#define IF_LOG(ch) { Tok162Log[Tok162LogPlace] = (ch); \
+ Tok162LogPlace = (Tok162LogPlace + 1) % LOG_SIZE; }
+
+#else // if dbg
+
+//
+// Make sure all of the debugging and logging calls resolve to NULL
+//
+#define LOUD_DEBUG(A)
+#define VERY_LOUD_DEBUG(A)
+#define EXTRA_LOUD_DEBUG(A)
+
+#define IF_LOG(ch) { }
+
+#endif // if dbg
+
+//
+// Version constants for this driver
+//
+#define TOK162_NDIS_MAJOR_VERSION 3
+#define TOK162_NDIS_MINOR_VERSION 0
+
+//
+// Macro to allocate physical memory.
+//
+#define TOK162_ALLOC_PHYS(_Status, _pBuffer, _Length) \
+{ \
+ NDIS_PHYSICAL_ADDRESS MinusOne = NDIS_PHYSICAL_ADDRESS_CONST (-1, -1); \
+ *(_Status) = NdisAllocateMemory( \
+ (PVOID*)(_pBuffer), \
+ (_Length), \
+ 0, \
+ MinusOne); \
+}
+
+//
+// Macro to free physical memory previously allocated.
+//
+#define TOK162_FREE_PHYS(_Buffer) NdisFreeMemory((_Buffer), 0, 0)
+
+//
+// Enumeration for the reset stages.
+//
+enum ResetStates{InitialInit,
+ CheckReset,
+ CheckResetRetry,
+ DoTheInit,
+ CheckInit,
+ CheckInitRetry
+ };
+
+//
+// Adapter structure is defined further down.
+//
+struct _TOK162_ADAPTER;
+
+
+//
+// TOK162 Configuration Block
+//
+// This structure contains configuration data for the TOK162. This
+// structure is filled in based on the switches.
+//
+typedef struct _TOK162_CONFIGURATION_BLOCK {
+
+ //
+ // This is the adapter mode;
+ //
+ USHORT AdapterMode;
+
+ //
+ // This field contains the wait state
+ //
+ USHORT WaitState;
+
+ //
+ // This field contains the RPL
+ //
+ BOOLEAN RPL;
+
+ //
+ // This field contains the RPL Address
+ //
+ UINT RPLAddress;
+
+ //
+ // This field contains the DMA Channel
+ //
+ USHORT DMAChannel;
+
+ //
+ // This field contains the Ring Speed
+ //
+ USHORT RingSpeed;
+
+ //
+ // Interrupt level
+ //
+ USHORT InterruptLevel;
+
+ //
+ // This field contains the connector type
+ //
+ USHORT UTPorSTP;
+
+} TOK162_CONFIGURATION_BLOCK, *PTOK162_CONFIGURATION_BLOCK;
+
+//
+// In addition to the Command Block fields which the TOK162HW.H
+// defines, we need some additional fields for our own purposes.
+// To ensure that these fields are properly aligned (and to
+// ensure that the actual Command Block is properly aligned)
+// we'll defined a Super Command Block. This structure will
+// contain a "normal" TOK162 Command Block plus some additional
+// fields. This structure is used for both commands and transmits.
+//
+typedef struct _TOK162_SUPER_COMMAND_BLOCK {
+
+ //
+ // The actual TOK162 Command Block.
+ //
+ TOK162_COMMAND_BLOCK Hardware;
+
+ //
+ // This contains the physical address of the above Command Block.
+ //
+ NDIS_PHYSICAL_ADDRESS Self;
+ TOK162_PHYSICAL_ADDRESS PhysicalTransmitEntry;
+
+ //
+ // Constrain Buffer addresses
+ //
+ NDIS_PHYSICAL_ADDRESS TOK162BufferPhysicalAddress;
+ TOK162_PHYSICAL_ADDRESS TOK162BufferAddress;
+
+ //
+ // This contains the virtual address of the next pending command.
+ //
+ struct _TOK162_SUPER_COMMAND_BLOCK *NextCommand;
+
+ //
+ // Points to the packet from which data is being transmitted
+ // through this Command Block.
+ //
+ PNDIS_PACKET OwningPacket;
+
+ //
+ // When a packet is submitted to the hardware we record
+ // here whether it used adapter buffers and if so, the buffer
+ // index.
+ //
+ BOOLEAN UsedTOK162Buffer;
+
+ //
+ // Is this from a set
+ //
+ BOOLEAN Set;
+
+ //
+ // If this is a public (adapter-wide) command block, then
+ // this will contain this block's index into the adapter's
+ // command queue.
+ //
+ USHORT CommandBlockIndex;
+
+ //
+ // This tells if the command block is a regular or transmit command block.
+ //
+ BOOLEAN CommandBlock;
+
+ //
+ // This field is used to timestamp the command blocks
+ // as they are placed into the command queue. If a
+ // block fails to execute, the adapter will get a kick in the ass to
+ // start it up again.
+ //
+ BOOLEAN Timeout;
+
+ //
+ // Count of the number of times we have retried a command.
+ //
+ UCHAR TimeoutCount;
+
+ //
+ // Points to an Mdl which points to this buffer
+ //
+ PNDIS_BUFFER FlushBuffer;
+
+} TOK162_SUPER_COMMAND_BLOCK, *PTOK162_SUPER_COMMAND_BLOCK;
+
+//
+// In addition to the Receive Entry fields which the TOK162HW.H
+// defines, we need some additional fields for our own purposes.
+// To ensure that these fields are properly aligned (and to
+// ensure that the actual Receive Entry is properly aligned)
+// we'll defined a Super Receive Entry. This structure will
+// contain a "normal" TOK162 Receive Entry plus some additional
+// fields.
+//
+typedef struct _TOK162_SUPER_RECEIVE_LIST {
+
+ //
+ // The actual TOK162 Receive List.
+ //
+ TOK162_RECEIVE_LIST Hardware;
+
+ //
+ // This contains the physical address of the above Receive List.
+ //
+ NDIS_PHYSICAL_ADDRESS Self;
+
+ //
+ // This contains the virtual address of this Receive List's
+ // frame buffer.
+ //
+ PVOID ReceiveBuffer;
+ NDIS_PHYSICAL_ADDRESS ReceiveBufferPhysical;
+
+ //
+ // This contains the virtual address of the next
+ // Receive List in the Receive Queue.
+ //
+ struct _TOK162_SUPER_RECEIVE_LIST *NextEntry;
+
+ //
+ // Points to an Mdl which points to this buffer
+ //
+ PNDIS_BUFFER FlushBuffer;
+
+} TOK162_SUPER_RECEIVE_LIST, *PTOK162_SUPER_RECEIVE_LIST;
+
+//
+// Adapter Structure
+//
+
+typedef struct _TOK162_ADAPTER {
+
+ //
+ // Handle given by NDIS when the miniport was initialized.
+ //
+ NDIS_HANDLE MiniportAdapterHandle;
+
+ //
+ // Interrupt pointers and variables for the adapter
+ //
+ NDIS_MINIPORT_INTERRUPT Interrupt;
+ USHORT InterruptLevel;
+
+ //
+ // Are we running at 16Mbps?
+ //
+ BOOLEAN Running16Mbps;
+
+ //
+ // Pointers for the System Command Block for the adapter
+ //
+ PSCB Scb;
+ NDIS_PHYSICAL_ADDRESS ScbPhysical;
+
+ //
+ // Pointers for the System Status Block for the adapter
+ //
+ PSSB Ssb;
+ NDIS_PHYSICAL_ADDRESS SsbPhysical;
+
+ //
+ // Command queue and related variables
+ //
+ PTOK162_SUPER_COMMAND_BLOCK CommandQueue;
+ NDIS_PHYSICAL_ADDRESS CommandQueuePhysical;
+
+ //
+ // Index to next command block
+ //
+ UINT NextCommandBlock;
+
+ //
+ // Number of command blocks available for use
+ //
+ UINT NumberOfAvailableCommandBlocks;
+
+ //
+ // Active command.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK CommandOnCard;
+
+ //
+ // First pending command.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK WaitingCommandHead;
+
+ //
+ // Last pending command.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK WaitingCommandTail;
+
+ //
+ // Current packet filter on adapter
+ //
+ UINT CurrentPacketFilter;
+
+ //
+ // Is there an outstanding request
+ //
+ BOOLEAN RequestInProgress;
+
+ //
+ // Number of bytes needed and written.
+ //
+ PUINT BytesWritten;
+ PUINT BytesNeeded;
+
+ //
+ // Current Oid processing.
+ //
+ NDIS_OID Oid;
+
+ //
+ // Buffer and length of buffer used for doing query/set info calls.
+ //
+ PVOID InformationBuffer;
+ UINT InformationBufferLength;
+
+ //
+ // Current interrupt value
+ //
+ USHORT InterruptMask;
+
+ //
+ // Command that caused the interrupt
+ //
+ USHORT SsbCommand;
+
+ //
+ // The status variables that are saved as the result of an interrupt
+ //
+ USHORT SsbStatus1;
+ USHORT SsbStatus2;
+ USHORT SsbStatus3;
+
+ //
+ // The I/O Base address of the adapter.
+ //
+ ULONG PortIOBase;
+ PVOID PortIOAddress;
+
+ //
+ // Pointers and variables for the Open block for the adapter
+ //
+ POPEN_COMMAND Open;
+ NDIS_PHYSICAL_ADDRESS OpenPhysical;
+
+ //
+ // The network address for the adapter and the current one being used.
+ //
+ CHAR NetworkAddress[TOK162_LENGTH_OF_ADDRESS];
+ CHAR CurrentAddress[TOK162_LENGTH_OF_ADDRESS];
+
+ //
+ // Functional and Group Addresses for the adapter
+ //
+ ULONG FunctionalAddress;
+ ULONG GroupAddress;
+
+ //
+ // Pointer to the Receive Queue.
+ //
+ PTOK162_SUPER_RECEIVE_LIST ReceiveQueue;
+ NDIS_PHYSICAL_ADDRESS ReceiveQueuePhysical;
+
+ //
+ // Pointer to the current receive list
+ //
+ PTOK162_SUPER_RECEIVE_LIST ReceiveQueueCurrent;
+
+ //
+ // Number of frame header bytes in the buffer.
+ //
+ USHORT SizeOfReceivedHeader;
+
+ //
+ // Count of the receive buffers
+ //
+ UINT NumberOfReceiveBuffers;
+
+ //
+ // Size of the receive buffer, based on the ring speed.
+ //
+ USHORT ReceiveBufferSize;
+
+ //
+ // The receive flush buffer pool handle
+ //
+ PNDIS_HANDLE FlushBufferPoolHandle;
+
+ //
+ // Pointer to the Transmit Command Queue.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK TransmitQueue;
+ NDIS_PHYSICAL_ADDRESS TransmitQueuePhysical;
+
+ //
+ // Index of next available transmit block
+ //
+ UINT NextTransmitBlock;
+
+ //
+ // Pointer to active transmit.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK TransmitOnCard;
+
+ //
+ // Pointer to head of waiting queue.
+ //
+ PTOK162_SUPER_COMMAND_BLOCK WaitingTransmitHead;
+
+ //
+ // Pointer to tail of waiting queue
+ //
+ PTOK162_SUPER_COMMAND_BLOCK WaitingTransmitTail;
+
+ //
+ // Number of transmit blocks currently free
+ //
+ UINT NumberOfAvailableTransmitBlocks;
+
+ //
+ // Total number of transmit blocks/lists
+ //
+ UINT NumberOfTransmitLists;
+
+ //
+ // Maximum number of physical buffers that we can handle and still not
+ // have to merge the packet
+ //
+ USHORT TransmitThreshold;
+
+ //
+ // Flag that when enabled lets routines know that a reset
+ // is in progress.
+ //
+ BOOLEAN ResetInProgress;
+
+ //
+ // Are we doing the initial initialization?
+ //
+ BOOLEAN InitialInit;
+
+ //
+ // Has the initial open completed?
+ //
+ BOOLEAN InitialOpenComplete;
+
+ //
+ // Has the initial receive command been sent
+ //
+ BOOLEAN InitialReceiveSent;
+
+ //
+ // Last open error code.
+ //
+ USHORT OpenErrorCode;
+
+ //
+ // Reset State
+ //
+ USHORT ResetState;
+
+ //
+ // Variables to keep track of the number of retries attempted during
+ // a reset
+ //
+ USHORT ResetRetries;
+ USHORT InitRetries;
+
+ //
+ // Result of Reset command
+ //
+ NDIS_STATUS ResetResult;
+
+ //
+ // Offsets into adapter memory for different structures.
+ // These are obtained at initialization time and the values
+ // are read using the READ.ADAPTER DMA command.
+ //
+ USHORT UniversalAddress;
+ USHORT MicrocodeLevel;
+ USHORT AdapterAddresses;
+ USHORT AdapterParms;
+ USHORT MacBuffer;
+
+ //
+ // Buffer for READ.ERROR.LOG
+ //
+ PTOK162_ERRORLOG ErrorLog;
+ NDIS_PHYSICAL_ADDRESS ErrorLogPhysical;
+
+ //
+ // Buffer for READ.ADAPTER for node addresses. If more info is needed
+ // in the future, this will have to be changed as the current addresses
+ // are being stored here (func,node,group)
+ //
+ PTOK162_READADAPTERBUF AdapterBuf;
+ NDIS_PHYSICAL_ADDRESS AdapterBufPhysical;
+
+ //
+ // Counters to hold the various number of errors/statistics for both
+ // reception and transmission.
+ //
+ UINT ReceiveCongestionError;
+ UINT LineError;
+ UINT LostFrameError;
+ UINT BurstError;
+ UINT FrameCopiedError;
+ UINT TokenError;
+ UINT InternalError;
+ UINT ARIFCIError;
+ UINT AbortDelimeter;
+ UINT DMABusError;
+
+ //
+ // Packet counts
+ //
+ UINT GoodTransmits;
+ UINT GoodReceives;
+ UINT TransmitsQueued;
+ UINT BadTransmits;
+ UINT BadReceives;
+
+ //
+ // Timer objects for TOK162InterruptHandler and TOK162ResetHandler
+ //
+ NDIS_MINIPORT_TIMER DeferredTimer;
+ NDIS_MINIPORT_TIMER ResetTimer;
+
+ //
+ // Holds number of different types of RING.STATUS.CHANGE
+ // indications.
+ //
+ UINT SignalLoss;
+ UINT HardError;
+ UINT SoftError;
+ UINT TransmitBeacon;
+ UINT LobeWireFault;
+ UINT AutoRemovalError;
+ UINT RemoveReceived;
+ UINT CounterOverflow;
+ UINT SingleStation;
+ UINT RingRecovery;
+
+ //
+ // Current state of the ring.
+ //
+ NDIS_802_5_RING_STATE CurrentRingState;
+
+ //
+ // Last ring status indicated to protocols.
+ //
+ NDIS_STATUS LastNotifyStatus;
+
+ //
+ // This is a pointer to the Configuration Block for this
+ // adapter. The Configuration Block will be modified during
+ // changes to the packet filter.
+ //
+ TOK162_CONFIGURATION_BLOCK ConfigurationBlock;
+
+ //
+ // Pointer to the initialization block
+ //
+ PADAPTER_INITIALIZATION InitializationBlock;
+ NDIS_PHYSICAL_ADDRESS InitializationBlockPhysical;
+
+ //
+ // This points to the next adapter registered for the same Miniport
+ //
+ LIST_ENTRY AdapterList;
+
+} TOK162_ADAPTER,*PTOK162_ADAPTER;
+
+//
+// Given a MiniportContextHandle return the PTOK162_ADAPTER
+// it represents.
+//
+#define PTOK162_ADAPTER_FROM_CONTEXT_HANDLE(Handle) \
+ ((PTOK162_ADAPTER)(Handle))
+
+//
+// This record type is inserted into the MiniportReserved portion
+// of the packet header when the packet is going through the
+// staged allocation of buffer space prior to the actual send.
+//
+typedef struct _TOK162_RESERVED {
+
+ //
+ // Number of Buffers to move
+ //
+ UINT NdisBuffersToMove;
+
+ //
+ // Don't need this part. Reserve it.
+ //
+ UINT Reserved;
+
+
+} TOK162_RESERVED,*PTOK162_RESERVED;
+
+//
+// This macro will return a pointer to the TOK162 reserved portion
+// of a packet given a pointer to a packet.
+//
+#define PTOK162_RESERVED_FROM_PACKET(Packet) \
+ ((PTOK162_RESERVED)((Packet)->MiniportReserved))
+
+#include <tok162pr.h>
diff --git a/private/ntos/ndis/ieepro/82595.h b/private/ntos/ndis/ieepro/82595.h
new file mode 100644
index 000000000..58b100ee6
--- /dev/null
+++ b/private/ntos/ndis/ieepro/82595.h
@@ -0,0 +1,218 @@
+#ifndef _I82595TX_
+#define _I82595TX_
+
+//////////////////////////////////////////////////////////////
+// General Parameters
+//////////////////////////////////////////////////////////////
+// There are 3 switchable banks of 16 IO ports
+// Bank switching is done via register 0
+#define I82595_PORTS_WIDTH 0x10
+#define I82595_NUM_BANKS 0x3
+
+// Number of usec to spin in various places before we give up...
+#define I82595_SPIN_TIMEOUT 10000
+
+//////////////////////////////////////////////////////////////
+// Exec States
+//////////////////////////////////////////////////////////////
+#define I82595_EXEC_STATE_ACTIVE (2 << 4)
+#define I82595_EXEC_STATE_IDLE 0
+#define I82595_EXEC_STATE_ABORTING (3 << 4)
+
+//////////////////////////////////////////////////////////////
+// Receive States
+//////////////////////////////////////////////////////////////
+#define I82595_RCV_STATE_DISABLED 0
+#define I82595_RCV_STATE_READY (1<<6)
+#define I82595_RCV_STATE_ACTIVE (2<<6)
+#define I82595_RCV_STATE_STOPPING (3<<6)
+
+//////////////////////////////////////////////////////////////
+// Command Constants
+//////////////////////////////////////////////////////////////
+// Bank switches...
+#define I82595_CMD_BANK0 0x0
+#define I82595_CMD_BANK1 0x40
+#define I82595_CMD_BANK2 0x80
+
+// Other command constants...
+#define I82595_CMD_MC_SETUP 0x03
+#define I82595_XMT 0x04
+#define I82595_XMT_SHORT 0x0004
+#define I82595_CMD_DIAGNOSE 0x07
+#define I82595_FULL_RESET 0x0e
+#define I82595_SEL_RESET 0x1e
+#define I82595_PWR_DOWN 0x18
+#define I82595_STOP_RCV 0x0b
+#define I82595_RCV_ENABLE 0x08
+#define I82595_XMT_RESUME 0x1c
+
+//////////////////////////////////////////////////////////////
+// Return Values (valid after 0,1,3 goes high)
+//////////////////////////////////////////////////////////////
+#define I82595_DIAGNOSE_PASS 0x07
+#define I82595_DIAGNOSE_FAIL 0x0f
+#define I82595_INIT_DONE 0x0e
+#define I82595_POWERUP_DONE 0x19
+
+
+//////////////////////////////////////////////////////////////
+// Register Defines
+//////////////////////////////////////////////////////////////
+#define I82595_CMD_REG 0x0
+
+// These are in bank 0
+#define I82595_STATUS_REG 0x1
+#define I82595_ID_REG 0x2
+#define I82595_INTMASK_REG 0x3
+#define I82595_32IOSEL_REG 0x3
+#define I82595_RX_BAR_REG 0x4
+#define I82595_RX_STOP_REG 0x6
+#define I82595_TX_BAR_REG 0xa
+#define I82595_HOST_ADDR_REG 0xc // LOW
+#define I82595_32MEM_IO_REG 0xc
+#define I82595_HOST_ADDR_HIGH_REG 0xd // HIGH
+#define I82595_MEM_IO_REG 0xe // LOW
+#define I82595_MEM_IO_HIGH_REG 0xf // HIGH
+
+// Bank 1
+#define I82595_ALT_RDY_REG 0x1
+#define I82595_INTENABLE_REG 0x1
+#define I82595_INT_SELECT_REG 0x2
+#define I82595_IOMAP_REG 0x3
+
+#define I82595_RX_LOWER_LIMIT_REG 0x8
+#define I82595_RX_UPPER_LIMIT_REG 0x9
+#define I82595_TX_LOWER_LIMIT_REG 0xa
+#define I82595_TX_UPPER_LIMIT_REG 0xb
+#define I82595_IOCHRDY_TEST_REG 0xd
+
+// Bank 2
+#define I82595_CONFIG1_REG 0x1
+#define I82595_CONFIG2_REG 0x2
+#define I82595_CONFIG3_REG 0x3
+#define I82595_IA_REG_0 0x4
+#define I82595_IA_REG_1 0x5
+#define I82595_IA_REG_2 0x6
+#define I82595_IA_REG_3 0x7
+#define I82595_IA_REG_4 0x8
+#define I82595_IA_REG_5 0x9
+#define I82595_EEPROM_REG 0xa // eeprom access reg
+#define I82595_STEPPING_REG 0xa
+
+//////////////////////////////////////////////////////////////
+// Register Masks...
+//////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////
+// Command Register (ALL,0)
+//////////////////////////////////////////////////////////////
+#define I82595_CUR_BANK_MASK 0xC0
+
+//////////////////////////////////////////////////////////////
+// Status Register (0,1) bitmasks
+//////////////////////////////////////////////////////////////
+#define I82595_RX_STP_INT_RCVD 0x1 // bit 0
+
+// Did we get a RX Interrupt
+#define I82595_RX_INT_RCVD 0x2 // bit 1
+
+// Mask the TX interupt?
+#define I82595_TX_INT_RCVD 0x4 // bit 2
+
+// This goes high when a command execution is complete.
+#define I82595_EXEC_INT_RCVD 0x8 // bit 3
+
+// status codes
+#define I82595_EXEC_STATE 0x30 // bit 4,5
+#define I82595_RCV_STATE 0xC0 // bit 6,7
+
+#define I82595_STATES_OFFSET 0x4
+
+//////////////////////////////////////////////////////////////
+// Reg 0,3
+//////////////////////////////////////////////////////////////
+#define I82595_RX_STP_INT_MASK 0x1 // bit 0
+
+// Mask the RX interrupt?
+#define I82595_RX_INT_MASK 0x2 // bit 1
+
+// Mask the TX interupt?
+#define I82595_TX_INT_MASK 0x4 // bit 2
+
+// This goes high when a command execution is complete.
+#define I82595_EXEC_INT_MASK 0x8 // bit 3
+
+#define I82595_32IOSEL 0x10 // bit 4
+
+//////////////////////////////////////////////////////////////
+// Reg 0,4
+//////////////////////////////////////////////////////////////
+#define I82595_IOBASE_SELECT 0x3f // bits 0-5
+#define I82595_IOBASE_TO_SELECTION(a) (a>>4)
+
+//////////////////////////////////////////////////////////////
+// Register 1,1
+//////////////////////////////////////////////////////////////
+#define I82595_USE_8_BIT_FLAG 0x2
+#define I82595_ALT_IOCHRDY 0x40
+#define I82595_ENABLE_INTS_FLAG 0x80
+
+//////////////////////////////////////////////////////////////
+// Register 1,2
+//////////////////////////////////////////////////////////////
+#define I82595_INTERRUPT_SELECT_MASK 0x3 // bits 0,1
+#define I82595_ALT_RDY_FLAG 0x40 // bit 6
+
+//////////////////////////////////////////////////////////////
+// Register 1,13
+//////////////////////////////////////////////////////////////
+#define I82595_IOCHRDY_PASS_FLAG 0x1
+#define I82595_IOCHRDY_TEST_FLAG 0x2
+
+
+//////////////////////////////////////////////////////////////
+// Register 2.2 - configuration
+//////////////////////////////////////////////////////////////
+#define I82595_PROMISCUOUS_FLAG 0x01
+#define I82595_NO_BROADCAST_FLAG 0x02
+
+//////////////////////////////////////////////////////////////
+// Register 2.10 -- eeprom access
+//////////////////////////////////////////////////////////////
+#define I82595_EESK_MASK 0x1
+#define I82595_EECS_MASK 0x2
+#define I82595_EEDI_MASK 0x4
+#define I82595_EEDO_MASK 0x8
+#define I82595_TURNOFF_ENABLE 0x10
+
+#define I82595_EEDI_OFFSET 0x2
+#define I82595_EEDO_OFFSET 0x3
+
+#define I82595_EEPROM_READ 0x6 // 110:b
+#define I82595_EEPROM_WRITE 0x5
+#define I82595_EEPROM_ERASE 0x7
+#define I82595_EEPROM_EWEN 19
+#define I82595_EEPROM_EWDS 16
+
+#define I82595_EEPROM_IOADDR_REG 0
+#define I82595_EEPROM_IOMASK ((0x3f) << 10)
+
+#define I82595_STEPPING_OFFSET 0x5 // bits 5-7 are 82595 stepping
+
+//////////////////////////////////////////////////////////////////////
+// TX constants
+//////////////////////////////////////////////////////////////////////
+#define I82595_TX_FRM_HDR_SIZE 0x8
+#define I82595_TX_DN_BYTE_MASK 0x80
+#define I82595_CH_SHORT_MASK 0x8000
+#define I82595_TX_OK_SHORT_MASK 0x2000
+#define I82595_NO_COLLISIONS_MASK 0x0f
+
+//////////////////////////////////////////////////////////////////////
+// RX Constants
+//////////////////////////////////////////////////////////////////////
+#define I82595_RX_EOF 0x08
+#define I82595_RX_OK 0x20
+
+#endif // ifndef _i82595TX_
diff --git a/private/ntos/ndis/ieepro/eeprom.c b/private/ntos/ndis/ieepro/eeprom.c
new file mode 100644
index 000000000..10b8fe9f0
--- /dev/null
+++ b/private/ntos/ndis/ieepro/eeprom.c
@@ -0,0 +1,392 @@
+#include <ndis.h>
+#include "82595.h"
+#include "eprohw.h"
+#include "eprosw.h"
+#include "epro.h"
+#include "eprodbg.h"
+
+VOID EProEERead(
+ PEPRO_ADAPTER adapter,
+ USHORT address,
+ PUSHORT data)
+/*++
+
+ Routine Description:
+
+ This function reads the 16-bit register at address (address % 64)
+ from the EPro's eeprom (there are only 64 words of registers
+ on the eeprom)
+
+ IMPORTANT NOTE - for PnP accesses to the EPro's eeprom (registers
+ 0x10 and higher), you must use the EProEEReverseRead since for some
+ reason the EPro stores PnP data in the reverse bit-order (except for
+ the low byte of word 10, which is in the normal bit order) -- see
+ the 82595 docs and PnP docs for an explanation.
+
+ Arguments:
+
+ data - the where the result is written to
+
+ Return Value:
+
+ none
+
+--*/
+{
+ UCHAR result;
+ UCHAR opcode;
+
+// siwtch to bank2
+ EPRO_SWITCH_BANK_2(adapter);
+
+// Get the value from the register, so we can flip the eecs bit
+ EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result);
+
+// turn the eecs bit on.. (1)
+ result |= I82595_EECS_MASK;
+ EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, result);
+
+// Write the read opcode to the eeprom (2)
+ opcode = I82595_EEPROM_READ;
+ EProEEShiftOutBits(adapter, opcode, 3);
+
+// Write the address to read to the eeprom
+ EProEEShiftOutBits(adapter, address, 6);
+
+// Read the result
+ EProEEShiftInBits(adapter, data, 16);
+
+ EProEECleanup(adapter);
+
+ EPRO_SWITCH_BANK_0(adapter);
+}
+
+
+VOID EProEEWrite(
+ PEPRO_ADAPTER adapter,
+ USHORT address,
+ USHORT data)
+{
+ UCHAR result;
+
+// siwtch to bank2
+ EPRO_SWITCH_BANK_2(adapter);
+
+ EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result);
+ result &= ~(I82595_EEDI_MASK | I82595_EEDO_MASK | I82595_EESK_MASK);
+ result |= I82595_EECS_MASK;
+ EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, result);
+
+ // write the read opcode and register number
+ EProEEShiftOutBits(adapter, I82595_EEPROM_EWEN, 5);
+ EProEEShiftOutBits(adapter, address, 4);
+
+ EProEEStandBy(adapter);
+
+ EProEEShiftOutBits(adapter, I82595_EEPROM_ERASE, 3);
+ EProEEShiftOutBits(adapter, address, 6);
+
+ if (EProEEWaitCmdDone(adapter) == FALSE) {
+ EPRO_DPRINTF_INIT(("Failed EEPROM erase!\n"));
+ return;
+ }
+
+ EProEEStandBy(adapter);
+
+ EProEEShiftOutBits(adapter, I82595_EEPROM_WRITE, 3);
+ EProEEShiftOutBits(adapter, address, 6);
+ EProEEShiftOutBits(adapter, data, 16);
+
+ if (EProEEWaitCmdDone(adapter) == FALSE) {
+ EPRO_DPRINTF_INIT(("Failed EEPROM write!\n"));
+ return;
+ }
+
+ EProEEStandBy(adapter);
+
+ EProEEShiftOutBits(adapter, I82595_EEPROM_EWDS, 5);
+ EProEEShiftOutBits(adapter, address, 4);
+
+ EProEECleanup(adapter);
+
+// siwtch to bank0
+ EPRO_SWITCH_BANK_0(adapter);
+
+}
+
+
+VOID EProEECleanup(PEPRO_ADAPTER adapter)
+{
+ UCHAR result;
+
+ EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result);
+ result &= ~(I82595_EECS_MASK | I82595_EEDI_MASK);
+ EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, result);
+ EProEERaiseClock(adapter, &result);
+ EProEELowerClock(adapter, &result);
+}
+
+
+VOID EProEEUpdateChecksum(PEPRO_ADAPTER adapter)
+{
+ USHORT chkSum = 0, result, i;
+
+ for (i=0;i<0x3f;i++) {
+ EProEERead(adapter, i, &result);
+ chkSum+=result;
+ }
+
+ chkSum = (USHORT)0xBABA - chkSum;
+ EProEEWrite(adapter, 0x3f, chkSum);
+}
+
+
+VOID EProEEStandBy(
+ PEPRO_ADAPTER adapter)
+{
+ UCHAR result;
+
+ EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result);
+ result &= ~(I82595_EECS_MASK | I82595_EESK_MASK);
+ EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, result);
+ NdisStallExecution(100);
+ result |= I82595_EECS_MASK;
+ EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, result);
+}
+
+
+
+BOOLEAN EProEEWaitCmdDone(
+ PEPRO_ADAPTER adapter)
+{
+ USHORT i;
+ UCHAR result;
+
+ EProEEStandBy(adapter);
+
+ for (i=0; i<200;i++) {
+ EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result);
+ if (result & I82595_EEDO_MASK) {
+ return(TRUE);
+ }
+ NdisStallExecution(100);
+ }
+
+ return(FALSE);
+
+}
+
+VOID EProEEReverseRead(
+ PEPRO_ADAPTER adapter,
+ USHORT address,
+ PUSHORT data)
+{
+ UCHAR result, opcode;
+ UINT i;
+
+// siwtch to bank2
+ EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_CMD_BANK2);
+
+// Get the value from the register, so we can flip the eecs bit
+ EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result);
+
+// turn the eecs bit on.. (1)
+ result |= I82595_EECS_MASK;
+ EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, result);
+
+// Write the read opcode to the eeprom (2)
+ opcode = I82595_EEPROM_READ;
+ EProEEShiftOutBits(adapter, opcode, 3);
+
+// Write the address to read to the eeprom
+ EProEEShiftOutBits(adapter, address, 6);
+
+// Read the result
+ EProEEReverseShiftInBits(adapter, data, 16);
+
+// Turn off EEPROM
+ EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result);
+ result &= (~I82595_EECS_MASK);
+ EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, result);
+
+ EPRO_SWITCH_BANK_0(adapter);
+}
+
+VOID EProEEShiftOutBits(
+ PEPRO_ADAPTER adapter,
+ USHORT data,
+ SHORT count)
+/*++
+
+ Routine Description:
+
+ This function shifts count bits OUT TO THE EEPROM through it's serial
+ interface
+
+ Arguments:
+
+ adapter - pointer to our adapter structure
+
+ data - the word to shift out from (MSB first)
+
+ count - the number of bits to shift out...
+
+ Return Value:
+
+ none
+
+--*/
+{
+ UCHAR result;
+ USHORT mask;
+
+ mask = 0x1 << (count - 1);
+ EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result);
+ result &= ~(I82595_EEDO_MASK | I82595_EEDI_MASK);
+
+ do
+ {
+ result &= ~I82595_EEDI_MASK;
+ if (data & mask)
+ {
+ result |= I82595_EEDI_MASK;
+ }
+
+ EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, result);
+ NdisStallExecution(100);
+ EProEERaiseClock(adapter, &result);
+ EProEELowerClock(adapter, &result);
+ mask = mask >> 1;
+ } while(mask);
+
+ result &= ~I82595_EEDI_MASK;
+ EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, result);
+}
+
+VOID EProEEShiftInBits(
+ PEPRO_ADAPTER adapter,
+ PUSHORT data,
+ SHORT count)
+/*++
+
+ Routine Description:
+
+ This routine is analagous to shift-out-bits, except reads bits from
+ the eeprom... Note that for PNP accesses to the EPro
+ (pnp for the EPro lives in registers 0x10 and higher) you must use
+ a different function since PnP data is written in reverse bit order
+ for some reason
+
+ Arguments:
+
+ adapter - pointer to our adapter structure
+
+ data - the word to read into
+
+ count - how many bits to read
+
+ Return Value:
+
+ none
+
+--*/
+{
+ UCHAR result;
+ USHORT i;
+
+ EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result);
+ result &= ~(I82595_EEDO_MASK | I82595_EEDI_MASK);
+ *data = 0;
+
+ for (i=0;i<16;i++)
+ {
+ *data = *data << 1;
+ EProEERaiseClock(adapter, &result); // 4.1
+ EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result); // 4.2
+ result &= ~I82595_EEDI_MASK;
+ if (result & I82595_EEDO_MASK) {
+ *data |= 1;
+ }
+ EProEELowerClock(adapter, &result);
+ }
+}
+
+void EProEEReverseShiftInBits(PEPRO_ADAPTER adapter, PUSHORT data, SHORT count)
+{
+ UCHAR result;
+ SHORT count1;
+
+ *data = 0;
+
+ for (count1=0;count1<=count;count1++) {
+
+ EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result); // 4.2
+
+ result &= I82595_EEDO_MASK; // turn off everything but the EEDO bit
+
+ // according to docs we get MSB out first...
+ // this is a REVERSE read - get LSB first
+ *data |= ((result >> I82595_EEDO_OFFSET) << count1);
+ }
+}
+
+VOID EProEERaiseClock(
+ PEPRO_ADAPTER adapter,
+ PUCHAR result)
+/*++
+
+ Routine Description:
+
+ This routine raises the "clock" bit in the eeprom access register --
+ basically since the eeprom is a serial device you raise then lower the
+ clock between bits...
+
+ Arguments:
+
+ adapter - pointer to the adapter structure
+
+ Return Value:
+
+ none
+
+--*/
+{
+// UCHAR result;
+
+// turn EESK bit high
+ *result = *result | I82595_EESK_MASK;
+ EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, *result);
+ NdisStallExecution(EPRO_SK_STALL_TIME);
+}
+
+VOID EProEELowerClock(
+ PEPRO_ADAPTER adapter,
+ PUCHAR result)
+/*++
+
+ Routine Description:
+
+ Analagous to EProEERaiseClock...
+
+ Arguments:
+
+ adapter - pointer to our adapter structure.
+
+ Return Value:
+
+ none
+
+--*/
+{
+// UCHAR result;
+
+// EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, result);
+
+ // turn EESK bit low...
+ *result = *result & ~I82595_EESK_MASK;
+ EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, *result);
+
+ NdisStallExecution(EPRO_SK_STALL_TIME);
+}
+
+
diff --git a/private/ntos/ndis/ieepro/epro.c b/private/ntos/ndis/ieepro/epro.c
new file mode 100644
index 000000000..ca80d467f
--- /dev/null
+++ b/private/ntos/ndis/ieepro/epro.c
@@ -0,0 +1,512 @@
+#include <ndis.h>
+#include "82595.h"
+#include "eprohw.h"
+#include "eprosw.h"
+#include "epro.h"
+#include "eprodbg.h"
+
+// Global data
+
+NDIS_MINIPORT_CHARACTERISTICS EPro_Miniport_Char;
+
+EPRO_DRIVER EProMiniportDriver={0};
+
+NDIS_STATUS EProSelReset(PEPRO_ADAPTER adapter)
+/*++
+
+ Routine Description:
+
+ This does a SEL-RESET of the i82595 chip. Read the 82595 docs
+ for more info on what this does.
+
+ Arguments:
+
+ adapter - pointer to our adapter structure
+
+ Return Values:
+
+ always returns NDIS_STATUS_SUCCESS
+
+--*/
+{
+ EPRO_ASSERT_BANK_0(adapter);
+
+ EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_SEL_RESET);
+
+// according to 82595 prelim doc: wait 2 us after sel reset before
+// accessing the 82595
+ NdisStallExecution(2);
+
+ EProEnableInterrupts((NDIS_HANDLE)adapter);
+
+ adapter->fHung = FALSE;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+VOID
+EProInitializeAdapterData(
+ IN PEPRO_ADAPTER adapter
+ )
+/*++
+
+ Routine Description:
+
+ This routine initializes our adapter structure - setting default
+ values, zeroing fields, etc. This is called on adapter initialization
+ and adapter reset.
+
+ Arguments:
+
+ A pointer to the adapter structure to clear.
+
+ Return Values:
+
+ none
+
+--*/
+{
+ UINT i;
+
+ adapter->CurrentHardwareStatus = NdisHardwareStatusReady;
+
+ adapter->vendorID[0] = EPRO_VENDOR_ID_L;
+ adapter->vendorID[1] = EPRO_VENDOR_ID_M;
+ adapter->vendorID[2] = EPRO_VENDOR_ID_H;
+
+ adapter->CurrentPacketFilter = 0;
+
+ // hack to get around wrapper bug:
+ // adapter->RXLookAheadSize = 0;
+ //
+ adapter->RXLookAheadSize = 256;
+ adapter->FramesXmitOK = 0;
+ adapter->FramesRcvOK = 0;
+ adapter->FramesXmitErr = 0;
+ adapter->FramesRcvErr = 0;
+ adapter->FramesMissed = 0;
+
+ adapter->FrameAlignmentErrors = 0;
+ adapter->FramesXmitOneCollision = 0;
+ adapter->FramesXmitManyCollisions = 0;
+
+ adapter->CurrentTXBuf = &adapter->TXBuf[0];
+ adapter->TXChainStart = NULL;
+
+ // Packet filter settings...
+ //
+ adapter->fPromiscuousEnable = FALSE;
+ adapter->fBroadcastEnable = FALSE;
+ adapter->fMulticastEnable = FALSE;
+ adapter->fReceiveEnabled = FALSE;
+ adapter->NumMCAddresses = 0;
+
+ // Don't force 8-bit operation
+ //
+ adapter->Use8Bit = FALSE;
+
+ adapter->IntPending = EPRO_INT_NONE_PENDING;
+ adapter->fHung = FALSE;
+ // adapter->fTransmitInProgress = FALSE;
+
+ // Set up the TX buffers...
+ //
+ for (i = 0;i < EPRO_NUM_TX_BUFFERS; i++)
+ {
+ if (0 == i)
+ {
+ adapter->TXBuf[0].LastBuf = &adapter->TXBuf[EPRO_NUM_TX_BUFFERS - 1];
+ }
+ else
+ {
+ adapter->TXBuf[i].LastBuf = &adapter->TXBuf[i-1];
+ }
+
+ if ((EPRO_NUM_TX_BUFFERS - 1) == i)
+ {
+ adapter->TXBuf[i].NextBuf = &adapter->TXBuf[0];
+ }
+ else
+ {
+ adapter->TXBuf[i].NextBuf = &adapter->TXBuf[i + 1];
+ }
+
+ adapter->TXBuf[i].fEmpty = TRUE;
+ adapter->TXBuf[i].TXBaseAddr = 0;
+ adapter->TXBuf[i].TXSendAddr = 0xffff;
+ }
+}
+
+VOID EProEnableInterrupts(IN NDIS_HANDLE miniportAdapterContext)
+/*++
+
+ Routine Description:
+
+ The MiniportEnableInterrupt Handler for the card.
+
+ Arguments:
+
+ miniportAdapterContext - really a PEPRO_ADAPTER to our adapter structure
+
+ Return Value: none
+
+--*/
+{
+ PEPRO_ADAPTER adapter = (PEPRO_ADAPTER)miniportAdapterContext;
+
+// If this isn't true, then NdisMSyncronizeWithInterrupt is broken
+// or we've called a function which switches banks without syncronizing
+// it...
+ EPRO_ASSERT_BANK_0(adapter);
+
+ EPRO_WR_PORT_UCHAR(adapter, I82595_INTMASK_REG,
+ adapter->CurrentInterruptMask);
+
+}
+
+VOID EProDisableInterrupts(IN NDIS_HANDLE miniportAdapterContext)
+/*++
+
+ Routine Description:
+
+ The MiniportDisableInterrupts handler for the driver
+
+ Arguments:
+
+ miniportAdapterContext - really a pointer to our adapter structure
+
+ Return Values: none
+
+--*/
+{
+ PEPRO_ADAPTER adapter = (PEPRO_ADAPTER)miniportAdapterContext;
+
+// If this isn't true, then NdisMSyncronizeWithInterrupt is broken
+// or we've called a function which switches banks without syncronizing
+// it...
+ EPRO_ASSERT_BANK_0(adapter);
+
+// mask all int's
+ EPRO_WR_PORT_UCHAR(adapter, I82595_INTMASK_REG,
+ (adapter->CurrentInterruptMask | 0x0f));
+}
+
+
+VOID EProHalt(IN NDIS_HANDLE miniportAdapterContext)
+/*++
+
+ Routine Description:
+
+ This is the function which halts the 82595 chip and disables the
+ adapter - frees hardware resources, etc.
+
+ Arguments:
+
+ miniportAdapterContext - pointer to our adapter structure
+
+ Returns: nothing
+
+--*/
+{
+ PEPRO_ADAPTER adapter = (EPRO_ADAPTER *)miniportAdapterContext;
+
+// Shut down the card - disable receives.
+ EProReceiveDisable(adapter);
+
+// There won't be any more interrupts
+ NdisMDeregisterInterrupt(&adapter->Interrupt);
+
+// Pause, wait for pending DPC stuff to clear... Random number stolen
+// from the NE2000 driver...
+ NdisStallExecution(250000);
+
+// Unmap our IO ports
+ NdisMDeregisterIoPortRange(adapter->MiniportAdapterHandle,
+ (ULONG)adapter->IoBaseAddr,
+ 0x10,
+ (PVOID)adapter->IoPAddr);
+
+// Free up our adapter structure...
+ NdisFreeMemory(adapter, sizeof(EPRO_ADAPTER), 0);
+}
+
+NDIS_STATUS EProReset(OUT PBOOLEAN fAddressingReset,
+ IN NDIS_HANDLE miniportAdapterContext)
+/*++
+
+ Routine Description:
+
+ This is the MiniportReset handler for the EPro driver
+
+ Arguments:
+
+ fAddressingReset - Do we need to be re-told our MC address list?
+ currently we say yes, although probably we don't
+ have to be told this (the driver saves it)
+
+ Return Values:
+
+ the return from EProSelReset (always NDIS_STATUS_SUCCESS)
+
+--*/
+{
+ PEPRO_ADAPTER adapter = (EPRO_ADAPTER *)miniportAdapterContext;
+
+// Okay, we don't want to get any interrupts anymore.
+ EProDisableInterrupts(adapter);
+ EProReceiveDisable(adapter);
+
+// clear out TX structures...
+ EProInitializeAdapterData(adapter);
+
+// We probably can set this to false -- TODO
+ *fAddressingReset = TRUE;
+
+ return(EProSelReset(adapter));
+}
+
+BOOLEAN EProCheckForHang(IN NDIS_HANDLE miniportAdapterContext)
+/*++
+
+ Routine Description:
+
+ This is the MiniportCheckForHang handler for the driver.
+ It does absolutely nothing right now.
+
+ Arguments:
+
+ miniportAdapterContext - right now a pointer to our adapter structure
+
+ Return Value:
+
+
+--*/
+{
+ PEPRO_ADAPTER adapter = (PEPRO_ADAPTER)miniportAdapterContext;
+
+ if (adapter->fHung)
+ {
+ return(TRUE);
+ }
+
+ return(FALSE);
+}
+
+VOID EProHandleInterrupt(
+ IN NDIS_HANDLE miniportAdapterContext)
+/*++
+
+ Routine Description:
+
+ This is the function that gets called at DPC level in response
+ to a hardware interrupt. It is queued by the wrapper's ISR routines.
+ Interrupts have been disabled when this routine is called.
+
+ Arguments:
+
+ miniportAdapterContext - really a pointer to our adapter structure
+
+ Return Value:
+
+ none
+
+--*/
+{
+ PEPRO_ADAPTER adapter = (EPRO_ADAPTER *)miniportAdapterContext;
+ UCHAR whichInt;
+ BOOLEAN fFoundInts, fFoundRX = FALSE;
+
+ // verify bank 0
+ EPRO_ASSERT_BANK_0(adapter);
+
+ do
+ {
+ fFoundInts = FALSE;
+
+ // Read in the int mask
+ //
+ EPRO_RD_PORT_UCHAR(adapter, I82595_STATUS_REG, &whichInt);
+
+ // quick out if there are no ints pending...
+ if (!(whichInt & 0x0f))
+ {
+ break;
+ }
+
+ // acknowlege interrupts - writing a 1 over the int flag clears it
+ EPRO_WR_PORT_UCHAR(adapter, I82595_STATUS_REG, whichInt);
+
+ if (whichInt & I82595_TX_INT_RCVD)
+ {
+ fFoundInts = TRUE;
+ if (adapter->TXChainStart != NULL)
+ {
+ EProCheckTransmitCompletion(adapter, adapter->TXChainStart);
+ }
+ }
+
+// if (whichInt & I82595_TX_INT_RCVD)
+// {
+// fFoundInts = TRUE;
+// if (adapter->TXChainStart != NULL)
+// {
+// while (EProCheckTransmitCompletion(adapter, adapter->TXChainStart))
+// ;
+// }
+// }
+
+ if (whichInt & I82595_RX_INT_RCVD)
+ {
+ fFoundInts = TRUE;
+ if (EProHandleReceive(adapter) > 0)
+ {
+ fFoundRX = TRUE;
+ }
+ }
+
+ if (whichInt & I82595_EXEC_INT_RCVD)
+ {
+ fFoundInts = TRUE;
+
+ EProSetInterruptMask(adapter, EPRO_DEFAULT_INTERRUPTS);
+
+ switch(adapter->IntPending)
+ {
+ case EPRO_INT_MC_SET_PENDING:
+
+ ((PEPRO_TRANSMIT_BUFFER)adapter->IntContext)->fEmpty = TRUE;
+ EPRO_DPRINTF_INTERRUPT(("Set COMPLETED!"));
+
+ NdisMSetInformationComplete(
+ adapter->MiniportAdapterHandle,
+ NDIS_STATUS_SUCCESS);
+
+ break;
+// default:
+// EPRO_ASSERT(FALSE); // we shouldn't hit this...
+ }
+
+ // clear the pending interrupt...
+ //
+ adapter->IntPending = 0;
+ adapter->IntContext = NULL;
+ }
+ } while ((fFoundInts == TRUE) && !adapter->fHung);
+
+ if (fFoundRX)
+ {
+ NdisMEthIndicateReceiveComplete(adapter->MiniportAdapterHandle);
+ }
+}
+
+void
+EProISR(
+ OUT PBOOLEAN interruptRecognized,
+ OUT PBOOLEAN queueMiniportHandleInterrupt,
+ IN NDIS_HANDLE miniportAdapterContext)
+{
+ EPRO_DPRINTF_INTERRUPT(("ISR"));
+
+ *interruptRecognized = TRUE;
+ *queueMiniportHandleInterrupt = FALSE;
+}
+
+
+BOOLEAN EProSyncSetInterruptMask(PVOID context)
+{
+ PEPRO_ADAPTER adapter = ((PEPRO_SETINTERRUPT_CONTEXT)context)->Adapter;
+ UCHAR newMask = ((PEPRO_SETINTERRUPT_CONTEXT)context)->NewMask;
+
+// unmask everyone...
+ adapter->CurrentInterruptMask &= 0xf0;
+// now mask the ones we don't want
+ adapter->CurrentInterruptMask |= newMask;
+
+ EPRO_ASSERT_BANK_0(adapter);
+
+ EPRO_WR_PORT_UCHAR(adapter, I82595_INTMASK_REG,
+ adapter->CurrentInterruptMask);
+
+ return(TRUE);
+}
+
+// Poll the exec-states reg (0,1), waiting for any execution to finish...
+BOOLEAN EProWaitForExeDma(PEPRO_ADAPTER adapter)
+{
+ UINT i;
+ UCHAR result;
+
+// status reg is in bank 0
+ EPRO_ASSERT_BANK_0(adapter);
+
+ for (i=0;i<I82595_SPIN_TIMEOUT;i++) {
+ // make sure the dma is idle
+ EPRO_RD_PORT_UCHAR(adapter, I82595_STATUS_REG, &result);
+ if (!(result&I82595_EXEC_STATE)) {
+ if (result & I82595_EXEC_INT_RCVD) {
+ // clear the exec int if it's high...
+ EPRO_WR_PORT_UCHAR(adapter, I82595_STATUS_REG,
+ I82595_EXEC_INT_RCVD);
+ }
+ return(TRUE);
+ }
+ NdisStallExecution(1);
+ }
+
+ return(FALSE);
+}
+
+BOOLEAN EProReceiveEnable(PEPRO_ADAPTER adapter)
+{
+ UINT i = 0;
+ UCHAR result;
+
+ adapter->RXCurrentAddress = 0 | (((USHORT)EPRO_RX_LOWER_LIMIT) << 8);
+
+ // EPRO_ASSERT(!adapter->fReceiveEnabled);
+
+ // don't enable if we're already enabled.
+ if (adapter->fReceiveEnabled)
+ {
+ return(TRUE);
+ }
+
+ // bank0
+ // EPRO_SWITCH_BANK_0(adapter);
+ //
+ EPRO_ASSERT_BANK_0(adapter);
+ EPRO_WR_PORT_USHORT(adapter, I82595_RX_STOP_REG, 0 | (((USHORT)EPRO_RX_UPPER_LIMIT) << 8));
+ EPRO_WR_PORT_USHORT(adapter, I82595_RX_BAR_REG, 0 | (((USHORT)EPRO_RX_LOWER_LIMIT) << 8));
+
+ //
+ // validate registers...
+ //
+ EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_RCV_ENABLE);
+
+ adapter->fReceiveEnabled = TRUE;
+
+ return(TRUE);
+}
+
+BOOLEAN EProReceiveDisable(PEPRO_ADAPTER adapter)
+{
+ UINT i = 0;
+ UCHAR result;
+
+// bank0
+// EPRO_SWITCH_BANK_0(adapter);
+ EPRO_ASSERT_BANK_0(adapter);
+ EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_STOP_RCV);
+
+ adapter->fReceiveEnabled = FALSE;
+
+ return(TRUE);
+}
+
+//VOID EProTimerFunc(IN PVOID foo1, IN PVOID context, IN PVOID foo2, IN PVOID foo3)
+//{
+// EProHandleInterrupt((NDIS_HANDLE)context);
+//
+// queue another timer...
+// NdisMSetTimer(&(((PEPRO_ADAPTER)context)->MiniportTimer), 10);
+//}
diff --git a/private/ntos/ndis/ieepro/epro.h b/private/ntos/ndis/ieepro/epro.h
new file mode 100644
index 000000000..f5f6ed7aa
--- /dev/null
+++ b/private/ntos/ndis/ieepro/epro.h
@@ -0,0 +1,221 @@
+#ifndef _IEPRO_
+#define _IEPRO_
+
+#define EPRO_DRIVER_VER_MAJOR 1
+#define EPRO_DRIVER_VER_MINOR 0
+
+#include "eprosw.h"
+
+///////////////////////////////////////////////////////////////////
+//epro.c:
+///////////////////////////////////////////////////////////////////
+
+NDIS_STATUS EProSelReset(PEPRO_ADAPTER adapter);
+
+VOID EProInitializeAdapterData(PEPRO_ADAPTER adapter);
+
+VOID EProEnableInterrupts(IN NDIS_HANDLE miniportAdapterContext);
+
+VOID EProDisableInterrupts(IN NDIS_HANDLE miniportAdapterContext);
+
+BOOLEAN EProVerifyRoundRobin(UCHAR *buf);
+
+BOOLEAN EProPowerupBoard(PEPRO_ADAPTER adapter);
+
+extern VOID EProHalt(IN NDIS_HANDLE miniportAdapterContext);
+
+NDIS_STATUS EProReset(OUT PBOOLEAN fAddressingReset,
+ IN NDIS_HANDLE miniportAdapterContext);
+
+BOOLEAN EProCheckForHang(IN NDIS_HANDLE miniportAdapterContext);
+
+VOID EProHandleInterrupt(IN NDIS_HANDLE miniportAdapterContext);
+
+VOID EProISR(OUT PBOOLEAN interruptRecognized,
+ OUT PBOOLEAN queueMiniportHandleInterrupt,
+ IN NDIS_HANDLE miniportAdapterContext);
+
+BOOLEAN EProCardReadEthernetAddress(PEPRO_ADAPTER adapter);
+
+BOOLEAN EProAltIOCHRDYTest(PEPRO_ADAPTER adapter);
+
+BOOLEAN EProSyncSetInterruptMask(PVOID context);
+
+// This is implemented via a macro
+//VOID EProSetInterruptMask(PEPRO_ADAPTER adapter, UCHAR newMask);
+
+#define EProSetInterruptMask(_adapter, _newMask) { \
+ EPRO_SETINTERRUPT_CONTEXT _context; \
+ _context.Adapter = _adapter; \
+ _context.NewMask = _newMask; \
+ NdisMSynchronizeWithInterrupt(&_adapter->Interrupt, \
+ &EProSyncSetInterruptMask, \
+ &_context); \
+}
+
+BOOLEAN EProWaitForExeDma(PEPRO_ADAPTER adapter);
+
+BOOLEAN EProReceiveEnable(PEPRO_ADAPTER adapter);
+
+BOOLEAN EProReceiveDisable(PEPRO_ADAPTER adapter);
+
+VOID EProMyLog(char *s);
+
+//VOID EProTimerFunc(IN PVOID foo1, IN PVOID context, IN PVOID foo2, IN PVOID foo3);
+
+#if DBG
+
+VOID EProLogStr(char *s);
+VOID EProLogLong(ULONG l);
+VOID EProLogBuffer(UCHAR *s, ULONG len);
+
+#else
+
+#define EProLogStr(a)
+#define EProLogLong(a)
+#define EProLogBuffer(a, b)
+
+#endif
+
+///////////////////////////////////////////////////////////////////
+// init.c
+///////////////////////////////////////////////////////////////////
+
+NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject_,
+ IN PUNICODE_STRING RegistryPath_);
+
+NDIS_STATUS EProInitialize(OUT PNDIS_STATUS openErrorStatus,
+ OUT PUINT selectedMedumIndex,
+ IN PNDIS_MEDIUM medumArray,
+ IN UINT mediumArraySize,
+ IN NDIS_HANDLE miniportAdapterHandle,
+ IN NDIS_HANDLE configurationHandle);
+
+NDIS_STATUS EProReadConfiguration(IN PEPRO_ADAPTER adapterxo,
+ IN NDIS_HANDLE configurationHandle);
+
+NDIS_STATUS EProRegisterAdapterHW(IN PEPRO_ADAPTER adapter);
+
+NDIS_STATUS EProInitialReset(IN PEPRO_ADAPTER adapter);
+
+NDIS_STATUS EProHWInitialize(IN PEPRO_ADAPTER adapter);
+
+VOID EProUpdateEEProm(IN PEPRO_ADAPTER adapter);
+
+NDIS_STATUS EProHWConfigure(IN PEPRO_ADAPTER adapter);
+
+//////////////////////////////////////////////////////////////////////
+// request.c:
+//////////////////////////////////////////////////////////////////////
+
+NDIS_STATUS EProSetInformation(IN NDIS_HANDLE miniportAdapterContext,
+ IN NDIS_OID oid,
+ IN PVOID informationBuffer,
+ IN ULONG informationLength,
+ OUT PULONG bytesRead,
+ OUT PULONG bytesNeeded);
+
+NDIS_STATUS EProQueryInformation(IN NDIS_HANDLE miniportAdapterContext,
+ IN NDIS_OID oid,
+ IN PVOID informationBuffer,
+ IN ULONG informationBuffrLength,
+ OUT PULONG bytesWritten,
+ OUT PULONG bytesNeeded);
+
+BOOLEAN EProSetEthernetAddress(PEPRO_ADAPTER adapter);
+
+NDIS_STATUS EProSetPacketFilter(PEPRO_ADAPTER adapter, ULONG newFilter);
+
+BOOLEAN EProSyncBroadcastPromiscuousChange(PVOID context);
+
+// Implemented via a macro
+//VOID EProBroadcastPromiscuousChange(PEPRO_ADAPTER adapter, UCHAR reg2flags);
+#define EProBroadcastPromiscuousChange(_adapter, _reg2Flags) { \
+ EPRO_BRDPROM_CONTEXT _context; \
+ _context.Adapter =_adapter; \
+ _context.Reg2Flags = _reg2Flags; \
+ NdisMSynchronizeWithInterrupt(&adapter->Interrupt, \
+ &EProSyncBroadcastPromiscuousChange, \
+ (PVOID)&_context); \
+}
+
+
+//////////////////////////////////////////////////////////////////////
+// eeprom.c:
+//////////////////////////////////////////////////////////////////////
+
+// EEProm Routines
+VOID EProEECleanup(PEPRO_ADAPTER adapter);
+VOID EProEEUpdateChecksum(PEPRO_ADAPTER adapter);
+VOID EProEEStandBy(PEPRO_ADAPTER adapter);
+VOID EProEERead(PEPRO_ADAPTER adapter, USHORT address, PUSHORT data);
+VOID EProEEWrite(PEPRO_ADAPTER adapter, USHORT address, USHORT data);
+VOID EProEEReverseRead(PEPRO_ADAPTER adapter, USHORT address, PUSHORT data);
+VOID EProEEShiftOutBits(PEPRO_ADAPTER adapter, USHORT data, SHORT count);
+VOID EProEEShiftInBits(PEPRO_ADAPTER adapter, PUSHORT data, SHORT count);
+VOID EProEEReverseShiftInBits(PEPRO_ADAPTER adapter, PUSHORT data, SHORT count);
+VOID EProEERaiseClock(PEPRO_ADAPTER adapter, PUCHAR result);
+VOID EProEELowerClock(PEPRO_ADAPTER adapter, PUCHAR result);
+BOOLEAN EProEEWaitCmdDone(PEPRO_ADAPTER adapter);
+
+
+//////////////////////////////////////////////////////////////////////
+// sndrcv.c
+//////////////////////////////////////////////////////////////////////
+
+BOOLEAN EProSyncReadBufferFromNicUlong(PVOID context);
+BOOLEAN EProSyncWriteBufferToNicUlong(PVOID context);
+
+NDIS_STATUS EProSend(IN NDIS_HANDLE miniportAdapterContext,
+ IN PNDIS_PACKET packet,
+ IN UINT flags);
+
+VOID EProCopyPacketToCard(PEPRO_ADAPTER adapter, PNDIS_PACKET packet);
+
+
+BOOLEAN EProCheckTransmitCompletion(PEPRO_ADAPTER adapter,
+ PEPRO_TRANSMIT_BUFFER txBuf);
+
+UINT EProHandleReceive(PEPRO_ADAPTER adapter);
+
+NDIS_STATUS EProTransferData(OUT PNDIS_PACKET packet,
+ OUT PUINT bytesTransferred,
+ IN NDIS_HANDLE miniportAdapterContext,
+ IN NDIS_HANDLE miniportReceivedContext,
+ IN UINT byteOffset,
+ IN UINT bytesToTransfer);
+
+BOOLEAN EProChangeMulticastList(PEPRO_ADAPTER adapter,
+ UINT addressCount,
+ UCHAR addresses[][EPRO_LENGTH_OF_ADDRESS]);
+
+#define EPRO_SET_CARD_MC 0
+#define EPRO_CLEAR_CARD_MC 1
+BOOLEAN EProSetCardMulticastList(PEPRO_ADAPTER adapter, int operation);
+
+BOOLEAN EProSyncCopyBufferToNicUlong(PVOID context);
+
+#define EPRO_READ_BUFFER_FROM_NIC_ULONG(adapter, buffer, len) \
+ { \
+ EPRO_COPYBUF_CONTEXT _context; \
+ _context.Adapter = adapter; \
+ _context.Buffer = buffer; \
+ _context.Len = len; \
+ NdisMSynchronizeWithInterrupt(&adapter->Interrupt, \
+ &EProSyncReadBufferFromNicUlong, \
+ (PVOID)&_context); \
+ }
+
+#define EPRO_COPY_BUFFER_TO_NIC_ULONG(adapter, buffer, len) \
+ { \
+ EPRO_COPYBUF_CONTEXT _context; \
+ _context.Adapter = adapter; \
+ _context.Buffer = buffer; \
+ _context.Len = len; \
+ NdisMSynchronizeWithInterrupt(&adapter->Interrupt, \
+ &EProSyncCopyBufferToNicUlong, \
+ (PVOID)&_context); \
+ }
+
+
+#endif _IEPRO_
diff --git a/private/ntos/ndis/ieepro/epro.rc b/private/ntos/ndis/ieepro/epro.rc
new file mode 100644
index 000000000..254086031
--- /dev/null
+++ b/private/ntos/ndis/ieepro/epro.rc
@@ -0,0 +1,39 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "Intel EtherExpress Pro network driver"
+#define VER_INTERNALNAME_STR "IEEPRO.SYS"
+#define VER_ORIGINALFILENAME_STR "IEEPRO.SYS"
+
+#include "common.ver"
+
diff --git a/private/ntos/ndis/ieepro/eprodbg.c b/private/ntos/ndis/ieepro/eprodbg.c
new file mode 100644
index 000000000..391349a73
--- /dev/null
+++ b/private/ntos/ndis/ieepro/eprodbg.c
@@ -0,0 +1,57 @@
+#include <ndis.h>
+#include "82595.h"
+#include "eprohw.h"
+#include "eprosw.h"
+#include "epro.h"
+#include "eprodbg.h"
+
+#if DBG
+
+// Flags to turn spew on or off from debugger...
+BOOLEAN EPRO_TX_DBG_ON = FALSE;
+BOOLEAN EPRO_RX_DBG_ON = FALSE;
+// default INIT spew to ON in debug version for now...
+BOOLEAN EPRO_INIT_DBG_ON = FALSE;
+BOOLEAN EPRO_REQ_DBG_ON = FALSE;
+BOOLEAN EPRO_INTERRUPT_DBG_ON = FALSE;
+
+#define EPRO_LOG_SIZE 10000
+
+UCHAR EPro_Log[EPRO_LOG_SIZE];
+UINT EPro_Log_Offset = 0;
+
+VOID EProLogStr(char *s)
+{
+ UINT len = strlen(s);
+
+ if ((EPro_Log_Offset + len) >= EPRO_LOG_SIZE) {
+ EPro_Log_Offset = 0;
+ }
+
+ NdisMoveMemory((&EPro_Log[EPro_Log_Offset]), s, len);
+ EPro_Log_Offset+=len;
+}
+
+VOID EProLogLong(ULONG l)
+{
+ if (EPro_Log_Offset + sizeof(ULONG) >= EPRO_LOG_SIZE) {
+ EPro_Log_Offset = 0;
+ }
+
+ NdisMoveMemory((&EPro_Log[EPro_Log_Offset]), &l, sizeof(ULONG));
+ EPro_Log_Offset+=sizeof(ULONG);
+}
+
+VOID EProLogBuffer(UCHAR *s, ULONG len)
+{
+ if ((EPro_Log_Offset + len) >= EPRO_LOG_SIZE) {
+ EPro_Log_Offset = 0;
+ }
+
+ NdisMoveMemory(&EPro_Log[EPro_Log_Offset], s, len);
+ EPro_Log_Offset+=len;
+}
+
+#endif // IF DBG
+
+
diff --git a/private/ntos/ndis/ieepro/eprodbg.h b/private/ntos/ndis/ieepro/eprodbg.h
new file mode 100644
index 000000000..42d7fb721
--- /dev/null
+++ b/private/ntos/ndis/ieepro/eprodbg.h
@@ -0,0 +1,129 @@
+#ifndef _IEPRODBG_
+#define _IEPRODBG_
+
+////////////////////////////////////////////////////////////
+// Debug
+////////////////////////////////////////////////////////////
+#if DBG
+
+extern BOOLEAN EPRO_TX_DBG_ON;
+extern BOOLEAN EPRO_RX_DBG_ON;
+extern BOOLEAN EPRO_INIT_DBG_ON;
+extern BOOLEAN EPRO_REQ_DBG_ON;
+extern BOOLEAN EPRO_INTERRUPT_DBG_ON;
+
+// comment these out if you want don't want DbgPrint's compiling in at all
+// or set the global variables in epro.c if you just want
+// to turn them on or off...
+#define EPRO_DEBUG_TX
+#define EPRO_DEBUG_RX
+#define EPRO_DEBUG_INIT
+#define EPRO_DEBUG_REQ
+#define EPRO_DEBUG_INTERRUPT
+
+// If you want a dump of the EPro's EEPROM for some reason
+// uncomment the following line. The EEPROM will be dumped
+// to the kernel debugger during driver initialization...
+//#define EPRO_DUMP_EEPROM
+
+#define EPRO_ASSERT(expression) { \
+ if ((!(expression))) { \
+ DbgPrint("Assertion failed: %s, at line %d in file %s\n", \
+ #expression, __LINE__, __FILE__); \
+ DbgBreakPoint(); \
+ } \
+}
+
+// TRANSMIT debugging
+#ifdef EPRO_DEBUG_TX
+# define EPRO_DPRINTF_TX(a) { \
+ if (EPRO_TX_DBG_ON) \
+ DbgPrint a; \
+ }
+#else
+# define EPRO_DPRINTF_TX(a)
+#endif
+
+// RECEIVE debugging
+#ifdef EPRO_DEBUG_RX
+# define EPRO_DPRINTF_RX(a) { \
+ if (EPRO_RX_DBG_ON) \
+ DbgPrint a; \
+ }
+#else
+# define EPRO_DPRINTF_RX(a)
+#endif
+
+// INIT debugging
+#ifdef EPRO_DEBUG_INIT
+# define EPRO_DPRINTF_INIT(a) { \
+ if (EPRO_INIT_DBG_ON) \
+ DbgPrint a; \
+ }
+#else
+# define EPRO_DPRINTF_INIT(a)
+#endif
+
+// REQUEST debugging
+#ifdef EPRO_DEBUG_REQ
+# define EPRO_DPRINTF_REQ(a) { \
+ if (EPRO_REQ_DBG_ON) \
+ DbgPrint a; \
+ }
+
+#else
+# define EPRO_DPRINTF_REQ(a)
+#endif
+
+// INTERRUPT debugging
+#ifdef EPRO_DEBUG_INTERRUPT
+# define EPRO_DPRINTF_INTERRUPT(a) { \
+ if (EPRO_INTERRUPT_DBG_ON) \
+ DbgPrint a; \
+ }
+#else
+# define EPRO_DPRINTF_INTERRUPT(a)
+#endif
+
+
+#define EPRO_ASSERT_BANK_0(_adapter) { \
+ UCHAR _result; \
+ EPRO_RD_PORT_UCHAR(adapter, I82595_CMD_REG, &_result); \
+ EPRO_ASSERT((_result & I82595_CUR_BANK_MASK) == I82595_CMD_BANK0); \
+}
+
+#define EPRO_ASSERT_BANK_1(_adapter) { \
+ UCHAR _result; \
+ EPRO_RD_PORT_UCHAR(adapter, I82595_CMD_REG, &_result); \
+ EPRO_ASSERT((_result & I82595_CUR_BANK_MASK) == I82595_CMD_BANK1); \
+}
+
+#define EPRO_ASSERT_BANK_2(_adapter) { \
+ UCHAR _result; \
+ EPRO_RD_PORT_UCHAR(adapter, I82595_CMD_REG, &_result); \
+ EPRO_ASSERT((_result & I82595_CUR_BANK_MASK) == I82595_CMD_BANK2); \
+}
+
+#else // ifdef DEBUG
+
+#define EPRO_ASSERT(expression)
+
+#define EPRO_ASSERT_BANK_0(_adapter)
+#define EPRO_ASSERT_BANK_1(_adapter)
+#define EPRO_ASSERT_BANK_2(_adapter)
+
+#define EPRO_DPRINTF_TX(a)
+#define EPRO_DPRINTF_RX(a)
+#define EPRO_DPRINTF_INIT(a)
+#define EPRO_DPRINTF_REQ(a)
+#define EPRO_DPRINTF_INTERRUPT(a)
+#define EPRO_LOG_INIT(a)
+#define EPRO_LOG_TX(a)
+#define EPRO_LOG_RX(a)
+#define EPRO_LOG_REQ(a)
+#define EPRO_LOG_INTERRUPT(a)
+
+#endif // ifdef DEBUG
+
+
+#endif
diff --git a/private/ntos/ndis/ieepro/eprohw.h b/private/ntos/ndis/ieepro/eprohw.h
new file mode 100644
index 000000000..fb1678e66
--- /dev/null
+++ b/private/ntos/ndis/ieepro/eprohw.h
@@ -0,0 +1,202 @@
+#ifndef _IEPROHW_
+#define _IEPROHW_
+
+#define EPRO_LENGTH_OF_ADDRESS 6
+
+////////////////////////////////////////////////////////////
+// Bank Switches
+////////////////////////////////////////////////////////////
+#define EPRO_GOTO_B0 EPRO_WRITE_UCHAR(epro_cmd_reg, EPRO_CMD_BANK0)
+#define EPRO_GOTO_B1 EPRO_WRITE_UCHAR(epro_cmd_reg, EPRO_CMD_BANK1)
+#define EPRO_GOTO_B2 EPRO_WRITE_UCHAR(epro_cmd_reg, EPRO_CMD_BANK2)
+
+////////////////////////////////////////////////////////////
+// Port I/O
+////////////////////////////////////////////////////////////
+#define EPRO_READ_UCHAR(_Port, _pValue) \
+ NdisRawReadPortUchar( \
+ (ULONG)(_Port), \
+ (PUCHAR)(_pValue) \
+ )
+
+#define EPRO_READ_USHORT(_Port, _pValue) \
+ NdisRawReadPortUshort( \
+ (ULONG)(_Port), \
+ (PUSHORT)(_pValue) \
+ )
+
+#define EPRO_WRITE_UCHAR(_Port, _Value) \
+ NdisRawWritePortUchar( \
+ (ULONG)(_Port), \
+ (UCHAR) (_Value) \
+ )
+
+////////////////////////////////////////////////////////////
+// Command Macros
+// Care must be taken to ensure you are in the right bank
+////////////////////////////////////////////////////////////
+
+// Memory I/O
+#define EPRO_MEM_READADDR(_pValue) \
+ EPRO_READ_USHORT(EPro_IOBaseAddress + EPRO_HOST_ADDR_REG, _pValue)
+
+#define EPRO_MEM_WRITEADDR(_Value) \
+ EPRO_WRITE_USHORT(EPro_IOBaseAddress + EPRO_HOST_ADDR_REG, Value)
+
+#define EPRO_MEM_READSHORT(_pValue) \
+ EPRO_READ_USHORT(EPro_IOBaseAddress + EPRO_MEM_IO_REG)
+
+#define EPRO_MEM_WRITESHORT(_Value) \
+ EPRO_WRITE_USHORT(EPro_IOBaseAddress + EPRO_MEM_IO_REG)
+
+//BOOLEAN EProMemcpyW(void *pMainMemSrc_, void *OnBoardDest_, UINT count);
+//BOOLEAN EProMemcpyR(void *OnBoardSrc_, void *pMainMemDest_, UINT count);
+
+////////////////////////////////////////////////////////////
+// TX Defines
+////////////////////////////////////////////////////////////
+#define EPRO_NUM_TX_BUFFERS 30
+#define EPRO_TX_FIRST_BUF_START 0
+
+// 1514 bytes ethernet frame
+// 16 bytes epro header
+// 2 bytes pad for word alignment
+//#define EPRO_BUFFER_LEN 1532
+
+#define EPRO_TRANSMIT_HEADER_SHORT1 (USHORT)I82595_XMT
+#define EPRO_TRANSMIT_HEADER_SHORT2 (USHORT)0x0
+
+////////////////////////////////////////////////////////////
+//
+////////////////////////////////////////////////////////////
+
+#define EPRO_REGISTRY_INTERRUPT_STRING NDIS_STRING_CONST("INTERRUPT")
+#define EPRO_REGISTRY_IOADDRESS_STRING NDIS_STRING_CONST("IOADDRESS")
+#define EPRO_REGISTRY_OLDIOADDRESS_STRING NDIS_STRING_CONST("OLDIOADDRESS")
+#define EPRO_REGISTRY_BUSTYPE_STRING NDIS_STRING_CONST("BusType")
+#define EPRO_REGISTRY_TRANSCEIVER_STRING NDIS_STRING_CONST("Transceiver")
+#define EPRO_REGISTRY_IOCHRDY_STRING NDIS_STRING_CONST("IoChannelReady")
+
+#define EPRO_IOCHRDY_EARLY 0x01
+#define EPRO_IOCHRDY_LATE 0x02
+#define EPRO_IOCHRDY_NEVER 0x03
+#define EPRO_IOCHRDY_AUTO 0x04
+
+////////////////////////////////////////////////////////////
+// Capabilities/Statistics about the EPRO card
+////////////////////////////////////////////////////////////
+
+#define EPRO_VENDOR_ID_L 0x00
+#define EPRO_VENDOR_ID_M 0xaa
+#define EPRO_VENDOR_ID_H 0x00
+
+#define EPRO_GEN_MEDIA_SUPPORTED NdisMedium802_3
+#define EPRO_GEN_MEDIA_IN_USE NdisMedium802_3
+#define EPRO_GEN_MAXIMUM_LOKAHEAD 256
+#define EPRO_GEN_MAXIMUM_FRAME_SIZE 1500
+#define EPRO_GEN_MAXIMUM_TOTAL_SIZE 1514
+#define EPRO_MAX_MULTICAST 64
+#define EPRO_GEN_MAC_OPTIONS (NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | \
+ NDIS_MAC_OPTION_RECEIVE_SERIALIZED | \
+ NDIS_MAC_OPTION_NO_LOOPBACK)
+#define EPRO_GEN_LINK_SPEED 100000
+#define EPRO_GEN_RECEIVE_BUFFER_SPACE (0x8000 - 0x3000)
+#define EPRO_TX_BUF_SIZE 1514
+#define EPRO_RX_BUF_SIZE 0
+#define EPRO_GEN_TRANSMIT_BUFFER_SPACE EPRO_TX_BUF_SIZE * EPRO_NUM_TX_BUFFERS
+#define EPRO_VENDOR_DESC "Intel EtherExpress PRO"
+
+
+////////////////////////////////////////////////////////////
+// EPro EEPROM defines
+////////////////////////////////////////////////////////////
+#define EPRO_SK_STALL_TIME 1000 // use 1000 microsecs
+
+#define EPRO_ETHERNET_ADDR_H 0x2
+#define EPRO_ETHERNET_ADDR_M 0x3
+#define EPRO_ETHERNET_ADDR_L 0x4
+
+#define EPRO_EEPROM_CONFIG_OFFSET 0
+#define EPRO_EEPROM_CONFIG1_OFFSET 1
+
+// word 0 on the eeprom
+#define EPRO_EEPROM_IOADDR_BITPOS 0x0a // bits 10-15
+#define EPRO_EEPROM_IOADDR_MASK 0xfc00
+#define EPRO_EEPROM_AUTO_IO_ENABLE_MASK 0x0040
+#define EPRO_EEPROM_HOST_BUS_WD_MASK 0x0004
+#define EPRO_EEPROM_PNP_ENABLE_MASK 0x0001
+
+// word 1 on the eeprom. RM: Due to chenges for eeprom stepping 4, we
+// have additional masks. For simplicity's sake, stepping 4 masks
+// are prefixed with the '4' (even if there is no other stepping
+// equivalent INT for that IRQ).
+#define EPRO_EEPROM_IRQ_MASK 0x000f
+#define EPRO_EEPROM_IRQ_2_MASK 0x0
+#define EPRO_EEPROM_IRQ_3_MASK 0x1
+#define EPRO_EEPROM4_IRQ_3_MASK 0x0
+#define EPRO_EEPROM4_IRQ_4_MASK 0x1
+#define EPRO_EEPROM_IRQ_5_MASK 0x2
+#define EPRO_EEPROM4_IRQ_7_MASK 0x3
+#define EPRO_EEPROM4_IRQ_9_MASK 0x4
+#define EPRO_EEPROM_IRQ_10_MASK 0x3
+#define EPRO_EEPROM4_IRQ_10_MASK 0x5
+#define EPRO_EEPROM_IRQ_11_MASK 0x4
+#define EPRO_EEPROM4_IRQ_11_MASK 0x6
+#define EPRO_EEPROM4_IRQ_12_MASK 0x7
+
+
+////////////////////////////////////////////////////////////
+// TX/RX buffers
+////////////////////////////////////////////////////////////
+#define EPRO_TX_LOWER_LIMIT 0x00
+#define EPRO_TX_UPPER_LIMIT 0x27
+
+#define EPRO_TX_LOWER_LIMIT_SHORT 0x0000
+#define EPRO_TX_UPPER_LIMIT_SHORT 0x2800
+
+#define EPRO_RX_LOWER_LIMIT 0x28
+#define EPRO_RX_UPPER_LIMIT 0x7f
+
+#define EPRO_RX_LOWER_LIMIT_SHORT 0x2800
+#define EPRO_RX_UPPER_LIMIT_SHORT 0x8000
+
+////////////////////////////////////////////////////////////
+// Configuration Defaults
+////////////////////////////////////////////////////////////
+//#define EPRO_CONFIG_1 0xa0 // a0
+#define EPRO_CONFIG_1 0xe0 // a0
+#define EPRO_CONFIG_2 0x16 // no broadcast
+
+// 4 different ones depending on the transceiver setting...
+#define EPRO_CONFIG_3_AUI 0x10
+#define EPRO_CONFIG_3_BNC 0x34
+#define EPRO_CONFIG_3_TPE 0x14
+#define EPRO_CONFIG_3_AUTO 0x00
+
+#define EPRO_NO_RX_STP_INTERRUPTS 0x01
+#define EPRO_NO_RX_INTERRUPTS 0x02
+#define EPRO_NO_TX_INTERRUPTS 0x04
+#define EPRO_NO_EXEC_INTERRUPTS 0x08
+
+#define EPRO_DEFAULT_INTERRUPTS 0x09 // RX and TX
+#define EPRO_ALL_INTERRUPTS 0x0f
+#define EPRO_RX_TX_EXE_INTERRUPTS 0x01
+
+////////////////////////////////////////////////////////////
+// Various states for our ISR
+////////////////////////////////////////////////////////////
+#define EPRO_INT_NONE_PENDING 0
+//#define EPRO_INT_IN_SETUP 1
+//#define EPRO_INT_RESET_PENDING 2
+//#define EPRO_INT_SET_PENDING 3
+#define EPRO_INT_MC_SET_PENDING 4
+
+////////////////////////////////////////////////////////////
+//
+////////////////////////////////////////////////////////////
+// How long do we wait for a TX to free up before we
+// consider ourselves hung?
+#define EPRO_TX_TIMEOUT 10000 // 10000 usec right now
+
+#endif // _IEPROHW_
+
diff --git a/private/ntos/ndis/ieepro/eprosw.h b/private/ntos/ndis/ieepro/eprosw.h
new file mode 100644
index 000000000..421824dee
--- /dev/null
+++ b/private/ntos/ndis/ieepro/eprosw.h
@@ -0,0 +1,254 @@
+#ifndef _IEPROSW_
+#define _IEPROSW_
+
+#define EPRO_NDIS_MAJOR_VERSION 3
+#define EPRO_NDIS_MINOR_VERSION 0
+#define EPRO_USE_32_BIT_IO
+
+////////////////////////////////////////////////////////////
+// Internal data structures used by the driver...
+////////////////////////////////////////////////////////////
+// do i really need this?
+typedef struct EPRO_DRIVER {
+ NDIS_HANDLE EProWrapperHandle;
+} EPRO_DRIVER, *PEPRO_DRIVER;
+
+
+////////////////////////////////////////////////////////////
+typedef struct _EPRO_TRANSMIT_BUFFER {
+// This is basically to make computing the next and last buffer
+// faster... Maybe saves us a few instructions, but makes a
+// lot of code a lot easier to read...
+ struct _EPRO_TRANSMIT_BUFFER *LastBuf;
+ struct _EPRO_TRANSMIT_BUFFER *NextBuf;
+
+ BOOLEAN fEmpty; // TRUE if this is an empty buffer,
+
+// This is valid iff !fEmpty
+ PNDIS_PACKET TXPacket;
+
+// These are addresses ON THE NIC
+ USHORT TXBaseAddr;
+ USHORT TXSendAddr;
+// USHORT TXBottomAddr;
+ USHORT TXSize;
+} EPRO_TRANSMIT_BUFFER, *PEPRO_TRANSMIT_BUFFER;
+
+////////////////////////////////////////////////////////////
+// The header is supposed to be "compatible with the 8595tx'
+// transmit buffer structure. Whatever.
+typedef struct _EPRO_MC_HEADER {
+ UCHAR CommandField;
+ UCHAR NullBytes[5];
+
+// do it this way for endian-safety
+ UCHAR ByteCountLo;
+ UCHAR ByteCountHi;
+} EPRO_MC_HEADER, *PEPRO_MC_HEADER;
+
+////////////////////////////////////////////////////////////
+typedef struct _EPRO_MC_ADDRESS {
+ UCHAR AddrByte[EPRO_LENGTH_OF_ADDRESS];
+} EPRO_MC_ADDRESS, *PEPRO_MC_ADDRESS;
+
+////////////////////////////////////////////////////////////
+// These are the structures to be copied onto the NIC -- they
+// are documented in the 82595 documentation
+typedef struct _EPRO_TX_FRAME_HEADER {
+// High dword
+ UCHAR XmitOp;
+ UCHAR NULLByte;
+ UCHAR Status0;
+ UCHAR Status1;
+// Low dword
+ UCHAR XMTChainLo;
+ UCHAR XMTChainHi;
+} EPRO_TX_FRAME_HEADER, *PEPRO_TX_FRAME_HEADER;
+
+////////////////////////////////////////////////////////////
+// Same as above...
+typedef struct _EPRO_RCV_HEADER {
+ UCHAR Event;
+ UCHAR NullByte;
+ UCHAR Status0;
+ UCHAR Status1;
+ UCHAR NextFrmLo;
+ UCHAR NextFrmHi;
+ UCHAR ByteCountLo;
+ UCHAR ByteCountHi;
+} EPRO_RCV_HEADER, *PEPRO_RCV_HEADER;
+
+////////////////////////////////////////////////////////////
+// This is an ETHERNET 802.3 frame header.
+typedef struct _EPRO_ETH_HEADER {
+ UCHAR DestAddress[EPRO_LENGTH_OF_ADDRESS];
+ UCHAR SourceAddress[EPRO_LENGTH_OF_ADDRESS];
+ USHORT Length;
+} EPRO_ETH_HEADER, *PEPRO_ETH_HEADER;
+
+////////////////////////////////////////////////////////////
+// This is the context that gets passed to EProTransferData
+// through NdisMIndicateReceive
+typedef struct _EPRO_RCV_CONTEXT {
+ USHORT RXCurrentAddress;
+ USHORT RXFrameSize;
+ USHORT LookAheadSize;
+} EPRO_RCV_CONTEXT, *PEPRO_RCV_CONTEXT;
+
+////////////////////////////////////////////////////////////
+// The EPro adapter structure...
+typedef struct EPRO_ADAPTER {
+ NDIS_HANDLE MiniportAdapterHandle;
+ NDIS_MINIPORT_INTERRUPT Interrupt;
+// NDIS_MINIPORT_TIMER MiniportTimer;
+ PVOID IoBaseAddr;
+ ULONG TransceiverType;
+ ULONG IoPAddr; // Returned by NdisMRegisterIoPortRange - handle to mapped ports
+ ULONG IoChannelReady;
+ // What version of 82595 is this?
+ ULONG EProStepping;
+ // Can we use 32-bit IO? (ie is this a new enough version of the 82595
+ // chip?)
+ BOOLEAN EProUse32BitIO;
+
+ ULONG CurrentHardwareStatus;
+ // what is our current packet filter?
+ ULONG CurrentPacketFilter;
+ // are promiscuous receptions currently enabled?
+ BOOLEAN fPromiscuousEnable;
+ // are broadcast receptions currently enabled?
+ BOOLEAN fBroadcastEnable;
+ // are multicast receptions currently enabled?
+ BOOLEAN fMulticastEnable;
+ // are we hung? NOTUSED
+ BOOLEAN fHung;
+ // are receives currently enabled?
+ BOOLEAN fReceiveEnabled;
+ // do we really need this?
+// BOOLEAN fTransmitInProgress;
+
+// statistics
+ ULONG FramesXmitOK;
+ ULONG FramesRcvOK;
+ ULONG FramesXmitErr;
+ ULONG FramesRcvErr;
+ ULONG FramesMissed;
+ ULONG FrameAlignmentErrors;
+ ULONG FramesXmitOneCollision;
+ ULONG FramesXmitManyCollisions;
+
+// transmit info
+ // these are our transmit buffers - structures which basically
+ // keep track of what frames are where in the NIC's memory.
+ EPRO_TRANSMIT_BUFFER TXBuf[EPRO_NUM_TX_BUFFERS];
+ // this is the first free transmit buffer pointer.
+ PEPRO_TRANSMIT_BUFFER CurrentTXBuf;
+ // This is the frame that is currently in the process of
+ // being transmitted onto the wire.
+ PEPRO_TRANSMIT_BUFFER TXChainStart;
+
+// Multicast info
+ UCHAR MCAddress[EPRO_MAX_MULTICAST][EPRO_LENGTH_OF_ADDRESS];
+ // how many mc addresses are currently set?
+ USHORT NumMCAddresses;
+
+// receive info
+ // how big is our lookahead buffer currently?
+ USHORT RXLookAheadSize;
+ // our lookahead buffer data
+ UCHAR RXLookAhead[EPRO_GEN_MAXIMUM_LOKAHEAD];
+ // what address ON THE NIC are we currently receiveing at?
+ // ie where do we check when we get a receive interrupt.
+ USHORT RXCurrentAddress;
+
+ // Is there an exec int pending? If so, why?
+ // right now only used to resolve pended set-mc calls...
+ ULONG IntPending;
+ // This is our context for a pended set-mc call
+ PVOID IntContext;
+ // set based on result of IOCHRDY test
+ BOOLEAN Use8Bit;
+ // set in ReadConfigInfo
+ BOOLEAN UseDefaultAddress;
+ // the MAC address burned into the eeprom
+ UCHAR PermanentIndividualAddress[EPRO_LENGTH_OF_ADDRESS];
+ // the address we are currently receiving at
+ UCHAR CurrentIndividualAddress[EPRO_LENGTH_OF_ADDRESS];
+ // always 00 aa 00 for intel
+ UCHAR vendorID[3];
+
+ UCHAR InterruptNumber;
+ UCHAR BusType;
+
+ // This is only used at initialization time
+ BOOLEAN fUpdateIOAddress;
+ PVOID OldIOAddress;
+
+ UCHAR CurrentInterruptMask;
+} EPRO_ADAPTER, *PEPRO_ADAPTER;
+
+
+////////////////////////////////////////////////////////////
+// Sync contexts
+////////////////////////////////////////////////////////////
+typedef struct _EPRO_COPYBUF_CONTEXT {
+ PEPRO_ADAPTER Adapter;
+ PVOID Buffer;
+ UINT Len;
+} EPRO_COPYBUF_CONTEXT, *PEPRO_COPYBUF_CONTEXT;
+
+typedef struct _EPRO_SETINTERRUPT_CONTEXT {
+ PEPRO_ADAPTER Adapter;
+ UCHAR NewMask;
+} EPRO_SETINTERRUPT_CONTEXT, *PEPRO_SETINTERRUPT_CONTEXT;
+
+typedef struct _EPRO_BRDPROM_CONTEXT {
+ PEPRO_ADAPTER Adapter;
+ UCHAR Reg2Flags;
+} EPRO_BRDPROM_CONTEXT, *PEPRO_BRDPROM_CONTEXT;
+
+
+////////////////////////////////////////////////////////////
+// Some macros for commonly used stuff....
+
+#define EPRO_WR_PORT_UCHAR(adapter, port, ch) \
+ NdisRawWritePortUchar(adapter->IoPAddr + port, ch)
+
+#define EPRO_RD_PORT_UCHAR(adapter, port, ch) \
+ NdisRawReadPortUchar(adapter->IoPAddr + port, ch)
+
+#define EPRO_WR_PORT_USHORT(adapter, port, us) \
+ NdisRawWritePortUshort(adapter->IoPAddr + port, us)
+
+#define EPRO_RD_PORT_USHORT(adapter, port, us) \
+ NdisRawReadPortUshort(adapter->IoPAddr + port, us)
+
+
+////////////////////////////////////////////////////////////
+// The EPro is a bank-switching card. These macros switch between the banks...
+#define EPRO_SWITCH_BANK_0(adapter) \
+ EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_CMD_BANK0)
+
+#define EPRO_SWITCH_BANK_1(adapter) \
+ EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_CMD_BANK1)
+
+#define EPRO_SWITCH_BANK_2(adapter) \
+ EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_CMD_BANK2)
+
+// Set the Host Address Register (0,c) -- use this to set up the NIC address
+// for PIO through the register via COPY_BUFFER macros.
+#define EPRO_SET_HOST_ADDR(adapter, addr) \
+ EPRO_WR_PORT_USHORT(adapter, I82595_HOST_ADDR_REG, addr);
+
+#define EPRO_COPY_BUFFER_TO_NIC_USHORT(adapter, buffer, len) \
+ NdisRawWritePortBufferUshort((adapter->IoPAddr + I82595_MEM_IO_REG), \
+ (buffer), \
+ (len))
+
+#define EPRO_READ_BUFFER_FROM_NIC_USHORT(adapter, buffer, len) \
+ NdisRawReadPortBufferUshort((adapter->IoPAddr + I82595_MEM_IO_REG), \
+ (buffer), \
+ len)
+
+
+#endif _IEPROSW_
diff --git a/private/ntos/ndis/ieepro/init.c b/private/ntos/ndis/ieepro/init.c
new file mode 100644
index 000000000..b94ae0e02
--- /dev/null
+++ b/private/ntos/ndis/ieepro/init.c
@@ -0,0 +1,1418 @@
+#include <stdio.h>
+#include <ndis.h>
+#include "82595.h"
+#include "eprohw.h"
+#include "eprosw.h"
+#include "epro.h"
+#include "eprodbg.h"
+
+NDIS_PHYSICAL_ADDRESS HighestAcceptableMax =
+ NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT pDriverObject_,
+ IN PUNICODE_STRING RegistryPath_)
+/*++
+ Routine Description:
+
+ This is the primary initialization routine for the EPRO driver.
+ It is simply responsible for the intializing the wrapper and registering
+ the Miniport driver. It then calls a system and architecture specific
+ routine that will initialize and register each adapter.
+
+ Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+ RegistryPath - Path to the parameters for this driver in the registry.
+
+ Return Value:
+
+ The status of the operation.
+--*/
+{
+ //
+ // Receives the status of the NdisMRegisterMiniport operation.
+ //
+ NDIS_STATUS status;
+
+ //
+ // Characteristics table for this driver.
+ //
+ NDIS_MINIPORT_CHARACTERISTICS EPro_Miniport_Char;
+
+ //
+ // Handle for referring to the wrapper about this driver.
+ //
+ NDIS_HANDLE ndisWrapperHandle;
+
+ //
+ // Initialize the wrapper.
+ //
+ NdisMInitializeWrapper(
+ &ndisWrapperHandle,
+ pDriverObject_,
+ RegistryPath_,
+ NULL);
+
+ //
+ // Initialize the Miniport characteristics for the call to
+ // NdisMRegisterMiniport.
+ //
+
+ // The major and minor version of the driver
+ EPro_Miniport_Char.MajorNdisVersion = EPRO_NDIS_MAJOR_VERSION;
+ EPro_Miniport_Char.MinorNdisVersion = EPRO_NDIS_MINOR_VERSION;
+
+ // our various Miniport handlers
+ EPro_Miniport_Char.CheckForHangHandler = EProCheckForHang;
+ EPro_Miniport_Char.DisableInterruptHandler = EProDisableInterrupts;
+ EPro_Miniport_Char.EnableInterruptHandler = EProEnableInterrupts;
+ EPro_Miniport_Char.HaltHandler = EProHalt;
+ EPro_Miniport_Char.HandleInterruptHandler = EProHandleInterrupt;
+ EPro_Miniport_Char.InitializeHandler = EProInitialize;
+ EPro_Miniport_Char.ISRHandler = EProISR;
+ EPro_Miniport_Char.QueryInformationHandler = EProQueryInformation;
+ EPro_Miniport_Char.ReconfigureHandler = NULL;
+ EPro_Miniport_Char.ResetHandler = EProReset;
+ EPro_Miniport_Char.SendHandler = EProSend;
+ EPro_Miniport_Char.SetInformationHandler = EProSetInformation;
+ EPro_Miniport_Char.TransferDataHandler = EProTransferData;
+
+ // register us as a miniport...
+ status = NdisMRegisterMiniport(
+ ndisWrapperHandle,
+ &EPro_Miniport_Char,
+ sizeof(EPro_Miniport_Char));
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ NdisTerminateWrapper(ndisWrapperHandle, NULL);
+ EPRO_DPRINTF_INIT(("DriverEntry UNSUCCESSFUL!\n"));
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ EPRO_DPRINTF_INIT(("EPro DriverEntry Successful!\n"));
+
+ return(STATUS_SUCCESS);
+}
+
+NDIS_STATUS EProInitialize(
+ OUT PNDIS_STATUS openErrorStatus,
+ OUT PUINT selectedMediumIndex,
+ IN PNDIS_MEDIUM mediumArray,
+ IN UINT mediumArraySize,
+ IN NDIS_HANDLE miniportAdapterHandle,
+ IN NDIS_HANDLE configurationHandle)
+/*++
+
+ Routine Description:
+
+ EProInitialize starts an adapter and registers resources with the
+ wrapper.
+
+ Arguments:
+
+ OpenErrorStatus - Extra status bytes for opening token ring adapters.
+
+ SelectedMediumIndex - Index of the media type chosen by the driver.
+
+ MediumArray - Array of media types for the driver to chose from.
+
+ MediumArraySize - Number of entries in the array.
+
+ MiniportAdapterHandle - Handle for passing to the wrapper when
+ referring to this adapter.
+
+ ConfigurationHandle - A handle to pass to NdisOpenConfiguration.
+
+ Return Values:
+ NDIS_STATUS_UNSUPPORTED_MEDIA - the wrapper tried to set a media
+ type we couldn't do
+
+ NDIS_STATUS_SUCCESS - operation succeeded ok
+
+ perhaps other error status returned from the NdisM calls..
+
+--*/
+{
+ PEPRO_ADAPTER adapter = NULL;
+ UINT i;
+ NDIS_STATUS status;
+ BOOLEAN fAllocatedAdapterMemory;
+ BOOLEAN fRegisteredIoPortRange;
+
+ //
+ // Find the 802.3 medium type and return it to the wrapper...
+ //
+ for (i = 0; i < mediumArraySize; i++)
+ {
+ if (mediumArray[i] == NdisMedium802_3)
+ {
+ break;
+ }
+ }
+
+ if (i == mediumArraySize)
+ {
+ return(NDIS_STATUS_UNSUPPORTED_MEDIA);
+ }
+
+ // Return the correct medium to the wrapper
+ //
+ *selectedMediumIndex = i;
+
+ fAllocatedAdapterMemory = FALSE;
+ fRegisteredIoPortRange = FALSE;
+
+ do
+ {
+ //
+ // Allocate Memory for the Adapter Structure
+ //
+ status = NdisAllocateMemory(
+ (PVOID *)&adapter,
+ sizeof(EPRO_ADAPTER),
+ 0,
+ HighestAcceptableMax);
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ EPRO_DPRINTF_INIT(("Failed to allocate memory for the EPRO adapter stucture\n"));
+ break;
+ }
+
+ fAllocatedAdapterMemory = TRUE;
+
+ //
+ // Zero the adapter structure.
+ //
+ NdisZeroMemory(adapter, sizeof(EPRO_ADAPTER));
+
+ //
+ // Set some initial values in the adapter structure...
+ //
+ EProInitializeAdapterData(adapter);
+
+ //
+ // Save the miniport adapter handle for later
+ //
+ adapter->MiniportAdapterHandle = miniportAdapterHandle;
+
+ //
+ // Read configuration information for this adapter
+ //
+ status = EProReadConfiguration(adapter, configurationHandle);
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ EPRO_DPRINTF_INIT(("EProReadConfiguration FAILED!\n"));
+
+ break;
+ }
+
+ //
+ // Register our adapter handler with the wrapper.
+ //
+ NdisMSetAttributes(
+ adapter->MiniportAdapterHandle,
+ (NDIS_HANDLE)adapter,
+ FALSE,
+ adapter->BusType);
+
+ //
+ // Register the IO port range needed.
+ //
+ status = NdisMRegisterIoPortRange(
+ (PVOID *)(&adapter->IoPAddr),
+ adapter->MiniportAdapterHandle,
+ (ULONG)adapter->IoBaseAddr,
+ 0x10);
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ EPRO_DPRINTF_INIT(("Could not register IO ports.\n"));
+
+ break;
+ }
+
+ fRegisteredIoPortRange = TRUE;
+
+ //
+ // Initialize the hardware and enable the card...
+ //
+ status = EProInitialReset(adapter);
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ EPRO_DPRINTF_INIT(("Failed Initial Reset\n"));
+
+ break;
+ }
+
+ //
+ // Now, the resetting is done - configure the hardware...
+ //
+ status = EProHWConfigure(adapter);
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ EPRO_DPRINTF_INIT(("Failed to configure EPRO hardware\n"));
+
+ break;
+ }
+
+ //
+ // If we are a step 2 or 3 adapter then update the eeprom if
+ // necessary. RM: add stepping 4.
+ //
+ if ((adapter->EProStepping == 2) || (adapter->EProStepping == 3) || (adapter->EProStepping == 4))
+ {
+ EProUpdateEEProm(adapter);
+ }
+
+ //
+ // Make sure that we do not free resources.
+ //
+ fAllocatedAdapterMemory = FALSE;
+ fRegisteredIoPortRange = FALSE;
+
+ } while (FALSE);
+
+ if (fRegisteredIoPortRange)
+ {
+ NdisMDeregisterIoPortRange(
+ adapter->MiniportAdapterHandle,
+ (ULONG)adapter->IoBaseAddr,
+ 0x10,
+ (PVOID)adapter->IoPAddr);
+ }
+
+ if (fAllocatedAdapterMemory)
+ {
+ NdisFreeMemory(adapter, sizeof(EPRO_ADAPTER), 0);
+ }
+
+ return(status);
+}
+
+VOID EProUpdateEEProm(IN PEPRO_ADAPTER adapter)
+/*++
+
+ Routine Description:
+
+ This routine is called after the card's configuration has been
+ read from the registry and after the card's IO ports have been
+ registered. Now we check the card's EEPROM and verify that the
+ configuration information in the registry matches that saved
+ in the EEPROM. If they DON'T match, we update the card's EEPROM
+ with the new info. Note that the registry always overrides the
+ info that is saved -- in fact the info saved on the card is never
+ used at all right now, except the IO address - it is always overriden
+ by defaults or the registry values. We just save it in case the user
+ boots to another OS or moves and re-installs the card (the detection
+ code DOES read the EEPROM-configured defaults, so a new install will
+ be interested in what we have set.)
+
+ Arguments:
+
+ adapter - pointer to our EPRO_ADAPTER structure
+
+ Return Values:
+
+ none
+
+--*/
+{
+ USHORT reg0, reg1;
+ BOOLEAN fCardUse8Bit;
+ BOOLEAN fUpdateEEPROM = FALSE;
+ USHORT cardIrq;
+
+ EProEERead(adapter, EPRO_EEPROM_CONFIG_OFFSET, &reg0);
+ EProEERead(adapter, EPRO_EEPROM_CONFIG1_OFFSET, &reg1);
+
+ //
+ // check the force 8-bit setting...
+ //
+ fCardUse8Bit = !(reg0 & EPRO_EEPROM_HOST_BUS_WD_MASK);
+ if (fCardUse8Bit != adapter->Use8Bit)
+ {
+ fUpdateEEPROM = TRUE;
+ if (adapter->Use8Bit)
+ {
+ reg0 &= ~EPRO_EEPROM_HOST_BUS_WD_MASK;
+ }
+ else
+ {
+ reg0 |= EPRO_EEPROM_HOST_BUS_WD_MASK;
+ }
+ }
+ //
+ // check the IRQ
+ //
+ switch(reg1 & EPRO_EEPROM_IRQ_MASK)
+ {
+ case 0:
+ cardIrq = (adapter->EProStepping == 4)? 3 : 9;
+ break;
+
+ case 1:
+ cardIrq = (adapter->EProStepping == 4)? 4 : 3;
+ break;
+
+ case 2:
+ cardIrq = 5;
+ break;
+
+ case 3:
+ cardIrq = (adapter->EProStepping == 4)? 7 : 10;
+ break;
+
+ case 4:
+ cardIrq = (adapter->EProStepping == 4)? 9 : 11;
+ break;
+
+ case 5:
+ cardIrq = (adapter->EProStepping == 4)? 10 : 5;
+ break;
+
+
+ case 6:
+ cardIrq = (adapter->EProStepping == 4)? 11 : 5;
+ break;
+
+ case 7:
+ cardIrq = (adapter->EProStepping == 4)? 12 : 5;
+ break;
+
+
+ default:
+ cardIrq = 0xff;
+ break;
+ }
+
+ EPRO_DPRINTF_INIT(("EEPROM Interrupt Number: 0x%x\n", cardIrq));
+
+ if (cardIrq != adapter->InterruptNumber)
+ {
+ EPRO_DPRINTF_INIT(("Changing EEPROM to interrupt number 0x%x\n", adapter->InterruptNumber));
+ fUpdateEEPROM = TRUE;
+ reg1 &= ~EPRO_EEPROM_IRQ_MASK;
+ //
+ // RM: in the following, some INTs are different for stepping 4.
+ // Unsupported ints default to IRQ 5. IRQ 2 and 9 are INT 0 for stepping 2/3.
+ //
+ switch(adapter->InterruptNumber)
+ {
+ case 2:
+ case 9:
+ reg1 |= (adapter->EProStepping == 4)? EPRO_EEPROM4_IRQ_9_MASK : EPRO_EEPROM_IRQ_2_MASK;
+ break;
+
+ case 3:
+ reg1 |= (adapter->EProStepping == 4)? EPRO_EEPROM4_IRQ_3_MASK : EPRO_EEPROM_IRQ_3_MASK;
+ break;
+
+ case 4:
+ reg1 |= (adapter->EProStepping == 4)? EPRO_EEPROM4_IRQ_4_MASK : EPRO_EEPROM_IRQ_5_MASK;
+ break;
+
+ case 5:
+ reg1 |= EPRO_EEPROM_IRQ_5_MASK;
+ break;
+
+ case 7:
+ reg1 |= (adapter->EProStepping == 4)? EPRO_EEPROM4_IRQ_7_MASK : EPRO_EEPROM_IRQ_5_MASK;
+ break;
+
+ case 10:
+ reg1 |= (adapter->EProStepping == 4)? EPRO_EEPROM4_IRQ_10_MASK : EPRO_EEPROM_IRQ_10_MASK;
+ break;
+
+ case 11:
+ reg1 |= (adapter->EProStepping == 4)? EPRO_EEPROM4_IRQ_11_MASK : EPRO_EEPROM_IRQ_11_MASK;
+ break;
+
+ case 12:
+ reg1 |= (adapter->EProStepping == 4)? EPRO_EEPROM4_IRQ_12_MASK : EPRO_EEPROM_IRQ_5_MASK;
+ break;
+
+ default:
+ reg1 |= EPRO_EEPROM_IRQ_5_MASK;
+ break;
+ }
+
+ EPRO_DPRINTF_INIT(("EEPROM interrupt mask 0x%x\n", reg1 & EPRO_EEPROM_IRQ_MASK));
+ }
+
+ if (fUpdateEEPROM)
+ {
+ EProEEWrite(adapter, EPRO_EEPROM_CONFIG_OFFSET, reg0);
+ EProEEWrite(adapter, EPRO_EEPROM_CONFIG1_OFFSET, reg1);
+ EProEEUpdateChecksum(adapter);
+ }
+}
+
+NDIS_STATUS
+EProReadConfiguration(
+ IN PEPRO_ADAPTER adapter,
+ IN NDIS_HANDLE configurationHandle
+ )
+/*++
+
+ Routine Description:
+
+ Read card config info from the registry and set the values
+ in the adapter structure
+
+ Arguments:
+
+ adapter - pointer to our adapter structure
+
+ configurationHandle - a handle to a place in the registry we can
+ read our settings from
+
+ Return Values:
+
+--*/
+{
+ NDIS_STATUS status;
+ NDIS_HANDLE configHandle;
+ PNDIS_CONFIGURATION_PARAMETER returnedValue;
+
+ // These are the keys we read from the registry..
+ //
+ NDIS_STRING interruptNumberString = EPRO_REGISTRY_INTERRUPT_STRING;
+
+ // I/O Port Base Address
+ //
+ NDIS_STRING ioAddressString = EPRO_REGISTRY_IOADDRESS_STRING;
+
+ // OLD I/O Base Address
+ //
+ NDIS_STRING oldIOAddressString = EPRO_REGISTRY_OLDIOADDRESS_STRING;
+
+ // bus type
+ //
+ NDIS_STRING busTypeString = EPRO_REGISTRY_BUSTYPE_STRING;
+
+ // Transceiver Type
+ //
+ NDIS_STRING transceiverString = EPRO_REGISTRY_TRANSCEIVER_STRING;
+
+ // Io Channel Ready
+ //
+ NDIS_STRING IoChannelReadyString = EPRO_REGISTRY_IOCHRDY_STRING;
+
+ // Open the configuration file...
+ //
+ NdisOpenConfiguration(
+ &status,
+ &configHandle,
+ configurationHandle);
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ EPRO_DPRINTF_INIT(("EProReadConfiguration - failed in NdisOpenConfiguration\n"));
+ NdisFreeMemory(adapter, sizeof(adapter),0);
+ return(status);
+ }
+
+ // right now we'll just assume it's an isa card...
+ //
+ adapter->BusType = NdisInterfaceIsa;
+
+ // Do we need to update the IO base address?
+ //
+ adapter->fUpdateIOAddress = FALSE;
+
+ // Read "Real" IO Base Address (the one we want to use)
+ //
+ NdisReadConfiguration(&status,
+ &returnedValue,
+ configHandle,
+ &ioAddressString,
+ NdisParameterHexInteger);
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ EPRO_DPRINTF_INIT(("Error, can't find io address in registry...using default 0x300\n"));
+ adapter->IoBaseAddr = (PVOID)0x300;
+ }
+ else
+ {
+ adapter->IoBaseAddr = (PVOID)(returnedValue->ParameterData.IntegerData);
+ }
+
+ if ((adapter->IoBaseAddr > (PVOID)0x3f0) || (adapter->IoBaseAddr < (PVOID)0x200))
+ {
+ EPRO_DPRINTF_INIT(("Bad io address set in registry. Using 0x300.\n"));
+ adapter->IoBaseAddr = (PVOID)0x300;
+ }
+
+ //
+ // Read the InterruptNumber
+ //
+ NdisReadConfiguration(
+ &status,
+ &returnedValue,
+ configHandle,
+ &interruptNumberString,
+ NdisParameterHexInteger);
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ EPRO_DPRINTF_REQ(("Error, can't read interrupt number from registry...using default\n"));
+ adapter->InterruptNumber = (CCHAR)5;
+ }
+ else
+ {
+ adapter->InterruptNumber = (CCHAR)(returnedValue->ParameterData.IntegerData);
+ }
+
+ // oh, yah, what was I on when I wrote this?
+ switch (adapter->InterruptNumber)
+ {
+ case 3:
+ case 5:
+ case 9:
+ case 10:
+ case 11:
+ // 4, 7 & 12 valid for v4 chips +RM
+ case 4:
+ case 7:
+ case 12:
+ break;
+
+ default:
+ adapter->InterruptNumber = (CCHAR)5;
+ }
+
+ //
+ // Read the TransceiverType
+ //
+ NdisReadConfiguration(
+ &status,
+ &returnedValue,
+ configHandle,
+ &transceiverString,
+ NdisParameterHexInteger);
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ EPRO_DPRINTF_REQ(("Error, can't read transceiver type from registry...using AUTO\n"));
+ adapter->TransceiverType = (CCHAR)4;
+ }
+ else
+ {
+ adapter->TransceiverType = (CCHAR)(returnedValue->ParameterData.IntegerData);
+ }
+
+ //
+ // Read the IoChannelReady Setting
+ //
+ NdisReadConfiguration(
+ &status,
+ &returnedValue,
+ configHandle,
+ &IoChannelReadyString,
+ NdisParameterHexInteger);
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ EPRO_DPRINTF_REQ(("Error, can't read transceiver type from registry...using AUTO\n"));
+ adapter->IoChannelReady = (CCHAR)4; // auto-detect is default
+ }
+ else
+ {
+ adapter->IoChannelReady = (CCHAR)(returnedValue->ParameterData.IntegerData);
+ }
+
+ //
+ // See if a MAC address has been specified in the registry to
+ // override our hardware-set one.
+ //
+ {
+ UINT addrLen;
+ PUCHAR netAddr;
+ NDIS_STATUS status;
+
+ //
+ // attempt to read the network address
+ //
+ NdisReadNetworkAddress(
+ &status,
+ &netAddr,
+ &addrLen,
+ configHandle);
+
+ // did the operation succeed?
+ //
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ adapter->UseDefaultAddress = FALSE;
+
+ // yes: use this address.
+ //
+ NdisMoveMemory(
+ &adapter->CurrentIndividualAddress,
+ netAddr,
+ EPRO_LENGTH_OF_ADDRESS);
+ }
+ else
+ {
+ // just use the one out of the eeprom
+ adapter->UseDefaultAddress = TRUE;
+ }
+ }
+
+
+ // Close the configuration file...
+ //
+ NdisCloseConfiguration(configHandle);
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS EProInitialReset(PEPRO_ADAPTER adapter)
+/*++
+
+ Routine Description:
+
+ This call really does two things: first, it calls
+ EProHWInitialize to set up the hardware, and then it
+ registers the card's interrupt and starts the card going.
+
+ Arguments:
+
+ adapter - pointer to our adapter structure...
+
+ Return Values:
+
+--*/
+{
+ NDIS_STATUS status;
+
+ status = EProHWInitialize(adapter);
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ EPRO_DPRINTF_INIT(("FAILED in EProHWInitialize.\n"));
+ return(status);
+ }
+
+ switch (adapter->IoChannelReady)
+ {
+ case EPRO_IOCHRDY_EARLY:
+ EPRO_DPRINTF_INIT(("EPro configured for EARLY IoChannelReady\n"));
+ break;
+
+ case EPRO_IOCHRDY_LATE:
+ EPRO_DPRINTF_INIT(("EPro configured for LATE IoChannelReady\n"));
+ break;
+
+ case EPRO_IOCHRDY_NEVER:
+ // They've set this in the cpanel - force 8 bits
+ //
+ EPRO_DPRINTF_INIT(("EPro configured for NEVER IoChannelReady\n"));
+ adapter->Use8Bit = TRUE;
+ break;
+
+ case EPRO_IOCHRDY_AUTO:
+ default:
+
+ EPRO_DPRINTF_INIT(("EPro configured for AUTO IoChannelReady\n"));
+
+ if (adapter->EProStepping < 4) //RM: don't do rev 4
+ {
+ if (!EProAltIOCHRDYTest(adapter))
+ {
+ EPRO_DPRINTF_INIT(("EPro failed the IOCHRDY test. Forcing 8-bit operation\n"));
+
+ // configure for 8-bit operation
+ //
+ EPRO_DPRINTF_INIT(("EPro configured for NEVER IoChannelReady\n"));
+ adapter->Use8Bit = TRUE;
+ }
+ }
+ break;
+ }
+
+ return(status);
+}
+
+NDIS_STATUS
+EProHWInitialize(
+ IN PEPRO_ADAPTER adapter
+ )
+/*++
+
+ Routine Description:
+
+ Now we start dealing with the card. Probe and verify its
+ existence, try to power it up if necessary, init it, etc.
+
+ Arguments:
+
+ adapter - pointer to our adapter structure
+
+ Return Values:
+
+--*/
+{
+ UCHAR buf[4], fExecDone, result, intReg;
+ UINT i;
+
+ // Make sure we're in bank 0
+ //
+ EPRO_SWITCH_BANK_0(adapter);
+
+ for (i = 0; i < 4; i++)
+ {
+ EPRO_RD_PORT_UCHAR(adapter, I82595_ID_REG, &buf[i]);
+ }
+
+ if (!EProVerifyRoundRobin(buf))
+ {
+ //
+ // hmm, didn't find the board. Try powering it up, then try again.
+ // It's concievable that the board was in its "powered down" state
+ // and so we try the powerup procedure as a last-ditch effort.
+ //
+ EPRO_DPRINTF_INIT(("Initial probe failing. Attempting to power board up.\n"));
+ if (!EProPowerupBoard(adapter))
+ {
+ EPRO_DPRINTF_INIT(("Couldn't power board up. Can't find board.\n"));
+ return(NDIS_STATUS_HARD_ERRORS);
+ }
+ }
+
+ // Do a full reset.
+ //
+ EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_FULL_RESET);
+
+ // poll for the card to be done it's init sequence.
+ //
+ for (i = 0; i < 10000; i++)
+ {
+ EPRO_RD_PORT_UCHAR(adapter, I82595_STATUS_REG, &intReg);
+
+ if (intReg & I82595_EXEC_INT_RCVD)
+ break;
+
+ NdisStallExecution(10);
+ }
+
+ if (i >= 10000)
+ {
+ EPRO_DPRINTF_INIT(("EPRO: Did NOT get return from init....\n"));
+ return(NDIS_STATUS_SOFT_ERRORS);
+ }
+
+
+ // According to the docs, writing a _1_ to the execution int bit
+ // clears it -- so we can just overwrite it to clear it.
+ //
+ EPRO_WR_PORT_UCHAR(adapter, I82595_STATUS_REG, intReg);
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+EProHWConfigure(
+ IN PEPRO_ADAPTER adapter
+ )
+/*++
+
+ Routine Description:
+
+ The second half of the init -- now the hardware has just been
+ told to reset. Wait for the reset to finish, then configure
+ the board...
+
+ Arguments:
+
+ adapter - pointer to our adapter structure
+
+ Return Values:
+
+--*/
+{
+ UCHAR result, intReg;
+ NDIS_STATUS status;
+ UINT i;
+ UCHAR intMask;
+
+ EPRO_DPRINTF_INIT(("EPRO: In EProHWConfigure\n"));
+
+ //
+ // Configure the adapter
+ //
+ EPRO_SWITCH_BANK_0(adapter);
+
+ //
+ // These two lines are a blatant hack to get around some timing
+ // problems I was having in the init sequence.
+ //
+ EPRO_RD_PORT_UCHAR(adapter, I82595_CMD_REG, &result);
+ NdisStallExecution(1000);
+
+ if (!EProWaitForExeDma(adapter))
+ {
+ return(NDIS_STATUS_HARD_ERRORS);
+ }
+
+ // Set the 82595's config registers up for the driver.
+ // RM: Moved this up here so we have the chip version upfront.
+
+ //
+ // Switch to bank2 for configuration
+ //
+ EPRO_SWITCH_BANK_2(adapter);
+
+ //
+ // Get 82595 chip version.
+ //
+ EPRO_RD_PORT_UCHAR(adapter, I82595_STEPPING_REG, &result);
+ adapter->EProStepping = (result >> I82595_STEPPING_OFFSET);
+
+ EPRO_DPRINTF_INIT(("This is a level %x 82595\n", adapter->EProStepping));
+
+ if (adapter->EProStepping < 2)
+ {
+ adapter->EProUse32BitIO = FALSE;
+ EPRO_DPRINTF_INIT(("NOT using 32-bit I/O port.\n"));
+ }
+ else if (adapter->EProStepping > 4) //RM: included rev 4
+ {
+ //
+ // We don't support this step of the adapter!
+ //
+ EPRO_DPRINTF_INIT(("Do not support step %u epro's\n", adapter->EProStepping));
+ return(NDIS_STATUS_HARD_ERRORS);
+ }
+ else
+ {
+ //
+ // Step is 2, 3 or 4.
+ //
+ adapter->EProUse32BitIO = TRUE;
+ EPRO_DPRINTF_INIT(("using 32-bit I/O port.\n"));
+ }
+
+ //
+ // Set configuration register 1 in bank 2
+ //
+ EPRO_WR_PORT_UCHAR(adapter, I82595_CONFIG1_REG, EPRO_CONFIG_1);
+
+ //
+ // Set the transceiver type...
+ //
+ EPRO_DPRINTF_INIT(("EPRO: Transceiver type is 0x%x\n",
+ adapter->TransceiverType));
+
+ switch (adapter->TransceiverType)
+ {
+ case 1:
+ result = EPRO_CONFIG_3_AUI;
+ break;
+
+ case 2:
+ result = EPRO_CONFIG_3_BNC;
+ break;
+
+ case 3:
+ result = EPRO_CONFIG_3_TPE;
+ break;
+
+ case 4:
+ default:
+ result = EPRO_CONFIG_3_AUTO;
+ break;
+ }
+
+ EPRO_WR_PORT_UCHAR(adapter, I82595_CONFIG2_REG, EPRO_CONFIG_2);
+ EPRO_WR_PORT_UCHAR(adapter, I82595_CONFIG3_REG, result);
+
+ //
+ // Switch to Bank1
+ //
+ EPRO_SWITCH_BANK_1(adapter);
+
+ if (adapter->EProStepping < 4) //Alt Ready timing reg n/a in rev 4 --
+ // included in EEPROM for back-compat only
+ {
+
+ //
+ // Configure the card's IOCHRDY setting if we're forcing it
+ //
+ if (adapter->IoChannelReady == EPRO_IOCHRDY_EARLY)
+ {
+ //
+ // force EARLY (alternate) timing
+ //
+ EPRO_RD_PORT_UCHAR(adapter, I82595_ALT_RDY_REG, &result);
+ result |= I82595_ALT_IOCHRDY;
+ EPRO_WR_PORT_UCHAR(adapter, I82595_ALT_RDY_REG, result);
+ }
+
+ //
+ // Configure the card's IOCHRDY setting if we're forcing it
+ //
+ if (adapter->IoChannelReady == EPRO_IOCHRDY_LATE)
+ {
+ //
+ // Force LATE (isa compatible) timing
+ //
+ EPRO_RD_PORT_UCHAR(adapter, I82595_ALT_RDY_REG, &result);
+ result &= ~I82595_ALT_IOCHRDY;
+ EPRO_WR_PORT_UCHAR(adapter, I82595_ALT_RDY_REG, result);
+ }
+ }
+ //
+ // Do we have to use 8-bit?
+ //
+ if (adapter->Use8Bit)
+ {
+ EPRO_DPRINTF_INIT(("Using 8 bits\n"));
+
+ EPRO_RD_PORT_UCHAR(adapter, I82595_ALT_RDY_REG, &result);
+ result &= ~I82595_USE_8_BIT_FLAG;
+ EPRO_WR_PORT_UCHAR(adapter, I82595_ALT_RDY_REG, result);
+ }
+
+ //
+ // Set the buffer limit registers...
+ //
+ EPRO_WR_PORT_UCHAR(adapter, I82595_TX_LOWER_LIMIT_REG, EPRO_TX_LOWER_LIMIT);
+ EPRO_WR_PORT_UCHAR(adapter, I82595_TX_UPPER_LIMIT_REG, EPRO_TX_UPPER_LIMIT);
+
+ EPRO_WR_PORT_UCHAR(adapter, I82595_RX_LOWER_LIMIT_REG, EPRO_RX_LOWER_LIMIT);
+ EPRO_WR_PORT_UCHAR(adapter, I82595_RX_UPPER_LIMIT_REG, EPRO_RX_UPPER_LIMIT);
+
+ //
+ // Tell the card what Interrupt to use, default to 5. RM: Added check for V4.
+ // Default bad IRQs to 5 (mask 2 for all steppings).
+ //
+
+ switch (adapter->InterruptNumber)
+ {
+ case 3:
+ intMask = (adapter->EProStepping == 4)? 0x0 : 0x1;
+ break;
+
+ case 4:
+ intMask = (adapter->EProStepping == 4)? 0x1 : 0x2;
+ break;
+
+ case 5:
+ intMask = 0x2;
+ break;
+
+ case 7:
+ intMask = (adapter->EProStepping == 4)? 0x3 : 0x2;
+ break;
+
+ case 9:
+ //
+ // note that this is out of order - because the epro
+ // uses the 0 to indicate 2/9 (2 on an 8-bit bus in DOS mode
+ // and 9 otherwise...or something like that) Anyways, it is
+ // 9 under NT.
+ //
+ intMask = (adapter->EProStepping == 4)? 0x4 : 0x0;
+ break;
+
+ case 10:
+ intMask = (adapter->EProStepping == 4)? 0x5 : 0x3;
+ break;
+
+ case 11:
+ intMask = (adapter->EProStepping == 4)? 0x6 : 0x4;
+ break;
+
+ case 12:
+ intMask = (adapter->EProStepping == 4)? 0x7 : 0x2;
+ break;
+
+ default:
+
+ EPRO_DPRINTF_INIT(("EPRO: invalid interrupt selected using interrupt 5."));
+ intMask = 0x2;
+ break;
+ }
+
+ EPRO_RD_PORT_UCHAR(adapter, I82595_INT_SELECT_REG, &result);
+
+ result &= ~(I82595_INTERRUPT_SELECT_MASK);
+ result |= intMask;
+ EPRO_WR_PORT_UCHAR(adapter, I82595_INT_SELECT_REG, result);
+
+ //
+ // Read the card's ethernet address out of the eeprom.
+ //
+ if (!EProCardReadEthernetAddress(adapter))
+ {
+ EPRO_DPRINTF_INIT(("EPRO: Could not read the EPro card's ethernet address.\n"));
+ return(NDIS_STATUS_SOFT_ERRORS);
+ }
+
+ if (adapter->UseDefaultAddress == TRUE)
+ {
+ //
+ // Copy the permanent address to the current address
+ //
+ NdisMoveMemory(
+ &adapter->CurrentIndividualAddress,
+ &adapter->PermanentIndividualAddress,
+ EPRO_LENGTH_OF_ADDRESS);
+ }
+
+ //
+ // Set the card's ethernet address to the one specified in
+ // adapter->current...
+ //
+ if (!EProSetEthernetAddress(adapter))
+ {
+ return(NDIS_STATUS_SOFT_ERRORS);
+ }
+
+ EPRO_SWITCH_BANK_1(adapter);
+
+ //
+ // flip the interrupt tri-state bit...
+ //
+ EPRO_RD_PORT_UCHAR(adapter, I82595_INTENABLE_REG, &result);
+ result|=I82595_ENABLE_INTS_FLAG;
+ EPRO_WR_PORT_UCHAR(adapter, I82595_INTENABLE_REG, result);
+
+ EPRO_SWITCH_BANK_0(adapter);
+
+ if (!EProWaitForExeDma(adapter))
+ {
+ return(NDIS_STATUS_SOFT_ERRORS);
+ }
+
+ //
+ // bank0
+ //
+ EPRO_SWITCH_BANK_0(adapter);
+
+ //
+ // Set the interrupt mask...
+ //
+ adapter->CurrentInterruptMask = EPRO_DEFAULT_INTERRUPTS;
+
+ //
+ // Register the interrupt.
+ //
+ status = NdisMRegisterInterrupt(
+ &adapter->Interrupt,
+ adapter->MiniportAdapterHandle,
+ adapter->InterruptNumber,
+ adapter->InterruptNumber,
+ FALSE,
+ FALSE,
+ NdisInterruptLatched);
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ EPRO_DPRINTF_INIT(("Register Interrupts FAILED\n"));
+ return(status);
+ }
+
+ //
+ // Enable interrupts...
+ //
+ EProEnableInterrupts((NDIS_HANDLE)adapter);
+
+ EProSelReset(adapter);
+
+ EPRO_DPRINTF_INIT(("EtherExpress Pro: configuration complete\n"));
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+BOOLEAN
+EProVerifyRoundRobin(
+ IN UCHAR *buf
+ )
+/*++
+
+ Routine Description:
+
+ This routine takes a sequence of 4 bytes passed in as the
+ result of 4 consecutive reads from the possible card's register
+ at address 2 (ie if base port is 0x300, 4 reads from 0x302) and
+ determines if the four constitute the EPro's ID signature. If they
+ do (epro identified) this returns TRUE, otherwise FALSE.
+
+ The 7th and 8th bits of these 4 should count 00 01 10 11 or some
+ permutation....
+
+ NOTE - if this code changes (because of chip updates, whatever) make
+ sure you change this function in the net-detection code (this function
+ is cut-and-pasted into detepro.c)
+
+ Arguments:
+
+ buf - a 4-byte character array with the four results in it...
+
+ Return Values:
+
+ TRUE if this is the 82595's signature
+ FALSE if it is not.
+
+--*/
+{
+ UCHAR ch;
+ int i, i1;
+
+ // Don't even bother. This works, take my word for it.
+ //
+ i1 = buf[0] >> 6;
+
+ for (i = 1; i < 4; i++)
+ {
+ i1 = (i1 > 2) ? 0 : i1 + 1;
+ if ((buf[i] >> 6) != i1)
+ {
+ return(FALSE);
+ }
+ }
+
+ return(TRUE);
+}
+
+BOOLEAN
+EProPowerupBoard(
+ IN PEPRO_ADAPTER adapter
+ )
+/*++
+
+ Routine Description:
+
+ The 82595 has a "powered down" state which could be why it didn't
+ respond correctly to the ID register probe.
+
+ Try the power up sequence. Return TRUE if the board responds
+ after the sequence, FALSE otherwise.
+
+ Arguments:
+
+ adapter - pointer to our adapter structure
+
+ Return Values:
+
+ TRUE - if the board was found after the power up sequence
+ FALSE - if it was not
+
+--*/
+{
+ UCHAR buf[4];
+ UINT i;
+
+ EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, 0);
+
+ // 32ms
+ //
+ NdisStallExecution(32000);
+
+ // Make sure we're in bank 0
+ //
+ EPRO_SWITCH_BANK_0(adapter);
+
+ for (i = 0; i < 4; i++)
+ {
+ EPRO_RD_PORT_UCHAR(adapter, I82595_ID_REG, &buf[i]);
+ }
+
+ return(EProVerifyRoundRobin(buf));
+}
+
+BOOLEAN
+EProCardReadEthernetAddress(
+ IN PEPRO_ADAPTER adapter
+ )
+{
+ USHORT data;
+
+ // EPRO_DPRINTF_INIT(("EProReadEthernetAddress\n"));
+
+#ifdef EPRO_DUMP_EEPROM
+ // Dump the eeprom...
+ {
+ USHORT i;
+
+ for (i = 0; i < 64; i++)
+ {
+ if ((i % 16) == 0)
+ {
+ DbgPrint("\n");
+ }
+
+ EProEERead(adapter, i, &data);
+ DbgPrint("%x ", data);
+ }
+
+ DbgPrint("\n");
+ }
+#endif
+
+ //
+ // Read the ethernet address out of the card. Also swap endian
+ // as you do it...
+ //
+ EProEERead(adapter, EPRO_ETHERNET_ADDR_H, &data);
+ adapter->PermanentIndividualAddress[4] = (UCHAR)(data >> 8);
+ adapter->PermanentIndividualAddress[5] = (UCHAR)(data & 0x00ff);
+
+ EProEERead(adapter, EPRO_ETHERNET_ADDR_M, &data);
+ adapter->PermanentIndividualAddress[2] = (UCHAR)(data >> 8);
+ adapter->PermanentIndividualAddress[3] = (UCHAR)(data & 0x00ff);
+
+ EProEERead(adapter, EPRO_ETHERNET_ADDR_L, &data);
+ adapter->PermanentIndividualAddress[0] = (UCHAR)(data >> 8);
+ adapter->PermanentIndividualAddress[1] = (UCHAR)(data & 0x00ff);
+
+ EPRO_DPRINTF_INIT(("MAC address read: %x %x %x %x %x %x\n",
+ adapter->PermanentIndividualAddress[0],
+ adapter->PermanentIndividualAddress[1],
+ adapter->PermanentIndividualAddress[2],
+ adapter->PermanentIndividualAddress[3],
+ adapter->PermanentIndividualAddress[4],
+ adapter->PermanentIndividualAddress[5]));
+
+ return(TRUE);
+}
+
+
+BOOLEAN EProSetEthernetAddress(PEPRO_ADAPTER adapter)
+/*++
+
+ Routine Description:
+
+ The EPro's ethernet address is read out of the EEPROM by the driver
+ in EProReadEthernetAddress. It is stored by the driver in the
+ adapter->PermanentIndividualAddress array. This function takes the
+ address stored there (presumably set by ReadEthernetAddress) and
+ configures the board to use that address. It could also be used
+ to software-override the default ethernet address.
+
+ Note that the software does not support multiple IA addresses
+ (multiple non-multicast addresses) although the hardware does.
+
+ Arguments:
+
+ adapter - pointer to our adapter structure
+
+ Return Value:
+
+ TRUE if the operation was successful
+ FALSE if it failed
+
+--*/
+{
+ UCHAR result;
+ UINT i = 0;
+
+// switch to bank2
+ EPRO_SWITCH_BANK_2(adapter);
+
+// write out the ethernet address. Make sure you write to reg 9 last:
+ EPRO_WR_PORT_UCHAR(adapter, I82595_IA_REG_0, adapter->PermanentIndividualAddress[0]);
+ EPRO_WR_PORT_UCHAR(adapter, I82595_IA_REG_1, adapter->PermanentIndividualAddress[1]);
+ EPRO_WR_PORT_UCHAR(adapter, I82595_IA_REG_2, adapter->PermanentIndividualAddress[2]);
+ EPRO_WR_PORT_UCHAR(adapter, I82595_IA_REG_3, adapter->PermanentIndividualAddress[3]);
+ EPRO_WR_PORT_UCHAR(adapter, I82595_IA_REG_4, adapter->PermanentIndividualAddress[4]);
+
+// switch to bank0
+ EPRO_SWITCH_BANK_0(adapter);
+
+ if (!EProWaitForExeDma(adapter)) {
+ return(FALSE);
+ }
+
+// switch to bank2
+ EPRO_SWITCH_BANK_2(adapter);
+
+ EPRO_WR_PORT_UCHAR(adapter, I82595_IA_REG_5, adapter->PermanentIndividualAddress[5]);
+
+ return(TRUE);
+}
+
+BOOLEAN EProAltIOCHRDYTest(PEPRO_ADAPTER adapter)
+/*++
+
+ Routine Description:
+
+ Check the current IOCHRDY timing and see if it is compatible.
+ if not, see if it can be changed and made compatible
+ otherwise fail.
+
+ Arguments:
+
+ adapter - pointer to our adapter structure
+
+ Return Values:
+
+ TRUE if the card can be configured properly to the way the machine
+ machine asserts the IOCHRDY line.
+
+ FALSE if the card could NOT be configured appropriately - the machine
+ is broken and we'll have to use 8-bit mode.
+
+--*/
+{
+ BOOLEAN testPending = TRUE, testResult, firstTime = TRUE;
+ UCHAR result;
+
+ // switch to bank 1
+ EPRO_SWITCH_BANK_1(adapter);
+
+ do
+ {
+ // Enter test mode...
+ EPRO_RD_PORT_UCHAR(adapter, I82595_IOCHRDY_TEST_REG, &result);
+ result |= I82595_IOCHRDY_TEST_FLAG;
+ EPRO_WR_PORT_UCHAR(adapter, I82595_IOCHRDY_TEST_REG, result);
+
+ // Read from 0,1
+ EPRO_RD_PORT_UCHAR(adapter, I82595_CMD_REG, &result);
+
+ EPRO_RD_PORT_UCHAR(adapter, I82595_IOCHRDY_TEST_REG, &result);
+
+ if (result & I82595_IOCHRDY_PASS_FLAG)
+ {
+ testPending = FALSE;
+ testResult = TRUE;
+ }
+ else
+ {
+ // test failed
+ if (firstTime)
+ {
+ // try it again - flip the current IOCHRDY timing and try again.
+ firstTime = FALSE;
+ EPRO_RD_PORT_UCHAR(adapter, I82595_ALT_RDY_REG, &result);
+
+ // toggle alt-rdy bit
+ result = (result & I82595_ALT_RDY_FLAG)?
+ result & (~I82595_ALT_RDY_FLAG) :
+ result | I82595_ALT_RDY_FLAG;
+
+ EPRO_WR_PORT_UCHAR(adapter, I82595_ALT_RDY_REG, result);
+ }
+ else
+ {
+ // nope, failed twice, can't do it.
+ testPending = FALSE;
+ testResult = FALSE;
+ }
+ }
+ } while (testPending);
+
+ // turn the test off
+ EPRO_RD_PORT_UCHAR(adapter, I82595_IOCHRDY_TEST_REG, &result);
+ result &= ~I82595_IOCHRDY_TEST_FLAG;
+ EPRO_WR_PORT_UCHAR(adapter, I82595_IOCHRDY_TEST_REG, result);
+
+ return(testResult);
+}
+
diff --git a/private/ntos/ndis/ieepro/makefile b/private/ntos/ndis/ieepro/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/ieepro/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/ieepro/request.c b/private/ntos/ndis/ieepro/request.c
new file mode 100644
index 000000000..995b8c0f2
--- /dev/null
+++ b/private/ntos/ndis/ieepro/request.c
@@ -0,0 +1,989 @@
+#include <ndis.h>
+#include "82595.h"
+#include "eprohw.h"
+#include "eprosw.h"
+#include "epro.h"
+#include "eprodbg.h"
+
+static UINT EProSupportedOids[] = {
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_RCV_ERROR_ALIGNMENT,
+ OID_802_3_XMIT_ONE_COLLISION,
+ OID_802_3_XMIT_MORE_COLLISIONS
+};
+
+NDIS_STATUS EProQueryInformation(IN NDIS_HANDLE miniportAdapterContext,
+ IN NDIS_OID oid,
+ IN PVOID informationBuffer,
+ IN ULONG informationBufferLength,
+ OUT PULONG bytesWritten,
+ OUT PULONG bytesNeeded)
+/*++
+
+ Routine Description:
+
+ This is the query configuration handler for the EPro
+
+ Arguments:
+
+ miniportAdapterContext - really a pointer to our adapter structure
+
+ oid - the oid we are querying
+
+ informationBuffer - The buffer to copy the queried info into
+
+ informationLength - how much room is there in the buffer
+
+ bytesWritten - the number of bytes we actually wrote into
+ informationBuffer
+
+ bytesNeeded - only valid if we return not enough space error --
+ how much more space do we need to be able to give
+ you that data?
+
+ Return Values:
+
+ NDIS_STATUS_SUCCESS - operation successful
+ NDIS_STATUS_INALID_OID - invalid oid, or we don't support it
+ NDIS_STATUS_INVALID_LENGTH - not enough room in informationbuffer
+ see bytesNeeded for more info
+
+--*/
+{
+ PEPRO_ADAPTER adapter = (PEPRO_ADAPTER)miniportAdapterContext;
+ UINT bytesToMove = 0;
+ PVOID moveSource = NULL;
+// since we can't transfer #define'd constants the way they want us to...
+ ULONG GenericUL;
+ USHORT GenericUS;
+ NDIS_STATUS statusToReturn = NDIS_STATUS_SUCCESS;
+
+ EPRO_DPRINTF_REQ(("EProQueryInformation. Oid = %lx\n", oid));
+
+// the oid's are documented in the DDK. See that for info on all of them
+ switch(oid) {
+ case OID_GEN_SUPPORTED_LIST:
+ EPRO_DPRINTF_REQ((" querying oid: OID_GEN_SUPPORTED_LIST\n"));
+ moveSource = &EProSupportedOids;
+ bytesToMove = sizeof(EProSupportedOids);
+ break;
+ case OID_GEN_HARDWARE_STATUS:
+ EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_HARDWARE_STATUS\n"));
+ moveSource = &adapter->CurrentHardwareStatus;
+ bytesToMove = sizeof(adapter->CurrentHardwareStatus);
+ break;
+ case OID_GEN_MEDIA_SUPPORTED:
+ EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_MEDIA_SUPPORTED\n"));
+ GenericUL = EPRO_GEN_MEDIA_SUPPORTED;
+ moveSource = &GenericUL;
+ bytesToMove = sizeof(GenericUL);
+ break;
+ case OID_GEN_MEDIA_IN_USE:
+ EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_MEDIA_IN_USE\n"));
+ GenericUL = EPRO_GEN_MEDIA_IN_USE;
+ moveSource = &GenericUL;
+ bytesToMove = sizeof(GenericUL);
+ break;
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+ EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_MAXIMUM_LOOKAHEAD\n"));
+ GenericUL = EPRO_GEN_MAXIMUM_LOKAHEAD;
+ moveSource = &GenericUL;
+ bytesToMove = sizeof(GenericUL);
+ break;
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+ EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_MAXIMUM_FRAME_SIZE\n"));
+ GenericUL = EPRO_GEN_MAXIMUM_FRAME_SIZE;
+ moveSource = &GenericUL;
+ bytesToMove = sizeof(GenericUL);
+ break;
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+ EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_MAXIMUM_TOTAL_SIZE\n"));
+ GenericUL = EPRO_GEN_MAXIMUM_TOTAL_SIZE;
+ moveSource = &GenericUL;
+ bytesToMove = sizeof(GenericUL);
+ break;
+ case OID_GEN_MAC_OPTIONS:
+ EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_MAC_OPTIONS\n"));
+ GenericUL = EPRO_GEN_MAC_OPTIONS;
+ moveSource = &GenericUL;
+ bytesToMove = sizeof(GenericUL);
+ break;
+ case OID_GEN_PROTOCOL_OPTIONS:
+ EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_PROTOCOL_OPTIONS\n"));
+ moveSource = NULL;
+ bytesToMove = 0;
+ break;
+ case OID_GEN_LINK_SPEED:
+ EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_LINK_SPEED\n"));
+ GenericUL = EPRO_GEN_LINK_SPEED;
+ moveSource = &GenericUL;
+ bytesToMove = sizeof(GenericUL);
+ break;
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+ EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_TRANSMIT_BUFFER_SPACE\n"));
+ GenericUL = EPRO_GEN_TRANSMIT_BUFFER_SPACE;
+ moveSource = &GenericUL;
+ bytesToMove = sizeof(GenericUL);
+ break;
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+ EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_RECEIVE_BUFFER_SPACE\n"));
+ GenericUL = EPRO_GEN_RECEIVE_BUFFER_SPACE;
+ moveSource = &GenericUL;
+ bytesToMove = sizeof(GenericUL);
+ break;
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+ EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_TRANSMIT_BLOCK_SIZE\n"));
+ GenericUL = EPRO_TX_BUF_SIZE;
+ moveSource = &GenericUL;
+ bytesToMove = sizeof(ULONG);
+ break;
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+ EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_RECEIVE_BOCK_SIZE\n"));
+ GenericUL = EPRO_RX_BUF_SIZE;
+ moveSource = &GenericUL;
+ bytesToMove = sizeof(ULONG);
+ break;
+ case OID_GEN_VENDOR_ID:
+ EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_VENDOR_ID\n"));
+ moveSource = &adapter->vendorID;
+ bytesToMove = sizeof(adapter->vendorID);
+ break;
+ case OID_GEN_VENDOR_DESCRIPTION:
+ EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_VENDOR_DESCRIPTION\n"));
+ moveSource = EPRO_VENDOR_DESC;
+ bytesToMove = sizeof(EPRO_VENDOR_DESC);
+ break;
+ case OID_GEN_DRIVER_VERSION:
+ EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_DRIVER_VERSION\n"));
+ GenericUS = ((USHORT)EPRO_DRIVER_VER_MAJOR << 8) |
+ EPRO_DRIVER_VER_MINOR;
+ moveSource = &GenericUS;
+ bytesToMove = sizeof(GenericUS);
+ break;
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_CURRENT_PACKET_FILTER\n"));
+ moveSource = &adapter->CurrentPacketFilter;
+ bytesToMove = sizeof(adapter->CurrentPacketFilter);
+ break;
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_CURRENT_LOOKAHEAD\n"));
+ GenericUL = adapter->RXLookAheadSize;
+ moveSource = &GenericUL;
+ bytesToMove = sizeof(GenericUL);
+ break;
+ case OID_GEN_XMIT_OK:
+ EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_XMIT_OK\n"));
+ moveSource = &adapter->FramesXmitOK;
+ bytesToMove = sizeof(adapter->FramesXmitOK);
+ break;
+ case OID_GEN_RCV_OK:
+ EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_RCV_OK\n"));
+ moveSource = &adapter->FramesRcvOK;
+ bytesToMove = sizeof(adapter->FramesRcvOK);
+ break;
+ case OID_GEN_XMIT_ERROR:
+ EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_XMIT_ERROR\n"));
+ moveSource = &adapter->FramesXmitErr;
+ bytesToMove = sizeof(adapter->FramesXmitErr);
+ break;
+ case OID_GEN_RCV_ERROR:
+ EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_RCV_ERROR\n"));
+ moveSource = &adapter->FramesRcvErr;
+ bytesToMove = sizeof(adapter->FramesRcvErr);
+ break;
+ case OID_GEN_RCV_NO_BUFFER:
+ EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_RCV_NO_BUFFER\n"));
+ moveSource = &adapter->FramesMissed;
+ bytesToMove = sizeof(adapter->FramesMissed);
+ break;
+ case OID_802_3_PERMANENT_ADDRESS:
+ EPRO_DPRINTF_REQ(("Querying oid - OID_802_3_PERMANENT_ADDRESS\n"));
+ moveSource = &adapter->PermanentIndividualAddress;
+ bytesToMove = sizeof(adapter->PermanentIndividualAddress);
+ break;
+ case OID_802_3_CURRENT_ADDRESS:
+ EPRO_DPRINTF_REQ(("Querying oid - OID_802_3_CURRENT_ADDRESS\n"));
+ moveSource = &adapter->CurrentIndividualAddress;
+ bytesToMove = sizeof(adapter->CurrentIndividualAddress);
+ break;
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+ EPRO_DPRINTF_REQ(("Querying Maximum Multicast List Size....\n"));
+ GenericUL = EPRO_MAX_MULTICAST;
+ moveSource = &GenericUL;
+ bytesToMove = sizeof(GenericUL);
+ break;
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+ EPRO_DPRINTF_REQ(("Querying oid - OID_802_3_RCV_ERROR_ALIGNMENT\n"));
+ moveSource = &adapter->FrameAlignmentErrors;
+ bytesToMove = sizeof(adapter->FrameAlignmentErrors);
+ break;
+ case OID_802_3_XMIT_ONE_COLLISION:
+ EPRO_DPRINTF_REQ(("Querying oid - OID_802_3_XMIT_ONE_COLLISION\n"));
+ moveSource = &adapter->FramesXmitOneCollision;
+ bytesToMove = sizeof(adapter->FramesXmitOneCollision);
+ break;
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+ EPRO_DPRINTF_REQ(("Querying oid - OID_802_3_XMIT_MORE_COLLISION\n"));
+ moveSource = &adapter->FramesXmitManyCollisions;
+ bytesToMove = sizeof(adapter->FramesXmitManyCollisions);
+ break;
+ default:
+ EPRO_DPRINTF_REQ(("Invalid Oid in Query.\n"));
+ EPRO_DPRINTF_REQ(("iq"));
+ statusToReturn = NDIS_STATUS_INVALID_OID;
+ }
+
+ if (statusToReturn == NDIS_STATUS_SUCCESS) {
+ if (bytesToMove > informationBufferLength) {
+ *bytesNeeded = bytesToMove;
+ statusToReturn = NDIS_STATUS_INVALID_LENGTH;
+ EPRO_DPRINTF_REQ(("Invalid Length in Query\n"));
+ } else {
+ NdisMoveMemory(informationBuffer, moveSource, bytesToMove);
+ (*bytesWritten)+=bytesToMove;
+ }
+ }
+
+ EPRO_DPRINTF_REQ(("EProQueryInfo - Done\n"));
+
+ EPRO_DPRINTF_REQ(("returning: 0x%lx\n", statusToReturn));
+ return(statusToReturn);
+}
+
+NDIS_STATUS EProSetInformation(IN NDIS_HANDLE miniportAdapterContext,
+ IN NDIS_OID oid,
+ IN PVOID informationBuffer,
+ IN ULONG informationLength,
+ OUT PULONG bytesRead,
+ OUT PULONG bytesNeeded)
+/*++
+
+ Routine Description:
+
+ This is the MiniportSetInformation Handler for the EPro driver
+
+ Arguments:
+
+ miniportAdapterContext - really a pointer to our adapter structure
+
+ oid - the oid to set
+
+ informationBuffer - the buffer which contains the information we need
+ to carry out the set
+
+ informationLength - the length of the informationBuffer's data
+
+ bytesRead - how many bytes did we actually read out of informationBuffer
+
+ bytesNeeded - if we failed -- how many bytes do we need to complete
+ the call?
+
+ Return Values:
+
+ NDIS_STATUS_SUCCESS - set completed OK
+ NDIS_STATUS_NOT_ACCEPTED - too many MC addresses set
+ NDIS_STATUS_INVALID_DATA - tried to set MC list, buf inf. buffer not
+ an integral multiple of 6 (len of 802_3 address)
+ NDIS_STATUS_PENDING - set PENDED (completed in EProHandleInterrupt)
+ NDIS_STATUS_INVALID_OID - the oid was bad, or we don't support it.
+
+--*/
+{
+ PEPRO_ADAPTER adapter = (PEPRO_ADAPTER)miniportAdapterContext;
+ NDIS_STATUS statusToReturn = NDIS_STATUS_SUCCESS;
+ ULONG genericUL;
+ BOOLEAN fReturn;
+
+ EPRO_DPRINTF_REQ(("EProSetInformation. Oid = %lx\n", oid));
+
+ switch(oid)
+ {
+ case OID_802_3_MULTICAST_LIST:
+ EPRO_DPRINTF_REQ(("setting: OID_802_3_MULTICAST_LIST\n"));
+
+ if (informationLength % EPRO_LENGTH_OF_ADDRESS != 0)
+ {
+ *bytesNeeded = EPRO_LENGTH_OF_ADDRESS;
+ EPRO_DPRINTF_REQ(("INVALID data length...\n"));
+ return(NDIS_STATUS_INVALID_DATA);
+ }
+
+ if ((informationLength / EPRO_LENGTH_OF_ADDRESS) > EPRO_MAX_MULTICAST)
+ {
+ EPRO_DPRINTF_REQ(("Attempted to set too many multicasts....\n"));
+ return(NDIS_STATUS_NOT_ACCEPTED);
+ }
+
+ *bytesRead = informationLength;
+ *bytesNeeded = 0;
+
+ //
+ // If they are trying to clear the multicast list and none
+ // have been set then we are done!
+ //
+ if ((0 == (informationLength / EPRO_LENGTH_OF_ADDRESS)) &&
+ (0 == adapter->NumMCAddresses))
+ {
+ return(NDIS_STATUS_SUCCESS);
+ }
+
+ fReturn = EProChangeMulticastList(
+ adapter,
+ informationLength / EPRO_LENGTH_OF_ADDRESS,
+ informationBuffer);
+ if (adapter->fMulticastEnable)
+ {
+ BOOLEAN fReturnStatus;
+
+ fReturnStatus = EProSetCardMulticastList(
+ adapter,
+ (fReturn) ? EPRO_CLEAR_CARD_MC : EPRO_SET_CARD_MC);
+ if (!fReturnStatus)
+ {
+ statusToReturn = NDIS_STATUS_NOT_ACCEPTED;
+ }
+ else
+ {
+ statusToReturn = NDIS_STATUS_PENDING;
+ }
+ }
+
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ EPRO_DPRINTF_REQ(("setting: OID_GEN_CURRENT_PACKET_FILTER\n"));
+ if (informationLength < 4)
+ {
+ EPRO_DPRINTF_REQ(("INVALID data length...\n"));
+ return(NDIS_STATUS_INVALID_LENGTH);
+ }
+
+ NdisMoveMemory(&genericUL, informationBuffer, sizeof(ULONG));
+
+ *bytesRead = sizeof(ULONG);
+ *bytesNeeded = 0;
+ statusToReturn = EProSetPacketFilter(adapter, genericUL);
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ if (informationLength < 4)
+ {
+ return(NDIS_STATUS_INVALID_LENGTH);
+ }
+
+ EPRO_DPRINTF_REQ(("EPRO: Attempting to set lookahead size\n"));
+
+ NdisMoveMemory(&genericUL, informationBuffer, sizeof(ULONG));
+
+ *bytesRead = sizeof(ULONG);
+ *bytesNeeded = 0;
+
+ if (genericUL <= EPRO_GEN_MAXIMUM_LOKAHEAD)
+ {
+ EPRO_DPRINTF_REQ(("EPRO: Current lookahead is now %d bytes\n", adapter->RXLookAheadSize));
+ adapter->RXLookAheadSize = (USHORT)genericUL;
+ statusToReturn = NDIS_STATUS_SUCCESS;
+ }
+ else
+ {
+ statusToReturn = NDIS_STATUS_FAILURE;
+ }
+ break;
+
+ default:
+ EPRO_DPRINTF_REQ(("Invalid oid in setinformation\n"));
+ EPRO_DPRINTF_REQ(("inv"));
+ statusToReturn = NDIS_STATUS_INVALID_OID;
+ }
+
+ return(statusToReturn);
+}
+
+NDIS_STATUS EProSetPacketFilter(PEPRO_ADAPTER adapter, ULONG newFilter)
+/*++
+
+ Routine Description:
+
+ This routine, invoked from EProSetInformation, is called to do the
+ real work of setting a packet filter.
+
+ Arguments:
+
+ Return Values:
+
+--*/
+{
+ // reg2flags are the flags currently set in the configuration register in
+ // bank2 (bank 2, reg 2). This is used when we twiddle with the bank
+ //
+ UCHAR reg2Flags = 0, result;
+
+ // Do we need to update the CONFIG registers in bank2? (iff broadcast or
+ // promiscuous setting are changed only) If so, then we will need to do
+ // a synchronized call, and also a reset...
+ //
+ BOOLEAN fUpdateConfig = FALSE;
+ ULONG oldFilter;
+
+ NDIS_STATUS Status;
+
+ EPRO_DPRINTF_REQ(("SetPacketFilter: %lx", newFilter));
+
+ //
+ // Validate the new packet filter that was passed in to be set.
+ //
+ if (newFilter & ~(NDIS_PACKET_TYPE_DIRECTED |
+ NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_BROADCAST |
+ //NDIS_PACKET_TYPE_ALL_MULTICAST |
+ NDIS_PACKET_TYPE_MULTICAST))
+ {
+ EPRO_DPRINTF_REQ(("PacketFilter NOT SUPPORTED!\n"));
+ EPRO_DPRINTF_REQ(("Not Supported\n"));
+
+ return(NDIS_STATUS_NOT_SUPPORTED);
+ }
+
+ //
+ // Save the new packet filter.
+ //
+ oldFilter = adapter->CurrentPacketFilter;
+ adapter->CurrentPacketFilter = newFilter;
+
+
+ //
+ // Ooh, here's a good hardware weirdness. If you issue the rcv enable
+ // command to the 82595tx when it is already in receive-enable mode,
+ // it munges the next received packet. no joke. So we always
+ // temporarily disable receives here.
+ //
+ EProReceiveDisable(adapter);
+
+ EPRO_DPRINTF_REQ(("Setting filter...\n"));
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ do
+ {
+ //
+ // Now, if we've modified the PROMISCUOUS or BROADCAST
+ // settings, we have to re-configure the card....
+ //
+ if (((oldFilter & NDIS_PACKET_TYPE_PROMISCUOUS) ^ (newFilter & NDIS_PACKET_TYPE_PROMISCUOUS)) ||
+ ((oldFilter & NDIS_PACKET_TYPE_BROADCAST) ^ (newFilter & NDIS_PACKET_TYPE_BROADCAST)))
+ {
+ //
+ // Are we supposed to set or clear the promiscuous bit?
+ //
+ if (newFilter & NDIS_PACKET_TYPE_PROMISCUOUS)
+ {
+ EPRO_DPRINTF_REQ(("Promiscuous mode set...\n"));
+
+ adapter->fPromiscuousEnable = TRUE;
+ reg2Flags |= I82595_PROMISCUOUS_FLAG;
+ }
+ else
+ {
+ //
+ // Promiscuous mode bit NOT set - do we need to turn it off?
+ //
+ adapter->fPromiscuousEnable = FALSE;
+ }
+
+ //
+ // Are we supposed to set or clear the broadcast bit?
+ //
+ if (newFilter & NDIS_PACKET_TYPE_BROADCAST)
+ {
+ adapter->fBroadcastEnable = TRUE;
+ }
+ else
+ {
+ adapter->fBroadcastEnable = FALSE;
+ reg2Flags |= I82595_NO_BROADCAST_FLAG;
+ }
+
+ //
+ // okay, we're going to have to modify the config, so we better stop
+ // receives to get ready for the reset...
+
+ // Okay, we're going to have to modify the configuration...
+ // So wait for any receives or sends to finish so the card is
+ // idle...
+ //
+ if (!EProWaitForExeDma(adapter))
+ {
+ EPRO_DPRINTF_RX(("FAILURE waiting for exedma....\n"));
+ Status = NDIS_STATUS_NOT_ACCEPTED;
+ break;
+ }
+
+ //
+ // This gets expanded to a Sync (synchronizedwithinterrupt) call --
+ // since it changes banks, it can NOT happen at the same time as the
+ // ISR (which requires bank0)
+ //
+ EProBroadcastPromiscuousChange(adapter, reg2Flags);
+
+ //
+ // Okay, make sure the card is idle again before we enable receives...
+ //
+ if (!EProWaitForExeDma(adapter))
+ {
+ adapter->fHung = TRUE;
+ return(NDIS_STATUS_HARD_ERRORS);
+// EPRO_ASSERT(FALSE);
+ }
+ }
+
+ //
+ // Enable receives.
+ //
+ EProReceiveEnable(adapter);
+
+ //
+ // Has the multicast bit changed?
+ //
+ if ((oldFilter & NDIS_PACKET_TYPE_MULTICAST) ^
+ (newFilter & NDIS_PACKET_TYPE_MULTICAST))
+ {
+ //
+ // Was the bit set or turned off?
+ //
+ if (newFilter & NDIS_PACKET_TYPE_MULTICAST)
+ {
+ adapter->fMulticastEnable = TRUE;
+
+ //
+ // If there are no multicast addresses to set then we are done.
+ //
+ if (0 == adapter->NumMCAddresses)
+ {
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+ }
+
+ //
+ // Set the multicast addresses to the card.
+ //
+ if (!EProSetCardMulticastList(adapter, EPRO_SET_CARD_MC))
+ {
+ EPRO_DPRINTF_REQ(("ERROR setting multicastlist on card\n"));
+ return(NDIS_STATUS_NOT_ACCEPTED);
+ }
+ else
+ {
+ Status = NDIS_STATUS_PENDING;
+ break;
+ }
+ }
+ else
+ {
+ //
+ // If they haven't set the MC bit, we check to see if we think
+ // it is on and turn it off if need be...
+ //
+ adapter->fMulticastEnable = FALSE;
+
+ //
+ // If there are no multicast addresses set on the card
+ // the we are done.
+ //
+ if (0 == adapter->NumMCAddresses)
+ {
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+ }
+
+ //
+ // Clear any multicast addresses that are currently on the
+ // adapter.
+ //
+ if (!EProSetCardMulticastList(adapter, EPRO_CLEAR_CARD_MC))
+ {
+ EPRO_DPRINTF_REQ(("ERROR setting Multicast List on card...\n"));
+
+ Status = NDIS_STATUS_NOT_ACCEPTED;
+ break;
+ }
+ else
+ {
+ Status = NDIS_STATUS_PENDING;
+ break;
+ }
+ }
+ }
+
+
+ } while (FALSE);
+
+
+
+ //
+ // if the filter = 0, then we are leaving with receives disabled
+ //
+ if (0 == newFilter)
+ {
+ //
+ // Make sure that
+ //
+ EProReceiveDisable(adapter);
+ adapter->CurrentPacketFilter = newFilter;
+ return(NDIS_STATUS_SUCCESS);
+ }
+
+ // This is probably a NOTREACHED...
+
+ return(NDIS_STATUS_SUCCESS);
+
+}
+
+BOOLEAN EProSyncBroadcastPromiscuousChange(PVOID context)
+/*++
+
+ Routine Description:
+
+ This routine is called by a macro expansion of the function
+ EProBroadcastPromiscuousChange -- the macro expands that call to
+ a NdisMSynchronizeWithInterrupt call to this function. This function
+ CANNOT BE CALLED DIRECTLY WHERE THERE IS A CHANCE IT CAN RUN CONCURRENTLY
+ WITH EProDisableInterrupts. Very Bad Things will happen if the two run
+ concurrently (only on an MP machine - on a UP machine, the syncwithint
+ call can be avoided - but alas we don't have the luxury of having
+ seperate binaries for each...
+
+ Arguments:
+
+ context - a EPRO_BRDPROM_CONTEXT which is basically just a strucutre
+ holding all the parameters to the EProBroadcastPromiscuousChange
+ macro (adapter structure pointer and reg2flags settings)
+
+ Return Values:
+
+ always TRUE...
+
+--*/
+{
+ PEPRO_ADAPTER adapter = ((PEPRO_BRDPROM_CONTEXT)context)->Adapter;
+ UCHAR reg2flags = ((PEPRO_BRDPROM_CONTEXT)context)->Reg2Flags;
+ UCHAR result;
+
+ EPRO_SWITCH_BANK_2(adapter);
+
+ EPRO_RD_PORT_UCHAR(adapter, I82595_CONFIG2_REG, &result);
+ result &= ~(I82595_PROMISCUOUS_FLAG | I82595_NO_BROADCAST_FLAG);
+ result |= reg2flags;
+ EPRO_WR_PORT_UCHAR(adapter, I82595_CONFIG2_REG, result);
+
+ // according to the docs, the configure is triggered by a write to reg 3, so we just
+ // read and write to it...
+ //
+ EPRO_RD_PORT_UCHAR(adapter, I82595_CONFIG3_REG, &result);
+ EPRO_WR_PORT_UCHAR(adapter, I82595_CONFIG3_REG, result);
+
+ // Probably don't need this (82595 is supposed to default to bank0 after
+ // a reset or sel-reset
+ //
+ EPRO_SWITCH_BANK_0(adapter);
+
+ // need to do a selreset after a config register modification
+ // per 82595 docs...
+ //
+ EProSelReset(adapter);
+
+ EPRO_ASSERT_BANK_0(adapter);
+
+ return(TRUE);
+}
+
+
+BOOLEAN
+EProChangeMulticastList(
+ IN PEPRO_ADAPTER adapter,
+ IN UINT addressCount,
+ IN UCHAR addresses[][EPRO_LENGTH_OF_ADDRESS])
+/*++
+
+ Routine Description:
+
+ This routine changed the multicast list as stored by the driver.
+ IT DOES NOT ACTUALLY MODIFY THE MULTICAST LIST IN THE HARDWARE ---
+ EProSetCardMulticastList does that.
+
+ Arguments:
+
+ adapter - pointer to our adapter structure
+
+ addressCount - how many addresses to set
+
+ addresses[] - the data...
+
+ Return Values:
+
+ NDIS_STATUS_NOT_ACCEPTED - tried to set too many (notreached b/c
+ setpacketfilter checks this too)
+ NDIS_STATUS_SUCCESS - operation completed ok.
+
+--*/
+{
+ UINT i;
+ BOOLEAN fReturn = FALSE;
+
+ EPRO_DPRINTF_REQ(("EProChangeMulticastList. Setting %d addresses...\n",
+ addressCount));
+
+ // now, put the multicast list into the adapter structure...
+ //
+ for (i = 0; i < addressCount; i++)
+ {
+ NdisMoveMemory(
+ &adapter->MCAddress[i],
+ &addresses[i],
+ EPRO_LENGTH_OF_ADDRESS);
+ }
+
+ //
+ // If we just cleared the multicast address list then we need to
+ // return the fact.
+ //
+ if ((adapter->NumMCAddresses != 0) && (0 == addressCount))
+ {
+ fReturn = TRUE;
+ }
+
+ //
+ // Save the new number of multicast addresses.
+ //
+ adapter->NumMCAddresses = addressCount;
+
+ return(fReturn);
+}
+
+
+BOOLEAN EProSetCardMulticastList(PEPRO_ADAPTER adapter, int operation)
+/*++
+
+ Routine Description:
+
+ This is the routine which takes the driver's MC list and copies it down
+ to the card. The MC list must already be set in the driver with
+ EProChangeMulticastList.
+
+ Arguments:
+
+ adapter - pointer to our adapter structure
+
+ operation - see epro.h for the definitions. Basically SET or CLEAR
+ either we are turning off MC or re-entering the list.
+
+ Return Values:
+
+ TRUE - MC list set okay and has been PENDED (completed in EProHandleInterrupt)
+ FALSE - MC list didn't set okay and was not pended
+
+--*/
+{
+ // The header for the MC_SETUP structure
+ EPRO_MC_HEADER mcHead;
+
+ // Setting the MC list uses a transmit buffer.
+ PEPRO_TRANSMIT_BUFFER curTBuf = adapter->CurrentTXBuf;
+
+ // look variable...
+ BOOLEAN fGotBuffer = FALSE;
+
+ USHORT lengthNeeded = I82595_TX_FRM_HDR_SIZE +
+ (adapter->NumMCAddresses * EPRO_LENGTH_OF_ADDRESS) + 2;
+ USHORT timeout = 0;
+
+ EPRO_ASSERT_BANK_0(adapter);
+ EPRO_DPRINTF_REQ(("Setting the MC list on the card...%d\n", operation));
+
+ // Make sure we have a free buffer pointer structure.
+ //
+ if (!curTBuf->fEmpty)
+ {
+ while (!EProCheckTransmitCompletion(adapter, curTBuf))
+ {
+ timeout++;
+
+ if (timeout > EPRO_TX_TIMEOUT)
+ {
+ return(FALSE);
+ }
+
+ NdisStallExecution(1);
+ }
+ }
+
+ // Is there a transmit in progress? If not, then we can just
+ // set the buffer to address zero and go
+ //
+ if (adapter->TXChainStart == NULL)
+ {
+ curTBuf->TXBaseAddr = EPRO_TX_LOWER_LIMIT_SHORT;
+ }
+ else
+ {
+ // Okay, there is a transmit in progress. Let's see if there is enough
+ // transmit buffer space.
+ //
+ USHORT freeSpace = 0;
+
+ // are we above the free space?
+ //
+ if (adapter->TXChainStart->TXBaseAddr < curTBuf->TXBaseAddr)
+ {
+ freeSpace = EPRO_TX_UPPER_LIMIT_SHORT - curTBuf->TXBaseAddr;
+ freeSpace += adapter->TXChainStart->TXBaseAddr -
+ EPRO_TX_LOWER_LIMIT_SHORT;
+ }
+ else
+ {
+ freeSpace = adapter->TXChainStart->TXBaseAddr -
+ curTBuf->TXBaseAddr;
+ }
+
+
+ while (freeSpace < lengthNeeded)
+ {
+ UINT timeout1;
+
+ while (!EProCheckTransmitCompletion(adapter, adapter->TXChainStart))
+ {
+ if (timeout1++ > EPRO_TX_TIMEOUT)
+ {
+ return(FALSE);
+ }
+
+ NdisStallExecution(1);
+ }
+
+ if (adapter->TXChainStart->TXBaseAddr < curTBuf->TXBaseAddr)
+ {
+ freeSpace = EPRO_TX_UPPER_LIMIT_SHORT - curTBuf->TXBaseAddr;
+ freeSpace += adapter->TXChainStart->TXBaseAddr -
+ EPRO_TX_LOWER_LIMIT_SHORT;
+ }
+ else
+ {
+ freeSpace = adapter->TXChainStart->TXBaseAddr -
+ curTBuf->TXBaseAddr;
+ }
+ }
+ }
+
+ //
+ // Okay, now we have to make sure we've got enough space to actually
+ // put the data in the transmit area...
+ //
+
+ // Now we've got a buffer....
+ //
+ EPRO_ASSERT(curTBuf->fEmpty);
+
+ mcHead.CommandField = I82595_CMD_MC_SETUP;
+
+ // Clear the header
+ //
+ NdisZeroMemory(mcHead.NullBytes, 5);
+
+ // Okay, are we setting or clearing? If we're clearing then the byte count
+ // is 0, if we're setting, then its a function of the number of addresses...
+ //
+ if (operation != EPRO_CLEAR_CARD_MC)
+ {
+ mcHead.ByteCountLo = (adapter->NumMCAddresses * EPRO_LENGTH_OF_ADDRESS) & 0xff;
+ mcHead.ByteCountHi = (adapter->NumMCAddresses * EPRO_LENGTH_OF_ADDRESS) >> 8;
+ }
+ else
+ {
+ mcHead.ByteCountLo = 0;
+ mcHead.ByteCountHi = 0;
+ }
+
+ EPRO_DPRINTF_REQ(("There are %d MC addresses.\n", adapter->NumMCAddresses));
+ EPRO_DPRINTF_REQ(("There are %x%x bytes of MC addresses at %lx\n", mcHead.ByteCountHi,
+ mcHead.ByteCountLo, &adapter->MCAddress));
+ EPRO_DPRINTF_REQ(("Sizeof MCHEAD is %x\n", sizeof(mcHead)));
+
+ // bank0
+ //
+ EPRO_ASSERT_BANK_0(adapter);
+
+ EPRO_DPRINTF_REQ(("Address on card is %lx\n", curTBuf->TXBaseAddr));
+ EPRO_SET_HOST_ADDR(adapter, curTBuf->TXBaseAddr);
+ EPRO_COPY_BUFFER_TO_NIC_USHORT(adapter, ((USHORT *)(&mcHead)), sizeof(mcHead) >> 1);
+
+ if (operation != EPRO_CLEAR_CARD_MC)
+ {
+ // since we know the len_of_address is an even #, we make the
+ // assumption here that the amount of memory to copy is divisible
+ // by two (so the shift is safe)
+ //
+ EPRO_COPY_BUFFER_TO_NIC_USHORT(
+ adapter,
+ (USHORT *)(&adapter->MCAddress),
+ (adapter->NumMCAddresses * 3)); // 3 shorts...
+ }
+
+
+ // okay, set up to and pend this thing....
+
+ if (!EProWaitForExeDma(adapter))
+ {
+ // we're in trouble if this happens...
+ //
+ adapter->fHung = TRUE;
+ return(FALSE);
+// EPRO_ASSERT(FALSE);
+ }
+
+ adapter->IntPending = EPRO_INT_MC_SET_PENDING;
+ adapter->IntContext = (PVOID)curTBuf;
+
+ // enable EXE interrupts so we can do this asynchronously...
+ //
+ EProSetInterruptMask(adapter, EPRO_RX_TX_EXE_INTERRUPTS);
+
+ // set the BAR and go....
+ //
+ EPRO_WR_PORT_USHORT(adapter, I82595_TX_BAR_REG, curTBuf->TXBaseAddr);
+ EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_CMD_MC_SETUP);
+
+ // Move the currenttxbuf pointer forward...
+ //
+ adapter->CurrentTXBuf = curTBuf->NextBuf;
+
+ return(TRUE);
+}
+
+
diff --git a/private/ntos/ndis/ieepro/sndrcv.c b/private/ntos/ndis/ieepro/sndrcv.c
new file mode 100644
index 000000000..a32d4098c
--- /dev/null
+++ b/private/ntos/ndis/ieepro/sndrcv.c
@@ -0,0 +1,1178 @@
+#include <ndis.h>
+#include "82595.h"
+#include "eprohw.h"
+#include "eprosw.h"
+#include "epro.h"
+#include "eprodbg.h"
+
+//////////////////////////////////////////////////////////////////////
+// SEND code
+//////////////////////////////////////////////////////////////////////
+
+ULONG numberOfResources = 0;
+
+NDIS_STATUS EProSend(IN NDIS_HANDLE miniportAdapterContext,
+ IN PNDIS_PACKET packet,
+ IN UINT flags)
+/*++
+Routine Description:
+
+ The MiniportSend handler for the EPro. About 18 million different
+ things happen here:
+
+ 1) We need to see if there are free transmit buffer pointer for
+ this packet.
+ 2) Once we've got a tx buffer pointer, we then see if we have enough
+ physical memory space for this transmit. If we don't, then
+ we resources out
+ 3) We need to copy the 82595 frame header, then the packet to the card
+ 4) We need to start the transmit if none are in progress
+ 5) We need to update some structures to keep track of the transmit
+
+Arguments:
+ miniportAdapterContext - Really a pointer to our EPRO_ADAPTER structure
+
+ packet - the packet to send
+
+ flags - an optional FLAGS field - not used currently in NDIS
+
+Return Value:
+
+ NDIS_STATUS_RESOURCES - no free transmit buffers. Please hang up and then
+ dial again. If you need help, please dial your operator
+ NDIS_STATUS_PENDING - The packet is on the card and is being sent.
+
+--*/
+
+{
+ PEPRO_ADAPTER adapter = (EPRO_ADAPTER *)miniportAdapterContext;
+// This is the adapter's current transmit buffer...
+ PEPRO_TRANSMIT_BUFFER curTBuf = adapter->CurrentTXBuf;
+ USHORT freeSpace;
+ UINT totalPacketLength;
+ USHORT result;
+
+// If we're currently executing an MC_SETUP command, we can't
+// handle any transmits. The reason is that the MC_SETUP uses
+// a transmit buffer, and we will have problems trying to complete
+// transfers if we do both at the same time. There are a few ways
+// we could get around this, but they'd make things more complicated,
+// and don't gain us much if we go by the assumption that in "normal"
+// use we won't get that many MC-setups...
+ if (adapter->IntPending == EPRO_INT_MC_SET_PENDING) {
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+// Check for free buffer. If can't find one, then return
+// NDIS_STATUS_RESOURCES.
+// is the current buffer free?
+ if (!curTBuf->fEmpty) {
+// nope. can we free it?
+ if (!EProCheckTransmitCompletion(adapter, curTBuf)) {
+ numberOfResources++;
+ return(NDIS_STATUS_RESOURCES);
+ }
+ }
+
+// Get the total length of this packet so we can see if we have
+// room for it.
+ NdisQueryPacket(packet, NULL, NULL, NULL, &totalPacketLength);
+
+ curTBuf->TXSize = totalPacketLength;
+
+// Add in the 82595's tx memory structure plus 2 bytes padding
+// between frames
+ totalPacketLength+=(I82595_TX_FRM_HDR_SIZE + 2);
+
+// is there a transmit in progress?
+ if (adapter->TXChainStart == NULL) {
+ curTBuf->TXBaseAddr = EPRO_TX_LOWER_LIMIT_SHORT;
+ curTBuf->NextBuf->TXBaseAddr = totalPacketLength;
+ } else {
+// Do we have free space for this packet?
+ EPRO_ASSERT(adapter->TXChainStart != curTBuf);
+ EPRO_ASSERT(curTBuf->TXBaseAddr >= EPRO_TX_LOWER_LIMIT_SHORT);
+
+// Although TxBaseAddr == upper limit is NOT LEGAL, we allow it in
+// this assert because it will fall through the next if statement
+// and be dealt with properly. (freespace will = 0 and then we will wrap)
+ EPRO_ASSERT(curTBuf->TXBaseAddr <= EPRO_TX_UPPER_LIMIT_SHORT);
+
+// Now we need to know if the current buffer position is above or
+// below the space in use.
+ if (adapter->TXChainStart->TXBaseAddr >= curTBuf->TXBaseAddr) {
+// We're BELOW the in-use space
+ freeSpace = adapter->TXChainStart->TXBaseAddr -
+ curTBuf->TXBaseAddr;
+ } else {
+ freeSpace = EPRO_TX_UPPER_LIMIT_SHORT -
+ curTBuf->TXBaseAddr;
+ freeSpace += (adapter->TXChainStart->TXBaseAddr -
+ EPRO_TX_LOWER_LIMIT_SHORT);
+ }
+
+ if (freeSpace < totalPacketLength) {
+ return(NDIS_STATUS_RESOURCES);
+ }
+ }
+
+// Now, the set the next buffer's address:
+ curTBuf->NextBuf->TXBaseAddr = curTBuf->TXBaseAddr +
+ totalPacketLength;
+
+ if (curTBuf->NextBuf->TXBaseAddr >= EPRO_TX_UPPER_LIMIT_SHORT)
+ curTBuf->NextBuf->TXBaseAddr -= EPRO_TX_UPPER_LIMIT_SHORT;
+
+// Okay, when we've gotten to this point, it's because we've determined
+// that there is enough space on the card for the packet. So, now we
+// set the current transmit buffer to be empty.
+ curTBuf->fEmpty = FALSE;
+// move the current buffer pointer forward
+ adapter->CurrentTXBuf = curTBuf->NextBuf;
+
+// bank 0
+ EPRO_ASSERT_BANK_0(adapter);
+
+// set our packet pointer so we can ethindicatereceive later.
+ curTBuf->TXPacket = packet;
+
+// This is a double-check that the txbuffer structure was freed
+// correctly -- this is set in checktransmitcompletion
+ EPRO_ASSERT(curTBuf->TXSendAddr == 0xffff);
+
+// We make a backup copy of the TXBaseAddr, in case we use up all
+// of our buffer pointer strucutres and wrap around and overwrite the
+// TXBaseAddr of this buffer....
+ curTBuf->TXSendAddr = curTBuf->TXBaseAddr;
+
+// Set the address on the card to copy to
+ EPRO_SET_HOST_ADDR(adapter, curTBuf->TXBaseAddr);
+ EProCopyPacketToCard(adapter, packet);
+
+// Is there a transmit already going?
+ if (!adapter->TXChainStart) {
+// Nope - queue this one up and let it rip..
+ {
+ UINT i;
+ UCHAR result;
+
+ for (i=0;i<I82595_SPIN_TIMEOUT;i++) {
+ EPRO_RD_PORT_UCHAR(adapter, I82595_STATUS_REG, &result);
+ if (!(result &I82595_EXEC_STATE)) {
+ if (result & I82595_EXEC_INT_RCVD) {
+ EPRO_WR_PORT_UCHAR(adapter, I82595_STATUS_REG,
+ I82595_EXEC_INT_RCVD);
+ }
+ break;
+ }
+ }
+ }
+
+ // Set up and start the transmit
+ EPRO_WR_PORT_USHORT(adapter, I82595_TX_BAR_REG, curTBuf->TXBaseAddr);
+ EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_XMT);
+
+ adapter->TXChainStart = curTBuf;
+ } else {
+// If chainstart != NULL (ie is pointing to a buffer) and there is no tx
+// in progress - we're hosed....
+// if (curTBuf->LastBuf->TXSendAddr + 4 >= EPRO_TX_UPPER_LIMIT_SHORT) {
+// EPRO_SET_HOST_ADDR(adapter, ((curTBuf->LastBuf->TXSendAddr + 4) -
+// EPRO_TX_UPPER_LIMIT_SHORT));
+// } else {
+// EPRO_SET_HOST_ADDR(adapter, (curTBuf->LastBuf->TXSendAddr + 4));
+// }
+// EPRO_WR_PORT_USHORT(adapter, I82595_MEM_IO_REG,
+// curTBuf->TXSendAddr);
+// EPRO_WR_PORT_USHORT(adapter, I82595_MEM_IO_REG,
+// curTBuf->LastBuf->TXSize | 8000);
+//
+// EPRO_RD_PORT_USHORT(adapter, I82595_MEM_IO_REG, &result);
+//
+// EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_XMT_RESUME);
+ }
+
+// okay, we're PENDING...
+ return(NDIS_STATUS_PENDING);
+}
+
+
+
+VOID EProCopyPacketToCard(PEPRO_ADAPTER adapter,
+ PNDIS_PACKET packet)
+/*++
+
+Routine Description:
+
+ This routine copies a packet down to the card. We assume the card's IO port
+ has been set to the correct address at function entry.
+
+Parameters:
+
+ adapter - Pointer to our EPRO_ADAPTER structure
+
+ packet - pointer to the NDIS_PACKET we are copying down.
+
+Return Values:
+
+ none
+
+--*/
+{
+// frame header....
+ EPRO_TX_FRAME_HEADER txFrameHeader;
+// This is a hack to transfer buffers of odd lengths
+ BOOLEAN fForward = FALSE;
+// this is the
+ USHORT forwardedShort;
+// The physical address of the buffer to copy out of...
+ PVOID bufferAddr;
+// packet information
+ UINT bufferCount, totalPacketLength, bufferLen, currentOffset;
+// This is the current buffer of the packet that is passed in...
+ PNDIS_BUFFER curBuffer;
+
+// Get the first buffer out of the packet.
+ NdisQueryPacket(packet, NULL, &bufferCount,
+ &curBuffer, &totalPacketLength);
+
+// Copy the TX header down to the card.
+ EPRO_WR_PORT_USHORT(adapter, I82595_MEM_IO_REG, I82595_XMT_SHORT);
+ EPRO_WR_PORT_USHORT(adapter, I82595_MEM_IO_REG, 0);
+ EPRO_WR_PORT_USHORT(adapter, I82595_MEM_IO_REG, 0);
+ EPRO_WR_PORT_USHORT(adapter, I82595_MEM_IO_REG, totalPacketLength);
+
+/////////////////////////////////////////////////////
+// LOOP on all the buffers in the packet...
+/////////////////////////////////////////////////////
+ do {
+ NdisQueryBuffer(curBuffer, &bufferAddr, &bufferLen);
+
+// skip over zero-length buffers.
+ if (bufferLen == 0) {
+ NdisGetNextBuffer(curBuffer, &curBuffer);
+ continue;
+ }
+
+// BEGIN fix for odd-length buffers
+ if (fForward) {
+ fForward = FALSE;
+ forwardedShort |= ((*((UCHAR *)bufferAddr)) << 8);
+ ((UCHAR *)bufferAddr)++;
+ bufferLen--;
+ EPRO_WR_PORT_USHORT(adapter, I82595_MEM_IO_REG, forwardedShort);
+ }
+
+ if (bufferLen & 1) {
+ fForward = TRUE;
+ forwardedShort =*(UCHAR *)( ((UCHAR *)bufferAddr) + (bufferLen-1) );
+ }
+// END fix for odd-length buffers...
+
+#ifndef EPRO_USE_32_BIT_IO
+ EPRO_COPY_BUFFER_TO_NIC_USHORT(adapter,
+ ((UNALIGNED USHORT *)bufferAddr),
+ ((ULONG)bufferLen>>1));
+#else
+// using 32-bit
+ if (adapter->EProUse32BitIO) {
+ if (bufferLen & 2) {
+ EPRO_WR_PORT_USHORT(adapter, I82595_MEM_IO_REG,
+ *((UNALIGNED USHORT *)bufferAddr));
+ (UCHAR *)bufferAddr += 2;
+ EPRO_COPY_BUFFER_TO_NIC_ULONG(adapter, ((UNALIGNED ULONG *)bufferAddr),
+ ((ULONG)bufferLen >> 2));
+ } else {
+ EPRO_COPY_BUFFER_TO_NIC_ULONG(adapter, ((UNALIGNED ULONG *)bufferAddr),
+ ((ULONG)bufferLen >> 2));
+ }
+ } else {
+// This is an older version of the 82595 - we need to use 16-bit anyway
+ EPRO_COPY_BUFFER_TO_NIC_USHORT(adapter,
+ (USHORT *)bufferAddr,
+ ((ULONG)bufferLen>>1));
+ }
+#endif
+
+ NdisGetNextBuffer(curBuffer, &curBuffer);
+
+ } while (curBuffer);
+////////////////////////////////////////////////////////
+// END of loop for all buffers in packet
+////////////////////////////////////////////////////////
+
+// copy down a trailing byte
+ if (fForward) {
+ EPRO_WR_PORT_USHORT(adapter, I82595_MEM_IO_REG, forwardedShort);
+ }
+}
+
+
+
+
+BOOLEAN EProCheckTransmitCompletion(PEPRO_ADAPTER adapter,
+ PEPRO_TRANSMIT_BUFFER txBuf)
+/*++
+Routine Description:
+
+ This routine takes the transmit buffer pointed to by txBuf and tries to
+ free it. This can be called from two places. On an adapter that is very
+ very busy transmitting, it can get called from our send handler if the send
+ handler is called and all the transmit buffers on the card are full. This
+ routine is called directly from the send handler to minimize the latency of
+ the returning NDIS_STATUS_RESOURCES----free buffer in interrupt handler dpc---
+ ---ndis calls back down in it's send handler. There is the possibility here
+ that packets will be sent out of order in this, but it doesn't matter, let the
+ protocols figure that out.
+
+ This routine is also called by our handleinterrupt handler where it does the
+ exact same thing, except in response to a transmit interrupt.
+
+Arguments:
+
+ adapter - a pointer to our EPRO_ADAPTER structure
+
+ txBuf - this is a pointer to the transmit buffer we are checking
+
+Return Value:
+
+ TRUE if the buffer is already free or has been indicated and now is free.
+ FALSE if the buffer is not finished being transmitted.
+
+--*/
+{
+ UCHAR result;
+ USHORT status;
+// NDIS_STATUS returnStatus = NDIS_STATUS_FAILURE;
+
+ if (!txBuf) {
+ return(FALSE);
+ }
+
+ if (txBuf->fEmpty) {
+ return(TRUE);
+ }
+
+// if we got through the first if, then there must be a non-empty
+// buffer. Therefore, we have to assume that there is a transmit in
+// progress (txchainstart is set to the tx in progress) - if there
+// is not one in progress, then something is screwed.
+ EPRO_ASSERT(adapter->TXChainStart != NULL);
+
+// bank0
+ EPRO_ASSERT_BANK_0(adapter);
+
+// Check and see if this transmit has completed...
+ EPRO_SET_HOST_ADDR(adapter, txBuf->TXSendAddr);
+
+// check DN (tx done) flag...
+ EPRO_RD_PORT_USHORT(adapter, I82595_MEM_IO_REG, &status);
+
+// See if the TX_DONE bit is set...
+ if (!(status & I82595_TX_DN_BYTE_MASK)) {
+ return(FALSE);
+ }
+
+// Check the status of the transmition
+ EPRO_RD_PORT_USHORT(adapter, I82595_MEM_IO_REG, &status);
+
+ if (status & I82595_TX_OK_SHORT_MASK) {
+// returnStatus = NDIS_STATUS_SUCCESS;
+ adapter->FramesXmitOK++;
+ if ((status & I82595_NO_COLLISIONS_MASK) > 0) {
+ adapter->FramesXmitOneCollision++;
+ if ((status & I82595_NO_COLLISIONS_MASK) > 1) {
+ adapter->FramesXmitManyCollisions++;
+ }
+ }
+ } else {
+ adapter->FramesXmitErr++;
+
+// D---it, the frame errored out...
+// Just re-send it.
+ EPRO_SET_HOST_ADDR(adapter, adapter->TXChainStart->TXSendAddr);
+
+ EPRO_WR_PORT_USHORT(adapter, I82595_MEM_IO_REG, I82595_XMT);
+ EPRO_WR_PORT_USHORT(adapter, I82595_MEM_IO_REG, 0);
+
+ if (!EProWaitForExeDma(adapter)) {
+ adapter->fHung = TRUE;
+// EPRO_ASSERT(FALSE);
+ }
+
+ EPRO_WR_PORT_USHORT(adapter, I82595_TX_BAR_REG,
+ adapter->TXChainStart->TXSendAddr);
+
+ EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_XMT);
+
+ return(FALSE);
+ }
+
+// move the chain forward b/c this buffer has been freed....
+#if DBG
+ adapter->TXChainStart->TXSendAddr = 0xffff;
+#endif
+ adapter->TXChainStart = adapter->TXChainStart->NextBuf;
+
+ if (adapter->TXChainStart == adapter->CurrentTXBuf) {
+// since we just moved the chain FORWARD one, if these
+// two pointers are equal it means the buffer is EMPTY, not full...
+ adapter->TXChainStart = NULL;
+ } else {
+
+// Make sure the card is idle
+// EProWaitForExeDma(adapter);
+ {
+ UINT i;
+
+ for (i=0;i<I82595_SPIN_TIMEOUT;i++) {
+ EPRO_RD_PORT_UCHAR(adapter, I82595_STATUS_REG, &result);
+ if (!(result &I82595_EXEC_STATE)) {
+ if (result & I82595_EXEC_INT_RCVD) {
+ EPRO_WR_PORT_UCHAR(adapter, I82595_STATUS_REG,
+ I82595_EXEC_INT_RCVD);
+ }
+ break;
+ }
+ }
+ }
+
+// Get the next TX going....
+ EPRO_WR_PORT_USHORT(adapter, I82595_TX_BAR_REG,
+ adapter->TXChainStart->TXSendAddr);
+
+ EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_XMT);
+ }
+
+// this buffer is empty now.
+ txBuf->fEmpty = TRUE;
+
+// Yes, here's the deep and dark secret: either we succeed a packet,
+// or we re-send it, so whenever packets complete, they ALWAYS
+// succeed :)
+ NdisMSendComplete(adapter->MiniportAdapterHandle,
+ txBuf->TXPacket, NDIS_STATUS_SUCCESS);
+
+ return(TRUE);
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////
+// RECEIVE code...
+//////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////
+
+
+
+UINT EProHandleReceive(PEPRO_ADAPTER adapter)
+/*++
+Routine Description:
+
+ This is the dpc-level code that really handles a receive interrupt.
+
+Arguments:
+
+ adapter - pointer to the adapter structure.
+
+Return Value:
+
+ the number of packets received
+
+--*/
+{
+ // The 82595s RCV header
+ EPRO_RCV_HEADER header;
+
+ // the Ethernet header to indicate up
+ EPRO_ETH_HEADER ethHeader;
+
+ // temp variable to figure out how much to copy up
+ USHORT bytesToCopy;
+
+ // Our context to pass in NdisMEthIndicateReceive...
+ EPRO_RCV_CONTEXT context;
+
+ // Use this to loop and handle multiple receives in one int...
+ //
+ UCHAR tempCopy;
+ UINT numRcvd = 0;
+
+ // bank0
+ // EPRO_SWITCH_BANK_0(adapter);
+ //
+ EPRO_ASSERT_BANK_0(adapter);
+
+ if ((adapter->RXCurrentAddress < EPRO_RX_LOWER_LIMIT_SHORT) ||
+ (adapter->RXCurrentAddress > EPRO_RX_UPPER_LIMIT_SHORT))
+ {
+ adapter->fHung = TRUE;
+#if DBG
+ DbgPrint("the RxCurrentAddress is not within acceptable limits: 0x%x\n", adapter->RXCurrentAddress);
+// EPRO_ASSERT(FALSE);
+#endif
+
+ return(0);
+ }
+
+ // Read the header...
+ EPRO_SET_HOST_ADDR(adapter, adapter->RXCurrentAddress);
+
+ EPRO_READ_BUFFER_FROM_NIC_USHORT(
+ adapter,
+ (USHORT *)&header,
+ ((ULONG)sizeof(EPRO_RCV_HEADER) >> 1));
+
+ // Process one or more received frames...
+ while ((header.Event == I82595_RX_EOF) && !adapter->fHung)
+ {
+ // Was the transmit OK?
+ if (!header.Status1 & I82595_RX_OK)
+ {
+ adapter->FramesRcvErr++;
+ // Since we configure the 82595 to discard bad frames, we know we've reached the
+ // latest received frame when we hit a bad one -- since the card will "reclaim"
+ // the space filled by the bad frame as soon as it gets another one.
+ break;
+ }
+ else
+ {
+ numRcvd++;
+
+ // Fill in our receive context - to be passed in to TransferData
+ context.RXFrameSize = (USHORT)((USHORT)header.ByteCountLo) | (((USHORT)header.ByteCountHi) << 8);
+
+ // Figure out how many bytes to indicate up. Either the size of the current lookahead
+ // or the entire frame - whichever is smaller.
+ bytesToCopy = ((context.RXFrameSize-sizeof(EPRO_ETH_HEADER)) > adapter->RXLookAheadSize) ?
+ adapter->RXLookAheadSize :
+ (context.RXFrameSize - sizeof(EPRO_ETH_HEADER));
+
+ EPRO_READ_BUFFER_FROM_NIC_USHORT(
+ adapter,
+ (USHORT *)(&ethHeader),
+ sizeof(EPRO_ETH_HEADER) >> 1);
+
+#ifndef EPRO_USE_32_BIT_IO
+ EPRO_READ_BUFFER_FROM_NIC_USHORT(adapter, &adapter->RXLookAhead, bytesToCopy >> 1);
+#else
+ if (adapter->EProUse32BitIO)
+ {
+ if (bytesToCopy & 2)
+ {
+ EPRO_RD_PORT_USHORT(
+ adapter,
+ I82595_MEM_IO_REG,
+ (UNALIGNED USHORT *)(&adapter->RXLookAhead));
+
+ EPRO_READ_BUFFER_FROM_NIC_ULONG(
+ adapter,
+ (UNALIGNED ULONG *)(((UCHAR *)&(adapter->RXLookAhead)) + 2),
+ bytesToCopy >> 2);
+ }
+ else
+ {
+ EPRO_READ_BUFFER_FROM_NIC_ULONG(
+ adapter,
+ (UNALIGNED ULONG *)(&(adapter->RXLookAhead)),
+ bytesToCopy >> 2);
+ }
+ }
+ else
+ {
+ // This is an old version of the 82595 - we have to use 16-bit IO
+ EPRO_READ_BUFFER_FROM_NIC_USHORT(
+ adapter,
+ (USHORT *)&adapter->RXLookAhead,
+ bytesToCopy>>1);
+ }
+#endif
+
+ if (bytesToCopy & 1)
+ {
+ // just read the low-order byte here....
+ EPRO_RD_PORT_UCHAR(adapter, I82595_MEM_IO_REG, &tempCopy);
+
+ adapter->RXLookAhead[bytesToCopy-1] = tempCopy;
+ }
+
+ context.RXCurrentAddress = adapter->RXCurrentAddress;
+ context.LookAheadSize = bytesToCopy;
+
+ // indicate packet
+ NdisMEthIndicateReceive(adapter->MiniportAdapterHandle,
+ (NDIS_HANDLE)&context,
+ (PCHAR)&ethHeader,
+ sizeof(EPRO_ETH_HEADER),
+ &adapter->RXLookAhead,
+ bytesToCopy,
+ context.RXFrameSize - sizeof(EPRO_ETH_HEADER));
+
+ // verify bank0
+ EPRO_ASSERT_BANK_0(adapter);
+ }
+
+{
+ USHORT temp = (USHORT)header.NextFrmLo | (((USHORT)header.NextFrmHi) << 8);
+
+ if ((temp < EPRO_RX_LOWER_LIMIT_SHORT) ||
+ (temp > EPRO_RX_UPPER_LIMIT_SHORT))
+ {
+ adapter->fHung = TRUE;
+#if DBG
+ DbgPrint("The receive header has an invalid next frame pointer!\n");
+ DbgPrint("current rx: %lx, rx: %lx, hi: %x, lo: %x hdr: %lx\n",
+ adapter->RXCurrentAddress,
+ temp,
+ header.NextFrmHi,
+ header.NextFrmLo,
+ &header);
+
+// EPRO_ASSERT(FALSE);
+#endif
+
+ break;
+ }
+}
+
+ adapter->RXCurrentAddress = (USHORT)header.NextFrmLo | (((USHORT)header.NextFrmHi) << 8);
+
+ // Seek to the next frame
+ EPRO_SET_HOST_ADDR(adapter, adapter->RXCurrentAddress);
+
+ // Read the header...
+ EPRO_READ_BUFFER_FROM_NIC_USHORT(
+ adapter,
+ (USHORT *)(&header),
+ sizeof(EPRO_RCV_HEADER) >> 1);
+ }
+
+ // now, update the stop reg to = the bottom of the received frame....
+ if (numRcvd > 0)
+ {
+ USHORT value;
+
+ value = context.RXCurrentAddress + context.RXFrameSize;
+
+ // wrap around...
+ if (value >= EPRO_RX_UPPER_LIMIT_SHORT)
+ {
+ value -= (EPRO_RX_UPPER_LIMIT_SHORT - EPRO_RX_LOWER_LIMIT_SHORT);
+ }
+
+ if (!((value <= EPRO_RX_UPPER_LIMIT_SHORT) &&
+ (value >= EPRO_RX_LOWER_LIMIT_SHORT)))
+ {
+ adapter->fHung = TRUE;
+#if DBG
+ DbgPrint("ca: %lx, fs: %lx, val: %lx",
+ context.RXCurrentAddress,
+ context.RXFrameSize,
+ value);
+// EPRO_ASSERT(FALSE);
+#endif
+ }
+
+ EPRO_WR_PORT_USHORT(adapter, I82595_RX_STOP_REG, value);
+ }
+
+ adapter->FramesRcvOK += numRcvd;
+
+ return(numRcvd);
+}
+
+#if 0
+// You know. This code PASSES all the stress tests. Passes everything the
+// tester can throw out, but still is broken when I try to make it work
+// in real life. <sigh>. Look at this later.
+
+NDIS_STATUS EProTransferData(OUT PNDIS_PACKET packet,
+ OUT PUINT bytesTransferred,
+ IN NDIS_HANDLE miniportAdapterContext,
+ IN NDIS_HANDLE miniportReceivedContext,
+ IN UINT byteOffset,
+ IN UINT bytesToTransfer)
+/*++
+
+Routine Description:
+
+ The transferdata handler for the EPro.
+
+Arguments:
+
+ packet - The packet to transfer the data into
+
+ bytesTransferred - The number of bytes actually copied into packet.
+
+ miniportAdapterContext - Reallly a pointer to our EPRO_ADAPTER structure
+
+ miniportReceivedContext - This is our EPRO_RCV_CONTEXT, which basically just
+ has the packet length and pointer to where it lies
+ in the card's address space.
+
+ byteOffset - where in the frame to begin trasferring from
+
+ bytesToTransfer - how many bytes to transfer.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS - data transfered OK
+ NDIS_STATUS_FAILURE - tried to transfer off end of frame
+
+--*/
+{
+ PEPRO_ADAPTER adapter = (PEPRO_ADAPTER)miniportAdapterContext;
+// The 82595's on-card RCV memory structure
+ EPRO_RCV_HEADER header;
+// An 802.3 ethernet header.
+ EPRO_ETH_HEADER ethHeader;
+// How many bytes have we copied, how many are left to copy
+ USHORT byteCount, bytesToCopy;
+ PEPRO_RCV_CONTEXT pcontext = (PEPRO_RCV_CONTEXT)miniportReceivedContext;
+// The current buffer we are copying into.
+ PNDIS_BUFFER curDestBuf;
+// The physical address of the buffer we are currently copying into
+ PVOID curDestBufAddr;
+// The length of that buffer
+ UINT curDestBufLen;
+// Two bytes used when we have to transfer in to odd-length buffers (since
+// accesses to the EPro's memory are only by-word.
+ UCHAR tempCopy[2];
+// This is TRUE if we are "forwarding" a single byte from an odd-length transfer
+ BOOLEAN fForward = FALSE;
+// the address to read from on the card
+ USHORT cardAddress;
+ UINT bytesWriteThisPacket;
+
+// TODO - copy first lookahead size bytes out of lookahead buffer.
+
+ *bytesTransferred = 0;
+
+// switch to bank0 for mem io
+ EPRO_ASSERT_BANK_0(adapter);
+
+// Make sure they're not seeking past the end of the frame
+ if (byteOffset > pcontext->RXFrameSize) {
+ return(NDIS_STATUS_FAILURE);
+ }
+
+// get the first buffer
+ NdisQueryPacket(packet, NULL, NULL, &curDestBuf, NULL);
+
+// copy the amount requested, or the entire packet - whichever is smaller
+ if ((bytesToTransfer + byteOffset) <= pcontext->RXFrameSize) {
+ bytesToCopy = bytesToTransfer;
+ } else {
+ bytesToCopy = (pcontext->RXFrameSize - byteOffset);
+ }
+
+// first loop -- copy up to the end of the lookahead buffer's worth:
+ if (byteOffset < adapter->RXLookAheadSize) {
+ UINT laOffset = byteOffset;
+ UINT laToCopy = adapter->RXLookAheadSize - laOffset;
+
+ if (laToCopy > bytesToCopy) {
+ laToCopy = bytesToCopy;
+ }
+
+ *bytesTransferred+=laToCopy;
+ bytesToCopy-=laToCopy;
+
+ while (laToCopy > 0) {
+ NdisQueryBuffer(curDestBuf, &curDestBufAddr, &curDestBufLen);
+
+ if (curDestBufLen == 0) {
+ continue;
+ }
+
+ // We either write the entire buffer size bytes or the number of bytes
+ // remaining to copy - whichever is smaller.
+ bytesWriteThisPacket = (laToCopy > curDestBufLen) ?
+ curDestBufLen : laToCopy;
+
+ EPRO_ASSERT(bytesWriteThisPacket <= laToCopy);
+
+ NdisMoveMemory(curDestBufAddr, &adapter->RXLookAhead[laOffset],
+ bytesWriteThisPacket);
+
+ laToCopy-=bytesWriteThisPacket;
+ laOffset+=bytesWriteThisPacket;
+ }
+
+ byteOffset = adapter->RXLookAheadSize;
+
+ EPRO_ASSERT(bytesToCopy >= laToCopy);
+
+ if (bytesToCopy == 0) {
+ EProLogStr(" 1BytesTo:");
+ EProLogLong(bytesToTransfer);
+ EProLogStr("BytesTransf:");
+ EProLogLong(*bytesTransferred);
+ return(NDIS_STATUS_SUCCESS);
+ }
+
+ if (curDestBufLen > bytesWriteThisPacket) {
+ (UCHAR *)curDestBufAddr += bytesWriteThisPacket;
+ } else {
+ curDestBufLen = 0;
+ while (curDestBufLen == 0) {
+ NdisGetNextBuffer(curDestBuf, &curDestBuf);
+ if (!curDestBuf) {
+ EProLogStr(" 2BytesTo:");
+ EProLogLong(bytesToTransfer);
+ EProLogStr("BytesTransf:");
+ EProLogLong(*bytesTransferred);
+ return(NDIS_STATUS_SUCCESS);
+ }
+ NdisQueryBuffer(curDestBuf, &curDestBufAddr, &curDestBufLen);
+ }
+ }
+ } else {
+ NdisQueryBuffer(curDestBuf, &curDestBufAddr, &curDestBufLen);
+ }
+
+// set our memory address on the card...
+ cardAddress = (pcontext->RXCurrentAddress + sizeof(EPRO_RCV_HEADER) +
+ sizeof(EPRO_ETH_HEADER) + byteOffset);
+
+// Set the address on the card. Note that you can do sequential reads
+// from the IO port which WRAP around the memory boundry, but if you
+// manually set the address, you have to wrap manually.
+ if (cardAddress >= EPRO_RX_UPPER_LIMIT_SHORT) {
+ cardAddress -= (EPRO_RX_UPPER_LIMIT_SHORT - EPRO_RX_LOWER_LIMIT_SHORT);
+ }
+
+// Are we starting of reading from an odd address?
+ if (cardAddress & 1) {
+// yes; odd offset -- forward a byte in...
+ fForward = TRUE;
+ cardAddress--;
+ }
+
+// Okay, now seek to the right address on the card
+ EPRO_SET_HOST_ADDR(adapter, cardAddress);
+
+// Are we forwarding a byte in? If so, fetch it now....
+ if (fForward == TRUE) {
+ EPRO_RD_PORT_USHORT(adapter, I82595_MEM_IO_REG, (USHORT *)(&tempCopy));
+ }
+
+
+// continue until we either run out of buffers, or out of bytes....
+ while((bytesToCopy > 0) && (curDestBuf!=NULL)) {
+// We either write the entire buffer size bytes or the number of bytes
+// remaining to copy - whichever is smaller.
+ bytesWriteThisPacket = (bytesToCopy > curDestBufLen) ?
+ curDestBufLen : bytesToCopy;
+ bytesToCopy-=bytesWriteThisPacket;
+
+// Ooh, we're going to transfer some bytes...
+ *bytesTransferred+=bytesWriteThisPacket;
+
+// Okay. Did we have to forward a byte in? Copy it to the buffer NOW..
+ if (fForward == TRUE) {
+ *(UCHAR *)curDestBufAddr = tempCopy[1];
+ fForward = FALSE;
+ ((UCHAR *)curDestBufAddr)++;
+ bytesWriteThisPacket--;
+ }
+
+// Copy the bulk of the data...
+#ifndef EPRO_USE_32_BIT_IO
+ EPRO_READ_BUFFER_FROM_NIC_USHORT(adapter, curDestBufAddr,
+ bytesWriteThisPacket>>1);
+#else
+ if (adapter->EProUse32BitIO) {
+ if (bytesWriteThisPacket & 2) {
+ EPRO_RD_PORT_USHORT(adapter, I82595_MEM_IO_REG, (USHORT *)curDestBufAddr);
+ EPRO_READ_BUFFER_FROM_NIC_ULONG(adapter,
+ (UNALIGNED ULONG *)((UCHAR *)curDestBufAddr +2),
+ bytesWriteThisPacket >> 2);
+ } else {
+ EPRO_READ_BUFFER_FROM_NIC_ULONG(adapter,
+ (UNALIGNED ULONG *)curDestBufAddr,
+ bytesWriteThisPacket >> 2);
+ }
+ } else {
+ EPRO_READ_BUFFER_FROM_NIC_USHORT(adapter, curDestBufAddr,
+ bytesWriteThisPacket>>1);
+ }
+#endif
+
+// Okay, the rshift in the last call will lose the odd byte. If there is one, we need
+// to read it and possibly forward the second byte....
+ if (bytesWriteThisPacket & 1) {
+ fForward = TRUE;
+ // Read the LOW order byte.
+ EPRO_RD_PORT_USHORT(adapter, I82595_MEM_IO_REG, (USHORT *)(&tempCopy));
+ ((UCHAR *)curDestBufAddr)[bytesWriteThisPacket-1] = tempCopy[0];
+ }
+ NdisGetNextBuffer(curDestBuf, &curDestBuf);
+ if (curDestBuf != NULL) {
+ NdisQueryBuffer(curDestBuf, &curDestBufAddr, &curDestBufLen);
+ }
+ }
+
+ EProLogStr(" 3BytesTo:");
+ EProLogLong(bytesToTransfer);
+ EProLogStr("BytesTransf:");
+ EProLogLong(*bytesTransferred);
+ return(NDIS_STATUS_SUCCESS);
+}
+
+#else
+
+
+NDIS_STATUS EProTransferData(OUT PNDIS_PACKET packet,
+ OUT PUINT bytesTransferred,
+ IN NDIS_HANDLE miniportAdapterContext,
+ IN NDIS_HANDLE miniportReceivedContext,
+ IN UINT byteOffset,
+ IN UINT bytesToTransfer)
+/*++
+
+Routine Description:
+
+ The transferdata handler for the EPro.
+
+Arguments:
+
+ packet - The packet to transfer the data into
+
+ bytesTransferred - The number of bytes actually copied into packet.
+
+ miniportAdapterContext - Reallly a pointer to our EPRO_ADAPTER structure
+
+ miniportReceivedContext - This is our EPRO_RCV_CONTEXT, which basically just
+ has the packet length and pointer to where it lies
+ in the card's address space.
+
+ byteOffset - where in the frame to begin trasferring from
+
+ bytesToTransfer - how many bytes to transfer.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS - data transfered OK
+ NDIS_STATUS_FAILURE - tried to transfer off end of frame
+
+--*/
+{
+ PEPRO_ADAPTER adapter = (PEPRO_ADAPTER)miniportAdapterContext;
+
+ // The 82595's on-card RCV memory structure
+ EPRO_RCV_HEADER header;
+
+ // An 802.3 ethernet header.
+ EPRO_ETH_HEADER ethHeader;
+
+ // How many bytes have we copied, how many are left to copy
+ USHORT byteCount, bytesToCopy;
+ PEPRO_RCV_CONTEXT pcontext = (PEPRO_RCV_CONTEXT)miniportReceivedContext;
+
+ // The current buffer we are copying into.
+ PNDIS_BUFFER curDestBuf;
+
+ // The physical address of the buffer we are currently copying into
+ PVOID curDestBufAddr;
+
+ // The length of that buffer
+ UINT curDestBufLen;
+
+ // Two bytes used when we have to transfer in to odd-length buffers (since
+ // accesses to the EPro's memory are only by-word.
+ UCHAR tempCopy[2];
+
+ // This is TRUE if we are "forwarding" a single byte from an odd-length transfer
+ BOOLEAN fForward = FALSE;
+
+ // the address to read from on the card
+ USHORT cardAddress;
+
+ // TODO - copy first lookahead size bytes out of lookahead buffer.
+
+ *bytesTransferred = 0;
+
+ // switch to bank0 for mem io
+ // EPRO_SWITCH_BANK_0(adapter);
+ EPRO_ASSERT_BANK_0(adapter);
+
+ // Make sure they're not asking for too much.
+ // if (bytesToTransfer + byteOffset > pcontext->RXFrameSize)
+ // {
+ // return(NDIS_STATUS_FAILURE);
+ // }
+
+ // Make sure they're not seeking past the end of the frame
+ if (byteOffset > pcontext->RXFrameSize)
+ {
+ return(NDIS_STATUS_FAILURE);
+ }
+
+
+ // copy the amount requested, or the entire packet - whichever is smaller
+ if ((bytesToTransfer + byteOffset) <= pcontext->RXFrameSize)
+ {
+ bytesToCopy = bytesToTransfer;
+ }
+ else
+ {
+ bytesToCopy = (pcontext->RXFrameSize - byteOffset);
+ }
+
+// set our memory address on the card...
+ cardAddress = (pcontext->RXCurrentAddress +
+ sizeof(EPRO_RCV_HEADER) +
+ sizeof(EPRO_ETH_HEADER) +
+ byteOffset);
+
+ if (cardAddress >= EPRO_RX_UPPER_LIMIT_SHORT)
+ {
+ // cardAddress = EPRO_RX_LOWER_LIMIT_SHORT + (cardAddress - EPRO_RX_UPPER_LIMIT_SHORT);
+ // Go algebraic simplification:
+ cardAddress -= (EPRO_RX_UPPER_LIMIT_SHORT - EPRO_RX_LOWER_LIMIT_SHORT);
+ }
+
+
+ // Are we starting of reading from an odd address?
+ if (cardAddress & 1)
+ {
+ // yes; odd offset -- forward a byte in...
+ fForward = TRUE;
+ cardAddress--;
+ }
+
+ // Okay, now seek to the right address on the card
+ EPRO_SET_HOST_ADDR(adapter, cardAddress);
+
+ // Are we forwarding a byte in? If so, fetch it now....
+ if (fForward == TRUE)
+ {
+ EPRO_RD_PORT_USHORT(adapter, I82595_MEM_IO_REG, (USHORT *)(&tempCopy));
+ }
+
+ // get the first buffer
+ NdisQueryPacket(packet, NULL, NULL, &curDestBuf, NULL);
+
+ // continue until we either run out of buffers, or out of bytes....
+ while((bytesToCopy > 0) && (curDestBuf!=NULL))
+ {
+ UINT bytesWriteThisPacket;
+
+ NdisQueryBuffer(curDestBuf, &curDestBufAddr, &curDestBufLen);
+
+ // We either write the entire buffer size bytes or the number of bytes
+ // remaining to copy - whichever is smaller.
+ bytesWriteThisPacket =
+ (bytesToCopy > curDestBufLen) ? curDestBufLen : bytesToCopy;
+
+ // Ooh, we're going to transfer some bytes...
+ *bytesTransferred+=bytesWriteThisPacket;
+
+ // Okay. Did we have to forward a byte in? Copy it to the buffer NOW..
+ if (fForward == TRUE)
+ {
+ *(UCHAR *)curDestBufAddr = tempCopy[1];
+ fForward = FALSE;
+ ((UCHAR *)curDestBufAddr)++;
+ bytesWriteThisPacket--;
+ }
+
+ // Copy the bulk of the data...
+#ifndef EPRO_USE_32_BIT_IO
+ EPRO_READ_BUFFER_FROM_NIC_USHORT(adapter, curDestBufAddr, bytesWriteThisPacket>>1);
+#else
+ if (adapter->EProUse32BitIO)
+ {
+ if (bytesWriteThisPacket & 2)
+ {
+ EPRO_RD_PORT_USHORT(
+ adapter,
+ I82595_MEM_IO_REG,
+ (UNALIGNED USHORT *)curDestBufAddr);
+
+ EPRO_READ_BUFFER_FROM_NIC_ULONG(
+ adapter,
+ ((UCHAR *)curDestBufAddr +2),
+ bytesWriteThisPacket >> 2);
+ }
+ else
+ {
+ EPRO_READ_BUFFER_FROM_NIC_ULONG(
+ adapter,
+ curDestBufAddr,
+ bytesWriteThisPacket >> 2);
+ }
+ }
+ else
+ {
+ EPRO_READ_BUFFER_FROM_NIC_USHORT(
+ adapter,
+ curDestBufAddr,
+ bytesWriteThisPacket >> 1);
+ }
+#endif
+
+ // Okay, the rshift in the last call will lose the odd byte. If there is one, we need
+ // to read it and possibly forward the second byte....
+ if (bytesWriteThisPacket & 1)
+ {
+ fForward = TRUE;
+
+ // Read the LOW order byte.
+ EPRO_RD_PORT_USHORT(
+ adapter,
+ I82595_MEM_IO_REG,
+ (USHORT *)(&tempCopy));
+
+ ((UCHAR *)curDestBufAddr)[bytesWriteThisPacket-1] = tempCopy[0];
+ }
+ NdisGetNextBuffer(curDestBuf, &curDestBuf);
+ bytesToCopy -= curDestBufLen;
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+#endif
+
+
+BOOLEAN EProSyncCopyBufferToNicUlong(PVOID context)
+{
+ UCHAR result;
+ PEPRO_ADAPTER adapter = ((PEPRO_COPYBUF_CONTEXT)context)->Adapter;
+// PVOID buffer = ((PEPRO_COPYBUF_CONTEXT)context)->Buffer;
+// UINT len = ((PEPRO_COPYBUF_CONTEXT)context)->Len;
+
+ EPRO_RD_PORT_UCHAR(adapter, I82595_32IOSEL_REG, &result);
+// result |= I82595_32IOSEL;
+ EPRO_WR_PORT_UCHAR(adapter, I82595_32IOSEL_REG, (result | I82595_32IOSEL));
+ NdisRawWritePortBufferUlong(adapter->IoPAddr + I82595_32MEM_IO_REG,
+ ((PEPRO_COPYBUF_CONTEXT)context)->Buffer,
+ ((PEPRO_COPYBUF_CONTEXT)context)->Len);
+// result &= ~I82595_32IOSEL;
+ EPRO_WR_PORT_UCHAR(adapter, I82595_32IOSEL_REG, result);
+
+ return(TRUE);
+}
+
+
+BOOLEAN EProSyncReadBufferFromNicUlong(PVOID context)
+{
+ UCHAR result;
+ PEPRO_ADAPTER adapter = ((PEPRO_COPYBUF_CONTEXT)context)->Adapter;
+// PVOID buffer = ((PEPRO_COPYBUF_CONTEXT)context)->Buffer;
+// UINT len = ((PEPRO_COPYBUF_CONTEXT)context)->Len;
+
+ EPRO_RD_PORT_UCHAR(adapter, I82595_32IOSEL_REG, &result);
+// result |= I82595_32IOSEL;
+ EPRO_WR_PORT_UCHAR(adapter, I82595_32IOSEL_REG, (result | I82595_32IOSEL));
+ NdisRawReadPortBufferUlong(adapter->IoPAddr + I82595_32MEM_IO_REG,
+ ((PEPRO_COPYBUF_CONTEXT)context)->Buffer,
+ ((PEPRO_COPYBUF_CONTEXT)context)->Len);
+// result &= ~I82595_32IOSEL;
+ EPRO_WR_PORT_UCHAR(adapter, I82595_32IOSEL_REG, result);
+
+ return(TRUE);
+}
+
diff --git a/private/ntos/ndis/ieepro/sources b/private/ntos/ndis/ieepro/sources
new file mode 100644
index 000000000..e950c6ce5
--- /dev/null
+++ b/private/ntos/ndis/ieepro/sources
@@ -0,0 +1,48 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=ieepro
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER
+
+INCLUDES=..\..\inc
+
+SOURCES=epro.c \
+ init.c \
+ request.c \
+ eeprom.c \
+ sndrcv.c \
+ eprodbg.c \
+ epro.rc
+
+RELATIVE_DEPTH=..\..
+
+MSC_WARNING_LEVEL=/W3 /WX
diff --git a/private/ntos/ndis/inc/ndisprv.h b/private/ntos/ndis/inc/ndisprv.h
new file mode 100644
index 000000000..a420931c3
--- /dev/null
+++ b/private/ntos/ndis/inc/ndisprv.h
@@ -0,0 +1,32 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ D:\nt\private\ntos\ndis\inc\ndisprv.h
+
+Abstract:
+
+Author:
+
+ Kyle Brandon (KyleB)
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#ifndef __NDISPRV_H
+#define __NDISPRV_H
+
+//
+// All mac options require the reserved bit to be set in
+// the miniports mac options.
+//
+#define NDIS_MAC_OPTION_NDISWAN 0x00000001
+
+#endif // __NDISPRV_H
diff --git a/private/ntos/ndis/irmini/actisys.c b/private/ntos/ndis/irmini/actisys.c
new file mode 100644
index 000000000..62ffc88c7
--- /dev/null
+++ b/private/ntos/ndis/irmini/actisys.c
@@ -0,0 +1,113 @@
+/*
+ * ACTISYS.C
+ *
+ *
+ *
+ */
+
+
+#ifndef IRMINILIB
+
+
+ #include "dongle.h"
+
+
+ /*
+ * The programming interface to a UART (COM serial port)
+ * consists of eight consecutive registers.
+ * These are the port offsets from the UART's base I/O address.
+ */
+ typedef enum comPortRegOffsets {
+ XFER_REG_OFFSET = 0,
+ INT_ENABLE_REG_OFFSET = 1,
+ INT_ID_AND_FIFO_CNTRL_REG_OFFSET = 2,
+ LINE_CONTROL_REG_OFFSET = 3,
+ MODEM_CONTROL_REG_OFFSET = 4,
+ LINE_STAT_REG_OFFSET = 5,
+ MODEM_STAT_REG_OFFSET = 6,
+ SCRATCH_REG_OFFSET = 7
+ } comPortRegOffset;
+
+
+ #define ACTISYS_IRDA_SPEEDS ( NDIS_IRDA_SPEED_9600 | \
+ NDIS_IRDA_SPEED_19200 | \
+ NDIS_IRDA_SPEED_57600 | \
+ NDIS_IRDA_SPEED_115200 \
+ )
+
+
+ BOOLEAN ACTISYS_Init(UINT comBase, dongleCapabilities *caps, UINT *context)
+ {
+ caps->supportedSpeedsMask = ACTISYS_IRDA_SPEEDS;
+ caps->turnAroundTime_usec = 5000;
+ caps->extraBOFsRequired = 0;
+
+ *context = 0;
+
+ return TRUE;
+ }
+
+ VOID ACTISYS_Deinit(UINT comBase, UINT context)
+ {
+
+ }
+
+
+ BOOLEAN ACTISYS_SetSpeed(UINT comBase, UINT bitsPerSec, UINT context)
+ {
+
+ /*
+ * For the ActiSys, we set speed by toggling the RTS line.
+ */
+ int i, numToggles = 0;
+ UCHAR modemCntrlReg;
+
+ switch (bitsPerSec){
+ case 9600:
+ numToggles = 0;
+ break;
+ case 19200:
+ numToggles = 1;
+ break;
+ case 57600:
+ numToggles = 2;
+ break;
+ case 115200:
+ numToggles = 3;
+ break;
+ default:
+ /*
+ * Illegal speed
+ */
+ return FALSE;
+ }
+
+ IRMINI_RawReadPort(comBase+MODEM_CONTROL_REG_OFFSET, &modemCntrlReg);
+
+ /*
+ * First reset by toggling DTR
+ */
+ modemCntrlReg &= ~1;
+ IRMINI_RawWritePort(comBase+MODEM_CONTROL_REG_OFFSET, modemCntrlReg);
+ IRMINI_StallExecution(50000);
+ modemCntrlReg |= 1;
+ IRMINI_RawWritePort(comBase+MODEM_CONTROL_REG_OFFSET, modemCntrlReg);
+ IRMINI_StallExecution(50000);
+
+ /*
+ * Now toggle RTS to set the speed.
+ */
+ for (i = 0; i < numToggles; i++){
+ modemCntrlReg &= ~2;
+ IRMINI_RawWritePort(comBase+MODEM_CONTROL_REG_OFFSET, modemCntrlReg);
+ IRMINI_StallExecution(50000);
+ modemCntrlReg |= 2;
+ IRMINI_RawWritePort(comBase+MODEM_CONTROL_REG_OFFSET, modemCntrlReg);
+ IRMINI_StallExecution(50000);
+ }
+
+ return TRUE;
+ }
+
+
+#endif
diff --git a/private/ntos/ndis/irmini/actisys.h b/private/ntos/ndis/irmini/actisys.h
new file mode 100644
index 000000000..638f9ecff
--- /dev/null
+++ b/private/ntos/ndis/irmini/actisys.h
@@ -0,0 +1,20 @@
+/*
+ * ACTISYS.H
+ *
+ *
+ *
+ */
+
+#include "dongle.h"
+
+#ifndef ACTISYS_H
+ #define ACTISYS_H
+
+ BOOLEAN ACTISYS_Init(UINT comBase, dongleCapabilities *caps, UINT *context);
+ VOID ACTISYS_Deinit(UINT comBase, UINT context);
+ BOOLEAN ACTISYS_SetSpeed(UINT comBase, UINT bitsPerSec, UINT context);
+
+#endif ACTISYS_H
+
+
+
diff --git a/private/ntos/ndis/irmini/adaptec.c b/private/ntos/ndis/irmini/adaptec.c
new file mode 100644
index 000000000..6d5bd0af2
--- /dev/null
+++ b/private/ntos/ndis/irmini/adaptec.c
@@ -0,0 +1,328 @@
+/*
+ * adaptec.c
+ *
+ *
+ *
+ */
+
+
+#ifndef IRMINILIB
+
+
+ #include "dongle.h"
+
+
+ /*
+ * The programming interface to a UART (COM serial port)
+ * consists of eight consecutive registers.
+ * These are the port offsets from the UART's base I/O address.
+ */
+ typedef enum comPortRegOffsets {
+ XFER_REG_OFFSET = 0,
+ INT_ENABLE_REG_OFFSET = 1,
+ INT_ID_AND_FIFO_CNTRL_REG_OFFSET = 2,
+ LINE_CONTROL_REG_OFFSET = 3,
+ MODEM_CONTROL_REG_OFFSET = 4,
+ LINE_STAT_REG_OFFSET = 5,
+ MODEM_STAT_REG_OFFSET = 6,
+ SCRATCH_REG_OFFSET = 7
+ } comPortRegOffset;
+
+
+ /*
+ * Bits in the UART line-status register.
+ */
+ #define LINESTAT_DATAREADY (UCHAR)(1 << 0)
+ #define LINESTAT_OVERRUNERROR (UCHAR)(1 << 1)
+ #define LINESTAT_PARITYERROR (UCHAR)(1 << 2)
+ #define LINESTAT_FRAMINGERROR (UCHAR)(1 << 3)
+ #define LINESTAT_BREAK (UCHAR)(1 << 4)
+ #define LINESTAT_XMIT_HOLDING_REG_EMPTY (UCHAR)(1 << 5)
+ #define LINESTAT_XMIT_SHIFT_AND_HOLDING_REG_EMPTY (UCHAR)(1 << 6)
+
+
+ #define ADAPTEC_IRDA_SPEEDS ( \
+ NDIS_IRDA_SPEED_2400 | \
+ NDIS_IRDA_SPEED_9600 | \
+ NDIS_IRDA_SPEED_19200 | \
+ NDIS_IRDA_SPEED_38400 | \
+ NDIS_IRDA_SPEED_57600 | \
+ NDIS_IRDA_SPEED_115200 \
+ )
+
+ /*
+ *************************************************************************
+ * AdaptecCommandMode
+ *************************************************************************
+ *
+ *
+ */
+ BOOLEAN AdaptecCommandMode(UINT comBase, BOOLEAN commandModeOn)
+ {
+ UCHAR modemCntrlVal, sig;
+ BOOLEAN result = FALSE;
+ UINT i;
+
+ IRMINI_RawReadPort(comBase+MODEM_CONTROL_REG_OFFSET, &modemCntrlVal);
+
+ if (commandModeOn){
+ /*
+ * Set command mode
+ */
+ modemCntrlVal |= 2;
+ modemCntrlVal &= ~1;
+ IRMINI_RawWritePort(comBase+MODEM_CONTROL_REG_OFFSET, modemCntrlVal);
+
+ IRMINI_StallExecution(20000);
+
+ for (i = 0; i < 10; i++){
+
+ /*
+ * Select the signature register
+ */
+ IRMINI_RawWritePort(comBase+XFER_REG_OFFSET, 0xff);
+
+ IRMINI_StallExecution(20000);
+
+ IRMINI_RawReadPort(comBase+XFER_REG_OFFSET, &sig);
+ if (sig == 0xc3){
+ result = TRUE;
+ break;
+ }
+ else {
+ /*
+ * Read a few characters to gyrate the part
+ */
+ UINT j;
+ for (j = 0; j < 3; j++){
+ UCHAR dummy;
+ IRMINI_RawReadPort(comBase+XFER_REG_OFFSET, &dummy);
+ }
+ }
+ }
+ }
+ else {
+ /*
+ * Set normal mode
+ */
+ modemCntrlVal |= 3;
+ IRMINI_RawWritePort(comBase+MODEM_CONTROL_REG_OFFSET, modemCntrlVal);
+ result = TRUE;
+ }
+
+ IRMINI_StallExecution(20000);
+
+ return result;
+ }
+
+
+ /*
+ *************************************************************************
+ * AdaptecWriteChar
+ *************************************************************************
+ *
+ *
+ */
+ BOOLEAN AdaptecWriteChar(UINT comBase, UCHAR val)
+ {
+ UINT i;
+ UCHAR lineStatReg;
+ BOOLEAN result = TRUE;
+ UINT confirmAttempts = 0;
+
+
+ /*
+ * Wait for ready-to-send.
+ */
+ i = 0;
+ do {
+ IRMINI_RawReadPort(comBase+LINE_STAT_REG_OFFSET, &lineStatReg);
+ IRMINI_StallExecution(20000);
+ } while (!(lineStatReg & LINESTAT_XMIT_HOLDING_REG_EMPTY) && (++i < 4));
+ if (!(lineStatReg & LINESTAT_XMIT_HOLDING_REG_EMPTY)){
+ return FALSE;
+ }
+
+ /*
+ * Send the byte.
+ */
+ IRMINI_RawWritePort(comBase+XFER_REG_OFFSET, val);
+ IRMINI_StallExecution(20000);
+
+ /*
+ * Confirm the write by reading back the character
+ */
+
+ do {
+ IRMINI_StallExecution(20000);
+ i = 0;
+ do {
+ IRMINI_RawReadPort(comBase+LINE_STAT_REG_OFFSET, &lineStatReg);
+ } while (!(lineStatReg & LINESTAT_DATAREADY) && (++i < 4));
+
+ if (lineStatReg & LINESTAT_DATAREADY){
+ UCHAR readBackChar;
+
+ IRMINI_RawReadPort(comBase+XFER_REG_OFFSET, &readBackChar);
+ if (readBackChar != val){
+ result = FALSE;
+ }
+ }
+ else {
+ result = FALSE;
+ }
+ } while (!result && (++confirmAttempts < 5));
+
+ return result;
+ }
+
+
+ /*
+ *************************************************************************
+ * AdaptecWriteCmd
+ *************************************************************************
+ *
+ * Initialize UART registers
+ *
+ */
+ BOOLEAN AdaptecWriteCmd(UINT comBase, UCHAR val)
+ {
+ UINT loops;
+ BOOLEAN result = FALSE;
+
+ /*
+ * Set command mode and attempt the operation 5 times.
+ */
+ if (!AdaptecCommandMode(comBase, TRUE)){
+ return FALSE;
+ }
+ for (loops = 0; loops < 5; loops++){
+ if (AdaptecWriteChar(comBase, val)){
+ result = TRUE;
+ break;
+ }
+ else {
+ IRMINI_StallExecution(20000);
+ }
+ }
+ AdaptecCommandMode(comBase, FALSE);
+
+ return result;
+ }
+
+
+ /*
+ *************************************************************************
+ * ADAPTEC_Init
+ *************************************************************************
+ *
+ * NOTE: The UART speed must be set to 9600 when this function is called.
+ *
+ */
+ BOOLEAN ADAPTEC_Init(UINT comBase, dongleCapabilities *caps, UINT *context)
+ {
+
+ /*
+ * Set normal (not command) mode
+ */
+ if (!AdaptecCommandMode(comBase, FALSE)){
+ return FALSE;
+ }
+
+ /*
+ * Wait 2 seconds (!) for power-up. BUGBUG - reduce ???
+ */
+ IRMINI_StallExecution(2000000);
+
+
+ /*
+ * Set speed to 9600 baud in both baud and reload registers
+ */
+ if (!AdaptecWriteCmd(comBase, 0x30)){
+ return FALSE;
+ }
+ if (!AdaptecWriteCmd(comBase, 0x31)){
+ return FALSE;
+ }
+
+ /*
+ * Initialize the xmit and rcv control registers.
+ */
+ if (!AdaptecWriteCmd(comBase, 0x02)){
+ return FALSE;
+ }
+ if (!AdaptecWriteCmd(comBase, 0x03)){
+ return FALSE;
+ }
+
+ /*
+ * Clear the status register and confirm the result.
+ */
+ if (!AdaptecWriteCmd(comBase, 0x04)){
+ return FALSE;
+ }
+
+ caps->supportedSpeedsMask = ADAPTEC_IRDA_SPEEDS;
+ caps->turnAroundTime_usec = 5000;
+ caps->extraBOFsRequired = 0;
+
+ *context = 0;
+
+ return TRUE;
+ }
+
+
+ /*
+ *************************************************************************
+ * ADAPTEC_Deinit
+ *************************************************************************
+ *
+ *
+ */
+ VOID ADAPTEC_Deinit(UINT comBase, UINT context)
+ {
+ UCHAR modemCntrlVal;
+
+ IRMINI_RawReadPort(comBase+MODEM_CONTROL_REG_OFFSET, &modemCntrlVal);
+ modemCntrlVal &= ~3;
+ IRMINI_RawWritePort(comBase+MODEM_CONTROL_REG_OFFSET, modemCntrlVal);
+ }
+
+
+
+ /*
+ *************************************************************************
+ * ADAPTEC_SetSpeed
+ *************************************************************************
+ *
+ * Initialize UART registers
+ *
+ * NOTE: The UART speed must be set to 9600 when this function is called.
+ *
+ */
+ BOOLEAN ADAPTEC_SetSpeed(UINT comBase, UINT bitsPerSec, UINT context)
+ {
+ UCHAR code;
+
+ switch (bitsPerSec){
+ case 2400: code = 0x10; break;
+ case 9600: code = 0x30; break;
+ case 19200: code = 0x40; break;
+ case 38400: code = 0x50; break;
+ case 57600: code = 0x60; break;
+ case 115200: code = 0x70; break;
+ default: code = 0x30; break;
+ }
+
+ if (!AdaptecWriteCmd(comBase, code)){
+ return FALSE;
+ }
+ if (!AdaptecWriteCmd(comBase, (UCHAR)(code | 1))){
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+#endif
+
diff --git a/private/ntos/ndis/irmini/adaptec.h b/private/ntos/ndis/irmini/adaptec.h
new file mode 100644
index 000000000..79471961e
--- /dev/null
+++ b/private/ntos/ndis/irmini/adaptec.h
@@ -0,0 +1,18 @@
+/*
+ * ADAPTEC.H
+ *
+ *
+ *
+ */
+
+#include "dongle.h"
+
+#ifndef ADAPTEC_H
+ #define ADAPTEC_H
+
+ BOOLEAN ADAPTEC_Init(UINT comBase, dongleCapabilities *caps, UINT *context);
+ VOID ADAPTEC_Deinit(UINT comBase, UINT context);
+ BOOLEAN ADAPTEC_SetSpeed(UINT comBase, UINT bitsPerSec, UINT context);
+
+#endif ADAPTEC_H
+
diff --git a/private/ntos/ndis/irmini/comm.c b/private/ntos/ndis/irmini/comm.c
new file mode 100644
index 000000000..493df9984
--- /dev/null
+++ b/private/ntos/ndis/irmini/comm.c
@@ -0,0 +1,1050 @@
+/*
+ ************************************************************************
+ *
+ * COMM.c
+ *
+ * IRMINI Infrared Serial NDIS Miniport driver.
+ *
+ * (C) Copyright 1996 Microsoft Corp.
+ *
+ *
+ * (ep)
+ *
+ *************************************************************************
+ */
+
+#include "irmini.h"
+
+
+/*
+ * These arrays give default IO/IRQ settings by COM port number.
+ */
+USHORT comPortIOBase[] = { 0xFFFF, 0x3F8, 0x2F8, 0x3E8, 0x2E8 };
+USHORT comPortIRQ[] = { 0xFFFF, 4, 3, 4, 5 };
+
+
+
+/*
+ *************************************************************************
+ * SetCOMInterrupts
+ *************************************************************************
+ */
+VOID SetCOMInterrupts(IrDevice *thisDev, BOOLEAN enable)
+{
+ if (enable){
+ if (thisDev->portInfo.writePending){
+ SetCOMPort(thisDev->portInfo.ioBase, INT_ENABLE_REG_OFFSET, XMIT_MODE_INTS_ENABLE);
+ }
+ else {
+ SetCOMPort(thisDev->portInfo.ioBase, INT_ENABLE_REG_OFFSET, RCV_MODE_INTS_ENABLE);
+ }
+ }
+ else {
+ SetCOMPort(thisDev->portInfo.ioBase, INT_ENABLE_REG_OFFSET, ALL_INTS_DISABLE);
+ }
+}
+
+
+/*
+ *************************************************************************
+ * IsCommReadyForTransmit
+ *************************************************************************
+ *
+ *
+ */
+BOOLEAN IsCommReadyForTransmit(IrDevice *thisDev)
+{
+ return !thisDev->portInfo.writePending;
+}
+
+
+
+
+/*
+ *************************************************************************
+ * DoOpen
+ *************************************************************************
+ *
+ * Open COMM port
+ *
+ */
+BOOLEAN DoOpen(IrDevice *thisDev)
+{
+ BOOLEAN result;
+
+ DBGOUT(("DoOpen(%d)", thisDev->portInfo.ioBase));
+
+ /*
+ * This buffer gets swapped with the rcvBuffer data pointer
+ * and must be the same size.
+ */
+ thisDev->portInfo.readBuf = MyMemAlloc(RCV_BUFFER_SIZE);
+ if (!thisDev->portInfo.readBuf){
+ return FALSE;
+ }
+
+ /*
+ * Initialize send/receive FSMs before OpenCOM(), which enables rcv interrupts.
+ */
+ thisDev->portInfo.rcvState = STATE_INIT;
+ thisDev->portInfo.writePending = FALSE;
+
+ result = OpenCOM(thisDev);
+
+ DBGOUT(("DoOpen %s", (CHAR *)(result ? "succeeded" : "failed")));
+ return result;
+
+}
+
+
+
+/*
+ *************************************************************************
+ * DoClose
+ *************************************************************************
+ *
+ * Close COMM port
+ *
+ */
+VOID DoClose(IrDevice *thisDev)
+{
+ DBGOUT(("DoClose(COM%d)", thisDev->portInfo.ioBase));
+
+ if (thisDev->portInfo.readBuf){
+ MyMemFree(thisDev->portInfo.readBuf, RCV_BUFFER_SIZE);
+ thisDev->portInfo.readBuf = NULL;
+ }
+ CloseCOM(thisDev);
+}
+
+
+
+/*
+ *************************************************************************
+ * SetUARTSpeed
+ *************************************************************************
+ *
+ *
+ */
+VOID SetUARTSpeed(IrDevice *thisDev, UINT bitsPerSec)
+{
+ /*
+ * Set speed in the standard UART divisor latch
+ *
+ * 1. Set up to access the divisor latch.
+ *
+ * 2. In divisor-latch mode:
+ * the transfer register doubles as the low divisor latch
+ * the int-enable register doubles as the hi divisor latch
+ *
+ * Set the divisor for the given speed.
+ * The divisor divides the maximum Slow IR speed of 115200 bits/sec.
+ *
+ * 3. Take the transfer register out of divisor-latch mode.
+ *
+ */
+ if (!bitsPerSec){
+ bitsPerSec = 9600;
+ }
+ SetCOMPort(thisDev->portInfo.ioBase, LINE_CONTROL_REG_OFFSET, 0x83);
+ SetCOMPort(thisDev->portInfo.ioBase, XFER_REG_OFFSET, (UCHAR)(115200/bitsPerSec));
+ SetCOMPort(thisDev->portInfo.ioBase, INT_ENABLE_REG_OFFSET, (UCHAR)((115200/bitsPerSec)>>8));
+ SetCOMPort(thisDev->portInfo.ioBase, LINE_CONTROL_REG_OFFSET, 0x03);
+
+ NdisStallExecution(5000);
+}
+
+
+/*
+ *************************************************************************
+ * SetSpeed
+ *************************************************************************
+ *
+ *
+ */
+BOOLEAN SetSpeed(IrDevice *thisDev)
+{
+ UINT bitsPerSec = thisDev->linkSpeedInfo->bitsPerSec;
+ BOOLEAN dongleSet, result = TRUE;
+
+ DBGOUT((" **** SetSpeed(%xh, %d bps) ***************************", thisDev->portInfo.ioBase, bitsPerSec));
+
+ if (thisDev->lastSendPacket){
+ /*
+ * We can't set speed in the hardware while
+ * send packets are queued.
+ */
+ DBGOUT(("delaying set-speed because send pkts queued"));
+ thisDev->lastPacketAtOldSpeed = thisDev->lastSendPacket;
+ return TRUE;
+ }
+ else if (thisDev->portInfo.writePending){
+ thisDev->setSpeedAfterCurrentSendPacket = TRUE;
+ DBGOUT(("will set speed after current write pkt"));
+ return TRUE;
+ }
+
+ /*
+ * Disable interrupts while changing speed.
+ * (This is especially important for the ADAPTEC dongle;
+ * we may get interrupted while setting command mode
+ * between writing 0xff and reading 0xc3).
+ */
+ SetCOMInterrupts(thisDev, FALSE);
+
+ /*
+ * First, set the UART's speed to 9600 baud.
+ * Some of the dongles need to receive their command sequences at this speed.
+ */
+ SetUARTSpeed(thisDev, 9600);
+
+ /*
+ * Some UART infrared transceivers need special treatment here.
+ */
+ #ifdef IRMINILIB
+ dongleSet = OEM_Interface.setSpeedHandler(thisDev->portInfo.ioBase, bitsPerSec, thisDev->portInfo.dongleContext);
+ #else
+ switch (thisDev->transceiverType){
+ case STANDARD_UART:
+ dongleSet = TRUE;
+ break;
+ case ESI_9680:
+ dongleSet = ESI_SetSpeed(thisDev->portInfo.ioBase, bitsPerSec, thisDev->portInfo.dongleContext);
+ break;
+ case CRYSTAL:
+ dongleSet = CRYSTAL_SetSpeed(thisDev->portInfo.ioBase, bitsPerSec, thisDev->portInfo.dongleContext);
+ break;
+ case ADAPTEC:
+ dongleSet = ADAPTEC_SetSpeed(thisDev->portInfo.ioBase, bitsPerSec, thisDev->portInfo.dongleContext);
+ break;
+ case ACTISYS_220L:
+ dongleSet = ACTISYS_SetSpeed(thisDev->portInfo.ioBase, bitsPerSec, thisDev->portInfo.dongleContext);
+ break;
+ case PARALLAX:
+ dongleSet = PARALLAX_SetSpeed(thisDev->portInfo.ioBase, bitsPerSec, thisDev->portInfo.dongleContext);
+ break;
+ case NSC_DEMO_BD:
+ dongleSet = NSC_DEMO_SetSpeed(thisDev->portInfo.ioBase, bitsPerSec, thisDev->portInfo.dongleContext);
+ break;
+ default:
+ dongleSet = FALSE;
+ DBGERR(("Illegal transceiver type in SetSpeed"));
+ break;
+ }
+ #endif
+
+ if (!dongleSet){
+ DBGERR(("Dongle set-speed failed"));
+ result = FALSE;
+ }
+
+ /*
+ * Now set the speed for the COM port
+ */
+ SetUARTSpeed(thisDev, bitsPerSec);
+
+ thisDev->currentSpeed = bitsPerSec;
+
+ SetCOMInterrupts(thisDev, TRUE);
+
+ return result;
+}
+
+
+
+/*
+ *************************************************************************
+ * DoSend
+ *************************************************************************
+ *
+ *
+ * Send an IR packet which has already been formatted with IR header
+ * and escape sequences.
+ *
+ * Return TRUE iff the send succeeded.
+ */
+BOOLEAN DoSend(IrDevice *thisDev, PNDIS_PACKET packetToSend)
+{
+ BOOLEAN convertedPacket;
+
+ DBGOUT(("DoSend(%xh)", thisDev->portInfo.ioBase));
+
+ /*
+ * Convert the NDIS packet to an IRDA packet.
+ */
+ convertedPacket = NdisToIrPacket( thisDev,
+ packetToSend,
+ (UCHAR *)thisDev->portInfo.writeBuf,
+ MAX_IRDA_DATA_SIZE,
+ &thisDev->portInfo.writeBufLen);
+
+ if (convertedPacket){
+
+ DBGPRINTBUF(thisDev->portInfo.writeBuf, thisDev->portInfo.writeBufLen);
+
+ /*
+ * Disable interrupts while setting up the send FSM.
+ */
+ SetCOMInterrupts(thisDev, FALSE);
+
+ /*
+ * Finish initializing the send FSM.
+ */
+ thisDev->portInfo.writeBufPos = 0;
+ thisDev->portInfo.writePending = TRUE;
+ thisDev->nowReceiving = FALSE;
+
+ /*
+ * Just enable transmit interrupts to start the ball rolling.
+ */
+ SetCOMInterrupts(thisDev, TRUE);
+ }
+ else {
+ DBGERR(("Couldn't convert packet in DoSend()"));
+ }
+
+ DBGOUT(("DoSend done"));
+ return convertedPacket;
+}
+
+
+
+/*
+ *************************************************************************
+ * StepSendFSM
+ *************************************************************************
+ *
+ *
+ * Step the send fsm to send a few more bytes of an IR frame.
+ * Return TRUE only after an entire frame has been sent.
+ *
+ */
+BOOLEAN StepSendFSM(IrDevice *thisDev)
+{
+ UINT i, bytesAtATime, startPos = thisDev->portInfo.writeBufPos;
+ UCHAR lineStatReg;
+ BOOLEAN result;
+ UINT maxLoops;
+
+ /*
+ * Ordinarily, we want to fill the send FIFO once per interrupt.
+ * However, at high speeds the interrupt latency is too slow and
+ * we need to poll inside the ISR to send the whole packet during
+ * the first interrupt.
+ */
+ if (thisDev->currentSpeed >= 115200){
+ maxLoops = REG_TIMEOUT_LOOPS;
+ }
+ else {
+ maxLoops = REG_POLL_LOOPS;
+ }
+
+
+ /*
+ * Write databytes as long as we have them and the UART's FIFO hasn't filled up.
+ */
+ while (thisDev->portInfo.writeBufPos < thisDev->portInfo.writeBufLen){
+
+ /*
+ * If this COM port has a FIFO, we'll send up to the FIFO size (16 bytes).
+ * Otherwise, we can only send one byte at a time.
+ */
+ if (thisDev->portInfo.haveFIFO){
+ bytesAtATime = MIN(FIFO_SIZE, (thisDev->portInfo.writeBufLen - thisDev->portInfo.writeBufPos));
+ }
+ else {
+ bytesAtATime = 1;
+ }
+
+
+ /*
+ * Wait for ready-to-send.
+ */
+ i = 0;
+ do {
+ lineStatReg = GetCOMPort(thisDev->portInfo.ioBase, LINE_STAT_REG_OFFSET);
+ } while (!(lineStatReg & LINESTAT_XMIT_HOLDING_REG_EMPTY) && (++i < maxLoops));
+ if (!(lineStatReg & LINESTAT_XMIT_HOLDING_REG_EMPTY)){
+ break;
+ }
+
+ /*
+ * Send the next byte or FIFO-volume of bytes.
+ */
+ for (i = 0; i < bytesAtATime; i++){
+ SetCOMPort( thisDev->portInfo.ioBase,
+ XFER_REG_OFFSET,
+ thisDev->portInfo.writeBuf[thisDev->portInfo.writeBufPos++]);
+ }
+
+ }
+
+ /*
+ * The return value will indicate whether we've sent the entire frame.
+ */
+ if (thisDev->portInfo.writeBufPos >= thisDev->portInfo.writeBufLen){
+
+ if (thisDev->setSpeedAfterCurrentSendPacket){
+ /*
+ * We'll be changing speeds after this packet,
+ * so poll until the packet bytes have been completely sent out the FIFO.
+ * After the 16550 says that it is empty, there may still be one remaining
+ * byte in the FIFO, so flush it out by sending one more BOF.
+ */
+ i = 0;
+ do {
+ lineStatReg = GetCOMPort(thisDev->portInfo.ioBase, LINE_STAT_REG_OFFSET);
+ } while (!(lineStatReg & 0x20) && (++i < REG_TIMEOUT_LOOPS));
+
+ SetCOMPort(thisDev->portInfo.ioBase, XFER_REG_OFFSET, (UCHAR)SLOW_IR_EXTRA_BOF);
+ i = 0;
+ do {
+ lineStatReg = GetCOMPort(thisDev->portInfo.ioBase, LINE_STAT_REG_OFFSET);
+ } while (!(lineStatReg & 0x20) && (++i < REG_TIMEOUT_LOOPS));
+ }
+
+ result = TRUE;
+ }
+ else {
+ result = FALSE;
+ }
+
+ DBGOUT(("StepSendFSM wrote %d bytes (%s):", (UINT)(thisDev->portInfo.writeBufPos-startPos), (PUCHAR)(result ? "DONE" : "not done")));
+ // DBGPRINTBUF(thisDev->portInfo.writeBuf+startPos, thisDev->portInfo.writeBufPos-startPos);
+
+ return result;
+
+}
+
+
+/*
+ *************************************************************************
+ * StepReceiveFSM
+ *************************************************************************
+ *
+ *
+ * Step the receive fsm to read in a piece of an IR frame;
+ * strip the BOFs and EOF, and eliminate escape sequences.
+ * Return TRUE only after an entire frame has been read in.
+ *
+ */
+BOOLEAN StepReceiveFSM(IrDevice *thisDev)
+{
+ UINT rawBufPos, rawBytesRead;
+ BOOLEAN result;
+ UCHAR thisch;
+
+ DBGOUT(("StepReceiveFSM(%xh)", thisDev->portInfo.ioBase));
+
+ /*
+ * Read in and process groups of incoming bytes from the FIFO.
+ * NOTE: We have to loop once more after getting MAX_RCV_DATA_SIZE
+ * bytes so that we can see the 'EOF'; hence <= and not <.
+ */
+ while ((thisDev->portInfo.rcvState != STATE_SAW_EOF) && (thisDev->portInfo.readBufPos <= MAX_RCV_DATA_SIZE)){
+
+ if (thisDev->portInfo.rcvState == STATE_CLEANUP){
+ /*
+ * We returned a complete packet last time, but we had read some
+ * extra bytes, which we stored into the rawBuf after returning
+ * the previous complete buffer to the user.
+ * So instead of calling DoRcvDirect in this first execution of this loop,
+ * we just use these previously-read bytes.
+ * (This is typically only 1 or 2 bytes).
+ */
+ rawBytesRead = thisDev->portInfo.readBufPos;
+ thisDev->portInfo.rcvState = STATE_INIT;
+ thisDev->portInfo.readBufPos = 0;
+ }
+ else {
+ rawBytesRead = DoRcvDirect(thisDev->portInfo.ioBase, thisDev->portInfo.rawBuf, FIFO_SIZE);
+ if (rawBytesRead == (UINT)-1){
+ /*
+ * Receive error occurred. Go back to INIT state.
+ */
+ thisDev->portInfo.rcvState = STATE_INIT;
+ thisDev->portInfo.readBufPos = 0;
+ continue;
+ }
+ else if (rawBytesRead == 0){
+ /*
+ * No more receive bytes. Break out.
+ */
+ break;
+ }
+ }
+
+ /*
+ * Let the receive state machine process this group of characters
+ * we got from the FIFO.
+ *
+ * NOTE: We have to loop once more after getting MAX_RCV_DATA_SIZE
+ * bytes so that we can see the 'EOF'; hence <= and not <.
+ */
+ for (rawBufPos = 0;
+ ((thisDev->portInfo.rcvState != STATE_SAW_EOF) &&
+ (rawBufPos < rawBytesRead) &&
+ (thisDev->portInfo.readBufPos <= MAX_RCV_DATA_SIZE));
+ rawBufPos++){
+
+ thisch = thisDev->portInfo.rawBuf[rawBufPos];
+
+ switch (thisDev->portInfo.rcvState){
+
+ case STATE_INIT:
+ switch (thisch){
+ case SLOW_IR_BOF:
+ thisDev->portInfo.rcvState = STATE_GOT_BOF;
+ break;
+ case SLOW_IR_EOF:
+ case SLOW_IR_ESC:
+ default:
+ /*
+ * This is meaningless garbage. Scan past it.
+ */
+ break;
+ }
+ break;
+
+ case STATE_GOT_BOF:
+ switch (thisch){
+ case SLOW_IR_BOF:
+ break;
+ case SLOW_IR_EOF:
+ /*
+ * Garbage
+ */
+ DBGERR(("EOF in absorbing-BOFs state in DoRcv"));
+ thisDev->portInfo.rcvState = STATE_INIT;
+ break;
+ case SLOW_IR_ESC:
+ /*
+ * Start of data.
+ * Our first data byte happens to be an ESC sequence.
+ */
+ thisDev->portInfo.readBufPos = 0;
+ thisDev->portInfo.rcvState = STATE_ESC_SEQUENCE;
+ break;
+ default:
+ thisDev->portInfo.readBuf[0] = thisch;
+ thisDev->portInfo.readBufPos = 1;
+ thisDev->portInfo.rcvState = STATE_ACCEPTING;
+ break;
+ }
+ break;
+
+ case STATE_ACCEPTING:
+ switch (thisch){
+ case SLOW_IR_BOF:
+ /*
+ * Meaningless garbage
+ */
+ DBGERR(("BOF during accepting state in DoRcv"));
+ thisDev->portInfo.rcvState = STATE_INIT;
+ thisDev->portInfo.readBufPos = 0;
+ break;
+ case SLOW_IR_EOF:
+ if (thisDev->portInfo.readBufPos < SLOW_IR_ADDR_SIZE +
+ SLOW_IR_CONTROL_SIZE +
+ SLOW_IR_FCS_SIZE){
+ thisDev->portInfo.rcvState = STATE_INIT;
+ thisDev->portInfo.readBufPos = 0;
+ }
+ else {
+ thisDev->portInfo.rcvState = STATE_SAW_EOF;
+ }
+ break;
+ case SLOW_IR_ESC:
+ thisDev->portInfo.rcvState = STATE_ESC_SEQUENCE;
+ break;
+ default:
+ thisDev->portInfo.readBuf[thisDev->portInfo.readBufPos++] = thisch;
+ break;
+ }
+ break;
+
+ case STATE_ESC_SEQUENCE:
+ switch (thisch){
+ case SLOW_IR_EOF:
+ case SLOW_IR_BOF:
+ case SLOW_IR_ESC:
+ /*
+ * ESC + {EOF|BOF|ESC} is an abort sequence
+ */
+ DBGERR(("DoRcv - abort sequence; ABORTING IR PACKET: (got following packet + ESC,%xh)", (UINT)thisch));
+ DBGPRINTBUF(thisDev->portInfo.readBuf, thisDev->portInfo.readBufPos);
+ thisDev->portInfo.rcvState = STATE_INIT;
+ thisDev->portInfo.readBufPos = 0;
+ break;
+
+ case SLOW_IR_EOF^SLOW_IR_ESC_COMP:
+ case SLOW_IR_BOF^SLOW_IR_ESC_COMP:
+ case SLOW_IR_ESC^SLOW_IR_ESC_COMP:
+ thisDev->portInfo.readBuf[thisDev->portInfo.readBufPos++] = thisch ^ SLOW_IR_ESC_COMP;
+ thisDev->portInfo.rcvState = STATE_ACCEPTING;
+ break;
+
+ default:
+ DBGERR(("Unnecessary escape sequence: (got following packet + ESC,%xh", (UINT)thisch));
+ DBGPRINTBUF(thisDev->portInfo.readBuf, thisDev->portInfo.readBufPos);
+
+ thisDev->portInfo.readBuf[thisDev->portInfo.readBufPos++] = thisch ^ SLOW_IR_ESC_COMP;
+ thisDev->portInfo.rcvState = STATE_ACCEPTING;
+ break;
+ }
+ break;
+
+ case STATE_SAW_EOF:
+ default:
+ DBGERR(("Illegal state in DoRcv"));
+ thisDev->portInfo.readBufPos = 0;
+ thisDev->portInfo.rcvState = STATE_INIT;
+ return 0;
+ }
+ }
+ }
+
+
+ /*
+ * Set result and do any post-cleanup.
+ */
+ switch (thisDev->portInfo.rcvState){
+
+ case STATE_SAW_EOF:
+ /*
+ * We've read in the entire packet.
+ * Queue it and return TRUE.
+ * NOTE: QueueReceivePacket will swap the data buffer pointer inside portInfo.
+ */
+ DBGOUT((" *** DoRcv returning with COMPLETE packet, read %d bytes ***", thisDev->portInfo.readBufPos));
+ QueueReceivePacket(thisDev, &thisDev->portInfo.readBuf, thisDev->portInfo.readBufPos);
+ result = TRUE;
+
+ if (rawBufPos < rawBytesRead){
+ /*
+ * This is ugly.
+ * We have some more unprocessed bytes in the raw buffer.
+ * Move these to the beginning of the raw buffer
+ * go to the CLEANUP state, which indicates that these
+ * bytes be used up during the next call.
+ * (This is typically only 1 or 2 bytes).
+ * Note: We can't just leave these in the raw buffer because
+ * we might be supporting connections to multiple COM ports.
+ */
+ memcpy(thisDev->portInfo.rawBuf, &thisDev->portInfo.rawBuf[rawBufPos], rawBytesRead-rawBufPos);
+ thisDev->portInfo.readBufPos = rawBytesRead-rawBufPos;
+ thisDev->portInfo.rcvState = STATE_CLEANUP;
+ }
+ else {
+ thisDev->portInfo.rcvState = STATE_INIT;
+ }
+ break;
+
+ default:
+ if (thisDev->portInfo.readBufPos > MAX_RCV_DATA_SIZE){
+ DBGERR(("Overrun in DoRcv : read %d=%xh bytes:", thisDev->portInfo.readBufPos, thisDev->portInfo.readBufPos));
+ DBGPRINTBUF(thisDev->portInfo.readBuf, thisDev->portInfo.readBufPos);
+ thisDev->portInfo.readBufPos = 0;
+ thisDev->portInfo.rcvState = STATE_INIT;
+ }
+ else {
+ DBGOUT(("DoRcv returning with partial packet, read %d bytes", thisDev->portInfo.readBufPos));
+ }
+ result = FALSE;
+ break;
+ }
+
+ return result;
+}
+
+
+
+/*
+ *************************************************************************
+ * COM_ISR
+ *************************************************************************
+ *
+ *
+ */
+VOID COM_ISR(IrDevice *thisDev, BOOLEAN *claimingInterrupt, BOOLEAN *requireDeferredCallback)
+{
+ UCHAR intId;
+
+ /*
+ * Get the interrupt status register value.
+ */
+ intId = GetCOMPort(thisDev->portInfo.ioBase, INT_ID_AND_FIFO_CNTRL_REG_OFFSET);
+
+
+ if (intId & INTID_INTERRUPT_NOT_PENDING){
+ /*
+ * This is NOT our interrupt.
+ * Set carry bit to pass the interrupt to the next driver in the chain.
+ */
+ *claimingInterrupt = *requireDeferredCallback = FALSE;
+ }
+ else {
+ /*
+ * This is our interrupt
+ */
+
+ *claimingInterrupt = TRUE;
+ *requireDeferredCallback = FALSE;
+
+ while (!(intId & INTID_INTERRUPT_NOT_PENDING)){
+
+ switch (intId & INTID_INTIDMASK){
+
+ case INTID_MODEMSTAT_INT:
+ DBGOUT(("COM INTERRUPT: modem status int"));
+ GetCOMPort(thisDev->portInfo.ioBase, MODEM_STAT_REG_OFFSET);
+ break;
+
+ case INTID_XMITREG_INT:
+ DBGOUT(("COM INTERRUPT: xmit reg empty"));
+
+ if (thisDev->portInfo.writePending){
+
+ /*
+ * Try to send a few more bytes
+ */
+ if (StepSendFSM(thisDev)){
+
+ /*
+ * There are no more bytes to send;
+ * reset interrupts for receive mode.
+ */
+ thisDev->portInfo.writePending = FALSE;
+ SetCOMInterrupts(thisDev, TRUE);
+
+ /*
+ * If we just sent the last frame to be sent at the old speed,
+ * set the hardware to the new speed.
+ */
+ if (thisDev->setSpeedAfterCurrentSendPacket){
+ thisDev->setSpeedAfterCurrentSendPacket = FALSE;
+ SetSpeed(thisDev);
+ }
+
+ /*
+ * Request a DPC so that we can try
+ * to send other pending write packets.
+ */
+ *requireDeferredCallback = TRUE;
+ }
+ }
+
+ break;
+
+ case INTID_RCVDATAREADY_INT:
+ DBGOUT(("COM INTERRUPT: rcv data available!"));
+
+ thisDev->nowReceiving = TRUE;
+
+ if (!thisDev->mediaBusy){
+ thisDev->mediaBusy = TRUE;
+ thisDev->haveIndicatedMediaBusy = FALSE;
+ *requireDeferredCallback = TRUE;
+ }
+
+ if (StepReceiveFSM(thisDev)){
+ /*
+ * The receive engine has accumulated an entire frame.
+ * Request a deferred callback so we can deliver the frame
+ * when not in interrupt context.
+ */
+ *requireDeferredCallback = TRUE;
+ thisDev->nowReceiving = FALSE;
+ }
+
+ break;
+
+ case INTID_RCVLINESTAT_INT:
+ DBGOUT(("COM INTERRUPT: rcv line stat int!"));
+ break;
+ }
+
+ /*
+ * After we service each interrupt condition, we read the line status register.
+ * This clears the current interrupt, and a new interrupt may then appear in
+ * the interrupt-id register.
+ */
+ GetCOMPort(thisDev->portInfo.ioBase, LINE_STAT_REG_OFFSET);
+ intId = GetCOMPort(thisDev->portInfo.ioBase, INT_ID_AND_FIFO_CNTRL_REG_OFFSET);
+
+ }
+ }
+}
+
+
+
+/*
+ *************************************************************************
+ * OpenCOM
+ *************************************************************************
+ *
+ * Initialize UART registers
+ *
+ */
+BOOLEAN OpenCOM(IrDevice *thisDev)
+{
+ BOOLEAN dongleInit;
+ UCHAR intIdReg;
+
+ DBGOUT(("-> OpenCOM"));
+
+ /*
+ * Disable all COM interrupts while setting up.
+ */
+ SetCOMInterrupts(thisDev, FALSE);
+
+ /*
+ * Set request-to-send and clear data-terminal-ready.
+ * Note: ** Bit 3 must be set to enable interrupts.
+ */
+ SetCOMPort(thisDev->portInfo.ioBase, MODEM_CONTROL_REG_OFFSET, 0x0A);
+
+ /*
+ * Set dongle- or part-specific info to default
+ */
+ thisDev->portInfo.hwCaps.supportedSpeedsMask = ALL_SLOW_IRDA_SPEEDS;
+ thisDev->portInfo.hwCaps.turnAroundTime_usec = 5000;
+ thisDev->portInfo.hwCaps.extraBOFsRequired = 0;
+
+ /*
+ * Set the COM port speed to the default 9600 baud.
+ * Some dongles can only receive cmd sequences at this speed.
+ */
+ SetUARTSpeed(thisDev, 9600);
+
+ /*
+ * Do special setup for dongles.
+ */
+ #ifdef IRMINILIB
+ dongleInit = OEM_Interface.initHandler( thisDev->portInfo.ioBase,
+ &thisDev->portInfo.hwCaps,
+ &thisDev->portInfo.dongleContext);
+ #else
+
+ switch (thisDev->transceiverType){
+ case ACTISYS_220L:
+ dongleInit = ACTISYS_Init( thisDev->portInfo.ioBase,
+ &thisDev->portInfo.hwCaps,
+ &thisDev->portInfo.dongleContext);
+ break;
+ case ADAPTEC:
+ dongleInit = ADAPTEC_Init( thisDev->portInfo.ioBase,
+ &thisDev->portInfo.hwCaps,
+ &thisDev->portInfo.dongleContext);
+ break;
+ case CRYSTAL:
+ dongleInit = CRYSTAL_Init( thisDev->portInfo.ioBase,
+ &thisDev->portInfo.hwCaps,
+ &thisDev->portInfo.dongleContext);
+ break;
+ case ESI_9680:
+ dongleInit = ESI_Init( thisDev->portInfo.ioBase,
+ &thisDev->portInfo.hwCaps,
+ &thisDev->portInfo.dongleContext);
+ break;
+ case PARALLAX:
+ dongleInit = PARALLAX_Init( thisDev->portInfo.ioBase,
+ &thisDev->portInfo.hwCaps,
+ &thisDev->portInfo.dongleContext);
+ break;
+ case NSC_DEMO_BD:
+ dongleInit = NSC_DEMO_Init( thisDev->portInfo.ioBase,
+ &thisDev->portInfo.hwCaps,
+ &thisDev->portInfo.dongleContext);
+ break;
+ default:
+ dongleInit = TRUE;
+ break;
+ }
+ #endif
+
+ if (!dongleInit){
+ DBGERR(("Dongle-specific init failed in OpenCOM"));
+ return FALSE;
+ }
+
+ /*
+ * Set speed to default for the entire part.
+ * (This is redundant in most, but not all, cases.)
+ */
+ thisDev->linkSpeedInfo = &supportedBaudRateTable[BAUDRATE_9600];;
+ SetSpeed(thisDev);
+
+ /*
+ * Clear the FIFO control register
+ */
+ SetCOMPort(thisDev->portInfo.ioBase, INT_ID_AND_FIFO_CNTRL_REG_OFFSET, 0x00);
+
+ /*
+ * Set up the FIFO control register to use both read and write FIFOs (if 16650),
+ * and with a receive FIFO trigger level of 1 byte.
+ */
+ SetCOMPort(thisDev->portInfo.ioBase, INT_ID_AND_FIFO_CNTRL_REG_OFFSET, 0x07);
+
+ /*
+ * Check whether we're running on a 16550,which has a 16-byte write FIFO.
+ * In this case, we'll be able to blast up to 16 bytes at a time.
+ */
+ intIdReg = GetCOMPort(thisDev->portInfo.ioBase, INT_ID_AND_FIFO_CNTRL_REG_OFFSET);
+ thisDev->portInfo.haveFIFO = (BOOLEAN)((intIdReg & 0xC0) == 0xC0);
+
+ /*
+ * Start out in receive mode.
+ * We always want to be in receive mode unless we're transmitting a frame.
+ */
+ SetCOMInterrupts(thisDev, TRUE);
+
+ DBGOUT(("OpenCOM succeeded"));
+ return TRUE;
+}
+
+
+/*
+ *************************************************************************
+ * CloseCOM
+ *************************************************************************
+ *
+ */
+VOID CloseCOM(IrDevice *thisDev)
+{
+ /*
+ * Do special deinit for dongles.
+ * Some dongles can only rcv cmd sequences at 9600, so set this speed first.
+ */
+ thisDev->linkSpeedInfo = &supportedBaudRateTable[BAUDRATE_9600];;
+ SetSpeed(thisDev);
+
+ #ifdef IRMINILIB
+ OEM_Interface.deinitHandler(thisDev->portInfo.ioBase, thisDev->portInfo.dongleContext);
+ #else
+ switch (thisDev->transceiverType){
+ case ACTISYS_220L:
+ ACTISYS_Deinit(thisDev->portInfo.ioBase, thisDev->portInfo.dongleContext);
+ break;
+ case ADAPTEC:
+ ADAPTEC_Deinit(thisDev->portInfo.ioBase, thisDev->portInfo.dongleContext);
+ break;
+ case CRYSTAL:
+ CRYSTAL_Deinit(thisDev->portInfo.ioBase, thisDev->portInfo.dongleContext);
+ break;
+ case ESI_9680:
+ ESI_Deinit(thisDev->portInfo.ioBase, thisDev->portInfo.dongleContext);
+ break;
+ case PARALLAX:
+ PARALLAX_Deinit(thisDev->portInfo.ioBase, thisDev->portInfo.dongleContext);
+ break;
+ case NSC_DEMO_BD:
+ NSC_DEMO_Deinit(thisDev->portInfo.ioBase, thisDev->portInfo.dongleContext);
+ break;
+ }
+ #endif
+
+ SetCOMInterrupts(thisDev, FALSE);
+}
+
+
+
+/*
+ *************************************************************************
+ * DoRcvDirect
+ *************************************************************************
+ *
+ * Read up to maxBytes bytes from the UART's receive FIFO.
+ * Return the number of bytes read or (UINT)-1 if an error occurred.
+ *
+ */
+UINT DoRcvDirect(UINT ioBase, UCHAR *data, UINT maxBytes)
+{
+ USHORT bytesRead;
+ UCHAR lineStatReg;
+ UINT i;
+ BOOLEAN goodChar;
+
+ for (bytesRead = 0; bytesRead < maxBytes; bytesRead++){
+
+ /*
+ * Wait for data-ready
+ */
+ i = 0;
+ do {
+ lineStatReg = GetCOMPort(ioBase, LINE_STAT_REG_OFFSET);
+
+ /*
+ * The UART reports framing and break errors as the effected
+ * characters appear on the stack. We drop these characters,
+ * which will probably result in a bad frame checksum.
+ */
+ if (lineStatReg & (LINESTAT_BREAK | LINESTAT_FRAMINGERROR)){
+ UCHAR badch = GetCOMPort(ioBase, XFER_REG_OFFSET);
+ DBGERR(("Bad rcv char %xh (lineStat=%xh)", (UINT)badch, (UINT)lineStatReg));
+ return (UINT)-1;
+ }
+ else if (lineStatReg & LINESTAT_DATAREADY){
+ goodChar = TRUE;
+ }
+ else {
+ /*
+ * No input char ready
+ */
+ goodChar = FALSE;
+ }
+
+ } while (!goodChar && (++i < REG_POLL_LOOPS));
+ if (!goodChar){
+ break;
+ }
+
+ /*
+ * Read in the next data byte
+ */
+ data[bytesRead] = GetCOMPort(ioBase, XFER_REG_OFFSET);
+ }
+
+ #if 0
+ if (bytesRead){
+ DBGOUT(("RAW bytes read:"));
+ DBGPRINTBUF(data, bytesRead);
+ }
+ #endif
+
+ return bytesRead;
+}
+
+
+/*
+ * These are wrappers for the OEM dongle interface.
+ * Sloppy things start to happen if they have to include ndis.h .
+ * This way, OEM's only include dongle.h .
+ */
+void _cdecl IRMINI_RawReadPort(UINT IOaddr, UCHAR *valPtr)
+{
+ NdisRawReadPortUchar(IOaddr, valPtr);
+}
+void _cdecl IRMINI_RawWritePort(UINT IOaddr, UCHAR val)
+{
+ NdisRawWritePortUchar(IOaddr, val);
+}
+void _cdecl IRMINI_StallExecution(UINT usec)
+{
+ /*
+ * Stalling for over 8ms causes a task switch,
+ * so break up the stall duration.
+ */
+ while (usec){
+ UINT thisTime = MIN(usec, 5000);
+ NdisStallExecution(thisTime);
+ usec -= thisTime;
+ }
+}
+UINT _cdecl IRMINI_GetSystemTime_msec()
+{
+ LONGLONG systime_usec;
+ NdisGetCurrentSystemTime(&systime_usec);
+ return (UINT)(systime_usec/1000);
+}
+
diff --git a/private/ntos/ndis/irmini/comm.h b/private/ntos/ndis/irmini/comm.h
new file mode 100644
index 000000000..2ce431b32
--- /dev/null
+++ b/private/ntos/ndis/irmini/comm.h
@@ -0,0 +1,194 @@
+/*
+ ************************************************************************
+ *
+ * COMM.h
+ *
+ * IRMINI Infrared Serial NDIS Miniport driver.
+ *
+ * (C) Copyright 1996 Microsoft Corp.
+ *
+ *
+ * (ep)
+ *
+ *************************************************************************
+ */
+
+
+#ifndef COMM_H
+ #define COMM_H
+
+ /*
+ * Size of the 16550 read and write FIFOs
+ */
+ #define FIFO_SIZE 16
+
+ /*
+ * The programming interface to a UART (COM serial port)
+ * consists of eight consecutive registers.
+ * These are the port offsets from the UART's base I/O address.
+ */
+ typedef enum comPortRegOffsets {
+ XFER_REG_OFFSET = 0,
+ INT_ENABLE_REG_OFFSET = 1,
+ INT_ID_AND_FIFO_CNTRL_REG_OFFSET = 2,
+ LINE_CONTROL_REG_OFFSET = 3,
+ MODEM_CONTROL_REG_OFFSET = 4,
+ LINE_STAT_REG_OFFSET = 5,
+ MODEM_STAT_REG_OFFSET = 6,
+ SCRATCH_REG_OFFSET = 7
+ } comPortRegOffset;
+
+
+ /*
+ * Bits in the UART Interrupt-Id register.
+ */
+ #define INTID_INTERRUPT_NOT_PENDING (UCHAR)(1 << 0)
+
+ /*
+ * Values for bits 2-1 of Interrupt-Id register:
+ * 00 Modem Stat reg interrupt
+ * 01 Transmitter holding reg interrupt
+ * 10 Receive data ready interrupt
+ * 11 Receive line status interrupt
+ *
+ */
+ #define INTID_INTIDMASK (UCHAR)(3 << 1)
+ #define INTID_MODEMSTAT_INT (UCHAR)(0 << 1)
+ #define INTID_XMITREG_INT (UCHAR)(1 << 1)
+ #define INTID_RCVDATAREADY_INT (UCHAR)(2 << 1)
+ #define INTID_RCVLINESTAT_INT (UCHAR)(3 << 1)
+
+
+
+ /*
+ * Bits in the UART line-status register.
+ */
+ #define LINESTAT_DATAREADY (UCHAR)(1 << 0)
+ #define LINESTAT_OVERRUNERROR (UCHAR)(1 << 1)
+ #define LINESTAT_PARITYERROR (UCHAR)(1 << 2)
+ #define LINESTAT_FRAMINGERROR (UCHAR)(1 << 3)
+ #define LINESTAT_BREAK (UCHAR)(1 << 4)
+ #define LINESTAT_XMIT_HOLDING_REG_EMPTY (UCHAR)(1 << 5)
+ #define LINESTAT_XMIT_SHIFT_AND_HOLDING_REG_EMPTY (UCHAR)(1 << 6)
+
+
+ /*
+ * These are bits in the UART's interrupt-enable register (INT_ENABLE_REG_OFFSET).
+ */
+ #define DATA_AVAIL_INT_ENABLE (1 << 0)
+ #define READY_FOR_XMIT_INT_ENABLE (1 << 1)
+ #define RCV_LINE_STAT_INT_ENABLE (1 << 2)
+ #define MODEM_STAT_INT_ENABLE (1 << 3)
+
+ #define RCV_MODE_INTS_ENABLE (DATA_AVAIL_INT_ENABLE)
+ #define XMIT_MODE_INTS_ENABLE (READY_FOR_XMIT_INT_ENABLE|DATA_AVAIL_INT_ENABLE)
+ #define ALL_INTS_ENABLE (RCV_MODE_INTS_ENABLE | XMIT_MODE_INTS_ENABLE)
+ #define ALL_INTS_DISABLE 0
+
+ /*
+ * Some UART transceivers have minor differences which require
+ * special treatment. We'll get the actual type out of the
+ * registry.
+ *
+ * Note that this enumeration must match that in irmini.inf.
+ */
+ typedef enum irTransceiverType {
+ STANDARD_UART = 0,
+ ESI_9680 = 1,
+ ACTISYS_220L = 2,
+ CRYSTAL = 3,
+ ADAPTEC = 4,
+ PARALLAX = 5,
+ NSC_DEMO_BD = 6, // NSC PC87108 demo board
+
+ NUM_TRANSCEIVER_TYPES
+ } irTransceiverType;
+
+ /*
+ * These are fine-tuning parameters for the COM port ISR.
+ * Number of times we poll a COM port register waiting
+ * for a value which may/must appear.
+ */
+ #define REG_POLL_LOOPS 2
+ #define REG_TIMEOUT_LOOPS 1000000
+
+
+ typedef enum {
+ STATE_INIT = 0,
+ STATE_GOT_BOF,
+ STATE_ACCEPTING,
+ STATE_ESC_SEQUENCE,
+ STATE_SAW_EOF,
+ STATE_CLEANUP
+ } portRcvState;
+
+
+
+ /*
+ * This is the information that we need to keep for each COMM port.
+ */
+ typedef struct {
+
+ /*
+ * HW resource settings for COM port.
+ */
+ UINT irq;
+ UINT ioBase;
+
+ /*
+ * Is this COM port a 16550 with a 16-byte FIFO or
+ * a 16450/8250 with no FIFO ?
+ */
+ BOOLEAN haveFIFO;
+
+ /*
+ * Data for our rcv state machine.
+ */
+ UCHAR rawBuf[FIFO_SIZE];
+ PUCHAR readBuf;
+ UINT readBufPos;
+ portRcvState rcvState;
+
+ /*
+ * Data for send state machine
+ */
+ UCHAR writeBuf[MAX_IRDA_DATA_SIZE];
+ UINT writeBufPos;
+ UINT writeBufLen;
+ BOOLEAN writePending;
+
+ /*
+ * Dongle or part-specific information
+ */
+ dongleCapabilities hwCaps;
+ UINT dongleContext;
+
+ } comPortInfo;
+
+
+ extern USHORT comPortIOBase[];
+
+ /*
+ *************************************************************************
+ * GetCOMPort
+ *************************************************************************
+ */
+ UCHAR __inline GetCOMPort(UINT comBase, comPortRegOffset portOffset)
+ {
+ UCHAR val;
+ NdisRawReadPortUchar(comBase+portOffset, &val);
+ return val;
+ }
+
+ /*
+ *************************************************************************
+ * SetCOMPort
+ *************************************************************************
+ */
+ VOID __inline SetCOMPort(UINT comBase, comPortRegOffset portOffset, UCHAR val)
+ {
+ NdisRawWritePortUchar(comBase+portOffset, val);
+ }
+
+
+#endif COMM_H
diff --git a/private/ntos/ndis/irmini/convert.c b/private/ntos/ndis/irmini/convert.c
new file mode 100644
index 000000000..2275b4f54
--- /dev/null
+++ b/private/ntos/ndis/irmini/convert.c
@@ -0,0 +1,228 @@
+/*
+ ************************************************************************
+ *
+ * CONVERT.c
+ *
+ * IRMINI Infrared Serial NDIS Miniport driver.
+ *
+ * (C) Copyright 1996 Microsoft Corp.
+ *
+ *
+ * (ep)
+ *
+ *************************************************************************
+ */
+
+
+
+#include "irmini.h"
+
+
+
+/*
+ *************************************************************************
+ * NdisToIrPacket
+ *************************************************************************
+ *
+ *
+ * Convert an NDIS Packet into an IR packet.
+ * Write the IR packet into the provided buffer and report its actual size.
+ *
+ * If failing, *irPacketLen will contain the buffer size that
+ * the caller should retry with (or 0 if a corruption was detected).
+ *
+ */
+BOOLEAN NdisToIrPacket( IrDevice *thisDev,
+ PNDIS_PACKET Packet,
+ UCHAR *irPacketBuf,
+ UINT irPacketBufLen,
+ UINT *irPacketLen
+ )
+{
+ static UCHAR contigPacketBuf[MAX_IRDA_DATA_SIZE];
+ PNDIS_BUFFER ndisBuf;
+ UINT i, ndisPacketBytes = 0, I_fieldBytes, totalBytes = 0;
+ UINT ndisPacketLen, numExtraBOFs;
+ SLOW_IR_FCS_TYPE fcs, tmpfcs;
+ UCHAR fcsBuf[SLOW_IR_FCS_SIZE*2];
+ UINT fcsLen=0;
+ PNDIS_IRDA_PACKET_INFO packetInfo = GetPacketInfo(Packet);
+ UCHAR nextChar;
+
+ DBGOUT(("NdisToIrPacket() ..."));
+
+ /*
+ * Get the packet's entire length and its first NDIS buffer
+ */
+ NdisQueryPacket(Packet, NULL, NULL, &ndisBuf, &ndisPacketLen);
+
+ /*
+ * Make sure that the packet is big enough to be legal.
+ * It consists of an A, C, and variable-length I field.
+ */
+ if (ndisPacketLen < SLOW_IR_ADDR_SIZE + SLOW_IR_CONTROL_SIZE){
+ DBGERR(("packet too short in NdisToIrPacket (%d bytes)", ndisPacketLen));
+ return FALSE;
+ }
+ else {
+ I_fieldBytes = ndisPacketLen - SLOW_IR_ADDR_SIZE - SLOW_IR_CONTROL_SIZE;
+ }
+
+ /*
+ * Make sure that we won't overwrite our contiguous buffer.
+ * Make sure that the passed-in buffer can accomodate this packet's
+ * data no matter how much it grows through adding ESC-sequences, etc.
+ */
+ if ((ndisPacketLen > MAX_IRDA_DATA_SIZE) ||
+ (MAX_POSSIBLE_IR_PACKET_SIZE_FOR_DATA(I_fieldBytes) > irPacketBufLen)){
+
+ /*
+ * The packet is too large
+ * Tell the caller to retry with a packet size large
+ * enough to get past this stage next time.
+ */
+ DBGERR(("Packet too large in NdisToIrPacket (%d=%xh bytes), MAX_IRDA_DATA_SIZE=%d, irPacketBufLen=%d.",
+ ndisPacketLen, ndisPacketLen, MAX_IRDA_DATA_SIZE, irPacketBufLen));
+ *irPacketLen = ndisPacketLen;
+ return FALSE;
+ }
+
+
+
+ /*
+ * First, read the NDIS packet into a contiguous buffer.
+ * We have to do this in two steps so that we can compute the
+ * FCS BEFORE applying escape-byte transparency.
+ */
+ while (ndisBuf){
+ UCHAR *bufData;
+ UINT bufLen;
+
+ NdisQueryBuffer(ndisBuf, (PVOID *)&bufData, &bufLen);
+
+ if (ndisPacketBytes + bufLen > ndisPacketLen){
+ /*
+ * Packet was corrupt -- it misreported its size.
+ */
+ *irPacketLen = 0;
+ return FALSE;
+ }
+
+ NdisMoveMemory((PVOID)(contigPacketBuf+ndisPacketBytes), (PVOID)bufData, bufLen);
+ ndisPacketBytes += bufLen;
+
+ NdisGetNextBuffer(ndisBuf, &ndisBuf);
+ }
+
+ /*
+ * Do a sanity check on the length of the packet.
+ */
+ if (ndisPacketBytes != ndisPacketLen){
+ /*
+ * Packet was corrupt -- it misreported its size.
+ */
+ DBGERR(("Packet corrupt in NdisToIrPacket (buffer lengths don't add up to packet length)."));
+ *irPacketLen = 0;
+ return FALSE;
+ }
+
+
+ #ifdef DBG_ADD_PKT_ID
+ if (addPktIdOn){
+ static USHORT uniqueId = 0;
+ *(USHORT *)(contigPacketBuf+ndisPacketBytes) = uniqueId++;
+ ndisPacketBytes += sizeof(USHORT);
+ }
+ #endif
+
+ /*
+ * Compute the FCS on the packet BEFORE applying transparency fixups.
+ * The FCS also must be sent using ESC-char transparency, so figure
+ * out how large the fcs will really be.
+ */
+ fcs = ComputeFCS(contigPacketBuf, ndisPacketBytes);
+ for (i = 0, tmpfcs = fcs, fcsLen = 0; i < SLOW_IR_FCS_SIZE; tmpfcs >>= 8, i++){
+ UCHAR fcsbyte = tmpfcs & 0x00ff;
+ switch (fcsbyte){
+ case SLOW_IR_BOF:
+ case SLOW_IR_EOF:
+ case SLOW_IR_ESC:
+ fcsBuf[fcsLen++] = SLOW_IR_ESC;
+ fcsBuf[fcsLen++] = fcsbyte ^ SLOW_IR_ESC_COMP;
+ break;
+
+ default:
+ fcsBuf[fcsLen++] = fcsbyte;
+ break;
+ }
+ }
+
+
+ /*
+ * Now begin building the IR frame.
+ *
+ * This is the final format:
+ *
+ * BOF (1)
+ * extra BOFs ...
+ * NdisMediumIrda packet (what we get from NDIS):
+ * Address (1)
+ * Control (1)
+ * FCS (2)
+ * EOF (1)
+ */
+
+ /*
+ * Prepend BOFs (extra BOFs + 1 actual BOF)
+ */
+ numExtraBOFs = packetInfo->ExtraBOFs;
+ if (numExtraBOFs > MAX_NUM_EXTRA_BOFS){
+ numExtraBOFs = MAX_NUM_EXTRA_BOFS;
+ }
+ for (i = totalBytes = 0; i < numExtraBOFs; i++){
+ *(SLOW_IR_BOF_TYPE *)(irPacketBuf+totalBytes) = SLOW_IR_EXTRA_BOF;
+ totalBytes += SLOW_IR_EXTRA_BOF_SIZE;
+ }
+ *(SLOW_IR_BOF_TYPE *)(irPacketBuf+totalBytes) = SLOW_IR_BOF;
+ totalBytes += SLOW_IR_BOF_SIZE;
+
+ /*
+ * Copy the NDIS packet from our contiguous buffer,
+ * applying escape-char transparency.
+ */
+ for (i = 0; i < ndisPacketBytes; i++){
+ nextChar = contigPacketBuf[i];
+
+ switch (nextChar){
+ case SLOW_IR_BOF:
+ case SLOW_IR_EOF:
+ case SLOW_IR_ESC:
+ irPacketBuf[totalBytes++] = SLOW_IR_ESC;
+ irPacketBuf[totalBytes++] = nextChar ^ SLOW_IR_ESC_COMP;
+ break;
+
+ default:
+ irPacketBuf[totalBytes++] = nextChar;
+ break;
+ }
+ }
+
+
+ /*
+ * Add FCS, EOF.
+ */
+ NdisMoveMemory((PVOID)(irPacketBuf+totalBytes), (PVOID)fcsBuf, fcsLen);
+ totalBytes += fcsLen;
+ *(SLOW_IR_EOF_TYPE *)(irPacketBuf+totalBytes) = (UCHAR)SLOW_IR_EOF;
+ totalBytes += SLOW_IR_EOF_SIZE;
+
+ *irPacketLen = totalBytes;
+
+ DBGOUT(("... NdisToIrPacket converted %d-byte ndis pkt to %d-byte irda pkt:", ndisPacketLen, *irPacketLen));
+
+ return TRUE;
+
+}
+
+
+
diff --git a/private/ntos/ndis/irmini/crystal.c b/private/ntos/ndis/irmini/crystal.c
new file mode 100644
index 000000000..108f4df7b
--- /dev/null
+++ b/private/ntos/ndis/irmini/crystal.c
@@ -0,0 +1,373 @@
+/*
+ * CRYSTAL.C
+ *
+ *
+ *
+ */
+
+
+#ifndef IRMINILIB
+
+ #include "dongle.h"
+
+
+ /*
+ * The programming interface to a UART (COM serial port)
+ * consists of eight consecutive registers.
+ * These are the port offsets from the UART's base I/O address.
+ */
+ typedef enum comPortRegOffsets {
+ XFER_REG_OFFSET = 0,
+ INT_ENABLE_REG_OFFSET = 1,
+ INT_ID_AND_FIFO_CNTRL_REG_OFFSET = 2,
+ LINE_CONTROL_REG_OFFSET = 3,
+ MODEM_CONTROL_REG_OFFSET = 4,
+ LINE_STAT_REG_OFFSET = 5,
+ MODEM_STAT_REG_OFFSET = 6,
+ SCRATCH_REG_OFFSET = 7
+ } comPortRegOffset;
+
+
+ /*
+ * Bits in the UART line-status register.
+ */
+ #define LINESTAT_DATAREADY (UCHAR)(1 << 0)
+ #define LINESTAT_OVERRUNERROR (UCHAR)(1 << 1)
+ #define LINESTAT_PARITYERROR (UCHAR)(1 << 2)
+ #define LINESTAT_FRAMINGERROR (UCHAR)(1 << 3)
+ #define LINESTAT_BREAK (UCHAR)(1 << 4)
+ #define LINESTAT_XMIT_HOLDING_REG_EMPTY (UCHAR)(1 << 5)
+ #define LINESTAT_XMIT_SHIFT_AND_HOLDING_REG_EMPTY (UCHAR)(1 << 6)
+
+
+ #define CRYSTAL_IRDA_SPEEDS ( \
+ NDIS_IRDA_SPEED_2400 | \
+ NDIS_IRDA_SPEED_9600 | \
+ NDIS_IRDA_SPEED_19200 | \
+ NDIS_IRDA_SPEED_38400 | \
+ NDIS_IRDA_SPEED_57600 | \
+ NDIS_IRDA_SPEED_115200 \
+ )
+
+
+
+ /*
+ * Command sequences for configuring CRYSTAL chip.
+ */
+ UCHAR CrystalSetPrimaryRegisterSet[] = { 0xD0 };
+ UCHAR CrystalSetSecondaryRegisterSet[] = { 0xD1 };
+ UCHAR CrystalSetSpeed2400[] = { 0x10, 0x8F, 0x95, 0x11 };
+ UCHAR CrystalSetSpeed9600[] = { 0x10, 0x87, 0x91, 0x11 };
+ UCHAR CrystalSetSpeed19200[] = { 0x10, 0x8B, 0x90, 0x11 };
+ UCHAR CrystalSetSpeed38400[] = { 0x10, 0x85, 0x90, 0x11 };
+ UCHAR CrystalSetSpeed57600[] = { 0x10, 0x83, 0x90, 0x11 };
+ UCHAR CrystalSetSpeed115200[] = { 0x10, 0x81, 0x90, 0x11 };
+ UCHAR CrystalSetIrdaMode[] = { 0x0B, 0x53, 0x47, 0x63, 0x74, 0xD1, 0x56, 0xD0 };
+ UCHAR CrystalSetASKMode[] = { 0x0b, 0x43, 0x62, 0x54 };
+ UCHAR CrystalSetLowPower[] = { 0x09, 0x00 };
+
+
+
+
+ /*
+ *************************************************************************
+ * CrystalWrite
+ *************************************************************************
+ *
+ */
+ BOOLEAN CrystalWrite(UINT comBase, UCHAR *data, UINT numBytes)
+ {
+ UINT i;
+ UCHAR lineStatReg;
+ BOOLEAN result = TRUE;
+
+ /*
+ * Write databytes as long as we have them and the UART's FIFO hasn't filled up.
+ */
+ while (numBytes){
+
+ /*
+ * Wait for ready-to-send.
+ */
+ i = 0;
+ do {
+ IRMINI_RawReadPort(comBase+LINE_STAT_REG_OFFSET, &lineStatReg);
+ IRMINI_StallExecution(20000);
+ } while (!(lineStatReg & LINESTAT_XMIT_HOLDING_REG_EMPTY) && (++i < 4));
+ if (!(lineStatReg & LINESTAT_XMIT_HOLDING_REG_EMPTY)){
+ result = FALSE;
+ break;
+ }
+
+ /*
+ * Send the next byte.
+ */
+ IRMINI_RawWritePort(comBase+XFER_REG_OFFSET, *data++);
+ IRMINI_StallExecution(20000);
+ numBytes--;
+ }
+
+ return result;
+ }
+
+
+ BOOLEAN CrystalRead(UINT comBase, UCHAR *data, UINT numBytes)
+ {
+ UINT i;
+ UCHAR lineStatReg;
+
+ while (numBytes--){
+ i = 0;
+ do {
+ IRMINI_RawReadPort(comBase+LINE_STAT_REG_OFFSET, &lineStatReg);
+ IRMINI_StallExecution(10000);
+ } while (!(lineStatReg & LINESTAT_DATAREADY) && (++i < 10));
+
+ if (lineStatReg & LINESTAT_DATAREADY){
+ IRMINI_RawReadPort(comBase+XFER_REG_OFFSET, data++);
+ IRMINI_StallExecution(10000);
+ return TRUE;
+ }
+ else {
+ return FALSE;
+ }
+ }
+ }
+
+
+ BOOLEAN CrystalWriteCmdString(UINT comBase, UCHAR *cmds, UINT len)
+ {
+ UCHAR byte;
+
+ /*
+ * Clear read FIFO
+ */
+ while (CrystalRead(comBase, &byte, 1)){ }
+
+ while (len--){
+ UCHAR thisByte = *cmds++;
+
+ if (!CrystalWrite(comBase, &thisByte, 1)){
+ return FALSE;
+ }
+
+ if (!CrystalRead(comBase, &byte, 1)){
+ return FALSE;
+ }
+
+ if (byte != thisByte){
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+ }
+
+
+ BOOLEAN CrystalReadRev(UINT comBase, UCHAR *rev)
+ {
+ UCHAR readval, writeval = 0xC0;
+
+ /*
+ * Set secondary register set
+ */
+ if (!CrystalWriteCmdString(comBase, CrystalSetSecondaryRegisterSet, sizeof(CrystalSetSecondaryRegisterSet))){
+ return FALSE;
+ }
+
+ if (!CrystalWrite(comBase, &writeval, 1)){
+ return FALSE;
+ }
+
+ if (!CrystalRead(comBase, &readval, 1)){
+ return FALSE;
+ }
+
+ if ((readval & 0xF0) != writeval){
+ return FALSE;
+ }
+
+ *rev = (readval & 0x0F);
+
+ /*
+ * Switch back to primary register set
+ */
+ if (!CrystalWriteCmdString(comBase, CrystalSetPrimaryRegisterSet, sizeof(CrystalSetPrimaryRegisterSet))){
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+
+ /*
+ * CrystalSetIrDAMode
+ *
+ * Returns with Crystal chip in command mode.
+ */
+ BOOLEAN CrystalSetIrDAMode(UINT comBase, UCHAR *crystalRev)
+ {
+ UINT attempts;
+ BOOLEAN result = FALSE;
+ UCHAR modemCntrlVal;
+
+ IRMINI_RawReadPort(comBase+MODEM_CONTROL_REG_OFFSET, &modemCntrlVal);
+
+ /*
+ * Try to set IrDA mode up to five times
+ */
+ for (attempts = 0; !result && (attempts < 5); attempts++){
+ /*
+ * Reset and leave Crystal in command mode (DTR high)
+ */
+ modemCntrlVal |= 3;
+ IRMINI_RawWritePort(comBase+MODEM_CONTROL_REG_OFFSET, modemCntrlVal);
+ IRMINI_StallExecution(50000);
+ modemCntrlVal &= ~2;
+ IRMINI_RawWritePort(comBase+MODEM_CONTROL_REG_OFFSET, modemCntrlVal);
+ IRMINI_StallExecution(50000);
+
+ /*
+ * Set IrDA mode.
+ */
+ if (CrystalWriteCmdString(comBase, CrystalSetIrdaMode, sizeof(CrystalSetIrdaMode)) &&
+ CrystalReadRev(comBase, crystalRev)){
+
+ result = TRUE;
+ }
+ }
+
+ return result;
+ }
+
+
+ /*
+ * CRYSTAL_Init
+ *
+ *
+ *
+ */
+ BOOLEAN CRYSTAL_Init(UINT comBase, dongleCapabilities *caps, UINT *context)
+ {
+ UCHAR modemCntrlVal, crystalRev;
+
+ IRMINI_RawReadPort(comBase+MODEM_CONTROL_REG_OFFSET, &modemCntrlVal);
+
+ /*
+ * Set command mode
+ */
+ modemCntrlVal |= 1;
+ IRMINI_RawWritePort(comBase+MODEM_CONTROL_REG_OFFSET, modemCntrlVal);
+
+ /*
+ * Set IrDA mode
+ */
+ if (!CrystalSetIrDAMode(comBase, &crystalRev)){
+ return FALSE;
+ }
+
+ /*
+ * Clear command mode
+ */
+ modemCntrlVal &= ~1;
+ IRMINI_RawWritePort(comBase+MODEM_CONTROL_REG_OFFSET, modemCntrlVal);
+ IRMINI_StallExecution(50000);
+
+ caps->supportedSpeedsMask = CRYSTAL_IRDA_SPEEDS;
+ if (crystalRev == 0x01){
+ /*
+ * This is rev C, which doesn't support 115.2 Kb.
+ */
+ caps->supportedSpeedsMask &= ~NDIS_IRDA_SPEED_115200;
+ }
+ caps->turnAroundTime_usec = 5000;
+ caps->extraBOFsRequired = 0;
+
+ *context = 0;
+
+ return TRUE;
+ }
+
+
+ /*
+ * CRYSTAL_Deinit
+ *
+ * NOTE: This function assumes that the UART speed has been set to 9600.
+ *
+ */
+ VOID CRYSTAL_Deinit(UINT comBase, UINT context)
+ {
+ /*
+ * Set low-power mode
+ */
+ CrystalWrite(comBase, CrystalSetLowPower, sizeof(CrystalSetLowPower));
+
+ /*
+ * Clear command mode
+ */
+ IRMINI_RawWritePort(comBase+MODEM_CONTROL_REG_OFFSET, 0);
+ IRMINI_StallExecution(50000);
+ }
+
+
+
+ /*
+ * CRYSTAL_SetSpeed
+ *
+ * This function assumes that the UART speed has been scaled back
+ * to 9600 baud for this call.
+ *
+ */
+ BOOLEAN CRYSTAL_SetSpeed(UINT comBase, UINT bitsPerSec, UINT context)
+ {
+ UCHAR modemCntrlVal;
+ UCHAR *cmdString;
+ BOOLEAN result = TRUE;
+
+ switch (bitsPerSec){
+ case 2400: cmdString = CrystalSetSpeed2400; break;
+ case 9600: cmdString = CrystalSetSpeed9600; break;
+ case 19200: cmdString = CrystalSetSpeed19200; break;
+ case 38400: cmdString = CrystalSetSpeed38400; break;
+ case 57600: cmdString = CrystalSetSpeed57600; break;
+ case 115200: cmdString = CrystalSetSpeed115200; break;
+ default: return FALSE;
+ }
+
+ /*
+ * Set data-terminal-ready to enter command mode.
+ */
+ IRMINI_RawReadPort(comBase+MODEM_CONTROL_REG_OFFSET, &modemCntrlVal);
+ modemCntrlVal |= 1;
+ IRMINI_RawWritePort(comBase+MODEM_CONTROL_REG_OFFSET, modemCntrlVal);
+ IRMINI_StallExecution(50000);
+
+ /*
+ * Send the cmd string to set speed.
+ * All the set-speed cmd strings have length 4.
+ */
+ if (!CrystalWriteCmdString(comBase, cmdString, 4)){
+ UCHAR rev;
+
+ /*
+ * Try one more time, after resetting IrDA mode.
+ */
+ if (!(CrystalSetIrDAMode(comBase, &rev) &&
+ CrystalWriteCmdString(comBase, cmdString, 4))){
+ result = FALSE;
+ }
+ }
+
+ /*
+ * Clear data-terminal-ready to exit command mode
+ * whether or not we succeeded.
+ */
+ IRMINI_RawReadPort(comBase+MODEM_CONTROL_REG_OFFSET, &modemCntrlVal);
+ modemCntrlVal &= ~1;
+ IRMINI_RawWritePort(comBase+MODEM_CONTROL_REG_OFFSET, modemCntrlVal);
+ IRMINI_StallExecution(50000);
+
+ return result;
+ }
+
+#endif
diff --git a/private/ntos/ndis/irmini/crystal.h b/private/ntos/ndis/irmini/crystal.h
new file mode 100644
index 000000000..d2425d5a3
--- /dev/null
+++ b/private/ntos/ndis/irmini/crystal.h
@@ -0,0 +1,20 @@
+/*
+ * CRYSTAL.H
+ *
+ *
+ *
+ */
+
+#include "dongle.h"
+
+#ifndef CRYSTAL_H
+ #define CRYSTAL_H
+
+ BOOLEAN CRYSTAL_Init(UINT comBase, dongleCapabilities *caps, UINT *context);
+ VOID CRYSTAL_Deinit(UINT comBase, UINT context);
+ BOOLEAN CRYSTAL_SetSpeed(UINT comBase, UINT bitsPerSec, UINT context);
+
+#endif CRYSTAL_H
+
+
+
diff --git a/private/ntos/ndis/irmini/dongle.h b/private/ntos/ndis/irmini/dongle.h
new file mode 100644
index 000000000..cc8ffd793
--- /dev/null
+++ b/private/ntos/ndis/irmini/dongle.h
@@ -0,0 +1,80 @@
+/*
+ * DONGLE.H
+ *
+ *
+ *
+ */
+
+#ifndef DONGLE_H
+ #define DONGLE_H
+
+
+ #define NDIS_IRDA_SPEED_2400 (UINT)(1 << 0) // SLOW IR ...
+ #define NDIS_IRDA_SPEED_9600 (UINT)(1 << 1)
+ #define NDIS_IRDA_SPEED_19200 (UINT)(1 << 2)
+ #define NDIS_IRDA_SPEED_38400 (UINT)(1 << 3)
+ #define NDIS_IRDA_SPEED_57600 (UINT)(1 << 4)
+ #define NDIS_IRDA_SPEED_115200 (UINT)(1 << 5)
+ #define NDIS_IRDA_SPEED_576K (UINT)(1 << 6) // MEDIUM IR ...
+ #define NDIS_IRDA_SPEED_1152K (UINT)(1 << 7)
+ #define NDIS_IRDA_SPEED_4M (UINT)(1 << 8) // FAST IR
+
+ typedef unsigned int UINT;
+ typedef unsigned char UCHAR;
+ typedef unsigned char BOOLEAN;
+ #undef VOID
+ #define VOID void
+ #undef FALSE
+ #define FALSE ((BOOLEAN)0)
+ #undef TRUE
+ #define TRUE (!FALSE)
+
+ typedef struct dongleCapabilities {
+
+ /*
+ * This is a mask of NDIS_IRDA_SPEED_xxx bit values.
+ *
+ */
+ UINT supportedSpeedsMask;
+
+ /*
+ * Time (in microseconds) that must transpire between
+ * a transmit and the next receive.
+ */
+ UINT turnAroundTime_usec;
+
+ /*
+ * Extra BOF (Beginning Of Frame) characters required
+ * at the start of each received frame.
+ */
+ UINT extraBOFsRequired;
+
+ } dongleCapabilities;
+
+
+ typedef BOOLEAN (_stdcall *IRMINI_INIT_HANDLER)
+ (UINT comBase, dongleCapabilities *caps, UINT *context);
+ typedef void (_stdcall *IRMINI_DEINIT_HANDLER)
+ (UINT comBase, UINT context);
+ typedef BOOLEAN (_stdcall *IRMINI_SETSPEED_HANDLER)
+ (UINT comBase, UINT bitsPerSec, UINT context);
+
+ typedef struct IRMINI_Dongle_Interface
+ {
+ IRMINI_INIT_HANDLER initHandler;
+ IRMINI_SETSPEED_HANDLER setSpeedHandler;
+ IRMINI_DEINIT_HANDLER deinitHandler;
+ } IRMINI_Dongle_Interface;
+
+
+ /*
+ * A dongle module should not use any NDIS functions directly.
+ * It should only use these wrapper functions to access hardware.
+ */
+ extern void _cdecl IRMINI_RawReadPort(UINT IOaddr, UCHAR *val);
+ extern void _cdecl IRMINI_RawWritePort(UINT IOaddr, UCHAR val);
+ extern void _cdecl IRMINI_StallExecution(UINT usec);
+ extern UINT _cdecl IRMINI_GetSystemTime_msec();
+
+#endif DONGLE_H
+
diff --git a/private/ntos/ndis/irmini/esi.c b/private/ntos/ndis/irmini/esi.c
new file mode 100644
index 000000000..860f9e768
--- /dev/null
+++ b/private/ntos/ndis/irmini/esi.c
@@ -0,0 +1,99 @@
+/*
+ * ESI.C
+ *
+ *
+ *
+ */
+
+#ifndef IRMINILIB
+
+ #include "dongle.h"
+
+
+ /*
+ * The programming interface to a UART (COM serial port)
+ * consists of eight consecutive registers.
+ * These are the port offsets from the UART's base I/O address.
+ */
+ typedef enum comPortRegOffsets {
+ XFER_REG_OFFSET = 0,
+ INT_ENABLE_REG_OFFSET = 1,
+ INT_ID_AND_FIFO_CNTRL_REG_OFFSET = 2,
+ LINE_CONTROL_REG_OFFSET = 3,
+ MODEM_CONTROL_REG_OFFSET = 4,
+ LINE_STAT_REG_OFFSET = 5,
+ MODEM_STAT_REG_OFFSET = 6,
+ SCRATCH_REG_OFFSET = 7
+ } comPortRegOffset;
+
+
+ #define ESI_9680_IRDA_SPEEDS ( NDIS_IRDA_SPEED_9600 | \
+ NDIS_IRDA_SPEED_19200 | \
+ NDIS_IRDA_SPEED_115200 \
+ )
+
+
+ BOOLEAN ESI_Init(UINT comBase, dongleCapabilities *caps, UINT *context)
+ {
+ caps->supportedSpeedsMask = ESI_9680_IRDA_SPEEDS;
+ caps->turnAroundTime_usec = 5000;
+ caps->extraBOFsRequired = 0;
+
+ *context = 0;
+
+ return TRUE;
+ }
+
+ VOID ESI_Deinit(UINT comBase, UINT context)
+ {
+
+ }
+
+ BOOLEAN ESI_SetSpeed(UINT comBase, UINT bitsPerSec, UINT context)
+ {
+ UCHAR modemCntrlVal;
+
+ IRMINI_RawReadPort(comBase+MODEM_CONTROL_REG_OFFSET, &modemCntrlVal);
+
+ switch (bitsPerSec){
+
+ case 9600:
+ /*
+ * Set request-to-send
+ * Clear data-terminal-ready
+ */
+ modemCntrlVal |= 2;
+ modemCntrlVal &= ~1;
+ break;
+
+ case 19200:
+ /*
+ * Clear request-to-send
+ * Set data-terminal-ready
+ */
+ modemCntrlVal |= 1;
+ modemCntrlVal &= ~2;
+ break;
+
+ case 115200:
+ /*
+ * Set request-to-send
+ * Set data-terminal-ready
+ */
+ modemCntrlVal |= 3;
+ break;
+
+ default:
+ /*
+ * Illegal speed
+ */
+ return FALSE;
+ }
+
+ IRMINI_RawWritePort(comBase+MODEM_CONTROL_REG_OFFSET, modemCntrlVal);
+
+ return TRUE;
+ }
+
+#endif
+
diff --git a/private/ntos/ndis/irmini/esi.h b/private/ntos/ndis/irmini/esi.h
new file mode 100644
index 000000000..eef5073d3
--- /dev/null
+++ b/private/ntos/ndis/irmini/esi.h
@@ -0,0 +1,20 @@
+/*
+ * ESI.H
+ *
+ *
+ *
+ */
+
+#include "dongle.h"
+
+#ifndef ESI_H
+ #define ESI_H
+
+ BOOLEAN ESI_Init(UINT comBase, dongleCapabilities *caps, UINT *context);
+ VOID ESI_Deinit(UINT comBase, UINT context);
+ BOOLEAN ESI_SetSpeed(UINT comBase, UINT bitsPerSec, UINT context);
+
+#endif ESI_H
+
+
+
diff --git a/private/ntos/ndis/irmini/externs.h b/private/ntos/ndis/irmini/externs.h
new file mode 100644
index 000000000..7696a25f2
--- /dev/null
+++ b/private/ntos/ndis/irmini/externs.h
@@ -0,0 +1,161 @@
+/*
+ ************************************************************************
+ *
+ * EXTERNS.h
+ *
+ * IRMINI Infrared Serial NDIS Miniport driver.
+ *
+ * (C) Copyright 1996 Microsoft Corp.
+ *
+ *
+ * (ep)
+ *
+ *************************************************************************
+ */
+
+
+
+#ifndef EXTERNS_H
+ #define EXTERNS_H
+
+
+ #ifndef IRMINILIB
+ /*
+ * Include externs for dongle modules
+ */
+ #include "actisys.h"
+ #include "adaptec.h"
+ #include "crystal.h"
+ #include "esi.h"
+ #include "parallax.h"
+ #include "nscdemo.h"
+ #endif
+
+
+ /*
+ * Externs for required miniport export functions
+ */
+ BOOLEAN MiniportCheckForHang(IN NDIS_HANDLE MiniportAdapterContext);
+ VOID MiniportDisableInterrupt(IN NDIS_HANDLE MiniportAdapterContext);
+ VOID MiniportEnableInterrupt(IN NDIS_HANDLE MiniportAdapterContext);
+ VOID MiniportHalt(IN NDIS_HANDLE MiniportAdapterContext);
+ VOID MiniportHandleInterrupt(IN NDIS_HANDLE MiniportAdapterContext);
+ NDIS_STATUS MiniportInitialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ );
+ VOID MiniportISR(
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueMiniportHandleInterrupt,
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+ NDIS_STATUS MiniportQueryInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+ );
+ NDIS_STATUS MiniportReconfigure(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ );
+ NDIS_STATUS MiniportReset(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ OUT PBOOLEAN AddressingReset
+ );
+ NDIS_STATUS MiniportSend(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET Packet,
+ IN UINT Flags
+ );
+ NDIS_STATUS MiniportSetInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ );
+ NDIS_STATUS MiniportTransferData (
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+ );
+
+
+
+ /*
+ * Other function externs
+ */
+ VOID InitDevice(IrDevice *thisDev);
+ BOOLEAN OpenDevice(IrDevice *dev);
+ VOID CloseDevice(IrDevice *dev);
+ VOID FreeAll();
+ PVOID MyMemAlloc(UINT size);
+ VOID MyMemFree(PVOID memptr, UINT size);
+ IrDevice *NewDevice();
+ VOID FreeDevice(IrDevice *dev);
+ USHORT ComputeFCS(UCHAR *data, UINT dataLen);
+ BOOLEAN NdisToIrPacket( IrDevice *thisDev,
+ PNDIS_PACKET Packet,
+ UCHAR *irPacketBuf,
+ UINT irPacketBufLen,
+ UINT *irPacketLen);
+
+
+ /*
+ * Externs for global data objects
+ */
+ struct IrDevice;
+ extern struct IrDevice *firstIrDevice;
+
+
+
+ /*
+ * From COMM.C
+ */
+ BOOLEAN DoOpen(struct IrDevice *thisDev);
+ VOID DoClose(IrDevice *thisDev);
+ BOOLEAN DoSend(IrDevice *thisDev, PNDIS_PACKET packetToSend);
+ BOOLEAN SetSpeed(IrDevice *thisDev);
+ BOOLEAN IsCommReadyForTransmit(IrDevice *thisDev);
+ BOOLEAN PortReadyForWrite(struct IrDevice *thisDev, BOOLEAN firstBufIsPending);
+ UINT Call_Get_System_Time();
+ VOID COM_ISR(struct IrDevice *thisDev, BOOLEAN *claimingInterrupt, BOOLEAN *requireDeferredCallback);
+ VOID QueueReceivePacket(struct IrDevice *thisDev, PUCHAR *data, UINT dataLen);
+ UINT DoRcvDirect(UINT ioBase, UCHAR *data, UINT maxBytes);
+ VOID CloseCOM(IrDevice *thisDev);
+ BOOLEAN OpenCOM(IrDevice *thisDev);
+ VOID SetCOMInterrupts(IrDevice *thisDev, BOOLEAN enable);
+
+ extern USHORT comPortIRQ[];
+ extern USHORT comPortIOBase[];
+
+
+ /*
+ * From SETTINGS.C
+ */
+ extern baudRateInfo supportedBaudRateTable[NUM_BAUDRATES];
+
+
+ #ifdef IRMINILIB
+ /*
+ * To be defined in OEM's dongle-specific module
+ */
+ extern IRMINI_Dongle_Interface OEM_Interface;
+
+
+ #endif
+
+
+#endif EXTERNS_H
diff --git a/private/ntos/ndis/irmini/fcs.c b/private/ntos/ndis/irmini/fcs.c
new file mode 100644
index 000000000..746854846
--- /dev/null
+++ b/private/ntos/ndis/irmini/fcs.c
@@ -0,0 +1,83 @@
+/*
+ ************************************************************************
+ *
+ * FCS.c
+ *
+ * IRMINI Infrared Serial NDIS Miniport driver.
+ *
+ * (C) Copyright 1996 Microsoft Corp.
+ *
+ *
+ * (ep)
+ *
+ *************************************************************************
+ */
+
+#include "irmini.h"
+
+static const USHORT fcsTable[256] =
+{
+ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+
+/*
+ *************************************************************************
+ * ComputeFCS
+ *************************************************************************
+ *
+ *
+ *
+ *
+ *
+ */
+USHORT ComputeFCS(UCHAR *data, UINT dataLen)
+{
+ USHORT fcs = 0xffff;
+ UINT i;
+
+ DBGOUT(("ComputeFCS() on %d-byte buffer.", dataLen));
+
+ for (i = 0; i < dataLen; i++){
+ fcs = (fcs >> 8) ^ fcsTable[(fcs ^ *data++) & 0xff];
+ }
+
+ fcs = ~fcs;
+
+ DBGOUT(("ComputeFCS returning %d=0x%x.", (UINT)fcs, (UINT)fcs));
+
+ return fcs;
+}
+
+
diff --git a/private/ntos/ndis/irmini/irmini.c b/private/ntos/ndis/irmini/irmini.c
new file mode 100644
index 000000000..bb60a2b14
--- /dev/null
+++ b/private/ntos/ndis/irmini/irmini.c
@@ -0,0 +1,1222 @@
+/*
+ ************************************************************************
+ *
+ * IRMINI.c
+ *
+ * IRMINI Infrared Serial NDIS Miniport driver.
+ *
+ * (C) Copyright 1996 Microsoft Corp.
+ *
+ *
+ * (ep)
+ *
+ *************************************************************************
+ */
+
+
+#include "irmini.h"
+
+
+/*
+ * We keep a linked list of device objects
+ */
+IrDevice *firstIrDevice = NULL;
+
+
+
+/*
+ *************************************************************************
+ * MiniportCheckForHang
+ *************************************************************************
+ *
+ * Reports the state of the network interface card.
+ *
+ */
+BOOLEAN MiniportCheckForHang(NDIS_HANDLE MiniportAdapterContext)
+{
+ DBGOUT(("MiniportCheckForHang(0x%x)", (UINT)MiniportAdapterContext));
+ return FALSE;
+}
+
+
+/*
+ *************************************************************************
+ * MiniportDisableInterrupt
+ *************************************************************************
+ *
+ * Disables the NIC from generating interrupts.
+ *
+ */
+VOID MiniportDisableInterrupt(NDIS_HANDLE MiniportAdapterContext)
+{
+ IrDevice *thisDev = CONTEXT_TO_DEV(MiniportAdapterContext);
+ DBGOUT(("MiniportDisableInterrupt(0x%x)", (UINT)MiniportAdapterContext));
+ SetCOMInterrupts(thisDev, FALSE);
+}
+
+
+/*
+ *************************************************************************
+ * MiniportEnableInterrupt
+ *************************************************************************
+ *
+ * Enables the NIC to generate interrupts.
+ *
+ */
+VOID MiniportEnableInterrupt(IN NDIS_HANDLE MiniportAdapterContext)
+{
+ IrDevice *thisDev = CONTEXT_TO_DEV(MiniportAdapterContext);
+ DBGOUT(("MiniportEnableInterrupt(0x%x)", (UINT)MiniportAdapterContext));
+ SetCOMInterrupts(thisDev, TRUE);
+}
+
+
+
+/*
+ *************************************************************************
+ * MiniportHalt
+ *************************************************************************
+ *
+ * Halts the network interface card.
+ *
+ */
+VOID MiniportHalt(IN NDIS_HANDLE MiniportAdapterContext)
+{
+ IrDevice *thisDev = CONTEXT_TO_DEV(MiniportAdapterContext);
+
+ DBGOUT(("MiniportHalt(0x%x)", (UINT)MiniportAdapterContext));
+
+ /*
+ * Remove this device from our global list
+ */
+
+ if (thisDev == firstIrDevice){
+ firstIrDevice = firstIrDevice->next;
+ }
+ else {
+ IrDevice *dev;
+ for (dev = firstIrDevice; dev && (dev->next != thisDev); dev = dev->next){ }
+ if (dev){
+ dev->next = dev->next->next;
+ }
+ else {
+ /*
+ * Don't omit this error check. I've seen NDIS call MiniportHalt with
+ * a bogus context when the system gets corrupted.
+ */
+ DBGERR(("Bad context in MiniportHalt"));
+ return;
+ }
+ }
+
+
+ /*
+ * Now destroy the device object.
+ */
+ DoClose(thisDev);
+
+ NdisMDeregisterIoPortRange( thisDev->ndisAdapterHandle,
+ thisDev->portInfo.ioBase,
+ 8,
+ (PVOID)thisDev->mappedPortRange);
+ FreeDevice(thisDev);
+
+
+}
+
+
+
+
+
+/*
+ *************************************************************************
+ * MiniportSyncHandleInterrupt
+ *************************************************************************
+ *
+ * This function is called from MiniportHandleInterrupt
+ * via NdisMSynchronizeWithInterrupt to synchronize with MiniportISR.
+ * This is required because the deferred procedure call (MiniportHandleInterrupt)
+ * shares data with MiniportISR but cannot achieve mutual exclusion with a spinlock
+ * because ISR's are not allowed to acquire spinlocks.
+ *
+ * This function should be called WITH DEVICE LOCK HELD, however, to synchronize
+ * with the rest of the miniport code (besides the ISR).
+ *
+ * The device's IRQ is masked out in the PIC while this function executes,
+ * so don't make calls up the stack.
+ *
+ */
+BOOLEAN MiniportSyncHandleInterrupt(PVOID MiniportAdapterContext)
+{
+ IrDevice *thisDev = CONTEXT_TO_DEV(MiniportAdapterContext);
+
+ DBGOUT(("==> MiniportSyncHandleInterrupt"));
+
+ /*
+ * Update .firstRcvBufIndex and .lastRcvBufIndex.
+ */
+ while ((thisDev->firstRcvBufIndex != NO_BUF_INDEX) &&
+ (thisDev->rcvBufs[thisDev->firstRcvBufIndex].state == STATE_FREE)){
+
+ if (thisDev->firstRcvBufIndex == thisDev->lastRcvBufIndex){
+ thisDev->firstRcvBufIndex = thisDev->lastRcvBufIndex = NO_BUF_INDEX;
+ }
+ else {
+ thisDev->firstRcvBufIndex = NEXT_RCV_BUF_INDEX(thisDev->firstRcvBufIndex);
+ }
+ }
+
+ DBGOUT(("<== MiniportSyncHandleInterrupt"));
+
+ return TRUE;
+}
+
+
+
+/*
+ *************************************************************************
+ * DeliverFullBuffers
+ *************************************************************************
+ *
+ * Deliver received packets to the protocol.
+ *
+ */
+VOID DeliverFullBuffers(IrDevice *thisDev)
+{
+ int rcvBufIndex = thisDev->firstRcvBufIndex;
+
+ DBGOUT(("==> DeliverFullBuffers"));
+
+
+
+ /*
+ * Deliver all full rcv buffers
+ */
+ while (rcvBufIndex != NO_BUF_INDEX){
+ rcvBuffer *rcvBuf = &thisDev->rcvBufs[rcvBufIndex];
+ NDIS_STATUS stat;
+ PNDIS_BUFFER packetBuf;
+ SLOW_IR_FCS_TYPE fcs;
+
+ switch (rcvBuf->state){
+
+ case STATE_FREE:
+ case STATE_PENDING:
+ /*
+ * This frame was already delivered. Just go to the next one.
+ */
+ break;
+
+ case STATE_FULL:
+
+ /*
+ * The packet we have already has had BOFs, EOF, and
+ * escape-sequences removed.
+ * It contains an FCS code at the end,
+ * which we need to verify and then remove before
+ * delivering the frame.
+ * We compute the FCS on the packet with the packet FCS
+ * attached; this should produce the constant value GOOD_FCS.
+ */
+ fcs = ComputeFCS(rcvBuf->dataBuf, rcvBuf->dataLen);
+
+ if (fcs != GOOD_FCS){
+ /*
+ * FCS Error. Drop this frame.
+ */
+ DBGERR(("Bad FCS in DeliverFullBuffers 0x%x!=0x%x.", (UINT)fcs, (UINT)GOOD_FCS));
+ rcvBuf->state = STATE_FREE;
+
+ DBGSTAT(("Dropped %d/%d packets; packet with BAD FCS (%xh!=%xh):",
+ ++thisDev->packetsDropped, thisDev->packetsDropped + thisDev->packetsRcvd, fcs, GOOD_FCS));
+ DBGPRINTBUF(rcvBuf->dataBuf, rcvBuf->dataLen);
+ break;
+ }
+
+
+ /*
+ * Remove the FCS from the end of the packet.
+ */
+ rcvBuf->dataLen -= SLOW_IR_FCS_SIZE;
+
+
+ #ifdef DBG_ADD_PKT_ID
+ if (addPktIdOn){
+ /*
+ * Remove dbg packet id.
+ */
+ rcvBuf->dataLen -= sizeof(USHORT);
+ DBGOUT((" RCVing packet %xh **", (UINT)*(USHORT *)(rcvBuf->dataBuf+rcvBuf->dataLen)));
+ }
+ #endif
+
+ /*
+ * The packet array is set up with its NDIS_PACKET.
+ * Now we need to allocate a single NDIS_BUFFER for the
+ * NDIS_PACKET and set the NDIS_BUFFER to the part of dataBuf
+ * that we want to deliver.
+ */
+ NdisAllocateBuffer( &stat,
+ &packetBuf,
+ thisDev->bufferPoolHandle,
+ (PVOID)rcvBuf->dataBuf,
+ rcvBuf->dataLen);
+ if (stat != NDIS_STATUS_SUCCESS){
+ DBGERR(("NdisAllocateBuffer failed"));
+ break;
+ }
+ NdisChainBufferAtFront(rcvBuf->packet, packetBuf);
+
+ /*
+ * Fix up some other packet fields.
+ */
+ NDIS_SET_PACKET_HEADER_SIZE(rcvBuf->packet, SLOW_IR_ADDR_SIZE + SLOW_IR_CONTROL_SIZE);
+
+ DBGPKT(("Indicating rcv packet 0x%x.", (UINT)rcvBuf->packet));
+ DBGPRINTBUF(rcvBuf->dataBuf, rcvBuf->dataLen);
+
+ /*
+ * Indicate to the protocol that another packet is ready.
+ * Set the rcv buffer's state to PENDING first to avoid
+ * a race condition with NDIS's call to the return packet
+ * handler.
+ */
+ rcvBuf->state = STATE_PENDING;
+ NdisMIndicateReceivePacket(thisDev->ndisAdapterHandle, &rcvBuf->packet, 1);
+ stat = NDIS_GET_PACKET_STATUS(rcvBuf->packet);
+ if (stat == NDIS_STATUS_PENDING){
+ /*
+ * The packet is being delivered asynchronously.
+ * Leave the rcv buffer's state as PENDING; we'll
+ * get a callback when the transfer is complete.
+ *
+ * Do NOT step firstRcvBufIndex.
+ * We don't really need to break out here,
+ * but we will anyways just to make things simple.
+ * This is ok since we get this deferred interrupt callback
+ * for each packet anyway. It'll give the protocol a chance
+ * to catch up.
+ */
+ DBGSTAT(("Rcv Pending. Rcvd %d packets", ++thisDev->packetsRcvd));
+ }
+ else {
+ /*
+ * If there was an error, we are dropping this packet;
+ * otherwise, this packet was delivered synchronously.
+ * We can free the packet buffer and make this rcv frame
+ * available.
+ */
+ NdisUnchainBufferAtFront(rcvBuf->packet, &packetBuf);
+ if (packetBuf){
+ NdisFreeBuffer(packetBuf);
+ }
+ rcvBuf->state = STATE_FREE;
+
+ if (stat == NDIS_STATUS_SUCCESS){
+ DBGSTAT(("Rcvd %d packets", ++thisDev->packetsRcvd));
+ }
+ else {
+ DBGSTAT(("Dropped %d/%d rcv packets. ", thisDev->packetsDropped++, thisDev->packetsDropped+thisDev->packetsRcvd));
+ }
+ }
+
+ break;
+
+
+ default:
+ /*
+ * This should never happen.
+ */
+ DBGERR(("Bad rcv buffer state in DPC"));
+ break;
+ }
+
+ /*
+ * Step the buffer index
+ */
+ if (rcvBufIndex == thisDev->lastRcvBufIndex){
+ rcvBufIndex = NO_BUF_INDEX;
+ }
+ else {
+ rcvBufIndex = NEXT_RCV_BUF_INDEX(rcvBufIndex);
+ }
+ }
+
+ DBGOUT(("<== DeliverFullBuffers"));
+
+}
+
+
+
+
+/*
+ *************************************************************************
+ * MiniportHandleInterrupt
+ *************************************************************************
+ *
+ *
+ * This is the deferred interrupt processing routine (DPC) which is
+ * optionally called following an interrupt serviced by MiniportISR.
+ *
+ */
+VOID MiniportHandleInterrupt(NDIS_HANDLE MiniportAdapterContext)
+{
+ IrDevice *thisDev = CONTEXT_TO_DEV(MiniportAdapterContext);
+
+ DBGOUT(("==> MiniportHandleInterrupt(0x%x)", (UINT)MiniportAdapterContext));
+
+
+ /*
+ * If we have just started receiving a packet,
+ * indicate media-busy to the protocol.
+ */
+ if (thisDev->mediaBusy && !thisDev->haveIndicatedMediaBusy){
+ NdisMIndicateStatus(thisDev->ndisAdapterHandle, NDIS_STATUS_MEDIA_BUSY, NULL, 0);
+ NdisMIndicateStatusComplete(thisDev->ndisAdapterHandle);
+ thisDev->haveIndicatedMediaBusy = TRUE;
+ }
+
+
+ /*
+ * Deliver all undelivered receive packets to the protocol.
+ */
+ DeliverFullBuffers(thisDev);
+
+
+ /*
+ * Update the rcv queue 'first' and 'last' pointers.
+ *
+ * We cannot use a spinlock to coordinate accesses to the rcv buffers
+ * with the ISR, since ISR's are not allowed to acquire spinlocks.
+ * So instead, we synchronize with the ISR using this special mechanism.
+ * MiniportSyncHandleInterrupt will do our work for us with the IRQ
+ * masked out in the PIC.
+ */
+ NdisMSynchronizeWithInterrupt( &thisDev->interruptObj,
+ MiniportSyncHandleInterrupt,
+ (PVOID)MiniportAdapterContext);
+
+
+ /*
+ * Send any pending write packets if possible.
+ */
+ if (IsCommReadyForTransmit(thisDev)){
+ PortReadyForWrite(thisDev, FALSE);
+ }
+
+ DBGOUT(("<== MiniportHandleInterrupt"));
+}
+
+
+
+/*
+ *************************************************************************
+ * Configure
+ *************************************************************************
+ *
+ * Read configurable parameters out of the system registry.
+ *
+ */
+BOOLEAN Configure(IrDevice *thisDev, NDIS_HANDLE WrapperConfigurationContext)
+{
+ NDIS_STATUS result = NDIS_STATUS_SUCCESS, stat;
+ NDIS_HANDLE configHandle;
+ PNDIS_CONFIGURATION_PARAMETER configParamPtr;
+ NDIS_STRING regKeyIRQString = NDIS_STRING_CONST("INTERRUPT");
+ NDIS_STRING regKeyIOString = NDIS_STRING_CONST("IOADDRESS");
+ NDIS_STRING regKeyIRTransceiverString = NDIS_STRING_CONST("InfraredTransceiverType");
+
+ DBGOUT(("Configure(0x%x)", (UINT)thisDev));
+
+ /*
+ * Set default values for configurable parameters. Default to COM1.
+ */
+ thisDev->portInfo.irq = comPortIRQ[1];
+ thisDev->portInfo.ioBase = comPortIOBase[1];
+ thisDev->transceiverType = STANDARD_UART;
+
+ NdisOpenConfiguration(&stat, &configHandle, WrapperConfigurationContext);
+ if (stat != NDIS_STATUS_SUCCESS){
+ DBGERR(("NdisOpenConfiguration failed in Configure()"));
+ return FALSE;
+ }
+
+#if 1
+ // BUGBUG REMOVE !!!
+ // (this here because reserving system resources causes problems for UART driver)
+ {
+ NDIS_STRING regKeyPortString = NDIS_STRING_CONST("PORT");
+ int comPort = 1;
+
+ /*
+ * Get infrared transceiver type for this connection.
+ */
+ NdisReadConfiguration( &stat,
+ &configParamPtr,
+ configHandle,
+ &regKeyPortString,
+ NdisParameterInteger);
+ if (stat == NDIS_STATUS_SUCCESS){
+
+ comPort = (irTransceiverType)configParamPtr->ParameterData.IntegerData;
+ thisDev->portInfo.irq = comPortIRQ[comPort];
+ thisDev->portInfo.ioBase = comPortIOBase[comPort];
+ }
+ else {
+ DBGERR(("Couldn't read Com# from registry"));
+ }
+ }
+#else
+
+ /*
+ * Get IRQ level for this connection.
+ */
+ NdisReadConfiguration( &stat,
+ &configParamPtr,
+ configHandle,
+ &regKeyIRQString,
+ NdisParameterInteger);
+ if (stat == NDIS_STATUS_SUCCESS){
+ thisDev->portInfo.irq = (UINT)configParamPtr->ParameterData.IntegerData;
+ }
+ else {
+ DBGERR(("Couldn't read IRQ value from registry"));
+ }
+
+ /*
+ * Get IO base address for this connection.
+ */
+ NdisReadConfiguration( &stat,
+ &configParamPtr,
+ configHandle,
+ &regKeyIOString,
+ NdisParameterHexInteger);
+ if (stat == NDIS_STATUS_SUCCESS){
+ thisDev->portInfo.ioBase = (UINT)configParamPtr->ParameterData.IntegerData;
+ }
+ else {
+ DBGERR(("Couldn't read IO value from registry"));
+ }
+#endif
+
+ /*
+ * Get infrared transceiver type for this connection.
+ */
+ NdisReadConfiguration( &stat,
+ &configParamPtr,
+ configHandle,
+ &regKeyIRTransceiverString,
+ NdisParameterInteger);
+ if ((stat == NDIS_STATUS_SUCCESS) &&
+ ((UINT)configParamPtr->ParameterData.IntegerData < NUM_TRANSCEIVER_TYPES)){
+
+ thisDev->transceiverType = (irTransceiverType)configParamPtr->ParameterData.IntegerData;
+ }
+ else {
+ DBGERR(("Couldn't read IR transceiver type from registry"));
+ }
+
+
+ NdisCloseConfiguration(configHandle);
+
+ DBGOUT(("Configure done: irq=%d IO=%xh", thisDev->portInfo.irq, thisDev->portInfo.ioBase));
+ return TRUE;
+}
+
+
+/*
+ *************************************************************************
+ * MiniportInitialize
+ *************************************************************************
+ *
+ *
+ * Initializes the network interface card.
+ *
+ *
+ *
+ */
+NDIS_STATUS MiniportInitialize ( PNDIS_STATUS OpenErrorStatus,
+ PUINT SelectedMediumIndex,
+ PNDIS_MEDIUM MediumArray,
+ UINT MediumArraySize,
+ NDIS_HANDLE NdisAdapterHandle,
+ NDIS_HANDLE WrapperConfigurationContext
+ )
+{
+ UINT mediumIndex;
+ IrDevice *thisDev = NULL;
+ NDIS_STATUS retStat, result = NDIS_STATUS_SUCCESS;
+
+ DBGOUT(("MiniportInitialize()"));
+
+ /*
+ * Search the passed-in array of supported media for the IrDA medium.
+ */
+ for (mediumIndex = 0; mediumIndex < MediumArraySize; mediumIndex++){
+ if (MediumArray[mediumIndex] == NdisMediumIrda){
+ break;
+ }
+ }
+ if (mediumIndex < MediumArraySize){
+ *SelectedMediumIndex = mediumIndex;
+ }
+ else {
+ /*
+ * Didn't see the IrDA medium
+ */
+ DBGERR(("Didn't see the IRDA medium in MiniportInitialize"));
+ result = NDIS_STATUS_UNSUPPORTED_MEDIA;
+ goto _initDone;
+ }
+
+ /*
+ * Allocate a new device object to represent this connection.
+ */
+ thisDev = NewDevice();
+ if (!thisDev){
+ return NDIS_STATUS_NOT_ACCEPTED;
+ }
+
+ /*
+ * Allocate resources for this connection.
+ */
+ if (!OpenDevice(thisDev)){
+ DBGERR(("OpenDevice failed"));
+ result = NDIS_STATUS_FAILURE;
+ goto _initDone;
+ }
+
+
+ /*
+ * Read the system registry to get parameters like COM port number, etc.
+ */
+ if (!Configure(thisDev, WrapperConfigurationContext)){
+ result = NDIS_STATUS_FAILURE;
+ goto _initDone;
+ }
+
+
+ /*
+ * This call will associate our adapter handle with the wrapper's
+ * adapter handle. The wrapper will then always use our handle
+ * when calling us. We use a pointer to the device object as the context.
+ */
+ NdisMSetAttributes ( NdisAdapterHandle,
+ (NDIS_HANDLE)thisDev,
+ FALSE,
+ NdisInterfaceInternal
+ );
+
+
+ /*
+ * Tell NDIS about the range of IO space that we'll be using.
+ */
+ retStat = NdisMRegisterIoPortRange( (PVOID)thisDev->mappedPortRange,
+ NdisAdapterHandle,
+ thisDev->portInfo.ioBase,
+ 8);
+ if (retStat != NDIS_STATUS_SUCCESS){
+ DBGERR(("NdisMRegisterIoPortRange failed"));
+ result = NDIS_STATUS_FAILURE;
+ goto _initDone;
+ }
+
+
+ /*
+ * Record the NDIS wrapper's handle for this adapter, which we use
+ * when we call up to the wrapper.
+ * (This miniport's adapter handle is just thisDev, the pointer to the device object.).
+ */
+ DBGOUT(("NDIS handle: %xh <-> IRMINI handle: %xh", (UINT)NdisAdapterHandle, (UINT)thisDev));
+ thisDev->ndisAdapterHandle = NdisAdapterHandle;
+
+
+ /*
+ * Open COMM communication channel.
+ * This will let the dongle driver update its capabilities from their default values.
+ */
+ if (!DoOpen(thisDev)){
+ DBGERR(("DoOpen failed"));
+ result = NDIS_STATUS_FAILURE;
+ goto _initDone;
+ }
+
+
+ /*
+ * Register an interrupt with NDIS.
+ */
+ retStat = NdisMRegisterInterrupt( (PNDIS_MINIPORT_INTERRUPT)&thisDev->interruptObj,
+ NdisAdapterHandle,
+ thisDev->portInfo.irq,
+ thisDev->portInfo.irq,
+ TRUE, // want ISR
+ TRUE, // MUST share interrupts
+ NdisInterruptLevelSensitive
+ );
+ if (retStat != NDIS_STATUS_SUCCESS){
+ DBGERR(("NdisMRegisterInterrupt failed"));
+ result = NDIS_STATUS_FAILURE;
+ goto _initDone;
+ }
+
+
+ _initDone:
+ if (result == NDIS_STATUS_SUCCESS){
+
+ /*
+ * Add this device object to the beginning of our global list.
+ */
+ thisDev->next = firstIrDevice;
+ firstIrDevice = thisDev;
+
+ DBGOUT(("MiniportInitialize succeeded"));
+ }
+ else {
+ if (thisDev){
+ FreeDevice(thisDev);
+ }
+ DBGOUT(("MiniportInitialize failed"));
+ }
+ return result;
+
+}
+
+
+
+/*
+ *************************************************************************
+ * QueueReceivePacket
+ *************************************************************************
+ *
+ *
+ *
+ *
+ */
+VOID QueueReceivePacket(IrDevice *thisDev, PUCHAR *data, UINT dataLen)
+{
+ rcvBuffer *rcvBuf;
+ int nextRcvBufIndex;
+
+ /*
+ * Note: We cannot use a spinlock to protect the rcv buffer structures
+ * in an ISR. This is ok, since we used a sync-with-isr function
+ * the the deferred callback routine to access the rcv buffers.
+ */
+
+ if (thisDev->firstRcvBufIndex == NO_BUF_INDEX){
+ nextRcvBufIndex = 0;
+ rcvBuf = &thisDev->rcvBufs[0];
+ }
+ else {
+ nextRcvBufIndex = NEXT_RCV_BUF_INDEX(thisDev->lastRcvBufIndex);
+
+ if (nextRcvBufIndex == thisDev->firstRcvBufIndex){
+ /*
+ * Buffers are all full.
+ */
+ rcvBuf = NULL;
+ }
+ else {
+ rcvBuf = &thisDev->rcvBufs[nextRcvBufIndex];
+ }
+ }
+
+ if (rcvBuf){
+ /*
+ * Get the COM port data into the receive buffer.
+ * For efficiency, we just swap pointers.
+ */
+ PVOID tmpptr = *data;
+ *data = rcvBuf->dataBuf;
+ rcvBuf->dataBuf = tmpptr;
+
+ rcvBuf->state = STATE_FULL;
+ rcvBuf->dataLen = dataLen;
+
+ /*
+ * Update rcv queue pointers only if DoRcv succeeded
+ */
+ if (thisDev->firstRcvBufIndex == NO_BUF_INDEX){
+ thisDev->firstRcvBufIndex = thisDev->lastRcvBufIndex = 0;
+ }
+ else {
+ thisDev->lastRcvBufIndex = nextRcvBufIndex;
+ }
+ }
+
+}
+
+
+/*
+ *************************************************************************
+ * MiniportISR
+ *************************************************************************
+ *
+ *
+ * This is the miniport's interrupt service routine (ISR).
+ *
+ *
+ */
+VOID MiniportISR ( PBOOLEAN InterruptRecognized,
+ PBOOLEAN QueueMiniportHandleInterrupt,
+ NDIS_HANDLE MiniportAdapterContext)
+{
+
+ IrDevice *thisDev = CONTEXT_TO_DEV(MiniportAdapterContext);
+
+ DBGOUT(("MiniportISR(0x%x, interrupt #%d)", (UINT)thisDev, ++thisDev->interruptCount));
+
+ /*
+ * Service the interrupt.
+ */
+ COM_ISR(thisDev, InterruptRecognized, QueueMiniportHandleInterrupt);
+
+ DBGOUT(("... MiniportISR done."));
+
+}
+
+
+
+
+
+/*
+ *************************************************************************
+ * MiniportReconfigure
+ *************************************************************************
+ *
+ *
+ * Reconfigures the network interface card to new parameters available
+ * in the NDIS library configuration functions.
+ *
+ *
+ */
+NDIS_STATUS MiniportReconfigure ( OUT PNDIS_STATUS OpenErrorStatus,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ )
+{
+ IrDevice *thisDev = CONTEXT_TO_DEV(MiniportAdapterContext);
+ NDIS_STATUS result;
+
+ DBGOUT(("MiniportReconfigure(0x%x)", (UINT)MiniportAdapterContext));
+
+ MiniportHalt(MiniportAdapterContext);
+
+ if (Configure(thisDev, WrapperConfigurationContext)){
+ result = NDIS_STATUS_SUCCESS;
+ }
+ else {
+ result = NDIS_STATUS_FAILURE;
+ }
+
+ DBGOUT(("MiniportReconfigure"));
+ *OpenErrorStatus = result;
+ return result;
+}
+
+
+/*
+ *************************************************************************
+ * MiniportReset
+ *************************************************************************
+ *
+ *
+ * MiniportReset issues a hardware reset to the network interface card.
+ * The miniport driver also resets its software state.
+ *
+ *
+ */
+// BUGBUG: Arguments are reversed from as documented in April '96 MSDN!
+NDIS_STATUS MiniportReset(PBOOLEAN AddressingReset, NDIS_HANDLE MiniportAdapterContext)
+{
+ IrDevice *dev, *thisDev = CONTEXT_TO_DEV(MiniportAdapterContext);
+ NDIS_STATUS result = NDIS_STATUS_SUCCESS;
+
+ DBGOUT(("MiniportReset(0x%x)", (UINT)MiniportAdapterContext));
+
+ /* BUGBUG: fixed; REMOVE ???
+ * Verify that the context is not bogus.
+ * I've seen bad contexts getting passed in when the system gets corrupted.
+ */
+ for (dev = firstIrDevice; dev && (dev != thisDev); dev = dev->next){ }
+ if (!dev){
+ DBGERR(("Bad context in MiniportReset"));
+ return NDIS_STATUS_FAILURE;
+ }
+
+ DoClose(thisDev);
+ CloseDevice(thisDev);
+ OpenDevice(thisDev);
+ DoOpen(thisDev);
+
+ *AddressingReset = TRUE;
+
+ DBGOUT(("MiniportReset done."));
+ return result;
+}
+
+
+
+
+/*
+ *************************************************************************
+ * MiniportSend
+ *************************************************************************
+ *
+ *
+ * Transmits a packet through the network interface card onto the medium.
+ *
+ *
+ *
+ */
+NDIS_STATUS MiniportSend(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET Packet,
+ IN UINT Flags
+ )
+{
+ IrDevice *thisDev = CONTEXT_TO_DEV(MiniportAdapterContext);
+ NDIS_STATUS result;
+
+ DBGOUT(("MiniportSend(thisDev=0x%x)", (UINT)thisDev));
+
+
+
+ /*
+ * Put this packet at the end of our send queue.
+ * We use the packet's MiniportReserved field as the
+ * 'next' pointer.
+ */
+ DBGPKT(("Queueing send packet 0x%x.", (UINT)Packet));
+ if (thisDev->firstSendPacket){
+ *(PNDIS_PACKET *)thisDev->lastSendPacket->MiniportReserved = Packet;
+ }
+ else {
+ thisDev->firstSendPacket = Packet;
+ }
+ thisDev->lastSendPacket = Packet;
+ *(PNDIS_PACKET *)Packet->MiniportReserved = NULL;
+
+
+ /*
+ * Try to send the first queued send packet.
+ */
+ if (IsCommReadyForTransmit(thisDev)){
+ BOOLEAN isSynchronousSend, xmitSucceeded;
+
+ isSynchronousSend = (BOOLEAN)(Packet == thisDev->firstSendPacket);
+
+ xmitSucceeded = PortReadyForWrite(thisDev, isSynchronousSend);
+
+ if (isSynchronousSend){
+ result = xmitSucceeded ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE;
+ }
+ else {
+ result = NDIS_STATUS_PENDING;
+ }
+ }
+ else {
+ result = NDIS_STATUS_PENDING;
+ }
+
+ DBGOUT(("MiniportSend returning %s", DBG_NDIS_RESULT_STR(result)));
+ return result;
+}
+
+
+
+/*
+ *************************************************************************
+ * MiniportTransferData
+ *************************************************************************
+ *
+ *
+ * Copies the contents of the received packet to a specified packet buffer.
+ *
+ *
+ *
+ */
+NDIS_STATUS MiniportTransferData (
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+ )
+{
+
+ DBGERR(("MiniportTransferData - should not get called."));
+
+ /*
+ * We always pass the entire packet up in the indicate-receive call,
+ * so we will never get this callback.
+ * (We can't do anything but return failure anyway,
+ * since NdisMIndicateReceivePacket does not pass up a packet context).
+ */
+ *BytesTransferred = 0;
+ return NDIS_STATUS_FAILURE;
+}
+
+
+/*
+ *************************************************************************
+ * ReturnPacketHandler
+ *************************************************************************
+ *
+ * When NdisMIndicateReceivePacket returns asynchronously,
+ * the protocol returns ownership of the packet to the miniport via this function.
+ *
+ */
+VOID ReturnPacketHandler(NDIS_HANDLE MiniportAdapterContext, PNDIS_PACKET Packet)
+{
+ IrDevice *thisDev = CONTEXT_TO_DEV(MiniportAdapterContext);
+ UINT rcvBufIndex;
+
+ DBGOUT(("ReturnPacketHandler(0x%x)", (UINT)MiniportAdapterContext));
+
+ /*
+ * The rcv buffer index is cached in the MiniportReserved field of the packet.
+ */
+ rcvBufIndex = *(UINT *)Packet->MiniportReserved;
+
+ if (rcvBufIndex < NUM_RCV_BUFS){
+ if (thisDev->rcvBufs[rcvBufIndex].state == STATE_PENDING){
+ PNDIS_BUFFER ndisBuf;
+
+ DBGPKT(("Reclaimed rcv packet 0x%x.", (UINT)Packet));
+
+ NdisUnchainBufferAtFront(Packet, &ndisBuf);
+ if (ndisBuf){
+ NdisFreeBuffer(ndisBuf);
+ }
+
+ thisDev->rcvBufs[rcvBufIndex].state = STATE_FREE;
+ }
+ else {
+ DBGERR(("Packet in ReturnPacketHandler was not PENDING."));
+ }
+ }
+ else {
+ DBGERR(("Bad rcvBufIndex (from corrupted MiniportReserved) in ReturnPacketHandler."));
+ }
+
+
+}
+
+
+
+/*
+ *************************************************************************
+ * SendPacketsHandler
+ *************************************************************************
+ *
+ * Send an array of packets simultaneously.
+ *
+ */
+VOID SendPacketsHandler(NDIS_HANDLE MiniportAdapterContext,
+ PPNDIS_PACKET PacketArray,
+ UINT NumberofPackets)
+{
+ NDIS_STATUS stat;
+ UINT i;
+
+ DBGOUT(("==> SendPacketsHandler(0x%x)", (UINT)MiniportAdapterContext));
+
+ /*
+ * This is a great opportunity to be lazy.
+ * Just call MiniportSend with each packet in sequence and
+ * set the result in the packet array object.
+ */
+ for (i = 0; i < NumberofPackets; i++){
+ stat = MiniportSend(MiniportAdapterContext, PacketArray[i], 0);
+ NDIS_SET_PACKET_STATUS(PacketArray[i], stat);
+ }
+
+ DBGOUT(("<== SendPacketsHandler"));
+}
+
+
+
+/*
+ *************************************************************************
+ * AllocateCompleteHandler
+ *************************************************************************
+ *
+ * Indicate completion of an NdisMAllocateSharedMemoryAsync call.
+ * We never call that function, so we should never get entered here.
+ *
+ */
+VOID AllocateCompleteHandler( NDIS_HANDLE MiniportAdapterContext,
+ PVOID VirtualAddress,
+ PNDIS_PHYSICAL_ADDRESS PhysicalAddress,
+ ULONG Length,
+ PVOID Context)
+{
+ DBGERR(("AllocateCompleteHandler - should not get called"));
+}
+
+
+
+
+/*
+ *************************************************************************
+ * PortReadyForWrite
+ *************************************************************************
+ *
+ * Called when COM port is ready for another write packet.
+ * Send the first frame in the send queue.
+ *
+ * Return TRUE iff send succeeded.
+ *
+ * NOTE: Do not call inside of interrupt context.
+ *
+ */
+BOOLEAN PortReadyForWrite(IrDevice *thisDev, BOOLEAN isSynchronousSend)
+{
+ BOOLEAN sendSucceeded = FALSE;
+
+ DBGOUT(("PortReadyForWrite(dev=0x%x, %xh, %s)",
+ (UINT)thisDev,
+ thisDev->portInfo.ioBase,
+ (CHAR *)(isSynchronousSend ? "sync" : "async")));
+
+
+ if (thisDev->firstSendPacket){
+ PNDIS_PACKET packetToSend;
+ PNDIS_IRDA_PACKET_INFO packetInfo;
+
+ /*
+ * Dequeue the first send packet and step the send queue.
+ * (We use the packet's MiniportReserved field is a 'next' pointer).
+ */
+ packetToSend = thisDev->firstSendPacket;
+ thisDev->firstSendPacket = *(PNDIS_PACKET *)thisDev->firstSendPacket->MiniportReserved;
+ if (!thisDev->firstSendPacket){
+ thisDev->lastSendPacket = NULL;
+ }
+ *(PNDIS_PACKET *)packetToSend->MiniportReserved = NULL;
+
+ /*
+ * Enforce the minimum turnaround time that must transpire
+ * after the last receive.
+ */
+ packetInfo = GetPacketInfo(packetToSend);
+
+ if (packetInfo->MinTurnAroundTime){
+ /*
+ * Don't want to call NdisStallExecution with more than
+ * 8 msec or it will cause a task switch.
+ * Make a series of calls with 8 msec or less.
+ */
+ UINT usecToWait = packetInfo->MinTurnAroundTime;
+ do {
+ UINT usec = (usecToWait > 8000) ? 8000 : usecToWait;
+ NdisStallExecution(usec);
+ usecToWait -= usec;
+ } while (usecToWait > 0);
+ }
+
+ /*
+ * See if this was the last packet before we need to change speed.
+ */
+ if (packetToSend == thisDev->lastPacketAtOldSpeed){
+ thisDev->lastPacketAtOldSpeed = NULL;
+ thisDev->setSpeedAfterCurrentSendPacket = TRUE;
+ }
+
+ /*
+ * Send one packet to the COMM port.
+ */
+ DBGPKT(("Sending packet 0x%x (0x%x).", thisDev->packetsSent++, (UINT)packetToSend));
+ sendSucceeded = DoSend(thisDev, packetToSend);
+
+ /*
+ * If the buffer we just sent was pending
+ * (i.e. we returned NDIS_STATUS_PENDING for it in MiniportSend),
+ * then hand the sent packet back to the protocol.
+ * Otherwise, we're just delivering it synchronously from MiniportSend.
+ */
+ if (!isSynchronousSend){
+ DBGOUT(("Calling NdisMSendComplete"));
+ NdisMSendComplete(thisDev->ndisAdapterHandle, packetToSend,
+ (NDIS_STATUS)(sendSucceeded ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE));
+ }
+
+ }
+
+
+ DBGOUT(("PortReadyForWrite done."));
+
+ return sendSucceeded;
+}
+
+
+/*
+ *************************************************************************
+ * DriverEntry
+ *************************************************************************
+ *
+ * Only include if IRMINI is a stand-alone driver.
+ *
+ */
+NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath);
+#pragma NDIS_INIT_FUNCTION(DriverEntry)
+NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
+{
+ NTSTATUS result = STATUS_SUCCESS, stat;
+ NDIS_HANDLE wrapperHandle;
+ NDIS40_MINIPORT_CHARACTERISTICS info;
+
+ DBGOUT(("==> IRMINI_Entry()"));
+
+ NdisMInitializeWrapper( (PNDIS_HANDLE)&wrapperHandle,
+ DriverObject,
+ RegistryPath,
+ NULL
+ );
+ DBGOUT(("Wrapper handle is %xh", (UINT)wrapperHandle));
+
+ info.MajorNdisVersion = (UCHAR)NDIS_MAJOR_VERSION;
+ info.MinorNdisVersion = (UCHAR)NDIS_MINOR_VERSION;
+// info.Flags = 0;
+ info.CheckForHangHandler = MiniportCheckForHang;
+ info.HaltHandler = MiniportHalt;
+ info.InitializeHandler = MiniportInitialize;
+ info.QueryInformationHandler = MiniportQueryInformation;
+ info.ReconfigureHandler = MiniportReconfigure;
+ info.ResetHandler = MiniportReset;
+ info.SendHandler = MiniportSend;
+ info.SetInformationHandler = MiniportSetInformation;
+ info.TransferDataHandler = MiniportTransferData;
+
+ info.HandleInterruptHandler = MiniportHandleInterrupt;
+ info.ISRHandler = MiniportISR;
+ info.DisableInterruptHandler = MiniportDisableInterrupt;
+ info.EnableInterruptHandler = MiniportEnableInterrupt;
+
+
+ /*
+ * New NDIS 4.0 fields
+ */
+ info.ReturnPacketHandler = ReturnPacketHandler;
+ info.SendPacketsHandler = SendPacketsHandler;
+ info.AllocateCompleteHandler = AllocateCompleteHandler;
+
+
+ stat = NdisMRegisterMiniport( wrapperHandle,
+ (PNDIS_MINIPORT_CHARACTERISTICS)&info,
+ sizeof(NDIS_MINIPORT_CHARACTERISTICS));
+ if (stat != NDIS_STATUS_SUCCESS){
+ DBGERR(("NdisMRegisterMiniport failed in DriverEntry"));
+ result = STATUS_UNSUCCESSFUL;
+ goto _entryDone;
+ }
+
+ _entryDone:
+ DBGOUT(("<== IRMINI_Entry %s", (PUCHAR)((result == NDIS_STATUS_SUCCESS) ? "succeeded" : "failed")));
+ return result;
+
+}
+
+
diff --git a/private/ntos/ndis/irmini/irmini.h b/private/ntos/ndis/irmini/irmini.h
new file mode 100644
index 000000000..cddae9762
--- /dev/null
+++ b/private/ntos/ndis/irmini/irmini.h
@@ -0,0 +1,180 @@
+/*
+ ************************************************************************
+ *
+ * IRMINI.h
+ *
+ * IRMINI Infrared Serial NDIS Miniport driver.
+ *
+ * (C) Copyright 1996 Microsoft Corp.
+ *
+ *
+ * (ep)
+ *
+ *************************************************************************
+ */
+
+
+
+#ifndef IRMINI_H
+ #define IRMINI_H
+
+ #include <ndis.h>
+ #include <ntddndis.h> // defines OID's
+
+ #include "settings.h"
+ #include "comm.h"
+
+ #define NDIS_MAJOR_VERSION 4
+ #define NDIS_MINOR_VERSION 0
+
+
+ PNDIS_IRDA_PACKET_INFO static __inline GetPacketInfo(PNDIS_PACKET packet)
+ {
+ MEDIA_SPECIFIC_INFORMATION *mediaInfo;
+ UINT size;
+ NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(packet, &mediaInfo, &size);
+ return (PNDIS_IRDA_PACKET_INFO)mediaInfo->ClassInformation;
+ }
+
+
+ /*
+ * A receive buffer is either FREE (not holding anything)
+ * FULL (holding undelivered data)
+ * or PENDING (holding data delivered asynchronously)
+ *
+ */
+ typedef enum rcvbufferStates {
+ STATE_FREE,
+ STATE_FULL,
+ STATE_PENDING
+ } rcvBufferState;
+
+
+
+ typedef struct {
+ rcvBufferState state;
+ PNDIS_PACKET packet;
+ UINT dataLen;
+ PUCHAR dataBuf;
+ } rcvBuffer;
+
+
+ typedef struct IrDevice {
+
+ /*
+ * This is the handle that the NDIS wrapper associates with a connection.
+ * (The handle that the miniport driver associates with the connection
+ * is just an index into the devStates array).
+ */
+ NDIS_HANDLE ndisAdapterHandle;
+
+ /*
+ * Current speed setting, in bits/sec.
+ * (Note: this is updated when we ACTUALLY change the speed,
+ * not when we get the request to change speed via
+ * MiniportSetInformation).
+ */
+ UINT currentSpeed;
+
+ /*
+ * This structure holds information about our ISR.
+ * It is used to synchronize with the ISR.
+ */
+ NDIS_MINIPORT_INTERRUPT interruptObj;
+
+ /*
+ * Memory-mapped port range
+ */
+ UCHAR mappedPortRange[8];
+
+ /*
+ * Circular queue of pending receive buffers
+ */
+ #define NUM_RCV_BUFS 4
+ #define NEXT_RCV_BUF_INDEX(i) (((i)==NO_BUF_INDEX) ? 0 : (((i)+1)%NUM_RCV_BUFS))
+ rcvBuffer rcvBufs[NUM_RCV_BUFS];
+
+ /*
+ * These indices into rcvBufs[] indicate the first and last
+ * non-FREE (FULL or PENDING) buffers in the circular list.
+ */
+ int firstRcvBufIndex, lastRcvBufIndex;
+ #define NO_BUF_INDEX -1
+
+ /*
+ * Send packet queue pointers.
+ */
+ PNDIS_PACKET firstSendPacket, lastSendPacket;
+
+ /*
+ * Handle to NDIS packet pool, from which packets are
+ * allocated.
+ */
+ NDIS_HANDLE packetPoolHandle;
+ NDIS_HANDLE bufferPoolHandle;
+
+
+ /*
+ * mediaBusy is set TRUE any time that this miniport driver moves a data frame.
+ * It can be reset by the protocol via MiniportSetInformation and later checked
+ * via MiniportQueryInformation to detect interleaving activity.
+ */
+ BOOLEAN mediaBusy;
+ BOOLEAN haveIndicatedMediaBusy;
+
+ /*
+ * nowReceiving is set while we are receiving a frame.
+ * It (not mediaBusy) is returned to the protocol when the protocol
+ * queries OID_MEDIA_BUSY
+ */
+ BOOLEAN nowReceiving;
+
+
+ /*
+ * Current link speed information.
+ */
+ baudRateInfo *linkSpeedInfo;
+
+ /*
+ * Some UART infrared transceiver have minor idiosyncracies,
+ * so we have to know the type.
+ */
+ irTransceiverType transceiverType;
+
+ /*
+ * When speed is changed, we have to clear the send queue before
+ * setting the new speed on the hardware.
+ * These vars let us remember to do it.
+ */
+ PNDIS_PACKET lastPacketAtOldSpeed;
+ BOOLEAN setSpeedAfterCurrentSendPacket;
+
+ /*
+ * Information on the COM port and send/receive FSM's.
+ */
+ comPortInfo portInfo;
+
+ /*
+ * Maintain statistical debug info.
+ */
+ UINT packetsRcvd;
+ UINT packetsDropped;
+ UINT packetsSent;
+ UINT interruptCount;
+
+ /*
+ * Pointer to next device in global list.
+ */
+ struct IrDevice *next;
+
+ } IrDevice;
+
+ /*
+ * We use a pointer to the IrDevice structure as the miniport's device context.
+ */
+ #define CONTEXT_TO_DEV(__deviceContext) ((IrDevice *)(__deviceContext))
+ #define DEV_TO_CONTEXT(__irdev) ((NDIS_HANDLE)(__irdev))
+
+ #include "externs.h"
+
+#endif IRMINI_H
diff --git a/private/ntos/ndis/irmini/irmini.rc b/private/ntos/ndis/irmini/irmini.rc
new file mode 100644
index 000000000..f62c335e1
--- /dev/null
+++ b/private/ntos/ndis/irmini/irmini.rc
@@ -0,0 +1,39 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "NDIS 4.0 Slow Infra-Red UART (COM) Driver"
+#define VER_INTERNALNAME_STR "IRMINI.SYS"
+#define VER_ORIGINALFILENAME_STR "IRMINI.SYS"
+
+#include "common.ver"
+
diff --git a/private/ntos/ndis/irmini/makefile b/private/ntos/ndis/irmini/makefile
new file mode 100644
index 000000000..9d474efa2
--- /dev/null
+++ b/private/ntos/ndis/irmini/makefile
@@ -0,0 +1,9 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+
+
+
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/irmini/nscdemo.c b/private/ntos/ndis/irmini/nscdemo.c
new file mode 100644
index 000000000..40ac6ea8c
--- /dev/null
+++ b/private/ntos/ndis/irmini/nscdemo.c
@@ -0,0 +1,198 @@
+/*
+ * NSCDEMO.C
+ *
+ *
+ *
+ */
+
+#ifndef IRMINILIB
+
+ #include "dongle.h"
+
+ #if DBG
+ extern unsigned long _cdecl DbgPrint(char *Format, ...);
+ #endif
+
+ /*
+ * The programming interface to a UART (COM serial port)
+ * consists of eight consecutive registers.
+ * These are the port offsets from the UART's base I/O address.
+ */
+ typedef enum comPortRegOffsets {
+ XFER_REG_OFFSET = 0,
+ INT_ENABLE_REG_OFFSET = 1,
+ INT_ID_AND_FIFO_CNTRL_REG_OFFSET = 2,
+ LINE_CONTROL_REG_OFFSET = 3,
+ MODEM_CONTROL_REG_OFFSET = 4,
+ LINE_STAT_REG_OFFSET = 5,
+ MODEM_STAT_REG_OFFSET = 6,
+ SCRATCH_REG_OFFSET = 7
+ } comPortRegOffset;
+
+
+ #define NSC_DEMO_IRDA_SPEEDS ( \
+ NDIS_IRDA_SPEED_2400 | \
+ NDIS_IRDA_SPEED_9600 | \
+ NDIS_IRDA_SPEED_19200 | \
+ NDIS_IRDA_SPEED_38400 | \
+ NDIS_IRDA_SPEED_57600 | \
+ NDIS_IRDA_SPEED_115200 \
+ )
+
+
+ /*
+ * NSC PC87108 index registers. See the spec for more info.
+ */
+ enum indexRegs {
+ BAIC_REG = 0,
+ CSRT_REG = 1,
+ MCTL_REG = 2,
+ GPDIR_REG = 3,
+ GPDAT_REG = 4
+ };
+
+ void Ir108ConfigWrite(UINT configIOBase, UCHAR indexReg, UCHAR data)
+ {
+ IRMINI_RawWritePort(configIOBase, indexReg);
+ IRMINI_RawWritePort(configIOBase+1, data);
+ IRMINI_RawWritePort(configIOBase+1, data);
+ IRMINI_RawWritePort(configIOBase, 0);
+ }
+
+
+
+
+ /*
+ * NSC_DEMO_Init
+ *
+ * Assumes configuration registers are at I/O addr 0x398.
+ * This function configures the demo board to make the SIR UART appear
+ * at <comBase>.
+ *
+ */
+ BOOLEAN NSC_DEMO_Init(UINT comBase, dongleCapabilities *caps, UINT *context)
+ {
+ const UINT configBase = 0x398;
+ UCHAR val;
+
+ /*
+ * Look for id at startup.
+ */
+ IRMINI_RawReadPort(configBase, &val);
+ if (val != 0x5A){
+ if (val == (UCHAR)0xff){
+ DbgPrint("ERROR: didn't see PC87108 id (0x5A); got ffh.\r\n");
+ return FALSE;
+ }
+ else {
+ /*
+ * ID only appears once, so in case we're resetting, don't fail if we don't see it.
+ */
+ #if DBG
+ DbgPrint("WARNING: didn't see PC87108 id (0x5A); got %xh.\r\n", (UINT)val);
+ #endif
+ }
+ }
+
+ /*
+ * Select the base address for the UART
+ */
+ switch (comBase){
+ case 0x3E8: val = 0; break;
+ case 0x2E8: val = 1; break;
+ case 0x3F8: val = 2; break;
+ case 0x2F8: val = 3; break;
+ default: return FALSE;
+ }
+ val |= 4; // enable register banks
+ Ir108ConfigWrite(configBase, BAIC_REG, val);
+
+ /*
+ * Select interrupt level according to base address,
+ * following COM port mapping.
+ */
+ switch (comBase){
+ case 0x3F8: val = 2; break; // COM1 -> IRQ3
+ case 0x2F8: val = 1; break; // COM2 -> IRQ3
+ case 0x3E8: val = 2; break; // COM3 -> IRQ3
+ case 0x2E8: val = 3; break; // COM4 -> IRQ3
+ default: return FALSE;
+ }
+ Ir108ConfigWrite(configBase, CSRT_REG, val);
+
+ /*
+ * Select device-enable and normal-operating-mode.
+ */
+ Ir108ConfigWrite(configBase, MCTL_REG, (UCHAR)3);
+
+ /*
+ * The UART doesn't appear until we clear and set the FIFO control register.
+ */
+ IRMINI_RawWritePort(comBase+2, (UCHAR)0x00);
+ IRMINI_RawWritePort(comBase+2, (UCHAR)0x07);
+
+
+ /*
+ * Switch to bank 7
+ * - enable power to the NSC dongle
+ * - set IRRX mode select and auto module config enable.
+ */
+ IRMINI_RawWritePort(comBase+3, (UCHAR)0xF4);
+ IRMINI_RawWritePort(comBase+4, (UCHAR)0x60);
+ IRMINI_RawWritePort(comBase+7, (UCHAR)0xC0);
+
+ /*
+ * Switch to bank 6
+ * set FIR CRC to 32 bits
+ */
+ IRMINI_RawWritePort(comBase+3, (UCHAR)0xF0);
+ IRMINI_RawWritePort(comBase+0, (UCHAR)0x20);
+
+ /*
+ * Switch to bank 5
+ * clear the status FIFO
+ *
+ */
+ IRMINI_RawWritePort(comBase+3, (UCHAR)0xEC);
+ do {
+ IRMINI_RawReadPort(comBase+6, &val);
+ IRMINI_RawReadPort(comBase+7, &val);
+ IRMINI_RawReadPort(comBase+5, &val);
+ }
+ while(val & 0x80);
+
+
+
+ /*
+ * Switch to bank 4 and set SIR mode in IRCR1.
+ * Then switch back to bank 0.
+ */
+ IRMINI_RawWritePort(comBase+3, (UCHAR)0xE8);
+ IRMINI_RawWritePort(comBase+2, (UCHAR)0x0C);
+ IRMINI_RawWritePort(comBase+3, (UCHAR)0);
+
+
+ caps->supportedSpeedsMask = NSC_DEMO_IRDA_SPEEDS;
+ caps->turnAroundTime_usec = 5000;
+ caps->extraBOFsRequired = 0;
+
+ *context = 0;
+
+ return TRUE;
+ }
+
+ VOID NSC_DEMO_Deinit(UINT comBase, UINT context)
+ {
+
+ }
+
+ BOOLEAN NSC_DEMO_SetSpeed(UINT comBase, UINT bitsPerSec, UINT context)
+ {
+
+
+ return TRUE;
+ }
+
+
+#endif
+
diff --git a/private/ntos/ndis/irmini/nscdemo.h b/private/ntos/ndis/irmini/nscdemo.h
new file mode 100644
index 000000000..8fb80189e
--- /dev/null
+++ b/private/ntos/ndis/irmini/nscdemo.h
@@ -0,0 +1,20 @@
+/*
+ * NSCDEMO.H
+ *
+ *
+ *
+ */
+
+#include "dongle.h"
+
+#ifndef NSCDEMO_H
+ #define NSCDEMO_H
+
+ BOOLEAN NSC_DEMO_Init(UINT comBase, dongleCapabilities *caps, UINT *context);
+ VOID NSC_DEMO_Deinit(UINT comBase, UINT context);
+ BOOLEAN NSC_DEMO_SetSpeed(UINT comBase, UINT bitsPerSec, UINT context);
+
+#endif NSCDEMO_H
+
+
+
diff --git a/private/ntos/ndis/irmini/oemsetup.inf b/private/ntos/ndis/irmini/oemsetup.inf
new file mode 100644
index 000000000..f3e34ed24
--- /dev/null
+++ b/private/ntos/ndis/irmini/oemsetup.inf
@@ -0,0 +1,1475 @@
+;***********************************************************************
+;
+; OEMSETUP.INF
+;
+;
+; IRMINI serial infrared reference driver INF.
+;
+; History:
+;
+; Author(s) Geeky Euro-date Action
+; --------- --------------- ------
+; davidhov 00-Feb-1992 Created
+; terryk 27-Feb-1992 Reorganize section location
+; added comment
+; terryk 03-Mar-1992 Changed to Elink II setup
+; terryk 02-Apr-1992 Code review changed
+; davidhov 03-Apr-1992 Enhanced to use new INF section
+; structure from SunilP, et al.
+; davidhov 06-Dec-1992 Netcard Detection
+; robertn 02-Jul-1993 Changed for Xircom PE3 without detect
+; davidlao 28-jun-1995 Added help file.
+; aarono,ervinp 18-jun-1996 Modified for IRMINI
+;
+;
+;***********************************************************************
+
+;-----------------------------------------------------------------------
+; OPTION TYPE
+; -----------
+; This identifies the Option type we are dealing with. The different
+; possible types are:
+;
+; COMPUTER, DISPLAY, MOUSE, KEYBOARD, LAYOUT, SCSI, PRINTER, ...
+;
+; Types specific to networking:
+;
+; NetAdapter, a netcard / adapter combination or just a netcard
+; NetDriver, just a netcard driver
+; NetTransport, a complete NDIS-compliant TDI transport stack
+; NetService, an NT networking service
+; NetWork, a complete network ensemble.
+; NetProvider a complete network which supports NT MPR protocol
+;-----------------------------------------------------------------------
+
+[Identification]
+ OptionType = NetAdapter
+
+;-----------------------------------------------------------------------
+; PlatformsSupported
+; ------------------
+; This identifies the platforms supported by the adapter card.
+; Possible types are:
+;
+; ISA
+;-----------------------------------------------------------------------
+
+[PlatformsSupported]
+ ISA
+
+;-----------------------------------------------------------------------
+; LANGUAGES SUPPORTED
+; -------------------
+;
+; The languages supported by the OEM INF, For every language supported
+; we need to have a separate text section for every displayable text
+; section.
+;
+;-----------------------------------------------------------------------
+
+[LanguagesSupported]
+ ENG
+
+;-----------------------------------------------------------------------
+; OPTION LIST
+; -----------
+; This section lists the OEM Option key names. These keys are locale
+; independent and used to represent the option in a locale independent
+; manner.
+;
+;-----------------------------------------------------------------------
+
+[Options]
+ IRMINI
+
+;-----------------------------------------------------------------------
+; OPTION TEXT SECTION
+; -------------------
+; These are text strings used to identify the option to the user. There
+; are separate sections for each language supported. The format of the
+; section name is "OptionsText" concatenated with the Language represented
+; by the section.
+;
+;-----------------------------------------------------------------------
+
+[OptionsTextENG]
+ IRMINI = "IRMINI Serial Infrared Port"
+
+;***********************************************************************
+; CONSTANTS FOR USING DIALOGS
+;***********************************************************************
+
+[FileConstants]
+
+;
+; File names, etc.
+;
+UtilityInf = "UTILITY.INF"
+ParamInf = "NCPARAM.INF"
+subroutineinf = "SUBROUTN.INF"
+SoftwareType = "driver"
+Exit_Code = 0
+
+;
+; EventLog Message File
+;
+NetEventDLL = "%SystemRoot%\System32\netevent.dll;%SystemRoot%\System32\Drivers\irmini.sys"
+IoLogMsgDLL = "%SystemRoot%\System32\IoLogMsg.dll"
+
+; Product Info
+;
+Manufacturer = "Microsoft"
+ProductMajorVersion = "4"
+ProductMinorVersion = "0"
+ProductVersion = $(ProductMajorVersion)"."$(ProductMinorVersion)
+;
+; Software
+;
+ProductSoftwareName = "IRMINI"
+ProductSoftwareTitle = "IRMINI Serial Infrared Port Driver"
+ProductSoftwareImagePath = "\SystemRoot\System32\drivers\irmini.sys"
+NetRuleSoftwareType = "IrminiSys ndisDriver irminiDriver"
+NetRuleSoftwareUse = $(SoftwareType)
+NetRuleSoftwareBindForm = """IrminiSys"" yes no container"
+NetRuleSoftwareClass = {"irminiDriver basic"}
+NetRuleSoftwareBindable = {"irminiDriver irminiAdapter non exclusive 100"}
+;
+; Hardware
+;
+ProductHardwareName = "Irmini"
+ProductHardwareIRMINITitle = "IRMINI Serial Infrared Port Driver"
+NetRuleHardwareType = "irmini irminiAdapter"
+NetRuleHardwareBindForm = " yes yes container"
+NetRuleHardwareClass = {"irminiAdapter basic"}
+;
+; Registry Key
+;
+ProductKeyName = $(!NTN_SoftwareBase)"\"$(Manufacturer)"\"$(ProductSoftwareName)"\CurrentVersion"
+ParamKeyName = $(!NTN_ServiceBase)"\"$(ProductHardwareName)"\Parameters"
+
+
+[GeneralConstants]
+;
+; Program flow control variables.
+;
+from = ""
+to = ""
+;
+; Return codes; Exit_Code is set to one of these
+;
+ExitCodeOk = 0
+ExitCodeCancel = 1
+ExitCodeFatal = 2
+
+;BUGBUG: don't know what MAXIMUM_ALLOWED means
+KeyNull = ""
+MAXIMUM_ALLOWED = 33554432
+RegistryErrorIndex = NO_ERROR
+KeyProduct = ""
+KeyParameters = ""
+
+TRUE = 1
+FALSE = 0
+NoTitle = 0
+
+ExitState = "Active"
+OldVersionExisted = $(FALSE)
+
+DriverPath = $(!STF_NTPATH)\drivers
+
+;***********************************************************************
+; Language-Dependent Dialog Constants
+;***********************************************************************
+
+[FileConstantsENG]
+;
+; Variables to support thermometer gauge and error dialogs
+;
+ProCaption = "Windows NT Setup"
+ProCancel = "Cancel"
+ProCancelMsg = "Windows NT Networking is not correctly installed. "+
+ "Are you sure you want to cancel copying files?"
+
+ProCancelCap = "Network Setup Message"
+ProText1 = "Copying:"
+ProText2 = "To:"
+
+;
+; Product Info
+;
+FunctionTitle = "IRMINI Serial Infrared Port Setup"
+;
+; Software
+;
+ProductSoftwareDescription = "IRMINI Serial Infrared Port Driver"
+;
+; Hardware
+;
+ProductHardwareIRMINIDescription = "IRMINI Serial Infrared Port Adapter"
+
+[DialogConstantsENG]
+;
+; Common button names, etc.
+;
+;BUGBUG: remove or resolve help issues.
+Help = "&Help"
+Exit = "Cancel"
+OK = "OK"
+HelpContext = ""
+Continue = "Continue"
+Cancel = "Cancel"
+
+[date]
+ ; Now is a list which contains { Sec from 1-1-1970, Year, Month, Day, Hour,
+ ; Minute, Second }
+ Now = {} ? $(!LIBHANDLE) GetSystemDate
+
+
+;-----------------------------------------------
+; Input DIALOGS
+;-----------------------------------------------
+
+[FileDependentDlgENG]
+
+DlgType = "MultiCombo"
+
+; BUGBUG ??? DlgTemplate = "NE2000"
+DlgTemplate = "UBNDIS"
+
+Caption = $(FunctionTitle)
+
+DlgText = "Please select values for the following fields:"
+
+Label1 = "&IRQ Level:"
+Label2 = "I/&O Port Address:"
+Label3 = "&Transceiver Type:"
+
+Combo1List = $(IRQ_List)
+Combo1Out = $(IRQ_Level)
+Combo2List = $(IOADDR_Hex_List)
+Combo2Out = $(IOADDR_Hex_Value)
+Combo3List = $(TRANSCEIVER_TYPE_List)
+Combo3Out = $(TRANSCEIVER_TYPE_Str)
+
+
+ComboListItemsIn = {Combo1List, Combo2List, Combo3List}
+ComboListItemsOut = {Combo1Out, Combo2Out, Combo3Out}
+
+EditTextIn = ""
+EditTextLim = ""
+CBOptionsGreyed = {}
+NotifyFields = {NO, NO, NO}
+
+HelpContext = 100
+
+;---------------------------------------------------------------------------
+; 1. Identify
+;
+; DESCRIPTION: To verify that this INF deals with the same type of options
+; as we are choosing currently.
+;
+; INPUT: None
+;
+; OUTPUT: $($R0): STATUS: STATUS_SUCCESSFUL
+; $($R1): Option Type (COMPUTER ...)
+; $($R2): Diskette description
+;---------------------------------------------------------------------------
+
+[Identify]
+ Set !G:DebugOutputControl = 1
+ Set !DebugOutputControl = 1
+ Set !STF_DISPLAYDEBUGOUTPUT = 1
+ Debug-Output $(STF_CONTEXTINFNAME)": Calling Identification"
+ ;
+ ;
+ read-syms Identification
+ Debug-Output $(STF_CONTEXTINFNAME)": Identification set OptionType = "$(OptionType)
+
+ set Status = STATUS_SUCCESSFUL
+ set Identifier = $(OptionType)
+ set Media = #("Source Media Descriptions", 1, 1)
+
+ Debug-Output $(STF_CONTEXTINFNAME)": Identify returning Status = "$(Status)", Identifier = "$(Identifier)", Media = "$(Media)
+
+ Return $(Status) $(Identifier) $(Media)
+
+;------------------------------------------------------------------------
+; 2. ReturnOptions:
+;
+; DESCRIPTION: To return the option list supported by this INF and the
+; localised text list representing the options.
+;
+;
+; INPUT: $($0): Language used. ( ENG | FRN | ... )
+;
+; OUTPUT: $($R0): STATUS: STATUS_SUCCESSFUL |
+; STATUS_NOLANGUAGE
+; STATUS_FAILED
+; STATUS_NOTSUPPORTED
+;
+; $($R1): Option List
+; $($R2): Option Text List
+;------------------------------------------------------------------------
+
+[ReturnOptions]
+ ;
+ ;
+ set Status = STATUS_FAILED
+ set OptionList = {}
+ set OptionTextList = {}
+
+ ;
+ ; Check if the language requested is supported
+ ;
+ set LanguageList = ^(LanguagesSupported, 1)
+ Ifcontains(i) $($0) in $(LanguageList)
+ ;
+ ; Check if the platforms requested is supported
+ ;
+ ifstr(i) $($1) == ""
+ goto returnoptions
+ endif
+
+ set PlatformList = ^(PlatformsSupported, 1)
+ Ifcontains(i) $($1) in $(PlatformList)
+ goto returnoptions
+ else
+ set Status = STATUS_NOTSUPPORTED
+ goto finish_ReturnOptions
+ endif
+ else
+ set Status = STATUS_NOLANGUAGE
+ goto finish_ReturnOptions
+ endif
+
+ ;
+ ; form a list of all the options and another of the text representing
+ ;
+
+returnoptions = +
+ set OptionList = ^(Options, 1)
+ set OptionTextList = ^(OptionsText$($0), 1)
+ set Status = STATUS_SUCCESSFUL
+
+finish_ReturnOptions = +
+ Return $(Status) $(OptionList) $(OptionTextList)
+
+;------------------------------------------------------------------------
+;
+; InstallOption:
+;
+; This section is shelled to by main installation processing
+; or by NCPASHEL.INF during reconfig, removal, update, etc.
+;
+;
+; FUNCTION: To copy files representing Options
+; To configure the installed option
+; To update the registry for the installed option
+;
+; INPUT: $($0): Language to use
+; $($1): OptionID to install
+; $($2): SourceDirectory
+; $($3): AddCopy (YES | NO)
+; $($4): DoCopy (YES | NO)
+; $($5): DoConfig (YES | NO)
+;
+; OUTPUT: $($R0): STATUS: STATUS_SUCCESSFUL |
+; STATUS_NOLANGUAGE |
+; STATUS_USERCANCEL |
+; STATUS_FAILED
+;
+;------------------------------------------------------------------------
+[InstallOption]
+ ;
+ ; Set default values for
+ ;
+ set Status = STATUS_FAILED
+ ;
+ ; extract parameters
+ ;
+ set Option = $($1)
+ set SrcDir = $($2)
+ set AddCopy = $($3)
+ set DoCopy = $($4)
+ set DoConfig = $($5)
+
+ ;
+ ; Check if the language requested is supported
+ ;
+ set LanguageList = ^(LanguagesSupported, 1)
+ Ifcontains(i) $($0) NOT-IN $(LanguageList)
+ Return STATUS_NOLANGUAGE
+ endif
+
+ set-subst LF = "\n"
+
+ read-syms GeneralConstants
+ read-syms FileConstants
+
+ ; BUGBUG: What is NCPA??
+
+ read-syms DialogConstants$(!STF_LANGUAGE)
+ ifstr(i) $(!NTN_Origination) == "NCPA"
+ set Continue = "OK"
+ endif
+ read-syms FileConstants$(!STF_LANGUAGE)
+
+ detect date
+
+ set-title $(FunctionTitle)
+
+ set to = Begin
+ set from = Begin
+;
+; Assume all is well.
+;
+ set CommonStatus = STATUS_SUCCESSFUL
+
+ EndWait
+
+;
+; Set up the operation-mode-based variables and gaily welcome
+; the user. If the "install mode" variable is improperly set,
+; assume this is a new installation.
+;
+;BUGBUG: calls out to shell, what is it doing?
+Begin = +
+ Set ActivateDetection = FALSE
+
+ Ifstr(i) $(!NTN_InstallMode) == deinstall
+ set StartLabel = removeadapter
+ else-Ifstr(i) $(!NTN_InstallMode) == Update
+ set StartLabel = UpgradeSoftware
+ else-Ifstr(i) $(!NTN_InstallMode) == bind
+ set StartLabel = bindingadapter
+ else-Ifstr(i) $(!NTN_InstallMode) == configure
+ set ActivateDetection = TRUE
+ set StartLabel = configureadapter
+ ;
+ ; You cannot config the software component
+ ;
+ Ifstr(i) $(ProductKeyName) == $(!NTN_RegBase)
+ Debug-Output "Cannot configure the NI6510 driver software."
+ Shell $(UtilityInf),RegistryErrorString,CANNOT_CONFIGURE_SOFTWARE
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output "ShellCode error: cannot get an error string."
+ goto ShellCodeError
+ endif
+ set Error = $($R0)
+ set from = end
+ set to = end
+ goto nonfatalinfo
+ endif
+ else
+ set ActivateDetection = TRUE
+ set StartLabel = installadapter
+ set OEM_ABANDON_OPTIONS = {}
+ set OEM_ABANDON_SOFTWARE = FALSE
+ set OEM_ABANDON_ON = TRUE
+ endif
+
+
+ ;===================================================
+ ; Netcard Detection logic
+ ;
+ ; Initialize use of netcard detection;
+ ; Construct require global parameter variables
+ ;
+ Debug-Output "OEMSETUP.INF: =================================================="
+ Debug-Output "OEMSETUP.INF: STF_CWDIR is: "$(!STF_CWDIR)
+ Debug-Output "OEMSETUP.INF: STF_LANGUAGE is: "$(!STF_LANGUAGE)
+ Debug-Output "OEMSETUP.INF: Option is: "$(Option)
+ Debug-Output "OEMSETUP.INF: !STF_NCDETECT is: "$(!STF_NCDETECT)
+ Debug-Output "OEMSETUP.INF: !STF_NCOPTION is: "$(!STF_NCOPTION)
+ Debug-Output "OEMSETUP.INF: !STF_NCDETCARD is: "$(!STF_NCDETCARD)
+ Debug-Output "OEMSETUP.INF: !STF_NCDETINFO is: "$(!STF_NCDETINFO)
+ Debug-Output "OEMSETUP.INF: =================================================="
+
+ Set DetectedCard = FALSE
+
+ Ifstr(i) $(ActivateDetection) != TRUE
+ Goto $(StartLabel)
+ Endif
+ ;
+ ; Set !STF_NC_PARAMS and !STF_NC_PNAMES by calling
+ ; PARAM.INF!Param_BuildTypeLists.
+ ; Pass it a list of the form:
+ ;
+ ; { { <param name>,
+ ; <name of choice list var>,
+ ; <name of default var> },
+ ; ...
+ ; }
+ ;
+ Set TypeList = {{IRQ, IRQ_List, IRQ_Level},+
+ {IOADDR, IOADDR_Addr_List, IOBaseAddrValue},+
+ {TRANSCEIVER_TYPE, TRANSCEIVER_TYPE_List, TRANSCEIVER_TYPE_Value}}
+
+ Debug-Output "OEMSETUP.INF: Calling Param_BuildTypeLists"
+; Shell $(ParamInf) Param_BuildTypeLists $(Option) $(TypeList)
+; Set Status = $($R0)
+; ifstr(i) $(Status) != STATUS_SUCCESSFUL
+; Goto fataldetect
+; Endif
+;
+; The following code performs the same as above Param_BuildTypeLists
+;
+ Set IRQ_List = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 }
+ Set IOADDR_Addr_List = { 744, 760, 1000, 1016 }
+
+
+ Set TRANSCEIVER_TYPE_List = { "Standard UART",+
+ "ESI-9680 JetEye",+
+ "ActiSys 220L",+
+ "Crystal",+
+ "Adaptec AIRport2000",+
+ "PARALLAX",+
+ "NSC PC87108 demo bd" }
+
+ Set !STF_NC_PARAMS = { { "IRQ", 1, 0, { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 } },+
+ { "IOADDR", 1, 0, { 744, 760, 1000, 1016 } },+
+ { "TRANSCEIVER_TYPE", 1, 0, {"Standard UART",+
+ "ESI-9680 JetEye",+
+ "ActiSys 220L",+
+ "Crystal",+
+ "Adaptec AIRport2000",+
+ "PARALLAX",+
+ "NSC PC87108 demo bd" } } }
+ Set !STF_NC_PNAMES = { { "IRQ", "IRQ_Level", 4 },+
+ { "IOADDR", "IOBaseAddrValue", 1016 },+
+ { "TRANSCEIVER_TYPE", "TRANSCEIVER_TYPE_Value", 0 } }
+ Set !p:IRQ = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 }
+ Set !p:IOADDR = { 744, 760, 1000, 1016 }
+
+ Set !p:TRANSCEIVER_TYPE = { "Standard UART",+
+ "ESI-9680 JetEye",+
+ "ActiSys 220L",+
+ "Crystal",+
+ "Adaptec AIRport2000",+
+ "PARALLAX",+
+ "NSC PC87108 demo bd" }
+
+
+;
+; End of additional code
+;
+ Debug-Output "OEMSETUP.INF: Calling Param_SetDefaults"
+ Shell $(ParamInf) Param_SetDefaults {}
+
+ ; Establish presentation versions of choice lists.
+
+ Shell $(ParamInf) HexListFromDecList $(IOADDR_Addr_List)
+ Set IOADDR_Hex_List = $($R0)
+
+ ; If this is a detected card, set the flag.
+
+ Ifstr(i) $(!STF_NCDETECT) == YES
+ Ifstr(i) $(!STF_NCOPTION) == $(Option)
+ Set DetectedCard = TRUE
+ Debug-Output "OEMSETUP.INF: Setting DetectedCard to TRUE"
+ Endif
+ Endif
+ ;
+ ; End Netcard Detection logic
+ ;===================================================
+
+ Shell "" DebugConfiguration "After parameter querying"
+
+ Set from = $(fatal)
+ Set to = $(fatal)
+ Goto $(StartLabel)
+
+;-----------------------------------------------
+; Installation Section
+;-----------------------------------------------
+
+installadapter = +
+;
+; First, check whether the same version of the software exists
+;
+ OpenRegKey $(!REG_H_LOCAL) "" $(ProductKeyName) $(MAXIMUM_ALLOWED) KeyProduct
+
+ Ifstr $(KeyProduct) != $(KeyNull)
+ ;
+ ; Same version already existed in the local machine
+ ; Popup the dialog and ask the user whether he wants to continue
+ ;
+ CloseRegKey $(KeyProduct)
+
+ ifstr(i) !(NTN_RegBase) == $(ProductKeyName)
+ ;
+ ; Cannot Install the same software again
+ ;
+ Shell $(UtilityInf), VerExistedDlg, $(ProductSoftwareTitle),+
+ $(ProductVersion)
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output "ShellCode error: cannot get an error string."
+ goto ShellCodeError
+ endif
+
+ goto end
+ else
+ ;
+ ; Add a new adapter card?
+ ;
+ Shell $(UtilityInf), CardExistedDlg
+
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output "ShellCode error: cannot get an error string."
+ goto ShellCodeError
+ endif
+
+ ifstr(i) $($R1) != "OK"
+ goto end
+ endif
+ set OldVersionExisted = $(TRUE)
+ endif
+ endif
+
+ Install "Install-Option"
+ ;===================================================
+ ; Netcard Detection logic
+ ;
+ ; If this is a detected card, query its parameters
+ ; and merge them into the default list.
+ ;
+ ;BUGBUG: detecting PCMCIA card ranges, probably needs to be removed.
+ Ifstr(i) $(DetectedCard) != TRUE
+ Goto adaptersetup
+ Endif
+ ;
+ ; Get the detected parameters
+ ;
+ StartWait
+ Shell $(ParamInf) Param_QueryCard $(!STF_NCDETCARD)
+ EndWait
+ Ifstr(i) $($R0) != STATUS_SUCCESSFUL
+ Goto adaptersetup
+ Endif
+ ;
+ ; Merge the detected values in.
+ ;
+ Set DetectedParams = $($R1)
+ Debug-Output "OEMSETUP.INF: Calling Param_SetDefaults to merge detected params"
+ Shell $(ParamInf) Param_SetDefaults $(DetectedParams)
+ ;
+ ; End Netcard Detection logic
+ ;===================================================
+
+ goto adaptersetup
+
+;-----------------------------------------------
+; Configuration Section
+;-----------------------------------------------
+;
+; Get the current values of all the parameters
+;
+configureadapter = +
+ Ifstr $(KeyProduct) == $(KeyNull)
+ OpenRegKey $(!REG_H_LOCAL) "" $(!NTN_RegBase) $(MAXIMUM_ALLOWED) KeyProduct
+ Ifstr $(KeyProduct) == $(KeyNull)
+ set RegistryErrorIndex = CANNOT_FIND_COMPONENT_SERVICE
+ Debug-Output "Cannot find component product key"
+ goto fatalregistry
+ Endif
+ Endif
+
+ ;
+ ; Get the other parameters; they're attached to the service parameters key
+ ;
+ Debug-Output "INF: Shelling to FindService"
+ Shell $(UtilityInf) FindService, $(KeyProduct)
+ Ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output "INF: FindService shell failure"
+ Goto ShellCodeError
+ Endif
+ Ifstr(i) $($R0) != NO_ERROR
+ Debug-Output "INF: FindService Shell error: "$($R0)
+ Goto fatalregistry
+ endif
+
+ Set KeyParameters = $($R2)
+
+ ;
+ ; We don't need the services key, so close it.
+ ;
+ CloseRegKey $($R1)
+
+ Ifstr $(KeyParameters) == $(KeyNull)
+ set RegistryErrorIndex = CANNOT_FIND_COMPONENT_SERVICE
+ Debug-Output "Cannot find component service"
+ goto fatalregistry
+ endif
+
+ set OldVersionExisted = $(TRUE)
+
+ set ValueName = ""
+ set ValueData = ""
+ set ValueStr = ""
+ set ValueList = {}
+
+ ;
+ ; Get the old values
+ ;
+ EnumRegValue $(KeyParameters) ValueList
+
+ ForListDo $(ValueList)
+ set ValueItem = $($)
+ set ValueName = *($(ValueItem),1)
+ set ValueData = *($(ValueItem),4)
+
+ Ifstr(i) $(ValueName) == "INTERRUPT"
+ set IRQ_Level = $(ValueData)
+ else-Ifstr(i) $(ValueName) == "IOADDRESS"
+ set IOBaseAddrValue = $(ValueData)
+ else-Ifstr(i) $(ValueName) == "InfraredTransceiverType"
+ set TRANSCEIVER_TYPE_Value = $(ValueData)
+ endif
+
+ EndForListDo
+;
+; Put up the adapter configuration dialog if necessary.
+;
+adaptersetup = +
+
+ Shell "" DebugConfiguration "before displaying dialog"
+
+ Set from = adapteroptions
+
+ Set IOADDR_Hex_Value = *($(IOADDR_Hex_List), ~($(IOADDR_Addr_List),$(IOBaseAddrValue)))
+
+ ;
+ ; Lists are indexed from one, so add one to our zero-based index.
+ ; Then select the current entry in the list we're about to display.
+ ;
+ set-add TRANSCEIVER_TYPE_Value = $(TRANSCEIVER_TYPE_Value), 1
+ set TRANSCEIVER_TYPE_Str = *($(TRANSCEIVER_TYPE_List), $(TRANSCEIVER_TYPE_Value))
+
+ ;===================================================
+ ; Netcard Detection logic
+ ;
+ ; Check that this card's parameters can be
+ ; fully detected.
+ ;
+ ; BUGBUG: network detection logic.
+ Shell $(ParamInf) Param_ParameterConfidence
+ Ifstr(i) $($R0) != STATUS_SUCCESSFUL
+ Debug-Output "OEMSETUP.INF: parameter confidence too low to bypass configuration"
+ Goto adapteroptions
+ Endif
+ ;
+ ; If this is a detected card and we're in EXPRESS mode,
+ ; see if the parameters as they currently exist are
+ ; verifiably correct.
+ ;
+ Ifstr(i) $(DetectedCard) == TRUE
+ Ifstr(i) $(!STF_INSTALL_MODE) != CUSTOM
+ Goto adapterverify
+ Endif
+ Endif
+ ;
+ ; End Netcard Detection logic
+ ;===================================================
+
+adapteroptions = +
+
+ ;BUGBUG: write a help file
+ ;sethelpfile "xpe3.hlp" 100 100
+
+ read-syms FileDependentDlg$(!STF_LANGUAGE)
+
+ ui start "InputDlg"
+
+ ifstr(i) $(DLGEVENT) == "CONTINUE"
+ set IRQ_Level = $(Combo1Out)
+ set IOADDR_Hex_Value = $(Combo2Out)
+
+ ; Lists are indexed starting from 1, so subtract 1 to get our index
+ set TRANSCEIVER_TYPE_Value = ~($(TRANSCEIVER_TYPE_List),$(Combo3Out))
+ set-sub TRANSCEIVER_TYPE_Value = $(TRANSCEIVER_TYPE_Value),1
+
+ Set IOBaseAddrValue = *($(IOADDR_Addr_List), ~($(IOADDR_Hex_List),$(IOADDR_Hex_Value)))
+
+ ui pop 1
+ else-ifstr(i) $(DLGEVENT) == "BACK"
+ set CommonStatus = STATUS_USERCANCEL
+ Debug-Output "Action: exit. Bye."
+ ui pop 1
+ goto end
+ else
+ Debug-Output "Action: unknown. Bye."
+ ui pop 1
+ goto end
+ endif
+
+adapterverify = +
+
+ Shell "" DebugConfiguration "after running dialog"
+
+ ;===================================================
+ ; Netcard Detection logic
+ ;
+ ; If this is a detected card, attempt to validate the options
+ ;
+ ;BUGBUG: no detection?
+ Ifstr(i) $(DetectedCard) != TRUE
+ Goto skipoptions
+ Endif
+
+ Debug-Output "OEMSETUP.INF: Calling Param_VerifyCard"
+ Shell $(ParamInf) Param_VerifyCard $(!STF_NCDETCARD)
+ Ifstr(i) $($R0) == STATUS_SUCCESSFUL
+ Debug-Output "OEMSETUP.INF: Param_VerifyCard succeeded"
+ Goto skipoptions
+ Endif
+ ;
+ ; Give the user a chance to retry or force the options given.
+ ;
+ Set from = adapteroptions
+ Set to = skipoptions
+ Shell $(UtilityInf),RegistryErrorString,VERIFY_WARNING
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output "ShellCode error: cannot get an error string."
+ goto ShellCodeError
+ endif
+ set Error = $($R0)
+ Goto Warning
+ ;
+ ; End Netcard Detection logic
+ ;===================================================
+
+;
+; If installing, go create the necessary keys;
+; if configuring, they're already open.
+;
+skipoptions =+
+
+ ifint $(OldVersionExisted) == $(TRUE)
+ ifstr(i) $(!NTN_InstallMode) == configure
+ goto writeparameters
+ endif
+ endif
+ StartWait
+ ;
+ ; Add Software Component
+ ;
+ ifint $(OldVersionExisted) == $(FALSE)
+ ifstr(i) $(!NTN_InstallMode) == "install"
+ Ifstr(i) $(DoCopy) == "YES"
+
+ Shell $(UtilityInf), DoAskSource, $(!STF_CWDDIR), $(SrcDir) YES
+
+ Ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Goto ShellCodeError
+ Else-Ifstr(i) $($R0) == STATUS_FAILED
+ Shell $(UtilityInf) RegistryErrorString "ASK_SOURCE_FAIL"
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ goto ShellCodeError
+ endif
+ set Error = $($R0)
+ Goto fatal
+ Else-Ifstr(i) $($R0) == STATUS_USERCANCEL
+ Goto successful
+ Endif
+
+ Set SrcDir = $($R1)
+
+ Endif
+
+ ifstr(i) $(STF_INSTALL_OUTCOME) != STF_SUCCESS
+ Shell $(UtilityInf) RegistryErrorString "UNABLE_COPY_FILE"
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ goto ShellCodeError
+ endif
+ set Error = $($R0)
+ goto fatal
+ endif
+ endif
+
+ Shell $(UtilityInf), AddSoftwareComponent, $(Manufacturer), +
+ $(ProductSoftwareName), +
+ $(ProductSoftwareName), +
+ $(ProductSoftwareTitle), $(STF_CONTEXTINFNAME), +
+ $(ProductSoftwareImagePath), "kernel", "NDIS", {}, "",+
+ $(NetEventDLL)
+
+ Set OEM_ABANDON_SOFTWARE = TRUE
+
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output "ShellCode error"
+ goto ShellCodeError
+ endif
+ ;
+ ; At this point:
+ ; $R1 contains the product version key handle;
+ ; $R2 contains the NetRules subkey handle;
+ ; $R3 contains the new Services key handle; and
+ ; $R4 contains the Parameters key
+ ; $R5 contains the Linkage Key
+ ;
+ set RegistryErrorIndex = $($R0)
+ set KeyProduct = $($R1)
+ Set SoftNetRulesKey = $($R2)
+ CloseRegKey $($R3)
+ CloseRegKey $($R4)
+ CloseRegKey $($R5)
+
+ Ifstr(i) $(RegistryErrorIndex) != NO_ERROR
+ EndWait
+ Debug-Output "Registry error: add software components"
+ CloseRegKey $(KeyProduct)
+ CloseRegKey $(SoftNetRulesKey)
+ goto fatalregistry
+ endif
+
+ set NewValueList = {{SoftwareType,$(NoTitle),$(!REG_VT_SZ),$(SoftwareType)},+
+ {MajorVersion,$(NoTitle),$(!REG_VT_DWORD),$(ProductMajorVersion)},+
+ {MinorVersion,$(NoTitle),$(!REG_VT_DWORD),$(ProductMinorVersion)},+
+ {Title,$(NoTitle),$(!REG_VT_SZ),$(ProductSoftwareTitle)},+
+ {Description,$(NoTitle),$(!REG_VT_SZ),$(ProductSoftwareDescription)},+
+ {ServiceName,$(NoTitle),$(!REG_VT_SZ),$(ProductSoftwareName)},+
+ {InstallDate,$(NoTitle),$(!REG_VT_DWORD),*($(Now),1)}}
+
+ Shell $(UtilityInf), AddValueList, $(KeyProduct), $(NewValueList)
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output "ShellCode error."
+ goto ShellCodeError
+ endif
+
+ set RegistryErrorIndex = $($R0)
+
+ Ifstr(i) $(RegistryErrorIndex) != NO_ERROR
+ EndWait
+ Debug-Output "Registry error: add value list."
+ CloseRegKey $(KeyProduct)
+ CloseRegKey $(SoftNetRulesKey)
+ goto fatalregistry
+ endif
+
+ set NewValueList = {{type,$(NoTitle),$(!REG_VT_SZ),$(NetRuleSoftwareType)},+
+ {use,$(NoTitle),$(!REG_VT_SZ),$(NetRuleSoftwareUse)}, +
+ {bindform,$(NoTitle),$(!REG_VT_SZ),$(NetRuleSoftwareBindForm)}, +
+ {class,$(NoTitle),$(!REG_VT_MULTI_SZ),$(NetRuleSoftwareClass)}, +
+ {bindable,$(NoTitle),$(!REG_VT_MULTI_SZ),$(NetRuleSoftwareBindable)}, +
+ {InfOption,$(NoTitle),$(!REG_VT_SZ),$(Option)}}
+
+ Shell $(UtilityInf), AddValueList, $(SoftNetRulesKey), $(NewValueList)
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output "ShellCode error."
+ goto ShellCodeError
+ endif
+
+ set RegistryErrorIndex = $($R0)
+
+ CloseRegKey $(KeyProduct)
+ CloseRegKey $(SoftNetRulesKey)
+
+ Ifstr(i) $(RegistryErrorIndex) != NO_ERROR
+ EndWait
+ Debug-Output "Registry error: add value list."
+ goto fatalregistry
+ endif
+ endif
+;
+; Create the HARDWARE\Netcard region and its corresponding service
+;
+ Shell $(UtilityInf), AddHardwareComponent, $(ProductHardwareName),$(STF_CONTEXTINFNAME),$(ProductKeyName)
+
+ ifint $($R4) != -1
+ Set OEM_ABANDON_OPTIONS = >($(OEM_ABANDON_OPTIONS), $(!NTN_SoftwareBase)"\Microsoft\Windows NT\CurrentVersion\NetworkCards\"$($R4))
+ endif
+
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output "Cannot add hardware component"
+ goto ShellCodeError
+ endif
+
+ set RegistryErrorIndex = $($R0)
+
+ Ifstr(i) $(RegistryErrorIndex) != NO_ERROR
+ EndWait
+ Debug-Output "Registry error: add hardware component"
+ CloseRegKey $($R1)
+ CloseRegKey $($R2)
+ CloseRegKey $($R3)
+ goto fatalregistry
+ endif
+
+;
+; At this point:
+; $R1 Registry key variable for HARDWARE\Netcard\(n)
+; $R2 Registry key variable for HARDWARE\Netcard\(n)\\NetRules
+; $R3 Registry key handle for <service>\Parameters key
+; $R4 Adapter number assigned to adapter
+; $R5 Service name generated by combining svc name with adapter number
+;
+ set KeyParameters = $($R3)
+ set KeyAdapterRules = $($R2)
+ set AdapterNumber = $($R4)
+
+ set NewValueList = {{Manufacturer,$(NoTitle),$(!REG_VT_SZ),$(Manufacturer)},+
+ {Title,$(NoTitle),$(!REG_VT_SZ),"["$($R4)"] "$(ProductHardware$(Option)Title)},+
+ {Description,$(NoTitle),$(!REG_VT_SZ),$(ProductHardware$(Option)Description)},+
+ {ProductName,$(NoTitle),$(!REG_VT_SZ),$(ProductHardwareName)},+
+ {ServiceName,$(NoTitle),$(!REG_VT_SZ),$($R5)},+
+ {InstallDate,$(NoTitle),$(!REG_VT_DWORD),*($(Now),1)}}
+
+ Shell $(UtilityInf), AddValueList, $($R1), $(NewValueList)
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output "ShellCode error"
+ goto ShellCodeError
+ endif
+
+ CloseRegKey $($R1)
+
+ set TempProdName = """"$(ProductHardwareName)$(AdapterNumber)""""
+ set TempBindForm = $(TempProdName)$(NetRuleHardwareBindForm)
+
+ set NewValueList = {{type,$(NoTitle),$(!REG_VT_SZ),$(NetRuleHardwareType)},+
+ {bindform,$(NoTitle),$(!REG_VT_SZ),$(TempBindForm)}, +
+ {class,$(NoTitle),$(!REG_VT_MULTI_SZ),$(NetRuleHardwareClass)}, +
+ {InfOption,$(NoTitle),$(!REG_VT_SZ),$(Option)}}
+
+ Shell $(UtilityInf), AddValueList, $(KeyAdapterRules), $(NewValueList)
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output "ShellCode error."
+ goto ShellCodeError
+ endif
+
+ set RegistryErrorIndex = $($R0)
+
+ Ifstr(i) $(RegistryErrorIndex) != NO_ERROR
+ EndWait
+ Debug-Output "Registry error: add value list."
+ CloseRegKey $(KeyParameters)
+ CloseRegKey $(KeyAdapterRules)
+ goto fatalregistry
+ endif
+
+ CloseRegKey $(KeyAdapterRules)
+
+ goto writeparameters
+;
+; REQUIRED: $(KeyParameters) contains service Parameters key handle
+;
+writeparameters = +
+ Shell $(UtilityInf), GetBusTypeNum
+ set BusTypeNum = $($R1)
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output "ShellCode error."
+ goto ShellCodeError
+ endif
+;
+; Add the rest of the parameters to the Services area
+;
+ Set NewValueList = {{BusType,$(NoTitle),$(!REG_VT_DWORD),$(BusTypeNum)},+
+ {BusNumber,$(NoTitle),$(!REG_VT_DWORD),0},+
+ {MediaType,$(NoTitle),$(!REG_VT_DWORD),1},+
+ {INTERRUPT,$(NoTitle),$(!REG_VT_DWORD),$(IRQ_Level)},+
+ {IOADDRESS,$(NoTitle),$(!REG_VT_DWORD),$(IOBaseAddrValue)},+
+ {InfraredTransceiverType,$(NoTitle),$(!REG_VT_DWORD),$(TRANSCEIVER_TYPE_Value)},+
+ {VerboseStatus,$(NoTitle),$(!REG_VT_DWORD),1}}
+
+
+
+ Shell $(UtilityInf), AddValueList, $(KeyParameters), $(NewValueList)
+
+ CloseRegKey $(KeyParameters)
+
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output "ShellCode error."
+ goto ShellCodeError
+ endif
+
+ set RegistryErrorIndex = $($R0)
+
+ Ifstr(i) $(RegistryErrorIndex) != NO_ERROR
+ Debug-Output "Registry error: Add value list"
+ goto fatalregistry
+ endif
+
+ EndWait
+
+ goto successful
+
+;-----------------------------------------------
+; Binding section
+;-----------------------------------------------
+bindingadapter =+
+ set Error = "Binding: Sorry, not yet implemented."
+ goto fatal
+
+;-----------------------------------------------
+; Removeadapter section
+;-----------------------------------------------
+
+removeadapter = +
+ Ifstr(i) $(ProductKeyName) == $(!NTN_RegBase)
+ ; Remove Software Component
+ Shell $(UtilityInf), RemoveSoftwareComponent, $(Manufacturer), +
+ $(ProductSoftwareName)
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output "ShellCode error"
+ goto ShellCodeError
+ endif
+
+ set RegistryErrorIndex = $($R0)
+
+ Ifstr(i) $(RegistryErrorIndex) != NO_ERROR
+ goto fatalregistry
+ endif
+ else
+ Shell $(UtilityInf), RemoveHardwareComponent, $(Manufacturer), +
+ $(ProductSoftwareName), $(!NTN_RegBase)
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output "ShellCode error"
+ goto ShellCodeError
+ endif
+
+ set RegistryErrorIndex = $($R0)
+
+ Ifstr(i) $(RegistryErrorIndex) != NO_ERROR
+ goto fatalregistry
+ endif
+ endif
+
+ goto end
+
+;-----------------------------------------------
+; Upgrade Software section
+;-----------------------------------------------
+
+UpgradeSoftware = +
+ ;
+ ; First determine whether we want to do upgrade or update for software
+ ; or hardware component. Then we will determine whether the Mode is
+ ; update or upgrade.
+ ;
+ ; If the same version of the product existed in the registry, we do
+ ; update. Otherwise, we will do a upgrade
+ ;
+ ifstr(i) $(ProductKeyName) == $(!NTN_RegBase)
+ ; Upgrade software component
+ ;
+ ; see whether the same version exist or not
+ ;
+ OpenRegKey $(!REG_H_LOCAL) "" $(ProductKeyName) $(MAXIMUM_ALLOWED) KeyProduct
+
+ Ifstr $(KeyProduct) != $(KeyNull)
+ GetRegValue $(KeyProduct),"MajorVersion", VersionInfo
+ set Version = *($(VersionInfo), 4)
+
+ ;
+ ; Update the binaries
+ ;
+ Split-String $(!NTN_Infname), "\", FilenameList
+ QueryListSize ListSize $(FilenameList)
+ set !UG_Filename = *($(FilenameList), $(ListSize))
+
+ install "Install-Update"
+ ifstr(i) $(STF_INSTALL_OUTCOME) != STF_SUCCESS
+ goto fatal
+ endif
+
+ ; Upgrade the version number
+ ;
+ SetRegValue $(KeyProduct) {MajorVersion,$(NoTitle),$(!REG_VT_SZ),$(ProductMajorVersion)}
+ SetRegValue $(KeyProduct) {MinorVersion,$(NoTitle),$(!REG_VT_SZ),$(ProductMinorVersion)}
+
+ ;
+ ; do nothing for update
+ ;
+ ifint $(Version) != $(ProductVersion)
+ ;
+ ; If the major version number is not the same,
+ ; it is major upgrade. So let Upgrade the product
+ ;
+ ;
+ ; make other upgrade change if necessary
+ ;
+ endif
+ CloseRegKey $(KeyProduct)
+ else
+ ;
+ ; Cannot Open software key, goto ERROR
+ ;
+ goto fatalregistry
+ endif
+ else
+ ;
+ ; upgrade/update hardware component
+ ; There is no different between upgrade and update for hardware
+ ; component
+ ;
+ ; 1. Get the Service Name
+ ; 2. Change the NetRule section if necessary
+ ;
+ OpenRegKey $(!REG_H_LOCAL) "" $(!NTN_RegBase) +
+ $(MAXIMUM_ALLOWED) NetworkCardKey
+ Ifstr(i) $(NetworkCardKey) != $(KeyNull)
+ ;
+ ; Get Service name
+ ;
+ GetRegValue $(NetworkCardKey),"ServiceName", ServiceNameInfo
+ set ServiceName = *($(ServiceNameInfo), 4)
+
+ ;
+ ; Change the NetRule if necessary
+ ;
+ OpenRegKey $(NetworkCardKey) "" "NetRules" +
+ $(MAXIMUM_ALLOWED) NetRuleKey
+ Ifstr(i) $(NetRuleKey) != $(KeyNull)
+ ;
+ ; Make the change....
+ ;
+ else
+ ;
+ ; Error, cannot open net rules key
+ ;
+ goto fatalregistry
+ endif
+
+ CloseRegKey $(NetRules)
+ CloseRegKey $(NetworkCardKey)
+ else
+ ;
+ ; Error, cannot open network card key
+ ;
+ goto fatalregistry
+ endif
+ ;
+ ; 3. Change the service section of the hardware. i.e.,
+ ; ParameterName change, value change, etc.
+ ;
+ OpenRegKey $(!REG_H_LOCAL) "" +
+ $(!NTN_ServiceBase)"\"$(ServiceName) +
+ $(MAXIMUM_ALLOWED) ServiceKey
+
+ Ifstr(i) $(ServiceKey) != $(KeyNull)
+ ;
+ ; Get the ServiceKey to change the Start value
+ ; or Type value. Or open Parameters key to
+ ; change the hardware parameters if necessary.
+ ;
+ CloseRegKey $(ServiceKey)
+ else
+ ;
+ ; Error, cannot open network card key
+ ;
+ goto fatalregistry
+ endif
+ endif
+
+ goto end
+ ;
+ ; End of Upgrade Software
+ ;
+
+;
+; Escape hatches
+;
+successful = +
+ goto end
+
+abandon = +
+ ForListDo $(OEM_ABANDON_OPTIONS)
+ Shell $(UtilityInf), RemoveHardwareComponent, $(Manufacturer), +
+ $(ProductSoftwareName), $($)
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output "ShellCode error"
+ goto ShellCodeError
+ endif
+
+ set RegistryErrorIndex = $($R0)
+
+ Ifstr(i) $(RegistryErrorIndex) != NO_ERROR
+ goto fatalregistry
+ endif
+ EndForListDo
+
+ Ifstr(i) $(OEM_ABANDON_SOFTWARE) == TRUE
+ ; Remove Software Component
+ Shell $(UtilityInf), RemoveSoftwareComponent, $(Manufacturer), +
+ $(ProductSoftwareName), FALSE
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output "ShellCode error"
+ goto ShellCodeError
+ endif
+
+ set RegistryErrorIndex = $($R0)
+
+ Ifstr(i) $(RegistryErrorIndex) != NO_ERROR
+ goto fatalregistry
+ endif
+ endif
+
+ goto end
+
+;
+; warning display
+;
+warning = +
+ Shell $(subroutineinf) SetupMessage, $(!STF_LANGUAGE), "WARNING", $(Error)
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ goto ShellCodeError
+ endif
+ ifstr(i) $($R1) == "OK"
+ goto $(to)
+ else-ifstr(i) $($R1) == "CANCEL"
+ goto $(from)
+ else
+ goto "end"
+ endif
+;
+; non fatal error display
+;
+nonfatalinfo = +
+ Set Severity = STATUS
+ Set CommonStatus = STATUS_USERCANCEL
+ goto nonfatalmsg
+nonfatal = +
+ Set Severity = NONFATAL
+ goto nonfatalmsg
+nonfatalmsg = +
+ ifstr(i) $(Error) == ""
+ Set Severity = NONFATAL
+ Shell $(UtilityInf) RegistryErrorString "SETUP_FAIL"
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ goto ShellCodeError
+ endif
+ set Error = $($R0)
+ endif
+ Shell $(subroutineinf) SetupMessage, $(!STF_LANGUAGE), $(Severity), $(Error)
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ goto ShellCodeError
+ endif
+ ifstr(i) $($R1) == "OK"
+ goto $(from)
+ else
+ goto "end"
+ endif
+
+;
+; Registry is broken
+;
+fatalregistry = +
+ Shell $(UtilityInf) RegistryErrorString $(RegistryErrorIndex)
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ goto ShellCodeError
+ endif
+ set Error = $($R0)
+ goto fatal
+;
+; Netcard detection failure
+;
+fataldetect = +
+ Shell $(UtilityInf),RegistryErrorString,CANNOT_DETECT
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output "ShellCode error: cannot get an error string."
+ goto ShellCodeError
+ endif
+ set Error = $($R0)
+ Goto fatal
+;
+; fatal error display
+;
+fatal = +
+ ifstr(i) $(Error) == ""
+ Shell $(UtilityInf) RegistryErrorString "SETUP_FAIL"
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ goto ShellCodeError
+ endif
+ set Error = $($R0)
+ endif
+ Shell $(subroutineinf) SetupMessage, $(!STF_LANGUAGE), "FATAL", $(Error)
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ goto ShellCodeError
+ endif
+
+ goto setfailed
+
+;
+; Shelling error
+;
+ShellCodeError = +
+ set DlgType = "MessageBox"
+ set STF_MB_TITLE = "Error: "$(FunctionTitle)
+ set STF_MB_TEXT = "Shell Code Error"
+ set STF_MB_TYPE = 1
+ set STF_MB_ICON = 3
+ set STF_MB_DEF = 1
+ ui start "Error Message"
+ goto setfailed
+
+setfailed = +
+ set CommonStatus = STATUS_FAILED
+ ;
+ ; if OEM_ABANDON_ON == TRUE, then remove the registry entries
+ ;
+ ifstr(i) $(OEM_ABANDON_ON) == TRUE
+ set OEM_ABANDON_ON = FALSE
+ goto abandon
+ endif
+ goto end
+
+end = +
+ goto term
+
+term = +
+
+ Return $(CommonStatus)
+
+[DebugConfiguration]
+
+ Set InfName = "OEMSETUP.INF"
+ Debug-Output $(InfName)" **CONFIGURATION STATE: "$($0)
+ Debug-Output $(InfName)" IRQ_Level is "$(!p:IRQ_Level)
+ Debug-Output $(InfName)" IOBaseAddrValue is "$(!p:IOBaseAddrValue)
+ Debug-Output $(InfName)" TRANSCEIVER_TYPE_Value is "$(!p:TRANSCEIVER_TYPE_Value)
+
+ return
+
+
+;***************************************************************
+; INSTALL SECTIONS
+;***************************************************************
+[Install-Option]
+ set STF_VITAL = ""
+
+ ifstr(i) $(AddCopy) == "YES"
+ AddSectionFilesToCopyList Files-$(Option) $(SrcDir) $(!STF_WINDOWSSYSPATH)\drivers
+ AddSectionFilesToCopyList Files-Help $(SrcDir) $(!STF_WINDOWSSYSPATH)
+ endif
+
+ ifstr(i) $(DoCopy) == "YES"
+ set !STF_NCPA_FLUSH_COPYLIST = TRUE
+ CopyFilesInCopyList
+
+ endif
+
+ Exit
+
+[Install-Update]
+ set STF_VITAL = ""
+ set STF_OVERWRITE = "VERIFYSOURCEOLDER"
+ ;set STF_VERSION = "YES"
+
+ AddSectionFilesToCopyList Files-$(Option) $(SrcDir) $(!STF_WINDOWSSYSPATH)\drivers
+ AddSectionFilesToCopyList Files-Inf $(SrcDir) $(!STF_WINDOWSSYSPATH)
+
+ set !STF_NCPA_FLUSH_COPYLIST = TRUE
+ CopyFilesInCopyList
+
+ exit
+
+[Source Media Descriptions]
+ 1 = "Fast Infrared setup disk"
+
+[Files-Inf]
+1, oemsetup.inf, SIZE=999, RENAME=$(!UG_Filename)
+
+[Files-IRMINI]
+1, IRMINI.SYS, SIZE=999
+
+[Files-Help]
+ \ No newline at end of file
diff --git a/private/ntos/ndis/irmini/parallax.c b/private/ntos/ndis/irmini/parallax.c
new file mode 100644
index 000000000..a9f12aab0
--- /dev/null
+++ b/private/ntos/ndis/irmini/parallax.c
@@ -0,0 +1,113 @@
+/*
+ * PARALLAX.C
+ *
+ *
+ *
+ */
+
+#ifndef IRMINILIB
+
+ #include "dongle.h"
+
+
+ /*
+ * The programming interface to a UART (COM serial port)
+ * consists of eight consecutive registers.
+ * These are the port offsets from the UART's base I/O address.
+ */
+ typedef enum comPortRegOffsets {
+ XFER_REG_OFFSET = 0,
+ INT_ENABLE_REG_OFFSET = 1,
+ INT_ID_AND_FIFO_CNTRL_REG_OFFSET = 2,
+ LINE_CONTROL_REG_OFFSET = 3,
+ MODEM_CONTROL_REG_OFFSET = 4,
+ LINE_STAT_REG_OFFSET = 5,
+ MODEM_STAT_REG_OFFSET = 6,
+ SCRATCH_REG_OFFSET = 7
+ } comPortRegOffset;
+
+
+ #define PARALLAX_IRDA_SPEEDS ( \
+ NDIS_IRDA_SPEED_2400 | \
+ NDIS_IRDA_SPEED_9600 | \
+ NDIS_IRDA_SPEED_19200 | \
+ NDIS_IRDA_SPEED_38400 | \
+ NDIS_IRDA_SPEED_57600 | \
+ NDIS_IRDA_SPEED_115200 \
+ )
+
+
+
+ BOOLEAN PARALLAX_Init(UINT comBase, dongleCapabilities *caps, UINT *context)
+ {
+ UCHAR modemCntrlVal;
+
+ IRMINI_RawReadPort(comBase+MODEM_CONTROL_REG_OFFSET, &modemCntrlVal);
+ modemCntrlVal |= 3;
+ IRMINI_RawWritePort(comBase+MODEM_CONTROL_REG_OFFSET, modemCntrlVal);
+ IRMINI_StallExecution(1000);
+
+ caps->supportedSpeedsMask = PARALLAX_IRDA_SPEEDS;
+ caps->turnAroundTime_usec = 5000;
+ caps->extraBOFsRequired = 0;
+
+ *context = 0;
+
+ return TRUE;
+ }
+
+ VOID PARALLAX_Deinit(UINT comBase, UINT context)
+ {
+
+ }
+
+ BOOLEAN PARALLAX_SetSpeed(UINT comBase, UINT bitsPerSec, UINT context)
+ {
+ UCHAR modemCntrlVal;
+ UINT numToggles;
+
+ IRMINI_RawReadPort(comBase+MODEM_CONTROL_REG_OFFSET, &modemCntrlVal);
+
+ /*
+ * First set the speed to 115200 baud.
+ */
+ modemCntrlVal &= ~2;
+ IRMINI_RawWritePort(comBase+MODEM_CONTROL_REG_OFFSET, modemCntrlVal);
+ IRMINI_StallExecution(1000);
+ modemCntrlVal |= 2;
+ IRMINI_RawWritePort(comBase+MODEM_CONTROL_REG_OFFSET, modemCntrlVal);
+ IRMINI_StallExecution(1000);
+
+ /*
+ * Now, "count down" from 115.2 Kbaud.
+ */
+ switch (bitsPerSec){
+ case 2400: numToggles = 6; break;
+ case 4800: numToggles = 5; break;
+ case 9600: numToggles = 4; break;
+ case 19200: numToggles = 3; break;
+ case 38400: numToggles = 2; break;
+ case 57600: numToggles = 1; break;
+ case 115200: numToggles = 0; break;
+ default:
+ /*
+ * Illegal speed
+ */
+ return FALSE;
+ }
+
+ while (numToggles-- > 0){
+ modemCntrlVal &= ~1;
+ IRMINI_RawWritePort(comBase+MODEM_CONTROL_REG_OFFSET, modemCntrlVal);
+ IRMINI_StallExecution(1000);
+ modemCntrlVal |= 1;
+ IRMINI_RawWritePort(comBase+MODEM_CONTROL_REG_OFFSET, modemCntrlVal);
+ IRMINI_StallExecution(1000);
+ }
+
+ return TRUE;
+ }
+
+
+#endif
+
diff --git a/private/ntos/ndis/irmini/parallax.h b/private/ntos/ndis/irmini/parallax.h
new file mode 100644
index 000000000..2fe8f2a08
--- /dev/null
+++ b/private/ntos/ndis/irmini/parallax.h
@@ -0,0 +1,20 @@
+/*
+ * PARALLAX.H
+ *
+ *
+ *
+ */
+
+#include "dongle.h"
+
+#ifndef PARALLAX_H
+ #define PARALLAX_H
+
+ BOOLEAN PARALLAX_Init(UINT comBase, dongleCapabilities *caps, UINT *context);
+ VOID PARALLAX_Deinit(UINT comBase, UINT context);
+ BOOLEAN PARALLAX_SetSpeed(UINT comBase, UINT bitsPerSec, UINT context);
+
+#endif PARALLAX_H
+
+
+
diff --git a/private/ntos/ndis/irmini/request.c b/private/ntos/ndis/irmini/request.c
new file mode 100644
index 000000000..17064d2d5
--- /dev/null
+++ b/private/ntos/ndis/irmini/request.c
@@ -0,0 +1,290 @@
+/*
+ ************************************************************************
+ *
+ * REQUEST.c
+ *
+ * IRMINI Infrared Serial NDIS Miniport driver.
+ *
+ * (C) Copyright 1996 Microsoft Corp.
+ *
+ *
+ * (ep)
+ *
+ *************************************************************************
+ */
+
+
+#include "irmini.h"
+
+
+
+/*
+ *************************************************************************
+ * MiniportQueryInformation
+ *************************************************************************
+ *
+ *
+ * MiniportQueryInformation queries the capabilities and status of the miniport driver.
+ *
+ *
+ */
+NDIS_STATUS MiniportQueryInformation (
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+ )
+{
+ NDIS_STATUS result = NDIS_STATUS_SUCCESS;
+ IrDevice *thisDev = CONTEXT_TO_DEV(MiniportAdapterContext);
+ UINT i, speeds;
+ UINT *infoPtr;
+
+
+ if (InformationBufferLength >= sizeof(int)){
+
+ switch (Oid){
+
+ case OID_IRDA_RECEIVING:
+ DBGOUT(("MiniportQueryInformation(OID_IRDA_RECEIVING)"));
+ *(UINT *)InformationBuffer = (UINT)thisDev->nowReceiving;
+ *BytesWritten = sizeof(UINT);
+ *BytesNeeded = 0;
+ break;
+
+ case OID_IRDA_SUPPORTED_SPEEDS:
+ DBGOUT(("MiniportQueryInformation(OID_IRDA_SUPPORTED_SPEEDS)"));
+
+ speeds = thisDev->portInfo.hwCaps.supportedSpeedsMask & ALL_SLOW_IRDA_SPEEDS;
+ *BytesWritten = 0;
+
+ for (i = 0, infoPtr = (PUINT)InformationBuffer;
+ (i < NUM_BAUDRATES) &&
+ speeds &&
+ (InformationBufferLength >= sizeof(UINT));
+ i++){
+
+ if (supportedBaudRateTable[i].ndisCode & speeds){
+ *infoPtr++ = supportedBaudRateTable[i].bitsPerSec;
+ InformationBufferLength -= sizeof(UINT);
+ *BytesWritten += sizeof(UINT);
+ speeds &= ~supportedBaudRateTable[i].ndisCode;
+ DBGOUT((" - supporting speed %d bps", supportedBaudRateTable[i].bitsPerSec));
+ }
+ }
+
+ if (speeds){
+ /*
+ * We ran out of room in InformationBuffer.
+ * Count the remaining number of bits set in speeds
+ * to figure out the number of remaining bytes needed.
+ */
+ for (*BytesNeeded = 0; speeds; *BytesNeeded += sizeof(UINT)){
+ /*
+ * This instruction clears the lowest set bit in speeds.
+ * Trust me.
+ */
+ speeds &= (speeds - 1);
+ }
+ result = NDIS_STATUS_INVALID_LENGTH;
+ }
+ else {
+ result = NDIS_STATUS_SUCCESS;
+ *BytesNeeded = 0;
+ }
+ break;
+
+ case OID_IRDA_LINK_SPEED:
+ DBGOUT(("MiniportQueryInformation(OID_IRDA_LINK_SPEED)"));
+ if (thisDev->linkSpeedInfo){
+ *(UINT *)InformationBuffer = thisDev->linkSpeedInfo->bitsPerSec;
+ }
+ else {
+ *(UINT *)InformationBuffer = DEFAULT_BAUD_RATE;
+ }
+ *BytesWritten = sizeof(UINT);
+ *BytesNeeded = 0;
+ break;
+
+ case OID_IRDA_MEDIA_BUSY:
+ DBGOUT(("MiniportQueryInformation(OID_IRDA_MEDIA_BUSY)"));
+ *(UINT *)InformationBuffer = (UINT)thisDev->mediaBusy;
+ *BytesWritten = sizeof(UINT);
+ *BytesNeeded = 0;
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+ DBGOUT(("MiniportQueryInformation(OID_GEN_MAXIMUM_LOOKAHEAD)"));
+ *(UINT *)InformationBuffer = 256;
+ *BytesWritten = sizeof(UINT);
+ *BytesNeeded = 0;
+ break;
+
+ case OID_GEN_MAC_OPTIONS:
+ DBGOUT(("MiniportQueryInformation(OID_GEN_MAC_OPTIONS)"));
+ *(UINT *)InformationBuffer =
+ NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
+ NDIS_MAC_OPTION_TRANSFERS_NOT_PEND;
+ *BytesWritten = sizeof(UINT);
+ *BytesNeeded = 0;
+ break;
+
+ case OID_GEN_MAXIMUM_SEND_PACKETS:
+ DBGOUT(("MiniportQueryInformation(OID_GEN_MAXIMUM_SEND_PACKETS)"));
+ *(UINT *)InformationBuffer = 16;
+ *BytesWritten = sizeof(UINT);
+ *BytesNeeded = 0;
+ break;
+
+ case OID_IRDA_TURNAROUND_TIME:
+ /*
+ * Indicate that the tranceiver requires at least 5000us (5 millisec)
+ * to recuperate after a send.
+ */
+ DBGOUT(("MiniportQueryInformation(OID_IRDA_TURNAROUND_TIME)"));
+ *(UINT *)InformationBuffer =
+ MAX(thisDev->portInfo.hwCaps.turnAroundTime_usec, 5000);
+ *BytesWritten = sizeof(UINT);
+ *BytesNeeded = 0;
+ break;
+
+ case OID_IRDA_EXTRA_RCV_BOFS:
+ /*
+ * Pass back the number of _extra_ BOFs to be prepended
+ * to packets sent to this unit at 115.2 baud, the
+ * maximum Slow IR speed. This will be scaled for other
+ * speed according to the table in the
+ * 'Infrared Extensions to NDIS' spec.
+ */
+ DBGOUT(("MiniportQueryInformation(OID_IRDA_EXTRA_RCV_BOFS)"));
+ *(UINT *)InformationBuffer = thisDev->portInfo.hwCaps.extraBOFsRequired;
+ *BytesWritten = sizeof(UINT);
+ *BytesNeeded = 0;
+ break;
+
+ case OID_IRDA_UNICAST_LIST:
+ case OID_IRDA_MAX_UNICAST_LIST_SIZE:
+ case OID_IRDA_RATE_SNIFF:
+ /*
+ * We don't support these
+ */
+ default:
+ DBGERR(("MiniportQueryInformation(%d=0x%x), unsupported OID", Oid, Oid));
+ result = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+ }
+ else {
+ *BytesNeeded = sizeof(UINT) - InformationBufferLength;
+ *BytesWritten = 0;
+ result = NDIS_STATUS_INVALID_LENGTH;
+ }
+
+
+ DBGOUT(("MiniportQueryInformation succeeded (info <- %d)", *(UINT *)InformationBuffer));
+ return result;
+
+}
+
+
+
+
+/*
+ *************************************************************************
+ * MiniportSetInformation
+ *************************************************************************
+ *
+ *
+ * MiniportSetInformation allows other layers of the network software
+ * (e.g., a transport driver) to control the miniport driver by changing
+ * information that the miniport driver maintains in its OIDs,
+ * such as the packet filters or multicast addresses.
+ *
+ *
+ */
+NDIS_STATUS MiniportSetInformation (
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ )
+{
+ NDIS_STATUS result = NDIS_STATUS_SUCCESS;
+ IrDevice *thisDev = CONTEXT_TO_DEV(MiniportAdapterContext);
+ int i;
+
+
+ if (InformationBufferLength >= sizeof(UINT)){
+
+ UINT info = *(UINT *)InformationBuffer;
+ *BytesRead = sizeof(UINT);
+ *BytesNeeded = 0;
+
+ switch (Oid){
+
+ case OID_IRDA_LINK_SPEED:
+ DBGOUT(("MiniportSetInformation(OID_IRDA_LINK_SPEED, %xh)", info));
+ result = NDIS_STATUS_INVALID_DATA;
+ for (i = 0; i < NUM_BAUDRATES; i++){
+ if (supportedBaudRateTable[i].bitsPerSec == info){
+ thisDev->linkSpeedInfo = &supportedBaudRateTable[i];
+ result = NDIS_STATUS_SUCCESS;
+ break;
+ }
+ }
+ if (result == NDIS_STATUS_SUCCESS){
+ if (!SetSpeed(thisDev)){
+ result = NDIS_STATUS_FAILURE;
+ }
+ }
+ else {
+ *BytesRead = 0;
+ *BytesNeeded = 0;
+ }
+ break;
+
+ case OID_IRDA_MEDIA_BUSY:
+ DBGOUT(("MiniportSetInformation(OID_IRDA_MEDIA_BUSY, %xh)", info));
+ /*
+ * The protocol can use this OID to reset the busy field
+ * in order to check it later for intervening activity.
+ */
+ thisDev->mediaBusy = (BOOLEAN)info;
+ result = NDIS_STATUS_SUCCESS;
+ break;
+
+ /*
+ * We don't support these
+ */
+ case OID_IRDA_RATE_SNIFF:
+ case OID_IRDA_UNICAST_LIST:
+ /*
+ * These are query-only parameters.
+ */
+ case OID_IRDA_SUPPORTED_SPEEDS:
+ case OID_IRDA_MAX_UNICAST_LIST_SIZE:
+ case OID_IRDA_TURNAROUND_TIME:
+ default:
+ DBGERR(("MiniportSetInformation(OID=%d=0x%x, value=%xh) - unsupported OID", Oid, Oid, info));
+ *BytesRead = 0;
+ *BytesNeeded = 0;
+ result = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+ }
+ else {
+ *BytesRead = 0;
+ *BytesNeeded = sizeof(UINT);
+ result = NDIS_STATUS_INVALID_LENGTH;
+ }
+
+
+ DBGOUT(("MiniportSetInformation succeeded"));
+ return result;
+
+}
+
diff --git a/private/ntos/ndis/irmini/resource.c b/private/ntos/ndis/irmini/resource.c
new file mode 100644
index 000000000..a6cad641a
--- /dev/null
+++ b/private/ntos/ndis/irmini/resource.c
@@ -0,0 +1,303 @@
+/*
+ ************************************************************************
+ *
+ * RESOURCE.c
+ *
+ * IRMINI Infrared Serial NDIS Miniport driver.
+ *
+ * (C) Copyright 1996 Microsoft Corp.
+ *
+ *
+ * (ep)
+ *
+ *************************************************************************
+ */
+
+
+#include "irmini.h"
+
+
+/*
+ *************************************************************************
+ * MyMemAlloc
+ *************************************************************************
+ *
+ */
+PVOID MyMemAlloc(UINT size)
+{
+ NDIS_STATUS stat;
+ PVOID memptr;
+ NDIS_PHYSICAL_ADDRESS noMaxAddr = NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
+ stat = NdisAllocateMemory(&memptr, size, 0, noMaxAddr);
+ if (stat != NDIS_STATUS_SUCCESS){
+ DBGERR(("Memory allocation failed"));
+ memptr = NULL;
+ }
+ return memptr;
+}
+
+
+/*
+ *************************************************************************
+ * MyMemFree
+ *************************************************************************
+ *
+ */
+VOID MyMemFree(PVOID memptr, UINT size)
+{
+ NdisFreeMemory(memptr, size, 0);
+}
+
+
+/*
+ *************************************************************************
+ * NewDevice
+ *************************************************************************
+ *
+ */
+IrDevice *NewDevice()
+{
+ IrDevice *newdev;
+
+ newdev = MyMemAlloc(sizeof(IrDevice));
+ if (newdev){
+ InitDevice(newdev);
+ }
+ return newdev;
+}
+
+
+/*
+ *************************************************************************
+ * FreeDevice
+ *************************************************************************
+ *
+ */
+VOID FreeDevice(IrDevice *dev)
+{
+ CloseDevice(dev);
+ MyMemFree((PVOID)dev, sizeof(IrDevice));
+}
+
+
+
+/*
+ *************************************************************************
+ * InitDevice
+ *************************************************************************
+ *
+ * Zero out the device object.
+ *
+ * Allocate the device object's spinlock, which will persist while
+ * the device is opened and closed.
+ *
+ */
+VOID InitDevice(IrDevice *thisDev)
+{
+ NdisZeroMemory((PVOID)thisDev, sizeof(IrDevice));
+ thisDev->firstRcvBufIndex = thisDev->lastRcvBufIndex = NO_BUF_INDEX;
+}
+
+
+
+
+/*
+ *************************************************************************
+ * OpenDevice
+ *************************************************************************
+ *
+ * Allocate resources for a single device object.
+ *
+ * This function should be called with device lock already held.
+ *
+ */
+BOOLEAN OpenDevice(IrDevice *thisDev)
+{
+ BOOLEAN result = FALSE;
+ NDIS_STATUS stat;
+ UINT bufIndex;
+
+ DBGOUT(("OpenDevice()"));
+
+ if (!thisDev){
+ return FALSE;
+ }
+
+
+ /*
+ * Allocate the NDIS packet and NDIS buffer pools
+ * for this device's RECEIVE buffer queue.
+ * Our receive packets must only contain one buffer apiece,
+ * so #buffers == #packets.
+ */
+ NdisAllocatePacketPool(&stat, &thisDev->packetPoolHandle, NUM_RCV_BUFS, 24);
+ if (stat != NDIS_STATUS_SUCCESS){
+ goto _openDone;
+ }
+ NdisAllocateBufferPool(&stat, &thisDev->bufferPoolHandle, NUM_RCV_BUFS);
+ if (stat != NDIS_STATUS_SUCCESS){
+ goto _openDone;
+ }
+
+
+ /*
+ * Initialize each of the RECEIVE packet objects for this device.
+ */
+ for (bufIndex = 0; bufIndex < NUM_RCV_BUFS; bufIndex++){
+
+ rcvBuffer *rcvBuf = &thisDev->rcvBufs[bufIndex];
+
+ rcvBuf->state = STATE_FREE;
+
+ /*
+ * Allocate a data buffer
+ *
+ * This buffer gets swapped with the one on comPortInfo
+ * and must be the same size.
+ */
+ rcvBuf->dataBuf = MyMemAlloc(RCV_BUFFER_SIZE);
+ if (!rcvBuf->dataBuf){
+ goto _openDone;
+ }
+
+ /*
+ * Allocate the NDIS_PACKET.
+ */
+ NdisAllocatePacket(&stat, &rcvBuf->packet, thisDev->packetPoolHandle);
+ if (stat != NDIS_STATUS_SUCCESS){
+ goto _openDone;
+ }
+
+ /*
+ * For future convenience, set the MiniportReserved portion of the packet
+ * to the index of the rcv buffer that contains it.
+ * This will be used in ReturnPacketHandler.
+ */
+ *(ULONG *)rcvBuf->packet->MiniportReserved = (ULONG)bufIndex;
+
+ rcvBuf->dataLen = 0;
+
+ }
+ thisDev->firstRcvBufIndex = thisDev->lastRcvBufIndex = NO_BUF_INDEX;
+
+
+ /*
+ * Initialize each of the SEND queue objects for this device.
+ */
+ thisDev->firstSendPacket = thisDev->lastSendPacket = NULL;
+
+ /*
+ * Set mediaBusy to TRUE initially. That way, we won't
+ * IndicateStatus to the protocol in the ISR unless the
+ * protocol has expressed interest by clearing this flag
+ * via MiniportSetInformation(OID_IRDA_MEDIA_BUSY).
+ */
+ thisDev->mediaBusy = FALSE;
+ thisDev->haveIndicatedMediaBusy = FALSE;
+
+ /*
+ * Will set speed to 9600 baud initially.
+ */
+ thisDev->linkSpeedInfo = &supportedBaudRateTable[BAUDRATE_9600];
+
+ thisDev->lastPacketAtOldSpeed = NULL;
+ thisDev->setSpeedAfterCurrentSendPacket = FALSE;
+
+ result = TRUE;
+
+_openDone:
+ if (!result){
+ /*
+ * If we're failing, close the device to free up any resources
+ * that were allocated for it.
+ */
+ CloseDevice(thisDev);
+ DBGOUT(("OpenDevice() failed"));
+ }
+ else {
+ DBGOUT(("OpenDevice() succeeded"));
+ }
+ return result;
+
+}
+
+
+
+/*
+ *************************************************************************
+ * CloseDevice
+ *************************************************************************
+ *
+ * Free the indicated device's resources.
+ *
+ *
+ * Called for shutdown and reset.
+ * Don't clear ndisAdapterHandle, since we might just be resetting.
+ * This function should be called with device lock held.
+ *
+ *
+ */
+VOID CloseDevice(IrDevice *thisDev)
+{
+ UINT bufIndex;
+
+ DBGOUT(("CloseDevice()"));
+
+ if (!thisDev){
+ return;
+ }
+
+ /*
+ * Free all resources for the RECEIVE buffer queue.
+ */
+ for (bufIndex = 0; bufIndex < NUM_RCV_BUFS; bufIndex++){
+
+ rcvBuffer *rcvBuf = &thisDev->rcvBufs[bufIndex];
+
+ if (rcvBuf->packet){
+ NdisFreePacket(rcvBuf->packet);
+ rcvBuf->packet = NULL;
+ }
+
+ if (rcvBuf->dataBuf){
+ MyMemFree(rcvBuf->dataBuf, RCV_BUFFER_SIZE);
+ rcvBuf->dataBuf = NULL;
+ }
+
+ rcvBuf->dataLen = 0;
+
+ rcvBuf->state = STATE_FREE;
+ }
+ thisDev->firstRcvBufIndex = thisDev->lastRcvBufIndex = NO_BUF_INDEX;
+
+ /*
+ * Free the packet and buffer pool handles for this device.
+ */
+ if (thisDev->packetPoolHandle){
+ NdisFreePacketPool(thisDev->packetPoolHandle);
+ thisDev->packetPoolHandle = NULL;
+ }
+ if (thisDev->bufferPoolHandle){
+ NdisFreeBufferPool(thisDev->bufferPoolHandle);
+ thisDev->bufferPoolHandle = NULL;
+ }
+
+
+ /*
+ * Free all resources for the SEND buffer queue.
+ */
+ while (thisDev->firstSendPacket){
+ PNDIS_PACKET nextPacket = *(PNDIS_PACKET *)thisDev->firstSendPacket->MiniportReserved;
+ NdisMSendComplete(thisDev->ndisAdapterHandle, thisDev->firstSendPacket, NDIS_STATUS_FAILURE);
+ thisDev->firstSendPacket = nextPacket;
+ }
+
+
+ thisDev->mediaBusy = FALSE;
+ thisDev->haveIndicatedMediaBusy = FALSE;
+
+ thisDev->linkSpeedInfo = NULL;
+
+}
+
+
diff --git a/private/ntos/ndis/irmini/settings.c b/private/ntos/ndis/irmini/settings.c
new file mode 100644
index 000000000..4a60986a1
--- /dev/null
+++ b/private/ntos/ndis/irmini/settings.c
@@ -0,0 +1,139 @@
+/*
+ ************************************************************************
+ *
+ * SETTINGS.c
+ *
+ * IRMINI Infrared Serial NDIS Miniport driver.
+ *
+ * (C) Copyright 1996 Microsoft Corp.
+ *
+ *
+ * (ep)
+ *
+ *************************************************************************
+ */
+
+
+
+#include "irmini.h"
+
+
+
+
+baudRateInfo supportedBaudRateTable[NUM_BAUDRATES] = {
+ {
+ BAUDRATE_2400,
+ 2400,
+ NDIS_IRDA_SPEED_2400,
+ },
+ {
+ BAUDRATE_9600,
+ 9600,
+ NDIS_IRDA_SPEED_9600,
+ },
+ {
+ BAUDRATE_19200,
+ 19200,
+ NDIS_IRDA_SPEED_19200,
+ },
+ {
+ BAUDRATE_38400,
+ 38400,
+ NDIS_IRDA_SPEED_38400,
+ },
+ {
+ BAUDRATE_57600,
+ 57600,
+ NDIS_IRDA_SPEED_57600,
+ },
+ {
+ BAUDRATE_115200,
+ 115200,
+ NDIS_IRDA_SPEED_115200,
+ },
+ {
+ BAUDRATE_576000,
+ 576000,
+ NDIS_IRDA_SPEED_576K,
+ },
+ {
+ BAUDRATE_1152000,
+ 1152000,
+ NDIS_IRDA_SPEED_1152K,
+ },
+ {
+ BAUDRATE_4000000,
+ 4000000,
+ NDIS_IRDA_SPEED_4M,
+ }
+};
+
+
+
+#if (DBG && defined(_X86_))
+
+ UINT dbgOptions = 0;
+ #ifdef DBG_ADD_PKT_ID
+ BOOLEAN addPktIdOn = FALSE;
+ #endif
+
+ VOID DBG_PrintBuf(PUCHAR bufptr, UINT buflen)
+ {
+ UINT i, linei;
+
+ #define ISPRINT(ch) (((ch) >= ' ') && ((ch) <= '~'))
+ #define PRINTCHAR(ch) (UCHAR)(ISPRINT(ch) ? (ch) : '.')
+
+ _asm pushf
+ _asm cli
+
+ DbgPrint("\r\n %d bytes @%xh:", buflen, (UINT)bufptr);
+
+ /*
+ * Print whole lines of 8 characters with HEX and ASCII
+ */
+ for (i = 0; i+8 <= (UINT)buflen; i += 8){
+ UCHAR ch0 = bufptr[i+0],
+ ch1 = bufptr[i+1],
+ ch2 = bufptr[i+2],
+ ch3 = bufptr[i+3],
+ ch4 = bufptr[i+4],
+ ch5 = bufptr[i+5],
+ ch6 = bufptr[i+6],
+ ch7 = bufptr[i+7];
+
+ DbgPrint("\r\n %02x %02x %02x %02x %02x %02x %02x %02x"
+ " %c %c %c %c %c %c %c %c",
+ ch0, ch1, ch2, ch3, ch4, ch5, ch6, ch7,
+ PRINTCHAR(ch0),
+ PRINTCHAR(ch1),
+ PRINTCHAR(ch2),
+ PRINTCHAR(ch3),
+ PRINTCHAR(ch4),
+ PRINTCHAR(ch5),
+ PRINTCHAR(ch6),
+ PRINTCHAR(ch7));
+ }
+
+ /*
+ * Print final incomplete line
+ */
+ DbgPrint("\r\n ");
+ for (linei = 0; (linei < 8) && (i < buflen); i++, linei++){
+ DbgPrint(" %02x", (UINT)(bufptr[i]));
+ }
+ DbgPrint(" ");
+ i -= linei;
+ while (linei++ < 8) DbgPrint(" ");
+ for (linei = 0; (linei < 8) && (i < buflen); i++, linei++){
+ UCHAR ch = bufptr[i];
+ DbgPrint(" %c", PRINTCHAR(ch));
+ }
+
+ DbgPrint("\t\t<>\r\n");
+
+ _asm popf
+ }
+
+#endif
+
diff --git a/private/ntos/ndis/irmini/settings.h b/private/ntos/ndis/irmini/settings.h
new file mode 100644
index 000000000..f41ccd3ae
--- /dev/null
+++ b/private/ntos/ndis/irmini/settings.h
@@ -0,0 +1,226 @@
+/*
+ ************************************************************************
+ *
+ * SETTINGS.h
+ *
+ * IRMINI Infrared Serial NDIS Miniport driver.
+ *
+ * (C) Copyright 1996 Microsoft Corp.
+ *
+ *
+ * (ep)
+ *
+ *************************************************************************
+ */
+
+
+
+#ifndef SETTINGS_H
+ #define SETTINGS_H
+
+ #include "dongle.h"
+
+ #if (DBG && defined(_X86_))
+
+ /*
+ * The DBG_ADD_PKT_ID flag causes the miniport to add/delete a packet id to each packet.
+ * This is only for debugging purposes; it makes the miniport INCOMPATIBLE
+ * with all others.
+ */
+ // #define DBG_ADD_PKT_ID
+
+ #ifdef DBG_ADD_PKT_ID
+ extern BOOLEAN addPktIdOn;
+ #endif
+
+ typedef enum {
+ DBG_ERR = (1 << 0),
+ DBG_STAT = (1 << 1),
+ DBG_MSG = (1 << 2),
+ DBG_BUF = (1 << 3),
+ DBG_PACKET = (1 << 4),
+
+ DBG_ALL = (DBG_ERR|DBG_STAT|DBG_MSG|DBG_BUF|DBG_PACKET)
+ };
+ extern ULONG _cdecl DbgPrint(PCHAR Format, ...);
+ extern UINT dbgOptions;
+
+ #define DBG_NDIS_RESULT_STR(_ndisResult) \
+ (PUCHAR)( (_ndisResult == NDIS_STATUS_SUCCESS) ? "NDIS_STATUS_SUCCESS" : \
+ (_ndisResult == NDIS_STATUS_FAILURE) ? "NDIS_STATUS_FAILURE" : \
+ (_ndisResult == NDIS_STATUS_PENDING) ? "NDIS_STATUS_PENDING" : \
+ "NDIS_STATUS_???")
+ #define DBGPRINT(dbgprint_params_in_parens) \
+ { \
+ _asm { pushf } \
+ _asm { cli } \
+ DbgPrint("IRMINI: "); \
+ DbgPrint dbgprint_params_in_parens; \
+ DbgPrint("\r\n"); \
+ _asm { popf } \
+ }
+ #define DBGOUT(dbgprint_params_in_parens) \
+ if (dbgOptions & DBG_MSG){ \
+ DBGPRINT(dbgprint_params_in_parens); \
+ }
+ #define DBGERR(dbgprint_params_in_parens) \
+ if (dbgOptions & DBG_ERR){ \
+ DBGPRINT((" *** IRMINI ERROR *** ")); \
+ DBGPRINT(dbgprint_params_in_parens); \
+ _asm { int 3 } /* DbgBreakPoint() causes problems */ \
+ }
+
+ #define DBGSTAT(dbgprint_params_in_parens) \
+ if (dbgOptions & DBG_STAT){ \
+ DBGPRINT(dbgprint_params_in_parens); \
+ }
+ #define DBGPKT(dbgprint_params_in_parens) \
+ if (dbgOptions & DBG_PACKET){ \
+ DBGPRINT(dbgprint_params_in_parens); \
+ }
+ extern VOID DBG_PrintBuf(PUCHAR bufptr, UINT buflen);
+ #define DBGPRINTBUF(bufptr, buflen) \
+ if (dbgOptions & DBG_BUF){ \
+ DBG_PrintBuf((PUCHAR)(bufptr), (UINT)(buflen)); \
+ }
+ #else
+ #define DBGOUT(dbgprint_params_in_parens)
+ #define DBGERR(dbgprint_params_in_parens)
+ #define DBGPRINTBUF(bufptr, buflen)
+ #define DBGSTAT(dbgprint_params_in_parens)
+ #define DBGPKT(dbgprint_params_in_parens)
+ #define DBGPRINTBUF(bufptr, buflen)
+ #define DBG_NDIS_RESULT_STR(_ndisResult)
+ #endif
+
+ enum baudRates {
+ /*
+ * Slow IR
+ */
+ BAUDRATE_2400 = 0,
+ BAUDRATE_9600,
+ BAUDRATE_19200,
+ BAUDRATE_38400,
+ BAUDRATE_57600,
+ BAUDRATE_115200,
+
+ /*
+ * Medium IR
+ */
+ BAUDRATE_576000,
+ BAUDRATE_1152000,
+
+ /*
+ * Fast IR
+ */
+ BAUDRATE_4000000,
+
+ NUM_BAUDRATES /* must be last */
+ };
+
+ #define DEFAULT_BAUDRATE BAUDRATE_115200
+
+ #define ALL_SLOW_IRDA_SPEEDS ( NDIS_IRDA_SPEED_2400 | \
+ NDIS_IRDA_SPEED_9600 | \
+ NDIS_IRDA_SPEED_19200 | \
+ NDIS_IRDA_SPEED_38400 | \
+ NDIS_IRDA_SPEED_57600 | \
+ NDIS_IRDA_SPEED_115200 \
+ )
+
+ #define DEFAULT_BOFS_CODE BOFS_48
+ #define MAX_NUM_EXTRA_BOFS 48
+ #define DEFAULT_NUM_EXTRA_BOFS MAX_NUM_EXTRA_BOFS
+
+
+ #define DEFAULT_TURNAROUND_usec 5000
+
+
+ typedef struct {
+ enum baudRates tableIndex;
+ UINT bitsPerSec;
+ UINT ndisCode; // bitmask element
+ } baudRateInfo;
+
+ #define DEFAULT_BAUD_RATE 9600
+
+
+
+ /*
+ * This is the largest IR packet size
+ * (counting _I_ field only, and not counting ESC characters)
+ * that we handle.
+ */
+ #define MAX_I_DATA_SIZE 2048
+ #define MAX_NDIS_DATA_SIZE (SLOW_IR_ADDR_SIZE+SLOW_IR_CONTROL_SIZE+MAX_I_DATA_SIZE)
+
+ #ifdef DBG_ADD_PKT_ID
+ #pragma message("WARNING: INCOMPATIBLE DEBUG VERSION")
+ #define MAX_RCV_DATA_SIZE (MAX_NDIS_DATA_SIZE+SLOW_IR_FCS_SIZE+sizeof(USHORT))
+ #else
+ #define MAX_RCV_DATA_SIZE (MAX_NDIS_DATA_SIZE+SLOW_IR_FCS_SIZE)
+ #endif
+
+ /*
+ * We loop an extra time in the receive FSM in order to
+ * see EOF after the last data byte; so we need some
+ * extra space in readBuf in case we then get garbage instead.
+ */
+ #define RCV_BUFFER_SIZE (MAX_RCV_DATA_SIZE+4)
+
+
+ /*
+ * We allocate buffers twice as large as the max rcv size to
+ * accomodate ESC characters and BOFs, etc.
+ * Recall that in the worst possible case, the data contains
+ * all BOF/EOF/ESC characters, in which case we must expand it to
+ * twice its original size.
+ */
+ #define MAX_POSSIBLE_IR_PACKET_SIZE_FOR_DATA(dataLen) \
+ ((dataLen)*2 + \
+ (MAX_NUM_EXTRA_BOFS+1)*SLOW_IR_BOF_SIZE + \
+ SLOW_IR_ADDR_SIZE + \
+ SLOW_IR_CONTROL_SIZE + \
+ SLOW_IR_FCS_SIZE + \
+ SLOW_IR_EOF_SIZE)
+ #define MAX_IRDA_DATA_SIZE MAX_POSSIBLE_IR_PACKET_SIZE_FOR_DATA(MAX_I_DATA_SIZE)
+
+ /*
+ * When FCS is computed on an IR packet with FCS appended,
+ * the result should be this constant.
+ */
+ #define GOOD_FCS ((USHORT)~0xf0b8)
+
+
+ /*
+ * Sizes of IrLAP frame fields:
+ * Beginning Of Frame (BOF)
+ * End Of Frame (EOF)
+ * Address
+ * Control
+ */
+ #define SLOW_IR_BOF_TYPE UCHAR
+ #define SLOW_IR_BOF_SIZE sizeof(SLOW_IR_BOF_TYPE)
+ #define SLOW_IR_EXTRA_BOF_TYPE UCHAR
+ #define SLOW_IR_EXTRA_BOF_SIZE sizeof(SLOW_IR_EXTRA_BOF_TYPE)
+ #define SLOW_IR_EOF_TYPE UCHAR
+ #define SLOW_IR_EOF_SIZE sizeof(SLOW_IR_EOF_TYPE)
+ #define SLOW_IR_FCS_TYPE USHORT
+ #define SLOW_IR_FCS_SIZE sizeof(SLOW_IR_FCS_TYPE)
+ #define SLOW_IR_ADDR_SIZE 1
+ #define SLOW_IR_CONTROL_SIZE 1
+ #define SLOW_IR_BOF 0xC0
+ #define SLOW_IR_EXTRA_BOF 0xC0 /* don't use 0xFF, it breaks some HP printers! */
+ #define SLOW_IR_EOF 0xC1
+ #define SLOW_IR_ESC 0x7D
+ #define SLOW_IR_ESC_COMP 0x20
+ #define MEDIUM_IR_BOF 0x7E
+ #define MEDIUM_IR_EOF 0x7E
+
+
+ #define MIN(a,b) (((a) <= (b)) ? (a) : (b))
+ #define MAX(a,b) (((a) >= (b)) ? (a) : (b))
+
+
+#endif SETTINGS_H
+
diff --git a/private/ntos/ndis/irmini/sources b/private/ntos/ndis/irmini/sources
new file mode 100644
index 000000000..9c493765b
--- /dev/null
+++ b/private/ntos/ndis/irmini/sources
@@ -0,0 +1,32 @@
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=irmini
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER -DNDIS40_MINIPORT -DIRDA -DDBG=1
+
+INCLUDES=$(BASEDIR)\private\ntos\inc
+
+SOURCES=
+
+i386_SOURCES=comm.c \
+ fcs.c \
+ irmini.c \
+ request.c \
+ resource.c \
+ settings.c \
+ convert.c \
+ actisys.c \
+ adaptec.c \
+ crystal.c \
+ esi.c \
+ parallax.c \
+ nscdemo.c \
+ irmini.rc
+
+
+
+
diff --git a/private/ntos/ndis/lance/dectc.c b/private/ntos/ndis/lance/dectc.c
new file mode 100644
index 000000000..499fca553
--- /dev/null
+++ b/private/ntos/ndis/lance/dectc.c
@@ -0,0 +1,301 @@
+#ifndef i386 // No INTEL system has a TurboChannel bus.
+
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ dectc.c
+
+Abstract:
+
+ This is the implementation of the card specific callbacks for the
+ DEC TurboChannel option for the Advanced Micro Devices LANCE (Am 7990)
+ Ethernet controller.
+
+Author:
+
+Environment:
+
+Revision History:
+
+ 31-Jul-1992 R.D. Lanser:
+
+ Moved/copied code from 'lance.c' to this file for all DEC
+ TurboChannel (PMAD-AA) specific code.
+
+--*/
+
+#include <ndis.h>
+#include "lancehrd.h"
+#include "lancesft.h"
+#include "dectc.h"
+
+
+NDIS_STATUS
+LanceDecTcGetConfiguration(
+ NDIS_HANDLE ConfigHandle,
+ PLANCE_ADAPTER PAdapter
+ )
+/*++
+Routine Description:
+
+ This is the Digital TurboChannel configuration routine. This routine
+ extracts configuration information from the configuration data base.
+
+Arguments:
+
+ ConfigHandle - Handle for configuration database.
+ PAdapter - Pointer for the adapter root.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS - Configuration get was successfully.
+ NDIS_STATUS_FAILURE - Configuration get was unsuccessfully.
+
+--*/
+
+
+{
+ NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+
+ enum {
+ CS_FIRST_INDEX = 0,
+ INTERRUPT_VECTOR = CS_FIRST_INDEX,
+ IRQL,
+ BASE_ADDR,
+ CS_NUM_OF_ENTRIES
+ } csIndex;
+
+ NDIS_STRING configString[CS_NUM_OF_ENTRIES] = {
+ NDIS_STRING_CONST("InterruptVector"),
+ NDIS_STRING_CONST("InterruptRequestLevel"),
+ NDIS_STRING_CONST("BaseAddress"),
+ };
+
+ UINT csCount = 0;
+
+ for (csIndex = CS_FIRST_INDEX; csIndex < CS_NUM_OF_ENTRIES; csIndex++) {
+
+ NDIS_STATUS returnedStatus;
+ PNDIS_CONFIGURATION_PARAMETER returnedValue;
+
+ //
+ // Read the configuration entry
+ //
+
+ NdisReadConfiguration(
+ &returnedStatus,
+ &returnedValue,
+ ConfigHandle,
+ &(configString[csIndex]),
+ NdisParameterInteger
+ );
+
+ if (returnedStatus == NDIS_STATUS_SUCCESS) {
+
+ switch (csIndex) {
+
+ case INTERRUPT_VECTOR:
+ PAdapter->InterruptNumber =
+ (CCHAR)returnedValue->ParameterData.IntegerData;
+ break;
+ case IRQL:
+ PAdapter->InterruptRequestLevel =
+ (CCHAR)returnedValue->ParameterData.IntegerData;
+ break;
+ case BASE_ADDR:
+ PAdapter->HardwareBaseAddr = (PVOID)
+ (returnedValue->ParameterData.IntegerData);
+ break;
+ default:
+ continue;
+ }
+
+ csCount++;
+
+ } else {
+
+ status = returnedStatus;
+
+#if DBG
+ {
+ PCCHAR str[CS_NUM_OF_ENTRIES] = {
+ "InterruptVector",
+ "InterruptRequestLevel",
+ "BaseAddress"
+ } ;
+ DbgPrint("LANCE: Configuration parameter '%s' not found",
+ str[csIndex]);
+ }
+#endif
+
+ }
+
+ } // for (csIndex ...
+
+ //
+ // Fill in the rest of the configuration.
+ //
+
+ if (status == NDIS_STATUS_SUCCESS) {
+ if (csCount == CS_NUM_OF_ENTRIES) {
+
+ //
+ // Treat the RAP, RDP, and NetworkHardwareAddress as port numbers
+ // (offsets from the first register). This will allow the
+ // usage of the Ndis{Read/Write}Portxxx macros after the port
+ // offset address is fixed up in LanceDecTcSoftwareDetails.
+ //
+
+ //
+ // The amount of dual ported memory.
+ //
+ PAdapter->AmountOfHardwareMemory = LANCE_DECTC_HARDWARE_MEMORY;
+ //
+ // The offset of this memory from the base address.
+ //
+ PAdapter->HardwareBaseOffset = 0;
+ //
+ // The register offsets from the base address.
+ //
+ PAdapter->RAP = (ULONG) LANCE_DECTC_RAP_OFFSET;
+ PAdapter->RDP = (ULONG) LANCE_DECTC_RDP_OFFSET;
+ //
+ // Not used for this adapter, simply null it.
+ //
+ PAdapter->Nicsr = (ULONG)NULL;
+ //
+ // And the offset from the base address for the hardware address.
+ //
+ PAdapter->NetworkHardwareAddress = LANCE_DECTC_NETWORK_OFFSET;
+
+ } else {
+
+ //
+ // Insufficient configuration data.
+ //
+ status = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION;
+
+ }
+ }
+
+ return status;
+}
+
+NDIS_STATUS
+LanceDecTcSoftwareDetails(
+ PLANCE_ADAPTER PAdapter
+ )
+/*++
+Routine Description:
+
+ Set buffer sizes and number of rings. Also, fixe the port mapping
+ offset address to avoid large unsigned subtractions in NDIS. See
+ the following macros in lancehrd.h:
+
+ LANCE_ISR_WRITE_RAP(A,C) NdisRawWritePortUshort (...
+ LANCE_ISR_READ_RDP(A,C) NdisRawReadPortUshort (...
+ LANCE_ISR_WRITE_RDP(A,C) NdisRawWritePortUshort (...
+ LANCE_ISR_WRITE_NICSR(A,C) NdisRawWritePortUshort (...
+
+ The port offset is the mapped address base, and the port number is
+ the offset from that base (confused yet?).
+
+Arguments:
+
+ PAdapter - Pointer for the adapter root.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS - Configuration get was successfully.
+ NDIS_STATUS_RESOURCES - Insufficient resources.
+
+--*/
+
+
+{
+ NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+
+ //
+ // Set buffer sizes and number of rings.
+ //
+
+ PAdapter->SizeOfReceiveBuffer = LANCE_128K_SIZE_OF_RECEIVE_BUFFERS;
+ PAdapter->NumberOfSmallBuffers = LANCE_128K_NUMBER_OF_SMALL_BUFFERS;
+ PAdapter->NumberOfMediumBuffers= LANCE_128K_NUMBER_OF_MEDIUM_BUFFERS;
+ PAdapter->NumberOfLargeBuffers = LANCE_128K_NUMBER_OF_LARGE_BUFFERS;
+
+ PAdapter->NumberOfReceiveRings = LANCE_128K_NUMBER_OF_RECEIVE_RINGS;
+ PAdapter->LogNumberReceiveRings = LANCE_128K_LOG_RECEIVE_RINGS;
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+NDIS_STATUS
+LanceDecTcHardwareDetails(
+ PLANCE_ADAPTER PAdapter
+ )
+/*++
+Routine Description:
+
+ This routine extracts the network hardware address.
+
+Arguments:
+
+ PAdapter - Pointer for the adapter root.
+
+Return Value:
+
+
+ NDIS_STATUS_SUCCESS - Success.
+ NDIS_STATUS_FAILURE - Failure.
+
+--*/
+
+
+{
+ ULONG port;
+ ULONG registerValue;
+
+
+
+ port = (ULONG)(PAdapter->NetworkHardwareAddress);
+ NdisRawReadPortUlong(port, &registerValue);
+
+ registerValue = (registerValue & 0x00ff0000u) >> 16;
+ PAdapter->NetworkAddress[0] = (UCHAR)registerValue;
+
+ port += sizeof(ULONG);
+ NdisRawReadPortUlong(port, &registerValue);
+ registerValue = (registerValue & 0x00ff0000u) >> 16;
+ PAdapter->NetworkAddress[1] = (UCHAR)registerValue;
+
+
+ port += sizeof(ULONG);
+ NdisRawReadPortUlong(port, &registerValue);
+ registerValue = (registerValue & 0x00ff0000u) >> 16;
+ PAdapter->NetworkAddress[2] = (UCHAR)registerValue;
+
+
+ port += sizeof(ULONG);
+ NdisRawReadPortUlong(port, &registerValue);
+ registerValue = (registerValue & 0x00ff0000u) >> 16;
+ PAdapter->NetworkAddress[3] = (UCHAR)registerValue;
+
+
+ port += sizeof(ULONG);
+ NdisRawReadPortUlong(port, &registerValue);
+ registerValue = (registerValue & 0x00ff0000u) >> 16;
+ PAdapter->NetworkAddress[4] = (UCHAR)registerValue;
+
+
+ port += sizeof(ULONG);
+ NdisRawReadPortUlong(port, &registerValue);
+ registerValue = (registerValue & 0x00ff0000u) >> 16;
+ PAdapter->NetworkAddress[5] = (UCHAR)registerValue;
+
+ return NDIS_STATUS_SUCCESS;
+}
+#endif // i386
diff --git a/private/ntos/ndis/lance/dectc.h b/private/ntos/ndis/lance/dectc.h
new file mode 100644
index 000000000..70e7f8089
--- /dev/null
+++ b/private/ntos/ndis/lance/dectc.h
@@ -0,0 +1,29 @@
+#ifndef _LANCEDECTC_
+#define _LANCEDECTC_
+
+
+#define LANCE_DECTC_HARDWARE_MEMORY (0x20000u) // Should be 128K
+#define LANCE_DECTC_REGISTER_OFFSET (0x100000)
+#define LANCE_DECTC_REGISTER_MAPSIZE (0x1c0080 - 0x100000)
+#define LANCE_DECTC_RAP_OFFSET (0x100004 - LANCE_DECTC_REGISTER_OFFSET)
+#define LANCE_DECTC_RDP_OFFSET (0x100000 - LANCE_DECTC_REGISTER_OFFSET)
+#define LANCE_DECTC_NETWORK_OFFSET (0x1c0000 - LANCE_DECTC_REGISTER_OFFSET)
+
+
+NDIS_STATUS
+LanceDecTcGetConfiguration(
+ NDIS_HANDLE ConfigHandle,
+ PLANCE_ADAPTER Adapter
+ );
+
+NDIS_STATUS
+LanceDecTcSoftwareDetails(
+ PLANCE_ADAPTER Adapter
+ );
+
+NDIS_STATUS
+LanceDecTcHardwareDetails(
+ PLANCE_ADAPTER Adapter
+ );
+
+#endif // _LANCEDECTC_
diff --git a/private/ntos/ndis/lance/details.c b/private/ntos/ndis/lance/details.c
new file mode 100644
index 000000000..963bd74e4
--- /dev/null
+++ b/private/ntos/ndis/lance/details.c
@@ -0,0 +1,428 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ transfer.c
+
+Abstract:
+
+ This file implements the routine that does very architecture
+ specific things.
+
+Author:
+
+ Anthony V. Ercolano (Tonye) 02-Oct-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+ Sean Selitrennikoff (SeanSe) 10/20/91
+ Added code to deal with a DecstationPC
+
+ 31-Jul-1992 R.D. Lanser:
+
+ Moved DEC TurboChannel (PMAD-AA) code to adapter specific routine.
+
+--*/
+
+#include <ndis.h>
+#include <lancehrd.h>
+#include <lancesft.h>
+
+
+#pragma NDIS_INIT_FUNCTION(LanceHardwareDetails)
+
+BOOLEAN
+LanceHardwareDetails(
+ IN PLANCE_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine gets the network address from the hardware.
+
+Arguments:
+
+ Adapter - Where to store the network address.
+
+Return Value:
+
+ TRUE - if successful.
+
+--*/
+
+{
+ UCHAR Signature[] = { 0xff, 0x00, 0x55, 0xaa, 0xff, 0x00, 0x55, 0xaa};
+ UCHAR BytesRead[8];
+
+ UINT ReadCount;
+
+ UINT Place;
+
+ //
+ // Reset E-PROM state
+ //
+ // To do this we first read from the E-PROM address until the
+ // specific signature is reached (then the next bytes read from
+ // the E-PROM address will be the ethernet address of the card).
+ //
+
+
+
+ //
+ // Read first part of the signature
+ //
+
+ for (Place=0; Place < 8; Place++){
+
+ NdisRawReadPortUchar((ULONG)(Adapter->NetworkHardwareAddress),
+ &(BytesRead[Place]));
+
+ }
+
+ ReadCount = 8;
+
+ //
+ // This advances to the front of the circular buffer.
+ //
+
+ while (ReadCount < 40) {
+
+ //
+ // Check if we have read the signature.
+ //
+
+ for (Place = 0; Place < 8; Place++){
+
+ if (BytesRead[Place] != Signature[Place]){
+
+ Place = 10;
+ break;
+
+ }
+
+ }
+
+ //
+ // If we have read the signature, stop.
+ //
+
+ if (Place != 10){
+
+ break;
+
+ }
+
+ //
+ // else, move all the bytes down one and read then
+ // next byte.
+ //
+
+ for (Place = 0; Place < 7; Place++){
+
+ BytesRead[Place] = BytesRead[Place+1];
+
+ }
+
+ NdisRawReadPortUchar((ULONG)(Adapter->NetworkHardwareAddress),
+ &(BytesRead[7]));
+
+ ReadCount++;
+ }
+
+
+ if (ReadCount == 40){
+
+ return(FALSE);
+
+ }
+
+
+ //
+ // Now read the ethernet address of the card.
+ //
+
+
+ NdisRawReadPortUchar(
+ (ULONG)(Adapter->NetworkHardwareAddress),
+ &(Adapter->NetworkAddress[0])
+ );
+ NdisRawReadPortUchar(
+ (ULONG)(Adapter->NetworkHardwareAddress),
+ &(Adapter->NetworkAddress[1])
+ );
+ NdisRawReadPortUchar(
+ (ULONG)(Adapter->NetworkHardwareAddress),
+ &(Adapter->NetworkAddress[2])
+ );
+ NdisRawReadPortUchar(
+ (ULONG)(Adapter->NetworkHardwareAddress),
+ &(Adapter->NetworkAddress[3])
+ );
+ NdisRawReadPortUchar(
+ (ULONG)(Adapter->NetworkHardwareAddress),
+ &(Adapter->NetworkAddress[4])
+ );
+ NdisRawReadPortUchar(
+ (ULONG)(Adapter->NetworkHardwareAddress),
+ &(Adapter->NetworkAddress[5])
+ );
+
+
+
+ if (!(Adapter->LanceCard & (LANCE_DE201 | LANCE_DE422))) {
+
+ if (Adapter->LanceCard == LANCE_DEPCA){
+
+ //
+ // Reset Lan Interface port.
+ //
+
+ NdisRawWritePortUchar(
+ (ULONG)(LANCE_DEPCA_LAN_CFG_OFFSET +
+ Adapter->Nicsr),
+ 0x00);
+
+ //
+ // Reset Network Interface Control Status Register
+ //
+
+ NdisRawWritePortUshort((ULONG)(Adapter->Nicsr), 0x00);
+ }
+
+ return(TRUE);
+
+ }
+
+
+
+
+ //
+ // Now do the EPROM Hardware check as outlined in the tech ref.
+ //
+
+
+ //
+ // Check for NULL address.
+ //
+
+ for (Place = 0; Place < 6; Place++) {
+
+ if (Adapter->NetworkAddress[Place] != 0) {
+
+ Place = 10;
+ break;
+
+ }
+
+ }
+
+ if (Place != 10) {
+
+ return(FALSE);
+
+ }
+
+
+
+ //
+ // Check that bit 0 is not a 1
+ //
+
+ if (Adapter->NetworkAddress[0] & 0x1) {
+
+ return(FALSE);
+
+ }
+
+
+
+
+
+ //
+ // Check that octet[0]->octet[7] == octet[15]->octet[8]
+ //
+
+ NdisRawReadPortUchar(
+ (ULONG)(Adapter->NetworkHardwareAddress),
+ &(BytesRead[6])
+ );
+ NdisRawReadPortUchar(
+ (ULONG)(Adapter->NetworkHardwareAddress),
+ &(BytesRead[7])
+ );
+
+ NdisRawReadPortUchar(
+ (ULONG)(Adapter->NetworkHardwareAddress),
+ &(BytesRead[0])
+ );
+ NdisRawReadPortUchar(
+ (ULONG)(Adapter->NetworkHardwareAddress),
+ &(BytesRead[1])
+ );
+
+ if ((BytesRead[7] != BytesRead[0]) ||
+ (BytesRead[6] != BytesRead[1])) {
+
+ return(FALSE);
+
+ }
+
+
+ NdisRawReadPortUchar(
+ (ULONG)(Adapter->NetworkHardwareAddress),
+ &(BytesRead[5])
+ );
+ NdisRawReadPortUchar(
+ (ULONG)(Adapter->NetworkHardwareAddress),
+ &(BytesRead[4])
+ );
+ NdisRawReadPortUchar(
+ (ULONG)(Adapter->NetworkHardwareAddress),
+ &(BytesRead[3])
+ );
+ NdisRawReadPortUchar(
+ (ULONG)(Adapter->NetworkHardwareAddress),
+ &(BytesRead[2])
+ );
+ NdisRawReadPortUchar(
+ (ULONG)(Adapter->NetworkHardwareAddress),
+ &(BytesRead[1])
+ );
+ NdisRawReadPortUchar(
+ (ULONG)(Adapter->NetworkHardwareAddress),
+ &(BytesRead[0])
+ );
+
+ for (Place = 0; Place < 6; Place++) {
+
+ if (BytesRead[Place] != (UCHAR)(Adapter->NetworkAddress[Place])) {
+
+ return(FALSE);
+
+ }
+
+ }
+
+
+ //
+ // Check that octet[0]->octet[8] == octet[16]->octet[23]
+ //
+
+ NdisRawReadPortUchar(
+ (ULONG)(Adapter->NetworkHardwareAddress),
+ &(BytesRead[0])
+ );
+ NdisRawReadPortUchar(
+ (ULONG)(Adapter->NetworkHardwareAddress),
+ &(BytesRead[1])
+ );
+ NdisRawReadPortUchar(
+ (ULONG)(Adapter->NetworkHardwareAddress),
+ &(BytesRead[2])
+ );
+ NdisRawReadPortUchar(
+ (ULONG)(Adapter->NetworkHardwareAddress),
+ &(BytesRead[3])
+ );
+ NdisRawReadPortUchar(
+ (ULONG)(Adapter->NetworkHardwareAddress),
+ &(BytesRead[4])
+ );
+ NdisRawReadPortUchar(
+ (ULONG)(Adapter->NetworkHardwareAddress),
+ &(BytesRead[5])
+ );
+
+ for (Place = 0; Place < 6; Place++) {
+
+ if (BytesRead[Place] != (UCHAR)(Adapter->NetworkAddress[Place])) {
+
+ return(FALSE);
+
+ }
+
+ }
+
+
+ NdisRawReadPortUchar(
+ (ULONG)(Adapter->NetworkHardwareAddress),
+ &(BytesRead[0])
+ );
+ NdisRawReadPortUchar(
+ (ULONG)(Adapter->NetworkHardwareAddress),
+ &(BytesRead[1])
+ );
+
+ if ((BytesRead[6] != BytesRead[0]) ||
+ (BytesRead[7] != BytesRead[1])) {
+
+ return(FALSE);
+
+ }
+
+ //
+ // Check that octet[24] -> octet[31] == signature bytes
+ //
+
+
+ for (Place = 0; Place < 8; Place++){
+
+
+ NdisRawReadPortUchar(
+ (ULONG)(Adapter->NetworkHardwareAddress),
+ &(BytesRead[Place])
+ );
+
+ if (BytesRead[Place] != Signature[Place]){
+
+#if DBG
+ DbgPrint("Lance: Hardware failure\n");
+#endif
+ return(FALSE);
+
+ }
+
+ }
+
+ if (Adapter->LanceCard == LANCE_DEPCA){
+
+ //
+ // Reset Lan Interface port.
+ //
+
+ NdisRawWritePortUchar(
+ (ULONG)(LANCE_DEPCA_LAN_CFG_OFFSET +
+ Adapter->Nicsr),
+ 0x00);
+
+ //
+ // Reset Network Interface Control Status Register
+ //
+
+ NdisRawWritePortUshort((ULONG)(Adapter->Nicsr), 0x00);
+ }
+
+ if (Adapter->LanceCard & (LANCE_DE201 | LANCE_DE422)) {
+
+ //
+ // Reset Network Interface Control Status Register
+ //
+
+ NdisRawWritePortUshort((ULONG)(Adapter->Nicsr), 0x00);
+
+ }
+
+ return(TRUE);
+
+}
+
+
+
diff --git a/private/ntos/ndis/lance/keywords.h b/private/ntos/ndis/lance/keywords.h
new file mode 100644
index 000000000..988905586
--- /dev/null
+++ b/private/ntos/ndis/lance/keywords.h
@@ -0,0 +1,56 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ keywords.h
+
+Abstract:
+
+ Contains all Ndis2 and Ndis3 mac-specific keywords.
+
+Author:
+
+ Bob Noradki
+
+Environment:
+
+ This driver is expected to work in DOS, OS2 and NT at the equivalent
+ of kernal mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+
+
+--*/
+#ifndef NDIS2
+#define NDIS2 0
+#endif
+
+#if NDIS2
+#define MEMMAPPEDBASEADDRESS NDIS_STRING_CONST("RAMADDRESS")
+#define SLOTNUMBER NDIS_STRING_CONST("SLOTNUMBER")
+#define IOADDRESS NDIS_STRING_CONST("IOADDRESS")
+#define INTERRUPT NDIS_STRING_CONST("INTERRUPT")
+#define MAXMULTICASTLIST NDIS_STRING_CONST("MAXMULTICAST")
+#define NETWORKADDRESS NDIS_STRING_CONST("NETADDRESS")
+#define CARDTYPE NDIS_STRING_CONST("AdapterName")
+
+#else // NDIS3
+
+#define MEMMAPPEDBASEADDRESS NDIS_STRING_CONST("MemoryMappedBaseAddress")
+#define IOADDRESS NDIS_STRING_CONST("IoBaseAddress")
+#define INTERRUPT NDIS_STRING_CONST("InterruptNumber")
+#define MAXMULTICASTLIST NDIS_STRING_CONST("MaximumMulticastList")
+#define NETWORKADDRESS NDIS_STRING_CONST("NetworkAddress")
+#define CARDTYPE NDIS_STRING_CONST("CardType")
+
+#endif
diff --git a/private/ntos/ndis/lance/lance.c b/private/ntos/ndis/lance/lance.c
new file mode 100644
index 000000000..3cabb6a7f
--- /dev/null
+++ b/private/ntos/ndis/lance/lance.c
@@ -0,0 +1,4974 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ lance.c
+
+Abstract:
+
+ This is the main file for the Advanced Micro Devices LANCE (Am 7990)
+ Ethernet controller. This driver conforms to the NDIS 3.0 interface.
+
+ The idea for handling loopback and sends simultaneously is largely
+ adapted from the EtherLink II NDIS driver by Adam Barr.
+
+Author:
+
+ Anthony V. Ercolano (Tonye) 20-Jul-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+#include "lancehrd.h"
+#include "lancesft.h"
+#include "dectc.h"
+#include "keywords.h"
+
+//#if DBG
+#define STATIC
+//#else
+//#define STATIC static
+//#endif
+
+
+#if DBG
+
+UCHAR LanceSendFails[256] = {0};
+UCHAR LanceSendFailPlace = 0;
+
+#endif
+
+
+NDIS_HANDLE LanceNdisWrapperHandle = NULL;
+PDRIVER_OBJECT LanceDriverObject = NULL;
+
+//
+// This constant is used for places where NdisAllocateMemory
+// needs to be called and the HighestAcceptableAddress does
+// not matter.
+//
+
+NDIS_PHYSICAL_ADDRESS HighestAcceptableMax =
+ NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
+
+
+#if LANCELOG
+
+UCHAR Log[LOG_SIZE] = {0};
+
+UCHAR LogPlace = 0;
+UCHAR LogWrapped = 0;
+
+UCHAR LancePrintLog = 0;
+
+#endif
+
+
+//
+// If you add to this, make sure to add the
+// LanceQueryInformation() if it is
+// queriable information.
+//
+UINT LanceGlobalSupportedOids[] = {
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ OID_802_3_RCV_ERROR_ALIGNMENT,
+ OID_802_3_XMIT_ONE_COLLISION,
+ OID_802_3_XMIT_MORE_COLLISIONS
+ };
+
+//
+// We define a constant csr0 value that is useful for initializing
+// an already stopped LANCE.
+//
+// This also enables the chip for interrupts.
+//
+#define LANCE_CSR0_INIT_CHIP ((USHORT)0x41)
+
+//
+// We define a constant csr0 value that is useful for clearing all of
+// the interesting bits that *could* be set on an interrupt.
+//
+#define LANCE_CSR0_CLEAR_INTERRUPT_BITS ((USHORT)0x7f00)
+
+VOID
+LanceDeferredTimerRoutine(
+ IN PVOID SystemSpecific1,
+ IN NDIS_HANDLE Context,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+NDIS_STATUS
+LanceQueryInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+ );
+
+NDIS_STATUS
+LanceSetInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ );
+
+NDIS_STATUS
+LanceReset(
+ OUT PBOOLEAN AddressingReset,
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+BOOLEAN
+AllocateAdapterMemory(
+ IN PLANCE_ADAPTER Adapter
+ );
+
+NDIS_STATUS
+LanceSetPacketFilter(
+ IN PLANCE_ADAPTER Adapter,
+ IN NDIS_REQUEST_TYPE NdisRequestType,
+ IN UINT PacketFilter
+ );
+
+NDIS_STATUS
+LanceChangeMulticastAddresses(
+ IN PLANCE_ADAPTER Adapter,
+ IN UINT NewAddressCount,
+ IN CHAR NewAddresses[][LANCE_LENGTH_OF_ADDRESS],
+ IN NDIS_REQUEST_TYPE NdisRequestType
+ );
+
+VOID
+DeleteAdapterMemory(
+ IN PLANCE_ADAPTER Adapter
+ );
+
+VOID
+RelinquishReceivePacket(
+ IN PLANCE_ADAPTER Adapter,
+ IN UINT StartingIndex,
+ IN UINT NumberOfBuffers
+ );
+
+BOOLEAN
+ProcessReceiveInterrupts(
+ IN PLANCE_ADAPTER Adapter
+ );
+
+NDIS_STATUS
+LanceRegisterAdapter(
+ IN PLANCE_ADAPTER Adapter
+ );
+
+BOOLEAN
+ProcessTransmitInterrupts(
+ IN PLANCE_ADAPTER Adapter
+ );
+
+UINT
+CalculateCRC(
+ IN UINT NumberOfBytes,
+ IN PCHAR Input
+ );
+
+VOID
+LanceStartChip(
+ IN PLANCE_ADAPTER Adapter
+ );
+
+VOID
+LanceSetInitializationBlock(
+ IN PLANCE_ADAPTER Adapter
+ );
+
+VOID
+SetInitBlockAndInit(
+ IN PLANCE_ADAPTER Adapter
+ );
+
+VOID
+StartAdapterReset(
+ IN PLANCE_ADAPTER Adapter
+ );
+
+VOID
+SetupForReset(
+ IN PLANCE_ADAPTER Adapter,
+ IN NDIS_REQUEST_TYPE RequestType
+ );
+
+NDIS_STATUS
+LanceInitialInit(
+ IN PLANCE_ADAPTER Adapter
+ );
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+
+
+#pragma NDIS_INIT_FUNCTION(DriverEntry)
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This is the primary initialization routine for the lance driver.
+ It is simply responsible for the intializing the wrapper and registering
+ the MAC. It then calls a system and architecture specific routine that
+ will initialize and register each adapter.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+Return Value:
+
+ The status of the operation.
+
+--*/
+
+{
+ //
+ // Receives the status of the NdisRegisterMac operation.
+ //
+ NDIS_STATUS Status;
+ NDIS_HANDLE NdisWrapperHandle;
+ NDIS_MINIPORT_CHARACTERISTICS LanceChar;
+ NDIS_STRING MacName = NDIS_STRING_CONST("Lance");
+
+#if NDIS_WIN
+ UCHAR pIds[sizeof (EISA_MCA_ADAPTER_IDS) + sizeof (ULONG)];
+#endif
+
+#if NDIS_WIN
+ ((PEISA_MCA_ADAPTER_IDS)pIds)->nEisaAdapters=1;
+ ((PEISA_MCA_ADAPTER_IDS)pIds)->nMcaAdapters=0;
+ *(PULONG)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray)=DE422_COMPRESSED_ID;
+ (PVOID)DriverObject=(PVOID)pIds;
+#endif
+
+ //
+ // Initialize the wrapper.
+ //
+ NdisInitializeWrapper(
+ &NdisWrapperHandle,
+ DriverObject,
+ RegistryPath,
+ NULL
+ );
+
+ //
+ // Initialize the MAC characteristics for the call to
+ // NdisRegisterMac.
+ //
+ NdisZeroMemory(&LanceChar, sizeof(LanceChar));
+ LanceChar.MajorNdisVersion = LANCE_NDIS_MAJOR_VERSION;
+ LanceChar.MinorNdisVersion = LANCE_NDIS_MINOR_VERSION;
+ LanceChar.CheckForHangHandler = NULL;
+ LanceChar.DisableInterruptHandler = LanceDisableInterrupt;
+ LanceChar.EnableInterruptHandler = LanceEnableInterrupt;
+ LanceChar.HaltHandler = LanceHalt;
+ LanceChar.HandleInterruptHandler = LanceHandleInterrupt;
+ LanceChar.InitializeHandler = LanceInitialize;
+ LanceChar.ISRHandler = LanceIsr;
+ LanceChar.QueryInformationHandler = LanceQueryInformation;
+ LanceChar.ReconfigureHandler = NULL;
+ LanceChar.ResetHandler = LanceReset;
+ LanceChar.SendHandler = LanceSend;
+ LanceChar.SetInformationHandler = LanceSetInformation;
+ LanceChar.TransferDataHandler = LanceTransferData;
+
+ Status = NdisMRegisterMiniport(
+ NdisWrapperHandle,
+ &LanceChar,
+ sizeof(LanceChar)
+ );
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ NdisTerminateWrapper(NdisWrapperHandle, NULL);
+ }
+
+ return(Status);
+}
+
+#pragma NDIS_INIT_FUNCTION(LanceInitialize)
+
+extern
+NDIS_STATUS
+LanceInitialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+
+/*++
+
+Routine Description:
+
+ NE3200Initialize starts an adapter.
+
+Arguments:
+
+ See NDIS 3.0 Miniport spec.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_PENDING
+
+--*/
+
+{
+ //
+ // Pointer for the adapter root.
+ //
+ PLANCE_ADAPTER Adapter;
+
+
+ NDIS_HANDLE ConfigHandle;
+ PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
+ NDIS_STRING IoAddressStr = IOADDRESS;
+ NDIS_STRING MaxMulticastListStr = MAXMULTICASTLIST;
+ NDIS_STRING NetworkAddressStr = NETWORKADDRESS;
+ NDIS_STRING InterruptStr = INTERRUPT;
+ NDIS_STRING CardStr = CARDTYPE;
+ NDIS_STRING MemoryBaseAddrStr = MEMMAPPEDBASEADDRESS;
+
+#if NDIS2
+ NDIS_STRING DE201Str = NDIS_STRING_CONST("DE201");
+ NDIS_STRING DE100Str = NDIS_STRING_CONST("DE100");
+ NDIS_STRING DEPCAStr = NDIS_STRING_CONST("DEPCA");
+ NDIS_STRING DECTCStr = NDIS_STRING_CONST("DECTC");
+ NDIS_STRING DE422Str = NDIS_STRING_CONST("DE422");
+ NDIS_STRING DE200Str = NDIS_STRING_CONST("DE200");
+ NDIS_STRING DE101Str = NDIS_STRING_CONST("DE101");
+#endif
+
+ NDIS_EISA_FUNCTION_INFORMATION EisaData;
+ USHORT ConfigValue = 0;
+ UCHAR HiBaseValue = 0;
+
+ UINT MaxMulticastList = 32;
+ PVOID NetAddress;
+ UINT Length;
+
+ USHORT RegUshort;
+ UCHAR RegUchar;
+ UINT LanceSlot = 1;
+
+ BOOLEAN ConfigError = FALSE;
+ NDIS_STATUS ConfigErrorCode;
+ NDIS_STATUS Status;
+
+
+ //
+ // Search for correct medium.
+ //
+
+ for (; MediumArraySize > 0; MediumArraySize--){
+
+ if (MediumArray[MediumArraySize - 1] == NdisMedium802_3){
+
+ MediumArraySize--;
+
+ break;
+
+ }
+
+ }
+
+ if (MediumArray[MediumArraySize] != NdisMedium802_3){
+
+ return( NDIS_STATUS_UNSUPPORTED_MEDIA );
+
+ }
+
+ *SelectedMediumIndex = MediumArraySize;
+
+ //
+ // Allocate the Adapter block.
+ //
+
+ LANCE_ALLOC_PHYS(&Adapter, sizeof(LANCE_ADAPTER));
+ if (Adapter == NULL)
+ {
+ return( NDIS_STATUS_RESOURCES ) ;
+ }
+
+ LANCE_ZERO_MEMORY(Adapter, sizeof(LANCE_ADAPTER));
+
+ Adapter->MaxLookAhead = LANCE_MAX_LOOKAHEAD;
+
+ //
+ // Start with the default card
+ //
+
+ Adapter->LanceCard = LANCE_DE201;
+ Adapter->MiniportAdapterHandle = MiniportAdapterHandle;
+
+ Adapter->IoBaseAddr = LANCE_DE201_PRI_NICSR_ADDRESS;
+ Adapter->HardwareBaseAddr = LANCE_DE201_BASE;
+ Adapter->AmountOfHardwareMemory = LANCE_DE201_HARDWARE_MEMORY;
+ Adapter->InterruptNumber = LANCE_DE201_INTERRUPT_VECTOR;
+ Adapter->InterruptRequestLevel = LANCE_DE201_INTERRUPT_VECTOR;
+ Adapter->BeingRemoved = FALSE;
+
+ NdisOpenConfiguration(&Status, &ConfigHandle, ConfigurationHandle);
+ if (Status != NDIS_STATUS_SUCCESS)
+ return(Status);
+
+#if NDIS2
+ //
+ // Read Card Type
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &CardStr,
+ NdisParameterString
+ );
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (NdisEqualString (&ReturnedValue->ParameterData.StringData, &DE201Str, 1)) {
+ Adapter->LanceCard = LANCE_DE201;
+ } else if (NdisEqualString (&ReturnedValue->ParameterData.StringData, &DE100Str, 1)) {
+ Adapter->LanceCard = LANCE_DE100;
+ } else if (NdisEqualString (&ReturnedValue->ParameterData.StringData, &DEPCAStr, 1)) {
+ Adapter->LanceCard = LANCE_DEPCA;
+#ifndef i386
+ } else if (NdisEqualString (&ReturnedValue->ParameterData.StringData, &DECTCStr, 1)) {
+ Adapter->LanceCard = LANCE_DECTC;
+ ConfigErrorCode = LanceDecTcGetConfiguration(ConfigHandle, Adapter);
+ if ( ConfigErrorCode != NDIS_STATUS_SUCCESS ) {
+ ConfigError = TRUE;
+ }
+#endif // i386
+ } else if (NdisEqualString (&ReturnedValue->ParameterData.StringData, &DE422Str, 1)) {
+ Adapter->LanceCard = LANCE_DE422;
+ } else if (NdisEqualString (&ReturnedValue->ParameterData.StringData, &DE200Str, 1)) {
+ //
+ // This is the De200, but it operates exactly like the 201.
+ //
+ Adapter->LanceCard = LANCE_DE201;
+ } else if (NdisEqualString (&ReturnedValue->ParameterData.StringData, &DE101Str, 1)) {
+ //
+ // This is the De101, but it operates exactly like the 100.
+ //
+ Adapter->LanceCard = LANCE_DE100;
+ } else {
+ ConfigError = TRUE;
+ ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION;
+ goto RegisterAdapter;
+ }
+
+ }
+
+
+#else
+ //
+ // Read Card Type
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &CardStr,
+ NdisParameterInteger
+ );
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (ReturnedValue->ParameterData.IntegerData == 2)
+ {
+ Adapter->LanceCard = LANCE_DE201;
+ }
+ else if (ReturnedValue->ParameterData.IntegerData == 1)
+ {
+ Adapter->LanceCard = LANCE_DE100;
+ }
+ else if (ReturnedValue->ParameterData.IntegerData == 3)
+ {
+ Adapter->LanceCard = LANCE_DEPCA;
+
+#ifndef i386
+ }
+ else if (ReturnedValue->ParameterData.IntegerData == 4)
+ {
+ Adapter->LanceCard = LANCE_DECTC;
+
+ ConfigErrorCode = LanceDecTcGetConfiguration(ConfigHandle, Adapter);
+
+ if ( ConfigErrorCode != NDIS_STATUS_SUCCESS )
+ {
+ ConfigError = TRUE;
+ }
+#endif // i386
+
+ }
+ else if (ReturnedValue->ParameterData.IntegerData == 5)
+ {
+ Adapter->LanceCard = LANCE_DE422;
+ }
+ else if (ReturnedValue->ParameterData.IntegerData == 6)
+ {
+ //
+ // This is the De200, but it operates exactly like the 201.
+ //
+ Adapter->LanceCard = LANCE_DE201;
+ }
+ else if (ReturnedValue->ParameterData.IntegerData == 7)
+ {
+ //
+ // This is the De101, but it operates exactly like the 100.
+ //
+ Adapter->LanceCard = LANCE_DE100;
+ }
+ else
+ {
+ ConfigError = TRUE;
+ ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION;
+
+ goto RegisterAdapter;
+ }
+ }
+#endif
+
+ //
+ // Read MaxMulticastList
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &MaxMulticastListStr,
+ NdisParameterInteger
+ );
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ MaxMulticastList = ReturnedValue->ParameterData.IntegerData;
+ }
+
+ //
+ // Read net address
+ //
+ NdisReadNetworkAddress(
+ &Status,
+ &NetAddress,
+ &Length,
+ ConfigHandle
+ );
+
+ if ((Length == LANCE_LENGTH_OF_ADDRESS) && (Status == NDIS_STATUS_SUCCESS))
+ {
+ NdisMoveMemory(
+ Adapter->CurrentNetworkAddress,
+ NetAddress,
+ LANCE_LENGTH_OF_ADDRESS
+ );
+ }
+
+ if (Adapter->LanceCard & (LANCE_DE201 | LANCE_DE100))
+ {
+ //
+ // Read IoAddress
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &IoAddressStr,
+ NdisParameterHexInteger
+ );
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (ReturnedValue->ParameterData.IntegerData == LANCE_DE201_PRI_NICSR_ADDRESS)
+ {
+ Adapter->IoBaseAddr = LANCE_DE201_PRI_NICSR_ADDRESS;
+ }
+ else if (ReturnedValue->ParameterData.IntegerData == LANCE_DE201_SEC_NICSR_ADDRESS)
+ {
+ Adapter->IoBaseAddr = LANCE_DE201_SEC_NICSR_ADDRESS;
+ }
+ else
+ {
+ ConfigError = TRUE;
+ ConfigErrorCode = NDIS_ERROR_CODE_BAD_IO_BASE_ADDRESS;
+
+ goto RegisterAdapter;
+ }
+ }
+
+ //
+ // Read Interrupt
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &InterruptStr,
+ NdisParameterInteger
+ );
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ Adapter->InterruptNumber = (CCHAR)ReturnedValue->ParameterData.IntegerData;
+ Adapter->InterruptRequestLevel = Adapter->InterruptNumber;
+
+ if (Adapter->LanceCard == LANCE_DE201)
+ {
+ if (!((Adapter->InterruptNumber == 5) ||
+ (Adapter->InterruptNumber == 9) ||
+ (Adapter->InterruptNumber == 10) ||
+ (Adapter->InterruptNumber == 11) ||
+ (Adapter->InterruptNumber == 15))) {
+
+ ConfigError = TRUE;
+ ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION;
+
+ goto RegisterAdapter;
+
+ }
+
+ } else {
+
+ if (!((Adapter->InterruptNumber == 2) ||
+ (Adapter->InterruptNumber == 3) ||
+ (Adapter->InterruptNumber == 4) ||
+ (Adapter->InterruptNumber == 5) ||
+ (Adapter->InterruptNumber == 7))) {
+
+ ConfigError = TRUE;
+ ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION;
+
+ goto RegisterAdapter;
+
+ }
+
+ }
+
+ }
+
+
+
+ //
+ // Read MemoryBaseAddress
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &MemoryBaseAddrStr,
+ NdisParameterHexInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+#if NDIS2
+ Adapter->HardwareBaseAddr = (PVOID)((ReturnedValue->ParameterData.IntegerData) << 4);
+#else
+ Adapter->HardwareBaseAddr = (PVOID)(ReturnedValue->ParameterData.IntegerData);
+#endif
+ if (!((Adapter->HardwareBaseAddr == (PVOID)0xC0000) ||
+ (Adapter->HardwareBaseAddr == (PVOID)0xC8000) ||
+ (Adapter->HardwareBaseAddr == (PVOID)0xD0000) ||
+ (Adapter->HardwareBaseAddr == (PVOID)0xD8000) ||
+ (Adapter->HardwareBaseAddr == (PVOID)0xE0000) ||
+ (Adapter->HardwareBaseAddr == (PVOID)0xE8000))) {
+
+ ConfigError = TRUE;
+ ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION;
+
+ goto RegisterAdapter;
+
+ }
+
+ }
+
+
+ if (((ULONG)Adapter->HardwareBaseAddr) & 0x8000) {
+
+ Adapter->AmountOfHardwareMemory = 0x8000;
+ Adapter->HardwareBaseOffset = 0x8000;
+
+ } else {
+
+ Adapter->AmountOfHardwareMemory = 0x10000;
+ Adapter->HardwareBaseOffset = 0x0;
+
+ }
+
+ } else if (Adapter->LanceCard == LANCE_DEPCA) {
+
+ Adapter->InterruptNumber = LANCE_DEPCA_INTERRUPT_VECTOR;
+ Adapter->InterruptRequestLevel = LANCE_DEPCA_INTERRUPT_VECTOR;
+ Adapter->AmountOfHardwareMemory = LANCE_DEPCA_HARDWARE_MEMORY;
+ Adapter->HardwareBaseAddr = LANCE_DEPCA_BASE;
+ Adapter->IoBaseAddr = LANCE_DEPCA_NICSR_ADDRESS;
+
+ } else if (Adapter->LanceCard == LANCE_DE422) {
+
+ PUCHAR CurrentChar;
+ BOOLEAN LastEntry;
+ UCHAR InitType;
+ USHORT PortAddress, PortValue, Mask;
+
+ //
+ // Read Slot Number
+ //
+ NdisReadEisaSlotInformation(
+ &Status,
+ ConfigurationHandle,
+ &(Adapter->SlotNumber),
+ &EisaData
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ ConfigError = TRUE;
+ ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION;
+
+ goto RegisterAdapter;
+
+ }
+
+ //
+ // Setup Ports
+ //
+
+ Adapter->IoBaseAddr = (((ULONG)Adapter->SlotNumber) << 12) +
+ LANCE_DE422_NICSR_ADDRESS;
+
+ Adapter->NetworkHardwareAddress = Adapter->IoBaseAddr + LANCE_DE422_NETWORK_OFFSET;
+
+ CurrentChar = (PUCHAR) (EisaData.InitializationData);
+ LastEntry = FALSE;
+
+ while (!LastEntry) {
+
+ InitType = *(CurrentChar++);
+ PortAddress = *((USHORT UNALIGNED *) CurrentChar++);
+
+ CurrentChar++;
+
+ if ((InitType & 0x80) == 0) {
+ LastEntry = TRUE;
+ }
+
+
+
+ if (PortAddress == (USHORT)(Adapter->NetworkHardwareAddress)) {
+
+ PortValue = *((USHORT UNALIGNED *) CurrentChar++);
+
+ } else if (PortAddress == ((Adapter->SlotNumber << 12) +
+ LANCE_DE422_NICSR_ADDRESS +
+ LANCE_DE422_EXTENDED_MEMORY_BASE_OFFSET)) {
+
+ PortValue = (USHORT)(*(CurrentChar++));
+
+ } else {
+
+ continue;
+
+ }
+
+
+
+ if (InitType & 0x40) {
+
+ if (PortAddress == Adapter->NetworkHardwareAddress) {
+
+ Mask = *((USHORT UNALIGNED *) CurrentChar++);
+
+ } else {
+
+ Mask = (USHORT)(*(CurrentChar++));
+
+ }
+
+ } else {
+
+ Mask = 0;
+
+ }
+
+ if (PortAddress == Adapter->NetworkHardwareAddress) {
+
+ ConfigValue &= Mask;
+ ConfigValue |= PortValue;
+
+ } else {
+
+ HiBaseValue &= (UCHAR)Mask;
+ HiBaseValue |= (UCHAR)PortValue;
+
+ }
+
+ }
+
+ //
+ // Interpret values
+ //
+
+ switch (ConfigValue & 0x78) {
+
+ case 0x40:
+
+ Adapter->InterruptNumber = 11;
+ break;
+
+ case 0x20:
+
+ Adapter->InterruptNumber = 10;
+ break;
+
+ case 0x10:
+
+ Adapter->InterruptNumber = 9;
+ break;
+
+ case 0x08:
+
+ Adapter->InterruptNumber = 5;
+ break;
+
+ default:
+
+ ConfigError = TRUE;
+ ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION;
+
+ goto RegisterAdapter;
+
+ }
+
+ Adapter->InterruptRequestLevel = Adapter->InterruptNumber;
+
+ //
+ // We postpone the rest of the processing since we have to read from
+ // the NICSR to get the amount of hardware memory and cannot do that
+ // until after we have called NdisRegisterAdapter.
+ //
+
+ }
+
+RegisterAdapter:
+
+ NdisCloseConfiguration(ConfigHandle);
+
+ if (ConfigError) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ ConfigErrorCode,
+ 0
+ );
+
+ LANCE_FREE_PHYS(Adapter, sizeof(LANCE_ADAPTER));
+
+ return(NDIS_STATUS_FAILURE);
+
+ }
+
+ NdisMSetAttributes(
+ MiniportAdapterHandle,
+ (NDIS_HANDLE)Adapter,
+ FALSE,
+ (Adapter->LanceCard == LANCE_DE422) ?
+ NdisInterfaceEisa :
+ NdisInterfaceIsa
+ );
+
+ //
+ // Register the IoPortRanges
+ //
+
+ if (Adapter->LanceCard & (LANCE_DE100 | LANCE_DE201)) {
+
+ Status = NdisMRegisterIoPortRange(
+ (PVOID *)(&(Adapter->Nicsr)),
+ MiniportAdapterHandle,
+ Adapter->IoBaseAddr,
+ 0x10
+ );
+
+ Adapter->RAP = Adapter->Nicsr + LANCE_DE201_RAP_OFFSET;
+ Adapter->RDP = Adapter->Nicsr + LANCE_DE201_RDP_OFFSET;
+ Adapter->NetworkHardwareAddress = Adapter->Nicsr + LANCE_DE201_NETWORK_OFFSET;
+
+ } else if (Adapter->LanceCard == LANCE_DE422) {
+
+ Status = NdisMRegisterIoPortRange(
+ (PVOID *)(&(Adapter->Nicsr)),
+ MiniportAdapterHandle,
+ Adapter->IoBaseAddr,
+ 0x90
+ );
+
+ Adapter->RAP = Adapter->Nicsr + LANCE_DE422_RAP_OFFSET;
+ Adapter->RDP = Adapter->Nicsr + LANCE_DE422_RDP_OFFSET;
+ Adapter->NetworkHardwareAddress = Adapter->Nicsr + LANCE_DE422_NETWORK_OFFSET;
+
+ } else if (Adapter->LanceCard == LANCE_DEPCA) {
+
+ Status = NdisMRegisterIoPortRange(
+ (PVOID *)(&(Adapter->Nicsr)),
+ MiniportAdapterHandle,
+ Adapter->IoBaseAddr,
+ 0x10
+ );
+
+ Adapter->LanceCard = LANCE_DE100;
+ Adapter->RAP = Adapter->Nicsr + LANCE_DEPCA_RAP_OFFSET;
+ Adapter->RDP = Adapter->Nicsr + LANCE_DEPCA_RDP_OFFSET;
+ Adapter->NetworkHardwareAddress = Adapter->Nicsr + LANCE_DEPCA_EPROM_OFFSET;
+
+ }
+
+#ifndef i386
+
+ else if (Adapter->LanceCard == LANCE_DECTC) {
+
+ Status = NdisMRegisterIoPortRange(
+ (PVOID *)(&(Adapter->Nicsr)),
+ MiniportAdapterHandle,
+ ((ULONG)Adapter->HardwareBaseAddr) + LANCE_DECTC_REGISTER_OFFSET,
+ LANCE_DECTC_REGISTER_MAPSIZE
+ );
+
+ Adapter->RAP = Adapter->Nicsr + LANCE_DEPCA_RAP_OFFSET;
+ Adapter->RDP = Adapter->Nicsr + LANCE_DEPCA_RDP_OFFSET;
+ Adapter->NetworkHardwareAddress = Adapter->Nicsr + LANCE_DEPCA_EPROM_OFFSET;
+
+ }
+
+#endif
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ LANCE_FREE_PHYS(Adapter, sizeof(LANCE_ADAPTER));
+
+ return Status;
+
+ }
+
+ //
+ // Now we get the rest of the information necessary for the DE422.
+ //
+ if (Adapter->LanceCard == LANCE_DE422)
+ {
+ //
+ // Verify card is a DE422
+ //
+
+ NdisRawReadPortUshort(
+ (Adapter->Nicsr + LANCE_DE422_EISA_IDENTIFICATION_OFFSET),
+ &RegUshort
+ );
+
+ if (RegUshort != 0xA310) {
+
+ //
+ // Not a DE422 card
+ //
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
+ 0
+ );
+
+ Status = NDIS_STATUS_FAILURE;
+ goto Fail1;
+
+ }
+
+ NdisRawReadPortUshort(
+ Adapter->Nicsr +
+ LANCE_DE422_EISA_IDENTIFICATION_OFFSET + 2,
+ &RegUshort
+ );
+
+ if (RegUshort != 0x2042) {
+
+ //
+ // Not a DE422 card
+ //
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
+ 0
+ );
+
+ Status = NDIS_STATUS_FAILURE;
+ goto Fail1;
+
+ }
+
+ //
+ // Check that the card is enabled.
+ //
+
+ NdisRawReadPortUchar(
+ Adapter->Nicsr +
+ LANCE_DE422_EISA_CONTROL_OFFSET,
+ &RegUchar
+ );
+
+ if (!(RegUchar & 0x1)) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_ADAPTER_DISABLED,
+ 0
+ );
+
+ Status = NDIS_STATUS_FAILURE;
+ goto Fail1;
+
+ }
+
+ //
+ // Get Memory size
+ //
+
+ NdisRawReadPortUshort(
+ Adapter->Nicsr,
+ &RegUshort
+ );
+
+ if (RegUshort & LANCE_NICSR_BUFFER_SIZE) {
+
+ Adapter->AmountOfHardwareMemory = 0x8000;
+
+ } else if (RegUshort & LANCE_NICSR_128K) {
+
+ Adapter->AmountOfHardwareMemory = 0x20000;
+ Adapter->NicsrDefaultValue = LANCE_NICSR_128K;
+
+ } else {
+
+ Adapter->AmountOfHardwareMemory = 0x10000;
+
+ }
+
+ //
+ // Get Base memory address
+ //
+
+ switch (Adapter->AmountOfHardwareMemory) {
+
+ case 0x8000:
+
+ switch (ConfigValue & 0x07) {
+
+ case 0x04:
+
+ Adapter->HardwareBaseAddr = (PVOID)((HiBaseValue << 24) + 0xC8000);
+ Adapter->HardwareBaseOffset = 0x8000;
+ break;
+
+ case 0x05:
+
+ Adapter->HardwareBaseAddr = (PVOID)((HiBaseValue << 24) + 0xE8000);
+ Adapter->HardwareBaseOffset = 0x8000;
+ break;
+
+ case 0x06:
+
+ Adapter->HardwareBaseAddr = (PVOID)((HiBaseValue << 24) + 0xD8000);
+ Adapter->HardwareBaseOffset = 0x8000;
+ break;
+
+ case 0x07:
+
+ Adapter->HardwareBaseAddr = (PVOID)((HiBaseValue << 24) + 0xF8000);
+ Adapter->HardwareBaseOffset = 0x8000;
+ break;
+
+ default:
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
+ 0
+ );
+
+ Status = NDIS_STATUS_FAILURE;
+ goto Fail1;
+
+ }
+ break;
+
+ case 0x10000:
+
+ switch (ConfigValue & 0x07) {
+
+ case 0x00:
+
+ Adapter->HardwareBaseAddr = (PVOID)((HiBaseValue << 24) + 0xC0000);
+ Adapter->HardwareBaseOffset = 0x0000;
+ break;
+
+ case 0x01:
+
+ Adapter->HardwareBaseAddr = (PVOID)((HiBaseValue << 24) + 0xE0000);
+ Adapter->HardwareBaseOffset = 0x0000;
+ break;
+
+ case 0x02:
+
+ Adapter->HardwareBaseAddr = (PVOID)((HiBaseValue << 24) + 0xD0000);
+ Adapter->HardwareBaseOffset = 0x0000;
+ break;
+
+ case 0x03:
+
+ Adapter->HardwareBaseAddr = (PVOID)((HiBaseValue << 24) + 0xF0000);
+ Adapter->HardwareBaseOffset = 0x0000;
+ break;
+
+ default:
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
+ 0
+ );
+
+ Status = NDIS_STATUS_FAILURE;
+ goto Fail1;
+
+ }
+ break;
+
+ case 0x20000:
+
+ switch (ConfigValue & 0x07) {
+
+ case 0x00:
+
+ Adapter->HardwareBaseAddr = (PVOID)((HiBaseValue << 24) + 0xC0000);
+ Adapter->HardwareBaseOffset = 0x0000;
+ break;
+
+ case 0x01:
+
+ Adapter->HardwareBaseAddr = (PVOID)((HiBaseValue << 24) + 0xD0000);
+ Adapter->HardwareBaseOffset = 0x0000;
+ break;
+
+ default:
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
+ 0
+ );
+
+ Status = NDIS_STATUS_FAILURE;
+ goto Fail1;
+
+ }
+
+ break;
+
+ }
+
+ }
+
+ //
+ // Set the port addresses and the network address.
+ //
+
+ Adapter->InterruptsStopped = FALSE;
+ Adapter->MaxMulticastList = MaxMulticastList;
+
+ Status = LanceRegisterAdapter( Adapter );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ goto Fail1;
+ }
+
+ return Status;
+
+Fail1:
+
+ //
+ // Deregister the IoPortRanges
+ //
+
+ if (Adapter->LanceCard & (LANCE_DE100 | LANCE_DE201)) {
+
+ NdisMDeregisterIoPortRange(
+ MiniportAdapterHandle,
+ Adapter->IoBaseAddr,
+ 0x10,
+ (PVOID)(Adapter->Nicsr)
+ );
+
+ } else if (Adapter->LanceCard == LANCE_DE422) {
+
+ NdisMDeregisterIoPortRange(
+ MiniportAdapterHandle,
+ Adapter->IoBaseAddr,
+ 0x90,
+ (PVOID)(Adapter->Nicsr)
+ );
+
+ }
+
+ LANCE_FREE_PHYS(Adapter, sizeof(LANCE_ADAPTER));
+
+ return(Status);
+}
+
+
+VOID
+LanceHalt(
+ IN PVOID MiniportAdapterContext
+ )
+/*++
+
+Routine Description:
+
+ LanceHalt stops an adapter and deregisters everything.
+
+Arguments:
+
+ MiniportAdapterContext - The context value that the driver when
+ LanceInitialize is called. Actually as pointer to an
+ LANCE_ADAPTER.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PLANCE_ADAPTER Adapter;
+
+ Adapter = PLANCE_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ LOG(REMOVE);
+
+ //
+ // bug 2275
+ //
+
+ LanceSyncStopChip(Adapter);
+
+ NdisMDeregisterInterrupt(&(Adapter->Interrupt));
+
+#if NDIS_WIN
+
+ //
+ // Restore saved values
+ //
+ {
+ PUCHAR pTemp = Adapter->MmMappedBaseAddr;
+
+ (UINT)pTemp &= 0xffff0000;
+ (UINT)pTemp |= 0x0000bffe;
+
+ NdisWriteRegisterUshort((PUSHORT)pTemp, Adapter->SavedMemBase);
+
+ pTemp = Adapter->MmMappedBaseAddr;
+ NdisWriteRegisterUlong((PULONG)pTemp, Adapter->Reserved1);
+ NdisWriteRegisterUlong((PULONG)pTemp, Adapter->Reserved2);
+ }
+
+#endif
+
+ NdisMUnmapIoSpace(
+ Adapter->MiniportAdapterHandle,
+ Adapter->MmMappedBaseAddr,
+ Adapter->AmountOfHardwareMemory
+ );
+
+ //
+ // bug3327
+ //
+ NdisRawWritePortUshort((ULONG)(Adapter->Nicsr), 0x04);
+
+ if (Adapter->LanceCard & (LANCE_DE100 | LANCE_DE201)) {
+
+ NdisMDeregisterIoPortRange(
+ Adapter->MiniportAdapterHandle,
+ Adapter->IoBaseAddr,
+ 0x10,
+ (PVOID)(Adapter->Nicsr)
+ );
+
+ } else if (Adapter->LanceCard == LANCE_DE422) {
+
+ NdisMDeregisterIoPortRange(
+ Adapter->MiniportAdapterHandle,
+ Adapter->IoBaseAddr,
+ 0x90,
+ (PVOID)(Adapter->Nicsr)
+ );
+
+ }
+
+ DeleteAdapterMemory(Adapter);
+
+ NdisFreeMemory(Adapter, sizeof(LANCE_ADAPTER), 0);
+
+ return;
+}
+
+#pragma NDIS_INIT_FUNCTION(LanceRegisterAdapter)
+
+NDIS_STATUS
+LanceRegisterAdapter(
+ IN PLANCE_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is responsible for the allocation of the datastructures
+ for the driver as well as any hardware specific details necessary
+ to talk with the device.
+
+Arguments:
+
+ Adapter - Pointer to the adapter block.
+
+Return Value:
+
+ Returns false if anything occurred that prevents the initialization
+ of the adapter.
+
+--*/
+{
+ //
+ // Result of Ndis Calls.
+ //
+ NDIS_STATUS Status;
+
+
+ //
+ // We put in this assertion to make sure that ushort are 2 bytes.
+ // if they aren't then the initialization block definition needs
+ // to be changed.
+ //
+ // Also all of the logic that deals with status registers assumes
+ // that control registers are only 2 bytes.
+ //
+
+ ASSERT(sizeof(USHORT) == 2);
+
+ //
+ // This assertion checks that the network address in the initialization
+ // block does start on the third byte of the initalization block.
+ //
+ // If this is true then other fields in the initialization block
+ // and the send and receive descriptors should be at their correct
+ // locations.
+ //
+
+#ifdef NDIS_NT
+ ASSERT(FIELD_OFFSET(LANCE_INITIALIZATION_BLOCK,PhysicalAddress[0]) == 2);
+#else
+ ASSERT(&((PLANCE_INITIALIZATION_BLOCK)0)->PhysicalAddress[0] == (PVOID)2);
+#endif //NDIS_NT
+
+ //
+ // Allocate memory for all of the adapter structures.
+ //
+
+ Adapter->NumberOfTransmitRings = LANCE_NUMBER_OF_TRANSMIT_RINGS;
+ Adapter->LogNumberTransmitRings = LANCE_LOG_TRANSMIT_RINGS;
+
+#ifndef i386
+
+ if (Adapter->LanceCard == LANCE_DECTC) {
+
+ Status = LanceDecTcSoftwareDetails(Adapter);
+ if (Status != NDIS_STATUS_SUCCESS) {
+ return Status;
+ }
+
+ } else
+
+
+#endif
+
+ {
+
+ if (Adapter->AmountOfHardwareMemory == 0x20000) {
+
+ ASSERT(Adapter->LanceCard == LANCE_DE422);
+
+ Adapter->SizeOfReceiveBuffer = LANCE_128K_SIZE_OF_RECEIVE_BUFFERS;
+ Adapter->NumberOfSmallBuffers = LANCE_128K_NUMBER_OF_SMALL_BUFFERS;
+ Adapter->NumberOfMediumBuffers= LANCE_128K_NUMBER_OF_MEDIUM_BUFFERS;
+ Adapter->NumberOfLargeBuffers = LANCE_128K_NUMBER_OF_LARGE_BUFFERS;
+
+ Adapter->NumberOfReceiveRings = LANCE_128K_NUMBER_OF_RECEIVE_RINGS;
+ Adapter->LogNumberReceiveRings = LANCE_128K_LOG_RECEIVE_RINGS;
+
+ } else if (Adapter->AmountOfHardwareMemory == 0x10000) {
+
+ Adapter->NumberOfReceiveRings = LANCE_64K_NUMBER_OF_RECEIVE_RINGS;
+ Adapter->LogNumberReceiveRings = LANCE_64K_LOG_RECEIVE_RINGS;
+
+ Adapter->SizeOfReceiveBuffer = LANCE_64K_SIZE_OF_RECEIVE_BUFFERS;
+ Adapter->NumberOfSmallBuffers = LANCE_64K_NUMBER_OF_SMALL_BUFFERS;
+ Adapter->NumberOfMediumBuffers= LANCE_64K_NUMBER_OF_MEDIUM_BUFFERS;
+ Adapter->NumberOfLargeBuffers = LANCE_64K_NUMBER_OF_LARGE_BUFFERS;
+
+ } else {
+
+ Adapter->NumberOfReceiveRings = LANCE_32K_NUMBER_OF_RECEIVE_RINGS;
+ Adapter->LogNumberReceiveRings = LANCE_32K_LOG_RECEIVE_RINGS;
+
+ Adapter->SizeOfReceiveBuffer = LANCE_32K_SIZE_OF_RECEIVE_BUFFERS;
+ Adapter->NumberOfSmallBuffers = LANCE_32K_NUMBER_OF_SMALL_BUFFERS;
+ Adapter->NumberOfMediumBuffers= LANCE_32K_NUMBER_OF_MEDIUM_BUFFERS;
+ Adapter->NumberOfLargeBuffers = LANCE_32K_NUMBER_OF_LARGE_BUFFERS;
+
+ }
+
+ }
+
+#ifndef i386
+
+ if (((Adapter->LanceCard == LANCE_DECTC) &&
+ (LanceDecTcHardwareDetails(Adapter) == NDIS_STATUS_SUCCESS)) ||
+ LanceHardwareDetails(Adapter))
+
+#else
+
+ if (LanceHardwareDetails(Adapter))
+
+#endif
+ {
+ NDIS_PHYSICAL_ADDRESS PhysicalAddress;
+
+ //
+ // Get hold of the RAP and RDP address as well
+ // as filling in the hardware assigned network
+ // address.
+ //
+
+ if ((Adapter->CurrentNetworkAddress[0] == 0x00) &&
+ (Adapter->CurrentNetworkAddress[1] == 0x00) &&
+ (Adapter->CurrentNetworkAddress[2] == 0x00) &&
+ (Adapter->CurrentNetworkAddress[3] == 0x00) &&
+ (Adapter->CurrentNetworkAddress[4] == 0x00) &&
+ (Adapter->CurrentNetworkAddress[5] == 0x00)) {
+
+ Adapter->CurrentNetworkAddress[0] = Adapter->NetworkAddress[0];
+ Adapter->CurrentNetworkAddress[1] = Adapter->NetworkAddress[1];
+ Adapter->CurrentNetworkAddress[2] = Adapter->NetworkAddress[2];
+ Adapter->CurrentNetworkAddress[3] = Adapter->NetworkAddress[3];
+ Adapter->CurrentNetworkAddress[4] = Adapter->NetworkAddress[4];
+ Adapter->CurrentNetworkAddress[5] = Adapter->NetworkAddress[5];
+
+ }
+
+ NdisSetPhysicalAddressHigh(PhysicalAddress, 0);
+ NdisSetPhysicalAddressLow(PhysicalAddress, (ULONG)(Adapter->HardwareBaseAddr));
+
+ Status = NdisMMapIoSpace(
+ &(Adapter->MmMappedBaseAddr),
+ Adapter->MiniportAdapterHandle,
+ PhysicalAddress,
+ Adapter->AmountOfHardwareMemory
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_RESOURCE_CONFLICT,
+ 0
+ );
+
+ return(Status);
+
+ }
+
+#if NDIS_WIN
+
+ //
+ // Save card setup information that is in card on-board memory
+ //
+ {
+ PUCHAR pTemp = (PUCHAR) (Adapter->MmMappedBaseAddr);
+
+ (UINT)pTemp &= 0xffff0000;
+ (UINT)pTemp |= 0x0000bffe;
+
+ NdisReadRegisterUshort((PUSHORT)pTemp, &(Adapter->SavedMemBase));
+ pTemp = (PUCHAR) (Adapter->MmMappedBaseAddr);
+
+ NdisReadRegisterUlong((PULONG)pTemp, &(Adapter->Reserved1));
+ NdisReadRegisterUlong((PULONG)pTemp, &(Adapter->Reserved2));
+
+ }
+
+#endif
+
+ Adapter->CurrentMemoryFirstFree = Adapter->MmMappedBaseAddr;
+
+
+ Adapter->MemoryFirstUnavailable =
+ (PUCHAR)(Adapter->CurrentMemoryFirstFree) +
+ Adapter->AmountOfHardwareMemory;
+
+ if (!AllocateAdapterMemory(Adapter)) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+
+ return( NDIS_STATUS_ADAPTER_NOT_FOUND );
+
+ }
+
+ Adapter->AllocateableRing = Adapter->TransmitRing;
+ Adapter->TransmittingRing = Adapter->TransmitRing;
+ Adapter->FirstUncommittedRing = Adapter->TransmitRing;
+ Adapter->NumberOfAvailableRings = Adapter->NumberOfTransmitRings;
+ Adapter->LastTransmitRingEntry = Adapter->TransmitRing +
+ (Adapter->NumberOfTransmitRings-1);
+
+ Adapter->CurrentReceiveIndex = 0;
+ Adapter->OutOfReceiveBuffers = 0;
+ Adapter->CRCError = 0;
+ Adapter->FramingError = 0;
+ Adapter->RetryFailure = 0;
+ Adapter->LostCarrier = 0;
+ Adapter->LateCollision = 0;
+ Adapter->UnderFlow = 0;
+ Adapter->Deferred = 0;
+ Adapter->OneRetry = 0;
+ Adapter->MoreThanOneRetry = 0;
+ Adapter->ResetInProgress = FALSE;
+ Adapter->ResetInitStarted = FALSE;
+ Adapter->FirstInitialization = TRUE;
+ Adapter->HardwareFailure = FALSE;
+
+ //
+ // First we make sure that the device is stopped. We call
+ // directly since we don't have an Interrupt object yet.
+ //
+
+ LanceSyncStopChip(Adapter);
+
+
+ //
+ // Initialize the interrupt.
+ //
+
+ Status = NdisMRegisterInterrupt(
+ &Adapter->Interrupt,
+ Adapter->MiniportAdapterHandle,
+ Adapter->InterruptNumber,
+ Adapter->InterruptRequestLevel,
+ FALSE,
+ FALSE,
+ NdisInterruptLatched
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS){
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_INTERRUPT_CONNECT,
+ 0
+ );
+
+ NdisMUnmapIoSpace(
+ Adapter->MiniportAdapterHandle,
+ Adapter->MmMappedBaseAddr,
+ Adapter->AmountOfHardwareMemory
+ );
+
+ DeleteAdapterMemory(Adapter);
+
+ return Status;
+ }
+
+ if ((Status = LanceInitialInit(Adapter)) != NDIS_STATUS_SUCCESS) {
+
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 0
+ );
+
+ NdisMUnmapIoSpace(
+ Adapter->MiniportAdapterHandle,
+ Adapter->MmMappedBaseAddr,
+ Adapter->AmountOfHardwareMemory
+ );
+
+ DeleteAdapterMemory(Adapter);
+
+ NdisMDeregisterInterrupt(&Adapter->Interrupt);
+
+ }
+
+ NdisMInitializeTimer(
+ &Adapter->DeferredTimer,
+ Adapter->MiniportAdapterHandle,
+ LanceDeferredTimerRoutine,
+ (PVOID)Adapter
+ );
+
+
+ return Status;
+
+ } else {
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
+ 0
+ );
+
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+}
+
+
+#pragma NDIS_INIT_FUNCTION(LanceInitialInit)
+
+NDIS_STATUS
+LanceInitialInit(
+ IN PLANCE_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets up the initial init of the driver.
+
+Arguments:
+
+ Adapter - The adapter for the hardware.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if (Adapter->LanceCard & (LANCE_DE201 | LANCE_DE100 | LANCE_DE422))
+ {
+ //
+ // Allow interrupts
+ //
+ Adapter->InterruptsStopped = FALSE;
+
+ LOG(UNPEND);
+
+ LANCE_WRITE_NICSR(Adapter, LANCE_NICSR_INT_ON);
+ }
+
+ SetInitBlockAndInit(Adapter);
+
+
+ //
+ // The only way that first initialization could have
+ // been turned off is if we actually initialized.
+ //
+ if (!Adapter->FirstInitialization)
+ {
+ //
+ // We can start the chip. We may not
+ // have any bindings to indicateto but this
+ // is unimportant.
+ //
+ LanceStartChip(Adapter);
+ return NDIS_STATUS_SUCCESS;
+ }
+ else
+ {
+ return(NDIS_STATUS_FAILURE);
+ }
+
+}
+
+
+STATIC
+VOID
+LanceStartChip(
+ IN PLANCE_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to start an already initialized lance.
+
+Arguments:
+
+ Adapter - The adapter for the LANCE to start.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ if (Adapter->ResetInProgress) {
+
+ return;
+
+ }
+
+ //
+ // Set the RAP to csr0.
+ //
+
+ LANCE_WRITE_RAP(
+ Adapter,
+ LANCE_SELECT_CSR0
+ );
+
+ //
+ // Set the RDP to a start chip.
+ //
+
+ LANCE_WRITE_RDP(
+ Adapter,
+ LANCE_CSR0_START | LANCE_CSR0_INTERRUPT_ENABLE
+ );
+
+}
+
+extern
+VOID
+LanceIsr(
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueDpc,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ Interrupt service routine for the lance.
+
+Arguments:
+
+ Context - Really a pointer to the adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Will hold the value from the csr.
+ //
+ USHORT LocalCSR0Value;
+
+ //
+ // Holds the pointer to the adapter.
+ //
+ PLANCE_ADAPTER Adapter = Context;
+
+ BOOLEAN StoppedInterrupts=FALSE;
+
+ LOG(IN_ISR);
+
+ *QueueDpc = FALSE;
+ *InterruptRecognized = FALSE;
+
+ if ((Adapter->LanceCard & (LANCE_DE201 | LANCE_DE100 | LANCE_DE422)) &&
+ !Adapter->InterruptsStopped
+ )
+ {
+ //
+ // Pend interrupts
+ //
+ StoppedInterrupts = TRUE;
+ Adapter->InterruptsStopped = TRUE;
+
+ LOG(PEND);
+
+ LANCE_ISR_WRITE_NICSR(
+ Adapter,
+ LANCE_NICSR_IMASK | LANCE_NICSR_LED_ON | LANCE_NICSR_INT_ON
+ );
+ }
+
+ //
+ // We don't need to select csr0, as the only way we could get
+ // an interrupt is to have already selected 0.
+ //
+ LANCE_ISR_READ_RDP(Adapter, &LocalCSR0Value);
+ if (LocalCSR0Value & LANCE_CSR0_INTERRUPT_FLAG)
+ {
+ *InterruptRecognized = TRUE;
+
+ //
+ // It's our interrupt. Clear only those bits that we got
+ // in this read of csr0. We do it this way incase any new
+ // reasons for interrupts occur between the time that we
+ // read csr0 and the time that we clear the bits.
+ //
+ LANCE_ISR_WRITE_RDP(
+ Adapter,
+ (USHORT)((LANCE_CSR0_CLEAR_INTERRUPT_BITS & LocalCSR0Value) |
+ LANCE_CSR0_INTERRUPT_ENABLE)
+ );
+ if (Adapter->FirstInitialization &&
+ (LocalCSR0Value & LANCE_CSR0_INITIALIZATION_DONE)
+ )
+ {
+ Adapter->FirstInitialization = FALSE;
+ }
+ }
+
+ //
+ // Enable the interrupts.
+ //
+ if ((Adapter->LanceCard & (LANCE_DE201 | LANCE_DE100 | LANCE_DE422)) &&
+ StoppedInterrupts
+ )
+ {
+ //
+ // Allow interrupts
+ //
+ Adapter->InterruptsStopped = FALSE;
+
+ LOG(UNPEND);
+
+ LANCE_ISR_WRITE_NICSR(Adapter, LANCE_NICSR_INT_ON);
+ }
+
+ LOG(OUT_ISR);
+
+ return;
+}
+STATIC
+VOID
+LanceDisableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine disables interrupts on the adapter.
+
+Arguments:
+
+ Context - Really a pointer to the adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLANCE_ADAPTER Adapter = (PLANCE_ADAPTER)MiniportAdapterContext;
+
+ //
+ // Pend any interrupts
+ //
+ ASSERT(Adapter->LanceCard & (LANCE_DE201 | LANCE_DE100 | LANCE_DE422));
+
+ LOG(PEND);
+
+ LANCE_ISR_WRITE_NICSR(
+ Adapter,
+ LANCE_NICSR_IMASK | LANCE_NICSR_LED_ON | LANCE_NICSR_INT_ON
+ );
+}
+
+
+STATIC
+VOID
+LanceEnableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine enables interrupts on the adapter.
+
+Arguments:
+
+ Context - Really a pointer to the adapter.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PLANCE_ADAPTER Adapter = (PLANCE_ADAPTER)MiniportAdapterContext;
+
+ ASSERT(Adapter->LanceCard & (LANCE_DE201 | LANCE_DE100 | LANCE_DE422));
+
+ //
+ // Allow interrupts
+ //
+
+ LOG(UNPEND);
+
+ LANCE_ISR_WRITE_NICSR(Adapter, LANCE_NICSR_INT_ON);
+}
+VOID
+LanceDeferredTimerRoutine(
+ IN PVOID SystemSpecific1,
+ IN NDIS_HANDLE Context,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+
+/*++
+
+Routine Description:
+
+ This DPC routine is used to handle deferred processing via a timer.
+
+Arguments:
+
+ Context - Really a pointer to the adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LanceHandleInterrupt(Context);
+}
+
+VOID
+LanceHandleInterrupt(
+ IN NDIS_HANDLE Context
+ )
+
+/*++
+
+Routine Description:
+
+ This DPC routine is queued by the interrupt service routine.
+
+Arguments:
+
+ Context - Really a pointer to the adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Holds the pointer to the adapter.
+ //
+ PLANCE_ADAPTER Adapter = Context;
+
+ //
+ // Holds a value of csr0.
+ //
+ USHORT Csr = 0;
+ USHORT LocalCSR0Value;
+
+ LOG(IN_DPC);
+
+ //
+ // Loop until there are no more processing sources.
+ //
+ for (;;)
+ {
+ //
+ // We don't need to select csr0, as the only way we could get
+ // an interrupt is to have already selected 0.
+ //
+ LANCE_ISR_READ_RDP(Adapter, &LocalCSR0Value);
+
+ if (LocalCSR0Value & LANCE_CSR0_INTERRUPT_FLAG)
+ {
+ //
+ // It's our interrupt. Clear only those bits that we got
+ // in this read of csr0. We do it this way incase any new
+ // reasons for interrupts occur between the time that we
+ // read csr0 and the time that we clear the bits.
+ //
+ LANCE_ISR_WRITE_RDP(
+ Adapter,
+ (USHORT)((LANCE_CSR0_CLEAR_INTERRUPT_BITS & LocalCSR0Value) |
+ LANCE_CSR0_INTERRUPT_ENABLE)
+ );
+
+ //
+ // Or the csr value into the adapter version of csr 0.
+ //
+ Csr |= LocalCSR0Value;
+ }
+
+ //
+ // Check the interrupt source and other reasons
+ // for processing. If there are no reasons to
+ // process then exit this loop.
+ //
+ if (((!Adapter->ResetInitStarted) &&
+ ((Csr & (LANCE_CSR0_MEMORY_ERROR |
+ LANCE_CSR0_MISSED_PACKET |
+ LANCE_CSR0_BABBLE |
+ LANCE_CSR0_RECEIVER_INTERRUPT |
+ LANCE_CSR0_TRANSMITTER_INTERRUPT)) ||
+ (Adapter->ResetInProgress))) ||
+ (Csr & LANCE_CSR0_INITIALIZATION_DONE)
+ )
+ {
+
+ }
+ else
+ {
+ break;
+ }
+
+ //
+ // Check for initialization.
+ //
+ // Note that we come out of the synchronization above holding
+ // the spinlock.
+ //
+ if (Csr & LANCE_CSR0_INITIALIZATION_DONE)
+ {
+ //
+ // Possibly undefined reason why the reset was requested.
+ //
+ // It is undefined if the adapter initiated the reset
+ // request on its own. It could do that if there
+ // were some sort of error.
+ //
+ NDIS_REQUEST_TYPE ResetRequestType;
+
+ LOG(RESET_STEP_3);
+
+ ASSERT(!Adapter->FirstInitialization);
+
+ Csr &= ~LANCE_CSR0_INITIALIZATION_DONE;
+
+ Adapter->ResetInProgress = FALSE;
+ Adapter->ResetInitStarted = FALSE;
+
+ //
+ // We save off the open that caused this reset incase
+ // we get *another* reset while we're indicating the
+ // last reset is done.
+ //
+ ResetRequestType = Adapter->ResetRequestType;
+
+ if (ResetRequestType == NdisRequestSetInformation)
+ {
+ //
+ // It was a request submitted by a protocol.
+ //
+ NdisMSetInformationComplete(
+ Adapter->MiniportAdapterHandle,
+ NDIS_STATUS_SUCCESS
+ );
+ }
+ else
+ {
+ //
+ // It was a reset command.
+ //
+ if (ResetRequestType == NdisRequestGeneric1)
+ {
+ //
+ // Is was a reset request
+ //
+ NdisMResetComplete(
+ Adapter->MiniportAdapterHandle,
+ NDIS_STATUS_SUCCESS,
+ FALSE
+ );
+ }
+ }
+
+ //
+ // Restart the chip.
+ //
+ LanceStartChip(Adapter);
+
+ goto LoopBottom;
+ }
+
+ //
+ // If we have a reset in progress and the adapters reference
+ // count is 1 (meaning no routine is in the interface and
+ // we are the only "active" interrupt processing routine) then
+ // it is safe to start the reset.
+ //
+ if (Adapter->ResetInProgress &&
+ !Adapter->ResetInitStarted
+ )
+ {
+#if LANCE_TRACE
+ DbgPrint("Starting Initialization.\n");
+#endif
+ StartAdapterReset(Adapter);
+
+ Adapter->ResetInitStarted = TRUE;
+ goto LoopBottom;
+ }
+
+ //
+ // Check for non-packet related errors.
+ //
+ if (Csr & (LANCE_CSR0_MEMORY_ERROR |
+ LANCE_CSR0_MISSED_PACKET |
+ LANCE_CSR0_BABBLE)
+ )
+ {
+ if (Csr & LANCE_CSR0_MISSED_PACKET)
+ {
+ Adapter->MissedPacket++;
+ }
+ else if (Csr & LANCE_CSR0_BABBLE)
+ {
+ //
+ // A babble error implies that we've sent a
+ // packet that is greater than the ethernet length.
+ // This implies that the driver is broken.
+ //
+ Adapter->Babble++;
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ (ULONG)processInterrupt,
+ (ULONG)0x1
+ );
+ }
+ else
+ {
+ //
+ // Could only be a memory error. This shuts down
+ // the receiver and the transmitter. We have to
+ // reset to get the device started again.
+ //
+ Adapter->MemoryError++;
+
+ SetupForReset(
+ Adapter,
+ NdisRequestGeneric4 // Means MAC issued
+ );
+ }
+
+ Csr &= ~LANCE_CSR0_ERROR_BITS;
+ }
+
+ //
+ // Check the interrupt vector and see if there are any
+ // more receives to process. After we process any
+ // other interrupt source we always come back to the top
+ // of the loop to check if any more receive packets have
+ // come in. This is to lessen the probability that we
+ // drop a receive.
+ //
+ if (Csr & LANCE_CSR0_RECEIVER_INTERRUPT)
+ {
+ if (ProcessReceiveInterrupts(Adapter))
+ {
+ Csr &= ~LANCE_CSR0_RECEIVER_INTERRUPT;
+ }
+ }
+
+ //
+ // Process the transmit interrupts if there are any.
+ //
+ if (Csr & LANCE_CSR0_TRANSMITTER_INTERRUPT)
+ {
+ //
+ // We need to check if the transmitter has
+ // stopped as a result of an error. If it
+ // has then we really need to reset the adapter.
+ //
+ if (!(Csr & LANCE_CSR0_TRANSMITTER_ON))
+ {
+ //
+ // Might as well turn off the transmitter interrupt
+ // source since we won't ever be processing them
+ // and we don't want to come back here again.
+ //
+ Csr &= ~LANCE_CSR0_TRANSMITTER_INTERRUPT;
+
+ //
+ // Before we setup for the reset make sure that
+ // we aren't already resetting.
+ //
+ if (!Adapter->ResetInProgress)
+ {
+ SetupForReset(
+ Adapter,
+ NdisRequestGeneric4 // means MAC issued
+ );
+ }
+
+ goto LoopBottom;
+ }
+ else
+ {
+ if (!ProcessTransmitInterrupts(Adapter))
+ {
+ //
+ // Process interrupts returns false if it
+ // finds no more work to do. If this so we
+ // turn off the transmitter interrupt source.
+ //
+ Csr &= ~LANCE_CSR0_TRANSMITTER_INTERRUPT;
+ }
+ }
+ }
+
+LoopBottom:;
+
+ }
+
+ //
+ // Check if we indicated any packets.
+ //
+ // Note: The only way to get out of the loop (via the break above) is
+ // while we're still holding the spin lock.
+ //
+ if (Adapter->IndicatedAPacket)
+ {
+ Adapter->IndicatedAPacket = FALSE;
+
+ NdisMEthIndicateReceiveComplete(Adapter->MiniportAdapterHandle);
+ }
+
+ LOG(OUT_DPC);
+}
+
+#pragma NDIS_INIT_FUNCTION(AllocateAdapterMemory)
+
+BOOLEAN
+AllocateAdapterMemory(
+ IN PLANCE_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates memory for:
+
+ - Transmit ring entries
+
+ - Receive ring entries
+
+ - Receive buffers
+
+ - Adapter buffers for use if user transmit buffers don't meet hardware
+ contraints
+
+ - Structures to map transmit ring entries back to the packets.
+
+Arguments:
+
+ Adapter - The adapter to allocate memory for.
+
+Return Value:
+
+ Returns FALSE if some memory needed for the adapter could not
+ be allocated.
+
+--*/
+
+{
+
+ //
+ // Pointer to a transmit ring entry. Used while initializing
+ // the ring.
+ //
+ PLANCE_TRANSMIT_ENTRY CurrentTransmitEntry;
+
+ //
+ // Pointer to a receive ring entry. Used while initializing
+ // the ring.
+ //
+ PLANCE_RECEIVE_ENTRY CurrentReceiveEntry;
+
+ //
+ // Simple iteration variable.
+ //
+ UINT i;
+
+ //
+ // These variables exist to reduce the amount of checking below.
+ //
+
+ ULONG NumberOfSmallBuffers;
+ ULONG NumberOfMediumBuffers;
+ ULONG NumberOfLargeBuffers;
+
+
+ NumberOfSmallBuffers = Adapter->NumberOfSmallBuffers;
+ NumberOfMediumBuffers = Adapter->NumberOfMediumBuffers;
+ NumberOfLargeBuffers = Adapter->NumberOfLargeBuffers;
+
+
+
+ //
+ // Allocate memory for the initialization block. Note that
+ // this memory can not cross a page boundary.
+ //
+
+ LANCE_ALLOCATE_MEMORY_FOR_HARDWARE(
+ Adapter,
+ sizeof(LANCE_INITIALIZATION_BLOCK),
+ &Adapter->InitBlock
+ );
+
+ if (Adapter->InitBlock == NULL) {
+ DeleteAdapterMemory(Adapter);
+ return FALSE;
+ }
+
+ //
+ // Allocate the transmit ring descriptors.
+ //
+
+ LANCE_ALLOCATE_MEMORY_FOR_HARDWARE(
+ Adapter,
+ sizeof(LANCE_TRANSMIT_ENTRY)*Adapter->NumberOfTransmitRings,
+ &Adapter->TransmitRing
+ )
+
+ if (Adapter->TransmitRing == NULL) {
+ DeleteAdapterMemory(Adapter);
+ return FALSE;
+ }
+
+ //
+ // We have the transmit ring descriptors. Make sure each is
+ // in a clean state.
+ //
+
+ for (
+ i = 0, CurrentTransmitEntry = Adapter->TransmitRing;
+ i < Adapter->NumberOfTransmitRings;
+ i++,CurrentTransmitEntry++
+ ) {
+
+ LANCE_ZERO_MEMORY_FOR_HARDWARE(
+ (PUCHAR)CurrentTransmitEntry,
+ sizeof(LANCE_TRANSMIT_ENTRY)
+ );
+
+ }
+
+
+ //
+ // Allocate all of the receive ring entries
+ //
+
+ LANCE_ALLOCATE_MEMORY_FOR_HARDWARE(
+ Adapter,
+ sizeof(LANCE_RECEIVE_ENTRY)*Adapter->NumberOfReceiveRings,
+ &Adapter->ReceiveRing
+ )
+
+ if (Adapter->ReceiveRing == NULL) {
+ DeleteAdapterMemory(Adapter);
+ return FALSE;
+ }
+
+ //
+ // We have the receive ring descriptors. Allocate an
+ // array to hold the virtual addresses of each receive
+ // buffer.
+ //
+
+ LANCE_ALLOC_PHYS(
+ &(Adapter->ReceiveVAs),
+ sizeof(PVOID) * Adapter->NumberOfReceiveRings
+ );
+
+ if (Adapter->ReceiveVAs == NULL) {
+ DeleteAdapterMemory(Adapter);
+ return FALSE;
+ }
+
+ //
+ // Clean the above memory
+ //
+
+ LANCE_ZERO_MEMORY(
+ Adapter->ReceiveVAs,
+ (sizeof(PVOID)*Adapter->NumberOfReceiveRings)
+ );
+
+
+ //
+ // We have the receive ring descriptors. Allocate a buffer
+ // for each descriptor and make sure descriptor is in a clean state.
+ //
+ // While we're at it, relinquish ownership of the ring discriptors to
+ // the lance.
+ //
+
+ for (
+ i = 0, CurrentReceiveEntry = Adapter->ReceiveRing;
+ i < Adapter->NumberOfReceiveRings;
+ i++,CurrentReceiveEntry++
+ ) {
+
+ LANCE_ALLOCATE_MEMORY_FOR_HARDWARE(
+ Adapter,
+ Adapter->SizeOfReceiveBuffer,
+ &Adapter->ReceiveVAs[i]
+ );
+
+ if (Adapter->ReceiveVAs[i] == NULL) {
+ DeleteAdapterMemory(Adapter);
+ return FALSE;
+ }
+
+
+ LANCE_SET_RECEIVE_BUFFER_ADDRESS(
+ Adapter,
+ CurrentReceiveEntry,
+ Adapter->ReceiveVAs[i]
+ );
+
+
+ LANCE_SET_RECEIVE_BUFFER_LENGTH(
+ CurrentReceiveEntry,
+ Adapter->SizeOfReceiveBuffer
+ );
+
+ LANCE_WRITE_HARDWARE_MEMORY_UCHAR(
+ CurrentReceiveEntry->ReceiveSummaryBits,
+ LANCE_RECEIVE_OWNED_BY_CHIP
+ );
+
+ }
+
+ //
+ // Allocate the ring to packet structure.
+ //
+
+ LANCE_ALLOC_PHYS(
+ &(Adapter->RingToPacket),
+ sizeof(LANCE_RING_TO_PACKET) * Adapter->NumberOfTransmitRings
+ );
+
+ if (Adapter->RingToPacket == NULL) {
+ DeleteAdapterMemory(Adapter);
+ return FALSE;
+ }
+
+ LANCE_ZERO_MEMORY(
+ Adapter->RingToPacket,
+ sizeof(LANCE_RING_TO_PACKET) * Adapter->NumberOfTransmitRings
+ );
+
+ //
+ // Allocate the array of buffer descriptors.
+ //
+
+ LANCE_ALLOC_PHYS(
+ &(Adapter->LanceBuffers),
+ sizeof(LANCE_BUFFER_DESCRIPTOR) *
+ (NumberOfSmallBuffers +
+ NumberOfMediumBuffers +
+ NumberOfLargeBuffers)
+ );
+
+ if (Adapter->LanceBuffers == NULL) {
+ DeleteAdapterMemory(Adapter);
+ return FALSE;
+ }
+
+ //
+ // Zero the memory of all the descriptors so that we can
+ // know which buffers wern't allocated incase we can't allocate
+ // them all.
+ //
+ LANCE_ZERO_MEMORY(
+ Adapter->LanceBuffers,
+ sizeof(LANCE_BUFFER_DESCRIPTOR)*
+ (NumberOfSmallBuffers +
+ NumberOfMediumBuffers +
+ NumberOfLargeBuffers)
+ );
+
+ //
+ // Allocate each of the small lance buffers and fill in the
+ // buffer descriptor.
+ //
+
+ Adapter->LanceBufferListHeads[0] = -1;
+ Adapter->LanceBufferListHeads[1] = 0;
+
+ for (
+ i = 0;
+ i < NumberOfSmallBuffers;
+ i++
+ ) {
+
+ LANCE_ALLOCATE_MEMORY_FOR_HARDWARE(
+ Adapter,
+ LANCE_SMALL_BUFFER_SIZE,
+ &Adapter->LanceBuffers[i].VirtualLanceBuffer
+ );
+
+ if (Adapter->LanceBuffers[i].VirtualLanceBuffer == NULL) {
+ DeleteAdapterMemory(Adapter);
+ return FALSE;
+ }
+
+ Adapter->LanceBuffers[i].Next = i+1;
+ Adapter->LanceBuffers[i].BufferSize = LANCE_SMALL_BUFFER_SIZE;
+
+ }
+
+ //
+ // Make sure that the last buffer correctly terminates the free list.
+ //
+
+ Adapter->LanceBuffers[i-1].Next = -1;
+
+ //
+ // Do the medium buffers now.
+ //
+
+ Adapter->LanceBufferListHeads[2] = i;
+
+ for (
+ ;
+ i < NumberOfSmallBuffers + NumberOfMediumBuffers;
+ i++
+ ) {
+
+ LANCE_ALLOCATE_MEMORY_FOR_HARDWARE(
+ Adapter,
+ LANCE_MEDIUM_BUFFER_SIZE,
+ &Adapter->LanceBuffers[i].VirtualLanceBuffer
+ );
+
+ if (Adapter->LanceBuffers[i].VirtualLanceBuffer == NULL) {
+ DeleteAdapterMemory(Adapter);
+ return FALSE;
+ }
+
+
+ Adapter->LanceBuffers[i].Next = i+1;
+ Adapter->LanceBuffers[i].BufferSize = LANCE_MEDIUM_BUFFER_SIZE;
+
+ }
+
+ //
+ // Make sure that the last buffer correctly terminates the free list.
+ //
+
+ Adapter->LanceBuffers[i-1].Next = -1;
+
+
+ Adapter->LanceBufferListHeads[3] = i;
+
+ for (
+ ;
+ i < NumberOfSmallBuffers + NumberOfMediumBuffers + NumberOfLargeBuffers;
+ i++
+ ) {
+
+
+ LANCE_ALLOCATE_MEMORY_FOR_HARDWARE(
+ Adapter,
+ LANCE_LARGE_BUFFER_SIZE,
+ &Adapter->LanceBuffers[i].VirtualLanceBuffer
+ );
+
+ if (Adapter->LanceBuffers[i].VirtualLanceBuffer == NULL) {
+ DeleteAdapterMemory(Adapter);
+ return FALSE;
+ }
+
+
+ Adapter->LanceBuffers[i].Next = i+1;
+ Adapter->LanceBuffers[i].BufferSize = LANCE_LARGE_BUFFER_SIZE;
+
+ }
+
+ //
+ // Make sure that the last buffer correctly terminates the free list.
+ //
+
+ Adapter->LanceBuffers[i-1].Next = -1;
+
+ return TRUE;
+
+}
+
+
+STATIC
+VOID
+DeleteAdapterMemory(
+ IN PLANCE_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deallocates memory for:
+
+ - Transmit ring entries
+
+ - Receive ring entries
+
+ - Receive buffers
+
+ - Adapter buffers for use if user transmit buffers don't meet hardware
+ contraints
+
+ - Structures to map transmit ring entries back to the packets.
+
+Arguments:
+
+ Adapter - The adapter to deallocate memory for.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // These variables exist to reduce the amount of checking below.
+ //
+
+ ULONG NumberOfSmallBuffers;
+ ULONG NumberOfMediumBuffers;
+ ULONG NumberOfLargeBuffers;
+
+ NumberOfSmallBuffers = Adapter->NumberOfSmallBuffers;
+ NumberOfMediumBuffers = Adapter->NumberOfMediumBuffers;
+ NumberOfLargeBuffers = Adapter->NumberOfLargeBuffers;
+
+
+ if (Adapter->InitBlock) {
+
+ LANCE_DEALLOCATE_MEMORY_FOR_HARDWARE(
+ Adapter,
+ Adapter->InitBlock
+ );
+
+ }
+
+ if (Adapter->TransmitRing) {
+
+ LANCE_DEALLOCATE_MEMORY_FOR_HARDWARE(
+ Adapter,
+ Adapter->TransmitRing
+ );
+
+ }
+
+ if (Adapter->ReceiveRing) {
+
+ LANCE_DEALLOCATE_MEMORY_FOR_HARDWARE(
+ Adapter,
+ Adapter->ReceiveRing
+ );
+
+ }
+
+ if (Adapter->ReceiveVAs) {
+
+ UINT i;
+
+ for (
+ i = 0;
+ i < Adapter->NumberOfReceiveRings;
+ i++
+ ) {
+
+ if (Adapter->ReceiveVAs[i]) {
+
+ LANCE_DEALLOCATE_MEMORY_FOR_HARDWARE(
+ Adapter,
+ Adapter->ReceiveVAs[i]
+ );
+
+ } else {
+
+ break;
+
+ }
+
+ }
+
+ LANCE_FREE_PHYS(
+ Adapter->ReceiveVAs,
+ sizeof(PVOID) * Adapter->NumberOfReceiveRings
+ );
+
+ }
+
+ if (Adapter->RingToPacket) {
+
+ LANCE_FREE_PHYS(
+ Adapter->RingToPacket,
+ sizeof(LANCE_RING_TO_PACKET) * Adapter->NumberOfTransmitRings
+ );
+
+ }
+
+ if (Adapter->LanceBuffers) {
+
+ UINT i;
+
+ for (
+ i = 0;
+ i < NumberOfSmallBuffers + NumberOfMediumBuffers + NumberOfLargeBuffers;
+ i++) {
+
+ if (Adapter->LanceBuffers[i].VirtualLanceBuffer) {
+
+ LANCE_DEALLOCATE_MEMORY_FOR_HARDWARE(
+ Adapter,
+ Adapter->LanceBuffers[i].VirtualLanceBuffer
+ );
+
+ } else {
+
+ break;
+
+ }
+
+ }
+
+ LANCE_FREE_PHYS(
+ Adapter->LanceBuffers,
+ sizeof(LANCE_BUFFER_DESCRIPTOR) *
+ (NumberOfSmallBuffers +
+ NumberOfMediumBuffers +
+ NumberOfLargeBuffers)
+ );
+
+ }
+
+}
+
+
+NDIS_STATUS
+LanceQueryInformation(
+ IN PNDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InfoBuffer,
+ IN ULONG BytesLeft,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+)
+/*++
+
+Routine Description:
+
+ The LanceQuerylInformation process a Query request for
+ NDIS_OIDs that are specific to a binding about the mini-port.
+
+Arguments:
+
+ Status - The status of the operation.
+
+ MiniportAdapterContext - a pointer to the adapter.
+
+ Oid - the NDIS_OID to process.
+
+ InfoBuffer - a pointer into the NdisRequest->InformationBuffer
+ into which store the result of the query.
+
+ BytesLeft - the number of bytes left in the InformationBuffer.
+
+ BytesNeeded - If there is not enough room in the information buffer
+ then this will contain the number of bytes needed to complete the
+ request.
+
+ BytesWritten - a pointer to the number of bytes written into the
+ InformationBuffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLANCE_ADAPTER Adapter = (PLANCE_ADAPTER)MiniportAdapterContext;
+ NDIS_MEDIUM Medium = NdisMedium802_3;
+ ULONG GenericULong;
+ USHORT GenericUShort;
+ UCHAR GenericArray[6];
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ //
+ // Common variables for pointing to result of query
+ //
+
+ PVOID MoveSource;
+ ULONG MoveBytes;
+
+ NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady;
+
+ //
+ // Make sure that ulong is 4 bytes. Else GenericULong must change
+ // to something of size 4.
+ //
+ ASSERT(sizeof(ULONG) == 4);
+
+
+#if LANCE_TRACE
+ DbgPrint("In LanceQueryInfo\n");
+#endif
+
+ //
+ // Set default values
+ //
+
+ MoveSource = (PVOID)(&GenericULong);
+ MoveBytes = sizeof(GenericULong);
+
+ //
+ // Switch on request type
+ //
+
+ switch (Oid) {
+
+ case OID_GEN_MAC_OPTIONS:
+
+ GenericULong = (ULONG)(NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
+ NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
+ NDIS_MAC_OPTION_NO_LOOPBACK
+ );
+
+ break;
+
+ case OID_GEN_SUPPORTED_LIST:
+
+ MoveSource = (PVOID)(LanceGlobalSupportedOids);
+ MoveBytes = sizeof(LanceGlobalSupportedOids);
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+
+
+ if (Adapter->ResetInProgress){
+
+ HardwareStatus = NdisHardwareStatusReset;
+
+ } else {
+
+ HardwareStatus = NdisHardwareStatusReady;
+
+ }
+
+ MoveSource = (PVOID)(&HardwareStatus);
+ MoveBytes = sizeof(NDIS_HARDWARE_STATUS);
+
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+
+ MoveSource = (PVOID) (&Medium);
+ MoveBytes = sizeof(NDIS_MEDIUM);
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+
+ GenericULong = LANCE_MAX_LOOKAHEAD;
+
+ break;
+
+
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+
+ GenericULong = (ULONG)(LANCE_LARGE_BUFFER_SIZE - LANCE_HEADER_SIZE);
+
+ break;
+
+
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+
+ GenericULong = (ULONG)(LANCE_LARGE_BUFFER_SIZE);
+
+ break;
+
+
+ case OID_GEN_LINK_SPEED:
+
+ GenericULong = (ULONG)(100000);
+
+ break;
+
+
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+
+ GenericULong = (ULONG)((LANCE_SMALL_BUFFER_SIZE * Adapter->NumberOfSmallBuffers) +
+ (LANCE_MEDIUM_BUFFER_SIZE * Adapter->NumberOfMediumBuffers) +
+ (LANCE_LARGE_BUFFER_SIZE * Adapter->NumberOfLargeBuffers));
+
+
+ break;
+
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+
+ GenericULong = (ULONG)(Adapter->NumberOfReceiveRings *
+ Adapter->SizeOfReceiveBuffer);
+
+ break;
+
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+
+ GenericULong = (ULONG)(LANCE_SMALL_BUFFER_SIZE);
+
+ break;
+
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+
+ GenericULong = (ULONG)(Adapter->SizeOfReceiveBuffer);
+
+ break;
+
+ case OID_GEN_VENDOR_ID:
+
+ NdisMoveMemory(
+ (PVOID)(&GenericULong),
+ Adapter->NetworkAddress,
+ 3
+ );
+
+ GenericULong &= 0xFFFFFF00;
+
+ if (Adapter->LanceCard == LANCE_DE201) {
+
+ GenericULong |= 0x01;
+
+ } else if (Adapter->LanceCard == LANCE_DE100) {
+
+ GenericULong |= 0x02;
+
+ } else if (Adapter->LanceCard == LANCE_DE422) {
+
+ GenericULong |= 0x03;
+
+ } else {
+
+ GenericULong |= 0x04;
+
+ }
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+
+ if (Adapter->LanceCard == LANCE_DE201) {
+
+ MoveSource = (PVOID)"DEC Etherworks Turbo Adapter";
+ MoveBytes = 29;
+
+ } else if (Adapter->LanceCard == LANCE_DE100) {
+
+ MoveSource = (PVOID)"DEC Etherworks Adapter";
+ MoveBytes = 23;
+
+ } else if (Adapter->LanceCard == LANCE_DE422) {
+
+ MoveSource = (PVOID)"DEC Etherworks Turbo EISA Adapter";
+ MoveBytes = 34;
+
+ } else {
+
+ MoveSource = (PVOID)"Lance Adapter.";
+ MoveBytes = 15;
+
+ }
+
+ break;
+
+ case OID_GEN_DRIVER_VERSION:
+
+ GenericUShort = (LANCE_NDIS_MAJOR_VERSION << 8) | LANCE_NDIS_MINOR_VERSION;
+
+ MoveSource = (PVOID)(&GenericUShort);
+ MoveBytes = sizeof(GenericUShort);
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ GenericULong = Adapter->SizeOfReceiveBuffer;
+
+ break;
+
+ case OID_802_3_PERMANENT_ADDRESS:
+
+ LANCE_MOVE_MEMORY((PCHAR)GenericArray,
+ Adapter->NetworkAddress,
+ LANCE_LENGTH_OF_ADDRESS
+ );
+
+ MoveSource = (PVOID)(GenericArray);
+ MoveBytes = sizeof(Adapter->NetworkAddress);
+ break;
+
+ case OID_802_3_CURRENT_ADDRESS:
+
+
+ LANCE_MOVE_MEMORY((PCHAR)GenericArray,
+ Adapter->CurrentNetworkAddress,
+ LANCE_LENGTH_OF_ADDRESS
+ );
+
+ MoveSource = (PVOID)(GenericArray);
+ MoveBytes = sizeof(Adapter->CurrentNetworkAddress);
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+
+ GenericULong = Adapter->MaxMulticastList;
+
+ break;
+
+ case OID_GEN_XMIT_OK:
+
+ GenericULong = (ULONG)(Adapter->Transmit + Adapter->LateCollision);
+
+ break;
+
+ case OID_GEN_RCV_OK:
+
+ GenericULong = (ULONG)(Adapter->Receive);
+
+ break;
+
+ case OID_GEN_XMIT_ERROR:
+
+ GenericULong = (ULONG)(Adapter->LostCarrier);
+
+ break;
+
+ case OID_GEN_RCV_ERROR:
+
+ GenericULong = (ULONG)(Adapter->CRCError);
+
+ break;
+
+ case OID_GEN_RCV_NO_BUFFER:
+
+ GenericULong = (ULONG)(Adapter->OutOfReceiveBuffers);
+
+ break;
+
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+
+ GenericULong = (ULONG)(Adapter->FramingError);
+
+ break;
+
+ case OID_802_3_XMIT_ONE_COLLISION:
+
+ GenericULong = (ULONG)(Adapter->OneRetry);
+
+ break;
+
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+
+ GenericULong = (ULONG)(Adapter->MoreThanOneRetry);
+
+ break;
+
+ default:
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS){
+
+ if (MoveBytes > BytesLeft){
+
+ //
+ // Not enough room in InformationBuffer. Punt
+ //
+
+ *BytesNeeded = MoveBytes;
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ } else {
+
+ //
+ // Store result.
+ //
+
+ LANCE_MOVE_MEMORY(InfoBuffer, MoveSource, MoveBytes);
+
+ (*BytesWritten) += MoveBytes;
+
+ }
+ }
+
+#if LANCE_TRACE
+ DbgPrint("Out LanceQueryInfo\n");
+#endif
+
+ LANCE_DO_DEFERRED(Adapter);
+
+ return StatusToReturn;
+}
+
+NDIS_STATUS
+LanceSetInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ )
+/*++
+
+Routine Description:
+
+ The LanceSetInformation is used by LanceRequest to set information
+ about the MAC.
+
+ Note: Assumes it is called with the lock held.
+
+Arguments:
+
+ Adapter - A pointer to the adapter.
+
+ Open - A pointer to an open instance.
+
+ NdisRequest - A structure which contains the request type (Set),
+ an array of operations to perform, and an array for holding
+ the results of the operations.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+ PLANCE_ADAPTER Adapter = (PLANCE_ADAPTER)(MiniportAdapterContext);
+ //
+ // General Algorithm:
+ //
+ // For each request
+ // Verify length
+ // Switch(Request)
+ // Process Request
+ //
+
+ UINT BytesLeft = InformationBufferLength;
+ PUCHAR InfoBuffer = (PUCHAR)InformationBuffer;
+
+ //
+ // Variables for a particular request
+ //
+
+ UINT OidLength;
+
+ //
+ // Variables for holding the new values to be used.
+ //
+
+ ULONG LookAhead;
+ ULONG Filter;
+
+ NDIS_STATUS Status;
+
+#if LANCE_TRACE
+ DbgPrint("In LanceSetInfo\n");
+#endif
+
+ //
+ // Get Oid and Length of next request
+ //
+
+ OidLength = BytesLeft;
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ switch (Oid) {
+
+ case OID_802_3_MULTICAST_LIST:
+
+ //
+ // Verify length
+ //
+
+ if ((OidLength % LANCE_LENGTH_OF_ADDRESS) != 0){
+
+ *BytesRead = 0;
+ *BytesNeeded = 0;
+
+ return( NDIS_STATUS_INVALID_LENGTH );
+
+ }
+
+ Status = LanceChangeMulticastAddresses(
+ Adapter,
+ OidLength / LANCE_LENGTH_OF_ADDRESS,
+ (CHAR (*)[LANCE_LENGTH_OF_ADDRESS])InfoBuffer,
+ NdisRequestSetInformation
+ );
+
+ break;
+
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ //
+ // Verify length
+ //
+
+ if (OidLength != 4) {
+
+ Status = NDIS_STATUS_INVALID_LENGTH;
+
+ *BytesRead = 0;
+ *BytesNeeded = 0;
+
+ break;
+
+ }
+
+
+ LANCE_MOVE_MEMORY(&Filter, InfoBuffer, 4);
+
+ //
+ // Verify bits
+ //
+ if (Filter & (NDIS_PACKET_TYPE_SOURCE_ROUTING |
+ NDIS_PACKET_TYPE_SMT |
+ NDIS_PACKET_TYPE_MAC_FRAME |
+ NDIS_PACKET_TYPE_FUNCTIONAL |
+ NDIS_PACKET_TYPE_ALL_FUNCTIONAL |
+ NDIS_PACKET_TYPE_GROUP
+ )) {
+
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+
+ *BytesRead = 4;
+ *BytesNeeded = 0;
+
+ break;
+
+ }
+
+ Status = LanceSetPacketFilter(
+ Adapter,
+ NdisRequestSetInformation,
+ Filter
+ );
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ //
+ // Verify length
+ //
+ if (OidLength != 4)
+ {
+ Status = NDIS_STATUS_INVALID_LENGTH;
+
+ *BytesRead = 0;
+ *BytesNeeded = 4;
+
+ break;
+ }
+
+ LANCE_MOVE_MEMORY(&LookAhead, InfoBuffer, 4);
+
+ if (LookAhead <= (LANCE_MAX_LOOKAHEAD))
+ {
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ else
+ {
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ }
+
+ *BytesRead = 4;
+ *BytesNeeded = 0;
+ break;
+
+ default:
+
+ Status = NDIS_STATUS_INVALID_OID;
+
+ *BytesRead = 0;
+ *BytesNeeded = 0;
+
+ break;
+ }
+
+ if (Status == NDIS_STATUS_SUCCESS){
+
+ *BytesRead = OidLength;
+ *BytesNeeded = 0;
+
+ }
+
+#if LANCE_TRACE
+ DbgPrint("Out LanceSetInfo\n");
+#endif
+
+ LANCE_DO_DEFERRED(Adapter);
+
+ return Status;
+}
+
+STATIC
+NDIS_STATUS
+LanceSetPacketFilter(
+ IN PLANCE_ADAPTER Adapter,
+ IN NDIS_REQUEST_TYPE NdisRequestType,
+ IN UINT PacketFilter
+ )
+
+/*++
+
+Routine Description:
+
+ The LanceSetPacketFilter request allows a protocol to control the types
+ of packets that it receives from the MAC.
+
+ Note : Assumes that the lock is currently held.
+
+Arguments:
+
+ Adapter - Pointer to the LANCE_ADAPTER.
+
+ NdisRequestType - Code to indicate from where this routine is being called.
+
+ PacketFilter - A bit mask that contains flags that correspond to specific
+ classes of received packets. If a particular bit is set in the mask,
+ then packet reception for that class of packet is enabled. If the
+ bit is clear, then packets that fall into that class are not received
+ by the client. A single exception to this rule is that if the promiscuous
+ bit is set, then the client receives all packets on the network, regardless
+ of the state of the other flags.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+ //
+ // Keeps track of the *MAC's* status. The status will only be
+ // reset if the filter change action routine is called.
+ //
+ NDIS_STATUS StatusOfFilterChange = NDIS_STATUS_SUCCESS;
+
+
+#if LANCE_TRACE
+ DbgPrint("In LanceSetPacketFilter\n");
+#endif
+
+ //
+ // Check to see if the device is already resetting.
+ //
+
+ if (Adapter->ResetInProgress || Adapter->HardwareFailure)
+ {
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // We need to add this to the hardware multicast filtering.
+ //
+ Adapter->PacketFilter = PacketFilter;
+
+ SetupForReset(Adapter, NdisRequestType);
+
+#if LANCE_TRACE
+ DbgPrint("Out LanceSetPacketFilter\n");
+#endif
+
+ return(NDIS_STATUS_PENDING);
+}
+
+STATIC
+UINT
+CalculateCRC(
+ IN UINT NumberOfBytes,
+ IN PCHAR Input
+ )
+
+/*++
+
+Routine Description:
+
+ Calculates a 32 bit crc value over the input number of bytes.
+
+Arguments:
+
+ NumberOfBytes - The number of bytes in the input.
+
+ Input - An input "string" to calculate a CRC over.
+
+Return Value:
+
+ A 32 bit crc value.
+
+
+--*/
+
+{
+
+ const UINT POLY = 0x04c11db6;
+ UINT CRCValue = 0xffffffff;
+
+ ASSERT(sizeof(UINT) == 4);
+
+ for ( ; NumberOfBytes; NumberOfBytes-- ) {
+
+ UINT CurrentBit;
+ UCHAR CurrentByte = *Input;
+ Input++;
+
+ for ( CurrentBit = 8; CurrentBit; CurrentBit-- ) {
+
+ UINT CurrentCRCHigh = CRCValue >> 31;
+
+ CRCValue <<= 1;
+
+ if (CurrentCRCHigh ^ (CurrentByte & 0x01)) {
+
+ CRCValue ^= POLY;
+ CRCValue |= 0x00000001;
+
+ }
+
+ CurrentByte >>= 1;
+
+ }
+
+ }
+
+ return CRCValue;
+
+}
+
+STATIC
+NDIS_STATUS
+LanceChangeMulticastAddresses(
+ IN PLANCE_ADAPTER Adapter,
+ IN UINT NewAddressCount,
+ IN CHAR NewAddresses[][LANCE_LENGTH_OF_ADDRESS],
+ IN NDIS_REQUEST_TYPE NdisRequestType
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when a particular filter
+ class is first used or last cleared.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ Adapter - The adapter.
+
+ NewAddressCount - Number of Addresses that should be put on the adapter.
+
+ NewAddresses - An array of all the multicast addresses that should
+ now be used.
+
+ NdisRequestType - The request type.
+
+Return Value:
+
+ Status of the operation.
+
+
+--*/
+
+{
+#if LANCE_TRACE
+ DbgPrint("In LanceChangeMultiAdresses\n");
+#endif
+
+ //
+ // Check to see if the device is already resetting. If it is
+ // then pend this add.
+ //
+ if (Adapter->ResetInProgress || Adapter->HardwareFailure)
+ {
+
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // We need to add this to the hardware multicast filtering.
+ //
+ Adapter->NumberOfAddresses = NewAddressCount;
+
+ NdisMoveMemory(
+ Adapter->MulticastAddresses,
+ NewAddresses,
+ NewAddressCount * LANCE_LENGTH_OF_ADDRESS
+ );
+
+ SetupForReset(Adapter, NdisRequestType);
+
+
+#if LANCE_TRACE
+ DbgPrint("Out LanceChangeMultiAdresses\n");
+#endif
+
+ return(NDIS_STATUS_PENDING);
+
+}
+
+NDIS_STATUS
+LanceReset(
+ OUT PBOOLEAN AddressingReset,
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ The LanceReset request instructs the mini-port to issue a hardware reset
+ to the network adapter. The Miniport also resets its software state. See
+ the description of MiniportReset for a detailed description of this request.
+
+Arguments:
+
+ Status - Status of the operation.
+
+ AddressingReset - Not used.
+
+ MiniportAdapterContext - The context value set by this mini-port.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+
+{
+ //
+ // Holds the status that should be returned to the caller.
+ //
+ PLANCE_ADAPTER Adapter = (PLANCE_ADAPTER)MiniportAdapterContext;
+
+ SetupForReset(
+ Adapter,
+ NdisRequestGeneric1 // Means Reset
+ );
+
+ LANCE_DO_DEFERRED(Adapter);
+
+ return(NDIS_STATUS_PENDING);
+}
+
+STATIC
+VOID
+LanceSetInitializationBlock(
+ IN PLANCE_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine simply fills the initialization block
+ with the information necessary for initialization.
+
+Arguments:
+
+ Adapter - The adapter which holds the initialization block
+ to initialize.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+
+ ULONG PhysAdr;
+
+ UINT PacketFilters;
+
+ PLANCE_RECEIVE_ENTRY CurrentEntry = Adapter->ReceiveRing;
+ USHORT Mode;
+ UCHAR RingNumber;
+ UCHAR i;
+
+#if LANCE_TRACE
+ DbgPrint("in SetInitBlock\n");
+#endif
+
+ LANCE_ZERO_MEMORY_FOR_HARDWARE(
+ (PUCHAR)Adapter->InitBlock,
+ sizeof(LANCE_INITIALIZATION_BLOCK)
+ );
+
+ //
+ // Set the card address.
+ //
+ for (i = 0; i < LANCE_LENGTH_OF_ADDRESS; i++)
+ {
+ LANCE_WRITE_HARDWARE_MEMORY_UCHAR(
+ Adapter->InitBlock->PhysicalAddress[i],
+ Adapter->CurrentNetworkAddress[i]
+ );
+ }
+
+ //
+ // Setup the transmit ring.
+ //
+ PhysAdr = LANCE_GET_HARDWARE_PHYSICAL_ADDRESS(
+ Adapter,
+ Adapter->TransmitRing
+ );
+
+ LANCE_WRITE_HARDWARE_LOW_PART_ADDRESS(
+ Adapter->InitBlock->LowTransmitRingAddress,
+ LANCE_GET_LOW_PART_ADDRESS(PhysAdr)
+ );
+
+ LANCE_WRITE_HARDWARE_HIGH_PART_ADDRESS(
+ Adapter->InitBlock->HighTransmitRingAddress,
+ LANCE_GET_HIGH_PART_ADDRESS(PhysAdr)
+ );
+
+ //
+ // Setup the receive ring.
+ //
+ PhysAdr = LANCE_GET_HARDWARE_PHYSICAL_ADDRESS(
+ Adapter,
+ Adapter->ReceiveRing
+ );
+
+ //
+ // Set that the chip owns each entry in the ring
+ //
+ for (CurrentEntry = Adapter->ReceiveRing, RingNumber = 0;
+ RingNumber < Adapter->NumberOfReceiveRings ;
+ RingNumber++, CurrentEntry++
+ )
+ {
+ LANCE_WRITE_HARDWARE_MEMORY_UCHAR(
+ CurrentEntry->ReceiveSummaryBits,
+ LANCE_RECEIVE_OWNED_BY_CHIP
+ );
+ }
+
+ LANCE_WRITE_HARDWARE_LOW_PART_ADDRESS(
+ Adapter->InitBlock->LowReceiveRingAddress,
+ LANCE_GET_LOW_PART_ADDRESS(PhysAdr)
+ );
+
+ LANCE_WRITE_HARDWARE_HIGH_PART_ADDRESS(
+ Adapter->InitBlock->HighReceiveRingAddress,
+ LANCE_GET_HIGH_PART_ADDRESS(PhysAdr)
+ );
+
+ LANCE_WRITE_HARDWARE_MEMORY_UCHAR(
+ Adapter->InitBlock->TransmitLengthLow5BitsReserved,
+ (UCHAR)(Adapter->LogNumberTransmitRings << 5)
+ );
+
+ LANCE_WRITE_HARDWARE_MEMORY_UCHAR(
+ Adapter->InitBlock->ReceiveLengthLow5BitsReserved,
+ (UCHAR)(Adapter->LogNumberReceiveRings << 5)
+ );
+
+ //
+ // Set up the address filtering.
+ //
+ // First get hold of the combined packet filter.
+ //
+ PacketFilters = Adapter->PacketFilter;
+
+#if LANCE_TRACE
+ DbgPrint("Filters 0x%x\n", PacketFilters);
+#endif
+
+ if (PacketFilters & NDIS_PACKET_TYPE_PROMISCUOUS)
+ {
+ //
+ // If one binding is promiscuous there is no point in
+ // setting up any other filtering. Every packet is
+ // going to be accepted by the hardware.
+ //
+ LANCE_READ_HARDWARE_MEMORY_USHORT(
+ Adapter->InitBlock->ModeRegister,
+ &Mode
+ );
+
+ LANCE_WRITE_HARDWARE_MEMORY_USHORT(
+ Adapter->InitBlock->ModeRegister,
+ Mode | LANCE_MODE_PROMISCUOUS
+ );
+ }
+ else
+ {
+ //
+ // Turn off promiscuous bit
+ //
+ LANCE_READ_HARDWARE_MEMORY_USHORT(
+ Adapter->InitBlock->ModeRegister,
+ &Mode
+ );
+
+ LANCE_WRITE_HARDWARE_MEMORY_USHORT(
+ Adapter->InitBlock->ModeRegister,
+ Mode & (~LANCE_MODE_PROMISCUOUS)
+ );
+
+ if (PacketFilters & NDIS_PACKET_TYPE_ALL_MULTICAST)
+ {
+ //
+ // We turn on all the bits in the filter since one binding
+ // wants every multicast address.
+ //
+ LANCE_WRITE_HARDWARE_MEMORY_UCHAR(
+ Adapter->InitBlock->LogicalAddressFilter[0],
+ 0xff
+ );
+ LANCE_WRITE_HARDWARE_MEMORY_UCHAR(
+ Adapter->InitBlock->LogicalAddressFilter[1],
+ 0xff
+ );
+ LANCE_WRITE_HARDWARE_MEMORY_UCHAR(
+ Adapter->InitBlock->LogicalAddressFilter[2],
+ 0xff
+ );
+ LANCE_WRITE_HARDWARE_MEMORY_UCHAR(
+ Adapter->InitBlock->LogicalAddressFilter[3],
+ 0xff
+ );
+ LANCE_WRITE_HARDWARE_MEMORY_UCHAR(
+ Adapter->InitBlock->LogicalAddressFilter[4],
+ 0xff
+ );
+ LANCE_WRITE_HARDWARE_MEMORY_UCHAR(
+ Adapter->InitBlock->LogicalAddressFilter[5],
+ 0xff
+ );
+ LANCE_WRITE_HARDWARE_MEMORY_UCHAR(
+ Adapter->InitBlock->LogicalAddressFilter[6],
+ 0xff
+ );
+ LANCE_WRITE_HARDWARE_MEMORY_UCHAR(
+ Adapter->InitBlock->LogicalAddressFilter[7],
+ 0xff
+ );
+ }
+ else if (PacketFilters & NDIS_PACKET_TYPE_MULTICAST)
+ {
+ //
+ // At least one open binding wants multicast addresses.
+ //
+ // We get the multicast addresses from the filter and
+ // put each one through a CRC. We then take the high
+ // order 6 bits from the 32 bit CRC and set that bit
+ // in the logical address filter.
+ //
+ UINT NumberOfAddresses;
+
+ NumberOfAddresses = Adapter->NumberOfAddresses;
+
+ ASSERT(sizeof(ULONG) == 4);
+
+ for ( ; NumberOfAddresses; NumberOfAddresses--)
+ {
+ UINT CRCValue;
+
+ UINT HashValue = 0;
+
+ CRCValue = CalculateCRC(
+ 6,
+ Adapter->MulticastAddresses[NumberOfAddresses-1]
+ );
+
+ HashValue |= ((CRCValue & 0x00000001)?(0x00000020):(0x00000000));
+ HashValue |= ((CRCValue & 0x00000002)?(0x00000010):(0x00000000));
+ HashValue |= ((CRCValue & 0x00000004)?(0x00000008):(0x00000000));
+ HashValue |= ((CRCValue & 0x00000008)?(0x00000004):(0x00000000));
+ HashValue |= ((CRCValue & 0x00000010)?(0x00000002):(0x00000000));
+ HashValue |= ((CRCValue & 0x00000020)?(0x00000001):(0x00000000));
+
+ LANCE_READ_HARDWARE_MEMORY_UCHAR(
+ Adapter->InitBlock->LogicalAddressFilter[HashValue >> 3],
+ &RingNumber
+ );
+
+ LANCE_WRITE_HARDWARE_MEMORY_UCHAR(
+ Adapter->InitBlock->LogicalAddressFilter[HashValue >> 3],
+ RingNumber | (1 << (HashValue & 0x00000007))
+ );
+ }
+ }
+ }
+
+#if LANCE_TRACE
+ DbgPrint("out SetInitBlock\n");
+#endif
+}
+
+
+STATIC
+BOOLEAN
+ProcessReceiveInterrupts(
+ IN PLANCE_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Process the packets that have finished receiving.
+
+ NOTE: This routine assumes that no other thread of execution
+ is processing receives! THE LOCK MUST BE HELD
+
+Arguments:
+
+ Adapter - The adapter to indicate to.
+
+Return Value:
+
+ Whether to clear the interrupt or not.
+
+--*/
+
+{
+ //
+ // We don't get here unless there was a receive. Loop through
+ // the receive descriptors starting at the last known descriptor
+ // owned by the hardware that begins a packet.
+ //
+ // Examine each receive ring descriptor for errors.
+ //
+ // We keep an array whose elements are indexed by the ring
+ // index of the receive descriptors. The arrays elements are
+ // the virtual addresses of the buffers pointed to by
+ // each ring descriptor.
+ //
+ // When we have the entire packet (and error processing doesn't
+ // prevent us from indicating it), we give the routine that
+ // processes the packet through the filter, the buffers virtual
+ // address (which is always the lookahead size) and as the
+ // MAC context the index to the first and last ring descriptors
+ // comprising the packet.
+ //
+
+ //
+ // Index of the ring descriptor in the ring.
+ //
+ UINT CurrentIndex = Adapter->CurrentReceiveIndex;
+
+ //
+ // Pointer to the ring descriptor being examined.
+ //
+ PLANCE_RECEIVE_ENTRY CurrentEntry = Adapter->ReceiveRing + CurrentIndex;
+
+ //
+ // Hold in a local the top receive ring index so that we don't
+ // need to get it from the adapter all the time.
+ //
+ const UINT TopReceiveIndex = Adapter->NumberOfReceiveRings - 1;
+
+ //
+ // Boolean to record the fact that we've finished processing
+ // one packet and we're about to start a new one.
+ //
+ BOOLEAN NewPacket = FALSE;
+
+ //
+ // Count of the number of buffers in the current packet.
+ //
+ UINT NumberOfBuffers = 1;
+
+ //
+ // Pointer to host addressable space for the lookahead buffer
+ //
+ PUCHAR LookaheadBuffer;
+
+ ULONG ReceivePacketCount = 0;
+
+ for (; ; )
+ {
+ UCHAR ReceiveSummaryBits;
+
+ //
+ // Check to see whether we own the packet. If
+ // we don't then simply return to the caller.
+ //
+
+ LANCE_READ_HARDWARE_MEMORY_UCHAR(
+ CurrentEntry->ReceiveSummaryBits,
+ &ReceiveSummaryBits
+ );
+
+ if (ReceiveSummaryBits & LANCE_RECEIVE_OWNED_BY_CHIP)
+ {
+ LOG(RECEIVE);
+
+ return(TRUE);
+ }
+ else if (ReceivePacketCount > 10)
+ {
+ LOG(RECEIVE)
+
+ return(FALSE);
+ }
+ else if (ReceiveSummaryBits & LANCE_RECEIVE_ERROR_SUMMARY)
+ {
+ //
+ // We have an error in the packet. Record
+ // the details of the error.
+ //
+
+ //
+ // Synch with the set/query information routines.
+ //
+ if (ReceiveSummaryBits & LANCE_RECEIVE_BUFFER_ERROR)
+ {
+ //
+ // Probably ran out of descriptors.
+ //
+
+ Adapter->OutOfReceiveBuffers++;
+ }
+ else if (ReceiveSummaryBits & LANCE_RECEIVE_CRC_ERROR)
+ {
+ Adapter->CRCError++;
+ }
+ else if (ReceiveSummaryBits & LANCE_RECEIVE_OVERFLOW_ERROR)
+ {
+ Adapter->OutOfReceiveBuffers++;
+ }
+ else if (ReceiveSummaryBits & LANCE_RECEIVE_FRAMING_ERROR)
+ {
+ Adapter->FramingError++;
+ }
+
+ ReceivePacketCount++;
+
+ //
+ // Give the packet back to the hardware.
+ //
+
+ RelinquishReceivePacket(
+ Adapter,
+ Adapter->CurrentReceiveIndex,
+ NumberOfBuffers
+ );
+
+ NewPacket = TRUE;
+ }
+ else if (ReceiveSummaryBits & LANCE_RECEIVE_END_OF_PACKET)
+ {
+ //
+ // We've reached the end of the packet. Prepare
+ // the parameters for indication, then indicate.
+ //
+
+ UINT PacketSize;
+ UINT LookAheadSize;
+
+ LANCE_RECEIVE_CONTEXT Context;
+
+ ASSERT(sizeof(LANCE_RECEIVE_CONTEXT) == sizeof(NDIS_HANDLE));
+
+ //
+ // Check just before we do indications that we aren't
+ // resetting.
+ //
+ if (Adapter->ResetInProgress)
+ {
+ return(TRUE);
+ }
+
+ Context.INFO.IsContext = TRUE;
+ Context.INFO.FirstBuffer = Adapter->CurrentReceiveIndex;
+ Context.INFO.LastBuffer = CurrentIndex;
+
+ LANCE_GET_MESSAGE_SIZE(CurrentEntry, PacketSize);
+
+ LookAheadSize = PacketSize;
+
+ //
+ // Find amount to indicate.
+ //
+
+ LookAheadSize = ((LookAheadSize < Adapter->SizeOfReceiveBuffer) ?
+ LookAheadSize :
+ Adapter->SizeOfReceiveBuffer);
+
+ LookAheadSize -= LANCE_HEADER_SIZE;
+
+ //
+ // Increment the number of packets succesfully received.
+ //
+
+ Adapter->Receive++;
+
+ LOG(INDICATE);
+
+ Adapter->IndicatingMacReceiveContext = Context;
+
+ Adapter->IndicatedAPacket = TRUE;
+
+ NdisCreateLookaheadBufferFromSharedMemory(
+ (PVOID)(Adapter->ReceiveVAs[Adapter->CurrentReceiveIndex]),
+ LookAheadSize + LANCE_HEADER_SIZE,
+ &LookaheadBuffer
+ );
+
+ if (LookaheadBuffer != NULL)
+ {
+ if (PacketSize < LANCE_HEADER_SIZE)
+ {
+ if (PacketSize >= ETH_LENGTH_OF_ADDRESS)
+ {
+ //
+ // Runt packet
+ //
+
+ NdisMEthIndicateReceive(
+ Adapter->MiniportAdapterHandle,
+ (NDIS_HANDLE)Context.WholeThing,
+ LookaheadBuffer,
+ PacketSize,
+ NULL,
+ 0,
+ 0
+ );
+ }
+ }
+ else
+ {
+ NdisMEthIndicateReceive(
+ Adapter->MiniportAdapterHandle,
+ (NDIS_HANDLE)Context.WholeThing,
+ LookaheadBuffer,
+ LANCE_HEADER_SIZE,
+ LookaheadBuffer + LANCE_HEADER_SIZE,
+ LookAheadSize,
+ PacketSize - LANCE_HEADER_SIZE
+ );
+ }
+
+ NdisDestroyLookaheadBufferFromSharedMemory(LookaheadBuffer);
+ }
+
+ ReceivePacketCount++;
+
+ //
+ // Give the packet back to the hardware.
+ //
+
+ RelinquishReceivePacket(
+ Adapter,
+ Adapter->CurrentReceiveIndex,
+ NumberOfBuffers
+ );
+
+ NewPacket = TRUE;
+ }
+
+ //
+ // We're at some indermediate packet. Advance to
+ // the next one.
+ //
+ if (CurrentIndex == TopReceiveIndex)
+ {
+ CurrentIndex = 0;
+ CurrentEntry = Adapter->ReceiveRing;
+ }
+ else
+ {
+ CurrentIndex++;
+ CurrentEntry++;
+ }
+
+ if (NewPacket)
+ {
+ Adapter->CurrentReceiveIndex = CurrentIndex;
+ NewPacket = FALSE;
+ NumberOfBuffers = 0;
+ }
+
+ NumberOfBuffers++;
+
+ if (NumberOfBuffers > (TopReceiveIndex + 1))
+ {
+ //
+ // Error! For some reason we wrapped without ever seeing
+ // the end of packet. The card is hosed. Stop the
+ // whole process.
+ //
+
+ //
+ // There are opens to notify
+ //
+ Adapter->HardwareFailure = TRUE;
+
+ NdisMIndicateStatus(
+ Adapter->MiniportAdapterHandle,
+ NDIS_STATUS_CLOSING,
+ NULL,
+ 0
+ );
+
+ NdisMIndicateStatusComplete(Adapter->MiniportAdapterHandle);
+
+ NdisMDeregisterInterrupt(&(Adapter->Interrupt));
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 0
+ );
+
+ return(TRUE);
+ }
+ }
+}
+
+STATIC
+VOID
+RelinquishReceivePacket(
+ IN PLANCE_ADAPTER Adapter,
+ IN UINT StartingIndex,
+ IN UINT NumberOfBuffers
+ )
+
+/*++
+
+Routine Description:
+
+ Gives a range of receive descriptors back to the hardware.
+
+Arguments:
+
+ Adapter - The adapter that the ring works with.
+
+ StartingIndex - The first ring to return. Note that since
+ we are dealing with a ring, this value could be greater than
+ the EndingIndex.
+
+ NumberOfBuffers - The number of buffers (or ring descriptors) in
+ the current packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Index of the ring descriptor in the ring.
+ //
+ UINT CurrentIndex = StartingIndex;
+
+ //
+ // Pointer to the ring descriptor being returned.
+ //
+ PLANCE_RECEIVE_ENTRY CurrentEntry = Adapter->ReceiveRing + CurrentIndex;
+
+ //
+ // Hold in a local so that we don't need to access via the adapter.
+ //
+ const UINT TopReceiveIndex = Adapter->NumberOfReceiveRings - 1;
+
+ UCHAR Tmp;
+
+ LANCE_READ_HARDWARE_MEMORY_UCHAR(CurrentEntry->ReceiveSummaryBits, &Tmp);
+
+ ASSERT(!(Tmp & LANCE_RECEIVE_OWNED_BY_CHIP));
+ ASSERT(Tmp & LANCE_RECEIVE_START_OF_PACKET);
+
+ for ( ; NumberOfBuffers; NumberOfBuffers-- )
+ {
+ LANCE_WRITE_HARDWARE_MEMORY_UCHAR(
+ CurrentEntry->ReceiveSummaryBits,
+ LANCE_RECEIVE_OWNED_BY_CHIP
+ );
+
+ if (CurrentIndex == TopReceiveIndex)
+ {
+ CurrentEntry = Adapter->ReceiveRing;
+ CurrentIndex = 0;
+ }
+ else
+ {
+ CurrentEntry++;
+ CurrentIndex++;
+ }
+ }
+}
+
+STATIC
+BOOLEAN
+ProcessTransmitInterrupts(
+ IN PLANCE_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Process the packets that have finished transmitting.
+
+ NOTE: This routine assumes that it is being executed in a
+ single thread of execution. CALLED WITH LOCK HELD!!!
+
+Arguments:
+
+ Adapter - The adapter that was sent from.
+
+Return Value:
+
+ This function will return TRUE if it finished up the
+ send on a packet. It will return FALSE if for some
+ reason there was no packet to process.
+
+--*/
+
+{
+ //
+ // Index into the ring to packet structure. This index points
+ // to the first ring entry for the first buffer used for transmitting
+ // the packet.
+ //
+ UINT FirstIndex;
+
+ //
+ // Pointer to the last ring entry for the packet to be transmitted.
+ // This pointer might actually point to a ring entry before the first
+ // ring entry for the packet since the ring structure is, simply, a ring.
+ //
+ PLANCE_TRANSMIT_ENTRY LastRingEntry;
+
+ //
+ // Pointer to the packet that started this transmission.
+ //
+ PNDIS_PACKET OwningPacket;
+
+ UCHAR TransmitSummaryBits;
+ USHORT ErrorSummaryInfo;
+
+ //
+ // Used to hold the ring to packet mapping information so that
+ // we can release the ring entries as quickly as possible.
+ //
+ LANCE_RING_TO_PACKET SavedRingMapping;
+
+
+ //
+ // Get hold of the first transmitted packet.
+ //
+
+ //
+ // First we check that this is a packet that was transmitted
+ // but not already processed. Recall that this routine
+ // will be called repeatedly until this tests false, Or we
+ // hit a packet that we don't completely own.
+ //
+
+ //
+ // NOTE: I found a problem where FirstUncommitedRing wraps around
+ // and becomes equal to TransmittingRing. This only happens when
+ // NumberOfAvailableRings is 0 (JohnsonA)
+ //
+
+ if ((Adapter->TransmittingRing == Adapter->FirstUncommittedRing) &&
+ (Adapter->NumberOfAvailableRings > 0)
+ )
+ {
+ return(FALSE);
+ }
+ else
+ {
+ FirstIndex = Adapter->TransmittingRing - Adapter->TransmitRing;
+ }
+
+
+ //
+ // We put the mapping into a local variable so that we
+ // can return the mapping as soon as possible.
+ //
+
+ SavedRingMapping = Adapter->RingToPacket[FirstIndex];
+
+ //
+ // Get a pointer to the last ring entry for this packet.
+ //
+
+ LastRingEntry = Adapter->TransmitRing + SavedRingMapping.RingIndex;
+
+ //
+ // Get a pointer to the owning packet .
+ //
+ OwningPacket = SavedRingMapping.OwningPacket;
+
+ SavedRingMapping.OwningPacket = NULL;
+
+ if (OwningPacket == NULL)
+ {
+ //
+ // We seem to be in a messed up state. Ignore this interrupt and
+ // the wake up dpc will reset the card if necessary.
+ //
+
+ ASSERT(OwningPacket != NULL);
+ return(FALSE);
+ }
+
+ //
+ // Check that the host does indeed own this entire packet.
+ //
+
+ LANCE_READ_HARDWARE_MEMORY_UCHAR(
+ LastRingEntry->TransmitSummaryBits,
+ &TransmitSummaryBits
+ );
+
+ if (TransmitSummaryBits & LANCE_TRANSMIT_OWNED_BY_CHIP)
+ {
+ //
+ // We don't own this last packet. We return FALSE to indicate
+ // that we don't have any more packets to work on.
+ //
+ return(FALSE);
+ }
+ else
+ {
+ //
+ // Pointer to the current ring descriptor being examine for errors
+ // and the statistics accumulated during its transmission.
+ //
+ PLANCE_TRANSMIT_ENTRY CurrentRingEntry;
+
+ //
+ // Holds whether the packet successfully transmitted or not.
+ //
+ BOOLEAN Successful = TRUE;
+ PLANCE_BUFFER_DESCRIPTOR BufferDescriptor = Adapter->LanceBuffers +
+ SavedRingMapping.LanceBuffersIndex;
+ INT ListHeadIndex = BufferDescriptor->Next;
+
+ LOG(TRANSMIT_COMPLETE);
+
+ CurrentRingEntry = Adapter->TransmitRing + FirstIndex;
+
+ //
+ // now return these buffers to the adapter.
+ //
+
+ BufferDescriptor->Next = Adapter->LanceBufferListHeads[ListHeadIndex];
+ Adapter->LanceBufferListHeads[ListHeadIndex] = SavedRingMapping.LanceBuffersIndex;
+
+ //
+ // Since the host owns the entire packet check the ring
+ // entries from first to last for any errors in transmission.
+ // Any errors found or multiple tries should be recorded in
+ // the information structure for the adapter.
+ //
+ // We treat Late Collisions as success since the packet was
+ // fully transmitted and may have been received.
+ //
+ for (;;)
+ {
+ LANCE_READ_HARDWARE_MEMORY_UCHAR(
+ CurrentRingEntry->TransmitSummaryBits,
+ &TransmitSummaryBits
+ );
+
+ LANCE_READ_HARDWARE_MEMORY_USHORT(
+ CurrentRingEntry->ErrorSummaryInfo,
+ &ErrorSummaryInfo
+ );
+
+ if ((TransmitSummaryBits & LANCE_TRANSMIT_ANY_ERRORS) &&
+ !(ErrorSummaryInfo & LANCE_TRANSMIT_LATE_COLLISION)
+ )
+ {
+ if (ErrorSummaryInfo & LANCE_TRANSMIT_RETRY)
+ {
+ Adapter->RetryFailure++;
+ }
+ else if (ErrorSummaryInfo & LANCE_TRANSMIT_LOST_CARRIER)
+ {
+ Adapter->LostCarrier++;
+ }
+ else if (ErrorSummaryInfo & LANCE_TRANSMIT_UNDERFLOW)
+ {
+ Adapter->UnderFlow++;
+ }
+
+#if DBG
+ LanceSendFails[LanceSendFailPlace] = (UCHAR)(ErrorSummaryInfo);
+ LanceSendFailPlace++;
+#endif
+
+#if LANCE_TRACE
+ DbgPrint("Unsuccessful Transmit 0x%x\n", ErrorSummaryInfo);
+#endif
+
+ Successful = FALSE;
+
+ //
+ // Move the pointer to transmitting but unprocessed
+ // ring entries to after this packet, and recover
+ // the remaining now available ring entries.
+ //
+
+ Adapter->NumberOfAvailableRings +=
+ (CurrentRingEntry <= LastRingEntry)?
+ ((LastRingEntry - CurrentRingEntry)+1):
+ ((Adapter->LastTransmitRingEntry - CurrentRingEntry) +
+ (LastRingEntry-Adapter->TransmitRing) + 2);
+
+ if (LastRingEntry == Adapter->LastTransmitRingEntry)
+ {
+ Adapter->TransmittingRing = Adapter->TransmitRing;
+ }
+ else
+ {
+ Adapter->TransmittingRing = LastRingEntry + 1;
+ }
+
+ break;
+ }
+ else
+ {
+ //
+ // Logical variable that records whether this
+ // is the last packet.
+ //
+
+ BOOLEAN DoneWithPacket = TransmitSummaryBits & LANCE_TRANSMIT_END_OF_PACKET;
+
+ if (ErrorSummaryInfo & LANCE_TRANSMIT_LATE_COLLISION)
+ {
+ Adapter->LateCollision++;
+ }
+
+ if (TransmitSummaryBits & LANCE_TRANSMIT_START_OF_PACKET)
+ {
+ //
+ // Collect some statistics on how many tries were needed.
+ //
+ if (TransmitSummaryBits & LANCE_TRANSMIT_DEFERRED)
+ {
+ Adapter->Deferred++;
+ }
+ else if (TransmitSummaryBits & LANCE_TRANSMIT_ONE_RETRY)
+ {
+ Adapter->OneRetry++;
+ }
+ else if (TransmitSummaryBits & LANCE_TRANSMIT_MORE_THAN_ONE_RETRY)
+ {
+ Adapter->MoreThanOneRetry++;
+ }
+ }
+
+ if (CurrentRingEntry == Adapter->LastTransmitRingEntry)
+ {
+ CurrentRingEntry = Adapter->TransmitRing;
+ }
+ else
+ {
+ CurrentRingEntry++;
+ }
+
+ Adapter->TransmittingRing = CurrentRingEntry;
+ Adapter->NumberOfAvailableRings++;
+
+ if (DoneWithPacket)
+ {
+ break;
+ }
+ }
+ }
+
+ //
+ // Store result
+ //
+ if (Successful)
+ {
+ //
+ // Increment number of packets successfully sent.
+ //
+ Adapter->Transmit++;
+ }
+
+ NdisMSendResourcesAvailable(Adapter->MiniportAdapterHandle);
+
+ return(TRUE);
+ }
+}
+
+STATIC
+VOID
+StartAdapterReset(
+ IN PLANCE_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This is the first phase of resetting the adapter hardware.
+
+ It makes the following assumptions:
+
+ 1) That the hardware has been stopped.
+
+ 2) That it can not be preempted.
+
+ 3) That no other adapter activity can occur.
+
+ When this routine is finished all of the adapter information
+ will be as if the driver was just initialized.
+
+Arguments:
+
+ Adapter - The adapter whose hardware is to be reset.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UINT i;
+
+#if LANCE_TRACE
+ DbgPrint("In StartAdapterReset\n");
+#endif
+
+ LOG(RESET_STEP_2);
+
+ Adapter->NumberOfAvailableRings = Adapter->NumberOfTransmitRings;
+ Adapter->AllocateableRing = Adapter->TransmitRing;
+ Adapter->TransmittingRing = Adapter->TransmitRing;
+ Adapter->FirstUncommittedRing = Adapter->TransmitRing;
+
+ Adapter->CurrentReceiveIndex = 0;
+
+ //
+ // Clean all of the receive ring entries.
+ //
+ {
+
+ PLANCE_RECEIVE_ENTRY CurrentReceive = Adapter->ReceiveRing;
+ const PLANCE_RECEIVE_ENTRY After = Adapter->ReceiveRing +
+ Adapter->NumberOfReceiveRings;
+
+ do
+ {
+ LANCE_WRITE_HARDWARE_MEMORY_UCHAR(
+ CurrentReceive->ReceiveSummaryBits,
+ LANCE_RECEIVE_OWNED_BY_CHIP
+ );
+
+ CurrentReceive++;
+
+ } while (CurrentReceive != After);
+ }
+
+
+ //
+ // Clean all of the transmit ring entries.
+ //
+
+ {
+ PLANCE_TRANSMIT_ENTRY CurrentTransmit = Adapter->TransmitRing;
+ const PLANCE_TRANSMIT_ENTRY After = Adapter->TransmitRing+
+ Adapter->NumberOfTransmitRings;
+
+ do
+ {
+ LANCE_WRITE_HARDWARE_MEMORY_UCHAR(
+ CurrentTransmit->TransmitSummaryBits,
+ 0x00
+ );
+
+ CurrentTransmit++;
+ } while (CurrentTransmit != After);
+ }
+
+ //
+ // Recover all of the adapter buffers.
+ //
+
+ for (i = 0;
+ i < (Adapter->NumberOfSmallBuffers +
+ Adapter->NumberOfMediumBuffers +
+ Adapter->NumberOfLargeBuffers);
+ i++
+ )
+ {
+ Adapter->LanceBuffers[i].Next = i+1;
+ }
+
+ Adapter->LanceBufferListHeads[0] = -1;
+ Adapter->LanceBufferListHeads[1] = 0;
+ Adapter->LanceBuffers[(Adapter->NumberOfSmallBuffers)-1].Next = -1;
+ Adapter->LanceBufferListHeads[2] = Adapter->NumberOfSmallBuffers;
+ Adapter->LanceBuffers[(Adapter->NumberOfSmallBuffers +
+ Adapter->NumberOfMediumBuffers)-1].Next = -1;
+ Adapter->LanceBufferListHeads[3] = Adapter->NumberOfSmallBuffers +
+ Adapter->NumberOfMediumBuffers;
+ Adapter->LanceBuffers[(Adapter->NumberOfSmallBuffers+
+ Adapter->NumberOfMediumBuffers+
+ Adapter->NumberOfLargeBuffers)-1].Next = -1;
+
+ SetInitBlockAndInit(Adapter);
+
+#if LANCE_TRACE
+ DbgPrint("Out StartAdapterReset\n");
+#endif
+
+}
+
+STATIC
+VOID
+SetInitBlockAndInit(
+ IN PLANCE_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ It is this routines responsibility to make sure that the
+ initialization block is filled and the chip is initialized
+ *but not* started.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired OR that only a single thread of execution is working
+ with this particular adapter.
+
+Arguments:
+
+ Adapter - The adapter whose hardware is to be initialized.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ ULONG PhysAdr;
+
+ //
+ // Fill in the adapters initialization block.
+ //
+ LanceSetInitializationBlock(Adapter);
+
+ PhysAdr = LANCE_GET_HARDWARE_PHYSICAL_ADDRESS(Adapter,Adapter->InitBlock);
+
+ //
+ // Make sure that it does have even byte alignment.
+ //
+ ASSERT((PhysAdr & 0x01)==0);
+
+ //
+ // Write the address of the initialization block to csr1 and csr2.
+ //
+ LANCE_WRITE_RAP(Adapter, LANCE_SELECT_CSR1);
+ LANCE_WRITE_RDP(Adapter, LANCE_GET_LOW_PART_ADDRESS(PhysAdr));
+ LANCE_WRITE_RAP(Adapter, LANCE_SELECT_CSR2);
+ LANCE_WRITE_RDP(Adapter, LANCE_GET_HIGH_PART_ADDRESS(PhysAdr));
+
+ //
+ // Write to csr0 to initialize the chip.
+ //
+ LANCE_WRITE_RAP(Adapter, LANCE_SELECT_CSR0);
+ LANCE_WRITE_RDP(Adapter, LANCE_CSR0_INIT_CHIP);
+
+ //
+ // Delay execution for 1/2 second to give the lance
+ // time to initialize.
+ //
+ NdisStallExecution( 500000 );
+}
+
+STATIC
+VOID
+SetupForReset(
+ IN PLANCE_ADAPTER Adapter,
+ IN NDIS_REQUEST_TYPE NdisRequestType
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to fill in the who and why a reset is
+ being set up as well as setting the appropriate fields in the
+ adapter.
+
+ NOTE: This routine must be called with the lock acquired.
+
+Arguments:
+
+ Adapter - The adapter whose hardware is to be initialized.
+
+ NdisRequestType - The reason for the reset.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+#if LANCE_TRACE
+ DbgPrint("In SetupForReset\n");
+#endif
+
+ LOG(RESET_STEP_1);
+
+ //
+ // Shut down the chip. We won't be doing any more work until
+ // the reset is complete.
+ //
+ NdisMSynchronizeWithInterrupt(
+ &Adapter->Interrupt,
+ LanceSyncStopChip,
+ (PVOID)Adapter
+ );
+
+ //
+ // Once the chip is stopped we can't get any more interrupts.
+ // Any interrupts that are "queued" for processing could
+ // only possibly service this reset. It is therefore safe for
+ // us to clear the adapter global csr value.
+ //
+ Adapter->ResetInProgress = TRUE;
+ Adapter->ResetInitStarted = FALSE;
+
+ //
+ // Shut down all of the transmit queues so that the
+ // transmit portion of the chip will eventually calm down.
+ //
+ Adapter->ResetRequestType = NdisRequestType;
+
+#if LANCE_TRACE
+ DbgPrint("Out SetupForReset\n");
+#endif
+}
+
+
+STATIC
+BOOLEAN
+LanceSyncWriteNicsr(
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ This routine is used by the normal interrupt processing routine
+ to synchronize with interrupts from the card. It will
+ Write to the NIC Status Register.
+
+Arguments:
+
+ Context - This is really a pointer to a record type peculiar
+ to this routine. The record contains a pointer to the adapter
+ and a pointer to an address which holds the value to write.
+
+Return Value:
+
+ Always returns false.
+
+--*/
+
+{
+
+ PLANCE_SYNCH_CONTEXT C = Context;
+
+ LANCE_ISR_WRITE_NICSR(C->Adapter, C->LocalWrite);
+
+ return FALSE;
+
+}
+
+STATIC
+BOOLEAN
+LanceSyncStopChip(
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to stop a lance.
+
+
+
+Arguments:
+
+ Adapter - The adapter for the LANCE to stop.
+
+Return Value:
+
+ FALSE
+
+--*/
+
+{
+
+ PLANCE_ADAPTER Adapter = (PLANCE_ADAPTER)Context;
+
+ //
+ // Set the RAP to csr0.
+ //
+ LANCE_ISR_WRITE_RAP(Adapter, LANCE_SELECT_CSR0);
+
+ //
+ // Set the RDP to stop chip.
+ //
+ LANCE_ISR_WRITE_RDP(Adapter, LANCE_CSR0_STOP);
+
+ if (Adapter->LanceCard & (LANCE_DE201 | LANCE_DE100 | LANCE_DE422))
+ {
+ //
+ // Always reset the ACON bit after a stop.
+ //
+ LANCE_ISR_WRITE_RAP(Adapter, LANCE_SELECT_CSR3);
+
+ LANCE_ISR_WRITE_RDP(Adapter, LANCE_CSR3_ACON);
+ }
+
+ //
+ // Select CSR0 again.
+ //
+ LANCE_ISR_WRITE_RAP(Adapter, LANCE_SELECT_CSR0);
+
+ return(FALSE);
+}
+
+
+
diff --git a/private/ntos/ndis/lance/lance.rc b/private/ntos/ndis/lance/lance.rc
new file mode 100644
index 000000000..8cf50295c
--- /dev/null
+++ b/private/ntos/ndis/lance/lance.rc
@@ -0,0 +1,39 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "DEC Etherworks network driver"
+#define VER_INTERNALNAME_STR "LANCE.SYS"
+#define VER_ORIGINALFILENAME_STR "LANCE.SYS"
+
+#include "common.ver"
+
diff --git a/private/ntos/ndis/lance/lancehrd.h b/private/ntos/ndis/lance/lancehrd.h
new file mode 100644
index 000000000..1a9f3c48e
--- /dev/null
+++ b/private/ntos/ndis/lance/lancehrd.h
@@ -0,0 +1,479 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ lance.c
+
+Abstract:
+
+ The main program for a LANCE (Local Area Network Controller
+ Am 7990) MAC driver.
+
+Author:
+
+ Anthony V. Ercolano (tonye) creation-date 19-Jun-1990
+
+Environment:
+
+ This driver is expected to work in DOS, OS2 and NT at the equivalent
+ of kernal mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+ 31-Jul-1992 R.D. Lanser:
+ Removed system implementation dependent defines for the DEC
+ TurboChannel option PMAD-AA (Lance ethernet).
+
+--*/
+
+#ifndef _LANCEHARDWARE_
+#define _LANCEHARDWARE_
+
+//
+// Compressed ID for DE422 EISA adapter
+//
+
+#define DE422_COMPRESSED_ID 0x2042a310
+
+//
+// All registers on the LANCE are 16 bits.
+//
+
+#define LANCE_SELECT_CSR0 ((USHORT)0)
+#define LANCE_SELECT_CSR1 ((USHORT)1)
+#define LANCE_SELECT_CSR2 ((USHORT)2)
+#define LANCE_SELECT_CSR3 ((USHORT)3)
+
+#define LANCE_CSR0_INITIALIZE ((USHORT)(0x0001))
+#define LANCE_CSR0_START ((USHORT)(0x0002))
+#define LANCE_CSR0_STOP ((USHORT)(0x0004))
+#define LANCE_CSR0_TRANSMIT_DEMAND ((USHORT)(0x0008))
+#define LANCE_CSR0_TRANSMITTER_ON ((USHORT)(0x0010))
+#define LANCE_CSR0_RECEIVER_ON ((USHORT)(0x0020))
+#define LANCE_CSR0_INTERRUPT_ENABLE ((USHORT)(0x0040))
+#define LANCE_CSR0_INTERRUPT_FLAG ((USHORT)(0x0080))
+#define LANCE_CSR0_INITIALIZATION_DONE ((USHORT)(0x0100))
+#define LANCE_CSR0_TRANSMITTER_INTERRUPT ((USHORT)(0x0200))
+#define LANCE_CSR0_RECEIVER_INTERRUPT ((USHORT)(0x0400))
+#define LANCE_CSR0_MEMORY_ERROR ((USHORT)(0x0800))
+#define LANCE_CSR0_MISSED_PACKET ((USHORT)(0x1000))
+#define LANCE_CSR0_COLLISION_ERROR ((USHORT)(0x2000))
+#define LANCE_CSR0_BABBLE ((USHORT)(0x4000))
+#define LANCE_CSR0_ERROR_SUMMARY ((USHORT)(0x8000))
+#define LANCE_CSR0_ERROR_BITS ((USHORT)(0xf800))
+
+
+//
+// We define a constant csr3 value that is useful for setting the ACON
+// bit in csr3.
+//
+#define LANCE_CSR3_ACON ((USHORT)0x02)
+
+
+#define LANCE_NICSR_LED_ON ((USHORT)(0x0001))
+#define LANCE_NICSR_INT_ON ((USHORT)(0x0002))
+#define LANCE_NICSR_IMASK ((USHORT)(0x0004))
+#define LANCE_NICSR_128K ((USHORT)(0x0008))
+#define LANCE_NICSR_BUFFER_SIZE ((USHORT)(0x0020))
+
+
+//
+// Definitions for the many different lance card types.
+//
+
+#define LANCE_DEPCA_INTERRUPT_VECTOR 5
+#define LANCE_DEPCA_INTERRUPT_IRQL 5
+
+#define LANCE_DE201_INTERRUPT_VECTOR ((CCHAR)5)
+#define LANCE_DE201_INTERRUPT_IRQL LANCE_DE201_INTERRUPT_VECTOR
+
+#define LANCE_DE100_INTERRUPT_VECTOR ((CCHAR)3)
+#define LANCE_DE100_INTERRUPT_IRQL LANCE_DE100_INTERRUPT_VECTOR
+
+
+
+
+#define LANCE_DEPCA_HARDWARE_MEMORY (0x10000) // 64K
+#define LANCE_DEPCA_NICSR_ADDRESS ((ULONG)(0x200))
+#define LANCE_DEPCA_BASE ((PVOID)(0xD0000))
+#define LANCE_DEPCA_RAP_OFFSET ((ULONG)(0x006))
+#define LANCE_DEPCA_RDP_OFFSET ((ULONG)(0x004))
+#define LANCE_DEPCA_EPROM_OFFSET ((ULONG)(0x00c))
+#define LANCE_DEPCA_LAN_CFG_OFFSET ((ULONG)(0x600))
+
+#define LANCE_DE201_HARDWARE_MEMORY (0x10000) // 64K
+#define LANCE_DE201_BASE ((PVOID)(0xD0000))
+
+#define LANCE_DE201_PRI_NICSR_ADDRESS ((ULONG)(0x300))
+#define LANCE_DE201_SEC_NICSR_ADDRESS ((ULONG)(0x200))
+#define LANCE_DE201_RAP_OFFSET ((ULONG)(0x006))
+#define LANCE_DE201_RDP_OFFSET ((ULONG)(0x004))
+#define LANCE_DE201_NETWORK_OFFSET ((ULONG)(0x00C))
+
+#define LANCE_DE422_NICSR_ADDRESS ((ULONG)(0xC00))
+#define LANCE_DE422_RAP_OFFSET ((ULONG)(0x006))
+#define LANCE_DE422_RDP_OFFSET ((ULONG)(0x004))
+#define LANCE_DE422_NETWORK_OFFSET ((ULONG)(0x00C))
+#define LANCE_DE422_EISA_CONFIGURATION_OFFSET ((ULONG)(0x00C))
+#define LANCE_DE422_EXTENDED_MEMORY_BASE_OFFSET ((ULONG)(0x008))
+#define LANCE_DE422_EISA_IDENTIFICATION_OFFSET ((ULONG)(0x080))
+#define LANCE_DE422_EISA_CONTROL_OFFSET ((ULONG)(0x084))
+
+
+
+
+
+#define LANCE_NUMBER_OF_TRANSMIT_RINGS ((UINT)64)
+#define LANCE_LOG_TRANSMIT_RINGS ((UINT)6)
+
+#define LANCE_128K_NUMBER_OF_RECEIVE_RINGS ((UINT)128)
+#define LANCE_128K_LOG_RECEIVE_RINGS ((UINT)7)
+
+#define LANCE_64K_NUMBER_OF_RECEIVE_RINGS ((UINT)128)
+#define LANCE_64K_LOG_RECEIVE_RINGS ((UINT)7)
+
+#define LANCE_32K_NUMBER_OF_RECEIVE_RINGS ((UINT)32)
+#define LANCE_32K_LOG_RECEIVE_RINGS ((UINT)5)
+
+#define LANCE_32K_SIZE_OF_RECEIVE_BUFFERS ((UINT)256)
+#define LANCE_64K_SIZE_OF_RECEIVE_BUFFERS ((UINT)256)
+#define LANCE_128K_SIZE_OF_RECEIVE_BUFFERS ((UINT)512)
+
+//
+// Note: The value of LANCE_SIZE_OF_RECEIVE_BUFFERS should always be the
+// largest of the receive buffers sizes. At this time, it is 512
+// for the DEC TurboChannel card. If this size changes, recompile
+// loopback.c.
+//
+#define LANCE_SIZE_OF_RECEIVE_BUFFERS ((UINT)256)
+#ifndef i386
+#define LANCE_LOOPBACK_SIZE_OF_RECEIVE_BUFFERS ((UINT)512)
+#else
+#define LANCE_LOOPBACK_SIZE_OF_RECEIVE_BUFFERS LANCE_SIZE_OF_RECEIVE_BUFFERS
+#endif
+
+
+#define LANCE_SMALL_BUFFER_SIZE ((UINT)64)
+#define LANCE_MEDIUM_BUFFER_SIZE ((UINT)256)
+#define LANCE_LARGE_BUFFER_SIZE ((UINT)1514)
+
+#define LANCE_128K_NUMBER_OF_SMALL_BUFFERS ((UINT)100)
+#define LANCE_128K_NUMBER_OF_MEDIUM_BUFFERS ((UINT)50)
+#define LANCE_128K_NUMBER_OF_LARGE_BUFFERS ((UINT)20)
+
+#define LANCE_64K_NUMBER_OF_SMALL_BUFFERS ((UINT)10)
+#define LANCE_64K_NUMBER_OF_MEDIUM_BUFFERS ((UINT)10)
+#define LANCE_64K_NUMBER_OF_LARGE_BUFFERS ((UINT)4)
+
+#define LANCE_32K_NUMBER_OF_SMALL_BUFFERS ((UINT)10)
+#define LANCE_32K_NUMBER_OF_MEDIUM_BUFFERS ((UINT)10)
+#define LANCE_32K_NUMBER_OF_LARGE_BUFFERS ((UINT)2)
+
+
+#define LANCE_ISR_WRITE_RAP(A,C) NdisRawWritePortUshort((ULONG)((A)->RAP),C)
+#define LANCE_ISR_READ_RDP(A,C) NdisRawReadPortUshort((ULONG)((A)->RDP),C)
+#define LANCE_ISR_WRITE_RDP(A,C) NdisRawWritePortUshort((ULONG)((A)->RDP),C)
+#define LANCE_ISR_WRITE_NICSR(A,C) NdisRawWritePortUshort((ULONG)((A)->Nicsr),C)
+
+
+#define LANCE_GET_LOW_PART_ADDRESS(Adr) \
+ ((USHORT)((Adr) & 0xffff))
+
+#define LANCE_GET_HIGH_PART_ADDRESS(Adr) \
+ ((UCHAR)((Adr) & 0xff0000) >> 16)
+
+typedef struct _LANCE_INITIALIZATION_BLOCK {
+
+ USHORT ModeRegister;
+ UCHAR PhysicalAddress[6];
+ UCHAR LogicalAddressFilter[8];
+ USHORT LowReceiveRingAddress;
+ UCHAR HighReceiveRingAddress;
+ UCHAR ReceiveLengthLow5BitsReserved;
+ USHORT LowTransmitRingAddress;
+ UCHAR HighTransmitRingAddress;
+ UCHAR TransmitLengthLow5BitsReserved;
+
+} LANCE_INITIALIZATION_BLOCK,*PLANCE_INITIALIZATION_BLOCK;
+
+//
+// Define masks to access bits in the mode register of the initialization
+// block.
+//
+#define LANCE_MODE_PROMISCUOUS ((USHORT)(0x8000))
+
+//
+// Defines for moving to/from shared memory.
+//
+
+
+#define LANCE_ZERO_MEMORY_FOR_HARDWARE(Destination,Length) \
+ NdisZeroMappedMemory(Destination,Length)
+
+#define LANCE_MOVE_STRUCT_TO_HARDWARE(Destination,Source) \
+ NdisMoveToMappedMemory(&(Destination), &(Source), sizeof(Source))
+
+#define LANCE_MOVE_MEMORY_TO_HARDWARE(Destination,Source,Length) \
+ NdisMoveToMappedMemory(Destination, Source, Length)
+
+#define LANCE_MOVE_HARDWARE_TO_MEMORY(Destination,Source,Length) \
+ NdisMoveFromMappedMemory(Destination, Source, Length)
+
+#define LANCE_WRITE_HARDWARE_LOW_PART_ADDRESS(Destination, Source) \
+ NdisWriteRegisterUshort((PUSHORT)(&Destination), (USHORT)(Source))
+
+#define LANCE_WRITE_HARDWARE_HIGH_PART_ADDRESS(Destination, Source) \
+ NdisWriteRegisterUchar((PUCHAR)(&Destination), (UCHAR)(Source))
+
+#define LANCE_WRITE_HARDWARE_MEMORY_UCHAR(Destination, Source) \
+ NdisWriteRegisterUchar((PUCHAR)(&Destination), (UCHAR)(Source))
+
+#define LANCE_WRITE_HARDWARE_MEMORY_USHORT(Destination, Source) \
+ NdisWriteRegisterUshort((PUSHORT)(&Destination), (USHORT)(Source))
+
+#define LANCE_READ_HARDWARE_MEMORY_UCHAR(Source, Destination) \
+ NdisReadRegisterUchar((PUCHAR)(&Source), Destination)
+
+#define LANCE_READ_HARDWARE_MEMORY_USHORT(Source, Destination) \
+ NdisReadRegisterUshort((PUSHORT)(&Source), Destination)
+
+#if defined(_ALPHA_)
+
+#define LANCE_SET_RING_BITS(Destination, Data) \
+{ \
+ UCHAR Tmp; \
+ LANCE_READ_HARDWARE_MEMORY_UCHAR(Destination, &Tmp); \
+ LANCE_WRITE_HARDWARE_MEMORY_UCHAR(Destination, Tmp | Data); \
+}
+
+#else
+
+#define LANCE_SET_RING_BITS(Destination, Data) (Destination) |= ((Data))
+
+#endif // _ALPHA_
+
+typedef struct _LANCE_RECEIVE_ENTRY {
+
+ //
+ // 24 bit pointer to the buffer for the receive
+ // data. This is written by the host and unchanged
+ // by the LANCE.
+ //
+ USHORT LowReceiveBufferAddress;
+ UCHAR HighReceiveBufferAddress;
+
+ //
+ // This char field contains numerous bits describing
+ // the errors that can occur in the packet as well as
+ // whether this is the first and/or last buffer in the packet.
+ //
+ UCHAR ReceiveSummaryBits;
+
+ //
+ // This is the twos compliment of the buffer length.
+ //
+ // NOTE: The high order 4 bits must be enabled.
+ //
+ USHORT BufferByteCount;
+
+ //
+ // This is the length of the data in the packet.
+ //
+ // Note that the high order 4 bits are undefined.
+ //
+ USHORT MessageLength;
+
+} LANCE_RECEIVE_ENTRY,*PLANCE_RECEIVE_ENTRY;
+
+//
+// A number of macros that make accessing the various bits of the receive
+// ring entry a little easier as well as providing some validity checks.
+//
+
+//
+// Used to set the address of the receive buffer.
+//
+// Rd is a pointer to a receive descriptor.
+//
+// Adr is a *physical* address.
+//
+//
+#define LANCE_SET_RECEIVE_BUFFER_ADDRESS(Adptr,Rd,Adr) \
+{ \
+ PVOID _Adr = (Adr); \
+ PLANCE_ADAPTER _Adptr = (Adptr);\
+ PLANCE_RECEIVE_ENTRY _Rd = (Rd); \
+ ULONG _Offset;\
+ _Offset = (ULONG)_Adr - (ULONG)(_Adptr->MmMappedBaseAddr);\
+ _Offset = _Offset + (ULONG)(_Adptr->HardwareBaseOffset);\
+ LANCE_WRITE_HARDWARE_LOW_PART_ADDRESS(\
+ _Rd->LowReceiveBufferAddress,\
+ (USHORT)((ULONG)_Offset) & 0xffff); \
+ LANCE_WRITE_HARDWARE_HIGH_PART_ADDRESS(\
+ _Rd->HighReceiveBufferAddress,\
+ (UCHAR)(((ULONG)_Offset) >> 16) & 0xff); \
+}
+
+
+//
+// Used to set the length of the receive buffer. The stored value
+// is actually the twos compliment of the length. Note that
+// the twos complement of this value must have the high order 4 bits
+// enabled.
+//
+// Rd is a pointer to a receive descriptor.
+//
+// Len is the unsigned short length of the buffer.
+//
+#define LANCE_SET_RECEIVE_BUFFER_LENGTH(Rd,Len) \
+ LANCE_WRITE_HARDWARE_MEMORY_USHORT(\
+ Rd->BufferByteCount,\
+ (USHORT)((~Len)+1)\
+ )
+
+//
+// Masks for the summary bits in the receive descriptor.
+//
+#define LANCE_RECEIVE_END_OF_PACKET ((UCHAR)0x01)
+#define LANCE_RECEIVE_START_OF_PACKET ((UCHAR)0x02)
+#define LANCE_RECEIVE_BUFFER_ERROR ((UCHAR)0x04)
+#define LANCE_RECEIVE_CRC_ERROR ((UCHAR)0x08)
+#define LANCE_RECEIVE_OVERFLOW_ERROR ((UCHAR)0x10)
+#define LANCE_RECEIVE_FRAMING_ERROR ((UCHAR)0x20)
+#define LANCE_RECEIVE_ERROR_SUMMARY ((UCHAR)0x40)
+#define LANCE_RECEIVE_OWNED_BY_CHIP ((UCHAR)0x80)
+
+//
+// This macro gets the packet message length from what is
+// assumed to be the last buffer in a packet. Note that
+// on the lance the length of the data includes the four
+// byte CRC so we must subtract four from length in the
+// ring entry.
+//
+// Rd is a pointer to a receive descriptor.
+// Value is the place to store the result.
+//
+#if defined(_ALPHA_)
+
+#define LANCE_GET_MESSAGE_SIZE(Rd, Value) \
+{ \
+ NdisReadRegisterUshort( \
+ ((ULONG)Rd + FIELD_OFFSET(LANCE_RECEIVE_ENTRY, MessageLength)), \
+ &Value \
+ ); \
+ Value = (Value & ((USHORT)0x0fff)) -4; \
+}
+
+
+#else
+
+#define LANCE_GET_MESSAGE_SIZE(Rd, Value) \
+ Value = (((Rd->MessageLength) & ((USHORT)0x0fff))-4)
+
+#endif // _ALPHA_
+
+typedef struct _LANCE_TRANSMIT_ENTRY {
+
+ //
+ // 24 bit pointer to the transmit buffer. This is
+ // written by the host and unchanged by the LANCE.
+ //
+ USHORT LowTransmitBufferAddress;
+ UCHAR HighTransmitBufferAddress;
+
+ //
+ // This field contains summary information about the packet.
+ //
+ UCHAR TransmitSummaryBits;
+
+ //
+ // This field contains the "twos complement" of the length
+ // of the buffer.
+ //
+ // NOTE: The high order four bits must be enabled.
+ //
+ USHORT BufferByteCount;
+
+ //
+ // This short contains the error summary information for the
+ // ring entry.
+ //
+ USHORT ErrorSummaryInfo;
+
+} LANCE_TRANSMIT_ENTRY,*PLANCE_TRANSMIT_ENTRY;
+
+//
+// Masks for the normal summary bits in the transmit descriptor.
+//
+#define LANCE_TRANSMIT_END_OF_PACKET ((UCHAR)(0x01))
+#define LANCE_TRANSMIT_START_OF_PACKET ((UCHAR)(0x02))
+#define LANCE_TRANSMIT_DEFERRED ((UCHAR)(0x04))
+#define LANCE_TRANSMIT_ONE_RETRY ((UCHAR)(0x08))
+#define LANCE_TRANSMIT_MORE_THAN_ONE_RETRY ((UCHAR)(0x10))
+#define LANCE_TRANSMIT_ANY_ERRORS ((UCHAR)(0x40))
+#define LANCE_TRANSMIT_OWNED_BY_CHIP ((UCHAR)(0x80))
+
+//
+// Set of masks to recover particular errors that a transmit can encounter.
+//
+#define LANCE_TRANSMIT_TDR ((USHORT)(0x03ff))
+#define LANCE_TRANSMIT_RETRY ((USHORT)(0x0400))
+#define LANCE_TRANSMIT_LOST_CARRIER ((USHORT)(0x0800))
+#define LANCE_TRANSMIT_LATE_COLLISION ((USHORT)(0x0100))
+#define LANCE_TRANSMIT_UNDERFLOW ((USHORT)(0x4000))
+#define LANCE_TRANSMIT_BUFFER ((USHORT)(0x8000))
+
+//
+// Used to set the address of the transmit buffer.
+//
+// Rd is a pointer to a transmit descriptor.
+//
+// Adr is a *physical* address.
+//
+//
+
+#define LANCE_SET_TRANSMIT_BUFFER_ADDRESS(Adptr,Td,Adr) \
+{ \
+ PVOID _Adr = (Adr); \
+ PLANCE_TRANSMIT_ENTRY _Td = (Td); \
+ ULONG _Offset;\
+ PLANCE_ADAPTER _Adptr = (Adptr);\
+ _Offset = (ULONG)_Adr - (ULONG)(_Adptr->MmMappedBaseAddr);\
+ _Offset = _Offset + (ULONG)(_Adptr->HardwareBaseOffset);\
+ LANCE_WRITE_HARDWARE_LOW_PART_ADDRESS(\
+ _Td->LowTransmitBufferAddress,\
+ (USHORT)(((ULONG)_Offset) & 0xffff)\
+ );\
+ LANCE_WRITE_HARDWARE_HIGH_PART_ADDRESS(\
+ _Td->HighTransmitBufferAddress,\
+ (UCHAR)((((ULONG)_Offset) >> 16) & 0xff)\
+ );\
+}
+
+
+//
+// Used to set the length of the transmit buffer. The stored value
+// is actually the twos compliment of the length. Note that
+// the twos complement of this value must have the high order 4 bits
+// enabled.
+//
+// Td is a pointer to a transmit descriptor.
+//
+// Len is the unsigned short length of the buffer.
+//
+#define LANCE_SET_TRANSMIT_BUFFER_LENGTH(Td,Len) \
+ LANCE_WRITE_HARDWARE_MEMORY_USHORT(\
+ Td->BufferByteCount,\
+ (USHORT)((~Len)+1)\
+ )
+
+#endif // _LANCEHARDWARE_
diff --git a/private/ntos/ndis/lance/lancesft.h b/private/ntos/ndis/lance/lancesft.h
new file mode 100644
index 000000000..945b21687
--- /dev/null
+++ b/private/ntos/ndis/lance/lancesft.h
@@ -0,0 +1,962 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ lancesft.h
+
+Abstract:
+
+ The main header for a LANCE (Local Area Network Controller
+ Am 7990) MAC driver.
+
+Author:
+
+ Anthony V. Ercolano (tonye) creation-date 19-Jun-1990
+
+Environment:
+
+ This driver is expected to work in DOS, OS2 and NT at the equivalent
+ of kernal mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+ 31-Jul-1992 R.D. Lanser:
+
+ Changed DECST card type to DECTC for the DEC TurboChannel option
+ PMAD-AA (Lance ethernet). This option will be available for all
+ TurboChannel systems regardless of CPU type or system.
+
+ Added InterruptRequestLevel to the _LANCE_ADAPTER structure because
+ 'lance.c' was passing the InterruptVector as the IRQL to the interrupt
+ connect routine which is not correct. This works on JAZZ because the
+ JAZZ HalGetInterruptVector is hardcoded to return a fixed IRQL for
+ EISA devices.
+
+ Removed PhysicalBuffersContained and UsedLanceBuffer field from
+ _ADAPTER structure. SeanSe says that the code related to this
+ field was used for adevice that is no longer supported. I removed
+ the dependent code(or at least what was obvious) from 'send.c'.
+
+--*/
+
+#ifndef _LANCESFT_
+#define _LANCESFT_
+
+#define LANCE_NDIS_MAJOR_VERSION 3
+#define LANCE_NDIS_MINOR_VERSION 0
+
+#if DBG
+
+#define LANCELOG 1
+#define LANCE_TRACE 0
+
+#else
+
+#define LANCELOG 0
+#define LANCE_TRACE 0
+
+#endif
+
+#if LANCELOG
+
+#define LOG_SIZE 256
+
+#define TIMER '.'
+#define IN_ISR 'i'
+#define OUT_ISR 'I'
+#define IN_DPC 'd'
+#define OUT_DPC 'D'
+#define RECEIVE 'R'
+#define TRANSMIT 'x'
+#define TRANSMIT_COMPLETE 'X'
+#define PEND 'p'
+#define UNPEND 'P'
+#define INDICATE 'r'
+#define IN_SEND 's'
+#define OUT_SEND 'S'
+#define START 'G'
+#define RESET_STEP_1 '1'
+#define RESET_STEP_2 '2'
+#define RESET_SAVE_PACKET 'b'
+#define RESET_RECOVER_PACKET 'B'
+#define RESET_COMPLETE_PACKET 'c'
+#define RESET_STEP_3 '3'
+#define REMOVE 'V'
+#define CLOSE 'C'
+#define UNLOAD 'U'
+
+
+
+extern UCHAR Log[LOG_SIZE];
+
+extern UCHAR LogPlace;
+extern UCHAR LogWrapped;
+
+
+
+#define LOG(c) { Log[LogPlace] = (c); Log[(LogPlace+3) % 255] ='\0'; \
+ LogPlace = (LogPlace + 1) % 255; }
+
+#else
+
+#define LOG(c)
+
+#endif
+
+
+
+extern NDIS_PHYSICAL_ADDRESS HighestAcceptableMax;
+
+//
+// ZZZ These macros are peculiar to NT.
+//
+
+#define LANCE_ALLOC_PHYS(pp, s) NdisAllocateMemory((PVOID *)(pp),(s),0,HighestAcceptableMax)
+#define LANCE_FREE_PHYS(p, s) NdisFreeMemory((PVOID)(p),(s),0)
+#define LANCE_MOVE_MEMORY(Destination,Source,Length) NdisMoveMemory(Destination,Source,Length)
+#define LANCE_ZERO_MEMORY(Destination,Length) NdisZeroMemory(Destination,Length)
+
+
+
+//
+// Definitions for all the different card types.
+//
+
+
+#define LANCE_DE100 0x01 // DE100 card
+#define LANCE_DE201 0x02 // DE201 card
+#define LANCE_DEPCA 0x04 // Card in a Dec PC x86 machine
+#define LANCE_DECST 0x08 // Card in a decstation
+#define LANCE_DE422 0x10 // DE422 card
+#define LANCE_DECTC 0x20 // TurboChannel PMAD-AA option
+
+#define LANCE_DE100_NAME LANCE_DEFAULT_NAME
+#define LANCE_DE201_NAME LANCE_DEFAULT_NAME
+#define LANCE_DEPCA_NAME LANCE_DEFAULT_NAME
+#define LANCE_DECST_NAME LANCE_DEFAULT_NAME
+#define LANCE_DE422_NAME LANCE_DEFAULT_NAME
+#define LANCE_DECTC_NAME LANCE_DEFAULT_NAME
+#define LANCE_DEFAULT_NAME "\\Device\\Lance01"
+
+
+//
+// This structure is passed as context from the receive interrupt
+// processor. Eventually it will be used as a parameter to
+// LanceTransferData. LanceTransferData can get two kinds of
+// context. It will receive either an ndis packet or it will
+// receive a LANCE_RECEIVE_CONTEXT. It will be able to tell
+// the difference since the LANCE_RECEIVE_CONTEXT will have
+// its low bit set. No pointer to an ndis packet can have its low
+// bit set.
+//
+typedef union _LANCE_RECEIVE_CONTEXT {
+
+ UINT WholeThing;
+ struct _INFO {
+ //
+ // Used to mark that this is context rather than a pointer
+ // to a packet.
+ //
+ UINT IsContext:1;
+
+ //
+ // The first receive ring descriptor used to hold the packet.
+ //
+ UINT FirstBuffer:7;
+
+ //
+ // The last receive ring descriptor used to hold the packet.
+ //
+ UINT LastBuffer:7;
+ } INFO;
+
+} LANCE_RECEIVE_CONTEXT,*PLANCE_RECEIVE_CONTEXT;
+
+
+
+
+
+
+//
+// This record type is inserted into the MacReserved portion
+// of the packet header when the packet is going through the
+// staged allocation of buffer space prior to the actual send.
+//
+typedef struct _LANCE_RESERVED {
+
+ //
+ // Points to the next packet in the chain of queued packets
+ // being allocated, loopbacked, or waiting for the finish
+ // of transmission.
+ //
+ // The packet will either be on the stage list for allocation,
+ // the loopback list for loopback processing, on an adapter
+ // wide doubly linked list (see below) for post transmission
+ // processing.
+ //
+ // We always keep the packet on a list so that in case the
+ // the adapter is closing down or resetting, all the packets
+ // can easily be located and "canceled".
+ //
+ PNDIS_PACKET Next;
+
+ //
+ // This gives the index into the array of adapter buffer
+ // descriptors that contains the packet information.
+ //
+ USHORT LanceBuffersIndex;
+
+ //
+ // When the hardware send is done this will record whether
+ // the send was successful or not.
+ //
+ BOOLEAN SuccessfulTransmit;
+
+} LANCE_RESERVED,*PLANCE_RESERVED;
+
+//
+// This macro will return a pointer to the lance reserved portion
+// of a packet given a pointer to a packet.
+//
+#define PLANCE_RESERVED_FROM_PACKET(Packet) \
+ ((PLANCE_RESERVED)((Packet)->MacReserved))
+
+//
+// This structure is used to map entries in the ring descriptors
+// back to the packets from which the data in the ring descriptor
+// originated.
+//
+
+typedef struct _LANCE_RING_TO_PACKET {
+
+ //
+ // Points to the packet from which data is being transmitted
+ // through this ring entry.
+ //
+ PNDIS_PACKET OwningPacket;
+
+ //
+ // Index of the ring entry that is being used by the packet.
+ //
+ UINT RingIndex;
+
+ //
+ // When a packet is submitted to the hardware we record
+ // here whether it used adapter buffers and if so, the buffer
+ // index.
+ //
+ UINT LanceBuffersIndex;
+
+} LANCE_RING_TO_PACKET,*PLANCE_RING_TO_PACKET;
+
+//
+// If an ndis packet does not meet the hardware contraints then
+// an adapter buffer will be allocated. Enough data will be copied
+// out of the ndis packet so that by using a combination of the
+// adapter buffer and remaining ndis buffers the hardware
+// constraints are satisfied.
+//
+// In the LANCE_ADAPTER structure three threaded lists are kept in
+// one array. One points to a list of LANCE_BUFFER_DESCRIPTORS
+// that point to small adapter buffers. Another is for medium sized
+// buffers and the last for full sized (large) buffers.
+//
+// The allocation is controlled via a free list head and
+// the free lists are "threaded" by a field in the adapter buffer
+// descriptor.
+//
+typedef struct _LANCE_BUFFER_DESCRIPTOR {
+
+ //
+ // A virtual pointer to a small, medium, or large buffer.
+ //
+ PVOID VirtualLanceBuffer;
+
+ //
+ // Threads the elements of an array of these descriptors into
+ // a free list. -1 implies no more entries in the list.
+ //
+ INT Next;
+
+ //
+ // Holds the amount of space (in bytes) available in the buffer
+ //
+ UINT BufferSize;
+
+ //
+ // Holds the length of data placed into the buffer. This
+ // can (and likely will) be less that the actual buffers
+ // length.
+ //
+ UINT DataLength;
+
+} LANCE_BUFFER_DESCRIPTOR,*PLANCE_BUFFER_DESCRIPTOR;
+
+
+#define LANCE_LENGTH_OF_ADDRESS 6
+
+//
+// Define the size of the ethernet header.
+//
+#define LANCE_HEADER_SIZE 14
+
+//
+// Define Maximum number of bytes a protocol can read during a
+// receive data indication.
+//
+#define LANCE_MAX_LOOKAHEAD ( 248 - LANCE_HEADER_SIZE )
+
+
+
+
+
+typedef struct _LANCE_ADAPTER {
+
+ //
+ // The card type of this adapter.
+ //
+ UCHAR LanceCard;
+
+ //
+ // Holds the interrupt object for this adapter.
+ //
+ NDIS_MINIPORT_INTERRUPT Interrupt;
+
+ NDIS_MINIPORT_TIMER DeferredTimer;
+
+ //
+ // Non OS fields of the adapter.
+ //
+
+ //
+ // Contains Address first byte of adapter memory is mapped to.
+ //
+ PVOID MmMappedBaseAddr;
+
+ //
+ // Contains address of the hardware memory.
+ //
+ PVOID HardwareBaseAddr;
+
+ //
+ // Offset for Init block from the Lance chip's point of view.
+ //
+ ULONG HardwareBaseOffset;
+
+ //
+ // Amount of memory
+ //
+ ULONG AmountOfHardwareMemory;
+
+ //
+ // For lance implementation that uses dual ported memory this
+ // field is used to point to the first available memory.
+ //
+ PVOID CurrentMemoryFirstFree;
+
+ //
+ // Address of the first byte following the memory.
+ //
+ PVOID MemoryFirstUnavailable;
+
+ //
+ // Physical address of base io port address
+ //
+ ULONG IoBaseAddr;
+
+ //
+ // Pointer to the RAP register.
+ //
+ ULONG RAP;
+
+ //
+ // Pointer to the RDP register.
+ //
+ ULONG RDP;
+
+ //
+ // Pointer to the NICSR register.
+ //
+ ULONG Nicsr;
+
+ //
+ // Slot Number the De422 is in.
+ //
+ UINT SlotNumber;
+
+ //
+ // Default information to add to the NICSR register value
+ //
+ USHORT NicsrDefaultValue;
+
+ //
+ // Have the interrupts from the card been turned off.
+ //
+ BOOLEAN InterruptsStopped;
+
+ //
+ // Address in memory of the network address
+ //
+ ULONG NetworkHardwareAddress;
+
+ //
+ // The network address from the hardware.
+ //
+ CHAR NetworkAddress[LANCE_LENGTH_OF_ADDRESS];
+
+ //
+ // The network address from the hardware.
+ //
+ CHAR CurrentNetworkAddress[LANCE_LENGTH_OF_ADDRESS];
+
+ //
+ // Interrupt number
+ //
+ CCHAR InterruptNumber;
+
+ //
+ // IRQL
+ //
+ CCHAR InterruptRequestLevel;
+
+ //
+ // Holds the number of transmit ring entries.
+ //
+ // NOTE NOTE NOTE
+ //
+ // There is code that depends on the number of transmit entries
+ // being a power of two.
+ //
+ UINT NumberOfTransmitRings;
+
+ //
+ // Holds the number of receive ring entries.
+ //
+ UINT NumberOfReceiveRings;
+
+ //
+ // Holds the size of receive buffers.
+ //
+ UINT SizeOfReceiveBuffer;
+
+ //
+ // Holds number of each buffer size.
+ //
+ UINT NumberOfSmallBuffers;
+ UINT NumberOfMediumBuffers;
+ UINT NumberOfLargeBuffers;
+
+ //
+ // The log base two of the number of transmit ring entries.
+ //
+ UINT LogNumberTransmitRings;
+
+ //
+ // The log base two of the number of receive ring entries.
+ //
+ UINT LogNumberReceiveRings;
+
+ //
+ // Handle given by NDIS when the MAC registered itself.
+ //
+ NDIS_HANDLE NdisDriverHandle;
+
+ //
+ // Handle given by NDIS when the adapter was registered.
+ //
+ NDIS_HANDLE MiniportAdapterHandle;
+
+ //
+ // Pointer to the LANCE initialization block.
+ //
+ PLANCE_INITIALIZATION_BLOCK InitBlock;
+
+ //
+ // Counter that records the number of transmit rings currently
+ // available for allocation.
+ //
+ UINT NumberOfAvailableRings;
+
+ //
+ // Pointer to transmit descriptor ring entry that is the
+ // first ring entry available for allocation of transmit
+ // buffers.
+ //
+ // Can only be accessed when the adapter lock
+ // is held.
+ //
+ PLANCE_TRANSMIT_ENTRY AllocateableRing;
+
+ //
+ // Pointer to a transmit descriptor ring entry that is the
+ // first ring entry that the MAC currently has made available
+ // for transmission.
+ //
+ // Can only be accessed when the adapter lock
+ // is held.
+ //
+ PLANCE_TRANSMIT_ENTRY TransmittingRing;
+
+ //
+ // Pointer to the first packet that has been allocated to
+ // a transmit packet but has not yet been relinquished to
+ // the hardware. We need this pointer to keep the transmit
+ // post processing from running into a packet that has not
+ // been transmitted.
+ //
+ PLANCE_TRANSMIT_ENTRY FirstUncommittedRing;
+
+ //
+ // Pointer to an array of structs that map transmit ring entries
+ // back to a packet.
+ //
+ PLANCE_RING_TO_PACKET RingToPacket;
+
+ //
+ // Pointer to the transmit ring.
+ //
+ PLANCE_TRANSMIT_ENTRY TransmitRing;
+
+ //
+ // Pointer to the last transmit ring entry.
+ //
+ PLANCE_TRANSMIT_ENTRY LastTransmitRingEntry;
+
+ //
+ // Pointer to the receive ring.
+ //
+ PLANCE_RECEIVE_ENTRY ReceiveRing;
+
+ //
+ // Listheads for the adapters buffers. If the list
+ // head is equal to -1 then there are no free elements
+ // on the list.
+ //
+ // The list heads must only be accessed when the
+ // adapter lock is held.
+ //
+ // Note that the listhead at index 0 will always be -1.
+ //
+ INT LanceBufferListHeads[4];
+
+ //
+ // Pointers to an array of adapter buffer descriptors.
+ // The array will actually be threaded together by
+ // three free lists. The lists will be for small,
+ // medium and full sized packets.
+ //
+ PLANCE_BUFFER_DESCRIPTOR LanceBuffers;
+
+ //
+ // Did we indicate a packet? Used to tell if NdisIndicateReceiveComplete
+ // should be called.
+ //
+ BOOLEAN IndicatedAPacket;
+
+ //
+ // Pointer to an array of virtual addresses that describe
+ // the virtual address of each receive ring descriptor buffer.
+ //
+ PVOID *ReceiveVAs;
+
+ //
+ // Index of the receive ring descriptor that started the
+ // last packet not completely received by the hardware.
+ //
+ UINT CurrentReceiveIndex;
+
+ //
+ // Counters to hold the various number of errors/statistics for both
+ // reception and transmission.
+ //
+ // Can only be accessed when the adapter lock is held.
+ //
+ UINT OutOfReceiveBuffers;
+ UINT CRCError;
+ UINT FramingError;
+ UINT RetryFailure;
+ UINT LostCarrier;
+ UINT LateCollision;
+ UINT UnderFlow;
+ UINT Deferred;
+ UINT OneRetry;
+ UINT MoreThanOneRetry;
+
+ //
+ // Holds counts of more global errors for the driver. If we
+ // get a memory error then the device needs to be reset.
+ //
+ UINT MemoryError;
+ UINT Babble;
+ UINT MissedPacket;
+
+ //
+ // Holds other cool counts.
+ //
+
+ ULONG Transmit;
+ ULONG Receive;
+
+ //
+ // Flag that when enabled lets routines know that a reset
+ // is in progress.
+ //
+ BOOLEAN ResetInProgress;
+
+ //
+ // Flag that when enabled lets routines know that a reset
+ // is in progress and the initialization needs doing.
+ //
+ BOOLEAN ResetInitStarted;
+
+ //
+ // The type of the request that caused the adapter to reset.
+ //
+ NDIS_REQUEST_TYPE ResetRequestType;
+
+ //
+ // During an indication this is set to the current indications context
+ //
+ LANCE_RECEIVE_CONTEXT IndicatingMacReceiveContext;
+
+
+ //
+ // Look ahead information.
+ //
+
+ ULONG MaxLookAhead;
+
+ //
+ // Open information
+ //
+ UCHAR MaxMulticastList;
+
+ //
+ // Will be true the first time that the hardware is initialized
+ // by the driver initialization.
+ //
+ BOOLEAN FirstInitialization;
+
+ //
+ // Is the adapter being removed
+ //
+ BOOLEAN BeingRemoved;
+
+ //
+ // Will be true if the hardware fails for some reason
+ //
+ BOOLEAN HardwareFailure;
+
+ USHORT SavedMemBase;
+ UINT Reserved1;
+ UINT Reserved2;
+ //
+ // Lookahead buffer for loopback packets
+ //
+ UCHAR Lookahead[LANCE_MAX_LOOKAHEAD + LANCE_HEADER_SIZE];
+
+ UINT PacketFilter;
+ UINT NumberOfAddresses;
+ UCHAR MulticastAddresses[32][LANCE_LENGTH_OF_ADDRESS];
+
+} LANCE_ADAPTER,*PLANCE_ADAPTER;
+
+//
+// Given a MacContextHandle return the PLANCE_ADAPTER
+// it represents.
+//
+#define PLANCE_ADAPTER_FROM_CONTEXT_HANDLE(Handle) \
+ ((PLANCE_ADAPTER)(Handle))
+
+//
+// Given a pointer to a LANCE_ADAPTER return the
+// proper MacContextHandle.
+//
+#define CONTEXT_HANDLE_FROM_PLANCE_ADAPTER(Ptr) \
+ ((NDIS_HANDLE)(Ptr))
+
+//
+// This macro will act a "epilogue" to every routine in the
+// *interface*. It will check whether any requests need
+// to defer their processing. It will also decrement the reference
+// count on the adapter. If the reference count is zero and there
+// is deferred work to do it will insert the interrupt processing
+// routine in the DPC queue.
+//
+// Note that we don't need to include checking for blocked receives
+// since blocked receives imply that there will eventually be an
+// interrupt.
+//
+// NOTE: This macro assumes that it is called with the lock acquired.
+//
+// ZZZ This routine is NT specific.
+//
+#define LANCE_DO_DEFERRED(Adapter) \
+{ \
+ PLANCE_ADAPTER _A = (Adapter); \
+ if (_A->ResetInProgress) { \
+ NdisMSetTimer(&_A->DeferredTimer, 0);\
+ } \
+}
+
+
+
+
+//
+// Procedures which log errors.
+//
+
+typedef enum _LANCE_PROC_ID {
+ processInterrupt
+} LANCE_PROC_ID;
+
+
+#define LANCE_ERRMSG_NDIS_ALLOC_MEM (ULONG)0x01
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//
+// This macro is used to "allocate" memory for the structures that
+// must be shared with the hardware. It assigns a pvoid that is
+// at least quadword aligned.
+//
+#define LANCE_ALLOCATE_MEMORY_FOR_HARDWARE(A,S,P) \
+{ \
+ PLANCE_ADAPTER _Adapter = (A); \
+ UINT _Size = (((S) + 7)/8)*8; \
+ PVOID _HighWater; \
+ if (!_Size) { \
+ *(P) = NULL; \
+ } else { \
+ _HighWater = ((PCHAR)_Adapter->CurrentMemoryFirstFree) + _Size; \
+ if (((PUCHAR)_HighWater) > \
+ (((PUCHAR)_Adapter->MemoryFirstUnavailable) + 1)) { \
+ *(P) = NULL; \
+ } else { \
+ *(P) = _Adapter->CurrentMemoryFirstFree; \
+ _Adapter->CurrentMemoryFirstFree = _HighWater; \
+ } \
+ } \
+}
+
+//
+// We now convert the virtual address to the actual physical address.
+//
+#define LANCE_GET_HARDWARE_PHYSICAL_ADDRESS(A,P) \
+ (ULONG)((PCHAR)P - (PCHAR)(A)->MmMappedBaseAddr + (A)->HardwareBaseOffset)
+
+//
+// This macro is used to "deallocate the memory from the hardware.
+// Since this is hardware memory that is only allocated and deallocated
+// once this macro really doesn't do anything.
+//
+#define LANCE_DEALLOCATE_MEMORY_FOR_HARDWARE(A,P)\
+{\
+}
+
+
+
+
+
+//
+// These are routines for synchronizing with the ISR
+//
+
+
+//
+// This structure is used to synchronize reading and writing to ports
+// with the ISR.
+//
+
+typedef struct _LANCE_SYNCH_CONTEXT {
+
+ //
+ // Pointer to the lance adapter for which interrupts are
+ // being synchronized.
+ //
+ PLANCE_ADAPTER Adapter;
+
+ //
+ // Pointer to a local variable that will receive the value
+ //
+ PUSHORT LocalRead;
+
+ //
+ // Value to write
+ //
+ USHORT LocalWrite;
+
+} LANCE_SYNCH_CONTEXT,*PLANCE_SYNCH_CONTEXT;
+
+
+
+#define LANCE_WRITE_RAP(A,C) { \
+ LANCE_ISR_WRITE_RAP(A,C);\
+}
+
+
+#define LANCE_WRITE_RDP(A,C) { \
+ LANCE_ISR_WRITE_RDP(A,C);\
+}
+
+#define LANCE_READ_RDP(A,C) { \
+ LANCE_ISR_READ_RDP(A,C);\
+}
+
+#define LANCE_WRITE_NICSR(A,C) { \
+ PLANCE_ADAPTER _A = A; \
+ LANCE_SYNCH_CONTEXT _C; \
+ _C.Adapter = _A; \
+ _C.LocalWrite = (C | _A->NicsrDefaultValue); \
+ NdisMSynchronizeWithInterrupt( \
+ &(_A)->Interrupt, \
+ LanceSyncWriteNicsr, \
+ &_C \
+ ); \
+}
+
+BOOLEAN
+LanceSyncWriteNicsr(
+ IN PVOID Context
+ );
+
+BOOLEAN
+LanceSyncGetInterruptsStopped(
+ IN PVOID Context
+ );
+
+BOOLEAN
+LanceSyncStopChip(
+ IN PVOID Context
+ );
+
+
+//
+// We define the external interfaces to the lance driver.
+// These routines are only external to permit separate
+// compilation. Given a truely fast compiler they could
+// all reside in a single file and be static.
+//
+
+
+NDIS_STATUS
+LanceTransferData(
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+ );
+
+NDIS_STATUS
+LanceSend(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET Packet,
+ IN UINT Flags
+ );
+
+extern
+VOID
+LanceStagedAllocation(
+ IN PLANCE_ADAPTER Adapter
+ );
+
+extern
+VOID
+LanceCopyFromPacketToBuffer(
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ IN UINT BytesToCopy,
+ OUT PCHAR Buffer,
+ OUT PUINT BytesCopied
+ );
+
+extern
+VOID
+LanceCopyFromPacketToPacket(
+ IN PNDIS_PACKET Destination,
+ IN UINT DestinationOffset,
+ IN UINT BytesToCopy,
+ IN PNDIS_PACKET Source,
+ IN UINT SourceOffset,
+ OUT PUINT BytesCopied
+ );
+
+extern
+BOOLEAN
+LanceHardwareDetails(
+ IN PLANCE_ADAPTER Adapter
+ );
+
+extern
+NDIS_STATUS
+LanceRegisterAdapter(
+ IN PLANCE_ADAPTER Adapter
+ );
+
+VOID
+SetupAllocate(
+ IN PLANCE_ADAPTER Adapter,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_PACKET Packet
+ );
+
+VOID
+LanceDisableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+VOID
+LanceEnableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+VOID
+LanceHalt(
+ IN PVOID MiniportAdapterContext
+ );
+
+VOID
+LanceHandleInterrupt(
+ IN NDIS_HANDLE Context
+ );
+
+VOID
+LanceIsr(
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueDpc,
+ IN PVOID Context
+ );
+
+NDIS_STATUS
+LanceInitialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE ConfigurationHandle
+ );
+
+#endif // _LANCESFT_
diff --git a/private/ntos/ndis/lance/makefile b/private/ntos/ndis/lance/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/lance/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/lance/send.c b/private/ntos/ndis/lance/send.c
new file mode 100644
index 000000000..8c7ca93bc
--- /dev/null
+++ b/private/ntos/ndis/lance/send.c
@@ -0,0 +1,437 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ send.c
+
+Abstract:
+
+ This file contains the code for putting a packet through the
+ staged allocation for transmission.
+
+ This is a process of
+
+ 1) Calculating the what would need to be done to the
+ packet so that the packet can be transmitted on the hardware.
+
+ 2) Potentially allocating adapter buffers and copying user data
+ to those buffers so that the packet data is transmitted under
+ the hardware constraints.
+
+ 3) Allocating enough hardware ring entries so that the packet
+ can be transmitted.
+
+ 4) Relinquish thos ring entries to the hardware.
+
+Author:
+
+ Anthony V. Ercolano (Tonye) 12-Sept-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+ 31-Jul-1992 R.D. Lanser:
+
+ Removed PhysicalBuffersContained and UsedLanceBuffer field from
+ _ADAPTER structure. SeanSe says that the code related to this
+ field was used for adevice that is no longer supported. I removed
+ the dependent code(or at least what was obvious) from 'send.c'.
+ This old code was generating an erroneous ring buffer count on the
+ MIPS R3000. I did not test it on the MIPS R4000. The problem goes
+ away with the removal of the offending code.
+
+--*/
+
+#include <ndis.h>
+#include <lancehrd.h>
+#include <lancesft.h>
+
+
+//
+// Minimum packet size that a transport can send. We subtract 4 bytes
+// because we add a 4 byte CRC on the end.
+//
+
+#define MIN_SINGLE_BUFFER ((UINT)LANCE_SMALL_BUFFER_SIZE - 4)
+
+
+//
+// It will poke the lance hardware into noticing that there is a packet
+// available for transmit.
+//
+// Note that there is the assumption that the register address
+// port (RAP) is already set to zero.
+//
+#define PROD_TRANSMIT(A) \
+ LANCE_WRITE_RDP( \
+ A, \
+ LANCE_CSR0_TRANSMIT_DEMAND | LANCE_CSR0_INTERRUPT_ENABLE \
+ );
+
+extern
+NDIS_STATUS
+LanceSend(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET Packet,
+ IN UINT Flags
+ )
+
+/*++
+
+Routine Description:
+
+ The LanceSend request instructs a MAC to transmit a packet through
+ the adapter onto the medium.
+
+Arguments:
+
+ Status - The status of the operation.
+
+ MiniportAdapterContext - The context value set by the mini-port.
+
+ Packet - A pointer to a descriptor for the packet that is to be
+ transmitted.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Pointer to the adapter.
+ //
+ PLANCE_ADAPTER Adapter = (PLANCE_ADAPTER)MiniportAdapterContext;
+
+ //
+ // Pointer to the ring entry to be filled with buffer information.
+ //
+ PLANCE_TRANSMIT_ENTRY CurrentRingElement;
+
+ //
+ // Pointer to the ring to packet entry that records the info about
+ // this packet.
+ //
+ PLANCE_RING_TO_PACKET RingToPacket;
+
+ //
+ // Length of the packet
+ //
+ ULONG TotalVirtualLength;
+
+ //
+ // Holds the adapter buffer index available for allocation.
+ //
+ INT LanceBuffersIndex;
+
+ //
+ // Points to a successfully allocated adapter buffer descriptor.
+ //
+ PLANCE_BUFFER_DESCRIPTOR BufferDescriptor;
+
+ //
+ // Simple iteration variable.
+ //
+ INT i;
+
+ //
+ // Size of Lance Buffer needed (1==Small, 2==Medium, 3==Large)
+ //
+ UCHAR BufferSize;
+
+ //
+ // If we successfully acquire some ring entries, this
+ // is the index of the first one.
+ //
+ UINT RingIndex;
+
+ //
+ // Will point into the virtual address space addressed
+ // by the adapter buffer if one was successfully allocated.
+ //
+ PCHAR CurrentDestination;
+
+ //
+ // Will point to the current source buffer.
+ //
+ PNDIS_BUFFER SourceBuffer;
+
+ //
+ // Points to the virtual address of the source buffers data.
+ //
+ PVOID SourceData;
+
+ //
+ // Will point to the number of bytes of data in the source
+ // buffer.
+ //
+ UINT SourceLength;
+
+ NDIS_STATUS Status;
+
+#if LANCE_TRACE
+ DbgPrint("In LanceSend\n");
+#endif
+
+ if (Adapter->HardwareFailure) {
+
+ return(NDIS_STATUS_FAILURE);
+
+ }
+
+ LOG(IN_SEND);
+
+ if (!Adapter->ResetInProgress) {
+
+ if (Adapter->NumberOfAvailableRings == 0) {
+
+ return(NDIS_STATUS_RESOURCES);
+
+ }
+
+ //
+ // It is reasonable to do a quick check and fail if the packet
+ // is larger than the maximum an ethernet can handle.
+ //
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ NULL,
+ &SourceBuffer,
+ &TotalVirtualLength
+ );
+
+ if ((!TotalVirtualLength) ||
+ (TotalVirtualLength > LANCE_LARGE_BUFFER_SIZE)) {
+
+ return(NDIS_STATUS_RESOURCES);
+
+ } else {
+
+ //
+ // Certain hardware implementation (Decstation) use a dual ported
+ // memory to communicate with the hardware. This is reasonable since
+ // it reduces bus contention. When using the dual ported memory, all
+ // send data must be moved to buffers allocated from the dual ported
+ // memory.
+ //
+
+ if (TotalVirtualLength <= LANCE_SMALL_BUFFER_SIZE) {
+
+ BufferSize = 1;
+
+ } else if (TotalVirtualLength <= LANCE_MEDIUM_BUFFER_SIZE) {
+
+ BufferSize = 2;
+
+ } else {
+
+ BufferSize = 3;
+
+ }
+
+ //
+ // Find a buffer
+ //
+ for (
+ i = BufferSize;
+ i <= 3;
+ i++
+ ) {
+
+ if ((LanceBuffersIndex = Adapter->LanceBufferListHeads[i]) != -1) {
+
+ BufferDescriptor = Adapter->LanceBuffers + LanceBuffersIndex;
+ Adapter->LanceBufferListHeads[i] = BufferDescriptor->Next;
+ break;
+
+ }
+
+ }
+
+ if (LanceBuffersIndex == -1) {
+
+ //
+ // Nothing available for the packet.
+ //
+
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ //
+ // Save the list head index in the buffer descriptor
+ // to permit easy deallocation later.
+ //
+ BufferDescriptor->Next = i;
+
+ //
+ // Now Acquire the ring
+ //
+ RingIndex = Adapter->AllocateableRing - Adapter->TransmitRing;
+
+ //
+ // Store the info
+ //
+ CurrentRingElement = Adapter->AllocateableRing;
+
+ //
+ // NOTE NOTE NOTE NOTE NOTE NOTE
+ //
+ // We can do the next calculation because we know that the number
+ // or ring entries is a power of two!
+ //
+
+ Adapter->AllocateableRing = Adapter->TransmitRing +
+ (((RingIndex) + 1) &
+ (Adapter->NumberOfTransmitRings-1));
+
+ Adapter->NumberOfAvailableRings--;
+
+ //
+ // Copy into buffer
+ //
+
+ CurrentDestination = BufferDescriptor->VirtualLanceBuffer;
+
+ while ( SourceBuffer != NULL ) {
+
+ NdisQueryBuffer(
+ SourceBuffer,
+ &SourceData,
+ &SourceLength
+ );
+
+ LANCE_MOVE_MEMORY_TO_HARDWARE(
+ CurrentDestination,
+ SourceData,
+ SourceLength
+ );
+
+ CurrentDestination = (PCHAR)CurrentDestination + SourceLength;
+
+ NdisGetNextBuffer(
+ SourceBuffer,
+ &SourceBuffer
+ );
+
+ }
+
+ //
+ // If the packet is less then the minimum size then we
+ // need to zero out the rest of the packet.
+ //
+
+ if (TotalVirtualLength < MIN_SINGLE_BUFFER) {
+
+ LANCE_ZERO_MEMORY_FOR_HARDWARE(
+ CurrentDestination,
+ MIN_SINGLE_BUFFER - TotalVirtualLength
+ );
+
+ BufferDescriptor->DataLength = MIN_SINGLE_BUFFER;
+
+ } else {
+
+ BufferDescriptor->DataLength = TotalVirtualLength;
+
+ }
+
+ //
+ // Get the position for mapping ring entries to packets.
+ // We record the owning packet information in the ring packet packet
+ // structure.
+ //
+ RingToPacket = Adapter->RingToPacket + RingIndex;
+ RingToPacket->OwningPacket = Packet;
+ RingToPacket->LanceBuffersIndex = LanceBuffersIndex;
+ RingToPacket->RingIndex = RingIndex;
+
+ //
+ // Make sure that the ring descriptor is clean.
+ //
+
+ LANCE_ZERO_MEMORY_FOR_HARDWARE((PUCHAR)CurrentRingElement,
+ sizeof(LANCE_TRANSMIT_ENTRY)
+ );
+
+ LANCE_SET_TRANSMIT_BUFFER_LENGTH(
+ CurrentRingElement,
+ BufferDescriptor->DataLength
+ );
+
+
+ LANCE_SET_TRANSMIT_BUFFER_ADDRESS(
+ Adapter,
+ CurrentRingElement,
+ BufferDescriptor->VirtualLanceBuffer
+ );
+
+ LOG(TRANSMIT);
+
+ //
+ // We update the ring ownership of the last packet under
+ // the protection of the lock so that the uncommitted packet
+ // pointer can be updated before the transmit post processing
+ // can examine it.
+ //
+
+ LANCE_SET_RING_BITS(
+ CurrentRingElement->TransmitSummaryBits,
+ LANCE_TRANSMIT_START_OF_PACKET |
+ LANCE_TRANSMIT_OWNED_BY_CHIP |
+ LANCE_TRANSMIT_END_OF_PACKET
+ );
+
+
+ if (RingIndex == (Adapter->NumberOfTransmitRings-1)) {
+
+ Adapter->FirstUncommittedRing = Adapter->TransmitRing ;
+
+ } else {
+
+ Adapter->FirstUncommittedRing = Adapter->TransmitRing + RingIndex + 1;
+
+ }
+
+ //
+ // Prod the chip into checking for packets to send.
+ //
+
+ PROD_TRANSMIT(Adapter);
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ }
+
+ } else if (Adapter->ResetRequestType == NdisRequestGeneric1) {
+
+ Status = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ } else {
+
+ //
+ // Have the upper layer try again later
+ //
+ Status = NDIS_STATUS_RESOURCES;
+
+ }
+
+ LOG(OUT_SEND);
+
+ LANCE_DO_DEFERRED(Adapter);
+
+#if LANCE_TRACE
+ DbgPrint("Out LanceSend\n");
+#endif
+
+ return Status;
+}
+
diff --git a/private/ntos/ndis/lance/sources b/private/ntos/ndis/lance/sources
new file mode 100644
index 000000000..d6f5951bd
--- /dev/null
+++ b/private/ntos/ndis/lance/sources
@@ -0,0 +1,47 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=lance
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER
+
+INCLUDES=..\..\inc
+
+SOURCES=lance.c \
+ send.c \
+ transfer.c \
+ details.c \
+ dectc.c \
+ lance.rc
+
+RELATIVE_DEPTH=..\..
+
+MSC_WARNING_LEVEL=/W3 /WX
+
diff --git a/private/ntos/ndis/lance/transfer.c b/private/ntos/ndis/lance/transfer.c
new file mode 100644
index 000000000..d0ded3180
--- /dev/null
+++ b/private/ntos/ndis/lance/transfer.c
@@ -0,0 +1,389 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ transfer.c
+
+Abstract:
+
+ This file contains the code to implement the MacTransferData
+ API for the ndis 3.0 interface.
+
+Author:
+
+ Anthony V. Ercolano (Tonye) 12-Sept-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+#include <lancehrd.h>
+#include <lancesft.h>
+
+
+extern
+NDIS_STATUS
+LanceTransferData(
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+ )
+
+/*++
+
+Routine Description:
+
+ A protocol calls the LanceTransferData request (indirectly via
+ NdisTransferData) from within its Receive event handler
+ to instruct the MAC to copy the contents of the received packet
+ a specified paqcket buffer.
+
+Arguments:
+
+ Status - Status of the operation.
+
+ MiniportAdapterContext - The context value set by the Miniport.
+
+ MiniportReceiveContext - The context value passed by the MAC on its call
+ to NdisMEthIndicateReceive.
+
+ ByteOffset - An unsigned integer specifying the offset within the
+ received packet at which the copy is to begin. If the entire packet
+ is to be copied, ByteOffset must be zero.
+
+ BytesToTransfer - An unsigned integer specifying the number of bytes
+ to copy. It is legal to transfer zero bytes; this has no effect. If
+ the sum of ByteOffset and BytesToTransfer is greater than the size
+ of the received packet, then the remainder of the packet (starting from
+ ByteOffset) is transferred, and the trailing portion of the receive
+ buffer is not modified.
+
+ Packet - A pointer to a descriptor for the packet storage into which
+ the MAC is to copy the received packet.
+
+ BytesTransfered - A pointer to an unsigned integer. The MAC writes
+ the actual number of bytes transferred into this location. This value
+ is not valid if the return status is STATUS_PENDING.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+
+{
+
+ PLANCE_ADAPTER Adapter = (PLANCE_ADAPTER)(MiniportAdapterContext);
+ //
+ // Keep a local for the number of receive ring entries so
+ // that we aren't always accessing through the adapter.
+ //
+ const UINT TopReceiveIndex = Adapter->NumberOfReceiveRings - 1;
+
+ //
+ // Used for only a short time to extract the context
+ // information from the parameter.
+ //
+ LANCE_RECEIVE_CONTEXT C;
+
+ //
+ // Holds the first and last index of the first and last
+ // receive ring descriptors that hold the current packet.
+ //
+ UINT FirstBuffer;
+ UINT LastBuffer;
+
+ //
+ // Pointer to the ring descriptor for the current buffer.
+ //
+ PLANCE_RECEIVE_ENTRY CurrentEntry;
+
+ //
+ // Holds the count of the number of ndis buffers comprising
+ // the destination packet.
+ //
+ UINT DestinationBufferCount;
+
+ //
+ // Points to the buffer into which we are putting data.
+ //
+ PNDIS_BUFFER DestinationCurrentBuffer;
+
+ //
+ // Holds the virtual address of the current destination
+ // buffer.
+ //
+ PVOID DestinationVirtualAddress;
+
+ //
+ // Holds the virtual address of the current source buffer.
+ //
+ PVOID SourceVirtualAddress;
+
+ //
+ // Holds the length of the current destination buffer.
+ //
+ UINT DestinationCurrentLength;
+
+ //
+ // Holds the length of the current source buffer.
+ //
+ UINT SourceCurrentLength;
+
+ //
+ // Keep a local variable of BytesTransferred so we aren't
+ // referencing through a pointer.
+ //
+ UINT LocalBytesTransferred = 0;
+
+ //
+ // Index in the ring of the current receive ring descriptor.
+ //
+ UINT CurrentSourceIndex;
+
+ ASSERT(!Adapter->ResetInitStarted);
+
+ ByteOffset += LANCE_HEADER_SIZE;
+
+ //
+ // Take care of boundary condition of zero length copy.
+ //
+
+ *BytesTransferred = 0;
+
+ ASSERT(sizeof(UINT) >= 2);
+ ASSERT(sizeof(UINT) == sizeof(NDIS_HANDLE));
+
+ C.WholeThing = (UINT)MiniportReceiveContext;
+ FirstBuffer = C.INFO.FirstBuffer;
+ LastBuffer = C.INFO.LastBuffer;
+
+ //
+ // Get the first buffer of the destination.
+ //
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ &DestinationBufferCount,
+ &DestinationCurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet.
+ //
+
+ if (DestinationBufferCount) {
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+
+ //
+ // Get the information for the first buffer of the source.
+ //
+
+ SourceVirtualAddress = Adapter->ReceiveVAs[FirstBuffer];
+ CurrentEntry = Adapter->ReceiveRing + FirstBuffer;
+ CurrentSourceIndex = FirstBuffer;
+
+ if (CurrentSourceIndex == LastBuffer) {
+
+ //
+ // The last buffer might only be partially filled with
+ // transmitted data. There is a field in the last
+ // ring entry that has the total packet data length.
+ //
+ LANCE_GET_MESSAGE_SIZE(CurrentEntry, SourceCurrentLength);
+ SourceCurrentLength -= LocalBytesTransferred;
+
+ } else {
+
+ SourceCurrentLength = Adapter->SizeOfReceiveBuffer;
+
+ }
+
+ while (LocalBytesTransferred < BytesToTransfer) {
+
+ //
+ // Check to see whether we've exhausted the current
+ // destination buffer. If so, move onto the next one.
+ //
+
+ if (!DestinationCurrentLength) {
+
+ NdisGetNextBuffer(
+ DestinationCurrentBuffer,
+ &DestinationCurrentBuffer
+ );
+
+ if (!DestinationCurrentBuffer) {
+
+ //
+ // We've reached the end of the packet. We
+ // return with what we've done so far. (Which
+ // must be shorter than requested.)
+ //
+
+ break;
+
+ }
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+ continue;
+
+ }
+
+
+ //
+ // Check to see whether we've exhausted the current
+ // source buffer. If so, move onto the next one.
+ //
+
+ if (!SourceCurrentLength) {
+
+ if (CurrentSourceIndex == LastBuffer) {
+
+ //
+ // We've reached the end of the packet. We
+ // return with what we've done so far. (Which
+ // must be shorter than requested.)
+ //
+
+ break;
+
+ }
+
+ if (CurrentSourceIndex == TopReceiveIndex) {
+
+ CurrentSourceIndex = 0;
+ CurrentEntry = Adapter->ReceiveRing;
+
+ } else {
+
+ CurrentSourceIndex++;
+ CurrentEntry++;
+
+ }
+
+ if (CurrentSourceIndex == LastBuffer) {
+
+ //
+ // The last buffer might only be partially
+ // filled with transmitted data. There is
+ // a field in the last ring entry that has
+ // the total packet data length.
+ //
+ LANCE_GET_MESSAGE_SIZE(CurrentEntry, SourceCurrentLength);
+ SourceCurrentLength -= LocalBytesTransferred;
+
+ } else {
+
+ SourceCurrentLength =
+ Adapter->SizeOfReceiveBuffer;
+
+ }
+
+ SourceVirtualAddress =
+ Adapter->ReceiveVAs[CurrentSourceIndex];
+ continue;
+
+ }
+
+ //
+ // Try to get us up to the point to start the copy.
+ //
+
+ if (ByteOffset) {
+
+ if (ByteOffset > SourceCurrentLength) {
+
+ //
+ // What we want isn't in this buffer.
+ //
+
+ ByteOffset -= SourceCurrentLength;
+ SourceCurrentLength = 0;
+ continue;
+
+ } else {
+
+ SourceVirtualAddress =
+ (PCHAR)SourceVirtualAddress + ByteOffset;
+ SourceCurrentLength -= ByteOffset;
+ ByteOffset = 0;
+
+ }
+
+ }
+
+ //
+ // Copy the data.
+ //
+
+ {
+
+ //
+ // Holds the amount of data to move.
+ //
+ UINT AmountToMove;
+
+ //
+ // Holds the amount desired remaining.
+ //
+ UINT Remaining = BytesToTransfer
+ - LocalBytesTransferred;
+
+ AmountToMove =
+ ((SourceCurrentLength <= DestinationCurrentLength)?
+ (SourceCurrentLength):(DestinationCurrentLength));
+
+ AmountToMove = ((Remaining < AmountToMove)?
+ (Remaining):(AmountToMove));
+
+ LANCE_MOVE_HARDWARE_TO_MEMORY(
+ DestinationVirtualAddress,
+ SourceVirtualAddress,
+ AmountToMove
+ );
+
+ DestinationVirtualAddress =
+ (PCHAR)DestinationVirtualAddress + AmountToMove;
+ SourceVirtualAddress =
+ (PCHAR)SourceVirtualAddress + AmountToMove;
+
+ LocalBytesTransferred += AmountToMove;
+ SourceCurrentLength -= AmountToMove;
+ DestinationCurrentLength -= AmountToMove;
+
+ }
+
+ }
+
+ *BytesTransferred = LocalBytesTransferred;
+
+ }
+
+ LANCE_DO_DEFERRED(Adapter);
+
+ return NDIS_STATUS_SUCCESS;
+}
diff --git a/private/ntos/ndis/loop/debug.h b/private/ntos/ndis/loop/debug.h
new file mode 100644
index 000000000..932be4267
--- /dev/null
+++ b/private/ntos/ndis/loop/debug.h
@@ -0,0 +1,47 @@
+#ifndef _DEBUG_
+#define _DEBUG_
+
+#if DBG
+ #define DEBUG DBG
+#endif
+//
+// Debug Levels used with DBGPRINT
+
+#define DBG_LEVEL_INFO 0
+#define DBG_LEVEL_WARN 1
+#define DBG_LEVEL_ERR 2
+#define DBG_LEVEL_FATAL 3
+
+// Component Types
+
+#define DBG_COMP_INIT 0x00000001
+#define DBG_COMP_DPC 0x00000002
+#define DBG_COMP_REGISTRY 0x00000004
+#define DBG_COMP_MEMORY 0x00000008
+#define DBG_COMP_SEND 0x00000010
+#define DBG_COMP_REQUEST 0x00000020
+#define DBG_COMP_MISC 0x00000040
+#define DBG_COMP_ALL 0xffffffff
+
+extern LONG LoopDebugLevel;
+extern LONG LoopDebugComponent;
+
+#ifdef DEBUG
+
+ #define DBGPRINT(Component, Level, Fmt) \
+ if ((LoopDebugComponent & Component) && (Level >= LoopDebugLevel)) { \
+ DbgPrint(" *** Loop - "); \
+ DbgPrint Fmt; \
+ }
+
+ #define DBGBREAK(Level) \
+ if (Level >= LoopDebugLevel) { \
+ DbgBreakPoint(); \
+ }
+
+#else
+ #define DBGPRINT(Component, Level, Fmt)
+ #define DBGBREAK(Level)
+#endif
+
+#endif // _DEBUG_
diff --git a/private/ntos/ndis/loop/loop.c b/private/ntos/ndis/loop/loop.c
new file mode 100644
index 000000000..39cfe2332
--- /dev/null
+++ b/private/ntos/ndis/loop/loop.c
@@ -0,0 +1,1378 @@
+#include <ndis.h>
+#include <efilter.h>
+#include <tfilter.h>
+#include <ffilter.h>
+
+#include "debug.h"
+#include "loop.h"
+
+#if DBG
+extern LONG LoopDebugLevel = DBG_LEVEL_FATAL;
+extern LONG LoopDebugComponent = DBG_COMP_ALL;
+#endif
+
+NDIS_STATUS
+LoopAddAdapter(
+ IN NDIS_HANDLE MacAdapterContext,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING AdapterName
+ );
+
+NDIS_STATUS
+LoopCloseAdapter(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+NDIS_STATUS
+LoopOpenAdapter(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT NDIS_HANDLE *MacBindingHandle,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_HANDLE MacAdapterContext,
+ IN UINT OpenOptions,
+ IN PSTRING AddressingOptions OPTIONAL
+ );
+
+VOID
+LoopRemoveAdapter(
+ IN NDIS_HANDLE MacAdapterContext
+ );
+
+NDIS_STATUS
+LoopReset(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+NDIS_STATUS
+LoopTransferData(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+VOID
+LoopUnload(
+ IN NDIS_HANDLE MacMacContext
+ );
+
+
+STATIC
+NDIS_STATUS
+LoopRegisterAdapter(
+ IN NDIS_HANDLE LoopMacHandle,
+ IN PNDIS_STRING AdapterName,
+ IN NDIS_MEDIUM AdapterMedium,
+ IN PVOID NetAddress,
+ IN NDIS_HANDLE ConfigurationHandle
+ );
+
+STATIC
+NDIS_STATUS
+LoopChangeFilter(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+STATIC
+VOID
+LoopCloseAction(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+STATIC
+NDIS_STATUS
+LoopEthChangeAddress(
+ IN UINT OldFilterCount,
+ IN CHAR OldAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN UINT NewFilterCouunt,
+ IN CHAR NewAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+STATIC
+NDIS_STATUS
+LoopTrChangeAddress(
+ IN TR_FUNCTIONAL_ADDRESS OldFunctionalAddresses,
+ IN TR_FUNCTIONAL_ADDRESS NewFunctionalAddresses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+STATIC
+NDIS_STATUS
+LoopFddiChangeAddress(
+ IN UINT OldLongAddressCount,
+ IN CHAR OldLongAddresses[][FDDI_LENGTH_OF_LONG_ADDRESS],
+ IN UINT NewLongAddressCouunt,
+ IN CHAR NewLongAddresses[][FDDI_LENGTH_OF_LONG_ADDRESS],
+ IN UINT OldShortAddressCount,
+ IN CHAR OldShortAddresses[][FDDI_LENGTH_OF_SHORT_ADDRESS],
+ IN UINT NewShortAddressCouunt,
+ IN CHAR NewShortAddresses[][FDDI_LENGTH_OF_SHORT_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+STATIC NDIS_HANDLE LoopWrapperHandle;
+STATIC NDIS_HANDLE LoopMacHandle;
+
+// !! need to verify filters !!
+#define PACKET_FILTER_802_3 0xF07F
+#define PACKET_FILTER_802_5 0xF07F
+#define PACKET_FILTER_DIX 0xF07F
+#define PACKET_FILTER_FDDI 0xF07F
+#define PACKET_FILTER_LTALK 0x8009
+#define PACKET_FILTER_ARCNET 0x8009
+
+static const NDIS_PHYSICAL_ADDRESS physicalConst = NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+{
+ NDIS_STATUS Status;
+ NDIS_MAC_CHARACTERISTICS LoopChar;
+ NDIS_STRING MacName = NDIS_STRING_CONST("LoopBack");
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO, (" --> DriverEntry\n"));
+
+ NdisInitializeWrapper(
+ &LoopWrapperHandle,
+ DriverObject,
+ RegistryPath,
+ NULL
+ );
+
+ LoopChar.MajorNdisVersion = LOOP_NDIS_MAJOR_VERSION;
+ LoopChar.MinorNdisVersion = LOOP_NDIS_MINOR_VERSION;
+ LoopChar.OpenAdapterHandler = LoopOpenAdapter;
+ LoopChar.CloseAdapterHandler = LoopCloseAdapter;
+ LoopChar.RequestHandler = LoopRequest;
+ LoopChar.SendHandler = LoopSend;
+ LoopChar.TransferDataHandler = LoopTransferData;
+ LoopChar.ResetHandler = LoopReset;
+ LoopChar.UnloadMacHandler = LoopUnload;
+ LoopChar.QueryGlobalStatisticsHandler = LoopQueryGlobalStats;
+ LoopChar.AddAdapterHandler = LoopAddAdapter;
+ LoopChar.RemoveAdapterHandler = LoopRemoveAdapter;
+ LoopChar.Name = MacName;
+
+ NdisRegisterMac(
+ &Status,
+ &LoopMacHandle,
+ LoopWrapperHandle,
+ NULL,
+ &LoopChar,
+ sizeof(LoopChar)
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ return STATUS_SUCCESS;
+
+ // Can only get here if something went wrong registering the MAC or
+ // all of the adapters
+ NdisTerminateWrapper(LoopWrapperHandle, DriverObject);
+ return STATUS_UNSUCCESSFUL;
+}
+
+NDIS_STATUS
+LoopAddAdapter(
+ IN NDIS_HANDLE MacAdapterContext,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING AdapterName
+ )
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ NDIS_HANDLE ConfigHandle;
+ PNDIS_CONFIGURATION_PARAMETER Parameter;
+ NDIS_STRING MediumKey = NDIS_STRING_CONST("Medium");
+ PUCHAR NetAddressBuffer[6];
+ PVOID NetAddress;
+ UINT Length;
+ NDIS_MEDIUM AdapterMedium;
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO, (" --> LoopAddAdapter\n"));
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO, ("Reading Config Info\n"));
+
+ // configuration info present, let's get it
+
+ NdisOpenConfiguration(
+ &Status,
+ &ConfigHandle,
+ ConfigurationHandle
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ // would like to log this, but adapter not registered yet
+ DBGPRINT(DBG_COMP_REGISTRY, DBG_LEVEL_FATAL,
+ ("Unable to open configuration database!\n"));
+
+ return Status;
+ }
+
+ NdisReadConfiguration(
+ &Status,
+ &Parameter,
+ ConfigHandle,
+ &MediumKey,
+ NdisParameterInteger
+ );
+
+ AdapterMedium = (NDIS_MEDIUM)Parameter->ParameterData.IntegerData;
+
+ if ((Status != NDIS_STATUS_SUCCESS) ||
+ !((AdapterMedium == NdisMedium802_3) ||
+ (AdapterMedium == NdisMedium802_5) ||
+ (AdapterMedium == NdisMediumFddi) ||
+ (AdapterMedium == NdisMediumLocalTalk) ||
+ (AdapterMedium == NdisMediumArcnet878_2))) {
+
+ // would like to log this, but adapter not registered yet
+ DBGPRINT(DBG_COMP_REGISTRY, DBG_LEVEL_FATAL,
+ ("Unable to find 'Medium' keyword or invalid value!\n"));
+
+ NdisCloseConfiguration(ConfigHandle);
+ return Status;
+ }
+
+ NdisReadNetworkAddress(
+ &Status,
+ &NetAddress,
+ &Length,
+ ConfigHandle
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ // verify the address is appropriate for the specific media and
+ // ensure that the locally administered address bit is set
+
+ switch (AdapterMedium) {
+ case NdisMedium802_3:
+ if ((Length != ETH_LENGTH_OF_ADDRESS) ||
+ ETH_IS_MULTICAST(NetAddress) ||
+ !(((PUCHAR)NetAddress)[0] & 0x02)) { // U/L bit
+ Length = 0;
+ }
+ break;
+ case NdisMedium802_5:
+ if ((Length != TR_LENGTH_OF_ADDRESS) ||
+ (((PUCHAR)NetAddress)[0] & 0x80) || // I/G bit
+ !(((PUCHAR)NetAddress)[0] & 0x40)) { // U/L bit
+ Length = 0;
+ }
+ break;
+ case NdisMediumFddi:
+ if ((Length != FDDI_LENGTH_OF_LONG_ADDRESS) ||
+ (((PUCHAR)NetAddress)[0] & 0x01) || // I/G bit
+ !(((PUCHAR)NetAddress)[0] & 0x02)) { // U/L bit
+ Length = 0;
+ }
+ break;
+ case NdisMediumLocalTalk:
+ if ((Length != 1) || LOOP_LT_IS_BROADCAST(*(PUCHAR)NetAddress)) {
+ Length = 0;
+ }
+ break;
+ case NdisMediumArcnet878_2:
+ if ((Length != 1) || LOOP_ARC_IS_BROADCAST(*(PUCHAR)NetAddress)) {
+ Length = 0;
+ }
+ break;
+ }
+
+ if (Length == 0) {
+ DBGPRINT(DBG_COMP_REGISTRY, DBG_LEVEL_FATAL,
+ ("Invalid NetAddress in registry!\n"));
+ NdisCloseConfiguration(ConfigHandle);
+ return NDIS_STATUS_FAILURE;
+ }
+
+ // have to save away the address as the info may be gone
+ // when we close the registry. we assume the length will
+ // be 6 bytes max
+
+ NdisMoveMemory(
+ NetAddressBuffer,
+ NetAddress,
+ Length
+ );
+ NetAddress = (PVOID)NetAddressBuffer;
+
+ }
+ else
+ NetAddress = NULL;
+
+ NdisCloseConfiguration(ConfigHandle);
+
+ Status = LoopRegisterAdapter(
+ LoopMacHandle,
+ AdapterName,
+ AdapterMedium,
+ NetAddress,
+ ConfigurationHandle
+ );
+ return Status;
+}
+
+NDIS_STATUS
+LoopCloseAdapter(
+ IN NDIS_HANDLE MacBindingHandle
+ )
+{
+ PLOOP_ADAPTER Adapter;
+ PLOOP_OPEN Open;
+ NDIS_STATUS StatusToReturn;
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO, (" --> LoopCloseAdapter\n"));
+
+ Adapter = PLOOP_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ Open = PLOOP_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO,
+ ("Closing Open %lx, reference count = %ld\n",Open,Open->References));
+
+ if (!Open->BindingClosing) {
+
+ Open->BindingClosing = TRUE;
+ RemoveEntryList(&Open->OpenList);
+ Adapter->OpenCount--;
+ Adapter->References--;
+
+ //
+ // shouldn't be called unless there isn't anything running in the
+ // binding. if there is we're hosed.
+ //
+
+ switch (Adapter->Medium) {
+ case NdisMedium802_3:
+ case NdisMediumDix:
+ StatusToReturn = EthDeleteFilterOpenAdapter(
+ Adapter->Filter.Eth,
+ Open->NdisFilterHandle,
+ NULL
+ );
+ // needs to handle pending delete, but should be ok
+ // since our close action routine doesn't pend
+ break;
+ case NdisMedium802_5:
+ StatusToReturn = TrDeleteFilterOpenAdapter(
+ Adapter->Filter.Tr,
+ Open->NdisFilterHandle,
+ NULL
+ );
+ // needs to handle pending delete, but should be ok
+ // since our close action routine doesn't pend
+ break;
+ case NdisMediumFddi:
+ StatusToReturn = FddiDeleteFilterOpenAdapter(
+ Adapter->Filter.Fddi,
+ Open->NdisFilterHandle,
+ NULL
+ );
+ // needs to handle pending delete, but should be ok
+ // since our close action routine doesn't pend
+ break;
+ case NdisMediumLocalTalk:
+ case NdisMediumArcnet878_2:
+ break;
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+
+ NdisFreeMemory(
+ Open,
+ sizeof(LOOP_OPEN),
+ 0
+ );
+
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ }
+ else
+ StatusToReturn = NDIS_STATUS_CLOSING;
+
+ Adapter->References--;
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ return StatusToReturn;
+}
+
+
+NDIS_STATUS
+LoopOpenAdapter(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT NDIS_HANDLE *MacBindingHandle,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_HANDLE MacAdapterContext,
+ IN UINT OpenOptions,
+ IN PSTRING AddressingOptions OPTIONAL
+ )
+{
+ PLOOP_ADAPTER Adapter = PLOOP_ADAPTER_FROM_CONTEXT_HANDLE(MacAdapterContext);
+ PLOOP_OPEN NewOpen;
+ NDIS_STATUS StatusToReturn;
+ UINT i;
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO, (" --> LoopOpenAdapter\n"));
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO,
+ ("Opening binding for Adapter %lx\n",Adapter));
+
+ for (i=0;i < MediumArraySize; i++) {
+ if (MediumArray[i] == Adapter->Medium)
+ break;
+ }
+
+ if (i == MediumArraySize)
+ return NDIS_STATUS_UNSUPPORTED_MEDIA;
+
+ *SelectedMediumIndex = i;
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ NdisAllocateMemory(
+ (PVOID)&NewOpen,
+ sizeof(LOOP_OPEN),
+ 0,
+ physicalConst
+ );
+
+ if (NewOpen != NULL) {
+
+ //
+ // Setup new Open Binding struct
+ //
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO, ("new Open = %lx\n",NewOpen));
+
+ NdisZeroMemory(
+ NewOpen,
+ sizeof(LOOP_OPEN)
+ );
+
+ switch (Adapter->Medium) {
+ case NdisMedium802_3:
+ case NdisMediumDix:
+ StatusToReturn = (NDIS_STATUS)EthNoteFilterOpenAdapter(
+ Adapter->Filter.Eth,
+ NewOpen,
+ NdisBindingContext,
+ &NewOpen->NdisFilterHandle
+ );
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO, ("new EthFilter Open = %lx\n",NewOpen->NdisFilterHandle));
+ break;
+ case NdisMedium802_5:
+ StatusToReturn = (NDIS_STATUS)TrNoteFilterOpenAdapter(
+ Adapter->Filter.Tr,
+ NewOpen,
+ NdisBindingContext,
+ &NewOpen->NdisFilterHandle
+ );
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO, ("new TrFilter Open = %lx\n",NewOpen->NdisFilterHandle));
+ break;
+ case NdisMediumFddi:
+ StatusToReturn = (NDIS_STATUS)FddiNoteFilterOpenAdapter(
+ Adapter->Filter.Fddi,
+ NewOpen,
+ NdisBindingContext,
+ &NewOpen->NdisFilterHandle
+ );
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO, ("new FddiFilter Open = %lx\n",NewOpen->NdisFilterHandle));
+ break;
+ default:
+ StatusToReturn = (NDIS_STATUS)TRUE;
+ break;
+ }
+
+ if (!StatusToReturn) {
+
+ DBGPRINT(DBG_COMP_MEMORY, DBG_LEVEL_ERR,
+ ("unable to create filter for binding %lx\n",NewOpen));
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+
+ NdisFreeMemory(
+ NewOpen,
+ sizeof(LOOP_OPEN),
+ 0);
+
+ Adapter->References--;
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ return NDIS_STATUS_FAILURE;
+ }
+
+ *MacBindingHandle = BINDING_HANDLE_FROM_PLOOP_OPEN(NewOpen);
+
+ InitializeListHead(&NewOpen->OpenList);
+ NewOpen->BindingClosing = FALSE;
+ NewOpen->Flags = 0;
+ NewOpen->NdisBindingContext = NdisBindingContext;
+ NewOpen->OwningLoop = Adapter;
+ NewOpen->References = 1;
+ NewOpen->CurrentLookAhead = LOOP_MAX_LOOKAHEAD;
+ NewOpen->CurrentPacketFilter = 0;
+
+ //
+ // Add the binding to the owning adapter
+ //
+
+ InsertTailList(&Adapter->OpenBindings,&NewOpen->OpenList);
+ Adapter->OpenCount++;
+ Adapter->References++;
+ Adapter->MaxLookAhead = LOOP_MAX_LOOKAHEAD;
+
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ }
+
+ else {
+
+ DBGPRINT(DBG_COMP_MEMORY, DBG_LEVEL_ERR,
+ ("unable to allocate binding struct for adapter %lx\n",Adapter));
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+
+ StatusToReturn = NDIS_STATUS_RESOURCES;
+
+ }
+
+ Adapter->References--;
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ return StatusToReturn;
+}
+
+
+VOID
+LoopRemoveAdapter(
+ IN NDIS_HANDLE MacAdapterContext
+ )
+//
+// All bindings should be closed before this gets called
+//
+{
+ PLOOP_ADAPTER Adapter = PLOOP_ADAPTER_FROM_CONTEXT_HANDLE(MacAdapterContext);
+ BOOLEAN TimerCancel;
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO, (" --> LoopRemoveAdapter\n"));
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO,
+ ("Removing adapter %lx\n",Adapter));
+
+ NdisCancelTimer(&Adapter->LoopTimer,&TimerCancel);
+
+ switch (Adapter->Medium) {
+ case NdisMedium802_3:
+ case NdisMediumDix:
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO,
+ ("deleting EthFilter %lx\n",Adapter->Filter.Eth));
+ EthDeleteFilter(Adapter->Filter.Eth);
+ break;
+ case NdisMedium802_5:
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO,
+ ("deleting TrFilter %lx\n",Adapter->Filter.Tr));
+ TrDeleteFilter(Adapter->Filter.Tr);
+ break;
+ case NdisMediumFddi:
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO,
+ ("deleting FddiFilter %lx\n",Adapter->Filter.Fddi));
+ FddiDeleteFilter(Adapter->Filter.Fddi);
+ break;
+ default:
+ break;
+ }
+
+ NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
+
+ NdisFreeSpinLock(&Adapter->Lock);
+
+ NdisFreeMemory(
+ Adapter->DeviceName.Buffer,
+ Adapter->DeviceNameLength,
+ 0
+ );
+
+ NdisFreeMemory(
+ Adapter,
+ sizeof(LOOP_ADAPTER),
+ 0
+ );
+}
+
+
+NDIS_STATUS
+LoopReset(
+ IN NDIS_HANDLE MacBindingHandle
+ )
+{
+ PLOOP_ADAPTER Adapter = PLOOP_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO, (" --> LoopReset\n"));
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ if (!Adapter->ResetInProgress) {
+
+ PLOOP_OPEN Open = PLOOP_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ if (!Open->BindingClosing) {
+
+ Open->References++;
+
+ //
+ // notify all bindings of beginning of reset
+ //
+ {
+ PLOOP_OPEN Open;
+ PLIST_ENTRY CurrentLink;
+
+ CurrentLink = Adapter->OpenBindings.Flink;
+ while(CurrentLink != &Adapter->OpenBindings) {
+
+ Open = CONTAINING_RECORD(
+ CurrentLink,
+ LOOP_OPEN,
+ OpenList
+ );
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO,
+ ("Signaling reset start to binding %lx\n",Open));
+
+ if (Open->BindingClosing) {
+ CurrentLink = CurrentLink->Flink;
+ continue;
+ }
+ Open->References++;
+ NdisReleaseSpinLock(&Adapter->Lock);
+ NdisIndicateStatus(
+ Open->NdisBindingContext,
+ NDIS_STATUS_RESET_START,
+ NULL,
+ 0
+ );
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Open->References--;
+ CurrentLink = CurrentLink->Flink;
+ }
+ }
+
+ Adapter->ResetInProgress = TRUE;
+
+ //
+ // Loop through the loopback queue and abort any pending sends
+ //
+
+ {
+ PNDIS_PACKET AbortPacket;
+ PLOOP_PACKET_RESERVED Reserved;
+ PLOOP_OPEN Open;
+
+ while (Adapter->Loopback != NULL) {
+
+ AbortPacket = Adapter->Loopback;
+ Reserved = PLOOP_RESERVED_FROM_PACKET(AbortPacket);
+ Adapter->Loopback = Reserved->Next;
+
+ Open = PLOOP_OPEN_FROM_BINDING_HANDLE(Reserved->MacBindingHandle);
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteSend(
+ Open->NdisBindingContext,
+ AbortPacket,
+ NDIS_STATUS_REQUEST_ABORTED
+ );
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Open->References--;
+ }
+
+ Adapter->CurrentLoopback = NULL;
+ Adapter->LastLoopback = NULL;
+ }
+
+ //
+ // notify all bindings of reset end
+ //
+ {
+ PLOOP_OPEN Open;
+ PLIST_ENTRY CurrentLink;
+
+ CurrentLink = Adapter->OpenBindings.Flink;
+ while(CurrentLink != &Adapter->OpenBindings) {
+
+ Open = CONTAINING_RECORD(
+ CurrentLink,
+ LOOP_OPEN,
+ OpenList
+ );
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
+ ("Signaling reset end to binding %lx\n",Open));
+
+ if (Open->BindingClosing) {
+ CurrentLink = CurrentLink->Flink;
+ continue;
+ }
+ Open->References++;
+ NdisReleaseSpinLock(&Adapter->Lock);
+ NdisIndicateStatus(
+ Open->NdisBindingContext,
+ NDIS_STATUS_RESET_END,
+ NULL,
+ 0
+ );
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Open->References--;
+ CurrentLink = CurrentLink->Flink;
+ }
+ }
+
+ Open->References--;
+ Adapter->ResetInProgress = FALSE;
+
+ }
+ else
+ Status = NDIS_STATUS_CLOSING;
+ }
+ else
+ Status = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ Adapter->References--;
+ NdisReleaseSpinLock(&Adapter->Lock);
+ return Status;
+}
+
+
+NDIS_STATUS
+LoopTransferData(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ )
+{
+ PLOOP_ADAPTER Adapter = PLOOP_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+ NDIS_STATUS StatusToReturn;
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO, (" --> LoopTransferData\n"));
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ if (!Adapter->ResetInProgress) {
+ PLOOP_OPEN Open = PLOOP_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ if (!Open->BindingClosing) {
+
+ Open->References++;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ if (MacReceiveContext == NULL) {
+ NdisCopyFromPacketToPacket(
+ Packet,
+ 0,
+ BytesToTransfer,
+ Adapter->CurrentLoopback,
+ ByteOffset+(PLOOP_RESERVED_FROM_PACKET(Adapter->CurrentLoopback)->HeaderLength),
+ BytesTransferred
+ );
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+ }
+ else {
+
+ //
+ // shouldn't get here as we never pass a non-NULL receive context
+ //
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_FATAL,
+ ("transfer data failed! passed a receive context of %lx\n",MacReceiveContext));
+ StatusToReturn = NDIS_STATUS_FAILURE;
+ }
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Open->References--;
+
+ }
+ else
+ StatusToReturn = NDIS_STATUS_REQUEST_ABORTED;
+
+ }
+ else
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ Adapter->References--;
+ NdisReleaseSpinLock(&Adapter->Lock);
+ return StatusToReturn;
+}
+
+
+VOID
+LoopUnload(
+ IN NDIS_HANDLE MacMacContext
+ )
+{
+ NDIS_STATUS Status;
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO, (" --> LoopUnload\n"));
+
+ NdisDeregisterMac(
+ &Status,
+ LoopMacHandle
+ );
+ NdisTerminateWrapper(
+ LoopWrapperHandle,
+ NULL
+ );
+}
+
+STATIC
+NDIS_STATUS
+LoopRegisterAdapter(
+ IN NDIS_HANDLE LoopMacHandle,
+ IN PNDIS_STRING AdapterName,
+ IN NDIS_MEDIUM AdapterMedium,
+ IN PVOID NetAddress,
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+{
+static const MEDIA_INFO MediaParams[] = {
+ /* NdisMedium802_3 */ { 1500, 14, PACKET_FILTER_802_3, 100000},
+ /* NdisMedium802_5 */ { 4082, 14, PACKET_FILTER_802_5, 40000},
+ /* NdisMediumFddi */ { 4486, 13, PACKET_FILTER_FDDI, 1000000},
+ /* NdisMediumWan */ { 0, 0, 0, 0},
+ /* NdisMediumLocalTalk */ { 600, 3, PACKET_FILTER_LTALK, 2300},
+ /* NdisMediumDix */ { 1500, 14, PACKET_FILTER_DIX, 100000},
+ /* NdisMediumArcnetRaw */ { 1512, 3, PACKET_FILTER_ARCNET, 25000},
+ /* NdisMediumArcnet878_2 */ {1512, 3, PACKET_FILTER_ARCNET, 25000} };
+
+ //
+ // Pointer to the adapter
+ //
+ PLOOP_ADAPTER Adapter;
+
+ //
+ // status of various NDIS calls
+ //
+ NDIS_STATUS Status;
+
+ //
+ // info for registering the adapter
+ //
+ NDIS_ADAPTER_INFORMATION AdapterInfo;
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO, (" --> LoopRegisterAdapter\n"));
+
+ //
+ // allocate the adapter block
+ //
+ NdisAllocateMemory(
+ (PVOID)&Adapter,
+ sizeof(LOOP_ADAPTER),
+ 0,
+ physicalConst
+ );
+
+ if (Adapter != NULL) {
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO, ("new Adapter = %lx\n",Adapter));
+
+ NdisZeroMemory(
+ Adapter,
+ sizeof(LOOP_ADAPTER)
+ );
+ Adapter->NdisMacHandle = LoopMacHandle;
+
+ //
+ // allocate memory for the name of the device
+ //
+
+ NdisAllocateMemory(
+ (PVOID)&Adapter->DeviceName.Buffer,
+ AdapterName->Length+2,
+ 0,
+ physicalConst
+ );
+
+ if (Adapter->DeviceName.Buffer != NULL) {
+
+ Adapter->DeviceNameLength = AdapterName->Length+2;
+ Adapter->DeviceName.MaximumLength = AdapterName->Length+2;
+ NdisZeroMemory(
+ Adapter->DeviceName.Buffer,
+ AdapterName->Length+2
+ );
+
+ #ifdef NDIS_NT
+
+ RtlCopyUnicodeString(
+ &Adapter->DeviceName,
+ AdapterName
+ );
+
+ #else
+
+ #error Need to copy a NDIS_STRING.
+
+ #endif
+
+ //
+ // set up the AdapterInfo structure
+ //
+
+ NdisZeroMemory(
+ &AdapterInfo,
+ sizeof(NDIS_ADAPTER_INFORMATION)
+ );
+ AdapterInfo.DmaChannel = 0;
+ AdapterInfo.Master = FALSE;
+ AdapterInfo.Dma32BitAddresses = FALSE;
+ AdapterInfo.AdapterType = NdisInterfaceInternal;
+ AdapterInfo.PhysicalMapRegistersNeeded = 0;
+ AdapterInfo.MaximumPhysicalMapping = 0;
+ AdapterInfo.NumberOfPortDescriptors = 0;
+
+ if ((Status = NdisRegisterAdapter(
+ &Adapter->NdisAdapterHandle,
+ Adapter->NdisMacHandle,
+ Adapter,
+ ConfigurationHandle,
+ AdapterName,
+ &AdapterInfo
+ )) == NDIS_STATUS_SUCCESS) {
+
+ InitializeListHead(&Adapter->OpenBindings);
+ Adapter->OpenCount = 0;
+
+ NdisAllocateSpinLock(&Adapter->Lock);
+ Adapter->InTimerProc = FALSE;
+ Adapter->TimerSet = FALSE;
+ Adapter->References = 1;
+ Adapter->Loopback = NULL;
+ Adapter->LastLoopback = NULL;
+ Adapter->CurrentLoopback = NULL;
+ NdisZeroMemory(
+ &Adapter->LoopBuffer,
+ LOOP_MAX_LOOKAHEAD
+ );
+
+ Adapter->ResetInProgress = FALSE;
+ Adapter->MaxLookAhead = 0;
+
+ Adapter->Medium = AdapterMedium;
+ Adapter->MediumLinkSpeed = MediaParams[(UINT)AdapterMedium].LinkSpeed;
+ Adapter->MediumMinPacketLen = MediaParams[(UINT)AdapterMedium].MacHeaderLen;
+ Adapter->MediumMaxPacketLen = MediaParams[(UINT)AdapterMedium].MacHeaderLen+
+ MediaParams[(UINT)AdapterMedium].MaxFrameLen;
+ Adapter->MediumMacHeaderLen = MediaParams[(UINT)AdapterMedium].MacHeaderLen;
+ Adapter->MediumMaxFrameLen = MediaParams[(UINT)AdapterMedium].MaxFrameLen;
+ Adapter->MediumPacketFilters = MediaParams[(UINT)AdapterMedium].PacketFilters;
+
+ switch (AdapterMedium) {
+ case NdisMedium802_3:
+ case NdisMediumDix:
+
+ NdisMoveMemory(
+ (PVOID)&Adapter->PermanentAddress,
+ LOOP_ETH_CARD_ADDRESS,
+ ETH_LENGTH_OF_ADDRESS
+ );
+
+ if (NetAddress != NULL) {
+ NdisMoveMemory(
+ (PVOID)&Adapter->CurrentAddress,
+ NetAddress,
+ ETH_LENGTH_OF_ADDRESS
+ );
+ }
+ else {
+ NdisMoveMemory(
+ (PVOID)&Adapter->CurrentAddress,
+ LOOP_ETH_CARD_ADDRESS,
+ ETH_LENGTH_OF_ADDRESS
+ );
+ }
+
+ Status = (NDIS_STATUS)EthCreateFilter(
+ LOOP_ETH_MAX_MULTICAST_ADDRESS,
+ LoopEthChangeAddress,
+ LoopChangeFilter,
+ LoopCloseAction,
+ Adapter->CurrentAddress,
+ &Adapter->Lock,
+ &Adapter->Filter.Eth
+ );
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
+ ("new EthFilter = %lx\n",Adapter->Filter.Eth));
+ break;
+
+ case NdisMedium802_5:
+
+ NdisMoveMemory(
+ (PVOID)&Adapter->PermanentAddress,
+ LOOP_TR_CARD_ADDRESS,
+ TR_LENGTH_OF_ADDRESS
+ );
+
+ if (NetAddress != NULL) {
+ NdisMoveMemory(
+ (PVOID)&Adapter->CurrentAddress,
+ NetAddress,
+ TR_LENGTH_OF_ADDRESS
+ );
+ }
+ else {
+ NdisMoveMemory(
+ (PVOID)&Adapter->CurrentAddress,
+ LOOP_TR_CARD_ADDRESS,
+ TR_LENGTH_OF_ADDRESS
+ );
+ }
+
+ Status = (NDIS_STATUS)TrCreateFilter(
+ LoopTrChangeAddress,
+ LoopTrChangeAddress,
+ LoopChangeFilter,
+ LoopCloseAction,
+ Adapter->CurrentAddress,
+ &Adapter->Lock,
+ &Adapter->Filter.Tr
+ );
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
+ ("new TrFilter = %lx\n",Adapter->Filter.Tr));
+ break;
+
+ case NdisMediumFddi:
+
+ // the short address will simply be the first 2
+ // bytes of the long address
+
+ NdisMoveMemory(
+ (PVOID)&Adapter->PermanentAddress,
+ LOOP_FDDI_CARD_ADDRESS,
+ FDDI_LENGTH_OF_LONG_ADDRESS
+ );
+
+ if (NetAddress != NULL) {
+ NdisMoveMemory(
+ (PVOID)&Adapter->CurrentAddress,
+ NetAddress,
+ FDDI_LENGTH_OF_LONG_ADDRESS
+ );
+ }
+ else {
+ NdisMoveMemory(
+ (PVOID)&Adapter->CurrentAddress,
+ LOOP_FDDI_CARD_ADDRESS,
+ FDDI_LENGTH_OF_LONG_ADDRESS
+ );
+ }
+
+ Status = (NDIS_STATUS)FddiCreateFilter(
+ LOOP_FDDI_MAX_MULTICAST_LONG,
+ LOOP_FDDI_MAX_MULTICAST_SHORT,
+ LoopFddiChangeAddress,
+ LoopChangeFilter,
+ LoopCloseAction,
+ Adapter->CurrentAddress,
+ Adapter->CurrentAddress,
+ &Adapter->Lock,
+ &Adapter->Filter.Fddi
+ );
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
+ ("new FddiFilter = %lx\n",Adapter->Filter.Fddi));
+ break;
+
+ case NdisMediumLocalTalk:
+
+ Adapter->PermanentAddress[0] = LOOP_LTALK_CARD_ADDRESS;
+
+ if (NetAddress != NULL)
+ Adapter->CurrentAddress[0] = ((PUCHAR)NetAddress)[0];
+ else
+ Adapter->CurrentAddress[0] = LOOP_LTALK_CARD_ADDRESS;
+
+ // dumb line to satisfy the following status check
+ Status = (NDIS_STATUS)TRUE;
+
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ Adapter->PermanentAddress[0] = LOOP_ARC_CARD_ADDRESS;
+
+ if (NetAddress != NULL)
+ Adapter->CurrentAddress[0] = ((PUCHAR)NetAddress)[0];
+ else
+ Adapter->CurrentAddress[0] = LOOP_ARC_CARD_ADDRESS;
+
+ // dumb line to satisfy the following status check
+ Status = (NDIS_STATUS)TRUE;
+
+ break;
+
+ default:
+ // shouldn't get here...
+ ASSERTMSG("LoopRegisterAdapter: received invalid medium\n",FALSE);
+ break;
+ }
+
+ if (!Status) {
+
+ DBGPRINT(DBG_COMP_MEMORY,DBG_LEVEL_FATAL,
+ ("%wS: Unable to configure media specific information\n",AdapterName));
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 0
+ );
+
+ NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
+
+ NdisFreeSpinLock(&Adapter->Lock);
+
+ NdisFreeMemory(
+ Adapter->DeviceName.Buffer,
+ Adapter->DeviceNameLength,
+ 0
+ );
+
+ NdisFreeMemory(
+ Adapter,
+ sizeof(LOOP_ADAPTER),
+ 0
+ );
+
+ return NDIS_STATUS_FAILURE;
+ }
+
+ NdisInitializeTimer(
+ &(Adapter->LoopTimer),
+ LoopTimerProc,
+ (PVOID)Adapter
+ );
+
+ NdisZeroMemory(
+ &Adapter->GeneralMandatory,
+ GM_ARRAY_SIZE * sizeof(ULONG)
+ );
+
+ return NDIS_STATUS_SUCCESS;
+
+ }
+
+ else {
+
+ //
+ // NdisRegisterAdapter failed
+ //
+
+ DBGPRINT(DBG_COMP_MEMORY,DBG_LEVEL_FATAL,
+ ("%wS: Unable to register adapter, Error = %x\n",AdapterName,Status));
+
+ NdisFreeMemory(
+ Adapter->DeviceName.Buffer,
+ Adapter->DeviceNameLength,
+ 0
+ );
+
+ NdisFreeMemory(
+ Adapter,
+ sizeof(LOOP_ADAPTER),
+ 0
+ );
+
+ return Status;
+ }
+
+ }
+ else {
+
+ //
+ // failed to allocate device name
+ //
+
+ DBGPRINT(DBG_COMP_MEMORY,DBG_LEVEL_FATAL,
+ ("%wS: Unable to allocate the device name\n",AdapterName));
+
+ NdisFreeMemory(
+ Adapter,
+ sizeof(LOOP_ADAPTER),
+ 0
+ );
+
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ }
+
+ else {
+
+ //
+ // failed to allocate Adapter object
+ //
+
+ DBGPRINT(DBG_COMP_MEMORY,DBG_LEVEL_FATAL,
+ ("%wS: Unable to allocate the adapter object\n",AdapterName));
+
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+}
+
+STATIC
+NDIS_STATUS
+LoopChangeFilter(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+{
+ PLOOP_ADAPTER Adapter = PLOOP_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+ NDIS_STATUS StatusToReturn;
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO, (" --> LoopChangeFilter\n"));
+
+ if (!Adapter->ResetInProgress)
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+ else
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ return StatusToReturn;
+}
+
+STATIC
+VOID
+LoopCloseAction(
+ IN NDIS_HANDLE MacBindingHandle
+ )
+{
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO, (" --> LoopCloseAction\n"));
+
+ PLOOP_OPEN_FROM_BINDING_HANDLE(MacBindingHandle)->References--;
+}
+
+STATIC
+NDIS_STATUS
+LoopEthChangeAddress(
+ IN UINT OldFilterCount,
+ IN CHAR OldAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN UINT NewFilterCouunt,
+ IN CHAR NewAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+{
+ PLOOP_ADAPTER Adapter = PLOOP_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+ NDIS_STATUS StatusToReturn;
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO, (" --> LoopEthChangeAddress\n"));
+
+ if (!Adapter->ResetInProgress)
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+ else
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ return StatusToReturn;
+}
+
+STATIC
+NDIS_STATUS
+LoopTrChangeAddress(
+ IN TR_FUNCTIONAL_ADDRESS OldFunctionalAddresses,
+ IN TR_FUNCTIONAL_ADDRESS NewFunctionalAddresses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+{
+ PLOOP_ADAPTER Adapter = PLOOP_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+ NDIS_STATUS StatusToReturn;
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO, (" --> LoopTrChangeAddress\n"));
+
+ if (!Adapter->ResetInProgress)
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+ else
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ return StatusToReturn;
+}
+
+STATIC
+NDIS_STATUS
+LoopFddiChangeAddress(
+ IN UINT OldLongAddressCount,
+ IN CHAR OldLongAddresses[][FDDI_LENGTH_OF_LONG_ADDRESS],
+ IN UINT NewLongAddressCouunt,
+ IN CHAR NewLongAddresses[][FDDI_LENGTH_OF_LONG_ADDRESS],
+ IN UINT OldShortAddressCount,
+ IN CHAR OldShortAddresses[][FDDI_LENGTH_OF_SHORT_ADDRESS],
+ IN UINT NewShortAddressCouunt,
+ IN CHAR NewShortAddresses[][FDDI_LENGTH_OF_SHORT_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+{
+ PLOOP_ADAPTER Adapter = PLOOP_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+ NDIS_STATUS StatusToReturn;
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO, (" --> LoopFddiChangeAddress\n"));
+
+ if (!Adapter->ResetInProgress)
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+ else
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ return StatusToReturn;
+}
diff --git a/private/ntos/ndis/loop/loop.h b/private/ntos/ndis/loop/loop.h
new file mode 100644
index 000000000..6df8f7f80
--- /dev/null
+++ b/private/ntos/ndis/loop/loop.h
@@ -0,0 +1,223 @@
+// STATIC is used for items which will be static in the release build
+// but we want visible for debugging
+
+#if DEVL
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+#define LOOP_MAJOR_VERSION 0x1
+#define LOOP_MINOR_VERSION 0x0
+
+#define LOOP_NDIS_MAJOR_VERSION 0x3
+#define LOOP_NDIS_MINOR_VERSION 0x0
+
+#define LOOP_ETH_CARD_ADDRESS " LOOP "
+#define LOOP_ETH_MAX_MULTICAST_ADDRESS 16
+#define LOOP_TR_CARD_ADDRESS " LOOP "
+#define LOOP_FDDI_CARD_ADDRESS " LOOP "
+#define LOOP_FDDI_MAX_MULTICAST_LONG 16
+#define LOOP_FDDI_MAX_MULTICAST_SHORT 16
+#define LOOP_LTALK_CARD_ADDRESS 0xAB
+#define LOOP_ARC_CARD_ADDRESS 'L'
+// arbitrary maximums...
+#define LOOP_MAX_LOOKAHEAD 256
+#define LOOP_INDICATE_MAXIMUM 256
+
+#define OID_TYPE_MASK 0xFFFF0000
+#define OID_TYPE 0xFF000000
+#define OID_TYPE_GENERAL 0x00000000
+#define OID_TYPE_GENERAL_OPERATIONAL 0x00010000
+#define OID_TYPE_GENERAL_STATISTICS 0x00020000
+#define OID_TYPE_802_3 0x01000000
+#define OID_TYPE_802_3_OPERATIONAL 0x01010000
+#define OID_TYPE_802_3_STATISTICS 0x01020000
+#define OID_TYPE_802_5 0x02000000
+#define OID_TYPE_802_5_OPERATIONAL 0x02010000
+#define OID_TYPE_802_5_STATISTICS 0x02020000
+#define OID_TYPE_FDDI 0x03000000
+#define OID_TYPE_FDDI_OPERATIONAL 0x03010000
+#define OID_TYPE_LTALK 0x05000000
+#define OID_TYPE_LTALK_OPERATIONAL 0x05010000
+#define OID_TYPE_ARCNET 0x06000000
+#define OID_TYPE_ARCNET_OPERATIONAL 0x06010000
+
+#define OID_REQUIRED_MASK 0x0000FF00
+#define OID_REQUIRED_MANDATORY 0x00000100
+#define OID_REQUIRED_OPTIONAL 0x00000200
+
+#define OID_INDEX_MASK 0x000000FF
+
+#define GM_TRANSMIT_GOOD 0x00
+#define GM_RECEIVE_GOOD 0x01
+#define GM_TRANSMIT_BAD 0x02
+#define GM_RECEIVE_BAD 0x03
+#define GM_RECEIVE_NO_BUFFER 0x04
+#define GM_ARRAY_SIZE 0x05
+
+#define LOOP_LT_IS_BROADCAST(Address) \
+ (BOOLEAN)(Address == 0xFF)
+
+#define LOOP_ARC_IS_BROADCAST(Address) \
+ (BOOLEAN)(!(Address))
+
+typedef
+struct _MEDIA_INFO {
+ ULONG MaxFrameLen;
+ UINT MacHeaderLen;
+ ULONG PacketFilters;
+ ULONG LinkSpeed;
+} MEDIA_INFO, *PMEDIA_INFO;
+
+typedef
+struct _LOOP_ADAPTER {
+
+ // this adapter's name
+ NDIS_STRING DeviceName;
+ UINT DeviceNameLength;
+
+ // MP and syncronization variables
+ NDIS_SPIN_LOCK Lock;
+ NDIS_TIMER LoopTimer;
+ BOOLEAN InTimerProc;
+ BOOLEAN TimerSet;
+
+ // reference count
+ UINT References;
+
+ // List of Bindings
+ UINT OpenCount;
+ LIST_ENTRY OpenBindings;
+
+ // the rest of the adapters
+ LIST_ENTRY AdapterList;
+
+ // handles for the adapter and mac driver
+ NDIS_HANDLE NdisMacHandle;
+ NDIS_HANDLE NdisAdapterHandle;
+
+ // loopback params
+ PNDIS_PACKET Loopback;
+ PNDIS_PACKET LastLoopback;
+ PNDIS_PACKET CurrentLoopback;
+ UCHAR LoopBuffer[LOOP_MAX_LOOKAHEAD];
+
+ BOOLEAN ResetInProgress;
+ UINT MaxLookAhead;
+
+ // media specific info
+ UCHAR PermanentAddress[6];
+ UCHAR CurrentAddress[6];
+ NDIS_MEDIUM Medium;
+ ULONG MediumLinkSpeed;
+ ULONG MediumMinPacketLen;
+ ULONG MediumMaxPacketLen;
+ UINT MediumMacHeaderLen;
+ ULONG MediumMaxFrameLen;
+ ULONG MediumPacketFilters;
+ union {
+ PETH_FILTER Eth;
+ PTR_FILTER Tr;
+ PFDDI_FILTER Fddi;
+ } Filter;
+
+ // statistics
+ ULONG GeneralMandatory[GM_ARRAY_SIZE];
+} LOOP_ADAPTER, *PLOOP_ADAPTER;
+
+#define BINDING_OPEN 0x00000001
+#define BINDING_CLOSING 0x00000002
+#define BINDING_RECEIVED_PACKET 0x00000004
+
+typedef
+struct _LOOP_OPEN {
+ LIST_ENTRY OpenList;
+ BOOLEAN BindingClosing;
+ UINT Flags;
+ PLOOP_ADAPTER OwningLoop;
+ NDIS_HANDLE NdisBindingContext;
+ NDIS_HANDLE NdisFilterHandle;
+ UINT References;
+ UINT CurrentLookAhead;
+ UINT CurrentPacketFilter;
+} LOOP_OPEN, *PLOOP_OPEN;
+
+typedef struct _LOOP_PACKET_RESERVED {
+ PNDIS_PACKET Next;
+ NDIS_HANDLE MacBindingHandle;
+ USHORT PacketLength;
+ UCHAR HeaderLength;
+} LOOP_PACKET_RESERVED, *PLOOP_PACKET_RESERVED;
+
+//
+// Given a MacBindingHandle this macro returns a pointer to the
+// LOOP_ADAPTER.
+//
+#define PLOOP_ADAPTER_FROM_BINDING_HANDLE(Handle) \
+ (((PLOOP_OPEN)((PVOID)(Handle)))->OwningLoop)
+
+//
+// Given a MacContextHandle return the PLOOP_ADAPTER
+// it represents.
+//
+#define PLOOP_ADAPTER_FROM_CONTEXT_HANDLE(Handle) \
+ ((PLOOP_ADAPTER)((PVOID)(Handle)))
+
+//
+// Given a pointer to a LOOP_ADAPTER return the
+// proper MacContextHandle.
+//
+#define CONTEXT_HANDLE_FROM_PLOOP_ADAPTER(Ptr) \
+ ((NDIS_HANDLE)((PVOID)(Ptr)))
+
+//
+// This macro returns a pointer to a PLOOP_OPEN given a MacBindingHandle.
+//
+#define PLOOP_OPEN_FROM_BINDING_HANDLE(Handle) \
+ ((PLOOP_OPEN)((PVOID)Handle))
+
+//
+// This macro returns a NDIS_HANDLE from a PLOOP_OPEN
+//
+#define BINDING_HANDLE_FROM_PLOOP_OPEN(Open) \
+ ((NDIS_HANDLE)((PVOID)Open))
+
+//
+// This macro returns a pointer to the LOOP reserved portion of the packet
+//
+#define PLOOP_RESERVED_FROM_PACKET(Packet) \
+ ((PLOOP_PACKET_RESERVED)((PVOID)((Packet)->MacReserved)))
+
+#define PLOOP_PACKET_FROM_RESERVED(Reserved) \
+ ((PNDIS_PACKET)((PVOID)((Reserved)->Packet)))
+
+extern
+NDIS_STATUS
+LoopQueryGlobalStats(
+ IN NDIS_HANDLE MacBindingContext,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+extern
+NDIS_STATUS
+LoopRequest(
+ IN NDIS_HANDLE MacBindingContext,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+extern
+NDIS_STATUS
+LoopSend(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_PACKET Packet
+ );
+
+extern
+VOID
+LoopTimerProc(
+ IN PVOID SystemSpecific1,
+ IN PVOID Context,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
diff --git a/private/ntos/ndis/loop/loop.rc b/private/ntos/ndis/loop/loop.rc
new file mode 100644
index 000000000..5761474d9
--- /dev/null
+++ b/private/ntos/ndis/loop/loop.rc
@@ -0,0 +1,39 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "Loopback network driver"
+#define VER_INTERNALNAME_STR "LOOP.SYS"
+#define VER_ORIGINALFILENAME_STR "LOOP.SYS"
+
+#include "common.ver"
+
diff --git a/private/ntos/ndis/loop/makefile b/private/ntos/ndis/loop/makefile
new file mode 100644
index 000000000..677d610db
--- /dev/null
+++ b/private/ntos/ndis/loop/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/loop/request.c b/private/ntos/ndis/loop/request.c
new file mode 100644
index 000000000..e0bc9e151
--- /dev/null
+++ b/private/ntos/ndis/loop/request.c
@@ -0,0 +1,1255 @@
+#include <ndis.h>
+#include <efilter.h>
+#include <tfilter.h>
+#include <ffilter.h>
+
+#include "debug.h"
+#include "loop.h"
+
+STATIC NDIS_OID LoopGlobalSupportedOids[] = {
+
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+
+ OID_802_3_RCV_ERROR_ALIGNMENT,
+ OID_802_3_XMIT_ONE_COLLISION,
+ OID_802_3_XMIT_MORE_COLLISIONS,
+
+ OID_802_5_PERMANENT_ADDRESS,
+ OID_802_5_CURRENT_ADDRESS,
+ OID_802_5_CURRENT_FUNCTIONAL,
+ OID_802_5_CURRENT_GROUP,
+ OID_802_5_LAST_OPEN_STATUS,
+ OID_802_5_CURRENT_RING_STATUS,
+ OID_802_5_CURRENT_RING_STATE,
+
+ OID_802_5_LINE_ERRORS,
+ OID_802_5_LOST_FRAMES,
+
+ OID_FDDI_LONG_PERMANENT_ADDR,
+ OID_FDDI_LONG_CURRENT_ADDR,
+ OID_FDDI_LONG_MULTICAST_LIST,
+ OID_FDDI_LONG_MAX_LIST_SIZE,
+ OID_FDDI_SHORT_PERMANENT_ADDR,
+ OID_FDDI_SHORT_CURRENT_ADDR,
+ OID_FDDI_SHORT_MULTICAST_LIST,
+ OID_FDDI_SHORT_MAX_LIST_SIZE,
+
+ OID_LTALK_CURRENT_NODE_ID,
+
+ OID_ARCNET_PERMANENT_ADDRESS,
+ OID_ARCNET_CURRENT_ADDRESS
+
+ };
+
+
+STATIC NDIS_OID LoopProtocolSupportedOids[] = {
+
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+
+ OID_802_5_PERMANENT_ADDRESS,
+ OID_802_5_CURRENT_ADDRESS,
+ OID_802_5_CURRENT_FUNCTIONAL,
+ OID_802_5_CURRENT_GROUP,
+
+ OID_FDDI_LONG_PERMANENT_ADDR,
+ OID_FDDI_LONG_CURRENT_ADDR,
+ OID_FDDI_LONG_MULTICAST_LIST,
+ OID_FDDI_LONG_MAX_LIST_SIZE,
+ OID_FDDI_SHORT_PERMANENT_ADDR,
+ OID_FDDI_SHORT_CURRENT_ADDR,
+ OID_FDDI_SHORT_MULTICAST_LIST,
+ OID_FDDI_SHORT_MAX_LIST_SIZE,
+
+ OID_LTALK_CURRENT_NODE_ID,
+
+ OID_ARCNET_PERMANENT_ADDRESS,
+ OID_ARCNET_CURRENT_ADDRESS
+
+ };
+
+STATIC
+NDIS_STATUS
+LoopQueryInformation(
+ IN PLOOP_ADAPTER Adapter,
+ IN PLOOP_OPEN Open,
+ IN NDIS_OID Oid,
+ IN BOOLEAN Global,
+ IN PVOID InformationBuffer,
+ IN UINT InformationBufferLength,
+ OUT PUINT BytesWritten,
+ OUT PUINT BytesNeeded
+ );
+
+STATIC
+NDIS_STATUS
+LoopSetInformation(
+ IN PLOOP_ADAPTER Adapter,
+ IN PLOOP_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+STATIC
+VOID
+LoopAdjustLookahead(
+ IN PLOOP_ADAPTER Adapter
+ );
+
+STATIC
+ULONG
+LoopQueryPacketFilter(
+ IN PLOOP_ADAPTER Adapter
+ );
+
+
+NDIS_STATUS
+LoopRequest(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+{
+ PLOOP_ADAPTER Adapter = PLOOP_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+ NDIS_STATUS StatusToReturn;
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO, (" --> LoopRequest\n"));
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ if (! Adapter->ResetInProgress) {
+ PLOOP_OPEN Open;
+
+ Open = PLOOP_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO, ("Request from binding %lx\n",Open));
+
+ if (! Open->BindingClosing) {
+
+ switch (NdisRequest->RequestType) {
+
+ case NdisRequestSetInformation:
+
+ Open->References++;
+ StatusToReturn = LoopSetInformation(
+ Adapter,
+ Open,
+ NdisRequest
+ );
+ Open->References--;
+ break;
+
+ case NdisRequestQueryInformation:
+
+ Open->References++;
+ StatusToReturn = LoopQueryInformation(
+ Adapter,
+ Open,
+ NdisRequest->DATA.QUERY_INFORMATION.Oid,
+ FALSE,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &(NdisRequest->DATA.QUERY_INFORMATION.BytesWritten),
+ &(NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded)
+ );
+ Open->References--;
+ break;
+
+ default:
+
+ // Unkown request
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+ } else {
+ StatusToReturn = NDIS_STATUS_CLOSING;
+ }
+ } else
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ Adapter->References--;
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ return StatusToReturn;
+}
+
+NDIS_STATUS
+LoopQueryGlobalStats(
+ IN NDIS_HANDLE MacAdapterContext,
+ IN PNDIS_REQUEST NdisRequest
+ )
+{
+ NDIS_STATUS StatusToReturn;
+ PLOOP_ADAPTER Adapter = PLOOP_ADAPTER_FROM_CONTEXT_HANDLE(MacAdapterContext);
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO, (" --> LoopQueryGlobalStats\n"));
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO, ("Request from adapter %lx\n",Adapter));
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ if (! Adapter->ResetInProgress) {
+
+ if (NdisRequest->RequestType == NdisRequestQueryStatistics) {
+
+ StatusToReturn = LoopQueryInformation(
+ Adapter,
+ NULL,
+ NdisRequest->DATA.QUERY_INFORMATION.Oid,
+ TRUE,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &(NdisRequest->DATA.QUERY_INFORMATION.BytesWritten),
+ &(NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded)
+ );
+ }
+ else
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+
+ } else
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ Adapter->References--;
+ NdisReleaseSpinLock(&Adapter->Lock);
+ return StatusToReturn;
+
+}
+
+STATIC
+NDIS_STATUS
+LoopSetInformation(
+ IN PLOOP_ADAPTER Adapter,
+ IN PLOOP_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest
+ )
+{
+ NDIS_STATUS StatusToReturn;
+ ULONG PacketFilter, CurrentLookahead;
+ NDIS_OID Oid = NdisRequest->DATA.SET_INFORMATION.Oid;
+ PVOID InformationBuffer = NdisRequest->DATA.SET_INFORMATION.InformationBuffer;
+ INT InformationBufferLength = NdisRequest->DATA.SET_INFORMATION.InformationBufferLength;
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO, (" --> LoopSetInformation\n"));
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ //
+ // Now check for the most common OIDs
+ //
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO, ("OID = %lx\n",Oid));
+ switch (Oid) {
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ if (InformationBufferLength != 4) {
+
+ StatusToReturn = NDIS_STATUS_INVALID_DATA;
+ break;
+
+ } else {
+
+ NdisMoveMemory(
+ (PVOID)&PacketFilter,
+ InformationBuffer,
+ sizeof(ULONG)
+ );
+ }
+
+ switch (Adapter->Medium) {
+ case NdisMedium802_3:
+ case NdisMediumDix:
+
+ StatusToReturn = EthFilterAdjust(
+ Adapter->Filter.Eth,
+ Open->NdisFilterHandle,
+ NdisRequest,
+ PacketFilter,
+ TRUE
+ );
+ break;
+
+ case NdisMedium802_5:
+
+ StatusToReturn = TrFilterAdjust(
+ Adapter->Filter.Tr,
+ Open->NdisFilterHandle,
+ NdisRequest,
+ PacketFilter,
+ TRUE
+ );
+ break;
+
+ case NdisMediumFddi:
+
+ StatusToReturn = FddiFilterAdjust(
+ Adapter->Filter.Fddi,
+ Open->NdisFilterHandle,
+ NdisRequest,
+ PacketFilter,
+ TRUE
+ );
+ break;
+
+ default:
+
+ if (PacketFilter == (PacketFilter & Adapter->MediumPacketFilters)) {
+
+ Open->CurrentPacketFilter = PacketFilter;
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ } else
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+
+ break;
+ }
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = InformationBufferLength;
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ if (InformationBufferLength != 4) {
+
+ StatusToReturn = NDIS_STATUS_INVALID_DATA;
+ break;
+
+ }
+
+ NdisMoveMemory(
+ (PVOID)&CurrentLookahead,
+ InformationBuffer,
+ sizeof(ULONG)
+ );
+
+ if (CurrentLookahead > LOOP_MAX_LOOKAHEAD) {
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+ break;
+
+ }
+
+ if (CurrentLookahead >= Adapter->MaxLookAhead)
+ Adapter->MaxLookAhead = CurrentLookahead;
+ else {
+ if (Open->CurrentLookAhead == Adapter->MaxLookAhead)
+ LoopAdjustLookahead(Adapter);
+ }
+
+ Open->CurrentLookAhead = CurrentLookahead;
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 4;
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+
+ if (Adapter->Medium != NdisMedium802_3) {
+ StatusToReturn = NDIS_STATUS_INVALID_OID;
+ break;
+ }
+
+ if ((InformationBufferLength % ETH_LENGTH_OF_ADDRESS) != 0) {
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ StatusToReturn = EthChangeFilterAddresses(
+ Adapter->Filter.Eth,
+ Open->NdisFilterHandle,
+ NdisRequest,
+ (UINT)(InformationBufferLength/ETH_LENGTH_OF_ADDRESS),
+ InformationBuffer,
+ TRUE
+ );
+
+ break;
+
+ case OID_802_5_CURRENT_FUNCTIONAL:
+
+ if (Adapter->Medium != NdisMedium802_5) {
+ StatusToReturn = NDIS_STATUS_INVALID_OID;
+ break;
+ }
+
+ if (InformationBufferLength != TR_LENGTH_OF_FUNCTIONAL) {
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ StatusToReturn = TrChangeFunctionalAddress(
+ Adapter->Filter.Tr,
+ Open->NdisFilterHandle,
+ NdisRequest,
+ InformationBuffer,
+ TRUE
+ );
+
+ break;
+
+ case OID_802_5_CURRENT_GROUP:
+
+ if (Adapter->Medium != NdisMedium802_5) {
+ StatusToReturn = NDIS_STATUS_INVALID_OID;
+ break;
+ }
+
+ if (InformationBufferLength != TR_LENGTH_OF_FUNCTIONAL) {
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ StatusToReturn = TrChangeGroupAddress(
+ Adapter->Filter.Tr,
+ Open->NdisFilterHandle,
+ NdisRequest,
+ InformationBuffer,
+ TRUE
+ );
+
+ break;
+
+ case OID_FDDI_LONG_MULTICAST_LIST:
+
+ if (Adapter->Medium != NdisMediumFddi) {
+ StatusToReturn = NDIS_STATUS_INVALID_OID;
+ break;
+ }
+
+ if ((InformationBufferLength % FDDI_LENGTH_OF_LONG_ADDRESS) != 0) {
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ StatusToReturn = FddiChangeFilterLongAddresses(
+ Adapter->Filter.Fddi,
+ Open->NdisFilterHandle,
+ NdisRequest,
+ (UINT)(InformationBufferLength/FDDI_LENGTH_OF_LONG_ADDRESS),
+ InformationBuffer,
+ TRUE
+ );
+
+ break;
+
+ case OID_FDDI_SHORT_MULTICAST_LIST:
+
+ if (Adapter->Medium != NdisMediumFddi) {
+ StatusToReturn = NDIS_STATUS_INVALID_OID;
+ break;
+ }
+
+ if ((InformationBufferLength % FDDI_LENGTH_OF_SHORT_ADDRESS) != 0) {
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ StatusToReturn = FddiChangeFilterShortAddresses(
+ Adapter->Filter.Fddi,
+ Open->NdisFilterHandle,
+ NdisRequest,
+ (UINT)(InformationBufferLength/FDDI_LENGTH_OF_SHORT_ADDRESS),
+ InformationBuffer,
+ TRUE
+ );
+
+ break;
+
+ case OID_GEN_PROTOCOL_OPTIONS:
+
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ break;
+
+ default:
+
+ StatusToReturn = NDIS_STATUS_INVALID_OID;
+ break;
+
+ }
+ return(StatusToReturn);
+
+}
+
+STATIC
+NDIS_STATUS
+LoopQueryInformation(
+ IN PLOOP_ADAPTER Adapter,
+ IN PLOOP_OPEN Open,
+ IN NDIS_OID Oid,
+ IN BOOLEAN Global,
+ IN PVOID InformationBuffer,
+ IN UINT InformationBufferLength,
+ OUT PUINT BytesWritten,
+ OUT PUINT BytesNeeded
+ )
+{
+
+ INT i;
+ PNDIS_OID SupportedOidArray;
+ INT SupportedOids;
+ PVOID SourceBuffer;
+ UINT SourceBufferLength;
+ ULONG GenericUlong;
+ USHORT GenericUshort;
+ static UCHAR VendorDescription[] = "MS LoopBack Driver";
+ static UCHAR VendorId[3] = {0xFF, 0xFF, 0xFF};
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO, (" --> LoopQueryInformation\n"));
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("OID = %lx, Global = %c\n",Oid,(Global)?'Y':'N'));
+
+ //
+ // Check that the OID is valid.
+ //
+
+ if (Global) {
+ SupportedOidArray = LoopGlobalSupportedOids;
+ SupportedOids = sizeof(LoopGlobalSupportedOids)/sizeof(ULONG);
+ }
+ else {
+ SupportedOidArray = LoopProtocolSupportedOids;
+ SupportedOids = sizeof(LoopProtocolSupportedOids)/sizeof(ULONG);
+ }
+
+ for (i=0; i<SupportedOids; i++) {
+ if (Oid == SupportedOidArray[i])
+ break;
+ }
+
+ if ((i == SupportedOids) || (((Oid & OID_TYPE) != OID_TYPE_GENERAL) &&
+ (((Adapter->Medium == NdisMedium802_3) && ((Oid & OID_TYPE) != OID_TYPE_802_3)) ||
+ ((Adapter->Medium == NdisMedium802_5) && ((Oid & OID_TYPE) != OID_TYPE_802_5)) ||
+ ((Adapter->Medium == NdisMediumFddi) && ((Oid & OID_TYPE) != OID_TYPE_FDDI)) ||
+ ((Adapter->Medium == NdisMediumLocalTalk) && ((Oid & OID_TYPE) != OID_TYPE_LTALK)) ||
+ ((Adapter->Medium == NdisMediumArcnet878_2) && ((Oid & OID_TYPE) != OID_TYPE_ARCNET))))) {
+ *BytesWritten = 0;
+ return NDIS_STATUS_INVALID_OID;
+ }
+
+ //
+ // Initialize these once, since this is the majority
+ // of cases.
+ //
+
+ SourceBuffer = (PVOID)&GenericUlong;
+ SourceBufferLength = sizeof(ULONG);
+
+ switch (Oid & OID_TYPE_MASK) {
+
+ case OID_TYPE_GENERAL_OPERATIONAL:
+
+ switch (Oid) {
+
+ case OID_GEN_MAC_OPTIONS:
+
+ GenericUlong = (ULONG)(0);
+
+ break;
+
+ case OID_GEN_SUPPORTED_LIST:
+
+ SourceBuffer = SupportedOidArray;
+ SourceBufferLength = SupportedOids * sizeof(ULONG);
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+
+ if (Adapter->ResetInProgress)
+ GenericUlong = NdisHardwareStatusReset;
+ else
+ GenericUlong = NdisHardwareStatusReady;
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+
+ GenericUlong = Adapter->Medium;
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+
+ GenericUlong = LOOP_MAX_LOOKAHEAD;
+ break;
+
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+
+ GenericUlong = Adapter->MediumMaxFrameLen;
+ break;
+
+ case OID_GEN_LINK_SPEED:
+
+ GenericUlong = Adapter->MediumLinkSpeed;
+ break;
+
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+
+ GenericUlong = Adapter->MediumMaxPacketLen;
+ break;
+
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+
+ GenericUlong = Adapter->MediumMaxPacketLen;
+ break;
+
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+
+ GenericUlong = 1;
+ break;
+
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+
+ GenericUlong = 1;
+ break;
+
+ case OID_GEN_VENDOR_ID:
+
+ SourceBuffer = VendorId;
+ SourceBufferLength = sizeof(VendorId);
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+
+ SourceBuffer = VendorDescription;
+ SourceBufferLength = sizeof(VendorDescription);
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ switch (Adapter->Medium) {
+ case NdisMedium802_3:
+ case NdisMediumDix:
+ if (Global)
+ GenericUlong = ETH_QUERY_FILTER_CLASSES(Adapter->Filter.Eth);
+ else
+ GenericUlong = ETH_QUERY_PACKET_FILTER(Adapter->Filter.Eth,
+ Open->NdisFilterHandle);
+ break;
+ case NdisMedium802_5:
+ if (Global)
+ GenericUlong = TR_QUERY_FILTER_CLASSES(Adapter->Filter.Tr);
+ else
+ GenericUlong = TR_QUERY_PACKET_FILTER(Adapter->Filter.Tr,
+ Open->NdisFilterHandle);
+ break;
+ case NdisMediumFddi:
+ if (Global)
+ GenericUlong = FDDI_QUERY_FILTER_CLASSES(Adapter->Filter.Fddi);
+ else
+ GenericUlong = FDDI_QUERY_PACKET_FILTER(Adapter->Filter.Fddi,
+ Open->NdisFilterHandle);
+ break;
+ default:
+ if (Global)
+ GenericUlong = LoopQueryPacketFilter(Adapter);
+ else
+ GenericUlong = Open->CurrentPacketFilter;
+ break;
+ }
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ if (Global)
+ GenericUlong = Adapter->MaxLookAhead;
+ else
+ GenericUlong = Open->CurrentLookAhead;
+ break;
+
+ case OID_GEN_DRIVER_VERSION:
+
+ GenericUshort = (LOOP_MAJOR_VERSION << 8) + LOOP_MINOR_VERSION;
+ SourceBuffer = &GenericUshort;
+ SourceBufferLength = sizeof(USHORT);
+ break;
+
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+
+ GenericUlong = Adapter->MediumMaxPacketLen;
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+
+ break;
+
+ case OID_TYPE_GENERAL_STATISTICS:
+
+ if (Global) {
+
+ NDIS_OID MaskOid = (Oid & OID_INDEX_MASK) - 1;
+
+ switch (Oid & OID_REQUIRED_MASK) {
+
+ case OID_REQUIRED_MANDATORY:
+
+ ASSERT (MaskOid < GM_ARRAY_SIZE);
+
+ GenericUlong = Adapter->GeneralMandatory[MaskOid];
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+
+ } else {
+
+ //
+ // None of the general stats are available per-open.
+ //
+
+ ASSERT(FALSE);
+
+ }
+
+ break;
+
+ case OID_TYPE_802_3_OPERATIONAL:
+
+ switch (Oid) {
+
+ case OID_802_3_PERMANENT_ADDRESS:
+
+ SourceBuffer = Adapter->PermanentAddress;
+ SourceBufferLength = ETH_LENGTH_OF_ADDRESS;
+ break;
+ case OID_802_3_CURRENT_ADDRESS:
+
+ SourceBuffer = Adapter->CurrentAddress;
+ SourceBufferLength = ETH_LENGTH_OF_ADDRESS;
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+
+ {
+ NDIS_STATUS StatusToReturn;
+ UINT NumAddresses;
+
+ if (Global) {
+
+ NumAddresses = ETH_NUMBER_OF_GLOBAL_FILTER_ADDRESSES(Adapter->Filter.Eth);
+ if ((NumAddresses * ETH_LENGTH_OF_ADDRESS) > InformationBufferLength) {
+
+ *BytesNeeded = (NumAddresses * ETH_LENGTH_OF_ADDRESS);
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ }
+
+ EthQueryGlobalFilterAddresses(
+ &StatusToReturn,
+ Adapter->Filter.Eth,
+ InformationBufferLength,
+ &NumAddresses,
+ InformationBuffer
+ );
+
+ } else {
+
+ NumAddresses = EthNumberOfOpenFilterAddresses(
+ Adapter->Filter.Eth,
+ Open->NdisFilterHandle
+ );
+
+ if ((NumAddresses * ETH_LENGTH_OF_ADDRESS) > InformationBufferLength) {
+
+ *BytesNeeded = (NumAddresses * ETH_LENGTH_OF_ADDRESS);
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ }
+
+ EthQueryOpenFilterAddresses(
+ &StatusToReturn,
+ Adapter->Filter.Eth,
+ Open->NdisFilterHandle,
+ InformationBufferLength,
+ &NumAddresses,
+ InformationBuffer
+ );
+ }
+
+ //
+ // Should not be an error since we held the spinlock
+ // nothing should have changed.
+ //
+
+ ASSERT(StatusToReturn == NDIS_STATUS_SUCCESS);
+
+ *BytesWritten = NumAddresses * ETH_LENGTH_OF_ADDRESS;
+
+ }
+
+ return NDIS_STATUS_SUCCESS;
+
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+
+ GenericUlong = LOOP_ETH_MAX_MULTICAST_ADDRESS;
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+ break;
+
+ case OID_TYPE_802_3_STATISTICS:
+
+ switch (Oid) {
+
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+ case OID_802_3_XMIT_ONE_COLLISION:
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+
+ GenericUlong = 0;
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+ break;
+
+ case OID_TYPE_802_5_OPERATIONAL:
+
+ switch (Oid) {
+
+ case OID_802_5_PERMANENT_ADDRESS:
+
+ SourceBuffer = Adapter->PermanentAddress;
+ SourceBufferLength = TR_LENGTH_OF_ADDRESS;
+ break;
+
+ case OID_802_5_CURRENT_ADDRESS:
+
+ SourceBuffer = Adapter->CurrentAddress;
+ SourceBufferLength = TR_LENGTH_OF_ADDRESS;
+ break;
+
+ case OID_802_5_CURRENT_FUNCTIONAL:
+
+ if (Global)
+ GenericUlong = TR_QUERY_FILTER_ADDRESSES(Adapter->Filter.Tr);
+ else
+ GenericUlong = TR_QUERY_FILTER_BINDING_ADDRESS(
+ Adapter->Filter.Tr,
+ Open->NdisFilterHandle);
+
+ GenericUlong = (ULONG)(((GenericUlong >> 24) & 0xFF) |
+ ((GenericUlong >> 8) & 0xFF00) |
+ ((GenericUlong << 8) & 0xFF0000) |
+ ((GenericUlong << 24) & 0xFF000000));
+ break;
+
+ case OID_802_5_CURRENT_GROUP:
+
+ GenericUlong = TR_QUERY_FILTER_Group(Adapter->Filter.Tr);
+
+ GenericUlong = (ULONG)(((GenericUlong >> 24) & 0xFF) |
+ ((GenericUlong >> 8) & 0xFF00) |
+ ((GenericUlong << 8) & 0xFF0000) |
+ ((GenericUlong << 24) & 0xFF000000));
+ break;
+
+ case OID_802_5_LAST_OPEN_STATUS:
+
+ // just return 0 since we never return NDIS_STATUS_OPEN_ERROR
+
+ GenericUlong = 0;
+ break;
+
+ case OID_802_5_CURRENT_RING_STATUS:
+
+ // need to verify validity
+
+ GenericUlong = NDIS_RING_SINGLE_STATION;
+ break;
+
+ case OID_802_5_CURRENT_RING_STATE:
+
+ // might want to return NdisRingStateClosed if there are no bindings
+
+ GenericUlong = NdisRingStateOpened;
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+ break;
+
+ case OID_TYPE_802_5_STATISTICS:
+
+ switch (Oid) {
+
+ case OID_802_5_LINE_ERRORS:
+ case OID_802_5_LOST_FRAMES:
+
+ GenericUlong = 0;
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+ break;
+
+ case OID_TYPE_FDDI_OPERATIONAL:
+
+ switch (Oid) {
+
+ case OID_FDDI_LONG_PERMANENT_ADDR:
+
+ SourceBuffer = Adapter->PermanentAddress;
+ SourceBufferLength = FDDI_LENGTH_OF_LONG_ADDRESS;
+ break;
+
+ case OID_FDDI_LONG_CURRENT_ADDR:
+
+ SourceBuffer = Adapter->CurrentAddress;
+ SourceBufferLength = FDDI_LENGTH_OF_LONG_ADDRESS;
+ break;
+
+ case OID_FDDI_LONG_MULTICAST_LIST:
+
+ {
+ NDIS_STATUS StatusToReturn;
+ UINT NumAddresses;
+
+ if (Global) {
+
+ NumAddresses = FDDI_NUMBER_OF_GLOBAL_FILTER_LONG_ADDRESSES(Adapter->Filter.Fddi);
+ if ((NumAddresses * FDDI_LENGTH_OF_LONG_ADDRESS) > InformationBufferLength) {
+
+ *BytesNeeded = (NumAddresses * FDDI_LENGTH_OF_LONG_ADDRESS);
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ }
+
+ FddiQueryGlobalFilterLongAddresses(
+ &StatusToReturn,
+ Adapter->Filter.Fddi,
+ InformationBufferLength,
+ &NumAddresses,
+ InformationBuffer
+ );
+
+ } else {
+
+ NumAddresses = FddiNumberOfOpenFilterLongAddresses(
+ Adapter->Filter.Fddi,
+ Open->NdisFilterHandle
+ );
+
+ if ((NumAddresses * FDDI_LENGTH_OF_LONG_ADDRESS) > InformationBufferLength) {
+
+ *BytesNeeded = (NumAddresses * FDDI_LENGTH_OF_LONG_ADDRESS);
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ }
+
+ FddiQueryOpenFilterLongAddresses(
+ &StatusToReturn,
+ Adapter->Filter.Fddi,
+ Open->NdisFilterHandle,
+ InformationBufferLength,
+ &NumAddresses,
+ InformationBuffer
+ );
+ }
+
+ //
+ // Should not be an error since we held the spinlock
+ // nothing should have changed.
+ //
+
+ ASSERT(StatusToReturn == NDIS_STATUS_SUCCESS);
+
+ *BytesWritten = NumAddresses * FDDI_LENGTH_OF_LONG_ADDRESS;
+
+ }
+
+ return NDIS_STATUS_SUCCESS;
+
+ break;
+
+ case OID_FDDI_LONG_MAX_LIST_SIZE:
+
+ GenericUlong = LOOP_FDDI_MAX_MULTICAST_LONG;
+ break;
+
+ case OID_FDDI_SHORT_PERMANENT_ADDR:
+
+ SourceBuffer = Adapter->PermanentAddress;
+ SourceBufferLength = FDDI_LENGTH_OF_SHORT_ADDRESS;
+ break;
+
+ case OID_FDDI_SHORT_CURRENT_ADDR:
+
+ SourceBuffer = Adapter->CurrentAddress;
+ SourceBufferLength = FDDI_LENGTH_OF_SHORT_ADDRESS;
+ break;
+
+ case OID_FDDI_SHORT_MULTICAST_LIST:
+
+ {
+ NDIS_STATUS StatusToReturn;
+ UINT NumAddresses;
+
+ if (Global) {
+
+ NumAddresses = FDDI_NUMBER_OF_GLOBAL_FILTER_SHORT_ADDRESSES(Adapter->Filter.Fddi);
+ if ((NumAddresses * FDDI_LENGTH_OF_SHORT_ADDRESS) > InformationBufferLength) {
+
+ *BytesNeeded = (NumAddresses * FDDI_LENGTH_OF_SHORT_ADDRESS);
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ }
+
+ FddiQueryGlobalFilterShortAddresses(
+ &StatusToReturn,
+ Adapter->Filter.Fddi,
+ InformationBufferLength,
+ &NumAddresses,
+ InformationBuffer
+ );
+
+ } else {
+
+ NumAddresses = FddiNumberOfOpenFilterShortAddresses(
+ Adapter->Filter.Fddi,
+ Open->NdisFilterHandle
+ );
+
+ if ((NumAddresses * FDDI_LENGTH_OF_SHORT_ADDRESS) > InformationBufferLength) {
+
+ *BytesNeeded = (NumAddresses * FDDI_LENGTH_OF_SHORT_ADDRESS);
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ }
+
+ FddiQueryOpenFilterShortAddresses(
+ &StatusToReturn,
+ Adapter->Filter.Fddi,
+ Open->NdisFilterHandle,
+ InformationBufferLength,
+ &NumAddresses,
+ InformationBuffer
+ );
+ }
+
+ //
+ // Should not be an error since we held the spinlock
+ // nothing should have changed.
+ //
+
+ ASSERT(StatusToReturn == NDIS_STATUS_SUCCESS);
+
+ *BytesWritten = NumAddresses * FDDI_LENGTH_OF_SHORT_ADDRESS;
+
+ }
+
+ return NDIS_STATUS_SUCCESS;
+
+ break;
+
+ case OID_FDDI_SHORT_MAX_LIST_SIZE:
+
+ GenericUlong = LOOP_FDDI_MAX_MULTICAST_SHORT;
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+ break;
+
+ case OID_TYPE_LTALK_OPERATIONAL:
+
+ switch(Oid) {
+ case OID_LTALK_CURRENT_NODE_ID:
+
+ SourceBuffer = Adapter->CurrentAddress;
+ SourceBufferLength = 1;
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+ break;
+
+ case OID_TYPE_ARCNET_OPERATIONAL:
+
+ switch(Oid) {
+ case OID_ARCNET_PERMANENT_ADDRESS:
+
+ SourceBuffer = Adapter->PermanentAddress;
+ SourceBufferLength = 1;
+ break;
+
+ case OID_ARCNET_CURRENT_ADDRESS:
+
+ SourceBuffer = Adapter->CurrentAddress;
+ SourceBufferLength = 1;
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+
+ if (SourceBufferLength > InformationBufferLength) {
+ *BytesNeeded = SourceBufferLength;
+ return NDIS_STATUS_BUFFER_TOO_SHORT;
+ }
+
+ NdisMoveMemory(
+ InformationBuffer,
+ SourceBuffer,
+ SourceBufferLength);
+
+ *BytesWritten = SourceBufferLength;
+
+ return NDIS_STATUS_SUCCESS;
+
+}
+
+STATIC
+VOID
+LoopAdjustLookahead(
+ IN PLOOP_ADAPTER Adapter
+ )
+{
+ PLOOP_OPEN Open;
+ PLIST_ENTRY OpenCurrentLink;
+ ULONG Lookahead=0;
+
+ OpenCurrentLink = Adapter->OpenBindings.Flink;
+
+ while(OpenCurrentLink != &Adapter->OpenBindings) {
+
+ Open = CONTAINING_RECORD(
+ OpenCurrentLink,
+ LOOP_OPEN,
+ OpenList
+ );
+
+ if (Open->CurrentLookAhead > Lookahead)
+ Lookahead = Open->CurrentLookAhead;
+
+ OpenCurrentLink = OpenCurrentLink->Flink;
+ }
+
+ Adapter->MaxLookAhead = Lookahead;
+}
+
+STATIC
+ULONG
+LoopQueryPacketFilter(
+ IN PLOOP_ADAPTER Adapter
+ )
+{
+ PLOOP_OPEN Open;
+ PLIST_ENTRY OpenCurrentLink;
+ ULONG Filter=0;
+
+ OpenCurrentLink = Adapter->OpenBindings.Flink;
+
+ while(OpenCurrentLink != &Adapter->OpenBindings) {
+
+ Open = CONTAINING_RECORD(
+ OpenCurrentLink,
+ LOOP_OPEN,
+ OpenList
+ );
+
+ Filter |= Open->CurrentPacketFilter;
+ OpenCurrentLink = OpenCurrentLink->Flink;
+ }
+
+ return Filter;
+}
diff --git a/private/ntos/ndis/loop/send.c b/private/ntos/ndis/loop/send.c
new file mode 100644
index 000000000..8eda49360
--- /dev/null
+++ b/private/ntos/ndis/loop/send.c
@@ -0,0 +1,717 @@
+#include <ndis.h>
+#include <efilter.h>
+#include <tfilter.h>
+#include <ffilter.h>
+
+#include "debug.h"
+#include "loop.h"
+
+STATIC
+VOID
+LoopProcessLoopback(
+ PLOOP_ADAPTER Adapter
+ );
+
+STATIC
+VOID
+LoopCopyFromPacketToBuffer(
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ IN UINT BytesToCopy,
+ OUT PCHAR Buffer,
+ OUT PUINT BytesCopied
+ );
+
+STATIC
+VOID
+LtIndicateReceive(
+ IN PLOOP_ADAPTER Adapter,
+ IN UINT PacketType,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+STATIC
+VOID
+LtIndicateReceiveComplete(
+ IN PLOOP_ADAPTER Adapter
+ );
+
+
+NDIS_STATUS
+LoopSend(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_PACKET Packet
+ )
+{
+ PLOOP_ADAPTER Adapter = PLOOP_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+ PLOOP_OPEN Open = PLOOP_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+ UINT PacketLength;
+ NDIS_STATUS StatusToReturn;
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, (" --> LoopSend\n"));
+
+ //
+ // Verify that the packet is correctly sized for the medium
+ //
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ NULL,
+ NULL,
+ &PacketLength
+ );
+
+ if ((PacketLength < Adapter->MediumMinPacketLen) ||
+ (PacketLength > Adapter->MediumMaxPacketLen)) {
+
+ return NDIS_STATUS_INVALID_PACKET;
+
+ }
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ if (!Adapter->ResetInProgress) {
+
+ if (!Open->BindingClosing) {
+
+ PLOOP_PACKET_RESERVED Reserved = PLOOP_RESERVED_FROM_PACKET(Packet);
+ BOOLEAN LoopIt=FALSE;
+ PNDIS_BUFFER FirstBuffer;
+ PVOID BufferVirtualAddress;
+ UINT BufferLength;
+
+ Open->References++;
+
+ Reserved->Next = NULL;
+ Reserved->MacBindingHandle = MacBindingHandle;
+ Reserved->PacketLength = PacketLength;
+ Reserved->HeaderLength = Adapter->MediumMacHeaderLen;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ NULL,
+ &FirstBuffer,
+ NULL
+ );
+
+ NdisQueryBuffer(
+ FirstBuffer,
+ &BufferVirtualAddress,
+ &BufferLength
+ );
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ switch (Adapter->Medium) {
+ case NdisMedium802_3:
+ case NdisMediumDix:
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Ethernet Dest Addr: %.2x-%.2x-%.2x-%.2x-%.2x-%.2x\n",
+ *((PUCHAR)BufferVirtualAddress),*((PUCHAR)BufferVirtualAddress+1),
+ *((PUCHAR)BufferVirtualAddress+2),*((PUCHAR)BufferVirtualAddress+3),
+ *((PUCHAR)BufferVirtualAddress+4),*((PUCHAR)BufferVirtualAddress+5)));
+
+ LoopIt = EthShouldAddressLoopBack(
+ Adapter->Filter.Eth,
+ BufferVirtualAddress
+ );
+ break;
+ case NdisMedium802_5:
+
+ // check for source routing info and adjust header
+
+ if (*((PUCHAR)BufferVirtualAddress+8) & 0x80)
+ Reserved->HeaderLength += (*((PUCHAR)BufferVirtualAddress+14) & 0x1f);
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("TokenRing Dest Addr: %.2x-%.2x-%.2x-%.2x-%.2x-%.2x\n",
+ *((PUCHAR)BufferVirtualAddress+2),*((PUCHAR)BufferVirtualAddress+3),
+ *((PUCHAR)BufferVirtualAddress+4),*((PUCHAR)BufferVirtualAddress+5),
+ *((PUCHAR)BufferVirtualAddress+6),*((PUCHAR)BufferVirtualAddress+7)));
+
+ LoopIt = TrShouldAddressLoopBack(
+ Adapter->Filter.Tr,
+ (PCHAR)BufferVirtualAddress+2,
+ Adapter->CurrentAddress
+ );
+
+ if (!LoopIt) {
+
+ // check if it's directed at ourselves
+
+ TR_COMPARE_NETWORK_ADDRESSES_EQ(
+ (PUCHAR)BufferVirtualAddress+2,
+ (PUCHAR)(Adapter->Filter.Tr)->AdapterAddress,
+ &BufferLength
+ );
+ if (!BufferLength)
+ LoopIt = TRUE;
+ }
+
+ break;
+ case NdisMediumFddi:
+
+ // check the address length bit and adjust the header length
+ // if it is short. by default we assume a long address
+
+ if (!(*((PUCHAR)BufferVirtualAddress) & 0x40)) {
+ Reserved->HeaderLength = 2*FDDI_LENGTH_OF_SHORT_ADDRESS+1;
+ BufferLength = FDDI_LENGTH_OF_SHORT_ADDRESS;
+ }
+ else
+ BufferLength = FDDI_LENGTH_OF_LONG_ADDRESS;
+
+ // hmmm... the DBGPRINT macro doesn't work too well to
+ // dump out dest addr of varying lengths
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Fddi Dest Addr: L(%d) %.2x-%.2x-%.2x-%.2x-%.2x-%.2x\n",BufferLength,
+ *((PUCHAR)BufferVirtualAddress+1),*((PUCHAR)BufferVirtualAddress+2),
+ *((PUCHAR)BufferVirtualAddress+3),*((PUCHAR)BufferVirtualAddress+4),
+ *((PUCHAR)BufferVirtualAddress+5),*((PUCHAR)BufferVirtualAddress+6)));
+
+ LoopIt = FddiShouldAddressLoopBack(
+ Adapter->Filter.Fddi,
+ (PCHAR)BufferVirtualAddress+1,
+ BufferLength
+ );
+ break;
+ case NdisMediumWan:
+ case NdisMediumLocalTalk:
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("LocalTalk Dest Addr: %.2x\n",((PUCHAR)BufferVirtualAddress)[0]));
+
+ if ((((PUCHAR)BufferVirtualAddress)[1] == Adapter->CurrentAddress[0]) ||
+ LOOP_LT_IS_BROADCAST(((PUCHAR)BufferVirtualAddress)[0]))
+ LoopIt = TRUE;
+ else
+ LoopIt = FALSE;
+
+ break;
+ case NdisMediumArcnet878_2:
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Arcnet Dest Addr: %.2x\n",((PUCHAR)BufferVirtualAddress)[1]));
+
+ if ((((PUCHAR)BufferVirtualAddress)[1] == Adapter->CurrentAddress[0]) ||
+ LOOP_ARC_IS_BROADCAST(((PUCHAR)BufferVirtualAddress)[1]))
+ LoopIt = TRUE;
+ else
+ LoopIt = FALSE;
+
+ break;
+ default:
+ // we should never get here...
+ ASSERT(FALSE);
+ break;
+ }
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO, ("LoopIt = %c\n",(LoopIt)?'Y':'N'));
+
+ if (LoopIt) {
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Queueing packet %lx for loopback\n",Packet));
+
+ if (Adapter->LastLoopback == NULL)
+ Adapter->Loopback = Packet;
+ else
+ PLOOP_RESERVED_FROM_PACKET(Adapter->LastLoopback)->Next = Packet;
+ Adapter->LastLoopback = Packet;
+
+ StatusToReturn = NDIS_STATUS_PENDING;
+
+ }
+ else {
+ //
+ // Since we're not looping this packet back, there's
+ // nothing for us to do. just return success and make
+ // like the packet was successfully sent out
+ //
+
+ Adapter->GeneralMandatory[GM_TRANSMIT_GOOD]++;
+ Open->References--;
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+ }
+ }
+ else
+ StatusToReturn = NDIS_STATUS_CLOSING;
+
+ }
+ else
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ Adapter->References--;
+
+ // might not queue a packet, but setting the timer anyway ensures
+ // we don't miss any packets sitting in the queue
+
+ if (!Adapter->TimerSet) {
+ Adapter->TimerSet = TRUE;
+ NdisReleaseSpinLock(&Adapter->Lock);
+ NdisSetTimer(
+ &Adapter->LoopTimer,
+ 25
+ );
+ }
+ else
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ return StatusToReturn;
+}
+
+
+VOID
+LoopTimerProc(
+ IN PVOID SystemSpecific1,
+ IN PVOID Context,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+{
+ PLOOP_ADAPTER Adapter = (PLOOP_ADAPTER)Context;
+
+ DBGPRINT(DBG_COMP_DPC, DBG_LEVEL_INFO, (" --> LoopTimerProc\n"));
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+ Adapter->TimerSet = FALSE;
+
+ if ((Adapter->Loopback != NULL) && !Adapter->InTimerProc) {
+ Adapter->InTimerProc = TRUE;
+ LoopProcessLoopback(Adapter);
+ Adapter->InTimerProc = FALSE;
+ }
+
+ Adapter->References--;
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+}
+
+
+STATIC
+VOID
+LoopProcessLoopback(
+ PLOOP_ADAPTER Adapter
+ )
+{
+ PNDIS_PACKET LoopPacket;
+ PLOOP_PACKET_RESERVED Reserved;
+ PLOOP_OPEN Open;
+ UINT BufferLength;
+ UINT IndicateLen;
+ UINT AddressType;
+ UCHAR DestAddress[FDDI_LENGTH_OF_LONG_ADDRESS];
+
+ DBGPRINT(DBG_COMP_DPC, DBG_LEVEL_INFO, (" --> LoopProcessLoopback\n"));
+
+ while ((Adapter->Loopback != NULL) && !Adapter->ResetInProgress) {
+
+ // dequeue the packet at the head of the loopback queue
+
+ LoopPacket = Adapter->Loopback;
+ Adapter->CurrentLoopback = LoopPacket;
+ Reserved = PLOOP_RESERVED_FROM_PACKET(LoopPacket);
+ Adapter->Loopback = Reserved->Next;
+ if (Adapter->Loopback == NULL)
+ Adapter->LastLoopback = NULL;
+
+ DBGPRINT(DBG_COMP_DPC, DBG_LEVEL_INFO, ("Dequeued packet %lx\n",LoopPacket));
+
+ IndicateLen = (Reserved->PacketLength > Adapter->MaxLookAhead) ?
+ Adapter->MaxLookAhead : Reserved->PacketLength;
+
+ Adapter->GeneralMandatory[GM_RECEIVE_GOOD]++;
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ LoopCopyFromPacketToBuffer(
+ LoopPacket,
+ 0,
+ IndicateLen,
+ Adapter->LoopBuffer,
+ &BufferLength
+ );
+
+ // indicate the packet as appropriate
+
+ switch (Adapter->Medium) {
+ case NdisMedium802_3:
+ case NdisMediumDix:
+ EthFilterIndicateReceive(
+ Adapter->Filter.Eth,
+ (NDIS_HANDLE)NULL,
+ (PCHAR)Adapter->LoopBuffer,
+ Adapter->LoopBuffer,
+ Reserved->HeaderLength,
+ (Adapter->LoopBuffer)+(Reserved->HeaderLength),
+ IndicateLen-(Reserved->HeaderLength),
+ (Reserved->PacketLength)-(Reserved->HeaderLength)
+ );
+ break;
+ case NdisMedium802_5:
+ TrFilterIndicateReceive(
+ Adapter->Filter.Tr,
+ (NDIS_HANDLE)NULL,
+ Adapter->LoopBuffer,
+ Reserved->HeaderLength,
+ (Adapter->LoopBuffer)+(Reserved->HeaderLength),
+ IndicateLen-(Reserved->HeaderLength),
+ (Reserved->PacketLength)-(Reserved->HeaderLength)
+ );
+ break;
+ case NdisMediumFddi:
+
+ // just copy over the long address size, even though it may
+ // be a short address
+
+ NdisMoveMemory(
+ DestAddress,
+ Adapter->LoopBuffer+1,
+ FDDI_LENGTH_OF_LONG_ADDRESS
+ );
+
+ FddiFilterIndicateReceive(
+ Adapter->Filter.Fddi,
+ (NDIS_HANDLE)NULL,
+ (PCHAR)DestAddress,
+ ((*(Adapter->LoopBuffer) & 0x40) ? FDDI_LENGTH_OF_LONG_ADDRESS :
+ FDDI_LENGTH_OF_SHORT_ADDRESS),
+ Adapter->LoopBuffer,
+ Reserved->HeaderLength,
+ (Adapter->LoopBuffer)+(Reserved->HeaderLength),
+ IndicateLen-(Reserved->HeaderLength),
+ (Reserved->PacketLength)-(Reserved->HeaderLength)
+ );
+ break;
+ case NdisMediumLocalTalk:
+ if (LOOP_LT_IS_BROADCAST(Adapter->LoopBuffer[0]))
+ AddressType = NDIS_PACKET_TYPE_BROADCAST;
+ else
+ AddressType = NDIS_PACKET_TYPE_DIRECTED;
+
+ LtIndicateReceive(
+ Adapter,
+ AddressType,
+ Adapter->LoopBuffer,
+ Reserved->HeaderLength,
+ (Adapter->LoopBuffer)+(Reserved->HeaderLength),
+ IndicateLen-(Reserved->HeaderLength),
+ (Reserved->PacketLength)-(Reserved->HeaderLength)
+ );
+ break;
+ case NdisMediumArcnet878_2:
+ if (LOOP_ARC_IS_BROADCAST(Adapter->LoopBuffer[1]))
+ AddressType = NDIS_PACKET_TYPE_BROADCAST;
+ else
+ AddressType = NDIS_PACKET_TYPE_DIRECTED;
+
+ LtIndicateReceive(
+ Adapter,
+ AddressType,
+ Adapter->LoopBuffer,
+ Reserved->HeaderLength,
+ (Adapter->LoopBuffer)+(Reserved->HeaderLength),
+ IndicateLen-(Reserved->HeaderLength),
+ (Reserved->PacketLength)-(Reserved->HeaderLength)
+ );
+ break;
+ default:
+ ASSERT(FALSE); // should never get here
+ break;
+ }
+
+ // complete the send
+
+ Open = PLOOP_OPEN_FROM_BINDING_HANDLE(Reserved->MacBindingHandle);
+ DBGPRINT(DBG_COMP_DPC, DBG_LEVEL_INFO,
+ ("Completing Send for binding %lx\n",Open));
+ NdisCompleteSend(
+ Open->NdisBindingContext,
+ LoopPacket,
+ NDIS_STATUS_SUCCESS
+ );
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+ Adapter->GeneralMandatory[GM_TRANSMIT_GOOD]++;
+ // remove reference for send just completed
+ Open->References--;
+ }
+
+ // rearm timer if there are still packets to loop back and the timer is
+ // not already ticking away
+
+ if (Adapter->Loopback != NULL && !Adapter->TimerSet) {
+ DBGPRINT(DBG_COMP_DPC, DBG_LEVEL_INFO, ("More packets to loopback\n"));
+ Adapter->TimerSet = TRUE;
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+ NdisSetTimer(
+ &Adapter->LoopTimer,
+ 25
+ );
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+ }
+
+ // issue indicate receive completes as necessary
+
+ switch (Adapter->Medium) {
+ case NdisMedium802_3:
+ case NdisMediumDix:
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+ EthFilterIndicateReceiveComplete(Adapter->Filter.Eth);
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+ break;
+ case NdisMedium802_5:
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+ TrFilterIndicateReceiveComplete(Adapter->Filter.Tr);
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+ break;
+ case NdisMediumFddi:
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+ FddiFilterIndicateReceiveComplete(Adapter->Filter.Fddi);
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+ break;
+ case NdisMediumLocalTalk:
+ case NdisMediumArcnet878_2:
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+ LtIndicateReceiveComplete(Adapter);
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+ break;
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+}
+
+STATIC
+VOID
+LoopCopyFromPacketToBuffer(
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ IN UINT BytesToCopy,
+ OUT PCHAR Buffer,
+ OUT PUINT BytesCopied
+ )
+{
+ //
+ // Holds the number of ndis buffers comprising the packet.
+ //
+ UINT NdisBufferCount;
+
+ //
+ // Points to the buffer from which we are extracting data.
+ //
+ PNDIS_BUFFER CurrentBuffer;
+
+ //
+ // Holds the virtual address of the current buffer.
+ //
+ PVOID VirtualAddress;
+
+ //
+ // Holds the length of the current buffer of the packet.
+ //
+ UINT CurrentLength;
+
+ //
+ // Keep a local variable of BytesCopied so we aren't referencing
+ // through a pointer.
+ //
+ UINT LocalBytesCopied = 0;
+
+ //
+ // Take care of boundary condition of zero length copy.
+ //
+
+ *BytesCopied = 0;
+ if (!BytesToCopy) return;
+
+ //
+ // Get the first buffer.
+ //
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ &NdisBufferCount,
+ &CurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet.
+ //
+
+ if (!NdisBufferCount) return;
+
+ NdisQueryBuffer(
+ CurrentBuffer,
+ &VirtualAddress,
+ &CurrentLength
+ );
+
+ while (LocalBytesCopied < BytesToCopy) {
+
+ if (!CurrentLength) {
+
+ NdisGetNextBuffer(
+ CurrentBuffer,
+ &CurrentBuffer
+ );
+
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.
+ //
+
+ if (!CurrentBuffer) break;
+
+ NdisQueryBuffer(
+ CurrentBuffer,
+ &VirtualAddress,
+ &CurrentLength
+ );
+ continue;
+
+ }
+
+ //
+ // Try to get us up to the point to start the copy.
+ //
+
+ if (Offset) {
+
+ if (Offset > CurrentLength) {
+
+ //
+ // What we want isn't in this buffer.
+ //
+
+ Offset -= CurrentLength;
+ CurrentLength = 0;
+ continue;
+
+ } else {
+
+ VirtualAddress = (PCHAR)VirtualAddress + Offset;
+ CurrentLength -= Offset;
+ Offset = 0;
+
+ }
+ }
+
+ //
+ // Copy the data.
+ //
+
+ {
+ //
+ // Holds the amount of data to move.
+ //
+ UINT AmountToMove;
+
+ AmountToMove = ((CurrentLength <= (BytesToCopy - LocalBytesCopied))?
+ (CurrentLength):(BytesToCopy - LocalBytesCopied));
+
+ NdisMoveMemory(
+ Buffer,
+ VirtualAddress,
+ AmountToMove
+ );
+
+ Buffer = (PCHAR)Buffer + AmountToMove;
+ VirtualAddress = (PCHAR)VirtualAddress + AmountToMove;
+
+ LocalBytesCopied += AmountToMove;
+ CurrentLength -= AmountToMove;
+
+ }
+ }
+
+ *BytesCopied = LocalBytesCopied;
+}
+
+
+STATIC
+VOID
+LtIndicateReceive(
+ IN PLOOP_ADAPTER Adapter,
+ IN UINT PacketType,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+{
+ PLOOP_OPEN Open;
+ PLIST_ENTRY CurrentLink = Adapter->OpenBindings.Flink;
+ NDIS_STATUS Status;
+
+ while(CurrentLink != &Adapter->OpenBindings) {
+
+ Open = CONTAINING_RECORD(
+ CurrentLink,
+ LOOP_OPEN,
+ OpenList);
+
+ if (PacketType & Open->CurrentPacketFilter) {
+
+ NdisIndicateReceive(
+ &Status,
+ Open->NdisBindingContext,
+ NULL,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize);
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+ Open->Flags |= BINDING_RECEIVED_PACKET;
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ }
+
+ CurrentLink = CurrentLink->Flink;
+ }
+}
+
+
+STATIC
+VOID
+LtIndicateReceiveComplete(
+ IN PLOOP_ADAPTER Adapter
+ )
+{
+ PLOOP_OPEN Open;
+ PLIST_ENTRY CurrentLink = Adapter->OpenBindings.Flink;
+
+ while(CurrentLink != &Adapter->OpenBindings) {
+
+ Open = CONTAINING_RECORD(
+ CurrentLink,
+ LOOP_OPEN,
+ OpenList);
+
+ if (Open->Flags & BINDING_RECEIVED_PACKET) {
+
+ NdisIndicateReceiveComplete(Open->NdisBindingContext);
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+ Open->Flags &= ~BINDING_RECEIVED_PACKET;
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ }
+
+ CurrentLink = CurrentLink->Flink;
+ }
+}
diff --git a/private/ntos/ndis/loop/sources b/private/ntos/ndis/loop/sources
new file mode 100644
index 000000000..9e1c063fb
--- /dev/null
+++ b/private/ntos/ndis/loop/sources
@@ -0,0 +1,20 @@
+MAJORCOMP=ntos
+MINORCOMP=ndis2
+
+TARGETNAME=loop
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+INCLUDES=..\..\inc
+
+SOURCES=loop.c \
+ request.c \
+ send.c \
+ loop.rc
+
+RELATIVE_DEPTH=..\..
+
+MSC_WARNING_LEVEL=/W3 /WX
+
diff --git a/private/ntos/ndis/lsl/frames.h b/private/ntos/ndis/lsl/frames.h
new file mode 100644
index 000000000..5c5a21010
--- /dev/null
+++ b/private/ntos/ndis/lsl/frames.h
@@ -0,0 +1,189 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ frames.h
+
+Abstract:
+
+ This file contains all the definitions for the different frames supported.
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 3-8-93
+
+Environment:
+
+ Kernel Mode.
+
+Revision History:
+
+--*/
+
+
+//
+// Definition of FrameIDs
+//
+#define ETHERNET_II_FRAME_ID 2
+#define ETHERNET_802_2_FRAME_ID 3
+#define TOKEN_RING_802_2_FRAME_ID 4
+#define ETHERNET_802_3_FRAME_ID 5
+#define ETHERNET_SNAP_FRAME_ID 10
+#define TOKEN_RING_SNAP_FRAME_ID 11
+#define FDDI_802_2_FRAME_ID 20
+#define FDDI_SNAP_FRAME_ID 23
+
+
+typedef struct _Ethernet_II_Header_ {
+
+ UINT8 DestinationAddress[6];
+ UINT8 SourceAddress[6];
+ UINT16 FrameType;
+
+} Ethernet_II_Header, *PEthernet_II_Header;
+
+typedef Ethernet_II_Header Ethernet_802_3_Header, *PEthernet_802_3_Header;
+
+
+typedef struct _Ethernet_802_2_Header_ {
+
+ UINT8 DestinationAddress[6];
+ UINT8 SourceAddress[6];
+ UINT16 FrameLength;
+ UINT8 DSAP;
+ UINT8 SSAP;
+ UINT8 Control;
+
+} Ethernet_802_2_Header, *PEthernet_802_2_Header;
+
+typedef struct _Ethernet_Snap_Header_ {
+
+ UINT8 DestinationAddress[6];
+ UINT8 SourceAddress[6];
+ UINT16 FrameLength;
+ UINT8 DSAP;
+ UINT8 SSAP;
+ UINT8 Control;
+ UINT8 ProtocolIdentification[5];
+
+} Ethernet_Snap_Header, *PEthernet_Snap_Header;
+
+
+typedef struct _Fddi_802_2_Header_ {
+
+ UINT8 DestinationAddress[6];
+ UINT8 SourceAddress[6];
+ UINT16 FrameLength;
+ UINT8 DSAP;
+ UINT8 SSAP;
+ UINT8 Control;
+
+} Fddi_802_2_Header, *PFddi_802_2_Header;
+
+
+typedef struct _Fddi_Snap_Header_ {
+
+ UINT8 DestinationAddress[6];
+ UINT8 SourceAddress[6];
+ UINT16 FrameLength;
+ UINT8 DSAP;
+ UINT8 SSAP;
+ UINT8 Control;
+ UINT8 ProtocolIdentification[5];
+
+} Fddi_Snap_Header, *PFddi_Snap_Header;
+
+
+typedef struct _TokenRing_Header_ {
+
+ UINT8 AccessControl;
+ UINT8 FrameControl;
+ UINT8 DestinationAddress[6];
+ UINT8 SourceAddress[6];
+
+} TokenRing_Header, *PTokenRing_Header;
+
+
+
+//
+// Check if an address is multicast
+//
+#define ETH_IS_MULTICAST(Address) \
+ (((PUCHAR)(Address))[0] & ((UCHAR)0x01))
+
+
+//
+// Check whether an address is broadcast.
+//
+#define ETH_IS_BROADCAST(Address) \
+ ((*((ULONG UNALIGNED *) \
+ (&(((PUCHAR) \
+ Address \
+ )[2] \
+ ) \
+ ) \
+ ) == \
+ ((ULONG)0xffffffff) \
+ ) && \
+ (((PUCHAR)Address)[0] == ((UCHAR)0xff)) && \
+ (((PUCHAR)Address)[1] == ((UCHAR)0xff)))
+
+//
+//
+#define TR_IS_FUNCTIONAL(Address, Result) \
+{ \
+ PUCHAR _A = Address; \
+ PBOOLEAN _R = Result; \
+ *_R = (BOOLEAN)(((_A[0] & ((UCHAR)0x80)) &&\
+ !(_A[2] & ((UCHAR)0x80)))?(TRUE):(FALSE)); \
+}
+
+//
+//
+#define TR_IS_GROUP(Address, Result) \
+{ \
+ PUCHAR _A = Address; \
+ PBOOLEAN _R = Result; \
+ *_R = (BOOLEAN)((_A[0] & _A[2] & ((UCHAR)0x80))?(TRUE):(FALSE)); \
+}
+
+
+//
+// Check whether an address is broadcast.
+//
+#define TR_IS_BROADCAST(Address, Result) \
+{ \
+ PUCHAR _A = Address; \
+ PBOOLEAN _R = Result; \
+ *_R = (BOOLEAN)(((((_A[0] == ((UCHAR)0xff)) && \
+ (_A[1] == ((UCHAR)0xff))) || \
+ ((_A[0] == ((UCHAR)0xc0)) && \
+ (_A[1] == ((UCHAR)0x00)))) && \
+ (_A[2] == ((UCHAR)0xff)) && \
+ (_A[3] == ((UCHAR)0xff)) && \
+ (_A[4] == ((UCHAR)0xff)) && \
+ (_A[5] == ((UCHAR)0xff)))?(TRUE):(FALSE)); \
+}
+
+//
+// See if two addresses are the same
+//
+#define COMPARE_NETWORK_ADDRESSES(A,B,Result) \
+{ \
+ PCHAR _A = A; \
+ PCHAR _B = B; \
+ INT _LocalResult = 0; \
+ UINT _i; \
+ for ( \
+ _i = 0; \
+ _i <= 5 && !_LocalResult; \
+ _i++ \
+ ) { \
+ _LocalResult = _A[_i] - _B[_i]; \
+ } \
+ *Result = (_LocalResult==0)?TRUE:FALSE; \
+}
+
+
diff --git a/private/ntos/ndis/lsl/init.c b/private/ntos/ndis/lsl/init.c
new file mode 100644
index 000000000..1d013881c
--- /dev/null
+++ b/private/ntos/ndis/lsl/init.c
@@ -0,0 +1,2060 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ init.c
+
+Abstract:
+
+ This file controls all the loading and unloading of the driver. It controls
+ the initial bindings and the teardown in the event it is told to unload.
+
+Author:
+
+ Sean Selitrennikoff (seanse) 3-93
+
+Environment:
+
+ Kernel Mode.
+
+Revision History:
+
+--*/
+
+#include <ntddk.h>
+#include <ndis.h>
+#include "lsl.h"
+#include "lslmlid.h"
+#include "frames.h"
+#include "mlid.h"
+#include "ndismlid.h"
+
+#define UNICODE_STRING_CONST(x) {sizeof(L##x)-2, sizeof(L##x), L##x}
+
+
+//
+// PLEASE NOTE: The ordering of the strings in the arrays is important.
+// Code depends on the indicies of the strings. Each dependency is
+// listed with the array that it depends on.
+//
+
+//
+// All the string names of the counters that must be kept by a MLID.
+// - ndismlid.c
+// - lslmlid.c
+//
+static
+MEON_STRING
+NdisMlidGenericStatStrings[] = {
+ "MTotalTxPacketCount",
+ "MTotalRxPacketCount",
+ "MNoECBAvailableCount",
+ "MPacketTxTooBigCount",
+ "MPacketTxTooSmallCount",
+ "MPacketRxTooBigCount",
+ "MTotalTxMiscCount",
+ "MTotalRxMiscCount",
+ "MTotalTxOKByteCount",
+ "MTotalRxOKByteCount",
+ "MTotalGroupAddrTxCount",
+ "MTotalGroupAddrRxCount",
+ "MAdapterResetCount",
+ "MAdapterOprTimeStamp",
+ "MQDepth"
+ };
+
+//
+// The type of each of the above stat, where 0 == UINT32 and 1 == UINT64
+// - No Dependencies
+//
+static
+UINT32
+NdisMlidGenericStatTypes[] = {
+ 0, // TotalTxPacketCount
+ 0, // TotalRxPacketCount
+ 0, // NoECBAvailableCount
+ 0, // PacketTxTooBigCount
+ 0, // PacketRxTooSmallCount
+ 0, // PacketRxTooBigCount
+ 0, // TotalTxMiscCount
+ 0, // TotalRxMiscCount
+ 1, // TotalTxOKByteCount
+ 1, // TotalRxOKByteCount
+ 0, // TotalGroupAddrTxCount
+ 0, // TotalGroupAddrRxCount
+ 0, // AdapterResetCount
+ 0, // AdapterOprTimeStamp
+ 0 // QDepth
+ };
+
+
+//
+// String names for counters kept by Token Ring MLIDs
+// - ndismlid.c: TRN_LastRingID
+//
+static
+MEON_STRING
+NdisMlidTokenRingStatStrings[] = {
+ "TRN_ACErrorCounter",
+ "TRN_AbortDelimiterCounter",
+ "TRN_BurstErrorCounter",
+ "TRN_FrameCopiedErrorCounter",
+ "TRN_FrequencyErrorCounter",
+ "TRN_InternalErrorCounter",
+ "TRN_LastRingStatus",
+ "TRN_LineErrorCounter",
+ "TRN_LostFrameCounter",
+ "TRN_TokenErrorCounter",
+ "TRN_UpstreamNodeAddress",
+ "TRN_LastRingID",
+ "TRN_LastBeaconType"
+ };
+
+
+//
+// The type of each of the above stat, where 0 == UINT32 and 1 == UINT64
+// - ndismlid.c: TRN_LastRingID
+//
+static
+UINT32
+NdisMlidTokenRingStatTypes[] = {
+ 0, // TRN_ACErrorCounter
+ 0, // TRN_AbortDelimiterCounter
+ 0, // TRN_BurstErrorCounter
+ 0, // TRN_FrameCopiedErrorCounter
+ 0, // TRN_FrequencyErrorCounter
+ 0, // TRN_InternalErrorCounter
+ 0, // TRN_LastRingStatus
+ 0, // TRN_LineErrorCounter
+ 0, // TRN_LostFrameCounter
+ 0, // TRN_TokenErrorCounter
+ 1, // TRN_UpstreamNodeAddress
+ 0, // TRN_LastRingID
+ 0 // TRN_LastBeaconType
+ };
+
+//
+// String names for counters kept by Ethernet MLIDs
+// - No Dependencies
+//
+static
+MEON_STRING
+NdisMlidEthernetStatStrings[] = {
+ "ETH_TxOKSingleCollisionsCount",
+ "ETH_TxOKMultipleCollisionsCount",
+ "ETH_TxOKButDeferred",
+ "ETH_TxAbortLateCollision",
+ "ETH_TxAbortExcessCollision",
+ "ETH_TxAbortCarrierSense",
+ "ETH_TxAbortExcessiveDeferral",
+ "ETH_RxAbortFrameAlignment"
+ };
+
+
+//
+// The type of each of the above stats, where 0 == UINT32 and 1 == UINT64
+// - No Dependencies
+//
+static
+UINT32
+NdisMlidEthernetStatTypes[] = {
+ 0, // ETH_TxOKSingleCollisionsCount
+ 0, // ETH_TxOKMultipleCollisionsCount
+ 0, // ETH_TxOKButDeferred
+ 0, // ETH_TxAbortLateCollision
+ 0, // ETH_TxAbortExcessCollision
+ 0, // ETH_TxAbortCarrierSense
+ 0, // ETH_TxAbortExcessiveDeferral
+ 0 // ETH_RxAbortFrameAlignment
+ };
+
+//
+// String names for counter kept by FDDI MLIDs
+// - No Dependencies
+//
+static
+MEON_STRING
+NdisMlidFddiStatStrings[] = {
+ "FDI_ConfigurationState",
+ "FDI_UpstreamNode",
+ "FDI_DownstreamNode",
+ "FDI_FrameErrorCount",
+ "FDI_FrameLostCount",
+ "FDI_RingManagementCount",
+ "FDI_LCTFailureCount",
+ "FDI_LemRejectCount",
+ "FDI_LemCount",
+ "FDI_LConnectionState"
+ };
+
+
+//
+// The type of each of the above stats, where 0 == UINT32 and 1 == UINT64
+// - No Dependencies
+//
+static
+UINT32
+NdisMlidFddiStatTypes[] = {
+ 0, // FDI_ConfigurationState
+ 1, // FDI_UpstreamNode
+ 1, // FDI_DownstreamNode
+ 0, // FDI_FrameErrorCount
+ 0, // FDI_FrameLostCount
+ 0, // FDI_RingManagementCount
+ 0, // FDI_LCTFailureCount
+ 0, // FDI_LemRejectCount
+ 0, // FDI_LemCount
+ 0 // FDI_LConnectionState
+ };
+
+
+//
+// Holds the string names of all frame types
+// - No Dependencies
+//
+static
+MEON_STRING
+NdisMlidFrameTypeStrings[] = {
+ "VIRTUAL_LAN",
+ "LOCALTALK",
+ "ETHERNET_II",
+ "ETHERNET_802.2",
+ "TOKEN-RING",
+ "ETHERNET_802.3"
+ "802.4",
+ "Reserved",
+ "GNET",
+ "PRONET-10",
+ "ETHERNET_SNAP",
+ "TOKEN-RING_SNAP",
+ "LANPAC_II",
+ "ISDN",
+ "NOVELL_RX-NET",
+ "IBM_PCN2_802.2",
+ "IBM_PCN2_SNAP",
+ "OMNINET/4",
+ "3270_COAXA",
+ "IP"
+ "FDDI_802.2",
+ "IVDLAN_802.9",
+ "DATACO_OSI",
+ "FDDI_SNAP"
+ };
+
+//
+// Handle for this "protocol" for NDIS
+//
+NDIS_HANDLE NdisMlidProtocolHandle = NULL;
+
+//
+// Spin lock for accessing MLID list
+//
+NDIS_SPIN_LOCK NdisMlidSpinLock;
+
+//
+// Array of MLIDs
+//
+extern PMLID_BOARDS MlidBoards = NULL;
+
+//
+// Number of MLIDs in use
+//
+extern UINT32 CountMlidBoards = 0;
+
+//
+// Size of the MLID array
+//
+extern UINT32 AllocatedMlidBoards = 0;
+
+
+
+
+
+NTSTATUS
+NdisMlidRegisterProtocol(
+ IN UNICODE_STRING *NameString
+ );
+
+VOID
+NdisMlidDeregisterProtocol(
+ VOID
+ );
+
+NTSTATUS
+NdisMlidInitializeMlids(
+ VOID
+ );
+
+VOID
+NdisMlidUnloadMlids(
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+VOID
+NdisMlidUnloadMlid(
+ IN PMLID_STRUCT Mlid
+ );
+
+PMLID_STRUCT
+NdisMlidOpenMlid(
+ PVOID OdiRegistryPtr,
+ PVOID NdisRegistryPtr,
+ );
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+
+/*++
+
+Routine Description:
+
+ This is the entry point for the driver.
+
+Arguments:
+
+ DriverObject - The driver object for this driver in the NT system.
+
+ RegistryPath - Path in the registry to it's parameters.
+
+Return Value:
+
+ Indicates the success or failure of the initialization.
+
+--*/
+
+{
+ NTSTATUS Status;
+ UNICODE_STRING NameString = UNICODE_STRING_CONST("\\Device\\NdisMlid");
+
+ //
+ // Fill in unload handler
+ //
+
+ DriverObject->DriverUnload = NdisMlidUnloadMlids;
+
+ //
+ // make ourselves known to the NDIS wrapper.
+ //
+
+ Status = NdisMlidRegisterProtocol(&NameString);
+
+ if (!NT_SUCCESS (Status)) {
+
+#if DBG
+ DbgPrint("NdisMlidInitialize: RegisterProtocol failed!\n");
+#endif
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+ NdisAllocateSpinLock(&NdisMlidSpinLock);
+
+ //
+ // Now Initialize all the boards according to registry
+ //
+
+ Status = NdisMlidInitializeMlids();
+
+ if (!(NT_SUCCESS(Status))) {
+
+ NdisFreeSpinLock(&NdisMlidSpinLock);
+
+ NdisMlidDeregisterProtocol();
+
+ return(Status);
+
+ }
+
+ return(STATUS_SUCCESS);
+
+}
+
+
+NTSTATUS
+NdisMlidRegisterProtocol(
+ IN UNICODE_STRING *NameString
+ )
+
+/*++
+
+Routine Description:
+
+ This routine introduces this driver as a transport to the NDIS interface.
+
+Arguments:
+
+ NameString - Name of this device.
+
+Return Value:
+
+ STATUS_SUCCESS - Success.
+ STATUS_INSUFFICIENT_RESOURCES - Failure.
+
+--*/
+
+{
+ NDIS_STATUS NdisStatus;
+ PNDIS_PROTOCOL_CHARACTERISTICS ProtChars; // Used temporarily to register
+
+ ProtChars = ExAllocatePool(NonPagedPool,
+ sizeof(NDIS_PROTOCOL_CHARACTERISTICS) + NameString->Length
+ );
+
+ //
+ // Set up the characteristics of this protocol
+ //
+
+ ProtChars->MajorNdisVersion = 3;
+ ProtChars->MinorNdisVersion = 0;
+
+ ProtChars->Name.Length = NameString->Length;
+ ProtChars->Name.Buffer = (PVOID)(ProtChars + 1);
+
+ ProtChars->OpenAdapterCompleteHandler = NdisMlidOpenAdapterComplete;
+ ProtChars->CloseAdapterCompleteHandler = NdisMlidCloseAdapterComplete;
+ ProtChars->ResetCompleteHandler = NdisMlidResetComplete;
+ ProtChars->RequestCompleteHandler = NdisMlidRequestComplete;
+ ProtChars->SendCompleteHandler = NdisMlidSendComplete;
+ ProtChars->TransferDataCompleteHandler = NdisMlidTransferDataComplete;
+ ProtChars->ReceiveHandler = NdisMlidReceive;
+ ProtChars->ReceiveCompleteHandler = NdisMlidReceiveComplete;
+ ProtChars->StatusHandler = NdisMlidStatus;
+ ProtChars->StatusCompleteHandler = NdisMlidStatusComplete;
+
+ NdisRegisterProtocol (
+ &NdisStatus,
+ &NdisMlidProtocolHandle,
+ ProtChars,
+ (UINT)sizeof(NDIS_PROTOCOL_CHARACTERISTICS) + NameString->Length
+ );
+
+ ExFreePool(ProtChars);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+#if DBG
+ DbgPrint("NdisMlidInitialize: NdisRegisterProtocol failed: %s\n", NdisStatus);
+#endif
+
+ return (NTSTATUS)NdisStatus;
+
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+VOID
+NdisMlidDeregisterProtocol(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes this transport to the NDIS interface.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS NdisStatus;
+
+ if (NdisMlidProtocolHandle != (NDIS_HANDLE)NULL) {
+
+ NdisDeregisterProtocol (
+ &NdisStatus,
+ NdisMlidProtocolHandle
+ );
+
+ NdisMlidProtocolHandle = (NDIS_HANDLE)NULL;
+ }
+
+}
+
+
+VOID
+NdisMlidUnloadMlids(
+ IN PDRIVER_OBJECT DriverObject
+ )
+
+/*++
+
+Routine Description:
+
+ This routine shuts down all the MLIDs and unloads itself.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UINT32 i;
+
+ NdisAcquireSpinLock(&NdisMlidSpinLock);
+
+ //
+ // For each MLID
+ //
+
+ for (i = 0; i < AllocatedMlidBoards; i++) {
+
+ //
+ // If MLID was opened
+ //
+
+ if (MlidBoards[i].Mlid != NULL) {
+
+ //
+ // Unload MLID
+ //
+
+ NdisMlidUnloadMlid(MlidBoards[i].Mlid);
+ MlidBoards[i].Mlid = NULL;
+
+ CountMlidBoards--;
+
+ if (CountMlidBoards == 0) {
+
+ break;
+
+ }
+
+ }
+
+ }
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ NdisFreeSpinLock(&NdisMlidSpinLock);
+
+ NdisMlidDeregisterProtocol();
+
+ ExFreePool(MlidBoards);
+
+}
+
+
+VOID
+NdisMlidUnloadMlid(
+ IN PMLID_STRUCT Mlid
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes this transport to the NDIS interface.
+
+ NOTE: You must hold the NdisMlidSpinLock when calling this routine!!
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UINT32 Status;
+ NDIS_STATUS NdisStatus;
+ PECB SendECB;
+
+ NdisAcquireSpinLock(&(Mlid->MlidSpinLock));
+
+ //
+ // Set unloading flag
+ //
+ Mlid->Unloading = TRUE;
+
+ //
+ // Remove all pending ECBs
+ //
+
+ while (Mlid->FirstPendingSend != NULL) {
+
+ //
+ // Remove ECB from queue
+ //
+
+ SendECB = Mlid->FirstPendingSend;
+
+ Mlid->FirstPendingSend = SendECB->ECB_NextLink;
+
+ if (SendECB->ECB_NextLink != NULL) {
+
+ SendECB->ECB_NextLink->ECB_PreviousLink = NULL;
+
+ }
+
+ if (Mlid->LastPendingSend == SendECB) {
+
+ Mlid->LastPendingSend = NULL;
+
+ }
+
+ //
+ // Cancel the ECB
+ //
+
+ SendECB->ECB_Status = (UINT16)CANCELED;
+
+ //
+ // Give it to LSL
+ //
+
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ (*(Mlid->LSLFunctionList->SupportAPIArray[HoldEvent_INDEX]))(
+ SendECB
+ );
+
+ NdisAcquireSpinLock(&(Mlid->MlidSpinLock));
+
+ }
+
+ //
+ // Service all held sends
+ //
+
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ (*(Mlid->LSLFunctionList->SupportAPIArray[ServiceEvents_INDEX]))(
+ );
+
+ //
+ // Close Ndis Adapter
+ //
+
+ NdisCloseAdapter(&NdisStatus, Mlid->NdisBindingHandle);
+
+ //
+ // If pend, wait
+ //
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // Wait for close to complete
+ //
+
+ KeWaitForSingleObject(
+ &(Mlid->MlidRequestCompleteEvent),
+ Executive,
+ KernelMode,
+ TRUE,
+ (PTIME)NULL
+ );
+
+ KeResetEvent(&Mlid->MlidRequestCompleteEvent);
+ }
+
+ //
+ // Get status
+ //
+
+ Status = Mlid->RequestStatus;
+
+ //
+ // Deregister with LSL
+ //
+
+ (*(Mlid->LSLFunctionList->SupportAPIArray[DeRegisterMLID_INDEX]))(
+ Mlid->ConfigTable.MLIDCFG_BoardNumber
+ );
+
+ NdisAcquireSpinLock(&(Mlid->MlidSpinLock));
+
+ //
+ // Free up resources
+ //
+
+ Mlid->StatsTable->References--;
+
+ if (Mlid->StatsTable->References == 0) {
+ ExFreePool(Mlid->StatsTable);
+ }
+
+ if (Mlid->MulticastAddresses.MAAllocated != 0) {
+
+ if (Mlid->NdisMlidMedium != NdisMedium802_5) {
+
+ ExFreePool(Mlid->MulticastAddresses.Addresses);
+
+ }
+
+ ExFreePool(Mlid->MulticastAddresses.EnableCounts);
+ Mlid->MulticastAddresses.MAAllocated = 0;
+ }
+
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ NdisFreeSpinLock(&(Mlid->MlidSpinLock));
+
+ ExFreePool(Mlid);
+
+}
+
+
+NTSTATUS
+NdisMlidInitializeMlids(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine loads all ODI boards that are supposed to be loaded.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if a single load succeeds.
+ NDIS_STATUS_FAILURE is no boards get loaded.
+
+--*/
+
+{
+ BOOLEAN LoadedADriver = FALSE;
+ PMLID_STRUCT Mlid;
+
+ PVOID OdiRegistryPtr;
+ PVOID NdisRegistryPtr;
+
+ UINT32 i;
+
+
+ //
+ // Find first ODI driver that is supposed to be loaded
+ //*\\ here - Config
+
+ //
+ // Find corresponding NDIS MAC Info
+ //*\\ here - Config
+
+ while (TRUE) {
+
+ //
+ // Open this MLID
+ //
+ Mlid = NdisMlidOpenMlid(OdiRegistryPtr, NdisRegistryPtr);
+
+ if (Mlid != NULL) {
+
+ //
+ // Do we have space in global array for this MLID
+ //
+
+ if (CountMlidBoards == AllocatedMlidBoards) {
+
+ //
+ // Allocate more space
+ //
+
+ Mlid = (PMLID_STRUCT)ExAllocatePool(
+ NonPagedPool,
+ sizeof(MLID_STRUCT) * (CountMlidBoards + 1)
+ );
+
+ if (Mlid == NULL) {
+
+ //
+ // No more memory available, unload opened MLID
+ //
+
+ NdisMlidUnloadMlid(Mlid);
+
+ return(STATUS_INSUFFICIENT_RESOURCES);
+
+ }
+
+ //
+ // Copy Array
+ //
+
+ RtlCopyMemory(Mlid, MlidBoards, sizeof(MLID_STRUCT) * CountMlidBoards);
+
+ //
+ // Init last cell
+ //
+
+ MlidBoards = Mlid;
+
+ MlidBoards[CountMlidBoards].Mlid = NULL;
+ MlidBoards[CountMlidBoards].BoardNumber = (UINT32)-1;
+
+ AllocatedMlidBoards++;
+
+ }
+
+ //
+ // Find an open index
+ //
+
+ for (i=0; i < AllocatedMlidBoards; i++) {
+
+ if (MlidBoards[i].Mlid == NULL) {
+
+ //
+ // Store into global array all info
+ //
+
+ MlidBoards[i].Mlid = Mlid;
+ MlidBoards[i].BoardNumber = Mlid->ConfigTable.MLIDCFG_BoardNumber;
+ MlidBoards[i].AdapterName = &(Mlid->AdapterName);
+
+ break;
+
+ }
+
+ }
+
+ //
+ // Set flag so we know to stay loaded.
+ //
+ LoadedADriver = TRUE;
+
+ }
+
+ //
+ // Get next ODI board to be loaded
+ //*\\ here - Config
+
+ //
+ // Get corresponding NDIS MAC Info
+ //*\\ here - Config
+
+ }
+
+ if (LoadedADriver) {
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+ return(NDIS_STATUS_FAILURE);
+
+}
+
+
+PMLID_STRUCT
+NdisMlidOpenMlid(
+ PVOID OdiRegistryPtr,
+ PVOID NdisRegistryPtr,
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will create a binding from an ODI board to an NDIS MAC. If the
+ NDIS MAC is not yet open, it will do so.
+
+Arguments:
+
+ OdiRegistryPtr - Pointer into the ODI registry information for this board number.
+
+ NdisRegistryPtr - Pointer into the corresponding NDIS registry for the ODI board.
+
+Return Value:
+
+ NULL - If error, else a pointer to the MLID structure.
+
+--*/
+
+{
+ PMLID_STRUCT Mlid;
+ PNDISMLID_StatsTable StatsTable;
+
+ UINT32 i;
+ UINT32 j;
+
+ UNICODE_STRING AdapterName;
+
+ NDIS_STATUS NdisStatus;
+ NDIS_STATUS OpenErrorStatus;
+
+ NDIS_HANDLE NdisBindingHandle;
+
+ NDIS_MEDIUM MediumArray[] = {NdisMedium802_3, NdisMedium802_5, NdisMediumFddi };
+ UINT SelectedMediumIndex;
+
+ UINT32 TotalFrameSize;
+ UINT16 FrameID;
+ UINT32 NdisLinkSpeed;
+ UINT32 NdisMacOptions;
+
+ PCM_RESOURCE_LIST Resources;
+
+ PNDIS_REQUEST NdisMlidRequest;
+
+ //
+ // Allocate memory for this MLID
+ //
+
+ Mlid = (PMLID_STRUCT)ExAllocatePool(NonPagedPool, sizeof(MLID_STRUCT));
+
+ if (Mlid == NULL) {
+
+ return(NULL);
+
+ }
+
+ RtlZeroMemory(Mlid, sizeof(MLID_STRUCT));
+
+ //
+ // Allocate NDIS_REQUEST for this initialization
+ //
+ NdisMlidRequest = (PNDIS_REQUEST)ExAllocatePool(NonPagedPool, sizeof(NDIS_REQUEST));
+
+ if (NdisMlidRequest == NULL) {
+
+ goto Fail1;
+
+ }
+
+ Mlid->SendPacketPool = (NDIS_HANDLE)NULL;
+ Mlid->SendBufferPool = (NDIS_HANDLE)NULL;
+ Mlid->ReceivePacketPool = (NDIS_HANDLE)NULL;
+ Mlid->ReceiveBufferPool = (NDIS_HANDLE)NULL;
+
+ //
+ // Allocate NDIS_PACKET_POOL for sends
+ //
+ NdisAllocatePacketPool(
+ &NdisStatus,
+ &(Mlid->SendPacketPool),
+ NDISMLID_SENDS_PER_MLID,
+ sizeof(MLID_RESERVED)
+ );
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ goto Fail2;
+
+ }
+
+ //
+ // Allocate NDIS_BUFFER_POOL for sends
+ //
+ NdisAllocateBufferPool(
+ &NdisStatus,
+ &(Mlid->SendBufferPool),
+ NDISMLID_SENDS_PER_MLID * NDISMLID_BUFFERS_PER_PACKET
+ );
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ goto Fail2;
+
+ }
+
+ //
+ // Set LSLFunctionList here
+ //*\\ here - How do I get the LSLFunctionList?
+
+ //
+ // Fail if count of functions is not enough, or if LSL version number is
+ // incorrect
+ //*\\ here - Implement check of LSLFunctionList.
+
+ //
+ // Open Send stage
+ //
+ Mlid->StageOpen = TRUE;
+
+ //
+
+ // Initialize completion event
+ //
+ KeInitializeEvent(
+ &(Mlid->MlidRequestCompleteEvent),
+ NotificationEvent,
+ FALSE
+ );
+
+ Mlid->UsingEvent = TRUE;
+
+ //
+ // Get name of NDIS MAC from registry
+ //*\\ here - Config
+
+
+ //
+ // Call NdisOpenAdapter
+ //
+ NdisOpenAdapter(
+ &NdisStatus,
+ &OpenErrorStatus,
+ &NdisBindingHandle,
+ &SelectedMediumIndex,
+ MediumArray,
+ 3,
+ NdisMlidProtocolHandle,
+ (NDIS_HANDLE)Mlid,
+ (PNDIS_STRING)(&AdapterName),
+ 0,
+ NULL
+ );
+
+ //
+ // if (pending), wait
+ //
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+
+ //
+ // Wait for open to complete
+ //
+
+ KeWaitForSingleObject(
+ &(Mlid->MlidRequestCompleteEvent),
+ Executive,
+ KernelMode,
+ TRUE,
+ (PTIME)NULL
+ );
+
+ KeResetEvent(&Mlid->MlidRequestCompleteEvent);
+
+ //
+ // Get status
+ //
+
+ NdisStatus = (NDIS_STATUS)(Mlid->RequestStatus);
+
+ }
+
+ //
+ // If failure, release resources
+ //
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ goto Fail1;
+
+ }
+
+ //
+ // Save Media type
+ //
+ Mlid->NdisMlidMedium = MediumArray[SelectedMediumIndex];
+
+ //
+ // Save Ndis MAC context
+ //
+ Mlid->NdisBindingHandle = NdisBindingHandle;
+
+ //
+ // Is NDIS MAC not already opened by another MLID?
+ //
+ for (i=0; i < AllocatedMlidBoards ; i++ ) {
+
+ if (MlidBoards[i].Mlid != NULL) {
+
+ //
+ // Are the names the same?
+ //
+
+ if (RtlEqualUnicodeString(&AdapterName, MlidBoards[i].AdapterName, TRUE)) {
+
+ //
+ // Store stat table pointer
+ //
+
+ StatsTable = (MlidBoards[i].Mlid)->StatsTable;
+ break;
+
+ }
+
+ }
+
+ }
+
+ //
+ // Did we find an NDIS MAC?
+ //
+
+ if (StatsTable == NULL) {
+
+ //
+ // Allocate memory for the MLID Statistic table
+ //
+
+ StatsTable = (PNDISMLID_StatsTable)ExAllocatePool(NonPagedPool,
+ sizeof(NDISMLID_StatsTable)
+ );
+
+ if (StatsTable == NULL) {
+
+ //
+ // Fail
+ //
+
+ goto Fail3;
+
+ }
+
+ //
+ // Initialize structure
+ //
+
+ RtlZeroMemory(StatsTable, sizeof(NDISMLID_StatsTable));
+
+ StatsTable->StatsTable.MStatTableMajorVer = 1;
+ StatsTable->StatsTable.MStatTableMinorVer = 0;
+
+ //
+ // Setup Generic counters
+ //
+ for (i = 0; i < NUM_GENERIC_COUNTS; i++) {
+
+ StatsTable->MLID_GenericCounts[i].StatString = &(NdisMlidGenericStatStrings[i]);
+ StatsTable->MLID_GenericCounts[i].StatUseFlag = NdisMlidGenericStatTypes[i];
+ StatsTable->MLID_GenericCounts[i].StatCounter = (PVOID)(&StatsTable->GenericCounts[i]);
+
+ }
+
+ StatsTable->StatsTable.MNumGenericCounters = NUM_GENERIC_COUNTS;
+ StatsTable->StatsTable.MGenericCountsPtr = &(StatsTable->MLID_GenericCounts);
+
+ //
+ // Setup Medium specific counters
+ //
+ switch (Mlid->NdisMlidMedium) {
+
+ case NdisMedium802_3:
+
+ for (i = 0; i < NUM_ETHERNET_COUNTS; i++) {
+
+ StatsTable->MLID_MediaCounts[i].StatString = &(NdisMlidEthernetStatStrings[i]);
+ StatsTable->MLID_MediaCounts[i].StatUseFlag = NdisMlidEthernetStatTypes[i];
+ StatsTable->MLID_MediaCounts[i].StatCounter = (PVOID)(&StatsTable->MediaCounts[i]);
+
+ }
+
+ StatsTable->StatsTable.MNumMediaCounters = NUM_ETHERNET_COUNTS;
+ StatsTable->StatsTable.MMediaCountsPtr = &(StatsTable->MLID_MediaCounts);
+
+ break;
+
+ case NdisMedium802_5:
+
+ for (i = 0; i < NUM_TOKEN_RING_COUNTS; i++) {
+
+ StatsTable->MLID_MediaCounts[i].StatString = &(NdisMlidTokenRingStatStrings[i]);
+ StatsTable->MLID_MediaCounts[i].StatUseFlag = NdisMlidTokenRingStatTypes[i];
+ StatsTable->MLID_MediaCounts[i].StatCounter = (PVOID)(&StatsTable->MediaCounts[i]);
+
+ }
+
+ StatsTable->StatsTable.MNumMediaCounters = NUM_TOKEN_RING_COUNTS;
+ StatsTable->StatsTable.MMediaCountsPtr = &(StatsTable->MLID_MediaCounts);
+
+ break;
+
+ case NdisMediumFddi:
+
+ for (i = 0; i < NUM_FDDI_COUNTS; i++) {
+
+ StatsTable->MLID_MediaCounts[i].StatString = &(NdisMlidFddiStatStrings[i]);
+ StatsTable->MLID_MediaCounts[i].StatUseFlag = NdisMlidFddiStatTypes[i];
+ StatsTable->MLID_MediaCounts[i].StatCounter = (PVOID)(&StatsTable->MediaCounts[i]);
+
+ }
+
+ StatsTable->StatsTable.MNumMediaCounters = NUM_FDDI_COUNTS;
+ StatsTable->StatsTable.MMediaCountsPtr = &(StatsTable->MLID_MediaCounts);
+
+ break;
+
+ }
+
+ }
+
+ //
+ // Link statistic table
+ //
+ Mlid->StatsTable = StatsTable;
+
+ //
+ // Increment reference count
+ //
+ StatsTable->References++;
+
+ //
+ // Get network address
+ //
+ NdisMlidRequest->RequestType = NdisRequestQueryInformation;
+
+ switch (Mlid->NdisMlidMedium) {
+
+ case NdisMedium802_3:
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid = OID_802_3_CURRENT_ADDRESS;
+ break;
+
+ case NdisMedium802_5:
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid = OID_802_5_CURRENT_ADDRESS;
+ break;
+
+ case NdisMediumFddi:
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid = OID_FDDI_LONG_CURRENT_ADDR;
+ break;
+
+ }
+
+ NdisMlidRequest->DATA.QUERY_INFORMATION.InformationBuffer = (PVOID)&(Mlid->ConfigTable.MLIDCFG_NodeAddress[0]);
+ NdisMlidRequest->DATA.QUERY_INFORMATION.InformationBufferLength = 6;
+ NdisMlidRequest->DATA.QUERY_INFORMATION.BytesWritten = 0;
+ NdisMlidRequest->DATA.QUERY_INFORMATION.BytesNeeded = 0;
+
+
+ NdisRequest(
+ &NdisStatus,
+ Mlid->NdisBindingHandle,
+ NdisMlidRequest
+ );
+
+ //
+ // if (pending), wait
+ //
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // Wait for request to complete
+ //
+
+ KeWaitForSingleObject(
+ &(Mlid->MlidRequestCompleteEvent),
+ Executive,
+ KernelMode,
+ TRUE,
+ (PTIME)NULL
+ );
+
+ KeResetEvent(&Mlid->MlidRequestCompleteEvent);
+
+ //
+ // Get status
+ //
+ NdisStatus = (NDIS_STATUS)Mlid->RequestStatus;
+
+ }
+
+ //
+ // If failure, release resources and close adapter
+ //
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ goto Fail4;
+ }
+
+
+ //
+ // Get FrameID for this MLID from registry, check that it is one we support.
+ //*\\ here - Config
+
+
+ //
+ // Get maximum total frame size
+ //
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_TOTAL_SIZE;
+ NdisMlidRequest->DATA.QUERY_INFORMATION.InformationBuffer = (PVOID)&(TotalFrameSize);
+ NdisMlidRequest->DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(TotalFrameSize);
+ NdisMlidRequest->DATA.QUERY_INFORMATION.BytesWritten = 0;
+ NdisMlidRequest->DATA.QUERY_INFORMATION.BytesNeeded = 0;
+
+ NdisRequest(
+ &NdisStatus,
+ Mlid->NdisBindingHandle,
+ NdisMlidRequest
+ );
+
+ //
+ // if (pending), wait
+ //
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // Wait for request to complete
+ //
+
+ KeWaitForSingleObject(
+ &(Mlid->MlidRequestCompleteEvent),
+ Executive,
+ KernelMode,
+ TRUE,
+ (PTIME)NULL
+ );
+
+ KeResetEvent(&Mlid->MlidRequestCompleteEvent);
+
+ //
+ // Get status
+ //
+ NdisStatus = (NDIS_STATUS)Mlid->RequestStatus;
+
+ }
+
+ //
+ // If failure, release resources and close adapter
+ //
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ goto Fail4;
+ }
+
+
+ //
+ // Get link speed
+ //
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid = OID_GEN_LINK_SPEED;
+ NdisMlidRequest->DATA.QUERY_INFORMATION.InformationBuffer = (PVOID)&(NdisLinkSpeed);
+ NdisMlidRequest->DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(NdisLinkSpeed);
+ NdisMlidRequest->DATA.QUERY_INFORMATION.BytesWritten = 0;
+ NdisMlidRequest->DATA.QUERY_INFORMATION.BytesNeeded = 0;
+
+ NdisRequest(
+ &NdisStatus,
+ Mlid->NdisBindingHandle,
+ NdisMlidRequest
+ );
+
+ //
+ // if (pending), wait
+ //
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // Wait for request to complete
+ //
+
+ KeWaitForSingleObject(
+ &(Mlid->MlidRequestCompleteEvent),
+ Executive,
+ KernelMode,
+ TRUE,
+ (PTIME)NULL
+ );
+
+ KeResetEvent(&Mlid->MlidRequestCompleteEvent);
+
+ //
+ // Get status
+ //
+ NdisStatus = (NDIS_STATUS)Mlid->RequestStatus;
+
+ }
+
+ //
+ // If failure, release resources and close adapter
+ //
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ goto Fail4;
+ }
+
+
+
+ //
+ // Get MAC_OPTIONS
+ //
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid = OID_GEN_MAC_OPTIONS;
+ NdisMlidRequest->DATA.QUERY_INFORMATION.InformationBuffer = (PVOID)&(NdisMacOptions);
+ NdisMlidRequest->DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(NdisMacOptions);
+ NdisMlidRequest->DATA.QUERY_INFORMATION.BytesWritten = 0;
+ NdisMlidRequest->DATA.QUERY_INFORMATION.BytesNeeded = 0;
+
+ NdisRequest(
+ &NdisStatus,
+ Mlid->NdisBindingHandle,
+ NdisMlidRequest
+ );
+
+ //
+ // if (pending), wait
+ //
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // Wait for request to complete
+ //
+
+ KeWaitForSingleObject(
+ &(Mlid->MlidRequestCompleteEvent),
+ Executive,
+ KernelMode,
+ TRUE,
+ (PTIME)NULL
+ );
+
+ KeResetEvent(&Mlid->MlidRequestCompleteEvent);
+
+ //
+ // Get status
+ //
+ NdisStatus = (NDIS_STATUS)Mlid->RequestStatus;
+
+ }
+
+ //
+ // If failure, release resources and close adapter
+ //
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ goto Fail4;
+ }
+
+
+ if ((NdisMacOptions & NDIS_MAC_OPTION_RECEIVE_SERIALIZED) &&
+ (NdisMacOptions & NDIS_MAC_OPTION_TRANSFERS_NOT_PEND)) {
+
+ //
+ // Allocate NDIS_PACKET_POOL for receives
+ //
+
+ NdisAllocatePacketPool(
+ &NdisStatus,
+ &(Mlid->ReceivePacketPool),
+ 1,
+ sizeof(MLID_RESERVED)
+ );
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ goto Fail4;
+
+ }
+
+ //
+ // Allocate NDIS_BUFFER_POOL for receives
+ // NOTE: In this case I added a huge number of NDIS_BUFFERS, since
+ // we only have one packet we need to be liberal in our guess of
+ // BUFFERs per PACKET.
+ //
+ NdisAllocateBufferPool(
+ &NdisStatus,
+ &(Mlid->ReceiveBufferPool),
+ NDISMLID_BUFFERS_PER_PACKET + 10
+ );
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ goto Fail4;
+
+ }
+
+ } else {
+
+ //
+ // Allocate NDIS_PACKET_POOL for receives
+ //
+ NdisAllocatePacketPool(
+ &NdisStatus,
+ &(Mlid->ReceivePacketPool),
+ NDISMLID_RECEIVES_PER_MLID,
+ sizeof(MLID_RESERVED)
+ );
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ goto Fail4;
+
+ }
+
+ //
+ // Allocate NDIS_BUFFER_POOL for receives
+ //
+ NdisAllocateBufferPool(
+ &NdisStatus,
+ &(Mlid->ReceiveBufferPool),
+ NDISMLID_RECEIVES_PER_MLID * NDISMLID_BUFFERS_PER_PACKET + 5
+ );
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ goto Fail4;
+
+ }
+
+ }
+
+
+
+ //
+ // Begin Init ConfigTable.
+ //
+
+
+ RtlCopyMemory(&(Mlid->ConfigTable.MLIDCFG_Signature[0]),
+ "HardwareDriverMLID ",
+ 26
+ );
+
+ Mlid->ConfigTable.MLIDCFG_MajorVersion = 1;
+ Mlid->ConfigTable.MLIDCFG_MinorVersion = 12;
+ Mlid->ConfigTable.MLIDCFG_ModeFlags = 0x24C9; // PromiscuousBit |
+ // SupFragECB |
+ // SupFrameDataSize |
+ // RawSend |
+ // RealDriver |
+ // MulticastBit
+
+ Mlid->ConfigTable.MLIDCFG_BoardNumber = (UINT16)-1;
+ Mlid->ConfigTable.MLIDCFG_BoardInstance = 1; //*\\ Should this change?
+ Mlid->ConfigTable.MLIDCFG_MaxFrameSize = TotalFrameSize;
+
+ switch (FrameID) {
+
+ case ETHERNET_II_FRAME_ID:
+
+ Mlid->ConfigTable.MLIDCFG_BestDataSize = TotalFrameSize - sizeof(Ethernet_II_Header);
+ Mlid->ConfigTable.MLIDCFG_WorstDataSize = TotalFrameSize - sizeof(Ethernet_II_Header);
+ break;
+
+ case ETHERNET_802_2_FRAME_ID:
+
+ Mlid->ConfigTable.MLIDCFG_BestDataSize = TotalFrameSize - sizeof(Ethernet_802_2_Header);
+ Mlid->ConfigTable.MLIDCFG_WorstDataSize = TotalFrameSize - sizeof(Ethernet_802_2_Header);
+ break;
+
+ case ETHERNET_802_3_FRAME_ID:
+
+ Mlid->ConfigTable.MLIDCFG_BestDataSize = TotalFrameSize - sizeof(Ethernet_802_3_Header);
+ Mlid->ConfigTable.MLIDCFG_WorstDataSize = TotalFrameSize - sizeof(Ethernet_802_3_Header);
+ break;
+
+ case ETHERNET_SNAP_FRAME_ID:
+
+ Mlid->ConfigTable.MLIDCFG_BestDataSize = TotalFrameSize - sizeof(Ethernet_Snap_Header);
+ Mlid->ConfigTable.MLIDCFG_WorstDataSize = TotalFrameSize - sizeof(Ethernet_Snap_Header);
+ break;
+
+ case FDDI_802_2_FRAME_ID:
+
+ Mlid->ConfigTable.MLIDCFG_BestDataSize = TotalFrameSize - sizeof(Fddi_802_2_Header);
+ Mlid->ConfigTable.MLIDCFG_WorstDataSize = TotalFrameSize - sizeof(Fddi_802_2_Header);
+ break;
+
+ case FDDI_SNAP_FRAME_ID:
+
+ Mlid->ConfigTable.MLIDCFG_BestDataSize = TotalFrameSize - sizeof(Fddi_Snap_Header);
+ Mlid->ConfigTable.MLIDCFG_WorstDataSize = TotalFrameSize - sizeof(Fddi_Snap_Header);
+ break;
+
+ case TOKEN_RING_SNAP_FRAME_ID:
+
+ Mlid->ConfigTable.MLIDCFG_BestDataSize = TotalFrameSize - sizeof(TokenRing_Header) - 8;
+ Mlid->ConfigTable.MLIDCFG_WorstDataSize = TotalFrameSize - sizeof(TokenRing_Header) - 26;
+ break;
+
+ case TOKEN_RING_802_2_FRAME_ID:
+
+ Mlid->ConfigTable.MLIDCFG_BestDataSize = TotalFrameSize - sizeof(TokenRing_Header) - 3;
+ Mlid->ConfigTable.MLIDCFG_WorstDataSize = TotalFrameSize - sizeof(TokenRing_Header) - 21;
+ break;
+
+ default:
+
+ //
+ // Invalid frame type. We should have already checked this.
+ //
+ ASSERT(0);
+
+ }
+
+ Mlid->ConfigTable.MLIDCFG_CardName = NULL; //*\\ here
+ Mlid->ConfigTable.MLIDCFG_ShortName = NULL; //*\\ here
+ Mlid->ConfigTable.MLIDCFG_FrameTypeString = &(NdisMlidFrameTypeStrings[FrameID]);
+ Mlid->ConfigTable.MLIDCFG_FrameID = FrameID;
+ Mlid->ConfigTable.MLIDCFG_TransportTime = (0x1000 / (NdisLinkSpeed / 10)) + 1;
+ Mlid->ConfigTable.MLIDCFG_SourceRouting = (PVOID)NULL;
+ Mlid->ConfigTable.MLIDCFG_LookAheadSize = 18;
+
+ //
+ // Convert to KBits/Second.
+ //
+ NdisLinkSpeed /= 10;
+
+ //
+ // Check if we can store it like this.
+ //
+ if (NdisLinkSpeed > 0x7FFF) {
+
+ //
+ // Convert to MBits/Second
+ //
+
+ NdisLinkSpeed /= 1000;
+
+ } else {
+
+ NdisLinkSpeed |= 0x8000;
+
+ }
+
+ Mlid->ConfigTable.MLIDCFG_LineSpeed = NdisLinkSpeed;
+ Mlid->ConfigTable.MLIDCFG_DriverMajorVer = 3;
+ Mlid->ConfigTable.MLIDCFG_DriverMinorVer = 0;
+ Mlid->ConfigTable.MLIDCFG_Flags = 0x600; // Adapter does group address filtering
+ Mlid->ConfigTable.MLIDCFG_SendRetries = (Mlid->NdisMlidMedium == NdisMedium802_3) ? 10 : 0;
+ Mlid->ConfigTable.MLIDCFG_Slot = 0; //*\\ change for EISA and MCA cards.
+
+ //
+ // Now we grunge through NDIS structures to get IoPort infor, Memory Info, DMA info
+ // and interrupt info.
+ //
+ Resources = ((PNDIS_OPEN_BLOCK)NdisBindingHandle)->AdapterHandle->Resources;
+
+ //
+ // First do port information
+ //
+ {
+ BOOLEAN TooManyPorts = FALSE;
+
+ for (i = 0; i < Resources->Count; i++) {
+
+ for (j=0; j < Resources->List[0].PartialResourceList.Count; j++) {
+
+ if (Resources->List[0].PartialResourceList.PartialDescriptors[j].Type ==
+ CmResourceTypePort) {
+
+ //
+ // Found a port
+ //
+
+ if (!TooManyPorts) {
+
+ TooManyPorts = TRUE;
+
+ //
+ // Store in Port0 holder
+ //
+ Mlid->ConfigTable.MLIDCFG_IOPort0 = (UINT16)(
+ Resources->List[0].PartialResourceList.PartialDescriptors[j].u.Port.Start.LowPart);
+
+ Mlid->ConfigTable.MLIDCFG_IORange0 = (UINT16)(
+ Resources->List[0].PartialResourceList.PartialDescriptors[j].u.Port.Length);
+
+ } else {
+
+ //
+ // Store in Port1 holder and exit port.
+ //
+ Mlid->ConfigTable.MLIDCFG_IOPort1 = (UINT16)(
+ Resources->List[0].PartialResourceList.PartialDescriptors[j].u.Port.Start.LowPart);
+
+ Mlid->ConfigTable.MLIDCFG_IORange1 = (UINT16)(
+ Resources->List[0].PartialResourceList.PartialDescriptors[j].u.Port.Length);
+
+ i = Resources->Count;
+ break;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ //
+ // Now do memory information
+ //
+ {
+ BOOLEAN TooManyMemorys = FALSE;
+
+ for (i = 0; i < Resources->Count; i++) {
+
+ for (j=0; j < Resources->List[0].PartialResourceList.Count; j++) {
+
+ if (Resources->List[0].PartialResourceList.PartialDescriptors[j].Type ==
+ CmResourceTypeMemory) {
+
+ //
+ // Found memory
+ //
+
+ if (!TooManyMemorys) {
+
+ TooManyMemorys = TRUE;
+
+ //
+ // Store in Memory0 holder
+ //
+ Mlid->ConfigTable.MLIDCFG_MemoryAddress0 = (UINT32)(
+ Resources->List[0].PartialResourceList.PartialDescriptors[j].u.Memory.Start.LowPart);
+
+ Mlid->ConfigTable.MLIDCFG_MemorySize0 = (UINT16)(
+ Resources->List[0].PartialResourceList.PartialDescriptors[j].u.Memory.Length / 16);
+
+ } else {
+
+ //
+ // Store in Memory1 holder and exit.
+ //
+ Mlid->ConfigTable.MLIDCFG_MemoryAddress1 = (UINT32)(
+ Resources->List[0].PartialResourceList.PartialDescriptors[j].u.Memory.Start.LowPart);
+
+ Mlid->ConfigTable.MLIDCFG_MemorySize1 = (UINT16)(
+ Resources->List[0].PartialResourceList.PartialDescriptors[j].u.Memory.Length / 16);
+
+ i = Resources->Count;
+ break;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+
+ //
+ // Now do interrupts
+ //
+ {
+ BOOLEAN TooManyInterrupts = FALSE;
+
+ for (i = 0; i < Resources->Count; i++) {
+
+ for (j=0; j < Resources->List[0].PartialResourceList.Count; j++) {
+
+ if (Resources->List[0].PartialResourceList.PartialDescriptors[j].Type ==
+ CmResourceTypeInterrupt) {
+
+ //
+ // Found interrupt
+ //
+
+ if (!TooManyInterrupts) {
+
+ TooManyInterrupts = TRUE;
+
+ //
+ // Store in Interrupt0 holder
+ //
+ Mlid->ConfigTable.MLIDCFG_Interrupt0 = (UINT8)(
+ Resources->List[0].PartialResourceList.PartialDescriptors[j].u.Interrupt.Level);
+
+ if (Resources->List[0].PartialResourceList.PartialDescriptors[j].ShareDisposition ==
+ CmResourceShareShared) {
+
+ Mlid->ConfigTable.MLIDCFG_SharingFlags |= 0x20;
+
+ }
+
+ } else {
+
+ //
+ // Store in Interrupt1 holder and exit.
+ //
+ Mlid->ConfigTable.MLIDCFG_Interrupt1 = (UINT8)(
+ Resources->List[0].PartialResourceList.PartialDescriptors[j].u.Interrupt.Level);
+
+ if (Resources->List[0].PartialResourceList.PartialDescriptors[j].ShareDisposition ==
+ CmResourceShareShared) {
+
+ Mlid->ConfigTable.MLIDCFG_SharingFlags |= 0x40;
+
+ }
+
+ i = Resources->Count;
+ break;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ //
+ // Now do DMA channels
+ //
+ {
+ BOOLEAN TooManyDMAs = FALSE;
+
+ for (i = 0; i < Resources->Count; i++) {
+
+ for (j=0; j < Resources->List[0].PartialResourceList.Count; j++) {
+
+ if (Resources->List[0].PartialResourceList.PartialDescriptors[j].Type ==
+ CmResourceTypeDma) {
+
+ //
+ // Found DMA Channel
+ //
+
+ if (!TooManyDMAs) {
+
+ TooManyDMAs = TRUE;
+
+ //
+ // Store in DMALine0 holder
+ //
+ Mlid->ConfigTable.MLIDCFG_DMALine0 = (UINT8)(
+ Resources->List[0].PartialResourceList.PartialDescriptors[j].u.Dma.Channel);
+
+ } else {
+
+ //
+ // Store in DMALine1 holder and exit.
+ //
+ Mlid->ConfigTable.MLIDCFG_DMALine1 = (UINT8)(
+ Resources->List[0].PartialResourceList.PartialDescriptors[j].u.Dma.Channel);
+
+ i = Resources->Count;
+ break;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ Mlid->ConfigTable.MLIDCFG_ResourceTag = 0;
+
+
+ //
+ // End of initialize ConfigTable.
+ //
+
+
+
+
+
+ //
+ // Register with LSL
+ //
+
+ (*(Mlid->LSLFunctionList->SupportAPIArray[RegisterMLID_INDEX]))(
+ NdisMlidHandlerInfo,
+ &(Mlid->ConfigTable),
+ &(Mlid->BoardNumber)
+ );
+
+ Mlid->UsingEvent = FALSE;
+
+ //
+ // Setup default packet filters
+ //
+
+ Mlid->RequestStatus = NDIS_STATUS_PENDING;
+
+ ASSERT(sizeof(TotalFrameSize) == 4);
+
+ TotalFrameSize = NDIS_PACKET_TYPE_DIRECTED |
+ NDIS_PACKET_TYPE_MULTICAST |
+ NDIS_PACKET_TYPE_BROADCAST;
+
+ NdisMlidRequest->DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
+ NdisMlidRequest->DATA.SET_INFORMATION.InformationBuffer = (PVOID)&(TotalFrameSize);
+ NdisMlidRequest->DATA.SET_INFORMATION.InformationBufferLength = sizeof(TotalFrameSize);
+ NdisMlidRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisMlidRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ NdisRequest(
+ &NdisStatus,
+ Mlid->NdisBindingHandle,
+ NdisMlidRequest
+ );
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // Get status and Semaphore is release inside RequestCompleteHandler
+ //
+ NdisStatus = (NDIS_STATUS)Mlid->RequestStatus;
+
+ } else {
+
+ ExFreePool(NdisMlidRequest);
+
+ }
+
+ //
+ // If failure, release resources and close adapter
+ //
+ if ((NdisStatus != NDIS_STATUS_SUCCESS) &&
+ (NdisStatus != NDIS_STATUS_PENDING)) {
+
+ goto Fail5;
+
+ }
+
+ //
+ // Time stamp the sucker
+ //
+ {
+ LARGE_INTEGER TimeStamp;
+
+ KeQuerySystemTime(&TimeStamp);
+ (*((PUINT32)((*(Mlid->StatsTable->StatsTable.MGenericCountsPtr))[13].StatCounter))) = // MAdapterOprTimeStamp
+ TimeStamp.LowPart;
+
+ }
+
+ NdisAcquireSpinLock(&(Mlid->MlidSpinLock));
+
+ if (Mlid->StatsTable->StatisticsOperational == FALSE) {
+
+ //
+ // Start the statistics timer
+ //
+ Mlid->StatsTable->StatisticsOperational = TRUE;
+
+ NdisInitializeTimer(&(Mlid->StatsTable->StatisticTimer),
+ NdisMlidStatisticTimer,
+ Mlid
+ );
+
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ NdisSetTimer(&(Mlid->StatsTable->StatisticTimer), 30000);
+
+ NdisAcquireSpinLock(&(Mlid->MlidSpinLock));
+
+ }
+
+ Mlid->NdisPacketFilterValue = NDIS_PACKET_TYPE_DIRECTED |
+ NDIS_PACKET_TYPE_MULTICAST |
+ NDIS_PACKET_TYPE_BROADCAST;
+
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ return(Mlid);
+
+Fail5:
+ //
+ // Deregister with LSL
+ //
+ (*(Mlid->LSLFunctionList->SupportAPIArray[DeRegisterMLID_INDEX]))(
+ Mlid->ConfigTable.MLIDCFG_BoardNumber
+ );
+
+Fail4:
+ //
+ // Free Receive packet pool
+ //
+ if (Mlid->ReceivePacketPool != (NDIS_HANDLE)NULL) {
+ NdisFreePacketPool(Mlid->ReceivePacketPool);
+ }
+
+ //
+ // Free Receive buffer pool
+ //
+ if (Mlid->ReceiveBufferPool != (NDIS_HANDLE)NULL) {
+ NdisFreeBufferPool(Mlid->ReceiveBufferPool);
+ }
+
+ //
+ // Free StatsTable
+ //
+ StatsTable->References--;
+ if (StatsTable->References == 0) {
+ ExFreePool(StatsTable);
+ }
+
+Fail3:
+ //
+ // Close Adapter
+ //
+ NdisCloseAdapter(&NdisStatus, Mlid->NdisBindingHandle);
+
+ //
+ // If pend, wait
+ //
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // Wait for close to complete
+ //
+
+ KeWaitForSingleObject(
+ &(Mlid->MlidRequestCompleteEvent),
+ Executive,
+ KernelMode,
+ TRUE,
+ (PTIME)NULL
+ );
+
+ KeResetEvent(&Mlid->MlidRequestCompleteEvent);
+
+ }
+
+Fail2:
+
+ //
+ // Free Send packet pool
+ //
+ if (Mlid->SendPacketPool != (NDIS_HANDLE)NULL) {
+ NdisFreePacketPool(Mlid->SendPacketPool);
+ }
+
+ //
+ // Free Send buffer pool
+ //
+ if (Mlid->SendBufferPool != (NDIS_HANDLE)NULL) {
+ NdisFreeBufferPool(Mlid->SendBufferPool);
+ }
+
+ //
+ // Free NDIS_REQUEST
+ //
+ if (Mlid->UsingEvent) {
+ ExFreePool(NdisMlidRequest);
+ }
+
+Fail1:
+
+ //
+ // Free Mlid structure
+ //
+ ExFreePool(Mlid);
+
+ return(NULL);
+
+}
+
diff --git a/private/ntos/ndis/lsl/lsl.h b/private/ntos/ndis/lsl/lsl.h
new file mode 100644
index 000000000..6a4528b44
--- /dev/null
+++ b/private/ntos/ndis/lsl/lsl.h
@@ -0,0 +1,526 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ lsl.c
+
+Abstract:
+
+ This file contains all the structures for the LSL driver.
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 3-8-93
+
+Environment:
+
+ Kernel Mode.
+
+Revision History:
+
+--*/
+
+typedef UCHAR MEON, *MEON_STRING;
+typedef UCHAR UINT8, *PUINT8;
+typedef USHORT UINT16, *PUINT16;
+typedef UINT UINT32, *PUINT32;
+
+
+typedef struct _UINT64_ {
+
+ UINT32 Low_UINT32;
+ UINT32 High_UINT32;
+
+} UINT64, *PUINT64;
+
+
+//
+// Definitions for Statistics Table Entries
+//
+
+typedef struct _StatTableEntry_ {
+
+ UINT32 StatUseFlag; // -1 == not in use, 0 == *StatCounter is PUINT32, 1 == PUINT64
+
+ PVOID StatCounter;
+
+ MEON_STRING *StatString;
+
+} StatTableEntry, *PStatTableEntry;
+
+
+
+//
+// Definitions for API Function Array passing, i.e. Information Block
+//
+
+typedef struct _INFO_BLOCK_ {
+
+ UINT32 NumberOfAPIs;
+
+ VOID (*SupportAPIArray[])();
+
+} INFO_BLOCK, *PINFO_BLOCK;
+
+
+
+
+//
+// Definitions for LSL
+//
+
+typedef struct _LogBrdStatTableEntry_ {
+
+ UINT32 LogBrd_TransmittedPackets;
+
+ UINT32 LogBrd_ReceivedPackets;
+
+ UINT32 LogBrd_UnclaimedPackets;
+
+ UINT32 LogBrd_Reserved;
+
+} LogBrdStatTableEntry, *PLogBrdStatTableEntry;
+
+
+typedef struct _LSL_ConfigTable_ {
+
+ UINT16 LConfigTableMajorVer;
+ UINT16 LConfigTableMinorVer;
+
+ MEON_STRING *LSLLongName;
+ MEON_STRING *LSLShortName;
+
+ UINT16 LSLMajorVer;
+ UINT16 LSLMinorVer;
+
+ UINT32 LMaxNumberOfBoards;
+ UINT32 LMaxNumberOfStacks;
+
+ UINT32 LConfigTableReserved0;
+ UINT32 LConfigTableReserved1;
+ UINT32 LConfigTableReserved2;
+
+} LSL_ConfigTable, *PLSL_ConfigTable;
+
+
+typedef struct _LSL_StatsTable_ {
+
+ UINT16 LStatTableMajorVer;
+ UINT16 LStatTableMinorVer;
+
+ UINT32 LNumGenericCounters;
+ StatTableEntry (*LGenericCountsPtr)[];
+
+ UINT32 LNumLogicalBoards;
+ LogBrdStatTableEntry (*LogicalBoardStatTablePtr)[];
+
+ UINT32 LNumCustomCounters;
+ StatTableEntry (*LCustomCountersPtr)[];
+
+} LSL_StatsTable, *PLSL_StatsTable;
+
+
+
+
+//
+// Definitions for LookAhead and Event Control Blocks (ECB)
+//
+
+typedef struct _LOOKAHEAD_ {
+
+ //
+ // Media specific header
+ //
+ PUINT8 LkAhd_MediaHeaderPtr;
+
+ //
+ // Rest of lookahead
+ //
+ PUINT8 LkAhd_DataLookAheadPtr;
+
+ UINT32 LkAhd_DataLookAheadLen;
+ UINT32 LkAhd_FrameDataSize;
+ UINT32 LkAhd_BoardNumber;
+ UINT8 LkAhd_ProtocolID[6];
+
+ UINT16 LkAhd_PadAlignBytes1;
+
+ UINT8 LkAhd_ImmediateAddress[6];
+
+ UINT16 LkAhd_PadAlignBytes2;
+
+ UINT32 LkAhd_FrameDataStartCopyOffset;
+ UINT32 LkAhd_FrameDataBytesWanted;
+
+ UINT32 LkAhd_PktAttr;
+ UINT32 LkAhd_DestType;
+
+ PVOID LkAhd_Reserved0;
+ PVOID LkAhd_Reserved1;
+
+} LOOKAHEAD, *PLOOKAHEAD;
+
+
+typedef struct _FRAGMENTSTRUCT_ {
+
+ VOID *FragmentAddress;
+ UINT32 FragmentLength;
+
+} FRAGMENTSTRUCT, *PFRAGMENTSTRUCT;
+
+
+typedef struct _ECB_ {
+
+ struct _ECB_ *ECB_NextLink;
+ struct _ECB_ *ECB_PreviousLink;
+
+ UINT16 ECB_Status;
+
+ VOID (*ECB_ESR)(struct _ECB_ *);
+
+ UINT16 ECB_StackID;
+
+ UINT8 ECB_ProtocolID[6];
+
+ UINT32 ECB_BoardNumber;
+
+ UINT8 ECB_ImmediateAddress[6];
+
+ union {
+ UINT8 DWs_i8val[8];
+ UINT16 DWs_i16val[4];
+ UINT32 DWs_i32val[2];
+ UINT64 DWs_i64val;
+ PVOID DWs_pval;
+ } ECB_DriverWorkspace;
+
+ union {
+ UINT8 PWs_i8val[8];
+ UINT16 PWs_i16val[4];
+ UINT32 PWs_i32val[2];
+ UINT64 PWs_i64val;
+ PVOID PWs_pval[2];
+ } ECB_ProtocolWorkspace;
+
+ UINT32 ECB_DataLength;
+
+ UINT32 ECB_FragmentCount;
+
+ FRAGMENTSTRUCT ECB_Fragment[1];
+
+} ECB, *PECB;
+
+
+typedef struct _AESECB_ {
+
+ struct _AESECB_ *AES_Link;
+
+ UINT32 AES_MSecondValue;
+ UINT16 AES_Status;
+
+ VOID (*AES_ESR)(struct _ECB_ *);
+
+ PVOID AES_Context;
+
+} AESECB, *PAESECB;
+
+
+
+//
+// Definitions for Protocol Stack Configuration And Statistics Tables
+//
+
+
+typedef struct _PS_ConfigTable_ {
+
+ UINT16 PConfigTableMajorVer;
+ UINT16 PConfigTableMinorVer;
+
+ MEON_STRING *PProtocolLongName;
+ MEON_STRING *PProtocolShortName;
+
+ UINT16 PProtocolMajorVer;
+ UINT16 PProtocolMinorVer;
+
+} PS_ConfigTable, *PPS_ConfigTable;
+
+
+typedef struct _PS_StatsTable_ {
+
+ UINT16 PStatTableMajorVer;
+ UINT16 PStatTableMinorVer;
+
+ UINT32 PNumGenericCounters;
+ StatTableEntry (*PGenericCountsPtr)[];
+
+ UINT32 PNumCustomCounters;
+ StatTableEntry (*PCustomCountersPtr)[];
+
+} PS_StatsTable, *PPS_StatsTable;
+
+
+
+
+//
+// Definitions for MLID Configuration and Statistics Tables and Misc structures
+//
+
+typedef struct _MLID_ConfigTable_ {
+
+ UINT8 MLIDCFG_Signature[26];
+ UINT8 MLIDCFG_MajorVersion;
+ UINT8 MLIDCFG_MinorVersion;
+ UINT8 MLIDCFG_NodeAddress[6];
+ UINT16 MLIDCFG_ModeFlags;
+ UINT16 MLIDCFG_BoardNumber;
+ UINT16 MLIDCFG_BoardInstance;
+ UINT32 MLIDCFG_MaxFrameSize;
+ UINT32 MLIDCFG_BestDataSize;
+ UINT32 MLIDCFG_WorstDataSize;
+ MEON_STRING *MLIDCFG_CardName;
+ MEON_STRING *MLIDCFG_ShortName;
+ MEON_STRING *MLIDCFG_FrameTypeString;
+ UINT16 MLIDCFG_Reserved0;
+ UINT16 MLIDCFG_FrameID;
+ UINT16 MLIDCFG_TransportTime;
+ PVOID MLIDCFG_SourceRouting;
+ UINT16 MLIDCFG_LineSpeed;
+ UINT16 MLIDCFG_LookAheadSize;
+ UINT8 MLIDCFG_Reserved1[8];
+ UINT8 MLIDCFG_DriverMajorVer;
+ UINT8 MLIDCFG_DriverMinorVer;
+ UINT16 MLIDCFG_Flags;
+ UINT16 MLIDCFG_SendRetries;
+ PVOID MLIDCFG_DriverLink;
+ UINT16 MLIDCFG_SharingFlags;
+ UINT16 MLIDCFG_Slot;
+ UINT16 MLIDCFG_IOPort0;
+ UINT16 MLIDCFG_IORange0;
+ UINT16 MLIDCFG_IOPort1;
+ UINT16 MLIDCFG_IORange1;
+ UINT32 MLIDCFG_MemoryAddress0;
+ UINT16 MLIDCFG_MemorySize0;
+ UINT32 MLIDCFG_MemoryAddress1;
+ UINT16 MLIDCFG_MemorySize1;
+ UINT8 MLIDCFG_Interrupt0;
+ UINT8 MLIDCFG_Interrupt1;
+ UINT8 MLIDCFG_DMALine0;
+ UINT8 MLIDCFG_DMALine1;
+ PVOID MLIDCFG_ResourceTag;
+ PVOID MLIDCFG_Config;
+ PVOID MLIDCFG_CommandString;
+ UINT8 MLIDCFG_LogicalName[6];
+ UINT32 MLIDCFG_LinearMemory0;
+ UINT32 MLIDCFG_LinearMemory1;
+ UINT16 MLIDCFG_ChannelNumber;
+ UINT16 MLIDCFG_BusTag;
+ UINT8 MLIDCFG_IOReserved[4];
+
+} MLID_ConfigTable, *PMLID_ConfigTable;
+
+
+typedef struct _MLID_StatsTable_ {
+
+ UINT16 MStatTableMajorVer;
+ UINT16 MStatTableMinorVer;
+
+ UINT32 MNumGenericCounters;
+ StatTableEntry (*MGenericCountsPtr)[];
+
+ UINT32 MNumMediaCounters;
+ StatTableEntry (*MMediaCountsPtr)[];
+
+ UINT32 MNumCustomCounters;
+ StatTableEntry (*MCustomCoutnersPtr)[];
+
+} MLID_StatsTable, *PMLID_StatsTable;
+
+
+typedef struct _MLID_Reg_ {
+
+ VOID (*MLIDSendHandler)(PECB);
+
+ PINFO_BLOCK MLIDControlHandler;
+
+} MLID_Reg, *PMLID_Reg;
+
+
+
+//
+// Definitions for Bound Protocol Stacks
+//
+
+
+typedef struct _PS_BoundNode_ {
+
+ MEON_STRING *ProtocolName;
+
+ PECB (*ProtocolReceiveHandler)(PLOOKAHEAD);
+
+ PINFO_BLOCK ProtocolControlHandler;
+
+} PS_BoundNode, *PPS_BoundNode;
+
+
+
+
+//
+// Definitions for PreScan Rx and Default Chained Protocol Stacks
+//
+
+
+typedef struct _PS_ChainedRxNode_ {
+
+ struct _PS_ChainedRxNode_ *StackChainLink;
+
+ UINT32 StackChainBoardNumber;
+
+ UINT32 StackChainPositionRequested;
+
+ PECB (*StackChainHandler)(PLOOKAHEAD);
+
+ PINFO_BLOCK StackChainControl;
+ UINT32 StackChainFilter;
+ PVOID StackChainContext;
+
+} PS_ChainedRxNode, *PPS_ChainedRxNode;
+
+
+//
+// Definitions for PreScan Tx Chained Protocol Stacks
+//
+
+
+typedef struct _PS_ChainedTxNode_ {
+
+ struct _PS_ChainedTxNode_ *StackChainLink;
+
+ UINT32 StackChainBoardNumber;
+
+ UINT32 StackChainPositionRequested;
+
+ UINT32 (*StackChainHandler)(PECB);
+
+ PINFO_BLOCK StackChainControl;
+ UINT32 StackChainFilter;
+ PVOID StackChainContext;
+
+} PS_ChainedTxNode, *PPS_ChainedTxNode;
+
+
+
+//
+// Return value definitions
+//
+
+
+#define SUCCESSFUL 0x00000000
+#define RESPONSE_DELAYED 0x00000001
+
+#define BAD_COMMAND 0xFFFFFF81
+#define BAD_PARAMETER 0xFFFFFF82
+#define DUPLICATE_ENTRY 0xFFFFFF83
+#define FAIL 0xFFFFFF84
+#define ITEM_NOT_PRESENT 0xFFFFFF85
+#define NO_MORE_ITEMS 0xFFFFFF86
+#define NO_SUCH_DRIVER 0xFFFFFF87
+#define NO_SUCH_HANDLER 0xFFFFFF88
+#define OUT_OF_RESOURCES 0xFFFFFF89
+#define RX_OVERFLOW 0xFFFFFF8A
+#define IN_CRITICAL_SECTION 0xFFFFFF8B
+#define TRANSMIT_FAILED 0xFFFFFF8C
+#define PACKET_UNDELIVERABLE 0xFFFFFF8D
+
+#define CANCELED 0xFFFFFFFC
+
+
+
+//
+// Definitions for Protocol Control Operations
+//
+
+#define GetProtocolStackConfiguration_INDEX 0
+#define GetProtocolStackStatistics_INDEX 1
+#define Bind_INDEX 2
+#define MLIDDeRegistered_INDEX 3
+#define UnBind_INDEX 4
+#define PromiscuousStatus_INDEX 5
+
+
+
+typedef UINT32 (*PCO_Bind)(UINT32, MEON_STRING *);
+typedef PPS_ConfigTable (*PCO_GetProtocolStackConfiguration)(VOID);
+typedef PPS_StatsTable (*PCO_GetProtocolStackStatistics)(VOID);
+typedef VOID (*PCO_MLIDDeRegistered)(UINT32);
+typedef UINT32 (*PCO_UnBind)(UINT32, UINT32);
+typedef UINT32 (*PCO_PromiscuousState)(UINT32, UINT32);
+
+
+//
+// Definitions for LSL API Services
+//
+
+#define GetSizeECB_INDEX 0
+#define ReturnECB_INDEX 1
+#define CancelEvent_INDEX 2
+#define ScheduleAESEvent_INDEX 3
+#define CancelAESEvent_INDEX 4
+#define GetIntervalMarker_INDEX 5
+#define RegisterStack_INDEX 6
+#define DeRegisterStack_INDEX 7
+#define LSLReserved0_INDEX 8
+#define LSLReserved1_INDEX 9
+#define LSLReserved2_INDEX 10
+#define GetStackECB_INDEX 11
+#define SendPacket_INDEX 12
+#define FastSendComplete_INDEX 13
+#define SendComplete_INDEX 14
+#define RegisterMLID_INDEX 15
+#define GetStackIDFromName_INDEX 16
+#define GetPIDFromStackIDBoard_INDEX 17
+#define GetMLIDControlEntry_INDEX 18
+#define GetProtocolControlEntry_INDEX 19
+#define GetLSLStatistics_INDEX 20
+#define BindStack_INDEX 21
+#define UnbindStack_INDEX 22
+#define AddProtocolID_INDEX 23
+#define GetBoundBoardInfo_INDEX 24
+#define GetLSLConfiguration_INDEX 25
+#define DeRegisterMLID_INDEX 26
+#define RegisterDefaultChain_INDEX 27
+#define RegisterPreScanRxChain_INDEX 28
+#define RegisterPreScanTxChain_INDEX 29
+#define DeRegisterDefaultChain_INDEX 30
+#define DeRegisterPreScanRxChain_INDEX 31
+#define DeRegisterPreScanTxChain_INDEX 32
+#define GetStartofChain_INDEX 33
+#define ReSubmitDefault_INDEX 34
+#define ReSubmitPreScanRx_INDEX 35
+#define ReSubmitPreScanTx_INDEX 36
+#define HoldEvent_INDEX 37
+#define FastHoldEvent_INDEX 38
+#define GetMaxECBBufferSize_INDEX 39
+#define LSLReserved3_INDEX 40
+#define ServiceEvents_INDEX 41
+#define ModifyStackEvents_INDEX 42
+#define ControlStackFilter_INDEX 43
+
+//
+// Definitions for MLID Control Services
+//
+
+
+#define MCS_GetMLIDConfiguration_INDEX 0x00
+#define MCS_GetMLIDStatistics_INDEX 0x01
+#define MCS_AddMulticastAddress_INDEX 0x02
+#define MCS_DeleteMulticastAddress_INDEX 0x03
+#define MCS_MLIDShutdown_INDEX 0x05
+#define MCS_MLIDReset_INDEX 0x06
+#define MCS_SetLookAheadSize_INDEX 0x09
+#define MCS_PromiscuousChange_INDEX 0x0A
+#define MCS_MLIDManagement_INDEX 0x0D
+
+
+typedef PVOID (*PLSL_SR_FUNCTION)(UINT32, PUINT32, PUINT8);
diff --git a/private/ntos/ndis/lsl/lslmlid.c b/private/ntos/ndis/lsl/lslmlid.c
new file mode 100644
index 000000000..a1f0b1b17
--- /dev/null
+++ b/private/ntos/ndis/lsl/lslmlid.c
@@ -0,0 +1,2085 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ lslmlid.c
+
+Abstract:
+
+ This file contains all the MLID interface routines to the LSL
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 3-8-93
+
+Environment:
+
+ Kernel Mode.
+
+Revision History:
+
+--*/
+
+#include <ndis.h>
+#include "lsl.h"
+#include "frames.h"
+#include "lslmlid.h"
+#include "mlid.h"
+
+
+//
+// A global which has pointers to the functions in this file. Used for registering
+// with the LSL.
+//
+INFO_BLOCK
+NdisMlidInfoBlock = {
+ 0xE,
+ {
+ GetMLIDConfiguration,
+ GetMLIDStatistics,
+ AddMulticastAddress,
+ DeleteMulticastAddress,
+ NULL,
+ MLIDShutdown,
+ MLIDReset,
+ NULL,
+ NULL,
+ SetLookAheadSize,
+ PromiscuousChange,
+ NULL,
+ NULL,
+ MLIDManagement
+ }
+};
+
+MLID_Reg
+NdisMlidHandlerInfo = {
+ MLIDSendHandler,
+ &NdisMlidInfoBlock
+};
+
+
+
+UINT32
+BuildNewMulticastList(
+ PMLID_STRUCT Mlid,
+ PUINT8 AddMulticastAddr
+ );
+
+UINT32
+BuildNewFunctionalAddr(
+ PMLID_STRUCT Mlid,
+ PUINT8 AddFunctionalAddr
+ );
+
+
+UINT32
+RemoveFromMulticastList(
+ PMLID_STRUCT Mlid,
+ PUINT8 DelMulticastAddr
+ );
+
+UINT32
+RemoveFromFunctionalAddr(
+ PMLID_STRUCT Mlid,
+ PUINT8 DelFunctionalAddr
+ );
+
+
+
+
+
+PMLID_ConfigTable
+GetMLIDConfiguration(
+ UINT32 BoardNumber
+ )
+
+/*++
+
+Routine Description:
+
+ Returns a pointer to the MLIDs configuration table for the specified logical
+ board. This commnand is supported by all MLIDs. A separate configuration
+ table is maintained by the MLID for each adapter/frame-type combination.
+
+Arguments:
+
+ BoardNumber - The board number.
+
+Return Value:
+
+ PMLID_ConfigTable - A pointer to tyhe MLIDs configuration table.
+ NULL - Reports the BAD_PARAMETER condition, MLID does not exist.
+
+--*/
+
+{
+ UINT32 i;
+ PMLID_ConfigTable ConfigTable;
+
+ NdisAcquireSpinLock(&NdisMlidSpinLock);
+
+ //
+ // Verify that BoardNumber is in valid range
+ //
+
+ for (i =0 ; i < AllocatedMlidBoards; i++) {
+
+ if (MlidBoards[i].BoardNumber == BoardNumber) {
+
+ break;
+
+ }
+
+ }
+
+ if (i == AllocatedMlidBoards) {
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ return(NULL);
+
+ }
+
+ //
+ // If BoardNumber is not open, fail.
+ //
+
+ if (MlidBoards[i].Mlid == NULL) {
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ return(NULL);
+
+ }
+
+ //
+ // If Board is unloading - fail
+ //
+ if (MlidBoards[i].Mlid->Unloading) {
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ return(NULL);
+ }
+
+ //
+ // return pointer to configuration table.
+ //
+
+ ConfigTable = &(MlidBoards[i].Mlid->ConfigTable);
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ return(ConfigTable);
+
+}
+
+
+PMLID_StatsTable
+GetMLIDStatistics(
+ UINT32 BoardNumber
+ )
+
+/*++
+
+Routine Description:
+
+ Returns a pointer to the MLIDs statistics table for the specified board. All
+ MLIDs support this command. The MLID maintains one statistics table for each
+ physical adapter. Each frame-type (or logical board) present for that physical
+ adapter uses the same table. The board number can be any of the logical
+ board values present for the physical adapter. Regardless of the logical
+ board number, GetMLIDStatistics will return the same table.
+
+Arguments:
+
+ BoardNumber - The board number.
+
+Return Value:
+
+ PMLID_Statistics - A pointer to the MLIDs Statistics Table.
+
+ NULL - Reports the BAD_PARAMETER condition.
+
+--*/
+
+{
+ UINT32 i;
+ PMLID_StatsTable StatsTable;
+
+ NdisAcquireSpinLock(&NdisMlidSpinLock);
+
+ //
+ // Verify that BoardNumber is in valid range
+ //
+
+ for (i =0 ; i < AllocatedMlidBoards; i++) {
+
+ if (MlidBoards[i].BoardNumber == BoardNumber) {
+
+ break;
+
+ }
+
+ }
+
+ if (i == AllocatedMlidBoards) {
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ return(NULL);
+
+ }
+
+ //
+ // If BoardNumber is not open, fail.
+ //
+
+ if (MlidBoards[i].Mlid == NULL) {
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ return(NULL);
+
+ }
+
+ //
+ // If Board is unloading - fail
+ //
+ if (MlidBoards[i].Mlid->Unloading) {
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ return(NULL);
+ }
+
+ //
+ // return pointer to statistics table.
+ //
+
+ StatsTable = &(MlidBoards[i].Mlid->StatsTable->StatsTable);
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ return(StatsTable);
+
+}
+
+
+UINT32
+AddMulticastAddress(
+ UINT32 BoardNumber,
+ PUINT8 AddMulticastAddr
+ )
+
+/*++
+
+Routine Description:
+
+ The MLID manages enabled multicast addresses according to the physical adapter.
+ The format of the multicast address is LAN medium dependent. This routine
+ allows a protocol to add a single multicast address.
+
+Arguments:
+
+ BoardNumber - The board number.
+
+ AddMulticastAddr - A pointer to the multicast address to add.
+
+Return Value:
+
+ SUCCESSFUL - Success.
+ OUT_OF_RESOURCES - The MLID has insufficient resources to enable the address.
+ BAD_PARAMETER - The address is not valid for the MLIDs media type.
+ BAD_COMMAND - Multicast addressing is not supported by the MLID.
+
+--*/
+
+{
+ PMLID_STRUCT Mlid;
+ UINT32 i;
+ UINT32 Status;
+ NDIS_STATUS NdisStatus;
+ PNDIS_REQUEST NdisMlidRequest;
+
+ NdisAcquireSpinLock(&NdisMlidSpinLock);
+
+ //
+ // Verify that BoardNumber is in valid range
+ //
+
+ for (i =0 ; i < AllocatedMlidBoards; i++) {
+
+ if (MlidBoards[i].BoardNumber == BoardNumber) {
+
+ break;
+
+ }
+
+ }
+
+ if (i == AllocatedMlidBoards) {
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ return(BAD_PARAMETER);
+
+ }
+
+ //
+ // If BoardNumber is not open, fail.
+ //
+
+ if (MlidBoards[i].Mlid == NULL) {
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ return(BAD_PARAMETER);
+
+ }
+
+ //
+ // If Board is unloading - fail
+ //
+ if (MlidBoards[i].Mlid->Unloading) {
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ return(BAD_PARAMETER);
+ }
+
+ Mlid = MlidBoards[i].Mlid;
+
+ NdisAcquireSpinLock(&(Mlid->MlidSpinLock));
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ switch (Mlid->NdisMlidMedium) {
+
+ case NdisMedium802_3:
+ Status = BuildNewMulticastList(Mlid, AddMulticastAddr);
+ break;
+
+ case NdisMedium802_5:
+ Status = BuildNewFunctionalAddr(Mlid, AddMulticastAddr);
+ break;
+
+ case NdisMediumFddi:
+ Status = BuildNewMulticastList(Mlid, AddMulticastAddr);
+ break;
+
+ }
+
+ if (Status == DUPLICATE_ENTRY) {
+
+ //
+ // The address already existed, return success
+ //
+
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+ return(SUCCESSFUL);
+ }
+
+ if (Status != SUCCESSFUL) {
+
+ //
+ // return error message -- most likely, OUT_OF_RESOURCES
+ //
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+ return(Status);
+
+ }
+
+ //
+ // Allocate NDIS_REQUEST
+ //
+ NdisMlidRequest = (PNDIS_REQUEST)ExAllocatePool(NonPagedPool, sizeof(NDIS_REQUEST));
+
+ if (NdisMlidRequest == NULL) {
+
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+ return(OUT_OF_RESOURCES);
+
+ }
+
+ //
+ // Build an NDIS request
+ //
+ NdisMlidRequest->RequestType = NdisRequestSetInformation;
+
+ switch (Mlid->NdisMlidMedium) {
+
+ case NdisMedium802_3:
+ NdisMlidRequest->DATA.SET_INFORMATION.Oid = OID_802_3_MULTICAST_LIST;
+ NdisMlidRequest->DATA.SET_INFORMATION.InformationBuffer = (PVOID)(Mlid->MulticastAddresses.Addresses);
+ NdisMlidRequest->DATA.SET_INFORMATION.InformationBufferLength =
+ Mlid->MulticastAddresses.MACount * 6;
+ break;
+
+ case NdisMedium802_5:
+ NdisMlidRequest->DATA.SET_INFORMATION.Oid = OID_802_5_CURRENT_FUNCTIONAL;
+ NdisMlidRequest->DATA.SET_INFORMATION.InformationBuffer = (PVOID)&(Mlid->MulticastAddresses.FunctionalAddr);
+ NdisMlidRequest->DATA.SET_INFORMATION.InformationBufferLength = 4;
+ break;
+
+ case NdisMediumFddi:
+ NdisMlidRequest->DATA.SET_INFORMATION.Oid = OID_FDDI_LONG_MULTICAST_LIST;
+ NdisMlidRequest->DATA.SET_INFORMATION.InformationBuffer = (PVOID)(Mlid->MulticastAddresses.Addresses);
+ NdisMlidRequest->DATA.SET_INFORMATION.InformationBufferLength =
+ Mlid->MulticastAddresses.MACount * 6;
+ break;
+
+ }
+
+ NdisMlidRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisMlidRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ Mlid->RequestStatus = NDIS_STATUS_PENDING;
+
+ //
+ // Release spin lock
+ //
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ //
+ // Submit NDIS request
+ //
+
+ NdisRequest(
+ &NdisStatus,
+ Mlid->NdisBindingHandle,
+ NdisMlidRequest
+ );
+
+ //
+ // If it pended, see if it completed already.
+ //
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ if ((NDIS_STATUS)Mlid->RequestStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // Assume it will complete successfully
+ //
+ NdisStatus = NDIS_STATUS_SUCCESS;
+
+ } else {
+
+ NdisStatus = (NDIS_STATUS)Mlid->RequestStatus;
+
+ }
+
+ } else {
+
+ //
+ // Free NDIS_REQUEST
+ //
+ ExFreePool(NdisMlidRequest);
+
+ }
+
+ //
+ // return status
+ //
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ return(SUCCESSFUL);
+
+ }
+
+ NdisAcquireSpinLock(&(Mlid->MlidSpinLock));
+
+ //
+ // Remove the address - error
+ //
+
+ switch (Mlid->NdisMlidMedium) {
+
+ case NdisMedium802_3:
+ Status = RemoveFromMulticastList(Mlid, AddMulticastAddr);
+ break;
+
+ case NdisMedium802_5:
+ Status = RemoveFromFunctionalAddr(Mlid, AddMulticastAddr);
+ break;
+
+ case NdisMediumFddi:
+ Status = RemoveFromMulticastList(Mlid, AddMulticastAddr);
+ break;
+
+ }
+
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ if (NdisStatus == NDIS_STATUS_RESOURCES) {
+
+ return(OUT_OF_RESOURCES);
+
+ }
+
+ return(BAD_PARAMETER);
+
+}
+
+
+UINT32
+DeleteMulticastAddress(
+ UINT32 BoardNumber,
+ PUINT8 DelMulticastAddr
+ )
+
+/*++
+
+Routine Description:
+
+ Disables the reception of a previously enabled multicast address.
+
+Arguments:
+
+ BoardNumber - The board number.
+
+ DelMulticastAddr - The address to remove/disable.
+
+Return Value:
+
+ SUCCESSFUL - Success.
+ ITEM_NOT_PRESENT - The specified address is not enabled for the MLID.
+ BAD_PARAMETER - The address is not valid for the MLIDs media type.
+ BAD_COMMAND - Multicast addressing is not supported by the MLID.
+
+--*/
+
+{
+ PMLID_STRUCT Mlid;
+ UINT32 i;
+ UINT32 Status;
+ NDIS_STATUS NdisStatus;
+ PNDIS_REQUEST NdisMlidRequest;
+
+ NdisAcquireSpinLock(&NdisMlidSpinLock);
+
+ //
+ // Verify that BoardNumber is in valid range
+ //
+
+ for (i =0 ; i < AllocatedMlidBoards; i++) {
+
+ if (MlidBoards[i].BoardNumber == BoardNumber) {
+
+ break;
+
+ }
+
+ }
+
+ if (i == AllocatedMlidBoards) {
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ return(BAD_PARAMETER);
+
+ }
+
+ //
+ // If BoardNumber is not open, fail.
+ //
+
+ if (MlidBoards[i].Mlid == NULL) {
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ return(BAD_PARAMETER);
+
+ }
+
+ //
+ // If Board is unloading - fail
+ //
+ if (MlidBoards[i].Mlid->Unloading) {
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ return(BAD_PARAMETER);
+ }
+
+ Mlid = MlidBoards[i].Mlid;
+
+ NdisAcquireSpinLock(&(Mlid->MlidSpinLock));
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ switch (Mlid->NdisMlidMedium) {
+
+ case NdisMedium802_3:
+ Status = RemoveFromMulticastList(Mlid, DelMulticastAddr);
+ break;
+
+ case NdisMedium802_5:
+ Status = RemoveFromFunctionalAddr(Mlid, DelMulticastAddr);
+ break;
+
+ case NdisMediumFddi:
+ Status = RemoveFromMulticastList(Mlid, DelMulticastAddr);
+ break;
+
+ }
+
+ if (Status == DUPLICATE_ENTRY) {
+
+ //
+ // The address still exists, return success
+ //
+
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+ return(SUCCESSFUL);
+ }
+
+ if (Status != SUCCESSFUL) {
+
+ //
+ // return error message -- most likely, ITEM_NOT_PRESENT
+ //
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+ return(Status);
+
+ }
+
+ //
+ // Allocate NDIS_REQUEST
+ //
+ NdisMlidRequest = (PNDIS_REQUEST)ExAllocatePool(NonPagedPool, sizeof(NDIS_REQUEST));
+
+ if (NdisMlidRequest == NULL) {
+
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+ return(OUT_OF_RESOURCES);
+
+ }
+
+
+ //
+ // Build an NDIS request
+ //
+ NdisMlidRequest->RequestType = NdisRequestSetInformation;
+
+ switch (Mlid->NdisMlidMedium) {
+
+ case NdisMedium802_3:
+ NdisMlidRequest->DATA.SET_INFORMATION.Oid = OID_802_3_MULTICAST_LIST;
+ NdisMlidRequest->DATA.SET_INFORMATION.InformationBuffer = (PVOID)(Mlid->MulticastAddresses.Addresses);
+ NdisMlidRequest->DATA.SET_INFORMATION.InformationBufferLength =
+ Mlid->MulticastAddresses.MACount * 6;
+ break;
+
+ case NdisMedium802_5:
+ NdisMlidRequest->DATA.SET_INFORMATION.Oid = OID_802_5_CURRENT_FUNCTIONAL;
+ NdisMlidRequest->DATA.SET_INFORMATION.InformationBuffer = (PVOID)&(Mlid->MulticastAddresses.FunctionalAddr);
+ NdisMlidRequest->DATA.SET_INFORMATION.InformationBufferLength = 4;
+ break;
+
+ case NdisMediumFddi:
+ NdisMlidRequest->DATA.SET_INFORMATION.Oid = OID_FDDI_LONG_MULTICAST_LIST;
+ NdisMlidRequest->DATA.SET_INFORMATION.InformationBuffer = (PVOID)(Mlid->MulticastAddresses.Addresses);
+ NdisMlidRequest->DATA.SET_INFORMATION.InformationBufferLength =
+ Mlid->MulticastAddresses.MACount * 6;
+ break;
+
+ }
+
+ NdisMlidRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisMlidRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ Mlid->RequestStatus = NDIS_STATUS_PENDING;
+
+ //
+ // Release spin lock
+ //
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ //
+ // Submit NDIS request
+ //
+
+ NdisRequest(
+ &NdisStatus,
+ Mlid->NdisBindingHandle,
+ NdisMlidRequest
+ );
+
+ //
+ // If it pended, see if it completed already.
+ //
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ if ((NDIS_STATUS)Mlid->RequestStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // Assume it will complete successfully
+ //
+ NdisStatus = NDIS_STATUS_SUCCESS;
+
+ } else {
+
+ NdisStatus = (NDIS_STATUS)Mlid->RequestStatus;
+
+ }
+
+ } else {
+
+ //
+ // Free NDIS_REQUEST
+ //
+ ExFreePool(NdisMlidRequest);
+
+ }
+
+ //
+ // return status
+ //
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ return(SUCCESSFUL);
+
+ }
+
+ //
+ // Put the address back -- error
+ //
+
+ NdisAcquireSpinLock(&(Mlid->MlidSpinLock));
+
+ switch (Mlid->NdisMlidMedium) {
+
+ case NdisMedium802_3:
+ Status = BuildNewMulticastList(Mlid, DelMulticastAddr);
+ break;
+
+ case NdisMedium802_5:
+ Status = BuildNewFunctionalAddr(Mlid, DelMulticastAddr);
+ break;
+
+ case NdisMediumFddi:
+ Status = BuildNewMulticastList(Mlid, DelMulticastAddr);
+ break;
+
+ }
+
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ return(BAD_PARAMETER);
+}
+
+
+UINT32
+MLIDShutdown(
+ UINT32 BoardNumber,
+ UINT32 ShutDownType
+ )
+
+/*++
+
+Routine Description:
+
+ Allows an application to shut down a physical adapter.
+
+Arguments:
+
+ BoardNumber - The board number.
+
+ ShutDownType - Form of shutdown desired: 0 == shutdown hardware and deregister
+ from LSL, 0 != shutdown hardware only.
+
+Return Value:
+
+ SUCCESSFUL - Success.
+ FAIL - Could not shutdown hardware.
+ BAD_COMMAND - The MLID does not support this command.
+
+--*/
+
+{
+
+ //
+ // Always return BAD_COMMAND. First, because it is easy. Second because
+ // we cannot guarantee that the we know of all accesses to the NDIS MAC.
+ //
+
+ return(BAD_COMMAND);
+
+}
+
+
+UINT32
+MLIDReset(
+ UINT32 BoardNumber
+ )
+
+/*++
+
+Routine Description:
+
+ Causes the MLID to totally re-initialize the physical adapter. Leaves any
+ multicast addresses that were previously enabled.
+
+Arguments:
+
+ BoardNumber - The board number.
+
+Return Value:
+
+ SUCCESSFUL - Success.
+ FAIL - The MLID was unable to reset its hardware.
+ BAD_COMMAND - The MLID does not support this command.
+
+--*/
+
+{
+ PMLID_STRUCT Mlid;
+ UINT32 i;
+ NDIS_STATUS NdisStatus;
+
+ NdisAcquireSpinLock(&NdisMlidSpinLock);
+
+ //
+ // Verify that BoardNumber is in valid range
+ //
+
+ for (i =0 ; i < AllocatedMlidBoards; i++) {
+
+ if (MlidBoards[i].BoardNumber == BoardNumber) {
+
+ break;
+
+ }
+
+ }
+
+ if (i == AllocatedMlidBoards) {
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ return(FAIL);
+
+ }
+
+ //
+ // If BoardNumber is not open, fail.
+ //
+
+ if (MlidBoards[i].Mlid == NULL) {
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ return(FAIL);
+
+ }
+
+ //
+ // If Board is unloading - fail
+ //
+ if (MlidBoards[i].Mlid->Unloading) {
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ return(FAIL);
+ }
+
+ Mlid = MlidBoards[i].Mlid;
+
+ NdisAcquireSpinLock(&(Mlid->MlidSpinLock));
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ //
+ // Hack so that we will cancel all requests until the reset completes
+ //
+ Mlid->Unloading = TRUE;
+
+ (*((PUINT32)((*(Mlid->StatsTable->StatsTable.MGenericCountsPtr))[12].StatCounter)))++; // MAdapterResetCount
+
+ //
+ // Time stamp the sucker
+ //
+ {
+ LARGE_INTEGER TimeStamp;
+
+ KeQuerySystemTime(&TimeStamp);
+ (*((PUINT32)((*(Mlid->StatsTable->StatsTable.MGenericCountsPtr))[13].StatCounter))) = // MAdapterOprTimeStamp
+ TimeStamp.LowPart;
+
+ }
+
+
+ //
+ // Release spin lock
+ //
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ //
+ // Call NdisReset
+ //
+
+ NdisReset(
+ &NdisStatus,
+ Mlid->NdisBindingHandle
+ );
+
+ //
+ // If it pended, see if it completed already.
+ //
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ if ((NDIS_STATUS)Mlid->RequestStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // Assume it will complete successfully
+ //
+ NdisStatus = NDIS_STATUS_SUCCESS;
+
+ } else {
+
+ NdisAcquireSpinLock(&(Mlid->MlidSpinLock));
+
+ Mlid->Unloading = FALSE;
+
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ NdisStatus = (NDIS_STATUS)Mlid->RequestStatus;
+
+ }
+
+ } else {
+
+ NdisAcquireSpinLock(&(Mlid->MlidSpinLock));
+
+ Mlid->Unloading = FALSE;
+
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ }
+
+ //
+ // return status
+ //
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ return(SUCCESSFUL);
+
+ }
+
+ return(FAIL);
+
+}
+
+
+UINT32
+SetLookAheadSize(
+ UINT32 BoardNumber,
+ UINT32 RequestSize
+ )
+
+/*++
+
+Routine Description:
+
+ Tells the MLID the amount of look ahead data that is needed by the caller
+ to properly process received packets.
+
+Arguments:
+
+ BoardNumber - The board number.
+
+ RequestedSize - Requested look ahead size in bytes.
+
+Return Value:
+
+ SUCCESSFUL - Success.
+ BAD_PARAMETER - Requested look ahead size exceed bounds.
+
+--*/
+
+{
+ PMLID_STRUCT Mlid;
+ UINT32 i;
+ UINT32 OldSize;
+ NDIS_STATUS NdisStatus;
+ PNDIS_REQUEST NdisMlidRequest;
+
+ //
+ // Verify that the size is ok
+ //
+
+ if (RequestSize > (256 - 40)) { // 40 is largest Media header size (TR SNAP w/ SR)
+
+ return(BAD_PARAMETER);
+
+ }
+
+ RequestSize += 40;
+
+ NdisAcquireSpinLock(&NdisMlidSpinLock);
+
+ //
+ // Verify that BoardNumber is in valid range
+ //
+
+ for (i =0 ; i < AllocatedMlidBoards; i++) {
+
+ if (MlidBoards[i].BoardNumber == BoardNumber) {
+
+ break;
+
+ }
+
+ }
+
+ if (i == AllocatedMlidBoards) {
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ return(BAD_PARAMETER);
+
+ }
+
+ //
+ // If BoardNumber is not open, fail.
+ //
+
+ if (MlidBoards[i].Mlid == NULL) {
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ return(BAD_PARAMETER);
+
+ }
+
+ //
+ // If Board is unloading - fail
+ //
+ if (MlidBoards[i].Mlid->Unloading) {
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ return(BAD_PARAMETER);
+ }
+
+
+ Mlid = MlidBoards[i].Mlid;
+
+ NdisAcquireSpinLock(&(Mlid->MlidSpinLock));
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ //
+ // Allocate NDIS_REQUEST
+ //
+ NdisMlidRequest = (PNDIS_REQUEST)ExAllocatePool(NonPagedPool, sizeof(NDIS_REQUEST));
+
+ if (NdisMlidRequest == NULL) {
+
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+ return(OUT_OF_RESOURCES);
+
+ }
+
+ //
+ // Store lookahead size
+ //
+ OldSize = Mlid->ConfigTable.MLIDCFG_LookAheadSize;
+ Mlid->ConfigTable.MLIDCFG_LookAheadSize = RequestSize;
+
+
+ //
+ // Build an NDIS request
+ //
+ NdisMlidRequest->RequestType = NdisRequestSetInformation;
+
+ NdisMlidRequest->DATA.SET_INFORMATION.Oid = OID_GEN_MAXIMUM_LOOKAHEAD;
+ NdisMlidRequest->DATA.SET_INFORMATION.InformationBuffer = (PVOID)&(Mlid->ConfigTable.MLIDCFG_LookAheadSize);
+ NdisMlidRequest->DATA.SET_INFORMATION.InformationBufferLength = sizeof(UINT32);
+
+ NdisMlidRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisMlidRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ Mlid->RequestStatus = NDIS_STATUS_PENDING;
+
+ //
+ // Release spin lock
+ //
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ //
+ // Submit NDIS request
+ //
+
+ NdisRequest(
+ &NdisStatus,
+ Mlid->NdisBindingHandle,
+ NdisMlidRequest
+ );
+
+ //
+ // If it pended, see if it completed already.
+ //
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ if ((NDIS_STATUS)Mlid->RequestStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // Assume it will complete successfully
+ //
+ NdisStatus = NDIS_STATUS_SUCCESS;
+
+ } else {
+
+ NdisStatus = (NDIS_STATUS)Mlid->RequestStatus;
+
+ }
+
+ } else {
+
+ //
+ // Free NDIS_REQUEST
+ //
+ ExFreePool(NdisMlidRequest);
+
+ }
+
+ //
+ // return status
+ //
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ return(SUCCESSFUL);
+
+ }
+
+ //
+ // Restore old size
+ //
+ Mlid->ConfigTable.MLIDCFG_LookAheadSize = OldSize;
+
+ return(BAD_PARAMETER);
+
+}
+
+
+UINT32
+PromiscuousChange(
+ UINT32 BoardNumber,
+ UINT32 PromiscuousState,
+ UINT32 PromiscuousMode
+ )
+
+/*++
+
+Routine Description:
+
+ Used to enable and disable promiscuous mode on the MLIDs adapter. A protocol
+ stack can enable promiscuous mode multiple times without error; however, only
+ the current call is in effect. If the LAN medium or adapter doees not distinquish
+ between MAC and non-MAC frames, both frames are assumed for the PromiscuousMode
+ mask.
+
+ The MLID keeps a counter for each promiscuous mode and disables only when the
+ count reaches zero.
+
+Arguments:
+
+ BoardNumber - The board number.
+
+ PromiscuousState - If 0, then disables promiscuous mode, else enables promiscuous mode.
+
+ PromiscuousMode - Has the mask for what type of frames the MLID is to
+ promiscuously receive. 0x1 - MAC Frames, 0x2 - Non-MAC Frames, 0x3 - Both.
+
+Return Value:
+
+ SUCCESSFUL - Success.
+ BAD_COMMAND - Promiscuous mode is not supported by the MLID.
+
+--*/
+
+{
+ PMLID_STRUCT Mlid;
+ UINT32 i;
+ UINT32 OldFilterValue;
+ UINT32 OldCount;
+ NDIS_STATUS NdisStatus;
+ PNDIS_REQUEST NdisMlidRequest;
+
+ NdisAcquireSpinLock(&NdisMlidSpinLock);
+
+ //
+ // Verify that BoardNumber is in valid range
+ //
+
+ for (i =0 ; i < AllocatedMlidBoards; i++) {
+
+ if (MlidBoards[i].BoardNumber == BoardNumber) {
+
+ break;
+
+ }
+
+ }
+
+ if (i == AllocatedMlidBoards) {
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ return(BAD_PARAMETER);
+
+ }
+
+ //
+ // If BoardNumber is not open, fail.
+ //
+
+ if (MlidBoards[i].Mlid == NULL) {
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ return(BAD_PARAMETER);
+
+ }
+
+ //
+ // If Board is unloading - fail
+ //
+ if (MlidBoards[i].Mlid->Unloading) {
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ return(BAD_PARAMETER);
+ }
+
+ Mlid = MlidBoards[i].Mlid;
+
+ NdisAcquireSpinLock(&(Mlid->MlidSpinLock));
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ //
+ // If already enabled and we are to enable it, then increment counter and exit
+ //
+ if ((PromiscuousState != 0) &&
+ (Mlid->PromiscuousModeEnables != 0)) {
+
+ Mlid->PromiscuousModeEnables++;
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+ return(SUCCESSFUL);
+
+ }
+
+ //
+ // If we are to disable it and count > 1 then decrement counter and exit
+ //
+ if ((PromiscuousState == 0) &&
+ (Mlid->PromiscuousModeEnables > 1)) {
+
+ Mlid->PromiscuousModeEnables--;
+
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+ return(SUCCESSFUL);
+
+ }
+
+ //
+ // Allocate NDIS_REQUEST
+ //
+ NdisMlidRequest = (PNDIS_REQUEST)ExAllocatePool(NonPagedPool, sizeof(NDIS_REQUEST));
+
+ if (NdisMlidRequest == NULL) {
+
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+ return(OUT_OF_RESOURCES);
+
+ }
+
+ //
+ // Save old value
+ //
+ OldFilterValue = Mlid->NdisPacketFilterValue;
+ OldCount = Mlid->PromiscuousModeEnables;
+
+ if (PromiscuousState == 0) {
+
+ Mlid->PromiscuousModeEnables = 0;
+ Mlid->NdisPacketFilterValue &= ~(NDIS_PACKET_TYPE_PROMISCUOUS);
+
+ } else {
+
+ Mlid->PromiscuousModeEnables = 1;
+ Mlid->NdisPacketFilterValue |= NDIS_PACKET_TYPE_PROMISCUOUS;
+
+ }
+
+ //
+ // Build an NDIS request
+ //
+ NdisMlidRequest->RequestType = NdisRequestSetInformation;
+
+ NdisMlidRequest->DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
+ NdisMlidRequest->DATA.SET_INFORMATION.InformationBuffer = (PVOID)&(Mlid->NdisPacketFilterValue);
+ NdisMlidRequest->DATA.SET_INFORMATION.InformationBufferLength = sizeof(UINT32);
+
+ NdisMlidRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisMlidRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ Mlid->RequestStatus = NDIS_STATUS_PENDING;
+
+ //
+ // Release spin lock
+ //
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ //
+ // Submit NDIS request
+ //
+
+ NdisRequest(
+ &NdisStatus,
+ Mlid->NdisBindingHandle,
+ NdisMlidRequest
+ );
+
+ //
+ // If it pended, see if it completed already.
+ //
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ if ((NDIS_STATUS)Mlid->RequestStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // Assume it will complete successfully
+ //
+ NdisStatus = NDIS_STATUS_SUCCESS;
+
+ } else {
+
+ NdisStatus = (NDIS_STATUS)Mlid->RequestStatus;
+
+ }
+
+ } else {
+
+ //
+ // Free NDIS_REQUEST
+ //
+ ExFreePool(NdisMlidRequest);
+
+ }
+
+ //
+ // return status
+ //
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ return(SUCCESSFUL);
+
+ }
+
+ //
+ // restore state
+ //
+ NdisAcquireSpinLock(&(Mlid->MlidSpinLock));
+
+ Mlid->NdisPacketFilterValue = OldFilterValue;
+ Mlid->PromiscuousModeEnables = OldCount;
+
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ return(BAD_COMMAND);
+
+}
+
+
+UINT32
+MLIDManagement(
+ UINT32 BoardNumber,
+ PECB ManagementECB
+ )
+
+/*++
+
+Routine Description:
+
+ Allows a management entity to access management information from/and control
+ an MLID.
+
+Arguments:
+
+ BoardNumber - The board number.
+
+ ManagementECB - A pointer to an ECB containing the management information.
+
+Return Value:
+
+ SUCCESSFUL - Success.
+ RESPONSE_DELAYED - Command will complete asyncronously.
+ BAD_COMMAND - Not supported.
+ BAD_PARAMETER - The Protocol ID field is invalid.
+ NO_SUCH_HANDLER - Management entity for the Management Handle in teh ECB does
+ not exist
+
+--*/
+
+{
+
+ //
+ // Always return BAD_COMMAND.
+ //
+
+ return(BAD_COMMAND);
+
+}
+
+
+VOID
+MLIDSendHandler(
+ PECB SendECB
+ )
+
+/*++
+
+Routine Description:
+
+ This routine takes an ECB, assembles a packet based on the frame-type and
+ sends it on the wire.
+
+Arguments:
+
+ SendECB - A pointer to the ECB discribing the data and destination address for
+ the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PMLID_STRUCT Mlid;
+ UINT32 i;
+ BOOLEAN Result;
+
+ NdisAcquireSpinLock(&NdisMlidSpinLock);
+
+ //
+ // Verify that BoardNumber is in valid range
+ //
+
+ for (i =0 ; i < AllocatedMlidBoards; i++) {
+
+ if (MlidBoards[i].BoardNumber == SendECB->ECB_BoardNumber) {
+
+ break;
+
+ }
+
+ }
+
+ if (i == AllocatedMlidBoards) {
+
+ //
+ // Cancel the ECB
+ //
+
+ SendECB->ECB_Status = (UINT16)CANCELED;
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ //
+ // We could try to find a board number with a link to the LSL, but
+ // in any case we might fail. The transport and/or LSL has hosed us,
+ // so we will just let it sit.
+ //
+ return;
+
+ }
+
+ //
+ // If BoardNumber is not open, fail.
+ //
+
+ if (MlidBoards[i].Mlid == NULL) {
+
+
+ //
+ // Cancel the ECB
+ //
+
+ SendECB->ECB_Status = (UINT16)CANCELED;
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ //
+ // We could try to find a board number with a link to the LSL, but
+ // in any case we might fail. The transport and/or LSL has hosed us,
+ // so we will just let it sit.
+ //
+ return;
+
+ }
+
+ //
+ // If Board is unloading - fail
+ //
+ if (MlidBoards[i].Mlid->Unloading) {
+
+
+ //
+ // Cancel the ECB
+ //
+
+ SendECB->ECB_Status = (UINT16)CANCELED;
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ //
+ // We could try to find a board number with a link to the LSL, but
+ // in any case we might fail. The transport and/or LSL has hosed us,
+ // so we will just let it sit.
+ //
+ return;
+ }
+
+ Mlid = MlidBoards[i].Mlid;
+
+ NdisAcquireSpinLock(&(Mlid->MlidSpinLock));
+
+ NdisReleaseSpinLock(&NdisMlidSpinLock);
+
+ //
+ // Update MTotalGroupAddrTxCount
+ //
+ switch (Mlid->NdisMlidMedium) {
+
+ case NdisMediumFddi:
+ case NdisMedium802_3:
+
+ if (ETH_IS_BROADCAST(SendECB->ECB_ImmediateAddress)) {
+ (*((PUINT32)((*(Mlid->StatsTable->StatsTable.MGenericCountsPtr))[10].StatCounter)))++;
+ break;
+ }
+
+ if (ETH_IS_MULTICAST(SendECB->ECB_ImmediateAddress)) {
+ (*((PUINT32)((*(Mlid->StatsTable->StatsTable.MGenericCountsPtr))[10].StatCounter)))++;
+ break;
+ }
+
+ if (ETH_IS_MULTICAST(SendECB->ECB_ImmediateAddress)) {
+ (*((PUINT32)((*(Mlid->StatsTable->StatsTable.MGenericCountsPtr))[10].StatCounter)))++;
+ break;
+ }
+ break;
+
+ case NdisMedium802_5:
+
+ TR_IS_BROADCAST(SendECB->ECB_ImmediateAddress, &Result);
+ if (Result == TRUE) {
+ (*((PUINT32)((*(Mlid->StatsTable->StatsTable.MGenericCountsPtr))[10].StatCounter)))++;
+ break;
+ }
+
+ TR_IS_GROUP(SendECB->ECB_ImmediateAddress, &Result);
+ if (Result == TRUE) {
+ (*((PUINT32)((*(Mlid->StatsTable->StatsTable.MGenericCountsPtr))[10].StatCounter)))++;
+ break;
+ }
+
+ TR_IS_FUNCTIONAL(SendECB->ECB_ImmediateAddress, &Result);
+ if (Result == TRUE) {
+ (*((PUINT32)((*(Mlid->StatsTable->StatsTable.MGenericCountsPtr))[10].StatCounter)))++;
+ break;
+ }
+ break;
+
+ }
+
+ (*((PUINT32)((*(Mlid->StatsTable->StatsTable.MGenericCountsPtr))[14].StatCounter)))++; // MQDepth
+
+ //
+ // Put ECB on send queue
+ //
+
+ if (Mlid->FirstPendingSend == NULL) {
+
+ Mlid->FirstPendingSend = SendECB;
+ Mlid->LastPendingSend = SendECB;
+ SendECB->ECB_NextLink = NULL;
+ SendECB->ECB_PreviousLink = NULL;
+
+ } else {
+
+ Mlid->LastPendingSend->ECB_NextLink = SendECB;
+ SendECB->ECB_PreviousLink = Mlid->LastPendingSend;
+ SendECB->ECB_NextLink = NULL;
+ Mlid->LastPendingSend = SendECB;
+
+ }
+
+ //
+ // Send all packets possible
+ //
+
+ if (Mlid->StageOpen && !Mlid->InSendPacket) {
+
+ SendPackets(Mlid);
+
+ }
+
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+}
+
+
+UINT32
+BuildNewMulticastList(
+ PMLID_STRUCT Mlid,
+ PUINT8 AddMulticastAddr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine takes a multicast addresses for either Ethernet or FDDI and
+ adds it to the Mlids database if it does not exist, otherwise it increments
+ the reference count on the address if it does exist.
+
+Arguments:
+
+ Mlid - Pointer to the MLID.
+
+ AddMulticastAddr - The multicast address to add.
+
+Return Value:
+
+ SUCCESSFUL - Success.
+ DUPLICATE_ENTRY - The address already existed in the database.
+ OUT_OF_RESOURCES - No memory avaiable to grow database.
+
+--*/
+
+{
+ UINT32 i;
+
+ //
+ // If address already exists, increment counter.
+ //
+ for (i = 0; i < Mlid->MulticastAddresses.MACount; i++) {
+
+ if (RtlCompareMemory(Mlid->MulticastAddresses.Addresses + i * 6,
+ AddMulticastAddr,
+ 6
+ ) == 0) {
+
+ //
+ // Increment count and exit
+ //
+
+ Mlid->MulticastAddresses.EnableCounts[i]++;
+ return(DUPLICATE_ENTRY);
+
+ }
+
+ }
+
+ //
+ // Allocate space for new array, if necessary
+ //
+ if (Mlid->MulticastAddresses.MACount == Mlid->MulticastAddresses.MAAllocated) {
+
+ PUINT8 TmpAddressArray;
+ PUINT32 TmpCountArray;
+
+ //
+ // Allocate memory for new array
+ //
+
+ TmpAddressArray = (PUINT8)ExAllocatePool(NonPagedPool,
+ 6 * (Mlid->MulticastAddresses.MACount + 2)
+ );
+
+ if (TmpAddressArray == NULL) {
+
+ return(OUT_OF_RESOURCES);
+
+ }
+
+ TmpCountArray = (PUINT32)ExAllocatePool(NonPagedPool,
+ sizeof(UINT32) *
+ (Mlid->MulticastAddresses.MACount + 2)
+ );
+
+ if (TmpCountArray == NULL) {
+
+ return(OUT_OF_RESOURCES);
+
+ }
+
+ //
+ // Copy over old addresses
+ //
+ RtlCopyMemory(TmpAddressArray,
+ Mlid->MulticastAddresses.Addresses,
+ 6 * Mlid->MulticastAddresses.MACount
+ );
+
+ //
+ // Copy over old counts
+ //
+ RtlCopyMemory(TmpCountArray,
+ Mlid->MulticastAddresses.EnableCounts,
+ sizeof(UINT32) * Mlid->MulticastAddresses.MACount
+ );
+
+ //
+ // Free old resources
+ //
+ ExFreePool(Mlid->MulticastAddresses.Addresses);
+ ExFreePool(Mlid->MulticastAddresses.EnableCounts);
+
+ //
+ // Save new space
+ //
+ Mlid->MulticastAddresses.Addresses = TmpAddressArray;
+ Mlid->MulticastAddresses.EnableCounts = TmpCountArray;
+
+ //
+ // Increment allocated count
+ //
+ Mlid->MulticastAddresses.MAAllocated += 2;
+
+ }
+
+ //
+ // Put address in new slot
+ //
+ RtlCopyMemory(Mlid->MulticastAddresses.Addresses +
+ Mlid->MulticastAddresses.MACount * 6,
+ AddMulticastAddr,
+ 6
+ );
+
+ //
+ // Set reference count
+ //
+ Mlid->MulticastAddresses.EnableCounts[Mlid->MulticastAddresses.MACount] = 1;
+
+ Mlid->MulticastAddresses.MACount++;
+
+ return(SUCCESSFUL);
+
+}
+
+
+UINT32
+BuildNewFunctionalAddr(
+ PMLID_STRUCT Mlid,
+ PUINT8 AddFunctionalAddr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine takes a functional address(es) for token ring and
+ adds it to the Mlid functional address if it does not exist, otherwise
+ it increments the reference count on the address(es) if it does exist.
+
+Arguments:
+
+ Mlid - Pointer to the MLID.
+
+ AddFunctionalAddr - The functional address to add.
+
+Return Value:
+
+ SUCCESSFUL - Success.
+ DUPLICATE_ENTRY - The address already existed in the database.
+ OUT_OF_RESOURCES - No memory avaiable to grow database.
+
+--*/
+
+{
+ UINT32 i;
+ UINT32 ShortenedFunctionalAddr;
+ UNALIGNED UINT32 *PAddr;
+ UINT32 NewAddressBits;
+ UINT32 OldAddressBits;
+
+ if (Mlid->MulticastAddresses.MAAllocated == 0) {
+
+ //
+ // Get memory for the counts
+ //
+
+ Mlid->MulticastAddresses.EnableCounts = (PUINT32)ExAllocatePool(NonPagedPool,
+ sizeof(UINT32) * 32
+ );
+
+ if (Mlid->MulticastAddresses.EnableCounts == NULL) {
+
+ return(OUT_OF_RESOURCES);
+
+ }
+
+ RtlZeroMemory(Mlid->MulticastAddresses.EnableCounts, sizeof(UINT32) * 32);
+
+ Mlid->MulticastAddresses.MAAllocated = 32;
+
+ }
+
+ //
+ // Get low four bytes of address
+ //
+ PAddr = (UNALIGNED UINT32 *)(AddFunctionalAddr + 2);
+ ShortenedFunctionalAddr = *PAddr;
+
+ //
+ // Get new bits and old bits
+ //
+ OldAddressBits = Mlid->MulticastAddresses.FunctionalAddr & ShortenedFunctionalAddr;
+ NewAddressBits = ShortenedFunctionalAddr ^ OldAddressBits;
+
+ //
+ // Increment count of each bit that exists in current functional address
+ //
+ i = 0;
+
+ while (OldAddressBits != 0) {
+
+ if (OldAddressBits & 1) {
+
+ Mlid->MulticastAddresses.EnableCounts[i]++;
+
+ }
+
+ OldAddressBits >>= 1;
+ i++;
+
+ }
+
+ if (NewAddressBits == 0) {
+
+ return(DUPLICATE_ENTRY);
+
+ }
+
+ //
+ // Store new bits
+ //
+
+ Mlid->MulticastAddresses.FunctionalAddr |= NewAddressBits;
+
+ //
+ // Set counts of each new address bit
+ //
+
+ i = 0;
+
+ while (NewAddressBits != 0) {
+
+ if (NewAddressBits & 1) {
+
+ Mlid->MulticastAddresses.EnableCounts[i] = 1;
+
+ }
+
+ NewAddressBits >>= 1;
+ i++;
+
+ }
+
+ return(SUCCESSFUL);
+
+}
+
+
+UINT32
+RemoveFromMulticastList(
+ PMLID_STRUCT Mlid,
+ PUINT8 DelMulticastAddr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine takes a multicast addresses for either Ethernet or FDDI and
+ removes it from the Mlids database if the reference count is one, otherwise
+ it decrements the reference count on the address.
+
+Arguments:
+
+ Mlid - Pointer to the MLID.
+
+ DelMulticastAddr - The multicast address to add.
+
+Return Value:
+
+ SUCCESSFUL - Success and address is removed.
+ ITEM_NOT_PRESENT - The address does not exist in the database.
+ DUPLICATE_ENTRY - Success and address still exists.
+
+--*/
+
+{
+ UINT32 i;
+
+ //
+ // If address already exists, decrement counter.
+ //
+ for (i = 0; i < Mlid->MulticastAddresses.MACount; i++) {
+
+ if (RtlCompareMemory(Mlid->MulticastAddresses.Addresses + i * 6,
+ DelMulticastAddr,
+ 6
+ ) == 0) {
+
+ //
+ // Increment count and exit
+ //
+
+ Mlid->MulticastAddresses.EnableCounts[i]--;
+
+ //
+ // If this is not the last reference we can exit now
+ //
+ if (Mlid->MulticastAddresses.EnableCounts[i] != 0) {
+
+ return(DUPLICATE_ENTRY);
+
+ }
+
+ //
+ // Now we need to adjust the address array and counts array
+ //
+
+ RtlMoveMemory(
+ Mlid->MulticastAddresses.Addresses + i * 6,
+ Mlid->MulticastAddresses.Addresses + (i + 1) * 6,
+ 6 * (Mlid->MulticastAddresses.MACount - (i + 1))
+ );
+
+ RtlMoveMemory(
+ Mlid->MulticastAddresses.EnableCounts + i,
+ Mlid->MulticastAddresses.EnableCounts + (i + 1),
+ sizeof(UINT32) * (Mlid->MulticastAddresses.MACount - (i + 1))
+ );
+
+ Mlid->MulticastAddresses.MACount--;
+
+ return(SUCCESSFUL);
+
+ }
+
+ }
+
+ return(ITEM_NOT_PRESENT);
+
+}
+
+
+UINT32
+RemoveFromFunctionalAddr(
+ PMLID_STRUCT Mlid,
+ PUINT8 DelFunctionalAddr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine takes functional address(es) for token ring and
+ removes it/them from the Mlids database if the reference count i/ares one,
+ otherwise it decrements the reference count on the address(es).
+
+Arguments:
+
+ Mlid - Pointer to the MLID.
+
+ DelFunctionalAddr - The functional address to remove.
+
+Return Value:
+
+ SUCCESSFUL - Success and address is changed.
+ ITEM_NOT_PRESENT - The address does not exist in the database.
+ DUPLICATE_ENTRY - Success and address is unchanged.
+
+--*/
+
+{
+ UINT32 i;
+ UINT32 ShortenedFunctionalAddr;
+ UNALIGNED UINT32 *PAddr;
+ UINT32 OldAddressBits;
+ UINT32 Status = DUPLICATE_ENTRY;
+
+ if (Mlid->MulticastAddresses.MAAllocated == 0) {
+
+ return(ITEM_NOT_PRESENT);
+
+ }
+
+ //
+ // Get low four bytes of address
+ //
+ PAddr = (UNALIGNED UINT32 *)(DelFunctionalAddr + 2);
+ ShortenedFunctionalAddr = *PAddr;
+
+ //
+ // Get new bits and old bits
+ //
+ OldAddressBits = Mlid->MulticastAddresses.FunctionalAddr & ShortenedFunctionalAddr;
+
+ if (OldAddressBits != ShortenedFunctionalAddr) {
+
+ return(ITEM_NOT_PRESENT);
+
+ }
+
+ //
+ // Increment count of each bit that exists in current functional address
+ //
+ i = 0;
+
+ while (OldAddressBits != 0) {
+
+ if (OldAddressBits & 1) {
+
+ Mlid->MulticastAddresses.EnableCounts[i]--;
+
+ if (Mlid->MulticastAddresses.EnableCounts[i] == 0) {
+
+ //
+ // Remove this bit
+ //
+
+ Mlid->MulticastAddresses.FunctionalAddr &= ~(1 << i);
+
+ Status = SUCCESSFUL;
+
+ }
+
+ }
+
+ OldAddressBits >>= 1;
+ i++;
+
+ }
+
+ return(Status);
+
+}
+
diff --git a/private/ntos/ndis/lsl/lslmlid.h b/private/ntos/ndis/lsl/lslmlid.h
new file mode 100644
index 000000000..7f7ad79b1
--- /dev/null
+++ b/private/ntos/ndis/lsl/lslmlid.h
@@ -0,0 +1,85 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ lslmlid.h
+
+Abstract:
+
+ This file contains all the MLID interface routine definitions to the LSL
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 3-8-93
+
+Environment:
+
+ Kernel Mode.
+
+Revision History:
+
+--*/
+
+extern MLID_Reg NdisMlidHandlerInfo;
+
+
+PMLID_ConfigTable
+GetMLIDConfiguration(
+ UINT32 BoardNumber
+ );
+
+PMLID_StatsTable
+GetMLIDStatistics(
+ UINT32 BoardNumber
+ );
+
+UINT32
+AddMulticastAddress(
+ UINT32 BoardNumber,
+ PUINT8 AddMulticastAddr
+ );
+
+UINT32
+DeleteMulticastAddress(
+ UINT32 BoardNumber,
+ PUINT8 DelMulticastAddr
+ );
+
+UINT32
+MLIDShutdown(
+ UINT32 BoardNumber,
+ UINT32 ShutDownType
+ );
+
+UINT32
+MLIDReset(
+ UINT32 BoardNumber
+ );
+
+UINT32
+SetLookAheadSize(
+ UINT32 BoardNumber,
+ UINT32 RequestSize
+ );
+
+UINT32
+PromiscuousChange(
+ UINT32 BoardNumber,
+ UINT32 PromiscuousState,
+ UINT32 PromiscuousMode
+ );
+
+UINT32
+MLIDManagement(
+ UINT32 BoardNumber,
+ PECB ManagementECB
+ );
+
+VOID
+MLIDSendHandler(
+ PECB SendECB
+ );
+
+
diff --git a/private/ntos/ndis/lsl/makefile b/private/ntos/ndis/lsl/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/lsl/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/lsl/mlid.h b/private/ntos/ndis/lsl/mlid.h
new file mode 100644
index 000000000..fe33ac327
--- /dev/null
+++ b/private/ntos/ndis/lsl/mlid.h
@@ -0,0 +1,361 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ mlid.h
+
+Abstract:
+
+ This file contains all the structures for internals of this driver.
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 3-8-93
+
+Environment:
+
+ Kernel Mode.
+
+Revision History:
+
+--*/
+
+
+//
+// NDIS handle for this "protocol"
+//
+extern NDIS_HANDLE NdisMlidProtocolHandle;
+
+//
+// Spin lock for accessing MLID list
+//
+extern NDIS_SPIN_LOCK NdisMlidSpinLock;
+
+
+
+
+typedef struct _MLID_MA_ {
+
+ //
+ // Number of allocated slots
+ //
+ UINT32 MAAllocated;
+
+ //
+ // Count of number of slots in use
+ //
+ UINT32 MACount;
+
+ //
+ // An array of counts of how many times each address has been enabled
+ //
+ PUINT32 EnableCounts;
+
+ //
+ // Array of Multicast Addresses stored as one long byte stream.
+ //
+ PUINT8 Addresses;
+
+ //
+ // Functional Address for Token rings -- Note that there is some weirdness
+ // here. ODI gives functional addresses as 6 byte strings and requires that
+ // the MLID keep track of the number of time each bit in the functional addresses
+ // has been enable. To do this, we lop off the first two bytes (there are
+ // the constant values C0-00) and then use the EnableCounts field to count
+ // the references on each bit.
+ //
+ ULONG FunctionalAddr;
+
+} MLID_MA, *PMLID_MA;
+
+
+//
+// Number of statistics kept for all MLIDS
+//
+#define NUM_GENERIC_COUNTS 15
+
+//
+// Number of statistics (max) kept by any media type
+//
+#define NUM_MEDIA_COUNTS 13
+
+//
+// Number of Token Ring statistics
+//
+#define NUM_TOKEN_RING_COUNTS 13
+
+//
+// Number of Ethernet statistics
+//
+#define NUM_ETHERNET_COUNTS 8
+
+//
+// Number of FDDI statistics
+//
+#define NUM_FDDI_COUNTS 10
+
+
+typedef struct _NDISMLID_StatsTable {
+
+ //
+ // Number of Boards using this stats table
+ //
+ UINT32 References;
+
+ //
+ // The current statistic number that we are getting from the NDIS MAC
+ //
+ UINT32 StatisticNumber;
+
+ //
+ // Timer Object for gathering statistics
+ //
+ NDIS_TIMER StatisticTimer;
+
+ //
+ // Is the timer up and running
+ //
+ BOOLEAN StatisticsOperational;
+
+ //
+ // For issuing the requests to the MAC
+ //
+ NDIS_REQUEST NdisRequest;
+
+ //
+ // A buffer for holding the response
+ //
+ UINT32 StatisticValue;
+
+ //
+ // The MLID statistic table
+ //
+ MLID_StatsTable StatsTable;
+
+ //
+ // Entries for the GenericCountsPtr
+ //
+ StatTableEntry MLID_GenericCounts[NUM_GENERIC_COUNTS];
+
+ //
+ // Entries for Medium Specific Counts
+ //
+ StatTableEntry MLID_MediaCounts[NUM_MEDIA_COUNTS];
+
+ //
+ // Finally, the actual counters
+ //
+ UINT64 GenericCounts[NUM_GENERIC_COUNTS];
+ UINT64 MediaCounts[NUM_MEDIA_COUNTS];
+
+} NDISMLID_StatsTable, *PNDISMLID_StatsTable;
+
+typedef struct _MLID_STRUCT_ {
+
+ //
+ // BoardNumber
+ //
+ UINT32 BoardNumber;
+
+ //
+ // Spin lock to guard accesses to this structure
+ //
+ NDIS_SPIN_LOCK MlidSpinLock;
+
+ //
+ // NdisBindingHandle - NDIS MAC Context.
+ //
+ NDIS_HANDLE NdisBindingHandle;
+
+ //
+ // Send packet pool for this MLID
+ //
+ NDIS_HANDLE SendPacketPool;
+
+ //
+ // Send Buffer pool for this MLID
+ //
+ NDIS_HANDLE SendBufferPool;
+
+ //
+ // Receive packet pool for this MLID
+ //
+ NDIS_HANDLE ReceivePacketPool;
+
+ //
+ // Receive Buffer pool for this MLID
+ //
+ NDIS_HANDLE ReceiveBufferPool;
+
+ //
+ // Queue of SendECBs that are waiting for resources
+ //
+ PECB FirstPendingSend;
+ PECB LastPendingSend;
+ BOOLEAN StageOpen;
+ BOOLEAN InSendPacket;
+
+ //
+ // Flag that signals that the MLID is unloading
+ //
+ BOOLEAN Unloading;
+
+ //
+ // Event for signalling the end of a request made to the MLID
+ //
+ KEVENT MlidRequestCompleteEvent;
+ BOOLEAN UsingEvent;
+
+ //
+ // Status of completed request
+ //
+ UINT32 RequestStatus;
+
+ //
+ // Count of Promiscuous mode enable calls
+ //
+ UINT32 PromiscuousModeEnables;
+
+ //
+ // Current NdisPacketFilter
+ //
+ UINT32 NdisPacketFilterValue;
+
+ //
+ // The MLID configuration table
+ //
+ MLID_ConfigTable ConfigTable;
+
+ //
+ // Pointer to the shared space
+ //
+ PNDISMLID_StatsTable StatsTable;
+
+ //
+ // Pointer to mulitcast address array
+ //
+ MLID_MA MulticastAddresses;
+
+ //
+ // LSL Control handler array
+ //
+ PINFO_BLOCK LSLFunctionList;
+
+ //
+ // Underlying Medium Type
+ //
+ NDIS_MEDIUM NdisMlidMedium;
+
+ //
+ // Adapter name, used for identifying multiple BoardNumbers on a the same
+ // physical adapter.
+ //
+ UNICODE_STRING AdapterName;
+
+} MLID_STRUCT, *PMLID_STRUCT;
+
+
+
+
+typedef struct _MLID_BOARDS_ {
+
+ //
+ // Board Number
+ //
+ UINT32 BoardNumber;
+
+ //
+ // Adapter Name
+ //
+ PUNICODE_STRING AdapterName;
+
+ //
+ // Pointer to MLID
+ //
+ PMLID_STRUCT Mlid;
+
+} MLID_BOARDS, *PMLID_BOARDS;
+
+//
+// Pointer to the array of board numbers
+//
+extern PMLID_BOARDS MlidBoards;
+
+extern UINT32 CountMlidBoards;
+
+extern UINT32 AllocatedMlidBoards;
+
+
+//
+// Defines on number of packets and buffers per MLID
+//
+
+#define NDISMLID_BUFFERS_PER_PACKET 6
+#define NDISMLID_RECEIVES_PER_MLID (*KeNumberProcessors + 1)
+#define NDISMLID_SENDS_PER_MLID 5
+
+
+//
+// Declarations for routines in mlidsend.c
+//
+
+extern
+VOID
+SendPackets(
+ PMLID_STRUCT Mlid
+ );
+
+
+extern
+VOID
+ReturnSendPacketResources(
+ PNDIS_PACKET NdisPacket
+ );
+
+
+//
+// Declarations for routines in mlidrcv.c
+//
+
+UINT32
+ReceiveGetFrameType(
+ PMLID_STRUCT Mlid,
+ PUINT8 MediaHeader,
+ PUINT8 DataBuffer
+ );
+
+
+VOID
+ReceiveGetProtocolID(
+ PMLID_STRUCT Mlid,
+ PLOOKAHEAD OdiLookAhead,
+ UINT32 FrameID
+ );
+
+VOID
+ReceiveSetDestinationType(
+ PMLID_STRUCT Mlid,
+ PLOOKAHEAD OdiLookAhead
+ );
+
+NDIS_STATUS
+BuildReceiveBufferChain(
+ PMLID_STRUCT Mlid,
+ PNDIS_PACKET NdisReceivePacket,
+ PECB ReceiveECB
+ );
+
+//
+// Functions in mlidstat.c
+//
+
+VOID
+NdisMlidStatisticTimer(
+ IN PVOID SystemSpecific1,
+ IN PVOID Context,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
diff --git a/private/ntos/ndis/lsl/mlidrcv.c b/private/ntos/ndis/lsl/mlidrcv.c
new file mode 100644
index 000000000..06fc37273
--- /dev/null
+++ b/private/ntos/ndis/lsl/mlidrcv.c
@@ -0,0 +1,589 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ mlidrcv.c
+
+Abstract:
+
+ This file contains all routines for receiving packets.
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 3-8-93
+
+Environment:
+
+ Kernel Mode.
+
+Revision History:
+
+--*/
+
+#include <ndis.h>
+#include "lsl.h"
+#include "frames.h"
+#include "mlid.h"
+#include "ndismlid.h"
+
+
+
+UINT32
+ReceiveGetFrameType(
+ PMLID_STRUCT Mlid,
+ PUINT8 MediaHeader,
+ PUINT8 DataBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the ODI FrameID of the MediaHeader and DataBuffer supplied.
+ It examines them to make a determination.
+
+ NOTE: This routine assumes that MediaHeader and DataBuffer have sufficient
+ bytes to make a determination.
+
+ NOTE: Called with Mlid->MlidSpinLock held!!
+
+Arguments:
+
+ Mlid - Pointer to MLID struct that this came in on.
+
+ MediaHeader - Pointer to the raw media header as defined by NDIS 3.0
+
+ MediaHeaderLength - Length of the media header.
+
+ DataBuffer - Pointer to the rest of the packet.
+
+ FrameLength - Length of the NDIS 3.0 data portion of the packet.
+
+Return Value:
+
+ ODI FrameID.
+
+--*/
+
+{
+ //
+ // Switch on media type
+ //
+ switch (Mlid->NdisMlidMedium) {
+
+ case NdisMedium802_5:
+
+
+ //
+ // Find frame type
+ //
+ if ((DataBuffer[0] == 0xAA) &&
+ (DataBuffer[1] == 0xAA) &&
+ (DataBuffer[2] == 0x03)) {
+
+ return(TOKEN_RING_SNAP_FRAME_ID);
+
+ }
+
+ return(TOKEN_RING_802_2_FRAME_ID);
+ break;
+
+
+ case NdisMedium802_3:
+
+ if (*((USHORT UNALIGNED *)(&(MediaHeader[13]))) > 1500) {
+
+ return(ETHERNET_II_FRAME_ID);
+
+ }
+
+ if ((DataBuffer[0] == 0xFF) && (DataBuffer[1] == 0xFF)) {
+
+ return(ETHERNET_802_3_FRAME_ID);
+ }
+
+ if ((DataBuffer[0] == 0xAA) &&
+ (DataBuffer[1] == 0xAA) &&
+ (DataBuffer[2] == 0x03)) {
+
+ return(ETHERNET_SNAP_FRAME_ID);
+
+ }
+
+ return(ETHERNET_802_2_FRAME_ID);
+ break;
+
+
+ case NdisMediumFddi:
+
+ //
+ // Check for short addresses (unsupported)
+ //
+ if ((MediaHeader[0] & 0x40) == 0) {
+
+ return((UINT32)-1);
+ }
+
+ //
+ // Find frame type
+ //
+ if ((DataBuffer[0] == 0xAA) &&
+ (DataBuffer[1] == 0xAA) &&
+ (DataBuffer[2] == 0x03)) {
+
+ return(FDDI_SNAP_FRAME_ID);
+
+ }
+
+ return(FDDI_802_2_FRAME_ID);
+ break;
+
+
+ default:
+
+ //
+ // Should never happen
+ //
+ ASSERT(0);
+ break;
+
+ }
+}
+
+
+VOID
+ReceiveGetProtocolID(
+ PMLID_STRUCT Mlid,
+ PLOOKAHEAD OdiLookAhead,
+ UINT32 FrameID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the ProtocolID field in the lookahead structure. It examines
+ the lookahead structure media header and data pointer, so these must be filled in.
+
+ NOTE: Called with Mlid->MlidSpinLock held!!
+
+Arguments:
+
+ Mlid - Pointer to the MLID which received the packet.
+
+ OdiLookAhead - Pointer to a partially filled in lookahead structure.
+
+ FrameID - Frame ID of the received frame.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PUINT8 DSAPArea;
+
+ RtlZeroMemory(OdiLookAhead->LkAhd_ProtocolID, 6);
+
+ switch (FrameID) {
+
+ case ETHERNET_II_FRAME_ID:
+
+ OdiLookAhead->LkAhd_ProtocolID[4] = OdiLookAhead->LkAhd_MediaHeaderPtr[12];
+ OdiLookAhead->LkAhd_ProtocolID[5] = OdiLookAhead->LkAhd_MediaHeaderPtr[13];
+ break;
+
+ case ETHERNET_802_3_FRAME_ID:
+
+ break;
+
+ case ETHERNET_SNAP_FRAME_ID:
+
+ RtlCopyMemory(&(OdiLookAhead->LkAhd_ProtocolID[1]),
+ &(OdiLookAhead->LkAhd_MediaHeaderPtr[17]),
+ 5
+ );
+ break;
+
+ case ETHERNET_802_2_FRAME_ID:
+
+ if (OdiLookAhead->LkAhd_MediaHeaderPtr[16] != 0x03) {
+
+ //
+ // A Type II frame
+ //
+ OdiLookAhead->LkAhd_ProtocolID[0] = 0x3;
+ OdiLookAhead->LkAhd_ProtocolID[2] = OdiLookAhead->LkAhd_MediaHeaderPtr[14];
+ OdiLookAhead->LkAhd_ProtocolID[3] = OdiLookAhead->LkAhd_MediaHeaderPtr[15];
+ OdiLookAhead->LkAhd_ProtocolID[4] = OdiLookAhead->LkAhd_MediaHeaderPtr[16];
+ OdiLookAhead->LkAhd_ProtocolID[5] = OdiLookAhead->LkAhd_MediaHeaderPtr[17];
+
+ } else {
+
+ //
+ // A Type I frame
+ //
+ if (OdiLookAhead->LkAhd_MediaHeaderPtr[14] !=
+ OdiLookAhead->LkAhd_MediaHeaderPtr[15]) {
+ OdiLookAhead->LkAhd_ProtocolID[0] = 0x2;
+ OdiLookAhead->LkAhd_ProtocolID[3] = OdiLookAhead->LkAhd_MediaHeaderPtr[14];
+ OdiLookAhead->LkAhd_ProtocolID[4] = OdiLookAhead->LkAhd_MediaHeaderPtr[15];
+ OdiLookAhead->LkAhd_ProtocolID[5] = OdiLookAhead->LkAhd_MediaHeaderPtr[16];
+
+ } else {
+ OdiLookAhead->LkAhd_ProtocolID[5] = OdiLookAhead->LkAhd_MediaHeaderPtr[14];
+ }
+
+ }
+
+ break;
+
+ case TOKEN_RING_SNAP_FRAME_ID:
+
+ if (OdiLookAhead->LkAhd_MediaHeaderPtr[8] & 0x80) {
+ //
+ // Skip Source Routining info
+ //
+
+ DSAPArea = OdiLookAhead->LkAhd_MediaHeaderPtr +
+ 14 +
+ (OdiLookAhead->LkAhd_MediaHeaderPtr[14] & 0x0F);
+ } else{
+
+ DSAPArea = OdiLookAhead->LkAhd_MediaHeaderPtr + 14;
+
+ }
+
+ RtlCopyMemory(&(OdiLookAhead->LkAhd_ProtocolID[1]),
+ DSAPArea + 3,
+ 5
+ );
+ break;
+
+ case TOKEN_RING_802_2_FRAME_ID:
+
+ if (OdiLookAhead->LkAhd_MediaHeaderPtr[8] & 0x80) {
+ //
+ // Skip Source Routining info
+ //
+
+ DSAPArea = OdiLookAhead->LkAhd_MediaHeaderPtr +
+ 14 +
+ (OdiLookAhead->LkAhd_MediaHeaderPtr[14] & 0x0F);
+
+ } else {
+
+ DSAPArea = OdiLookAhead->LkAhd_MediaHeaderPtr + 14;
+
+ }
+
+ if (DSAPArea[2] != 0x03) {
+
+ //
+ // A Type II frame
+ //
+ OdiLookAhead->LkAhd_ProtocolID[0] = 0x3;
+ OdiLookAhead->LkAhd_ProtocolID[2] = DSAPArea[0];
+ OdiLookAhead->LkAhd_ProtocolID[3] = DSAPArea[1];
+ OdiLookAhead->LkAhd_ProtocolID[4] = DSAPArea[2];
+ OdiLookAhead->LkAhd_ProtocolID[5] = DSAPArea[3];
+
+ } else {
+
+ //
+ // A Type I frame
+ //
+ if (DSAPArea[0] != DSAPArea[1]) {
+ OdiLookAhead->LkAhd_ProtocolID[0] = 0x2;
+ OdiLookAhead->LkAhd_ProtocolID[3] = DSAPArea[0];
+ OdiLookAhead->LkAhd_ProtocolID[4] = DSAPArea[1];
+ OdiLookAhead->LkAhd_ProtocolID[5] = DSAPArea[2];
+
+ } else {
+ OdiLookAhead->LkAhd_ProtocolID[5] = DSAPArea[0];
+ }
+
+ }
+
+ break;
+
+ case FDDI_SNAP_FRAME_ID:
+
+ RtlCopyMemory(&(OdiLookAhead->LkAhd_ProtocolID[1]),
+ &(OdiLookAhead->LkAhd_MediaHeaderPtr[18]),
+ 5
+ );
+ break;
+
+ case FDDI_802_2_FRAME_ID:
+
+ if (OdiLookAhead->LkAhd_MediaHeaderPtr[17] != 0x03) {
+
+ //
+ // A Type II frame
+ //
+ OdiLookAhead->LkAhd_ProtocolID[0] = 0x3;
+ OdiLookAhead->LkAhd_ProtocolID[2] = OdiLookAhead->LkAhd_MediaHeaderPtr[15];
+ OdiLookAhead->LkAhd_ProtocolID[3] = OdiLookAhead->LkAhd_MediaHeaderPtr[16];
+ OdiLookAhead->LkAhd_ProtocolID[4] = OdiLookAhead->LkAhd_MediaHeaderPtr[17];
+ OdiLookAhead->LkAhd_ProtocolID[5] = OdiLookAhead->LkAhd_MediaHeaderPtr[18];
+
+ } else {
+
+ //
+ // A Type I frame
+ //
+ if (OdiLookAhead->LkAhd_MediaHeaderPtr[15] !=
+ OdiLookAhead->LkAhd_MediaHeaderPtr[16]) {
+ OdiLookAhead->LkAhd_ProtocolID[0] = 0x2;
+ OdiLookAhead->LkAhd_ProtocolID[3] = OdiLookAhead->LkAhd_MediaHeaderPtr[15];
+ OdiLookAhead->LkAhd_ProtocolID[4] = OdiLookAhead->LkAhd_MediaHeaderPtr[16];
+ OdiLookAhead->LkAhd_ProtocolID[5] = OdiLookAhead->LkAhd_MediaHeaderPtr[17];
+
+ } else {
+ OdiLookAhead->LkAhd_ProtocolID[5] = OdiLookAhead->LkAhd_MediaHeaderPtr[15];
+ }
+
+ }
+
+ break;
+
+ }
+}
+
+
+VOID
+ReceiveSetDestinationType(
+ PMLID_STRUCT Mlid,
+ PLOOKAHEAD OdiLookAhead
+ )
+
+
+/*++
+
+Routine Description:
+
+ This routine sets the DestType field in the lookahead structure. It examines
+ the lookahead structure media header and data pointer, so these must be filled in.
+
+ NOTE: Require the ImmediateAddress field to be filled with the source address.
+ NOTE: Called with Mlid->MlidSpinLock held!!
+
+Arguments:
+
+ Mlid - Pointer to MLID receiving the packet.
+
+ OdiLookAhead - Pointer to a partially filled in lookahead structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ BOOLEAN Result;
+
+ if (OdiLookAhead->LkAhd_PktAttr != 0) {
+
+ OdiLookAhead->LkAhd_DestType = 0x20; // Global Error
+ return;
+
+ }
+
+ OdiLookAhead->LkAhd_DestType = 0x0;
+
+ switch (Mlid->NdisMlidMedium) {
+
+ case NdisMedium802_3:
+
+ //*\\ Does not support setting MulticastRemote bit in DestType. Is this OK?
+
+ if (ETH_IS_BROADCAST(OdiLookAhead->LkAhd_ImmediateAddress)) {
+ OdiLookAhead->LkAhd_DestType = 0x3; // Broadcast
+ return;
+ }
+
+ if (ETH_IS_MULTICAST(OdiLookAhead->LkAhd_ImmediateAddress)) {
+ OdiLookAhead->LkAhd_DestType = 0x1; // Multicast
+ return;
+ }
+
+ COMPARE_NETWORK_ADDRESSES(OdiLookAhead->LkAhd_ImmediateAddress,
+ Mlid->ConfigTable.MLIDCFG_NodeAddress,
+ &Result);
+ if (Result) {
+ OdiLookAhead->LkAhd_DestType = 0x80; // Direct
+ return;
+ }
+
+ OdiLookAhead->LkAhd_DestType = 0x4; // Directed to another station
+
+ break;
+
+ case NdisMedium802_5:
+
+ //
+ // First check for SR Info
+ //
+ if (OdiLookAhead->LkAhd_ImmediateAddress[0] & 0x80) {
+
+ //
+ // Yes
+ //
+ if (Mlid->ConfigTable.MLIDCFG_SourceRouting == NULL) {
+
+ //
+ // Set bit and exit
+ //
+ OdiLookAhead->LkAhd_DestType = 0x10; // No Source Routing
+ return;
+ }
+
+ }
+
+ TR_IS_BROADCAST(OdiLookAhead->LkAhd_ImmediateAddress, &Result);
+ if (Result == TRUE) {
+ OdiLookAhead->LkAhd_DestType = 0x3; // Broadcast
+ return;
+ }
+
+ TR_IS_GROUP(OdiLookAhead->LkAhd_ImmediateAddress, &Result);
+ if (Result == TRUE) {
+ OdiLookAhead->LkAhd_DestType = 0x1; // Multicast
+ return;
+ }
+
+ TR_IS_FUNCTIONAL(OdiLookAhead->LkAhd_ImmediateAddress, &Result);
+ if (Result == TRUE) {
+ OdiLookAhead->LkAhd_DestType = 0x1; // Multicast
+ return;
+ }
+
+ COMPARE_NETWORK_ADDRESSES(OdiLookAhead->LkAhd_ImmediateAddress,
+ Mlid->ConfigTable.MLIDCFG_NodeAddress,
+ &Result);
+ if (Result) {
+ OdiLookAhead->LkAhd_DestType = 0x80; // Direct
+ return;
+ }
+
+ OdiLookAhead->LkAhd_DestType = 0x4; // Directed to another station
+
+ break;
+
+ case NdisMediumFddi:
+
+ if (ETH_IS_BROADCAST(OdiLookAhead->LkAhd_ImmediateAddress)) {
+ OdiLookAhead->LkAhd_DestType = 0x3; // Broadcast
+ return;
+ }
+
+ if (ETH_IS_MULTICAST(OdiLookAhead->LkAhd_ImmediateAddress)) {
+ OdiLookAhead->LkAhd_DestType = 0x1; // Multicast
+ return;
+ }
+
+ COMPARE_NETWORK_ADDRESSES(OdiLookAhead->LkAhd_ImmediateAddress,
+ Mlid->ConfigTable.MLIDCFG_NodeAddress,
+ &Result);
+ if (Result) {
+ OdiLookAhead->LkAhd_DestType = 0x80; // Direct
+ return;
+ }
+
+ OdiLookAhead->LkAhd_DestType = 0x4; // Directed to another station
+
+ break;
+
+ }
+
+}
+
+
+NDIS_STATUS
+BuildReceiveBufferChain(
+ PMLID_STRUCT Mlid,
+ PNDIS_PACKET NdisReceivePacket,
+ PECB ReceiveECB
+ )
+
+/*++
+
+Routine Description:
+
+ This routine builds an MDL chain describing the ECB fragment list
+ and attaches it to the NDIS_PACKET.
+
+ NOTE: Called with Mlid->MlidSpinLock held!!
+
+Arguments:
+
+ Mlid - Owning Mlid.
+
+ Packet - Pointer to the NDIS_PACKET to free.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UINT32 i;
+ PNDIS_BUFFER NdisBuffer;
+ NDIS_STATUS NdisStatus;
+
+ //
+ // Convert ECB fragment list into an MDL chain
+ //
+ for (i = 0; i < ReceiveECB->ECB_FragmentCount; i++) {
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ Mlid->ReceiveBufferPool,
+ ReceiveECB->ECB_Fragment[i].FragmentAddress,
+ ReceiveECB->ECB_Fragment[i].FragmentLength
+ );
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Unchain all NDIS_BUFFERs from packet
+ //
+
+ NdisUnchainBufferAtFront(
+ NdisReceivePacket,
+ &NdisBuffer
+ );
+
+ while (NdisBuffer != NULL) {
+
+ NdisFreeBuffer(NdisBuffer);
+
+ NdisUnchainBufferAtFront(
+ NdisReceivePacket,
+ &NdisBuffer
+ );
+
+ }
+
+ return(NDIS_STATUS_RESOURCES);
+
+ }
+
+ NdisChainBufferAtBack(
+ NdisReceivePacket,
+ NdisBuffer
+ );
+
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+
+}
+
diff --git a/private/ntos/ndis/lsl/mlidsend.c b/private/ntos/ndis/lsl/mlidsend.c
new file mode 100644
index 000000000..611707835
--- /dev/null
+++ b/private/ntos/ndis/lsl/mlidsend.c
@@ -0,0 +1,875 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ mlidsend.c
+
+Abstract:
+
+ This file contains all routines for sending packets.
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 3-8-93
+
+Environment:
+
+ Kernel Mode.
+
+Revision History:
+
+--*/
+
+#include <ndis.h>
+#include "lsl.h"
+#include "frames.h"
+#include "mlid.h"
+#include "ndismlid.h"
+
+VOID
+NdisMlidBuildMediaHeader(
+ PMLID_STRUCT Mlid,
+ PMLID_RESERVED Reserved,
+ UINT32 FrameLength,
+ PUINT8 DestinationAddress,
+ PUINT8 ProtocolID
+ );
+
+
+VOID
+SendPackets(
+ PMLID_STRUCT Mlid
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called whenever there is a need to send a packet. It will
+ take as many Send ECBs from the Mlid as possible and convert them into NDIS_PACKETS
+ and submit them to the NDIS_MAC.
+
+ NOTE: This must be called with Mlid->StageOpen = TRUE;
+ NOTE: This must be called with Mlid->InSendPacket = FALSE;
+ NOTE: Called with Mlid->MlidSpinLock held!!
+
+Arguments:
+
+ Mlid - Pointer to the MLID_STRUCT to service.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_PACKET NdisSendPacket;
+ PNDIS_BUFFER NdisBuffer;
+ PMLID_RESERVED Reserved;
+ UINT32 i;
+ BOOLEAN HeldEvents = FALSE;
+ NDIS_STATUS NdisStatus;
+
+ PECB SendECB;
+
+ ASSERT(Mlid->StageOpen == TRUE);
+ ASSERT(Mlid->InSendPacket == FALSE);
+
+ //
+ // While there any sends queued
+ //
+ while (Mlid->FirstPendingSend) {
+
+ //
+ // If there are no NDIS_PACKETs avaiable, then close stage and exit.
+ //
+ NdisAllocatePacket(
+ &NdisStatus,
+ &NdisSendPacket,
+ Mlid->SendPacketPool
+ );
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ Mlid->StageOpen = FALSE;
+ break;
+
+ }
+
+ Reserved = PMLID_RESERVED_FROM_PNDIS_PACKET(NdisSendPacket);
+
+ //
+ // Initialize NDIS_PACKET
+ //
+ NdisReinitializePacket(NdisSendPacket);
+
+ SendECB = Mlid->FirstPendingSend;
+
+ //
+ // Convert ECB fragment list into an MDL chain
+ //
+ for (i = 0; i < SendECB->ECB_FragmentCount; i++) {
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ Mlid->SendBufferPool,
+ SendECB->ECB_Fragment[i].FragmentAddress,
+ SendECB->ECB_Fragment[i].FragmentLength
+ );
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ goto Fail1;
+
+ }
+
+ NdisChainBufferAtBack(
+ NdisSendPacket,
+ NdisBuffer
+ );
+
+ }
+
+ //
+ // Build the media header
+ //
+ NdisMlidBuildMediaHeader(Mlid,
+ Reserved,
+ SendECB->ECB_DataLength,
+ SendECB->ECB_ImmediateAddress,
+ SendECB->ECB_ProtocolID
+ );
+
+ //
+ // Link media header into front of MDL chain
+ //
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ Mlid->SendBufferPool,
+ Reserved->MediaHeader,
+ Reserved->MediaHeaderLength
+ );
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ goto Fail1;
+
+ }
+
+ NdisChainBufferAtFront(
+ NdisSendPacket,
+ NdisBuffer
+ );
+
+ //
+ // Remove Send ECB from Send Queue
+ //
+ Mlid->FirstPendingSend = SendECB->ECB_NextLink;
+
+ if (Mlid->LastPendingSend == SendECB) {
+
+ Mlid->LastPendingSend = NULL;
+
+ } else {
+
+ SendECB->ECB_NextLink->ECB_PreviousLink = NULL;
+
+ }
+
+ //
+ // Store ECB in reserved section
+ //
+ Reserved->SendECB = SendECB;
+
+ //
+ // Release MlidSpinLock
+ //
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ //
+ // Submit to NDIS_MAC
+ //
+ NdisSend(
+ &NdisStatus,
+ Mlid->NdisBindingHandle,
+ NdisSendPacket
+ );
+
+ //
+ // Acquire MlidSpinLock
+ //
+ NdisAcquireSpinLock(&(Mlid->MlidSpinLock));
+
+ //
+ // If not pending, then
+ //
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+
+ //
+ // Return resources to Mlid
+ //
+ NdisUnchainBufferAtFront(
+ NdisSendPacket,
+ &NdisBuffer
+ );
+
+ while (NdisBuffer != NULL) {
+
+ NdisFreeBuffer(NdisBuffer);
+
+ NdisUnchainBufferAtFront(
+ NdisSendPacket,
+ &NdisBuffer
+ );
+
+ }
+
+ NdisFreePacket(NdisSendPacket);
+
+ //
+ // Store completion status in ECB
+ //
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ SendECB->ECB_Status = (UINT16)SUCCESSFUL;
+
+ } else {
+
+ SendECB->ECB_Status = (UINT16)FAIL;
+
+ }
+
+ //
+ // Release MlidSpinLock
+ //
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ //
+ // put ECB on LSLEventQueue
+ //
+ (*(Mlid->LSLFunctionList->SupportAPIArray[HoldEvent_INDEX]))(
+ SendECB
+ );
+
+ //
+ // Acquire MlidSpinLock
+ //
+ NdisAcquireSpinLock(&(Mlid->MlidSpinLock));
+
+ //
+ // Set flag to service events
+ //
+ HeldEvents = TRUE;
+
+ }
+
+ }
+
+ //
+ // Call LSL_ServiceEvents if necessary
+ //
+ if (HeldEvents) {
+ (*(Mlid->LSLFunctionList->SupportAPIArray[ServiceEvents_INDEX]))(
+ );
+
+ }
+
+ return;
+
+Fail1:
+
+ //
+ // Unchain all NDIS_BUFFERs from packet
+ //
+
+ NdisUnchainBufferAtFront(
+ NdisSendPacket,
+ &NdisBuffer
+ );
+
+ while (NdisBuffer != NULL) {
+
+ NdisFreeBuffer(NdisBuffer);
+
+ NdisUnchainBufferAtFront(
+ NdisSendPacket,
+ &NdisBuffer
+ );
+
+ }
+
+ //
+ // Return NDIS_PACKET
+ //
+ NdisFreePacket(NdisSendPacket);
+
+ //
+ // Close stage
+ //
+ Mlid->StageOpen = FALSE;
+
+ return;
+}
+
+
+VOID
+ReturnSendPacketResources(
+ PNDIS_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to return the MLID resources allocated for a sent NDIS_PACKET.
+ This includes the entire MDL chain itself and the NDIS_PACKET.
+
+ NOTE: Called with Mlid->MlidSpinLock held!!
+
+Arguments:
+
+ Packet - Pointer to the NDIS_PACKET to free.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_BUFFER NdisBuffer;
+
+ //
+ // Unchain all NDIS_BUFFERs from packet
+ //
+
+ NdisUnchainBufferAtFront(
+ Packet,
+ &NdisBuffer
+ );
+
+ while (NdisBuffer != NULL) {
+
+ NdisFreeBuffer(NdisBuffer);
+
+ NdisUnchainBufferAtFront(
+ Packet,
+ &NdisBuffer
+ );
+
+ }
+
+ //
+ // Return NDIS_PACKET
+ //
+ NdisFreePacket(Packet);
+
+}
+
+
+VOID
+NdisMlidBuildMediaHeader(
+ PMLID_STRUCT Mlid,
+ PMLID_RESERVED Reserved,
+ UINT32 FrameLength,
+ PUINT8 DestinationAddress,
+ PUINT8 ProtocolID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine assembles a packet header for the MLID and ProtocolID given into
+ the given reserved section.
+
+ NOTE: Called with Mlid->MlidSpinLock held!!
+
+Arguments:
+
+ Mlid - Pointer to MLID
+
+ Reserved - Pointer to a reserved section with memory to hold the header.
+
+ FrameLength - Length of the Data portion of the frame.
+
+ DestinationAddress - The address that the packet will be addresses to.
+
+ ProtocolID - The ID that has DSAP and other information in it.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PUINT8 SourceRoutingInfo;
+ UINT32 SourceRoutingLength;
+ UINT32 DataLength = FrameLength;
+ PUINT8 CurrentPlace = Reserved->MediaHeader;
+
+ //
+ // Switch on media type
+ //
+ switch (Mlid->NdisMlidMedium) {
+
+ case NdisMedium802_5:
+
+ if (Mlid->ConfigTable.MLIDCFG_SourceRouting != NULL) {
+
+ //
+ // Get any source routing information
+ //*\\ Get SR Info. Are parameters correct?
+ SourceRoutingInfo = (*((PLSL_SR_FUNCTION)(Mlid->ConfigTable.MLIDCFG_SourceRouting)))
+ ( Mlid->BoardNumber,
+ &SourceRoutingLength,
+ DestinationAddress
+ );
+
+ }
+
+ //
+ // Set AC field
+ //
+ *CurrentPlace = 0x10;
+ CurrentPlace++;
+
+ //
+ // Set FC field
+ //
+ *CurrentPlace = 0x40;
+ CurrentPlace++;
+
+ //
+ // Set DestinationAddress
+ //
+ RtlCopyMemory(CurrentPlace, DestinationAddress, 6);
+ CurrentPlace += 6;
+
+ //
+ // Set SourceAddress
+ //
+ RtlCopyMemory(CurrentPlace, Mlid->ConfigTable.MLIDCFG_NodeAddress, 6);
+ CurrentPlace += 6;
+
+ //
+ // Copy SourceRoutingInfo
+ //
+ RtlCopyMemory(CurrentPlace, SourceRoutingInfo, SourceRoutingLength);
+ CurrentPlace += SourceRoutingLength;
+
+ //
+ // Switch on frame type
+ //
+ switch (Mlid->ConfigTable.MLIDCFG_FrameID) {
+
+ //
+ // TR - 802.2
+ //
+ case TOKEN_RING_802_2_FRAME_ID:
+
+ //
+ // Set DSAP, SSAP and Control
+ //
+ if (ProtocolID[0] < 2) {
+
+ *CurrentPlace = ProtocolID[5];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[5];
+ CurrentPlace++;
+ *CurrentPlace = 0x03;
+ CurrentPlace++;
+
+ } else if (ProtocolID[0] == 2) {
+
+ //
+ // Type I header
+ //
+
+ *CurrentPlace = ProtocolID[3];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[4];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[5];
+ CurrentPlace++;
+
+ } else {
+
+ //
+ // Type II header
+ //
+
+ *CurrentPlace = ProtocolID[2];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[3];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[4];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[5];
+ CurrentPlace++;
+
+ }
+
+ break;
+
+ //
+ // TR - SNAP
+ //
+ case TOKEN_RING_SNAP_FRAME_ID:
+
+ //
+ // Set DSAP, SSAP and Control
+ //
+ *CurrentPlace = 0xAA;
+ CurrentPlace++;
+ *CurrentPlace = 0xAA;
+ CurrentPlace++;
+ *CurrentPlace = 0x03;
+ CurrentPlace++;
+
+ //
+ // Copy in ProtocolID
+ //
+ RtlCopyMemory(CurrentPlace, &(ProtocolID[1]), 5);
+ CurrentPlace += 5;
+
+ break;
+
+ default:
+
+ //
+ // Should never happen
+ //
+ ASSERT(0);
+ break;
+ }
+ break;
+
+
+ case NdisMedium802_3:
+
+ //
+ // Set DestinationAddress
+ //
+ RtlCopyMemory(CurrentPlace, DestinationAddress, 6);
+ CurrentPlace += 6;
+
+ //
+ // Set SourceAddress
+ //
+ RtlCopyMemory(CurrentPlace, Mlid->ConfigTable.MLIDCFG_NodeAddress, 6);
+ CurrentPlace += 6;
+
+ FrameLength += 12;
+
+ //
+ // Switch on frame type
+ //
+ switch (Mlid->ConfigTable.MLIDCFG_FrameID) {
+
+ //
+ // Ethernet 802.2
+ //
+ case ETHERNET_802_2_FRAME_ID:
+
+ FrameLength += 5;
+
+ //
+ // Set FrameLength
+ //
+ *CurrentPlace = (UINT8)((FrameLength >> 8) & 0xFF);
+ CurrentPlace++;
+ *CurrentPlace = (UINT8)(FrameLength & 0xFF);
+ CurrentPlace++;
+
+ //
+ // Set DSAP, SSAP and Control
+ //
+ if (ProtocolID[0] < 2) {
+
+ *CurrentPlace = ProtocolID[5];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[5];
+ CurrentPlace++;
+ *CurrentPlace = 0x03;
+ CurrentPlace++;
+
+ } else if (ProtocolID[0] == 2) {
+
+ //
+ // Type I header
+ //
+
+ *CurrentPlace = ProtocolID[3];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[4];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[5];
+ CurrentPlace++;
+
+ } else {
+
+ //
+ // Type II header
+ //
+
+ *CurrentPlace = ProtocolID[2];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[3];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[4];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[5];
+ CurrentPlace++;
+
+ }
+
+ break;
+
+ //
+ // Ethernet SNAP
+ //
+ case ETHERNET_SNAP_FRAME_ID:
+
+ FrameLength += 10;
+
+ //
+ // Set FrameLength
+ //
+ *CurrentPlace = (UINT8)((FrameLength >> 8) & 0xFF);
+ CurrentPlace++;
+ *CurrentPlace = (UINT8)(FrameLength & 0xFF);
+ CurrentPlace++;
+
+ //
+ // Set DSAP, SSAP and Control
+ //
+ *CurrentPlace = 0xAA;
+ CurrentPlace++;
+ *CurrentPlace = 0xAA;
+ CurrentPlace++;
+ *CurrentPlace = 0x03;
+ CurrentPlace++;
+
+ //
+ // Copy in ProtocolID
+ //
+ RtlCopyMemory(CurrentPlace, &(ProtocolID[1]), 5);
+ CurrentPlace += 5;
+
+ break;
+
+ //
+ // Ethernet Raw 802.3
+ //
+ case ETHERNET_802_3_FRAME_ID:
+
+ FrameLength += 2;
+
+ //
+ // Set FrameLength
+ //
+ *CurrentPlace = (UINT8)((FrameLength >> 8) & 0xFF);
+ CurrentPlace++;
+ *CurrentPlace = (UINT8)(FrameLength & 0xFF);
+ CurrentPlace++;
+
+ break;
+
+
+ //
+ // Ethernet II
+ //
+ case ETHERNET_II_FRAME_ID:
+
+ FrameLength += 2;
+
+ //
+ // Set FrameType
+ //*\\ Is this right? - Ethernet II, where is FrameType stored in ProtocolID?
+ *CurrentPlace = (UINT8)ProtocolID[4];
+ CurrentPlace++;
+ *CurrentPlace = (UINT8)ProtocolID[5];
+ CurrentPlace++;
+
+ break;
+
+
+ default:
+
+ //
+ // Should never happen
+ //
+ ASSERT(0);
+ break;
+
+ }
+
+ break;
+
+
+ case NdisMediumFddi:
+
+ //
+ // Set FCByte
+ //
+ *CurrentPlace = 0x57;
+ CurrentPlace ++;
+
+ //
+ // Set DestinationAddress
+ //
+ RtlCopyMemory(CurrentPlace, DestinationAddress, 6);
+ CurrentPlace += 6;
+
+ //
+ // Set SourceAddress
+ //
+ RtlCopyMemory(CurrentPlace, Mlid->ConfigTable.MLIDCFG_NodeAddress, 6);
+ CurrentPlace += 6;
+
+ FrameLength += 13;
+
+ //
+ // Switch on frame type
+ //
+ switch (Mlid->ConfigTable.MLIDCFG_FrameID) {
+
+ //
+ // FDDI 802.2
+ //
+ case FDDI_802_2_FRAME_ID:
+
+ if (ProtocolID[0] > 2) {
+
+ //
+ // Type II header
+ //
+ FrameLength += 6;
+
+ } else {
+
+ //
+ // Type I header
+ //
+ FrameLength += 5;
+ }
+
+ //
+ // Set FrameLength
+ //
+ *CurrentPlace = (UINT8)((FrameLength >> 8) & 0xFF);
+ CurrentPlace++;
+ *CurrentPlace = (UINT8)(FrameLength & 0xFF);
+ CurrentPlace++;
+
+ //
+ // Set DSAP, SSAP and Control
+ //
+ if (ProtocolID[0] < 2) {
+
+ *CurrentPlace = ProtocolID[5];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[5];
+ CurrentPlace++;
+ *CurrentPlace = 0x03;
+ CurrentPlace++;
+
+ } else if (ProtocolID[0] == 2) {
+
+ //
+ // Type I header
+ //
+
+ *CurrentPlace = ProtocolID[3];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[4];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[5];
+ CurrentPlace++;
+
+ } else {
+
+ //
+ // Type II header
+ //
+
+ *CurrentPlace = ProtocolID[2];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[3];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[4];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[5];
+ CurrentPlace++;
+
+ }
+
+ break;
+
+ //
+ // Fddi SNAP
+ //
+ case FDDI_SNAP_FRAME_ID:
+
+ FrameLength += 10;
+
+ //
+ // Set FrameLength
+ //
+ *CurrentPlace = (UINT8)((FrameLength >> 8) & 0xFF);
+ CurrentPlace++;
+ *CurrentPlace = (UINT8)(FrameLength & 0xFF);
+ CurrentPlace++;
+
+ //
+ // Set DSAP, SSAP and Control
+ //
+ *CurrentPlace = 0xAA;
+ CurrentPlace++;
+ *CurrentPlace = 0xAA;
+ CurrentPlace++;
+ *CurrentPlace = 0x03;
+ CurrentPlace++;
+
+ //
+ // Copy in ProtocolID
+ //
+ RtlCopyMemory(CurrentPlace, &(ProtocolID[1]), 5);
+ CurrentPlace += 5;
+
+ break;
+
+ default:
+
+ //
+ // Should never happen
+ //
+ ASSERT(0);
+ break;
+
+ }
+
+ break;
+
+
+ default:
+
+ //
+ // Should never happen
+ //
+ ASSERT(0);
+ break;
+
+ }
+
+ Reserved->MediaHeaderLength = FrameLength - DataLength;
+
+}
diff --git a/private/ntos/ndis/lsl/mlidstat.c b/private/ntos/ndis/lsl/mlidstat.c
new file mode 100644
index 000000000..63399e09d
--- /dev/null
+++ b/private/ntos/ndis/lsl/mlidstat.c
@@ -0,0 +1,363 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ mlidstat.c
+
+Abstract:
+
+ This file contains the code for asynchronous statistic gathering from the
+ NDIS MAC.
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 3-8-93
+
+Environment:
+
+ Kernel Mode.
+
+Revision History:
+
+--*/
+
+#include <ndis.h>
+#include "lsl.h"
+#include "frames.h"
+#include "mlid.h"
+#include "ndismlid.h"
+
+VOID
+NdisMlidStatisticTimer(
+ IN PVOID SystemSpecific1,
+ IN PVOID Context,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+
+/*++
+
+Routine Description:
+
+ This DPC routine is queued to gather statistics from then
+ NDIS MAC.
+
+Arguments:
+
+ Context - Really a pointer to the MLID.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PMLID_STRUCT Mlid = (PMLID_STRUCT)Context;
+ PNDIS_REQUEST NdisMlidRequest = &(Mlid->StatsTable->NdisRequest);
+ NDIS_STATUS NdisStatus;
+
+ NdisAcquireSpinLock(&(Mlid->MlidSpinLock));
+
+ //
+ // Loop
+ //
+ while (TRUE) {
+
+ //
+ // Set up NdisRequest
+ //
+ NdisMlidRequest->RequestType = NdisRequestQueryInformation;
+
+ switch (Mlid->NdisMlidMedium) {
+
+ case NdisMedium802_3:
+
+ switch (Mlid->StatsTable->StatisticNumber) {
+
+ case 0:
+
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid =
+ OID_802_3_XMIT_ONE_COLLISION;
+ break;
+
+ case 1:
+
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid =
+ OID_802_3_XMIT_MORE_COLLISIONS;
+ break;
+
+ case 2:
+
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid =
+ OID_802_3_XMIT_DEFERRED;
+ break;
+
+ case 3:
+
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid =
+ OID_802_3_XMIT_LATE_COLLISIONS;
+ break;
+
+ case 4:
+
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid =
+ OID_802_3_XMIT_MAX_COLLISIONS;
+ break;
+
+ case 5:
+
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid =
+ OID_802_3_XMIT_TIMES_CRS_LOST;
+ break;
+
+ case 6:
+ goto DoNextStatistic;
+
+ case 7:
+
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid =
+ OID_802_3_RCV_ERROR_ALIGNMENT;
+ break;
+
+ }
+
+ break;
+
+ case NdisMedium802_5:
+ switch (Mlid->StatsTable->StatisticNumber) {
+
+ case 0:
+
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid =
+ OID_802_5_AC_ERRORS;
+ break;
+
+ case 1:
+
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid =
+ OID_802_5_ABORT_DELIMETERS;
+ break;
+
+ case 2:
+
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid =
+ OID_802_5_BURST_ERRORS;
+ break;
+
+ case 3:
+
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid =
+ OID_802_5_FRAME_COPIED_ERRORS;
+ break;
+
+ case 4:
+
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid =
+ OID_802_5_FREQUENCY_ERRORS;
+ break;
+
+ case 5:
+
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid =
+ OID_802_5_INTERNAL_ERRORS;
+ break;
+
+ case 6:
+
+ goto DoNextStatistic;
+
+ case 7:
+
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid =
+ OID_802_5_LINE_ERRORS;
+ break;
+
+ case 8:
+
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid =
+ OID_802_5_LOST_FRAMES;
+ break;
+
+ case 9:
+
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid =
+ OID_802_5_TOKEN_ERRORS;
+ break;
+
+ case 10:
+ case 11:
+ case 12:
+
+ goto DoNextStatistic;
+
+ }
+
+ break;
+
+ case NdisMediumFddi:
+
+ switch (Mlid->StatsTable->StatisticNumber) {
+
+ case 0:
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid =
+ OID_FDDI_ATTACHMENT_TYPE;
+
+ break;
+
+ case 1:
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid =
+ OID_FDDI_UPSTREAM_NODE_LONG;
+
+ break;
+
+ case 2:
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid =
+ OID_FDDI_DOWNSTREAM_NODE_LONG;
+
+ break;
+
+ case 3:
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid =
+ OID_FDDI_FRAME_ERRORS;
+
+ break;
+
+ case 4:
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid =
+ OID_FDDI_FRAMES_LOST;
+
+ break;
+
+ case 5:
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid =
+ OID_FDDI_RING_MGT_STATE;
+
+ break;
+
+ case 6:
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid =
+ OID_FDDI_LCT_FAILURES;
+
+ break;
+
+ case 7:
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid =
+ OID_FDDI_LEM_REJECTS;
+
+ break;
+
+ case 8: // LemCount
+
+ goto DoNextStatistic;
+
+ case 9:
+
+ NdisMlidRequest->DATA.QUERY_INFORMATION.Oid =
+ OID_FDDI_LCONNECTION_STATE;
+
+ break;
+
+ default:
+
+ goto DoNextStatistic;
+ }
+
+ break;
+
+ }
+
+ NdisMlidRequest->DATA.QUERY_INFORMATION.InformationBuffer =
+ (PVOID)&(Mlid->StatsTable->StatisticValue);
+ NdisMlidRequest->DATA.QUERY_INFORMATION.InformationBufferLength =
+ sizeof(Mlid->StatsTable->StatisticValue);
+ NdisMlidRequest->DATA.QUERY_INFORMATION.BytesWritten = 0;
+ NdisMlidRequest->DATA.QUERY_INFORMATION.BytesNeeded = 0;
+
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ NdisRequest(
+ &NdisStatus,
+ Mlid->NdisBindingHandle,
+ NdisMlidRequest
+ );
+
+ //
+ // if (pending), exit.
+ //
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ return;
+
+ }
+
+ NdisAcquireSpinLock(&(Mlid->MlidSpinLock));
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ //
+ // Store Statistic
+ //
+ (*((PUINT32)((*(Mlid->StatsTable->StatsTable.MMediaCountsPtr))
+ [
+ Mlid->StatsTable->StatisticNumber
+ ].StatCounter))) =
+ Mlid->StatsTable->StatisticValue;
+
+ }
+
+DoNextStatistic:
+
+ Mlid->StatsTable->StatisticNumber++;
+
+
+ switch (Mlid->NdisMlidMedium) {
+
+ case NdisMedium802_3:
+
+ if (Mlid->StatsTable->StatisticNumber >= NUM_ETHERNET_COUNTS) {
+ Mlid->StatsTable->StatisticNumber = 0;
+ }
+
+ break;
+
+ case NdisMedium802_5:
+
+ if (Mlid->StatsTable->StatisticNumber >= NUM_TOKEN_RING_COUNTS) {
+ Mlid->StatsTable->StatisticNumber = 0;
+ }
+
+ break;
+
+ case NdisMediumFddi:
+
+ if (Mlid->StatsTable->StatisticNumber >= NUM_FDDI_COUNTS) {
+ Mlid->StatsTable->StatisticNumber = 0;
+ }
+
+ break;
+
+ }
+
+ if (Mlid->StatsTable->StatisticNumber == 0) {
+
+ //
+ // Set timer for 30 seconds from now.
+ //
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ NdisSetTimer(&(Mlid->StatsTable->StatisticTimer), 30000);
+
+ return;
+
+ }
+
+ }
+
+}
+
+
+
+
diff --git a/private/ntos/ndis/lsl/ndismlid.c b/private/ntos/ndis/lsl/ndismlid.c
new file mode 100644
index 000000000..47d779485
--- /dev/null
+++ b/private/ntos/ndis/lsl/ndismlid.c
@@ -0,0 +1,1183 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ndismlid.c
+
+Abstract:
+
+ This file contains all the NDIS inteface routines between NDIS mac and this MLID.
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 3-8-93
+
+Environment:
+
+ Kernel Mode.
+
+Revision History:
+
+--*/
+
+#include <ndis.h>
+#include "lsl.h"
+#include "frames.h"
+#include "mlid.h"
+#include "ndismlid.h"
+
+
+
+VOID
+NdisMlidOpenAdapterComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status,
+ IN NDIS_STATUS OpenErrorStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that an open adapter
+ is complete. Since we only ever have one outstanding, and then only
+ during initialization, all we do is record the status and set
+ the event to signalled to unblock the initialization thread.
+
+Arguments:
+
+ BindingContext - Pointer to the device object for this driver.
+
+ NdisStatus - The request completion code.
+
+ OpenErrorStatus - More status information.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PMLID_STRUCT Mlid = (PMLID_STRUCT)ProtocolBindingContext;
+
+ //
+ // Store completion status
+ //
+ Mlid->RequestStatus = Status;
+
+ //
+ // Set event to indicate the completion of the open
+ //
+
+ KeSetEvent(&Mlid->MlidRequestCompleteEvent, 0L, FALSE);
+
+}
+
+VOID
+NdisMlidCloseAdapterComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that a close adapter
+ is complete.
+
+ NOTE: This processing assumes that CloseAdapter is only called during
+ initialization time.
+
+Arguments:
+
+ BindingContext - Pointer to the device object for this driver.
+
+ NdisStatus - The request completion code.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PMLID_STRUCT Mlid = (PMLID_STRUCT)ProtocolBindingContext;
+
+ //
+ // Store completion status
+ //
+ Mlid->RequestStatus = Status;
+
+ //
+ // Set event to indicate the completion of the open
+ //
+
+ KeSetEvent(&Mlid->MlidRequestCompleteEvent, 0L, FALSE);
+
+}
+
+VOID
+NdisMlidSendComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a send has been completed.
+
+Arguments:
+
+ ProtocolBindingContext - A pointer to the MLID_STRUCT that the send was sent across.
+
+ NdisPacket - A pointer to the NDIS_PACKET that we sent.
+
+ Status - the completion status of the send.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PMLID_STRUCT Mlid = (PMLID_STRUCT)ProtocolBindingContext;
+ PECB SendECB;
+ ULONG PacketSize;
+ PUINT64 Statistic;
+ PMLID_RESERVED Reserved = PMLID_RESERVED_FROM_PNDIS_PACKET(Packet);
+
+ //
+ // Get corresponding ECB
+ //
+ SendECB = Reserved->SendECB;
+
+ NdisAcquireSpinLock(&(Mlid->MlidSpinLock));
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ NULL,
+ NULL,
+ &PacketSize
+ );
+
+ //
+ // Return resources to Mlid
+ //
+ ReturnSendPacketResources(Packet);
+
+ //
+ // Open the stage
+ //
+ Mlid->StageOpen = TRUE;
+
+ (*((PUINT32)((*(Mlid->StatsTable->StatsTable.MGenericCountsPtr))[14].StatCounter)))--; // MQDepth
+
+ //
+ // Store send status in ECB
+ //
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ SendECB->ECB_Status = (UINT16)SUCCESSFUL;
+ (*((PUINT32)((*(Mlid->StatsTable->StatsTable.MGenericCountsPtr))[0].StatCounter)))++; // MTotalTxPacketCount
+
+ Statistic = ((PUINT64)((*(Mlid->StatsTable->StatsTable.MGenericCountsPtr))[8].StatCounter)); // MTotalTxOKByteCount;
+ if (((UINT32)0xFFFFFFFF - Statistic->Low_UINT32) < PacketSize) {
+ Statistic->High_UINT32++;
+ }
+ Statistic->Low_UINT32 += PacketSize;
+
+ } else {
+
+ SendECB->ECB_Status = (UINT16)FAIL;
+ (*((PUINT32)((*(Mlid->StatsTable->StatsTable.MGenericCountsPtr))[6].StatCounter)))++; // MTotalTxMiscCount
+
+ }
+
+ //
+ // Call FastSendComplete()
+ //
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ (*(Mlid->LSLFunctionList->SupportAPIArray[FastSendComplete_INDEX]))(
+ SendECB
+ );
+
+ //
+ // Call Service Events
+ //
+ (*(Mlid->LSLFunctionList->SupportAPIArray[ServiceEvents_INDEX]))(
+ );
+
+ NdisAcquireSpinLock(&(Mlid->MlidSpinLock));
+
+ //
+ // If StageOpen and !InSendPacket and SendsQueued
+ //
+
+ if (Mlid->StageOpen && !Mlid->InSendPacket) {
+
+ //
+ // Send all packets possible for MLID
+ //
+
+ SendPackets(Mlid);
+
+ }
+
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+}
+
+VOID
+NdisMlidTransferDataComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that an NdisTransferData has completed.
+
+Arguments:
+
+ ProtocolBindingContext - A pointer to the MLID_STRUCT that the transfer data
+ was called for.
+
+ NdisPacket - The packet that contains the data.
+
+ NdisStatus - The completion status for the request.
+
+ BytesTransferred - Number of bytes actually transferred.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PMLID_STRUCT Mlid = (PMLID_STRUCT)ProtocolBindingContext;
+ PECB ReceiveECB;
+ PMLID_RESERVED Reserved = PMLID_RESERVED_FROM_PNDIS_PACKET(Packet);
+ PNDIS_BUFFER NdisBuffer;
+
+ //
+ // Get corresponding ECB
+ //
+ ReceiveECB = Reserved->SendECB;
+
+ NdisAcquireSpinLock(&(Mlid->MlidSpinLock));
+
+ //
+ // Return resources to Mlid
+ //
+
+ //
+ // Unchain all NDIS_BUFFERs from packet
+ //
+
+ NdisUnchainBufferAtFront(
+ Packet,
+ &NdisBuffer
+ );
+
+ while (NdisBuffer != NULL) {
+
+ NdisFreeBuffer(NdisBuffer);
+
+ NdisUnchainBufferAtFront(
+ Packet,
+ &NdisBuffer
+ );
+
+ }
+
+ NdisFreePacket(Packet);
+
+ //
+ // Store status in ECB
+ //
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ ReceiveECB->ECB_Status = (UINT16)SUCCESSFUL;
+
+ } else {
+
+ ReceiveECB->ECB_Status = (UINT16)FAIL;
+
+ }
+
+ //
+ // Call FastHoldEvent()
+ //
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ (*(Mlid->LSLFunctionList->SupportAPIArray[FastHoldEvent_INDEX]))(
+ ReceiveECB
+ );
+
+ //
+ // Call Service Events
+ //
+ (*(Mlid->LSLFunctionList->SupportAPIArray[ServiceEvents_INDEX]))(
+ );
+
+}
+
+VOID
+NdisMlidResetComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that a reset adapter
+ is complete. This routine may be called at initialization time
+ or during runtime. Therefore it merely stores the completion
+ status.
+
+Arguments:
+
+ ProtocolBindingContext - Pointer to the MLID_STRUCT that we submitted the Reset to.
+
+ NdisStatus - The request completion code.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PMLID_STRUCT Mlid = (PMLID_STRUCT)ProtocolBindingContext;
+
+ //
+ // Store status
+ //
+ Mlid->RequestStatus = Status;
+
+}
+
+VOID
+NdisMlidRequestComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS Status
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that a request is complete.
+ Since we only ever have one request outstanding, all we do is record the
+ status and, if necessary, set the event to signalled to unblock the
+ initialization thread.
+
+Arguments:
+
+ ProtocolBindingContext - Pointer to the MLID_STRUCT that we submitted the request to.
+
+ NdisRequest - The object describing the request.
+
+ NdisStatus - The request completion code.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PMLID_STRUCT Mlid = (PMLID_STRUCT)ProtocolBindingContext;
+
+ NdisAcquireSpinLock(&(Mlid->MlidSpinLock));
+
+ Mlid->Unloading = FALSE;
+
+ //
+ // Store status
+ //
+ Mlid->RequestStatus = Status;
+
+ if (Mlid->UsingEvent) {
+
+ //
+ // Set event to indicate completion of request
+ //
+
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ KeSetEvent(&Mlid->MlidRequestCompleteEvent, 0L, FALSE);
+
+ } else if (NdisRequest == (&(Mlid->StatsTable->NdisRequest))) {
+
+ //
+ // This is from the statistic gathering timer.
+ //
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ (*((PUINT32)((*(Mlid->StatsTable->StatsTable.MMediaCountsPtr))
+ [
+ Mlid->StatsTable->StatisticNumber
+ ].StatCounter))) =
+ Mlid->StatsTable->StatisticValue;
+
+ }
+
+ Mlid->StatsTable->StatisticNumber++;
+
+ switch (Mlid->NdisMlidMedium) {
+
+ case NdisMedium802_3:
+
+ if (Mlid->StatsTable->StatisticNumber >= NUM_ETHERNET_COUNTS) {
+ Mlid->StatsTable->StatisticNumber = 0;
+ }
+
+ break;
+
+ case NdisMedium802_5:
+
+ if (Mlid->StatsTable->StatisticNumber >= NUM_TOKEN_RING_COUNTS) {
+ Mlid->StatsTable->StatisticNumber = 0;
+ }
+
+ break;
+
+ case NdisMediumFddi:
+
+ if (Mlid->StatsTable->StatisticNumber >= NUM_FDDI_COUNTS) {
+ Mlid->StatsTable->StatisticNumber = 0;
+ }
+
+ break;
+
+ }
+
+ if (Mlid->StatsTable->StatisticNumber == 0) {
+
+ //
+ // Set timer for 30 seconds from now.
+ //
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ NdisSetTimer(&(Mlid->StatsTable->StatisticTimer), 30000);
+
+ return;
+
+ }
+
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ NdisSetTimer(&(Mlid->StatsTable->StatisticTimer), 1);
+
+ return;
+
+ } else {
+
+ //
+ // Free request
+ //
+
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ ExFreePool(NdisRequest);
+
+ }
+
+}
+
+NDIS_STATUS
+NdisMlidReceive(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookAheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that a frame has been received on the physical link.
+
+Arguments:
+
+ BindingContext - The Adapter Binding specified at initialization time.
+
+ ReceiveContext - A magic cookie for the MAC.
+
+ HeaderBuffer - pointer to a buffer containing the packet header.
+
+ HeaderBufferSize - the size of the header.
+
+ LookaheadBuffer - pointer to a buffer containing the negotiated minimum
+ amount of buffer I get to look at (not including header).
+
+ LookaheadBufferSize - the size of the above. May be less than asked
+ for, if that's all there is.
+
+ PacketSize - Overall size of the packet (not including header).
+
+Return Value:
+
+ NDIS_STATUS - status of operation, one of:
+
+ NDIS_STATUS_SUCCESS if packet accepted,
+ NDIS_STATUS_NOT_RECOGNIZED if not recognized by protocol,
+ NDIS_any_other_thing if I understand, but can't handle.
+
+--*/
+{
+ PMLID_STRUCT Mlid = (PMLID_STRUCT)ProtocolBindingContext;
+ LOOKAHEAD OdiLookAhead;
+ UINT32 MlidHeaderSize;
+ PUINT64 Statistic;
+ UINT8 TmpMediaHeader[64];
+ PECB ReceiveECB;
+
+ NDIS_STATUS NdisStatus;
+ PNDIS_PACKET NdisReceivePacket;
+ PNDIS_BUFFER NdisBuffer;
+ PMLID_RESERVED Reserved;
+ ULONG NdisBytesCopied;
+ UINT32 FrameID;
+
+ //
+ // If MLID is unloading, then return
+ //
+ if (Mlid->Unloading) {
+ return(NDIS_STATUS_SUCCESS);
+ }
+
+ NdisAcquireSpinLock(&(Mlid->MlidSpinLock));
+
+ if (PacketSize < 8) {
+
+ ASSERT(Mlid->PromiscuousModeEnables > 0);
+
+ //
+ // Not enough bytes to determine
+ //
+
+ OdiLookAhead.LkAhd_FrameDataSize = (UINT32)PacketSize;
+ OdiLookAhead.LkAhd_MediaHeaderPtr = (PUINT8)HeaderBuffer;
+
+ OdiLookAhead.LkAhd_DataLookAheadPtr = (PUINT8)LookAheadBuffer;
+ OdiLookAhead.LkAhd_DataLookAheadLen = (UINT32)LookaheadBufferSize;
+
+ switch (Mlid->NdisMlidMedium) {
+
+ case NdisMedium802_3:
+ RtlCopyMemory(&(OdiLookAhead.LkAhd_ImmediateAddress[0]),
+ ((PUINT8)HeaderBuffer) + 6,
+ 6
+ );
+ break;
+
+ case NdisMedium802_5:
+ RtlCopyMemory(&(OdiLookAhead.LkAhd_ImmediateAddress[0]),
+ ((PUINT8)HeaderBuffer) + 8,
+ 6
+ );
+ break;
+
+ case NdisMediumFddi:
+ RtlCopyMemory(&(OdiLookAhead.LkAhd_ImmediateAddress[0]),
+ ((PUINT8)HeaderBuffer) + 7,
+ 6
+ );
+ break;
+
+ }
+
+ OdiLookAhead.LkAhd_BoardNumber = Mlid->BoardNumber;
+ RtlZeroMemory(OdiLookAhead.LkAhd_ProtocolID, 6);
+
+ OdiLookAhead.LkAhd_PktAttr = 0x4; // Runt packet
+ OdiLookAhead.LkAhd_DestType = 0x20; // Global Error
+
+ goto IndicatePacket;
+
+ }
+
+ //
+ // Determine the frame-type of the frame.
+ // this will move the Data Pointer if necessary and modify the Size fields.
+ //
+ FrameID = ReceiveGetFrameType(Mlid,
+ HeaderBuffer,
+ LookAheadBuffer
+ );
+
+ //
+ // If FrameType is not the same as for this MLID, then exit
+ //
+ if ((FrameID != Mlid->ConfigTable.MLIDCFG_FrameID) &&
+ (Mlid->PromiscuousModeEnables == 0)) {
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+ //
+ // Now get header length based on the FrameID
+ //
+ switch (FrameID) {
+
+ case ETHERNET_II_FRAME_ID:
+ case ETHERNET_802_3_FRAME_ID:
+ MlidHeaderSize = 0;
+ break;
+
+ case FDDI_802_2_FRAME_ID:
+ case TOKEN_RING_802_2_FRAME_ID:
+ case ETHERNET_802_2_FRAME_ID:
+ if (((PUCHAR)LookAheadBuffer)[2] != 0x03) {
+ MlidHeaderSize = 4;
+ } else {
+ MlidHeaderSize = 3;
+ }
+ break;
+
+ case FDDI_SNAP_FRAME_ID:
+ case TOKEN_RING_SNAP_FRAME_ID:
+ case ETHERNET_SNAP_FRAME_ID:
+ MlidHeaderSize = 8;
+ break;
+
+ default:
+ MlidHeaderSize = 0;
+ break;
+
+ }
+ OdiLookAhead.LkAhd_FrameDataSize = (UINT32)PacketSize - MlidHeaderSize;
+
+ if (MlidHeaderSize != 0) {
+
+ //
+ // We must move media header info around so that the ODI media header
+ // is correct.
+ //
+
+ NdisMoveMappedMemory((PUCHAR)TmpMediaHeader,
+ HeaderBuffer,
+ HeaderBufferSize
+ );
+ NdisMoveMappedMemory((PUCHAR)(TmpMediaHeader + HeaderBufferSize),
+ LookAheadBuffer,
+ MlidHeaderSize
+ );
+
+ OdiLookAhead.LkAhd_MediaHeaderPtr = (PUINT8)TmpMediaHeader;
+
+ } else {
+
+ OdiLookAhead.LkAhd_MediaHeaderPtr = (PUINT8)HeaderBuffer;
+
+ }
+
+ //
+ // Fill in buffer portions of ODI LOOKAHEAD structure
+ //
+
+ OdiLookAhead.LkAhd_DataLookAheadPtr = ((PUINT8)LookAheadBuffer) + MlidHeaderSize;
+ OdiLookAhead.LkAhd_DataLookAheadLen = (UINT32)LookaheadBufferSize - MlidHeaderSize;
+
+ switch (Mlid->NdisMlidMedium) {
+
+ case NdisMedium802_3:
+ RtlCopyMemory(&(OdiLookAhead.LkAhd_ImmediateAddress[0]),
+ ((PUINT8)HeaderBuffer) + 6,
+ 6
+ );
+ break;
+
+ case NdisMedium802_5:
+ RtlCopyMemory(&(OdiLookAhead.LkAhd_ImmediateAddress[0]),
+ ((PUINT8)HeaderBuffer) + 8,
+ 6
+ );
+ break;
+
+ case NdisMediumFddi:
+ RtlCopyMemory(&(OdiLookAhead.LkAhd_ImmediateAddress[0]),
+ ((PUINT8)HeaderBuffer) + 7,
+ 6
+ );
+ break;
+
+ }
+
+
+ //
+ // Get the BoardNumber for this NDIS MAC
+ //
+ OdiLookAhead.LkAhd_BoardNumber = Mlid->BoardNumber;
+
+ //
+ // Build protocol ID for the frame
+ //
+ ReceiveGetProtocolID(Mlid, &OdiLookAhead, FrameID);
+
+ //
+ // Fill in the packet attributes.
+ //
+ switch (FrameID) {
+
+ case ETHERNET_II_FRAME_ID:
+ case ETHERNET_802_3_FRAME_ID:
+ case FDDI_SNAP_FRAME_ID:
+ case TOKEN_RING_SNAP_FRAME_ID:
+ case ETHERNET_SNAP_FRAME_ID:
+ OdiLookAhead.LkAhd_PktAttr = 0;
+ break;
+
+ case FDDI_802_2_FRAME_ID:
+ case TOKEN_RING_802_2_FRAME_ID:
+ case ETHERNET_802_2_FRAME_ID:
+ if (((PUCHAR)LookAheadBuffer)[2] != 0x03) {
+ OdiLookAhead.LkAhd_PktAttr = 0x40000000;
+ } else {
+ if (((PUCHAR)LookAheadBuffer)[0] != ((PUCHAR)LookAheadBuffer)[1]) {
+ OdiLookAhead.LkAhd_PktAttr = 0x20000000;
+ } else {
+ OdiLookAhead.LkAhd_PktAttr = 0x0;
+ }
+ }
+ break;
+
+ default:
+ OdiLookAhead.LkAhd_PktAttr = 0x20;
+ break;
+
+ }
+
+
+ //
+ // Update SR info
+ //
+ if (OdiLookAhead.LkAhd_ImmediateAddress[0] & 0x80) {
+
+ //
+ // Yes
+ //
+ if (Mlid->ConfigTable.MLIDCFG_SourceRouting != NULL) {
+
+ //
+ // Call function
+ //*\\ here - Update SR Info. Are parameters correct?
+ (*((PLSL_SR_FUNCTION)(Mlid->ConfigTable.MLIDCFG_SourceRouting)))
+ ( Mlid->BoardNumber,
+ OdiLookAhead.LkAhd_MediaHeaderPtr + 14,
+ OdiLookAhead.LkAhd_ImmediateAddress
+ );
+
+
+ }
+
+ }
+
+ ReceiveSetDestinationType(Mlid, &OdiLookAhead);
+
+ if (OdiLookAhead.LkAhd_DestType & 0x1) {
+ (*((PUINT32)((*(Mlid->StatsTable->StatsTable.MGenericCountsPtr))[11].StatCounter)))++; // MTotalGroupAddrRxCount
+ }
+ (*((PUINT32)((*(Mlid->StatsTable->StatsTable.MGenericCountsPtr))[1].StatCounter)))++; // MTotalRxPacketCount
+
+IndicatePacket:
+
+ Statistic = ((PUINT64)((*(Mlid->StatsTable->StatsTable.MGenericCountsPtr))[8].StatCounter)); // MTotalTxOKByteCount;
+ if (((UINT32)0xFFFFFFFF - Statistic->Low_UINT32) < PacketSize) {
+ Statistic->High_UINT32++;
+ }
+ Statistic->Low_UINT32 += PacketSize;
+
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ //
+ // CLSL_GetStackECB to obtain and ECB for this packet
+ //
+ ReceiveECB = (*((PECB (*) (PLOOKAHEAD))
+ (Mlid->LSLFunctionList->SupportAPIArray[GetStackECB_INDEX])))(
+ &OdiLookAhead
+ );
+
+
+ if (ReceiveECB == NULL) {
+
+ (*((PUINT32)((*(Mlid->StatsTable->StatsTable.MGenericCountsPtr))[2].StatCounter)))++; // MNoECBAvailableCount
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+ NdisAcquireSpinLock(&(Mlid->MlidSpinLock));
+
+ //
+ // Get an NDIS_PACKET
+ //
+ NdisAllocatePacket(
+ &NdisStatus,
+ &NdisReceivePacket,
+ Mlid->ReceivePacketPool
+ );
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Fail ECB and return it
+ //
+
+ (*((PUINT32)((*(Mlid->StatsTable->StatsTable.MGenericCountsPtr))[2].StatCounter)))++; // MNoECBAvailableCount
+
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ ReceiveECB->ECB_Status = (UINT16)OUT_OF_RESOURCES;
+
+ //
+ // Call CLSL_FastHoldEvent
+ //
+ (*(Mlid->LSLFunctionList->SupportAPIArray[FastHoldEvent_INDEX]))(
+ ReceiveECB
+ );
+
+ //
+ // Call Service Events
+ //
+ (*(Mlid->LSLFunctionList->SupportAPIArray[ServiceEvents_INDEX]))(
+ );
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+ //
+ // Convert ECB fragment list into an NDIS_BUFFER chain
+ //
+ if (BuildReceiveBufferChain(Mlid, NdisReceivePacket, ReceiveECB) !=
+ NDIS_STATUS_SUCCESS) {
+
+ //
+ // Return resources
+ //
+
+ NdisFreePacket(NdisReceivePacket);
+
+ //
+ // Fail ECB and return it
+ //
+
+ (*((PUINT32)((*(Mlid->StatsTable->StatsTable.MGenericCountsPtr))[2].StatCounter)))++; // MNoECBAvailableCount
+
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ ReceiveECB->ECB_Status = (UINT16)OUT_OF_RESOURCES;
+
+ //
+ // Call CLSL_FastHoldEvent
+ //
+ (*(Mlid->LSLFunctionList->SupportAPIArray[FastHoldEvent_INDEX]))(
+ ReceiveECB
+ );
+
+ //
+ // Call Service Events
+ //
+ (*(Mlid->LSLFunctionList->SupportAPIArray[ServiceEvents_INDEX]))(
+ );
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+ //
+ // Store ECB info into packet header
+ //
+ Reserved = PMLID_RESERVED_FROM_PNDIS_PACKET(NdisReceivePacket);
+ Reserved->SendECB = ReceiveECB;
+
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ //
+ // Call NdisTransferData on ECB, if one exists
+ //
+ NdisTransferData(
+ &NdisStatus,
+ Mlid->NdisBindingHandle,
+ MacReceiveContext,
+ OdiLookAhead.LkAhd_FrameDataStartCopyOffset + MlidHeaderSize,
+ OdiLookAhead.LkAhd_FrameDataBytesWanted - MlidHeaderSize,
+ NdisReceivePacket,
+ &NdisBytesCopied
+ );
+
+ //
+ // If it pended, return
+ //
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+ //
+ // Store Status
+ //
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ ReceiveECB->ECB_Status = (UINT16)SUCCESSFUL;
+
+ } else {
+
+ ReceiveECB->ECB_Status = (UINT16)FAIL;
+
+ }
+
+ //
+ // Release Resources
+ //
+ NdisAcquireSpinLock(&(Mlid->MlidSpinLock));
+
+ //
+ // Unchain all NDIS_BUFFERs from packet
+ //
+
+ NdisUnchainBufferAtFront(
+ NdisReceivePacket,
+ &NdisBuffer
+ );
+
+ while (NdisBuffer != NULL) {
+
+ NdisFreeBuffer(NdisBuffer);
+
+ NdisUnchainBufferAtFront(
+ NdisReceivePacket,
+ &NdisBuffer
+ );
+
+ }
+
+ NdisFreePacket(NdisReceivePacket);
+
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ //
+ // Call CLSL_FastHoldEvent
+ //
+ (*(Mlid->LSLFunctionList->SupportAPIArray[FastHoldEvent_INDEX]))(
+ ReceiveECB
+ );
+
+ //
+ // Call Service Events
+ //
+ (*(Mlid->LSLFunctionList->SupportAPIArray[ServiceEvents_INDEX]))(
+ );
+
+ return(NDIS_STATUS_SUCCESS);
+
+}
+
+VOID
+NdisMlidReceiveComplete(
+ IN NDIS_HANDLE ProtocolBindingContext
+ )
+
+/*++
+
+Routine Description:
+
+ Marks the completion of receives from the NDIS_MAC.
+
+Arguments:
+
+ ProtocolBindingContext - Pointer to the MLID_STRUCT that is changing.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ return;
+}
+
+VOID
+NdisMlidStatus(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to indicate status changes in the NDIS_MAC.
+
+Arguments:
+
+ ProtocolBindingContext - Pointer to the MLID_STRUCT that is changing.
+
+ GeneralStatus - NDIS_STATUS that is being indicated.
+
+ StatusBuffer - A buffer containing more information.
+
+ StatusBufferSize - Size of the buffer.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PMLID_STRUCT Mlid = (PMLID_STRUCT)ProtocolBindingContext;
+ UINT32 RingStatus;
+ UINT32 RingValue;
+
+ //
+ // Switch on status
+ //
+ switch (GeneralStatus) {
+
+ //
+ // NDIS_STATUS_CLOSED
+ // For the MLID call CLSL_DeRegisterMLID
+ // Set closed flag
+ //
+
+ case NDIS_STATUS_CLOSED:
+
+ //
+ // Call DeregisterMlid
+ //
+ (*(Mlid->LSLFunctionList->SupportAPIArray[DeRegisterMLID_INDEX]))(
+ Mlid->BoardNumber
+ );
+
+ //
+ // Set a flag to stop all processing
+ //
+ Mlid->Unloading = TRUE;
+
+ break;
+
+ case NDIS_STATUS_RING_STATUS:
+
+ //
+ // NDIS_STATUS_RING_STATUS
+ // Store new ring status in MLID_ConfigTable.
+ //
+ if (StatusBufferSize != sizeof(UINT32)) {
+
+ break;
+
+ }
+
+ RingStatus = *((UNALIGNED UINT32 *)(StatusBuffer));
+ RingValue = 0;
+
+ if (RingStatus & NDIS_RING_SIGNAL_LOSS) {
+ RingValue |= 0x8000;
+ }
+
+ if (RingStatus & NDIS_RING_HARD_ERROR) {
+ RingValue |= 0x4000;
+ }
+
+ if (RingStatus & NDIS_RING_SOFT_ERROR) {
+ RingValue |= 0x2000;
+ }
+
+ if (RingStatus & NDIS_RING_TRANSMIT_BEACON) {
+ RingValue |= 0x1000;
+ }
+
+ if (RingStatus & NDIS_RING_LOBE_WIRE_FAULT) {
+ RingValue |= 0x0800;
+ }
+
+ if (RingStatus & NDIS_RING_AUTO_REMOVAL_ERROR) {
+ RingValue |= 0x0400;
+ }
+
+ if (RingStatus & NDIS_RING_REMOVE_RECEIVED) {
+ RingValue |= 0x0100;
+ }
+
+ if (RingStatus & NDIS_RING_COUNTER_OVERFLOW) {
+ RingValue |= 0x0080;
+ }
+
+ if (RingStatus & NDIS_RING_SINGLE_STATION) {
+ RingValue |= 0x0040;
+ }
+
+ if (RingStatus & NDIS_RING_RING_RECOVERY) {
+ RingValue |= 0x0020;
+ }
+
+ NdisAcquireSpinLock(&(Mlid->MlidSpinLock));
+
+ *((PUINT32)((*(Mlid->StatsTable->StatsTable.MMediaCountsPtr))[11].StatCounter)) =
+ RingValue;
+
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ break;
+
+ }
+
+}
+
+VOID
+NdisMlidStatusComplete(
+ IN NDIS_HANDLE ProtocolBindingContext
+ )
+
+/*++
+
+Routine Description:
+
+ Marks the completion of any state previously indicated.
+
+Arguments:
+
+ ProtocolBindingContext - Pointer to the MLID_STRUCT that is changing.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ return;
+}
+
diff --git a/private/ntos/ndis/lsl/ndismlid.h b/private/ntos/ndis/lsl/ndismlid.h
new file mode 100644
index 000000000..ff1550820
--- /dev/null
+++ b/private/ntos/ndis/lsl/ndismlid.h
@@ -0,0 +1,128 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ndismlid.h
+
+Abstract:
+
+ This file contains all the NDIS protocol interface routines.
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 3-8-93
+
+Environment:
+
+ Kernel Mode.
+
+Revision History:
+
+--*/
+
+
+//
+// Protocol Reserved portion of NDIS_PACKET
+//
+
+typedef struct _MLID_RESERVED {
+
+ PECB SendECB;
+
+ //
+ // Here is a cheap way of getting buffers for media headers
+ //
+ UCHAR MediaHeaderLength;
+ UCHAR MediaHeader[64];
+
+} MLID_RESERVED, *PMLID_RESERVED;
+
+//
+// Returns the reserved portion of the NDIS_PACKET.
+//
+#define PMLID_RESERVED_FROM_PNDIS_PACKET(_P) (PMLID_RESERVED)&((_P)->ProtocolReserved[0])
+
+
+extern
+VOID
+NdisMlidOpenAdapterComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status,
+ IN NDIS_STATUS OpenErrorStatus
+ );
+
+extern
+VOID
+NdisMlidCloseAdapterComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status
+ );
+
+extern
+VOID
+NdisMlidSendComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ );
+
+extern
+VOID
+NdisMlidTransferDataComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ );
+
+extern
+VOID
+NdisMlidResetComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status
+ );
+
+extern
+VOID
+NdisMlidRequestComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS Status
+ );
+
+extern
+NDIS_STATUS
+NdisMlidReceive(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookAheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+extern
+VOID
+NdisMlidReceiveComplete(
+ IN NDIS_HANDLE ProtocolBindingContext
+ );
+
+extern
+VOID
+NdisMlidStatus(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ );
+
+extern
+VOID
+NdisMlidStatusComplete(
+ IN NDIS_HANDLE ProtocolBindingContext
+ );
+
+
diff --git a/private/ntos/ndis/lsl/sources b/private/ntos/ndis/lsl/sources
new file mode 100644
index 000000000..4a61377d7
--- /dev/null
+++ b/private/ntos/ndis/lsl/sources
@@ -0,0 +1,46 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=ndismlid
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+INCLUDES=..\..\inc
+
+SOURCES=lslmlid.c \
+ ndismlid.c \
+ mlidsend.c \
+ mlidrcv.c \
+ mlidstat.c \
+ init.c
+
+RELATIVE_DEPTH=..\..
+
+MSC_WARNING_LEVEL=/W3 /WX
+
diff --git a/private/ntos/ndis/lt200/lt200.rc b/private/ntos/ndis/lt200/lt200.rc
new file mode 100644
index 000000000..666e93c84
--- /dev/null
+++ b/private/ntos/ndis/lt200/lt200.rc
@@ -0,0 +1,38 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "DayStar Digital LT200 LocalTalk Card Driver"
+#define VER_INTERNALNAME_STR "LT200.SYS"
+
+#include "common.ver"
+
diff --git a/private/ntos/ndis/lt200/ltdebug.h b/private/ntos/ndis/lt200/ltdebug.h
new file mode 100644
index 000000000..5bf42fafd
--- /dev/null
+++ b/private/ntos/ndis/lt200/ltdebug.h
@@ -0,0 +1,103 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ltdebug.h
+
+Abstract:
+
+ This module contains the debug code.
+
+Author:
+
+ Stephen Hou (stephh@microsoft.com)
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+
+Revision History:
+ 19 Jun 1992 Initial Version (dch@pacvax.pacersoft.com)
+
+Notes: Tab stop: 4
+--*/
+
+#ifndef _LTDEBUG_
+#define _LTDEBUG_
+
+// Debug Levels used with DBGPRINT
+#define DBG_LEVEL_LOW 0
+#define DBG_LEVEL_ENTRY 0x1000
+#define DBG_LEVEL_INFO 0x5000
+#define DBG_LEVEL_WARN 0x6000
+#define DBG_LEVEL_ERR 0x7000
+#define DBG_LEVEL_FATAL 0x8000
+
+// Component Types
+#define DBG_COMP_INIT 0x00000001
+#define DBG_COMP_DEINIT 0x00000002
+#define DBG_COMP_SEND 0x00000004
+#define DBG_COMP_RECV 0x00000008
+#define DBG_COMP_LOOP 0x00000010
+#define DBG_COMP_REQ 0x00000020
+#define DBG_COMP_REGISTRY 0x00000040
+#define DBG_COMP_NDIS 0x00000080
+#define DBG_COMP_REF 0x00000100
+#define DBG_COMP_TIMER 0x00000200
+#define DBG_COMP_UTILS 0x00000400
+#define DBG_COMP_ALL 0xffffffff
+
+// File Ids used for errorlogging
+#define LTRECV 0x00010000
+#define LTSEND 0x00020000
+#define LTREG 0x00040000
+#define LTRESET 0x00080000
+#define LTTIMER 0x00100000
+#define LTFIRM 0x00200000
+#define LTREQ 0x00400000
+#define LTUTILS 0x00800000
+#define LTLOOP 0x01000000
+#define LTINIT 0x02000000
+
+
+// Macro we use to do our errorlogging.
+#define LOGERROR(Adapter, ErrorCode) \
+ { \
+ NdisWriteErrorLogEntry( \
+ Adapter, \
+ ErrorCode, \
+ 1, \
+ FILENUM | __LINE__); \
+ }
+
+#if DBG
+
+#define TMPLOGERR() (DbgPrint("LT200: TMP LOG ERROR %s %lx\n", __FILE__, __LINE__))
+
+#define DBGPRINT(Component, Level, Fmt) \
+ { \
+ if ((LtDebugSystems & Component) && (Level >= LtDebugLevel)) \
+ { \
+ DbgPrint(" *** LT200 - "); \
+ DbgPrint Fmt; \
+ } \
+ }
+
+#define DBGBREAK(Level) \
+ { \
+ if (Level >= LtDebugLevel) { \
+ DbgBreakPoint(); \
+ } \
+ }
+
+#else
+#define TMPLOGERR()
+#define DBGPRINT(Component, Level, Fmt)
+#define DBGBREAK(Level)
+#endif
+
+
+#ifdef LTDEBUG_LOCALS
+
+#endif // LTDEBUG_LOCALS
+
+#endif // _LTDEBUG_
diff --git a/private/ntos/ndis/lt200/ltfirm.c b/private/ntos/ndis/lt200/ltfirm.c
new file mode 100644
index 000000000..b5c4c2ddd
--- /dev/null
+++ b/private/ntos/ndis/lt200/ltfirm.c
@@ -0,0 +1,755 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ltfirm.c
+
+Abstract:
+
+
+Author:
+
+ Stephen Hou (stephh@microsoft.com)
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+
+Revision History:
+ 19 Jun 1992 Initial Version (dch@pacvax.pacersoft.com)
+
+Notes: Tab stop: 4
+--*/
+
+#define LTFIRM_H_LOCALS
+#include "ltmain.h"
+#include "ltfirm.h"
+
+// Define file id for errorlogging
+#define FILENUM LTFIRM
+
+UCHAR LtMicroCode[] =
+{
+#ifndef OLD_FIRMWARE
+ 0x3A, 0x03, 0x00, 0x32, 0x93, 0x0A, 0x21, 0x8E, 0x0F, 0x3E,
+ 0x55, 0x77, 0xBE, 0x20, 0x09, 0x3E, 0xAA, 0x77, 0xBE, 0x20,
+ 0x03, 0x23, 0x18, 0xF1, 0x22, 0x91, 0x0A, 0xF9, 0x11, 0x95,
+ 0x0A, 0x21, 0x8E, 0x0F, 0xB7, 0xED, 0x52, 0x4D, 0x44, 0x0B,
+ 0x6B, 0x62, 0x13, 0x36, 0x00, 0xED, 0xB0, 0x3E, 0x10, 0xED,
+ 0x39, 0x33, 0x3E, 0x00, 0xED, 0x39, 0x32, 0xED, 0x39, 0x36,
+ 0x3E, 0x0C, 0xED, 0x39, 0x31, 0x3E, 0xC3, 0x21, 0x26, 0x02,
+ 0x32, 0x38, 0x00, 0x22, 0x39, 0x00, 0xED, 0x56, 0xCD, 0x1D,
+ 0x02, 0xFB, 0xCD, 0x3B, 0x0A, 0x18, 0xA9, 0x43, 0x6F, 0x70,
+ 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29,
+ 0x20, 0x31, 0x39, 0x38, 0x38, 0x20, 0x2D, 0x20, 0x31, 0x39,
+ 0x39, 0x31, 0x2C, 0x20, 0x50, 0x72, 0x69, 0x6E, 0x74, 0x69,
+ 0x6E, 0x67, 0x20, 0x43, 0x6F, 0x6D, 0x6D, 0x75, 0x6E, 0x69,
+ 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, 0x41, 0x73,
+ 0x73, 0x6F, 0x63, 0x69, 0x61, 0x74, 0x65, 0x73, 0x2E, 0x20,
+ 0x20, 0x41, 0x6C, 0x6C, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74,
+ 0x73, 0x20, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64,
+ 0x2E, 0x20, 0x20, 0x04, 0x04, 0x16, 0x28, 0xFF, 0x3C, 0x04,
+ 0x60, 0x0A, 0xE0, 0x06, 0x00, 0x07, 0x7E, 0x02, 0x40, 0x0B,
+ 0xF6, 0x0C, 0x06, 0x0D, 0x00, 0x0E, 0xC1, 0x0F, 0x00, 0x05,
+ 0x60, 0x03, 0xC0, 0x01, 0x00, 0x09, 0x08, 0x3E, 0x03, 0xD3,
+ 0x52, 0x3E, 0xC0, 0xD3, 0x52, 0xC9, 0x3E, 0x03, 0xD3, 0x52,
+ 0x3E, 0xD5, 0xD3, 0x52, 0xC9, 0x3E, 0x05, 0xD3, 0x52, 0x3E,
+ 0xE0, 0xD3, 0x52, 0xC9, 0x3E, 0x05, 0xD3, 0x52, 0x3E, 0xE0,
+ 0xD3, 0x52, 0xC9, 0x3E, 0x05, 0xD3, 0x52, 0x3E, 0x60, 0xD3,
+ 0x52, 0xC9, 0x06, 0x1C, 0x21, 0xB3, 0x01, 0x0E, 0x52, 0xED,
+ 0xA3, 0xC2, 0x03, 0x02, 0x21, 0x26, 0x02, 0x22, 0x40, 0x00,
+ 0x3A, 0x03, 0x00, 0xE6, 0x01, 0xC0, 0x3E, 0x0B, 0xED, 0x79,
+ 0x3E, 0x76, 0xED, 0x79, 0xC9, 0x21, 0xB5, 0x0A, 0x36, 0x84,
+ 0xCD, 0xFC, 0x01, 0xC9, 0xF5, 0xC5, 0xD5, 0xE5, 0x2A, 0x95,
+ 0x0A, 0x0E, 0x53, 0x11, 0x62, 0x02, 0x43, 0x14, 0xED, 0xA2,
+ 0x3A, 0xB2, 0x01, 0x5F, 0xDB, 0x52, 0xE6, 0x01, 0x20, 0x06,
+ 0x1D, 0x20, 0xF7, 0xC3, 0x10, 0x03, 0x3E, 0x01, 0xD3, 0x52,
+ 0xDB, 0x52, 0x5F, 0xE6, 0xA0, 0x20, 0x0A, 0xED, 0xA2, 0x20,
+ 0xE1, 0x15, 0x20, 0xDE, 0xC3, 0x0E, 0x03, 0xED, 0xA2, 0x7B,
+ 0xE6, 0x60, 0xC2, 0x14, 0x03, 0x3E, 0x30, 0xD3, 0x52, 0x3E,
+ 0x01, 0xD3, 0x52, 0xAF, 0xD3, 0x52, 0xED, 0x5B, 0x95, 0x0A,
+ 0x2B, 0x37, 0xED, 0x52, 0xDA, 0x12, 0x03, 0x22, 0x97, 0x0A,
+ 0x62, 0x6B, 0x3A, 0x99, 0x0A, 0xBE, 0x20, 0x51, 0x3E, 0x01,
+ 0x32, 0x9D, 0x0A, 0x23, 0x23, 0x3E, 0x84, 0xBE, 0x20, 0x2C,
+ 0x36, 0x85, 0x2B, 0x46, 0x3A, 0x99, 0x0A, 0x77, 0x2B, 0x70,
+ 0x11, 0x03, 0x00, 0xCD, 0x88, 0x03, 0x3E, 0x10, 0xD3, 0x52,
+ 0x3E, 0x38, 0xD3, 0x52, 0xCD, 0xD8, 0x01, 0x2A, 0x95, 0x0A,
+ 0x0E, 0x53, 0x11, 0x62, 0x02, 0x43, 0x14, 0x3A, 0xB1, 0x01,
+ 0x5F, 0xC3, 0x3A, 0x02, 0x3E, 0x81, 0xBE, 0xC2, 0xE2, 0x02,
+ 0x36, 0x82, 0x2B, 0x46, 0x3A, 0x99, 0x0A, 0x77, 0x2B, 0x70,
+ 0x11, 0x03, 0x00, 0xCD, 0x88, 0x03, 0xC3, 0xFD, 0x02, 0x23,
+ 0x23, 0x7E, 0xFE, 0x84, 0xC2, 0xE2, 0x02, 0xCD, 0x3C, 0x03,
+ 0x18, 0x14, 0x3E, 0x80, 0xA6, 0xC2, 0xDD, 0x02, 0xDD, 0xE5,
+ 0xDD, 0x21, 0xAE, 0x0A, 0xCD, 0x5C, 0x06, 0xCD, 0x8F, 0x07,
+ 0xDD, 0xE1, 0xE1, 0xD1, 0xC1, 0xF1, 0xFB, 0xED, 0x4D, 0xDD,
+ 0xE5, 0xDD, 0x21, 0x9E, 0x0A, 0xCD, 0x5C, 0x06, 0xDD, 0xE1,
+ 0xCD, 0x3C, 0x03, 0xC3, 0xF6, 0x02, 0x18, 0xED, 0x18, 0xEB,
+ 0x18, 0xE9, 0xE6, 0x40, 0x28, 0x02, 0x18, 0xE3, 0x18, 0xE1,
+ 0xAF, 0x32, 0xB2, 0x0A, 0xCD, 0xCF, 0x01, 0xC9, 0xC5, 0x21,
+ 0x04, 0x00, 0x39, 0x7E, 0x23, 0x66, 0x6F, 0xCD, 0x32, 0x03,
+ 0xC1, 0xC9, 0x3E, 0x01, 0x32, 0xB2, 0x0A, 0x22, 0x95, 0x0A,
+ 0x36, 0x00, 0x3A, 0xB2, 0x0A, 0xB7, 0xC8, 0x3E, 0x0E, 0xD3,
+ 0x52, 0x3E, 0xC1, 0xD3, 0x52, 0x3E, 0x0A, 0xD3, 0x52, 0x3E,
+ 0xE0, 0xD3, 0x52, 0x3E, 0x06, 0xD3, 0x52, 0x3A, 0x99, 0x0A,
+ 0xD3, 0x52, 0x3E, 0x10, 0xD3, 0x52, 0x3E, 0x38, 0xD3, 0x52,
+ 0x3E, 0x30, 0xD3, 0x52, 0xDB, 0x52, 0xE6, 0x01, 0x28, 0x04,
+ 0xDB, 0x53, 0x18, 0xF2, 0x3E, 0x0E, 0xD3, 0x52, 0x3E, 0x21,
+ 0xD3, 0x52, 0x3E, 0x01, 0xD3, 0x52, 0x3E, 0x09, 0xD3, 0x52,
+ 0x3E, 0x20, 0xD3, 0x52, 0xCD, 0xD8, 0x01, 0xC9, 0x0E, 0x53,
+ 0xCD, 0xCF, 0x01, 0x18, 0x17, 0x0E, 0x53, 0xCD, 0xCF, 0x01,
+ 0xCD, 0xE1, 0x01, 0x3A, 0xAD, 0x01, 0x3D, 0x20, 0xFD, 0xCD,
+ 0xF3, 0x01, 0x3A, 0xAD, 0x01, 0x3D, 0x20, 0xFD, 0xCD, 0xE1,
+ 0x01, 0x3A, 0xAE, 0x01, 0x3D, 0x20, 0xFD, 0x3E, 0x05, 0xD3,
+ 0x52, 0x3E, 0xE9, 0xD3, 0x52, 0x3E, 0x80, 0xD3, 0x52, 0x3A,
+ 0xAF, 0x01, 0x3D, 0x20, 0xFD, 0xED, 0xA3, 0x1B, 0x3E, 0xC0,
+ 0xD3, 0x52, 0xDB, 0x52, 0xE6, 0x04, 0x28, 0xFA, 0xED, 0xA3,
+ 0x1B, 0x7A, 0xB3, 0x20, 0xF3, 0xDB, 0x52, 0xE6, 0x04, 0x28,
+ 0xFA, 0x3A, 0xB1, 0x01, 0x47, 0xDB, 0x52, 0xE6, 0x04, 0x28,
+ 0x03, 0x05, 0x20, 0xF7, 0xDB, 0x52, 0xE6, 0x04, 0x28, 0xFA,
+ 0xCD, 0xEA, 0x01, 0x3A, 0xB0, 0x01, 0x3D, 0x20, 0xFD, 0xCD,
+ 0xF3, 0x01, 0xC9, 0xE5, 0xD5, 0x23, 0x23, 0x7E, 0xE6, 0x80,
+ 0xC2, 0x90, 0x04, 0x2B, 0x3A, 0x99, 0x0A, 0x77, 0x2B, 0x46,
+ 0x21, 0xB4, 0x0A, 0x77, 0x2B, 0x70, 0x11, 0x03, 0x00, 0xF3,
+ 0x3E, 0x0A, 0xD3, 0x52, 0xDB, 0x52, 0xE6, 0x80, 0xCA, 0x28,
+ 0x04, 0xD1, 0xE1, 0x3E, 0x01, 0x37, 0xFB, 0xC9, 0xCD, 0x8F,
+ 0x03, 0x3A, 0xB3, 0x0A, 0xFE, 0xFF, 0xCA, 0x7E, 0x04, 0xCD,
+ 0xD8, 0x01, 0x3A, 0xB1, 0x01, 0x47, 0xDB, 0x52, 0xE6, 0x01,
+ 0x20, 0x06, 0x05, 0x20, 0xF7, 0xC3, 0xAC, 0x04, 0xDB, 0x53,
+ 0x47, 0x3A, 0x99, 0x0A, 0xB8, 0xC2, 0xAC, 0x04, 0x3A, 0xB1,
+ 0x01, 0x47, 0xDB, 0x52, 0xE6, 0x01, 0x20, 0x06, 0x05, 0x20,
+ 0xF7, 0xC3, 0xAC, 0x04, 0xDB, 0x53, 0x3A, 0xB1, 0x01, 0x47,
+ 0xDB, 0x52, 0xE6, 0x01, 0x20, 0x06, 0x05, 0x20, 0xF7, 0xC3,
+ 0xAC, 0x04, 0xDB, 0x53, 0xFE, 0x85, 0xC2, 0xAC, 0x04, 0x3A,
+ 0xB2, 0x01, 0x18, 0x04, 0x3A, 0xB2, 0x01, 0x87, 0x3D, 0x20,
+ 0xFD, 0xD1, 0xE1, 0xCD, 0x88, 0x03, 0xCD, 0x3C, 0x03, 0xB7,
+ 0xFB, 0xC9, 0xD1, 0xE1, 0xF3, 0x3E, 0x0A, 0xD3, 0x52, 0xDB,
+ 0x52, 0xE6, 0x80, 0xCA, 0xA3, 0x04, 0x3E, 0x01, 0x37, 0xFB,
+ 0xC9, 0xCD, 0x8F, 0x03, 0xCD, 0x3C, 0x03, 0xB7, 0xFB, 0xC9,
+ 0xD1, 0xE1, 0x3E, 0x02, 0x37, 0xFB, 0xC9, 0xF3, 0x3E, 0x0E,
+ 0xD3, 0x52, 0x3E, 0x21, 0xD3, 0x52, 0xFB, 0xC9, 0x21, 0x04,
+ 0x00, 0x39, 0x5E, 0x23, 0x56, 0x21, 0x02, 0x00, 0x39, 0x7E,
+ 0x23, 0x66, 0x6F, 0xDD, 0xE5, 0x22, 0xC0, 0x0A, 0xED, 0x53,
+ 0xC2, 0x0A, 0xDD, 0x21, 0xAA, 0x0A, 0xCD, 0x5C, 0x06, 0x3A,
+ 0xB8, 0x0A, 0x32, 0xB9, 0x0A, 0x3A, 0xB7, 0x0A, 0x87, 0x32,
+ 0xB7, 0x0A, 0xCD, 0x6F, 0x06, 0xFE, 0x03, 0x38, 0x10, 0x3A,
+ 0xB8, 0x0A, 0x87, 0x3C, 0xE6, 0x0F, 0x32, 0xB8, 0x0A, 0xAF,
+ 0x32, 0xB7, 0x0A, 0x18, 0x17, 0x3A, 0xB6, 0x0A, 0xCD, 0x6F,
+ 0x06, 0xFE, 0x03, 0x30, 0x0D, 0x3A, 0xB8, 0x0A, 0xCB, 0x3F,
+ 0x32, 0xB8, 0x0A, 0x3E, 0xFF, 0x32, 0xB6, 0x0A, 0x3A, 0xB8,
+ 0x0A, 0x32, 0xB9, 0x0A, 0x3A, 0xB6, 0x0A, 0x87, 0x32, 0xB6,
+ 0x0A, 0x3E, 0x20, 0x32, 0xBA, 0x0A, 0x32, 0xBB, 0x0A, 0x06,
+ 0xFF, 0xDB, 0x52, 0xE6, 0x10, 0x20, 0x03, 0x05, 0x20, 0xF7,
+ 0xCD, 0xB3, 0x04, 0x06, 0x28, 0xDB, 0x52, 0xE6, 0x10, 0x28,
+ 0x03, 0x05, 0x20, 0xF7, 0x3E, 0x0A, 0xD3, 0x52, 0xDB, 0x52,
+ 0xE6, 0x80, 0xC2, 0x2D, 0x05, 0xDB, 0x52, 0xE6, 0x10, 0x28,
+ 0xD6, 0xED, 0x5F, 0x47, 0x3A, 0xB9, 0x0A, 0xA0, 0xE6, 0x0F,
+ 0x28, 0x20, 0x47, 0x0E, 0x0A, 0x3E, 0x0A, 0xD3, 0x52, 0xDB,
+ 0x52, 0xE6, 0x80, 0xCA, 0x76, 0x05, 0xCD, 0xB3, 0x04, 0xC3,
+ 0x9B, 0x05, 0xDB, 0x52, 0xE6, 0x10, 0xCA, 0x9B, 0x05, 0x0D,
+ 0x20, 0xE5, 0x10, 0xE1, 0x2A, 0xC0, 0x0A, 0xED, 0x5B, 0xC2,
+ 0x0A, 0xCD, 0xFB, 0x03, 0x30, 0x07, 0x3D, 0xCA, 0x9B, 0x05,
+ 0xC3, 0xC4, 0x05, 0xDD, 0xE1, 0x21, 0x00, 0x00, 0xC9, 0xDD,
+ 0x21, 0xA2, 0x0A, 0xCD, 0x5C, 0x06, 0x3A, 0xBB, 0x0A, 0x3D,
+ 0x32, 0xBB, 0x0A, 0x28, 0x13, 0x3A, 0xB9, 0x0A, 0xF6, 0x01,
+ 0x32, 0xB9, 0x0A, 0x3A, 0xB6, 0x0A, 0xF6, 0x01, 0x32, 0xB6,
+ 0x0A, 0xC3, 0x2D, 0x05, 0xDD, 0xE1, 0x21, 0x01, 0x00, 0xC9,
+ 0xDD, 0x21, 0xA6, 0x0A, 0xCD, 0x5C, 0x06, 0x3A, 0xB7, 0x0A,
+ 0xF6, 0x01, 0x32, 0xB7, 0x0A, 0x3A, 0xB9, 0x0A, 0x87, 0xF6,
+ 0x01, 0x32, 0xB9, 0x0A, 0x3A, 0xBA, 0x0A, 0x3D, 0x32, 0xBA,
+ 0x0A, 0xC2, 0x2D, 0x05, 0xDD, 0xE1, 0x21, 0x02, 0x00, 0xC9,
+ 0xDD, 0xE5, 0x21, 0x00, 0x00, 0x39, 0x11, 0x04, 0x00, 0x19,
+ 0x7E, 0x32, 0x99, 0x0A, 0xE6, 0x80, 0x32, 0xBC, 0x0A, 0x3A,
+ 0xBC, 0x0A, 0xB7, 0x28, 0x06, 0xDD, 0x21, 0x58, 0x02, 0x18,
+ 0x04, 0xDD, 0x21, 0x96, 0x00, 0x3A, 0x99, 0x0A, 0xB7, 0x28,
+ 0x31, 0x3C, 0x28, 0x2E, 0x3D, 0x21, 0xBD, 0x0A, 0x77, 0x23,
+ 0x77, 0x23, 0x36, 0x81, 0xAF, 0x32, 0x9D, 0x0A, 0xDD, 0x2B,
+ 0xDD, 0xE5, 0xE1, 0x7C, 0xB5, 0x28, 0x2A, 0x21, 0xBD, 0x0A,
+ 0x11, 0x03, 0x00, 0xCD, 0xCD, 0x04, 0x11, 0xE8, 0x03, 0x1B,
+ 0x7B, 0xB2, 0x20, 0xFB, 0x3A, 0x9D, 0x0A, 0xB7, 0x28, 0xE0,
+ 0x3A, 0x99, 0x0A, 0x47, 0x3E, 0x07, 0x80, 0xE6, 0x7F, 0x47,
+ 0x3A, 0xBC, 0x0A, 0xB0, 0x32, 0x99, 0x0A, 0x18, 0xA6, 0xDD,
+ 0xE1, 0xC9, 0xB7, 0xDD, 0x34, 0x00, 0xC0, 0xDD, 0x34, 0x01,
+ 0xC0, 0xDD, 0x34, 0x02, 0xC0, 0xDD, 0x34, 0x03, 0xC0, 0x37,
+ 0xC9, 0x06, 0x08, 0x0E, 0x00, 0x1F, 0x30, 0x01, 0x0C, 0x10,
+ 0xFA, 0x79, 0xC9, 0x21, 0x02, 0x00, 0x39, 0x5E, 0x23, 0x56,
+ 0x23, 0x4E, 0x23, 0x46, 0x23, 0x7E, 0x23, 0x66, 0x69, 0x4F,
+ 0x78, 0x44, 0x67, 0xED, 0xB0, 0xC9, 0x21, 0x02, 0x00, 0x39,
+ 0x7E, 0x23, 0x66, 0x6F, 0x3E, 0x11, 0xED, 0x39, 0x30, 0x7D,
+ 0xED, 0x39, 0x28, 0x7C, 0xED, 0x39, 0x29, 0x3E, 0x00, 0xED,
+ 0x39, 0x2A, 0x3E, 0x40, 0xED, 0x39, 0x2B, 0x3E, 0x00, 0xED,
+ 0x39, 0x2C, 0x21, 0x80, 0x02, 0x7D, 0xED, 0x39, 0x2E, 0x7C,
+ 0xED, 0x39, 0x2F, 0x3E, 0x91, 0xED, 0x39, 0x30, 0xD3, 0x44,
+ 0x3A, 0x94, 0x0A, 0xD3, 0x42, 0xC9, 0x21, 0x02, 0x00, 0x39,
+ 0x7E, 0x23, 0x66, 0x6F, 0x3E, 0x21, 0xED, 0x39, 0x30, 0x3E,
+ 0x40, 0xED, 0x39, 0x20, 0x3E, 0x00, 0xED, 0x39, 0x21, 0xED,
+ 0x39, 0x22, 0x7D, 0xED, 0x39, 0x23, 0x7C, 0xED, 0x39, 0x24,
+ 0x3E, 0x00, 0xED, 0x39, 0x25, 0x21, 0x80, 0x02, 0x7D, 0xED,
+ 0x39, 0x26, 0x7C, 0xED, 0x39, 0x27, 0x3E, 0x61, 0xED, 0x39,
+ 0x30, 0xD3, 0x43, 0x3A, 0x94, 0x0A, 0xD3, 0x42, 0xC9, 0xED,
+ 0x38, 0x2E, 0x5F, 0xED, 0x38, 0x2F, 0x57, 0xED, 0x38, 0x2E,
+ 0x6F, 0xED, 0x38, 0x2F, 0x67, 0xB7, 0xED, 0x52, 0x20, 0xEB,
+ 0x21, 0x80, 0x02, 0xB7, 0xED, 0x52, 0xC9, 0xED, 0x38, 0x26,
+ 0x5F, 0xED, 0x38, 0x27, 0x57, 0xED, 0x38, 0x26, 0x6F, 0xED,
+ 0x38, 0x27, 0x67, 0xB7, 0xED, 0x52, 0x20, 0xEB, 0x21, 0x80,
+ 0x02, 0xB7, 0xED, 0x52, 0xC9, 0xCD, 0x69, 0x0A, 0xDD, 0x6E,
+ 0x06, 0xDD, 0x66, 0x07, 0x7E, 0x23, 0x6E, 0x67, 0xC3, 0x75,
+ 0x0A, 0xCD, 0x69, 0x0A, 0x21, 0x00, 0x00, 0x22, 0xCC, 0x0A,
+ 0x22, 0xC5, 0x0A, 0x22, 0xC7, 0x0A, 0x21, 0x8E, 0x0F, 0x22,
+ 0xCE, 0x0A, 0xED, 0x5B, 0xCE, 0x0A, 0x2A, 0x91, 0x0A, 0xB7,
+ 0xED, 0x52, 0x11, 0x00, 0xFF, 0x19, 0x22, 0xCA, 0x0A, 0xCB,
+ 0x7C, 0x28, 0x06, 0x21, 0x00, 0x7D, 0x22, 0xCA, 0x0A, 0x2A,
+ 0xCE, 0x0A, 0xE5, 0xCD, 0x24, 0x03, 0xC3, 0x75, 0x0A, 0xCD,
+ 0x69, 0x0A, 0xE5, 0x2A, 0x95, 0x0A, 0x23, 0x23, 0x23, 0xE5,
+ 0xCD, 0x45, 0x07, 0xC1, 0x7C, 0xE6, 0x03, 0x67, 0xDD, 0x75,
+ 0xFE, 0xDD, 0x74, 0xFF, 0xED, 0x5B, 0x97, 0x0A, 0x23, 0x23,
+ 0x23, 0xB7, 0xED, 0x52, 0x20, 0x0C, 0x11, 0x05, 0x00, 0x2A,
+ 0x97, 0x0A, 0xCD, 0x5A, 0x0A, 0xF2, 0xCA, 0x07, 0x2A, 0x95,
+ 0x0A, 0xE5, 0xCD, 0x24, 0x03, 0xC3, 0x75, 0x0A, 0xED, 0x5B,
+ 0x97, 0x0A, 0x2A, 0xC7, 0x0A, 0x19, 0x22, 0xC7, 0x0A, 0x2A,
+ 0xCC, 0x0A, 0x19, 0x22, 0xCC, 0x0A, 0xED, 0x5B, 0xCA, 0x0A,
+ 0x21, 0x9E, 0xFD, 0x19, 0xED, 0x5B, 0xCC, 0x0A, 0xCD, 0x5A,
+ 0x0A, 0xF2, 0xF4, 0x07, 0x21, 0x00, 0x00, 0x22, 0xCC, 0x0A,
+ 0x3E, 0x01, 0x32, 0xC4, 0x0A, 0xCD, 0x04, 0x08, 0x21, 0x00,
+ 0x00, 0x39, 0xF9, 0xC3, 0x75, 0x0A, 0xCD, 0x69, 0x0A, 0x3A,
+ 0xC4, 0x0A, 0xB7, 0xCA, 0x75, 0x0A, 0xED, 0x5B, 0xC5, 0x0A,
+ 0x2A, 0xCC, 0x0A, 0xCD, 0x5A, 0x0A, 0xF2, 0x2D, 0x08, 0xED,
+ 0x5B, 0xCC, 0x0A, 0x21, 0x62, 0x02, 0x19, 0xED, 0x5B, 0xC5,
+ 0x0A, 0xCD, 0x5A, 0x0A, 0xFA, 0x4D, 0x08, 0xED, 0x5B, 0xC5,
+ 0x0A, 0x2A, 0xCC, 0x0A, 0xB7, 0xED, 0x52, 0x20, 0x07, 0x2A,
+ 0xC7, 0x0A, 0x7D, 0xB4, 0x28, 0x0D, 0xED, 0x5B, 0xCC, 0x0A,
+ 0x2A, 0xC5, 0x0A, 0xCD, 0x5A, 0x0A, 0xF2, 0x60, 0x08, 0xED,
+ 0x5B, 0xCE, 0x0A, 0x2A, 0xCC, 0x0A, 0x19, 0xE5, 0xCD, 0x24,
+ 0x03, 0xAF, 0x32, 0xC4, 0x0A, 0xC3, 0x75, 0x0A, 0xCD, 0x1C,
+ 0x03, 0x21, 0x00, 0x00, 0x39, 0xF9, 0xC3, 0x75, 0x0A, 0xCD,
+ 0x69, 0x0A, 0x3A, 0xC9, 0x0A, 0xB7, 0x28, 0x16, 0xCD, 0x0D,
+ 0x07, 0xED, 0x5B, 0xD0, 0x0A, 0x13, 0x13, 0x13, 0xCD, 0x5A,
+ 0x0A, 0xF2, 0x8A, 0x08, 0x21, 0x01, 0x00, 0xC3, 0x75, 0x0A,
+ 0x21, 0x00, 0x00, 0xC3, 0x75, 0x0A, 0xCD, 0x7D, 0x0A, 0xFC,
+ 0xFF, 0xCD, 0x6B, 0x08, 0x7D, 0xB4, 0xC2, 0x75, 0x0A, 0xED,
+ 0x5B, 0xC7, 0x0A, 0x21, 0x00, 0x00, 0xCD, 0x5A, 0x0A, 0xF2,
+ 0x75, 0x0A, 0xED, 0x5B, 0xCE, 0x0A, 0x2A, 0xC5, 0x0A, 0x19,
+ 0xDD, 0x75, 0xFE, 0xDD, 0x74, 0xFF, 0x23, 0x23, 0x23, 0xE5,
+ 0xCD, 0x45, 0x07, 0xC1, 0x7C, 0xE6, 0x03, 0x67, 0x23, 0x23,
+ 0x23, 0xDD, 0x75, 0xFC, 0xDD, 0x74, 0xFD, 0xE5, 0xDD, 0x6E,
+ 0xFE, 0xDD, 0x66, 0xFF, 0xE5, 0x21, 0xD3, 0x0A, 0xE5, 0xCD,
+ 0x7B, 0x06, 0xC1, 0xC1, 0xDD, 0x6E, 0xFC, 0xDD, 0x66, 0xFD,
+ 0x22, 0xD0, 0x0A, 0x21, 0xD2, 0x0A, 0x36, 0x04, 0x21, 0xD0,
+ 0x0A, 0xE3, 0xCD, 0x92, 0x06, 0xC1, 0x3E, 0x01, 0x32, 0xC9,
+ 0x0A, 0xF3, 0xDD, 0x5E, 0xFC, 0xDD, 0x56, 0xFD, 0x2A, 0xC7,
+ 0x0A, 0xB7, 0xED, 0x52, 0x22, 0xC7, 0x0A, 0xCB, 0x7C, 0x28,
+ 0x11, 0x21, 0x00, 0x00, 0x22, 0xC7, 0x0A, 0x22, 0xCC, 0x0A,
+ 0x22, 0xC5, 0x0A, 0x32, 0xC4, 0x0A, 0x18, 0x25, 0xDD, 0x5E,
+ 0xFC, 0xDD, 0x56, 0xFD, 0x2A, 0xC5, 0x0A, 0x19, 0x22, 0xC5,
+ 0x0A, 0xED, 0x5B, 0xCA, 0x0A, 0x21, 0x9E, 0xFD, 0x19, 0xED,
+ 0x5B, 0xC5, 0x0A, 0xCD, 0x5A, 0x0A, 0xF2, 0x43, 0x09, 0x21,
+ 0x00, 0x00, 0x22, 0xC5, 0x0A, 0xCD, 0x04, 0x08, 0x21, 0x00,
+ 0x00, 0x39, 0xF9, 0xFB, 0xC3, 0x75, 0x0A, 0xCD, 0x69, 0x0A,
+ 0x21, 0x30, 0x0D, 0x7E, 0xB7, 0x28, 0x10, 0xCD, 0x29, 0x07,
+ 0xED, 0x5B, 0x2E, 0x0D, 0x13, 0x13, 0x13, 0xCD, 0x5A, 0x0A,
+ 0xF2, 0x74, 0x09, 0x3A, 0x8D, 0x0F, 0xC6, 0x01, 0x32, 0x8D,
+ 0x0F, 0xC3, 0x75, 0x0A, 0x21, 0x30, 0x0D, 0x7E, 0xFE, 0x01,
+ 0x28, 0x19, 0xFE, 0x03, 0xCA, 0x06, 0x0A, 0xFE, 0x05, 0xCA,
+ 0x14, 0x0A, 0x21, 0x30, 0x0D, 0x36, 0x00, 0x21, 0x2E, 0x0D,
+ 0xE5, 0xCD, 0xCE, 0x06, 0xC3, 0x75, 0x0A, 0x3A, 0x8C, 0x0F,
+ 0xB7, 0x20, 0x48, 0x21, 0x32, 0x0D, 0x7E, 0x32, 0x94, 0x0A,
+ 0xCD, 0x55, 0x07, 0x21, 0x31, 0x0D, 0x7E, 0xE6, 0x7F, 0xB7,
+ 0x20, 0x28, 0x3A, 0x8D, 0x0F, 0xE6, 0x7F, 0x32, 0x8D, 0x0F,
+ 0xB7, 0x20, 0x05, 0xC6, 0x01, 0x32, 0x8D, 0x0F, 0x21, 0x31,
+ 0x0D, 0x7E, 0x6F, 0x17, 0x9F, 0x67, 0xCB, 0x7D, 0x3A, 0x8D,
+ 0x0F, 0x28, 0x05, 0xC6, 0x80, 0x32, 0x8D, 0x0F, 0x21, 0x31,
+ 0x0D, 0x77, 0x21, 0x31, 0x0D, 0x7E, 0x6F, 0x17, 0x9F, 0x67,
+ 0xE5, 0xCD, 0xEC, 0x05, 0xC1, 0x21, 0xD2, 0x0A, 0x36, 0x02,
+ 0x21, 0x02, 0x00, 0x22, 0xD0, 0x0A, 0x3A, 0x99, 0x0A, 0x21,
+ 0xD3, 0x0A, 0x77, 0x3A, 0x93, 0x0A, 0x21, 0xD4, 0x0A, 0x77,
+ 0x21, 0xD0, 0x0A, 0xE5, 0xCD, 0x92, 0x06, 0xC1, 0x18, 0x80,
+ 0x2A, 0x2E, 0x0D, 0xE5, 0x21, 0x31, 0x0D, 0xE5, 0xCD, 0xBE,
+ 0x04, 0xC1, 0x18, 0xEF, 0x21, 0xD2, 0x0A, 0x36, 0x06, 0x21,
+ 0x03, 0x00, 0x22, 0xD0, 0x0A, 0x3A, 0x99, 0x0A, 0x21, 0xD3,
+ 0x0A, 0x77, 0x3A, 0x93, 0x0A, 0x21, 0xD4, 0x0A, 0x77, 0x21,
+ 0xD5, 0x0A, 0x36, 0x05, 0x21, 0xD0, 0x0A, 0xE5, 0xCD, 0x92,
+ 0x06, 0x18, 0xC8, 0xCD, 0x69, 0x0A, 0x21, 0x30, 0x0D, 0x36,
+ 0x00, 0x21, 0x2E, 0x0D, 0xE5, 0xCD, 0xCE, 0x06, 0x21, 0xD0,
+ 0x0A, 0xE3, 0xCD, 0x92, 0x06, 0xC1, 0xCD, 0x4F, 0x09, 0xCD,
+ 0x90, 0x08, 0x18, 0xF8, 0x7C, 0xAA, 0xFA, 0x62, 0x0A, 0xED,
+ 0x52, 0xC9, 0x7C, 0xE6, 0x80, 0xED, 0x52, 0x3C, 0xC9, 0xE1,
+ 0xFD, 0xE5, 0xDD, 0xE5, 0xDD, 0x21, 0x00, 0x00, 0xDD, 0x39,
+ 0xE9, 0xDD, 0xF9, 0xDD, 0xE1, 0xFD, 0xE1, 0xC9, 0xE9, 0xE1,
+ 0xFD, 0xE5, 0xDD, 0xE5, 0xDD, 0x21, 0x00, 0x00, 0xDD, 0x39,
+ 0x5E, 0x23, 0x56, 0x23, 0xEB, 0x39, 0xF9, 0xEB, 0xE9, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+#else
+ 0x3A, 0x03, 0x00, 0x32, 0xDE, 0x09, 0x21, 0xD8, 0x0E, 0x3E,
+ 0x55, 0x77, 0xBE, 0x20, 0x09, 0x3E, 0xAA, 0x77, 0xBE, 0x20,
+ 0x03, 0x23, 0x18, 0xF1, 0x22, 0xDC, 0x09, 0xF9, 0x11, 0xE0,
+ 0x09, 0x21, 0xD8, 0x0E, 0xB7, 0xED, 0x52, 0x4D, 0x44, 0x0B,
+ 0x6B, 0x62, 0x13, 0x36, 0x00, 0xED, 0xB0, 0x3E, 0x10, 0xED,
+ 0x39, 0x33, 0x3E, 0x00, 0xED, 0x39, 0x32, 0xED, 0x39, 0x36,
+ 0x3E, 0x0C, 0xED, 0x39, 0x31, 0x3E, 0xC3, 0x21, 0xE5, 0x01,
+ 0x32, 0x38, 0x00, 0x22, 0x39, 0x00, 0xED, 0x56, 0xCD, 0xDC,
+ 0x01, 0xFB, 0xCD, 0x00, 0x09, 0x18, 0xA9, 0x43, 0x6F, 0x70,
+ 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x43, 0x29,
+ 0x20, 0x31, 0x39, 0x38, 0x37, 0x20, 0x2D, 0x20, 0x54, 0x61,
+ 0x6E, 0x67, 0x65, 0x6E, 0x74, 0x20, 0x54, 0x65, 0x63, 0x68,
+ 0x6E, 0x6F, 0x6C, 0x6F, 0x67, 0x69, 0x65, 0x73, 0x20, 0x20,
+ 0x20, 0x41, 0x6C, 0x6C, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74,
+ 0x73, 0x20, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64,
+ 0x2E, 0x20, 0x20, 0x04, 0x04, 0x16, 0x28, 0xFF, 0x3C, 0x04,
+ 0x60, 0x0A, 0xE0, 0x06, 0x00, 0x07, 0x7E, 0x02, 0x40, 0x0B,
+ 0xF6, 0x0C, 0x06, 0x0D, 0x00, 0x0E, 0xC1, 0x0F, 0x00, 0x05,
+ 0x60, 0x03, 0xC0, 0x01, 0x00, 0x09, 0x08, 0x06, 0x1C, 0x21,
+ 0x9F, 0x01, 0x0E, 0x52, 0xED, 0xA3, 0xC2, 0xC2, 0x01, 0x21,
+ 0xE5, 0x01, 0x22, 0x40, 0x00, 0x3A, 0x03, 0x00, 0xE6, 0x01,
+ 0xC0, 0x3E, 0x0B, 0xED, 0x79, 0x3E, 0x76, 0xED, 0x79, 0xC9,
+ 0x21, 0x00, 0x0A, 0x36, 0x84, 0xCD, 0xBB, 0x01, 0xC9, 0xF5,
+ 0xC5, 0xD5, 0xE5, 0x2A, 0xE0, 0x09, 0x0E, 0x53, 0x11, 0x62,
+ 0x02, 0x43, 0x14, 0xED, 0xA2, 0x3A, 0x9E, 0x01, 0x5F, 0xDB,
+ 0x52, 0xE6, 0x01, 0x20, 0x06, 0x1D, 0x20, 0xF7, 0xC3, 0xD4,
+ 0x02, 0x3E, 0x01, 0xD3, 0x52, 0xDB, 0x52, 0x5F, 0xE6, 0xA0,
+ 0x20, 0x0A, 0xED, 0xA2, 0x20, 0xE1, 0x15, 0x20, 0xDE, 0xC3,
+ 0xD2, 0x02, 0xED, 0xA2, 0x7B, 0xE6, 0x60, 0xC2, 0xD8, 0x02,
+ 0x3E, 0x30, 0xD3, 0x52, 0x3E, 0x01, 0xD3, 0x52, 0xAF, 0xD3,
+ 0x52, 0xED, 0x5B, 0xE0, 0x09, 0x2B, 0x37, 0xED, 0x52, 0xDA,
+ 0xD6, 0x02, 0x22, 0xE2, 0x09, 0x62, 0x6B, 0x3A, 0xE4, 0x09,
+ 0xBE, 0x20, 0x56, 0x3E, 0x01, 0x32, 0xE8, 0x09, 0x23, 0x23,
+ 0x3E, 0x84, 0xBE, 0x20, 0x31, 0x36, 0x85, 0x2B, 0x46, 0x3A,
+ 0xE4, 0x09, 0x77, 0x2B, 0x70, 0x11, 0x03, 0x00, 0xCD, 0x56,
+ 0x03, 0x3E, 0x10, 0xD3, 0x52, 0x3E, 0x38, 0xD3, 0x52, 0x3E,
+ 0x03, 0xD3, 0x52, 0x3E, 0xD5, 0xD3, 0x52, 0x2A, 0xE0, 0x09,
+ 0x0E, 0x53, 0x11, 0x62, 0x02, 0x43, 0x14, 0x3A, 0x9D, 0x01,
+ 0x5F, 0xC3, 0xF9, 0x01, 0x3E, 0x81, 0xBE, 0xC2, 0xA6, 0x02,
+ 0x36, 0x82, 0x2B, 0x46, 0x3A, 0xE4, 0x09, 0x77, 0x2B, 0x70,
+ 0x11, 0x03, 0x00, 0xCD, 0x56, 0x03, 0xC3, 0xC1, 0x02, 0x23,
+ 0x23, 0x7E, 0xFE, 0x84, 0xC2, 0xA6, 0x02, 0xCD, 0x05, 0x03,
+ 0x18, 0x14, 0x3E, 0x80, 0xA6, 0xC2, 0xA1, 0x02, 0xDD, 0xE5,
+ 0xDD, 0x21, 0xF9, 0x09, 0xCD, 0x13, 0x06, 0xCD, 0x40, 0x07,
+ 0xDD, 0xE1, 0xE1, 0xD1, 0xC1, 0xF1, 0xFB, 0xED, 0x4D, 0xDD,
+ 0xE5, 0xDD, 0x21, 0xE9, 0x09, 0xCD, 0x13, 0x06, 0xDD, 0xE1,
+ 0xCD, 0x05, 0x03, 0xC3, 0xBA, 0x02, 0x18, 0xED, 0x18, 0xEB,
+ 0x18, 0xE9, 0xE6, 0x40, 0x28, 0x02, 0x18, 0xE3, 0x18, 0xE1,
+ 0xAF, 0x32, 0xFD, 0x09, 0x3E, 0x03, 0xD3, 0x52, 0x3E, 0xC0,
+ 0xD3, 0x52, 0xC9, 0xC5, 0x21, 0x04, 0x00, 0x39, 0x7E, 0x23,
+ 0x66, 0x6F, 0xCD, 0xFB, 0x02, 0xC1, 0xC9, 0x3E, 0x01, 0x32,
+ 0xFD, 0x09, 0x22, 0xE0, 0x09, 0x36, 0x00, 0x3A, 0xFD, 0x09,
+ 0xB7, 0xC8, 0x3E, 0x0E, 0xD3, 0x52, 0x3E, 0xC1, 0xD3, 0x52,
+ 0x3E, 0x0A, 0xD3, 0x52, 0x3E, 0xE0, 0xD3, 0x52, 0x3E, 0x06,
+ 0xD3, 0x52, 0x3A, 0xE4, 0x09, 0xD3, 0x52, 0x3E, 0x10, 0xD3,
+ 0x52, 0x3E, 0x38, 0xD3, 0x52, 0x3E, 0x30, 0xD3, 0x52, 0xDB,
+ 0x52, 0xE6, 0x01, 0x28, 0x04, 0xDB, 0x53, 0x18, 0xF2, 0x3E,
+ 0x0E, 0xD3, 0x52, 0x3E, 0x21, 0xD3, 0x52, 0x3E, 0x03, 0xD3,
+ 0x52, 0x3E, 0xD5, 0xD3, 0x52, 0x3E, 0x01, 0xD3, 0x52, 0x3E,
+ 0x09, 0xD3, 0x52, 0x3E, 0x20, 0xD3, 0x52, 0xC9, 0x0E, 0x53,
+ 0x3E, 0x03, 0xD3, 0x52, 0x3E, 0xC0, 0xD3, 0x52, 0x18, 0x20,
+ 0x0E, 0x53, 0x3E, 0x03, 0xD3, 0x52, 0x3E, 0xC0, 0xD3, 0x52,
+ 0x3E, 0x05, 0xD3, 0x52, 0x3E, 0xE0, 0xD3, 0x52, 0x3E, 0x05,
+ 0xD3, 0x52, 0x3E, 0x60, 0xD3, 0x52, 0x3A, 0x99, 0x01, 0x3D,
+ 0x20, 0xFD, 0x3E, 0x05, 0xD3, 0x52, 0x3E, 0xE0, 0xD3, 0x52,
+ 0x3A, 0x9A, 0x01, 0x3D, 0x20, 0xFD, 0x3E, 0x05, 0xD3, 0x52,
+ 0x3E, 0xE9, 0xD3, 0x52, 0x3E, 0x80, 0xD3, 0x52, 0x3A, 0x9B,
+ 0x01, 0x3D, 0x20, 0xFD, 0xED, 0xA3, 0x1B, 0x3E, 0xC0, 0xD3,
+ 0x52, 0xDB, 0x52, 0xE6, 0x04, 0x28, 0xFA, 0xED, 0xA3, 0x1B,
+ 0x7A, 0xB3, 0x20, 0xF3, 0xDB, 0x52, 0xE6, 0x04, 0x28, 0xFA,
+ 0x3A, 0x9D, 0x01, 0x47, 0xDB, 0x52, 0xE6, 0x04, 0x28, 0x03,
+ 0x05, 0x20, 0xF7, 0xDB, 0x52, 0xE6, 0x04, 0x28, 0xFA, 0x3E,
+ 0x05, 0xD3, 0x52, 0x3E, 0xE0, 0xD3, 0x52, 0x3A, 0x9C, 0x01,
+ 0x3D, 0x20, 0xFD, 0x3E, 0x05, 0xD3, 0x52, 0x3E, 0x60, 0xD3,
+ 0x52, 0xC9, 0xE5, 0xD5, 0x23, 0x23, 0x7E, 0xE6, 0x80, 0xC2,
+ 0x6C, 0x04, 0x2B, 0x3A, 0xE4, 0x09, 0x77, 0x2B, 0x46, 0x21,
+ 0xFF, 0x09, 0x77, 0x2B, 0x70, 0x11, 0x03, 0x00, 0xF3, 0x3E,
+ 0x0A, 0xD3, 0x52, 0xDB, 0x52, 0xE6, 0x00, 0xCA, 0x13, 0x04,
+ 0xD1, 0xE1, 0x3E, 0x01, 0x37, 0xFB, 0xC9, 0xCD, 0x62, 0x03,
+ 0x3A, 0xFE, 0x09, 0xFE, 0xFF, 0xCA, 0x5A, 0x04, 0x3E, 0x03,
+ 0xD3, 0x52, 0x3E, 0xC1, 0xD3, 0x52, 0x3A, 0x9D, 0x01, 0x47,
+ 0xDB, 0x52, 0xE6, 0x01, 0x20, 0x06, 0x05, 0x20, 0xF7, 0xC3,
+ 0x88, 0x04, 0xDB, 0x53, 0x47, 0x3A, 0xE4, 0x09, 0xB8, 0xC2,
+ 0x88, 0x04, 0xDB, 0x52, 0xE6, 0x01, 0x28, 0xFA, 0xDB, 0x53,
+ 0xDB, 0x52, 0xE6, 0x01, 0x28, 0xFA, 0xDB, 0x53, 0xFE, 0x85,
+ 0xC2, 0x88, 0x04, 0x3A, 0x9E, 0x01, 0x18, 0x04, 0x3A, 0x9E,
+ 0x01, 0x87, 0x3D, 0x20, 0xFD, 0xD1, 0xE1, 0xCD, 0x56, 0x03,
+ 0xCD, 0x05, 0x03, 0xB7, 0xFB, 0xC9, 0xD1, 0xE1, 0xF3, 0x3E,
+ 0x0A, 0xD3, 0x52, 0xDB, 0x52, 0xE6, 0xC0, 0xCA, 0x7F, 0x04,
+ 0x3E, 0x01, 0x37, 0xFB, 0xC9, 0xCD, 0x62, 0x03, 0xCD, 0x05,
+ 0x03, 0xB7, 0xFB, 0xC9, 0xD1, 0xE1, 0x3E, 0x02, 0x37, 0xFB,
+ 0xC9, 0x06, 0x08, 0x0E, 0x00, 0x1F, 0x30, 0x01, 0x0C, 0x10,
+ 0xFA, 0x79, 0xC9, 0x21, 0x04, 0x00, 0x39, 0x5E, 0x23, 0x56,
+ 0x21, 0x02, 0x00, 0x39, 0x7E, 0x23, 0x66, 0x6F, 0xDD, 0xE5,
+ 0x22, 0x0B, 0x0A, 0xED, 0x53, 0x0D, 0x0A, 0xDD, 0x21, 0xF5,
+ 0x09, 0xCD, 0x13, 0x06, 0x3A, 0x03, 0x0A, 0x32, 0x04, 0x0A,
+ 0x3A, 0x02, 0x0A, 0x87, 0x32, 0x02, 0x0A, 0xCD, 0x8F, 0x04,
+ 0xFE, 0x03, 0x38, 0x10, 0x3A, 0x03, 0x0A, 0x87, 0x3C, 0xE6,
+ 0x0F, 0x32, 0x03, 0x0A, 0xAF, 0x32, 0x02, 0x0A, 0x18, 0x17,
+ 0x3A, 0x01, 0x0A, 0xCD, 0x8F, 0x04, 0xFE, 0x03, 0x30, 0x0D,
+ 0x3A, 0x03, 0x0A, 0xCB, 0x3F, 0x32, 0x03, 0x0A, 0x3E, 0xFF,
+ 0x32, 0x01, 0x0A, 0x3A, 0x03, 0x0A, 0x32, 0x04, 0x0A, 0x3A,
+ 0x01, 0x0A, 0x87, 0x32, 0x01, 0x0A, 0x3E, 0x20, 0x32, 0x05,
+ 0x0A, 0x32, 0x06, 0x0A, 0x06, 0x28, 0xDB, 0x52, 0xE6, 0x10,
+ 0x28, 0xF8, 0x05, 0x20, 0xF7, 0xF3, 0x3E, 0x0E, 0xD3, 0x52,
+ 0x3E, 0x41, 0xD3, 0x52, 0xFB, 0xED, 0x5F, 0x47, 0x3A, 0x04,
+ 0x0A, 0xA0, 0xE6, 0x0F, 0x28, 0x0F, 0x47, 0x0E, 0x0A, 0xDB,
+ 0x52, 0xE6, 0x10, 0xCA, 0x52, 0x05, 0x0D, 0x20, 0xF6, 0x10,
+ 0xF2, 0x2A, 0x0B, 0x0A, 0xED, 0x5B, 0x0D, 0x0A, 0xCD, 0xE6,
+ 0x03, 0x30, 0x07, 0x3D, 0xCA, 0x52, 0x05, 0xC3, 0x7B, 0x05,
+ 0xDD, 0xE1, 0x21, 0x00, 0x00, 0xC9, 0xDD, 0x21, 0xED, 0x09,
+ 0xCD, 0x13, 0x06, 0x3A, 0x06, 0x0A, 0x3D, 0x32, 0x06, 0x0A,
+ 0x28, 0x13, 0x3A, 0x04, 0x0A, 0xF6, 0x01, 0x32, 0x04, 0x0A,
+ 0x3A, 0x01, 0x0A, 0xF6, 0x01, 0x32, 0x01, 0x0A, 0xC3, 0x0A,
+ 0x05, 0xDD, 0xE1, 0x21, 0x01, 0x00, 0xC9, 0xDD, 0x21, 0xF1,
+ 0x09, 0xCD, 0x13, 0x06, 0x3A, 0x02, 0x0A, 0xF6, 0x01, 0x32,
+ 0x02, 0x0A, 0x3A, 0x04, 0x0A, 0x87, 0xF6, 0x01, 0x32, 0x04,
+ 0x0A, 0x3A, 0x05, 0x0A, 0x3D, 0x32, 0x05, 0x0A, 0xC2, 0x0A,
+ 0x05, 0xDD, 0xE1, 0x21, 0x02, 0x00, 0xC9, 0xDD, 0xE5, 0x21,
+ 0x00, 0x00, 0x39, 0x11, 0x04, 0x00, 0x19, 0x7E, 0x32, 0xE4,
+ 0x09, 0xE6, 0x80, 0x32, 0x07, 0x0A, 0x3A, 0x07, 0x0A, 0xB7,
+ 0x28, 0x06, 0xDD, 0x21, 0x58, 0x02, 0x18, 0x04, 0xDD, 0x21,
+ 0x96, 0x00, 0x3A, 0xE4, 0x09, 0xB7, 0x28, 0x31, 0x3C, 0x28,
+ 0x2E, 0x3D, 0x21, 0x08, 0x0A, 0x77, 0x23, 0x77, 0x23, 0x36,
+ 0x81, 0xAF, 0x32, 0xE8, 0x09, 0xDD, 0x2B, 0xDD, 0xE5, 0xE1,
+ 0x7C, 0xB5, 0x28, 0x2A, 0x21, 0x08, 0x0A, 0x11, 0x03, 0x00,
+ 0xCD, 0xAA, 0x04, 0x11, 0xE8, 0x03, 0x1B, 0x7B, 0xB2, 0x20,
+ 0xFB, 0x3A, 0xE8, 0x09, 0xB7, 0x28, 0xE0, 0x3A, 0xE4, 0x09,
+ 0x47, 0x3E, 0x07, 0x80, 0xE6, 0x7F, 0x47, 0x3A, 0x07, 0x0A,
+ 0xB0, 0x32, 0xE4, 0x09, 0x18, 0xA6, 0xDD, 0xE1, 0xC9, 0xB7,
+ 0xDD, 0x34, 0x00, 0xC0, 0xDD, 0x34, 0x01, 0xC0, 0xDD, 0x34,
+ 0x02, 0xC0, 0xDD, 0x34, 0x03, 0xC0, 0x37, 0xC9, 0x21, 0x02,
+ 0x00, 0x39, 0x5E, 0x23, 0x56, 0x23, 0x4E, 0x23, 0x46, 0x23,
+ 0x7E, 0x23, 0x66, 0x69, 0x4F, 0x78, 0x44, 0x67, 0xED, 0xB0,
+ 0xC9, 0x21, 0x02, 0x00, 0x39, 0x7E, 0x23, 0x66, 0x6F, 0x3E,
+ 0x11, 0xED, 0x39, 0x30, 0x7D, 0xED, 0x39, 0x28, 0x7C, 0xED,
+ 0x39, 0x29, 0x3E, 0x00, 0xED, 0x39, 0x2A, 0x3E, 0x40, 0xED,
+ 0x39, 0x2B, 0x3E, 0x00, 0xED, 0x39, 0x2C, 0x21, 0x80, 0x02,
+ 0x7D, 0xED, 0x39, 0x2E, 0x7C, 0xED, 0x39, 0x2F, 0x3E, 0x91,
+ 0xED, 0x39, 0x30, 0xD3, 0x44, 0x3A, 0xDF, 0x09, 0xB7, 0x28,
+ 0x02, 0xD3, 0x42, 0xC9, 0x21, 0x02, 0x00, 0x39, 0x7E, 0x23,
+ 0x66, 0x6F, 0x3E, 0x21, 0xED, 0x39, 0x30, 0x3E, 0x40, 0xED,
+ 0x39, 0x20, 0x3E, 0x00, 0xED, 0x39, 0x21, 0xED, 0x39, 0x22,
+ 0x7D, 0xED, 0x39, 0x23, 0x7C, 0xED, 0x39, 0x24, 0x3E, 0x00,
+ 0xED, 0x39, 0x25, 0x21, 0x80, 0x02, 0x7D, 0xED, 0x39, 0x26,
+ 0x7C, 0xED, 0x39, 0x27, 0x3E, 0x61, 0xED, 0x39, 0x30, 0xD3,
+ 0x43, 0x3A, 0xDF, 0x09, 0xB7, 0x28, 0x02, 0xD3, 0x42, 0xC9,
+ 0xED, 0x38, 0x2E, 0x5F, 0xED, 0x38, 0x2F, 0x57, 0xED, 0x38,
+ 0x2E, 0x6F, 0xED, 0x38, 0x2F, 0x67, 0xB7, 0xED, 0x52, 0x20,
+ 0xEB, 0x21, 0x80, 0x02, 0xB7, 0xED, 0x52, 0xC9, 0xED, 0x38,
+ 0x26, 0x5F, 0xED, 0x38, 0x27, 0x57, 0xED, 0x38, 0x26, 0x6F,
+ 0xED, 0x38, 0x27, 0x67, 0xB7, 0xED, 0x52, 0x20, 0xEB, 0x21,
+ 0x80, 0x02, 0xB7, 0xED, 0x52, 0xC9, 0xCD, 0xB4, 0x09, 0xDD,
+ 0x6E, 0x06, 0xDD, 0x66, 0x07, 0x7E, 0x23, 0x6E, 0x67, 0xC3,
+ 0xC0, 0x09, 0xCD, 0xB4, 0x09, 0x21, 0x00, 0x00, 0x22, 0x17,
+ 0x0A, 0x22, 0x10, 0x0A, 0x22, 0x12, 0x0A, 0x21, 0xD8, 0x0E,
+ 0x22, 0x19, 0x0A, 0xED, 0x5B, 0x19, 0x0A, 0x2A, 0xDC, 0x09,
+ 0xB7, 0xED, 0x52, 0x11, 0x00, 0xFF, 0x19, 0x22, 0x15, 0x0A,
+ 0xCB, 0x7C, 0x28, 0x06, 0x21, 0x00, 0x7D, 0x22, 0x15, 0x0A,
+ 0x2A, 0x19, 0x0A, 0xE5, 0xCD, 0xED, 0x02, 0xC3, 0xC0, 0x09,
+ 0xCD, 0xB4, 0x09, 0xE5, 0x2A, 0xE0, 0x09, 0x23, 0x23, 0x23,
+ 0xE5, 0xCD, 0xF6, 0x06, 0xC1, 0x7C, 0xE6, 0x03, 0x67, 0xDD,
+ 0x75, 0xFE, 0xDD, 0x74, 0xFF, 0xED, 0x5B, 0xE2, 0x09, 0x23,
+ 0x23, 0x23, 0xB7, 0xED, 0x52, 0x20, 0x0C, 0x11, 0x05, 0x00,
+ 0x2A, 0xE2, 0x09, 0xCD, 0xA5, 0x09, 0xF2, 0x7B, 0x07, 0x2A,
+ 0xE0, 0x09, 0xE5, 0xCD, 0xED, 0x02, 0xC3, 0xC0, 0x09, 0xED,
+ 0x5B, 0xE2, 0x09, 0x2A, 0x12, 0x0A, 0x19, 0x22, 0x12, 0x0A,
+ 0x2A, 0x17, 0x0A, 0x19, 0x22, 0x17, 0x0A, 0xED, 0x5B, 0x15,
+ 0x0A, 0x21, 0x9E, 0xFD, 0x19, 0xED, 0x5B, 0x17, 0x0A, 0xCD,
+ 0xA5, 0x09, 0xF2, 0xA5, 0x07, 0x21, 0x00, 0x00, 0x22, 0x17,
+ 0x0A, 0x3E, 0x01, 0x32, 0x0F, 0x0A, 0xCD, 0xB5, 0x07, 0x21,
+ 0x00, 0x00, 0x39, 0xF9, 0xC3, 0xC0, 0x09, 0xCD, 0xB4, 0x09,
+ 0x3A, 0x0F, 0x0A, 0xB7, 0xCA, 0xC0, 0x09, 0xED, 0x5B, 0x10,
+ 0x0A, 0x2A, 0x17, 0x0A, 0xCD, 0xA5, 0x09, 0xF2, 0xDE, 0x07,
+ 0xED, 0x5B, 0x17, 0x0A, 0x21, 0x62, 0x02, 0x19, 0xED, 0x5B,
+ 0x10, 0x0A, 0xCD, 0xA5, 0x09, 0xFA, 0xFE, 0x07, 0xED, 0x5B,
+ 0x10, 0x0A, 0x2A, 0x17, 0x0A, 0xB7, 0xED, 0x52, 0x20, 0x07,
+ 0x2A, 0x12, 0x0A, 0x7D, 0xB4, 0x28, 0x0D, 0xED, 0x5B, 0x17,
+ 0x0A, 0x2A, 0x10, 0x0A, 0xCD, 0xA5, 0x09, 0xF2, 0x11, 0x08,
+ 0xED, 0x5B, 0x19, 0x0A, 0x2A, 0x17, 0x0A, 0x19, 0xE5, 0xCD,
+ 0xED, 0x02, 0xAF, 0x32, 0x0F, 0x0A, 0xC3, 0xC0, 0x09, 0xCD,
+ 0xE0, 0x02, 0x21, 0x00, 0x00, 0x39, 0xF9, 0xC3, 0xC0, 0x09,
+ 0xCD, 0xB4, 0x09, 0x3A, 0x14, 0x0A, 0xB7, 0x28, 0x16, 0xCD,
+ 0xBE, 0x06, 0xED, 0x5B, 0x1B, 0x0A, 0x13, 0x13, 0x13, 0xCD,
+ 0xA5, 0x09, 0xF2, 0x3B, 0x08, 0x21, 0x01, 0x00, 0xC3, 0xC0,
+ 0x09, 0x21, 0x00, 0x00, 0xC3, 0xC0, 0x09, 0xCD, 0xC8, 0x09,
+ 0xFC, 0xFF, 0xCD, 0x1C, 0x08, 0x7D, 0xB4, 0xC2, 0xC0, 0x09,
+ 0xED, 0x5B, 0x12, 0x0A, 0x21, 0x00, 0x00, 0xCD, 0xA5, 0x09,
+ 0xF2, 0xC0, 0x09, 0xED, 0x5B, 0x19, 0x0A, 0x2A, 0x10, 0x0A,
+ 0x19, 0xDD, 0x75, 0xFE, 0xDD, 0x74, 0xFF, 0x23, 0x23, 0x23,
+ 0xE5, 0xCD, 0xF6, 0x06, 0xC1, 0x7C, 0xE6, 0x03, 0x67, 0x23,
+ 0x23, 0x23, 0xDD, 0x75, 0xFC, 0xDD, 0x74, 0xFD, 0xE5, 0xDD,
+ 0x6E, 0xFE, 0xDD, 0x66, 0xFF, 0xE5, 0x21, 0x1E, 0x0A, 0xE5,
+ 0xCD, 0x26, 0x06, 0xC1, 0xC1, 0xDD, 0x6E, 0xFC, 0xDD, 0x66,
+ 0xFD, 0x22, 0x1B, 0x0A, 0x21, 0x1D, 0x0A, 0x36, 0x04, 0x21,
+ 0x1B, 0x0A, 0xE3, 0xCD, 0x3D, 0x06, 0xC1, 0x3E, 0x01, 0x32,
+ 0x14, 0x0A, 0xF3, 0xDD, 0x5E, 0xFC, 0xDD, 0x56, 0xFD, 0x2A,
+ 0x12, 0x0A, 0xB7, 0xED, 0x52, 0x22, 0x12, 0x0A, 0xCB, 0x7C,
+ 0x28, 0x11, 0x21, 0x00, 0x00, 0x22, 0x12, 0x0A, 0x22, 0x17,
+ 0x0A, 0x22, 0x10, 0x0A, 0x32, 0x0F, 0x0A, 0x18, 0x25, 0xDD,
+ 0x5E, 0xFC, 0xDD, 0x56, 0xFD, 0x2A, 0x10, 0x0A, 0x19, 0x22,
+ 0x10, 0x0A, 0xED, 0x5B, 0x15, 0x0A, 0x21, 0x9E, 0xFD, 0x19,
+ 0xED, 0x5B, 0x10, 0x0A, 0xCD, 0xA5, 0x09, 0xF2, 0xF4, 0x08,
+ 0x21, 0x00, 0x00, 0x22, 0x10, 0x0A, 0xCD, 0xB5, 0x07, 0x21,
+ 0x00, 0x00, 0x39, 0xF9, 0xFB, 0xC3, 0xC0, 0x09, 0xCD, 0xB4,
+ 0x09, 0x21, 0x7B, 0x0C, 0x36, 0x00, 0x21, 0x79, 0x0C, 0xE5,
+ 0xCD, 0x7C, 0x06, 0x21, 0x1B, 0x0A, 0xE3, 0xCD, 0x3D, 0x06,
+ 0xC1, 0xCD, 0x1F, 0x09, 0xCD, 0x41, 0x08, 0x18, 0xF8, 0xCD,
+ 0xB4, 0x09, 0x21, 0x7B, 0x0C, 0x7E, 0xB7, 0xCA, 0xC0, 0x09,
+ 0xCD, 0xDA, 0x06, 0xED, 0x5B, 0x79, 0x0C, 0x13, 0x13, 0x13,
+ 0xCD, 0xA5, 0x09, 0xFA, 0xC0, 0x09, 0x21, 0x7B, 0x0C, 0x7E,
+ 0xFE, 0x01, 0x28, 0x15, 0xFE, 0x03, 0x28, 0x51, 0xFE, 0x05,
+ 0x21, 0x7B, 0x0C, 0x36, 0x00, 0x21, 0x79, 0x0C, 0xE5, 0xCD,
+ 0x7C, 0x06, 0xC3, 0xC0, 0x09, 0x3A, 0xD7, 0x0E, 0xB7, 0x20,
+ 0x17, 0x21, 0x7D, 0x0C, 0x7E, 0x32, 0xDF, 0x09, 0xCD, 0x06,
+ 0x07, 0x21, 0x7C, 0x0C, 0x7E, 0x6F, 0x17, 0x9F, 0x67, 0xE5,
+ 0xCD, 0xA3, 0x05, 0xC1, 0x21, 0x1D, 0x0A, 0x36, 0x02, 0x21,
+ 0x02, 0x00, 0x22, 0x1B, 0x0A, 0x3A, 0xE4, 0x09, 0x21, 0x1E,
+ 0x0A, 0x77, 0x3A, 0xDE, 0x09, 0x21, 0x1F, 0x0A, 0x77, 0x21,
+ 0x1B, 0x0A, 0xE5, 0xCD, 0x3D, 0x06, 0xC1, 0x18, 0xB1, 0x2A,
+ 0x79, 0x0C, 0xE5, 0x21, 0x7C, 0x0C, 0xE5, 0xCD, 0x9B, 0x04,
+ 0xC1, 0x18, 0xEF, 0x7C, 0xAA, 0xFA, 0xAD, 0x09, 0xED, 0x52,
+ 0xC9, 0x7C, 0xE6, 0x80, 0xED, 0x52, 0x3C, 0xC9, 0xE1, 0xFD,
+ 0xE5, 0xDD, 0xE5, 0xDD, 0x21, 0x00, 0x00, 0xDD, 0x39, 0xE9,
+ 0xDD, 0xF9, 0xDD, 0xE1, 0xFD, 0xE1, 0xC9, 0xE9, 0xE1, 0xFD,
+ 0xE5, 0xDD, 0xE5, 0xDD, 0x21, 0x00, 0x00, 0xDD, 0x39, 0x5E,
+ 0x23, 0x56, 0x23, 0xEB, 0x39, 0xF9, 0xEB, 0xE9, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+#endif
+};
+
+
+BOOLEAN
+LtFirmInitialize(
+ IN PLT_ADAPTER Adapter,
+ IN UCHAR SuggestedNodeId
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the card, downloads the firmware to it.
+
+Arguments:
+
+ Adapter : Pointer to the adapter structure.
+
+Return Value:
+
+ TRUE : If successful, false otherwise
+
+--*/
+{
+ PUCHAR Firmware;
+ UINT FirmwareLen;
+ UINT RetryCount;
+ UCHAR Data;
+ BOOLEAN Result = FALSE;
+
+ // Clear the request Latch
+ NdisRawReadPortUchar(XFER_PORT, &Data);
+
+ // Clear the TX_READY FLOP
+ NdisRawWritePortUchar(XFER_PORT, (UCHAR)0);
+
+ // Reset the card.
+ NdisRawWritePortUchar(RESET_PORT, (UCHAR)0);
+
+ NdisStallExecution(LT_FIRM_INIT_STALL_TIME*5);
+
+ for (RetryCount = 0; RetryCount < MAX_READ_RETRY_COUNT; RetryCount++)
+ {
+ // Get Card Status.
+ NdisRawReadPortUchar(SC_PORT, &Data);
+
+ if (Data & TX_READY)
+ {
+ break;
+ }
+ else DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("LtFirmInitialize: Waiting for card ready SC_PORT %x\n", Data));
+
+ NdisStallExecution(LT_FIRM_INIT_STALL_TIME);
+ }
+
+ // BUGBUG:
+ // !!!!!!
+ // For DAYNA, it will not be ready at this point. DCH is going to
+ // send information to fix this.
+
+ do
+ {
+ if (RetryCount == MAX_READ_RETRY_COUNT)
+ {
+ LOGERROR(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE);
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_FATAL,
+ ("LtFirmInitialize: Card Not Ready after Reset\n"));
+ break;
+ }
+
+ // Copy the firmware to the card.
+ Firmware = LtMicroCode;
+ FirmwareLen = sizeof(LtMicroCode);
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
+ ("LtFirmInitialize: DownLoad %d bytes of firmware\n", FirmwareLen));
+
+ // Well... the card is alive and well and in a reset state.
+ // Next we need to output the first byte of the firmware and
+ // check for TX_READY.
+ NdisRawWritePortUchar(XFER_PORT, *Firmware);
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
+ ("LtFirmInitialize: First byte of Firmware on card\n"));
+
+ NdisRawReadPortUchar(SC_PORT, &Data);
+
+ if (Data & TX_READY)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_FATAL,
+ ("LtFirmInitialize: Card Not Ready During Download\n"));
+
+ LOGERROR(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE);
+ break;
+ }
+
+ // Skip over the first byte because it already out there.
+ Firmware ++;
+ FirmwareLen --;
+
+ NdisRawWritePortBufferUchar(XFER_PORT,
+ Firmware,
+ FirmwareLen);
+
+ // Tell the card to start
+ NdisRawReadPortUchar(XFER_PORT, &Data);
+
+ // Wait for the card to start
+ for (RetryCount = 0; RetryCount < MAX_START_RETRY_COUNT; RetryCount++)
+ {
+ NdisStallExecution(LT_FIRM_INIT_STALL_TIME);
+
+ // Get Status
+ NdisRawReadPortUchar(SC_PORT, &Data);
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("LtFirmInitialize: Waiting for start - SC_PORT Data %x\n",
+ (UCHAR)Data));
+
+ if (Data & RX_READY)
+ {
+ break;
+ }
+ }
+
+ // !!! This seems to be the only way the MCA card works according to
+ // !!! Dave Hornbaker. It seems that the MCA card doesnt get ready at
+ // !!! this point, but works later on.
+ if (RetryCount == MAX_START_RETRY_COUNT)
+ {
+ ASSERT(Adapter->BusType != NdisInterfaceMca);
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_FATAL,
+ ("LtFirmInitialize: Card Not Ready, could not get status\n"));
+
+ LOGERROR(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_INVALID_VALUE_FROM_ADAPTER);
+ break;
+ }
+
+ // Clear the initial ready signal.
+ NdisRawReadPortUchar(XFER_PORT, &Data);
+
+ // Now loop here for a finite time till the card acquires a node id.
+ // If it fails to do so in the specified time, fail the load.
+ if (!LtInitGetAddressSetPoll(Adapter, SuggestedNodeId))
+ {
+ break;
+ }
+
+ // We need to catch the card fast after it acquire the node id and before it
+ // receives any packets. If it does receive any packets, then ask it acquire
+ // the node id again. The stall happens ONLY IF A PACKET IS RECVD.
+ for (RetryCount = 0; RetryCount < MAX_START_RETRY_COUNT*200; RetryCount++)
+ {
+ USHORT ResponseLength;
+ UCHAR ResponseType;
+ LT_INIT_RESPONSE InitPacket;
+
+ // Check for receive data
+ NdisRawReadPortUchar(SC_PORT, &Data);
+
+ if (Data & RX_READY)
+ {
+ // Get the length of the response on the card
+ NdisRawReadPortUchar(XFER_PORT, &Data);
+
+ ResponseLength = (USHORT)(Data & 0xFF);
+
+ NdisRawReadPortUchar(XFER_PORT, &Data);
+
+ ResponseLength |= (Data << 8);
+
+ // Now get the IO code.
+ NdisRawReadPortUchar(XFER_PORT, &ResponseType);
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
+ ("LtFirmInitialize: RespType = %x, RespLength = %d\n",
+ ResponseType, ResponseLength));
+
+ if ((ResponseType == LT_RSP_LAP_INIT) &&
+ (ResponseLength == sizeof(LT_INIT_RESPONSE)))
+ {
+ NdisRawReadPortBufferUchar(XFER_PORT,
+ (PUCHAR)&InitPacket,
+ ResponseLength);
+
+ Adapter->NodeId = InitPacket.NodeId;
+ Adapter->Flags |= ADAPTER_NODE_ID_VALID;
+
+ // This should start off a worker thread to write the
+ // node id into the pram.
+ // BUGBUG: Implement using worker threads.
+ // LtRegWritePramNodeId(Adapter);
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
+ ("LtFirmInitailize: Node id acquired %x\n", InitPacket.NodeId));
+ break;
+ }
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("LtFirmInitailize: Node id not valid yet !!\n"));
+
+ // Suck in the packet and throw it away
+ while (ResponseLength-- > 0)
+ {
+ NdisRawReadPortUchar(XFER_PORT, &Data);
+ }
+
+ // The response was probably over-written by incoming packet.
+ // Try again.
+ NdisStallExecution(LT_FIRM_INIT_STALL_TIME);
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("LtFirmInitailize: Re-acquire node after packet recv\n"));
+ if (!LtInitGetAddressSetPoll(Adapter, SuggestedNodeId))
+ {
+ break;
+ }
+ }
+ else
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("LtFirmInitialize: Waiting for node - SC_PORT Data %x\n",
+ (UCHAR)Data));
+ }
+ NdisStallExecution(500); // 500us
+ }
+ Result = ((Adapter->Flags & ADAPTER_NODE_ID_VALID) != 0);
+ } while (FALSE);
+
+ return(Result);
+}
+
diff --git a/private/ntos/ndis/lt200/ltfirm.h b/private/ntos/ndis/lt200/ltfirm.h
new file mode 100644
index 000000000..5ddae948d
--- /dev/null
+++ b/private/ntos/ndis/lt200/ltfirm.h
@@ -0,0 +1,42 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ltfirm.h
+
+Abstract:
+
+ This module contains the firmware init definitions.
+
+Author:
+
+ Stephen Hou (stephh@microsoft.com)
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+
+Revision History:
+ 19 Jun 1992 Initial Version (dch@pacvax.pacersoft.com)
+
+Notes: Tab stop: 4
+--*/
+
+#ifndef _LTFIRM_H_
+#define _LTFIRM_H_
+
+BOOLEAN
+LtFirmInitialize(
+ IN PLT_ADAPTER Adapter,
+ IN UCHAR SuggestedNodeId);
+
+#ifdef LTFIRM_H_LOCALS
+#define MAX_READ_RETRY_COUNT 500
+#define MAX_START_RETRY_COUNT 500
+
+#define LT_FIRM_INIT_STALL_TIME 10000 // 10ms
+
+#endif // LTFIRM_H_LOCALS
+
+
+#endif // _LTFIRM_H_
+
diff --git a/private/ntos/ndis/lt200/ltglobal.h b/private/ntos/ndis/lt200/ltglobal.h
new file mode 100644
index 000000000..c8e523e54
--- /dev/null
+++ b/private/ntos/ndis/lt200/ltglobal.h
@@ -0,0 +1,48 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ltglobal.h
+
+Abstract:
+
+ This module contains the globals the driver uses.
+
+Author:
+
+ Stephen Hou (stephh@microsoft.com)
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+
+Revision History:
+ 19 Jun 1992 Initial Version (dch@pacvax.pacersoft.com)
+
+Notes: Tab stop: 4
+--*/
+
+#ifndef _LTGLOBAL_
+#define _LTGLOBAL_
+
+#ifdef _GLOBALS_
+ #define GLOBAL
+ #define EQU =
+#else
+ #define GLOBAL extern
+ #define EQU ; / ## /
+#endif
+
+// This variable is used to control debug output.
+#if DBG
+GLOBAL ULONG LtDebugLevel EQU DBG_LEVEL_ERR;
+GLOBAL ULONG LtDebugSystems EQU DBG_COMP_ALL;
+#endif
+
+GLOBAL NDIS_HANDLE LtMacHandle EQU (NDIS_HANDLE)NULL;
+GLOBAL NDIS_HANDLE LtNdisWrapperHandle EQU (NDIS_HANDLE)NULL;
+
+// To indicate there is no restriction on the highest physical address for
+// NdisAllocateMemory calls.
+GLOBAL NDIS_PHYSICAL_ADDRESS LtNdisPhyAddr EQU NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
+
+#endif // _LTGLOBAL_
diff --git a/private/ntos/ndis/lt200/lthrd.h b/private/ntos/ndis/lt200/lthrd.h
new file mode 100644
index 000000000..dc5378f89
--- /dev/null
+++ b/private/ntos/ndis/lt200/lthrd.h
@@ -0,0 +1,85 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ lthrd.h
+
+Abstract:
+
+ This module contains the hardware specific defines.
+
+Author:
+
+ Stephen Hou (stephh@microsoft.com)
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+
+Revision History:
+ 19 Jun 1992 Initial Version (dch@pacvax.pacersoft.com)
+
+Notes: Tab stop: 4
+--*/
+
+#ifndef _LTHRD_
+#define _LTHRD_
+
+
+#define LT_DEFAULT_SLOT_NUMBER 1
+#define LT_DEFAULT_BUS_NUMBER 0
+#define LT_DEFAULT_RECEIVE_BUFFERS 3
+#define LT_DEFAULT_IO_BASE_ADDRESS 0x340
+#define LT_MAX_ADAPTERS 8
+#define LT_NUMBER_OF_PORTS 4
+#define LT_MAXIMUM_PACKET_SIZE 603
+
+#define LT_MINIMUM_PACKET_SIZE 3
+#define LT_LENGTH_OF_ADDRESS 1
+
+#define LT_ADAPTER_POLLED_MODE 0xFF // Adapter in polling mode
+
+// LT command/response codes.
+
+#define LT_CMD_LAP_INIT 1 // initialize command.
+#define LT_RSP_LAP_INIT 2 // Initialize response.
+#define LT_CMD_LAP_WRITE 3 // Transmit a lap frame.
+#define LT_RSP_LAP_FRAME 4 // Received lap frameresponse.
+#define LT_CMD_GET_STATUS 5 // Get LAP hardware status command.
+#define LT_RSP_STATUS 6 // LAP Hardware status response.
+
+typedef struct _LT_STATUS_RESPONSE {
+
+ UCHAR NodeId; // Adapters LocalTalk Address.
+ UCHAR RomVer; // Version of LT ROM.
+ UCHAR SwVer; // Version of downloaded Firmware
+
+} LT_STATUS_RESPONSE, *PLT_STATUS_RESPONSE;
+
+typedef struct _LT_INIT_RESPONSE {
+ UCHAR NodeId;
+ UCHAR RomVer;
+} LT_INIT_RESPONSE, *PLT_INIT_RESPONSE;
+
+// Definition for the LT Transfer Control Status Register.
+#define TX_READY 1
+#define RX_READY 2
+
+// I/O Port Address Mapping Definitions
+#define XFER_PORT Adapter->MappedIoBaseAddr+0 // (Adapter->LtPortAddress)
+#define SC_PORT Adapter->MappedIoBaseAddr+1 // (Adapter->LtPortAddress+1)
+#define RESET_PORT Adapter->MappedIoBaseAddr+3 // (Adapter->LtPortAddress+3)
+
+typedef struct _LT_CARD_IO {
+ USHORT IoLen; // Length of io_data
+ UCHAR IoCode; // Command response
+ UCHAR IoData[1]; // Command response Data.
+} LtCardIo, *PLtCardIo;
+
+#ifdef LTHRD_LOCALS
+
+#endif // LTHRD_LOCALS
+
+
+#endif // _LTHRD_
+
+
diff --git a/private/ntos/ndis/lt200/ltinit.c b/private/ntos/ndis/lt200/ltinit.c
new file mode 100644
index 000000000..69cdc1ba4
--- /dev/null
+++ b/private/ntos/ndis/lt200/ltinit.c
@@ -0,0 +1,738 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ltinit.c
+
+Abstract:
+
+ This module contains the main processing routines.
+
+Author:
+
+ Stephen Hou (stephh@microsoft.com)
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+
+Revision History:
+ 19 Jun 1992 Initial Version (dch@pacvax.pacersoft.com)
+
+Notes: Tab stop: 4
+--*/
+
+#define _GLOBALS_
+#include "ltmain.h"
+#include "ltreg.h"
+#include "ltreq.h"
+#include "ltfirm.h"
+#include "lttimer.h"
+#include "ltreset.h"
+
+// Define file id for errorlogging
+#define FILENUM LTINIT
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+/*++
+
+Routine Description:
+
+ This is the entry routine for the localtalk driver.
+
+Arguments:
+
+ DriverObject: The IO driver object for this driver object.
+ RegistryPath: The path to the registry config for this driver.
+
+Return Value:
+
+ STATUS_SUCCESS: If load was successful
+ Error : Otherwise
+
+--*/
+{
+ NDIS_STATUS Status;
+ NDIS_MAC_CHARACTERISTICS LtChar;
+ static const NDIS_STRING MacName = NDIS_STRING_CONST("LT200");
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
+ ("Debugging breakpoint, Hit G <cr> to continue\n"));
+
+ DBGBREAK(DBG_LEVEL_INFO);
+
+ // Initialize the NDIS Wrapper.
+ NdisInitializeWrapper(
+ &LtNdisWrapperHandle,
+ DriverObject,
+ RegistryPath,
+ NULL);
+
+ // Setup the MAC Characteristics
+ LtChar.MajorNdisVersion = NDIS_MAJOR_VERSION;
+ LtChar.MinorNdisVersion = NDIS_MINOR_VERSION;
+ LtChar.OpenAdapterHandler = LtInitOpenAdapter;
+ LtChar.CloseAdapterHandler = LtInitCloseAdapter;
+ LtChar.SendHandler = LtSend;
+ LtChar.RequestHandler = LtRequest;
+ LtChar.TransferDataHandler = LtRecvTransferData;
+ LtChar.ResetHandler = LtReset;
+ LtChar.QueryGlobalStatisticsHandler = LtReqQueryGlobalStatistics;
+ LtChar.UnloadMacHandler = LtInitUnload;
+ LtChar.AddAdapterHandler = LtInitAddAdapter;
+ LtChar.RemoveAdapterHandler = LtInitRemoveAdapter;
+ LtChar.Name = MacName;
+
+ NdisRegisterMac(
+ &Status,
+ &LtMacHandle,
+ LtNdisWrapperHandle,
+ NULL, // Context for AddAdapter/Unload
+ &LtChar,
+ sizeof(LtChar));
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ // Can only get here if something went wrong registering the MAC or
+ // all of the adapters
+ NdisTerminateWrapper(LtNdisWrapperHandle, DriverObject);
+ }
+
+ return Status;
+}
+
+
+
+
+NDIS_STATUS
+LtInitAddAdapter(
+ IN NDIS_HANDLE MacMacContext,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING AdapterName
+ )
+/*++
+
+Routine Description:
+
+ This is called by NDIS when we do a register adapter.
+
+Arguments:
+
+ MacMacContext : Context passed to Add/Unload. NULL in our case.
+ ConfigurationHandle : Handle to configuration info.
+ AdapterName : Name to use to register the adapter.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS : If successful, error otherwise
+
+--*/
+{
+ NDIS_HANDLE ConfigHandle;
+ UCHAR SuggestedNodeId;
+ UINT BusNumber, IoBaseAddress;
+ NDIS_INTERFACE_TYPE BusType;
+ BOOLEAN configHandleOpen = FALSE;
+ NDIS_STATUS Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+
+ if (ConfigurationHandle == NULL)
+ {
+ return(Status);
+ }
+
+
+ do
+ {
+ NdisOpenConfiguration(
+ &Status,
+ &ConfigHandle,
+ ConfigurationHandle);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ configHandleOpen = TRUE;
+
+ // The following functions return the parameter as specified in the
+ // Configuration database or the default. If the database has an
+ // incorrect value, then the default is returned and an Error Event
+ // is logged.
+
+ BusNumber = LtRegGetBusNumber(ConfigHandle);
+
+ Status = LtRegGetBusType(ConfigHandle, &BusType);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ // Get the io base address
+ Status = LtRegGetIoBaseAddr(
+ &IoBaseAddress,
+ ConfigurationHandle,
+ ConfigHandle,
+ BusType);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ // Get default id or pram node id to try.
+ SuggestedNodeId = LtRegGetNodeId(ConfigHandle);
+
+ } while (FALSE);
+
+ // We have to register the adapter to log an error if that happened.
+ Status = LtInitRegisterAdapter(
+ LtMacHandle,
+ ConfigurationHandle,
+ AdapterName,
+ BusType,
+ SuggestedNodeId,
+ IoBaseAddress,
+ LT_MAX_ADAPTERS,
+ Status);
+
+ if (configHandleOpen)
+ {
+ NdisCloseConfiguration(ConfigHandle);
+ }
+
+ return Status;
+}
+
+
+
+
+VOID
+LtInitRemoveAdapter(
+ IN NDIS_HANDLE MacAdapterContext
+ )
+/*++
+
+Routine Description:
+
+ Called to remove an adapter. This is only called after all bindings
+ are closed.
+
+Arguments:
+
+ MacAdapterContext : Context value passed to NdisRegister. Adapter
+
+Return Value:
+
+ None.
+
+--*/
+{
+ BOOLEAN Cancelled, TimerQueued, Closing;
+ PLT_ADAPTER Adapter = (PLT_ADAPTER)MacAdapterContext;
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Closing = ((Adapter->Flags & ADAPTER_CLOSING) != 0);
+
+ Adapter->Flags |= ADAPTER_CLOSING;
+ TimerQueued = ((Adapter->Flags & ADAPTER_TIMER_QUEUED) != 0);
+ Adapter->Flags &= ~ADAPTER_TIMER_QUEUED;
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ if (Closing)
+ {
+ ASSERTMSG("LtInitRemoveAdapter: Removing twice!\n", 0);
+ return;
+ }
+
+ // Acording to Adam, this routine will NEVER be called with
+ // outstanding opens.
+ ASSERTMSG("LtRemoveAdapter: OpenCount is not zero!\n",
+ (Adapter->OpenCount == 0));
+
+ // There are no opens left so remove ourselves.
+ if (TimerQueued)
+ {
+ NdisCancelTimer(&Adapter->PollingTimer, &Cancelled);
+ if (Cancelled)
+ {
+ // Remove the timer reference
+ LtDeReferenceAdapter(Adapter);
+ }
+ }
+
+ ASSERTMSG("LtRemoveAdapter: RefCount not correct!\n", (Adapter->RefCount == 1));
+
+ // Remove the creation reference
+ LtDeReferenceAdapter(Adapter);
+ return;
+}
+
+
+
+
+NDIS_STATUS
+LtInitOpenAdapter(
+ OUT PNDIS_STATUS OperErrorStatus,
+ OUT NDIS_HANDLE *MacBindingHandle,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_HANDLE MacAdapterContext,
+ IN UINT OpenOptions,
+ IN PSTRING AddressingInformation
+ )
+/*++
+
+Routine Description:
+
+ Called by ndis when a protocol attempts to bind to us.
+
+Arguments:
+
+ As described in the NDIS 3.0 Spec.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESSFUL : If ok, error otherwise
+
+--*/
+{
+
+ UINT i;
+ PLT_OPEN NewOpen;
+
+ PLT_ADAPTER Adapter = (PLT_ADAPTER)MacAdapterContext;
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ // if the adapter is being closed, then do not allow the open
+ LtReferenceAdapter(Adapter, &StatusToReturn);
+ if (StatusToReturn != NDIS_STATUS_SUCCESS)
+ {
+ ASSERTMSG("LtInitOpenAdapter: Adapter is closing down!\n", 0);
+ return(StatusToReturn);
+ }
+
+ do
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
+ ("LtInitOpenAdapter Entered:\n"));
+
+ // Search thru the supplied MediumArray for NdisMediumLocalTalk
+ for (i = 0; i < MediumArraySize; i++)
+ {
+ if (MediumArray[i] == NdisMediumLocalTalk)
+ {
+ break;
+ }
+ }
+
+ if (i == MediumArraySize)
+ {
+ StatusToReturn = NDIS_STATUS_UNSUPPORTED_MEDIA;
+ break;
+ }
+
+ *SelectedMediumIndex = i;
+
+ // Allocate some space for the open binding.
+ NdisAllocateMemory(
+ (PVOID)&NewOpen,
+ (UINT)sizeof(LT_OPEN),
+ (UINT)0,
+ LtNdisPhyAddr);
+
+ if (NewOpen == NULL)
+ {
+ StatusToReturn = NDIS_STATUS_RESOURCES;
+
+ // NdisWriteErrorLogEntry();
+ TMPLOGERR();
+ break;
+ }
+
+ NdisZeroMemory(
+ NewOpen,
+ sizeof(LT_OPEN));
+
+ *MacBindingHandle = (NDIS_HANDLE)NewOpen;
+ NewOpen->NdisBindingContext = NdisBindingContext;
+ NewOpen->Flags |= BINDING_OPEN;
+ NewOpen->LtAdapter = Adapter;
+
+ // Set the creation reference
+ NewOpen->RefCount = 1;
+ InitializeListHead(&NewOpen->Linkage);
+
+ // Insert into adapter list and increment adapter open count.
+ NdisAcquireSpinLock(&Adapter->Lock);
+ InsertTailList(&Adapter->OpenBindings, &NewOpen->Linkage);
+ Adapter->OpenCount++;
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ } while (FALSE);
+
+ if (StatusToReturn != NDIS_STATUS_SUCCESS)
+ {
+ LtDeReferenceAdapter(Adapter);
+ }
+
+ return StatusToReturn;
+}
+
+
+
+
+NDIS_STATUS
+LtInitCloseAdapter(
+ IN NDIS_HANDLE MacBindingHandle
+ )
+/*++
+
+Routine Description:
+
+ Called by NDIS to close a binding.
+
+Arguments:
+
+ MacBindingHandle : Context passed back in OpenAdapter.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS : If successful, error otherwise.
+ NDIS_STATUS_PENDING : If pending.
+
+--*/
+{
+
+ PLT_ADAPTER Adapter;
+ PLT_OPEN Open;
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_PENDING;
+ BOOLEAN Closing = FALSE;
+
+ Open = (PLT_OPEN)MacBindingHandle;
+ Adapter = Open->LtAdapter;
+
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ // Do not do any thing if already closing.
+ if (Open->Flags & BINDING_CLOSING)
+ {
+ StatusToReturn = NDIS_STATUS_CLOSING;
+ }
+ else
+ {
+ // This flag prevents further requests on this binding.
+ Open->Flags |= BINDING_CLOSING;
+ Closing = TRUE;
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+
+ if (Closing)
+ {
+ // Remove the creation reference
+ LtDeReferenceBinding(Open);
+ }
+
+ return StatusToReturn;
+}
+
+
+
+
+VOID
+LtInitUnload(
+ IN NDIS_HANDLE MacMacContext
+ )
+/*++
+
+Routine Description:
+
+ Called when the driver is to be unloaded.
+
+Arguments:
+
+ MacMacContext : Context passed to RegisterMac.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ NDIS_STATUS Status;
+ UNREFERENCED_PARAMETER(MacMacContext);
+
+ ASSERT(MacMacContext == (NDIS_HANDLE)NULL);
+
+ NdisDeregisterMac(
+ &Status,
+ LtMacHandle);
+
+ NdisTerminateWrapper(
+ LtNdisWrapperHandle,
+ NULL);
+
+ return;
+}
+
+
+
+
+NDIS_STATUS
+LtInitRegisterAdapter(
+ IN NDIS_HANDLE LtMacHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN PNDIS_STRING AdapterName,
+ IN NDIS_INTERFACE_TYPE BusType,
+ IN UCHAR SuggestedNodeId,
+ IN UINT IoBaseAddress,
+ IN UINT MaxAdapters,
+ IN NDIS_STATUS ConfigError
+ )
+/*++
+
+Routine Description:
+
+ This routine (and its interface) are not portable. They are
+ defined by the OS, the architecture, and the particular Lt
+ implementation.
+
+ This routine is responsible for the allocation of the datastructures
+ for the driver as well as any hardware specific details necessary
+ to talk with the device.
+
+Arguments:
+
+ LtMacHandle : The handle given back to the mac from ndis when
+ the mac registered itself.
+
+ WrapperConfigurationContext
+ : configuration context passed in by NDIS in the AddAdapter
+ call.
+
+ AdapterName : The string containing the name to give to the device adapter.
+ BusType : The type of bus in use. (MCA, ISA, EISA ...)
+ IoBaseAddress : The base IO address of the card.
+ MaxAdapters : The maximum number of opens at any one time.
+ ConfigError : Error with the Config parameters if any.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS : If successful, error otherwise.
+
+--*/
+{
+ // Pointer for the adapter root.
+ PLT_ADAPTER Adapter;
+ NDIS_STATUS Status, RefStatus;
+ NDIS_ERROR_CODE LogErrorCode;
+
+ // Holds information needed when registering the adapter.
+ NDIS_ADAPTER_INFORMATION AdapterInformation;
+
+ // Allocate the Adapter block.
+ NdisAllocateMemory(
+ (PVOID)&Adapter,
+ sizeof(LT_ADAPTER),
+ 0,
+ LtNdisPhyAddr);
+
+ if (Adapter == NULL)
+ {
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ NdisZeroMemory(
+ Adapter,
+ sizeof(LT_ADAPTER));
+
+ Adapter->NdisMacHandle = LtMacHandle;
+
+ // Set up the AdapterInformation structure.
+ NdisZeroMemory (&AdapterInformation, sizeof(NDIS_ADAPTER_INFORMATION));
+
+ AdapterInformation.DmaChannel = 0;
+ AdapterInformation.Master = FALSE ;
+ AdapterInformation.Dma32BitAddresses = FALSE ;
+ AdapterInformation.AdapterType = BusType ;
+ AdapterInformation.PhysicalMapRegistersNeeded = 0;
+ AdapterInformation.MaximumPhysicalMapping = 0;
+ AdapterInformation.NumberOfPortDescriptors = 1 ;
+ AdapterInformation.PortDescriptors[0].InitialPort = IoBaseAddress;
+ AdapterInformation.PortDescriptors[0].NumberOfPorts = 4;
+ AdapterInformation.PortDescriptors[0].PortOffset = (PVOID *)(&(Adapter->MappedIoBaseAddr));
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("LtInitRegisterAdapter: IoBaseAddr %lx\n", IoBaseAddress));
+
+ // Register the adapter with NDIS.
+ if ((Status = NdisRegisterAdapter(
+ &Adapter->NdisAdapterHandle,
+ Adapter->NdisMacHandle,
+ Adapter,
+ WrapperConfigurationContext,
+ AdapterName,
+ &AdapterInformation)) != NDIS_STATUS_SUCCESS)
+ {
+ // Could not register the adapter, so we cannot log any errors
+ // either.
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_FATAL,
+ ("LtInitRegisterAdapter: Failed %lx\n", Status));
+
+ // Free up the memory allocated.
+ NdisFreeMemory(
+ Adapter,
+ sizeof(LT_ADAPTER),
+ 0);
+
+ return(Status);
+ }
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("LtInitRegisterAdapter: MappedIoBaseAddr %lx\n", Adapter->MappedIoBaseAddr));
+
+ do
+ {
+ // Ok. We are all set.
+ Adapter->BusType = BusType;
+
+ InitializeListHead(&Adapter->Request);
+ InitializeListHead(&Adapter->OpenBindings);
+
+ InitializeListHead(&Adapter->LoopBack);
+ InitializeListHead(&Adapter->Transmit);
+ InitializeListHead(&Adapter->Receive);
+
+ NdisAllocateSpinLock(&Adapter->Lock);
+
+ Adapter->OpenCount = 0;
+
+ // Set refcount to 1 - creation
+ Adapter->RefCount = 1;
+
+ NdisInitializeTimer(
+ &Adapter->PollingTimer,
+ LtTimerPoll,
+ (PVOID)Adapter);
+
+ // If there were no configuration errors, then go ahead with the
+ // initialize.
+
+ if (ConfigError == NDIS_STATUS_SUCCESS)
+ {
+ // Start the card up. This writes an error
+ // log entry if it fails.
+ if (LtFirmInitialize(Adapter, SuggestedNodeId))
+ {
+ // Ok, the firmware code has been downloaded to the card.
+ // Start the poll timer. We should do this before we call
+ // GetAddress. Add a reference for the timer.
+ NdisAcquireSpinLock(&Adapter->Lock);
+ LtReferenceAdapterNonInterlock(Adapter, &RefStatus);
+
+ ASSERTMSG("LtInitRegisterAdapter: RefAdater Failed!\n",
+ (RefStatus == NDIS_STATUS_SUCCESS));
+
+ Adapter->Flags |= ADAPTER_TIMER_QUEUED;
+ NdisSetTimer(&Adapter->PollingTimer, LT_POLLING_TIME);
+ NdisReleaseSpinLock(&Adapter->Lock);
+ break;
+ }
+
+ LogErrorCode = NDIS_ERROR_CODE_HARDWARE_FAILURE;
+
+ }
+ else
+ {
+ LogErrorCode = NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER;
+ }
+
+
+ // We either could not initialize the hardware or get the node
+ // address. OR there was a config error. Log it and deregister
+ // the adapter.
+ LOGERROR(Adapter->NdisAdapterHandle, LogErrorCode);
+
+ // Deregister the adapter. This calls LtInitRemoveAdapter which
+ // will do all necessary cleanup.
+ NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
+
+ Status = NDIS_STATUS_FAILURE;
+ break;
+
+ } while (FALSE);
+
+ return(Status);
+}
+
+
+
+
+BOOLEAN
+LtInitGetAddressSetPoll(
+ IN PLT_ADAPTER Adapter,
+ IN UCHAR SuggestedNodeId
+ )
+/*++
+
+Routine Description:
+
+ This gets the node id from the card (starts it off actually) and
+ sets the card to be in polling mode.
+
+Arguments:
+
+ Adapter : Pointer to the adapter structure
+ SuggestedNodeId : Pram node id or 0
+
+Return Value:
+
+ TRUE : if success, FALSE otherwise
+
+--*/
+{
+ ULONG Seed, Random;
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
+ ("LtGetAddress: Getting a node address for lt adapter...\n"));
+
+ if (SuggestedNodeId == 0)
+ {
+ Seed = (ULONG)Adapter;
+ Random = RtlRandom(&Seed);
+ SuggestedNodeId =
+ (UCHAR)((Random % LT_MAX_CLIENT_NODE_ID) + LT_MIN_SERVER_NODE_ID);
+ }
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
+ ("LtGetAddress: Suggested Node Id = %lx\n", SuggestedNodeId));
+
+ // Command Length LSB
+ NdisRawWritePortUchar(XFER_PORT, 2);
+
+ // Command Length MSB
+ NdisRawWritePortUchar(XFER_PORT, 0);
+
+ NdisRawWritePortUchar(XFER_PORT, (UCHAR)LT_CMD_LAP_INIT);
+
+ NdisRawWritePortUchar(XFER_PORT, SuggestedNodeId);
+
+ // Use 0xFF for the interrupt if this card is to be polled.
+ // We *ONLY* support polling.
+ NdisRawWritePortUchar(XFER_PORT, LT_ADAPTER_POLLED_MODE);
+
+ return TRUE;
+}
+
+
+
diff --git a/private/ntos/ndis/lt200/ltinit.h b/private/ntos/ndis/lt200/ltinit.h
new file mode 100644
index 000000000..c067c63b5
--- /dev/null
+++ b/private/ntos/ndis/lt200/ltinit.h
@@ -0,0 +1,96 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ltinit.h
+
+Abstract:
+
+ This module contains definitions specific to init code.
+
+Author:
+
+ Stephen Hou (stephh@microsoft.com)
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+
+Revision History:
+ 19 Jun 1992 Initial Version (dch@pacvax.pacersoft.com)
+
+Notes: Tab stop: 4
+--*/
+
+#ifndef _LTINIT_H_
+#define _LTINIT_H_
+
+// Exports/Prototypes
+extern
+NDIS_STATUS
+LtInitAddAdapter(
+ IN NDIS_HANDLE MacAdapterContext,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING AdapterName);
+
+extern
+VOID
+LtInitRemoveAdapter(
+ IN NDIS_HANDLE MacAdapterContext);
+
+extern
+NDIS_STATUS
+LtInitOpenAdapter(
+ OUT PNDIS_STATUS OperErrorStatus,
+ OUT NDIS_HANDLE *MacBindingHandle,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_HANDLE MacAdapterContext,
+ IN UINT OpenOptions,
+ IN PSTRING AddressingInformation);
+
+extern
+NDIS_STATUS
+LtInitCloseAdapter(
+ IN NDIS_HANDLE MacBindingHandle);
+
+extern
+VOID
+LtInitUnload(
+ IN NDIS_HANDLE MacMacContext);
+
+extern
+NDIS_STATUS
+LtInitRegisterAdapter(
+ IN NDIS_HANDLE LtMacHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN PNDIS_STRING AdapterName,
+ IN NDIS_INTERFACE_TYPE BusType,
+ IN UCHAR SuggestedNodeId,
+ IN UINT IoBaseAddress,
+ IN UINT MaxAdapters,
+ IN NDIS_STATUS Status);
+
+extern
+BOOLEAN
+LtInitGetAddressSetPoll(
+ IN PLT_ADAPTER Adapter,
+ IN UCHAR SuggestedNodeId);
+
+#ifdef LTINIT_H_LOCALS
+
+NTSTATUS
+DriverEntry (
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath);
+
+
+
+
+
+#endif // LTINIT_H_LOCALS
+
+
+#endif // _LTINIT_H_
+
diff --git a/private/ntos/ndis/lt200/ltloop.c b/private/ntos/ndis/lt200/ltloop.c
new file mode 100644
index 000000000..9baad5bd5
--- /dev/null
+++ b/private/ntos/ndis/lt200/ltloop.c
@@ -0,0 +1,185 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ltloop.c
+
+Abstract:
+
+ This module contains the loopback queue processing routines.
+
+Author:
+
+ Stephen Hou (stephh@microsoft.com)
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+
+Revision History:
+ 19 Jun 1992 Initial Version (dch@pacvax.pacersoft.com)
+
+Notes: Tab stop: 4
+--*/
+
+#include "ltmain.h"
+
+// Define file id for errorlogging
+#define FILENUM LTLOOP
+
+
+VOID
+LtLoopProcessQueue(
+ IN PLT_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine is responsible for indicating *one* packet on
+ the loopback queue either completing it or moving on to the
+ finish send queue.
+
+Arguments:
+
+ Adapter - The adapter whose loopback queue we are processing.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ // Packet at the head of the loopback list.
+ PNDIS_PACKET Packet;
+
+ // The reserved portion of the above packet.
+ PLT_PACKET_RESERVED Reserved;
+
+ // Buffer for loopback.
+ CHAR Loopback[LT_MAX_INDICATE_SIZE];
+
+ // The first buffer in the ndis packet to be loopedback.
+ PNDIS_BUFFER FirstBuffer;
+
+ // The total amount of user data in the packet to be
+ // loopedback.
+ UINT PacketLength;
+
+ // Eventually the address of the data to be indicated
+ // to the transport.
+ PCHAR BufferAddress, LinkAddress;
+
+ // Eventually the length of the data to be indicated
+ // to the transport.
+ UINT BufferLength;
+ PLIST_ENTRY p;
+ PLT_OPEN Binding;
+
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ while((!IsListEmpty(&Adapter->LoopBack)) &&
+ ((Adapter->Flags & ADAPTER_RESET_IN_PROGRESS) == 0))
+ {
+ p = RemoveHeadList(&Adapter->LoopBack);
+ Packet = CONTAINING_RECORD(
+ p,
+ NDIS_PACKET,
+ MacReserved);
+
+ Reserved = (PLT_PACKET_RESERVED)Packet->MacReserved;
+
+ // Remember this in CurrentLoopbackPacket in Adapter.
+ // Used by Transfer data.
+ Adapter->CurrentLoopbackPacket = Packet;
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("LtLoopProcessLoopback: Dequeued %lx \n", Packet));
+
+ // See if we need to copy the data from the packet
+ // into the loopback buffer.
+ //
+ // We need to copy to the local loopback buffer if
+ // the first buffer of the packet is less than the
+ // minimum loopback size AND the first buffer isn't
+ // the total packet.
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ NULL,
+ &FirstBuffer,
+ &PacketLength);
+
+ NdisQueryBuffer(
+ FirstBuffer,
+ &BufferAddress,
+ &BufferLength);
+
+ LinkAddress = BufferAddress;
+ if (BufferLength != PacketLength)
+ {
+ // !!!BUGBUG: What do the sizes mean?
+ LtUtilsCopyFromPacketToBuffer(
+ Packet,
+ LT_DGRAM_OFFSET,
+ LT_MAX_INDICATE_SIZE,
+ Loopback,
+ &BufferLength);
+
+ BufferAddress = Loopback;
+
+ }
+ else
+ {
+ // Adjust the buffer to account for the link header
+ // which is not part of the lookahead.
+ BufferAddress += LT_DGRAM_OFFSET;
+ BufferLength -= LT_LINK_HEADER_LENGTH;
+ }
+
+ // Indicate the packet to every open binding
+ // that could want it. Since loopback indications
+ // are seralized, we use a NULL handle to indicate that it
+ // is for a loopback packet. TransferData always gets the
+ // first packet off the loopback queue.
+
+ // Since we do not have an complicated filtering to do.
+ // Just walk the list of Open bindings and Indicate the packet
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ LtRecvIndicatePacket(
+ Adapter,
+ LinkAddress,
+ BufferAddress,
+ BufferLength,
+ PacketLength - LT_LINK_HEADER_LENGTH,
+ (NDIS_HANDLE)NULL);
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+
+ // We have indicated the packet to all the binding. Now we just
+ // need to call send completion.
+
+ DBGPRINT(DBG_COMP_LOOP, DBG_LEVEL_WARN,
+ ("LtLoopProcessLoopback: NdisSendComplete Packet = %p\n", Packet ));
+
+
+ Binding = (PLT_OPEN)(Reserved->MacBindingHandle);
+ NdisCompleteSend(
+ Binding->NdisBindingContext,
+ Packet,
+ NDIS_STATUS_SUCCESS);
+
+ // Dereference the adapter and the binding for this completed
+ // send.
+ LtDeReferenceBinding(Binding);
+ LtDeReferenceAdapter(Adapter);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ }
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ return;
+}
+
+
diff --git a/private/ntos/ndis/lt200/ltloop.h b/private/ntos/ndis/lt200/ltloop.h
new file mode 100644
index 000000000..359b5d470
--- /dev/null
+++ b/private/ntos/ndis/lt200/ltloop.h
@@ -0,0 +1,37 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ltloop.h
+
+Abstract:
+
+ This module contains definitions from ltloop.c
+
+Author:
+
+ Stephen Hou (stephh@microsoft.com)
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+
+Revision History:
+ 19 Jun 1992 Initial Version (dch@pacvax.pacersoft.com)
+
+Notes: Tab stop: 4
+--*/
+
+#ifndef _LTLOOP_H_
+#define _LTLOOP_H_
+
+VOID
+LtLoopProcessQueue(
+ IN PLT_ADAPTER Adapter);
+
+#ifdef LTLOOP_H_LOCALS
+
+#endif // LTLOOP_H_LOCALS
+
+
+#endif // _LTLOOP_H_
+
diff --git a/private/ntos/ndis/lt200/ltmain.h b/private/ntos/ndis/lt200/ltmain.h
new file mode 100644
index 000000000..3b7d7e63c
--- /dev/null
+++ b/private/ntos/ndis/lt200/ltmain.h
@@ -0,0 +1,53 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ltmain.h
+
+Abstract:
+
+ This module is the main common include file.
+
+Author:
+
+ Stephen Hou (stephh@microsoft.com)
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+
+Revision History:
+ 19 Jun 1992 Initial Version (dch@pacvax.pacersoft.com)
+
+Notes: Tab stop: 4
+--*/
+
+#ifndef _LTMAIN_H_
+#define _LTMAIN_H_
+
+#include <ndis.h>
+#include <stdlib.h>
+
+// !!!ntddk.h doesnt include the prototype for this function!!!
+ULONG
+RtlRandom (
+ PULONG Seed);
+
+#include "ltdebug.h"
+#include "lthrd.h"
+#include "ltsft.h"
+#include "ltinit.h"
+#include "ltsend.h"
+#include "ltrecv.h"
+#include "ltloop.h"
+#include "ltutils.h"
+
+// Define all the globals
+#include "ltglobal.h"
+
+#ifdef LTMAIN_H_LOCALS
+
+#endif // LTMAIN_H_LOCALS
+
+
+#endif // _LTMAIN_H_
+
diff --git a/private/ntos/ndis/lt200/ltrecv.c b/private/ntos/ndis/lt200/ltrecv.c
new file mode 100644
index 000000000..bf468c617
--- /dev/null
+++ b/private/ntos/ndis/lt200/ltrecv.c
@@ -0,0 +1,523 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ltrecv.c
+
+Abstract:
+
+ This module contains the receive processing routines.
+
+Author:
+
+ Stephen Hou (stephh@microsoft.com)
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+
+Revision History:
+ 19 Jun 1992 Initial Version (dch@pacvax.pacersoft.com)
+
+Notes: Tab stop: 4
+--*/
+
+#define LTRECV_H_LOCALS
+#include "ltmain.h"
+
+// Define file id for errorlogging
+#define FILENUM LTRECV
+
+
+VOID
+LtRecvProcessQueue(
+ IN PLT_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by the timer poll routine to process the receive
+ queue. Note that the actual receives from the card happen in the timer
+ poll routine itself.
+
+Arguments:
+
+ Adapter : Pointer to the Adapter on which receive completion
+ needs to happen.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ UINT PacketLength, DgramLength;
+ PUCHAR Packet, Dgram;
+ PLIST_ENTRY p;
+ PRECV_DESC RecvDesc;
+
+ DBGPRINT(DBG_COMP_RECV, DBG_LEVEL_ENTRY,
+ ("LtRecvProcessQueue: Entering...\n"));
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ while((!IsListEmpty(&Adapter->Receive)) &&
+ ((Adapter->Flags & ADAPTER_RESET_IN_PROGRESS) == 0))
+ {
+ p = RemoveHeadList(&Adapter->Receive);
+ RecvDesc = CONTAINING_RECORD(
+ p,
+ RECV_DESC,
+ Linkage);
+
+ // We will always have the link header at minimum
+ PacketLength = RecvDesc->BufferLength;
+ DgramLength = PacketLength - LT_LINK_HEADER_LENGTH;
+ ASSERTMSG("LtRecvProcessQueue: Packet length 0!\n", PacketLength != 0);
+
+ Packet = (PUCHAR)((PUCHAR)RecvDesc+sizeof(RECV_DESC));
+ Dgram = Packet + LT_LINK_HEADER_LENGTH;
+
+ if (IsListEmpty(&Adapter->OpenBindings))
+ {
+ DBGPRINT(DBG_COMP_RECV, DBG_LEVEL_WARN,
+ ("LtRecvProcessQueue: No Binding! Discarding packet!\n"));
+
+ // No body to receive this, free up the buffer;
+ NdisFreeMemory(
+ RecvDesc,
+ sizeof(RecvDesc)+PacketLength,
+ 0);
+
+ continue;
+ }
+
+ // Indicate the packet to all the open bindings on this adapter.
+ // After return from this routine, we should be able to free up
+ // the packet.
+ LtRecvIndicatePacket(
+ Adapter,
+ Packet,
+ Dgram,
+ DgramLength,
+ DgramLength,
+ (NDIS_HANDLE)Packet);
+
+ NdisFreeMemory(
+ RecvDesc,
+ sizeof(RecvDesc)+PacketLength,
+ 0);
+ }
+
+
+ // Check if we need to do any receive completes.
+ LtRecvQueueCompletion(Adapter);
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ DBGPRINT(DBG_COMP_RECV, DBG_LEVEL_ENTRY,
+ ("LTProcessReceiveQueue: Leaving...\n"));
+
+ return;
+}
+
+
+
+
+NDIS_STATUS
+LtRecvTransferData(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ )
+/*++
+
+Routine Description:
+
+ This is called by ndis to transfer previously indicated data. A
+ MacReceiveContext of NULL is used to transfer data from the current
+ loopback packet.
+
+Arguments:
+
+ As described in NDIS 3.0.
+ MacReceiveContext : NULL - Use current loopback packet
+ Otherwise it is a pointer to a RECV_DESC.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS : If successful, error otherwise.
+
+--*/
+{
+ BOOLEAN DerefAdapter = FALSE;
+ BOOLEAN DerefBinding = FALSE;
+ PLT_OPEN Binding = (PLT_OPEN)MacBindingHandle;
+ PLT_ADAPTER Adapter = Binding->LtAdapter;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ DBGPRINT(DBG_COMP_RECV, DBG_LEVEL_ENTRY,
+ ("LtRecvTransferData: Entered\n"));
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ do
+ {
+ LtReferenceAdapterNonInterlock(Adapter, &Status);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ Status = NDIS_STATUS_REQUEST_ABORTED;
+ break;
+ }
+ else
+ {
+ DerefAdapter = TRUE;
+ LtReferenceBindingNonInterlock(Binding, &Status);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ Status = NDIS_STATUS_REQUEST_ABORTED;
+ break;
+ }
+ DerefBinding = TRUE;
+ }
+
+ if (Adapter->Flags & ADAPTER_RESET_IN_PROGRESS)
+ {
+ Status = NDIS_STATUS_RESET_IN_PROGRESS;
+ break;
+ }
+
+ } while (FALSE);
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (MacReceiveContext == NULL)
+ {
+ DBGPRINT(DBG_COMP_RECV, DBG_LEVEL_INFO,
+ ("LtRecvTransferData: CurrentLookXfer\n"));
+
+ NdisCopyFromPacketToPacket(
+ Packet,
+ 0,
+ BytesToTransfer,
+ Adapter->CurrentLoopbackPacket,
+ ByteOffset + LT_LINK_HEADER_LENGTH,
+ BytesTransferred);
+
+ }
+ else
+ {
+ DBGPRINT(DBG_COMP_RECV, DBG_LEVEL_INFO,
+ ("LtRecvTransferData: NormalXfer\n"));
+
+ LtUtilsCopyFromBufferToPacket(
+ (PUCHAR)MacReceiveContext,
+ ByteOffset + LT_LINK_HEADER_LENGTH,
+ BytesToTransfer,
+ Packet,
+ BytesTransferred);
+ }
+ }
+
+ if (DerefAdapter)
+ LtDeReferenceAdapter(Adapter);
+
+ if (DerefBinding)
+ LtDeReferenceBinding(Binding);
+
+ return Status;
+}
+
+
+
+
+VOID
+LtRecvIndicatePacket(
+ IN PLT_ADAPTER Adapter,
+ IN PUCHAR LinkHdr,
+ IN PUCHAR LookAheadBuffer,
+ IN UINT LookAheadSize,
+ IN UINT DgramLength,
+ IN NDIS_HANDLE IndicateCtx
+ )
+/*++
+
+Routine Description:
+
+ This routine is called to indicate a specific packet to all bindings
+ on an adapter.
+
+Arguments:
+
+ Adapter : Pointer to the adapter
+ LinkHdr : Link header, guaranteed to be 3 bytes
+ LookAheadBuffer : Lookahead buffer to indicate
+ LookAheadSize : Size of lookahead buffer (excludes link header)
+ DgramLength : Size of the complete packet (excludes link header)
+ IndicateCtx : Ctx to pass as indicate context to NDIS
+
+Return Value:
+
+ None.
+
+--*/
+{
+ NDIS_STATUS RefStatus, Status;
+ PLT_OPEN NextBinding, Binding;
+ UINT CurLookAheadSize;
+
+ NextBinding = NULL;
+ LtReferenceBindingNextNcNonInterlock(
+ Adapter->OpenBindings.Flink,
+ &Adapter->OpenBindings,
+ &Binding,
+ &RefStatus);
+
+ while (RefStatus == NDIS_STATUS_SUCCESS)
+ {
+ // Reference the next non-closing binding
+ LtReferenceBindingNextNcNonInterlock(
+ Binding->Linkage.Flink,
+ &Adapter->OpenBindings,
+ &NextBinding,
+ &RefStatus);
+
+ // Never more than one binding usually, remove when not true.
+ ASSERT(RefStatus != NDIS_STATUS_SUCCESS);
+
+ // Go ahead and do the indicate.
+ CurLookAheadSize = Binding->CurrentLookAheadSize;
+
+ if (((LtUtilsUcharPacketType(LinkHdr[0], LinkHdr[1]) == LT_BROADCAST) &&
+ (Binding->CurrentPacketFilter & NDIS_PACKET_TYPE_BROADCAST))
+
+ ||
+
+ ((LtUtilsUcharPacketType(LinkHdr[0], LinkHdr[1]) != LT_BROADCAST) &&
+ (Binding->CurrentPacketFilter & NDIS_PACKET_TYPE_DIRECTED)))
+ {
+ DBGPRINT(DBG_COMP_RECV, DBG_LEVEL_INFO,
+ ("LtRecvIndicatePacket: Indicating packet on bind %lx\n",
+ Binding));
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisIndicateReceive(
+ &Status,
+ Binding->NdisBindingContext,
+ IndicateCtx,
+ LinkHdr,
+ LT_LINK_HEADER_LENGTH,
+ LookAheadBuffer,
+ ((LookAheadSize > CurLookAheadSize) ? \
+ CurLookAheadSize : LookAheadSize),
+ DgramLength);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ Adapter->MediaOptional[MO_NO_HANDLERS] ++;
+ }
+
+ // Since this routine is called within a loop in LtRecvProcessQueue,
+ // and since we need only one reference per binding for receive
+ // completion, we do the following to avoid over-referencing the
+ // binding structure.
+
+ if (Binding->Flags & BINDING_DO_RECV_COMPLETION)
+ {
+ NdisReleaseSpinLock(&Adapter->Lock);
+ LtDeReferenceBinding(Binding);
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ }
+ else
+ {
+ // Remember this binding needs a receive completion
+ Binding->Flags |= BINDING_DO_RECV_COMPLETION;
+ }
+
+ // Also, make a note in the adapter so that the receive
+ // completion handler is enqueued.
+ Adapter->Flags |= ADAPTER_QUEUE_RECV_COMPLETION;
+
+ }
+ else
+ {
+ // Remove the reference on this binding.
+ NdisReleaseSpinLock(&Adapter->Lock);
+ LtDeReferenceBinding(Binding);
+ NdisAcquireSpinLock(&Adapter->Lock);
+ }
+
+ // Never more than one binding usually, remove when not true.
+ ASSERT(RefStatus != NDIS_STATUS_SUCCESS);
+
+ Binding = NextBinding;
+ }
+
+ return;
+}
+
+
+
+
+VOID
+LtRecvQueueCompletion(
+ IN PLT_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to queue up a completion handler on the adapter.
+ This handler will then indicate receive completion to all necessary
+ bindings on the adapter.
+
+ ASSUMES: Adapter->Lock is HELD.
+
+Arguments:
+
+ Adapter : Pointer to the adapter
+
+Return Value:
+
+ None.
+
+--*/
+{
+ NDIS_STATUS Status;
+ BOOLEAN Queue = FALSE;
+
+ // !!! ASSUMES Adapter->Lock is held!!!
+ if (Adapter->Flags & ADAPTER_QUEUE_RECV_COMPLETION)
+ {
+ if ((Adapter->Flags & ADAPTER_QUEUED_RECV_COMPLETION) == 0)
+ {
+ Adapter->Flags |= ADAPTER_QUEUED_RECV_COMPLETION;
+ Queue = TRUE;
+ }
+
+ Adapter->Flags &= ~ADAPTER_QUEUE_RECV_COMPLETION;
+ }
+
+ if (Queue)
+ {
+ DBGPRINT(DBG_COMP_RECV, DBG_LEVEL_INFO,
+ ("LtRecvQueueCompletion: queing receive complete\n"));
+
+ // !!! NOTE !!!
+ // This should never fail!! If Queue is set, then a binding
+ // was referenced for receive completion. So it couldnt have
+ // gone away. And so the adapter cannot be in a CLOSING state.
+ // As all binding need to have gone away, before the RemovAdapter
+ // is called by NDIS.
+
+ LtReferenceAdapterNonInterlock(Adapter, &Status);
+ ASSERTMSG("LtRecvQueueCompletion: Adapter is closing!\n",
+ (Status == NDIS_STATUS_SUCCESS));
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ // !!! KEBUGCHECK() !!!
+ KeBugCheck((ULONG)__LINE__);
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+ LtRecvCompletion(Adapter);
+ LtDeReferenceAdapter(Adapter);
+ NdisAcquireSpinLock(&Adapter->Lock);
+ }
+
+ return;
+}
+
+
+
+NTSTATUS
+LtRecvCompletion(
+ IN PLT_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ Called to indicate receive completion on all binding on this adapter.
+ This will loop until all receive completions are done. This might
+ tend to starve bindings towards the end of the list, but we wont
+ worry about that.
+
+Arguments:
+
+ Adapter : Pointer to the Adapter on which receive completion
+ needs to happen.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+{
+ PLIST_ENTRY p;
+ PLT_OPEN Binding;
+
+ // For each binding, if recv completion is to be called, do it.
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ DBGPRINT(DBG_COMP_RECV, DBG_LEVEL_INFO,
+ ("LtRecvCompletion: Indicating receive completion\n"));
+
+ for (p = Adapter->OpenBindings.Flink; (p != &Adapter->OpenBindings);)
+ {
+ Binding = CONTAINING_RECORD(
+ p,
+ LT_OPEN,
+ Linkage);
+
+ if (Binding->Flags & BINDING_DO_RECV_COMPLETION)
+ {
+ Binding->Flags &= ~BINDING_DO_RECV_COMPLETION;
+ }
+ else
+ {
+ // !!! Note the continue in here !!!
+
+ DBGPRINT(DBG_COMP_RECV, DBG_LEVEL_WARN,
+ ("LtRecvCompletion: No recv comp flag on binding\n"));
+
+ p = p->Flink;
+
+ // Never more than one binding usually, remove when not true.
+ ASSERT(p == &Adapter->OpenBindings);
+ continue;
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ // Call NdisReceiveCompletion for this binding.
+ NdisIndicateReceiveComplete(Binding->NdisBindingContext);
+
+ // Dereference the binding, this was added in the process queue
+ // routine.
+ LtDeReferenceBinding(Binding);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ // Restart the search
+ p = Adapter->OpenBindings.Flink;
+ }
+
+ DBGPRINT(DBG_COMP_RECV, DBG_LEVEL_INFO,
+ ("LtRecvCompletion: Enabling receive queing\n"));
+
+ // Enable any new queue requests to take effect.
+ Adapter->Flags &= ~ADAPTER_QUEUED_RECV_COMPLETION;
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ return STATUS_SUCCESS;
+}
+
diff --git a/private/ntos/ndis/lt200/ltrecv.h b/private/ntos/ndis/lt200/ltrecv.h
new file mode 100644
index 000000000..7dcd8eff3
--- /dev/null
+++ b/private/ntos/ndis/lt200/ltrecv.h
@@ -0,0 +1,78 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ltrecv.h
+
+Abstract:
+
+ This module contains definitions for the receive packet processing.
+
+Author:
+
+ Stephen Hou (stephh@microsoft.com)
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+
+Revision History:
+ 19 Jun 1992 Initial Version (dch@pacvax.pacersoft.com)
+
+Notes: Tab stop: 4
+--*/
+
+#ifndef _LTRECV_H_
+#define _LTRECV_H_
+
+extern
+VOID
+LtRecvProcessQueue(
+ IN PLT_ADAPTER Adapter);
+
+extern
+NDIS_STATUS
+LtRecvTransferData(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred);
+
+VOID
+LtRecvQueueCompletion(
+ IN PLT_ADAPTER Adapter);
+
+VOID
+LtRecvIndicatePacket(
+ IN PLT_ADAPTER Adapter,
+ IN PUCHAR LinkHdr,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadSize,
+ IN UINT DgramLength,
+ IN NDIS_HANDLE IndicateCtx);
+
+NTSTATUS
+LtRecvCompletion(
+ IN PLT_ADAPTER Adapter);
+
+// Define the Receive descriptor. This will contain info about the packet
+// and the packet itself will follow this structure.
+typedef struct _LT_RECV_DESC {
+ LIST_ENTRY Linkage;
+ BOOLEAN Broadcast;
+ UINT BufferLength;
+
+ //
+ // This is followed by BufferLength bytes of data
+ // UCHAR Buffer[BufferLength];
+
+} RECV_DESC, *PRECV_DESC;
+
+#ifdef LTRECV_H_LOCALS
+
+#endif // LTRECV_H_LOCALS
+
+
+#endif // _LTRECV_H_
+
diff --git a/private/ntos/ndis/lt200/ltreg.c b/private/ntos/ndis/lt200/ltreg.c
new file mode 100644
index 000000000..36a89a019
--- /dev/null
+++ b/private/ntos/ndis/lt200/ltreg.c
@@ -0,0 +1,262 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ltreg.c
+
+Abstract:
+
+ This module contains helper routines for reading configuration
+ information from the registry.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+ Stephen Hou (stephh@microsoft.com)
+
+Revision History:
+ 19 Jun 1992 Initial Version (dch@pacvax.pacersoft.com)
+
+Notes: Tab stop: 4
+--*/
+
+#define LTREG_H_LOCALS
+#include "ltmain.h"
+#include "ltreg.h"
+
+// Define file id for errorlogging
+#define FILENUM LTREG
+
+
+UINT
+LtRegGetBusNumber(
+ IN NDIS_HANDLE ConfigHandle
+ )
+/*++
+
+Routine Description:
+
+ This routine determines the bus number the card is installed on
+
+Arguments:
+
+ ConfigHandle : The handle to the configuration database
+
+Return Value:
+
+ Returns the bus number the card is on. If we do not find the
+ relevant information in the database, then 0 is returned.
+
+--*/
+{
+ NDIS_STATUS Status;
+ PNDIS_CONFIGURATION_PARAMETER Parameter;
+
+ UINT BusNumber = 0;
+
+ NDIS_STRING Keyword = LT_REG_KEY_BUS_NUMBER_STRING;
+
+ NdisReadConfiguration(
+ &Status,
+ &Parameter,
+ ConfigHandle,
+ &Keyword,
+ NdisParameterInteger);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ BusNumber = (UINT)Parameter->ParameterData.IntegerData;
+ }
+
+ return(BusNumber);
+}
+
+
+NDIS_STATUS
+LtRegGetBusType(
+ IN NDIS_HANDLE ConfigHandle,
+ OUT PNDIS_INTERFACE_TYPE BusType
+ )
+/*++
+
+Routine Description:
+
+ This routine determines the type of bus the card is installed on
+
+Arguments:
+
+ ConfigHandle : The handle to the configuration database
+ BusType : On return, the bus type is stored here
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS : if successfully read from the config database
+ NDIS_STATUS_FAILURE : if unable to find the information in the config
+ database
+
+--*/
+{
+ NDIS_STATUS Status;
+ PNDIS_CONFIGURATION_PARAMETER Parameter;
+
+ NDIS_STRING Keyword = LT_REG_KEY_BUS_TYPE_STRING;
+
+ NdisReadConfiguration(
+ &Status,
+ &Parameter,
+ ConfigHandle,
+ &Keyword,
+ NdisParameterInteger);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ *BusType = (UINT)Parameter->ParameterData.IntegerData;
+ }
+
+ return(Status);
+}
+
+
+UCHAR
+LtRegGetNodeId(
+ IN NDIS_HANDLE ConfigHandle
+ )
+/*++
+
+Routine Description:
+
+ This routine determines the last NodeId used by the card.
+
+Arguments:
+
+ ConfigHandle : The handle to the configuration database
+
+Return Value:
+
+ Returns the last valid NodeId used by the card. If we find that
+ the value stored in the configuration info is not valid, then the
+ suggested NodeId is returned.
+
+--*/
+{
+ NDIS_STATUS Status;
+ PNDIS_CONFIGURATION_PARAMETER Parameter;
+
+ NDIS_STRING Keyword = LT_REG_KEY_NODE_ID_STRING;
+ UCHAR NodeId = 0;
+
+ NdisReadConfiguration(
+ &Status,
+ &Parameter,
+ ConfigHandle,
+ &Keyword,
+ NdisParameterInteger);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ NodeId = (UCHAR)Parameter->ParameterData.IntegerData;
+ if ((NodeId < LT_NODE_ID_MIN) || (NodeId > LT_NODE_ID_MAX))
+ {
+
+ NodeId = 0;
+ }
+ }
+
+ return(NodeId);
+}
+
+
+NDIS_STATUS
+LtRegGetIoBaseAddr(
+ OUT PUINT IoBaseAddress,
+ IN NDIS_HANDLE NdisConfigHandle,
+ IN NDIS_HANDLE ConfigHandle,
+ IN NDIS_INTERFACE_TYPE BusType
+ )
+/*++
+
+Routine Description:
+
+ This routine determines the port addresses used to communicate
+ with the card.
+
+Arguments:
+
+ IoBaseAddress : On return, the I/O port address is stored here
+ ConfigHandle : The handle to the configuration database
+ SlotNumber : For MCA machines, the indicates the slot the card is in
+ BusType : The type of bus the card is located on
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS : if successful
+ NDIS_STATUS_ADAPTER_NOT_FOUND : if running on a MCA machine and
+ the adapter cannot be located
+ NDIS_STATUS_BAD_CHARACTERISTICS : if the I/O base is not within
+ the legal range
+
+--*/
+{
+ NDIS_MCA_POS_DATA McaData;
+ NDIS_STATUS Status;
+ PNDIS_CONFIGURATION_PARAMETER Parameter;
+
+ NDIS_STRING Keyword = LT_REG_KEY_IO_BASE_ADDRESS_STRING;
+ UINT SlotNumber = 0;
+
+ // If BusType is NdisInterfaceMca, then we read the MCA POS info to
+ // get our parameters. Otherwise, we just read the registry.
+
+ if (BusType == NdisInterfaceMca)
+ {
+ NdisReadMcaPosInformation(
+ &Status,
+ NdisConfigHandle,
+ &SlotNumber,
+ &McaData);
+
+// *IoBaseAddress = (UINT)(McaData.PosData2 | (McaData.PosData3 << 8));
+ *IoBaseAddress = LT_DECODE_ADDR_FROM_POSDATA(McaData);
+
+ DBGPRINT(DBG_COMP_REGISTRY, DBG_LEVEL_FATAL,
+ ("LtRegGetIoBaseAddr: Base %lx. %lx.%lx.%lx.%lx, Id - %lx\n",
+ *IoBaseAddress, McaData.PosData1, McaData.PosData2,
+ McaData.PosData3, McaData.PosData4, McaData.AdapterId));
+
+ if ((Status != NDIS_STATUS_SUCCESS) || (McaData.AdapterId != LT_MCA_POS_ID))
+ {
+ Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+ }
+
+ }
+ else
+ {
+ NdisReadConfiguration(
+ &Status,
+ &Parameter,
+ ConfigHandle,
+ &Keyword,
+ NdisParameterHexInteger);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ *IoBaseAddress = (UINT)Parameter->ParameterData.IntegerData;
+ }
+ }
+
+ if ((Status == NDIS_STATUS_SUCCESS) &&
+ ((*IoBaseAddress < LT_IO_BASE_ADDRESS_MIN) ||
+ (*IoBaseAddress > LT_IO_BASE_ADDRESS_MAX)))
+ {
+ DBGPRINT(DBG_COMP_REGISTRY, DBG_LEVEL_FATAL,
+ ("LtRegGetIoBaseAddr: invalid value found for %s\n", LT_REG_KEY_IO_BASE_ADDRESS));
+
+ Status = NDIS_STATUS_BAD_CHARACTERISTICS;
+ }
+
+ return(Status);
+}
+
+
diff --git a/private/ntos/ndis/lt200/ltreg.h b/private/ntos/ndis/lt200/ltreg.h
new file mode 100644
index 000000000..ba3895ce1
--- /dev/null
+++ b/private/ntos/ndis/lt200/ltreg.h
@@ -0,0 +1,80 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ltreg.h
+
+Abstract:
+
+ This module contains
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+ Stephen Hou (stephh@microsoft.com)
+
+Revision History:
+ 19 Jun 1992 Initial Version (dch@pacvax.pacersoft.com)
+
+Notes: Tab stop: 4
+--*/
+
+#ifndef _LTREG_H_
+#define _LTREG_H_
+
+
+UINT
+LtRegGetBusNumber(
+ IN NDIS_HANDLE ConfigHandle
+ );
+
+NDIS_STATUS
+LtRegGetBusType(
+ IN NDIS_HANDLE ConfigHandle,
+ OUT PNDIS_INTERFACE_TYPE BusType
+ );
+
+UCHAR
+LtRegGetNodeId(
+ IN NDIS_HANDLE ConfigHandle
+ );
+
+NDIS_STATUS
+LtRegGetIoBaseAddr(
+ OUT PUINT IoBaseAddress,
+ IN NDIS_HANDLE NdisConfigHandle,
+ IN NDIS_HANDLE ConfigHandle,
+ IN NDIS_INTERFACE_TYPE BusType
+ );
+
+
+
+#ifdef LTREG_H_LOCALS
+
+
+#define LT_NODE_ID_MIN 128
+#define LT_NODE_ID_MAX 254
+
+#define LT_IO_BASE_ADDRESS_MIN 0x200
+#define LT_IO_BASE_ADDRESS_MAX 0x3F0
+
+#define LT_MCA_POS_ID 0x6674
+
+#define LT_REG_KEY_BUS_NUMBER "BusNumber"
+#define LT_REG_KEY_IO_BASE_ADDRESS "IoBaseAddress"
+#define LT_REG_KEY_NODE_ID "NodeID"
+
+#define LT_REG_KEY_BUS_NUMBER_STRING NDIS_STRING_CONST("BusNumber")
+#define LT_REG_KEY_BUS_TYPE_STRING NDIS_STRING_CONST("BusType")
+#define LT_REG_KEY_IO_BASE_ADDRESS_STRING NDIS_STRING_CONST("IoBaseAddress")
+#define LT_REG_KEY_NODE_ID_STRING NDIS_STRING_CONST("NodeID")
+
+// MACROS
+#define LT_DECODE_ADDR_FROM_POSDATA(McaData) \
+ ((((UINT)McaData.PosData3 << 8) | (UINT)McaData.PosData2) & 0x0FF0)
+
+#endif // LTREG_H_LOCALS
+
+#endif // _LTREG_H_
diff --git a/private/ntos/ndis/lt200/ltreq.c b/private/ntos/ndis/lt200/ltreq.c
new file mode 100644
index 000000000..6b54c9915
--- /dev/null
+++ b/private/ntos/ndis/lt200/ltreq.c
@@ -0,0 +1,651 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ltreq.c
+
+Abstract:
+
+ This module contains
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+ Stephen Hou (stephh@microsoft.com)
+
+Revision History:
+ 19 Jun 1992 Initial Version (dch@pacvax.pacersoft.com)
+
+Notes: Tab stop: 4
+--*/
+
+#define LTREQ_H_LOCALS
+#include "ltmain.h"
+#include "ltreq.h"
+
+// Define file id for errorlogging
+#define FILENUM LTREQ
+
+
+NDIS_STATUS
+LtRequest(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+/*++
+
+Routine Description:
+
+ called by NDIS to query or set card/driver information on a binding
+
+Arguments:
+
+ MacBindingHandle : the binding submitting the request
+ NdisRequest : the request we've been asked to satisfy
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS : if completed successfully
+ NDIS_STATUS_RESET_IN_PROGRESS : if the adapter's in the middle of a reset
+ NDIS_STATUS_ADAPTER_REMOVED : if the adapter's been closed
+ NDIS_STATUS_CLOSING : if the binding is closing down
+ NDIS_STATUS_NOT_SUPPORTED : if we do not support the requested action
+
+--*/
+{
+ NDIS_STATUS Status;
+ PLT_ADAPTER Adapter = ((PLT_OPEN)MacBindingHandle)->LtAdapter;
+ PLT_OPEN Open = (PLT_OPEN)MacBindingHandle;
+
+ if (Adapter->Flags & ADAPTER_RESET_IN_PROGRESS)
+ {
+ return(NDIS_STATUS_RESET_IN_PROGRESS);
+ }
+
+ switch (NdisRequest->RequestType)
+ {
+ case NdisRequestSetInformation:
+ case NdisRequestQueryInformation:
+
+ // increment count since we'll be in the binding with the request
+ LtReferenceBinding(Open,&Status);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (NdisRequest->RequestType == NdisRequestSetInformation)
+ {
+ Status = LtReqSetInformation(
+ Adapter,
+ Open,
+ NdisRequest->DATA.SET_INFORMATION.Oid,
+ NdisRequest->DATA.SET_INFORMATION.InformationBuffer,
+ NdisRequest->DATA.SET_INFORMATION.InformationBufferLength,
+ &(NdisRequest->DATA.SET_INFORMATION.BytesRead),
+ &(NdisRequest->DATA.SET_INFORMATION.BytesNeeded));
+ }
+ else
+ {
+ Status = LtReqQueryInformation(
+ Adapter,
+ Open,
+ NdisRequest->DATA.QUERY_INFORMATION.Oid,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &(NdisRequest->DATA.QUERY_INFORMATION.BytesWritten),
+ &(NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded),
+ FALSE);
+ }
+
+ // completed the request for the binding; outa there
+ LtDeReferenceBinding(Open);
+ }
+
+ break;
+
+ default:
+ // Unkown request
+
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+
+ }
+
+ return(Status);
+}
+
+
+NDIS_STATUS
+LtReqQueryGlobalStatistics(
+ IN NDIS_HANDLE MacAdapterContext,
+ IN PNDIS_REQUEST NdisRequest
+ )
+/*++
+
+Routine Description:
+
+ called by NDIS to query or set global card/driver information
+
+Arguments:
+
+ MacAdapterContext : the adapter the request is submitted on
+ NdisRequest : the request we've been asked to satisfy
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS : if completed successfully
+ NDIS_STATUS_RESET_IN_PROGRESS : if the adapter's in the middle of a reset
+ NDIS_STATUS_ADAPTER_REMOVED : if the adapter's been closed
+ NDIS_STATUS_CLOSING : if the binding is closing down
+ NDIS_STATUS_NOT_SUPPORTED : if we do not support the requested action
+
+--*/
+{
+ NDIS_STATUS Status;
+ PLT_ADAPTER Adapter = MacAdapterContext;
+
+ if (Adapter->Flags & ADAPTER_RESET_IN_PROGRESS)
+ {
+ return(NDIS_STATUS_RESET_IN_PROGRESS);
+ }
+
+ switch (NdisRequest->RequestType)
+ {
+ case NdisRequestQueryStatistics:
+
+ LtReferenceAdapter(Adapter,&Status);
+ if (Status != NDIS_STATUS_SUCCESS)
+ break;
+
+ Status = LtReqQueryInformation(
+ Adapter,
+ NULL,
+ NdisRequest->DATA.QUERY_INFORMATION.Oid,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &(NdisRequest->DATA.QUERY_INFORMATION.BytesWritten),
+ &(NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded),
+ TRUE);
+
+ LtDeReferenceAdapter(Adapter);
+ break;
+
+ default:
+
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ return(Status);
+}
+
+
+STATIC
+NDIS_STATUS
+LtReqSetInformation(
+ IN PLT_ADAPTER Adapter,
+ IN PLT_OPEN Open,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN INT InformationBufferLength,
+ IN PUINT BytesRead,
+ IN PUINT BytesNeeded
+ )
+/*++
+
+Routine Description:
+
+ performs a set operation for a single OID.
+
+Arguments:
+
+ Adapter : The adapter that the set is for
+ Open : The binding that the set is for
+ Oid : The OID to set
+ InformationBuffer : Holds the data to be set
+ InformationBufferLength : The length of InformationBuffer
+ BytesRead : If the call is successful, returns the number
+ of bytes read from InformationBuffer
+ BytesNeeded : If there is not enough data in InformationBuffer
+ to satisfy the request, returns the amount of
+ storage needed.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS : if successful
+ NDIS_STATUS_INVALID_OID : if the oid is not supported
+ NDIS_STATUS_INVALID_DATA : if InformationBuffer contains bad data
+ NDIS_STATUS_INVALID_LENGTH : if the InformationBufferLength is incorrect
+
+--*/
+{
+
+ ULONG PacketFilter, NewLookAhead;
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ //
+ // Now check for the most common OIDs
+ //
+
+ DBGPRINT(DBG_COMP_REQ,DBG_LEVEL_INFO,
+ ("LtReqSetInformation: setting OID - 0x%.8lx\n", Oid));
+
+ switch (Oid)
+ {
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ // Localtalk only supports Directed and broadcast packets.
+ // And the Lt firmware does not support PROMISCUSOUS mode.
+ // so return NDIS_STATUS_NOT_SUPPORTED for these packet filters.
+
+ if (InformationBufferLength != 4)
+ {
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+ break;
+
+ }
+
+ NdisMoveMemory(
+ (PVOID)&PacketFilter,
+ InformationBuffer,
+ sizeof(ULONG));
+
+ DBGPRINT(DBG_COMP_REQ,DBG_LEVEL_INFO,
+ ("LtReqSetInformation: Requested packet filter is %x\n", PacketFilter));
+
+ if (PacketFilter == NDIS_PACKET_TYPE_BROADCAST ||
+ PacketFilter == NDIS_PACKET_TYPE_DIRECTED ||
+ PacketFilter == (NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_DIRECTED))
+ {
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->GlobalPacketFilter |= PacketFilter;
+ Open->CurrentPacketFilter = PacketFilter;
+ NdisReleaseSpinLock(&Adapter->Lock);
+ *BytesRead = InformationBufferLength;
+
+ }
+ else
+ {
+ StatusToReturn = NDIS_STATUS_INVALID_DATA;
+ }
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ if (InformationBufferLength != 4)
+ {
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+ break;
+
+ }
+
+ NdisMoveMemory(
+ (PVOID)&NewLookAhead,
+ InformationBuffer,
+ sizeof(ULONG));
+
+ DBGPRINT(DBG_COMP_REQ,DBG_LEVEL_INFO,
+ ("LtReqSetInformation: Requested Lookahead size is %d\n", NewLookAhead));
+
+ if ((NewLookAhead > LT_MAX_INDICATE_SIZE) ||
+ (NewLookAhead < LT_MIN_INDICATE_SIZE))
+ {
+ StatusToReturn = NDIS_STATUS_INVALID_DATA;
+ break;
+
+ }
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ // valid lookahead size, so set it
+ Open->CurrentLookAheadSize = NewLookAhead;
+
+ // adjust the global lookaheadsize
+ if (Adapter->GlobalLookAheadSize < NewLookAhead)
+ {
+ Adapter->GlobalLookAheadSize = NewLookAhead;
+ }
+ else
+ {
+ LtReqAdjustLookAhead(
+ &Adapter->GlobalLookAheadSize,
+ &Adapter->OpenBindings);
+ }
+ NdisReleaseSpinLock(&Adapter->Lock);
+ *BytesRead = 4;
+ break;
+
+ default:
+
+ StatusToReturn = NDIS_STATUS_INVALID_OID;
+ break;
+ }
+
+ return(StatusToReturn);
+}
+
+
+LtReqQueryInformation(
+ IN PLT_ADAPTER Adapter,
+ IN PLT_OPEN Open,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN INT InformationBufferLength,
+ IN PUINT BytesWritten,
+ IN PUINT BytesNeeded,
+ IN BOOLEAN Global
+ )
+/*++
+
+Routine Description:
+
+ performs a query operation for a single OID.
+
+Arguments:
+
+ Adapter : The adapter that the query is for
+ Open : The binding that the query is for
+ Oid : The OID to query
+ InformationBuffer : Holds the result of the query.
+ InformationBufferLength : The length of InformationBuffer.
+ BytesWritten : If the call is successful, returns the
+ number of bytes written to InformationBuffer
+ BytesNeeded : If there is not enough room in InformationBuffer
+ to satisfy the request, returns the amount of
+ storage needed
+ Global : TRUE if the request originated from the adapter.
+ FALSE if the request came from a binding
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS : if successful
+ NDIS_STATUS_INVALID_OID : if the query is on an OID we do not support
+ NDIS_STATUS_BUFFER_TOO_SHORT: if InformationBufferLength is too small to
+ hold the information returned
+
+--*/
+{
+
+ UINT OidIndex;
+ ULONG GenericUlong;
+ USHORT GenericUshort;
+ PVOID SourceBuffer = &GenericUlong;
+ UINT SourceBufferLength = sizeof(ULONG);
+ PNDIS_OID SupportedOidArray = LtProtocolSupportedOids;
+ UINT SupportedOids = (sizeof(LtProtocolSupportedOids)/sizeof(ULONG));
+ static UCHAR VendorDescription[] = LT_VENDOR_DESCR;
+ static UCHAR VendorId[3] = LT_VENDOR_ID;
+
+ if (Global)
+ {
+ SupportedOidArray = LtGlobalSupportedOids;
+ SupportedOids = sizeof(LtGlobalSupportedOids)/sizeof(ULONG);
+ }
+
+ //
+ // Check that the OID is valid.
+ //
+ for (OidIndex=0; OidIndex < SupportedOids; OidIndex++)
+ {
+ if (Oid == SupportedOidArray[OidIndex])
+ {
+ break;
+ }
+ }
+
+ if (OidIndex == SupportedOids)
+ {
+ *BytesWritten = 0;
+ return(NDIS_STATUS_INVALID_OID);
+ }
+
+ switch (Oid)
+ {
+ case OID_GEN_SUPPORTED_LIST:
+
+ SourceBuffer = SupportedOidArray;
+ SourceBufferLength = SupportedOids * sizeof(ULONG);
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+
+ GenericUlong = NdisHardwareStatusReady;
+ if (Adapter->Flags & ADAPTER_RESET_IN_PROGRESS)
+ {
+ GenericUlong = NdisHardwareStatusReset;
+ }
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+
+ GenericUlong = NdisMediumLocalTalk;
+ break;
+
+ case OID_GEN_MEDIA_IN_USE:
+
+ GenericUlong = NdisMediumLocalTalk;
+ // if no binding exists then media is not in use
+ if (Global && Adapter->OpenCount == 0)
+ {
+ SourceBufferLength = 0;
+ }
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+
+ GenericUlong = LT_MAX_INDICATE_SIZE;
+ break;
+
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+
+ GenericUlong = LT_MAXIMUM_PACKET_SIZE;
+ break;
+
+ case OID_GEN_LINK_SPEED:
+
+ GenericUlong = LT_LINK_SPEED;
+ break;
+
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+
+ GenericUlong = LT_MAXIMUM_PACKET_SIZE;
+ break;
+
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+
+ // BUGBUG: need to determine number of recv buffers or in this case the
+ // amount of space for receives
+ GenericUlong = LT_MAXIMUM_PACKET_SIZE * 5;
+ break;
+
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+
+ GenericUlong = 1;
+ break;
+
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+
+ // BUGBUG: need to determine number of recv buffers
+ GenericUlong = 5;
+ break;
+
+ case OID_GEN_VENDOR_ID:
+
+ SourceBuffer = VendorId;
+ SourceBufferLength = sizeof(VendorId);
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+
+ SourceBuffer = VendorDescription;
+ SourceBufferLength = sizeof(VendorDescription);
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ GenericUlong = Open->CurrentPacketFilter;
+ if (Global)
+ {
+ GenericUlong = Adapter->GlobalPacketFilter;
+ }
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ GenericUlong = Open->CurrentLookAheadSize;
+ if (Global)
+ {
+ GenericUlong = Adapter->GlobalLookAheadSize;
+ }
+ break;
+
+ case OID_GEN_DRIVER_VERSION:
+
+ GenericUshort = (LT_MAJOR_VERSION << 8) + LT_MINOR_VERSION;
+ SourceBuffer = &GenericUshort;
+ SourceBufferLength = sizeof(USHORT);
+ break;
+
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+
+ GenericUlong = LT_MAXIMUM_PACKET_SIZE;
+ break;
+
+ case OID_GEN_XMIT_OK:
+ case OID_GEN_RCV_OK:
+ case OID_GEN_XMIT_ERROR:
+ case OID_GEN_RCV_ERROR:
+ case OID_GEN_RCV_NO_BUFFER:
+
+ OidIndex = (Oid & LT_OID_INDEX_MASK) - 1;
+ ASSERT(OidIndex < GM_ARRAY_SIZE);
+ GenericUlong = Adapter->GeneralMandatory[OidIndex];
+ break;
+
+ case OID_GEN_DIRECTED_BYTES_XMIT:
+ case OID_GEN_BROADCAST_BYTES_XMIT:
+ case OID_GEN_DIRECTED_BYTES_RCV:
+ case OID_GEN_BROADCAST_BYTES_RCV:
+
+ OidIndex = (Oid & LT_OID_INDEX_MASK) - 1;
+ ASSERT(OidIndex < GM_ARRAY_SIZE);
+ SourceBuffer = &Adapter->GeneralOptionalByteCount[OidIndex / 2];
+ SourceBufferLength = sizeof(LARGE_INTEGER);
+ break;
+
+ case OID_GEN_DIRECTED_FRAMES_XMIT:
+ case OID_GEN_BROADCAST_FRAMES_XMIT:
+ case OID_GEN_DIRECTED_FRAMES_RCV:
+ case OID_GEN_BROADCAST_FRAMES_RCV:
+
+ OidIndex = (Oid & LT_OID_INDEX_MASK) - 1;
+ ASSERT(OidIndex < GO_COUNT_ARRAY_SIZE);
+ GenericUlong = Adapter->GeneralOptionalFrameCount[OidIndex / 2];
+ break;
+
+ case OID_GEN_RCV_CRC_ERROR:
+ case OID_GEN_TRANSMIT_QUEUE_LENGTH:
+
+ OidIndex = (Oid & LT_OID_INDEX_MASK) - 1;
+ ASSERT(OidIndex < GO_ARRAY_SIZE);
+ GenericUlong = Adapter->GeneralOptional[OidIndex - GO_ARRAY_START];
+ break;
+
+ case OID_GEN_MAC_OPTIONS:
+
+ GenericUlong = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA;
+ break;
+
+ case OID_LTALK_CURRENT_NODE_ID:
+
+ SourceBuffer = &GenericUshort;
+ GenericUshort = Adapter->NodeId;
+ SourceBufferLength = 2;
+ break;
+
+ case OID_LTALK_IN_BROADCASTS:
+ case OID_LTALK_IN_LENGTH_ERRORS:
+
+ OidIndex = (Oid & LT_OID_INDEX_MASK) - 1;
+ ASSERT (OidIndex < MM_ARRAY_SIZE);
+ GenericUlong = Adapter->MediaMandatory[OidIndex];
+ break;
+
+ case OID_LTALK_OUT_NO_HANDLERS:
+ case OID_LTALK_DEFERS:
+
+ OidIndex = (Oid & LT_OID_INDEX_MASK) - 1;
+ ASSERT (OidIndex < MO_ARRAY_SIZE);
+ GenericUlong = Adapter->MediaOptional[OidIndex];
+ break;
+
+ default:
+
+ // should never get here
+ ASSERT(FALSE);
+ break;
+ }
+
+ if ((INT)SourceBufferLength > InformationBufferLength)
+ {
+ *BytesNeeded = SourceBufferLength;
+ return(NDIS_STATUS_BUFFER_TOO_SHORT);
+ }
+
+ NdisMoveMemory(
+ InformationBuffer,
+ SourceBuffer,
+ SourceBufferLength);
+
+ *BytesWritten = SourceBufferLength;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+STATIC
+VOID
+LtReqAdjustLookAhead(
+ OUT PUINT GlobalLookAheadSize,
+ IN PLIST_ENTRY OpenBindings
+ )
+/*++
+
+Routine Description:
+
+ called by LtReqSetInformation to adjust the global lookahead size when
+ the previously largest lookahead size (on a binding) is adjusted
+
+ THIS ROUTINE IS CALLED WITH THE SPINLOCK HELD
+
+Arguments:
+
+ GlobalLookAheadSize : the global lookahead param we're adjusting
+ OpenBindings : the list of bindings we need to traverse
+
+Return Value:
+
+ none
+
+--*/
+{
+ PLT_OPEN Binding;
+ PLIST_ENTRY p = OpenBindings->Flink;
+ UINT MaxLookAheadSize = 0;
+
+ while(p != OpenBindings)
+ {
+ Binding = CONTAINING_RECORD(
+ p,
+ LT_OPEN,
+ Linkage);
+
+ if (Binding->CurrentLookAheadSize > MaxLookAheadSize)
+ {
+ MaxLookAheadSize = Binding->CurrentLookAheadSize;
+ }
+ p = p->Flink;
+ }
+ *GlobalLookAheadSize = MaxLookAheadSize;
+}
+
diff --git a/private/ntos/ndis/lt200/ltreq.h b/private/ntos/ndis/lt200/ltreq.h
new file mode 100644
index 000000000..fb2c94aa7
--- /dev/null
+++ b/private/ntos/ndis/lt200/ltreq.h
@@ -0,0 +1,159 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ltreq.h
+
+Abstract:
+
+ This module contains
+
+Author:
+
+ Stephen Hou (stephh@microsoft.com)
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+
+Revision History:
+ 19 Jun 1992 Initial Version (dch@pacvax.pacersoft.com)
+
+Notes: Tab stop: 4
+--*/
+
+#ifndef _LTREQ_H_
+#define _LTREQ_H_
+
+
+NDIS_STATUS
+LtRequest(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+NDIS_STATUS
+LtReqQueryGlobalStatistics(
+ IN NDIS_HANDLE MacAdapterContext,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+
+#ifdef LTREQ_H_LOCALS
+
+#define LT_VENDOR_DESCR "Daystar Digital LT200"
+#define LT_VENDOR_ID {0xFF,0xFF,0xFF}
+#define LT_LINK_SPEED 2300 // 230K bps in 100bps units
+#define LT_OID_INDEX_MASK 0x000000FF
+
+STATIC
+NDIS_OID LtGlobalSupportedOids[] = {
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+
+ OID_GEN_DIRECTED_BYTES_XMIT,
+ OID_GEN_DIRECTED_FRAMES_XMIT,
+ OID_GEN_BROADCAST_BYTES_XMIT,
+ OID_GEN_BROADCAST_FRAMES_XMIT,
+ OID_GEN_DIRECTED_BYTES_RCV,
+ OID_GEN_DIRECTED_FRAMES_RCV,
+ OID_GEN_BROADCAST_BYTES_RCV,
+ OID_GEN_BROADCAST_FRAMES_RCV,
+
+ OID_GEN_RCV_CRC_ERROR,
+ OID_GEN_TRANSMIT_QUEUE_LENGTH,
+
+ OID_LTALK_CURRENT_NODE_ID,
+
+ OID_LTALK_IN_BROADCASTS,
+ OID_LTALK_IN_LENGTH_ERRORS,
+
+ OID_LTALK_OUT_NO_HANDLERS,
+ OID_LTALK_DEFERS
+
+ };
+
+// Note we do not support OID's which we cannot get the statistics
+// for from the FIRMWARE, or that we cannot collect ourselves!
+
+STATIC
+NDIS_OID LtProtocolSupportedOids[] = {
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+
+ OID_LTALK_CURRENT_NODE_ID
+
+ };
+
+
+STATIC
+NDIS_STATUS
+LtReqQueryInformation(
+ IN PLT_ADAPTER Adapter,
+ IN PLT_OPEN Open,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN INT InformationBufferLength,
+ IN PUINT BytesWritten,
+ IN PUINT BytesNeeded,
+ IN BOOLEAN Global
+ );
+
+STATIC
+NDIS_STATUS
+LtReqSetInformation(
+ IN PLT_ADAPTER Adapter,
+ IN PLT_OPEN Open,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN INT InformationBufferLength,
+ IN PUINT BytesRead,
+ IN PUINT BytesNeeded
+ );
+
+STATIC
+VOID
+LtReqAdjustLookAhead(
+ OUT PUINT GlobalLookaheadSize,
+ IN PLIST_ENTRY BindingList
+ );
+
+
+#endif // LTREQ_H_LOCALS
+
+#endif // _LTREQ_H_
diff --git a/private/ntos/ndis/lt200/ltreset.c b/private/ntos/ndis/lt200/ltreset.c
new file mode 100644
index 000000000..c64c9e305
--- /dev/null
+++ b/private/ntos/ndis/lt200/ltreset.c
@@ -0,0 +1,344 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ltreset.c
+
+Abstract:
+
+ This module contains
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+ Stephen Hou (stephh@microsoft.com)
+
+Revision History:
+ 19 Jun 1992 Initial Version (dch@pacvax.pacersoft.com)
+
+Notes: Tab stop: 4
+--*/
+
+#define LTRESET_H_LOCALS
+#include "ltmain.h"
+#include "ltreset.h"
+#include "ltfirm.h"
+#include "lttimer.h"
+
+// Define file id for errorlogging
+#define FILENUM LTRESET
+
+
+NDIS_STATUS
+LtReset(
+ IN NDIS_HANDLE MacBindingHandle
+ )
+/*++
+
+Routine Description:
+
+ called by NDIS to reset the adapter
+
+Arguments:
+
+ MacBindingHandle : context passed back in OpenAdapter
+
+Return Value:
+
+ NDIS_STATUS_PENDING : if the reset successfully pended
+ and waiting to be completed
+ NDIS_STATUS_RESET_IN_PROGRESS : if the adapter is current being reset
+ NDIS_STATUS_ADAPTER_REMOVED : if the adapter has been closed
+ NDIS_STATUS_CLOSING : if the binding request the reset is closing
+
+--*/
+{
+ NDIS_STATUS Status;
+
+ BOOLEAN TimerCancelled = FALSE;
+ PLT_ADAPTER Adapter = ((PLT_OPEN)MacBindingHandle)->LtAdapter;
+ PLT_OPEN Open = (PLT_OPEN)MacBindingHandle;
+
+
+ LtReferenceBinding(Open,&Status);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (Adapter->Flags & ADAPTER_RESET_IN_PROGRESS)
+ {
+ Status = NDIS_STATUS_RESET_IN_PROGRESS;
+ }
+
+ if (Adapter->Flags & ADAPTER_CLOSING)
+ {
+ Status = NDIS_STATUS_ADAPTER_REMOVED;
+ }
+
+ if (Open->Flags & BINDING_CLOSING)
+ {
+ Status = NDIS_STATUS_CLOSING;
+ }
+ }
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ LtDeReferenceBinding(Open);
+ return(Status);
+ }
+
+ // kill the timer so we don't get any conflicts when trying to reset the card
+ NdisCancelTimer(&Adapter->PollingTimer, &TimerCancelled);
+ if (TimerCancelled)
+ {
+ LtDeReferenceAdapter(Adapter);
+ }
+
+ // indicate the start of the reset to all bindings
+ LtResetSignalBindings(
+ Adapter,
+ NDIS_STATUS_RESET_START);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ // set the reset in progress flag
+ Adapter->Flags ^= ADAPTER_RESET_IN_PROGRESS;
+ Adapter->ResetOwner = Open;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ LtResetSetupForReset(Adapter);
+
+ // intstantiate the reference for the timer
+ // too late to do anything other than return
+ // success since the reset's done. no problem
+ // as long as the adapter can't close while the
+ // reset is in progress.
+ LtReferenceAdapter(Adapter,&Status);
+
+ // card's essentially reset, restart the timer
+ NdisSetTimer(&Adapter->PollingTimer, LT_POLLING_TIME);
+
+ return(NDIS_STATUS_PENDING);
+}
+
+
+VOID
+LtResetComplete(
+ PLT_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ completes the pending reset
+
+Arguments:
+
+ Adapter : pointer to the logical adapter
+
+Return Value:
+
+ none
+
+--*/
+{
+ NdisAcquireSpinLock(&Adapter->Lock);
+ // flip the reset in progress flags
+ Adapter->Flags ^= ADAPTER_RESET_IN_PROGRESS;
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ LtResetSignalBindings(
+ Adapter,
+ NDIS_STATUS_RESET_END);
+
+ NdisCompleteReset(
+ (Adapter->ResetOwner)->NdisBindingContext,
+ NDIS_STATUS_SUCCESS);
+
+ LtDeReferenceBinding(Adapter->ResetOwner);
+}
+
+
+STATIC
+VOID
+LtResetSetupForReset(
+ IN PLT_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ Kills off anything in the transmit, receive and loopback queues and
+ returns the appropriate status. It then resets the card and acquires
+ a new NodeId
+
+Arguments:
+
+ Adapter : pointer to the logical adapter
+
+Return Value:
+
+ none
+
+--*/
+{
+ PLIST_ENTRY CurrentPacketLink;
+ PLT_PACKET_RESERVED PacketReserved;
+ PRECV_DESC RecvDesc;
+ UINT PacketLength;
+ PNDIS_PACKET Packet;
+ PLT_OPEN Open;
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ // remove everything from the receive list and return it to the free list
+ while(!IsListEmpty(&Adapter->Receive)){
+
+ CurrentPacketLink = RemoveHeadList(&Adapter->Receive);
+ RecvDesc = CONTAINING_RECORD(
+ CurrentPacketLink,
+ RECV_DESC,
+ Linkage);
+
+ PacketLength = RecvDesc->BufferLength;
+
+ NdisFreeMemory(
+ RecvDesc,
+ sizeof(RecvDesc)+PacketLength,
+ 0);
+
+ }
+
+ // complete any pending transmits
+ while(!IsListEmpty(&Adapter->Transmit))
+ {
+ CurrentPacketLink = RemoveHeadList(&Adapter->Transmit);
+
+ PacketReserved = CONTAINING_RECORD(
+ CurrentPacketLink,
+ LT_PACKET_RESERVED,
+ Linkage);
+
+ Packet = CONTAINING_RECORD(
+ PacketReserved,
+ NDIS_PACKET,
+ MacReserved);
+
+ Open = PacketReserved->MacBindingHandle;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteSend(
+ Open->NdisBindingContext,
+ Packet,
+ NDIS_STATUS_REQUEST_ABORTED);
+
+ // decrement the count instantiated by the send
+ LtDeReferenceBinding(Open);
+ LtDeReferenceAdapter(Adapter);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ }
+
+ // complete anything on the loopback queue
+ while(!IsListEmpty(&Adapter->LoopBack))
+ {
+ CurrentPacketLink = RemoveHeadList(&Adapter->LoopBack);
+
+ PacketReserved = CONTAINING_RECORD(
+ CurrentPacketLink,
+ LT_PACKET_RESERVED,
+ Linkage);
+
+ Packet = CONTAINING_RECORD(
+ PacketReserved,
+ NDIS_PACKET,
+ MacReserved);
+
+ Open = PacketReserved->MacBindingHandle;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteSend(
+ Open->NdisBindingContext,
+ Packet,
+ NDIS_STATUS_REQUEST_ABORTED);
+
+ // decrement the count instantiated by the send
+ LtDeReferenceBinding(Open);
+ LtDeReferenceAdapter(Adapter);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+ LtFirmInitialize(Adapter, Adapter->NodeId);
+}
+
+
+STATIC
+VOID
+LtResetSignalBindings(
+ PLT_ADAPTER Adapter,
+ NDIS_STATUS StatusToSignal
+ )
+/*++
+
+Routine Description:
+
+ Loops through all bindings and indicates the status passed
+
+Arguments:
+
+ Adapter : pointer to the logical adapter
+ StatusToSignal : status to indicate to all bindings associated with the adapter
+
+Return Value:
+
+ none
+
+--*/
+{
+ PLT_OPEN Open;
+ PLIST_ENTRY CurrentLink;
+ NDIS_STATUS Status;
+
+ CurrentLink = Adapter->OpenBindings.Flink;
+ while (CurrentLink != &Adapter->OpenBindings)
+ {
+ Open = CONTAINING_RECORD(
+ CurrentLink,
+ LT_OPEN,
+ Linkage
+ );
+
+ // skip the binding if it's closing
+ if (Open->Flags & BINDING_CLOSING)
+ {
+ CurrentLink = CurrentLink->Flink;
+ continue;
+ }
+
+ // increment the reference count while in the binding
+ // only return we can get back is that the binding is
+ // closing down, but this isn't a problem since we won't
+ // reach this statement if that's true because of the prior
+ // statements
+ LtReferenceBinding(Open,&Status);
+
+ NdisIndicateStatus(
+ Open->NdisBindingContext,
+ StatusToSignal,
+ 0,
+ 0);
+
+ // decrement refcount now that we've finished with that binding
+ LtDeReferenceBinding(Open);
+ CurrentLink = CurrentLink->Flink;
+ }
+}
+
+
+
diff --git a/private/ntos/ndis/lt200/ltreset.h b/private/ntos/ndis/lt200/ltreset.h
new file mode 100644
index 000000000..cc998daf4
--- /dev/null
+++ b/private/ntos/ndis/lt200/ltreset.h
@@ -0,0 +1,58 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ltreset.h
+
+Abstract:
+
+ This module contains
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+ Stephen Hou (stephh@microsoft.com)
+
+Revision History:
+ 19 Jun 1992 Initial Version (dch@pacvax.pacersoft.com)
+
+Notes: Tab stop: 4
+--*/
+
+#ifndef _LTRESET_H_
+#define _LTRESET_H_
+
+
+NDIS_STATUS
+LtReset(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+VOID
+LtResetComplete(
+ PLT_ADAPTER Adapter
+ );
+
+
+#ifdef LTRESET_H_LOCALS
+
+
+STATIC
+VOID
+LtResetSetupForReset(
+ IN PLT_ADAPTER Adapter
+ );
+
+STATIC
+VOID
+LtResetSignalBindings(
+ PLT_ADAPTER Adapter,
+ NDIS_STATUS StatusToSignal
+ );
+
+
+#endif // LTRESET_H_LOCALS
+
+#endif // _LTRESET_H_
diff --git a/private/ntos/ndis/lt200/ltsend.c b/private/ntos/ndis/lt200/ltsend.c
new file mode 100644
index 000000000..f3246ba3b
--- /dev/null
+++ b/private/ntos/ndis/lt200/ltsend.c
@@ -0,0 +1,342 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ltsend.c
+
+Abstract:
+
+ This module contains the send queue processing routines.
+
+Author:
+
+ Stephen Hou (stephh@microsoft.com)
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+
+Revision History:
+ 19 Jun 1992 Initial Version (dch@pacvax.pacersoft.com)
+
+Notes: Tab stop: 4
+--*/
+
+#define LTSEND_H_LOCALS
+#include "ltmain.h"
+
+// Define file id for errorlogging
+#define FILENUM LTSEND
+
+
+NDIS_STATUS
+LtSend(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to send a packet.
+
+Arguments:
+
+ MacBindingHandle : Passed as context to NDIS in OpenAdapter.
+ Packet : Ndis Packet to send.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS : If successful, else error.
+
+--*/
+{
+ NDIS_STATUS Status;
+ UINT PacketSize;
+
+ BOOLEAN DerefAdapter = FALSE;
+ PLT_OPEN Binding = (PLT_OPEN)MacBindingHandle;
+ PLT_ADAPTER Adapter = Binding->LtAdapter;
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_ENTRY,
+ ("LtSend: Entering...\n"));
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ // This will go away, when the entry is taken off the adapter transmit queue
+ LtReferenceAdapterNonInterlock(Adapter, &Status);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ DerefAdapter = TRUE;
+ do
+ {
+ // Check to see if there is a reset in progress
+ if (Adapter->Flags & ADAPTER_RESET_IN_PROGRESS)
+ {
+ Status = NDIS_STATUS_RESET_IN_PROGRESS;
+ break;
+ }
+
+ // If binding is closing down, we get out.
+ if (Binding->Flags & BINDING_CLOSING)
+ {
+ Status = NDIS_STATUS_CLOSING;
+ break;
+ }
+
+ // Try to reference the binding. This will go away after
+ // the send completes.
+ LtReferenceBindingNonInterlock(Binding, &Status);
+
+ } while (FALSE);
+ }
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ if (DerefAdapter)
+ LtDeReferenceAdapter(Adapter);
+
+ return(Status);
+ }
+
+
+ do
+ {
+ Status = NDIS_STATUS_PENDING;
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ NULL,
+ NULL,
+ &PacketSize);
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("LtSend: Packet %lx Length %lx\n", Packet, PacketSize));
+
+ if ((PacketSize < LT_MIN_PACKET_SIZE ) ||
+ (PacketSize > LT_MAX_PACKET_SIZE)) {
+
+ Status = NDIS_STATUS_RESOURCES;
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ ++Adapter->GeneralMandatory[GM_TRANSMIT_BAD];
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ break;
+
+ }
+ else
+ {
+ PLT_PACKET_RESERVED Reserved = (PLT_PACKET_RESERVED)Packet->MacReserved;
+
+ // Initialize the reserved portion
+ Reserved->MacBindingHandle = MacBindingHandle;
+ InitializeListHead(&Reserved->Linkage);
+
+ if (LtUtilsPacketType(Packet) != LT_LOOPBACK)
+ {
+ // The packet needs to go onto the wire.
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("LtSend: Queuing %lx on transmit q\n", Packet));
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ InsertTailList(&Adapter->Transmit, &Reserved->Linkage);
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ }
+ else
+ {
+ // Put on the loopback queue
+ NdisAcquireSpinLock(&Adapter->Lock);
+ InsertTailList(&Adapter->LoopBack, &Reserved->Linkage);
+
+ // Since we are doing a Loopback send, lets add up the stats now.
+ ++Adapter->GeneralMandatory[GM_TRANSMIT_GOOD];
+ ++Adapter->GeneralOptionalFrameCount[GO_DIRECTED_TRANSMITS];
+
+ Adapter ->GeneralOptionalByteCount[GO_DIRECTED_TRANSMITS] =
+ LtAddLongToLargeInteger(
+ Adapter ->GeneralOptionalByteCount[GO_DIRECTED_TRANSMITS],
+ PacketSize);
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+ }
+ }
+
+ } while (FALSE);
+
+ // Process send queue. We also process the send queue in the timer
+ // in case, some sends have pended and ndis does no further sends.
+ // !!! Send's get very high priority. In total, the queue is processed
+ // !!! three times, twice in the timer and once in LtSend
+ LtSendProcessQueue(Adapter);
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ // Send unsuccessful. Remove the binding reference and adapter reference
+ LtDeReferenceBinding(Binding);
+ LtDeReferenceAdapter(Adapter);
+ }
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_ENTRY,
+ ("LtSend: Leaving...\n"));
+
+ return Status;
+}
+
+
+
+VOID
+LtSendProcessQueue(
+ IN PLT_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ SendProcessQueue processes, yeah, you guessed it. The SendQueue.
+
+Arguments:
+
+ Adapter : Pointer to the adapter structure.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_PACKET Packet;
+ PLT_PACKET_RESERVED Reserved;
+ PLT_OPEN Binding;
+ UINT BufferCount, TotalLength, BufLength;
+ PNDIS_BUFFER Buffer;
+ UCHAR Data;
+ PUCHAR Address;
+ PLIST_ENTRY p;
+
+ // Use this to avoid multiple threads from calling this routine.
+ static BOOLEAN QueueActive = FALSE;
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_ENTRY,
+ ("LtSendProcessTransmit: Entering...\n"));
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ if (QueueActive)
+ {
+ NdisReleaseSpinLock(&Adapter->Lock);
+ return;
+ }
+ QueueActive = TRUE;
+
+ while((!IsListEmpty(&Adapter->Transmit)) &&
+ ((Adapter->Flags & ADAPTER_RESET_IN_PROGRESS) == 0))
+ {
+ // Ok, Can we trasnmit a packet now?
+ NdisRawReadPortUchar(SC_PORT, &Data);
+
+ if ((Data & TX_READY) == 0)
+ {
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_WARN,
+ ("LtSendProcessTransmit: Media not ready...\n"));
+
+ Adapter->MediaOptional[MO_TRANSMIT_DEFERS]++;
+ break;
+ }
+
+ p = RemoveHeadList(&Adapter->Transmit);
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ Packet = CONTAINING_RECORD(
+ p,
+ NDIS_PACKET,
+ MacReserved);
+
+ Reserved = (PLT_PACKET_RESERVED)Packet->MacReserved;
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("LtSendProcessTransmit: Dequeued %lx-%lx\n", Packet, Reserved));
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ &BufferCount,
+ &Buffer,
+ &TotalLength);
+
+ // Ok, Output the packet length.
+ NdisRawWritePortUchar(XFER_PORT, (UCHAR)(TotalLength & 0xFF));
+
+ NdisRawWritePortUchar(XFER_PORT, (UCHAR)((TotalLength >> 8) & 0xFF));
+
+ NdisRawWritePortUchar(XFER_PORT, (UCHAR)LT_CMD_LAP_WRITE);
+
+ while (BufferCount-- > 0)
+ {
+ NdisQueryBuffer(
+ Buffer,
+ &Address,
+ &BufLength);
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("LtSendProcessTransmit: Buffer #%d\n", BufferCount));
+
+ NdisRawWritePortBufferUchar(XFER_PORT,
+ Address,
+ BufLength);
+
+ NdisGetNextBuffer(Buffer, &Buffer);
+ }
+
+ if (LtUtilsPacketType(Packet) == LT_DIRECTED)
+ {
+ Binding = (PLT_OPEN)Reserved->MacBindingHandle;
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("LtSendProcessTransmit: Process xmit: Packet %p\n", Packet));
+
+ NdisCompleteSend(
+ Binding->NdisBindingContext,
+ Packet,
+ NDIS_STATUS_SUCCESS);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ ++Adapter->GeneralMandatory[GM_TRANSMIT_GOOD];
+ ++Adapter->GeneralOptionalFrameCount[GO_DIRECTED_TRANSMITS];
+ Adapter ->GeneralOptionalByteCount[GO_DIRECTED_TRANSMITS] =
+ LtAddLongToLargeInteger(
+ Adapter ->GeneralOptionalByteCount[GO_DIRECTED_TRANSMITS],
+ TotalLength);
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ // Dereference the adapter and the binding for this completed
+ // send.
+ LtDeReferenceBinding(Binding);
+ LtDeReferenceAdapter(Adapter);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ }
+ else
+ {
+ // This was a broadcast, loop it back.
+ NdisAcquireSpinLock(&Adapter->Lock);
+ ++Adapter->GeneralOptionalFrameCount[GO_BROADCAST_TRANSMITS];
+ ++Adapter->GeneralMandatory[GM_TRANSMIT_GOOD];
+ Adapter ->GeneralOptionalByteCount[GO_BROADCAST_TRANSMITS] =
+ LtAddLongToLargeInteger(
+ Adapter ->GeneralOptionalByteCount[GO_BROADCAST_TRANSMITS],
+ TotalLength);
+ InsertTailList(&Adapter->LoopBack, &Reserved->Linkage);
+ }
+ }
+
+ QueueActive = FALSE;
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_ENTRY,
+ ("LtSendProcessTransmit: Leaving...\n"));
+
+ return;
+}
diff --git a/private/ntos/ndis/lt200/ltsend.h b/private/ntos/ndis/lt200/ltsend.h
new file mode 100644
index 000000000..451722f5c
--- /dev/null
+++ b/private/ntos/ndis/lt200/ltsend.h
@@ -0,0 +1,43 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ltsend.h
+
+Abstract:
+
+ This module contains the send related definitions.
+
+Author:
+
+ Stephen Hou (stephh@microsoft.com)
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+
+Revision History:
+ 19 Jun 1992 Initial Version (dch@pacvax.pacersoft.com)
+
+Notes: Tab stop: 4
+--*/
+
+#ifndef _LTSEND_H_
+#define _LTSEND_H_
+
+NDIS_STATUS
+LtSend(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_PACKET Packet);
+
+VOID
+LtSendProcessQueue(
+ IN PLT_ADAPTER Adapter);
+
+
+#ifdef LTSEND_H_LOCALS
+
+#endif // LTSEND_H_LOCALS
+
+
+#endif // _LTSEND_H_
+
diff --git a/private/ntos/ndis/lt200/ltsft.h b/private/ntos/ndis/lt200/ltsft.h
new file mode 100644
index 000000000..9d2b0081b
--- /dev/null
+++ b/private/ntos/ndis/lt200/ltsft.h
@@ -0,0 +1,223 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ltsft.h
+
+Abstract:
+
+ This module contains the main adapter/binding definitions and all
+ other main definitions.
+
+Author:
+
+ Stephen Hou (stephh@microsoft.com)
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+
+Revision History:
+ 19 Jun 1992 Initial Version (dch@pacvax.pacersoft.com)
+
+Notes: Tab stop: 4
+--*/
+
+#ifndef _LTSFT_
+#define _LTSFT_
+
+
+// We use STATIC to define procedures that will be static in the
+// final build but which we now make extern to allow them to be
+// debugged.
+#if DBG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+
+#define NDIS_MAJOR_VERSION 3
+#define NDIS_MINOR_VERSION 0
+
+#define LT_MAJOR_VERSION 2
+#define LT_MINOR_VERSION 0
+
+#define LT_MAX_INDICATE_SIZE 603
+#define LT_MAX_PACKET_SIZE 603
+#define LT_MIN_PACKET_SIZE 3
+#define LT_MIN_INDICATE_SIZE 13
+
+// Offset into packet from where the datagram begins.
+#define LT_LINK_HEADER_LENGTH 3
+#define LT_DGRAM_OFFSET (LT_LINK_HEADER_LENGTH)
+
+// Localtalk separates node id's into two classes, server/client. We attempt
+// to get ours in the Server Class.
+#define LT_MAX_CLIENT_NODE_ID 127
+#define LT_MIN_SERVER_NODE_ID 128
+#define LT_BROADCAST_NODE_ID 0xFF
+
+// Indexes in the GeneralMandatory array.
+#define GM_TRANSMIT_GOOD 0x00
+#define GM_RECEIVE_GOOD 0x01
+#define GM_TRANSMIT_BAD 0x02
+#define GM_RECEIVE_BAD 0x03
+#define GM_RECEIVE_NO_BUFFER 0x04
+#define GM_ARRAY_SIZE 0x05
+
+// Indexes in the GeneralOptional array. There are
+// two sections, the ones up to COUNT_ARRAY_SIZE
+// have entries for number (4 bytes) and number of
+// bytes (8 bytes), the rest are a normal array.
+#define GO_DIRECTED_TRANSMITS 0x00
+#define GO_MULTICAST_TRANSMITS 0x01
+#define GO_BROADCAST_TRANSMITS 0x02
+#define GO_DIRECTED_RECEIVES 0x03
+#define GO_MULTICAST_RECEIVES 0x04
+#define GO_BROADCAST_RECEIVES 0x05
+#define GO_COUNT_ARRAY_SIZE 0x06
+
+#define GO_ARRAY_START 0x0C
+#define GO_RECEIVE_CRC 0x0C
+#define GO_TRANSMIT_QUEUE_LENGTH 0x0D
+#define GO_ARRAY_SIZE 0x0E
+
+// Indexes in the MediaMandatory array.
+#define MM_IN_BROADCASTS 0x00
+#define MM_IN_LENGTH_ERRORS 0x01
+#define MM_ARRAY_SIZE 0x02
+
+// Indexes in the MediaOptional array.
+#define MO_NO_HANDLERS 0x00
+#define MO_TRANSMIT_MAX_COLLISIONS 0x01
+#define MO_TRANSMIT_DEFERS 0x02
+#define MO_NO_DATA_ERRORS 0x03
+#define MO_RANDOM_CTS_ERRORS 0x04
+#define MO_FCS_ERRORS 0x05
+#define MO_ARRAY_SIZE 0x06
+
+// Adapter States/Conditions.
+#define ADAPTER_OPEN 0x00000001
+#define ADAPTER_CLOSING 0x00000002
+#define ADAPTER_NODE_ID_VALID 0x00000004
+#define ADAPTER_XMIT_IN_PROGRESS 0x00000008
+#define ADAPTER_REQ_IN_PROGRESS 0x00000010
+#define ADAPTER_RESET_IN_PROGRESS 0x00000020
+#define ADAPTER_QUEUE_RECV_COMPLETION 0x00000040
+#define ADAPTER_QUEUED_RECV_COMPLETION 0x00000080
+#define ADAPTER_TIMER_QUEUED 0x00000100
+
+
+typedef struct _LT_ADAPTER {
+
+#if DBG
+ ULONG Signature;
+#endif
+
+ ULONG Flags;
+ ULONG RefCount;
+ NDIS_SPIN_LOCK Lock;
+
+ // Node ID. Localtalk acquires a node id dynamically.
+ UCHAR NodeId;
+ UCHAR PramNodeId;
+
+ // List of Bindings
+ UINT OpenCount;
+ LIST_ENTRY OpenBindings;
+
+ // We have a Polling timer which will handle all the work that this
+ // driver needs to do.
+ NDIS_TIMER PollingTimer;
+
+ // Hardware settings on the card. From the configuration manager
+ ULONG MappedIoBaseAddr;
+ NDIS_INTERFACE_TYPE BusType;
+
+ // Handles for our adapter and the MAC driver itself.
+ NDIS_HANDLE NdisMacHandle;
+ NDIS_HANDLE NdisAdapterHandle;
+
+ // Reset processing.
+ struct _LT_OPEN * ResetOwner;
+
+ // Queues
+ LIST_ENTRY LoopBack;
+ LIST_ENTRY Transmit;
+ LIST_ENTRY Receive;
+ LIST_ENTRY Request;
+
+ // Current loopback packet
+ PNDIS_PACKET CurrentLoopbackPacket;
+
+ // Statistics
+ ULONG GlobalPacketFilter;
+ ULONG GlobalLookAheadSize;
+ LT_STATUS_RESPONSE LastCardStatusResponse;
+ ULONG GeneralMandatory[GM_ARRAY_SIZE];
+ LARGE_INTEGER GeneralOptionalByteCount[GO_COUNT_ARRAY_SIZE];
+ ULONG GeneralOptionalFrameCount[GO_COUNT_ARRAY_SIZE];
+ ULONG GeneralOptional[GO_ARRAY_SIZE - GO_ARRAY_START];
+ ULONG MediaMandatory[MM_ARRAY_SIZE];
+ ULONG MediaOptional[MO_ARRAY_SIZE];
+
+} LT_ADAPTER, *PLT_ADAPTER;
+
+
+
+// Binding states
+#define BINDING_OPEN 0x00000001
+#define BINDING_CLOSING 0x00000002
+#define BINDING_DO_RECV_COMPLETION 0x00000004
+
+typedef struct _LT_OPEN {
+
+#if DBG
+ ULONG Signature;
+#endif
+
+ ULONG Flags;
+ ULONG RefCount;
+
+ LIST_ENTRY Linkage;
+ PLT_ADAPTER LtAdapter;
+
+ NDIS_HANDLE NdisBindingContext;
+ UINT CurrentLookAheadSize;
+ UINT CurrentPacketFilter;
+
+} LT_OPEN, *PLT_OPEN;
+
+
+#define LT_DIRECTED 1
+#define LT_BROADCAST 2
+#define LT_LOOPBACK 3
+
+
+// This record type is inserted into the MacReserved portion
+// of the packet header when the packet is going through the
+// staged allocation of buffer space prior to the actual send.
+typedef struct _LT_PACKET_RESERVED {
+
+ // This must be the first entry so we can use CONTAINING_RECORD
+ // to get back to the packet.
+ LIST_ENTRY Linkage;
+ NDIS_HANDLE MacBindingHandle;
+
+} LT_PACKET_RESERVED, *PLT_PACKET_RESERVED;
+
+
+// This structure is used in the MacReserved field of
+// an NDIS_REQUEST_BLOCK, passed in during multicast
+// address/packet filter operations.
+typedef struct _LT_REQUEST_RESERVED {
+ LIST_ENTRY RequestList;
+ PLT_OPEN * OpenBlock;
+} LT_REQUEST_RESERVED, *PLT_REQUEST_RESERVED;
+
+#ifdef LTSFT_LOCALS
+
+#endif // LTSFT_LOCALS
+
+
+#endif // _LTSFT_
diff --git a/private/ntos/ndis/lt200/lttimer.c b/private/ntos/ndis/lt200/lttimer.c
new file mode 100644
index 000000000..99186d552
--- /dev/null
+++ b/private/ntos/ndis/lt200/lttimer.c
@@ -0,0 +1,280 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ lttimer.c
+
+Abstract:
+
+ This module contains the polling timer processing routines.
+
+Author:
+
+ Stephen Hou (stephh@microsoft.com)
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+
+Revision History:
+ 19 Jun 1992 Initial Version (dch@pacvax.pacersoft.com)
+
+Notes: Tab stop: 4
+--*/
+
+#define LTTIMER_H_LOCALS
+#include "ltmain.h"
+#include "lttimer.h"
+#include "ltreset.h"
+
+
+// Define file id for errorlogging
+#define FILENUM LTTIMER
+
+
+VOID
+LtTimerPoll(
+ IN PVOID SystemSpecific1,
+ IN PVOID Context,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+/*++
+
+Routine Description:
+
+ This is the polling timer routine. It will receive data from the card
+ and process all the queues that are there- send/receive/loopback. NOTE:
+ Priority must be given to sends.
+
+Arguments:
+
+ Context : Pointer to the Adapter structure.
+ All other parameters as described in NDIS 3.0
+
+Return Value:
+
+ None.
+
+--*/
+{
+ USHORT ResponseLength;
+ UCHAR Data, ResponseType;
+ LT_INIT_RESPONSE InitPacket;
+ PRECV_DESC RecvDesc;
+ PUCHAR RecvPkt;
+ NDIS_STATUS Status;
+
+ BOOLEAN ProcessReset = FALSE;
+
+ BOOLEAN ClearCardData = FALSE;
+ PLT_ADAPTER Adapter = (PLT_ADAPTER)Context;
+
+ DBGPRINT(DBG_COMP_TIMER, DBG_LEVEL_LOW,
+ ("LtTimerPoll: Entering...\n"));
+
+ LtReferenceAdapter(Adapter, &Status);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ // We are probably shutting down.
+ ASSERTMSG("LtTimerPoll: Adapter not closing!\n",
+ ((Adapter->Flags & ADAPTER_CLOSING) == 0));
+
+ // Remove the reference we added at timer set.
+ LtDeReferenceAdapter(Adapter);
+ return;
+ }
+
+ // BUGBUG: Verify reset handling.
+
+ // !!! Send's get very high priority. In total, the queue is processed
+ // !!! three times, twice in the timer and once in LtSend
+ LtSendProcessQueue(Adapter);
+
+ // Check for receive data
+ NdisRawReadPortUchar(SC_PORT, &Data);
+
+ if (Data & RX_READY)
+ {
+ // Get the length of the response on the card
+ NdisRawReadPortUchar(XFER_PORT, &Data);
+
+ ResponseLength = (USHORT)(Data & 0xFF);
+
+ NdisRawReadPortUchar(XFER_PORT, &Data);
+
+ ResponseLength |= (Data << 8);
+
+ // Now get the IO code.
+ NdisRawReadPortUchar(XFER_PORT, &ResponseType);
+
+ DBGPRINT(DBG_COMP_TIMER, DBG_LEVEL_INFO,
+ ("LtPoll: RespType = %x, RespLength = %d\n",
+ ResponseType, ResponseLength));
+
+ switch (ResponseType)
+ {
+ case LT_RSP_LAP_INIT:
+
+ if (ResponseLength != sizeof(LT_INIT_RESPONSE))
+ {
+ DBGPRINT(DBG_COMP_TIMER, DBG_LEVEL_ERR,
+ ("LtTimerPoll: Bad response length %lx! \n", ResponseLength));
+
+ ClearCardData = TRUE;
+ }
+ break;
+
+ case LT_RSP_LAP_FRAME:
+
+ // Verify the frame is of the maximum packet size possible.
+ if (ResponseLength > LT_MAX_PACKET_SIZE)
+ {
+ DBGPRINT(DBG_COMP_TIMER, DBG_LEVEL_ERR,
+ ("LtTimerPoll: Bad packet length %lx! \n", ResponseLength));
+
+ // Keep track of number of bad receives
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+ ++Adapter->GeneralMandatory[GM_RECEIVE_BAD];
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ ClearCardData = TRUE;
+ break;
+ }
+
+ // Allocate a receive buffer descriptor for the packet.
+ NdisAllocateMemory(
+ &RecvDesc,
+ (UINT)(sizeof(RECV_DESC)+ResponseLength),
+ 0,
+ LtNdisPhyAddr);
+
+ if (RecvDesc == NULL)
+ {
+ // Keep track of the number of times we couldnt get a buffer.
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+ ++Adapter->GeneralMandatory[GM_RECEIVE_NO_BUFFER];
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ ClearCardData = TRUE;
+ break;
+ }
+
+
+ // Get a pointer to the receive packet storage.
+ RecvPkt = (PUCHAR)((PUCHAR)RecvDesc + sizeof(RECV_DESC));
+
+ NdisRawReadPortBufferUchar(XFER_PORT,
+ RecvPkt,
+ ResponseLength);
+
+ RecvDesc->Broadcast = IS_PACKET_BROADCAST(RecvPkt);
+ RecvDesc->BufferLength = ResponseLength;
+
+ DBGPRINT(DBG_COMP_TIMER, DBG_LEVEL_INFO,
+ ("LtTimerPoll: Recd Pkt Desc %lx Pkt %lx! \n",
+ RecvDesc, RecvPkt));
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+ ++Adapter->GeneralMandatory[GM_RECEIVE_GOOD];
+ if (RecvDesc->Broadcast)
+ {
+ ++Adapter->GeneralOptionalFrameCount[GO_BROADCAST_RECEIVES];
+ LtAddLongToLargeInteger(
+ Adapter->GeneralOptionalByteCount[GO_BROADCAST_RECEIVES],
+ RecvDesc->BufferLength);
+
+ Adapter->MediaMandatory[MM_IN_BROADCASTS]++;
+
+ }
+ else
+ {
+ ++Adapter->GeneralOptionalFrameCount[GO_DIRECTED_RECEIVES];
+ LtAddLongToLargeInteger(
+ Adapter->GeneralOptionalByteCount[GO_DIRECTED_RECEIVES],
+ RecvDesc->BufferLength);
+ }
+
+ InsertTailList(
+ &Adapter->Receive,
+ &RecvDesc->Linkage);
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+ break;
+
+ case LT_RSP_STATUS:
+
+ if (ResponseLength != sizeof(LT_STATUS_RESPONSE))
+ {
+ ClearCardData = TRUE;
+ break;
+ }
+
+ NdisRawReadPortBufferUchar(XFER_PORT,
+ (PUCHAR)&Adapter->LastCardStatusResponse,
+ ResponseLength);
+
+ DBGPRINT(DBG_COMP_TIMER, DBG_LEVEL_INFO,
+ ("Node ID = %lx, Rom Ver = %lx, FirmWare Ver %lx\n",
+ Adapter->LastCardStatusResponse.NodeId,
+ Adapter->LastCardStatusResponse.RomVer,
+ Adapter->LastCardStatusResponse.SwVer));
+
+ break;
+
+ default:
+ DBGPRINT(DBG_COMP_TIMER, DBG_LEVEL_ERR,
+ ("LtTimerPoll: Unknown response type %lx\n", ResponseType));
+
+ ClearCardData = TRUE;
+ break;
+ }
+ }
+
+ if (ClearCardData)
+ {
+ DBGPRINT(DBG_COMP_TIMER, DBG_LEVEL_WARN,
+ ("LtTimerPoll: Clearing Card of response %d\n", ResponseLength));
+
+ while (ResponseLength-- > 0 )
+ {
+ NdisRawReadPortUchar(XFER_PORT, &Data);
+ }
+ }
+
+ // Call all the processing routines if their respective queues are
+ // not empty!
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ ASSERT (Adapter->Flags & ADAPTER_NODE_ID_VALID);
+
+ if (Adapter->Flags & ADAPTER_RESET_IN_PROGRESS)
+ {
+ ProcessReset = TRUE;
+ }
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ if (ProcessReset)
+ {
+ LtResetComplete(Adapter);
+ }
+
+ // Process our receive queue.
+ LtRecvProcessQueue(Adapter);
+
+ // Process send queue as processing receives would have entailed
+ // some sends.
+ // NOTE: Process LoopQueue after SendQueue as the Send Packet
+ // goes into the loop queue if it is a broadcast, after
+ // being sent out on the net.
+ LtSendProcessQueue(Adapter);
+ LtLoopProcessQueue(Adapter);
+
+ DBGPRINT(DBG_COMP_TIMER, DBG_LEVEL_LOW,
+ ("LtTimerPoll: Setting timer and Leaving...\n"));
+
+ // Re-arm the timer
+ NdisSetTimer(&Adapter->PollingTimer, LT_POLLING_TIME);
+
+ // Remove the reference we added at the beginning of this routine.
+ LtDeReferenceAdapter(Adapter);
+}
diff --git a/private/ntos/ndis/lt200/lttimer.h b/private/ntos/ndis/lt200/lttimer.h
new file mode 100644
index 000000000..ef6f86248
--- /dev/null
+++ b/private/ntos/ndis/lt200/lttimer.h
@@ -0,0 +1,46 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ lttimer.h
+
+Abstract:
+
+ This module contains the polling timer definitions
+
+Author:
+
+ Stephen Hou (stephh@microsoft.com)
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+
+Revision History:
+ 19 Jun 1992 Initial Version (dch@pacvax.pacersoft.com)
+
+Notes: Tab stop: 4
+--*/
+
+#ifndef _LTTIMER_H_
+#define _LTTIMER_H_
+
+// Poll timer value in milliseconds.
+#define LT_POLLING_TIME (UINT)20
+
+VOID
+LtTimerPoll(
+ IN PVOID SystemSpecific1,
+ IN PVOID Context,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3);
+
+#ifdef LTTIMER_H_LOCALS
+
+// Check to see if packet is broadcast.
+#define IS_PACKET_BROADCAST(p) (((UCHAR)p[0] == LT_BROADCAST_NODE_ID))
+
+#endif // LTTIMER_H_LOCALS
+
+
+#endif // _LTTIMER_H_
+
diff --git a/private/ntos/ndis/lt200/ltutils.c b/private/ntos/ndis/lt200/ltutils.c
new file mode 100644
index 000000000..b1d1c2322
--- /dev/null
+++ b/private/ntos/ndis/lt200/ltutils.c
@@ -0,0 +1,610 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ltutils.c
+
+Abstract:
+
+ This module contains utility routines.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+ Stephen Hou (stephh@microsoft.com)
+
+Revision History:
+ 19 Jun 1992 Initial Version (dch@pacvax.pacersoft.com)
+
+Notes: Tab stop: 4
+--*/
+
+#include "ltmain.h"
+#include "ltutils.h"
+
+
+// Define file id for errorlogging
+#define FILENUM LTUTILS
+
+
+USHORT
+LtUtilsPacketType(
+ IN PNDIS_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ Calculates the packet type for this packet. It also determines
+ if this packet should go out on the wire.
+
+Arguments:
+
+ Packet - Packet whose source and destination addresses are tested.
+
+Return Value:
+
+ Returns FALSE if the source is equal to the destination.
+
+
+--*/
+
+{
+ // Holds the destination and source address from the packet.
+ UCHAR PacketAddresses[2];
+
+ // Junk variable to hold the length of the addresses
+ UINT AddressLength;
+
+ LtUtilsCopyFromPacketToBuffer(
+ Packet,
+ 0,
+ 2,
+ PacketAddresses,
+ &AddressLength);
+
+ return(LtUtilsUcharPacketType(PacketAddresses[0], PacketAddresses[1]));
+}
+
+
+USHORT
+LtUtilsUcharPacketType(
+ IN UCHAR DestinationAddress,
+ IN UCHAR SourceAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Calculates the packet type for this packet. It also determines
+ if this packet should go out on the wire.
+
+Arguments:
+
+ Packet - Packet whose source and destination addresses are tested.
+
+Return Value:
+
+ Returns FALSE if the source is equal to the destination.
+
+
+--*/
+
+{
+ int PacketType = LT_DIRECTED;
+
+ if (DestinationAddress == LT_BROADCAST_NODE_ID)
+ {
+ PacketType = LT_BROADCAST;
+ }
+ else
+ {
+ if (DestinationAddress == SourceAddress)
+ {
+ PacketType = LT_LOOPBACK;
+ }
+ }
+
+ return(PacketType);
+}
+
+
+VOID
+LtUtilsCopyFromPacketToBuffer(
+ IN PNDIS_PACKET SrcPacket,
+ IN UINT SrcOffset,
+ IN UINT BytesToCopy,
+ OUT PUCHAR DestBuffer,
+ OUT PUINT BytesCopied
+ )
+/*++
+
+Routine Description:
+
+ Copy from an ndis packet into a buffer.
+
+Arguments:
+
+ SrcPacket - The packet to copy from.
+
+ SrcOffset - The offset within the packet from which to start the copy.
+
+ BytesToCopy - The number of bytes to copy from the packet.
+
+ DestBuffer - The destination of the copy.
+
+ BytesCopied - The number of bytes actually copied. Can be less then
+ BytesToCopy if the packet is shorter than BytesToCopy.
+
+Return Value:
+
+ None
+
+--*/
+{
+
+ UINT SrcBufferCount; // number of buffers in the current buffer
+ PNDIS_BUFFER SrcCurrentBuffer; // current buffer
+ UINT SrcCurrentBufferLen; // length of the current buffer
+ PVOID SrcVirtualAddress; // virtual address of the current buffer
+ UINT AmountToCopy; // bytes to copy
+
+ UINT LocalBytesCopied = 0; // total bytes copied
+
+ *BytesCopied = 0;
+
+ // Take care of boundary condition of zero length copy.
+ if (!BytesToCopy)
+ {
+ return;
+ }
+
+ //
+ // Get the first buffer.
+ //
+
+ NdisQueryPacket(
+ SrcPacket,
+ NULL,
+ &SrcBufferCount,
+ &SrcCurrentBuffer,
+ NULL);
+
+ // Could have a null packet.
+ if (!SrcBufferCount)
+ {
+ return;
+ }
+
+ NdisQueryBuffer(
+ SrcCurrentBuffer,
+ &SrcVirtualAddress,
+ &SrcCurrentBufferLen);
+
+ // advance to the start point for the copy.
+ while (SrcOffset)
+ {
+ if (SrcOffset > SrcCurrentBufferLen)
+ {
+ //
+ // What we want isn't in this buffer.
+ //
+
+ SrcOffset -= SrcCurrentBufferLen;
+ SrcCurrentBufferLen = 0;
+
+ }
+ else
+ {
+ //
+ SrcVirtualAddress = (PCHAR)SrcVirtualAddress + SrcOffset;
+ SrcCurrentBufferLen -= SrcOffset;
+ SrcOffset = 0;
+ break;
+
+ }
+
+ NdisGetNextBuffer(
+ SrcCurrentBuffer,
+ &SrcCurrentBuffer);
+
+ // We hit the end of the packet
+ if (!SrcCurrentBuffer)
+ {
+ return;
+ }
+
+ NdisQueryBuffer(
+ SrcCurrentBuffer,
+ &SrcVirtualAddress,
+ &SrcCurrentBufferLen);
+ }
+
+ // Copy the data.
+ while (LocalBytesCopied < BytesToCopy)
+ {
+ AmountToCopy = ((SrcCurrentBufferLen <= (BytesToCopy - LocalBytesCopied))?
+ (SrcCurrentBufferLen):(BytesToCopy - LocalBytesCopied));
+
+ NdisMoveMemory(
+ DestBuffer,
+ SrcVirtualAddress,
+ AmountToCopy);
+
+ DestBuffer = (PCHAR)DestBuffer + AmountToCopy;
+ SrcVirtualAddress = (PCHAR)SrcVirtualAddress + AmountToCopy;
+
+ LocalBytesCopied += AmountToCopy;
+ SrcCurrentBufferLen -= AmountToCopy;
+
+ // read the entire buffer, read in the next one
+ if (!SrcCurrentBufferLen)
+ {
+ NdisGetNextBuffer(
+ SrcCurrentBuffer,
+ &SrcCurrentBuffer);
+
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.
+ //
+
+ if (!SrcCurrentBuffer)
+ break;
+
+ NdisQueryBuffer(
+ SrcCurrentBuffer,
+ &SrcVirtualAddress,
+ &SrcCurrentBufferLen);
+
+ }
+ }
+
+ *BytesCopied = LocalBytesCopied;
+}
+
+
+VOID
+LtUtilsCopyFromBufferToPacket(
+ IN PUCHAR SrcBuffer,
+ IN UINT SrcOffset,
+ IN UINT BytesToCopy,
+ IN PNDIS_PACKET DestPacket,
+ OUT PUINT BytesCopied
+ )
+/*++
+
+Routine Description:
+
+ Copy from a buffer into an ndis packet.
+
+Arguments:
+
+ SrcBuffer - The buffer to copy from.
+
+ SrcOffset - The offset within SrcBuffer from which to start the copy.
+
+ DestPacket - The destination of the copy.
+
+ BytesToCopy - The number of bytes to copy from the buffer.
+
+ BytesCopied - The number of bytes actually copied. Will be less
+ than BytesToCopy if the packet is not large enough.
+
+Return Value:
+
+ None
+
+--*/
+{
+
+ UINT DestBufferCount; // number of buffers in the packet
+ PNDIS_BUFFER DestCurrentBuffer; // current buffer
+ UINT DestCurrentBufferLen; // length of the current buffer
+ PVOID DestVirtualAddress; // virtual addr of the current dest buffer
+ PUCHAR SrcCurrentAddress; // ptr to current location in src buffer
+ UINT AmountToCopy; // bytes to copy
+ UINT BytesRemaining; // bytes left to copy
+
+ UINT LocalBytesCopied = 0; // bytes copied
+
+ *BytesCopied = 0;
+
+ // Take care of boundary condition of zero length copy.
+ if (!BytesToCopy)
+ {
+ return;
+ }
+
+ // Get the first buffer of the destination.
+ NdisQueryPacket(
+ DestPacket,
+ NULL,
+ &DestBufferCount,
+ &DestCurrentBuffer,
+ NULL);
+
+ // Could have a null packet.
+ if (!DestBufferCount)
+ {
+ return;
+ }
+
+ NdisQueryBuffer(
+ DestCurrentBuffer,
+ &DestVirtualAddress,
+ &DestCurrentBufferLen);
+
+ // Set up the source address.
+ SrcCurrentAddress = SrcBuffer + SrcOffset;
+
+ while (LocalBytesCopied < BytesToCopy)
+ {
+ //
+ // Check to see whether we've exhausted the current destination
+ // buffer. If so, move onto the next one.
+ //
+
+ if (!DestCurrentBufferLen)
+ {
+ NdisGetNextBuffer(
+ DestCurrentBuffer,
+ &DestCurrentBuffer);
+
+ if (!DestCurrentBuffer)
+ {
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.)
+ //
+
+ break;
+
+ }
+
+ NdisQueryBuffer(
+ DestCurrentBuffer,
+ &DestVirtualAddress,
+ &DestCurrentBufferLen);
+
+ // go back to the start of the loop and repeat buffer size check
+ continue;
+
+ }
+
+ //
+ // Copy the data.
+ //
+
+ BytesRemaining = BytesToCopy - LocalBytesCopied;
+
+ AmountToCopy = ((BytesRemaining < DestCurrentBufferLen)?
+ (BytesRemaining):(DestCurrentBufferLen));
+
+ NdisMoveMemory(
+ DestVirtualAddress,
+ SrcCurrentAddress,
+ AmountToCopy);
+
+ SrcCurrentAddress += AmountToCopy;
+ LocalBytesCopied += AmountToCopy;
+ DestCurrentBufferLen -= AmountToCopy;
+
+ }
+
+ *BytesCopied = LocalBytesCopied;
+}
+
+
+
+
+VOID
+LtRefAdapter(
+ IN OUT PLT_ADAPTER Adapter,
+ OUT PNDIS_STATUS Status
+ )
+{
+ *Status = NDIS_STATUS_SUCCESS;
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ if ((Adapter->Flags & ADAPTER_CLOSING) == 0)
+ {
+ Adapter->RefCount++;
+ }
+ else
+ {
+ *Status = NDIS_STATUS_ADAPTER_REMOVED;
+ }
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ return;
+}
+
+
+
+
+VOID
+LtRefAdapterNonInterlock(
+ IN OUT PLT_ADAPTER Adapter,
+ OUT PNDIS_STATUS Status
+ )
+{
+ *Status = NDIS_STATUS_SUCCESS;
+
+ if ((Adapter->Flags & ADAPTER_CLOSING) == 0)
+ {
+ Adapter->RefCount++;
+ }
+ else
+ {
+ *Status = NDIS_STATUS_ADAPTER_REMOVED;
+ }
+
+ return;
+}
+
+
+
+
+VOID
+LtDeRefAdapter(
+ IN OUT PLT_ADAPTER Adapter
+ )
+{
+ BOOLEAN Close = FALSE;
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ if (--Adapter->RefCount == 0)
+ Close = TRUE;
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ if (Close)
+ {
+ // Last reference on adapter is gone.
+ ASSERTMSG("LtDeRefAdapter: Closing flag not set!\n",
+ (Adapter->Flags & ADAPTER_CLOSING));
+
+ ASSERTMSG("LtDeRefAdapter: Open count is not zero!\n",
+ (Adapter->OpenCount == 0));
+
+ // Release the adapter
+ NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
+ NdisFreeSpinLock(&Adapter->Lock);
+
+ NdisFreeMemory(
+ Adapter,
+ sizeof(LT_ADAPTER),
+ (UINT)0);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+LtRefBinding(
+ IN OUT PLT_OPEN Binding,
+ OUT PNDIS_STATUS Status
+ )
+{
+ *Status = NDIS_STATUS_SUCCESS;
+
+ NdisAcquireSpinLock(&Binding->LtAdapter->Lock);
+ if ((Binding->Flags & BINDING_CLOSING) == 0)
+ {
+ Binding->RefCount++;
+ }
+ else
+ {
+ *Status = NDIS_STATUS_CLOSING;
+ }
+ NdisReleaseSpinLock(&Binding->LtAdapter->Lock);
+
+ return;
+}
+
+
+
+
+VOID
+LtRefBindingNextNcNonInterlock(
+ IN PLIST_ENTRY PList,
+ IN PLIST_ENTRY PEnd,
+ OUT PLT_OPEN * Binding,
+ OUT PNDIS_STATUS Status
+ )
+{
+ PLT_OPEN ChkBinding;
+ *Status = NDIS_STATUS_FAILURE;
+
+ *Binding = NULL;
+ while (PList != PEnd)
+ {
+ ChkBinding = CONTAINING_RECORD(PList, LT_OPEN, Linkage);
+
+ DBGPRINT(DBG_COMP_UTILS, DBG_LEVEL_INFO,
+ ("LtRefBindingNextNcNonInterlock: ChkBind %lx\n", ChkBinding));
+
+ LtRefBindingNonInterlock(ChkBinding, Status);
+ if (*Status == NDIS_STATUS_SUCCESS)
+ {
+ *Binding = ChkBinding;
+ break;
+ }
+
+ PList = PList->Flink;
+ }
+
+ return;
+}
+
+
+
+
+VOID
+LtRefBindingNonInterlock(
+ IN OUT PLT_OPEN Binding,
+ OUT PNDIS_STATUS Status
+ )
+{
+ *Status = NDIS_STATUS_SUCCESS;
+
+ if ((Binding->Flags & BINDING_CLOSING) == 0)
+ {
+ Binding->RefCount++;
+ }
+ else
+ {
+ *Status = NDIS_STATUS_CLOSING;
+ }
+
+ return;
+}
+
+
+
+
+VOID
+LtDeRefBinding(
+ IN OUT PLT_OPEN Binding
+ )
+{
+ BOOLEAN Close = FALSE;
+
+ NdisAcquireSpinLock(&Binding->LtAdapter->Lock);
+ if (--Binding->RefCount == 0)
+ {
+ Close = TRUE;
+ RemoveEntryList(&Binding->Linkage);
+ (Binding->LtAdapter->OpenCount)--;
+ }
+ NdisReleaseSpinLock(&Binding->LtAdapter->Lock);
+
+ if (Close)
+ {
+ NDIS_HANDLE OpenBindingContext = Binding->NdisBindingContext;
+
+ // Last reference on binding is gone.
+ ASSERTMSG("LtDeRefBinding: Closing flag not set!\n",
+ (Binding->Flags & BINDING_CLOSING));
+
+ // Release the binding and remove its reference on the
+ // adapter.
+ NdisCompleteCloseAdapter(OpenBindingContext, NDIS_STATUS_SUCCESS);
+ LtDeReferenceAdapter(Binding->LtAdapter);
+
+ // Free up the binding structure
+ NdisFreeMemory(Binding, sizeof(LT_OPEN), (UINT)0);
+ }
+
+ return;
+}
+
diff --git a/private/ntos/ndis/lt200/ltutils.h b/private/ntos/ndis/lt200/ltutils.h
new file mode 100644
index 000000000..14debcec2
--- /dev/null
+++ b/private/ntos/ndis/lt200/ltutils.h
@@ -0,0 +1,184 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ltutils.h
+
+Abstract:
+
+ This module contains
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+ Stephen Hou (stephh@microsoft.com)
+
+Revision History:
+ 19 Jun 1992 Initial Version (dch@pacvax.pacersoft.com)
+
+Notes: Tab stop: 4
+--*/
+
+#ifndef _LTUTILS_H_
+#define _LTUTILS_H_
+
+
+USHORT
+LtUtilsPacketType(
+ IN PNDIS_PACKET Packet
+ );
+
+USHORT
+LtUtilsUcharPacketType(
+ IN UCHAR DestinationAddress,
+ IN UCHAR SourceAddress
+ );
+
+VOID
+LtUtilsCopyFromPacketToBuffer(
+ IN PNDIS_PACKET SrcPacket,
+ IN UINT SrcOffset,
+ IN UINT BytesToCopy,
+ OUT PUCHAR DestBuffer,
+ OUT PUINT BytesCopied
+ );
+
+VOID
+LtUtilsCopyFromBufferToPacket(
+ IN PUCHAR SrcBuffer,
+ IN UINT SrcOffset,
+ IN UINT BytesToCopy,
+ IN PNDIS_PACKET DestPacket,
+ OUT PUINT BytesCopied
+ );
+
+
+extern
+VOID
+LtRefAdapter(
+ IN OUT PLT_ADAPTER Adapter,
+ OUT PNDIS_STATUS Status);
+
+extern
+VOID
+LtRefAdapterNonInterlock(
+ IN OUT PLT_ADAPTER Adapter,
+ OUT PNDIS_STATUS Status);
+
+extern
+VOID
+LtDeRefAdapter(
+ IN OUT PLT_ADAPTER Adapter);
+
+extern
+VOID
+LtRefBinding(
+ IN OUT PLT_OPEN Binding,
+ OUT PNDIS_STATUS Status);
+
+extern
+VOID
+LtRefBindingNonInterlock(
+ IN OUT PLT_OPEN Binding,
+ OUT PNDIS_STATUS Status);
+
+extern
+VOID
+LtRefBindingNextNcNonInterlock(
+ IN PLIST_ENTRY PList,
+ IN PLIST_ENTRY PEnd,
+ OUT PLT_OPEN * Binding,
+ OUT PNDIS_STATUS Status);
+
+extern
+VOID
+LtDeRefBinding(
+ IN OUT PLT_OPEN Binding);
+
+
+// Reference Macros for Adapter/Bindings
+#if DBG
+#define LtReferenceAdapter(adapter, perror) \
+ { \
+ LtRefAdapter(adapter, perror); \
+ }
+
+#define LtReferenceAdapterNonInterlock(adapter, perror) \
+ { \
+ LtRefAdapterNonInterlock(adapter, perror); \
+ }
+
+#define LtDeReferenceAdapter(adapter) \
+ { \
+ LtDeRefAdapter(adapter); \
+ }
+
+#define LtReferenceBinding(binding, perror) \
+ { \
+ LtRefBinding(binding, perror); \
+ }
+
+#define LtReferenceBindingNonInterlock(binding, perror) \
+ { \
+ LtRefBindingNonInterlock(binding, perror); \
+ }
+
+#define LtReferenceBindingNextNcNonInterlock(PList, PEnd, Binding, Status) \
+ { \
+ LtRefBindingNextNcNonInterlock(PList, PEnd, Binding, Status); \
+ }
+
+#define LtDeReferenceBinding(binding) \
+ { \
+ LtDeRefBinding(binding); \
+ }
+
+#else
+
+#define LtReferenceAdapter(adapter, perror) \
+ { \
+ LtRefAdapter(adapter, perror); \
+ }
+
+#define LtReferenceAdapterNonInterlock(adapter, perror) \
+ { \
+ LtRefAdapterNonInterlock(adapter, perror); \
+ }
+
+#define LtDeReferenceAdapter(adapter) \
+ { \
+ LtDeRefAdapter(adapter); \
+ }
+
+#define LtReferenceBinding(binding, perror) \
+ { \
+ LtRefBinding(binding, perror); \
+ }
+
+#define LtReferenceBindingNonInterlock(binding, perror) \
+ { \
+ LtRefBindingNonInterlock(binding, perror); \
+ }
+
+#define LtReferenceBindingNextNcNonInterlock(PList, PEnd, Binding, Status) \
+ { \
+ LtRefBindingNextNcNonInterlock(PList, PEnd, Binding, Status); \
+ }
+
+#define LtDeReferenceBinding(binding) \
+ { \
+ LtDeRefBinding(binding); \
+ }
+
+#endif
+
+
+#ifdef NDIS_NT
+
+#define LtAddLongToLargeInteger(a,b) \
+ (RtlLargeIntegerAdd(a, RtlConvertLongToLargeInteger(b)))
+#endif
+
+#endif // _LTUTILS_H_
diff --git a/private/ntos/ndis/lt200/makefile b/private/ntos/ndis/lt200/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/lt200/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/lt200/sources b/private/ntos/ndis/lt200/sources
new file mode 100644
index 000000000..cce47fc27
--- /dev/null
+++ b/private/ntos/ndis/lt200/sources
@@ -0,0 +1,50 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=lt200
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+INCLUDES=..\..\inc
+
+SOURCES=ltinit.c \
+ ltfirm.c \
+ lttimer.c \
+ ltloop.c \
+ ltsend.c \
+ ltrecv.c \
+ ltreg.c \
+ ltreq.c \
+ ltreset.c \
+ ltutils.c \
+ lt200.rc
+
+
+MSC_WARNING_LEVEL=/W3 /WX
+
diff --git a/private/ntos/ndis/madge/detect/makefile b/private/ntos/ndis/madge/detect/makefile
new file mode 100644
index 000000000..58189757d
--- /dev/null
+++ b/private/ntos/ndis/madge/detect/makefile
@@ -0,0 +1,7 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the driver components of the Windows NT DDK
+#
+
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/madge/detect/mdgat.c b/private/ntos/ndis/madge/detect/mdgat.c
new file mode 100644
index 000000000..2897b550b
--- /dev/null
+++ b/private/ntos/ndis/madge/detect/mdgat.c
@@ -0,0 +1,1956 @@
+/****************************************************************************
+*
+* MDGAT.C
+*
+* ATULA Based Adapter Detection Module
+*
+* Copyright (c) Madge Networks Ltd 1994
+*
+* COMPANY CONFIDENTIAL - RELEASED TO MICROSOFT CORP. ONLY FOR DEVELOPMENT
+* OF WINDOWS95 NETCARD DETECTION - THIS SOURCE IS NOT TO BE RELEASED OUTSIDE
+* OF MICROSOFT WITHOUT EXPLICIT WRITTEN PERMISSION FROM AN AUTHORISED
+* OFFICER OF MADGE NETWORKS LTD.
+*
+* Created: PBA 25/08/1994
+*
+****************************************************************************/
+
+#include <ntddk.h>
+#include <ntddnetd.h>
+
+#include <windef.h>
+#include <winerror.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mdgncdet.h"
+
+//
+// Prototype "borrowed" from WINUSER.H
+//
+
+extern int WINAPIV wsprintfW(LPWSTR, LPCWSTR, ...);
+
+
+/*---------------------------------------------------------------------------
+|
+| AT adapter types. These correspond to the indexes that the upper layers
+| use for identifying adapters, so change them with care.
+|
+|--------------------------------------------------------------------------*/
+
+#define SMART_NONE 0
+#define SMART_AT 1000
+#define SMART_AT_P 1100
+#define SMART_ISA_C 1200
+#define SMART_ISA_C_P 1300
+#define SMART_PC 1400
+
+
+/*---------------------------------------------------------------------------
+|
+| IO locations that AT adapters can be at.
+|
+---------------------------------------------------------------------------*/
+
+static
+ULONG ATIoLocations[4] =
+ {0x0a20, 0x1a20, 0x2a20, 0x3a20};
+
+
+/*---------------------------------------------------------------------------
+|
+| Various ATULA card specific constants.
+|
+---------------------------------------------------------------------------*/
+
+#define AT_IO_RANGE 32
+
+#define AT_CONTROL_REGISTER_1 1
+#define AT_CONTROL_REGISTER_2 2
+#define AT_STATUS_REGISTER 3
+#define AT_CONTROL_REGISTER_6 6
+#define AT_CONTROL_REGISTER_7 7
+
+#define AT_BIA_PROM_BASE 8
+#define AT_P_SW_CONFIG_REG 22
+
+#define BIA_PROM_ID 0
+#define BIA_PROM_BOARD 1
+#define BIA_PROM_REVISION 2
+
+#define BIA_PROM_NODE_ADDRESS 1
+
+#define BIA_PROM_TYPE_16_4_AT 0x04
+#define BIA_PROM_TYPE_16_4_MC 0x08
+#define BIA_PROM_TYPE_16_4_PC 0x0B
+#define BIA_PROM_TYPE_16_4_MAXY 0x0C
+#define BIA_PROM_TYPE_16_4_MC_32 0x0D
+#define BIA_PROM_TYPE_16_4_AT_P 0x0E
+
+#define MAX_ADAPTER_CARD_AT_REV 6
+
+#define ADAPTER_CARD_16_4_PC 0
+#define ADAPTER_CARD_16_4_MAXY 1
+#define ADAPTER_CARD_16_4_AT 2
+#define ADAPTER_CARD_16_4_FIBRE 3
+#define ADAPTER_CARD_16_4_BRIDGE 4
+#define ADAPTER_CARD_16_4_ISA_C 5
+#define ADAPTER_CARD_16_4_AT_P_REV 6
+#define ADAPTER_CARD_16_4_FIBRE_P 7
+#define ADAPTER_CARD_16_4_ISA_C_P 8
+#define ADAPTER_CARD_16_4_AT_P 9
+
+#define ADAPTER_CARD_UNKNOWN 255
+
+#define AT_CTRL7_PAGE 0x08
+
+#define ATP_INTSEL_MASK 0x07
+#define ATP_DMASEL_MASK 0x18
+
+
+/*---------------------------------------------------------------------------
+|
+| Soft configurable adapter IRQ number mapping table.
+|
+---------------------------------------------------------------------------*/
+
+static
+UCHAR IrqMapTable[16] =
+{
+ 0xff, // 0 Unused
+ 0xff, // 1 Unused
+ 0x07, // 2
+ 0x06, // 3
+ 0xff, // 4 Unused
+ 0x05, // 5
+ 0xff, // 6 Unused
+ 0x04, // 7
+ 0xff, // 8 Unused
+ 0xff, // 9 Unused
+ 0x03, // 10
+ 0x02, // 11
+ 0x01, // 12
+ 0xff, // 13 Unused
+ 0xff, // 14 Unused
+ 0x00 // 15
+};
+
+
+/*---------------------------------------------------------------------------
+|
+| Soft configurable adapter DMA channel mapping table.
+|
+---------------------------------------------------------------------------*/
+
+static
+UCHAR DmaMapTable[7] =
+{
+ 0xff, // 0 Unused
+ 0xff, // 1 Unused
+ 0xff, // 2 Unused
+ 0x08, // 3
+ 0xff, // 4 Unused
+ 0x10, // 5
+ 0x18 // 6
+};
+
+
+/*---------------------------------------------------------------------------
+|
+| First three bytes of a Madge node address.
+|
+|---------------------------------------------------------------------------*/
+
+static
+UCHAR MadgeNodeAddressPrefix[3] =
+ {0x00, 0x00, 0xf6};
+
+
+/*---------------------------------------------------------------------------
+|
+| List of adapter types supported by this module.
+|
+|---------------------------------------------------------------------------*/
+
+static
+ADAPTER_INFO Adapters[] =
+{
+ {
+ SMART_AT,
+ MDGAT,
+ L"Madge 16/4 AT Ringnode/Bridgnode",
+ L"Madge Networks",
+ L"IOLOCATION\0"
+ L"000\0"
+ L"00100\0"
+ L"DMACHANNEL\0"
+ L"000\0"
+ L"000\0"
+ L"INTERRUPTNUMBER\0"
+ L"000\0"
+ L"000\0"
+ L"MULTIPROCESSOR\0"
+ L"000\0"
+ L"00100\0",
+ NULL,
+ 902
+ },
+
+ {
+ SMART_AT_P,
+ MDGATP,
+ L"Madge 16/4 ATP Ringnode",
+ L"Madge Networks",
+ L"IOLOCATION\0"
+ L"000\0"
+ L"00100\0"
+ L"DMACHANNEL\0"
+ L"000\0"
+ L"00100\0"
+ L"INTERRUPTNUMBER\0"
+ L"000\0"
+ L"00100\0"
+ L"MULTIPROCESSOR\0"
+ L"000\0"
+ L"00100\0",
+ NULL,
+ 902
+ },
+
+ {
+ SMART_ISA_C,
+ MDGISAC,
+ L"Madge 16/4 ISA Client Ringnode",
+ L"Madge Networks",
+ L"IOLOCATION\0"
+ L"000\0"
+ L"00100\0"
+ L"DMACHANNEL\0"
+ L"000\0"
+ L"00100\0"
+ L"INTERRUPTNUMBER\0"
+ L"000\0"
+ L"000\0"
+ L"MULTIPROCESSOR\0"
+ L"000\0"
+ L"00100\0",
+ NULL,
+ 902
+ },
+
+ {
+ SMART_ISA_C_P,
+ MDGISACP,
+ L"Madge 16/4 ISA Client Plus Ringnode",
+ L"Madge Networks",
+ L"IOLOCATION\0"
+ L"000\0"
+ L"00100\0"
+ L"DMACHANNEL\0"
+ L"000\0"
+ L"00100\0"
+ L"INTERRUPTNUMBER\0"
+ L"000\0"
+ L"00100\0"
+ L"MULTIPROCESSOR\0"
+ L"000\0"
+ L"00100\0",
+ NULL,
+ 902
+ },
+
+ {
+ SMART_PC,
+ MDGPC,
+ L"Madge 16/4 PC Ringnode",
+ L"Madge Networks",
+ L"IOLOCATION\0"
+ L"000\0"
+ L"00100\0"
+ L"DMACHANNEL\0"
+ L"000\0"
+ L"000\0"
+ L"INTERRUPTNUMBER\0"
+ L"000\0"
+ L"000\0"
+ L"MULTIPROCESSOR\0"
+ L"000\0"
+ L"00100\0",
+ NULL,
+ 902
+ }
+};
+
+
+/*---------------------------------------------------------------------------
+|
+| Madge specific parameter range information. The order entries in this
+| table MUST match that in the Adapters table above. The first value
+Ý in each list is the default.
+|
+---------------------------------------------------------------------------*/
+
+static
+struct
+{
+ ULONG IrqRange[9];
+ ULONG DmaRange[6];
+}
+ParamRange[] =
+{
+ //
+ // Smart 16/4 AT.
+ //
+
+ {
+ { 3, 2, 5, 7, 10, 11, 12, 15, END_OF_LIST},
+
+#if defined(_PPC_) || defined(_MIPS_)
+
+ { 0, END_OF_LIST}
+
+#else
+
+ { 5, 1, 3, 0, 6, END_OF_LIST}
+
+#endif
+ },
+
+ //
+ // Smart 16/4 ATP.
+ //
+
+ {
+ { 3, 2, 5, 7, 10, 11, 12, 15, END_OF_LIST},
+
+#if defined(_PPC_) || defined(_MIPS_)
+
+ { 0, END_OF_LIST}
+
+#else
+
+ { 5, 3, 0, 6, END_OF_LIST}
+
+#endif
+ },
+
+ //
+ // Smart 16/4 ISA Client.
+ //
+
+ {
+ { 3, 2, 5, 7, 10, 11, 12, 15, END_OF_LIST},
+ { 0, END_OF_LIST}
+ },
+
+ //
+ // Smart 16/4 ISA Client Plus.
+ //
+
+ {
+ { 3, 2, 5, 7, 10, 11, 12, 15, END_OF_LIST},
+ { 0, END_OF_LIST}
+ },
+
+ //
+ // Smart 16/4 PC.
+ //
+
+ {
+ { 3, 2, 5, 7, END_OF_LIST},
+ { 0, END_OF_LIST}
+ }
+};
+
+
+/*---------------------------------------------------------------------------
+|
+| Structure for holding state of a search.
+|
+|--------------------------------------------------------------------------*/
+
+typedef struct
+{
+ ULONG IoLocationIndex;
+ ULONG Irq;
+ ULONG Dma;
+}
+AT_SEARCH_STATE;
+
+
+/*---------------------------------------------------------------------------
+|
+| This is an array of search states. We need one state for each type
+| of adapter supported.
+|
+|--------------------------------------------------------------------------*/
+
+static
+AT_SEARCH_STATE SearchStates[sizeof(Adapters) / sizeof(ADAPTER_INFO)] = {0};
+
+
+/*---------------------------------------------------------------------------
+|
+| Structure for holding a particular adapter's complete information.
+|
+|--------------------------------------------------------------------------*/
+
+typedef struct
+{
+ BOOLEAN Found;
+ ULONG CardType;
+ ULONG BusNumber;
+ INTERFACE_TYPE InterfaceType;
+ ULONG IoLocation;
+ ULONG Irq;
+ ULONG Dma;
+}
+AT_ADAPTER;
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - CheckForCard
+|
+| Parameters - busNumber -> The number of the bus to check.
+| interface -> The interface type of the bus.
+| ioLocation -> The IO location to be checked.
+| irq -> Pointer to a holder for the IRQ if
+| discovered.
+| dma -> Pointer to a holder for the DMA
+| channel if discovered.
+|
+| Purpose - Check to see if an Madge AT card is at the specified
+| IO location. If the card is soft programmable then the
+| IRQ number and DMA channel are also determined.
+|
+| Returns - A card type.
+|
+---------------------------------------------------------------------------*/
+
+static ULONG
+CheckForCard(
+ ULONG busNumber,
+ INTERFACE_TYPE interface,
+ ULONG ioLocation,
+ ULONG * irq,
+ ULONG * dma
+ )
+{
+ UCHAR byte;
+ ULONG board;
+ ULONG revision;
+ ULONG type;
+ ULONG found;
+ UINT i;
+
+ MadgePrint2("CheckForCard (ioLocation=%04lx)\n", ioLocation);
+
+ //
+ // For the moment we don't know what these are.
+ //
+
+ *irq = RESOURCE_UNKNOWN;
+ *dma = RESOURCE_UNKNOWN;
+
+ //
+ // First check that the IO range is not in use by some other
+ // device.
+ //
+
+ if (DetectCheckPortUsage(
+ interface,
+ busNumber,
+ ioLocation,
+ AT_IO_RANGE
+ ) != STATUS_SUCCESS)
+ {
+ return SMART_NONE;
+ }
+
+ MadgePrint1("CheckForCard: DetectCheckPortUsage() OK\n");
+
+ //
+ // Now we must reset the ATULA (if it's there).
+ //
+
+ if (DetectWritePortUchar(
+ interface,
+ busNumber,
+ ioLocation + AT_CONTROL_REGISTER_1,
+ 0
+ ) != STATUS_SUCCESS)
+ {
+ return SMART_NONE;
+ }
+
+ MadgePrint1("CheckForCard: Reset ATULA OK\n");
+
+ //
+ // And map in the first page of the BIA PROM.
+ //
+
+ if (DetectWritePortUchar(
+ interface,
+ busNumber,
+ ioLocation + AT_CONTROL_REGISTER_7,
+ 0
+ ) != STATUS_SUCCESS)
+ {
+ return SMART_NONE;
+ }
+
+ MadgePrint1("CheckForCard: Map in BIA OK\n");
+
+ //
+ // Next look to see if there is an 'M' in the BIA PROM identification
+ // field.
+ //
+
+ if (DetectReadPortUchar(
+ interface,
+ busNumber,
+ ioLocation + AT_BIA_PROM_BASE + BIA_PROM_ID,
+ &byte
+ ) != STATUS_SUCCESS)
+ {
+ return SMART_NONE;
+ }
+
+ if (byte != 'M')
+ {
+ return SMART_NONE;
+ }
+
+ MadgePrint1("CheckForCard: Read Madge byte OK\n");
+
+ //
+ // If we reach this point there is a reasonable chance that
+ // there is a Madge AT adapter at the IO location. Now we will
+ // try and work out what type it is.
+ //
+
+ if (DetectReadPortUchar(
+ interface,
+ busNumber,
+ ioLocation + AT_BIA_PROM_BASE + BIA_PROM_BOARD,
+ &byte
+ ) != STATUS_SUCCESS)
+ {
+ return SMART_NONE;
+ }
+
+ board = byte;
+
+ MadgePrint2("CheckForCard: Read board type OK (board = %lx)\n", board);
+
+ if (DetectReadPortUchar(
+ interface,
+ busNumber,
+ ioLocation + AT_BIA_PROM_BASE + BIA_PROM_REVISION,
+ &byte
+ ) != STATUS_SUCCESS)
+ {
+ return SMART_NONE;
+ }
+
+ revision = byte;
+
+ MadgePrint2("CheckForCard: Read revision OK (revision = %lx)\n", revision);
+
+ //
+ // Work out the hardware type based on the board type and revision.
+ //
+
+ type = ADAPTER_CARD_UNKNOWN;
+
+ if (board == BIA_PROM_TYPE_16_4_PC)
+ {
+ type = ADAPTER_CARD_16_4_PC;
+ }
+ else if (board == BIA_PROM_TYPE_16_4_AT)
+ {
+ if (revision < ADAPTER_CARD_16_4_AT)
+ {
+ type = ADAPTER_CARD_16_4_AT;
+ }
+ else
+ {
+ type = revision;
+ }
+ }
+ else if (board == BIA_PROM_TYPE_16_4_AT_P)
+ {
+ if (revision == ADAPTER_CARD_16_4_FIBRE)
+ {
+ type = ADAPTER_CARD_16_4_FIBRE_P;
+ }
+ else if (revision == ADAPTER_CARD_16_4_ISA_C)
+ {
+ type = ADAPTER_CARD_16_4_ISA_C_P;
+ }
+ else if (revision == ADAPTER_CARD_16_4_AT_P_REV)
+ {
+ type = ADAPTER_CARD_16_4_AT_P;
+ }
+ }
+
+ //
+ // Convert the hardware type into our nomencalculature or abort
+ // if we couldn't identify the adapter.
+ //
+
+ switch (type)
+ {
+ case ADAPTER_CARD_16_4_AT:
+ case ADAPTER_CARD_16_4_FIBRE:
+ case ADAPTER_CARD_16_4_BRIDGE:
+
+ found = SMART_AT;
+ break;
+
+ case ADAPTER_CARD_16_4_ISA_C:
+
+ found = SMART_ISA_C;
+ break;
+
+ case ADAPTER_CARD_16_4_AT_P_REV:
+ case ADAPTER_CARD_16_4_AT_P:
+ case ADAPTER_CARD_16_4_FIBRE_P:
+
+ found = SMART_AT_P;
+ break;
+
+ case ADAPTER_CARD_16_4_ISA_C_P:
+
+ found = SMART_ISA_C_P;
+ break;
+
+ case ADAPTER_CARD_16_4_PC:
+
+ found = SMART_PC;
+ break;
+
+ default:
+
+ return SMART_NONE;
+ }
+
+ MadgePrint2("CheckForCard: Idetification OK (found = %ld)\n", found);
+
+ //
+ // As a final check read the first three bytes of the BIA node
+ // address and check they are a valid Madge prefix.
+ //
+
+ //
+ // Map in the second page of the BIA PROM.
+ //
+
+ if (DetectReadPortUchar(
+ interface,
+ busNumber,
+ ioLocation + AT_CONTROL_REGISTER_7,
+ &byte
+ ) != STATUS_SUCCESS)
+ {
+ return SMART_NONE;
+ }
+
+ byte |= AT_CTRL7_PAGE;
+
+ if (DetectWritePortUchar(
+ interface,
+ busNumber,
+ ioLocation + AT_CONTROL_REGISTER_7,
+ byte
+ ) != STATUS_SUCCESS)
+ {
+ return SMART_NONE;
+ }
+
+ //
+ // Now read and check the node address.
+ //
+
+ for (i = 0; i < 3; i++)
+ {
+ if (DetectReadPortUchar(
+ interface,
+ busNumber,
+ ioLocation + AT_BIA_PROM_BASE + BIA_PROM_NODE_ADDRESS + i,
+ &byte
+ ) != STATUS_SUCCESS)
+ {
+ return SMART_NONE;
+ }
+
+ if (byte != MadgeNodeAddressPrefix[i])
+ {
+ return SMART_NONE;
+ }
+ }
+
+ MadgePrint1("CheckForCard: Read node address OK\n");
+
+ //
+ // At this point we're as sure as we will ever be that there is
+ // an ATULA based Madge adapter at ioLocation. If the card is
+ // an ISA/C or an ISA/C/P then the DMA channel is always 0
+ // (for PIO).
+ //
+
+ if (found == SMART_ISA_C || found == SMART_ISA_C_P)
+ {
+ *dma = 0;
+ }
+
+ // If the card is soft programmable then we'll read the
+ // config register to out the IRQ number and the DMA channel
+ // (if there is one).
+ //
+
+ if (found == SMART_AT_P || found == SMART_ISA_C_P)
+ {
+ //
+ // Read the soft configuration byte.
+ //
+
+ if (DetectReadPortUchar(
+ interface,
+ busNumber,
+ ioLocation + AT_P_SW_CONFIG_REG,
+ &byte
+ ) != STATUS_SUCCESS)
+ {
+ return SMART_NONE;
+ }
+
+ //
+ // Find out what the IRQ number is.
+ //
+
+ for (i = 0; i < sizeof(IrqMapTable) / sizeof(UCHAR); i++)
+ {
+ if (IrqMapTable[i] == (byte & ATP_INTSEL_MASK))
+ {
+ *irq = i;
+ }
+ }
+
+ //
+ // If it's an ATP then find out the DMA channel.
+ //
+
+ if (found == SMART_AT_P)
+ {
+ //
+ // We'll start of with the DMA channel being zero since
+ // if we don't find a valid DMA setting DMA must be
+ // disabled and we should use PIO.
+ //
+
+ *dma = 0;
+
+ for (i = 0; i < sizeof(DmaMapTable) / sizeof(UCHAR); i++)
+ {
+ if (DmaMapTable[i] == (byte & ATP_DMASEL_MASK))
+ {
+ *dma = i;
+ }
+ }
+ }
+ }
+
+ MadgePrint3("IRQ = %ld DMA = %ld\n", *irq, *dma);
+
+ return found;
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - FindATCard
+|
+| Parameters - adapterNumber -> Adapter type index used to index the
+| global array SearchStates.
+| busNumber -> The number of the bus to search.
+| interface -> The interface type of the bus.
+| first -> TRUE if this is the first call for
+| a given adapter type.
+| type -> The type of adapter to find.
+| confidence -> Pointer a holder for the confidence in
+| which the adapter was found.
+|
+| Purpose - Search the specified bus for an adapter of the
+| specified type. If first is TRUE then the search
+| starts from the first possible IO location. If first is
+| FALSE then the search starts from one after the last
+| IO location checked the previous time FindATCard was called.
+|
+| Returns - A WINERROR.H error code.
+|
+|--------------------------------------------------------------------------*/
+
+static ULONG
+FindATCard(
+ ULONG adapterNumber,
+ ULONG busNumber,
+ INTERFACE_TYPE interface,
+ BOOLEAN first,
+ ULONG type,
+ ULONG * confidence
+ )
+{
+ //
+ // If this is the first call then we want to start from the
+ // first possible IO location.
+ //
+
+ if (first)
+ {
+ SearchStates[adapterNumber].IoLocationIndex = 0;
+ }
+
+ //
+ // Otherwise we want to start from 1 after were we left off
+ // last time.
+ //
+
+ else
+ {
+ SearchStates[adapterNumber].IoLocationIndex++;
+ }
+
+ //
+ // Step through the IO locations in the bus for which there aren't
+ // already Madge adapters installed looking for one with the
+ // required adapter type. If we don't find one we will return a
+ // confidence level of zero. (Note we check that there isn't a
+ // Madge adapter at the IO location first to avoid trashing a
+ // working adapter.)
+ //
+
+ *confidence = 0;
+
+ while (SearchStates[adapterNumber].IoLocationIndex <
+ sizeof(ATIoLocations) / sizeof(ULONG))
+ {
+ if (!MadgeCardAlreadyInstalled(
+ FALSE,
+ busNumber,
+ ATIoLocations[SearchStates[adapterNumber].IoLocationIndex]
+ ))
+ {
+ if (CheckForCard(
+ busNumber,
+ interface,
+ ATIoLocations[SearchStates[adapterNumber].IoLocationIndex],
+ &SearchStates[adapterNumber].Irq,
+ &SearchStates[adapterNumber].Dma
+ ) == type)
+ {
+ *confidence = 100;
+ break;
+ }
+ }
+
+ SearchStates[adapterNumber].IoLocationIndex++;
+ }
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeATIdentifyHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* buffer -> Buffer for the results.
+* bufferSize -> Size of the buffer in WCHARs.
+*
+* Purpose - Return information about a type of adapter that this module
+* supports.
+*
+* Returns - A WINERROR.H error code. ERROR_NO_MORE_ITEMS
+* is returned if index refers to an adapter type not
+* supported.
+*
+****************************************************************************/
+
+LONG
+MadgeATIdentifyHandler(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ LONG numberOfAdapters;
+ LONG action;
+ LONG length;
+ LONG i;
+
+ MadgePrint2("MadgeATIdentifyHandler (index = %ld)\n", index);
+
+ //
+ // Do some initialisation.
+ //
+
+ numberOfAdapters = sizeof(Adapters) / sizeof(ADAPTER_INFO);
+ action = index % 100;
+ index = index - action;
+
+ //
+ // Check that index does not exceed the number of adapters we
+ // support.
+ //
+
+ if ((index - 1000) / 100 >= numberOfAdapters)
+ {
+ return ERROR_NO_MORE_ITEMS;
+ }
+
+ //
+ // If index refers to an adapter type supported then carry out the
+ // requested action.
+ //
+
+ for (i = 0; i < numberOfAdapters; i++)
+ {
+ if (Adapters[i].Index == index)
+ {
+ switch (action)
+ {
+ //
+ // Return the adapter's abbreviation.
+ //
+
+ case 0:
+
+ length = UnicodeStrLen(Adapters[i].InfId) + 1;
+
+ if (bufferSize < length)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ memcpy(
+ (VOID *) buffer,
+ Adapters[i].InfId,
+ length * sizeof(WCHAR)
+ );
+
+ break;
+
+ //
+ // Return the adapter's description.
+ //
+
+ case 1:
+
+ length = UnicodeStrLen(Adapters[i].CardDescription) + 1;
+
+ if (bufferSize < length)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ memcpy(
+ (VOID *) buffer,
+ Adapters[i].CardDescription,
+ length * sizeof(WCHAR)
+ );
+
+ break;
+
+ //
+ // Return the adapter's manufacturer.
+ //
+
+ case 2:
+
+ length = UnicodeStrLen(Adapters[i].Manufacturer) + 1;
+
+ if (bufferSize < length)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ memcpy(
+ (VOID *) buffer,
+ Adapters[i].Manufacturer,
+ length * sizeof(WCHAR)
+ );
+
+ break;
+
+ //
+ // Return the search order.
+ //
+
+ case 3:
+
+ if (bufferSize < 5)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ wsprintfW(
+ (VOID *) buffer,
+ L"%d",
+ Adapters[i].SearchOrder
+ );
+
+ break;
+
+ //
+ // Anything else is invalid.
+ //
+
+ default:
+
+ return ERROR_INVALID_PARAMETER;
+
+ }
+
+ return NO_ERROR;
+ }
+ }
+
+ //
+ // We didn't find an adapter type that matched the index so
+ // return an error.
+ //
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeATFirstNextHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* interface -> The NT interface type (ISA, EISA etc).
+* busNumber -> The bus number to search.
+* first -> TRUE if the search of this bus should start
+* from scratch.
+* token -> Pointer to holder for a token that identifies
+* the adapter found.
+* confidence -> Pointer to a holder for the confidence by
+* which the adapter has been found.
+*
+* Purpose - Attempts to find an adapter on the specified bus. If first
+* is TRUE then the search starts from scratch. Otherwise
+* the search starts from where it left of the last time we
+* were called.
+*
+* Returns - A WINERROR.H error code. A return code of NO_ERROR
+* and a *confidence of 0 means we didn't find an adapter.
+*
+****************************************************************************/
+
+LONG
+MadgeATFirstNextHandler(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ BOOL first,
+ VOID * * token,
+ LONG * confidence
+ )
+{
+ LONG adapterNumber;
+ ULONG retCode;
+
+ MadgePrint2("MadgeATFirstNextHandler (index = %ld)\n", index);
+
+ //
+ // Check the interface type (could be an ISA adapter in an EISA bus).
+ //
+
+ if (interface != Isa && interface != Eisa)
+ {
+ *confidence = 0;
+ return NO_ERROR;
+ }
+
+ //
+ // Work out and validate the adapter type being searched for.
+ //
+
+ adapterNumber = (index - 1000) / 100;
+
+ if (adapterNumber < 0 ||
+ adapterNumber >= sizeof(Adapters) / sizeof(ADAPTER_INFO) ||
+ (index % 100) != 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Type to find an adapter.
+ //
+
+ retCode = FindATCard(
+ (ULONG) adapterNumber,
+ busNumber,
+ interface,
+ (BOOLEAN) first,
+ (ULONG) index,
+ confidence
+ );
+
+ if (retCode == NO_ERROR)
+ {
+ //
+ // In this module I use the token as follows: Remember that
+ // the token can only be 2 bytes long (the low 2) because of
+ // the interface to the upper part of this DLL.
+ //
+ // The rest of the high byte is the the bus number.
+ // The low byte is the driver index number into Adapters.
+ //
+ // NOTE: This presumes that there are < 129 buses in the
+ // system. Is this reasonable?
+ //
+
+ *token = (VOID *) ((busNumber & 0x7F) << 8);
+ *token = (VOID *) (((ULONG) *token) | (adapterNumber << 1));
+
+ if (interface == Eisa)
+ {
+ *token = (VOID *) (((ULONG) *token) | 1);
+ }
+ }
+
+ return retCode;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeATOpenHandleHandler
+*
+* Parameters - token -> Pointer to holder for a token that identifies
+* an adapter found by FirstNextHandler.
+* handle -> Pointer to a holder a handle the caller
+* should use to query the adapter refered to
+* by *token.
+*
+* Purpose - Generates a handle for an adapter just found by a call
+* to FirstNextHandler.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgeATOpenHandleHandler(
+ VOID * token,
+ VOID * * handle
+ )
+{
+ AT_ADAPTER * adapter;
+ ULONG adapterNumber;
+ ULONG busNumber;
+ INTERFACE_TYPE interface;
+
+ MadgePrint1("MadgeATOpenHandleHandler\n");
+
+ //
+ // Get info from the token.
+ //
+
+ busNumber = (ULONG) (((ULONG) token >> 8) & 0x7F);
+ adapterNumber = (((ULONG) token) & 0xFF) >> 1;
+
+ MadgePrint2("adapterNumber = %ld\n", adapterNumber);
+
+ if ((((ULONG) token) & 1) == 1)
+ {
+ interface = Eisa;
+ }
+ else
+ {
+ interface = Isa;
+ }
+
+ //
+ // Allocate a structure for the details of the adapter.
+ //
+
+ adapter = (AT_ADAPTER *) DetectAllocateHeap(sizeof(AT_ADAPTER));
+
+ if (adapter == NULL)
+ {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // Copy the details.
+ //
+
+ adapter->Found = TRUE;
+ adapter->CardType = Adapters[adapterNumber].Index;
+ adapter->InterfaceType = interface;
+ adapter->BusNumber = busNumber;
+ adapter->IoLocation =
+ ATIoLocations[SearchStates[adapterNumber].IoLocationIndex];
+ adapter->Irq = SearchStates[adapterNumber].Irq;
+ adapter->Dma = SearchStates[adapterNumber].Dma;
+
+ *handle = (VOID *) adapter;
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeATCreateHandleHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* interface -> NT interface type (Eisa, Isa etc).
+* busNumber -> Number of the bus containing the adapter.
+* handle -> Pointer to a holder a handle the caller
+* should use to query the adapter.
+*
+* Purpose - Generates a handle for an adapter that has not been detected
+* but the caller claims exists.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgeATCreateHandleHandler(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ VOID * * handle
+ )
+{
+ AT_ADAPTER * adapter;
+ LONG numberOfAdapters;
+ LONG i;
+
+ MadgePrint2("MadgeATCreateHandleHandler (index = %ld)\n", index);
+
+ //
+ // Check that the interface type is correct for this module
+ // (could be an Isa adapter in an Eisa slot).
+ //
+
+ if (interface != Isa && interface != Eisa)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // If the index is valid then create a handle.
+ //
+
+ numberOfAdapters = sizeof(Adapters) / sizeof(ADAPTER_INFO);
+
+ for (i = 0; i < numberOfAdapters; i++)
+ {
+ if (Adapters[i].Index == index)
+ {
+ //
+ // Allocate a structure for the adapter details.
+ //
+
+ adapter = (AT_ADAPTER *) DetectAllocateHeap(sizeof(AT_ADAPTER));
+
+ if (adapter == NULL)
+ {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // Copy the details.
+ //
+
+ adapter->Found = FALSE;
+ adapter->CardType = index;
+ adapter->InterfaceType = interface;
+ adapter->BusNumber = busNumber;
+ adapter->IoLocation = ATIoLocations[0];
+ adapter->Irq = RESOURCE_UNKNOWN;
+ adapter->Dma = RESOURCE_UNKNOWN;
+
+ *handle = (VOID *) adapter;
+
+ return NO_ERROR;
+ }
+ }
+
+ //
+ // We didn't find an adapter type that matched the one the caller
+ // claims exists so return an error.
+ //
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeATCloseHandleHandler
+*
+* Parameters - handle -> Handle to be closed.
+*
+* Purpose - Closes a previously opened or created handle.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgeATCloseHandleHandler(
+ VOID * handle
+ )
+{
+ MadgePrint1("MadgeATCloseHandleHandler\n");
+
+ DetectFreeHeap(handle);
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeATQueryCfgHandler
+*
+* Parameters - handle -> Handle to for the adapter to be queried.
+* buffer -> Buffer for the returned parameters.
+* bufferSize -> Size of the buffer in WCHARs.
+*
+* Purpose - Find out what the parameters are for the adapter identified
+* by the handle. This function does not assume that the
+* adapter described by the handle is valid if the handle
+* was created rather than being opened. If the handle
+* was created then a search is made for an adapter.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgeATQueryCfgHandler(
+ VOID * handle,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ AT_ADAPTER * adapter;
+ ULONG confidence;
+ LONG adapterNumber;
+ LONG retCode;
+
+ MadgePrint1("MadgeATQueryCfgHandler\n");
+
+ //
+ // Do some initialisation.
+ //
+
+ adapter = (AT_ADAPTER *) handle;
+
+ //
+ // Check that the interface type specified by the handle is
+ // valid for this module (could be an Isa card in an Eisa slot).
+ //
+
+ if (adapter->InterfaceType != Isa && adapter->InterfaceType != Eisa)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // If the adapter was created rather than being opened we must search
+ // for an adapter.
+ //
+
+ if (!adapter->Found)
+ {
+ adapterNumber = (adapter->CardType - 1000) / 100;
+
+ retCode = FindATCard(
+ adapterNumber,
+ adapter->BusNumber,
+ adapter->InterfaceType,
+ TRUE,
+ adapter->CardType,
+ &confidence
+ );
+
+ //
+ // If we are not 100% sure that we found an adapter with
+ // the right ID we give up.
+ //
+
+ if (retCode != NO_ERROR || confidence != 100)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ adapter->Found = TRUE;
+ adapter->IoLocation =
+ ATIoLocations[SearchStates[adapterNumber].IoLocationIndex];
+ adapter->Irq = SearchStates[adapterNumber].Irq;
+ adapter->Dma = SearchStates[adapterNumber].Dma;
+
+ }
+
+ //
+ // Build resulting buffer.
+ //
+ // Copy in the IO location.
+ //
+
+ if (AppendParameter(
+ &buffer,
+ &bufferSize,
+ IoAddrString,
+ adapter->IoLocation
+ ) != NO_ERROR)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ //
+ // Copy in the DMA channel.
+ //
+
+ if (AppendParameter(
+ &buffer,
+ &bufferSize,
+ DmaChanString,
+ adapter->Dma
+ ) != NO_ERROR)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ //
+ // Copy in the IRQ number.
+ //
+
+ if (AppendParameter(
+ &buffer,
+ &bufferSize,
+ IrqString,
+ adapter->Irq
+ ) != NO_ERROR)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ //
+ // Copy in the multiprocessor flag.
+ //
+
+ if (AppendParameter(
+ &buffer,
+ &bufferSize,
+ MultiprocessorString,
+ IsMultiprocessor()
+ ) != NO_ERROR)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ //
+ // Copy in final \0.
+ //
+
+ if (bufferSize < 1)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ *buffer = L'\0';
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeATVerifyCfgHandler
+*
+* Parameters - handle -> Handle to for the adapter to be verified.
+* buffer -> Buffer containing the returned parameters.
+*
+* Purpose - Verify that the parameters in buffer are correct for
+* the adapter identified by handle.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgeATVerifyCfgHandler(
+ VOID * handle,
+ WCHAR * buffer
+ )
+{
+ AT_ADAPTER * adapter;
+ WCHAR * place;
+ BOOLEAN found;
+ ULONG ioLocation;
+ ULONG dmaChannel;
+ ULONG irqNumber;
+ ULONG multiprocessor;
+ LONG adapterNumber;
+
+ MadgePrint1("MadgeATVerifyCfgHandler\n");
+
+ //
+ // Do some initialisation.
+ //
+
+ adapter = (AT_ADAPTER *) handle;
+ adapterNumber = (adapter->CardType - 1000) / 100;
+
+ //
+ // Check that the interface type is correct for this module
+ // (could be an Isa adapter in an Eisa slot).
+ //
+
+ if (adapter->InterfaceType != Isa && adapter->InterfaceType != Eisa)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // Parse the parameters.
+ //
+
+ //
+ // Get the IO location.
+ //
+
+ place = FindParameterString(buffer, IoAddrString);
+
+ if (place == NULL)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ place += UnicodeStrLen(IoAddrString) + 1;
+
+ ScanForNumber(place, &ioLocation, &found);
+
+ if (!found)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // Get the DMA channel.
+ //
+
+ place = FindParameterString(buffer, DmaChanString);
+
+ if (place == NULL)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ place += UnicodeStrLen(DmaChanString) + 1;
+
+ ScanForNumber(place, &dmaChannel, &found);
+
+ if (!found)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // Get the IRQ number.
+ //
+
+ place = FindParameterString(buffer, IrqString);
+
+ if (place == NULL)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ place += UnicodeStrLen(IrqString) + 1;
+
+ ScanForNumber(place, &irqNumber, &found);
+
+ if (!found)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // Get the multiprocessor flag.
+ //
+
+ place = FindParameterString(buffer, MultiprocessorString);
+
+ if (place == NULL)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ place += UnicodeStrLen(MultiprocessorString) + 1;
+
+ //
+ // Now parse the value.
+ //
+
+ ScanForNumber(place, &multiprocessor, &found);
+
+ //
+ // If the handle does not refer to an adapter that has been found
+ // by search we must query the hardware.
+ //
+
+ if (!adapter->Found)
+ {
+ if (CheckForCard(
+ adapter->BusNumber,
+ adapter->InterfaceType,
+ ioLocation,
+ &adapter->Irq,
+ &adapter->Dma
+ ) != adapter->CardType)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ adapter->IoLocation = ioLocation;
+ adapter->Found = TRUE;
+ }
+
+ //
+ // Verify the parameters.
+ //
+
+ if (ioLocation != adapter->IoLocation ||
+ multiprocessor != IsMultiprocessor())
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ if (adapter->Dma == RESOURCE_UNKNOWN)
+ {
+ if (!IsValueInList(dmaChannel, ParamRange[adapterNumber].DmaRange))
+ {
+ return ERROR_INVALID_DATA;
+ }
+ }
+ else if (adapter->Dma != dmaChannel)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ if (adapter->Irq == RESOURCE_UNKNOWN)
+ {
+ if (!IsValueInList(irqNumber, ParamRange[adapterNumber].IrqRange))
+ {
+ return ERROR_INVALID_DATA;
+ }
+ }
+ else if (adapter->Irq != irqNumber)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // If we make it to here everything checked out ok.
+ //
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeATQueryMaskHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* buffer -> Buffer for the returned parameters.
+* bufferSize -> Size of buffer in WCHARs.
+*
+* Purpose - Return the list of parameters required for the adapter
+* type specified by index.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgeATQueryMaskHandler(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ WCHAR * params;
+ LONG length;
+ LONG numberOfAdapters;
+ LONG i;
+
+ MadgePrint2("MadgeATQueryMaskHandler (index = %ld)\n", index);
+ MadgePrint2("BufferSize = %ld\n", bufferSize);
+
+ //
+ // Find the adapter type.
+ //
+
+ numberOfAdapters = sizeof(Adapters) / sizeof(ADAPTER_INFO);
+
+ for (i = 0; i < numberOfAdapters; i++)
+ {
+ if (Adapters[i].Index == index)
+ {
+ params = Adapters[i].Parameters;
+
+ //
+ // Find the string length (Ends with 2 NULLs)
+ //
+
+ for (length = 0; ; length++)
+ {
+ if (params[length] == L'\0')
+ {
+ length++;
+
+ if (params[length] == L'\0')
+ {
+ break;
+ }
+ }
+ }
+
+ length++;
+
+ MadgePrint2("length = %ld\n", length);
+
+ //
+ // Copy the parameters into buffer.
+ //
+
+ if (bufferSize < length)
+ {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ memcpy((VOID *) buffer, params, length * sizeof(WCHAR));
+
+ return NO_ERROR;
+ }
+ }
+
+ //
+ // If we make it here we did not find a valid adapter type so
+ // return and error.
+ //
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeATParamRangeHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* param -> Paramter being queried.
+* buffer -> Buffer for the returned parameters.
+* bufferSize -> Size of buffer in LONGs.
+*
+* Purpose - Return the list of acceptable values for the parameter
+* specified.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgeATParamRangeHandler(
+ LONG index,
+ WCHAR * param,
+ LONG * buffer,
+ LONG * bufferSize
+ )
+{
+ LONG i;
+ LONG adapterNumber;
+ LONG count;
+
+ MadgePrint2("MadgeATParamRangeHandler (index=%ld)\n", index);
+
+ //
+ // Work out and validate the adapter number.
+ //
+
+ adapterNumber = (index - 1000) / 100;
+
+ if (adapterNumber < 0 ||
+ adapterNumber >= sizeof(Adapters) / sizeof(ADAPTER_INFO) ||
+ (index % 100) != 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // The simplest parameter is the IO location because this is the
+ // same for all of the adapter types.
+ //
+
+ if (UnicodeStringsEqual(param, IoAddrString))
+ {
+ count = sizeof(ATIoLocations) / sizeof(ULONG);
+
+ if (*bufferSize < count)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ buffer[i] = ATIoLocations[i];
+ }
+
+ *bufferSize = count;
+
+ return NO_ERROR;
+ }
+
+ //
+ // IRQ number is slightly more complicated because it is different
+ // for different adapter types.
+ //
+
+ else if (UnicodeStringsEqual(param, IrqString))
+ {
+ count = 0;
+
+ while (ParamRange[adapterNumber].IrqRange[count] != END_OF_LIST)
+ {
+ count++;
+ }
+
+ if (*bufferSize < count)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ buffer[i] = ParamRange[adapterNumber].IrqRange[i];
+ }
+
+ *bufferSize = count;
+
+ return NO_ERROR;
+ }
+
+
+ //
+ // Likewise DMA channel.
+ //
+
+ else if (UnicodeStringsEqual(param, DmaChanString))
+ {
+ count = 0;
+
+ while (ParamRange[adapterNumber].DmaRange[count] != END_OF_LIST)
+ {
+ count++;
+ }
+
+ if (*bufferSize < count)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ buffer[i] = ParamRange[adapterNumber].DmaRange[i];
+ }
+
+ *bufferSize = count;
+
+ return NO_ERROR;
+ }
+
+ //
+ // Or fill in the allowable values for the multiprocessor flag.
+ //
+
+ else if (UnicodeStringsEqual(param, MultiprocessorString))
+ {
+ if (*bufferSize < 2)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ *bufferSize = 2;
+
+ buffer[0] = 0;
+ buffer[1] = 1;
+
+ return NO_ERROR;
+ }
+
+ //
+ // If we reach this point we have been passed a parameter we
+ // don't know about.
+ //
+
+ return ERROR_INVALID_DATA;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeATQueryParameterNameHandler
+*
+* Parameters - param -> Paramter being queried.
+* buffer -> Buffer for the returned name.
+* bufferSize -> Size of buffer in WCHARs.
+*
+* Purpose - Return the name of a parameter.
+*
+* Returns - ERROR_INVALID_PARAMETER to cause the caller to use
+* the Microsoft provided default names.
+*
+****************************************************************************/
+
+LONG
+MadgeATQueryParameterNameHandler(
+ WCHAR * param,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/********* End of MDGAT.C **************************************************/
+
diff --git a/private/ntos/ndis/madge/detect/mdgeisa.c b/private/ntos/ndis/madge/detect/mdgeisa.c
new file mode 100644
index 000000000..a832e2728
--- /dev/null
+++ b/private/ntos/ndis/madge/detect/mdgeisa.c
@@ -0,0 +1,1288 @@
+/****************************************************************************
+*
+* MDGEISA.C
+*
+* EISA Adapter Detection Module
+*
+* Copyright (c) Madge Networks Ltd 1994
+*
+* COMPANY CONFIDENTIAL - RELEASED TO MICROSOFT CORP. ONLY FOR DEVELOPMENT
+* OF WINDOWS95 NETCARD DETECTION - THIS SOURCE IS NOT TO BE RELEASED OUTSIDE
+* OF MICROSOFT WITHOUT EXPLICIT WRITTEN PERMISSION FROM AN AUTHORISED
+* OFFICER OF MADGE NETWORKS LTD.
+*
+* Created: PBA 16/08/1994
+*
+****************************************************************************/
+
+#include <ntddk.h>
+#include <ntddnetd.h>
+
+#include <windef.h>
+#include <winerror.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mdgncdet.h"
+
+//
+// Prototype "borrowed" from WINUSER.H
+//
+
+extern int WINAPIV wsprintfW(LPWSTR, LPCWSTR, ...);
+
+
+/*---------------------------------------------------------------------------
+|
+| EISA adapter types. These correspond to the indexes that the upper layers
+| use for identifying adapters, so change them with care.
+|
+|--------------------------------------------------------------------------*/
+
+#define SMART_NONE 0
+#define SMART_EISA 1000
+
+
+/*---------------------------------------------------------------------------
+|
+| EISA Compressed ID.
+|
+| NT only seems to use the bottom 3 bytes of an EISA compressed ID.
+| This has mixed blessings. The advantage is that all of our EISA
+| adapters appear with the same compressed ID.
+|
+|--------------------------------------------------------------------------*/
+
+#define MADGE_COMPRESSED_ID 0x00008734L
+
+
+/*---------------------------------------------------------------------------
+|
+| List of adapter types supported by this module.
+|
+|---------------------------------------------------------------------------*/
+
+static
+ADAPTER_INFO Adapters[] =
+{
+ {
+ SMART_EISA,
+ MDGEISA,
+ L"Madge 16/4 Eisa Ringnode/Bridgnode",
+ L"Madge Networks",
+ L"SLOTNUMBER\0"
+ L"000\0"
+ L"00100\0"
+ L"DMACHANNEL\0"
+ L"000\0"
+ L"00100\0"
+ L"MULTIPROCESSOR\0"
+ L"000\0"
+ L"00100\0",
+ NULL,
+ 900
+ }
+};
+
+
+/*---------------------------------------------------------------------------
+|
+| Madge specific parameter range information. The order entries in this
+| table MUST match that in the Adapters table above. The first value
+Ý in each list is the default.
+|
+---------------------------------------------------------------------------*/
+
+static
+struct
+{
+ ULONG SlotNumber[16];
+ ULONG DmaRange[2];
+}
+ParamRange[] =
+{
+ //
+ // Smart 16/4 EISA.
+ //
+
+ {
+ { 1, 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, END_OF_LIST},
+
+ {GENERAL_DMA, END_OF_LIST}
+ }
+};
+
+
+/*---------------------------------------------------------------------------
+|
+| Structure for holding state of a search.
+|
+|--------------------------------------------------------------------------*/
+
+typedef struct
+{
+ ULONG SlotNumber;
+}
+EISA_SEARCH_STATE;
+
+
+/*---------------------------------------------------------------------------
+|
+| This is an array of search states. We need one state for each type
+| of adapter supported.
+|
+|--------------------------------------------------------------------------*/
+
+static
+EISA_SEARCH_STATE SearchStates[sizeof(Adapters) / sizeof(ADAPTER_INFO)] = {0};
+
+
+/*---------------------------------------------------------------------------
+|
+| Structure for holding a particular adapter's complete information.
+|
+|--------------------------------------------------------------------------*/
+
+typedef struct
+{
+ BOOLEAN Found;
+ ULONG CardType;
+ INTERFACE_TYPE InterfaceType;
+ ULONG BusNumber;
+ ULONG SlotNumber;
+ ULONG Dma;
+}
+EISA_ADAPTER;
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - CompIdToCardType
+|
+| Parameters - compId -> A compressed EISA Id.
+|
+| Purpose - Translate a compressed EISA Id into a card type.
+|
+| Returns - A Madge card type of SMART_NONE if the compressed Id
+| is not recognised.
+|
+---------------------------------------------------------------------------*/
+
+static ULONG
+CompIdToCardType(
+ ULONG compId
+ )
+{
+ if (compId == MADGE_COMPRESSED_ID)
+ {
+ return SMART_EISA;
+ }
+
+ return SMART_NONE;
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - FindEisaCard
+|
+| Parameters - adapterNumber -> Adapter type index used to index the
+| global array SearchStates.
+| busNumber -> The bus number to search.
+| first -> TRUE if this is the first call for
+| a given adapter type.
+| type -> The type of adapter being searched for.
+| confidence -> Pointer a holder for the confidence in
+| which the adapter was found.
+|
+| Purpose - Search the specified EISA bus for an adapter with the
+| specified compressed ID. If first is TRUE then the search
+| starts from slot number 1. If first is FALSE then the
+| search starts from one after the last slot checked the
+| previous time FindEisaCard was called.
+|
+| Returns - A WINERROR.H error code.
+|
+|--------------------------------------------------------------------------*/
+
+static ULONG
+FindEisaCard(
+ ULONG adapterNumber,
+ ULONG busNumber,
+ BOOLEAN first,
+ ULONG type,
+ ULONG * confidence
+ )
+{
+ VOID * busHandle;
+ ULONG compressedId;
+
+ //
+ // If this is the first call then we want to start from slot
+ // number 1.
+ //
+
+ if (first)
+ {
+ SearchStates[adapterNumber].SlotNumber = 1;
+ }
+
+ //
+ // Otherwise we want to start from 1 after were we left off
+ // last time.
+ //
+
+ else
+ {
+ SearchStates[adapterNumber].SlotNumber++;
+ }
+
+ //
+ // Get a handle onto NT's information for the EISA bus with the
+ // number busNumber.
+ //
+
+ if (!GetEisaKey(busNumber, &busHandle))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Step through the slots in the bus looking for one with our
+ // compressed ID for which there isn't already a Madge card installed.
+ // If we don't find one we will return a confidence level of zero.
+ //
+
+ *confidence = 0;
+
+ while (GetEisaCompressedId(
+ busHandle,
+ SearchStates[adapterNumber].SlotNumber,
+ &compressedId
+ ))
+ {
+ if (CompIdToCardType(compressedId) == type)
+ {
+ if (!MadgeCardAlreadyInstalled(
+ TRUE,
+ busNumber,
+ SearchStates[adapterNumber].SlotNumber
+ ))
+ {
+ *confidence = 100;
+ break;
+ }
+ }
+
+ SearchStates[adapterNumber].SlotNumber++;
+ }
+
+ DeleteEisaKey(busHandle);
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeEisaIdentifyHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* buffer -> Buffer for the results.
+* bufferSize -> Size of the buffer in WCHARs.
+*
+* Purpose - Return information about a type of adapter that this module
+* supports.
+*
+* Returns - A WINERROR.H error code. ERROR_NO_MORE_ITEMS
+* is returned if index refers to an adapter type not
+* supported.
+*
+****************************************************************************/
+
+LONG
+MadgeEisaIdentifyHandler(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ LONG numberOfAdapters;
+ LONG action;
+ LONG length;
+ LONG i;
+
+ MadgePrint2("MadgeEisaIdentifyHandler (index = %ld)\n", index);
+
+ //
+ // Do some initialisation.
+ //
+
+ numberOfAdapters = sizeof(Adapters) / sizeof(ADAPTER_INFO);
+ action = index % 100;
+ index = index - action;
+
+ //
+ // Check that index does not exceed the number of adapters we
+ // support.
+ //
+
+ if ((index - 1000) / 100 >= numberOfAdapters)
+ {
+ return ERROR_NO_MORE_ITEMS;
+ }
+
+ //
+ // If index refers to an adapter type supported then carry out the
+ // requested action.
+ //
+
+ for (i = 0; i < numberOfAdapters; i++)
+ {
+ if (Adapters[i].Index == index)
+ {
+ switch (action)
+ {
+ //
+ // Return the adapter's abbreviation.
+ //
+
+ case 0:
+
+ length = UnicodeStrLen(Adapters[i].InfId) + 1;
+
+ if (bufferSize < length)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ memcpy(
+ (VOID *) buffer,
+ Adapters[i].InfId,
+ length * sizeof(WCHAR)
+ );
+
+ break;
+
+ //
+ // Return the adapter's description.
+ //
+
+ case 1:
+
+ length = UnicodeStrLen(Adapters[i].CardDescription) + 1;
+
+ if (bufferSize < length)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ memcpy(
+ (VOID *) buffer,
+ Adapters[i].CardDescription,
+ length * sizeof(WCHAR)
+ );
+
+ break;
+
+ //
+ // Return the adapter's manufacturer.
+ //
+
+ case 2:
+
+ length = UnicodeStrLen(Adapters[i].Manufacturer) + 1;
+
+ if (bufferSize < length)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ memcpy(
+ (VOID *) buffer,
+ Adapters[i].Manufacturer,
+ length * sizeof(WCHAR)
+ );
+
+ break;
+
+ //
+ // Return the search order.
+ //
+
+ case 3:
+
+ if (bufferSize < 5)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ wsprintfW(
+ (VOID *) buffer,
+ L"%d",
+ Adapters[i].SearchOrder
+ );
+
+ break;
+
+ //
+ // Anything else is invalid.
+ //
+
+ default:
+
+ return ERROR_INVALID_PARAMETER;
+
+ }
+
+ return NO_ERROR;
+ }
+ }
+
+ //
+ // We didn't find an adapter type that matched the index so
+ // return an error.
+ //
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeEisaFirstNextHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* interface -> The NT interface type (ISA, EISA etc).
+* busNumber -> The bus number to search.
+* first -> TRUE if the search of this bus should start
+* from scratch.
+* token -> Pointer to holder for a token that identifies
+* the adapter found.
+* confidence -> Pointer to a holder for the confidence by
+* which the adapter has been found.
+*
+* Purpose - Attempts to find an adapter on the specified bus. If first
+* is TRUE then the search starts from scratch. Otherwise
+* the search starts from where it left of the last time we
+* were called.
+*
+* Returns - A WINERROR.H error code. A return code of NO_ERROR
+* and a *confidence of 0 means we didn't find an adapter.
+*
+****************************************************************************/
+
+LONG
+MadgeEisaFirstNextHandler(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ BOOL first,
+ VOID * * token,
+ LONG * confidence
+ )
+{
+ ULONG retCode;
+ LONG adapterNumber;
+
+ MadgePrint2("MadgeEisaFirstNextHandler (index = %ld)\n", index);
+
+ //
+ // Check the interface type.
+ //
+
+ if (interface != Eisa)
+ {
+ *confidence = 0;
+ return NO_ERROR;
+ }
+
+ //
+ // Work out and validate the adapter type being searched for.
+ //
+
+ adapterNumber = (index - 1000) / 100;
+
+ if (adapterNumber < 0 ||
+ adapterNumber >= sizeof(Adapters) / sizeof(ADAPTER_INFO) ||
+ (index % 100) != 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Type to find an adapter.
+ //
+
+ retCode = FindEisaCard(
+ (ULONG) adapterNumber,
+ busNumber,
+ (BOOLEAN) first,
+ (ULONG) index,
+ confidence
+ );
+
+ if (retCode == NO_ERROR)
+ {
+ //
+ // In this module I use the token as follows: Remember that
+ // the token can only be 2 bytes long (the low 2) because of
+ // the interface to the upper part of this DLL.
+ //
+ // The rest of the high byte is the the bus number.
+ // The low byte is the driver index number into Adapters.
+ //
+ // NOTE: This presumes that there are < 129 buses in the
+ // system. Is this reasonable?
+ //
+
+ *token = (VOID *) ((busNumber & 0x7F) << 8);
+ *token = (VOID *) (((ULONG) *token) | adapterNumber);
+ }
+
+ return retCode;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeEisaOpenHandleHandler
+*
+* Parameters - token -> Pointer to holder for a token that identifies
+* an adapter found by FirstNextHandler.
+* handle -> Pointer to a holder a handle the caller
+* should use to query the adapter refered to
+* by *token.
+*
+* Purpose - Generates a handle for an adapter just found by a call
+* to FirstNextHandler.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgeEisaOpenHandleHandler(
+ VOID * token,
+ VOID * * handle
+ )
+{
+ EISA_ADAPTER * adapter;
+ ULONG adapterNumber;
+ ULONG busNumber;
+ INTERFACE_TYPE interface;
+
+ MadgePrint1("MadgeEisaOpenHandleHandler\n");
+
+ //
+ // Get info from the token.
+ //
+
+ interface = Eisa;
+ busNumber = (ULONG) (((ULONG) token >> 8) & 0x7F);
+ adapterNumber = ((ULONG) token) & 0xFF;
+
+ //
+ // Allocate a structure for the details of the adapter.
+ //
+
+ adapter = (EISA_ADAPTER *) DetectAllocateHeap(sizeof(EISA_ADAPTER));
+
+ if (adapter == NULL)
+ {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // Copy the details.
+ //
+
+ adapter->Found = TRUE;
+ adapter->SlotNumber = SearchStates[adapterNumber].SlotNumber;
+ adapter->CardType = Adapters[adapterNumber].Index;
+ adapter->InterfaceType = interface;
+ adapter->BusNumber = busNumber;
+ adapter->Dma = GENERAL_DMA; // EISA is always DMA.
+
+ *handle = (VOID *) adapter;
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeEisaCreateHandleHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* interface -> NT interface type (Eisa, Isa etc).
+* busNumber -> Number of the bus containing the adapter.
+* handle -> Pointer to a holder a handle the caller
+* should use to query the adapter.
+*
+* Purpose - Generates a handle for an adapter that has not been detected
+* but the caller claims exists.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgeEisaCreateHandleHandler(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ VOID * * handle
+ )
+{
+ EISA_ADAPTER * adapter;
+ LONG numberOfAdapters;
+ LONG i;
+
+ MadgePrint2("MadgeEisaCreateHandleHandler (index = %ld)\n", index);
+
+ //
+ // Check that the interface type is correct for this module.
+ //
+
+ if (interface != Eisa)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // If the index is valid then create a handle.
+ //
+
+ numberOfAdapters = sizeof(Adapters) / sizeof(ADAPTER_INFO);
+
+ for (i = 0; i < numberOfAdapters; i++)
+ {
+ if (Adapters[i].Index == index)
+ {
+ //
+ // Allocate a structure for the adapter details.
+ //
+
+ adapter = (EISA_ADAPTER *) DetectAllocateHeap(
+ sizeof(EISA_ADAPTER)
+ );
+ if (adapter == NULL)
+ {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // Copy the details.
+ //
+
+ adapter->Found = FALSE;
+ adapter->SlotNumber = 1;
+ adapter->CardType = index;
+ adapter->InterfaceType = interface;
+ adapter->BusNumber = busNumber;
+ adapter->Dma = GENERAL_DMA; // EISA is always DMA.
+
+ *handle = (VOID *) adapter;
+
+ return NO_ERROR;
+ }
+ }
+
+ //
+ // We didn't find an adapter type that matched the one the caller
+ // claims exists so return an error.
+ //
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeEisaCloseHandleHandler
+*
+* Parameters - handle -> Handle to be closed.
+*
+* Purpose - Closes a previously opened or created handle.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgeEisaCloseHandleHandler(
+ VOID * handle
+ )
+{
+ MadgePrint1("MadgeEisaCloseHandleHandler\n");
+
+ DetectFreeHeap(handle);
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeEisaQueryCfgHandler
+*
+* Parameters - handle -> Handle to for the adapter to be queried.
+* buffer -> Buffer for the returned parameters.
+* bufferSize -> Size of the buffer in WCHARs.
+*
+* Purpose - Find out what the parameters are for the adapter identified
+* by the handle. This function does not assume that the
+* adapter described by the handle is valid. This is because
+* the handle could have been created rather than opened.
+* The function validates the handle and if the handle does
+* not identify a physical adapter then we attempt to
+* find an adapter that matches the handle.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgeEisaQueryCfgHandler(
+ VOID * handle,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ EISA_ADAPTER * adapter;
+ VOID * busHandle;
+ ULONG confidence;
+ BOOLEAN found;
+ LONG adapterNumber;
+ LONG retCode;
+
+ //
+ // Do some initialisation.
+ //
+
+ adapter = (EISA_ADAPTER *) handle;
+
+ //
+ // Check that the interface type specified by the handle is
+ // valid for this module.
+ //
+
+ if (adapter->InterfaceType != Eisa)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // If the adapter was created rather than being opened we must search
+ // for an adapter.
+ //
+
+ if (!adapter->Found)
+ {
+ adapterNumber = (adapter->CardType - 1000) / 100;
+
+ retCode = FindEisaCard(
+ adapterNumber,
+ adapter->BusNumber,
+ TRUE,
+ adapter->CardType,
+ &confidence
+ );
+
+ //
+ // If we are not 100% sure that we found an adapter with
+ // the right ID we give up.
+ //
+
+ if (retCode != NO_ERROR || confidence != 100)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ adapter->Found = TRUE;
+ adapter->SlotNumber = SearchStates[adapterNumber].SlotNumber;
+ }
+
+ //
+ // Build resulting buffer.
+ //
+ // Copy in the slot number title and value.
+ //
+
+ if (AppendParameter(
+ &buffer,
+ &bufferSize,
+ SlotNumberString,
+ adapter->SlotNumber
+ ) != NO_ERROR)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ //
+ // Copy in the DMA channel title and value.
+ //
+
+ if (AppendParameter(
+ &buffer,
+ &bufferSize,
+ DmaChanString,
+ adapter->Dma
+ ) != NO_ERROR)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ //
+ // Copy in the multiprocessor flag.
+ //
+
+ if (AppendParameter(
+ &buffer,
+ &bufferSize,
+ MultiprocessorString,
+ IsMultiprocessor()
+ ) != NO_ERROR)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ //
+ // Copy in final \0.
+ //
+
+ if (bufferSize < 1)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ *buffer = L'\0';
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeEisaVerifyCfgHandler
+*
+* Parameters - handle -> Handle to for the adapter to be verified.
+* buffer -> Buffer containing the returned parameters.
+*
+* Purpose - Verify that the parameters in buffer are correct for
+* the adapter identified by handle.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgeEisaVerifyCfgHandler(
+ VOID * handle,
+ WCHAR * buffer
+ )
+{
+ EISA_ADAPTER * adapter;
+ WCHAR * place;
+ ULONG compressedId;
+ ULONG slotNumber;
+ ULONG dmaChannel;
+ ULONG multiprocessor;
+ VOID * busHandle;
+ BOOLEAN found;
+ LONG adapterNumber;
+
+ MadgePrint1("MadgeEisaVerifyCfgHandler\n");
+
+ //
+ // Do some initialisation.
+ //
+
+ adapter = (EISA_ADAPTER *) handle;
+ adapterNumber = (adapter->CardType - 1000) / 100;
+
+ //
+ // Check that the interface type is correct for this module.
+ //
+
+ if (adapter->InterfaceType != Eisa)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // Parse the parameters.
+ //
+ // Get the slot number.
+ //
+
+ place = FindParameterString(buffer, SlotNumberString);
+
+ if (place == NULL)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ place += UnicodeStrLen(SlotNumberString) + 1;
+
+ //
+ // Now parse the slot number.
+ //
+
+ ScanForNumber(place, &slotNumber, &found);
+
+ if (!found)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // Get the DMA channel.
+ //
+
+ place = FindParameterString(buffer, DmaChanString);
+
+ if (place == NULL)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ place += UnicodeStrLen(DmaChanString) + 1;
+
+ ScanForNumber(place, &dmaChannel, &found);
+
+ if (!found)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // Get the multiprocessor flag.
+ //
+
+ place = FindParameterString(buffer, MultiprocessorString);
+
+ if (place == NULL)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ place += UnicodeStrLen(MultiprocessorString) + 1;
+
+ //
+ // Now parse the value.
+ //
+
+ ScanForNumber(place, &multiprocessor, &found);
+
+ //
+ // If the adapter was created rather than being opened we must check
+ // the EISA configuration table to make sure the slot contains a
+ // Madge adapter.
+ //
+
+ if (!adapter->Found)
+ {
+ if (!GetEisaKey(adapter->BusNumber, &busHandle))
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ found = GetEisaCompressedId(
+ busHandle,
+ slotNumber,
+ &compressedId
+ );
+
+ DeleteEisaKey(busHandle);
+
+ if (!found || CompIdToCardType(compressedId) != adapter->CardType)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ adapter->Found = TRUE;
+ adapter->SlotNumber = slotNumber;
+ }
+
+ //
+ // Verify the parameter.
+ //
+
+ if (slotNumber != adapter->SlotNumber ||
+ multiprocessor != IsMultiprocessor())
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ if (adapter->Dma == RESOURCE_UNKNOWN)
+ {
+ if (!IsValueInList(dmaChannel, ParamRange[adapterNumber].DmaRange))
+ {
+ return ERROR_INVALID_DATA;
+ }
+ }
+ else if (adapter->Dma != dmaChannel)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // If we make it to here everything checked out ok.
+ //
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeEisaQueryMaskHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* buffer -> Buffer for the returned parameters.
+* bufferSize -> Size of buffer in WCHARs.
+*
+* Purpose - Return the list of parameters required for the adapter
+* type specified by index.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgeEisaQueryMaskHandler(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ WCHAR * params;
+ LONG length;
+ LONG numberOfAdapters;
+ LONG i;
+
+ MadgePrint1("MadgeEisaQueryMaskHandler\n");
+
+ //
+ // Find the adapter type.
+ //
+
+ numberOfAdapters = sizeof(Adapters) / sizeof(ADAPTER_INFO);
+
+ for (i = 0; i < numberOfAdapters; i++)
+ {
+ if (Adapters[i].Index == index)
+ {
+ params = Adapters[i].Parameters;
+
+ //
+ // Find the string length (Ends with 2 NULLs)
+ //
+
+ for (length = 0; ; length++)
+ {
+ if (params[length] == L'\0')
+ {
+ length++;
+
+ if (params[length] == L'\0')
+ {
+ break;
+ }
+ }
+ }
+
+ length++;
+
+ //
+ // Copy the parameters into buffer.
+ //
+
+ if (bufferSize < length)
+ {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ memcpy((VOID *) buffer, params, length * sizeof(WCHAR));
+
+ return NO_ERROR;
+ }
+ }
+
+ //
+ // If we make it here we did not find a valid adapter type so
+ // return and error.
+ //
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeEisaParamRangeHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* param -> Paramter being queried.
+* buffer -> Buffer for the returned parameters.
+* bufferSize -> Size of buffer in LONGs.
+*
+* Purpose - Return the list of acceptable values for the parameter
+* specified.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgeEisaParamRangeHandler(
+ LONG index,
+ WCHAR * param,
+ LONG * buffer,
+ LONG * bufferSize
+ )
+{
+ LONG adapterNumber;
+ LONG count;
+ LONG i;
+
+ //
+ // Work out and validate the adapter number.
+ //
+
+ adapterNumber = (index - 1000) / 100;
+
+ if (adapterNumber < 0 ||
+ adapterNumber >= sizeof(Adapters) / sizeof(ADAPTER_INFO) ||
+ (index % 100) != 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Fill in the allowable slot numbers in the buffer.
+ //
+
+ if (UnicodeStringsEqual(param, SlotNumberString))
+ {
+ count = 0;
+
+ while (ParamRange[adapterNumber].SlotNumber[count] != END_OF_LIST)
+ {
+ count++;
+ }
+
+ if (*bufferSize < count)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ buffer[i] = ParamRange[adapterNumber].SlotNumber[i];
+ }
+
+ *bufferSize = count;
+
+ return NO_ERROR;
+ }
+
+ //
+ // Or the valid DMA channels.
+ //
+
+ else if (UnicodeStringsEqual(param, DmaChanString))
+ {
+ count = 0;
+
+ while (ParamRange[adapterNumber].DmaRange[count] != END_OF_LIST)
+ {
+ count++;
+ }
+
+ if (*bufferSize < count)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ buffer[i] = ParamRange[adapterNumber].DmaRange[i];
+ }
+
+ *bufferSize = count;
+
+ return NO_ERROR;
+ }
+
+ //
+ // Or fill in the allowable values for the multiprocessor flag.
+ //
+
+ else if (UnicodeStringsEqual(param, MultiprocessorString))
+ {
+ if (*bufferSize < 2)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ *bufferSize = 2;
+
+ buffer[0] = 0;
+ buffer[1] = 1;
+
+ return NO_ERROR;
+ }
+
+ //
+ // If we reach this point we have been passed a parameter we
+ // don't know about.
+ //
+
+ return ERROR_INVALID_DATA;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeEisaQueryParameterNameHandler
+*
+* Parameters - param -> Paramter being queried.
+* buffer -> Buffer for the returned name.
+* bufferSize -> Size of buffer in WCHARs.
+*
+* Purpose - Return the name of a parameter.
+*
+* Returns - ERROR_INVALID_PARAMETER to cause the caller to use
+* the Microsoft provided default names.
+*
+****************************************************************************/
+
+LONG
+MadgeEisaQueryParameterNameHandler(
+ WCHAR * param,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/********* End of MDGEISA.C ************************************************/
+
diff --git a/private/ntos/ndis/madge/detect/mdgmc.c b/private/ntos/ndis/madge/detect/mdgmc.c
new file mode 100644
index 000000000..112af2532
--- /dev/null
+++ b/private/ntos/ndis/madge/detect/mdgmc.c
@@ -0,0 +1,1316 @@
+/****************************************************************************
+*
+* MDGMC.C
+*
+* MC Adapter Detection Module
+*
+* Copyright (c) Madge Networks Ltd 1994
+*
+* COMPANY CONFIDENTIAL - RELEASED TO MICROSOFT CORP. ONLY FOR DEVELOPMENT
+* OF WINDOWS95 NETCARD DETECTION - THIS SOURCE IS NOT TO BE RELEASED OUTSIDE
+* OF MICROSOFT WITHOUT EXPLICIT WRITTEN PERMISSION FROM AN AUTHORISED
+* OFFICER OF MADGE NETWORKS LTD.
+*
+* Created: PBA 14/09/1994
+*
+****************************************************************************/
+
+#include <ntddk.h>
+#include <ntddnetd.h>
+
+#include <windef.h>
+#include <winerror.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mdgncdet.h"
+
+//
+// Prototype "borrowed" from WINUSER.H
+//
+
+extern int WINAPIV wsprintfW(LPWSTR, LPCWSTR, ...);
+
+
+/*---------------------------------------------------------------------------
+|
+| MC adapter types. These correspond to the indexes that the upper layers
+| use for identifying adapters, so change them with care.
+|
+|--------------------------------------------------------------------------*/
+
+#define SMART_NONE 0
+#define SMART_MC16 1000
+#define SMART_MC32 1100
+
+
+/*---------------------------------------------------------------------------
+|
+| Madge MC ADF IDs.
+|
+|--------------------------------------------------------------------------*/
+
+#define MADGE_MC16_ID 0x002d
+#define MADGE_MC32_ID 0x0074
+
+
+/*---------------------------------------------------------------------------
+|
+| List of adapter types supported by this module.
+|
+|---------------------------------------------------------------------------*/
+
+static
+ADAPTER_INFO Adapters[] =
+{
+ {
+ SMART_MC16,
+ MDGMC16,
+ L"Madge 16/4 MC16 Ringnode",
+ L"Madge Networks",
+ L"SLOTNUMBER\0"
+ L"000\0"
+ L"00100\0"
+ L"DMACHANNEL\0"
+ L"000\0"
+ L"00100\0"
+ L"MULTIPROCESSOR\0"
+ L"000\0"
+ L"00100\0",
+ NULL,
+ 900
+ },
+
+ {
+ SMART_MC32,
+ MDGMC32,
+ L"Madge 16/4 MC32 Ringnode",
+ L"Madge Networks",
+ L"SLOTNUMBER\0"
+ L"000\0"
+ L"00100\0"
+ L"DMACHANNEL\0"
+ L"000\0"
+ L"00100\0"
+ L"MULTIPROCESSOR\0"
+ L"000\0"
+ L"00100\0",
+ NULL,
+ 900
+ }
+
+};
+
+
+/*---------------------------------------------------------------------------
+|
+| Madge specific parameter range information. The order entries in this
+| table MUST match that in the Adapters table above. The first value
+Ý in each list is the default.
+|
+---------------------------------------------------------------------------*/
+
+static
+struct
+{
+ ULONG SlotNumber[11];
+ ULONG DmaRange[2];
+}
+ParamRange[] =
+{
+ //
+ // Smart 16/4 MC16.
+ //
+
+ {
+ { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, END_OF_LIST},
+ { GENERAL_DMA, END_OF_LIST}
+ },
+
+ //
+ // Smart 16/4 MC32.
+ //
+
+ {
+ { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, END_OF_LIST},
+ { GENERAL_DMA, END_OF_LIST}
+ }
+
+};
+
+
+/*---------------------------------------------------------------------------
+|
+| Structure for holding state of a search.
+|
+|--------------------------------------------------------------------------*/
+
+typedef struct
+{
+ ULONG SlotNumber;
+}
+MC_SEARCH_STATE;
+
+
+/*---------------------------------------------------------------------------
+|
+| This is an array of search states. We need one state for each type
+| of adapter supported.
+|
+|--------------------------------------------------------------------------*/
+
+static
+MC_SEARCH_STATE SearchStates[sizeof(Adapters) / sizeof(ADAPTER_INFO)] = {0};
+
+
+/*---------------------------------------------------------------------------
+|
+| Structure for holding a particular adapter's complete information.
+|
+|--------------------------------------------------------------------------*/
+
+typedef struct
+{
+ BOOLEAN Found;
+ ULONG CardType;
+ INTERFACE_TYPE InterfaceType;
+ ULONG BusNumber;
+ ULONG SlotNumber;
+ ULONG Dma;
+}
+MC_ADAPTER;
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - AdfIdToCardType
+|
+| Parameters - adfId -> An MC ADF Id.
+|
+| Purpose - Translate an ADF Id into a card type.
+|
+| Returns - A Madge card type of SMART_NONE if the ADF Id
+| is not recognised.
+|
+---------------------------------------------------------------------------*/
+
+static ULONG
+AdfIdToCardType(
+ ULONG adfId
+ )
+{
+ if (adfId == MADGE_MC16_ID)
+ {
+ return SMART_MC16;
+ }
+ else if (adfId == MADGE_MC32_ID)
+ {
+ return SMART_MC32;
+ }
+
+ return SMART_NONE;
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - FindMCCard
+|
+| Parameters - adapterNumber -> Adapter type index used to index the
+| global array SearchStates.
+| busNumber -> The bus number to search.
+| first -> TRUE if this is the first call for
+| a given adapter type.
+| type -> The type of adapter being searched for.
+| confidence -> Pointer a holder for the confidence in
+| which the adapter was found.
+|
+| Purpose - Search the specified MC bus for an adapter with the
+| specified compressed ID. If first is TRUE then the search
+| starts from slot number 1. If first is FALSE then the
+| search starts from one after the last slot checked the
+| previous time FindMCCard was called.
+|
+| Returns - A WINERROR.H error code.
+|
+|--------------------------------------------------------------------------*/
+
+static ULONG
+FindMCCard(
+ ULONG adapterNumber,
+ ULONG busNumber,
+ BOOLEAN first,
+ ULONG type,
+ ULONG * confidence
+ )
+{
+ VOID * busHandle;
+ ULONG adfId;
+
+ //
+ // If this is the first call then we want to start from slot
+ // number 1.
+ //
+
+ if (first)
+ {
+ SearchStates[adapterNumber].SlotNumber = 1;
+ }
+
+ //
+ // Otherwise we want to start from 1 after were we left off
+ // last time.
+ //
+
+ else
+ {
+ SearchStates[adapterNumber].SlotNumber++;
+ }
+
+ //
+ // Get a handle onto NT's information for the MC bus with the
+ // number busNumber.
+ //
+
+ if (!GetMcaKey(busNumber, &busHandle))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Step through the slots in the bus looking for one with our
+ // ADF ID for which there isn't a Madge card installed.
+ // If we don't find one we will return a confidence
+ // level of zero.
+ //
+
+ *confidence = 0;
+
+ while (GetMcaPosId(
+ busHandle,
+ SearchStates[adapterNumber].SlotNumber,
+ &adfId
+ ))
+ {
+ if (AdfIdToCardType(adfId) == type)
+ {
+ if (!MadgeCardAlreadyInstalled(
+ TRUE,
+ busNumber,
+ SearchStates[adapterNumber].SlotNumber
+ ))
+ {
+ *confidence = 100;
+ break;
+ }
+ }
+
+ SearchStates[adapterNumber].SlotNumber++;
+ }
+
+ DeleteMcaKey(busHandle);
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeMCIdentifyHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* buffer -> Buffer for the results.
+* bufferSize -> Size of the buffer in WCHARs.
+*
+* Purpose - Return information about a type of adapter that this module
+* supports.
+*
+* Returns - A WINERROR.H error code. ERROR_NO_MORE_ITEMS
+* is returned if index refers to an adapter type not
+* supported.
+*
+****************************************************************************/
+
+LONG
+MadgeMCIdentifyHandler(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ LONG numberOfAdapters;
+ LONG action;
+ LONG length;
+ LONG i;
+
+ MadgePrint2("MadgeMCIdentifyHandler (index = %ld)\n", index);
+
+ //
+ // Do some initialisation.
+ //
+
+ numberOfAdapters = sizeof(Adapters) / sizeof(ADAPTER_INFO);
+ action = index % 100;
+ index = index - action;
+
+ //
+ // Check that index does not exceed the number of adapters we
+ // support.
+ //
+
+ if ((index - 1000) / 100 >= numberOfAdapters)
+ {
+ return ERROR_NO_MORE_ITEMS;
+ }
+
+ //
+ // If index refers to an adapter type supported then carry out the
+ // requested action.
+ //
+
+ for (i = 0; i < numberOfAdapters; i++)
+ {
+ if (Adapters[i].Index == index)
+ {
+ switch (action)
+ {
+ //
+ // Return the adapter's abbreviation.
+ //
+
+ case 0:
+
+ length = UnicodeStrLen(Adapters[i].InfId) + 1;
+
+ if (bufferSize < length)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ memcpy(
+ (VOID *) buffer,
+ Adapters[i].InfId,
+ length * sizeof(WCHAR)
+ );
+
+ break;
+
+ //
+ // Return the adapter's description.
+ //
+
+ case 1:
+
+ length = UnicodeStrLen(Adapters[i].CardDescription) + 1;
+
+ if (bufferSize < length)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ memcpy(
+ (VOID *) buffer,
+ Adapters[i].CardDescription,
+ length * sizeof(WCHAR)
+ );
+
+ break;
+
+ //
+ // Return the adapter's manufacturer.
+ //
+
+ case 2:
+
+ length = UnicodeStrLen(Adapters[i].Manufacturer) + 1;
+
+ if (bufferSize < length)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ memcpy(
+ (VOID *) buffer,
+ Adapters[i].Manufacturer,
+ length * sizeof(WCHAR)
+ );
+
+ break;
+
+ //
+ // Return the search order.
+ //
+
+ case 3:
+
+ if (bufferSize < 5)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ wsprintfW(
+ (VOID *) buffer,
+ L"%d",
+ Adapters[i].SearchOrder
+ );
+
+ break;
+
+ //
+ // Anything else is invalid.
+ //
+
+ default:
+
+ return ERROR_INVALID_PARAMETER;
+
+ }
+
+ return NO_ERROR;
+ }
+ }
+
+ //
+ // We didn't find an adapter type that matched the index so
+ // return an error.
+ //
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeMCFirstNextHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* interface -> The NT interface type (ISA, EISA etc).
+* busNumber -> The bus number to search.
+* first -> TRUE if the search of this bus should start
+* from scratch.
+* token -> Pointer to holder for a token that identifies
+* the adapter found.
+* confidence -> Pointer to a holder for the confidence by
+* which the adapter has been found.
+*
+* Purpose - Attempts to find an adapter on the specified bus. If first
+* is TRUE then the search starts from scratch. Otherwise
+* the search starts from where it left of the last time we
+* were called.
+*
+* Returns - A WINERROR.H error code. A return code of NO_ERROR
+* and a *confidence of 0 means we didn't find an adapter.
+*
+****************************************************************************/
+
+LONG
+MadgeMCFirstNextHandler(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ BOOL first,
+ VOID * * token,
+ LONG * confidence
+ )
+{
+ ULONG retCode;
+ LONG adapterNumber;
+
+ MadgePrint2("MadgeMCFirstNextHandler (index = %ld)\n", index);
+
+ //
+ // Check the interface type.
+ //
+
+ if (interface != MicroChannel)
+ {
+ *confidence = 0;
+ return NO_ERROR;
+ }
+
+ //
+ // Work out and validate the adapter type being searched for.
+ //
+
+ adapterNumber = (index - 1000) / 100;
+
+ if (adapterNumber < 0 ||
+ adapterNumber >= sizeof(Adapters) / sizeof(ADAPTER_INFO) ||
+ (index % 100) != 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Type to find an adapter.
+ //
+
+ retCode = FindMCCard(
+ (ULONG) adapterNumber,
+ busNumber,
+ (BOOLEAN) first,
+ (ULONG) index,
+ confidence
+ );
+
+ if (retCode == NO_ERROR)
+ {
+ //
+ // In this module I use the token as follows: Remember that
+ // the token can only be 2 bytes long (the low 2) because of
+ // the interface to the upper part of this DLL.
+ //
+ // The rest of the high byte is the the bus number.
+ // The low byte is the driver index number into Adapters.
+ //
+ // NOTE: This presumes that there are < 129 buses in the
+ // system. Is this reasonable?
+ //
+
+ *token = (VOID *) ((busNumber & 0x7F) << 8);
+ *token = (VOID *) (((ULONG) *token) | adapterNumber);
+ }
+
+ return retCode;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeMCOpenHandleHandler
+*
+* Parameters - token -> Pointer to holder for a token that identifies
+* an adapter found by FirstNextHandler.
+* handle -> Pointer to a holder a handle the caller
+* should use to query the adapter refered to
+* by *token.
+*
+* Purpose - Generates a handle for an adapter just found by a call
+* to FirstNextHandler.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgeMCOpenHandleHandler(
+ VOID * token,
+ VOID * * handle
+ )
+{
+ MC_ADAPTER * adapter;
+ ULONG adapterNumber;
+ ULONG busNumber;
+ INTERFACE_TYPE interface;
+
+ MadgePrint1("MadgeMCOpenHandleHandler\n");
+
+ //
+ // Get info from the token.
+ //
+
+ interface = MicroChannel;
+ busNumber = (ULONG) (((ULONG) token >> 8) & 0x7F);
+ adapterNumber = ((ULONG) token) & 0xFF;
+
+ //
+ // Allocate a structure for the details of the adapter.
+ //
+
+ adapter = (MC_ADAPTER *) DetectAllocateHeap(sizeof(MC_ADAPTER));
+
+ if (adapter == NULL)
+ {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // Copy the details.
+ //
+
+ adapter->Found = TRUE;
+ adapter->SlotNumber = SearchStates[adapterNumber].SlotNumber;
+ adapter->CardType = Adapters[adapterNumber].Index;
+ adapter->InterfaceType = interface;
+ adapter->BusNumber = busNumber;
+ adapter->Dma = GENERAL_DMA; // MC's are always DMA.
+
+ *handle = (VOID *) adapter;
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeMCCreateHandleHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* interface -> NT interface type (Eisa, Isa etc).
+* busNumber -> Number of the bus containing the adapter.
+* handle -> Pointer to a holder a handle the caller
+* should use to query the adapter.
+*
+* Purpose - Generates a handle for an adapter that has not been detected
+* but the caller claims exists.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgeMCCreateHandleHandler(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ VOID * * handle
+ )
+{
+ MC_ADAPTER * adapter;
+ LONG numberOfAdapters;
+ LONG i;
+
+ MadgePrint2("MadgeMCCreateHandleHandler (index = %ld)\n", index);
+
+ //
+ // Check that the interface type is correct for this module.
+ //
+
+ if (interface != MicroChannel)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // If the index is valid then create a handle.
+ //
+
+ numberOfAdapters = sizeof(Adapters) / sizeof(ADAPTER_INFO);
+
+ for (i = 0; i < numberOfAdapters; i++)
+ {
+ if (Adapters[i].Index == index)
+ {
+ //
+ // Allocate a structure for the adapter details.
+ //
+
+ adapter = (MC_ADAPTER *) DetectAllocateHeap(sizeof(MC_ADAPTER));
+
+ if (adapter == NULL)
+ {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // Copy the details.
+ //
+
+ adapter->Found = FALSE;
+ adapter->SlotNumber = 1;
+ adapter->CardType = index;
+ adapter->InterfaceType = interface;
+ adapter->BusNumber = busNumber;
+ adapter->Dma = GENERAL_DMA; // MC's are always DMA.
+
+ *handle = (VOID *) adapter;
+
+ return NO_ERROR;
+ }
+ }
+
+ //
+ // We didn't find an adapter type that matched the one the caller
+ // claims exists so return an error.
+ //
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeMCCloseHandleHandler
+*
+* Parameters - handle -> Handle to be closed.
+*
+* Purpose - Closes a previously opened or created handle.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgeMCCloseHandleHandler(
+ VOID * handle
+ )
+{
+ MadgePrint1("MadgeMCCloseHandleHandler\n");
+
+ DetectFreeHeap(handle);
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeMCQueryCfgHandler
+*
+* Parameters - handle -> Handle to for the adapter to be queried.
+* buffer -> Buffer for the returned parameters.
+* bufferSize -> Size of the buffer in WCHARs.
+*
+* Purpose - Find out what the parameters are for the adapter identified
+* by the handle. This function does not assume that the
+* adapter described by the handle is valid. This is because
+* the handle could have been created rather than opened.
+* The function validates the handle and if the handle does
+* not identify a physical adapter then we attempt to
+* find an adapter that matches the handle.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgeMCQueryCfgHandler(
+ VOID * handle,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ MC_ADAPTER * adapter;
+ VOID * busHandle;
+ ULONG confidence;
+ BOOLEAN found;
+ LONG adapterNumber;
+ LONG retCode;
+
+ //
+ // Do some initialisation.
+ //
+
+ adapter = (MC_ADAPTER *) handle;
+
+ //
+ // Check that the interface type specified by the handle is
+ // valid for this module.
+ //
+
+ if (adapter->InterfaceType != MicroChannel)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // If the adapter was created rather than being opened we must search
+ // for an adapter.
+ //
+
+ if (!adapter->Found)
+ {
+ adapterNumber = (adapter->CardType - 1000) / 100;
+
+ retCode = FindMCCard(
+ adapterNumber,
+ adapter->BusNumber,
+ TRUE,
+ adapter->CardType,
+ &confidence
+ );
+
+ //
+ // If we are not 100% sure that we found an adapter with
+ // the right ID we give up.
+ //
+
+ if (retCode != NO_ERROR || confidence != 100)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ adapter->Found = TRUE;
+ adapter->SlotNumber = SearchStates[adapterNumber].SlotNumber;
+ }
+
+ //
+ // Build resulting buffer.
+ //
+ // Copy in the slot number title and value.
+ //
+
+ if (AppendParameter(
+ &buffer,
+ &bufferSize,
+ SlotNumberString,
+ adapter->SlotNumber
+ ) != NO_ERROR)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ //
+ // Copy in the DMA channel title and value.
+ //
+
+ if (AppendParameter(
+ &buffer,
+ &bufferSize,
+ DmaChanString,
+ adapter->Dma
+ ) != NO_ERROR)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ //
+ // Copy in the multiprocessor flag.
+ //
+
+ if (AppendParameter(
+ &buffer,
+ &bufferSize,
+ MultiprocessorString,
+ IsMultiprocessor()
+ ) != NO_ERROR)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ //
+ // Copy in final \0.
+ //
+
+ if (bufferSize < 1)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ *buffer = L'\0';
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeMCVerifyCfgHandler
+*
+* Parameters - handle -> Handle to for the adapter to be verified.
+* buffer -> Buffer containing the returned parameters.
+*
+* Purpose - Verify that the parameters in buffer are correct for
+* the adapter identified by handle.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgeMCVerifyCfgHandler(
+ VOID * handle,
+ WCHAR * buffer
+ )
+{
+ MC_ADAPTER * adapter;
+ WCHAR * place;
+ ULONG adfId;
+ ULONG slotNumber;
+ ULONG dmaChannel;
+ ULONG multiprocessor;
+ VOID * busHandle;
+ BOOLEAN found;
+ LONG adapterNumber;
+
+ MadgePrint1("MadgeMCVerifyCfgHandler\n");
+
+ //
+ // Do some initialisation.
+ //
+
+ adapter = (MC_ADAPTER *) handle;
+ adapterNumber = (adapter->CardType - 1000) / 100;
+
+ //
+ // Check that the interface type is correct for this module.
+ //
+
+ if (adapter->InterfaceType != MicroChannel)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // Parse the parameters.
+ //
+ // Get the slot number.
+ //
+
+ place = FindParameterString(buffer, SlotNumberString);
+
+ if (place == NULL)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ place += UnicodeStrLen(SlotNumberString) + 1;
+
+ //
+ // Now parse the slot number.
+ //
+
+ ScanForNumber(place, &slotNumber, &found);
+
+ if (!found)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // Get the DMA channel.
+ //
+
+ place = FindParameterString(buffer, DmaChanString);
+
+ if (place == NULL)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ place += UnicodeStrLen(DmaChanString) + 1;
+
+ ScanForNumber(place, &dmaChannel, &found);
+
+ if (!found)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // Get the multiprocessor flag.
+ //
+
+ place = FindParameterString(buffer, MultiprocessorString);
+
+ if (place == NULL)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ place += UnicodeStrLen(MultiprocessorString) + 1;
+
+ //
+ // Now parse the value.
+ //
+
+ ScanForNumber(place, &multiprocessor, &found);
+
+ //
+ // If the adapter was created rather than being opened we must check
+ // the POS table to make sure the slot contains a Madge adapter.
+ //
+
+ if (!adapter->Found)
+ {
+ if (!GetMcaKey(adapter->BusNumber, &busHandle))
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ found = GetMcaPosId(
+ busHandle,
+ slotNumber,
+ &adfId
+ );
+
+ DeleteMcaKey(busHandle);
+
+ if (!found || AdfIdToCardType(adfId) != adapter->CardType)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ adapter->Found = TRUE;
+ adapter->SlotNumber = slotNumber;
+ }
+
+ //
+ // Verify the parameter.
+ //
+
+ if (slotNumber != adapter->SlotNumber ||
+ multiprocessor != IsMultiprocessor())
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ if (adapter->Dma == RESOURCE_UNKNOWN)
+ {
+ if (!IsValueInList(dmaChannel, ParamRange[adapterNumber].DmaRange))
+ {
+ return ERROR_INVALID_DATA;
+ }
+ }
+ else if (adapter->Dma != dmaChannel)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // If we make it to here everything checked out ok.
+ //
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeMCQueryMaskHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* buffer -> Buffer for the returned parameters.
+* bufferSize -> Size of buffer in WCHARs.
+*
+* Purpose - Return the list of parameters required for the adapter
+* type specified by index.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgeMCQueryMaskHandler(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ WCHAR * params;
+ LONG length;
+ LONG numberOfAdapters;
+ LONG i;
+
+ MadgePrint1("MadgeMCQueryMaskHandler\n");
+
+ //
+ // Find the adapter type.
+ //
+
+ numberOfAdapters = sizeof(Adapters) / sizeof(ADAPTER_INFO);
+
+ for (i = 0; i < numberOfAdapters; i++)
+ {
+ if (Adapters[i].Index == index)
+ {
+ params = Adapters[i].Parameters;
+
+ //
+ // Find the string length (Ends with 2 NULLs)
+ //
+
+ for (length = 0; ; length++)
+ {
+ if (params[length] == L'\0')
+ {
+ length++;
+
+ if (params[length] == L'\0')
+ {
+ break;
+ }
+ }
+ }
+
+ length++;
+
+ //
+ // Copy the parameters into buffer.
+ //
+
+ if (bufferSize < length)
+ {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ memcpy((VOID *) buffer, params, length * sizeof(WCHAR));
+
+ return NO_ERROR;
+ }
+ }
+
+ //
+ // If we make it here we did not find a valid adapter type so
+ // return and error.
+ //
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeMCParamRangeHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* param -> Paramter being queried.
+* buffer -> Buffer for the returned parameters.
+* bufferSize -> Size of buffer in LONGs.
+*
+* Purpose - Return the list of acceptable values for the parameter
+* specified.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgeMCParamRangeHandler(
+ LONG index,
+ WCHAR * param,
+ LONG * buffer,
+ LONG * bufferSize
+ )
+{
+ LONG adapterNumber;
+ LONG count;
+ LONG i;
+
+ //
+ // Work out and validate the adapter number.
+ //
+
+ adapterNumber = (index - 1000) / 100;
+
+ if (adapterNumber < 0 ||
+ adapterNumber >= sizeof(Adapters) / sizeof(ADAPTER_INFO) ||
+ (index % 100) != 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Fill in the allowable slot numbers in the buffer.
+ //
+
+ if (UnicodeStringsEqual(param, SlotNumberString))
+ {
+ count = 0;
+
+ while (ParamRange[adapterNumber].SlotNumber[count] != END_OF_LIST)
+ {
+ count++;
+ }
+
+ if (*bufferSize < count)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ buffer[i] = ParamRange[adapterNumber].SlotNumber[i];
+ }
+
+ *bufferSize = count;
+
+ return NO_ERROR;
+ }
+
+ //
+ // Or the valid DMA channels.
+ //
+
+ else if (UnicodeStringsEqual(param, DmaChanString))
+ {
+ count = 0;
+
+ while (ParamRange[adapterNumber].DmaRange[count] != END_OF_LIST)
+ {
+ count++;
+ }
+
+ if (*bufferSize < count)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ buffer[i] = ParamRange[adapterNumber].DmaRange[i];
+ }
+
+ *bufferSize = count;
+
+ return NO_ERROR;
+ }
+
+ //
+ // Or fill in the allowable values for the multiprocessor flag.
+ //
+
+ else if (UnicodeStringsEqual(param, MultiprocessorString))
+ {
+ if (*bufferSize < 2)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ *bufferSize = 2;
+
+ buffer[0] = 0;
+ buffer[1] = 1;
+
+ return NO_ERROR;
+ }
+
+ //
+ // If we reach this point we have been passed a parameter we
+ // don't know about.
+ //
+
+ return ERROR_INVALID_DATA;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeMCQueryParameterNameHandler
+*
+* Parameters - param -> Paramter being queried.
+* buffer -> Buffer for the returned name.
+* bufferSize -> Size of buffer in WCHARs.
+*
+* Purpose - Return the name of a parameter.
+*
+* Returns - ERROR_INVALID_PARAMETER to cause the caller to use
+* the Microsoft provided default names.
+*
+****************************************************************************/
+
+LONG
+MadgeMCQueryParameterNameHandler(
+ WCHAR * param,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/********* End of MDGMC.C **************************************************/
+
diff --git a/private/ntos/ndis/madge/detect/mdgncdet.c b/private/ntos/ndis/madge/detect/mdgncdet.c
new file mode 100644
index 000000000..9d1a7ef75
--- /dev/null
+++ b/private/ntos/ndis/madge/detect/mdgncdet.c
@@ -0,0 +1,1101 @@
+/****************************************************************************
+*
+* MDGNCDET.C
+*
+* Adapter Detection DLL
+*
+* Copyright (c) Madge Networks Ltd 1994
+*
+* COMPANY CONFIDENTIAL - RELEASED TO MICROSOFT CORP. ONLY FOR DEVELOPMENT
+* OF WINDOWS95 NETCARD DETECTION - THIS SOURCE IS NOT TO BE RELEASED OUTSIDE
+* OF MICROSOFT WITHOUT EXPLICIT WRITTEN PERMISSION FROM AN AUTHORISED
+* OFFICER OF MADGE NETWORKS LTD.
+*
+* Created: PBA 18/08/1994
+* Derived from the DTEXAMPL.C DDK sample. As far as possible
+* the structure of the Microsoft example NetDetect DLL has
+* been preserved so that our individual adapter detection
+* modules could be plugged into the Microsoft DLL.
+*
+* This module provides a wrapper for the modules that detect individual
+* adapter types. It fields calls out to the individual detection modules
+* so that the caller is unaware that it is dealing with multiple modules.
+*
+****************************************************************************/
+
+#include <ntddk.h>
+#include <ntddnetd.h>
+
+#include <windef.h>
+#include <winerror.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mdgncdet.h"
+#include "mdgncdet.upd"
+
+//
+// Prototype "borrowed" from WINUSER.H
+//
+
+extern int WINAPIV wsprintfW(LPWSTR, LPCWSTR, ...);
+
+//
+// MVER string.
+//
+
+static
+char MVerString[] = MVER_STRING;
+
+
+/*---------------------------------------------------------------------------
+|
+| This is the structure for all the cards that the DLL can detect.
+| To add detection for a new adapter(s), simply add the proper routines to
+| this structure. The rest is automatic.
+|
+---------------------------------------------------------------------------*/
+
+static
+DETECT_ADAPTER DetectAdapters[] =
+{
+ {
+ MadgeEisaIdentifyHandler,
+ MadgeEisaFirstNextHandler,
+ MadgeEisaOpenHandleHandler,
+ MadgeEisaCreateHandleHandler,
+ MadgeEisaCloseHandleHandler,
+ MadgeEisaQueryCfgHandler,
+ MadgeEisaVerifyCfgHandler,
+ MadgeEisaQueryMaskHandler,
+ MadgeEisaParamRangeHandler,
+ MadgeEisaQueryParameterNameHandler,
+ 0
+ },
+
+ {
+ MadgeATIdentifyHandler,
+ MadgeATFirstNextHandler,
+ MadgeATOpenHandleHandler,
+ MadgeATCreateHandleHandler,
+ MadgeATCloseHandleHandler,
+ MadgeATQueryCfgHandler,
+ MadgeATVerifyCfgHandler,
+ MadgeATQueryMaskHandler,
+ MadgeATParamRangeHandler,
+ MadgeATQueryParameterNameHandler,
+ 0
+ },
+
+ {
+ MadgeSm16IdentifyHandler,
+ MadgeSm16FirstNextHandler,
+ MadgeSm16OpenHandleHandler,
+ MadgeSm16CreateHandleHandler,
+ MadgeSm16CloseHandleHandler,
+ MadgeSm16QueryCfgHandler,
+ MadgeSm16VerifyCfgHandler,
+ MadgeSm16QueryMaskHandler,
+ MadgeSm16ParamRangeHandler,
+ MadgeSm16QueryParameterNameHandler,
+ 0
+ },
+
+ {
+ MadgePnPIdentifyHandler,
+ MadgePnPFirstNextHandler,
+ MadgePnPOpenHandleHandler,
+ MadgePnPCreateHandleHandler,
+ MadgePnPCloseHandleHandler,
+ MadgePnPQueryCfgHandler,
+ MadgePnPVerifyCfgHandler,
+ MadgePnPQueryMaskHandler,
+ MadgePnPParamRangeHandler,
+ MadgePnPQueryParameterNameHandler,
+ 0
+ },
+
+ {
+ MadgeMCIdentifyHandler,
+ MadgeMCFirstNextHandler,
+ MadgeMCOpenHandleHandler,
+ MadgeMCCreateHandleHandler,
+ MadgeMCCloseHandleHandler,
+ MadgeMCQueryCfgHandler,
+ MadgeMCVerifyCfgHandler,
+ MadgeMCQueryMaskHandler,
+ MadgeMCParamRangeHandler,
+ MadgeMCQueryParameterNameHandler,
+ 0
+ },
+
+ {
+ MadgePciIdentifyHandler,
+ MadgePciFirstNextHandler,
+ MadgePciOpenHandleHandler,
+ MadgePciCreateHandleHandler,
+ MadgePciCloseHandleHandler,
+ MadgePciQueryCfgHandler,
+ MadgePciVerifyCfgHandler,
+ MadgePciQueryMaskHandler,
+ MadgePciParamRangeHandler,
+ MadgePciQueryParameterNameHandler,
+ 0
+ },
+
+ {
+ MadgePcmciaIdentifyHandler,
+ MadgePcmciaFirstNextHandler,
+ MadgePcmciaOpenHandleHandler,
+ MadgePcmciaCreateHandleHandler,
+ MadgePcmciaCloseHandleHandler,
+ MadgePcmciaQueryCfgHandler,
+ MadgePcmciaVerifyCfgHandler,
+ MadgePcmciaQueryMaskHandler,
+ MadgePcmciaParamRangeHandler,
+ MadgePcmciaQueryParameterNameHandler,
+ 0
+ }
+};
+
+
+/*---------------------------------------------------------------------------
+|
+| Constant strings for parameters.
+|
+---------------------------------------------------------------------------*/
+
+WCHAR IrqString[] = L"INTERRUPTNUMBER";
+WCHAR IoAddrString[] = L"IOLOCATION";
+WCHAR DmaChanString[] = L"DMACHANNEL";
+WCHAR AdapTypeString[] = L"ADAPTERTYPE";
+WCHAR SlotNumberString[] = L"SLOTNUMBER";
+WCHAR MultiprocessorString[] = L"MULTIPROCESSOR";
+
+
+/****************************************************************************
+*
+* Function - NcDetectInitialInit
+*
+* Parameters - dllHandle -> Our DLL handle.
+* reason -> The reason this function has been called.
+* context -> Context information.
+*
+* Purpose - Standard DLL initialisation/closedown function. If called
+* with reason == 0 then we closedown. If called with
+* reason != 0 then we initialise.
+*
+* Returns - TRUE on success or FALSE on failure.
+*
+****************************************************************************/
+
+BOOLEAN PASCAL
+NcDetectInitialInit(
+ VOID * dllHandle,
+ ULONG reason,
+ CONTEXT * context
+ )
+{
+ LONG supportedDrivers;
+ LONG currentDriver;
+ LONG supportedAdapters;
+ LONG totalAdapters;
+
+ MadgePrint2("MADGE: NcDetectInitialInit (reason = %ld)\n", reason);
+
+ //
+ // If reason == 0 then this is a closedown call so free any resources
+ // we have allocated.
+ //
+
+ if (reason == 0)
+ {
+ return TRUE;
+ }
+
+ //
+ // If we get here it we should initialise.
+ //
+
+ totalAdapters = 0;
+ supportedDrivers = sizeof(DetectAdapters) / sizeof(DETECT_ADAPTER);
+
+ //
+ // Count the total number of adapters supported by this DLL by
+ // iterating through each module, finding the number of adapters
+ // each module supports.
+ //
+
+ for (currentDriver = 0;
+ currentDriver < supportedDrivers;
+ currentDriver++)
+ {
+ for (supportedAdapters = 0; ; supportedAdapters++)
+ {
+ if ((*(DetectAdapters[currentDriver].NcDetectIdentifyHandler))(
+ ((supportedAdapters + 10) * 100),
+ NULL,
+ 0
+ ) == ERROR_NO_MORE_ITEMS)
+ {
+ break;
+ }
+ }
+
+ totalAdapters += supportedAdapters;
+
+ DetectAdapters[currentDriver].SupportedAdapters = supportedAdapters;
+ }
+
+ //
+ // We don't support more than 65535 adapters in this DLL because of
+ // the way we build the Tokens and NetcardIds.
+ //
+
+ if (totalAdapters > 65535L)
+ {
+ return FALSE;
+ }
+
+ //
+ // We have successfully completed initialisation.
+ //
+
+ return TRUE;
+}
+
+
+/****************************************************************************
+*
+* Function - NcDetectIdentify
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* buffer -> Buffer for the results.
+* bufferSize -> Size of the buffer in WCHARs.
+*
+* Purpose - Return information about a type of adapter that this module
+* supports.
+*
+* Returns - A WINERROR.H error code. ERROR_NO_MORE_ITEMS
+* is returned if index refers to an adapter type not
+* supported.
+*
+****************************************************************************/
+
+LONG
+NcDetectIdentify(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ LONG supportedDrivers;
+ LONG currentDriver;
+ LONG adapterNumber;
+ LONG codeNumber;
+
+ //
+ // Do some initialisation.
+ //
+
+ adapterNumber = (index / 100) - 10;
+ codeNumber = index % 100;
+
+ //
+ // First we check the index for any of the 'special' values.
+ //
+ // index == 0 means return manufacturers identfication.
+ //
+
+ if (index == 0)
+ {
+
+ if (bufferSize < 4)
+ {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ wsprintfW(buffer, L"0x0");
+
+ return NO_ERROR;
+ }
+
+ //
+ // index == 1 means return the date and version.
+ //
+
+ if (index == 1)
+ {
+ if (bufferSize < 12) {
+
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ wsprintfW(buffer, L"0x10920301");
+
+ return NO_ERROR;
+ }
+
+ //
+ // Make sure the adapter number is sensible.
+ //
+
+ if (adapterNumber < 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Now we find the number of drivers this DLL is supporting.
+ //
+
+ supportedDrivers = sizeof(DetectAdapters) / sizeof(DETECT_ADAPTER);
+
+ //
+ // Iterate through index until we find the the adapter indicated above.
+ //
+
+ for (currentDriver = 0;
+ currentDriver < supportedDrivers;
+ currentDriver++)
+ {
+ //
+ // See if the one we want is in here
+ //
+
+ if (adapterNumber < DetectAdapters[currentDriver].SupportedAdapters)
+ {
+ return (*(DetectAdapters[currentDriver].NcDetectIdentifyHandler))(
+ ((adapterNumber + 10) * 100) + codeNumber,
+ buffer,
+ bufferSize
+ );
+ }
+
+ //
+ // No, move on to next driver.
+ //
+
+ adapterNumber -= DetectAdapters[currentDriver].SupportedAdapters;
+ }
+
+ //
+ // If we get here we didn't find a module that supports the adapter
+ // type.
+ //
+
+ return ERROR_NO_MORE_ITEMS;
+}
+
+
+/****************************************************************************
+*
+* Function - NcDetectFirstNext
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* interface -> The NT interface type (ISA, EISA etc).
+* busNumber -> The bus number to search.
+* first -> TRUE if the search of this bus should start
+* from scratch.
+* token -> Pointer to holder for a token that identifies
+* the adapter found.
+* confidence -> Pointer to a holder for the confidence by
+* which the adapter has been found.
+*
+* Purpose - Attempts to find an adapter on the specified bus. If first
+* is TRUE then the search starts from scratch. Otherwise
+* the search starts from where it left of the last time we
+* were called.
+*
+* Returns - A WINERROR.H error code. A return code of NO_ERROR
+* and a *confidence of 0 means we didn't find an adapter.
+*
+****************************************************************************/
+
+
+LONG
+NcDetectFirstNext(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ BOOL first,
+ VOID * * token,
+ LONG * confidence
+ )
+{
+ LONG supportedDrivers;
+ LONG currentDriver;
+ LONG adapterNumber;
+ LONG retCode;
+
+ //
+ // Do some initialisation.
+ //
+
+ adapterNumber = (index / 100) - 10;
+
+ //
+ // Check that the adapter type and operation are sensible.
+ //
+
+ if (adapterNumber < 0 || (index % 100) != 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Now we find the number of drivers this DLL is supporting.
+ //
+
+ supportedDrivers = sizeof(DetectAdapters) / sizeof(DETECT_ADAPTER);
+
+ //
+ // Iterate through index until we find the the adapter indicated above.
+ //
+
+ for (currentDriver = 0;
+ currentDriver < supportedDrivers;
+ currentDriver++)
+ {
+ //
+ // See if the one we want is in here.
+ //
+
+ if (adapterNumber < DetectAdapters[currentDriver].SupportedAdapters)
+ {
+ //
+ // Yes, so call to get the right one.
+ //
+
+ retCode =
+ (*(DetectAdapters[currentDriver].NcDetectFirstNextHandler))(
+ (adapterNumber + 10) * 100,
+ interface,
+ busNumber,
+ first,
+ token,
+ confidence
+ );
+
+ //
+ // If it worked then include the driver number in the token.
+ //
+
+ if (retCode == NO_ERROR)
+ {
+ *token = (VOID *)
+ (((ULONG) (*token)) | (currentDriver << 16));
+ }
+ else
+ {
+ *token = NULL;
+ }
+
+ return retCode;
+ }
+
+ //
+ // No, move on to next driver.
+ //
+
+ adapterNumber -= DetectAdapters[currentDriver].SupportedAdapters;
+ }
+
+ //
+ // If we get here we didn't find a module that supports the adapter
+ // type.
+ //
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/****************************************************************************
+*
+* Function - NcDetectOpenHandle
+*
+* Parameters - token -> Pointer to holder for a token that identifies
+* an adapter found by FirstNextHandler.
+* handle -> Pointer to a holder a handle the caller
+* should use to query the adapter refered to
+* by *token.
+*
+* Purpose - Generates a handle for an adapter just found by a call
+* to FirstNext.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+NcDetectOpenHandle(
+ VOID * token,
+ VOID * * handle
+ )
+{
+ LONG driverToken;
+ LONG driverNumber;
+ LONG retCode;
+ ADAPTER_HANDLE * adapter;
+
+ //
+ // Get the driver number and the driver's token out of the
+ // token.
+ //
+
+ driverToken = ((ULONG) token & 0xFFFF);
+ driverNumber = ((ULONG) token >> 16);
+
+ //
+ // Call the appropriate driver.
+ //
+
+ retCode = (*(DetectAdapters[driverNumber].NcDetectOpenHandleHandler))(
+ (VOID *) driverToken,
+ handle
+ );
+
+ //
+ // If the driver succeeded then create a handle for the adapter.
+ //
+
+ if (retCode == NO_ERROR)
+ {
+ adapter = DetectAllocateHeap(sizeof(ADAPTER_HANDLE));
+
+ if (adapter == NULL)
+ {
+ (*(DetectAdapters[driverNumber].NcDetectCloseHandleHandler))(
+ *handle
+ );
+
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ adapter->Handle = *handle;
+ adapter->DriverNumber = driverNumber;
+
+ *handle = (VOID *) adapter;
+ }
+ else
+ {
+ *handle = NULL;
+ }
+
+ return retCode;
+
+}
+
+
+/****************************************************************************
+*
+* Function - NcDetectCreateHandle
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* interface -> NT interface type (Eisa, Isa etc).
+* busNumber -> Number of the bus containing the adapter.
+* handle -> Pointer to a holder a handle the caller
+* should use to query the adapter.
+*
+* Purpose - Generates a handle for an adapter that has not been detected
+* but the caller claims exists.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+NcDetectCreateHandle(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ VOID * * handle
+ )
+{
+ LONG supportedDrivers;
+ LONG currentDriver;
+ LONG retCode;
+ LONG adapterNumber;
+ ADAPTER_HANDLE * adapter;
+
+ //
+ // Do some initialisation.
+ //
+
+ adapterNumber = (index / 100) - 10;
+
+ //
+ // Check that the adapter number and the operation requested
+ // are sensible.
+ //
+
+ if (adapterNumber < 0 || (index % 100) != 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Now we find the number of drivers this DLL is supporting.
+ //
+
+ supportedDrivers = sizeof(DetectAdapters) / sizeof(DETECT_ADAPTER);
+
+ //
+ // Iterate through index until we find the the adapter indicated above.
+ //
+
+ for (currentDriver = 0;
+ currentDriver < supportedDrivers;
+ currentDriver++)
+ {
+ //
+ // See if the one we want is in here
+ //
+
+ if (adapterNumber < DetectAdapters[currentDriver].SupportedAdapters)
+ {
+ //
+ // Yes, so call to get the right one.
+ //
+
+ retCode =
+ (*(DetectAdapters[currentDriver].NcDetectCreateHandleHandler))(
+ (adapterNumber + 10) * 100,
+ interface,
+ busNumber,
+ handle
+ );
+
+ //
+ // If the driver succeeded then create a handle for the adapter.
+ //
+
+ if (retCode == NO_ERROR)
+ {
+ adapter = DetectAllocateHeap(sizeof(ADAPTER_HANDLE));
+
+ if (adapter == NULL)
+ {
+ (*(DetectAdapters[currentDriver].NcDetectCloseHandleHandler))(
+ *handle
+ );
+
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ adapter->Handle = *handle;
+ adapter->DriverNumber = currentDriver;
+
+ *handle = (VOID *) adapter;
+ }
+ else
+ {
+ *handle = NULL;
+ }
+
+ return retCode;
+ }
+
+ //
+ // No, move on to next driver.
+ //
+
+ adapterNumber -= DetectAdapters[currentDriver].SupportedAdapters;
+ }
+
+ //
+ // If we get here we didn't find a module that supports the adapter
+ // type.
+ //
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+
+/****************************************************************************
+*
+* Function - NcDetectCloseHandle
+*
+* Parameters - handle -> Handle to be closed.
+*
+* Purpose - Closes a previously opened or created handle.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+NcDetectCloseHandle(
+ VOID * handle
+ )
+{
+ ADAPTER_HANDLE * adapter;
+
+ //
+ // Do some initialisation.
+ //
+
+ adapter = (ADAPTER_HANDLE *) handle;
+
+ //
+ // Call the appropriate driver.
+ //
+
+ (*(DetectAdapters[adapter->DriverNumber].NcDetectCloseHandleHandler))(
+ adapter->Handle
+ );
+
+ DetectFreeHeap(adapter);
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - NcDetectQueryCfg
+*
+* Parameters - handle -> Handle to for the adapter to be queried.
+* buffer -> Buffer for the returned parameters.
+* bufferSize -> Size of the buffer in WCHARs.
+*
+* Purpose - Find out what the parameters are for the adapter identified
+* by the handle. This function does not assume that the
+* adapter described by the handle is valid. This is because
+* the handle could have been created rather than opened.
+* The function validates the handle and if the handle does
+* not identify a physical adapter then we attempt to
+* find an adapter that matches the handle.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+NcDetectQueryCfg(
+ VOID * handle,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ ADAPTER_HANDLE * adapter;
+
+ //
+ // Do some initialisation.
+ //
+
+ adapter = (ADAPTER_HANDLE *) handle;
+
+ //
+ // Call the appropriate driver.
+ //
+
+ return (*(DetectAdapters[adapter->DriverNumber].NcDetectQueryCfgHandler))(
+ adapter->Handle,
+ buffer,
+ bufferSize
+ );
+}
+
+
+/****************************************************************************
+*
+* Function - NcDetectVerifyCfg
+*
+* Parameters - handle -> Handle to for the adapter to be verified.
+* buffer -> Buffer containing the returned parameters.
+*
+* Purpose - Verify that the parameters in buffer are correct for
+* the adapter identified by handle.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+NcDetectVerifyCfg(
+ VOID * handle,
+ WCHAR * buffer
+ )
+{
+ ADAPTER_HANDLE * adapter;
+
+ //
+ // Do some initialisation.
+ //
+
+ adapter = (ADAPTER_HANDLE *) handle;
+
+ //
+ // Call the appropriate driver.
+ //
+
+ return (*(DetectAdapters[adapter->DriverNumber].NcDetectVerifyCfgHandler))(
+ adapter->Handle,
+ buffer
+ );
+}
+
+
+/****************************************************************************
+*
+* Function - NcDetectQueryMask
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* buffer -> Buffer for the returned parameters.
+* bufferSize -> Size of buffer in WCHARs.
+*
+* Purpose - Return the list of parameters required for the adapter
+* type specified by index.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+NcDetectQueryMask(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ LONG supportedDrivers;
+ LONG currentDriver;
+ LONG adapterNumber;
+
+ //
+ // Do some initialisation.
+ //
+
+ adapterNumber = (index / 100) - 10;
+
+ //
+ // Check that the adapter number and operation requested are
+ // sensible.
+ //
+
+ if (adapterNumber < 0 || (index % 100) != 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Now we find the number of drivers this DLL is supporting.
+ //
+
+ supportedDrivers = sizeof(DetectAdapters) / sizeof(DETECT_ADAPTER);
+
+ //
+ // Iterate through index until we find the the adapter indicated above.
+ //
+
+
+ for (currentDriver = 0;
+ currentDriver < supportedDrivers;
+ currentDriver++)
+ {
+ //
+ // See if the one we want is in here.
+ //
+
+ if (adapterNumber < DetectAdapters[currentDriver].SupportedAdapters)
+ {
+ //
+ // Yes, so call to get the right one.
+ //
+
+ return (*(DetectAdapters[currentDriver].NcDetectQueryMaskHandler))(
+ ((adapterNumber + 10) * 100),
+ buffer,
+ bufferSize
+ );
+ }
+
+ //
+ // No, move on to next driver.
+ //
+
+ adapterNumber -= DetectAdapters[currentDriver].SupportedAdapters;
+ }
+
+ //
+ // If we get here we didn't find a module that supports the adapter
+ // type.
+ //
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/****************************************************************************
+*
+* Function - NcDetectParamRange
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* param -> Paramter being queried.
+* buffer -> Buffer for the returned parameters.
+* bufferSize -> Size of buffer in LONGs.
+*
+* Purpose - Return the list of acceptable values for the parameter
+* specified.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+NcDetectParamRange(
+ LONG index,
+ WCHAR * param,
+ LONG * buffer,
+ LONG * bufferSize
+ )
+{
+ LONG supportedDrivers;
+ LONG currentDriver;
+ LONG adapterNumber;
+
+ //
+ // Do some initialisation.
+ //
+
+ adapterNumber = (index / 100) - 10;
+
+ //
+ // Check that the adapter number and operation requested are
+ // sensible.
+ //
+
+ if (adapterNumber < 0 || (index % 100) != 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Now we find the number of drivers this DLL is supporting.
+ //
+
+ supportedDrivers = sizeof(DetectAdapters) / sizeof(DETECT_ADAPTER);
+
+ //
+ // Iterate through index until we find the the adapter indicated above.
+ //
+
+ for (currentDriver = 0;
+ currentDriver < supportedDrivers;
+ currentDriver++)
+ {
+ //
+ // See if the one we want is in here.
+ //
+
+ if (adapterNumber < DetectAdapters[currentDriver].SupportedAdapters)
+ {
+ //
+ // Yes, so call to get the right one.
+ //
+
+ return (*(DetectAdapters[currentDriver].NcDetectParamRangeHandler))(
+ ((adapterNumber + 10) * 100),
+ param,
+ buffer,
+ bufferSize
+ );
+ }
+
+ //
+ // No, move on to next driver.
+ //
+
+ adapterNumber -= DetectAdapters[currentDriver].SupportedAdapters;
+ }
+
+ //
+ // If we get here we didn't find a module that supports the adapter
+ // type.
+ //
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/****************************************************************************
+*
+* Function - NcDetectQueryParameterNameHandler
+*
+* Parameters - param -> Paramter being queried.
+* buffer -> Buffer for the returned name.
+* bufferSize -> Size of buffer in WCHARs.
+*
+* Purpose - Return the name of a parameter.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+NcDetectQueryParameterName(
+ WCHAR * param,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ LONG supportedDrivers;
+ LONG currentDriver;
+ LONG retCode;
+
+ //
+ // Now we find the number of drivers this DLL is supporting.
+ //
+
+ supportedDrivers = sizeof(DetectAdapters) / sizeof(DETECT_ADAPTER);
+
+ //
+ // Iterate through index until we find the the adapter indicated above.
+ //
+
+ for (currentDriver = 0;
+ currentDriver < supportedDrivers;
+ currentDriver++)
+ {
+ //
+ // No way to tell where this came from -- guess until success.
+ //
+
+ retCode =
+ (*(DetectAdapters[currentDriver].NcDetectQueryParameterNameHandler))(
+ param,
+ buffer,
+ bufferSize
+ );
+
+ if (retCode == NO_ERROR)
+ {
+ return NO_ERROR;
+ }
+ }
+
+ //
+ // If we make it here we did not find a driver that could
+ // provide a name for the parameter.
+ //
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/******** End of MDGNCDET.C ************************************************/
+
diff --git a/private/ntos/ndis/madge/detect/mdgncdet.def b/private/ntos/ndis/madge/detect/mdgncdet.def
new file mode 100644
index 000000000..aaed20a5d
--- /dev/null
+++ b/private/ntos/ndis/madge/detect/mdgncdet.def
@@ -0,0 +1,18 @@
+LIBRARY MDGNCDET
+
+DESCRIPTION 'Net Card Detection For Madge Cards'
+
+EXPORTS
+ NcDetectIdentify
+ NcDetectFirstNext
+ NcDetectOpenHandle
+ NcDetectCreateHandle
+ NcDetectCloseHandle
+ NcDetectQueryCfg
+ NcDetectVerifyCfg
+ NcDetectQueryMask
+ NcDetectParamRange
+ NcDetectQueryParameterName
+ NcDetectInitialInit
+
+
diff --git a/private/ntos/ndis/madge/detect/mdgncdet.h b/private/ntos/ndis/madge/detect/mdgncdet.h
new file mode 100644
index 000000000..0fc2046c5
--- /dev/null
+++ b/private/ntos/ndis/madge/detect/mdgncdet.h
@@ -0,0 +1,930 @@
+/****************************************************************************
+*
+* MDGNCDET.H
+*
+* Madge Adapter Dection DLL Global Header File
+*
+* Copyright (c) Madge Networks Ltd 1994
+*
+* COMPANY CONFIDENTIAL - RELEASED TO MICROSOFT CORP. ONLY FOR DEVELOPMENT
+* OF WINDOWS95 NETCARD DETECTION - THIS SOURCE IS NOT TO BE RELEASED OUTSIDE
+* OF MICROSOFT WITHOUT EXPLICIT WRITTEN PERMISSION FROM AN AUTHORISED
+* OFFICER OF MADGE NETWORKS LTD.
+*
+* Created: PBA 19/08/1994
+*
+****************************************************************************/
+
+#ifndef __MDGNCDET__
+#define __MDGNCDET__
+
+
+/*---------------------------------------------------------------------------
+|
+| Debugging macros.
+|
+|--------------------------------------------------------------------------*/
+
+#if DBG
+
+#define MadgePrint1(p1) DbgPrint("MdgNcDet: "##p1)
+#define MadgePrint2(p1, p2) DbgPrint("MdgNcDet: "##p1, (p2))
+#define MadgePrint3(p1, p2, p3) DbgPrint("MdgNcDet: "##p1, (p2), (p3))
+
+#else
+
+#define MadgePrint1(p1)
+#define MadgePrint2(p1, p2)
+#define MadgePrint3(p1, p2, p3)
+
+#endif
+
+
+/*---------------------------------------------------------------------------
+|
+| Adapter option tokens.
+|
+Ý Note: The MDGMPISA and MDGMPMCA tokens are used so that the OEMSETUP.INF
+Ý can be backwards compatible (and therefore upgradeable).
+|--------------------------------------------------------------------------*/
+
+#define MDGMPORT
+
+#ifdef MDGMPORT
+
+#define MDGAT L"MSMDGMPISA"
+#define MDGATP L"MSMDGMPATP"
+#define MDGISAC L"MSMDGMPISAC"
+#define MDGISACP L"MSMDGMPISACP"
+#define MDGPC L"MSMDGMPPC"
+#define MDGSM16 L"MSMDGMPSM16"
+#define MDGPNP L"MSMDGMPPNP"
+#define MDGEISA L"MSMDGMPEISA"
+#define MDGMC16 L"MSMDGMPMCA"
+#define MDGMC32 L"MSMDGMPMC32"
+#define MDGPCI L"MSMDGMPPCI"
+#define MDGPCIBM L"MSMDGMPPCIBM"
+#define MDGPCMCIA L"MSMDGMPPCMCIA"
+
+#endif
+
+
+/*---------------------------------------------------------------------------
+|
+Ý Name of the net detect DLL.
+--------------------------------------------------------------------------*/
+
+#define NET_DETECT_DLL_NAME "NETDTECT"
+
+
+/*---------------------------------------------------------------------------
+|
+| Resource constants.
+Ý Note: For historical reasons DMA channel 0 is used to mean PIO and
+Ý 0 < DMA channel < 16 means bus master DMA on ATULA based adapters.
+Ý (This scheme also works well for Windows95 where we have to
+Ý give a DMA resource range in the NETMADGE.INF file. The user
+Ý must choose one of the valid DMA channels at installtion time.
+Ý The simplest way to say to Windows95 that although we have
+Ý said the we use a DMA channel we don't actually wont want is
+Ý specify a DMA channel of 0 when the use wants PIO.) To make things
+Ý easier for OEMSETUP.INF we have extended this approach.
+Ý A DMA channel of GENERAL_DMA means the adapter uses DMA but
+Ý the channel is determined by the driver at start up (EISA and MC).
+Ý A DMA channel of GENERAL_MMIO means that the driver uses MMIO.
+|
+|--------------------------------------------------------------------------*/
+
+#define RESOURCE_UNKNOWN 0xffff // Unknown DMA, IRQ etc.
+
+#define GENERAL_DMA 500 // DMA without explicit channel
+ // (EISA/MC).
+#define GENERAL_MMIO 501 // General memory mapped IO.
+
+#define END_OF_LIST 1000 // End of a resource list.
+
+
+/*---------------------------------------------------------------------------
+|
+| Function typedefs for the functions exported by the individual adapter
+| detection modules.
+|
+|--------------------------------------------------------------------------*/
+
+typedef
+LONG
+(*NC_DETECT_IDENTIFY)(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+typedef
+LONG
+(*NC_DETECT_FIRST_NEXT)(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ BOOL first,
+ VOID * * token,
+ LONG * confidence
+ );
+
+typedef
+LONG
+(*NC_DETECT_OPEN_HANDLE)(
+ VOID * token,
+ VOID * * handle
+ );
+
+typedef
+LONG
+(*NC_DETECT_CREATE_HANDLE)(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ VOID * * handle
+ );
+
+typedef
+LONG
+(*NC_DETECT_CLOSE_HANDLE)(
+ VOID * handle
+ );
+
+typedef
+LONG
+(*NC_DETECT_QUERY_CFG)(
+ VOID * handle,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+typedef
+LONG
+(*NC_DETECT_VERIFY_CFG)(
+ VOID * handle,
+ WCHAR * buffer
+ );
+
+typedef
+LONG
+(*NC_DETECT_QUERY_MASK)(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+typedef
+LONG
+(*NC_DETECT_PARAM_RANGE)(
+ LONG index,
+ WCHAR * param,
+ LONG * buffer,
+ LONG * bufferSize
+ );
+
+typedef
+LONG
+(*NC_DETECT_QUERY_PARAMETER_NAME)(
+ WCHAR * param,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+
+/*---------------------------------------------------------------------------
+|
+| Structure used to hold all the information required by the main wrapper
+| about an individual adapter setection module.
+|
+|--------------------------------------------------------------------------*/
+
+typedef struct
+{
+ NC_DETECT_IDENTIFY NcDetectIdentifyHandler;
+ NC_DETECT_FIRST_NEXT NcDetectFirstNextHandler;
+ NC_DETECT_OPEN_HANDLE NcDetectOpenHandleHandler;
+ NC_DETECT_CREATE_HANDLE NcDetectCreateHandleHandler;
+ NC_DETECT_CLOSE_HANDLE NcDetectCloseHandleHandler;
+ NC_DETECT_QUERY_CFG NcDetectQueryCfgHandler;
+ NC_DETECT_VERIFY_CFG NcDetectVerifyCfgHandler;
+ NC_DETECT_QUERY_MASK NcDetectQueryMaskHandler;
+ NC_DETECT_PARAM_RANGE NcDetectParamRangeHandler;
+ NC_DETECT_QUERY_PARAMETER_NAME NcDetectQueryParameterNameHandler;
+
+ LONG SupportedAdapters;
+
+}
+DETECT_ADAPTER;
+
+
+/*--------------------------------------------------------------------------
+|
+| Structure for holding information about an adapter type.
+|
+---------------------------------------------------------------------------*/
+
+typedef struct
+{
+ LONG Index;
+ WCHAR * InfId;
+ WCHAR * CardDescription;
+ WCHAR * Manufacturer;
+ WCHAR * Parameters;
+ NC_DETECT_FIRST_NEXT FirstNext;
+ ULONG SearchOrder;
+
+}
+ADAPTER_INFO;
+
+
+/*---------------------------------------------------------------------------
+|
+| Structure for holding handles in the NcDetect routines.
+|
+---------------------------------------------------------------------------*/
+
+typedef struct
+{
+ VOID * Handle;
+ LONG DriverNumber;
+
+}
+ADAPTER_HANDLE;
+
+
+/*---------------------------------------------------------------------------
+|
+| Parameter identifier strings. Instantiated in MDGNCDET.C.
+|
+|--------------------------------------------------------------------------*/
+
+extern WCHAR IrqString[];
+extern WCHAR IoAddrString[];
+extern WCHAR DmaChanString[];
+extern WCHAR AdapTypeString[];
+extern WCHAR SlotNumberString[];
+extern WCHAR MultiprocessorString[];
+
+
+/*---------------------------------------------------------------------------
+|
+| Functions exported by MDGUTILS.C
+|
+|--------------------------------------------------------------------------*/
+
+ULONG
+UnicodeStrLen(
+ WCHAR * string
+ );
+
+WCHAR *
+FindParameterString(
+ WCHAR * string1,
+ WCHAR * string2
+ );
+
+VOID
+ScanForNumber(
+ WCHAR * place,
+ ULONG * value,
+ BOOLEAN * found
+ );
+
+VOID *
+DetectAllocateHeap(
+ LONG size
+ );
+
+VOID
+DetectFreeHeap(
+ VOID * ptr
+ );
+
+BOOLEAN
+GetMcaKey(
+ ULONG busNumber,
+ VOID * * infoHandle
+ );
+
+BOOLEAN
+GetMcaPosId(
+ VOID * infoHandle,
+ ULONG slotNumber,
+ ULONG * posId
+ );
+
+VOID
+DeleteMcaKey(
+ VOID * infoHandle
+ );
+
+BOOLEAN
+GetEisaKey(
+ ULONG busNumber,
+ VOID * * infoHandle
+ );
+
+BOOLEAN
+GetEisaCompressedId(
+ VOID * infoHandle,
+ ULONG slotNumber,
+ ULONG * compressedId
+ );
+
+VOID
+DeleteEisaKey(
+ VOID * infoHandle
+ );
+
+LONG
+AppendParameter(
+ WCHAR * * buffer,
+ LONG * bufferSize,
+ WCHAR * title,
+ ULONG value
+ );
+
+BOOLEAN
+UnicodeStringsEqual(
+ WCHAR *string1,
+ WCHAR *string2
+ );
+
+BOOLEAN
+MadgeCardAlreadyInstalled(
+ BOOLEAN useSlotNumber,
+ ULONG busNumber,
+ ULONG descriptor
+ );
+
+ULONG
+IsMultiprocessor(void);
+
+BOOLEAN
+IsValueInList(
+ ULONG value,
+ ULONG * list
+ );
+
+BOOLEAN
+CheckForPcmciaCard(
+ ULONG * ioLocation,
+ ULONG * irqNumber
+ );
+
+
+/*---------------------------------------------------------------------------
+|
+| Functions exported by MDGEISA.C.
+|
+|--------------------------------------------------------------------------*/
+
+LONG
+MadgeEisaIdentifyHandler(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+LONG
+MadgeEisaFirstNextHandler(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ BOOL first,
+ VOID * * token,
+ LONG * confidence
+ );
+
+LONG
+MadgeEisaOpenHandleHandler(
+ VOID * token,
+ VOID * * handle
+ );
+
+LONG
+MadgeEisaCreateHandleHandler(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ VOID * * handle
+ );
+
+LONG
+MadgeEisaCloseHandleHandler(
+ VOID * handle
+ );
+
+LONG
+MadgeEisaQueryCfgHandler(
+ VOID * handle,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+LONG
+MadgeEisaVerifyCfgHandler(
+ VOID * handle,
+ WCHAR * buffer
+ );
+
+LONG
+MadgeEisaQueryMaskHandler(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+LONG
+MadgeEisaParamRangeHandler(
+ LONG index,
+ WCHAR * param,
+ LONG * buffer,
+ LONG * bufferSize
+ );
+
+LONG
+MadgeEisaQueryParameterNameHandler(
+ WCHAR * param,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+
+/*---------------------------------------------------------------------------
+|
+| Functions exported by MDGPCI.C.
+|
+|--------------------------------------------------------------------------*/
+
+LONG
+MadgePciIdentifyHandler(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+LONG
+MadgePciFirstNextHandler(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ BOOL first,
+ VOID * * token,
+ LONG * confidence
+ );
+
+LONG
+MadgePciOpenHandleHandler(
+ VOID * token,
+ VOID * * handle
+ );
+
+LONG
+MadgePciCreateHandleHandler(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ VOID * * handle
+ );
+
+LONG
+MadgePciCloseHandleHandler(
+ VOID * handle
+ );
+
+LONG
+MadgePciQueryCfgHandler(
+ VOID * handle,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+LONG
+MadgePciVerifyCfgHandler(
+ VOID * handle,
+ WCHAR * buffer
+ );
+
+LONG
+MadgePciQueryMaskHandler(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+LONG
+MadgePciParamRangeHandler(
+ LONG index,
+ WCHAR * param,
+ LONG * buffer,
+ LONG * bufferSize
+ );
+
+LONG
+MadgePciQueryParameterNameHandler(
+ WCHAR * param,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+
+/*---------------------------------------------------------------------------
+|
+| Functions exported by MDGPCMC.C.
+|
+|--------------------------------------------------------------------------*/
+
+LONG
+MadgePcmciaIdentifyHandler(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+LONG
+MadgePcmciaFirstNextHandler(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ BOOL first,
+ VOID * * token,
+ LONG * confidence
+ );
+
+LONG
+MadgePcmciaOpenHandleHandler(
+ VOID * token,
+ VOID * * handle
+ );
+
+LONG
+MadgePcmciaCreateHandleHandler(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ VOID * * handle
+ );
+
+LONG
+MadgePcmciaCloseHandleHandler(
+ VOID * handle
+ );
+
+LONG
+MadgePcmciaQueryCfgHandler(
+ VOID * handle,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+LONG
+MadgePcmciaVerifyCfgHandler(
+ VOID * handle,
+ WCHAR * buffer
+ );
+
+LONG
+MadgePcmciaQueryMaskHandler(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+LONG
+MadgePcmciaParamRangeHandler(
+ LONG index,
+ WCHAR * param,
+ LONG * buffer,
+ LONG * bufferSize
+ );
+
+LONG
+MadgePcmciaQueryParameterNameHandler(
+ WCHAR * param,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+
+/*---------------------------------------------------------------------------
+|
+| Functions exported by MDGAT.C.
+|
+|--------------------------------------------------------------------------*/
+
+LONG
+MadgeATIdentifyHandler(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+LONG
+MadgeATFirstNextHandler(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ BOOL first,
+ VOID * * token,
+ LONG * confidence
+ );
+
+LONG
+MadgeATOpenHandleHandler(
+ VOID * token,
+ VOID * * handle
+ );
+
+LONG
+MadgeATCreateHandleHandler(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ VOID * * handle
+ );
+
+LONG
+MadgeATCloseHandleHandler(
+ VOID * handle
+ );
+
+LONG
+MadgeATQueryCfgHandler(
+ VOID * handle,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+LONG
+MadgeATVerifyCfgHandler(
+ VOID * handle,
+ WCHAR * buffer
+ );
+
+LONG
+MadgeATQueryMaskHandler(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+LONG
+MadgeATParamRangeHandler(
+ LONG index,
+ WCHAR * param,
+ LONG * buffer,
+ LONG * bufferSize
+ );
+
+LONG
+MadgeATQueryParameterNameHandler(
+ WCHAR * param,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+
+/*---------------------------------------------------------------------------
+|
+| Functions exported by MDGSM16.C.
+|
+|--------------------------------------------------------------------------*/
+
+LONG
+MadgeSm16IdentifyHandler(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+LONG
+MadgeSm16FirstNextHandler(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ BOOL first,
+ VOID * * token,
+ LONG * confidence
+ );
+
+LONG
+MadgeSm16OpenHandleHandler(
+ VOID * token,
+ VOID * * handle
+ );
+
+LONG
+MadgeSm16CreateHandleHandler(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ VOID * * handle
+ );
+
+LONG
+MadgeSm16CloseHandleHandler(
+ VOID * handle
+ );
+
+LONG
+MadgeSm16QueryCfgHandler(
+ VOID * handle,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+LONG
+MadgeSm16VerifyCfgHandler(
+ VOID * handle,
+ WCHAR * buffer
+ );
+
+LONG
+MadgeSm16QueryMaskHandler(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+LONG
+MadgeSm16ParamRangeHandler(
+ LONG index,
+ WCHAR * param,
+ LONG * buffer,
+ LONG * bufferSize
+ );
+
+LONG
+MadgeSm16QueryParameterNameHandler(
+ WCHAR * param,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+
+/*---------------------------------------------------------------------------
+|
+| Functions exported by MDGPNP.C.
+|
+|--------------------------------------------------------------------------*/
+
+LONG
+MadgePnPIdentifyHandler(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+LONG
+MadgePnPFirstNextHandler(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ BOOL first,
+ VOID * * token,
+ LONG * confidence
+ );
+
+LONG
+MadgePnPOpenHandleHandler(
+ VOID * token,
+ VOID * * handle
+ );
+
+LONG
+MadgePnPCreateHandleHandler(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ VOID * * handle
+ );
+
+LONG
+MadgePnPCloseHandleHandler(
+ VOID * handle
+ );
+
+LONG
+MadgePnPQueryCfgHandler(
+ VOID * handle,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+LONG
+MadgePnPVerifyCfgHandler(
+ VOID * handle,
+ WCHAR * buffer
+ );
+
+LONG
+MadgePnPQueryMaskHandler(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+LONG
+MadgePnPParamRangeHandler(
+ LONG index,
+ WCHAR * param,
+ LONG * buffer,
+ LONG * bufferSize
+ );
+
+LONG
+MadgePnPQueryParameterNameHandler(
+ WCHAR * param,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+
+/*---------------------------------------------------------------------------
+|
+| Functions exported by MDGMC.C.
+|
+|--------------------------------------------------------------------------*/
+
+LONG
+MadgeMCIdentifyHandler(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+LONG
+MadgeMCFirstNextHandler(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ BOOL first,
+ VOID * * token,
+ LONG * confidence
+ );
+
+LONG
+MadgeMCOpenHandleHandler(
+ VOID * token,
+ VOID * * handle
+ );
+
+LONG
+MadgeMCCreateHandleHandler(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ VOID * * handle
+ );
+
+LONG
+MadgeMCCloseHandleHandler(
+ VOID * handle
+ );
+
+LONG
+MadgeMCQueryCfgHandler(
+ VOID * handle,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+LONG
+MadgeMCVerifyCfgHandler(
+ VOID * handle,
+ WCHAR * buffer
+ );
+
+LONG
+MadgeMCQueryMaskHandler(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+LONG
+MadgeMCParamRangeHandler(
+ LONG index,
+ WCHAR * param,
+ LONG * buffer,
+ LONG * bufferSize
+ );
+
+LONG
+MadgeMCQueryParameterNameHandler(
+ WCHAR * param,
+ WCHAR * buffer,
+ LONG bufferSize
+ );
+
+
+#endif
+
+/******** End of MDGNCDET.H ************************************************/
+
diff --git a/private/ntos/ndis/madge/detect/mdgncdet.rc b/private/ntos/ndis/madge/detect/mdgncdet.rc
new file mode 100644
index 000000000..bda6f9427
--- /dev/null
+++ b/private/ntos/ndis/madge/detect/mdgncdet.rc
@@ -0,0 +1,27 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#include "mdgncdet.upd"
+
+#undef VER_COMPANYNAME_STR
+#undef VER_PRODUCTNAME_STR
+#undef VER_PRODUCTVERSION
+#undef VER_PRODUCTVERSION_STR
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+#define VER_COMPANYNAME_STR "Madge Networks Ltd"
+#define VER_PRODUCTNAME_STR "Madge Networks Smart Ringnode Netcard Detection"
+#define VER_FILEDESCRIPTION_STR "Madge NetDetect"
+#define VER_INTERNALNAME_STR "MdgNcDet.DLL"
+
+#define VER_LEGALCOPYRIGHT_YEARS "1994"
+#define VER_LEGALCOPYRIGHT_STR "Copyright (C) Madge Networks Ltd " VER_LEGALCOPYRIGHT_YEARS
+#define VER_FILEVERSION MADGE_DLL_VERSION
+#define VER_FILEVERSION_STR MADGE_DLL_VERSION_STR
+#define VER_PRODUCTVERSION MADGE_NT_VERSION
+#define VER_PRODUCTVERSION_STR MADGE_NT_VERSION_STR
+
+#include <common.ver>
+
diff --git a/private/ntos/ndis/madge/detect/mdgncdet.upd b/private/ntos/ndis/madge/detect/mdgncdet.upd
new file mode 100644
index 000000000..42d021ec4
--- /dev/null
+++ b/private/ntos/ndis/madge/detect/mdgncdet.upd
@@ -0,0 +1,200 @@
+/***************************************************************************
+*
+* MDGNCDET.UPD
+*
+* Update log and version information for Madge Smart Adapter NetDetect DLL.
+*
+* Copyright (c) Madge Networks Ltd 1994
+*
+* COMPANY CONFIDENTIAL
+*
+* Created: 21/09/1994
+*
+****************************************************************************/
+
+#include "..\driver\mdgmport.upd"
+
+/*---------------------------------------------------------------------------
+|
+| Version number.
+|
+---------------------------------------------------------------------------*/
+
+//
+// Define both a string and a comma separated list of numbers. These will be
+// used by the resource compiler when version stamping the driver file.
+//
+
+#define MADGE_DLL_VERSION 2,04,02,00
+#define MADGE_DLL_VERSION_STR "2.04.02"
+
+#define MADGE_DLL_NAME "MdgNcDet.DLL"
+
+#define _DRIVER_DESC MADGE_NT_NAME##" "##MADGE_NT_VERSION_STR
+#define _DLL_DESC MADGE_DLL_NAME##" "##MADGE_DLL_VERSION_STR
+
+
+/*---------------------------------------------------------------------------
+|
+| String for identification by MVER.
+|
+|--------------------------------------------------------------------------*/
+
+#ifdef MVER_STRING
+#undef MVER_STRING
+#endif
+
+#define MVER_STRING \
+ "VeRsIoN="##_DLL_DESC##" (for "##_DRIVER_DESC##")"
+
+
+/*---------------------------------------------------------------------------
+|
+| Update history.
+|
+|----------------------------------------------------------------------------
+
+ 2.04.01-.49 Reserved for 4.3(1) maintanance.
+
+ 2.04.02 07/12/1995 PBA
+
+ We now check the bus number as well as the slot number
+ or I/O location when checking if a card is already
+ installed. We need this for machines with multiple
+ PCI buses. CR=59/SOL=117
+
+ 2.04.01 30/10/1995 PBA
+
+ Maintenance build.
+
+ 2.04 21/07/1995 PBA
+
+ Re-released for 4.3(1) with PCI-TI DMA/DIO fix.
+
+ 2.03.01-.49 Reserved for 4.3(1) maintanance.
+
+ 2.03 30/06/1995 PBA
+
+ Released for LSS 4.3(1) hardware thread with support
+ for PCI-TI adapters and untested support for PCI-Abyss
+ adapters.
+
+ 2.02 Useds for non-intel thread derived from LSS 4.3(0).
+
+ 2.01.04 09/05/1995 PBA
+
+ Changed the PCI detection code so that it manually
+ gets a pointer to DetectReadPciSlotInformation
+ using GetProcAddress rather than just calling it
+ in line. This allows the same DLL to be used under
+ NT 3.5 and NT 3.51 (though PCI adapters will only
+ be found under NT 3.51+).
+
+ 2.01.03 02/05/1995 PBA
+
+ Added code to actually find a PCI adapter. Made
+ PIO the default mode for PCI adapters and removed
+ MMIO support for PowerPC.
+
+ 2.01.02 07/04/1995 PBA
+
+ Changed PCMCIA support so that it reads the hardware
+ resources from the registry.
+
+ 2.01.01 04/04/1995 PBA
+
+ Added proper PCMCIA report. MDGMPORT 2.01.01.
+
+ Power PC build. Only supports PIO on ISA and PCI
+ adapters.
+
+
+ 2.01.02 - .49 Reserved for 4.3(0 and/or PnP) maintenance.
+
+ 2.01 02/02/1995 PBA
+
+ Released for 4.3(0 and/or PnP). All previous 4.(x)
+ threads are now dead.
+
+ MDGMPORT 2.01.
+
+ 2.00.53 02/02/1995 PBA
+
+ Given to DaveF for Chicago testing and possible
+ shipment to Microsoft for M8 and/or NT 3.51.
+ MDGMPORT 2.00.61.
+
+ 2.00.52 31/01/1995 PBA
+
+ Added partial support for PCMCIA adapters. Cannot actually
+ detect an adapter put can provide parameter range
+ information.
+
+ 2.00.51 06/01/1995 PBA
+
+ Shipped source to FrancisT so that he could do a MIPs
+ build.
+
+ 2.00.50 15/12/1994 PBA
+
+ Live development continues.
+
+ Version numbers 1.50.01 to 1.99.99 are used for a FastMAC version.
+
+ 1.02.01 - .49 Reserved for release 4.3(1) maintenance.
+
+ Version number 1.02 is reserved for use in the 4.3(1) release. Live
+ development continues with 2.02.50.
+
+ 1.01.50 15/12/1994 PBA
+
+ Alpha release for product marketing to test. For use with
+ MDGMPORT 1.05.07.
+
+ 1.01.01 - .49 Reserved for release 4.3(0) maintenance.
+
+ Due the delay in getting the 4.3(0) release out it was decided to use
+ the new installtion software for 4.3(0). Version number 2.01 is
+ reserved for this. Live development continues with 2.01.50.
+
+ 1.00.05 25/11/1994 PBA
+
+ Arranged that all adapter modules return a DMA channel
+ value. In the case of EISA and MC this always returns
+ a constant to means DMA without a specific channel. PCI
+ always returns a constant to mean MMIO.
+
+ 1.00.04 24/11/1994 PBA
+
+ Added partial support for PCI adapters. Cannot actually
+ detect an adapter put can provide parameter range
+ information.
+
+ -- Special -----------------------------------------------------------------
+
+ 1.00.03a 11/01/1995 PBA
+
+ Added PCMCIA module that doesn't do anything other than
+ provide parameter lists. Shipped to Jameel Hyder at
+ Microsoft for NT 3.51 beta. MDGMPORT 1.06.80.
+
+ ----------------------------------------------------------------------------
+
+ 1.00.03 23/11/1994 PBA
+
+ Shipped to Microsoft for possible inclusion in the next
+ NT release. MDGMPORT v1.06.50.
+
+ 1.00.02 23/11/1994 PBA
+
+ Added support for ISA PnP adapters.
+
+ 1.00.01 12/09/1994 PBA
+
+ First version.
+
+---------------------------------------------------------------------------*/
+
+
+/******** End of MDGNCDET.UPD **********************************************/
+ \ No newline at end of file
diff --git a/private/ntos/ndis/madge/detect/mdgpci.c b/private/ntos/ndis/madge/detect/mdgpci.c
new file mode 100644
index 000000000..7c52f25df
--- /dev/null
+++ b/private/ntos/ndis/madge/detect/mdgpci.c
@@ -0,0 +1,1446 @@
+/****************************************************************************
+*
+* MDGPCI.C
+*
+* PCI Adapter Detection Module
+*
+* Copyright (c) Madge Networks Ltd 1994
+*
+* COMPANY CONFIDENTIAL - RELEASED TO MICROSOFT CORP. ONLY FOR DEVELOPMENT
+* OF WINDOWS95 NETCARD DETECTION - THIS SOURCE IS NOT TO BE RELEASED OUTSIDE
+* OF MICROSOFT WITHOUT EXPLICIT WRITTEN PERMISSION FROM AN AUTHORISED
+* OFFICER OF MADGE NETWORKS LTD.
+*
+* Created: PBA 24/11/1994
+*
+****************************************************************************/
+
+#include <ntddk.h>
+#include <ntddnetd.h>
+
+#include <windef.h>
+#include <winerror.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mdgncdet.h"
+
+//
+// Prototype "borrowed" from WINUSER.H
+//
+
+extern int WINAPIV wsprintfW(LPWSTR, LPCWSTR, ...);
+
+
+//
+// Prototypes "borrowed" from WINBASE.H
+//
+
+#if !defined(_KERNEL32_)
+#define WINBASEAPI DECLSPEC_IMPORT
+#else
+#define WINBASEAPI
+#endif
+
+WINBASEAPI
+FARPROC
+WINAPI
+GetProcAddress(
+ HINSTANCE hModule,
+ LPCSTR lpProcName
+ );
+
+WINBASEAPI
+HMODULE
+WINAPI
+GetModuleHandleA(
+ LPCSTR lpModuleName
+ );
+
+WINBASEAPI
+HMODULE
+WINAPI
+GetModuleHandleW(
+ LPCWSTR lpModuleName
+ );
+
+#ifdef UNICODE
+#define GetModuleHandle GetModuleHandleW
+#else
+#define GetModuleHandle GetModuleHandleA
+#endif // !UNICODE
+
+
+/*---------------------------------------------------------------------------
+|
+| PCI adapter types. These correspond to the indexes that the upper layers
+| use for identifying adapters, so change them with care.
+|
+|--------------------------------------------------------------------------*/
+
+#define SMART_NONE 0
+#define SMART_PCI 1000
+#define SMART_PCI_BM 1100
+
+
+/*---------------------------------------------------------------------------
+|
+| PCI Vendor ID.
+|
+|--------------------------------------------------------------------------*/
+
+#define MADGE_VENDOR_ID 0x10b6
+
+
+/*---------------------------------------------------------------------------
+|
+| PCI revision IDs.
+|
+|--------------------------------------------------------------------------*/
+
+#define MADGE_PCI_RAP1B_REVISION 0x0001
+#define MADGE_PCI_PCI2_REVISION 0x0002
+#define MADGE_PCI_PCIT_REVISION 0x0004
+
+
+/*---------------------------------------------------------------------------
+|
+| PCI Configuration Space.
+|
+|--------------------------------------------------------------------------*/
+
+#define PCI_CONFIG_SIZE 64
+#define PCI_VENDOR_ID(buff) (((UINT *) (buff))[0] & 0x0000ffffL)
+#define PCI_REVISION(buff) ((((UINT *) (buff))[0] & 0xffff0000L) >> 16)
+
+
+/*---------------------------------------------------------------------------
+|
+| Maximum PCI slot number. (Slot numbers range from 0 to MAX_PCI_SLOT.)
+|
+|---------------------------------------------------------------------------*/
+
+#define MAX_PCI_SLOT 31
+
+
+/*---------------------------------------------------------------------------
+|
+| List of adapter types supported by this module.
+|
+|---------------------------------------------------------------------------*/
+
+static
+ADAPTER_INFO Adapters[] =
+{
+ {
+ SMART_PCI,
+ MDGPCI,
+ L"Madge 16/4 PCI Ringnode",
+ L"Madge Networks",
+ L"SLOTNUMBER\0"
+ L"000\0"
+ L"00100\0"
+ L"DMACHANNEL\0"
+ L"000\0"
+ L"00100\0"
+ L"MULTIPROCESSOR\0"
+ L"000\0"
+ L"00100\0",
+ NULL,
+ 900
+ },
+
+ {
+ SMART_PCI_BM,
+ MDGPCIBM,
+ L"Madge 16/4 PCI Ringnode (BM)",
+ L"Madge Networks",
+ L"SLOTNUMBER\0"
+ L"000\0"
+ L"00100\0"
+ L"DMACHANNEL\0"
+ L"000\0"
+ L"00100\0"
+ L"MULTIPROCESSOR\0"
+ L"000\0"
+ L"00100\0",
+ NULL,
+ 900
+ }
+
+};
+
+
+/*---------------------------------------------------------------------------
+|
+| Madge specific parameter range information. The order entries in this
+| table MUST match that in the Adapters table above. The first value
+Ý in each list is the default.
+|
+---------------------------------------------------------------------------*/
+
+static
+struct
+{
+ ULONG SlotNumber[34];
+ ULONG DmaRange[3];
+}
+ParamRange[] =
+{
+ //
+ // Smart 16/4 PCI.
+ //
+
+ {
+ { RESOURCE_UNKNOWN,
+ 0, 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,
+ END_OF_LIST},
+
+#if defined(_PPC_) || defined(_MIPS_)
+
+ { 0, END_OF_LIST}
+
+#else
+
+ { 0, GENERAL_MMIO, END_OF_LIST}
+
+#endif
+ },
+
+ //
+ // Smart 16/4 PciT and Pci2 (i.e. Smart 16/4 PCI (BM)).
+ //
+
+ {
+ { RESOURCE_UNKNOWN,
+ 0, 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,
+ END_OF_LIST},
+
+#if defined(_PPC_) || defined(_MIPS_)
+
+ { GENERAL_DMA, 0, END_OF_LIST}
+
+#else
+
+ { GENERAL_DMA, 0, END_OF_LIST}
+
+#endif
+ }
+
+};
+
+
+/*---------------------------------------------------------------------------
+|
+| Structure for holding state of a search.
+|
+|--------------------------------------------------------------------------*/
+
+typedef struct
+{
+ ULONG SlotNumber;
+}
+PCI_SEARCH_STATE;
+
+
+/*---------------------------------------------------------------------------
+|
+| This is an array of search states. We need one state for each type
+| of adapter supported.
+|
+|--------------------------------------------------------------------------*/
+
+static
+PCI_SEARCH_STATE SearchStates[sizeof(Adapters) / sizeof(ADAPTER_INFO)] = {0};
+
+
+/*---------------------------------------------------------------------------
+|
+| Structure for holding a particular adapter's complete information.
+|
+|--------------------------------------------------------------------------*/
+
+typedef struct
+{
+ BOOLEAN Found;
+ ULONG CardType;
+ INTERFACE_TYPE InterfaceType;
+ ULONG BusNumber;
+ ULONG SlotNumber;
+ ULONG Dma;
+}
+PCI_ADAPTER;
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - CheckForCard
+|
+| Parameters - busNumber -> The number of the bus to check.
+| interface -> The interface type of the bus.
+| slotNumber -> The slot number to be checked.
+|
+| Purpose - Check to see if an Madge PCI card in the specified
+| slot.
+|
+| Returns - A card type.
+|
+---------------------------------------------------------------------------*/
+
+static ULONG
+CheckForCard(
+ ULONG busNumber,
+ INTERFACE_TYPE interface,
+ ULONG slotNumber
+ )
+{
+ HMODULE detectDll;
+ FARPROC readPciSlot;
+ UCHAR pciInfo[PCI_CONFIG_SIZE];
+
+ MadgePrint2("CheckForCard (slotNumber=%ld)\n", slotNumber);
+
+ //
+ // The DetectReadPciSlotInformation function was not exported under
+ // NT 3.5 but is available under NT 3.51. So that we can have code
+ // that works on both versions of NT we will obtain the address of
+ // the function explicitly rather than using load time linking.
+ //
+
+ detectDll = GetModuleHandle(NET_DETECT_DLL_NAME);
+
+ if (detectDll == NULL)
+ {
+ MadgePrint1("GetModuleHandle failed\n");
+ return SMART_NONE;
+ }
+
+ readPciSlot = GetProcAddress(detectDll, "DetectReadPciSlotInformation");
+
+ if (readPciSlot == NULL)
+ {
+ MadgePrint1("GetProcAddress failed\n");
+ return SMART_NONE;
+ }
+
+ //
+ // If we make it here we should have a pointer to the
+ // DetectReadPciSlotInformation function. All we have to
+ // do now is cast the function and call.
+ //
+
+ if (((NTSTATUS (*)(ULONG, ULONG, ULONG, ULONG, PVOID)) readPciSlot)(
+ busNumber,
+ slotNumber,
+ 0,
+ PCI_CONFIG_SIZE,
+ (void *) pciInfo
+ ) == NO_ERROR)
+ {
+ if (PCI_VENDOR_ID(pciInfo) == MADGE_VENDOR_ID)
+ {
+
+ switch (PCI_REVISION(pciInfo))
+ {
+ case MADGE_PCI_RAP1B_REVISION:
+
+ return SMART_PCI;
+
+ case MADGE_PCI_PCI2_REVISION:
+ case MADGE_PCI_PCIT_REVISION:
+
+ return SMART_PCI_BM;
+ }
+ }
+ }
+
+ return SMART_NONE;
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - FindPciCard
+|
+| Parameters - adapterNumber -> Adapter type index used to index the
+| global array SearchStates.
+| busNumber -> The number of the bus to search.
+| interface -> The interface type of the bus.
+| first -> TRUE if this is the first call for
+| a given adapter type.
+| type -> The type of adapter to find.
+| confidence -> Pointer a holder for the confidence in
+| which the adapter was found.
+|
+| Purpose - Search the specified bus for an adapter of the
+| specified type. If first is TRUE then the search
+| starts from the first possible IO location. If first is
+| FALSE then the search starts from one after the last
+| slot number checked the previous time FindPciCard was called.
+|
+| Returns - A WINERROR.H error code.
+|
+|--------------------------------------------------------------------------*/
+
+static ULONG
+FindPciCard(
+ ULONG adapterNumber,
+ ULONG busNumber,
+ INTERFACE_TYPE interface,
+ BOOLEAN first,
+ ULONG type,
+ ULONG * confidence
+ )
+{
+ //
+ // If this is the first call then we want to start from the
+ // first possible slot number.
+ //
+
+ if (first)
+ {
+ SearchStates[adapterNumber].SlotNumber = 0;
+ }
+
+ //
+ // Otherwise we want to start from 1 after were we left off
+ // last time.
+ //
+
+ else
+ {
+ SearchStates[adapterNumber].SlotNumber++;
+ }
+
+ //
+ // Step through the slots in the bus for which there aren't
+ // already Madge adapters installed looking for one with the
+ // required adapter type. If we don't find one we will return a
+ // confidence level of zero.
+ //
+
+ *confidence = 0;
+
+ while (SearchStates[adapterNumber].SlotNumber <= MAX_PCI_SLOT)
+ {
+ if (!MadgeCardAlreadyInstalled(
+ TRUE,
+ busNumber,
+ SearchStates[adapterNumber].SlotNumber
+ ))
+ {
+ if (CheckForCard(
+ busNumber,
+ interface,
+ SearchStates[adapterNumber].SlotNumber
+ ) == type)
+ {
+ *confidence = 100;
+ break;
+ }
+ }
+
+ SearchStates[adapterNumber].SlotNumber++;
+ }
+
+ return NO_ERROR;
+}
+
+
+
+/****************************************************************************
+*
+* Function - MadgePciIdentifyHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* buffer -> Buffer for the results.
+* bufferSize -> Size of the buffer in WCHARs.
+*
+* Purpose - Return information about a type of adapter that this module
+* supports.
+*
+* Returns - A WINERROR.H error code. ERROR_NO_MORE_ITEMS
+* is returned if index refers to an adapter type not
+* supported.
+*
+****************************************************************************/
+
+LONG
+MadgePciIdentifyHandler(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ LONG numberOfAdapters;
+ LONG action;
+ LONG length;
+ LONG i;
+
+ MadgePrint2("MadgePciIdentifyHandler (index = %ld)\n", index);
+
+ //
+ // Do some initialisation.
+ //
+
+ numberOfAdapters = sizeof(Adapters) / sizeof(ADAPTER_INFO);
+ action = index % 100;
+ index = index - action;
+
+ //
+ // Check that index does not exceed the number of adapters we
+ // support.
+ //
+
+ if ((index - 1000) / 100 >= numberOfAdapters)
+ {
+ return ERROR_NO_MORE_ITEMS;
+ }
+
+ //
+ // If index refers to an adapter type supported then carry out the
+ // requested action.
+ //
+
+ for (i = 0; i < numberOfAdapters; i++)
+ {
+ if (Adapters[i].Index == index)
+ {
+ switch (action)
+ {
+ //
+ // Return the adapter's abbreviation.
+ //
+
+ case 0:
+
+ length = UnicodeStrLen(Adapters[i].InfId) + 1;
+
+ if (bufferSize < length)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ memcpy(
+ (VOID *) buffer,
+ Adapters[i].InfId,
+ length * sizeof(WCHAR)
+ );
+
+ break;
+
+ //
+ // Return the adapter's description.
+ //
+
+ case 1:
+
+ length = UnicodeStrLen(Adapters[i].CardDescription) + 1;
+
+ if (bufferSize < length)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ memcpy(
+ (VOID *) buffer,
+ Adapters[i].CardDescription,
+ length * sizeof(WCHAR)
+ );
+
+ break;
+
+ //
+ // Return the adapter's manufacturer.
+ //
+
+ case 2:
+
+ length = UnicodeStrLen(Adapters[i].Manufacturer) + 1;
+
+ if (bufferSize < length)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ memcpy(
+ (VOID *) buffer,
+ Adapters[i].Manufacturer,
+ length * sizeof(WCHAR)
+ );
+
+ break;
+
+ //
+ // Return the search order.
+ //
+
+ case 3:
+
+ if (bufferSize < 5)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ wsprintfW(
+ (VOID *) buffer,
+ L"%d",
+ Adapters[i].SearchOrder
+ );
+
+ break;
+
+ //
+ // Anything else is invalid.
+ //
+
+ default:
+
+ return ERROR_INVALID_PARAMETER;
+
+ }
+
+ return NO_ERROR;
+ }
+ }
+
+ //
+ // We didn't find an adapter type that matched the index so
+ // return an error.
+ //
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgePciFirstNextHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* interface -> The NT interface type (ISA, EISA etc).
+* busNumber -> The bus number to search.
+* first -> TRUE if the search of this bus should start
+* from scratch.
+* token -> Pointer to holder for a token that identifies
+* the adapter found.
+* confidence -> Pointer to a holder for the confidence by
+* which the adapter has been found.
+*
+* Purpose - Attempts to find an adapter on the specified bus. If first
+* is TRUE then the search starts from scratch. Otherwise
+* the search starts from where it left of the last time we
+* were called.
+*
+* Returns - A WINERROR.H error code. A return code of NO_ERROR
+* and a *confidence of 0 means we didn't find an adapter.
+*
+****************************************************************************/
+
+LONG
+MadgePciFirstNextHandler(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ BOOL first,
+ VOID * * token,
+ LONG * confidence
+ )
+{
+ ULONG retCode;
+ LONG adapterNumber;
+
+ MadgePrint2("MadgePciFirstNextHandler (index = %ld)\n", index);
+
+ //
+ // Check the interface type.
+ //
+
+ if (interface != PCIBus)
+ {
+ *confidence = 0;
+ return NO_ERROR;
+ }
+
+ //
+ // Work out and validate the adapter type being searched for.
+ //
+
+ adapterNumber = (index - 1000) / 100;
+
+ if (adapterNumber < 0 ||
+ adapterNumber >= sizeof(Adapters) / sizeof(ADAPTER_INFO) ||
+ (index % 100) != 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Type to find an adapter.
+ //
+
+ retCode = FindPciCard(
+ (ULONG) adapterNumber,
+ busNumber,
+ interface,
+ (BOOLEAN) first,
+ (ULONG) index,
+ confidence
+ );
+
+ if (retCode == NO_ERROR)
+ {
+ //
+ // In this module I use the token as follows: Remember that
+ // the token can only be 2 bytes long (the low 2) because of
+ // the interface to the upper part of this DLL.
+ //
+ // The rest of the high byte is the the bus number.
+ // The low byte is the driver index number into Adapters.
+ //
+ // NOTE: This presumes that there are < 129 buses in the
+ // system. Is this reasonable?
+ //
+
+ *token = (VOID *) ((busNumber & 0x7F) << 8);
+ *token = (VOID *) (((ULONG) *token) | adapterNumber);
+ }
+
+ return retCode;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgePciOpenHandleHandler
+*
+* Parameters - token -> Pointer to holder for a token that identifies
+* an adapter found by FirstNextHandler.
+* handle -> Pointer to a holder a handle the caller
+* should use to query the adapter refered to
+* by *token.
+*
+* Purpose - Generates a handle for an adapter just found by a call
+* to FirstNextHandler.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgePciOpenHandleHandler(
+ VOID * token,
+ VOID * * handle
+ )
+{
+ PCI_ADAPTER * adapter;
+ ULONG adapterNumber;
+ ULONG busNumber;
+ INTERFACE_TYPE interface;
+
+ MadgePrint1("MadgePciOpenHandleHandler\n");
+
+ //
+ // Get info from the token.
+ //
+
+ interface = PCIBus;
+ busNumber = (ULONG) (((ULONG) token >> 8) & 0x7F);
+ adapterNumber = ((ULONG) token) & 0xFF;
+
+ //
+ // Allocate a structure for the details of the adapter.
+ //
+
+ adapter = (PCI_ADAPTER *) DetectAllocateHeap(sizeof(PCI_ADAPTER));
+
+ if (adapter == NULL)
+ {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // Copy the details.
+ //
+
+ adapter->Found = TRUE;
+ adapter->SlotNumber = SearchStates[adapterNumber].SlotNumber;
+ adapter->CardType = Adapters[adapterNumber].Index;
+ adapter->InterfaceType = interface;
+ adapter->BusNumber = busNumber;
+ adapter->Dma = ParamRange[adapterNumber].DmaRange[0];
+
+ *handle = (VOID *) adapter;
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgePciCreateHandleHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* interface -> NT interface type (Eisa, Isa etc).
+* busNumber -> Number of the bus containing the adapter.
+* handle -> Pointer to a holder a handle the caller
+* should use to query the adapter.
+*
+* Purpose - Generates a handle for an adapter that has not been detected
+* but the caller claims exists.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgePciCreateHandleHandler(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ VOID * * handle
+ )
+{
+ PCI_ADAPTER * adapter;
+ LONG numberOfAdapters;
+ LONG i;
+
+ MadgePrint2("MadgePciCreateHandleHandler (index = %ld)\n", index);
+
+ //
+ // Check that the interface type is correct for this module.
+ //
+
+ if (interface != PCIBus)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // If the index is valid then create a handle.
+ //
+
+ numberOfAdapters = sizeof(Adapters) / sizeof(ADAPTER_INFO);
+
+ for (i = 0; i < numberOfAdapters; i++)
+ {
+ if (Adapters[i].Index == index)
+ {
+ //
+ // Allocate a structure for the adapter details.
+ //
+
+ adapter = (PCI_ADAPTER *) DetectAllocateHeap(sizeof(PCI_ADAPTER));
+
+ if (adapter == NULL)
+ {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // Copy the details.
+ //
+
+ adapter->Found = FALSE;
+ adapter->SlotNumber = 1;
+ adapter->CardType = index;
+ adapter->InterfaceType = interface;
+ adapter->BusNumber = busNumber;
+ adapter->Dma = ParamRange[i].DmaRange[0];
+
+ *handle = (VOID *) adapter;
+
+ return NO_ERROR;
+ }
+ }
+
+ //
+ // We didn't find an adapter type that matched the one the caller
+ // claims exists so return an error.
+ //
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgePciCloseHandleHandler
+*
+* Parameters - handle -> Handle to be closed.
+*
+* Purpose - Closes a previously opened or created handle.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgePciCloseHandleHandler(
+ VOID * handle
+ )
+{
+ MadgePrint1("MadgePciCloseHandleHandler\n");
+
+ DetectFreeHeap(handle);
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgePciQueryCfgHandler
+*
+* Parameters - handle -> Handle to for the adapter to be queried.
+* buffer -> Buffer for the returned parameters.
+* bufferSize -> Size of the buffer in WCHARs.
+*
+* Purpose - Find out what the parameters are for the adapter identified
+* by the handle. This function does not assume that the
+* adapter described by the handle is valid. This is because
+* the handle could have been created rather than opened.
+* The function validates the handle and if the handle does
+* not identify a physical adapter then we attempt to
+* find an adapter that matches the handle.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgePciQueryCfgHandler(
+ VOID * handle,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ PCI_ADAPTER * adapter;
+ VOID * busHandle;
+ ULONG confidence;
+ BOOLEAN found;
+ LONG adapterNumber;
+ LONG retCode;
+
+ //
+ // Do some initialisation.
+ //
+
+ adapter = (PCI_ADAPTER *) handle;
+
+ //
+ // Check that the interface type specified by the handle is
+ // valid for this module.
+ //
+
+ if (adapter->InterfaceType != PCIBus)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // If the adapter was created rather than being opened we must search
+ // for an adapter.
+ //
+
+ if (!adapter->Found)
+ {
+ adapterNumber = (adapter->CardType - 1000) / 100;
+
+ retCode = FindPciCard(
+ adapterNumber,
+ adapter->BusNumber,
+ adapter->InterfaceType,
+ TRUE,
+ adapter->CardType,
+ &confidence
+ );
+
+ //
+ // If we are not 100% sure that we found an adapter with
+ // the right ID we give up.
+ //
+
+ if (retCode != NO_ERROR || confidence != 100)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ adapter->Found = TRUE;
+ adapter->SlotNumber = SearchStates[adapterNumber].SlotNumber;
+ }
+
+ //
+ // Build resulting buffer.
+ //
+ // Copy in the slot number title and value.
+ //
+
+ if (AppendParameter(
+ &buffer,
+ &bufferSize,
+ SlotNumberString,
+ adapter->SlotNumber
+ ) != NO_ERROR)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ //
+ // Copy in the DMA channel title and value.
+ //
+
+ if (AppendParameter(
+ &buffer,
+ &bufferSize,
+ DmaChanString,
+ adapter->Dma
+ ) != NO_ERROR)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ //
+ // Copy in the multiprocessor flag.
+ //
+
+ if (AppendParameter(
+ &buffer,
+ &bufferSize,
+ MultiprocessorString,
+ IsMultiprocessor()
+ ) != NO_ERROR)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ //
+ // Copy in final \0.
+ //
+
+ if (bufferSize < 1)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ *buffer = L'\0';
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgePciVerifyCfgHandler
+*
+* Parameters - handle -> Handle to for the adapter to be verified.
+* buffer -> Buffer containing the returned parameters.
+*
+* Purpose - Verify that the parameters in buffer are correct for
+* the adapter identified by handle.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgePciVerifyCfgHandler(
+ VOID * handle,
+ WCHAR * buffer
+ )
+{
+ PCI_ADAPTER * adapter;
+ WCHAR * place;
+ ULONG compressedId;
+ ULONG slotNumber;
+ ULONG dmaChannel;
+ ULONG multiprocessor;
+ VOID * busHandle;
+ BOOLEAN found;
+ LONG adapterNumber;
+
+ MadgePrint1("MadgePciVerifyCfgHandler\n");
+
+ //
+ // Do some initialisation.
+ //
+
+ adapter = (PCI_ADAPTER *) handle;
+ adapterNumber = (adapter->CardType - 1000) / 100;
+
+ //
+ // Check that the interface type is correct for this module.
+ //
+
+ if (adapter->InterfaceType != PCIBus)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // Parse the parameters.
+ //
+ // Get the slot number.
+ //
+
+ place = FindParameterString(buffer, SlotNumberString);
+
+ if (place == NULL)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ place += UnicodeStrLen(SlotNumberString) + 1;
+
+ //
+ // Now parse the slot number.
+ //
+
+ ScanForNumber(place, &slotNumber, &found);
+
+ if (!found)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // Get the DMA channel.
+ //
+
+ place = FindParameterString(buffer, DmaChanString);
+
+ if (place == NULL)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ place += UnicodeStrLen(DmaChanString) + 1;
+
+ ScanForNumber(place, &dmaChannel, &found);
+
+ if (!found)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // Get the multiprocessor flag.
+ //
+
+ place = FindParameterString(buffer, MultiprocessorString);
+
+ if (place == NULL)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ place += UnicodeStrLen(MultiprocessorString) + 1;
+
+ //
+ // Now parse the value.
+ //
+
+ ScanForNumber(place, &multiprocessor, &found);
+
+ //
+ // If the adapter was created rather than being opened we must check
+ // the PCI configuration to make sure the slot contains a
+ // Madge adapter.
+ //
+
+ if (!adapter->Found)
+ {
+ if (CheckForCard(
+ adapter->BusNumber,
+ adapter->InterfaceType,
+ slotNumber
+ ) != adapter->CardType)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ adapter->Found = TRUE;
+ adapter->SlotNumber = slotNumber;
+ }
+
+ //
+ // Verify the parameter.
+ //
+
+ if (slotNumber != adapter->SlotNumber ||
+ multiprocessor != IsMultiprocessor())
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ if (adapter->Dma == RESOURCE_UNKNOWN)
+ {
+ if (!IsValueInList(dmaChannel, ParamRange[adapterNumber].DmaRange))
+ {
+ return ERROR_INVALID_DATA;
+ }
+ }
+ else if (adapter->Dma != dmaChannel)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // If we make it to here everything checked out ok.
+ //
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgePciQueryMaskHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* buffer -> Buffer for the returned parameters.
+* bufferSize -> Size of buffer in WCHARs.
+*
+* Purpose - Return the list of parameters required for the adapter
+* type specified by index.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgePciQueryMaskHandler(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ WCHAR * params;
+ LONG length;
+ LONG numberOfAdapters;
+ LONG i;
+
+ MadgePrint1("MadgePciQueryMaskHandler\n");
+
+ //
+ // Find the adapter type.
+ //
+
+ numberOfAdapters = sizeof(Adapters) / sizeof(ADAPTER_INFO);
+
+ for (i = 0; i < numberOfAdapters; i++)
+ {
+ if (Adapters[i].Index == index)
+ {
+ params = Adapters[i].Parameters;
+
+ //
+ // Find the string length (Ends with 2 NULLs)
+ //
+
+ for (length = 0; ; length++)
+ {
+ if (params[length] == L'\0')
+ {
+ length++;
+
+ if (params[length] == L'\0')
+ {
+ break;
+ }
+ }
+ }
+
+ length++;
+
+ //
+ // Copy the parameters into buffer.
+ //
+
+ if (bufferSize < length)
+ {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ memcpy((VOID *) buffer, params, length * sizeof(WCHAR));
+
+ return NO_ERROR;
+ }
+ }
+
+ //
+ // If we make it here we did not find a valid adapter type so
+ // return and error.
+ //
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgePciParamRangeHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* param -> Paramter being queried.
+* buffer -> Buffer for the returned parameters.
+* bufferSize -> Size of buffer in LONGs.
+*
+* Purpose - Return the list of acceptable values for the parameter
+* specified.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgePciParamRangeHandler(
+ LONG index,
+ WCHAR * param,
+ LONG * buffer,
+ LONG * bufferSize
+ )
+{
+ LONG adapterNumber;
+ LONG count;
+ LONG i;
+
+ //
+ // Work out and validate the adapter number.
+ //
+
+ adapterNumber = (index - 1000) / 100;
+
+ if (adapterNumber < 0 ||
+ adapterNumber >= sizeof(Adapters) / sizeof(ADAPTER_INFO) ||
+ (index % 100) != 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Fill in the allowable slot numbers in the buffer.
+ //
+
+ if (UnicodeStringsEqual(param, SlotNumberString))
+ {
+ count = 0;
+
+ while (ParamRange[adapterNumber].SlotNumber[count] != END_OF_LIST)
+ {
+ count++;
+ }
+
+ if (*bufferSize < count)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ buffer[i] = ParamRange[adapterNumber].SlotNumber[i];
+ }
+
+ *bufferSize = count;
+
+ return NO_ERROR;
+ }
+
+ //
+ // Or the valid DMA channels.
+ //
+
+ else if (UnicodeStringsEqual(param, DmaChanString))
+ {
+ count = 0;
+
+ while (ParamRange[adapterNumber].DmaRange[count] != END_OF_LIST)
+ {
+ count++;
+ }
+
+ if (*bufferSize < count)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ buffer[i] = ParamRange[adapterNumber].DmaRange[i];
+ }
+
+ *bufferSize = count;
+
+ return NO_ERROR;
+ }
+
+ //
+ // Or fill in the allowable values for the multiprocessor flag.
+ //
+
+ else if (UnicodeStringsEqual(param, MultiprocessorString))
+ {
+ if (*bufferSize < 2)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ *bufferSize = 2;
+
+ buffer[0] = 0;
+ buffer[1] = 1;
+
+ return NO_ERROR;
+ }
+
+ //
+ // If we reach this point we have been passed a parameter we
+ // don't know about.
+ //
+
+ return ERROR_INVALID_DATA;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgePciQueryParameterNameHandler
+*
+* Parameters - param -> Paramter being queried.
+* buffer -> Buffer for the returned name.
+* bufferSize -> Size of buffer in WCHARs.
+*
+* Purpose - Return the name of a parameter.
+*
+* Returns - ERROR_INVALID_PARAMETER to cause the caller to use
+* the Microsoft provided default names.
+*
+****************************************************************************/
+
+LONG
+MadgePciQueryParameterNameHandler(
+ WCHAR * param,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/********* End of MDGPCI.C *************************************************/
+
diff --git a/private/ntos/ndis/madge/detect/mdgpcmc.c b/private/ntos/ndis/madge/detect/mdgpcmc.c
new file mode 100644
index 000000000..b07547c5b
--- /dev/null
+++ b/private/ntos/ndis/madge/detect/mdgpcmc.c
@@ -0,0 +1,1396 @@
+/****************************************************************************
+*
+* MDGPCMC.C
+*
+* PCMCIA Adapter Detection Module
+*
+* Copyright (c) Madge Networks Ltd 1995
+*
+* COMPANY CONFIDENTIAL - RELEASED TO MICROSOFT CORP. ONLY FOR DEVELOPMENT
+* OF WINDOWS95 NETCARD DETECTION - THIS SOURCE IS NOT TO BE RELEASED OUTSIDE
+* OF MICROSOFT WITHOUT EXPLICIT WRITTEN PERMISSION FROM AN AUTHORISED
+* OFFICER OF MADGE NETWORKS LTD.
+*
+* Created: PBA 11/01/1994
+*
+****************************************************************************/
+
+#include <ntddk.h>
+#include <ntddnetd.h>
+
+#include <windef.h>
+#include <winerror.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mdgncdet.h"
+
+//
+// Prototype "borrowed" from WINUSER.H
+//
+
+extern int WINAPIV wsprintfW(LPWSTR, LPCWSTR, ...);
+
+
+
+/*---------------------------------------------------------------------------
+|
+| PCMCIA adapter types. These correspond to the indexes that the upper layers
+| use for identifying adapters, so change them with care.
+|
+|--------------------------------------------------------------------------*/
+
+#define SMART_NONE 0
+#define SMART_PCMCIA 1000
+
+
+/*---------------------------------------------------------------------------
+|
+| A selection of IO locations that PCMCIA adapters can be at.
+|
+---------------------------------------------------------------------------*/
+
+static
+ULONG PcmciaIoLocations[18] =
+ {0x0300,
+ 0x1a20, 0x2a20, 0x3a20,
+ 0x0140,
+ 0x0920, 0x0940, 0x0960, 0x0980,
+ 0x0a20, 0x0a40, 0x0a60, 0x0a80, 0x0aa0,
+ 0x0b20, 0x0b40, 0x0b60, 0x0b80};
+
+
+/*---------------------------------------------------------------------------
+|
+| List of adapter types supported by this module.
+|
+|---------------------------------------------------------------------------*/
+
+static
+ADAPTER_INFO Adapters[] =
+{
+ {
+ SMART_PCMCIA,
+ MDGPCMCIA,
+ L"Madge 16/4 PCMCIA Ringnode",
+ L"Madge Networks",
+ L"IOLOCATION\0"
+ L"000\0"
+ L"00100\0"
+ L"DMACHANNEL\0"
+ L"000\0"
+ L"00100\0"
+ L"INTERRUPTNUMBER\0"
+ L"000\0"
+ L"000\0"
+ L"MULTIPROCESSOR\0"
+ L"000\0"
+ L"00100\0",
+ NULL,
+ 903
+ }
+};
+
+
+/*---------------------------------------------------------------------------
+|
+| Madge specific parameter range information. The order entries in this
+| table MUST match that in the Adapters table above. (99 is a null entry.)
+|
+---------------------------------------------------------------------------*/
+
+static
+struct
+{
+ ULONG IrqRange[16];
+ ULONG DmaRange[2];
+}
+ParamRange[] =
+{
+ //
+ // PCMCIA.
+ //
+
+ {
+ { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15,
+ END_OF_LIST},
+ { 0, END_OF_LIST}
+ }
+};
+
+
+/*---------------------------------------------------------------------------
+|
+| Structure for holding state of a search.
+|
+|--------------------------------------------------------------------------*/
+
+typedef struct
+{
+ ULONG IoLocationIndex;
+ ULONG Irq;
+}
+PCMCIA_SEARCH_STATE;
+
+
+/*---------------------------------------------------------------------------
+|
+| This is an array of search states. We need one state for each type
+| of adapter supported.
+|
+|--------------------------------------------------------------------------*/
+
+static
+PCMCIA_SEARCH_STATE SearchStates[sizeof(Adapters) / sizeof(ADAPTER_INFO)] = {0};
+
+
+/*---------------------------------------------------------------------------
+|
+| Structure for holding a particular adapter's complete information.
+|
+|--------------------------------------------------------------------------*/
+
+typedef struct
+{
+ BOOLEAN Found;
+ ULONG CardType;
+ ULONG BusNumber;
+ INTERFACE_TYPE InterfaceType;
+ ULONG IoLocation;
+ ULONG Dma;
+ ULONG Irq;
+}
+PCMCIA_ADAPTER;
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - CheckForCard
+|
+| Parameters - busNumber -> The number of the bus to check.
+| interface -> The interface type of the bus.
+| ioLocation -> IO location to check.
+Ý irqNumber -> Pointer to a holder for the returned
+Ý IRQ number.
+|
+| Purpose - Check to see if an Madge Pcmcia card is present in the
+Ý machine at the given IO location.
+|
+| Returns - A card type.
+|
+---------------------------------------------------------------------------*/
+
+static ULONG
+CheckForCard(
+ ULONG busNumber,
+ INTERFACE_TYPE interface,
+ ULONG ioLocation,
+ ULONG * irqNumber
+ )
+{
+ ULONG ioBase;
+
+ MadgePrint2("CheckForCard (ioLocation=%04lx)\n", ioLocation);
+
+ if (CheckForPcmciaCard(&ioBase, irqNumber))
+ {
+ if (ioBase == ioLocation)
+ {
+ MadgePrint1("Found PCMCIA card\n");
+
+ return SMART_PCMCIA;
+ }
+ }
+
+ MadgePrint1("Did not find PCMCIA card\n");
+
+ return SMART_NONE;
+}
+
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - FindPcmciaCard
+|
+| Parameters - adapterNumber -> Adapter type index used to index the
+| global array SearchStates.
+| busNumber -> The number of the bus to search.
+| interface -> The interface type of the bus.
+| first -> TRUE if this is the first call for
+| a given adapter type.
+| type -> The type of adapter to find.
+| confidence -> Pointer a holder for the confidence in
+| which the adapter was found.
+|
+| Purpose - Search the specified bus for an adapter of the
+| specified type. If first is TRUE then the search
+| starts from the first possible IO location. If first is
+| FALSE then the search starts from one after the last
+| IO location checked the previous time FindPcmciaCard was called.
+|
+| Returns - A WINERROR.H error code.
+|
+|--------------------------------------------------------------------------*/
+
+static ULONG
+FindPcmciaCard(
+ ULONG adapterNumber,
+ ULONG busNumber,
+ INTERFACE_TYPE interface,
+ BOOLEAN first,
+ ULONG type,
+ ULONG * confidence
+ )
+{
+ //
+ // If this is the first call then we want to start from the
+ // first possible IO location.
+ //
+
+ if (first)
+ {
+ SearchStates[adapterNumber].IoLocationIndex = 0;
+ }
+
+ //
+ // Otherwise we want to start from 1 after were we left off
+ // last time.
+ //
+
+ else
+ {
+ SearchStates[adapterNumber].IoLocationIndex++;
+ }
+
+ //
+ // Step through the IO locations in the bus for which there aren't
+ // already Madge adapters installed looking for one with the
+ // required adapter type. If we don't find one we will return a
+ // confidence level of zero. (Note we check that there isn't a
+ // Madge adapter at the IO location first to avoid trashing a
+ // working adapter.)
+ //
+
+ *confidence = 0;
+
+ while (SearchStates[adapterNumber].IoLocationIndex <
+ sizeof(PcmciaIoLocations) / sizeof(ULONG))
+ {
+ if (!MadgeCardAlreadyInstalled(
+ FALSE,
+ busNumber,
+ PcmciaIoLocations[SearchStates[adapterNumber].IoLocationIndex]
+ ))
+ {
+ if (CheckForCard(
+ busNumber,
+ interface,
+ PcmciaIoLocations[SearchStates[adapterNumber].IoLocationIndex],
+ &SearchStates[adapterNumber].Irq
+ ) == type)
+ {
+ *confidence = 100;
+ break;
+ }
+ }
+
+ SearchStates[adapterNumber].IoLocationIndex++;
+ }
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgePcmciaIdentifyHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* buffer -> Buffer for the results.
+* bufferSize -> Size of the buffer in WCHARs.
+*
+* Purpose - Return information about a type of adapter that this module
+* supports.
+*
+* Returns - A WINERROR.H error code. ERROR_NO_MORE_ITEMS
+* is returned if index refers to an adapter type not
+* supported.
+*
+****************************************************************************/
+
+LONG
+MadgePcmciaIdentifyHandler(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ LONG numberOfAdapters;
+ LONG action;
+ LONG length;
+ LONG i;
+
+ MadgePrint2("MadgePcmciaIdentifyHandler (index = %ld)\n", index);
+
+ //
+ // Do some initialisation.
+ //
+
+ numberOfAdapters = sizeof(Adapters) / sizeof(ADAPTER_INFO);
+ action = index % 100;
+ index = index - action;
+
+ //
+ // Check that index does not exceed the number of adapters we
+ // support.
+ //
+
+ if ((index - 1000) / 100 >= numberOfAdapters)
+ {
+ return ERROR_NO_MORE_ITEMS;
+ }
+
+ //
+ // If index refers to an adapter type supported then carry out the
+ // requested action.
+ //
+
+ for (i = 0; i < numberOfAdapters; i++)
+ {
+ if (Adapters[i].Index == index)
+ {
+ switch (action)
+ {
+ //
+ // Return the adapter's abbreviation.
+ //
+
+ case 0:
+
+ length = UnicodeStrLen(Adapters[i].InfId) + 1;
+
+ if (bufferSize < length)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ memcpy(
+ (VOID *) buffer,
+ Adapters[i].InfId,
+ length * sizeof(WCHAR)
+ );
+
+ break;
+
+ //
+ // Return the adapter's description.
+ //
+
+ case 1:
+
+ length = UnicodeStrLen(Adapters[i].CardDescription) + 1;
+
+ if (bufferSize < length)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ memcpy(
+ (VOID *) buffer,
+ Adapters[i].CardDescription,
+ length * sizeof(WCHAR)
+ );
+
+ break;
+
+ //
+ // Return the adapter's manufacturer.
+ //
+
+ case 2:
+
+ length = UnicodeStrLen(Adapters[i].Manufacturer) + 1;
+
+ if (bufferSize < length)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ memcpy(
+ (VOID *) buffer,
+ Adapters[i].Manufacturer,
+ length * sizeof(WCHAR)
+ );
+
+ break;
+
+ //
+ // Return the search order.
+ //
+
+ case 3:
+
+ if (bufferSize < 5)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ wsprintfW(
+ (VOID *) buffer,
+ L"%d",
+ Adapters[i].SearchOrder
+ );
+
+ break;
+
+ //
+ // Anything else is invalid.
+ //
+
+ default:
+
+ return ERROR_INVALID_PARAMETER;
+
+ }
+
+ return NO_ERROR;
+ }
+ }
+
+ //
+ // We didn't find an adapter type that matched the index so
+ // return an error.
+ //
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgePcmciaFirstNextHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* interface -> The NT interface type (ISA, EISA etc).
+* busNumber -> The bus number to search.
+* first -> TRUE if the search of this bus should start
+* from scratch.
+* token -> Pointer to holder for a token that identifies
+* the adapter found.
+* confidence -> Pointer to a holder for the confidence by
+* which the adapter has been found.
+*
+* Purpose - Attempts to find an adapter on the specified bus. If first
+* is TRUE then the search starts from scratch. Otherwise
+* the search starts from where it left of the last time we
+* were called.
+*
+* Returns - A WINERROR.H error code. A return code of NO_ERROR
+* and a *confidence of 0 means we didn't find an adapter.
+*
+****************************************************************************/
+
+LONG
+MadgePcmciaFirstNextHandler(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ BOOL first,
+ VOID * * token,
+ LONG * confidence
+ )
+{
+ LONG adapterNumber;
+ ULONG retCode;
+
+ MadgePrint2("MadgePcmciaFirstNextHandler (index = %ld)\n", index);
+
+ //
+ // Check the interface type (could be an ISA adapter in an EISA bus).
+ //
+
+ if (interface != Isa && interface != Eisa)
+ {
+ *confidence = 0;
+ return NO_ERROR;
+ }
+
+ //
+ // Work out and validate the adapter type being searched for.
+ //
+
+ adapterNumber = (index - 1000) / 100;
+
+ if (adapterNumber < 0 ||
+ adapterNumber >= sizeof(Adapters) / sizeof(ADAPTER_INFO) ||
+ (index % 100) != 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Type to find an adapter.
+ //
+
+ retCode = FindPcmciaCard(
+ (ULONG) adapterNumber,
+ busNumber,
+ interface,
+ (BOOLEAN) first,
+ (ULONG) index,
+ confidence
+ );
+
+ if (retCode == NO_ERROR)
+ {
+ //
+ // In this module I use the token as follows: Remember that
+ // the token can only be 2 bytes long (the low 2) because of
+ // the interface to the upper part of this DLL.
+ //
+ // The rest of the high byte is the the bus number.
+ // The low byte is the driver index number into Adapters.
+ //
+ // NOTE: This presumes that there are < 129 buses in the
+ // system. Is this reasonable?
+ //
+
+ *token = (VOID *) ((busNumber & 0x7F) << 8);
+ *token = (VOID *) (((ULONG) *token) | (adapterNumber << 1));
+
+ if (interface == Eisa)
+ {
+ *token = (VOID *) (((ULONG) *token) | 1);
+ }
+ }
+
+ return retCode;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgePcmciaOpenHandleHandler
+*
+* Parameters - token -> Pointer to holder for a token that identifies
+* an adapter found by FirstNextHandler.
+* handle -> Pointer to a holder a handle the caller
+* should use to query the adapter refered to
+* by *token.
+*
+* Purpose - Generates a handle for an adapter just found by a call
+* to FirstNextHandler.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgePcmciaOpenHandleHandler(
+ VOID * token,
+ VOID * * handle
+ )
+{
+ PCMCIA_ADAPTER * adapter;
+ ULONG adapterNumber;
+ ULONG busNumber;
+ INTERFACE_TYPE interface;
+
+ MadgePrint1("MadgePcmciaOpenHandleHandler\n");
+
+ //
+ // Get info from the token.
+ //
+
+ busNumber = (ULONG) (((ULONG) token >> 8) & 0x7F);
+ adapterNumber = (((ULONG) token) & 0xFF) >> 1;
+
+ MadgePrint2("adapterNumber = %ld\n", adapterNumber);
+
+ if ((((ULONG) token) & 1) == 1)
+ {
+ interface = Eisa;
+ }
+ else
+ {
+ interface = Isa;
+ }
+
+ //
+ // Allocate a structure for the details of the adapter.
+ //
+
+ adapter = (PCMCIA_ADAPTER *) DetectAllocateHeap(sizeof(PCMCIA_ADAPTER));
+
+ if (adapter == NULL)
+ {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // Copy the details.
+ //
+
+ adapter->Found = TRUE;
+ adapter->CardType = Adapters[adapterNumber].Index;
+ adapter->InterfaceType = interface;
+ adapter->BusNumber = busNumber;
+ adapter->IoLocation =
+ PcmciaIoLocations[SearchStates[adapterNumber].IoLocationIndex];
+ adapter->Dma = 0; // Pcmcia's are always in PIO mode.
+ adapter->Irq = SearchStates[adapterNumber].Irq;
+
+ *handle = (VOID *) adapter;
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgePcmciaCreateHandleHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* interface -> NT interface type (Eisa, Isa etc).
+* busNumber -> Number of the bus containing the adapter.
+* handle -> Pointer to a holder a handle the caller
+* should use to query the adapter.
+*
+* Purpose - Generates a handle for an adapter that has not been detected
+* but the caller claims exists.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgePcmciaCreateHandleHandler(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ VOID * * handle
+ )
+{
+ PCMCIA_ADAPTER * adapter;
+ LONG numberOfAdapters;
+ LONG i;
+
+ MadgePrint2("MadgePcmciaCreateHandleHandler (index = %ld)\n", index);
+
+ //
+ // Check that the interface type is correct for this module
+ // (could be an Isa adapter in an Eisa slot).
+ //
+
+ if (interface != Isa && interface != Eisa)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // If the index is valid then create a handle.
+ //
+
+ numberOfAdapters = sizeof(Adapters) / sizeof(ADAPTER_INFO);
+
+ for (i = 0; i < numberOfAdapters; i++)
+ {
+ if (Adapters[i].Index == index)
+ {
+ //
+ // Allocate a structure for the adapter details.
+ //
+
+ adapter = (PCMCIA_ADAPTER *) DetectAllocateHeap(sizeof(PCMCIA_ADAPTER));
+
+ if (adapter == NULL)
+ {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // Copy the details.
+ //
+
+ adapter->Found = FALSE;
+ adapter->CardType = index;
+ adapter->InterfaceType = interface;
+ adapter->BusNumber = busNumber;
+ adapter->IoLocation = PcmciaIoLocations[0];
+ adapter->Dma = 0; // Pcmcia's are always in PIO mode.
+ adapter->Irq = RESOURCE_UNKNOWN;
+
+ *handle = (VOID *) adapter;
+
+ return NO_ERROR;
+ }
+ }
+
+ //
+ // We didn't find an adapter type that matched the one the caller
+ // claims exists so return an error.
+ //
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgePcmciaCloseHandleHandler
+*
+* Parameters - handle -> Handle to be closed.
+*
+* Purpose - Closes a previously opened or created handle.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgePcmciaCloseHandleHandler(
+ VOID * handle
+ )
+{
+ MadgePrint1("MadgePcmciaCloseHandleHandler\n");
+
+ DetectFreeHeap(handle);
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgePcmciaQueryCfgHandler
+*
+* Parameters - handle -> Handle to for the adapter to be queried.
+* buffer -> Buffer for the returned parameters.
+* bufferSize -> Size of the buffer in WCHARs.
+*
+* Purpose - Find out what the parameters are for the adapter identified
+* by the handle. This function does not assume that the
+* adapter described by the handle is valid if the handle
+* was created rather than being opened. If the handle
+* was created then a search is made for an adapter.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgePcmciaQueryCfgHandler(
+ VOID * handle,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ PCMCIA_ADAPTER * adapter;
+ ULONG confidence;
+ LONG adapterNumber;
+ LONG retCode;
+
+ MadgePrint1("MadgePcmciaQueryCfgHandler\n");
+
+ //
+ // Do some initialisation.
+ //
+
+ adapter = (PCMCIA_ADAPTER *) handle;
+
+ //
+ // Check that the interface type specified by the handle is
+ // valid for this module (could be an Isa card in an Eisa slot).
+ //
+
+ if (adapter->InterfaceType != Isa && adapter->InterfaceType != Eisa)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // If the adapter was created rather than being opened we must search
+ // for an adapter.
+ //
+
+ if (!adapter->Found)
+ {
+ adapterNumber = (adapter->CardType - 1000) / 100;
+
+ retCode = FindPcmciaCard(
+ adapterNumber,
+ adapter->BusNumber,
+ adapter->InterfaceType,
+ TRUE,
+ adapter->CardType,
+ &confidence
+ );
+
+ //
+ // If we are not 100% sure that we found an adapter with
+ // the right ID we give up.
+ //
+
+ if (retCode != NO_ERROR || confidence != 100)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ adapter->Found = TRUE;
+ adapter->IoLocation =
+ PcmciaIoLocations[SearchStates[adapterNumber].IoLocationIndex];
+ adapter->Dma = 0; // Pcmcia's are always in PIO mode.
+ adapter->Irq = SearchStates[adapterNumber].Irq;
+ }
+
+ //
+ // Build resulting buffer.
+ //
+ // Copy in the IO location.
+ //
+
+ if (AppendParameter(
+ &buffer,
+ &bufferSize,
+ IoAddrString,
+ adapter->IoLocation
+ ) != NO_ERROR)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ //
+ // Copy in the DMA channel.
+ //
+
+ if (AppendParameter(
+ &buffer,
+ &bufferSize,
+ DmaChanString,
+ adapter->Dma
+ ) != NO_ERROR)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ //
+ // Copy in the IRQ number.
+ //
+
+ if (AppendParameter(
+ &buffer,
+ &bufferSize,
+ IrqString,
+ adapter->Irq
+ ) != NO_ERROR)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ //
+ // Copy in the multiprocessor flag.
+ //
+
+ if (AppendParameter(
+ &buffer,
+ &bufferSize,
+ MultiprocessorString,
+ IsMultiprocessor()
+ ) != NO_ERROR)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ //
+ // Copy in final \0.
+ //
+
+ if (bufferSize < 1)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ *buffer = L'\0';
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgePcmciaVerifyCfgHandler
+*
+* Parameters - handle -> Handle to for the adapter to be verified.
+* buffer -> Buffer containing the returned parameters.
+*
+* Purpose - Verify that the parameters in buffer are correct for
+* the adapter identified by handle.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgePcmciaVerifyCfgHandler(
+ VOID * handle,
+ WCHAR * buffer
+ )
+{
+ PCMCIA_ADAPTER * adapter;
+ WCHAR * place;
+ BOOLEAN found;
+ ULONG ioLocation;
+ ULONG dmaChannel;
+ ULONG irqNumber;
+ ULONG multiprocessor;
+ LONG adapterNumber;
+ ULONG irq;
+
+ MadgePrint1("MadgePcmciaVerifyCfgHandler\n");
+
+ //
+ // Do some initialisation.
+ //
+
+ adapter = (PCMCIA_ADAPTER *) handle;
+ adapterNumber = (adapter->CardType - 1000) / 100;
+
+ //
+ // Check that the interface type is correct for this module
+ // (could be an Isa adapter in an Eisa slot).
+ //
+
+ if (adapter->InterfaceType != Isa && adapter->InterfaceType != Eisa)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // Parse the parameters.
+ //
+
+ //
+ // Get the IO location.
+ //
+
+ place = FindParameterString(buffer, IoAddrString);
+
+ if (place == NULL)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ place += UnicodeStrLen(IoAddrString) + 1;
+
+ ScanForNumber(place, &ioLocation, &found);
+
+ if (!found)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // Get the DMA channel.
+ //
+
+ place = FindParameterString(buffer, DmaChanString);
+
+ if (place == NULL)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ place += UnicodeStrLen(DmaChanString) + 1;
+
+ ScanForNumber(place, &dmaChannel, &found);
+
+ if (!found)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // Get the IRQ number.
+ //
+
+ place = FindParameterString(buffer, IrqString);
+
+ if (place == NULL)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ place += UnicodeStrLen(IrqString) + 1;
+
+ ScanForNumber(place, &irqNumber, &found);
+
+ if (!found)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // Get the multiprocessor flag.
+ //
+
+ place = FindParameterString(buffer, MultiprocessorString);
+
+ if (place == NULL)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ place += UnicodeStrLen(MultiprocessorString) + 1;
+
+ //
+ // Now parse the value.
+ //
+
+ ScanForNumber(place, &multiprocessor, &found);
+
+ //
+ // If the handle does not refer to an adapter that has been found
+ // by search we must query the hardware.
+ //
+
+ if (!adapter->Found)
+ {
+ if (CheckForCard(
+ adapter->BusNumber,
+ adapter->InterfaceType,
+ ioLocation,
+ &irq
+ ) != adapter->CardType)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ adapter->IoLocation = ioLocation;
+ adapter->Dma = 0; // Pcmcia's are always in PIO mode.
+ adapter->Irq = irq;
+ adapter->Found = TRUE;
+ }
+
+ //
+ // Verify the parameters.
+ //
+
+ if (ioLocation != adapter->IoLocation ||
+ multiprocessor != IsMultiprocessor())
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ if (adapter->Dma == RESOURCE_UNKNOWN)
+ {
+ if (!IsValueInList(dmaChannel, ParamRange[adapterNumber].DmaRange))
+ {
+ return ERROR_INVALID_DATA;
+ }
+ }
+ else if (adapter->Dma != dmaChannel)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ if (adapter->Irq == RESOURCE_UNKNOWN)
+ {
+ if (!IsValueInList(irqNumber, ParamRange[adapterNumber].IrqRange))
+ {
+ return ERROR_INVALID_DATA;
+ }
+ }
+ else if (adapter->Irq != irqNumber)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // If we make it to here everything checked out ok.
+ //
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgePcmciaQueryMaskHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* buffer -> Buffer for the returned parameters.
+* bufferSize -> Size of buffer in WCHARs.
+*
+* Purpose - Return the list of parameters required for the adapter
+* type specified by index.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgePcmciaQueryMaskHandler(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ WCHAR * params;
+ LONG length;
+ LONG numberOfAdapters;
+ LONG i;
+
+ MadgePrint2("MadgePcmciaQueryMaskHandler (index = %ld)\n", index);
+ MadgePrint2("BufferSize = %ld\n", bufferSize);
+
+ //
+ // Find the adapter type.
+ //
+
+ numberOfAdapters = sizeof(Adapters) / sizeof(ADAPTER_INFO);
+
+ for (i = 0; i < numberOfAdapters; i++)
+ {
+ if (Adapters[i].Index == index)
+ {
+ params = Adapters[i].Parameters;
+
+ //
+ // Find the string length (Ends with 2 NULLs)
+ //
+
+ for (length = 0; ; length++)
+ {
+ if (params[length] == L'\0')
+ {
+ length++;
+
+ if (params[length] == L'\0')
+ {
+ break;
+ }
+ }
+ }
+
+ length++;
+
+ MadgePrint2("length = %ld\n", length);
+
+ //
+ // Copy the parameters into buffer.
+ //
+
+ if (bufferSize < length)
+ {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ memcpy((VOID *) buffer, params, length * sizeof(WCHAR));
+
+ return NO_ERROR;
+ }
+ }
+
+ //
+ // If we make it here we did not find a valid adapter type so
+ // return and error.
+ //
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgePcmciaParamRangeHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* param -> Paramter being queried.
+* buffer -> Buffer for the returned parameters.
+* bufferSize -> Size of buffer in LONGs.
+*
+* Purpose - Return the list of acceptable values for the parameter
+* specified.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgePcmciaParamRangeHandler(
+ LONG index,
+ WCHAR * param,
+ LONG * buffer,
+ LONG * bufferSize
+ )
+{
+ LONG i;
+ LONG adapterNumber;
+ LONG count;
+
+ MadgePrint2("MadgePcmciaParamRangeHandler (index=%ld)\n", index);
+
+ //
+ // Work out and validate the adapter number.
+ //
+
+ adapterNumber = (index - 1000) / 100;
+
+ if (adapterNumber < 0 ||
+ adapterNumber >= sizeof(Adapters) / sizeof(ADAPTER_INFO) ||
+ (index % 100) != 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // The simplest parameter is the IO location because this is the
+ // same for all of the adapter types.
+ //
+
+ if (UnicodeStringsEqual(param, IoAddrString))
+ {
+ count = sizeof(PcmciaIoLocations) / sizeof(ULONG);
+
+ if (*bufferSize < count)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ buffer[i] = PcmciaIoLocations[i];
+ }
+
+ *bufferSize = count;
+
+ return NO_ERROR;
+ }
+
+ //
+ // IRQ number is slightly more complicated because it is different
+ // for different adapter types.
+ //
+
+ else if (UnicodeStringsEqual(param, IrqString))
+ {
+ count = 0;
+
+ while (ParamRange[adapterNumber].IrqRange[count] != END_OF_LIST)
+ {
+ count++;
+ }
+
+ if (*bufferSize < count)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ buffer[i] = ParamRange[adapterNumber].IrqRange[i];
+ }
+
+ *bufferSize = count;
+
+ return NO_ERROR;
+ }
+
+
+ //
+ // Likewise DMA channel.
+ //
+
+ else if (UnicodeStringsEqual(param, DmaChanString))
+ {
+ count = 0;
+
+ while (ParamRange[adapterNumber].DmaRange[count] != END_OF_LIST)
+ {
+ count++;
+ }
+
+ if (*bufferSize < count)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ buffer[i] = ParamRange[adapterNumber].DmaRange[i];
+ }
+
+ *bufferSize = count;
+
+ return NO_ERROR;
+ }
+
+ //
+ // Or fill in the allowable values for the multiprocessor flag.
+ //
+
+ else if (UnicodeStringsEqual(param, MultiprocessorString))
+ {
+ if (*bufferSize < 2)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ *bufferSize = 2;
+
+ buffer[0] = 0;
+ buffer[1] = 1;
+
+ return NO_ERROR;
+ }
+
+ //
+ // If we reach this point we have been passed a parameter we
+ // don't know about.
+ //
+
+ return ERROR_INVALID_DATA;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgePcmciaQueryParameterNameHandler
+*
+* Parameters - param -> Paramter being queried.
+* buffer -> Buffer for the returned name.
+* bufferSize -> Size of buffer in WCHARs.
+*
+* Purpose - Return the name of a parameter.
+*
+* Returns - ERROR_INVALID_PARAMETER to cause the caller to use
+* the Microsoft provided default names.
+*
+****************************************************************************/
+
+LONG
+MadgePcmciaQueryParameterNameHandler(
+ WCHAR * param,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/********* End of MDGPCMC.C ************************************************/
+
diff --git a/private/ntos/ndis/madge/detect/mdgpnp.c b/private/ntos/ndis/madge/detect/mdgpnp.c
new file mode 100644
index 000000000..4c2d3d1c2
--- /dev/null
+++ b/private/ntos/ndis/madge/detect/mdgpnp.c
@@ -0,0 +1,2231 @@
+/****************************************************************************
+*
+* MDGPNP.C
+*
+* ISA PnP Adapter Detection Module
+*
+* Copyright (c) Madge Networks Ltd 1994
+*
+* COMPANY CONFIDENTIAL - RELEASED TO MICROSOFT CORP. ONLY FOR DEVELOPMENT
+* OF WINDOWS95 NETCARD DETECTION - THIS SOURCE IS NOT TO BE RELEASED OUTSIDE
+* OF MICROSOFT WITHOUT EXPLICIT WRITTEN PERMISSION FROM AN AUTHORISED
+* OFFICER OF MADGE NETWORKS LTD.
+*
+* Created: PBA 23/11/1994
+*
+****************************************************************************/
+
+#include <ntddk.h>
+#include <ntddnetd.h>
+
+#include <windef.h>
+#include <winerror.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mdgncdet.h"
+
+//
+// Prototype "borrowed" from WINUSER.H
+//
+
+extern int WINAPIV wsprintfW(LPWSTR, LPCWSTR, ...);
+
+
+/*---------------------------------------------------------------------------
+|
+| Smart16 adapter types. These correspond to the indexes that the upper layers
+| use for identifying adapters, so change them with care.
+|
+|--------------------------------------------------------------------------*/
+
+#define SMART_NONE 0
+#define SMART_PNP 1000
+
+
+/*---------------------------------------------------------------------------
+|
+| IO locations that PnP adapters can be at as of 23/11/1994.
+|
+---------------------------------------------------------------------------*/
+
+static
+ULONG PnPIoLocations[17] =
+ {0x1a20, 0x2a20, 0x3a20,
+ 0x0140,
+ 0x0920, 0x0940, 0x0960, 0x0980,
+ 0x0a20, 0x0a40, 0x0a60, 0x0a80, 0x0aa0,
+ 0x0b20, 0x0b40, 0x0b60, 0x0b80};
+
+
+/*---------------------------------------------------------------------------
+|
+| Various PnP card specific constants.
+|
+---------------------------------------------------------------------------*/
+
+#define PNP_IO_RANGE 32
+
+#define PNP_CONTROL_REGISTER_1 3
+#define PNP_ID_REGISTER 8
+
+#define PNP_CON_REG_OFFSET 4
+#define PNP_EEDO 0x0002
+#define PNP_EEDEN 0x0004
+#define PNP_SSK 0x0001
+#define PNP_DELAY_CNT 16
+#define PNP_WAIT_CNT 1000
+#define PNP_WRITE_CMD 0x00a0
+#define PNP_READ_CMD 0x00a1
+
+#define PNP_EEPROM_NODE_ADDRESS3 15
+
+#define PNP_CONFIG_ADDRESS_REGISTER 1
+#define PNP_CONFIG_DATA_REGISTER 2
+
+#define PNP_VENDOR_CONFIG_IRQ 0x70
+
+
+/*---------------------------------------------------------------------------
+|
+| First three bytes of a Madge node address.
+|
+|---------------------------------------------------------------------------*/
+
+static
+UCHAR MadgeNodeAddressPrefix[3] =
+ {0x00, 0x00, 0xf6};
+
+
+/*---------------------------------------------------------------------------
+|
+| List of adapter types supported by this module.
+|
+|---------------------------------------------------------------------------*/
+
+static
+ADAPTER_INFO Adapters[] =
+{
+ {
+ SMART_PNP,
+ MDGPNP,
+ L"Madge 16/4 ISA PnP Ringnode",
+ L"Madge Networks",
+ L"IOLOCATION\0"
+ L"000\0"
+ L"00100\0"
+ L"DMACHANNEL\0"
+ L"000\0"
+ L"00100\0"
+ L"INTERRUPTNUMBER\0"
+ L"000\0"
+ L"000\0"
+ L"MULTIPROCESSOR\0"
+ L"000\0"
+ L"00100\0",
+ NULL,
+ 903
+ }
+};
+
+
+/*---------------------------------------------------------------------------
+|
+| Madge specific parameter range information. The order entries in this
+| table MUST match that in the Adapters table above. The first value
+Ý in each list is the default.
+|
+---------------------------------------------------------------------------*/
+
+static
+struct
+{
+ ULONG IrqRange[8];
+ ULONG DmaRange[2];
+}
+ParamRange[] =
+{
+ //
+ // PnP.
+ //
+
+ {
+ { 3, 2, 7, 9, 10, 11, 15, END_OF_LIST},
+ { 0, END_OF_LIST}
+ }
+};
+
+
+/*---------------------------------------------------------------------------
+|
+| Structure for holding state of a search.
+|
+|--------------------------------------------------------------------------*/
+
+typedef struct
+{
+ ULONG IoLocationIndex;
+ ULONG Irq;
+}
+PNP_SEARCH_STATE;
+
+
+/*---------------------------------------------------------------------------
+|
+| This is an array of search states. We need one state for each type
+| of adapter supported.
+|
+|--------------------------------------------------------------------------*/
+
+static
+PNP_SEARCH_STATE SearchStates[sizeof(Adapters) / sizeof(ADAPTER_INFO)] = {0};
+
+
+/*---------------------------------------------------------------------------
+|
+| Structure for holding a particular adapter's complete information.
+|
+|--------------------------------------------------------------------------*/
+
+typedef struct
+{
+ BOOLEAN Found;
+ ULONG CardType;
+ ULONG BusNumber;
+ INTERFACE_TYPE InterfaceType;
+ ULONG IoLocation;
+ ULONG Dma;
+ ULONG Irq;
+}
+PNP_ADAPTER;
+
+
+/*---------------------------------------------------------------------------
+Ý Function - PnPReadCtrl
+| Parameters - busNumber -> The number of the bus.
+| interface -> The interface type of the bus.
+| ioLocation -> The IO location of the adapter.
+|
+| Purpose - Read the PnP control register of an adapter at the
+Ý specified location.
+|
+| Returns - The value read.
+|
+---------------------------------------------------------------------------*/
+
+static UCHAR
+PnPReadCtrl(
+ ULONG busNumber,
+ INTERFACE_TYPE interface,
+ ULONG ioLocation
+ )
+{
+ UCHAR byte;
+
+ if (DetectReadPortUchar(
+ interface,
+ busNumber,
+ ioLocation + PNP_CON_REG_OFFSET,
+ &byte
+ ) != STATUS_SUCCESS)
+ {
+ return 0;
+ }
+
+ return byte;
+}
+
+
+/*---------------------------------------------------------------------------
+Ý Function - PnPWriteCtrl
+| Parameters - busNumber -> The number of the bus.
+| interface -> The interface type of the bus.
+| ioLocation -> The IO location of the adapter.
+| data -> The data to write.
+| Purpose - Write to the PnP control register of an adapter at the
+Ý specified location.
+|
+| Returns - Nothing.
+|
+---------------------------------------------------------------------------*/
+
+static void
+PnPWriteCtrl(
+ ULONG busNumber,
+ INTERFACE_TYPE interface,
+ ULONG ioLocation,
+ UCHAR data
+ )
+{
+ DetectWritePortUchar(
+ interface,
+ busNumber,
+ ioLocation + PNP_CON_REG_OFFSET,
+ data
+ );
+}
+
+
+/*---------------------------------------------------------------------------
+Ý Function - PnPDelay
+| Parameters - busNumber -> The number of the bus.
+| interface -> The interface type of the bus.
+| ioLocation -> The IO location of the adapter.
+|
+| Purpose - Wait a short time.
+|
+| Returns - Nothing.
+|
+---------------------------------------------------------------------------*/
+
+static void
+PnPDelay(
+ ULONG busNumber,
+ INTERFACE_TYPE interface,
+ ULONG ioLocation
+ )
+{
+ UINT i;
+ UCHAR byte;
+
+ for (i = 0; i < PNP_DELAY_CNT; i++)
+ {
+ DetectReadPortUchar(
+ interface,
+ busNumber,
+ ioLocation,
+ &byte
+ );
+ }
+}
+
+
+/*---------------------------------------------------------------------------
+Ý Function - PnPSetClk
+| Parameters - busNumber -> The number of the bus.
+| interface -> The interface type of the bus.
+| ioLocation -> The IO location of the adapter.
+|
+| Purpose - Set the serial device clock bit.
+|
+| Returns - Nothing.
+|
+---------------------------------------------------------------------------*/
+
+static void
+PnPSetClk(
+ ULONG busNumber,
+ INTERFACE_TYPE interface,
+ ULONG ioLocation
+ )
+{
+ UCHAR temp;
+
+ temp = PnPReadCtrl(busNumber, interface, ioLocation);
+ temp |= PNP_SSK;
+
+ PnPWriteCtrl(busNumber, interface, ioLocation, temp);
+
+ PnPDelay(busNumber, interface, ioLocation);
+}
+
+
+/*---------------------------------------------------------------------------
+Ý Function - PnPClrClk
+| Parameters - busNumber -> The number of the bus.
+| interface -> The interface type of the bus.
+| ioLocation -> The IO location of the adapter.
+|
+| Purpose - Clear the serial device clock bit.
+|
+| Returns - Nothing.
+|
+---------------------------------------------------------------------------*/
+
+static void
+PnPClrClk(
+ ULONG busNumber,
+ INTERFACE_TYPE interface,
+ ULONG ioLocation
+ )
+{
+ UCHAR temp;
+
+ temp = PnPReadCtrl(busNumber, interface, ioLocation);
+ temp &= ~PNP_SSK;
+
+ PnPWriteCtrl(busNumber, interface, ioLocation, temp);
+
+ PnPDelay(busNumber, interface, ioLocation);
+}
+
+
+/*---------------------------------------------------------------------------
+Ý Function - PnPSetEEDEN
+| Parameters - busNumber -> The number of the bus.
+| interface -> The interface type of the bus.
+| ioLocation -> The IO location of the adapter.
+|
+| Purpose - Put the serial device into output mode.
+|
+| Returns - Nothing.
+|
+---------------------------------------------------------------------------*/
+
+static void
+PnPSetEEDEN(
+ ULONG busNumber,
+ INTERFACE_TYPE interface,
+ ULONG ioLocation
+ )
+{
+ UCHAR temp;
+
+ temp = PnPReadCtrl(busNumber, interface, ioLocation);
+ temp |= PNP_EEDEN;
+
+ PnPWriteCtrl(busNumber, interface, ioLocation, temp);
+
+ PnPDelay(busNumber, interface, ioLocation);
+}
+
+
+/*---------------------------------------------------------------------------
+Ý Function - PnPClrEEDEN
+| Parameters - busNumber -> The number of the bus.
+| interface -> The interface type of the bus.
+| ioLocation -> The IO location of the adapter.
+|
+| Purpose - Put the serial device into input mode.
+|
+| Returns - Nothing.
+|
+---------------------------------------------------------------------------*/
+
+static void
+PnPClrEEDEN(
+ ULONG busNumber,
+ INTERFACE_TYPE interface,
+ ULONG ioLocation
+ )
+{
+ UCHAR temp;
+
+ temp = PnPReadCtrl(busNumber, interface, ioLocation);
+ temp &= ~PNP_EEDEN;
+
+ PnPWriteCtrl(busNumber, interface, ioLocation, temp);
+
+ PnPDelay(busNumber, interface, ioLocation);
+}
+
+/*---------------------------------------------------------------------------
+Ý Function - PnPTwitchClk
+| Parameters - busNumber -> The number of the bus.
+| interface -> The interface type of the bus.
+| ioLocation -> The IO location of the adapter.
+|
+| Purpose - Toggle the serial device clock bit to strobe data into
+Ý the device.
+|
+| Returns - Nothing.
+|
+---------------------------------------------------------------------------*/
+
+static void
+PnPTwitchClk(
+ ULONG busNumber,
+ INTERFACE_TYPE interface,
+ ULONG ioLocation
+ )
+{
+ PnPSetClk(busNumber, interface, ioLocation);
+ PnPClrClk(busNumber, interface, ioLocation);
+}
+
+
+/*---------------------------------------------------------------------------
+Ý Function - PnPStartBit
+| Parameters - busNumber -> The number of the bus.
+| interface -> The interface type of the bus.
+| ioLocation -> The IO location of the adapter.
+|
+| Purpose - Send a start bit to the serial device. This is done by a
+Ý 1 to 0 transition of the data bit while the clock bit
+Ý is 1.
+|
+| Returns - Nothing.
+|
+---------------------------------------------------------------------------*/
+
+static void
+PnPStartBit(
+ ULONG busNumber,
+ INTERFACE_TYPE interface,
+ ULONG ioLocation
+ )
+{
+ UCHAR temp;
+
+ temp = PnPReadCtrl(busNumber, interface, ioLocation);
+ temp &= ~(PNP_EEDO + PNP_EEDEN + PNP_SSK);
+ temp |= (PNP_EEDO + PNP_EEDEN);
+
+ PnPWriteCtrl(busNumber, interface, ioLocation, temp);
+
+ PnPDelay(busNumber, interface, ioLocation);
+
+ temp |= PNP_SSK;
+
+ PnPWriteCtrl(busNumber, interface, ioLocation, temp);
+
+ PnPDelay(busNumber, interface, ioLocation);
+
+ temp &= ~PNP_EEDO;
+
+ PnPWriteCtrl(busNumber, interface, ioLocation, temp);
+
+ PnPDelay(busNumber, interface, ioLocation);
+
+ temp &= ~(PNP_EEDO + PNP_EEDEN + PNP_SSK);
+
+ PnPWriteCtrl(busNumber, interface, ioLocation, temp);
+
+ PnPDelay(busNumber, interface, ioLocation);
+}
+
+
+/*---------------------------------------------------------------------------
+Ý Function - PnPStopBit
+| Parameters - busNumber -> The number of the bus.
+| interface -> The interface type of the bus.
+| ioLocation -> The IO location of the adapter.
+|
+| Purpose - Send a stop bit to the serial device. This is done by a
+Ý 0 to 1 transition of the data bit while the clock bit
+Ý is 1.
+|
+| Returns - Nothing.
+|
+---------------------------------------------------------------------------*/
+
+static void
+PnPStopBit(
+ ULONG busNumber,
+ INTERFACE_TYPE interface,
+ ULONG ioLocation
+ )
+{
+ UCHAR temp;
+
+ temp = PnPReadCtrl(busNumber, interface, ioLocation);
+ temp &= ~(PNP_EEDO + PNP_EEDEN + PNP_SSK);
+ temp |= (PNP_EEDEN);
+
+ PnPWriteCtrl(busNumber, interface, ioLocation, temp);
+
+ PnPDelay(busNumber, interface, ioLocation);
+
+ temp |= PNP_SSK;
+
+ PnPWriteCtrl(busNumber, interface, ioLocation, temp);
+
+ PnPDelay(busNumber, interface, ioLocation);
+
+ temp |= PNP_EEDO;
+
+ PnPWriteCtrl(busNumber, interface, ioLocation, temp);
+
+ PnPDelay(busNumber, interface, ioLocation);
+
+ temp &= ~(PNP_EEDO + PNP_EEDEN + PNP_SSK);
+
+ PnPWriteCtrl(busNumber, interface, ioLocation, temp);
+
+ PnPDelay(busNumber, interface, ioLocation);
+}
+
+
+/*---------------------------------------------------------------------------
+Ý Function - PnPWaitAck
+| Parameters - busNumber -> The number of the bus.
+| interface -> The interface type of the bus.
+| ioLocation -> The IO location of the adapter.
+|
+| Purpose - Wait for the serial device to indicate that it has
+Ý accepted the last command or data.
+|
+| Returns - TRUE if the device has accepted the command or data
+Ý or FALSE otherwise.
+|
+---------------------------------------------------------------------------*/
+
+static BOOLEAN
+PnPWaitAck(
+ ULONG busNumber,
+ INTERFACE_TYPE interface,
+ ULONG ioLocation
+ )
+{
+ UCHAR temp;
+ UINT i;
+
+ temp = PnPReadCtrl(busNumber, interface, ioLocation);
+ temp &= ~(PNP_EEDO + PNP_EEDEN + PNP_SSK);
+
+ PnPWriteCtrl(busNumber, interface, ioLocation, temp);
+
+ PnPDelay(busNumber, interface, ioLocation);
+
+ for (i = 0; i < PNP_WAIT_CNT; i++)
+ {
+ PnPSetClk(busNumber, interface, ioLocation);
+
+ temp = PnPReadCtrl(busNumber, interface, ioLocation);
+
+ PnPClrClk(busNumber, interface, ioLocation);
+
+ if ((temp & PNP_EEDO) == 0)
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+/*---------------------------------------------------------------------------
+Ý Function - PnPDummyWaitAck
+| Parameters - busNumber -> The number of the bus.
+| interface -> The interface type of the bus.
+| ioLocation -> The IO location of the adapter.
+|
+| Purpose - Wait for the serial device to indicate that it has
+Ý passed the last of the data to be read.
+|
+| Returns - TRUE if the device has passed data or FALSE otherwise.
+|
+---------------------------------------------------------------------------*/
+
+static BOOLEAN
+PnPDummyWaitAck(
+ ULONG busNumber,
+ INTERFACE_TYPE interface,
+ ULONG ioLocation
+ )
+{
+ UCHAR temp;
+ UINT i;
+
+ temp = PnPReadCtrl(busNumber, interface, ioLocation);
+ temp &= ~(PNP_EEDO + PNP_EEDEN + PNP_SSK);
+
+ PnPWriteCtrl(busNumber, interface, ioLocation, temp);
+
+ PnPDelay(busNumber, interface, ioLocation);
+
+ for (i = 0; i < PNP_WAIT_CNT ; i++)
+ {
+ PnPSetClk(busNumber, interface, ioLocation);
+
+ temp = PnPReadCtrl(busNumber, interface, ioLocation);
+
+ PnPClrClk(busNumber, interface, ioLocation);
+
+ if ((temp & PNP_EEDO) != 0)
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+/*---------------------------------------------------------------------------
+Ý Function - PnPWriteData
+| Parameters - busNumber -> The number of the bus.
+| interface -> The interface type of the bus.
+| ioLocation -> The IO location of the adapter.
+| data -> The data to write.
+| Purpose - Writes a bit to the serial device.
+|
+| Returns - Nothing.
+|
+---------------------------------------------------------------------------*/
+
+static void
+PnPWriteData(
+ ULONG busNumber,
+ INTERFACE_TYPE interface,
+ ULONG ioLocation,
+ UCHAR data
+ )
+{
+ UCHAR temp;
+
+ temp = PnPReadCtrl(busNumber, interface, ioLocation);
+ temp &= ~(PNP_EEDO);
+ temp |= (data & 0x0080) >> 6;
+
+ PnPWriteCtrl(busNumber, interface, ioLocation, temp);
+
+ PnPDelay(busNumber, interface, ioLocation);
+}
+
+
+/*---------------------------------------------------------------------------
+Ý Function - PnPReadByte
+| Parameters - busNumber -> The number of the bus.
+| interface -> The interface type of the bus.
+| ioLocation -> The IO location of the adapter.
+| index -> Offset in the serial device to read.
+| Purpose - Reads a byte from the serial device.
+|
+| Returns - The word read.
+|
+---------------------------------------------------------------------------*/
+
+static UINT
+PnPReadByte(
+ ULONG busNumber,
+ INTERFACE_TYPE interface,
+ ULONG ioLocation,
+ UINT index
+ )
+{
+ UCHAR temp;
+ UCHAR dataByte;
+ UINT i;
+
+ dataByte = 0;
+
+ //
+ // Wake up the device.
+ //
+
+ PnPStartBit(busNumber, interface, ioLocation);
+
+ //
+ // Set data 'OUTPUT' mode.
+ //
+
+ PnPSetEEDEN(busNumber, interface, ioLocation);
+
+ //
+ // Send WRITE CMD - a dummy really to allow us to set the
+ // READ address!
+ //
+
+ temp = PNP_WRITE_CMD;
+
+ //
+ // MSB first.
+ //
+
+ for (i = 0; i < 8; i++)
+ {
+ PnPWriteData(busNumber, interface, ioLocation, temp);
+ PnPTwitchClk(busNumber, interface, ioLocation);
+ temp = temp << 1;
+ }
+
+ if (!PnPWaitAck(busNumber, interface, ioLocation))
+ {
+ //
+ // Return something invalid if it timed out.
+ //
+
+ MadgePrint1("Timeout 1\n");
+
+ return 0xff;
+ }
+
+ //
+ // Set data 'OUTPUT' mode.
+ //
+
+ PnPSetEEDEN(busNumber, interface, ioLocation);
+
+ //
+ // Send Address in EEPROM.
+ //
+
+ temp = index;
+
+ //
+ // MSB first.
+ //
+
+ for (i = 0; i < 8; i++)
+ {
+ PnPWriteData(busNumber, interface, ioLocation, temp);
+ PnPTwitchClk(busNumber, interface, ioLocation);
+ temp = temp << 1;
+ }
+
+ if (!PnPWaitAck(busNumber, interface, ioLocation))
+ {
+ //
+ // Return something invalid if it timed out.
+ //
+
+ MadgePrint1("Timeout 2\n");
+
+ return 0xff;
+ }
+
+ PnPStartBit(busNumber, interface, ioLocation);
+
+ //
+ // Set data 'OUTPUT' mode.
+ //
+
+ PnPSetEEDEN(busNumber, interface, ioLocation);
+
+ //
+ // Send READ CMD.
+ //
+
+ temp = PNP_READ_CMD;
+
+ //
+ // MSB first.
+ //
+
+ for (i = 0; i < 8; i++)
+ {
+ PnPWriteData(busNumber, interface, ioLocation, temp);
+ PnPTwitchClk(busNumber, interface, ioLocation);
+ temp = temp << 1;
+ }
+
+ if (!PnPWaitAck(busNumber, interface, ioLocation))
+ {
+ //
+ // Return sommething invalid if it timed out.
+ //
+
+ MadgePrint1("Timeout 3\n");
+
+ return 0xff;
+ }
+
+ //
+ // Set data 'INPUT' mode.
+ //
+
+ PnPClrEEDEN(busNumber, interface, ioLocation);
+
+ //
+ // Now read the serial data - MSB first.
+ //
+
+ for (i = 0; i < 8 ;i++)
+ {
+ PnPSetClk(busNumber, interface, ioLocation);
+
+ temp = PnPReadCtrl(busNumber, interface, ioLocation);
+
+ PnPClrClk(busNumber, interface, ioLocation);
+
+ temp &= PNP_EEDO;
+ temp = temp >> 1;
+ dataByte = dataByte << 1;
+ dataByte &= 0xfffe;
+ dataByte |= temp;
+ }
+
+ if (!PnPDummyWaitAck(busNumber, interface, ioLocation))
+ {
+ //
+ // Return something invalid if it timed out.
+ //
+
+ MadgePrint1("Timeout 4\n");
+
+ return 0xff;
+ }
+
+ PnPStopBit(busNumber, interface, ioLocation);
+
+ return dataByte;
+}
+
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - CheckForCard
+|
+| Parameters - busNumber -> The number of the bus to check.
+| interface -> The interface type of the bus.
+| ioLocation -> The IO location to be checked.
+Ý irq -> Pointer to a holder for the IRQ of the
+Ý adapter.
+|
+| Purpose - Check to see if an Madge PnP card is at the specified
+| IO location.
+|
+| Returns - A card type.
+|
+---------------------------------------------------------------------------*/
+
+static ULONG
+CheckForCard(
+ ULONG busNumber,
+ INTERFACE_TYPE interface,
+ ULONG ioLocation,
+ ULONG * irq
+ )
+{
+ UCHAR byte;
+ UINT i;
+ BOOLEAN found;
+
+ MadgePrint2("CheckForCard (ioLocation=%04lx)\n", ioLocation);
+
+ //
+ // Start of by assuming that we don't know the IRQ number.
+ //
+
+ *irq = RESOURCE_UNKNOWN;
+
+ //
+ // First check that the IO range is not in use by some other
+ // device.
+ //
+
+ if (DetectCheckPortUsage(
+ interface,
+ busNumber,
+ ioLocation,
+ PNP_IO_RANGE
+ ) != STATUS_SUCCESS)
+ {
+ return SMART_NONE;
+ }
+
+ MadgePrint1("CheckForCard: DetectCheckPortUsage() OK\n");
+
+ //
+ // OK, lets see if there's a Madge PnP adapter at the specified
+ // IO location. We just check to see if we can read 'md' back from
+ // the identification register. We read the identification register
+ // up to four times to get the 'm' and then check that the next
+ // byte is a 'd'.
+ //
+
+ found = FALSE;
+
+ for (i = 0; i < 4 && !found; i++)
+ {
+ if (DetectReadPortUchar(
+ interface,
+ busNumber,
+ ioLocation + PNP_ID_REGISTER,
+ &byte
+ ) != STATUS_SUCCESS)
+ {
+ return SMART_NONE;
+ }
+
+ if (byte == 'm')
+ {
+ if (DetectReadPortUchar(
+ interface,
+ busNumber,
+ ioLocation + PNP_ID_REGISTER,
+ &byte
+ ) != STATUS_SUCCESS)
+ {
+ return SMART_NONE;
+ }
+
+ if (byte == 'd')
+ {
+ found = TRUE;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ return SMART_NONE;
+ }
+
+ MadgePrint1("CheckForCard: found ID\n");
+
+ //
+ // Read the 3rd byte of the node address back. This should
+ // be 0xf6 if this is a Madge PnP adapter.
+ //
+
+ byte = PnPReadByte(
+ busNumber,
+ interface,
+ ioLocation,
+ PNP_EEPROM_NODE_ADDRESS3
+ );
+
+ MadgePrint2("CheckForCard: read node address byte = %02x\n", byte);
+
+ if (byte != MadgeNodeAddressPrefix[2])
+ {
+ return SMART_NONE;
+ }
+
+ //
+ // If we make it here we're as sure as we're ever going to be that
+ // we've found a PnP adapter. Next we'll read the configured
+ // IRQ number.
+ //
+
+ if (DetectWritePortUchar(
+ interface,
+ busNumber,
+ ioLocation + PNP_CONFIG_ADDRESS_REGISTER,
+ (UCHAR) PNP_VENDOR_CONFIG_IRQ
+ ) != STATUS_SUCCESS)
+ {
+ return SMART_NONE;
+ }
+
+
+ if (DetectReadPortUchar(
+ interface,
+ busNumber,
+ ioLocation + PNP_CONFIG_DATA_REGISTER,
+ &byte
+ ) != STATUS_SUCCESS)
+ {
+ return SMART_NONE;
+ }
+
+ *irq = byte;
+
+ MadgePrint2("CheckForCard: read IRQ byte = %d\n", byte);
+
+ //
+ // And return the adapter type found.
+ //
+
+ return SMART_PNP;
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - FindPnPCard
+|
+| Parameters - adapterNumber -> Adapter type index used to index the
+| global array SearchStates.
+| busNumber -> The number of the bus to search.
+| interface -> The interface type of the bus.
+| first -> TRUE if this is the first call for
+| a given adapter type.
+| type -> The type of adapter to find.
+| confidence -> Pointer a holder for the confidence in
+| which the adapter was found.
+|
+| Purpose - Search the specified bus for an adapter of the
+| specified type. If first is TRUE then the search
+| starts from the first possible IO location. If first is
+| FALSE then the search starts from one after the last
+| IO location checked the previous time FindPnPCard was called.
+|
+| Returns - A WINERROR.H error code.
+|
+|--------------------------------------------------------------------------*/
+
+static ULONG
+FindPnPCard(
+ ULONG adapterNumber,
+ ULONG busNumber,
+ INTERFACE_TYPE interface,
+ BOOLEAN first,
+ ULONG type,
+ ULONG * confidence
+ )
+{
+ //
+ // If this is the first call then we want to start from the
+ // first possible IO location.
+ //
+
+ if (first)
+ {
+ SearchStates[adapterNumber].IoLocationIndex = 0;
+ }
+
+ //
+ // Otherwise we want to start from 1 after were we left off
+ // last time.
+ //
+
+ else
+ {
+ SearchStates[adapterNumber].IoLocationIndex++;
+ }
+
+ //
+ // Step through the IO locations in the bus for which there aren't
+ // already Madge adapters installed looking for one with the
+ // required adapter type. If we don't find one we will return a
+ // confidence level of zero. (Note we check that there isn't a
+ // Madge adapter at the IO location first to avoid trashing a
+ // working adapter.)
+ //
+
+ *confidence = 0;
+
+ while (SearchStates[adapterNumber].IoLocationIndex <
+ sizeof(PnPIoLocations) / sizeof(ULONG))
+ {
+ if (!MadgeCardAlreadyInstalled(
+ FALSE,
+ busNumber,
+ PnPIoLocations[SearchStates[adapterNumber].IoLocationIndex]
+ ))
+ {
+ if (CheckForCard(
+ busNumber,
+ interface,
+ PnPIoLocations[SearchStates[adapterNumber].IoLocationIndex],
+ &SearchStates[adapterNumber].Irq
+ ) == type)
+ {
+ *confidence = 100;
+ break;
+ }
+ }
+
+ SearchStates[adapterNumber].IoLocationIndex++;
+ }
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgePnPIdentifyHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* buffer -> Buffer for the results.
+* bufferSize -> Size of the buffer in WCHARs.
+*
+* Purpose - Return information about a type of adapter that this module
+* supports.
+*
+* Returns - A WINERROR.H error code. ERROR_NO_MORE_ITEMS
+* is returned if index refers to an adapter type not
+* supported.
+*
+****************************************************************************/
+
+LONG
+MadgePnPIdentifyHandler(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ LONG numberOfAdapters;
+ LONG action;
+ LONG length;
+ LONG i;
+
+ MadgePrint2("MadgePnPIdentifyHandler (index = %ld)\n", index);
+
+ //
+ // Do some initialisation.
+ //
+
+ numberOfAdapters = sizeof(Adapters) / sizeof(ADAPTER_INFO);
+ action = index % 100;
+ index = index - action;
+
+ //
+ // Check that index does not exceed the number of adapters we
+ // support.
+ //
+
+ if ((index - 1000) / 100 >= numberOfAdapters)
+ {
+ return ERROR_NO_MORE_ITEMS;
+ }
+
+ //
+ // If index refers to an adapter type supported then carry out the
+ // requested action.
+ //
+
+ for (i = 0; i < numberOfAdapters; i++)
+ {
+ if (Adapters[i].Index == index)
+ {
+ switch (action)
+ {
+ //
+ // Return the adapter's abbreviation.
+ //
+
+ case 0:
+
+ length = UnicodeStrLen(Adapters[i].InfId) + 1;
+
+ if (bufferSize < length)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ memcpy(
+ (VOID *) buffer,
+ Adapters[i].InfId,
+ length * sizeof(WCHAR)
+ );
+
+ break;
+
+ //
+ // Return the adapter's description.
+ //
+
+ case 1:
+
+ length = UnicodeStrLen(Adapters[i].CardDescription) + 1;
+
+ if (bufferSize < length)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ memcpy(
+ (VOID *) buffer,
+ Adapters[i].CardDescription,
+ length * sizeof(WCHAR)
+ );
+
+ break;
+
+ //
+ // Return the adapter's manufacturer.
+ //
+
+ case 2:
+
+ length = UnicodeStrLen(Adapters[i].Manufacturer) + 1;
+
+ if (bufferSize < length)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ memcpy(
+ (VOID *) buffer,
+ Adapters[i].Manufacturer,
+ length * sizeof(WCHAR)
+ );
+
+ break;
+
+ //
+ // Return the search order.
+ //
+
+ case 3:
+
+ if (bufferSize < 5)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ wsprintfW(
+ (VOID *) buffer,
+ L"%d",
+ Adapters[i].SearchOrder
+ );
+
+ break;
+
+ //
+ // Anything else is invalid.
+ //
+
+ default:
+
+ return ERROR_INVALID_PARAMETER;
+
+ }
+
+ return NO_ERROR;
+ }
+ }
+
+ //
+ // We didn't find an adapter type that matched the index so
+ // return an error.
+ //
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgePnPFirstNextHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* interface -> The NT interface type (ISA, EISA etc).
+* busNumber -> The bus number to search.
+* first -> TRUE if the search of this bus should start
+* from scratch.
+* token -> Pointer to holder for a token that identifies
+* the adapter found.
+* confidence -> Pointer to a holder for the confidence by
+* which the adapter has been found.
+*
+* Purpose - Attempts to find an adapter on the specified bus. If first
+* is TRUE then the search starts from scratch. Otherwise
+* the search starts from where it left of the last time we
+* were called.
+*
+* Returns - A WINERROR.H error code. A return code of NO_ERROR
+* and a *confidence of 0 means we didn't find an adapter.
+*
+****************************************************************************/
+
+LONG
+MadgePnPFirstNextHandler(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ BOOL first,
+ VOID * * token,
+ LONG * confidence
+ )
+{
+ LONG adapterNumber;
+ ULONG retCode;
+
+ MadgePrint2("MadgePnPFirstNextHandler (index = %ld)\n", index);
+
+ //
+ // Check the interface type (could be an ISA adapter in an EISA bus).
+ //
+
+ if (interface != Isa && interface != Eisa)
+ {
+ *confidence = 0;
+ return NO_ERROR;
+ }
+
+ //
+ // Work out and validate the adapter type being searched for.
+ //
+
+ adapterNumber = (index - 1000) / 100;
+
+ if (adapterNumber < 0 ||
+ adapterNumber >= sizeof(Adapters) / sizeof(ADAPTER_INFO) ||
+ (index % 100) != 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Type to find an adapter.
+ //
+
+ retCode = FindPnPCard(
+ (ULONG) adapterNumber,
+ busNumber,
+ interface,
+ (BOOLEAN) first,
+ (ULONG) index,
+ confidence
+ );
+
+ if (retCode == NO_ERROR)
+ {
+ //
+ // In this module I use the token as follows: Remember that
+ // the token can only be 2 bytes long (the low 2) because of
+ // the interface to the upper part of this DLL.
+ //
+ // The rest of the high byte is the the bus number.
+ // The low byte is the driver index number into Adapters.
+ //
+ // NOTE: This presumes that there are < 129 buses in the
+ // system. Is this reasonable?
+ //
+
+ *token = (VOID *) ((busNumber & 0x7F) << 8);
+ *token = (VOID *) (((ULONG) *token) | (adapterNumber << 1));
+
+ if (interface == Eisa)
+ {
+ *token = (VOID *) (((ULONG) *token) | 1);
+ }
+ }
+
+ return retCode;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgePnPOpenHandleHandler
+*
+* Parameters - token -> Pointer to holder for a token that identifies
+* an adapter found by FirstNextHandler.
+* handle -> Pointer to a holder a handle the caller
+* should use to query the adapter refered to
+* by *token.
+*
+* Purpose - Generates a handle for an adapter just found by a call
+* to FirstNextHandler.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgePnPOpenHandleHandler(
+ VOID * token,
+ VOID * * handle
+ )
+{
+ PNP_ADAPTER * adapter;
+ ULONG adapterNumber;
+ ULONG busNumber;
+ INTERFACE_TYPE interface;
+
+ MadgePrint1("MadgePnPOpenHandleHandler\n");
+
+ //
+ // Get info from the token.
+ //
+
+ busNumber = (ULONG) (((ULONG) token >> 8) & 0x7F);
+ adapterNumber = (((ULONG) token) & 0xFF) >> 1;
+
+ MadgePrint2("adapterNumber = %ld\n", adapterNumber);
+
+ if ((((ULONG) token) & 1) == 1)
+ {
+ interface = Eisa;
+ }
+ else
+ {
+ interface = Isa;
+ }
+
+ //
+ // Allocate a structure for the details of the adapter.
+ //
+
+ adapter = (PNP_ADAPTER *) DetectAllocateHeap(sizeof(PNP_ADAPTER));
+
+ if (adapter == NULL)
+ {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // Copy the details.
+ //
+
+ adapter->Found = TRUE;
+ adapter->CardType = Adapters[adapterNumber].Index;
+ adapter->InterfaceType = interface;
+ adapter->BusNumber = busNumber;
+ adapter->IoLocation =
+ PnPIoLocations[SearchStates[adapterNumber].IoLocationIndex];
+ adapter->Dma = 0; // PnP's are always in PIO mode.
+ adapter->Irq = SearchStates[adapterNumber].Irq;
+
+ *handle = (VOID *) adapter;
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgePnPCreateHandleHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* interface -> NT interface type (Eisa, Isa etc).
+* busNumber -> Number of the bus containing the adapter.
+* handle -> Pointer to a holder a handle the caller
+* should use to query the adapter.
+*
+* Purpose - Generates a handle for an adapter that has not been detected
+* but the caller claims exists.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgePnPCreateHandleHandler(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ VOID * * handle
+ )
+{
+ PNP_ADAPTER * adapter;
+ LONG numberOfAdapters;
+ LONG i;
+
+ MadgePrint2("MadgePnPCreateHandleHandler (index = %ld)\n", index);
+
+ //
+ // Check that the interface type is correct for this module
+ // (could be an Isa adapter in an Eisa slot).
+ //
+
+ if (interface != Isa && interface != Eisa)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // If the index is valid then create a handle.
+ //
+
+ numberOfAdapters = sizeof(Adapters) / sizeof(ADAPTER_INFO);
+
+ for (i = 0; i < numberOfAdapters; i++)
+ {
+ if (Adapters[i].Index == index)
+ {
+ //
+ // Allocate a structure for the adapter details.
+ //
+
+ adapter = (PNP_ADAPTER *) DetectAllocateHeap(sizeof(PNP_ADAPTER));
+
+ if (adapter == NULL)
+ {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // Copy the details.
+ //
+
+ adapter->Found = FALSE;
+ adapter->CardType = index;
+ adapter->InterfaceType = interface;
+ adapter->BusNumber = busNumber;
+ adapter->IoLocation = PnPIoLocations[0];
+ adapter->Dma = 0; // PnP's are always in PIO mode.
+ adapter->Irq = RESOURCE_UNKNOWN;
+
+ *handle = (VOID *) adapter;
+
+ return NO_ERROR;
+ }
+ }
+
+ //
+ // We didn't find an adapter type that matched the one the caller
+ // claims exists so return an error.
+ //
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgePnPCloseHandleHandler
+*
+* Parameters - handle -> Handle to be closed.
+*
+* Purpose - Closes a previously opened or created handle.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgePnPCloseHandleHandler(
+ VOID * handle
+ )
+{
+ MadgePrint1("MadgePnPCloseHandleHandler\n");
+
+ DetectFreeHeap(handle);
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgePnPQueryCfgHandler
+*
+* Parameters - handle -> Handle to for the adapter to be queried.
+* buffer -> Buffer for the returned parameters.
+* bufferSize -> Size of the buffer in WCHARs.
+*
+* Purpose - Find out what the parameters are for the adapter identified
+* by the handle. This function does not assume that the
+* adapter described by the handle is valid if the handle
+* was created rather than being opened. If the handle
+* was created then a search is made for an adapter.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgePnPQueryCfgHandler(
+ VOID * handle,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ PNP_ADAPTER * adapter;
+ ULONG confidence;
+ LONG adapterNumber;
+ LONG retCode;
+
+ MadgePrint1("MadgePnPQueryCfgHandler\n");
+
+ //
+ // Do some initialisation.
+ //
+
+ adapter = (PNP_ADAPTER *) handle;
+
+ //
+ // Check that the interface type specified by the handle is
+ // valid for this module (could be an Isa card in an Eisa slot).
+ //
+
+ if (adapter->InterfaceType != Isa && adapter->InterfaceType != Eisa)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // If the adapter was created rather than being opened we must search
+ // for an adapter.
+ //
+
+ if (!adapter->Found)
+ {
+ adapterNumber = (adapter->CardType - 1000) / 100;
+
+ retCode = FindPnPCard(
+ adapterNumber,
+ adapter->BusNumber,
+ adapter->InterfaceType,
+ TRUE,
+ adapter->CardType,
+ &confidence
+ );
+
+ //
+ // If we are not 100% sure that we found an adapter with
+ // the right ID we give up.
+ //
+
+ if (retCode != NO_ERROR || confidence != 100)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ adapter->Found = TRUE;
+ adapter->IoLocation =
+ PnPIoLocations[SearchStates[adapterNumber].IoLocationIndex];
+ adapter->Dma = 0; // PnP's are always in PIO mode.
+ adapter->Irq = SearchStates[adapterNumber].Irq;
+ }
+
+ //
+ // Build resulting buffer.
+ //
+ // Copy in the IO location.
+ //
+
+ if (AppendParameter(
+ &buffer,
+ &bufferSize,
+ IoAddrString,
+ adapter->IoLocation
+ ) != NO_ERROR)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ //
+ // Copy in the DMA channel.
+ //
+
+ if (AppendParameter(
+ &buffer,
+ &bufferSize,
+ DmaChanString,
+ adapter->Dma
+ ) != NO_ERROR)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ //
+ // Copy in the IRQ number.
+ //
+
+ if (AppendParameter(
+ &buffer,
+ &bufferSize,
+ IrqString,
+ adapter->Irq
+ ) != NO_ERROR)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ //
+ // Copy in the multiprocessor flag.
+ //
+
+ if (AppendParameter(
+ &buffer,
+ &bufferSize,
+ MultiprocessorString,
+ IsMultiprocessor()
+ ) != NO_ERROR)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ //
+ // Copy in final \0.
+ //
+
+ if (bufferSize < 1)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ *buffer = L'\0';
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgePnPVerifyCfgHandler
+*
+* Parameters - handle -> Handle to for the adapter to be verified.
+* buffer -> Buffer containing the returned parameters.
+*
+* Purpose - Verify that the parameters in buffer are correct for
+* the adapter identified by handle.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgePnPVerifyCfgHandler(
+ VOID * handle,
+ WCHAR * buffer
+ )
+{
+ PNP_ADAPTER * adapter;
+ WCHAR * place;
+ BOOLEAN found;
+ ULONG ioLocation;
+ ULONG dmaChannel;
+ ULONG irqNumber;
+ ULONG multiprocessor;
+ LONG adapterNumber;
+
+ MadgePrint1("MadgePnPVerifyCfgHandler\n");
+
+ //
+ // Do some initialisation.
+ //
+
+ adapter = (PNP_ADAPTER *) handle;
+ adapterNumber = (adapter->CardType - 1000) / 100;
+
+ //
+ // Check that the interface type is correct for this module
+ // (could be an Isa adapter in an Eisa slot).
+ //
+
+ if (adapter->InterfaceType != Isa && adapter->InterfaceType != Eisa)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // Parse the parameters.
+ //
+
+ //
+ // Get the IO location.
+ //
+
+ place = FindParameterString(buffer, IoAddrString);
+
+ if (place == NULL)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ place += UnicodeStrLen(IoAddrString) + 1;
+
+ ScanForNumber(place, &ioLocation, &found);
+
+ if (!found)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // Get the DMA channel.
+ //
+
+ place = FindParameterString(buffer, DmaChanString);
+
+ if (place == NULL)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ place += UnicodeStrLen(DmaChanString) + 1;
+
+ ScanForNumber(place, &dmaChannel, &found);
+
+ if (!found)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // Get the IRQ number.
+ //
+
+ place = FindParameterString(buffer, IrqString);
+
+ if (place == NULL)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ place += UnicodeStrLen(IrqString) + 1;
+
+ ScanForNumber(place, &irqNumber, &found);
+
+ if (!found)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // Get the multiprocessor flag.
+ //
+
+ place = FindParameterString(buffer, MultiprocessorString);
+
+ if (place == NULL)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ place += UnicodeStrLen(MultiprocessorString) + 1;
+
+ //
+ // Now parse the value.
+ //
+
+ ScanForNumber(place, &multiprocessor, &found);
+
+ //
+ // If the handle does not refer to an adapter that has been found
+ // by search we must query the hardware.
+ //
+
+ if (!adapter->Found)
+ {
+ if (CheckForCard(
+ adapter->BusNumber,
+ adapter->InterfaceType,
+ ioLocation,
+ &adapter->Irq
+ ) != adapter->CardType)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ adapter->IoLocation = ioLocation;
+ adapter->Dma = 0; // PnP's are always in PIO mode.
+ adapter->Found = TRUE;
+ }
+
+ //
+ // Verify the parameters.
+ //
+
+ if (ioLocation != adapter->IoLocation ||
+ multiprocessor != IsMultiprocessor())
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ if (adapter->Dma == RESOURCE_UNKNOWN)
+ {
+ if (!IsValueInList(dmaChannel, ParamRange[adapterNumber].DmaRange))
+ {
+ return ERROR_INVALID_DATA;
+ }
+ }
+ else if (adapter->Dma != dmaChannel)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ if (adapter->Irq == RESOURCE_UNKNOWN)
+ {
+ if (!IsValueInList(irqNumber, ParamRange[adapterNumber].IrqRange))
+ {
+ return ERROR_INVALID_DATA;
+ }
+ }
+ else if (adapter->Irq != irqNumber)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // If we make it to here everything checked out ok.
+ //
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgePnPQueryMaskHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* buffer -> Buffer for the returned parameters.
+* bufferSize -> Size of buffer in WCHARs.
+*
+* Purpose - Return the list of parameters required for the adapter
+* type specified by index.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgePnPQueryMaskHandler(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ WCHAR * params;
+ LONG length;
+ LONG numberOfAdapters;
+ LONG i;
+
+ MadgePrint2("MadgePnPQueryMaskHandler (index = %ld)\n", index);
+ MadgePrint2("BufferSize = %ld\n", bufferSize);
+
+ //
+ // Find the adapter type.
+ //
+
+ numberOfAdapters = sizeof(Adapters) / sizeof(ADAPTER_INFO);
+
+ for (i = 0; i < numberOfAdapters; i++)
+ {
+ if (Adapters[i].Index == index)
+ {
+ params = Adapters[i].Parameters;
+
+ //
+ // Find the string length (Ends with 2 NULLs)
+ //
+
+ for (length = 0; ; length++)
+ {
+ if (params[length] == L'\0')
+ {
+ length++;
+
+ if (params[length] == L'\0')
+ {
+ break;
+ }
+ }
+ }
+
+ length++;
+
+ MadgePrint2("length = %ld\n", length);
+
+ //
+ // Copy the parameters into buffer.
+ //
+
+ if (bufferSize < length)
+ {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ memcpy((VOID *) buffer, params, length * sizeof(WCHAR));
+
+ return NO_ERROR;
+ }
+ }
+
+ //
+ // If we make it here we did not find a valid adapter type so
+ // return and error.
+ //
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgePnPParamRangeHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* param -> Paramter being queried.
+* buffer -> Buffer for the returned parameters.
+* bufferSize -> Size of buffer in LONGs.
+*
+* Purpose - Return the list of acceptable values for the parameter
+* specified.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgePnPParamRangeHandler(
+ LONG index,
+ WCHAR * param,
+ LONG * buffer,
+ LONG * bufferSize
+ )
+{
+ LONG i;
+ LONG adapterNumber;
+ LONG count;
+
+ MadgePrint2("MadgePnPParamRangeHandler (index=%ld)\n", index);
+
+ //
+ // Work out and validate the adapter number.
+ //
+
+ adapterNumber = (index - 1000) / 100;
+
+ if (adapterNumber < 0 ||
+ adapterNumber >= sizeof(Adapters) / sizeof(ADAPTER_INFO) ||
+ (index % 100) != 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // The simplest parameter is the IO location because this is the
+ // same for all of the adapter types.
+ //
+
+ if (UnicodeStringsEqual(param, IoAddrString))
+ {
+ count = sizeof(PnPIoLocations) / sizeof(ULONG);
+
+ if (*bufferSize < count)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ buffer[i] = PnPIoLocations[i];
+ }
+
+ *bufferSize = count;
+
+ return NO_ERROR;
+ }
+
+ //
+ // IRQ number is slightly more complicated because it is different
+ // for different adapter types.
+ //
+
+ else if (UnicodeStringsEqual(param, IrqString))
+ {
+ count = 0;
+
+ while (ParamRange[adapterNumber].IrqRange[count] != END_OF_LIST)
+ {
+ count++;
+ }
+
+ if (*bufferSize < count)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ buffer[i] = ParamRange[adapterNumber].IrqRange[i];
+ }
+
+ *bufferSize = count;
+
+ return NO_ERROR;
+ }
+
+
+ //
+ // Likewise DMA channel.
+ //
+
+ else if (UnicodeStringsEqual(param, DmaChanString))
+ {
+ count = 0;
+
+ while (ParamRange[adapterNumber].DmaRange[count] != END_OF_LIST)
+ {
+ count++;
+ }
+
+ if (*bufferSize < count)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ buffer[i] = ParamRange[adapterNumber].DmaRange[i];
+ }
+
+ *bufferSize = count;
+
+ return NO_ERROR;
+ }
+
+ //
+ // Or fill in the allowable values for the multiprocessor flag.
+ //
+
+ else if (UnicodeStringsEqual(param, MultiprocessorString))
+ {
+ if (*bufferSize < 2)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ *bufferSize = 2;
+
+ buffer[0] = 0;
+ buffer[1] = 1;
+
+ return NO_ERROR;
+ }
+
+ //
+ // If we reach this point we have been passed a parameter we
+ // don't know about.
+ //
+
+ return ERROR_INVALID_DATA;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgePnPQueryParameterNameHandler
+*
+* Parameters - param -> Paramter being queried.
+* buffer -> Buffer for the returned name.
+* bufferSize -> Size of buffer in WCHARs.
+*
+* Purpose - Return the name of a parameter.
+*
+* Returns - ERROR_INVALID_PARAMETER to cause the caller to use
+* the Microsoft provided default names.
+*
+****************************************************************************/
+
+LONG
+MadgePnPQueryParameterNameHandler(
+ WCHAR * param,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/********* End of MDGPNP.C *************************************************/
+
diff --git a/private/ntos/ndis/madge/detect/mdgsm16.c b/private/ntos/ndis/madge/detect/mdgsm16.c
new file mode 100644
index 000000000..bbaabc051
--- /dev/null
+++ b/private/ntos/ndis/madge/detect/mdgsm16.c
@@ -0,0 +1,1495 @@
+/****************************************************************************
+*
+* MDGSM16.C
+*
+* Smart 16 Adapter Detection Module
+*
+* Copyright (c) Madge Networks Ltd 1994
+*
+* COMPANY CONFIDENTIAL - RELEASED TO MICROSOFT CORP. ONLY FOR DEVELOPMENT
+* OF WINDOWS95 NETCARD DETECTION - THIS SOURCE IS NOT TO BE RELEASED OUTSIDE
+* OF MICROSOFT WITHOUT EXPLICIT WRITTEN PERMISSION FROM AN AUTHORISED
+* OFFICER OF MADGE NETWORKS LTD.
+*
+* Created: PBA 12/09/1994
+*
+****************************************************************************/
+
+#include <ntddk.h>
+#include <ntddnetd.h>
+
+#include <windef.h>
+#include <winerror.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mdgncdet.h"
+
+//
+// Prototype "borrowed" from WINUSER.H
+//
+
+extern int WINAPIV wsprintfW(LPWSTR, LPCWSTR, ...);
+
+
+/*---------------------------------------------------------------------------
+|
+| Smart16 adapter types. These correspond to the indexes that the upper layers
+| use for identifying adapters, so change them with care.
+|
+|--------------------------------------------------------------------------*/
+
+#define SMART_NONE 0
+#define SMART_SM16 1000
+
+
+/*---------------------------------------------------------------------------
+|
+| IO locations that Smart16 adapters can be at. The second for are
+| REV3 only locations that are normally specified as one of the first
+| four locations with the ALTERNATE flag set.
+|
+---------------------------------------------------------------------------*/
+
+static
+ULONG Sm16IoLocations[4] =
+ {0x4a20, 0x4e20, 0x6a20, 0x6e20};
+
+
+/*---------------------------------------------------------------------------
+|
+| Various Smart16 card specific constants.
+|
+---------------------------------------------------------------------------*/
+
+#define SM16_IO_RANGE 32
+
+#define SM16_CONTROL_REGISTER_1 0
+#define SM16_CONTROL_REGISTER_2 8
+
+
+/*---------------------------------------------------------------------------
+|
+| First three bytes of a Madge node address.
+|
+|---------------------------------------------------------------------------*/
+
+static
+UCHAR MadgeNodeAddressPrefix[3] =
+ {0x00, 0x00, 0xf6};
+
+
+/*---------------------------------------------------------------------------
+|
+| List of adapter types supported by this module.
+|
+|---------------------------------------------------------------------------*/
+
+static
+ADAPTER_INFO Adapters[] =
+{
+ {
+ SMART_SM16,
+ MDGSM16,
+ L"Madge Smart 16 Ringnode",
+ L"Madge Networks",
+ L"IOLOCATION\0"
+ L"000\0"
+ L"00100\0"
+ L"DMACHANNEL\0"
+ L"000\0"
+ L"00100\0"
+ L"INTERRUPTNUMBER\0"
+ L"000\0"
+ L"000\0"
+ L"MULTIPROCESSOR\0"
+ L"000\0"
+ L"00100\0",
+ NULL,
+ 901
+ }
+};
+
+
+/*---------------------------------------------------------------------------
+|
+| Madge specific parameter range information. The order entries in this
+| table MUST match that in the Adapters table above. The first value
+Ý in each list is the default.
+|
+---------------------------------------------------------------------------*/
+
+static
+struct
+{
+ ULONG IrqRange[4];
+ ULONG DmaRange[2];
+}
+ParamRange[] =
+{
+ //
+ // Smart16.
+ //
+
+ {
+ { 3, 2, 7, END_OF_LIST},
+ { 0, END_OF_LIST}
+ }
+};
+
+
+/*---------------------------------------------------------------------------
+|
+| Structure for holding state of a search.
+|
+|--------------------------------------------------------------------------*/
+
+typedef struct
+{
+ ULONG IoLocationIndex;
+}
+SM16_SEARCH_STATE;
+
+
+/*---------------------------------------------------------------------------
+|
+| This is an array of search states. We need one state for each type
+| of adapter supported.
+|
+|--------------------------------------------------------------------------*/
+
+static
+SM16_SEARCH_STATE SearchStates[sizeof(Adapters) / sizeof(ADAPTER_INFO)] = {0};
+
+
+/*---------------------------------------------------------------------------
+|
+| Structure for holding a particular adapter's complete information.
+|
+|--------------------------------------------------------------------------*/
+
+typedef struct
+{
+ BOOLEAN Found;
+ ULONG CardType;
+ ULONG BusNumber;
+ INTERFACE_TYPE InterfaceType;
+ ULONG IoLocation;
+ ULONG Dma;
+ ULONG Irq;
+}
+SM16_ADAPTER;
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - CheckForCard
+|
+| Parameters - busNumber -> The number of the bus to check.
+| interface -> The interface type of the bus.
+| ioLocation -> The IO location to be checked.
+|
+| Purpose - Check to see if an Madge Smart16 card is at the specified
+| IO location.
+|
+| Returns - A card type.
+|
+---------------------------------------------------------------------------*/
+
+static ULONG
+CheckForCard(
+ ULONG busNumber,
+ INTERFACE_TYPE interface,
+ ULONG ioLocation
+ )
+{
+ UCHAR byte;
+ ULONG dword;
+ UINT i;
+ UINT j;
+
+ MadgePrint2("CheckForCard (ioLocation=%04lx)\n", ioLocation);
+
+ //
+ // First check that the IO range is not in use by some other
+ // device.
+ //
+
+ if (DetectCheckPortUsage(
+ interface,
+ busNumber,
+ ioLocation,
+ SM16_IO_RANGE
+ ) != STATUS_SUCCESS)
+ {
+ return SMART_NONE;
+ }
+
+ MadgePrint1("CheckForCard: DetectCheckPortUsage() OK\n");
+
+ //
+ // Now we must reset the adapter (if it's there).
+ //
+
+ if (DetectWritePortUchar(
+ interface,
+ busNumber,
+ ioLocation + SM16_CONTROL_REGISTER_1,
+ 0
+ ) != STATUS_SUCCESS)
+ {
+ return SMART_NONE;
+ }
+
+ MadgePrint1("CheckForCard: Reset Smart16 OK\n");
+
+ //
+ // Now read and check the node address. The Smart16 does not store
+ // the two leading 0 bytes of the address so we can only really
+ // check the 0xf6; but we read the whole node address to make sure
+ // we can.
+ //
+ // The node address is stored in some wierd sort of EEPROM that
+ // is read by writing a byte number into control register 2 and
+ // then reading the bits of the byte in pairs from IO locations
+ // 8 appart. i.e. bits 7 and 6 come from the base IO location,
+ // bits 5 and 4 from the base IO location plus 8 and so on.
+ //
+
+ dword = 0;
+
+ for (i = 0; i < 4; i++)
+ {
+ if (DetectWritePortUchar(
+ interface,
+ busNumber,
+ ioLocation + SM16_CONTROL_REGISTER_2,
+ (UCHAR) i) != STATUS_SUCCESS)
+ {
+ return SMART_NONE;
+ }
+
+ for (j = 0; j < 4; j++)
+ {
+ if (DetectReadPortUchar(
+ interface,
+ busNumber,
+ ioLocation + j * 8,
+ &byte
+ ) != STATUS_SUCCESS)
+ {
+ return SMART_NONE;
+ }
+
+ dword = (dword << 2) | (byte & 0x03);
+ }
+ }
+
+ MadgePrint2("CheckForCard: node address = %lx\n", dword);
+
+ //
+ // Check that the first byte of the node address read is
+ // correct for a Madge adapter. We also check that the rest
+ // of the address isn't all 1s or all 0s just to be on the
+ // safe side.
+ //
+
+ if (((dword >> 24) & 0x000000ffL) != MadgeNodeAddressPrefix[2] ||
+ (dword & 0x00ffffffL) == 0x00ffffffL ||
+ (dword & 0x00ffffffL) == 0x00000000L)
+ {
+ return SMART_NONE;
+ }
+
+ MadgePrint1("CheckForCard: Read node address OK\n");
+
+ //
+ // If we make it here we're as sure as we're ever going to be that
+ // we've found a Smart16 adapter.
+
+ return SMART_SM16;
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - FindSm16Card
+|
+| Parameters - adapterNumber -> Adapter type index used to index the
+| global array SearchStates.
+| busNumber -> The number of the bus to search.
+| interface -> The interface type of the bus.
+| first -> TRUE if this is the first call for
+| a given adapter type.
+| type -> The type of adapter to find.
+| confidence -> Pointer a holder for the confidence in
+| which the adapter was found.
+|
+| Purpose - Search the specified bus for an adapter of the
+| specified type. If first is TRUE then the search
+| starts from the first possible IO location. If first is
+| FALSE then the search starts from one after the last
+| IO location checked the previous time FindSm16Card was called.
+|
+| Returns - A WINERROR.H error code.
+|
+|--------------------------------------------------------------------------*/
+
+static ULONG
+FindSm16Card(
+ ULONG adapterNumber,
+ ULONG busNumber,
+ INTERFACE_TYPE interface,
+ BOOLEAN first,
+ ULONG type,
+ ULONG * confidence
+ )
+{
+ //
+ // If this is the first call then we want to start from the
+ // first possible IO location.
+ //
+
+ if (first)
+ {
+ SearchStates[adapterNumber].IoLocationIndex = 0;
+ }
+
+ //
+ // Otherwise we want to start from 1 after were we left off
+ // last time.
+ //
+
+ else
+ {
+ SearchStates[adapterNumber].IoLocationIndex++;
+ }
+
+ //
+ // Step through the IO locations in the bus for which there aren't
+ // already Madge adapters installed looking for one with the
+ // required adapter type. If we don't find one we will return a
+ // confidence level of zero. (Note we check that there isn't a
+ // Madge adapter at the IO location first to avoid trashing a
+ // working adapter.)
+ //
+
+ *confidence = 0;
+
+ while (SearchStates[adapterNumber].IoLocationIndex <
+ sizeof(Sm16IoLocations) / sizeof(ULONG))
+ {
+ if (!MadgeCardAlreadyInstalled(
+ FALSE,
+ busNumber,
+ Sm16IoLocations[SearchStates[adapterNumber].IoLocationIndex]
+ ))
+ {
+ if (CheckForCard(
+ busNumber,
+ interface,
+ Sm16IoLocations[SearchStates[adapterNumber].IoLocationIndex]
+ ) == type)
+ {
+ *confidence = 100;
+ break;
+ }
+ }
+
+ SearchStates[adapterNumber].IoLocationIndex++;
+ }
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeSm16IdentifyHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* buffer -> Buffer for the results.
+* bufferSize -> Size of the buffer in WCHARs.
+*
+* Purpose - Return information about a type of adapter that this module
+* supports.
+*
+* Returns - A WINERROR.H error code. ERROR_NO_MORE_ITEMS
+* is returned if index refers to an adapter type not
+* supported.
+*
+****************************************************************************/
+
+LONG
+MadgeSm16IdentifyHandler(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ LONG numberOfAdapters;
+ LONG action;
+ LONG length;
+ LONG i;
+
+ MadgePrint2("MadgeSm16IdentifyHandler (index = %ld)\n", index);
+
+ //
+ // Do some initialisation.
+ //
+
+ numberOfAdapters = sizeof(Adapters) / sizeof(ADAPTER_INFO);
+ action = index % 100;
+ index = index - action;
+
+ //
+ // Check that index does not exceed the number of adapters we
+ // support.
+ //
+
+ if ((index - 1000) / 100 >= numberOfAdapters)
+ {
+ return ERROR_NO_MORE_ITEMS;
+ }
+
+ //
+ // If index refers to an adapter type supported then carry out the
+ // requested action.
+ //
+
+ for (i = 0; i < numberOfAdapters; i++)
+ {
+ if (Adapters[i].Index == index)
+ {
+ switch (action)
+ {
+ //
+ // Return the adapter's abbreviation.
+ //
+
+ case 0:
+
+ length = UnicodeStrLen(Adapters[i].InfId) + 1;
+
+ if (bufferSize < length)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ memcpy(
+ (VOID *) buffer,
+ Adapters[i].InfId,
+ length * sizeof(WCHAR)
+ );
+
+ break;
+
+ //
+ // Return the adapter's description.
+ //
+
+ case 1:
+
+ length = UnicodeStrLen(Adapters[i].CardDescription) + 1;
+
+ if (bufferSize < length)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ memcpy(
+ (VOID *) buffer,
+ Adapters[i].CardDescription,
+ length * sizeof(WCHAR)
+ );
+
+ break;
+
+ //
+ // Return the adapter's manufacturer.
+ //
+
+ case 2:
+
+ length = UnicodeStrLen(Adapters[i].Manufacturer) + 1;
+
+ if (bufferSize < length)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ memcpy(
+ (VOID *) buffer,
+ Adapters[i].Manufacturer,
+ length * sizeof(WCHAR)
+ );
+
+ break;
+
+ //
+ // Return the search order.
+ //
+
+ case 3:
+
+ if (bufferSize < 5)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ wsprintfW(
+ (VOID *) buffer,
+ L"%d",
+ Adapters[i].SearchOrder
+ );
+
+ break;
+
+ //
+ // Anything else is invalid.
+ //
+
+ default:
+
+ return ERROR_INVALID_PARAMETER;
+
+ }
+
+ return NO_ERROR;
+ }
+ }
+
+ //
+ // We didn't find an adapter type that matched the index so
+ // return an error.
+ //
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeSm16FirstNextHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* interface -> The NT interface type (ISA, EISA etc).
+* busNumber -> The bus number to search.
+* first -> TRUE if the search of this bus should start
+* from scratch.
+* token -> Pointer to holder for a token that identifies
+* the adapter found.
+* confidence -> Pointer to a holder for the confidence by
+* which the adapter has been found.
+*
+* Purpose - Attempts to find an adapter on the specified bus. If first
+* is TRUE then the search starts from scratch. Otherwise
+* the search starts from where it left of the last time we
+* were called.
+*
+* Returns - A WINERROR.H error code. A return code of NO_ERROR
+* and a *confidence of 0 means we didn't find an adapter.
+*
+****************************************************************************/
+
+LONG
+MadgeSm16FirstNextHandler(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ BOOL first,
+ VOID * * token,
+ LONG * confidence
+ )
+{
+ LONG adapterNumber;
+ ULONG retCode;
+
+ MadgePrint2("MadgeSm16FirstNextHandler (index = %ld)\n", index);
+
+ //
+ // Check the interface type (could be an ISA adapter in an EISA bus).
+ //
+
+ if (interface != Isa && interface != Eisa)
+ {
+ *confidence = 0;
+ return NO_ERROR;
+ }
+
+ //
+ // Work out and validate the adapter type being searched for.
+ //
+
+ adapterNumber = (index - 1000) / 100;
+
+ if (adapterNumber < 0 ||
+ adapterNumber >= sizeof(Adapters) / sizeof(ADAPTER_INFO) ||
+ (index % 100) != 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Type to find an adapter.
+ //
+
+ retCode = FindSm16Card(
+ (ULONG) adapterNumber,
+ busNumber,
+ interface,
+ (BOOLEAN) first,
+ (ULONG) index,
+ confidence
+ );
+
+ if (retCode == NO_ERROR)
+ {
+ //
+ // In this module I use the token as follows: Remember that
+ // the token can only be 2 bytes long (the low 2) because of
+ // the interface to the upper part of this DLL.
+ //
+ // The rest of the high byte is the the bus number.
+ // The low byte is the driver index number into Adapters.
+ //
+ // NOTE: This presumes that there are < 129 buses in the
+ // system. Is this reasonable?
+ //
+
+ *token = (VOID *) ((busNumber & 0x7F) << 8);
+ *token = (VOID *) (((ULONG) *token) | (adapterNumber << 1));
+
+ if (interface == Eisa)
+ {
+ *token = (VOID *) (((ULONG) *token) | 1);
+ }
+ }
+
+ return retCode;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeSm16OpenHandleHandler
+*
+* Parameters - token -> Pointer to holder for a token that identifies
+* an adapter found by FirstNextHandler.
+* handle -> Pointer to a holder a handle the caller
+* should use to query the adapter refered to
+* by *token.
+*
+* Purpose - Generates a handle for an adapter just found by a call
+* to FirstNextHandler.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgeSm16OpenHandleHandler(
+ VOID * token,
+ VOID * * handle
+ )
+{
+ SM16_ADAPTER * adapter;
+ ULONG adapterNumber;
+ ULONG busNumber;
+ INTERFACE_TYPE interface;
+
+ MadgePrint1("MadgeSm16OpenHandleHandler\n");
+
+ //
+ // Get info from the token.
+ //
+
+ busNumber = (ULONG) (((ULONG) token >> 8) & 0x7F);
+ adapterNumber = (((ULONG) token) & 0xFF) >> 1;
+
+ MadgePrint2("adapterNumber = %ld\n", adapterNumber);
+
+ if ((((ULONG) token) & 1) == 1)
+ {
+ interface = Eisa;
+ }
+ else
+ {
+ interface = Isa;
+ }
+
+ //
+ // Allocate a structure for the details of the adapter.
+ //
+
+ adapter = (SM16_ADAPTER *) DetectAllocateHeap(sizeof(SM16_ADAPTER));
+
+ if (adapter == NULL)
+ {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // Copy the details.
+ //
+
+ adapter->Found = TRUE;
+ adapter->CardType = Adapters[adapterNumber].Index;
+ adapter->InterfaceType = interface;
+ adapter->BusNumber = busNumber;
+ adapter->IoLocation =
+ Sm16IoLocations[SearchStates[adapterNumber].IoLocationIndex];
+ adapter->Dma = 0; // Smart16's are always in PIO mode.
+ adapter->Irq = RESOURCE_UNKNOWN;
+
+ *handle = (VOID *) adapter;
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeSm16CreateHandleHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* interface -> NT interface type (Eisa, Isa etc).
+* busNumber -> Number of the bus containing the adapter.
+* handle -> Pointer to a holder a handle the caller
+* should use to query the adapter.
+*
+* Purpose - Generates a handle for an adapter that has not been detected
+* but the caller claims exists.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgeSm16CreateHandleHandler(
+ LONG index,
+ INTERFACE_TYPE interface,
+ ULONG busNumber,
+ VOID * * handle
+ )
+{
+ SM16_ADAPTER * adapter;
+ LONG numberOfAdapters;
+ LONG i;
+
+ MadgePrint2("MadgeSm16CreateHandleHandler (index = %ld)\n", index);
+
+ //
+ // Check that the interface type is correct for this module
+ // (could be an Isa adapter in an Eisa slot).
+ //
+
+ if (interface != Isa && interface != Eisa)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // If the index is valid then create a handle.
+ //
+
+ numberOfAdapters = sizeof(Adapters) / sizeof(ADAPTER_INFO);
+
+ for (i = 0; i < numberOfAdapters; i++)
+ {
+ if (Adapters[i].Index == index)
+ {
+ //
+ // Allocate a structure for the adapter details.
+ //
+
+ adapter = (SM16_ADAPTER *) DetectAllocateHeap(sizeof(SM16_ADAPTER));
+
+ if (adapter == NULL)
+ {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // Copy the details.
+ //
+
+ adapter->Found = FALSE;
+ adapter->CardType = index;
+ adapter->InterfaceType = interface;
+ adapter->BusNumber = busNumber;
+ adapter->IoLocation = Sm16IoLocations[0];
+ adapter->Dma = 0; // Smart16's are always in PIO mode.
+ adapter->Irq = RESOURCE_UNKNOWN;
+
+ *handle = (VOID *) adapter;
+
+ return NO_ERROR;
+ }
+ }
+
+ //
+ // We didn't find an adapter type that matched the one the caller
+ // claims exists so return an error.
+ //
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeSm16CloseHandleHandler
+*
+* Parameters - handle -> Handle to be closed.
+*
+* Purpose - Closes a previously opened or created handle.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgeSm16CloseHandleHandler(
+ VOID * handle
+ )
+{
+ MadgePrint1("MadgeSm16CloseHandleHandler\n");
+
+ DetectFreeHeap(handle);
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeSm16QueryCfgHandler
+*
+* Parameters - handle -> Handle to for the adapter to be queried.
+* buffer -> Buffer for the returned parameters.
+* bufferSize -> Size of the buffer in WCHARs.
+*
+* Purpose - Find out what the parameters are for the adapter identified
+* by the handle. This function does not assume that the
+* adapter described by the handle is valid if the handle
+* was created rather than being opened. If the handle
+* was created then a search is made for an adapter.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgeSm16QueryCfgHandler(
+ VOID * handle,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ SM16_ADAPTER * adapter;
+ ULONG confidence;
+ LONG adapterNumber;
+ LONG retCode;
+
+ MadgePrint1("MadgeSm16QueryCfgHandler\n");
+
+ //
+ // Do some initialisation.
+ //
+
+ adapter = (SM16_ADAPTER *) handle;
+
+ //
+ // Check that the interface type specified by the handle is
+ // valid for this module (could be an Isa card in an Eisa slot).
+ //
+
+ if (adapter->InterfaceType != Isa && adapter->InterfaceType != Eisa)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // If the adapter was created rather than being opened we must search
+ // for an adapter.
+ //
+
+ if (!adapter->Found)
+ {
+ adapterNumber = (adapter->CardType - 1000) / 100;
+
+ retCode = FindSm16Card(
+ adapterNumber,
+ adapter->BusNumber,
+ adapter->InterfaceType,
+ TRUE,
+ adapter->CardType,
+ &confidence
+ );
+
+ //
+ // If we are not 100% sure that we found an adapter with
+ // the right ID we give up.
+ //
+
+ if (retCode != NO_ERROR || confidence != 100)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ adapter->Found = TRUE;
+ adapter->IoLocation =
+ Sm16IoLocations[SearchStates[adapterNumber].IoLocationIndex];
+ adapter->Dma = 0; // Smart16's are always in PIO mode.
+ adapter->Irq = RESOURCE_UNKNOWN;
+ }
+
+ //
+ // Build resulting buffer.
+ //
+ // Copy in the IO location.
+ //
+
+ if (AppendParameter(
+ &buffer,
+ &bufferSize,
+ IoAddrString,
+ adapter->IoLocation
+ ) != NO_ERROR)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ //
+ // Copy in the DMA channel.
+ //
+
+ if (AppendParameter(
+ &buffer,
+ &bufferSize,
+ DmaChanString,
+ adapter->Dma
+ ) != NO_ERROR)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ //
+ // Copy in the IRQ number.
+ //
+
+ if (AppendParameter(
+ &buffer,
+ &bufferSize,
+ IrqString,
+ adapter->Irq
+ ) != NO_ERROR)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ //
+ // Copy in the multiprocessor flag.
+ //
+
+ if (AppendParameter(
+ &buffer,
+ &bufferSize,
+ MultiprocessorString,
+ IsMultiprocessor()
+ ) != NO_ERROR)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ //
+ // Copy in final \0.
+ //
+
+ if (bufferSize < 1)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ *buffer = L'\0';
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeSm16VerifyCfgHandler
+*
+* Parameters - handle -> Handle to for the adapter to be verified.
+* buffer -> Buffer containing the returned parameters.
+*
+* Purpose - Verify that the parameters in buffer are correct for
+* the adapter identified by handle.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgeSm16VerifyCfgHandler(
+ VOID * handle,
+ WCHAR * buffer
+ )
+{
+ SM16_ADAPTER * adapter;
+ WCHAR * place;
+ BOOLEAN found;
+ ULONG ioLocation;
+ ULONG dmaChannel;
+ ULONG irqNumber;
+ ULONG multiprocessor;
+ LONG adapterNumber;
+
+ MadgePrint1("MadgeSm16VerifyCfgHandler\n");
+
+ //
+ // Do some initialisation.
+ //
+
+ adapter = (SM16_ADAPTER *) handle;
+ adapterNumber = (adapter->CardType - 1000) / 100;
+
+ //
+ // Check that the interface type is correct for this module
+ // (could be an Isa adapter in an Eisa slot).
+ //
+
+ if (adapter->InterfaceType != Isa && adapter->InterfaceType != Eisa)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // Parse the parameters.
+ //
+
+ //
+ // Get the IO location.
+ //
+
+ place = FindParameterString(buffer, IoAddrString);
+
+ if (place == NULL)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ place += UnicodeStrLen(IoAddrString) + 1;
+
+ ScanForNumber(place, &ioLocation, &found);
+
+ if (!found)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // Get the DMA channel.
+ //
+
+ place = FindParameterString(buffer, DmaChanString);
+
+ if (place == NULL)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ place += UnicodeStrLen(DmaChanString) + 1;
+
+ ScanForNumber(place, &dmaChannel, &found);
+
+ if (!found)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // Get the IRQ number.
+ //
+
+ place = FindParameterString(buffer, IrqString);
+
+ if (place == NULL)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ place += UnicodeStrLen(IrqString) + 1;
+
+ ScanForNumber(place, &irqNumber, &found);
+
+ if (!found)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // Get the multiprocessor flag.
+ //
+
+ place = FindParameterString(buffer, MultiprocessorString);
+
+ if (place == NULL)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ place += UnicodeStrLen(MultiprocessorString) + 1;
+
+ //
+ // Now parse the value.
+ //
+
+ ScanForNumber(place, &multiprocessor, &found);
+
+ //
+ // If the handle does not refer to an adapter that has been found
+ // by search we must query the hardware.
+ //
+
+ if (!adapter->Found)
+ {
+ if (CheckForCard(
+ adapter->BusNumber,
+ adapter->InterfaceType,
+ ioLocation
+ ) != adapter->CardType)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ adapter->IoLocation = ioLocation;
+ adapter->Dma = 0; // Smart16's are always in PIO mode.
+ adapter->Irq = RESOURCE_UNKNOWN;
+ adapter->Found = TRUE;
+ }
+
+ //
+ // Verify the parameters.
+ //
+
+ if (ioLocation != adapter->IoLocation ||
+ multiprocessor != IsMultiprocessor())
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ if (adapter->Dma == RESOURCE_UNKNOWN)
+ {
+ if (!IsValueInList(dmaChannel, ParamRange[adapterNumber].DmaRange))
+ {
+ return ERROR_INVALID_DATA;
+ }
+ }
+ else if (adapter->Dma != dmaChannel)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ if (adapter->Irq == RESOURCE_UNKNOWN)
+ {
+ if (!IsValueInList(irqNumber, ParamRange[adapterNumber].IrqRange))
+ {
+ return ERROR_INVALID_DATA;
+ }
+ }
+ else if (adapter->Irq != irqNumber)
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ //
+ // If we make it to here everything checked out ok.
+ //
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeSm16QueryMaskHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* buffer -> Buffer for the returned parameters.
+* bufferSize -> Size of buffer in WCHARs.
+*
+* Purpose - Return the list of parameters required for the adapter
+* type specified by index.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgeSm16QueryMaskHandler(
+ LONG index,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ WCHAR * params;
+ LONG length;
+ LONG numberOfAdapters;
+ LONG i;
+
+ MadgePrint2("MadgeSm16QueryMaskHandler (index = %ld)\n", index);
+ MadgePrint2("BufferSize = %ld\n", bufferSize);
+
+ //
+ // Find the adapter type.
+ //
+
+ numberOfAdapters = sizeof(Adapters) / sizeof(ADAPTER_INFO);
+
+ for (i = 0; i < numberOfAdapters; i++)
+ {
+ if (Adapters[i].Index == index)
+ {
+ params = Adapters[i].Parameters;
+
+ //
+ // Find the string length (Ends with 2 NULLs)
+ //
+
+ for (length = 0; ; length++)
+ {
+ if (params[length] == L'\0')
+ {
+ length++;
+
+ if (params[length] == L'\0')
+ {
+ break;
+ }
+ }
+ }
+
+ length++;
+
+ MadgePrint2("length = %ld\n", length);
+
+ //
+ // Copy the parameters into buffer.
+ //
+
+ if (bufferSize < length)
+ {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ memcpy((VOID *) buffer, params, length * sizeof(WCHAR));
+
+ return NO_ERROR;
+ }
+ }
+
+ //
+ // If we make it here we did not find a valid adapter type so
+ // return and error.
+ //
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeSm16ParamRangeHandler
+*
+* Parameters - index -> Index of the adapter type. 1000 for the first
+* type, 1100 for the second, 1200 for the third
+* etc.
+* param -> Paramter being queried.
+* buffer -> Buffer for the returned parameters.
+* bufferSize -> Size of buffer in LONGs.
+*
+* Purpose - Return the list of acceptable values for the parameter
+* specified.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+MadgeSm16ParamRangeHandler(
+ LONG index,
+ WCHAR * param,
+ LONG * buffer,
+ LONG * bufferSize
+ )
+{
+ LONG i;
+ LONG adapterNumber;
+ LONG count;
+
+ MadgePrint2("MadgeSm16ParamRangeHandler (index=%ld)\n", index);
+
+ //
+ // Work out and validate the adapter number.
+ //
+
+ adapterNumber = (index - 1000) / 100;
+
+ if (adapterNumber < 0 ||
+ adapterNumber >= sizeof(Adapters) / sizeof(ADAPTER_INFO) ||
+ (index % 100) != 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // The simplest parameter is the IO location because this is the
+ // same for all of the adapter types.
+ //
+
+ if (UnicodeStringsEqual(param, IoAddrString))
+ {
+ count = sizeof(Sm16IoLocations) / sizeof(ULONG);
+
+ if (*bufferSize < count)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ buffer[i] = Sm16IoLocations[i];
+ }
+
+ *bufferSize = count;
+
+ return NO_ERROR;
+ }
+
+ //
+ // IRQ number is slightly more complicated because it is different
+ // for different adapter types.
+ //
+
+ else if (UnicodeStringsEqual(param, IrqString))
+ {
+ count = 0;
+
+ while (ParamRange[adapterNumber].IrqRange[count] != END_OF_LIST)
+ {
+ count++;
+ }
+
+ if (*bufferSize < count)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ buffer[i] = ParamRange[adapterNumber].IrqRange[i];
+ }
+
+ *bufferSize = count;
+
+ return NO_ERROR;
+ }
+
+
+ //
+ // Likewise DMA channel.
+ //
+
+ else if (UnicodeStringsEqual(param, DmaChanString))
+ {
+ count = 0;
+
+ while (ParamRange[adapterNumber].DmaRange[count] != END_OF_LIST)
+ {
+ count++;
+ }
+
+ if (*bufferSize < count)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ buffer[i] = ParamRange[adapterNumber].DmaRange[i];
+ }
+
+ *bufferSize = count;
+
+ return NO_ERROR;
+ }
+
+ //
+ // Or fill in the allowable values for the multiprocessor flag.
+ //
+
+ else if (UnicodeStringsEqual(param, MultiprocessorString))
+ {
+ if (*bufferSize < 2)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ *bufferSize = 2;
+
+ buffer[0] = 0;
+ buffer[1] = 1;
+
+ return NO_ERROR;
+ }
+
+ //
+ // If we reach this point we have been passed a parameter we
+ // don't know about.
+ //
+
+ return ERROR_INVALID_DATA;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeSm16QueryParameterNameHandler
+*
+* Parameters - param -> Paramter being queried.
+* buffer -> Buffer for the returned name.
+* bufferSize -> Size of buffer in WCHARs.
+*
+* Purpose - Return the name of a parameter.
+*
+* Returns - ERROR_INVALID_PARAMETER to cause the caller to use
+* the Microsoft provided default names.
+*
+****************************************************************************/
+
+LONG
+MadgeSm16QueryParameterNameHandler(
+ WCHAR * param,
+ WCHAR * buffer,
+ LONG bufferSize
+ )
+{
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+/********* End of MDGSM16.C ************************************************/
+
diff --git a/private/ntos/ndis/madge/detect/mdgutils.c b/private/ntos/ndis/madge/detect/mdgutils.c
new file mode 100644
index 000000000..9ee0cdec4
--- /dev/null
+++ b/private/ntos/ndis/madge/detect/mdgutils.c
@@ -0,0 +1,1599 @@
+/****************************************************************************
+*
+* MDGUTILS.C
+*
+* Adapter Detection DLL Utility Functions
+*
+* Copyright (c) Madge Networks Ltd 1994
+*
+* COMPANY CONFIDENTIAL - RELEASED TO MICROSOFT CORP. ONLY FOR DEVELOPMENT
+* OF WINDOWS95 NETCARD DETECTION - THIS SOURCE IS NOT TO BE RELEASED OUTSIDE
+* OF MICROSOFT WITHOUT EXPLICIT WRITTEN PERMISSION FROM AN AUTHORISED
+* OFFICER OF MADGE NETWORKS LTD.
+*
+* Created: PBA 19/08/1994
+* Derived initially from the DTAUX.C DDK sample.
+*
+****************************************************************************/
+
+#include <ntddk.h>
+#include <ntddnetd.h>
+#include <windef.h>
+#include <winerror.h>
+
+//
+// Prototype "borrowed" from WINUSER.H
+//
+
+extern int WINAPIV wsprintfW(LPWSTR, LPCWSTR, ...);
+
+
+/*---------------------------------------------------------------------------
+|
+| Define API decoration for direct importing of DLL references.
+|
+---------------------------------------------------------------------------*/
+
+#if !defined(_ADVAPI32_)
+#define WINADVAPI DECLSPEC_IMPORT
+#else
+#define WINADVAPI
+#endif
+
+
+/*---------------------------------------------------------------------------
+|
+| FUDGE the definition of LPSECURITY_ATTRIBUTES.
+|
+|--------------------------------------------------------------------------*/
+
+typedef void * LPSECURITY_ATTRIBUTES;
+
+
+/*---------------------------------------------------------------------------
+|
+| File System time stamps are represented with the following structure.
+|
+---------------------------------------------------------------------------*/
+
+typedef struct _FILETIME
+{
+ DWORD dwLowDateTime;
+ DWORD dwHighDateTime;
+}
+FILETIME, *PFILETIME, *LPFILETIME;
+
+
+//
+// These includes require the typedefs above.
+//
+
+#include <winreg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#include "mdgncdet.h"
+
+
+/*---------------------------------------------------------------------------
+|
+| Maximum size of the bus information that can be extracted from the
+| registry.
+|
+---------------------------------------------------------------------------*/
+
+#define MAX_BUS_INFO_SIZE 16384
+
+
+/*---------------------------------------------------------------------------
+|
+| Registry key strings.
+|
+---------------------------------------------------------------------------*/
+
+static PSTR BusTypeBase = "Hardware\\Description\\System\\";
+static PSTR ConfigData = "Configuration Data";
+static PSTR MicroChanTypeName = "MultifunctionAdapter";
+static PSTR EisaTypeName = "EisaAdapter";
+static PSTR PcmciaTypeName = "PCMCIA PCCARDs";
+
+static PSTR NetworkCardsBase =
+ "Software\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards";
+static PSTR ServiceName = "ServiceName";
+static PSTR ManufacturerName = "Manufacturer";
+static PSTR MadgeName = "Madge";
+static PSTR DriverName = "mdgmport";
+static PSTR ServicesBase = "System\\CurrentControlSet\\Services\\";
+static PSTR ParametersName = "\\Parameters";
+static PSTR SlotNumberName = "SlotNumber";
+static PSTR IoLocationName = "IoLocation";
+static PSTR BusNumberName = "BusNumber";
+
+static PSTR ProcessorsBase =
+ "Hardware\\Description\\System\\CentralProcessor";
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - GetBusTypeKey
+|
+| Parameters - busNumber -> Number of the bus we're interested in.
+| busTypeName -> The name of the bus type.
+| interfaceType -> The NT interface type of the bus.
+| infoHandle -> Pointer to a holder for a pointer to
+| a returned bus information structure.
+|
+| Purpose - Extract the information about a bus from the registry.
+|
+| Returns - TRUE on success or FALSE on failure.
+|
+---------------------------------------------------------------------------*/
+
+static BOOLEAN
+GetBusTypeKey(
+ ULONG busNumber,
+ const CHAR * busTypeName,
+ INT interfaceType,
+ VOID * * infoHandle
+ )
+{
+ CHAR busTypePath[MAX_PATH];
+ UCHAR * bufferPointer;
+ char subkeyName[MAX_PATH];
+ PCM_FULL_RESOURCE_DESCRIPTOR fullResource;
+ HKEY busTypeHandle;
+ HKEY busHandle;
+ FILETIME lastWrite;
+ ULONG index;
+ DWORD type;
+ DWORD bufferSize;
+ DWORD nameSize;
+ LONG err;
+ BOOL result;
+
+ //
+ // Do some initialisation.
+ //
+
+ bufferPointer = NULL;
+ busTypeHandle = NULL;
+ busHandle = NULL;
+ result = FALSE;
+ *infoHandle = NULL;
+
+ //
+ // Can only deal with 98 busses.
+ //
+
+ if (busNumber > 98)
+ {
+ return FALSE;
+ }
+
+ //
+ // Open the root of the registry section for our bus type.
+ //
+
+ strcpy(busTypePath, BusTypeBase) ;
+ strcat(busTypePath, busTypeName);
+
+ err = RegOpenKeyExA(
+ HKEY_LOCAL_MACHINE,
+ busTypePath,
+ 0,
+ KEY_READ,
+ &busTypeHandle
+ );
+
+ if (err != NO_ERROR)
+ {
+ return FALSE;
+ }
+
+ //
+ // Search through the entries in our bus section of the registry looking
+ // for an entry whose Configuration Data sub-entry is for our
+ // interface type and bus number.
+ //
+
+ for (index = 0; !result; index++)
+ {
+ //
+ // If we have already allocated a buffer for some registry
+ // data then trash it.
+ //
+
+ if (bufferPointer != NULL)
+ {
+ free(bufferPointer);
+ bufferPointer = NULL;
+ }
+
+ //
+ // If we have already opened a registry key for an individual
+ // bus then close it.
+ //
+
+ if (busHandle != NULL)
+ {
+ RegCloseKey(busHandle);
+ busHandle = NULL ;
+ }
+
+ //
+ // Enumerate through keys, searching for the proper bus number
+ //
+
+ nameSize = sizeof(subkeyName);
+
+ err = RegEnumKeyExA(
+ busTypeHandle,
+ index,
+ subkeyName,
+ &nameSize,
+ 0,
+ NULL,
+ 0,
+ &lastWrite
+ );
+
+ if (err != NO_ERROR)
+ {
+ break;
+ }
+
+ //
+ // Open the BusType root + Bus Number.
+ //
+
+ err = RegOpenKeyExA(
+ busTypeHandle,
+ subkeyName,
+ 0,
+ KEY_READ,
+ &busHandle
+ );
+
+ if (err != NO_ERROR)
+ {
+ continue;
+ }
+
+ //
+ // Get some memory for the bus information.
+ //
+
+ bufferSize = MAX_BUS_INFO_SIZE;
+ bufferPointer = (UCHAR *) malloc(bufferSize) ;
+
+ if (bufferPointer == NULL)
+ {
+ break;
+ }
+
+ //
+ // Get the configuration data for this bus instance.
+ //
+
+ err = RegQueryValueExA(
+ busHandle,
+ ConfigData,
+ NULL,
+ &type,
+ bufferPointer,
+ &bufferSize
+ );
+
+ if (err != NO_ERROR)
+ {
+ break;
+ }
+
+ //
+ // Check for our bus number and type.
+ //
+
+ fullResource = (PCM_FULL_RESOURCE_DESCRIPTOR) bufferPointer;
+
+ result = fullResource->InterfaceType == interfaceType &&
+ fullResource->BusNumber == busNumber;
+ }
+
+ //
+ // Close any open registry handles.
+ //
+
+ if (busTypeHandle != NULL)
+ {
+ RegCloseKey(busTypeHandle);
+ }
+
+ if (busHandle != NULL)
+ {
+ RegCloseKey(busHandle);
+ }
+
+ //
+ // If we were successful then pass a pointer to the bus information
+ // back to the caller.
+ //
+
+ if (result)
+ {
+ *infoHandle = bufferPointer ;
+ }
+
+ //
+ // If not then free any memory.
+ //
+
+ else if (bufferPointer != NULL)
+ {
+ free(bufferPointer);
+ }
+
+ return result;
+}
+
+
+/****************************************************************************
+*
+* Function - GetMcaKey
+*
+* Parameters - busNumber -> Number of the bus we're interested in.
+* infoHandle -> Pointer to a holder for a pointer to
+* a returned bus information structure.
+*
+* Purpose - Extract the information about a microchannel bus from
+* the registry.
+*
+* Returns - TRUE on success or FALSE on failure.
+*
+****************************************************************************/
+
+BOOLEAN
+GetMcaKey(
+ ULONG busNumber,
+ VOID * * infoHandle
+ )
+{
+ return GetBusTypeKey(
+ busNumber,
+ MicroChanTypeName,
+ MicroChannel,
+ infoHandle
+ );
+}
+
+
+/****************************************************************************
+*
+* Function - GetMcaPosId
+*
+* Parameters - infoHandle -> Pointer to the bus information for an
+* MCA bus.
+* slotNumber -> The slot number to read.
+* posId -> A pointer to a holder for the pos ID read.
+*
+* Purpose - Read the pos id for a slot from the bus information of
+* an MCA bus.
+*
+* Returns - TRUE on success or FALSE on failure.
+*
+****************************************************************************/
+
+BOOLEAN
+GetMcaPosId(
+ VOID * infoHandle,
+ ULONG slotNumber,
+ ULONG * posId
+ )
+{
+ PCM_FULL_RESOURCE_DESCRIPTOR fullResource;
+ PCM_PARTIAL_RESOURCE_LIST resourceList;
+ ULONG i;
+ ULONG totalSlots;
+ PCM_MCA_POS_DATA posData;
+
+ fullResource = (PCM_FULL_RESOURCE_DESCRIPTOR) infoHandle;
+ resourceList = &fullResource->PartialResourceList;
+
+ //
+ // Find the device-specific information, which is where the POS data is.
+ //
+
+ for (i = 0; i < resourceList->Count; i++)
+ {
+ if (resourceList->PartialDescriptors[i].Type == CmResourceTypeDeviceSpecific)
+ {
+ break;
+ }
+ }
+
+ if (i == resourceList->Count)
+ {
+ //
+ // Couldn't find device-specific information.
+ //
+
+ return FALSE;
+ }
+
+ //
+ // Now examine the device specific data.
+ //
+
+ totalSlots = resourceList->PartialDescriptors[i].u.DeviceSpecificData.DataSize;
+ totalSlots = totalSlots / sizeof(CM_MCA_POS_DATA);
+
+ if (slotNumber <= totalSlots)
+ {
+ posData = (PCM_MCA_POS_DATA) (&resourceList->PartialDescriptors[i + 1]);
+ posData += slotNumber - 1;
+
+ *posId = posData->AdapterId;
+
+ return TRUE;
+ }
+
+ //
+ // If we make it here there wasn't any pos data for the specified slot.
+ //
+
+ return FALSE;
+}
+
+
+/****************************************************************************
+*
+* Function - DeleteMcaKey
+*
+* Parameters - infoHandle -> Pointer to a bus information structure.
+*
+* Purpose - Free the memory associated with a bus information
+* structure prevously returned by GetMcaKey.
+*
+* Returns - Nothing.
+*
+****************************************************************************/
+
+VOID
+DeleteMcaKey(
+ VOID * infoHandle
+ )
+{
+ free(infoHandle) ;
+}
+
+
+/****************************************************************************
+*
+* Function - GetEisaKey
+*
+* Parameters - busNumber -> Number of the bus we're interested in.
+* infoHandle -> Pointer to a holder for a pointer to
+* a returned bus information structure.
+*
+* Purpose - Extract the information about an EISA bus from
+* the registry.
+*
+* Returns - TRUE on success or FALSE on failure.
+*
+****************************************************************************/
+
+BOOLEAN
+GetEisaKey(
+ ULONG busNumber,
+ VOID * * infoHandle
+ )
+{
+ return GetBusTypeKey(
+ busNumber,
+ EisaTypeName,
+ Eisa,
+ infoHandle
+ );
+}
+
+
+/****************************************************************************
+*
+* Function - GetEisaCompressedId
+*
+* Parameters - infoHandle -> Pointer to the bus information for an
+* EISA bus.
+* slotNumber -> The slot number to read.
+* compressedId -> A pointer to a holder for the compressed
+* ID read.
+*
+* Purpose - Read the compressed id for a slot from the bus information
+* of an EISA bus.
+*
+* Returns - TRUE on success or FALSE on failure.
+*
+****************************************************************************/
+
+BOOLEAN
+GetEisaCompressedId(
+ VOID * infoHandle,
+ ULONG slotNumber,
+ ULONG * compressedId
+ )
+{
+ PCM_FULL_RESOURCE_DESCRIPTOR fullResource;
+ PCM_PARTIAL_RESOURCE_LIST resourceList;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR resourceDescriptor;
+ ULONG i;
+ ULONG totalDataSize;
+ ULONG slotDataSize;
+ PCM_EISA_SLOT_INFORMATION slotInformation;
+
+ fullResource = (PCM_FULL_RESOURCE_DESCRIPTOR) infoHandle;
+ resourceList = &fullResource->PartialResourceList;
+
+ //
+ // Find the device-specific information, which is where the slot data is.
+ //
+
+ for (i = 0; i < resourceList->Count; i++)
+ {
+ if (resourceList->PartialDescriptors[i].Type == CmResourceTypeDeviceSpecific)
+ {
+ break;
+ }
+ }
+
+ if (i == resourceList->Count)
+ {
+ //
+ // Couldn't find device-specific information.
+ //
+
+ return FALSE;
+ }
+
+ //
+ // Now examine the device specific data.
+ //
+
+ resourceDescriptor = &(resourceList->PartialDescriptors[i]);
+ totalDataSize = resourceDescriptor->u.DeviceSpecificData.DataSize;
+
+ slotInformation = (PCM_EISA_SLOT_INFORMATION)
+ ((UCHAR *) resourceDescriptor +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
+
+ //
+ // Iterate through the slot list until we reach our slot number.
+ //
+
+ while (((LONG) totalDataSize) > 0)
+ {
+ if (slotInformation->ReturnCode == EISA_EMPTY_SLOT)
+ {
+ slotDataSize = sizeof(CM_EISA_SLOT_INFORMATION);
+ }
+ else
+ {
+ slotDataSize = sizeof(CM_EISA_SLOT_INFORMATION) +
+ slotInformation->NumberFunctions *
+ sizeof(CM_EISA_FUNCTION_INFORMATION);
+ }
+
+ if (slotDataSize > totalDataSize)
+ {
+ //
+ // Something is wrong.
+ //
+
+ return FALSE;
+ }
+
+ //
+ // If we haven't reached our slot yet then advance one slot.
+ //
+
+ if (slotNumber > 0)
+ {
+ slotNumber--;
+
+ slotInformation = (PCM_EISA_SLOT_INFORMATION)
+ ((PUCHAR) slotInformation + slotDataSize);
+
+ totalDataSize -= slotDataSize;
+
+ continue;
+ }
+
+ //
+ // This is our slot.
+ //
+
+ break;
+ }
+
+ //
+ // Check that we have really found a slot.
+ //
+
+ if (slotNumber != 0 || totalDataSize == 0)
+ {
+ return FALSE;
+ }
+
+ //
+ // If we make it here we have found a valid slot list entry
+ // for our slot number.
+ //
+
+ *compressedId = slotInformation->CompressedId & 0x00FFFFFF;
+
+ return TRUE;
+}
+
+
+/****************************************************************************
+*
+* Function - DeleteEisaKey
+*
+* Parameters - infoHandle -> Pointer to a bus information structure.
+*
+* Purpose - Free the memory associated with a bus information
+* structure prevously returned by GetEisaKey.
+*
+* Returns - Nothing.
+*
+****************************************************************************/
+
+VOID
+DeleteEisaKey(
+ VOID * infoHandle
+ )
+{
+ free(infoHandle);
+}
+
+
+/****************************************************************************
+*
+* Function - CheckForPcmciaCard
+*
+* Parameters - ioLocation -> Pointer to a holder for the IO location.
+* irqNumber -> Pointer to a holder for the IRQ number.
+*
+* Purpose - Check for PCMCIA entry for Madge card in the registry.
+*
+* Returns - TRUE if there is an entry, FALSE otherwise.
+*
+****************************************************************************/
+
+BOOLEAN
+CheckForPcmciaCard(
+ ULONG * ioLocation,
+ ULONG * irqNumber
+ )
+{
+ CHAR busTypePath[MAX_PATH];
+ UCHAR * bufferPointer;
+ PCM_FULL_RESOURCE_DESCRIPTOR fullResource;
+ PCM_PARTIAL_RESOURCE_LIST resList;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR resDesc;
+ HKEY busTypeHandle;
+ DWORD type;
+ DWORD bufferSize;
+ LONG err;
+ BOOL result;
+ UINT i;
+
+ //
+ // Do some initialisation.
+ //
+
+ bufferPointer = NULL;
+ busTypeHandle = NULL;
+ result = FALSE;
+ *ioLocation = RESOURCE_UNKNOWN;
+ *irqNumber = RESOURCE_UNKNOWN;
+
+ //
+ // Open the root of the registry section for PCMCIA cards.
+ //
+
+ strcpy(busTypePath, BusTypeBase) ;
+ strcat(busTypePath, PcmciaTypeName);
+
+ err = RegOpenKeyExA(
+ HKEY_LOCAL_MACHINE,
+ busTypePath,
+ 0,
+ KEY_READ,
+ &busTypeHandle
+ );
+
+ if (err != NO_ERROR)
+ {
+ MadgePrint1("RegOpenKeyExA failed\n");
+ return FALSE;
+ }
+
+ //
+ // Query the entry for 'mdgmport.' If this works then there must be
+ // a Madge PCMCIA card present.
+ //
+
+ //
+ // Get some memory for the bus information.
+ //
+
+ bufferSize = MAX_BUS_INFO_SIZE;
+ bufferPointer = (UCHAR *) malloc(bufferSize) ;
+
+ if (bufferPointer == NULL)
+ {
+ return FALSE;
+ }
+
+ //
+ // Get the configuration data for Madge PCMCIA card.
+ //
+
+ err = RegQueryValueExA(
+ busTypeHandle,
+ DriverName,
+ NULL,
+ &type,
+ bufferPointer,
+ &bufferSize
+ );
+
+ if (err != NO_ERROR)
+ {
+ MadgePrint1("RegQueryValueExA failed\n");
+ result = FALSE;
+ }
+ else
+ {
+ MadgePrint1("RegQueryValueExA succeeded\n");
+ result = TRUE;
+ }
+
+ //
+ // Now look at the returned resource list to find our
+ // IO location and IRQ number.
+ //
+
+ if (result)
+ {
+ fullResource = (PCM_FULL_RESOURCE_DESCRIPTOR) bufferPointer;
+ resList = &fullResource->PartialResourceList;
+
+ for (i = 0; i < resList->Count; i++)
+ {
+ resDesc = &resList->PartialDescriptors[i];
+
+ switch (resDesc->Type)
+ {
+ case CmResourceTypeInterrupt:
+
+ *irqNumber = (ULONG) resDesc->u.Interrupt.Vector;
+ break;
+
+ case CmResourceTypePort:
+
+ *ioLocation = (ULONG) resDesc->u.Port.Start.LowPart;
+ break;
+ }
+ }
+
+ MadgePrint2("IO Location = %x\n", *ioLocation);
+ MadgePrint2("IRQ Number = %d\n", *irqNumber);
+ }
+
+ //
+ // Close any open registry handles.
+ //
+
+ RegCloseKey(busTypeHandle);
+
+ //
+ // Free memory used for query. We don't pass anything back since the
+ // data would mean very little. A PCMCIA card is programmed with what-
+ // ever values the user chooses. There isn't really a concept of reading
+ // the cofiguration information from the card.
+ //
+
+ free(bufferPointer);
+
+ return result;
+}
+
+
+/****************************************************************************
+*
+* Function - UnicodeStrLen
+*
+* Parameters - string -> A unicode string.
+*
+* Purpose - Determine the length of a unicode string.
+*
+* Returns - The length of string.
+*
+****************************************************************************/
+
+ULONG
+UnicodeStrLen(WCHAR * string)
+{
+ ULONG length;
+
+ length = 0;
+
+ while (string[length] != L'\0')
+ {
+ length++;
+ }
+
+ return length;
+}
+
+
+/****************************************************************************
+*
+* Function - FindParameterString
+*
+* Parameters - string1 -> A unicode parameter list string to be searched.
+* string2 -> A unicode string to be searched for.
+*
+* Purpose - Search string1 for string2 and return a pointer to
+* the place in string1 where string2 starts.
+*
+* Returns - A pointer to the start of string2 in string1 or NULL.
+*
+****************************************************************************/
+
+WCHAR *
+FindParameterString(
+ WCHAR * string1,
+ WCHAR * string2
+ )
+{
+ ULONG length1;
+ ULONG length2;
+ WCHAR * place;
+
+ //
+ // Do some initialisation.
+ //
+
+ place = string1;
+ length2 = UnicodeStrLen(string2) + 1;
+ length1 = UnicodeStrLen(string1) + 1;
+
+ //
+ // While there's more than the last NULL left look for
+ // string2.
+ //
+
+ while (length1 > 1)
+ {
+ //
+ // Are these the same?
+ //
+
+ if (memcmp(place, string2, length2 * sizeof(WCHAR)) == 0)
+ {
+ return place;
+ }
+
+ place = place + length1;
+ length1 = UnicodeStrLen(place) + 1;
+
+ }
+
+ return NULL;
+}
+
+
+/****************************************************************************
+*
+* Function - ScanForNumber
+*
+* Parameters - place -> A unicode string to search for a number.
+* value -> Pointer to holder for the number found.
+* found -> Pointer to a flag that indicates if we
+* found a number.
+*
+* Purpose - Search the unicode string that starts a place for
+* a number.
+*
+* Returns - Nothing. *found indicates if a number was found.
+*
+****************************************************************************/
+
+VOID
+ScanForNumber(
+ WCHAR * place,
+ ULONG * value,
+ BOOLEAN * found
+ )
+{
+ ULONG tmp;
+
+ *value = 0;
+ *found = FALSE;
+
+ //
+ // Skip leading blanks.
+ //
+
+ while (*place == L' ')
+ {
+ place++;
+ }
+
+ //
+ // Is this a hex number?
+ //
+
+ if ((place[0] == L'0') && (place[1] == L'x'))
+ {
+ //
+ // Yes, parse it as a hex number.
+ //
+
+ *found = TRUE;
+
+ //
+ // Skip leading '0x'.
+ //
+
+ place += 2;
+
+ //
+ // Convert a hex number.
+ //
+
+ for (;;)
+ {
+ if ((*place >= L'0') && (*place <= L'9'))
+ {
+ tmp = ((ULONG) *place) - ((ULONG) L'0');
+ }
+ else
+ {
+ switch (*place)
+ {
+ case L'a':
+ case L'A':
+
+ tmp = 10;
+ break;
+
+ case L'b':
+ case L'B':
+
+ tmp = 11;
+ break;
+
+ case L'c':
+ case L'C':
+
+ tmp = 12;
+ break;
+
+ case L'd':
+ case L'D':
+
+ tmp = 13;
+ break;
+
+ case L'e':
+ case L'E':
+
+ tmp = 14;
+ break;
+
+ case L'f':
+ case L'F':
+
+ tmp = 15;
+ break;
+
+ default:
+
+ return;
+ }
+ }
+
+ (*value) = (*value * 16) + tmp;
+
+ place++;
+ }
+ }
+
+ //
+ // Is it a decimal number?
+ //
+
+ else if ((*place >= L'0') && (*place <= L'9'))
+ {
+ //
+ // Parse it as a decimal number.
+ //
+
+ *found = TRUE;
+
+ //
+ // Convert a decimal number.
+ //
+
+ for (;;)
+ {
+ if ((*place >= L'0') && (*place <= L'9'))
+ {
+ tmp = ((ULONG) *place) - ((ULONG) L'0');
+ }
+ else
+ {
+ return;
+ }
+
+ (*value) *= (*value * 10) + tmp;
+
+ place++;
+ }
+ }
+}
+
+/****************************************************************************
+*
+* Function - DetectAllocateHeap
+*
+* Parameters - size -> Number of bytes of heap required.
+*
+* Purpose - Allocate some heap space.
+*
+* Returns - A pointer to some heap or NULL.
+*
+****************************************************************************/
+
+VOID *
+DetectAllocateHeap(LONG size)
+{
+ VOID * ptr;
+
+ if (size > 0)
+ {
+ ptr = malloc(size);
+
+ if (ptr != NULL)
+ {
+ memset(ptr, 0, size);
+ }
+
+ return ptr;
+ }
+
+ return NULL;
+}
+
+
+/****************************************************************************
+*
+* Function - DetectFreeHeap
+*
+* Parameters - ptr -> A pointer to the start of some heap to free.
+*
+* Purpose - Free some heap space.
+*
+* Returns - Nothing.
+*
+****************************************************************************/
+
+VOID
+DetectFreeHeap(VOID *ptr)
+{
+ free(ptr);
+}
+
+
+/****************************************************************************
+*
+* Function - AppendParameter
+*
+* Parameters - buffer -> Pointer to pointer buffer to append to.
+* bufferSize -> Pointer to the buffer size.
+* title -> Parameter title.
+* value -> Parameter value.
+*
+* Purpose - Append a parameter's title and value to a buffer. *buffer
+* and *bufferSize are incremented and decremented accordinlgy.
+*
+* Returns - A WINERROR.H error code.
+*
+****************************************************************************/
+
+LONG
+AppendParameter(
+ WCHAR * * buffer,
+ LONG * bufferSize,
+ WCHAR * title,
+ ULONG value
+ )
+{
+ LONG copyLength;
+
+ //
+ // Copy in the title.
+ //
+
+ copyLength = UnicodeStrLen(title)+ 1;
+
+ if (*bufferSize < copyLength)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ memcpy(
+ (VOID *) *buffer,
+ (VOID *) title,
+ (copyLength * sizeof(WCHAR))
+ );
+
+ *buffer += copyLength;
+ *bufferSize -= copyLength;
+
+ //
+ // Copy in the value
+ //
+
+ if (*bufferSize < 8)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ copyLength = wsprintfW(*buffer, L"0x%x", value);
+
+ if (copyLength < 0)
+ {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ copyLength++; // Add in the \0.
+
+ *buffer += copyLength;
+ *bufferSize -= copyLength;
+
+ return NO_ERROR;
+}
+
+
+/****************************************************************************
+*
+* Function - UnicodeStringsEqual
+*
+* Parameters - string1
+* string2 -> Unicode strings to compare.
+*
+* Purpose - Test two unicode strings for equality.
+*
+* Returns - TRUE if the strings are equal and FALSE otherwise.
+*
+****************************************************************************/
+
+BOOLEAN
+UnicodeStringsEqual(
+ WCHAR *string1,
+ WCHAR *string2
+ )
+{
+ while (*string1 != L'\0' && *string1 == *string2)
+ {
+ string1++;
+ string2++;
+ }
+
+ return *string1 == *string2;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeCardAlreadyInstalled
+*
+* Parameters - useSlotNumber -> TRUE if we are to search on slot number or
+* FALSE if we are to search on IO location.
+* busNumber -> The bus number.
+* descriptor -> The slot number or IO location.
+*
+* Purpose - Search the registry to see if a Madge adapter is already
+* installed at the specified slot number or IO location.
+*
+* Returns - TRUE if an adapter is installed or FALSE if not.
+*
+****************************************************************************/
+
+BOOLEAN
+MadgeCardAlreadyInstalled(
+ BOOLEAN useSlotNumber,
+ ULONG busNumber,
+ ULONG descriptor
+ )
+{
+ CHAR driverPath[MAX_PATH];
+ UCHAR buffer[MAX_PATH];
+ char subkeyName[MAX_PATH];
+ HKEY netCardsHandle;
+ HKEY cardHandle;
+ HKEY driverHandle;
+ FILETIME lastWrite;
+ ULONG index;
+ DWORD type;
+ DWORD bufferSize;
+ DWORD nameSize;
+ LONG err;
+ BOOLEAN found;
+ ULONG tempDescriptor;
+ ULONG tempBusNumber;
+
+ //
+ // Do some initialisation.
+ //
+
+ netCardsHandle = NULL;
+ cardHandle = NULL;
+ driverHandle = NULL;
+ found = FALSE;
+
+ //
+ // Open the root of the registry section net cards.
+ //
+
+ err = RegOpenKeyExA(
+ HKEY_LOCAL_MACHINE,
+ NetworkCardsBase,
+ 0,
+ KEY_READ,
+ &netCardsHandle
+ );
+
+ if (err != NO_ERROR)
+ {
+ return FALSE;
+ }
+
+ //
+ // Search through the network card entries looking for entries
+ // that are for drivers with manufacturer set to "Madge".
+ //
+
+ for (index = 0; !found; index++)
+ {
+ //
+ // Close any open registry handles.
+ //
+
+ if (cardHandle != NULL)
+ {
+ RegCloseKey(cardHandle);
+ cardHandle = NULL;
+ }
+
+ if (driverHandle != NULL)
+ {
+ RegCloseKey(driverHandle);
+ driverHandle = NULL;
+ }
+
+ //
+ // Enumerate through keys.
+ //
+
+ nameSize = sizeof(subkeyName);
+
+ err = RegEnumKeyExA(
+ netCardsHandle,
+ index,
+ subkeyName,
+ &nameSize,
+ 0,
+ NULL,
+ 0,
+ &lastWrite
+ );
+
+ if (err != NO_ERROR)
+ {
+ break;
+ }
+
+ //
+ // Open the net card key.
+ //
+
+ err = RegOpenKeyExA(
+ netCardsHandle,
+ subkeyName,
+ 0,
+ KEY_READ,
+ &cardHandle
+ );
+
+ if (err != NO_ERROR)
+ {
+ continue;
+ }
+
+ //
+ // Get the manufacturer name and check that it is
+ // "Madge".
+ //
+
+ bufferSize = sizeof(buffer);
+
+ err = RegQueryValueExA(
+ cardHandle,
+ ManufacturerName,
+ NULL,
+ &type,
+ buffer,
+ &bufferSize
+ );
+
+ if (err != NO_ERROR)
+ {
+ continue;
+ }
+
+ if (strcmp(buffer, MadgeName) != 0)
+ {
+ continue;
+ }
+
+ //
+ // Get the driver name.
+ //
+
+ bufferSize = sizeof(buffer);
+
+ err = RegQueryValueExA(
+ cardHandle,
+ ServiceName,
+ NULL,
+ &type,
+ buffer,
+ &bufferSize
+ );
+
+ if (err != NO_ERROR)
+ {
+ continue;
+ }
+
+ //
+ // Open a key for the driver entry under services.
+ //
+
+ strcpy(driverPath, ServicesBase);
+ strcat(driverPath, buffer);
+ strcat(driverPath, ParametersName);
+
+ err = RegOpenKeyExA(
+ HKEY_LOCAL_MACHINE,
+ driverPath,
+ 0,
+ KEY_READ,
+ &driverHandle
+ );
+
+ if (err != NO_ERROR)
+ {
+ continue;
+ }
+
+ //
+ // Try and read the slot number or IO location.
+ //
+
+ bufferSize = sizeof(buffer);
+
+ if (useSlotNumber)
+ {
+ err = RegQueryValueExA(
+ driverHandle,
+ SlotNumberName,
+ NULL,
+ &type,
+ buffer,
+ &bufferSize
+ );
+ }
+ else
+ {
+ err = RegQueryValueExA(
+ driverHandle,
+ IoLocationName,
+ NULL,
+ &type,
+ buffer,
+ &bufferSize
+ );
+ }
+
+ if (err != NO_ERROR)
+ {
+ continue;
+ }
+
+ tempDescriptor = (ULONG) *((DWORD *) buffer);
+
+ //
+ // Try and read the bus number.
+ //
+
+ bufferSize = sizeof(buffer);
+
+ err = RegQueryValueExA(
+ driverHandle,
+ BusNumberName,
+ NULL,
+ &type,
+ buffer,
+ &bufferSize
+ );
+
+ if (err != NO_ERROR)
+ {
+ continue;
+ }
+
+ tempBusNumber = (ULONG) *((DWORD *) buffer);
+
+ //
+ // Check to see if we have a match.
+ //
+
+ if (descriptor == tempDescriptor &&
+ busNumber == tempBusNumber)
+ {
+ MadgePrint2("Found Madge adapter at %lx\n", descriptor);
+ found = TRUE;
+ break;
+ }
+ }
+
+ //
+ // Close any open registry handles.
+ //
+
+ if (netCardsHandle != NULL)
+ {
+ RegCloseKey(netCardsHandle);
+ }
+
+ if (cardHandle != NULL)
+ {
+ RegCloseKey(cardHandle);
+ }
+
+ if (driverHandle != NULL)
+ {
+ RegCloseKey(driverHandle);
+ }
+
+ return found;
+}
+
+
+/****************************************************************************
+*
+* Function - IsMultiprocessor
+*
+* Parameters - None.
+*
+* Purpose - Examine the registry to find out if the machine is a
+* multiprocessor.
+*
+* Returns - 0 for a single processor or 1 for a multiprocessor.
+*
+****************************************************************************/
+
+ULONG
+IsMultiprocessor(void)
+{
+ char subkeyName[MAX_PATH];
+ HKEY cpuHandle;
+ FILETIME lastWrite;
+ ULONG count;
+ DWORD nameSize;
+ LONG err;
+
+ //
+ // Open the root of the registry section net cards.
+ //
+
+ err = RegOpenKeyExA(
+ HKEY_LOCAL_MACHINE,
+ ProcessorsBase,
+ 0,
+ KEY_READ,
+ &cpuHandle
+ );
+
+ if (err != NO_ERROR)
+ {
+ return 0;
+ }
+
+ //
+ // Enumerate the processors.
+ //
+
+ count = 0;
+
+ for (;;)
+ {
+ nameSize = sizeof(subkeyName);
+
+ err = RegEnumKeyExA(
+ cpuHandle,
+ count,
+ subkeyName,
+ &nameSize,
+ 0,
+ NULL,
+ 0,
+ &lastWrite
+ );
+
+ if (err != NO_ERROR)
+ {
+ break;
+ }
+
+ count++;
+
+ MadgePrint2("Found a CPU, number %d\n", count);
+ }
+
+ //
+ // Close any open registry handles.
+ //
+
+ RegCloseKey(cpuHandle);
+
+ return (count <= 1) ? 0 : 1;
+}
+
+
+/****************************************************************************
+*
+* Function - IsValueInList
+*
+* Parameters - value -> Value to be checked.
+* list -> Pointer to a list of values.
+*
+* Purpose - Check to see if a value is present in a list of values. The
+* list should be terminated with a value of END_OF_LIST.
+*
+* Returns - TRUE if the value is in the list or FALSE if it is not.
+*
+****************************************************************************/
+
+BOOLEAN
+IsValueInList(
+ ULONG value,
+ ULONG * list
+ )
+{
+ while (*list != END_OF_LIST && *list != value)
+ {
+ list++;
+ }
+
+ return *list == value;
+}
+
+
+/******** End of MDGUTILS.C ************************************************/
diff --git a/private/ntos/ndis/madge/detect/sources b/private/ntos/ndis/madge/detect/sources
new file mode 100644
index 000000000..41b1595da
--- /dev/null
+++ b/private/ntos/ndis/madge/detect/sources
@@ -0,0 +1,47 @@
+!if 0
+
+ Copyright (C) 1992-1995 by Digital Equipment Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the MADGE NDIS3 miniport driver being built
+ and the list of sources files needed to build it.
+ It specifies also the compiler switches specific to this driver
+
+Author:
+
+!endif
+
+TARGETNAME=mdgncdet
+TARGETTYPE=DYNLINK
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\netdtect.lib \
+ $(BASEDIR)\public\sdk\lib\*\advapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib
+
+INCLUDES=..\..\..\inc;$(BASEDIR)\public\sdk\inc
+C_DEFINES=$(C_DEFINES) -DNDIS_NT=1
+USE_CRTDLL=1
+
+DLLBASE=0x1C000000
+DLLENTRY=NcDetectInitialInit
+
+SOURCES=mdgncdet.c \
+ mdgeisa.c \
+ mdgat.c \
+ mdgsm16.c \
+ mdgpnp.c \
+ mdgmc.c \
+ mdgpci.c \
+ mdgpcmc.c \
+ mdgutils.c \
+ mdgncdet.rc
+
+
+
diff --git a/private/ntos/ndis/madge/dirs b/private/ntos/ndis/madge/dirs
new file mode 100644
index 000000000..b934a0f79
--- /dev/null
+++ b/private/ntos/ndis/madge/dirs
@@ -0,0 +1,29 @@
+!IF 0
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ dirs
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=dll \
+ detect \
+ driver
+
+
+
+
diff --git a/private/ntos/ndis/madge/dll/blmadge.ico b/private/ntos/ndis/madge/dll/blmadge.ico
new file mode 100644
index 000000000..df38f5b23
--- /dev/null
+++ b/private/ntos/ndis/madge/dll/blmadge.ico
Binary files differ
diff --git a/private/ntos/ndis/madge/dll/brmadge.ico b/private/ntos/ndis/madge/dll/brmadge.ico
new file mode 100644
index 000000000..1a3a00324
--- /dev/null
+++ b/private/ntos/ndis/madge/dll/brmadge.ico
Binary files differ
diff --git a/private/ntos/ndis/madge/dll/madge.ico b/private/ntos/ndis/madge/dll/madge.ico
new file mode 100644
index 000000000..4958cd770
--- /dev/null
+++ b/private/ntos/ndis/madge/dll/madge.ico
Binary files differ
diff --git a/private/ntos/ndis/madge/dll/makefile b/private/ntos/ndis/madge/dll/makefile
new file mode 100644
index 000000000..14f79b701
--- /dev/null
+++ b/private/ntos/ndis/madge/dll/makefile
@@ -0,0 +1 @@
+!include $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/madge/dll/makefile.inc b/private/ntos/ndis/madge/dll/makefile.inc
new file mode 100644
index 000000000..b4798f5d7
--- /dev/null
+++ b/private/ntos/ndis/madge/dll/makefile.inc
@@ -0,0 +1,5 @@
+mdgmpdlg.hlp: $(TARGETEXEFILES)
+ chmode -r mdgmpdlg.hlp
+ binplace mdgmpdlg.hlp
+ touch mdgmpdlg.hlp
+ chmode +r mdgmpdlg.hlp
diff --git a/private/ntos/ndis/madge/dll/mdgmpdlg.c b/private/ntos/ndis/madge/dll/mdgmpdlg.c
new file mode 100644
index 000000000..f0f27797f
--- /dev/null
+++ b/private/ntos/ndis/madge/dll/mdgmpdlg.c
@@ -0,0 +1,124 @@
+
+#include <ntddk.h>
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include "mdgmpdlg.upd"
+
+typedef int BOOL;
+typedef unsigned long DWORD;
+typedef unsigned char BYTE;
+
+
+//
+// Identification string for MVER.
+//
+
+static char MVerString[] = MVER_STRING;
+
+BOOL
+MadgeLAACheck(DWORD cargs,
+ LPSTR lpszArgs[],
+ LPSTR *lpszTextOut)
+ {
+ /* We are expecting one argument, a node address, and we want to parse */
+ /* it, check it, and return true/false. */
+ /* NB According to the book, the arguments are not Unicode, so we can */
+ /* use old style routines. */
+
+ static char buffer[50] = "";
+ BYTE nodeaddr[6] = { 0, };
+ char ch;
+ int nibbles;
+ int nibble;
+ BOOL hyphens, hyphen;
+
+ *lpszTextOut = buffer;
+
+ if (cargs != 1)
+ {
+ sprintf(buffer, "MadgeLAACheck: too few arguments");
+ return FALSE;
+ }
+
+ /* We have the correct number of arguments, now parse it */
+
+ hyphens = FALSE;
+ hyphen = FALSE;
+ nibbles = 0;
+
+ while (nibbles < 12)
+ {
+ ch = *(lpszArgs[0]++);
+
+ /* First make sure the hyphenation of the node address is correct. */
+ /* We allow either fully hyphenated or not hyphenated, but not a */
+ /* mixture. */
+
+ if ((nibbles % 2) == 0)
+ {
+ if (nibbles == 2)
+ {
+ if (ch == '-' && !hyphen)
+ {
+ hyphens = TRUE;
+ hyphen = TRUE;
+ continue;
+ }
+ }
+ else
+ if (hyphens)
+ if (ch == '-')
+ if (!hyphen)
+ {
+ hyphen = TRUE;
+ continue;
+ }
+ else
+ break;
+ else
+ if (!hyphen)
+ break;
+ }
+ else
+ hyphen = FALSE;
+
+ if (ch >= '0' && ch <= '9')
+ nibble = ch - '0';
+ else if (ch >= 'A' && ch <= 'F')
+ nibble = ch - 'A' + 10;
+ else if (ch >= 'a' && ch <= 'f')
+ nibble = ch - 'a' + 10;
+ else
+ break;
+
+ /* So we've got a valid nibble - now slot it into place */
+
+ nodeaddr[nibbles / 2] |= nibble << (nibbles % 2 ? 0 : 4);
+
+ nibbles++;
+ }
+
+ if ((nibbles != 12) || (*lpszArgs[0] != '\0' && !isspace(*lpszArgs[0])))
+ {
+ sprintf(buffer, "Bad node address. Use xx-xx-xx-xx-xx-xx.");
+ return FALSE;
+ }
+
+ /* We have a valid node address - just check that it is good as a LAA */
+
+ if ((nodeaddr[0] & 0xC0) != 0x40)
+ {
+ sprintf(buffer, "Illegal LAA (first digit must be between 4 and 7)");
+ return FALSE;
+ }
+
+ sprintf(buffer, "MADGE_STATUS_SUCCESS");
+
+ return TRUE;
+ }
+
+/*****************************************************************************/
+/* End of file. */
+/*****************************************************************************/
diff --git a/private/ntos/ndis/madge/dll/mdgmpdlg.def b/private/ntos/ndis/madge/dll/mdgmpdlg.def
new file mode 100644
index 000000000..f6d51e565
--- /dev/null
+++ b/private/ntos/ndis/madge/dll/mdgmpdlg.def
@@ -0,0 +1,8 @@
+LIBRARY MDGMPDLG
+
+DESCRIPTION 'Madge Installation assist DLL'
+
+EXPORTS
+ MadgeLAACheck
+
+; VERSION 1.02
diff --git a/private/ntos/ndis/madge/dll/mdgmpdlg.dlg b/private/ntos/ndis/madge/dll/mdgmpdlg.dlg
new file mode 100644
index 000000000..d90541aa0
--- /dev/null
+++ b/private/ntos/ndis/madge/dll/mdgmpdlg.dlg
@@ -0,0 +1,111 @@
+1 DLGINCLUDE "UILSTF.H"
+
+MDGEISA DIALOG PRELOAD 8, 23, 243, 232
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "@Caption"
+FONT 8, "MS Shell Dlg"
+CLASS "mydlg"
+BEGIN
+ PUSHBUTTON "@Continue", IDC_C, 19, 202, 40, 14
+ PUSHBUTTON "@Cancel", IDC_X, 99, 202, 40, 14
+ PUSHBUTTON "@Help", IDC_H, 179, 202, 40, 14
+ ICON 102, 200, 183, 119, 16, 16, WS_GROUP
+ ICON 103, 200, 201, 119, 16, 16
+ ICON 104, 200, 201, 101, 16, 16
+ ICON 105, 200, 183, 101, 16, 16
+ EDITTEXT IDC_EDIT1, 67, 83, 96, 12, ES_AUTOHSCROLL
+ LTEXT "@Edit1Label", 205, 3, 83, 50, 8
+ EDITTEXT IDC_EDIT2, 67, 101, 96, 12, ES_AUTOHSCROLL
+ LTEXT "@Edit2Label", 206, 3, 102, 50, 8
+ LTEXT "@Combo4Label", 101, 3, 140, 54, 8
+ COMBOBOX IDC_COMBO4, 66, 139, 96, 50, CBS_DROPDOWNLIST |
+ CBS_OEMCONVERT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "@ConsultHelp", 106, 3, 123, 159, 8, NOT WS_GROUP
+ LTEXT "@Combo5Label", 107, 3, 160, 100, 8
+ COMBOBOX IDC_COMBO5, 109, 159, 53, 36, CBS_DROPDOWNLIST |
+ CBS_OEMCONVERT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "@Combo7Label", 108, 3, 65, 100, 8
+ COMBOBOX IDC_COMBO7, 110, 64, 53, 32, CBS_DROPDOWNLIST |
+ CBS_OEMCONVERT | WS_VSCROLL | WS_TABSTOP
+ COMBOBOX IDC_COMBO8, 67, 25, 96, 51, CBS_DROPDOWNLIST |
+ CBS_OEMCONVERT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "@Combo8Label", 109, 3, 26, 61, 8
+ LTEXT "@AdapterTitle", 110, 3, 7, 167, 8, NOT WS_GROUP
+ LTEXT "@OldValueTitle", 111, 173, 7, 70, 17, NOT WS_GROUP
+ LTEXT "@OldSlotNumber", 112, 173, 26, 64, 8, NOT WS_GROUP
+ LTEXT "@OldMpFlag", 113, 173, 65, 64, 8, NOT WS_GROUP
+ LTEXT "@Combo3Label", 114, 3, 46, 61, 8
+ COMBOBOX IDC_COMBO3, 67, 45, 96, 51, CBS_DROPDOWNLIST |
+ CBS_OEMCONVERT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "@OldDmaChannel", 115, 173, 46, 64, 8
+ LTEXT "@Combo9Label", 116, 3, 180, 55, 8
+ COMBOBOX IDC_COMBO9, 66, 179, 96, 35, CBS_DROPDOWNLIST |
+ CBS_OEMCONVERT | WS_VSCROLL | WS_TABSTOP
+END
+
+MDGISA DIALOG PRELOAD 13, 23, 243, 244
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "@Caption"
+FONT 8, "MS Shell Dlg"
+CLASS "mydlg"
+BEGIN
+ PUSHBUTTON "@Continue", IDC_C, 19, 220, 40, 14
+ PUSHBUTTON "@Cancel", IDC_X, 99, 220, 40, 14
+ PUSHBUTTON "@Help", IDC_H, 179, 220, 40, 14
+ LTEXT "@Combo2Label", 202, 3, 26, 61, 8
+ COMBOBOX IDC_COMBO2, 67, 25, 96, 45, CBS_DROPDOWNLIST |
+ CBS_OEMCONVERT | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "@Combo1Label", 203, 3, 48, 60, 8
+ COMBOBOX IDC_COMBO1, 67, 47, 96, 54, CBS_DROPDOWNLIST |
+ CBS_OEMCONVERT | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "@Combo3Label", 204, 3, 69, 61, 8
+ COMBOBOX IDC_COMBO3, 67, 68, 96, 55, CBS_DROPDOWNLIST |
+ CBS_OEMCONVERT | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ ICON 102, 200, 183, 148, 16, 16, WS_GROUP
+ ICON 103, 200, 201, 148, 16, 16
+ ICON 104, 200, 201, 130, 16, 16
+ ICON 105, 200, 183, 130, 16, 16
+ EDITTEXT IDC_EDIT1, 67, 110, 96, 12, ES_AUTOHSCROLL
+ LTEXT "@Edit1Label", 205, 3, 111, 62, 8
+ EDITTEXT IDC_EDIT2, 67, 129, 96, 12, ES_AUTOHSCROLL
+ LTEXT "@Edit2Label", 206, 3, 130, 44, 8
+ LTEXT "@Combo4Label", 301, 3, 161, 57, 8
+ COMBOBOX IDC_COMBO4, 67, 160, 96, 48, CBS_DROPDOWNLIST |
+ CBS_OEMCONVERT | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "@Combo5Label", 303, 3, 181, 100, 8
+ COMBOBOX IDC_COMBO5, 110, 180, 53, 36, CBS_DROPDOWNLIST |
+ CBS_OEMCONVERT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "@Combo7Label", 304, 3, 90, 100, 8
+ COMBOBOX IDC_COMBO7, 110, 89, 53, 36, CBS_DROPDOWNLIST |
+ CBS_OEMCONVERT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "@AdapterTitle", 305, 3, 7, 167, 8, NOT WS_GROUP
+ LTEXT "@ConsultHelp", 306, 3, 146, 160, 8, NOT WS_GROUP
+ LTEXT "@OldValueTitle", 302, 173, 7, 70, 17, NOT WS_GROUP
+ LTEXT "@OldIoLocation", 307, 173, 26, 64, 8, NOT WS_GROUP
+ LTEXT "@OldIrqNumber", 308, 173, 48, 64, 8, NOT WS_GROUP
+ LTEXT "@OldDmaChannel", 309, 173, 69, 64, 8, NOT WS_GROUP
+ LTEXT "@OldMpFlag", 310, 173, 90, 64, 9, NOT WS_GROUP
+ LTEXT "@Combo9Label", 311, 3, 201, 62, 8
+ COMBOBOX IDC_COMBO9, 67, 200, 96, 35, CBS_DROPDOWNLIST |
+ CBS_OEMCONVERT | WS_VSCROLL | WS_TABSTOP
+END
+
+MDGADAPTERS DIALOG 3, 15, 229, 106
+LANGUAGE LANG_NEUTRAL, SUBLANG_DEFAULT
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "@Caption"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ PUSHBUTTON "@Continue", IDC_C, 13, 83, 40, 14
+ PUSHBUTTON "@Cancel", IDC_X, 93, 83, 40, 14
+ LTEXT "", 201, 5, 0, 20, 8
+ LTEXT "@Combo6Label", 202, 6, 7, 215, 11
+ ICON 102, 203, 183, 82, 16, 16, WS_GROUP
+ ICON 103, 204, 201, 82, 16, 16
+ ICON 104, 205, 201, 64, 16, 16
+ ICON 105, 206, 183, 64, 16, 16
+ COMBOBOX IDC_COMBO6, 6, 23, 214, 76, CBS_DROPDOWNLIST |
+ CBS_OEMCONVERT | WS_VSCROLL | WS_TABSTOP
+END
diff --git a/private/ntos/ndis/madge/dll/mdgmpdlg.h b/private/ntos/ndis/madge/dll/mdgmpdlg.h
new file mode 100644
index 000000000..a295b2e68
--- /dev/null
+++ b/private/ntos/ndis/madge/dll/mdgmpdlg.h
@@ -0,0 +1,6 @@
+/* Definitions for the icons in the dialog boxes. */
+
+#define dllicon1 102
+#define dllicon2 103
+#define dllicon3 104
+#define dllicon4 105
diff --git a/private/ntos/ndis/madge/dll/mdgmpdlg.hlp b/private/ntos/ndis/madge/dll/mdgmpdlg.hlp
new file mode 100644
index 000000000..6a5069858
--- /dev/null
+++ b/private/ntos/ndis/madge/dll/mdgmpdlg.hlp
Binary files differ
diff --git a/private/ntos/ndis/madge/dll/mdgmpdlg.hpj b/private/ntos/ndis/madge/dll/mdgmpdlg.hpj
new file mode 100644
index 000000000..bd87e3a7e
--- /dev/null
+++ b/private/ntos/ndis/madge/dll/mdgmpdlg.hpj
@@ -0,0 +1,18 @@
+
+[OPTIONS]
+CONTENTS=Contents
+COMPRESS=YES
+TITLE=Madge Smart Ringnode Driver
+
+[FILES]
+mdgmpdlg.rtf
+
+[CONFIG]
+BrowseButtons()
+
+[MAP]
+Contents 6000
+Madge_ISA_Dialog 6001
+Madge_EISA_MCA_Dialog 6002
+Madge_PCI_Dialog 6003
+ \ No newline at end of file
diff --git a/private/ntos/ndis/madge/dll/mdgmpdlg.rc b/private/ntos/ndis/madge/dll/mdgmpdlg.rc
new file mode 100644
index 000000000..abc16d8da
--- /dev/null
+++ b/private/ntos/ndis/madge/dll/mdgmpdlg.rc
@@ -0,0 +1,36 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#include "mdgmpdlg.upd"
+
+#undef VER_COMPANYNAME_STR
+#undef VER_PRODUCTNAME_STR
+#undef VER_PRODUCTVERSION
+#undef VER_PRODUCTVERSION_STR
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+#define VER_COMPANYNAME_STR "Madge Networks Ltd"
+#define VER_PRODUCTNAME_STR "Madge Networks Smart 16/4 Ringnode Driver"
+#define VER_FILEDESCRIPTION_STR "Madge Installation Dialog"
+#define VER_INTERNALNAME_STR "MdgMPDlg.dll"
+
+#define VER_LEGALCOPYRIGHT_YEARS "1994"
+#define VER_LEGALCOPYRIGHT_STR "Copyright (C) Madge Networks Ltd " VER_LEGALCOPYRIGHT_YEARS
+#define VER_FILEVERSION MADGE_DLL_VERSION
+#define VER_FILEVERSION_STR MADGE_DLL_VERSION_STR
+#define VER_PRODUCTVERSION MADGE_NT_VERSION
+#define VER_PRODUCTVERSION_STR MADGE_NT_VERSION_STR
+
+#include <common.ver>
+
+#include "uilstf.h"
+#include "mdgmpdlg.h"
+
+dllicon4 ICON "tlmadge.ico"
+dllicon1 ICON "blmadge.ico"
+dllicon2 ICON "brmadge.ico"
+dllicon3 ICON "trmadge.ico"
+
+#include "mdgmpdlg.dlg"
diff --git a/private/ntos/ndis/madge/dll/mdgmpdlg.res b/private/ntos/ndis/madge/dll/mdgmpdlg.res
new file mode 100644
index 000000000..8a2160c4a
--- /dev/null
+++ b/private/ntos/ndis/madge/dll/mdgmpdlg.res
Binary files differ
diff --git a/private/ntos/ndis/madge/dll/mdgmpdlg.rtf b/private/ntos/ndis/madge/dll/mdgmpdlg.rtf
new file mode 100644
index 000000000..c3277fde8
--- /dev/null
+++ b/private/ntos/ndis/madge/dll/mdgmpdlg.rtf
@@ -0,0 +1,307 @@
+{\rtf1\ansi
+\deff0\deflang1024
+{\fonttbl
+{\f0\froman Times New Roman;}
+{\f1\froman Symbol;}
+{\f2\fswiss Arial;}
+{\f3\froman ;}}
+{\colortbl;
+\red0\green0\blue0;
+\red0\green0\blue255;
+\red0\green255\blue255;
+\red0\green255\blue0;
+\red255\green0\blue255;
+\red255\green0\blue0;
+\red255\green255\blue0;
+\red255\green255\blue255;
+\red0\green0\blue127;
+\red0\green127\blue127;
+\red0\green127\blue0;
+\red127\green0\blue127;
+\red127\green0\blue0;
+\red127\green127\blue0;
+\red127\green127\blue127;
+\red192\green192\blue192;}
+{\stylesheet
+{\s242\tqc\tx4320\tqr\tx8640 \fs20\lang2057 \sbasedon0\snext242 footer;}
+{\s244 \fs16\up6\lang2057 \sbasedon0\snext0 footnote reference;}
+{\s245 \fs20\lang2057 \sbasedon0\snext245 footnote text;}
+{\fs20\lang2057\snext0 Normal;}}
+{\info
+{\author Paul Austin}
+{\creatim\yr1994\mo2\dy9\hr16\min56}
+{\version1}
+{\edmins977}
+{\nofpages0}
+{\nofwords0}
+{\nofchars0}
+{\vern16504}}
+\paperw12240\paperh15840\margl1800\margr1800\margt1440\margb1440\gutter0 \makebackup \sectd
+\pard\plain \keepn \fs20\lang2057
+#{\footnote \pard\plain \s245 \fs20\lang2057 Contents}
+${\footnote \pard\plain \s245 \fs20\lang2057 Contents}
++{\footnote madgehelp:01}
+K{\footnote Contents}
+\pard \keepn \par {\plain\b Madge Smart 16/4 Ringnode NDIS3 Driver Help}
+\par \pard
+\par\plain Help is available on the following topics : \par\par\tx360
+\tab{\uldb Madge Smart 16/4 ISA Ringnode Configuration}{\v Madge_ISA_Dialog}\line
+\tab{\uldb Madge Smart 16/4 EISA and MCA Ringnode Configuration}{\v Madge_EISA_MCA_Dialog}\line
+\tab{\uldb Madge Smart 16/4 PCI Ringnode Configuration}{\v Madge_PCI_Dialog}\line
+\tab{\uldb Locally Administered Addresses}{\v locally_administered_address}\line
+\tab{\uldb Maximum Frame Sizes}{\v max_frame_size}\line
+\tab{\uldb Rx/Tx Buffers}{\v rx_tx_slots}\line
+\tab{\uldb Traffic Statistics Gathering}{\v stats}\line
+\par\pard\page
+#{\footnote \pard\plain \fs20\lang2057 Madge_ISA_Dialog}
+${\footnote \pard\plain \fs20\lang2057 Madge Smart 16/4 ISA Ringnodes Help}
++{\footnote madgehelp:02}
+K{\footnote ISA Bus Cards; AT Bus Cards}
+\keepn\par{\plain\b Madge Smart 16/4 Ringnode ISA Configuration Dialog}
+\par\pard\sb200
+This dialog allows you to configure the Madge Smart 16/4 Ringnode Driver to
+ work with any Madge ISA bus adapters that you have installed.
+ You should set the switches on the cards as directed in the documentation
+ that accompany them, being careful to avoid conflicts with other devices
+ in the system.
+\par
+The driver must then be told how each card has been configured, using
+ this dialog for each one.
+ You must set the {\ul IO Location}{\v io_location}, the {\ul IRQ Level}{\v irq_channel},
+ and the {\ul Transfer method}{\v dma_channel} to match the switch settings on
+ the card.
+ If you have disabled DMA, or the adapter card does not support
+ DMA, then for transfer method select {\i PIO}.
+ Otherwise select the DMA channel for which your adapter is configured.
+\par
+If you chose automatic Smart Ringnode installation then some or all
+ of the settings may have been automatically determined.
+ Settings that have been determined will be shown on the right of the dialog
+ box under the headering "Current hardware settings".
+ Any settings that are not shown as {\i UNKNOWN} should not need changing.
+ Those that are shown as {\i UNKNOWN} must be manually set to match the
+ values set by the switches on the adapter.
+\par
+If the machine you are installing the driver on only has one processor
+ then you should set the {\i Number of processors in PC} value to {\i one}.
+ If the machine is a multi-processor then this value should be set to
+ {\i multiple}.
+\par
+The remaining fields in the dialog are optional and allow modification
+ of the behaviour of the
+ adapter card. The driver will work quite happily if they are not touched,
+ however. For further details, see the following topics :
+\par\tx360\tab{\uldb Maximum Frame Size}{\v max_frame_size}\line
+\tab{\uldb Locally Administered Addresses}{\v locally_administered_address}\line
+\tab{\uldb Rx/Tx Buffers}{\v rx_tx_slots}\line
+\tab{\uldb Traffic Statistics Gathering}{\v stats}
+\par \pard \page
+#{\footnote \pard\plain \s245 \fs20\lang2057 Madge_EISA_MCA_Dialog}
+${\footnote \pard\plain \s245 \fs20\lang2057 Madge Smart 16/4 EISA and MCA Ringnodes Help}
++{\footnote madgehelp:03}
+K{\footnote EISA Bus Cards; MicroChannel Cards; MCA Cards}
+\pard \keepn\par{\plain\b Madge Smart 16/4 Ringnode EISA and MCA Configuration Dialog}
+\par\pard\sb200\tx360
+This dialog allows you to configure the Madge Smart 16/4 Ringnode Driver to
+ work with any Madge EISA bus or Madge MCA bus adapters that you have
+ installed.
+ An EISA or MC adapter is identified by the number of the slot containing
+ the adapter.
+ This should be printed on the back of the machine near where the lobe
+ cable is plugged into the adapter.
+\par
+If you chose automatic Smart Ringnode installation then this
+ setting should have been automatically determined.
+ Settings that have been determined will be shown on the right of the
+ dialog box under the headering "Current hardware settings".
+ Any settings that are not shown as {\i UNKNOWN} should not need changing.
+\par
+If the machine you are installing the driver on only has one processor
+ then you should set the {\i Number of processors in PC} value to {\i one}.
+ If the machine is a multi-processor then this value should be set to
+ {\i multiple}.
+\par
+The remaining fields in the dialog are optional and allow modification
+ of the behaviour of the
+ adapter card. The driver will work quite happily if they are not touched,
+ however. For further details, see the following topics :
+\par\tx360\tab{\uldb Maximum Frame Size}{\v max_frame_size}\line
+\tab{\uldb Locally Administered Addresses}{\v locally_administered_address}\line
+\tab{\uldb Rx/Tx Buffers}{\v rx_tx_slots}\line
+\tab{\uldb Traffic Statistics Gathering}{\v stats}
+\par \pard \page
+#{\footnote \pard\plain \s245 \fs20\lang2057 Madge_PCI_Dialog}
+${\footnote \pard\plain \s245 \fs20\lang2057 Madge Smart 16/4 PCI Ringnodes Help}
++{\footnote madgehelp:04}
+K{\footnote PCI Bus Cards}
+\pard \keepn\par{\plain\b Madge Smart 16/4 Ringnode PCI Configuration Dialog}
+\par\pard\sb200\tx360
+This dialog allows you to configure the Madge Smart 16/4 Ringnode Driver to
+ work with any Madge PCI bus adapters that you have installed.
+ PCI adapters are identified by the {\i PCI Device Number}.
+ This value is assigned to the adapter by the PCI BIOS when the PC is
+ powered up or reset.
+ If you do not have a way of determining the PCI Device Number of your
+ Madge PCI Ringonde(s) (some manufacturer's configuration utilities provide
+ this information) then it is recommended that you set the PCI Device
+ Number setting to {\i UNKNOWN}.
+ If the Madge NDIS3 Miniport driver is installed with the PCI Device Number
+ setting set to {\i UNKNOWN} then when the driver starts it searches for
+ the Madge PCI Ringnode with the lowest PCI Device Number that is not
+ already in use.
+\par
+Many PCs and workstations have numbers marked on their PCI slots and it
+ is common for the PCI Device Numbers assigned to PCI adapters to increase
+ with the slot numbers.
+ (Though it is unlikely that the PCI Device Numbers will be the same as
+ the slot numbers.)
+ Therefore, if the Madge NDIS3 Miniport driver is installed for multiple
+ Madge PCI Ringnodes and all of the PCI Device Numbers are set to
+ {\i UNKNOWN}, it is quite likely that the first installation will be for
+ the Madge PCI Ringnode in the lowest number slot, the second installation
+ for the Madge PCI Ringnode in the second lowest numbered slot and so on.
+\par
+Smart 16/4 PCI Ringnodes support two {\ul Transfer methods}{\v dma_channel}.
+ The extremely high performance MMIO method and the PIO method.
+ Normally you should select {\i MMIO} for the transfer method.
+ However, if you have experienced problems using the MMIO method
+ then select {\i PIO}.
+ (You may experience problems with MMIO in certain PCI PC's or with
+ certain combinations of PCI adapters.)
+\par
+Smart 16/4 PCI Ringnodes (BM) also support
+ two {\ul Transfer methods}{\v dma_channel}.
+ Bus Master DMA and PIO.
+ Normally you should select {\i DMA} for the transfer method.
+\par
+ If the machine you are installing the driver on only has one processor
+ then you should set the {\i Number of processors in PC} value to {\i one}.
+ If the machine is a multi-processor then this value should be set to
+ {\i multiple}.
+\par
+The remaining fields in the dialog are optional and allow modification
+ of the behaviour of the
+ adapter card. The driver will work quite happily if they are not touched,
+ however. For further details, see the following topics :
+\par\tx360\tab{\uldb Maximum Frame Size}{\v max_frame_size}\line
+\tab{\uldb Locally Administered Addresses}{\v locally_administered_address}\line
+\tab{\uldb Rx/Tx Buffers}{\v rx_tx_slots}\line
+\tab{\uldb Traffic Statistics Gathering}{\v stats}
+\par \pard \page
+#{\footnote \pard\plain \fs20\lang2057 max_frame_size}
+${\footnote \pard\plain \fs20\lang2057 Maximum Frame Size}
++{\footnote madgehelp:05}
+K{\footnote Maximum Frame Size; MFS}
+\pard\keepn\par{\plain\b Maximum Frame Size}
+\par\pard
+\sb200\plain
+On a sixteen megabits per second token ring, the adapter card can send and
+ receive frames up to 17839 bytes in length. For many applications this may
+ be too big, so a facility is provided to limit the size of frames sent onto
+ the ring. On a four megabits per second token ring the maximum frame size is
+ nearer four and a half thousand bytes. By default, the driver will use a frame
+ size of 4096 bytes, but you
+ can edit the {\i MaxFrameSize} control to set it to a larger
+ (or indeed smaller) value.
+\par Note that if you set a value which is too big, the software will
+ automatically truncate it, and write an error into the event log that
+ contains as one of the data words the actual maximum frame size.
+\par Note also that if you know how big the frames used by higher
+ layer prototocols are going to be, you should set the driver maximum
+ frame size accordingly to enable it to make more efficient use of its
+ buffer space.
+\par\pard {\plain \lang2057 \page }
+#{\footnote \pard\plain \s245 \fs20\lang2057 locally_administered_address}
+${\footnote \pard\plain \s245 \fs20\lang2057 Locally Administered Address}
++{\footnote madgehelp:06}
+K{\footnote LAA; Locally Adminstered Address}
+\pard\keepn\par{\plain\b Locally Administered Addresses}\par\pard
+\sb200
+Every network adapter card has a unique six byte address encoded in it
+ which it uses in network frames to identify itself. It is possible
+ to override the address that the adapter recognises as its own by
+ setting the {\b Locally Administered Address}.
+ As the name suggests, this is locally administered, and so cannot
+ be guaranteed unique - it is up to the network manager to ensure this.
+\par The {\i LAA} can be set to any six byte value at all, as long
+ as the first digit is somewhere between four and seven (i.e. the
+ first two binary bits of the address must be "01"). Other than that,
+ there are no restrictions on its value.
+ In setting it, it can be entered as either a string of twelve contiguous
+ hexadecimal digits, or it can be entered as a sequence of six pairs
+ of hexadecimal digits separated by "-" (minus) characters\line
+e.g. 40-01-02-03-04-05.
+\par Normally, the {\b LAA} need not be set, but certain pieces of
+ communications software do use this facility.
+\page
+#{\footnote \pard\plain \s245 \fs20\lang2057 rx_tx_slots}
+${\footnote \pard\plain \s245 \fs20\lang2057 Rx/Tx Buffers}
++{\footnote madgehelp:07}
+K{\footnote Rx/Tx Buffers}
+\pard\keepn\par{\plain\b Rx/Tx Buffers}\par\pard
+\sb200
+MdgMPort associates a pool of receive (Rx) and transmit (Tx) buffers with each
+ adapter card installed.
+ The default value of 4 receive buffers and 4 transmit buffers has been
+ chosen to be optimal for a '486' class machine being used as a workstation.
+ If you have a machine that will be used as a server or is a high performance
+ RISC platform then you may wish to increase the number of receive and
+ transmit buffers. However, be warned that increasing the number
+ of buffers increases MdgMPort's use of memory, which may cause problems
+ if there are multiple adapters in the machine.
+\page
+#{\footnote \pard\plain \s245 \fs20\lang2057 stats}
+${\footnote \pard\plain \s245 \fs20\lang2057 Traffic Statistics Gathering}
++{\footnote madgehelp:08}
+K{\footnote Traffic Statistics Gathering}
+\pard\keepn\par{\plain\b Traffic Statistics Gathering}\par\pard
+\sb200
+The Madge NDIS3 Miniport driver can support products that gather statistics on,
+ and analyse network traffic.
+ To enable this support select the "enabled" option.
+ Unfortunately enabling this support results in the computer having to perform
+ much more network processing and performance may be degraded.
+ Madge therefore recommend that unless you must have this support you
+ set the option to "disabled".
+\page
+#{\footnote \pard\plain \fs20\lang2057 io_location}
+\plain The {\i IO Location} specifies the address of a range of I/O ports
+ used to communicate with the adapter card.
+ These must not conflict with any other device in the system, including
+ other network adapter cards.
+\par\page
+#{\footnote \pard\plain \fs20\lang2057 irq_channel}
+\plain The {\i Interrupt Level} is how the adapter card is identified
+ when it interrupts the host.
+ For each Interrupt Level that is in use in the system, there will be a
+ handler to attend to the device's needs.
+\par\page
+#{\footnote \pard\plain \fs20\lang2057 dma_channel}
+\plain The {\i Transfer method} is used to indicate what method
+ an adapter should use to transfer data to and from host memory.
+\par
+ Some adapters support bus master DMA and do not required a specific
+ channel to be identified; in which case {\i DMA} can be specified as the
+ transfer method.
+ Other adapters may support bus master DMA but require a particular
+ DMA channel to be identified.
+ In this case {\i DMA Channel nn} can be specified for the transfer method.
+ {\i nn} is the number of the DMA channel for which the adapter is
+ configured (by switches on older adapters or the DIAG configuration
+ utility on newer adapters).
+\par
+An alternative transfer method is {\i PIO} (Programmed I/O)
+ which causes the card to interrupt the host when it wants to perform
+ a transfer.
+ The host then reads/writes one of the IO Locations repeatedly
+ until the transfer is complete.
+ This transfer method is supported by all adapter types except for
+ EISA and MC.
+ {\i PIO} can be used if an adapter does not support DMA or DMA has been
+ disabled by switches on the adapter or the configuration utility.
+\par
+A final transfer method is {\i MMIO} (Memory Mapped I/O) which is similar
+ to but faster than {\i PIO}.
+\par\page
+}
+ \ No newline at end of file
diff --git a/private/ntos/ndis/madge/dll/mdgmpdlg.upd b/private/ntos/ndis/madge/dll/mdgmpdlg.upd
new file mode 100644
index 000000000..bd926863d
--- /dev/null
+++ b/private/ntos/ndis/madge/dll/mdgmpdlg.upd
@@ -0,0 +1,181 @@
+/***************************************************************************
+*
+* MDGMPDLG.UPD: MdgMPDlg (MdgMPort.SYS install helper DLL) update history.
+*
+* Copyright (c) Madge Networks Ltd. 1994
+*
+* Created: PBA 23/06/1994
+*
+***************************************************************************/
+
+#include "..\driver\mdgmport.upd"
+
+#define MADGE_DLL_VERSION 3,04,30,00
+#define MADGE_DLL_VERSION_STR "3.04.30"
+#define MADGE_DLL_NAME "MdgMPDlg"
+
+#define _DRIVER_DESC MADGE_NT_NAME##" "##MADGE_NT_VERSION_STR
+#define _DLL_DESC MADGE_DLL_NAME##" "##MADGE_DLL_VERSION_STR
+
+//
+// Identification string for MVER.
+//
+
+#ifdef MVER_STRING
+#undef MVER_STRING
+#endif
+
+#define MVER_STRING "VeRsIoN="##_DLL_DESC##" (for "##_DRIVER_DESC##")"
+
+
+/*---------------------------------------------------------------------------
+|
+| Update History.
+|
+|---------------------------------------------------------------------------
+
+ 3.04.30 10/10/1995 PBA
+
+ Source to be shipped to Microsoft. This is the LSS 4.31
+ build with support added for non-intel platforms.
+
+ 3.04.01-.29 Reserved for 4.3(1) maintanance.
+
+ 3.04 21/07/1995 PBA
+
+ Re-released for 4.3(1) with PCI-TI DMA/DIO fix.
+
+ 3.03.01-.49 Reserved for 4.3(1) maintanance.
+
+ 3.03 30/06/1995 PBA
+
+ Hardware thread released for LSS 4.3(1) with support
+ for PCI-TI adapters and untested support for PCI-Abyss
+ adapters.
+
+ 3.02 Used for non-intel thread derived from LSS 4.3(0).
+
+ 3.01.02 07/04/1995 PBA
+
+ Unchanged maintenance build.
+
+ 3.01.01 04/04/1995 PBA
+
+ Power PC build.
+
+
+ 3.01.02 - .49 Reserved for 4.3(0 and/or PnP) maintenance.
+
+ 3.01 02/02/1995 PBA
+
+ Released for 4.3(0 and/or PnP). All previous 4.3(x)
+ threads are now dead.
+
+ MDGMPORT 2.01.
+
+ 3.00.53 02/02/1995 PBA
+
+ Given to DaveF for Chicago testing and possible
+ shipment to Microsoft for M8 and/or NT 3.51.
+ MDGMPORT 2.00.61.
+
+ 3.00.52 24/01/1995 PBA
+
+ Added support for setting the ring speed.
+
+ 3.00.51 06/01/1995 PBA
+
+ Shipped source to FrancisT so that he could do a MIPs
+ build.
+
+ 3.00.50 15/12/1994 PBA
+
+ Live development continues.
+
+ Version numbers 2.50.01 to 2.99.99 are used for a FastMAC version.
+
+ 2.02.01 - .49 Reserved for release 4.3(1) maintenance.
+
+ Version number 2.02 is reserved for use in the 4.3(1) release. Live
+ development continues with 2.02.50.
+
+ 2.01.50 15/12/1994 PBA
+
+ Alpha release for product marketing to test. For use
+ with MDGMPORT 1.05.07.
+
+ 2.01.01 - .49 Reserved for release 4.3(0) maintenance.
+
+ Due the delay in getting the 4.3(0) release out it was decided to use
+ the new installtion software for 4.3(0). Version number 2.01 is
+ reserved for this. Live development continues with 2.01.50.
+
+ 2.00.03 25/11/1994 PBA
+
+ Added support for "Transfer method" for all adapters.
+
+ -- Special -----------------------------------------------------------------
+
+ 2.00.02a 11/01/1995 PBA
+
+ As 2.00.02 but has support for PCMCIA adapters. Shipped
+ to Jameel Hyder at Microsoft for NT 3.51 beta.
+ MDGMPORT 1.06.80.
+
+ ----------------------------------------------------------------------------
+
+ 2.00.02 23/11/1994 PBA
+
+ Shipped to Microsoft for possible inclusion in the next
+ NT release. MDGMPORT v1.06.50.
+
+ 2.00.01 21/09/1994 PBA
+
+ Major changes to support NetDetect based installation.
+ No PCI support at the moment.
+
+ 1.04 Reserved for release 4.3(1).
+
+ 1.03 08/11/1994 PBA
+
+ Re-released for the PCI release 4.2(3). MdgMPort.SYS
+ version 1.04.
+
+ 1.02 28/09/1994 PBA
+
+ Released for the PCI release 4.2(3). MdgMPort.SYS
+ version 1.03.
+
+ 1.01.50 28/09/1994 PBA
+
+ Added a new dialog box for PCI.
+
+ Due to the problems with FastMAC Plus a re-release with a new FastMAC
+ plus image will be needed for LSS 4.30. This release will be based on
+ 1.01.02 which is the same as the earlier LSS 4.30 with some minor bug
+ fixes. Live development continues with 1.01.50.
+
+ 1.01.02 02/09/1994 PBA
+
+ Dialog box now has support for enabling promiscuous mode.
+
+ 1.01.01 31/08/1994 PBA
+
+ Source shipped to Microsoft.
+
+ 1.01 22/07/1994 PBA
+
+ Released for 4.30 for MdgMPort.SYS 1.01.
+
+ 1.00.01 23/06/1994 PBA
+
+ First version derived from MDGNTDLG v1.04.01.
+
+---------------------------------------------------------------------------*/
+
+/******** End of MDGMPDLG.UPD **********************************************/
+
+
+
+
+ \ No newline at end of file
diff --git a/private/ntos/ndis/madge/dll/oemsetup.upd b/private/ntos/ndis/madge/dll/oemsetup.upd
new file mode 100644
index 000000000..57bbaf58c
--- /dev/null
+++ b/private/ntos/ndis/madge/dll/oemsetup.upd
@@ -0,0 +1,241 @@
+/***************************************************************************
+*
+* OEMSETUP.UPD: Update log for the MdgMPort.SYS OEMSETUP.INF file.
+*
+* Copyright (c) Madge Networks Ltd. 1994
+*
+* Created: PBA 23/06/1994
+*
+***************************************************************************/
+
+/*--------------------------------------------------------------------------
+
+ 3.04.30 10/10/1995 PBA
+
+ Source to be shipped to Microsoft. This is the LSS 4.31
+ build with support added for non-intel platforms.
+
+ 3.04.01-.29 Reserved for 4.3(1) maintanance.
+
+ 3.04 21/07/1995 PBA
+
+ Re-released for 4.3(1) with PCI-TI DMA/DIO fix.
+
+ 3.03.01-.49 Reserved for 4.3(1) maintanance.
+
+ 3.03 30/06/1995 PBA
+
+ Hardware thread released for LSS 4.3(1) with support
+ for PCI-TI adapters and untested support for PCI-Abyss
+ adapters.
+
+ 3.01.02 07/04/1995 PBA
+
+ Added 0x0300 to the list of IO locations for PCMCIA
+ adapters.
+
+ 3.01.01 04/04/1995 PBA
+
+ Added PCMCIA support back in. MDGMPORT 2.01.01.
+ Power PC build.
+
+
+ 3.01.02 - .49 Reserved for 4.3(0 and/or PnP) maintenance.
+
+ 3.01 02/02/1995 PBA
+
+ Removed PCMCIA support just for this version as the
+ rest of the world doesn't know about NT 3.51 PCMCIA
+ support.
+
+ Released for 4.3(0 and/or PnP). All previous 4.3(x)
+ threads are now dead.
+
+ MDGMPORT 2.01.
+
+ 3.00.55 02/02/1995 PBA
+
+ Given to DaveF for Chicago testing and possible
+ shipment to Microsoft for M8 and/or NT 3.51.
+ MDGMPORT 2.00.61.
+
+ 3.00.54 01/02/1995 PBA
+
+ Now add an "AdapterType" to the registry for all adapter
+ types.
+
+ 3.00.53 31/01/1995 PBA
+
+ Added support for PCMCIA. I.e. now supports "IoBaseAddress"
+ as well as "IoLocation" and adds "AdapterType = 200" and
+ "Pcmcia = 1" to the registry.
+
+ 3.00.52 24/01/1995 PBA
+
+ Added support for setting the ring speed.
+
+ 3.00.51 06/01/1995 PBA
+
+ Shipped source to FrancisT so he could do a MIPs build.
+
+ 3.00.50 15/12/1994 PBA
+
+ Live development continues.
+
+ Version numbers 2.50.01 to 2.99.99 are used for a FastMAC version.
+
+ 2.02.01 - .49 Reserved for release 4.3(1) maintenance.
+
+ Version number 2.02 is reserved for use in the 4.3(1) release. Live
+ development continues with 2.02.50.
+
+ 2.01.50 15/12/1994 PBA
+
+ ALpha release for product marketing to test. For use with
+ MDGMPORT 1.05.07.
+
+ 2.01.01 - .49 Reserved for release 4.3(0) maintenance.
+
+ Due the delay in getting the 4.3(0) release out it was decided to use
+ the new installtion software for 4.3(0). Version number 2.01 is
+ reserved for this. Live development continues with 2.01.50.
+
+ 2.00.09 25/11/1994 PBA
+
+ Removed PCI and PnP support for a special version
+ for the "frozen" release 4.3(0) thread.
+
+ 2.00.08 25/11/1994 PBA
+
+ The detection DLL now completely describes the transfer
+ mode (DMA, PIO, MMIO) in the DmaChannel value. The
+ The DmaChannel and NoMmio values in the registry are
+ used to specify the transfer mode. We now translate between
+ the two schemes and allow the user to enable and disable
+ MMIO in a way that is consistent with choosing PIO or DMA.
+
+ 2.00.07 24/11/1994 PBA
+
+ Tidied up the code that sets default values if adapters
+ were not auto-detected.
+
+ 2.00.06 24/11/1994 PBA
+
+ Added support for PCI adapters.
+
+ -- Special -----------------------------------------------------------------
+
+ 2.00.05a 11/01/1995 PBA
+
+ As 2.00.05 but has support for PCMCIA adapters. Shipped
+ to Jameel Hyder at Microsoft for NT 3.51 beta.
+ MDGMPORT 1.06.80.
+
+ ----------------------------------------------------------------------------
+
+ 2.00.05 23/11/1994 PBA
+
+ Shipped to Microsoft for possible inclusion in the
+ next NT release. MDGMPORT v1.06.50.
+
+ 2.00.04 23/11/1994 PBA
+
+ Added support for ISA PnP adapters.
+
+ 2.00.03 22/11/1994 PBA
+
+ Changed the RX/TX slot list to range from 2/2 to 10/10
+ to try and alleviate Microsoft's multi-adapter problems.
+
+ 2.00.02 21/10/1994 PBA
+
+ Changed the RX/TX slot default to 4/4 to try and alleviate
+ some of Microsoft's multi-adapter memory problems.
+
+ 2.00.01 20/09/1994 PBA
+
+ Major re-write to use our NetDetect DLL.
+ No PCI support at the moment.
+
+ 1.05 Reserved for release 4.3(1)
+
+ 1.04 08/11/1994 PBA
+
+ Re-release for PCI release 4.2(3). MdgMPort.SYS
+ version 1.03.
+
+ 1.03 28/09/1994 PBA
+
+ Released for the PCI release 4.2(3). MdgMPort.SYS
+ version 1.03.
+
+ 1.02.50 28/09/1994 PBA
+
+ Added support for PCI.
+
+ Due to the problems with FastMAC Plus a re-release with a new FastMAC
+ plus image will be needed for LSS 4.30. This release will be based on
+ 1.02.02 which is the same as the earlier LSS 4.30 with some minor bug
+ fixes. Live development continues with 1.02.50.
+
+ 1.02.02 02/09/1994 PBA
+
+ Added support for setting promiscuous mode from the
+ dialog box.
+
+ 1.02.01 31/08/1994 PBA
+
+ Source shipped to Microsoft.
+
+ 1.02 24/08/1994 PBA
+
+ Re-released for 4.3. For use with MdgMPort.SYS v1.02.
+
+ 1.01.03 16/08/1994 PBA
+
+ Re-arranged the order of some of the sections and arranged
+ for all of the files to be copied in one go rather than
+ DLL and HELP and then driver later. Also set the file
+ sizes accurately in the file sections. Hopefully this may
+ make the file work under MCL's build of Daytona.
+
+ 1.01.02 15/08/1994 PBA
+
+ It looks possible that under later builds of Daytona we
+ may be called with DoCopy set to NO. To make sure we copy
+ the help and DLL files we ignore the value of DoCopy and
+ always do the copy.
+
+ 1.01.01 10/08/1994 PBA
+
+ Now has a multiprocessor PIO option.
+
+ 1.01 22/07/1994 PBA
+
+ Released for 4.30 for MdgMPort.SYS 1.01.
+
+ 1.00.04 19/07/1994 PBA
+
+ Increased the default maximum frame size to 4096 bytes.
+
+ 1.00.03 11/07/1994 PBA
+
+ Fixed bug where the MCA adapter enumeration code did not
+ merge two lists properly so if there where MC16 and MC32
+ adapters present the installation didn't work properly.
+
+ 1.00.02 28/06/1994 PBA
+
+ Fixed update option. Now copies .dll and .hlp files as
+ well as binaries. Displays error message if user tries
+ to update the hardware.
+
+ 1.00.01 23/06/1994 PBA
+
+ First version derived from 1.01.02 for MdgNT.SYS.
+
+--------------------------------------------------------------------------*/
+
+/******** End of OEMSETUP.UPD *********************************************/
+
+ \ No newline at end of file
diff --git a/private/ntos/ndis/madge/dll/sources b/private/ntos/ndis/madge/dll/sources
new file mode 100644
index 000000000..192a7f7cf
--- /dev/null
+++ b/private/ntos/ndis/madge/dll/sources
@@ -0,0 +1,42 @@
+!if 0
+
+ Copyright (C) 1992-1995 by Digital Equipment Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the MADGE NDIS3 miniport driver being built
+ and the list of sources files needed to build it.
+ It specifies also the compiler switches specific to this driver
+
+Author:
+
+!endif
+
+TARGETNAME=MDGMPDLG
+TARGETTYPE=DYNLINK
+
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\kernel32.lib
+
+INCLUDES=..\..\..\inc;$(BASEDIR)\public\sdk\inc
+C_DEFINES=$(C_DEFINES) -DNDIS_NT=1
+
+#MSC_WARNING_LEVEL=/W3 /WX
+MSC_WARNING_LEVEL=/W3
+
+SOURCES=mdgmpdlg.c \
+ mdgmpdlg.rc
+
+DLLBASE=0x1C000000
+
+DLLENTRY=_CRT_INIT
+
+USE_CRTDLL=1 # (link with crtdll.lib)
+
+MAKEDLL=1
+
+NTTARGETFILES=mdgmpdlg.hlp
diff --git a/private/ntos/ndis/madge/dll/tlmadge.ico b/private/ntos/ndis/madge/dll/tlmadge.ico
new file mode 100644
index 000000000..50d82343b
--- /dev/null
+++ b/private/ntos/ndis/madge/dll/tlmadge.ico
Binary files differ
diff --git a/private/ntos/ndis/madge/dll/trmadge.ico b/private/ntos/ndis/madge/dll/trmadge.ico
new file mode 100644
index 000000000..6d650c9fd
--- /dev/null
+++ b/private/ntos/ndis/madge/dll/trmadge.ico
Binary files differ
diff --git a/private/ntos/ndis/madge/dll/uilstf.h b/private/ntos/ndis/madge/dll/uilstf.h
new file mode 100644
index 000000000..562975e2c
--- /dev/null
+++ b/private/ntos/ndis/madge/dll/uilstf.h
@@ -0,0 +1,481 @@
+/***************************************************************************/
+/*********************** include file for UI Library *********************/
+/***************************************************************************/
+
+#define STF_MESSAGE (WM_USER + 0x8000)
+
+/*
+** Window Messages
+*/
+_dt_public
+#define STF_UI_EVENT (STF_MESSAGE)
+_dt_public
+#define STF_DESTROY_DLG (STF_MESSAGE + 1)
+_dt_public
+#define STF_HELP_DLG_DESTROYED (STF_MESSAGE + 2)
+_dt_public
+#define STF_INFO_DLG_DESTROYED (STF_MESSAGE + 3)
+_dt_public
+#define STF_EDIT_DLG_DESTROYED (STF_MESSAGE + 4)
+_dt_public
+#define STF_RADIO_DLG_DESTROYED (STF_MESSAGE + 5)
+_dt_public
+#define STF_CHECK_DLG_DESTROYED (STF_MESSAGE + 6)
+_dt_public
+#define STF_LIST_DLG_DESTROYED (STF_MESSAGE + 7)
+_dt_public
+#define STF_MULTI_DLG_DESTROYED (STF_MESSAGE + 8)
+_dt_public
+#define STF_QUIT_DLG_DESTROYED (STF_MESSAGE + 9)
+_dt_public
+#define STF_DLG_ACTIVATE (STF_MESSAGE + 10)
+_dt_public
+#define STF_UILIB_ACTIVATE (STF_MESSAGE + 11)
+_dt_public
+#define STF_REINITDIALOG (STF_MESSAGE + 12)
+_dt_public
+#define STF_SHL_INTERP (STF_MESSAGE + 13)
+_dt_hidden
+#define STF_COMBO_DLG_DESTROYED (STF_MESSAGE + 14)
+_dt_hidden
+#define STF_MULTICOMBO_DLG_DESTROYED (STF_MESSAGE + 15)
+_dt_hidden
+#define STF_DUAL_DLG_DESTROYED (STF_MESSAGE + 16)
+_dt_hidden
+#define STF_MULTICOMBO_RADIO_DLG_DESTROYED (STF_MESSAGE + 17)
+_dt_hidden
+#define STF_MAINT_DLG_DESTROYED (STF_MESSAGE + 18)
+
+
+_dt_hidden
+#define STF_SET_INSTRUCTION_TEXT (STF_MESSAGE + 0x100)
+
+_dt_hidden
+#define STF_SET_HELP_CONTEXT (STF_MESSAGE + 0x101)
+
+_dt_hidden
+#define STF_ENABLE_EXIT_BUTTON (STF_MESSAGE + 0x102)
+
+_dt_hidden
+#define STF_ERROR_ABORT (STF_MESSAGE + 0x103)
+
+
+
+
+//
+// Button IDS to communicate help and exit button messages to shell
+//
+#define ID_EXITBUTTON 7
+#define ID_HELPBUTTON 8
+
+
+/*
+** Symbols used by Basic Dialog Class procedures
+*/
+
+#define CLS_MYDLGS "mydlg"
+#define DLGTEXT "DlgText"
+#define DLGCAPTION "Caption"
+#define DLGTYPE "DlgType"
+#define DLGTEMPLATE "DlgTemplate"
+
+
+
+#define INSTRUCTIONTEXT "InstructionText"
+#define HELPCONTEXT "HelpContext"
+#define EXITSTATE "ExitState"
+
+#define EXIT_ENABLE "Active"
+#define EXIT_DISABLE "Inactive"
+
+
+/*
+** PushButton Control IDs
+*/
+_dt_public
+#define IDC_A 401
+_dt_public
+#define IDC_B 402
+_dt_public
+#define IDC_C 403
+_dt_public
+#define IDC_D 404
+_dt_public
+#define IDC_E 405
+_dt_public
+#define IDC_F 406
+_dt_public
+#define IDC_G 407
+_dt_public
+#define IDC_H 408
+_dt_public
+#define IDC_I 409
+_dt_public
+#define IDC_J 410
+_dt_public
+#define IDC_K 411
+_dt_public
+#define IDC_L 412
+_dt_public
+#define IDC_M 413
+_dt_public
+#define IDC_N 414
+_dt_public
+#define IDC_O 415
+_dt_public
+#define IDC_P 416
+_dt_public
+#define IDC_Q 417
+_dt_public
+#define IDC_R 418
+_dt_public
+#define IDC_S 419
+_dt_public
+#define IDC_T 420
+_dt_public
+#define IDC_U 421
+_dt_public
+#define IDC_V 422
+_dt_public
+#define IDC_W 423
+_dt_public
+#define IDC_X 424
+_dt_public
+#define IDC_Y 425
+_dt_public
+#define IDC_Z 426
+
+
+/*
+** Text Control IDs
+*/
+_dt_public
+#define IDC_TEXT1 431
+_dt_public
+#define IDC_TEXT2 432
+_dt_public
+#define IDC_TEXT3 433
+_dt_public
+#define IDC_TEXT4 434
+_dt_public
+#define IDC_TEXT5 435
+_dt_public
+#define IDC_TEXT6 436
+_dt_public
+#define IDC_TEXT7 437
+_dt_public
+#define IDC_TEXT8 438
+_dt_public
+#define IDC_TEXT9 439
+_dt_public
+#define IDC_TEXT10 440
+_dt_public
+#define IDC_TEXT11 441
+
+
+/*
+** Radio and Checkbox Button Control IDs
+*/
+_dt_public
+#define IDC_B0 450
+_dt_public
+#define IDC_B1 451
+_dt_public
+#define IDC_B2 452
+_dt_public
+#define IDC_B3 453
+_dt_public
+#define IDC_B4 454
+_dt_public
+#define IDC_B5 455
+_dt_public
+#define IDC_B6 456
+_dt_public
+#define IDC_B7 457
+_dt_public
+#define IDC_B8 458
+_dt_public
+#define IDC_B9 459
+_dt_public
+#define IDC_B10 460
+
+_dt_public
+#define IDC_RB0 610
+_dt_public
+#define IDC_RB1 611
+_dt_public
+#define IDC_RB2 612
+_dt_public
+#define IDC_RB3 613
+_dt_public
+#define IDC_RB4 614
+_dt_public
+#define IDC_RB5 615
+_dt_public
+#define IDC_RB6 616
+_dt_public
+#define IDC_RB7 617
+_dt_public
+#define IDC_RB8 618
+_dt_public
+#define IDC_RB9 619
+_dt_public
+#define IDC_RB10 620
+
+/*
+** Generic Dialog Button IDs
+*/
+
+_dt_public
+#define IDC_BTN0 630
+_dt_public
+#define IDC_BTN1 631
+_dt_public
+#define IDC_BTN2 632
+_dt_public
+#define IDC_BTN3 633
+_dt_public
+#define IDC_BTN4 634
+_dt_public
+#define IDC_BTN5 635
+_dt_public
+#define IDC_BTN6 636
+_dt_public
+#define IDC_BTN7 637
+_dt_public
+#define IDC_BTN8 638
+_dt_public
+#define IDC_BTN9 639
+
+
+/*
+** Combo box IDs
+*/
+_dt_public
+#define IDC_COMBO0 480
+_dt_public
+#define IDC_COMBO1 481
+_dt_public
+#define IDC_COMBO2 482
+_dt_public
+#define IDC_COMBO3 483
+_dt_public
+#define IDC_COMBO4 484
+_dt_public
+#define IDC_COMBO5 485
+_dt_public
+#define IDC_COMBO6 486
+_dt_public
+#define IDC_COMBO7 487
+_dt_public
+#define IDC_COMBO8 488
+_dt_public
+#define IDC_COMBO9 489
+
+/*
+** ICON IDs
+*/
+_dt_public
+#define IDC_ICON0 500
+_dt_public
+#define IDC_ICON1 501
+_dt_public
+#define IDC_ICON2 502
+_dt_public
+#define IDC_ICON3 503
+_dt_public
+#define IDC_ICON4 504
+_dt_public
+#define IDC_ICON5 505
+_dt_public
+#define IDC_ICON6 506
+_dt_public
+#define IDC_ICON7 507
+_dt_public
+#define IDC_ICON8 508
+_dt_public
+#define IDC_ICON9 509
+
+/*
+** SPECIAL PUSHBUTTONS
+*/
+
+_dt_public
+#define IDC_SP1 521
+_dt_public
+#define IDC_SP2 522
+_dt_public
+#define IDC_SP3 523
+_dt_public
+#define IDC_SP4 524
+_dt_public
+#define IDC_SP5 525
+_dt_public
+#define IDC_SP6 526
+_dt_public
+#define IDC_SP7 527
+_dt_public
+#define IDC_SP8 528
+_dt_public
+#define IDC_SP9 529
+_dt_public
+#define IDC_SP10 530
+
+/*
+** STATUS TEXT FIELDS
+*/
+
+_dt_public
+#define IDC_STATUS1 541
+_dt_public
+#define IDC_STATUS2 542
+_dt_public
+#define IDC_STATUS3 543
+_dt_public
+#define IDC_STATUS4 544
+_dt_public
+#define IDC_STATUS5 545
+_dt_public
+#define IDC_STATUS6 546
+_dt_public
+#define IDC_STATUS7 547
+_dt_public
+#define IDC_STATUS8 548
+_dt_public
+#define IDC_STATUS9 549
+_dt_public
+#define IDC_STATUS10 550
+
+
+
+/*
+** SIZE FIELDS ASSOCIATED WITH CHECK OPTIONAL COMPONENTS
+*/
+
+_dt_public
+#define IDC_SIZE1 551
+_dt_public
+#define IDC_SIZE2 552
+_dt_public
+#define IDC_SIZE3 553
+_dt_public
+#define IDC_SIZE4 554
+_dt_public
+#define IDC_SIZE5 555
+_dt_public
+#define IDC_SIZE6 556
+_dt_public
+#define IDC_SIZE7 557
+_dt_public
+#define IDC_SIZE8 558
+_dt_public
+#define IDC_SIZE9 559
+_dt_public
+#define IDC_SIZE10 560
+
+
+
+/*
+** TOTALS OF SIZES
+*/
+
+_dt_public
+#define IDC_TOTAL1 561
+_dt_public
+#define IDC_TOTAL2 562
+_dt_public
+#define IDC_TOTAL3 563
+_dt_public
+#define IDC_TOTAL4 564
+_dt_public
+#define IDC_TOTAL5 565
+_dt_public
+#define IDC_TOTAL6 566
+_dt_public
+#define IDC_TOTAL7 567
+_dt_public
+#define IDC_TOTAL8 568
+_dt_public
+#define IDC_TOTAL9 569
+_dt_public
+#define IDC_TOTAL10 570
+
+/*
+** MAXIMUM SIZES
+*/
+
+_dt_public
+#define IDC_MAX1 571
+_dt_public
+#define IDC_MAX2 572
+_dt_public
+#define IDC_MAX3 573
+_dt_public
+#define IDC_MAX4 574
+_dt_public
+#define IDC_MAX5 575
+_dt_public
+#define IDC_MAX6 576
+_dt_public
+#define IDC_MAX7 577
+_dt_public
+#define IDC_MAX8 578
+_dt_public
+#define IDC_MAX9 579
+_dt_public
+#define IDC_MAX10 580
+
+/*
+** Edit Control IDs
+*/
+
+#define IDC_EDIT1 581
+#define IDC_EDIT2 582
+#define IDC_EDIT3 583
+#define IDC_EDIT4 584
+#define IDC_EDIT5 585
+#define IDC_EDIT6 586
+#define IDC_EDIT7 587
+#define IDC_EDIT8 588
+#define IDC_EDIT9 589
+#define IDC_EDIT10 590
+
+/*
+** ListBox Control IDs
+*/
+
+#define IDC_LIST1 591
+#define IDC_LIST2 592
+#define IDC_LIST3 593
+#define IDC_LIST4 594
+#define IDC_LIST5 595
+#define IDC_LIST6 596
+#define IDC_LIST7 597
+#define IDC_LIST8 598
+#define IDC_LIST9 599
+#define IDC_LIST10 600
+
+
+/*
+** MENU IDS
+*/
+
+#define ID_MAINTAIN 651
+
+
+/*
+** ID_MAINTAIN MENU IDS
+*/
+
+#define MENU_CHANGE 701
+#define MENU_INSTALL 702
+#define MENU_ADD_REMOVE 703
+#define MENU_EXIT 704
+#define MENU_HELPINDEX 705
+#define MENU_HELPSEARCH 706
+#define MENU_HELPONHELP 708
+#define MENU_HELPONLINE 709
+#define MENU_ABOUT 710
+#define MENU_PROFILE 711
+#define MENU_ADD_REMOVE_SCSI 712
+#define MENU_ADD_REMOVE_TAPE 713
diff --git a/private/ntos/ndis/madge/driver/dispatch.c b/private/ntos/ndis/madge/driver/dispatch.c
new file mode 100644
index 000000000..593ef071d
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/dispatch.c
@@ -0,0 +1,919 @@
+/***************************************************************************
+*
+* DISPATCH.C
+*
+* FastMAC Plus based NDIS3 miniport driver dispatch routines. This module
+* contains all of the upper interface functions that are not purely
+* for initialization and closedown (i.e. DriverEntry, MadgeInitialize
+* and MadgeHalt) excluding MadgeSetInformation and MadgeQueryInformation.
+*
+* Copyright (c) Madge Networks Ltd 1994
+*
+* COMPANY CONFIDENTIAL
+*
+* Created: PBA 21/06/1994
+*
+****************************************************************************/
+
+#include <ndis.h>
+
+#include "ftk_defs.h"
+#include "ftk_intr.h"
+#include "ftk_extr.h"
+
+#include "mdgmport.upd"
+#include "ndismod.h"
+
+
+/****************************************************************************
+*
+* Function - MadgeGetAdapterStatus
+*
+* Parameters - systemSpecific1 -> Unused.
+* context -> Actually a pointer to our NDIS3 level
+* adapter structure.
+* systemSpecific2 -> Unused.
+* systemSpecific3 -> Unused.
+*
+* Purpose - This function is called of a timer tick and notifies
+* open bindings of any interesting events.
+*
+* Returns - Nothing.
+*
+****************************************************************************/
+
+VOID
+MadgeGetAdapterStatus(
+ PVOID systemSpecific1,
+ PVOID context,
+ PVOID systemSpecific2,
+ PVOID systemSpecific3
+ )
+{
+ PMADGE_ADAPTER ndisAdap;
+ NDIS_STATUS notifyStatus;
+ WORD ringStatus;
+
+ //
+ // Do some pre-calculation.
+ //
+
+ ndisAdap = (PMADGE_ADAPTER) context;
+ notifyStatus = 0;
+ ringStatus = ndisAdap->CurrentRingStatus;
+
+ if (ndisAdap->CurrentRingState == NdisRingStateOpened)
+ {
+ //
+ // WARNING: If the adapter has been shutdown, this will return zero
+ // in the two fields.
+ //
+
+ driver_get_open_and_ring_status(
+ ndisAdap->FtkAdapterHandle,
+ &ndisAdap->CurrentRingStatus,
+ &ndisAdap->LastOpenStatus
+ );
+
+ if (ringStatus != ndisAdap->CurrentRingStatus)
+ {
+ if (ndisAdap->CurrentRingStatus & RING_STATUS_RING_RECOVERY)
+ {
+ notifyStatus |= NDIS_RING_RING_RECOVERY;
+ }
+
+ if (ndisAdap->CurrentRingStatus & RING_STATUS_SINGLE_STATION)
+ {
+ notifyStatus |= NDIS_RING_SINGLE_STATION;
+ }
+
+ if (ndisAdap->CurrentRingStatus & RING_STATUS_COUNTER_OVERFLOW)
+ {
+ notifyStatus |= NDIS_RING_COUNTER_OVERFLOW;
+ }
+
+ if (ndisAdap->CurrentRingStatus & RING_STATUS_REMOVE_RECEIVED)
+ {
+ notifyStatus |= NDIS_RING_REMOVE_RECEIVED;
+ }
+
+ if (ndisAdap->CurrentRingStatus & RING_STATUS_AUTO_REMOVAL)
+ {
+ notifyStatus |= NDIS_RING_AUTO_REMOVAL_ERROR;
+ }
+
+ if (ndisAdap->CurrentRingStatus & RING_STATUS_LOBE_FAULT)
+ {
+ notifyStatus |= NDIS_RING_LOBE_WIRE_FAULT;
+ }
+
+ if (ndisAdap->CurrentRingStatus & RING_STATUS_TRANSMIT_BEACON)
+ {
+ notifyStatus |= NDIS_RING_TRANSMIT_BEACON;
+ }
+
+ if (ndisAdap->CurrentRingStatus & RING_STATUS_SOFT_ERROR)
+ {
+ notifyStatus |= NDIS_RING_SOFT_ERROR;
+ }
+
+ if (ndisAdap->CurrentRingStatus & RING_STATUS_HARD_ERROR)
+ {
+ notifyStatus |= NDIS_RING_HARD_ERROR;
+ }
+
+ if (ndisAdap->CurrentRingStatus & RING_STATUS_SIGNAL_LOSS)
+ {
+ notifyStatus |= NDIS_RING_SIGNAL_LOSS;
+ }
+
+ if (notifyStatus != 0)
+ {
+ NdisMIndicateStatus(
+ ndisAdap->UsedInISR.MiniportHandle,
+ NDIS_STATUS_RING_STATUS,
+ (PVOID) &notifyStatus,
+ sizeof(notifyStatus)
+ );
+
+ NdisMIndicateStatusComplete(
+ ndisAdap->UsedInISR.MiniportHandle
+ );
+
+ MadgePrint2(
+ "Ring Status %04x\n", ndisAdap->CurrentRingStatus);
+ }
+ }
+ }
+
+ //
+ // Just before we go, clear the JustReadErrorLog flag, so that requests
+ // for statistics will cause an SRB to be issued every now and then.
+ //
+
+ ndisAdap->JustReadErrorLog = 0;
+
+ //
+ // And finally re-arm the timer.
+ //
+
+ NdisMSetTimer(&ndisAdap->WakeUpTimer, EVERY_2_SECONDS);
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeCheckForHang
+*
+* Parameters - adapterContext -> A pointer to our NDIS adapter structure.
+*
+* Purpose - Process a call from the NDIS3 wrapper to check if
+* an adapter has hung.
+*
+* Returns - We always return FALSE since the only action the wrapper
+* can take is to invoke a reset, which we don't support
+* anyway.
+*
+****************************************************************************/
+
+BOOLEAN
+MadgeCheckForHang(NDIS_HANDLE adapterContext)
+{
+ return FALSE;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeReset
+*
+* Parameters - adapterContext -> A pointer to our NDIS adapter structure.
+* addressReset -> Ignored.
+*
+* Purpose - Process a call from the NDIS3 wrapper to reset an
+* adapter.
+*
+* Returns - NDIS_STATUS_NOT_RESETTABLE as we don't support resets.
+*
+****************************************************************************/
+
+NDIS_STATUS
+MadgeReset(PBOOLEAN addressReset, NDIS_HANDLE adapterContext)
+{
+ MadgePrint1("MadgeReset\n");
+
+ MadgePrint2(
+ "ndisAdap = %x\n",
+ PMADGE_ADAPTER_FROM_CONTEXT(adapterContext)
+ );
+
+ return NDIS_STATUS_NOT_RESETTABLE;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeDisableInterrupts
+*
+* Parameters - adapterContext -> A pointer to our NDIS adapter structure.
+*
+* Purpose - Process a call from the NDIS3 wrapper to turn adapter
+* interrupts off.
+*
+* Returns - Nothing.
+*
+****************************************************************************/
+
+VOID
+MadgeDisableInterrupts(NDIS_HANDLE adapterContext)
+{
+// MadgePrint1("MadgeDisableInterrupts\n");
+
+ //
+ // Note: it is very difficult for use to disble interrupts at the
+ // adapter so we don't. We use a spin lock to protect our DPR
+ // routine.
+ //
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeEnableInterrupts
+*
+* Parameters - adapterContext -> A pointer to our NDIS adapter structure.
+*
+* Purpose - Process a call from the NDIS3 wrapper to turn adapter
+* interrupts on.
+*
+* Returns - Nothing.
+*
+****************************************************************************/
+
+VOID
+MadgeEnableInterrupts(NDIS_HANDLE adapterContext)
+{
+// MadgePrint1("MadgeEnableInterrupts\n");
+
+ //
+ // Note: it is very difficult for use to disble interrupts at the
+ // adapter so we don't. We use a spin lock to protect our DPR
+ // routine.
+ //
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeSend
+*
+* Parameters - adapterContext -> Pointer to our NDIS level adapter
+* structure.
+* packet -> Pointer to the NDIS3 packet to send.
+* flags -> Optional flags.
+*
+* Purpose - Called by the NDIS3 wrapper when it wants us to send a
+* frame.
+*
+* Returns - NDIS3 status code.
+*
+****************************************************************************/
+
+NDIS_STATUS
+MadgeSend(NDIS_HANDLE adapterContext, PNDIS_PACKET packet, UINT flags)
+{
+ ULONG *pagePtr;
+ UINT pageCount;
+ UINT physFrags;
+ UINT i;
+ UINT size;
+ UINT bytes;
+ UINT count;
+ NDIS_BUFFER *bufPtr;
+ NDIS_STATUS retCode;
+ PMADGE_ADAPTER ndisAdap;
+ UINT totalPacketSize;
+ WORD status;
+
+ //
+ // Set up a pointer to our adapter handle.
+ //
+
+ ndisAdap = PMADGE_ADAPTER_FROM_CONTEXT(adapterContext);
+
+ //
+ // Find out how long the frame is and where it's header is.
+ //
+
+ NdisQueryPacket(packet, NULL, NULL, NULL, &totalPacketSize);
+
+ //
+ // Make sure the frame isn't too long or two short.
+ //
+
+ if (totalPacketSize > ndisAdap->MaxFrameSize ||
+ totalPacketSize < FRAME_HEADER_SIZE)
+ {
+ retCode = NDIS_STATUS_INVALID_PACKET;
+ }
+
+ //
+ // Check that a PCMCIA adapter is still physically present.
+ //
+
+ else if (ndisAdap->AdapterRemoved)
+ {
+ MadgePrint1("MadgeSend aborting - adapter removed\n");
+ retCode = NDIS_STATUS_SUCCESS;
+ }
+
+ //
+ // Otherwise we need to send the frame over the ring.
+ //
+
+ else
+ {
+ status = rxtx_transmit_frame(
+ ndisAdap->FtkAdapterHandle,
+ (DWORD) packet,
+ (WORD) totalPacketSize,
+ TRUE
+ );
+
+ //
+ // Check if the frame has been transmitted completely.
+ //
+
+ if (status == DRIVER_TRANSMIT_SUCCEED)
+ {
+ ndisAdap->FramesTransmitted++;
+ retCode = NDIS_STATUS_SUCCESS;
+
+#ifdef OID_MADGE_MONITOR
+ //
+ // Update the appropriate parts of the monitor structure
+ //
+
+ (ndisAdap->MonitorInfo).TransmitFrames++;
+ (ndisAdap->MonitorInfo).TransmitFrameSize[totalPacketSize/128]++;
+
+ //
+ // Find the number of physical fragments sent
+ //
+
+ NdisQueryPacket(packet,
+ NULL,
+ NULL,
+ &bufPtr,
+ &totalPacketSize);
+
+ physFrags = 0;
+ count = 0;
+
+ while (bufPtr != NULL)
+ {
+ MDL *mdl = (MDL *) bufPtr;
+
+ count++;
+ pageCount = (((MDL *) bufPtr)->Size - sizeof(MDL)) / sizeof(ULONG);
+ pagePtr = (ULONG *) (((MDL *) bufPtr) + 1);
+
+ physFrags++; // First page.
+
+ bytes = mdl->ByteCount;
+
+ if (pageCount <= 1)
+ {
+ size = bytes;
+ }
+ else
+ {
+ size = 4096 - mdl->ByteOffset;
+ bytes -= size;
+ }
+
+ for (i = 1; i < pageCount; i++)
+ {
+ if (pagePtr[i] != pagePtr[i - 1] + 1)
+ {
+ size = 0;
+ physFrags++;
+ }
+
+ if (i == pageCount - 1)
+ {
+ size += bytes;
+ }
+ else
+ {
+ bytes -= 4096;
+ size += 4096;
+ }
+
+ }
+
+ NdisGetNextBuffer(bufPtr, &bufPtr);
+ }
+
+ if (count < 65)
+ {
+ (ndisAdap->MonitorInfo).NumberOfVFrags[count]++;
+ }
+
+ if (physFrags < 65)
+ {
+ (ndisAdap->MonitorInfo).NumberOfPFrags[physFrags]++;
+ }
+#endif
+ }
+
+ //
+ // Or not transmitted at all, in which case we must
+ // queue it for later.
+ //
+
+ else
+ {
+ retCode = NDIS_STATUS_RESOURCES;
+ }
+ }
+
+ return retCode;
+}
+
+
+/***************************************************************************
+*
+* Function - MadgeCopyFromPacketToBuffer
+*
+* Parameters - packet -> The NDIS3 packet to copy.
+* offset -> Starting offset into the packet.
+* bytesToCopy -> Number of bytes to copy.
+* destPtr -> Pointer to the destination buffer.
+* bytesCopied -> Pointer to a holder for the number of
+* bytes actually copied.
+*
+* Purpose - Copy data from an NDIS3 packet into a buffer.
+*
+* Returns - Nothing.
+*
+****************************************************************************/
+
+VOID
+MadgeCopyFromPacketToBuffer(
+ PNDIS_PACKET packet,
+ UINT offset,
+ UINT bytesToCopy,
+ PCHAR destPtr,
+ PUINT bytesCopied
+ )
+{
+ UINT bufferCount;
+ PNDIS_BUFFER currentBuffer;
+ PVOID currentPtr;
+ UINT currentLength;
+ UINT amountToMove;
+ UINT localBytesCopied;
+
+ *bytesCopied = 0;
+ localBytesCopied = 0;
+
+ if (bytesToCopy == 0)
+ {
+ return;
+ }
+
+ NdisQueryPacket(packet, NULL, &bufferCount, &currentBuffer, NULL);
+ if (bufferCount == 0)
+ {
+ return;
+ }
+
+ NdisQueryBuffer(currentBuffer, &currentPtr, &currentLength);
+
+ while (localBytesCopied < bytesToCopy)
+ {
+ if (currentLength == 0)
+ {
+ NdisGetNextBuffer(currentBuffer, &currentBuffer);
+ if (currentBuffer == 0)
+ {
+ break;
+ }
+
+ NdisQueryBuffer(currentBuffer, &currentPtr, &currentLength);
+ continue;
+ }
+
+ if (offset > 0)
+ {
+ if (offset > currentLength)
+ {
+ offset -= currentLength;
+ currentLength = 0;
+ continue;
+ }
+ else
+ {
+ currentPtr = (PCHAR) currentPtr + offset;
+ currentLength -= offset;
+ offset = 0;
+ }
+ }
+
+ amountToMove =
+ (currentLength <= (bytesToCopy - localBytesCopied))
+ ? currentLength
+ : bytesToCopy - localBytesCopied;
+
+ MADGE_MOVE_MEMORY(destPtr, currentPtr, amountToMove);
+
+ destPtr = (PCHAR) destPtr + amountToMove;
+ currentPtr = (PCHAR) currentPtr + amountToMove;
+
+ localBytesCopied += amountToMove;
+ currentLength -= amountToMove;
+ }
+
+ *bytesCopied = localBytesCopied;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeTransferData
+*
+* Parameters - adapterContext -> Pointer to our NDIS level adapter
+* structure.
+* receiveContext -> Pointer to the start of the frame data.
+* byteOffset -> Offset to start copying from.
+* bytesToTransfer -> Number of bytes to copy.
+* packet -> NDIS packet for the data.
+* bytesTransferred -> Pointer to a holder for the number of
+* bytes actually copied.
+*
+* Purpose - Copy data from the received frame just indicated into an
+* NDIS packet. This function is called by the NDIS3 wrapper
+* in response to our indication frame rxtx_irq_received_frame.
+*
+* Returns - An NDIS3 status code.
+*
+****************************************************************************/
+
+NDIS_STATUS
+MadgeTransferData(
+ PNDIS_PACKET packet,
+ PUINT bytesTransferred,
+ NDIS_HANDLE adapterContext,
+ NDIS_HANDLE receiveContext,
+ UINT byteOffset,
+ UINT bytesToTransfer
+ )
+{
+ PMADGE_ADAPTER ndisAdap;
+ NDIS_STATUS retCode;
+
+ //
+ // Pre-calculate some values.
+ //
+
+ ndisAdap = PMADGE_ADAPTER_FROM_CONTEXT(adapterContext);
+
+ //
+ // Check that the data pointer is valid.
+ //
+
+ if ((PCHAR) receiveContext == NULL)
+ {
+ retCode = NDIS_STATUS_FAILURE;
+ }
+
+ //
+ // If it is, copy from the frame from the receive buffer
+ // into the packet.
+ //
+
+ else
+ {
+ MadgeCopyFromBufferToPacket(
+ (PCHAR) receiveContext + byteOffset,
+ bytesToTransfer,
+ packet,
+ 0,
+ bytesTransferred
+ );
+
+ retCode = NDIS_STATUS_SUCCESS;
+
+#ifdef OID_MADGE_MONITOR
+ //
+ // Update the appropriate parts of the monitor structure
+ //
+ if ((ndisAdap->MonitorInfo).ReceiveFlag > 0)
+ {
+ (ndisAdap->MonitorInfo).TransferFrames++;
+ (ndisAdap->MonitorInfo).TransferFrameSize[(ndisAdap->MonitorInfo).CurrentFrameSize/128]++;
+ (ndisAdap->MonitorInfo).ReceiveFlag = 0;
+ }
+#endif
+
+ }
+
+ return retCode;
+}
+
+
+/***************************************************************************
+*
+* Function - MadgeCopyFromBufferToPacket
+*
+* Parameters - srcPtr -> Pointer to the source buffer.
+* bytesToCopy -> Number of bytes to copy.
+* packet -> The NDIS3 destination packet.
+* offset -> Starting offset into the buffer.
+* bytesCopied -> Pointer to a holder for the number of
+* bytes actually copied.
+*
+* Purpose - Copy data from a buffer into an NDIS3 packet.
+*
+* Returns - Nothing.
+*
+****************************************************************************/
+
+VOID
+MadgeCopyFromBufferToPacket(
+ PCHAR srcPtr,
+ UINT bytesToCopy,
+ PNDIS_PACKET packet,
+ UINT offset,
+ PUINT bytesCopied
+ )
+{
+ UINT bufferCount;
+ PNDIS_BUFFER currentBuffer;
+ PVOID virtualAddress;
+ UINT currentLength;
+ UINT amountToMove;
+ UINT localBytesCopied;
+
+ *bytesCopied = 0;
+ localBytesCopied = 0;
+
+ if (bytesToCopy == 0)
+ {
+ return;
+ }
+
+ NdisQueryPacket(packet, NULL, &bufferCount, &currentBuffer, NULL);
+ if (bufferCount == 0)
+ {
+ return;
+ }
+
+ NdisQueryBuffer(currentBuffer, &virtualAddress, &currentLength);
+
+ while (localBytesCopied < bytesToCopy)
+ {
+ if (currentLength == 0)
+ {
+ NdisGetNextBuffer(currentBuffer, &currentBuffer);
+ if (currentBuffer == NULL)
+ {
+ break;
+ }
+
+ NdisQueryBuffer(currentBuffer, &virtualAddress, &currentLength);
+ continue;
+ }
+
+ if (offset > 0)
+ {
+ if (offset > currentLength)
+ {
+ offset -= currentLength;
+ currentLength = 0;
+ continue;
+ }
+ else
+ {
+ virtualAddress = (PCHAR) virtualAddress + offset;
+ currentLength -= offset;
+ offset = 0;
+ }
+ }
+
+ amountToMove = (bytesToCopy - localBytesCopied < currentLength)
+ ? bytesToCopy - localBytesCopied
+ : currentLength;
+
+ MADGE_MOVE_MEMORY(
+ virtualAddress,
+ srcPtr,
+ amountToMove
+ );
+
+ srcPtr += amountToMove;
+ localBytesCopied += amountToMove;
+ currentLength -= amountToMove;
+ }
+
+ *bytesCopied = localBytesCopied;
+}
+
+
+/***************************************************************************
+*
+* Function - MadgeISR
+*
+* Parameters - interruptRecognised -> Pointer to an interrupt recognised
+* flag we set if we recognise the
+* interrupt.
+* queueDPR -> Pointer to DPR required flag we
+* set if we need a DPR.
+* adapterContext -> Pointer to our NDIS level adapter
+* structure.
+*
+* Purpose - Process an IRQ from an adapter. All we do is call the
+* HWI and schedule a DPR if required.
+*
+* Returns - Nothing.
+*
+****************************************************************************/
+
+VOID
+MadgeISR(
+ PBOOLEAN interruptRecognised,
+ PBOOLEAN queueDPR,
+ NDIS_HANDLE adapterContext
+ )
+{
+ PMADGE_ADAPTER ndisAdap;
+
+ ndisAdap = PMADGE_ADAPTER_FROM_CONTEXT(adapterContext);
+
+ hwi_interrupt_entry(
+ ndisAdap->FtkAdapterHandle,
+ (WORD) ndisAdap->UsedInISR.InterruptNumber
+ );
+
+ //
+ // If ndisAdap->DprRequired is TRUE then we recognised the interrupt
+ // and found something that requires further processing (e.g. received
+ // a frame). If ndisAdap->DprRequired is FALSE then we either didn't
+ // recognise the interrupt or we don't need any further processing.
+ // The only operation that doesn't need further processing is ISA
+ // PIO. Since ISA cards cannot share interrupt lines it doesn't
+ // matter if we say we don't recognise the interrupt if we don't
+ // need any further processing. Hence we can use ndisAdap->DprRequired
+ // to set both *interruptRecognised and *queueDpr.
+ //
+
+ //
+ // However ...
+ // There is a race condition with ATULA based cards in PIO mode.
+ // Normally we do not claim interrupts that are used for PIO transfers
+ // to avoid the overhead of a DPR on PIO transfers. However, in some
+ // instances if we do not claim the PIO interrupts used for the
+ // initial "DMA" tests then WFWG (and possibly NT) permanently disables
+ // our interrupts. To get around this we claim all interrupts until
+ // our rx/tx buffers have been allocated since the optimisation of not
+ // queuing a DPR for PIO interrupts doesn't matter until we have
+ // rx/tx buffers in place.
+ //
+
+ *interruptRecognised =
+ (ndisAdap->RxTxBufferState != MADGE_RXTX_INITIALIZED)
+ ? TRUE
+ : ndisAdap->DprRequired;
+
+ *queueDPR = ndisAdap->DprRequired;
+
+ ndisAdap->DprRequired = FALSE;
+}
+
+
+/*--------------------------------------------------------------------------
+|
+| Function - MadgeSyncSRBPending
+|
+| Parameters - synchonizedContext -> A pointer to an NDIS3 level adapter
+| structure.
+|
+| Purpose - Process a completed SRBs. This routine is always
+| syncronised with IRQs.
+|
+| Returns - TRUE if the SRB has actually completed or FALSE if not.
+|
+--------------------------------------------------------------------------*/
+
+STATIC BOOLEAN
+MadgeSyncSRBPending(PVOID synchronizeContext)
+{
+ PMADGE_ADAPTER ndisAdap;
+ BOOLEAN retCode;
+
+ ndisAdap = PMADGE_ADAPTER_FROM_CONTEXT(synchronizeContext);
+ retCode = ndisAdap->UsedInISR.SrbRequestCompleted;
+
+ if (retCode)
+ {
+ ndisAdap->UsedInISR.SrbRequestCompleted = FALSE;
+ ndisAdap->SrbRequestStatus = ndisAdap->UsedInISR.SrbRequestStatus;
+ }
+
+ return retCode;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeHandleInterrupt
+*
+* Parameters - adapterContext -> Pointer to our NDIS level adapter
+* structure.
+*
+* Purpose - Our DPR routine.
+*
+* Returns - Nothing.
+*
+****************************************************************************/
+
+VOID
+MadgeHandleInterrupt(NDIS_HANDLE adapterContext)
+{
+ PMADGE_ADAPTER ndisAdap;
+
+ ndisAdap = PMADGE_ADAPTER_FROM_CONTEXT(adapterContext);
+
+ //
+ // Must do anything if we don't have tx/rx buffers.
+ //
+
+ if (ndisAdap->RxTxBufferState != MADGE_RXTX_INITIALIZED)
+ {
+ return;
+ }
+
+ //
+ // I think this check is a bit paranoid. I think DPRs are guaranteed
+ // to be single threaded. I suppose it might be needed on a multi-
+ // processor. Just 'cos your've paraonoid doesn't mean they're not
+ // out to get you!
+ //
+
+ if (!ndisAdap->DprInProgress)
+ {
+ ndisAdap->DprInProgress = TRUE;
+
+ //
+ // Handle completed SRBs first.
+ //
+
+ if (NdisMSynchronizeWithInterrupt(
+ &ndisAdap->Interrupt,
+ MadgeSyncSRBPending,
+ adapterContext))
+ {
+ MadgeCompletePendingRequest(ndisAdap);
+ }
+
+ //
+ // If the adapter has been removed then call the housekeeping
+ // function.
+ //
+
+ if (ndisAdap->AdapterRemoved)
+ {
+ rxtx_adapter_removed(ndisAdap->FtkAdapterHandle);
+ }
+
+ //
+ // Check for transmit completions.
+ //
+
+ rxtx_irq_tx_completion_check(
+ ndisAdap->FtkAdapterHandle,
+ adapter_record[ndisAdap->FtkAdapterHandle]
+ );
+
+ //
+ // See if there are any received frames.
+ //
+
+ driver_get_outstanding_receive(ndisAdap->FtkAdapterHandle);
+
+ ndisAdap->DprInProgress = FALSE;
+ }
+
+ //
+ // This else should never be executed!
+ //
+
+ else
+ {
+ MadgePrint1("DPR reentered!!!!\n");
+ }
+}
+
+/******** End of DISPATCH.C ************************************************/
+
diff --git a/private/ntos/ndis/madge/driver/drv_err.c b/private/ntos/ndis/madge/driver/drv_err.c
new file mode 100644
index 000000000..a254c8669
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/drv_err.c
@@ -0,0 +1,555 @@
+/****************************************************************************
+*
+* DRV_ERR.C : Part of the FASTMAC TOOL-KIT (FTK)
+*
+* THE ERROR EXPLANATION MODULE
+*
+* Copyright (c) Madge Networks Ltd. 1991-1993
+*
+* COMPANY CONFIDENTIAL
+*
+*****************************************************************************
+*
+* The driver module provides a simple interface to allow the use of
+* Fastmac in as general a setting as possible. It handles the downloading
+* of the Fastmac code and the initialization of the adapter card. It
+* provides simple transmit and receive routines. It is desgined to
+* quickly allow the implementation of Fastmac applications. It is not
+* designed as the fastest or most memory efficient solution.
+*
+* The DRV_ERR.C module contains the routine to explain the cause of errors
+* when other driver routines fail.
+*
+****************************************************************************/
+
+/*---------------------------------------------------------------------------
+|
+| DEFINITIONS
+|
+---------------------------------------------------------------------------*/
+
+#include "ftk_defs.h"
+
+/*---------------------------------------------------------------------------
+|
+| MODULE ENTRY POINTS
+|
+---------------------------------------------------------------------------*/
+
+#include "ftk_intr.h" /* routines internal to FTK */
+#include "ftk_extr.h" /* routines provided or used by external FTK user */
+
+/*---------------------------------------------------------------------------
+|
+| LOCAL VARIABLES
+|
+---------------------------------------------------------------------------*/
+
+#include "ftk_tab.h"
+
+/****************************************************************************
+*
+* driver_explain_error
+* ====================
+*
+* PARAMETERS :
+* ============
+*
+* ADAPTER_HANDLE adapter_handle
+*
+* This handle identifies the adapter for which the error has occured.
+*
+* BYTE * returned_error_type
+*
+* The byte pointed to is filled in with a value representing the type of
+* error that has occured. If no error has actually occured it is filled in
+* woth the value zero (0).
+*
+* BYTE * returned_error_value
+*
+* The byte pointed to is filled in with a value representing the
+* particular error of a given type that has occured. If no error has
+* actually occured it is filled in with the value zero (0).
+*
+* char * * returned_error_message
+*
+* This pointer, on exit, points to a string containing a message
+* describing the error that has occured. If no error has actually occured
+* then it points to a null message.
+*
+* BODY :
+* ======
+*
+* The driver_explain_error routine returns details of the most recent
+* error to occur using a given adapter.
+*
+* RETURNS :
+* =========
+*
+* The routine returns a boolean value indicating whether the error is
+* fatal or not. If the error is fatal (returns FALSE) then the adapter can
+* not be used subsequently except via a call to driver_remove_adapter.
+* However, the adapter can, after a call to driver_remove_adapter, be
+* initialized again etc.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(driver_explain_error)
+#endif
+
+export WBOOLEAN
+driver_explain_error(
+ ADAPTER_HANDLE adapter_handle,
+ BYTE * returned_error_type,
+ BYTE * returned_error_value,
+ char * * returned_error_message
+ )
+{
+
+ ERROR_MESSAGE_RECORD * err_msg_record;
+ char * err_msg_header;
+ ADAPTER * adapter;
+ ERROR_RECORD * adapter_error_record;
+
+
+ if (adapter_handle >= MAX_NUMBER_OF_ADAPTERS)
+ {
+ /*
+ * Adapter handle is invalid if greater than max number of adapters.
+ */
+
+ *returned_error_type = ERROR_TYPE_DRIVER;
+ *returned_error_value = DRIVER_E_01_INVALID_HANDLE;
+
+ /*
+ * Set up returned error msg to point to special string.
+ * No adapter structure so can not use error message adapter field.
+ */
+
+#ifdef FTK_NO_ERROR_MESSAGES
+ *returned_error_message = "";
+#else
+ *returned_error_message = drv_err_msg_1;
+#endif
+ /*
+ * This is a fatal error.
+ */
+
+ return FALSE;
+ }
+
+ if (adapter_record[adapter_handle] == NULL)
+ {
+ /*
+ * Adapter handle is invalid when no adapter structure for handle.
+ * Caused by either the adapter handle being invalid or
+ * the call to sys_alloc_adapter_structure having failed.
+ * Fill in returned error type and value.
+ */
+
+ *returned_error_type = ERROR_TYPE_DRIVER;
+ *returned_error_value = DRIVER_E_02_NO_ADAP_STRUCT;
+
+ /*
+ * Set up returned error msg to point to special string.
+ * No adapter structure so can not use error message adapter field.
+ */
+
+#ifdef FTK_NO_ERROR_MESSAGES
+ *returned_error_message = "";
+#else
+ *returned_error_message = drv_err_msg_2;
+#endif
+ /*
+ * This is a fatal error.
+ */
+
+ return FALSE;
+ }
+
+ /*
+ * Now know adapter handle is valid. Get pointer to adapter structure.
+ */
+
+ adapter = adapter_record[adapter_handle];
+
+ /*
+ * Get pointer to error record for adapter.
+ */
+
+ adapter_error_record = &adapter->error_record;
+
+ /*
+ * Check for special case when no error has actually occured.
+ */
+
+ if (adapter_error_record->type == ERROR_TYPE_NONE)
+ {
+ /*
+ * Fill in returned error type and value as zero.
+ */
+
+ *returned_error_type = 0;
+ *returned_error_value = 0;
+
+ /*
+ * Set the returned error message string to be null.
+ * If no error then adapter error message field must be null.
+ */
+
+#ifdef FTK_NO_ERROR_MESSAGES
+ *returned_error_message = "";
+#else
+ *returned_error_message = adapter->error_message.string;
+#endif
+
+ /*
+ * This is a non-fatal 'error'.
+ */
+
+ return TRUE;
+ }
+
+ /*
+ * Now know have genuine error recorded by FTK. Fill in
+ * returned error type and value.
+ */
+
+ *returned_error_type = adapter_error_record->type;
+ *returned_error_value = adapter_error_record->value;
+
+#ifdef FTK_NO_ERROR_MESSAGES
+ *returned_error_message = "";
+#else
+
+ /*
+ * All error messages are got from error message tables.
+ * First get error message header. Note it is known that
+ * *returned_error_type is valid here.
+ */
+
+ err_msg_header = error_msg_headers_table[(*returned_error_type) - 1];
+
+ /*
+ * Copy error message header to error message in adapter structure.
+ */
+
+ util_string_copy(adapter->error_message.string, err_msg_header);
+
+ /*
+ * Get pointer to correct error message table for rest of message.
+ */
+
+ err_msg_record = list_of_error_msg_tables[(*returned_error_type) - 1];
+
+ /*
+ * Search for required error message within table. Table ends with
+ * special marked entry. So if error message not found will use
+ * "Unknown error" message.
+ */
+
+ while (err_msg_record->value != ERR_MSG_UNKNOWN_END_MARKER)
+ {
+ if (err_msg_record->value == *returned_error_value)
+ {
+ break;
+ }
+ err_msg_record++;
+ }
+
+ /*
+ * Concatenate error message onto end of error header in
+ * error message field of adapter structure.
+ */
+
+ util_string_concatenate(
+ adapter->error_message.string,
+ err_msg_record->err_msg_string
+ );
+
+ /*
+ * Set up return pointer to error message.
+ */
+
+ *returned_error_message = adapter->error_message.string;
+
+#endif
+
+ /*
+ * Return FALSE for fatal errors.
+ */
+
+ if (macro_fatal_error(*returned_error_type))
+ {
+ return FALSE;
+ }
+
+ /*
+ * Return TRUE for non-fatal errors.
+ */
+
+ return TRUE;
+}
+
+
+/****************************************************************************
+*
+* driver_check_version
+* ====================
+*
+* PARAMETERS :
+* ============
+*
+* UINT * returned_version_number
+*
+* The returned version number is zero (0) if the version numbers of all
+* the FTK modules do not match correctly. If they do, then the returned
+* version number is the real version number mutiplied by 100 (eg. 1.01
+* becomes 101).
+*
+*
+* BODY :
+* ======
+*
+* The driver_check_version routine checks the version number consistency
+* of the FTK by looking at all the different code modules and header
+* files.
+*
+* RETURNS :
+* =========
+*
+* The routine returns TRUE if the version numbers are consistent.
+* Otherwise, it returns FALSE.
+*
+****************************************************************************/
+
+/*
+ * Marker at end of version number array.
+ */
+
+#define VERSION_NUMBERS_END_MARK 0xFFFF
+
+/*
+ * Version number array containing version numbers of ALL header files.
+ */
+
+local UINT version_number[] =
+{
+ FTK_VERSION_NUMBER_FTK_ADAP_H,
+ FTK_VERSION_NUMBER_FTK_AT_H,
+ FTK_VERSION_NUMBER_FTK_CARD_H,
+ FTK_VERSION_NUMBER_FTK_DOWN_H,
+ FTK_VERSION_NUMBER_FTK_EISA_H,
+ FTK_VERSION_NUMBER_FTK_PCI_H,
+ FTK_VERSION_NUMBER_FTK_PCMC_H,
+ FTK_VERSION_NUMBER_FTK_PNP_H,
+ FTK_VERSION_NUMBER_FTK_ERR_H,
+ FTK_VERSION_NUMBER_FTK_FM_H,
+ FTK_VERSION_NUMBER_FTK_INIT_H,
+ FTK_VERSION_NUMBER_FTK_MACR_H,
+ FTK_VERSION_NUMBER_FTK_MC_H,
+ FTK_VERSION_NUMBER_FTK_SRB_H,
+ FTK_VERSION_NUMBER_FTK_TAB_H,
+ FTK_VERSION_NUMBER_FTK_USER_H,
+ FTK_VERSION_NUMBER_DRV_ERR_H,
+ FTK_VERSION_NUMBER_DRV_INIT_H,
+ FTK_VERSION_NUMBER_DRV_IRQ_H,
+ FTK_VERSION_NUMBER_DRV_MISC_H,
+ FTK_VERSION_NUMBER_DRV_SRB_H,
+ FTK_VERSION_NUMBER_DRV_RXTX_H,
+ FTK_VERSION_NUMBER_HWI_GEN_H,
+ FTK_VERSION_NUMBER_HWI_AT_H,
+ FTK_VERSION_NUMBER_HWI_EISA_H,
+ FTK_VERSION_NUMBER_HWI_MC_H,
+ FTK_VERSION_NUMBER_HWI_PCI_H,
+ FTK_VERSION_NUMBER_HWI_PCMC_H,
+ FTK_VERSION_NUMBER_HWI_PNP_H,
+ FTK_VERSION_NUMBER_SYS_ALLO_H,
+ FTK_VERSION_NUMBER_SYS_BUFF_H,
+ FTK_VERSION_NUMBER_SYS_DMA_H,
+ FTK_VERSION_NUMBER_SYS_IRQ_H,
+ FTK_VERSION_NUMBER_SYS_MEM_H,
+ FTK_VERSION_NUMBER_SYS_TIME_H,
+ FTK_VERSION_NUMBER_SYS_PCI_H,
+ FTK_VERSION_NUMBER_SYS_CS_H,
+ FTK_VERSION_NUMBER_USER_H,
+ FTK_VERSION_NUMBER_UTIL_H,
+ VERSION_NUMBERS_END_MARK};
+
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(driver_check_version)
+#endif
+
+export WBOOLEAN
+driver_check_version(
+ UINT * returned_version_number
+ )
+{
+ UINT i;
+
+ /*
+ * Check for consistent version number.
+ */
+
+ i = 0;
+
+ while (version_number[i+1] != VERSION_NUMBERS_END_MARK)
+ {
+ if (version_number[i] != version_number[i + 1])
+ {
+ /*
+ * Inconsistent version numbers so return failure.
+ */
+
+ *returned_version_number = 0;
+ return FALSE;
+ }
+
+ i++;
+ }
+
+ /*
+ * Version numbers are consistent so return version number and success.
+ */
+
+ *returned_version_number = version_number[0];
+
+ return TRUE;
+}
+
+
+/****************************************************************************
+*
+* driver_check_adapter
+* ====================
+*
+* The driver_check_adapter routine is called at the beginning of every
+* driver routine, except driver_remove_adapter and driver_prepare_adapter,
+* in order to check the validity of the adapter handle. It also checks
+* that the adapter is in the correct operative state, and that the SRB
+* associated with the adapter is in the correct state (if any particular
+* state is required).
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(driver_check_adapter)
+#endif
+
+export WBOOLEAN
+driver_check_adapter(
+ ADAPTER_HANDLE adapter_handle,
+ UINT required_adapter_status,
+ UINT required_srb_status
+ )
+{
+ ADAPTER * adapter;
+
+ /*
+ * Adapter handle is invalid if greater than max number of adapter.
+ * Can not set up error record but see driver_explain_error.
+ */
+
+ if (adapter_handle >= MAX_NUMBER_OF_ADAPTERS)
+ {
+ return FALSE;
+ }
+
+ /*
+ * Adapter handle is invalid when no adapter structure for handle.
+ * Can not set up error record but see driver_explain_error.
+ */
+
+ if (adapter_record[adapter_handle] == NULL)
+ {
+ return FALSE;
+ }
+
+ /*
+ * Get pointer to adapter structure.
+ */
+
+ adapter = adapter_record[adapter_handle];
+
+ /*
+ * If fatal error already exists for adapter then fail. Do not not
+ * change error code in this case. Fatal errors are - driver, hwi,
+ * init, bring-up, adapter, auto_open.
+ */
+
+ if (macro_fatal_error(adapter->error_record.type))
+ {
+ return FALSE;
+ }
+
+ /*
+ * Check if status of adapter is that required.
+ */
+
+ if (adapter->adapter_status != required_adapter_status)
+ {
+ if (required_adapter_status == ADAPTER_PREPARED_FOR_START)
+ {
+ /*
+ * Required adapter status is ADAPTER_PREPARED_FOR_START.
+ * Fill in error record and fail.
+ */
+
+ adapter->error_record.type = ERROR_TYPE_DRIVER;
+ adapter->error_record.value = DRIVER_E_07_NOT_PREPARED;
+
+ return FALSE;
+ }
+ else
+ {
+ /*
+ * Required adapter status is ADAPTER_RUNNING.
+ * Fill in error record and fail.
+ */
+
+ adapter->error_record.type = ERROR_TYPE_DRIVER;
+ adapter->error_record.value = DRIVER_E_08_NOT_RUNNING;
+
+ return FALSE;
+ }
+ }
+
+ /*
+ * Check if status of SRB is that required. Only do if particular
+ * state is needed.
+ */
+
+ if ((required_srb_status != SRB_ANY_STATE) &&
+ (adapter->srb_status != required_srb_status))
+ {
+ if (required_srb_status == SRB_FREE)
+ {
+ /*
+ * Required srb status is SRB_FREE fill in error record
+ * and fail.
+ */
+
+ adapter->error_record.type = ERROR_TYPE_DRIVER;
+ adapter->error_record.value = DRIVER_E_09_SRB_NOT_FREE;
+
+ return FALSE;
+ }
+ else
+ {
+ /*
+ * Never require srb status to be SRB_NOT_FREE.
+ */
+ }
+ }
+
+ /*
+ * Adapter handle and status are okay so complete successfully.
+ */
+
+ return TRUE;
+}
+
+
+/******** End of DRV_ERR.C *************************************************/
diff --git a/private/ntos/ndis/madge/driver/drv_init.c b/private/ntos/ndis/madge/driver/drv_init.c
new file mode 100644
index 000000000..28539f67c
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/drv_init.c
@@ -0,0 +1,1656 @@
+/****************************************************************************
+*
+* DRV_INIT.C : Part of the FASTMAC TOOL-KIT (FTK)
+*
+* THE DRIVER MODULE (INITIALIZE / REMOVE)
+*
+* Copyright (c) Madge Networks Ltd. 1991-1994
+*
+* COMPANY CONFIDENTIAL
+*
+*****************************************************************************
+*
+* The driver module provides a simple interface to allow the use of
+* Fastmac in as general a setting as possible. It handles the downloading
+* of the Fastmac code and the initialization of the adapter card. It
+* provides simple transmit and receive routines. It is desgined to
+* quickly allow the implementation of Fastmac applications. It is not
+* designed as the fastest or most memory efficient solution.
+*
+* The DRV_INIT.C module contains the routines necessary to initialize
+* Fastmac and the adapter and remove, ie. terminate usage of, the
+* adapter. Upon adapter initialization the user is returned a handle
+* which is used to identify the adapter in all future accesses to the
+* driver module.
+*
+****************************************************************************/
+
+/*---------------------------------------------------------------------------
+|
+| DEFINITIONS
+|
+---------------------------------------------------------------------------*/
+
+#include "ftk_defs.h"
+
+/*---------------------------------------------------------------------------
+|
+| MODULE ENTRY POINTS
+|
+---------------------------------------------------------------------------*/
+
+#include "ftk_intr.h" /* routines internal to FTK */
+#include "ftk_extr.h" /* routines provided or used by external FTK user */
+
+/*---------------------------------------------------------------------------
+|
+| LOCAL FUNCTIONS
+|
+---------------------------------------------------------------------------*/
+
+local WBOOLEAN
+driver_wait_for_adapter_open(
+ UINT * open_status,
+ ADAPTER * adapter
+ );
+
+local WORD
+driver_get_max_frame_size(
+ ADAPTER * adapter,
+ FASTMAC_INIT_PARMS * fastmac_parms
+ );
+
+/*---------------------------------------------------------------------------
+|
+| GLOBAL VARIABLES
+|
+---------------------------------------------------------------------------*/
+
+export ADAPTER * adapter_record[MAX_NUMBER_OF_ADAPTERS] = {NULL};
+
+#ifndef FTK_NO_PROBE
+/****************************************************************************
+*
+* driver_probe_card
+* =================
+*
+*
+* PARAMETERS :
+* ============
+*
+* WORD adapter_card_bus_type
+*
+* The bus type (card family) the adapters for which to search. e.g.
+* ADAPTER_CARD_ATULA_BUS_TYPE or ADAPTER_CARD_EISA_BUS_TYPE.
+*
+* PROBE * resources
+*
+* resources is an array structures used to identify and record specific
+* information about adapters found.
+*
+* UINT length
+*
+* length is the number of structures pointed to by reources.
+*
+* WORD * valid_locations
+*
+* valid_locations is an array of IO locations to examine for the presence
+* of an adapter. For ATULA based adapters with should be a subset of
+* {0x0a20, 0x1a20, 0x2a20, 0x3a20}.
+*
+* UINT number_locations
+*
+* This is the number of IO locations in the above list.
+*
+* BODY :
+* ======
+*
+* The hwi_atula_probe_card routine is called by hwi_probe_adapter. It
+* probes the adapter card for information such as DMA channel, IRQ number
+* etc. This information can then be supplied by the user when starting the
+* adapter.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine returns the number of adapters found, or PROBE_FAILURE
+* if there's a problem.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(driver_probe_adapter)
+#endif
+
+export UINT
+driver_probe_adapter(
+ WORD adapter_card_bus_type,
+ PROBE * resources,
+ UINT length,
+ WORD * valid_locations,
+ UINT number_locations
+ )
+{
+ return hwi_probe_adapter(
+ adapter_card_bus_type,
+ resources,
+ length,
+ valid_locations,
+ number_locations
+ );
+}
+
+
+/****************************************************************************
+*
+* driver_deprobe_adapter
+* ======================
+*
+* PARAMETERS :
+* ============
+*
+* PROBE * resources
+*
+* resources is an array structures used to identify and record specific
+* information about adapters found.
+*
+* UINT length
+*
+* length is the number of structures pointed to by reources.
+*
+* BODY :
+* ======
+*
+* This function frees any resources that were claimed by a call to
+* driver_probe_adapter. Every valid PROBE structure returned by
+* driver_probe_adapter MUST be passed to driver_deprobe adapter otherwise
+* resources that were claimed from the operating system by
+* driver_probe_adapter (such as PCMCIA sockets) will not be freed.
+*
+* RETURNS :
+* =========
+*
+* TRUE if everything worked or FALSE if it did not.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(driver_deprobe_adapter)
+#endif
+
+export WBOOLEAN
+driver_deprobe_adapter(
+ PROBE * resources,
+ UINT length
+ )
+{
+ return hwi_deprobe_adapter(
+ resources,
+ length
+ );
+}
+
+#endif
+
+/****************************************************************************
+*
+* driver_prepare_adapter
+* ======================
+*
+*
+* PARAMETERS :
+* ============
+*
+* PREPARE_ARGS * arguments
+*
+* This is a pointer to the arguments structure set up by the user code.
+*
+* ADAPTER_HANDLE * returned_adapter_handle
+*
+* An adapter handle is returned that is used for all subsequent calls to
+* the driver to identify the particular adapter.
+*
+* BODY :
+* ======
+*
+* The driver_prepare_adapter routine firstly sets up the adapter structure
+* for this adapter. Then it gets memory for the status information
+* structure that is filled in by driver_get_status calls. It then
+* requests memory for the Fastmac transmit and receive buffers. This memory
+* must be static, it must not be swapped out to disk because of DMA issues.
+*
+* This routine should be called once for every adapter that is to have
+* Fastmac used on it.
+*
+* RETURNS :
+* =========
+*
+* The routine returns TRUE if it succeeds. If this routine fails (returns
+* FALSE) then a subsequent call to driver_explain_error with the returned
+* adapter handle will give an explanation.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(driver_prepare_adapter)
+#endif
+
+export WBOOLEAN
+driver_prepare_adapter(
+ PREPARE_ARGS * arguments,
+ ADAPTER_HANDLE * returned_adapter_handle
+ )
+{
+ ADAPTER_HANDLE adapter_handle;
+ ADAPTER * adapter;
+ FASTMAC_INIT_PARMS * fastmac_parms;
+ WORD i;
+
+ /*
+ * Set up adapter handle which is an index to an array of pointers.
+ * Find first a pointer not yet used.
+ */
+
+ for (i = 0; i < MAX_NUMBER_OF_ADAPTERS; i++)
+ {
+ if (adapter_record[i] == NULL)
+ {
+ break;
+ }
+ }
+
+ /*
+ * Set up returned adapter handle ( = index to adapter structure).
+ * returned_adapter_handle is set up here before any failure.
+ * This is so can use adapter handle for call to driver_explain_error.
+ */
+
+ adapter_handle = (ADAPTER_HANDLE) i;
+ *returned_adapter_handle = adapter_handle;
+
+ /*
+ * If all pointers to adapter structures are used then return error.
+ * Can not set up error record but see driver_explain_error.
+ */
+
+ if (i == MAX_NUMBER_OF_ADAPTERS)
+ {
+ return FALSE;
+ }
+
+ /*
+ * Get memory for adapter structure.
+ */
+
+ adapter_record[adapter_handle] = (ADAPTER *)
+ sys_alloc_adapter_structure(adapter_handle, sizeof(ADAPTER));
+
+ /*
+ * Check that the memory allocation was successful. Can not set up
+ * error record but see driver_explain_error.
+ */
+
+ if (adapter_record[adapter_handle] == NULL)
+ {
+ return FALSE;
+ }
+
+ /*
+ * Remember pointer to adapter structure.
+ */
+
+ adapter = adapter_record[adapter_handle];
+
+ /*
+ * Zero adapter structure memory.
+ */
+
+ util_zero_memory((BYTE *) adapter, sizeof(ADAPTER));
+
+ /*
+ * Save handle, so that HWI routines that need it can find it.
+ */
+
+ adapter->adapter_handle = adapter_handle;
+
+ /*
+ * Save the user's private information for the users sys_ functions.
+ */
+
+ adapter->user_information = arguments->user_information;
+
+#ifdef FMPLUS
+
+ /*
+ * Allocate memory for the FastMAC Plus to do its DMA tests.
+ * This is now a byte longer to allocate the byte used
+ * to handshake the DMA on a PCI(T) card with broken DMA.
+ */
+
+ if (!sys_alloc_dma_phys_buffer(
+ adapter_handle,
+ SCB_TEST_PATTERN_LENGTH + SSB_TEST_PATTERN_LENGTH + 1,
+ &(adapter->dma_test_buf_phys),
+ &(adapter->dma_test_buf_virt)))
+ {
+ adapter->error_record.type = ERROR_TYPE_DRIVER;
+ adapter->error_record.value = DRIVER_E_12_FAIL_ALLOC_DMA_BUF;
+
+ return FALSE;
+ }
+
+#endif
+
+ /*
+ * Indicate no errors have occured for this adapter yet.
+ */
+
+ adapter->error_record.type = ERROR_TYPE_NONE;
+
+ /*
+ * Get memory for status information structure.
+ */
+
+ adapter->status_info = (STATUS_INFORMATION *)
+ sys_alloc_status_structure(adapter_handle,sizeof(STATUS_INFORMATION));
+
+ /*
+ * Check that the memory allocation was successful.
+ */
+
+ if (adapter->status_info == NULL)
+ {
+ adapter->error_record.type = ERROR_TYPE_DRIVER;
+ adapter->error_record.value = DRIVER_E_03_FAIL_ALLOC_STATUS;
+
+ return FALSE;
+ }
+
+ /*
+ * Zero status information structure memory.
+ */
+
+ util_zero_memory(
+ (BYTE *) adapter->status_info,
+ sizeof(STATUS_INFORMATION)
+ );
+
+ /*
+ * Get memory for initialization block.
+ */
+
+ adapter->init_block = (INITIALIZATION_BLOCK *)
+ sys_alloc_init_block(adapter_handle, sizeof(INITIALIZATION_BLOCK));
+
+ /*
+ * Check that the memory allocation was successful.
+ */
+
+ if (adapter->init_block == NULL)
+ {
+ adapter->error_record.type = ERROR_TYPE_DRIVER;
+ adapter->error_record.value = DRIVER_E_04_FAIL_ALLOC_INIT;
+
+ return FALSE;
+ }
+
+ /*
+ * Zero initialization block memory.
+ */
+
+ util_zero_memory(
+ (BYTE *) adapter->init_block,
+ sizeof(INITIALIZATION_BLOCK)
+ );
+
+ /*
+ * Get pointer to Fastmac init parameters for this adapter.
+ */
+
+ fastmac_parms = &adapter->init_block->fastmac_parms;
+
+ /*
+ * Ensure that the fastmac_parms->features reserved bits and the
+ * fastmac_parms->int_flags reserved bits are zero (bits 4,11-15
+ * of features, and bits 3-15 of int_flags).
+ * (In fact they will be already from the above util_zero_memory.)
+ */
+
+ /*
+ * Now fill in all of the hardware independant non-zero fields in the
+ * Fastmac part of init block.
+ */
+
+ /*
+ * Check that the frame size requested in within the bounds
+ * of possibility.
+ */
+
+ if (arguments->max_frame_size < MIN_FRAME_SIZE ||
+ arguments->max_frame_size > MAX_FRAME_SIZE_16_MBITS)
+ {
+ adapter->error_record.type = ERROR_TYPE_DRIVER;
+ adapter->error_record.value = DRIVER_E_13_BAD_FRAME_SIZE;
+
+ return FALSE;
+ }
+
+ /*
+ * Make a note of the maximum frame size requested.
+ */
+
+ fastmac_parms->max_frame_size = arguments->max_frame_size;
+
+
+#ifndef FMPLUS
+
+ /*
+ * Set up the header.
+ */
+
+ fastmac_parms->header.length = sizeof(FASTMAC_INIT_PARMS);
+ fastmac_parms->header.signature = FASTMAC_INIT_HEADER_SIGNATURE;
+ fastmac_parms->header.version = FASTMAC_INIT_HEADER_VERSION;
+
+ /*
+ * Now set up the interrupt options.
+ */
+
+#ifdef FTK_TX_WITH_COMPLETION
+ fastmac_parms->int_flags |= INT_FLAG_TX_BUF_EMPTY;
+#endif
+
+ /*
+ * Check have sensible value for Fastmac receive buffer size.
+ */
+
+ if ((arguments->receive_buffer_byte_size < FASTMAC_MINIMUM_BUFFER_SIZE) ||
+ (arguments->receive_buffer_byte_size > FASTMAC_MAXIMUM_BUFFER_SIZE))
+ {
+ adapter->error_record.type = ERROR_TYPE_DRIVER;
+ adapter->error_record.value = DRIVER_E_0A_RX_BUF_BAD_SIZE;
+
+ return FALSE;
+ }
+
+ /*
+ * Get memory for the receive buffer.
+ */
+
+ if (!sys_alloc_dma_phys_buffer(
+ adapter_handle,
+ arguments->receive_buffer_byte_size,
+ &adapter->rx_buffer_phys,
+ &adapter->rx_buffer_virt))
+ {
+ adapter->error_record.type = ERROR_TYPE_DRIVER;
+ adapter->error_record.value = DRIVER_E_05_FAIL_ALLOC_RX_BUF;
+
+ return FALSE;
+ }
+
+ fastmac_parms->rx_buf_physaddr = adapter->rx_buffer_phys;
+
+ /*
+ * Check that Fastmac receive buffer begins on a DWORD boundary.
+ */
+
+ if ((fastmac_parms->rx_buf_physaddr & 0x00000003) != 0L)
+ {
+ adapter->error_record.type = ERROR_TYPE_DRIVER;
+ adapter->error_record.value = DRIVER_E_0B_RX_BUF_NOT_DWORD;
+
+ return FALSE;
+ }
+
+ /*
+ * Fill in Fastmac receive buffer size.
+ */
+
+ fastmac_parms->rx_buf_size = arguments->receive_buffer_byte_size;
+
+ /*
+ * Check have sensible value for Fastmac transmit buffer size.
+ */
+
+ if ((arguments->transmit_buffer_byte_size < FASTMAC_MINIMUM_BUFFER_SIZE) ||
+ (arguments->transmit_buffer_byte_size > FASTMAC_MAXIMUM_BUFFER_SIZE))
+ {
+ adapter->error_record.type = ERROR_TYPE_DRIVER;
+ adapter->error_record.value = DRIVER_E_0C_TX_BUF_BAD_SIZE;
+
+ return FALSE;
+ }
+
+ /*
+ * Get memory for the transmit buffer.
+ */
+
+ if (!sys_alloc_dma_phys_buffer(
+ adapter_handle,
+ arguments->receive_buffer_byte_size,
+ &adapter->tx_buffer_phys,
+ &adapter->tx_buffer_virt))
+ {
+ adapter->error_record.type = ERROR_TYPE_DRIVER;
+ adapter->error_record.value = DRIVER_E_06_FAIL_ALLOC_TX_BUF;
+
+ return FALSE;
+ }
+
+ fastmac_parms->tx_buf_physaddr = adapter->tx_buffer_phys;
+
+ /*
+ * Check that Fastmac transmit buffer begins on a DWORD boundary.
+ */
+
+ if ((fastmac_parms->tx_buf_physaddr & 0x00000003) != 0L)
+ {
+ adapter->error_record.type = ERROR_TYPE_DRIVER;
+ adapter->error_record.value = DRIVER_E_0D_TX_BUF_NOT_DWORD;
+
+ return FALSE;
+ }
+
+ /*
+ * Fill in Fastmac transmit buffer size.
+ */
+
+ fastmac_parms->tx_buf_size = arguments->transmit_buffer_byte_size;
+
+ /*
+ * Mark adapter structure as containing details of initialized Fastmac
+ * and indicate that SRB is free.
+ */
+
+ adapter->adapter_status = ADAPTER_PREPARED_FOR_START;
+ adapter->srb_status = SRB_FREE;
+
+#else
+
+ /*
+ * Set set up the header.
+ */
+
+ fastmac_parms->header.length = sizeof(FASTMAC_INIT_PARMS);
+ fastmac_parms->header.signature = FMPLUS_INIT_HEADER_SIGNATURE;
+ fastmac_parms->header.version = FMPLUS_INIT_HEADER_VERSION;
+
+ /*
+ * Now set up the interrupt options.
+ */
+
+#ifdef FTK_RX_OUT_OF_INTERRUPTS
+ fastmac_parms->int_flags |= INT_FLAG_RX;
+#endif
+
+#ifdef FTK_RX_BY_SCHEDULED_PROCESS
+ fastmac_parms->int_flags |= INT_FLAG_RX;
+#endif
+
+#ifdef FTK_TX_WITH_COMPLETION
+ fastmac_parms->int_flags |= INT_FLAG_LARGE_DMA;
+#endif
+
+ /*
+ * Now fill in the number of slots that are required. These are user
+ * specified, since the numbers are host dependent (each slot must have
+ * a maximum frame sized buffer on the host).
+ */
+
+ if (arguments->number_of_rx_slots < FMPLUS_MIN_RX_SLOTS ||
+ arguments->number_of_rx_slots > FMPLUS_MAX_RX_SLOTS)
+ {
+ adapter->error_record.type = ERROR_TYPE_DRIVER;
+ adapter->error_record.value = DRIVER_E_10_BAD_RX_SLOT_NUMBER;
+
+ return FALSE;
+ }
+
+ fastmac_parms->rx_slots = arguments->number_of_rx_slots;
+
+ if (arguments->number_of_tx_slots < FMPLUS_MIN_TX_SLOTS ||
+ arguments->number_of_tx_slots > FMPLUS_MAX_TX_SLOTS)
+ {
+ adapter->error_record.type = ERROR_TYPE_DRIVER;
+ adapter->error_record.value = DRIVER_E_11_BAD_TX_SLOT_NUMBER;
+
+ return FALSE;
+ }
+
+ fastmac_parms->tx_slots = arguments->number_of_tx_slots;
+
+ /*
+ * Allocate the receive slot buffers.
+ */
+
+ if (!rxtx_allocate_rx_buffers(
+ adapter,
+ arguments->max_frame_size,
+ arguments->number_of_rx_slots
+ ))
+ {
+ adapter->error_record.type = ERROR_TYPE_DRIVER;
+ adapter->error_record.value = DRIVER_E_05_FAIL_ALLOC_RX_BUF;
+
+ return FALSE;
+ }
+
+ /*
+ * Allocate the transmit slot buffers.
+ */
+
+ if (!rxtx_allocate_tx_buffers(
+ adapter,
+ arguments->max_frame_size,
+ arguments->number_of_tx_slots
+ ))
+ {
+ adapter->error_record.type = ERROR_TYPE_DRIVER;
+ adapter->error_record.value = DRIVER_E_06_FAIL_ALLOC_TX_BUF;
+
+ return FALSE;
+ }
+
+ /*
+ * Mark adapter structure as containing details of initialized Fastmac
+ * and indicate that SRB is free.
+ */
+
+ adapter->adapter_status = ADAPTER_PREPARED_FOR_START;
+ adapter->srb_status = SRB_FREE;
+
+#endif
+
+ /*
+ * Complete successfully.
+ */
+
+ return TRUE;
+}
+
+/****************************************************************************
+*
+* driver_start_adapter
+* ====================
+*
+* PARAMETERS :
+* ============
+*
+* ADAPTER_HANDLE adapter_handle
+*
+* This handle identifies the adapter to be initialized. This should be a
+* handle returned by a call to driver_prepare_adapter.
+*
+* START_ARGS * arguments
+*
+* This is a pointer to the arguments structure set up by the user code.
+*
+* NODE_ADDRESS * returned_permanent_address
+*
+* The node address pointed to is always filled in with the BIA PROM node
+* address of the adapter. This is so the user of the FTK can fill in MAC
+* headers etc. with the source node address (unless the user has supplied
+* an opening address to driver_prepare_adapter which they should then use
+* instead).
+*
+*
+* BODY :
+* ======
+*
+* The driver_start_adapter routine is called once per adapter after a call
+* to driver_prepare_adapter. It takes the user supplied adapter
+* information and passes it in a form usable by the HWI so that the HWI
+* can install and then initialize the adapter (that is initialize
+* registers on the card, download the Fastmac image and set up the IRQ and
+* DMA channels if necessary). After initialization, this routine waits for
+* the adapter to open if the auto-open option is enabled.
+*
+* RETURNS :
+* =========
+*
+* The routine returns TRUE if it succeeds. If this routine fails (returns
+* FALSE) then a subsequent call to driver_explain_error with the same
+* adapter handle will give an explanation.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(driver_start_adapter)
+#endif
+
+export WBOOLEAN
+driver_start_adapter(
+ ADAPTER_HANDLE adapter_handle,
+ START_ARGS * arguments,
+ NODE_ADDRESS * returned_permanent_address
+ )
+{
+ ADAPTER * adapter;
+ FASTMAC_INIT_PARMS * fastmac_parms;
+ WBOOLEAN init_success;
+ WORD max_frame_size;
+ UINT i;
+#ifdef FMPLUS
+ RX_SLOT * next_rx_slot;
+ TX_SLOT * next_tx_slot;
+ RX_SLOT * * rx_slot_array;
+ TX_SLOT * * tx_slot_array;
+ UINT slot_index;
+#endif
+
+ /*
+ * Check adapter handle and status of adapter for validity.
+ * If routine fails return failure (error record already filled in).
+ */
+
+ if (!driver_check_adapter(
+ adapter_handle,
+ ADAPTER_PREPARED_FOR_START,
+ SRB_ANY_STATE
+ ))
+ {
+ return FALSE;
+ }
+
+ /*
+ * Get pointer to adapter structure.
+ */
+
+ adapter = adapter_record[adapter_handle];
+
+ /*
+ * Fill user supplied info into adapter structure.
+ */
+
+ adapter->mmio_base_address = arguments->mmio_base_address;
+ adapter->adapter_card_bus_type = arguments->adapter_card_bus_type;
+ adapter->io_location = arguments->io_location;
+ adapter->dma_channel = arguments->dma_channel;
+ adapter->transfer_mode = arguments->transfer_mode;
+ adapter->interrupt_number = arguments->interrupt_number;
+ adapter->set_dma = arguments->set_dma_channel;
+ adapter->set_irq = arguments->set_interrupt_number;
+ adapter->set_ring_speed = arguments->set_ring_speed;
+ adapter->download_image = arguments->code;
+ adapter->pci_handle = arguments->pci_handle;
+
+
+#ifdef FMPLUS
+
+ /*
+ * Need these values later.
+ */
+
+ rx_slot_array = adapter->rx_slot_array;
+ tx_slot_array = adapter->tx_slot_array;
+
+#endif
+
+ /*
+ * Call the HWI routine to install the adapter. This also downloads
+ * the Fastmac image to the adapter. If routine fails return failure
+ * (error record already filled in). DMA and IRQ are only enabled
+ * if hwi_install_adapter succeeds.
+ */
+
+ /*
+ * WARNING: we must mark the adapter as running NOW, before downloading
+ * the microcode, because on AT cards in PIO mode ONLY, bring
+ * up diagnostics on the card fail when carrying out DMA tests.
+ * This occurs because the interrupt handling routine ignores
+ * all interrupts from the card until it is marked as running,
+ * but this unfortunately masks off PIO interrupts too.
+ */
+
+ /*
+ * Mark adapter structure that adapter is now going to be running.
+ * Hence hwi_interrupt_entry will check adapter for interrupts
+ */
+
+ adapter->adapter_status = ADAPTER_RUNNING;
+
+ if (!hwi_install_adapter(adapter, adapter->download_image))
+ {
+ /*
+ * Now that initial installation has failed, we can turn off the
+ * above indication that the card is running.
+ */
+
+ adapter->adapter_status = ADAPTER_PREPARED_FOR_START;
+
+ return FALSE;
+ }
+
+ /*
+ * Get pointer to Fastmac init parameters for this adapter.
+ */
+
+ fastmac_parms = &adapter->init_block->fastmac_parms;
+
+ /*
+ * Now fill in max frame size in init block that Fastmac should support.
+ * This is based on the size of the Fastmac buffers and
+ * max frame size supported by adapter because of ring speed. We
+ * put the requested max frame is into fastmac_parms->max_frame_size
+ * in driver_prepare_adapter.
+ */
+
+ max_frame_size = driver_get_max_frame_size(adapter, fastmac_parms);
+
+ fastmac_parms->max_frame_size =
+ min(max_frame_size, fastmac_parms->max_frame_size);
+
+ /*
+ * Write the actual max frame size back up to the caller, so they know
+ * what it is too.
+ */
+
+ arguments->max_frame_size = fastmac_parms->max_frame_size;
+
+
+#ifdef FMPLUS
+
+ /*
+ * Set up the user selected RX/TX buffer size. This will be changed
+ * in hwi_gen.c if the value given is not sensible.
+ */
+
+ adapter->init_block->smart_parms.rx_tx_buffer_size =
+ arguments->rx_tx_buffer_size;
+
+#endif
+
+ /*
+ * If auto open option is on then put necessary info into init block.
+ */
+
+ if (arguments->auto_open_option)
+ {
+#ifndef FMPLUS
+
+ /*
+ * Use delay_rx to prevent race condition occuring whereby
+ * on auto-open an interrupt could occur before the host
+ * code has had a chance to read the location of the status
+ * block on the card. The other half of the code to fix this
+ * problem is in driver_start_adapter, where the ARB is freed.
+ */
+
+ fastmac_parms->feature_flags =
+ FEATURE_FLAG_AUTO_OPEN | FEATURE_FLAG_DELAY_RX;
+
+#else
+
+ fastmac_parms->feature_flags = FEATURE_FLAG_AUTO_OPEN;
+
+#endif
+
+ fastmac_parms->open_options = arguments->open_options;
+
+ /*
+ * Check if auto-opening node address is set (ie. not all zeroes).
+ */
+
+ for (i = 0; i < sizeof(NODE_ADDRESS); i++)
+ {
+ if (arguments->opening_node_address.byte[i] != 0)
+ {
+ break;
+ }
+ }
+
+ /*
+ * If opening node address not set up use BIA PROM address.
+ */
+
+ if (i == sizeof(NODE_ADDRESS))
+ {
+ fastmac_parms->open_address = adapter->permanent_address;
+ }
+ else
+ {
+ fastmac_parms->open_address = arguments->opening_node_address;
+ }
+
+ fastmac_parms->group_address = arguments->opening_group_address;
+ fastmac_parms->functional_address = arguments->opening_functional_address;
+ }
+
+ /*
+ * Call the HWI routine to initialize the adapter. This downloads the
+ * init block to the adapter. Leaves EAGLE_SIFADRX=0x0001 so driver
+ * never use extended SIF regs. If routine fails return failure
+ * (error record already filled in).
+ */
+
+ if (!hwi_initialize_adapter(adapter, adapter->init_block))
+ {
+ return FALSE;
+ }
+
+ /*
+ * At this stage the actual adapter card type is known.
+ * Get the IO location of the first SIF register for the adapter.
+ * Inform the system about the IO ports we are going to access.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ /*
+ * Get the DIO addresses of the Fastmac SSB and STB (ststus block).
+ * Only use non-extended SIF regs (EAGLE_SIFADR and EAGLE_SIFDAT_INC).
+ * Hence can use same code for all adapter card types.
+ */
+
+ sys_outsw(adapter_handle, adapter->sif_adr, DIO_LOCATION_SRB_POINTER);
+
+ adapter->srb_dio_addr = (SRB_HEADER *) (card_t)
+ sys_insw(adapter_handle, adapter->sif_datinc);
+
+ sys_outsw(adapter_handle, adapter->sif_adr, DIO_LOCATION_STB_POINTER);
+
+ adapter->stb_dio_addr = (FASTMAC_STATUS_BLOCK *) (card_t)
+ sys_insw(adapter_handle, adapter->sif_datinc);
+
+#ifndef FMPLUS
+
+ /*
+ * In the case of auto-open :
+ * Free the ARB to enable data to be received from here on... This only
+ * occurs now because it is only now that we know where to look for the
+ * pointers in the status block that will tell us whether data has come
+ * in or not.
+ */
+
+ if (arguments->auto_open_option)
+ {
+ sys_outsw(adapter_handle, adapter->sif_int, EAGLE_ARB_FREE_CODE);
+ }
+
+#else
+
+ /*
+ * Now recover the receive slot and transmit slot chains.
+ */
+
+ /*
+ * Start with the receive slot chain. We must poll the location in the
+ * status block that holds the start address until it is non-zero. It
+ * is then safe to run down the chain finding the other slots.
+ */
+
+ sys_outsw(
+ adapter_handle,
+ adapter->sif_adr,
+ (WORD) (card_t) &adapter->stb_dio_addr->rx_slot_start
+ );
+
+ /*
+ * Poll this address until it is non-zero.
+ */
+
+ do
+ {
+ rx_slot_array[0] = (RX_SLOT *) (card_t)
+ sys_insw(adapter_handle, adapter->sif_dat);
+ }
+ while (rx_slot_array[0] == 0);
+
+ /*
+ * Recover all the other slots by running down the chain.
+ */
+
+ slot_index = 0;
+
+ do
+ {
+ sys_outsw(
+ adapter_handle,
+ adapter->sif_adr,
+ (WORD) (card_t) &rx_slot_array[slot_index]->next_slot
+ );
+
+ next_rx_slot = (RX_SLOT *) (card_t)
+ sys_insw(adapter_handle, adapter->sif_dat);
+
+ if (next_rx_slot != rx_slot_array[0])
+ {
+ rx_slot_array[++slot_index] = next_rx_slot;
+ }
+ }
+ while (next_rx_slot != rx_slot_array[0]);
+
+ /*
+ * Now do the same for the transmit slots.
+ */
+
+ sys_outsw(
+ adapter_handle,
+ adapter->sif_adr,
+ (WORD) (card_t) &adapter->stb_dio_addr->tx_slot_start
+ );
+
+ /*
+ * Poll this address until it is non-zero.
+ */
+
+ do
+ {
+ tx_slot_array[0] = (TX_SLOT *) (card_t)
+ sys_insw(adapter_handle, adapter->sif_dat);
+ }
+ while (tx_slot_array[0] == 0);
+
+ /*
+ * Now recover all the other slots by running down the chain.
+ */
+
+ slot_index = 0;
+
+ do
+ {
+ sys_outsw(
+ adapter_handle,
+ adapter->sif_adr,
+ (WORD) (card_t) &tx_slot_array[slot_index]->next_slot
+ );
+
+ next_tx_slot = (TX_SLOT *) (card_t)
+ sys_insw(adapter_handle, adapter->sif_dat);
+
+ if (next_tx_slot != tx_slot_array[0])
+ {
+ tx_slot_array[++slot_index] = next_tx_slot;
+ }
+ }
+ while (next_tx_slot != tx_slot_array[0]);
+
+ /*
+ * Now that we have the slot locations on the card, we can associate
+ * buffers with each of them. The user needs to supply a routine that
+ * set up the slots from the host buffers previously allocated as
+ * we don't enforce an organisation on the allocation of multiple
+ * slot buffers. We tell the user routine if it should program the
+ * adapter slots with physical addresses (for DMA) or virtual
+ * addresses (for PIO or MMIO).
+ */
+
+
+ rxtx_setup_rx_buffers(
+ adapter,
+ (WBOOLEAN) (adapter->transfer_mode == DMA_DATA_TRANSFER_MODE),
+ fastmac_parms->rx_slots
+ );
+
+
+ rxtx_setup_tx_buffers(
+ adapter,
+ (WBOOLEAN) (adapter->transfer_mode == DMA_DATA_TRANSFER_MODE),
+ fastmac_parms->tx_slots
+ );
+
+#endif
+
+ /*
+ * Let the system know we have finished accessing the IO ports.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io( adapter);
+#endif
+
+ /*
+ * Check that Fastmac has correctly installed. Do this by reading
+ * node address from Fastmac status block. If routine fails return
+ * failure (error record already filled in). Note for EISA cards,
+ * this is actually first time get node address.
+ */
+
+ if (!hwi_get_node_address_check(adapter))
+ {
+ return FALSE;
+ }
+
+ /*
+ * Copy permanent BIA PROM node address into user supplied node address.
+ */
+
+ *returned_permanent_address = adapter->permanent_address;
+
+ /*
+ * If the auto open option is on then wait to see if adapter opens okay.
+ * Enable and disable accessing IO locations around check.
+ * If adapter open routine fails then error record already filled in.
+ */
+
+ if (arguments->auto_open_option)
+ {
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io( adapter);
+#endif
+
+ init_success = driver_wait_for_adapter_open(
+ &(arguments->open_status),
+ adapter
+ );
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io( adapter);
+#endif
+ }
+ else
+ {
+ init_success = TRUE;
+ }
+
+ /*
+ * Initialization completed.
+ */
+
+ return init_success;
+}
+
+#ifdef FMPLUS
+
+/****************************************************************************
+*
+* driver_start_receive_process
+* ============================
+*
+* PARAMETERS :
+* ============
+*
+* ADAPTER_HANDLE adapter_handle
+*
+* This handle identifies the adapter to be initialized. This should be a
+* handle returned by a call to driver_prepare_adapter.
+*
+* BODY :
+* ======
+*
+* The driver_start_adapter routine is called once per adapter after a call
+* to driver_start_adapter. It uses the supplied handle to identify which
+* adapter it should affect : by writing a zero into the Fastmac Plus init-
+* ialization block on the adapter (as specified in the manual), the card
+* will start to receive frames and pass them up to the host.
+*
+* NOTE: If SRBs are going to be used, this MUST be called first.
+*
+* RETURNS :
+* =========
+*
+* The routine returns TRUE if it succeeds. If this routine fails (returns
+* FALSE) then a subsequent call to driver_explain_error with the same
+* adapter handle will give an explanation.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(driver_start_receive_process)
+#endif
+
+export WBOOLEAN
+driver_start_receive_process(
+ ADAPTER_HANDLE adapter_handle
+ )
+{
+ ADAPTER * adapter;
+
+ /*
+ * Adapter handle is invalid if greater than max number of adapters.
+ * Can not set up error record but see driver_explain_error.
+ */
+
+ if (adapter_handle >= MAX_NUMBER_OF_ADAPTERS)
+ {
+ return FALSE;
+ }
+
+ /*
+ * Adapter handle is invalid when no adapter structure for handle.
+ * Can not set up error record but see driver_explain_error.
+ */
+
+ if (adapter_record[adapter_handle] == NULL)
+ {
+ return FALSE;
+ }
+
+ /*
+ * Get pointer to adapter structure.
+ */
+
+ adapter = adapter_record[adapter_handle];
+
+ /*
+ * Inform the system about the IO ports we are going to access.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ /*
+ * Let's fire off the receive process from here then...
+ */
+
+ sys_outsw(
+ adapter_handle,
+ adapter->sif_adr,
+ (WORD) (card_t) &adapter->stb_dio_addr->rx_slot_start
+ );
+
+ sys_outsw(adapter_handle, adapter->sif_dat, 0);
+
+ /*
+ * Let the system know we have finished accessing the IO ports.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+
+ return TRUE;
+}
+
+#endif
+
+/****************************************************************************
+*
+* driver_remove_adapter
+* =====================
+*
+* PARAMETERS :
+* ============
+*
+* ADAPTER_HANDLE adapter_handle
+*
+* This handle identifies the adapter to be removed.
+*
+* BODY :
+* ======
+*
+* The driver_remove_adapter routine is written such that, whatever the
+* current state of the adapter, a call to driver_remove_adapter will place
+* the adapter in a state whereby driver_prepare_adapter must be called to
+* start using the adapter once more. Hence, on ANY fatal adapter error, a
+* call to driver_remove adapter is needed before installing the adapter
+* again.
+*
+* The routine calls the HWI to reset the required adapter if the adapter
+* has been running. It also calls certain system routines in order to
+* free the memory used by the Fastmac receive and transmit buffers as well
+* as that used by the adapter structure. However, it only does this when
+* the allocate calls were successful.
+*
+* RETURNS :
+* =========
+*
+* The routine always succeeds. Even if the adapter handle is invalid then
+* the routine does not fail it just does nothing.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(driver_remove_adapter)
+#endif
+
+export WBOOLEAN
+driver_remove_adapter(
+ ADAPTER_HANDLE adapter_handle
+ )
+{
+ ADAPTER * adapter;
+ FASTMAC_INIT_PARMS * fastmac_parms;
+
+ /*
+ * Adapter handle is invalid if greater than max number of adapters.
+ * Can not set up error record but see driver_explain_error.
+ */
+
+ if (adapter_handle >= MAX_NUMBER_OF_ADAPTERS)
+ {
+ return FALSE;
+ }
+
+ /*
+ * Adapter handle is invalid when no adapter structure for handle.
+ * Can not set up error record but see driver_explain_error.
+ */
+
+ if (adapter_record[adapter_handle] == NULL)
+ {
+ return FALSE;
+ }
+
+ /*
+ * Get pointer to adapter structure.
+ */
+
+ adapter = adapter_record[adapter_handle];
+
+ /*
+ * Call the HWI routine to kill the adapter (DMA channel, IRQ number).
+ * Only call it if either DMA or interrupts are enabled at adapter.
+ * Note in this case the actual adapter card type is known.
+ */
+
+ if (adapter->interrupts_on || adapter->dma_on)
+ {
+ hwi_remove_adapter(adapter);
+ }
+
+ /*
+ * Free all memory that was allocated for handling use of this adapter.
+ * Includes Fastmac buffers, init block and adapter structure.
+ * Only free memory if allocate memory calls were successful.
+ */
+
+ if (adapter->init_block != NULL)
+ {
+ /*
+ * Initialize variable used for freeing memory.
+ */
+
+ fastmac_parms = &adapter->init_block->fastmac_parms;
+
+#ifndef FMPLUS
+
+ /*
+ * Free transmit buffer space if allocated.
+ */
+
+ if (adapter->tx_buffer_phys != NULL_PHYSADDR)
+ {
+ sys_free_dma_phys_buffer(
+ adapter_handle,
+ fastmac_parms->tx_buf_size,
+ adapter->tx_buffer_phys,
+ adapter->tx_buffer_virt
+ );
+ }
+
+ /*
+ * Free receive buffer space if allocated.
+ */
+
+ if (adapter->rx_buffer_phys != NULL_PHYSADDR)
+ {
+ sys_free_dma_phys_buffer(
+ adapter_handle,
+ fastmac_parms->rx_buf_size,
+ adapter->rx_buffer_phys,
+ adapter->rx_buffer_virt
+ );
+ }
+
+#else
+
+ /*
+ * Free receive buffer space if allocated.
+ */
+
+ rxtx_free_rx_buffers(
+ adapter,
+ fastmac_parms->max_frame_size,
+ fastmac_parms->rx_slots
+ );
+
+ /*
+ * Free transmit buffer space if allocated.
+ */
+
+ rxtx_free_tx_buffers(
+ adapter,
+ fastmac_parms->max_frame_size,
+ fastmac_parms->tx_slots
+ );
+
+#endif
+
+ /*
+ * Free the initialization block allocated memory.
+ */
+
+ sys_free_init_block(
+ adapter_handle,
+ (BYTE *) adapter->init_block,
+ sizeof(INITIALIZATION_BLOCK)
+ );
+ }
+
+ /*
+ * Free status structure if allocated.
+ */
+
+ if (adapter->status_info != NULL)
+ {
+ sys_free_status_structure(
+ adapter_handle,
+ (BYTE *) adapter->status_info,
+ sizeof(STATUS_INFORMATION)
+ );
+ }
+
+#ifdef FMPLUS
+
+ if (adapter->dma_test_buf_virt != 0)
+ {
+ sys_free_dma_phys_buffer(
+ adapter->adapter_handle,
+ SCB_TEST_PATTERN_LENGTH + SSB_TEST_PATTERN_LENGTH + 1,
+ adapter->dma_test_buf_phys,
+ adapter->dma_test_buf_virt
+ );
+ }
+
+#endif
+
+ /*
+ * Already know adapter allocate was successful hence always free it.
+ */
+
+ sys_free_adapter_structure(
+ adapter_handle,
+ (BYTE *) adapter,
+ sizeof(ADAPTER)
+ );
+
+ /*
+ * Clear entry in adapter pointers array.
+ */
+
+ adapter_record[adapter_handle] = NULL;
+
+ /*
+ * Complete successfully.
+ */
+
+ return TRUE;
+}
+
+/*---------------------------------------------------------------------------
+|
+| driver_wait_for_adapter_open
+| ============================
+|
+| The driver_wait_for_adapter_open routine waits at least 40 seconds for
+| the adapter to open. It discovers whether the adapter has opened
+| successfully or not by looking in the Fastmac status block (STB). If the
+| adapter fails to open then this routine fills in the adapter error
+| record.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(driver_wait_for_adapter_open)
+#endif
+
+local WBOOLEAN
+driver_wait_for_adapter_open(
+ UINT * open_status,
+ ADAPTER * adapter
+ )
+{
+ ADAPTER_HANDLE adapter_handle = adapter->adapter_handle;
+ WBOOLEAN open_okay;
+ UINT open_error;
+ UINT index;
+
+ /*
+ * Wait at least a total of 40 seconds for adapter to open.
+ */
+
+ for (index = 0; index < 160; index++)
+ {
+ /*
+ * Set up DIO address to open status field in STB (status block).
+ */
+
+ sys_outsw(
+ adapter_handle,
+ adapter->sif_adr,
+ (WORD) (card_t) &adapter->stb_dio_addr->adapter_open
+ );
+
+ /*
+ * Read open status field from DIO space. If successfully
+ * opened then complete successfully.
+ */
+
+ open_okay = (WBOOLEAN) sys_insw(
+ adapter_handle,
+ adapter->sif_datinc
+ );
+
+ if (open_okay)
+ {
+ *open_status = EAGLE_OPEN_ERROR_SUCCESS;
+ return TRUE;
+ }
+
+ /*
+ * If not opened, see if an error has occured to prevent opening.
+ */
+
+ open_error = sys_insw(adapter_handle, adapter->sif_datinc);
+ *open_status = open_error;
+
+ if (open_error != EAGLE_OPEN_ERROR_SUCCESS)
+ {
+ adapter->error_record.type = ERROR_TYPE_AUTO_OPEN;
+ adapter->error_record.value = AUTO_OPEN_E_01_OPEN_ERROR;
+
+ return FALSE;
+ }
+
+ /*
+ * Opening procedure not completed. Wait at least 250 milliseconds
+ * before checkig again. Disable and re-enable accessing IO locations
+ * around wait so delay can reschedule this task and not effect others
+ * running.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io( adapter);
+#endif
+
+ sys_wait_at_least_milliseconds(250);
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io( adapter);
+#endif
+
+ }
+
+ /*
+ * At least 40 seconds have gone so return time out failure.
+ */
+
+ adapter->error_record.type = ERROR_TYPE_AUTO_OPEN;
+ adapter->error_record.value = AUTO_OPEN_E_80_TIME_OUT;
+
+ return FALSE;
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| driver_get_max_frame_size
+| =========================
+|
+| The driver_get_max_frame_size routine calculates the maximum sized frame
+| that can be transmitted or received. This calculation is based on the
+| maximum frame size determined by ring speed alone, the size of the
+| Fastmac buffers, and the fact that Fastmac pointers have to be DWORD
+| aligned.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(driver_get_max_frame_size)
+#endif
+
+local WORD
+driver_get_max_frame_size(
+ ADAPTER * adapter,
+ FASTMAC_INIT_PARMS * fastmac_parms
+ )
+{
+#ifdef FMPLUS
+
+ return adapter->max_frame_size;
+
+#else
+
+ WORD tx_max_frame_size;
+ WORD rx_max_frame_size;
+ WORD max_frame_size;
+
+ /*
+ * Calculate max transmit frame size from size of buffer, size of
+ * header and knowing that one frame must leave space such that host
+ * and adapter ptrs into buffer are not the same.
+ */
+
+ tx_max_frame_size =
+ fastmac_parms->tx_buf_size - macro_dword_align(
+ FASTMAC_BUFFER_HEADER_SIZE +
+ fastmac_parms->tx_buf_space +
+ sizeof(DWORD)
+ );
+
+ /*
+ * Calculate max receive frame size from size of buffer, size of
+ * header and knowing that one frame must leave space such that host
+ * and adapter ptrs into buffer are not the same.
+ */
+
+ rx_max_frame_size =
+ fastmac_parms->rx_buf_size - macro_dword_align(
+ FASTMAC_BUFFER_HEADER_SIZE +
+ fastmac_parms->rx_buf_space +
+ sizeof(DWORD)
+ );
+
+ /*
+ * Actual max frame size is minimum of max transmit and receive frame
+ * sizes and max frame size for adapter (ring speed dependent).
+ */
+
+ max_frame_size = util_minimum(
+ tx_max_frame_size,
+ rx_max_frame_size,
+ adapter->max_frame_size
+ );
+
+ return max_frame_size;
+
+#endif
+}
+
+/**** End of DRV_INIT.C file ***********************************************/
diff --git a/private/ntos/ndis/madge/driver/drv_irq.c b/private/ntos/ndis/madge/driver/drv_irq.c
new file mode 100644
index 000000000..5d484aa61
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/drv_irq.c
@@ -0,0 +1,413 @@
+/****************************************************************************
+*
+* DRV_IRQ.C : Part of the FASTMAC TOOL-KIT (FTK)
+*
+* THE DRIVER MODULE (INTERRUPT HANDLE)
+*
+* Copyright (c) Madge Networks Ltd. 1991-1994
+*
+* COMPANY CONFIDENTIAL
+*
+*****************************************************************************
+*
+* The driver module provides a simple interface to allow the use of
+* Fastmac in as general a setting as possible. It handles the downloading
+* of the Fastmac code and the initialization of the adapter card. It
+* provides simple transmit and receive routines. It is desgined to
+* quickly allow the implementation of Fastmac applications. It is not
+* designed as the fastest or most memory efficient solution.
+*
+* DRV_IRQ.C contains code to handle SIF interrupts from the adapter card.
+* The HWI_ modules take care of any PIO interrupts, and anything else is
+* passed here. There is also code for calling the received frame handler
+* from the foreground task rather than at interrupt time.
+*
+****************************************************************************/
+
+/*---------------------------------------------------------------------------
+|
+| DEFINITIONS
+|
+---------------------------------------------------------------------------*/
+
+#include "ftk_defs.h"
+
+/*---------------------------------------------------------------------------
+|
+| MODULE ENTRY POINTS
+|
+---------------------------------------------------------------------------*/
+
+#include "ftk_intr.h" /* routines internal to FTK */
+#include "ftk_extr.h" /* routines provided or used by external FTK user */
+
+/****************************************************************************
+*
+* driver_interrupt_entry
+* ======================
+*
+* PARAMETERS (passed by hwi_<card_type>_sif_interrupt) :
+* ======================================================
+*
+* ADAPTER_HANDLE adapter_handle
+*
+* The adapter handle for the adapter so it can be passed to the user
+* supplied user_receive_frame or user_completed_srb routine.
+*
+* ADAPTER * adapter
+*
+* The details of the adapter that the interrupt has occured on.
+*
+* WORD sifint_actual
+*
+* The actual contents of the EAGLE SIF interrupt register.
+*
+* BODY :
+* ======
+*
+* The driver_interupt_entry routine is called by the HWI. It is entered
+* when an interrupt has occured for the given adapter. This could be
+* because of an SRB free interrupt, an adapter chack interrupt or because
+* frames are in the Fastmac receive buffer. Note these frames may have
+* been in the receive buffer some time but not yet dealt with.
+*
+* On an SRB free interrupt, the interrupt is acknowledged and the
+* driver_completing_srb routine in DRV_SRB.C is called. This results in
+* the user supplied routine user_completed_srb being called informing the
+* user on the success or failure of the current SRB and letting the user
+* know that another SRB can be issued.
+*
+* On adapter check interrupts, the error record for the adapter is filled
+* in to mark the adapter as no longer working. A call to a user function
+* is made in case higher level code needs to take action.
+*
+* On receive frame interrupts, the action taken depends on the receive
+* method being used. In FTK_RX_BY_SCHEDULED_PROCESS mode, the user routine
+* user_schedule_receive_process is called with the adapter handle as the
+* only parameter. It is the job of this user routine to schedule a process
+* to call driver_get_outstanding_receive to get the received frames out of
+* the Fastmac receive buffer. In FTK_RX_OUT_OF_INTERRUPTS mode, the received
+* frames are dealt with immediately via the rxtx_irq_rx_frame_handler
+* routine and the user supplied receive routine user_receive_frame.
+*
+* The rxtx_irq_rx_frame_handler routine is actually the same routine
+* that is called by the driver_get_outstanding_receive routine if the
+* FTK_RX_BY_SCHEDULED_PROCESS receive method is being used.
+*
+*
+* Note on increasing speed:
+*
+* One way of speeding up execution of the receive routine would be to
+* replace the sys_outsw and sys_insw routines by similar routines supplied
+* with your C compiler and have them compiled in-line.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine always succeeds and returns control to the HWI routine
+* hwi_<type>_sif_interrupt.
+*
+****************************************************************************/
+
+#ifdef FTK_IRQ_FUNCTION
+#pragma FTK_IRQ_FUNCTION(driver_interrupt_entry)
+#endif
+
+export void
+driver_interrupt_entry(
+ ADAPTER_HANDLE adapter_handle,
+ ADAPTER * adapter,
+ WORD sifint_actual
+ )
+{
+ WORD sifint_value;
+ WBOOLEAN ack_needed = FALSE;
+
+ /*
+ * XOR the high byte and low byte of contents of EAGLE_SIFINT register.
+ */
+
+ sifint_value = (sifint_actual & 0x00FF) ^ (sifint_actual >> 8);
+
+ /*
+ * AND with 0x000F so left with a nibble identifying interrupt type.
+ */
+
+ sifint_value = sifint_value & 0x000F;
+
+ /*
+ * Action depends on interrupt type.
+ */
+
+ if (sifint_value != 0)
+ {
+ if ((sifint_value & FASTMAC_SIFINT_ADAPTER_CHECK) != 0)
+ {
+ /*
+ * For adapter check, fill in error record so adapter now dead.
+ * No need to check if any other interrupt bits set.
+ */
+
+ adapter->error_record.type = ERROR_TYPE_ADAPTER;
+ adapter->error_record.value = ADAPTER_E_01_ADAPTER_CHECK;
+
+ /*
+ * Allow the user to give some sort of warning.
+ */
+
+ user_handle_adapter_check(adapter_handle);
+ }
+ else
+ {
+ if ((sifint_value & FASTMAC_SIFINT_SRB_FREE) != 0)
+ {
+ /*
+ * For SRB free interrupts, call routine which informs user.
+ */
+
+ driver_completing_srb(adapter_handle, adapter);
+ ack_needed = TRUE;
+ }
+
+ if ((sifint_value & FASTMAC_SIFINT_ARB_COMMAND) != 0)
+ {
+ /*
+ * For ARB command interrupts, do nothing as
+ * they should never happen.
+ */
+
+ ack_needed = TRUE;
+ }
+
+ if ((sifint_value & FASTMAC_SIFINT_SSB_RESPONSE) != 0)
+ {
+ /*
+ * For SSB response interrupts, do nothing as
+ * they should never happen.
+ */
+
+ ack_needed = TRUE;
+ }
+ }
+ }
+
+ /*
+ * Now check for receives and transmits...
+ */
+
+#ifdef FMPLUS
+
+ /*
+ * For Fastmac Plus, we must allow for the possibility that the
+ * interrupt is because a large transmit buffer DMA is complete.
+ */
+
+#ifdef FTK_TX_WITH_COMPLETION
+
+#ifndef FTK_NO_TX_COMPLETION_CALL
+
+ rxtx_irq_tx_completion_check(adapter_handle, adapter);
+
+#endif
+
+#endif
+
+#endif
+
+ /*
+ * Invoke received frame processing based on the receive mode.
+ */
+
+#ifdef FTK_RX_OUT_OF_INTERRUPTS
+
+ rxtx_irq_rx_frame_handler(adapter_handle, adapter);
+
+#endif
+
+#ifdef FTK_RX_BY_SCHEDULED_PROCESS
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+
+ user_schedule_receive_process(adapter_handle);
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+#endif
+
+ /*
+ * Now do any cleaning up that is needed ...
+ * For certain interrupts, need to interrupt Fastmac to acknowledge.
+ */
+
+ if (ack_needed)
+ {
+ /*
+ * Convert from FASTMAC_SIFINT interrupt into DRIVER_SIFINT_ACK
+ * to acknowledge interrupt.
+ */
+
+ sifint_value = (sifint_value << 8);
+
+ /*
+ * Set interrupt adapter bit in SIFCMD.
+ */
+
+ sifint_value = (sifint_value | DRIVER_SIFINT_IRQ_FASTMAC);
+
+ /*
+ * Mask SIFSTS so not clear interrupt if Fastmac interrupted again.
+ */
+
+ sifint_value = (sifint_value | DRIVER_SIFINT_FASTMAC_IRQ_MASK);
+
+ /*
+ * Interrupt Fastmac.
+ */
+
+ sys_outsw(adapter_handle, adapter->sif_int, sifint_value);
+ }
+
+ /*
+ * Return to hwi_interrupt_entry routine.
+ */
+}
+
+/****************************************************************************
+*
+* driver_get_outstanding_receive
+* ==============================
+*
+* PARAMETERS :
+* ============
+*
+* ADAPTER_HANDLE adapter_handle
+*
+* This handle identifies the adapter which we wish to deal with
+* outstanding received frames on.
+*
+* BODY :
+* ======
+*
+* The driver_get_outstanding_receive routine should be called only when
+* using the FTK_RX_BY_SCHEDULED_PROCESS receive method. The user supplied
+* receive routine (user_receive_frame) is called with the adapter handle
+* and the length and a physical address pointer to the oldest unprocessed
+* received frame for the given adapter. If there are no oustanding
+* received frames the user routine is never called but this is not an
+* error and is not regsitered as such.
+*
+* If the receive routine processes the frame (returns DO_NOT_KEEP_FRAME),
+* and if the Fastmac receive buffer is not empty, the receive routine is
+* called again with the details of the next frame. This continues until
+* either the Fastmac buffer is empty or the receive routine does not
+* process the frame (returns KEEP_FRAME). However, no more than one buffer
+* full of frames is passed to the user receive routine on any one entry to
+* driver_get_outstanding_receive. Note that if the receive buffer is not
+* emptied by the user then another interrupt will occur later and the
+* process that calls driver_get_outstanding_receive will be rescheduled.
+*
+* To deal with the details of handling received frames in the Fastmac
+* buffers, this routine uses rxtx_irq_rx_frame_handler. This is the
+* same routine called out of driver_interrupt_entry if the
+* FTK_RX_OUT_OF_INTERRUPTS receive method is being used. The routine uses
+* an algorithm for dealing with received frames similar to that in the
+* Fastmac specification document.
+*
+* Dealing with received frames using the driver_get_outstanding_receive
+* routine is different to using the driver_interrupt_entry routine in that
+* the former routine is called under user control, in strategy time as
+* opposed to interrupt time, and hence gives the user receive frame
+* routine more time to process frames. This is necessary under certain
+* operating systems such as AIX.
+*
+* Notes on increasing speed:
+*
+* The code between "#ifndef SPEED_ABOVE_TESTING" to "#endif" is only for
+* testing purposes. If SPEED_ABOVE_TESTING is defined during compilation
+* then the code will not be included so the receive routine will execute
+* faster. However, an erroneous adapter handle would then cause a program
+* to crash unpredicatably. The SPEED_ABOVE_TESTING option should be used
+* with care.
+*
+* Another way of speeding up execution of the receive routine would be to
+* replace the sys_outsw and sys_insw routines by similar routines supplied
+* with your C compiler and have them compiled in-line.
+*
+* RETURNS :
+* =========
+*
+* The routine returns TRUE if it succeeds. If this routine fails (returns
+* FALSE) then a subsequent call to driver_explain_error with the same
+* adapter handle will give an explanation. Note that it will not fail just
+* because there are no frames to receive.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(driver_get_outstanding_receive)
+#endif
+
+export WBOOLEAN
+driver_get_outstanding_receive(
+ ADAPTER_HANDLE adapter_handle
+ )
+{
+ ADAPTER * adapter;
+
+ /*
+ * Check adapter handle and status of adapter for validity.
+ * If routine fails return failure (error record already filled in).
+ */
+
+#ifndef SPEED_ABOVE_TESTING
+
+ if (!driver_check_adapter(adapter_handle, ADAPTER_RUNNING, SRB_ANY_STATE))
+ {
+ return FALSE;
+ }
+
+#endif
+
+ /*
+ * Get pointer to adapter structure.
+ */
+
+ adapter = adapter_record[adapter_handle];
+
+ /*
+ * Inform the system about the IO ports we are going to access.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ /*
+ * Perform the actual frame receiving uses same routine called out
+ * of interrupts with FTK_RX_OUT_OF_INTERRUPTS.
+ */
+
+ rxtx_irq_rx_frame_handler(adapter_handle, adapter);
+
+ /*
+ * Let the system know we have finished accessing the IO ports.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+
+ /*
+ * Receive completed.
+ */
+
+ return TRUE;
+}
+
+
+/**** End of DRV_IRQ.C file ************************************************/
diff --git a/private/ntos/ndis/madge/driver/drv_srb.c b/private/ntos/ndis/madge/driver/drv_srb.c
new file mode 100644
index 000000000..cd84d70d3
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/drv_srb.c
@@ -0,0 +1,1849 @@
+/****************************************************************************
+*
+* DRV_SRB.C : Part of the FASTMAC TOOL-KIT (FTK)
+*
+* THE DRIVER MODULE (SRBs)
+*
+* Copyright (c) Madge Networks Ltd. 1991-1994
+*
+* COMPANY CONFIDENTIAL
+*
+*****************************************************************************
+*
+* The driver module provides a simple interface to allow the use of
+* Fastmac in as general a setting as possible. It handles the downloading
+* of the Fastmac code and the initialization of the adapter card. It
+* provides simple transmit and receive routines. It is desgined to
+* quickly allow the implementation of Fastmac applications. It is not
+* designed as the fastest or most memory efficient solution.
+*
+* The DRV_SRB.C module contains those routines that involve issuing SRBs,
+* such as open adapter and set functional address. It also contains the
+* code that calls the user when an SRB completes.
+*
+****************************************************************************/
+
+/*---------------------------------------------------------------------------
+|
+| DEFINITIONS
+|
+---------------------------------------------------------------------------*/
+
+#include "ftk_defs.h"
+
+/*---------------------------------------------------------------------------
+|
+| MODULE ENTRY POINTS
+|
+---------------------------------------------------------------------------*/
+
+#include "ftk_intr.h" /* routines internal to FTK */
+#include "ftk_extr.h" /* routines provided or used by external FTK user */
+
+/*---------------------------------------------------------------------------
+|
+| GLOBAL VARIABLES
+|
+---------------------------------------------------------------------------*/
+
+export char ftk_product_inst_id[SIZEOF_PRODUCT_ID] = FASTMAC_PRODUCT_ID;
+
+/*---------------------------------------------------------------------------
+|
+| LOCAL FUNCTIONS
+|
+---------------------------------------------------------------------------*/
+
+local void
+driver_issue_srb(
+ ADAPTER * adapter
+ );
+
+local WBOOLEAN
+get_open_and_ring_status(
+ void * ptr
+ );
+
+local WBOOLEAN
+issue_srb(
+ void * ptr
+ );
+
+/****************************************************************************
+*
+* driver_ring_speed
+* =================
+*
+* PARAMETERS :
+* ============
+*
+* ADAPTER_HANDLE adapter_handle
+*
+* This handle identifies the adapter whose ring speed is to be returned.
+*
+* BODY :
+* ======
+*
+* This is a short helper function (that could easily be replaced by a
+* macro). It just digs out the stored ring speed from the adapter
+* structure, so that external users of the FTK have some way of getting at
+* this piece of information.
+*
+* RETURNS :
+* =========
+*
+* The current ring speed.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(driver_ring_speed)
+#endif
+
+export UINT
+driver_ring_speed(
+ ADAPTER_HANDLE adapter_handle
+ )
+{
+ return adapter_record[adapter_handle]->ring_speed;
+}
+
+/****************************************************************************
+*
+* driver_max_frame_size
+* =====================
+*
+* PARAMETERS :
+* ============
+*
+* ADAPTER_HANDLE adapter_handle
+*
+* This handle identifies the adapter whose maximum supported frame size is
+* to be returned.
+*
+* BODY :
+* ======
+*
+* This is a short helper function (that could easily be replaced by a
+* macro). It just digs out the stored maximum frame size from the adapter
+* structure, so that external users of the FTK have some way of getting at
+* this piece of information.
+*
+* RETURNS :
+* =========
+*
+* The current maximum frame size.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(driver_max_frame_size)
+#endif
+
+export UINT
+driver_max_frame_size(
+ ADAPTER_HANDLE adapter_handle
+ )
+{
+ return adapter_record[adapter_handle]->max_frame_size;
+}
+
+/****************************************************************************
+*
+* driver_modify_open_options
+* ==========================
+*
+* PARAMETERS :
+* ============
+*
+* ADAPTER_HANDLE adapter_handle
+*
+* This handle identifies the adapter on which to modify the open options.
+*
+* WORD open_options
+*
+* This gives the new modified open options for the adapter.
+*
+* BODY :
+* ======
+*
+* The driver_modify_open_options routine issues a modify open parms SRB.
+* The adapter must be open for this command to complete successfully. It
+* does not matter whether the adapter has been opened in auto-open mode or
+* using an open adapter SRB.
+*
+* As with all the routines that involve issuing SRBs, the user routine
+* user_completed_srb is called when the SRB completes. It is this user
+* routine that is informed as to whether the SRB completed successfully.
+* Also, until this routine is called by the driver, no other driver
+* routines involving the issuing of SRBs for the given adapter will work.
+* This is because there is only one SRB per adapter.
+*
+* Note that only those fields that are used in the SRB (ie. have non-zero
+* values) that need to be byte swapped are byte swapped either in this
+* routine or in driver_issue_srb. Hence, if any adjustments are made to
+* the code it may be necessary to make sure that any newly used fields are
+* correctly byte swapped before downloading.
+*
+* Take special note of the fact that the user_completed_srb routine can be
+* called before this routine completes. This is because it is called out
+* of interrupts.
+*
+* RETURNS :
+* =========
+*
+* The routine returns TRUE if it succeeds. If this routine fails (returns
+* FALSE) then a subsequent call to driver_explain_error with the same
+* adapter handle will give an explanation.
+*
+* Note that a successful call to this routine only means that the SRB has
+* been issued successfully. It does not mean that it has completed
+* successfully. The success or failure of the SRB is indicated in a
+* subsequent call to user_completed_srb.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(driver_modify_open_options)
+#endif
+
+export WBOOLEAN
+driver_modify_open_options(
+ ADAPTER_HANDLE adapter_handle,
+ WORD open_options
+ )
+{
+ ADAPTER * adapter;
+ SRB_GENERAL * srb_gen;
+
+ /*
+ * Check adapter handle and status of adapter for validity.
+ * If routine fails return failure (error record already filled in).
+ */
+
+ if (!driver_check_adapter(adapter_handle, ADAPTER_RUNNING, SRB_FREE))
+ {
+ return FALSE;
+ }
+
+ /*
+ * Get pointer to adapter structure.
+ */
+
+ adapter = adapter_record[adapter_handle];
+
+ /*
+ * Set adapter SRB status to show that SRB is now in use.
+ */
+
+ adapter->srb_status = SRB_NOT_FREE;
+
+ /*
+ * Get pointer to general SRB structure to be used.
+ */
+
+ srb_gen = &adapter->srb_general;
+
+ /*
+ * Clear part of general SRB to be used.
+ */
+
+ util_zero_memory((BYTE *) srb_gen, sizeof(SRB_MODIFY_OPEN_PARMS));
+
+ /*
+ * Set up non-zero modify open parms SRB fields.
+ */
+
+ srb_gen->mod_parms.header.function = MODIFY_OPEN_PARMS_SRB;
+ srb_gen->mod_parms.open_options = open_options;
+
+ /*
+ * Save a copy of the open options in the fastmac init block, in
+ * case we later have to re-open the adapter with the same state. This
+ * is the case with NDIS3 MacReset(), which causes the card to be re-
+ * initialized, but the open options must be left as they were before
+ * the reset.
+ */
+
+ adapter->init_block->fastmac_parms.open_options = open_options;
+
+ /*
+ * Record size of SRB that is being issued.
+ */
+
+ adapter->size_of_srb = sizeof(SRB_MODIFY_OPEN_PARMS);
+
+ /*
+ * Call routine to issue SRB.
+ */
+
+ driver_issue_srb(adapter);
+
+ /*
+ * SRB issued successfully.
+ */
+
+ return TRUE;
+}
+
+/****************************************************************************
+*
+* driver_open_adapter
+* ===================
+*
+* PARAMETERS :
+* ============
+*
+* ADAPTER_HANDLE adapter_handle
+*
+* This handle identifies the adapter to be opened.
+*
+* PTR_OPEN_DATA open_data
+*
+* This points to a structure containing : the open options, the opening
+* node address, the opening functional address, and the opening group
+* address. If the opening node address is NULL, the BIA PROM node address
+* will be used instead.
+*
+* BODY :
+* ======
+*
+* The driver_open_adapter routine issues an open adapter SRB. This routine
+* is not needed when the Fastmac auto_open option is used.
+*
+* As with all the routines that involve issuing SRBs, the user routine
+* user_completed_srb is called when the SRB completes. It is this user
+* routine that is informed as to whether the SRB completed successfully.
+* Also, until this routine is called by the driver, no other driver
+* routines involving the issuing of SRBs for the given adapter will work.
+* This is because there is only one SRB per adapter.
+*
+* Note that only those fields that are used in the SRB (ie. have non-zero
+* values) that need to be byte swapped are byte swapped either in this
+* routine or in driver_issue_srb. Hence, if any adjustments are made to
+* the code it may be necessary to make sure that any newly used fields are
+* correctly byte swapped before downloading.
+*
+* Take special note of the fact that the user_completed_srb routine can be
+* called before this routine completes. This is because it is called out
+* of interrupts.
+*
+* RETURNS :
+* =========
+*
+* The routine returns TRUE if it succeeds. If this routine fails (returns
+* FALSE) then a subsequent call to driver_explain_error with the same
+* adapter handle will give an explanation.
+*
+* Note that a successful call to this routine only means that the SRB has
+* been issued successfully. It does not mean that it has completed
+* successfully. The success or failure of the SRB is indicated in a
+* subsequent call to user_completed_srb.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(driver_open_adapter)
+#endif
+
+export WBOOLEAN
+driver_open_adapter(
+ ADAPTER_HANDLE adapter_handle,
+ PTR_OPEN_DATA open_data
+ )
+{
+ ADAPTER * adapter;
+ SRB_GENERAL * srb_gen;
+ UINT i;
+
+ /*
+ * Check adapter handle and status of adapter for validity.
+ * If routine fails return failure (error record already filled in).
+ */
+
+ if (!driver_check_adapter( adapter_handle, ADAPTER_RUNNING, SRB_FREE))
+ {
+ return FALSE;
+ }
+
+ /*
+ * Get pointer to adapter structure.
+ */
+
+ adapter = adapter_record[adapter_handle];
+
+ /*
+ * Set adapter SRB status to show that SRB is now in use.
+ */
+
+ adapter->srb_status = SRB_NOT_FREE;
+
+ /*
+ * get pointer to general SRB structure to be used.
+ */
+
+ srb_gen = &adapter->srb_general;
+
+ /*
+ * Clear part of general SRB to be used.
+ */
+
+ util_zero_memory((BYTE *) srb_gen, sizeof(SRB_OPEN_ADAPTER));
+
+ /*
+ * Set up non-zero open adapter SRB fields.
+ */
+
+ srb_gen->open_adap.header.function = OPEN_ADAPTER_SRB;
+ srb_gen->open_adap.open_options = open_data->open_options;
+
+ /*
+ * Fill in opening node address field.
+ */
+
+ for (i = 0; i < sizeof(NODE_ADDRESS); i++)
+ {
+ if (open_data->opening_node_address.byte[i] != 0)
+ {
+ break;
+ }
+ }
+
+ if (i == sizeof(NODE_ADDRESS))
+ {
+ /*
+ * If opening node address not given then use BIA PROM address.
+ */
+
+ srb_gen->open_adap.open_address = adapter->permanent_address;
+ }
+ else
+ {
+ /*
+ * Otherwise use supplied node address.
+ */
+
+ srb_gen->open_adap.open_address = open_data->opening_node_address;
+ }
+
+ srb_gen->open_adap.group_address = open_data->group_address;
+ srb_gen->open_adap.functional_address = open_data->functional_address;
+
+ /*
+ * Byte swap node address before downloading to adapter.
+ */
+
+ util_byte_swap_structure(
+ (BYTE *) &srb_gen->open_adap.open_address,
+ sizeof(NODE_ADDRESS)
+ );
+
+ /*
+ * Fill in the product id with product ID string.
+ */
+
+ util_mem_copy(
+ srb_gen->open_adap.product_id,
+ ftk_product_inst_id,
+ SIZEOF_PRODUCT_ID
+ );
+
+ /*
+ * Byte swap the product id string before downloading.
+ */
+
+ util_byte_swap_structure(
+ (BYTE *) srb_gen->open_adap.product_id,
+ SIZEOF_PRODUCT_ID
+ );
+
+ /*
+ * Record size of SRB that is being issued.
+ */
+
+ adapter->size_of_srb = sizeof(SRB_OPEN_ADAPTER);
+
+ /*
+ * Call routine to issue SRB.
+ */
+
+ driver_issue_srb(adapter);
+
+ /*
+ * SRB issued successfully.
+ */
+
+ return TRUE;
+}
+
+/****************************************************************************
+*
+* driver_close_adapter
+* ====================
+*
+* PARAMETERS :
+* ============
+*
+* ADAPTER_HANDLE adapter_handle
+*
+* This handle identifies the adapter to be closed.
+*
+*
+* BODY :
+* ======
+*
+* The driver_close_adapter routine issues a close adapter SRB. If the
+* auto_open feature is being used then it is disabled by this call.
+*
+* As with all the routines that involve issuing SRBs, the user routine
+* user_completed_srb is called when the SRB completes. It is this user
+* routine that is informed as to whether the SRB completed successfully.
+* Also, until this routine is called by the driver, no other driver
+* routines involving the issuing of SRBs for the given adapter will work.
+* This is because there is only one SRB per adapter.
+*
+* Note that only those fields that are used in the SRB (ie. have non-zero
+* values) that need to be byte swapped are byte swapped either in this
+* routine or in driver_issue_srb. Hence, if any adjustments are made to
+* the code it may be necessary to make sure that any newly used fields are
+* correctly byte swapped before downloading.
+*
+* Take special note of the fact that the user_completed_srb routine can be
+* called before this routine completes. This is because it is called out
+* of interrupts.
+*
+* RETURNS :
+* =========
+*
+* The routine returns TRUE if it succeeds. If this routine fails (returns
+* FALSE) then a subsequent call to driver_explain_error with the same
+* adapter handle will give an explanation.
+*
+* Note that a successful call to this routine only means that the SRB has
+* been issued successfully. It does not mean that it has completed
+* successfully. The success or failure of the SRB is indicated in a
+* subsequent call to user_completed_srb.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(driver_close_adapter)
+#endif
+
+export WBOOLEAN
+driver_close_adapter(
+ ADAPTER_HANDLE adapter_handle
+ )
+{
+ ADAPTER * adapter;
+ SRB_GENERAL * srb_gen;
+
+ /*
+ * Check adapter handle and status of adapter for validity.
+ * If routine fails return failure (error record already filled in).
+ */
+
+ if (!driver_check_adapter(adapter_handle, ADAPTER_RUNNING, SRB_FREE))
+ {
+ return FALSE;
+ }
+
+ /*
+ * Get pointer to adapter structure.
+ */
+
+ adapter = adapter_record[adapter_handle];
+
+ /*
+ * Set adapter SRB status to show that SRB is now in use.
+ */
+
+ adapter->srb_status = SRB_NOT_FREE;
+
+ /*
+ * Get pointer to general SRB structure to be used.
+ */
+
+ srb_gen = &adapter->srb_general;
+
+ /*
+ * Clear part of general SRB to be used.
+ */
+
+ util_zero_memory((BYTE *) srb_gen, sizeof(SRB_CLOSE_ADAPTER));
+
+ /*
+ * Place SRB type into header.
+ */
+
+ srb_gen->close_adap.header.function = CLOSE_ADAPTER_SRB;
+
+ /*
+ * Record size of SRB that is being issued.
+ */
+
+ adapter->size_of_srb = sizeof(SRB_CLOSE_ADAPTER);
+
+ /*
+ * Call routine to issue SRB.
+ */
+
+ driver_issue_srb(adapter);
+
+ /*
+ * SRB issued successfully.
+ */
+
+ return TRUE;
+}
+
+/****************************************************************************
+*
+* driver_set_group_address
+* ========================
+*
+* PARAMETERS :
+* ============
+*
+* ADAPTER_HANDLE adapter_handle
+*
+* This handle identifies the required adapter.
+*
+* MULTI_ADDRESS * group_address
+*
+* The adapter is configured to receive frames sent to the group address
+* formed from this parameter with the prefix 0xC000 and logically ANDed
+* with 0x80000000. For example {0x12,0x34,0x56,0x78} gives the group
+* address 0xC00092345678.
+*
+* BODY :
+* ======
+*
+* The driver_set_group_address routine issues a set group address SRB. The
+* adapter must be open for the SRB to complete successfully.
+*
+* As with all the routines that involve issuing SRBs, the user routine
+* user_completed_srb is called when the SRB completes. It is this user
+* routine that is informed as to whether the SRB completed successfully.
+* Also, until this routine is called by the driver, no other driver
+* routines involving the issuing of SRBs for the given adapter will work.
+* This is because there is only one SRB per adapter.
+*
+* Note that only those fields that are used in the SRB (ie. have non-zero
+* values) that need to be byte swapped are byte swapped either in this
+* routine or in driver_issue_srb. Hence, if any adjustments are made to
+* the code it may be necessary to make sure that any newly used fields are
+* correctly byte swapped before downloading.
+*
+* Take special note of the fact that the user_completed_srb routine can be
+* called before this routine completes. This is because it is called out
+* of interrupts.
+*
+* RETURNS :
+* =========
+*
+* The routine returns TRUE if it succeeds. If this routine fails (returns
+* FALSE) then a subsequent call to driver_explain_error with the same
+* adapter handle will give an explanation.
+*
+* Note that a successful call to this routine only means that the SRB has
+* been issued successfully. It does not mean that it has completed
+* successfully. The success or failure of the SRB is indicated in a
+* subsequent call to user_completed_srb.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(driver_set_group_address)
+#endif
+
+export WBOOLEAN
+driver_set_group_address(
+ ADAPTER_HANDLE adapter_handle,
+ MULTI_ADDRESS * group_address
+ )
+{
+ ADAPTER * adapter;
+ SRB_GENERAL * srb_gen;
+
+ /*
+ * Check adapter handle and status of adapter for validity.
+ * If routine fails return failure (error record already filled in).
+ */
+
+ if (!driver_check_adapter(adapter_handle, ADAPTER_RUNNING, SRB_FREE))
+ {
+ return FALSE;
+ }
+
+ /*
+ * Get pointer to adapter structure.
+ */
+
+ adapter = adapter_record[adapter_handle];
+
+ /*
+ * Set adapter SRB status to show that SRB is now in use.
+ */
+
+ adapter->srb_status = SRB_NOT_FREE;
+
+ /*
+ * Get pointer to general SRB structure to be used.
+ */
+
+ srb_gen = &adapter->srb_general;
+
+ /*
+ * Clear part of general SRB to be used.
+ */
+
+ util_zero_memory((BYTE *) srb_gen, sizeof(SRB_SET_GROUP_ADDRESS));
+
+ /*
+ * Place SRB type into header.
+ */
+
+ srb_gen->set_group.header.function = SET_GROUP_ADDRESS_SRB;
+
+ /*
+ * Byte swap group address (for downloading) when putting it in SRB.
+ */
+
+ srb_gen->set_group.multi_address = *group_address;
+
+ util_byte_swap_structure(
+ (BYTE *) &srb_gen->set_group.multi_address,
+ sizeof(MULTI_ADDRESS)
+ );
+
+ /*
+ * Record size of SRB that is being issued.
+ */
+
+ adapter->size_of_srb = sizeof(SRB_SET_GROUP_ADDRESS);
+
+ /*
+ * Call routine to issue SRB.
+ */
+
+ driver_issue_srb(adapter);
+
+ /*
+ * SRB issued successfully.
+ */
+
+ return TRUE;
+}
+
+/****************************************************************************
+*
+* driver_set_functional_address
+* =============================
+*
+* PARAMETERS :
+* ============
+*
+* ADAPTER_HANDLE adapter_handle
+*
+* This handle identifies the required adapter.
+*
+* MULTI_ADDRESS * functional_address
+*
+* For each bit set in this parameter, the adapter is configured to receive
+* frames sent to that functional address (0xC000xxxxxxxx). For example, if
+* functional_address equals {0x40,0x00,0x00,0x80} then the corresponding
+* functional addresses are 0xC00040000000 and 0xC00000000080.
+*
+*
+* BODY :
+* ======
+*
+* The driver_set_functional_address routine issues a set functional
+* address SRB. The adapter must be open for the SRB to complete
+* successfully. The effects of this call are not cumulative - that is
+* each call must specify ALL functional addresses required.
+*
+* As with all the routines that involve issuing SRBs, the user routine
+* user_completed_srb is called when the SRB completes. It is this user
+* routine that is informed as to whether the SRB completed successfully.
+* Also, until this routine is called by the driver, no other driver
+* routines involving the issuing of SRBs for the given adapter will work.
+* This is because there is only one SRB per adapter.
+*
+* Note that only those fields that are used in the SRB (ie. have non-zero
+* values) that need to be byte swapped are byte swapped either in this
+* routine or in driver_issue_srb. Hence, if any adjustments are made to
+* the code it may be necessary to make sure that any newly used fields are
+* correctly byte swapped before downloading.
+*
+* Take special note of the fact that the user_completed_srb routine can be
+* called before this routine completes. This is because it is called out
+* of interrupts.
+*
+* RETURNS :
+* =========
+*
+* The routine returns TRUE if it succeeds. If this routine fails (returns
+* FALSE) then a subsequent call to driver_explain_error with the same
+* adapter handle will give an explanation.
+*
+* Note that a successful call to this routine only means that the SRB has
+* been issued successfully. It does not mean that it has completed
+* successfully. The success or failure of the SRB is indicated in a
+* subsequent call to user_completed_srb.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(driver_set_functional_address)
+#endif
+
+export WBOOLEAN
+driver_set_functional_address(
+ ADAPTER_HANDLE adapter_handle,
+ MULTI_ADDRESS * functional_address
+ )
+{
+ ADAPTER * adapter;
+ SRB_GENERAL * srb_gen;
+
+ /*
+ * Check adapter handle and status of adapter for validity.
+ * If routine fails return failure (error record already filled in).
+ */
+
+ if (!driver_check_adapter(adapter_handle, ADAPTER_RUNNING, SRB_FREE))
+ {
+ return FALSE;
+ }
+
+ /*
+ * Get pointer to adapter structure.
+ */
+
+ adapter = adapter_record[adapter_handle];
+
+ /*
+ * Set adapter SRB status to show that SRB is now in use.
+ */
+
+ adapter->srb_status = SRB_NOT_FREE;
+
+ /*
+ * Get pointer to general SRB structure to be used.
+ */
+
+ srb_gen = &adapter->srb_general;
+
+ /*
+ * Clear part of general SRB to be used.
+ */
+
+ util_zero_memory((BYTE *) srb_gen, sizeof(SRB_SET_FUNCTIONAL_ADDRESS));
+
+ /*
+ * Place SRB type into header.
+ */
+
+ srb_gen->set_func.header.function = SET_FUNCTIONAL_ADDRESS_SRB;
+
+ /*
+ * Byte swap functional address (for downloading) when putting in SRB.
+ */
+
+ srb_gen->set_func.multi_address = *functional_address;
+
+ util_byte_swap_structure(
+ (BYTE *) &srb_gen->set_func.multi_address,
+ sizeof(MULTI_ADDRESS)
+ );
+
+ /*
+ * Record size of SRB that is being issued.
+ */
+
+ adapter->size_of_srb = sizeof(SRB_SET_FUNCTIONAL_ADDRESS);
+
+ /*
+ * Call routine to issue SRB.
+ */
+
+ driver_issue_srb(adapter);
+
+ /*
+ * SRB issued successfully.
+ */
+
+ return TRUE;
+}
+
+/****************************************************************************
+*
+* driver_get_open_and_ring_status
+* ===============================
+*
+* PARAMETERS :
+* ============
+*
+* ADAPTER_HANDLE adapter_handle
+*
+* This handle identifies the adapter to get the adapter status information
+* on.
+*
+* WORD * pwRingStatus
+* WORD * pwOpenStatus
+*
+* These OUT parameters are filled with the Open and Ring status values in
+* addition to them being written into the status structure. It is often
+* convenient to be able to have these values stored at the callers whim.
+* They can be NULL if the caller does not need these values directly.
+*
+* BODY :
+* ======
+*
+* The driver_get_open_and_ring_status routine accesses DIO space to get
+* the current adapter open status and the current ring status. These two
+* bits of information are filled into the status information structure in
+* the adapter structure, and written to the supplied locations.
+*
+* RETURNS :
+* =========
+*
+* Nothing. But see the status information structure in the current adapter
+* for the open status and ring status.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(driver_get_open_and_ring_status)
+#endif
+
+export void
+driver_get_open_and_ring_status(
+ ADAPTER_HANDLE adapter_handle,
+ WORD * pwRingStatus,
+ WORD * pwOpenStatus
+ )
+{
+ ADAPTER * adapter;
+
+ /*
+ * Get pointer to adapter structure.
+ */
+
+ adapter = adapter_record[adapter_handle];
+
+ if (adapter == NULL)
+ {
+ if (pwRingStatus != NULL)
+ {
+ *pwRingStatus = 0;
+ }
+ if (pwOpenStatus != NULL)
+ {
+ *pwOpenStatus = 0;
+ }
+ return;
+ }
+
+ /*
+ * Inform the system about the IO ports we are going to access.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ /*
+ * Get adapter open status from the STB in DIO space.
+ */
+
+ sys_sync_with_interrupt(
+ adapter->adapter_handle,
+ get_open_and_ring_status,
+ adapter);
+
+ /*
+ * Let the system know we have finished accessing the IO ports.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+
+ if (pwRingStatus != NULL)
+ {
+ *pwRingStatus = adapter->status_info->ring_status;
+ }
+ if (pwOpenStatus != NULL)
+ {
+ *pwOpenStatus = adapter->status_info->adapter_open;
+ }
+}
+
+/****************************************************************************
+*
+* driver_get_status
+* =================
+*
+* PARAMETERS :
+* ============
+*
+* ADAPTER_HANDLE adapter_handle
+*
+* This handle identifies the adapter to get the adapter status information
+* on.
+*
+* BODY :
+* ======
+*
+* The driver_get_status routine issues a read error log SRB in order to
+* get the error log maintained by the protocol handler. This routine also
+* accesses DIO space to get the current adapter open status and the
+* current ring status. These two bits of information are actually filled
+* into the status information structure immediately - they are available
+* before the user_completed_srb routine is called.
+*
+* As with all the routines that involve issuing SRBs, the user routine
+* user_completed_srb is called when the actual SRB completes. It is this
+* user routine that is informed as to whether the SRB completed
+* successfully and it is at this time that the error log is filled into
+* the status information structure. Also, until the user_completed_srb
+* routine is called by the driver, no other driver routines involving the
+* issuing of SRBs for the given adapter will work. This is because there
+* is only one SRB per adapter.
+*
+* Note that only those fields that are used in the SRB (ie. have non-zero
+* values) that need to be byte swapped are byte swapped either in this
+* routine or in driver_issue_srb. Hence, if any adjustments are made to
+* the code it may be necessary to make sure that any newly used fields are
+* correctly byte swapped before downloading.
+*
+* Take special note of the fact that the user_completed_srb routine can be
+* called before this routine completes. This is because it is called out
+* of interrupts.
+*
+* Note there is no need to worry about an interrupt occuring, (between the
+* setting of the EAGLE SIFADR register and the reading/writing of the
+* required DIO space data), that would alter the contents of the EAGLE
+* SIFADR register (and hence the SIFDAT and SIFDAT_INC registers too).
+* This is because the receive frame interrupt handler exits leaving the
+* contents of SIFADR as on entry.
+*
+* RETURNS :
+* =========
+*
+* The routine returns TRUE if it succeeds and will have filled in the
+* requested status information but not the error log. If this routine
+* fails (returns FALSE) then a subsequent call to driver_explain_error
+* with the same adapter handle will give an explanation.
+*
+* Note that a successful call to this routine only means that the SRB has
+* been issued successfully. It does not mean that it has completed
+* successfully. The success or failure of the SRB is indicated in a
+* subsequent call to user_completed_srb. Also, in this particular case, it
+* is important to note that the error log is not filled in until the SRB
+* completes.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(driver_get_status)
+#endif
+
+export WBOOLEAN
+driver_get_status(
+ ADAPTER_HANDLE adapter_handle
+ )
+{
+ ADAPTER * adapter;
+ SRB_GENERAL * srb_gen;
+
+ /*
+ * Check adapter handle and status of adapter for validity.
+ * If routine fails return failure (error record already filled in).
+ */
+
+ if (!driver_check_adapter(adapter_handle, ADAPTER_RUNNING, SRB_FREE))
+ {
+ return FALSE;
+ }
+
+ /*
+ * Get pointer to adapter structure.
+ */
+
+ adapter = adapter_record[adapter_handle];
+
+ /*
+ * Get the adapter open status and ring status.
+ */
+
+ driver_get_open_and_ring_status(adapter_handle, NULL, NULL);
+
+ /*
+ * Set adapter SRB status to show that SRB is now in use.
+ */
+
+ adapter->srb_status = SRB_NOT_FREE;
+
+ /*
+ * Get pointer to general SRB structure to be used.
+ */
+
+ srb_gen = &adapter->srb_general;
+
+ /*
+ * Clear part of general SRB to be used.
+ */
+
+ util_zero_memory((BYTE *) srb_gen, sizeof(SRB_READ_ERROR_LOG));
+
+ /*
+ * Place SRB type into header.
+ */
+
+ srb_gen->err_log.header.function = READ_ERROR_LOG_SRB;
+
+ /*
+ * Record size of SRB that is being issued.
+ */
+
+ adapter->size_of_srb = sizeof(SRB_READ_ERROR_LOG);
+
+ /*
+ * Call routine to issue SRB.
+ */
+
+ driver_issue_srb(adapter);
+
+ /*
+ * SRB issued successfully.
+ */
+
+ return TRUE;
+}
+
+
+
+/****************************************************************************
+*
+* driver_set_bridge_parms
+* =======================
+*
+* PARAMETERS :
+* ============
+*
+* ADAPTER_HANDLE adapter_handle
+*
+* This handle identifies the adapter to get the adapter status information
+* on.
+*
+* WBOOLEAN single_route_bcast
+*
+* If this is TRUE, then single route broadcast frames will be rejected
+* by the SRA.
+*
+* UINT this_ring
+*
+* This is the ring number that the SRA will recognise as the source ring.
+* It must be the number of the ring to which this adapter is connected. It
+* will be matched against the source ring field in the routing information
+* section of frames received from this ring.
+*
+* UINT that_ring
+*
+* This is the ring number that the SRA will recognise as the destination
+* ring. It must be the number of the ring to which the other adapter in
+* this host is connected. It will be matched against the target ring field
+* in the routing information section of frames received from the source
+* ring.
+*
+* UINT bridge_num
+*
+* This is the number that identifies this bridge on both rings. It will be
+* matched against the bridge number field in the routing information field
+* of frames received from the source ring.
+*
+* BODY :
+* ======
+*
+* The driver_set_bridge_parms routine issues a set bridge parms SRB.
+* The adapter must be open for the SRB to complete successfully.
+* Two of the fields use default values to simplify the calling procedure a
+* little - these are the number of bridge bits and the maximum length of
+* the routing information field. The number of bridge bits defaults to 4
+* allowing bridge numbers between 0 and 0xF, and ring numbers between 0
+* and 0xFFF. All bridges on the network must agree on this value. The max.
+* routing field causes all frames with routing information fields longer
+* than the specified value to be rejected by the SRA. To be IBM compatible
+* this value should be 18, which is the default value.
+* These values are defined in FTK_SRB.H.
+*
+* As with all the routines that involve issuing SRBs, the user routine
+* user_completed_srb is called when the SRB completes. It is this user
+* routine that is informed as to whether the SRB completed successfully.
+* Also, until this routine is called by the driver, no other driver
+* routines involving the issuing of SRBs for the given adapter will work.
+* This is because there is only one SRB per adapter.
+*
+* Note that only those fields that are used in the SRB (ie. have non-zero
+* values) that need to be byte swapped are byte swapped either in this
+* routine or in driver_issue_srb. Hence, if any adjustments are made to
+* the code it may be necessary to make sure that any newly used fields are
+* correctly byte swapped before downloading.
+*
+* Take special note of the fact that the user_completed_srb routine can be
+* called before this routine completes. This is because it is called out
+* of interrupts.
+*
+* RETURNS :
+* =========
+*
+* The routine returns TRUE if it succeeds. If this routine fails (returns
+* FALSE) then a subsequent call to driver_explain_error with the same
+* adapter handle will give an explanation.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(driver_set_bridge_parms)
+#endif
+
+export WBOOLEAN
+driver_set_bridge_parms(
+ ADAPTER_HANDLE adapter_handle,
+ WBOOLEAN single_route_bcast,
+ UINT this_ring,
+ UINT that_ring,
+ UINT bridge_num
+ )
+{
+ ADAPTER * adapter;
+ SRB_GENERAL * srb_gen;
+ WORD options;
+
+ /*
+ * Check adapter handle and status of adapter for validity.
+ * If routine fails return failure (error record already filled in).
+ */
+
+ if (!driver_check_adapter(adapter_handle, ADAPTER_RUNNING, SRB_FREE))
+ {
+ return FALSE;
+ }
+
+ /*
+ * Get pointer to adapter structure.
+ */
+
+ adapter = adapter_record[adapter_handle];
+
+ /*
+ * Set adapter SRB status to show that SRB is now in use.
+ */
+
+ adapter->srb_status = SRB_NOT_FREE;
+
+ /*
+ * Get pointer to general SRB structure to be used.
+ */
+
+ srb_gen = &adapter->srb_general;
+
+ /*
+ * Clear part of general SRB to be used.
+ */
+
+ util_zero_memory((BYTE *) srb_gen, sizeof(SRB_SET_BRIDGE_PARMS));
+
+ /*
+ * Place SRB type into header.
+ */
+
+ srb_gen->set_bridge_parms.header.function = SET_BRIDGE_PARMS_SRB;
+
+ /*
+ * Fill in the bridge parameters, using defaults from FTK_SRB.H and the
+ * user supplied values.
+ *
+ * Note that the bit fields in the options word are filled in here using
+ * shifts and ORs, because of the danger that different compilers will
+ * order bit fields in a structure differently.
+ */
+
+ options = ((single_route_bcast ? 0x8000 : 0)
+ | ((SRB_SBP_DFLT_ROUTE_LEN & 0x3f) << 4)
+ | (SRB_SBP_DFLT_BRIDGE_BITS & 0xf));
+
+ srb_gen->set_bridge_parms.options = options;
+ srb_gen->set_bridge_parms.this_ring = this_ring;
+ srb_gen->set_bridge_parms.that_ring = that_ring;
+ srb_gen->set_bridge_parms.bridge_num = bridge_num;
+
+ /*
+ * Record size of SRB that is being issued.
+ */
+
+ adapter->size_of_srb = sizeof(SRB_SET_BRIDGE_PARMS);
+
+ /*
+ * Call routine to issue SRB.
+ */
+
+ driver_issue_srb(adapter);
+
+ /*
+ * SRB issued successfully.
+ */
+
+ return TRUE;
+}
+
+
+/****************************************************************************
+*
+* driver_set_product_instance_id
+* ==============================
+*
+* PARAMETERS :
+* ============
+*
+* ADAPTER_HANDLE adapter_handle
+*
+* This handle identifies the adapter on which to set the product instance
+* identification string.
+*
+* BYTE * product_id
+*
+* A pointer to an eighteen byte ASCII Identification string.
+*
+* BODY :
+* ======
+*
+* The driver_set_product_instance_id issues an SRB to set the product id
+* string. This string is written into certain MAC frames to report various
+* software and hardware conditions.
+* As with all the routines that involve issuing SRBs, the user routine
+* user_completed_srb is called when the actual SRB completes. It is this
+* user routine that is informed as to whether the SRB completed
+* successfully and it is at this time that the error log is filled into
+* the status information structure. Also, until the user_completed_srb
+* routine is called by the driver, no other driver routines involving the
+* issuing of SRBs for the given adapter will work. This is because there
+* is only one SRB per adapter.
+*
+* Note that only those fields that are used in the SRB (ie. have non-zero
+* values) that need to be byte swapped are byte swapped either in this
+* routine or in driver_issue_srb. Hence, if any adjustments are made to
+* the code it may be necessary to make sure that any newly used fields are
+* correctly byte swapped before downloading.
+*
+* Take special note of the fact that the user_completed_srb routine can be
+* called before this routine completes. This is because it is called out
+* of interrupts.
+*
+* RETURNS :
+* =========
+*
+* The routine returns TRUE if it succeeds. If this routine fails (returns
+* FALSE) then a subsequent call to driver_explain_error with the same
+* adapter handle will give an explanation.
+*
+* Note that a successful call to this routine only means that the SRB has
+* been issued successfully. It does not mean that it has completed
+* successfully. The success or failure of the SRB is indicated in a
+* subsequent call to user_completed_srb. Also, in this particular case, it
+* is important to note that the error log is not filled in until the SRB
+* completes.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(driver_set_product_instance_id)
+#endif
+
+export WBOOLEAN
+driver_set_product_instance_id(
+ ADAPTER_HANDLE adapter_handle,
+ BYTE * product_id
+ )
+{
+ ADAPTER * adapter;
+ SRB_GENERAL * srb_gen;
+
+ /*
+ * Check adapter handle and status of adapter for validity.
+ * If routine fails return failure (error record already filled in).
+ */
+
+ if (!driver_check_adapter(adapter_handle, ADAPTER_RUNNING, SRB_FREE))
+ {
+ return FALSE;
+ }
+
+ /*
+ * Get pointer to adapter structure.
+ */
+
+ adapter = adapter_record[adapter_handle];
+
+ /*
+ * Set adapter SRB status to show that SRB is now in use.
+ */
+
+ adapter->srb_status = SRB_NOT_FREE;
+
+ /*
+ * Get pointer to general SRB structure to be used.
+ */
+
+ srb_gen = &adapter->srb_general;
+
+ /*
+ * Clear part of general SRB to be used.
+ */
+
+ util_zero_memory((BYTE *) srb_gen, sizeof(SRB_SET_PROD_INST_ID));
+
+ /*
+ * Place SRB type into header - this is a Fastmac Plus specific one, so
+ * we have to set a subcode value too.
+ */
+
+ srb_gen->set_prod_inst_id.header.function = FMPLUS_SPECIFIC_SRB;
+ srb_gen->set_prod_inst_id.subcode = SET_PROD_INST_ID_SUBCODE;
+
+ /*
+ * Copy in the product instance id.
+ */
+
+ util_mem_copy(
+ srb_gen->set_prod_inst_id.product_id,
+ product_id,
+ SIZEOF_PRODUCT_ID
+ );
+
+ /*
+ * Byte swap the product instance id.
+ */
+
+ util_byte_swap_structure(
+ (BYTE *) srb_gen->set_prod_inst_id.product_id,
+ SIZEOF_PRODUCT_ID
+ );
+
+ /*
+ * Record size of SRB that is being issued.
+ */
+
+ adapter->size_of_srb = sizeof(SRB_SET_PROD_INST_ID);
+
+ /*
+ * Call routine to issue SRB.
+ */
+
+ driver_issue_srb(adapter);
+
+ /*
+ * SRB issued successfully.
+ */
+
+ return TRUE;
+}
+
+/****************************************************************************
+*
+* driver_issue_srb
+* ================
+*
+* The driver_issue_srb routine issues an SRB. It does this by copying it
+* into DIO space and issuing an SRB command interrupt to Fastmac via the
+* SIFINT register.
+*
+* Note there is no need to worry about an interrupt occuring, (between the
+* setting of the EAGLE SIFADR register and the reading/writing of the
+* required DIO space data), that would alter the contents of the EAGLE
+* SIFADR register (and hence the SIFDAT and SIFDAT_INC registers too).
+* This is because the receive frame interrupt handler exits leaving the
+* contents of SIFADR as on entry.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(driver_issue_srb)
+#endif
+
+local void
+driver_issue_srb(
+ ADAPTER * adapter
+ )
+{
+ ADAPTER_HANDLE hnd = adapter->adapter_handle;
+ SRB_GENERAL * srb_gen = &adapter->srb_general;
+
+ /*
+ * Before downloading need to byte swap the SRB header.
+ */
+
+ util_byte_swap_structure(
+ (BYTE *) &srb_gen->header,
+ sizeof(SRB_HEADER)
+ );
+
+ /*
+ * Inform the system about the IO ports we are going to access.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io( adapter);
+#endif
+
+ sys_sync_with_interrupt(hnd, issue_srb, adapter);
+
+ /*
+ * Let the system know we have finished accessing the IO ports.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io( adapter);
+#endif
+}
+
+/****************************************************************************
+*
+* driver_completing_srb
+* =====================
+*
+* PARAMETERS (passed by driver_interrupt_entry) :
+* ===============================================
+*
+* ADAPTER_HANDLE adapter_handle
+*
+* The adapter handle for the adapter so it can be passed to the user
+* supplied user_completed_srb routine.
+*
+* ADAPTER * adapter
+*
+* The details of the adapter that the SRB has completed on.
+*
+* BODY :
+* ======
+*
+* The driver_completing_srb routine is called by driver_interrupt_entry.
+* It is called when Fastmac has generated an interrupt to say that the
+* SRB, associated with a particular adapter, has completed and further
+* SRBs can be issued.
+*
+* The routine reads the SRB out of DIO space into the SRB structure
+* maintained for the correct adapter. It then checks the SRB return code
+* to see if the SRB completed successfully and records the fact that the
+* SRB is now free. Then, it informs the user as to the success of the
+* completed SRB by calling user_completed_srb.
+*
+* The user_completed_srb routine should do a minimum amount of processing
+* because it is being called out of interrupts. Sensibly, it should just
+* set a flag, to say that the SRB has completed, that can be checked for
+* at strategy time when a further driver routine involving the use of the
+* SRB is called.
+*
+* Note that only those fields that are needed in the completed SRB that
+* need to be byte swapped back to Intel format are byte swapped. Hence,
+* if any adjustments are made to the code it may be necessary to make sure
+* that any newly used fields are correctly byte swapped back.
+*
+* RETURNS :
+* =========
+*
+* The routine always succeeds and returns control to the driver routine
+* driver_interrupt_entry.
+*
+****************************************************************************/
+
+#ifdef FTK_IRQ_FUNCTION
+#pragma FTK_IRQ_FUNCTION(driver_completing_srb)
+#endif
+
+export void
+driver_completing_srb(
+ ADAPTER_HANDLE adapter_handle,
+ ADAPTER * adapter
+ )
+{
+ SRB_GENERAL * srb_gen = &adapter->srb_general;
+ WORD saved_sifadr_value;
+ WBOOLEAN user_success_code;
+
+ /*
+ * Before accessing SIFADR, save current value for restoring on exit.
+ * Do this so interrupt not effect SIFADR value.
+ */
+
+ saved_sifadr_value = sys_insw(adapter_handle, adapter->sif_adr);
+
+ /*
+ * Copy SRB out of DIO space into adapter's SRB structure.
+ */
+
+ sys_outsw(
+ adapter_handle,
+ adapter->sif_adr,
+ (WORD) (card_t) adapter->srb_dio_addr
+ );
+
+ sys_rep_insw(
+ adapter_handle,
+ adapter->sif_datinc,
+ (BYTE *) srb_gen,
+ (WORD) (adapter->size_of_srb / 2)
+ );
+
+ if (adapter->size_of_srb & 1)
+ {
+ *(((BYTE * ) srb_gen) + adapter->size_of_srb - 1) =
+ sys_insb(adapter_handle, adapter->sif_datinc);
+ }
+
+ /*
+ * Once read from DIO space, byte swap SRB header back to Intel format.
+ */
+
+ util_byte_swap_structure((BYTE *) &srb_gen->header, sizeof(SRB_HEADER));
+
+ /*
+ * Check if SRB has completed successfully.
+ */
+
+ if (srb_gen->header.return_code == SRB_E_00_SUCCESS)
+ {
+ /*
+ * SRB completed successfully so record this to inform user.
+ */
+
+ user_success_code = TRUE;
+
+ /*
+ * If read error log SRB completed successfully
+ * then copy error log information into user's structure.
+ * Need to byte swap error log structure to Intel format first.
+ */
+
+ if (srb_gen->header.function == READ_ERROR_LOG_SRB)
+ {
+ util_byte_swap_structure(
+ (BYTE *) &srb_gen->err_log.error_log,
+ sizeof(ERROR_LOG)
+ );
+
+ adapter->status_info->error_log = srb_gen->err_log.error_log;
+ }
+ }
+ else
+ {
+ /*
+ * SRB not completed successfully so record this to inform user
+ * and fill in error record.
+ */
+
+ user_success_code = FALSE;
+ adapter->error_record.type = ERROR_TYPE_SRB;
+ adapter->error_record.value = srb_gen->header.return_code;
+ }
+
+ /*
+ * If issued an open adapter SRB and error is E_07_CMD_CANCELLED_FAIL
+ * then actually have an open error so change adapter error record.
+ */
+
+ if ((srb_gen->header.function == OPEN_ADAPTER_SRB) &&
+ (srb_gen->header.return_code == SRB_E_07_CMD_CANCELLED_FAIL))
+ {
+ /*
+ * Fill in error record with open error (not SRB error).
+ */
+
+ adapter->error_record.type = ERROR_TYPE_OPEN;
+ adapter->error_record.value = OPEN_E_01_OPEN_ERROR;
+ }
+
+ /*
+ * Set adapter SRB status to show that SRB is now free.
+ */
+
+ adapter->srb_status = SRB_FREE;
+
+ /*
+ * Inform user as to success of completed SRB.
+ * Disable and re-enable accessing IO locations around user call.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io( adapter);
+#endif
+
+ user_completed_srb(adapter_handle, user_success_code);
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io( adapter);
+#endif
+
+ /*
+ * Before finishing, restore saved value of EAGLE SIFADR register.
+ * Do this so interrupt does not effect SIFADR value.
+ */
+
+ sys_outsw(adapter_handle, adapter->sif_adr, saved_sifadr_value);
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - get_open_and_ring_status
+|
+| Paramters - ptr -> Pointer to our ADAPTER structure.
+|
+| Purpose - Reads status information from DIO space. This
+| function is called via NdisSynchronizeWithInterrupt when
+| in PIO mode so that we don't get SIF register contention
+| on a multiprocessor.
+|
+| Returns - Nothing.
+|
+|--------------------------------------------------------------------------*/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(get_open_and_ring_status)
+#endif
+
+local WBOOLEAN
+get_open_and_ring_status(
+ void * ptr
+ )
+{
+ ADAPTER * adapter = (ADAPTER *) ptr;
+ ADAPTER_HANDLE adapter_handle = adapter->adapter_handle;
+ WORD saved_sifadr;
+
+ /*
+ * Get adapter open status from the STB in DIO space.
+ */
+
+ saved_sifadr = sys_insw(adapter_handle, adapter->sif_adr);
+
+ sys_outsw(
+ adapter_handle,
+ adapter->sif_adr,
+ (WORD) (card_t) &adapter->stb_dio_addr->adapter_open
+ );
+
+ adapter->status_info->adapter_open =
+ sys_insw(adapter_handle, adapter->sif_dat);
+
+ /*
+ * Get ring status from the STB in DIO space.
+ */
+
+ sys_outsw(
+ adapter_handle,
+ adapter->sif_adr,
+ (WORD) (card_t) &adapter->stb_dio_addr->ring_status
+ );
+
+ adapter->status_info->ring_status =
+ sys_insw(adapter_handle, adapter->sif_dat);
+
+ sys_outsw(
+ adapter_handle,
+ adapter->sif_adr, saved_sifadr
+ );
+
+ return FALSE;
+}
+
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - issue_srb
+|
+| Paramters - ptr -> Pointer to our ADAPTER structure.
+|
+| Purpose - Copy an SRB to the adapter. This
+| function is called via NdisSynchronizeWithInterrupt when
+| in PIO mode so that we don't get SIF register contention
+| on a multiprocessor.
+|
+| Returns - Nothing.
+|
+|--------------------------------------------------------------------------*/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(issue_srb)
+#endif
+
+local WBOOLEAN
+issue_srb(
+ void * ptr
+ )
+{
+ ADAPTER * adapter = (ADAPTER *) ptr;
+ ADAPTER_HANDLE hnd = adapter->adapter_handle;
+ SRB_GENERAL * srb_gen = &adapter->srb_general;
+ WORD sifint_value;
+
+ /*
+ * Copy the SRB into DIO space at Fastmac specified location.
+ * only copy the required amount for the specific type of SRB.
+ */
+
+ sys_outsw(
+ hnd,
+ adapter->sif_adr,
+ (WORD) (card_t) adapter->srb_dio_addr
+ );
+
+ sys_rep_outsw(
+ hnd,
+ adapter->sif_datinc,
+ (BYTE *) srb_gen,
+ (WORD) (adapter->size_of_srb / 2)
+ );
+
+ if (adapter->size_of_srb & 1)
+ {
+ sys_outsb(
+ hnd,
+ adapter->sif_datinc,
+ *(((BYTE * ) srb_gen) + adapter->size_of_srb - 1)
+ );
+ }
+
+ /*
+ * Set up SIFCMD value for SRB command interrupt.
+ */
+
+ sifint_value = DRIVER_SIFINT_SRB_COMMAND;
+
+ /*
+ * Set interrupt adapter bit in SIFCMD.
+ */
+
+ sifint_value = (sifint_value | DRIVER_SIFINT_IRQ_FASTMAC);
+
+ /*
+ * Mask SIFSTS so not clear interrupt if outstanding Fastmac interrupt.
+ */
+
+ sifint_value = (sifint_value | DRIVER_SIFINT_FASTMAC_IRQ_MASK);
+
+ /*
+ * Interrupt Fastmac.
+ */
+
+ sys_outsw(hnd, adapter->sif_int, sifint_value);
+
+ return FALSE;
+}
+
+/**** End of DRV_SRB.C file ************************************************/
diff --git a/private/ntos/ndis/madge/driver/ftk.upd b/private/ntos/ndis/madge/driver/ftk.upd
new file mode 100644
index 000000000..a1dc10fa1
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/ftk.upd
@@ -0,0 +1,279 @@
+/****************************************************************************
+*
+* FTK.UPD
+*
+* FastMAC and FastMAC Plus Toolkit
+*
+* Copyright (c) Madge Networks Ltd 1991-1994
+*
+* COMPANY CONFIDENTIAL
+*
+****************************************************************************/
+
+/*---------------------------------------------------------------------------
+
+ Update History
+
+-----------------------------------------------------------------------------
+
+2.21.12 PBA 17/07/1995
+
+ Fixed a bug in hwi_pci.c. We were doing MMIO processing
+ if either the TX or RX bit in SIFINT was set without
+ requiring the host interrupt bit to also be set. This
+ meant that if we were on a shared interrupt we could
+ do an erroneous MMIO transfer because the RX or TX was
+ set but the adapter had not generated an interrupt.
+
+2.21.11 PRR 11/07/1995
+
+ Added another PCI fix to all the PCI cards, when using PIO
+ we need to handshake the transfer because of some PCI/Eagle
+ problems.
+
+2.21.10 PRR 10/07/11995
+
+ Added the fix for the PCI-Ti ASIC for DMA, also found a bug in
+ the ISR which is worth noting. To check for Pseudo DMA we need
+ to check the SWHRQ and PSDMAEN bits we were just checking SWHRQ
+ (DMA in progress). This causes a few problems if we go into the
+ Pseudo DMA code whilst in DMA mode.
+
+2.21.09 PRR 05/07/1995
+
+ Added the new fix to DMA on the PCI-Ti card.
+
+2.21.08 PRR & PBA 28/06/1995
+
+ Added the WinBook PCMCIA fix. Define WIN_BOOK_FIX
+ to enable it.
+
+2.21.07 PBA 22/06/1995
+
+ Fixed a bug where hwi_gen.c was not setting the MAC
+ buffer size to 504 bytes for PCIx adapters.
+
+2.21.06 PRR (& PBA) 21/06/1995
+
+ Finished support for TI ASIC based PCI adapter.
+
+2.21.05 PBA 24/05/1995
+
+ Fixed a bug in hwi_eisa.c where interrupts were not
+ being regenerated properly. Only affected edge triggered
+ interrupts.
+
+2.21.04 PBA 24/05/1995
+
+ Added support for the mark 3 EISA adapter.
+
+2.21.03 PRR 02/05/1995
+
+ Support for PCI-Ti and PCI-BM cards added.
+ The Ti one is works with all 3 demo programs in Pseudo-DMA
+ mode, the ASIC does not work for DMA so I have not tested it.
+ The BM code is as yet untested because of Silicon features.
+
+2.21.02 PBA 12/05/1995
+
+ It appears that certain sorts of PCMCIA socket
+ controllers can generate stray interrupts as soon as
+ we touch the adapter. Re-ordered some of the interrupt
+ initialisation code so that we can cope with the stray
+ interrupt.
+
+2.21.01 PBA 07/04/1995
+
+ Changed hwi_pci.c so that is uses the extended
+ handshake on transmit MMIO.
+
+2.21 PD 03/04/1995
+
+ Second version of the combined FastMAC and FastMAC
+ Plus toolkit. Uses FastMAC v4.50 and FastMAC Plus v1.34.
+
+2.20.27 PD 09/02/1995
+
+ Added a pokeouts module to allow debug information to be
+ sent to the serial ports on an IBM or clone. See head_def\
+ ftk_poke.h for the macros to use.
+ Also altered hwi_pcmc.c with calls for point enabling a
+ PCMCIA adapter. They are protected by #ifdef PCMCIA_POINT_
+ ENABLE. The prototypes for the calls are in sys_pcmc.h, but
+ no example DOS sys_pcmc.c or sys_pcmc.asm file is included.
+ DOS programs should use MADGECS or similar to provide card
+ and socket services - in which case the point enabler code
+ is not required.
+
+2.20.26 PBA 23/01/1995
+
+ hwi_pcmc.c now sets the MC_AND_ISACP_USE_PIO flag in
+ the adapter->mc32_config byte to get the software
+ handshake to work properly.
+
+2.20.25 PBA 12/01/1995
+
+ Removed bug in driver_remove_adapter where the FastMAC
+ Plus dma test buffer was freed if the pointer was NULL
+ rather than not NULL!
+
+2.20.24 PBA 12/01/1995
+
+ Changed hwi_get_node_address_check so that it doesn't
+ check for a Madge node address so that the FTK will
+ work on none Madge adapters.
+
+ Also changed drv_init.c so that the Madgic bits are only
+ set if MADGIC_BIT is defined. This allows support for
+ Madgic bits to be removed with RIFFDEF for releases.
+
+2.20.23 PBA 03/01/1995
+
+ Changed sys_allocate_dma_phys_buffer and
+ sys_free_dma_phys_buffer so that they take a DWORD
+ for the memory block size.
+
+2.20.22 PBA 12/12/1994
+
+ Tidied up some differences between the PCMCIA FTK and
+ HWI to do with interrupt regeneration that was causing
+ Windows95 to hang occassionally.
+
+2.20.21 PBA 12/12/1994
+
+ There us a problem with pseduo DMA on PnP and Smart16.
+ We have to read SIFACL, set the SINTEN bit and write
+ it back to regenerate interrupts. However, sometimes
+ when we read SIFACL the SWHLDA bit has not been cleared
+ by the Eagle. If at the same time the SWHRQ bit has been
+ set by the Eagle to indicate another transfer is pending
+ we may accidentally start another transfer when we write
+ the value of SIFACL + SINTEN back. The solution is
+ to poll SIFACL until the SWHLDA bit is cleared. This
+ fix gets rid of the delay in 2.20.19.
+
+2.20.20 PBA 08/12/1994
+
+ Added 32 bit PCMCIA support.
+
+2.20.19 PBA 08/12/1994
+
+ Put the code back that was removed in 2.20.17. Under
+ NT/Win95 we seem to need a short delay at the pointer
+ where under DOS we would clear the interrupt controller.
+
+2.20.18 PBA 07/12/1994
+
+ Added code in hwi_pcmc.c to call user_adapter_removed
+ if the PCMCIA adapter goes away. Enabled by defining
+ FTK_ADAPTER_REMOVED_NOTIFY.
+
+2.20.17 PBA 06/12/1994
+
+ Removed some code in hwi_pnp.c and hwi_sm16.c that toggled
+ EAGLE_SIFACL_SINTEN. I don't know why this code was there
+ and it breaks the hwi.
+
+2.20.16 PBA 06/12/1994
+
+ Now sets the "Madgic" bits.
+
+2.20.15 PBA 06/12/1994
+
+ Added lots of casts to stop the NT compiler from generating
+ warnings.
+
+2.20.14 PBA 06/12/1994
+
+ Added compile directive FTK_NO_TX_COMPLETION_CALL that
+ stops drv_irq.c calling rxtx_irq_completion_check even
+ if we have asked for TX complete interrupts by defining
+ FTK_TX_WITH_COMPLETION.
+
+2.20.13 PBA 02/12/1994
+
+ Fixed a bug in hwi_sm16.c where the node address wasn't
+ read properly because of an unitialised variable.
+
+2.20.12 PBA 01/12/1994
+
+ Changed the minumum number of RX/TX slots to 2.
+
+2.20.11 PBA 01/12/1994
+
+ Removed the calls to driver_remove_adapter in
+ driver_prepare_adapter, otherwise there's
+ no way to return an error message.
+
+2.20.10 PBA 01/12/1994
+
+ Fixed some places where macro_enable_io calls where
+ not enclosed by an #ifndef FTK_NO_IO_EMABLE. Also
+ changed an errant sys_probe_insb to a sys_insb.
+
+2.20.09 PBA 01/12/1994
+
+ Changed sys_sync_with_interrupt so that it takes an
+ abapter_handle parameter and returns a WBOOLEAN. Also
+ moved the definition to sys_mem.h.
+
+2.20.08 PBA 01/12/1994
+
+ Added a tx_flags parameter to rxtx_transmit_frame.
+
+2.20.07 PBA 30/11/1994
+
+ Fixed driver_prepare_adapter so that it always
+ calls driver_remove_adapter if it fails to
+ free up any memory allocated.
+
+2.20.06 PBA 29/11/1994
+
+ Initialise time functions are now marked with
+ #pragma FTK_INIT_FUNCTION(...), interrupt time
+ functions with #pragma FTK_IRQ_FUNCTION(...)
+ and run time but not interrupt time functions with
+ #pragma FTK_RES_FUNCTION(...). The #pragma's are
+ prefixed by #ifdef FTK_xxx_FUNCTION. The
+ FTK_xxx_FUNCTION definitions should be in user.h.
+
+2.20.05 PBA 21/11/1994
+
+ Change get_bring_up_code to retry the bring-up up to
+ 10 times. There is a problem with ICL PCs/ATPs with
+ SMARTNT.SYS where the bring up occassionally fails.
+ Retrying is the way the HWI fixes it.
+
+2.20.04 PBA 18/11/1994
+
+ Changed driver_open_adapter so that it takes the product
+ instance id from the string ftk_product_inst_id. This
+ string is initialised to FASTMAC_PRODUCT_ID so if
+ the user doesn't do anything it behaves as before.
+ However the user can change the string before calling
+ driver_open_adapter.
+
+2.20.03 PBA 16/11/1994
+
+ Fixed HWI_PCMC.C which was not setting the RAM size in
+ the adapter structure.
+
+2.20.02 PRR 16/11/1994
+
+ Change the polling routing for PNP cards such that it only
+ looks for md not md01.
+
+2.20.01 PBA 16/11/1994
+
+ Fixed spelling mistake in user.h of header files.
+ FTK_NO_PROBING should have been FTK_NO_PROBE.
+
+2.20 PD & PBA 15/11/1994
+
+ First recorded version of the combined FastMAC and FastMAC
+ Plus toolkit. Heaviliy revised from v1.x and the 2.x
+ beta. Uses FastMAC v4.48 and FastMAC Plus v1.22.
+
+---------------------------------------------------------------------------*/
+
+ \ No newline at end of file
diff --git a/private/ntos/ndis/madge/driver/ftk_poke.c b/private/ntos/ndis/madge/driver/ftk_poke.c
new file mode 100644
index 000000000..a9074dd76
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/ftk_poke.c
@@ -0,0 +1,267 @@
+/****************************************************************************
+*
+* FTK_POKE.C
+*
+* Part of the FastMAC Toolkit.
+* Copyright (c) Madge Networks Ltd 1995
+*
+* This module provides some functions that will send tracing information
+* to either serial port (COM1 or COM2) on a standard IBM PC clone.
+*
+*****************************************************************************/
+
+#include "ftk_defs.h"
+#include "ftk_intr.h"
+#include "ftk_extr.h"
+
+#ifdef FTK_POKEOUTS
+
+/*---------------------------------------------------------------------------
+|
+| Private constants.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef USE_COM2
+#define COM_BASE 0x0200 /* Base address for COM2. */
+#else
+#define COM_BASE 0x0300 /* Base address for COM1. */
+#endif
+
+#define THR (COM_BASE + 0x0f8) /* Transmit holding register. */
+#define IER (COM_BASE + 0x0f9) /* IRQ enable register. */
+#define IDR (COM_BASE + 0x0fa) /* IRQ identification register. */
+#define LCR (COM_BASE + 0x0fb) /* Line control register. */
+#define MCR (COM_BASE + 0x0fc) /* Modem control register. */
+#define LSR (COM_BASE + 0x0fd) /* Line status register. */
+#define MSR (COM_BASE + 0x0fe) /* Modem status register. */
+
+#define TX_RDY 0x020 /* THR empty flag bit in LSR. */
+#define BAUD_MASK 0x080 /* Baud rate mask in LCR. */
+#define PARAMS_MASK 0x07f /* Parameter mask in LCR. */
+#define EOUT2 0x008 /* EOUT2 flag in MCR. */
+#define CMCR 0x0f0 /* Clear MCR command. */
+#define DTR 0x001 /* DTR flag in MCR. */
+
+#define PARITY_TYPE 0
+#define STOP_BITS 1
+#define DATA_BITS 8
+#define BAUD_RATE 9600
+
+
+/*----------------------------------------------------------------------------
+|
+| Private global variables.
+|
+----------------------------------------------------------------------------*/
+
+int ftk_poke_initialised = FALSE;
+char ftk_hex_chars[16] = "0123456789abcdef";
+
+
+/*----------------------------------------------------------------------------
+|
+| Function - ftk_poke_init
+|
+| Parameters - Node.
+|
+| Purpose - Initialise the serial port.
+|
+| Returns - Nothing.
+|
+----------------------------------------------------------------------------*/
+
+void
+ftk_poke_init(void)
+{
+ unsigned t;
+ unsigned v;
+
+ /*
+ * Data, stop and parity bits.
+ */
+
+ t = DATA_BITS - 5;
+ if (STOP_BITS == 2)
+ {
+ t |= 0x04;
+ }
+ if (PARITY_TYPE > 0)
+ {
+ t |= ((PARITY_TYPE << 1) - 1) << 3;
+ }
+
+ OUTB(LCR, (BYTE) (INB(LCR) & PARAMS_MASK));
+ OUTB(LCR, (BYTE) t);
+
+ /*
+ * Set up the baud rate.
+ */
+
+ t = 115200L / BAUD_RATE;
+ v = INB(LCR) | BAUD_MASK;
+ OUTB(LCR, (BYTE) v);
+ OUTB(THR, (BYTE) (t & 0xff));
+ OUTB(IER, (BYTE) ((t >> 8) & 0xff));
+ OUTB(LCR, (BYTE) (v & PARAMS_MASK));
+
+ /*
+ * Empty the transmit buffer.
+ */
+
+ INB(THR);
+
+ /*
+ * Clear the modem control register and enable OUT2.
+ */
+
+ OUTB(MCR, (BYTE) ((INB(MCR) & CMCR) | EOUT2));
+
+ /*
+ * Turn DTR on.
+ */
+
+ OUTB(MCR, (BYTE) (INB(MCR) | DTR));
+}
+
+
+/*****************************************************************************
+*
+* Function - _ftk_poke_char
+*
+* Parameters - ch -> Character to poke out.
+*
+* Purpose - Poke a single character to the serial port.
+*
+* Returns - Nothing.
+*
+*****************************************************************************/
+
+void
+_ftk_poke_char(int ch)
+{
+ /*
+ * Initialise the serial port if this is the first access.
+ */
+
+ if (!ftk_poke_initialised)
+ {
+ ftk_poke_init();
+ ftk_poke_initialised = TRUE;
+ }
+
+ /*
+ * Wait until the transmit holding register is empty.
+ */
+
+ while ((INB(LSR) & TX_RDY) == 0);
+
+ /*
+ * And transmit the character.
+ */
+
+ OUTB(THR, (unsigned char) ch);
+}
+
+
+/*****************************************************************************
+*
+* Function - _ftk_poke_string
+*
+* Parameters - str -> String to poke out.
+*
+* Purpose - Poke a string to the serial port.
+*
+* Returns - Nothing.
+*
+*****************************************************************************/
+
+void
+_ftk_poke_string(char *str)
+{
+ while (*str != '\0')
+ {
+ if (*str == '\n')
+ {
+ _ftk_poke_char('\n');
+ _ftk_poke_char('\r');
+ }
+ else
+ {
+ _ftk_poke_char(*str);
+ }
+ str++;
+ }
+}
+
+
+/*****************************************************************************
+*
+* Function - _ftk_poke_byte
+*
+* Parameters - byte -> The byte to poke out.
+*
+* Purpose - Poke the hex string for a byte to the serial port.
+*
+* Returns - Nothing.
+*
+*****************************************************************************/
+
+void
+_ftk_poke_byte(int byte)
+{
+ _ftk_poke_char(ftk_hex_chars[(byte >> 4) & 0x000f]);
+ _ftk_poke_char(ftk_hex_chars[(byte ) & 0x000f]);
+}
+
+
+/*****************************************************************************
+*
+* Function - _ftk_poke_word
+*
+* Parameters - word -> The word to poke out.
+*
+* Purpose - Poke the hex string for a word to the serial port.
+*
+* Returns - Nothing.
+*
+*****************************************************************************/
+
+void
+_ftk_poke_word(int word)
+{
+ _ftk_poke_char(ftk_hex_chars[(word >> 12) & 0x000f]);
+ _ftk_poke_char(ftk_hex_chars[(word >> 8) & 0x000f]);
+ _ftk_poke_char(ftk_hex_chars[(word >> 4) & 0x000f]);
+ _ftk_poke_char(ftk_hex_chars[(word ) & 0x000f]);
+}
+
+
+/*****************************************************************************
+*
+* Function - _ftk_poke_dword
+*
+* Parameters - dword -> The dword to poke out.
+*
+* Purpose - Poke the hex string for a dword to the serial port.
+*
+* Returns - Nothing.
+*
+*****************************************************************************/
+
+void
+_ftk_poke_dword(long dword)
+{
+ _ftk_poke_char(ftk_hex_chars[(dword >> 28) & 0x000f]);
+ _ftk_poke_char(ftk_hex_chars[(dword >> 24) & 0x000f]);
+ _ftk_poke_char(ftk_hex_chars[(dword >> 20) & 0x000f]);
+ _ftk_poke_char(ftk_hex_chars[(dword >> 16) & 0x000f]);
+ _ftk_poke_char(ftk_hex_chars[(dword >> 12) & 0x000f]);
+ _ftk_poke_char(ftk_hex_chars[(dword >> 8) & 0x000f]);
+ _ftk_poke_char(ftk_hex_chars[(dword >> 4) & 0x000f]);
+ _ftk_poke_char(ftk_hex_chars[(dword ) & 0x000f]);
+}
+
+#endif
+
+
diff --git a/private/ntos/ndis/madge/driver/ftk_user.c b/private/ntos/ndis/madge/driver/ftk_user.c
new file mode 100644
index 000000000..5a58b90d4
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/ftk_user.c
@@ -0,0 +1,2187 @@
+/****************************************************************************
+*
+* FTK_USER.C
+*
+* FastMAC Plus based NDIS3 miniport driver FTK interface. This module
+* contains all of the routines required to interface with the FastMAC
+* Plus FTK. This is includes the routines traditionally found in transmit.c
+* and receive.c.
+*
+* Copyright (c) Madge Networks Ltd 1994
+*
+* COMPANY CONFIDENTIAL
+*
+* Created: PBA 21/06/1994
+*
+****************************************************************************/
+
+#include <ndis.h>
+
+#include "ftk_defs.h"
+#include "ftk_extr.h"
+#include "ftk_intr.h"
+
+#include "mdgmport.upd"
+#include "ndismod.h"
+
+
+/*---------------------------------------------------------------------------
+|
+| LOCAL VARIABLES
+|
+---------------------------------------------------------------------------*/
+
+//
+// To cut down on accesses to the slot structures on the card we keep
+// a host cache of various detaisl we need.
+//
+
+typedef struct
+{
+ DWORD PhysicalAddress;
+ PVOID VirtualAddress;
+}
+RX_SLOT_CACHE, *PRX_SLOT_CACHE;
+
+
+typedef struct
+{
+ ULONG BufferSize;
+ ULONG SharedMemoryAllocation;
+ PVOID SharedMemoryVirtAddr;
+ DWORD SharedMemoryPhysAddr;
+
+ RX_SLOT_CACHE rx_slot_cache[FMPLUS_MAX_RX_SLOTS];
+
+ UINT active_rx_slot; /* Used to count through the slot array */
+}
+RX_SLOT_MGMNT, *PRX_SLOT_MGMNT;
+
+
+typedef struct
+{
+ DWORD PhysicalAddress;
+ PVOID VirtualAddress;
+}
+TX_SLOT_CACHE, *PTX_SLOT_CACHE;
+
+
+typedef struct
+{
+ ULONG BufferSize;
+ ULONG SharedMemoryAllocation;
+ PVOID SharedMemoryVirtAddr;
+ DWORD SharedMemoryPhysAddr;
+
+ TX_SLOT_CACHE tx_slot_cache[FMPLUS_MAX_TX_SLOTS];
+
+ UINT active_tx_slot;
+ UINT first_tx_in_use;
+ UINT number_tx_in_use;
+}
+TX_SLOT_MGMNT, *PTX_SLOT_MGMNT;
+
+
+#define FRAME_TYPE_MASK ((BYTE) 0xC0) // What is ANDed with FC byte.
+#define FRAME_TYPE_MAC ((BYTE) 0x00) // What's left for a MAC frame.
+
+
+typedef struct
+{
+ ADAPTER_HANDLE adapter_handle;
+ ADAPTER * adapter;
+ TX_SLOT * tx_slot_ptr;
+ RX_SLOT * rx_slot_ptr;
+ UINT frame_length;
+ UINT result1;
+ UINT result2;
+}
+MPSAFE_INFO;
+
+
+#if 0
+
+typedef struct
+{
+ ADAPTER_HANDLE handle;
+ WORD location;
+ WORD result;
+}
+RDIO;
+
+WORD
+_madge_rdio(
+ void * ptr
+ )
+{
+ RDIO * rdio;
+
+ rdio = (RDIO *) ptr;
+
+ sys_outsw(
+ rdio->handle,
+ adapter_record[rdio->handle]->sif_adr,
+ rdio->location
+ );
+
+ rdio->result = sys_insw(
+ rdio->handle,
+ adapter_record[rdio->handle]->sif_dat
+ );
+
+ return 0;
+}
+
+
+WORD
+madge_rdio(
+ ADAPTER_HANDLE adapter_handle,
+ WORD dio_location
+ )
+{
+ RDIO rdio;
+
+ rdio.handle = adapter_handle;
+ rdio.location = dio_location;
+
+ sys_sync_with_interrupt(
+ adapter_handle,
+ _madge_rdio,
+ (void *) &rdio
+ );
+
+ return rdio.result;
+}
+
+
+void
+madge_dump_fmplus_info(
+ ADAPTER_HANDLE adapter_handle
+ )
+{
+ ADAPTER * adapter;
+ PRX_SLOT_MGMNT rx_slot_mgmnt;
+ PTX_SLOT_MGMNT tx_slot_mgmnt;
+ PMADGE_ADAPTER ndisAdap;
+ RX_SLOT * * rx_slot_array;
+ TX_SLOT * * tx_slot_array;
+ UINT active_rx_slot;
+ UINT active_tx_slot;
+ UINT first_tx_slot;
+ UINT rx_slots;
+ UINT tx_slots;
+ UINT i;
+
+ adapter = adapter_record[adapter_handle];
+
+ rx_slot_array = adapter->rx_slot_array;
+ rx_slot_mgmnt = (PRX_SLOT_MGMNT) adapter->rx_slot_mgmnt;
+ active_rx_slot = rx_slot_mgmnt->active_rx_slot;
+ rx_slots = adapter->init_block->fastmac_parms.rx_slots;
+
+ tx_slot_array = adapter->tx_slot_array;
+ tx_slot_mgmnt = (PTX_SLOT_MGMNT) adapter->tx_slot_mgmnt;
+ active_tx_slot = tx_slot_mgmnt->active_tx_slot;
+ first_tx_slot = tx_slot_mgmnt->first_tx_in_use;
+ tx_slots = adapter->init_block->fastmac_parms.tx_slots;
+
+ DbgPrint("----------------------------------------------------------\n");
+
+ DbgPrint(
+ "SIFADR high word = %04x\n\n",
+ sys_insw(adapter_handle, adapter->sif_adx)
+ );
+
+ DbgPrint("RX SLOTS:\n\n");
+ DbgPrint("Active slot = %d\n", active_rx_slot);
+
+ DbgPrint(" Len Res Buffer Stat Next\n");
+ DbgPrint(" ---- ---- --------- ---- ----\n");
+
+ for (i = 0; i < rx_slots; i++)
+ {
+ DbgPrint(
+ "%04x: %04x %04x %04x %04x %04x %04x\n",
+ (WORD) (card_t) rx_slot_array[i],
+ madge_rdio(adapter_handle, (WORD) (card_t) &rx_slot_array[i]->buffer_len),
+ madge_rdio(adapter_handle, (WORD) (card_t) &rx_slot_array[i]->reserved),
+ madge_rdio(adapter_handle, (WORD) (card_t) &rx_slot_array[i]->buffer_hiw),
+ madge_rdio(adapter_handle, (WORD) (card_t) &rx_slot_array[i]->buffer_low),
+ madge_rdio(adapter_handle, (WORD) (card_t) &rx_slot_array[i]->rx_status),
+ madge_rdio(adapter_handle, (WORD) (card_t) &rx_slot_array[i]->next_slot)
+ );
+ }
+
+ DbgPrint("\n");
+
+ DbgPrint("TX SLOTS:\n\n");
+ DbgPrint("Active slot = %d\n", active_tx_slot);
+ DbgPrint("First used slot = %d\n", first_tx_slot);
+
+ DbgPrint(" Stat SLen LLen Res1 Res2 Sbuffer Next LBuffer\n");
+ DbgPrint(" ---- ---- ---- ---- ---- --------- ---- ---------\n");
+
+ for (i = 0; i < tx_slots; i++)
+ {
+ DbgPrint(
+ "%04x: %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x\n",
+ (WORD) (card_t) tx_slot_array[i],
+ madge_rdio(adapter_handle, (WORD) (card_t) &tx_slot_array[i]->tx_status),
+ madge_rdio(adapter_handle, (WORD) (card_t) &tx_slot_array[i]->small_buffer_len),
+ madge_rdio(adapter_handle, (WORD) (card_t) &tx_slot_array[i]->large_buffer_len),
+ madge_rdio(adapter_handle, (WORD) (card_t) &tx_slot_array[i]->reserved[0]),
+ madge_rdio(adapter_handle, (WORD) (card_t) &tx_slot_array[i]->reserved[1]),
+ madge_rdio(adapter_handle, (WORD) (card_t) &tx_slot_array[i]->small_buffer_hiw),
+ madge_rdio(adapter_handle, (WORD) (card_t) &tx_slot_array[i]->small_buffer_low),
+ madge_rdio(adapter_handle, (WORD) (card_t) &tx_slot_array[i]->next_slot),
+ madge_rdio(adapter_handle, (WORD) (card_t) &tx_slot_array[i]->large_buffer_hiw),
+ madge_rdio(adapter_handle, (WORD) (card_t) &tx_slot_array[i]->large_buffer_low)
+ );
+ }
+
+ DbgPrint("\n");
+
+ DbgPrint("DIO LOCATION 0x0CE0\n\n");
+
+ for (i = 0; i < 32; i++)
+ {
+ DbgPrint(" %04x", madge_rdio(adapter_handle, (WORD) (0x0ce0 + i * 2)));
+ if (i == 15)
+ {
+ DbgPrint("\n");
+ }
+ }
+
+ DbgPrint("\n");
+}
+
+#endif
+
+/***************************************************************************
+*
+* Function - rxtx_allocate_rx_buffers
+*
+* Parameters - adapter -> Pointer to an FTK adapter structure.
+* max_frame_size -> Maximum frame size.
+* number_of_slots -> Number of receive slots.
+*
+* Purpose - Allocate buffer space for the receive slots.
+*
+* Returns - TRUE if it succeeds or FALSE otherwise.
+*
+****************************************************************************/
+
+WBOOLEAN
+rxtx_allocate_rx_buffers(
+ ADAPTER * adapter,
+ WORD max_frame_size,
+ WORD number_of_slots
+ );
+
+#pragma FTK_INIT_FUNCTION(rxtx_allocate_rx_buffers)
+
+WBOOLEAN
+rxtx_allocate_rx_buffers(
+ ADAPTER * adapter,
+ WORD max_frame_size,
+ WORD number_of_slots
+ )
+{
+ PRX_SLOT_MGMNT rx_slot_mgmnt;
+ NDIS_STATUS status;
+ ADAPTER_HANDLE adapter_handle;
+ PMADGE_ADAPTER ndisAdap;
+ DWORD SharedMemVirtAddr;
+ DWORD SharedMemPhysAddr;
+
+ //
+ // Pre-calculate some commonly used values.
+ //
+
+ rx_slot_mgmnt = (PRX_SLOT_MGMNT) adapter->rx_slot_mgmnt;
+
+ //
+ // Only want to allocate the receive buffers and slot management once
+ // per adapter.
+ //
+
+ if (rx_slot_mgmnt == NULL)
+ {
+ //
+ // Pre-calculate some commonly used values.
+ //
+
+ adapter_handle = adapter->adapter_handle;
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+
+ //
+ // Allocate the slot management structure.
+ //
+
+ MADGE_ALLOC_MEMORY(
+ &status,
+ &adapter->rx_slot_mgmnt,
+ sizeof(RX_SLOT_MGMNT)
+ );
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ return FALSE;
+ }
+
+ MADGE_ZERO_MEMORY(adapter->rx_slot_mgmnt, sizeof(RX_SLOT_MGMNT));
+
+ rx_slot_mgmnt = (PRX_SLOT_MGMNT) adapter->rx_slot_mgmnt;
+
+ //
+ // Work out how big the buffer should be. Remember to add
+ // four to the buffer allocation for the CRC. The addition
+ // of 32 provides a little space between receive buffers
+ // for those naughty transport protocols that read more
+ // then the indicated lookahead.
+ //
+
+ rx_slot_mgmnt->BufferSize = (max_frame_size + 4 + 32 + 3) & ~3;
+
+ rx_slot_mgmnt->SharedMemoryAllocation =
+ rx_slot_mgmnt->BufferSize * number_of_slots;
+
+ //
+ // Allocate the buffer.
+ //
+
+ if (!sys_alloc_dma_phys_buffer(
+ adapter_handle,
+ rx_slot_mgmnt->SharedMemoryAllocation,
+ &SharedMemPhysAddr,
+ &SharedMemVirtAddr
+ ))
+ {
+ return FALSE;
+ }
+
+ rx_slot_mgmnt->SharedMemoryVirtAddr = (VOID *) SharedMemVirtAddr;
+ rx_slot_mgmnt->SharedMemoryPhysAddr = SharedMemPhysAddr;
+ }
+
+ return TRUE;
+}
+
+
+/***************************************************************************
+*
+* Function - rxtx_setup_rx_buffers
+*
+* Parameters - adapter -> Pointer to an FTK adapter structure.
+* physical_addresses -> Use physical addresses?
+* number_of_slots -> Number of receive slots.
+*
+* Purpose - Set up the adapter receive slots.
+*
+* Returns - TRUE if it succeeds or FALSE otherwise.
+*
+****************************************************************************/
+
+void
+rxtx_setup_rx_buffers(
+ ADAPTER * adapter,
+ WBOOLEAN physical_addresses,
+ WORD number_of_slots
+ );
+
+#pragma FTK_INIT_FUNCTION(rxtx_setup_rx_buffers)
+
+void
+rxtx_setup_rx_buffers(
+ ADAPTER * adapter,
+ WBOOLEAN physical_addresses,
+ WORD number_of_slots
+ )
+{
+ PRX_SLOT_MGMNT rx_slot_mgmnt;
+ NDIS_STATUS status;
+ ADAPTER_HANDLE adapter_handle;
+ PMADGE_ADAPTER ndisAdap;
+ PVOID SharedMemVirtAddr;
+ DWORD SharedMemPhysAddr;
+ PRX_SLOT_CACHE rx_slot_cache;
+ RX_SLOT * * rx_slot_array;
+ DWORD phys_addr;
+ WORD slot_index;
+ WORD sifadr;
+ WORD sifdat;
+ WORD sifdatinc;
+ UINT buffer_size;
+
+ //
+ // Pre-calculate some commonly used values.
+ //
+
+ adapter_handle = adapter->adapter_handle;
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+
+ rx_slot_array = adapter->rx_slot_array;
+ rx_slot_mgmnt = (PRX_SLOT_MGMNT) adapter->rx_slot_mgmnt;
+ rx_slot_cache = rx_slot_mgmnt->rx_slot_cache;
+ SharedMemVirtAddr = rx_slot_mgmnt->SharedMemoryVirtAddr;
+ SharedMemPhysAddr = rx_slot_mgmnt->SharedMemoryPhysAddr;
+ buffer_size = rx_slot_mgmnt->BufferSize;
+
+ sifadr = adapter->sif_adr;
+ sifdat = adapter->sif_dat;
+ sifdatinc = adapter->sif_datinc;
+
+ MadgePrint2("rxtx_setup_rx_buffers number_of_slots = %d\n", number_of_slots);
+ MadgePrint2("rxtx_setup_rx_buffers buffer_size = %d\n", buffer_size);
+
+ //
+ // Work out the physical and virtual address of each buffer.
+ //
+
+ for (slot_index = 0; slot_index < number_of_slots; slot_index++)
+ {
+ rx_slot_cache[slot_index].VirtualAddress = SharedMemVirtAddr;
+ (PUCHAR) SharedMemVirtAddr += buffer_size;
+
+ rx_slot_cache[slot_index].PhysicalAddress = SharedMemPhysAddr;
+ SharedMemPhysAddr += buffer_size;
+
+ phys_addr = (physical_addresses)
+ ? (DWORD) rx_slot_cache[slot_index].PhysicalAddress
+ : (DWORD) rx_slot_cache[slot_index].VirtualAddress;
+
+ //
+ // Write the buffer locations into the slots.
+ //
+
+ sys_outsw(
+ adapter_handle,
+ sifadr,
+ (WORD) (card_t) &rx_slot_array[slot_index]->buffer_hiw
+ );
+
+ sys_outsw(
+ adapter_handle,
+ sifdatinc,
+ (WORD) (phys_addr >> 16)
+ );
+
+ sys_outsw(
+ adapter_handle,
+ sifdat,
+ (WORD) (phys_addr & 0x0FFFF)
+ );
+ }
+
+ ndisAdap->RxTxBufferState |= MADGE_RX_INITIALIZED;
+ rx_slot_mgmnt->active_rx_slot = 0;
+}
+
+
+/***************************************************************************
+*
+* Function - rxtx_free_rx_buffers
+*
+* Parameters - adapter -> Pointer to an FTK adapter structure.
+* max_frame_size -> Maximum frame size.
+* number_of_slots -> Number of receive slots.
+*
+* Purpose - Free the previously allocated receive buffers.
+*
+* Returns - Nothing.
+*
+****************************************************************************/
+
+void
+rxtx_free_rx_buffers(
+ ADAPTER * adapter,
+ WORD max_frame_size,
+ WORD number_of_slots
+ )
+{
+ ADAPTER_HANDLE adapter_handle;
+ PMADGE_ADAPTER ndisAdap;
+ PRX_SLOT_MGMNT rx_slot_mgmnt;
+
+ //
+ // Pre-calculate some commonly used values.
+ //
+
+ adapter_handle = adapter->adapter_handle;
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+ rx_slot_mgmnt = (PRX_SLOT_MGMNT) adapter->rx_slot_mgmnt;
+
+ //
+ // If the slot management structure exists them free it
+ // and the buffers.
+ //
+
+ if (rx_slot_mgmnt != NULL)
+ {
+ if (rx_slot_mgmnt->SharedMemoryVirtAddr != NULL)
+ {
+ sys_free_dma_phys_buffer(
+ adapter_handle,
+ rx_slot_mgmnt->SharedMemoryAllocation,
+ (DWORD) rx_slot_mgmnt->SharedMemoryPhysAddr,
+ (DWORD) rx_slot_mgmnt->SharedMemoryVirtAddr
+ );
+ }
+
+ MADGE_FREE_MEMORY(adapter->rx_slot_mgmnt, sizeof(RX_SLOT_MGMNT));
+
+ adapter->rx_slot_mgmnt = NULL;
+
+ ndisAdap->RxTxBufferState &= ~MADGE_RX_INITIALIZED;
+ }
+}
+
+
+/***************************************************************************
+*
+* Function - rxtx_allocate_tx_buffers
+*
+* Parameters - adapter -> Pointer to an FTK adapter structure.
+* max_frame_size -> Maximum frame size.
+* number_of_slots -> Number of transmit slots.
+*
+* Purpose - Allocate buffer space for the transmit slots.
+*
+* Returns - TRUE if it succeeds or FALSE otherwise.
+*
+****************************************************************************/
+
+WBOOLEAN
+rxtx_allocate_tx_buffers(
+ ADAPTER * adapter,
+ WORD max_frame_size,
+ WORD number_of_slots
+ );
+
+#pragma FTK_INIT_FUNCTION(rxtx_allocate_tx_buffers)
+
+WBOOLEAN
+rxtx_allocate_tx_buffers(
+ ADAPTER * adapter,
+ WORD max_frame_size,
+ WORD number_of_slots
+ )
+{
+ PTX_SLOT_MGMNT tx_slot_mgmnt;
+ NDIS_STATUS status;
+ ADAPTER_HANDLE adapter_handle;
+ PMADGE_ADAPTER ndisAdap;
+ DWORD SharedMemVirtAddr;
+ DWORD SharedMemPhysAddr;
+
+ //
+ // Pre-calculate some commonly used values.
+ //
+
+ tx_slot_mgmnt = (PTX_SLOT_MGMNT) adapter->tx_slot_mgmnt;
+
+ //
+ // Only want to allocate the receive buffers and slot management once
+ // per adapter.
+ //
+
+ if (tx_slot_mgmnt == NULL)
+ {
+ //
+ // Pre-calculate some commonly used values.
+ //
+
+ adapter_handle = adapter->adapter_handle;
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+
+ //
+ // Allocate the slot management structure.
+ //
+
+ MADGE_ALLOC_MEMORY(
+ &status,
+ &adapter->tx_slot_mgmnt,
+ sizeof(TX_SLOT_MGMNT)
+ );
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ return FALSE;
+ }
+
+ MADGE_ZERO_MEMORY(adapter->tx_slot_mgmnt, sizeof(TX_SLOT_MGMNT));
+
+ tx_slot_mgmnt = (PTX_SLOT_MGMNT) adapter->tx_slot_mgmnt;
+
+ //
+ // Work out how big the buffer should be.
+ //
+
+ tx_slot_mgmnt->BufferSize = (max_frame_size + 3) & ~3;
+
+ tx_slot_mgmnt->SharedMemoryAllocation =
+ tx_slot_mgmnt->BufferSize * number_of_slots;
+
+ //
+ // Allocate the buffer.
+ //
+
+ if (!sys_alloc_dma_phys_buffer(
+ adapter_handle,
+ tx_slot_mgmnt->SharedMemoryAllocation,
+ &SharedMemPhysAddr,
+ &SharedMemVirtAddr
+ ))
+ {
+ return FALSE;
+ }
+
+ tx_slot_mgmnt->SharedMemoryVirtAddr = (VOID *) SharedMemVirtAddr;
+ tx_slot_mgmnt->SharedMemoryPhysAddr = SharedMemPhysAddr;
+ }
+
+ return TRUE;
+}
+
+
+/***************************************************************************
+*
+* Function - rxtx_setup_tx_buffers
+*
+* Parameters - adapter -> Pointer to an FTK adapter structure.
+* physical_addresses -> Use physical addresses?
+* number_of_slots -> Number of transmit slots.
+*
+* Purpose - Set up the adapter transmit slots.
+*
+* Returns - TRUE if it succeeds or FALSE otherwise.
+*
+****************************************************************************/
+
+void
+rxtx_setup_tx_buffers(
+ ADAPTER * adapter,
+ WBOOLEAN physical_addresses,
+ WORD number_of_slots
+ );
+
+#pragma FTK_INIT_FUNCTION(rxtx_setup_tx_buffers)
+
+void
+rxtx_setup_tx_buffers(
+ ADAPTER * adapter,
+ WBOOLEAN physical_addresses,
+ WORD number_of_slots
+ )
+{
+ PTX_SLOT_MGMNT tx_slot_mgmnt;
+ NDIS_STATUS status;
+ ADAPTER_HANDLE adapter_handle;
+ PMADGE_ADAPTER ndisAdap;
+ PVOID SharedMemVirtAddr;
+ DWORD SharedMemPhysAddr;
+ PTX_SLOT_CACHE tx_slot_cache;
+ TX_SLOT * * tx_slot_array;
+ DWORD phys_addr;
+ WORD slot_index;
+ WORD sifadr;
+ WORD sifdat;
+ WORD sifdatinc;
+ UINT buffer_size;
+
+ //
+ // Pre-calculate some commonly used values.
+ //
+
+ adapter_handle = adapter->adapter_handle;
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+
+ tx_slot_array = adapter->tx_slot_array;
+ tx_slot_mgmnt = (PTX_SLOT_MGMNT) adapter->tx_slot_mgmnt;
+ tx_slot_cache = tx_slot_mgmnt->tx_slot_cache;
+ SharedMemVirtAddr = tx_slot_mgmnt->SharedMemoryVirtAddr;
+ SharedMemPhysAddr = tx_slot_mgmnt->SharedMemoryPhysAddr;
+ buffer_size = tx_slot_mgmnt->BufferSize;
+
+ sifadr = adapter->sif_adr;
+ sifdat = adapter->sif_dat;
+ sifdatinc = adapter->sif_datinc;
+
+ MadgePrint2("rxtx_setup_tx_buffers number_of_slots = %d\n", number_of_slots);
+ MadgePrint2("rxtx_setup_tx_buffers buffer_size = %d\n", buffer_size);
+
+ //
+ // Work out the physical and virtual address of each buffer.
+ //
+
+ for (slot_index = 0; slot_index < number_of_slots; slot_index++)
+ {
+ tx_slot_cache[slot_index].VirtualAddress = SharedMemVirtAddr;
+ (PUCHAR) SharedMemVirtAddr += buffer_size;
+
+ tx_slot_cache[slot_index].PhysicalAddress = SharedMemPhysAddr;
+ SharedMemPhysAddr += buffer_size;
+
+ phys_addr = (physical_addresses)
+ ? (DWORD) tx_slot_cache[slot_index].PhysicalAddress
+ : (DWORD) tx_slot_cache[slot_index].VirtualAddress;
+
+ //
+ // Write the buffer locations into the slots.
+ //
+
+ sys_outsw(
+ adapter_handle,
+ sifadr,
+ (WORD) (card_t) &tx_slot_array[slot_index]->large_buffer_hiw
+ );
+
+ sys_outsw(
+ adapter_handle,
+ sifdatinc,
+ (WORD) (phys_addr >> 16)
+ );
+
+ sys_outsw(
+ adapter_handle,
+ sifdat,
+ (WORD) (phys_addr & 0x0FFFF)
+ );
+ }
+
+ ndisAdap->RxTxBufferState |= MADGE_TX_INITIALIZED;
+ tx_slot_mgmnt->active_tx_slot = 0;
+ tx_slot_mgmnt->first_tx_in_use = 0;
+ tx_slot_mgmnt->number_tx_in_use = 0;
+}
+
+
+/***************************************************************************
+*
+* Function - rxtx_free_tx_buffers
+*
+* Parameters - adapter -> Pointer to an FTK adapter structure.
+* max_frame_size -> Maximum frame size.
+* number_of_slots -> Number of transmit slots.
+*
+* Purpose - Free the previously allocated transmit buffers.
+*
+* Returns - Nothing.
+*
+****************************************************************************/
+
+void
+rxtx_free_tx_buffers(
+ ADAPTER * adapter,
+ WORD max_frame_size,
+ WORD number_of_slots
+ )
+{
+ ADAPTER_HANDLE adapter_handle;
+ PMADGE_ADAPTER ndisAdap;
+ PTX_SLOT_MGMNT tx_slot_mgmnt;
+
+ //
+ // Pre-calculate some commonly used values.
+ //
+
+ adapter_handle = adapter->adapter_handle;
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+ tx_slot_mgmnt = (PTX_SLOT_MGMNT) adapter->tx_slot_mgmnt;
+
+ //
+ // If the slot management structure exists them free it
+ // and the buffers.
+ //
+
+ if (tx_slot_mgmnt != NULL)
+ {
+ if (tx_slot_mgmnt->SharedMemoryVirtAddr != NULL)
+ {
+ sys_free_dma_phys_buffer(
+ adapter_handle,
+ tx_slot_mgmnt->SharedMemoryAllocation,
+ (DWORD) tx_slot_mgmnt->SharedMemoryPhysAddr,
+ (DWORD) tx_slot_mgmnt->SharedMemoryVirtAddr
+ );
+ }
+
+ MADGE_FREE_MEMORY(adapter->tx_slot_mgmnt, sizeof(TX_SLOT_MGMNT));
+
+ adapter->tx_slot_mgmnt = NULL;
+
+ ndisAdap->RxTxBufferState &= ~MADGE_TX_INITIALIZED;
+ }
+}
+
+
+/*--------------------------------------------------------------------------
+|
+| Function - MPSafeReadTxStatus
+|
+| Paramters - ptr -> Pointer to an MPSAFE_INFO structure.
+|
+| Purpose - Reads the transmit status from the next slot to use. This
+| function is called via NdisSynchronizeWithInterrupt when
+| in PIO mode so that we don't get SIF register contention
+| on a multiprocessor.
+|
+| Returns - Nothing.
+|
+--------------------------------------------------------------------------*/
+
+STATIC BOOLEAN
+MPSafeReadTxStatus(PVOID ptr)
+{
+ MPSAFE_INFO * info = (MPSAFE_INFO *) ptr;
+
+ //
+ // Read the transmit status from the slot.
+ //
+
+ sys_outsw(
+ info->adapter_handle,
+ info->adapter->sif_adr,
+ (WORD) (card_t) &(info->tx_slot_ptr)->tx_status
+ );
+
+ info->result1 = sys_insw(
+ info->adapter_handle,
+ info->adapter->sif_dat
+ );
+
+ return FALSE;
+}
+
+
+/***************************************************************************
+*
+* Function - rxtx_irq_tx_completion_check
+*
+* Parameters - adapter_handle -> FTK adapter handle.
+* adapter -> Pointer to FTK adapter structure.
+*
+* Purpose - Complete any outstanding transmits.
+*
+* Returns - Nothing.
+*
+****************************************************************************/
+
+void
+rxtx_irq_tx_completion_check(
+ ADAPTER_HANDLE adapter_handle,
+ ADAPTER * adapter
+ )
+{
+ UINT tx_slots;
+ PTX_SLOT_MGMNT tx_slot_mgmnt;
+ PTX_SLOT_CACHE tx_slot_cache;
+ TX_SLOT * * tx_slot_array;
+ PMADGE_ADAPTER ndisAdap;
+ UINT tx_status;
+ MPSAFE_INFO info;
+ WORD sifadr;
+ WORD sifdat;
+
+ //
+ // Pre-calculate some commonly used values.
+ //
+
+ tx_slot_mgmnt = (PTX_SLOT_MGMNT) adapter->tx_slot_mgmnt;
+ tx_slot_cache = tx_slot_mgmnt->tx_slot_cache;
+ tx_slot_array = adapter->tx_slot_array;
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+ tx_slots = adapter->init_block->fastmac_parms.tx_slots;
+ sifadr = adapter->sif_adr;
+ sifdat = adapter->sif_dat;
+
+ //
+ // If we're doing multiprocessor safe PIO then we need to set up
+ // the info structure.
+ //
+
+ if (ndisAdap->UseMPSafePIO)
+ {
+ info.adapter_handle = adapter_handle;
+ info.adapter = adapter;
+ }
+
+ //
+ // Iterate around the transmit slots that are are marked as in use
+ // checking if they are now free. Note: we must work with the
+ // global coopies of the first_tx_in_use and number_tx_in_use
+ // in case rxtx_transmit_frame is called during our up-call
+ // to the wrapper.
+ //
+
+ while (tx_slot_mgmnt->number_tx_in_use > 0)
+ {
+ //
+ // Read the transmit status from the slot. If we're doing
+ // multiprocessor safe PIO we must do the DIO via an ISR
+ // synchronized function.
+ //
+
+ if (ndisAdap->UseMPSafePIO)
+ {
+ info.tx_slot_ptr = tx_slot_array[tx_slot_mgmnt->first_tx_in_use];
+
+ NdisMSynchronizeWithInterrupt(
+ &ndisAdap->Interrupt,
+ MPSafeReadTxStatus,
+ &info
+ );
+
+ tx_status = info.result1;
+ }
+ else
+ {
+ sys_outsw(
+ adapter_handle,
+ sifadr,
+ (WORD) (card_t) &tx_slot_array[
+ tx_slot_mgmnt->first_tx_in_use
+ ]->tx_status
+ );
+
+ tx_status = sys_insw(
+ adapter_handle,
+ sifdat
+ );
+ }
+
+ //
+ // If the slot is still in use then we must give up. This will
+ // also work if a PCMCIA adapter has been removed because
+ // tx_status will have been read as 0xffff.
+ //
+
+ if (tx_status >= 0x8000 || tx_status == 0)
+ {
+ break;
+ }
+
+ //
+ // Update the appropriate counters from the frame transmit
+ // status.
+ //
+
+ if ((tx_status & TX_RECEIVE_STATUS_MASK) == TX_RECEIVE_LOST_FRAME)
+ {
+ ndisAdap->LostFrames++;
+ }
+ else if ((tx_status & GOOD_TX_FRAME_MASK) != GOOD_TX_FRAME_VALUE)
+ {
+ ndisAdap->FrameTransmitErrors++;
+ }
+
+ //
+ // Update the slot usage.
+ //
+
+ tx_slot_mgmnt->number_tx_in_use--;
+
+ if (++tx_slot_mgmnt->first_tx_in_use == tx_slots)
+ {
+ tx_slot_mgmnt->first_tx_in_use = 0;
+ }
+
+ //
+ // Tell the wrapper that there is a free slot.
+ //
+
+ NdisMSendResourcesAvailable(ndisAdap->UsedInISR.MiniportHandle);
+ }
+
+ //
+ // If there are any frames we have queued for transmit that
+ // have not been completed then arm the timer so we are guaranteed
+ // to be called again. Under normal operation our DPR gets called
+ // often enough that this function is called frequently enough to
+ // complete all of the frames. However if we have an adapter in a
+ // fast bus (PCI/EISA) with a lot of RAM and we are not
+ // getting any recieve interrupts we can occasionally miss
+ // completing a frame. Hence the timer.
+ //
+
+ if (tx_slot_mgmnt->number_tx_in_use > 0)
+ {
+ NdisMSetTimer(&ndisAdap->CompletionTimer, 20);
+ }
+}
+
+
+/*--------------------------------------------------------------------------
+|
+| Function - MPSafeStartTx
+|
+| Paramters - ptr -> Pointer to an MPSAFE_INFO structure.
+|
+| Purpose - Set up a tx slot and start the transmit going. This
+| function is called via NdisSynchronizeWithInterrupt when
+| in PIO mode so that we don't get SIF register contention
+| on a multiprocessor.
+|
+| Returns - Nothing.
+|
+--------------------------------------------------------------------------*/
+
+STATIC BOOLEAN
+MPSafeStartTx(PVOID ptr)
+{
+ MPSAFE_INFO * info = (MPSAFE_INFO *) ptr;
+
+ //
+ // Reset the transmit status in the transmit slot.
+ //
+
+ sys_outsw(
+ info->adapter_handle,
+ info->adapter->sif_adr,
+ (WORD) (card_t) &(info->tx_slot_ptr)->tx_status
+ );
+
+ sys_outsw(
+ info->adapter_handle,
+ info->adapter->sif_dat,
+ 0x8000
+ );
+
+ //
+ // Write in the length of the buffer into the transmit slot
+ // (large buffer).
+ //
+
+ sys_outsw(
+ info->adapter_handle,
+ info->adapter->sif_adr,
+ (WORD) (card_t) &(info->tx_slot_ptr)->large_buffer_len
+ );
+
+ sys_outsw(
+ info->adapter_handle,
+ info->adapter->sif_dat,
+ (WORD) info->frame_length
+ );
+
+ //
+ // Write the length of the small buffer in the transmit slot to
+ // start the transmit going.
+ //
+
+ sys_outsw(
+ info->adapter_handle,
+ info->adapter->sif_adr,
+ (WORD) (card_t) &(info->tx_slot_ptr)->small_buffer_len
+ );
+
+ sys_outsw(
+ info->adapter_handle,
+ info->adapter->sif_dat,
+ FMPLUS_SBUFF_ZERO_LENGTH
+ );
+
+ return FALSE;
+}
+
+
+/***************************************************************************
+*
+* Function - rxtx_transmit_frame
+*
+* Parameters - adapter_handle -> FTK adapter handle.
+* tx_frame_identifier -> NDIS packet handle or a pointer
+* to some data to send.
+* tx_frame_length -> Length of the frame.
+* tx_is_packet -> TRUE if tx_frame_identifier is
+* an NDIS packet handle.
+*
+* Purpose - Attempts to transmit a frame by copying it into a transmit
+* buffer and activating a FastMAC Plus tx slot.
+*
+* Returns - DRIVER_TRANSMIT_SUCCESS if it succeeds or
+* DRIVER_TRANSMIT_FAILURE if it does not.
+*
+****************************************************************************/
+
+WORD
+rxtx_transmit_frame(
+ ADAPTER_HANDLE adapter_handle,
+ DWORD tx_frame_identifier,
+ WORD tx_frame_length,
+ WORD tx_is_packet
+ )
+{
+ ADAPTER * adapter;
+ PTX_SLOT_MGMNT tx_slot_mgmnt;
+ PTX_SLOT_CACHE tx_slot_cache;
+ TX_SLOT * tx_slot_ptr;
+ UINT active_tx_slot;
+ UINT tx_slots;
+ PMADGE_ADAPTER ndisAdap;
+ UINT bytes_copied;
+ UINT tx_status;
+ MPSAFE_INFO info;
+ WORD sifadr;
+ WORD sifdat;
+
+ //
+ // Pre-calculate some commonly used values.
+ //
+
+ adapter = adapter_record[adapter_handle];
+ tx_slot_mgmnt = (PTX_SLOT_MGMNT) adapter->tx_slot_mgmnt;
+ tx_slot_cache = tx_slot_mgmnt->tx_slot_cache;
+ active_tx_slot = tx_slot_mgmnt->active_tx_slot;
+ tx_slot_ptr = adapter->tx_slot_array[active_tx_slot];
+ tx_slots = adapter->init_block->fastmac_parms.tx_slots;
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+ sifadr = adapter->sif_adr;
+ sifdat = adapter->sif_dat;
+
+ //
+ // If we are a PCMCIA adapter it is possible that the adapter
+ // may have been removed. To detect this we check if SIFADR
+ // is 0xffff since this should not normally be true.
+ //
+
+ if (adapter->adapter_card_bus_type == ADAPTER_CARD_PCMCIA_BUS_TYPE)
+ {
+ if (sys_insw(adapter_handle, sifadr) == 0xffff)
+ {
+ rxtx_adapter_removed(adapter_handle);
+
+ return DRIVER_TRANSMIT_SUCCEED;
+ }
+ }
+
+ //
+ // If the next slot to be used is still in use then we must
+ // give up.
+ //
+
+ if (tx_slot_mgmnt->number_tx_in_use == tx_slots)
+ {
+
+#ifdef OID_MADGE_MONITOR
+ (ndisAdap->MonitorInfo).FailedToTransmit++;
+#endif
+
+ return DRIVER_TRANSMIT_FAIL;
+ }
+
+ //
+ // Copy the frame into the transmit buffer.
+ //
+
+ if (tx_is_packet)
+ {
+ MadgeCopyFromPacketToBuffer(
+ (PNDIS_PACKET) tx_frame_identifier,
+ 0,
+ tx_frame_length,
+ (PUCHAR) tx_slot_cache[active_tx_slot].VirtualAddress,
+ &bytes_copied
+ );
+ }
+ else
+ {
+ MADGE_MOVE_MEMORY(
+ tx_slot_cache[active_tx_slot].VirtualAddress,
+ (PUCHAR) tx_frame_identifier,
+ tx_frame_length
+ );
+ }
+
+ //
+ // Set up the tx slot and start the transmit. If we're using
+ // multiprocessor safe PIO then we must do the DIO via an ISR
+ // synchronised function.
+ //
+
+ if (ndisAdap->UseMPSafePIO)
+ {
+ info.adapter_handle = adapter_handle;
+ info.adapter = adapter;
+ info.tx_slot_ptr = tx_slot_ptr;
+ info.frame_length = tx_frame_length;
+
+ NdisMSynchronizeWithInterrupt(
+ &ndisAdap->Interrupt,
+ MPSafeStartTx,
+ &info
+ );
+ }
+ else
+ {
+ //
+ // Reset the transmit status in the transmit slot.
+ //
+
+ sys_outsw(
+ adapter_handle,
+ sifadr,
+ (WORD) (card_t) &tx_slot_ptr->tx_status
+ );
+
+ sys_outsw(
+ adapter_handle,
+ sifdat,
+ (WORD) 0x8000
+ );
+
+ //
+ // Write in the length of the buffer into the transmit slot
+ // (large buffer).
+ //
+
+ sys_outsw(
+ adapter_handle,
+ sifadr,
+ (WORD) (card_t) &tx_slot_ptr->large_buffer_len
+ );
+
+ sys_outsw(
+ adapter_handle,
+ sifdat,
+ (WORD) tx_frame_length
+ );
+
+ //
+ // Write the length of the small buffer in the transmit slot to
+ // start the transmit going.
+ //
+
+ sys_outsw(
+ adapter_handle,
+ sifadr,
+ (WORD) (card_t) &tx_slot_ptr->small_buffer_len
+ );
+
+ sys_outsw(
+ adapter_handle,
+ sifdat,
+ FMPLUS_SBUFF_ZERO_LENGTH
+ );
+ }
+
+ //
+ // Note that the slot is in use.
+ //
+
+ tx_slot_mgmnt->number_tx_in_use++;
+
+ //
+ // Update the slot counter ready for the next transmit.
+ //
+
+ if (++tx_slot_mgmnt->active_tx_slot == tx_slots)
+ {
+ tx_slot_mgmnt->active_tx_slot = 0;
+ }
+
+ return DRIVER_TRANSMIT_SUCCEED;
+}
+
+
+/*--------------------------------------------------------------------------
+|
+| Function - ProcessTestAndXIDFrames
+|
+| Paramters - adapHnd -> An FTK adapter handle.
+| framePtr -> Pointer to the start of the frame.
+| frameLen -> The length of the frame.
+| headerLen -> The length of the frame header.
+|
+| Purpose - Process LLC Test and XID frames in the same way as IBM
+| adapter hardware.
+|
+| Returns - TRUE if the frame was processed or FALSE if not.
+|
+|-------------------------------------------------------------------------*/
+
+STATIC BOOLEAN
+ProcessTestAndXIDFrames(
+ ADAPTER_HANDLE adapHnd,
+ UCHAR *framePtr,
+ UINT frameLen,
+ UINT headerLen
+ )
+{
+ UINT llcCmd;
+ UINT sSAP;
+ NODE_ADDRESS tempNodeAddr;
+ BOOLEAN doneFrame;
+
+ doneFrame = FALSE;
+
+ //
+ // We are only interested in frames that are LLC (i.e. frame
+ // control byte is 0x40), have a null destination SAP and are
+ // commands (i.e. 0x01 bit of the source SAP is clear).
+ //
+
+ sSAP = framePtr[headerLen + 1];
+
+ if (framePtr[1] == 0x40 &&
+ framePtr[headerLen] == 0x00 &&
+ (sSAP & 0x01) == 0x00)
+ {
+ llcCmd = framePtr[headerLen + 2] & 0xef;
+
+ //
+ // Test frames have an LLC command byte of 0b111x0011.
+ //
+
+ if (llcCmd == 0xe3)
+ {
+ MadgePrint1("Got TEST frame\n");
+
+ //
+ // We don't need to do anything to a test frame
+ // other than send it back.
+ //
+
+ doneFrame = TRUE;
+ }
+
+ //
+ // XID frames have an LLC command byte of 0b101x1111 and
+ // a standard IEEE defined XID frame will have 3 data
+ // bytes and its first data byte set to 0x81.
+ //
+
+ else if (llcCmd == 0xaf &&
+ frameLen == headerLen + 6 &&
+ framePtr[headerLen + 3] == 0x81)
+ {
+ MadgePrint1("Got XID frame\n");
+
+ //
+ // Fill in the XID frame data with 0x81 0x01 0x00
+ // (Standard XID frame, type 1 only and 0 sized
+ // receive window).
+ //
+
+ framePtr[headerLen + 4] = 0x01;
+ framePtr[headerLen + 5] = 0x00;
+
+ doneFrame = TRUE;
+ }
+
+ //
+ // If we've had a TEST or a XID frame then doneFrame will
+ // be TRUE and we should send a frame back.
+ //
+
+ if (doneFrame)
+ {
+ //
+ // Flip the direction bit in the source routing
+ // control word and switch the source routing flag
+ // from the source to destination address.
+ //
+
+ if ((framePtr[8] & 0x80) != 0)
+ {
+ framePtr[14] &= 0x1f; // Clear broadcast bits.
+ framePtr[15] ^= 0x80; // Flip direction bit.
+ framePtr[8] &= 0x7f; // Clear source routing bit.
+ framePtr[2] |= 0x80; // Set source routing bit.
+ }
+
+ //
+ // Swap the node addresses around.
+ //
+
+ tempNodeAddr = *((NODE_ADDRESS *) &framePtr[2]);
+ *((NODE_ADDRESS *) &framePtr[2]) = *((NODE_ADDRESS *) &framePtr[8]);
+ *((NODE_ADDRESS *) &framePtr[8]) = tempNodeAddr;
+
+ //
+ // Swap the SAPs around and set the response bit in the
+ // new source SAP.
+ //
+
+ framePtr[headerLen + 1] = 0x01;
+ framePtr[headerLen] = sSAP;
+ framePtr[0] = 0x10;
+
+ //
+ // And now send the frame.
+ //
+
+ rxtx_transmit_frame(
+ adapHnd,
+ (DWORD) framePtr,
+ (WORD) frameLen,
+ FALSE
+ );
+ }
+ }
+
+ return doneFrame;
+}
+
+
+/*--------------------------------------------------------------------------
+|
+| Function - MPSafeReadRxStatus
+|
+| Paramters - ptr -> Pointer to an MPSAFE_INFO structure.
+|
+| Purpose - Read the status and length of the current rx slot. This
+| function is called via NdisSynchronizeWithInterrupt when
+| in PIO mode so that we don't get SIF register contention
+| on a multiprocessor.
+|
+| Returns - Nothing.
+|
+--------------------------------------------------------------------------*/
+
+STATIC BOOLEAN
+MPSafeReadRxStatus(PVOID ptr)
+{
+ MPSAFE_INFO * info = (MPSAFE_INFO *) ptr;
+
+ sys_outsw(
+ info->adapter_handle,
+ info->adapter->sif_adr,
+ (WORD) (card_t) &(info->rx_slot_ptr)->buffer_len
+ );
+
+ info->result1 = sys_insw(
+ info->adapter_handle,
+ info->adapter->sif_dat
+ );
+
+ sys_outsw(
+ info->adapter_handle,
+ info->adapter->sif_adr,
+ (WORD) (card_t) &(info->rx_slot_ptr)->rx_status
+ );
+
+ info->result2 = sys_insw(
+ info->adapter_handle,
+ info->adapter->sif_dat
+ );
+
+ return FALSE;
+}
+
+/*--------------------------------------------------------------------------
+|
+| Function - MPSafeFreeRxSlot
+|
+| Paramters - ptr -> Pointer to an MPSAFE_INFO structure.
+|
+| Purpose - Free an rx slot. This
+| function is called via NdisSynchronizeWithInterrupt when
+| in PIO mode so that we don't get SIF register contention
+| on a multiprocessor.
+|
+| Returns - Nothing.
+|
+--------------------------------------------------------------------------*/
+
+STATIC BOOLEAN
+MPSafeFreeRxSlot(PVOID ptr)
+{
+ MPSAFE_INFO * info = (MPSAFE_INFO *) ptr;
+
+ sys_outsw(
+ info->adapter_handle,
+ info->adapter->sif_adr,
+ (WORD) (card_t) &(info->rx_slot_ptr)->buffer_len
+ );
+
+ sys_outsw(
+ info->adapter_handle,
+ info->adapter->sif_dat,
+ (WORD) 0x0000
+ );
+
+ return FALSE;
+}
+
+
+/***************************************************************************
+*
+* Function - rxtx_irq_rx_frame_handler
+*
+* Parameters - adapter_handle -> FTK adapter handle.
+* adapter -> Pointer to an FTK adapter structure.
+*
+* Purpose - Called out of the back or our DPR route via
+* driver_get_outstanding_receive() to process received
+* frames.
+*
+* Note we preserve the value of SIFADR so that the transmit
+* code does not have to worry about it changing under its
+* feet. No we don't because we are called out of a DPR
+* and the wrapper will have grabbed a spin lock so
+* we can't be executing at the same time as the transmit
+* code.
+*
+* Returns - Nothing.
+*
+****************************************************************************/
+
+#define PROM_OR_MAC \
+ (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_MAC_FRAME)
+
+void
+rxtx_irq_rx_frame_handler(
+ ADAPTER_HANDLE adapter_handle,
+ ADAPTER * adapter
+ )
+{
+ BYTE * rx_frame_addr;
+ UINT rx_frame_stat;
+ UINT rx_frame_length;
+ UINT slot_count;
+ UINT active_rx_slot;
+ PRX_SLOT_MGMNT rx_slot_mgmnt;
+ PRX_SLOT_CACHE rx_slot_cache;
+ RX_SLOT * * rx_slot_array;
+ RX_SLOT * rx_slot_ptr;
+ UINT rx_slots;
+ PMADGE_ADAPTER ndisAdap;
+ UINT packet_filter;
+ UINT header_len;
+ BOOLEAN done_frame;
+ BOOLEAN ignore_frame;
+ BOOLEAN test_and_xid;
+ MPSAFE_INFO info;
+ WORD sifadr;
+ WORD sifdat;
+
+ //
+ // Pre-calculate some commonly used values.
+ //
+
+ rx_slot_array = adapter->rx_slot_array;
+ rx_slot_mgmnt = (PRX_SLOT_MGMNT) adapter->rx_slot_mgmnt;
+ active_rx_slot = rx_slot_mgmnt->active_rx_slot;
+ rx_slot_cache = rx_slot_mgmnt->rx_slot_cache;
+ rx_slots = adapter->init_block->fastmac_parms.rx_slots;
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+ packet_filter = ndisAdap->CurrentPacketFilter;
+ test_and_xid = ndisAdap->TestAndXIDEnabled;
+ done_frame = FALSE;
+ sifadr = adapter->sif_adr;
+ sifdat = adapter->sif_dat;
+
+ //
+ // If we're doing multiprocessor safe PIO then we need to set up
+ // the info structure.
+ //
+
+ if (ndisAdap->UseMPSafePIO)
+ {
+ info.adapter_handle = adapter_handle;
+ info.adapter = adapter;
+ }
+
+ //
+ // Now read the length and status fields of the current receive slot.
+ // If we are doing multiprocessor safe PIO then we must do the DIO via
+ // an ISR synchronised function.
+ //
+
+ rx_slot_ptr = rx_slot_array[active_rx_slot];
+
+ if (ndisAdap->UseMPSafePIO)
+ {
+ info.rx_slot_ptr = rx_slot_ptr;
+
+ NdisMSynchronizeWithInterrupt(
+ &ndisAdap->Interrupt,
+ MPSafeReadRxStatus,
+ &info
+ );
+
+ rx_frame_length = info.result1;
+ rx_frame_stat = info.result2;
+ }
+ else
+ {
+ sys_outsw(
+ adapter_handle,
+ sifadr,
+ (WORD) (card_t) &rx_slot_ptr->buffer_len
+ );
+
+ rx_frame_length = sys_insw(
+ adapter_handle,
+ sifdat
+ );
+ sys_outsw(
+ adapter_handle,
+ sifadr,
+ (WORD) (card_t) &rx_slot_ptr->rx_status
+ );
+
+ rx_frame_stat = sys_insw(
+ adapter_handle,
+ sifdat
+ );
+
+ }
+
+ //
+ // Try to receive as many frames as possible, but only examine as many
+ // slots as we have, otherwise we might end up going round this loop
+ // forever! If we do stop and there is still a frame to be received, we
+ // will be re-interrupted anyway.
+ //
+
+ slot_count = 0;
+
+ while (rx_frame_length != 0 && slot_count++ < rx_slots)
+ {
+ //
+ // It is possible that a PCMCIA adapter may have been removed
+ // in which case we must not wait forever. If an adapter has
+ // been removed we would expect to read 0xffff from any IO
+ // location occupied by the adapter. 0xffff is not a valid
+ // value for an FMP RX status.
+ //
+
+ if (rx_frame_stat == 0xffff)
+ {
+ MadgePrint1("Rx frame: RX status == 0xffff\n");
+ ndisAdap->AdapterRemoved = TRUE;
+ return;
+ }
+
+ //
+ // FastMAC Plus includes the CRC in the frame length.
+ //
+
+ rx_frame_length -= 4;
+
+ if ((rx_frame_stat & GOOD_RX_FRAME_MASK) == 0)
+ {
+ //
+ // We have got a good frame here.
+ //
+
+ rx_frame_addr = rx_slot_cache[active_rx_slot].VirtualAddress;
+
+ header_len = (FRAME_IS_SOURCE_ROUTED(rx_frame_addr))
+ ? FRAME_HEADER_SIZE + FRAME_SOURCE_ROUTING_BYTES(rx_frame_addr)
+ : FRAME_HEADER_SIZE;
+
+ //
+ // Check for a frame copied error.
+ //
+
+ if ((rx_frame_addr[2] & 0x80) && (rx_frame_stat & 0x80))
+ {
+ ndisAdap->FrameCopiedErrors++;
+ }
+
+ //
+ // We may have to behave like the hardware of an IBM adapter
+ // and process LLC TEST and XID frames ourselves.
+ //
+
+ if (test_and_xid)
+ {
+ ignore_frame = ProcessTestAndXIDFrames(
+ adapter_handle,
+ rx_frame_addr,
+ rx_frame_length,
+ header_len
+ );
+ }
+ else
+ {
+ ignore_frame = FALSE;
+ }
+
+ //
+ // If we've got a valid frame then pass it up to the user.
+ //
+
+ if (!ignore_frame &&
+ ((rx_frame_addr[1] & FRAME_TYPE_MASK) != FRAME_TYPE_MAC ||
+ (packet_filter & PROM_OR_MAC) != 0))
+ {
+ //
+ // When indicating the frame, we can pass all of it
+ // as lookahead if we want, but we ought to take
+ // account of the current lookahead setting in case it
+ // is less than the frame size. This becomes important in
+ // WFWG, where it is unable to cope with large lookaheads. The
+ // lookahead length used to be :
+ // (UINT) rx_frame_length - header_len
+ //
+
+ NdisMTrIndicateReceive(
+ ndisAdap->UsedInISR.MiniportHandle,
+ (NDIS_HANDLE) (rx_frame_addr + header_len),
+ (PVOID) rx_frame_addr,
+ (UINT) header_len,
+ (PVOID) (rx_frame_addr + header_len),
+ (UINT) MIN(
+ ndisAdap->CurrentLookahead,
+ (rx_frame_length - header_len)
+ ),
+ (UINT) (rx_frame_length - header_len)
+ );
+
+ //
+ // Note that we've given the upper protocol at
+ // least one frame.
+ //
+
+ done_frame = TRUE;
+
+ ndisAdap->FramesReceived++;
+
+#ifdef OID_MADGE_MONITOR
+ //
+ // Update the appropriate parts of the monitor structure
+ //
+ (ndisAdap->MonitorInfo).ReceiveFrames++;
+ (ndisAdap->MonitorInfo).ReceiveFrameSize[rx_frame_length/128]++;
+ (ndisAdap->MonitorInfo).CurrentFrameSize = rx_frame_length;
+ (ndisAdap->MonitorInfo).ReceiveFlag = 1;
+#endif
+ }
+ }
+
+ //
+ // Otherwise we have some sort of receive error.
+ //
+
+ else
+ {
+ ndisAdap->FrameReceiveErrors++;
+ }
+
+ //
+ // Zero the frame length so that FastMAC Plus can reuse the buffer.
+ // If we're doing multiprocessor safe PIO then we must do the DIO
+ // via an ISR synchronised function.
+ //
+
+ if (ndisAdap->UseMPSafePIO)
+ {
+ info.rx_slot_ptr = rx_slot_ptr;
+
+ NdisMSynchronizeWithInterrupt(
+ &ndisAdap->Interrupt,
+ MPSafeFreeRxSlot,
+ &info
+ );
+ }
+ else
+ {
+ sys_outsw(
+ adapter_handle,
+ sifadr,
+ (WORD) (card_t) &rx_slot_ptr->buffer_len
+ );
+
+ sys_outsw(
+ adapter_handle,
+ sifdat,
+ 0x0000
+ );
+ }
+
+ //
+ // Update the active receive slot pointer.
+ //
+
+ if (++active_rx_slot == rx_slots)
+ {
+ active_rx_slot = 0;
+ }
+
+ rx_slot_mgmnt->active_rx_slot = active_rx_slot;
+
+ //
+ // Now we had better look at the next slot in case another frame
+ // has been received.
+ //
+
+ rx_slot_ptr = rx_slot_array[active_rx_slot];
+
+ if (ndisAdap->UseMPSafePIO)
+ {
+ info.rx_slot_ptr = rx_slot_ptr;
+
+ NdisMSynchronizeWithInterrupt(
+ &ndisAdap->Interrupt,
+ MPSafeReadRxStatus,
+ &info
+ );
+
+ rx_frame_length = info.result1;
+ rx_frame_stat = info.result2;
+ }
+ else
+ {
+ sys_outsw(
+ adapter_handle,
+ sifadr,
+ (WORD) (card_t) &rx_slot_ptr->buffer_len
+ );
+
+ rx_frame_length = sys_insw(
+ adapter_handle,
+ sifdat
+ );
+ sys_outsw(
+ adapter_handle,
+ sifadr,
+ (WORD) (card_t) &rx_slot_ptr->rx_status
+ );
+
+ rx_frame_stat = sys_insw(
+ adapter_handle,
+ sifdat
+ );
+
+ }
+ }
+
+ //
+ // If we've given the upper protocol a frame then call the
+ // receive completion routine.
+ //
+
+ if (done_frame)
+ {
+ NdisMTrIndicateReceiveComplete(ndisAdap->UsedInISR.MiniportHandle);
+ }
+}
+
+
+
+/***************************************************************************
+*
+* Function - rxtx_abort_txing_frames
+*
+* Parameters - adapter_handle -> FTK adapter handle.
+*
+* Purpose - Stop sending frames.
+*
+* Returns - Nothing.
+*
+****************************************************************************/
+
+void
+rxtx_abort_txing_frames(ADAPTER_HANDLE adapter_handle)
+{
+ //
+ // Nothing to do here.
+ //
+}
+
+
+/***************************************************************************
+*
+* Function - rxtx_await_empty_tx_slots
+*
+* Parameters - adapter_handle -> FTK adapter handle.
+*
+* Purpose - Wait until all of the tx slots are empty.
+*
+* Returns - Nothing.
+*
+****************************************************************************/
+
+void
+rxtx_await_empty_tx_slots(ADAPTER_HANDLE adapter_handle)
+{
+ ADAPTER * adapter;
+ FASTMAC_INIT_PARMS * fastmac_parms;
+ TX_SLOT * * tx_slot_array;
+ UINT i;
+ UINT status;
+ PMADGE_ADAPTER ndisAdap;
+ MPSAFE_INFO info;
+ WORD sifadr;
+ WORD sifdat;
+
+ if (!driver_check_adapter(adapter_handle, ADAPTER_RUNNING, SRB_ANY_STATE))
+ {
+ MadgePrint1("rxtx_await_empty_tx_slots: adapter not running\n");
+ return;
+ }
+
+ //
+ // Pre-calculate some commonly used values.
+ //
+
+ adapter = adapter_record[adapter_handle];
+ fastmac_parms = &adapter->init_block->fastmac_parms;
+ tx_slot_array = adapter->tx_slot_array;
+ info.adapter_handle = adapter_handle;
+ info.adapter = adapter;
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+ sifadr = adapter->sif_adr;
+ sifdat = adapter->sif_dat;
+
+ for (i = 0; i < fastmac_parms->tx_slots; i++)
+ {
+ do
+ {
+ //
+ // Get the slot status. If we are doing multiprocessor safe
+ // PIO then we must do this with an ISR synchronised function.
+ //
+
+ if (ndisAdap->UseMPSafePIO)
+ {
+ info.tx_slot_ptr = tx_slot_array[i];
+
+ NdisMSynchronizeWithInterrupt(
+ &ndisAdap->Interrupt,
+ MPSafeReadTxStatus,
+ &info
+ );
+
+ status = info.result1;
+ }
+ else
+ {
+ sys_outsw(
+ adapter_handle,
+ sifadr,
+ (WORD) (card_t) &tx_slot_array[i]->tx_status
+ );
+
+ status = sys_insw(adapter_handle, sifdat);
+ }
+
+ //
+ // It is possible that a PCMCIA adapter may have been removed
+ // in which case we must not wait forever. If an adapter has
+ // been removed we would expect to read 0xffff from any IO
+ // location occupied by the adapter. 0xffff is not a valid
+ // value for an FMP TX status.
+ //
+
+ if (status == 0xffff)
+ {
+ MadgePrint1("Await empty tx: TX status == 0xffff\n");
+ return;
+ }
+ }
+ while (status >= 0x8000 || status == 0);
+ }
+}
+
+
+/***************************************************************************
+*
+* Function - user_completed_srb
+*
+* Parameters - adapter_handle -> FTK adapter handle.
+* srb_completed_successfully -> SRB successful?
+*
+* Purpose - Record that an SRB has completed and arrange for our
+* DPR to be scheduled.
+*
+* Returns - Nothing.
+*
+****************************************************************************/
+
+void
+user_completed_srb(
+ ADAPTER_HANDLE adapter_handle,
+ WBOOLEAN srb_completed_successfully
+ )
+{
+ PMADGE_ADAPTER ndisAdap;
+
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+
+ //
+ // If we have issued a private SRB then we just clear the
+ // private SRB flag. Otherwise we need to arrange for our
+ // DPR to be told about the SRB.
+ //
+
+ if (ndisAdap->PrivateSrbInProgress)
+ {
+ ndisAdap->PrivateSrbInProgress = FALSE;
+ }
+ else
+ {
+ ndisAdap->UsedInISR.SrbRequestStatus = (BOOLEAN) srb_completed_successfully;
+ ndisAdap->UsedInISR.SrbRequestCompleted = TRUE;
+ ndisAdap->DprRequired = TRUE;
+ }
+}
+
+
+/***************************************************************************
+*
+* Function - user_shedule_receive_process
+*
+* Parameters - adapter_handle -> FTK adapter handle.
+*
+* Purpose - Arrange for our DPR to be scheduled so that we can deal
+* with received frames.
+*
+* Returns - Nothing.
+*
+****************************************************************************/
+
+
+void
+user_schedule_receive_process(ADAPTER_HANDLE adapter_handle)
+{
+ PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle)->DprRequired = TRUE;
+}
+
+
+/***************************************************************************
+*
+* Function - user_adapter_removed
+*
+* Parameters - adapter_handle -> FTK adapter handle.
+*
+* Purpose - Arrange for our DPR to be scheduled so that we can deal
+* with a removed adapter.
+*
+* Returns - Nothing.
+*
+****************************************************************************/
+
+
+void
+user_adapter_removed(ADAPTER_HANDLE adapter_handle)
+{
+ PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle)->DprRequired = TRUE;
+ PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle)->AdapterRemoved = TRUE;
+}
+
+
+/***************************************************************************
+*
+* Function - user_handle_adapter_check
+*
+* Parameters - adapter_handle -> FTK adapter handle.
+*
+* Purpose - Called on an adapter check. Not a lot we can do really!
+*
+* Returns - Nothing.
+*
+****************************************************************************/
+
+
+void
+user_handle_adapter_check(ADAPTER_HANDLE adapter_handle)
+{
+ MadgePrint1("Adapter Check!!!!\n");
+}
+
+
+//
+// Currently we are not supporting transmit modes that require
+// user completion routine.
+//
+
+#if 0
+
+/***************************************************************************
+*
+* Function - user_transmit_completion
+*
+* Parameters - adapter_handle -> FTK adapter handle.
+* identifier -> NDIS packet handle.
+*
+* Purpose - To notify an upper protocol that a transmit has completed.
+*
+* Returns - Nothing.
+*
+****************************************************************************/
+
+
+void
+user_transmit_completion(
+ ADAPTER_HANDLE adapter_handle,
+ DWORD identifier
+ )
+{
+}
+
+#endif
+
+
+/***************************************************************************
+*
+* Function - rxtx_adapter_removed
+*
+* Parameters - adapter_handle -> FTK adapter handle.
+*
+* Purpose - Called to tidy up when we find out that the adapter has
+* been removed. All we do is tell the wrapper that we
+* have finished any submitted transmits.
+*
+* Returns - Nothing.
+*
+****************************************************************************/
+
+void
+rxtx_adapter_removed(
+ ADAPTER_HANDLE adapter_handle
+ )
+{
+ ADAPTER * adapter;
+ PTX_SLOT_MGMNT tx_slot_mgmnt;
+ UINT tx_slots;
+ PMADGE_ADAPTER ndisAdap;
+
+ //
+ // Pre-calculate some commonly used values.
+ //
+
+ adapter = adapter_record[adapter_handle];
+ tx_slot_mgmnt = (PTX_SLOT_MGMNT) adapter->tx_slot_mgmnt;
+ tx_slots = adapter->init_block->fastmac_parms.tx_slots;
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+
+ //
+ // Note that the adapter has been removed.
+ //
+
+ ndisAdap->AdapterRemoved = TRUE;
+
+ //
+ // Iterate around the transmit slots that are in use and
+ // up call to indicate that the transmits are over.
+ //
+
+ while (tx_slot_mgmnt->number_tx_in_use > 0)
+ {
+ //
+ // Update the slot usage.
+ //
+
+ tx_slot_mgmnt->number_tx_in_use--;
+
+ if (++tx_slot_mgmnt->first_tx_in_use == tx_slots)
+ {
+ tx_slot_mgmnt->first_tx_in_use = 0;
+ }
+
+ //
+ // Tell the wrapper that there is a free slot.
+ //
+
+ NdisMSendResourcesAvailable(ndisAdap->UsedInISR.MiniportHandle);
+ }
+}
+
+
+/******** End of FTK_USER.C ***********************************************/
+
diff --git a/private/ntos/ndis/madge/driver/head_def/ftk_adap.h b/private/ntos/ndis/madge/driver/head_def/ftk_adap.h
new file mode 100644
index 000000000..b5f982bc7
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_def/ftk_adap.h
@@ -0,0 +1,280 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE ADAPTER DEFINITIONS */
+/* ======================= */
+/* */
+/* FTK_ADAP.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* Developed by MF */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* This header file contains the definitions for the structure which is */
+/* used to maintain information on an adapter that is being used by the */
+/* FTK. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this FTK_ADAP.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_FTK_ADAP_H 221
+
+
+/****************************************************************************/
+/* */
+/* TYPEDEFs for all structures defined within this header file : */
+/* */
+
+typedef struct STRUCT_ADAPTER ADAPTER;
+
+
+/****************************************************************************/
+/* */
+/* Structure type : ADAPTER */
+/* */
+/* The adapter structure is used to maintain all the information for a */
+/* single adapter. This includes information on the Fastmac for the */
+/* adapter. Most of the fields are filled in from the user supplied adapter */
+/* information to driver_prepare_adapter and driver_start_adapter. */
+/* */
+
+struct STRUCT_ADAPTER
+ {
+ void (*set_dio_address) (struct STRUCT_ADAPTER*, DWORD);
+ void (*interrupt_handler) (struct STRUCT_ADAPTER*);
+ void (*remove_card) (struct STRUCT_ADAPTER*);
+ UINT adapter_card_bus_type;
+ UINT adapter_card_type;
+ UINT adapter_card_revision;
+ UINT adapter_ram_size; /* Depends on card type. */
+#ifdef PCMCIA_POINT_ENABLE
+ UINT socket; /* Socket passed to point
+ enabler. */
+ BOOLEAN drop_int; /* Flag used to stop a
+ spurious interrupt being
+ claimed. */
+#endif
+ WORD io_location;
+ WORD io_range;
+ WORD interrupt_number; /* 0 == Polling mode */
+ WBOOLEAN edge_triggered_ints;
+ WORD nselout_bits; /* IRQ select on Smart16 */
+ WORD dma_channel;
+ UINT transfer_mode; /* DMA/MMIO/PIO */
+ WBOOLEAN EaglePsDMA;
+ WORD mc32_config; /* special config info */
+ NODE_ADDRESS permanent_address; /* BIA PROM node address */
+ UINT ring_speed;
+ WBOOLEAN speed_detect; /* Card is capable of detecting ring speed */
+ WORD max_frame_size; /* determined by ring speed */
+ UINT set_ring_speed; /* Force ring speed to this */
+ DWORD mmio_base_address; /* MMIO base address */
+ DWORD pci_handle; /* PCI slot handle. */
+ WBOOLEAN use_32bit_pio;
+ WORD sif_dat; /* SIF register IO locations*/
+ WORD sif_datinc;
+ WORD sif_adr;
+ WORD sif_int;
+ WORD sif_acl;
+ WORD sif_adr2;
+ WORD sif_adx;
+ WORD sif_dmalen;
+ WORD sif_sdmadat;
+ WORD sif_sdmaadr;
+ WORD sif_sdmaadx;
+ WORD c46_bits; /* Bits we must remember in */
+ /* the AT93C46 control reg. */
+
+
+ WBOOLEAN set_irq; /* set IRQ if possible */
+ WBOOLEAN set_dma; /* set DMA if possible */
+
+ SRB_GENERAL srb_general; /* SRB for this adapter */
+ WORD size_of_srb; /* size of current SRB */
+
+ DOWNLOAD_IMAGE * download_image; /* ptr Fastmac binary image */
+ INITIALIZATION_BLOCK * init_block; /* ptr Fastmac init block */
+ SRB_HEADER * srb_dio_addr; /* addr of SRB in DIO space */
+ FASTMAC_STATUS_BLOCK * stb_dio_addr; /* addr of STB in DIO space */
+
+ WBOOLEAN interrupts_on; /* for this adapter */
+ WBOOLEAN dma_on; /* for this adapter */
+
+ UINT adapter_status; /* prepared or running */
+ UINT srb_status; /* free or in use */
+ ERROR_RECORD error_record; /* error type and value */
+ ERROR_MESSAGE error_message; /* error message string */
+
+ STATUS_INFORMATION * status_info; /* ptr adapter status info */
+
+ void * user_information; /* User's private data. */
+
+ ADAPTER_HANDLE adapter_handle;
+
+#ifdef FMPLUS
+
+ DWORD dma_test_buf_phys;
+ DWORD dma_test_buf_virt;
+
+
+ RX_SLOT * rx_slot_array[FMPLUS_MAX_RX_SLOTS];
+ /* Rx slot DIO addresses */
+ TX_SLOT * tx_slot_array[FMPLUS_MAX_TX_SLOTS];
+ /* Tx slot DIO addresses */
+
+ void * rx_slot_mgmnt; /* pointer to user slot */
+ void * tx_slot_mgmnt; /* management structures. */
+
+#else
+
+ DWORD rx_buffer_phys; /* RX buffer physical address*/
+ DWORD rx_buffer_virt; /* RX buffer virtual address */
+ DWORD tx_buffer_phys; /* TX buffer physical address*/
+ DWORD tx_buffer_virt; /* TX buffer virtual address */
+
+#endif
+ };
+
+
+/****************************************************************************/
+/* */
+/* Values : ADAPTER - WORD adapter_card_type */
+/* */
+/* The following are the different types of adapter cards supported by the */
+/* FTK (and their subtypes). */
+/* */
+
+#define ADAPTER_CARD_TYPE_16_4_AT 2
+
+#define ADAPTER_CARD_16_4_PC 0
+#define ADAPTER_CARD_16_4_MAXY 1
+#define ADAPTER_CARD_16_4_AT 2
+#define ADAPTER_CARD_16_4_FIBRE 3
+#define ADAPTER_CARD_16_4_BRIDGE 4
+#define ADAPTER_CARD_16_4_ISA_C 5
+#define ADAPTER_CARD_16_4_AT_P_REV 6
+#define ADAPTER_CARD_16_4_FIBRE_P 7
+#define ADAPTER_CARD_16_4_ISA_C_P 8
+#define ADAPTER_CARD_16_4_AT_P 9
+
+#define ADAPTER_CARD_TYPE_16_4_MC 3
+
+#define ADAPTER_CARD_TYPE_16_4_MC_32 4
+
+#define ADAPTER_CARD_TYPE_16_4_EISA 5
+
+#define ADAPTER_CARD_16_4_EISA_MK1 1
+#define ADAPTER_CARD_16_4_EISA_MK2 2
+#define ADAPTER_CARD_16_4_EISA_BRIDGE 3
+#define ADAPTER_CARD_16_4_EISA_MK3 4
+
+#define ADAPTER_CARD_TYPE_SMART_16 6
+#define ADAPTER_CARD_SMART_16 1
+
+#define ADAPTER_CARD_TYPE_16_4_PCI 7
+#define ADAPTER_CARD_16_4_PCI 0
+
+#define ADAPTER_CARD_TYPE_16_4_PCMCIA 8
+#define ADAPTER_CARD_16_4_PCMCIA 1
+
+#define ADAPTER_CARD_TYPE_16_4_PNP 9
+#define ADAPTER_CARD_PNP 0
+
+#define ADAPTER_CARD_TYPE_16_4_PCIT 10
+#define ADAPTER_CARD_16_4_PCIT 0
+
+#define ADAPTER_CARD_TYPE_16_4_PCI2 11
+#define ADAPTER_CARD_16_4_PCI2 0
+
+#define ADAPTER_CARD_UNKNOWN 255
+
+/****************************************************************************/
+/* */
+/* Values : ADAPTER - WORD adapter_status */
+/* */
+/* These values are for the different required states of the adapter when */
+/* using the FTK. */
+/* */
+
+#define ADAPTER_PREPARED_FOR_START 0
+#define ADAPTER_RUNNING 1
+
+
+/****************************************************************************/
+/* */
+/* Values : ADAPTER - WORD srb_status */
+/* */
+/* These values are for the different required states of the SRB, */
+/* associated with an adapter, when using the FTK. */
+/* */
+
+#define SRB_ANY_STATE 0
+#define SRB_FREE 1
+#define SRB_NOT_FREE 2
+
+
+/****************************************************************************/
+/* */
+/* Value : Number of Adapters supported */
+/* */
+/* The FTK supports a specified maximum number of adapters. The smaller */
+/* this value is, the less memory that is used. This is especially true */
+/* when considering system specific parts such as the DOS example code */
+/* within this FTK. It uses the maximum number of adapters value for */
+/* determining the size of static arrays of adapter structures and */
+/* initialization blocks. It also uses it for determining the number of */
+/* interrupt stubs required given that : */
+/* */
+/* NOTE : If using the DOS example system specific code, then it must be */
+/* the case that MAX_NUMBER_OF_ADAPTERS defined here equals */
+/* MAX_NUMBER_OF_ADAPTERS as defined in SYS_IRQ.ASM. */
+/* */
+
+#define MAX_NUMBER_OF_ADAPTERS 8
+
+
+#define ISA_IO_LOCATIONS 4
+#define MAX_ISA_ADAPATERS ISA_IO_LOCATIONS
+
+#define MC_IO_LOCATIONS 8
+#define MAX_MC_ADAPATERS MC_IO_LOCATIONS
+
+#define MC32_IO_LOCATIONS 8
+#define MAX_MC32_ADAPATERS MC32_IO_LOCATIONS
+
+
+/****************************************************************************/
+/* */
+/* Varaibles : adapter_record array */
+/* */
+/* The FTK maintains an array of pointers to the adapter structures used to */
+/* maintain information on the different adapters being used. This array is */
+/* exported by DRV_INIT.C. */
+/* */
+
+extern ADAPTER * adapter_record[MAX_NUMBER_OF_ADAPTERS];
+
+/****************************************************************************/
+/* */
+/* Macro: FTK_ADAPTER_USER_INFORMATION */
+/* */
+/* A macro to let FTK users get at their private adapter information from */
+/* an adapter handle. */
+/* */
+
+#define FTK_ADAPTER_USER_INFORMATION(adapter_handle) \
+ (adapter_record[(adapter_handle)]->user_information)
+
+
+/* */
+/* */
+/************** End of FTK_ADAP.H file **************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_def/ftk_at.h b/private/ntos/ndis/madge/driver/head_def/ftk_at.h
new file mode 100644
index 000000000..45d6c4345
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_def/ftk_at.h
@@ -0,0 +1,234 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE MADGE ADAPTER CARD DEFINITIONS (ATULA CARDS) */
+/* ================================================ */
+/* */
+/* FTK_AT.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* Developed by MF */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* This header file contains the definitions for programming Madge ATULA */
+/* adapter cards. Each adapter card has a number of control and status */
+/* registers. ALL bits in ALL registers are defined by Madge Networks Ltd, */
+/* however only a restricted number are defined below as used within the */
+/* FTK. All other bits must NOT be changed and no support will be offered */
+/* for any application that does so or uses the defined bits in any way */
+/* different to the FTK. */
+/* */
+/* Note: The ATULA is Madge Network's name for the ASIC on its 16/4 AT and */
+/* 16/4 PC adapter cards. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this FTK_AT.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_FTK_AT_H 221
+
+
+/****************************************************************************/
+/* */
+/* Values : ATULA REGISTER MAP */
+/* */
+/* Madge 16/4 AT and 16/4 PC adapter cards both use the ATULA and hence */
+/* have the following register map. By setting certain bits in the control */
+/* registers it is possible to page in a) the status register or the PIO */
+/* address registers, b) the BIA PROM (page 0 or page 1) or the EAGLE SIF */
+/* registers (normal or extended). */
+/* */
+/* NB. There is a lot of similarity between the ATULA and MC register maps. */
+/* */
+
+#define ATULA_IO_RANGE 32
+
+#define ATULA_CONTROL_REGISTER_1 1
+#define ATULA_CONTROL_REGISTER_2 2
+#define ATULA_STATUS_REGISTER 3
+#define ATULA_CONTROL_REGISTER_6 6
+#define ATULA_CONTROL_REGISTER_7 7
+
+#define ATULA_FIRST_SIF_REGISTER 8
+
+#define ATULA_BIA_PROM 8
+
+#define ATULA_PIO_ADDRESS_LOW_REGISTER 3
+#define ATULA_PIO_ADDRESS_MID_REGISTER 4
+#define ATULA_PIO_ADDRESS_HIGH_REGISTER 5
+
+#define AT_P_EISA_REV2_CTRL_REG 21
+#define AT_P_SW_CONFIG_REG 22
+
+/****************************************************************************/
+/* */
+/* Values : ATULA CONTROL_REGISTER_1 */
+/* */
+/* These are the bit definitions for control register 1 on ATULA cards. */
+/* */
+/* NB. The bit definitions are mostly the same as MC CONTROL_REGISTER_1. */
+/* */
+
+#define ATULA_CTRL1_SINTREN ((BYTE) 0x01) /* SIF interrupt enable */
+#define ATULA_CTRL1_NSRESET ((BYTE) 0x04) /* active low SIF reset */
+#define ATULA_CTRL1_SRSX ((BYTE) 0x40) /* SIF extended register select */
+#define ATULA_CTRL1_4_16_SEL ((BYTE) 0x80) /* Select 4 or 16 Mb/s */
+
+
+/****************************************************************************/
+/* */
+/* Values : ATULA CONTROL_REGISTER_2 BITS */
+/* */
+/* These are the bit definitions for control register 2 on ATULA cards. */
+/* */
+
+#define ATULA_CTRL2_CS16DLY ((BYTE) 0x01) /* 1=REV3, 0=REV4 bus timings */
+#define ATULA_CTRL2_ADDSEL ((BYTE) 0x04) /* page in PIO addr regs (PIO) */
+#define ATULA_CTRL2_SHRQEN ((BYTE) 0x10) /* SHRQ enable (PIO) */
+#define ATULA_CTRL2_INTEN ((BYTE) 0x20) /* overall interrupt enable */
+#define ATULA_CTRL2_SHRQ ((BYTE) 0x40) /* SHRQ pin status (PIO) */
+#define ATULA_CTRL2_SHLDA ((BYTE) 0x80) /* SHLDA pin status (PIO) */
+
+
+/****************************************************************************/
+/* */
+/* Values : ATULA CONTROL_REGISTER_6 BITS */
+/* */
+/* These are the bit definitions for control register 6 on ATULA cards. */
+/* */
+
+#define ATULA_CTRL6_MODES ((BYTE) 0x03) /* transfer mode (2 bits) */
+#define ATULA_CTRL6_UDRQ ((BYTE) 0x04) /* user generate DMA request */
+#define ATULA_CTRL6_DMAEN ((BYTE) 0x08) /* enable DMA */
+#define ATULA_CTRL6_CLKSEL ((BYTE) 0xC0) /* clock speed select (2 bits) */
+
+
+/****************************************************************************/
+/* */
+/* Values : ATULA CONTROL_REGISTER_7 */
+/* */
+/* These are the bit definitions for control register 7 on ATULA cards. */
+/* */
+/* NB. The bit definitions are mostly the same as MC CONTROL_REGISTER_0. */
+/* */
+
+#define ATULA_CTRL7_SIFSEL ((BYTE) 0x04) /* page in BIA PROM or SIF regs */
+#define ATULA_CTRL7_PAGE ((BYTE) 0x08) /* pages BIA PROM or EEPROM */
+#define ATULA_CTRL7_UINT ((BYTE) 0x10) /* user generate interrupt */
+#define ATULA_CTRL7_SINTR ((BYTE) 0x40) /* SIF interrupt pending */
+#define ATULA_CTRL7_REV_4 ((BYTE) 0x80) /* 1=REV4, 0=REV3 mode */
+
+
+/****************************************************************************/
+/* */
+/* Values : ATULA STATUS_REGISTER BITS */
+/* */
+/* These are the bit definitions for the status register on ATULA cards. */
+/* */
+
+#define ATULA_STATUS_SDDIR ((BYTE) 0x10) /* data xfer direction (PIO) */
+#define ATULA_STATUS_ASYN_BUS ((BYTE) 0x20) /* asynchronous bus */
+#define ATULA_STATUS_BUS8 ((BYTE) 0x40) /* 8 bit slot */
+
+
+/****************************************************************************/
+/* */
+/* Values : MODE IN ATULA CONTROL_REGISTER_6 */
+/* */
+/* The two mode select bits in control register 6 (ATULA_CTRL6_MODES) are */
+/* configured for the data transfer mode being used. */
+/* */
+
+#define ATULA_CTRL6_MODE_BUS_MASTER ((BYTE) 0x03) /* bus master DMA mode */
+#define ATULA_CTRL6_MODE_PIO ((BYTE) 0x00) /* PIO mode */
+
+
+/****************************************************************************/
+/* */
+/* Values : CLOCK SPEED IN ATULA CONTROL_REGISTER_6 */
+/* */
+/* The two SIF clock speed select bits in control register 6 */
+/* (ATULA_CTRL6_CLKSEL) are configured for either on-board (8MHz) or host */
+/* oscillator frequency. */
+/* */
+
+#define ATULA_CTRL6_CLKSEL_HOST ((BYTE) 0xC0) /* host bus */
+#define ATULA_CTRL6_CLKSEL_ON_BOARD ((BYTE) 0x00) /* 8Mhz on board */
+
+
+/****************************************************************************/
+/* */
+/* Values : FIELDS IN THE AT_P_EISA_REV2_CTRL REGISTER */
+/* */
+/* These bit masks define bit fields within the AT/P control register. */
+/* */
+
+#define ATP_RSCTRL ((BYTE) 0x08)
+#define ATP_CLKDIV ((BYTE) 0x10)
+
+
+/****************************************************************************/
+/* */
+/* Values : FIELDS IN THE AT_P_SW_CONFIG REGISTER */
+/* */
+/* These bit masks define bit fields within the AT/P control register. */
+/* */
+
+#define ATP_INTSEL0 ((BYTE) 0x01)
+#define ATP_INTSEL1 ((BYTE) 0x02)
+#define ATP_INTSEL2 ((BYTE) 0x04)
+#define ATP_INTSEL ((BYTE) 0x07)
+
+#define ATP_DMA0 ((BYTE) 0x08)
+#define ATP_DMA1 ((BYTE) 0x10)
+#define ATP_DMA ((BYTE) 0x18)
+
+#define ATP_S4N16 ((BYTE) 0x40)
+
+/****************************************************************************/
+/* */
+/* Value : PIO IO LOCATION */
+/* */
+/* The IO location used during PIO for reading/writing data from/to the */
+/* adapter card is mapped on top of the EAGLE SIFDAT register in the ATULA */
+/* card register map. */
+/* */
+
+#define ATULA_PIO_IO_LOC 0
+
+
+/****************************************************************************/
+/* */
+/* Values : ATULA EXTENDED EAGLE SIF REGISTERS */
+/* */
+/* The EAGLE SIF registers are in two groups - the normal SIF registers */
+/* (those from the old TI chipset) and the extended SIF registers (those */
+/* particular to the EAGLE). For Madge ATULA adapter cards, with */
+/* CTRL7_SIFSEL = 1 and CTRL1_NRESET = 1, having CTRL1_SRSX = 0 selects the */
+/* normal SIF registers and having CTRL1_SRSX = 1 selects the extended SIF */
+/* registers. */
+/* */
+/* The definitions for the normal SIF registers are in FTK_CARD.H because */
+/* they appear in the same relative IO locations for all adapter cards. The */
+/* extended SIF registers are here because they appear at different */
+/* relative IO locations for different types of adapter cards. For ATULA */
+/* and MC cards they are in fact identical. */
+/* */
+
+#define ATULA_EAGLE_SIFACL 0 /* adapter control */
+#define ATULA_EAGLE_SIFADR_2 2 /* copy of SIFADR */
+#define ATULA_EAGLE_SIFADX 4 /* DIO address (high) */
+#define ATULA_EAGLE_DMALEN 6 /* DMA length */
+
+
+/* */
+/* */
+/************** End of FTK_AT.H file ****************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_def/ftk_card.h b/private/ntos/ndis/madge/driver/head_def/ftk_card.h
new file mode 100644
index 000000000..02c4e4ef0
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_def/ftk_card.h
@@ -0,0 +1,341 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE ADAPTER CARD DEFINITIONS : EAGLE (TMS 380 2nd GEN) */
+/* ====================================================== */
+/* */
+/* FTK_CARD.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* Developed by MF */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* This header file contains the definitions specific to the TI EAGLE (TMS */
+/* 380 2nd generation) chipset and the bring-up, initialization and opening */
+/* of the adapter. It also contains the details of the BIA PROM on ATULA */
+/* and MC cards. */
+/* */
+/* REFERENCE : The TMS 380 Second-Generation Token_Ring User's Guide */
+/* by Texas Instruments */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this FTK_CARD.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_FTK_CARD_H 221
+
+
+/****************************************************************************/
+/* */
+/* Values : EAGLE SIF REGISTERS */
+/* */
+/* The EAGLE SIF registers are in two groups - the normal SIF registers */
+/* (those from the old TI chipset) and the extended SIF registers (those */
+/* particular to the EAGLE). */
+/* */
+/* The definitions for the normal SIF registers are here because they */
+/* appear in the same relative IO locations for all adapter cards. The */
+/* definitions for the extended SIF registers are in the FTK_<card_type>.H */
+/* files. */
+/* */
+
+#define EAGLE_SIFDAT 0 /* DIO data */
+#define EAGLE_SIFDAT_INC 2 /* DIO data auto-increment */
+#define EAGLE_SIFADR 4 /* DIO address (low) */
+#define EAGLE_SIFINT 6 /* interrupt SIFCMD-SIFSTS */
+
+/* These definitions are for the case when the SIF registers are mapped */
+/* linearly. Otherwise, they will be at some extended location. */
+
+#define EAGLE_SIFACL 8
+#define EAGLE_SIFADX 12
+
+/* These definitions are for Eagle Pseudo DMA. Notice that they replace the */
+/* registers above - this is controlled by SIFACL. */
+
+#define EAGLE_SDMADAT 0
+#define EAGLE_DMALEN 2
+#define EAGLE_SDMAADR 4
+#define EAGLE_SDMAADX 6
+
+/****************************************************************************/
+/* */
+/* Value : Number of IO locations for SIF registers */
+/* */
+/* The number of SIF registers is only needed for enabling and disabling */
+/* ranges of IO ports. For the ATULA and MC cards the SIF registers are in */
+/* 2 pages only using 8 IO ports. However, for EISA cards, the SIF */
+/* registers are in a single page of 16 IO ports. Hence, 16 IO ports need */
+/* to be enabled whenever accessing SIF registers. */
+/* */
+
+#define SIF_IO_RANGE 16
+
+/****************************************************************************/
+/* */
+/* Value : Number of IO locations for adapter cards */
+/* */
+/* The maximum IO range required for the register map of any type of */
+/* adapter card is that used by the EISA card. The ATULA based cards have */
+/* the largest contiguous IO range, however. The EISA range is split into */
+/* two, the upper range only being used during installation. */
+/* */
+
+#define MAX_CARD_IO_RANGE ATULA_IO_RANGE
+
+
+/****************************************************************************/
+/* */
+/* Values : MAX FRAME SIZES SUPPORTED */
+/* */
+/* Depending on the ring speed (4 Mbit/s or 16 Mbit/s) different maximum */
+/* frame sizes are supported as defined in the ISO standards. The ISO */
+/* standards give the maximum size of the information field to which has to */
+/* added the MAC header, SR info fields etc. to give real maximum token */
+/* ring frame size. */
+/* */
+
+#define MAC_FRAME_SIZE 39
+
+#define MIN_FRAME_SIZE (256 + MAC_FRAME_SIZE)
+#define MAX_FRAME_SIZE_4_MBITS (4472 + MAC_FRAME_SIZE)
+#define MAX_FRAME_SIZE_16_MBITS (17800 + MAC_FRAME_SIZE)
+
+
+/****************************************************************************/
+/* */
+/* Values : EAGLE ADAPTER CONTROL (SIFACL) REGISTER BITS */
+/* */
+/* The bits in the EAGLE extended SIF register EAGLE_SIFACL can be used for */
+/* general controlling of the adapter card. */
+/* */
+/* REFERENCE : The TMS 380 Second-Generation Token_Ring User's Guide */
+/* by Texas Instruments */
+/* 4-18 4.3.1 SIFACL - SIF Adapter Control Register */
+/* */
+
+#define EAGLE_SIFACL_SWHLDA 0x0800 /* for EAGLE pseudo-DMA */
+#define EAGLE_SIFACL_SWDDIR 0x0400 /* data transfer direction */
+#define EAGLE_SIFACL_SWHRQ 0x0200 /* DMA pending */
+#define EAGLE_SIFACL_PSDMAEN 0x0100 /* for EAGLE pseudo-DMA */
+#define EAGLE_SIFACL_ARESET 0x0080 /* adapter reset */
+#define EAGLE_SIFACL_CPHALT 0x0040 /* halt EAGLE */
+#define EAGLE_SIFACL_BOOT 0x0020 /* bootstrap */
+#define EAGLE_SIFACL_RESERVED1 0x0010 /* reserved */
+#define EAGLE_SIFACL_SINTEN 0x0008 /* system interrupt enable */
+#define EAGLE_SIFACL_PARITY 0x0004 /* adapter parity enable */
+#define EAGLE_SIFACL_INPUT0 0x0002 /* reserved */
+#define EAGLE_SIFACL_RESERVED2 0x0001 /* reserved */
+
+
+/****************************************************************************/
+/* */
+/* Values : DIO LOCATIONS */
+/* */
+/* When initializing an adapter the initialization block must be downloaded */
+/* to location 0x00010A00L in DIO space. */
+/* */
+/* The ring speed, from which the maximum frame size is deduced, can be */
+/* determined by the value in the ring speed register at DIO address 0x0142 */
+/* in the EAGLE DATA page 0x00010000. */
+/* */
+
+#define DIO_LOCATION_INIT_BLOCK 0x00010A00L
+
+#define DIO_LOCATION_EAGLE_DATA_PAGE 0x00010000L
+#define DIO_LOCATION_RING_SPEED_REG 0x0142
+
+#define RING_SPEED_REG_4_MBITS_MASK 0x0400
+
+#define DIO_LOCATION_EXT_DMA_ADDR 0x010E
+#define DIO_LOCATION_DMA_ADDR 0x0110
+
+#define DIO_LOCATION_DMA_CONTROL 0x100A
+
+/****************************************************************************/
+/* */
+/* Values : EAGLE BRING UP INTERRUPT REGISTER VALUES */
+/* */
+/* The code produced at the SIFSTS part of the SIF interrupt register at */
+/* bring up time indicates the success or failure of the bring up. The */
+/* success or failure is determined by looking at the top nibble. On */
+/* success, the INITIALIZE bit is set. On failure, the TEST and ERROR bits */
+/* are set and the error code is in the bottom nibble. */
+/* */
+/* REFERENCE : The TMS 380 Second-Generation Token_Ring User's Guide */
+/* by Texas Instruments */
+/* 4-40 4.5 Bring-Up Diagnostics - BUD */
+/* */
+
+#define EAGLE_SIFINT_SYSTEM (UINT) 0x0080
+
+#define EAGLE_BRING_UP_TOP_NIBBLE (BYTE) 0xF0
+#define EAGLE_BRING_UP_BOTTOM_NIBBLE (BYTE) 0x0F
+
+#define EAGLE_BRING_UP_SUCCESS (BYTE) 0x40
+#define EAGLE_BRING_UP_FAILURE (BYTE) 0x30
+
+
+/****************************************************************************/
+/* */
+/* Values : EAGLE INITIALIZATION INTERRUPT REGISTER VALUES */
+/* */
+/* The code 0x9080 is output to the SIF interrupt register in order to */
+/* start the initialization process. The code produced at the SIFSTS part */
+/* of the SIF interrupt register at initialization time indicates the */
+/* success or failure of the initialization. On success, the INITIALIZE, */
+/* TEST and ERROR bits are all zero. On failure, the ERROR bit is set and */
+/* the error code is in the bottom nibble. */
+/* */
+/* REFERENCE : The TMS 380 Second-Generation Token_Ring User's Guide */
+/* by Texas Instruments */
+/* 4-46 4.6.2 Writing The Initialization Block */
+/* */
+
+#define EAGLE_INIT_START_CODE 0x9080
+
+#define EAGLE_INIT_TOP_NIBBLE (BYTE) 0xF0
+#define EAGLE_INIT_BOTTOM_NIBBLE (BYTE) 0x0F
+
+#define EAGLE_INIT_SUCCESS_MASK (BYTE) 0x70
+#define EAGLE_INIT_FAILURE_MASK (BYTE) 0x10
+
+
+/****************************************************************************/
+/* */
+/* Values : SCB and SSB test patterns */
+/* */
+/* As a result of initialization, certain test patterns should be left in */
+/* the SSB and SCB as pointed to by the TI initialization parameters. */
+/* */
+/* REFERENCE : The TMS 380 Second-Generation Token_Ring User's Guide */
+/* by Texas Instruments */
+/* 4-46 4.6.2 Writing The Initialization Block */
+/* */
+
+#define SSB_TEST_PATTERN_LENGTH 8
+#define SSB_TEST_PATTERN_DATA {0xFF,0xFF,0xD1,0xD7,0xC5,0xD9,0xC3,0xD4}
+
+#define SCB_TEST_PATTERN_LENGTH 6
+#define SCB_TEST_PATTERN_DATA {0x00,0x00,0xC1,0xE2,0xD4,0x8B}
+
+
+/****************************************************************************/
+/* */
+/* Value : EAGLE ARB FREE CODE - written to the EAGLE interrupt register to */
+/* indicate that the ARB is now free for use by the adapter. This */
+/* is of most use at start time when combined with the DELAY_RX */
+/* FEATURE FLAG. This code can be used to enable receives. */
+
+#define EAGLE_ARB_FREE_CODE 0x90FF
+
+
+/****************************************************************************/
+/* */
+/* Values : EAGLE OPENING ERRORS */
+/* */
+/* On opening the adapter, the success or failure is recorded in the */
+/* open_error field of the Fastmac status parameter block. The bottom byte */
+/* has the error value on failure. On success, the word is clear. The open */
+/* error is that which would be given by a MAC 0003 OPEN command. */
+/* */
+/* REFERENCE : The TMS 380 Second-Generation Token_Ring User's Guide */
+/* by Texas Instruments */
+/* 4-80 MAC 0003 OPEN command */
+/* */
+
+#define EAGLE_OPEN_ERROR_BOTTOM_BYTE 0x00FF
+
+#define EAGLE_OPEN_ERROR_SUCCESS 0x0000
+
+
+/****************************************************************************/
+/* */
+/* Values : BIA PROM FORMAT */
+/* */
+/* The BIA PROM is accessed in 2 pages. With CTRLn_SIFSEL = 0 (n=7 for */
+/* ATULA cards, n=0 for MC cards) or CTRL1_NRESET = 0, the bit CTRLn_PAGE */
+/* selects the different pages. With CTRLn_PAGE = 0, the id and board type */
+/* are available; with CTRLn_PAGE = 1, the node address is available. */
+/* */
+
+#define BIA_PROM_ID_BYTE 0
+#define BIA_PROM_ADAPTER_BYTE 1
+#define BIA_PROM_REVISION_BYTE 2
+#define BIA_PROM_FEATURES_BYTE 3
+#define BIA_PROM_HWF2 4
+#define BIA_PROM_HWF3 5
+
+#define BIA_PROM_NODE_ADDRESS 1
+
+/****************************************************************************/
+/* */
+/* Values : Bits defined in the HW flags */
+/* */
+/* HWF2 */
+#define C30 0x1
+
+/* HWF3 */
+#define RSPEED_DETECT 0x80
+
+
+/****************************************************************************/
+/* */
+/* Values : BIA PROM ADAPTER CARD TYPES */
+/* */
+/* The second byte in the first page of the BIA PROM contains an adapter */
+/* card type. */
+/* */
+
+#define BIA_PROM_TYPE_16_4_AT ((BYTE) 0x04)
+#define BIA_PROM_TYPE_16_4_MC ((BYTE) 0x08)
+#define BIA_PROM_TYPE_16_4_PC ((BYTE) 0x0B)
+#define BIA_PROM_TYPE_16_4_MAXY ((BYTE) 0x0C)
+#define BIA_PROM_TYPE_16_4_MC_32 ((BYTE) 0x0D)
+#define BIA_PROM_TYPE_16_4_AT_P ((BYTE) 0x0E)
+
+#define MAX_ADAPTER_CARD_AT_REV 6
+
+
+/****************************************************************************/
+/* */
+/* Values : BIA PROM FEATURES BYTE MASKS (and related values) */
+/* */
+/* The features byte in the BIA indicates certain hardware characteristics */
+/* of AT/P cards (and later cards). */
+/* Note that you can multiply the masked DRAM field by the DRAM_MULT value */
+/* to get the amount of RAM on the card (don't shift the field). */
+/* */
+
+#define BIA_PROM_FEATURE_SRA_MASK ((BYTE) 0x01)
+#define BIA_PROM_FEATURE_DRAM_MASK ((BYTE) 0x3E)
+#define BIA_PROM_FEATURE_CLKDIV_MASK ((BYTE) 0x40)
+
+#define DRAM_MULT 64
+
+
+/****************************************************************************/
+/* */
+/* Values : MADGE ADAPTER CARD NODE ADDRESSES */
+/* */
+/* The first 3 bytes of the permanent node address for Madge adapter cards */
+/* must have certain values. All Madge node addresses are of the form */
+/* 0000F6xxxxxx. */
+/* */
+
+#define MADGE_NODE_BYTE_0 ((BYTE) 0x00)
+#define MADGE_NODE_BYTE_1 ((BYTE) 0x00)
+#define MADGE_NODE_BYTE_2 ((BYTE) 0xF6)
+
+
+/* */
+/* */
+/************** End of FTK_CARD.H file **************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_def/ftk_defs.h b/private/ntos/ndis/madge/driver/head_def/ftk_defs.h
new file mode 100644
index 000000000..e5271ea61
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_def/ftk_defs.h
@@ -0,0 +1,52 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE FTK DEFINITIONS */
+/* =================== */
+/* */
+/* FTK_DEFS.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* Developed by MF */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* This header file includes all the definition header files used by the */
+/* FTK. The header files are included in an order such that all */
+/* dependenices between files are satisfied. */
+/* */
+/* IMPORTANT : All structures used within the FTK need to be packed in */
+/* order to work correctly. This means sizeof(STRUCTURE) will give the real */
+/* size in bytes, and if a structure contains sub-structures there will be */
+/* no spaces between the sub-structures. */
+/* */
+/****************************************************************************/
+
+#include "user.h"
+#include "ftk_user.h"
+#include "ftk_down.h"
+#include "ftk_init.h"
+#include "ftk_at.h"
+#include "ftk_sm16.h"
+#include "ftk_pci.h"
+#include "ftk_pcit.h"
+#include "ftk_pci2.h"
+#include "ftk_pcmc.h"
+#include "ftk_eisa.h"
+#include "ftk_mc.h"
+#include "ftk_pnp.h"
+#include "ftk_card.h"
+#include "ftk_fm.h"
+#include "ftk_err.h"
+#include "ftk_srb.h"
+#include "ftk_adap.h"
+#include "ftk_macr.h"
+#include "ftk_poke.h"
+
+/* */
+/* */
+/************** End of FTK_DEFS.H file **************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_def/ftk_down.h b/private/ntos/ndis/madge/driver/head_def/ftk_down.h
new file mode 100644
index 000000000..7ea825141
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_def/ftk_down.h
@@ -0,0 +1,128 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE DOWNLOAD DEFINITIONS */
+/* ======================== */
+/* */
+/* FTK_DOWN.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* Developed by MF */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* This header file contains the definitions for the structure which is */
+/* used for downloading information on to an adapter that is being used by */
+/* the FTK. */
+/* */
+/* REFERENCE : The Madge Smart SRB Interface */
+/* - Downloading The Code */
+/* */
+/* IMPORTANT : All structures used within the FTK need to be packed in */
+/* order to work correctly. This means sizeof(STRUCTURE) will give the real */
+/* size in bytes, and if a structure contains sub-structures there will be */
+/* no spaces between the sub-structures. */
+/* */
+/****************************************************************************/
+
+#pragma pack(1)
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this FTK_DOWN.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_FTK_DOWN_H 221
+
+
+/****************************************************************************/
+/* */
+/* TYPEDEFs for all structures defined within this header file : */
+/* */
+
+typedef struct STRUCT_DOWNLOAD_RECORD DOWNLOAD_RECORD;
+
+/****************************************************************************/
+/* */
+/* Structure type : DOWNLOAD_RECORD */
+/* */
+/* This structure gives the format of the records that define how data is */
+/* downloaded into adapter DIO space. There are only 3 types of record that */
+/* are used on EAGLEs when downloading. These are MODULE - a special record */
+/* that starts a download image, DATA_32 - null terminated data with DIO */
+/* start address location, and FILL_32 - pattern with length to be filled */
+/* in starting at given DIO location. */
+/* */
+/* Each download record is an array of words in Intel byte ordering (ie. */
+/* least significant byte first). */
+/* */
+/* REFERENCE : The Madge Smart SRB Interface */
+/* - Downloading The Code */
+/* */
+
+struct STRUCT_DOWNLOAD_RECORD
+ {
+ WORD length; /* length of entire record */
+ WORD type; /* type of record */
+ union
+ {
+ struct /* MODULE */
+ {
+ WORD reserved_1;
+ WORD download_features;
+ WORD reserved_2;
+ WORD reserved_3;
+ WORD reserved_4;
+ BYTE name[1]; /* '\0' ending module name */
+ } module;
+
+ struct /* DATA_32 */
+ {
+ DWORD dio_addr; /* 32 bit EAGLE address */
+ WORD word_count; /* number of words */
+ WORD data[1]; /* null terminated data */
+ } data_32;
+
+ struct /* FILL_32 */
+ {
+ DWORD dio_addr; /* 32 bit EAGLE address */
+ WORD word_count; /* number of words */
+ WORD pattern; /* value to fill */
+ } fill_32;
+
+ } body;
+
+ };
+
+/****************************************************************************/
+/* */
+/* Values : DOWNLOAD_RECORD - WORD type */
+/* */
+/* These values are for the different types of download record. */
+/* */
+
+#define DOWNLOAD_RECORD_TYPE_DATA_32 0x04
+#define DOWNLOAD_RECORD_TYPE_FILL_32 0x05
+#define DOWNLOAD_RECORD_TYPE_MODULE 0x12
+
+
+/****************************************************************************/
+/* */
+/* Values : DOWNLOAD_RECORD - module. WORD download_features */
+/* */
+/* These specify some features of the module to be downloaded that may be */
+/* checked for. */
+/* */
+
+#define DOWNLOAD_FASTMAC_INTERFACE 0x0011
+#define DOWNLOAD_BMIC_SUPPORT 0x4000 /* required for EISA cards */
+
+#pragma pack()
+
+/* */
+/* */
+/************** End of FTK_DOWN.H file **************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_def/ftk_eisa.h b/private/ntos/ndis/madge/driver/head_def/ftk_eisa.h
new file mode 100644
index 000000000..8845363c5
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_def/ftk_eisa.h
@@ -0,0 +1,132 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE MADGE ADAPTER CARD DEFINITIONS (EISA CARDS) */
+/* =============================================== */
+/* */
+/* FTK_EISA.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* Developed by MF */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* This header file contains the definitions for programming Madge EISA */
+/* adapter cards. Each adapter card has a number of control and status */
+/* registers. ALL bits in ALL registers are defined by Madge Networks Ltd, */
+/* however only a restricted number are defined below as used within the */
+/* FTK. All other bits must NOT be changed and no support will be offered */
+/* for any application that does so or uses the defined bits in any way */
+/* different to the FTK. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this FTK_EISA.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_FTK_EISA_H 221
+
+
+/****************************************************************************/
+/* */
+/* Values : EISA REGISTER MAP */
+/* */
+/* Madge EISA cards have the following register map. All SIF registers are */
+/* always visible. */
+/* */
+/* NB. The IO registers are actually in two groups 0x0000-0x000F (the SIF */
+/* registers) and 0x0C80-0x00C9F (the control type registers). */
+/* */
+
+#define EISA_IO_RANGE 16
+
+#define EISA_FIRST_SIF_REGISTER 0x0000
+
+#define EISA_IO_RANGE2 32
+
+#define EISA_IO_RANGE2_BASE 0x0C80
+
+#define EISA_ID_REGISTER_0 0x0C80
+#define EISA_ID_REGISTER_1 0x0C82
+#define EISA_CONTROLX_REGISTER 0x0C84
+
+#define EISA_BMIC_REGISTER_3 0x0C90
+
+
+/****************************************************************************/
+/* */
+/* Values : MC POS_REGISTER_0 */
+/* */
+/* These are the required contents of the EISA ID registers for Madge 16/4 */
+/* EISA mk1 and mk2 cards. */
+/* */
+
+#define EISA_ID0_MDG_CODE 0x8734 /* 'MDG' encoded */
+
+#define EISA_ID1_MK1_MDG_CODE 0x0100 /* '0001' encoded */
+#define EISA_ID1_MK2_MDG_CODE 0x0200 /* '0002' encoded */
+#define EISA_ID1_BRIDGE_MDG_CODE 0x0300 /* '0003' encoded */
+#define EISA_ID1_MK3_MDG_CODE 0x0400 /* '0004' encoded */
+
+
+/****************************************************************************/
+/* */
+/* Values : EISA CONTROLX_REGISTER */
+/* */
+/* These are the bit definitions for the expansion board control register */
+/* on EISA cards. */
+/* */
+
+#define EISA_CTRLX_CDEN ((BYTE) 0x01) /* card enabled */
+
+
+/****************************************************************************/
+/* */
+/* Values : EISA BMIC_REGISTER_3 */
+/* */
+/* These are the bit definitions for BMIC register 3 on EISA cards. */
+/* */
+
+#define EISA_BMIC3_IRQSEL ((BYTE) 0x0F) /* interrupt number (4 bits) */
+#define EISA_BMIC3_EDGE ((BYTE) 0x10) /* edge\level triggered ints */
+#define EISA_BMIC3_SPD ((BYTE) 0x80) /* any speed selected */
+
+
+/****************************************************************************/
+/* */
+/* Values : EISA EXTENDED EAGLE SIF REGISTERS */
+/* */
+/* The EAGLE SIF registers are in two groups - the normal SIF registers */
+/* (those from the old TI chipset) and the extended SIF registers (those */
+/* particular to the EAGLE). For Madge EISA adapter cards, both normal and */
+/* extended SIF registers are always accessible. */
+/* */
+/* The definitions for the normal SIF registers are in FTK_CARD.H because */
+/* they appear in the same relative IO locations for all adapter cards. The */
+/* extended SIF registers are here because they appear at different */
+/* relative IO locations for different types of adapter cards. */
+/* */
+
+#define EISA_EAGLE_SIFACL 8 /* adapter control */
+#define EISA_EAGLE_SIFADR_2 10 /* copy of SIFADR */
+#define EISA_EAGLE_SIFADX 12 /* DIO address (high) */
+#define EISA_EAGLE_DMALEN 14 /* DMA length */
+
+
+/****************************************************************************/
+/* */
+/* Values : VRAM enable on EIDA Mk3 */
+/* */
+
+#define DIO_LOCATION_EISA_VRAM_ENABLE ((DWORD) 0xC0000L)
+#define EISA_VRAM_ENABLE_WORD ((WORD) 0xFFFF)
+
+/* */
+/* */
+/************** End of FTK_EISA.H file **************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_def/ftk_err.h b/private/ntos/ndis/madge/driver/head_def/ftk_err.h
new file mode 100644
index 000000000..595460bb5
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_def/ftk_err.h
@@ -0,0 +1,389 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE ERROR DEFINITIONS */
+/* ===================== */
+/* */
+/* FTK_ERR.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* Developed by MF */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* This header file contains the structures associated with error handling */
+/* and all the possible error codes (types and values) produced by the FTK. */
+/* */
+/* A string of text describing each of the possible error codes (type and */
+/* value) can be found in the error tables in FTK_TAB.H. */
+/* */
+/* IMPORTANT : All structures used within the FTK need to be packed in */
+/* order to work correctly. This means sizeof(STRUCTURE) will give the real */
+/* size in bytes, and if a structure contains sub-structures there will be */
+/* no spaces between the sub-structures. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this FTK_ERR.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_FTK_ERR_H 221
+
+
+/****************************************************************************/
+/* */
+/* TYPEDEFs for all structures defined within this header file : */
+/* */
+
+typedef struct STRUCT_ERROR_RECORD ERROR_RECORD;
+typedef struct STRUCT_ERROR_MESSAGE ERROR_MESSAGE;
+typedef struct STRUCT_ERROR_MESSAGE_RECORD ERROR_MESSAGE_RECORD;
+
+
+/****************************************************************************/
+/* */
+/* Structure type : ERROR_MESSAGE_RECORD */
+/* */
+/* The error message tables (see FTK_TAB.H) are made up of elements of this */
+/* structure. Each error message string has associated with it an error */
+/* value of the type of error that the table is for. */
+/* */
+
+struct STRUCT_ERROR_MESSAGE_RECORD
+ {
+ BYTE value;
+ char * err_msg_string;
+ };
+
+
+/****************************************************************************/
+/* */
+/* Structure type : ERROR_MESSAGE */
+/* */
+/* Associated with an adapter structure is an error message for the last */
+/* error to occur on the adapter. It is filled in by a call to */
+/* driver_explain_error and a pointer to it is returned to the user. */
+/* */
+
+#define MAX_ERROR_MESSAGE_LENGTH 600
+
+struct STRUCT_ERROR_MESSAGE
+ {
+ char string[MAX_ERROR_MESSAGE_LENGTH];
+ };
+
+/****************************************************************************/
+/* */
+/* Structure type : ERROR_RECORD */
+/* */
+/* This structure is used for recording error information. There is an */
+/* element of this structure, associated with every adapter, that is used */
+/* to record the current error status of the adapter. */
+/* */
+
+struct STRUCT_ERROR_RECORD
+ {
+ BYTE type;
+ BYTE value;
+ };
+
+
+/****************************************************************************/
+/* */
+/* Values : ERROR_RECORD - BYTE type */
+/* */
+/* The following lists the type of errors that can occur. Some of these are */
+/* fatal in that an adapter for which they occur can not subsequently be */
+/* used. The value 0 (zero) is used to indicate no error has yet occured. */
+/* */
+
+#define ERROR_TYPE_NONE (BYTE) 0x00 /* no error */
+#define ERROR_TYPE_SRB (BYTE) 0x01 /* non-fatal error */
+#define ERROR_TYPE_OPEN (BYTE) 0x02 /* non-fatal error */
+#define ERROR_TYPE_DATA_XFER (BYTE) 0x03 /* non-fatal error */
+#define ERROR_TYPE_DRIVER (BYTE) 0x04 /* fatal error */
+#define ERROR_TYPE_HWI (BYTE) 0x05 /* fatal error */
+#define ERROR_TYPE_BRING_UP (BYTE) 0x06 /* fatal error */
+#define ERROR_TYPE_INIT (BYTE) 0x07 /* fatal error */
+#define ERROR_TYPE_AUTO_OPEN (BYTE) 0x08 /* fatal error */
+#define ERROR_TYPE_ADAPTER (BYTE) 0x09 /* fatal error */
+#define ERROR_TYPE_CS (BYTE) 0x0A /* fatal error */
+
+
+/****************************************************************************/
+/* */
+/* Values : ERROR_RECORD - ERROR_TYPE_SRB . BYTE value */
+/* SRB_HEADER - BYTE return_code */
+/* */
+/* The non-fatal SRB error type uses for error values the return codes in */
+/* the SRB header. For the SRBs that are supported by the FTK there are */
+/* only a limited number of possible error values that can occur. Note */
+/* however, that a failing open adapter SRB call may cause OPEN error type */
+/* errors and not just SRB error type errors (see ERROR_TYPE_OPEN below). */
+/* */
+/* REFERENCE : The Madge Fastmac Interface Specification */
+/* - SRB Interface */
+/* */
+
+#define SRB_E_00_SUCCESS (BYTE) 0x00
+#define SRB_E_03_ADAPTER_OPEN (BYTE) 0x03
+#define SRB_E_04_ADAPTER_CLOSED (BYTE) 0x04
+#define SRB_E_06_INVALID_OPTIONS (BYTE) 0x06
+#define SRB_E_07_CMD_CANCELLED_FAIL (BYTE) 0x07
+#define SRB_E_32_INVALID_NODE_ADDRESS (BYTE) 0x32
+
+
+/****************************************************************************/
+/* */
+/* Values : ERROR_RECORD - ERROR_TYPE_OPEN . BYTE value */
+/* */
+/* Non-fatal open errors occur when an open adapter SRB returns with code */
+/* SRB_E_07_CMD_CANCELLED_FAILED. In this case the error type is changed to */
+/* ERROR_TYPE_OPEN and the error value is changed to show that an open */
+/* error has occured. The actual open error details are determined when the */
+/* user calls driver_explain_error (see TMS Open Error Codes below). */
+/* */
+
+#define OPEN_E_01_OPEN_ERROR (BYTE) 0x01
+
+
+/****************************************************************************/
+/* */
+/* Values : ERROR_RECORD - ERROR_TYPE_DATA_XFER . BYTE value */
+/* */
+/* There is only one possible non-fatal data transfer error. This occurs on */
+/* an attempted transmit when the Fastmac transmit buffer is full. */
+/* */
+
+#define DATA_XFER_E_01_BUFFER_FULL (BYTE) 0x01
+
+
+/****************************************************************************/
+/* */
+/* Values : ERROR_RECORD - ERROR_TYPE_DRIVER . BYTE value */
+/* */
+/* The DRIVER part of the FTK can generate the following fatal error */
+/* values. These can, for example, be caused by sys_alloc routines failing */
+/* or passing an illegal adapter handle to a driver routine. See FTK_TAB.H */
+/* for more details. */
+/* */
+
+#define DRIVER_E_01_INVALID_HANDLE (BYTE) 0x01
+#define DRIVER_E_02_NO_ADAP_STRUCT (BYTE) 0x02
+#define DRIVER_E_03_FAIL_ALLOC_STATUS (BYTE) 0x03
+#define DRIVER_E_04_FAIL_ALLOC_INIT (BYTE) 0x04
+#define DRIVER_E_05_FAIL_ALLOC_RX_BUF (BYTE) 0x05
+#define DRIVER_E_06_FAIL_ALLOC_TX_BUF (BYTE) 0x06
+#define DRIVER_E_07_NOT_PREPARED (BYTE) 0x07
+#define DRIVER_E_08_NOT_RUNNING (BYTE) 0x08
+#define DRIVER_E_09_SRB_NOT_FREE (BYTE) 0x09
+#define DRIVER_E_0A_RX_BUF_BAD_SIZE (BYTE) 0x0A
+#define DRIVER_E_0B_RX_BUF_NOT_DWORD (BYTE) 0x0B
+#define DRIVER_E_0C_TX_BUF_BAD_SIZE (BYTE) 0x0C
+#define DRIVER_E_0D_TX_BUF_NOT_DWORD (BYTE) 0x0D
+#define DRIVER_E_0E_BAD_RX_METHOD (BYTE) 0x0E
+#define DRIVER_E_0F_WRONG_RX_METHOD (BYTE) 0x0F
+
+#define DRIVER_E_10_BAD_RX_SLOT_NUMBER (BYTE) 0x10
+#define DRIVER_E_11_BAD_TX_SLOT_NUMBER (BYTE) 0x11
+#define DRIVER_E_12_FAIL_ALLOC_DMA_BUF (BYTE) 0x12
+#define DRIVER_E_13_BAD_FRAME_SIZE (BYTE) 0x13
+
+
+/****************************************************************************/
+/* */
+/* Values : ERROR_RECORD - ERROR_TYPE_HWI . BYTE value */
+/* */
+/* The HWI part of the FTK can generate the following fatal error values. */
+/* Most of these are caused by the user supplying illegal values to */
+/* driver_start_adapter. See FTK_TAB.H for more details. */
+/* */
+
+#define HWI_E_01_BAD_CARD_BUS_TYPE (BYTE) 0x01
+#define HWI_E_02_BAD_IO_LOCATION (BYTE) 0x02
+#define HWI_E_03_BAD_INTERRUPT_NUMBER (BYTE) 0x03
+#define HWI_E_04_BAD_DMA_CHANNEL (BYTE) 0x04
+#define HWI_E_05_ADAPTER_NOT_FOUND (BYTE) 0x05
+#define HWI_E_06_CANNOT_USE_DMA (BYTE) 0x06
+#define HWI_E_07_FAILED_TEST_DMA (BYTE) 0x07
+#define HWI_E_08_BAD_DOWNLOAD (BYTE) 0x08
+#define HWI_E_09_BAD_DOWNLOAD_IMAGE (BYTE) 0x09
+#define HWI_E_0A_NO_DOWNLOAD_IMAGE (BYTE) 0x0A
+#define HWI_E_0B_FAIL_IRQ_ENABLE (BYTE) 0x0B
+#define HWI_E_0C_FAIL_DMA_ENABLE (BYTE) 0x0C
+#define HWI_E_0D_CARD_NOT_ENABLED (BYTE) 0x0D
+#define HWI_E_0E_NO_SPEED_SELECTED (BYTE) 0x0E
+#define HWI_E_0F_BAD_FASTMAC_INIT (BYTE) 0x0F
+
+#define HWI_E_10_BAD_TX_RX_BUFF_SIZE (BYTE) 0x10
+#define HWI_E_11_TOO_MANY_TX_RX_BUFFS (BYTE) 0x11
+#define HWI_E_12_BAD_SCB_ALLOC (BYTE) 0x12
+#define HWI_E_13_BAD_SSB_ALLOC (BYTE) 0x13
+#define HWI_E_14_BAD_PCI_MACHINE (BYTE) 0x14
+#define HWI_E_15_BAD_PCI_MEMORY (BYTE) 0x15
+#define HWI_E_16_PCI_3BYTE_PROBLEM (BYTE) 0x16
+#define HWI_E_17_BAD_TRANSFER_MODE (BYTE) 0x17
+
+/****************************************************************************/
+/* */
+/* Values : ERROR_RECORD - ERROR_TYPE_BRING_UP . BYTE value */
+/* */
+/* During an attempt to perform bring-up of an adapter card, one of a */
+/* number of fatal error values may be produced. Bits 12-15 of the EAGLE */
+/* SIFINT register contain the error value. These codes are used by the FTK */
+/* to distinguish different bring-up errors. An extra error value is used */
+/* for the case when no bring up code is produced within a timeout period */
+/* (3 seconds). */
+/* */
+/* REFERENCE : The TMS 380 Second-Generation Token_Ring User's Guide */
+/* by Texas Instruments */
+/* 4-40 4.5 Bring-Up Diagnostics - BUD */
+/* */
+
+#define BRING_UP_E_00_INITIAL_TEST (BYTE) 0x00
+#define BRING_UP_E_01_SOFTWARE_CHECKSUM (BYTE) 0x01
+#define BRING_UP_E_02_ADAPTER_RAM (BYTE) 0x02
+#define BRING_UP_E_03_INSTRUCTION_TEST (BYTE) 0x03
+#define BRING_UP_E_04_INTERRUPT_TEST (BYTE) 0x04
+#define BRING_UP_E_05_FRONT_END (BYTE) 0x05
+#define BRING_UP_E_06_SIF_REGISTERS (BYTE) 0x06
+
+#define BRING_UP_E_10_TIME_OUT (BYTE) 0x10
+
+
+/****************************************************************************/
+/* */
+/* Values : ERROR_RECORD - ERROR_TYPE_INIT . BYTE value */
+/* */
+/* During an attempt to perform adapter initialization, one of a number of */
+/* fatal error values may be produced. Bits 12-15 of the EAGLE SIFINT */
+/* regsiter contain the error value. These codes are used by the FTK to */
+/* distinguish different initialization errors. An extra error value is */
+/* used for the case when no initialization code is produced within a */
+/* timeout period (11 seconds). */
+/* */
+/* REFERENCE : The TMS 380 Second-Generation Token_Ring User's Guide */
+/* by Texas Instruments */
+/* 4-47 4.6 Adapter Initialization */
+/* */
+
+#define INIT_E_01_INIT_BLOCK (BYTE) 0x01
+#define INIT_E_02_INIT_OPTIONS (BYTE) 0x02
+#define INIT_E_03_RX_BURST_SIZE (BYTE) 0x03
+#define INIT_E_04_TX_BURST_SIZE (BYTE) 0x04
+#define INIT_E_05_DMA_THRESHOLD (BYTE) 0x05
+#define INIT_E_06_ODD_SCB_ADDRESS (BYTE) 0x06
+#define INIT_E_07_ODD_SSB_ADDRESS (BYTE) 0x07
+#define INIT_E_08_DIO_PARITY (BYTE) 0x08
+#define INIT_E_09_DMA_TIMEOUT (BYTE) 0x09
+#define INIT_E_0A_DMA_PARITY (BYTE) 0x0A
+#define INIT_E_0B_DMA_BUS (BYTE) 0x0B
+#define INIT_E_0C_DMA_DATA (BYTE) 0x0C
+#define INIT_E_0D_ADAPTER_CHECK (BYTE) 0x0D
+#define INIT_E_0E_NOT_ENOUGH_MEMORY (BYTE) 0x0E
+
+#define INIT_E_10_TIME_OUT (BYTE) 0x10
+
+
+/****************************************************************************/
+/* */
+/* Values : ERROR_RECORD - ERROR_TYPE_AUTO_OPEN . BYTE value */
+/* */
+/* Auto-open errors are fatal - there is no chance to try to open the */
+/* adapter again. The error value is usually set to show that an open */
+/* adapter error has occured. The details of the open error are determined */
+/* when the user calls driver_explain_error (see TMS Open Error Codes */
+/* below). There is also an extra error value which is used for the case */
+/* when no open adapter error code is produced within a timeout period (40 */
+/* seconds). */
+/* */
+/* REFERENCE : The TMS 380 Second-Generation Token_Ring User's Guide */
+/* by Texas Instruments */
+/* 4-79 MAC 0003 OPEN command */
+/* */
+
+#define AUTO_OPEN_E_01_OPEN_ERROR (BYTE) 0x01
+#define AUTO_OPEN_E_80_TIME_OUT (BYTE) 0x80
+
+
+/****************************************************************************/
+/* */
+/* Values : ERROR_RECORD - ERROR_TYPE_ADAPTER . BYTE value */
+/* */
+/* An adapter check interrupt causes an adapter check fatal error. */
+/* Different types of adapter checks are not distinguished by the FTK. */
+/* */
+
+#define ADAPTER_E_01_ADAPTER_CHECK (BYTE) 0x01
+
+
+/****************************************************************************/
+/* */
+/* Values : ERROR_RECORD - ERROR_TYPE_CS . BYTE value */
+/* */
+/* These are possible errors return from calling PCMCIA Card Services. */
+/* These errors can only occur on 16/4 PCMCIA ringnode. Other adapters do */
+/* not make calls to PCMCIA Card Services. To start up a 16/4 PCMCIA */
+/* Ringnode, the driver first registers with PCMCIA Card Services as a */
+/* client, gropes for the ringnode using Card Services calls, requests I/O */
+/* and interrupt resources from Card Services. If any of these operations */
+/* fails, the driver will return following errors. Note that these are */
+/* fatal errors. */
+/* */
+
+#define CS_E_01_NO_CARD_SERVICES (BYTE) 0x01
+#define CS_E_02_REGISTER_CLIENT_FAILED (BYTE) 0x02
+#define CS_E_03_REGISTRATION_TIMEOUT (BYTE) 0x03
+#define CS_E_04_NO_MADGE_ADAPTER_FOUND (BYTE) 0x04
+#define CS_E_05_ADAPTER_NOT_FOUND (BYTE) 0x05
+#define CS_E_06_SPECIFIED_SOCKET_IN_USE (BYTE) 0x06
+#define CS_E_07_IO_REQUEST_FAILED (BYTE) 0x07
+#define CS_E_08_BAD_IRQ_CHANNEL (BYTE) 0x08
+#define CS_E_09_IRQ_REQUEST_FAILED (BYTE) 0x09
+#define CS_E_0A_REQUEST_CONFIG_FAILED (BYTE) 0x0A
+
+
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* Values : TMS Open Error Codes */
+/* */
+/* When an E_01_OPEN_ERROR (either AUTO_OPEN or OPEN) occurs, more details */
+/* of the open adapter error are available by looking at the open_error */
+/* field in the Fastmac status block. This open error is the same as that */
+/* generated by a TI MAC 0003 OPEN command. */
+/* */
+/* REFERENCE : The TMS 380 Second-Generation Token_Ring User's Guide */
+/* by Texas Instruments */
+/* 4-79 MAC 0003 OPEN command */
+/* */
+
+#define TMS_OPEN_FAIL_E_40_OPEN_ADDR 0x4000
+#define TMS_OPEN_FAIL_E_02_FAIL_OPEN 0x0200
+#define TMS_OPEN_FAIL_E_01_OPEN_OPTS 0x0100
+
+#define TMS_OPEN_PHASE_E_01_LOBE_TEST 0x0010
+#define TMS_OPEN_PHASE_E_02_INSERTION 0x0020
+#define TMS_OPEN_PHASE_E_03_ADDR_VER 0x0030
+#define TMS_OPEN_PHASE_E_04_RING_POLL 0x0040
+#define TMS_OPEN_PHASE_E_05_REQ_INIT 0x0050
+
+#define TMS_OPEN_ERR_E_01_FUNC_FAIL 0x0001
+#define TMS_OPEN_ERR_E_02_SIGNAL_LOSS 0x0002
+#define TMS_OPEN_ERR_E_05_TIMEOUT 0x0005
+#define TMS_OPEN_ERR_E_06_RING_FAIL 0x0006
+#define TMS_OPEN_ERR_E_07_BEACONING 0x0007
+#define TMS_OPEN_ERR_E_08_DUPL_ADDR 0x0008
+#define TMS_OPEN_ERR_E_09_REQ_INIT 0x0009
+#define TMS_OPEN_ERR_E_0A_REMOVE 0x000A
+
+
+/* */
+/* */
+/************** End of FTK_ERR.H file ***************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_def/ftk_fm.h b/private/ntos/ndis/madge/driver/head_def/ftk_fm.h
new file mode 100644
index 000000000..0d99596df
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_def/ftk_fm.h
@@ -0,0 +1,351 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE FASTMAC DEFINITIONS */
+/* ======================= */
+/* */
+/* FTK_FM.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* This header file contains the structures, constants etc., that are */
+/* relevant to Fastmac and its use by the FTK and are not included */
+/* elsewhere. This includes the Fastmac status block structure and the */
+/* Fastmac use of the EAGLE SIFINT register. */
+/* */
+/* IMPORTANT : All structures used within the FTK need to be packed in */
+/* order to work correctly. This means sizeof(STRUCTURE) will give the real */
+/* size in bytes, and if a structure contains sub-structures there will be */
+/* no spaces between the sub-structures. */
+/* */
+/****************************************************************************/
+
+#pragma pack(1)
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this FTK_FM.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_FTK_FM_H 221
+
+
+/****************************************************************************/
+/* */
+/* TYPEDEFs for all structures defined within this header file : */
+/* */
+
+typedef struct STRUCT_FASTMAC_STATUS_BLOCK FASTMAC_STATUS_BLOCK;
+#ifdef FMPLUS
+typedef struct STRUCT_RX_SLOT RX_SLOT;
+typedef struct STRUCT_TX_SLOT TX_SLOT;
+#endif
+
+/****************************************************************************/
+/* */
+/* Structure type : FASTMAC_STATUS_BLOCK */
+/* */
+/* Fastmac maintains a status block that includes the pointers to the */
+/* receive and transmit buffers, as well as the ring status and a boolean */
+/* flag to say if the adapter is open. */
+/* */
+/* REFERENCE : The Madge Fastmac Interface Specification */
+/* - Status Block */
+/* */
+
+struct STRUCT_FASTMAC_STATUS_BLOCK
+ {
+ WORD reserved_1;
+ WORD signature;
+ WBOOLEAN adapter_open; /* TRUE when open */
+ WORD open_error; /* open error code */
+ WORD tx_adap_ptr; /* transmit buffer pointers */
+ WORD tx_host_ptr;
+ WORD tx_wrap_ptr;
+ WORD rx_adap_ptr; /* receive buffer pointers */
+ WORD rx_wrap_ptr;
+ WORD rx_host_ptr;
+ NODE_ADDRESS permanent_address; /* BIA PROM node address */
+ NODE_ADDRESS open_address; /* opening node address */
+ WORD tx_dma_count;
+ WORD timestamp_ptr;
+ WORD rx_internal_buffer_size;
+ WORD rx_total_buffers_avail;
+ WORD rx_buffers_in_use;
+ WORD rx_frames_lost;
+ WORD watchdog_timer;
+ WORD ring_status; /* current ring status */
+ WORD tx_discarded;
+#ifdef FMPLUS
+ WORD rx_slot_start; /* where to find rx slots */
+ WORD tx_slot_start; /* where to find tx slots */
+#endif
+ WORD reserved_2[1];
+ WORD rxdesc_host_ptr;
+ DWORD rxdesc_queue[1];
+ };
+
+
+/****************************************************************************/
+/* */
+/* Values : Fastmac buffer sizes */
+/* */
+/* The Fastmac receive and transmit buffers have minimum and maximum */
+/* allowable sizes. The minimum size allows the buffer to contain a single */
+/* 1K frame. */
+/* */
+
+#define FASTMAC_MAXIMUM_BUFFER_SIZE 0xFF00
+#define FASTMAC_MINIMUM_BUFFER_SIZE 0x0404
+
+
+/****************************************************************************/
+/* */
+/* Values : FASTMAC SIF INTERRUPT (SIFCMD-SIFSTS) REGISTER BITS */
+/* */
+/* When Fastmac generates an interrupt (via the SIF interrupt register), */
+/* the value in the register will indicate the reason for the interrupt. */
+/* Also, when the user interrupts Fastmac (again via the SIF interrupt */
+/* register), the value in the register indicates the reason. */
+/* */
+/* REFERENCE : The Madge Smart SRB Interface */
+/* - The Interrupt Register */
+/* */
+
+#define DRIVER_SIFINT_IRQ_FASTMAC 0x8000 /* interrupt Fastmac */
+
+#define DRIVER_SIFINT_FASTMAC_IRQ_MASK 0x00FF
+
+#define DRIVER_SIFINT_SSB_FREE 0x4000
+#define DRIVER_SIFINT_SRB_COMMAND 0x2000
+#define DRIVER_SIFINT_ARB_FREE 0x1000
+
+#define DRIVER_SIFINT_ACK_SSB_RESPONSE 0x0400
+#define DRIVER_SIFINT_ACK_SRB_FREE 0x0200
+#define DRIVER_SIFINT_ACK_ARB_COMMAND 0x0100
+
+
+#define FASTMAC_SIFINT_IRQ_DRIVER 0x0080 /* interrupt driver */
+
+#define FASTMAC_SIFINT_ADAPTER_CHECK 0x0008
+#define FASTMAC_SIFINT_SSB_RESPONSE 0x0004
+#define FASTMAC_SIFINT_SRB_FREE 0x0002
+#define FASTMAC_SIFINT_ARB_COMMAND 0x0001
+
+#define FASTMAC_SIFINT_RECEIVE 0x0000
+
+
+/****************************************************************************/
+/* */
+/* Values : FASTMAC DIO LOCATIONS */
+/* */
+/* There are certain fixed locations in DIO space containing pointers that */
+/* are accessed by the driver to determine DIO locations where the driver */
+/* must read or store Fastmac information. These pointers identify the */
+/* location of such things as the SRB and status block (STB). The pointers */
+/* are at DIO locations 0x00011000 - 0x00011008. The values defined below */
+/* give the location of the pointers within the EAGLE DATA page 0x00010000. */
+/* */
+/* REFERENCE : The Madge Smart SRB Interface */
+/* - Shared RAM Format */
+/* */
+
+#define DIO_LOCATION_SSB_POINTER 0x1000
+#define DIO_LOCATION_SRB_POINTER 0x1002
+#define DIO_LOCATION_ARB_POINTER 0x1004
+#define DIO_LOCATION_STB_POINTER 0x1006 /* status block */
+#define DIO_LOCATION_IPB_POINTER 0x1008 /* init block */
+#define DIO_LOCATION_DMA_CONTROL 0x100A
+#define DIO_LOCATION_DMA_POINTER 0x100C
+
+
+/****************************************************************************/
+/* */
+/* Values : Fastmac product id string */
+/* */
+/* The product id string for Fastmac that is used by certain management MAC */
+/* frames. If the Fastmac auto-open feature is used then the product id is */
+/* always "THE MADGE FASTMAC". If an OPEN_ADAPTER SRB then the FTK product */
+/* id is "FTK MADGE FASTMAC". */
+/* */
+/* REFERENCE : The Madge Fastmac Interface Specification */
+/* - SRB Interface : Open Adapter SRB */
+/* */
+
+#define SIZEOF_PRODUCT_ID 18
+#ifdef FMPLUS
+#define FASTMAC_PRODUCT_ID "FTK MADGE FM PLUS"
+#else
+#define FASTMAC_PRODUCT_ID "FTK MADGE FASTMAC"
+#endif
+
+/****************************************************************************/
+/* */
+/* Global variable : ftk_product_inst_id */
+/* */
+/* Value of the product ID strings set when an open adapter SRB */
+/* is generated. This is set to FASTMAC_PRODUCT_ID in DRV_SRB.C. */
+/* */
+
+extern char ftk_product_inst_id[SIZEOF_PRODUCT_ID];
+
+/****************************************************************************/
+/* */
+/* Values : Fastmac buffer format */
+/* */
+/* The format in which frames are kept in the Fastmac buffers includes a */
+/* header to the frame containing the length of the entire header and */
+/* frame, and a timestamp. */
+/* */
+/* REFERENCE : The Madge Fastmac Interface Specification */
+/* - The Fastmac Algorithm */
+/* */
+
+
+#define FASTMAC_BUFFER_HEADER_SIZE 4
+
+#define FASTMAC_HEADER_LENGTH_OFFSET 0
+#define FASTMAC_HEADER_STAMP_OFFSET 2
+
+
+#ifdef FMPLUS
+/****************************************************************************/
+/* */
+/* Structure type : RX_SLOT */
+/* */
+/* Fastmac Plus maintains a slot structure on the card for each receive */
+/* buffer on the host. These include the address of the buffer, the length */
+/* of any frame in it, and the receive status of any frame there. When a */
+/* frame is received, Fastmac Plus updates the length and status fields. */
+/* */
+/* REFERENCE : The Madge Fastmac Plus Programming Specification */
+/* - Receive Details: Slot Structure */
+/* */
+
+struct STRUCT_RX_SLOT
+ {
+ WORD buffer_len;
+ WORD reserved;
+ WORD buffer_hiw;
+ WORD buffer_low;
+ WORD rx_status;
+ WORD next_slot;
+ };
+
+
+/****************************************************************************/
+/* */
+/* Structure type : TX_SLOT */
+/* */
+/* Fastmac Plus maintains a number of slot structures on the card, to allow */
+/* transmit pipelining. Each of these structures includes two fields for */
+/* host buffers and lengths - one is for a small buffer, less than the size */
+/* of a buffer on the adapter card, and the other is for a large buffer, up */
+/* to the maximum frame size. There is also a status field so that the host */
+/* transmit code can monitor the progress of the transmit. */
+/* */
+/* REFERENCE : The Madge Fastmac Plus Programming Specification */
+/* - Transmit Details: Slot Structure */
+/* */
+
+struct STRUCT_TX_SLOT
+ {
+ WORD tx_status;
+ WORD small_buffer_len;
+ WORD large_buffer_len;
+ WORD reserved[2];
+ WORD small_buffer_hiw;
+ WORD small_buffer_low;
+ WORD next_slot;
+ WORD large_buffer_hiw;
+ WORD large_buffer_low;
+ };
+
+
+/****************************************************************************/
+/* */
+/* Values : Fastmac Plus min/max slot numbers */
+/* */
+/* Fastmac Plus places certain restrictions on the numbers of transmit and */
+/* receive slots that can be allocated. These constants specify the values. */
+/* */
+/* REFERENCE : The Madge Fastmac Plus Programming Specification */
+/* - Initialisation : TMS Load Parms */
+/* */
+
+#define FMPLUS_MAX_RX_SLOTS 32
+#define FMPLUS_MIN_RX_SLOTS 2
+
+#define FMPLUS_MAX_TX_SLOTS 32
+#define FMPLUS_MIN_TX_SLOTS 2
+
+
+/****************************************************************************/
+/* */
+/* Values : Fastmac Plus Receive Status Mask */
+/* */
+/* By bitwise AND-ing the mask here with the receive status read from the */
+/* receive slot, code can determine whether the received frame is good or */
+/* not. If the result is zero, the frame is good, otherwise it is a junk */
+/* frame. */
+/* */
+/* REFERENCE : The Madge Fastmac Plus Programming Specification */
+/* - Receive Status Processing */
+/* */
+
+#define GOOD_RX_FRAME_MASK ((WORD) 0x5E00)
+
+
+/****************************************************************************/
+/* */
+/* Values : Fastmac Plus Transmit Status Mask And Values */
+/* */
+/* By bitwise AND-ing the good frame mask with the transmit status read */
+/* from the receive slot, code can determine whether the frame was */
+/* transmitted properly or not. If more detail is required, the receive */
+/* status mask can be used to check various conditions in the transmitted */
+/* frame when it returned to the adapter. */
+/* */
+/* REFERENCE : The Madge Fastmac Plus Programming Specification */
+/* - Transmit Status Processing */
+/* */
+
+#define GOOD_TX_FRAME_MASK ((WORD) 0x5F00)
+#define GOOD_TX_FRAME_VALUE ((WORD) 0x0100)
+
+#define TX_RECEIVE_STATUS_MASK ((WORD) 0x0700)
+#define TX_RECEIVE_LOST_FRAME ((WORD) 0x0300)
+#define TX_RECEIVE_CORRUPT_TOKEN ((WORD) 0x0500)
+#define TX_RECEIVE_IMPLICIT_ABORT ((WORD) 0x0700)
+
+
+/****************************************************************************/
+/* */
+/* Values : Fastmac Plus Zero Length Small Buffer value */
+/* */
+/* When transmitting a frame that exists only in a large buffer, a special */
+/* non-zero value must be written to the small buffer length field of the */
+/* receive slot (this is because Fastmac Plus uses zero there to indicate */
+/* that a transmit has completed, and waits for it to change before trying */
+/* to transmit any more from that slot). This special value is defined here.*/
+/* */
+/* REFERENCE : The Madge Fastmac Plus Programming Specification */
+/* - Transmit Details */
+/* */
+
+#define FMPLUS_SBUFF_ZERO_LENGTH ((WORD)(0x8000))
+
+#endif
+
+
+#pragma pack()
+
+/* */
+/* */
+/************** End of FTK_FM.H file ****************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_def/ftk_init.h b/private/ntos/ndis/madge/driver/head_def/ftk_init.h
new file mode 100644
index 000000000..491df1e0a
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_def/ftk_init.h
@@ -0,0 +1,330 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE INITIALIZATION BLOCK DEFINITIONS */
+/* ==================================== */
+/* */
+/* FTK_INIT.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* This header file contains the definitions for the structures that go to */
+/* make the initialization block that is needed in order to initialize an */
+/* adapter card that is in use by the FTK. */
+/* */
+/* IMPORTANT : All structures used within the FTK need to be packed in */
+/* order to work correctly. This means sizeof(STRUCTURE) will give the real */
+/* size in bytes, and if a structure contains sub-structures there will be */
+/* no spaces between the sub-structures. */
+/* */
+/****************************************************************************/
+
+#pragma pack(1)
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this FTK_INIT.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_FTK_INIT_H 221
+
+
+/****************************************************************************/
+/* */
+/* TYPEDEFs for all structures defined within this header file : */
+/* */
+
+typedef struct STRUCT_INITIALIZATION_BLOCK INITIALIZATION_BLOCK;
+typedef struct STRUCT_TI_INIT_PARMS TI_INIT_PARMS;
+typedef struct STRUCT_MADGE_INIT_PARMS_HEADER MADGE_INIT_PARMS_HEADER;
+typedef struct STRUCT_SMART_INIT_PARMS SMART_INIT_PARMS;
+typedef struct STRUCT_FASTMAC_INIT_PARMS FASTMAC_INIT_PARMS;
+
+/****************************************************************************/
+/* */
+/* Structure type : TI_INIT_PARMS */
+/* */
+/* The TI initialization parameters are exactly those defined by TI for */
+/* initializing an adapter based on the EAGLE chipset except for a special */
+/* byte of 16/4 MC 32 configuration information. This byte overrides a TI */
+/* initialization block field not used by Madge adapter cards. */
+/* */
+/* REFERENCE : The TMS 380 Second-Generation Token_Ring User's Guide */
+/* by Texas Instruments */
+/* 4-42 4.6 Adapter Initialization */
+/* */
+
+struct STRUCT_TI_INIT_PARMS
+ {
+ WORD init_options;
+ WORD madge_mc32_config; /* special MC 32 data */
+ BYTE reserved[4]; /* ignored by Madge cards */
+ WORD rx_burst;
+ WORD tx_burst;
+ BYTE parity_retry;
+ BYTE dma_retry;
+ DWORD scb_addr; /* 32 bit phys host addr */
+ DWORD ssb_addr; /* 32 bit phys host addr */
+ };
+
+
+/****************************************************************************/
+/* */
+/* Values : TI_INIT_PARMS - WORD init_options */
+/* */
+/* The init_options are set up for burst mode DMA. */
+/* */
+
+#define TI_INIT_OPTIONS_BURST_DMA 0x9F00
+
+
+/****************************************************************************/
+/* */
+/* Values : TI_INIT_PARMS - WORD madge_mc32_config */
+/* */
+/* This value is used to configure MC and ISA CLIENT cards. */
+/* */
+
+#define MC_AND_ISACP_USE_PIO 0x0040
+
+
+/****************************************************************************/
+/* */
+/* Values : TI_INIT_PARMS - BYTE parity_retry, BYTE dma_retry */
+/* */
+/* A default value is used by the FTK for the parity and dma retry counts. */
+/* */
+
+#define TI_INIT_RETRY_DEFAULT 5
+
+
+/****************************************************************************/
+/* */
+/* Structure type : MADGE_INIT_PARMS_HEADER */
+/* */
+/* This is the common header to all Madge smart software initialization */
+/* parameter blocks - that is, in this case, the header for the general */
+/* smart software MAC level parameters and the Fastmac specific parameters. */
+/* */
+/* REFERENCE : The Madge Smart SRB Interface */
+/* - Bring-Up and Initialization */
+/* */
+
+
+struct STRUCT_MADGE_INIT_PARMS_HEADER
+ {
+ WORD length; /* byte length of parms */
+ WORD signature; /* parms specific */
+ WORD reserved; /* must be 0 */
+ WORD version; /* parms specific */
+ };
+
+
+/****************************************************************************/
+/* */
+/* Structure type : SMART_INIT_PARMS */
+/* */
+/* This structure contains general MAC level parameters for when */
+/* downloading any Madge smart software. */
+/* */
+/* REFERENCE : The Madge Smart SRB Interface */
+/* - Bring-Up and Initialization */
+/* */
+
+struct STRUCT_SMART_INIT_PARMS
+ {
+
+ MADGE_INIT_PARMS_HEADER header;
+
+ WORD reserved_1; /* must be 0 */
+ NODE_ADDRESS permanent_address; /* BIA PROM node address */
+ WORD rx_tx_buffer_size; /* 0 => default 1K-8 bytes */
+ DWORD reserved_2; /* must be 0 */
+ WORD dma_buffer_size; /* 0 => no limit */
+ WORD max_buffer_ram; /* 0 => default 2MB */
+ WORD min_buffer_ram; /* 0 => default 10K */
+ WORD sif_burst_size; /* 0 => no limit */
+ };
+
+
+/****************************************************************************/
+/* */
+/* Values : SMART_INIT_PARMS - header. WORD signature, WORD version */
+/* */
+/* The values for the header of the general smart software MAC level */
+/* paramters strcture. */
+/* */
+
+#define SMART_INIT_HEADER_SIGNATURE 0x0007
+#define SMART_INIT_HEADER_VERSION 0x0101
+#ifdef FMPLUS
+#define SMART_INIT_MIN_RAM_DEFAULT 0x0002
+#endif
+
+/****************************************************************************/
+/* */
+/* Structure type : SMART_FASTMAC_INIT_PARMS */
+/* */
+/* The Fastmac initialization parameters as specified in the Fastmac */
+/* documentation. */
+/* */
+/* REFERENCE : The Madge Fastmac Interface Specification */
+/* - Initialization */
+/* */
+
+
+struct STRUCT_FASTMAC_INIT_PARMS
+ {
+
+ MADGE_INIT_PARMS_HEADER header;
+
+ WORD feature_flags;
+ WORD int_flags;
+
+ WORD open_options; /* only for auto_open */
+ NODE_ADDRESS open_address; /* only for auto_open */
+ DWORD group_address; /* only for auto_open */
+ DWORD functional_address; /* only for auto_open */
+
+ DWORD rx_buf_physaddr; /* set to zero for FMPlus */
+ WORD rx_buf_size; /* (see rx_bufs/rx_slots) */
+ WORD rx_buf_space;
+
+ DWORD tx_buf_physaddr; /* set to zero for FMPlus */
+ WORD tx_buf_size; /* (see tx_bufs/tx_slots) */
+ WORD tx_buf_space;
+
+ WORD max_frame_size; /* for both rx and tx */
+ WORD size_rxdesc_queue; /* set to zero for FMPlus */
+ WORD max_rx_dma; /* set to zero for FMPlus */
+
+ WORD group_root_address; /* only for auto_open */
+#ifdef FMPLUS
+ WORD rx_bufs; /* # of internel rx buffers */
+ WORD tx_bufs; /* # of internal tx buffers */
+ WORD rx_slots; /* # of host rx buffers */
+ WORD tx_slots; /* # of host tx buffers */
+ WORD tx_ahead; /* Leave as zero */
+#endif
+ };
+
+
+/****************************************************************************/
+/* */
+/* Values : FASTMAC_INIT_PARMS - header. WORD signature, WORD version */
+/* */
+/* The values for the header of the Fastmac specific initialization */
+/* parameter block. */
+/* */
+
+#ifdef FMPLUS
+#define FMPLUS_INIT_HEADER_SIGNATURE 0x000E
+#define FMPLUS_INIT_HEADER_VERSION 0x0200 /* NOT Fastmac version! */
+#else
+#define FASTMAC_INIT_HEADER_SIGNATURE 0x0005
+#define FASTMAC_INIT_HEADER_VERSION 0x0405 /* NOT Fastmac version! */
+#endif
+
+/****************************************************************************/
+/* */
+/* Values : FASTMAC_INIT_PARMS - WORD feature_flags */
+/* */
+/* The feature flag bit signifcant values as described in the Fastmac */
+/* specification document. */
+/* */
+/* REFERENCE : The Madge Fastmac Interface Specification */
+/* - Initialization */
+/* */
+
+#define FEATURE_FLAG_AUTO_OPEN 0x0001
+#define FEATURE_FLAG_NOVELL 0x0002
+#define FEATURE_FLAG_SELL_BY_DATE 0x0004
+#define FEATURE_FLAG_PASS_RX_CRC 0x0008
+#define FEATURE_FLAG_WATCHDOG_TIMER 0x0020
+#define FEATURE_FLAG_DISCARD_BEACON_TX 0x0040
+#define FEATURE_FLAG_TRUNCATE_DMA 0x0080
+#define FEATURE_FLAG_DELAY_RX 0x0100
+#define FEATURE_FLAG_ONE_INT_PER_RX 0x0200
+#define FEATURE_FLAG_NEW_INIT_BLOCK 0x0400
+#define FEATURE_FLAG_AUTO_OPEN_ON_OPEN 0x0800
+#define FEATURE_FLAG_DISABLE_TX_FAIRNES 0x1000
+#ifdef FMPLUS
+#define FEATURE_FLAG_FMPLUS_ALWAYS_SET 0x0000
+#endif
+
+/* Yes, the FMPLUS_ALWAYS_SET bit is ZERO, because in fact it must NOT */
+/* always be set! This is an unfortunate historical legacy... */
+
+
+/****************************************************************************/
+/* */
+/* Values : FASTMAC_INIT_PARMS - WORD int_flags */
+/* */
+/* The interrupt flag bit significant values as described in the Fastmac */
+/* Plus specification document. */
+/* */
+/* REFERENCE : The Madge Fastmac Plus Programming Specification */
+/* - Initialization : TMS Load Parms */
+/* */
+
+#define INT_FLAG_TX_BUF_EMPTY 0x0001
+#define INT_FLAG_TIMER_TICK_ARB 0x0002
+#define INT_FLAG_RING_STATUS_ARB 0x0004
+#ifdef FMPLUS
+#define INT_FLAG_LARGE_DMA 0x0008
+#define INT_FLAG_RX 0x0010
+#endif
+
+#ifdef FMPLUS
+/****************************************************************************/
+/* */
+/* Values : Magic Fastmac Plus numbers to do with buffers on the adapter */
+/* */
+/* The size of buffers on the adapter card can be set with in the init. */
+/* block with the rx_tx_buffer_size field. The minimum value and default */
+/* values are specified here. Also, there are numbers giving the amount of */
+/* memory (in bytes) available for buffers on adapter cards of various RAM */
+/* sizes. */
+/* */
+/* REFERENCE : The Madge Fastmac Plus Programming Specification */
+/* - Initialization : SMTMAC Load Parms */
+/* */
+
+#define FMPLUS_MIN_TXRX_BUFF_SIZE 97
+
+#define FMPLUS_DEFAULT_BUFF_SIZE_SMALL 504 /* For EISA/MC32 cards */
+#define FMPLUS_DEFAULT_BUFF_SIZE_LARGE 1016 /* For all other cards */
+
+#define FMPLUS_MAX_BUFFMEM_IN_128K 63056 /* Bytes available for buffs*/
+#define FMPLUS_MAX_BUFFMEM_IN_256K 193104 /* on cards of 128K,256K, & */
+#define FMPLUS_MAX_BUFFMEM_IN_512K 453200 /* 512K RAM. */
+#endif
+
+/****************************************************************************/
+/* */
+/* Structure type : INITIALIZATION_BLOCK */
+/* */
+/* The initialization block consists of 3 parts - 22 bytes of TI */
+/* intialization parameters, general smart software MAC level parameters, */
+/* and the Fastmac specific parameters. */
+/* */
+
+struct STRUCT_INITIALIZATION_BLOCK
+ {
+ TI_INIT_PARMS ti_parms;
+ SMART_INIT_PARMS smart_parms;
+ FASTMAC_INIT_PARMS fastmac_parms;
+ };
+
+
+#pragma pack()
+
+/* */
+/* */
+/************** End of FTK_INIT.H file **************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_def/ftk_macr.h b/private/ntos/ndis/madge/driver/head_def/ftk_macr.h
new file mode 100644
index 000000000..d8bf16bec
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_def/ftk_macr.h
@@ -0,0 +1,157 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE MACRO DEFINITIONS */
+/* ===================== */
+/* */
+/* FTK_MACR.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* Developed by MF */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* This header file contains the macros that are used within the FTK. All */
+/* macros are included here for convenience, even though some are only used */
+/* in a single module. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this FTK_MACR.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_FTK_MACR_H 221
+
+
+/****************************************************************************/
+/* */
+/* The macro_dword_align macro is used in DRV_TX.C to align Fastmac buffer */
+/* pointers on DWORD boundaries. */
+/* */
+
+#define macro_dword_align(p) (((p) + 0x0003) & 0xFFFC)
+
+
+/****************************************************************************/
+/* */
+/* The macro_word_swap_dword macro is used in DRV_INIT.C, DRV_SRB.C and */
+/* HWI_GEN.C to swap the WORDs within a DWORD in preparation for */
+/* downloading of the DWORD on to the adapter. */
+/* */
+
+#define macro_word_swap_dword(dw) dw = ((dw << 16) | (dw >> 16))
+
+
+/****************************************************************************/
+/* */
+/* The macro_byte_swap_word macro is used in DRV_RX.C and DRV_TX.C to swap */
+/* the BYTEs within a WORD because the length field in a Fastmac buffer is */
+/* in TMS ordering. */
+/* */
+
+#define macro_byte_swap_word(w) (((w) << 8) | ((w) >> 8))
+
+
+/****************************************************************************/
+/* */
+/* The macro_set<w/b>_bit macros are used in HWI_<card_type>.C to set */
+/* specific bits in control and other IO registers without affecting the */
+/* value of any other bits. */
+/* */
+/* The macro_setb_bit macro is for byte-size registers; the macro_setw_bit */
+/* macro is for word-size registers. */
+/* */
+
+#define macro_probe_setb_bit(io, b) \
+ sys_probe_outsb(io, (BYTE) (sys_probe_insb(io) | (b)))
+#define macro_setb_bit(hnd, io, b) \
+ sys_outsb( hnd, io, (BYTE) (sys_insb(hnd, io) | (b)))
+#define macro_setw_bit(hnd, io, b) \
+ sys_outsw( hnd, io, (WORD) (sys_insw(hnd, io) | (b)))
+
+
+/****************************************************************************/
+/* */
+/* The macro_clear<w/b>_bit macros are used in HWI_<card_type>.C to clear */
+/* specific bits in control and other IO registers without affecting the */
+/* value of any other bits. */
+/* */
+/* The macro_clearb_bit macro is for byte-size registers; the */
+/* macro_clearw_bit macro is for word-size registers. */
+/* */
+
+#define macro_probe_clearb_bit(io, b) \
+ sys_probe_outsb(io, (BYTE) (sys_probe_insb(io) & ~(b)))
+#define macro_clearb_bit(hnd, io, b) \
+ sys_outsb( hnd, io, (BYTE) (sys_insb(hnd, io) & ~(b)))
+#define macro_clearw_bit(hnd, io, b) \
+ sys_outsw( hnd, io, (WORD) (sys_insw(hnd, io) & ~(b)))
+
+
+/****************************************************************************/
+/* */
+/* The macro_fatal_error macro is used in DRV_ERR.C to distinguish fatal */
+/* from non-fatal errors. Fatal errors cause an adapter to no longer be */
+/* usable. */
+/* */
+
+#define macro_fatal_error(err) \
+ \
+ ( (err == ERROR_TYPE_HWI) || \
+ (err == ERROR_TYPE_DRIVER) || \
+ (err == ERROR_TYPE_INIT) || \
+ (err == ERROR_TYPE_BRING_UP) || \
+ (err == ERROR_TYPE_AUTO_OPEN) || \
+ (err == ERROR_TYPE_ADAPTER) )
+
+
+/****************************************************************************/
+/* */
+/* The macro_get_next_record macro is used in HWI_GEN.C to adjust a */
+/* pointer such that it points to the next download record in a list of */
+/* such records. */
+/* */
+
+#define macro_get_next_record(p) \
+ \
+ p = (DOWNLOAD_RECORD *) (((BYTE *) p) + p->length)
+
+
+/****************************************************************************/
+/* */
+/* The macro_enable_io and macro_disable_io macros are used throughout the */
+/* FTK for enabling/disabling access to specific IO locations. This is */
+/* required under certain operating systems, and the macros are implemented */
+/* by calls to system specific routines. */
+/* */
+/* Note on increasing speed: */
+/* */
+/* The reason for the macros is so that for systems where enabling and */
+/* disabling of IO locations is not required, the macros can just be */
+/* replaced by null code and there is no overhead of calling a system */
+/* routine that does nothing. */
+/* */
+
+#define macro_enable_io(adap) \
+ sys_enable_io((adap)->io_location, (adap)->io_range)
+
+#define macro_disable_io(adap) \
+ sys_disable_io((adap)->io_location, (adap)->io_range)
+
+#define macro_probe_enable_io(io_loc, io_range) \
+ sys_enable_io(io_loc, io_range)
+
+#define macro_probe_disable_io(io_loc, io_range) \
+ sys_disable_io(io_loc, io_range)
+
+
+
+/* */
+/* */
+/************** End of FTK_MACR.H file **************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_def/ftk_mc.h b/private/ntos/ndis/madge/driver/head_def/ftk_mc.h
new file mode 100644
index 000000000..07807d4e4
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_def/ftk_mc.h
@@ -0,0 +1,195 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE MADGE ADAPTER CARD DEFINITIONS (MICROCHANNEL CARDS) */
+/* ======================================================= */
+/* */
+/* FTK_MC.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* Developed by MF */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* This header file contains the definitions for programming Madge MC */
+/* adapter cards. Each adapter card has a number of control and status */
+/* registers. ALL bits in ALL registers are defined by Madge Networks Ltd, */
+/* however only a restricted number are defined below as used within the */
+/* FTK. All other bits must NOT be changed and no support will be offered */
+/* for any application that does so or uses the defined bits in any way */
+/* different to the FTK. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this FTK_MC.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_FTK_MC_H 221
+
+
+/****************************************************************************/
+/* */
+/* Values : MC REGISTER MAP */
+/* */
+/* Madge MC cards have the following register map. By setting certain bits */
+/* in the control registers it is possible to page in the BIA PROM (page 0 */
+/* or page 1) or the EAGLE SIF registers (normal or extended). */
+/* */
+/* NB. There is a lot of similarity between the MC and ATULA register maps. */
+/* */
+
+#define MC_IO_RANGE 16
+
+#define MC_CONTROL_REGISTER_0 0
+#define MC_CONTROL_REGISTER_1 1
+#define MC_POS_REGISTER_0 2
+#define MC_POS_REGISTER_1 3
+#define MC_POS_REGISTER_2 4
+#define MC_CONTROL_REGISTER_7 7
+
+#define MC_FIRST_SIF_REGISTER 8
+
+#define MC_BIA_PROM 8
+
+
+/****************************************************************************/
+/* */
+/* Values : MC CONTROL_REGISTER_0 */
+/* */
+/* These are the bit definitions for control register 0 on MC cards. */
+/* */
+/* NB. The bit definitions are mostly the same as ATULA CONTROL_REGISTER_7. */
+/* */
+
+#define MC_CTRL0_SIFSEL ((BYTE) 0x04) /* page in BIA PROM or SIF regs */
+#define MC_CTRL0_PAGE ((BYTE) 0x08) /* pages BIA PROM or EEPROM */
+#define MC_CTRL0_SINTR ((BYTE) 0x40) /* SIF interrupt pending */
+
+
+/****************************************************************************/
+/* */
+/* Values : MC CONTROL_REGISTER_1 */
+/* */
+/* These are the bit definitions for control register 1 on MC cards. */
+/* */
+/* NB. The bit definitions are mostly the same as ATULA CONTROL_REGISTER_1. */
+/* */
+
+#define MC_CTRL1_SINTREN ((BYTE) 0x01) /* SIF interrupt enable */
+#define MC_CTRL1_NSRESET ((BYTE) 0x04) /* active low SIF reset */
+#define MC_CTRL1_SRSX ((BYTE) 0x40) /* SIF extended register select */
+#define MC_CTRL1_16N4 ((BYTE) 0x80) /* ring speed select */
+
+
+/****************************************************************************/
+/* */
+/* Values : MC POS_REGISTER_0 */
+/* */
+/* These are the bit definitions for POS register 0 on MC cards. */
+/* */
+
+#define MC_POS0_CDEN ((BYTE) 0x01) /* card enabled */
+#define MC_POS0_DMAS ((BYTE) 0x1E) /* arbitration level (4 bits) */
+#define MC_POS0_IRQSEL ((BYTE) 0xC0) /* interrupt (2 bits encoded) */
+
+
+/****************************************************************************/
+/* */
+/* Values : MC POS_REGISTER_1 */
+/* */
+/* These are the bit definitions for POS register 1 on MC cards. */
+/* */
+
+#define MC_POS1_NOSPD ((BYTE) 0x04) /* any speed selected */
+#define MC_POS1_STYPE6 ((BYTE) 0x40) /* 16/4 MC media type */
+#define MC32_POS1_STYPE6 ((BYTE) 0x01) /* 16/4 MC 32 media type */
+
+
+/****************************************************************************/
+/* */
+/* Values : MC POS_REGISTER_2 */
+/* */
+/* These are the bit definitions for POS register 2 on MC cards. The */
+/* streaming bit is only applicable to 16/4 MC 32 cards. */
+/* */
+
+#define MC_POS2_FAIRNESS ((BYTE) 0x10) /* fair bus arbitration */
+#define MC_POS2_16N4 ((BYTE) 0x20) /* ring speed select */
+#define MC_POS2_STREAMING ((BYTE) 0x40) /* use streaming DMA */
+
+
+/****************************************************************************/
+/* */
+/* Values : MC CONTROL_REGISTER_7 */
+/* */
+/* These are the bit definitions for control register 7 on MC cards. */
+/* */
+
+#define MC_CTRL7_STYPE3 ((BYTE) 0x01) /* media type select */
+
+
+/****************************************************************************/
+/* */
+/* Values : IRQ SELECT IN MC POS_REGISTER_0 */
+/* */
+/* The two interrupt select bits in POS register 0 (MC_POS0_IRQSEL) */
+/* represent the interrupt number the card is on. */
+/* */
+
+#define MC_POS0_IRSEL_IRQ3 ((BYTE) 0x40) /* interrupt 3 encoding */
+#define MC_POS0_IRSEL_IRQ9 ((BYTE) 0x80) /* interrupt 9 encoding */
+#define MC_POS0_IRSEL_IRQ10 ((BYTE) 0xC0) /* interrupt 10 encoding */
+
+
+/****************************************************************************/
+/* */
+/* Values : MC EXTENDED EAGLE SIF REGISTERS */
+/* */
+/* The EAGLE SIF registers are in two groups - the normal SIF registers */
+/* (those from the old TI chipset) and the extended SIF registers (those */
+/* particular to the EAGLE). For Madge MC adapter cards, with CTRL0_SIFSEL */
+/* = 1 and CTRL1_NRESET = 1, having CTRL1_SRSX = 0 selects the normal SIF */
+/* registers and having CTRL1_SRSX = 1 selects the extended SIF registers. */
+/* */
+/* The definitions for the normal SIF registers are in FTK_CARD.H because */
+/* they appear in the same relative IO locations for all adapter cards. The */
+/* extended SIF registers are here because they appear at different */
+/* relative IO locations for different types of adapter cards. For ATULA */
+/* and MC cards they are in fact identical. */
+/* */
+
+#define MC_EAGLE_SIFACL 0 /* adapter control */
+#define MC_EAGLE_SIFADR_2 2 /* copy of SIFADR */
+#define MC_EAGLE_SIFADX 4 /* DIO address (high) */
+#define MC_EAGLE_DMALEN 6 /* DMA length */
+
+/****************************************************************************/
+/* */
+/* Values : ADAPTER - BYTE mc32_config */
+/* */
+/* The adapter structure field mc32_config is made up of streaming, */
+/* fairness and arbitration level information as follows : */
+/* */
+/* bits 0-3 MC_POS0_DMAS */
+/* bit 4 MC_POS2_FAIRNESS */
+/* bit 5 MC_POS2_STREAMING */
+/* */
+/* The POS register fields need to be shifted into the correct bit */
+/* positions for the mc32_config byte. The right shift values are given */
+/* below. */
+/* */
+
+#define MC32_CONFIG_DMA_SHIFT ((BYTE) 1)
+#define MC32_CONFIG_FAIRNESS_SHIFT ((BYTE) 0)
+#define MC32_CONFIG_STREAMING_SHIFT ((BYTE) 1)
+
+
+/* */
+/* */
+/************** End of FTK_MC.H file ****************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_def/ftk_pci.h b/private/ntos/ndis/madge/driver/head_def/ftk_pci.h
new file mode 100644
index 000000000..6c6a63ea6
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_def/ftk_pci.h
@@ -0,0 +1,150 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE MADGE ADAPTER CARD DEFINITIONS (PCI CARDS) */
+/* =================================================== */
+/* */
+/* FTK_PCI.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1994 */
+/* Developed by PRR */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* This header file contains the definitions for programming Madge Smart */
+/* 16/4 PCI */
+/* adapter cards. These adapter cards have a couple of control registers, */
+/* in addition to the SIF registers. ALL bits in ALL control registers are */
+/* defined by Madge Networks Ltd */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this FTK_PCI.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_FTK_PCI_H 221
+
+
+/****************************************************************************/
+/* */
+/* Values : PCI REGISTER MAP */
+/* */
+/* The Madge PCI Ringnode uses the following register layout. */
+/* N.B. The SIF registers are mapped linearly, with no overlaying. */
+/* */
+
+#define PCI_GENERAL_CONTROL_REG 0
+#define PCI_INT_MASK_REG 4
+#define PCI_SEEPROM_CONTROL_REG 8
+#define PCI_FIRST_SIF_REGISTER 0x20
+
+#define PCI_IO_RANGE 256
+
+#define PCI1_SRESET 1 /* Bit 0 of General Control Register */
+#define PCI1_RSPEED_4MBPS 0x200 /* Bit 9 of General Control Register */
+#define PCI1_RSPEED_VALID 0x400 /* Bit 10 of General Control Register */
+
+#define PCI1_BIA_CLK 0x0001 /* Bit 0 of SEEPROM control word. */
+#define PCI1_BIA_DOUT 0x0002 /* Bit 1 of SEEPROM control word. */
+#define PCI1_BIA_ENA 0x0004 /* Bit 2 of SEEPROM control word. */
+#define PCI1_BIA_DIN 0x0008 /* Bit 3 of SEEPROM control word. */
+
+#define PCI1_ENABLE_MMIO 0x0080 /* MC32 config value to enable MMIO. */
+
+
+/****************************************************************************/
+/* */
+/* Values : AT93C46 Serial EEPROM control valuse */
+/* */
+
+#define PCI_C46_START_BIT 0x8000
+#define PCI_C46_READ_CMD 0x4000
+#define PCI_C46_ADDR_MASK 0x003f
+#define PCI_C46_ADDR_SHIFT 7
+#define PCI_C46_CMD_LENGTH 9
+
+
+/****************************************************************************/
+/* */
+/* Values : PCI SIF REGISTERS */
+/* */
+/* The EAGLE SIF registers are in two groups - the normal SIF registers */
+/* (those from the old TI chipset) and the extended SIF registers (those */
+/* particular to the EAGLE). */
+/* */
+/* The definitions for the normal SIF registers are here because they */
+/* appear in the same relative IO locations for all adapter cards. */
+/* */
+
+#define PCI_SIFDAT 0 /* DIO data */
+#define PCI_SIFDAT_INC 4 /* DIO data auto-increment */
+#define PCI_SIFADR 8 /* DIO address (low) */
+#define PCI_SIFINT 12 /* interrupt SIFCMD-SIFSTS */
+
+/* These definitions are for the case when the SIF registers are mapped */
+/* linearly. Otherwise, they will be at some extended location. */
+
+#define PCI_SIFACL 16
+#define PCI_SIFADX 24
+
+/* These definitions are for Eagle Pseudo DMA. Notice that they replace the */
+/* registers above - this is controlled by SIFACL. */
+
+#define PCI_SDMADAT 0
+#define PCI_DMALEN 4
+#define PCI_SDMAADR 8
+#define PCI_SDMAADX 12
+
+
+/****************************************************************************/
+/* */
+/* Value : Number of IO locations for SIF registers */
+/* */
+/* The number of SIF registers is only needed for enabling and disabling */
+/* ranges of IO ports. For the ATULA and MC cards the SIF registers are in */
+/* 2 pages only using 8 IO ports. However, for EISA cards, the SIF */
+/* registers are in a single page of 16 IO ports. Hence, 16 IO ports need */
+/* to be enabled whenever accessing SIF registers. */
+/* */
+
+#define PCI_SIF_IO_RANGE 32
+
+/****************************************************************************/
+/* */
+/* Values : Locations of data in the serial EEPROM (in words) */
+/* */
+/* */
+
+#define PCI_EEPROM_BIA_WORD0 0
+#define PCI_EEPROM_BIA_WORD1 1
+#define PCI_EEPROM_BIA_WORD2 2
+#define PCI_EEPROM_RING_SPEED 3
+#define PCI_EEPROM_RAM_SIZE 4
+
+
+
+/* */
+/* For some perverted reason it is not possible to read these bits back */
+/* from the SEEPROM control register once they have been written. */
+/* */
+
+#define BITS_TO_REMEMBER (PCI1_BIA_ENA | PCI1_BIA_DOUT | PCI1_BIA_CLK)
+
+/****************************************************************************/
+/* */
+/* Values : Ring speed values stored in the serial EEPROM */
+/* */
+/* */
+
+#define PCI_EEPROM_4MBS 1
+#define PCI_EEPROM_16MBPS 0
+
+/* */
+/* */
+/************** End of FTK_PCI.H file ***************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_def/ftk_pci2.h b/private/ntos/ndis/madge/driver/head_def/ftk_pci2.h
new file mode 100644
index 000000000..4d488bd35
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_def/ftk_pci2.h
@@ -0,0 +1,122 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE MADGE ADAPTER CARD DEFINITIONS (PCI CARDS) */
+/* =================================================== */
+/* */
+/* FTK_PCI2.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1994 */
+/* Developed by PRR */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* This header file contains the definitions for programming Madge Smart */
+/* 16/4 PCI (BM) adapter cards, ie based on the Madge bus interface ASIC. */
+/* */
+/* The SIF registers are WORD aligned and start at offset 0x10 from the IO */
+/* space */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this FTK_PCI.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_FTK_PCI_H 221
+
+/***************************************************************************/
+/* */
+/* PCI-2 IO Map */
+/* Offsets of register locations are from the start of the card's IO space.*/
+/* */
+
+#define PCI2_INTERRUPT_STATUS 0x01 /* One byte. */
+#define PCI2_DMAING 0x01 /* Bit 0 - Dma in progress */
+#define PCI2_SINTR 0x02 /* Bit 1 - SIF int */
+#define PCI2_SWINT 0x04 /* Bit 2 - Software int */
+#define PCI2_PCI_INT 0x80 /* Bit 8 - Catastrophic error */
+
+#define PCI2_INTERRUPT_CONTROL 0x02 /* One byte. */
+#define PCI2_SINTEN 0x02 /* Bit 1 - SIF int enable */
+#define PCI2_SWINTEN 0x04 /* Bit 2 - S/w int enable */
+#define PCI2_PCI_ERR_EN 0x80 /* Bit 9 - Catastrophic err en */
+
+#define PCI2_RESET 0x04 /* One byte. */
+#define PCI2_CHIP_NRES 0x01 /* Bit 0 - Reset chip if zero */
+#define PCI2_FIFO_NRES 0x02 /* Bit 2 - Fifo reset if zero */
+#define PCI2_SIF_NRES 0x04 /* Bit 3 - SIF reset if zero */
+
+#define PCI2_SEEPROM_CONTROL 0x07 /* One byte. */
+#define PCI2_SEESK 0x01 /* Bit 0 - Clock */
+#define PCI2_SEED 0x02 /* Bit 1 - Data */
+#define PCI2_SEEOE 0x04 /* Bit 2 - Output enable */
+
+#define PCI2_EEPROM_CONTROL 0x08 /* Dword - Low 19 bits are addr */
+#define PCI2_AUTOINC 0x80000000 /* Bit 31 - Does addr autoinc */
+
+#define PCI2_EEPROM_DATA 0x0C /* One byte. */
+
+#define PCI2_SIF_OFFSET 0x10
+
+/* Locations 0x22 onwards are for ASIC debugging only */
+#define PCI2_IO_RANGE 0x36
+
+
+
+/****************************************************************************/
+/* */
+/* Bits for programming the EEPROM */
+/* */
+/* */
+#define AT24_IO_CLOCK 1
+#define AT24_IO_DATA 2
+#define AT24_IO_ENABLE 4
+
+/****************************************************************************/
+/* */
+/* Usefule locations in the EEPROM */
+/* */
+/* */
+#define PCI2_EEPROM_BIA_WORD0 9
+#define PCI2_EEPROM_BIA_WORD1 10
+#define PCI2_EEPROM_BIA_WORD2 11
+#define PCI2_EEPROM_RING_SPEED 12
+#define PCI2_EEPROM_RAM_SIZE 13
+#define PCI2_HWF1 14
+#define PCI2_HWF2 15
+
+
+/****************************************************************************/
+/* */
+/* Useful values in the EEPROM */
+/* */
+#define PCI2_EEPROM_4MBITS 1
+#define PCI2_EEPROM_16MBITS 0
+
+
+#define PCI2_BUS_MASTER_ONLY 4
+#define PCI2_HW2_431_READY 0x10
+
+
+/****************************************************************************/
+/* */
+/* Useful locations in the PCI config space */
+/* */
+/* */
+#define PCI_CONFIG_COMMAND 0x4
+
+/****************************************************************************/
+/* */
+/* The BUS Master DMA Enable bit in the CONFIG_COMMAND register */
+#define PCI_CONFIG_BUS_MASTER_ENABLE 0x4
+
+
+/* */
+/* */
+/************** End of FTK_PCI.H file ***************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_def/ftk_pcit.h b/private/ntos/ndis/madge/driver/head_def/ftk_pcit.h
new file mode 100644
index 000000000..9822c09ce
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_def/ftk_pcit.h
@@ -0,0 +1,109 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE MADGE ADAPTER CARD DEFINITIONS (PCI CARDS) */
+/* =================================================== */
+/* */
+/* FTK_PCIT.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1994 */
+/* Developed by PRR */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* This header file contains the definitions for programming Madge Smart */
+/* 16/4 PCI (T) adapter cards, ie based on the Ti PCI bus interface ASIC */
+/* The only IO registers are the SIF registers, all other control is */
+/* through PCI config space */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this FTK_PCI.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_FTK_PCI_H 221
+
+
+/****************************************************************************/
+/* */
+/* Values : PCI REGISTER MAP */
+/* */
+/* The Madge PCI Ringnode uses the following register layout. */
+/* N.B. The SIF registers are mapped linearly, with no overlaying. */
+/* */
+#define PCIT_HANDSHAKE 0x100C
+#define PCIT_HANDSHAKE 0x100C
+
+
+/****************************************************************************/
+/* */
+/* Useful locations in the PCI config space */
+/* */
+/* */
+#define EEPROM_OFFSET 0x48
+#define MISC_CONT_REG 0x40
+#define PCI_CONFIG_COMMAND 0x4
+#define CACHE_LINE_SIZE 0xC
+
+/****************************************************************************/
+/* */
+/* The BUS Master DMA Enable bit in the CONFIG_COMMAND register */
+#define PCI_CONFIG_BUS_MASTER_ENABLE 0x4
+#define PCI_CONFIG_IO_ENABLE 0x2
+#define PCI_CONFIG_MEM_ENABLE 0x1
+
+/****************************************************************************/
+/* */
+/* Bits for programming the EEPROM */
+/* */
+/* */
+#define AT24_IO_CLOCK 1
+#define AT24_IO_DATA 2
+#define AT24_IO_ENABLE 4
+
+/****************************************************************************/
+/* */
+/* EEPROM commands */
+/* */
+#define AT24_WRITE_CMD 0xA0
+#define AT24_READ_CMD 0xA1
+
+/****************************************************************************/
+/* */
+/* Useful locations in the EEPROM */
+/* */
+/* */
+
+#define PCIT_EEPROM_BIA_WORD0 9
+#define PCIT_EEPROM_BIA_WORD1 10
+#define PCIT_EEPROM_BIA_WORD2 11
+#define PCIT_EEPROM_RING_SPEED 12
+#define PCIT_EEPROM_RAM_SIZE 13
+#define PCIT_EEPROM_HWF2 15
+
+#define NSEL_4MBITS 3
+#define NSEL_16MBITS 1
+
+/****************************************************************************/
+/* */
+/* Values in the EEPROM */
+/* */
+#define PCIT_EEPROM_4MBITS 1
+#define PCIT_EEPROM_16MBITS 0
+
+#define PCIT_BROKEN_DMA 0x20
+
+/*
+* Value passed to the adapter in the mc32 byte to tell it to use the FMPLUS
+* code which supports broken DMA.
+*/
+#define TRN_PCIT_BROKEN_DMA 0x200
+
+/* */
+/* */
+/************** End of FTK_PCI.H file ***************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_def/ftk_pcmc.h b/private/ntos/ndis/madge/driver/head_def/ftk_pcmc.h
new file mode 100644
index 000000000..b229657ae
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_def/ftk_pcmc.h
@@ -0,0 +1,256 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE MADGE ADAPTER CARD DEFINITIONS (PCMCIA CARDS) */
+/* ================================================= */
+/* */
+/* FTK_PCMC.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* Developed by VL */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* This header file contains the definitions for programming Madge PCMCIA */
+/* adapter cards. Each adapter card has a number of control and status */
+/* registers. ALL bits in ALL registers are defined by Madge Networks Ltd, */
+/* however only a restricted number are defined below as used within the */
+/* FTK. All other bits must NOT be changed and no support will be offered */
+/* for any application that does so or uses the defined bits in any way */
+/* different to the FTK. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this FTK_PCMC.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_FTK_PCMC_H 221
+
+
+/****************************************************************************/
+/* */
+/* Values : PCMCIA REGISTER MAP */
+/* */
+/* Madge PCMCIA cards have the following register map. All SIF registers */
+/* are always visible. */
+/* */
+
+#define PCMCIA_IO_RANGE 32
+
+#define PCMCIA_CONTROL_REGISTER_1 0x0000
+#define PCMCIA_CONTROL_REGISTER_2 0x0002
+
+#define PCMCIA_PIO_IO_LOC 0x0008
+
+#define PCMCIA_FIRST_SIF_REGISTER 0x0010
+
+
+/****************************************************************************/
+/* */
+/* Values : PCMCIA_CONTROL_REGISTER_1 */
+/* */
+/* These are bit definitions for control register 1 on PCMCIA adapters. */
+/* */
+
+#define PCMCIA_CTRL1_SINTREN ((BYTE) 0x01) /* SIF interrupt enable */
+#define PCMCIA_CTRL1_SRESET ((BYTE) 0x02) /* EAGLE SIF reset */
+#define PCMCIA_CTRL1_CISDIS ((BYTE) 0x04) /* CIS ROM / extern EEPROM */
+#define PCMCIA_CTRL1_SHLDA ((BYTE) 0x40) /* SHLDA pin status (PIO) */
+#define PCMCIA_CTRL1_SHRQ ((BYTE) 0x80) /* SHRQ pin status (PIO) */
+
+
+/****************************************************************************/
+/* */
+/* Values : PCMCIA_CONTROL_REGISTER_2 */
+/* */
+/* These are bit definitions for control register 2 on PCMCIA adapters. */
+/* */
+
+#define PCMCIA_CTRL2_SBCKSEL ((BYTE) 0x03) /* SIF clock frequency */
+#define PCMCIA_CTRL2_4N16 ((BYTE) 0x04) /* Ring speed 4/16 */
+#define PCMCIA_CTRL2_FLSHWREN ((BYTE) 0x08) /* EEPROM write enable */
+#define PCMCIA_CTRL2_E2SK ((BYTE) 0x10) /* SK (sync clk) pin of EEPROM */
+#define PCMCIA_CTRL2_E2CS ((BYTE) 0x20) /* CS (chip sel) pin of EEPROM */
+#define PCMCIA_CTRL2_E2DI ((BYTE) 0x40) /* DI (data in) pin of EEPROM */
+#define PCMCIA_CTRL2_E2DO ((BYTE) 0x80) /* Output statue of EEPROm */
+
+#define PCMCIA_CTRL2_4N16_4 ((BYTE) 0x04) /* ringspeed = 4MB/s */
+#define PCMCIA_CTRL2_4N16_16 ((BYTE) 0x00) /* ringspeed = 16MB/s */
+
+#define PCMCIA_CTRL2_SBCKSEL_2 ((BYTE) 0x00) /* sif clock frequency 2MHz */
+#define PCMCIA_CTRL2_SBCKSEL_8 ((BYTE) 0x01) /* sif clock frequency 8MHz */
+#define PCMCIA_CTRL2_SBCKSEL_16 ((BYTE) 0x02) /* sif clock frequency 16MHz */
+#define PCMCIA_CTRL2_SBCKSEL_32 ((BYTE) 0x03) /* sif clock frequency 32MHz */
+
+
+/****************************************************************************/
+/* */
+/* Values : PCMCIA EXTENDED EAGLE SIF REGISTERS */
+/* */
+/* The EAGLE SIF registers are in two groups - the normal SIF registers */
+/* (those from the old TI chipset) and the extended SIF registers (those */
+/* particular to the EAGLE). For Madge PCMCIA adapter cards, both normal */
+/* and extended SIF registers are always accessible. */
+/* */
+/* The definitions for the normal SIF registers are in FTK_CARD.H because */
+/* they appear in the same relative IO locations for all adapter cards. The */
+/* extended SIF registers are here because they appear at different */
+/* relative IO locations for different types of adapter cards. */
+/* */
+
+#define PCMCIA_EAGLE_SIFACL 8 /* adapter control */
+#define PCMCIA_EAGLE_SIFADR_2 10 /* copy of SIFADR */
+#define PCMCIA_EAGLE_SIFADX 12 /* DIO address (high) */
+#define PCMCIA_EAGLE_DMALEN 14 /* DMA length */
+
+
+/****************************************************************************/
+/* */
+/* Values : PCMCIA CARD CONFIGURATION REGISTER */
+/* */
+/* These are definition of PCMCIA card configuration register (CCR) which */
+/* are mapped into attribute memory space. They should only be accessed */
+/* through PCMCIA Card Services. */
+/* */
+
+#define PCMCIA_CONFIG_BASE 0x00000800 /* Offset from attribute memory space */
+
+/* SMART 16/4 PCMCIA ringnode only have Configuration Option Register and */
+/* Configuration Status Register. There are no Pin Register and Socket/Copy */
+/* Register. */
+
+#define PCMCIA_REGISTER_PRESENT RC_PRESENT_OPTION_REG | RC_PRESENT_STATUS_REG
+
+#define PCMCIA_OPTION_REG 0x00 /* configruation option register (COR) */
+#define PCMCIA_STATUS_REG 0x02 /* configuration status register (CSR) */
+
+
+/****************************************************************************/
+/* */
+/* Values : PCMCIA CARD CONFIGURATION OPTION REGISTER (COR) */
+/* */
+
+#define PCMCIA_COR_CNFGD_MASK ((BYTE) 0x3F) /* IO Config. Enable port */
+#define PCMCIA_COR_LEVLREQ ((BYTE) 0x40) /* Level/Edge IRQ mode select */
+#define PCMCIA_COR_SYSRESET ((BYTE) 0x80) /* soft reset (not sif reset) */
+
+
+/****************************************************************************/
+/* */
+/* Values : PCMCIA CARD CONFIGURATION STATUS REGISTER (CSR) */
+/* */
+
+#define PCMCIA_CSR_RSRVD2 ((BYTE) 0x01) /* Reserved */
+#define PCMCIA_CSR_INTR ((BYTE) 0x02) /* Interrupt request to host */
+#define PCMCIA_CSR_PWRDWN ((BYTE) 0x04) /* Power down bit. Not used */
+#define PCMCIA_CSR_AUDIO ((BYTE) 0x08) /* Audio. Not used */
+#define PCMCIA_CSR_RSRVD1 ((BYTE) 0x10) /* Reserved */
+#define PCMCIA_CSR_IOIS8 ((BYTE) 0x20) /* 8-bit/16-bit data path */
+#define PCMCIA_CSR_SIGCHG ((BYTE) 0x40) /* Status Change. Not used */
+#define PCMCIA_CSR_CHANGED ((BYTE) 0x80) /* Not used */
+
+
+/****************************************************************************/
+/* */
+/* Initial Setting of these register */
+/* */
+
+#define PCMCIA_STATUS_REG_SETTING ((BYTE) 0x00)
+#define PCMCIA_PIN_REG_SETTING ((BYTE) 0x00)
+#define PCMCIA_COPY_REG_SETTING ((BYTE) 0x00)
+#define PCMCIA_OPTION_REG_SETTING \
+ ( 0x01 & PCMCIA_COR_CNFGD_MASK ) | PCMCIA_COR_LEVLREQ
+
+
+/****************************************************************************/
+/* */
+/* Other Hardware specification related definitions */
+/* */
+
+
+/* */
+/* EEPROM */
+/* */
+
+#define C46_START_BIT 0x8000 /* start bit of command */
+#define C46_READ_CMD 0x4000 /* command to enable reading of EEPROM */
+#define C46_ADDR_MASK 0x003F /* Bottom 6 bits are the address */
+#define C46_ADDR_SHIFT 7 /* no. of bits to shift the address */
+#define C46_CMD_LENGTH 9 /* 1 start bit, 2 cmd bits, 6 adr bits */
+
+#define EEPROM_ADDR_NODEADDR1 0x0000 /* 1st word in EEPROM = Nodeaddress1 */
+#define EEPROM_ADDR_NODEADDR2 0x0001 /* 2nd word in EEPROM = Nodeaddress2 */
+#define EEPROM_ADDR_NODEADDR3 0x0002 /* 3rd word in EEPROM = Nodeaddress3 */
+#define EEPROM_ADDR_RINGSPEED 0x0003 /* 4th word in EEPROM = RingSpeed */
+#define EEPROM_ADDR_RAMSIZE 0x0004 /* 5th word in EEPROM = Ram size / 128 */
+#define EEPROM_ADDR_REVISION 0x0005 /* 6th word in EEPROM = Revsion */
+
+#define EEPROM_RINGSPEED_16 0x0000 /* The 4th word = 0 -> 16MB/s */
+#define EEPROM_RINGSPEED_4 0x0001 /* The 4th word = 1 -> 4MB/s */
+
+
+/* */
+/* Miscellaneous */
+/* */
+
+#define PCMCIA_RAM_SIZE 512 /* 512k RAM on adapter */
+
+#define PCMCIA_NUMBER_OF_ADDR_LINES 16 /* Number of address lines decoded */
+
+#define PCMCIA_VCC 50 /* Vcc in tenth of a volt */
+#define PCMCIA_VPP1 0 /* Vpp1 in tenth of a volt */
+#define PCMCIA_VPP2 0 /* Vpp2 in tenth of a volt */
+
+
+/****************************************************************************/
+/* */
+/* Madge Signature for tuple CISTPL_VERS_1 */
+/* */
+
+#define MADGE_TPLLV1_INFO_LEN 33 /* note that there is a '\0' in the string */
+ /* so strlen will not work. */
+
+ /* 123456 789012345678901234567890123 */
+
+#define MADGE_TPLLV1_INFO_STRING "MADGE\0SMART 16/4 PCMCIA RINGNODE"
+
+
+/****************************************************************************/
+/* */
+/* Data sturcture of tuple CISTPL_VERS_1 */
+/* */
+/* Note that CS Level 2.00 or below start with a byte of tpl_code and a */
+/* byte of tpl_link. They are removed in CS Level 2.01 */
+/* */
+
+struct STRUCT_CS200_CISTPL_VERS_1_DATA
+{
+ BYTE tpl_code;
+ BYTE tpl_link;
+ BYTE tpllv1_major;
+ BYTE tpllv1_minor;
+ BYTE info[MADGE_TPLLV1_INFO_LEN];
+ BYTE additional_info[1];
+};
+
+typedef struct STRUCT_CS200_CISTPL_VERS_1_DATA CS200_CISTPL_VERS_1_DATA;
+
+struct STRUCT_CS201_CISTPL_VERS_1_DATA
+{
+ BYTE tpllv1_major;
+ BYTE tpllv1_minor;
+ BYTE info[MADGE_TPLLV1_INFO_LEN];
+ BYTE additional_info[1];
+};
+
+typedef struct STRUCT_CS201_CISTPL_VERS_1_DATA CS201_CISTPL_VERS_1_DATA;
+
+/* */
+/* */
+/********************* End of FTK_PCMC.H file *****************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_def/ftk_pnp.h b/private/ntos/ndis/madge/driver/head_def/ftk_pnp.h
new file mode 100644
index 000000000..319a0c15d
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_def/ftk_pnp.h
@@ -0,0 +1,142 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE MADGE ADAPTER CARD DEFINITIONS (Plug aNd Play (PNP) CARDS) */
+/* ============================================================== */
+/* */
+/* FTK_PNP.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* Developed by AC */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* This header file contains the definitions for programming Madge PNP */
+/* adapter cards. These adapter cards have a couple of control registers, */
+/* in addition to the SIF registers. ALL bits in ALL control registers are */
+/* defined by Madge Networks Ltd */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this FTK_PNP.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_FTK_PNP_H 221
+
+
+/****************************************************************************/
+/* */
+/* Values : PNP REGISTER MAP */
+/* */
+/* The Madge Smart 16 Ringnode uses the following register layout. */
+/* N.B. The SIF registers are mapped linearly, with no overlaying. */
+/* */
+
+#define PNP_IO_RANGE 32
+
+#define PNP_CONTROL_REGISTER_1 3
+#define PNP_ID_REGISTER 8
+
+#define PNP_FIRST_SIF_REGISTER 16
+
+
+/****************************************************************************/
+/* */
+/* Values : PNP CONFIGURATION REGISTERS */
+/* */
+/* These are the bit definitions for the PnP configuration registers. */
+/* */
+
+#define PNP_CONFIG_ADDRESS_REGISTER 1
+#define PNP_CONFIG_DATA_REGISTER 2
+
+#define PNP_VENDOR_CONFIG_BYTE ((BYTE) 0xf0)
+
+#define PNP_VENDOR_CONFIG_IRQ ((BYTE )0x70)
+#define PNP_VENDOR_CONFIG_4MBITS ((BYTE) 0x80)
+#define PNP_VENDOR_CONFIG_RSVALID ((BYTE) 0x02)
+#define PNP_VENDOR_CONFIG_PXTAL ((BYTE) 0x01)
+
+
+/****************************************************************************/
+/* */
+/* Values : PNP CONTROL_REGISTER_1 */
+/* */
+/* These are the bit definitions for control register 1 on Smart 16 cards. */
+/* */
+/* NB. The bit definitions are mostly the same as MC CONTROL_REGISTER_1. */
+/* */
+
+#define PNP_CTRL1_NSRESET ((BYTE) 0x80) /* SIF Reset signal */
+#define PNP_CTRL1_CHRDY_ACTIVE ((BYTE) 0x20) /* Active channel ready. */
+
+
+/****************************************************************************/
+/* */
+/* This defines the bits used to set the RING SPEED for PNP cards. */
+/* */
+/* The bit is SET/CLEARED in SIFACL via adapter->nselout_bits just before */
+/* taking the card out of the RESET state. */
+/* */
+/* NSELOUT1 is use to control the ring speed */
+/* NSELOUT0 should ALWAYS be left alone. */
+/* */
+
+#define PNP_RING_SPEED_4 1
+#define PNP_RING_SPEED_16 0
+
+/*
+*
+* Various definitions used to talk to EEPROM.
+*
+*/
+#define PNP_CON_REG_OFFSET 4
+#define PNP_EEDO 0x0002
+#define PNP_EEDEN 0x0004
+#define PNP_SSK 0x0001
+#define PNP_DELAY_CNT 16
+#define PNP_WAIT_CNT 1000
+#define PNP_WRITE_CMD 0x00a0
+#define PNP_READ_CMD 0x00a1
+
+/*
+* Useful locations in the EEPROM
+*/
+#define PNP_HWARE_FEATURES1 0xEB
+#define PNP_HWARE_FEATURES3 0xED
+#define PNP_HWARE_PNP_FLAGS 0xEE
+
+/*
+*
+* This defines the bits in HWARE_FEATURES1 which give the DRAM size.
+*
+*/
+
+#define PNP_DRAM_SIZE_MASK 0x3E
+
+/*
+*
+* This defines the bits in HWARE_FEATURES3 which give the chip type.
+*
+*/
+
+#define PNP_C30_MASK 0x40
+#define PNP_C30 PNP_C30_MASK
+
+
+/*
+* This defines the bits in HWARE_PNP_FLAGS.
+*/
+
+#define PNP_ACTIVE_FLOAT_CHRDY 0x02
+
+/* */
+/* */
+/************** End of FTK_PNP.H file ***************************************/
+/* */
+/* */
+
diff --git a/private/ntos/ndis/madge/driver/head_def/ftk_poke.h b/private/ntos/ndis/madge/driver/head_def/ftk_poke.h
new file mode 100644
index 000000000..eb469ba9e
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_def/ftk_poke.h
@@ -0,0 +1,52 @@
+/****************************************************************************
+*
+* FTK_POKE.H
+*
+* Part of the FastMAC Toolkit.
+* Copyright (c) Madge Networks Ltd 1995
+*
+* This module provides some functions that will send tracing information
+* to either serial port (COM1 or COM2) on a standard IBM PC clone.
+*
+*****************************************************************************/
+
+#ifdef FTK_POKEOUTS
+
+void _ftk_poke_char(int ch);
+void _ftk_poke_string(char *str);
+void _ftk_poke_byte(int byte);
+void _ftk_poke_word(int word);
+void _ftk_poke_dword(long dword);
+
+#define FTK_POKE_CHAR(x) _ftk_poke_char((int) (x))
+#define FTK_POKE_STRING(x) _ftk_poke_string(x)
+#define FTK_POKE_BYTE(x) _ftk_poke_byte((int) (x))
+#define FTK_POKE_WORD(x) _ftk_poke_word((int) (x))
+#define FTK_POKE_DWORD(x) _ftk_poke_dword((long) (x))
+
+/*
+ * Prototypes and macro definitions for comms primitives.
+ */
+
+int _inp(unsigned port);
+int _outp(unsigned port, int data_byte);
+
+#define OUTB(x, y) _outp(x, y)
+#define INB(x) _inp(x)
+
+/*
+ * Use the following definition to force pokeouts to COM2.
+ */
+
+/* #define USE_COM2 */
+
+#else
+
+#define FTK_POKE_CHAR(x)
+#define FTK_POKE_STRING(x)
+#define FTK_POKE_BYTE(x)
+#define FTK_POKE_WORD(x)
+#define FTK_POKE_DWORD(x)
+
+#endif
+
diff --git a/private/ntos/ndis/madge/driver/head_def/ftk_sm16.h b/private/ntos/ndis/madge/driver/head_def/ftk_sm16.h
new file mode 100644
index 000000000..3005e775d
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_def/ftk_sm16.h
@@ -0,0 +1,100 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE MADGE ADAPTER CARD DEFINITIONS (SMART 16 CARDS) */
+/* ================================================ */
+/* */
+/* FTK_SM16.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* Developed by AC */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* This header file contains the definitions for programming Madge Smart 16 */
+/* adapter cards. These adapter cards have a couple of control registers, */
+/* in addition to the SIF registers. ALL bits in ALL control registers are */
+/* defined by Madge Networks Ltd */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this FTK_SM16.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_FTK_SM16_H 221
+
+
+/****************************************************************************/
+/* */
+/* Values : SMART 16 REGISTER MAP */
+/* */
+/* The Madge Smart 16 Ringnode uses the following register layout. */
+/* N.B. The SIF registers are mapped linearly, with no overlaying. */
+/* */
+
+#define SMART16_IO_RANGE 32
+
+#define SMART16_DEFAULT_INTERRUPT 2
+
+#define SMART16_CONTROL_REGISTER_1 0
+#define SMART16_CONTROL_REGISTER_2 8
+
+#define SMART16_FIRST_SIF_REGISTER 16
+
+
+/****************************************************************************/
+/* */
+/* Values : SMART 16 CONTROL_REGISTER_1 */
+/* */
+/* These are the bit definitions for control register 1 on Smart 16 cards. */
+/* */
+/* NB. The bit definitions are mostly the same as MC CONTROL_REGISTER_1. */
+/* */
+
+#define SMART16_CTRL1_NSRESET ((BYTE) 0x01) /* SIF Reset signal */
+#define SMART16_CTRL1_SCS ((BYTE) 0x02) /* Chip select */
+
+
+/****************************************************************************/
+/* */
+/* Values : SMART 16 CONTROL_REGISTER_2 BITS */
+/* */
+/* These are the bit definitions for control register 2 on Smart 16 cards. */
+/* */
+
+#define SMART16_CTRL2_XTAL ((BYTE) 0x01) /* Used to decode BIA */
+#define SMART16_CTRL2_SCS ((BYTE) 0x02) /* Same as CTRL1_SCS */
+
+
+/****************************************************************************/
+/* */
+/* Values : SMART 16 SIFACL INTERRUPT SETTINGS */
+/* */
+/* These are the values to be written into the NSELOUT0/1 bits of SIFACL to */
+/* select the interrupt number on the adapter card. */
+/* */
+
+#define SMART16_IRQ_2 3
+#define SMART16_IRQ_3 0
+#define SMART16_IRQ_7 2
+
+
+/****************************************************************************/
+/* */
+/* Values : SMART 16 IO PORT MASK for revision type */
+/* */
+/* This bit in the IO address selects between rev3 and rev4 bus timings. */
+/* */
+
+#define SMART16_REV3 ((UINT) 0x1000)
+
+
+/* */
+/* */
+/************** End of FTK_SM16.H file **************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_def/ftk_srb.h b/private/ntos/ndis/madge/driver/head_def/ftk_srb.h
new file mode 100644
index 000000000..027611abd
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_def/ftk_srb.h
@@ -0,0 +1,279 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE SRB DEFINITIONS */
+/* =================== */
+/* */
+/* FTK_SRB.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* Developed by MF */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* This header file contains all the definitions and structures that are */
+/* required for the SRB interface. */
+/* */
+/* REFERENCE : The Madge Fastmac Interface Specification */
+/* - SRB Interface */
+/* */
+/* IMPORTANT : All structures used within the FTK need to be packed in */
+/* order to work correctly. This means sizeof(STRUCTURE) will give the real */
+/* size in bytes, and if a structure contains sub-structures there will be */
+/* no spaces between the sub-structures. */
+/* */
+/****************************************************************************/
+
+#pragma pack(1)
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this FTK_SRB.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_FTK_SRB_H 221
+
+
+/****************************************************************************/
+/* */
+/* TYPEDEFs for all structures defined within this header file : */
+/* */
+
+typedef struct STRUCT_SRB_HEADER SRB_HEADER;
+
+typedef union UNION_SRB_GENERAL SRB_GENERAL;
+
+typedef struct STRUCT_SRB_MODIFY_OPEN_PARMS SRB_MODIFY_OPEN_PARMS;
+
+typedef struct STRUCT_SRB_OPEN_ADAPTER SRB_OPEN_ADAPTER;
+
+typedef struct STRUCT_SRB_CLOSE_ADAPTER SRB_CLOSE_ADAPTER;
+
+typedef struct STRUCT_SRB_SET_MULTICAST_ADDR SRB_SET_GROUP_ADDRESS;
+typedef struct STRUCT_SRB_SET_MULTICAST_ADDR SRB_SET_FUNCTIONAL_ADDRESS;
+
+typedef struct STRUCT_SRB_READ_ERROR_LOG SRB_READ_ERROR_LOG;
+
+typedef struct STRUCT_SRB_SET_BRIDGE_PARMS SRB_SET_BRIDGE_PARMS;
+
+typedef struct STRUCT_SRB_SET_PROD_INST_ID SRB_SET_PROD_INST_ID;
+
+/****************************************************************************/
+/* */
+/* Structure type : SRB_HEADER */
+/* */
+/* All SRBs have a common header. With Fastmac all SRBs complete */
+/* synchronously, ie. the return code is never E_FF_COMMAND_NOT_COMPLETE */
+/* and the correlator field is not used. */
+/* */
+
+struct STRUCT_SRB_HEADER
+ {
+ BYTE function;
+ BYTE correlator;
+ BYTE return_code;
+ BYTE reserved;
+ };
+
+
+/****************************************************************************/
+/* */
+/* Values : SRB_HEADER - BYTE function */
+/* */
+/* These are the SRBs currently supported by the FTK. */
+/* */
+/* REFERENCE : The Madge Fastmac Interface Specification */
+/* - SRB Interface */
+/* */
+
+#define MODIFY_OPEN_PARMS_SRB 0x01
+#define OPEN_ADAPTER_SRB 0x03
+#define CLOSE_ADAPTER_SRB 0x04
+#define SET_GROUP_ADDRESS_SRB 0x06
+#define SET_FUNCTIONAL_ADDRESS_SRB 0x07
+#define READ_ERROR_LOG_SRB 0x08
+#define SET_BRIDGE_PARMS_SRB 0x09
+#define FMPLUS_SPECIFIC_SRB 0xC3
+
+#define SET_PROD_INST_ID_SUBCODE 4
+
+/****************************************************************************/
+/* */
+/* Values : SRB_HEADER - BYTE return_code */
+/* */
+/* These are defined in FTK_ERR.H */
+/* */
+
+
+/****************************************************************************/
+/* */
+/* Structure type : SRB_MODIFY_OPEN_PARMS */
+/* */
+/* This SRB is issued to modify the open options for an adapter. The */
+/* adapter can be in auto-open mode or have been opened by an SRB (see */
+/* below). */
+/* */
+/* REFERENCE : The Madge Fastmac Interface Specification */
+/* - SRB Interface : Modify Open Parms SRB */
+/* */
+
+struct STRUCT_SRB_MODIFY_OPEN_PARMS
+ {
+ SRB_HEADER header;
+ WORD open_options;
+ };
+
+
+/****************************************************************************/
+/* */
+/* Structure type : SRB_OPEN_ADAPTER */
+/* */
+/* This SRB is issued to open the adapter with the given node address and */
+/* functional and group addresses. */
+/* */
+/* REFERENCE : The Madge Fastmac Interface Specification */
+/* - SRB Interface : Open Adapter SRB */
+/* */
+
+struct STRUCT_SRB_OPEN_ADAPTER
+ {
+ SRB_HEADER header;
+ BYTE reserved_1[2];
+ WORD open_error; /* secondary error code */
+ WORD open_options; /* see USER.H for options */
+ NODE_ADDRESS open_address;
+ DWORD group_address;
+ DWORD functional_address;
+ WORD reserved_2;
+ WORD reserved_3;
+ WORD reserved_4;
+ BYTE reserved_5;
+ BYTE reserved_6;
+ BYTE reserved_7[10];
+ char product_id[SIZEOF_PRODUCT_ID]; /* network managers */
+ };
+
+
+/****************************************************************************/
+/* */
+/* Structure type : SRB_CLOSE_ADAPTER */
+/* */
+/* The SRB for closing the adapter consists of just an SRB header. */
+/* */
+/* REFERENCE : The Madge Fastmac Interface Specification */
+/* - SRB Interface : Close Adapter SRB */
+/* */
+
+struct STRUCT_SRB_CLOSE_ADAPTER
+ {
+ SRB_HEADER header;
+ };
+
+
+/****************************************************************************/
+/* */
+/* Structure types : SRB_SET_GROUP_ADDRESS */
+/* SRB_SET_FUNCTIONAL_ADDRESS */
+/* */
+/* This structure is used for SRBs for setting both the functional and */
+/* group addresses of an adapter. */
+/* */
+/* REFERENCE : The Madge Fastmac Interface Specification */
+/* - SRB Interface : Set Group/Functional Address SRB */
+/* */
+
+struct STRUCT_SRB_SET_MULTICAST_ADDR
+ {
+ SRB_HEADER header;
+ WORD reserved;
+ MULTI_ADDRESS multi_address;
+ };
+
+
+/****************************************************************************/
+/* */
+/* Structure type : SRB_READ_ERROR_LOG */
+/* */
+/* This SRB is used to get MAC error log counter information from the */
+/* adapter. The counters are reset to zero as they are read. */
+/* */
+/* REFERENCE : The Madge Fastmac Interface Specification */
+/* - SRB Interface : Read Error Log SRB */
+/* */
+
+struct STRUCT_SRB_READ_ERROR_LOG
+ {
+ SRB_HEADER header;
+ WORD reserved;
+ ERROR_LOG error_log; /* defined in FTK_USER.H */
+ };
+
+
+/****************************************************************************/
+/* */
+/* Structure type : SRB_SET_BRIDGE_PARMS */
+/* */
+/* This SRB is used to configure the TI Source Routing Accelerator (SRA) */
+/* ASIC. The adapter must be open for this SRB to work. */
+/* The order for the fields in the options word is : */
+/* Bit 15 (MSB) : single-route-broadcast */
+/* Bit 14 - 10 : reserved (all zero) */
+/* Bit 9 - 4 : maximum route length */
+/* Bit 3 - 0 : number of bridge bits */
+/* */
+/* REFERENCE : The Madge Fastmac Interface Specification */
+/* - SRB Interface : Set Bridge Parms SRB */
+/* */
+
+struct STRUCT_SRB_SET_BRIDGE_PARMS
+ {
+ SRB_HEADER header;
+ WORD options;
+ UINT this_ring;
+ UINT that_ring;
+ UINT bridge_num;
+ };
+
+#define SRB_SBP_DFLT_BRIDGE_BITS 4
+#define SRB_SBP_DFLT_ROUTE_LEN 18
+
+
+struct STRUCT_SRB_SET_PROD_INST_ID
+ {
+ SRB_HEADER header;
+ WORD subcode;
+ BYTE product_id[SIZEOF_PRODUCT_ID];
+ };
+
+/****************************************************************************/
+/* */
+/* Structure type : SRB_GENERAL */
+/* */
+/* This SRB structure is a union of all the possible SRB structures used by */
+/* the FTK. Included in the union is an SRB header structure so that the */
+/* header of an SRB can be accessed without knowing the type of SRB. */
+/* */
+
+union UNION_SRB_GENERAL
+ {
+ SRB_HEADER header;
+ SRB_MODIFY_OPEN_PARMS mod_parms;
+ SRB_OPEN_ADAPTER open_adap;
+ SRB_CLOSE_ADAPTER close_adap;
+ SRB_SET_GROUP_ADDRESS set_group;
+ SRB_SET_FUNCTIONAL_ADDRESS set_func;
+ SRB_READ_ERROR_LOG err_log;
+ SRB_SET_BRIDGE_PARMS set_bridge_parms;
+ SRB_SET_PROD_INST_ID set_prod_inst_id;
+ };
+
+#pragma pack()
+
+
+/* */
+/* */
+/************** End of FTK_SRB.H file ***************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_def/ftk_tab.h b/private/ntos/ndis/madge/driver/head_def/ftk_tab.h
new file mode 100644
index 000000000..89ff399f9
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_def/ftk_tab.h
@@ -0,0 +1,1054 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE ERROR TABLES DEFINITIONS */
+/* ============================ */
+/* */
+/* FTK_TAB.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1993 */
+/* Developed by MF */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* This header file contains the definitions and local variable */
+/* declarations that are required by the error handling part of the FTK. It */
+/* includes the error message text for all the possible errors that can */
+/* occur. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this FTK_TAB.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_FTK_TAB_H 221
+
+#ifndef FTK_NO_ERROR_MESSAGES
+
+/****************************************************************************/
+/* */
+/* Variables : error_msg_headers_table */
+/* */
+/* The error_msg_headers_table contains the text of the error message */
+/* header for each type of error. This header is combined with the main */
+/* body of the error message to produce the full error text which is put in */
+/* the adapter structure of the adapter on which the error occurred. */
+/* */
+
+local char * error_msg_headers_table[] =
+
+{
+ "\n SRB error :"
+ "\n -----------",
+
+ "\n Open adapter error :"
+ "\n --------------------",
+
+ "\n Data transfer error :"
+ "\n ---------------------",
+
+ "\n Driver error :"
+ "\n --------------",
+
+ "\n HWI error :"
+ "\n -----------",
+
+ "\n Bring up error :"
+ "\n ----------------",
+
+ "\n Initialization error :"
+ "\n ----------------------",
+
+ "\n Auto-open adapter error :"
+ "\n -------------------------",
+
+ "\n Adapter check error :"
+ "\n ---------------------",
+
+ "\n PCMCIA Card Services error :"
+ "\n ----------------------------"
+};
+
+
+/****************************************************************************/
+/* */
+/* Variables : special error messages */
+/* */
+/* Some error messages have to have the full text, header and body, */
+/* together. These include those error messages that can be produced when */
+/* there is no valid adapter structure into which to put the full message. */
+/* This is the case for drv_err_msg_1 and drv_err_msg_2. */
+/* */
+
+local char drv_err_msg_1[] =
+
+ "\n Driver error :"
+ "\n --------------"
+ "\n The adapter handle being used is invalid. It"
+ "\n has been corrupted by the user of the FTK.";
+
+local char drv_err_msg_2[] =
+
+ "\n Driver error :"
+ "\n --------------"
+ "\n Either the adapter handle is invalid or memory"
+ "\n for an adapter structure has not successfully"
+ "\n been allocated by a call to the system routine"
+ "\n sys_alloc_adapter_structure.";
+
+
+/****************************************************************************/
+/* */
+/* Value : Default marker */
+/* */
+/* Each table of error message texts, for a particular error type, needs a */
+/* final marker in case an unknown error value is encountered. This should */
+/* not occur within the FTK, but it may be that extra error values are */
+/* added by users incorrectly. */
+/* */
+
+
+#define ERR_MSG_UNKNOWN_END_MARKER 0xFF
+
+
+/****************************************************************************/
+/* */
+/* Variables : srb_error_msg_table */
+/* */
+/* The srb_error_msg_table contains the error message body texts for SRB */
+/* error type messages. These texts are combined with the error type header */
+/* messages to produce the full error message. */
+/* */
+
+
+local ERROR_MESSAGE_RECORD srb_error_msg_table[] =
+
+{
+ {
+ SRB_E_03_ADAPTER_OPEN,
+ "\n The adapter is open and should be closed for"
+ "\n the previous SRB to complete successfully."
+ },
+
+ {
+ SRB_E_04_ADAPTER_CLOSED,
+ "\n The adapter is closed and should be open for"
+ "\n the previous SRB to complete successfully."
+ },
+
+ {
+ SRB_E_06_INVALID_OPTIONS,
+ "\n The parameters used to configure the bridge are"
+ "\n invalid in some way."
+ },
+
+ {
+ SRB_E_07_CMD_CANCELLED_FAIL,
+ "\n The previous SRB command has been cancelled"
+ "\n because of an unrecoverable error when"
+ "\n attempting to complete it. A field in the SRB"
+ "\n is probably invalid."
+ },
+
+ {
+ SRB_E_32_INVALID_NODE_ADDRESS,
+ "\n The node address field in the previous SRB is"
+ "\n invalid. Either the BIA PROM on the card is"
+ "\n faulty or the user has supplied an invalid node"
+ "\n address to the appropriate driver routine."
+ },
+
+ {
+ ERR_MSG_UNKNOWN_END_MARKER,
+ "\n An unknown error has occurred."
+ }
+};
+
+
+/****************************************************************************/
+/* */
+/* Variables : open_error_msg_table */
+/* */
+/* The open_error_msg_table contains the error message body texts for open */
+/* error type messages. These texts are combined with the error type header */
+/* messages to produce the full error message. */
+/* */
+
+local ERROR_MESSAGE_RECORD open_error_msg_table[] =
+
+{
+ {
+ OPEN_E_01_OPEN_ERROR,
+ "\n The adapter has failed to open onto the ring."
+ "\n This could be caused by one of the following -"
+ "\n"
+ "\n i) the lobe cable is not securely"
+ "\n attached to the adapter card or cabling"
+ "\n unit."
+ "\n"
+ "\n ii) the ring speed setting on the card"
+ "\n does not match the actual ring speed."
+ "\n"
+ "\n iii) insertion onto the ring has been"
+ "\n prevented by ring management software."
+ "\n"
+ "\n iv) the ring is beaconing."
+ "\n"
+ "\n v) there is a crashed ring parameter"
+ "\n server on the ring."
+ "\n"
+ "\n Check the above and then retry the operation."
+ },
+
+ {
+ ERR_MSG_UNKNOWN_END_MARKER,
+ "\n An unknown error has occurred."
+ }
+};
+
+
+/****************************************************************************/
+/* */
+/* Variables : data_xfer_error_msg_table */
+/* */
+/* The data_xfer_error_msg_table contains the error message body texts for */
+/* data transfer error type messages. These texts are combined with the */
+/* error type header messages to produce the full error message. */
+/* */
+
+local ERROR_MESSAGE_RECORD data_xfer_error_msg_table[] =
+
+{
+ {
+ DATA_XFER_E_01_BUFFER_FULL,
+ "\n The Fastmac transmit buffer is full. This is"
+ "\n probably because it can be filled by the host"
+ "\n quicker than the adapter can put the frames"
+ "\n onto the ring. However, it could be because the"
+ "\n adapter has closed. Hence, check the ring"
+ "\n status if this error persists."
+ },
+
+ {
+ ERR_MSG_UNKNOWN_END_MARKER,
+ "\n An unknown error has occurred."
+ }
+};
+
+
+/****************************************************************************/
+/* */
+/* Variables : driver_error_msg_table */
+/* */
+/* The driver_error_msg_table contains the error message body texts for */
+/* driver error type messages. These texts are combined with the error type */
+/* header messages to produce the full error message. */
+/* */
+
+local ERROR_MESSAGE_RECORD driver_error_msg_table[] =
+
+{
+ {
+ DRIVER_E_03_FAIL_ALLOC_STATUS,
+ "\n Memory for a status information structure has"
+ "\n not successfully been allocated by a call to"
+ "\n the system routine sys_alloc_status_structure."
+ },
+
+ {
+ DRIVER_E_04_FAIL_ALLOC_INIT,
+ "\n Memory for an initialization block has not"
+ "\n successfully been allocated by a call to the"
+ "\n system routine sys_alloc_init_block."
+ },
+
+ {
+ DRIVER_E_05_FAIL_ALLOC_RX_BUF,
+ "\n Memory for a Fastmac receive buffer has not"
+ "\n successfully been allocated by a call to the"
+ "\n system routine sys_alloc_receive_buffer."
+ },
+
+ {
+ DRIVER_E_06_FAIL_ALLOC_TX_BUF,
+ "\n Memory for a Fastmac transmit buffer has not"
+ "\n successfully been allocated by a call to the"
+ "\n system routine sys_alloc_transmit_buffer."
+ },
+
+ {
+ DRIVER_E_07_NOT_PREPARED,
+ "\n A call to driver_start_adapter has been made"
+ "\n without first calling driver_prepare_adapter."
+ },
+
+ {
+ DRIVER_E_08_NOT_RUNNING,
+ "\n A driver routine has been called without first"
+ "\n getting the adapter up an running (by first"
+ "\n calling driver_prepare_adapter and then calling"
+ "\n driver_start_adapter)."
+ },
+
+ {
+ DRIVER_E_09_SRB_NOT_FREE,
+ "\n The SRB for the adapter is not free and hence"
+ "\n the previously called driver routine can not"
+ "\n execute since it uses the SRB. After calling a"
+ "\n driver routine that uses the SRB, wait for the"
+ "\n user_completed_srb routine to be called before"
+ "\n calling such a driver routine again."
+ },
+
+ {
+ DRIVER_E_0A_RX_BUF_BAD_SIZE,
+ "\n The size of the Fastmac receive buffer is"
+ "\n either too big or too small. The maximum"
+ "\n allowable size is 0xFF00. The minimum allowable"
+ "\n size is 0x0404 which allows the buffer to hold"
+ "\n a single 1K frame."
+ },
+
+ {
+ DRIVER_E_0B_RX_BUF_NOT_DWORD,
+ "\n The physical address of the Fastmac receive"
+ "\n buffer must be on a DWORD boundary ie. the"
+ "\n bottom 2 bits of the address must be zero."
+ },
+
+ {
+ DRIVER_E_0C_TX_BUF_BAD_SIZE,
+ "\n The size of the Fastmac transmit buffer is"
+ "\n either too big or too small. The maximum"
+ "\n allowable size is 0xFF00. The minimum allowable"
+ "\n size is 0x0404 which allows the buffer to hold"
+ "\n a single 1K frame."
+ },
+
+ {
+ DRIVER_E_0D_TX_BUF_NOT_DWORD,
+ "\n The physical address of the Fastmac transmit"
+ "\n buffer must be on a DWORD boundary ie. the"
+ "\n bottom 2 bits of the address must be zero."
+ },
+
+ {
+ DRIVER_E_0E_BAD_RX_METHOD,
+ "\n The receive method value that has been supplied"
+ "\n to driver_prepare_adapter is invalid. A choice"
+ "\n of two values is possible; either"
+ "\n RX_OUT_OF_INTERRUPTS or RX_BY_SCHEDULED_PROCESS"
+ "\n is allowed."
+ },
+
+ {
+ DRIVER_E_0F_WRONG_RX_METHOD,
+ "\n The driver_get_outstanding_receive routine can"
+ "\n only be called if the receive method chosen is"
+ "\n RX_BY_SCHEDULED_PROCESS."
+ },
+
+ {
+ DRIVER_E_10_BAD_RX_SLOT_NUMBER,
+ "\n The number of receive slots requested from the"
+ "\n driver_prepare_adapter routine must lie within"
+ "\n the limits set in the FastMac Plus programming"
+ "\n specification (currently from 4 to 32)."
+ },
+
+ {
+ DRIVER_E_11_BAD_TX_SLOT_NUMBER,
+ "\n The number of transmit slots requested from"
+ "\n the driver_prepare_adapter routine must lie"
+ "\n within the limits set in the FastMac Plus pro-"
+ "\n gramming specification (currently 4 to 32)."
+ },
+
+ {
+ DRIVER_E_12_FAIL_ALLOC_DMA_BUF,
+ "\n Memory for a dma buffer has not successfully"
+ "\n been allocated by a call to the system routine"
+ "\n sys_alloc_dma_phys_buf."
+ },
+
+ {
+ DRIVER_E_13_BAD_FRAME_SIZE,
+ "\n The frame size specified is out of range."
+ "\n Please choose a smaller value."
+ },
+
+ {
+ ERR_MSG_UNKNOWN_END_MARKER,
+ "\n An unknown error has occurred."
+ }
+};
+
+
+/****************************************************************************/
+/* */
+/* Variables : hwi_error_msg_table */
+/* */
+/* The hwi_error_msg_table contains the error message body texts for hwi */
+/* error type messages. These texts are combined with the error type header */
+/* messages to produce the full error message. */
+/* */
+
+local ERROR_MESSAGE_RECORD hwi_error_msg_table[] =
+
+{
+ {
+ HWI_E_01_BAD_CARD_BUS_TYPE,
+ "\n The adapter card bus type given is invalid. It"
+ "\n does not correspond to a valid Madge adapter"
+ "\n card bus type."
+ },
+
+ {
+ HWI_E_02_BAD_IO_LOCATION,
+ "\n The IO location given is not valid for the"
+ "\n adapter card being used."
+ },
+
+ {
+ HWI_E_03_BAD_INTERRUPT_NUMBER,
+ "\n The interrupt number given is not valid for the"
+ "\n adapter card being used."
+ },
+
+ {
+ HWI_E_04_BAD_DMA_CHANNEL,
+ "\n The DMA channel given is not valid for the"
+ "\n adapter card being used. Alternatively, a DMA"
+ "\n channel has been specified and the card is"
+ "\n configured for PIO mode. Note 16/4 PC cards do"
+ "\n not support DMA, and that EISA and MC cards do"
+ "\n not support PIO."
+ },
+
+ {
+ HWI_E_05_ADAPTER_NOT_FOUND,
+ "\n An adapter card of the given bus type has not"
+ "\n been found at the IO location specified. Check"
+ "\n that the adapter details are correct and that"
+ "\n the adapter card has been correctly installed"
+ "\n in the machine."
+ },
+
+ {
+ HWI_E_06_CANNOT_USE_DMA,
+ "\n It is not possible to use DMA when an adapter"
+ "\n card is in an 8-bit slot. Either select PIO"
+ "\n data transfer mode or put the adapter card in a"
+ "\n 16-bit slot. Note 16/4 PC cards do not support"
+ "\n DMA."
+ },
+
+ {
+ HWI_E_07_FAILED_TEST_DMA,
+ "\n The test DMAs that take place as part of the"
+ "\n adapter initialization have failed. The address"
+ "\n for the DMAs is probably not downloaded to the"
+ "\n adapter card correctly due to the byte ordering"
+ "\n of the host machine."
+ },
+
+ {
+ HWI_E_08_BAD_DOWNLOAD,
+ "\n Downloading the Fastmac binary image has"
+ "\n failed. When reading the downloaded data back"
+ "\n from the adapter, it does not equal the data"
+ "\n that was downloaded. There is probably a fault"
+ "\n with the adapter card - use a diagnostics"
+ "\n program to check it more thoroughly."
+ },
+
+ {
+ HWI_E_09_BAD_DOWNLOAD_IMAGE,
+ "\n The format of the Fastmac binary image that is"
+ "\n being downloaded is invalid. Check that the"
+ "\n data has not been corrupted and that the"
+ "\n pointer to the Fastmac download code (supplied"
+ "\n to driver_prepare_adapter) is correct."
+ },
+
+ {
+ HWI_E_0A_NO_DOWNLOAD_IMAGE,
+ "\n No download image has been provided. The"
+ "\n pointer to the Fastmac binary image supplied to"
+ "\n driver_prepare_adapter is NULL and hence"
+ "\n invalid."
+ },
+
+ {
+ HWI_E_0B_FAIL_IRQ_ENABLE,
+ "\n The required interrupt channel has not been"
+ "\n successfully enabled by a call to the system"
+ "\n routine sys_enable_irq_channel."
+ },
+
+ {
+ HWI_E_0C_FAIL_DMA_ENABLE,
+ "\n The required DMA channel has not been"
+ "\n successfully enabled by a call to the system"
+ "\n routine sys_enable_dma_channel."
+ },
+
+ {
+ HWI_E_0D_CARD_NOT_ENABLED,
+ "\n The card has not been enabled. Both EISA and MC"
+ "\n cards must be properly configured before use."
+ "\n Use the configuration utility provided with"
+ "\n your computer."
+ },
+
+ {
+ HWI_E_0E_NO_SPEED_SELECTED,
+ "\n A speed (16Mb/s or 4Mb/s) has not been selected"
+ "\n for the adapter card. Both EISA and MC cards"
+ "\n must be configured for a particular ring speed"
+ "\n before use. Use the configuration utility"
+ "\n provided with your computer."
+ },
+
+ {
+ HWI_E_0F_BAD_FASTMAC_INIT,
+ "\n The initialization of Fastmac has not completed"
+ "\n successfully. The node address field in the"
+ "\n Fastmac status block is not a Madge node"
+ "\n address. Either an attempt has been made to use"
+ "\n the FTK with a non-Madge card or there is a"
+ "\n problem with the adapter. Use a diagnostics"
+ "\n program to check the adapter card more"
+ "\n thoroughly."
+ },
+
+ {
+ HWI_E_10_BAD_TX_RX_BUFF_SIZE,
+ "\n The size of the buffers used by the code on the"
+ "\n adapter must exceed the minimum value specified"
+ "\n in the FastMac Plus programming specification,"
+ "\n which is currently 96 bytes."
+ },
+
+ {
+ HWI_E_11_TOO_MANY_TX_RX_BUFFS,
+ "\n There is not enough memory on the adapter to"
+ "\n accommodate the number of transmit and receive"
+ "\n buffers requested. Try reducing the number of"
+ "\n transmit slots requested, or reducing the allo-"
+ "\n cation of buffers to large frame transmits in"
+ "\n hwi_initialise_adapter."
+ },
+
+ {
+ HWI_E_12_BAD_SCB_ALLOC,
+ "\n Failed to allocate a block of memory suitable"
+ "\n for the DMA test into the SCB. This is a system"
+ "\n memory allocation failure, arising in the func-"
+ "\n tion sys_alloc_dma_buffer."
+ },
+
+ {
+ HWI_E_13_BAD_SSB_ALLOC,
+ "\n Failed to allocate a block of memory suitable"
+ "\n for the DMA test into the SSB. This is a system"
+ "\n memory allocation failure, arising in the func-"
+ "\n tion sys_alloc_dma_buffer."
+ },
+
+ {
+ HWI_E_14_BAD_PCI_MACHINE,
+ "\n This machine is either not a 386 (or higher) or"
+ "\n there is a problem with the PCI BIOS."
+ },
+
+ {
+ HWI_E_15_BAD_PCI_MEMORY,
+ "\n The PCI BIOS has failed to allocate any memory"
+ "\n to do memory mapped IO."
+ },
+
+ {
+ HWI_E_16_PCI_3BYTE_PROBLEM,
+ "\n Internal error &3800"
+ },
+
+ {
+ HWI_E_17_BAD_TRANSFER_MODE,
+ "\n The transfer mode specified is not supported by"
+ "\n this card."
+ },
+
+ {
+ ERR_MSG_UNKNOWN_END_MARKER,
+ "\n An unknown error has occurred."
+ }
+};
+
+
+/****************************************************************************/
+/* */
+/* Variables : bring_up_error_msg_table */
+/* */
+/* The bring_up_error_msg_table contains the error message body texts for */
+/* bring up error type messages. These texts are combined with the error */
+/* type header messages to produce the full error message. */
+/* */
+
+local ERROR_MESSAGE_RECORD bring_up_error_msg_table[] =
+
+{
+ {
+ BRING_UP_E_00_INITIAL_TEST,
+ "\n The bring up diagnostics failed with an initial"
+ "\n test error. This is an unrecoverable hardware"
+ "\n error. There is probably a fault with the"
+ "\n adapter card - use a diagnostics program to"
+ "\n check it more thoroughly."
+ },
+
+ {
+ BRING_UP_E_01_SOFTWARE_CHECKSUM,
+ "\n The bring up diagnostics failed with an adapter"
+ "\n software checksum error. This is an"
+ "\n unrecoverable hardware error. There is probably"
+ "\n a fault with the adapter card - use a"
+ "\n diagnostics program to check it more"
+ "\n thoroughly."
+ },
+
+ {
+ BRING_UP_E_02_ADAPTER_RAM,
+ "\n The bring up diagnostics failed with an adapter"
+ "\n RAM error when checking the first 128Kbytes."
+ "\n This is an unrecoverable hardware error. There"
+ "\n is probably a fault with the adapter card - use"
+ "\n a diagnostics program to check it more"
+ "\n thoroughly."
+ },
+
+ {
+ BRING_UP_E_03_INSTRUCTION_TEST,
+ "\n The bring up diagonstics failed with an"
+ "\n instruction test error. This is an"
+ "\n unrecoverable hardware error. There is probably"
+ "\n a fault with the adapter card - use a"
+ "\n diagnostics program to check it more"
+ "\n thoroughly."
+ },
+
+ {
+ BRING_UP_E_04_INTERRUPT_TEST,
+ "\n The bring up diagonstics failed with a context"
+ "\n / interrupt test error. This is an"
+ "\n unrecoverable hardware error. There is probably"
+ "\n a fault with the adapter card - use a"
+ "\n diagnostics program to check it more"
+ "\n thoroughly."
+ },
+
+ {
+ BRING_UP_E_05_FRONT_END,
+ "\n The bring up diagonstics failed with a protocol"
+ "\n handler / ring interface hardware error. This"
+ "\n is an unrecoverable hardware error. There is"
+ "\n probably a fault with the adapter card - use a"
+ "\n diagnostics program to check it more"
+ "\n thoroughly."
+ },
+
+ {
+ BRING_UP_E_06_SIF_REGISTERS,
+ "\n The bring up diagonstics failed with a system"
+ "\n interface register error. This is an"
+ "\n unrecoverable hardware error. There is probably"
+ "\n a fault with the adapter card - use a"
+ "\n diagnostics program to check it more"
+ "\n thoroughly."
+ },
+
+ {
+ BRING_UP_E_10_TIME_OUT,
+ "\n The adapter failed to complete the bring up"
+ "\n diagnostics within the time out period. Check"
+ "\n that the system provided timer routines are"
+ "\n working correctly. Alternatively, there may be"
+ "\n a fault with the adapter card - use a"
+ "\n diagnostics program to check it more"
+ "\n thoroughly."
+ },
+
+ {
+ ERR_MSG_UNKNOWN_END_MARKER,
+ "\n An unknown error has occurred."
+ }
+};
+
+
+/****************************************************************************/
+/* */
+/* Variables : init_error_msg_table */
+/* */
+/* The init_error_msg_table contains the error message body texts for init */
+/* error type messages. These texts are combined with the error type header */
+/* messages to produce the full error message. */
+/* */
+
+local ERROR_MESSAGE_RECORD init_error_msg_table[] =
+
+{
+ {
+ INIT_E_01_INIT_BLOCK,
+ "\n Adapter initialization has failed because the"
+ "\n TI initialization block has not been correctly"
+ "\n downloaded. There is probably a fault with the"
+ "\n adapter card - use a diagnostics program to"
+ "\n check it more thoroughly."
+ },
+
+ {
+ INIT_E_02_INIT_OPTIONS,
+ "\n Adapter initialization has failed because of"
+ "\n invalid options in the TI part of the"
+ "\n initialization block. This field is set"
+ "\n correctly by the FTK and should not be changed"
+ "\n elsewhere. One possible reason for this error"
+ "\n is if the structures used by the FTK are not"
+ "\n byte packed."
+ },
+
+ {
+ INIT_E_03_RX_BURST_SIZE,
+ "\n Adapter initialization has failed because of an"
+ "\n odd receive burst size being set in the TI part"
+ "\n of the initialization block. This field is set"
+ "\n correctly by the FTK and should not be changed"
+ "\n elsewhere. One possible reason for this error"
+ "\n is if the structures used by the FTK are not"
+ "\n byte packed."
+ },
+
+ {
+ INIT_E_04_TX_BURST_SIZE,
+ "\n Adapter initialization has failed because of an"
+ "\n odd transmit burst size being set in the TI"
+ "\n part of the initialization block. This field is"
+ "\n set correctly by the FTK and should not be"
+ "\n changed elsewhere. One possible reason for"
+ "\n this error is if the structures used by the FTK"
+ "\n are not byte packed."
+ },
+
+ {
+ INIT_E_05_DMA_THRESHOLD,
+ "\n Adapter initialization has failed because of an"
+ "\n invalid DMA abort threshold being set in the TI"
+ "\n part of the initialization block. This field is"
+ "\n set correctly by the FTK and should not be"
+ "\n changed elsewhere. One possible reason for"
+ "\n this error is if the structures used by the FTK"
+ "\n are not byte packed."
+ },
+
+ {
+ INIT_E_06_ODD_SCB_ADDRESS,
+ "\n Adapter initialization has failed because of an"
+ "\n odd SCB address being set in the TI part of the"
+ "\n initialization block. This field is set"
+ "\n correctly by the FTK and should not be changed"
+ "\n elsewhere. One possible reason for this error"
+ "\n is if the structures used by the FTK are not"
+ "\n byte packed."
+ },
+
+ {
+ INIT_E_07_ODD_SSB_ADDRESS,
+ "\n Adapter initialization has failed because of an"
+ "\n odd SSB address being set in the TI part of the"
+ "\n initialization block. This field is set"
+ "\n correctly by the FTK and should not be changed"
+ "\n elsewhere. One possible reason for this error"
+ "\n is if the structures used by the FTK are not"
+ "\n byte packed."
+ },
+
+ {
+ INIT_E_08_DIO_PARITY,
+ "\n Adapter initialization has failed because a"
+ "\n parity error occurred during a DIO write"
+ "\n operation. There is probably a fault with the"
+ "\n adapter card - use a diagnostics program to"
+ "\n check it more thoroughly."
+ },
+
+ {
+ INIT_E_09_DMA_TIMEOUT,
+ "\n Adapter initialization has failed because of a"
+ "\n DMA timeout error. The adapter timed out"
+ "\n waiting for a test DMA transfer to complete. If"
+ "\n PIO data transfer mode is being used then the"
+ "\n fault probably lies in the system routines"
+ "\n called by the PIO code."
+ },
+
+ {
+ INIT_E_0A_DMA_PARITY,
+ "\n Adapter initialization has failed because of a"
+ "\n DMA parity error. There is probably a fault"
+ "\n with the adapter card - use a diagnostics"
+ "\n program to check it more thoroughly."
+ },
+
+ {
+ INIT_E_0B_DMA_BUS,
+ "\n Adapter initialization has failed because of a"
+ "\n DMA bus error. There is probably a fault with"
+ "\n the adapter card - use a diagnostics program to"
+ "\n check it more thoroughly."
+ },
+
+ {
+ INIT_E_0C_DMA_DATA,
+ "\n Adapter initialization has failed because of a"
+ "\n DMA data error. On completing a test DMA,"
+ "\n comparing the final data to the initial data"
+ "\n showed an error. If PIO data transfer mode is"
+ "\n being used then the fault probably lies in the"
+ "\n system routines called by the PIO code."
+ },
+
+ {
+ INIT_E_0D_ADAPTER_CHECK,
+ "\n Adapter initialization has failed because of an"
+ "\n adapter check. An unrecoverable hardware error"
+ "\n occurred on the adapter. There is probably a"
+ "\n fault with the adapter card - use a diagnostics"
+ "\n program to check it more thoroughly."
+ },
+
+ {
+ INIT_E_0E_NOT_ENOUGH_MEMORY,
+ "\n Adapter initialization failed because there was"
+ "\n insufficient memory for the number of transmit"
+ "\n and receive buffers requested. Reduce either"
+ "\n the buffer allocation or the number of transmit"
+ "\n slots."
+ },
+
+ {
+ INIT_E_10_TIME_OUT,
+ "\n The adapter failed to complete initialization"
+ "\n within the time out period. Check that the"
+ "\n system provided timer routines are working"
+ "\n correctly. Another possible reason for this"
+ "\n error is if the structures used by the FTK are"
+ "\n not byte packed. Alternatively, there may be a"
+ "\n fault with the adapter card - use a diagnostics"
+ "\n program to check it more thoroughly."
+ },
+
+ {
+ ERR_MSG_UNKNOWN_END_MARKER,
+ "\n An unknown error has occurred."
+ }
+};
+
+
+/****************************************************************************/
+/* */
+/* Variables : auto_open_error_msg_table */
+/* */
+/* The auto_open_error_msg_table contains the error message body texts for */
+/* auto open error type messages. These texts are combined with the error */
+/* type header messages to produce the full error message. */
+/* */
+
+local ERROR_MESSAGE_RECORD auto_open_error_msg_table[] =
+
+{
+ {
+ AUTO_OPEN_E_01_OPEN_ERROR,
+ "\n The adapter has failed to open onto the ring."
+ "\n This could be caused by one of the following -"
+ "\n"
+ "\n i) the lobe cable is not securely"
+ "\n attached to the adapter card or cabling"
+ "\n unit."
+ "\n"
+ "\n ii) insertion onto the ring has been"
+ "\n prevented by ring management software."
+ "\n"
+ "\n iii) there is a crashed ring parameter"
+ "\n server on the ring."
+ "\n"
+ "\n Check the above before retrying the operation."
+ },
+
+ {
+ AUTO_OPEN_E_80_TIME_OUT,
+ "\n The adapter has failed to open within a"
+ "\n substantial time out period (greater than 30"
+ "\n seconds). There is probably a fault with the"
+ "\n adapter card - use a diagnostics program to"
+ "\n check it more thoroughly."
+ },
+
+ {
+ ERR_MSG_UNKNOWN_END_MARKER,
+ "\n An unknown error has occurred."
+ }
+};
+
+
+/****************************************************************************/
+/* */
+/* Variables : adapter_error_msg_table */
+/* */
+/* The adapter_error_msg_table contains the error message body texts for */
+/* adapter check error type messages. These texts are combined with the */
+/* error type header messages to produce the full error message. */
+/* */
+
+local ERROR_MESSAGE_RECORD adapter_error_msg_table[] =
+
+{
+ {
+ ADAPTER_E_01_ADAPTER_CHECK,
+ "\n An adapter check interrupt has occurred. An"
+ "\n unrecoverable hardware error has caused the"
+ "\n adapter to become inoperable. There is probably"
+ "\n a fault with the adapter card - use a"
+ "\n diagnostics program to check it more"
+ "\n thoroughly."
+ },
+
+ {
+ ERR_MSG_UNKNOWN_END_MARKER,
+ "\n An unknown error has occurred."
+ }
+};
+
+/****************************************************************************/
+/* */
+/* Variables : pcmcia_cs_error_msg_table */
+/* */
+/* The pcmcia_cs_error_msg_table contains the error message body texts for */
+/* PCMCIA Card Services error type messages. These texts are combined with */
+/* the error type header messages to produce the full error message. */
+/* */
+
+local ERROR_MESSAGE_RECORD pcmcia_cs_error_msg_table[] =
+
+{
+ {
+ CS_E_01_NO_CARD_SERVICES,
+ "\n No PCMCIA Card Services installed. Madge Smart"
+ "\n 16/4 PCMCIA ringnode driver requires PCMCIA"
+ "\n Card Services. You can use Card Services which"
+ "\n come with your computer or Madge Card Services."
+ },
+
+ {
+ CS_E_02_REGISTER_CLIENT_FAILED,
+ "\n Failed to register with PCMCIA Card Services."
+ "\n Check that PCMCIA Card Services is properly"
+ "\n installed. Make sure there is no crashing of"
+ "\n memory usage with other TSR or memory manager."
+ },
+
+ {
+ CS_E_03_REGISTRATION_TIMEOUT,
+ "\n PCMCIA Card Services failed to response in time"
+ "\n Check that PCMCIA Card Services is properly"
+ "\n installed. Make sure there is no crashing of"
+ "\n memory usage with other TSR or memory manager."
+ },
+
+ {
+ CS_E_04_NO_MADGE_ADAPTER_FOUND,
+ "\n No Madge Smart 16/4 PCMCIA Ringnode found."
+ },
+
+ {
+ CS_E_05_ADAPTER_NOT_FOUND,
+ "\n Cannot find a Madge Smart 16/4 PCMCIA Ringnode"
+ "\n in the PCMCIA Socket specified. Check if the"
+ "\n adapter is properly fitted."
+ },
+
+ {
+ CS_E_06_SPECIFIED_SOCKET_IN_USE,
+ "\n The adapter in the PCMCIA socket specified is"
+ "\n in use."
+ },
+
+ {
+ CS_E_07_IO_REQUEST_FAILED,
+ "\n PCMCIA Card Services refused the request for IO"
+ "\n resource. The IO location specified is being"
+ "\n used by other devices."
+ },
+
+ {
+ CS_E_08_BAD_IRQ_CHANNEL,
+ "\n The interrupt number specified is not"
+ "\n supported."
+ },
+
+ {
+ CS_E_09_IRQ_REQUEST_FAILED,
+ "\n PCMCIA Card Services refused the request for"
+ "\n interupt channel resources. The interrupt"
+ "\n number specified is being used by other devices"
+ },
+
+ {
+ CS_E_0A_REQUEST_CONFIG_FAILED,
+ "\n PCMCIA Card Services refused the request for"
+ "\n resources."
+ },
+
+ {
+ ERR_MSG_UNKNOWN_END_MARKER,
+ "\n An unknown error has occurred."
+ }
+};
+
+
+/****************************************************************************/
+/* */
+/* Variables : list_of_error_msg_tables */
+/* */
+/* The list_of_error_msg_tables contains a list of pointers to the */
+/* different tables of error message body texts (one table per error type). */
+/* This variable is used to access the correct table for the error type */
+/* that has occurred. */
+/* */
+
+
+local ERROR_MESSAGE_RECORD * list_of_error_msg_tables[] =
+
+{
+ srb_error_msg_table ,
+ open_error_msg_table ,
+ data_xfer_error_msg_table ,
+ driver_error_msg_table ,
+ hwi_error_msg_table ,
+ bring_up_error_msg_table ,
+ init_error_msg_table ,
+ auto_open_error_msg_table ,
+ adapter_error_msg_table ,
+ pcmcia_cs_error_msg_table
+};
+
+#endif
+
+/* */
+/* */
+/************** End of FTK_TAB.H file ***************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_def/ftk_user.h b/private/ntos/ndis/madge/driver/head_def/ftk_user.h
new file mode 100644
index 000000000..09f85c8b5
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_def/ftk_user.h
@@ -0,0 +1,666 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE USER DEFINITIONS */
+/* ==================== */
+/* */
+/* FTK_USER.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* Developed by MF */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* This header file contains ALL the definitions and structures required by */
+/* any user of the FTK driver. Any user of the FTK need only include this */
+/* definitions header file in order to use the FTK. */
+/* */
+/* IMPORTANT : Some structures used within the FTK need to be packed in */
+/* order to work correctly. This means sizeof(STRUCTURE) will give the real */
+/* size in bytes, and if a structure contains sub-structures there will be */
+/* no spaces between the sub-structures. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this FTK_USER.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_FTK_USER_H 221
+
+
+/****************************************************************************/
+/* */
+/* TYPEDEFs for all structures defined within this header file : */
+/* */
+
+typedef struct STRUCT_NODE_ADDRESS NODE_ADDRESS;
+typedef union UNION_MULTI_ADDRESS MULTI_ADDRESS;
+typedef struct STRUCT_STATUS_INFORMATION STATUS_INFORMATION;
+typedef struct STRUCT_ERROR_LOG ERROR_LOG;
+typedef struct STRUCT_PROBE PROBE;
+typedef struct STRUCT_PREPARE_ARGS PREPARE_ARGS, *PPREPARE_ARGS;
+typedef struct STRUCT_START_ARGS START_ARGS, *PSTART_ARGS;
+typedef struct STRUCT_TR_OPEN_DATA TR_OPEN_DATA, *PTR_OPEN_DATA;
+
+
+/****************************************************************************/
+/* */
+/* Function declarations */
+/* */
+/* Routines in the FTK are either local to a module, or they are exported. */
+/* Exported routines are entry points to the user of a module and the */
+/* routine has an 'extern' definition in an appropriate header file (see */
+/* FTK_INTR.H and FTK_EXTR.H). A user of the FTK may wish to follow this */
+/* method of function declarations using the following definitions. */
+/* */
+
+#define local static
+#define export
+
+
+/****************************************************************************/
+/* */
+/* Basic types : BYTE, WORD, DWORD and BOOLEAN */
+/* */
+/* The basic types used throughout the FTK, and for passing parameters to */
+/* it, are BYTE (8 bit unsigned), WORD (16 bit unsigned), DWORD (32 bit */
+/* unsigned) and BOOLEAN (16 bit unsigned). A BOOLEAN variable should take */
+/* the value TRUE or FALSE. */
+/* */
+/* Note that none of the FTK code makes an explicit check for the value */
+/* TRUE (it only checks for FALSE which must be zero) and hence TRUE can */
+/* have any non-zero value. */
+/* */
+
+typedef unsigned char BYTE; /* 8 bits */
+
+typedef unsigned short int WORD; /* 16 bits */
+
+typedef unsigned long int DWORD; /* 32 bits */
+
+typedef unsigned long int ULONG;
+
+typedef WORD WBOOLEAN;
+
+typedef unsigned int UINT;
+
+#define VOID void
+
+#define FALSE 0
+#define TRUE 1
+
+#if !defined(max)
+#define max(a,b) ((a) < (b) ? (b) : (a))
+#endif
+
+#if !defined(min)
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+
+#ifdef FMPLUS
+
+/****************************************************************************/
+/* */
+/* Variables : Fmplus download image */
+/* */
+/* The following variables are exported by FMPLUS.C which contains the */
+/* binary image for FastmacPlus in a 'C' format BYTE array. These variables */
+/* will be needed by a user of the FTK in order to download Fastmac */
+/* Plus (fmplus_image), display the Fastmac Plus version number and */
+/* copyright message (fmplus_version and fmplus_copyright_msg) and check */
+/* that the FTK version number is that required by Fastmac */
+/* (ftk_version_for_fmplus). The variables concerned with the size of the */
+/* Fastmac Plus binary (sizeof_fmplus_array and recorded_size_fmplus_array) */
+/* can be used to check for corruption of the Fasmtac image array. The */
+/* checksum byte (fmplus_checksum) can also be used for this purpose. */
+/* */
+
+extern BYTE fmplus_image[];
+
+extern char fmplus_version[];
+
+extern char fmplus_copyright_msg[];
+
+extern WORD ftk_version_for_fmplus;
+
+extern WORD sizeof_fmplus_array;
+
+extern WORD recorded_size_fmplus_array;
+
+extern BYTE fmplus_checksum;
+
+#else
+
+/****************************************************************************/
+/* */
+/* Variables : Fastmac download image */
+/* */
+/* The following variables are exported by FASTMAC.C which contains the */
+/* binary image for Fastmac in a 'C' format BYTE array. These variables */
+/* will be needed by a user of the FTK in order to download Fastmac */
+/* (fastmac_image), display the Fastmac version number and copyright */
+/* message (fastmac_version and fastmac_copyright_msg) and check that the */
+/* FTK version number is that required by Fastmac */
+/* (ftk_version_for_fastmac). The variables concerned with the size of the */
+/* Fastmac binary (sizeof_fastmac_array and recorded_size_fastmac_array) */
+/* can be used to check for corruption of the Fasmtac image array. The */
+/* checksum byte (fastmac_checksum) can also be used for this purpose. */
+/* */
+
+extern BYTE fastmac_image[];
+
+extern WORD fastmac_version;
+
+extern char fastmac_copyright_msg[];
+
+extern WORD ftk_version_for_fastmac;
+
+extern WORD sizeof_fastmac_array;
+
+extern WORD recorded_size_fastmac_array;
+
+extern BYTE fastmac_checksum;
+
+#endif
+
+/****************************************************************************/
+/* */
+/* Values : Pointers */
+/* */
+/* For a near pointer, (one that points to a location in DGROUP), the value */
+/* NULL (must equal 0) is used to specify that it is yet to be assigned or */
+/* an attempt to assign to it was unsuccessful. For example, an attempt to */
+/* allocate memory via a system specific call to which a near pointer is to */
+/* point, eg. sys_alloc_init_block, should return NULL if unsuccessful. */
+/* Similarly, when a DWORD is used as a pointer to a 32 bit physical */
+/* address pointer, the value NULL_PHYSADDR (must equal 0L) is used. It */
+/* should be returned by sys_alloc fastmac buffer routines if unsuccessful. */
+/* */
+
+#if !defined(NULL)
+#define NULL 0
+#endif
+
+#define NULL_PHYSADDR 0L
+
+
+/****************************************************************************/
+/* */
+/* Type : ADAPTER_HANDLE */
+/* */
+/* An element of this type is returned by driver_prepare_adapter in order */
+/* to identify a particular adapter for all subsequent calls to the driver */
+/* module of the FTK. */
+/* */
+
+typedef WORD ADAPTER_HANDLE;
+
+
+/****************************************************************************/
+/* */
+/* Type : DOWNLOAD_IMAGE */
+/* */
+/* A pointer to a download image must be supplied by the user to */
+/* driver_prepare_adapter. This download image should be Fastmac. */
+/* */
+
+typedef BYTE DOWNLOAD_IMAGE;
+
+
+/****************************************************************************/
+/* */
+/* The following structures represent data strcutures on the adapter and */
+/* must be byte packed. */
+/* */
+
+#pragma pack(1)
+
+
+/****************************************************************************/
+/* */
+/* Structure type : NODE_ADDRESS */
+/* */
+/* A node address may be supplied by the user to driver_prepare_adapter or */
+/* driver_open_adapter. The permanent node address of the adapter is */
+/* returned by driver_start_adapter. A node address is a 6 byte value. For */
+/* Madge adapters the bytes would be 0x00, 0x00, 0xF6, ... etc. */
+/* */
+
+struct STRUCT_NODE_ADDRESS
+ {
+ BYTE byte[6];
+ };
+
+
+/****************************************************************************/
+/* */
+/* Union type : MULTI_ADDRESS */
+/* */
+/* A multicast address may be supplied by the user to */
+/* driver_set_group_address or driver_set_functional_address. The */
+/* multicast address is the final 4 bytes of a 6 byte node address. The */
+/* first 2 bytes are determined by whether it is a group address or a */
+/* functional address. */
+/* */
+
+union UNION_MULTI_ADDRESS
+ {
+ DWORD all;
+ BYTE byte[4];
+ };
+
+
+/****************************************************************************/
+/* */
+/* Type : LONG_ADDRESS */
+/* */
+/* A LONG_ADDRESS is a 64 bit address. Some architectures (e.g. Alpha) use */
+/* 64 bit physical addresses. */
+/* */
+
+union STRUCT_LONG_ADDRESS
+ {
+ BYTE bytes[8];
+ WORD words[4];
+ DWORD dwords[2];
+ };
+
+typedef union STRUCT_LONG_ADDRESS LONG_ADDRESS;
+
+
+/****************************************************************************/
+/* */
+/* Structure type : TR_OPEN_DATA */
+/* */
+/* The TR_OPEN_DATA structure is used to pass to the Open SRB and to the */
+/* driver_start_adapter functions all the addressing details that could */
+/* usefully set. This is especially useful for restoring the card to a */
+/* prior state after a reset. */
+/* */
+
+typedef struct STRUCT_TR_OPEN_DATA
+ {
+ WORD open_options;
+ NODE_ADDRESS opening_node_address;
+ ULONG group_address;
+ ULONG functional_address;
+ };
+
+
+/****************************************************************************/
+/* */
+/* Structure type : ERROR_LOG */
+/* */
+/* This is part of the information returned by a call to */
+/* driver_get_adapter_status. The error log contains the information from a */
+/* READ_ERROR_LOG SRB call. All the MAC level error counters are reset to */
+/* zero after they are read. */
+/* */
+/* REFERENCE : The TMS 380 Second-Generation Token_Ring User's Guide */
+/* by Texas Instruments */
+/* 4-112 MAC 000A READ.ERROR.LOG Command */
+/* */
+
+struct STRUCT_ERROR_LOG
+ {
+ BYTE line_errors;
+ BYTE reserved_1;
+ BYTE burst_errors;
+ BYTE ari_fci_errors;
+ BYTE reserved_2;
+ BYTE reserved_3;
+ BYTE lost_frame_errors;
+ BYTE congestion_errors;
+ BYTE frame_copied_errors;
+ BYTE reserved_4;
+ BYTE token_errors;
+ BYTE reserved_5;
+ BYTE dma_bus_errors;
+ BYTE dma_parity_errors;
+ };
+
+
+/****************************************************************************/
+/* */
+/* Structure type : STATUS_INFORMATION */
+/* */
+/* The status information returned by a call to driver_get_status */
+/* includes whether the adapter is currently open, the current ring status */
+/* and the MAC level error log information. */
+/* */
+
+struct STRUCT_STATUS_INFORMATION
+ {
+ WBOOLEAN adapter_open;
+ WORD ring_status;
+ ERROR_LOG error_log;
+ };
+
+
+/****************************************************************************/
+/* */
+/* Values : STATUS_INFORMATION - WORD ring_status */
+/* */
+/* These are the possible ring status values returned by a call to */
+/* driver_get_adapter_status. */
+/* */
+/* REFERENCE : The TMS 380 Second-Generation Token_Ring User's Guide */
+/* by Texas Instruments */
+/* 4-61 4.12.2 RING.STATUS */
+/* */
+
+#define RING_STATUS_SIGNAL_LOSS 0x8000
+#define RING_STATUS_HARD_ERROR 0x4000
+#define RING_STATUS_SOFT_ERROR 0x2000
+#define RING_STATUS_TRANSMIT_BEACON 0x1000
+#define RING_STATUS_LOBE_FAULT 0x0800
+#define RING_STATUS_AUTO_REMOVAL 0x0400
+#define RING_STATUS_REMOVE_RECEIVED 0x0100
+#define RING_STATUS_COUNTER_OVERFLOW 0x0080
+#define RING_STATUS_SINGLE_STATION 0x0040
+#define RING_STATUS_RING_RECOVERY 0x0020
+
+
+/****************************************************************************/
+/* */
+/* Values : WORD open_options */
+/* */
+/* The open_options parameter to driver_prepare_adapter and */
+/* driver_open_adapter has the following bit fields defined. */
+/* */
+/* WARNING : The FORCE_OPEN option is a special Fastmac option that will */
+/* open an adapter onto any ring - even if the adapter and ring speed do */
+/* not match! Use it with caution. */
+/* */
+/* REFERENCE : The Madge Fastmac Interface Specification */
+/* - SRB Interface : Open Adapter SRB */
+/* */
+/* REFERENCE : The TMS 380 Second-Generation Token_Ring User's Guide */
+/* by Texas Instruments */
+/* 4-71 MAC 0003 OPEN command */
+/* */
+
+#define OPEN_OPT_WRAP_INTERFACE 0x8000
+#define OPEN_OPT_DISABLE_SOFT_ERROR 0x4000
+#define OPEN_OPT_DISABLE_HARD_ERROR 0x2000
+#define OPEN_OPT_PASS_ADAPTER_MACS 0x1000
+#define OPEN_OPT_PASS_ATTENTION_MACS 0x0800
+#define OPEN_OPT_FORCE_OPEN 0x0400 /* Fastmac only */
+#define OPEN_OPT_CONTENDER 0x0100
+#define OPEN_OPT_PASS_BEACON_MACS 0x0080
+#define OPEN_OPT_EARLY_TOKEN_RELEASE 0x0010
+#define OPEN_OPT_COPY_ALL_MACS 0x0004
+#define OPEN_OPT_COPY_ALL_LLCS 0x0002
+
+
+/****************************************************************************/
+/* */
+/* Values : WORD adapter_card_bus_type */
+/* */
+/* The following adapter card bus types are defined and can be passed to */
+/* driver_start_adapter. Different adapter card bus types apply to */
+/* different adapter cards : */
+/* */
+/* ADAPTER_CARD_ISA_BUS_TYPE 16/4 PC or 16/4 AT */
+/* ADAPTER_CARD_MC_BUS_TYPE 16/4 MC or 16/4 MC 32 */
+/* ADAPTER_CARD_EISA_BUS_TYPE 16/4 EISA mk1 or mk2 */
+/* */
+
+#define ADAPTER_CARD_ATULA_BUS_TYPE 1
+#define ADAPTER_CARD_MC_BUS_TYPE 2
+#define ADAPTER_CARD_EISA_BUS_TYPE 3
+#define ADAPTER_CARD_PCI_BUS_TYPE 4
+#define ADAPTER_CARD_SMART16_BUS_TYPE 5
+#define ADAPTER_CARD_PCMCIA_BUS_TYPE 6
+#define ADAPTER_CARD_PNP_BUS_TYPE 7
+#define ADAPTER_CARD_TI_PCI_BUS_TYPE 8
+#define ADAPTER_CARD_PCI2_BUS_TYPE 9
+
+
+/****************************************************************************/
+/* */
+/* Values : WORD transfer_mode, WORD interrupt_number */
+/* */
+/* If POLLING_INTERRUPTS_MODE is given as the interrupt number to */
+/* driver_start_adapter, then polling is assumed to be used. */
+/* */
+/* NOTE : If using the DOS example system specific code, then note that */
+/* PIO_DATA_TRANSFER_MODE is defined in SYS_IRQ.ASM and SYS_DMA.ASM */
+/* resepctively. The value used here must be, and is, identical. */
+/* */
+
+#define PIO_DATA_TRANSFER_MODE 0
+#define DMA_DATA_TRANSFER_MODE 1
+#define MMIO_DATA_TRANSFER_MODE 2
+#define POLLING_INTERRUPTS_MODE 0
+
+
+/****************************************************************************/
+/* */
+/* Values : Returned from driver_transmit_frame (or some such) */
+/* */
+/* The value returned by driver_transmit_frame indicates how far the code */
+/* got with transmitting the frame. FAIL and SUCCEED are obvious, WAIT */
+/* means that the caller should not assume the frame has been transmitted */
+/* until some later indication. */
+/* */
+
+#define DRIVER_TRANSMIT_FAIL 0
+#define DRIVER_TRANSMIT_WAIT 1
+#define DRIVER_TRANSMIT_SUCCEED 2
+
+
+/****************************************************************************/
+/* */
+/* Values : Returned from user_receive_frame */
+/* */
+/* The value returned by a call to the user_receive_frame routine indicates */
+/* whether the user wishes to keep the frame in the Fastmac buffer or has */
+/* dealt with it (decided it can be thrown away or copied it elsewhere). In */
+/* the latter case the frame can be removed from the Fastmac receive */
+/* buffer. */
+/* */
+
+#define DO_NOT_KEEP_FRAME 0
+#define KEEP_FRAME 1
+
+
+/****************************************************************************/
+/* */
+/* Type : card_t */
+/* */
+/* To support large model compilation, certain type casts have to be made */
+/* to evade compilation errors. The card_t type is used to convert pointers */
+/* to structures on the adapter card into unsigned integers so that they */
+/* can be truncated to 16 bits without warnings. */
+/* */
+/* */
+
+typedef DWORD card_t;
+
+
+/****************************************************************************/
+/* */
+/* The following structures do not need to be byte packed. */
+/* */
+
+#pragma pack()
+
+
+/****************************************************************************/
+/* */
+/* Values : PROBE_FAILURE */
+/* */
+/* This value is returned by the driver_probe_adapter function if an error */
+/* occurs. */
+/* */
+
+#define PROBE_FAILURE 0xffff
+
+
+/****************************************************************************/
+/* */
+/* Values : FTK_UNDEFINED */
+/* */
+/* This value means that a value is not defined or not used. */
+/* */
+
+#define FTK_UNDEFINED 0xeeff
+
+
+/****************************************************************************/
+/* */
+/* Structure type : PROBE */
+/* */
+/* The probe structure can be filled in with card details by a call to */
+/* driver_probe_adapter. This is the way the user of the FTK should obtain */
+/* hardware resource information (DMA channel, IRQ number etc) about an */
+/* adapter before calling driver_prepare_adapter and driver_start_adapter. */
+/* */
+
+struct STRUCT_PROBE
+{
+ WORD socket;
+ UINT adapter_card_bus_type;
+ UINT adapter_card_type;
+ UINT adapter_card_revision;
+ UINT adapter_ram_size;
+ WORD io_location;
+ WORD interrupt_number;
+ WORD dma_channel;
+ UINT transfer_mode;
+ DWORD mmio_base_address;
+ DWORD pci_handle;
+};
+
+
+/****************************************************************************/
+/* */
+/* Types : PREPARE_ARGS */
+/* */
+/* The driver_prepare_adapter function takes a collection of arguments. An */
+/* instance of this structure is used to pass the arguments. */
+/* */
+
+typedef struct STRUCT_PREPARE_ARGS
+{
+ /* User's private information, not interpreted by the FTK. */
+
+ void * user_information;
+
+#ifdef FMPLUS
+
+ /* Number of FastMAC Plus receive and transmit slots. */
+
+ WORD number_of_rx_slots;
+ WORD number_of_tx_slots;
+
+#else
+
+ /* Size of the FastMAC receive and transmit buffers. */
+
+ WORD receive_buffer_byte_size;
+ WORD transmit_buffer_byte_size;
+
+#endif
+
+ /* Requested maximum frame size. */
+
+ WORD max_frame_size;
+
+};
+
+
+/****************************************************************************/
+/* */
+/* Types : START_ARGS */
+/* */
+/* The driver_start_adapter function takes a collection of arguments. An */
+/* instance of this structure is used to pass the arguments. Note that some */
+/* of the structure fields are filled in on return from */
+/* driver_start_adapter. */
+/* */
+
+typedef struct STRUCT_START_ARGS
+{
+ /* Adapter family. */
+
+ UINT adapter_card_bus_type;
+
+ /* Hardware resource details. */
+
+#ifdef PCMCIA_POINT_ENABLE
+ UINT socket;
+#endif
+ WORD io_location;
+ WORD dma_channel;
+ UINT transfer_mode;
+ WORD interrupt_number;
+
+ /* Override DMA/IRQ values on soft programmable adapters? */
+
+ WBOOLEAN set_dma_channel;
+ WBOOLEAN set_interrupt_number;
+
+ /* Force ring speed to this if possible. 4, 16 or 0 for default. */
+
+ UINT set_ring_speed;
+
+ /* Base Address for MMIO */
+
+ DWORD mmio_base_address;
+
+ /*
+ * Used for the Ti PCI ASIC which in hwi_install needs to access PCI
+ * Config space.
+ */
+
+ DWORD pci_handle;
+
+ /* Actual maximum frame size. Set on return. */
+
+ WORD max_frame_size;
+
+ /* Auto open the adapter? */
+
+ WBOOLEAN auto_open_option;
+
+ /* Open options and addresses for auto open mode. If
+ opening_node_address == 000000000000 the the BIA address
+ is used. */
+
+ WORD open_options;
+
+ NODE_ADDRESS opening_node_address;
+ ULONG opening_group_address;
+ ULONG opening_functional_address;
+
+ /* Pointer to the adapter download image. */
+
+ DOWNLOAD_IMAGE * code;
+
+ /* The open status of the adapter on return. */
+
+ UINT open_status;
+
+#ifdef FMPLUS
+
+ /* Size of the RX/TX buffers on the adapter. */
+
+ WORD rx_tx_buffer_size;
+
+#endif
+
+};
+
+
+/* */
+/* */
+/************** End of FTK_USER.H file **************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_mod/drv_err.h b/private/ntos/ndis/madge/driver/head_mod/drv_err.h
new file mode 100644
index 000000000..c8e90ac6b
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_mod/drv_err.h
@@ -0,0 +1,56 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE ERROR EXPLANATION MODULE */
+/* ============================ */
+/* */
+/* DRV_ERR.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* Developed by MF */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* The driver module provides a simple interface to allow the use of */
+/* Fastmac in as general a setting as possible. It handles the downloading */
+/* of the Fastmac code and the initialization of the adapter card. It */
+/* provides simple transmit and receive routines. It is desgined to */
+/* quickly allow the implementation of Fastmac applications. It is not */
+/* designed as the fastest or most memory efficient solution. */
+/* */
+/* The DRV_ERR.H file contains the exported function definitions for the */
+/* procedures in the DRV_ERR.C module that may be called by the user. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this DRV_ERR.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_DRV_ERR_H 221
+
+
+/****************************************************************************/
+
+extern WBOOLEAN driver_explain_error(
+
+ ADAPTER_HANDLE adapter_handle,
+ BYTE * returned_error_type,
+ BYTE * returned_error_value,
+ char * * returned_error_message
+ );
+
+extern WBOOLEAN driver_check_version(
+
+ UINT * returned_version_number
+ );
+
+
+/* */
+/* */
+/************** End of DRV_ERR.H file ***************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_mod/drv_init.h b/private/ntos/ndis/madge/driver/head_mod/drv_init.h
new file mode 100644
index 000000000..0878e5cad
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_mod/drv_init.h
@@ -0,0 +1,79 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE DRIVER MODULE (INITIALIZE / REMOVE) */
+/* ======================================= */
+/* */
+/* DRV_INIT.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* The driver module provides a simple interface to allow the use of */
+/* Fastmac in as general a setting as possible. It handles the downloading */
+/* of the Fastmac code and the initialization of the adapter card. It */
+/* provides simple transmit and receive routines. It is desgined to */
+/* quickly allow the implementation of Fastmac applications. It is not */
+/* designed as the fastest or most memory efficient solution. */
+/* */
+/* The DRV_INIT.H file contains the exported function definitions for the */
+/* procedures in the DRV_INIT.C module that may be called by the user. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this DRV_INIT.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_DRV_INIT_H 221
+
+/****************************************************************************/
+
+export UINT driver_probe_adapter(
+ WORD adapter_card_bus_type,
+ PROBE * resources,
+ UINT length,
+ WORD * valid_locations,
+ UINT number_locations
+ );
+
+export UINT driver_deprobe_adapter(
+ PROBE * resources,
+ UINT length
+ );
+
+export WBOOLEAN driver_prepare_adapter(
+
+ PPREPARE_ARGS arguments,
+ ADAPTER_HANDLE * returned_adapter_handle
+ );
+
+extern WBOOLEAN driver_start_adapter(
+
+ ADAPTER_HANDLE adapter_handle,
+ PSTART_ARGS arguments,
+ NODE_ADDRESS * returned_permanent_address
+ );
+
+#ifdef FMPLUS
+extern WBOOLEAN driver_start_receive_process(
+
+ ADAPTER_HANDLE adapter_handle
+ );
+#endif
+
+extern WBOOLEAN driver_remove_adapter(
+
+ ADAPTER_HANDLE adapter_handle
+ );
+
+
+/* */
+/* */
+/************** End of DRV_INIT.H file **************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_mod/drv_irq.h b/private/ntos/ndis/madge/driver/head_mod/drv_irq.h
new file mode 100644
index 000000000..3582496d3
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_mod/drv_irq.h
@@ -0,0 +1,48 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE DRIVER MODULE (INTERRUPT HANDLER) */
+/* ===================================== */
+/* */
+/* DRV_IRQ.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* Developed by MF */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* The driver module provides a simple interface to allow the use of */
+/* Fastmac in as general a setting as possible. It handles the downloading */
+/* of the Fastmac code and the initialization of the adapter card. It */
+/* provides simple transmit and receive routines. It is desgined to */
+/* quickly allow the implementation of Fastmac applications. It is not */
+/* designed as the fastest or most memory efficient solution. */
+/* */
+/* The DRV_IRQ.H file contains the exported function definitions for the */
+/* procedures in the DRV_IRQ.C module that may be called by the user. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this DRV_IRQ.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_DRV_IRQ_H 221
+
+
+/****************************************************************************/
+
+extern WBOOLEAN driver_get_outstanding_receive(
+
+ ADAPTER_HANDLE adapter_handle
+ );
+
+
+/* */
+/* */
+/************** End of DRV_IRQ.H file ***************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_mod/drv_misc.h b/private/ntos/ndis/madge/driver/head_mod/drv_misc.h
new file mode 100644
index 000000000..41ba1683a
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_mod/drv_misc.h
@@ -0,0 +1,81 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* MISCELLANEOUS DRIVER PROCEDURE DECLARATIONS */
+/* =========================================== */
+/* */
+/* DRV_MISC.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* Developed by MF */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* The driver module provides a simple interface to allow the use of */
+/* Fastmac in as general a setting as possible. It handles the downloading */
+/* of the Fastmac code and the initialization of the adapter card. It */
+/* provides simple transmit and receive routines. It is desgined to */
+/* quickly allow the implementation of Fastmac applications. It is not */
+/* designed as the fastest or most memory efficient solution. */
+/* */
+/* The DRV_MISC.H file contains the exported function definitions for the */
+/* those procedures that are exported by driver modules but are not */
+/* required by the user. Hence, for example, it includes the definitions */
+/* for those driver routines involved in handling interrupts. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this DRV_MISC.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_DRV_MISC_H 221
+
+
+/****************************************************************************/
+/* */
+/* From DRV_ERR.C ... */
+/* */
+
+extern WBOOLEAN driver_check_adapter(
+
+ ADAPTER_HANDLE adapter_handle,
+ UINT required_adapter_status,
+ UINT required_srb_status
+ );
+
+
+/****************************************************************************/
+/* */
+/* From DRV_SRB.C ... */
+/* */
+
+extern void driver_completing_srb(
+
+ ADAPTER_HANDLE adapter_handle,
+ ADAPTER * adapter
+ );
+
+
+/****************************************************************************/
+/* */
+/* From DRV_IRQ.C ... */
+/* */
+
+extern void driver_interrupt_entry(
+
+ ADAPTER_HANDLE adapter_handle,
+ ADAPTER * adapter,
+ WORD sifint_actual
+ );
+
+
+
+/* */
+/* */
+/************** End of DRV_MISC.H file **************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_mod/drv_rxtx.h b/private/ntos/ndis/madge/driver/head_mod/drv_rxtx.h
new file mode 100644
index 000000000..38576fb7b
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_mod/drv_rxtx.h
@@ -0,0 +1,201 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* DRIVER/USER INTERFACE PROCEDURE DEFINITIONS */
+/* =========================================== */
+/* */
+/* DRV_RXTX.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* The first section contains all the function definitions of routines that */
+/* must be supplied by the user to receive frames plus information on */
+/* completed SRBs. */
+/* */
+/* The next sections contain function prototypes for the transmit and */
+/* receive functions the user must provide. Eaxmples of these functions can */
+/* be found in the TRANSMIT.C and RECEIVE.C modules of the DOS demonstration*/
+/* programs. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this DRV_RXTX.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_DRV_RXTX_H 221
+
+/****************************************************************************/
+/* */
+/* FUNCTION PROTOTYPES */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* WARNING: Depending on the implementation, the receive side processing may*/
+/* require a USER_RECEIVE_FRAME routine, but this is implementation*/
+/* dependent. A fixed interface does not fit well with FastmacPlus.*/
+/* */
+
+extern void user_schedule_receive_process(
+
+ ADAPTER_HANDLE adapter_handle
+ );
+
+extern void user_handle_adapter_check(
+
+ ADAPTER_HANDLE adapter_handle
+ );
+
+extern void user_completed_srb(
+
+ ADAPTER_HANDLE adapter_handle,
+ WBOOLEAN srb_completed_successfully
+ );
+
+extern void user_transmit_completion(
+
+ ADAPTER_HANDLE adapter_handle,
+ DWORD identifier
+ );
+
+extern WORD user_receive_frame(
+
+ ADAPTER_HANDLE adapter_handle,
+ BYTE FAR * rx_frame_addr,
+ WORD rx_frame_len
+ );
+
+extern void user_adapter_removed(
+
+ ADAPTER_HANDLE adapter_handle
+ );
+
+
+/****************************************************************************/
+/* */
+/* These are the function prototypes that the FastMAC Plus user must */
+/* provide to handle transmission. Note that rxtx_irq_completion_check */
+/* is only needed for the FTK_TX_WITH_COMPLETION transmit method. */
+/* */
+
+#ifdef FMPLUS
+
+extern WBOOLEAN rxtx_transmit_frame(
+
+ ADAPTER_HANDLE adapter_handle,
+ DWORD tx_frame_identifier,
+ WORD tx_frame_length,
+ WORD tx_flags
+ );
+
+extern void rxtx_irq_tx_completion_check(
+
+ ADAPTER_HANDLE adapter_handle,
+ ADAPTER * adapter
+ );
+
+extern WBOOLEAN rxtx_allocate_tx_buffers(
+
+ ADAPTER * adapter,
+ WORD max_frame_size,
+ WORD number_of_slots
+ );
+
+extern void rxtx_setup_tx_buffers(
+
+ ADAPTER * adapter,
+ WBOOLEAN use_physical_addresses,
+ WORD number_of_slots
+ );
+
+extern void rxtx_free_tx_buffers(
+
+ ADAPTER * adapter,
+ WORD max_frame_size,
+ WORD number_of_slots
+ );
+#endif
+
+
+/****************************************************************************/
+/* */
+/* These are the function prototypes that the FastMAC Plus user must */
+/* provide to handle receiving. */
+/* */
+
+#ifdef FMPLUS
+
+extern void rxtx_irq_rx_frame_handler(
+
+ ADAPTER_HANDLE adapter_handle,
+ ADAPTER * adapter
+ );
+
+extern WBOOLEAN rxtx_allocate_rx_buffers(
+
+ ADAPTER * adapter,
+ WORD max_frame_size,
+ WORD number_of_slots
+ );
+
+extern void rxtx_setup_rx_buffers(
+
+ ADAPTER * adapter,
+ WBOOLEAN use_physical_addresses,
+ WORD number_of_slots
+ );
+
+extern void rxtx_free_rx_buffers(
+
+ ADAPTER * adapter,
+ WORD max_frame_size,
+ WORD number_of_slots
+ );
+
+#endif
+
+
+/****************************************************************************/
+/* */
+/* These are the function prototypes that the FastMAC user must */
+/* provide to handle transmission. */
+/* */
+
+#ifndef FMPLUS
+
+extern WBOOLEAN rxtx_transmit_frame(
+
+ ADAPTER_HANDLE adapter_handle,
+ DWORD tx_frame_identifier,
+ WORD tx_frame_length,
+ WORD tx_flags
+ );
+
+#endif
+
+
+/****************************************************************************/
+/* */
+/* These are the function prototypes that the FastMAC user must */
+/* provide to handle receiving. */
+/* */
+
+#ifndef FMPLUS
+
+extern void rxtx_irq_rx_frame_handler(
+
+ ADAPTER_HANDLE adapter_handle,
+ ADAPTER * adapter
+ );
+
+
+#endif
+
+/************** End of DRV_RXTX.H file **************************************/
diff --git a/private/ntos/ndis/madge/driver/head_mod/drv_srb.h b/private/ntos/ndis/madge/driver/head_mod/drv_srb.h
new file mode 100644
index 000000000..319e3c1c4
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_mod/drv_srb.h
@@ -0,0 +1,110 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE DRIVER MODULE (SRBs) */
+/* ======================== */
+/* */
+/* DRV_SRB.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* Developed by MF */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* The driver module provides a simple interface to allow the use of */
+/* Fastmac in as general a setting as possible. It handles the downloading */
+/* of the Fastmac code and the initialization of the adapter card. It */
+/* provides simple transmit and receive routines. It is desgined to */
+/* quickly allow the implementation of Fastmac applications. It is not */
+/* designed as the fastest or most memory efficient solution. */
+/* */
+/* The DRV_SRB.H file contains the exported function definitions for the */
+/* procedures in the DRV_SRB.C module that may be called by the user. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this DRV_SRB.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_DRV_SRB_H 221
+
+
+/****************************************************************************/
+
+extern UINT driver_ring_speed(
+
+ ADAPTER_HANDLE
+ );
+
+extern UINT driver_max_frame_size(
+
+ ADAPTER_HANDLE
+ );
+
+extern WBOOLEAN driver_modify_open_options(
+
+ ADAPTER_HANDLE adapter_handle,
+ WORD open_options
+ );
+
+extern WBOOLEAN driver_open_adapter(
+
+ ADAPTER_HANDLE adapter_handle,
+ PTR_OPEN_DATA open_data
+ );
+
+extern WBOOLEAN driver_close_adapter(
+
+ ADAPTER_HANDLE adapter_handle
+ );
+
+extern WBOOLEAN driver_set_group_address(
+
+ ADAPTER_HANDLE adapter_handle,
+ MULTI_ADDRESS * group_address
+ );
+
+
+extern WBOOLEAN driver_set_functional_address(
+
+ ADAPTER_HANDLE adapter_handle,
+ MULTI_ADDRESS * functional_address
+ );
+
+extern void driver_get_open_and_ring_status(
+
+ ADAPTER_HANDLE adapter_handle,
+ WORD * pwRingStatus,
+ WORD * pwOpenStatus
+ );
+
+extern WBOOLEAN driver_get_status(
+
+ ADAPTER_HANDLE adapter_handle
+ );
+
+extern WBOOLEAN driver_set_bridge_parms(
+
+ ADAPTER_HANDLE adapter_handle,
+ WBOOLEAN single_route_bcast,
+ UINT this_ring,
+ UINT that_ring,
+ UINT bridge_num
+ );
+
+extern WBOOLEAN driver_set_product_instance_id(
+
+ ADAPTER_HANDLE adapter_handle,
+ BYTE * product_id
+ );
+
+
+/* */
+/* */
+/************** End of DRV_SRB.H file ***************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_mod/ftk_extr.h b/private/ntos/ndis/madge/driver/head_mod/ftk_extr.h
new file mode 100644
index 000000000..a35a46d39
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_mod/ftk_extr.h
@@ -0,0 +1,67 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE MODULE ENTRY POINTS DEFINITIONS (EXTERNAL) */
+/* ============================================== */
+/* */
+/* FTK_EXTR.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* Developed by MF */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* The FASTMAC TOOL-KIT consists of three parts - the DRIVER, the HWI and */
+/* the SYSTEM specific parts. These parts are further divided into a number */
+/* of modules. Each module has a number of exported procedures that are */
+/* the entry points to the users of that module. The definitions of these */
+/* entry points are maintained within header files using the same name as */
+/* the module itself. Each of these header files also contains a version */
+/* number of the FTK to which it belongs for consistency checking. */
+/* */
+/* There is also a header file for the utilities module that contains */
+/* useful routines used in different parts of the FTK. */
+/* */
+/* */
+/* The FTK_EXTR.H file contains the exported function definitions that are */
+/* required external to the FTK ie. by a user of the FTK. It includes the */
+/* definitions for the USER and SYSTEM functions that must be supplied by */
+/* any application. It also contains the definitions of those functions in */
+/* the DRIVER part that may be called by an FTK user. */
+/* */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* SYSTEM part : module header files */
+/* */
+
+#include "sys_allo.h"
+#include "sys_buff.h"
+#include "sys_dma.h"
+#include "sys_irq.h"
+#include "sys_mem.h"
+#include "sys_time.h"
+#include "sys_pci.h"
+#include "sys_cs.h"
+#include "sys_pcmc.h"
+
+/****************************************************************************/
+/* */
+/* DRIVER part : module header files */
+/* */
+
+#include "drv_err.h"
+#include "drv_srb.h"
+#include "drv_irq.h"
+#include "drv_init.h"
+#include "drv_rxtx.h"
+
+/* */
+/* */
+/************** End of FTK_EXTR.H file **************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_mod/ftk_intr.h b/private/ntos/ndis/madge/driver/head_mod/ftk_intr.h
new file mode 100644
index 000000000..b112700a9
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_mod/ftk_intr.h
@@ -0,0 +1,76 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE MODULE ENTRY POINTS DEFINITIONS (INTERNAL) */
+/* ============================================== */
+/* */
+/* FTK_INTR.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* Developed by MF */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* The FASTMAC TOOL-KIT consists of three parts - the DRIVER, the HWI and */
+/* the SYSTEM specific parts. These parts are further divided into a number */
+/* of modules. Each module has a number of exported procedures that are */
+/* the entry points to the users of that module. The definitions of these */
+/* entry points are maintained within header files using the same name as */
+/* the module itself. Each of these header files also contains a version */
+/* number of the FTK to which it belongs for consistency checking. */
+/* */
+/* Any application supplies a further fourth part to the FTK - the USER */
+/* part. Hence there is also a header file specifying the format of */
+/* procedures to be supplied by the user for the use of the FTK. */
+/* */
+/* There is also a header file for the utilities module that contains */
+/* useful routines used in different parts of the FTK. */
+/* */
+/* */
+/* The FTK_INTR.H file contains the exported function definitions that are */
+/* required internally by the FTK. It includes the definitions for the HWI */
+/* functions and for those DRIVER functions that are called from within the */
+/* FTK only. It also includes the utilities function definitions. */
+/* */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* HWI part : module header files */
+/* */
+
+#include "hwi_gen.h"
+#include "hwi_at.h"
+#include "hwi_sm16.h"
+#include "hwi_mc.h"
+#include "hwi_eisa.h"
+#include "hwi_pcmc.h"
+#include "hwi_pci.h"
+#include "hwi_pcit.h"
+#include "hwi_pci2.h"
+#include "hwi_pnp.h"
+
+/****************************************************************************/
+/* */
+/* DRIVER part : module header files */
+/* */
+
+#include "drv_misc.h"
+
+
+/****************************************************************************/
+/* */
+/* utilities module header file */
+/* */
+
+#include "util.h"
+
+
+/* */
+/* */
+/************** End of FTK_INTR.H file **************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_mod/hwi_at.h b/private/ntos/ndis/madge/driver/head_mod/hwi_at.h
new file mode 100644
index 000000000..b8f884afd
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_mod/hwi_at.h
@@ -0,0 +1,75 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE HARDWARE INTERFACE MODULE (ATULA CARDS) */
+/* =========================================== */
+/* */
+/* HWI_AT.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1990-1994 */
+/* Developed by MF */
+/* From code by NT */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* The purpose of the Hardware Interface (HWI) is to supply an adapter card */
+/* independent interface to any driver. It performs nearly all of the */
+/* functions that involve affecting SIF registers on the adapter cards. */
+/* This includes downloading code to, initializing, and removing adapters. */
+/* */
+/* The HWI_AT.H file contains the exported function definitions for the */
+/* HWI_AT.C module. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this HWI_AT.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_HWI_AT_H 221
+
+
+/****************************************************************************/
+
+export UINT hwi_atula_probe_card(
+
+ PROBE * resources,
+ UINT length,
+ WORD * valid_locations,
+ UINT number_locations
+ );
+
+export WBOOLEAN hwi_atula_read_rate_error( ADAPTER * adapter
+ );
+
+extern WBOOLEAN hwi_atula_install_card(
+
+ ADAPTER * adapter,
+ DOWNLOAD_IMAGE * download_image
+ );
+
+extern void hwi_atula_interrupt_handler(
+
+ ADAPTER * adapter
+ );
+
+extern void hwi_atula_remove_card(
+
+ ADAPTER * adapter
+ );
+
+extern void hwi_atula_set_dio_address(
+
+ ADAPTER * adapter,
+ DWORD dio_address
+ );
+
+
+/* */
+/* */
+/************** End of HWI_AT.H file ****************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_mod/hwi_eisa.h b/private/ntos/ndis/madge/driver/head_mod/hwi_eisa.h
new file mode 100644
index 000000000..884e4f938
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_mod/hwi_eisa.h
@@ -0,0 +1,72 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE HARDWARE INTERFACE MODULE (EISA CARDS) */
+/* ========================================== */
+/* */
+/* HWI_EISA.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1990-1994 */
+/* Developed by MF */
+/* From code by NT */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* The purpose of the Hardware Interface (HWI) is to supply an adapter card */
+/* independent interface to any driver. It performs nearly all of the */
+/* functions that involve affecting SIF registers on the adapter cards. */
+/* This includes downloading code to, initializing, and removing adapters. */
+/* */
+/* The HWI_EISA.H file contains the exported function definitions for the */
+/* HWI_EISA.C module. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this HWI_EISA.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_HWI_EISA_H 221
+
+
+/****************************************************************************/
+
+export UINT hwi_eisa_probe_card(
+
+ PROBE * resources,
+ UINT length,
+ WORD * valid_locations,
+ UINT number_locations
+ );
+
+extern WBOOLEAN hwi_eisa_install_card(
+
+ ADAPTER * adapter,
+ DOWNLOAD_IMAGE * download_image
+ );
+
+extern void hwi_eisa_interrupt_handler(
+
+ ADAPTER * adapter
+ );
+
+extern void hwi_eisa_remove_card(
+
+ ADAPTER * adapter
+ );
+
+extern void hwi_eisa_set_dio_address(
+
+ ADAPTER * adapter,
+ DWORD dio_address
+ );
+
+
+/* */
+/* */
+/************** End of HWI_EISA.H file **************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_mod/hwi_gen.h b/private/ntos/ndis/madge/driver/head_mod/hwi_gen.h
new file mode 100644
index 000000000..da4cccad5
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_mod/hwi_gen.h
@@ -0,0 +1,127 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE HARDWARE INTERFACE MODULE (GENERAL) */
+/* ======================================= */
+/* */
+/* HWI_GEN.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1990-1994 */
+/* Developed by MF */
+/* From code by NT */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* The purpose of the Hardware Interface (HWI) is to supply an adapter card */
+/* independent interface to any driver. It performs nearly all of the */
+/* functions that involve affecting SIF registers on the adapter cards. */
+/* This includes downloading code to, initializing, and removing adapters. */
+/* */
+/* The HWI_GEN.H file contains the exported function definitions for the */
+/* HWI_GEN.C module. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this HWI_GEN.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_HWI_GEN_H 221
+
+
+/****************************************************************************/
+
+export WBOOLEAN
+hwi_read_rate_error(
+ ADAPTER * adapter
+ );
+
+/****************************************************************************/
+/* */
+/* Return codes hwi_read_rate_error. */
+/* */
+/****************************************************************************/
+#define RATE_ERROR 1
+#define NOT_SUPP 2
+
+export UINT hwi_probe_adapter(
+ WORD adapter_card_bus_type,
+ PROBE * resources,
+ UINT length,
+ WORD * valid_locations,
+ UINT number_locations
+ );
+
+export UINT hwi_deprobe_adapter(
+ PROBE * resources,
+ UINT length
+ );
+
+extern WBOOLEAN hwi_install_adapter(
+
+ ADAPTER * adapter,
+ DOWNLOAD_IMAGE * download_image
+ );
+
+extern WBOOLEAN hwi_initialize_adapter(
+
+ ADAPTER * adapter,
+ INITIALIZATION_BLOCK * init_block
+ );
+
+extern WBOOLEAN hwi_get_node_address_check(
+
+ ADAPTER * adapter
+ );
+
+extern void hwi_interrupt_entry(
+
+ ADAPTER_HANDLE adapter_handle,
+ WORD interrupt_number
+ );
+
+extern void hwi_remove_adapter(
+
+ ADAPTER * adapter
+ );
+
+export void hwi_halt_eagle(
+
+ ADAPTER * adapter
+ );
+
+export WBOOLEAN hwi_download_code(
+
+ ADAPTER * adapter,
+ DOWNLOAD_RECORD * download_record,
+ void (*set_dio_address)(ADAPTER *, DWORD)
+ );
+
+export void hwi_start_eagle(
+
+ ADAPTER * adapter
+ );
+
+export WBOOLEAN hwi_get_bring_up_code(
+
+ ADAPTER * adapter
+ );
+
+export WORD hwi_get_max_frame_size(
+
+ ADAPTER * adapter
+ );
+
+export UINT hwi_get_ring_speed(
+
+ ADAPTER * adapter
+ );
+
+/* */
+/* */
+/************** End of HWI_GEN.H file ***************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_mod/hwi_mc.h b/private/ntos/ndis/madge/driver/head_mod/hwi_mc.h
new file mode 100644
index 000000000..ec5253223
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_mod/hwi_mc.h
@@ -0,0 +1,72 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE HARDWARE INTERFACE MODULE (MICROCHANNEL CARDS) */
+/* ================================================== */
+/* */
+/* HWI_MC.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1990-1994 */
+/* Developed by MF */
+/* From code by NT */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* The purpose of the Hardware Interface (HWI) is to supply an adapter card */
+/* independent interface to any driver. It performs nearly all of the */
+/* functions that involve affecting SIF registers on the adapter cards. */
+/* This includes downloading code to, initializing, and removing adapters. */
+/* */
+/* The HWI_MC.H file contains the exported function definitions for the */
+/* HWI_MC.C module. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this HWI_MC.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_HWI_MC_H 221
+
+
+/****************************************************************************/
+
+export UINT hwi_mc_probe_card(
+
+ PROBE * resources,
+ UINT length,
+ WORD * valid_locations,
+ UINT number_locations
+ );
+
+extern WBOOLEAN hwi_mc_install_card(
+
+ ADAPTER * adapter,
+ DOWNLOAD_IMAGE * download_image
+ );
+
+extern void hwi_mc_interrupt_handler(
+
+ ADAPTER * adapter
+ );
+
+extern void hwi_mc_remove_card(
+
+ ADAPTER * adapter
+ );
+
+extern void hwi_mc_set_dio_address(
+
+ ADAPTER * adapter,
+ DWORD dio_address
+ );
+
+
+/* */
+/* */
+/************** End of HWI_MC.H file ****************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_mod/hwi_pci.h b/private/ntos/ndis/madge/driver/head_mod/hwi_pci.h
new file mode 100644
index 000000000..933bed373
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_mod/hwi_pci.h
@@ -0,0 +1,61 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE HARDWARE INTERFACE MODULE (PCI CARDS) */
+/* ========================================= */
+/* */
+/* HWI_PCI.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1990-1994 */
+/* Developed by PRR */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* The purpose of the Hardware Interface (HWI) is to supply an adapter card */
+/* independent interface to any driver. It performs nearly all of the */
+/* functions that involve affecting SIF registers on the adapter cards. */
+/* This includes downloading code to, initializing, and removing adapters. */
+/* */
+/* The HWI_PCI.H file contains the exported function definitions for the */
+/* HWI_PCI.C module. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this HWI_EISA.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_HWI_PCI_H 221
+
+
+/****************************************************************************/
+
+export WBOOLEAN hwi_pci_install_card( ADAPTER * adapter,
+ DOWNLOAD_IMAGE * download_image );
+
+export void hwi_pci_interrupt_handler( ADAPTER * adapter);
+
+export void hwi_pci_remove_card( ADAPTER * adapter );
+
+export void hwi_pci_set_dio_address( ADAPTER * adapter,
+ DWORD dio_address );
+
+export UINT hwi_pci_probe_card( PROBE * Resources,
+ UINT NumberOfResources,
+ WORD * IOMask,
+ UINT NumberIO
+ );
+
+export WBOOLEAN hwi_pci_deprobe_card(
+ PROBE resource
+ );
+
+
+/* */
+/* */
+/************** End of HWI_PCI.H file ***************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_mod/hwi_pci2.h b/private/ntos/ndis/madge/driver/head_mod/hwi_pci2.h
new file mode 100644
index 000000000..5ecd286ce
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_mod/hwi_pci2.h
@@ -0,0 +1,56 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE HARDWARE INTERFACE MODULE (PCI CARDS) */
+/* ========================================= */
+/* */
+/* HWI_PCI.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1990-1994 */
+/* Developed by PRR */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* The purpose of the Hardware Interface (HWI) is to supply an adapter card */
+/* independent interface to any driver. It performs nearly all of the */
+/* functions that involve affecting SIF registers on the adapter cards. */
+/* This includes downloading code to, initializing, and removing adapters. */
+/* */
+/* The HWI_PCI2.H file contains the exported function definitions for the */
+/* HWI_PCI2.C module. */
+/* */
+/****************************************************************************/
+
+#define FTK_VERSION_NUMBER_hwi_pci2_H 221
+
+
+/****************************************************************************/
+
+export WBOOLEAN hwi_pci2_install_card( ADAPTER * adapter,
+ DOWNLOAD_IMAGE * download_image );
+
+export void hwi_pci2_interrupt_handler( ADAPTER * adapter);
+
+export void hwi_pci2_remove_card( ADAPTER * adapter );
+
+export void hwi_pci2_set_dio_address( ADAPTER * adapter,
+ DWORD dio_address );
+
+export UINT hwi_pci2_probe_card( PROBE * Resources,
+ UINT NumberOfResources,
+ WORD * IOMask,
+ UINT NumberIO
+ );
+
+export WBOOLEAN hwi_pci2_deprobe_card(
+ PROBE resource
+ );
+
+
+/* */
+/* */
+/************** End of HWI_PCI.H file ***************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_mod/hwi_pcit.h b/private/ntos/ndis/madge/driver/head_mod/hwi_pcit.h
new file mode 100644
index 000000000..714e2b24a
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_mod/hwi_pcit.h
@@ -0,0 +1,56 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE HARDWARE INTERFACE MODULE (PCI CARDS) */
+/* ========================================= */
+/* */
+/* HWI_PCI.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1990-1994 */
+/* Developed by PRR */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* The purpose of the Hardware Interface (HWI) is to supply an adapter card */
+/* independent interface to any driver. It performs nearly all of the */
+/* functions that involve affecting SIF registers on the adapter cards. */
+/* This includes downloading code to, initializing, and removing adapters. */
+/* */
+/* The HWI_PCI.H file contains the exported function definitions for the */
+/* HWI_PCI.C module. */
+/* */
+/****************************************************************************/
+
+#define FTK_VERSION_NUMBER_HWI_PCIT_H 221
+
+
+/****************************************************************************/
+
+export WBOOLEAN hwi_pcit_install_card( ADAPTER * adapter,
+ DOWNLOAD_IMAGE * download_image );
+
+export void hwi_pcit_interrupt_handler( ADAPTER * adapter);
+
+export void hwi_pcit_remove_card( ADAPTER * adapter );
+
+export void hwi_pcit_set_dio_address( ADAPTER * adapter,
+ DWORD dio_address );
+
+export UINT hwi_pcit_probe_card( PROBE * Resources,
+ UINT NumberOfResources,
+ WORD * IOMask,
+ UINT NumberIO
+ );
+
+export WBOOLEAN hwi_pcit_deprobe_card(
+ PROBE resource
+ );
+
+
+/* */
+/* */
+/************** End of HWI_PCI.H file ***************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_mod/hwi_pcmc.h b/private/ntos/ndis/madge/driver/head_mod/hwi_pcmc.h
new file mode 100644
index 000000000..5ab0c7e13
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_mod/hwi_pcmc.h
@@ -0,0 +1,77 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE HARDWARE INTERFACE MODULE (PCMCIA CARDS) */
+/* ============================================ */
+/* */
+/* HWI_PCMC.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1990-1993 */
+/* Developed by VL */
+/* From code by MF, NT */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* The purpose of the Hardware Interface (HWI) is to supply an adapter card */
+/* independent interface to any driver. It performs nearly all of the */
+/* functions that involve affecting SIF registers on the adapter cards. */
+/* This includes downloading code to, initializing, and removing adapters. */
+/* */
+/* The HWI_PCMC.H file contains the exported function definitions for the */
+/* HWI_PCMC.C module. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this HWI_PCMC.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_HWI_PCMC_H 221
+
+
+/****************************************************************************/
+
+export UINT hwi_pcmcia_probe_card(
+
+ PROBE * resources,
+ UINT length,
+ WORD * valid_locations,
+ UINT number_locations
+ );
+
+export WBOOLEAN hwi_pcmcia_deprobe_card(
+
+ PROBE resource
+ );
+
+extern WBOOLEAN hwi_pcmcia_install_card(
+
+ ADAPTER * adapter,
+ DOWNLOAD_IMAGE * download_image
+ );
+
+extern void hwi_pcmcia_interrupt_handler(
+
+ ADAPTER * adapter
+ );
+
+extern void hwi_pcmcia_remove_card(
+
+ ADAPTER * adapter
+ );
+
+extern void hwi_pcmcia_set_dio_address(
+
+ ADAPTER * adapter,
+ DWORD dio_address
+ );
+
+
+/* */
+/* */
+/************** End of HWI_PCMC.H file **************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_mod/hwi_pnp.h b/private/ntos/ndis/madge/driver/head_mod/hwi_pnp.h
new file mode 100644
index 000000000..4bed4f1e9
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_mod/hwi_pnp.h
@@ -0,0 +1,72 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE HARDWARE INTERFACE MODULE (SMART 16 CARDS) */
+/* ============================================== */
+/* */
+/* HWI_PNP.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1990-1994 */
+/* Developed by AC */
+/* From code by MF */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* The purpose of the Hardware Interface (HWI) is to supply an adapter card */
+/* independent interface to any driver. It performs nearly all of the */
+/* functions that involve affecting SIF registers on the adapter cards. */
+/* This includes downloading code to, initializing, and removing adapters. */
+/* */
+/* The HWI_PNP.H file contains the exported function definitions for the */
+/* HWI_PNP.C module. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this HWI_PNP.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_HWI_PNP_H 221
+
+
+/****************************************************************************/
+
+extern WBOOLEAN hwi_pnp_install_card(
+
+ ADAPTER * adapter,
+ DOWNLOAD_IMAGE * download_image
+ );
+
+extern void hwi_pnp_interrupt_handler(
+
+ ADAPTER * adapter
+ );
+
+extern void hwi_pnp_remove_card(
+
+ ADAPTER * adapter
+ );
+
+extern void hwi_pnp_set_dio_address(
+
+ ADAPTER * adapter,
+ DWORD dio_address
+ );
+#ifndef FTK_NO_PROBE
+export UINT
+hwi_pnp_probe_card(
+ PROBE * resources,
+ UINT length,
+ WORD * valid_locations,
+ UINT number_locations
+ );
+#endif
+
+/* */
+/* */
+/************** End of HWI_PNP.H file ***************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_mod/hwi_sm16.h b/private/ntos/ndis/madge/driver/head_mod/hwi_sm16.h
new file mode 100644
index 000000000..23a9df200
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_mod/hwi_sm16.h
@@ -0,0 +1,70 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE HARDWARE INTERFACE MODULE (SMART 16 CARDS) */
+/* ============================================== */
+/* */
+/* HWI_SM16.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1994 */
+/* Developed by AC */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* The purpose of the Hardware Interface (HWI) is to supply an adapter card */
+/* independent interface to any driver. It performs nearly all of the */
+/* functions that involve affecting SIF registers on the adapter cards. */
+/* This includes downloading code to, initializing, and removing adapters. */
+/* */
+/* The HWI_SM16.H file contains the exported function definitions for the */
+/* HWI_SM16.C module. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this HWI_SM16.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_HWI_SM16_H 221
+
+
+/****************************************************************************/
+
+export UINT hwi_smart16_probe_card(
+
+ PROBE * resources,
+ UINT length,
+ WORD * valid_locations,
+ UINT number_locations
+ );
+
+extern WBOOLEAN hwi_smart16_install_card(
+
+ ADAPTER * adapter,
+ DOWNLOAD_IMAGE * download_image
+ );
+
+extern void hwi_smart16_interrupt_handler(
+
+ ADAPTER * adapter
+ );
+
+extern void hwi_smart16_remove_card(
+
+ ADAPTER * adapter
+ );
+
+extern void hwi_smart16_set_dio_address(
+
+ ADAPTER * adapter,
+ DWORD dio_address
+ );
+
+/* */
+/* */
+/************** End of HWI_SM16.H file **************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_mod/sys_allo.h b/private/ntos/ndis/madge/driver/head_mod/sys_allo.h
new file mode 100644
index 000000000..4a959b90f
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_mod/sys_allo.h
@@ -0,0 +1,95 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE DOS SYSTEM SPECIFIC MODULE (ALLOCATE/FREE MEMORY) */
+/* ===================================================== */
+/* */
+/* SYS_ALLO.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* Developed by MF */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* The purpose of the DOS system specific module is to provide those */
+/* services that are influenced by the operating system. This includes */
+/* memory allocation routines, interrupt and DMA channel enabling/disabling */
+/* routines, and routines for accessing IO ports. */
+/* */
+/* The SYS_ALLO.H file contains the exported function definitions for the */
+/* SYS_ALLO.C module. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this SYS_ALLO.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_SYS_ALLO_H 221
+
+
+/****************************************************************************/
+
+extern BYTE * sys_alloc_init_block(
+
+ ADAPTER_HANDLE adapter_handle,
+ WORD init_block_byte_size
+ );
+
+extern BYTE * sys_alloc_adapter_structure(
+
+ ADAPTER_HANDLE adapter_handle,
+ WORD adapter_structure_byte_size
+ );
+
+extern BYTE * sys_alloc_status_structure(
+
+ ADAPTER_HANDLE adapter_handle,
+ WORD status_structure_byte_size
+ );
+
+extern WBOOLEAN sys_alloc_dma_phys_buffer(
+
+ ADAPTER_HANDLE adapter_handle,
+ DWORD buffer_byte_size,
+ DWORD * phys,
+ DWORD * virt
+ );
+
+extern void sys_free_init_block(
+
+ ADAPTER_HANDLE adapter_handle,
+ BYTE * init_block_addr,
+ WORD init_block_byte_size
+ );
+
+extern void sys_free_adapter_structure(
+
+ ADAPTER_HANDLE adapter_handle,
+ BYTE * adapter_structure_addr,
+ WORD adapter_structure_byte_size
+ );
+
+extern void sys_free_status_structure(
+
+ ADAPTER_HANDLE adapter_handle,
+ BYTE * status_structure_addr,
+ WORD status_structure_byte_size
+ );
+
+extern void sys_free_dma_phys_buffer(
+
+ ADAPTER_HANDLE adapter_handle,
+ DWORD buffer_byte_size,
+ DWORD phys,
+ DWORD virt
+ );
+
+/* */
+/* */
+/************** End of SYS_ALLO.H file **************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_mod/sys_buff.h b/private/ntos/ndis/madge/driver/head_mod/sys_buff.h
new file mode 100644
index 000000000..c708440ec
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_mod/sys_buff.h
@@ -0,0 +1,67 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE DOS SYSTEM SPECIFIC MODULE (ALLOCATE/FREE BUFFERS) */
+/* ====================================================== */
+/* */
+/* SYS_BUFF.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* Developed by MF */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* The purpose of the DOS system specific module is to provide those */
+/* services that are influenced by the operating system. This includes */
+/* memory allocation routines, interrupt and DMA channel enabling/disabling */
+/* routines, and routines for accessing IO ports. */
+/* */
+/* The SYS_BUFF.H file contains the exported function definitions for the */
+/* SYS_BUFF.ASM module. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this SYS_BUFF.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_SYS_BUFF_H 221
+
+
+/****************************************************************************/
+
+extern DWORD sys_alloc_transmit_buffer(
+
+ ADAPTER_HANDLE adapter_handle,
+ WORD transmit_buffer_byte_size
+ );
+
+extern DWORD sys_alloc_receive_buffer(
+
+ ADAPTER_HANDLE adapter_handle,
+ WORD receive_buffer_byte_size
+ );
+
+extern void sys_free_transmit_buffer(
+
+ ADAPTER_HANDLE adapter_handle,
+ DWORD transmit_buffer_physaddr,
+ WORD transmit_buffer_byte_size
+ );
+
+extern void sys_free_receive_buffer(
+
+ ADAPTER_HANDLE adapter_handle,
+ DWORD receive_buffer_physaddr,
+ WORD receive_buffer_byte_size
+ );
+
+/* */
+/* */
+/************** End of SYS_BUFF.H file **************************************/
+/* */
+/* */
+
diff --git a/private/ntos/ndis/madge/driver/head_mod/sys_cs.h b/private/ntos/ndis/madge/driver/head_mod/sys_cs.h
new file mode 100644
index 000000000..14ea4dfd9
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_mod/sys_cs.h
@@ -0,0 +1,651 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE DOS SYSTEM SPECIFIC MODULE (INTERFACE TO PCMCIA CARD SERVICES) */
+/* ================================================================== */
+/* */
+/* SYS_CS.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* Developed by VL */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* The purpose of the DOS system specific module is to provide those */
+/* services that are influenced by the operating system. This includes */
+/* memory allocation routines, interrupt and DMA channel enabling/disabling */
+/* routines, and routines for accessing IO ports. */
+/* */
+/* This SYS_CS.H file contains the exported function definitions for the */
+/* SYS_CS.ASM module. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this SYS_CS.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_SYS_CS_H 221
+
+/****************************************************************************/
+/* */
+/* Routine to invoke PCMCIA Card Services. */
+/* */
+/* PCMCIA spec. defines card services as: */
+/* */
+/* Status = CardServices (Function, Handle, Pointer, ArgLength, ArgPointer) */
+/* */
+/* Note that Handle and Pointer can be both input and output argument. So */
+/* in our C function, the second and third argument are pointer to Handle */
+/* and pointer to Pointer respectively. */
+/* */
+/* NOTE THAT NO ARGUMENT CHECKING IS DONE HERE, MAKE SURE THAT YOU PASS IN */
+/* CORRECT ARGUMENTS. */
+/* */
+
+extern WORD CardServices (
+ BYTE Function,
+ WORD FAR * PHandle,
+ void * FAR * PPointer,
+ WORD ArgLength,
+ BYTE FAR * ArgPointer );
+
+
+/****************************************************************************/
+/* */
+/* This is the prototype of the Callback function. When user make */
+/* RegisterClient call to card services, pointer to callback function must */
+/* be supplied. Card Services will then notify the user of any event by */
+/* calling this Callback function. */
+/* */
+
+extern WORD Callback (
+ WORD Function,
+ WORD Socket,
+ WORD Info,
+ void FAR * MTDRequest,
+ void FAR * Buffer,
+ WORD Misc,
+ WORD ClientData1,
+ WORD ClientData2,
+ WORD ClientData3 );
+
+
+
+/****************************************************************************/
+/* */
+/* #DEFINES */
+/* ======== */
+
+
+/****************************************************************************/
+/* */
+/* This is the version number of the Card Services specification upon which */
+/* the following Card Services constants are based. It is stored in BCD */
+/* format. */
+
+#define CARD_SERVICES_VERSION 0x0201
+
+
+/****************************************************************************/
+/* */
+/* This is the version number of the Socket Services specification upon */
+/* which the following Socket Services constants are based. It is stored in */
+/* BCD format. */
+/* */
+
+#define SOCKET_SERVICES_VERSION 0x0210
+
+
+/****************************************************************************/
+/* */
+/* These are the Card Services Functions available through the CardServices */
+/* Function call to Socket Services. */
+/* */
+
+#define CS_GetCardServicesInfo 0x0B
+#define CS_RegisterClient 0x10
+#define CS_DeregisterClient 0x02
+#define CS_GetStatus 0x0C
+#define CS_ResetCard 0x11
+#define CS_SetEventMask 0x31
+#define CS_GetEventMask 0x2E
+
+#define CS_RequestIO 0x1F
+#define CS_ReleaseIO 0x1B
+#define CS_RequestIRQ 0x20
+#define CS_ReleaseIRQ 0x1C
+#define CS_RequestWindow 0x21
+#define CS_ModifyWindow 0x17
+#define CS_ReleaseWindow 0x1D
+#define CS_MapMemPage 0x14
+#define CS_RequestSocketMask 0x22
+#define CS_ReleaseSocketMask 0x2F
+#define CS_RequestConfiguration 0x30
+#define CS_GetConfiguration 0x04
+#define CS_ModifyConfiguration 0x27
+#define CS_ReleaseConfiguration 0x1E
+
+#define CS_OpenMemory 0x18
+#define CS_ReadMemory 0x19
+#define CS_WriteMemory 0x24
+#define CS_CopyMemory 0x01
+#define CS_RegisterEraseQueue 0x0F
+#define CS_CheckEraseQueue 0x26
+#define CS_DeregisterEraseQueue 0x25
+#define CS_CloseMemory 0x00
+
+#define CS_GetFirstTuple 0x07
+#define CS_GetNextTuple 0x0A
+#define CS_GetTupleData 0x0D
+#define CS_GetFirstRegion 0x06
+#define CS_GetNextRegion 0x09
+#define CS_GetFirstPartition 0x05
+#define CS_GetNextPartition 0x08
+
+#define CS_ReturnSSEntry 0x23
+#define CS_MapLogSocket 0x12
+#define CS_MapPhySocket 0x15
+#define CS_MapLogWindow 0x13
+#define CS_MapPhyWindow 0x16
+#define CS_RegisterMTD 0x1A
+#define CS_RegisterTimer 0x38
+#define CS_SetRegion 0x39
+#define CS_ValidateCIS 0x2B
+#define CS_RequestExclusive 0x2C
+#define CS_ReleaseExclusive 0x2D
+#define CS_GetFirstClient 0x0E
+#define CS_GetNextClient 0x2A
+#define CS_GetClientInfo 0x03
+#define CS_AddSocketServices 0x32
+#define CS_ReplaceSocketServices 0x33
+#define CS_VendorSpecific 0x34
+#define CS_AdjustResourceInfo 0x35
+
+#define CS_AccessConfigurationRegister 0x36
+
+
+/****************************************************************************/
+/* */
+/* These are the Card Services Callback Function codes */
+/* */
+
+#define BATTERY_DEAD 0x01
+#define BATTERY_LOW 0x02
+#define CARD_LOCK 0x03
+#define CARD_READY 0x04
+#define CARD_REMOVAL 0x05
+#define CARD_UNLOCK 0x06
+#define EJECTION_COMPLETE 0x07
+#define EJECTION_REQUEST 0x08
+#define INSERTION_COMPLETE 0x09
+#define INSERTION_REQUEST 0x0A
+#define EXCLUSIVE_COMPLETE 0x0D
+#define EXCLUSIVE_REQUEST 0x0E
+#define RESET_PHYSICAL 0x0F
+#define RESET_REQUEST 0x10
+#define CARD_RESET 0x11
+#define CLIENT_INFO 0x14
+#define TIMER_EXPIRED 0x15
+#define SS_UPDATED 0x16
+#define CARD_INSERTION 0x40
+#define RESET_COMPLETE 0x80
+#define REGISTRATION_COMPLETE 0x82
+
+
+/****************************************************************************/
+/* */
+/* These are the SocketServices/CardServices Return codes */
+/* */
+
+#define CMD_SUCCESS 0x00
+#define BAD_ADAPTER 0x01
+#define BAD_ATTRIBUTE 0x02
+#define BAD_BASE 0x03
+#define BAD_EDC 0x04
+#define BAD_IRQ 0x06
+#define BAD_OFFSET 0x07
+#define BAD_PAGE 0x08
+#define READ_FAILURE 0x09
+#define BAD_SIZE 0x0A
+#define BAD_SOCKET 0x0B
+#define BAD_TYPE 0x0D
+#define BAD_VCC 0x0E
+#define BAD_VPP 0x0F
+#define BAD_WINDOW 0x11
+#define WRITE_FAILURE 0x12
+#define NO_CARD 0x14
+#define BAD_FUNCTION 0x15
+#define BAD_MODE 0x16
+#define BAD_SPEED 0x17
+#define BUSY 0x18
+#define GENERAL_FAILURE 0x19
+#define WRITE_PROTECTED 0x1A
+#define BAD_ARG_LENGTH 0x1B
+#define BAD_ARGS 0x1C
+#define CONFIGURATION_LOCKED 0x1D
+#define IN_USE 0x1E
+#define NO_MORE_ITEMS 0x1F
+#define OUT_OF_RESOURCE 0x20
+#define BAD_HANDLE 0x21
+
+
+
+/****************************************************************************/
+/* */
+/* These are the bit definitions for Event Mask Functions */
+/* */
+
+#define MASK_WRITE_PROTECT 0x0001
+#define MASK_CARD_LOCK 0x0002
+#define MASK_EJECTION 0x0004
+#define MASK_INSERTION 0x0008
+#define MASK_BATTERY_DEAD 0x0010
+#define MASK_BATTERY_LOW 0x0020
+#define MASK_READY 0x0040
+#define MASK_CARD_DETECT 0x0080
+#define MASK_PM 0x0100
+#define MASK_RESET 0x0200
+#define MASK_SS_UPDATE 0x0400
+
+/****************************************************************************/
+/* */
+/* These are the bit definition for RegisterClient attribute */
+/* */
+
+#define RC_ATTR_MEMORY_CLIENT_DRIVER 0x0001
+#define RC_ATTR_MEMORY_TECH_DRIVER 0x0002
+#define RC_ATTR_IO_CLIENT_DEVICE_DRIVER 0x0004
+#define RC_ATTR_IO_INSERTION_SHARABLE 0x0008
+#define RC_ATTR_IO_INSERTION_EXCLUSIVE 0x0010
+
+/****************************************************************************/
+/* */
+/* These are definition for AdjustResourceInfo Action */
+/* */
+
+#define ARI_ACTION_REMOVE 0x00
+#define ARI_ACTION_ADD 0x01
+#define ARI_ACTION_GET_FIRST 0x02
+#define ARI_ACTION_GET_NEXT 0x03
+
+/****************************************************************************/
+/* */
+/* These are definition for AdjustResourceInfo Resource */
+/* */
+
+#define ARI_RESOURCE_MEMORY 0x00
+#define ARI_RESOURCE_IO 0x01
+#define ARI_RESOURCE_IRQ 0x02
+
+/****************************************************************************/
+/* */
+/* These are definition for RequestIO Attributes */
+/* */
+
+#define RIO_ATTR_SHARED 0x01
+#define RIO_ATTR_FIRST_SHARED 0x02
+#define RIO_ATTR_FORCE_ALIAS_ACCESS 0x04
+#define RIO_ATTR_16_BIT_DATA 0x08
+
+/****************************************************************************/
+/* */
+/* These are definition for RequestIRQ Attributes */
+/* */
+
+#define RIRQ_ATTR_TYPE_EXCLUSIVE 0x0000
+#define RIRQ_ATTR_TYPE_TIME_MULTIPLEX 0x0001
+#define RIRQ_ATTR_TYPE_DYMANIC_SHARE 0x0002
+#define RIRQ_ATTR_TYPE_RESERVED 0x0003
+
+
+/****************************************************************************/
+/* */
+/* These are definition for RequestIRQ IRQInfos */
+/* */
+
+
+#define IRQ_INFO1_INFO2_ENABLE 0x10
+
+#define IRQ_INFO1_LEVEL 0x20
+#define IRQ_INFO1_PULSE 0x40
+#define IRQ_INFO1_SHARE 0x80
+
+#define IRQ_0 0x0001
+#define IRQ_1 0x0002
+#define IRQ_2 0x0004
+#define IRQ_3 0x0008
+#define IRQ_4 0x0010
+#define IRQ_5 0x0020
+#define IRQ_6 0x0040
+#define IRQ_7 0x0080
+#define IRQ_8 0x0100
+#define IRQ_9 0x0200
+#define IRQ_10 0x0400
+#define IRQ_11 0x0800
+#define IRQ_12 0x1000
+#define IRQ_13 0x2000
+#define IRQ_14 0x4000
+#define IRQ_15 0x8000
+
+/****************************************************************************/
+/* */
+/* These are RequestConfiguration related things */
+/* */
+
+#define RC_ATTR_ENABLE_IRQ_STEERING 0x02
+
+
+#define RC_PRESENT_OPTION_REG 0x01
+#define RC_PRESENT_STATUS_REG 0x02
+#define RC_PRESENT_PIN_REPLACEMENT 0x04
+#define RC_PRESENT_COPY_REG 0x08
+
+#define RC_INTTYPE_MEMORY 0x01
+#define RC_INTTYPE_MEMORY_AND_IO 0x02
+
+
+/****************************************************************************/
+/* */
+/* These are AccessConfigurationRegister related things */
+/* */
+
+#define ACR_ACTION_READ 0x00
+#define ACR_ACTION_WRITE 0x01
+
+
+/****************************************************************************/
+/* */
+/* These are the codes for tuples within the CIS (Card Information */
+/* Structure) */
+/* */
+
+#define CISTPL_NULL 0x00
+#define CISTPL_DEVICE 0x01
+#define CISTPL_CHECKSUM 0x10
+#define CISTPL_LONGLINK_A 0x11
+#define CISTPL_LONGLINK_C 0x12
+#define CISTPL_LINKTARGET 0x13
+#define CISTPL_NO_LINK 0x14
+#define CISTPL_VERS_1 0x15
+#define CISTPL_ALTSTR 0x16
+#define CISTPL_DEVICE_A 0x17
+#define CISTPL_JEDEC_C 0x18
+#define CISTPL_JEDEC_A 0x19
+#define CISTPL_CONFIG 0x1A
+#define CISTPL_CFTABLE_ENTRY 0x1B
+#define CISTPL_DEVICE_OC 0x1C
+#define CISTPL_DEVICE_OA 0x1D
+#define CISTPL_DEVICE_GEO 0x1E
+#define CISTPL_DEVICE_GEO_A 0x1F
+
+#define CISTPL_MANFID 0x20
+#define CISTPL_FUNCID 0x21
+#define CISTPL_FUNCE 0x22
+#define CISTPL_SWIL 0x23
+#define CISTPL_VERS_2 0x40
+#define CISTPL_FORMAT 0x41
+#define CISTPL_GEOMETRY 0x42
+#define CISTPL_BYTEORDER 0x43
+#define CISTPL_DATE 0x44
+#define CISTPL_BATTERY 0x45
+
+
+/****************************************************************************/
+/* */
+/* These are argument block definitions for various card services functions */
+/* */
+/****************************************************************************/
+/* */
+
+/****************************************************************************/
+/* */
+/* Argument for GetCardServicesInfo */
+/* */
+
+struct STRUCT_CS_GET_CS_INFO_ARG
+{
+ WORD InfoLen;
+ BYTE Signature[2];
+ WORD Count;
+ WORD Revision;
+ WORD CSLevel;
+ WORD VStrOff;
+ WORD VStrLen;
+ BYTE VendorString[1];
+};
+
+typedef struct STRUCT_CS_GET_CS_INFO_ARG CS_GET_CS_INFO_ARG;
+
+
+/****************************************************************************/
+/* */
+/* Argument for RegisterClient */
+/* */
+
+struct STRUCT_CS_REGISTER_CLIENT_ARG
+{
+ WORD Attributes;
+ WORD EventMask;
+ WORD ClientData[4];
+ WORD Version;
+};
+
+typedef struct STRUCT_CS_REGISTER_CLIENT_ARG CS_REGISTER_CLIENT_ARG;
+
+
+/****************************************************************************/
+/* */
+/* Argument for GetFirstTuple */
+/* */
+
+struct STRUCT_CS_GET_FIRST_TUPLE_ARG
+{
+ WORD Socket;
+ WORD Attributes;
+ BYTE DesiredTuple;
+ BYTE Reserved;
+ WORD Flags;
+ DWORD LinkOffset;
+ DWORD CISOffset;
+ BYTE TupleCode;
+ BYTE TupleLink;
+};
+
+typedef struct STRUCT_CS_GET_FIRST_TUPLE_ARG CS_GET_FIRST_TUPLE_ARG;
+
+
+/****************************************************************************/
+/* */
+/* Argument for GetTupleData */
+/* */
+
+struct STRUCT_CS_GET_TUPLE_DATA_ARG
+{
+ WORD Socket;
+ WORD Attributes;
+ BYTE DesiredTuples;
+ BYTE TupleOffset;
+ WORD Flags;
+ DWORD LinkOffset;
+ DWORD CISOffset;
+ WORD TupleDataMax;
+ WORD TupleDataLen;
+ BYTE TupleData[1];
+};
+
+typedef struct STRUCT_CS_GET_TUPLE_DATA_ARG CS_GET_TUPLE_DATA_ARG;
+
+
+
+/****************************************************************************/
+/* */
+/* Argument for AdjustResouceInfo ( IO resources ) */
+/* */
+
+struct STRUCT_CS_ADJ_IO_RESOURCE_ARG
+{
+ BYTE Action;
+ BYTE Resource;
+ WORD BasePort;
+ BYTE NumPorts;
+ BYTE Attributes;
+ BYTE IOAddrLines;
+};
+
+typedef struct STRUCT_CS_ADJ_IO_RESOURCE_ARG CS_ADJ_IO_RESOURCE_ARG;
+
+
+/****************************************************************************/
+/* */
+/* Argument for RequestIO */
+/* */
+
+struct STRUCT_CS_REQUEST_IO_ARG
+{
+ WORD Socket;
+ WORD BasePort1;
+ BYTE NumPorts1;
+ BYTE Attributes1;
+ WORD BasePort2;
+ BYTE NumPorts2;
+ BYTE Attributes2;
+ BYTE IOAddrLines;
+
+};
+
+typedef struct STRUCT_CS_REQUEST_IO_ARG CS_REQUEST_IO_ARG;
+
+/****************************************************************************/
+/* */
+/* Argument for RequestIRQ */
+/* */
+
+struct STRUCT_CS_REQUEST_IRQ_ARG
+{
+ WORD Socket;
+ WORD Attributes;
+ BYTE AssignedIRQ;
+ BYTE IRQInfo1;
+ WORD IRQInfo2;
+};
+
+typedef struct STRUCT_CS_REQUEST_IRQ_ARG CS_REQUEST_IRQ_ARG;
+
+
+/****************************************************************************/
+/* */
+/* Argument for RequestConfiguration */
+/* */
+
+struct STRUCT_CS_REQUEST_CONFIG_ARG
+{
+ WORD Socket;
+ WORD Attributes;
+ BYTE Vcc;
+ BYTE Vpp1;
+ BYTE Vpp2;
+ BYTE IntType;
+ DWORD ConfigBase;
+ BYTE Status;
+ BYTE Pin;
+ BYTE Copy;
+ BYTE ConfigIndex;
+ BYTE Present;
+};
+
+typedef struct STRUCT_CS_REQUEST_CONFIG_ARG CS_REQUEST_CONFIG_ARG;
+
+
+/****************************************************************************/
+/* */
+/* Argument for AccessConfigurationRegister */
+/* */
+
+struct STRUCT_CS_ACCESS_CONFIG_REG_ARG
+{
+ WORD Socket;
+ BYTE Action;
+ BYTE Offset;
+ BYTE Value;
+};
+
+typedef struct STRUCT_CS_ACCESS_CONFIG_REG_ARG CS_ACCESS_CONFIG_REG_ARG;
+
+/****************************************************************************/
+/* */
+/* Argument for ReleaseIO */
+/* */
+
+struct STRUCT_CS_RELEASE_IO_ARG
+{
+ WORD Socket;
+ WORD BasePort1;
+ BYTE NumPorts1;
+ BYTE Attributes1;
+ WORD BasePort2;
+ BYTE NumPorts2;
+ BYTE Attributes2;
+ BYTE IOAddrLines;
+};
+
+typedef struct STRUCT_CS_RELEASE_IO_ARG CS_RELEASE_IO_ARG;
+
+
+/****************************************************************************/
+/* */
+/* Argument for ReleaseIRQ */
+/* */
+
+struct STRUCT_CS_RELEASE_IRQ_ARG
+{
+ WORD Socket;
+ WORD Attributes;
+ BYTE AssignedIRQ;
+};
+
+typedef struct STRUCT_CS_RELEASE_IRQ_ARG CS_RELEASE_IRQ_ARG;
+
+
+/****************************************************************************/
+/* */
+/* Argument for ReleaseConfiguration */
+/* */
+
+struct STRUCT_CS_RELEASE_CONFIG_ARG
+{
+ WORD Socket;
+};
+
+typedef struct STRUCT_CS_RELEASE_CONFIG_ARG CS_RELEASE_CONFIG_ARG;
+
+
+/****************************************************************************/
+/* */
+/* Client Information Structure */
+/* */
+
+struct STRUCT_CS_CLIENT_INFO
+{
+ WORD MaxLen;
+ WORD InfoLen;
+ WORD Atrributes;
+ WORD Revision;
+ WORD CSLevel;
+ WORD RevDate;
+ WORD NameOff;
+ WORD NameLen;
+ WORD VStringOff;
+ WORD VStringLen;
+};
+
+typedef struct STRUCT_CS_CLIENT_INFO CS_CLIENT_INFO;
+
+/* */
+/* */
+/************** End of SYS_CS.H file ****************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_mod/sys_dma.h b/private/ntos/ndis/madge/driver/head_mod/sys_dma.h
new file mode 100644
index 000000000..7e29b6315
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_mod/sys_dma.h
@@ -0,0 +1,60 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE DOS SYSTEM SPECIFIC MODULE (DMA) */
+/* ==================================== */
+/* */
+/* SYS_DMA.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* Developed by MF */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* The purpose of the DOS system specific module is to provide those */
+/* services that are influenced by the operating system. This includes */
+/* DMAory allocation routines, interrupt and DMA channel enabling/disabling */
+/* routines, and routines for accessing IO ports. */
+/* */
+/* The SYS_DMA.H file contains the exported function definitions for the */
+/* SYS_DMA.ASM module. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this SYS_DMA.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_SYS_DMA_H 221
+
+
+/****************************************************************************/
+
+extern WBOOLEAN sys_enable_dma_channel(
+
+ ADAPTER_HANDLE adapter_handle,
+ WORD dma_channel
+ );
+
+extern void sys_disable_dma_channel(
+
+ ADAPTER_HANDLE adapter_handle,
+ WORD dma_channel
+ );
+
+extern WORD sys_atula_find_dma_channel(
+
+ WORD io_on_off_location,
+ BYTE dma_on_byte,
+ BYTE dma_off_byte
+ );
+
+
+/* */
+/* */
+/************** End of SYS_DMA.H file ***************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_mod/sys_irq.h b/private/ntos/ndis/madge/driver/head_mod/sys_irq.h
new file mode 100644
index 000000000..4e8db1d8f
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_mod/sys_irq.h
@@ -0,0 +1,65 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE DOS SYSTEM SPECIFIC MODULE (INTERRUPT) */
+/* ========================================== */
+/* */
+/* SYS_IRQ.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* Developed by MF */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* The purpose of the DOS system specific module is to provide those */
+/* services that are influenced by the operating system. This includes */
+/* IRQory allocation routines, interrupt and DMA channel enabling/disabling */
+/* routines, and routines for accessing IO ports. */
+/* */
+/* The SYS_IRQ.H file contains the exported function definitions for the */
+/* SYS_IRQ.ASM module. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this SYS_IRQ.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_SYS_IRQ_H 221
+
+
+/****************************************************************************/
+
+extern WBOOLEAN sys_enable_irq_channel(
+
+ ADAPTER_HANDLE adapter_handle,
+ WORD interrupt_number
+ );
+
+extern void sys_disable_irq_channel(
+
+ ADAPTER_HANDLE adapter_handle,
+ WORD interrupt_number
+ );
+
+extern void sys_clear_controller_interrupt(
+
+ ADAPTER_HANDLE adapter_handle,
+ WORD interrupt_number
+ );
+
+extern WORD sys_atula_find_irq_channel(
+
+ WORD io_on_off_location,
+ BYTE irq_on_byte,
+ BYTE irq_off_byte
+ );
+
+/* */
+/* */
+/************** End of SYS_IRQ.H file ***************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_mod/sys_mem.h b/private/ntos/ndis/madge/driver/head_mod/sys_mem.h
new file mode 100644
index 000000000..ebcc6670b
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_mod/sys_mem.h
@@ -0,0 +1,206 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE DOS SYSTEM SPECIFIC MODULE (MEMORY IO) */
+/* ========================================== */
+/* */
+/* SYS_MEM.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* Developed by MF */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* The purpose of the DOS system specific module is to provide those */
+/* services that are influenced by the operating system. This includes */
+/* memory allocation routines, interrupt and DMA channel enabling/disabling */
+/* routines, and routines for accessing IO ports. */
+/* */
+/* The SYS_MEM.H file contains the exported function definitions for the */
+/* SYS_MEM.ASM module. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this SYS_MEM.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_SYS_MEM_H 221
+
+
+/****************************************************************************/
+
+extern void sys_enable_io(
+
+ WORD io_location,
+ WORD io_range
+ );
+
+extern void sys_disable_io(
+
+ WORD io_location,
+ WORD io_range
+ );
+
+extern WORD sys_insw(
+
+ ADAPTER_HANDLE adapter_handle,
+ WORD input_location
+ );
+
+extern BYTE sys_insb(
+
+ ADAPTER_HANDLE adapter_handle,
+ WORD input_location
+ );
+
+extern void sys_outsw(
+
+ ADAPTER_HANDLE adapter_handle,
+ WORD output_location,
+ WORD output_word
+ );
+
+extern void sys_outsb(
+
+ ADAPTER_HANDLE adapter_handle,
+ WORD output_location,
+ BYTE output_byte
+ );
+
+extern WORD sys_probe_insw(
+
+ WORD input_location
+ );
+
+extern BYTE sys_probe_insb(
+
+ WORD input_location
+ );
+
+extern void sys_probe_outsw(
+
+ WORD output_location,
+ WORD output_word
+ );
+
+extern void sys_probe_outsb(
+
+ WORD output_location,
+ BYTE output_byte
+ );
+
+extern void sys_rep_insw(
+
+ ADAPTER_HANDLE adapter_handle,
+ WORD input_location,
+ BYTE FAR * destination_address,
+ WORD length_in_words
+ );
+
+extern void sys_rep_swap_insw(
+
+ ADAPTER_HANDLE adapter_handle,
+ WORD input_location,
+ BYTE FAR * destination_address,
+ WORD length_in_words
+ );
+
+extern void sys_rep_outsw(
+
+ ADAPTER_HANDLE adapter_handle,
+ WORD output_location,
+ BYTE FAR * source_address,
+ WORD length_in_words
+ );
+
+extern void sys_rep_swap_outsw(
+
+ ADAPTER_HANDLE adapter_handle,
+ WORD output_location,
+ BYTE FAR * source_address,
+ WORD length_in_words
+ );
+
+extern void sys_rep_insd(
+
+ ADAPTER_HANDLE adapter_handle,
+ WORD input_location,
+ BYTE FAR * destination_address,
+ WORD length_in_dwords
+ );
+
+extern void sys_rep_outsd(
+
+ ADAPTER_HANDLE adapter_handle,
+ WORD output_location,
+ BYTE FAR * source_address,
+ WORD length_in_dwords
+ );
+
+extern DWORD sys_phys_to_virt(
+
+ ADAPTER_HANDLE adapter_handle,
+ DWORD physaddr
+ );
+
+
+extern DWORD sys_virt_to_phys(
+
+ ADAPTER_HANDLE adapter_handle,
+ void FAR * virtaddr
+ );
+
+export void sys_rep_movsd_to(
+
+ ADAPTER_HANDLE adapter_handle,
+ DWORD SourcePtr,
+ DWORD DestPtr,
+ WORD TransferSize
+ );
+
+
+export void sys_rep_movsd_from(
+
+ ADAPTER_HANDLE adapter_handle,
+ DWORD SourcePtr,
+ DWORD DestPtr,
+ WORD TransferSize
+ );
+
+export void sys_movsd_from(
+
+ ADAPTER_HANDLE adapter_handle,
+ DWORD SourcePtr,
+ DWORD DestPtr
+ );
+
+export void sys_movsd_to(
+
+ ADAPTER_HANDLE adapter_handle,
+ DWORD SourcePtr,
+ DWORD DestPtr
+ );
+
+export void sys_mem_copy(
+
+ BYTE FAR * destination_ptr,
+ BYTE FAR * source_ptr,
+ WORD byte_count
+ );
+
+extern WBOOLEAN sys_sync_with_interrupt(
+
+ ADAPTER_HANDLE adapter_handle,
+ WBOOLEAN (*f)(void *),
+ void * ptr
+ );
+
+/* */
+/* */
+/************** End of SYS_MEM.H file ***************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_mod/sys_pci.h b/private/ntos/ndis/madge/driver/head_mod/sys_pci.h
new file mode 100644
index 000000000..6b0faf0ba
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_mod/sys_pci.h
@@ -0,0 +1,93 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE DOS SYSTEM SPECIFIC MODULE (PCI BIOS) */
+/* ========================================= */
+/* */
+/* SYS_PCI.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* Developed by PRR */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* The purpose of the DOS system specific module is to provide those */
+/* services that are influenced by the operating system. This includes */
+/* routines for accessing PCI configuration info. */
+/* */
+/* The SYS_PCI.H file contains the exported function definitions for the */
+/* SYS_PCI.ASM module. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this SYS_MEM.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_SYS_PCI_H 221
+
+export WBOOLEAN sys_pci_valid_machine( void );
+
+export WBOOLEAN sys_pci_read_config_dword(
+
+ ADAPTER_HANDLE adapter_handle,
+ WORD index,
+ DWORD * dword_ptr
+ );
+
+export WBOOLEAN sys_pci_read_config_word(
+
+ ADAPTER_HANDLE adapter_handle,
+ WORD index,
+ WORD * dword_ptr
+ );
+
+export WBOOLEAN sys_pci_read_config_byte(
+
+ ADAPTER_HANDLE adapter_handle,
+ WORD index,
+ BYTE * byte_ptr
+ );
+
+export WBOOLEAN sys_pci_write_config_dword(
+
+ ADAPTER_HANDLE adapter_handle,
+ WORD index,
+ DWORD dword
+ );
+
+export WBOOLEAN sys_pci_write_config_word(
+
+ ADAPTER_HANDLE adapter_handle,
+ WORD index,
+ WORD word
+ );
+
+export WBOOLEAN sys_pci_write_config_byte(
+
+ ADAPTER_HANDLE adapter_handle,
+ WORD index,
+ BYTE byte
+ );
+
+export WBOOLEAN sys_pci_find_card( WORD FAR * PCIHandlePtr,
+ WORD Index,
+ WORD DeviceID);
+
+export WBOOLEAN sys_pci_get_io_base(WORD PCIHandle,
+ WORD FAR * BaseAddressPtr );
+
+export WBOOLEAN sys_pci_get_irq( WORD PCIHandle,
+ WORD FAR * IRQPtr );
+
+export WORD sys_pci_get_mem( WORD PCIHandle,
+ DWORD FAR * MemPtr);
+
+/* */
+/* */
+/************** End of SYS_PCI.H file ***************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_mod/sys_pcmc.h b/private/ntos/ndis/madge/driver/head_mod/sys_pcmc.h
new file mode 100644
index 000000000..9c16efca4
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_mod/sys_pcmc.h
@@ -0,0 +1,50 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE DOS SYSTEM SPECIFIC MODULE (MEMORY IO) */
+/* ========================================== */
+/* */
+/* SYS_PCMC.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* Developed by MF */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* The purpose of the DOS system specific module is to provide those */
+/* services that are influenced by the operating system. This includes */
+/* memory allocation routines, interrupt and DMA channel enabling/disabling */
+/* routines, and routines for accessing IO ports. */
+/* */
+/* The SYS_PCMC.H file contains the exported function definitions for the */
+/* SYS_PCMC.C module. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this SYS_MEM.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_SYS_PCMC_H 221
+
+
+/****************************************************************************/
+
+extern WBOOLEAN sys_pcmcia_point_enable(
+
+ ADAPTER* adapter
+ );
+
+extern void sys_pcmcia_point_disable(
+
+ ADAPTER* adapter
+ );
+
+/* */
+/* */
+/************** End of SYS_PCMC.H file **************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_mod/sys_time.h b/private/ntos/ndis/madge/driver/head_mod/sys_time.h
new file mode 100644
index 000000000..b4a3932cd
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_mod/sys_time.h
@@ -0,0 +1,52 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE DOS SYSTEM SPECIFIC MODULE (TIMERS) */
+/* ======================================= */
+/* */
+/* SYS_TIME.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* Developed by MF */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* The purpose of the DOS system specific module is to provide those */
+/* services that are influenced by the operating system. This includes */
+/* memory allocation routines, interrupt and DMA channel enabling/disabling */
+/* routines, and routines for accessing IO ports. */
+/* */
+/* The SYS_TIME.H file contains the exported function definitions for the */
+/* SYS_TIME.ASM module. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this SYS_TIME.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_SYS_TIME_H 221
+
+
+/****************************************************************************/
+
+extern void sys_wait_at_least_milliseconds(
+
+ WORD number_of_milliseconds
+ );
+
+extern void sys_wait_at_least_microseconds(
+
+ WORD number_of_microseconds
+ );
+
+
+
+/* */
+/* */
+/************** End of SYS_TIME.H file **************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/head_mod/util.h b/private/ntos/ndis/madge/driver/head_mod/util.h
new file mode 100644
index 000000000..12d5c5ee1
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/head_mod/util.h
@@ -0,0 +1,80 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE UTILITIES MODULE */
+/* ==================== */
+/* */
+/* UTIL.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* Developed by MF */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* The UTIL.C utilities module provides a range of general purpose */
+/* utilities that are used throughout the FTK. These routines provide such */
+/* functions as the ability to copy strings, clear memory, byte swap node */
+/* addresses and caculate the minimum of three values. */
+/* */
+/* The UTIL.H file contains the exported function definitions for the */
+/* UTIL.C module. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this UTIL.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_UTIL_H 221
+
+
+/****************************************************************************/
+
+
+extern void util_string_copy(
+
+ char * copy_to_string,
+ char * copy_from_string
+ );
+
+extern void util_mem_copy(
+ BYTE * copy_to_string,
+ BYTE * copy_from_string,
+ UINT count
+ );
+
+
+extern void util_string_concatenate(
+
+ char * add_to_string,
+ char * string_to_add
+ );
+
+extern UINT util_minimum(
+
+ UINT val_1,
+ UINT val_2,
+ UINT val_3
+ );
+
+extern void util_zero_memory(
+
+ BYTE * memory,
+ UINT size_in_bytes
+ );
+
+extern void util_byte_swap_structure(
+
+ BYTE * byte_based_structure,
+ UINT size_of_structure
+ );
+
+
+/* */
+/* */
+/************** End of UTIL.H file ******************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/hwi_at.c b/private/ntos/ndis/madge/driver/hwi_at.c
new file mode 100644
index 000000000..fa9ed25dc
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/hwi_at.c
@@ -0,0 +1,2206 @@
+/****************************************************************************
+*
+* HWI_AT.C : Part of the FASTMAC TOOL-KIT (FTK)
+*
+* HARDWARE INTERFACE MODULE FOR ATULA CARDS
+*
+* Copyright (c) Madge Networks Ltd. 1990-1994
+*
+* COMPANY CONFIDENTIAL
+*
+*****************************************************************************
+*
+* The purpose of the Hardware Interface (HWI) is to supply an adapter card
+* independent interface to any driver. It performs nearly all of the
+* functions that involve affecting SIF registers on the adapter cards.
+* This includes downloading code to, initializing, and removing adapters.
+*
+* The HWI_AT.C module contains the routines specific to 16/4 PC and 16/4
+* AT cards which are necessary to install an adapter, to initialize an
+* adapter, to remove an adapter and to handle interrupts on an adapter.
+*
+****************************************************************************/
+
+/*---------------------------------------------------------------------------
+|
+| DEFINITIONS
+|
+---------------------------------------------------------------------------*/
+
+#include "ftk_defs.h"
+
+/*---------------------------------------------------------------------------
+|
+| MODULE ENTRY POINTS
+|
+---------------------------------------------------------------------------*/
+
+#include "ftk_intr.h" /* Routines internal to FTK */
+#include "ftk_extr.h" /* Routines provided or used by external FTK user */
+
+#ifndef FTK_NO_ATULA
+
+/*---------------------------------------------------------------------------
+|
+| LOCAL PROCEDURES
+|
+---------------------------------------------------------------------------*/
+
+local void
+hwi_atula_read_node_address(
+ ADAPTER * adapter
+ );
+
+local WBOOLEAN
+hwi_atula_valid_io_location(
+ WORD io_location
+ );
+
+#ifndef FTK_NO_PROBE
+
+local WORD
+hwi_atula_get_irq_channel(
+ WORD io_location,
+ UINT adapter_revision
+ );
+
+local WORD
+hwi_atula_get_dma_channel(
+ WORD io_location,
+ UINT adapter_revsion
+ );
+
+#endif
+
+local WORD
+hwi_atula_valid_transfer_mode(
+ ADAPTER * adapter
+ );
+
+local WORD
+hwi_atula_valid_irq_channel(
+ ADAPTER * adapter
+ );
+
+local WORD
+hwi_atula_valid_dma_channel(
+ ADAPTER * adapter
+ );
+
+/*---------------------------------------------------------------------------
+|
+| LOCAL VARIABLES
+|
+---------------------------------------------------------------------------*/
+
+local BYTE atp_irq_select_table[16] =
+{
+ 0xff, /* 0 Unused */
+ 0xff, /* 1 Unused */
+ 0x07, /* 2 */
+ 0x06, /* 3 */
+ 0xff, /* 4 Unused */
+ 0x05, /* 5 */
+ 0xff, /* 6 Unused */
+ 0x04, /* 7 */
+ 0xff, /* 8 Unused */
+ 0x07, /* 9 */
+ 0x03, /* 10 */
+ 0x02, /* 11 */
+ 0x01, /* 12 */
+ 0xff, /* 13 Unused */
+ 0xff, /* 14 Unused */
+ 0x00 /* 15 */
+};
+
+local BYTE atp_dma_select_table[7] =
+{
+ 0xff, /* 0 Unused */
+ 0xff, /* 1 Unused */
+ 0xff, /* 2 Unused */
+ 0x08, /* 3 */
+ 0xff, /* 4 Unused */
+ 0x10, /* 5 */
+ 0x18 /* 6 */
+};
+
+local WORD adapter_card_at_rmsz_lut[7] =
+{
+ 128, /* 16/4 AT */
+ 128, /* 16/4 AT */
+ 256, /* 16/4 AT */
+ 256, /* 16/4 Fibre AT */
+ 256, /* 16/4 AT Bridgenode */
+ 128, /* 16/4 ISA Client */
+ 512 /* 16/4 AT Plus */
+};
+
+#ifndef FTK_NO_PROBE
+/****************************************************************************
+*
+* hwi_atula_probe_card
+* ====================
+*
+*
+* PARAMETERS (passed by hwi_probe_adapter) :
+* ==========================================
+*
+* PROBE * resources
+*
+* resources is an array structures used to identify and record specific
+* information about adapters found.
+*
+* UINT length
+*
+* length is the number of structures pointed to by reources.
+*
+* WORD * valid_locations
+*
+* valid_locations is an array of IO locations to examine for the presence
+* of an adapter. For ATULA based adapters with should be a subset of
+* {0x0a20, 0x1a20, 0x2a20, 0x3a20}.
+*
+* UINT number_locations
+*
+* This is the number of IO locations in the above list.
+*
+* BODY :
+* ======
+*
+* The hwi_atula_probe_card routine is called by hwi_probe_adapter. It
+* probes the adapter card for information such as DMA channel, IRQ number
+* etc. This information can then be supplied by the user when starting the
+* adapter.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine returns the number of adapters found, or PROBE_FAILURE if
+* there's a problem.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_atula_probe_card)
+#endif
+
+export UINT
+hwi_atula_probe_card(
+ PROBE * resources,
+ UINT length,
+ WORD * valid_locations,
+ UINT number_locations
+ )
+{
+ WBOOLEAN card_found;
+ WORD control_1;
+ WORD control_2;
+ WORD status;
+ WORD control_6;
+ WORD control_7;
+ WORD bia_prom;
+ WORD bia_prom_id;
+ WORD bia_prom_adap;
+ WORD bia_prom_rev;
+ WORD bia_prom_hwf;
+ BYTE bia_temp_bd;
+ BYTE bia_temp_rev;
+ BYTE bia_temp_hwf;
+ UINT i;
+ UINT j;
+
+ /*
+ * Sanity check the bounds.
+ */
+
+ if (length <= 0 || number_locations <= 0)
+ {
+ return PROBE_FAILURE;
+ }
+
+ /*
+ * Validate the IO locations.
+ */
+
+ for (i = 0; i < number_locations; i++)
+ {
+ if (!hwi_atula_valid_io_location(valid_locations[i]))
+ {
+ return PROBE_FAILURE;
+ }
+ }
+
+ /*
+ * j is the number of adapters found.
+ */
+
+ j = 0;
+
+ for (i = 0; i < number_locations; i++)
+ {
+ /*
+ * Make sure that we haven't run out of PROBE structures.
+ */
+
+ if (j >= length)
+ {
+ return j;
+ }
+
+ /*
+ * Set up the ATULA control IO locations.
+ */
+
+ control_1 = valid_locations[i] + ATULA_CONTROL_REGISTER_1;
+ control_2 = valid_locations[i] + ATULA_CONTROL_REGISTER_2;
+ status = valid_locations[i] + ATULA_STATUS_REGISTER;
+ control_6 = valid_locations[i] + ATULA_CONTROL_REGISTER_6;
+ control_7 = valid_locations[i] + ATULA_CONTROL_REGISTER_7;
+ bia_prom = valid_locations[i] + ATULA_BIA_PROM;
+ bia_prom_id = bia_prom + BIA_PROM_ID_BYTE;
+ bia_prom_adap = bia_prom + BIA_PROM_ADAPTER_BYTE;
+ bia_prom_rev = bia_prom + BIA_PROM_REVISION_BYTE;
+ bia_prom_hwf = bia_prom + BIA_PROM_FEATURES_BYTE;
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_probe_enable_io(valid_locations[i], ATULA_IO_RANGE);
+#endif
+
+ /*
+ * Reset adapter (ATULA_CTRL1_NRESET = 0).
+ */
+
+ sys_probe_outsb(control_1, 0);
+
+ /*
+ * Page in first page of BIA PROM.
+ * set ATULA_CTRL7_PAGE = 0 and ATULA_CTRL7_SIFSEL = 0.
+ */
+
+ sys_probe_outsb(control_7, 0);
+
+ /*
+ * Check we have a functioning adapter at the given IO location by
+ * checking the BIA PROM for an 'M' id byte and also by checking that
+ * the BIA adapter card byte is for a supported card type.
+ */
+
+ /*
+ * At the moment there are four major board types that are acceptable
+ * AT, PC, MAXY, and ATP.
+ */
+
+ card_found = FALSE;
+
+ if (sys_probe_insb(bia_prom_id) == 'M')
+ {
+ bia_temp_bd = sys_probe_insb(bia_prom_adap);
+ bia_temp_rev = sys_probe_insb(bia_prom_rev);
+ bia_temp_hwf = sys_probe_insb(bia_prom_hwf);
+
+ if (bia_temp_bd == BIA_PROM_TYPE_16_4_PC)
+ {
+ resources[j].adapter_card_revision = ADAPTER_CARD_16_4_PC;
+ resources[j].adapter_ram_size = 128;
+ card_found = TRUE;
+ }
+ else if (bia_temp_bd == BIA_PROM_TYPE_16_4_MAXY)
+ {
+ resources[j].adapter_card_revision = ADAPTER_CARD_16_4_MAXY;
+ resources[j].adapter_ram_size = 256;
+ card_found = TRUE;
+ }
+ else if (bia_temp_bd == BIA_PROM_TYPE_16_4_AT)
+ {
+ if (bia_temp_rev <= MAX_ADAPTER_CARD_AT_REV)
+ {
+ resources[j].adapter_ram_size = adapter_card_at_rmsz_lut[bia_temp_rev];
+ }
+ else
+ {
+ resources[j].adapter_ram_size = 128;
+ }
+
+ if (bia_temp_rev < ADAPTER_CARD_16_4_AT)
+ {
+ resources[j].adapter_card_revision = ADAPTER_CARD_16_4_AT;
+ }
+ else
+ {
+ resources[j].adapter_card_revision = bia_temp_rev;
+ }
+ card_found = TRUE;
+ }
+ else if (bia_temp_bd == BIA_PROM_TYPE_16_4_AT_P)
+ {
+ resources[j].adapter_ram_size = 512;
+
+ switch(bia_temp_rev)
+ {
+ case ADAPTER_CARD_16_4_FIBRE:
+ resources[j].adapter_card_revision = ADAPTER_CARD_16_4_FIBRE_P;
+ break;
+ case ADAPTER_CARD_16_4_ISA_C:
+ resources[j].adapter_card_revision = ADAPTER_CARD_16_4_ISA_C_P;
+ resources[j].adapter_ram_size = 128;
+ break;
+ case ADAPTER_CARD_16_4_AT_P_REV:
+ resources[j].adapter_card_revision = ADAPTER_CARD_16_4_AT_P;
+ break;
+ default:
+ resources[j].adapter_card_revision = ADAPTER_CARD_UNKNOWN;
+ break;
+ }
+
+ card_found = TRUE;
+ }
+ }
+
+ /*
+ * Check for the features byte - if it is non-zero, it may override our
+ * RAM size calculations.
+ */
+
+ if (bia_temp_hwf)
+ {
+ UINT dram = (bia_temp_hwf & BIA_PROM_FEATURE_DRAM_MASK) * DRAM_MULT;
+
+ if (dram)
+ {
+ resources[j].adapter_ram_size = dram;
+ }
+ }
+
+ /*
+ * If we've found an adapter then we need to make a note of
+ * the IO location and attempt to determine the interrupt
+ * number and DMA channel.
+ */
+
+ if (card_found)
+ {
+ resources[j].io_location = valid_locations[i];
+ resources[j].adapter_card_bus_type = ADAPTER_CARD_ATULA_BUS_TYPE;
+ resources[j].adapter_card_type = ADAPTER_CARD_TYPE_16_4_AT;
+
+ resources[j].dma_channel = hwi_atula_get_dma_channel(
+ valid_locations[i],
+ resources[j].adapter_card_revision
+ );
+
+ /*
+ * If we get a DMA channel of 0 back then we can't use DMA so
+ * default the transfer mode to PIO. Otherwise we'll set the
+ * transfer mode to DMA.
+ */
+
+ if (resources[j].dma_channel == 0)
+ {
+ resources[j].transfer_mode = PIO_DATA_TRANSFER_MODE;
+ }
+ else
+ {
+ resources[j].transfer_mode = DMA_DATA_TRANSFER_MODE;
+ }
+
+ resources[j].interrupt_number = hwi_atula_get_irq_channel(
+ valid_locations[i],
+ resources[j].adapter_card_revision
+ );
+
+ /*
+ * And note that we've found an adapter.
+ */
+
+ j++;
+ }
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_probe_disable_io(valid_locations[i], ATULA_IO_RANGE);
+#endif
+ }
+
+ return j;
+}
+#endif /* FTK_NO_PROBE */
+
+#ifndef FTK_NO_DETECT
+/****************************************************************************/
+/* */
+/* hwi_atula_read_rate_error */
+/* ========================= */
+/* */
+/* */
+/* PARAMETERS : */
+/* ============ */
+/* */
+/* adapter : The ubiqitous adapter structure. */
+/* */
+/* BODY : */
+/* ====== */
+/* */
+/* The hwi_atula_read_rate_error reads the NRATE_ERR signal from the */
+/* adapter DIO space. This is read from chapter 0 address 0. */
+/* */
+/* RETURNS : */
+/* ========= */
+/* */
+/* The routine returns RATE_ERROR if there is a rate error, 0 if there is no*/
+/* error, and NOT_SUPP if the card doesn't support this. */
+/* */
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_atula_read_rate_error)
+#endif
+
+export WORD hwi_atula_read_rate_error( ADAPTER * adapter
+ )
+{
+ WBOOLEAN ret_code;
+ WORD error_word;
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io( adapter );
+#endif
+
+ if (adapter->speed_detect == TRUE)
+ {
+ hwi_atula_set_dio_address( adapter, 0x00000000L);
+
+ sys_outsw( adapter->adapter_handle, adapter->sif_adr, 0x0);
+
+
+ error_word = sys_insw( adapter->adapter_handle, adapter->sif_dat) & 0x0080;
+
+ hwi_atula_set_dio_address( adapter, DIO_LOCATION_EAGLE_DATA_PAGE);
+
+ if (error_word & 0x0080)
+ {
+ ret_code = 0;
+ }
+ else
+ {
+ ret_code = RATE_ERROR;
+ }
+ }
+ else
+ {
+ ret_code = NOT_SUPP;
+ }
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io( adapter );
+#endif
+
+ return ret_code;
+}
+#endif /* FTK_NO_DETECT */
+
+/****************************************************************************
+*
+* hwi_atula_install_card
+* ======================
+*
+* PARAMETERS (passed by hwi_install_adapter) :
+* ============================================
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+* DOWNLOAD_IMAGE * download_image
+*
+* This is the code to be downloaded to the adapter. The image must be of
+* the correct type i.e. must be downloadable into the adapter. If the
+* pointer is 0 downloading is not done.
+*
+* BODY :
+* ======
+*
+* The hwi_atula_install_card routine is called by hwi_install_adapter. It
+* sets up the adapter card and downloads the required code to it. Firstly,
+* it checks there is a valid adapter at the required IO address. If so it
+* reads the node address from the BIA PROM and sets up and checks numerous
+* on-board registers for correct operation.
+*
+* Then, it halts the EAGLE, downloads the code, restarts the EAGLE and
+* waits up to 3 seconds for a valid bring-up code. If interrupts are
+* required, these are enabled by operating system specific calls.
+* Similarly, operating system calls are used to enable DMA if required. If
+* DMA is not used then the adapter is set up for PIO.
+*
+* RETURNS :
+* =========
+*
+* The routine returns TRUE if it succeeds. If this routine fails (returns
+* FALSE) then a subsequent call to driver_explain_error, with the adapter
+* handle corresponding to the adapter parameter used here, will give an
+* explanation.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_atula_install_card)
+#endif
+
+export WBOOLEAN
+hwi_atula_install_card(
+ ADAPTER * adapter,
+ DOWNLOAD_IMAGE * download_image
+ )
+{
+ WBOOLEAN is_soft_prog = FALSE;
+ ADAPTER_HANDLE handle = adapter->adapter_handle;
+ WORD control_1 = adapter->io_location + ATULA_CONTROL_REGISTER_1;
+ WORD control_2 = adapter->io_location + ATULA_CONTROL_REGISTER_2;
+ WORD status = adapter->io_location + ATULA_STATUS_REGISTER;
+ WORD control_6 = adapter->io_location + ATULA_CONTROL_REGISTER_6;
+ WORD control_7 = adapter->io_location + ATULA_CONTROL_REGISTER_7;
+ WORD bia_prom = adapter->io_location + ATULA_BIA_PROM;
+ WORD bia_prom_id = bia_prom + BIA_PROM_ID_BYTE;
+ WORD bia_prom_adap = bia_prom + BIA_PROM_ADAPTER_BYTE;
+ WORD bia_prom_rev = bia_prom + BIA_PROM_REVISION_BYTE;
+ WORD bia_prom_hwf = bia_prom + BIA_PROM_FEATURES_BYTE;
+ WORD bia_prom_hwf2 = bia_prom + BIA_PROM_HWF2;
+ WORD bia_prom_hwf3 = bia_prom + BIA_PROM_HWF3;
+ BYTE control_6_out;
+ BYTE dummy_sifdat;
+ BYTE bia_temp_bd = 0;
+ BYTE bia_temp_rev = 0;
+ BYTE bia_temp_hwf = 0;
+ BYTE bia_temp_hwf2 = 0;
+ BYTE bia_temp_hwf3 = 0;
+ WBOOLEAN card_found;
+ WORD sif_base;
+
+ /*
+ * Check that the IO location is valid.
+ */
+
+ if (!hwi_atula_valid_io_location(adapter->io_location))
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_02_BAD_IO_LOCATION;
+
+ return FALSE;
+ }
+
+ /*
+ * Record the locations of the SIF registers.
+ */
+
+ sif_base = adapter->io_location + ATULA_FIRST_SIF_REGISTER;
+
+ adapter->sif_dat = sif_base + EAGLE_SIFDAT;
+ adapter->sif_datinc = sif_base + EAGLE_SIFDAT_INC;
+ adapter->sif_adr = sif_base + EAGLE_SIFADR;
+ adapter->sif_int = sif_base + EAGLE_SIFINT;
+ adapter->sif_acl = sif_base + ATULA_EAGLE_SIFACL;
+ adapter->sif_adr2 = sif_base + ATULA_EAGLE_SIFADR_2;
+ adapter->sif_adx = sif_base + ATULA_EAGLE_SIFADX;
+ adapter->sif_dmalen = sif_base + ATULA_EAGLE_DMALEN;
+
+ adapter->io_range = ATULA_IO_RANGE;
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ /*
+ * Enable adapter card interrupts.
+ */
+
+ sys_outsb(handle, control_2, ATULA_CTRL2_INTEN);
+
+ /*
+ * Reset adapter (ATULA_CTRL1_NRESET = 0).
+ */
+
+ sys_outsb(handle, control_1, 0);
+
+ /*
+ * Page in first page of BIA PROM.
+ * Set ATULA_CTRL7_PAGE = 0 and ATULA_CTRL7_SIFSEL = 0.
+ */
+
+ sys_outsb(handle, control_7, 0);
+
+ /*
+ * Check we have a functioning adapter at the given IO location by
+ * checking the BIA PROM for an 'M' id byte and also by checking that
+ * the BIA adapter card byte is for a supported card type.
+ */
+
+ /*
+ * At the moment there are four major board types that are acceptable
+ * AT, PC, MAXY, and ATP.
+ */
+
+ card_found = FALSE;
+
+ if (sys_insb(handle, bia_prom_id) == 'M')
+ {
+ bia_temp_bd = sys_insb(handle, bia_prom_adap);
+ bia_temp_rev = sys_insb(handle, bia_prom_rev);
+ bia_temp_hwf = sys_insb(handle, bia_prom_hwf);
+ bia_temp_hwf2 = sys_insb(handle, bia_prom_hwf2);
+ bia_temp_hwf3 = sys_insb(handle, bia_prom_hwf3);
+
+ if (bia_temp_bd == BIA_PROM_TYPE_16_4_PC)
+ {
+ adapter->adapter_card_revision = ADAPTER_CARD_16_4_PC;
+ adapter->adapter_ram_size = 128;
+ card_found = TRUE;
+ }
+ else if (bia_temp_bd == BIA_PROM_TYPE_16_4_MAXY)
+ {
+ adapter->adapter_card_revision = ADAPTER_CARD_16_4_MAXY;
+ adapter->adapter_ram_size = 256;
+ card_found = TRUE;
+ }
+ else if (bia_temp_bd == BIA_PROM_TYPE_16_4_AT)
+ {
+ if (bia_temp_rev <= MAX_ADAPTER_CARD_AT_REV)
+ {
+ adapter->adapter_ram_size = adapter_card_at_rmsz_lut[bia_temp_rev];
+ }
+ else
+ {
+ adapter->adapter_ram_size = 128;
+ }
+
+ if (bia_temp_rev < ADAPTER_CARD_16_4_AT)
+ {
+ adapter->adapter_card_revision = ADAPTER_CARD_16_4_AT;
+ }
+ else
+ {
+ adapter->adapter_card_revision = bia_temp_rev;
+ }
+
+ card_found = TRUE;
+ }
+ else if (bia_temp_bd == BIA_PROM_TYPE_16_4_AT_P)
+ {
+ adapter->adapter_ram_size = 512;
+
+ switch(bia_temp_rev)
+ {
+ case ADAPTER_CARD_16_4_FIBRE:
+ adapter->adapter_card_revision = ADAPTER_CARD_16_4_FIBRE_P;
+ break;
+ case ADAPTER_CARD_16_4_ISA_C:
+ adapter->adapter_card_revision = ADAPTER_CARD_16_4_ISA_C_P;
+ adapter->adapter_ram_size = 128;
+ adapter->mc32_config = MC_AND_ISACP_USE_PIO;
+ break;
+ case ADAPTER_CARD_16_4_AT_P_REV:
+ adapter->adapter_card_revision = ADAPTER_CARD_16_4_AT_P;
+ break;
+ default:
+ adapter->adapter_card_revision = ADAPTER_CARD_UNKNOWN;
+ break;
+ }
+
+ card_found = TRUE;
+ }
+ }
+
+ /*
+ * If no ATULA card found then fill in error record and return.
+ */
+
+ if (!card_found)
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_05_ADAPTER_NOT_FOUND;
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+
+ /*
+ * Sanity check the interrupt number and DMA channel. The checking
+ * routines fill in the error record in the adapter structure.
+ */
+
+ if (!hwi_atula_valid_irq_channel(adapter) ||
+ !hwi_atula_valid_transfer_mode(adapter) ||
+ !hwi_atula_valid_dma_channel(adapter))
+ {
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+
+ /*
+ * Note the major card type.
+ */
+
+ adapter->adapter_card_type = ADAPTER_CARD_TYPE_16_4_AT;
+
+ /*
+ * If this card has a C30 on board and the ring speed bit is set then
+ * we support ring speed detect.
+ */
+
+ if (((bia_temp_hwf2 & 0x3) == C30 ) && (bia_temp_hwf3 & RSPEED_DETECT))
+ {
+ adapter->speed_detect = TRUE;
+ }
+
+ /*
+ * Now we need to check for AT/P cards - these need special processing.
+ */
+
+ if (bia_temp_bd == BIA_PROM_TYPE_16_4_AT_P ||
+ bia_temp_rev == ADAPTER_CARD_16_4_AT_P_REV)
+ {
+ WORD atp_eisa_rev2 = adapter->io_location + AT_P_EISA_REV2_CTRL_REG;
+ BYTE eisa_rev2_byte = 0;
+
+ if (bia_temp_bd == BIA_PROM_TYPE_16_4_AT_P)
+ {
+ eisa_rev2_byte |= ATP_RSCTRL;
+ }
+
+ if ((bia_temp_hwf & BIA_PROM_FEATURE_CLKDIV_MASK) ||
+ (bia_temp_rev == ADAPTER_CARD_16_4_ISA_C))
+ {
+ eisa_rev2_byte |= ATP_CLKDIV;
+ }
+
+ sys_outsb(handle, atp_eisa_rev2, eisa_rev2_byte);
+
+ is_soft_prog = TRUE;
+ }
+
+ /*
+ * Check for the features byte - if it is non-zero, it may override our
+ * RAM size calculations.
+ */
+
+ if (bia_temp_hwf)
+ {
+ UINT dram = (bia_temp_hwf & BIA_PROM_FEATURE_DRAM_MASK) * DRAM_MULT;
+
+ if (dram)
+ {
+ adapter->adapter_ram_size = dram;
+ }
+ }
+
+ /*
+ * The user might have asked to override the card configuration with
+ * the values supplied - this only works for ATPs and ISA/C/Ps.
+ */
+
+ if (is_soft_prog)
+ {
+ WORD atp_sw_config = adapter->io_location + AT_P_SW_CONFIG_REG;
+ BYTE config_byte;
+ UINT int_num = adapter->interrupt_number;
+ UINT dma_chan = adapter->dma_channel;
+
+ if (adapter->set_irq || adapter->set_dma || adapter->set_ring_speed)
+ {
+ config_byte = sys_insb(handle, atp_sw_config);
+
+ /*
+ * Override the interrupt number.
+ */
+
+ if (adapter->set_irq &&
+ int_num < sizeof(atp_irq_select_table) &&
+ atp_irq_select_table[int_num] != 0xff)
+ {
+ config_byte = (config_byte & ~ATP_INTSEL) |
+ atp_irq_select_table[int_num];
+ }
+
+ /*
+ * Override the DMA channel.
+ */
+
+ if (adapter->set_dma &&
+ dma_chan < sizeof(atp_dma_select_table) &&
+ atp_dma_select_table[dma_chan] != 0xff)
+ {
+ config_byte = (config_byte & ~ATP_DMA) |
+ atp_dma_select_table[dma_chan];
+ }
+
+ /*
+ * Set the ring speed.
+ */
+
+ if (adapter->set_ring_speed == 16)
+ {
+ config_byte = (config_byte & ~ATP_S4N16);
+ }
+ else if (adapter->set_ring_speed == 4)
+ {
+ config_byte = (config_byte | ATP_S4N16);
+ }
+
+ sys_outsb(handle, atp_sw_config, config_byte);
+ }
+ }
+
+ /*
+ * May have changed from software running in bus master to PIO.
+ * Hence get spurious data at ?a28 cos of DLATCH bug in ATULA hardware
+ * so get next read data as if doing PIO data transfer.
+ * Hence do extra read from ?a28 to fix bug.
+ */
+
+ dummy_sifdat = sys_insb(handle, adapter->sif_dat);
+
+ /*
+ * Check here to see if we have to force card to 16 Mb/s for a none
+ * soft programmable card.
+ */
+
+ if (!is_soft_prog && adapter->set_ring_speed == 16)
+ {
+ macro_setb_bit(handle, control_1, ATULA_CTRL1_4_16_SEL);
+ }
+
+ /*
+ * Interrupts for ATULA cards are always edge triggered.
+ */
+
+ adapter->edge_triggered_ints = TRUE;
+
+ /*
+ * Machine reset does not affect speed or media setting of ATULA cards.
+ */
+
+ /*
+ * Find the adapter card node address.
+ */
+
+ hwi_atula_read_node_address(adapter);
+
+ /*
+ * If have REV3 adapter type then must set up special bus timings
+ * must do this before any SIF register access
+ * on 16/4 PC doing this is not necessary but has no effect
+ */
+
+ if ((sys_insb(handle, control_7) & ATULA_CTRL7_REV_4) == 0)
+ {
+ /*
+ * Note that a sys_outsb here will clear the INTEN bit that was set
+ * earlier on. This does not matter, however, because we have found
+ * the interrupt vector by this stage. If this does become a problem,
+ * use macro_setb_bit().
+ */
+
+ sys_outsb(handle, control_2, ATULA_CTRL2_CS16DLY);
+ }
+
+ /*
+ * Set control register 6 for normal or synchronous bus operation.
+ * Use status register to get bus operation mode. On 16/4 PC will always
+ * in fact have normal bus operation.
+ */
+
+ control_6_out = 0;
+
+ if ((sys_insb(handle, status) & ATULA_STATUS_ASYN_BUS) != 0)
+ {
+ control_6_out |= ATULA_CTRL6_CLKSEL_ON_BOARD;
+ }
+ else
+ {
+ control_6_out |= ATULA_CTRL6_CLKSEL_HOST;
+ }
+
+ /*
+ * If want to use DMA, need a 16 bit slot.
+ * Note that 16/4 PC will always be in an 8 bit slot.
+ */
+
+ if ((adapter->transfer_mode == DMA_DATA_TRANSFER_MODE) &&
+ ((sys_insb(handle, status) & ATULA_STATUS_BUS8) != 0))
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_06_CANNOT_USE_DMA;
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+
+ /*
+ * Set up transfer mode now that we know we are in a valid slot.
+ */
+
+ if (adapter->transfer_mode == DMA_DATA_TRANSFER_MODE)
+ {
+ control_6_out |= ATULA_CTRL6_MODE_BUS_MASTER;
+ }
+ else
+ {
+ control_6_out |= ATULA_CTRL6_MODE_PIO;
+ }
+
+ /*
+ * Now output to control register 6 the required value we have set up.
+ */
+
+ sys_outsb(handle, control_6, control_6_out);
+
+ /*
+ * Wait at least 10 milliseconds and bring adapter out of reset state.
+ * 10ms is the minimum time must hold ATULA_CTRL1_NRESET low after
+ * changing ATULA_CTRL6_CLKSEL bits. Disable and re-enable accessing
+ * IO locations around wait so delay can reschedule this task and not
+ * effect others running.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+
+ sys_wait_at_least_milliseconds(10);
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ macro_setb_bit( handle, control_1, ATULA_CTRL1_NSRESET);
+
+ /*
+ * Get extended SIF registers, halt EAGLE, then get normal SIF regs.
+ */
+
+ macro_setb_bit(handle, control_7, ATULA_CTRL7_SIFSEL);
+ macro_setb_bit(handle, control_1, ATULA_CTRL1_SRSX);
+
+ hwi_halt_eagle(adapter);
+
+ macro_clearb_bit(handle, control_1, ATULA_CTRL1_SRSX);
+
+ /*
+ * Download code to adapter. View download image as a sequence of
+ * download records. Pass address of routine to set up DIO addresses
+ * on ATULA cards. If routine fails return failure (error record
+ * already filled in).
+ */
+
+ if (!hwi_download_code(
+ adapter,
+ (DOWNLOAD_RECORD *) download_image,
+ hwi_atula_set_dio_address
+ ))
+ {
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+
+ /*
+ * Get extended SIF registers, start EAGLE, then get normal SIF regs.
+ */
+
+ macro_setb_bit(handle, control_1, ATULA_CTRL1_SRSX);
+
+ hwi_start_eagle(adapter);
+
+ macro_clearb_bit(handle, control_1, ATULA_CTRL1_SRSX);
+
+ /*
+ * Wait for a valid bring up code, may wait 3 seconds.
+ * if routine fails return failure (error record already filled in).
+ */
+
+ if (!hwi_get_bring_up_code(adapter))
+ {
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+
+ /*
+ * Set DIO address to point to EAGLE DATA page 0x10000L.
+ */
+
+ hwi_atula_set_dio_address(adapter, DIO_LOCATION_EAGLE_DATA_PAGE);
+
+ /*
+ * Set maximum frame size from the ring speed.
+ */
+
+ adapter->max_frame_size = hwi_get_max_frame_size(adapter);
+ adapter->ring_speed = hwi_get_ring_speed(adapter);
+
+ /*
+ * If not in polling mode then set up interrupts. Interrupts_on
+ * field is used when disabling interrupts for adapter.
+ */
+
+ if (adapter->interrupt_number != POLLING_INTERRUPTS_MODE)
+ {
+ adapter->interrupts_on =
+ sys_enable_irq_channel(handle, adapter->interrupt_number);
+
+ /*
+ * If fail enable irq channel then fill in error record and return.
+ */
+
+ if (!adapter->interrupts_on)
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_0B_FAIL_IRQ_ENABLE;
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+ }
+ else
+ {
+ adapter->interrupts_on = TRUE;
+ }
+
+ /*
+ * Enable interrupts at adapter (do this even in polling mode).
+ * Hence when polling still 'using' interrupt channel.
+ * So do not use card interrupt switch setting shared by other devices.
+ */
+
+ macro_setb_bit( handle, control_1, ATULA_CTRL1_SINTREN);
+ macro_setb_bit( handle, control_2, ATULA_CTRL2_INTEN);
+
+ /*
+ * Set up PIO or DMA as required.
+ */
+
+ if (adapter->transfer_mode == DMA_DATA_TRANSFER_MODE)
+ {
+ /*
+ * Bus master DMA. This is not possible for 16/4 PC adapters.
+ * Enable DMA at adapter and then call system service routine.
+ * Must enable DMA at adapter before enable DMA channel
+ * otherwise machine will 'crash'. Also important that DMA
+ * channel is correct for same reason. dma_on field is used
+ * when disabling DMA for adapter.
+ */
+
+ macro_setb_bit(handle, control_6, ATULA_CTRL6_DMAEN);
+
+ adapter->dma_on = sys_enable_dma_channel(handle, adapter->dma_channel);
+
+ /*
+ * If we fail to enable dma channel then fill in error record
+ * and return also disable DMA at adapter because of failure.
+ */
+
+ if (!adapter->dma_on)
+ {
+ macro_clearb_bit(handle, control_6, ATULA_CTRL6_DMAEN);
+
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_0C_FAIL_DMA_ENABLE;
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+ }
+ else
+ {
+ /*
+ * PIO mode. This is only data transfer mode possible for
+ * 16/4 PC adapters. Enable PIO interrupt.
+ */
+
+ macro_setb_bit(handle, control_2, ATULA_CTRL2_SHRQEN);
+ }
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+
+ /*
+ * Return successfully.
+ */
+
+ return TRUE;
+}
+
+
+/****************************************************************************
+*
+* hwi_atula_interrupt_handler
+* ===========================
+*
+* PARAMETERS (passed by hwi_interrupt_entry) :
+* ============================================
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+* BODY :
+* ======
+*
+* The hwi_atula_interrupt_handler routine is called, when an interrupt
+* occurs, by hwi_interrupt_entry. It checks to see if a particular card
+* has interrupted. The interrupt could be generated by the SIF or by the
+* ATULA in order to do a PIO data transfer. Note it could in fact be the
+* case that no interrupt has occured on the particular adapter being
+* checked.
+*
+* On SIF interrupts, the interrupt is acknowledged and cleared. The value
+* in the SIF interrupt register is recorded in order to pass it to the
+* driver_interrupt_entry routine (along with the adapter details).
+*
+* On PIO interrupts, the length, direction and physical address of the
+* transfer is determined. A system provided routine is called to do the
+* data transfer itself. Note the EAGLE thinks it is doing a DMA transfer
+* - it is the ATULA which allows us to do it via in/out instructions. Also
+* note that the IO location for the PIO is mapped onto the location of the
+* EAGLE SIFDAT register - the PIO does not actually use the SIFDAT
+* register so it's value is not effected by this routine.
+*
+* RETURNS :
+* =========
+*
+* The routine always successfully completes.
+*
+****************************************************************************/
+
+#ifdef FTK_IRQ_FUNCTION
+#pragma FTK_IRQ_FUNCTION(hwi_atula_interrupt_handler)
+#endif
+
+export void
+hwi_atula_interrupt_handler(
+ ADAPTER * adapter
+ )
+{
+ ADAPTER_HANDLE handle = adapter->adapter_handle;
+ WORD control_1 = adapter->io_location + ATULA_CONTROL_REGISTER_1;
+ WORD control_2 = adapter->io_location + ATULA_CONTROL_REGISTER_2;
+ WORD status = adapter->io_location + ATULA_STATUS_REGISTER;
+ WORD control_7 = adapter->io_location + ATULA_CONTROL_REGISTER_7;
+ WORD sifadr = adapter->sif_adr;
+ WORD sifdat = adapter->sif_dat;
+ WORD sifint = adapter->sif_int;
+ WORD sifint_value;
+ WORD sifint_tmp;
+ BYTE FAR * pio_virtaddr;
+ WORD pio_len_bytes;
+ WBOOLEAN pio_from_adapter;
+ WORD saved_sifadr;
+ UINT dummy;
+ DWORD dma_high_word;
+ WORD dma_low_word;
+
+ /*
+ * Inform system about the IO ports we are going to access.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ /*
+ * Check for SIF interrupt or PIO interrupt.
+ */
+
+ if ((sys_insb(handle, control_7) & ATULA_CTRL7_SINTR) != 0)
+ {
+ /*
+ * SIF interrupt has occurred. SRB free, adapter check
+ * or received frame interrupt.
+ */
+
+ /*
+ * Toggle SIF interrupt enable to acknowledge interrupt at ATULA.
+ */
+
+ macro_clearb_bit(handle, control_1, ATULA_CTRL1_SINTREN);
+ macro_setb_bit(handle, control_1, ATULA_CTRL1_SINTREN);
+
+ /*
+ * Clear EAGLE_SIFINT_HOST_IRQ to acknowledge interrupt at SIF.
+ */
+
+ /*
+ * WARNING: Do NOT reorder the clearing of the SIFINT register with
+ * the reading of it. If SIFINT is cleared after reading it, any
+ * interrupts raised after reading it will be lost. Admittedly
+ * this is a small time frame, but it is important.
+ */
+
+ sys_outsw(handle, sifint, 0);
+
+ /*
+ * Record the EAGLE SIF interrupt register value.
+ */
+
+ /*
+ * WARNING: Continue to read the SIFINT register until it is stable
+ * because of a potential problem involving the host reading the
+ * register after the adapter has written the low byte of it, but
+ * before it has written the high byte. Failure to wait for the
+ * SIFINT register to settle can cause spurious interrupts.
+ */
+
+ sifint_value = sys_insw(handle, sifint);
+ do
+ {
+ sifint_tmp = sifint_value;
+ sifint_value = sys_insw(handle, sifint);
+ }
+ while (sifint_tmp != sifint_value);
+
+ /*
+ * Acknowledge/clear interrupt at interrupt controller.
+ */
+
+#ifndef FTK_NO_CLEAR_IRQ
+ sys_clear_controller_interrupt(handle, adapter->interrupt_number);
+#endif
+
+ /*
+ * Toggle interrupt enable bit to regenerate any lost interrupts.
+ * Need do this because using edge triggered interrupts.
+ */
+
+ macro_clearb_bit(handle, control_2, ATULA_CTRL2_INTEN);
+ macro_setb_bit(handle, control_2, ATULA_CTRL2_INTEN);
+
+ /*
+ * Call driver with details of SIF interrupt.
+ */
+ driver_interrupt_entry(handle, adapter, sifint_value);
+ }
+ else if ((sys_insb(handle, control_2) & ATULA_CTRL2_SHRQ) != 0)
+ {
+ /*
+ * PIO interrupt has occurred. Data transfer to/from adapter
+ * interrupt.
+ */
+
+ /*
+ * Toggle PIO interrupt enable to acknowledge interrupt at ATULA.
+ */
+
+ macro_clearb_bit(handle, control_2, ATULA_CTRL2_SHRQEN);
+ macro_setb_bit(handle, control_2, ATULA_CTRL2_SHRQEN);
+
+ /*
+ * We must preserve the value of SIF address in case we have
+ * interrupted someone who relies on it not chaning.
+ */
+
+ saved_sifadr = sys_insw(handle, adapter->sif_adr);
+
+ /*
+ * Read the virtual address for the PIO through DIO space from the
+ * SIF registers. Because the SIF thinks that it is doing real DMA,
+ * the SDMAADR/SDMAADX registers cannot be paged in, so they must
+ * be read from their memory mapped locations in Eagle memory.
+ */
+
+ sys_outsw(handle, sifadr, DIO_LOCATION_EXT_DMA_ADDR);
+ dma_high_word = (DWORD) sys_insw(handle, sifdat);
+
+ sys_outsw(handle, sifadr, DIO_LOCATION_DMA_ADDR);
+ dma_low_word = sys_insw(handle, sifdat);
+
+ pio_virtaddr = (BYTE FAR *) ((dma_high_word << 16) | ((DWORD) dma_low_word));
+
+ /*
+ * Read the DMA length from the extended SIF register.
+ */
+
+ macro_setb_bit(handle, control_1, ATULA_CTRL1_SRSX);
+ pio_len_bytes = sys_insw(handle, adapter->sif_dmalen);
+ macro_clearb_bit( handle, control_1, ATULA_CTRL1_SRSX);
+
+ /*
+ * If we are talking to the ISA Client/P, we need to use software
+ * handshaking across the PIO. Start by writing zero to a magic
+ * location on the adapter.
+ */
+
+ if (adapter->adapter_card_revision == ADAPTER_CARD_16_4_ISA_C_P)
+ {
+ sys_outsw(handle, sifadr, DIO_LOCATION_DMA_CONTROL);
+ sys_outsw(handle, sifdat, 0);
+ }
+
+ /*
+ * Start what the SIF thinks is a DMA but is PIO instead.
+ */
+
+ macro_setb_bit(handle, control_2, ATULA_CTRL2_SHLDA);
+
+ /*
+ * Determine what direction the data transfer is to take place in.
+ */
+
+ pio_from_adapter = sys_insb(handle, status) & ATULA_STATUS_SDDIR;
+
+ /*
+ * Do the actual data transfer. Note that Fastmac only copies whole
+ * WORDs to DWORD boundaries. FastmacPlus, however, can transfer
+ * any length to any address.
+ */
+
+ if (pio_from_adapter)
+ {
+ /*
+ * Transfer into host memory from adapter.
+ */
+
+ /*
+ * First, check if host address is on an odd byte boundary.
+ */
+
+ if ((card_t) pio_virtaddr % 2)
+ {
+ pio_len_bytes--;
+ *(pio_virtaddr++) =
+ sys_insb(handle, (WORD) (sifdat + ATULA_PIO_IO_LOC + 1));
+ }
+
+ /*
+ * Now transfer the bulk of the data.
+ */
+
+ sys_rep_insw(
+ handle,
+ (WORD) (sifdat + ATULA_PIO_IO_LOC),
+ pio_virtaddr,
+ (WORD) (pio_len_bytes >> 1)
+ );
+
+ /*
+ * Finally transfer any trailing byte.
+ */
+
+ if (pio_len_bytes % 2)
+ {
+ *(pio_virtaddr + pio_len_bytes - 1) =
+ sys_insb(handle, (WORD) (sifdat + ATULA_PIO_IO_LOC));
+ }
+ }
+ else
+ {
+ /*
+ * Transfer into adapter memory from the host.
+ */
+
+ /*
+ * If we are talking to an ISA Client/P card, we need to assert
+ * the -CLKDIV signal to prevent dips in one of the signals to
+ * the ATULA. This is only needed for ISA/C/P transmits.
+ */
+
+ if (adapter->adapter_card_revision == ADAPTER_CARD_16_4_ISA_C_P &&
+ pio_len_bytes > 13)
+ {
+ /*
+ * Need to write ATP_RSCTRL to ATP_EISA_REV2_CTRL reg.
+ */
+
+ sys_outsb(
+ handle,
+ (WORD) (adapter->io_location + AT_P_EISA_REV2_CTRL_REG),
+ ATP_RSCTRL
+ );
+ }
+
+ /*
+ * First, check if host address is on an odd byte boundary.
+ */
+
+ if ((card_t) pio_virtaddr % 2)
+ {
+ pio_len_bytes--;
+ sys_outsb(
+ handle,
+ (WORD) (sifdat + ATULA_PIO_IO_LOC + 1),
+ *(pio_virtaddr++)
+ );
+ }
+
+ /*
+ * Now transfer the bulk of the data.
+ */
+
+ sys_rep_outsw(
+ handle,
+ (WORD) (sifdat + ATULA_PIO_IO_LOC),
+ pio_virtaddr,
+ (WORD) (pio_len_bytes >> 1)
+ );
+
+ /*
+ * Finally transfer any trailing byte.
+ */
+
+ if (pio_len_bytes % 2)
+ {
+ sys_outsb(
+ handle,
+ (WORD) (sifdat + ATULA_PIO_IO_LOC),
+ *(pio_virtaddr + pio_len_bytes - 1)
+ );
+ }
+
+ /*
+ * If we are talking to an ISA Client/P card, we need to remove
+ * the -CLKDIV signal that we asserted above.
+ */
+
+ if (adapter->adapter_card_revision == ADAPTER_CARD_16_4_ISA_C_P &&
+ pio_len_bytes > 13)
+ {
+ /*
+ * Deassert the -CLKDIV signal that we asserted up above.
+ */
+
+ sys_outsb(
+ handle,
+ (WORD) (adapter->io_location + AT_P_EISA_REV2_CTRL_REG),
+ ATP_RSCTRL | ATP_CLKDIV
+ );
+ }
+ }
+
+ /*
+ * If we are talking to an ISA Client/P card, we now finish off the
+ * software handshake process that we started at the beginning.
+ */
+
+ if (adapter->adapter_card_revision == ADAPTER_CARD_16_4_ISA_C_P)
+ {
+ /*
+ * Do a read first - otherwise the write might fail.
+ */
+
+ sys_outsw(handle, sifadr, DIO_LOCATION_DMA_CONTROL);
+ dummy = sys_insw(handle, sifdat);
+
+ sys_outsw(handle, sifadr, DIO_LOCATION_DMA_CONTROL);
+ sys_outsw(handle, sifdat, 0xFFFF);
+ }
+
+ /*
+ * Restore the SIF address.
+ */
+
+ sys_outsw(handle, adapter->sif_adr, saved_sifadr);
+
+ /*
+ * Acknowledge/clear interrupt at interrupt controller.
+ */
+
+#ifndef FTK_NO_CLEAR_IRQ
+ sys_clear_controller_interrupt(handle, adapter->interrupt_number);
+#endif
+
+ /*
+ * Toggle interrupt enable bit to regenerate any lost interrupts.
+ */
+
+ macro_clearb_bit(handle, control_2, ATULA_CTRL2_INTEN);
+ macro_setb_bit(handle, control_2, ATULA_CTRL2_INTEN);
+ }
+
+ /*
+ * Let system know we have finished accessing the IO ports.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+}
+
+
+/****************************************************************************
+*
+* hwi_atula_remove_card
+* =====================
+*
+* PARAMETERS (passed by hwi_remove_adapter) :
+* ===========================================
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+* BODY :
+* ======
+*
+* The hwi_atula_remove_card routine is called by hwi_remove_adapter. It
+* disables DMA and interrupts if they are being used. It also resets the
+* adapter.
+*
+* RETURNS :
+* =========
+*
+* The routine always successfully completes.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(hwi_atula_remove_card)
+#endif
+
+export void
+hwi_atula_remove_card(
+ ADAPTER * adapter
+ )
+{
+ ADAPTER_HANDLE handle = adapter->adapter_handle;
+ WORD control_1 = adapter->io_location + ATULA_CONTROL_REGISTER_1;
+ WORD control_2 = adapter->io_location + ATULA_CONTROL_REGISTER_2;
+ WORD control_6 = adapter->io_location + ATULA_CONTROL_REGISTER_6;
+
+ /*
+ * Disable DMA if successfully enabled. DMA will only be on if not
+ * in PIO mode. DMA channel must be disabled before disabling DMA
+ * at adapter otherwise machine will 'crash'.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ if (adapter->dma_on)
+ {
+ sys_disable_dma_channel(handle, adapter->dma_channel);
+
+ macro_clearb_bit(handle, control_6, ATULA_CTRL6_DMAEN);
+
+ adapter->dma_on = FALSE;
+ }
+
+ /*
+ * Disable interrupts being generated. Only need to do this if
+ * interrupts successfully enabled. Interrupt must be disabled at
+ * adapter before unpatching interrupt. Even in polling mode we
+ * must turn off interrupts at adapter.
+ */
+
+ if (adapter->interrupts_on)
+ {
+ macro_clearb_bit(handle, control_2, ATULA_CTRL2_INTEN);
+
+ if (adapter->interrupt_number != POLLING_INTERRUPTS_MODE)
+ {
+ sys_disable_irq_channel(handle, adapter->interrupt_number);
+ }
+
+ adapter->interrupts_on = FALSE;
+ }
+
+ /*
+ * Perform adapter reset, set ATULA_CTRL1_NSRESET low.
+ */
+
+ sys_outsb(handle, control_1, 0);
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+}
+
+
+/****************************************************************************
+*
+* hwi_atula_set_dio_address
+* =========================
+* PARAMETERS :
+* ============
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+* DWORD dio_address
+*
+* The 32 bit DIO address to select.
+*
+* BODY :
+* ======
+*
+* The hwi_atula_set_dio_address routine is used, with ATULA cards, for
+* putting a 32 bit DIO address into the SIF DIO address and extended DIO
+* address registers. Note that the extended address register should be
+* loaded first.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_atula_set_dio_address)
+#endif
+
+export void
+hwi_atula_set_dio_address(
+ ADAPTER * adapter,
+ DWORD dio_address
+ )
+{
+ ADAPTER_HANDLE handle = adapter->adapter_handle;
+ WORD control_1 = adapter->io_location + ATULA_CONTROL_REGISTER_1;
+ WORD sif_dio_adr = adapter->sif_adr;
+ WORD sif_dio_adrx = adapter->sif_adx;
+
+ /*
+ * Page in extended SIF registers.
+ */
+
+ macro_setb_bit(handle, control_1, ATULA_CTRL1_SRSX);
+
+ /*
+ * Load extended DIO address register with top 16 bits of address.
+ * Always load extended address register first.
+ */
+
+ sys_outsw(handle, sif_dio_adrx, (WORD) (dio_address >> 16));
+
+ /*
+ * Return to having normal SIF registers paged in.
+ */
+
+ macro_clearb_bit(handle, control_1, ATULA_CTRL1_SRSX);
+
+ /*
+ * Load DIO address register with low 16 bits of address.
+ */
+
+ sys_outsw(handle, sif_dio_adr, (WORD) (dio_address & 0x0000FFFF));
+}
+
+/*---------------------------------------------------------------------------
+|
+| LOCAL PROCEDURES
+|
+---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+|
+| hwi_atula_valid_io_location
+| ===========================
+|
+| The hwi_atula_valid_io_location routine checks to see if the user has
+| supplied a valid IO location for an ATULA based adapter card.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_atula_valid_io_location)
+#endif
+
+local WBOOLEAN
+hwi_atula_valid_io_location(
+ WORD io_location
+ )
+{
+ WBOOLEAN io_valid;
+
+ switch (io_location)
+ {
+ case 0x0A20 :
+ case 0x1A20 :
+ case 0x2A20 :
+ case 0x3A20 :
+
+ /*
+ * These are the valid user supplied io locations.
+ */
+
+ io_valid = TRUE;
+ break;
+
+
+ default :
+
+ /*
+ * Anything else is invalid.
+ */
+
+ io_valid = FALSE;
+ break;
+ }
+
+ return io_valid;
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| hwi_atula_read_node_address
+| ===========================
+|
+| The hwi_atula_read_node_address routine reads in the node address that
+| is stored in the second page of the BIA PROM on ATULA cards.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_atula_read_node_address)
+#endif
+
+local void
+hwi_atula_read_node_address(
+ ADAPTER * adapter
+ )
+{
+ ADAPTER_HANDLE handle = adapter->adapter_handle;
+ WORD control_7 = adapter->io_location + ATULA_CONTROL_REGISTER_7;
+ WORD bia_prom = adapter->io_location + ATULA_BIA_PROM;
+ WORD bia_prom_address = bia_prom + BIA_PROM_NODE_ADDRESS;
+ WORD index;
+
+ /*
+ * Page in second page of BIA PROM containing node address.
+ */
+
+ macro_setb_bit(handle, control_7, ATULA_CTRL7_PAGE);
+
+ /*
+ * Read node address from BIA PROM.
+ */
+
+ for (index = 0; index < 6; index++)
+ {
+ adapter->permanent_address.byte[index] =
+ sys_insb(handle, (WORD) (bia_prom_address + index));
+ }
+
+ /*
+ * Restore first page of BIA PROM.
+ */
+
+ macro_clearb_bit(handle, control_7, ATULA_CTRL7_PAGE);
+}
+
+
+#ifndef FTK_NO_PROBE
+/*---------------------------------------------------------------------------
+|
+| hwi_atula_get_irq_channel
+| =========================
+|
+| The hwi_atula_get_irq_channel routine attempts to determine the
+| interrupt number that an ATULA card is using. It does this by calling
+| system provided routine. It does not always succeed in finding the
+| interrupt number being used.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_atula_get_irq_channel)
+#endif
+
+local WORD
+hwi_atula_get_irq_channel(
+ WORD io_location,
+ UINT adapter_revision
+ )
+{
+ WORD control_2 = io_location + ATULA_CONTROL_REGISTER_2;
+ WORD control_7 = io_location + ATULA_CONTROL_REGISTER_7;
+ BYTE original_ctrl7;
+ BYTE irq_off;
+ BYTE irq_on;
+ WORD irq;
+
+ /*
+ * Enable interrupts at adapter card temporarily.
+ */
+
+ macro_probe_setb_bit(control_2, ATULA_CTRL2_INTEN);
+
+ /*
+ * Save contents of ATULA control register 7.
+ */
+
+ original_ctrl7 = sys_probe_insb(control_7);
+
+ /*
+ * Current contents of control register 7 does not generate interrupt.
+ */
+
+ irq_off = original_ctrl7;
+
+ /*
+ * If set user interrupt bit then will generate interrupt.
+ */
+
+ irq_on = irq_off | ATULA_CTRL7_UINT;
+
+ /*
+ * Call system provided routine to attempt to dicover interrupt number.
+ * Routine returns FTK_NOT_DETERMINED if not get interrupt number.
+ */
+
+ irq = sys_atula_find_irq_channel(control_7, irq_on, irq_off);
+
+ /*
+ * Restore original contents of ATULA control register 7.
+ */
+
+ sys_probe_outsb(control_7, original_ctrl7);
+
+ /*
+ * Disable interrupts at adapter card.
+ */
+
+ macro_probe_clearb_bit( control_2, ATULA_CTRL2_INTEN);
+
+ /*
+ * Return discovered interrupt number (could be FTK_NOT_DETERMINED).
+ */
+
+ return irq;
+}
+#endif
+
+#ifndef FTK_NO_PROBE
+/*---------------------------------------------------------------------------
+|
+| hwi_atula_get_dma_channel
+| =========================
+|
+| The hwi_atula_get_dma_channel routine attempts to determine the DMA
+| channel that an ATULA card is using. It does this by calling a system
+| provided routine.
+|
+| It may be that the system routine does not always succeed in finding the
+| DMA channel being used. However, if the provided system routine is used,
+| then PIO mode is chosen if the DMA channel can not be determined. Hence,
+| in this case, the value FTK_NOT_DETERMINED will never be returned by the
+| hwi_atula_get_dma_channel routine.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_atula_get_dma_channel)
+#endif
+
+local WORD
+hwi_atula_get_dma_channel(
+ WORD io_location ,
+ UINT adapter_revision
+ )
+{
+ WORD control_6 = io_location + ATULA_CONTROL_REGISTER_6;
+ WORD bia_prom = io_location + ATULA_BIA_PROM;
+ WORD bia_prom_adap = bia_prom + BIA_PROM_ADAPTER_BYTE;
+ BYTE original_ctrl6;
+ BYTE dma_off;
+ BYTE dma_on;
+ WORD dma;
+
+ /*
+ * Check to see if an adapter that doesn't support DMA is being used.
+ */
+
+ if (adapter_revision == ADAPTER_CARD_16_4_PC ||
+ adapter_revision == ADAPTER_CARD_16_4_ISA_C ||
+ adapter_revision == ADAPTER_CARD_16_4_ISA_C_P)
+ {
+ dma = 0;
+ }
+ else
+ {
+ /*
+ * For the 16/4 AT card, save the contents of control register 6.
+ */
+
+ original_ctrl6 = sys_probe_insb(control_6);
+
+ /*
+ * Need to enable DMA for bus master.
+ */
+
+ dma_off = original_ctrl6 |
+ ATULA_CTRL6_MODE_BUS_MASTER |
+ ATULA_CTRL6_DMAEN;
+
+ /*
+ * Set user generate DMA request bit for turning DMA signal on.
+ */
+
+ dma_on = dma_off | ATULA_CTRL6_UDRQ;
+
+ /*
+ * Call system provided routine to attempt to dicover DMA channel.
+ * Provided routine returns PIO_DATA_TRANSFER_MODE if not find.
+ */
+
+ dma = sys_atula_find_dma_channel(control_6, dma_on, dma_off);
+
+ /*
+ * Restore original contents of ATULA control register 6.
+ */
+
+ sys_probe_outsb(control_6, original_ctrl6);
+ }
+
+ /*
+ * Return discovered DMA channel details.
+ */
+
+ return dma;
+}
+#endif
+
+
+/*---------------------------------------------------------------------------
+|
+| hwi_atula_valid_transfer_mode
+| =============================
+|
+| The hwi_atula_valid_transfer mode routine checks to see if the user has
+| supplied a valid transfer mode for an ATULA based adapter card.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_atula_valid_transfer_mode)
+#endif
+
+local WBOOLEAN
+hwi_atula_valid_transfer_mode(
+ ADAPTER * adapter
+ )
+{
+ WBOOLEAN mode_valid;
+
+ /*
+ * Assume that transfer mode is valid.
+ */
+
+ mode_valid = TRUE;
+
+ /*
+ * MMIO is always invalid.
+ */
+
+ if (adapter->transfer_mode == MMIO_DATA_TRANSFER_MODE)
+ {
+ mode_valid = FALSE;
+ }
+
+ /*
+ * PIO is always valid but DMA may not be.
+ */
+
+ else if (adapter->transfer_mode == DMA_DATA_TRANSFER_MODE)
+ {
+ if (adapter->adapter_card_revision == ADAPTER_CARD_16_4_PC ||
+ adapter->adapter_card_revision == ADAPTER_CARD_16_4_ISA_C ||
+ adapter->adapter_card_revision == ADAPTER_CARD_16_4_ISA_C_P)
+ {
+ mode_valid = FALSE;
+ }
+ }
+
+ if (!mode_valid)
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_17_BAD_TRANSFER_MODE;
+ }
+
+ return mode_valid;
+}
+
+/*---------------------------------------------------------------------------
+|
+| hwi_atula_valid_irq_channel
+| ===========================
+|
+| The hwi_atula_valid_irq_channel routine checks to see if the user has
+| supplied a valid interrupt number for an ATULA based adapter card.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_atula_valid_irq_channel)
+#endif
+
+local WBOOLEAN
+hwi_atula_valid_irq_channel(
+ ADAPTER * adapter
+ )
+{
+ WBOOLEAN int_valid;
+
+ /*
+ * Assume that interrupt number is valid.
+ */
+
+ int_valid = TRUE;
+
+ /*
+ * No need to do any check on interrupt number if in polling mode.
+ */
+
+ if (adapter->interrupt_number != POLLING_INTERRUPTS_MODE)
+ {
+ /*
+ * Check the interrupt number based on adapter type.
+ */
+
+ if (adapter->adapter_card_revision == ADAPTER_CARD_16_4_PC)
+ {
+ switch (adapter->interrupt_number)
+ {
+ case 2 :
+ case 3 :
+ case 5 :
+ case 7 :
+ case 9 :
+ break;
+
+ default :
+ int_valid = FALSE;
+ break;
+
+ }
+ }
+ else
+ {
+ switch (adapter->interrupt_number)
+ {
+ case 2 :
+ case 3 :
+ case 5 :
+ case 7 :
+ case 9 :
+ case 10 :
+ case 11 :
+ case 12 :
+ case 15 :
+ break;
+
+ default :
+ int_valid = FALSE;
+ break;
+ }
+ }
+ }
+
+ if (!int_valid)
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_03_BAD_INTERRUPT_NUMBER;
+ }
+
+ return int_valid;
+}
+
+/*---------------------------------------------------------------------------
+|
+| hwi_atula_valid_dma_channel
+| ===========================
+|
+| The hwi_atula_valid_dma_channel routine checks to see if the user has
+| supplied a valid DMA channel for an ATULA based adapter card.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_atula_valid_dma_channel)
+#endif
+
+local WBOOLEAN
+hwi_atula_valid_dma_channel(
+ ADAPTER * adapter
+ )
+{
+ WBOOLEAN dma_valid;
+
+ /*
+ * Assume that DMA channel is valid.
+ */
+
+ dma_valid = TRUE;
+
+ /*
+ * Only need to check on DMA channel in DMA mode.
+ */
+
+ if (adapter->transfer_mode == DMA_DATA_TRANSFER_MODE)
+ {
+ /*
+ * Some adapters do not support DMA.
+ */
+
+ if (adapter->adapter_card_revision == ADAPTER_CARD_16_4_PC ||
+ adapter->adapter_card_revision == ADAPTER_CARD_16_4_ISA_C ||
+ adapter->adapter_card_revision == ADAPTER_CARD_16_4_ISA_C_P)
+ {
+ dma_valid = FALSE;
+ }
+ else if (adapter->adapter_card_revision == ADAPTER_CARD_16_4_AT_P ||
+ adapter->adapter_card_revision == ADAPTER_CARD_16_4_FIBRE_P)
+ {
+ switch (adapter->dma_channel)
+ {
+ case 3 :
+ case 5 :
+ case 6 :
+ break;
+
+ default :
+ dma_valid = FALSE;
+ break;
+ }
+ }
+ else
+ {
+ switch (adapter->dma_channel)
+ {
+ case 1 :
+ case 3 :
+ case 5 :
+ case 6 :
+ break;
+
+ default :
+ dma_valid = FALSE;
+ break;
+ }
+ }
+ }
+
+ if (!dma_valid)
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_04_BAD_DMA_CHANNEL;
+ }
+
+ return dma_valid;
+}
+
+
+#endif
+
+/**** End of HWI_AT.C file *************************************************/
diff --git a/private/ntos/ndis/madge/driver/hwi_eisa.c b/private/ntos/ndis/madge/driver/hwi_eisa.c
new file mode 100644
index 000000000..741a8dadf
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/hwi_eisa.c
@@ -0,0 +1,1054 @@
+/****************************************************************************
+*
+* HWI_EISA.C : Part of the FASTMAC TOOL-KIT (FTK)
+*
+* HARDWARE INTERFACE MODULE FOR EISA CARDS
+*
+* Copyright (c) Madge Networks Ltd. 1990-1994
+*
+* COMPANY CONFIDENTIAL
+*
+*
+*****************************************************************************
+*
+* The purpose of the Hardware Interface (HWI) is to supply an adapter card
+* independent interface to any driver. It performs nearly all of the
+* functions that involve affecting SIF registers on the adapter cards.
+* This includes downloading code to, initializing, and removing adapters.
+*
+* The HWI_EISA.C module contains the routines specific to 16/4 EISA mk1
+* and mk2 cards which are necessary to install an adapter, to initialize
+* an adapter, to remove an adapter and to handle interrupts on an adapter.
+* Also supported are EISA Bridge nodes.
+*
+****************************************************************************/
+
+/*---------------------------------------------------------------------------
+|
+| DEFINITIONS
+|
+---------------------------------------------------------------------------*/
+
+#include "ftk_defs.h"
+
+/*---------------------------------------------------------------------------
+|
+| MODULE ENTRY POINTS
+|
+---------------------------------------------------------------------------*/
+
+#include "ftk_intr.h" /* routines internal to FTK */
+#include "ftk_extr.h" /* routines provided or used by external FTK user */
+
+#ifndef FTK_NO_EISA
+
+/*---------------------------------------------------------------------------
+|
+| LOCAL PROCEDURES
+|
+---------------------------------------------------------------------------*/
+
+local WBOOLEAN
+hwi_eisa_valid_io_location(
+ WORD io_location
+ );
+
+#ifndef FTK_NO_PROBE
+
+local WORD
+hwi_eisa_get_irq_channel(
+ WORD io_location
+ );
+
+#endif
+
+local WBOOLEAN
+hwi_eisa_valid_dma_channel(
+ WORD dma_channel
+ );
+
+local WBOOLEAN
+hwi_eisa_valid_irq_channel(
+ WORD irq_channel
+ );
+
+local WBOOLEAN
+hwi_eisa_valid_transfer_mode(
+ UINT transfer_mode
+ );
+
+#ifndef FTK_NO_PROBE
+/****************************************************************************
+*
+* hwi_eisa_probe_card
+* ===================
+*
+*
+* PARAMETERS (passed by hwi_probe_adapter) :
+* ==========================================
+*
+* PROBE * resources
+*
+* resources is an array structures used to identify and record specific
+* information about adapters found.
+*
+* UINT length
+*
+* length is the number of structures pointed to by reources.
+*
+* WORD * valid_locations
+*
+* valid_locations is an array of IO locations to examine for the presence
+* of an adapter. For EISA adapters with should be a subset of
+* {0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000, 0x9000}.
+*
+* UINT number_locations
+*
+* This is the number of IO locations in the above list.
+*
+* BODY :
+* ======
+*
+* The hwi_eisa_probe_card routine is called by hwi_probe_adapter. It
+* reads the id registers to find the type of card and also reads the IRQ.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine returns the number of adapters found, or PROBE_FAILURE if
+* there's a problem.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_eisa_probe_card)
+#endif
+
+export UINT
+hwi_eisa_probe_card(
+ PROBE * resources,
+ UINT length,
+ WORD * valid_locations,
+ UINT number_locations
+ )
+{
+ WBOOLEAN card_found;
+ WORD id_reg_0;
+ WORD id_reg_1;
+ WORD control_x;
+ WORD bmic_3;
+ UINT i;
+ UINT j;
+
+ /*
+ * Check the bounds are sensible.
+ */
+
+ if(length <= 0 || number_locations <= 0)
+ {
+ return PROBE_FAILURE;
+ }
+
+ for(i = 0; i < number_locations; i++)
+ {
+ if(!hwi_eisa_valid_io_location(valid_locations[i]))
+ {
+ return PROBE_FAILURE;
+ }
+ }
+
+ /*
+ * j is the number of adapters found. Unsurprisingly we zero it.
+ */
+
+ j = 0;
+
+ for(i = 0; i < number_locations; i++)
+ {
+ /*
+ * If we run out of PROBE structures then bomb out.
+ */
+
+ if(j >= length)
+ {
+ return(j);
+ }
+
+ /*
+ * Set up the EISA registers.
+ */
+
+ id_reg_0 = valid_locations[i] + EISA_ID_REGISTER_0;
+ id_reg_1 = valid_locations[i] + EISA_ID_REGISTER_1;
+ control_x = valid_locations[i] + EISA_CONTROLX_REGISTER;
+ bmic_3 = valid_locations[i] + EISA_BMIC_REGISTER_3;
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_probe_enable_io(valid_locations[i], EISA_IO_RANGE);
+#endif
+ card_found = FALSE;
+
+ /*
+ * Look for an EISA card.
+ */
+
+ if (sys_probe_insw(id_reg_0) == EISA_ID0_MDG_CODE)
+ {
+ if (sys_probe_insw(id_reg_1) == EISA_ID1_MK1_MDG_CODE)
+ {
+ resources[j].adapter_ram_size = 128;
+ card_found = TRUE;
+ }
+ else if (sys_probe_insw(id_reg_1) == EISA_ID1_MK2_MDG_CODE)
+ {
+ resources[j].adapter_ram_size = 256;
+ card_found = TRUE;
+ }
+ else if (sys_probe_insw(id_reg_1) == EISA_ID1_BRIDGE_MDG_CODE)
+ {
+ resources[j].adapter_ram_size = 256;
+ card_found = TRUE;
+ }
+ else if (sys_probe_insw(id_reg_1) == EISA_ID1_MK3_MDG_CODE)
+ {
+ resources[j].adapter_ram_size = 256;
+ card_found = TRUE;
+ }
+ }
+
+
+ if(card_found)
+ {
+ /*
+ * Wayhay! We found one. Let's set up some values.
+ */
+
+ resources[j].io_location = valid_locations[i];
+ resources[j].adapter_card_bus_type = ADAPTER_CARD_EISA_BUS_TYPE;
+ resources[j].adapter_card_type = ADAPTER_CARD_TYPE_16_4_EISA;
+ resources[j].interrupt_number = hwi_eisa_get_irq_channel(
+ valid_locations[i]);
+ resources[j].dma_channel = 0;
+ resources[j].transfer_mode = DMA_DATA_TRANSFER_MODE;
+
+ /*
+ * Increment j to point to the next structure and try again.
+ */
+
+ j++;
+ }
+#ifndef FTK_NO_IO_ENABLE
+ macro_probe_disable_io(resources->io_location, EISA_IO_RANGE);
+#endif
+ }
+
+ return(j);
+}
+#endif
+
+/****************************************************************************
+*
+* hwi_eisa_install_card
+* =====================
+*
+*
+* PARAMETERS (passed by hwi_install_adapter) :
+* ============================================
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+* DOWNLOAD_IMAGE * download_image
+*
+* This is the code to be downloaded to the adapter. The image must be of
+* the correct type i.e. must be downloadable into the adapter. If the
+* pointer is 0 downloading is not done.
+*
+*
+* BODY :
+* ======
+*
+* The hwi_eisa_install_card routine is called by hwi_install_adapter. It
+* sets up the adapter card and downloads the required code to it. Firstly,
+* it checks there is a valid adapter at the required IO address. If so it
+* sets up and checks numerous on-board registers for correct operation.
+* The node address can not be read from the BIA PROM at this stage.
+*
+* Then, it halts the EAGLE, downloads the code, restarts the EAGLE and
+* waits up to 3 seconds for a valid bring-up code. If interrupts are
+* required, these are enabled by operating system specific calls. There is
+* no need to explicitly enable DMA. Note PIO can not be used.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine returns TRUE if it succeeds. If this routine fails (returns
+* FALSE) then a subsequent call to driver_explain_error, with the adapter
+* handle corresponding to the adapter parameter used here, will give an
+* explanation.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_eisa_install_card)
+#endif
+
+export WBOOLEAN
+hwi_eisa_install_card(
+ ADAPTER * adapter,
+ DOWNLOAD_IMAGE * download_image
+ )
+{
+ ADAPTER_HANDLE handle = adapter->adapter_handle;
+ WORD id_reg_0 = adapter->io_location +
+ EISA_ID_REGISTER_0;
+ WORD id_reg_1 = adapter->io_location +
+ EISA_ID_REGISTER_1;
+ WORD control_x = adapter->io_location +
+ EISA_CONTROLX_REGISTER;
+ WORD bmic_3 = adapter->io_location +
+ EISA_BMIC_REGISTER_3;
+ WORD sif_base;
+
+ /*
+ * Check the IO location is valid.
+ */
+
+ if(!hwi_eisa_valid_io_location(adapter->io_location))
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_02_BAD_IO_LOCATION;
+
+ return FALSE;
+ }
+
+ /*
+ * Check the transfer mode is valid.
+ */
+
+ if(!hwi_eisa_valid_transfer_mode(adapter->transfer_mode))
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_02_BAD_IO_LOCATION;
+
+ return FALSE;
+ }
+
+ /*
+ * Check the DMA channel is valid.
+ */
+
+ if(!hwi_eisa_valid_dma_channel(adapter->dma_channel))
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_04_BAD_DMA_CHANNEL;
+
+ return FALSE;
+ }
+
+ /*
+ * Check the IRQ is valid.
+ */
+
+ if(!hwi_eisa_valid_irq_channel(adapter->interrupt_number))
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_03_BAD_INTERRUPT_NUMBER;
+
+ return FALSE;
+ }
+
+ /*
+ * Save IO locations of SIF registers.
+ */
+
+ sif_base = adapter->io_location + EISA_FIRST_SIF_REGISTER;
+
+ adapter->sif_dat = sif_base + EAGLE_SIFDAT;
+ adapter->sif_datinc = sif_base + EAGLE_SIFDAT_INC;
+ adapter->sif_adr = sif_base + EAGLE_SIFADR;
+ adapter->sif_int = sif_base + EAGLE_SIFINT;
+ adapter->sif_acl = sif_base + EISA_EAGLE_SIFACL;
+ adapter->sif_adr2 = sif_base + EISA_EAGLE_SIFADR_2;
+ adapter->sif_adx = sif_base + EISA_EAGLE_SIFADX;
+ adapter->sif_dmalen = sif_base + EISA_EAGLE_DMALEN;
+
+ adapter->io_range = EISA_IO_RANGE;
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ adapter->adapter_card_type = ADAPTER_CARD_TYPE_16_4_EISA;
+
+ if (sys_insw( handle, id_reg_0) == EISA_ID0_MDG_CODE)
+ {
+ if (sys_insw( handle, id_reg_1) == EISA_ID1_MK1_MDG_CODE)
+ {
+ adapter->adapter_card_revision = ADAPTER_CARD_16_4_EISA_MK1;
+ adapter->adapter_ram_size = 128;
+ }
+ else if (sys_insw( handle, id_reg_1) == EISA_ID1_MK2_MDG_CODE)
+ {
+ adapter->adapter_card_revision = ADAPTER_CARD_16_4_EISA_MK2;
+ adapter->adapter_ram_size = 256;
+ }
+ else if (sys_insw( handle, id_reg_1) == EISA_ID1_BRIDGE_MDG_CODE)
+ {
+ adapter->adapter_card_revision = ADAPTER_CARD_16_4_EISA_BRIDGE;
+ adapter->adapter_ram_size = 256;
+ }
+ else if (sys_insw( handle, id_reg_1) == EISA_ID1_MK3_MDG_CODE)
+ {
+ adapter->adapter_card_revision = ADAPTER_CARD_16_4_EISA_MK3;
+ adapter->adapter_ram_size = 256;
+ }
+ else
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_05_ADAPTER_NOT_FOUND;
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+ }
+
+ /*
+ * Check that the adapter card is enabled.
+ * If not then fill in error record and return.
+ */
+
+ if ((sys_insb( handle, control_x) & EISA_CTRLX_CDEN) == 0)
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_0D_CARD_NOT_ENABLED;
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+
+ /*
+ * Check that a speed has been selected for the card.
+ * If not then fill in error record and return.
+ */
+
+ if ((sys_insb( handle, bmic_3) & EISA_BMIC3_SPD) == 0)
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_0E_NO_SPEED_SELECTED;
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+
+ /*
+ * Discover whether interrupts are edge or level triggered.
+ */
+
+ if ((sys_insb( handle, bmic_3) & EISA_BMIC3_EDGE) == 0)
+ {
+ adapter->edge_triggered_ints = TRUE;
+ }
+ else
+ {
+ adapter->edge_triggered_ints = FALSE;
+ }
+
+ /*
+ * Machine reset does not affect speed or media setting of EISA cards.
+ * Also we cannot find adapter node address at this stage for EISA cards.
+ * The adapter permanent address remains all zeroes.
+ *
+ * There are no other special control registers to set for EISA cards
+ * and no issue of bringing adapter out of reset state.
+ */
+
+ /*
+ * Halt the eagle. No need to page in extended SIF registers for
+ * EISA cards.
+ */
+
+ hwi_halt_eagle(adapter);
+
+ /*
+ * download code to adapter.
+ * View download image as a sequence of download records. Pass address
+ * of routine to set up DIO addresses on EISA cards. If routine fails
+ * return failure (error record already filled in).
+ */
+
+ if (!hwi_download_code(
+ adapter,
+ (DOWNLOAD_RECORD *) download_image,
+ hwi_eisa_set_dio_address))
+ {
+ return FALSE;
+ }
+
+ /*
+ * Start the eagle.
+ */
+
+ hwi_start_eagle(adapter);
+
+ /*
+ * Wait for a valid bring up code, may wait 3 seconds.
+ * If routine fails return failure (error record already filled in).
+ */
+
+ if (!hwi_get_bring_up_code( adapter))
+ {
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return(FALSE);
+ }
+
+ /*
+ * Set DIO address to point to EAGLE DATA page 0x10000L.
+ */
+
+ hwi_eisa_set_dio_address(adapter, DIO_LOCATION_EAGLE_DATA_PAGE);
+
+ /*
+ * Set maximum frame size from the ring speed.
+ */
+
+ adapter->max_frame_size = hwi_get_max_frame_size(adapter);
+
+ /*
+ * Set the ring speed.
+ */
+
+ adapter->ring_speed = hwi_get_ring_speed(adapter);
+
+ /*
+ * If we have a mark 3 adapter then we need to initialise the
+ * VRAM by writing 0xffff to 0xc0000 in DIO space. Remember to
+ * to set the extended address register back to the Eagle
+ * data page.
+ */
+
+ if (adapter->adapter_card_revision == ADAPTER_CARD_16_4_EISA_MK3)
+ {
+ hwi_eisa_set_dio_address(adapter, DIO_LOCATION_EISA_VRAM_ENABLE);
+ sys_outsw(handle, adapter->sif_dat, EISA_VRAM_ENABLE_WORD);
+ hwi_eisa_set_dio_address(adapter, DIO_LOCATION_EAGLE_DATA_PAGE);
+ }
+
+ /*
+ * If not in polling mode then set up interrupts.
+ * interrupts_on field is used when disabling interrupts for adapter.
+ */
+
+ if (adapter->interrupt_number != POLLING_INTERRUPTS_MODE)
+ {
+ adapter->interrupts_on =
+ sys_enable_irq_channel( handle, adapter->interrupt_number);
+
+ if (!adapter->interrupts_on)
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_0B_FAIL_IRQ_ENABLE;
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+ }
+ else
+ {
+ adapter->interrupts_on = TRUE;
+ }
+
+ /*
+ * No need to explicitly enable interrupts at adapter for EISA card
+ * and no need to explicitly set up DMA channel.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return TRUE;
+
+}
+
+
+/****************************************************************************
+*
+* hwi_eisa_interrupt_handler
+* ==========================
+*
+*
+* PARAMETERS (passed by hwi_interrupt_entry) :
+* ============================================
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+*
+* BODY :
+* ======
+*
+* The hwi_eisa_interrupt_handler routine is called, when an interrupt
+* occurs, by hwi_interrupt_entry. It checks to see if a particular card
+* has interrupted. The interrupt could be generated by the SIF only.
+* There are no PIO interupts on EISA cards. Note it could in fact be the
+* case that no interrupt has occured on the particular adapter being
+* checked.
+*
+* On SIF interrupts, the interrupt is acknowledged and cleared. The value
+* in the SIF interrupt register is recorded in order to pass it to the
+* driver_interrupt_entry routine (along with the adapter details).
+*
+*
+* RETURNS :
+* =========
+*
+* The routine always successfully completes.
+*
+****************************************************************************/
+
+#ifdef FTK_IRQ_FUNCTION
+#pragma FTK_IRQ_FUNCTION(hwi_eisa_interrupt_handler)
+#endif
+
+export void
+hwi_eisa_interrupt_handler(
+ ADAPTER * adapter
+ )
+{
+ ADAPTER_HANDLE handle = adapter->adapter_handle;
+ WORD control_x = adapter->io_location +
+ EISA_CONTROLX_REGISTER;
+ WORD sifint_register = adapter->sif_int;
+ WORD sifint_value;
+ WORD sifint_tmp;
+
+ /*
+ * Inform system about the IO ports we are going to access.
+ * Enable maximum number of IO locations used by any adapter card.
+ * Do this so at driver level we can disable IO not knowing the adapter
+ * type.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ /*
+ * Check for SIF interrupt. (We don't get PIO interrupts on EISA cards).
+ */
+
+ if ((sys_insw(handle, sifint_register) &
+ FASTMAC_SIFINT_IRQ_DRIVER) != 0)
+ {
+ /*
+ * A SIF interrupt has occurred. This could be an SRB free,
+ * an adapter check or a received frame interrupt
+
+ * No need to acknowledge interrupt at EISA card.
+ * Clear EAGLE_SIFINT_HOST_IRQ to acknowledge interrupt at SIF.
+
+ * WARNING: Do NOT reorder the clearing of the SIFINT register with
+ * the reading of it. If SIFINT is cleared after reading it, any
+ * interrupts raised after reading it will be lost. Admittedly
+ * this is a small time frame, but it is important.
+ */
+
+ sys_outsw(handle, adapter->sif_int, 0);
+
+ /*
+ * Record the EAGLE SIF interrupt register value.
+
+ * WARNING: Continue to read the SIFINT register until it is stable
+ * because of a potential problem involving the host reading the
+ * register after the adapter has written the low byte of it, but
+ * before it has written the high byte. Failure to wait for the
+ * SIFINT register to settle can cause spurious interrupts.
+ */
+
+ sifint_value = sys_insw(handle, adapter->sif_int);
+ do
+ {
+ sifint_tmp = sifint_value;
+ sifint_value = sys_insw(
+ handle,
+ adapter->sif_int);
+ }
+ while (sifint_tmp != sifint_value);
+
+ /*
+ * Acknowledge/clear interrupt at interrupt controller.
+ */
+
+#ifndef FTK_NO_CLEAR_IRQ
+ sys_clear_controller_interrupt(handle, adapter->interrupt_number);
+#endif
+
+ /*
+ * No need regenerate any interrupts when using level sensitive.
+ * For edge triggered we need to disable\enable board to regenerate
+ * interrupts.
+ */
+
+ if (adapter->edge_triggered_ints)
+ {
+ macro_clearb_bit(handle, control_x, EISA_CTRLX_CDEN);
+ macro_setb_bit(handle, control_x, EISA_CTRLX_CDEN);
+ }
+
+ /*
+ * Call driver with details of SIF interrupt.
+ */
+
+ driver_interrupt_entry(handle, adapter, sifint_value);
+
+ }
+
+ /*
+ * Let the system know we have finished accessing the IO ports.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+
+}
+
+
+/****************************************************************************
+*
+* hwi_eisa_remove_card
+* ====================
+*
+*
+* PARAMETERS (passed by hwi_remove_adapter) :
+* ===========================================
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+*
+* BODY :
+* ======
+*
+* The hwi_eisa_remove_card routine is called by hwi_remove_adapter. It
+* disables interrupts if they are being used. It also resets the adapter.
+* Note there is no need to explicitly disable DMA channels.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine always successfully completes.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(hwi_eisa_remove_card)
+#endif
+
+export void
+hwi_eisa_remove_card(
+ ADAPTER * adapter
+ )
+{
+ ADAPTER_HANDLE handle = adapter->adapter_handle;
+ WORD sif_acontrol = adapter->sif_acl;
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ /*
+ * Disable interrupts. Only need to do this if interrupts successfully
+ * enabled.
+ * Interrupts must be disabled at adapter before unpatching interrupt.
+ * Even in polling mode we must turn off interrupts at adapter.
+ */
+
+ if (adapter->interrupts_on)
+ {
+ macro_clearw_bit( handle, sif_acontrol, EAGLE_SIFACL_SINTEN);
+
+ if (adapter->interrupt_number != POLLING_INTERRUPTS_MODE)
+ {
+ sys_disable_irq_channel(handle, adapter->interrupt_number);
+ }
+ adapter->interrupts_on = FALSE;
+
+ }
+
+ /*
+ * Perform adapter reset, set EAGLE_SIFACL_ARESET high.
+ */
+
+ macro_setw_bit( handle, sif_acontrol, EAGLE_SIFACL_ARESET);
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+}
+
+
+/****************************************************************************
+*
+* hwi_eisa_set_dio_address
+* ========================
+*
+* The hwi_eisa_set_dio_address routine is used, with EISA cards, for
+* putting a 32 bit DIO address into the SIF DIO address and extended DIO
+* address registers. Note that the extended address register should be
+* loaded first.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_eisa_set_dio_address)
+#endif
+
+export void
+hwi_eisa_set_dio_address(
+ ADAPTER * adapter,
+ DWORD dio_address
+ )
+{
+ ADAPTER_HANDLE handle = adapter->adapter_handle;
+ WORD sif_dio_adr = adapter->sif_adr;
+ WORD sif_dio_adrx = adapter->sif_adx;
+
+ /*
+ * Load extended DIO address register with top 16 bits of address.
+ * Always load extended address register first.
+ * Note EISA cards have single page of all SIF registers, hence do not
+ * need page in certain SIF registers.
+ */
+
+ sys_outsw(
+ handle,
+ sif_dio_adrx,
+ (WORD)(dio_address >> 16));
+
+ /*
+ * Load DIO address register with low 16 bits of address.
+ */
+
+ sys_outsw(
+ handle,
+ sif_dio_adr,
+ (WORD)(dio_address & 0x0000FFFF));
+
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| LOCAL PROCEDURES
+|
+---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+|
+| hwi_eisa_valid_io_location
+| ==========================
+|
+| The hwi_eisa_valid_io_location routine checks to see if the user has
+| supplied a valid IO location for an EISA adapter card.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_eisa_valid_io_location)
+#endif
+
+export WBOOLEAN
+hwi_eisa_valid_io_location(
+ WORD io_location
+ )
+{
+ WBOOLEAN io_valid;
+
+ switch (io_location)
+ {
+ case 0x1000 :
+ case 0x2000 :
+ case 0x3000 :
+ case 0x4000 :
+ case 0x5000 :
+ case 0x6000 :
+ case 0x7000 :
+ case 0x8000 :
+ case 0x9000 :
+ case 0xA000 :
+ case 0xB000 :
+ case 0xC000 :
+ case 0xD000 :
+ case 0xE000 :
+ case 0xF000 :
+
+ io_valid = TRUE;
+ break;
+
+ default :
+
+ io_valid = FALSE;
+ break;
+
+ }
+
+ return(io_valid);
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| hwi_eisa_valid_irq_channel
+| ==========================
+|
+| The hwi_eisa_valid_irq_channel routine checks to see if the user has
+| supplied a sensible IRQ for an EISA adapter card.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_eisa_valid_irq_channel)
+#endif
+
+export WBOOLEAN
+hwi_eisa_valid_irq_channel(
+ WORD irq_channel
+ )
+{
+ WBOOLEAN int_valid = TRUE;
+
+
+ if (irq_channel != POLLING_INTERRUPTS_MODE)
+ {
+ switch (irq_channel)
+ {
+ case 3:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 15:
+ break;
+
+ default:
+ int_valid = FALSE;
+ }
+ }
+
+ return int_valid;
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| hwi_eisa_valid_dma_channel
+| ==========================
+|
+| The hwi_eisa_valid_dma_channel routine checks to see if the user has
+| supplied a sensible dma channel for an EISA adapter card.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_eisa_valid_dma_channel)
+#endif
+
+export WBOOLEAN
+hwi_eisa_valid_dma_channel(
+ WORD dma_channel
+ )
+{
+ return (dma_channel == 0);
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| hwi_eisa_valid_transfer_mode
+| ============================
+|
+| The hwi_eisa_valid_transfer_mode routine checks to see if the user has
+| supplied a sensible transfer mode for an EISA adapter card. That means DMA
+| at the moment.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_eisa_valid_transfer_mode)
+#endif
+
+export WBOOLEAN
+hwi_eisa_valid_transfer_mode(
+ UINT transfer_mode
+ )
+{
+ return (transfer_mode == DMA_DATA_TRANSFER_MODE);
+}
+
+#ifndef FTK_NO_PROBE
+/*---------------------------------------------------------------------------
+|
+| hwi_eisa_get_irq_channel
+| ========================
+|
+| The hwi_eisa_get_irq_channel routine determines the interrupt number
+| that an EISA card is using. It does this by looking at one of the BMIC
+| registers. It always succeeds in finding the interrupt number being
+| used.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_eisa_get_irq_channel)
+#endif
+
+local WORD
+hwi_eisa_get_irq_channel(
+ WORD io_location
+ )
+{
+ WORD bmic_3 = io_location + EISA_BMIC_REGISTER_3;
+ WORD irq;
+
+ /*
+ * The interrupt number is in four bits (3,2,1,0) in BMIC register 3.
+ */
+
+ irq = sys_probe_insb(bmic_3) & EISA_BMIC3_IRQSEL;
+
+ /*
+ * Interrupt 2 needs to be changed to 9 for system routines.
+ */
+
+ if (irq == 2)
+ {
+ irq = 9;
+ }
+
+ /*
+ * Return the discovered interrupt number.
+ */
+
+ return(irq);
+}
+#endif
+
+#endif
+
+/******** End of HWI_EISA.C ************************************************/
diff --git a/private/ntos/ndis/madge/driver/hwi_gen.c b/private/ntos/ndis/madge/driver/hwi_gen.c
new file mode 100644
index 000000000..d0a2d7928
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/hwi_gen.c
@@ -0,0 +1,2077 @@
+/****************************************************************************
+*
+* HWI_GEN.C : Part of the FASTMAC TOOL-KIT (FTK)
+*
+* THE GENERAL HARDWARE INTERFACE MODULE
+*
+* Copyright (c) Madge Networks Ltd. 1990-1994
+*
+* COMPANY CONFIDENTIAL
+*
+*****************************************************************************
+*
+* The purpose of the Hardware Interface (HWI) is to supply an adapter card
+* independent interface to any driver. It performs nearly all of the
+* functions that involve affecting SIF registers on the adapter cards.
+* This includes downloading code to, initializing, and removing adapters.
+*
+* The HWI_GEN.C module contains the general routines necessary to install
+* an adapter, to initialize an adapter, to remove an adapter and to handle
+* interrupts on an adapter. It does not contain the routines specific to a
+* particular card type involved in any of these processes. These are in
+* the relevant HWI_<card_type>.C modules.
+*
+****************************************************************************/
+
+/*---------------------------------------------------------------------------
+|
+| DEFINITIONS
+|
+---------------------------------------------------------------------------*/
+
+#include "ftk_defs.h"
+
+/*---------------------------------------------------------------------------
+|
+| MODULE ENTRY POINTS
+|
+---------------------------------------------------------------------------*/
+
+#include "ftk_intr.h" /* routines internal to FTK */
+#include "ftk_extr.h" /* routines provided or used by external FTK user */
+
+/*---------------------------------------------------------------------------
+|
+| GLOBAL VARIABLES
+|
+---------------------------------------------------------------------------*/
+
+local BYTE scb_test_pattern[] = SCB_TEST_PATTERN_DATA;
+local BYTE ssb_test_pattern[] = SSB_TEST_PATTERN_DATA;
+
+/*---------------------------------------------------------------------------
+|
+| LOCAL PROCEDURES
+|
+---------------------------------------------------------------------------*/
+
+local void
+hwi_copy_to_dio_space(
+ ADAPTER * adapter,
+ DWORD dio_location,
+ BYTE * download_data,
+ WORD data_length_bytes
+ );
+
+local WBOOLEAN
+hwi_get_init_code(
+ ADAPTER * adapter
+ );
+
+#ifndef FTK_NO_PROBE
+/****************************************************************************
+*
+* hwi_deprobe_adapter
+* ===================
+*
+*
+* PARAMETERS :
+* ============
+*
+* PROBE * probe_values
+*
+* This structure identifies cards that have been probed.
+*
+* UINT length
+*
+* The length of the above array.
+*
+* BODY :
+* ======
+*
+* The hwi_deprobe_adapter routine uses the card bus type to call the
+* correct hwi_<card_type>_deprobe_card routine.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine returns TRUE if it succeeds.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(hwi_deprobe_adapter)
+#endif
+
+export WBOOLEAN
+hwi_deprobe_adapter(
+ PROBE * resources,
+ UINT length
+ )
+{
+ WBOOLEAN success = TRUE;
+ UINT i;
+
+ for(i = 0; i < length; i++)
+ {
+ switch(resources[i].adapter_card_bus_type)
+ {
+ /*
+ * As it stands the only adapter that needs to be deprobed is a
+ * PCMCIA, since it has to deregister with card services.
+ */
+
+#ifndef FTK_NO_PCMCIA
+ case ADAPTER_CARD_PCMCIA_BUS_TYPE :
+ success = success && hwi_pcmcia_deprobe_card(resources[i]);
+ break;
+#endif
+ default :
+ break;
+ }
+ }
+
+ return(success);
+}
+
+/****************************************************************************
+*
+* hwi_probe_adapter
+* =================
+*
+*
+* PARAMETERS (passed by driver_probe_adapter) :
+* =============================================
+*
+* WORD adapter_card_bus_type
+*
+* the bus type of the card, so we can switch to the correct hwi module.
+*
+* PROBE * resources
+*
+* resources is an array structures used to identify and record specific
+* information about adapters found.
+*
+* UINT length
+*
+* length is the number of structures pointed to by reources.
+*
+* WORD * valid_locations
+*
+* valid_locations is an array of IO locations to examine for the presence
+* of an adapter.
+*
+* UINT number_locations
+*
+* This is the number of IO locations in the above list.
+*
+* BODY :
+* ======
+*
+* The hwi_probe_adapter routine is called by driver_probe_adapter. It
+* switches to a hwi_<card type>_probe_card routine which does the work.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine returns the value returned from below.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_probe_adapter)
+#endif
+
+export UINT
+hwi_probe_adapter(
+ WORD adapter_card_bus_type,
+ PROBE * resources,
+ UINT length,
+ WORD * valid_locations,
+ UINT number_locations
+ )
+{
+ UINT number_found;
+ UINT i;
+
+ /*
+ * Mark all resource entries as undefined to start off with.
+ */
+
+ for (i = 0; i < length; i++)
+ {
+ resources[i].socket = FTK_UNDEFINED;
+ resources[i].adapter_card_bus_type = FTK_UNDEFINED;
+ resources[i].adapter_card_type = FTK_UNDEFINED;
+ resources[i].adapter_card_revision = FTK_UNDEFINED;
+ resources[i].adapter_ram_size = FTK_UNDEFINED;
+ resources[i].io_location = FTK_UNDEFINED;
+ resources[i].interrupt_number = FTK_UNDEFINED;
+ resources[i].dma_channel = FTK_UNDEFINED;
+ resources[i].transfer_mode = FTK_UNDEFINED;
+ resources[i].mmio_base_address = FTK_UNDEFINED;
+ }
+
+ /*
+ * And call the appropriate probe routine.
+ */
+
+ switch(adapter_card_bus_type)
+ {
+#ifndef FTK_NO_ATULA
+ case ADAPTER_CARD_ATULA_BUS_TYPE :
+ number_found = hwi_atula_probe_card(resources,
+ length,
+ valid_locations,
+ number_locations);
+ break;
+#endif
+#ifndef FTK_NO_PNP
+ case ADAPTER_CARD_PNP_BUS_TYPE :
+ number_found = hwi_pnp_probe_card(resources,
+ length,
+ valid_locations,
+ number_locations);
+ break;
+#endif
+#ifndef FTK_NO_MC
+ case ADAPTER_CARD_MC_BUS_TYPE :
+ number_found = hwi_mc_probe_card(resources,
+ length,
+ valid_locations,
+ number_locations);
+ break;
+#endif
+#ifndef FTK_NO_EISA
+ case ADAPTER_CARD_EISA_BUS_TYPE :
+ number_found = hwi_eisa_probe_card(resources,
+ length,
+ valid_locations,
+ number_locations);
+ break;
+#endif
+#ifndef FTK_NO_SMART16
+ case ADAPTER_CARD_SMART16_BUS_TYPE :
+ number_found = hwi_smart16_probe_card(resources,
+ length,
+ valid_locations,
+ number_locations);
+ break;
+#endif
+#ifndef FTK_NO_PCI
+ case ADAPTER_CARD_PCI_BUS_TYPE :
+ number_found = hwi_pci_probe_card(resources,
+ length,
+ valid_locations,
+ number_locations);
+ break;
+#endif
+#ifndef FTK_NO_PCMCIA
+ case ADAPTER_CARD_PCMCIA_BUS_TYPE :
+ number_found = hwi_pcmcia_probe_card(resources,
+ length,
+ valid_locations,
+ number_locations);
+ break;
+#endif
+#ifndef FTK_NO_PCI_TI
+ case ADAPTER_CARD_TI_PCI_BUS_TYPE :
+ number_found = hwi_pcit_probe_card(resources,
+ length,
+ valid_locations,
+ number_locations);
+ break;
+#endif
+#ifndef FTK_NO_PCI2
+ case ADAPTER_CARD_PCI2_BUS_TYPE :
+ number_found = hwi_pci2_probe_card(resources,
+ length,
+ valid_locations,
+ number_locations);
+ break;
+#endif
+
+ default :
+
+ /*
+ * Bad adapter card bus type so fail.
+ */
+
+ number_found = 0;
+ break;
+ }
+
+ return number_found;
+}
+#endif
+
+
+#ifndef FTK_NO_DETECT
+/****************************************************************************
+*
+* hwi_read_rate_error
+* ===================
+*
+*
+* PARAMETERS (passed by driver_probe_adapter) :
+* =============================================
+*
+* ADAPTER * adapter
+*
+* The adapter structure
+*
+*
+* BODY :
+* ======
+*
+* The hwi_read_rate_error switches to a hwi_<card type>_read_rate_error
+* which reads the rate error bit of the C30. Normally this is visible in
+* the IO space of the bus interface chip, except for the AT space when we
+* read it through DIO.
+*
+* RETURNS :
+* =========
+*
+* The routine returns TRUE if there was a rate error.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_read_rate_error)
+#endif
+
+export WORD
+hwi_read_rate_error(
+ ADAPTER * adapter
+ )
+{
+ WBOOLEAN wrong_speed = FALSE;
+
+ switch (adapter->adapter_card_bus_type)
+ {
+
+#ifndef FTK_NO_ATULA
+ case ADAPTER_CARD_ATULA_BUS_TYPE :
+ wrong_speed = hwi_atula_read_rate_error(
+ adapter);
+
+ break;
+#endif
+ default:
+ {
+ wrong_speed = NOT_SUPP;
+ break;
+ }
+ }
+
+ return wrong_speed;
+}
+#endif /* FTK_NO_DETECT */
+
+
+/****************************************************************************
+*
+* hwi_install_adapter
+* ===================
+*
+*
+* PARAMETERS :
+* ============
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+* DOWNLOAD_IMAGE * download_image
+*
+* This is the code to be downloaded to the adapter. The image must be of
+* the correct type i.e. must be downloadable into the adapter. If the
+* pointer is 0 downloading is not done.
+*
+*
+* BODY :
+* ======
+*
+* The hwi_install_adapter routine uses the card bus type to call the
+* correct hwi_<card_type>_install_card routine.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine returns TRUE if it succeeds. If this routine fails (returns
+* FALSE) then a subsequent call to driver_explain_error, with the adapter
+* handle corresponding to the adapter parameter used here, will give an
+* explanation.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_install_adapter)
+#endif
+
+export WBOOLEAN
+hwi_install_adapter(
+ ADAPTER * adapter,
+ DOWNLOAD_IMAGE * download_image
+ )
+{
+ ADAPTER_HANDLE handle = adapter->adapter_handle;
+ WBOOLEAN install_success;
+
+ /*
+ * Record fact that adapter does not have interrupts or DMA enabled.
+ */
+
+ adapter->interrupts_on = FALSE;
+ adapter->dma_on = FALSE;
+
+ /*
+ * Cards do not support speed detect unless they have a C30.
+ */
+ adapter->speed_detect = FALSE;
+
+ /*
+ * Call correct install routine dependent on adapter card bus type.
+ */
+
+ switch (adapter->adapter_card_bus_type)
+ {
+#ifndef FTK_NO_ATULA
+ case ADAPTER_CARD_ATULA_BUS_TYPE :
+
+ /*
+ * Set up pointers to the functions we will need later.
+ */
+
+ adapter->interrupt_handler = hwi_atula_interrupt_handler;
+ adapter->remove_card = hwi_atula_remove_card;
+ adapter->set_dio_address = hwi_atula_set_dio_address;
+
+ /*
+ * Call the install routine.
+ */
+
+ install_success = hwi_atula_install_card(
+ adapter,
+ download_image);
+
+ break;
+#endif
+#ifndef FTK_NO_PNP
+ case ADAPTER_CARD_PNP_BUS_TYPE :
+
+ /*
+ * Set up pointers to the functions we will need later.
+ */
+
+ adapter->interrupt_handler = hwi_pnp_interrupt_handler;
+ adapter->remove_card = hwi_pnp_remove_card;
+ adapter->set_dio_address = hwi_pnp_set_dio_address;
+
+ /*
+ * Call the install routine.
+ */
+
+ install_success = hwi_pnp_install_card(
+ adapter,
+ download_image);
+
+ break;
+#endif
+#ifndef FTK_NO_MC
+ case ADAPTER_CARD_MC_BUS_TYPE :
+
+ adapter->interrupt_handler = hwi_mc_interrupt_handler;
+ adapter->remove_card = hwi_mc_remove_card;
+ adapter->set_dio_address = hwi_mc_set_dio_address;
+
+ install_success = hwi_mc_install_card(
+ adapter,
+ download_image);
+
+ break;
+#endif
+#ifndef FTK_NO_EISA
+ case ADAPTER_CARD_EISA_BUS_TYPE :
+
+ adapter->interrupt_handler = hwi_eisa_interrupt_handler;
+ adapter->remove_card = hwi_eisa_remove_card;
+ adapter->set_dio_address = hwi_eisa_set_dio_address;
+
+
+ install_success = hwi_eisa_install_card(
+ adapter,
+ download_image);
+
+ break;
+#endif
+#ifndef FTK_NO_SMART16
+ case ADAPTER_CARD_SMART16_BUS_TYPE :
+
+ adapter->interrupt_handler = hwi_smart16_interrupt_handler;
+ adapter->remove_card = hwi_smart16_remove_card;
+ adapter->set_dio_address = hwi_smart16_set_dio_address;
+
+ install_success = hwi_smart16_install_card(
+ adapter,
+ download_image);
+
+ break;
+#endif
+#ifndef FTK_NO_PCI
+ case ADAPTER_CARD_PCI_BUS_TYPE :
+
+ adapter->interrupt_handler = hwi_pci_interrupt_handler;
+ adapter->remove_card = hwi_pci_remove_card;
+ adapter->set_dio_address = hwi_pci_set_dio_address;
+
+
+ install_success = hwi_pci_install_card(
+ adapter,
+ download_image);
+
+ break;
+#endif
+#ifndef FTK_NO_PCMCIA
+ case ADAPTER_CARD_PCMCIA_BUS_TYPE :
+
+ adapter->interrupt_handler = hwi_pcmcia_interrupt_handler;
+ adapter->remove_card = hwi_pcmcia_remove_card;
+ adapter->set_dio_address = hwi_pcmcia_set_dio_address;
+
+ install_success = hwi_pcmcia_install_card(adapter, download_image);
+
+ break;
+#endif
+#ifndef FTK_NO_PCIT
+ case ADAPTER_CARD_TI_PCI_BUS_TYPE :
+
+ adapter->interrupt_handler = hwi_pcit_interrupt_handler;
+ adapter->remove_card = hwi_pcit_remove_card;
+ adapter->set_dio_address = hwi_pcit_set_dio_address;
+
+ install_success = hwi_pcit_install_card(
+ adapter,
+ download_image);
+
+ break;
+#endif
+
+#ifndef FTK_NO_PCI2
+ case ADAPTER_CARD_PCI2_BUS_TYPE :
+
+ adapter->interrupt_handler = hwi_pci2_interrupt_handler;
+ adapter->remove_card = hwi_pci2_remove_card;
+ adapter->set_dio_address = hwi_pci2_set_dio_address;
+
+ install_success = hwi_pci2_install_card(
+ adapter,
+ download_image);
+
+ break;
+#endif
+
+ default :
+
+ /*
+ * Bad adapter card bus type so fail.
+ */
+
+ install_success = FALSE;
+
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_01_BAD_CARD_BUS_TYPE;
+
+ break;
+ }
+
+ return install_success;
+}
+
+
+/****************************************************************************
+*
+* hwi_initialize_adapter
+* ======================
+*
+*
+* PARAMETERS :
+* ============
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+* INITIALIZATION_BLOCK * init_block
+*
+* This is the initialization block that is to be copied into DIO space
+* before performing the actual chipset initialization.
+*
+*
+* BODY :
+* ======
+*
+* The hwi_initialize_adapter routine performs the initialization of the
+* chipset. It sets up the TI initialization block and the general MAC
+* level smart software initialization parameters and copies these into DIO
+* space at 0x10A00 on the EAGLE. These are followed in DIO space by the
+* Fastmac module specific initialization block details. The
+* initialization is started and then the routine waits up to 11 seconds
+* for success or failure to be registered by the SIF interrupt register.
+* The DMAs that occur during initialization are also checked for success.
+* Note these DMAs may actually be done by PIO transfers by the HWI itself
+* for ATULA cards.
+*
+* During downloading BYTE fields in structures need to be swapped and
+* DWORDs need to have the UINTs within swapped around. This is because of
+* the low-high byte ordering on Intel machines and the high-low ordering
+* of the EAGLE and the byte swapping that automatically occurs when
+* downloading through the SIF. Note that the automatic byte swapping
+* means UINTs do not themselves need any special treatment.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine returns TRUE if it succeeds. If this routine fails (returns
+* FALSE) then a subsequent call to driver_explain_error, with the adapter
+* handle corresponding to the adapter parameter used here, will give an
+* explanation.
+*
+* On success we also exit with 0x0001 in the EAGLE_SIDADRX register.
+* This should never need to be altered by any user. This means for example
+* that the FTK driver need only interest itself in the non-extended SIF
+* registers.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_initialize_adapter)
+#endif
+
+#if 1
+sys_int53( void);
+#endif
+
+export WBOOLEAN
+hwi_initialize_adapter(
+ ADAPTER * adapter,
+ INITIALIZATION_BLOCK * init_block
+ )
+{
+ ADAPTER_HANDLE handle = adapter->adapter_handle;
+ FASTMAC_INIT_PARMS * fastmac_parms = &init_block->fastmac_parms;
+ WBOOLEAN init_success;
+ UINT i;
+ BYTE FAR * dma_test_scb_buff;
+ BYTE FAR * dma_test_ssb_buff;
+ DWORD dma_test_scb_phys;
+ DWORD dma_test_ssb_phys;
+#ifdef FMPLUS
+ WORD fmplus_buffer_size;
+ DWORD fmplus_max_buffmem;
+ WORD fmplus_max_buffers;
+#endif
+
+ /*
+ * Set up the TI initialization parameters. Those fields not set up here
+ * must be zero. Set up for burst DMA.
+ */
+
+ init_block->ti_parms.init_options = TI_INIT_OPTIONS_BURST_DMA;
+
+ /*
+ * Copy in 16/4 MC 32 configuration information. This data is zero for
+ * non-16/4 MC 32 cards.
+ */
+
+ init_block->ti_parms.madge_mc32_config = adapter->mc32_config;
+
+ /*
+ * Set up retry counts.
+ */
+
+ init_block->ti_parms.parity_retry = TI_INIT_RETRY_DEFAULT;
+ init_block->ti_parms.dma_retry = TI_INIT_RETRY_DEFAULT;
+
+ /*
+ * NB It is not safe to use the Fastmac receive buffer for the DMA test
+ * because if auto-open is used, a frame could be received before we
+ * have a chance to test the contents of this memory. So put both SSB
+ * and SCB in the Tx buffer.
+ */
+
+#ifdef FMPLUS
+ /*
+ * FMPlus does not have a transmit buffer it can use for the test DMAs,
+ * so we use a buffer previously allocated in the drv_init module.
+ */
+
+ dma_test_scb_buff = (BYTE FAR *) adapter->dma_test_buf_virt;
+ dma_test_scb_phys = adapter->dma_test_buf_phys;
+
+ dma_test_ssb_phys = dma_test_scb_phys + SCB_TEST_PATTERN_LENGTH;
+ dma_test_ssb_buff = dma_test_scb_buff + SCB_TEST_PATTERN_LENGTH;
+
+#else
+ /*
+ * For Fastmac, we use the transmit buffer for the test DMAs.
+ */
+
+ dma_test_scb_buff = (BYTE FAR *) adapter->tx_buffer_virt;
+ dma_test_scb_phys = adapter->tx_buffer_phys;
+
+ dma_test_ssb_phys = dma_test_scb_phys + SCB_TEST_PATTERN_LENGTH;
+ dma_test_ssb_buff = dma_test_scb_buff + SCB_TEST_PATTERN_LENGTH;
+
+ if (adapter->transfer_mode != DMA_DATA_TRANSFER_MODE)
+ {
+ fastmac_parms->tx_buf_physaddr = adapter->tx_buffer_virt;
+
+ fastmac_parms->rx_buf_physaddr = adapter->rx_buffer_virt;
+ }
+
+#endif
+
+ if (adapter->transfer_mode != DMA_DATA_TRANSFER_MODE)
+ {
+ /*
+ * PIO uses virtual addresses to save having to perform Phys-to-Virt
+ * conversions in the interrupt service routine.
+ */
+
+ init_block->ti_parms.scb_addr = (DWORD)dma_test_scb_buff;
+ init_block->ti_parms.ssb_addr = (DWORD)dma_test_ssb_buff;
+ }
+ else
+ {
+ /*
+ * DMA must use physical addresses, however. We already have these
+ * saved.
+ */
+
+ init_block->ti_parms.scb_addr = dma_test_scb_phys;
+ init_block->ti_parms.ssb_addr = dma_test_ssb_phys;
+ }
+
+
+ macro_word_swap_dword(init_block->ti_parms.scb_addr);
+ macro_word_swap_dword(init_block->ti_parms.ssb_addr);
+
+ #if 0
+ /*
+ * TMSDebug support
+ */
+ printf("\nTMSDebug Enabled\n");
+ init_block->smart_parms.reserved_1 = 3;
+ sys_int53();
+ #endif
+
+ /*
+ * Set up the smart software initialization parameters. Those fields
+ * not set up here must be zero.
+ * Set up header to identify the smart software initialization parms.
+ */
+
+ init_block->smart_parms.header.length = sizeof(SMART_INIT_PARMS);
+ init_block->smart_parms.header.signature = SMART_INIT_HEADER_SIGNATURE;
+ init_block->smart_parms.header.version = SMART_INIT_HEADER_VERSION;
+
+ /*
+ * Byte swap the permanent node address when setting it up.
+ */
+
+ init_block->smart_parms.permanent_address = adapter->permanent_address;
+
+ util_byte_swap_structure(
+ (BYTE *) &init_block->smart_parms.permanent_address,
+ sizeof(NODE_ADDRESS));
+
+#ifdef FMPLUS
+ /*
+ * Must set min_buffer_ram field for backwards compatibility with other
+ * Madge code (see FMPlus programming spec.)
+ */
+
+ init_block->smart_parms.min_buffer_ram = SMART_INIT_MIN_RAM_DEFAULT;
+#endif
+
+ /*
+ * Need to byte swap fields in the Fastmac specific init parms.
+ * These fields are the opening node address and the buffer addresses.
+ */
+
+ util_byte_swap_structure(
+ (BYTE *)&fastmac_parms->open_address,
+ sizeof(NODE_ADDRESS));
+
+#ifdef FMPLUS
+ /*
+ * Now work out the number of transmit and receive buffers.
+ * The number of buffers allocated depends on the maximum frame size
+ * anticipated, and on the amount of memory on the card. Unfortunately,
+ * one cannot know the maximum possible frame size until after the mac
+ * code has started and worked out what the ring speed is. Thus it is
+ * necessary to make an assumption about what the largest frame size
+ * supported will be.
+ */
+
+ /*
+ * First, work out how big the buffers are. Unless a different size has
+ * been specified, use the default buffer size.
+ */
+
+ fmplus_buffer_size = init_block->smart_parms.rx_tx_buffer_size;
+
+ /*
+ * MC32, EISA and PCIx cards use a smaller default buffer size than other
+ * cards do (16/4 AT and 16/4 MC cards).
+ */
+
+ if (adapter->adapter_card_type == ADAPTER_CARD_TYPE_16_4_EISA ||
+ adapter->adapter_card_type == ADAPTER_CARD_TYPE_16_4_MC_32 ||
+ adapter->adapter_card_type == ADAPTER_CARD_TYPE_16_4_PCI ||
+ adapter->adapter_card_type == ADAPTER_CARD_TYPE_16_4_PCIT ||
+ adapter->adapter_card_type == ADAPTER_CARD_TYPE_16_4_PCI2)
+ {
+ if (fmplus_buffer_size)
+ {
+ fmplus_buffer_size =
+ max(FMPLUS_MIN_TXRX_BUFF_SIZE,
+ min(FMPLUS_DEFAULT_BUFF_SIZE_SMALL, fmplus_buffer_size)
+ );
+ }
+ else
+ {
+ fmplus_buffer_size = FMPLUS_DEFAULT_BUFF_SIZE_SMALL;
+ }
+ }
+ else
+ {
+ if (fmplus_buffer_size)
+ {
+ fmplus_buffer_size =
+ max(FMPLUS_MIN_TXRX_BUFF_SIZE, fmplus_buffer_size);
+ }
+ else
+ {
+ fmplus_buffer_size = FMPLUS_DEFAULT_BUFF_SIZE_LARGE;
+ }
+ }
+
+ init_block->smart_parms.rx_tx_buffer_size = fmplus_buffer_size;
+
+ if (fmplus_buffer_size < FMPLUS_MIN_TXRX_BUFF_SIZE)
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_10_BAD_TX_RX_BUFF_SIZE;
+ return FALSE;
+ }
+
+ /*
+ * Next, work out how much memory on the card we can use for buffers.
+ */
+
+ if (adapter->adapter_ram_size == 128)
+ {
+ fmplus_max_buffmem = FMPLUS_MAX_BUFFMEM_IN_128K;
+ }
+ else if (adapter->adapter_ram_size == 256)
+ {
+ fmplus_max_buffmem = FMPLUS_MAX_BUFFMEM_IN_256K;
+ }
+ else if (adapter->adapter_ram_size == 512)
+ {
+ fmplus_max_buffmem = FMPLUS_MAX_BUFFMEM_IN_512K;
+ }
+ else
+ {
+ fmplus_max_buffmem = FMPLUS_MAX_BUFFMEM_IN_128K;
+ }
+
+ /*
+ * Use the two numbers worked out above to determine the maximum number
+ * of buffers we can fit on the card.
+ * The calculation is to round the buffer size up to the nearest 1K,
+ * and to divide that into the total amount of memory. The rounding up
+ * has to take account of the eight bytes buffer header that is added
+ * by FMP i.e. buffer_allocation = (buffer_size + 8 + 1023) 1024
+ * (there is also a "fudge-factor" of 5 buffers to allow the binary to
+ * grow a little from its current size!)
+ */
+
+ fmplus_max_buffers =
+ (WORD)(fmplus_max_buffmem / ((fmplus_buffer_size + 1031) & ~1023)) -
+ 5;
+
+ /*
+ * Finally, allocate the buffers between transmit and receive. Notice
+ * that we allow here for frames as big as they are ever going to get
+ * on token ring. For smaller frames and 4 Mbps rings, this will just
+ * have the effect of improving back-to-back transmit performance.
+ */
+
+ fastmac_parms->tx_bufs = 2 *
+ ((fastmac_parms->max_frame_size +
+ fmplus_buffer_size) /
+ fmplus_buffer_size);
+
+ fastmac_parms->rx_bufs = fmplus_max_buffers -
+ fastmac_parms->tx_slots -
+ fastmac_parms->tx_bufs;
+
+ /*
+ * When an error occurs is a little subjective at this point. It is, in
+ * fact, possible to receive a frame with only about three buffers, but
+ * for safety's sake, we demand that there be enough to receive a max.
+ * sized frame.
+ */
+
+ if (fastmac_parms->rx_bufs < fastmac_parms->tx_bufs)
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_11_TOO_MANY_TX_RX_BUFFS;
+ return (FALSE);
+ }
+
+#else
+ macro_word_swap_dword(fastmac_parms->tx_buf_physaddr);
+ macro_word_swap_dword(fastmac_parms->rx_buf_physaddr);
+#endif
+
+ /*
+ * Inform the system about the IO ports we are going to access.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ /*
+ * Download initialization block to required location in DIO space.
+ * Note routine leaves 0x0001 in EAGLE SIFADRX register.
+ */
+
+ hwi_copy_to_dio_space(
+ adapter,
+ DIO_LOCATION_INIT_BLOCK,
+ (BYTE *) init_block,
+ sizeof(INITIALIZATION_BLOCK));
+
+ /*
+ * After downloading byte swap back some Fastmac specific init parms.
+ * Fields are the opening node address and the Fastmac buffer addresses.
+ * This is especially important to do for the buffer addresses
+ * because they are used in transmit/receive routines.
+ */
+
+ util_byte_swap_structure(
+ (BYTE *)&fastmac_parms->open_address,
+ sizeof(NODE_ADDRESS));
+
+#ifndef FMPLUS
+ macro_word_swap_dword(fastmac_parms->tx_buf_physaddr);
+ macro_word_swap_dword(fastmac_parms->rx_buf_physaddr);
+
+ /*
+ * The mainline transmit receive code assumes that these values ar
+ * physical addresses, so we had better convert them back... The al-
+ * ternative would be to rewrite all the transmit and receive modules
+ * to note which transfer mode is in use.
+ */
+
+ if (adapter->transfer_mode != DMA_DATA_TRANSFER_MODE)
+ {
+ fastmac_parms->tx_buf_physaddr = adapter->tx_buffer_phys;
+
+ fastmac_parms->rx_buf_physaddr = adapter->rx_buffer_phys;
+ }
+
+#endif
+
+ /*
+ * Start initialization by output 0x9080 to SIF interrupt register.
+ */
+
+ sys_outsw(handle, adapter->sif_int, EAGLE_INIT_START_CODE);
+
+ /*
+ * Wait for a valid initialization code, may wait 11 seconds.
+ * During this process test DMAs need to occur, hence in PIO mode needs
+ * calls to hwi_interrupt_entry, hence need interrupts or polling active.
+ */
+
+ init_success = hwi_get_init_code(adapter);
+
+ /*
+ * Let the system know we have finished accessing the IO ports.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io( adapter );
+#endif
+
+ if (!init_success)
+ {
+ return FALSE;
+ }
+
+ /*
+ * Check that test DMAs were successful.
+ */
+
+ /*
+ * First check SCB for correct test pattern. Remember used Fastmac
+ * transmit buffer address for SCB address.
+ */
+
+ for (i = 0; i < SCB_TEST_PATTERN_LENGTH; i++)
+ {
+ if (dma_test_scb_buff[i] != scb_test_pattern[i])
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_07_FAILED_TEST_DMA;
+ return FALSE;
+ }
+ }
+
+ /*
+ * Now check SSB for correct test pattern. Remember used Fastmac
+ * receive buffer address for SSB address.
+ */
+
+ for (i = 0; i < SSB_TEST_PATTERN_LENGTH; i++)
+ {
+ if (dma_test_ssb_buff[i] != ssb_test_pattern[i])
+ {
+ /* fill in error record and fail if pattern doesn't match */
+
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_07_FAILED_TEST_DMA;
+ return FALSE;
+ }
+ }
+
+ /*
+ * Successful completion of initialization.
+ */
+
+ return TRUE;
+}
+
+
+/****************************************************************************
+*
+* hwi_get_node_address_check
+* ==========================
+*
+*
+* PARAMETERS :
+* ============
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+*
+* BODY :
+* ======
+*
+* The hwi_get_node_address_check routine reads the adapter's permanent
+* node address from the Fastmac status block (STB) in DIO space. It then
+* checks to see if this node address is a valid Madge address. This
+* checks that Fastmac is correctly installed.
+*
+* For ATULA and MC cards, the adapter node address has actually been read
+* once already. There is no harm in getting it again, from Fastmac this
+* time; (previously it was read from the BIA PROM). For EISA cards, the
+* node address has not been read previously. This is the first time we can
+* get it. The node address is not readable from the host with EISA cards.
+* Only Fastmac can find it out for us.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine returns TRUE if it succeeds. If this routine fails (returns
+* FALSE) then a subsequent call to driver_explain_error, with the adapter
+* handle corresponding to the adapter parameter used here, will give an
+* explanation.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_get_node_address_check)
+#endif
+
+export WBOOLEAN
+hwi_get_node_address_check(
+ ADAPTER * adapter
+ )
+{
+ ADAPTER_HANDLE handle = adapter->adapter_handle;
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ /*
+ * Get the permanent node address from the STB in DIO space.
+ * Record address in adapter structure.
+ */
+
+ sys_outsw(
+ handle,
+ adapter->sif_adr,
+ (WORD)(card_t)&adapter->stb_dio_addr->permanent_address);
+
+ sys_rep_insw(
+ handle,
+ adapter->sif_datinc,
+ (BYTE *)&adapter->permanent_address,
+ (sizeof(NODE_ADDRESS) / 2));
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io( adapter );
+#endif
+
+ /*
+ * Byte swap node address after reading from adapter.
+ */
+
+ util_byte_swap_structure(
+ (BYTE *) &adapter->permanent_address,
+ sizeof(NODE_ADDRESS));
+
+ return TRUE;
+}
+
+
+/****************************************************************************
+*
+* hwi_interrupt_entry
+* ===================
+*
+*
+* PARAMETERS :
+* ============
+*
+* UINT interrupt_number
+*
+* This is the interrupt number of the interrupting adapter card. If it is
+* zero (POLLING_INTERRUPTS_MODE) then all cards must be checked to see if
+* they require servicing.
+*
+*
+* BODY :
+* ======
+*
+* The hwi_interrupt_entry routine is either called by an operating system
+* specific interrupt detection routine with an actual interrupt number as
+* the parameter or, at intervals, by a routine passing the
+* POLLING_INTERRUPTS_MODE parameter. In the former case all adapters using
+* the given interrupt number are checked for outstanding interrupts. In
+* the latter case, ALL adapters are checked for outstanding interrupts.
+*
+* It is important that hwi_interrupt_entry is not re-entered with a
+* subsequent interrupt on the same adapter. Hence, in the polling case,
+* the routine that called hwi_interrupt_entry must not call it again until
+* the hwi finishes it's current execution. If real interrupts are being
+* used, then care must be taken not to turn interrupts on and allow a
+* further interrupt to cause hwi_interrupt_entry to be re-entered.
+*
+* The details of interrupt handling are dealt with by card specific
+* interrupt handlers. In general, for SIF Fastmac interrupts, th
+* interrupt is acknowledged at the SIF. Driver_interrupt_entry is then
+* called with the interrupt number, details of the relevant adapter and
+* the contents of the EAGLE_SIFINT register. If instead a PIO transfer is
+* required, then the necessary data transfer is performed between the
+* adapter and host memory. PIO can only occur with ATULA adapter cards.
+*
+*
+* Note on increasing speed:
+*
+* One way of speeding up execution of the interrupt routine would be to
+* replace the sys_outsw and sys_insw routines by similar routines supplied
+* with your C compiler and have them compiled in-line. This would be
+* particularly advantageous when handling PIO data transfer.
+*
+*
+* RETURNS :
+* =========
+*
+* This routine always completes successfully.
+*
+****************************************************************************/
+
+#ifdef FTK_IRQ_FUNCTION
+#pragma FTK_IRQ_FUNCTION(hwi_interrupt_entry)
+#endif
+
+export void
+hwi_interrupt_entry(
+ ADAPTER_HANDLE adapter_handle,
+ WORD interrupt_number
+ )
+{
+ ADAPTER * adapter;
+
+#ifndef FTK_NO_SHARED_IRQ_POLL
+ for (adapter_handle = 0;
+ adapter_handle < MAX_NUMBER_OF_ADAPTERS;
+ adapter_handle++)
+ {
+#endif
+
+ /*
+ * Get pointer to adapter structure.
+ */
+
+ adapter = adapter_record[adapter_handle];
+
+ /*
+ * In polling mode check ALL adapters.
+ * In interrupt mode check all adapters with correct int number.
+ * Only check actual running, working adapters.
+ */
+
+ if ((adapter != NULL) &&
+ (adapter->adapter_status == ADAPTER_RUNNING) &&
+ ((interrupt_number == POLLING_INTERRUPTS_MODE) ||
+ (adapter->interrupt_number == interrupt_number)))
+ {
+ /*
+ * Interrupts are handled by adapter modules.
+ */
+
+ (*(adapter->interrupt_handler))(adapter);
+ }
+
+#ifndef FTK_NO_SHARED_IRQ_POLL
+ }
+#endif
+
+ return;
+}
+
+
+/****************************************************************************
+*
+* hwi_remove_adapter
+* ==================
+*
+*
+* PARAMETERS :
+* ============
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+*
+* BODY :
+* ======
+*
+* The hwi_remove_adapter routine uses the card bus type to call the
+* correct hwi_<card_type>_remove_card routine.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine always successfully completes.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(hwi_remove_adapter)
+#endif
+
+export void
+hwi_remove_adapter(
+ ADAPTER * adapter
+ )
+{
+ ADAPTER_HANDLE handle = adapter->adapter_handle;
+
+ /*
+ * Call correct remove routine.
+ */
+
+ (*(adapter->remove_card))(adapter);
+
+ return;
+}
+
+/****************************************************************************
+*
+* UPCALL PROCEDURES - Used by hwi_<card type>.c modules
+*
+****************************************************************************/
+
+/****************************************************************************
+*
+* hwi_halt_eagle
+* ==============
+*
+* The hwi_halt_eagle routine halts the EAGLE. It does this by setting the
+* halt EAGLE bit in the SIF adapter control register. It also resets the
+* adapter by twiddling the adapter reset bit in the same register.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_halt_eagle)
+#endif
+
+export void
+hwi_halt_eagle(
+ ADAPTER * adapter
+ )
+{
+ ADAPTER_HANDLE handle = adapter->adapter_handle;
+ WORD sif_adapter_control_register = adapter->sif_acl;
+ WORD acontrol_output;
+
+ /*
+ * Set output for SIF register EAGLE_ACONTROL.
+ * Maintain parity; set halt, reset, enable SIF interrupts.
+ */
+
+ acontrol_output = (sys_insw(handle, sif_adapter_control_register) &
+ EAGLE_SIFACL_PARITY) |
+ EAGLE_SIFACL_ARESET |
+ EAGLE_SIFACL_CPHALT |
+ EAGLE_SIFACL_BOOT |
+ EAGLE_SIFACL_SINTEN |
+ adapter->nselout_bits;
+
+ if (adapter->EaglePsDMA)
+ {
+ acontrol_output |= EAGLE_SIFACL_PSDMAEN;
+ }
+
+ /*
+ * Wait at least 14 microseconds before putting adapter in reset state.
+ * We may have just taken adapter out of reset state.
+ * 14us is the minimum time must hold ARESET low between resets.
+ * Disable and re-enable accessing IO locations around wait so
+ * OS can reschedule this task and not effect others running.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io( adapter );
+#endif
+
+ sys_wait_at_least_microseconds(14);
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io( adapter );
+#endif
+
+ /*
+ * Output to SIF register EAGLE_ACONTROL to halt EAGLE.
+ */
+
+ sys_outsw(
+ handle,
+ sif_adapter_control_register,
+ acontrol_output);
+
+ /*
+ * Wait at least 14 microseconds before taking adapter out of reset
+ * state.
+ * 14us is the minimum time must hold ARESET low between resets.
+ * Disable and re-enable accessing IO locations around wait so
+ * OS can reschedule this task and not effect others running.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io( adapter );
+#endif
+
+ sys_wait_at_least_microseconds(14);
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io( adapter );
+#endif
+
+ /*
+ * Bring EAGLE out of reset state, maintain halt status.
+ */
+
+ sys_outsw(
+ handle,
+ sif_adapter_control_register,
+ (WORD) (acontrol_output & ~EAGLE_SIFACL_ARESET));
+
+ return;
+}
+
+
+/****************************************************************************
+*
+* hwi_download_code
+* =================
+*
+* The hwi_download_code routine downloads the given data to the adapter.
+* This must be done with the EAGLE halted. Besides details of the adapter
+* and a pointer to the first download reocrd of the download image, the
+* routine is passed a helper routine for setting DIO addresses for the
+* actual downloading.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_download_code)
+#endif
+
+export WBOOLEAN
+hwi_download_code(
+ ADAPTER * adapter,
+ DOWNLOAD_RECORD * download_record,
+ void (*set_dio_address)(ADAPTER *, DWORD)
+ )
+{
+ ADAPTER_HANDLE handle = adapter->adapter_handle;
+ WORD sif_data_inc_register = adapter->sif_datinc;
+ UINT i;
+
+ /*
+ * If there is no code to be downloaded then fail.
+ */
+
+ if (download_record == NULL)
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_0A_NO_DOWNLOAD_IMAGE;
+ return FALSE;
+ }
+
+ /*
+ * The first record in the image must be a MODULE type record.
+ */
+
+ if (download_record->type != DOWNLOAD_RECORD_TYPE_MODULE)
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_09_BAD_DOWNLOAD_IMAGE;
+ return FALSE;
+ }
+
+ /*
+ * The code to be downloaded must be Fastmac (Plus).
+ */
+
+ if ((download_record->body.module.download_features &
+ DOWNLOAD_FASTMAC_INTERFACE) == 0)
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_09_BAD_DOWNLOAD_IMAGE;
+ return FALSE;
+ }
+
+ /*
+ * Get the next download record.
+ */
+
+ macro_get_next_record(download_record);
+
+ /*
+ * Now download the data; a zero length record marks the end.
+ */
+
+ while (download_record->length != 0)
+ {
+ /*
+ * the action depends on type of record.
+ */
+
+ if (download_record->type == DOWNLOAD_RECORD_TYPE_DATA_32)
+ {
+ /*
+ * Set DIO address for downloading data to in SIF registers.
+ */
+
+ (*set_dio_address)(
+ adapter,
+ download_record->body.data_32.dio_addr);
+
+ /*
+ * Download data.
+ */
+
+ for (i = 0; i < download_record->body.data_32.word_count; i++)
+ {
+ sys_outsw(
+ handle,
+ sif_data_inc_register,
+ download_record->body.data_32.data[i]);
+ }
+
+ /*
+ * Check download worked by reading back and comparing.
+ */
+
+ (*set_dio_address)(
+ adapter,
+ download_record->body.data_32.dio_addr);
+
+ for (i = 0; i < download_record->body.data_32.word_count; i++)
+ {
+ if (sys_insw(handle, sif_data_inc_register) !=
+ download_record->body.data_32.data[i])
+ {
+ /*
+ * Fill in error record if read back not correct.
+ */
+
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_08_BAD_DOWNLOAD;
+ return FALSE;
+ }
+ }
+ }
+ else if (download_record->type == DOWNLOAD_RECORD_TYPE_FILL_32)
+ {
+ /*
+ * Set DIO address for downloading to in SIF registers.
+ */
+
+ (*set_dio_address)(
+ adapter,
+ download_record->body.fill_32.dio_addr);
+
+ /*
+ * Fill EAGLE memory with required pattern.
+ */
+
+ for (i = 0; i < download_record->body.fill_32.word_count; i++)
+ {
+ sys_outsw(
+ handle,
+ sif_data_inc_register,
+ download_record->body.fill_32.pattern);
+ }
+
+ /*
+ * Check download worked by reading back and comparing.
+ */
+
+ (*set_dio_address)(
+ adapter,
+ download_record->body.fill_32.dio_addr);
+
+ for (i = 0; i < download_record->body.fill_32.word_count; i++)
+ {
+ WORD x;
+
+ if ((x = sys_insw(handle, sif_data_inc_register)) !=
+ download_record->body.fill_32.pattern)
+ {
+ /*
+ * Fill in error record if read back not correct.
+ */
+
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_08_BAD_DOWNLOAD;
+ return FALSE;
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Can only have DATA and FILL records after first MODULE.
+ */
+
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_09_BAD_DOWNLOAD_IMAGE;
+ return FALSE;
+ }
+
+ /*
+ * Get the next download record.
+ */
+
+ macro_get_next_record(download_record);
+ }
+
+ /*
+ * Successful downloading complete.
+ */
+
+ return TRUE;
+}
+
+
+/****************************************************************************
+*
+* hwi_start_eagle
+* ===============
+*
+* The hwi_start_eagle routine takes the EAGLE out of the halt state it is
+* in.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_start_eagle)
+#endif
+
+export void
+hwi_start_eagle(
+ ADAPTER * adapter
+ )
+{
+ WORD sif_adapter_control_register = adapter->sif_acl;
+
+ /*
+ * Only change the halt status in the SIF register EAGLE_ACONTROL.
+ */
+
+ sys_outsw(
+ adapter->adapter_handle,
+ sif_adapter_control_register,
+ (WORD) (sys_insw(
+ adapter->adapter_handle,
+ sif_adapter_control_register) & ~EAGLE_SIFACL_CPHALT));
+
+}
+
+
+/****************************************************************************
+*
+* hwi_get_bring_up_code
+* =====================
+*
+* The hwi_get_bring_up_code routine waits for at least 15 seconds for a
+* valid bring up code to appear in the SIF interrupt register. If bring up
+* fails then this routine will retry up to 10 times. If even this fails,
+* then an error record is filled in.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_get_bring_up_code)
+#endif
+
+export WBOOLEAN
+hwi_get_bring_up_code(
+ ADAPTER * adapter
+ )
+{
+ ADAPTER_HANDLE handle = adapter->adapter_handle;
+ WORD sif_interrupt_register = adapter->sif_int;
+ UINT index;
+ BYTE bring_up_code;
+ BYTE bring_up_error;
+ UINT retry;
+
+ /*
+ * We'll retry 10 times and if we don't get any other error we'll
+ * return a timeout.
+ */
+
+ retry = 10;
+ bring_up_error = BRING_UP_E_10_TIME_OUT;
+
+ do
+ {
+ retry--;
+
+ for (index = 0; index < 60; index++)
+ {
+ /*
+ * No bring up code available yet. Wait at least a quarter of a
+ * second before trying again. Disable and re-enable accessing IO
+ * locations around wait so delay can reschedule this task and not
+ * effect others running.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io( adapter );
+#endif
+
+ sys_wait_at_least_milliseconds(250);
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io( adapter );
+#endif
+
+ /*
+ * Get bring up code from SIFSTS register.
+ */
+
+ bring_up_code = sys_insb(handle, sif_interrupt_register);
+
+ /*
+ * Check for successful bring up in top nibble of SIFSTS register.
+ * Success is shown by INITIALIZE bit being set.
+ */
+
+ if ((bring_up_code & EAGLE_BRING_UP_TOP_NIBBLE) ==
+ EAGLE_BRING_UP_SUCCESS)
+ {
+ return TRUE;
+ }
+
+ /*
+ * Check for failed bring up in top nibble of SIFSTS register.
+ * Failure is shown by the TEST and ERROR bits being set.
+ */
+
+ if ((bring_up_code & EAGLE_BRING_UP_TOP_NIBBLE) ==
+ EAGLE_BRING_UP_FAILURE)
+ {
+ /*
+ * Get actual bring up error code from bottom nibble of
+ * SIFSTS.
+ */
+
+ bring_up_error = bring_up_code & EAGLE_BRING_UP_BOTTOM_NIBBLE;
+ break;
+ }
+ }
+
+ /*
+ * We have failed to do a bring up, if retry hasn't reached
+ * zero yet then write 0xff00 to SIFINT to reset the Eagle
+ * and start bring up again.
+ */
+
+ if (retry > 0)
+ {
+ sys_outsw(handle, sif_interrupt_register, (WORD) 0xff00);
+ }
+ }
+ while (retry > 0);
+
+ /*
+ * We have completely failed bring up so return an error.
+ */
+
+ adapter->error_record.type = ERROR_TYPE_BRING_UP;
+ adapter->error_record.value = bring_up_error;
+
+ return FALSE;
+}
+
+
+/****************************************************************************
+*
+* hwi_get_max_frame_size
+* ======================
+*
+* The hwi_get_max_frame_size routine uses the ring speed register in DIO
+* space to find the ring speed and hence the maximum allowable frame size
+* set by the ISO standard.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_get_max_frame_size)
+#endif
+
+export WORD
+hwi_get_max_frame_size(
+ ADAPTER * adapter
+ )
+{
+ ADAPTER_HANDLE handle = adapter->adapter_handle;
+ WORD sif_dio_address_register = adapter->sif_adr;
+ WORD sif_dio_data_register = adapter->sif_dat;
+
+ /*
+ * Set DIO address register to point to ring speed register.
+ * Note that SIFADRX already equals 0x0001 (for DATA page at 0x10000).
+ */
+
+ sys_outsw(
+ handle,
+ sif_dio_address_register,
+ DIO_LOCATION_RING_SPEED_REG);
+
+ /*
+ * Use the contents of the ring speed register to determine ring speed.
+ */
+
+ if (sys_insw(handle, sif_dio_data_register) & RING_SPEED_REG_4_MBITS_MASK)
+ {
+ return MAX_FRAME_SIZE_4_MBITS;
+ }
+ else
+ {
+ return MAX_FRAME_SIZE_16_MBITS;
+ }
+
+}
+
+
+/****************************************************************************
+*
+* hwi_get_ring_speed
+* ==================
+*
+* The hwi_get_ring_speed routine uses the ring speed register in DIO
+* space to find the ring speed.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_get_ring_speed)
+#endif
+
+export UINT
+hwi_get_ring_speed(
+ ADAPTER * adapter
+ )
+{
+ WORD sif_dio_address_register = adapter->sif_adr;
+ WORD sif_dio_data_register = adapter->sif_dat;
+ ADAPTER_HANDLE hnd = adapter->adapter_handle;
+
+ /*
+ * Set DIO address register to point to ring speed register.
+ * Note that SIFADRX already equals 0x0001 (for DATA page at 0x10000).
+ */
+
+ sys_outsw(
+ hnd,
+ sif_dio_address_register,
+ DIO_LOCATION_RING_SPEED_REG);
+
+ /*
+ * Use the contents of the ring speed register to determine ring speed.
+ */
+
+ if (sys_insw(hnd, sif_dio_data_register) & RING_SPEED_REG_4_MBITS_MASK)
+ {
+ return 4;
+ }
+ else
+ {
+ return 16;
+ }
+
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| LOCAL PROCEDURES
+|
+---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+|
+| hwi_copy_to_dio_space
+| =====================
+|
+| The hwi_copy_to_dio_space routine copies the given amount of data into
+| DIO space at the specified location. The method of setting up the SIF
+| DIO address registers depends on the type of adapter card.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_copy_to_dio_space)
+#endif
+
+local void
+hwi_copy_to_dio_space(
+ ADAPTER * adapter,
+ DWORD dio_location,
+ BYTE * download_data,
+ WORD data_length_bytes
+ )
+{
+ ADAPTER_HANDLE handle = adapter->adapter_handle;
+
+ /*
+ * Set up DIO address in SIF DIO address registers.
+ * This needs to be done differently depending on adapter card type.
+ */
+
+ (*(adapter->set_dio_address))(adapter, dio_location);
+
+ /*
+ * Copy data into DIO space.
+ */
+ sys_rep_outsw(
+ handle,
+ adapter->sif_datinc,
+ download_data,
+ (WORD) (data_length_bytes / 2));
+
+ if (data_length_bytes & 1)
+ {
+ /*
+ * Byte out instructions do not work on the Ti PCI card,
+ * as it is not definate whether we ship this card, the fix
+ * shall stay here for now. PRR
+ */
+ if (adapter->adapter_card_type != ADAPTER_CARD_TYPE_16_4_PCIT)
+ {
+ sys_outsb(
+ handle,
+ adapter->sif_datinc,
+ *(download_data + data_length_bytes - 1));
+ }
+ #ifndef FTK_NO_PCIT
+ else
+ {
+ WORD last_byte;
+ last_byte = *(download_data + data_length_bytes - 1);
+ last_byte <<= 8;
+ last_byte &= 0xFF00;
+ sys_outsw(
+ handle,
+ adapter->sif_datinc,
+ last_byte);
+
+ }
+ #endif
+ }
+
+ return;
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| hwi_read_sifint
+| ===============
+|
+| Read the SIFINT register. This function is called via
+Ý sys_sych_with_interruptto avoid DMA/SIF problems on PciT adapters.
+---------------------------------------------------------------------------*/
+
+local WBOOLEAN
+hwi_read_sifint(
+ void * ptr
+ );
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_read_sifint)
+#endif
+
+local WBOOLEAN
+hwi_read_sifint(
+ void * ptr
+ )
+{
+ ADAPTER * adapter = (ADAPTER *) ptr;
+
+ return sys_insb(adapter->adapter_handle, adapter->sif_int);
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| hwi_get_init_code
+| =================
+|
+| The hwi_get_init_code routine waits for at least 11 seconds for a valid
+| initialization code to appear in the SIF interrupt register. If
+| initialization fails then this routine fills in the adapter error
+| record.
+|
+---------------------------------------------------------------------------*/
+
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_get_init_code)
+#endif
+
+local WBOOLEAN
+hwi_get_init_code(
+ ADAPTER * adapter
+ )
+{
+ UINT index;
+ BYTE init_code;
+
+ for (index = 0; index < 100; index++)
+ {
+ /*
+ * Get initialization code from SIFSTS register.
+ */
+
+ init_code = (BYTE) sys_sync_with_interrupt(
+ adapter->adapter_handle,
+ hwi_read_sifint,
+ (void *) adapter
+ );
+
+ /*
+ * Check for successful initialization in top nibble of SIFSTS.
+ * Success is shown by INITIALIZE, TEST and ERROR bits being zero.
+ */
+
+ if ((init_code & EAGLE_INIT_SUCCESS_MASK) == 0)
+ {
+ return TRUE;
+ }
+
+ /*
+ * Check for failed initialization in top nibble of SIFSTS.
+ * Failure is shown by the ERROR bit being set.
+ */
+
+ if ((init_code & EAGLE_INIT_FAILURE_MASK) != 0)
+ {
+ /*
+ * Get actual init error code from bottom nibble of SIFSTS
+ */
+
+ init_code = init_code & EAGLE_INIT_BOTTOM_NIBBLE;
+
+ /*
+ * Fill in error record with actual initialization error code.
+ */
+
+ adapter->error_record.type = ERROR_TYPE_INIT;
+ adapter->error_record.value = init_code;
+ return FALSE;
+ }
+
+ /*
+ * No initialization code available yet. Wait at least a quarter of
+ * a second before trying again. Disable and re-enable accessing IO
+ * locations around wait so OS can reschedule this task and not
+ * effect others running.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io( adapter );
+#endif
+
+ sys_wait_at_least_milliseconds(250);
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io( adapter );
+#endif
+
+ }
+
+ /*
+ * At least 11 seconds have gone so return time out failure.
+ */
+
+ adapter->error_record.type = ERROR_TYPE_INIT;
+ adapter->error_record.value = INIT_E_10_TIME_OUT;
+ return FALSE;
+
+}
+
+
+/******* End of HWI_GEN.C **************************************************/
diff --git a/private/ntos/ndis/madge/driver/hwi_mc.c b/private/ntos/ndis/madge/driver/hwi_mc.c
new file mode 100644
index 000000000..eb67eb5eb
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/hwi_mc.c
@@ -0,0 +1,1326 @@
+/****************************************************************************
+*
+* HWI_MC.C : Part of the FASTMAC TOOL-KIT (FTK)
+*
+* THE HARDWARE INTERFACE MODULE FOR MICROCHANNEL CARDS
+*
+* Copyright (c) Madge Networks Ltd. 1990-1994
+*
+* COMPANY CONFIDENTIAL
+*
+*****************************************************************************
+*
+* The purpose of the Hardware Interface (HWI) is to supply an adapter card
+* independent interface to any driver. It performs nearly all of the
+* functions that involve affecting SIF registers on the adapter cards.
+* This includes downloading code to, initializing, and removing adapters.
+*
+* The HWI_MC.C module contains the routines specific to 16/4 MC and 16/4
+* MC 32 cards which are necessary to install an adapter, to initialize an
+* adapter, to remove an adapter and to handle interrupts on an adapter.
+*
+****************************************************************************/
+
+/*---------------------------------------------------------------------------
+|
+| DEFINITIONS
+|
+---------------------------------------------------------------------------*/
+
+#include "ftk_defs.h"
+
+/*---------------------------------------------------------------------------
+|
+| MODULE ENTRY POINTS
+|
+---------------------------------------------------------------------------*/
+
+#include "ftk_intr.h" /* routines internal to FTK */
+#include "ftk_extr.h" /* routines provided or used by external FTK user */
+
+#ifndef FTK_NO_MC
+
+/*---------------------------------------------------------------------------
+|
+| LOCAL PROCEDURES
+|
+---------------------------------------------------------------------------*/
+
+local void
+hwi_mc_read_node_address(
+ ADAPTER * adapter
+ );
+
+local WBOOLEAN
+hwi_mc_valid_io_location(
+ WORD io_location
+ );
+
+#ifndef FTK_NO_PROBE
+
+local WORD
+hwi_mc_get_irq_channel(
+ WORD io_location
+ );
+
+local WORD
+hwi_mc_get_dma_channel(
+ WORD io_location
+ );
+
+#endif
+
+local WBOOLEAN
+hwi_mc_valid_irq_channel(
+ WORD irq_channel
+ );
+
+local WBOOLEAN
+hwi_mc_valid_dma_channel(
+ WORD dma_channel
+ );
+
+local WBOOLEAN
+hwi_mc_valid_transfer_mode(
+ UINT transfer_mode
+ );
+
+#ifndef FTK_NO_PROBE
+/****************************************************************************
+*
+* hwi_mc_probe_card
+* =================
+*
+*
+* PARAMETERS (passed by hwi_probe_adapter) :
+* ==========================================
+*
+* PROBE * resources
+*
+* resources is an array structures used to identify and record specific
+* information about adapters found.
+*
+* UINT length
+*
+* length is the number of structures pointed to by reources.
+*
+* WORD * valid_locations
+*
+* valid_locations is an array of IO locations to examine for the presence
+* of an adapter. For microchannel adapters with should be a subset of
+* {0x0a20, 0x1a20, 0x2a20, 0x3a20}.
+*
+* UINT number_locations
+*
+* This is the number of IO locations in the above list.
+*
+* BODY :
+* ======
+*
+* The hwi_mc_probe_card routine is called by hwi_probe_adapter. It
+* reads the id registers to find the type of card and also reads the IRQ.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine returns the number of adapters found, or PROBE_FAILURE if
+* there's a problem.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_mc_probe_card)
+#endif
+
+export UINT
+hwi_mc_probe_card(
+ PROBE * resources,
+ UINT length,
+ WORD * valid_locations,
+ UINT number_locations
+ )
+{
+ WORD pos_0;
+ WORD pos_1;
+ WORD pos_2;
+ WORD control_0;
+ WORD control_1;
+ WORD control_7;
+ WORD bia_prom;
+ WORD bia_prom_id;
+ WORD bia_prom_adap;
+ WORD bia_prom_rev;
+ WBOOLEAN card_found;
+ UINT i;
+ UINT j;
+
+ /*
+ * Check the bounds.
+ */
+
+ if(length <= 0 || number_locations <= 0)
+ {
+ return PROBE_FAILURE;
+ }
+
+ /*
+ * Check we've been passed a valid set of IO locations.
+ */
+
+ for(i = 0; i < number_locations; i++)
+ {
+ if(!hwi_mc_valid_io_location(valid_locations[i]))
+ {
+ return PROBE_FAILURE;
+ }
+ }
+
+ /*
+ * j is the number of adapters found, so zero it.
+ */
+
+ j = 0;
+
+ for(i = 0; i < number_locations; i++)
+ {
+ /*
+ * If we've run out of PROBE structures, return.
+ */
+
+ if(j >= length)
+ {
+ return j;
+ }
+
+ /*
+ * Set up the MC control registers.
+ */
+
+ pos_0 = valid_locations[i] + MC_POS_REGISTER_0;
+ pos_1 = valid_locations[i] + MC_POS_REGISTER_1;
+ pos_2 = valid_locations[i] + MC_POS_REGISTER_2;
+ control_0 = valid_locations[i] + MC_CONTROL_REGISTER_0;
+ control_1 = valid_locations[i] + MC_CONTROL_REGISTER_1;
+ control_7 = valid_locations[i] + MC_CONTROL_REGISTER_7;
+ bia_prom = valid_locations[i] + MC_BIA_PROM;
+ bia_prom_id = bia_prom + BIA_PROM_ID_BYTE;
+ bia_prom_adap = bia_prom + BIA_PROM_ADAPTER_BYTE;
+ bia_prom_rev = bia_prom + BIA_PROM_REVISION_BYTE;
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_probe_enable_io(valid_locations[i], MC_IO_RANGE);
+#endif
+ card_found = FALSE;
+
+ /*
+ * Reset the card.
+ */
+
+ sys_probe_outsb( control_1, 0);
+ sys_probe_outsb( control_0, 0);
+
+ if (sys_probe_insb(bia_prom_id) == 'M')
+ {
+ if (sys_probe_insb(bia_prom_adap) ==
+ BIA_PROM_TYPE_16_4_MC)
+ {
+ resources[j].adapter_card_type =
+ ADAPTER_CARD_TYPE_16_4_MC;
+
+ if(sys_probe_insb(bia_prom_rev) < 2)
+ {
+ resources[j].adapter_ram_size = 128;
+ }
+ else
+ {
+ resources[j].adapter_ram_size = 256;
+ }
+
+ card_found = TRUE;
+ }
+ else if (sys_probe_insb(bia_prom_adap) ==
+ BIA_PROM_TYPE_16_4_MC_32)
+ {
+ resources[j].adapter_card_type =
+ ADAPTER_CARD_TYPE_16_4_MC_32;
+
+ resources[j].adapter_ram_size = 256;
+
+ card_found = TRUE;
+ }
+ }
+
+ if(card_found)
+ {
+ resources[j].io_location = valid_locations[i];
+ resources[j].adapter_card_bus_type = ADAPTER_CARD_MC_BUS_TYPE;
+ resources[j].interrupt_number = hwi_mc_get_irq_channel(
+ valid_locations[i]);
+ resources[j].dma_channel = hwi_mc_get_dma_channel(
+ valid_locations[i]);
+ resources[j].transfer_mode = DMA_DATA_TRANSFER_MODE;
+
+ /*
+ * Increment j to point at the next PROBE structure.
+ */
+
+ j++;
+ }
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_probe_disable_io(resources->io_location, MC_IO_RANGE);
+#endif
+ }
+
+ return j;
+}
+#endif
+
+/****************************************************************************
+*
+* hwi_mc_install_card
+* ===================
+*
+*
+* PARAMETERS (passed by hwi_install_adapter) :
+* ============================================
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+* DOWNLOAD_IMAGE * download_image
+*
+* This is the code to be downloaded to the adapter. The image must be of
+* the correct type i.e. must be downloadable into the adapter. If the
+* pointer is 0 downloading is not done.
+*
+*
+* BODY :
+* ======
+*
+* The hwi_mc_install_card routine is called by hwi_install_adapter. It
+* sets up the adapter card and downloads the required code to it. Firstly,
+* it checks there is a valid adapter at the required IO address. If so it
+* reads the node address from the BIA PROM and sets up and checks numerous
+* on-board registers for correct operation.
+*
+* Then, it halts the EAGLE, downloads the code, restarts the EAGLE and
+* waits up to 3 seconds for a valid bring-up code. If interrupts are
+* required, these are enabled by operating system specific calls. There is
+* no need to explicitly enable DMA. Note PIO can not be used.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine returns TRUE if it succeeds. If this routine fails (returns
+* FALSE) then a subsequent call to driver_explain_error, with the adapter
+* handle corresponding to the adapter parameter used here, will give an
+* explanation.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_mc_install_card)
+#endif
+
+export WBOOLEAN
+hwi_mc_install_card(
+ ADAPTER * adapter,
+ DOWNLOAD_IMAGE * download_image
+ )
+{
+ ADAPTER_HANDLE handle = adapter->adapter_handle;
+ WORD pos_0 = adapter->io_location +
+ MC_POS_REGISTER_0;
+ WORD pos_1 = adapter->io_location +
+ MC_POS_REGISTER_1;
+ WORD pos_2 = adapter->io_location +
+ MC_POS_REGISTER_2;
+ WORD control_0 = adapter->io_location +
+ MC_CONTROL_REGISTER_0;
+ WORD control_1 = adapter->io_location +
+ MC_CONTROL_REGISTER_1;
+ WORD control_7 = adapter->io_location +
+ MC_CONTROL_REGISTER_7;
+ WORD bia_prom = adapter->io_location +
+ MC_BIA_PROM;
+ WORD bia_prom_id = bia_prom +
+ BIA_PROM_ID_BYTE;
+ WORD bia_prom_adap = bia_prom +
+ BIA_PROM_ADAPTER_BYTE;
+ WORD bia_prom_rev = bia_prom +
+ BIA_PROM_REVISION_BYTE;
+ BYTE streaming;
+ BYTE fairness;
+ BYTE arbitration;
+ WBOOLEAN card_found;
+ WORD sif_base;
+
+
+ /*
+ * Check the IO location is valid.
+ */
+
+ if(!hwi_mc_valid_io_location(adapter->io_location))
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_02_BAD_IO_LOCATION;
+
+ return FALSE;
+ }
+
+ /*
+ * Check the transfer mode is valid.
+ */
+
+ if(!hwi_mc_valid_transfer_mode(adapter->transfer_mode))
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_02_BAD_IO_LOCATION;
+
+ return FALSE;
+ }
+
+ /*
+ * Check the DMA channel is valid.
+ */
+
+ if(!hwi_mc_valid_dma_channel(adapter->dma_channel))
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_04_BAD_DMA_CHANNEL;
+
+ return FALSE;
+ }
+
+ /*
+ * Check the IRQ is valid.
+ */
+
+ if(!hwi_mc_valid_irq_channel(adapter->interrupt_number))
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_03_BAD_INTERRUPT_NUMBER;
+
+ return FALSE;
+ }
+
+ /*
+ * Save IO locations of SIF registers.
+ */
+
+ sif_base = adapter->io_location + MC_FIRST_SIF_REGISTER;
+
+ adapter->sif_dat = sif_base + EAGLE_SIFDAT;
+ adapter->sif_datinc = sif_base + EAGLE_SIFDAT_INC;
+ adapter->sif_adr = sif_base + EAGLE_SIFADR;
+ adapter->sif_int = sif_base + EAGLE_SIFINT;
+ adapter->sif_acl = sif_base + MC_EAGLE_SIFACL;
+ adapter->sif_adr2 = sif_base + MC_EAGLE_SIFADR_2;
+ adapter->sif_adx = sif_base + MC_EAGLE_SIFADX;
+ adapter->sif_dmalen = sif_base + MC_EAGLE_DMALEN;
+
+ adapter->io_range = MC_IO_RANGE;
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ /*
+ * Reset adapter (MC_CTRL1_NSRESET = 0).
+ */
+
+ sys_outsb(handle, control_1, 0);
+
+ /*
+ * Page in the first page of BIA PROM and set MC_CTRL0_PAGE = 0
+ * and MC_CTRL0_SIFSEL = 0.
+ */
+
+ sys_outsb(handle, control_0, 0);
+
+ /*
+ * Check we have a functioning adapter at the given IO location by
+ * checking the BIA PROM for an 'M' id byte and also by checking that
+ * the BIA adapter card byte is for a supported card type
+ * While we are doing this, we might as well record the card revision
+ * type, and use it to work out how much memory is on the card.
+ */
+
+ card_found = FALSE;
+
+ if (sys_insb( handle, bia_prom_id) == 'M')
+ {
+ if (sys_insb( handle, bia_prom_adap) ==
+ BIA_PROM_TYPE_16_4_MC)
+ {
+ adapter->adapter_card_type =
+ ADAPTER_CARD_TYPE_16_4_MC;
+
+ adapter->adapter_card_revision =
+ sys_insb(handle, bia_prom_rev);
+
+ if (adapter->adapter_card_revision < 2)
+ {
+ adapter->adapter_ram_size = 128;
+ }
+ else
+ {
+ adapter->adapter_ram_size = 256;
+ }
+
+ card_found = TRUE;
+ }
+ else if (sys_insb(handle, bia_prom_adap) ==
+ BIA_PROM_TYPE_16_4_MC_32)
+ {
+ adapter->adapter_card_type =
+ ADAPTER_CARD_TYPE_16_4_MC_32;
+
+ adapter->adapter_card_revision =
+ sys_insb(handle, bia_prom_rev);
+
+ adapter->adapter_ram_size = 256;
+
+ card_found = TRUE;
+ }
+ }
+
+ /*
+ * If no MC card found then fill in error record and return.
+ */
+
+ if (!card_found)
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_05_ADAPTER_NOT_FOUND;
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+
+ /*
+ * Check that the adapter card is enabled. If not then fill in error
+ * record and return.
+ */
+
+ if ((sys_insb(handle, pos_0) & MC_POS0_CDEN) == 0)
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_0D_CARD_NOT_ENABLED;
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+
+ /*
+ * Check that a speed has been selected for the card.
+ */
+
+ if ((sys_insb(handle, pos_1) & MC_POS1_NOSPD) != 0)
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_0E_NO_SPEED_SELECTED;
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return(FALSE);
+ }
+
+ /*
+ * Interrupts for MC cards are always level triggered.
+ */
+
+ adapter->edge_triggered_ints = FALSE;
+
+ /*
+ * Card speed has been set to 4Mb/s by machine reset. Set card to 16Mb/s
+ * if necessary.
+ */
+
+ if ((sys_insb(handle, pos_2) & MC_POS2_16N4) != 0)
+ {
+ macro_setb_bit(handle, control_1, MC_CTRL1_16N4);
+ }
+
+ /*
+ * Find the adapter card node address.
+ */
+
+ hwi_mc_read_node_address(adapter);
+
+ /*
+ * There are no other special control registers to set up for MC cards.
+ */
+
+ /*
+ * Wait at least 14 microseconds and bring adapter out of reset state.
+ * 14us is the minimum time must hold MC_CTRL1_NSRESET low.
+ * There are no CLKSEL issues as with ATULA cards for MC cards.
+ * Disable and re-enable accessing IO locations around the wait
+ * so the OS can reschedule this task and not effect others running.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+
+ sys_wait_at_least_microseconds(14);
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ macro_setb_bit(handle, control_1, MC_CTRL1_NSRESET);
+
+ /*
+ * Media type set to STP (type 6) by machine reset on 16 4 MC
+ * and set to UTP (type 3) by MC_CTRL1_NSRESET on 16 4 MC 32.
+ * Change media type if necessary now that MC_CTRL1_NSRESET != 0.
+ * POS media type bit is in different place for 16/4 MC and 16/4 MC 32.
+ */
+
+ if (adapter->adapter_card_type == ADAPTER_CARD_TYPE_16_4_MC)
+ {
+ if ((sys_insb(handle, pos_1) & MC_POS1_STYPE6) == 0)
+ {
+ macro_setb_bit(handle, control_7, MC_CTRL7_STYPE3);
+ }
+ }
+ else
+ {
+ if ((sys_insb(handle, pos_1) & MC32_POS1_STYPE6) != 0)
+ {
+ macro_clearb_bit(handle, control_7, MC_CTRL7_STYPE3);
+ }
+ }
+
+ /*
+ * Get extended SIF registers, halt EAGLE, then get normal SIF regs.
+ */
+
+ macro_setb_bit(handle, control_0, MC_CTRL0_SIFSEL);
+ macro_setb_bit(handle, control_1, MC_CTRL1_SRSX);
+
+ hwi_halt_eagle(adapter);
+
+ macro_clearb_bit(handle, control_1, MC_CTRL1_SRSX);
+
+ /*
+ * Download code to the adapter. View download image as a sequence of
+ * download records. Pass address of routine to set up DIO addresses
+ * on MC cards.
+ */
+
+ if (!hwi_download_code(
+ adapter,
+ (DOWNLOAD_RECORD *) download_image,
+ hwi_mc_set_dio_address))
+ {
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+
+ /*
+ * Get extended SIF registers, start EAGLE, then get normal SIF regs.
+ */
+
+ macro_setb_bit(handle, control_1, MC_CTRL1_SRSX);
+
+ hwi_start_eagle(adapter);
+
+ macro_clearb_bit(handle, control_1, MC_CTRL1_SRSX);
+
+ /*
+ * Wait for a valid bring up code, may wait 3 seconds.
+ */
+
+ if (!hwi_get_bring_up_code(adapter))
+ {
+ return FALSE;
+ }
+
+ /*
+ * Set DIO address to point to EAGLE DATA page 0x10000L.
+ */
+
+ hwi_mc_set_dio_address(
+ adapter,
+ DIO_LOCATION_EAGLE_DATA_PAGE);
+
+ /*
+ * Set maximum frame size from the ring speed.
+ */
+
+ adapter->max_frame_size = hwi_get_max_frame_size(adapter);
+
+ /*
+ * Set the ring speed.
+ */
+
+ adapter->ring_speed = hwi_get_ring_speed(adapter);
+
+ /* if not in polling mode then set up interrupts */
+ /* interrupts_on field is used when disabling interrupts for adapter */
+
+ if (adapter->interrupt_number != POLLING_INTERRUPTS_MODE)
+ {
+ adapter->interrupts_on =
+ sys_enable_irq_channel(handle, adapter->interrupt_number);
+
+ if (!adapter->interrupts_on)
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_0B_FAIL_IRQ_ENABLE;
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+ }
+ else
+ {
+ adapter->interrupts_on = TRUE;
+ }
+
+ /*
+ * Enable interrupts at adapter (do this even in polling mode).
+ * Hence when polling still 'using' interrupt channel
+ * so do not use card interrupt switch setting shared by other devices.
+ */
+
+ macro_setb_bit(handle, control_1, MC_CTRL1_SINTREN);
+
+ /*
+ * No need to explicitly set up DMA channel for MC card.
+ */
+
+ /*
+ * Set up 16/4 MC 32 configuation information.
+ * This information is later placed in the TI initialization block.
+ * It includes streaming, fairness and aribtration level details.
+ */
+
+ if (adapter->adapter_card_type == ADAPTER_CARD_TYPE_16_4_MC_32)
+ {
+ /*
+ * Get streaming info, adjust bit position for mc32_config byte.
+ */
+
+ streaming = sys_insb(handle, pos_2) & MC_POS2_STREAMING;
+ streaming = (BYTE)(streaming >> MC32_CONFIG_STREAMING_SHIFT);
+
+ /*
+ * Get fairness info, adjust bit position for mc32_config byte.
+ */
+
+ fairness = sys_insb(handle, pos_2) & MC_POS2_FAIRNESS;
+ fairness = (BYTE)(fairness >> MC32_CONFIG_FAIRNESS_SHIFT);
+
+ /*
+ * Get arbitration info, adjust bit position for mc32_config byte.
+ */
+
+ arbitration = sys_insb(handle, pos_0) & MC_POS0_DMAS;
+ arbitration = (BYTE)(arbitration >> MC32_CONFIG_DMA_SHIFT);
+
+ /*
+ * Record mc32_config byte.
+ */
+
+ adapter->mc32_config = streaming | fairness | arbitration;
+ }
+
+ /*
+ * Return successfully.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+
+ return(TRUE);
+
+}
+
+
+/****************************************************************************
+*
+* hwi_mc_interrupt_handler
+* ========================
+*
+*
+* PARAMETERS (passed by hwi_interrupt_entry) :
+* ============================================
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+*
+* BODY :
+* ======
+*
+* The hwi_mc_interrupt_handler routine is called, when an interrupt
+* occurs, by hwi_interrupt_entry. It checks to see if a particular card
+* has interrupted. The interrupt could be generated by the SIF only.
+* There are no PIO interupts on MC cards. Note it could in fact be the
+* case that no interrupt has occured on the particular adapter being
+* checked.
+*
+* On SIF interrupts, the interrupt is acknowledged and cleared. The value
+* in the SIF interrupt register is recorded in order to pass it to the
+* driver_interrupt_entry routine (along with the adapter details).
+*
+*
+* RETURNS :
+* =========
+*
+* The routine always successfully completes.
+*
+****************************************************************************/
+
+#ifdef FTK_IRQ_FUNCTION
+#pragma FTK_IRQ_FUNCTION(hwi_mc_interrupt_handler)
+#endif
+
+export void
+hwi_mc_interrupt_handler(
+ ADAPTER * adapter
+ )
+{
+ ADAPTER_HANDLE handle = adapter->adapter_handle;
+ WORD control_0 = adapter->io_location +
+ MC_CONTROL_REGISTER_0;
+ WORD control_1 = adapter->io_location +
+ MC_CONTROL_REGISTER_1;
+ WORD sifint_value;
+ WORD sifint_tmp;
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io( adapter);
+#endif
+
+ /*
+ * Check for SIF interrupt (do not get PIO interrupts on MC cards).
+ */
+
+ if ((sys_insb( handle, control_0) & MC_CTRL0_SINTR) != 0)
+ {
+ /*
+ * SIF interrupt has occurred. This could be an SRB free, an adapter
+ * check or a received frame interrupt.
+ */
+
+ /*
+ * Toggle SIF interrupt enable to acknowledge interrupt at MC card.
+ */
+
+ macro_clearb_bit(handle, control_1, MC_CTRL1_SINTREN);
+ macro_setb_bit(handle, control_1, MC_CTRL1_SINTREN);
+
+ /*
+ * Clear EAGLE_SIFINT_HOST_IRQ to acknowledge interrupt at SIF.
+ */
+
+ /*
+ * WARNING: Do NOT reorder the clearing of the SIFINT register with
+ * the reading of it. If SIFINT is cleared after reading it, any
+ * interrupts raised after reading it will be lost. Admittedly
+ * this is a small time frame, but it is important.
+ */
+
+ sys_outsw(handle, adapter->sif_int, 0);
+
+ /*
+ * Record the EAGLE SIF interrupt register value.
+ */
+
+ /*
+ * WARNING: Continue to read the SIFINT register until it is stable
+ * because of a potential problem involving the host reading the
+ * register after the adapter has written the low byte of it, but
+ * before it has written the high byte. Failure to wait for the
+ * SIFINT register to settle can cause spurious interrupts.
+ */
+
+ sifint_value = sys_insw(handle, adapter->sif_int);
+ do
+ {
+ sifint_tmp = sifint_value;
+ sifint_value = sys_insw(
+ handle,
+ adapter->sif_int );
+ } while (sifint_tmp != sifint_value);
+
+ /*
+ * Acknowledge/clear interrupt at interrupt controller.
+ */
+
+#ifndef FTK_NO_CLEAR_IRQ
+ sys_clear_controller_interrupt(handle, adapter->interrupt_number);
+#endif
+
+ /*
+ * No need regenerate any interrupts because using level sensitive.
+ */
+
+ /*
+ * Call driver with details of SIF interrupt.
+ */
+
+ driver_interrupt_entry(handle, adapter, sifint_value);
+
+ }
+
+ /*
+ * Let system know we have finished accessing the IO ports.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io( adapter);
+#endif
+
+ return;
+}
+
+
+/****************************************************************************
+*
+* hwi_mc_remove_card
+* ==================
+*
+*
+* PARAMETERS (passed by hwi_remove_adapter) :
+* ===========================================
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+*
+* BODY :
+* ======
+*
+* The hwi_mc_remove_card routine is called by hwi_remove_adapter. It
+* disables interrupts if they are being used. It also resets the adapter.
+* Note there is no need to explicitly disable DMA channels.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine always successfully completes.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(hwi_mc_remove_card)
+#endif
+
+export void
+hwi_mc_remove_card(
+ ADAPTER * adapter
+ )
+{
+ ADAPTER_HANDLE handle = adapter->adapter_handle;
+ WORD control_1 = adapter->io_location + MC_CONTROL_REGISTER_1;
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ /*
+ * Disable interrupts. Only need to do this if interrupts successfully
+ * enabled. Interrupt must be disabled at adapter before unpatching
+ * interrupt. Even in polling mode we must turn off interrupts at
+ * adapter.
+ */
+
+ if (adapter->interrupts_on)
+ {
+
+ macro_clearb_bit(handle, control_1, MC_CTRL1_SINTREN);
+
+ if (adapter->interrupt_number != POLLING_INTERRUPTS_MODE)
+ {
+ sys_disable_irq_channel(handle, adapter->interrupt_number);
+ }
+
+ adapter->interrupts_on = FALSE;
+
+ }
+
+ /*
+ * Perform adapter reset, set MC_CTRL1_NSRESET low.
+ */
+
+ sys_outsb(handle, control_1, 0);
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+
+}
+
+
+/****************************************************************************
+*
+* hwi_mc_set_dio_address
+* ======================
+*
+* The hwi_mc_set_dio_address routine is used, with MC cards, for putting a
+* 32 bit DIO address into the SIF DIO address and extended DIO address
+* registers. Note that the extended address register should be loaded
+* first.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_mc_set_dio_address)
+#endif
+
+export void
+hwi_mc_set_dio_address(
+ ADAPTER * adapter,
+ DWORD dio_address
+ )
+{
+ ADAPTER_HANDLE handle = adapter->adapter_handle;
+ WORD control_1 = adapter->io_location +
+ MC_CONTROL_REGISTER_1;
+ WORD sif_dio_adr = adapter->sif_adr;
+ WORD sif_dio_adrx = adapter->sif_adx;
+
+ /*
+ * Page in extended SIF registers.
+ */
+
+ macro_setb_bit(handle, control_1, MC_CTRL1_SRSX);
+
+ /*
+ * Load extended DIO address register with top 16 bits of address.
+ * Always load extended address register first.
+ */
+
+ sys_outsw(handle, sif_dio_adrx, (WORD)(dio_address >> 16));
+
+ /*
+ * Return to having normal SIF registers paged in.
+ */
+
+ macro_clearb_bit(handle, control_1, MC_CTRL1_SRSX);
+
+ /*
+ * Load DIO address register with low 16 bits of address.
+ */
+
+ sys_outsw(handle, sif_dio_adr, (WORD)(dio_address & 0x0000FFFF));
+
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| LOCAL PROCEDURES
+|
+---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+|
+| hwi_mc_read_node_address
+| ========================
+|
+| The hwi_mc_read_node_address routine reads in the node address that is
+| stored in the second page of the BIA PROM on MC cards.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_mc_read_node_address)
+#endif
+
+local void
+hwi_mc_read_node_address(
+ ADAPTER * adapter
+ )
+{
+ ADAPTER_HANDLE handle = adapter->adapter_handle;
+ WORD control_0 = adapter->io_location +
+ MC_CONTROL_REGISTER_0;
+ WORD bia_prom = adapter->io_location +
+ MC_BIA_PROM;
+ WORD bia_prom_address = bia_prom + BIA_PROM_NODE_ADDRESS;
+ WORD index;
+
+ /*
+ * Page in second page of BIA PROM containing node address.
+ */
+
+ macro_setb_bit(handle, control_0, MC_CTRL0_PAGE);
+
+ /*
+ * Read node address from BIA PROM.
+ */
+
+ for (index = 0; index < 6; index++)
+ {
+ adapter->permanent_address.byte[index] =
+ sys_insb(handle, (WORD) (bia_prom_address + index));
+ }
+
+ /*
+ * Restore first page of BIA PROM.
+ */
+
+ macro_clearb_bit(handle, control_0, MC_CTRL0_PAGE);
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| hwi_mc_valid_io_location
+| ========================
+|
+| The hwi_mc_valid_io_location routine checks to see if the user has
+| supplied a valid IO location for an MC adapter card.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_mc_valid_io_location)
+#endif
+
+local WBOOLEAN
+hwi_mc_valid_io_location(
+ WORD io_location
+ )
+{
+ WBOOLEAN io_valid;
+
+ switch (io_location)
+ {
+ case 0x0A20 :
+ case 0x1A20 :
+ case 0x2A20 :
+ case 0x3A20 :
+ case 0x0E20 :
+ case 0x1E20 :
+ case 0x2E20 :
+ case 0x3E20 :
+ /*
+ * These are the valid user supplied io locations.
+ */
+
+ io_valid = TRUE;
+ break;
+
+ default :
+ /*
+ * Anything else is invalid.
+ */
+
+ io_valid = FALSE;
+ break;
+ }
+
+ return(io_valid);
+}
+
+#ifndef FTK_NO_PROBE
+/*---------------------------------------------------------------------------
+|
+| hwi_mc_get_irq_channel
+| ======================
+|
+| The hwi_mc_get_irq_channel routine determines the interrupt number that
+| an MC card is using. It does this by looking at one of the POS
+| registers. It always succeeds in finding the interrupt number being
+| used.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_mc_get_irq_channel)
+#endif
+
+local WORD
+hwi_mc_get_irq_channel(
+ WORD io_location
+ )
+{
+ WORD pos_0 = io_location + MC_POS_REGISTER_0;
+ WORD irq = 0;
+ WORD irq_coded;
+
+ /*
+ * The interrupt number is encoded in two bits (7,6) in POS register 0.
+ */
+
+ irq_coded = sys_probe_insb(pos_0) & MC_POS0_IRQSEL;
+
+ /*
+ * There are only 3 possible interrupt numbers that can be configured.
+ * One of these 3 cases will always be true.
+ */
+
+ switch (irq_coded)
+ {
+ case MC_POS0_IRSEL_IRQ3 :
+ irq = 3;
+ break;
+
+ case MC_POS0_IRSEL_IRQ9 :
+ irq = 9;
+ break;
+
+ case MC_POS0_IRSEL_IRQ10 :
+ irq = 10;
+ break;
+
+ default :
+ break;
+
+ }
+
+ /*
+ * Return the discovered interrupt number.
+ */
+
+ return(irq);
+}
+#endif
+
+#ifndef FTK_NO_PROBE
+/*---------------------------------------------------------------------------
+|
+| hwi_mc_get_dma_channel
+| ======================
+|
+| The hwi_mc_get_dma_channel routine determines the DMA channel
+| (arbitration level) that an MC card is using. It does this by looking at
+| one of the POS registers. It always succeeds in finding the DMA channel
+| being used.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_mc_get_dma_channel)
+#endif
+
+local WORD
+hwi_mc_get_dma_channel(
+ WORD io_location
+ )
+{
+ WORD pos_0 = io_location + MC_POS_REGISTER_0;
+ WORD dma_coded;
+ WORD dma;
+
+ /*
+ * The DMA channel is encoded in 4 bits (4,3,2,1) in POS register 0.
+ */
+
+ dma_coded = sys_probe_insb(pos_0) & MC_POS0_DMAS;
+
+ /*
+ * In order to get the actual DMA channel, shift right by one bit.
+ */
+
+ dma = dma_coded >> 1;
+
+ /*
+ * Return the discovered DMA channel.
+ */
+
+ return(dma);
+}
+#endif
+
+/*---------------------------------------------------------------------------
+|
+| hwi_mc_valid_irq_channel
+| ========================
+|
+| The hwi_mc_valid_irq_channel routine checks to see if the user has
+| supplied a sensible IRQ for an MC adapter card.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_mc_valid_irq_channel)
+#endif
+
+export WBOOLEAN
+hwi_mc_valid_irq_channel(
+ WORD irq_channel
+ )
+{
+ return (irq_channel == POLLING_INTERRUPTS_MODE ||
+ irq_channel == 3 ||
+ irq_channel == 9 ||
+ irq_channel == 10);
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| hwi_mc_valid_dma_channel
+| ========================
+|
+| The hwi_mc_valid_dma_channel routine checks to see if the user has
+| supplied a sensible dma channel for an MC adapter card.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_mc_valid_dma_channel)
+#endif
+
+export WBOOLEAN
+hwi_mc_valid_dma_channel(
+ WORD dma_channel
+ )
+{
+ return (dma_channel <= 14);
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| hwi_mc_valid_transfer_mode
+| ============================
+|
+| The hwi_mc_valid_transfer_mode routine checks to see if the user has
+| supplied a sensible transfer mode for an MC adapter card. That means DMA
+| at the moment.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_mc_valid_transfer_mode)
+#endif
+
+export WBOOLEAN
+hwi_mc_valid_transfer_mode(
+ UINT transfer_mode
+ )
+{
+ return (transfer_mode == DMA_DATA_TRANSFER_MODE);
+}
+
+
+#endif
+
+/******** End of HWI_MC.C **************************************************/
diff --git a/private/ntos/ndis/madge/driver/hwi_pci.c b/private/ntos/ndis/madge/driver/hwi_pci.c
new file mode 100644
index 000000000..7eb19fec0
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/hwi_pci.c
@@ -0,0 +1,1567 @@
+/****************************************************************************
+*
+* HWI_PCI.C : Part of the FASTMAC TOOL-KIT (FTK)
+*
+* HARDWARE INTERFACE MODULE FOR PCI CARDS
+*
+* Copyright (c) Madge Networks Ltd. 1994
+*
+* COMPANY CONFIDENTIAL
+*
+*
+*****************************************************************************
+*
+* The purpose of the Hardware Interface (HWI) is to supply an adapter card
+* independent interface to any driver. It performs nearly all of the
+* functions that involve affecting SIF registers on the adapter cards.
+* This includes downloading code to, initializing, and removing adapters.
+*
+* The HWI_PCI.C module contains the routines specific to the Smart 16/4 PCI
+* card which supports MMIO and pseudo DMA.
+*
+*****************************************************************************
+
+/*---------------------------------------------------------------------------
+|
+| DEFINITIONS
+|
+---------------------------------------------------------------------------*/
+
+#define PCI_PCI1_DEVICE_ID 1
+
+#define INT_PCIMMIO_RX 0x40
+#define INT_PCIMMIO_TX 0x20
+#define INT_PCIMMIO (INT_PCIMMIO_RX | INT_PCIMMIO_TX)
+
+#include "ftk_defs.h"
+
+/*---------------------------------------------------------------------------
+|
+| MODULE ENTRY POINTS
+|
+---------------------------------------------------------------------------*/
+
+#include "ftk_intr.h" /* routines internal to FTK */
+#include "ftk_extr.h" /* routines provided or used by external FTK user */
+
+#ifndef FTK_NO_PCI
+
+/*---------------------------------------------------------------------------
+|
+| LOCAL PROCEDURES
+|
+---------------------------------------------------------------------------*/
+
+local void
+pci_c46_write_bit(
+ ADAPTER * adapter,
+ WORD mask,
+ WBOOLEAN set_bit
+ );
+
+local void
+pci_c46_twitch_clock(
+ ADAPTER * adapter
+ );
+
+local WORD
+pci_c46_read_data(
+ ADAPTER * adapter
+ );
+
+local WBOOLEAN
+hwi_pci_read_node_address(
+ ADAPTER * adapter
+ );
+
+local WORD
+hwi_pci_read_eeprom_word(
+ ADAPTER * adapter,
+ WORD word_address
+ );
+
+#ifndef FTK_NO_PROBE
+/****************************************************************************
+*
+* hwi_pci_probe_card
+* ==================
+*
+*
+* PARAMETERS (passed by hwi_probe_adapter) :
+* ==========================================
+*
+* PROBE * resources
+*
+* resources is an array structures used to identify and record specific
+* information about adapters found.
+*
+* UINT length
+*
+* length is the number of structures pointed to by reources.
+*
+* WORD * valid_locations
+*
+* valid_locations is normally an array of IO locations to examine for the
+* presence of an adapter. However for PCI adapters the io location is read
+* from the BIOS, so this array can remain empty.
+*
+* UINT number_locations
+*
+* This is the number of IO locations in the above list.
+*
+* BODY :
+* ======
+*
+* The hwi_pci_probe_card routine is called by hwi_probe_adapter. It
+* reads the id registers to find the type of card and also reads the IRQ.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine returns the number of adapters found, or PROBE_FAILURE if
+* there's a problem.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_pci_probe_card)
+#endif
+
+export UINT
+hwi_pci_probe_card(
+ PROBE * Resources,
+ UINT NumberOfResources,
+ WORD * IOMask,
+ UINT NumberIO
+ )
+{
+ WORD i;
+ WORD Handle;
+ DWORD MMIOAddress;
+
+ if (!sys_pci_valid_machine())
+ {
+ return 0;
+ }
+
+ for (i=0;i<NumberOfResources;i++)
+ {
+ if (!sys_pci_find_card(&Handle, i,PCI_PCI1_DEVICE_ID))
+ {
+ break;
+ }
+
+ Resources[i].adapter_card_bus_type = ADAPTER_CARD_PCI_BUS_TYPE;
+
+ if (!sys_pci_get_io_base(Handle, &(Resources[i].io_location)))
+ {
+ return PROBE_FAILURE;
+ }
+
+ if (!sys_pci_get_irq(Handle, &(Resources[i].interrupt_number)))
+ {
+ return PROBE_FAILURE;
+ }
+
+ if (!sys_pci_get_mem(Handle, &MMIOAddress))
+ {
+ /*
+ * The user wants MMIO and we weren't given any Memory
+ */
+
+ return PROBE_FAILURE;
+ }
+
+ /*
+ * Convert the address to virtual addressing.
+ */
+
+ Resources[i].mmio_base_address = sys_phys_to_virt(0, MMIOAddress);
+
+ /*
+ * We can't read the memory size from the serial EEPROM until the
+ * hwi_pci_install_card function is called.
+ */
+
+ Resources[i].adapter_ram_size = 512;
+
+ Resources[i].adapter_card_type = ADAPTER_CARD_TYPE_16_4_PCI;
+
+ Resources[i].transfer_mode = PIO_DATA_TRANSFER_MODE;
+
+ }
+
+ return i;
+}
+#endif
+
+/****************************************************************************
+*
+* hwi_pci_install_card
+* ====================
+*
+*
+* PARAMETERS (passed by hwi_install_adapter) :
+* ============================================
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+* DOWNLOAD_IMAGE * download_image
+*
+* This is the code to be downloaded to the adapter. The image must be of
+* the correct type i.e. must be downloadable into the adapter. If the
+* pointer is 0 downloading is not done.
+*
+*
+* BODY :
+* ======
+*
+* hwi_pci_install_card is called by hwi_install_adapter. It sets up
+* the adapter card and downloads the required code to it. Firstly, it
+* checks there is a valid adapter at the required IO address by reading
+* the node address from the BIA PROM. It then sets up and checks various
+* on-board registers for correct operation.
+*
+* Then, it halts the EAGLE, downloads the code, restarts the EAGLE and
+* waits up to 3 seconds for a valid bring-up code. If interrupts are
+* required, these are enabled by operating system specific calls.
+* The adapter is set up for Eagle Pseudo-DMA, since real DMA is not used.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine returns TRUE if it succeeds. If this routine fails (returns
+* FALSE) then a subsequent call to driver_explain_error, with the adapter
+* handle corresponding to the adapter parameter used here, will give an
+* explanation.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_pci_install_card)
+#endif
+
+export WBOOLEAN
+hwi_pci_install_card(
+ ADAPTER * adapter,
+ DOWNLOAD_IMAGE * download_image
+ )
+{
+ ADAPTER_HANDLE adapter_handle = adapter->adapter_handle;
+ WORD control_reg;
+ WORD control_value;
+ WORD sif_base;
+ WORD ring_speed;
+
+ /*
+ * These things can all be assumed for the PCI Card.
+ */
+
+ adapter->adapter_card_type = ADAPTER_CARD_TYPE_16_4_PCI;
+ adapter->adapter_card_revision = ADAPTER_CARD_16_4_PCI;
+ adapter->edge_triggered_ints = FALSE;
+ adapter->mc32_config = 0;
+
+ /*
+ * Start off by assuming we will use pseudo DMA.
+ */
+
+ adapter->EaglePsDMA = TRUE;
+
+ /*
+ * If we are supposed to use MMIO then enable it.
+ */
+
+ if (adapter->transfer_mode == MMIO_DATA_TRANSFER_MODE)
+ {
+ adapter->mc32_config = PCI1_ENABLE_MMIO;
+ adapter->EaglePsDMA = FALSE;
+ }
+ else
+ {
+ /*
+ * If we've using pseudo DMA then we need a software handshake.
+ */
+ adapter->mc32_config = MC_AND_ISACP_USE_PIO;
+ }
+
+ /*
+ * Save IO locations of SIF registers.
+ */
+
+ sif_base = adapter->io_location + PCI_FIRST_SIF_REGISTER;
+
+ adapter->sif_dat = sif_base + PCI_SIFDAT;
+ adapter->sif_datinc = sif_base + PCI_SIFDAT_INC;
+ adapter->sif_adr = sif_base + PCI_SIFADR;
+ adapter->sif_int = sif_base + PCI_SIFINT;
+ adapter->sif_acl = sif_base + PCI_SIFACL;
+ adapter->sif_adx = sif_base + PCI_SIFADX;
+ adapter->sif_dmalen = sif_base + PCI_DMALEN;
+ adapter->sif_sdmadat = sif_base + PCI_SDMADAT;
+ adapter->sif_sdmaadr = sif_base + PCI_SDMAADR;
+ adapter->sif_sdmaadx = sif_base + PCI_SDMAADX;
+
+ adapter->io_range = PCI_IO_RANGE;
+
+ /*
+ * Set up a pointer to the general control register.
+ */
+
+ control_reg = adapter->io_location + PCI_GENERAL_CONTROL_REG;
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ /*
+ * Toggle the Reset bit to Reset the Eagle and take it out of reset
+ */
+
+ control_value = 0;
+ sys_outsw(
+ adapter_handle,
+ control_reg,
+ control_value);
+
+ sys_wait_at_least_microseconds(28);
+
+ control_value = PCI1_SRESET;
+ sys_outsw(
+ adapter_handle,
+ control_reg,
+ control_value);
+
+ /*
+ * Read the node address.
+ */
+
+ if (!hwi_pci_read_node_address(adapter))
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_05_ADAPTER_NOT_FOUND;
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+
+ ring_speed = hwi_pci_read_eeprom_word(adapter, PCI_EEPROM_RING_SPEED);
+
+ /*
+ * Get the amount of RAM from the serial EEPROM (in units of 128k).
+ */
+
+ adapter->adapter_ram_size = hwi_pci_read_eeprom_word(
+ adapter,
+ PCI_EEPROM_RAM_SIZE) * 128;
+
+ /*
+ * Set the ring speed. If the user has specified a value then we will
+ * use that, otherwise we will use the value read from the EEPROM.
+ */
+
+ if (adapter->set_ring_speed == 16)
+ {
+ control_value &= ~PCI1_RSPEED_4MBPS;
+ }
+ else if (adapter->set_ring_speed == 4)
+ {
+ control_value |= PCI1_RSPEED_4MBPS;
+ }
+ else if (ring_speed == PCI_EEPROM_16MBPS)
+ {
+ control_value &= ~PCI1_RSPEED_4MBPS;
+ }
+ else
+ {
+ control_value |= PCI1_RSPEED_4MBPS;
+ }
+
+ control_value |= PCI1_RSPEED_VALID;
+ sys_outsw(
+ adapter_handle,
+ control_reg,
+ control_value);
+
+ /*
+ * Halt the Eagle prior to downloading the MAC code - this will also
+ * write the interrupt bits into the SIFACL register, where the MAC can
+ * find them.
+ */
+
+ hwi_halt_eagle(adapter);
+
+ /*
+ * Download code to adapter.
+ * View download image as a sequence of download records.
+ * Pass address of routine to set up DIO addresses on PCI cards.
+ * If routine fails return failure (error record already filled in).
+ */
+
+ if (!hwi_download_code(
+ adapter,
+ (DOWNLOAD_RECORD *) download_image,
+ hwi_pci_set_dio_address))
+ {
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+
+ /*
+ * Restart the Eagle to initiate bring up diagnostics.
+ */
+
+ hwi_start_eagle(adapter);
+
+ /*
+ * Wait for a valid bring up code, may wait 3 seconds.
+ */
+
+ if (!hwi_get_bring_up_code(adapter))
+ {
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+
+ /*
+ * Set DIO address to point to EAGLE DATA page 0x10000L.
+ */
+
+ hwi_pci_set_dio_address(adapter, DIO_LOCATION_EAGLE_DATA_PAGE);
+
+ /*
+ * Get the ring speed, from the Eagle DIO space.
+ */
+
+ adapter->ring_speed = hwi_get_ring_speed(adapter);
+
+ /*
+ * Set maximum frame size from the ring speed.
+ */
+
+ adapter->max_frame_size = hwi_get_max_frame_size(adapter);
+
+ /*
+ * If not in polling mode then set up interrupts.
+ * interrupts_on field is used when disabling interrupts for adapter.
+ */
+
+ if (adapter->interrupt_number != POLLING_INTERRUPTS_MODE)
+ {
+ adapter->interrupts_on = sys_enable_irq_channel(
+ adapter_handle,
+ adapter->interrupt_number);
+
+ if (!adapter->interrupts_on)
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_0B_FAIL_IRQ_ENABLE;
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+ }
+ else
+ {
+ adapter->interrupts_on = TRUE;
+ }
+
+ /*
+ * Return successfully.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return TRUE;
+}
+
+/****************************************************************************
+*
+* hwi_pci_interrupt_handler
+* =========================
+*
+*
+* PARAMETERS (passed by hwi_interrupt_entry) :
+* ==========================================
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+*
+* BODY :
+* ======
+*
+* The hwi_pci_interrupt_handler routine is called, when an interrupt
+* occurs, by hwi_interrupt_entry. It checks to see if a particular card
+* has interrupted. The interrupt could be generated by the SIF for either
+* a PIO data transfer or a normal condition (received frame, SRB complete,
+* ARB indication etc). Note it could in fact be the case that no interrupt
+* has occured on the particular adapter being checked.
+*
+* On normal SIF interrupts, the interrupt is acknowledged and cleared. The
+* value in the SIF interrupt register is recorded in order to pass it to
+* the driver_interrupt_entry routine (along with the adapter details).
+*
+* On PseudoDMA interrupts, the length, direction and physical address of
+* the transfer is determined. A system provided routine is called to do
+* the data transfer itself.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine always successfully completes.
+*
+****************************************************************************/
+
+#ifdef FTK_IRQ_FUNCTION
+#pragma FTK_IRQ_FUNCTION(hwi_pci_interrupt_handler)
+#endif
+
+export void
+hwi_pci_interrupt_handler(
+ ADAPTER * adapter
+ )
+{
+ ADAPTER_HANDLE adapter_handle = adapter->adapter_handle;
+ WORD sifacl;
+ WORD sifint_value;
+ WORD sifint_tmp;
+ WBOOLEAN sifint_occurred = FALSE;
+ WBOOLEAN pioint_occurred = FALSE;
+ WORD pio_addr_lo;
+ DWORD pio_addr_hi;
+ WORD pio_len_bytes;
+ WBOOLEAN pio_from_adapter;
+ UINT i;
+ BYTE FAR * pio_address;
+ WORD saved_sifadr;
+ WORD mmio_alignment;
+ BYTE FAR * mmio_addr;
+ DWORD mmio_dword;
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ /*
+ * Check for SIF interrupt or PIO interrupt.
+ */
+
+ /*
+ * Read SIFINT, and then re-read to make sure value is stable.
+ */
+
+ sifint_value = sys_insw(adapter_handle, adapter->sif_int);
+ do
+ {
+ sifint_tmp = sifint_value;
+ sifint_value = sys_insw(adapter_handle, adapter->sif_int);
+ } while (sifint_tmp != sifint_value);
+
+ /*
+ * Given the SIFINT value, we can check one of the bits in it to see
+ * if that is what caused the interrupt.
+ */
+
+ if ((sifint_value & EAGLE_SIFINT_SYSTEM) != 0)
+ {
+ /*
+ * A SIF interrupt has occurred.
+ * This could be an SRB free, an adapter check or a received frame
+ * interrupt.
+ * Note that we do not process it yet - we wait until we have EOI'd
+ * the interrupt controller.
+ */
+
+ sifint_occurred = TRUE;
+
+ /*
+ * Clear EAGLE_SIFINT_HOST_IRQ to acknowledge interrupt at SIF.
+ */
+
+ sys_outsw(adapter_handle, adapter->sif_int, 0);
+ }
+
+ if (adapter->EaglePsDMA == TRUE)
+ {
+ /*
+ * Now read the SIFACL register to check for a PseudoDMA interrupt.
+ */
+
+ sifacl = sys_insw(adapter_handle, adapter->sif_acl);
+
+ if ((sifacl & EAGLE_SIFACL_SWHRQ) != 0)
+ {
+ /*
+ * PIO interrupt has occurred. Transfer data to/from adapter.
+ */
+
+ pioint_occurred = TRUE;
+
+ /*
+ * Using any PCI card, a software handshake must occur so that the MAC
+ * does not try to initiate another transfer until a point has been reached on
+ * the host at which the transfer has completed. If not, the following could
+ * happen:
+ *
+ * - The host requests the last word/byte of a receive from the card.
+ * - The SIF does not has the data ready.
+ * - Control of the bus is given to a SCSI card.
+ * - It bursts/does nothing in bus master mode for 16 microseconds.
+ * - The data becomes ready early on during these 16 microseconds and
+ * as a result the card software beleives that the transfer has completed.
+ * - The card software continues and sets up another PsDMA transfer.
+ * - The SCSI card finishes, but the PdDMA length is now incorrect and
+ * all is lost.
+ *
+ */
+
+ saved_sifadr = sys_insw(adapter_handle, adapter->sif_adr);
+
+ /*
+ * Set the PIO_HANDSHAKE word to 0
+ */
+ sys_outsw(adapter_handle, adapter->sif_adr, DIO_LOCATION_DMA_CONTROL);
+
+ sys_outsw(adapter_handle, adapter->sif_dat, 0 );
+
+
+ /*
+ * By writing the SWHLDA bit, we "start" the transfer,
+ * causing the SDMA registers to mapped in.
+ */
+
+ macro_setw_bit(
+ adapter_handle,
+ adapter->sif_acl,
+ EAGLE_SIFACL_SWHLDA);
+
+ /*
+ * Determine what direction the data transfer is to take place in.
+ */
+
+ pio_from_adapter = sys_insw(
+ adapter_handle,
+ adapter->sif_acl) & EAGLE_SIFACL_SWDDIR;
+
+ pio_len_bytes = sys_insw(
+ adapter_handle,
+ adapter->sif_dmalen);
+
+ pio_addr_lo = sys_insw(
+ adapter_handle,
+ adapter->sif_sdmaadr);
+
+ pio_addr_hi = (DWORD) sys_insw(
+ adapter_handle,
+ adapter->sif_sdmaadx);
+
+ pio_address = (BYTE FAR *) ((pio_addr_hi << 16) |
+ ((DWORD) pio_addr_lo));
+
+
+ /*
+ * Do the actual data transfer.
+ */
+
+ /*
+ * Note that Fastmac only copies whole WORDs to DWORD boundaries.
+ * FastmacPlus, however, can transfer any length to any address.
+ */
+
+ if (pio_from_adapter)
+ {
+ /*
+ * Transfer into host memory from adapter.
+ */
+
+ /*
+ * First, check if host address is on an odd byte boundary.
+ */
+
+ if ((card_t)pio_address % 2)
+ {
+ pio_len_bytes--;
+ *(pio_address++) = sys_insb(
+ adapter_handle,
+ (WORD) (adapter->sif_sdmadat + 1));
+ }
+
+ /*
+ * Now transfer the bulk of the data.
+ */
+
+ sys_rep_insw(
+ adapter_handle,
+ adapter->sif_sdmadat,
+ pio_address,
+ (WORD) (pio_len_bytes >> 1));
+
+ /*
+ * Finally transfer any trailing byte.
+ */
+
+ if (pio_len_bytes % 2)
+ {
+ *(pio_address+pio_len_bytes - 1) =
+ sys_insb(
+ adapter_handle,
+ adapter->sif_sdmadat);
+ }
+ }
+ else
+ {
+ /*
+ * Transfer into adapter memory from the host.
+ */
+
+ if ((card_t)pio_address % 2)
+ {
+ pio_len_bytes--;
+ sys_outsb(
+ adapter_handle,
+ (WORD) (adapter->sif_sdmadat + 1),
+ *(pio_address++));
+ }
+
+ sys_rep_outsw(
+ adapter_handle,
+ adapter->sif_sdmadat,
+ pio_address,
+ (WORD) (pio_len_bytes >> 1));
+
+ if (pio_len_bytes % 2)
+ {
+ sys_outsb(
+ adapter_handle,
+ adapter->sif_sdmadat,
+ *(pio_address+pio_len_bytes-1));
+ }
+ }
+ /*
+ * Wait for SWHLDA to go low, it is not safe to access normal SIF registers
+ * until this is the case.
+ */
+ do
+ {
+ sifacl = sys_insw(adapter_handle, adapter->sif_acl);
+ }
+ while (sifacl & EAGLE_SIFACL_SWHLDA);
+
+ /*
+ * Now output 0xFFFF to the PIO_HANDSHAKE word, to signal the DMA is complete.
+ */
+ sys_outsw(adapter_handle, adapter->sif_dat, 0xFFFF );
+
+ /*
+ * Restore the saved SIF address.
+ */
+ sys_outsw(adapter_handle, adapter->sif_adr, saved_sifadr);
+
+
+ }
+ }
+ else if ((sifint_value & INT_PCIMMIO) != 0 && sifint_occurred)
+ {
+ /*
+ * We have an MMIO interrupt so we can
+ * assume that we've not had an ordinary SIF interrupt.
+ */
+
+ sifint_occurred = FALSE;
+
+ /*
+ * PIO interrupt has occurred.Transfer data to/from adapter.
+ */
+
+ pioint_occurred = TRUE;
+
+ /*
+ * Preserve the contents of SIFADR.
+ */
+
+ saved_sifadr = sys_insw(adapter_handle,
+ adapter->sif_adr);
+
+ sys_outsw(
+ adapter_handle,
+ adapter->sif_adr,
+ DIO_LOCATION_DMA_POINTER);
+
+ pio_addr_lo = sys_insw(
+ adapter_handle,
+ adapter->sif_datinc);
+
+ pio_addr_hi = sys_insw(
+ adapter_handle,
+ adapter->sif_datinc);
+
+ pio_address = (BYTE FAR *) ((((DWORD) pio_addr_hi) << 16) |
+ pio_addr_lo);
+
+ pio_len_bytes = sys_insw(
+ adapter_handle,
+ adapter->sif_datinc);
+
+ mmio_alignment = sys_insw(
+ adapter_handle,
+ adapter->sif_datinc);
+
+ sys_outsw(
+ adapter_handle,
+ adapter->sif_adr,
+ DIO_LOCATION_DMA_CONTROL);
+
+ if (pio_len_bytes != 0)
+ {
+ mmio_addr = (BYTE FAR *) adapter->mmio_base_address;
+
+ if ((sifint_value & INT_PCIMMIO_RX) != 0)
+ {
+ /*
+ * Receive.
+ */
+
+ /*
+ * First off need to do a dummy read to initialise Hardware
+ * Read into a global variable to stop the optimiser from
+ * optimising out the statement.
+ */
+
+ sys_movsd_from(
+ adapter_handle,
+ (DWORD)mmio_addr,
+ (DWORD)(&mmio_dword));
+
+ /*
+ * Take care of the first DWORD, which may not all be valid
+ * data.
+ */
+
+ if (mmio_alignment != 0)
+ {
+ sys_movsd_from(
+ adapter_handle,
+ (DWORD)mmio_addr,
+ (DWORD)(&mmio_dword));
+
+ mmio_addr += 4;
+
+ for (i = mmio_alignment;
+ ((i < 4) && (pio_len_bytes > 0));
+ i++)
+ {
+ *pio_address = *(((BYTE FAR *) &mmio_dword) + i);
+ pio_address++;
+ pio_len_bytes--;
+ }
+ }
+
+ /*
+ * Transfer the bulk of the DWORDs.
+ */
+
+ if (pio_len_bytes >= 4)
+ {
+ sys_rep_movsd_from(
+ adapter_handle,
+ (DWORD)mmio_addr,
+ (DWORD)pio_address,
+ (WORD) (pio_len_bytes & 0xfffc));
+
+ pio_address += (pio_len_bytes & 0xfffc);
+ mmio_addr += (pio_len_bytes & 0xfffc);
+ pio_len_bytes &= 0x0003;
+ }
+
+ /*
+ * Deal with any trailing bytes in the last DWORD.
+ */
+
+ if (pio_len_bytes > 0)
+ {
+ sys_movsd_from(
+ adapter_handle,
+ (DWORD)mmio_addr,
+ (DWORD)(&mmio_dword));
+
+ for(i = 0; i < pio_len_bytes; i++)
+ {
+ *pio_address = *(((BYTE FAR *) &mmio_dword) + i);
+ pio_address++;
+ }
+ }
+
+ /*
+ * Write the handshake value.
+ */
+
+ sys_outsw(
+ adapter_handle,
+ adapter->sif_dat,
+ 0xffff);
+ }
+ else
+ {
+ /*
+ * Transmit.
+ */
+
+ switch (mmio_alignment)
+ {
+ /*
+ * If the alignment is 0 then there is a whole DWORD
+ * to copy so we don't do anything and let the following
+ * code handle it.
+ */
+
+ case 0:
+ break;
+
+ /*
+ * If the alignment is 1 then we can't do anything
+ * we cannot write 3 bytes in one go.
+ */
+
+ case 1:
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_16_PCI_3BYTE_PROBLEM;
+
+ return;
+
+ /*
+ * If the alignment is 2 then we must transfer a word
+ * unless there is only one byte of data.
+ */
+
+ case 2:
+ if (pio_len_bytes == 1)
+ {
+ *(mmio_addr + 2) = *pio_address;
+ pio_address++;
+ pio_len_bytes--;
+ }
+ else
+ {
+ *((WORD FAR *) (mmio_addr + 2)) =
+ *((WORD FAR *) pio_address);
+ pio_address += 2;
+ pio_len_bytes -= 2;
+ mmio_addr += 4;
+ }
+
+ break;
+
+ /*
+ * If the alignment is 3 then we must transfer a byte.
+ */
+
+ case 3:
+ *(mmio_addr + 3) = *pio_address;
+ pio_address++;
+ pio_len_bytes--;
+ mmio_addr += 4;
+
+ break;
+ }
+
+ /*
+ * Transfer the bulk of the DWORDs.
+ */
+
+ if (pio_len_bytes >= 4)
+ {
+ sys_rep_movsd_to(
+ adapter_handle,
+ (DWORD)pio_address,
+ (DWORD)mmio_addr,
+ (WORD) (pio_len_bytes & 0xfffc));
+
+ pio_address += (pio_len_bytes & 0xfffc);
+ mmio_addr += (pio_len_bytes & 0xfffc);
+ pio_len_bytes &= 0x0003;
+ }
+
+ /*
+ * Transfer the remainder of the data.
+ */
+
+ switch (pio_len_bytes)
+ {
+ /*
+ * There may be nothing left to do.
+ */
+
+ case 0:
+ break;
+
+ /*
+ * If there is 1 byte left the just do a single byte
+ * copy.
+ */
+
+ case 1:
+ *mmio_addr = *pio_address;
+
+ break;
+
+ /*
+ * If there are two bytes left then do a word copy.
+ */
+
+ case 2:
+ *((WORD FAR *) mmio_addr) = *((WORD FAR *) pio_address);
+
+ break;
+
+ /*
+ * If there are 3 bytes left then we have a slight
+ * problem as we cannot do a single write of 3 bytes.
+ * Fortunately there should always be some space left
+ * at the end of a buffer on the adapter.
+ */
+
+ case 3:
+ sys_movsd_to(
+ adapter_handle,
+ (DWORD)pio_address,
+ (DWORD)mmio_addr);
+
+ break;
+ }
+
+ /*
+ * There now follows an extended handshake, to
+ * workaround the SAM upload hardware bug on the PCI I. The
+ * host must not make any DIO access until the upload has
+ * finished. In order to achieve this we:
+ *
+ * a) write 05555h to the DMA_CONTROL, to indicate that we've
+ * completed the MMIO write.
+ *
+ * b) poll DMA_CONTROL until it becomes 0AAAAh, indicating
+ * that the adapter is now about to do the upload.
+ *
+ * c) write 0FFFFh to DMA_CONTROL, to indicate that we've
+ * completed reading from DIO space.
+ *
+ * d) wait 'x' microseconds while the adapter does
+ * the upload.
+ *
+ * We make sure that we're not reading any cached
+ * value from the data_reg by writing to the sifaddr
+ * beforehand.
+ */
+
+ sys_outsw(
+ adapter_handle,
+ adapter->sif_dat,
+ 0x5555);
+
+ do
+ {
+ sys_outsw(
+ adapter_handle,
+ adapter->sif_adr,
+ DIO_LOCATION_DMA_CONTROL);
+ }
+ while (sys_insw(adapter_handle, adapter->sif_dat) != 0xaaaa);
+
+ sys_outsw(
+ adapter_handle,
+ adapter->sif_adr,
+ DIO_LOCATION_DMA_CONTROL);
+
+ sys_outsw(
+ adapter_handle,
+ adapter->sif_dat,
+ 0xffff);
+
+ sys_wait_at_least_microseconds(4);
+ }
+ }
+
+ /*
+ * Restore SIFADR.
+ */
+
+ sys_outsw(
+ adapter_handle,
+ adapter->sif_adr,
+ saved_sifadr);
+ }
+
+ /*
+ * Now that we have finished acknowledging the interrupt at the card,
+ * we acknowledge it at the interrupt controller.
+ */
+
+#ifndef FTK_NO_CLEAR_IRQ
+
+ if (sifint_occurred || pioint_occurred)
+ {
+ /*
+ * Acknowledge/clear interrupt at interrupt controller.
+ */
+
+ sys_clear_controller_interrupt(
+ adapter_handle,
+ adapter->interrupt_number);
+ }
+
+#endif
+
+ /*
+ * Only now do we do driver specific processing of SIF interrupts.
+ */
+
+ if (sifint_occurred)
+ {
+ /*
+ * Call driver with details of SIF interrupt.
+ */
+
+ driver_interrupt_entry(adapter_handle, adapter, sifint_value);
+ }
+
+ /*
+ * Let system know we have finished accessing the IO ports.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+}
+
+
+/****************************************************************************
+*
+* hwi_pci_remove_card
+* ===================
+*
+*
+* PARAMETERS (passed by hwi_remove_card)
+* ======================================
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+*
+* BODY :
+* ======
+*
+* The hwi_smart16_remove_card routine is called by hwi_remove_adapter. It
+* disables interrupts if they are being used. It also resets the adapter.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine always successfully completes.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(hwi_pci_remove_card)
+#endif
+
+export void
+hwi_pci_remove_card(
+ ADAPTER * adapter
+ )
+{
+ ADAPTER_HANDLE adapter_handle = adapter->adapter_handle;
+ WORD wGenConAddr = adapter->io_location +
+ PCI_GENERAL_CONTROL_REG;
+ WORD wControl;
+ WORD sifacl;
+
+ /*
+ * Interrupt must be disabled at adapter before unpatching interrupt.
+ * Even in polling mode we must turn off interrupts at adapter.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ sifacl = sys_insw(adapter_handle, adapter->sif_acl);
+ sifacl = (sifacl & ~(EAGLE_SIFACL_PSDMAEN | EAGLE_SIFACL_SINTEN));
+ sys_outsw(adapter_handle, adapter->sif_acl, sifacl);
+
+ if (adapter->interrupts_on)
+ {
+ if (adapter->interrupt_number != POLLING_INTERRUPTS_MODE)
+ {
+ sys_disable_irq_channel(
+ adapter_handle,
+ adapter->interrupt_number);
+ }
+
+ adapter->interrupts_on = FALSE;
+ }
+
+ /*
+ * Reset the Eagle
+ */
+
+ wControl = sys_insw(adapter_handle, wGenConAddr);
+ wControl &= ~PCI1_SRESET;
+ sys_outsw(adapter_handle, wGenConAddr, wControl);
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+}
+
+
+/****************************************************************************
+*
+* hwi_pci_set_dio_address
+* =======================
+*
+* The hwi_pci_set_dio_address routine is used, with PCI cards, for
+* putting a 32 bit DIO address into the SIF DIO address and extended DIO
+* address registers. Note that the extended address register should be
+* loaded first.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_pci_set_dio_address)
+#endif
+
+export void
+hwi_pci_set_dio_address(
+ ADAPTER * adapter,
+ DWORD dio_address )
+{
+ ADAPTER_HANDLE adapter_handle = adapter->adapter_handle;
+ WORD sif_dio_adr = adapter->sif_adr;
+ WORD sif_dio_adrx = adapter->sif_adx;
+
+ /*
+ * Load extended DIO address register with top 16 bits of address.
+ * Always load extended address register first.
+ */
+
+ sys_outsw(
+ adapter_handle,
+ sif_dio_adrx,
+ (WORD)(dio_address >> 16));
+
+ /*
+ * Load DIO address register with low 16 bits of address.
+ */
+
+ sys_outsw(
+ adapter_handle,
+ sif_dio_adr,
+ (WORD)(dio_address & 0x0000FFFF));
+}
+
+/*---------------------------------------------------------------------------
+|
+| LOCAL PROCEDURES
+|
+---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------
+|
+| pci_c46_write_bit
+| ==================
+|
+| Write a bit to the SEEPROM control register.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pci_c46_write_bit)
+#endif
+
+local void
+pci_c46_write_bit(
+ ADAPTER * adapter,
+ WORD mask,
+ WBOOLEAN set_bit
+ )
+{
+ WORD ctrl_reg;
+
+ /*
+ * Get the current value of the SEEPROM control register.
+ */
+
+ ctrl_reg = sys_insb(
+ adapter->adapter_handle,
+ (WORD) (adapter->io_location + PCI_SEEPROM_CONTROL_REG));
+
+ /*
+ * Some bits cannot be read back from the SEEPROM control register once
+ * they have been written, so we must keep track of them ourself.
+ */
+
+ ctrl_reg |= adapter->c46_bits;
+
+ /*
+ * Clear or set the bit.
+ */
+
+ if (set_bit)
+ {
+ ctrl_reg |= mask;
+ }
+ else
+ {
+ ctrl_reg &= ~mask;
+ }
+
+ /*
+ * Write the data to the SEEPROM control register.
+ */
+
+ sys_outsb(
+ adapter->adapter_handle,
+ (WORD) (adapter->io_location + PCI_SEEPROM_CONTROL_REG),
+ (BYTE) ctrl_reg);
+
+ /*
+ * Remember the bits that we cannot read back.
+ */
+
+ adapter->c46_bits = ctrl_reg & BITS_TO_REMEMBER;
+
+ /*
+ * Wait for a bit.
+ */
+
+ sys_wait_at_least_microseconds(10);
+
+ /*
+ * And read the SEEPROM control register back so that the data gets
+ * latched properly.
+ */
+
+ sys_insb(
+ adapter->adapter_handle,
+ (WORD) (adapter->io_location + PCI_SEEPROM_CONTROL_REG));
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| pci_c46_twitch_clock
+| ====================
+|
+| Toggle the SEEPROM clock.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pci_c46_twitch_clock)
+#endif
+
+local void
+pci_c46_twitch_clock(
+ ADAPTER * adapter
+ )
+{
+ pci_c46_write_bit(adapter, PCI1_BIA_CLK, TRUE);
+ pci_c46_write_bit(adapter, PCI1_BIA_CLK, FALSE);
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| pci_c46_read_data
+| =================
+|
+| Read a data bit from the SEEPROM control register
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pci_c46_read_data)
+#endif
+
+local WORD
+pci_c46_read_data(
+ ADAPTER * adapter
+ )
+{
+ return sys_insb(
+ adapter->adapter_handle,
+ (WORD) (adapter->io_location + PCI_SEEPROM_CONTROL_REG)
+ ) & PCI1_BIA_DIN;
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| hwi_pci_read_eeprom_word
+| ========================
+|
+| hwi_pci_read_eeprom_word takes the address of the word to be read
+| from the AT93C46 serial EEPROM, write to the IO ports a magic sequence
+| to switch the EEPROM to reading mode and finally read the required word
+| and return.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_pci_read_eeprom_word)
+#endif
+
+local WORD
+hwi_pci_read_eeprom_word(
+ ADAPTER * adapter,
+ WORD word_address
+ )
+{
+ WORD i;
+ WORD cmd_word = PCI_C46_START_BIT | PCI_C46_READ_CMD;
+ WORD tmp_word;
+
+ /*
+ * Concatenate the address to command word.
+ */
+
+ cmd_word |= (WORD)((word_address & PCI_C46_ADDR_MASK) <<
+ PCI_C46_ADDR_SHIFT);
+
+ /*
+ * Clear data in bit.
+ */
+
+ pci_c46_write_bit(
+ adapter,
+ PCI1_BIA_DOUT,
+ FALSE);
+
+ /*
+ * Assert chip select bit.
+ */
+
+ pci_c46_write_bit(
+ adapter,
+ PCI1_BIA_ENA,
+ TRUE);
+
+ /*
+ * Send read command and address.
+ */
+
+ pci_c46_twitch_clock(adapter);
+
+ tmp_word = cmd_word;
+
+ for (i = 0; i < PCI_C46_CMD_LENGTH; i++)
+ {
+ pci_c46_write_bit(
+ adapter,
+ PCI1_BIA_DOUT,
+ (WBOOLEAN) ((tmp_word & 0x8000) != 0));
+ pci_c46_twitch_clock(adapter);
+ tmp_word <<= 1;
+ }
+
+ /*
+ * Read data word.
+ */
+
+ tmp_word = 0x0000;
+
+ for (i = 0; i < 16; i++)
+ {
+ pci_c46_twitch_clock(adapter);
+
+ if (i > 0)
+ {
+ tmp_word <<= 1;
+ }
+
+ if (pci_c46_read_data(adapter) != 0)
+ {
+ tmp_word |= 0x0001;
+ }
+ }
+
+ /*
+ * Clear data in bit.
+ */
+
+ pci_c46_write_bit(adapter, PCI1_BIA_DOUT, FALSE);
+
+ /*
+ * Deselect chip.
+ */
+
+ pci_c46_write_bit(adapter, PCI1_BIA_ENA, FALSE);
+
+ /*
+ * Tick clock.
+ */
+
+ pci_c46_twitch_clock(adapter);
+
+ return tmp_word;
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| hwi_pci_read_node_address
+| =========================
+|
+| The hwi_pci_read_node_address routine reads in the node address from
+| the SEEPROM, and checks that it is a valid Madge node address.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_pci_read_node_address)
+#endif
+
+local WBOOLEAN
+hwi_pci_read_node_address(
+ ADAPTER * adapter
+ )
+{
+ WORD temp;
+
+ temp = hwi_pci_read_eeprom_word(adapter, PCI_EEPROM_BIA_WORD0);
+ adapter->permanent_address.byte[0] = (BYTE) ((temp ) & 0x00ff);
+ adapter->permanent_address.byte[1] = (BYTE) ((temp >> 8) & 0x00ff);
+
+ temp = hwi_pci_read_eeprom_word(adapter, PCI_EEPROM_BIA_WORD1);
+ adapter->permanent_address.byte[2] = (BYTE) ((temp ) & 0x00ff);
+ adapter->permanent_address.byte[3] = (BYTE) ((temp >> 8) & 0x00ff);
+
+ temp = hwi_pci_read_eeprom_word(adapter, PCI_EEPROM_BIA_WORD2);
+ adapter->permanent_address.byte[4] = (BYTE) ((temp ) & 0x00ff);
+ adapter->permanent_address.byte[5] = (BYTE) ((temp >> 8) & 0x00ff);
+
+ return TRUE;
+}
+
+#endif
+
+/******* End of HWI_PCI.C **************************************************/
diff --git a/private/ntos/ndis/madge/driver/hwi_pci2.c b/private/ntos/ndis/madge/driver/hwi_pci2.c
new file mode 100644
index 000000000..40a5320ed
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/hwi_pci2.c
@@ -0,0 +1,1792 @@
+/****************************************************************************
+*
+* HWI_PCI2.C : Part of the FASTMAC TOOL-KIT (FTK)
+*
+* HARDWARE INTERFACE MODULE FOR PCI CARDS
+*
+* Copyright (c) Madge Networks Ltd. 1994
+*
+* COMPANY CONFIDENTIAL
+*
+*
+*****************************************************************************
+*
+* The purpose of the Hardware Interface (HWI) is to supply an adapter card
+* independent interface to any driver. It performs nearly all of the
+* functions that involve affecting SIF registers on the adapter cards.
+* This includes downloading code to, initializing, and removing adapters.
+*
+* The HWI_PCIT.C module contains the routines specific to the Smart 16/4
+* PCI(BM) based on the Madge PCI ASIC, this card supports Pseudo DMA, and
+* bus master DMA.
+*
+*****************************************************************************
+
+/*---------------------------------------------------------------------------
+|
+| DEFINITIONS
+|
+---------------------------------------------------------------------------*/
+
+#define PCI_PCI2_DEVICE_ID 2
+
+#include "ftk_defs.h"
+
+/*---------------------------------------------------------------------------
+|
+| MODULE ENTRY POINTS
+|
+---------------------------------------------------------------------------*/
+
+#include "ftk_intr.h" /* routines internal to FTK */
+#include "ftk_extr.h" /* routines provided or used by external FTK user */
+
+BYTE bEepromByteStore;
+BYTE bLastDataBit;
+
+#ifndef FTK_NO_PCI2
+
+/*---------------------------------------------------------------------------
+|
+| LOCAL PROCEDURES
+|
+---------------------------------------------------------------------------*/
+
+local WBOOLEAN
+hwi_pci2_read_node_address(
+ ADAPTER * adapter
+ );
+
+local WORD
+hwi_at24_read_a_word(
+ ADAPTER * adapter,
+ WORD word_address
+ );
+
+#ifndef FTK_NO_PROBE
+/****************************************************************************
+*
+* hwi_pci2_probe_card
+* ==================
+*
+*
+* PARAMETERS (passed by hwi_probe_adapter) :
+* ==========================================
+*
+* PROBE * resources
+*
+* resources is an array structures used to identify and record specific
+* information about adapters found.
+*
+* UINT length
+*
+* length is the number of structures pointed to by reources.
+*
+* WORD * valid_locations
+*
+* valid_locations is normally an array of IO locations to examine for the
+* presence of an adapter. However for PCI adapters the io location is read
+* from the BIOS, so this array can remain empty.
+*
+* UINT number_locations
+*
+* This is the number of IO locations in the above list.
+*
+* BODY :
+* ======
+*
+* The hwi_pci2_probe_card routine is called by hwi_probe_adapter. It
+* reads the id registers to find the type of card and also reads the IRQ.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine returns the number of adapters found, or PROBE_FAILURE if
+* there's a problem.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_pci2_probe_card)
+#endif
+
+export UINT
+hwi_pci2_probe_card(
+ PROBE * Resources,
+ UINT NumberOfResources,
+ WORD * IOMask,
+ UINT NumberIO
+ )
+{
+ WORD i;
+ WORD Handle;
+
+ if (!sys_pci_valid_machine())
+ {
+ return 0;
+ }
+
+ for (i=0;i<NumberOfResources;i++)
+ {
+ if (!sys_pci_find_card(&Handle, i,PCI_PCI2_DEVICE_ID))
+ {
+ break;
+ }
+
+ Resources[i].pci_handle = Handle;
+ Resources[i].adapter_card_bus_type = ADAPTER_CARD_PCI2_BUS_TYPE;
+
+ if (!sys_pci_get_io_base(Handle, &(Resources[i].io_location)))
+ {
+ return PROBE_FAILURE;
+ }
+
+ if (!sys_pci_get_irq(Handle, &(Resources[i].interrupt_number)))
+ {
+ return PROBE_FAILURE;
+ }
+
+
+ /*
+ * We can't read the memory size from the serial EEPROM until the
+ * hwi_pci2_install_card function is called.
+ */
+
+ Resources[i].adapter_ram_size = 512;
+
+ Resources[i].adapter_card_type = ADAPTER_CARD_TYPE_16_4_PCI2;
+
+ Resources[i].transfer_mode = PIO_DATA_TRANSFER_MODE;
+
+ }
+
+ return i;
+}
+#endif
+
+/****************************************************************************
+*
+* hwi_pci2_install_card
+* ====================
+*
+*
+* PARAMETERS (passed by hwi_install_adapter) :
+* ============================================
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+* DOWNLOAD_IMAGE * download_image
+*
+* This is the code to be downloaded to the adapter. The image must be of
+* the correct type i.e. must be downloadable into the adapter. If the
+* pointer is 0 downloading is not done.
+*
+*
+* BODY :
+* ======
+*
+* hwi_pci2_install_card is called by hwi_install_adapter. It sets up
+* the adapter card and downloads the required code to it. Firstly, it
+* checks there is a valid adapter at the required IO address by reading
+* the node address from the BIA PROM. It then sets up and checks various
+* on-board registers for correct operation.
+*
+* Then, it halts the EAGLE, downloads the code, restarts the EAGLE and
+* waits up to 3 seconds for a valid bring-up code. If interrupts are
+* required, these are enabled by operating system specific calls.
+* The adapter is set up for Eagle Pseudo-DMA, since real DMA is not used.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine returns TRUE if it succeeds. If this routine fails (returns
+* FALSE) then a subsequent call to driver_explain_error, with the adapter
+* handle corresponding to the adapter parameter used here, will give an
+* explanation.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_pci2_install_card)
+#endif
+
+export WBOOLEAN
+hwi_pci2_install_card(
+ ADAPTER * adapter,
+ DOWNLOAD_IMAGE * download_image
+ )
+{
+ ADAPTER_HANDLE adapter_handle = adapter->adapter_handle;
+ WORD sif_base;
+ WORD ring_speed;
+ WORD wHardFeatures;
+ BYTE bTemp;
+
+ /*
+ * These things can all be assumed for the PCI2 Card.
+ */
+
+ adapter->adapter_card_type = ADAPTER_CARD_TYPE_16_4_PCI2;
+ adapter->adapter_card_revision = ADAPTER_CARD_16_4_PCI2;
+ adapter->edge_triggered_ints = FALSE;
+ adapter->mc32_config = 0;
+
+ /*
+ * Start off by assuming we will use pseudo DMA.
+ */
+
+ adapter->EaglePsDMA = TRUE;
+
+ /*
+ * Save IO locations of SIF registers.
+ */
+
+ sif_base = adapter->io_location + PCI2_SIF_OFFSET;
+
+ adapter->sif_dat = sif_base + EAGLE_SIFDAT;
+ adapter->sif_datinc = sif_base + EAGLE_SIFDAT_INC;
+ adapter->sif_adr = sif_base + EAGLE_SIFADR;
+ adapter->sif_int = sif_base + EAGLE_SIFINT;
+ adapter->sif_acl = sif_base + EAGLE_SIFACL;
+ adapter->sif_adx = sif_base + EAGLE_SIFADX;
+ adapter->sif_dmalen = sif_base + EAGLE_DMALEN;
+ adapter->sif_sdmadat = sif_base + EAGLE_SDMADAT;
+ adapter->sif_sdmaadr = sif_base + EAGLE_SDMAADR;
+ adapter->sif_sdmaadx = sif_base + EAGLE_SDMAADX;
+
+ adapter->io_range = PCI2_IO_RANGE;
+
+ /*
+ * RESET the Card
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ /*
+ * Clear all the RESET bits, wait at least 14uS and then assert all three
+ * , turning on one at a time, in the following sequence
+ * - Set CHIP_NRES
+ * - Set SIF_NRES
+ * - Set FIFO_NRES
+ */
+
+ bTemp = sys_insb(
+ adapter_handle,
+ (WORD) (adapter->io_location + PCI2_RESET));
+
+ bTemp &= ~(PCI2_CHIP_NRES | PCI2_FIFO_NRES | PCI2_SIF_NRES);
+
+ sys_outsb(
+ adapter_handle,
+ (WORD) (adapter->io_location + PCI2_RESET),
+ bTemp);
+
+ /*
+ * Wait 14 uS before taking it out of reset.
+ */
+
+ sys_wait_at_least_microseconds(14);
+
+ bTemp |= PCI2_CHIP_NRES;
+
+ sys_outsb(
+ adapter_handle,
+ (WORD) (adapter->io_location + PCI2_RESET),
+ bTemp);
+
+ bTemp |= PCI2_SIF_NRES;
+
+ sys_outsb(
+ adapter_handle,
+ (WORD) (adapter->io_location + PCI2_RESET),
+ bTemp);
+
+ bTemp |= PCI2_FIFO_NRES;
+
+ sys_outsb(adapter_handle,
+ (WORD) (adapter->io_location + PCI2_RESET),
+ bTemp);
+
+
+ if (!hwi_pci2_read_node_address(adapter))
+ {
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_05_ADAPTER_NOT_FOUND;
+ return FALSE;
+ }
+
+ /*
+ * If this is 1 the card is @ 4Mbit/s 0 16MBit/s.
+ */
+
+ ring_speed = hwi_at24_read_a_word(adapter, PCI2_EEPROM_RING_SPEED);
+
+ /*
+ * Get the amount of RAM from the serial EEPROM (in units of 128k).
+ */
+
+ adapter->adapter_ram_size = hwi_at24_read_a_word(
+ adapter,
+ PCI2_EEPROM_RAM_SIZE) * 128;
+
+
+ /*
+ * This flag tells us if the card supports DMA, and if it supports release
+ * 4.31 software.
+ */
+
+ wHardFeatures = hwi_at24_read_a_word(adapter, PCI2_HWF2);
+
+#define RELEASE_431 1
+#ifdef RELEASE_431
+
+ if (!(wHardFeatures & PCI2_HW2_431_READY))
+ {
+ /*
+ * This card does not support Release 4.31 software.
+ */
+
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_05_ADAPTER_NOT_FOUND;
+ return FALSE;
+ }
+
+#endif
+
+ if (adapter->transfer_mode == DMA_DATA_TRANSFER_MODE)
+ {
+ /*
+ * Does this card support DMA ???
+ */
+
+ if (wHardFeatures & PCI2_BUS_MASTER_ONLY)
+ {
+ adapter->EaglePsDMA = FALSE;
+
+ /*
+ * Need to set the MASTER ENABLE bit in the PCI Command register
+ * otherwise DMA will not work and will hang the machine.
+ * The BIOS should do this, but some don't.
+ */
+
+ sys_pci_read_config_byte(
+ adapter_handle,
+ PCI_CONFIG_COMMAND,
+ &bTemp);
+
+ bTemp |= PCI_CONFIG_BUS_MASTER_ENABLE;
+
+ sys_pci_write_config_byte(
+ adapter_handle,
+ PCI_CONFIG_COMMAND,
+ bTemp);
+ }
+ else
+ {
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_06_CANNOT_USE_DMA;
+ return FALSE;
+ }
+
+ }
+
+ /*
+ * If we've using pseudo DMA then we need a software handshake.
+ */
+
+ if (adapter->EaglePsDMA)
+ {
+ adapter->mc32_config = MC_AND_ISACP_USE_PIO;
+ }
+
+ /*
+ * Set the ring speed. If the user has specified a value then we will
+ * use that, otherwise we will use the value read from the EEPROM.
+ */
+
+ /*
+ * These NSEL bits are different to other cards, bit 0 must be ~bit1
+ * There is a missing NOT gate in the ASIC.
+ */
+
+ if (adapter->set_ring_speed == 16)
+ {
+ adapter->nselout_bits = 0;
+ }
+ else if (adapter->set_ring_speed == 4)
+ {
+ adapter->nselout_bits = 2;
+ }
+ else if (ring_speed == PCI2_EEPROM_4MBITS)
+ {
+ adapter->nselout_bits = 2;
+ }
+ else
+ {
+ adapter->nselout_bits = 0;
+ }
+
+ /*
+ * Set the interrupt control register to enable SIF interrupts and
+ * PCI Error interrupts, although the ISR does nowt about the latter
+ * at present.
+ */
+
+ sys_outsb( adapter->adapter_handle, (WORD) (adapter->io_location + PCI2_INTERRUPT_CONTROL), PCI2_SINTEN | PCI2_PCI_ERR_EN);
+
+ /*
+ * Halt the Eagle prior to downloading the MAC code - this will also
+ * write the interrupt bits into the SIFACL register, where the MAC can
+ * find them.
+ */
+
+ hwi_halt_eagle(adapter);
+
+ /*
+ * Download code to adapter.
+ * View download image as a sequence of download records.
+ * Pass address of routine to set up DIO addresses on PCI cards.
+ * If routine fails return failure (error record already filled in).
+ */
+
+ if (!hwi_download_code(
+ adapter,
+ (DOWNLOAD_RECORD *) download_image,
+ hwi_pci2_set_dio_address))
+ {
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+
+ /*
+ * Restart the Eagle to initiate bring up diagnostics.
+ */
+
+ hwi_start_eagle(adapter);
+
+ /*
+ * Wait for a valid bring up code, may wait 3 seconds.
+ */
+
+ if (!hwi_get_bring_up_code(adapter))
+ {
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+
+ /*
+ * Set DIO address to point to EAGLE DATA page 0x10000L.
+ */
+
+ hwi_pci2_set_dio_address(adapter, DIO_LOCATION_EAGLE_DATA_PAGE);
+
+ /*
+ * Get the ring speed, from the Eagle DIO space.
+ */
+
+ adapter->ring_speed = hwi_get_ring_speed(adapter);
+
+ /*
+ * Set maximum frame size from the ring speed.
+ */
+
+ adapter->max_frame_size = hwi_get_max_frame_size(adapter);
+
+ /*
+ * If not in polling mode then set up interrupts.
+ * interrupts_on field is used when disabling interrupts for adapter.
+ */
+
+ if (adapter->interrupt_number != POLLING_INTERRUPTS_MODE)
+ {
+ adapter->interrupts_on = sys_enable_irq_channel(
+ adapter_handle,
+ adapter->interrupt_number);
+
+ if (!adapter->interrupts_on)
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_0B_FAIL_IRQ_ENABLE;
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+ }
+ else
+ {
+ adapter->interrupts_on = TRUE;
+ }
+
+ /*
+ * Return successfully.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return TRUE;
+}
+
+/****************************************************************************
+*
+* hwi_pci2_interrupt_handler
+* =========================
+*
+*
+* PARAMETERS (passed by hwi_interrupt_entry) :
+* ==========================================
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+*
+* BODY :
+* ======
+*
+* The hwi_pci2_interrupt_handler routine is called, when an interrupt
+* occurs, by hwi_interrupt_entry. It checks to see if a particular card
+* has interrupted. The interrupt could be generated by the SIF for either
+* a PIO data transfer or a normal condition (received frame, SRB complete,
+* ARB indication etc). Note it could in fact be the case that no interrupt
+* has occured on the particular adapter being checked.
+*
+* On normal SIF interrupts, the interrupt is acknowledged and cleared. The
+* value in the SIF interrupt register is recorded in order to pass it to
+* the driver_interrupt_entry routine (along with the adapter details).
+*
+* On PseudoDMA interrupts, the length, direction and physical address of
+* the transfer is determined. A system provided routine is called to do
+* the data transfer itself.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine always successfully completes.
+*
+****************************************************************************/
+
+#ifdef FTK_IRQ_FUNCTION
+#pragma FTK_IRQ_FUNCTION(hwi_pci2_interrupt_handler)
+#endif
+
+export void
+hwi_pci2_interrupt_handler(
+ ADAPTER * adapter
+ )
+{
+ ADAPTER_HANDLE adapter_handle = adapter->adapter_handle;
+ WORD sifacl;
+ WORD sifint_value;
+ WORD sifint_tmp;
+ WORD pio_addr_lo;
+ WBOOLEAN sifint_occurred = FALSE;
+ WBOOLEAN pioint_occurred = FALSE;
+ DWORD pio_addr_hi;
+ WORD pio_len_bytes;
+ WBOOLEAN pio_from_adapter;
+ BYTE bInt;
+ BYTE FAR * pio_address;
+ WORD saved_sifadr;
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ /*
+ * Check for SIF interrupt or PIO interrupt.
+ */
+
+ /*
+ * Read SIFINT, and then re-read to make sure value is stable.
+ */
+
+ sifint_value = sys_insw(adapter_handle, adapter->sif_int);
+ do
+ {
+ sifint_tmp = sifint_value;
+ sifint_value = sys_insw(adapter_handle, adapter->sif_int);
+ }
+ while (sifint_tmp != sifint_value);
+
+ /*
+ * Given the SIFINT value, we can check one of the bits in it to see
+ * if that is what caused the interrupt.
+ */
+
+ if ((sifint_value & EAGLE_SIFINT_SYSTEM) != 0)
+ {
+ /*
+ * A SIF interrupt has occurred.
+ * This could be an SRB free, an adapter check or a received frame
+ * interrupt.
+ * Note that we do not process it yet - we wait until we have EOI'd
+ * the interrupt controller.
+ */
+
+ sifint_occurred = TRUE;
+
+ /*
+ * Clear EAGLE_SIFINT_HOST_IRQ to acknowledge interrupt at SIF.
+ */
+
+ sys_outsw(adapter_handle, adapter->sif_int, 0);
+
+ /*
+ * Call driver with details of SIF interrupt.
+ */
+
+ driver_interrupt_entry(adapter_handle, adapter, sifint_value);
+ }
+
+
+ /*
+ * Now read the SIFACL register to check for a PseudoDMA interrupt.
+ */
+
+ if (adapter->transfer_mode != DMA_DATA_TRANSFER_MODE)
+ {
+ sifacl = sys_insw(adapter_handle, adapter->sif_acl);
+
+ if ((sifacl & EAGLE_SIFACL_SWHRQ) != 0)
+ {
+ /*
+ * PIO interrupt has occurred. Transfer data to/from adapter.
+ */
+
+ pioint_occurred = TRUE;
+
+ /*
+ * Preserve SIFADR.
+ */
+
+ saved_sifadr = sys_insw(adapter_handle, adapter->sif_adr);
+
+ /*
+ * Start the software handshake.
+ */
+
+ sys_outsw(adapter_handle, adapter->sif_adr, DIO_LOCATION_DMA_CONTROL);
+ sys_outsw(adapter_handle, adapter->sif_dat, 0);
+
+ /*
+ * By writing the SWHLDA bit, we "start" the transfer,
+ * causing the SDMA registers to mapped in.
+ */
+
+ macro_setw_bit(
+ adapter_handle,
+ adapter->sif_acl,
+ EAGLE_SIFACL_SWHLDA);
+
+ /*
+ * Determine what direction the data transfer is to take place in.
+ */
+
+ pio_from_adapter = sys_insw(
+ adapter_handle,
+ adapter->sif_acl) & EAGLE_SIFACL_SWDDIR;
+
+ pio_len_bytes = sys_insw(
+ adapter_handle,
+ adapter->sif_dmalen);
+
+ pio_addr_lo = sys_insw(
+ adapter_handle,
+ adapter->sif_sdmaadr);
+
+ pio_addr_hi = (DWORD) sys_insw(
+ adapter_handle,
+ adapter->sif_sdmaadx);
+
+ pio_address = (BYTE FAR *) ((pio_addr_hi << 16) |
+ ((DWORD) pio_addr_lo));
+
+
+ /*
+ * Do the actual data transfer.
+ */
+
+ /*
+ * Note that Fastmac only copies whole WORDs to DWORD boundaries.
+ * FastmacPlus, however, can transfer any length to any address.
+ */
+
+ if (pio_from_adapter)
+ {
+ /*
+ * Transfer into host memory from adapter.
+ */
+
+ /*
+ * First, check if host address is on an odd byte boundary.
+ */
+
+ if ((card_t)pio_address % 2)
+ {
+ pio_len_bytes--;
+ *(pio_address++) = sys_insb(
+ adapter_handle,
+ (WORD) (adapter->sif_sdmadat + 1));
+ }
+
+ /*
+ * Now transfer the bulk of the data.
+ */
+
+ sys_rep_insw(
+ adapter_handle,
+ adapter->sif_sdmadat,
+ pio_address,
+ (WORD) (pio_len_bytes >> 1));
+
+ /*
+ * Finally transfer any trailing byte.
+ */
+
+ if (pio_len_bytes % 2)
+ {
+ *(pio_address+pio_len_bytes - 1) =
+ sys_insb(adapter_handle, adapter->sif_sdmadat);
+ }
+ }
+ else
+ {
+ /*
+ * Transfer into adapter memory from the host.
+ */
+
+ if ((card_t)pio_address % 2)
+ {
+ pio_len_bytes--;
+ sys_outsb(
+ adapter_handle,
+ (WORD) (adapter->sif_sdmadat + 1),
+ *(pio_address++));
+ }
+
+ sys_rep_outsw(
+ adapter_handle,
+ adapter->sif_sdmadat,
+ pio_address,
+ (WORD) (pio_len_bytes >> 1));
+
+ if (pio_len_bytes % 2)
+ {
+ sys_outsb(
+ adapter_handle,
+ adapter->sif_sdmadat,
+ *(pio_address+pio_len_bytes-1));
+ }
+ }
+
+ /*
+ * Wait for SWHLDA to go low, it is not safe to access
+ * normal SIF registers until this is the case.
+ */
+
+ do
+ {
+ sifacl = sys_insw(adapter_handle, adapter->sif_acl);
+ }
+ while (sifacl & EAGLE_SIFACL_SWHLDA);
+
+ /*
+ * Finish the software handshake. We need a dummy ready so that
+ * the SIF can stabalise.
+ */
+
+ sys_outsw(adapter_handle, adapter->sif_adr, DIO_LOCATION_DMA_CONTROL);
+ sys_insw(adapter_handle, adapter->sif_dat);
+
+ sys_outsw(adapter_handle, adapter->sif_adr, DIO_LOCATION_DMA_CONTROL);
+ sys_outsw(adapter_handle, adapter->sif_dat, 0xFFFF);
+
+ /*
+ * Restore SIFDR.
+ */
+
+ sys_outsw(adapter_handle, adapter->sif_adr, saved_sifadr);
+ }
+ }
+
+ if (pioint_occurred || sifint_occurred)
+ {
+#ifndef FTK_NO_CLEAR_IRQ
+
+ /*
+ * Acknowledge/clear interrupt at interrupt controller.
+ */
+
+ sys_clear_controller_interrupt(
+ adapter_handle,
+ adapter->interrupt_number);
+
+#endif
+ }
+ else
+ {
+ bInt = sys_insb(
+ adapter->adapter_handle,
+ (WORD) (adapter->io_location + PCI2_INTERRUPT_STATUS));
+
+ if (bInt & PCI2_PCI_INT)
+ {
+#ifndef FTK_NO_CLEAR_IRQ
+
+ sys_clear_controller_interrupt(
+ adapter_handle,
+ adapter->interrupt_number);
+
+#endif
+ }
+ }
+
+ /*
+ * Let system know we have finished accessing the IO ports.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+
+}
+
+
+/****************************************************************************
+*
+* hwi_pci2_remove_card
+* ===================
+*
+*
+* PARAMETERS (passed by hwi_remove_card)
+* ======================================
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+*
+* BODY :
+* ======
+*
+* The hwi_smart16_remove_card routine is called by hwi_remove_adapter. It
+* disables interrupts if they are being used. It also resets the adapter.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine always successfully completes.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(hwi_pci2_remove_card)
+#endif
+
+export void
+hwi_pci2_remove_card(
+ ADAPTER * adapter
+ )
+{
+ ADAPTER_HANDLE adapter_handle = adapter->adapter_handle;
+ WORD wGenConAddr = adapter->io_location +
+ PCI_GENERAL_CONTROL_REG;
+ WORD sifacl;
+ BYTE bTemp;
+
+ /*
+ * Interrupt must be disabled at adapter before unpatching interrupt.
+ * Even in polling mode we must turn off interrupts at adapter.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ sifacl = sys_insw(adapter_handle, adapter->sif_acl);
+ sifacl = (sifacl & ~(EAGLE_SIFACL_PSDMAEN | EAGLE_SIFACL_SINTEN));
+ sys_outsw(adapter_handle, adapter->sif_acl, sifacl);
+
+ if (adapter->interrupts_on)
+ {
+ if (adapter->interrupt_number != POLLING_INTERRUPTS_MODE)
+ {
+ sys_disable_irq_channel(
+ adapter_handle,
+ adapter->interrupt_number);
+ }
+
+ adapter->interrupts_on = FALSE;
+ }
+
+ /*
+ * RESET the Eagle
+ */
+
+ bTemp = sys_insb(
+ adapter_handle,
+ (WORD) (adapter->io_location + PCI2_RESET));
+
+ bTemp &= ~(PCI2_CHIP_NRES | PCI2_FIFO_NRES | PCI2_SIF_NRES);
+
+ sys_outsb(
+ adapter_handle,
+ (WORD) (adapter->io_location + PCI2_RESET),
+ bTemp);
+
+ /*
+ * Wait 14 uS before taking it out of reset.
+ */
+
+ sys_wait_at_least_microseconds(14);
+
+ bTemp |= (PCI2_CHIP_NRES | PCI2_FIFO_NRES | PCI2_SIF_NRES);
+
+ sys_outsb(
+ adapter_handle,
+ (WORD) (adapter->io_location + PCI2_RESET),
+ bTemp);
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+}
+
+
+/****************************************************************************
+*
+* hwi_pci2_set_dio_address
+* =======================
+*
+* The hwi_pci2_set_dio_address routine is used, with PCI cards, for
+* putting a 32 bit DIO address into the SIF DIO address and extended DIO
+* address registers. Note that the extended address register should be
+* loaded first.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_pci2_set_dio_address)
+#endif
+
+export void
+hwi_pci2_set_dio_address(
+ ADAPTER * adapter,
+ DWORD dio_address )
+{
+ ADAPTER_HANDLE adapter_handle = adapter->adapter_handle;
+ WORD sif_dio_adr = adapter->sif_adr;
+ WORD sif_dio_adrx = adapter->sif_adx;
+
+ /*
+ * Load extended DIO address register with top 16 bits of address.
+ * Always load extended address register first.
+ */
+
+ sys_outsw(
+ adapter_handle,
+ sif_dio_adrx,
+ (WORD)(dio_address >> 16));
+
+ /*
+ * Load DIO address register with low 16 bits of address.
+ */
+
+ sys_outsw(
+ adapter_handle,
+ sif_dio_adr,
+ (WORD)(dio_address & 0x0000FFFF));
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| LOCAL PROCEDURES
+|
+---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------
+|
+| hwi_pci2_read_node_address
+| ==========================
+|
+| The hwi_pci2_read_node_address routine reads in the node address from
+| the SEEPROM, and checks that it is a valid Madge node address.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_pci2_read_node_address)
+#endif
+
+local WBOOLEAN
+hwi_pci2_read_node_address(
+ ADAPTER * adapter
+ )
+{
+ WORD temp;
+
+ temp = hwi_at24_read_a_word(adapter, PCIT_EEPROM_BIA_WORD0);
+ adapter->permanent_address.byte[0] = (BYTE) ((temp ) & 0x00ff);
+ adapter->permanent_address.byte[1] = (BYTE) ((temp >> 8) & 0x00ff);
+
+ temp = hwi_at24_read_a_word(adapter, PCIT_EEPROM_BIA_WORD1);
+ adapter->permanent_address.byte[2] = (BYTE) ((temp ) & 0x00ff);
+ adapter->permanent_address.byte[3] = (BYTE) ((temp >> 8) & 0x00ff);
+
+ temp = hwi_at24_read_a_word(adapter, PCIT_EEPROM_BIA_WORD2);
+ adapter->permanent_address.byte[4] = (BYTE) ((temp ) & 0x00ff);
+ adapter->permanent_address.byte[5] = (BYTE) ((temp >> 8) & 0x00ff);
+
+ return TRUE;
+}
+
+/***************************************************************************
+* *
+* Local routines for accessing the AT93AT24 Serial EEPROM, this is the same*
+* EEPROM fitted to the PNP card and the PCI 2 card. *
+* *
+* The routines are 'nicked' from the PCI-T card with just write_bits and *
+* input having been changed to reflect I/O through I/O space not PCI config*
+* space. *
+* *
+***************************************************************************/
+
+local void hwi_at24_delay( ADAPTER * adapter );
+local void hwi_at24_set_clk( ADAPTER * adapter );
+local void hwi_at24_clr_clk( ADAPTER * adapter );
+local void hwi_at24_twitch_clk( ADAPTER * adapter );
+local void hwi_at24_start_bit( ADAPTER * adapter );
+local void hwi_at24_stop_bit( ADAPTER * adapter );
+local WBOOLEAN hwi_at24_wait_ack( ADAPTER * adapter );
+local WBOOLEAN hwi_at24_dummy_wait_ack( ADAPTER * adapter );
+
+
+/************************************************************************
+ * Read the 3 EEPROM bits
+ *
+ * Inputs : Adapter structure.
+ *
+ * Outputs : Value read from control register.
+ ***********************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_input)
+#endif
+
+local BYTE hwi_at24_input(ADAPTER * adapter)
+{
+ BYTE bInput;
+
+ bInput = sys_insb(
+ adapter->adapter_handle,
+ (WORD) (adapter->io_location + PCI2_SEEPROM_CONTROL));
+
+ /*
+ * Store the 5 bits which don't interrest us
+ */
+
+ bEepromByteStore = bInput & (BYTE)0xF8;
+
+ return bInput;
+}
+
+
+/************************************************************************
+ * Write to the 3 EEPROM bits
+ *
+ * Inputs : Adapter structure.
+ * The data to be written.
+ *
+ * Outputs : None.
+ ***********************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_write_bits)
+#endif
+
+local void hwi_at24_write_bits(ADAPTER * adapter, BYTE bValue)
+{
+ BYTE bTemp;
+
+ /*
+ * Restore the 5 bits we were not interested in from the previous read
+ */
+
+ bTemp |= bEepromByteStore;
+
+ sys_outsb(
+ adapter->adapter_handle,
+ (WORD) (adapter->io_location + PCI2_SEEPROM_CONTROL),
+ bValue);
+}
+
+
+/************************************************************************
+ *
+ * Write to the three EEPROM bits.
+ *
+ * We have to store the DATA bit as we cannot definately read it back.
+ *
+ * Inputs : Adapter structure.
+ * The data to be written.
+ *
+ * Outputs : None.
+ ***********************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_output)
+#endif
+
+local void hwi_at24_output(ADAPTER * adapter, BYTE bValue)
+{
+ bLastDataBit = bValue & (BYTE)AT24_IO_DATA;
+
+ hwi_at24_write_bits(adapter, bValue);
+}
+
+
+/************************************************************************
+ *
+ * Write to the three EEPROM bits.
+ *
+ * Set the DATA bit to the most recent written bit.
+ *
+ * Inputs : Adapter structure.
+ * The data to be written.
+ *
+ * Outputs : None.
+ ***********************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_output_preserve_data)
+#endif
+
+local void hwi_at24_output_preserve_data(ADAPTER * adapter, BYTE bValue)
+{
+ bValue &= ~AT24_IO_DATA;
+
+ bValue |= bLastDataBit;
+
+ hwi_at24_write_bits(adapter, bValue);
+}
+
+
+/************************************************************************
+ * Delay to allow for serial device timing issues
+ *
+ * Inputs : Adapter structure
+ *
+ * Outputs : None
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_delay)
+#endif
+
+local void hwi_at24_delay(ADAPTER * adapter)
+{
+ UINT i;
+
+ for (i = 0; i < 100; i++)
+ {
+ sys_insb(adapter->adapter_handle, adapter->io_location);
+ }
+}
+
+
+/************************************************************************
+ * Set the serial device clock bit
+ *
+ * Inputs : Adapter structure
+ *
+ * Outputs : None
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_set_clk)
+#endif
+
+local void hwi_at24_set_clk(ADAPTER * adapter)
+{
+ BYTE temp;
+
+ temp = hwi_at24_input(adapter);
+ temp |= AT24_IO_CLOCK;
+
+ hwi_at24_output_preserve_data(adapter, temp);
+}
+
+
+/************************************************************************
+ *
+ * Clears the serial device clock bit
+ *
+ * Inputs : Adapter structure
+ *
+ * Outputs : None
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_clr_clk)
+#endif
+
+local void hwi_at24_clr_clk(ADAPTER * adapter)
+{
+ BYTE temp;
+
+ temp = hwi_at24_input(adapter);
+ temp &= ~AT24_IO_CLOCK;
+
+ hwi_at24_output_preserve_data(adapter, temp);
+
+ return;
+}
+
+/************************************************************************
+*
+* hwi_at24_read_data
+* Read a data bit from the serial EEPROM. It is assumed that the clock is low
+* on entry to this routine. The data bit is forced high to allow access to
+* the data from the EEPROM, then the clock is toggled, with a read of the
+* data in the middle.
+*
+* Beware! The latched data bit will be set on exit.
+*
+************************************************************************/
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_read_data)
+#endif
+
+local BYTE hwi_at24_read_data(ADAPTER * adapter)
+{
+ BYTE bData;
+
+ /*
+ * Set the latched data bit to disconnect us from the data line.
+ */
+
+ bData = AT24_IO_ENABLE | AT24_IO_DATA;
+
+ hwi_at24_output(adapter, bData);
+
+ /*
+ * Set the clk bit to enable the data line.
+ */
+
+ hwi_at24_set_clk(adapter);
+
+ /*
+ * Read the data bit.
+ */
+
+ bData = hwi_at24_input(adapter);
+
+ /*
+ * Get the Data bit into bit 0.
+ */
+
+ bData &= AT24_IO_DATA;
+ bData >>= 1;
+
+ /*
+ * Clear clock again.
+ */
+
+ hwi_at24_clr_clk(adapter);
+
+ return bData;
+}
+
+/************************************************************************
+*
+* hwi_at24_write_data
+*
+* Write a data bit to the serial EEPROM. No clock toggle is performed.
+*
+************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_write_data)
+#endif
+
+local void hwi_at24_write_data(ADAPTER * adapter, BYTE bData)
+{
+ BYTE bTemp;
+
+ /*
+ * The bit value is in position 0, get it into position 1
+ */
+
+ bData <<= 1;
+
+ /*
+ * Not strictly neccessary, but I'm paranoid.
+ */
+
+ bData &= AT24_IO_DATA;
+
+ bTemp = hwi_at24_input(adapter);
+ bTemp &= ~AT24_IO_DATA;
+
+ bTemp |= bData;
+ hwi_at24_output(adapter, bTemp);
+}
+
+
+/************************************************************************
+ *
+ * hwi_at24_enable_eeprom
+ *
+ * Must be called at the start of eeprom access to ensure we can pull low
+ * the data and clock pins on the EEPROM. Forces the clock signal low, as part
+ * of the strategy of routines assuming the clock is low on entry to them.
+ *
+ * Inputs : Adapter structure
+ *
+ * Outputs : None
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_enable_eeprom)
+#endif
+
+local void hwi_at24_enable_eeprom(ADAPTER * adapter)
+{
+ BYTE temp;
+
+ temp = hwi_at24_input(adapter);
+ temp |= AT24_IO_ENABLE;
+
+ hwi_at24_output(adapter, temp);
+}
+
+
+/************************************************************************
+ *
+ * hwi_at24_start_bit
+ *
+ * Send a "START bit" to the serial EEPROM. This involves toggling the
+ * clock bit low to high, with data set on the rising edge and cleared on the
+ * falling edge. Assumes clock is low and EEPROM enabled on entry.
+ *
+ * Inputs : Adapter structure
+ *
+ * Outputs : None
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_start_bit)
+#endif
+
+local void hwi_at24_start_bit(ADAPTER * adapter)
+{
+ BYTE bData;
+
+ bData = AT24_IO_ENABLE | AT24_IO_DATA;
+
+ /*
+ * Set the Data bit
+ */
+
+ hwi_at24_output(adapter, bData);
+ hwi_at24_set_clk(adapter);
+
+ /*
+ * Clear the Data bit.
+ */
+
+ bData = AT24_IO_ENABLE | AT24_IO_CLOCK;
+ hwi_at24_output(adapter, bData);
+ hwi_at24_clr_clk(adapter);
+}
+
+
+/************************************************************************
+ *
+ * hwi_at24_stop_bit
+ *
+ * Send a "STOP bit" to the serial EEPROM. This involves toggling the
+ * clock bit low to high, with data clear on the rising edge and set on the
+ * falling edge. Assumes clock is low and EEPROM enabled on entry.
+ * Inputs : Adapter structure
+ *
+ * Outputs : None
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_stop_bit)
+#endif
+
+local void hwi_at24_stop_bit(ADAPTER * adapter)
+{
+ BYTE bData;
+
+ bData = AT24_IO_ENABLE;
+
+ /*
+ * Clear the Data Bit
+ */
+
+ hwi_at24_output(adapter, bData);
+ hwi_at24_set_clk(adapter);
+
+ /*
+ * Set the Data Bit.
+ */
+
+ bData |= (AT24_IO_DATA | AT24_IO_CLOCK);
+ hwi_at24_output(adapter, bData);
+ hwi_at24_clr_clk(adapter);
+}
+
+
+/************************************************************************
+ *
+ * hwi_at24_wait_ack
+ *
+ * Wait for an ack from the EEPROM.
+ * Outputs : TRUE or FALSE
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_wait_ack)
+#endif
+
+local WBOOLEAN hwi_at24_wait_ack(ADAPTER * adapter)
+{
+ WBOOLEAN Acked = FALSE;
+ UINT i;
+ BYTE bData;
+
+ for (i = 0; i < 10; i++)
+ {
+ bData = hwi_at24_read_data(adapter);
+ bData &= 1;
+
+ if (!bData)
+ {
+ Acked = TRUE;
+ break;
+ }
+ }
+
+ return Acked;
+}
+
+
+/************************************************************************
+ *
+ * hwi_at24_dummy_wait_ack
+ *
+ * Wait for a negative ack from the EEPROM.
+ *
+ * Outputs : TRUE or FALSE
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_dummy_wait_ack)
+#endif
+
+local WBOOLEAN hwi_at24_dummy_wait_ack(ADAPTER * adapter)
+{
+ WBOOLEAN Acked = FALSE;
+ UINT i;
+ BYTE bData;
+
+ for (i = 0; i < 10; i++)
+ {
+ bData = hwi_at24_read_data(adapter);
+
+ if (bData & 1)
+ {
+ Acked = TRUE;
+ break;
+ }
+ }
+
+ return Acked;
+}
+
+
+/************************************************************************
+ *
+ * hwi_at24_serial_read_bits
+ *
+ * Read a Byte from the serial EEPROM.
+ *
+ * NB This routine gets 8 bits from the EEPROM, but relies upon commands
+ * having been sent to the EEPROM 1st. In order to read a byte use
+ * hwi_at24_receive_data.
+ *
+ * Outputs : None
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_serial_read_bits)
+#endif
+
+local BYTE hwi_at24_serial_read_bits(ADAPTER * adapter)
+{
+ BYTE bData = 0;
+ BYTE bBit;
+ UINT i;
+
+ for (i = 0; i < 8; i++)
+ {
+ /*
+ * The EEPROM clocks data out MSB first.
+ */
+
+ bBit = hwi_at24_read_data(adapter);
+ bData <<= 1;
+ bData |= bBit;
+ }
+
+ return bData;
+}
+
+/************************************************************************
+ *
+ * hwi_at24_serial_write_bits
+ *
+ * Send 8 bits to the serial EEPROM.
+ *
+ * Outputs : None
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_serial_write_bits)
+#endif
+
+local void hwi_at24_serial_write_bits(ADAPTER * adapter, BYTE bData)
+{
+ BYTE bBit;
+ UINT i;
+
+ for (i = 0; i < 8; i++)
+ {
+ bBit = (BYTE)(bData >> (7-i));
+ bBit &= 1;
+ hwi_at24_write_data(adapter, bBit);
+
+ /*
+ * Toggle the clock line to pass the data to the device.
+ */
+
+ hwi_at24_set_clk(adapter);
+ hwi_at24_clr_clk(adapter);
+ }
+}
+
+
+/************************************************************************
+ *
+ * hwi_at24_serial_send_cmd
+ *
+ * Send a command to the serial EEPROM.
+ *
+ * Outputs : TRUE if sent OK
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_serial_send_cmd)
+#endif
+
+local WBOOLEAN hwi_at24_serial_send_cmd(ADAPTER * adapter, BYTE bCommand)
+{
+ UINT i = 0;
+ WBOOLEAN Sent = FALSE;
+
+ while ((i < 40) && (Sent == FALSE))
+ {
+ i++;
+
+ /*
+ * Wake the device up.
+ */
+
+ hwi_at24_start_bit(adapter);
+ hwi_at24_serial_write_bits(adapter, bCommand);
+
+ Sent = hwi_at24_wait_ack(adapter);
+ }
+
+ return Sent;
+}
+
+
+/************************************************************************
+ *
+ * hwi_at24_serial_send_cmd_addr
+ *
+ * Send a command and address to the serial EEPROM.
+ *
+ * Outputs : TRUE if sent OK
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_serial_send_cmd_addr)
+#endif
+
+local WBOOLEAN
+hwi_at24_serial_send_cmd_addr(ADAPTER * adapter, BYTE bCommand, BYTE bAddr)
+{
+ WBOOLEAN RetCode;
+
+ RetCode = hwi_at24_serial_send_cmd(adapter, bCommand);
+
+ if (RetCode)
+ {
+ hwi_at24_serial_write_bits(adapter, bAddr);
+
+ RetCode = hwi_at24_wait_ack(adapter);
+ }
+
+ return RetCode;
+}
+
+
+/************************************************************************
+ *
+ * hwi_at24_serial_receive_data
+ *
+ * Having set up the address we want to read from, read the data.
+ *
+ * Outputs : Data read back.
+ *
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_serial_receive_data)
+#endif
+
+local BYTE hwi_at24_serial_receive_data(ADAPTER * adapter)
+{
+ BYTE bData;
+ WBOOLEAN Acked;
+
+ bData = hwi_at24_serial_read_bits(adapter);
+
+ Acked = hwi_at24_dummy_wait_ack(adapter);
+
+ if (!Acked)
+ {
+ bData = 0xFF;
+ }
+
+ return bData;
+
+}
+
+/************************************************************************
+ *
+ * hwi_at24_serial_read_byte
+ *
+ * Read a byte of data from the specified ROM address
+ *
+ * Outputs : Data read back.
+ *
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_serial_read_byte)
+#endif
+
+local BYTE hwi_at24_serial_read_byte(ADAPTER * adapter, BYTE bAddr)
+{
+ BYTE bData;
+
+ hwi_at24_enable_eeprom(adapter);
+
+ /*
+ * Send the serial device a dummy WRITE command
+ * that contains the address of the byte we want to
+ * read !
+ */
+
+ hwi_at24_serial_send_cmd_addr(adapter, AT24_WRITE_CMD, bAddr);
+
+ /*
+ * Send the read command
+ */
+
+ hwi_at24_serial_send_cmd(adapter, AT24_READ_CMD);
+
+ /*
+ * Read the data
+ */
+
+ bData = hwi_at24_serial_receive_data(adapter);
+
+ /*
+ * Deselect the EEPROM
+ */
+
+ hwi_at24_stop_bit(adapter);
+
+ return bData;
+
+}
+
+
+/************************************************************************
+ *
+ * hwi_at24_read_a_word
+ *
+ * Read a word of data from the specified ROM address
+ *
+ * Outputs : Data read back.
+ *
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_read_a_word)
+#endif
+
+local WORD hwi_at24_read_a_word(ADAPTER * adapter, WORD word_address)
+{
+ WORD wData;
+ BYTE bLoByte;
+ BYTE bByteAddress = (BYTE)((word_address * 2)&0xFF);
+
+ bLoByte = hwi_at24_serial_read_byte(adapter, bByteAddress);
+
+ wData = (WORD) hwi_at24_serial_read_byte(
+ adapter,
+ (BYTE)(bByteAddress + 1));
+
+ wData <<= 8;
+ wData |= bLoByte;
+
+ return wData;
+}
+
+#endif
+
+
+/******* End of HWI_PCI2.C **************************************************/
diff --git a/private/ntos/ndis/madge/driver/hwi_pcit.c b/private/ntos/ndis/madge/driver/hwi_pcit.c
new file mode 100644
index 000000000..fee338a22
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/hwi_pcit.c
@@ -0,0 +1,2028 @@
+/****************************************************************************
+*
+* HWI_PCIT.C : Part of the FASTMAC TOOL-KIT (FTK)
+*
+* HARDWARE INTERFACE MODULE FOR PCI CARDS
+*
+* Copyright (c) Madge Networks Ltd. 1994
+*
+* COMPANY CONFIDENTIAL
+*
+*
+*****************************************************************************
+*
+* The purpose of the Hardware Interface (HWI) is to supply an adapter card
+* independent interface to any driver. It performs nearly all of the
+* functions that involve affecting SIF registers on the adapter cards.
+* This includes downloading code to, initializing, and removing adapters.
+*
+* The HWI_PCIT.C module contains the routines specific to the Smart 16/4 PCI(T)
+* based on the TI PCI ASIC, this card supports PSEUDO DMA, and BUs master DMA.
+*
+* The second spin of the Ti ASIC had a problem where it was not possible to do
+* DIO and DMA at the same time. Version 1.36 of FastMac plus had an interlock
+* put into it to prevent these happening @ the same time. FastMAC however
+* must be used in PIO mode. More details on the interlocking is found
+* at the top of hwi_pcit_interrupt
+*
+*****************************************************************************
+
+/*---------------------------------------------------------------------------
+|
+| DEFINITIONS
+|
+---------------------------------------------------------------------------*/
+
+#define PCI_PCIT_DEVICE_ID 4
+
+#include "ftk_defs.h"
+
+#define COLOUR_BLACK 0x00
+#define COLOUR_BLUE 0x10
+#define COLOUR_GREEN 0x20
+#define COLOUR_CYAN 0x30
+#define COLOUR_RED 0x40
+#define COLOUR_MAGENTA 0x50
+#define COLOUR_YELLOW 0x60
+#define COLOUR_WHITE 0x70
+
+
+/*---------------------------------------------------------------------------
+|
+| MODULE ENTRY POINTS
+|
+---------------------------------------------------------------------------*/
+
+#include "ftk_intr.h" /* routines internal to FTK */
+#include "ftk_extr.h" /* routines provided or used by external FTK user */
+
+BYTE bEepromByteStore;
+BYTE bLastDataBit;
+
+#ifndef FTK_NO_PCIT
+
+/*---------------------------------------------------------------------------
+|
+| LOCAL PROCEDURES
+|
+---------------------------------------------------------------------------*/
+
+local WBOOLEAN
+hwi_pcit_read_node_address(
+ ADAPTER * adapter
+ );
+
+local WORD
+hwi_at24_read_a_word(
+ ADAPTER * adapter,
+ WORD word_address
+ );
+
+
+#ifndef FTK_NO_PROBE
+
+/****************************************************************************
+*
+* hwi_pcit_probe_card
+* ==================
+*
+*
+* PARAMETERS (passed by hwi_probe_adapter) :
+* ==========================================
+*
+* PROBE * resources
+*
+* resources is an array structures used to identify and record specific
+* information about adapters found.
+*
+* UINT length
+*
+* length is the number of structures pointed to by reources.
+*
+* WORD * valid_locations
+*
+* valid_locations is normally an array of IO locations to examine for the
+* presence of an adapter. However for PCI adapters the io location is read
+* from the BIOS, so this array can remain empty.
+*
+* UINT number_locations
+*
+* This is the number of IO locations in the above list.
+*
+* BODY :
+* ======
+*
+* The hwi_pcit_probe_card routine is called by hwi_probe_adapter. It
+* reads the id registers to find the type of card and also reads the IRQ.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine returns the number of adapters found, or PROBE_FAILURE if
+* there's a problem.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_pcit_probe_card)
+#endif
+
+export UINT
+hwi_pcit_probe_card(
+ PROBE * Resources,
+ UINT NumberOfResources,
+ WORD * IOMask,
+ UINT NumberIO
+ )
+{
+ WORD i;
+ WORD Handle;
+
+ if (!sys_pci_valid_machine())
+ {
+ return 0;
+ }
+
+ for (i=0;i<NumberOfResources;i++)
+ {
+ if (!sys_pci_find_card(&Handle, i,PCI_PCIT_DEVICE_ID))
+ {
+ break;
+ }
+
+ Resources[i].pci_handle = Handle;
+ Resources[i].adapter_card_bus_type = ADAPTER_CARD_TI_PCI_BUS_TYPE;
+
+ if (!sys_pci_get_io_base(Handle, &(Resources[i].io_location)))
+ {
+ return PROBE_FAILURE;
+ }
+
+ if (!sys_pci_get_irq(Handle, &(Resources[i].interrupt_number)))
+ {
+ return PROBE_FAILURE;
+ }
+
+ /*
+ * We can't read the memory size from the serial EEPROM until the
+ * hwi_pcit_install_card function is called.
+ */
+
+ Resources[i].adapter_ram_size = 512;
+
+ Resources[i].adapter_card_type = ADAPTER_CARD_TYPE_16_4_PCIT;
+
+#ifdef FMPLUS
+ Resources[i].transfer_mode = PIO_DATA_TRANSFER_MODE;
+/* Resources[i].transfer_mode = DMA_DATA_TRANSFER_MODE;*/
+#else
+ Resources[i].transfer_mode = PIO_DATA_TRANSFER_MODE;
+#endif
+
+ }
+
+ return i;
+}
+
+#endif
+
+
+/****************************************************************************
+*
+* hwi_pcit_install_card
+* ====================
+*
+*
+* PARAMETERS (passed by hwi_install_adapter) :
+* ============================================
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+* DOWNLOAD_IMAGE * download_image
+*
+* This is the code to be downloaded to the adapter. The image must be of
+* the correct type i.e. must be downloadable into the adapter. If the
+* pointer is 0 downloading is not done.
+*
+*
+* BODY :
+* ======
+*
+* hwi_pcit_install_card is called by hwi_install_adapter. It sets up
+* the adapter card and downloads the required code to it. Firstly, it
+* checks there is a valid adapter at the required IO address by reading
+* the node address from the BIA PROM. It then sets up and checks various
+* on-board registers for correct operation.
+*
+* Then, it halts the EAGLE, downloads the code, restarts the EAGLE and
+* waits up to 3 seconds for a valid bring-up code. If interrupts are
+* required, these are enabled by operating system specific calls.
+* The adapter is set up for Eagle Pseudo-DMA, since real DMA is not used.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine returns TRUE if it succeeds. If this routine fails (returns
+* FALSE) then a subsequent call to driver_explain_error, with the adapter
+* handle corresponding to the adapter parameter used here, will give an
+* explanation.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_pcit_install_card)
+#endif
+
+export WBOOLEAN
+hwi_pcit_install_card(
+ ADAPTER * adapter,
+ DOWNLOAD_IMAGE * download_image
+ )
+{
+ ADAPTER_HANDLE adapter_handle = adapter->adapter_handle;
+ WORD sif_base;
+ WORD ring_speed;
+ WORD wControlReg;
+ WORD wBrokenDMA;
+ BYTE bCache;
+#ifdef FMPLUS
+ DWORD dwHandShakeAddress;
+#endif
+
+ /*
+ * These things can all be assumed for the Ti PCI Card.
+ */
+
+ adapter->adapter_card_type = ADAPTER_CARD_TYPE_16_4_PCIT;
+ adapter->adapter_card_revision = ADAPTER_CARD_16_4_PCIT;
+ adapter->edge_triggered_ints = FALSE;
+
+ /*
+ * Start off by assuming we will use pseudo DMA.
+ */
+
+ adapter->EaglePsDMA = TRUE;
+
+ /*
+ * Save IO locations of SIF registers.
+ */
+
+ sif_base = adapter->io_location;
+
+ adapter->sif_dat = sif_base + EAGLE_SIFDAT;
+ adapter->sif_datinc = sif_base + EAGLE_SIFDAT_INC;
+ adapter->sif_adr = sif_base + EAGLE_SIFADR;
+ adapter->sif_int = sif_base + EAGLE_SIFINT;
+ adapter->sif_acl = sif_base + EAGLE_SIFACL;
+ adapter->sif_adx = sif_base + EAGLE_SIFADX;
+ adapter->sif_dmalen = sif_base + EAGLE_DMALEN;
+ adapter->sif_sdmadat = sif_base + EAGLE_SDMADAT;
+ adapter->sif_sdmaadr = sif_base + EAGLE_SDMAADR;
+ adapter->sif_sdmaadx = sif_base + EAGLE_SDMAADX;
+
+ adapter->io_range = SIF_IO_RANGE;
+
+ /*
+ * If we are supposed to use DMA then enable it.
+ */
+
+ if (adapter->transfer_mode == DMA_DATA_TRANSFER_MODE)
+ {
+ adapter->EaglePsDMA = FALSE;
+
+ /*
+ * Does this card have a 'broken' DMA ASIC ??
+ * Read the HW features 2 to find out.
+ */
+
+ wBrokenDMA = hwi_at24_read_a_word(adapter, PCIT_EEPROM_HWF2);
+ if (wBrokenDMA == PCIT_BROKEN_DMA)
+ {
+#ifdef FMPLUS
+ adapter->mc32_config = TRN_PCIT_BROKEN_DMA;
+#else
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_17_BAD_TRANSFER_MODE;
+ return FALSE;
+#endif
+ }
+ else
+ {
+ adapter->mc32_config = 0;
+ }
+ }
+ else
+ {
+ /*
+ * If we've using pseudo DMA then we need a software handshake.
+ */
+ adapter->mc32_config = MC_AND_ISACP_USE_PIO;
+ }
+
+ /*
+ * The Command word of the PCI config space must be set to 7 i.e.
+ * we support BUS MASTER DMA. Some BIOS' don't do this. The Ti ASIC
+ * refuses to let this field be set to 3 which some BIOS's do this is
+ * turned into 0 by the Ti ASIC.
+ */
+
+ sys_pci_write_config_byte(
+ adapter_handle,
+ PCI_CONFIG_COMMAND,
+ PCI_CONFIG_BUS_MASTER_ENABLE |
+ PCI_CONFIG_IO_ENABLE |
+ PCI_CONFIG_MEM_ENABLE);
+
+
+ /*
+ *
+ * Since the BIOS may have failed to set the card up correctly as a result of
+ * the above problem, it may have got the Latency timer (offset 0Dh) and
+ * cache line size (offset 0Ch) bytes wrong too. The only observed erroneous
+ * values (Compaq Deskpro XL 466) are F8h and FFh respectively (all bits set
+ * that can be set).
+ *
+ * The latency timer is not particularly important, and can safely be left at
+ * F8h.
+ *
+ * A cache line size of FFh causes DMA problems and is changed to 20h.
+ *
+ */
+
+ sys_pci_read_config_byte(adapter_handle, CACHE_LINE_SIZE, &bCache);
+
+ if (bCache == 0xFF)
+ {
+ sys_pci_write_config_byte(
+ adapter_handle,
+ CACHE_LINE_SIZE,
+ 0x20
+ );
+ }
+
+ /*
+ * Set up the Miscellanous Control Register, we only need to modify the
+ * top word.
+ */
+
+ sys_pci_read_config_word(
+ adapter_handle,
+ MISC_CONT_REG + 2,
+ &wControlReg);
+
+#if 0
+ wControlReg &= 0xE4;
+ wControlReg |= 0x4;
+#else
+ /*
+ * A fix to the DMA bug, we now clear bit 18 rather than setting it
+ * (Slight lie this was not really a fix, but J.M. thinks leave it
+ * in as it does no harm. M.D. & P.R. disagree )
+ */
+ wControlReg &= 0xE0;
+#endif
+
+ sys_pci_write_config_word(
+ adapter_handle,
+ MISC_CONT_REG + 2,
+ wControlReg);
+
+ /*
+ * Can't RESET the Eagle as this does not work
+ */
+
+ if (!hwi_pcit_read_node_address(adapter))
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_05_ADAPTER_NOT_FOUND;
+ return FALSE;
+ }
+
+ ring_speed = hwi_at24_read_a_word(adapter, PCIT_EEPROM_RING_SPEED);
+
+ /*
+ * Get the amount of RAM from the serial EEPROM (in units of 128k).
+ */
+
+ adapter->adapter_ram_size = hwi_at24_read_a_word(
+ adapter,
+ PCIT_EEPROM_RAM_SIZE) * 128;
+
+ /*
+ * Set the ring speed. If the user has specified a value then we will
+ * use that, otherwise we will use the value read from the EEPROM.
+ */
+
+ if (adapter->set_ring_speed == 16)
+ {
+ adapter->nselout_bits = NSEL_16MBITS;
+ }
+ else if (adapter->set_ring_speed == 4)
+ {
+ adapter->nselout_bits = NSEL_4MBITS;
+ }
+ else if (ring_speed == PCIT_EEPROM_4MBITS)
+ {
+ adapter->nselout_bits = NSEL_4MBITS;
+ }
+ else
+ {
+ adapter->nselout_bits = NSEL_16MBITS;
+ }
+
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ /*
+ * Halt the Eagle prior to downloading the MAC code - this will also
+ * write the interrupt bits into the SIFACL register, where the MAC can
+ * find them.
+ */
+
+ hwi_halt_eagle(adapter);
+
+ /*
+ * Download code to adapter.
+ * View download image as a sequence of download records.
+ * Pass address of routine to set up DIO addresses on PCI cards.
+ * If routine fails return failure (error record already filled in).
+ */
+
+ if (!hwi_download_code(
+ adapter,
+ (DOWNLOAD_RECORD *) download_image,
+ hwi_pcit_set_dio_address))
+ {
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+
+
+ /*
+ * Restart the Eagle to initiate bring up diagnostics.
+ */
+
+ hwi_start_eagle(adapter);
+
+ /*
+ * Wait for a valid bring up code, may wait 3 seconds.
+ */
+
+ if (!hwi_get_bring_up_code(adapter))
+ {
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+
+ /*
+ * Set DIO address to point to EAGLE DATA page 0x10000L.
+ */
+
+ hwi_pcit_set_dio_address(adapter, DIO_LOCATION_EAGLE_DATA_PAGE);
+
+ /*
+ * Get the ring speed, from the Eagle DIO space.
+ */
+
+ adapter->ring_speed = hwi_get_ring_speed(adapter);
+
+ /*
+ * Set maximum frame size from the ring speed.
+ */
+
+ adapter->max_frame_size = hwi_get_max_frame_size(adapter);
+
+ /*
+ * If not in polling mode then set up interrupts.
+ * interrupts_on field is used when disabling interrupts for adapter.
+ */
+
+ if (adapter->interrupt_number != POLLING_INTERRUPTS_MODE)
+ {
+ adapter->interrupts_on = sys_enable_irq_channel(
+ adapter_handle,
+ adapter->interrupt_number);
+
+ if (!adapter->interrupts_on)
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_0B_FAIL_IRQ_ENABLE;
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+ }
+ else
+ {
+ adapter->interrupts_on = TRUE;
+ }
+
+ /*
+ * Pass the address to be used for the 'broken' DMA handshake to the
+ * adapter.
+ */
+
+#ifdef FMPLUS
+
+ if (adapter->mc32_config == TRN_PCIT_BROKEN_DMA)
+ {
+ sys_outsw(
+ adapter_handle,
+ adapter->sif_adr,
+ DIO_LOCATION_DMA_POINTER);
+
+ dwHandShakeAddress = adapter->dma_test_buf_phys
+ + SCB_TEST_PATTERN_LENGTH
+ + SSB_TEST_PATTERN_LENGTH;
+
+ /*
+ * We have to Output this address LSW first;
+ */
+
+ sys_outsw(
+ adapter_handle,
+ adapter->sif_datinc,
+ (WORD) (dwHandShakeAddress & 0xFFFF));
+
+ sys_outsw(
+ adapter_handle,
+ adapter->sif_datinc,
+ (WORD) ((dwHandShakeAddress & 0xFFFF0000) >> 16));
+
+
+ }
+
+#endif
+
+
+ /*
+ * Return successfully.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+
+ return TRUE;
+}
+
+
+/****************************************************************************
+*
+* hwi_pcit_interrupt_handler
+* =========================
+*
+*
+* PARAMETERS (passed by hwi_interrupt_entry) :
+* ==========================================
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+*
+* BODY :
+* ======
+*
+* The hwi_pcit_interrupt_handler routine is called, when an interrupt
+* occurs, by hwi_interrupt_entry. It checks to see if a particular card
+* has interrupted. The interrupt could be generated by the SIF for either
+* a PIO data transfer or a normal condition (received frame, SRB complete,
+* ARB indication etc). Note it could in fact be the case that no interrupt
+* has occured on the particular adapter being checked.
+*
+* On normal SIF interrupts, the interrupt is acknowledged and cleared. The
+* value in the SIF interrupt register is recorded in order to pass it to
+* the driver_interrupt_entry routine (along with the adapter details).
+*
+* On PseudoDMA interrupts, the length, direction and physical address of
+* the transfer is determined. A system provided routine is called to do
+* the data transfer itself.
+*
+* The Second spin of the Ti ASIC has some problems such that no access to SIF
+* registers can occur safely during a DMA.
+*
+* If the Broken DMA bit was set in the HW features 2 the we need the following
+* mechanism.
+*
+* - The card wishes to do a DMA
+* - The card sets the handshake word to 1111h
+* - The card sets the SIF interrupt bit in the SIFINT register
+* - The host interrupt routine is entered
+* - The host notices it is a SIF interrupt and it is a special SIF
+* interrupt since the handshake word is 1111h
+* - The host clears the handshake word
+* - ... which the card has been waiting for
+* - The card performs the DMA transfer
+* - The card does an extra, single byte, DMA transfer to a flag in
+* the adapter structure on the host, of data 11h
+* - ... which the host has been waiting for
+* - The host resets the transfer flag to its previous value
+* - The host EOIs the interrupt and leaves the interrupt routine
+*
+* The handshake word off the adapter which tells us the following:
+*
+* 0000 => Normal SIF interrupt.
+* 1111 => Spin whilst DMA completes.
+* 2222 => As for 1111 but this hints that a SIF interrupt may follow very soon
+* after the DMA, hence poll for this.
+*
+* RETURNS :
+* =========
+*
+* The routine always successfully completes.
+*
+****************************************************************************/
+
+local BYTE
+hwi_pcit_read_byte(
+ BYTE FAR * ptr
+ );
+
+#ifdef FTK_IRQ_FUNCTION
+#pragma FTK_IRQ_FUNCTION(hwi_pcit_read_byte)
+#endif
+
+local BYTE
+hwi_pcit_read_byte(
+ BYTE FAR * ptr
+ )
+{
+ return *ptr;
+}
+
+
+#ifdef FTK_IRQ_FUNCTION
+#pragma FTK_IRQ_FUNCTION(hwi_pcit_interrupt_handler)
+#endif
+
+export void
+hwi_pcit_interrupt_handler(
+ ADAPTER * adapter
+ )
+{
+ ADAPTER_HANDLE adapter_handle = adapter->adapter_handle;
+ WORD sifacl;
+ WORD sifint_value;
+ WORD sifint_tmp;
+ WORD pio_addr_lo;
+ DWORD pio_addr_hi;
+ WORD pio_len_bytes;
+ WORD last_byte;
+ WBOOLEAN pio_from_adapter;
+ WBOOLEAN our_interrupt = FALSE;
+ WBOOLEAN proper_sif_int = FALSE;
+ BYTE FAR * pio_address;
+ WORD saved_sifadr;
+#ifdef FMPLUS
+ BYTE FAR * dma_handshake_addr;
+ WORD dodgy_dma;
+ WORD timeout;
+#endif
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ /*
+ * Check for SIF interrupt or PIO interrupt.
+ */
+
+ /*
+ * Read SIFINT, and then re-read to make sure value is stable.
+ */
+
+ sifint_value = sys_insw(adapter_handle, adapter->sif_int);
+ do
+ {
+ sifint_tmp = sifint_value;
+ sifint_value = sys_insw(adapter_handle, adapter->sif_int);
+ }
+ while (sifint_tmp != sifint_value);
+
+ /*
+ * Given the SIFINT value, we can check one of the bits in it to see
+ * if that is what caused the interrupt.
+ */
+
+ if ((sifint_value & EAGLE_SIFINT_SYSTEM) != 0)
+ {
+
+ /*
+ * It's our interrupt and as far as we can tell it's a real
+ * SIF interrupt.
+ */
+
+ proper_sif_int = TRUE;
+ our_interrupt = TRUE;
+
+#ifdef FMPLUS
+
+ if (adapter->mc32_config == TRN_PCIT_BROKEN_DMA)
+ {
+
+ /*
+ * Preserve SIFADR.
+ */
+
+ saved_sifadr = sys_insw(adapter_handle, adapter->sif_adr);
+
+ /*
+ * Broken DMA is enabled so check if this was a broken
+ * DMA interrupt.
+ */
+
+ sys_outsw(
+ adapter_handle,
+ adapter->sif_adr,
+ DIO_LOCATION_DMA_CONTROL
+ );
+
+ dodgy_dma = sys_insw(adapter_handle, adapter->sif_dat);
+
+ /*
+ * If there is a DMA pending then do some DMA processing.
+ */
+
+ if (dodgy_dma != 0)
+ {
+ /*
+ * This is not a proper SIF interrupt so note the fact.
+ */
+
+ proper_sif_int = FALSE;
+
+ /*
+ * Work out where the handshake byte will be in host
+ * memory.
+ */
+
+ dma_handshake_addr = (BYTE FAR *)
+ adapter->dma_test_buf_virt +
+ SCB_TEST_PATTERN_LENGTH +
+ SSB_TEST_PATTERN_LENGTH;
+
+ /*
+ * Clear EAGLE_SIFINT_HOST_IRQ to acknowledge
+ * interrupt at SIF.
+ */
+
+ sys_outsw(adapter_handle, adapter->sif_int, 0);
+
+ /*
+ * Set the host flag to zero.
+ */
+
+ *dma_handshake_addr = 0;
+
+ /*
+ * Clear the flag on the adapter i.e. start DMA.
+ */
+
+ sys_outsw(adapter_handle, adapter->sif_dat, 0);
+
+ /*
+ * Wait until the adapter puts 0x11 in our flag.
+ */
+
+ while (hwi_pcit_read_byte(dma_handshake_addr) != 0x11)
+ NdisStallExecution(10);
+ }
+
+ /*
+ * Now did the adapter hint that a SIF interrupt will follow
+ * presently.
+ */
+
+ if (dodgy_dma == 0x2222)
+ {
+ /*
+ * Poll For a SIF interrupt - wait for it to stabalise at the
+ * same time.
+ */
+
+ timeout = 0;
+
+ sifint_value = sys_insw(adapter_handle, adapter->sif_int);
+ do
+ {
+ sifint_tmp = sifint_value;
+ sifint_value = sys_insw(adapter_handle, adapter->sif_int);
+
+ if (sifint_value == sifint_tmp &&
+ (sifint_value & EAGLE_SIFINT_SYSTEM) != 0);
+ {
+ proper_sif_int = TRUE;
+ }
+ timeout++;
+ }
+ while (!proper_sif_int && timeout < 40);
+ }
+
+ /*
+ * Restore SIFADR.
+ */
+
+ sys_outsw(
+ adapter_handle,
+ adapter->sif_adr,
+ saved_sifadr);
+
+ }
+#endif
+ }
+
+ /*
+ * Now read the SIFACL register to check for a PseudoDMA interrupt.
+ */
+
+ if (adapter->transfer_mode != DMA_DATA_TRANSFER_MODE)
+ {
+ sifacl = sys_insw(adapter_handle, adapter->sif_acl);
+
+ if ((sifacl & EAGLE_SIFACL_SWHRQ) != 0)
+ {
+ our_interrupt = TRUE;
+
+ /*
+ * Using any PCI card, a software handshake must occur so that the MAC
+ * does not try to initiate another transfer until a point has been reached on
+ * the host at which the transfer has completed. If not, the following could
+ * happen:
+ *
+ * - The host requests the last word/byte of a receive from the card.
+ * - The SIF does not has the data ready.
+ * - Control of the bus is given to a SCSI card.
+ * - It bursts/does nothing in bus master mode for 16 microseconds.
+ * - The data becomes ready early on during these 16 microseconds and
+ * as a result the card software beleives that the transfer has completed.
+ * - The card software continues and sets up another PsDMA transfer.
+ * - The SCSI card finishes, but the PdDMA length is now incorrect and
+ * all is lost.
+ *
+ */
+
+ saved_sifadr = sys_insw(adapter_handle, adapter->sif_adr);
+
+ /*
+ * Set the PIO_HANDSHAKE word to 0
+ */
+
+ sys_outsw(adapter_handle, adapter->sif_adr, DIO_LOCATION_DMA_CONTROL);
+ sys_outsw(adapter_handle, adapter->sif_dat, 0 );
+
+ /*
+ * NB Words must be byte swapped, this is done in the SIF and
+ * then Ti kindly byte swap in their ASIC, so we have to do it again.
+ * Also beacause of a bug in the ASIC byte read/writes don't work
+ * so if the buffer is odd aligned the rep insw/outsw must
+ * mis-aligned on the host. Apparently this causes no performance
+ * loss on the 486 or above.
+ */
+
+ /*
+ * PIO interrupt has occurred. Transfer data to/from adapter.
+ */
+
+ /*
+ * By writing the SWHLDA bit, we "start" the transfer,
+ * causing the SDMA registers to mapped in.
+ */
+
+ macro_setw_bit(
+ adapter_handle,
+ adapter->sif_acl,
+ EAGLE_SIFACL_SWHLDA);
+
+ /*
+ * Determine what direction the data transfer is to take place in.
+ */
+
+ pio_from_adapter = sys_insw(
+ adapter_handle,
+ adapter->sif_acl) & EAGLE_SIFACL_SWDDIR;
+
+ pio_len_bytes = sys_insw(
+ adapter_handle,
+ adapter->sif_dmalen);
+
+ pio_addr_lo = sys_insw(
+ adapter_handle,
+ adapter->sif_sdmaadr);
+
+ pio_addr_hi = (DWORD) sys_insw(
+ adapter_handle,
+ adapter->sif_sdmaadx);
+
+ pio_address = (BYTE FAR *) ((pio_addr_hi << 16) |
+ ((DWORD) pio_addr_lo));
+
+
+ /*
+ * Do the actual data transfer.
+ */
+
+ /*
+ * Note that Fastmac only copies whole WORDs to DWORD boundaries.
+ * FastmacPlus, however, can transfer any length to any address.
+ */
+
+ if (pio_from_adapter)
+ {
+ /*
+ * Transfer into host memory from adapter.
+ */
+
+ sys_rep_swap_insw(
+ adapter_handle,
+ adapter->sif_sdmadat,
+ pio_address,
+ (WORD) (pio_len_bytes >> 1));
+
+
+ if (pio_len_bytes % 2)
+ {
+ /*
+ * Odd length transfer, need to get the last byte, this
+ * is done using an in ax, dx, and the byte is in the top
+ * byte due to byte swapping issues.
+ */
+
+ last_byte = sys_insw(
+ adapter_handle,
+ adapter->sif_sdmadat);
+
+ *(pio_address + pio_len_bytes - 1) = (BYTE)
+ ((last_byte & 0xFF00) >> 8);
+
+ }
+ }
+ else
+ {
+ /*
+ * Transfer into adapter memory from the host.
+ */
+
+ sys_rep_swap_outsw(
+ adapter_handle,
+ adapter->sif_sdmadat,
+ pio_address,
+ (WORD) (pio_len_bytes >> 1));
+
+ if (pio_len_bytes % 2)
+ {
+ /*
+ * Odd length transfer, need to send the last byte, this
+ * is done using by writing a word, with the byte is in
+ * the top byte due to byte swapping issues.
+ */
+
+ last_byte = (WORD) *(pio_address + pio_len_bytes - 1);
+ last_byte <<= 8;
+
+ sys_outsw(
+ adapter_handle,
+ adapter->sif_sdmadat,
+ last_byte);
+ }
+ }
+
+ /*
+ * Wait for SWHLDA to go low, it is not safe to access normal
+ * SIF registers until this is the case.
+ */
+
+ do
+ {
+ sifacl = sys_insw(adapter_handle, adapter->sif_acl);
+ }
+ while (sifacl & EAGLE_SIFACL_SWHLDA);
+
+ /*
+ * Now output 0xFFFF to the PIO_HANDSHAKE word, to signal
+ * the DMA is complete.
+ */
+
+ sys_outsw(adapter_handle, adapter->sif_dat, 0xFFFF );
+
+ /*
+ * Restore the saved SIF address.
+ */
+
+ sys_outsw(adapter_handle, adapter->sif_adr, saved_sifadr);
+ }
+ }
+
+ /*
+ * Does a normal sif_int need processing as opposed to a 'dodgy' DMA
+ * interrupt.
+ */
+
+ if (proper_sif_int)
+ {
+ /*
+ * A SIF interrupt has occurred.
+ * This could be an SRB free, an adapter check or a received
+ * frame interrupt.
+ */
+
+ /*
+ * Clear EAGLE_SIFINT_HOST_IRQ to acknowledge interrupt at SIF.
+ */
+
+ sys_outsw(adapter_handle, adapter->sif_int, 0);
+
+ /*
+ * Call driver with details of SIF interrupt.
+ */
+
+ driver_interrupt_entry(adapter_handle, adapter, sifint_value);
+ }
+
+ if (our_interrupt)
+ {
+
+#ifndef FTK_NO_CLEAR_IRQ
+ sys_clear_controller_interrupt(
+ adapter_handle,
+ adapter->interrupt_number);
+#endif
+
+ }
+
+ /*
+ * Let system know we have finished accessing the IO ports.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+}
+
+
+/****************************************************************************
+*
+* hwi_pcit_remove_card
+* ====================
+*
+*
+* PARAMETERS (passed by hwi_remove_card)
+* ======================================
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+*
+* BODY :
+* ======
+*
+* The hwi_smart16_remove_card routine is called by hwi_remove_adapter. It
+* disables interrupts if they are being used. It also resets the adapter.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine always successfully completes.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(hwi_pcit_remove_card)
+#endif
+
+export void
+hwi_pcit_remove_card(
+ ADAPTER * adapter
+ )
+{
+ ADAPTER_HANDLE adapter_handle = adapter->adapter_handle;
+ WORD wGenConAddr = adapter->io_location +
+ PCI_GENERAL_CONTROL_REG;
+ WORD sifacl;
+
+ /*
+ * Interrupt must be disabled at adapter before unpatching interrupt.
+ * Even in polling mode we must turn off interrupts at adapter.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ sifacl = sys_insw(adapter_handle, adapter->sif_acl);
+ sifacl = (sifacl & ~(EAGLE_SIFACL_PSDMAEN | EAGLE_SIFACL_SINTEN));
+ sys_outsw(adapter_handle, adapter->sif_acl, sifacl);
+
+ if (adapter->interrupts_on)
+ {
+ if (adapter->interrupt_number != POLLING_INTERRUPTS_MODE)
+ {
+ sys_disable_irq_channel(
+ adapter_handle,
+ adapter->interrupt_number);
+ }
+
+ adapter->interrupts_on = FALSE;
+ }
+
+ /*
+ * Can't reset the Eagle as the reset line does not work, lets try
+ * hwi_halt_eagle.
+ */
+
+ hwi_halt_eagle( adapter );
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+}
+
+
+/****************************************************************************
+*
+* hwi_pcit_set_dio_address
+* =======================
+*
+* The hwi_pcit_set_dio_address routine is used, with PCI cards, for
+* putting a 32 bit DIO address into the SIF DIO address and extended DIO
+* address registers. Note that the extended address register should be
+* loaded first.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_pcit_set_dio_address)
+#endif
+
+export void
+hwi_pcit_set_dio_address(
+ ADAPTER * adapter,
+ DWORD dio_address )
+{
+ ADAPTER_HANDLE adapter_handle = adapter->adapter_handle;
+ WORD sif_dio_adr = adapter->sif_adr;
+ WORD sif_dio_adrx = adapter->sif_adx;
+
+ /*
+ * Load extended DIO address register with top 16 bits of address.
+ * Always load extended address register first.
+ */
+
+ sys_outsw(
+ adapter_handle,
+ sif_dio_adrx,
+ (WORD)(dio_address >> 16));
+
+ /*
+ * Load DIO address register with low 16 bits of address.
+ */
+
+ sys_outsw(
+ adapter_handle,
+ sif_dio_adr,
+ (WORD)(dio_address & 0x0000FFFF));
+}
+
+/*---------------------------------------------------------------------------
+|
+| LOCAL PROCEDURES
+|
+---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------
+|
+| hwi_pcit_read_node_address
+| ==========================
+|
+| The hwi_pcit_read_node_address routine reads in the node address from
+| the SEEPROM, and checks that it is a valid Madge node address.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_pcit_read_node_address)
+#endif
+
+local WBOOLEAN
+hwi_pcit_read_node_address(
+ ADAPTER * adapter
+ )
+{
+ WORD temp;
+ temp = hwi_at24_read_a_word(adapter, PCIT_EEPROM_BIA_WORD0);
+ adapter->permanent_address.byte[0] = (BYTE) ((temp ) & 0x00ff);
+ adapter->permanent_address.byte[1] = (BYTE) ((temp >> 8) & 0x00ff);
+
+ temp = hwi_at24_read_a_word(adapter, PCIT_EEPROM_BIA_WORD1);
+ adapter->permanent_address.byte[2] = (BYTE) ((temp ) & 0x00ff);
+ adapter->permanent_address.byte[3] = (BYTE) ((temp >> 8) & 0x00ff);
+
+ temp = hwi_at24_read_a_word(adapter, PCIT_EEPROM_BIA_WORD2);
+ adapter->permanent_address.byte[4] = (BYTE) ((temp ) & 0x00ff);
+ adapter->permanent_address.byte[5] = (BYTE) ((temp >> 8) & 0x00ff);
+
+ return TRUE;
+}
+
+/***************************************************************************
+* *
+* Local routines for accessing the AT93AT24 Serial EEPROM, this is the same*
+* EEPROM fitted to the PNP card and the PCI 2 card. The only difference, is*
+* that for this card the I/O is done through the PCI config space. *
+* *
+***************************************************************************/
+
+local void hwi_at24_delay( ADAPTER * adapter );
+local void hwi_at24_set_clk( ADAPTER * adapter );
+local void hwi_at24_clr_clk( ADAPTER * adapter );
+local void hwi_at24_twitch_clk( ADAPTER * adapter );
+local void hwi_at24_start_bit( ADAPTER * adapter );
+local void hwi_at24_stop_bit( ADAPTER * adapter );
+local WBOOLEAN hwi_at24_wait_ack( ADAPTER * adapter );
+local WBOOLEAN hwi_at24_dummy_wait_ack( ADAPTER * adapter );
+
+
+/************************************************************************
+*
+* Read the EEPROM bits
+*
+* The Data Bit does not always match the previously ouptut value.
+*
+* Inputs : Adapter structure.
+*
+* Outputs : Value read from control register.
+*
+***********************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_input)
+#endif
+
+local BYTE hwi_at24_input( ADAPTER * adapter )
+{
+ BYTE bInput;
+ BYTE bStore;
+
+ sys_pci_read_config_byte(adapter->adapter_handle, EEPROM_OFFSET, &bInput);
+
+ /*
+ * Store the 5 bits which don't interrest us.
+ */
+
+ bEepromByteStore = bInput & (BYTE) 0x8F;
+
+ /*
+ * The bits are arranged as follows
+ * 0ZXY0000,
+ * all the above routines are generic and expect
+ * 00000XYZ
+ */
+
+ bStore = bInput;
+ bInput &= 0x40;
+ bInput >>= 6;
+ bStore &= 0x30;
+ bStore >>= 3;
+ bInput |= bStore;
+
+ return bInput;
+}
+
+
+/************************************************************************
+*
+* Write to the three EEPROM bits.
+*
+* Inputs : Adapter structure.
+* The data to be written.
+*
+* Outputs : None.
+*
+***********************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_write_bits)
+#endif
+
+local void hwi_at24_write_bits(ADAPTER * adapter, BYTE bValue)
+{
+ BYTE bTemp;
+
+ bTemp = (BYTE)((bValue & 0x6) << 3);
+ bTemp |= (BYTE)((bValue & 0x1) << 6);
+
+ /*
+ * Restore the 5 bits we were not interested in from the previous read.
+ */
+
+ bTemp |= bEepromByteStore;
+
+ sys_pci_write_config_byte(adapter->adapter_handle, EEPROM_OFFSET, bTemp);
+
+
+ return;
+}
+
+
+/************************************************************************
+*
+* Write to the three EEPROM bits.
+*
+* We have to store the DATA bit as we cannot definately read it back.
+*
+* Inputs : Adapter structure.
+* The data to be written.
+*
+* Outputs : None.
+*
+***********************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_output)
+#endif
+
+local void hwi_at24_output(ADAPTER * adapter, BYTE bValue)
+{
+ bLastDataBit = bValue & (BYTE) AT24_IO_DATA;
+
+ hwi_at24_write_bits(adapter, bValue);
+
+ return;
+}
+
+
+/************************************************************************
+*
+* Write to the three EEPROM bits.
+*
+* Set the DATA bit to the most recent written bit.
+*
+* Inputs : Adapter structure.
+* The data to be written.
+*
+* Outputs : None.
+*
+***********************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_output_preserve_data)
+#endif
+
+local void hwi_at24_output_preserve_data( ADAPTER * adapter, BYTE bValue)
+{
+ bValue &= ~AT24_IO_DATA;
+ bValue |= bLastDataBit;
+
+ hwi_at24_write_bits(adapter, bValue);
+
+ return;
+}
+
+
+/************************************************************************
+*
+* Delay to allow for serial device timing issues
+*
+* Inputs : Adapter structure
+*
+* Outputs : None
+*
+************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_delay)
+#endif
+
+local void hwi_at24_delay(ADAPTER * adapter)
+{
+ UINT i;
+
+ for (i = 0; i < 100; i++)
+ {
+ sys_insb(adapter->adapter_handle, adapter->io_location);
+ }
+}
+
+
+/************************************************************************
+*
+* Set the serial device clock bit
+*
+* Inputs : Adapter structure
+*
+* Outputs : None
+*
+************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_set_clk)
+#endif
+
+local void hwi_at24_set_clk(ADAPTER * adapter )
+{
+ BYTE temp;
+
+ temp = hwi_at24_input(adapter );
+ temp |= AT24_IO_CLOCK;
+
+ hwi_at24_output_preserve_data(adapter, temp);
+
+ return;
+}
+
+
+/************************************************************************
+*
+* Clears the serial device clock bit
+*
+* Inputs : Adapter structure
+*
+* Outputs : None
+*
+************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_clr_clk)
+#endif
+
+local void hwi_at24_clr_clk(ADAPTER * adapter )
+{
+ BYTE temp;
+
+ temp = hwi_at24_input(adapter );
+ temp &= ~AT24_IO_CLOCK;
+
+ hwi_at24_output_preserve_data(adapter, temp);
+
+ return;
+}
+
+/************************************************************************
+*
+* hwi_at24_read_data
+* Read a data bit from the serial EEPROM. It is assumed that the clock is low
+* on entry to this routine. The data bit is forced high to allow access to
+* the data from the EEPROM, then the clock is toggled, with a read of the
+* data in the middle.
+*
+* Beware! The latched data bit will be set on exit.
+*
+************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_read_data)
+#endif
+
+local BYTE hwi_at24_read_data(ADAPTER * adapter)
+{
+ BYTE bData;
+
+ /*
+ * Set the latched data bit to disconnect us from the data line.
+ */
+
+ bData = AT24_IO_ENABLE | AT24_IO_DATA;
+
+ hwi_at24_output(adapter, bData);
+
+ /*
+ * Set the clk bit to enable the data line.
+ */
+
+ hwi_at24_set_clk(adapter);
+
+ /*
+ * Read the data bit.
+ */
+
+ bData = hwi_at24_input(adapter);
+
+ /*
+ * Get the Data bit into bit 0.
+ */
+
+ bData &= AT24_IO_DATA;
+ bData >>= 1;
+
+ /*
+ * Clear clock again.
+ */
+
+ hwi_at24_clr_clk(adapter);
+
+ return bData;
+}
+
+
+/************************************************************************
+*
+* hwi_at24_write_data
+*
+* Write a data bit to the serial EEPROM. No clock toggle is performed.
+*
+************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_write_data)
+#endif
+
+local void hwi_at24_write_data(ADAPTER * adapter, BYTE bData)
+{
+ BYTE bTemp;
+
+ /*
+ * The bit value is in position 0, get it into position 1.
+ */
+
+ bData <<= 1;
+
+ /*
+ * Not strictly neccessary, but I'm paranoid.
+ */
+
+ bData &= AT24_IO_DATA;
+ bTemp = hwi_at24_input(adapter);
+ bTemp &= ~AT24_IO_DATA;
+
+ bTemp |= bData;
+ hwi_at24_output(adapter, bTemp);
+
+ return;
+}
+
+
+/************************************************************************
+*
+* hwi_at24_enable_eeprom
+*
+* Must be called at the start of eeprom access to ensure we can pull low
+* the data and clock pins on the EEPROM. Forces the clock signal low, as part
+* of the strategy of routines assuming the clock is low on entry to them.
+*
+* Inputs : Adapter structure
+*
+* Outputs : None
+*
+************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_enable_eeprom)
+#endif
+
+local void hwi_at24_enable_eeprom(ADAPTER * adapter)
+{
+ BYTE temp;
+
+ temp = hwi_at24_input(adapter);
+ temp |= AT24_IO_ENABLE;
+
+ hwi_at24_output(adapter, temp);
+
+ return;
+}
+
+
+/************************************************************************
+*
+* hwi_at24_start_bit
+*
+* Send a "START bit" to the serial EEPROM. This involves toggling the
+* clock bit low to high, with data set on the rising edge and cleared on the
+* falling edge. Assumes clock is low and EEPROM enabled on entry.
+*
+* Inputs : Adapter structure
+*
+* Outputs : None
+*
+************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_start_bit)
+#endif
+
+local void hwi_at24_start_bit(ADAPTER * adapter)
+{
+ BYTE bData;
+
+ bData = AT24_IO_ENABLE | AT24_IO_DATA;
+
+ /*
+ * Set the Data bit.
+ */
+
+ hwi_at24_output(adapter, bData);
+
+ hwi_at24_set_clk(adapter);
+
+ /*
+ * Clear the Data bit
+ */
+
+ bData = AT24_IO_ENABLE | AT24_IO_CLOCK;
+ hwi_at24_output(adapter, bData);
+
+ hwi_at24_clr_clk(adapter);
+
+ return;
+
+}
+
+
+/************************************************************************
+*
+* hwi_at24_stop_bit
+*
+* Send a "STOP bit" to the serial EEPROM. This involves toggling the
+* clock bit low to high, with data clear on the rising edge and set on the
+* falling edge. Assumes clock is low and EEPROM enabled on entry.
+* Inputs : Adapter structure
+*
+* Outputs : None
+*
+************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_stop_bit)
+#endif
+
+local void hwi_at24_stop_bit(ADAPTER * adapter)
+{
+ BYTE bData;
+
+ bData = AT24_IO_ENABLE;
+
+ /*
+ * Clear the Data Bit.
+ */
+
+ hwi_at24_output(adapter, bData);
+
+ hwi_at24_set_clk(adapter);
+
+ /*
+ * Set the Data Bit.
+ */
+
+ bData |= (AT24_IO_DATA | AT24_IO_CLOCK);
+ hwi_at24_output(adapter, bData);
+
+ hwi_at24_clr_clk(adapter);
+
+ return;
+}
+
+
+/************************************************************************
+*
+* hwi_at24_wait_ack
+*
+* Wait for an ack from the EEPROM.
+* Outputs : TRUE or FALSE
+*
+************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_wait_ack)
+#endif
+
+local WBOOLEAN hwi_at24_wait_ack(ADAPTER * adapter)
+{
+ WBOOLEAN Acked = FALSE;
+ UINT i;
+ BYTE bData;
+
+ for (i = 0; i < 10; i++)
+ {
+ bData = hwi_at24_read_data(adapter);
+ bData &= 1;
+
+ if (!bData)
+ {
+ Acked = TRUE;
+ break;
+ }
+ }
+
+ return Acked;
+}
+
+
+/************************************************************************
+*
+* hwi_at24_dummy_wait_ack
+*
+* Wait for a negative ack from the EEPROM.
+*
+* Outputs : TRUE or FALSE
+*
+************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_dummy_wait_ack)
+#endif
+
+local WBOOLEAN hwi_at24_dummy_wait_ack(ADAPTER * adapter)
+{
+ WBOOLEAN Acked = FALSE;
+ UINT i;
+ BYTE bData;
+
+ for (i = 0; i < 10; i++)
+ {
+ bData = hwi_at24_read_data(adapter);
+
+ if (bData & 1)
+ {
+ Acked = TRUE;
+ break;
+ }
+ }
+
+ return Acked;
+}
+
+
+/************************************************************************
+*
+* hwi_at24_serial_read_bits
+*
+* Read a Byte from the serial EEPROM.
+*
+* NB This routine gets 8 bits from the EEPROM, but relies upon commands
+* having been sent to the EEPROM 1st. In order to read a byte use
+* hwi_at24_receive_data.
+*
+* Outputs : None
+*
+************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_serial_read_bits)
+#endif
+
+local BYTE hwi_at24_serial_read_bits(ADAPTER * adapter)
+{
+ BYTE bData = 0;
+ BYTE bBit;
+ UINT i;
+
+ for (i = 0; i < 8; i++)
+ {
+ /*
+ * The EEPROM clocks data out MSB first.
+ */
+
+ bBit = hwi_at24_read_data( adapter );
+ bData <<= 1;
+ bData |= bBit;
+ }
+
+ return bData;
+}
+
+
+/************************************************************************
+*
+* hwi_at24_serial_write_bits
+*
+* Send 8 bits to the serial EEPROM.
+*
+* Outputs : None
+*
+************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_serial_write_bits)
+#endif
+
+local void hwi_at24_serial_write_bits(ADAPTER * adapter, BYTE bData)
+{
+ BYTE bBit;
+ UINT i;
+
+ for ( i = 0; i < 8; i++)
+ {
+ bBit = (BYTE)(bData >> (7-i));
+ bBit &= 1;
+ hwi_at24_write_data(adapter, bBit);
+
+ /*
+ * Toggle the clock line to pass the data to the device.
+ */
+
+ hwi_at24_set_clk(adapter);
+ hwi_at24_clr_clk(adapter);
+ }
+
+ return;
+}
+
+
+/************************************************************************
+*
+* hwi_at24_serial_send_cmd
+*
+* Send a command to the serial EEPROM.
+*
+* Outputs : TRUE if sent OK
+*
+************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_serial_send_cmd)
+#endif
+
+local WBOOLEAN hwi_at24_serial_send_cmd( ADAPTER * adapter, BYTE bCommand )
+{
+ UINT i = 0;
+ WBOOLEAN Sent = FALSE;
+
+ while ((i < 40) && (Sent == FALSE))
+ {
+ i++;
+
+ /*
+ * Wake the device up.
+ */
+
+ hwi_at24_start_bit(adapter);
+
+ hwi_at24_serial_write_bits( adapter, bCommand);
+
+ Sent = hwi_at24_wait_ack(adapter);
+ }
+
+ return Sent;
+}
+
+
+/************************************************************************
+*
+* hwi_at24_serial_send_cmd_addr
+*
+* Send a command and address to the serial EEPROM.
+*
+* Outputs : TRUE if sent OK
+*
+************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_serial_send_cmd_addr)
+#endif
+
+local WBOOLEAN hwi_at24_serial_send_cmd_addr(
+ ADAPTER * adapter,
+ BYTE bCommand,
+ BYTE bAddr
+ )
+{
+ WBOOLEAN RetCode;
+
+ RetCode = hwi_at24_serial_send_cmd(adapter, bCommand);
+
+ if (RetCode)
+ {
+ hwi_at24_serial_write_bits(adapter, bAddr);
+
+ RetCode = hwi_at24_wait_ack(adapter);
+ }
+
+ return RetCode;
+}
+
+
+/************************************************************************
+*
+* hwi_at24_serial_receive_data
+*
+* Having set up the address we want to read from, read the data.
+*
+* Outputs : Data read back.
+*
+************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_serial_receive_data)
+#endif
+
+local BYTE hwi_at24_serial_receive_data(ADAPTER * adapter)
+{
+ BYTE bData;
+ WBOOLEAN Acked;
+
+ bData = hwi_at24_serial_read_bits(adapter);
+
+ Acked = hwi_at24_dummy_wait_ack(adapter);
+
+ if (!Acked)
+ {
+ bData = 0xFF;
+ }
+
+ return bData;
+}
+
+
+/************************************************************************
+*
+* hwi_at24_serial_read_byte
+*
+* Read a byte of data from the specified ROM address
+*
+* Outputs : Data read back.
+*
+************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_serial_read_byte)
+#endif
+
+local BYTE hwi_at24_serial_read_byte(ADAPTER * adapter, BYTE bAddr)
+{
+ BYTE bData;
+
+ hwi_at24_enable_eeprom(adapter);
+
+ /*
+ * Send the serial device a dummy WRITE command
+ * that contains the address of the byte we want to
+ * read !
+ */
+
+ hwi_at24_serial_send_cmd_addr(adapter, AT24_WRITE_CMD, bAddr);
+
+ /*
+ * Send the read command.
+ */
+
+ hwi_at24_serial_send_cmd(adapter, AT24_READ_CMD);
+
+ /*
+ * Read the data.
+ */
+
+ bData = hwi_at24_serial_receive_data(adapter);
+
+ /*
+ * Deselect the EEPROM.
+ */
+
+ hwi_at24_stop_bit( adapter );
+
+ return bData;
+}
+
+
+/************************************************************************
+*
+* hwi_at24_read_a_word
+*
+* Read a word of data from the specified ROM address
+*
+* Outputs : Data read back.
+*
+************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_at24_read_a_word)
+#endif
+
+local WORD hwi_at24_read_a_word(ADAPTER * adapter, WORD word_address)
+{
+ WORD wData;
+ BYTE bLoByte;
+ BYTE bByteAddress = (BYTE) ((word_address * 2) & 0xFF);
+
+ bLoByte = hwi_at24_serial_read_byte(adapter, bByteAddress);
+
+ wData = (WORD) hwi_at24_serial_read_byte(
+ adapter,
+ (BYTE) (bByteAddress + 1));
+
+ wData <<= 8;
+ wData |= bLoByte;
+
+ return wData;
+}
+
+#endif
+
+
+/******* End of HWI_PCIT.C **************************************************/
diff --git a/private/ntos/ndis/madge/driver/hwi_pcmc.c b/private/ntos/ndis/madge/driver/hwi_pcmc.c
new file mode 100644
index 000000000..f5aa76c3a
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/hwi_pcmc.c
@@ -0,0 +1,3366 @@
+/****************************************************************************
+*
+* HWI_PCMC.C : Part of the FASTMAC TOOL-KIT (FTK)
+*
+* THE HARDWARE INTERFACE MODULE FOR PCMCIA CARDS
+*
+* Copyright (c) Madge Networks Ltd. 1990-1994
+*
+* COMPANY CONFIDENTIAL
+*
+****************************************************************************
+*
+* The purpose of the Hardware Interface (HWI) is to supply an adapter card
+* independent interface to any driver. It performs nearly all of the
+* functions that involve affecting SIF registers on the adapter cards.
+* This includes downloading code to, initializing, and removing adapters.
+*
+* The HWI_PCMC.C module contains the routines specific to PCMCIA cards
+* which are necessary to install an adapter, to initialize an adapter, to
+* remove an adapter and to handle interrupts on an adapter.
+*
+****************************************************************************/
+
+/*---------------------------------------------------------------------------
+|
+| DEFINITIONS
+|
+---------------------------------------------------------------------------*/
+
+#include "ftk_defs.h"
+
+/*---------------------------------------------------------------------------
+|
+| MODULE ENTRY POINTS
+|
+---------------------------------------------------------------------------*/
+
+#include "ftk_intr.h" /* routines internal to FTK */
+#include "ftk_extr.h" /* routines provided or used by external FTK user */
+
+#ifndef FTK_NO_PCMCIA
+
+#ifndef FTK_NO_PROBE
+/*---------------------------------------------------------------------------
+|
+| Card Services related defines and globals. Used only in this module.
+|
+---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+|
+| #defines
+|
+---------------------------------------------------------------------------*/
+
+#define DETERMINED_BY_CARD_SERVICES 0x00FF
+
+#define MAX_PCMCIA_SOCKETS 0x08
+
+#define PCMCIA_CS_REGISTRATION_TIMEOUT 0xF0000 /* Not real time. Just a */
+ /* for loop counting so */
+ /* 0xF0000 times. */
+
+/*---------------------------------------------------------------------------
+|
+| These are hardware related defines. These are not put in ftk_pcmc.h
+| because: 1. they are only used here and not by ftk user. 2. they are
+| defined using #defines in sys_cs.h which is only included internally.
+|
+---------------------------------------------------------------------------*/
+
+/*
+ * Interrupt channels supported in form of bit mask.
+ */
+
+#define PCMCIA_AVAILABLE_IRQ_MASK \
+ \
+ (IRQ_2|IRQ_3|IRQ_5|IRQ_6|IRQ_7|IRQ_8|IRQ_10|IRQ_11|IRQ_12|IRQ_13|IRQ_14|IRQ_15)
+
+/*
+ * This is the value of IRQInfo1 used in RequestConfiguration. Note that
+ * only level triggered interupt is supported.
+ */
+
+/*
+ * User has specified an interrupt channel.
+ */
+
+#define PCMCIA_IRQINFO1_SPECIFIED IRQ_INFO1_LEVEL
+
+/*
+ * User has not specified an interrupt channel, will be allocated by PCMCIA
+ * card services.
+ */
+
+#define PCMCIA_IRQINFO1_NOT_SPECIFIED \
+ \
+ (IRQ_INFO1_LEVEL | IRQ_INFO1_INFO2_ENABLE)
+
+
+/*---------------------------------------------------------------------------
+|
+| PCMCIA client information
+|
+---------------------------------------------------------------------------*/
+
+#define PCMCIA_VENDOR_NAME "MADGE"
+#define PCMCIA_VENDOR_NAME_LEN 6
+
+ /* 1234567890123456789012345678901 */
+#define PCMCIA_CLIENT_NAME "SMART 16/4 PCMCIA RINGNODE HWI"
+#define PCMCIA_CLIENT_NAME_LEN 31
+
+#define PCMCIA_VENDOR_REVISION 0x0001
+
+#define PCMCIA_VENDOR_REVISION_DATE 0x1C2D /* 13/01/94 in dos format */
+
+struct STRUCT_MADGE_CLIENT_INFODD
+{
+ CS_CLIENT_INFO info;
+ BYTE NameString[PCMCIA_CLIENT_NAME_LEN];
+ BYTE VendorString[PCMCIA_VENDOR_NAME_LEN];
+};
+
+typedef struct STRUCT_MADGE_CLIENT_INFODD MADGE_CLIENT_INFO;
+
+#define DEFAULT_CLIENT_INFO \
+{ \
+ { \
+ 0x0000, \
+ sizeof(MADGE_CLIENT_INFO), \
+ RC_ATTR_IO_CLIENT_DEVICE_DRIVER | RC_ATTR_IO_INSERTION_SHARABLE, \
+ PCMCIA_VENDOR_REVISION, \
+ CARD_SERVICES_VERSION, \
+ PCMCIA_VENDOR_REVISION_DATE, \
+ 20, \
+ PCMCIA_CLIENT_NAME_LEN, \
+ 20+PCMCIA_CLIENT_NAME_LEN, \
+ PCMCIA_VENDOR_NAME_LEN, \
+ }, \
+ PCMCIA_CLIENT_NAME, \
+ PCMCIA_VENDOR_NAME, \
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| PCMCIA sockets record structures
+|
+---------------------------------------------------------------------------*/
+
+enum ENUM_SOCKET_STATUS
+{
+ SOCKET_NOT_INITIALIZED = 0,
+ SOCKET_READY,
+ SOCKET_IN_USE,
+};
+
+typedef enum ENUM_SOCKET_STATUS SOCKET_STATUS;
+
+struct STRUCT_PCMCIA_SOCKET_RECORD
+{
+ WORD ClientHandle;
+ WORD io_location;
+ WORD irq_number;
+ SOCKET_STATUS status;
+ ADAPTER_HANDLE adapter_handle;
+};
+
+typedef struct STRUCT_PCMCIA_SOCKET_RECORD PCMCIA_SOCKET_RECORD;
+
+
+/*---------------------------------------------------------------------------
+|
+| Things use to set up argument buffer
+|
+---------------------------------------------------------------------------*/
+
+/*
+ * Default arg buffer length.
+ */
+
+#define MAX_PCMCIA_ARG_BUFFER_LEN 100
+
+/*
+ * Arg buffer structure.
+ */
+
+/*
+ * Madge Card Services expects the string "Madge" prepended to the argument
+ * buffer.
+ */
+
+struct STRUCT_PCMCIA_ARG_BUFFER
+{
+ BYTE Madge[5];
+ BYTE Buf[MAX_PCMCIA_ARG_BUFFER_LEN];
+};
+
+typedef struct STRUCT_PCMCIA_ARG_BUFFER PCMCIA_ARG_BUFFER;
+
+/*
+ * A macro which creates a new argument buffer and initializes it.
+ */
+
+#define NEW_PCMCIA_ARG_BUFFER(Fp) \
+ \
+ PCMCIA_ARG_BUFFER _xXx_arg_buf_##Fp = {{'M','a','d','g','e'}, {0x00}}; \
+ BYTE FAR * ##Fp = (BYTE FAR *)(_xXx_arg_buf_##Fp.Buf)
+
+
+/*---------------------------------------------------------------------------
+|
+| Global variables Used by Card Services related routines
+|
+---------------------------------------------------------------------------*/
+
+/*
+ * PCMCIA Socket Record. One for each socket. Index by socket no. i.e. 0 to
+ * MAX_PCMCIA_SOCKETS-1
+ */
+
+PCMCIA_SOCKET_RECORD pcmcia_socket_table[MAX_PCMCIA_SOCKETS] =
+{
+ {0x0000, 0x0000, 0x0000, SOCKET_NOT_INITIALIZED, 0x0000},
+};
+
+WORD CardServicesVersion; /* Version of Card Services found */
+
+/*
+ * A flag set by callback to signal of registration completion
+ */
+
+WBOOLEAN RegisterClientCompleted = FALSE;
+
+/*
+ * A signature string found on Madge 16 4 PCMCIA Ringnode. Use in adapter
+ * groping.
+ */
+
+BYTE MADGE_TPLLV1_INFO[] = MADGE_TPLLV1_INFO_STRING;
+
+/*
+ * A bit mask of interrupt channel current used by active ringnode.
+ */
+
+WORD UsedIrqChannelsMask = 0x0000;
+
+/*
+ * The default client information. Reply with this for CLIENT_INFO callback.
+ */
+
+MADGE_CLIENT_INFO default_client_info = DEFAULT_CLIENT_INFO;
+
+#endif
+
+
+/*---------------------------------------------------------------------------
+|
+| LOCAL PROCEDURES
+|
+---------------------------------------------------------------------------*/
+
+local WORD
+hwi_pcmcia_read_eeprom_word(
+ ADAPTER * adapter,
+ WORD word_address);
+
+local WORD
+pcmcia_c46_read_data(
+ ADAPTER * adapter);
+
+local void
+pcmcia_c46_write_bit(
+ ADAPTER * adapter,
+ WORD mask,
+ WBOOLEAN set_bit);
+
+local void
+pcmcia_c46_twitch_clock(
+ ADAPTER * adapter);
+
+#ifndef FTK_NO_PROBE
+
+local WBOOLEAN
+hwi_pcmcia_card_services_setup(
+ PROBE * resource
+ );
+
+local WORD
+hwi_pcmcia_cs_release_config(
+ WORD ClientHandle,
+ WORD Socket
+ );
+
+local WORD
+hwi_pcmcia_cs_release_io(
+ WORD ClientHandle,
+ WORD Socket,
+ WORD IoLocation
+ );
+
+local WORD
+hwi_pcmcia_cs_release_irq(
+ WORD ClientHandle,
+ WORD Socket,
+ WORD IRQChannel
+ );
+
+local WORD
+hwi_pcmcia_cs_deregister_client(
+ WORD ClientHandle
+ );
+
+local WBOOLEAN
+hwi_pcmcia_tear_down_cs(
+ PROBE resource
+ );
+
+#endif
+
+#ifndef FTK_NO_PROBE
+/****************************************************************************
+*
+* hwi_pcmcia_probe_card
+* =====================
+*
+*
+* PARAMETERS (passed by hwi_probe_adapter) :
+* ==========================================
+*
+* PROBE * resources
+*
+* resources is an array structures used to identify and record specific
+* information about adapters found.
+*
+* UINT length
+*
+* length is the number of structures pointed to by reources.
+*
+* WORD * valid_locations
+*
+* valid_locations is an array of IO locations to examine for the presence
+* of an adapter. For PCMCIA adapters with should be a subset of
+* {0x0a20, 0x1a20, 0x2a20, 0x3a20}.
+*
+* UINT number_locations
+*
+* This is the number of IO locations in the above list.
+*
+* BODY :
+* ======
+*
+* The hwi_pcmcia_probe_card routine is called by hwi_probe_adapter. It
+* reads the id registers to find the type of card and also reads the IRQ.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine returns the number of adapters found, or PROBE_FAILURE if
+* there's a problem.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_pcmcia_probe_card)
+#endif
+
+export UINT
+hwi_pcmcia_probe_card(
+ PROBE * resources,
+ UINT length,
+ WORD * valid_locations,
+ UINT number_locations
+ )
+{
+ UINT i;
+ UINT j;
+
+ /*
+ * Check the bounds to make sure they're sensible
+ */
+
+ if(length <= 0 || number_locations <= 0)
+ {
+ return PROBE_FAILURE;
+ }
+
+ /*
+ * j is the number of adapters found.
+ */
+
+ j = 0;
+
+ for(i = 0; i < number_locations; i++)
+ {
+ /*
+ * If we've run out of PROBE structures then return.
+ */
+
+ if(j >= length)
+ {
+ return(j);
+ }
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_probe_enable_io(valid_locations[i], PCMCIA_IO_RANGE);
+#endif
+
+ resources[j].io_location = valid_locations[i];
+
+ if ( hwi_pcmcia_card_services_setup(&resources[j]) )
+ {
+ resources[j].adapter_card_type =
+ ADAPTER_CARD_TYPE_16_4_PCMCIA;
+ resources[j].adapter_ram_size =
+ PCMCIA_RAM_SIZE;
+ resources[j].adapter_card_bus_type =
+ ADAPTER_CARD_PCMCIA_BUS_TYPE;
+ resources[j].dma_channel =
+ 0;
+ resources[j].transfer_mode =
+ PIO_DATA_TRANSFER_MODE;
+
+ /*
+ * Increment j to point at the next PROBE structure.
+ */
+
+ j++;
+
+ /*
+ * HACK!! Card Services doesn't seem to be re-entrant so quit
+ * straight away.
+ */
+
+ return j;
+ }
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_probe_disable_io(resources->io_location, PCMCIA_IO_RANGE);
+#endif
+ }
+
+ return(j);
+}
+
+
+/****************************************************************************
+*
+* hwi_pcmcia_deprobe_card
+* =======================
+*
+*
+* PARAMETERS (passed by hwi_probe_adapter) :
+* ==========================================
+*
+* PROBE resource
+*
+* This structure is used to identify and record specific information about
+* the adapter.
+*
+* BODY :
+* ======
+*
+* The hwi_smart16_probe_card routine is called by hwi_probe_adapter. It
+* probes the adapter card for information such as DMA channel, IRQ number
+* etc. This information can then be supplied by the user when starting the
+* adapter.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine returns the number of adapters found, or zero if there's a
+* problem
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(hwi_pcmcia_deprobe_card)
+#endif
+
+export WBOOLEAN
+hwi_pcmcia_deprobe_card(
+ PROBE resource
+ )
+{
+ WBOOLEAN success;
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_probe_enable_io(resource.io_location, PCMCIA_IO_RANGE);
+#endif
+
+ /*
+ * Release resources requested from card services and deregister.
+ */
+
+ success = hwi_pcmcia_tear_down_cs(resource);
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_probe_disable_io(resource.io_location, PCMCIA_IO_RANGE);
+#endif
+
+ return(success);
+}
+#endif
+
+/****************************************************************************
+*
+* hwi_pcmcia_install_card
+* =======================
+*
+*
+* PARAMETERS (passed by hwi_install_adapter) :
+* ============================================
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+* DOWNLOAD_IMAGE * download_image
+*
+* This is the code to be downloaded to the adapter. The image must be of
+* the correct type i.e. must be downloadable into the adapter. If the
+* pointer is 0 downloading is not done.
+*
+*
+* BODY :
+* ======
+*
+* The hwi_pcmcia_install_card routine is called by hwi_install_adapter.
+* It sets up the adapter card and downloads the required code to it.
+*
+* Firstly, it checks if the I O location and interrupt channel are valid
+* Then it registers with PCMCIA card services, and checks if the required
+* Madge PCMCIA ringnode exists. If so it requests interrrupt and I
+* resources from PCMCIA card services, sets up and checks numerous
+* on-board registers for correct operation. Burnt in address and default
+* ring speed are read from EEPROM.
+*
+* Then, it halts the EAGLE, downloads the code, restarts the EAGLE and
+* waits up to 3 seconds for a valid bring-up code. If interrupts are
+* required, these are enabled by operating system specific calls.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine returns TRUE if it succeeds. If this routine fails (returns
+* FALSE) then a subsequent call to driver_explain_error, with the adapter
+* handle corresponding to the adapter parameter used here, will give an
+* explanation.
+*
+****************************************************************************/
+
+void hlpr_unmap_PCMCIA_irq(WORD irq);
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_pcmcia_install_card)
+#endif
+
+export WBOOLEAN
+hwi_pcmcia_install_card(
+ ADAPTER * adapter,
+ DOWNLOAD_IMAGE * download_image
+ )
+{
+ WORD control_1 = adapter->io_location +
+ PCMCIA_CONTROL_REGISTER_1;
+ WORD control_2 = adapter->io_location +
+ PCMCIA_CONTROL_REGISTER_2;
+ WORD eeprom_word;
+ WORD ring_speed;
+ WORD sif_base;
+ BYTE tmp_byte;
+
+#ifdef PCMCIA_POINT_ENABLE
+ /*
+ * Make sure we don't lose any interrupts.
+ */
+
+ adapter->drop_int = FALSE;
+
+ /*
+ * Enable the card.
+ */
+
+ if(!sys_pcmcia_point_enable(adapter))
+ {
+ /*
+ * Error record already filled in.
+ */
+
+ return(FALSE);
+ }
+#endif
+
+ /*
+ * We don't do any validation on the user supplied adapter details
+ * since the user has to obtain the values from card services in the
+ * first place! (Or did they?)
+ */
+
+ /*
+ * Save IO location of the SIF registers.
+ */
+
+ sif_base = adapter->io_location + PCMCIA_FIRST_SIF_REGISTER;
+
+ adapter->sif_dat = sif_base + EAGLE_SIFDAT;
+ adapter->sif_datinc = sif_base + EAGLE_SIFDAT_INC;
+ adapter->sif_adr = sif_base + EAGLE_SIFADR;
+ adapter->sif_int = sif_base + EAGLE_SIFINT;
+ adapter->sif_acl = sif_base + PCMCIA_EAGLE_SIFACL;
+ adapter->sif_adr2 = sif_base + PCMCIA_EAGLE_SIFADR_2;
+ adapter->sif_adx = sif_base + PCMCIA_EAGLE_SIFADX;
+ adapter->sif_dmalen = sif_base + PCMCIA_EAGLE_DMALEN;
+
+ adapter->io_range = PCMCIA_IO_RANGE;
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ /*
+ * Can be assumed for a PCMCIA adapter.
+ */
+
+ adapter->adapter_card_type = ADAPTER_CARD_TYPE_16_4_PCMCIA;
+
+#if 0
+
+ adapter->adapter_card_revision = 0x0000;
+ adapter->adapter_ram_size = PCMCIA_RAM_SIZE;
+
+#endif
+
+ /*
+ * Interrupts are always level triggered.
+ */
+
+ adapter->edge_triggered_ints = FALSE;
+
+ /*
+ * To get the software handeshake to work properly on PIO
+ * we need to set the MC_AND_ISACP_USE_PIO bit in the
+ * mc32_config byte.
+ */
+
+ adapter->mc32_config = MC_AND_ISACP_USE_PIO;
+
+ /*
+ * Read node address from serial EEPROM.
+ */
+
+ eeprom_word = hwi_pcmcia_read_eeprom_word(
+ adapter,
+ EEPROM_ADDR_NODEADDR1);
+ adapter->permanent_address.byte[0] = (BYTE)(eeprom_word & 0x00FF);
+ adapter->permanent_address.byte[1] = (BYTE)(eeprom_word >> 8);
+
+ eeprom_word = hwi_pcmcia_read_eeprom_word(
+ adapter,
+ EEPROM_ADDR_NODEADDR2);
+ adapter->permanent_address.byte[2] = (BYTE)(eeprom_word & 0x00FF);
+ adapter->permanent_address.byte[3] = (BYTE)(eeprom_word >> 8);
+
+ eeprom_word = hwi_pcmcia_read_eeprom_word(
+ adapter,
+ EEPROM_ADDR_NODEADDR3);
+ adapter->permanent_address.byte[4] = (BYTE)(eeprom_word & 0x00FF);
+ adapter->permanent_address.byte[5] = (BYTE)(eeprom_word >> 8);
+
+ /*
+ * Read ring speed from serial EEPROM.
+ */
+
+ ring_speed = hwi_pcmcia_read_eeprom_word(
+ adapter,
+ EEPROM_ADDR_RINGSPEED);
+
+ /*
+ * Read RAM size from serial EEPROM. Use 512k default if nothing
+ * specified.
+ */
+
+ adapter->adapter_ram_size = hwi_pcmcia_read_eeprom_word(
+ adapter,
+ EEPROM_ADDR_RAMSIZE
+ ) * 128;
+
+ if (adapter->adapter_ram_size == 0)
+ {
+ adapter->adapter_ram_size = PCMCIA_RAM_SIZE;
+ }
+
+ /*
+ * Read hardware revision from serial EEPROM.
+ */
+
+ adapter->adapter_card_revision = hwi_pcmcia_read_eeprom_word(
+ adapter,
+ EEPROM_ADDR_REVISION);
+
+ adapter->use_32bit_pio = FALSE;
+
+#ifdef FTK_PCMCIA_32BIT_PIO
+
+ if (adapter->adapter_card_revision != 0)
+ {
+ adapter->use_32bit_pio = TRUE;
+ }
+
+#endif
+
+ /*
+ * Set all the EEPROM related bits in control register 2 to zero.
+ */
+
+ tmp_byte = 0x00;
+
+ tmp_byte &= ~( PCMCIA_CTRL2_E2DO | PCMCIA_CTRL2_E2DI |
+ PCMCIA_CTRL2_E2CS | PCMCIA_CTRL2_E2SK |
+ PCMCIA_CTRL2_FLSHWREN );
+
+ /*
+ * Set SIF clock frequency to 16MHz.
+ */
+
+ tmp_byte |= PCMCIA_CTRL2_SBCKSEL_16;
+
+ /*
+ * Ring Speed is read from EEPROM, now program it to the front
+ * end chip.
+ */
+
+ if (adapter->set_ring_speed == 16)
+ {
+ tmp_byte |= ( PCMCIA_CTRL2_4N16 & PCMCIA_CTRL2_4N16_16 );
+ }
+ else if (adapter->set_ring_speed == 4)
+ {
+ tmp_byte |= ( PCMCIA_CTRL2_4N16 & PCMCIA_CTRL2_4N16_4 );
+ }
+ else if ( ring_speed == EEPROM_RINGSPEED_4 )
+ {
+ tmp_byte |= ( PCMCIA_CTRL2_4N16 & PCMCIA_CTRL2_4N16_4 );
+ }
+ else
+ {
+ tmp_byte |= ( PCMCIA_CTRL2_4N16 & PCMCIA_CTRL2_4N16_16 );
+ }
+
+ /*
+ * Write all these setting to control register 2 all in one go.
+ */
+
+ sys_outsb(adapter->adapter_handle, control_2, tmp_byte);
+
+
+ /*
+ * Bring EAGLE out of reset.
+ */
+
+ macro_setb_bit(
+ adapter->adapter_handle,
+ control_1,
+ PCMCIA_CTRL1_SRESET);
+
+ /*
+ * Halt EAGLE, no need to page in extended SIF registers for pcmcia.
+ */
+
+ hwi_halt_eagle(adapter);
+
+ /*
+ * Download code to adapter. View download image as a sequence of
+ * download records.
+ * Pass address of routine to set up DIO addresses on pcmcia cards. If
+ * routine fails return failure (error record already filled in).
+ */
+
+ if (!hwi_download_code(
+ adapter,
+ (DOWNLOAD_RECORD *) download_image,
+ hwi_pcmcia_set_dio_address))
+ {
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+
+ /*
+ * Start EAGLE, no need page in extended SIF registers for pcmcia cards.
+ */
+
+ hwi_start_eagle(adapter);
+
+ /*
+ * Wait for a valid bring up code, may wait 3 seconds. If routine fails
+ * return failure (error record already filled in).
+ */
+
+
+ if (!hwi_get_bring_up_code(adapter))
+ {
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+
+ /*
+ * Set DIO address to point to EAGLE DATA page 0x10000L.
+ */
+
+ hwi_pcmcia_set_dio_address(adapter, DIO_LOCATION_EAGLE_DATA_PAGE);
+
+ /*
+ * Set maximum frame size from the ring speed.
+ */
+
+ adapter->max_frame_size = hwi_get_max_frame_size(adapter);
+
+ /*
+ * Get the ring speed.
+ */
+
+ adapter->ring_speed = hwi_get_ring_speed(adapter);
+
+ /*
+ * If not in polling mode then set up interrupts interrupts_on field
+ * is used when disabling interrupts for adapter.
+ */
+
+ if (adapter->interrupt_number != POLLING_INTERRUPTS_MODE)
+ {
+ adapter->interrupts_on = sys_enable_irq_channel(
+ adapter->adapter_handle,
+ adapter->interrupt_number);
+
+ if (!adapter->interrupts_on)
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_0B_FAIL_IRQ_ENABLE;
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+ }
+ else
+ {
+ adapter->interrupts_on = TRUE;
+ }
+
+
+ /*
+ * Enable interrupts at adapter GCR1 SINTREN.
+ */
+
+ macro_setb_bit(
+ adapter->adapter_handle,
+ control_1,
+ PCMCIA_CTRL1_SINTREN);
+
+ /*
+ * PCMCIA adapters do not have DMA channel to setup.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+
+ return TRUE;
+}
+
+
+/****************************************************************************
+*
+* hwi_pcmcia_interrupt_handler
+* ============================
+*
+*
+* PARAMETERS (passed by hwi_interrupt_entry) :
+* ============================================
+*
+* ADAPTER_HANDLE adapter_handle
+*
+* The adapter handle for the adapter so it can later be passed to the user
+* supplied user_receive_frame or user_completed_srb routine.
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+*
+* BODY :
+* ======
+*
+* The hwi_pcmcia_interrupt_handler routine is called, when an interrupt
+* occurs, by hwi_interrupt_entry. It checks to see if a particular card
+* has interrupted. The interrupt could be generated by the SIF or a PIO
+* data transfer. Note it could in fact be the case that no interrupt has
+* occured on the particular adapter being checked.
+*
+* On SIF interrupts, the interrupt is acknowledged and cleared. The value
+* in the SIF interrupt register is recorded in order to pass it to the
+* driver_interrupt_entry routine (along with the adapter details).
+*
+* On PIO interrupts, the length, direction and physical address of the
+* transfer is determined. A system provided routine is called to do the
+* data transfer itself. Note the EAGLE thinks it is doing a DMA transfer.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine always successfully completes.
+*
+****************************************************************************/
+
+#ifdef FTK_IRQ_FUNCTION
+#pragma FTK_IRQ_FUNCTION(hwi_pcmcia_interrupt_handler)
+#endif
+
+#ifndef WIN_BOOK_FIX
+
+/*---------------------------------------------------------------------------
+Ý This is the ordinary, none WinBook, interrupt handler.
+Ý--------------------------------------------------------------------------*/
+
+export void
+hwi_pcmcia_interrupt_handler(
+ ADAPTER * adapter
+ )
+{
+ ADAPTER_HANDLE adapter_handle = adapter->adapter_handle;
+ WORD control_1 = adapter->io_location +
+ PCMCIA_CONTROL_REGISTER_1;
+ WORD control_2 = adapter->io_location +
+ PCMCIA_CONTROL_REGISTER_2;
+ WORD pio_location = adapter->io_location +
+ PCMCIA_PIO_IO_LOC;
+ WORD sifint_register = adapter->sif_int;
+ WORD sifadr = adapter->sif_adr;
+ WORD sifdat = adapter->sif_dat;
+ WORD sifacl = adapter->sif_acl;
+ WORD sifint_value;
+ WORD sifint_tmp;
+ BYTE FAR * pio_address;
+ WORD pio_len_bytes;
+ WORD pio_from_adapter;
+
+ WORD saved_sifadr;
+ WORD dummy;
+
+ DWORD dma_high_word;
+ WORD dma_low_word;
+
+ WORD temp_word;
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io( adapter);
+#endif
+
+ /*
+ * Check for SIF interrupt or PIO interrupt.
+ */
+
+ if ((sys_insw(adapter_handle, sifint_register) &
+ FASTMAC_SIFINT_IRQ_DRIVER) != 0)
+ {
+ /*
+ * A SIF interrupt has occurred. Thsi could be an SRB free,
+ * an adapter check or a received frame interrupt.
+ */
+
+ /*
+ * Clear SIF interrupt enable bit in control register.
+ */
+
+ macro_clearb_bit(adapter_handle, control_1, PCMCIA_CTRL1_SINTREN);
+
+ /*
+ * Clear EAGLE_SIFINT_HOST_IRQ to acknowledge interrupt at SIF.
+ */
+
+ /*
+ * WARNING: Do NOT reorder the clearing of the SIFINT register with
+ * the reading of it. If SIFINT is cleared after reading it, any
+ * interrupts raised after reading it will be lost. Admittedly
+ * this is a small time frame, but it is important.
+ */
+
+ sys_outsw(adapter_handle, sifint_register, 0);
+
+ /*
+ * Record the EAGLE SIF interrupt register value.
+ */
+
+ /*
+ * WARNING: Continue to read the SIFINT register until it is stable
+ * because of a potential problem involving the host reading the
+ * register after the adapter has written the low byte of it, but
+ * before it has written the high byte. Failure to wait for the
+ * SIFINT register to settle can cause spurious interrupts.
+ */
+
+ sifint_value = sys_insw(adapter_handle, sifint_register);
+ do
+ {
+ sifint_tmp = sifint_value;
+ sifint_value = sys_insw(adapter_handle, sifint_register);
+ }
+ while (sifint_tmp != sifint_value);
+
+ /*
+ * Acknowledge clear interrupt at interrupt controller.
+ */
+
+#ifndef FTK_NO_CLEAR_IRQ
+ sys_clear_controller_interrupt(
+ adapter_handle,
+ adapter->interrupt_number
+ );
+#endif
+
+ /*
+ * Set interrupt enable bit to regenerate any lost interrupts.
+ */
+
+ macro_setb_bit(adapter_handle, control_1, PCMCIA_CTRL1_SINTREN);
+
+ /*
+ * It is possible that the PCMCIA adapter may have been removed. In
+ * which case we would expect to get 0xffff from an IO location
+ * occupied by the adapter. We will check the value of SIFADR since
+ * this should never be 0xffff.
+ */
+
+ if (sys_insw(adapter_handle, sifadr) == 0xffff)
+ {
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io( adapter);
+#endif
+
+#ifdef FTK_ADAPTER_REMOVED_NOTIFY
+ user_adapter_removed(adapter_handle);
+#endif
+ return;
+ }
+
+ /*
+ * Call driver with details of SIF interrupt.
+ */
+
+ driver_interrupt_entry(adapter_handle, adapter, sifint_value);
+
+ }
+ else if ((sys_insb(adapter_handle, control_1) & PCMCIA_CTRL1_SHRQ) != 0)
+ {
+ /*
+ * A PIO interrupt has occurred. Transfer data to/from adapter.
+ */
+
+ saved_sifadr = sys_insw(adapter_handle, sifadr);
+
+ /*
+ * Read the physical address for the PIO through DIO space from the
+ * SIF registers. Because the SIF thinks that it is doing real DMA,
+ * the SDMAADR SDMAADX registers cannot be paged in, so they must
+ * be read from their memory mapped locations in Eagle memory.
+ */
+
+ sys_outsw(adapter_handle, sifadr, DIO_LOCATION_EXT_DMA_ADDR);
+ dma_high_word = (DWORD)sys_insw(adapter_handle, sifdat);
+
+ sys_outsw(adapter_handle, sifadr, DIO_LOCATION_DMA_ADDR);
+ dma_low_word = sys_insw(adapter_handle, sifdat);
+
+ pio_address = (BYTE FAR *) ((dma_high_word << 16) |
+ ((DWORD) dma_low_word));
+
+ /*
+ * Read the PIO length from SIF register.
+ */
+
+ pio_len_bytes = sys_insw(adapter_handle, adapter->sif_dmalen);
+
+ /*
+ * Determine what direction the data transfer is to take place in.
+ */
+
+ pio_from_adapter = sys_insw(
+ adapter_handle,
+ sifacl) & EAGLE_SIFACL_SWDDIR;
+
+
+ /*
+ * It is possible that the PCMCIA adapter may have been removed. In
+ * which case we would expect to get 0xffff from an IO location
+ * occupied by the adapter. We will check the value of pio_len_bytes
+ * since this should never be 0xffff. We do this test here as we have
+ * read what we think are the DMA location and length. The following
+ * code may DMA rubbish if the adapter goes away after this test
+ * but at least we know it will happen to/from a valid host buffer.
+ */
+
+ if (pio_len_bytes == 0xffff)
+ {
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+#ifndef FTK_NO_CLEAR_IRQ
+ sys_clear_controller_interrupt(
+ adapter_handle,
+ adapter->interrupt_number
+ );
+#endif
+
+#ifdef FTK_ADAPTER_REMOVED_NOTIFY
+ user_adapter_removed(adapter_handle);
+#endif
+
+ return;
+ }
+
+ /*
+ * We need to use software handshaking across the PIO.
+ * Start by writing zero to a magic location on the adapter.
+ */
+
+ sys_outsw(adapter_handle, sifadr, DIO_LOCATION_DMA_CONTROL);
+ sys_outsw(adapter_handle, sifdat, 0);
+
+ /*
+ * Start what the SIF thinks is a DMA but is PIO instead. This
+ * involves clearing the SINTREN bit and setting SHLDA bit on
+ * control register 1. Note that we have to keep SRESET bit set
+ * otherwise we will reset the EAGLE.
+ */
+
+ sys_outsb(
+ adapter_handle,
+ control_1,
+ PCMCIA_CTRL1_SHLDA | PCMCIA_CTRL1_SRESET);
+
+ /*
+ * Do the actual data transfer.
+ */
+
+ /*
+ * Note that Fastmac only copies whole WORDs to DWORD boundaries
+ * FastmacPlus, however, can transfer any length to any address.
+ */
+
+ if (pio_from_adapter)
+ {
+ /*
+ *
+ *
+ * Transfer into host memory from adapter.
+ *
+ *
+ */
+
+ /*
+ * Deal with an odd leading byte.
+ */
+
+ if (((card_t) pio_address & 0x01) != 0)
+ {
+ /*
+ * Read a WORD, the top byte is data.
+ */
+
+ temp_word = sys_insw(adapter_handle, pio_location);
+ pio_len_bytes--;
+ *(pio_address++) = (BYTE) (temp_word >> 8);
+ }
+
+ /*
+ * We might be able to do 32 bit PIO.
+ */
+
+ if (adapter->use_32bit_pio)
+ {
+ /*
+ * Deal with an odd leading word.
+ */
+
+ if (((card_t) pio_address & 0x02) != 0 && pio_len_bytes > 0)
+ {
+ /*
+ * There could be one or two bytes of data.
+ */
+
+ if (pio_len_bytes == 1)
+ {
+ pio_len_bytes--;
+ *(pio_address) =
+ sys_insb(adapter_handle, pio_location);
+ }
+ else
+ {
+ pio_len_bytes -= 2;
+ *((WORD *) pio_address) =
+ sys_insw(adapter_handle, pio_location);
+ pio_address += 2;
+ }
+ }
+
+ /*
+ * Deal with the bulk of the dwords.
+ */
+
+ sys_rep_insd(
+ adapter_handle,
+ pio_location,
+ pio_address,
+ (WORD) (pio_len_bytes >> 2)
+ );
+
+ pio_address += (pio_len_bytes & 0xfffc);
+
+ /*
+ * Deal with a trailing word.
+ */
+
+ if ((pio_len_bytes & 0x02) != 0)
+ {
+ /*
+ * Read a word.
+ */
+
+ *((WORD *) pio_address) =
+ sys_insw(adapter_handle, pio_location);
+ pio_address += 2;
+ }
+ }
+
+ /*
+ * Otherwise use 16 bit PIO.
+ */
+
+ else
+ {
+ /*
+ * Transfer the bulk of the data.
+ */
+
+ sys_rep_insw(
+ adapter_handle,
+ pio_location,
+ pio_address,
+ (WORD) (pio_len_bytes >> 1)
+ );
+
+ pio_address += (pio_len_bytes & 0xfffe);
+
+ }
+
+ /*
+ * Finally transfer any trailing byte.
+ */
+
+ if ((pio_len_bytes & 0x01) != 0)
+ {
+ *(pio_address) = sys_insb(adapter_handle, pio_location);
+ }
+ }
+
+ else
+ {
+ /*
+ *
+ *
+ * Transfer into adapter memory from the host.
+ *
+ *
+ */
+
+ /*
+ * Deal with a leading odd byte.
+ */
+
+ if (((card_t) pio_address & 0x01) != 0)
+ {
+ /*
+ * Write a WORD with data in top byte.
+ */
+
+ temp_word = ((WORD) *(pio_address++)) << 8;
+ pio_len_bytes--;
+ sys_outsw(adapter_handle, pio_location, temp_word);
+ }
+
+ /*
+ * We might be able to do 32 bit PIO.
+ */
+
+ if (adapter->use_32bit_pio)
+ {
+ /*
+ * Deal with an odd leading word.
+ */
+
+ if (((card_t) pio_address & 0x02) != 0 && pio_len_bytes > 0)
+ {
+ /*
+ * There could be one or two bytes of data. If there
+ * is only one byte it goes in the high word.
+ */
+
+ if (pio_len_bytes == 1)
+ {
+ pio_len_bytes--;
+ sys_outsb(
+ adapter_handle,
+ pio_location,
+ *(pio_address)
+ );
+ }
+ else
+ {
+ pio_len_bytes -= 2;
+ sys_outsw(
+ adapter_handle,
+ pio_location,
+ *((WORD *) pio_address)
+ );
+ pio_address += 2;
+ }
+ }
+
+ /*
+ * Deal with the bulk of the dwords.
+ */
+
+ sys_rep_outsd(
+ adapter_handle,
+ pio_location,
+ pio_address,
+ (WORD) (pio_len_bytes >> 2)
+ );
+
+ pio_address += (pio_len_bytes & 0xfffc);
+
+ /*
+ * Deal with a trailing word.
+ */
+
+ if ((pio_len_bytes & 0x02) != 0)
+ {
+ /*
+ * Write a word.
+ */
+
+ sys_outsw(
+ adapter_handle,
+ pio_location,
+ *((WORD *) pio_address)
+ );
+ pio_address += 2;
+ }
+ }
+
+ /*
+ * Otherwise use 16 bit PIO.
+ */
+
+ else
+ {
+ sys_rep_outsw(
+ adapter_handle,
+ pio_location,
+ pio_address,
+ (WORD) (pio_len_bytes >> 1)
+ );
+
+ pio_address += (pio_len_bytes & 0xfffe);
+ }
+
+ /*
+ * Deal with a trailing byte.
+ */
+
+ if ((pio_len_bytes & 0x01) != 0)
+ {
+ sys_outsb(
+ adapter_handle,
+ pio_location,
+ *(pio_address)
+ );
+ }
+ }
+
+ /*
+ * Transfer done. We have to tell the hardware we have finished.
+ * This involves clearing the SHLDA bit to signal the end of PIO.
+ * Note that the SRESET bit is kept set otherwise we will reset the
+ * EAGLE.
+ */
+
+ sys_outsb(
+ adapter_handle,
+ control_1,
+ PCMCIA_CTRL1_SRESET);
+
+
+ /*
+ * Poll until SHLAD clears.
+ */
+
+ /*
+ * Now wait until SHLDA clears. This is needed since while SHLDA is
+ * set the EAGLE still believes it is in bus master mode; and any
+ * attempt to access the SIF will fail.
+ */
+
+ do
+ {
+ dummy = sys_insb(adapter_handle, control_1);
+
+ /*
+ * It is possible that the adapter was removed during the
+ * transfer. If it was we could spin forever. We will test
+ * the value read from control_1, if it is 0xff then we
+ * assume that the adapter has been removed.
+ */
+
+ if (dummy == 0xff)
+ {
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io( adapter);
+#endif
+
+#ifndef FTK_NO_CLEAR_IRQ
+ sys_clear_controller_interrupt(
+ adapter_handle,
+ adapter->interrupt_number);
+#endif
+
+#ifdef FTK_ADAPTER_REMOVED_NOTIFY
+ user_adapter_removed(adapter_handle);
+#endif
+
+ return;
+ }
+ }
+ while ((dummy & PCMCIA_CTRL1_SHLDA) != 0);
+
+ /*
+ * Finish off the software handshake process that we started at the
+ * beginning. This time we have to write 0xFFFF to
+ * DIO_LOCATION_DMA_CONTROL
+
+ * Do a read first - otherwise the write might fail
+ */
+
+ sys_outsw(adapter_handle, sifadr, DIO_LOCATION_DMA_CONTROL);
+ dummy = sys_insw(adapter_handle, sifdat);
+
+ sys_outsw(adapter_handle, sifadr, DIO_LOCATION_DMA_CONTROL);
+ sys_outsw(adapter_handle, sifdat, 0xFFFF);
+
+ sys_outsw(adapter_handle, sifadr, saved_sifadr);
+
+ /*
+ * acknowledge/clear interrupt at interrupt controller.
+ */
+
+#ifndef FTK_NO_CLEAR_IRQ
+ sys_clear_controller_interrupt(
+ adapter_handle,
+ adapter->interrupt_number);
+#endif
+
+ /*
+ * Set interrupt enable bit to regenerate any lost interrupts.
+ */
+
+ macro_setb_bit(adapter_handle, control_1, PCMCIA_CTRL1_SINTREN);
+ }
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+
+}
+
+#else
+
+/*---------------------------------------------------------------------------
+Ý This is the special interrupt handler for WinBooks.
+Ý On a WinBook there is a 120us window after an interrupt has been
+Ý signalled before the interrupt line floats up to a high enough
+Ý level that another interrupt can be generated. To avoid loosing
+Ý an interrupt in this window we must hold either not allow another
+Ý interrupt to be generated in the windows or poll the adapter for
+Ý interrupt causes for the duration of the window. Since on some
+Ý OSs we cannot spend very long in our interrupt handler we cannot
+Ý just poll (which is the fastest scheme) so we use a mixture. We
+Ý use the PIO handshake to delay a second PIO interrupt and poll
+Ý for SIF interrupts - which are much rarer.
+---------------------------------------------------------------------------*/
+
+export void
+hwi_pcmcia_interrupt_handler(
+ ADAPTER * adapter
+ )
+{
+ ADAPTER_HANDLE adapter_handle = adapter->adapter_handle;
+ WORD control_1 = adapter->io_location +
+ PCMCIA_CONTROL_REGISTER_1;
+ WORD control_2 = adapter->io_location +
+ PCMCIA_CONTROL_REGISTER_2;
+ WORD pio_location = adapter->io_location +
+ PCMCIA_PIO_IO_LOC;
+ WORD sifint_register = adapter->sif_int;
+ WORD sifadr = adapter->sif_adr;
+ WORD sifdat = adapter->sif_dat;
+ WORD sifacl = adapter->sif_acl;
+ WORD sifint_value;
+ WORD sifint_tmp;
+ BYTE FAR * pio_address;
+ WORD pio_len_bytes;
+ WORD pio_from_adapter;
+
+ WORD saved_sifadr;
+ WORD dummy;
+
+ DWORD dma_high_word;
+ WORD dma_low_word;
+
+ WORD temp_word;
+ UINT i;
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io( adapter);
+#endif
+
+ /*
+ * Clear SIF interrupt enable bit in control register.
+ */
+
+ macro_clearb_bit(adapter_handle, control_1, PCMCIA_CTRL1_SINTREN);
+
+ /*
+ * Check for SIF interrupt or PIO interrupt. We do this 80 times
+ * as this has been empirically shown to result in a delay of
+ * 120us since we cleared SINTREN above.
+ */
+
+ for (i = 0; i < 80; i++)
+ {
+ if ((sys_insw(adapter_handle, sifint_register) &
+ FASTMAC_SIFINT_IRQ_DRIVER) != 0)
+ {
+ /*
+ * A SIF interrupt has occurred. This could be an SRB free,
+ * an adapter check or a received frame interrupt.
+ */
+
+ /*
+ * Clear EAGLE_SIFINT_HOST_IRQ to acknowledge interrupt at SIF.
+ */
+
+ /*
+ * WARNING: Do NOT reorder the clearing of the SIFINT register with
+ * the reading of it. If SIFINT is cleared after reading it, any
+ * interrupts raised after reading it will be lost. Admittedly
+ * this is a small time frame, but it is important.
+ */
+
+ sys_outsw(adapter_handle, sifint_register, 0);
+
+ /*
+ * Record the EAGLE SIF interrupt register value.
+ */
+
+ /*
+ * WARNING: Continue to read the SIFINT register until it is stable
+ * because of a potential problem involving the host reading the
+ * register after the adapter has written the low byte of it, but
+ * before it has written the high byte. Failure to wait for the
+ * SIFINT register to settle can cause spurious interrupts.
+ */
+
+ sifint_value = sys_insw(adapter_handle, sifint_register);
+ do
+ {
+ sifint_tmp = sifint_value;
+ sifint_value = sys_insw(adapter_handle, sifint_register);
+ }
+ while (sifint_tmp != sifint_value);
+
+ /*
+ * It is possible that the PCMCIA adapter may have been removed. In
+ * which case we would expect to get 0xffff from an IO location
+ * occupied by the adapter. We will check the value of SIFADR since
+ * this should never be 0xffff.
+ */
+
+ if (sys_insw(adapter_handle, sifadr) == 0xffff)
+ {
+ #ifndef FTK_NO_IO_ENABLE
+ macro_disable_io( adapter);
+ #endif
+
+ #ifdef FTK_ADAPTER_REMOVED_NOTIFY
+ user_adapter_removed(adapter_handle);
+ #endif
+ return;
+ }
+
+ /*
+ * Call driver with details of SIF interrupt.
+ */
+
+ driver_interrupt_entry(adapter_handle, adapter, sifint_value);
+ }
+ else if ((sys_insb(adapter_handle, control_1) & PCMCIA_CTRL1_SHRQ) != 0)
+ {
+ /*
+ * A PIO interrupt has occurred. Transfer data to/from adapter.
+ */
+
+ saved_sifadr = sys_insw(adapter_handle, sifadr);
+
+ /*
+ * Read the physical address for the PIO through DIO space from the
+ * SIF registers. Because the SIF thinks that it is doing real DMA,
+ * the SDMAADR SDMAADX registers cannot be paged in, so they must
+ * be read from their memory mapped locations in Eagle memory.
+ */
+
+ sys_outsw(adapter_handle, sifadr, DIO_LOCATION_EXT_DMA_ADDR);
+ dma_high_word = (DWORD)sys_insw(adapter_handle, sifdat);
+
+ sys_outsw(adapter_handle, sifadr, DIO_LOCATION_DMA_ADDR);
+ dma_low_word = sys_insw(adapter_handle, sifdat);
+
+ pio_address = (BYTE FAR *) ((dma_high_word << 16) |
+ ((DWORD) dma_low_word));
+
+ /*
+ * Read the PIO length from SIF register.
+ */
+
+ pio_len_bytes = sys_insw(adapter_handle, adapter->sif_dmalen);
+
+ /*
+ * Determine what direction the data transfer is to take place in.
+ */
+
+ pio_from_adapter = sys_insw(
+ adapter_handle,
+ sifacl) & EAGLE_SIFACL_SWDDIR;
+
+
+ /*
+ * It is possible that the PCMCIA adapter may have been removed. In
+ * which case we would expect to get 0xffff from an IO location
+ * occupied by the adapter. We will check the value of pio_len_bytes
+ * since this should never be 0xffff. We do this test here as we have
+ * read what we think are the DMA location and length. The following
+ * code may DMA rubbish if the adapter goes away after this test
+ * but at least we know it will happen to/from a valid host buffer.
+ */
+
+ if (pio_len_bytes == 0xffff)
+ {
+ #ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+ #endif
+ #ifndef FTK_NO_CLEAR_IRQ
+ sys_clear_controller_interrupt(
+ adapter_handle,
+ adapter->interrupt_number
+ );
+ #endif
+
+ #ifdef FTK_ADAPTER_REMOVED_NOTIFY
+ user_adapter_removed(adapter_handle);
+ #endif
+
+ return;
+ }
+
+ /*
+ * We need to use software handshaking across the PIO.
+ * Start by writing zero to a magic location on the adapter.
+ */
+
+ sys_outsw(adapter_handle, sifadr, DIO_LOCATION_DMA_CONTROL);
+ sys_outsw(adapter_handle, sifdat, 0);
+
+ /*
+ * Start what the SIF thinks is a DMA but is PIO instead. This
+ * involves clearing the SINTREN bit and setting SHLDA bit on
+ * control register 1. Note that we have to keep SRESET bit set
+ * otherwise we will reset the EAGLE.
+ */
+
+ macro_setb_bit(adapter_handle, control_1, PCMCIA_CTRL1_SHLDA);
+
+ /*
+ * Do the actual data transfer.
+ */
+
+ /*
+ * Note that Fastmac only copies whole WORDs to DWORD boundaries
+ * FastmacPlus, however, can transfer any length to any address.
+ */
+
+ if (pio_from_adapter)
+ {
+ /*
+ *
+ *
+ * Transfer into host memory from adapter.
+ *
+ *
+ */
+
+ /*
+ * Deal with an odd leading byte.
+ */
+
+ if (((card_t) pio_address & 0x01) != 0)
+ {
+ /*
+ * Read a WORD, the top byte is data.
+ */
+
+ temp_word = sys_insw(adapter_handle, pio_location);
+ pio_len_bytes--;
+ *(pio_address++) = (BYTE) (temp_word >> 8);
+ }
+
+ /*
+ * We might be able to do 32 bit PIO.
+ */
+
+ if (adapter->use_32bit_pio)
+ {
+ /*
+ * Deal with an odd leading word.
+ */
+
+ if (((card_t) pio_address & 0x02) != 0 && pio_len_bytes > 0)
+ {
+ /*
+ * There could be one or two bytes of data.
+ */
+
+ if (pio_len_bytes == 1)
+ {
+ pio_len_bytes--;
+ *(pio_address) =
+ sys_insb(adapter_handle, pio_location);
+ }
+ else
+ {
+ pio_len_bytes -= 2;
+ *((WORD *) pio_address) =
+ sys_insw(adapter_handle, pio_location);
+ pio_address += 2;
+ }
+ }
+
+ /*
+ * Deal with the bulk of the dwords.
+ */
+
+ sys_rep_insd(
+ adapter_handle,
+ pio_location,
+ pio_address,
+ (WORD) (pio_len_bytes >> 2)
+ );
+
+ pio_address += (pio_len_bytes & 0xfffc);
+
+ /*
+ * Deal with a trailing word.
+ */
+
+ if ((pio_len_bytes & 0x02) != 0)
+ {
+ /*
+ * Read a word.
+ */
+
+ *((WORD *) pio_address) =
+ sys_insw(adapter_handle, pio_location);
+ pio_address += 2;
+ }
+ }
+
+ /*
+ * Otherwise use 16 bit PIO.
+ */
+
+ else
+ {
+ /*
+ * Transfer the bulk of the data.
+ */
+
+ sys_rep_insw(
+ adapter_handle,
+ pio_location,
+ pio_address,
+ (WORD) (pio_len_bytes >> 1)
+ );
+
+ pio_address += (pio_len_bytes & 0xfffe);
+
+ }
+
+ /*
+ * Finally transfer any trailing byte.
+ */
+
+ if ((pio_len_bytes & 0x01) != 0)
+ {
+ *(pio_address) = sys_insb(adapter_handle, pio_location);
+ }
+ }
+
+ else
+ {
+ /*
+ *
+ *
+ * Transfer into adapter memory from the host.
+ *
+ *
+ */
+
+ /*
+ * Deal with a leading odd byte.
+ */
+
+ if (((card_t) pio_address & 0x01) != 0)
+ {
+ /*
+ * Write a WORD with data in top byte.
+ */
+
+ temp_word = ((WORD) *(pio_address++)) << 8;
+ pio_len_bytes--;
+ sys_outsw(adapter_handle, pio_location, temp_word);
+ }
+
+ /*
+ * We might be able to do 32 bit PIO.
+ */
+
+ if (adapter->use_32bit_pio)
+ {
+ /*
+ * Deal with an odd leading word.
+ */
+
+ if (((card_t) pio_address & 0x02) != 0 && pio_len_bytes > 0)
+ {
+ /*
+ * There could be one or two bytes of data. If there
+ * is only one byte it goes in the high word.
+ */
+
+ if (pio_len_bytes == 1)
+ {
+ pio_len_bytes--;
+ sys_outsb(
+ adapter_handle,
+ pio_location,
+ *(pio_address)
+ );
+ }
+ else
+ {
+ pio_len_bytes -= 2;
+ sys_outsw(
+ adapter_handle,
+ pio_location,
+ *((WORD *) pio_address)
+ );
+ pio_address += 2;
+ }
+ }
+
+ /*
+ * Deal with the bulk of the dwords.
+ */
+
+ sys_rep_outsd(
+ adapter_handle,
+ pio_location,
+ pio_address,
+ (WORD) (pio_len_bytes >> 2)
+ );
+
+ pio_address += (pio_len_bytes & 0xfffc);
+
+ /*
+ * Deal with a trailing word.
+ */
+
+ if ((pio_len_bytes & 0x02) != 0)
+ {
+ /*
+ * Write a word.
+ */
+
+ sys_outsw(
+ adapter_handle,
+ pio_location,
+ *((WORD *) pio_address)
+ );
+ pio_address += 2;
+ }
+ }
+
+ /*
+ * Otherwise use 16 bit PIO.
+ */
+
+ else
+ {
+ sys_rep_outsw(
+ adapter_handle,
+ pio_location,
+ pio_address,
+ (WORD) (pio_len_bytes >> 1)
+ );
+
+ pio_address += (pio_len_bytes & 0xfffe);
+ }
+
+ /*
+ * Deal with a trailing byte.
+ */
+
+ if ((pio_len_bytes & 0x01) != 0)
+ {
+ sys_outsb(
+ adapter_handle,
+ pio_location,
+ *(pio_address)
+ );
+ }
+ }
+
+ /*
+ * Transfer done. We have to tell the hardware we have finished.
+ * This involves clearing the SHLDA bit to signal the end of PIO.
+ * Note that the SRESET bit is kept set otherwise we will reset the
+ * EAGLE.
+ */
+
+ macro_clearb_bit(adapter_handle, control_1, PCMCIA_CTRL1_SHLDA);
+
+ /*
+ * Poll until SHLDA clears.
+ */
+
+ /*
+ * Now wait until SHLDA clears. This is needed since while SHLDA is
+ * set the EAGLE still believes it is in bus master mode; and any
+ * attempt to access the SIF will fail.
+ */
+
+ do
+ {
+ dummy = sys_insb(adapter_handle, control_1);
+
+ /*
+ * It is possible that the adapter was removed during the
+ * transfer. If it was we could spin forever. We will test
+ * the value read from control_1, if it is 0xff then we
+ * assume that the adapter has been removed.
+ */
+
+ if (dummy == 0xff)
+ {
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io( adapter);
+#endif
+
+#ifndef FTK_NO_CLEAR_IRQ
+ sys_clear_controller_interrupt(
+ adapter_handle,
+ adapter->interrupt_number);
+#endif
+
+#ifdef FTK_ADAPTER_REMOVED_NOTIFY
+ user_adapter_removed(adapter_handle);
+#endif
+
+ return;
+ }
+ }
+ while ((dummy & PCMCIA_CTRL1_SHLDA) != 0);
+
+ /*
+ * We don't clear the handshake here to stop another
+ * PIO interrupt being generated for at least 120us
+ */
+ }
+ }
+
+
+ /*
+ * Finish off the software handshake process that we started at the
+ * beginning. This time we have to write 0xFFFF to
+ * DIO_LOCATION_DMA_CONTROL
+ *
+ * Do a read first - otherwise the write might fail
+ */
+
+ sys_outsw(adapter_handle, sifadr, DIO_LOCATION_DMA_CONTROL);
+ dummy = sys_insw(adapter_handle, sifdat);
+
+ sys_outsw(adapter_handle, sifadr, DIO_LOCATION_DMA_CONTROL);
+ sys_outsw(adapter_handle, sifdat, 0xFFFF);
+
+ sys_outsw(adapter_handle, sifadr, saved_sifadr);
+
+ /*
+ * acknowledge/clear interrupt at interrupt controller.
+ */
+
+#ifndef FTK_NO_CLEAR_IRQ
+ sys_clear_controller_interrupt(
+ adapter_handle,
+ adapter->interrupt_number);
+#endif
+
+ /*
+ * Set interrupt enable bit to regenerate any lost interrupts.
+ */
+
+ macro_setb_bit(adapter_handle, control_1, PCMCIA_CTRL1_SINTREN);
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+}
+
+#endif
+
+
+/****************************************************************************
+*
+* hwi_pcmcia_remove_card
+* ======================
+*
+*
+* PARAMETERS (passed by hwi_remove_adapter) :
+* ===========================================
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+*
+* BODY :
+* ======
+*
+* The hwi_pcmcia_remove_card routine is called by hwi_remove_adapter. It
+* disables interrupts if they are being used. It also resets the adapter.
+* Note there is no need to explicitly disable DMA channels.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine always successfully completes.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(hwi_pcmcia_remove_card)
+#endif
+
+export void
+hwi_pcmcia_remove_card(
+ ADAPTER * adapter
+ )
+{
+ WORD sif_acontrol = adapter->sif_acl;
+ WORD control_1 = adapter->io_location +
+ PCMCIA_CONTROL_REGISTER_1;
+
+ /*
+ * Disable interrupts. Only need to do this if interrupts successfully
+ * enabled.
+ * Interrupts must be disabled at adapter before unpatching interrupts.
+ * Even in polling mode we must turn off interrupts at adapter.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ if (adapter->interrupts_on)
+ {
+ macro_clearw_bit(
+ adapter->adapter_handle,
+ sif_acontrol,
+ EAGLE_SIFACL_SINTEN);
+
+#ifdef PCMCIA_POINT_ENABLE
+ /* Deconfigure and power down the card before disabling host
+ * interrupt handler in case of spurious interrupts from the
+ * PCMCIA controller.
+ */
+
+ /*
+ * Warn our handler of the likelihood of a spurious interrupt.
+ */
+
+ adapter->drop_int = TRUE;
+ sys_pcmcia_point_disable(adapter);
+#endif
+
+ if (adapter->interrupt_number != POLLING_INTERRUPTS_MODE)
+ {
+ sys_disable_irq_channel(
+ adapter->adapter_handle,
+ adapter->interrupt_number);
+ }
+
+ adapter->interrupts_on = FALSE;
+ }
+
+ /*
+ * Perform adapter reset, and set EAGLE_SIFACL_ARESET high.
+ */
+
+ macro_clearb_bit(
+ adapter->adapter_handle,
+ control_1,
+ PCMCIA_CTRL1_SRESET);
+
+ macro_setw_bit(
+ adapter->adapter_handle,
+ sif_acontrol,
+ EAGLE_SIFACL_ARESET);
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+
+}
+
+
+/****************************************************************************
+*
+* hwi_pcmcia_set_dio_address
+* ==========================
+*
+* The hwi_pcmcia_set_dio_address routine is used, with pcmcia cards, for
+* putting a 32 bit DIO address into the SIF DIO address and extended DIO
+* address registers.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_pcmcia_set_dio_address)
+#endif
+
+export void
+hwi_pcmcia_set_dio_address(
+ ADAPTER * adapter,
+ DWORD dio_address
+ )
+{
+ WORD sif_dio_adr = adapter->sif_adr;
+ WORD sif_dio_adrx = adapter->sif_adx;
+
+ /*
+ * Load extended DIO address register with top 16 bits of address.
+ * Always load extended address register first.
+ * Note pcmcia cards have single page of all SIF registers hence do not
+ * need page in certain SIF registers.
+ */
+
+ sys_outsw(
+ adapter->adapter_handle,
+ sif_dio_adrx,
+ (WORD)(dio_address >> 16));
+
+ /*
+ * Load DIO address register with low 16 bits of address.
+ */
+
+ sys_outsw(
+ adapter->adapter_handle,
+ sif_dio_adr,
+ (WORD)(dio_address & 0x0000FFFF));
+
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| LOCAL PROCEDURES
+|
+---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+|
+| pcmcia_c46_write_bit
+| ====================
+|
+| Write a bit to the SEEPROM control register.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pcmcia_c46_write_bit)
+#endif
+
+local void
+pcmcia_c46_write_bit(
+ ADAPTER * adapter,
+ WORD mask,
+ WBOOLEAN set_bit)
+{
+ WORD ctrl_reg;
+
+ /*
+ * Get the current value of the SEEPROM control register.
+ */
+
+ ctrl_reg = sys_insb(
+ adapter->adapter_handle,
+ (WORD) (adapter->io_location + PCMCIA_CONTROL_REGISTER_2)
+ );
+
+ /*
+ * Clear or set the bit.
+ */
+
+ if (set_bit)
+ {
+ ctrl_reg |= mask;
+ }
+ else
+ {
+ ctrl_reg &= ~mask;
+ }
+
+ /*
+ * Write the data to the SEEPROM control register.
+ */
+
+ sys_outsb(
+ adapter->adapter_handle,
+ (WORD) (adapter->io_location + PCMCIA_CONTROL_REGISTER_2),
+ (BYTE) ctrl_reg);
+
+ /*
+ * Wait for a bit.
+ */
+
+ sys_wait_at_least_microseconds(10);
+
+ /*
+ * And read the SEEPROM control register back so that the data gets
+ * latched properly.
+ */
+
+ sys_insb(
+ adapter->adapter_handle,
+ (WORD) (adapter->io_location + PCMCIA_CONTROL_REGISTER_2));
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| pcmcia_c46_twitch_clock
+| =======================
+|
+| Toggle the SEEPROM clock.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pcmcia_c46_twitch_clock)
+#endif
+
+local void
+pcmcia_c46_twitch_clock(
+ ADAPTER * adapter
+ )
+{
+ pcmcia_c46_write_bit(adapter, PCMCIA_CTRL2_E2SK, TRUE);
+ pcmcia_c46_write_bit(adapter, PCMCIA_CTRL2_E2SK, FALSE);
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| pcmcia_c46_read_data
+| ====================
+|
+| Read a data bit from the SEEPROM control register
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pcmcia_c46_read_data)
+#endif
+
+local WORD
+pcmcia_c46_read_data(
+ ADAPTER * adapter
+ )
+{
+ return sys_insb(
+ adapter->adapter_handle,
+ (WORD) (adapter->io_location + PCMCIA_CONTROL_REGISTER_2)
+ ) & PCMCIA_CTRL2_E2DO;
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| hwi_pcmcia_read_eeprom_word
+| ===========================
+|
+| hwi_pcmcia_read_eeprom_word takes the address of the word to be read
+| from the AT93C46 serial EEPROM, write to the IO ports a magic sequence
+| to switch the EEPROM to reading mode and finally read the required word
+| and return.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_pcmcia_read_eeprom_word)
+#endif
+
+local WORD
+hwi_pcmcia_read_eeprom_word(
+ ADAPTER * adapter,
+ WORD word_address
+ )
+{
+ WORD i;
+ WORD cmd_word = C46_START_BIT | C46_READ_CMD;
+ WORD tmp_word;
+
+ /*
+ * Concatenate the address to command word.
+ */
+
+ cmd_word |= (WORD)((word_address & C46_ADDR_MASK) << C46_ADDR_SHIFT);
+
+ /*
+ * Clear data in bit.
+ */
+
+ pcmcia_c46_write_bit(
+ adapter,
+ PCMCIA_CTRL2_E2DI,
+ FALSE);
+
+ /*
+ * Assert chip select bit.
+ */
+
+ pcmcia_c46_write_bit(
+ adapter,
+ PCMCIA_CTRL2_E2CS,
+ TRUE);
+
+ /*
+ * Send read command and address.
+ */
+
+ pcmcia_c46_twitch_clock(
+ adapter);
+
+ tmp_word = cmd_word;
+
+ for (i = 0; i < C46_CMD_LENGTH; i++)
+ {
+ pcmcia_c46_write_bit(
+ adapter,
+ PCMCIA_CTRL2_E2DI,
+ (WBOOLEAN) ((tmp_word & 0x8000) != 0));
+ pcmcia_c46_twitch_clock(adapter);
+ tmp_word <<= 1;
+ }
+
+ /*
+ * Read data word.
+ */
+
+ tmp_word = 0x0000;
+
+ for (i = 0; i < 16; i++)
+ {
+ pcmcia_c46_twitch_clock(adapter);
+
+ if (i > 0)
+ {
+ tmp_word <<= 1;
+ }
+
+ if (pcmcia_c46_read_data(adapter) != 0)
+ {
+ tmp_word |= 0x0001;
+ }
+ }
+
+ /*
+ * Clear data in bit.
+ */
+
+ pcmcia_c46_write_bit(
+ adapter,
+ PCMCIA_CTRL2_E2DI,
+ FALSE);
+
+ /*
+ * Deselect chip.
+ */
+
+ pcmcia_c46_write_bit(
+ adapter,
+ PCMCIA_CTRL2_E2CS,
+ FALSE);
+
+ /*
+ * Tick clock.
+ */
+
+ pcmcia_c46_twitch_clock(adapter);
+
+ return tmp_word;
+}
+
+#ifndef FTK_NO_PROBE
+/*---------------------------------------------------------------------------
+|
+| hwi_pcmcia_card_services_setup
+| ==============================
+|
+| hwi_pcmcia_card_services_setup is called by hwi_pcmcia_install_card. It
+| handles all the procedures required to register with PCMCIA Card
+| Serivces and request I O and interrupt resources.
+|
+| The caller must fill in interrupt_number and io_location field of the
+| input adapter structure. Interrupt number can be any number supported by
+| the 16 4 PCMCIA ringnode or DETERMINED_BY_CS. A valid io_location mus
+| be supplied.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_pcmcia_card_services_setup)
+#endif
+
+local WBOOLEAN
+hwi_pcmcia_card_services_setup(
+ PROBE * resource
+ )
+{
+ NEW_PCMCIA_ARG_BUFFER(fp);
+
+ WORD rc;
+ WORD ClientHandle;
+ DWORD i = 0;
+ WORD j;
+ void FAR * CallBackPtr = (void FAR *) Callback;
+ WORD socket = DETERMINED_BY_CARD_SERVICES;
+ WORD irq = DETERMINED_BY_CARD_SERVICES;
+ WORD io_location = resource->io_location;
+
+ rc = CardServices(
+ CS_GetCardServicesInfo, /* Function */
+ NULL, /* Handle not used */
+ NULL, /* Pointer not used */
+ MAX_PCMCIA_ARG_BUFFER_LEN, /* argbuffer length */
+ fp ); /* argbuffer */
+
+ if (rc == CMD_SUCCESS)
+ {
+ CS_GET_CS_INFO_ARG FAR * ptr = (CS_GET_CS_INFO_ARG FAR *)fp;
+
+ if ((ptr->Signature[0] == 'C') &&
+ (ptr->Signature[1] == 'S'))
+ {
+ CardServicesVersion = ptr->CSLevel;
+ }
+ else if ((ptr->Signature[0] == 'M') &&
+ (ptr->Signature[1] == 'N'))
+ {
+ CardServicesVersion = ptr->CSLevel;
+ }
+ else
+ {
+ return FALSE;
+ }
+
+ }
+ else
+ {
+ return FALSE;
+ }
+
+ {
+ CS_REGISTER_CLIENT_ARG FAR * ptr =
+ (CS_REGISTER_CLIENT_ARG FAR *)fp;
+
+ ptr->Attributes = RC_ATTR_IO_CLIENT_DEVICE_DRIVER |
+ RC_ATTR_IO_INSERTION_SHARABLE;
+
+ ptr->EventMask = MASK_CARD_DETECT;
+
+ ptr->ClientData[0] = 0x00; /* Not used */
+ ptr->ClientData[1] = 0x00; /* CardServices will put DS here. */
+ ptr->ClientData[2] = 0x00; /* Not used */
+ ptr->ClientData[3] = 0x00; /* Not used */
+ ptr->Version = 0x0201;
+ }
+
+ /*
+ * Set RegisterClientCompleted flag to FALSE. When registration
+ * complete event occur, call back function will set this flag to TRUE.
+ */
+
+ RegisterClientCompleted = FALSE;
+
+ rc = CardServices(
+ CS_RegisterClient,
+ (WORD FAR *)&ClientHandle,
+ (void * FAR *)&CallBackPtr,
+ MAX_PCMCIA_ARG_BUFFER_LEN,
+ fp );
+
+ if (CMD_SUCCESS != rc)
+ {
+ return FALSE;
+ }
+
+ while (!RegisterClientCompleted)
+ {
+ /*
+ * Wait for card insertion event to complete, timeout if waiting
+ * for too long.
+ */
+
+ i++;
+
+ if (i == PCMCIA_CS_REGISTRATION_TIMEOUT)
+ {
+ return FALSE;
+ }
+ }
+
+ /*
+ * Check if there is a least one socket ready for use. Return false if
+ * none is found. Remember we have registered with card services, so
+ * deregister before returning.
+ */
+
+ for (j = 0; j < MAX_PCMCIA_SOCKETS; j++)
+ {
+ if (SOCKET_READY == pcmcia_socket_table[j].status)
+ {
+ break;
+ }
+ }
+
+ if (MAX_PCMCIA_SOCKETS == j)
+ {
+ /*
+ * No socket available. Either no Madge card installed or they are
+ * already in use. Report error here. Must deregister before
+ * returning.
+ */
+
+ hwi_pcmcia_cs_deregister_client(ClientHandle);
+
+ return FALSE;
+ }
+
+ if (socket != DETERMINED_BY_CARD_SERVICES)
+ {
+ /*
+ * User specified a socket number to use. Check if it is available.
+ */
+
+ if (pcmcia_socket_table[socket].status == SOCKET_NOT_INITIALIZED)
+ {
+ /*
+ * No Madge Card found in PCMCIA socket specified, deregister
+ * and report error.
+ */
+
+ hwi_pcmcia_cs_deregister_client(ClientHandle);
+
+ return FALSE;
+ }
+ else if (pcmcia_socket_table[socket].status == SOCKET_IN_USE)
+ {
+ /*
+ * Card in socket number specified is currently in use,
+ * deregister and report error.
+ */
+
+ hwi_pcmcia_cs_deregister_client(ClientHandle);
+
+ return FALSE;
+ }
+ else
+ {
+ /*
+ * Socket number specified has a Madge Card in it and it is
+ * available.
+ */
+ ;
+ }
+
+ }
+ else
+ {
+ /*
+ * User asked Card Services to choose which socket to use.
+ * Use the first available one.
+ */
+ socket = j;
+ }
+
+ /*
+ * Call CS AdjustResourceInfo.
+ */
+
+ {
+ CS_ADJ_IO_RESOURCE_ARG FAR * ptr =
+ (CS_ADJ_IO_RESOURCE_ARG FAR *)fp;
+
+ ptr->Action = ARI_ACTION_ADD;
+ ptr->Resource = ARI_RESOURCE_IO;
+ ptr->BasePort = io_location;
+ ptr->NumPorts = PCMCIA_IO_RANGE;
+ ptr->Attributes = 0x00;
+ ptr->IOAddrLines = PCMCIA_NUMBER_OF_ADDR_LINES;
+ }
+
+ rc = CardServices(CS_AdjustResourceInfo,
+ NULL,
+ NULL,
+ MAX_PCMCIA_ARG_BUFFER_LEN,
+ fp );
+
+ if (CMD_SUCCESS != rc)
+ {
+ /*
+ * Requested IO location is not available, deregister and report
+ * error.
+ */
+
+ hwi_pcmcia_cs_deregister_client(ClientHandle);
+
+ return FALSE;
+ }
+
+ /*
+ * AdjustResourceInfo does not exist for CS V2.00 on the IBM ThinkPad.
+ * Assume it is ok. Do not bother to check the return code here.
+ */
+
+ /*
+ * Call CS RequestIO to ask for IO resources.
+ */
+
+ {
+ CS_REQUEST_IO_ARG FAR * ptr = (CS_REQUEST_IO_ARG FAR *) fp;
+
+ ptr->Socket = socket;
+ ptr->BasePort1 = io_location;
+ ptr->NumPorts1 = PCMCIA_IO_RANGE;
+ ptr->Attributes1 = RIO_ATTR_16_BIT_DATA;
+ ptr->BasePort2 = 0x0000;
+ ptr->NumPorts2 = 0x00;
+ ptr->Attributes2 = 0x00;
+ ptr->IOAddrLines = PCMCIA_NUMBER_OF_ADDR_LINES;
+
+ }
+
+ rc = CardServices(CS_RequestIO,
+ (WORD FAR *)&ClientHandle,
+ NULL,
+ MAX_PCMCIA_ARG_BUFFER_LEN,
+ fp );
+
+
+ if (CMD_SUCCESS != rc)
+ {
+ /*
+ * Requested IO location is not available, deregister and report
+ * error.
+ */
+
+ hwi_pcmcia_cs_deregister_client(ClientHandle);
+
+ return FALSE;
+ }
+
+ /*
+ * Call CS RequestIRQ to ask for interrupt resources.
+ */
+
+ {
+ CS_REQUEST_IRQ_ARG FAR * ptr = (CS_REQUEST_IRQ_ARG FAR *)fp;
+
+ if (DETERMINED_BY_CARD_SERVICES == irq)
+ {
+ /*
+ * User asked card services to choose any interrupt channel
+ * available.
+ */
+
+ ptr->IRQInfo1 = PCMCIA_IRQINFO1_NOT_SPECIFIED;
+
+ /*
+ * List of IRQ channel available (in form of bit mask) for card
+ * services to choose from. Exclude those already in use.
+ */
+
+ ptr->IRQInfo2 = PCMCIA_AVAILABLE_IRQ_MASK & ~UsedIrqChannelsMask;
+ }
+ else if ((0x0001 << irq) & PCMCIA_AVAILABLE_IRQ_MASK)
+ {
+ /*
+ * Use the interrupt channel the user supplied.
+ */
+
+ ptr->IRQInfo1 = (BYTE)((irq & 0x00FF) |
+ PCMCIA_IRQINFO1_SPECIFIED);
+ ptr->IRQInfo2 = 0x0000;
+ }
+ else
+ {
+ /*
+ * An invalid interrupt channel is specified.
+ * We have already requested for an IO resource, we must
+ * release it and deregister with card services before
+ * returning.
+ */
+
+ hwi_pcmcia_cs_release_io(ClientHandle, socket, io_location);
+ hwi_pcmcia_cs_deregister_client(ClientHandle);
+
+ return FALSE;
+ }
+
+ ptr->Socket = socket;
+ ptr->Attributes = 0x0000;
+
+ rc = CardServices(
+ CS_RequestIRQ,
+ (WORD FAR *)&ClientHandle,
+ NULL,
+ MAX_PCMCIA_ARG_BUFFER_LEN,
+ fp );
+
+ if (CMD_SUCCESS == rc)
+ {
+ /*
+ * Card Services successfully allocated us an interrupt
+ * channel, record it for later use.
+ */
+
+ irq = (WORD)ptr->AssignedIRQ;
+ }
+ else
+ { /*
+ * Failed to obtain an interrupt channel. Release the IO
+ * allocated and deregister with card services.
+ */
+
+ hwi_pcmcia_cs_release_io(ClientHandle, socket, io_location);
+ hwi_pcmcia_cs_deregister_client(ClientHandle);
+
+ return FALSE;
+ }
+ }
+
+ /*
+ * Call CS RequestConfiguration.
+ */
+
+ {
+ CS_REQUEST_CONFIG_ARG FAR * ptr = (CS_REQUEST_CONFIG_ARG FAR *)fp;
+
+ ptr->Socket = socket;
+ ptr->Attributes = RC_ATTR_ENABLE_IRQ_STEERING;
+ ptr->Vcc = PCMCIA_VCC;
+ ptr->Vpp1 = PCMCIA_VPP1;
+ ptr->Vpp2 = PCMCIA_VPP2;
+ ptr->IntType = RC_INTTYPE_MEMORY_AND_IO;
+ ptr->ConfigBase = PCMCIA_CONFIG_BASE;
+ ptr->Status = PCMCIA_STATUS_REG_SETTING;
+ ptr->Pin = PCMCIA_PIN_REG_SETTING;
+ ptr->Copy = PCMCIA_COPY_REG_SETTING;
+ ptr->ConfigIndex = PCMCIA_OPTION_REG_SETTING;
+ ptr->Present = PCMCIA_REGISTER_PRESENT;
+
+ }
+
+ rc = CardServices(
+ CS_RequestConfiguration,
+ (WORD FAR *)&ClientHandle,
+ NULL,
+ MAX_PCMCIA_ARG_BUFFER_LEN,
+ fp );
+
+ if (CMD_SUCCESS != rc)
+ {
+ /*
+ * RequestConfiguration failed. Release all resources and return
+ * error.
+ */
+
+ hwi_pcmcia_cs_release_io(ClientHandle, socket, io_location);
+ hwi_pcmcia_cs_release_irq(ClientHandle, socket, irq);
+ hwi_pcmcia_cs_deregister_client(ClientHandle);
+
+ return FALSE;
+
+ }
+
+ /*
+ * We successfully made all the card services call. Update our local
+ * sockets record here.
+ */
+
+ pcmcia_socket_table[socket].status = SOCKET_IN_USE;
+ pcmcia_socket_table[socket].irq_number = irq;
+ pcmcia_socket_table[socket].io_location = io_location;
+ pcmcia_socket_table[socket].ClientHandle = ClientHandle;
+
+ /*
+ * Record interrupt channel used.
+ */
+
+ UsedIrqChannelsMask |= ( 0x0001 << irq );
+
+ /*
+ * Fill adapter sturcture with resources allocated.
+ */
+
+ resource->interrupt_number = irq;
+ resource->io_location = io_location;
+ resource->socket = socket;
+
+ /*
+ * Toggle the top bit of Configuration Option Register to reset card.
+ */
+
+ /*
+ * Note that this is not necessary for later cards.
+ * CS 2.00 may not have this function, so just do it but don't bother
+ * to check return code.
+ */
+
+ {
+ CS_ACCESS_CONFIG_REG_ARG FAR * ptr =
+ (CS_ACCESS_CONFIG_REG_ARG FAR *) fp;
+
+ ptr->Socket = socket;
+ ptr->Action = ACR_ACTION_WRITE;
+ ptr->Offset = PCMCIA_OPTION_REG;
+ ptr->Value = PCMCIA_COR_SYSRESET;
+
+ CardServices(
+ CS_AccessConfigurationRegister,
+ NULL,
+ NULL,
+ MAX_PCMCIA_ARG_BUFFER_LEN,
+ fp );
+
+ ptr->Value = 0x00;
+
+ CardServices(
+ CS_AccessConfigurationRegister,
+ NULL,
+ NULL,
+ MAX_PCMCIA_ARG_BUFFER_LEN,
+ fp );
+
+ ptr->Value = PCMCIA_OPTION_REG_SETTING;
+
+ CardServices(
+ CS_AccessConfigurationRegister,
+ NULL,
+ NULL,
+ MAX_PCMCIA_ARG_BUFFER_LEN,
+ fp );
+ }
+
+ return TRUE;
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| hwi_pcmcia_cs_release_config
+| ============================
+|
+| hwi_pcmcia_cs_release_config releases resources requested earlier from
+| Card Services. This is part of the shut down procedure.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(hwi_pcmcia_cs_release_config)
+#endif
+
+local WORD
+hwi_pcmcia_cs_release_config(
+ WORD ClientHandle,
+ WORD Socket)
+{
+ NEW_PCMCIA_ARG_BUFFER(fp);
+ WORD chandle = ClientHandle;
+ CS_RELEASE_CONFIG_ARG FAR * ptr = (CS_RELEASE_CONFIG_ARG FAR *)fp;
+
+ ptr->Socket = Socket;
+
+ return CardServices(
+ CS_ReleaseConfiguration,
+ &chandle,
+ NULL,
+ MAX_PCMCIA_ARG_BUFFER_LEN,
+ fp);
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| hwi_pcmcia_cs_release_io
+| ========================
+|
+| hwi_pcmcia_cs_release_io releases the IO resources requested earlier
+| from Card Services.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(hwi_pcmcia_cs_release_io)
+#endif
+
+local WORD
+hwi_pcmcia_cs_release_io(
+ WORD ClientHandle,
+ WORD Socket,
+ WORD IoLocation
+ )
+{
+ NEW_PCMCIA_ARG_BUFFER(fp);
+ WORD chandle = ClientHandle;
+ CS_RELEASE_IO_ARG FAR * ptr = (CS_RELEASE_IO_ARG FAR *)fp;
+
+
+ ptr->Socket = Socket;
+ ptr->BasePort1 = IoLocation;
+ ptr->NumPorts1 = PCMCIA_IO_RANGE;
+ ptr->Attributes1 = RIO_ATTR_16_BIT_DATA;
+ ptr->BasePort2 = 0x0000;
+ ptr->NumPorts2 = 0x00;
+ ptr->Attributes2 = 0x00;
+ ptr->IOAddrLines = PCMCIA_NUMBER_OF_ADDR_LINES;
+
+ return CardServices(
+ CS_ReleaseIO,
+ (WORD FAR *)&chandle,
+ NULL,
+ MAX_PCMCIA_ARG_BUFFER_LEN,
+ fp);
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| hwi_pcmcia_cs_release_irq
+| =========================
+|
+| hwi_pcmcia_cs_release_irq release the IRQ resources requested earlier
+| from Card Services.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(hwi_pcmcia_cs_release_irq)
+#endif
+
+local WORD
+hwi_pcmcia_cs_release_irq(
+ WORD ClientHandle,
+ WORD Socket,
+ WORD IRQChannel)
+{
+ NEW_PCMCIA_ARG_BUFFER(fp);
+ WORD chandle = ClientHandle;
+ CS_RELEASE_IRQ_ARG FAR * ptr = (CS_RELEASE_IRQ_ARG FAR *)fp;
+
+
+ ptr->Socket = Socket;
+ ptr->Attributes = 0x0000;
+ ptr->AssignedIRQ = (BYTE)IRQChannel;
+
+ return CardServices(
+ CS_ReleaseIRQ,
+ (WORD FAR *)&chandle,
+ NULL,
+ MAX_PCMCIA_ARG_BUFFER_LEN,
+ fp);
+}
+
+/*---------------------------------------------------------------------------
+|
+| hwi_pcmcia_cs_deregister_client
+| ===============================
+|
+| hwi_pcmcia_cs_deregister_client informs PCMCIA card services that we are
+| not longer interest in any PCMCIA event and/or resources. It is called
+| in shut down or failure in invoking other card services related
+| function.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(hwi_pcmcia_cs_deregister_client)
+#endif
+
+local WORD
+hwi_pcmcia_cs_deregister_client(
+ WORD ClientHandle
+ )
+{
+ NEW_PCMCIA_ARG_BUFFER(fp);
+ WORD chandle = ClientHandle;
+
+ return CardServices(
+ CS_DeregisterClient,
+ (WORD FAR *)&chandle,
+ NULL,
+ 0,
+ fp);
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| hwi_pcmcia_tear_down_cs
+| =======================
+|
+| hwi_pcmcia_tear_down_cs is called by hwi_pcmcia_remove card to release
+| all the resources allocated by PCMCIA card services and deregister with
+| card services
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(hwi_pcmcia_tear_down_cs)
+#endif
+
+local WBOOLEAN
+hwi_pcmcia_tear_down_cs(
+ PROBE resource
+ )
+{
+
+ WORD socket = resource.socket;
+ WORD ClientHandle;
+ WORD io_location;
+ WORD irq_number;
+ WBOOLEAN rc1;
+ WBOOLEAN rc2;
+ WBOOLEAN rc3;
+ WBOOLEAN rc4;
+
+
+ if (pcmcia_socket_table[socket].status != SOCKET_IN_USE)
+ {
+ return FALSE;
+ }
+
+ /*
+ * Socket number found. retrieve clienthandle, irq, iolocation from our
+ * local socket record.
+ */
+
+ ClientHandle = pcmcia_socket_table[socket].ClientHandle;
+ io_location = pcmcia_socket_table[socket].io_location;
+ irq_number = pcmcia_socket_table[socket].irq_number;
+
+ /*
+ * Call the PCMCIA card services routine to bring it down.
+ */
+
+ rc1 = hwi_pcmcia_cs_release_config(ClientHandle, socket);
+ rc2 = hwi_pcmcia_cs_release_io(ClientHandle, socket, io_location);
+ rc3 = hwi_pcmcia_cs_release_irq(ClientHandle, socket, irq_number);
+ rc4 = hwi_pcmcia_cs_deregister_client(ClientHandle);
+
+ /*
+ * Update local record.
+ */
+
+ pcmcia_socket_table[socket].ClientHandle = 0x0000;
+ pcmcia_socket_table[socket].io_location = 0x0000;
+ pcmcia_socket_table[socket].irq_number = 0x0000;
+ pcmcia_socket_table[socket].status = SOCKET_NOT_INITIALIZED;
+
+ return (rc1 && rc2 && rc3 && rc4);
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| This is the callback function used by Card Services to notify client any
+| event changes. Its prototype is defined in sys_cs.h module.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(Callback)
+#endif
+
+WORD FAR
+Callback(
+ WORD Function,
+ WORD Socket,
+ WORD Info,
+ void FAR * MTDRequest,
+ void FAR * Buffer,
+ WORD Misc,
+ WORD ClientData1,
+ WORD ClientData2,
+ WORD ClientData3
+ )
+{
+ NEW_PCMCIA_ARG_BUFFER(fp);
+ WORD rc;
+
+ switch (Function)
+ {
+ case REGISTRATION_COMPLETE :
+ RegisterClientCompleted = TRUE;
+ break;
+
+ case CARD_INSERTION :
+ /*
+ * Call GetFistTuple of card services.
+ */
+
+ {
+ CS_GET_FIRST_TUPLE_ARG FAR * ptr =
+ (CS_GET_FIRST_TUPLE_ARG FAR *)fp;
+
+ ptr->Socket = Socket;
+ ptr->Attributes = 0x0000;
+ ptr->DesiredTuple = CISTPL_VERS_1;
+ ptr->Reserved = 0x00;
+ }
+
+ rc = CardServices(
+ CS_GetFirstTuple,
+ NULL,
+ NULL,
+ MAX_PCMCIA_ARG_BUFFER_LEN,
+ fp);
+
+ if (rc != CMD_SUCCESS)
+ {
+ break;
+ }
+
+ /*
+ * Call GetTupleData of card services.
+ */
+
+ {
+ CS_GET_TUPLE_DATA_ARG FAR * ptr =
+ (CS_GET_TUPLE_DATA_ARG FAR *)fp;
+
+ ptr->TupleOffset = 0x00;
+ ptr->TupleDataMax = MAX_PCMCIA_ARG_BUFFER_LEN;
+ }
+
+ rc = CardServices(
+ CS_GetTupleData,
+ NULL,
+ NULL,
+ MAX_PCMCIA_ARG_BUFFER_LEN,
+ fp);
+
+ if (rc != CMD_SUCCESS)
+ {
+ break;
+ }
+
+ /*
+ * Is it a Madge Smart 16/4 PCMCIA Ringnode?
+ */
+
+ {
+ CS_GET_TUPLE_DATA_ARG FAR * ptr =
+ (CS_GET_TUPLE_DATA_ARG FAR *)fp;
+ BYTE FAR * info_ptr;
+ WORD i;
+
+ /*
+ * Find the signature strings in the tuple.
+ * Allow for CS version 2.00 or below. See the TupleData
+ * union in the header file.
+ */
+
+ if (CardServicesVersion <= 0x0200)
+ {
+ info_ptr = ((CS200_CISTPL_VERS_1_DATA FAR *)
+ (ptr->TupleData) )->info;
+ }
+ else
+ {
+ info_ptr = ((CS201_CISTPL_VERS_1_DATA FAR *)
+ (ptr->TupleData) )->info;
+ }
+
+ /*
+ * Compare signature strings. Avoid strcmp, _fstrcmp,
+ * memcmp, _fmemcmp, etc. to make it model independent.
+ */
+
+ for (i = 0; i < MADGE_TPLLV1_INFO_LEN; i++)
+ {
+ if (*(MADGE_TPLLV1_INFO+i) != *(info_ptr+i))
+ {
+ break;
+ }
+ }
+
+
+ if (MADGE_TPLLV1_INFO_LEN == i) /* yes, a madge card. */
+ {
+ if (pcmcia_socket_table[Socket].status ==
+ SOCKET_NOT_INITIALIZED)
+ {
+ pcmcia_socket_table[Socket].status = SOCKET_READY;
+ }
+
+ /*
+ * do nothing if status is SOCKET_READY or
+ * SOCKET_IN_USE.
+ */
+ }
+ }
+
+ break;
+
+ case CLIENT_INFO :
+ {
+ WORD buffer_size =
+ ((CS_CLIENT_INFO FAR *)Buffer)->MaxLen;
+ WORD len_to_copy;
+ WORD i;
+ WORD madge_info_size = sizeof(MADGE_CLIENT_INFO);
+ BYTE FAR * src;
+ BYTE FAR * dest;
+
+ /*
+ * Copy whole client info structure if there is space,
+ * otherwise just fill the buffer supplied.
+ */
+
+ len_to_copy =
+ (buffer_size > madge_info_size) ? madge_info_size :
+ buffer_size;
+
+ src = (BYTE FAR *)&default_client_info;
+ dest = (BYTE FAR *)Buffer;
+
+ for (i = 0; i < len_to_copy; i++)
+ {
+ if (i > 1) /* Skip MaxLen field which is preserved. */
+ {
+ *(dest+i) = *(src+1);
+ }
+ }
+ }
+
+ break;
+
+ case CARD_REMOVAL:
+ /*
+ * Only remove card in use.
+ * Check Socket < MAX_PCMCIA_SOCKETS to prevent access
+ * to out-of-bound array element.
+ */
+
+ if ((Socket < MAX_PCMCIA_SOCKETS) &&
+ (pcmcia_socket_table[Socket].status == SOCKET_IN_USE))
+ {
+ WORD ClientHandle = pcmcia_socket_table[Socket].ClientHandle;
+ WORD io_location = pcmcia_socket_table[Socket].io_location;
+ WORD irq_number = pcmcia_socket_table[Socket].irq_number;
+
+ /*
+ * Call the PCMCIA card services routine to bring it down.
+ */
+
+ hwi_pcmcia_cs_release_config(ClientHandle, Socket);
+ hwi_pcmcia_cs_release_io(ClientHandle, Socket, io_location);
+ hwi_pcmcia_cs_release_irq(ClientHandle, Socket, irq_number);
+ hwi_pcmcia_cs_deregister_client(ClientHandle);
+
+ /*
+ * Update local record.
+ */
+
+ pcmcia_socket_table[Socket].ClientHandle = 0x0000;
+ pcmcia_socket_table[Socket].io_location = 0x0000;
+ pcmcia_socket_table[Socket].irq_number = 0x0000;
+ pcmcia_socket_table[Socket].status =
+ SOCKET_NOT_INITIALIZED;
+ pcmcia_socket_table[Socket].adapter_handle = 0x0000;
+ }
+
+ break;
+
+ default :
+
+ break;
+ }
+
+ return CMD_SUCCESS;
+}
+
+#endif
+
+#endif
+
+/******** End of HWI_PCMC.C ************************************************/
diff --git a/private/ntos/ndis/madge/driver/hwi_pnp.c b/private/ntos/ndis/madge/driver/hwi_pnp.c
new file mode 100644
index 000000000..29e9821db
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/hwi_pnp.c
@@ -0,0 +1,2490 @@
+/****************************************************************************
+*
+* THE HARDWARE INTERFACE MODULE (SMART PNP RINGNODES)
+* ===================================================
+*
+* HWI_PNP.C : Part of the FASTMAC TOOL-KIT (FTK)
+*
+* Copyright (c) Madge Networks Ltd. 1990-1994
+* Developed by AC
+* From code by MF
+* CONFIDENTIAL
+*
+*
+*****************************************************************************
+*
+* The purpose of the Hardware Interface (HWI) is to supply an adapter card
+* independent interface to any driver. It performs nearly all of the
+* functions that involve affecting SIF registers on the adapter cards.
+* This includes downloading code to, initializing, and removing adapters.
+*
+* The HWI_PNP.C module contains the routines specific to the PnP card
+* which are necessary to install an adapter, to initialize an adapter, to
+* remove an adapter, and to handle interrupts on an adapter.
+*
+*****************************************************************************
+
+/*---------------------------------------------------------------------------
+|
+| DEFINITIONS
+|
+---------------------------------------------------------------------------*/
+
+#include "ftk_defs.h"
+
+/*---------------------------------------------------------------------------
+|
+| MODULE ENTRY POINTS
+|
+---------------------------------------------------------------------------*/
+
+#include "ftk_intr.h" /* routines internal to FTK */
+#include "ftk_extr.h" /* routines provided or used by external FTK user */
+
+#ifndef FTK_NO_PNP
+
+/*---------------------------------------------------------------------------
+|
+| LOCAL PROCEDURES
+|
+---------------------------------------------------------------------------*/
+
+local WBOOLEAN
+hwi_pnp_valid_io_location(
+ WORD io_location
+ );
+
+local WBOOLEAN
+hwi_pnp_read_node_address(
+ ADAPTER * adapter
+ );
+
+local WBOOLEAN
+hwi_pnp_valid_irq_channel(
+ ADAPTER * adapter
+ );
+
+local WBOOLEAN
+hwi_pnp_test_for_id(
+ ADAPTER * adapter
+ );
+
+local WORD
+pnp_read_a_word(
+ ADAPTER * adapter,
+ WORD index
+ );
+
+#ifndef FTK_NO_PROBE
+
+local WBOOLEAN
+hwi_pnp_probe_find_card(
+ WORD io_location
+ );
+
+local WORD
+hwi_pnp_probe_get_irq(
+ WORD io_location
+ );
+
+local WORD
+pnp_probe_read_a_word(
+ WORD io_location,
+ WORD index
+ );
+
+#endif
+
+#ifndef FTK_NO_PROBE
+/****************************************************************************
+*
+* hwi_pnp_probe_card
+* ==================
+*
+*
+* PARAMETERS (passed by hwi_probe_adapter) :
+* ==========================================
+*
+* PROBE * resources
+*
+* resources is an array structures used to identify and record specific
+* information about adapters found.
+*
+* UINT length
+*
+* length is the number of structures pointed to by reources.
+*
+* WORD * valid_locations
+*
+* valid_locations is an array of IO locations to examine for the presence
+* of an adapter. For PNP based adapters this should be a subset of
+* {0x3a20, 0x920, 0x940, 0x960, 0x980, 0xa20, 0xa40, 0xa60, 0xa80, 0xb20,
+* 0xb40, 0xb60, 0xb80}.
+*
+* UINT number_locations
+*
+* This is the number of IO locations in the above list.
+*
+* BODY :
+* ======
+*
+* The hwi_pnp_probe_card routine is called by hwi_probe_adapter. It
+* probes the adapter card for information such as DMA channel, IRQ number
+* etc. This information can then be supplied by the user when starting the
+* adapter.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine returns the number of adapters found, or PROBE_FAILURE if
+* there's a problem.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_pnp_probe_card)
+#endif
+
+export UINT
+hwi_pnp_probe_card(
+ PROBE * resources,
+ UINT length,
+ WORD * valid_locations,
+ UINT number_locations
+ )
+{
+ WORD temp_word;
+ UINT adapters_found;
+ UINT i;
+
+ /*
+ * Sanity check the bounds.
+ */
+
+ if (length <= 0 || number_locations <= 0)
+ {
+ return PROBE_FAILURE;
+ }
+
+ /*
+ * Validate the IO locations.
+ */
+
+ for (i = 0; i < number_locations; i++)
+ {
+ if (!hwi_pnp_valid_io_location(valid_locations[i]))
+ {
+ return PROBE_FAILURE;
+ }
+ }
+
+ adapters_found = 0;
+
+ for (i = 0; i < number_locations; i++)
+ {
+ /*
+ * Make sure that we haven't run out of PROBE structures.
+ */
+ if (adapters_found >= length)
+ {
+ return adapters_found;
+ }
+
+ if (hwi_pnp_probe_find_card(valid_locations[i]))
+ {
+
+ /*
+ * Found a card! Now fill out the probe structure.
+ */
+
+ resources[adapters_found].io_location = valid_locations[i];
+ resources[adapters_found].adapter_card_bus_type = ADAPTER_CARD_PNP_BUS_TYPE;
+ resources[adapters_found].adapter_card_type = ADAPTER_CARD_TYPE_16_4_PNP;
+ resources[adapters_found].adapter_card_revision = ADAPTER_CARD_PNP;
+ resources[adapters_found].transfer_mode = PIO_DATA_TRANSFER_MODE;
+
+ /*
+ * Now find out how much RAM we have.
+ */
+
+ temp_word = pnp_probe_read_a_word(
+ valid_locations[i],
+ PNP_HWARE_FEATURES1);
+
+ temp_word &= PNP_DRAM_SIZE_MASK;
+
+ /*
+ * Convert the DRAM size to multiples of bytes.
+ */
+
+ resources[adapters_found].adapter_ram_size = temp_word * 64;
+
+ /*
+ * Now find out what IRQ we are using.
+ */
+
+ resources[adapters_found].interrupt_number = hwi_pnp_probe_get_irq( valid_locations[i]);
+
+ adapters_found++;
+ }
+ }
+
+ return adapters_found;
+
+}
+#endif
+
+/****************************************************************************
+*
+* hwi_pnp_install_card
+* =====================
+*
+*
+* PARAMETERS (passed by hwi_install_adapter) :
+* ============================================
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+* DOWNLOAD_IMAGE * download_image
+*
+* This is the code to be downloaded to the adapter. The image must be of
+* the correct type i.e. must be downloadable into the adapter. If the
+* pointer is 0 downloading is not done.
+*
+*
+* BODY :
+* ======
+*
+* The hwi_pnp_install_card routine is called by hwi_install_adapter. It
+* sets up the adapter card and downloads the required code to it. Firstly,
+* it checks there is a valid adapter at the required IO address. If so it
+* reads the node address from the BIA PROM and sets up and checks numerous
+* on-board registers for correct operation.
+*
+* Then, it halts the EAGLE, downloads the code, restarts the EAGLE and
+* waits up to 3 seconds for a valid bring-up code. If interrupts are
+* required, these are enabled by operating system specific calls.
+* Similarly, operating system calls are used to enable DMA if required. If
+* DMA is not used then the adapter is set up for PIO.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine returns TRUE if it succeeds. If this routine fails (returns
+* FALSE) then a subsequent call to driver_explain_error, with the adapter
+* handle corresponding to the adapter parameter used here, will give an
+* explanation.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_pnp_install_card)
+#endif
+
+export WBOOLEAN
+hwi_pnp_install_card(
+ ADAPTER * adapter,
+ DOWNLOAD_IMAGE * download_image
+ )
+{
+ ADAPTER_HANDLE adapter_handle = adapter->adapter_handle;
+ WORD control_1 = adapter->io_location +
+ PNP_CONTROL_REGISTER_1;
+ WORD config_addr = adapter->io_location +
+ PNP_CONFIG_ADDRESS_REGISTER;
+ WORD config_data = adapter->io_location +
+ PNP_CONFIG_DATA_REGISTER;
+ WORD chip_type;
+ WORD ram_size;
+ BYTE byte;
+ WORD sif_base;
+
+
+ /*
+ * Firstly do some validation on the user supplied adapter details
+ * check that the IO location is valid
+ * if routine fails return failure (error record already filled in)
+ * In theory we shouldnt have to do this - but Chicago has been known
+ * to pass out junk !!
+ */
+
+ if (!hwi_pnp_valid_io_location(adapter->io_location))
+ {
+
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_02_BAD_IO_LOCATION;
+ return FALSE;
+ }
+
+ /*
+ * save IO locations of the SIF registers
+ */
+
+ sif_base = adapter->io_location + PNP_FIRST_SIF_REGISTER;
+
+ adapter->sif_dat = sif_base + EAGLE_SIFDAT;
+ adapter->sif_datinc = sif_base + EAGLE_SIFDAT_INC;
+ adapter->sif_adr = sif_base + EAGLE_SIFADR;
+ adapter->sif_int = sif_base + EAGLE_SIFINT;
+ adapter->sif_acl = sif_base + EAGLE_SIFACL;
+ adapter->sif_adr2 = sif_base + EAGLE_SIFADR;
+ adapter->sif_adx = sif_base + EAGLE_SIFADX;
+ adapter->sif_dmalen = sif_base + EAGLE_DMALEN;
+ adapter->sif_sdmadat = sif_base + EAGLE_SDMADAT;
+ adapter->sif_sdmaadr = sif_base + EAGLE_SDMAADR;
+ adapter->sif_sdmaadx = sif_base + EAGLE_SDMAADX;
+
+ adapter->io_range = PNP_IO_RANGE;
+
+ /*
+ * Make sure this is a real PNP card by reading the ID register
+ */
+
+ if(!hwi_pnp_test_for_id(adapter))
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_05_ADAPTER_NOT_FOUND;
+ return FALSE;
+ }
+
+ /*
+ * You might want to check that we have not already checked for a card
+ * at this address (or its rev3/4 equivalent).
+ * Read the node address for the specified IO location.
+ */
+
+ if (!hwi_pnp_read_node_address(adapter))
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_05_ADAPTER_NOT_FOUND;
+ return FALSE;
+ }
+
+ /*
+ * Check the transfer mode - this is very easy as we only do PIO
+ * (albeit EAGLE PseudoDMA).
+ */
+
+ if (adapter->transfer_mode != PIO_DATA_TRANSFER_MODE)
+ {
+ return FALSE;
+ }
+
+ /*
+ * Check the IRQ channel supplied.
+ * In theory we shouldnt have to do this - but Chicago has been known
+ * to pass out junk !!
+ */
+
+ if (!hwi_pnp_valid_irq_channel(adapter))
+ {
+ /*
+ * Fill in error record and return
+ */
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_03_BAD_INTERRUPT_NUMBER;
+ return FALSE;
+ }
+
+ /*
+ * These things can all be assumed for the pnp.
+ */
+
+ adapter->adapter_card_type = ADAPTER_CARD_TYPE_16_4_PNP;
+ adapter->adapter_card_revision = ADAPTER_CARD_PNP;
+
+ /*
+ * Now find out how much RAM we have.
+ */
+
+ ram_size = pnp_read_a_word(adapter,
+ PNP_HWARE_FEATURES1);
+
+ ram_size &= PNP_DRAM_SIZE_MASK;
+
+ /*
+ * Convert the DRAM size to multiples of bytes.
+ */
+
+ adapter->adapter_ram_size = ram_size * 64;
+ adapter->edge_triggered_ints = TRUE;
+ adapter->EaglePsDMA = TRUE;
+
+ /*
+ * Set the ring speed if required.
+ */
+
+ /*
+ * RCS 2/11/94 Added code to set the adapter->nselout bits so that
+ * the ring speed is fully adopted by the adapter when "hwi_halt_eagle()"
+ * is called.
+ *
+ * Also set the "ringspeed configured" bit if the "set_ring_speed"
+ * feature is specified so that we will use the value.
+ *
+ * Also return an error if the ringspeed hasnt been configured and
+ * the user hasnt specified "set_ring_speed".
+ */
+
+ /*
+ * Is this a C30 based card???
+ * If it is then we can't drive the lowest bit of the vendor config
+ * register as this gives an indication of ring_speed error (Potentially).
+ *
+ */
+
+ chip_type = pnp_read_a_word(
+ adapter,
+ PNP_HWARE_FEATURES3);
+ chip_type &= PNP_C30_MASK;
+
+ /*
+ * First read the current settings
+ */
+
+ sys_outsb(
+ adapter_handle,
+ config_addr,
+ PNP_VENDOR_CONFIG_BYTE);
+
+ byte = sys_insb(
+ adapter_handle,
+ config_data);
+
+ if (adapter->set_ring_speed != 0)
+ {
+ if (adapter->set_ring_speed == 4)
+ {
+ if ( chip_type != PNP_C30 )
+ {
+ /*
+ * Set bits to select 4mbits as the ring speed
+ */
+ byte |= (PNP_VENDOR_CONFIG_4MBITS + PNP_VENDOR_CONFIG_PXTAL);
+ }
+ else
+ {
+ byte |= PNP_VENDOR_CONFIG_4MBITS;
+ }
+ }
+ else if (adapter->set_ring_speed == 16)
+ {
+ if ( chip_type != PNP_C30 )
+ {
+ /*
+ * Clear bits to select 16mbits as the ring speed
+ */
+
+ byte &= ~(PNP_VENDOR_CONFIG_4MBITS +
+ PNP_VENDOR_CONFIG_PXTAL);
+ }
+ else
+ {
+ byte &= ~(PNP_VENDOR_CONFIG_4MBITS);
+ }
+ }
+
+ /*
+ * Show ring speed as having been configured
+ */
+
+ byte |= PNP_VENDOR_CONFIG_RSVALID;
+
+ /*
+ * and write it back to the card
+ */
+
+ sys_outsb(
+ adapter_handle,
+ config_data,
+ byte);
+ }
+
+ /*
+ * Use the value in "byte" to set the NSELOUT bits or it will still
+ * only run at 16 !!
+ */
+
+ if (byte & PNP_VENDOR_CONFIG_RSVALID)
+ {
+ if (byte & PNP_VENDOR_CONFIG_4MBITS)
+ {
+ adapter->nselout_bits = PNP_RING_SPEED_4;
+ }
+ else
+ {
+ adapter->nselout_bits = PNP_RING_SPEED_16;
+ }
+ }
+ else
+ {
+ /*
+ * The user MUST configure the RING SPEED before we will let him use
+ * the card.
+ * He can either run the CONFIG util or use the FORCE4/FORCE16
+ * mechanism.
+ * Fill in error record and return
+ */
+
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_0E_NO_SPEED_SELECTED;
+
+ return FALSE;
+ }
+
+ /*
+ * Bring adapter out of reset state (ensure that SCS is zero before
+ * doing this). If active float channel ready is set in the Plug and
+ * Play hardware flags then set the PNP_CHRDY_ACTIVE bit.
+ */
+
+ byte = PNP_CTRL1_NSRESET;
+
+ if ((pnp_read_a_word(
+ adapter,
+ PNP_HWARE_PNP_FLAGS) & PNP_ACTIVE_FLOAT_CHRDY) != 0)
+ {
+ byte |= PNP_CTRL1_CHRDY_ACTIVE;
+ }
+
+ sys_outsb(
+ adapter_handle,
+ control_1,
+ byte);
+
+ /*
+ * Halt the Eagle prior to downloading the MAC code - this will also
+ * write the ringspeed bits into the SIFACL register.
+ */
+
+ hwi_halt_eagle(adapter);
+
+ /*
+ * download code to adapter
+ * view download image as a sequence of download records
+ * pass address of routine to set up DIO addresses on ATULA cards
+ * if routine fails return failure (error record already filled in)
+ */
+
+ if (!hwi_download_code(
+ adapter,
+ (DOWNLOAD_RECORD *) download_image,
+ hwi_pnp_set_dio_address))
+ {
+ return FALSE;
+ }
+
+ /*
+ * Restart the Eagle to initiate bring up diagnostics.
+ */
+
+ hwi_start_eagle(adapter);
+
+ /*
+ * wait for a valid bring up code, may wait 3 seconds
+ * if routine fails return failure (error record already filled in)
+ */
+
+ if (!hwi_get_bring_up_code(adapter))
+ {
+ return FALSE;
+ }
+
+ /*
+ * set DIO address to point to EAGLE DATA page 0x10000L
+ */
+
+ hwi_pnp_set_dio_address(
+ adapter,
+ DIO_LOCATION_EAGLE_DATA_PAGE);
+
+ /*
+ * set maximum frame size from the ring speed
+ */
+
+ adapter->max_frame_size = hwi_get_max_frame_size(adapter);
+
+ /*
+ * Get the ring speed.
+ */
+
+ adapter->ring_speed = hwi_get_ring_speed(adapter);
+
+ /*
+ * if not in polling mode then set up interrupts
+ * interrupts_on field is used when disabling interrupts for adapter
+ */
+
+ if (adapter->interrupt_number != POLLING_INTERRUPTS_MODE)
+ {
+ adapter->interrupts_on =
+ sys_enable_irq_channel(adapter_handle,
+ adapter->interrupt_number);
+
+ /*
+ * if fail enable irq channel then fill in error record and return
+ */
+ if (!adapter->interrupts_on)
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_0B_FAIL_IRQ_ENABLE;
+ return FALSE;
+ }
+ }
+ else
+ {
+ adapter->interrupts_on = TRUE;
+ }
+
+ /*
+ * return successfully
+ */
+
+ return TRUE;
+}
+
+
+/****************************************************************************
+*
+* hwi_pnp_interrupt_handler
+* ==========================
+*
+*
+* PARAMETERS (passed by hwi_interrupt_entry) :
+* ============================================
+*
+* ADAPTER_HANDLE adapter_handle
+*
+* The adapter handle for the adapter so it can later be passed to the user
+* supplied user_receive_frame or user_completed_srb routine.
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+*
+* BODY :
+* ======
+*
+* The hwi_pnp_interrupt_handler routine is called, when an interrupt
+* occurs, by hwi_interrupt_entry. It checks to see if a particular card
+* has interrupted. The interrupt could be generated by the SIF or by the
+* ATULA in order to do a PIO data transfer. Note it could in fact be the
+* case that no interrupt has occured on the particular adapter being
+* checked.
+*
+* On SIF interrupts, the interrupt is acknowledged and cleared. The value
+* in the SIF interrupt register is recorded in order to pass it to the
+* driver_interrupt_entry routine (along with the adapter details).
+*
+* On PIO interrupts, the length, direction and physical address of the
+* transfer is determined. A system provided routine is called to do the
+* data transfer itself. Note the EAGLE thinks it is doing a DMA transfer
+* - it is the ATULA which allows us to do it via in/out instructions. Also
+* note that the IO location for the PIO is mapped onto the location of the
+* EAGLE SIFDAT register - the PIO does not actually use the SIFDAT
+* register so it's value is not effected by this routine.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine always successfully completes.
+*
+****************************************************************************/
+
+#ifdef FTK_IRQ_FUNCTION
+#pragma FTK_IRQ_FUNCTION(hwi_pnp_interrupt_handler)
+#endif
+
+export void
+hwi_pnp_interrupt_handler(
+ ADAPTER * adapter
+ )
+{
+ WORD sifacl;
+ WORD sifint_value;
+ WORD sifint_tmp;
+ WBOOLEAN sifint_occurred = FALSE;
+ WBOOLEAN pioint_occurred = FALSE;
+ BYTE FAR * pio_virtaddr;
+ WORD lo_word;
+ DWORD hi_word;
+ WORD pio_len_bytes;
+ WBOOLEAN pio_from_adapter;
+ ADAPTER_HANDLE adapter_handle;
+
+ adapter_handle = adapter->adapter_handle;
+
+ /*
+ * inform system about the IO ports we are going to access
+ * eanble maximum number of IO locations used by any adapter card
+ * do this so at driver level can disable IO not knowing adapter type
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ /*
+ * check for SIF interrupt or PIO interrupt
+ */
+
+ /*
+ * Mask off any further interrupts while we read SIFINT (note that this
+ * does not mask off Pseudo DMA interrupts)
+ */
+
+ macro_clearw_bit(
+ adapter_handle,
+ adapter->sif_acl,
+ EAGLE_SIFACL_SINTEN
+ );
+
+ sifint_value = sys_insw(adapter_handle, adapter->sif_int);
+ do
+ {
+ sifint_tmp = sifint_value;
+ sifint_value = sys_insw(adapter_handle, adapter->sif_int);
+ }
+ while (sifint_tmp != sifint_value);
+
+ if ((sifint_value & EAGLE_SIFINT_SYSTEM) != 0)
+ {
+ /*
+ * SIF interrupt has occurred
+ * SRB free, adapter check or received frame interrupt
+ */
+
+ sifint_occurred = TRUE;
+
+ /*
+ * clear EAGLE_SIFINT_HOST_IRQ to acknowledge interrupt at SIF
+ */
+
+ sys_outsw(adapter_handle, adapter->sif_int, 0);
+ }
+
+ sifacl = sys_insw(adapter_handle, adapter->sif_acl);
+
+ if ((sifacl & EAGLE_SIFACL_SWHRQ) != 0)
+ {
+ /*
+ * PIO interrupt has occurred
+ * data transfer to/from adapter interrupt
+ */
+
+ pioint_occurred = TRUE;
+
+ macro_setw_bit(
+ adapter_handle,
+ adapter->sif_acl,
+ EAGLE_SIFACL_SWHLDA
+ );
+
+ /*
+ * determine what direction the data transfer is to take place in
+ */
+
+ pio_from_adapter = sys_insw(
+ adapter_handle,
+ adapter->sif_acl
+ ) & EAGLE_SIFACL_SWDDIR;
+
+ pio_len_bytes = sys_insw(
+ adapter_handle,
+ adapter->sif_dmalen
+ );
+
+ lo_word = sys_insw(
+ adapter_handle,
+ adapter->sif_sdmaadr
+ );
+
+ hi_word = (DWORD) sys_insw(
+ adapter_handle,
+ adapter->sif_sdmaadx
+ );
+
+ pio_virtaddr = (BYTE FAR *) ((hi_word << 16) | ((DWORD) lo_word));
+
+ /*
+ * do the actual data transfer
+ * note that Fastmac only copies whole WORDs to DWORD boundaries
+ * FastmacPlus, however, can transfer any length to any address.
+ */
+
+ if (pio_from_adapter)
+ {
+ /*
+ * transfer into host memory from adapter
+ */
+
+ /*
+ * transfer whole WORDs to Fastmac receive buffer
+ * NOT FORGETTING the possibility of a trailing byte.
+ */
+
+ sys_rep_insw(
+ adapter_handle,
+ adapter->sif_sdmadat,
+ pio_virtaddr,
+ (WORD) (pio_len_bytes >> 1)
+ );
+
+ if (pio_len_bytes % 2)
+ {
+ /*
+ * Finally transfer any trailing byte.
+ */
+
+ *(pio_virtaddr + pio_len_bytes - 1) =
+ sys_insb(adapter_handle, adapter->sif_sdmadat);
+ }
+ }
+ else
+ {
+ /*
+ * transfer into adapter memory from the host
+ */
+
+ sys_rep_outsw(
+ adapter_handle,
+ adapter->sif_sdmadat,
+ pio_virtaddr,
+ (WORD) (pio_len_bytes >> 1)
+ );
+
+ if (pio_len_bytes % 2)
+ {
+ sys_outsb(
+ adapter_handle,
+ adapter->sif_sdmadat,
+ *(pio_virtaddr+pio_len_bytes-1)
+ );
+ }
+ }
+ }
+
+#ifndef FTK_NO_CLEAR_IRQ
+
+ if (sifint_occurred || pioint_occurred)
+ {
+ /*
+ * acknowledge/clear interrupt at interrupt controller
+ */
+
+ sys_clear_controller_interrupt(
+ adapter_handle,
+ adapter->interrupt_number);
+ }
+
+#endif
+
+ if (sifint_occurred)
+ {
+ /*
+ * call driver with details of SIF interrupt
+ */
+
+ driver_interrupt_entry(adapter_handle, adapter, sifint_value);
+ }
+
+ /*
+ * Read SIFACL until the SWHLDA bit has cleared.
+ */
+
+ do
+ {
+ sifacl = sys_insw(adapter_handle, adapter->sif_acl);
+ }
+ while ((sifacl & EAGLE_SIFACL_SWHLDA) != 0);
+
+ /*
+ * Now set SINTEN in SIFACL to regenerate interrupts.
+ */
+
+ sys_outsw(
+ adapter_handle,
+ adapter->sif_acl,
+ (WORD) (sifacl | EAGLE_SIFACL_SINTEN)
+ );
+
+ /*
+ * let system know we have finished accessing the IO ports
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io( adapter );
+#endif
+}
+
+
+/****************************************************************************
+*
+* hwi_pnp_remove_card
+* ====================
+*
+*
+* PARAMETERS (passed by hwi_remove_adapter) :
+* ===========================================
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+*
+* BODY :
+* ======
+*
+* The hwi_pnp_remove_card routine is called by hwi_remove_adapter. It
+* disables interrupts if they are being used. It also resets the adapter.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine always successfully completes.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(hwi_pnp_remove_card)
+#endif
+
+export void
+hwi_pnp_remove_card(
+ ADAPTER * adapter
+ )
+{
+ ADAPTER_HANDLE adapter_handle = adapter->adapter_handle;
+ WORD control_1 = adapter->io_location +
+ PNP_CONTROL_REGISTER_1;
+ WORD sifacl;
+
+ /*
+ * interrupt must be disabled at adapter before unpatching interrupt
+ * even in polling mode we must turn off interrupts at adapter
+ */
+
+ sifacl = sys_insw(adapter_handle, adapter->sif_acl);
+ sifacl = (sifacl & ~(EAGLE_SIFACL_PSDMAEN | EAGLE_SIFACL_SINTEN));
+
+ sys_outsw(adapter_handle,
+ adapter->sif_acl,
+ sifacl);
+
+ if (adapter->interrupts_on)
+ {
+ if (adapter->interrupt_number != POLLING_INTERRUPTS_MODE)
+ {
+ sys_disable_irq_channel(
+ adapter_handle,
+ adapter->interrupt_number);
+ }
+
+ adapter->interrupts_on = FALSE;
+ }
+
+
+ /*
+ * perform adapter reset, set PNP_CTRL1_NSRESET low
+ */
+
+ sys_outsb(adapter_handle, control_1, !PNP_CTRL1_NSRESET);
+}
+
+
+/****************************************************************************
+*
+* hwi_atula_set_dio_address
+* =========================
+*
+* The hwi_atula_set_dio_address routine is used, with ATULA cards, for
+* putting a 32 bit DIO address into the SIF DIO address and extended DIO
+* address registers. Note that the extended address register should be
+* loaded first.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_pnp_set_dio_address)
+#endif
+
+export void
+hwi_pnp_set_dio_address(
+ ADAPTER * adapter,
+ DWORD dio_address
+ )
+{
+ ADAPTER_HANDLE adapter_handle = adapter->adapter_handle;
+ WORD sif_dio_adr = adapter->sif_adr;
+ WORD sif_dio_adrx = adapter->sif_adx;
+
+ /*
+ * load extended DIO address register with top 16 bits of address
+ * always load extended address register first
+ */
+
+ sys_outsw(adapter_handle, sif_dio_adrx, (WORD)(dio_address >> 16));
+
+ /*
+ * load DIO address register with low 16 bits of address
+ */
+
+ sys_outsw(adapter_handle, sif_dio_adr, (WORD)(dio_address & 0x0000FFFF));
+
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| LOCAL PROCEDURES
+|
+---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+|
+| hwi_pnp_read_node_address
+| ==========================
+|
+| The hwi_pnp_read_node_address routine reads in the node address from
+| the BIA, and checks that it is a valid Madge node address.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_pnp_read_node_address)
+#endif
+
+local WBOOLEAN
+hwi_pnp_read_node_address(
+ ADAPTER * adapter
+ )
+{
+ WORD ioport = adapter->io_location;
+
+ adapter->permanent_address.byte[0] = 0;
+ adapter->permanent_address.byte[1] = 0;
+ adapter->permanent_address.byte[2] = (BYTE) pnp_read_a_word(adapter, 15);
+ adapter->permanent_address.byte[3] = (BYTE) pnp_read_a_word(adapter, 14);
+ adapter->permanent_address.byte[4] = (BYTE) pnp_read_a_word(adapter, 13);
+ adapter->permanent_address.byte[5] = (BYTE) pnp_read_a_word(adapter, 12);
+
+ return (adapter->permanent_address.byte[2] == MADGE_NODE_BYTE_2);
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| hwi_pnp_valid_io_location
+| ==========================
+|
+| The hwi_pnp_valid_io_location routine checks to see if the user has
+| supplied a valid IO location for a PNP adapter card.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_pnp_valid_io_location)
+#endif
+
+local WBOOLEAN
+hwi_pnp_valid_io_location(
+ WORD io_location
+ )
+{
+ WBOOLEAN io_valid;
+
+ switch (io_location)
+ {
+
+ case 0x1A20 :
+ case 0x2A20 :
+ case 0x3A20 :
+
+ /*
+ * The following are needed coz Chicago won't configure our
+ * PNP card at xA20 (a problem with Chicago !??)
+ */
+
+ case 0x0140 : /* In case CHICAGO cant find a free one */
+
+ /*
+ * It (Chicago) also wont allow cards to be at a 10 bit alias
+ * of each other ! (despite the fact we set the bit that says
+ * we fully decode all sixteen bits of the address !!)
+ */
+
+ case 0x0920 :
+ case 0x0940 :
+ case 0x0960 :
+ case 0x0980 :
+
+ case 0x0A20 :
+ case 0x0A40 :
+ case 0x0A60 :
+ case 0x0A80 :
+ case 0x0AA0 :
+
+ case 0x0B20 :
+ case 0x0B40 :
+ case 0x0B60 :
+ case 0x0B80 :
+
+ /*
+ * These are the valid user supplied io locations
+ */
+ io_valid = TRUE;
+ break;
+
+
+ default :
+
+ /*
+ * Anything else is invalid
+ */
+ io_valid = FALSE;
+ break;
+ }
+
+ return io_valid;
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| hwi_pnp_valid_irq_channel
+| ==========================
+|
+| The hwi_pnp_valid_irq_channel routine checks to see if the user has
+| supplied a valid interrupt number for a PNP
+|
+| If the user has stated that polling mode is to be used, then this is
+| always okay. If not, then a check is made that the user given interrupt
+| number is a valid number for the card type.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_pnp_valid_irq_channel)
+#endif
+
+local WBOOLEAN
+hwi_pnp_valid_irq_channel(
+ ADAPTER * adapter
+ )
+{
+ WBOOLEAN int_valid;
+
+ /*
+ * assume that interrupt number is valid
+ */
+
+ int_valid = TRUE;
+
+ /*
+ * no need to do any check on interrupt number if in polling mode
+ */
+
+ if (adapter->interrupt_number != POLLING_INTERRUPTS_MODE)
+ {
+ /*
+ * Can only check that the interrupt number given is valid
+ */
+
+ switch (adapter->interrupt_number)
+ {
+ case 2 :
+ case 3 :
+ case 7 :
+ case 9 :
+ case 10 :
+ case 11 :
+ case 15 :
+ break;
+
+ default :
+ int_valid = FALSE;
+ break;
+
+ }
+ }
+
+ if (!int_valid)
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_03_BAD_INTERRUPT_NUMBER;
+ }
+
+ return int_valid;
+}
+
+
+#ifndef FTK_NO_PROBE
+/*---------------------------------------------------------------------------
+|
+| hwi_pnp_probe_find_card
+| =======================
+|
+| The hwi_pnp_find_card checks if a PNP card is at a particular location.
+| This is called by the probe routines.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_pnp_probe_find_card)
+#endif
+
+local WBOOLEAN
+hwi_pnp_probe_find_card(
+ WORD io_location
+ )
+{
+ WORD id_reg = io_location + PNP_ID_REGISTER;
+ WORD i;
+
+ /*
+ * Search for leading 'm'
+ */
+
+ for (i = 0; i < 4; i++)
+ {
+ if (sys_insb(0 , id_reg) == 'm')
+ {
+ /*
+ * Next byte must be 'd'.
+ */
+
+ if (sys_insb(0 , id_reg) == 'd')
+ {
+ return TRUE;
+ }
+ }
+ }
+
+ /*
+ * PNP ID not seen, or incorrect!
+ */
+
+ return FALSE;
+}
+
+/*---------------------------------------------------------------------------
+|
+| hwi_pnp_probe_get_irq
+| =====================
+|
+| The hwi_pnp_gwt_irq gets the Interrupt used by a plug and play card.
+| This is called by the probe routines.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_pnp_probe_get_irq)
+#endif
+
+local WORD
+hwi_pnp_probe_get_irq(
+ WORD io_location
+ )
+{
+ WORD interrupt;
+
+ sys_probe_outsb(
+ (io_location + PNP_CONFIG_ADDRESS_REGISTER),
+ PNP_VENDOR_CONFIG_IRQ);
+
+ interrupt = (WORD)sys_probe_insb(
+ (io_location+PNP_CONFIG_DATA_REGISTER));
+
+ return interrupt;
+}
+
+
+
+#endif
+
+/*---------------------------------------------------------------------------
+|
+| hwi_pnp_test_for_id
+| ===================
+|
+| The hwi_pnp_test_for_id routine confirms that a real PNP card exists
+| at the supplied addreess by checking the contents of the ID register.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_pnp_test_for_id)
+#endif
+
+local WBOOLEAN
+hwi_pnp_test_for_id(
+ ADAPTER * adapter
+ )
+{
+ ADAPTER_HANDLE adapter_handle = adapter->adapter_handle;
+ WORD id_reg = adapter->io_location + PNP_ID_REGISTER;
+ WORD i;
+
+ /*
+ * Search for leading 'm'
+ */
+ for (i = 0; i < 4; i++)
+ {
+ if (sys_insb(adapter_handle, id_reg) == 'm')
+ {
+ /*
+ * Next byte must be 'd'
+ */
+ if (sys_insb(adapter_handle, id_reg) == 'd')
+ {
+ return TRUE;
+ }
+ break;
+ }
+ }
+
+ /*
+ * PNP ID not seen, or incorrect.
+ */
+ return FALSE;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+#ifndef FTK_NO_PROBE
+
+/************************************************************************
+ *
+ * Support routines for the serial device fitted to the Plug aNd Play
+ * cards. To be used by the probe functions.
+ *
+ ************************************************************************/
+
+local void pnp_probe_delay( WORD io_location );
+local void pnp_probe_set_clk( WORD io_location );
+local void pnp_probe_clr_clk( WORD io_location );
+local void pnp_probe_twitch_clk( WORD io_location );
+local void pnp_probe_start_bit( WORD io_location );
+local void pnp_probe_stop_bit( WORD io_location );
+local WBOOLEAN pnp_probe_wait_ack( WORD io_location );
+local WBOOLEAN pnp_probe_dummy_wait_ack(WORD io_location );
+
+
+/************************************************************************
+ * Read a byte from the control register for the specified adapter.
+ *
+ * Inputs : Adapter structure.
+ *
+ * Outputs : Value read from control register.
+ ***********************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pnp_probe_read_ctrl)
+#endif
+
+local WORD pnp_probe_read_ctrl( WORD io_location )
+{
+ return sys_probe_insb( io_location + PNP_CON_REG_OFFSET );
+}
+
+
+/************************************************************************
+ * Write a byte to the control register for the specified adapter.
+ *
+ * Inputs : Adapter structure.
+ * The data to be written.
+ *
+ * Outputs : None.
+ ***********************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pnp_probe_write_ctrl)
+#endif
+
+local void pnp_probe_write_ctrl( WORD io_location, WORD data)
+{
+ sys_probe_outsb( io_location + PNP_CON_REG_OFFSET, (BYTE)data );
+}
+
+
+/************************************************************************
+ * Delay to allow for serial device timing issues
+ *
+ * Inputs : Adapter structure
+ *
+ * Outputs : None
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pnp_probe_delay)
+#endif
+
+local void pnp_probe_delay( WORD io_location )
+{
+ UINT i;
+
+ for (i = 0; i < PNP_DELAY_CNT; i++)
+ {
+ sys_probe_insb( io_location );
+ }
+}
+
+/************************************************************************
+ * Set the serial device clock bit
+ *
+ * Inputs : Adapter structure
+ *
+ * Outputs : None
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pnp_probe_set_clk)
+#endif
+
+local void pnp_probe_set_clk( WORD io_location )
+{
+ WORD temp;
+
+ temp = pnp_probe_read_ctrl( io_location );
+ temp |= PNP_SSK;
+
+ pnp_probe_write_ctrl( io_location, temp);
+
+ pnp_probe_delay( io_location );
+}
+
+
+/************************************************************************
+ * Clears the serial device clock bit
+ *
+ * Inputs : Adapter structure
+ *
+ * Outputs : None
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pnp_probe_clr_clk)
+#endif
+
+local void pnp_probe_clr_clk( WORD io_location )
+{
+ WORD temp;
+
+ temp = pnp_probe_read_ctrl( io_location );
+ temp &= ~PNP_SSK;
+
+ pnp_probe_write_ctrl( io_location, temp);
+
+ pnp_probe_delay( io_location );
+}
+
+
+/************************************************************************
+ * Puts the serial device data port into OUTPUT mode
+ *
+ * Inputs : Adapter structure
+ *
+ * Outputs : None
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pnp_probe_set_eeden)
+#endif
+
+local void pnp_probe_set_eeden( WORD io_location )
+{
+ WORD temp;
+
+ temp = pnp_probe_read_ctrl( io_location );
+ temp |= PNP_EEDEN;
+
+ pnp_probe_write_ctrl( io_location , temp);
+
+ pnp_probe_delay( io_location );
+}
+
+
+/************************************************************************
+ * Puts the serial device data port into INPUT mode
+ *
+ * Inputs : Adapter structure
+ *
+ * Outputs : None
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pnp_probe_clr_eeden)
+#endif
+
+local void pnp_probe_clr_eeden( WORD io_location )
+{
+ WORD temp;
+
+ temp = pnp_probe_read_ctrl( io_location );
+ temp &= ~PNP_EEDEN;
+
+ pnp_probe_write_ctrl( io_location, temp);
+
+ pnp_probe_delay( io_location );
+}
+
+
+/************************************************************************
+ * Sets the clears the serial device clock bit to strobe data into device
+ *
+ * Inputs : Adapter structure
+ *
+ * Outputs : None
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pnp_probe_twitch_clk)
+#endif
+
+local void pnp_probe_twitch_clk( WORD io_location )
+{
+ pnp_probe_set_clk( io_location );
+ pnp_probe_clr_clk( io_location );
+}
+
+
+/************************************************************************
+ * Sends a start bit to the serial device.
+ *
+ * This is done by a 1 to 0 transition of the data bit while the clock
+ * bit it 1.
+ *
+ * Inputs : Adapter structure
+ *
+ * Outputs : None
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pnp_probe_start_bit)
+#endif
+
+local void pnp_probe_start_bit( WORD io_location )
+{
+ WORD temp;
+
+ temp = pnp_probe_read_ctrl( io_location );
+ temp &= ~(PNP_EEDO + PNP_EEDEN + PNP_SSK);
+ temp |= (PNP_EEDO + PNP_EEDEN);
+
+ pnp_probe_write_ctrl( io_location, temp);
+
+ pnp_probe_delay( io_location );
+
+ temp |= PNP_SSK;
+
+ pnp_probe_write_ctrl( io_location, temp);
+
+ pnp_probe_delay( io_location );
+
+ temp &= ~PNP_EEDO;
+
+ pnp_probe_write_ctrl( io_location , temp);
+
+ pnp_probe_delay( io_location );
+
+ temp &= ~(PNP_EEDO + PNP_EEDEN + PNP_SSK);
+
+ pnp_probe_write_ctrl( io_location , temp);
+
+ pnp_probe_delay( io_location );
+}
+
+
+/************************************************************************
+ * Sends a stop bit to the serial device.
+ *
+ * This is done by a 0 to 1 transition of the data bit while the clock
+ * bit it 1.
+ *
+ * Inputs : Adapter structure
+ *
+ * Outputs : None
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pnp_probe_stop_bit)
+#endif
+
+local void pnp_probe_stop_bit( WORD io_location )
+{
+ WORD temp;
+
+ temp = pnp_probe_read_ctrl( io_location );
+ temp &= ~(PNP_EEDO + PNP_EEDEN + PNP_SSK);
+ temp |= (PNP_EEDEN);
+
+ pnp_probe_write_ctrl( io_location, temp);
+
+ pnp_probe_delay( io_location );
+
+ temp |= PNP_SSK;
+
+ pnp_probe_write_ctrl(io_location, temp);
+
+ pnp_probe_delay(io_location);
+
+ temp |= PNP_EEDO;
+
+ pnp_probe_write_ctrl(io_location, temp);
+
+ pnp_probe_delay(io_location);
+
+ temp &= ~(PNP_EEDO + PNP_EEDEN + PNP_SSK);
+
+ pnp_probe_write_ctrl(io_location, temp);
+
+ pnp_probe_delay(io_location);
+}
+
+
+/************************************************************************
+ * Waits for the serial device to say its accepted the last cmd/data
+ *
+ * Inputs : Adapter structure
+ *
+ * Outputs : TRUE if OK, FALSE if it timed out
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pnp_probe_wait_ack)
+#endif
+
+local WBOOLEAN pnp_probe_wait_ack(WORD io_location)
+{
+ WORD temp;
+ WORD i;
+
+ temp = pnp_probe_read_ctrl(io_location);
+ temp &= ~(PNP_EEDO + PNP_EEDEN + PNP_SSK);
+
+ pnp_probe_write_ctrl(io_location, temp);
+
+ pnp_probe_delay(io_location);
+
+ for (i = 0; i < PNP_WAIT_CNT; i++)
+ {
+ pnp_probe_set_clk(io_location);
+
+ temp = pnp_probe_read_ctrl(io_location);
+
+ pnp_probe_clr_clk(io_location);
+
+ if (!(temp & PNP_EEDO))
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+/************************************************************************
+ * Waits for the serial device to say its passed the last of the data to
+ * be read.
+ *
+ * Inputs : Adapter structure
+ *
+ * Outputs : TRUE if OK, FALSE if it timed out
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pnp_probe_dummy_wait_ack)
+#endif
+
+local WBOOLEAN pnp_probe_dummy_wait_ack(WORD io_location)
+{
+ WORD temp;
+ WORD i;
+
+ temp = pnp_probe_read_ctrl(io_location);
+ temp &= ~(PNP_EEDO + PNP_EEDEN + PNP_SSK);
+
+ pnp_probe_write_ctrl(io_location, temp);
+
+ pnp_probe_delay(io_location);
+
+ for (i = 0; i < PNP_WAIT_CNT ; i++)
+ {
+ pnp_probe_set_clk(io_location);
+
+ temp = pnp_probe_read_ctrl(io_location);
+
+ pnp_probe_clr_clk(io_location);
+
+ if (temp & PNP_EEDO)
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+/************************************************************************
+ * Writes a bit to the serial device
+ * be read.
+ *
+ * Inputs : Adapter structure
+ * The data bit to be written
+ *
+ * Outputs : TRUE if OK, FALSE if it timed out
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pnp_probe_write_data)
+#endif
+
+local void pnp_probe_write_data(WORD io_location, WORD data)
+{
+ WORD temp;
+
+ temp = pnp_probe_read_ctrl(io_location);
+ temp &= ~(PNP_EEDO);
+ temp |= (data & 0x0080) >> 6;
+
+ pnp_probe_write_ctrl(io_location, temp);
+
+ pnp_probe_delay(io_location);
+}
+
+
+/************************************************************************
+ *
+ * Routine to read a byte from the serial device fitted to the Plug aNd Play
+ * cards.
+ *
+ * Inputs : Adapter structure.
+ * Offset (address) in the serial device to read
+ *
+ * Outputs : A word with the interstng byte in the LSB
+ *
+ * RCS 22/07/94
+ *
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pnp_probe_read_a_word)
+#endif
+
+local WORD pnp_probe_read_a_word(WORD io_location, WORD index)
+{
+ WORD temp;
+ WORD data_byte = 0;
+ WORD i;
+
+ /*
+ * Wake up the device
+ */
+ pnp_probe_start_bit(io_location);
+
+ /*
+ * Set data 'OUTPUT' mode
+ */
+ pnp_probe_set_eeden(io_location);
+
+ /*
+ * Send WRITE CMD - a dummy really to allow us to set the READ address!
+ */
+ temp = PNP_WRITE_CMD;
+
+ /*
+ * MSB first !
+ */
+ for (i = 0; i < 8; i++)
+ {
+ pnp_probe_write_data(io_location, temp);
+ pnp_probe_twitch_clk(io_location);
+ temp = temp << 1;
+ }
+
+ if (!pnp_probe_wait_ack(io_location))
+ {
+ /*
+ * Return sommat invalid if it timed out !
+ */
+ return 0xffff;
+ }
+
+ /*
+ * Set data 'OUTPUT' mode
+ */
+ pnp_probe_set_eeden(io_location);
+
+ /*
+ * Send Address in ROM
+ */
+ temp = index;
+
+ /*
+ * MSB first !
+ */
+ for (i = 0; i < 8; i++)
+ {
+ pnp_probe_write_data(io_location, temp);
+ pnp_probe_twitch_clk(io_location);
+ temp = temp << 1;
+ }
+
+ if (!pnp_probe_wait_ack(io_location))
+ {
+ /*
+ * Return sommat invalid if it timed out !
+ */
+ return 0xffff;
+ }
+
+ pnp_probe_start_bit(io_location);
+
+ /*
+ * Set data 'OUTPUT' mode
+ */
+ pnp_probe_set_eeden(io_location);
+
+ /*
+ * Send READ CMD
+ */
+ temp = PNP_READ_CMD;
+
+ /*
+ * MSB first !
+ */
+ for (i = 0; i < 8 ;i++)
+ {
+ pnp_probe_write_data(io_location, temp);
+ pnp_probe_twitch_clk(io_location);
+ temp = temp << 1;
+ }
+
+ if (!pnp_probe_wait_ack(io_location))
+ {
+ /*
+ * Return sommat invalid if it timed out !
+ */
+ return 0xffff;
+ }
+
+ /*
+ * Set data 'INPUT' mode
+ */
+ pnp_probe_clr_eeden(io_location);
+
+ /*
+ * Now read the serial data - MSB first !
+ */
+ for (i = 0; i < 8 ;i++)
+ {
+ pnp_probe_set_clk(io_location);
+
+ temp = pnp_probe_read_ctrl(io_location);
+
+ pnp_probe_clr_clk(io_location);
+
+ temp &= PNP_EEDO;
+ temp = temp >> 1;
+ data_byte = data_byte << 1;
+ data_byte &= 0xfffe;
+ data_byte |= temp;
+ }
+
+ if (!pnp_probe_dummy_wait_ack(io_location))
+ {
+ /*
+ * Return sommat invalid if it timed out !
+ */
+
+ return 0xffff;
+ }
+
+ pnp_probe_stop_bit(io_location);
+
+ return data_byte;
+}
+
+#endif
+
+/************************************************************************
+ *
+ * Support routines for the serial device fitted to the Plug aNd Play
+ * cards.
+ *
+ * RCS 22/07/94
+ *
+ ************************************************************************/
+
+
+local void pnp_delay(ADAPTER *);
+local void pnp_set_clk(ADAPTER *);
+local void pnp_clr_clk(ADAPTER *);
+local void pnp_twitch_clk(ADAPTER *);
+local void pnp_start_bit(ADAPTER *);
+local void pnp_stop_bit(ADAPTER *);
+local WBOOLEAN pnp_wait_ack(ADAPTER *);
+local WBOOLEAN pnp_dummy_wait_ack(ADAPTER *);
+local void pnp_write_data(ADAPTER *, WORD);
+
+
+/************************************************************************
+ * Read a byte from the control register for the specified adapter.
+ *
+ * Inputs : Adapter structure.
+ *
+ * Outputs : Value read from control register.
+ ***********************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pnp_read_ctrl)
+#endif
+
+local WORD pnp_read_ctrl(ADAPTER * adapter)
+{
+ return sys_insb(
+ adapter->adapter_handle,
+ (WORD) (adapter->io_location + PNP_CON_REG_OFFSET)
+ );
+}
+
+
+/************************************************************************
+ * Write a byte to the control register for the specified adapter.
+ *
+ * Inputs : Adapter structure.
+ * The data to be written.
+ *
+ * Outputs : None.
+ ***********************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pnp_write_ctrl)
+#endif
+
+local void pnp_write_ctrl(ADAPTER * adapter, WORD data)
+{
+ sys_outsb(
+ adapter->adapter_handle,
+ (WORD) (adapter->io_location + PNP_CON_REG_OFFSET),
+ (BYTE) data
+ );
+}
+
+
+/************************************************************************
+ * Delay to allow for serial device timing issues
+ *
+ * Inputs : Adapter structure
+ *
+ * Outputs : None
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pnp_delay)
+#endif
+
+local void pnp_delay(ADAPTER * adapter)
+{
+ WORD i;
+
+ for (i = 0; i < PNP_DELAY_CNT; i++)
+ {
+ sys_insb(adapter->adapter_handle, adapter->io_location);
+ }
+}
+
+
+/************************************************************************
+ * Set the serial device clock bit
+ *
+ * Inputs : Adapter structure
+ *
+ * Outputs : None
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pnp_set_clk)
+#endif
+
+local void pnp_set_clk(ADAPTER * adapter)
+{
+ WORD temp;
+
+ temp = pnp_read_ctrl(adapter);
+ temp |= PNP_SSK;
+
+ pnp_write_ctrl(adapter, temp);
+
+ pnp_delay(adapter);
+}
+
+
+/************************************************************************
+ * Clears the serial device clock bit
+ *
+ * Inputs : Adapter structure
+ *
+ * Outputs : None
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pnp_clr_clk)
+#endif
+
+local void pnp_clr_clk(ADAPTER * adapter)
+{
+ WORD temp;
+
+ temp = pnp_read_ctrl(adapter);
+ temp &= ~PNP_SSK;
+
+ pnp_write_ctrl(adapter, temp);
+
+ pnp_delay(adapter);
+}
+
+
+/************************************************************************
+ * Puts the serial device data port into OUTPUT mode
+ *
+ * Inputs : Adapter structure
+ *
+ * Outputs : None
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pnp_set_eeden)
+#endif
+
+local void pnp_set_eeden(ADAPTER * adapter)
+{
+ WORD temp;
+
+ temp = pnp_read_ctrl(adapter);
+ temp |= PNP_EEDEN;
+
+ pnp_write_ctrl(adapter, temp);
+
+ pnp_delay(adapter);
+}
+
+
+/************************************************************************
+ * Puts the serial device data port into INPUT mode
+ *
+ * Inputs : Adapter structure
+ *
+ * Outputs : None
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pnp_clr_eeden)
+#endif
+
+local void pnp_clr_eeden(ADAPTER * adapter)
+{
+ WORD temp;
+
+ temp = pnp_read_ctrl(adapter);
+ temp &= ~PNP_EEDEN;
+
+ pnp_write_ctrl(adapter, temp);
+
+ pnp_delay(adapter);
+}
+
+
+/************************************************************************
+ * Sets the clears the serial device clock bit to strobe data into device
+ *
+ * Inputs : Adapter structure
+ *
+ * Outputs : None
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pnp_twitch_clk)
+#endif
+
+local void pnp_twitch_clk(ADAPTER * adapter)
+{
+ pnp_set_clk(adapter);
+ pnp_clr_clk(adapter);
+}
+
+
+/************************************************************************
+ * Sends a start bit to the serial device.
+ *
+ * This is done by a 1 to 0 transition of the data bit while the clock
+ * bit it 1.
+ *
+ * Inputs : Adapter structure
+ *
+ * Outputs : None
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pnp_start_bit)
+#endif
+
+local void pnp_start_bit(ADAPTER * adapter)
+{
+ WORD temp;
+
+ temp = pnp_read_ctrl(adapter);
+ temp &= ~(PNP_EEDO + PNP_EEDEN + PNP_SSK);
+ temp |= (PNP_EEDO + PNP_EEDEN);
+
+ pnp_write_ctrl(adapter, temp);
+
+ pnp_delay(adapter);
+
+ temp |= PNP_SSK;
+
+ pnp_write_ctrl(adapter, temp);
+
+ pnp_delay(adapter);
+
+ temp &= ~PNP_EEDO;
+
+ pnp_write_ctrl(adapter, temp);
+
+ pnp_delay(adapter);
+
+ temp &= ~(PNP_EEDO + PNP_EEDEN + PNP_SSK);
+
+ pnp_write_ctrl(adapter, temp);
+
+ pnp_delay(adapter);
+}
+
+
+/************************************************************************
+ * Sends a stop bit to the serial device.
+ *
+ * This is done by a 0 to 1 transition of the data bit while the clock
+ * bit it 1.
+ *
+ * Inputs : Adapter structure
+ *
+ * Outputs : None
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pnp_stop_bit)
+#endif
+
+local void pnp_stop_bit(ADAPTER * adapter)
+{
+ WORD temp;
+
+ temp = pnp_read_ctrl(adapter);
+ temp &= ~(PNP_EEDO + PNP_EEDEN + PNP_SSK);
+ temp |= (PNP_EEDEN);
+
+ pnp_write_ctrl(adapter, temp);
+
+ pnp_delay(adapter);
+
+ temp |= PNP_SSK;
+
+ pnp_write_ctrl(adapter, temp);
+
+ pnp_delay(adapter);
+
+ temp |= PNP_EEDO;
+
+ pnp_write_ctrl(adapter, temp);
+
+ pnp_delay(adapter);
+
+ temp &= ~(PNP_EEDO + PNP_EEDEN + PNP_SSK);
+
+ pnp_write_ctrl(adapter, temp);
+
+ pnp_delay(adapter);
+}
+
+
+/************************************************************************
+ * Waits for the serial device to say its accepted the last cmd/data
+ *
+ * Inputs : Adapter structure
+ *
+ * Outputs : TRUE if OK, FALSE if it timed out
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pnp_wait_ack)
+#endif
+
+local WBOOLEAN pnp_wait_ack(ADAPTER * adapter)
+{
+ WORD temp;
+ WORD i;
+
+ temp = pnp_read_ctrl(adapter);
+ temp &= ~(PNP_EEDO + PNP_EEDEN + PNP_SSK);
+
+ pnp_write_ctrl(adapter, temp);
+
+ pnp_delay(adapter);
+
+ for (i = 0; i < PNP_WAIT_CNT; i++)
+ {
+ pnp_set_clk(adapter);
+
+ temp = pnp_read_ctrl(adapter);
+
+ pnp_clr_clk(adapter);
+
+ if (!(temp & PNP_EEDO))
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+/************************************************************************
+ * Waits for the serial device to say its passed the last of the data to
+ * be read.
+ *
+ * Inputs : Adapter structure
+ *
+ * Outputs : TRUE if OK, FALSE if it timed out
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pnp_dummy_wait_ack)
+#endif
+
+local WBOOLEAN pnp_dummy_wait_ack(ADAPTER * adapter)
+{
+ WORD temp;
+ WORD i;
+
+ temp = pnp_read_ctrl(adapter);
+ temp &= ~(PNP_EEDO + PNP_EEDEN + PNP_SSK);
+
+ pnp_write_ctrl(adapter, temp);
+
+ pnp_delay(adapter);
+
+ for (i = 0; i < PNP_WAIT_CNT ; i++)
+ {
+ pnp_set_clk(adapter);
+
+ temp = pnp_read_ctrl(adapter);
+
+ pnp_clr_clk(adapter);
+
+ if (temp & PNP_EEDO)
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+/************************************************************************
+ * Writes a bit to the serial device
+ * be read.
+ *
+ * Inputs : Adapter structure
+ * The data bit to be written
+ *
+ * Outputs : TRUE if OK, FALSE if it timed out
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pnp_write_data)
+#endif
+
+local void pnp_write_data(ADAPTER * adapter, WORD data)
+{
+ WORD temp;
+
+ temp = pnp_read_ctrl(adapter);
+ temp &= ~(PNP_EEDO);
+ temp |= (data & 0x0080) >> 6;
+
+ pnp_write_ctrl(adapter, temp);
+
+ pnp_delay(adapter);
+}
+
+
+/************************************************************************
+ *
+ * Routine to read a byte from the serial device fitted to the Plug aNd Play
+ * cards.
+ *
+ * Inputs : Adapter structure.
+ * Offset (address) in the serial device to read
+ *
+ * Outputs : A word with the interstng byte in the LSB
+ *
+ * RCS 22/07/94
+ *
+ ************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(pnp_read_a_word)
+#endif
+
+local WORD pnp_read_a_word(ADAPTER * adapter, WORD index)
+{
+ WORD temp;
+ WORD data_byte = 0;
+ WORD i;
+
+ /*
+ * Wake up the device
+ */
+ pnp_start_bit(adapter);
+
+ /*
+ * Set data 'OUTPUT' mode
+ */
+ pnp_set_eeden(adapter);
+
+ /*
+ * Send WRITE CMD - a dummy really to allow us to set the READ address!
+ */
+ temp = PNP_WRITE_CMD;
+
+ /*
+ * MSB first !
+ */
+ for (i = 0; i < 8; i++)
+ {
+ pnp_write_data(adapter, temp);
+ pnp_twitch_clk(adapter);
+ temp = temp << 1;
+ }
+
+ if (!pnp_wait_ack(adapter))
+ {
+ /*
+ * Return sommat invalid if it timed out !
+ */
+ return 0xffff;
+ }
+
+ /*
+ * Set data 'OUTPUT' mode
+ */
+ pnp_set_eeden(adapter);
+
+ /*
+ * Send Address in ROM
+ */
+ temp = index;
+
+ /*
+ * MSB first !
+ */
+ for (i = 0; i < 8; i++)
+ {
+ pnp_write_data(adapter, temp);
+ pnp_twitch_clk(adapter);
+ temp = temp << 1;
+ }
+
+ if (!pnp_wait_ack(adapter))
+ {
+ /*
+ * Return sommat invalid if it timed out !
+ */
+ return 0xffff;
+ }
+
+ pnp_start_bit(adapter);
+
+ /*
+ * Set data 'OUTPUT' mode
+ */
+ pnp_set_eeden(adapter);
+
+ /*
+ * Send READ CMD
+ */
+ temp = PNP_READ_CMD;
+
+ /*
+ * MSB first !
+ */
+ for (i = 0; i < 8 ;i++)
+ {
+ pnp_write_data(adapter, temp);
+ pnp_twitch_clk(adapter);
+ temp = temp << 1;
+ }
+
+ if (!pnp_wait_ack(adapter))
+ {
+ /*
+ * Return sommat invalid if it timed out !
+ */
+ return 0xffff;
+ }
+
+ /*
+ * Set data 'INPUT' mode
+ */
+ pnp_clr_eeden(adapter);
+
+ /*
+ * Now read the serial data - MSB first !
+ */
+ for (i = 0; i < 8 ;i++)
+ {
+ pnp_set_clk(adapter);
+
+ temp = pnp_read_ctrl(adapter);
+
+ pnp_clr_clk(adapter);
+
+ temp &= PNP_EEDO;
+ temp = temp >> 1;
+ data_byte = data_byte << 1;
+ data_byte &= 0xfffe;
+ data_byte |= temp;
+ }
+
+ if (!pnp_dummy_wait_ack(adapter))
+ {
+ /*
+ * Return sommat invalid if it timed out !
+ */
+ return 0xffff;
+ }
+
+ pnp_stop_bit(adapter);
+
+ return data_byte;
+}
+
+#endif
+
+/******** End of HWI_PNP.C *************************************************/
diff --git a/private/ntos/ndis/madge/driver/hwi_sm16.c b/private/ntos/ndis/madge/driver/hwi_sm16.c
new file mode 100644
index 000000000..75c637c21
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/hwi_sm16.c
@@ -0,0 +1,1191 @@
+/****************************************************************************
+*
+* HWI_SM16.C : Part of the FASTMAC TOOL-KIT (FTK)
+*
+* HARDWARE INTERFACE MODULE FOR SMART 16 CARDS
+*
+* Copyright (c) Madge Networks Ltd. 1994
+*
+* COMPANY CONFIDENTIAL
+*
+*
+*****************************************************************************
+*
+* The purpose of the Hardware Interface (HWI) is to supply an adapter card
+* independent interface to any driver. It performs nearly all of the
+* functions that involve affecting SIF registers on the adapter cards.
+* This includes downloading code to, initializing, and removing adapters.
+*
+* The HWI_SM16.C module contains the routines specific to the Smart16 card
+* which are necessary to install an adapter, to initialize an adapter, to
+* remove an adapter, and to handle interrupts on an adapter.
+*
+/***************************************************************************/
+
+/*---------------------------------------------------------------------------
+|
+| DEFINITIONS
+|
+---------------------------------------------------------------------------*/
+
+#include "ftk_defs.h"
+
+/*---------------------------------------------------------------------------
+|
+| MODULE ENTRY POINTS
+|
+---------------------------------------------------------------------------*/
+
+#include "ftk_intr.h" /* routines internal to FTK */
+#include "ftk_extr.h" /* routines provided or used by external FTK user */
+
+#ifndef FTK_NO_SMART16
+
+/*---------------------------------------------------------------------------
+|
+| LOCAL PROCEDURES
+|
+---------------------------------------------------------------------------*/
+
+local WBOOLEAN
+hwi_smart16_read_node_address(
+ ADAPTER * adapter
+ );
+
+local WBOOLEAN
+hwi_smart16_valid_io_location(
+ WORD io_location
+ );
+
+local WBOOLEAN
+hwi_smart16_valid_transfer_mode(
+ UINT transfer_mode
+ );
+
+#ifndef FTK_NO_PROBE
+
+local WBOOLEAN
+hwi_smart16_check_for_card(
+ WORD io_location
+ );
+
+#endif
+
+local WBOOLEAN
+hwi_smart16_valid_irq_channel(
+ ADAPTER * adapter
+ );
+
+#ifndef FTK_NO_PROBE
+/****************************************************************************
+*
+* hwi_smart16_probe_card
+* ======================
+*
+*
+* PARAMETERS (passed by hwi_probe_adapter) :
+* ==========================================
+*
+* PROBE * resources
+*
+* resources is an array structures used to identify and record specific
+* information about adapters found.
+*
+* UINT length
+*
+* length is the number of structures pointed to by reources.
+*
+* WORD * valid_locations
+*
+* valid_locations is an array of IO locations to examine for the presence
+* of an adapter. For smart 16 adapters with should be a subset of
+* {0x4a20, 0x4e20, 0x6a20, 0x6e20}.
+*
+* UINT number_locations
+*
+* This is the number of IO locations in the above list.
+*
+* BODY :
+* ======
+*
+* The hwi_smart16_probe_card routine is called by hwi_probe_adapter. It
+* checks for the existence of a card by reading its node address. This is
+* about all we can do for a smart 16.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine returns the number of adapters found, or PROBE_FAILURE if
+* there's a problem.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_smart16_probe_card)
+#endif
+
+export UINT
+hwi_smart16_probe_card(
+ PROBE * resources,
+ UINT length,
+ WORD * valid_locations,
+ UINT number_locations
+ )
+{
+ WORD control_1;
+ WORD control_2;
+ UINT i;
+ UINT j;
+
+ /*
+ * Check the bounds are sensible.
+ */
+
+ if(length <= 0 || number_locations <= 0)
+ {
+ return PROBE_FAILURE;
+ }
+
+ /*
+ * Range check the IO locations.
+ */
+
+ for(i = 0; i < number_locations; i++)
+ {
+ if(!hwi_smart16_valid_io_location(valid_locations[i]))
+ {
+ return PROBE_FAILURE;
+ }
+ }
+
+ /*
+ * j is the number of adapters found.
+ */
+
+ j = 0;
+
+ for(i = 0; i < number_locations; i++)
+ {
+ /*
+ * Check we aren't out of PROBE structures.
+ */
+
+ if(j >= length)
+ {
+ return j;
+ }
+
+ /*
+ * Set up the control register locations.
+ */
+
+ control_1 = valid_locations[i] + SMART16_CONTROL_REGISTER_1;
+ control_2 = valid_locations[i] + SMART16_CONTROL_REGISTER_2;
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_probe_enable_io(valid_locations[i], SMART16_IO_RANGE);
+#endif
+ /*
+ * Reset the card.
+ */
+
+ sys_probe_outsb(control_1, 0);
+
+ if (hwi_smart16_check_for_card(valid_locations[i]))
+ {
+
+ /*
+ * We have obviously found a valid smart 16 by this point so
+ * set up some values.
+ */
+
+ resources[j].adapter_card_bus_type = ADAPTER_CARD_SMART16_BUS_TYPE;
+ resources[j].adapter_card_type = ADAPTER_CARD_TYPE_SMART_16;
+ resources[j].adapter_card_revision = ADAPTER_CARD_SMART_16;
+ resources[j].adapter_ram_size = 128;
+ resources[j].io_location = valid_locations[i];
+ resources[j].interrupt_number = SMART16_DEFAULT_INTERRUPT;
+ resources[j].dma_channel = 0;
+ resources[j].transfer_mode = PIO_DATA_TRANSFER_MODE;
+
+ /*
+ * And increment j to point at the next free PROBE structure.
+ */
+
+ j++;
+ }
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_probe_disable_io(resources->io_location, SMART16_IO_RANGE);
+#endif
+
+ }
+
+ return j;
+}
+#endif
+
+/****************************************************************************
+*
+* hwi_smart16_install_card
+* ========================
+*
+*
+* PARAMETERS (passed by hwi_install_adapter) :
+* ============================================
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+* DOWNLOAD_IMAGE * download_image
+*
+* This is the code to be downloaded to the adapter. The image must be of
+* the correct type i.e. must be downloadable into the adapter. If the
+* pointer is 0 downloading is not done.
+*
+*
+* BODY :
+* ======
+*
+* hwi_smart16_install_card is called by hwi_install_adapter. It sets up
+* the adapter card and downloads the required code to it. Firstly, it
+* checks there is a valid adapter at the required IO address by reading
+* the node address from the BIA PROM. It then sets up and checks various
+* on-board registers for correct operation.
+*
+* Then, it halts the EAGLE, downloads the code, restarts the EAGLE and
+* waits up to 3 seconds for a valid bring-up code. If interrupts are
+* required, these are enabled by operating system specific calls.
+* The adapter is set up for Eagle Pseudo-DMA, since real DMA is not used.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine returns TRUE if it succeeds. If this routine fails (returns
+* FALSE) then a subsequent call to driver_explain_error, with the adapter
+* handle corresponding to the adapter parameter used here, will give an
+* explanation.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_smart16_install_card)
+#endif
+
+export WBOOLEAN
+hwi_smart16_install_card(
+ ADAPTER * adapter,
+ DOWNLOAD_IMAGE * download_image
+ )
+{
+ ADAPTER_HANDLE adapter_handle = adapter->adapter_handle;
+ WORD control_1 = adapter->io_location +
+ SMART16_CONTROL_REGISTER_1;
+ WORD control_2 = adapter->io_location +
+ SMART16_CONTROL_REGISTER_2;
+ WORD sif_base;
+
+ /*
+ * Check the IO location is valid.
+ */
+
+ if(!hwi_smart16_valid_io_location(adapter->io_location))
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_02_BAD_IO_LOCATION;
+
+ return FALSE;
+ }
+
+ /*
+ * Check the transfer mode is valid.
+ */
+
+ if(!hwi_smart16_valid_transfer_mode(adapter->transfer_mode))
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_02_BAD_IO_LOCATION;
+
+ return FALSE;
+ }
+
+ if (!hwi_smart16_valid_irq_channel(adapter))
+ {
+ return FALSE;
+ }
+
+ /*
+ * Record the locations of the SIF registers.
+ */
+
+ sif_base = adapter->io_location + SMART16_FIRST_SIF_REGISTER;
+
+ adapter->sif_dat = sif_base + EAGLE_SIFDAT;
+ adapter->sif_datinc = sif_base + EAGLE_SIFDAT_INC;
+ adapter->sif_adr = sif_base + EAGLE_SIFADR;
+ adapter->sif_int = sif_base + EAGLE_SIFINT;
+ adapter->sif_acl = sif_base + EAGLE_SIFACL;
+ adapter->sif_adr2 = sif_base + EAGLE_SIFADR;
+ adapter->sif_adx = sif_base + EAGLE_SIFADX;
+ adapter->sif_dmalen = sif_base + EAGLE_DMALEN;
+ adapter->sif_sdmadat = sif_base + EAGLE_SDMADAT;
+ adapter->sif_sdmaadr = sif_base + EAGLE_SDMAADR;
+ adapter->sif_sdmaadx = sif_base + EAGLE_SDMAADX;
+
+ adapter->io_range = SMART16_IO_RANGE;
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ /*
+ * You might want to check that we have not already checked for a card
+ * at this address (or its rev3/4 equivalent).
+ */
+
+ /*
+ * Reset adapter (SMART16_CTRL1_SRESET = 0). This is necessary for
+ * reading the BIA.
+ */
+
+ sys_outsb(adapter_handle, control_1, 0);
+
+ /*
+ * Read the node address for the specified IO location. This will check
+ * that it is a valid Madge address, which is the only way we have of
+ * identifying the card.
+ */
+
+ if (!hwi_smart16_read_node_address(adapter))
+ {
+ /*
+ * Fill in error record and return
+ */
+
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_05_ADAPTER_NOT_FOUND;
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+
+ return FALSE;
+ }
+
+ /*
+ * Make sure that SCS bit is zero (see below where we bring card out of
+ * reset).
+ */
+
+ sys_outsb(adapter_handle, control_1, 0);
+
+ /*
+ * nselout_bits are needed to select the IRQ on the card.
+ */
+
+ switch (adapter->interrupt_number)
+ {
+ case 2 :
+ adapter->nselout_bits = SMART16_IRQ_2;
+ break;
+ case 3 :
+ adapter->nselout_bits = SMART16_IRQ_3;
+ break;
+ case 7 :
+ adapter->nselout_bits = SMART16_IRQ_7;
+ break;
+ default :
+ break;
+
+ }
+
+ /*
+ * These things can all be assumed for the smart16.
+ */
+
+ adapter->adapter_card_type = ADAPTER_CARD_TYPE_SMART_16;
+ adapter->adapter_card_revision = ADAPTER_CARD_SMART_16;
+ adapter->adapter_ram_size = 128;
+ adapter->edge_triggered_ints = TRUE;
+ adapter->EaglePsDMA = TRUE;
+ adapter->max_frame_size = MAX_FRAME_SIZE_16_MBITS;
+ adapter->ring_speed = 16;
+
+ /*
+ * Bring adapter out of reset state (ensure that SCS is zero before
+ * doing this).
+ */
+
+ sys_outsb(adapter_handle, control_1, 1);
+
+ /*
+ * Halt the Eagle prior to downloading the MAC code - this will also
+ * write the interrupt bits into the SIFACL register, where the MAC can
+ * find them.
+ */
+
+ hwi_halt_eagle(adapter);
+
+ /*
+ * Download code to adapter.
+ * View download image as a sequence of download records. Pass address
+ * of routine to set up DIO addresses on ATULA cards.
+ * If routine fails return failure (error record already filled in).
+ */
+
+ if (!hwi_download_code(adapter,
+ (DOWNLOAD_RECORD *) download_image,
+ hwi_smart16_set_dio_address))
+ {
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+
+ /*
+ * Restart the Eagle to initiate bring up diagnostics.
+ */
+
+ hwi_start_eagle(adapter);
+
+ /*
+ * Wait for a valid bring up code, may wait 3 seconds.
+ * If routine fails return failure (error record already filled in).
+ */
+
+ if (!hwi_get_bring_up_code(adapter))
+ {
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+
+ /*
+ * Set DIO address to point to EAGLE DATA page 0x10000L.
+ */
+
+ hwi_smart16_set_dio_address(adapter, DIO_LOCATION_EAGLE_DATA_PAGE);
+
+ /*
+ * If not in polling mode then set up interrupts.
+ * Interrupts_on field is used when disabling interrupts for adapter.
+ */
+
+ if (adapter->interrupt_number != POLLING_INTERRUPTS_MODE)
+ {
+ adapter->interrupts_on =
+ sys_enable_irq_channel(adapter_handle, adapter->interrupt_number);
+
+ /*
+ * If fail enable irq channel then fill in error record and return.
+ */
+
+ if (!adapter->interrupts_on)
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_0B_FAIL_IRQ_ENABLE;
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return FALSE;
+ }
+ }
+ else
+ {
+ adapter->interrupts_on = TRUE;
+ }
+
+ /* return successfully */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+ return TRUE;
+
+}
+
+
+/****************************************************************************
+*
+* hwi_smart16_interrupt_handler
+* =============================
+*
+*
+* PARAMETERS (passed by hwi_interrupt_entry) :
+* ============================================
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+*
+* BODY :
+* ======
+*
+* The hwi_smart16_interrupt_handler routine is called, when an interrupt
+* occurs, by hwi_interrupt_entry. It checks to see if a particular card
+* has interrupted. The interrupt could be generated by the SIF for either
+* a PIO data transfer or a normal condition (received frame, SRB complete,
+* ARB indication etc). Note it could in fact be the case that no interrupt
+* has occured on the particular adapter being checked.
+*
+* On normal SIF interrupts, the interrupt is acknowledged and cleared. The
+* value in the SIF interrupt register is recorded in order to pass it to
+* the driver_interrupt_entry routine (along with the adapter details).
+*
+* On PseudoDMA interrupts, the length, direction and physical address of
+* the transfer is determined. A system provided routine is called to do
+* the data transfer itself.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine always successfully completes.
+*
+****************************************************************************/
+
+#ifdef FTK_IRQ_FUNCTION
+#pragma FTK_IRQ_FUNCTION(hwi_smart16_interrupt_handler)
+#endif
+
+export void
+hwi_smart16_interrupt_handler(
+ ADAPTER * adapter
+ )
+{
+ ADAPTER_HANDLE adapter_handle = adapter->adapter_handle;
+ WORD sifacl_value;
+ WORD sifint_value;
+ WORD sifint_tmp;
+ WBOOLEAN sifint_occurred = FALSE;
+ WBOOLEAN pioint_occurred = FALSE;
+ WORD pio_len_bytes;
+ WBOOLEAN pio_from_adapter;
+ BYTE FAR * pio_address;
+ WORD lo_word;
+ DWORD hi_word;
+
+ /*
+ * Inform system about the IO ports we are going to access.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ /*
+ * Check for SIF interrupt or PIO interrupt.
+ */
+
+ /*
+ * Mask off any further interrupts while we read SIFINT (note that this
+ * does not mask off Pseudo DMA interrupts).
+ */
+
+ macro_clearw_bit(
+ adapter_handle,
+ adapter->sif_acl,
+ EAGLE_SIFACL_SINTEN
+ );
+
+ sifint_value = sys_insw(adapter_handle, adapter->sif_int);
+ do
+ {
+ sifint_tmp = sifint_value;
+ sifint_value = sys_insw(
+ adapter_handle,
+ adapter->sif_int
+ );
+ }
+ while (sifint_tmp != sifint_value);
+
+ if ((sifint_value & EAGLE_SIFINT_SYSTEM) != 0)
+ {
+ /*
+ * SIF interrupt has occurred.
+ * SRB free, adapter check or received frame interrupt.
+ */
+
+ sifint_occurred = TRUE;
+
+ /*
+ * Clear EAGLE_SIFINT_HOST_IRQ to acknowledge interrupt at SIF.
+ */
+
+ sys_outsw( adapter_handle, adapter->sif_int, 0);
+
+ }
+
+ sifacl_value = sys_insw(adapter_handle, adapter->sif_acl);
+
+ if ((sifacl_value & EAGLE_SIFACL_SWHRQ) != 0)
+ {
+ /*
+ * PIO interrupt has occurred.
+ * Data transfer to/from adapter interrupt.
+ */
+
+ pioint_occurred = TRUE;
+
+ macro_setw_bit(
+ adapter_handle,
+ adapter->sif_acl,
+ EAGLE_SIFACL_SWHLDA
+ );
+
+ /*
+ * Determine what direction the data transfer is to take place in.
+ */
+
+ pio_from_adapter = sys_insw(
+ adapter_handle,
+ adapter->sif_acl
+ ) & EAGLE_SIFACL_SWDDIR;
+
+ pio_len_bytes = sys_insw(
+ adapter_handle,
+ adapter->sif_dmalen
+ );
+
+ lo_word = sys_insw(
+ adapter_handle,
+ adapter->sif_sdmaadr
+ );
+
+ hi_word = (DWORD) sys_insw(
+ adapter_handle,
+ adapter->sif_sdmaadx
+ );
+
+ pio_address = (BYTE FAR *) ((hi_word << 16) | ((DWORD) lo_word));
+
+ /*
+ * Do the actual data transfer.
+ * Note that Fastmac only copies whole UINTs to DWORD boundaries.
+ * FastmacPlus, however, can transfer any length to any address.
+ */
+
+ if (pio_from_adapter)
+ {
+ /*
+ * Transfer into host memory from adapter.
+ * First, check if host address is on an odd byte boundary.
+ */
+
+ if ((card_t)pio_address % 2)
+ {
+ pio_len_bytes--;
+ *(pio_address++) =
+ sys_insb(adapter_handle,
+ (WORD) (adapter->sif_sdmadat + 1));
+ }
+
+ /*
+ * Now transfer the bulk of the data.
+ */
+
+ sys_rep_insw(
+ adapter_handle,
+ adapter->sif_sdmadat,
+ pio_address,
+ (WORD) (pio_len_bytes >> 1));
+
+ /*
+ * Finally transfer any trailing byte.
+ */
+
+ if (pio_len_bytes % 2)
+ {
+ *(pio_address+pio_len_bytes-1) =
+ sys_insb(adapter_handle,
+ adapter->sif_sdmadat);
+ }
+ }
+ else
+ {
+ /*
+ * Transfer into adapter memory from the host.
+ */
+
+ if ((card_t)pio_address % 2)
+ {
+ pio_len_bytes--;
+ sys_outsb(
+ adapter_handle,
+ (WORD) (adapter->sif_sdmadat + 1),
+ *(pio_address++)
+ );
+ }
+
+ sys_rep_outsw(
+ adapter_handle,
+ adapter->sif_sdmadat,
+ pio_address,
+ (WORD) (pio_len_bytes >> 1)
+ );
+
+ if (pio_len_bytes % 2)
+ {
+ sys_outsb(
+ adapter_handle,
+ adapter->sif_sdmadat,
+ *(pio_address+pio_len_bytes-1)
+ );
+ }
+ }
+ }
+
+#ifndef FTK_NO_CLEAR_IRQ
+
+ if (sifint_occurred || pioint_occurred)
+ {
+ /*
+ * Acknowledge/clear interrupt at interrupt controller.
+ */
+ sys_clear_controller_interrupt(
+ adapter_handle,
+ adapter->interrupt_number);
+ }
+
+#endif
+
+ if (sifint_occurred)
+ {
+ /*
+ * Call driver with details of SIF interrupt.
+ */
+
+ driver_interrupt_entry(
+ adapter_handle,
+ adapter,
+ sifint_value);
+ }
+
+ /*
+ * Read SIFACL until the SWHLDA bit has cleared.
+ */
+
+ do
+ {
+ sifacl_value = sys_insw(adapter_handle, adapter->sif_acl);
+ }
+ while ((sifacl_value & EAGLE_SIFACL_SWHLDA) != 0);
+
+ /*
+ * Now set SINTEN in SIFACL to regenerate interrupts.
+ */
+
+ sys_outsw(
+ adapter_handle,
+ adapter->sif_acl,
+ (WORD) (sifacl_value | EAGLE_SIFACL_SINTEN)
+ );
+
+ /*
+ * Let system know we have finished accessing the IO ports.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io( adapter);
+#endif
+}
+
+
+/****************************************************************************
+*
+* hwi_smart16_remove_card
+* =======================
+*
+*
+* PARAMETERS (passed by hwi_remove_adapter) :
+* ===========================================
+*
+* ADAPTER * adapter
+*
+* This structure is used to identify and record specific information about
+* the required adapter.
+*
+*
+* BODY :
+* ======
+*
+* The hwi_smart16_remove_card routine is called by hwi_remove_adapter. It
+* disables interrupts if they are being used. It also resets the adapter.
+*
+*
+* RETURNS :
+* =========
+*
+* The routine always successfully completes.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(hwi_smart16_remove_card)
+#endif
+
+export void
+hwi_smart16_remove_card(
+ ADAPTER * adapter
+ )
+{
+ ADAPTER_HANDLE adapter_handle = adapter->adapter_handle;
+ WORD control_1 = adapter->io_location +
+ SMART16_CONTROL_REGISTER_1;
+ WORD sifacl_value;
+
+ /*
+ * Interrupt must be disabled at adapter before unpatching interrupt.
+ * Even in polling mode we must turn off interrupts at adapter.
+ */
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_enable_io(adapter);
+#endif
+
+ sifacl_value = sys_insw(adapter_handle, adapter->sif_acl);
+ sifacl_value = (sifacl_value & ~(EAGLE_SIFACL_PSDMAEN | EAGLE_SIFACL_SINTEN));
+ sys_outsw(
+ adapter_handle,
+ adapter->sif_acl,
+ sifacl_value);
+
+ if (adapter->interrupts_on)
+ {
+ if (adapter->interrupt_number != POLLING_INTERRUPTS_MODE)
+ {
+ sys_disable_irq_channel(
+ adapter_handle,
+ adapter->interrupt_number);
+ }
+
+ adapter->interrupts_on = FALSE;
+ }
+
+ /*
+ * perform adapter reset, set BALD_EAGLE_CTRL1_NSRESET low
+ */
+
+ sys_outsb(adapter_handle, control_1, 0);
+
+#ifndef FTK_NO_IO_ENABLE
+ macro_disable_io(adapter);
+#endif
+}
+
+
+/****************************************************************************
+*
+* hwi_smart16_set_dio_address
+* ===========================
+*
+* The hwi_smart16_set_dio_address routine is used, with Smart16 cards, for
+* putting a 32 bit DIO address into the SIF DIO address and extended DIO
+* address registers. Note that the extended address register should be
+* loaded first.
+*
+****************************************************************************/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_smart16_set_dio_address)
+#endif
+
+export void
+hwi_smart16_set_dio_address(
+ ADAPTER * adapter,
+ DWORD dio_address
+ )
+{
+ ADAPTER_HANDLE adapter_handle = adapter->adapter_handle;
+ WORD sif_dio_adr = adapter->sif_adr;
+ WORD sif_dio_adrx = adapter->sif_adx;
+
+ /*
+ * Load extended DIO address register with top 16 bits of address.
+ * Always load extended address register first.
+ */
+ sys_outsw(
+ adapter_handle,
+ sif_dio_adrx,
+ (WORD)(dio_address >> 16));
+
+ /*
+ * Load DIO address register with low 16 bits of address.
+ */
+
+ sys_outsw(
+ adapter_handle,
+ sif_dio_adr,
+ (WORD)(dio_address & 0x0000FFFF));
+
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| LOCAL PROCEDURES
+|
+---------------------------------------------------------------------------*/
+
+#ifndef FTK_NO_PROBE
+/*---------------------------------------------------------------------------
+|
+| hwi_smart16_check_for_card
+| ==========================
+|
+| The hwi_smart16_check_for_card routine reads in the node address from
+| the BIA, and checks that it is a valid Madge node address. Basically
+| it's just the same as hwi_smart16_read_node_address.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_smart16_check_for_card)
+#endif
+
+local WBOOLEAN
+hwi_smart16_check_for_card(
+ WORD io_location
+ )
+{
+ WORD control_2 = io_location + SMART16_CONTROL_REGISTER_2;
+ WORD port;
+ BYTE i;
+ BYTE j;
+ BYTE two_bits;
+ DWORD node_address = 0;
+
+ for (i = 0; i < 4; i++)
+ {
+ sys_probe_outsb(control_2, i);
+
+ /*
+ * Read the 8 bit node address 2 bits at a time.
+ */
+
+ port = io_location;
+
+ for (j = 0; j < 4; j++)
+ {
+ two_bits = (BYTE)(sys_probe_insb(port) & 3);
+ node_address = (node_address << 2) | two_bits;
+ port += 8;
+ }
+ }
+
+ /*
+ * If we find that the high byte is not f6 then we know we haven't
+ * got a valid card so we fail.
+ */
+
+ return (((node_address >> 24) & 0x000000ffL) == 0x000000f6L &&
+ (node_address & 0x00ffffffL) != 0x00ffffffL &&
+ (node_address & 0x00ffffffL) != 0x00000000L);
+}
+#endif
+
+/*---------------------------------------------------------------------------
+|
+| hwi_smart16_read_node_address
+| =============================
+|
+| The hwi_smart16_read_node_address routine reads in the node address from
+| the BIA, and checks that it is a valid Madge node address.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_smart16_read_node_address)
+#endif
+
+local WBOOLEAN
+hwi_smart16_read_node_address(
+ ADAPTER * adapter
+ )
+{
+ WORD control_2 = adapter->io_location +
+ SMART16_CONTROL_REGISTER_2;
+ WORD port;
+ BYTE i;
+ BYTE j;
+ BYTE two_bits;
+ DWORD node_address = 0;
+
+ for (i = 0; i < 4; i++)
+ {
+ sys_outsb(
+ adapter->adapter_handle,
+ control_2,
+ i);
+
+ /*
+ * Read the 8 bit node address 2 bits at a time.
+ */
+
+ port = adapter->io_location;
+
+ for (j = 0; j < 4; j++)
+ {
+ two_bits = (BYTE)(sys_insb(adapter->adapter_handle, port) & 3);
+ node_address = (node_address << 2) | two_bits;
+ port += 8;
+ }
+ }
+
+ adapter->permanent_address.byte[0] = 0;
+ adapter->permanent_address.byte[1] = 0;
+
+ for (i = 0; i < 4; i++)
+ {
+ adapter->permanent_address.byte[5-i]
+ = (BYTE)((node_address >> (8 * i)) & 0x0ff);
+ }
+
+ return (adapter->permanent_address.byte[2] == MADGE_NODE_BYTE_2);
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| hwi_smart16_valid_io_location
+| =============================
+|
+| The hwi_smart16_valid_io_location routine checks to see if the user has
+| supplied a valid IO location for a smart 16 adapter card.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_smart16_valid_io_location)
+#endif
+
+local WBOOLEAN
+hwi_smart16_valid_io_location(
+ WORD io_location
+ )
+{
+ WBOOLEAN io_valid;
+
+ switch (io_location & ~SMART16_REV3)
+ {
+
+ case 0x4A20 :
+ case 0x4E20 :
+ case 0x6A20 :
+ case 0x6E20 :
+
+ /*
+ * These are the valid user supplied io locations.
+ */
+
+ io_valid = TRUE;
+ break;
+
+
+ default :
+
+ /*
+ * Anything else is invalid.
+ */
+
+ io_valid = FALSE;
+
+ break;
+ }
+
+ return(io_valid);
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| hwi_smart16_valid_transfer_mode
+| ===============================
+|
+| The hwi_smart16_valid_transfer_mode routine checks to see if the user has
+| supplied a valid transfer mode for a smart 16 adapter card (that's PIO to
+| you and me).
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_smart16_valid_transfer_mode)
+#endif
+
+local WBOOLEAN
+hwi_smart16_valid_transfer_mode(
+ UINT transfer_mode
+ )
+{
+ return(transfer_mode == PIO_DATA_TRANSFER_MODE);
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| hwi_smart16_valid_irq_channel
+| =============================
+|
+| The hwi_smart16_valid_irq_channel routine checks to see if the user has
+| supplied a valid interrupt number for a Smart16 adapter card.
+|
+---------------------------------------------------------------------------*/
+
+#ifdef FTK_INIT_FUNCTION
+#pragma FTK_INIT_FUNCTION(hwi_smart16_valid_irq_channel)
+#endif
+
+local WBOOLEAN
+hwi_smart16_valid_irq_channel(
+ ADAPTER * adapter
+ )
+{
+ WBOOLEAN int_valid;
+
+ /*
+ * Assume that interrupt number is valid.
+ */
+
+ int_valid = TRUE;
+
+ /*
+ * No need to do any check on interrupt number if in polling mode.
+ */
+
+ if (adapter->interrupt_number != POLLING_INTERRUPTS_MODE)
+ {
+ switch (adapter->interrupt_number)
+ {
+ case 2 :
+ case 3 :
+ case 7 :
+ break;
+
+ default :
+ int_valid = FALSE;
+ break;
+
+ }
+ }
+
+ if (!int_valid)
+ {
+ adapter->error_record.type = ERROR_TYPE_HWI;
+ adapter->error_record.value = HWI_E_03_BAD_INTERRUPT_NUMBER;
+ }
+
+ return int_valid;
+}
+
+#endif
+
+/******** End of HWI_SM16.C file *******************************************/
+
diff --git a/private/ntos/ndis/madge/driver/inc/ndismod.h b/private/ntos/ndis/madge/driver/inc/ndismod.h
new file mode 100644
index 000000000..d7aab4d6c
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/inc/ndismod.h
@@ -0,0 +1,792 @@
+/***************************************************************************
+*
+* NDISMOD.H
+*
+* NDIS3 miniport driver main header file.
+*
+* Copyright (c) Madge Networks Ltd 1994
+*
+* COMPANY CONFIDENTIAL
+*
+* Created: PBA 21/06/1994
+*
+****************************************************************************/
+
+#ifndef _NDIS_
+#include <ndis.h>
+#endif
+
+/*---------------------------------------------------------------------------
+|
+| General Constants
+|
+|--------------------------------------------------------------------------*/
+
+#define MADGE_NDIS_MAJOR_VERSION 3
+#define MADGE_NDIS_MINOR_VERSION 0
+
+#define EVERY_2_SECONDS 2000
+
+#define MADGE_MINIMUM_LOOKAHEAD (64)
+
+//
+// Keep this OID if we are gathering performance statistics
+//
+// #define OID_MADGE_MONITOR 0x0303028e
+
+#define OID_TYPE_MASK 0xffff0000
+#define OID_TYPE_GENERAL_OPERATIONAL 0x00010000
+#define OID_TYPE_GENERAL_STATISTICS 0x00020000
+#define OID_TYPE_802_5_OPERATIONAL 0x02010000
+#define OID_TYPE_802_5_STATISTICS 0x02020000
+
+#define MADGE_ERRMSG_INIT_INTERRUPT (ULONG)0x01
+#define MADGE_ERRMSG_CREATE_FILTER (ULONG)0x02
+#define MADGE_ERRMSG_ALLOC_MEMORY (ULONG)0x03
+#define MADGE_ERRMSG_REGISTER_ADAPTER (ULONG)0x04
+#define MADGE_ERRMSG_ALLOC_DEVICE_NAME (ULONG)0x05
+#define MADGE_ERRMSG_ALLOC_ADAPTER (ULONG)0x06
+#define MADGE_ERRMSG_INITIAL_INIT (ULONG)0x07
+#define MADGE_ERRMSG_OPEN_DB (ULONG)0x08
+#define MADGE_ERRMSG_ALLOC_OPEN (ULONG)0x09
+#define MADGE_ERRMSG_HARDWARE_ADDRESS (ULONG)0x0A
+#define MADGE_ERRMSG_WRONG_RBA (ULONG)0x0B
+#define MADGE_ERRMSG_REDUCE_MAX_FSIZE (ULONG)0x0C
+#define MADGE_ERRMSG_OPEN_IMAGE_FILE (ULONG)0x0D
+#define MADGE_ERRMSG_MAP_IMAGE_FILE (ULONG)0x0E
+#define MADGE_ERRMSG_BAD_IMAGE_FILE (ULONG)0x0F
+#define MADGE_ERRMSG_NO_BUS_TYPE (ULONG)0x10
+#define MADGE_ERRMSG_NO_MCA_POS (ULONG)0x11
+#define MADGE_ERRMSG_NO_EISA_CONFIG (ULONG)0x12
+#define MADGE_ERRMSG_NO_ISA_IO (ULONG)0x13
+#define MADGE_ERRMSG_NO_ISA_IRQ (ULONG)0x14
+#define MADGE_ERRMSG_NO_ISA_DMA (ULONG)0x15
+#define MADGE_ERRMSG_BAD_PARAMETER (ULONG)0x16
+#define MADGE_ERRMSG_NO_PCI_SLOTNUMBER (ULONG)0x17
+#define MADGE_ERRMSG_BAD_PCI_SLOTNUMBER (ULONG)0x18
+#define MADGE_ERRMSG_BAD_PCI_MMIO (ULONG)0x19
+#define MADGE_ERRMSG_MAPPING_PCI_MMIO (ULONG)0x1a
+#define MADGE_ERRMSG_NO_PCI_IO (ULONG)0x1b
+#define MADGE_ERRMSG_NO_PCI_IRQ (ULONG)0x1c
+
+//
+// Number of bytes in a minimum length token ring frame (MAC not
+// LLC so just FC, AC and addresses).
+//
+
+#define FRAME_HEADER_SIZE 14
+
+
+/*---------------------------------------------------------------------------
+|
+| Optional Parameter Definition Structure.
+|
+|--------------------------------------------------------------------------*/
+
+typedef struct
+{
+ NDIS_STRING Keyword;
+ DWORD Minimum;
+ DWORD Maximum;
+ NDIS_CONFIGURATION_PARAMETER DefaultValue;
+ NDIS_CONFIGURATION_PARAMETER ActualValue;
+}
+MADGE_PARM_DEFINITION;
+
+
+/*---------------------------------------------------------------------------
+|
+| ISR Information Structure.
+|
+|--------------------------------------------------------------------------*/
+
+typedef struct
+{
+ NDIS_HANDLE MiniportHandle;
+ ULONG InterruptNumber;
+ BOOLEAN InterruptShared;
+ NDIS_INTERRUPT_MODE InterruptMode;
+ BOOLEAN SrbRequestCompleted;
+ BOOLEAN SrbRequestStatus;
+}
+USED_IN_ISR, *PUSED_IN_ISR;
+
+#ifdef OID_MADGE_MONITOR
+/*---------------------------------------------------------------------------
+|
+| Monitor Structure
+|
+|--------------------------------------------------------------------------*/
+
+typedef struct
+{
+ UINT TransmitFrames;
+ UINT ReceiveFrames;
+ UINT TransferFrames;
+ UINT TransmitFrameSize[65];
+ UINT ReceiveFrameSize[65];
+ UINT TransferFrameSize[65];
+ UINT ReceiveFlag;
+ UINT CurrentFrameSize;
+ UINT NumberOfPFrags[65];
+ UINT NumberOfVFrags[65];
+ UINT FailedToTransmit;
+}
+MADGE_MONITOR, *PMADGE_MONITOR;
+#endif
+
+/*---------------------------------------------------------------------------
+|
+| Adapter Structure.
+|
+| We actually have two adapter structures for each adapter. One of the type
+| described below for NDIS3 level information and one maintained by the
+| FTK for lower level adapter specific information.
+|
+|--------------------------------------------------------------------------*/
+
+typedef struct
+{
+ //
+ // Card configuration options.
+ //
+
+ UINT BusType;
+ UINT IoLocation1;
+ UINT IoLocation2;
+ UINT InterruptLevel;
+ UINT DmaChannel;
+ UINT TransferMode;
+ UINT SlotNumber;
+ UINT FastmacTxSlots;
+ UINT FastmacRxSlots;
+ UINT MaxFrameSize;
+ UINT CardBufferSize;
+ BOOLEAN PromiscuousMode;
+ BOOLEAN AlternateIo;
+ BOOLEAN TestAndXIDEnabled;
+ BOOLEAN ForceOpen;
+ BOOLEAN Force4;
+ BOOLEAN Force16;
+ BOOLEAN Multiprocessor;
+
+ UINT MapRegistersAllocated;
+
+ //
+ // Card dependent parameters.
+ //
+
+ WORD FTKCardBusType;
+ NDIS_INTERFACE_TYPE NTCardBusType;
+
+ //
+ // Handle for communicating with the FTK.
+ //
+
+ ADAPTER_HANDLE FtkAdapterHandle;
+
+ //
+ // Kernel resources allocated for the adapter.
+ //
+
+ NDIS_MINIPORT_INTERRUPT Interrupt;
+ NDIS_MINIPORT_TIMER WakeUpTimer;
+ NDIS_MINIPORT_TIMER CompletionTimer;
+
+ //
+ // Flags to indicate the current state of the driver/card.
+ //
+
+ BOOLEAN TimerInitialized;
+ BOOLEAN FtkInitialized;
+ BOOLEAN IORange1Initialized;
+ BOOLEAN IORange2Initialized;
+ BOOLEAN DprInProgress;
+
+ UINT RxTxBufferState;
+
+ BOOLEAN UseMPSafePIO;
+
+ BOOLEAN AdapterRemoved;
+
+ BOOLEAN ShutdownHandlerRegistered;
+
+ //
+ // Details of I/O ports used.
+ //
+
+ UINT IoLocationBase;
+
+ WORD IORange1;
+ WORD IORange2;
+ UINT IORange1End;
+
+ PVOID MappedIOLocation1;
+ PVOID MappedIOLocation2;
+
+ //
+ // Memory usage for PCI.
+ //
+
+ DWORD MmioRawAddress;
+ VOID * MmioVirtualAddress;
+ BOOLEAN MmioMapped;
+
+ //
+ // Interrupt related details.
+ //
+
+ USED_IN_ISR UsedInISR;
+ BOOLEAN SrbRequestStatus;
+ BOOLEAN DprRequired;
+
+ //
+ // Flag set if we are waiting for a private SRB to complete.
+ //
+
+ BOOLEAN PrivateSrbInProgress;
+
+ //
+ // General Mandatory Operational Characteristics.
+ //
+
+ NDIS_HARDWARE_STATUS HardwareStatus;
+ UINT CurrentPacketFilter;
+ ULONG CurrentLookahead;
+
+ //
+ // Counters for the General Mandatory Statistics.
+ //
+
+ UINT FramesTransmitted;
+ UINT FramesReceived;
+ UINT FrameTransmitErrors;
+ UINT FrameReceiveErrors;
+ UINT ReceiveCongestionCount;
+
+ //
+ // Token Ring Mandatory Operational Characteristics.
+ //
+
+ NODE_ADDRESS OpeningNodeAddress;
+ NODE_ADDRESS PermanentNodeAddress;
+ ULONG GroupAddress;
+ ULONG FunctionalAddress;
+ WORD OpenOptions;
+ WORD LastOpenStatus;
+ WORD CurrentRingStatus;
+ NDIS_802_5_RING_STATE CurrentRingState;
+
+ //
+ // Counters for the Token Ring Mandatory Statistics.
+ //
+
+ UINT LineErrors;
+ UINT LostFrames;
+
+ //
+ // Counters for the Token Ring Optional Statistics.
+ //
+
+ UINT BurstErrors;
+ UINT AcErrors;
+ UINT FrameCopiedErrors;
+ UINT TokenErrors;
+
+ NDIS_OID JustReadErrorLog;
+
+ //
+ // Status of a pended request.
+ //
+
+ NDIS_REQUEST_TYPE RequestType;
+ NDIS_OID RequestOid;
+ PVOID InformationBuffer;
+
+#ifdef OID_MADGE_MONITOR
+ MADGE_MONITOR MonitorInfo;
+#endif
+
+}
+MADGE_ADAPTER, *PMADGE_ADAPTER;
+
+
+/*---------------------------------------------------------------------------
+|
+| Adapter types.
+|
+---------------------------------------------------------------------------*/
+
+#define MADGE_ADAPTER_ATULA 100
+
+#define MADGE_ADAPTER_PCMCIA 200
+
+#define MADGE_ADAPTER_PNP 300
+
+#define MADGE_ADAPTER_SMART16 400
+
+#define MADGE_ADAPTER_EISA 500
+
+#define MADGE_ADAPTER_MC 600
+
+#define MADGE_ADAPTER_PCI 700
+
+#define MADGE_ADAPTER_UNKNOWN 9999
+
+
+/*---------------------------------------------------------------------------
+|
+| Transfer modes.
+|
+---------------------------------------------------------------------------*/
+
+#define MADGE_PIO_MODE 0
+#define MADGE_DMA_MODE 1
+#define MADGE_MMIO_MODE 2
+
+
+/*---------------------------------------------------------------------------
+|
+| OS types.
+|
+---------------------------------------------------------------------------*/
+
+#define MADGE_OS_NT 100
+#define MADGE_OS_WIN95 200
+
+
+/*---------------------------------------------------------------------------
+|
+| Rx and Tx Buffer Initialization Flags.
+|
+---------------------------------------------------------------------------*/
+
+#define MADGE_RX_INITIALIZED 0x0001
+#define MADGE_TX_INITIALIZED 0x0002
+
+#define MADGE_RXTX_INITIALIZED (MADGE_RX_INITIALIZED | MADGE_TX_INITIALIZED)
+
+
+/*---------------------------------------------------------------------------
+|
+| Definition of a token ring frame MAC header.
+|
+|--------------------------------------------------------------------------*/
+
+typedef struct
+{
+ BYTE AC;
+ BYTE FC;
+ UCHAR DestAddress[6];
+ UCHAR SrcAddress[6];
+}
+TOKENRING, *PTOKENRING;
+
+
+/*---------------------------------------------------------------------------
+|
+| Procedure Identifiers for Logging.
+|
+|--------------------------------------------------------------------------*/
+
+typedef enum
+{
+ readRegistry,
+ registerAdapter,
+ initAdapter,
+ madgeInitialize,
+ inFtk
+}
+MADGE_PROC_ID;
+
+
+/*---------------------------------------------------------------------------
+|
+| Structure of the FastMAC Plus download file header.
+|
+|--------------------------------------------------------------------------*/
+
+#define DOWNLOAD_CHECKSUM_SKIP (sizeof(DWORD) * 2)
+
+#define DOWNLOAD_CHECKSUM_BYTE(chk, byte) \
+ (chk) = \
+ (((DWORD) (chk) >> 30) ^ ((DWORD) (chk) << 1)) + (UCHAR) (byte)
+
+
+#define BUILD_DWORD(a, b, c, d) \
+ ((((DWORD) (a)) << 24) + \
+ (((DWORD) (b)) << 16) + \
+ (((DWORD) (c)) << 8 ) + \
+ (((DWORD) (d)) ))
+
+#define DOWNLOAD_SIGNATURE BUILD_DWORD(26, 'G', 'D', 'M')
+
+typedef
+struct
+{
+ DWORD signature;
+ DWORD chkSum;
+ DWORD version;
+ char mVer[32];
+}
+DOWNLOAD_FILE_HEADER;
+
+
+/*---------------------------------------------------------------------------
+|
+| Macro to check that a download file is cosha.
+|
+|--------------------------------------------------------------------------*/
+
+#define IS_DOWNLOAD_OK(downHdr, checkSum) \
+ ((downHdr)->signature == DOWNLOAD_SIGNATURE && \
+ (((downHdr)->version & 0xffff0000L) == \
+ (MADGE_NT_VERSION_DWORD & 0xffff0000L) || \
+ (downHdr)->version == 0) && \
+ (downHdr)->chkSum == (checkSum))
+
+
+/*---------------------------------------------------------------------------
+|
+| Details of PCI configuration memory.
+|
+| We don't define a structure for this to avoid byte alignment problems on
+| none x86 machines.
+|
+---------------------------------------------------------------------------*/
+
+#define PCI_CONFIG_SIZE 64
+#define PCI_MMIO_SIZE 4096
+
+#define PCI_VENDOR_ID(buff) (((DWORD *) (buff))[0] & 0x0000ffffL)
+#define PCI_REVISION(buff) ((((DWORD *) (buff))[0] & 0xffff0000L) >> 16)
+#define PCI_IO_BASE(buff) (((DWORD *) (buff))[4] & 0xfffffffeL)
+#define PCI_MMIO_BASE(buff) (((DWORD *) (buff))[5] & 0xfffffff0L)
+#define PCI_IRQ_NUMBER(buff) (((DWORD *) (buff))[15] & 0x000000ffL)
+
+#define MAX_PCI_SLOTS 32 // There are 5 bits of device ID which
+ // is what NT uses as the slot number.
+
+#define PCI_FIND_ADAPTER 0xffff
+
+
+#define MADGE_PCI_VENDOR_ID 0x10b6
+
+#define MADGE_PCI_RAP1B_REVISION 0x0001
+#define MADGE_PCI_PCI2_REVISION 0x0002
+#define MADGE_PCI_PCIT_REVISION 0x0004
+
+
+/*---------------------------------------------------------------------------
+|
+| Table to Map FTK Adapter Handles to NDIS3 Level Adapter Structures.
+|
+|--------------------------------------------------------------------------*/
+
+// extern PMADGE_ADAPTER MadgeAdapterRecord[MAX_NUMBER_OF_ADAPTERS];
+
+
+/*---------------------------------------------------------------------------
+|
+| Macros to Map Between Objects.
+|
+|--------------------------------------------------------------------------*/
+
+//
+// Get an NDIS3 level adapter structure pointer from an FTK adapter handle.
+//
+
+#define PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(handle) \
+ ((PMADGE_ADAPTER) FTK_ADAPTER_USER_INFORMATION(handle))
+
+//
+// Get an NDIS3 level adapter structure pointer from an NDIS adapter
+// adapter context handle.
+//
+
+#define PMADGE_ADAPTER_FROM_CONTEXT(handle) \
+ ((PMADGE_ADAPTER) ((PVOID) (handle)))
+
+
+/*---------------------------------------------------------------------------
+|
+| Memory Manipulation Macros.
+|
+|--------------------------------------------------------------------------*/
+
+//
+// Allocate ordinary memory.
+//
+
+#define MADGE_ALLOC_MEMORY(status, address, length) \
+{ \
+ NDIS_PHYSICAL_ADDRESS temp = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1); \
+ *(status) = NdisAllocateMemory( \
+ (PVOID) (address), \
+ (length), \
+ 0, \
+ temp \
+ ); \
+}
+
+//
+// Free ordinary memory.
+//
+
+#define MADGE_FREE_MEMORY(address, length) \
+ NdisFreeMemory( \
+ (PVOID)(address), \
+ (length), \
+ 0 \
+ )
+
+
+//
+// Copy memory.
+//
+
+#define MADGE_MOVE_MEMORY(destination, source, length) \
+ NdisMoveMemory((PVOID) (destination), (PVOID) (source), (ULONG) (length))
+
+//
+// Zero memory.
+//
+
+#define MADGE_ZERO_MEMORY(destination, length) \
+ NdisZeroMemory((PVOID) (destination), (ULONG) (length))
+
+
+/*---------------------------------------------------------------------------
+|
+| Tokening Ring Address Testing Macros.
+|
+|--------------------------------------------------------------------------*/
+
+//
+// Compare two token ring MAC addresses pointed to by addPtr0 and
+// addrPtr1. Return TRUE if they are the same.
+//
+
+#define MADGE_ADDRESS_SAME(addrPtr0, addrPtr1) \
+ (((WORD *) (addrPtr0))[2] == ((WORD *) (addrPtr1))[2] && \
+ ((WORD *) (addrPtr0))[1] == ((WORD *) (addrPtr1))[1] && \
+ ((WORD *) (addrPtr0))[0] == ((WORD *) (addrPtr1))[0])
+
+
+//
+// Return TRUE if the frame pointer to by framePtr is source routed.
+//
+
+#define FRAME_IS_SOURCE_ROUTED(framePtr) \
+ ((((UCHAR *) (framePtr))[8] & 0x80) != 0)
+
+//
+// Return the number of bytes of source routing information in
+// a frame.
+//
+
+#define FRAME_SOURCE_ROUTING_BYTES(framePtr) \
+ (((UCHAR *) (framePtr))[14] & 0x1f)
+
+
+/*---------------------------------------------------------------------------
+|
+| Utility Macros.
+|
+|--------------------------------------------------------------------------*/
+
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+
+
+/*---------------------------------------------------------------------------
+|
+| Functions Exported by MADGE.C
+|
+|--------------------------------------------------------------------------*/
+
+NDIS_STATUS
+DriverEntry(PDRIVER_OBJECT driverObject, PUNICODE_STRING registryPath);
+
+NDIS_STATUS
+MadgeInitialize(
+ PNDIS_STATUS openErrorStatus,
+ PUINT selectedMediumIndex,
+ PNDIS_MEDIUM mediumArray,
+ UINT mediumArraySize,
+ NDIS_HANDLE miniportHandle,
+ NDIS_HANDLE wrapperConfigContext
+ );
+
+VOID
+MadgeHalt(NDIS_HANDLE adapterContext);
+
+
+/*---------------------------------------------------------------------------
+|
+| Functions Exported by DISPATCH.C
+|
+|--------------------------------------------------------------------------*/
+
+VOID
+MadgeGetAdapterStatus(
+ PVOID systemSpecific1,
+ PVOID context,
+ PVOID systemSpecific2,
+ PVOID systemSpecific3
+ );
+
+BOOLEAN
+MadgeCheckForHang(NDIS_HANDLE adapterContext);
+
+NDIS_STATUS
+MadgeReset(PBOOLEAN addressReset, NDIS_HANDLE adapterContext);
+
+VOID
+MadgeDisableInterrupts(NDIS_HANDLE adapterContext);
+
+VOID
+MadgeEnableInterrupts(NDIS_HANDLE adapterContext);
+
+NDIS_STATUS
+MadgeSend(NDIS_HANDLE adapterContext, PNDIS_PACKET packet, UINT flags);
+
+VOID
+MadgeCopyFromPacketToBuffer(
+ PNDIS_PACKET packet,
+ UINT offset,
+ UINT bytesToCopy,
+ PCHAR destPtr,
+ PUINT bytesCopied
+ );
+
+NDIS_STATUS
+MadgeTransferData(
+ PNDIS_PACKET packet,
+ PUINT bytesTransferred,
+ NDIS_HANDLE adapterContext,
+ NDIS_HANDLE receiveContext,
+ UINT byteOffset,
+ UINT bytesToTransfer
+ );
+
+VOID
+MadgeCopyFromBufferToPacket(
+ PCHAR srcPtr,
+ UINT bytesToCopy,
+ PNDIS_PACKET packet,
+ UINT offset,
+ PUINT bytesCopied
+ );
+
+VOID
+MadgeISR(
+ PBOOLEAN interruptRecognised,
+ PBOOLEAN queueDPR,
+ NDIS_HANDLE adapterContext
+ );
+
+VOID
+MadgeHandleInterrupt(NDIS_HANDLE adapterContext);
+
+
+/*---------------------------------------------------------------------------
+|
+| Functions Exported by REQUEST.C
+|
+|--------------------------------------------------------------------------*/
+
+VOID
+MadgeCompletePendingRequest(PMADGE_ADAPTER ndisAdap);
+
+NDIS_STATUS
+MadgeQueryInformation(
+ NDIS_HANDLE adapterContext,
+ NDIS_OID oid,
+ PVOID infoBuffer,
+ ULONG infoLength,
+ PULONG bytesRead,
+ PULONG bytesNeeded
+ );
+
+NDIS_STATUS
+MadgeSetInformation(
+ NDIS_HANDLE adapterContext,
+ NDIS_OID oid,
+ PVOID infoBuffer,
+ ULONG infoLength,
+ PULONG bytesRead,
+ PULONG bytesNeeded
+ );
+
+
+/*---------------------------------------------------------------------------
+|
+| Functions Exported by FTK_USER.C
+|
+|--------------------------------------------------------------------------*/
+
+void
+rxtx_await_empty_tx_slots(
+ ADAPTER_HANDLE adapter_handle
+ );
+
+void
+rxtx_adapter_removed(
+ ADAPTER_HANDLE adapter_handle
+ );
+
+
+/*---------------------------------------------------------------------------
+|
+| Debugging Macros.
+|
+|--------------------------------------------------------------------------*/
+
+#if DBG
+
+#define MadgePrint1(fmt) \
+ DbgPrint("MdgMPort: "##fmt)
+#define MadgePrint2(fmt, v1) \
+ DbgPrint("MdgMPort: "##fmt, v1)
+#define MadgePrint3(fmt, v1, v2) \
+ DbgPrint("MdgMPort: "##fmt, v1, v2)
+#define MadgePrint4(fmt, v1, v2, v3) \
+ DbgPrint("MdgMPort: "##fmt, v1, v2, v3)
+#define MadgePrint5(fmt, v1, v2, v3, v4) \
+ DbgPrint("MdgMPort: "##fmt, v1, v2, v3, v4)
+
+#define STATIC
+
+#else
+
+#define MadgePrint1(fmt)
+#define MadgePrint2(fmt, v1)
+#define MadgePrint3(fmt, v1, v2)
+#define MadgePrint4(fmt, v1, v2, v3)
+#define MadgePrint5(fmt, v1, v2, v3, v4)
+
+#define STATIC
+
+#endif
+
+
+/*---------------------------------------------------------------------------
+|
+| These event codes aren't mapped to NDIS error codes in the release DDK.
+|
+---------------------------------------------------------------------------*/
+
+#ifndef NDIS_ERROR_CODE_MEMORY_CONFLICT
+#define NDIS_ERROR_CODE_MEMORY_CONFLICT \
+ EVENT_NDIS_MEMORY_CONFLICT
+#endif
+
+#ifndef NDIS_ERROR_CODE_INVALID_DOWNLOAD_FILE_ERROR
+#define NDIS_ERROR_CODE_INVALID_DOWNLOAD_FILE_ERROR \
+ EVENT_NDIS_INVALID_DOWNLOAD_FILE_ERROR
+#endif
+
+
+/**** End of NDISMOD.H *****************************************************/
+
diff --git a/private/ntos/ndis/madge/driver/inc/user.h b/private/ntos/ndis/madge/driver/inc/user.h
new file mode 100644
index 000000000..933ac4473
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/inc/user.h
@@ -0,0 +1,235 @@
+/****************************************************************************/
+/****************************************************************************/
+/* */
+/* THE USER OPTIONS */
+/* ================ */
+/* */
+/* USER.H : Part of the FASTMAC TOOL-KIT (FTK) */
+/* */
+/* Copyright (c) Madge Networks Ltd. 1991-1994 */
+/* CONFIDENTIAL */
+/* */
+/* */
+/****************************************************************************/
+/* */
+/* This header file contains option settings that the user may configure. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+/* VERSION_NUMBER of FTK to which this USER.H belongs : */
+/* */
+
+#define FTK_VERSION_NUMBER_USER_H 221
+
+
+/****************************************************************************/
+/* */
+/* ADAPTER DOWNLOAD */
+/* */
+/* Define if you with to use FastMAC Plus. Leave undefined to use FastMAC. */
+/* */
+
+#define FMPLUS
+
+
+/****************************************************************************/
+/* */
+/* RECEIVE METHOD */
+/* */
+/* Define one method only. */
+/* */
+/* FTK_RX_OUT_OF_INTERRUPTS means that the rxtx_irq_rx_frame_handler will */
+/* be called out of the interrupt handler. This will call */
+/* user_receive_frame if there is a frame to be received. */
+/* */
+/* FTK_RX_BY_SCHEDULED_PROCESS means that the user_schedule_receive_process */
+/* is called out of the interrupt handler. The user should note that this */
+/* has happened and at his/her convenience call */
+/* driver_get_outstanding_receives which will call user_receive_frame for */
+/* each received frame. */
+/* */
+/* FTK_RX_BY_POLLING means the user should repeatedly call */
+/* driver_get_outstanding_receives to collect any received frames. */
+/* */
+
+#define FTK_RX_BY_SCHEDULED_PROCESS
+/* #define FTK_RX_BY_POLLING */
+/* #define FTK_RX_OUT_OF_INTERRUPTS */
+
+
+/****************************************************************************/
+/* */
+/* TRANSMIT METHOD */
+/* */
+/* Define only one method. These options are only relevant to FastMAC Plus. */
+/* */
+/* FTK_TX_WITH_COMPLETION means that the adapter will generate an interrupt */
+/* when it has finished with a host transmit slot buffer. The */
+/* rxtx_irq_tx_completion_check function will be called out of the interrupt*/
+/* handler so that the user can deal with the freed buffer. */
+/* */
+/* FTK_TX_WITH_POLLING means the user must poll the FastMAC Plus transmit */
+/* status values on the adapter to determine if a host transmit slot buffer */
+/* is no longer in use. */
+/* */
+
+#define FTK_TX_WITH_COMPLETION
+/* #define FTK_TX_WITH_POLLING */
+
+
+/****************************************************************************/
+/* */
+/* TRANSMIT METHOD 2 */
+/* */
+/* If FTK_TX_WITH_COMPLETION is defined then the adapter will generate */
+/* an interrupt each time its has transfered a frame from host to adapter. */
+/* Normally the user supplied routine rxtx_irq_tx_completion_check is called*/
+/* as a result. If the completion interrupt should be enabled but */
+/* rxtx_irq_tx_completion_check should not be called then define */
+/* FTK_NO_TX_COMPLETION_CALL. */
+/* */
+
+#define FTK_NO_TX_COMPLETION_CALL
+
+
+/****************************************************************************/
+/* */
+/* ADAPTER TYPE EXCLUSION */
+/* */
+/* Define one or more of these flags to disable support for adapter types. */
+/* */
+
+/* #define FTK_NO_PCMCIA */
+/* #define FTK_NO_PCI */
+/* #define FTK_NO_EISA */
+/* #define FTK_NO_ATULA */
+/* #define FTK_NO_MC */
+/* #define FTK_NO_SMART16 */
+/* #define FTK_NO_PNP */
+/* #define FTK_NO_PCIT */
+/* #define FTK_NO_PCI2 */
+
+
+/****************************************************************************/
+/* */
+/* REMOVAL OF ADAPTER PROBE SUPPORT */
+/* */
+/* Define this flags to disable support for adapter probing. */
+/* */
+
+#define FTK_NO_PROBE
+
+
+/****************************************************************************/
+/* */
+/* REMOVAL OF ERROR MESSAGES */
+/* */
+/* Define this flags to disable support for textual explinations of errors. */
+/* */
+
+#define FTK_NO_ERROR_MESSAGES
+
+
+/****************************************************************************/
+/* */
+/* SPEED ABOVE TESTING */
+/* */
+/* Define this flags to improve performance but reduce error checking. */
+/* */
+
+#define SPEED_ABOVE_TESTING
+
+
+/****************************************************************************/
+/* */
+/* CLEARING INTERRUPT CONTROLLER */
+/* */
+/* Define this flags if the interrupt routines should not call */
+/* sys_clear_controller_interrupt to clear an interrupt at the machine's */
+/* interrupt controller. */
+/* */
+
+#define FTK_NO_CLEAR_IRQ
+
+
+/****************************************************************************/
+/* */
+/* ENABLING/DISABLING IO ACCESS */
+/* */
+/* Define this flag if the macros macro_enable_io and macro_disable_io */
+/* should not be called to enable IO access and disable IO access. */
+/* */
+
+#define FTK_NO_IO_ENABLE
+
+
+/****************************************************************************/
+/* */
+/* SHARED INTERRUPTS */
+/* */
+/* Define this flag if the FTK should not poll every adapter on an */
+/* interrupt. */
+/* */
+
+#define FTK_NO_SHARED_IRQ_POLL
+
+
+/****************************************************************************/
+/* */
+/* ADAPTER REMOVAL NOTOFICATION */
+/* */
+/* Define this flag if the PCMCIA interrupt handler should call */
+/* user_adapter_removed if it detects that the PCMCIA adapter has been */
+/* removed. */
+/* */
+
+#define FTK_ADAPTER_REMOVED_NOTIFY
+
+
+/****************************************************************************/
+/* */
+/* PCMCIA 32 BIT PIO SUPPORT */
+/* */
+/* Define this flag if 32 bit PIO should be used with PCMCIA adapters that */
+/* support it. */
+/* */
+
+#define FTK_PCMCIA_32BIT_PIO
+
+
+/****************************************************************************/
+/* */
+/* POINTER SIZES */
+/* */
+/* Most of the FTK can be compiled in any memory model. However some parts */
+/* need to be able to access all of memory with a pointer (e.g. PIO and */
+/* MMIO transfer routines). These pointers are all marked with a FAR */
+/* modifier. If you are using a DOS compiler then this should be defined */
+/* to the appropriate value to mark a pointer as being 32 bit. If you are */
+/* compiling for a flat memory model then defien FAR to be nothing. */
+/* */
+
+#define FAR
+
+
+/*---------------------------------------------------------------------------
+Ý NDIS 3 Specific function memory occupancy.
+----------------------------------------------------------------------------*/
+
+#ifndef _NDIS_
+#include <ndis.h>
+#endif
+
+// #define FTK_INIT_FUNCTION(_F) NDIS_PAGABLE_FUNCTION(_F)
+#define FTK_INIT_FUNCTION(_F)
+
+
+/* */
+/* */
+/************** End of USER.H file ******************************************/
+/* */
+/* */
diff --git a/private/ntos/ndis/madge/driver/madge.c b/private/ntos/ndis/madge/driver/madge.c
new file mode 100644
index 000000000..9e3e22dda
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/madge.c
@@ -0,0 +1,3393 @@
+/***************************************************************************
+*
+* MADGE.C
+*
+* FastMAC Plus based NDIS3 miniport driver entry, initialisation and
+* closedown module.
+*
+* Copyright (c) Madge Networks Ltd 1994
+*
+* COMPANY CONFIDENTIAL
+*
+* Created: PBA 21/06/1994
+*
+****************************************************************************/
+
+#include <ndis.h>
+
+#include "ftk_defs.h"
+#include "ftk_extr.h"
+#include "ftk_intr.h"
+
+#include "mdgmport.upd"
+#include "ndismod.h"
+
+/*---------------------------------------------------------------------------
+|
+| Identification string for MVER.
+|
+---------------------------------------------------------------------------*/
+
+char MVerString[] = MVER_STRING;
+
+
+/*---------------------------------------------------------------------------
+|
+| Option strings for registry queries.
+|
+| There is a lot of fuss here to get the various strings defined in the
+| correct way - those that are optional need to be defined in the parm.
+| table as string constants, while those that are passed directly to the
+| registry query functions need to be explicitly defined outside any
+| structures.
+|
+|--------------------------------------------------------------------------*/
+
+#define HIDDEN_OFFS 0x80
+
+#define EmptyString NDIS_STRING_CONST("")
+
+//
+// These are the NT versions of the option strings.
+//
+
+#define IOAddrString NDIS_STRING_CONST("IoLocation")
+#define IOBaseString NDIS_STRING_CONST("IoBaseAddress")
+#define InterruptNumString NDIS_STRING_CONST("InterruptNumber")
+#define DMAChanString NDIS_STRING_CONST("DmaChannel")
+#define TxSlotNumString NDIS_STRING_CONST("TxSlots")
+#define RxSlotNumString NDIS_STRING_CONST("RxSlots")
+#define MaxFrameSizeString NDIS_STRING_CONST("MaxFrameSize")
+#define CardBuffSizeString NDIS_STRING_CONST("CardBufferSize")
+#define AlternateIoString NDIS_STRING_CONST("Alternate")
+#define TestAndXIDString NDIS_STRING_CONST("TestAndXIDEnabled")
+#define RxTxSlotsString NDIS_STRING_CONST("RxTxSlots")
+#define ForceOpenString NDIS_STRING_CONST("ForceOpen")
+#define Force4String NDIS_STRING_CONST("Force4")
+#define Force16String NDIS_STRING_CONST("Force16")
+#define SlotNumString NDIS_STRING_CONST("SlotNumber")
+#define NoPciMmioString NDIS_STRING_CONST("NoMmio")
+#define RingSpeedString NDIS_STRING_CONST("RingSpeed")
+#define AdapterTypeString NDIS_STRING_CONST("AdapterType")
+#define MmioAddrString NDIS_STRING_CONST("MemBase")
+#define PlatformTypeString NDIS_STRING_CONST("PlatformType")
+#define TransferTypeString NDIS_STRING_CONST("TransferType")
+
+WCHAR PromModeString[] =
+ { L'P' + HIDDEN_OFFS, L'r' + HIDDEN_OFFS, L'o' + HIDDEN_OFFS,
+ L'm' + HIDDEN_OFFS, L'i' + HIDDEN_OFFS, L's' + HIDDEN_OFFS,
+ L'c' + HIDDEN_OFFS, L'u' + HIDDEN_OFFS, L'o' + HIDDEN_OFFS,
+ L'u' + HIDDEN_OFFS, L's' + HIDDEN_OFFS, L'M' + HIDDEN_OFFS,
+ L'o' + HIDDEN_OFFS, L'd' + HIDDEN_OFFS, L'e' + HIDDEN_OFFS,
+ L'X' + HIDDEN_OFFS, 000 };
+
+#define PromiscuousString { sizeof(PromModeString) - 2, \
+ sizeof(PromModeString), \
+ PromModeString }
+
+//
+// These strings are passed direct to NdisReadConfiguration.
+//
+
+STATIC NDIS_STRING BusTypeString = NDIS_STRING_CONST("BusType");
+STATIC NDIS_STRING BusNumberString = NDIS_STRING_CONST("BusNumber");
+STATIC NDIS_STRING IOAddressString = IOAddrString;
+STATIC NDIS_STRING IOBaseAddrString = IOBaseString;
+STATIC NDIS_STRING InterruptNumberString = InterruptNumString;
+STATIC NDIS_STRING DMAChannelString = DMAChanString;
+STATIC NDIS_STRING SlotNumberString = SlotNumString;
+STATIC NDIS_STRING NoMmioString = NoPciMmioString;
+STATIC NDIS_STRING AdapterString = AdapterTypeString;
+STATIC NDIS_STRING MmioAddressString = MmioAddrString;
+STATIC NDIS_STRING PlatformString = PlatformTypeString;
+STATIC NDIS_STRING TransferModeString = TransferTypeString;
+
+STATIC NDIS_STRING NullString = EmptyString;
+
+
+/*---------------------------------------------------------------------------
+|
+| Optional parameter structure.
+|
+|--------------------------------------------------------------------------*/
+
+//
+// The Keyword parameters here use the #define's above, so the compiler is
+// kept happy about string initialisers.
+//
+
+STATIC struct
+{
+ MADGE_PARM_DEFINITION TxSlots;
+ MADGE_PARM_DEFINITION RxSlots;
+ MADGE_PARM_DEFINITION MaxFrameSize;
+ MADGE_PARM_DEFINITION CardBufferSize;
+ MADGE_PARM_DEFINITION PromiscuousMode;
+ MADGE_PARM_DEFINITION AlternateIo;
+ MADGE_PARM_DEFINITION TestAndXIDEnabled;
+ MADGE_PARM_DEFINITION RxTxSlots;
+ MADGE_PARM_DEFINITION ForceOpen;
+ MADGE_PARM_DEFINITION Force4;
+ MADGE_PARM_DEFINITION Force16;
+ MADGE_PARM_DEFINITION RingSpeed;
+ MADGE_PARM_DEFINITION NullParm;
+}
+MadgeParmTable =
+{
+ {TxSlotNumString, 2, 32, {NdisParameterInteger, 0}},
+ {RxSlotNumString, 2, 32, {NdisParameterInteger, 0}},
+ {MaxFrameSizeString, 1024, 17839, {NdisParameterInteger, 4096}},
+ {CardBuffSizeString, 0, 0xFFFF, {NdisParameterInteger, 0}},
+ {PromiscuousString, 0, 1, {NdisParameterInteger, 0}},
+ {AlternateIoString, 0, 1, {NdisParameterInteger, 0}},
+ {TestAndXIDString, 0, 1, {NdisParameterInteger, 0}},
+ {RxTxSlotsString, 0, 5, {NdisParameterInteger, 2}},
+ {ForceOpenString, 0, 1, {NdisParameterInteger, 0}},
+ {Force4String, 0, 1, {NdisParameterInteger, 0}},
+ {Force16String, 0, 1, {NdisParameterInteger, 0}},
+ {RingSpeedString, 0, 2, {NdisParameterInteger, 0}},
+ {EmptyString}
+};
+
+
+/*---------------------------------------------------------------------------
+|
+| Name of the FastMAC Plus image file.
+|
+|--------------------------------------------------------------------------*/
+
+STATIC NDIS_STRING FmpImageFileName = MADGE_FMP_NAME;
+
+
+/*---------------------------------------------------------------------------
+|
+| List of PCI adapters in use.
+|
+---------------------------------------------------------------------------*/
+
+STATIC struct
+{
+ UINT BusNumber;
+ UINT SlotNumber;
+}
+PciSlotsUsedList[MAX_NUMBER_OF_ADAPTERS];
+
+STATIC int
+PciSlotsUsedCount = 0;
+
+
+/****************************************************************************
+*
+* NDIS3 level adapter structure pointer table.
+*
+****************************************************************************/
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - MadgeReadRegistryForMC
+|
+| Parameters - wrapperConfigHandle -> Wrapper context handle.
+| registryConfigHandle -> Already open registry query handle.
+| ndisAdap -> Pointer to an NDIS3 level adapter
+| structure.
+|
+| Purpose - Read configuration information for MC adapters out of
+Ý the registry.
+|
+| Returns - An NDIS3 status code.
+|
+|--------------------------------------------------------------------------*/
+
+STATIC NDIS_STATUS
+MadgeReadRegistryForMC(
+ NDIS_HANDLE wrapperConfigHandle,
+ NDIS_HANDLE registryConfigHandle,
+ PMADGE_ADAPTER ndisAdap
+ );
+
+#pragma FTK_INIT_FUNCTION(MadgeReadRegistryForMC)
+
+STATIC NDIS_STATUS
+MadgeReadRegistryForMC(
+ NDIS_HANDLE wrapperConfigHandle,
+ NDIS_HANDLE registryConfigHandle,
+ PMADGE_ADAPTER ndisAdap
+ )
+{
+ static WORD mcaIrqMap[4] = { 0, 3, 9, 10};
+ static WORD mcaIoMap[8] = {0x0a20, 0x1a20, 0x2a20, 0x3a20,
+ 0x0e20, 0x1e20, 0x2e20, 0x3e20};
+
+ NDIS_STATUS status;
+ PNDIS_CONFIGURATION_PARAMETER configParam;
+ UINT slotNumber;
+ NDIS_MCA_POS_DATA mcaData;
+ BYTE iOSelect;
+
+ //
+ // Note the information that is always true for MC adapters.
+ //
+
+ ndisAdap->NTCardBusType = NdisInterfaceMca;
+ ndisAdap->FTKCardBusType = ADAPTER_CARD_MC_BUS_TYPE;
+ ndisAdap->TransferMode = DMA_DATA_TRANSFER_MODE;
+
+ //
+ // MicroChannel is easy - the POS registers contain all the info
+ // we need, so read those and save the information.
+ //
+
+ NdisReadMcaPosInformation(
+ &status,
+ wrapperConfigHandle,
+ &slotNumber,
+ &mcaData
+ );
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ NdisWriteErrorLogEntry(
+ ndisAdap->UsedInISR.MiniportHandle,
+ NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER,
+ 2,
+ readRegistry,
+ MADGE_ERRMSG_NO_MCA_POS
+ );
+
+ return status;
+ }
+
+ //
+ // Decode the Interrupt Number. Note: the FTK will throw
+ // IRQ 0 out as invalid.
+ //
+
+ ndisAdap->UsedInISR.InterruptNumber = mcaIrqMap[mcaData.PosData1 >> 6];
+
+ //
+ // NB: Arbitration Level 15 => PIO, which we do not allow -
+ // the FTK will throw this out as an invalid DMA channel.
+ // NB: We call it DmaChannel to be compatible with ISA cards.
+ //
+
+ ndisAdap->DmaChannel = (mcaData.PosData1 >> 1) & 0x0F;
+
+ //
+ // Build the IO Location select value from several sources.
+ //
+
+ iOSelect = (mcaData.PosData1 >> 5) & 0x01;
+ iOSelect |= (mcaData.PosData4 >> 4) & 0x02;
+ iOSelect |= (mcaData.PosData3 >> 0) & 0x04;
+
+ //
+ // NB: IO locations 0x2e20 and 0x3e20 are only valid for
+ // MC32 cards, but the .ADF file will have prevented them
+ // being set for MC16s.
+ //
+
+ ndisAdap->IoLocation1 = mcaIoMap[iOSelect];
+ ndisAdap->UsedInISR.InterruptMode = NdisInterruptLevelSensitive;
+ ndisAdap->UsedInISR.InterruptShared = TRUE;
+ ndisAdap->IORange1 = MC_IO_RANGE;
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - MadgeReadRegistryForEISA
+|
+| Parameters - wrapperConfigHandle -> Wrapper context handle.
+| registryConfigHandle -> Already open registry query handle.
+| ndisAdap -> Pointer to an NDIS3 level adapter
+| structure.
+|
+| Purpose - Read configuration information for an EISA adapter
+Ý out of the registry.
+|
+| Returns - An NDIS3 status code.
+|
+|--------------------------------------------------------------------------*/
+
+STATIC NDIS_STATUS
+MadgeReadRegistryForEISA(
+ NDIS_HANDLE wrapperConfigHandle,
+ NDIS_HANDLE registryConfigHandle,
+ PMADGE_ADAPTER ndisAdap
+ );
+
+#pragma FTK_INIT_FUNCTION(MadgeReadRegistryForEISA)
+
+STATIC NDIS_STATUS
+MadgeReadRegistryForEISA(
+ NDIS_HANDLE wrapperConfigHandle,
+ NDIS_HANDLE registryConfigHandle,
+ PMADGE_ADAPTER ndisAdap
+ )
+{
+ NDIS_STATUS status;
+ PNDIS_CONFIGURATION_PARAMETER configParam;
+ UINT slotNumber;
+ NDIS_EISA_FUNCTION_INFORMATION eisaData;
+
+ //
+ // For Eisa bus systems, we could have an Isa card or an Eisa
+ // card - try to read the Eisa information, and if that fails
+ // MadgeReadRegistry will assume it is an Isa card instead.
+ //
+
+ NdisReadEisaSlotInformation(
+ &status,
+ wrapperConfigHandle,
+ &slotNumber,
+ &eisaData
+ );
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ return status;
+ }
+
+ //
+ // Note the information that is always true for EISA
+ // adapters.
+ //
+
+ ndisAdap->NTCardBusType = NdisInterfaceEisa;
+ ndisAdap->FTKCardBusType = ADAPTER_CARD_EISA_BUS_TYPE;
+ ndisAdap->TransferMode = DMA_DATA_TRANSFER_MODE;
+
+ //
+ // Got EISA configuration data - decode the relevant bits.
+ //
+
+ ndisAdap->IoLocation1 = slotNumber << 12;
+
+ //
+ // Get the Interrupt number from the NVRAM data - we know it
+ // is going to be the first Irq element in the Irq array
+ // because the card only uses one interrupt.
+ //
+
+ ndisAdap->UsedInISR.InterruptNumber =
+ eisaData.EisaIrq[0].ConfigurationByte.Interrupt;
+
+ ndisAdap->UsedInISR.InterruptMode = (NDIS_INTERRUPT_MODE)
+ (eisaData.EisaIrq[0].ConfigurationByte.LevelTriggered
+ ? NdisInterruptLevelSensitive
+ : NdisInterruptLatched);
+
+ ndisAdap->UsedInISR.InterruptShared = (BOOLEAN)
+ eisaData.EisaIrq[0].ConfigurationByte.Shared;
+
+ //
+ // For EISA cards we don't care what the DMA setting is. So
+ // we leave it set to 0 forget about it.
+ //
+
+ ndisAdap->IORange1 = EISA_IO_RANGE;
+ ndisAdap->IoLocation2 = ndisAdap->IoLocation1 + EISA_IO_RANGE2_BASE;
+ ndisAdap->IORange2 = EISA_IO_RANGE2;
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - MadgeReadRegistryForISA
+|
+| Parameters - wrapperConfigHandle -> Wrapper context handle.
+| registryConfigHandle -> Already open registry query handle.
+| ndisAdap -> Pointer to an NDIS3 level adapter
+| structure.
+Ý adapterType -> Adapter type.
+|
+| Purpose - Read configuration information for ISA adapters out
+Ý of the registry.
+|
+| Returns - An NDIS3 status code.
+|
+|--------------------------------------------------------------------------*/
+
+STATIC NDIS_STATUS
+MadgeReadRegistryForISA(
+ NDIS_HANDLE wrapperConfigHandle,
+ NDIS_HANDLE registryConfigHandle,
+ PMADGE_ADAPTER ndisAdap,
+ ULONG adapterType
+ );
+
+#pragma FTK_INIT_FUNCTION(MadgeReadRegistryForISA)
+
+STATIC NDIS_STATUS
+MadgeReadRegistryForISA(
+ NDIS_HANDLE wrapperConfigHandle,
+ NDIS_HANDLE registryConfigHandle,
+ PMADGE_ADAPTER ndisAdap,
+ ULONG adapterType
+ )
+{
+ NDIS_STATUS status;
+ PNDIS_CONFIGURATION_PARAMETER configParam;
+
+ //
+ // Note the information that is always TRUE for ISA adapters.
+ //
+
+ ndisAdap->NTCardBusType = NdisInterfaceIsa;
+
+ //
+ // Do some adapter type specific setup. If we don't
+ // know what sort of adapter it is we'll assume it's
+ // an ATULA adapter so we are backwards compatible.
+ //
+
+ switch (adapterType)
+ {
+ case MADGE_ADAPTER_UNKNOWN:
+ case MADGE_ADAPTER_ATULA:
+
+ ndisAdap->FTKCardBusType = ADAPTER_CARD_ATULA_BUS_TYPE;
+ ndisAdap->IORange1 = ATULA_IO_RANGE;
+ ndisAdap->TransferMode = DMA_DATA_TRANSFER_MODE;
+ break;
+
+ case MADGE_ADAPTER_SMART16:
+
+ ndisAdap->FTKCardBusType = ADAPTER_CARD_SMART16_BUS_TYPE;
+ ndisAdap->IORange1 = SMART16_IO_RANGE;
+ ndisAdap->TransferMode = PIO_DATA_TRANSFER_MODE;
+ break;
+
+ case MADGE_ADAPTER_PCMCIA:
+
+ ndisAdap->FTKCardBusType = ADAPTER_CARD_PCMCIA_BUS_TYPE;
+ ndisAdap->IORange1 = PCMCIA_IO_RANGE;
+ ndisAdap->TransferMode = PIO_DATA_TRANSFER_MODE;
+ break;
+
+ case MADGE_ADAPTER_PNP:
+
+ ndisAdap->FTKCardBusType = ADAPTER_CARD_PNP_BUS_TYPE;
+ ndisAdap->IORange1 = PNP_IO_RANGE;
+ ndisAdap->TransferMode = PIO_DATA_TRANSFER_MODE;
+ break;
+
+ default:
+
+ return NDIS_STATUS_FAILURE;
+ }
+
+ //
+ // Get the IO location - must have this. First try
+ // "IoLocation" and then "IoBaseAddress".
+ //
+
+ NdisReadConfiguration(
+ &status,
+ &configParam,
+ registryConfigHandle,
+ &IOAddressString,
+ NdisParameterHexInteger
+ );
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ NdisReadConfiguration(
+ &status,
+ &configParam,
+ registryConfigHandle,
+ &IOBaseAddrString,
+ NdisParameterHexInteger
+ );
+ }
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ NdisWriteErrorLogEntry(
+ ndisAdap->UsedInISR.MiniportHandle,
+ NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER,
+ 2,
+ readRegistry,
+ MADGE_ERRMSG_NO_ISA_IO
+ );
+
+ return status;
+ }
+
+ ndisAdap->IoLocation1 = configParam->ParameterData.IntegerData;
+
+ //
+ // Er, slight hack here. We used to pretend that Smart16
+ // adapters were ATULA adapters. We now don't. So to
+ // be backwards compatible, if we have an unknown adapter
+ // with an IO base >= 0x4a20 and <= 0x6e20 we'll assume it's
+ // really a Smart16.
+ //
+
+ if (adapterType == MADGE_ADAPTER_UNKNOWN &&
+ ndisAdap->IoLocation1 >= 0x4a20 &&
+ ndisAdap->IoLocation1 <= 0x6e20)
+ {
+ adapterType = MADGE_ADAPTER_SMART16;
+ ndisAdap->FTKCardBusType = ADAPTER_CARD_SMART16_BUS_TYPE;
+ ndisAdap->IORange1 = SMART16_IO_RANGE;
+ ndisAdap->TransferMode = PIO_DATA_TRANSFER_MODE;
+ }
+
+ //
+ // Get the IRQ number - we must have this.
+ //
+
+ NdisReadConfiguration(
+ &status,
+ &configParam,
+ registryConfigHandle,
+ &InterruptNumberString,
+ NdisParameterInteger
+ );
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ NdisWriteErrorLogEntry(
+ ndisAdap->UsedInISR.MiniportHandle,
+ NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER,
+ 2,
+ readRegistry,
+ MADGE_ERRMSG_NO_ISA_IRQ
+ );
+
+ return status;
+ }
+
+ ndisAdap->UsedInISR.InterruptNumber =
+ configParam->ParameterData.IntegerData;
+
+ ndisAdap->UsedInISR.InterruptMode = NdisInterruptLatched;
+ ndisAdap->UsedInISR.InterruptShared = FALSE;
+
+ //
+ // Read the TransferType parameter and switch into PIO
+ // mode if specified.
+ //
+
+ NdisReadConfiguration(
+ &status,
+ &configParam,
+ registryConfigHandle,
+ &TransferModeString,
+ NdisParameterInteger
+ );
+
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ if (configParam->ParameterData.IntegerData == MADGE_PIO_MODE)
+ {
+ ndisAdap->TransferMode = PIO_DATA_TRANSFER_MODE;
+ }
+ }
+
+ //
+ // Get the DMA channel (PIO is specified as channel 0,
+ // multiprocessor safe PIO is specified as 0x8000). We
+ // don't need a DMA channel if the adapter isn't an ATULA so
+ // the only reason for reading the DMA channel for none
+ // ATULA adapters is to allow backwards compatability with old
+ // registry set ups that specify multiprocessor safe PIO
+ // with the DmaChannel == 0x8000. Using the DMA channel
+ // to specify PIO is retained for backwards compatibility
+ // the correct way is to set the TransferType parameter.
+ //
+
+ NdisReadConfiguration(
+ &status,
+ &configParam,
+ registryConfigHandle,
+ &DMAChannelString,
+ NdisParameterInteger
+ );
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ ndisAdap->DmaChannel = 0;
+ }
+ else
+ {
+ ndisAdap->DmaChannel = configParam->ParameterData.IntegerData;
+ }
+
+ //
+ // Note if we should be using multiprocessor safe PIO.
+ //
+
+ if (ndisAdap->DmaChannel == 0x8000)
+ {
+ ndisAdap->DmaChannel = 0;
+ ndisAdap->UseMPSafePIO = TRUE;
+ }
+
+ //
+ // If we did not get a DMA channel then we must use PIO.
+ //
+
+ if (ndisAdap->DmaChannel == 0)
+ {
+ ndisAdap->TransferMode = PIO_DATA_TRANSFER_MODE;
+ }
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - MadgeFindPciInfoForWin95
+|
+| Parameters - wrapperConfigHandle -> Wrapper context handle.
+| registryConfigHandle -> Already open registry query handle.
+| ndisAdap -> Pointer to an NDIS3 level adapter
+| structure.
+Ý pciSlotInfo -> Pointer to a buffer that will
+Ý be filled with the configuration
+Ý data for the adapter.
+|
+| Purpose - Read configuration information for PCI adapters out
+Ý of the registry when running on Windows95. The slot
+Ý containing the adapter is also found and the configuration
+Ý data from the slot returned in the pciSlotInfo buffer.
+|
+| Returns - An NDIS3 status code.
+|
+|--------------------------------------------------------------------------*/
+
+STATIC NDIS_STATUS
+MadgeFindPciInfoForWin95(
+ NDIS_HANDLE wrapperConfigHandle,
+ NDIS_HANDLE registryConfigHandle,
+ PMADGE_ADAPTER ndisAdap,
+ BYTE * pciSlotInfo
+ );
+
+#pragma FTK_INIT_FUNCTION(MadgeFindPciInfoForWin95)
+
+STATIC NDIS_STATUS
+MadgeFindPciInfoForWin95(
+ NDIS_HANDLE wrapperConfigHandle,
+ NDIS_HANDLE registryConfigHandle,
+ PMADGE_ADAPTER ndisAdap,
+ BYTE * pciSlotInfo
+
+ )
+{
+ NDIS_STATUS status;
+ PNDIS_CONFIGURATION_PARAMETER configParam;
+ UINT i;
+
+ //
+ // Unfortunately Windows95 (M7) and NT handle PCI configuration
+ // in different ways. Under NT one has to read the slot
+ // configuration. Under Windows95 the resource information
+ // is faked up by the configuration manager and can be read
+ // directly from the wrapper.
+ //
+
+ //
+ // Get the IO location - must have this. First try
+ // "IoLocation" and then "IoBaseAddress".
+ //
+
+ NdisReadConfiguration(
+ &status,
+ &configParam,
+ registryConfigHandle,
+ &IOAddressString,
+ NdisParameterHexInteger
+ );
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ NdisReadConfiguration(
+ &status,
+ &configParam,
+ registryConfigHandle,
+ &IOBaseAddrString,
+ NdisParameterHexInteger
+ );
+ }
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ NdisWriteErrorLogEntry(
+ ndisAdap->UsedInISR.MiniportHandle,
+ NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER,
+ 2,
+ readRegistry,
+ MADGE_ERRMSG_NO_PCI_IO
+ );
+
+ return status;
+ }
+
+ ndisAdap->IoLocation1 = configParam->ParameterData.IntegerData;
+
+ //
+ // Get the IRQ number - we must have this.
+ //
+
+ NdisReadConfiguration(
+ &status,
+ &configParam,
+ registryConfigHandle,
+ &InterruptNumberString,
+ NdisParameterInteger
+ );
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ NdisWriteErrorLogEntry(
+ ndisAdap->UsedInISR.MiniportHandle,
+ NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER,
+ 2,
+ readRegistry,
+ MADGE_ERRMSG_NO_PCI_IRQ
+ );
+
+ return status;
+ }
+
+ ndisAdap->UsedInISR.InterruptNumber =
+ configParam->ParameterData.IntegerData;
+
+ //
+ // Get the MMIO base address - optional.
+ //
+
+ NdisReadConfiguration(
+ &status,
+ &configParam,
+ registryConfigHandle,
+ &MmioAddressString,
+ NdisParameterInteger
+ );
+
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ ndisAdap->MmioRawAddress =
+ configParam->ParameterData.IntegerData;
+ }
+
+ //
+ // We also need to know which slot the adapter is in so we can
+ // read and write configuration space directly. We'll search for
+ // a slot which contains a Madge adapter which the correct I/O
+ // location. As a side effect we'll store the configuration data
+ // for the slot in pciSlotInfo. Note: Under Windows 95 (build 490)
+ // NdisReadPciSlotInformation does appear to return the number
+ // of bytes read as it does under NT - not sure what it returns ...
+ //
+
+ ndisAdap->SlotNumber = PCI_FIND_ADAPTER;
+
+ for (i = 0; i < MAX_PCI_SLOTS; i++)
+ {
+ NdisReadPciSlotInformation(
+ ndisAdap->UsedInISR.MiniportHandle,
+ i,
+ 0,
+ (VOID *) pciSlotInfo,
+ PCI_CONFIG_SIZE
+ );
+
+ if (PCI_VENDOR_ID(pciSlotInfo) == MADGE_PCI_VENDOR_ID &&
+ PCI_IO_BASE(pciSlotInfo) == ndisAdap->IoLocation1)
+ {
+ ndisAdap->SlotNumber = i;
+ break;
+ }
+ }
+
+ if (ndisAdap->SlotNumber == PCI_FIND_ADAPTER)
+ {
+ NdisWriteErrorLogEntry(
+ ndisAdap->UsedInISR.MiniportHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ readRegistry,
+ MADGE_ERRMSG_BAD_PCI_SLOTNUMBER
+ );
+
+ return NDIS_STATUS_FAILURE;
+ }
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+/*---------------------------------------------------------------------------
+Ý Function - MadgePciSlotUsed
+Ý Parameters - busNumber -> Bus number containing the adapter.
+Ý slotNumber -> Slot number containing the adapter.
+Ý Purpose - Check if a PCI slot is already in use.
+Ý Returns - TRUE if the slot is in use or FALSE if not.
+Ý--------------------------------------------------------------------------*/
+
+STATIC BOOLEAN
+MadgePciSlotUsed(
+ UINT busNumber,
+ UINT slotNumber
+ );
+
+#pragma FTK_INIT_FUNCTION(MadgePciSlotUsed)
+
+STATIC BOOLEAN
+MadgePciSlotUsed(
+ UINT busNumber,
+ UINT slotNumber
+ )
+{
+ int i;
+
+ for (i = 0; i < PciSlotsUsedCount; i++)
+ {
+ if (PciSlotsUsedList[i].BusNumber == busNumber &&
+ PciSlotsUsedList[i].SlotNumber == slotNumber)
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - MadgeFindPciInfoForNt
+|
+| Parameters - wrapperConfigHandle -> Wrapper context handle.
+| registryConfigHandle -> Already open registry query handle.
+| ndisAdap -> Pointer to an NDIS3 level adapter
+| structure.
+Ý pciSlotInfo -> Pointer to a buffer that will
+Ý be filled with the configuration
+Ý data for the adapter.
+|
+| Purpose - Read configuration information for PCI adapters out
+Ý of the registry when running on Windows95. The slot
+Ý containing the adapter is also found and the configuration
+Ý data from the slot returned in the pciSlotInfo buffer.
+|
+| Returns - An NDIS3 status code.
+|
+|--------------------------------------------------------------------------*/
+
+STATIC NDIS_STATUS
+MadgeFindPciInfoForNt(
+ NDIS_HANDLE wrapperConfigHandle,
+ NDIS_HANDLE registryConfigHandle,
+ PMADGE_ADAPTER ndisAdap,
+ BYTE * pciSlotInfo
+ );
+
+#pragma FTK_INIT_FUNCTION(MadgeFindPciInfoForNt)
+
+STATIC NDIS_STATUS
+MadgeFindPciInfoForNt(
+ NDIS_HANDLE wrapperConfigHandle,
+ NDIS_HANDLE registryConfigHandle,
+ PMADGE_ADAPTER ndisAdap,
+ BYTE * pciSlotInfo
+ )
+{
+ NDIS_STATUS status;
+ PNDIS_CONFIGURATION_PARAMETER configParam;
+ UINT slotNumber;
+ BOOLEAN pciSlotRead;
+ BOOLEAN useMmio;
+ UINT i;
+ PNDIS_RESOURCE_LIST pciResources;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR resDesc;
+ UINT busNumber;
+
+ //
+ // Unfortunately Windows95 (M7) and NT handle PCI configuration
+ // in different ways. Under NT one has to read the slot
+ // configuration. Under Windows95 the resource information
+ // is faked up by the configuration manager and can be read
+ // directly from the wrapper.
+ //
+
+ //
+ // Find out what the slot number is. This is in fact the
+ // PCI device number. Values 0 through 31 represent real
+ // slot numbers. 0xffff means we should search for the
+ // first unused Madge PCI adapter.
+ //
+
+ NdisReadConfiguration(
+ &status,
+ &configParam,
+ registryConfigHandle,
+ &SlotNumberString,
+ NdisParameterInteger
+ );
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ NdisWriteErrorLogEntry(
+ ndisAdap->UsedInISR.MiniportHandle,
+ NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER,
+ 2,
+ readRegistry,
+ MADGE_ERRMSG_NO_PCI_SLOTNUMBER
+ );
+
+ return status;
+ }
+
+ slotNumber = configParam->ParameterData.IntegerData;
+ pciSlotRead = FALSE;
+
+ //
+ // Read the bus number.
+ //
+
+ NdisReadConfiguration(
+ &status,
+ &configParam,
+ registryConfigHandle,
+ &BusNumberString,
+ NdisParameterInteger
+ );
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ NdisWriteErrorLogEntry(
+ ndisAdap->UsedInISR.MiniportHandle,
+ NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER,
+ 2,
+ readRegistry,
+ MADGE_ERRMSG_NO_PCI_SLOTNUMBER
+ );
+
+ return status;
+ }
+
+ busNumber = configParam->ParameterData.IntegerData;
+
+ //
+ // If the slot number is PCI_FIND_ADAPTER (0xffff) then we
+ // will attempt to search for the first Madge PCI adapter
+ // that is not already in use.
+ //
+
+ if (slotNumber == PCI_FIND_ADAPTER)
+ {
+ for (i = 0; !pciSlotRead && i < MAX_PCI_SLOTS; i++)
+ {
+ if (!MadgePciSlotUsed(busNumber, i))
+ {
+ //
+ // Extract the PCI configuration information from
+ // the slot.
+ //
+
+ status = NdisReadPciSlotInformation(
+ ndisAdap->UsedInISR.MiniportHandle,
+ i,
+ 0,
+ (VOID *) pciSlotInfo,
+ PCI_CONFIG_SIZE
+ );
+ //
+ // Check if the slot contains a Madge adapter and
+ // break out of the loop if it does.
+ //
+
+ if (status == PCI_CONFIG_SIZE &&
+ PCI_VENDOR_ID(pciSlotInfo) == MADGE_PCI_VENDOR_ID)
+ {
+ slotNumber = i;
+ pciSlotRead = TRUE;
+ }
+ }
+ }
+ }
+
+ //
+ // Check if the slotNumber is valid. This will fail if the
+ // above adapter search failed.
+ //
+
+ if (slotNumber < 0 ||
+ slotNumber >= MAX_PCI_SLOTS ||
+ MadgePciSlotUsed(busNumber, slotNumber))
+ {
+ NdisWriteErrorLogEntry(
+ ndisAdap->UsedInISR.MiniportHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ readRegistry,
+ MADGE_ERRMSG_BAD_PCI_SLOTNUMBER
+ );
+
+ return NDIS_STATUS_FAILURE;
+ }
+
+ //
+ // Note that the PCI slot is in use.
+ //
+
+ PciSlotsUsedList[PciSlotsUsedCount].BusNumber = busNumber;
+ PciSlotsUsedList[PciSlotsUsedCount].SlotNumber = slotNumber;
+ PciSlotsUsedCount++;
+
+ ndisAdap->SlotNumber = slotNumber;
+
+ //
+ // There two methods for getting the PCI configuration. One is
+ // to read it directly from the PCI configuration space. This
+ // works for Intel patforms where a PCI BIOS has configured
+ // all of the adapters at boot time. It does not work for
+ // none Intel platforms where the PCI devices are not
+ // configured at boot time. Unfortunately the call which
+ // provokes NT to configure a PCI device, NdisMPciAssignResources
+ // is not available in the NT 3.5 wrapper. So, until NT 3.51
+ // becomes dominant we must support both configuration methods.
+ //
+
+ //
+ // If we haven't already extracted the PCI configuration
+ // information from the slot and check that it is valid.
+ //
+
+ if (!pciSlotRead)
+ {
+ status = NdisReadPciSlotInformation(
+ ndisAdap->UsedInISR.MiniportHandle,
+ slotNumber,
+ 0,
+ (VOID *) pciSlotInfo,
+ PCI_CONFIG_SIZE
+ );
+
+ if (status != PCI_CONFIG_SIZE ||
+ PCI_VENDOR_ID(pciSlotInfo) != MADGE_PCI_VENDOR_ID)
+ {
+ MadgePrint1("No Madge adapter in slot\n");
+
+ NdisWriteErrorLogEntry(
+ ndisAdap->UsedInISR.MiniportHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ readRegistry,
+ MADGE_ERRMSG_BAD_PCI_SLOTNUMBER
+ );
+
+ return NDIS_STATUS_FAILURE;
+ }
+ }
+
+ //
+ // Call NdisMPciAssignResources for the specified slot to
+ // get the adapter configuration.
+ //
+
+ status = NdisMPciAssignResources(
+ ndisAdap->UsedInISR.MiniportHandle,
+ slotNumber,
+ &pciResources
+ );
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ NdisWriteErrorLogEntry(
+ ndisAdap->UsedInISR.MiniportHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ readRegistry,
+ MADGE_ERRMSG_BAD_PCI_SLOTNUMBER
+ );
+
+ return NDIS_STATUS_FAILURE;
+ }
+
+ //
+ // Iterate through the returned resource list recording the values
+ // in the PCI configuration
+ //
+
+ for (i = 0; i < pciResources->Count; i++)
+ {
+ resDesc = &pciResources->PartialDescriptors[i];
+
+ switch (resDesc->Type)
+ {
+ case CmResourceTypeInterrupt:
+
+ ndisAdap->UsedInISR.InterruptNumber =
+ (ULONG) resDesc->u.Interrupt.Vector;
+ break;
+
+ case CmResourceTypePort:
+
+ ndisAdap->IoLocation1 =
+ (UINT) NdisGetPhysicalAddressLow(resDesc->u.Port.Start);
+ break;
+
+ case CmResourceTypeMemory:
+
+ ndisAdap->MmioRawAddress =
+ (DWORD) NdisGetPhysicalAddressLow(resDesc->u.Memory.Start);
+ break;
+ }
+ }
+
+
+ //
+ // On none-Intel platforms it's possible for the PCI adapter's I/O
+ // base to be greater than 0xffff. Since the FTK uses 16bit
+ // I/O locations we make a note of the I/O base in a 32bit cell
+ // that we can add in inside the I/O functions in sys_mem.c
+ //
+
+#ifndef _M_IX86
+
+ ndisAdap->IoLocationBase = ndisAdap->IoLocation1;
+ ndisAdap->IoLocation1 = 0;
+
+#endif
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - MadgeReadRegistryForPCI
+|
+| Parameters - wrapperConfigHandle -> Wrapper context handle.
+| registryConfigHandle -> Already open registry query handle.
+| ndisAdap -> Pointer to an NDIS3 level adapter
+| structure.
+Ý platformType -> Type of platform: NT or Win95.
+|
+| Purpose - Read configuration information for PCI.
+|
+| Returns - An NDIS3 status code.
+|
+|--------------------------------------------------------------------------*/
+
+STATIC NDIS_STATUS
+MadgeReadRegistryForPCI(
+ NDIS_HANDLE wrapperConfigHandle,
+ NDIS_HANDLE registryConfigHandle,
+ PMADGE_ADAPTER ndisAdap,
+ UINT platformType
+ );
+
+#pragma FTK_INIT_FUNCTION(MadgeReadRegistryForPCI)
+
+STATIC NDIS_STATUS
+MadgeReadRegistryForPCI(
+ NDIS_HANDLE wrapperConfigHandle,
+ NDIS_HANDLE registryConfigHandle,
+ PMADGE_ADAPTER ndisAdap,
+ UINT platformType
+ )
+{
+ NDIS_STATUS status;
+ PNDIS_CONFIGURATION_PARAMETER configParam;
+ BYTE pciSlotInfo[PCI_CONFIG_SIZE];
+ BOOLEAN useMmio;
+
+ //
+ // Note the information that is always true for PCI adapters.
+ //
+
+ ndisAdap->NTCardBusType = NdisInterfacePci;
+
+ //
+ // Set up the fixed configuration information.
+ //
+
+ ndisAdap->UsedInISR.InterruptMode = NdisInterruptLevelSensitive;
+ ndisAdap->UsedInISR.InterruptShared = TRUE;
+
+ //
+ // We know need to find the PCI adapter and read in the configuration
+ // information for the slot. Unfortunatetly the method we have to use
+ // is different for NT and Win95.
+ //
+
+ if (platformType == MADGE_OS_WIN95)
+ {
+ status = MadgeFindPciInfoForWin95(
+ wrapperConfigHandle,
+ registryConfigHandle,
+ ndisAdap,
+ pciSlotInfo
+ );
+ }
+ else
+ {
+ status = MadgeFindPciInfoForNt(
+ wrapperConfigHandle,
+ registryConfigHandle,
+ ndisAdap,
+ pciSlotInfo
+ );
+ }
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ return status;
+ }
+
+ //
+ // Now we know we have a Madge PCI adapter of some sort but
+ // as yet we don't know what type. We'll work this out by
+ // looking at the device/revision ID in the slot's configuration
+ // data. At the same time we'll note the default transfer type
+ // for the adapter.
+ //
+
+ switch (PCI_REVISION(pciSlotInfo))
+ {
+ case MADGE_PCI_RAP1B_REVISION:
+
+ ndisAdap->FTKCardBusType = ADAPTER_CARD_PCI_BUS_TYPE;
+ ndisAdap->TransferMode = MMIO_DATA_TRANSFER_MODE;
+ ndisAdap->IORange1 = PCI_IO_RANGE;
+ break;
+
+ case MADGE_PCI_PCI2_REVISION:
+
+ ndisAdap->FTKCardBusType = ADAPTER_CARD_PCI2_BUS_TYPE;
+ ndisAdap->TransferMode = DMA_DATA_TRANSFER_MODE;
+ ndisAdap->IORange1 = PCI2_IO_RANGE;
+ break;
+
+ case MADGE_PCI_PCIT_REVISION:
+
+ ndisAdap->FTKCardBusType = ADAPTER_CARD_TI_PCI_BUS_TYPE;
+ ndisAdap->TransferMode = DMA_DATA_TRANSFER_MODE;
+ ndisAdap->IORange1 = SIF_IO_RANGE;
+ break;
+
+ default:
+
+ return NDIS_STATUS_FAILURE;
+ }
+
+ //
+ // Now we need to work out the transfer type. There are three
+ // things that affect the transfer type: the setting of
+ // the TransferType registry parameter, the setting of the
+ // NoMmio registry flag and whether we have been allocated any
+ // MMIO memory. Ideally we would just use the TransferType flag.
+ // The NoMmio flag is to preserve backwards compatibility with old
+ // registry set ups.
+ //
+
+ //
+ // Read the transfer type flag if possible.
+ //
+
+ NdisReadConfiguration(
+ &status,
+ &configParam,
+ registryConfigHandle,
+ &TransferModeString,
+ NdisParameterInteger
+ );
+
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Set the transfer type depending on the TransferType parameter
+ // and the adapter type.
+ //
+
+ if (configParam->ParameterData.IntegerData == MADGE_DMA_MODE)
+ {
+ if (ndisAdap->FTKCardBusType == ADAPTER_CARD_PCI2_BUS_TYPE ||
+ ndisAdap->FTKCardBusType == ADAPTER_CARD_TI_PCI_BUS_TYPE)
+ {
+ ndisAdap->TransferMode = DMA_DATA_TRANSFER_MODE;
+ }
+ }
+
+ if (configParam->ParameterData.IntegerData == MADGE_PIO_MODE)
+ {
+ ndisAdap->TransferMode = PIO_DATA_TRANSFER_MODE;
+ }
+
+ if (configParam->ParameterData.IntegerData == MADGE_MMIO_MODE)
+ {
+ if (ndisAdap->FTKCardBusType == ADAPTER_CARD_PCI_BUS_TYPE)
+ {
+ ndisAdap->TransferMode = MMIO_DATA_TRANSFER_MODE;
+ }
+ }
+ }
+
+ //
+ // To preserve backwards compatibility if we find the NoMmio flag
+ // set then switch to PIO mode.
+ //
+
+ if (ndisAdap->TransferMode == MMIO_DATA_TRANSFER_MODE)
+ {
+ NdisReadConfiguration(
+ &status,
+ &configParam,
+ registryConfigHandle,
+ &NoMmioString,
+ NdisParameterInteger
+ );
+
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ if (configParam->ParameterData.IntegerData != 0)
+ {
+ ndisAdap->TransferMode = PIO_DATA_TRANSFER_MODE;
+ }
+ }
+ }
+
+ //
+ // If we are in MMIO mode then check that we were allocated some MMIO
+ // memory. If not switch to PIO mode.
+ //
+
+ if (ndisAdap->TransferMode == MMIO_DATA_TRANSFER_MODE)
+ {
+ if (ndisAdap->MmioRawAddress == 0)
+ {
+ NdisWriteErrorLogEntry(
+ ndisAdap->UsedInISR.MiniportHandle,
+ NDIS_ERROR_CODE_MEMORY_CONFLICT,
+ 2,
+ readRegistry,
+ MADGE_ERRMSG_BAD_PCI_MMIO
+ );
+
+ ndisAdap->TransferMode == PIO_DATA_TRANSFER_MODE;
+
+ }
+ }
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - MadgeReadRegistry
+|
+| Parameters - wrapperConfigHandle -> Wrapper context handle.
+| registryConfigHandle -> Already open registry query handle.
+| ndisAdap -> Pointer to an NDIS3 level adapter
+| structure.
+|
+| Purpose - Read configuration information out of the registry.
+|
+| Returns - An NDIS3 status code.
+|
+|--------------------------------------------------------------------------*/
+
+STATIC NDIS_STATUS
+MadgeReadRegistry(
+ NDIS_HANDLE wrapperConfigHandle,
+ NDIS_HANDLE registryConfigHandle,
+ PMADGE_ADAPTER ndisAdap
+ );
+
+#pragma FTK_INIT_FUNCTION(MadgeReadRegistry)
+
+STATIC NDIS_STATUS
+MadgeReadRegistry(
+ NDIS_HANDLE wrapperConfigHandle,
+ NDIS_HANDLE registryConfigHandle,
+ PMADGE_ADAPTER ndisAdap
+ )
+{
+ NDIS_STATUS status;
+ PNDIS_CONFIGURATION_PARAMETER configParam;
+ MADGE_PARM_DEFINITION * pMadgeParmTable;
+ PVOID networkAddress;
+ ULONG networkAddressLength;
+ UINT adapterType;
+ UINT platformType;
+
+ //
+ // Try to read the OS platform type. If we don't find one then
+ // assume we are running on NT.
+ //
+
+ NdisReadConfiguration(
+ &status,
+ &configParam,
+ registryConfigHandle,
+ &PlatformString,
+ NdisParameterInteger
+ );
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ platformType = MADGE_OS_NT;
+ }
+ else
+ {
+ platformType = configParam->ParameterData.IntegerData;
+ }
+
+ //
+ // Read the system bus type - that will give us a direction
+ // in which to search for further details.
+ //
+
+ NdisReadConfiguration(
+ &status,
+ &configParam,
+ registryConfigHandle,
+ &BusTypeString,
+ NdisParameterInteger
+ );
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ NdisWriteErrorLogEntry(
+ ndisAdap->UsedInISR.MiniportHandle,
+ NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER,
+ 2,
+ readRegistry,
+ MADGE_ERRMSG_NO_BUS_TYPE
+ );
+
+ return status;
+ }
+
+ ndisAdap->BusType = configParam->ParameterData.IntegerData;
+
+ //
+ // Originally we determined what sort of adapter we had based
+ // on the bus type returned by the configuration call to the
+ // wrapper. This works for NT but doesn't for Windows95 (M7)
+ // which seems to fail to identify a card as being in a PCI
+ // bus. We also cannot tell between the various sorts of ISA
+ // adapter now available. To fix this we look in the registry
+ // for an adapter type parameter. We use this and the bus type
+ // returned by the wrapper to work out where to start. We don't
+ // fail if we can't read an adapter type so that we will work with
+ // old registry set ups.
+ //
+ // Build 310 of Windows95 seems to return the native bus type of the
+ // PC. This means on a PCI machine we always get NdisInterfacePci.
+ // To get around this problem we will work out the bus type from
+ // the adapter type parameter if one is present.
+ //
+ // Unfortunately we can't just abandon the bus type de-multiplexing
+ // if we are to work with old NT registry set ups.
+ //
+
+ NdisReadConfiguration(
+ &status,
+ &configParam,
+ registryConfigHandle,
+ &AdapterString,
+ NdisParameterInteger
+ );
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ adapterType = MADGE_ADAPTER_UNKNOWN;
+ }
+ else
+ {
+ adapterType = configParam->ParameterData.IntegerData;
+ }
+
+ switch (adapterType)
+ {
+ case MADGE_ADAPTER_ATULA:
+ case MADGE_ADAPTER_PCMCIA:
+ case MADGE_ADAPTER_PNP:
+ case MADGE_ADAPTER_SMART16:
+
+ ndisAdap->BusType = NdisInterfaceIsa;
+ break;
+
+ case MADGE_ADAPTER_EISA:
+
+ ndisAdap->BusType = NdisInterfaceEisa;
+ break;
+
+ case MADGE_ADAPTER_MC:
+
+ ndisAdap->BusType = NdisInterfaceMca;
+ break;
+
+ case MADGE_ADAPTER_PCI:
+
+ ndisAdap->BusType = NdisInterfacePci;
+ break;
+
+ default:
+
+ //
+ // We don't have a valid adapter type parameter so we'll
+ // just have to beleive the bus type the wrapper passed
+ // us.
+ //
+
+ break;
+ }
+
+ //
+ // Based on the determined Bus Type, try to find details of the card.
+ //
+
+ //
+ // Remember, all fields of the MADGE_ADAPTER structure were zeroed
+ // after the structure's allocation.
+ //
+
+ switch (ndisAdap->BusType)
+ {
+ case NdisInterfaceMca:
+
+ status = MadgeReadRegistryForMC(
+ wrapperConfigHandle,
+ registryConfigHandle,
+ ndisAdap
+ );
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ return status;
+ }
+
+ break;
+
+ case NdisInterfaceEisa:
+
+ //
+ // For Eisa bus systems, we could have an Isa card or an Eisa
+ // card - try to read the Eisa information, and if that fails
+ // assume it is an Isa card instead.
+ //
+
+ status = MadgeReadRegistryForEISA(
+ wrapperConfigHandle,
+ registryConfigHandle,
+ ndisAdap
+ );
+
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ //
+ // Failed to read EISA data for this card, so it is unlikely
+ // to be one - try ISA instead - fall through.
+ //
+
+ case NdisInterfaceIsa:
+
+ status = MadgeReadRegistryForISA(
+ wrapperConfigHandle,
+ registryConfigHandle,
+ ndisAdap,
+ adapterType
+ );
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ return status;
+ }
+
+ break;
+
+ case NdisInterfacePci:
+
+ status = MadgeReadRegistryForPCI(
+ wrapperConfigHandle,
+ registryConfigHandle,
+ ndisAdap,
+ platformType
+ );
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ return status;
+ }
+
+ break;
+
+
+ default:
+
+ //
+ // Unsupported Bus Type, so return failure - no point being more
+ // explicit than that at the moment since any of the bits above
+ // could have failed too, and they do not return anything more
+ // meaningful either.
+ //
+
+ return NDIS_STATUS_FAILURE;
+ }
+
+ MadgePrint2("FTKCardBusType = %d\n", ndisAdap->FTKCardBusType);
+ MadgePrint2("SlotNumber = %d\n", ndisAdap->SlotNumber);
+ MadgePrint2("IoLocation1 = %lx\n", ndisAdap->IoLocation1);
+ MadgePrint2("MmioAddress = %lx\n", ndisAdap->MmioRawAddress);
+ MadgePrint2("InterruptNumber = %lx\n", ndisAdap->UsedInISR.InterruptNumber);
+ MadgePrint2("TransferMode = %d\n", ndisAdap->TransferMode);
+ MadgePrint2("DmaChannel = %d\n", ndisAdap->DmaChannel);
+
+ //
+ // To get here, we must have worked out the IO Address, IRQ number, DMA
+ // channel/arbitration level, and all the interrupt details. This just
+ // leaves the optional parameters for tuning the performance of the MAC
+ // code.
+ //
+
+ pMadgeParmTable = (MADGE_PARM_DEFINITION *) &MadgeParmTable;
+
+ while (!NdisEqualString(&pMadgeParmTable->Keyword, &NullString, TRUE))
+ {
+ NdisReadConfiguration(
+ &status,
+ &configParam,
+ registryConfigHandle,
+ &pMadgeParmTable->Keyword,
+ pMadgeParmTable->DefaultValue.ParameterType
+ );
+
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Did read something. Check bounds. We assume all are Integers.
+ //
+
+ if (configParam->ParameterData.IntegerData <
+ pMadgeParmTable->Minimum ||
+ configParam->ParameterData.IntegerData >
+ pMadgeParmTable->Maximum)
+ {
+ NdisWriteErrorLogEntry(
+ ndisAdap->UsedInISR.MiniportHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ readRegistry,
+ MADGE_ERRMSG_BAD_PARAMETER
+ );
+
+ pMadgeParmTable->ActualValue = pMadgeParmTable->DefaultValue;
+ }
+ else
+ {
+ pMadgeParmTable->ActualValue = *configParam;
+ }
+ }
+ else
+ {
+ //
+ // We didn't read anything, so use the default value.
+ //
+
+ pMadgeParmTable->ActualValue = pMadgeParmTable->DefaultValue;
+ }
+
+ pMadgeParmTable++;
+ }
+
+ //
+ // We have successfully read any optional keywords and none of them is
+ // too small or big. The other thing we need the registry for is the
+ // locally administered address, for which there is a specific NDIS call
+ //
+
+ NdisReadNetworkAddress(
+ &status,
+ &networkAddress,
+ &networkAddressLength,
+ registryConfigHandle
+ );
+
+ if (status == NDIS_STATUS_SUCCESS &&
+ networkAddressLength == TR_LENGTH_OF_ADDRESS)
+ {
+ //
+ // We read a valid length TR address, but if the
+ // top two bits are not "01", it is not legal.
+ //
+
+ if ((((BYTE *) networkAddress)[0] & 0xc0) == 0x40)
+ {
+ ndisAdap->OpeningNodeAddress =
+ *((NODE_ADDRESS *) networkAddress);
+ }
+ }
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeShutdown
+*
+* Parameters - context -> Adapter context.
+*
+* Purpose - Quickly shutdown the adapter.
+*
+* Returns - Nothing.
+*
+****************************************************************************/
+
+VOID
+MadgeShutdown(
+ NDIS_HANDLE context
+ )
+{
+ MADGE_ADAPTER * ndisAdap;
+
+ ndisAdap = PMADGE_ADAPTER_FROM_CONTEXT(context);
+
+ MadgePrint1("MadgeShutdown called\n");
+
+ if (ndisAdap->TimerInitialized)
+ {
+ BOOLEAN timerOutstanding;
+
+ NdisMCancelTimer(&ndisAdap->WakeUpTimer, &timerOutstanding);
+ NdisMCancelTimer(&ndisAdap->CompletionTimer, &timerOutstanding);
+
+ ndisAdap->TimerInitialized = FALSE;
+ }
+
+ //
+ // Just call the FTK to shutdown the adapter.
+ //
+
+ if (ndisAdap->FtkInitialized)
+ {
+ rxtx_await_empty_tx_slots(ndisAdap->FtkAdapterHandle);
+ driver_remove_adapter(ndisAdap->FtkAdapterHandle);
+ ndisAdap->FtkInitialized = FALSE;
+ ndisAdap->AdapterRemoved = TRUE;
+ }
+
+ MadgePrint1("MadgeShutdown ended\n");
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - MadgeRegisterAdapter
+|
+| Parameters - ndisAdap -> Pointer to an NDIS3 level adapter
+| structure.
+| wrapperConfigHandle -> Wrapper context handle.
+|
+| Purpose - Register an adapter instance with the NDIS3 wrapper.
+|
+| Returns - An NDIS3 status code.
+|
+|--------------------------------------------------------------------------*/
+
+STATIC NDIS_STATUS
+MadgeRegisterAdapter(
+ PMADGE_ADAPTER ndisAdap,
+ NDIS_HANDLE wrapperConfigHandle
+ );
+
+#pragma FTK_INIT_FUNCTION(MadgeRegisterAdapter)
+
+STATIC NDIS_STATUS
+MadgeRegisterAdapter(
+ PMADGE_ADAPTER ndisAdap,
+ NDIS_HANDLE wrapperConfigHandle
+ )
+{
+ NDIS_STATUS status;
+ BOOLEAN busMaster;
+
+ MadgePrint1("MadgeRegisterAdapter started\n");
+
+ //
+ // Register a shutdown handler with the wrapper.
+ //
+
+ NdisMRegisterAdapterShutdownHandler(
+ ndisAdap->UsedInISR.MiniportHandle,
+ ndisAdap,
+ MadgeShutdown
+ );
+
+ ndisAdap->ShutdownHandlerRegistered = TRUE;
+
+ //
+ // Register our attributes with the wrapper. These are our adapter
+ // context (i.e. a pointer to our adapter structure), whether we
+ // are a bus master device and our bus type.
+ //
+
+ busMaster = (ndisAdap->TransferMode == DMA_DATA_TRANSFER_MODE);
+
+ MadgePrint1("NdisMSetAttributes called\n");
+ MadgePrint2("busMaster = %d\n", (UINT) busMaster);
+
+ NdisMSetAttributes(
+ ndisAdap->UsedInISR.MiniportHandle,
+ (NDIS_HANDLE) ndisAdap,
+ busMaster,
+ ndisAdap->NTCardBusType
+ );
+
+ MadgePrint1("NdisMSetAttributes returned\n");
+
+ //
+ // Register our IO port usage.
+ //
+
+ MadgePrint1("NdisMRegisterIoPortRange called\n");
+
+ status = NdisMRegisterIoPortRange(
+ &ndisAdap->MappedIOLocation1,
+ ndisAdap->UsedInISR.MiniportHandle,
+ ndisAdap->IoLocation1 + ndisAdap->IoLocationBase,
+ ndisAdap->IORange1
+ );
+
+ MadgePrint1("NdisMRegisterIoPortRange returned\n");
+ MadgePrint2("MappedIORange1 = %x\n", (UINT) ndisAdap->MappedIOLocation1);
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ MadgePrint2("NdisMRegisterIoPortRange failed rc = %x\n", status);
+ return status;
+ }
+
+ ndisAdap->IORange1Initialized = TRUE;
+
+ //
+ // If we are using an EISA card then we have a second range of IO
+ // locations.
+ //
+
+ if (ndisAdap->IORange2 > 0)
+ {
+ MadgePrint1("NdisMRegisterIoPortRange called\n");
+
+ status = NdisMRegisterIoPortRange(
+ &ndisAdap->MappedIOLocation2,
+ ndisAdap->UsedInISR.MiniportHandle,
+ ndisAdap->IoLocation2 + ndisAdap->IoLocationBase,
+ ndisAdap->IORange2
+ );
+
+ MadgePrint1("NdisMRegisterIoPortRange returned\n");
+ MadgePrint2("MappedIORange2 = %x\n", (UINT) ndisAdap->MappedIOLocation2);
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ MadgePrint2("NdisMRegisterIoPortRange failed rc = %x\n", status);
+ return status;
+ }
+
+ ndisAdap->IORange2Initialized = TRUE;
+ }
+
+ MadgePrint1("MadgeRegisterAdapter finished\n");
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - FlagIsTrue
+|
+| Parameters - flag -> Pointer to a flag to find the value of.
+|
+| Purpose - Return the value of a flag. Can be called by a function
+Ý that polls a flag to avoid the compiler optimising out
+Ý the test of the flag.
+|
+| Returns - The value of the flag.
+|
+|--------------------------------------------------------------------------*/
+
+STATIC BOOLEAN
+FlagIsTrue(BOOLEAN * flag);
+
+#pragma FTK_INIT_FUNCTION(FlagIsTrue)
+
+STATIC BOOLEAN
+FlagIsTrue(BOOLEAN * flag)
+{
+ MadgePrint1("FlagIsTrue\n");
+
+ return *flag;
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - MadgeMapMmioMemory
+|
+| Parameters - ndisAdap -> Pointer to an NDIS3 level adapter structure.
+|
+| Purpose - Attempt to map in our MMIO memory.
+|
+| Returns - An NDIS3 status code.
+|
+|--------------------------------------------------------------------------*/
+
+STATIC NDIS_STATUS
+MadgeMapMmioMemory(PMADGE_ADAPTER ndisAdap);
+
+#pragma FTK_INIT_FUNCTION(MadgeMapMmioMemory)
+
+STATIC NDIS_STATUS
+MadgeMapMmioMemory(PMADGE_ADAPTER ndisAdap)
+{
+ NDIS_PHYSICAL_ADDRESS mmioPhysAddr = NDIS_PHYSICAL_ADDRESS_CONST(0, 0);
+ UINT status;
+
+ NdisSetPhysicalAddressLow(
+ mmioPhysAddr,
+ ndisAdap->MmioRawAddress
+ );
+
+ status = NdisMMapIoSpace(
+ &ndisAdap->MmioVirtualAddress,
+ ndisAdap->UsedInISR.MiniportHandle,
+ mmioPhysAddr,
+ PCI_MMIO_SIZE
+ );
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ NdisWriteErrorLogEntry(
+ ndisAdap->UsedInISR.MiniportHandle,
+ NDIS_ERROR_CODE_MEMORY_CONFLICT,
+ 2,
+ initAdapter,
+ MADGE_ERRMSG_MAPPING_PCI_MMIO
+ );
+ }
+ else
+ {
+ ndisAdap->MmioMapped = TRUE;
+ }
+
+ return status;
+}
+
+
+#ifndef LINK_FMPLUS
+
+/*---------------------------------------------------------------------------
+|
+| Function - MadgeReadDownload
+|
+| Parameters - ndisAdap -> Pointer to an NDIS3 level adapter structure.
+Ý downloadFile -> Pointer to as handle for the download file.
+| download -> Pointer to a holder for a pointer to the
+Ý download image read into memory.
+| Purpose - Read the download into memory. If the function returns
+Ý success then must unmap and close *downloadFile.
+|
+| Returns - An NDIS3 status code.
+|
+|--------------------------------------------------------------------------*/
+
+STATIC NDIS_STATUS
+MadgeReadDownload(
+ PMADGE_ADAPTER ndisAdap,
+ NDIS_HANDLE * downloadFile,
+ void * * download
+ );
+
+#pragma FTK_INIT_FUNCTION(MadgeReadDownload)
+
+STATIC NDIS_STATUS
+MadgeReadDownload(
+ PMADGE_ADAPTER ndisAdap,
+ NDIS_HANDLE * downloadFile,
+ void * * download
+ )
+{
+ NDIS_STATUS status;
+ NDIS_HANDLE imageFile;
+ UINT imageLength;
+ PVOID imagePtr;
+ NDIS_PHYSICAL_ADDRESS highestAddress = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
+ DOWNLOAD_FILE_HEADER * downHdrPtr;
+ UCHAR * chkPtr;
+ ULONG chkSum;
+ UINT i;
+
+ //
+ // Open the FastMAC Plus image file.
+ //
+
+ MadgePrint1("NdisOpenFile called\n");
+
+ NdisOpenFile(
+ &status,
+ &imageFile,
+ &imageLength,
+ &FmpImageFileName,
+ highestAddress
+ );
+
+ MadgePrint1("NdisOpenFile returned\n");
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ MadgePrint2("NdisOpenFile failed rc= %x\n", status);
+
+ NdisWriteErrorLogEntry(
+ ndisAdap->UsedInISR.MiniportHandle,
+ NDIS_ERROR_CODE_INVALID_DOWNLOAD_FILE_ERROR,
+ 2,
+ initAdapter,
+ MADGE_ERRMSG_OPEN_IMAGE_FILE
+ );
+
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ //
+ // Map in the FastMAC Plus image file.
+ //
+
+ NdisMapFile(&status, &imagePtr, imageFile);
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ NdisWriteErrorLogEntry(
+ ndisAdap->UsedInISR.MiniportHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ initAdapter,
+ MADGE_ERRMSG_MAP_IMAGE_FILE
+ );
+
+ NdisCloseFile(imageFile);
+
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ //
+ // Make sure that the image file is valid by checking its checksum,
+ // version number and signature.
+ //
+
+ downHdrPtr = (DOWNLOAD_FILE_HEADER *) imagePtr;
+ chkPtr = ((UCHAR *) imagePtr) + DOWNLOAD_CHECKSUM_SKIP;
+ chkSum = 0;
+
+ for (i = DOWNLOAD_CHECKSUM_SKIP; i < imageLength; i++)
+ {
+ DOWNLOAD_CHECKSUM_BYTE(chkSum, *chkPtr);
+ chkPtr++;
+ }
+
+ if (!IS_DOWNLOAD_OK(downHdrPtr, chkSum))
+ {
+ NdisWriteErrorLogEntry(
+ ndisAdap->UsedInISR.MiniportHandle,
+ NDIS_ERROR_CODE_INVALID_DOWNLOAD_FILE_ERROR,
+ 2,
+ initAdapter,
+ MADGE_ERRMSG_BAD_IMAGE_FILE
+ );
+
+ NdisUnmapFile(imageFile);
+ NdisCloseFile(imageFile);
+
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ *downloadFile = imageFile;
+ *download = imagePtr;
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+#else
+
+#include "fmplus.c"
+
+#endif
+
+#ifdef _M_IX86
+
+/*---------------------------------------------------------------------------
+|
+| Function - MadgeArbitrateBufferMemory
+|
+| Parameters - ndisAdap -> Pointer to an NDIS3 level adapter structure.
+|
+| Purpose - Determine if we can allocate all the shared memory
+Ý we need for DMA buffer space and if we can't then
+Ý reduce our requirements until we can or we reach
+Ý our minimum requirements. If the buffer space cannot
+Ý be aribtrated then the requirements are left as is and
+Ý it is assumed that the FTK initialisation will fail
+Ý and generate an out of memory error.
+|
+| Returns - Nothing.
+|
+|--------------------------------------------------------------------------*/
+
+STATIC VOID
+MadgeArbitrateBufferMemory(PMADGE_ADAPTER ndisAdap);
+
+#pragma FTK_INIT_FUNCTION(MadgeArbitrateBufferMemory)
+
+STATIC VOID
+MadgeArbitrateBufferMemory(PMADGE_ADAPTER ndisAdap)
+{
+ VOID * testVirt;
+ VOID * rxVirt;
+ VOID * txVirt;
+ NDIS_PHYSICAL_ADDRESS testPhys;
+ NDIS_PHYSICAL_ADDRESS rxPhys;
+ NDIS_PHYSICAL_ADDRESS txPhys;
+ ULONG rxBufferSize;
+ ULONG txBufferSize;
+ UINT maxFrameSize;
+ UINT rxSlots;
+ UINT txSlots;
+ BOOLEAN succeeded;
+ BOOLEAN failed;
+ BOOLEAN arbitrated;
+
+ //
+ // There doesn't seem to be a problem allocating none
+ // shared memory so if we aren't in DMA mode then
+ // don't do anything.
+ //
+
+ if (ndisAdap->TransferMode != DMA_DATA_TRANSFER_MODE)
+ {
+ return;
+ }
+
+ //
+ // The first bit of shared memory we must have is for the DMA
+ // test buffers.
+ //
+
+ testVirt = NULL;
+
+ NdisMAllocateSharedMemory(
+ ndisAdap->UsedInISR.MiniportHandle,
+ SCB_TEST_PATTERN_LENGTH + SSB_TEST_PATTERN_LENGTH,
+ FALSE,
+ &testVirt,
+ &testPhys
+ );
+
+ //
+ // If we can't allocate the test buffer then just give up.
+ //
+
+ if (testVirt == NULL)
+ {
+ return;
+ }
+
+ //
+ // We've got the test buffer memory so now arbitrate the
+ // RX/TX buffers. Note: the buffer allocation MUST MATCH
+ // THAT IN FTK_USER.C.
+ //
+
+ maxFrameSize = ndisAdap->MaxFrameSize;
+ rxSlots = ndisAdap->FastmacRxSlots;
+ txSlots = ndisAdap->FastmacTxSlots;
+
+ failed = FALSE;
+ succeeded = FALSE;
+ arbitrated = FALSE;
+
+ while (!failed && !succeeded)
+ {
+ rxVirt = NULL;
+ txVirt = NULL;
+
+ //
+ // Try to allocate the receive buffer.
+ //
+
+ rxBufferSize = ((maxFrameSize + 4 + 32 + 3) & ~3) * rxSlots;
+
+ NdisMAllocateSharedMemory(
+ ndisAdap->UsedInISR.MiniportHandle,
+ rxBufferSize,
+ FALSE,
+ &rxVirt,
+ &rxPhys
+ );
+
+ //
+ // If we allocated the RX buffer space then try to allocate
+ // the TX buffer space.
+ //
+
+ if (rxVirt != NULL)
+ {
+ txBufferSize = ((maxFrameSize + 3) & ~3) * txSlots;
+
+ NdisMAllocateSharedMemory(
+ ndisAdap->UsedInISR.MiniportHandle,
+ txBufferSize,
+ FALSE,
+ &txVirt,
+ &txPhys
+ );
+ }
+
+ //
+ // Free any buffers we managed to allocate.
+ //
+
+ if (rxVirt != NULL)
+ {
+ NdisMFreeSharedMemory(
+ ndisAdap->UsedInISR.MiniportHandle,
+ rxBufferSize,
+ FALSE,
+ rxVirt,
+ rxPhys
+ );
+ }
+
+ if (txVirt != NULL)
+ {
+ NdisMFreeSharedMemory(
+ ndisAdap->UsedInISR.MiniportHandle,
+ txBufferSize,
+ FALSE,
+ txVirt,
+ txPhys
+ );
+ }
+
+ //
+ // If we managed to allocate both buffers then we have
+ // succeeded.
+ //
+
+ if (rxVirt != NULL && txVirt != NULL)
+ {
+ succeeded = TRUE;
+ }
+
+ //
+ // Otherwise we must reduce our memory requirements.
+ //
+
+ else
+ {
+ arbitrated = TRUE;
+
+ //
+ // First try reducing the number of transmit slots.
+ //
+
+ if (txSlots > FMPLUS_MIN_TX_SLOTS)
+ {
+ txSlots--;
+ }
+
+ //
+ // Next try reducing the number of receive slots.
+ //
+
+ else if (rxSlots > FMPLUS_MIN_RX_SLOTS)
+ {
+ rxSlots--;
+ }
+
+ //
+ // Finally try reducing the frame size. 1800 bytes has
+ // empirically shown to be the minimum value required
+ // for the DOMAIN server startup to work at NT installation.
+ //
+
+ else if (maxFrameSize > 1800)
+ {
+ maxFrameSize -= 512;
+
+ if (maxFrameSize < 1800)
+ {
+ maxFrameSize = 1800;
+ }
+ }
+
+ //
+ // If we can't reduce our buffer requirements any further
+ // then fail.
+ //
+
+ else
+ {
+ failed = TRUE;
+ }
+ }
+ }
+
+ //
+ // Free the memory for the DMA test buffer.
+ //
+
+ NdisMFreeSharedMemory(
+ ndisAdap->UsedInISR.MiniportHandle,
+ SCB_TEST_PATTERN_LENGTH + SSB_TEST_PATTERN_LENGTH,
+ FALSE,
+ testVirt,
+ testPhys
+ );
+
+ //
+ // If we have succeded then we must update the requirements in
+ // adapter structure and if we have changed any values we must
+ // write a message to the event log.
+ //
+
+ if (succeeded && arbitrated)
+ {
+ ndisAdap->MaxFrameSize = maxFrameSize;
+ ndisAdap->FastmacRxSlots = rxSlots;
+ ndisAdap->FastmacTxSlots = txSlots;
+
+ NdisWriteErrorLogEntry(
+ ndisAdap->UsedInISR.MiniportHandle,
+ NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
+ 1,
+ initAdapter
+ );
+ }
+}
+
+#endif
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - MadgeInitAdapter
+|
+| Parameters - ndisAdap -> Pointer to an NDIS3 level adapter structure.
+|
+| Purpose - Initialise an adapter.
+|
+| Returns - An NDIS3 status code.
+|
+|--------------------------------------------------------------------------*/
+
+STATIC NDIS_STATUS
+MadgeInitAdapter(PMADGE_ADAPTER ndisAdap);
+
+#pragma FTK_INIT_FUNCTION(MadgeInitAdapter)
+
+STATIC NDIS_STATUS
+MadgeInitAdapter(PMADGE_ADAPTER ndisAdap)
+{
+ WORD ftkStatus;
+ NDIS_STATUS status;
+ PREPARE_ARGS prepare;
+ START_ARGS start;
+
+#ifndef LINK_FMPLUS
+
+ NDIS_HANDLE imageFile;
+ PVOID imagePtr;
+
+#endif
+
+ MadgePrint1("MadgeInitAdapter started\n");
+
+ //
+ // If we are doing MMIO then we need to map in the MMIO memory.
+ // If we fail to map in the memory then default ti PIO.
+ //
+
+ if (ndisAdap->TransferMode == MMIO_DATA_TRANSFER_MODE)
+ {
+ if (MadgeMapMmioMemory(ndisAdap) != NDIS_STATUS_SUCCESS)
+ {
+ ndisAdap->TransferMode = PIO_DATA_TRANSFER_MODE;
+ }
+ }
+
+#ifdef _M_IX86
+
+ //
+ // Arbitrate "DMA" buffer memory.
+ //
+
+ MadgeArbitrateBufferMemory(ndisAdap);
+
+#endif
+
+ //
+ // Set up the arguments to pass to driver_prepare_adapter.
+ //
+
+ MADGE_ZERO_MEMORY(&prepare, sizeof(PREPARE_ARGS));
+
+ prepare.user_information = (void *) ndisAdap;
+ prepare.number_of_rx_slots = (WORD) ndisAdap->FastmacRxSlots;
+ prepare.number_of_tx_slots = (WORD) ndisAdap->FastmacTxSlots;
+ prepare.max_frame_size = (WORD) ndisAdap->MaxFrameSize;
+
+ //
+ // Try to prepare the adapter for use.
+ //
+
+ //
+ // Mark the fact that the FTK has been called, so that we know if we
+ // have to call driver_remove_adapter() when doing clean up.
+ //
+
+ ndisAdap->FtkInitialized = TRUE;
+
+ MadgePrint1("driver_prepare_adapter called\n");
+
+ if (!driver_prepare_adapter(&prepare, &(ndisAdap->FtkAdapterHandle)))
+ {
+ return NDIS_STATUS_FAILURE;
+ }
+
+ MadgePrint1("driver_prepare_adapter returned\n");
+ MadgePrint2("adapter_handle = %d\n", ndisAdap->FtkAdapterHandle);
+
+#ifndef LINK_FMPLUS
+
+ //
+ // Read in the download file.
+ //
+
+ status = MadgeReadDownload(ndisAdap, &imageFile, &imagePtr);
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ return status;
+ }
+
+#endif
+
+ //
+ // Set up the arguments to driver_start_adapter.
+ //
+
+ MADGE_ZERO_MEMORY(&start, sizeof(START_ARGS));
+
+ start.adapter_card_bus_type = (UINT) ndisAdap->FTKCardBusType;
+
+ start.io_location = (WORD) ndisAdap->IoLocation1;
+ start.transfer_mode = (UINT) ndisAdap->TransferMode;
+ start.dma_channel = (WORD) ndisAdap->DmaChannel;
+ start.interrupt_number = (WORD) ndisAdap->UsedInISR.InterruptNumber;
+ start.set_dma_channel = TRUE;
+ start.set_interrupt_number = TRUE;
+ start.mmio_base_address = (DWORD) ndisAdap->MmioVirtualAddress;
+ start.pci_handle = (DWORD) ndisAdap->SlotNumber;
+
+ if (ndisAdap->Force16)
+ {
+ start.set_ring_speed = 16;
+ }
+ else if (ndisAdap->Force4)
+ {
+ start.set_ring_speed = 4;
+ }
+
+ start.opening_node_address = ndisAdap->OpeningNodeAddress;
+ start.auto_open_option = TRUE;
+
+ if (ndisAdap->ForceOpen)
+ {
+ ndisAdap->OpenOptions |= OPEN_OPT_FORCE_OPEN;
+ }
+
+ start.open_options = (WORD) ndisAdap->OpenOptions;
+
+ start.rx_tx_buffer_size = (WORD) ndisAdap->CardBufferSize;
+
+#ifndef LINK_FMPLUS
+
+ start.code = (DOWNLOAD_IMAGE *)
+ (((UCHAR *) imagePtr) + sizeof(DOWNLOAD_FILE_HEADER));
+
+#else
+
+ start.code = (DOWNLOAD_IMAGE *) fmplus_image;
+
+#endif
+
+ MadgePrint1("driver_start_adapter called\n");
+
+ ftkStatus = driver_start_adapter(
+ ndisAdap->FtkAdapterHandle,
+ &start,
+ &ndisAdap->PermanentNodeAddress
+ );
+
+ MadgePrint1("driver_start_adapter returned\n");
+ MadgePrint2("MAC buffer size = %d\n",
+ adapter_record[ndisAdap->FtkAdapterHandle
+ ]->init_block->smart_parms.rx_tx_buffer_size
+ );
+
+#ifndef LINK_FMPLUS
+
+ //
+ // No matter what we have finished with the FastMAC Plus image file.
+ //
+
+ NdisUnmapFile(imageFile);
+ NdisCloseFile(imageFile);
+
+#endif
+
+ if (!ftkStatus)
+ {
+ MadgePrint1("driver_start_adapter failed\n");
+
+ //
+ // Were it not for the fact that we are going to clean up and fail
+ // as soon as we return, we ought to set the CurrentRingState to
+ // NdisRingStateOpenFailure here if AutoOpen was selected.
+ //
+
+ return NDIS_STATUS_FAILURE;
+ }
+
+ //
+ // Warn the user if FastMAC Plus had to reduce the frame size.
+ //
+
+ if (ndisAdap->MaxFrameSize > start.max_frame_size)
+ {
+ NdisWriteErrorLogEntry(
+ ndisAdap->UsedInISR.MiniportHandle,
+ NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
+ 3,
+ initAdapter,
+ MADGE_ERRMSG_REDUCE_MAX_FSIZE,
+ ndisAdap->MaxFrameSize
+ );
+ }
+
+ ndisAdap->MaxFrameSize = start.max_frame_size;
+
+ //
+ // If we did not specify a locally administered address then copy the
+ // permanent one across to the local one.
+ //
+
+ if (ndisAdap->OpeningNodeAddress.byte[0] == 0)
+ {
+ MADGE_MOVE_MEMORY(
+ &ndisAdap->OpeningNodeAddress,
+ &ndisAdap->PermanentNodeAddress,
+ sizeof(ndisAdap->PermanentNodeAddress)
+ );
+ }
+
+ //
+ // Note that the adapter is open.
+ //
+
+ ndisAdap->CurrentRingState = NdisRingStateOpened;
+ ndisAdap->LastOpenStatus = start.open_status;
+
+ //
+ // Nasty hack. If we have a PciT atapter with broken dma and we are
+ // running on a multiprocessor we need set the multiprocessor safe
+ // PIO flag to make sure that we don't do DIO whilst our interrupt
+ // hander is running. Unfortunately we don't know if we have
+ // broken DMA until after we've started the adapter.
+ //
+
+ if (ndisAdap->Multiprocessor &&
+ adapter_record[ndisAdap->FtkAdapterHandle]->mc32_config ==
+ TRN_PCIT_BROKEN_DMA)
+ {
+ MadgePrint1("Using MP sfae PIO because of PCIT DMA.\n");
+ ndisAdap->UseMPSafePIO = TRUE;
+ }
+
+ //
+ // Note that we MUST start the receive process, even if we are NOT using
+ // auto-open, because FastmacPlus ignores SRBs (including OPEN SRBs) if
+ // this has not been done.
+ //
+
+ driver_start_receive_process(ndisAdap->FtkAdapterHandle);
+
+ //
+ // We now need to set the product instance ID. The product instance
+ // ID will be set to the contents of ftk_product_inst_id[] if we
+ // issue an open SRB, but since Miniports always auto-open we
+ // need to generate a set product instance SRB to set it.
+ //
+
+ //
+ // Note that we are generating a private SRB (not to be treated
+ // as a normal NDIS request), generate the SRB and then wait
+ // for it to finish.
+ //
+
+ ndisAdap->PrivateSrbInProgress = TRUE;
+
+ MadgePrint1("Calling driver_set_product_instance_id\n");
+
+ driver_set_product_instance_id(
+ ndisAdap->FtkAdapterHandle,
+ NT_PRODUCT_INSTANCE_ID
+ );
+
+ MadgePrint1("Waiting for SRB to complete\n");
+
+ while (FlagIsTrue(&ndisAdap->PrivateSrbInProgress))
+ NdisMSleep(100);
+
+ MadgePrint1("MadgeInitAdapter finished\n");
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - MadgeCleanupAdapter
+|
+| Parameters - ndisAdap -> Pointer to an NDIS3 level adapter structure.
+|
+| Purpose - Deallocate the resources associated with an adapter.
+|
+| Returns - Nothing.
+|
+|--------------------------------------------------------------------------*/
+
+STATIC VOID
+MadgeCleanupAdapter(PMADGE_ADAPTER ndisAdap)
+{
+ BOOLEAN timerOutstanding;
+
+ MadgePrint1("MadgeCleanupAdapter 1\n");
+
+ if (ndisAdap->TimerInitialized)
+ {
+ NdisMCancelTimer(&ndisAdap->WakeUpTimer, &timerOutstanding);
+ NdisMCancelTimer(&ndisAdap->CompletionTimer, &timerOutstanding);
+ ndisAdap->TimerInitialized = FALSE;
+ }
+
+ MadgePrint1("MadgeCleanupAdapter 2\n");
+
+ if (ndisAdap->FtkInitialized)
+ {
+ rxtx_await_empty_tx_slots(ndisAdap->FtkAdapterHandle);
+ driver_remove_adapter(ndisAdap->FtkAdapterHandle);
+ ndisAdap->FtkInitialized = FALSE;
+ }
+
+ if (ndisAdap->MapRegistersAllocated > 0)
+ {
+ NdisMFreeMapRegisters(ndisAdap->UsedInISR.MiniportHandle);
+ ndisAdap->MapRegistersAllocated = 0;
+ }
+
+ MadgePrint1("MadgeCleanupAdapter 3\n");
+
+ if (ndisAdap->MmioMapped)
+ {
+ NdisMUnmapIoSpace(
+ ndisAdap->UsedInISR.MiniportHandle,
+ ndisAdap->MmioVirtualAddress,
+ PCI_MMIO_SIZE
+ );
+ ndisAdap->MmioMapped = FALSE;
+ }
+
+ MadgePrint1("MadgeCleanupAdapter 4\n");
+
+ if (ndisAdap->IORange1Initialized)
+ {
+ NdisMDeregisterIoPortRange(
+ ndisAdap->UsedInISR.MiniportHandle,
+ ndisAdap->IoLocation1 + ndisAdap->IoLocationBase,
+ ndisAdap->IORange1,
+ ndisAdap->MappedIOLocation1
+ );
+ ndisAdap->IORange1Initialized = FALSE;
+ }
+
+ MadgePrint1("MadgeCleanupAdapter 5\n");
+
+ if (ndisAdap->IORange2Initialized)
+ {
+ NdisMDeregisterIoPortRange(
+ ndisAdap->UsedInISR.MiniportHandle,
+ ndisAdap->IoLocation2 + ndisAdap->IoLocationBase,
+ ndisAdap->IORange2,
+ ndisAdap->MappedIOLocation2
+ );
+ ndisAdap->IORange2Initialized = FALSE;
+ }
+
+ MadgePrint1("MadgeCleanupAdapter 6\n");
+
+ if (ndisAdap->ShutdownHandlerRegistered)
+ {
+ NdisMDeregisterAdapterShutdownHandler(
+ ndisAdap->UsedInISR.MiniportHandle
+ );
+ ndisAdap->ShutdownHandlerRegistered = FALSE;
+
+ MadgePrint1("De-registered shutdown handler\n");
+ }
+
+ MADGE_FREE_MEMORY(ndisAdap, sizeof(MADGE_ADAPTER));
+}
+
+
+/***************************************************************************
+*
+* Function - MadgeHalt
+*
+* Parameters - adapterContext -> Pointer to our NDIS level adapter
+* structure.
+*
+* Purpose - Process a call from the NDIS3 wrapper to remove an
+* adapter instance.
+*
+* Returns - Nothing.
+*
+****************************************************************************/
+
+VOID
+MadgeHalt(NDIS_HANDLE adapterContext)
+{
+ PMADGE_ADAPTER ndisAdap;
+
+ MadgePrint1("MadgeHalt started\n");
+
+ ndisAdap = PMADGE_ADAPTER_FROM_CONTEXT(adapterContext);
+
+ //
+ // The NDIS interface guarantees that all bindings are closed, i.e. all
+ // MadgeCloseAdapter calls have completed successfully.
+ //
+
+ ndisAdap->HardwareStatus = NdisHardwareStatusClosing;
+
+ MadgeCleanupAdapter(ndisAdap);
+
+ MadgePrint1("MadgeHalt finished\n");
+}
+
+
+/****************************************************************************
+*
+* Function - MadgeTxCompletion
+*
+* Parameters - systemSpecific1 -> Unused.
+* context -> Actually a pointer to our NDIS3 level
+* adapter structure.
+* systemSpecific2 -> Unused.
+* systemSpecific3 -> Unused.
+*
+* Purpose - Call our TX competion routine as a result of a timer.
+*
+* Returns - Nothing.
+*
+****************************************************************************/
+
+VOID
+MadgeTxCompletion(
+ PVOID systemSpecific1,
+ PVOID context,
+ PVOID systemSpecific2,
+ PVOID systemSpecific3
+ )
+{
+ PMADGE_ADAPTER ndisAdap = (PMADGE_ADAPTER) context;
+
+ //
+ // Call the TX completion function.
+ //
+
+ rxtx_irq_tx_completion_check(
+ ndisAdap->FtkAdapterHandle,
+ adapter_record[ndisAdap->FtkAdapterHandle]
+ );
+}
+
+
+/***************************************************************************
+*
+* Function - MadgeInitialise
+*
+* Parameters - openErrorStatus -> Pointer to a holder for an open
+* error status.
+* selectedMediumIndex -> Pointer to a holder for the index
+* of the medium selected.
+* mediumArray -> Array of media types.
+* mediumArraySize -> Size of the media array.
+* miniportHandle -> Miniport adapter handle.
+* wrapperConfigContext -> Handle used when querying the
+* registry.
+*
+* Purpose - Carry out adapter instance initialisation.
+*
+* Returns - An NDIS3 status code.
+*
+***************************************************************************/
+
+NDIS_STATUS
+MadgeInitialize(
+ PNDIS_STATUS openErrorStatus,
+ PUINT selectedMediumIndex,
+ PNDIS_MEDIUM mediumArray,
+ UINT mediumArraySize,
+ NDIS_HANDLE miniportHandle,
+ NDIS_HANDLE wrapperConfigContext
+ );
+
+#pragma FTK_INIT_FUNCTION(MadgeInitialize)
+
+NDIS_STATUS
+MadgeInitialize(
+ PNDIS_STATUS openErrorStatus,
+ PUINT selectedMediumIndex,
+ PNDIS_MEDIUM mediumArray,
+ UINT mediumArraySize,
+ NDIS_HANDLE miniportHandle,
+ NDIS_HANDLE wrapperConfigContext
+ )
+{
+ NDIS_STATUS status;
+ PMADGE_ADAPTER ndisAdap;
+ NDIS_HANDLE configHandle;
+ UINT i;
+
+ MadgePrint1("MadgeInitialize started\n");
+
+ //
+ // ---------------------------------------------------------------------
+ // Check that the upper protocol knows about token ring and if
+ // it does set the index.
+ //
+
+ for (i = 0; i < mediumArraySize; i++)
+ {
+ if (mediumArray[i] == NdisMedium802_5)
+ {
+ break;
+ }
+ }
+
+ if (i == mediumArraySize)
+ {
+ return NDIS_STATUS_UNSUPPORTED_MEDIA;
+ }
+
+ *selectedMediumIndex = i;
+
+ //
+ // ---------------------------------------------------------------------
+ // Doing basic sanity checks and allocating some memory for our
+ // per-adapter structure.
+ //
+
+ if (wrapperConfigContext == NULL)
+ {
+ //
+ // No registry config. information found by NDIS library for us.
+ // We cannot proceed without it.
+ //
+
+ return NDIS_STATUS_FAILURE;
+ }
+
+ //
+ // Allocate memory for the adapter structure.
+ //
+
+ MADGE_ALLOC_MEMORY(&status, &ndisAdap, sizeof(MADGE_ADAPTER));
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Failed to allocate adapter structure. Can't go on without it.
+ //
+
+ return status;
+ }
+
+ MADGE_ZERO_MEMORY(ndisAdap, sizeof(MADGE_ADAPTER));
+
+ MadgePrint2("ndisAdap = %x\n", ndisAdap);
+
+ //
+ // We need the mini port handle early on.
+ //
+
+ ndisAdap->UsedInISR.MiniportHandle = miniportHandle;
+
+ //
+ // ---------------------------------------------------------------------
+ // Read the registry: open the registry, read the contents, and close it
+ // again. This will handle adapter parameters and LAAs, and also working
+ // out various values to do with interrupt modes.
+ //
+
+ MadgePrint1("NdisOpenConfiguration called\n");
+
+ NdisOpenConfiguration(
+ &status,
+ &configHandle,
+ wrapperConfigContext
+ );
+
+ MadgePrint1("NdisOpenConfiguration returned\n");
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ MadgePrint2("NdisOpenConfiguration failed rc=%x\n", status);
+ MADGE_FREE_MEMORY(ndisAdap, sizeof(MADGE_ADAPTER));
+ return status;
+ }
+
+ status = MadgeReadRegistry(
+ wrapperConfigContext,
+ configHandle,
+ ndisAdap
+ );
+
+ NdisCloseConfiguration(configHandle);
+
+ //
+ // We have gleaned all we can from the registry - was it all OK?
+ //
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // If Status is not success, it will be either NDIS_STATUS_FAILURE
+ // if a parameter was out of range, or it will be the error code
+ // returned by NdisReadConfiguration().
+ //
+
+ MadgePrint2("MadgeReadRegistry failed rc = %x\n", status);
+ MADGE_FREE_MEMORY(ndisAdap, sizeof(MADGE_ADAPTER));
+ return status;
+ }
+
+ //
+ // ---------------------------------------------------------------------
+ // Having read the registry, we can initialize the rest of the fields in
+ // the adapter structure.
+ //
+
+ #define I_DATA ActualValue.ParameterData.IntegerData
+
+ //
+ // Copy the values from the Parameter table into the per-adapter struct.
+ // This is necessary because the Parameter table will be used again for
+ // the next card that is added.
+ //
+ // Note that we handle the rx/tx slots configuration in a special way.
+ // The value of rx/tx slots is set by indexing into a table with the
+ // single paramter RxTxSlots, unless RxSlots or TxSlots have been set in
+ // which case these values override the values derived from RxTxSlots.
+ //
+
+ switch (MadgeParmTable.RxTxSlots.I_DATA)
+ {
+ case 0:
+ ndisAdap->FastmacTxSlots = 2;
+ ndisAdap->FastmacRxSlots = 2;
+ break;
+ case 1:
+ ndisAdap->FastmacTxSlots = 3;
+ ndisAdap->FastmacRxSlots = 3;
+ break;
+ case 2:
+ ndisAdap->FastmacTxSlots = 4;
+ ndisAdap->FastmacRxSlots = 4;
+ break;
+ case 3:
+ ndisAdap->FastmacTxSlots = 6;
+ ndisAdap->FastmacRxSlots = 6;
+ break;
+ case 4:
+ ndisAdap->FastmacTxSlots = 8;
+ ndisAdap->FastmacRxSlots = 8;
+ break;
+ case 5:
+ ndisAdap->FastmacTxSlots = 10;
+ ndisAdap->FastmacRxSlots = 10;
+ break;
+ default:
+ ndisAdap->FastmacTxSlots = 4;
+ ndisAdap->FastmacRxSlots = 4;
+ break;
+ }
+
+ if (MadgeParmTable.TxSlots.I_DATA != 0)
+ {
+ ndisAdap->FastmacTxSlots = MadgeParmTable.TxSlots.I_DATA;
+ }
+
+ if (MadgeParmTable.RxSlots.I_DATA != 0)
+ {
+ ndisAdap->FastmacRxSlots = MadgeParmTable.RxSlots.I_DATA;
+ }
+
+ MadgePrint3("TX slots = %d RX slots = %d\n",
+ ndisAdap->FastmacTxSlots,
+ ndisAdap->FastmacRxSlots
+ );
+
+ ndisAdap->MaxFrameSize = MadgeParmTable.MaxFrameSize.I_DATA;
+ ndisAdap->CardBufferSize = MadgeParmTable.CardBufferSize.I_DATA;
+ ndisAdap->PromiscuousMode = (MadgeParmTable.PromiscuousMode.I_DATA == 1);
+ ndisAdap->AlternateIo = (MadgeParmTable.AlternateIo.I_DATA == 1);
+ ndisAdap->TestAndXIDEnabled = (MadgeParmTable.TestAndXIDEnabled.I_DATA == 1);
+ ndisAdap->ForceOpen = (MadgeParmTable.ForceOpen.I_DATA == 1);
+ ndisAdap->Force4 = (MadgeParmTable.Force4.I_DATA == 1);
+ ndisAdap->Force16 = (MadgeParmTable.Force16.I_DATA == 1);
+ ndisAdap->Multiprocessor = (NdisSystemProcessorCount() > 1);
+
+ if (ndisAdap->TransferMode != DMA_DATA_TRANSFER_MODE &&
+ ndisAdap->Multiprocessor)
+ {
+ ndisAdap->UseMPSafePIO = TRUE;
+ }
+
+ //
+ // If the RingSpeed parameter is present then this overrides the
+ // Force4 and Force16 parameters. RingSpeed == 0 means either not
+ // present or don't care. RingSpeed == 1 means 4MBits. RingSpeed == 2
+ // means 16MBits.
+ //
+
+ switch (MadgeParmTable.RingSpeed.I_DATA)
+ {
+ case 1:
+ ndisAdap->Force4 = TRUE;
+ ndisAdap->Force16 = FALSE;
+ break;
+
+ case 2:
+ ndisAdap->Force4 = FALSE;
+ ndisAdap->Force16 = TRUE;
+
+ default:
+ break;
+ }
+
+ //
+ // Initialize the rest of the Adapter structure.
+ //
+
+ ndisAdap->UsedInISR.MiniportHandle = miniportHandle;
+ ndisAdap->CurrentLookahead = ndisAdap->MaxFrameSize - FRAME_HEADER_SIZE;
+ ndisAdap->CurrentRingState = NdisRingStateClosed;
+ ndisAdap->HardwareStatus = NdisHardwareStatusNotReady;
+
+ //
+ // These next few lines are strictly unnecessary because their fields in
+ // the structure are already zero from our earlier ZERO_MEMORY() call.
+ //
+
+ ndisAdap->UsedInISR.SrbRequestCompleted = FALSE;
+ ndisAdap->UsedInISR.SrbRequestStatus = FALSE;
+ ndisAdap->DprInProgress = FALSE;
+
+ //
+ // One nasty piece of hackery for Smart16 cards, whereby we must add to
+ // the IoLocation 0x1000 if the Alternate switch is true.
+ //
+
+ if (ndisAdap->NTCardBusType == NdisInterfaceIsa &&
+ ndisAdap->IoLocation1 > 0x3a20 &&
+ ndisAdap->AlternateIo)
+ {
+ ndisAdap->IoLocation1 += 0x1000;
+ }
+
+ //
+ // We need to know where the end of the first range of IO locations
+ // we use is.
+ //
+
+ ndisAdap->IORange1End = ndisAdap->IoLocation1 + ndisAdap->IORange1 - 1;
+
+ //
+ // ---------------------------------------------------------------------
+ // We can now try to register the adapter. This involves filling in the
+ // AdapterInformation structure and calling NdisRegisterAdapter(). See
+ // the function MadgeRegisterAdapter for details.
+ //
+
+ if ((status = MadgeRegisterAdapter(
+ ndisAdap,
+ wrapperConfigContext
+ )) != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Either we failed to allocate memory for the adapter information
+ // structure, or the NdisRegisterAdapter() call failed.
+ //
+
+ MadgePrint2("MadgeRegisterAdapter failed rc = %x\n", status);
+ MADGE_FREE_MEMORY(ndisAdap, sizeof(MADGE_ADAPTER));
+ return status;
+ }
+
+ //
+ // ---------------------------------------------------------------------
+ // We are now into the last stages of initialization. This is going to
+ // cause to be allocated several more resources (in the form of kernel
+ // objects, filter databases, FTK structures, interrupt channels, ...)
+ // so from here on we have to be a lot more careful about cleaning up.
+ //
+
+ ndisAdap->HardwareStatus = NdisHardwareStatusInitializing;
+
+ //
+ // Call the FTK to download the MAC code to the card and initialize it.
+ //
+
+ status = MadgeInitAdapter(ndisAdap);
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // If it was an FTK generated error then log an appropriate event.
+ //
+
+ if (status == NDIS_STATUS_FAILURE)
+ {
+ BYTE error_type;
+ BYTE error_value;
+ char * error_message;
+
+ driver_explain_error(
+ ndisAdap->FtkAdapterHandle,
+ &error_type,
+ &error_value,
+ &error_message
+ );
+
+ MadgePrint3("FTK error %02x, %02x\n", error_type, error_value);
+
+ //
+ // To keep Microsoft happy we will generate special error
+ // messages for some of the more common error conditions.
+ //
+
+ //
+ // An open error is probably because the cable isn't plugged in.
+ //
+
+ if (error_type == ERROR_TYPE_OPEN ||
+ error_type == ERROR_TYPE_AUTO_OPEN)
+ {
+ NdisWriteErrorLogEntry(
+ ndisAdap->UsedInISR.MiniportHandle,
+ NDIS_ERROR_CODE_INVALID_VALUE_FROM_ADAPTER,
+ 4,
+ madgeInitialize,
+ MADGE_ERRMSG_INITIAL_INIT,
+ (ULONG) error_type,
+ (ULONG) error_value
+ );
+ }
+ else
+ {
+ NdisWriteErrorLogEntry(
+ ndisAdap->UsedInISR.MiniportHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 4,
+ madgeInitialize,
+ MADGE_ERRMSG_INITIAL_INIT,
+ (ULONG) error_type,
+ (ULONG) error_value
+ );
+ }
+ }
+
+ //
+ // In any case, tidy up the adapter and abort.
+ //
+
+ MadgeCleanupAdapter(ndisAdap);
+ return status;
+ }
+
+ ndisAdap->HardwareStatus = NdisHardwareStatusReady;
+
+ //
+ // Set up the ring status monitor function.
+ //
+
+ NdisMInitializeTimer(
+ &ndisAdap->WakeUpTimer,
+ ndisAdap->UsedInISR.MiniportHandle,
+ (PVOID) MadgeGetAdapterStatus,
+ ndisAdap
+ );
+
+ NdisMSetTimer(&ndisAdap->WakeUpTimer, EVERY_2_SECONDS);
+
+ NdisMInitializeTimer(
+ &ndisAdap->CompletionTimer,
+ ndisAdap->UsedInISR.MiniportHandle,
+ (PVOID) MadgeTxCompletion,
+ ndisAdap
+ );
+
+ ndisAdap->TimerInitialized = TRUE;
+
+ MadgePrint1("MadgeInitialize finished\n");
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+/***************************************************************************
+*
+* Function - DriverEntry
+*
+* Parameters - driverObject -> Pointer to a driver object.
+* registryPath -> Path to our configuration information in
+* the registry.
+*
+* Purpose - Carry out the driver (as opposed to adapter instance)
+* initialisation. This is the main entry point.
+*
+* Returns - An NDIS3 status code.
+*
+***************************************************************************/
+
+NDIS_STATUS
+DriverEntry(PDRIVER_OBJECT driverObject, PUNICODE_STRING registryPath);
+
+#pragma FTK_INIT_FUNCTION(DriverEntry)
+
+NDIS_STATUS
+DriverEntry(PDRIVER_OBJECT driverObject, PUNICODE_STRING registryPath)
+{
+ NDIS_HANDLE ndisWrapperHandle;
+ NDIS_STATUS status;
+ NDIS_MINIPORT_CHARACTERISTICS madgeChar;
+ UINT i;
+
+ MadgePrint1("DriverEntry starting\n");
+
+ //
+ // We are obliged first of all to initialize the NDIS wrapper.
+ //
+
+ MadgePrint1("NdisMInitializeWrapper called\n");
+
+ NdisMInitializeWrapper(
+ &ndisWrapperHandle,
+ driverObject,
+ registryPath,
+ NULL
+ );
+
+ MadgePrint1("NdisMInitializeWrapper returned\n");
+
+ //
+ // Decode any hidden strings here, for use later in MacAddAdapter. This
+ // only applies to PromiscuousMode support at the moment.
+ //
+
+ for (i = 0;
+ i < MadgeParmTable.PromiscuousMode.Keyword.Length /
+ sizeof(*(MadgeParmTable.PromiscuousMode.Keyword.Buffer));
+ i++)
+ {
+ MadgeParmTable.PromiscuousMode.Keyword.Buffer[i] -= HIDDEN_OFFS;
+ }
+
+ //
+ // Fill in the characteristics table - this lists all the driver entry
+ // points that may be called by the NDIS wrapper.
+ //
+
+ madgeChar.MajorNdisVersion = MADGE_NDIS_MAJOR_VERSION;
+ madgeChar.MinorNdisVersion = MADGE_NDIS_MINOR_VERSION;
+ madgeChar.CheckForHangHandler = MadgeCheckForHang;
+ madgeChar.DisableInterruptHandler = MadgeDisableInterrupts;
+ madgeChar.EnableInterruptHandler = MadgeEnableInterrupts;
+ madgeChar.HaltHandler = MadgeHalt;
+ madgeChar.HandleInterruptHandler = MadgeHandleInterrupt;
+ madgeChar.InitializeHandler = MadgeInitialize;
+ madgeChar.ISRHandler = MadgeISR;
+ madgeChar.QueryInformationHandler = MadgeQueryInformation;
+ madgeChar.ReconfigureHandler = NULL;
+ madgeChar.ResetHandler = MadgeReset;
+ madgeChar.SendHandler = MadgeSend;
+ madgeChar.SetInformationHandler = MadgeSetInformation;
+ madgeChar.TransferDataHandler = MadgeTransferData;
+
+ //
+ // Register the miniport driver with NDIS library.
+ //
+
+ MadgePrint1("NdisMRegisterMiniport called\n");
+
+ status = NdisMRegisterMiniport(
+ ndisWrapperHandle,
+ &madgeChar,
+ sizeof(madgeChar)
+ );
+
+ MadgePrint1("NdisMRegisterMiniport returned\n");
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ MadgePrint2("NdisMRegisterMiniport failed rc=%x\n", status);
+ NdisTerminateWrapper(ndisWrapperHandle, NULL);
+ return NDIS_STATUS_FAILURE;
+ }
+
+ MadgePrint1("DriverEntry finished\n");
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+/******** End of MADGE.C ***************************************************/
+
diff --git a/private/ntos/ndis/madge/driver/makefile b/private/ntos/ndis/madge/driver/makefile
new file mode 100644
index 000000000..9481f22cd
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/makefile
@@ -0,0 +1,7 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT
+#
+
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/madge/driver/makefile.inc b/private/ntos/ndis/madge/driver/makefile.inc
new file mode 100644
index 000000000..6eba30160
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/makefile.inc
@@ -0,0 +1,5 @@
+mdgmport.bin: $(TARGETEXEFILES)
+ chmode -r mdgmport.bin
+ binplace mdgmport.bin
+ touch mdgmport.bin
+ chmode +r mdgmport.bin
diff --git a/private/ntos/ndis/madge/driver/mdgerrs.h b/private/ntos/ndis/madge/driver/mdgerrs.h
new file mode 100644
index 000000000..af2e4b3d3
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/mdgerrs.h
@@ -0,0 +1,154 @@
+//
+// Values are 32 bit values layed out as follows:
+//
+// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+// +---+-+-+-----------------------+-------------------------------+
+// |Sev|C|R| Facility | Code |
+// +---+-+-+-----------------------+-------------------------------+
+//
+// where
+//
+// Sev - is the severity code
+//
+// 00 - Success
+// 01 - Informational
+// 10 - Warning
+// 11 - Error
+//
+// C - is the Customer code flag
+//
+// R - is a reserved bit
+//
+// Facility - is the facility code
+//
+// Code - is the facility's status code
+//
+//
+// Define the facility codes
+//
+
+
+//
+// Define the severity codes
+//
+
+
+//
+// MessageId: NDIS_ERROR_CODE_OUT_OF_RESOURCE
+//
+// MessageText:
+//
+// Adapter %2 : Insufficient memory or system resources was available
+// for the netcard driver to initialize. (The last DWORD of the data section
+// below contains a detailed error code.)
+//
+#define NDIS_ERROR_CODE_OUT_OF_RESOURCE ((NDIS_ERROR_CODE)0xC0001389L)
+
+//
+// MessageId: NDIS_ERROR_CODE_HARDWARE_FAILURE
+//
+// MessageText:
+//
+// Adapter %2 : The adapter hardware failed to initialize. Please
+// check that the adapter card is properly inserted into its slot and that the
+// network cable is connected. If its is an ISA adapter check that the interrupt
+// number, DMA channel and IO location in the adapter configuration match the
+// settings on the adapter card. (The data section below includes a driver
+// specific error code of 0x07 and the last two DWORDS give a detailed error
+// code.)
+//
+#define NDIS_ERROR_CODE_HARDWARE_FAILURE ((NDIS_ERROR_CODE)0xC000138AL)
+
+//
+// MessageId: NDIS_ERROR_CODE_ADAPTER_NOT_FOUND
+//
+// MessageText:
+//
+// Adapter %2 : The netcard driver could not allocate sufficient memory
+// for transmit and recive buffers. The number of RX and TX slots and
+// the maximum frame size may have been reduced to reduce the amount
+// of memory required.
+//
+#define NDIS_ERROR_CODE_ADAPTER_NOT_FOUND ((NDIS_ERROR_CODE)0xC000138BL)
+
+//
+// MessageId: NDIS_ERROR_CODE_INTERRUPT_CONNECT
+//
+// MessageText:
+//
+// Adapter %2 : The netcard driver was not able to connect the
+// adapter card's interrupt. Please ensure that the adapter card is properly
+// inserted into its slot. If it is an ISA adapter then check that the
+// interrupt number specified in the adapter configuration matches that
+// set on the adapter card.
+//
+#define NDIS_ERROR_CODE_INTERRUPT_CONNECT ((NDIS_ERROR_CODE)0xC000138CL)
+
+//
+// MessageId: NDIS_ERROR_CODE_DRIVER_FAILURE
+//
+// MessageText:
+//
+// Adapter %2 : One of the paramters in the registry entry for this adapter
+// is invalid. If possible a default value will have been used.
+//
+#define NDIS_ERROR_CODE_DRIVER_FAILURE ((NDIS_ERROR_CODE)0xC000138DL)
+
+//
+// MessageId: NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION
+//
+// MessageText:
+//
+// Adapter %2 : The maximum frame size setting in the registry is too
+// large. The driver has trimmed it down to the maximum allowable setting. (The
+// data section below includes a driver specific error code of 0xC, followed by
+// the actual maximum frame size used in the last DWORD. Replace the value in the
+// registry with this).
+//
+#define NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION ((NDIS_ERROR_CODE)0xC0001391L)
+
+//
+// MessageId: NDIS_ERROR_CODE_INAVLID_VALUE_FROM_ADAPTER
+//
+// MessageText:
+//
+// Adapter %2 : The adapter could not be opened onto the ring. Please ensure
+// that the network cable is connected to the adapter and that the token
+// ring is fully connected. Also ensure that all the nodes on your ring
+// are set to the same speed and that all nodes have different addresses.
+//
+#define NDIS_ERROR_CODE_INAVLID_VALUE_FROM_ADAPTER ((NDIS_ERROR_CODE)0xC0001392L)
+
+//
+// MessageId: NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER
+//
+// MessageText:
+//
+// Adapter %2 : An essential registry parameter is missing for this adapter.
+// For MCA and EISA adapters the registry must contain BusType and SlotNumber
+// parameters. For ISA adapters the registry must contain IoLocation,
+// InterruptNumber and DmaChannel parameters.
+//
+#define NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER ((NDIS_ERROR_CODE)0xC0001393L)
+
+//
+// MessageId: NDIS_ERROR_CODE_INVALID_DOWNLOAD_FILE_ERROR
+//
+// MessageText:
+//
+// Adapter %2 : Either the file MDGMPORT.BIN is not present in the device drivers
+// directory, the file is of the wrong version or the file is corrupt.
+//
+#define NDIS_ERROR_CODE_INVALID_DOWNLOAD_FILE_ERROR ((NDIS_ERROR_CODE)0xC000139CL)
+
+//
+// MessageId: NDIS_ERROR_CODE_MEMORY_CONFLICT
+//
+// MessageText:
+//
+// Adapter %2 : Either MMIO memory was not assigned or could not be mapped into
+// virtual memory. PIO transfer method is being used instead of MMIO.
+//
+#define NDIS_ERROR_CODE_MEMORY_CONFLICT ((NDIS_ERROR_CODE)0x80001399L)
+
diff --git a/private/ntos/ndis/madge/driver/mdgerrs.rc b/private/ntos/ndis/madge/driver/mdgerrs.rc
new file mode 100644
index 000000000..0885a897e
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/mdgerrs.rc
@@ -0,0 +1,2 @@
+LANGUAGE 0x9,0x1
+1 11 MSG00001.bin
diff --git a/private/ntos/ndis/madge/driver/mdgmport.bin b/private/ntos/ndis/madge/driver/mdgmport.bin
new file mode 100644
index 000000000..cfb369d88
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/mdgmport.bin
Binary files differ
diff --git a/private/ntos/ndis/madge/driver/mdgmport.rc b/private/ntos/ndis/madge/driver/mdgmport.rc
new file mode 100644
index 000000000..a445b6bbe
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/mdgmport.rc
@@ -0,0 +1,26 @@
+#include <windows.h>
+
+#include "mdgerrs.rc"
+
+#include "mdgmport.upd"
+
+#include <ntverp.h>
+
+#undef VER_COMPANYNAME_STR
+#undef VER_PRODUCTNAME_STR
+#undef VER_PRODUCTVERSION
+#undef VER_PRODUCTVERSION_STR
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+#define VER_COMPANYNAME_STR "Madge Networks Ltd"
+#define VER_PRODUCTNAME_STR "Madge Networks Smart 16/4 Ringnode Driver"
+#define VER_FILEDESCRIPTION_STR "Madge Smart 16/4 Ringnode Driver"
+#define VER_INTERNALNAME_STR "MdgNT.SYS"
+
+#define VER_LEGALCOPYRIGHT_YEARS "1994"
+#define VER_LEGALCOPYRIGHT_STR "Copyright (C) Madge Networks Ltd " VER_LEGALCOPYRIGHT_YEARS
+#define VER_PRODUCTVERSION MADGE_NT_VERSION
+#define VER_PRODUCTVERSION_STR MADGE_NT_VERSION_STR
+
+#include "common.ver"
diff --git a/private/ntos/ndis/madge/driver/mdgmport.upd b/private/ntos/ndis/madge/driver/mdgmport.upd
new file mode 100644
index 000000000..62ca51952
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/mdgmport.upd
@@ -0,0 +1,553 @@
+/***************************************************************************
+*
+* MDGMPORT.UPD
+*
+* Update log and version information for FastMAC Plus based NDIS 3.0
+* miniport driver.
+*
+* Copyright (c) Madge Networks Ltd 1994
+*
+* COMPANY CONFIDENTIAL
+*
+* Created: 20/06/1994
+*
+****************************************************************************/
+
+/*---------------------------------------------------------------------------
+|
+| Helper macro to make a DWORD.
+|
+---------------------------------------------------------------------------*/
+
+#define MAKE_DWORD(a, b, c, d) \
+ ((((DWORD) (a)) << 24) + \
+ (((DWORD) (b)) << 16) + \
+ (((DWORD) (c)) << 8 ) + \
+ (((DWORD) (d)) ))
+
+
+/*---------------------------------------------------------------------------
+|
+| Version number.
+|
+---------------------------------------------------------------------------*/
+
+//
+// Define both a string and a comma separated list of numbers. These will be
+// used by the resource compiler when version stamping the driver file.
+//
+
+#define MADGE_NT_VERSION 2,04,30,00
+#define MADGE_NT_VERSION_STR "2.04.30"
+#define MADGE_NT_VERSION_DWORD MAKE_DWORD(2, 4, 30, 0)
+
+#define _IS_ALPHA // Define if alpha version.
+
+
+/*---------------------------------------------------------------------------
+|
+| Compile time string definitions identifying driver type. Used in one of
+| the request calls (OID_GEN_VENDOR_DESCRIPTION).
+|
+|--------------------------------------------------------------------------*/
+
+#if NDIS_NT
+#define MADGE_NT_NAME "MdgMPort"
+#define MADGE_DRIVER_NAME NDIS_STRING_CONST("MdgMPort");
+#define MADGE_FMP_NAME NDIS_STRING_CONST("MDGMPORT.BIN");
+#endif
+
+#if DBG
+#define _DRIVER_PREFIX "DEBUG_MADGE_NDIS3_DRIVER:"
+#else
+#define _DRIVER_PREFIX "MADGE_NDIS3_DRIVER:"
+#endif
+
+#define DRIVER_VERSION \
+ _DRIVER_PREFIX##" "##MADGE_NT_NAME##" "##MADGE_NT_VERSION_STR
+
+
+/*---------------------------------------------------------------------------
+Ý Product instance identification string.
+---------------------------------------------------------------------------*/
+
+#ifdef _IS_ALPHA
+#define NT_PRODUCT_INSTANCE_ID "MDGMPORT v"##MADGE_NT_VERSION_STR
+#else
+#define NT_PRODUCT_INSTANCE_ID "MDGMPORT.SYS v"##MADGE_NT_VERSION_STR
+#endif
+
+
+/*---------------------------------------------------------------------------
+|
+| String for identification by MVER.
+|
+|--------------------------------------------------------------------------*/
+
+#define MVER_STRING \
+ "VeRsIoN="##MADGE_NT_NAME##" "##MADGE_NT_VERSION_STR
+
+
+/*---------------------------------------------------------------------------
+|
+| Update history.
+|
+|----------------------------------------------------------------------------
+
+ 2.04.30 10/10/1995 PBA
+
+ Source to be shipped to Microsoft. This is the LSS 4.31
+ build with support added for non-intel platforms.
+
+ 2.04.01-.29 Reserved for 4.3(1) maintanance.
+
+ 2.04 21/07/1995 PBA
+
+ Re-released for 4.3(1) with PCI-TI DMA/DIO fix.
+
+ 2.03.01-.49 Reserved for 4.3(1) maintanance.
+
+ 2.03.01 14/07/1995 PBA
+
+ Now uses FTK 2.21.11 which has software handshakes
+ for all PCI cards in pseduo DMA mode. There is a race
+ condition on a PCI bus whereby SWHLDA gets "stuck" and
+ a pending pseudo DMA starts before the host tells
+ the adapter to start it.
+
+ FTK 2.21.11 also fixes a bug in the RAP 1B MMIO code
+ where we could erroneously do an MMIO transfer if
+ we were on a shared interrupt.
+
+ FTK 2.21.11 also fixes a PCI-IT DMA problem. We were
+ not checking if pseudo DMA was enabled in the
+ interrupt handler and because the interrupt handler
+ is called for real DMA should SWHRQ be set we would
+ do some erroneous pseudo DMA processing.
+
+ 2.03 30/06/1995 PBA
+
+ Hardware thread released for LSS 4.3(1) with support
+ for PCI-TI adapters and untested support for PCI-Abyss
+ adapters. Uses FTK 2.21.07 and FMPLUS 1.36.
+
+ 2.02 Used for non-intel thread drivied from LSS 4.30.
+
+ 2.01.03 12/05/1995 PBA
+
+ Now uses FTK 2.21.02 that can cope with the stray
+ initialisation interrupt generated by some
+ socket controllers.
+
+ 2.01.02 07/04/1995 PBA
+
+ Now uses FTK 2.21.01 and FastMAC Plus 1.34.10 which
+ have an extended handshake on transmit MMIO to
+ avoid a SAM upload/DIO race condition.
+
+ 2.01.01 05/04/1995 PBA
+
+ Power PC build. Only tested on ISA and PCI adapters.
+ Only works in PIO mode.
+
+
+ 2.02.01 - .49 Reserved for 4.3(0 and/or PnP) maintenance.
+
+ 2.01 02/02/1995 PBA
+
+ Released for 4.3(0 and/or PnP). Any previous 4.3(x)
+ threads are now dead.
+
+ 2.00.61 02/02/1995 PBA
+
+ Now uses FastMAC Plus 1.28. Given to DaveF for Chicago
+ testing and possible shipping to Microsoft for M8
+ and/or NT 3.51.
+
+ 2.00.60 01/02/1995 PBA
+
+ Windows95 build 310 always returns the native bus type
+ of the PC rather than the type of the bus the adapter
+ is in. To get around the problem we now read the bus
+ type from the wrapper and then override the value if
+ we find an adapter type parameter in the registry.
+
+ 2.00.59 31/01/1995 PBA
+
+ The Windows95 wrapper now supports the
+ NdisReadPciSlotInformation so we can now have a binary
+ compatible build. The register parameter "PlatformType"
+ is used to determine the OS type the driver is running on.
+
+ Also allowed "IoBaseAddress" to be used instead of
+ "IoLocation" for forwards compatibility with NT 3.51.
+
+ 2.00.58 24/01/1995 PBA
+
+ Uses FTK 2.20.26 that fixes a problem where the software
+ handshake was not being enabled properly for PCMCIA
+ adapters.
+
+ 2.00.57 12/01/1995 PBA
+
+ Given to central support to fix PRF 2841.
+ Uses FastMAC Plus 1.20.
+
+ 2.00.56 12/01/1995 PBA
+
+ Now uses FTK 2.20.25 that has a fix to avoid
+ driver_remove_adapter deallocating the FastMAC Plus
+ dma test buffer when it has not been allocated.
+
+ 2.00.55 12/01/1995 PBA
+
+ Now deregister shutdown handler in MadgeCleanupAdapter
+ to avoid the odd blue screen when MadgeShutdown was
+ called after we had freed the adapter structure.
+
+ 2.00.54 12/01/1995 PBA
+
+ Now uses FTK 2.20.24 that allows the driver to run
+ on none Madge adapters if #define MADGIC_BIT 0x8000
+ is present in user.h.
+
+ 2.00.53 11/01/1995 PBA
+
+ Given to central support. Uses FastMAC Plus 1.25.
+
+ 2.00.52 11/01/1995 PBA
+
+ Given to central support to fix PRF 2841.
+ i.e. Insufficient shared memory available when the
+ driver is installed while NT is being installed to
+ start the adapter during the NT installation. The solution
+ is to add a shared memory aribitration routine which
+ attempts to reduce the number of RX/TX slots and the
+ maxiumum frame size until there is enough shared memory
+ left. Uses FastMAC Plus 1.20.
+
+ 2.00.51 06/01/1995 PBA
+
+ Shipped source to FrancisT so he could build it on
+ a MIPs. Uses FastMAC Plus 1.25.
+
+ 2.00.50 03/01/1995 PBA
+
+ Changed so that TX/RX buffers on use shared memory in DMA
+ mode. PIO and MMIO use ordinary memory.
+
+ Version numbers 1.50.01 to 1.99.99 are used for a FastMAC version.
+
+ 1.07.52 13/12/1994 PBA
+
+ No longer sets monitor contender in the open options.
+
+ 1.07.51 09/12/1994 PBA
+
+ Changed so that if we are compiling for a none Intel
+ platform we allocate map registers properly. For Intel
+ platforms we still use the cludge where we allocate
+ the adapter block ourselves. This should solve the
+ DEC AXP 2100 problem.
+
+ 1.07.50 09/12/1994 PBA
+
+ Revised to use the new FTK (2.20.xx).
+
+ 1.07.01 - .49 Reserved for release 4.3(1) maintenance.
+
+ 1.07 Reserved for release 4.3(1).
+
+ Screwed up the versions numbers. Live development jumps to 1.07.50
+
+ 1.06.52 29/11/1994 PBA
+
+ Gave source to FrancisF to try and track down the
+ DEC 2100 shared memory allocation problem.
+
+ 1.06.51 24/11/1994 PBA
+
+ Moved the clearing of the private SRB in progress flag
+ out of the DPR and into the ISR as the DPR doesn't
+ get called during the initialisation code under Chicago.
+ Doing it this way avoids the nasty delay loop in the
+ initialisation code when setting the product instance id.
+
+ ---- Special ---------------------------------------------------------------
+
+ 1.06.81 - Microsoft thread based on 1.06.80 splits here.
+
+ 1.06.80 11/01/1994 PBA
+
+ Same as 1.06.50 but accepts IoBaseAddress for the I/O
+ location as well as IoLocation. Uses FastMAC Plus 1.20.
+ Shipped to Jameel Hyder at Microsoft for NT 3.51 beta.
+
+ ---- Special ---------------------------------------------------------------
+
+ 1.06.70 13/12/1994 PBA
+
+ This is an alpha for FrancisT derived directly from
+ 1.06. The only differences are that it does not open in
+ monitor contention mode, it uses map registers rather
+ than the "horrible hack" and it is an NT only build.
+
+ ---- Special ---------------------------------------------------------------
+
+ 1.06.60 05/11/1994 PBA
+
+ Same as 1.06.50 but with FastMAC Plus 1.24.
+
+ ---- Special ---------------------------------------------------------------
+
+ 1.06.50 23/11/1994 PBA
+
+ Shipped to Microsoft for possible inclusion in the next
+ NT and Chicago (M8) releases. Uses FastMAC Plus v1.20.
+ This is based on 1.05.04.
+
+ ----------------------------------------------------------------------------
+
+ 1.06.01 - .49 Reserved for release 4.3(0) maintenance.
+
+ 1.06 Reserved for release 4.3(0).
+
+ Source used for 4.3(1) split from the main thread here.
+
+ 1.05.04 22/11/1994 PBA
+
+ Changed the initialisation code to allow as few as
+ 2 RX and 2 TX slots. Hopefully this will keep
+ Microsoft quiet about shared memory allocation.
+
+ 1.05.03 22/11/1994 PBA
+
+ Added a shutdown handler. Note there is no documentation
+ for this, just an example in the IBMTOK2i source.
+
+ 1.05.02 21/11/1994 PBA
+
+ Now re-tries bring-up up to 10 times.
+
+ 1.05.01 18/11/1994 PBA
+
+ Added code to set a product instance id in FastMAC plus.
+
+ 1.05 18/11/1994 PBA
+
+ Windows95 build for PnP field trials. Uses FastMAC Plus
+ v1.20.
+
+ 1.04.54 17/11/1994 PBA
+
+ Modified the PnP HWI to set the channel ready bit
+ if the active float channel ready bit is set in the
+ PnP hardware features byte.
+
+ 1.04.53 17/11/1994 PBA
+
+ Added support for PCI under Chicago. This has to be
+ done with a compile time switch because the
+ NdisReadPciSlotInformation functions is not in the
+ Chicago (M7) Ndis wrapper. If this function call
+ is present then Chicago refuses to load the driver.
+ We get the PCI configuration in Chicago by just reading
+ from the registry.
+
+ 1.04.52 16/11/1994 PBA
+
+ Changed PnP HWI so that it knows about C30s.
+
+ 1.04.51 07/11/1994 PBA
+
+ Added PnP support. Chicago only at the moment.
+
+ 1.04.50 04/11/1994 PBA
+
+ Added PCMCIA support. Chicago only at the moment.
+
+ Version numbers 1.04.01 to 1.04.49 are reserved for maintenance fixes
+ to version 1.04. Live development continues at 1.04.50.
+
+ 1.04 08/11/1994 PBA
+
+ Cludged version use for PCI Releases. Uses FastMAC Plus v1.21
+ and hwi_pci.c from v1.03 archive. This means that the
+ driver does MMIO on RX only (pseudo DMA on transmit).
+
+ 1.03.07 07/11/1994 PBA
+
+ Alpha version shipped to Gordon Cairns.
+ Uses FastMAC Plus alpha v1.23.01
+
+ 1.03.06 03/11/1994 PBA
+
+ Now supports transmit and receive PCI MMIO.
+
+ 1.03.05 02/11/1994 PBA
+
+ Now sets the FTK error code if RX or TX buffers cannot
+ be allocaed.
+
+ 1.03.04 01/11/1994 PBA
+
+ Arranged for the PCI cards to be defaulted to pseudo DMA
+ if MMIO memory is not allocated or cannot be mapped into
+ virtual memory.
+
+ 1.03.03 01/11/1994 PBA
+
+ Tidied up the error messages written to the event long
+ as the new DDK has a better range of error codes.
+
+ 1.03.02 11/10/1994 PBA
+
+ Added a RingSpeed parameter to set the ringspeed(!).
+ RingSpeed == 0 means don't care about the ring speed;
+ use the default or use Force4/Force16. 1 means 4MBits.
+ 2 means 16 MBits. RingSpeed overrides Force4/Force16.
+
+ 1.03.01 7/10/1994 PD
+
+ Added traffic monitoring code enabled by uncommenting
+ line defining OID_MADGE_MONITOR in NDISMOD.H.
+
+
+ 1.03 28/09/1994 PBA
+
+ Released for PCI release 4.2(3).
+
+ 1.02.53 28/09/1994 PBA
+
+ Now uses FastMAC Plus 1.21.
+
+ 1.02.52 28/09/1994 PBA
+
+ Added PCI support. There is a new registry parameter
+ called "NoMmio". By default MMIO is used as the PCI
+ transfer method. If NoMmio is 1 then pseudo DMA is used.
+ PCI adapters are identified by the "SlotNumber" parameter
+ in the registry. This is actually set to the logical
+ device number of the PCI adapter. If SlotNumber is set
+ to 0xffff then the PCI bus is searched for the first
+ unused Madge PCI adapter.
+
+ 1.02.51 21/09/1994 PBA
+
+ Added a Multiprocessor parameter. If this parameter is
+ non-zero and the DMA channel is zero then multiprocessor
+ safe PIO is used. The code which enabled multiprocessor
+ safe PIO by when the DMA channel was set to 0x8000 has
+ been left in for backwards compatibility.
+
+ 1.02.50 12/09/1994 PBA
+
+ The I/O location of the SIF registers is now recorded in
+ the adapter structure at initialisation time by the
+ hwi_xxx.c routines. Previously the SIF registers were
+ assumed to be at fixed offsets from a SIF base address.
+ This change is needed to support PCI adapters.
+
+ Due to the problems with FastMAC Plus a re-release with a new FastMAC
+ plus image will be needed for LSS 4.30. This release will be based on
+ 1.02.xx which is the same as the earlier LSS 4.30 with some minor bug
+ fixes. Live development continues with 1.02.50.
+
+ 1.02.04 12/09/1994 PBA
+
+ Now sets the "Madgic" bits in the FMP dowload header so
+ that we will run on none Madge adapters.
+
+ 1.02.03 12/09/1994 PBA
+
+ Fixed a bug where we didn't check if the tx buffer memory
+ allocation had succeeded.
+
+ 1.02.02 31/08/1994 PBA
+
+ Source shipped to Microsoft.
+
+ 1.02.01 31/08/1994 PBA
+
+ Noew only checks the major and minor version numbers
+ of the download.
+
+ 1.02 24/08/1994 PBA
+
+ Re-released for 4.3.
+
+ 1.01.03 16/08/1994 PBA
+
+ Added comments about ring speed and duplicate addresses
+ to the cannot open error message.
+
+ 1.01.02 11/08/1994 PBA
+
+ At the recommendation of Kevin Martin (Microsoft) the
+ NDIS_MAC_OPTIONS_NO_LOOPBACK bit is no-longer set and we
+ just allow the hardware to do loopback.
+
+ 1.01.01 10/08/1994 PBA
+
+ Added a flag to the adapter structure called UseMPSafePIO.
+ If this flag is set then all of the DIO on the transmit
+ and receive paths is encapsulated in functions invoked
+ by NdisMSynchronizeWithInterrupt to protect the DIO
+ from PIO interrupts happening on another processor in
+ a multiprocessor machine. This flag is set if the DMA
+ channel is specified as 0x8000 - see MadgeReadRegstry().
+
+ 1.01 22/07/1994 PBA
+
+ Released for 4.30.
+
+ 1.00.08 20/07/1994 PBA
+
+ Added support for a Force16 option for ATULA adapters
+ and Force16 and Force4 options for AT/P and ISA/C/P
+ adapters.
+
+ 1.00.07 19/07/1994 PBA
+
+ Added an option to allow the adapter to be forced open
+ (it was always done before, which is wrong).
+
+ 1.00.06 04/07/1994 PBA
+
+ Found a race condition with ATULA cards in PIO mode. We
+ MUST claim interrupts (even if they are just for PIO)
+ until the "DMA" initialisation test is over or sometimes
+ WFWG (and possibly NT) permanently masks out our interrupts.
+
+ 1.00.05 01/07/1994 PBA
+
+ Alpha version for Gordon Cairns to test.
+
+ 1.00.04 29/06/1994 PBA
+
+ Used conditional assembly in sys_mem.c so that the
+ I/O on Intel platforms does not involve any mapping
+ (since the mapping always results in the port address
+ anyway).
+
+ 1.00.03 28/06/1994 PBA
+
+ Now uses FTK common to all of the NDIS3 drivers.
+
+ 1.00.02 28/06/1994 PBA
+
+ Fixed a bug in the ChangeFilter function. We were carefully
+ working out the new open options and passing the old options
+ in the SRB.
+
+ 1.00.01 21/06/1994 PBA
+
+ First instance for MdgMPort. Derived from MdgNT v1.01.12
+
+---------------------------------------------------------------------------*/
+
+
+/******** End of MDGMPORT.UPD **********************************************/
+ \ No newline at end of file
diff --git a/private/ntos/ndis/madge/driver/msg00001.bin b/private/ntos/ndis/madge/driver/msg00001.bin
new file mode 100644
index 000000000..7e2f93fb0
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/msg00001.bin
Binary files differ
diff --git a/private/ntos/ndis/madge/driver/request.c b/private/ntos/ndis/madge/driver/request.c
new file mode 100644
index 000000000..21172e71b
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/request.c
@@ -0,0 +1,1158 @@
+/***************************************************************************
+*
+* REQUEST.C
+*
+* FastMAC Plus based NDIS3 miniport driver routines for handling SRB
+* requests and ODI_ requsts.
+*
+* Copyright (c) Madge Networks Ltd 1994
+*
+* COMPANY CONFIDENTIAL
+*
+* Created: PBA 21/06/1994
+*
+****************************************************************************/
+
+#include <ndis.h>
+
+#include "ftk_defs.h"
+#include "ftk_extr.h"
+
+#include "mdgmport.upd"
+#include "ndismod.h"
+
+
+/*---------------------------------------------------------------------------
+|
+| Global OIDs that we will support queries on.
+|
+---------------------------------------------------------------------------*/
+
+NDIS_OID MadgeGlobalSupportedOids[] =
+{
+ //
+ // General, Operational, Mandatory.
+ //
+
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_MAC_OPTIONS,
+
+ //
+ // General, Statistical, Mandatory.
+ //
+
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+
+ //
+ // Token Ring, Operational, Mandatory.
+ //
+
+ OID_802_5_PERMANENT_ADDRESS,
+ OID_802_5_CURRENT_ADDRESS,
+ OID_802_5_CURRENT_FUNCTIONAL,
+ OID_802_5_CURRENT_GROUP,
+ OID_802_5_LAST_OPEN_STATUS,
+ OID_802_5_CURRENT_RING_STATUS,
+ OID_802_5_CURRENT_RING_STATE,
+
+ //
+ // Token Ring, Statistical, Mandatory.
+ //
+
+ OID_802_5_LINE_ERRORS,
+ OID_802_5_LOST_FRAMES,
+
+ //
+ // Token Ring Statistical, Optional.
+ //
+
+ OID_802_5_BURST_ERRORS,
+ OID_802_5_AC_ERRORS,
+ OID_802_5_FRAME_COPIED_ERRORS,
+ OID_802_5_TOKEN_ERRORS
+
+ //
+ // There are three more Token Ring error stat's but TI MAC code does not
+ // support them, so we go without! (ABORT_DELIMITERS, FREQUENCY_ERRORS,
+ // and INTERNAL_ERRORS).
+ //
+};
+
+
+/**************************************************************************
+*
+* Function - MadgeCompletePendingRequest
+*
+* Parameters - ndisAdap -> Pointer NDIS3 level adapter structure.
+*
+* Purpose - Complete a pending request on the adapter specified.
+*
+* Returns - Nothing.
+*
+***************************************************************************/
+
+VOID
+MadgeCompletePendingRequest(PMADGE_ADAPTER ndisAdap)
+{
+ BOOLEAN success;
+ ADAPTER * ftkAdapter;
+ ULONG * infoBuffer;
+
+// MadgePrint1("MadgeCompletePendingRequest started\n");
+
+ success = ndisAdap->SrbRequestStatus;
+
+ switch(ndisAdap->RequestType)
+ {
+ case NdisRequestQueryInformation:
+
+ infoBuffer = (ULONG *) ndisAdap->InformationBuffer;
+
+ if (success)
+ {
+ ftkAdapter = adapter_record[ndisAdap->FtkAdapterHandle];
+
+ ndisAdap->ReceiveCongestionCount +=
+ ftkAdapter->status_info->error_log.congestion_errors;
+ ndisAdap->LineErrors +=
+ ftkAdapter->status_info->error_log.line_errors;
+ ndisAdap->BurstErrors +=
+ ftkAdapter->status_info->error_log.burst_errors;
+ ndisAdap->AcErrors +=
+ ftkAdapter->status_info->error_log.ari_fci_errors;
+ ndisAdap->TokenErrors +=
+ ftkAdapter->status_info->error_log.token_errors;
+
+ switch(ndisAdap->RequestOid)
+ {
+ case OID_GEN_RCV_NO_BUFFER:
+
+ *infoBuffer = ndisAdap->ReceiveCongestionCount;
+ break;
+
+ case OID_802_5_LINE_ERRORS:
+
+ *infoBuffer = ndisAdap->LineErrors;
+ break;
+
+ case OID_802_5_BURST_ERRORS:
+
+ *infoBuffer = ndisAdap->BurstErrors;
+ break;
+
+ case OID_802_5_AC_ERRORS:
+
+ *infoBuffer = ndisAdap->AcErrors;
+ break;
+
+ case OID_802_5_TOKEN_ERRORS:
+
+ *infoBuffer = ndisAdap->TokenErrors;
+ break;
+ }
+
+ ndisAdap->JustReadErrorLog = ndisAdap->RequestOid;
+ }
+
+ //
+ // And complete the request.
+ //
+
+ NdisMQueryInformationComplete(
+ ndisAdap->UsedInISR.MiniportHandle,
+ (success) ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE
+ );
+
+ break;
+
+ case NdisRequestSetInformation:
+
+ //
+ // All we need to do is complete the request.
+ //
+
+ NdisMSetInformationComplete(
+ ndisAdap->UsedInISR.MiniportHandle,
+ (success) ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE
+ );
+
+ break;
+ }
+
+// MadgePrint1("MadgeCompletePendingRequest finished\n");
+}
+
+
+/***************************************************************************
+*
+* Function - MadgeQueryInformation
+*
+* Parameters - adapterContext -> Pointer NDIS3 level adapter structure.
+* oid -> The OID.
+* infoBuffer -> Pointer to the information buffer.
+* infoLength -> Length of the information buffer.
+* bytesWritten -> Pointer to a holder for the number of
+* bytes we've written.
+* bytesNeeded -> Pointer to a holder for the number of
+* bytes we need.
+*
+* Purpose - Set adapter information.
+*
+* Returns - An NDIS3 status code.
+*
+***************************************************************************/
+
+NDIS_STATUS
+MadgeQueryInformation(
+ NDIS_HANDLE adapterContext,
+ NDIS_OID oid,
+ PVOID infoBuffer,
+ ULONG infoLength,
+ PULONG bytesWritten,
+ PULONG bytesNeeded
+ )
+{
+ PMADGE_ADAPTER ndisAdap;
+ UINT supportedOids;
+ UINT i;
+ ULONG genericULong;
+ USHORT genericUShort;
+ UCHAR genericArray[6];
+ PVOID sourceBuffer;
+ ULONG sourceLength;
+ UCHAR * vendorID;
+
+
+ static UCHAR VendorDescription[] = DRIVER_VERSION;
+
+// MadgePrint2("MadgeQueryInformation Oid = %08x\n", (UINT) oid);
+
+ //
+ // Do some pre-calculation.
+ //
+
+ ndisAdap = PMADGE_ADAPTER_FROM_CONTEXT(adapterContext);
+ sourceBuffer = (PVOID) &genericULong;
+ sourceLength = (ULONG) sizeof(ULONG);
+ vendorID = (UCHAR *) &genericULong;
+ supportedOids = sizeof(MadgeGlobalSupportedOids) / sizeof(NDIS_OID);
+
+ //
+ // Check that we recognise the OID.
+ //
+
+#ifdef OID_MADGE_MONITOR
+
+ if (oid == OID_MADGE_MONITOR)
+ {
+ if (sizeof(MADGE_MONITOR) > infoLength)
+ {
+ *bytesNeeded = sizeof(MADGE_MONITOR);
+ return NDIS_STATUS_BUFFER_TOO_SHORT;
+ }
+
+ MADGE_MOVE_MEMORY(
+ infoBuffer,
+ &(ndisAdap->MonitorInfo),
+ sizeof(MADGE_MONITOR)
+ );
+
+ *bytesWritten = sizeof(MADGE_MONITOR);
+
+ // Clear out the Monitor Structure
+ for (i = 0; i < sizeof(MADGE_MONITOR); i++)
+ {
+ ((UCHAR *) &(ndisAdap->MonitorInfo))[i] = (UCHAR) 0;
+ }
+
+ return NDIS_STATUS_SUCCESS;
+ }
+
+#endif
+
+ for (i = 0; i < supportedOids; i++)
+ {
+ if (oid == MadgeGlobalSupportedOids[i])
+ {
+ break;
+ }
+ }
+
+ if (i == supportedOids)
+ {
+ *bytesWritten = 0;
+ MadgePrint1("OID not supported\n");
+ return NDIS_STATUS_INVALID_OID;
+ }
+
+ //
+ // Now decode the OID based on the component bytes - this should make
+ // the switch statement slightly quicker than a simple linear list.
+ //
+ // The OIDs are classed by category (General or Media Specific) and type
+ // (Operational or Statistical), so we'll deal with them thus :
+ // General Operational
+ // General Statistical
+ // Media Specific Operational
+ // Media Specific Statistical
+ //
+
+ switch (oid & OID_TYPE_MASK)
+ {
+ /*-----------------------------------------------------------------*/
+
+ case OID_TYPE_GENERAL_OPERATIONAL:
+
+ switch (oid)
+ {
+ case OID_GEN_SUPPORTED_LIST:
+
+ sourceBuffer = MadgeGlobalSupportedOids;
+ sourceLength = sizeof(MadgeGlobalSupportedOids);
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+
+ genericULong = ndisAdap->HardwareStatus;
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+
+ genericULong = NdisMedium802_5;
+ break;
+
+ case OID_GEN_MEDIA_IN_USE:
+
+ genericULong = NdisMedium802_5;
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+
+ //
+ // The maximum lookahead size is the size of the whole
+ // frame, less the MAC header. It is NOT the maximum
+ // frame size according to the ring speed.
+ //
+
+ genericULong = ndisAdap->MaxFrameSize - FRAME_HEADER_SIZE;
+
+ //
+ // WARNING: What about Source Routing in the header?
+ //
+
+// MadgePrint2("OID_GEN_MAXIMUM_LOOKAHEAD = %ld\n",
+// genericULong);
+
+ break;
+
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+
+ //
+ // Note that the MAXIMUM_FRAME_SIZE is the largest frame
+ // supported, not including any MAC header, while the
+ // MAXIMUM_TOTAL_SIZE does include the MAC header.
+ //
+
+ genericULong = ndisAdap->MaxFrameSize;
+
+ if (oid == OID_GEN_MAXIMUM_FRAME_SIZE)
+ {
+ genericULong -= FRAME_HEADER_SIZE;
+ }
+
+// MadgePrint2("OID_GEN_MAXIMUM_FRAME_SIZE = %ld\n",
+// genericULong);
+
+ break;
+
+ case OID_GEN_LINK_SPEED:
+
+ //
+ // Is this right? Shouldn't it be 16000000 and 4000000?
+ //
+
+ genericULong =
+ (driver_ring_speed(ndisAdap->FtkAdapterHandle) == 16)
+ ? 160000
+ : 40000;
+ break;
+
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+
+ genericULong =
+ ndisAdap->MaxFrameSize * ndisAdap->FastmacTxSlots;
+ break;
+
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+
+ genericULong =
+ ndisAdap->MaxFrameSize * ndisAdap->FastmacRxSlots;
+ break;
+
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+
+ genericULong = ndisAdap->MaxFrameSize;
+ break;
+
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+
+ genericULong = ndisAdap->MaxFrameSize;
+ break;
+
+ case OID_GEN_VENDOR_ID:
+
+ MADGE_MOVE_MEMORY(
+ vendorID,
+ &ndisAdap->PermanentNodeAddress,
+ 3
+ );
+ vendorID[3] = 0x00;
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+
+ sourceBuffer = VendorDescription;
+ sourceLength = sizeof(VendorDescription);
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ genericULong = (ULONG) ndisAdap->CurrentPacketFilter;
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ genericULong = (ULONG) ndisAdap->CurrentLookahead;
+
+// MadgePrint2("OID_GEN_CURRENT_LOOKAHEAD = %ld\n",
+// genericULong);
+
+ break;
+
+ case OID_GEN_DRIVER_VERSION:
+
+ genericUShort = (MADGE_NDIS_MAJOR_VERSION << 8) +
+ MADGE_NDIS_MINOR_VERSION;
+ sourceBuffer = &genericUShort;
+ sourceLength = sizeof(USHORT);
+ break;
+
+ case OID_GEN_MAC_OPTIONS:
+
+ genericULong = (ULONG)
+ (NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
+ NDIS_MAC_OPTION_RECEIVE_SERIALIZED);
+ break;
+
+ default:
+
+ MadgePrint2("OID %x not recognised\n", oid);
+ return NDIS_STATUS_INVALID_OID;
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+
+ case OID_TYPE_GENERAL_STATISTICS:
+
+ //
+ // Might need these later.
+ //
+
+ *bytesWritten = sourceLength;
+ ndisAdap->RequestType = NdisRequestQueryInformation;
+ ndisAdap->RequestOid = oid;
+ ndisAdap->InformationBuffer = infoBuffer;
+
+ switch (oid)
+ {
+ case OID_GEN_XMIT_OK:
+
+ genericULong = (ULONG) ndisAdap->FramesTransmitted;
+ break;
+
+ case OID_GEN_RCV_OK:
+
+ genericULong = (ULONG) ndisAdap->FramesReceived;
+ break;
+
+ case OID_GEN_XMIT_ERROR:
+
+ genericULong = (ULONG) ndisAdap->FrameTransmitErrors;
+ break;
+
+ case OID_GEN_RCV_ERROR:
+
+ genericULong = (ULONG) ndisAdap->FrameReceiveErrors;
+ break;
+
+ case OID_GEN_RCV_NO_BUFFER:
+
+ //
+ // We need to issue a READ_ERROR_LOG SRB to recover an
+ // up to date value for this counter.
+ //
+
+ if (ndisAdap->JustReadErrorLog != 0 &&
+ ndisAdap->JustReadErrorLog != oid)
+ {
+ genericULong = (ULONG)
+ ndisAdap->ReceiveCongestionCount;
+ }
+ else if (infoLength >= sourceLength)
+ {
+ driver_get_status(ndisAdap->FtkAdapterHandle);
+ return NDIS_STATUS_PENDING;
+ }
+ break;
+
+ default:
+
+ MadgePrint2("OID %x not recognised\n", oid);
+ return NDIS_STATUS_INVALID_OID;
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+
+ case OID_TYPE_802_5_OPERATIONAL:
+
+ switch (oid)
+ {
+ case OID_802_5_PERMANENT_ADDRESS:
+
+ sourceBuffer = &genericArray;
+ sourceLength = sizeof(ndisAdap->PermanentNodeAddress);
+
+ MADGE_MOVE_MEMORY(
+ sourceBuffer,
+ &ndisAdap->PermanentNodeAddress,
+ sizeof(ndisAdap->PermanentNodeAddress)
+ );
+ break;
+
+ case OID_802_5_CURRENT_ADDRESS:
+
+ sourceBuffer = &genericArray;
+ sourceLength =
+ sizeof(ndisAdap->OpeningNodeAddress);
+
+ MADGE_MOVE_MEMORY(
+ sourceBuffer,
+ &ndisAdap->OpeningNodeAddress,
+ sizeof(ndisAdap->OpeningNodeAddress)
+ );
+ break;
+
+ case OID_802_5_CURRENT_FUNCTIONAL:
+
+ genericULong =
+ ndisAdap->FunctionalAddress & 0xffffffff;
+ break;
+
+ case OID_802_5_CURRENT_GROUP:
+
+ genericULong =
+ ndisAdap->GroupAddress & 0xffffffff;
+ break;
+
+ case OID_802_5_LAST_OPEN_STATUS:
+
+ genericULong = ndisAdap->LastOpenStatus;
+ break;
+
+ case OID_802_5_CURRENT_RING_STATUS:
+
+ genericULong = ndisAdap->CurrentRingStatus;
+ break;
+
+ case OID_802_5_CURRENT_RING_STATE:
+
+ genericULong = NdisRingStateOpened;
+ break;
+
+ default:
+
+ MadgePrint2("OID %x not recognised\n", oid);
+ return NDIS_STATUS_INVALID_OID;
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+
+ case OID_TYPE_802_5_STATISTICS:
+
+ //
+ // We do a bit of pre-processing here in case we have to queue
+ // an SRB request. In this instance we want everything ready bar
+ // the actual data.
+ //
+
+ if (sourceLength > infoLength)
+ {
+ break;
+ }
+
+ *bytesWritten = sourceLength;
+ ndisAdap->RequestType = NdisRequestQueryInformation;
+ ndisAdap->RequestOid = oid;
+ ndisAdap->InformationBuffer = infoBuffer;
+
+ //
+ // Now get on with working out the data.
+ //
+
+ switch (oid)
+ {
+ case OID_802_5_LINE_ERRORS:
+
+ //
+ // We need to issue a READ_ERROR_LOG SRB to recover an
+ // up to date value for this counter.
+ //
+
+ if (ndisAdap->JustReadErrorLog != 0 &&
+ ndisAdap->JustReadErrorLog != oid)
+ {
+ genericULong = (ULONG) ndisAdap->LineErrors;
+ }
+ else
+ {
+ driver_get_status(ndisAdap->FtkAdapterHandle);
+ return NDIS_STATUS_PENDING;
+ }
+ break;
+
+ case OID_802_5_LOST_FRAMES:
+
+ //
+ // This counter is managed by the transmit process using
+ // the transmit status returned by FastmacPlus.
+ //
+
+ genericULong = (ULONG) ndisAdap->LostFrames;
+ break;
+
+ case OID_802_5_BURST_ERRORS:
+
+ if (ndisAdap->JustReadErrorLog != 0 &&
+ ndisAdap->JustReadErrorLog != oid)
+ {
+ genericULong= (ULONG) ndisAdap->BurstErrors;
+ }
+ else
+ {
+ driver_get_status(ndisAdap->FtkAdapterHandle);
+ return NDIS_STATUS_PENDING;
+ }
+ break;
+
+ case OID_802_5_AC_ERRORS:
+
+ if (ndisAdap->JustReadErrorLog != 0 &&
+ ndisAdap->JustReadErrorLog != oid)
+ {
+ genericULong= (ULONG) ndisAdap->AcErrors;
+ }
+ else
+ {
+ driver_get_status(ndisAdap->FtkAdapterHandle);
+ return NDIS_STATUS_PENDING;
+ }
+ break;
+
+ case OID_802_5_FRAME_COPIED_ERRORS:
+
+ //
+ // This counter is managed by the receive process using
+ // the receive status returned by FastmacPlus.
+ //
+
+ genericULong = (ULONG) ndisAdap->FrameCopiedErrors;
+ break;
+
+ case OID_802_5_TOKEN_ERRORS:
+
+ if (ndisAdap->JustReadErrorLog != 0 &&
+ ndisAdap->JustReadErrorLog != oid)
+ {
+ genericULong = (ULONG) ndisAdap->TokenErrors;
+ }
+ else
+ {
+ driver_get_status(ndisAdap->FtkAdapterHandle);
+ return NDIS_STATUS_PENDING;
+ }
+ break;
+
+ default:
+
+ MadgePrint2("OID %x not recognised\n", oid);
+ return NDIS_STATUS_INVALID_OID;
+ }
+ break;
+ }
+
+ //
+ // Check memory allocation provided by caller - report required amount
+ // if we haven't got enough.
+ //
+
+ if (sourceLength > infoLength)
+ {
+ *bytesNeeded = sourceLength;
+ return NDIS_STATUS_BUFFER_TOO_SHORT;
+ }
+
+ MADGE_MOVE_MEMORY(
+ infoBuffer,
+ sourceBuffer,
+ sourceLength
+ );
+
+ *bytesWritten = sourceLength;
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - MadgeChangeGroupAddress
+|
+| Parameters - ndisAdap -> Pointer to our NDIS level adapter structure.
+| newAddress -> The new group address.
+|
+| Purpose - Queue an SRB to change the group address.
+|
+| Returns - Nothing.
+|
+---------------------------------------------------------------------------*/
+
+STATIC VOID
+MadgeChangeGroupAddress(
+ PMADGE_ADAPTER ndisAdap,
+ TR_FUNCTIONAL_ADDRESS newAddress
+ )
+{
+ MULTI_ADDRESS multiAddress;
+
+// MadgePrint1("MadgeChangeGroupAddress started\n");
+
+ ndisAdap->GroupAddress = newAddress;
+ multiAddress.all = (DWORD) newAddress;
+
+ ndisAdap->RequestType = NdisRequestSetInformation;
+
+ //
+ // And call the FTK to change the address.
+ //
+
+ driver_set_group_address(ndisAdap->FtkAdapterHandle, &multiAddress);
+
+// MadgePrint1("MadgeChangeGroupAddress finished\n");
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - MadgeChangeFunctionalAddress
+|
+| Parameters - ndisAdap -> Pointer to our NDIS level adapter structure.
+| newAddress -> The new functional address.
+|
+| Purpose - Queue an SRB to change the functional address.
+|
+| Returns - Nothing.
+|
+---------------------------------------------------------------------------*/
+
+STATIC VOID
+MadgeChangeFunctionalAddress(
+ PMADGE_ADAPTER ndisAdap,
+ TR_FUNCTIONAL_ADDRESS newAddress
+ )
+{
+ MULTI_ADDRESS multiAddress;
+
+// MadgePrint2("MadgeChangeFunctionalAddress started %08x\n",
+// (UINT) newAddress);
+
+ ndisAdap->FunctionalAddress = newAddress;
+ multiAddress.all = (DWORD) newAddress;
+
+ ndisAdap->RequestType = NdisRequestSetInformation;
+
+ //
+ // And call the FTK to change the address.
+ //
+
+ driver_set_functional_address(ndisAdap->FtkAdapterHandle, &multiAddress);
+
+// MadgePrint1("MadgeChangeFunctionalAddress finished\n");
+}
+
+
+/*---------------------------------------------------------------------------
+|
+| Function - MadgeChangeFilter
+|
+| Parameters - ndisAdap -> Pointer to our NDIS level adapter structure.
+| newFilter -> The new packet filter.
+|
+| Purpose - Change the packet filter.
+|
+| Returns - NDIS_STATUS_PENDING if an SRB is required,
+| NDIS_STATUS_NOT_SUPPORTED if we don't support the filter
+| types, otherwise NDIS_STATUS_SUCCESS.
+|
+---------------------------------------------------------------------------*/
+
+NDIS_STATUS
+MadgeChangeFilter(
+ PMADGE_ADAPTER ndisAdap,
+ UINT newFilter
+ )
+{
+ UINT index;
+ UINT modifyOpenOptions;
+ UINT oldFilter;
+
+ //
+ // Lookup table for the various ways we might want to modify the open
+ // options of the adapter.
+ //
+
+#define MOO_NO_CHANGE (0xffff)
+#define MOO_MASK ((WORD) (~(OPEN_OPT_COPY_ALL_MACS | OPEN_OPT_COPY_ALL_LLCS)))
+
+WORD MooLookupTable[] = {
+ MOO_NO_CHANGE,
+ OPEN_OPT_COPY_ALL_MACS | OPEN_OPT_COPY_ALL_LLCS,
+ OPEN_OPT_COPY_ALL_MACS,
+ OPEN_OPT_COPY_ALL_MACS | OPEN_OPT_COPY_ALL_LLCS,
+ 0,
+ MOO_NO_CHANGE,
+ OPEN_OPT_COPY_ALL_MACS,
+ MOO_NO_CHANGE,
+ 0,
+ OPEN_OPT_COPY_ALL_MACS | OPEN_OPT_COPY_ALL_LLCS,
+ MOO_NO_CHANGE,
+ OPEN_OPT_COPY_ALL_MACS | OPEN_OPT_COPY_ALL_LLCS,
+ 0,
+ MOO_NO_CHANGE,
+ OPEN_OPT_COPY_ALL_MACS,
+ MOO_NO_CHANGE
+ };
+
+// MadgePrint2("MadgeChangeFilter started filter = %04x\n",
+// (UINT) newFilter);
+
+ //
+ // Do some pre-calculation.
+ //
+
+ modifyOpenOptions = 0;
+ index = 0;
+ oldFilter = ndisAdap->CurrentPacketFilter;
+
+// MadgePrint2("Old filter = %04x\n", oldFilter);
+
+ //
+ // By default, the card will receive directed frames, broadcast frames,
+ // and matching functional and group address frames. Thus the following
+ // filter types are handled automatically, whether we want them or not:
+ // NDIS_PACKET_TYPE_DIRECTED NDIS_PACKET_TYPE_BROADCAST
+ // NDIS_PACKET_TYPE_FUNCTIONAL NDIS_PACKET_TYPE_GROUP
+ //
+ // Of the remaining filters, the following are not supported (see below)
+ // NDIS_PACKET_TYPE_MULTICAST NDIS_PACKET_TYPE_ALL_FUNCTIONAL
+ // NDIS_PACKET_TYPE_ALL_MULTICAST NDIS_PACKET_TYPE_SOURCE_ROUTING
+ //
+ // This leaves NDIS_PACKET_TYPE_PROMISCUOUS and NDIS_PACKET_TYPE_MAC,
+ // which we can handle if we want to.
+ //
+
+ if ((newFilter & (NDIS_PACKET_TYPE_MULTICAST |
+ NDIS_PACKET_TYPE_ALL_FUNCTIONAL |
+ NDIS_PACKET_TYPE_ALL_MULTICAST |
+ NDIS_PACKET_TYPE_MAC_FRAME |
+ NDIS_PACKET_TYPE_SOURCE_ROUTING)) != 0)
+
+ {
+ //
+ // These filters are not supported - there is no way our MAC/hw can
+ // be this selective, although the host software could do its own
+ // filtering i.e. enable promiscuous mode, and then throw away all
+ // frames except those indicated above. At some stage it might be
+ // an idea to do this anyway, together with a caveat that it is not
+ // going to be a high performance solution.
+ //
+ // Anyway, in the mean time, return NDIS_STATUS_NOT_SUPPORTED.
+ //
+
+ return NDIS_STATUS_NOT_SUPPORTED;
+ }
+
+ //
+ // Only allow promiscuous mode if it has been enabled.
+ //
+
+ if ((newFilter & (NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_MAC_FRAME)) != 0)
+ {
+ if (!ndisAdap->PromiscuousMode)
+ {
+ return NDIS_STATUS_NOT_SUPPORTED;
+ }
+ }
+
+ //
+ // We've weeded out the illegal ones now - note that no change has been
+ // made to the current filter - this is as specified in the paperwork!
+ //
+ // Make a note of the _adapter_ notion of the filter. Each
+ // binding will have its own idea of what it wants, but this is
+ // the Filter Database's problem, not ours!
+ //
+
+ ndisAdap->CurrentPacketFilter = newFilter;
+
+ //
+ // Now we have to work out which bits need setting in the Modify Open
+ // Options SRB - when I looked at this there didn't appear to be any
+ // obvious way of simplifying the logic, so I use a look up table to do
+ // the decoding instead. You'll just have to take my word for it that I
+ // worked all the permutations out correctly!
+ //
+
+ if (oldFilter & NDIS_PACKET_TYPE_MAC_FRAME)
+ {
+ index |= 8;
+ }
+ if (oldFilter & NDIS_PACKET_TYPE_PROMISCUOUS)
+ {
+ index |= 4;
+ }
+ if (newFilter & NDIS_PACKET_TYPE_MAC_FRAME)
+ {
+ index |= 2;
+ }
+ if (newFilter & NDIS_PACKET_TYPE_PROMISCUOUS)
+ {
+ index |= 1;
+ }
+
+// MadgePrint2("index = %d\n", index);
+
+ modifyOpenOptions =
+ (ndisAdap->OpenOptions & MOO_MASK) | MooLookupTable[index];
+
+// MadgePrint2("modifyOpenOptions = %04x\n", modifyOpenOptions);
+
+ //
+ // Now see if we need to issue an SRB - note that MOO_NO_CHANGE is not
+ // zero, to distinguish from the case when we actually want to write out
+ // zero to turn all the options off.
+ //
+
+ if (modifyOpenOptions != MOO_NO_CHANGE)
+ {
+ //
+ // We have to issue a ModifyOpenOptions SRB.
+ //
+
+ ndisAdap->RequestType = NdisRequestSetInformation;
+ ndisAdap->OpenOptions = (WORD) modifyOpenOptions;
+
+ driver_modify_open_options(
+ ndisAdap->FtkAdapterHandle,
+ ndisAdap->OpenOptions
+ );
+
+// MadgePrint1("MadgeChangeFilter pended\n");
+
+ return NDIS_STATUS_PENDING;
+ }
+
+// MadgePrint1("MadgeChangeFilter finished\n");
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+
+/***************************************************************************
+*
+* Function - MadgeSetInformation
+*
+* Parameters - adapterContext -> Pointer NDIS3 level adapter structure.
+* oid -> The OID.
+* infoBuffer -> Pointer to the information buffer.
+* infoLength -> Length of the information buffer.
+* bytesRead -> Pointer to a holder for the number of
+* bytes we've read.
+* bytesNeeded -> Pointer to a holder for the number of
+* bytes we need.
+*
+* Purpose - Set adapter information.
+*
+* Returns - An NDIS3 status code.
+*
+***************************************************************************/
+
+NDIS_STATUS
+MadgeSetInformation(
+ NDIS_HANDLE adapterContext,
+ NDIS_OID oid,
+ PVOID infoBuffer,
+ ULONG infoLength,
+ PULONG bytesRead,
+ PULONG bytesNeeded
+ )
+{
+ PMADGE_ADAPTER ndisAdap;
+ NDIS_STATUS retCode;
+
+// MadgePrint2("MadgeSetInformation Oid = %08x\n", (UINT) oid);
+
+ //
+ // Do some pre-calculation.
+ //
+
+ ndisAdap = PMADGE_ADAPTER_FROM_CONTEXT(adapterContext);
+
+ //
+ // Process the request.
+ //
+
+ switch (oid)
+ {
+ case OID_802_5_CURRENT_FUNCTIONAL:
+
+ if (infoLength != TR_LENGTH_OF_FUNCTIONAL)
+ {
+ *bytesNeeded = TR_LENGTH_OF_FUNCTIONAL;
+ retCode = NDIS_STATUS_INVALID_LENGTH;
+ }
+ else
+ {
+ MadgeChangeFunctionalAddress(
+ ndisAdap,
+ *((TR_FUNCTIONAL_ADDRESS *) infoBuffer)
+ );
+ *bytesRead = TR_LENGTH_OF_FUNCTIONAL;
+ retCode = NDIS_STATUS_PENDING;
+ }
+ break;
+
+ case OID_802_5_CURRENT_GROUP:
+
+ if (infoLength != TR_LENGTH_OF_FUNCTIONAL)
+ {
+ *bytesNeeded = TR_LENGTH_OF_FUNCTIONAL;
+ retCode = NDIS_STATUS_INVALID_LENGTH;
+ }
+ else
+ {
+ MadgeChangeGroupAddress(
+ ndisAdap,
+ *((TR_FUNCTIONAL_ADDRESS *) infoBuffer)
+ );
+ *bytesRead = TR_LENGTH_OF_FUNCTIONAL;
+ retCode = NDIS_STATUS_PENDING;
+ }
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ if (infoLength != sizeof(UINT))
+ {
+ *bytesNeeded = sizeof(UINT);
+ retCode = NDIS_STATUS_INVALID_LENGTH;
+ }
+ else
+ {
+ retCode = MadgeChangeFilter(
+ ndisAdap,
+ *((UINT *) infoBuffer)
+ );
+ *bytesRead = sizeof(UINT);
+ }
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ //
+ // It IS important to record the current lookahead. On WFWG
+ // machines it is not possible to indicate the whole frame
+ // as lookahead, so take a note of it here.
+ //
+
+// MadgePrint3("Set lookahead infoLength = %d (%d)\n", infoLength, sizeof(ULONG));
+
+ if (infoLength != sizeof(ULONG))
+ {
+ *bytesNeeded = sizeof(ULONG);
+ retCode = NDIS_STATUS_INVALID_LENGTH;
+ }
+ else
+ {
+ ndisAdap->CurrentLookahead =
+ MIN(
+ ndisAdap->MaxFrameSize - FRAME_HEADER_SIZE,
+ MAX(
+ *((ULONG *) infoBuffer),
+ MADGE_MINIMUM_LOOKAHEAD
+ )
+ );
+ *bytesRead = sizeof(ULONG);
+ retCode = NDIS_STATUS_SUCCESS;
+ }
+ break;
+
+ case OID_GEN_PROTOCOL_OPTIONS:
+
+ //
+ // This does nothing - we really don't care about the protocol
+ // options at the moment since we are too stupid to make use of
+ // them anyway.
+ //
+
+ *bytesRead = 4;
+ retCode = NDIS_STATUS_SUCCESS;
+ break;
+
+ default:
+
+ MadgePrint1("Invalid OID\n");
+ retCode = NDIS_STATUS_INVALID_OID;
+ break;
+ }
+
+ return retCode;
+}
+
+/******** End of REQUEST.C ************************************************/
diff --git a/private/ntos/ndis/madge/driver/sources b/private/ntos/ndis/madge/driver/sources
new file mode 100644
index 000000000..23e95be6c
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/sources
@@ -0,0 +1,56 @@
+!if 0
+
+ Copyright (C) 1992-1995 by Digital Equipment Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the MADGE NDIS3 miniport driver being built
+ and the list of sources files needed to build it.
+ It specifies also the compiler switches specific to this driver
+
+Author:
+
+!endif
+
+TARGETNAME=MDGMPORT
+TARGETTYPE=DRIVER
+
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+INCLUDES=.;..\..\..\inc;HEAD_DEF;HEAD_MOD;INC
+
+C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER=1
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=madge.c \
+ dispatch.c \
+ request.c \
+ ftk_user.c \
+ mdgmport.rc \
+ sys_allo.c \
+ sys_dma.c \
+ sys_irq.c \
+ sys_mem.c \
+ sys_time.c \
+ hwi_gen.c \
+ hwi_at.c \
+ hwi_sm16.c \
+ hwi_eisa.c \
+ hwi_mc.c \
+ hwi_pci.c \
+ hwi_pcmc.c \
+ hwi_pnp.c \
+ hwi_pcit.c \
+ hwi_pci2.c \
+ drv_err.c \
+ drv_srb.c \
+ drv_irq.c \
+ drv_init.c \
+ util.c
+
+NTTARGETFILES=mdgmport.bin
diff --git a/private/ntos/ndis/madge/driver/sys_allo.c b/private/ntos/ndis/madge/driver/sys_allo.c
new file mode 100644
index 000000000..d643826c8
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/sys_allo.c
@@ -0,0 +1,492 @@
+/****************************************************************************
+*
+* SYS_ALLO.C
+*
+* FastMAC Plus based NDIS3 miniport driver. This module contains helper
+* routines used by the FTK to allocate resources.
+*
+* Copyright (c) Madge Networks Ltd 1991-1994
+*
+* COMPANY CONFIDENTIAL
+*
+* Created: MF
+* Major modifications: PBA 21/06/1994
+*
+****************************************************************************/
+
+#include <ndis.h>
+
+#include "ftk_defs.h"
+#include "ftk_extr.h"
+
+#include "ndismod.h"
+
+
+/***************************************************************************
+*
+* Function - sys_allocate_adapter_structure
+*
+* Parameter - adapter_handle -> FTK adapter handle.
+* adapter_structure_byte_size -> Size of the adapter structure.
+*
+* Purpose - Allocate an FTK adapter structure.
+*
+* Returns - A pointer to the structure on success or NULL on failure.
+*
+***************************************************************************/
+
+BYTE *
+sys_alloc_adapter_structure(
+ ADAPTER_HANDLE adapter_handle,
+ WORD adapter_structure_byte_size
+ );
+
+#pragma FTK_INIT_FUNCTION(sys_alloc_adapter_structure)
+
+BYTE *
+sys_alloc_adapter_structure(
+ ADAPTER_HANDLE adapter_handle,
+ WORD adapter_structure_byte_size
+ )
+{
+ PVOID ptr;
+ NDIS_STATUS status;
+
+ MADGE_ALLOC_MEMORY(&status, &ptr, (UINT) adapter_structure_byte_size);
+
+ return (status == NDIS_STATUS_SUCCESS)
+ ? (BYTE *) ptr
+ : NULL;
+
+}
+
+/***************************************************************************
+*
+* Function - sys_allocate_dma_phys_buffer
+*
+* Parameter - adapter_handle -> FTK adapter handle.
+* buffer_byte_size -> Size of the DMA buffer.
+* buf_phys -> Pointer to a holder for the DMA
+* buffer's physical address.
+* buf_virt -> Pointer to a holder for the DMA
+* buffer's virtual address.
+*
+* Purpose - Allocate a DMA buffer.
+*
+* Returns - TRUE on success or FALSE on failure.
+*
+***************************************************************************/
+
+WBOOLEAN
+sys_alloc_dma_phys_buffer(
+ ADAPTER_HANDLE adapter_handle,
+ DWORD buffer_byte_size,
+ DWORD * buf_phys,
+ DWORD * buf_virt
+ );
+
+#pragma FTK_INIT_FUNCTION(sys_alloc_dma_phys_buffer)
+
+WBOOLEAN
+sys_alloc_dma_phys_buffer(
+ ADAPTER_HANDLE adapter_handle,
+ DWORD buffer_byte_size,
+ DWORD * buf_phys,
+ DWORD * buf_virt
+ )
+{
+ PMADGE_ADAPTER ndisAdap;
+ VOID * virt;
+ NDIS_PHYSICAL_ADDRESS phys;
+ NDIS_STATUS status;
+
+ *buf_virt = 0;
+ *buf_phys = 0;
+ ndisAdap = (PMADGE_ADAPTER) FTK_ADAPTER_USER_INFORMATION(adapter_handle);
+
+ //
+ // If we are in DMA mode then we must use shared memory. If we are
+ // not in DMA mode then we can use ordinary memory.
+ //
+
+ if (ndisAdap->TransferMode == DMA_DATA_TRANSFER_MODE)
+ {
+#ifdef _ALPHA_
+
+ //
+ // If we are running on an Alpha platform then we need
+ // to allocate map registers. This allocation scheme was
+ // recommended to FrancisT by DEC.
+ //
+
+ if (NdisMAllocateMapRegisters(
+ ndisAdap->UsedInISR.MiniportHandle,
+ (ndisAdap->DmaChannel == 0) ? 255 : ndisAdap->DmaChannel,
+ (BOOLEAN) (ndisAdap->NTCardBusType != NdisInterfaceIsa),
+ BYTES_TO_PAGES(buffer_byte_size),
+ buffer_byte_size
+ ) != NDIS_STATUS_SUCCESS)
+ {
+ return FALSE;
+ }
+
+ //
+ // Note that we have allocated some map registers.
+ //
+
+ ndisAdap->MapRegistersAllocated += BYTES_TO_PAGES(buffer_byte_size);
+
+#endif
+
+#ifdef _MIPS_
+
+ //
+ // If we are running on a MIPs platform then we only
+ // seem to need one map register.
+ //
+
+ if (ndisAdap->MapRegistersAllocated == 0)
+ {
+ if (NdisMAllocateMapRegisters(
+ ndisAdap->UsedInISR.MiniportHandle,
+ (ndisAdap->DmaChannel == 0) ? 255 : ndisAdap->DmaChannel,
+ (BOOLEAN) (ndisAdap->NTCardBusType != NdisInterfaceIsa),
+ 1,
+ buffer_byte_size
+ ) != NDIS_STATUS_SUCCESS)
+ {
+ return FALSE;
+ }
+
+ //
+ // Note that we have allocated some map registers.
+ //
+
+ ndisAdap->MapRegistersAllocated++;
+ }
+
+#endif
+
+#ifdef _PPC_
+
+ //
+ // If we are running on a PPC platform then we only
+ // seem to need one map register.
+ //
+
+ if (ndisAdap->MapRegistersAllocated == 0)
+ {
+ if (NdisMAllocateMapRegisters(
+ ndisAdap->UsedInISR.MiniportHandle,
+ (ndisAdap->DmaChannel == 0) ? 255 : ndisAdap->DmaChannel,
+ (BOOLEAN) (ndisAdap->NTCardBusType != NdisInterfaceIsa),
+ 1,
+ buffer_byte_size
+ ) != NDIS_STATUS_SUCCESS)
+ {
+ return FALSE;
+ }
+
+ //
+ // Note that we have allocated some map registers.
+ //
+
+ ndisAdap->MapRegistersAllocated++;
+ }
+
+#endif
+
+#ifdef _M_IX86
+
+ //
+ // If we are running on an Intel platform then we only
+ // seem to need one map register.
+ //
+
+ if (ndisAdap->MapRegistersAllocated == 0)
+ {
+ if (NdisMAllocateMapRegisters(
+ ndisAdap->UsedInISR.MiniportHandle,
+ (ndisAdap->DmaChannel == 0) ? 255 : ndisAdap->DmaChannel,
+ (BOOLEAN) (ndisAdap->NTCardBusType != NdisInterfaceIsa),
+ 1,
+ buffer_byte_size
+ ) != NDIS_STATUS_SUCCESS)
+ {
+ return FALSE;
+ }
+
+ //
+ // Note that we have allocated some map registers.
+ //
+
+ ndisAdap->MapRegistersAllocated++;
+ }
+
+#endif
+
+ MadgePrint1("sys_alloc_dma_phys_buffer: allocating SHARED memory\n");
+
+ NdisMAllocateSharedMemory(
+ ndisAdap->UsedInISR.MiniportHandle,
+ (ULONG) buffer_byte_size,
+ FALSE,
+ &virt,
+ &phys
+ );
+
+ if (virt != NULL)
+ {
+ *buf_virt = (DWORD) virt;
+ *buf_phys = (DWORD) NdisGetPhysicalAddressLow(phys);
+ }
+
+ MadgePrint3(
+ "sys_alloc_dma_phys_buffer physical low = %lx high = %lx\n",
+ (DWORD) NdisGetPhysicalAddressLow(phys),
+ (DWORD) NdisGetPhysicalAddressHigh(phys)
+ );
+ }
+
+ else
+ {
+ MadgePrint1("sys_alloc_dma_phys_buffer: allocating NORMAL memory\n");
+
+ MADGE_ALLOC_MEMORY(&status, &virt, buffer_byte_size);
+
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ *buf_virt = (DWORD) virt;
+ }
+ else
+ {
+ virt = NULL;
+ }
+ }
+
+
+ MadgePrint2("sys_alloc_dma_phys_buffer virtual = %lx\n", (DWORD) virt);
+
+ return virt != NULL;
+}
+
+
+/***************************************************************************
+*
+* Function - sys_allocate_status_structure
+*
+* Parameter - adapter_handle -> FTK adapter handle.
+* status_structure_byte_size -> Size of the status structure.
+*
+* Purpose - Allocate an FTK status structure.
+*
+* Returns - A pointer to the structure on success or NULL on failure.
+*
+***************************************************************************/
+
+BYTE *
+sys_alloc_status_structure(
+ ADAPTER_HANDLE adapter_handle,
+ WORD status_structure_byte_size
+ );
+
+#pragma FTK_INIT_FUNCTION(sys_alloc_status_structure)
+
+BYTE *
+sys_alloc_status_structure(
+ ADAPTER_HANDLE adapter_handle,
+ WORD status_structure_byte_size
+ )
+{
+ PVOID ptr;
+ NDIS_STATUS status;
+
+ MADGE_ALLOC_MEMORY(&status, &ptr, (UINT) status_structure_byte_size);
+
+ return (status == NDIS_STATUS_SUCCESS)
+ ? (BYTE *) ptr
+ : NULL;
+
+}
+
+
+/***************************************************************************
+*
+* Function - sys_allocate_init_block
+*
+* Parameter - adapter_handle -> FTK adapter handle.
+* init_block_byte_size -> Size of the adapter structure.
+*
+* Purpose - Allocate an FTK initialisation block.
+*
+* Returns - A pointer to the block on success or NULL on failure.
+*
+***************************************************************************/
+
+BYTE *
+sys_alloc_init_block(
+ ADAPTER_HANDLE adapter_handle,
+ WORD init_block_byte_size
+ );
+
+#pragma FTK_INIT_FUNCTION(sys_alloc_init_block)
+
+BYTE *
+sys_alloc_init_block(
+ ADAPTER_HANDLE adapter_handle,
+ WORD init_block_byte_size
+ )
+{
+ PVOID ptr;
+ NDIS_STATUS status;
+
+ MADGE_ALLOC_MEMORY(&status, &ptr, (UINT) init_block_byte_size);
+
+ return (status == NDIS_STATUS_SUCCESS)
+ ? (BYTE *) ptr
+ : NULL;
+}
+
+
+/***************************************************************************
+*
+* Function - sys_free_adapter_structure
+*
+* Parameter - adapter_handle -> FTK adapter handle.
+* adapter_structure_addr -> Pointer to the adapter
+* structure.
+* adapter_structure_byte_size -> Size of the adapter structure.
+*
+* Purpose - Deallocate an FTK adapter structure.
+*
+* Returns - Nothing.
+*
+***************************************************************************/
+
+void
+sys_free_adapter_structure(
+ ADAPTER_HANDLE adapter_handle,
+ BYTE * adapter_structure_addr,
+ WORD adapter_structure_byte_size
+ )
+{
+ MADGE_FREE_MEMORY(
+ (PVOID) adapter_structure_addr,
+ (UINT) adapter_structure_byte_size
+ );
+}
+
+
+/***************************************************************************
+*
+* Function - sys_free_dma_phys_buffer
+*
+* Parameter - adapter_handle -> FTK adapter handle.
+* buffer_byte_size -> Size of the DMA buffer.
+* buf_phys -> The DMA buffer's physical address.
+* buf_virt -> The DMA buffer's virtual address.
+*
+* Purpose - Free a DMA buffer.
+*
+* Returns - Nothing.
+*
+***************************************************************************/
+
+void
+sys_free_dma_phys_buffer(
+ ADAPTER_HANDLE adapter_handle,
+ DWORD buffer_byte_size,
+ DWORD buf_phys,
+ DWORD buf_virt
+ )
+{
+ PMADGE_ADAPTER ndisAdap;
+ VOID * virt;
+ NDIS_PHYSICAL_ADDRESS phys;
+
+ ndisAdap = (PMADGE_ADAPTER) FTK_ADAPTER_USER_INFORMATION(adapter_handle);
+ virt = (VOID *) buf_virt;
+
+ //
+ // If we are in DMA mode then we must free shared memory, otherwise we
+ // must free ordinary memory.
+ //
+
+ if (ndisAdap->TransferMode == DMA_DATA_TRANSFER_MODE)
+ {
+ NdisSetPhysicalAddressHigh(phys, 0);
+ NdisSetPhysicalAddressLow(phys, buf_phys);
+
+ NdisMFreeSharedMemory(
+ ndisAdap->UsedInISR.MiniportHandle,
+ (ULONG) buffer_byte_size,
+ FALSE,
+ virt,
+ phys
+ );
+ }
+
+ else
+ {
+ MADGE_FREE_MEMORY(virt, buffer_byte_size);
+ }
+}
+
+/***************************************************************************
+*
+* Function - sys_free_status_structure
+*
+* Parameter - adapter_handle -> FTK adapter handle.
+* status_structure_addr -> Pointer to the status structure.
+* status_structure_byte_size -> Size of the status structure.
+*
+* Purpose - Deallocate an FTK status structure.
+*
+* Returns - Nothing.
+*
+***************************************************************************/
+
+export void
+sys_free_status_structure(
+ ADAPTER_HANDLE adapter_handle,
+ BYTE * status_structure_addr,
+ WORD status_structure_byte_size
+ )
+{
+ MADGE_FREE_MEMORY(
+ (PVOID) status_structure_addr,
+ (UINT) status_structure_byte_size
+ );
+}
+
+
+/***************************************************************************
+*
+* Function - sys_free_init_block
+*
+* Parameter - adapter_handle -> FTK adapter handle.
+* init_block_addr -> Pointer to the initialisation block.
+* init_block_byte_size -> Size of the initialisation block.
+*
+* Purpose - Deallocate an FTK initialisation block.
+*
+* Returns - Nothing.
+*
+***************************************************************************/
+
+export void
+sys_free_init_block(
+ ADAPTER_HANDLE adapter_handle,
+ BYTE * init_block_addr,
+ WORD init_block_byte_size
+ )
+{
+ MADGE_FREE_MEMORY(
+ (PVOID) init_block_addr,
+ (UINT) init_block_byte_size
+ );
+}
+
+
+/******** End of SYS_ALLO.C ***********************************************/
+
diff --git a/private/ntos/ndis/madge/driver/sys_dma.c b/private/ntos/ndis/madge/driver/sys_dma.c
new file mode 100644
index 000000000..42d5b5244
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/sys_dma.c
@@ -0,0 +1,233 @@
+/****************************************************************************
+*
+* SYS_DMA.C
+*
+* This module contains helper routines used by the FTK to initialise
+* DMA access to adapters.
+*
+* Copyright (c) Madge Networks Ltd 1991-1994
+*
+* COMPANY CONFIDENTIAL
+*
+* Created: MF
+* Major modifications: PBA 21/06/1994
+*
+****************************************************************************/
+
+#include <ndis.h>
+
+#include "ftk_defs.h"
+#include "ftk_extr.h"
+
+#include "ndismod.h"
+
+/*---------------------------------------------------------------------------
+|
+| DMA General Note
+| ----------------
+|
+| On an IBM compatible PC/AT machine, DMA is controlled by Programmable
+| DMA Controller 8237 chips. On AT machines there are two 8237 DMA
+| controllers. The primary controller handles DMA channels 0-3, the
+| secondary controller handles channels 4-7.
+|
+| The FTK is interested in three registers on each controller. These are
+| the mode register for setting the DMA mode for a given channel, the
+| mask register used for enabling/disabling a DMA channel, and the status
+| register for seeing what DMA channel requests have been generated.
+|
+---------------------------------------------------------------------------*/
+
+//
+// IO ports for status, mask and mode registers on primary DMA controller
+//
+
+#define DMA_STATUS_PRIMARY_8237 0x08
+#define DMA_MASK_PRIMARY_8237 0x0A
+#define DMA_MODE_PRIMARY_8237 0x0B
+
+//
+// IO ports for status, mask and mode registers on secondary DMA controller
+//
+
+#define DMA_STATUS_SECONDARY_8237 0x0D0
+#define DMA_MASK_SECONDARY_8237 0x0D4
+#define DMA_MODE_SECONDARY_8237 0x0D6
+
+//
+// Set cascade mode code (sent to mode register along with DMA channel)
+//
+
+#define DMA_CASCADE_MODE_8237 0x0C0
+
+//
+// Disable DMA channel code (sent to mask register along with DMA channel)
+//
+
+#define DMA_DISABLE_MASK_8237 0x04
+
+
+/****************************************************************************
+*
+* Function - sys_enable_dma_channel
+*
+* Parameters - adapter_handle -> FTK adapter handle.
+* dma_channel -> The DMA channel number.
+*
+* Purpose - Initialise a DMA channel.
+*
+* Returns - TRUE on success or FALSE on failure.
+*
+* Notes:
+*
+* With the NDIS3 driver the dma channel is enabled by the underlying
+* operating system. We pass information about our adapter in the
+* NDIS_ADAPTER_INFORMATION structure, including whether its a
+* BusMasterDma card --- by setting the AdapterInformation.Master flag
+* in MDGNT.c.
+*
+* So eventually this routine should be null and just return TRUE.
+*
+* Upto NT build 438, there is a problem with the AdapterInformation.Master
+* flag. Setting it does not enable the DMA channel on certain ISA/AT
+* platforms. Therefore the following code has been included such that we
+* explicitly enable the DMA channel.
+*
+* The DMA channel has been specified in the AdapterInformation structure
+* passed by the MAC driver to NdisRegisterAdapter()
+*
+****************************************************************************/
+
+WBOOLEAN
+sys_enable_dma_channel(ADAPTER_HANDLE adapter_handle, WORD dma_channel);
+
+#pragma FTK_INIT_FUNCTION(sys_enable_dma_channel)
+
+WBOOLEAN
+sys_enable_dma_channel(ADAPTER_HANDLE adapter_handle, WORD dma_channel)
+{
+#ifdef _M_IX86
+
+ if (dma_channel < 4)
+ {
+ //
+ // Program up primary 8237. Write local DMA channel with cascade
+ // mode to mode register. Write local DMA channel to mask register
+ // to enable it.
+ //
+
+ //
+ // (dma_channel + DMA_CASCADE_MODE_8237) -> DMA_MODE_PRIMARY_8237
+ //
+
+ sys_outsb(
+ adapter_handle,
+ (WORD) DMA_MODE_PRIMARY_8237,
+ (BYTE) (dma_channel + DMA_CASCADE_MODE_8237)
+ );
+
+ //
+ // (dma_channel) -> DMA_MASK_PRIMARY_8237
+ //
+
+ sys_outsb(
+ adapter_handle,
+ (WORD) DMA_MASK_PRIMARY_8237,
+ (BYTE) dma_channel
+ );
+
+ }
+ else
+ {
+ //
+ // Program up secondary 8237. Get local DMA channel by DMA-4.
+ // Write local DMA channel with cascade mode to mode register.
+ // Write local DMA channel to mask register to enable it.
+ //
+
+ dma_channel = dma_channel - 4;
+
+ //
+ // (dma_channel + DMA_CASCADE_MODE_8237) -> DMA_MODE_SECONDARY_8237
+ //
+
+ sys_outsb(
+ adapter_handle,
+ (WORD) DMA_MODE_SECONDARY_8237,
+ (BYTE)(dma_channel + DMA_CASCADE_MODE_8237)
+ );
+
+
+ //
+ // (dma_channel) -> DMA_MASK_SECONDARY_8237
+ //
+
+ sys_outsb(
+ adapter_handle,
+ (WORD) DMA_MASK_SECONDARY_8237,
+ (BYTE) dma_channel
+ );
+ }
+
+#endif
+
+ return TRUE;
+}
+
+
+/****************************************************************************
+*
+* Function - sys_disable_dma_channel
+*
+* Parameters - adapter_handle -> FTK adapter handle.
+* dma_channel -> The DMA channel number.
+*
+* Purpose - De-initialise a DMA channel.
+*
+* Returns - Nothing.
+*
+* Notes:
+*
+* Upto NT build 438, there is a problem with the AdapterInformation.Master
+* flag. Setting it does not enable the DMA channel on certain ISA/AT
+* platforms. Therefore the code in sys_enable_dma_channel() above, has been
+* included such that we explicitly enable the DMA channel.
+*
+* Eventually, the Operating system will do this for us. And will also disable
+* the DMA channel when the driver is unloaded.
+*
+* Therefore, I have not added code to explicitly disable DMA channel.
+*
+*
+* However, if we do not disable the channel certain ISA platforms hang
+* on shutdown. (pba 25/5/1994)
+*
+***************************************************************************/
+
+void
+sys_disable_dma_channel(ADAPTER_HANDLE adapter_handle, WORD dma_channel)
+{
+#ifdef _M_IX86
+
+ if (dma_channel < 4)
+ {
+ sys_outsb(
+ adapter_handle,
+ (WORD) DMA_MASK_PRIMARY_8237,
+ (BYTE) (DMA_DISABLE_MASK_8237 + dma_channel)
+ );
+ }
+ else
+ {
+ sys_outsb(
+ adapter_handle,
+ (WORD)DMA_MASK_SECONDARY_8237,
+ (BYTE)(DMA_DISABLE_MASK_8237 + (dma_channel - 4))
+ );
+ }
+
+#endif
+}
+
+
+/******** End of SYS_DMA.C *************************************************/
diff --git a/private/ntos/ndis/madge/driver/sys_irq.c b/private/ntos/ndis/madge/driver/sys_irq.c
new file mode 100644
index 000000000..a056ffab0
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/sys_irq.c
@@ -0,0 +1,119 @@
+/****************************************************************************
+*
+* SYS_IRQ.C
+*
+* FastMAC Plus based NDIS3 miniport driver. This module contains helper
+* routines used by the FTK to handle interrupts.
+*
+* Copyright (c) Madge Networks Ltd 1991-1994
+*
+* COMPANY CONFIDENTIAL
+*
+* Created: MF
+* Major modifications: PBA 21/06/1994
+*
+****************************************************************************/
+
+#include <ndis.h>
+
+#include "ftk_defs.h"
+#include "ftk_intr.h"
+#include "ftk_extr.h"
+
+#include "ndismod.h"
+
+
+/****************************************************************************
+*
+* Function - sys_enable_irq_channel
+*
+* Parameters - adapter_handle -> FTK adapter handle.
+* interrupt_number -> Interrupt number to enable (unused).
+*
+* Purpose - Register an IRQ with the NDIS3 wrapper so that
+* MadgeInterruptServiceRoutine() gets called on the
+* IRQ and MadgeDeferredProcessingRoutine() as the DPR.
+*
+* Returns - TRUE on success or FALSE on failure.
+*
+****************************************************************************/
+
+WBOOLEAN
+sys_enable_irq_channel(ADAPTER_HANDLE adapter_handle, WORD interrupt_number);
+
+#pragma FTK_INIT_FUNCTION(sys_enable_irq_channel)
+
+WBOOLEAN
+sys_enable_irq_channel(ADAPTER_HANDLE adapter_handle, WORD interrupt_number)
+{
+ PMADGE_ADAPTER ndisAdap;
+ NDIS_STATUS status;
+
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+
+ //
+ // Register with the NDIS3 wrapper.
+ //
+
+ status = NdisMRegisterInterrupt(
+ &ndisAdap->Interrupt,
+ ndisAdap->UsedInISR.MiniportHandle,
+ (UINT) ndisAdap->UsedInISR.InterruptNumber,
+ (UINT) ndisAdap->UsedInISR.InterruptNumber,
+ TRUE, // We want ISRs.
+ ndisAdap->UsedInISR.InterruptShared,
+ ndisAdap->UsedInISR.InterruptMode
+ );
+
+ //
+ // If it didn't work then write an entry to the event log.
+ //
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ NdisWriteErrorLogEntry(
+ ndisAdap->UsedInISR.MiniportHandle,
+ NDIS_ERROR_CODE_INTERRUPT_CONNECT,
+ 2,
+ inFtk,
+ MADGE_ERRMSG_INIT_INTERRUPT
+ );
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/****************************************************************************
+*
+* Function - sys_disable_irq_channel
+*
+* Parameters - adapter_handle -> FTK adapter handle.
+* interrupt_number -> Interrupt number to disable (unused).
+*
+* Purpose - De-register an IRQ with the NDIS3 wrapper.
+*
+* Returns - Nothing.
+*
+****************************************************************************/
+
+void
+sys_disable_irq_channel(ADAPTER_HANDLE adapter_handle, WORD interrupt_number)
+{
+ PMADGE_ADAPTER ndisAdap;
+
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+
+ //
+ // De-register with the NDIS3 wrapper.
+ //
+
+ NdisMDeregisterInterrupt(&ndisAdap->Interrupt);
+}
+
+
+
+/******** End of SYS_IRQ.C ************************************************/
+
diff --git a/private/ntos/ndis/madge/driver/sys_mem.c b/private/ntos/ndis/madge/driver/sys_mem.c
new file mode 100644
index 000000000..f72beb7bc
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/sys_mem.c
@@ -0,0 +1,925 @@
+/****************************************************************************
+*
+* SYS_MEM.C
+*
+* FastMAC Plus based NDIS3 miniport driver. This module contains helper
+* routines used by the FTK to perform I/O access to adapters.
+*
+* Copyright (c) Madge Networks Ltd 1991-1994
+*
+* COMPANY CONFIDENTIAL
+*
+* Created: MF
+* Major modifications: PBA 21/06/1994
+*
+****************************************************************************/
+
+#include <ndis.h>
+
+#include "ftk_defs.h"
+#include "ftk_extr.h"
+
+#include "ndismod.h"
+
+/*--------------------------------------------------------------------------
+|
+| Note: These I/O routines are more involved that I would have liked for
+| two reasons. We cannot use uncooked raw I/O routines because our
+| EISA adapters use two ranges of I/O locations which could have some
+| other device in between them. Also we cannot turn these functions into
+| macros because the FTK expects sys_ins{b|w} to return a value but the
+| Ndis take a pointer to a memory cell for the value read.
+|
+--------------------------------------------------------------------------*/
+
+/***************************************************************************
+*
+* Function - sys_insw
+*
+* Parameters - adapter_handle -> FTK adapter handle.
+* input_location -> I/O location to be read.
+*
+* Purpose - Read a word from an I/O location.
+*
+* Returns - The word read.
+*
+***************************************************************************/
+
+WORD
+sys_insw(
+ ADAPTER_HANDLE adapter_handle,
+ WORD input_location
+ )
+{
+ PMADGE_ADAPTER ndisAdap;
+ ULONG port;
+ WORD word_data;
+
+#ifdef _M_IX86
+
+ NdisRawReadPortUshort((ULONG) input_location, &word_data);
+
+#else
+
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+ port = ((UINT) input_location <= ndisAdap->IORange1End)
+ ? (ULONG) ndisAdap->MappedIOLocation1 +
+ ((UINT) input_location - ndisAdap->IoLocation1)
+ : (ULONG) ndisAdap->MappedIOLocation2 +
+ ((UINT) input_location - ndisAdap->IoLocation2);
+
+ NdisRawReadPortUshort(port, &word_data);
+
+#endif
+
+ return word_data;
+}
+
+
+/***************************************************************************
+*
+* Function - sys_insb
+*
+* Parameters - adapter_handle -> FTK adapter handle.
+* input_location -> I/O location to be read.
+*
+* Purpose - Read a byte from an I/O location.
+*
+* Returns - The byte read.
+*
+***************************************************************************/
+
+BYTE
+sys_insb(
+ ADAPTER_HANDLE adapter_handle,
+ WORD input_location
+ )
+{
+ PMADGE_ADAPTER ndisAdap;
+ ULONG port;
+ BYTE byte_data;
+
+#ifdef _M_IX86
+
+ NdisRawReadPortUchar((ULONG) input_location, &byte_data);
+
+#else
+
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+ port = ((UINT) input_location <= ndisAdap->IORange1End)
+ ? (ULONG) ndisAdap->MappedIOLocation1 +
+ ((UINT) input_location - ndisAdap->IoLocation1)
+ : (ULONG) ndisAdap->MappedIOLocation2 +
+ ((UINT) input_location - ndisAdap->IoLocation2);
+
+ NdisRawReadPortUchar(port, &byte_data);
+
+#endif
+
+ return byte_data;
+}
+
+
+/***************************************************************************
+*
+* Function - sys_outsw
+*
+* Parameters - adapter_handle -> FTK adapter handle.
+* output_location -> I/O location to be written.
+* output_word -> The word to be written.
+*
+* Purpose - Write a word to an I/O location.
+*
+* Returns - Nothing.
+*
+***************************************************************************/
+
+void
+sys_outsw(
+ ADAPTER_HANDLE adapter_handle,
+ WORD output_location,
+ WORD output_word
+ )
+{
+ PMADGE_ADAPTER ndisAdap;
+ ULONG port;
+
+#ifdef _M_IX86
+
+ NdisRawWritePortUshort((ULONG) output_location, output_word);
+
+#else
+
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+ port = ((UINT) output_location <= ndisAdap->IORange1End)
+ ? (ULONG) ndisAdap->MappedIOLocation1 +
+ ((UINT) output_location - ndisAdap->IoLocation1)
+ : (ULONG) ndisAdap->MappedIOLocation2 +
+ ((UINT) output_location - ndisAdap->IoLocation2);
+
+ NdisRawWritePortUshort(port, output_word);
+
+#endif
+}
+
+
+/***************************************************************************
+*
+* Function - sys_outsb
+*
+* Parameters - adapter_handle -> FTK adapter handle.
+* output_location -> I/O location to be written.
+* output_byte -> The byte to be written.
+*
+* Purpose - Write a byte to an I/O location.
+*
+* Returns - Nothing.
+*
+***************************************************************************/
+
+void
+sys_outsb(
+ ADAPTER_HANDLE adapter_handle,
+ WORD output_location,
+ BYTE output_byte
+ )
+{
+ PMADGE_ADAPTER ndisAdap;
+ ULONG port;
+
+#ifdef _M_IX86
+
+ NdisRawWritePortUchar((ULONG) output_location, output_byte);
+
+#else
+
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+ port = ((UINT) output_location <= ndisAdap->IORange1End)
+ ? (ULONG) ndisAdap->MappedIOLocation1 +
+ ((UINT) output_location - ndisAdap->IoLocation1)
+ : (ULONG) ndisAdap->MappedIOLocation2 +
+ ((UINT) output_location - ndisAdap->IoLocation2);
+
+ NdisRawWritePortUchar(port, output_byte);
+
+#endif
+}
+
+
+/***************************************************************************
+*
+* Function - sys_rep_insw
+*
+* Parameters - adapter_handle -> FTK adapter handle.
+* output_location -> I/O location to be read.
+* destination_address -> Destination for the data read.
+* length_in_words -> Number of words to read.
+*
+* Purpose - Read a number of words from an I/O location.
+*
+* Returns - Nothing.
+*
+***************************************************************************/
+
+void
+sys_rep_insw(
+ ADAPTER_HANDLE adapter_handle,
+ WORD input_location,
+ BYTE * destination_address,
+ WORD length_in_words
+ )
+{
+ PMADGE_ADAPTER ndisAdap;
+ ULONG port;
+
+#ifdef _M_IX86
+
+ NdisRawReadPortBufferUshort(
+ (ULONG) input_location,
+ (USHORT *) destination_address,
+ (ULONG) length_in_words
+ );
+
+#else
+
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+ port = ((UINT) input_location <= ndisAdap->IORange1End)
+ ? (ULONG) ndisAdap->MappedIOLocation1 +
+ ((UINT) input_location - ndisAdap->IoLocation1)
+ : (ULONG) ndisAdap->MappedIOLocation2 +
+ ((UINT) input_location - ndisAdap->IoLocation2);
+
+ NdisRawReadPortBufferUshort(
+ port,
+ (USHORT *) destination_address,
+ (ULONG) length_in_words
+ );
+
+#endif
+}
+
+
+/***************************************************************************
+*
+* Function - sys_rep_outsw
+*
+* Parameters - adapter_handle -> FTK adapter handle.
+* output_location -> I/O location to be written.
+* source_address -> Address of the data to be written.
+* length_in_words -> Number of words to read.
+*
+* Purpose - Write a number of words to an I/O location.
+*
+* Returns - Nothing.
+*
+***************************************************************************/
+
+void
+sys_rep_outsw(
+ ADAPTER_HANDLE adapter_handle,
+ WORD input_location,
+ BYTE * source_address,
+ WORD length_in_words
+ )
+{
+ PMADGE_ADAPTER ndisAdap;
+ ULONG port;
+
+#ifdef _M_IX86
+
+ NdisRawWritePortBufferUshort(
+ (ULONG) input_location,
+ (USHORT *) source_address,
+ (ULONG) length_in_words
+ );
+
+#else
+
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+ port = ((UINT) input_location <= ndisAdap->IORange1End)
+ ? (ULONG) ndisAdap->MappedIOLocation1 +
+ ((UINT) input_location - ndisAdap->IoLocation1)
+ : (ULONG) ndisAdap->MappedIOLocation2 +
+ ((UINT) input_location - ndisAdap->IoLocation2);
+
+ NdisRawWritePortBufferUshort(
+ port,
+ (USHORT *) source_address,
+ (ULONG) length_in_words
+ );
+
+#endif
+}
+
+
+/***************************************************************************
+*
+* Function - sys_rep_swap_insw
+*
+* Parameters - adapter_handle -> FTK adapter handle.
+* output_location -> I/O location to be read.
+* destination_address -> Destination for the data read.
+* length_in_words -> Number of words to read.
+*
+* Purpose - Read a number of byte swapped words from an I/O location.
+*
+* Returns - Nothing.
+*
+***************************************************************************/
+
+void
+sys_rep_swap_insw(
+ ADAPTER_HANDLE adapter_handle,
+ WORD input_location,
+ BYTE * destination_address,
+ WORD length_in_words
+ )
+{
+ PMADGE_ADAPTER ndisAdap;
+ ULONG port;
+ USHORT word_data;
+ WORD * ptr;
+
+ ptr = (WORD *) destination_address;
+
+#ifdef _M_IX86
+
+ while (length_in_words > 0)
+ {
+ NdisRawReadPortUshort((ULONG) input_location, &word_data);
+ *ptr = ((WORD) word_data << 8) | ((WORD) word_data >> 8);
+
+ ptr++;
+ length_in_words--;
+ }
+
+#else
+
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+ port = ((UINT) input_location <= ndisAdap->IORange1End)
+ ? (ULONG) ndisAdap->MappedIOLocation1 +
+ ((UINT) input_location - ndisAdap->IoLocation1)
+ : (ULONG) ndisAdap->MappedIOLocation2 +
+ ((UINT) input_location - ndisAdap->IoLocation2);
+
+ while (length_in_words > 0)
+ {
+ NdisRawReadPortUshort(port, &word_data);
+ *ptr = ((WORD) word_data << 8) | ((WORD) word_data >> 8);
+
+ ptr++;
+ length_in_words--;
+ }
+
+
+#endif
+}
+
+
+/***************************************************************************
+*
+* Function - sys_rep_swap_outsw
+*
+* Parameters - adapter_handle -> FTK adapter handle.
+* output_location -> I/O location to be written.
+* source_address -> Address of the data to be written.
+* length_in_words -> Number of words to read.
+*
+* Purpose - Write a number of byte swapped words to an I/O location.
+*
+* Returns - Nothing.
+*
+***************************************************************************/
+
+void
+sys_rep_swap_outsw(
+ ADAPTER_HANDLE adapter_handle,
+ WORD input_location,
+ BYTE * source_address,
+ WORD length_in_words
+ )
+{
+ PMADGE_ADAPTER ndisAdap;
+ ULONG port;
+ USHORT word_data;
+ WORD * ptr;
+
+ ptr = (WORD *) source_address;
+
+#ifdef _M_IX86
+
+ while (length_in_words > 0)
+ {
+ word_data = (USHORT) (*ptr << 8) | (*ptr >> 8);
+ NdisRawWritePortUshort((ULONG) input_location, word_data);
+
+ ptr++;
+ length_in_words--;
+ }
+
+#else
+
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+ port = ((UINT) input_location <= ndisAdap->IORange1End)
+ ? (ULONG) ndisAdap->MappedIOLocation1 +
+ ((UINT) input_location - ndisAdap->IoLocation1)
+ : (ULONG) ndisAdap->MappedIOLocation2 +
+ ((UINT) input_location - ndisAdap->IoLocation2);
+
+ while (length_in_words > 0)
+ {
+ word_data = (USHORT) (*ptr << 8) | (*ptr >> 8);
+ NdisRawWritePortUshort(port, word_data);
+
+ ptr++;
+ length_in_words--;
+ }
+
+#endif
+}
+
+
+/***************************************************************************
+*
+* Function - sys_rep_insd
+*
+* Parameters - adapter_handle -> FTK adapter handle.
+* output_location -> I/O location to be read.
+* destination_address -> Destination for the data read.
+* length_in_dwords -> Number of dwords to read.
+*
+* Purpose - Read a number of dwords from an I/O location.
+*
+* Returns - Nothing.
+*
+***************************************************************************/
+
+void
+sys_rep_insd(
+ ADAPTER_HANDLE adapter_handle,
+ WORD input_location,
+ BYTE * destination_address,
+ WORD length_in_dwords
+ )
+{
+ PMADGE_ADAPTER ndisAdap;
+ ULONG port;
+
+#ifdef _M_IX86
+
+ NdisRawReadPortBufferUlong(
+ (ULONG) input_location,
+ (USHORT *) destination_address,
+ (ULONG) length_in_dwords
+ );
+
+#else
+
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+ port = ((UINT) input_location <= ndisAdap->IORange1End)
+ ? (ULONG) ndisAdap->MappedIOLocation1 +
+ ((UINT) input_location - ndisAdap->IoLocation1)
+ : (ULONG) ndisAdap->MappedIOLocation2 +
+ ((UINT) input_location - ndisAdap->IoLocation2);
+
+ NdisRawReadPortBufferUlong(
+ port,
+ (ULONG *) destination_address,
+ (ULONG) length_in_dwords
+ );
+
+#endif
+}
+
+
+/***************************************************************************
+*
+* Function - sys_rep_outsd
+*
+* Parameters - adapter_handle -> FTK adapter handle.
+* output_location -> I/O location to be written.
+* source_address -> Address of the data to be written.
+* length_in_dwords -> Number of dwords to read.
+*
+* Purpose - Write a number of dwords to an I/O location.
+*
+* Returns - Nothing.
+*
+***************************************************************************/
+
+void
+sys_rep_outsd(
+ ADAPTER_HANDLE adapter_handle,
+ WORD input_location,
+ BYTE * source_address,
+ WORD length_in_dwords
+ )
+{
+ PMADGE_ADAPTER ndisAdap;
+ ULONG port;
+
+#ifdef _M_IX86
+
+ NdisRawWritePortBufferUlong(
+ (ULONG) input_location,
+ (USHORT *) source_address,
+ (ULONG) length_in_dwords
+ );
+
+#else
+
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+ port = ((UINT) input_location <= ndisAdap->IORange1End)
+ ? (ULONG) ndisAdap->MappedIOLocation1 +
+ ((UINT) input_location - ndisAdap->IoLocation1)
+ : (ULONG) ndisAdap->MappedIOLocation2 +
+ ((UINT) input_location - ndisAdap->IoLocation2);
+
+ NdisRawWritePortBufferUlong(
+ port,
+ (ULONG *) source_address,
+ (ULONG) length_in_dwords
+ );
+
+#endif
+}
+
+/***************************************************************************
+*
+* Function - sys_sync_with_interrupt
+*
+* Parameter - adapter_handle -> FTK adapter handle.
+* f -> Function to call.
+* ptr -> Argument for f.
+*
+* Purpose - Call a function in such as way that its execution will
+* never overlap with the ISR.
+*
+* Returns - The return value from *f.
+*
+***************************************************************************/
+
+WBOOLEAN
+sys_sync_with_interrupt(
+ ADAPTER_HANDLE adapter_handle,
+ WBOOLEAN (*f)(void *),
+ void * ptr
+ )
+{
+ PMADGE_ADAPTER ndisAdap;
+
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+
+ return NdisMSynchronizeWithInterrupt(
+ &ndisAdap->Interrupt,
+ (void *) f,
+ ptr
+ );
+}
+
+
+/***************************************************************************
+*
+* Function - sys_rep_movsd_to
+*
+* Parameter - adapter_handle -> FTK adapter handle.
+* SourcePtr -> Pointer to the source data.
+* DestPtr -> pointer to the destination.
+* TransferSize -> Number of bytes to transfer.
+*
+* Purpose - Transfer data to a memory mapped device. Although bytes
+* are given as the transfer size a whole number of
+* DWORDS are transferred.
+*
+* Returns - Nothing.
+*
+***************************************************************************/
+
+void
+sys_rep_movsd_to(
+ ADAPTER_HANDLE adapter_handle,
+ DWORD SourcePtr,
+ DWORD DestPtr,
+ WORD TransferSize
+ )
+{
+ NdisMoveToMappedMemory(
+ (VOID *) DestPtr,
+ (VOID *) SourcePtr,
+ (ULONG) TransferSize
+ );
+}
+
+
+/***************************************************************************
+*
+* Function - sys_rep_movsd_from
+*
+* Parameter - adapter_handle -> FTK adapter handle.
+* SourcePtr -> Pointer to the source data.
+* DestPtr -> pointer to the destination.
+* TransferSize -> Number of bytes to transfer.
+*
+* Purpose - Transfer data from a memory mapped device. Although bytes
+* are given as the transfer size a whole number of
+* DWORDS are transferred.
+*
+* Returns - Nothing.
+*
+***************************************************************************/
+
+void
+sys_rep_movsd_from(
+ ADAPTER_HANDLE adapter_handle,
+ DWORD SourcePtr,
+ DWORD DestPtr,
+ WORD TransferSize
+ )
+{
+ NdisMoveFromMappedMemory(
+ (VOID *) DestPtr,
+ (VOID *) SourcePtr,
+ (ULONG) TransferSize
+ );
+}
+
+
+/***************************************************************************
+*
+* Function - sys_movsd_to
+*
+* Parameter - adapter_handle -> FTK adapter handle.
+* SourcePtr -> Pointer to the source data.
+* DestPtr -> pointer to the destination.
+*
+* Purpose - Transfer a DWORD of data to a memory mapped device.
+*
+* Returns - Nothing.
+*
+***************************************************************************/
+
+void
+sys_movsd_to(
+ ADAPTER_HANDLE adapter_handle,
+ DWORD SourcePtr,
+ DWORD DestPtr
+ )
+{
+ *((DWORD *) DestPtr) = *((DWORD *) SourcePtr);
+}
+
+
+/***************************************************************************
+*
+* Function - sys_movsd_from
+*
+* Parameter - adapter_handle -> FTK adapter handle.
+* SourcePtr -> Pointer to the source data.
+* DestPtr -> pointer to the destination.
+*
+* Purpose - Transfer a DWORD of data from a memory mapped device.
+*
+* Returns - Nothing.
+*
+***************************************************************************/
+
+void
+sys_movsd_from(
+ ADAPTER_HANDLE adapter_handle,
+ DWORD SourcePtr,
+ DWORD DestPtr
+ )
+{
+ *((DWORD *) DestPtr) = *((DWORD *) SourcePtr);
+}
+
+
+/***************************************************************************
+*
+* Function - sys_pci_read_config_dword
+*
+* Parameter - adapter_handle -> FTK adapter handle.
+* index -> Offset into the configuration space from
+* which to read.
+* dword_ptr -> Buffer for the data read.
+*
+* Purpose - Read a DWORD from PCI configuration space.
+*
+* Returns - TRUE on success.
+*
+***************************************************************************/
+
+WBOOLEAN
+sys_pci_read_config_dword(
+ ADAPTER_HANDLE adapter_handle,
+ WORD index,
+ DWORD * dword_ptr
+ )
+{
+ PMADGE_ADAPTER ndisAdap;
+
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+
+ NdisReadPciSlotInformation(
+ ndisAdap->UsedInISR.MiniportHandle,
+ (ULONG) adapter_record[adapter_handle]->pci_handle,
+ index,
+ (void *) dword_ptr,
+ 4
+ );
+
+ return TRUE;
+}
+
+
+/***************************************************************************
+*
+* Function - sys_pci_read_config_word
+*
+* Parameter - adapter_handle -> FTK adapter handle.
+* index -> Offset into the configuration space from
+* which to read.
+* word_ptr -> Buffer for the data read.
+*
+* Purpose - Read a WORD from PCI configuration space.
+*
+* Returns - TRUE on success.
+*
+***************************************************************************/
+
+WBOOLEAN
+sys_pci_read_config_word(
+ ADAPTER_HANDLE adapter_handle,
+ WORD index,
+ WORD * word_ptr
+ )
+{
+ PMADGE_ADAPTER ndisAdap;
+
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+
+ NdisReadPciSlotInformation(
+ ndisAdap->UsedInISR.MiniportHandle,
+ (ULONG) adapter_record[adapter_handle]->pci_handle,
+ index,
+ (void *) word_ptr,
+ 2
+ );
+
+ return TRUE;
+}
+
+
+/***************************************************************************
+*
+* Function - sys_pci_read_config_byte
+*
+* Parameter - adapter_handle -> FTK adapter handle.
+* index -> Offset into the configuration space from
+* which to read.
+* byte_ptr -> Buffer for the data read.
+*
+* Purpose - Read a BYTE from PCI configuration space.
+*
+* Returns - TRUE on success.
+*
+***************************************************************************/
+
+WBOOLEAN
+sys_pci_read_config_byte(
+ ADAPTER_HANDLE adapter_handle,
+ WORD index,
+ BYTE * byte_ptr
+ )
+{
+ PMADGE_ADAPTER ndisAdap;
+
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+
+ NdisReadPciSlotInformation(
+ ndisAdap->UsedInISR.MiniportHandle,
+ (ULONG) adapter_record[adapter_handle]->pci_handle,
+ index,
+ (void *) byte_ptr,
+ 1
+ );
+
+ return TRUE;
+}
+
+
+/***************************************************************************
+*
+* Function - sys_pci_write_config_dword
+*
+* Parameter - adapter_handle -> FTK adapter handle.
+* index -> Offset into the configuration space to
+* which to write.
+* dword -> Data to write.
+*
+* Purpose - Write a DWORD to PCI configuration space.
+*
+* Returns - TRUE on success.
+*
+***************************************************************************/
+
+WBOOLEAN
+sys_pci_write_config_dword(
+ ADAPTER_HANDLE adapter_handle,
+ WORD index,
+ DWORD dword
+ )
+{
+ PMADGE_ADAPTER ndisAdap;
+
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+
+ NdisWritePciSlotInformation(
+ ndisAdap->UsedInISR.MiniportHandle,
+ (ULONG) adapter_record[adapter_handle]->pci_handle,
+ index,
+ (void *) &dword,
+ 4
+ );
+
+ return TRUE;
+}
+
+
+/***************************************************************************
+*
+* Function - sys_pci_write_config_word
+*
+* Parameter - adapter_handle -> FTK adapter handle.
+* index -> Offset into the configuration space to
+* which to write.
+* word -> Data to write.
+*
+* Purpose - Write a WORD to PCI configuration space.
+*
+* Returns - TRUE on success.
+*
+***************************************************************************/
+
+WBOOLEAN
+sys_pci_write_config_word(
+ ADAPTER_HANDLE adapter_handle,
+ WORD index,
+ WORD word
+ )
+{
+ PMADGE_ADAPTER ndisAdap;
+
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+
+ NdisWritePciSlotInformation(
+ ndisAdap->UsedInISR.MiniportHandle,
+ (ULONG) adapter_record[adapter_handle]->pci_handle,
+ index,
+ (void *) &word,
+ 2
+ );
+
+ return TRUE;
+}
+
+
+/***************************************************************************
+*
+* Function - sys_pci_write_config_byte
+*
+* Parameter - adapter_handle -> FTK adapter handle.
+* index -> Offset into the configuration space to
+* which to write.
+* byte -> Data to write.
+*
+* Purpose - Write a BYTE to PCI configuration space.
+*
+* Returns - TRUE on success.
+*
+***************************************************************************/
+
+WBOOLEAN
+sys_pci_write_config_byte(
+ ADAPTER_HANDLE adapter_handle,
+ WORD index,
+ BYTE byte
+ )
+{
+ PMADGE_ADAPTER ndisAdap;
+
+ ndisAdap = PMADGE_ADAPTER_FROM_ADAPTER_HANDLE(adapter_handle);
+
+ NdisWritePciSlotInformation(
+ ndisAdap->UsedInISR.MiniportHandle,
+ (ULONG) adapter_record[adapter_handle]->pci_handle,
+ index,
+ (void *) &byte,
+ 1
+ );
+
+ return TRUE;
+}
+
+/******** End of SYS_MEM.C ************************************************/
+
diff --git a/private/ntos/ndis/madge/driver/sys_time.c b/private/ntos/ndis/madge/driver/sys_time.c
new file mode 100644
index 000000000..6376c2d75
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/sys_time.c
@@ -0,0 +1,80 @@
+/****************************************************************************
+*
+* SYS_TIME.C
+*
+* This module contains helper routines used by the FTK to handle timers.
+*
+* Copyright (c) Madge Networks Ltd 1991-1994
+*
+* COMPANY CONFIDENTIAL
+*
+* Created: MF
+* Major modifications: PBA 21/06/1994
+*
+****************************************************************************/
+
+#include <ndis.h>
+
+#include "ftk_defs.h"
+#include "ftk_extr.h"
+
+#include "ndismod.h"
+
+
+/***************************************************************************
+*
+* Function - sys_wait_for_at_least_milliseconds
+*
+* Parameters - number_of_milliseconds -> Number of milliseconds for which
+* to wait.
+*
+* Purpose - Wait for at least a given number of milliseconds.
+*
+* Returns - Nothing.
+*
+***************************************************************************/
+
+void
+sys_wait_at_least_milliseconds(WORD number_of_milliseconds)
+{
+ DWORD number_of_microseconds;
+
+ //
+ // Note: During a call to NdisStallExecution(), all other system
+ // activity is stopped. For this reason stalls of more than 10 ms
+ // are strongly discouraged.
+ //
+
+ number_of_microseconds = (DWORD) number_of_milliseconds * 1000;
+
+ NdisStallExecution((UINT) number_of_microseconds);
+}
+
+
+/***************************************************************************
+*
+* Function - sys_wait_for_at_least_microseconds
+*
+* Parameters - number_of_microseconds -> number of microseconds for which
+* to wait.
+*
+* Purpose - Wait for at least a given number of milliseconds.
+*
+* Returns - Nothing.
+*
+***************************************************************************/
+
+void
+sys_wait_at_least_microseconds(WORD number_of_microseconds)
+{
+ //
+ // Note: During a call to NdisStallExecution(), all other system
+ // activity is stopped. For this reason stalls of more than 10 ms
+ // are strongly discouraged.
+ //
+
+ NdisStallExecution((UINT) number_of_microseconds);
+}
+
+/******** End of SYS_TIME.C ***********************************************/
+
diff --git a/private/ntos/ndis/madge/driver/util.c b/private/ntos/ndis/madge/driver/util.c
new file mode 100644
index 000000000..ef458cad4
--- /dev/null
+++ b/private/ntos/ndis/madge/driver/util.c
@@ -0,0 +1,252 @@
+/****************************************************************************
+*
+* UTIL.C : Part of the FASTMAC TOOL-KIT (FTK)
+*
+* THE UTILITIES MODULE
+*
+* Copyright (c) Madge Networks Ltd. 1991-1994
+*
+* COMPANY CONFIDENTIAL
+*
+*****************************************************************************
+*
+* The UTIL.C utilities module provides a range of general purpose
+* utilities that are used throughout the FTK. These routines provide such
+* functions as the ability to copy strings, clear memory, byte swap node
+* addresses and caculate the minimum of three values.
+*
+****************************************************************************/
+
+/*---------------------------------------------------------------------------
+|
+| DEFINITIONS
+|
+---------------------------------------------------------------------------*/
+
+#include "ftk_defs.h"
+
+/*---------------------------------------------------------------------------
+|
+| MODULE ENTRY POINTS
+|
+---------------------------------------------------------------------------*/
+
+#include "ftk_intr.h" /* routines internal to FTK */
+#include "ftk_extr.h" /* routines provided or used by external FTK user */
+
+/****************************************************************************
+*
+* util_string_copy
+* ================
+*
+* The util_string_copy routine copies a null terminated string from source
+* to destination.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(util_string_copy)
+#endif
+
+export void
+util_string_copy(
+ char * copy_to_string,
+ char * copy_from_string
+ )
+{
+
+ while (*copy_from_string != '\0')
+ {
+ *copy_to_string++ = *copy_from_string++;
+ }
+
+ *copy_to_string = '\0';
+
+ return;
+}
+
+
+/****************************************************************************
+*
+* util_mem_copy
+* =============
+*
+* The util_mem_copy routine copies max_copy_len bytes from the source
+* address to the destination address (both are virtual addresses).
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(util_mem_copy)
+#endif
+
+export void
+util_mem_copy(
+ BYTE * copy_to_mem,
+ BYTE * copy_from_mem,
+ UINT max_copy_len
+ )
+{
+ while (max_copy_len > 0)
+ {
+ *copy_to_mem = *copy_from_mem;
+
+ copy_to_mem++;
+ copy_from_mem++;
+ max_copy_len--;
+ }
+}
+
+
+/****************************************************************************
+*
+* util_string_concatenate
+* =======================
+*
+* The util_string_concatenate routine adds one null terminated string onto
+* the end of another, creating a new null terminated string.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(util_string_concatenate)
+#endif
+
+export void
+util_string_concatenate(
+ char * add_to_string,
+ char * string_to_add
+ )
+{
+
+ while (*add_to_string != '\0')
+ {
+ add_to_string++;
+ }
+
+ while (*string_to_add != '\0')
+ {
+ *add_to_string++ = *string_to_add++;
+ }
+
+ *add_to_string = '\0';
+
+ return;
+}
+
+
+/****************************************************************************
+*
+* util_minimum
+* ============
+*
+* The util_minimum routine returns the minimum of three values that are
+* passed to it.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(util_minimum)
+#endif
+
+export UINT
+util_minimum(
+ UINT val_1,
+ UINT val_2,
+ UINT val_3
+ )
+{
+ if (val_1 > val_2)
+ {
+ if (val_2 > val_3)
+ {
+ return val_3;
+ }
+ else
+ {
+ return val_2;
+ }
+ }
+ else
+ {
+ if (val_1 > val_3)
+ {
+ return val_3;
+ }
+ else
+ {
+ return val_1;
+ }
+ }
+}
+
+
+/****************************************************************************
+*
+* util_zero_memory
+* ================
+*
+* The util_zero_memory routine clears an area of memory of a given size in
+* bytes.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(util_zero_memory)
+#endif
+
+export void
+util_zero_memory(
+ BYTE * memory,
+ UINT size_in_bytes
+ )
+{
+ while (size_in_bytes--)
+ {
+ *memory++ = 0;
+ }
+
+ return;
+}
+
+
+/****************************************************************************
+*
+* util_byte_swap_structure
+* ========================
+*
+* The util_byte_swap_structure routine swaps adjacent bytes in a structure
+* so that it can be correctly downloaded onto an adapter card. It is used
+* for byte swapping a node address, a multicast address and a product id
+* string.
+*
+****************************************************************************/
+
+#ifdef FTK_RES_FUNCTION
+#pragma FTK_RES_FUNCTION(util_byte_swap_structure)
+#endif
+
+export void
+util_byte_swap_structure(
+ BYTE * byte_based_structure,
+ UINT size_of_structure
+ )
+{
+ UINT i;
+ BYTE temp;
+
+ for ( i = 0; i < size_of_structure; i = i+2)
+ {
+ temp = *byte_based_structure;
+ *byte_based_structure = *(byte_based_structure + 1);
+ *(byte_based_structure + 1) = temp;
+ byte_based_structure += 2;
+ }
+
+ return;
+}
+
+
+/******** End of UTIL.C ****************************************************/
+
+
diff --git a/private/ntos/ndis/ndis30/afilter.c b/private/ntos/ndis/ndis30/afilter.c
new file mode 100644
index 000000000..9d50eedc9
--- /dev/null
+++ b/private/ntos/ndis/ndis30/afilter.c
@@ -0,0 +1,2083 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ afilter.c
+
+Abstract:
+
+ This module implements a set of library routines to handle packet
+ filtering for NDIS MAC drivers. It also provides routines for collecting fragmented packets and
+ breaking up a packet into fragmented packets
+
+Author:
+
+ Alireza Dabagh 3-22-1993, (partially borrowed from EFILTER.C)
+
+
+Revision History:
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+#if DBG
+UINT AfilterDebugFlag = 0;
+#endif
+
+//
+// This constant is used for places where NdisAllocateMemory
+// needs to be called and the HighestAcceptableAddress does
+// not matter.
+//
+
+static const NDIS_PHYSICAL_ADDRESS HighestAcceptableMax =
+ NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
+
+//
+// A set of macros to manipulate bitmasks.
+//
+
+//VOID
+//CLEAR_BIT_IN_MASK(
+// IN UINT Offset,
+// IN OUT PMASK MaskToClear
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Clear a bit in the bitmask pointed to by the parameter.
+//
+//Arguments:
+//
+// Offset - The offset (from 0) of the bit to altered.
+//
+// MaskToClear - Pointer to the mask to be adjusted.
+//
+//Return Value:
+//
+// None.
+//
+//--*/
+//
+#define CLEAR_BIT_IN_MASK(Offset,MaskToClear) *MaskToClear &= (~(1 << Offset))
+
+//VOID
+//SET_BIT_IN_MASK(
+// IN UINT Offset,
+// IN OUT PMASK MaskToSet
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Set a bit in the bitmask pointed to by the parameter.
+//
+//Arguments:
+//
+// Offset - The offset (from 0) of the bit to altered.
+//
+// MaskToSet - Pointer to the mask to be adjusted.
+//
+//Return Value:
+//
+// None.
+//
+//--*/
+#define SET_BIT_IN_MASK(Offset,MaskToSet) *MaskToSet |= (1 << Offset)
+
+//BOOLEAN
+//IS_BIT_SET_IN_MASK(
+// IN UINT Offset,
+// IN MASK MaskToTest
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Tests if a particular bit in the bitmask pointed to by the parameter is
+// set.
+//
+//Arguments:
+//
+// Offset - The offset (from 0) of the bit to test.
+//
+// MaskToTest - The mask to be tested.
+//
+//Return Value:
+//
+// Returns TRUE if the bit is set.
+//
+//--*/
+#define IS_BIT_SET_IN_MASK(Offset,MaskToTest) \
+((MaskToTest & (1 << Offset))?(TRUE):(FALSE))
+
+//BOOLEAN
+//IS_MASK_CLEAR(
+// IN MASK MaskToTest
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Tests whether there are *any* bits enabled in the mask.
+//
+//Arguments:
+//
+// MaskToTest - The bit mask to test for all clear.
+//
+//Return Value:
+//
+// Will return TRUE if no bits are set in the mask.
+//
+//--*/
+#define IS_MASK_CLEAR(MaskToTest) ((!MaskToTest)?(TRUE):(FALSE))
+
+//VOID
+//CLEAR_MASK(
+// IN OUT PMASK MaskToClear
+// );
+//
+///*++
+//
+//Routine Description:
+//
+// Clears a mask.
+//
+//Arguments:
+//
+// MaskToClear - The bit mask to adjust.
+//
+//Return Value:
+//
+// None.
+//
+//--*/
+#define CLEAR_MASK(MaskToClear) *MaskToClear = 0
+
+//
+// VOID
+// ARC_FILTER_ALLOC_OPEN(
+// IN PETH_FILTER Filter,
+// OUT PUINT FilterIndex
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Allocates an open block. This only allocate the index, not memory for
+// the open block.
+//
+//Arguments:
+//
+// Filter - DB from which to allocate the space
+//
+// FilterIndex - pointer to place to store the index.
+//
+//Return Value:
+//
+// FilterIndex of the new open
+//
+//--*/
+#define ARC_FILTER_ALLOC_OPEN(Filter, FilterIndex)\
+{\
+ UINT i; \
+ for (i=0; i < ARC_FILTER_MAX_OPENS; i++) { \
+ if (IS_BIT_SET_IN_MASK(i,(Filter)->FreeBindingMask)) { \
+ *(FilterIndex) = i; \
+ CLEAR_BIT_IN_MASK(i, &((Filter)->FreeBindingMask)); \
+ break; \
+ } \
+ } \
+}
+
+//
+// VOID
+// ARC_FILTER_FREE_OPEN(
+// IN PETH_FILTER Filter,
+// IN PARC_BINDING_INFO LocalOpen
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Frees an open block. Also frees the memory associated with the open.
+//
+//Arguments:
+//
+// Filter - DB from which to allocate the space
+//
+// FilterIndex - Index to free
+//
+//Return Value:
+//
+// FilterIndex of the new open
+//
+//--*/
+#define ARC_FILTER_FREE_OPEN(Filter, LocalOpen)\
+{\
+ SET_BIT_IN_MASK(((LocalOpen)->FilterIndex), &((Filter)->FreeBindingMask)); \
+ NdisFreeMemory((LocalOpen), sizeof(ARC_BINDING_INFO), 0);\
+}
+
+
+
+NDIS_SPIN_LOCK ArcReferenceLock = {0};
+KEVENT ArcPagedInEvent = {0};
+ULONG ArcReferenceCount = 0;
+PVOID ArcImageHandle = {0};
+
+VOID
+ArcInitializePackage(VOID)
+{
+ NdisAllocateSpinLock(&ArcReferenceLock);
+ KeInitializeEvent(
+ &ArcPagedInEvent,
+ NotificationEvent,
+ FALSE
+ );
+}
+
+VOID
+ArcReferencePackage(VOID)
+{
+ ACQUIRE_SPIN_LOCK(&ArcReferenceLock);
+
+ ArcReferenceCount++;
+
+ if (ArcReferenceCount == 1) {
+
+ KeResetEvent(
+ &ArcPagedInEvent
+ );
+
+ RELEASE_SPIN_LOCK(&ArcReferenceLock);
+
+ //
+ // Page in all the functions
+ //
+ ArcImageHandle = MmLockPagableCodeSection(ArcCreateFilter);
+
+ //
+ // Signal to everyone to go
+ //
+ KeSetEvent(
+ &ArcPagedInEvent,
+ 0L,
+ FALSE
+ );
+
+ } else {
+
+ RELEASE_SPIN_LOCK(&ArcReferenceLock);
+
+ //
+ // Wait for everything to be paged in
+ //
+ KeWaitForSingleObject(
+ &ArcPagedInEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ NULL
+ );
+
+ }
+
+}
+
+VOID
+ArcDereferencePackage(VOID)
+{
+ ACQUIRE_SPIN_LOCK(&ArcReferenceLock);
+
+ ArcReferenceCount--;
+
+ if (ArcReferenceCount == 0) {
+
+ RELEASE_SPIN_LOCK(&ArcReferenceLock);
+
+ //
+ // Page out all the functions
+ //
+ MmUnlockPagableImageSection(ArcImageHandle);
+
+ } else {
+
+ RELEASE_SPIN_LOCK(&ArcReferenceLock);
+
+ }
+
+}
+
+
+//
+// Defines for resource growth
+//
+#define ARC_BUFFER_SIZE 1024
+#define ARC_BUFFER_ALLOCATION_UNIT 8
+#define ARC_PACKET_ALLOCATION_UNIT 2
+
+
+//
+// Forward declarations
+//
+NDIS_STATUS
+ArcAllocateBuffers(
+ IN PARC_FILTER Filter
+ );
+
+NDIS_STATUS
+ArcAllocatePackets(
+ IN PARC_FILTER Filter
+ );
+
+VOID
+ArcDiscardPacketBuffers(
+ IN PARC_FILTER Filter,
+ IN PARC_PACKET Packet
+ );
+
+VOID
+ArcDestroyPacket(
+ IN PARC_FILTER Filter,
+ IN PARC_PACKET Packet
+ );
+
+BOOLEAN
+ArcConvertToNdisPacket(
+ IN PARC_FILTER Filter,
+ IN PARC_PACKET Packet,
+ IN BOOLEAN ConvertWholePacket
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGENDSA, ArcFilterTransferData)
+#pragma alloc_text(PAGENDSA, ArcFilterDprIndicateReceiveComplete)
+#pragma alloc_text(PAGENDSA, ArcFilterDoIndication)
+#pragma alloc_text(PAGENDSA, ArcFilterAdjust)
+#pragma alloc_text(PAGENDSA, ArcDeleteFilterOpenAdapter)
+#pragma alloc_text(PAGENDSA, ArcNoteFilterOpenAdapter)
+#pragma alloc_text(PAGENDSA, ArcCreateFilter)
+#pragma alloc_text(PAGENDSA, ArcFilterDprIndicateReceive)
+#pragma alloc_text(PAGENDSA, ArcConvertToNdisPacket)
+#pragma alloc_text(PAGENDSA, ArcDestroyPacket)
+#pragma alloc_text(PAGENDSA, ArcFreeNdisPacket)
+#pragma alloc_text(PAGENDSA, ArcDiscardPacketBuffers)
+#pragma alloc_text(PAGENDSA, ArcAllocatePackets)
+#pragma alloc_text(PAGENDSA, ArcAllocateBuffers)
+#pragma alloc_text(PAGENDSA, ArcConvertOidListToEthernet)
+#endif
+
+
+
+NDIS_STATUS
+ArcAllocateBuffers(
+ IN PARC_FILTER Filter
+ )
+/*++
+
+Routine Description:
+
+ This routine allocates Receive buffers for the filter database.
+
+Arguments:
+
+ Filter - The filter db to allocate for.
+
+Returns:
+
+ NDIS_STATUS_SUCCESS if any buffer was allocated.
+
+--*/
+{
+ ULONG i;
+ PARC_BUFFER_LIST Buffer;
+ PVOID DataBuffer;
+
+ for (i = ARC_BUFFER_ALLOCATION_UNIT; i != 0 ; i--) {
+
+ NdisAllocateMemory((PVOID)&Buffer,
+ sizeof(ARC_BUFFER_LIST),
+ 0,
+ HighestAcceptableMax
+ );
+
+ if (Buffer == NULL) {
+
+ if (i == ARC_BUFFER_ALLOCATION_UNIT) {
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+ NdisAllocateMemory((PVOID)&DataBuffer,
+ ARC_BUFFER_SIZE,
+ 0,
+ HighestAcceptableMax
+ );
+
+ if (DataBuffer == NULL) {
+
+ NdisFreeMemory(Buffer, sizeof(ARC_BUFFER_LIST), 0);
+
+ if (i == ARC_BUFFER_ALLOCATION_UNIT) {
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // We allocated some packets, that is good enough for now
+ //
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+ Buffer->BytesLeft = Buffer->Size = ARC_BUFFER_SIZE;
+ Buffer->Buffer = DataBuffer;
+ Buffer->Next = Filter->FreeBufferList;
+ Filter->FreeBufferList = Buffer;
+
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+
+}
+
+
+NDIS_STATUS
+ArcAllocatePackets(
+ IN PARC_FILTER Filter
+ )
+/*++
+
+Routine Description:
+
+ This routine allocates Receive packets for the filter database.
+
+Arguments:
+
+ Filter - The filter db to allocate for.
+
+Returns:
+
+ NDIS_STATUS_SUCCESS if any packet was allocated.
+
+--*/
+{
+ ULONG i;
+ PARC_PACKET Packet;
+
+ for (i = ARC_PACKET_ALLOCATION_UNIT; i != 0 ; i--) {
+
+ NdisAllocateMemory((PVOID)&Packet,
+ sizeof(ARC_PACKET),
+ 0,
+ HighestAcceptableMax
+ );
+
+ if (Packet == NULL) {
+
+ if (i == ARC_BUFFER_ALLOCATION_UNIT) {
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+ NdisZeroMemory(Packet, sizeof(ARC_PACKET));
+
+ NdisReinitializePacket(&(Packet->TmpNdisPacket));
+
+ Packet->Next = Filter->FreePackets;
+ Filter->FreePackets = Packet;
+
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+VOID
+ArcDiscardPacketBuffers(
+ IN PARC_FILTER Filter,
+ IN PARC_PACKET Packet
+ )
+/*++
+
+Routine description:
+
+ This routine takes an arcnet packet that contains buffers of data and
+ puts the buffers on the free list.
+
+ NOTE: This assumes that LastBuffer points to the real last buffer
+ in the chain.
+
+Arguments:
+
+ Filter - The filter to free the buffers to.
+
+ Packet - The packet to free up.
+
+Return values:
+
+ None
+
+--*/
+{
+ PARC_BUFFER_LIST Buffer;
+
+ //
+ // Reset Packet info
+ //
+ Packet->LastFrame = FALSE;
+ Packet->TotalLength = 0;
+
+ //
+ // Reset buffer sizes
+ //
+ Buffer = Packet->FirstBuffer;
+ while (Buffer != NULL) {
+ Buffer->BytesLeft = Buffer->Size;
+ Buffer = Buffer->Next;
+ }
+
+ //
+ // Put buffers on free list
+ //
+ if (Packet->LastBuffer != NULL) {
+
+ Packet->LastBuffer->Next = Filter->FreeBufferList;
+ Filter->FreeBufferList = Packet->FirstBuffer;
+ Packet->FirstBuffer = Packet->LastBuffer = NULL;
+
+ }
+
+}
+
+
+VOID
+ArcFreeNdisPacket(
+ IN PARC_PACKET Packet
+ )
+/*++
+
+Routine description:
+
+ This routine takes an arcnet packet and frees up the corresponding
+ Ndis packet built for it.
+
+Arguments:
+
+ Packet - The packet to free up.
+
+Return values:
+
+ None
+
+--*/
+{
+ PNDIS_BUFFER NdisBuffer, NextNdisBuffer;
+
+ NdisQueryPacket(
+ &(Packet->TmpNdisPacket),
+ NULL,
+ NULL,
+ &NdisBuffer,
+ NULL
+ );
+
+ while (NdisBuffer != NULL) {
+
+ NdisGetNextBuffer(
+ NdisBuffer,
+ &NextNdisBuffer
+ );
+
+ NdisFreeBuffer(
+ NdisBuffer
+ );
+
+ NdisBuffer = NextNdisBuffer;
+ }
+
+ NdisReinitializePacket(&(Packet->TmpNdisPacket));
+
+}
+
+
+VOID
+ArcDestroyPacket(
+ IN PARC_FILTER Filter,
+ IN PARC_PACKET Packet
+ )
+/*++
+
+Routine description:
+
+ This routine takes an arcnet packet and frees up the entire packet.
+
+Arguments:
+
+ Filter - Filter to free to.
+
+ Packet - The packet to free up.
+
+Return values:
+
+ None
+
+--*/
+{
+ ArcFreeNdisPacket(Packet);
+ ArcDiscardPacketBuffers(Filter, Packet);
+
+ //
+ // Now put packet on free list
+ //
+ Packet->Next = Filter->FreePackets;
+ Filter->FreePackets = Packet;
+}
+
+
+BOOLEAN
+ArcConvertToNdisPacket(
+ IN PARC_FILTER Filter,
+ IN PARC_PACKET Packet,
+ IN BOOLEAN ConvertWholePacket
+ )
+/*++
+
+Routine description:
+
+ This routine builds a corresponding NDIS_PACKET in TmpNdisPacket,
+ that corresponds to the arcnet packet. The flag ConvertWholePacket
+ is used to convert only part of the arcnet packet, or the whole
+ stream. If the flag is FALSE, then only the buffers that have
+ free space (starting with buffer LastBuffer on up) are converted.
+
+ NOTE: It assumes TmpNdisPacket is an initialized ndis_packet structure.
+
+Arguments:
+
+ Filter - Filter to allocate from.
+
+ Packet - The packet to convert.
+
+ ConvertWholePacket - Convert the whole stream, or only part?
+
+Return values:
+
+ TRUE - If successful, else FALSE
+
+--*/
+{
+ PNDIS_BUFFER NdisBuffer;
+ PARC_BUFFER_LIST Buffer;
+ NDIS_STATUS NdisStatus;
+
+ Buffer = Packet->FirstBuffer;
+
+ while (Buffer != NULL) {
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ Filter->ReceiveBufferPool,
+ Buffer->Buffer,
+ Buffer->Size - Buffer->BytesLeft
+ );
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ return(FALSE);
+
+ }
+
+ NdisChainBufferAtBack(
+ &(Packet->TmpNdisPacket),
+ NdisBuffer
+ );
+
+ Buffer = Buffer->Next;
+
+ }
+
+ return(TRUE);
+}
+
+
+VOID
+ArcFilterDprIndicateReceive(
+ IN PARC_FILTER Filter, // Pointer to filter database
+ IN PUCHAR pRawHeader, // Pointer to Arcnet frame header
+ IN PUCHAR pData, // Pointer to data portion of Arcnet frame
+ IN UINT Length // Data Length
+ )
+{
+ ARC_PACKET_HEADER NewFrameInfo;
+ PARC_PACKET Packet, PrevPacket;
+ BOOLEAN FrameOk, NewFrame, LastFrame;
+ PARC_BUFFER_LIST Buffer;
+ UCHAR TmpUchar;
+ UINT TmpLength;
+ UINT TotalLength = Length;
+ PUCHAR OrigpData = pData;
+ USHORT TmpUshort;
+
+ //
+ // Check for ethernet encapsulation first
+ //
+
+ NdisReadRegisterUchar(pData, &TmpUchar);
+
+ if ( TmpUchar == 0xE8 ) {
+
+ //
+ // Yes! Indicate it to the wrapper for indicating to all
+ // protocols running ethernet on top of the arcnet miniport
+ // driver.
+ //
+
+ NdisMArcIndicateEthEncapsulatedReceive(
+ Filter->Miniport, // miniport.
+ pRawHeader, // 878.2 header.
+ pData + 1, // ethernet header.
+ Length - 1 // length of ethernet frame.
+ );
+
+ //
+ // We're done.
+ //
+
+ return;
+ }
+
+ //
+ // Get information from packet
+ //
+
+ NdisReadRegisterUchar(pRawHeader,
+ &(NewFrameInfo.ProtHeader.SourceId[0])
+ );
+
+ NdisReadRegisterUchar(pRawHeader + 1,
+ &(NewFrameInfo.ProtHeader.DestId[0])
+ );
+
+ NewFrameInfo.ProtHeader.ProtId = TmpUchar;
+
+ //
+ // Read the split flag. If this is an exception packet (i.e.
+ // TmpUChar == 0xFF then we need to add an extra 3 onto
+ // pData to skip the series of 0xFF 0xFF 0xFF.
+ //
+
+ pData++; //... Skip the SC byte.
+
+ NdisReadRegisterUchar(pData, &TmpUchar); //... Read split flag.
+
+ if ( TmpUchar == 0xFF ) {
+
+ pData += 4;
+ Length -= 4;
+
+ //
+ // Re-read the split flag.
+ //
+
+ NdisReadRegisterUchar(pData, &TmpUchar);
+ }
+
+ //
+ // Save off the split flag.
+ //
+
+ NewFrameInfo.SplitFlag = TmpUchar;
+
+ //
+ // Read the sequence number, which follows the split flag.
+ //
+
+ NdisReadRegisterUchar(pData + 1, &TmpUshort);
+ NdisReadRegisterUchar(pData + 2, &TmpUchar);
+ TmpUshort = TmpUshort | (TmpUchar << 8);
+ NewFrameInfo.FrameSequence = TmpUshort;
+
+ //
+ // Point pData at protocol data.
+ //
+
+ pData += 3; //... Beginning of protocol data.
+ Length -= 4; //... Length of protocol data.
+
+ //
+ // NOTE: Length is now the Length of the data portion of this packet
+ //
+
+#if DBG
+ if ( AfilterDebugFlag ){
+
+ DbgPrint("ArcFilter: Frame received: SourceId= %#1x\nDestId=%#1x\nProtId=%#1x\nSplitFlag=%#1x\nFrameSeq=%d\n",
+ (USHORT)NewFrameInfo.ProtHeader.SourceId[0],
+ (USHORT)NewFrameInfo.ProtHeader.DestId[0],
+ (USHORT)NewFrameInfo.ProtHeader.ProtId,
+ (USHORT)NewFrameInfo.SplitFlag,
+ NewFrameInfo.FrameSequence
+ );
+ DbgPrint("ArcFilter: Data at address: %lx, Length = %ld\n", pData, Length);
+
+ }
+#endif
+
+ FrameOk = TRUE;
+ NewFrame = TRUE;
+ LastFrame = TRUE;
+
+ PrevPacket = NULL;
+ Packet = Filter->OutstandingPackets;
+
+ //
+ // Walk throgh all outstanding packet to see if this frame belongs to any one of them
+ //
+
+ while ( Packet != NULL ) {
+
+ if (Packet->Header.ProtHeader.SourceId[0] == NewFrameInfo.ProtHeader.SourceId[0]){
+
+ //
+ // A packet received from the same source, check packet Sequence number and throw away
+ // outstanding packet if they don't match. We are allowed to do this since we know
+ // all the frames belonging to one packet are sent before starting a new packet. We
+ // HAVE to do this, because this is how we find out that a send at the other end, was aborted
+ // after some of the frames were already sent and received here.
+ //
+
+ if(Packet->Header.FrameSequence == NewFrameInfo.FrameSequence &&
+ Packet->Header.ProtHeader.DestId[0] == NewFrameInfo.ProtHeader.DestId[0] &&
+ Packet->Header.ProtHeader.ProtId == NewFrameInfo.ProtHeader.ProtId){
+
+ //
+ // We found a packet that this frame belongs to, check split flag
+ //
+ if (Packet->Header.FramesReceived * 2 == NewFrameInfo.SplitFlag){
+
+ //
+ // A packet found for this frame and SplitFlag is OK, check to see if it is
+ // the last frame of the packet
+ //
+ NewFrame = FALSE;
+ LastFrame = (BOOLEAN)(NewFrameInfo.SplitFlag == Packet->Header.LastSplitFlag);
+
+ } else {
+
+ //
+ // compare current split flag with the one from the last frame, if not equal
+ // the whole packet should be dropped.
+ //
+
+ if (Packet->Header.SplitFlag != NewFrameInfo.SplitFlag){
+
+ //
+ // Corrupted incomplete packet, get rid of it, but keep the new frame
+ // and we will re-use this Packet pointer.
+ //
+ ArcDiscardPacketBuffers(Filter, Packet);
+ break;
+
+ } else {
+
+ //
+ // We see to have received a duplicate frame. Ignore it.
+ //
+ return;
+
+ }
+
+ }
+
+ } else {
+
+ //
+ // We received a frame from a source that already has an incomplete packet outstanding
+ // But Frame Seq. or DestId or ProtId are not the same.
+ // We have to discard the old packet and check the new frame for validity,
+ // we will re-use this packet pointer below.
+ //
+ ArcDiscardPacketBuffers(Filter, Packet);
+
+ }
+
+ break;
+
+ } else {
+
+ PrevPacket = Packet;
+ Packet = Packet->Next;
+
+ }
+
+ }
+
+
+ if (NewFrame) {
+
+ //
+ // first frame of a packet, split flag must be odd or zero
+ // NewFrame is already TRUE
+ // LastFrame is already TRUE
+ //
+ if (NewFrameInfo.SplitFlag) {
+
+ if (!(NewFrameInfo.SplitFlag & 0x01)) {
+
+ //
+ // This frame is the middle of another split, but we
+ // don't have it on file. Drop the frame.
+ //
+ return;
+
+ }
+
+ //
+ // First Frame of a multiple frame packet
+ //
+ NewFrameInfo.LastSplitFlag = NewFrameInfo.SplitFlag + 1;
+ NewFrameInfo.FramesReceived = 1;
+ LastFrame = FALSE; // New packet and SplitFlag not zero
+
+ } else {
+
+ //
+ // The frame is fully contained in this packet.
+ //
+ }
+
+ //
+ // allocate a new packet descriptor if it is a new packet
+ //
+ if (Packet == NULL) {
+
+ if (Filter->FreePackets == NULL) {
+
+ ArcAllocatePackets(Filter);
+
+ if (Filter->FreePackets == NULL) {
+
+ return;
+
+ }
+
+ }
+
+ Packet = Filter->FreePackets;
+ Filter->FreePackets = Packet->Next;
+
+ if (!LastFrame) {
+
+ //
+ // Insert the packet in list of outstanding packets
+ //
+ Packet->Next = Filter->OutstandingPackets;
+ Filter->OutstandingPackets = Packet;
+
+ }
+
+ } else {
+
+ if (LastFrame) {
+
+ //
+ // remove it from the list
+ //
+ if (PrevPacket == NULL) {
+
+ Filter->OutstandingPackets = Packet->Next;
+
+ } else {
+
+ PrevPacket->Next = Packet->Next;
+
+ }
+
+ }
+
+ }
+
+ Packet->Header = NewFrameInfo;
+
+ } else {
+
+ if (LastFrame) {
+
+ //
+ // Remove it from the queue
+ //
+
+ if (PrevPacket == NULL) {
+
+ Filter->OutstandingPackets = Packet->Next;
+
+ } else {
+
+ PrevPacket->Next = Packet->Next;
+
+ }
+
+ }
+
+ Packet->Header.FramesReceived++;
+
+ //
+ // keep track of last split flag to detect duplicate frames
+ //
+ Packet->Header.SplitFlag=NewFrameInfo.SplitFlag;
+
+ }
+
+ //
+ // At this point we know Packet points to the packet to receive
+ // the buffer into. If this is the LastFrame, then Packet will
+ // have been removed from the OutstandingPackets list, otw it will
+ // be in the list.
+ //
+ // Now get around to getting space for the buffer.
+ //
+
+ //
+ // Find the last buffer in the packet
+ //
+ Buffer = Packet->LastBuffer;
+
+ if (Buffer == NULL) {
+
+ //
+ // Allocate a new buffer to hold the packet
+ //
+ if (Filter->FreeBufferList == NULL) {
+
+ if (ArcAllocateBuffers(Filter) != NDIS_STATUS_SUCCESS) {
+
+ ArcDiscardPacketBuffers(Filter,Packet);
+ //
+ // Do not have to discard any packet that may have
+ // been allocated above, as it will get discarded
+ // the next time a packet comes in from that source.
+ //
+ return;
+
+ }
+
+ }
+
+ Buffer = Filter->FreeBufferList;
+ Filter->FreeBufferList = Buffer->Next;
+
+ Packet->FirstBuffer = Packet->LastBuffer = Buffer;
+ Buffer->Next = NULL;
+
+ }
+
+ // Copy the data off into the ARC_PACKET list.
+ // If it doesn't fit within the current buffer, we'll need to
+ // allocate more
+
+ TmpLength = Length;
+
+ while ( Buffer->BytesLeft < TmpLength ) {
+
+ //
+ // Copy the data
+ //
+
+ NdisMoveFromMappedMemory(
+ (PUCHAR) Buffer->Buffer + (Buffer->Size - Buffer->BytesLeft),
+ pData,
+ Buffer->BytesLeft
+ );
+
+ pData += Buffer->BytesLeft;
+ TmpLength -= Buffer->BytesLeft;
+ Buffer->BytesLeft = 0;
+
+ //
+ // Need to allocate more
+ //
+ if (Filter->FreeBufferList == NULL) {
+
+ if (ArcAllocateBuffers(Filter) != NDIS_STATUS_SUCCESS) {
+
+ ArcDiscardPacketBuffers(Filter,Packet);
+ //
+ // Do not have to discard any packet that may have
+ // been allocated above, as it will get discarded
+ // the next time a packet comes in from that source.
+ //
+ return;
+
+ }
+
+ }
+
+ Buffer->Next = Filter->FreeBufferList;
+ Filter->FreeBufferList = Filter->FreeBufferList->Next;
+ Buffer = Buffer->Next;
+ Buffer->Next = NULL;
+
+ Packet->LastBuffer->Next = Buffer;
+ Packet->LastBuffer = Buffer;
+ }
+
+ //
+ // Copy the last bit
+ //
+
+ NdisMoveFromMappedMemory(
+ (PUCHAR) Buffer->Buffer + (Buffer->Size - Buffer->BytesLeft),
+ pData,
+ TmpLength
+ );
+
+
+ Buffer->BytesLeft -= TmpLength;
+ Packet->TotalLength += Length;
+
+ //
+ // And now we can start indicating the packet to the bindings that want it
+ //
+
+ if (LastFrame){
+
+ ArcFilterDoIndication(
+ Filter,
+ Packet
+ );
+
+ ArcDestroyPacket(Filter, Packet);
+
+ }
+
+}
+
+
+
+BOOLEAN
+ArcCreateFilter(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN ARC_FILTER_CHANGE FilterChangeAction,
+ IN ARC_DEFERRED_CLOSE CloseAction,
+ UCHAR AdapterAddress,
+ IN PNDIS_SPIN_LOCK Lock,
+ OUT PARC_FILTER *Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to create and initialize the Arcnet filter database.
+
+Arguments:
+
+ Miniport - Pointer to the mini-port object.
+
+ ChangeAction - Action routine to call when a binding sets or clears
+ a particular filter class and it is the first or only binding using
+ the filter class.
+
+ CloseAction - This routine is called if a binding closes while
+ it is being indicated to via NdisIndicateReceive. It will be
+ called upon return from NdisIndicateReceive.
+
+ AdapterAddress - the address of the adapter associated with this filter
+ database.
+
+ Lock - Pointer to the lock that should be held when mutual exclusion
+ is required.
+
+ Filter - A pointer to an ARC_FILTER. This is what is allocated and
+ created by this routine.
+
+Return Value:
+
+ If the function returns false then one of the parameters exceeded
+ what the filter was willing to support.
+
+--*/
+
+{
+
+ PARC_FILTER LocalFilter;
+ NDIS_STATUS AllocStatus;
+
+ //
+ // Allocate the database and it's associated arrays.
+ //
+
+ AllocStatus = NdisAllocateMemory(&LocalFilter, sizeof(ARC_FILTER), 0, HighestAcceptableMax);
+ *Filter = LocalFilter;
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+ return FALSE;
+ }
+
+ NdisZeroMemory(
+ LocalFilter,
+ sizeof(ARC_FILTER)
+ );
+
+ LocalFilter->Miniport = Miniport;
+ LocalFilter->FreeBindingMask = (ULONG)(-1);
+ LocalFilter->OpenList = NULL;
+ LocalFilter->AdapterAddress = AdapterAddress ;
+ LocalFilter->Lock = Lock;
+ LocalFilter->FilterChangeAction = FilterChangeAction;
+ LocalFilter->CloseAction = CloseAction;
+
+ NdisAllocateBufferPool(
+ &AllocStatus,
+ (PNDIS_HANDLE)(&LocalFilter->ReceiveBufferPool),
+ ARC_RECEIVE_BUFFERS
+ );
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+
+ NdisFreeMemory(LocalFilter, sizeof(ARC_FILTER), 0);
+ return(FALSE);
+ }
+
+ ArcReferencePackage();
+
+ return TRUE;
+
+}
+
+//
+// NOTE: THIS CANNOT BE PAGEABLE
+//
+VOID
+ArcDeleteFilter(
+ IN PARC_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to delete the memory associated with a filter
+ database. Note that this routines *ASSUMES* that the database
+ has been cleared of any active filters.
+
+Arguments:
+
+ Filter - A pointer to an ARC_FILTER to be deleted.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PARC_PACKET Packet;
+ PARC_BUFFER_LIST Buffer;
+
+ ASSERT(Filter->FreeBindingMask == (MASK)-1);
+ ASSERT(Filter->OpenList == NULL);
+
+
+ NdisFreeBufferPool(Filter->ReceiveBufferPool);
+
+ //
+ // Free all ARC_PACKETS
+ //
+
+ while (Filter->OutstandingPackets != NULL) {
+
+ Packet = Filter->OutstandingPackets;
+ Filter->OutstandingPackets = Packet->Next;
+
+ //
+ // This puts all the component parts on the free lists.
+ //
+ ArcDestroyPacket(Filter, Packet);
+
+ }
+
+ while (Filter->FreePackets != NULL) {
+
+ Packet = Filter->FreePackets;
+ Filter->FreePackets = Packet->Next;
+
+ ExFreePool(Packet);
+
+ }
+
+ while (Filter->FreeBufferList) {
+
+ Buffer = Filter->FreeBufferList;
+ Filter->FreeBufferList = Buffer->Next;
+
+ ExFreePool(Buffer->Buffer);
+ ExFreePool(Buffer);
+
+ }
+
+ NdisFreeMemory(Filter, sizeof(ARC_FILTER), 0);
+
+ ArcDereferencePackage();
+
+}
+
+
+BOOLEAN
+ArcNoteFilterOpenAdapter(
+ IN PARC_FILTER Filter,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE NdisBindingContext,
+ OUT PNDIS_HANDLE NdisFilterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to add a new binding to the filter database.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE DATABASE IS LOCKED WHEN
+ IT IS CALLED.
+
+Arguments:
+
+ Filter - A pointer to the previously created and initialized filter
+ database.
+
+ MacBindingHandle - The MAC supplied value to the protocol in response
+ to a call to NdisOpenAdapter.
+
+ NdisBindingContext - An NDIS supplied value to the call to NdisOpenAdapter.
+
+ NdisFilterHandle - A pointer to this open.
+
+Return Value:
+
+ Will return false if creating a new filter index will cause the maximum
+ number of filter indexes to be exceeded.
+
+--*/
+
+{
+
+ //
+ // Will hold the value of the filter index so that we
+ // need not indirectly address through pointer parameter.
+ //
+ UINT LocalIndex;
+
+ NDIS_STATUS AllocStatus;
+
+ //
+ // Pointer to new open block.
+ //
+ PARC_BINDING_INFO LocalOpen;
+
+
+ //
+ // Get the first free binding slot and remove that slot from
+ // the free list. We check to see if the list is empty.
+ //
+
+
+ if (Filter->FreeBindingMask == 0) {
+
+ return FALSE;
+
+ }
+
+ AllocStatus = NdisAllocateMemory(
+ &LocalOpen,
+ sizeof(ARC_BINDING_INFO),
+ 0,
+ HighestAcceptableMax
+ );
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Get place for the open and insert it.
+ //
+
+ ARC_FILTER_ALLOC_OPEN(Filter, &LocalIndex);
+
+ LocalOpen->NextOpen = Filter->OpenList;
+
+ if (Filter->OpenList != NULL) {
+ Filter->OpenList->PrevOpen = LocalOpen;
+ }
+
+ LocalOpen->PrevOpen = NULL;
+
+ Filter->OpenList = LocalOpen;
+
+ LocalOpen->FilterIndex = (UCHAR)LocalIndex;
+ LocalOpen->References = 1;
+ LocalOpen->MacBindingHandle = MacBindingHandle;
+ LocalOpen->NdisBindingContext = NdisBindingContext;
+ LocalOpen->PacketFilters = 0;
+ LocalOpen->ReceivedAPacket = FALSE;
+
+ *NdisFilterHandle = (NDIS_HANDLE)LocalOpen;
+
+ return TRUE;
+
+}
+
+
+NDIS_STATUS
+ArcDeleteFilterOpenAdapter(
+ IN PARC_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ When an adapter is being closed this routine should
+ be called to delete knowledge of the adapter from
+ the filter database. This routine is likely to call
+ action routines associated with clearing filter classes
+ and addresses.
+
+ NOTE: THIS ROUTINE SHOULD ****NOT**** BE CALLED IF THE ACTION
+ ROUTINES FOR DELETING THE FILTER CLASSES OR THE MULTICAST ADDRESSES
+ HAVE ANY POSSIBILITY OF RETURNING A STATUS OTHER THAN NDIS_STATUS_PENDING
+ OR NDIS_STATUS_SUCCESS. WHILE THESE ROUTINES WILL NOT BUGCHECK IF
+ SUCH A THING IS DONE, THE CALLER WILL PROBABLY FIND IT DIFFICULT
+ TO CODE A CLOSE ROUTINE!
+
+ NOTE: THIS ROUTINE ASSUMES THAT IT IS CALLED WITH THE LOCK HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routines,
+ this will be passed to it.
+
+Return Value:
+
+ If action routines are called by the various address and filtering
+ routines the this routine will likely return the status returned
+ by those routines. The exception to this rule is noted below.
+
+ Given that the filter and address deletion routines return a status
+ NDIS_STATUS_PENDING or NDIS_STATUS_SUCCESS this routine will then
+ try to return the filter index to the freelist. If the routine
+ detects that this binding is currently being indicated to via
+ NdisIndicateReceive, this routine will return a status of
+ NDIS_STATUS_CLOSING_INDICATING.
+
+--*/
+
+{
+
+ //
+ // Holds the status returned from the packet filter and address
+ // deletion routines. Will be used to return the status to
+ // the caller of this routine.
+ //
+ NDIS_STATUS StatusToReturn;
+
+ //
+ // Local variable.
+ //
+ PARC_BINDING_INFO LocalOpen = (PARC_BINDING_INFO)NdisFilterHandle;
+
+ StatusToReturn = ArcFilterAdjust(
+ Filter,
+ NdisFilterHandle,
+ NdisRequest,
+ (UINT)0,
+ FALSE
+ );
+
+ if ((StatusToReturn == NDIS_STATUS_SUCCESS) ||
+ (StatusToReturn == NDIS_STATUS_PENDING)) {
+
+ //
+ // Remove the reference from the original open.
+ //
+
+ if (--(LocalOpen->References) == 0) {
+
+ //
+ // Remove it from the list.
+ //
+
+ if (LocalOpen->NextOpen != NULL) {
+
+ LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen;
+
+ }
+
+ if (LocalOpen->PrevOpen != NULL) {
+
+ LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen;
+
+ } else {
+
+ Filter->OpenList = LocalOpen->NextOpen;
+
+ }
+
+
+ //
+ // First we finish any NdisIndicateReceiveComplete that
+ // may be needed for this binding.
+ //
+
+ if (LocalOpen->ReceivedAPacket) {
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ }
+ ARC_FILTER_FREE_OPEN(Filter, LocalOpen);
+
+ } else {
+
+ //
+ // Let the caller know that there is a reference to the open
+ // by the receive indication. The close action routine will be
+ // called upon return from NdisIndicateReceive.
+ //
+
+ StatusToReturn = NDIS_STATUS_CLOSING_INDICATING;
+
+ }
+
+ }
+
+ return StatusToReturn;
+
+}
+
+
+NDIS_STATUS
+ArcFilterAdjust(
+ IN PARC_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT FilterClasses,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ The FilterAdjust routine will call an action routine when a
+ particular filter class is changes from not being used by any
+ binding to being used by at least one binding or vice versa.
+
+ If the action routine returns a value other than pending or
+ success then this routine has no effect on the packet filters
+ for the open or for the adapter as a whole.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - A pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routine,
+ this will be passed to it.
+
+ FilterClasses - The filter classes that are to be added or
+ deleted.
+
+ Set - A boolean that determines whether the filter classes
+ are being adjusted due to a set or because of a close. (The filtering
+ routines don't care, the MAC might.)
+
+Return Value:
+
+ If it calls the action routine then it will return the
+ status returned by the action routine. If the status
+ returned by the action routine is anything other than
+ NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
+ will be returned to the state it was in upon entrance to this
+ routine.
+
+ If the action routine is not called this routine will return
+ the following statum:
+
+ NDIS_STATUS_SUCCESS - If the new packet filters doesn't change
+ the combined mask of all bindings packet filters.
+
+--*/
+
+{
+ //
+ // Contains the value of the combined filter classes before
+ // it is adjusted.
+ //
+ UINT OldCombined = Filter->CombinedPacketFilter;
+
+ PARC_BINDING_INFO LocalOpen = (PARC_BINDING_INFO)NdisFilterHandle;
+ PARC_BINDING_INFO OpenList;
+
+ //
+ // Contains the value of the particlar opens packet filters
+ // prior to the change. We save this incase the action
+ // routine (if called) returns an "error" status.
+ //
+ UINT OldOpenFilters = LocalOpen->PacketFilters;
+
+ //
+ // Holds the status returned to the user of this routine, if the
+ // action routine is not called then the status will be success,
+ // otherwise, it is whatever the action routine returns.
+ //
+ NDIS_STATUS StatusOfAdjust;
+
+ //
+ // Set the new filter information for the open.
+ //
+
+ LocalOpen->PacketFilters = FilterClasses;
+
+ //
+ // We always have to reform the compbined filter since
+ // this filter index may have been the only filter index
+ // to use a particular bit.
+ //
+
+
+ for (
+ OpenList = Filter->OpenList,
+ Filter->CombinedPacketFilter = 0;
+ OpenList != NULL;
+ OpenList = OpenList->NextOpen
+ ) {
+
+ Filter->CombinedPacketFilter |=
+ OpenList->PacketFilters;
+
+ }
+
+ if (OldCombined != Filter->CombinedPacketFilter) {
+
+ StatusOfAdjust = Filter->FilterChangeAction(
+ OldCombined,
+ Filter->CombinedPacketFilter,
+ LocalOpen->MacBindingHandle,
+ NdisRequest,
+ Set
+ );
+
+ if ((StatusOfAdjust != NDIS_STATUS_SUCCESS) &&
+ (StatusOfAdjust != NDIS_STATUS_PENDING)) {
+
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+
+ LocalOpen->PacketFilters = OldOpenFilters;
+ Filter->CombinedPacketFilter = OldCombined;
+
+ }
+
+ } else {
+
+ StatusOfAdjust = NDIS_STATUS_SUCCESS;
+
+ }
+
+ return StatusOfAdjust;
+
+}
+
+
+VOID
+ArcFilterDoIndication(
+ IN PARC_FILTER Filter,
+ IN PARC_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the filter package only to indicate
+ that a packet is ready to be indicated to procotols.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ Packet - Packet to indicate.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Will hold the type of address that we know we've got.
+ //
+ UINT AddressType;
+
+ NDIS_STATUS StatusOfReceive;
+
+ //
+ // Will hold the filter classes of the binding being indicated.
+ //
+ UINT BindingFilters;
+
+ //
+ // Current Open to indicate to.
+ //
+ PARC_BINDING_INFO LocalOpen;
+
+ if (Packet->Header.ProtHeader.DestId[0] != 0x00) {
+ AddressType = NDIS_PACKET_TYPE_DIRECTED;
+ } else {
+ AddressType = NDIS_PACKET_TYPE_BROADCAST;
+ }
+
+ //
+ // We need to acquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+
+ LocalOpen = Filter->OpenList;
+
+ if (!ArcConvertToNdisPacket(Filter, Packet, TRUE)) {
+
+ //
+ // Out of resources, abort.
+ //
+ return;
+
+ }
+
+ while (LocalOpen != NULL) {
+
+ //
+ // Reference the open during indication.
+ //
+
+ BindingFilters = LocalOpen->PacketFilters;
+
+ if (BindingFilters & AddressType){
+
+ LocalOpen->References++;
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ //
+ // Indicate the packet to the binding.
+ //
+ FilterIndicateReceive(
+ &StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ &Packet->TmpNdisPacket,
+ &(Packet->Header.ProtHeader),
+ 3,
+ Packet->FirstBuffer->Buffer,
+ Packet->FirstBuffer->Size - Packet->FirstBuffer->BytesLeft,
+ Packet->TotalLength
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ if ((--(LocalOpen->References)) == 0) {
+
+ PARC_BINDING_INFO NextOpen = LocalOpen->NextOpen;
+
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+
+ //
+ // Remove it from the list.
+ //
+
+ if (LocalOpen->NextOpen != NULL) {
+
+ LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen;
+
+ }
+
+ if (LocalOpen->PrevOpen != NULL) {
+
+ LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen;
+
+ } else {
+
+ Filter->OpenList = LocalOpen->NextOpen;
+
+ }
+
+
+
+ //
+ // Call the IndicateComplete routine.
+ //
+
+
+ if (LocalOpen->ReceivedAPacket) {
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ }
+
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+
+ Filter->CloseAction(LocalOpen->MacBindingHandle);
+
+
+ ARC_FILTER_FREE_OPEN(Filter, LocalOpen);
+
+ LocalOpen = NextOpen;
+
+ continue;
+
+ } // end of if binding is shutting down
+
+ } // end of if any binding wants the packet
+
+ LocalOpen = LocalOpen->NextOpen;
+
+ } // end of there are more open bindings
+
+}
+
+
+VOID
+ArcFilterDprIndicateReceiveComplete(
+ IN PARC_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by to indicate that the receive
+ process is complete to all bindings. Only those bindings which
+ have received packets will be notified.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PARC_BINDING_INFO LocalOpen;
+
+ //
+ // We need to acquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+
+ LocalOpen = Filter->OpenList;
+
+ while (LocalOpen != NULL) {
+
+ if (LocalOpen->ReceivedAPacket) {
+
+ //
+ // Indicate the binding.
+ //
+
+ LocalOpen->ReceivedAPacket = FALSE;
+
+ LocalOpen->References++;
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ if ((--(LocalOpen->References)) == 0) {
+
+ PARC_BINDING_INFO NextOpen = LocalOpen->NextOpen;
+
+ //
+ // This binding is shutting down. We have to kill it.
+ //
+
+ //
+ // Remove it from the list.
+ //
+
+ if (LocalOpen->NextOpen != NULL) {
+
+ LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen;
+
+ }
+
+ if (LocalOpen->PrevOpen != NULL) {
+
+ LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen;
+
+ } else {
+
+ Filter->OpenList = LocalOpen->NextOpen;
+
+ }
+
+
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+
+ Filter->CloseAction(LocalOpen->MacBindingHandle);
+
+
+ ARC_FILTER_FREE_OPEN(Filter, LocalOpen);
+
+ LocalOpen = NextOpen;
+
+ continue;
+
+ }
+
+ }
+
+ LocalOpen = LocalOpen->NextOpen;
+
+ }
+
+}
+
+
+NDIS_STATUS ArcConvertOidListToEthernet(
+ IN PNDIS_OID pOidList,
+ IN PULONG pcOidList,
+ IN PNDIS_OID pTmpBuffer
+)
+
+/*++
+
+Routine Description:
+
+ This routine converts an arcnet supported OID list into
+ an ethernet OID list by replacing or removing arcnet
+ OID's.
+
+Arguments:
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG c;
+ ULONG cArcOids;
+ ULONG cMaxOids;
+ NDIS_OID EthernetOidList[ARC_NUMBER_OF_EXTRA_OIDS] = {
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE
+ };
+
+ //
+ // Now we need to copy the returned results into the callers buffer,
+ // removing arcnet OID's and adding in ethernet OID's. At this point
+ // we do not know if the callers buffer is big enough since we may
+ // remove some entries, checking it up front may not yield correct
+ // results (i.e. it may actually be big enough).
+ //
+ for (c = 0, cArcOids = 0; c < *pcOidList; c++)
+ {
+ switch (pOidList[c])
+ {
+ case OID_ARCNET_PERMANENT_ADDRESS:
+ pTmpBuffer[cArcOids++] = OID_802_3_PERMANENT_ADDRESS;
+ break;
+
+ case OID_ARCNET_CURRENT_ADDRESS:
+ pTmpBuffer[cArcOids++] = OID_802_3_CURRENT_ADDRESS;
+ break;
+
+ case OID_ARCNET_RECONFIGURATIONS:
+ break;
+
+ default:
+ if ((pOidList[c] & 0xFFF00000) != 0x06000000)
+ pTmpBuffer[cArcOids++] = pOidList[c];
+
+ break;
+ }
+ }
+
+ //
+ // Copy the ARCnet OIDs from the temp buffer to the
+ // callers buffer.
+ //
+ RtlCopyMemory(pOidList, pTmpBuffer, cArcOids * sizeof(NDIS_OID));
+
+ //
+ // Add the ethernet OIDs.
+ //
+ RtlCopyMemory(
+ (PUCHAR)pOidList + (cArcOids * sizeof(NDIS_OID)),
+ EthernetOidList,
+ ARC_NUMBER_OF_EXTRA_OIDS * sizeof(NDIS_OID)
+ );
+
+ //
+ // Update the size of the buffer to send back to the caller.
+ //
+ *pcOidList = cArcOids + ARC_NUMBER_OF_EXTRA_OIDS;
+
+ return(NDIS_STATUS_SUCCESS);
+}
diff --git a/private/ntos/ndis/ndis30/afilter.h b/private/ntos/ndis/ndis30/afilter.h
new file mode 100644
index 000000000..1bfa9e97f
--- /dev/null
+++ b/private/ntos/ndis/ndis30/afilter.h
@@ -0,0 +1,339 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ afilter.h
+
+Abstract:
+
+ Header file for the address filtering library for NDIS MAC's.
+
+Author:
+
+ Alireza Dabagh creation-date 3-22-1993, mostly borrowed from efilter.h
+
+Revision History:
+
+--*/
+
+#ifndef _ARC_FILTER_DEFS_
+#define _ARC_FILTER_DEFS_
+
+//
+// Number of Ndis buffers in the buffer pool
+//
+#define ARC_RECEIVE_BUFFERS 64
+
+//
+// Linked list Structure for keeping track of allocated memory so we can free them later
+//
+typedef struct _ARC_BUFFER_LIST{
+ PVOID Buffer;
+ UINT Size;
+ UINT BytesLeft;
+ struct _ARC_BUFFER_LIST *Next;
+} ARC_BUFFER_LIST, *PARC_BUFFER_LIST;
+
+//
+// This is the structure that is passed to the protocol as the packet
+// header during receive indication. It is also the header expected from the protocol.
+// This header is NOT the same as the header passed to the mac driver
+//
+
+#define ARCNET_ADDRESS_LEN 1
+
+typedef struct _ARC_PROTOCOL_HEADER {
+ UCHAR SourceId[ARCNET_ADDRESS_LEN]; // Source Address
+ UCHAR DestId[ARCNET_ADDRESS_LEN]; // Destination Address
+ UCHAR ProtId; // Protocol ID
+} ARC_PROTOCOL_HEADER, *PARC_PROTOCOL_HEADER;
+
+//
+// This structure keeps track of information about a received packet
+//
+typedef struct _ARC_PACKET_HEADER {
+ ARC_PROTOCOL_HEADER ProtHeader; // Protocol header
+ USHORT FrameSequence; // Frame sequence Number
+ UCHAR SplitFlag; // Split flag
+ UCHAR LastSplitFlag; // Split Flag for the last frame
+ UCHAR FramesReceived; // Frames in This Packet
+} ARC_PACKET_HEADER, * PARC_PACKET_HEADER;
+
+//
+// Arcnet specific packet header
+//
+typedef struct _ARC_PACKET {
+ ARC_PACKET_HEADER Header; // Information about the packet
+ struct _ARC_PACKET * Next; // Next packet in use by filter
+ ULONG TotalLength;
+ BOOLEAN LastFrame;
+ PARC_BUFFER_LIST FirstBuffer;
+ PARC_BUFFER_LIST LastBuffer;
+ NDIS_PACKET TmpNdisPacket;
+} ARC_PACKET, * PARC_PACKET;
+
+
+#define ARC_PROTOCOL_HEADER_SIZE (sizeof(ARC_PROTOCOL_HEADER))
+#define ARC_MAX_FRAME_SIZE 504
+#define ARC_MAX_ADDRESS_IDS 256
+#define ARC_MAX_FRAME_HEADER_SIZE 6
+#define ARC_MAX_PACKET_SIZE 576
+
+
+//
+// Check whether an address is broadcast.
+//
+
+#define ARC_IS_BROADCAST(Address) \
+ (BOOLEAN)(!(Address))
+
+
+//
+// An action routine type. The routines are called
+// when a filter type is set for the first time or
+// no more bindings require a particular type of filter.
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+NDIS_STATUS
+(*ARC_FILTER_CHANGE)(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+
+//
+// This action routine is called when the mac requests a close for
+// a particular binding *WHILE THE BINDING IS BEING INDICATED TO
+// THE PROTOCOL*. The filtering package can't get rid of the open
+// right away. So this routine will be called as soon as the
+// NdisIndicateReceive returns.
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+VOID
+(*ARC_DEFERRED_CLOSE)(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+typedef ULONG MASK,*PMASK;
+
+//
+// Maximum number of opens the filter package will support. This is
+// the max so that bit masks can be used instead of a spaghetti of
+// pointers.
+//
+#define ARC_FILTER_MAX_OPENS (sizeof(ULONG) * 8)
+
+
+//
+// The binding info is threaded on two lists. When
+// the binding is free it is on a single freelist.
+//
+// When the binding is being used it is on a doubly linked
+// index list.
+//
+typedef struct _ARC_BINDING_INFO {
+ NDIS_HANDLE MacBindingHandle;
+ NDIS_HANDLE NdisBindingContext;
+ UINT PacketFilters;
+ ULONG References;
+ struct _ARC_BINDING_INFO *NextOpen;
+ struct _ARC_BINDING_INFO *PrevOpen;
+ BOOLEAN ReceivedAPacket;
+ UCHAR FilterIndex;
+} ARC_BINDING_INFO,*PARC_BINDING_INFO;
+
+//
+// An opaque type that contains a filter database.
+// The MAC need not know how it is structured.
+//
+typedef struct _ARC_FILTER {
+
+ //
+ // For accessing the mini-port.
+ //
+ struct _NDIS_MINIPORT_BLOCK *Miniport;
+
+ //
+ // Spin lock used to protect the filter from multiple accesses.
+ //
+ PNDIS_SPIN_LOCK Lock;
+
+ //
+ // Combination of all the filters of all the open bindings.
+ //
+ UINT CombinedPacketFilter;
+
+ //
+ // Pointer for traversing the open list.
+ //
+ PARC_BINDING_INFO OpenList;
+
+ //
+ // Action routines to be invoked on notable changes in the filter.
+ //
+
+ ARC_FILTER_CHANGE FilterChangeAction;
+ ARC_DEFERRED_CLOSE CloseAction;
+
+ //
+ // Bit mask of opens that are available.
+ //
+ ULONG FreeBindingMask;
+
+ NDIS_HANDLE ReceiveBufferPool;
+
+ PARC_BUFFER_LIST FreeBufferList;
+ PARC_PACKET FreePackets;
+
+ PARC_PACKET OutstandingPackets;
+
+ //
+ // Address of the adapter.
+ //
+ UCHAR AdapterAddress;
+
+} ARC_FILTER,*PARC_FILTER;
+
+
+
+
+//
+//UINT
+//ARC_QUERY_FILTER_CLASSES(
+// IN PARC_FILTER Filter
+// )
+//
+// This macro returns the currently enabled filter classes.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define ARC_QUERY_FILTER_CLASSES(Filter) ((Filter)->CombinedPacketFilter)
+
+
+//
+//UINT
+//ARC_QUERY_PACKET_FILTER(
+// IN ARC_FILTER Filter,
+// IN NDIS_HANDLE NdisFilterHandle
+// )
+//
+// This macro returns the currently enabled filter classes for a specific
+// open instance.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define ARC_QUERY_PACKET_FILTER(Filter, NdisFilterHandle) \
+ (((PARC_BINDING_INFO)(NdisFilterHandle))->PacketFilters)
+
+//
+// Only for internal wrapper use.
+//
+VOID
+ArcInitializePackage(
+ VOID
+ );
+
+VOID
+ArcReferencePackage(
+ VOID
+ );
+
+VOID
+ArcDereferencePackage(
+ VOID
+ );
+
+
+//
+// Exported routines
+//
+
+BOOLEAN
+ArcCreateFilter(
+ IN struct _NDIS_MINIPORT_BLOCK *Miniport,
+ IN ARC_FILTER_CHANGE FilterChangeAction,
+ IN ARC_DEFERRED_CLOSE CloseAction,
+ IN UCHAR AdapterAddress,
+ IN PNDIS_SPIN_LOCK Lock,
+ OUT PARC_FILTER *Filter
+ );
+
+VOID
+ArcDeleteFilter(
+ IN PARC_FILTER Filter
+ );
+
+BOOLEAN
+ArcNoteFilterOpenAdapter(
+ IN PARC_FILTER Filter,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE NdisBindingContext,
+ OUT PNDIS_HANDLE NdisFilterHandle
+ );
+
+NDIS_STATUS
+ArcDeleteFilterOpenAdapter(
+ IN PARC_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+NDIS_STATUS
+ArcFilterAdjust(
+ IN PARC_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT FilterClasses,
+ IN BOOLEAN Set
+ );
+
+VOID
+ArcFilterDprIndicateReceiveComplete(
+ IN PARC_FILTER Filter
+ );
+
+VOID
+ArcFilterDprIndicateReceive(
+ IN PARC_FILTER Filter, // Pointer to filter database
+ IN PUCHAR pRawHeader, // Pointer to Arcnet frame header
+ IN PUCHAR pData, // Pointer to data portion of Arcnet frame
+ IN UINT Length // Data Length
+ );
+
+NDIS_STATUS
+ArcFilterTransferData(
+ IN PARC_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransfered
+ );
+
+VOID
+ArcFreeNdisPacket(
+ IN PARC_PACKET Packet
+ );
+
+VOID
+ArcFilterDoIndication(
+ IN PARC_FILTER Filter,
+ IN PARC_PACKET Packet
+ );
+
+VOID
+ArcDestroyPacket(
+ IN PARC_FILTER Filter,
+ IN PARC_PACKET Packet
+ );
+
+#endif // _ARC_FILTER_DEFS_
diff --git a/private/ntos/ndis/ndis30/efilter.c b/private/ntos/ndis/ndis30/efilter.c
new file mode 100644
index 000000000..98ebac0c3
--- /dev/null
+++ b/private/ntos/ndis/ndis30/efilter.c
@@ -0,0 +1,2252 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ efilter.c
+
+Abstract:
+
+ This module implements a set of library routines to handle packet
+ filtering for NDIS MAC drivers.
+
+Author:
+
+ Anthony V. Ercolano (Tonye) 03-Aug-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+ Adam Barr (adamba) 28-Nov-1990
+
+ - Added AddressContexts
+
+ Adam Barr (adamba) 28-May-1991
+
+ - renamed MacXXX to EthXXX, changed filter.c to efilter.c
+
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+//
+// This constant is used for places where NdisAllocateMemory
+// needs to be called and the HighestAcceptableAddress does
+// not matter.
+//
+
+static const NDIS_PHYSICAL_ADDRESS HighestAcceptableMax =
+ NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
+
+//
+// ZZZ NonPortable definitions.
+//
+#define AllocPhys(s, l) NdisAllocateMemory((PVOID *)(s), (l), 0, HighestAcceptableMax)
+#define FreePhys(s, l) NdisFreeMemory((PVOID)(s), (l), 0)
+
+#ifdef NDIS_NT
+
+#define MoveMemory(Destination,Source,Length) RtlMoveMemory(Destination,Source,Length)
+#define ZeroMemory(Destination,Length) RtlZeroMemory(Destination,Length)
+
+#endif
+
+#ifdef NDIS_DOS
+
+#define MoveMemory(Destination,Source,Length) NdisMoveOverlappedMemory(Destination,Source,Length)
+#define ZeroMemory(Destination,Length) NdisZeroMemory(Destination,Length)
+
+#endif
+
+#if DBG
+extern BOOLEAN NdisCheckBadDrivers;
+#endif
+
+//
+// A set of macros to manipulate bitmasks.
+//
+
+//VOID
+//CLEAR_BIT_IN_MASK(
+// IN UINT Offset,
+// IN OUT PETH_MASK MaskToClear
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Clear a bit in the bitmask pointed to by the parameter.
+//
+//Arguments:
+//
+// Offset - The offset (from 0) of the bit to altered.
+//
+// MaskToClear - Pointer to the mask to be adjusted.
+//
+//Return Value:
+//
+// None.
+//
+//--*/
+//
+#define CLEAR_BIT_IN_MASK(Offset,MaskToClear) *MaskToClear &= (~(1 << Offset))
+
+//VOID
+//SET_BIT_IN_MASK(
+// IN UINT Offset,
+// IN OUT PETH_MASK MaskToSet
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Set a bit in the bitmask pointed to by the parameter.
+//
+//Arguments:
+//
+// Offset - The offset (from 0) of the bit to altered.
+//
+// MaskToSet - Pointer to the mask to be adjusted.
+//
+//Return Value:
+//
+// None.
+//
+//--*/
+#define SET_BIT_IN_MASK(Offset,MaskToSet) *MaskToSet |= (1 << Offset)
+
+//BOOLEAN
+//IS_BIT_SET_IN_MASK(
+// IN UINT Offset,
+// IN ETH_MASK MaskToTest
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Tests if a particular bit in the bitmask pointed to by the parameter is
+// set.
+//
+//Arguments:
+//
+// Offset - The offset (from 0) of the bit to test.
+//
+// MaskToTest - The mask to be tested.
+//
+//Return Value:
+//
+// Returns TRUE if the bit is set.
+//
+//--*/
+#define IS_BIT_SET_IN_MASK(Offset,MaskToTest) \
+((MaskToTest & (1 << Offset))?(TRUE):(FALSE))
+
+//BOOLEAN
+//IS_MASK_CLEAR(
+// IN ETH_MASK MaskToTest
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Tests whether there are *any* bits enabled in the mask.
+//
+//Arguments:
+//
+// MaskToTest - The bit mask to test for all clear.
+//
+//Return Value:
+//
+// Will return TRUE if no bits are set in the mask.
+//
+//--*/
+#define IS_MASK_CLEAR(MaskToTest) ((!MaskToTest)?(TRUE):(FALSE))
+
+//VOID
+//CLEAR_MASK(
+// IN OUT PETH_MASK MaskToClear
+// );
+//
+///*++
+//
+//Routine Description:
+//
+// Clears a mask.
+//
+//Arguments:
+//
+// MaskToClear - The bit mask to adjust.
+//
+//Return Value:
+//
+// None.
+//
+//--*/
+#define CLEAR_MASK(MaskToClear) *MaskToClear = 0
+
+//
+// VOID
+// ETH_FILTER_ALLOC_OPEN(
+// IN PETH_FILTER Filter,
+// OUT PUINT FilterIndex
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Allocates an open block. This only allocate the index, not memory for
+// the open block.
+//
+//Arguments:
+//
+// Filter - DB from which to allocate the space
+//
+// FilterIndex - pointer to place to store the index.
+//
+//Return Value:
+//
+// FilterIndex of the new open
+//
+//--*/
+#define ETH_FILTER_ALLOC_OPEN(Filter, FilterIndex)\
+{\
+ UINT i; \
+ for (i=0; i < ETH_FILTER_MAX_OPENS; i++) { \
+ if (IS_BIT_SET_IN_MASK(i,(Filter)->FreeBindingMask)) { \
+ *(FilterIndex) = i; \
+ CLEAR_BIT_IN_MASK(i, &((Filter)->FreeBindingMask)); \
+ break; \
+ } \
+ } \
+}
+
+//
+// VOID
+// ETH_FILTER_FREE_OPEN(
+// IN PETH_FILTER Filter,
+// IN PETH_BINDING_INFO LocalOpen
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Frees an open block. Also frees the memory associated with the open.
+//
+//Arguments:
+//
+// Filter - DB from which to allocate the space
+//
+// FilterIndex - Index to free
+//
+//Return Value:
+//
+// FilterIndex of the new open
+//
+//--*/
+#define ETH_FILTER_FREE_OPEN(Filter, LocalOpen)\
+{\
+ SET_BIT_IN_MASK(((LocalOpen)->FilterIndex), &((Filter)->FreeBindingMask)); \
+ FreePhys((LocalOpen), sizeof(ETH_BINDING_INFO));\
+}
+
+
+
+NDIS_SPIN_LOCK EthReferenceLock = {0};
+KEVENT EthPagedInEvent = {0};
+ULONG EthReferenceCount = 0;
+PVOID EthImageHandle = {0};
+
+VOID
+EthInitializePackage(VOID)
+{
+ NdisAllocateSpinLock(&EthReferenceLock);
+ KeInitializeEvent(
+ &EthPagedInEvent,
+ NotificationEvent,
+ FALSE
+ );
+}
+
+VOID
+EthReferencePackage(VOID)
+{
+
+ ACQUIRE_SPIN_LOCK(&EthReferenceLock);
+
+ EthReferenceCount++;
+
+ if (EthReferenceCount == 1) {
+
+ KeResetEvent(
+ &EthPagedInEvent
+ );
+
+ RELEASE_SPIN_LOCK(&EthReferenceLock);
+
+ //
+ // Page in all the functions
+ //
+ EthImageHandle = MmLockPagableCodeSection(EthCreateFilter);
+
+ //
+ // Signal to everyone to go
+ //
+ KeSetEvent(
+ &EthPagedInEvent,
+ 0L,
+ FALSE
+ );
+
+ } else {
+
+ RELEASE_SPIN_LOCK(&EthReferenceLock);
+
+ //
+ // Wait for everything to be paged in
+ //
+ KeWaitForSingleObject(
+ &EthPagedInEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ NULL
+ );
+
+ }
+
+}
+
+VOID
+EthDereferencePackage(VOID)
+{
+ ACQUIRE_SPIN_LOCK(&EthReferenceLock);
+
+ EthReferenceCount--;
+
+ if (EthReferenceCount == 0) {
+
+ RELEASE_SPIN_LOCK(&EthReferenceLock);
+
+ //
+ // Page out all the functions
+ //
+ MmUnlockPagableImageSection(EthImageHandle);
+
+ } else {
+
+ RELEASE_SPIN_LOCK(&EthReferenceLock);
+
+ }
+
+}
+
+
+static
+BOOLEAN
+FindMulticast(
+ IN UINT NumberOfAddresses,
+ IN CHAR AddressArray[][ETH_LENGTH_OF_ADDRESS],
+ IN CHAR MulticastAddress[ETH_LENGTH_OF_ADDRESS],
+ OUT PUINT ArrayIndex
+ );
+
+
+#ifdef ALLOC_PRAGMA
+//#pragma alloc_text(PAGENDSE, EthShouldAddressLoopBack)
+#pragma alloc_text(PAGENDSE, FindMulticast)
+//#pragma alloc_text(PAGENDSE, EthFilterDprIndicateReceiveComplete)
+#pragma alloc_text(PAGENDSE, EthFilterIndicateReceiveComplete)
+//#pragma alloc_text(PAGENDSE, EthFilterDprIndicateReceive)
+#pragma alloc_text(PAGENDSE, EthFilterIndicateReceive)
+#pragma alloc_text(PAGENDSE, EthQueryGlobalFilterAddresses)
+#pragma alloc_text(PAGENDSE, EthQueryOpenFilterAddresses)
+#pragma alloc_text(PAGENDSE, EthNumberOfOpenFilterAddresses)
+#pragma alloc_text(PAGENDSE, EthFilterAdjust)
+#pragma alloc_text(PAGENDSE, EthChangeFilterAddresses)
+#pragma alloc_text(PAGENDSE, EthDeleteFilterOpenAdapter)
+#pragma alloc_text(PAGENDSE, EthNoteFilterOpenAdapter)
+#pragma alloc_text(PAGENDSE, EthCreateFilter)
+
+#endif
+
+
+
+BOOLEAN
+EthCreateFilter(
+ IN UINT MaximumMulticastAddresses,
+ IN ETH_ADDRESS_CHANGE AddressChangeAction,
+ IN ETH_FILTER_CHANGE FilterChangeAction,
+ IN ETH_DEFERRED_CLOSE CloseAction,
+ IN PUCHAR AdapterAddress,
+ IN PNDIS_SPIN_LOCK Lock,
+ OUT PETH_FILTER *Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to create and initialize the filter database.
+
+Arguments:
+
+ MaximumMulticastAddresses - The maximum number of multicast addresses
+ that the MAC will support.
+
+ AddressChangeAction - Action routine to call when the list of
+ multicast addresses the card must enable has changed.
+
+ ChangeAction - Action routine to call when a binding sets or clears
+ a particular filter class and it is the first or only binding using
+ the filter class.
+
+ CloseAction - This routine is called if a binding closes while
+ it is being indicated to via NdisIndicateReceive. It will be
+ called upon return from NdisIndicateReceive.
+
+ AdapterAddress - the address of the adapter associated with this filter
+ database.
+
+ Lock - Pointer to the lock that should be held when mutual exclusion
+ is required.
+
+ Filter - A pointer to an ETH_FILTER. This is what is allocated and
+ created by this routine.
+
+Return Value:
+
+ If the function returns false then one of the parameters exceeded
+ what the filter was willing to support.
+
+--*/
+
+{
+
+ PETH_FILTER LocalFilter;
+ NDIS_STATUS AllocStatus;
+
+ //
+ // Allocate the database and it's associated arrays.
+ //
+
+ AllocStatus = AllocPhys(&LocalFilter, sizeof(ETH_FILTER));
+ *Filter = LocalFilter;
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+ return FALSE;
+ }
+
+ ZeroMemory(
+ LocalFilter,
+ sizeof(ETH_FILTER)
+ );
+
+ if (MaximumMulticastAddresses == 0) {
+
+ //
+ // Why 2 and not 1? Why not. A protocol is going to need at least
+ // one to run on this, so let's give one extra one for any user stuff
+ // that may need it.
+ //
+
+ MaximumMulticastAddresses = 2;
+
+ }
+
+ {
+ PVOID TmpAlloc;
+
+ AllocStatus = AllocPhys(
+ &TmpAlloc,
+ 2*ETH_LENGTH_OF_ADDRESS*MaximumMulticastAddresses
+ );
+
+ LocalFilter->MulticastAddresses = TmpAlloc;
+
+ }
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+
+ EthDeleteFilter(LocalFilter);
+ return FALSE;
+
+ }
+
+ AllocStatus = AllocPhys(
+ &LocalFilter->BindingsUsingAddress,
+ 2*sizeof(ETH_MASK)*MaximumMulticastAddresses
+ );
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+
+ EthDeleteFilter(LocalFilter);
+ return FALSE;
+
+ }
+
+ EthReferencePackage();
+
+ LocalFilter->FreeBindingMask = (ULONG)(-1);
+ LocalFilter->OpenList = NULL;
+
+ ETH_COPY_NETWORK_ADDRESS(LocalFilter->AdapterAddress, AdapterAddress);
+ LocalFilter->Lock = Lock;
+ LocalFilter->AddressChangeAction = AddressChangeAction;
+ LocalFilter->FilterChangeAction = FilterChangeAction;
+ LocalFilter->CloseAction = CloseAction;
+ LocalFilter->NumberOfAddresses = 0;
+ LocalFilter->MaximumMulticastAddresses = MaximumMulticastAddresses;
+
+ return TRUE;
+}
+
+
+//
+// NOTE: THIS FUNCTION CANNOT BE PAGEABLE
+//
+VOID
+EthDeleteFilter(
+ IN PETH_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to delete the memory associated with a filter
+ database. Note that this routines *ASSUMES* that the database
+ has been cleared of any active filters.
+
+Arguments:
+
+ Filter - A pointer to an ETH_FILTER to be deleted.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ASSERT(Filter->FreeBindingMask == (ETH_MASK)-1);
+ ASSERT(Filter->OpenList == NULL);
+
+ if (Filter->MulticastAddresses) {
+
+ FreePhys(
+ Filter->MulticastAddresses,
+ 2*ETH_LENGTH_OF_ADDRESS*Filter->MaximumMulticastAddresses
+ );
+
+ }
+
+ if (Filter->BindingsUsingAddress) {
+
+ FreePhys(
+ Filter->BindingsUsingAddress,
+ 2*sizeof(ETH_MASK)*Filter->MaximumMulticastAddresses
+ );
+
+ }
+
+ FreePhys(Filter, sizeof(ETH_FILTER));
+
+ EthDereferencePackage();
+
+}
+
+
+BOOLEAN
+EthNoteFilterOpenAdapter(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE NdisBindingContext,
+ OUT PNDIS_HANDLE NdisFilterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to add a new binding to the filter database.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE DATABASE IS LOCKED WHEN
+ IT IS CALLED.
+
+Arguments:
+
+ Filter - A pointer to the previously created and initialized filter
+ database.
+
+ MacBindingHandle - The MAC supplied value to the protocol in response
+ to a call to EthOpenAdapter.
+
+ NdisBindingContext - An NDIS supplied value to the call to EthOpenAdapter.
+
+ NdisFilterHandle - A pointer to this open.
+
+Return Value:
+
+ Will return false if creating a new filter index will cause the maximum
+ number of filter indexes to be exceeded.
+
+--*/
+
+{
+
+ //
+ // Will hold the value of the filter index so that we
+ // need not indirectly address through pointer parameter.
+ //
+ UINT LocalIndex;
+
+ NDIS_STATUS AllocStatus;
+
+ //
+ // Pointer to new open block.
+ //
+ PETH_BINDING_INFO LocalOpen;
+
+ PNDIS_OPEN_BLOCK NdisOpen = (PNDIS_OPEN_BLOCK)NdisBindingContext;
+
+ //
+ // Get the first free binding slot and remove that slot from
+ // the free list. We check to see if the list is empty.
+ //
+
+
+ if (Filter->FreeBindingMask == 0) {
+
+ return FALSE;
+
+ }
+
+ AllocStatus = AllocPhys(
+ &LocalOpen,
+ sizeof(ETH_BINDING_INFO)
+ );
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Get place for the open and insert it.
+ //
+
+ ETH_FILTER_ALLOC_OPEN(Filter, &LocalIndex);
+
+ LocalOpen->NextOpen = Filter->OpenList;
+
+ if (Filter->OpenList != NULL) {
+ Filter->OpenList->PrevOpen = LocalOpen;
+ }
+
+ LocalOpen->PrevOpen = NULL;
+
+ Filter->OpenList = LocalOpen;
+
+ LocalOpen->FilterIndex = (UCHAR)LocalIndex;
+ LocalOpen->References = 1;
+ LocalOpen->MacBindingHandle = MacBindingHandle;
+ LocalOpen->NdisBindingContext = NdisBindingContext;
+ LocalOpen->PacketFilters = 0;
+ LocalOpen->ReceivedAPacket = FALSE;
+
+ *NdisFilterHandle = (NDIS_HANDLE)LocalOpen;
+
+ return TRUE;
+
+}
+
+
+NDIS_STATUS
+EthDeleteFilterOpenAdapter(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ When an adapter is being closed this routine should
+ be called to delete knowledge of the adapter from
+ the filter database. This routine is likely to call
+ action routines associated with clearing filter classes
+ and addresses.
+
+ NOTE: THIS ROUTINE SHOULD ****NOT**** BE CALLED IF THE ACTION
+ ROUTINES FOR DELETING THE FILTER CLASSES OR THE MULTICAST ADDRESSES
+ HAVE ANY POSSIBILITY OF RETURNING A STATUS OTHER THAN NDIS_STATUS_PENDING
+ OR NDIS_STATUS_SUCCESS. WHILE THESE ROUTINES WILL NOT BUGCHECK IF
+ SUCH A THING IS DONE, THE CALLER WILL PROBABLY FIND IT DIFFICULT
+ TO CODE A CLOSE ROUTINE!
+
+ NOTE: THIS ROUTINE ASSUMES THAT IT IS CALLED WITH THE LOCK HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routines,
+ this will be passed to it.
+
+Return Value:
+
+ If action routines are called by the various address and filtering
+ routines the this routine will likely return the status returned
+ by those routines. The exception to this rule is noted below.
+
+ Given that the filter and address deletion routines return a status
+ NDIS_STATUS_PENDING or NDIS_STATUS_SUCCESS this routine will then
+ try to return the filter index to the freelist. If the routine
+ detects that this binding is currently being indicated to via
+ NdisIndicateReceive, this routine will return a status of
+ NDIS_STATUS_CLOSING_INDICATING.
+
+--*/
+
+{
+
+ //
+ // Holds the status returned from the packet filter and address
+ // deletion routines. Will be used to return the status to
+ // the caller of this routine.
+ //
+ NDIS_STATUS StatusToReturn;
+
+ //
+ // Local variable.
+ //
+ PETH_BINDING_INFO LocalOpen = (PETH_BINDING_INFO)NdisFilterHandle;
+
+ StatusToReturn = EthFilterAdjust(
+ Filter,
+ NdisFilterHandle,
+ NdisRequest,
+ (UINT)0,
+ FALSE
+ );
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS ||
+ StatusToReturn == NDIS_STATUS_PENDING) {
+
+ NDIS_STATUS StatusToReturn2;
+
+ StatusToReturn2 = EthChangeFilterAddresses(
+ Filter,
+ NdisFilterHandle,
+ NdisRequest,
+ 0,
+ NULL,
+ FALSE
+ );
+
+ if (StatusToReturn2 != NDIS_STATUS_SUCCESS) {
+
+ StatusToReturn = StatusToReturn2;
+
+ }
+
+ }
+
+
+ if ((StatusToReturn == NDIS_STATUS_SUCCESS) ||
+ (StatusToReturn == NDIS_STATUS_PENDING)) {
+
+ //
+ // Remove the reference from the original open.
+ //
+
+ if (--(LocalOpen->References) == 0) {
+
+ //
+ // Remove it from the list.
+ //
+
+ if (LocalOpen->NextOpen != NULL) {
+
+ LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen;
+
+ }
+
+ if (LocalOpen->PrevOpen != NULL) {
+
+ LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen;
+
+ } else {
+
+ Filter->OpenList = LocalOpen->NextOpen;
+
+ }
+
+
+ //
+ // First we finish any NdisIndicateReceiveComplete that
+ // may be needed for this binding.
+ //
+
+ if (LocalOpen->ReceivedAPacket) {
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ }
+
+ ETH_FILTER_FREE_OPEN(Filter, LocalOpen);
+
+ } else {
+
+ //
+ // Let the caller know that there is a reference to the open
+ // by the receive indication. The close action routine will be
+ // called upon return from NdisIndicateReceive.
+ //
+
+ StatusToReturn = NDIS_STATUS_CLOSING_INDICATING;
+
+ }
+
+ }
+
+ return StatusToReturn;
+
+}
+
+
+NDIS_STATUS
+EthChangeFilterAddresses(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT AddressCount,
+ IN CHAR Addresses[][ETH_LENGTH_OF_ADDRESS],
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ The ChangeFilterAddress routine will call an action
+ routine when the overall multicast address list for the adapter
+ has changed.
+
+ If the action routine returns a value other than pending or
+ success then this routine has no effect on the multicast address
+ list for the open or for the adapter as a whole.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routine,
+ this will be passed to it.
+
+ AddressCount - The number of elements (addresses,
+ not bytes) in MulticastAddressList.
+
+ Addresses - The new multicast address list for this
+ binding. This is a sequence of ETH_LENGTH_OF_ADDRESS byte
+ addresses, with no padding between them.
+
+ Set - A boolean that determines whether the multicast addresses
+ are being adjusted due to a set or because of a close. (The filtering
+ routines don't care, the MAC might.)
+
+Return Value:
+
+ If it calls the action routine then it will return the
+ status returned by the action routine. If the status
+ returned by the action routine is anything other than
+ NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
+ will be returned to the state it was in upon entrance to this
+ routine.
+
+ If the action routine is not called this routine will return
+ the following statum:
+
+ NDIS_STATUS_SUCCESS - If the new packet filters doesn't change
+ the combined mask of all bindings packet filters.
+
+--*/
+
+{
+ //
+ // Holds the status returned to the user of this routine, if the
+ // action routine is not called then the status will be success,
+ // otherwise, it is whatever the action routine returns.
+ //
+ NDIS_STATUS StatusOfChange;
+
+ //
+ // Saves the original length of the address array.
+ //
+ UINT InitialArraySize;
+
+ //
+ // Set true when the address array changes
+ //
+ UINT AddressesChanged = 0;
+
+ //
+ // Use to save data if needed.
+ //
+ PVOID TmpAddressArray, TmpMaskArray;
+
+ //
+ // Simple iteration variables.
+ //
+ UINT ArrayIndex, i;
+
+
+ //
+ // Simple Temp variable
+ //
+ PCHAR CurrentAddress;
+
+ PETH_BINDING_INFO LocalOpen = (PETH_BINDING_INFO)NdisFilterHandle;
+
+
+ TmpAddressArray =
+ (PUCHAR)Filter->MulticastAddresses +
+ (ETH_LENGTH_OF_ADDRESS*Filter->MaximumMulticastAddresses);
+
+ TmpMaskArray =
+ (PUCHAR)Filter->BindingsUsingAddress +
+ (sizeof(ETH_MASK)*Filter->MaximumMulticastAddresses);
+
+
+ //
+ // We have to save the old mask array in
+ // case we need to restore it. If we need
+ // to save the address array too we will
+ // do that later.
+ //
+
+ MoveMemory(
+ TmpMaskArray,
+ (PVOID)Filter->BindingsUsingAddress,
+ Filter->NumberOfAddresses * sizeof(ETH_MASK)
+ );
+
+ //
+ // We have to save the old address array in
+ // case we need to restore it. If we need
+ // to save the address array too we will
+ // do that later.
+ //
+
+ MoveMemory(
+ TmpAddressArray,
+ (PVOID)Filter->MulticastAddresses,
+ Filter->NumberOfAddresses * ETH_LENGTH_OF_ADDRESS
+ );
+
+ InitialArraySize = Filter->NumberOfAddresses;
+
+
+ //
+ // Now modify the original array...
+ //
+
+ //
+ // First go through and turn off the bit for this
+ // binding throughout the array.
+ //
+
+ for (i=0; i<(Filter->NumberOfAddresses); i++) {
+
+ CLEAR_BIT_IN_MASK(
+ LocalOpen->FilterIndex,
+ &(Filter->BindingsUsingAddress[i])
+ );
+
+ }
+
+ //
+ // First we have to remove any addresses from
+ // the multicast array if they have no bits on any more.
+ //
+ for (ArrayIndex = 0; ArrayIndex < Filter->NumberOfAddresses; ) {
+
+ if (IS_MASK_CLEAR(Filter->BindingsUsingAddress[ArrayIndex])) {
+
+ //
+ // yes it is clear, so we have to shift everything
+ // above it down one.
+ //
+
+ MoveMemory(
+ Filter->MulticastAddresses[ArrayIndex],
+ Filter->MulticastAddresses[ArrayIndex+1],
+ (Filter->NumberOfAddresses-(ArrayIndex+1))
+ *ETH_LENGTH_OF_ADDRESS
+ );
+
+ MoveMemory(
+ &Filter->BindingsUsingAddress[ArrayIndex],
+ &Filter->BindingsUsingAddress[ArrayIndex+1],
+ (Filter->NumberOfAddresses-(ArrayIndex+1))*(sizeof(ETH_MASK))
+ );
+
+ Filter->NumberOfAddresses--;
+
+ } else {
+
+ ArrayIndex++;
+
+ }
+
+ }
+
+
+ //
+ // Now go through the new addresses for this binding,
+ // and insert them into the array.
+ //
+
+ for (i=0; i<AddressCount; i++) {
+
+ CurrentAddress = ((PCHAR)Addresses) + (i*ETH_LENGTH_OF_ADDRESS);
+
+ if (FindMulticast(
+ Filter->NumberOfAddresses,
+ Filter->MulticastAddresses,
+ CurrentAddress,
+ &ArrayIndex)) {
+
+ //
+ // The address is there, so just turn the bit
+ // back on.
+ //
+
+ SET_BIT_IN_MASK(
+ LocalOpen->FilterIndex,
+ &Filter->BindingsUsingAddress[ArrayIndex]
+ );
+
+ } else {
+
+ //
+ // The address was not found, add it.
+ //
+
+ if (Filter->NumberOfAddresses < Filter->MaximumMulticastAddresses) {
+
+ //
+ // Save the address array if it hasn't been.
+ //
+
+ MoveMemory(
+ Filter->MulticastAddresses[ArrayIndex+1],
+ Filter->MulticastAddresses[ArrayIndex],
+ (Filter->NumberOfAddresses-ArrayIndex)*ETH_LENGTH_OF_ADDRESS
+ );
+
+ ETH_COPY_NETWORK_ADDRESS(
+ Filter->MulticastAddresses[ArrayIndex],
+ CurrentAddress
+ );
+
+ MoveMemory(
+ &(Filter->BindingsUsingAddress[ArrayIndex+1]),
+ &(Filter->BindingsUsingAddress[ArrayIndex]),
+ (Filter->NumberOfAddresses-ArrayIndex)*sizeof(ETH_MASK)
+ );
+
+ CLEAR_MASK(&Filter->BindingsUsingAddress[ArrayIndex]);
+
+ SET_BIT_IN_MASK(
+ LocalOpen->FilterIndex,
+ &Filter->BindingsUsingAddress[ArrayIndex]
+ );
+
+ Filter->NumberOfAddresses++;
+
+ } else {
+
+ //
+ // No room in the array, oh well.
+ //
+
+ MoveMemory(
+ (PVOID)Filter->MulticastAddresses,
+ TmpAddressArray,
+ InitialArraySize * ETH_LENGTH_OF_ADDRESS
+ );
+
+ MoveMemory(
+ (PVOID)Filter->BindingsUsingAddress,
+ TmpMaskArray,
+ InitialArraySize * sizeof(ETH_MASK)
+ );
+
+ Filter->NumberOfAddresses = InitialArraySize;
+
+ return NDIS_STATUS_MULTICAST_FULL;
+
+ }
+
+ }
+
+ }
+
+ // Check to see if address array has chnaged
+
+ AddressesChanged = Filter->NumberOfAddresses - InitialArraySize;
+
+ for (i=0; i<InitialArraySize && AddressesChanged==0; i++) {
+
+ ETH_COMPARE_NETWORK_ADDRESSES_EQ(Filter->MulticastAddresses[i],
+ (PUCHAR)TmpAddressArray + i * ETH_LENGTH_OF_ADDRESS,
+ &AddressesChanged);
+
+ }
+
+ //
+ // If the address array has changed, we have to call the
+ // action array to inform the adapter of this.
+ //
+
+ if (AddressesChanged != 0) {
+
+ StatusOfChange = Filter->AddressChangeAction(
+ InitialArraySize,
+ TmpAddressArray,
+ Filter->NumberOfAddresses,
+ Filter->MulticastAddresses,
+ LocalOpen->MacBindingHandle,
+ NdisRequest,
+ Set
+ );
+
+ if ((StatusOfChange != NDIS_STATUS_SUCCESS) &&
+ (StatusOfChange != NDIS_STATUS_PENDING)) {
+
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+
+ MoveMemory(
+ (PVOID)Filter->MulticastAddresses,
+ TmpAddressArray,
+ InitialArraySize * ETH_LENGTH_OF_ADDRESS
+ );
+
+ MoveMemory(
+ (PVOID)Filter->MulticastAddresses,
+ TmpAddressArray,
+ InitialArraySize * ETH_LENGTH_OF_ADDRESS
+ );
+
+ }
+
+ } else {
+
+ StatusOfChange = NDIS_STATUS_SUCCESS;
+
+ }
+
+
+ return StatusOfChange;
+
+
+}
+
+
+NDIS_STATUS
+EthFilterAdjust(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT FilterClasses,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ The FilterAdjust routine will call an action routine when a
+ particular filter class is changes from not being used by any
+ binding to being used by at least one binding or vice versa.
+
+ If the action routine returns a value other than pending or
+ success then this routine has no effect on the packet filters
+ for the open or for the adapter as a whole.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - A pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routine,
+ this will be passed to it.
+
+ FilterClasses - The filter classes that are to be added or
+ deleted.
+
+ Set - A boolean that determines whether the filter classes
+ are being adjusted due to a set or because of a close. (The filtering
+ routines don't care, the MAC might.)
+
+Return Value:
+
+ If it calls the action routine then it will return the
+ status returned by the action routine. If the status
+ returned by the action routine is anything other than
+ NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
+ will be returned to the state it was in upon entrance to this
+ routine.
+
+ If the action routine is not called this routine will return
+ the following statum:
+
+ NDIS_STATUS_SUCCESS - If the new packet filters doesn't change
+ the combined mask of all bindings packet filters.
+
+--*/
+
+{
+ //
+ // Contains the value of the combined filter classes before
+ // it is adjusted.
+ //
+ UINT OldCombined = Filter->CombinedPacketFilter;
+
+ PETH_BINDING_INFO LocalOpen = (PETH_BINDING_INFO)NdisFilterHandle;
+ PETH_BINDING_INFO OpenList;
+
+ //
+ // Contains the value of the particlar opens packet filters
+ // prior to the change. We save this incase the action
+ // routine (if called) returns an "error" status.
+ //
+ UINT OldOpenFilters = LocalOpen->PacketFilters;
+
+ //
+ // Holds the status returned to the user of this routine, if the
+ // action routine is not called then the status will be success,
+ // otherwise, it is whatever the action routine returns.
+ //
+ NDIS_STATUS StatusOfAdjust;
+
+ //
+ // Set the new filter information for the open.
+ //
+
+ LocalOpen->PacketFilters = FilterClasses;
+
+ //
+ // We always have to reform the compbined filter since
+ // this filter index may have been the only filter index
+ // to use a particular bit.
+ //
+
+
+ for (
+ OpenList = Filter->OpenList,
+ Filter->CombinedPacketFilter = 0;
+ OpenList != NULL;
+ OpenList = OpenList->NextOpen
+ ) {
+
+ Filter->CombinedPacketFilter |=
+ OpenList->PacketFilters;
+
+ }
+
+ if (OldCombined != Filter->CombinedPacketFilter) {
+
+ StatusOfAdjust = Filter->FilterChangeAction(
+ OldCombined,
+ Filter->CombinedPacketFilter,
+ LocalOpen->MacBindingHandle,
+ NdisRequest,
+ Set
+ );
+
+ if ((StatusOfAdjust != NDIS_STATUS_SUCCESS) &&
+ (StatusOfAdjust != NDIS_STATUS_PENDING)) {
+
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+
+ LocalOpen->PacketFilters = OldOpenFilters;
+ Filter->CombinedPacketFilter = OldCombined;
+
+ }
+
+ } else {
+
+ StatusOfAdjust = NDIS_STATUS_SUCCESS;
+
+ }
+
+ return StatusOfAdjust;
+
+}
+
+
+UINT
+EthNumberOfOpenFilterAddresses(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine counts the number of multicast addresses that a specific
+ open has.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to open block.
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ UINT IndexOfAddress;
+ UINT CountOfAddresses = 0;
+
+ UINT FilterIndex = ((PETH_BINDING_INFO)NdisFilterHandle)->FilterIndex;
+
+ for(IndexOfAddress=0;
+ IndexOfAddress < Filter->NumberOfAddresses;
+ IndexOfAddress++
+ ){
+
+ if (IS_BIT_SET_IN_MASK(FilterIndex,
+ Filter->BindingsUsingAddress[IndexOfAddress])) {
+
+ CountOfAddresses++;
+
+
+ }
+
+ }
+
+ return(CountOfAddresses);
+
+}
+
+
+VOID
+EthQueryOpenFilterAddresses(
+ OUT PNDIS_STATUS Status,
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN UINT SizeOfArray,
+ OUT PUINT NumberOfAddresses,
+ OUT CHAR AddressArray[][ETH_LENGTH_OF_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ The routine should be used by the MAC before
+ it actually alters the hardware registers to effect a
+ filtering hardware. This is usefull if another binding
+ has altered the address list since the action routine
+ is called.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Status - A pointer to the status of the call, NDIS_STATUS_SUCCESS or
+ NDIS_STATUS_FAILURE. Use EthNumberOfOpenAddresses() to get the
+ size that is needed.
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to the open block
+
+ SizeOfArray - The byte count of the AddressArray.
+
+ NumberOfAddresses - The number of addresses written to the array.
+
+ AddressArray - Will be filled with the addresses currently in the
+ multicast address list.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ UINT IndexOfAddress;
+ UINT CountOfAddresses = 0;
+ UINT FilterIndex = ((PETH_BINDING_INFO)NdisFilterHandle)->FilterIndex;
+
+ for(IndexOfAddress=0;
+ IndexOfAddress < Filter->NumberOfAddresses;
+ IndexOfAddress++
+ ){
+
+ if (IS_BIT_SET_IN_MASK(FilterIndex,
+ Filter->BindingsUsingAddress[IndexOfAddress])) {
+
+ if (SizeOfArray < ETH_LENGTH_OF_ADDRESS) {
+
+ *Status = NDIS_STATUS_FAILURE;
+
+ *NumberOfAddresses = 0;
+
+ return;
+
+ }
+
+ SizeOfArray -= ETH_LENGTH_OF_ADDRESS;
+
+ MoveMemory(
+ AddressArray[CountOfAddresses],
+ Filter->MulticastAddresses[IndexOfAddress],
+ ETH_LENGTH_OF_ADDRESS
+ );
+
+ CountOfAddresses++;
+
+ }
+
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ *NumberOfAddresses = CountOfAddresses;
+
+ return;
+
+}
+
+
+VOID
+EthQueryGlobalFilterAddresses(
+ OUT PNDIS_STATUS Status,
+ IN PETH_FILTER Filter,
+ IN UINT SizeOfArray,
+ OUT PUINT NumberOfAddresses,
+ IN OUT CHAR AddressArray[][ETH_LENGTH_OF_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ The routine should be used by the MAC before
+ it actually alters the hardware registers to effect a
+ filtering hardware. This is usefull if another binding
+ has altered the address list since the action routine
+ is called.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Status - A pointer to the status of the call, NDIS_STATUS_SUCCESS or
+ NDIS_STATUS_FAILURE. Use ETH_NUMBER_OF_GLOBAL_ADDRESSES() to get the
+ size that is needed.
+
+ Filter - A pointer to the filter database.
+
+ SizeOfArray - The byte count of the AddressArray.
+
+ NumberOfAddresses - A pointer to the number of addresses written to the
+ array.
+
+ AddressArray - Will be filled with the addresses currently in the
+ multicast address list.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ if (SizeOfArray < (Filter->NumberOfAddresses * ETH_LENGTH_OF_ADDRESS)) {
+
+ *Status = NDIS_STATUS_FAILURE;
+
+ *NumberOfAddresses = 0;
+
+ } else {
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ *NumberOfAddresses = Filter->NumberOfAddresses;
+
+ MoveMemory(
+ AddressArray[0],
+ Filter->MulticastAddresses[0],
+ Filter->NumberOfAddresses*ETH_LENGTH_OF_ADDRESS
+ );
+
+ }
+
+}
+
+
+VOID
+EthFilterIndicateReceive(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PCHAR Address,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+{
+ KIRQL oldIrql;
+ KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ EthFilterDprIndicateReceive(
+ Filter,
+ MacReceiveContext,
+ Address,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize
+ );
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ KeLowerIrql( oldIrql );
+ return;
+}
+
+
+VOID
+EthFilterDprIndicateReceive(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PCHAR Address,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate a packet to
+ all bindings. The packet will be filtered so that only the
+ appropriate bindings will receive the packet.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ MacReceiveContext - A MAC supplied context value that must be
+ returned by the protocol if it calls MacTransferData.
+
+ Address - The destination address from the received packet.
+
+ HeaderBuffer - A virtual address of the virtually contiguous
+ buffer containing the MAC header of the packet.
+
+ HeaderBufferSize - An unsigned integer indicating the size of
+ the header buffer, in bytes.
+
+ LookaheadBuffer - A virtual address of the virtually contiguous
+ buffer containing the first LookaheadBufferSize bytes of data
+ of the packet. The packet buffer is valid only within the current
+ call to the receive event handler.
+
+ LookaheadBufferSize - An unsigned integer indicating the size of
+ the lookahead buffer, in bytes.
+
+ PacketSize - An unsigned integer indicating the size of the received
+ packet, in bytes. This number has nothing to do with the lookahead
+ buffer, but indicates how large the arrived packet is so that a
+ subsequent MacTransferData request can be made to transfer the entire
+ packet as necessary.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Will hold the type of address that we know we've got.
+ //
+ UINT AddressType;
+
+ //
+ // Will hold the status of indicating the receive packet.
+ // ZZZ For now this isn't used.
+ //
+ NDIS_STATUS StatusOfReceive;
+
+ //
+ // Will hold the filter classes of the binding being indicated.
+ //
+ UINT BindingFilters;
+ UINT IntersectionOfFilters;
+
+ //
+ // Current Open to indicate to.
+ //
+ PETH_BINDING_INFO LocalOpen;
+
+ //
+ // If the packet is a runt packet, then only indicate to PROMISCUOUS
+ //
+
+ if ( HeaderBufferSize >= 14 && PacketSize != 0 ) {
+
+ //
+ // Valid ethernet header
+ //
+
+ //
+ // Determine whether the input address is a simple direct,
+ // a broadcast, or a multicast address.
+ //
+ //
+ // First check if it *at least* has the multicast address bit.
+ //
+
+ if (ETH_IS_MULTICAST(Address)) {
+
+ //
+ // It is at least a multicast address. Check to see if
+ // it is a broadcast address.
+ //
+
+ if (ETH_IS_BROADCAST(Address)) {
+
+
+#if DBG
+
+if (NdisCheckBadDrivers) {
+
+ if (!(Filter->CombinedPacketFilter & NDIS_PACKET_TYPE_BROADCAST)) {
+
+ //
+ // We should never receive directed packets
+ // to someone else unless in p-mode.
+ //
+ DbgPrint("NDIS: Bad driver, indicating broadcast\n");
+ DbgPrint("NDIS: packets when not set to.\n");
+ DbgBreakPoint();
+
+ }
+
+}
+
+#endif
+
+ AddressType = NDIS_PACKET_TYPE_BROADCAST;
+
+ } else {
+
+ AddressType = NDIS_PACKET_TYPE_MULTICAST;
+
+ }
+
+ } else {
+
+ //
+ // Verify that the address is directed to the adapter. We
+ // have to check for this because of the following senario.
+ //
+ // Adapter A is in promiscuous mode.
+ // Adapter B only wants directed packets to this adapter.
+ //
+ // The MAC will indicate *all* packets.
+ //
+ // The filter package needs to filter directed packets to
+ // other adapters from ones directed to this adapter.
+ //
+
+ if (Filter->CombinedPacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS) {
+
+ //
+ // The result of comparing an element of the address
+ // array and the multicast address.
+ //
+ // Result < 0 Implies the adapter address is greater.
+ // Result > 0 Implies the address is greater.
+ // Result = 0 Implies that the they are equal.
+ //
+ INT Result;
+
+ ETH_COMPARE_NETWORK_ADDRESSES_EQ(
+ Filter->AdapterAddress,
+ Address,
+ &Result
+ );
+
+ if (Result == 0) {
+
+ AddressType = NDIS_PACKET_TYPE_DIRECTED;
+
+ } else {
+
+ //
+ // This will cause binding that only want a specific
+ // address type to not be indicated.
+ //
+
+ AddressType = NDIS_PACKET_TYPE_PROMISCUOUS;
+
+ }
+
+ } else {
+
+#if DBG
+
+if (NdisCheckBadDrivers) {
+
+ //
+ // The result of comparing an element of the address
+ // array and the multicast address.
+ //
+ // Result < 0 Implies the adapter address is greater.
+ // Result > 0 Implies the address is greater.
+ // Result = 0 Implies that the they are equal.
+ //
+ INT Result;
+
+ ETH_COMPARE_NETWORK_ADDRESSES_EQ(
+ Filter->AdapterAddress,
+ Address,
+ &Result
+ );
+
+ if (Result != 0) {
+
+ //
+ // We should never receive directed packets
+ // to someone else unless in p-mode.
+ //
+ DbgPrint("NDIS: Bad driver, indicating packets\n");
+ DbgPrint("NDIS: to another station when not in\n");
+ DbgPrint("NDIS: promiscuous mode.\n");
+ DbgBreakPoint();
+
+
+ }
+
+}
+
+#endif
+
+ AddressType = NDIS_PACKET_TYPE_DIRECTED;
+
+ }
+
+ }
+
+ } else {
+
+ //
+ // runt packet
+ //
+
+ AddressType = NDIS_PACKET_TYPE_PROMISCUOUS;
+
+ }
+
+ //
+ // We need to acquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+
+ LocalOpen = Filter->OpenList;
+
+ while (LocalOpen != NULL) {
+
+ BindingFilters = LocalOpen->PacketFilters;
+ IntersectionOfFilters = BindingFilters & AddressType;
+
+ //
+ // if the binding wants direct packets and this is a directly
+ // addressed packet then the binding gets the packet.
+ //
+ //
+ // if the binding wants broadcast packets and the packet
+ // is a broadcast packet it will get the packet.
+ //
+
+ if (IntersectionOfFilters & (NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_BROADCAST)) {
+
+ goto IndicatePacket;
+
+ }
+
+ //
+ // if the binding wants multicast packets and the packet
+ // is a multicast packet and it's in the list of addresses
+ // it will get the packet.
+ //
+
+ if (IntersectionOfFilters & NDIS_PACKET_TYPE_MULTICAST) {
+
+ //
+ // Will hold the index of the multicast
+ // address if it finds it.
+ //
+ UINT IndexOfAddress;
+
+ if (FindMulticast(
+ Filter->NumberOfAddresses,
+ Filter->MulticastAddresses,
+ Address,
+ &IndexOfAddress
+ )) {
+
+ if (IS_BIT_SET_IN_MASK(
+ LocalOpen->FilterIndex,
+ Filter->BindingsUsingAddress[IndexOfAddress]
+ )) {
+
+ goto IndicatePacket;
+
+ }
+
+ }
+
+ }
+
+ //
+ // if the binding wants all multicast packets and the packet
+ // has a multicast address it will get the packet
+ //
+
+ if ((AddressType & NDIS_PACKET_TYPE_MULTICAST) &&
+ (BindingFilters & NDIS_PACKET_TYPE_ALL_MULTICAST)) {
+
+ goto IndicatePacket;
+
+ }
+
+ //
+ // if the binding is promiscuous then it will get the packet
+ //
+
+ if (BindingFilters & NDIS_PACKET_TYPE_PROMISCUOUS) {
+
+ goto IndicatePacket;
+
+ }
+
+ goto GetNextBinding;
+
+IndicatePacket:;
+
+ LocalOpen->References++;
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ //
+ // Indicate the packet to the binding.
+ //
+
+ FilterIndicateReceive(
+ &StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ if ((--(LocalOpen->References)) == 0) {
+
+ PETH_BINDING_INFO NextOpen = LocalOpen->NextOpen;
+
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+
+ //
+ // Remove it from the list.
+ //
+
+ if (LocalOpen->NextOpen != NULL) {
+
+ LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen;
+
+ }
+
+ if (LocalOpen->PrevOpen != NULL) {
+
+ LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen;
+
+ } else {
+
+ Filter->OpenList = LocalOpen->NextOpen;
+
+ }
+
+
+
+ //
+ // Call the IndicateComplete routine.
+ //
+
+
+ if (LocalOpen->ReceivedAPacket) {
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ }
+
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+
+ Filter->CloseAction(LocalOpen->MacBindingHandle);
+
+
+ ETH_FILTER_FREE_OPEN(Filter, LocalOpen);
+
+ LocalOpen = NextOpen;
+
+ continue;
+
+ }
+
+GetNextBinding:
+
+ LocalOpen = LocalOpen->NextOpen;
+
+ }
+
+}
+
+
+VOID
+EthFilterIndicateReceiveComplete(
+ IN PETH_FILTER Filter
+ )
+{
+ KIRQL oldIrql;
+ KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ EthFilterDprIndicateReceiveComplete(
+ Filter
+ );
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ KeLowerIrql( oldIrql );
+ return;
+}
+
+
+VOID
+EthFilterDprIndicateReceiveComplete(
+ IN PETH_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate that the receive
+ process is complete to all bindings. Only those bindings which
+ have received packets will be notified.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PETH_BINDING_INFO LocalOpen;
+
+ //
+ // We need to aquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+
+ LocalOpen = Filter->OpenList;
+
+ while (LocalOpen != NULL) {
+
+ if (LocalOpen->ReceivedAPacket) {
+
+ //
+ // Indicate the binding.
+ //
+
+ LocalOpen->ReceivedAPacket = FALSE;
+
+ LocalOpen->References++;
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ if ((--(LocalOpen->References)) == 0) {
+
+ PETH_BINDING_INFO NextOpen = LocalOpen->NextOpen;
+
+ //
+ // This binding is shutting down. We have to kill it.
+ //
+
+ //
+ // Remove it from the list.
+ //
+
+ if (LocalOpen->NextOpen != NULL) {
+
+ LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen;
+
+ }
+
+ if (LocalOpen->PrevOpen != NULL) {
+
+ LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen;
+
+ } else {
+
+ Filter->OpenList = LocalOpen->NextOpen;
+
+ }
+
+
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+
+ Filter->CloseAction(LocalOpen->MacBindingHandle);
+
+
+ ETH_FILTER_FREE_OPEN(Filter, LocalOpen);
+
+ LocalOpen = NextOpen;
+
+ continue;
+
+ }
+
+ }
+
+ LocalOpen = LocalOpen->NextOpen;
+
+ }
+
+}
+
+
+static
+BOOLEAN
+FindMulticast(
+ IN UINT NumberOfAddresses,
+ IN CHAR AddressArray[][ETH_LENGTH_OF_ADDRESS],
+ IN CHAR MulticastAddress[ETH_LENGTH_OF_ADDRESS],
+ OUT PUINT ArrayIndex
+ )
+
+/*++
+
+Routine Description:
+
+ Given an array of multicast addresses search the array for
+ a particular multicast address. It is assumed that the
+ address array is already sorted.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+ NOTE: This ordering is arbitrary but consistant.
+
+Arguments:
+
+ NumberOfAddresses - The number of addresses currently in the
+ address array.
+
+ AddressArray - An array of multicast addresses.
+
+ MulticastAddress - The address to search for in the address array.
+
+ ArrayIndex - Will point to where the MulticastAddress is in
+ the AddressArray, or if it isn't in the array, where it should
+ be in the array.
+
+Return Value:
+
+ If the address is in the sorted list this routine will return
+ TRUE, otherwise FALSE.
+
+--*/
+
+{
+
+ //
+ // Indices into the address array so that we may do a binary
+ // search.
+ //
+ UINT Bottom = 0;
+ UINT Middle = NumberOfAddresses / 2;
+ UINT Top;
+
+ if (NumberOfAddresses) {
+
+ Top = NumberOfAddresses - 1;
+
+ while ((Middle <= Top) && (Middle >= Bottom)) {
+
+ //
+ // The result of comparing an element of the address
+ // array and the multicast address.
+ //
+ // Result < 0 Implies the multicast address is greater.
+ // Result > 0 Implies the address array element is greater.
+ // Result = 0 Implies that the array element and the address
+ // are equal.
+ //
+ INT Result;
+
+ ETH_COMPARE_NETWORK_ADDRESSES(
+ AddressArray[Middle],
+ MulticastAddress,
+ &Result
+ );
+
+ if (Result == 0) {
+
+ *ArrayIndex = Middle;
+ return(TRUE);
+
+ } else if (Result > 0) {
+
+ if (Middle == 0) break;
+ Top = Middle - 1;
+
+
+ } else {
+
+ Bottom = Middle+1;
+
+ }
+
+ Middle = Bottom + (((Top+1) - Bottom)/2);
+
+ }
+
+ }
+
+ *ArrayIndex = Middle;
+
+ return(FALSE);
+
+}
+
+
+BOOLEAN
+EthShouldAddressLoopBack(
+ IN PETH_FILTER Filter,
+ IN CHAR Address[ETH_LENGTH_OF_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ Do a quick check to see whether the input address should
+ loopback.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+ NOTE: THIS ROUTINE DOES NOT CHECK THE SPECIAL CASE OF SOURCE
+ EQUALS DESTINATION.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ Address - A network address to check for loopback.
+
+
+Return Value:
+
+ Returns TRUE if the address is *likely* to need loopback. It
+ will return FALSE if there is *no* chance that the address would
+ require loopback.
+
+--*/
+{
+ BOOLEAN fLoopback, fSelfDirected;
+
+ EthShouldAddressLoopBackMacro(Filter, Address, &fLoopback, &fSelfDirected);
+
+ return(fLoopback);
+}
diff --git a/private/ntos/ndis/ndis30/efilter.h b/private/ntos/ndis/ndis30/efilter.h
new file mode 100644
index 000000000..c33749973
--- /dev/null
+++ b/private/ntos/ndis/ndis30/efilter.h
@@ -0,0 +1,605 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ efilter.h
+
+Abstract:
+
+ Header file for the address filtering library for NDIS MAC's.
+
+Author:
+
+ Anthony V. Ercolano (tonye) creation-date 3-Aug-1990
+
+Environment:
+
+ Runs in the context of a single MAC driver.
+
+Notes:
+
+ None.
+
+Revision History:
+
+ Adam Barr (adamba) 28-May-1991
+
+ - renamed MacXXX to EthXXX, changed filter.h to efilter.h
+
+
+--*/
+
+#ifndef _ETH_FILTER_DEFS_
+#define _ETH_FILTER_DEFS_
+
+#define ETH_LENGTH_OF_ADDRESS 6
+
+
+//
+// ZZZ This is a little-endian specific check.
+//
+#define ETH_IS_MULTICAST(Address) \
+ (((PUCHAR)(Address))[0] & ((UCHAR)0x01))
+
+
+//
+// Check whether an address is broadcast.
+//
+#define ETH_IS_BROADCAST(Address) \
+ ((*((ULONG UNALIGNED *) \
+ (&(((PUCHAR) \
+ Address \
+ )[2] \
+ ) \
+ ) \
+ ) == \
+ ((ULONG)0xffffffff) \
+ ) && \
+ (((PUCHAR)Address)[0] == ((UCHAR)0xff)) && \
+ (((PUCHAR)Address)[1] == ((UCHAR)0xff)))
+
+
+//
+// This macro will compare network addresses.
+//
+// A - Is a network address.
+//
+// B - Is a network address.
+//
+// Result - The result of comparing two network address.
+//
+// Result < 0 Implies the B address is greater.
+// Result > 0 Implies the A element is greater.
+// Result = 0 Implies equality.
+//
+// Note that this is an arbitrary ordering. There is not
+// defined relation on network addresses. This is ad-hoc!
+//
+//
+#define ETH_COMPARE_NETWORK_ADDRESSES(A,B,Result) \
+{ \
+ PUCHAR _A = (PUCHAR)(A); \
+ PUCHAR _B = (PUCHAR)(B); \
+ if ( *(ULONG UNALIGNED *)&_A[2] > \
+ *(ULONG UNALIGNED *)&_B[2] ) { \
+ *Result = 1; \
+ } else if ( *(ULONG UNALIGNED *)&_A[2] < \
+ *(ULONG UNALIGNED *)&_B[2] ) { \
+ *Result = (UINT)-1; \
+ } else if ( *(USHORT UNALIGNED *)_A > \
+ *(USHORT UNALIGNED *)_B ) { \
+ *Result = 1; \
+ } else if ( *(USHORT UNALIGNED *)_A < \
+ *(USHORT UNALIGNED *)_B ) { \
+ *Result = (UINT)-1; \
+ } else { \
+ *Result = 0; \
+ } \
+}
+
+//
+// This macro will compare network addresses.
+//
+// A - Is a network address.
+//
+// B - Is a network address.
+//
+// Result - The result of comparing two network address.
+//
+// Result != 0 Implies inequality.
+// Result == 0 Implies equality.
+//
+//
+#define ETH_COMPARE_NETWORK_ADDRESSES_EQ(A,B,Result) \
+{ \
+ PUCHAR _A = (PUCHAR)(A); \
+ PUCHAR _B = (PUCHAR)(B); \
+ if ( ( *(ULONG UNALIGNED *)&_A[2] == \
+ *(ULONG UNALIGNED *)&_B[2] ) && \
+ ( *(USHORT UNALIGNED *)_A == \
+ *(USHORT UNALIGNED *)_B ) ) { \
+ *Result = 0; \
+ } else { \
+ *Result = 1; \
+ } \
+}
+
+
+//
+// This macro is used to copy from one network address to
+// another.
+//
+#define ETH_COPY_NETWORK_ADDRESS(D,S) \
+{ \
+ PCHAR _D = (D); \
+ PCHAR _S = (S); \
+ *((ULONG UNALIGNED *)_D) = *((ULONG UNALIGNED *)_S); \
+ _D[4] = _S[4]; \
+ _D[5] = _S[5]; \
+}
+
+
+//
+//UINT
+//ETH_QUERY_FILTER_CLASSES(
+// IN PETH_FILTER Filter
+// )
+//
+// This macro returns the currently enabled filter classes.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define ETH_QUERY_FILTER_CLASSES(Filter) ((Filter)->CombinedPacketFilter)
+
+
+//
+//UINT
+//ETH_QUERY_PACKET_FILTER(
+// IN PETH_FILTER Filter,
+// IN NDIS_HANDLE NdisFilterHandle
+// )
+//
+// This macro returns the currently enabled filter classes for a specific
+// open instance.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define ETH_QUERY_PACKET_FILTER(Filter, NdisFilterHandle) \
+ (((PETH_BINDING_INFO)(NdisFilterHandle))->PacketFilters)
+
+
+//
+//UINT
+//ETH_NUMBER_OF_GLOBAL_FILTER_ADDRESSES(
+// IN PETH_FILTER Filter
+// )
+//
+// This macro returns the number of multicast addresses in the
+// multicast address list.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define ETH_NUMBER_OF_GLOBAL_FILTER_ADDRESSES(Filter) ((Filter)->NumberOfAddresses)
+
+
+//
+// An action routine type. The routines are called
+// when a filter type is set for the first time or
+// no more bindings require a particular type of filter.
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+NDIS_STATUS
+(*ETH_FILTER_CHANGE)(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+//
+// This action routine is called when a new multicast address
+// list is given to the filter. The action routine is given
+// arrays containing the old and new multicast addresses.
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+NDIS_STATUS
+(*ETH_ADDRESS_CHANGE)(
+ IN UINT OldAddressCount,
+ IN CHAR OldAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN UINT NewAddressCount,
+ IN CHAR NewAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+#if 0
+// This action routine is called when a unique multicast address
+// is added to the filter. The action routine is passed an array
+// filled with all of the addresses that are being filtered, as
+// well as the index into this array of the unique address just
+// added. It is also passed an array of contexts, associated
+// with each address; it can store a context for the new address
+// in AddressContexts[NewAddress]. The contexts are passed
+// back to the delete action routine.
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+NDIS_STATUS
+(*ETH_ADDRESS_ADD)(
+ IN UINT CurrentAddressCount,
+ IN CHAR CurrentAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN UINT NewAddress,
+ IN OUT NDIS_HANDLE AddressContexts[],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+//
+// This action routine is called when a unique multicast address
+// is no longer requested for filtering by any binding. The
+// action routine is passed an array filled with the all of the
+// addresses that are *still* being used for multicast filtering.
+// It is also passed the array of contexts for those addresses.
+// The routine is also passed the address of the address being deleted,
+// and the context of the address being deleted (as set during
+// the add action routine).
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+NDIS_STATUS
+(*ETH_ADDRESS_DELETE)(
+ IN UINT CurrentAddressCount,
+ IN CHAR CurrentAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN CHAR OldAddress[ETH_LENGTH_OF_ADDRESS],
+ IN NDIS_HANDLE AddressContexts[],
+ IN NDIS_HANDLE OldAddressContext,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ );
+#endif
+
+//
+// This action routine is called when the mac requests a close for
+// a particular binding *WHILE THE BINDING IS BEING INDICATED TO
+// THE PROTOCOL*. The filtering package can't get rid of the open
+// right away. So this routine will be called as soon as the
+// NdisIndicateReceive returns.
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+VOID
+(*ETH_DEFERRED_CLOSE)(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+typedef ULONG ETH_MASK,*PETH_MASK;
+
+//
+// Maximum number of opens the filter package will support. This is
+// the max so that bit masks can be used instead of a spaghetti of
+// pointers.
+//
+#define ETH_FILTER_MAX_OPENS (sizeof(ULONG) * 8)
+
+//
+// The binding info is threaded on two lists. When
+// the binding is free it is on a single freelist.
+//
+// When the binding is being used it is on a doubly linked
+// index list.
+//
+typedef struct _ETH_BINDING_INFO {
+ NDIS_HANDLE MacBindingHandle;
+ NDIS_HANDLE NdisBindingContext;
+ UINT PacketFilters;
+ ULONG References;
+ struct _ETH_BINDING_INFO *NextOpen;
+ struct _ETH_BINDING_INFO *PrevOpen;
+ BOOLEAN ReceivedAPacket;
+ UCHAR FilterIndex;
+} ETH_BINDING_INFO,*PETH_BINDING_INFO;
+
+//
+// An opaque type that contains a filter database.
+// The MAC need not know how it is structured.
+//
+typedef struct _ETH_FILTER {
+
+ //
+ // Spin lock used to protect the filter from multiple accesses.
+ //
+ PNDIS_SPIN_LOCK Lock;
+
+ //
+ // Pointer to an array of 6 character arrays holding the
+ // multicast addresses requested for filtering.
+ //
+ CHAR (*MulticastAddresses)[ETH_LENGTH_OF_ADDRESS];
+
+ //
+ // Pointer to an array of ETH_MASKS that work in conjuction with
+ // the MulticastAddress array. In the masks, a bit being enabled
+ // indicates that the binding with the given FilterIndex is using
+ // the corresponding address.
+ //
+ ETH_MASK *BindingsUsingAddress;
+
+ //
+ // Combination of all the filters of all the open bindings.
+ //
+ UINT CombinedPacketFilter;
+
+ //
+ // Pointer for traversing the open list.
+ //
+ PETH_BINDING_INFO OpenList;
+
+
+ //
+ // Action routines to be invoked on notable changes in the filter.
+ //
+
+ ETH_ADDRESS_CHANGE AddressChangeAction;
+ ETH_FILTER_CHANGE FilterChangeAction;
+ ETH_DEFERRED_CLOSE CloseAction;
+
+ //
+ // The maximum number of addresses used for filtering.
+ //
+ UINT MaximumMulticastAddresses;
+
+ //
+ // The current number of addresses in the address filter.
+ //
+ UINT NumberOfAddresses;
+
+ //
+ // Bit mask of opens that are available.
+ //
+ ULONG FreeBindingMask;
+
+ //
+ // Address of the adapter.
+ //
+ UCHAR AdapterAddress[ETH_LENGTH_OF_ADDRESS];
+
+} ETH_FILTER,*PETH_FILTER;
+
+
+//
+// Only for internal wrapper use.
+//
+VOID
+EthInitializePackage(
+ VOID
+ );
+
+VOID
+EthReferencePackage(
+ VOID
+ );
+
+VOID
+EthDereferencePackage(
+ VOID
+ );
+
+//
+// Exported functions
+//
+EXPORT
+BOOLEAN
+EthCreateFilter(
+ IN UINT MaximumMulticastAddresses,
+ IN ETH_ADDRESS_CHANGE AddressChangeAction,
+ IN ETH_FILTER_CHANGE FilterChangeAction,
+ IN ETH_DEFERRED_CLOSE CloseAction,
+ IN PUCHAR AdapterAddress,
+ IN PNDIS_SPIN_LOCK Lock,
+ OUT PETH_FILTER *Filter
+ );
+
+EXPORT
+VOID
+EthDeleteFilter(
+ IN PETH_FILTER Filter
+ );
+
+EXPORT
+BOOLEAN
+EthNoteFilterOpenAdapter(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE NdisBindingContext,
+ OUT PNDIS_HANDLE NdisFilterHandle
+ );
+
+EXPORT
+NDIS_STATUS
+EthDeleteFilterOpenAdapter(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+EXPORT
+NDIS_STATUS
+EthChangeFilterAddresses(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT AddressCount,
+ IN CHAR Addresses[][ETH_LENGTH_OF_ADDRESS],
+ IN BOOLEAN Set
+ );
+
+
+#define EthShouldAddressLoopBackMacro(_Filter, _Address, _pfLoopback, _pfSelfDirected) \
+{ \
+ UINT CombinedFilters; \
+ \
+ CombinedFilters = ETH_QUERY_FILTER_CLASSES(_Filter); \
+ \
+ *(_pfLoopback) = FALSE; \
+ *(_pfSelfDirected) = FALSE; \
+ \
+ do \
+ { \
+ /* \
+ * First check if the filter is promiscuous. \
+ */ \
+ \
+ if (CombinedFilters & NDIS_PACKET_TYPE_PROMISCUOUS) \
+ { \
+ *(_pfLoopback) = TRUE; \
+ break; \
+ } \
+ \
+ /* \
+ * Check if it *at least* has the multicast address bit. \
+ */ \
+ \
+ if (ETH_IS_MULTICAST(_Address)) \
+ { \
+ /* \
+ * It is at least a multicast address. Check to see if \
+ * it is a broadcast address. \
+ */ \
+ \
+ if (ETH_IS_BROADCAST(_Address)) \
+ { \
+ if (CombinedFilters & NDIS_PACKET_TYPE_BROADCAST) \
+ { \
+ *(_pfLoopback) = TRUE; \
+ break; \
+ } \
+ else \
+ { \
+ break; \
+ } \
+ } \
+ else \
+ { \
+ if ((CombinedFilters & NDIS_PACKET_TYPE_ALL_MULTICAST) || \
+ (CombinedFilters & NDIS_PACKET_TYPE_MULTICAST)) \
+ { \
+ *(_pfLoopback) = TRUE; \
+ break; \
+ } \
+ } \
+ } \
+ else \
+ { \
+ /* \
+ * Directed to ourself?? \
+ */ \
+ \
+ if ((*(ULONG UNALIGNED *)&(_Address)[2] == \
+ *(ULONG UNALIGNED *)&(_Filter)->AdapterAddress[2]) && \
+ (*(USHORT UNALIGNED *)&(_Address)[0] == \
+ *(USHORT UNALIGNED *)&(_Filter)->AdapterAddress[0])) \
+ { \
+ *(_pfLoopback) = TRUE; \
+ *(_pfSelfDirected) = TRUE; \
+ } \
+ } \
+ } while (FALSE); \
+}
+
+EXPORT
+BOOLEAN
+EthShouldAddressLoopBack(
+ IN PETH_FILTER Filter,
+ IN CHAR Address[ETH_LENGTH_OF_ADDRESS]
+ );
+
+EXPORT
+NDIS_STATUS
+EthFilterAdjust(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT FilterClasses,
+ IN BOOLEAN Set
+ );
+
+EXPORT
+UINT
+EthNumberOfOpenFilterAddresses(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle
+ );
+
+EXPORT
+VOID
+EthQueryGlobalFilterAddresses(
+ OUT PNDIS_STATUS Status,
+ IN PETH_FILTER Filter,
+ IN UINT SizeOfArray,
+ OUT PUINT NumberOfAddresses,
+ IN OUT CHAR AddressArray[][ETH_LENGTH_OF_ADDRESS]
+ );
+
+EXPORT
+VOID
+EthQueryOpenFilterAddresses(
+ OUT PNDIS_STATUS Status,
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN UINT SizeOfArray,
+ OUT PUINT NumberOfAddresses,
+ IN OUT CHAR AddressArray[][ETH_LENGTH_OF_ADDRESS]
+ );
+
+
+EXPORT
+VOID
+EthFilterIndicateReceive(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PCHAR Address,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+EXPORT
+VOID
+EthFilterDprIndicateReceive(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PCHAR Address,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+EXPORT
+VOID
+EthFilterIndicateReceiveComplete(
+ IN PETH_FILTER Filter
+ );
+
+EXPORT
+VOID
+EthFilterDprIndicateReceiveComplete(
+ IN PETH_FILTER Filter
+ );
+
+#endif // _ETH_FILTER_DEFS_
+
diff --git a/private/ntos/ndis/ndis30/ffilter.c b/private/ntos/ndis/ndis30/ffilter.c
new file mode 100644
index 000000000..6a6397669
--- /dev/null
+++ b/private/ntos/ndis/ndis30/ffilter.c
@@ -0,0 +1,3193 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ffilter.c
+
+Abstract:
+
+ This module implements a set of library routines to handle packet
+ filtering for NDIS MAC drivers.
+
+Author:
+
+ Anthony V. Ercolano (Tonye) 03-Aug-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+ Sean Selitrennikoff (SeanSe) converted Efilter.* for FDDI filtering.
+
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+//
+// This constant is used for places where NdisAllocateMemory
+// needs to be called and the HighestAcceptableAddress does
+// not matter.
+//
+
+static const NDIS_PHYSICAL_ADDRESS HighestAcceptableMax =
+ NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
+
+//
+// ZZZ NonPortable definitions.
+//
+#define AllocPhys(s, l) NdisAllocateMemory((PVOID *)(s), (l), 0, HighestAcceptableMax)
+#define FreePhys(s, l) NdisFreeMemory((PVOID)(s), (l), 0)
+#ifdef NDIS_NT
+#define MoveMemory(Destination,Source,Length) RtlMoveMemory(Destination,Source,Length)
+#define ZeroMemory(Destination,Length) RtlZeroMemory(Destination,Length)
+#endif
+
+#ifdef NDIS_DOS
+#define MoveMemory(Destination,Source,Length) memcpy(Destination,Source,Length)
+#define ZeroMemory(Destination,Length) memset(Destination,0,Length)
+#endif
+
+#if DBG
+extern BOOLEAN NdisCheckBadDrivers;
+#endif
+
+//
+// A set of macros to manipulate bitmasks.
+//
+
+//VOID
+//CLEAR_BIT_IN_MASK(
+// IN UINT Offset,
+// IN OUT PFDDI_MASK MaskToClear
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Clear a bit in the bitmask pointed to by the parameter.
+//
+//Arguments:
+//
+// Offset - The offset (from 0) of the bit to altered.
+//
+// MaskToClear - Pointer to the mask to be adjusted.
+//
+//Return Value:
+//
+// None.
+//
+//--*/
+//
+#define CLEAR_BIT_IN_MASK(Offset,MaskToClear) *MaskToClear &= (~(1 << Offset))
+
+//VOID
+//SET_BIT_IN_MASK(
+// IN UINT Offset,
+// IN OUT PFDDI_MASK MaskToSet
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Set a bit in the bitmask pointed to by the parameter.
+//
+//Arguments:
+//
+// Offset - The offset (from 0) of the bit to altered.
+//
+// MaskToSet - Pointer to the mask to be adjusted.
+//
+//Return Value:
+//
+// None.
+//
+//--*/
+#define SET_BIT_IN_MASK(Offset,MaskToSet) *MaskToSet |= (1 << Offset)
+
+//BOOLEAN
+//IS_BIT_SET_IN_MASK(
+// IN UINT Offset,
+// IN FDDI_MASK MaskToTest
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Tests if a particular bit in the bitmask pointed to by the parameter is
+// set.
+//
+//Arguments:
+//
+// Offset - The offset (from 0) of the bit to test.
+//
+// MaskToTest - The mask to be tested.
+//
+//Return Value:
+//
+// Returns TRUE if the bit is set.
+//
+//--*/
+#define IS_BIT_SET_IN_MASK(Offset,MaskToTest) \
+((MaskToTest & (1 << Offset))?(TRUE):(FALSE))
+
+//BOOLEAN
+//IS_MASK_CLEAR(
+// IN FDDI_MASK MaskToTest
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Tests whether there are *any* bits enabled in the mask.
+//
+//Arguments:
+//
+// MaskToTest - The bit mask to test for all clear.
+//
+//Return Value:
+//
+// Will return TRUE if no bits are set in the mask.
+//
+//--*/
+#define IS_MASK_CLEAR(MaskToTest) ((!MaskToTest)?(TRUE):(FALSE))
+
+//VOID
+//CLEAR_MASK(
+// IN OUT PFDDI_MASK MaskToClear
+// );
+//
+///*++
+//
+//Routine Description:
+//
+// Clears a mask.
+//
+//Arguments:
+//
+// MaskToClear - The bit mask to adjust.
+//
+//Return Value:
+//
+// None.
+//
+//--*/
+#define CLEAR_MASK(MaskToClear) *MaskToClear = 0
+
+//
+// VOID
+// FDDI_FILTER_ALLOC_OPEN(
+// IN PFDDI_FILTER Filter,
+// OUT PUINT FilterIndex
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Allocates an open block. This only allocate the index, not memory for
+// the open block.
+//
+//Arguments:
+//
+// Filter - DB from which to allocate the space
+//
+// FilterIndex - pointer to place to store the index.
+//
+//Return Value:
+//
+// FilterIndex of the new open
+//
+//--*/
+#define FDDI_FILTER_ALLOC_OPEN(Filter, FilterIndex)\
+{\
+ UINT i; \
+ for (i=0; i < FDDI_FILTER_MAX_OPENS; i++) { \
+ if (IS_BIT_SET_IN_MASK(i,(Filter)->FreeBindingMask)) { \
+ *(FilterIndex) = i; \
+ CLEAR_BIT_IN_MASK(i, &((Filter)->FreeBindingMask)); \
+ break; \
+ } \
+ } \
+}
+
+//
+// VOID
+// FDDI_FILTER_FREE_OPEN(
+// IN PFDDI_FILTER Filter,
+// IN PFDDI_BINDING_INFO LocalOpen
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Frees an open block. Also frees the memory associated with the open.
+//
+//Arguments:
+//
+// Filter - DB from which to allocate the space
+//
+// FilterIndex - Index to free
+//
+//Return Value:
+//
+// FilterIndex of the new open
+//
+//--*/
+#define FDDI_FILTER_FREE_OPEN(Filter, LocalOpen)\
+{\
+ SET_BIT_IN_MASK(((LocalOpen)->FilterIndex), &((Filter)->FreeBindingMask)); \
+ FreePhys((LocalOpen), sizeof(FDDI_BINDING_INFO));\
+}
+
+
+NDIS_SPIN_LOCK FddiReferenceLock = {0};
+KEVENT FddiPagedInEvent = {0};
+ULONG FddiReferenceCount = 0;
+PVOID FddiImageHandle = {0};
+
+VOID
+FddiInitializePackage(VOID)
+{
+ NdisAllocateSpinLock(&FddiReferenceLock);
+ KeInitializeEvent(
+ &FddiPagedInEvent,
+ NotificationEvent,
+ FALSE
+ );
+}
+
+VOID
+FddiReferencePackage(VOID)
+{
+
+ ACQUIRE_SPIN_LOCK(&FddiReferenceLock);
+
+ FddiReferenceCount++;
+
+ if (FddiReferenceCount == 1) {
+
+ KeResetEvent(
+ &FddiPagedInEvent
+ );
+
+ RELEASE_SPIN_LOCK(&FddiReferenceLock);
+
+ //
+ // Page in all the functions
+ //
+ FddiImageHandle = MmLockPagableCodeSection(FddiCreateFilter);
+
+ //
+ // Signal to everyone to go
+ //
+ KeSetEvent(
+ &FddiPagedInEvent,
+ 0L,
+ FALSE
+ );
+
+ } else {
+
+ RELEASE_SPIN_LOCK(&FddiReferenceLock);
+
+ //
+ // Wait for everything to be paged in
+ //
+ KeWaitForSingleObject(
+ &FddiPagedInEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ NULL
+ );
+
+ }
+
+}
+
+VOID
+FddiDereferencePackage(VOID)
+{
+ ACQUIRE_SPIN_LOCK(&FddiReferenceLock);
+
+ FddiReferenceCount--;
+
+ if (FddiReferenceCount == 0) {
+
+ RELEASE_SPIN_LOCK(&FddiReferenceLock);
+
+ //
+ // Page out all the functions
+ //
+ MmUnlockPagableImageSection(FddiImageHandle);
+
+ } else {
+
+ RELEASE_SPIN_LOCK(&FddiReferenceLock);
+
+ }
+
+}
+
+static
+BOOLEAN
+FindMulticastLongAddress(
+ IN UINT NumberOfAddresses,
+ IN CHAR AddressArray[][FDDI_LENGTH_OF_LONG_ADDRESS],
+ IN CHAR MulticastAddress[FDDI_LENGTH_OF_LONG_ADDRESS],
+ OUT PUINT ArrayIndex
+ );
+
+static
+BOOLEAN
+FindMulticastShortAddress(
+ IN UINT NumberOfAddresses,
+ IN CHAR AddressArray[][FDDI_LENGTH_OF_SHORT_ADDRESS],
+ IN CHAR MulticastAddress[FDDI_LENGTH_OF_SHORT_ADDRESS],
+ OUT PUINT ArrayIndex
+ );
+
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGENDSF, FddiShouldAddressLoopBack)
+#pragma alloc_text(PAGENDSF, FindMulticastShortAddress)
+#pragma alloc_text(PAGENDSF, FindMulticastLongAddress)
+#pragma alloc_text(PAGENDSF, FddiFilterDprIndicateReceiveComplete)
+#pragma alloc_text(PAGENDSF, FddiFilterIndicateReceiveComplete)
+#pragma alloc_text(PAGENDSF, FddiFilterDprIndicateReceive)
+#pragma alloc_text(PAGENDSF, FddiFilterIndicateReceive)
+#pragma alloc_text(PAGENDSF, FddiQueryGlobalFilterShortAddresses)
+#pragma alloc_text(PAGENDSF, FddiQueryGlobalFilterLongAddresses)
+#pragma alloc_text(PAGENDSF, FddiQueryOpenFilterShortAddresses)
+#pragma alloc_text(PAGENDSF, FddiQueryOpenFilterLongAddresses)
+#pragma alloc_text(PAGENDSF, FddiNumberOfOpenFilterShortAddresses)
+#pragma alloc_text(PAGENDSF, FddiNumberOfOpenFilterLongAddresses)
+#pragma alloc_text(PAGENDSF, FddiFilterAdjust)
+#pragma alloc_text(PAGENDSF, FddiChangeFilterShortAddresses)
+#pragma alloc_text(PAGENDSF, FddiChangeFilterLongAddresses)
+#pragma alloc_text(PAGENDSF, FddiDeleteFilterOpenAdapter)
+#pragma alloc_text(PAGENDSF, FddiNoteFilterOpenAdapter)
+#pragma alloc_text(PAGENDSF, FddiCreateFilter)
+
+#endif
+
+
+
+
+BOOLEAN
+FddiCreateFilter(
+ IN UINT MaximumMulticastLongAddresses,
+ IN UINT MaximumMulticastShortAddresses,
+ IN FDDI_ADDRESS_CHANGE AddressChangeAction,
+ IN FDDI_FILTER_CHANGE FilterChangeAction,
+ IN FDDI_DEFERRED_CLOSE CloseAction,
+ IN PUCHAR AdapterLongAddress,
+ IN PUCHAR AdapterShortAddress,
+ IN PNDIS_SPIN_LOCK Lock,
+ OUT PFDDI_FILTER *Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to create and initialize the filter database.
+
+Arguments:
+
+ MaximumMulticastLongAddresses - The maximum number of Long multicast addresses
+ that the MAC will support.
+
+ MaximumMulticastShortAddresses - The maximum number of short multicast addresses
+ that the MAC will support.
+
+ AddressChangeAction - Action routine to call when the list of
+ multicast addresses the card must enable has changed.
+
+ ChangeAction - Action routine to call when a binding sets or clears
+ a particular filter class and it is the first or only binding using
+ the filter class.
+
+ CloseAction - This routine is called if a binding closes while
+ it is being indicated to via NdisIndicateReceive. It will be
+ called upon return from NdisIndicateReceive.
+
+ AdapterLongAddress - the long address of the adapter associated with this filter
+ database.
+
+ AdapterShortAddress - the short address of the adapter associated with this filter
+ database.
+
+ Lock - Pointer to the lock that should be held when mutual exclusion
+ is required.w
+
+ Filter - A pointer to an FDDI_FILTER. This is what is allocated and
+ created by this routine.
+
+Return Value:
+
+ If the function returns false then one of the parameters exceeded
+ what the filter was willing to support.
+
+--*/
+
+{
+
+ PFDDI_FILTER LocalFilter;
+ NDIS_STATUS AllocStatus;
+
+ //
+ // Allocate the database and it's associated arrays.
+ //
+
+ AllocStatus = AllocPhys(&LocalFilter, sizeof(FDDI_FILTER));
+ *Filter = LocalFilter;
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+ return FALSE;
+ }
+
+ ZeroMemory(
+ LocalFilter,
+ sizeof(FDDI_FILTER)
+ );
+
+ if (MaximumMulticastLongAddresses == 0) {
+
+ //
+ // Why 2 and not 1? Why not. A protocol is going to need at least
+ // one to run on this, so let's give one extra one for any user stuff
+ // that may need it.
+ //
+
+ MaximumMulticastLongAddresses = 2;
+
+ }
+
+ if (MaximumMulticastShortAddresses == 0) {
+
+ //
+ // Why 2 and not 1? Why not. A protocol is going to need at least
+ // one to run on this, so let's give one extra one for any user stuff
+ // that may need it.
+ //
+
+ MaximumMulticastShortAddresses = 2;
+
+ }
+
+ {
+ PVOID TmpAlloc;
+
+ AllocStatus = AllocPhys(
+ &TmpAlloc,
+ 2*FDDI_LENGTH_OF_LONG_ADDRESS*MaximumMulticastLongAddresses
+ );
+
+ LocalFilter->MulticastLongAddresses = TmpAlloc;
+
+ }
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+
+ FddiDeleteFilter(LocalFilter);
+ return FALSE;
+
+ }
+
+ {
+ PVOID TmpAlloc;
+
+ AllocStatus = AllocPhys(
+ &TmpAlloc,
+ 2*FDDI_LENGTH_OF_SHORT_ADDRESS*MaximumMulticastShortAddresses
+ );
+
+ LocalFilter->MulticastShortAddresses = TmpAlloc;
+
+ }
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+
+ FddiDeleteFilter(LocalFilter);
+ return FALSE;
+
+ }
+
+ AllocStatus = AllocPhys(
+ &LocalFilter->BindingsUsingLongAddress,
+ 2*sizeof(FDDI_MASK)*MaximumMulticastLongAddresses
+ );
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+
+ FddiDeleteFilter(LocalFilter);
+ return FALSE;
+
+ }
+
+ AllocStatus = AllocPhys(
+ &LocalFilter->BindingsUsingShortAddress,
+ 2*sizeof(FDDI_MASK)*MaximumMulticastShortAddresses
+ );
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+
+ FddiDeleteFilter(LocalFilter);
+ return FALSE;
+
+ }
+
+ FddiReferencePackage();
+
+ LocalFilter->FreeBindingMask = (ULONG)(-1);
+ LocalFilter->OpenList = NULL;
+
+ FDDI_COPY_NETWORK_ADDRESS(LocalFilter->AdapterLongAddress,
+ AdapterLongAddress,
+ FDDI_LENGTH_OF_LONG_ADDRESS
+ );
+
+ FDDI_COPY_NETWORK_ADDRESS(LocalFilter->AdapterShortAddress,
+ AdapterShortAddress,
+ FDDI_LENGTH_OF_SHORT_ADDRESS
+ );
+
+ LocalFilter->Lock = Lock;
+ LocalFilter->AddressChangeAction = AddressChangeAction;
+ LocalFilter->FilterChangeAction = FilterChangeAction;
+ LocalFilter->CloseAction = CloseAction;
+ LocalFilter->NumberOfLongAddresses = 0;
+ LocalFilter->NumberOfShortAddresses = 0;
+ LocalFilter->MaximumMulticastLongAddresses = MaximumMulticastLongAddresses;
+ LocalFilter->MaximumMulticastShortAddresses = MaximumMulticastShortAddresses;
+
+ return TRUE;
+}
+
+//
+// NOTE: THIS CANNOT BE PAGABLE
+//
+VOID
+FddiDeleteFilter(
+ IN PFDDI_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to delete the memory associated with a filter
+ database. Note that this routines *ASSUMES* that the database
+ has been cleared of any active filters.
+
+Arguments:
+
+ Filter - A pointer to an FDDI_FILTER to be deleted.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ASSERT(Filter->FreeBindingMask == (FDDI_MASK)-1);
+ ASSERT(Filter->OpenList == NULL);
+
+ if (Filter->MulticastLongAddresses) {
+
+ FreePhys(
+ Filter->MulticastLongAddresses,
+ 2*FDDI_LENGTH_OF_LONG_ADDRESS*Filter->MaximumMulticastLongAddresses
+ );
+
+ }
+
+ if (Filter->MulticastShortAddresses) {
+
+ FreePhys(
+ Filter->MulticastShortAddresses,
+ 2*FDDI_LENGTH_OF_SHORT_ADDRESS*Filter->MaximumMulticastShortAddresses
+ );
+
+ }
+
+ if (Filter->BindingsUsingLongAddress) {
+
+ FreePhys(
+ Filter->BindingsUsingLongAddress,
+ 2*sizeof(FDDI_MASK)*Filter->MaximumMulticastLongAddresses
+ );
+
+ }
+
+ if (Filter->BindingsUsingShortAddress) {
+
+ FreePhys(
+ Filter->BindingsUsingShortAddress,
+ 2*sizeof(FDDI_MASK)*Filter->MaximumMulticastShortAddresses
+ );
+
+ }
+
+ FreePhys(Filter, sizeof(FDDI_FILTER));
+
+ FddiDereferencePackage();
+}
+
+
+BOOLEAN
+FddiNoteFilterOpenAdapter(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE NdisBindingContext,
+ OUT PNDIS_HANDLE NdisFilterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to add a new binding to the filter database.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE DATABASE IS LOCKED WHEN
+ IT IS CALLED.
+
+Arguments:
+
+ Filter - A pointer to the previously created and initialized filter
+ database.
+
+ MacBindingHandle - The MAC supplied value to the protocol in response
+ to a call to FddiOpenAdapter.
+
+ NdisBindingContext - An NDIS supplied value to the call to FddiOpenAdapter.
+
+ NdisFilterHandle - A pointer to this open.
+
+Return Value:
+
+ Will return false if creating a new filter index will cause the maximum
+ number of filter indexes to be exceeded.
+
+--*/
+
+{
+
+ //
+ // Will hold the value of the filter index so that we
+ // need not indirectly address through pointer parameter.
+ //
+ UINT LocalIndex;
+
+ NDIS_STATUS AllocStatus;
+
+ //
+ // Pointer to new open block.
+ //
+ PFDDI_BINDING_INFO LocalOpen;
+
+ PNDIS_OPEN_BLOCK NdisOpen = (PNDIS_OPEN_BLOCK)NdisBindingContext;
+
+
+ //
+ // Get the first free binding slot and remove that slot from
+ // the free list. We check to see if the list is empty.
+ //
+
+
+ if (Filter->FreeBindingMask == 0) {
+
+ return FALSE;
+
+ }
+
+ AllocStatus = AllocPhys(
+ &LocalOpen,
+ sizeof(FDDI_BINDING_INFO)
+ );
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Get place for the open and insert it.
+ //
+
+ FDDI_FILTER_ALLOC_OPEN(Filter, &LocalIndex);
+
+ LocalOpen->NextOpen = Filter->OpenList;
+
+ if (Filter->OpenList != NULL) {
+ Filter->OpenList->PrevOpen = LocalOpen;
+ }
+
+ LocalOpen->PrevOpen = NULL;
+
+ Filter->OpenList = LocalOpen;
+
+ LocalOpen->FilterIndex = (UCHAR)LocalIndex;
+ LocalOpen->References = 1;
+ LocalOpen->MacBindingHandle = MacBindingHandle;
+ LocalOpen->NdisBindingContext = NdisBindingContext;
+ LocalOpen->PacketFilters = 0;
+ LocalOpen->ReceivedAPacket = FALSE;
+
+ *NdisFilterHandle = (NDIS_HANDLE)LocalOpen;
+
+ return TRUE;
+
+}
+
+
+NDIS_STATUS
+FddiDeleteFilterOpenAdapter(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ When an adapter is being closed this routine should
+ be called to delete knowledge of the adapter from
+ the filter database. This routine is likely to call
+ action routines associated with clearing filter classes
+ and addresses.
+
+ NOTE: THIS ROUTINE SHOULD ****NOT**** BE CALLED IF THE ACTION
+ ROUTINES FOR DELETING THE FILTER CLASSES OR THE MULTICAST ADDRESSES
+ HAVE ANY POSSIBILITY OF RETURNING A STATUS OTHER THAN NDIS_STATUS_PENDING
+ OR NDIS_STATUS_SUCCESS. WHILE THESE ROUTINES WILL NOT BUGCHECK IF
+ SUCH A THING IS DONE, THE CALLER WILL PROBABLY FIND IT DIFFICULT
+ TO CODE A CLOSE ROUTINE!
+
+ NOTE: THIS ROUTINE ASSUMES THAT IT IS CALLED WITH THE LOCK HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routines,
+ this will be passed to it.
+
+Return Value:
+
+ If action routines are called by the various address and filtering
+ routines the this routine will likely return the status returned
+ by those routines. The exception to this rule is noted below.
+
+ Given that the filter and address deletion routines return a status
+ NDIS_STATUS_PENDING or NDIS_STATUS_SUCCESS this routine will then
+ try to return the filter index to the freelist. If the routine
+ detects that this binding is currently being indicated to via
+ NdisIndicateReceive, this routine will return a status of
+ NDIS_STATUS_CLOSING_INDICATING.
+
+--*/
+
+{
+
+ //
+ // Holds the status returned from the packet filter and address
+ // deletion routines. Will be used to return the status to
+ // the caller of this routine.
+ //
+ NDIS_STATUS StatusToReturn;
+
+ //
+ // Local variable.
+ //
+ PFDDI_BINDING_INFO LocalOpen = (PFDDI_BINDING_INFO)NdisFilterHandle;
+
+ StatusToReturn = FddiFilterAdjust(
+ Filter,
+ NdisFilterHandle,
+ NdisRequest,
+ (UINT)0,
+ FALSE
+ );
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS ||
+ StatusToReturn == NDIS_STATUS_PENDING) {
+
+ NDIS_STATUS StatusToReturn2;
+
+ StatusToReturn2 = FddiChangeFilterLongAddresses(
+ Filter,
+ NdisFilterHandle,
+ NdisRequest,
+ 0,
+ NULL,
+ FALSE
+ );
+
+ if (StatusToReturn2 != NDIS_STATUS_SUCCESS) {
+
+ StatusToReturn = StatusToReturn2;
+
+ }
+
+ if ((StatusToReturn == NDIS_STATUS_SUCCESS) ||
+ (StatusToReturn == NDIS_STATUS_PENDING)) {
+
+
+ StatusToReturn2 = FddiChangeFilterShortAddresses(
+ Filter,
+ NdisFilterHandle,
+ NdisRequest,
+ 0,
+ NULL,
+ FALSE
+ );
+
+ if (StatusToReturn2 != NDIS_STATUS_SUCCESS) {
+
+ StatusToReturn = StatusToReturn2;
+
+ }
+
+ }
+
+ }
+
+
+ if ((StatusToReturn == NDIS_STATUS_SUCCESS) ||
+ (StatusToReturn == NDIS_STATUS_PENDING)) {
+
+ //
+ // Remove the reference from the original open.
+ //
+
+ if (--(LocalOpen->References) == 0) {
+
+ //
+ // Remove it from the list.
+ //
+
+ if (LocalOpen->NextOpen != NULL) {
+
+ LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen;
+
+ }
+
+ if (LocalOpen->PrevOpen != NULL) {
+
+ LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen;
+
+ } else {
+
+ Filter->OpenList = LocalOpen->NextOpen;
+
+ }
+
+
+ //
+ // First we finish any NdisIndicateReceiveComplete that
+ // may be needed for this binding.
+ //
+
+ if (LocalOpen->ReceivedAPacket) {
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ }
+
+ FDDI_FILTER_FREE_OPEN(Filter, LocalOpen);
+
+ } else {
+
+ //
+ // Let the caller know that there is a reference to the open
+ // by the receive indication. The close action routine will be
+ // called upon return from NdisIndicateReceive.
+ //
+
+ StatusToReturn = NDIS_STATUS_CLOSING_INDICATING;
+
+ }
+
+ }
+
+ return StatusToReturn;
+
+}
+
+
+NDIS_STATUS
+FddiChangeFilterLongAddresses(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT AddressCount,
+ IN CHAR Addresses[][FDDI_LENGTH_OF_LONG_ADDRESS],
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ The ChangeFilterAddress routine will call an action
+ routine when the overall multicast address list for the adapter
+ has changed.
+
+ If the action routine returns a value other than pending or
+ success then this routine has no effect on the multicast address
+ list for the open or for the adapter as a whole.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routine,
+ this will be passed to it.
+
+ AddressCount - The number of elements (addresses,
+ not bytes) in MulticastAddressList.
+
+ Addresses - The new multicast address list for this
+ binding. This is a sequence of FDDI_LENGTH_OF_LONG_ADDRESS byte
+ addresses, with no padding between them.
+
+ Set - A boolean that determines whether the multicast addresses
+ are being adjusted due to a set or because of a close. (The filtering
+ routines don't care, the MAC might.)
+
+Return Value:
+
+ If it calls the action routine then it will return the
+ status returned by the action routine. If the status
+ returned by the action routine is anything other than
+ NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
+ will be returned to the state it was in upon entrance to this
+ routine.
+
+ If the action routine is not called this routine will return
+ the following statum:
+
+ NDIS_STATUS_SUCCESS - If the new packet filters doesn't change
+ the combined mask of all bindings packet filters.
+
+--*/
+
+{
+ //
+ // Holds the status returned to the user of this routine, if the
+ // action routine is not called then the status will be success,
+ // otherwise, it is whatever the action routine returns.
+ //
+ NDIS_STATUS StatusOfChange;
+
+ //
+ // Saves the original length of the address array.
+ //
+ UINT InitialArraySize;
+
+ //
+ // Set true when the address array changes
+ //
+ BOOLEAN AddressesChanged = FALSE;
+
+ //
+ // Use to save data if needed.
+ //
+ PVOID TmpAddressArray, TmpMaskArray;
+
+ //
+ // Simple iteration variables.
+ //
+ UINT ArrayIndex, i;
+
+
+ //
+ // Simple Temp variable
+ //
+ PCHAR CurrentAddress;
+
+ PFDDI_BINDING_INFO LocalOpen = (PFDDI_BINDING_INFO)NdisFilterHandle;
+
+
+ TmpAddressArray =
+ (PUCHAR)Filter->MulticastLongAddresses +
+ (FDDI_LENGTH_OF_LONG_ADDRESS*Filter->MaximumMulticastLongAddresses);
+
+ TmpMaskArray =
+ (PUCHAR)Filter->BindingsUsingLongAddress +
+ (sizeof(FDDI_MASK)*Filter->MaximumMulticastLongAddresses);
+
+
+ //
+ // We have to save the old mask array in
+ // case we need to restore it. If we need
+ // to save the address array too we will
+ // do that later.
+ //
+
+ MoveMemory(
+ TmpMaskArray,
+ (PVOID)Filter->BindingsUsingLongAddress,
+ Filter->NumberOfLongAddresses * sizeof(FDDI_MASK)
+ );
+
+ //
+ // We have to save the old address array in
+ // case we need to restore it. If we need
+ // to save the address array too we will
+ // do that later.
+ //
+
+ MoveMemory(
+ TmpAddressArray,
+ (PVOID)Filter->MulticastLongAddresses,
+ Filter->NumberOfLongAddresses * FDDI_LENGTH_OF_LONG_ADDRESS
+ );
+
+ InitialArraySize = Filter->NumberOfLongAddresses;
+
+
+ //
+ // Now modify the original array...
+ //
+
+ //
+ // First go through and turn off the bit for this
+ // binding throughout the array.
+ //
+
+ for (i=0; i<(Filter->NumberOfLongAddresses); i++) {
+
+ CLEAR_BIT_IN_MASK(
+ LocalOpen->FilterIndex,
+ &(Filter->BindingsUsingLongAddress[i])
+ );
+
+ }
+
+
+ //
+ // Now go through the new addresses for this binding,
+ // and insert them into the array.
+ //
+
+ for (i=0; i<AddressCount; i++) {
+
+ CurrentAddress = ((PCHAR)Addresses) + (i*FDDI_LENGTH_OF_LONG_ADDRESS);
+
+ if (FindMulticastLongAddress(
+ Filter->NumberOfLongAddresses,
+ Filter->MulticastLongAddresses,
+ CurrentAddress,
+ &ArrayIndex)) {
+
+ //
+ // The address is there, so just turn the bit
+ // back on.
+ //
+
+ SET_BIT_IN_MASK(
+ LocalOpen->FilterIndex,
+ &Filter->BindingsUsingLongAddress[ArrayIndex]
+ );
+
+ } else {
+
+ //
+ // The address was not found, add it.
+ //
+ // NOTE: Here we temporarily need more array
+ // space then we may finally, but for now this
+ // will work.
+ //
+
+ if (Filter->NumberOfLongAddresses < Filter->MaximumMulticastLongAddresses) {
+
+ //
+ // Save the address array if it hasn't been.
+ //
+
+ AddressesChanged = TRUE;
+
+ MoveMemory(
+ Filter->MulticastLongAddresses[ArrayIndex+1],
+ Filter->MulticastLongAddresses[ArrayIndex],
+ (Filter->NumberOfLongAddresses-ArrayIndex)*FDDI_LENGTH_OF_LONG_ADDRESS
+ );
+
+ FDDI_COPY_NETWORK_ADDRESS(
+ Filter->MulticastLongAddresses[ArrayIndex],
+ CurrentAddress,
+ FDDI_LENGTH_OF_LONG_ADDRESS
+ );
+
+ MoveMemory(
+ &(Filter->BindingsUsingLongAddress[ArrayIndex+1]),
+ &(Filter->BindingsUsingLongAddress[ArrayIndex]),
+ (Filter->NumberOfLongAddresses-ArrayIndex)*sizeof(FDDI_MASK)
+ );
+
+ CLEAR_MASK(&Filter->BindingsUsingLongAddress[ArrayIndex]);
+
+ SET_BIT_IN_MASK(
+ LocalOpen->FilterIndex,
+ &Filter->BindingsUsingLongAddress[ArrayIndex]
+ );
+
+ Filter->NumberOfLongAddresses++;
+
+ } else {
+
+ //
+ // No room in the array, oh well.
+ //
+
+ MoveMemory(
+ (PVOID)Filter->MulticastLongAddresses,
+ TmpAddressArray,
+ InitialArraySize * FDDI_LENGTH_OF_LONG_ADDRESS
+ );
+
+ MoveMemory(
+ (PVOID)Filter->BindingsUsingLongAddress,
+ TmpMaskArray,
+ InitialArraySize * sizeof(FDDI_MASK)
+ );
+
+ Filter->NumberOfLongAddresses = InitialArraySize;
+
+ return NDIS_STATUS_MULTICAST_FULL;
+
+ }
+
+ }
+
+ }
+
+
+ //
+ // Finally we have to remove any addresses from
+ // the multicast array if they have no bits on any more.
+ //
+ for (ArrayIndex = 0; ArrayIndex < Filter->NumberOfLongAddresses; ) {
+
+ if (IS_MASK_CLEAR(Filter->BindingsUsingLongAddress[ArrayIndex])) {
+
+ //
+ // yes it is clear, so we have to shift everything
+ // above it down one.
+ //
+
+ AddressesChanged = TRUE;
+
+ MoveMemory(
+ Filter->MulticastLongAddresses[ArrayIndex],
+ Filter->MulticastLongAddresses[ArrayIndex+1],
+ (Filter->NumberOfLongAddresses-(ArrayIndex+1))
+ *FDDI_LENGTH_OF_LONG_ADDRESS
+ );
+
+ MoveMemory(
+ &Filter->BindingsUsingLongAddress[ArrayIndex],
+ &Filter->BindingsUsingLongAddress[ArrayIndex+1],
+ (Filter->NumberOfLongAddresses-(ArrayIndex+1))*(sizeof(FDDI_MASK))
+ );
+
+ Filter->NumberOfLongAddresses--;
+
+ } else {
+
+ ArrayIndex++;
+
+ }
+
+ }
+
+ //
+ // If the address array has changed, we have to call the
+ // action array to inform the adapter of this.
+ //
+
+ if (AddressesChanged) {
+
+ StatusOfChange = Filter->AddressChangeAction(
+ InitialArraySize,
+ TmpAddressArray,
+ Filter->NumberOfLongAddresses,
+ Filter->MulticastLongAddresses,
+ Filter->NumberOfShortAddresses,
+ Filter->MulticastShortAddresses,
+ Filter->NumberOfShortAddresses,
+ Filter->MulticastShortAddresses,
+ LocalOpen->MacBindingHandle,
+ NdisRequest,
+ Set
+ );
+
+ if ((StatusOfChange != NDIS_STATUS_SUCCESS) &&
+ (StatusOfChange != NDIS_STATUS_PENDING)) {
+
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+
+ MoveMemory(
+ (PVOID)Filter->MulticastLongAddresses,
+ TmpAddressArray,
+ InitialArraySize * FDDI_LENGTH_OF_LONG_ADDRESS
+ );
+
+ MoveMemory(
+ (PVOID)Filter->MulticastLongAddresses,
+ TmpAddressArray,
+ InitialArraySize * FDDI_LENGTH_OF_LONG_ADDRESS
+ );
+
+ }
+
+ } else {
+
+ StatusOfChange = NDIS_STATUS_SUCCESS;
+
+ }
+
+
+ return StatusOfChange;
+
+
+}
+
+
+NDIS_STATUS
+FddiChangeFilterShortAddresses(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT AddressCount,
+ IN CHAR Addresses[][FDDI_LENGTH_OF_SHORT_ADDRESS],
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ The ChangeFilterAddress routine will call an action
+ routine when the overall multicast address list for the adapter
+ has changed.
+
+ If the action routine returns a value other than pending or
+ success then this routine has no effect on the multicast address
+ list for the open or for the adapter as a whole.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routine,
+ this will be passed to it.
+
+ AddressCount - The number of elements (addresses,
+ not bytes) in MulticastAddressList.
+
+ Addresses - The new multicast address list for this
+ binding. This is a sequence of FDDI_LENGTH_OF_SHORT_ADDRESS byte
+ addresses, with no padding between them.
+
+ Set - A boolean that determines whether the multicast addresses
+ are being adjusted due to a set or because of a close. (The filtering
+ routines don't care, the MAC might.)
+
+Return Value:
+
+ If it calls the action routine then it will return the
+ status returned by the action routine. If the status
+ returned by the action routine is anything other than
+ NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
+ will be returned to the state it was in upon entrance to this
+ routine.
+
+ If the action routine is not called this routine will return
+ the following statum:
+
+ NDIS_STATUS_SUCCESS - If the new packet filters doesn't change
+ the combined mask of all bindings packet filters.
+
+--*/
+
+{
+ //
+ // Holds the status returned to the user of this routine, if the
+ // action routine is not called then the status will be success,
+ // otherwise, it is whatever the action routine returns.
+ //
+ NDIS_STATUS StatusOfChange;
+
+ //
+ // Saves the original length of the address array.
+ //
+ UINT InitialArraySize;
+
+ //
+ // Set true when the address array changes
+ //
+ BOOLEAN AddressesChanged = FALSE;
+
+ //
+ // Use to save data if needed.
+ //
+ PVOID TmpAddressArray, TmpMaskArray;
+
+ //
+ // Simple iteration variables.
+ //
+ UINT ArrayIndex, i;
+
+
+ //
+ // Simple Temp variable
+ //
+ PCHAR CurrentAddress;
+
+ PFDDI_BINDING_INFO LocalOpen = (PFDDI_BINDING_INFO)NdisFilterHandle;
+
+
+ TmpAddressArray =
+ (PUCHAR)Filter->MulticastShortAddresses +
+ (FDDI_LENGTH_OF_SHORT_ADDRESS*Filter->MaximumMulticastShortAddresses);
+
+ TmpMaskArray =
+ (PUCHAR)Filter->BindingsUsingShortAddress +
+ (sizeof(FDDI_MASK)*Filter->MaximumMulticastShortAddresses);
+
+
+ //
+ // We have to save the old mask array in
+ // case we need to restore it. If we need
+ // to save the address array too we will
+ // do that later.
+ //
+
+ MoveMemory(
+ TmpMaskArray,
+ (PVOID)Filter->BindingsUsingShortAddress,
+ Filter->NumberOfShortAddresses * sizeof(FDDI_MASK)
+ );
+
+ //
+ // We have to save the old address array in
+ // case we need to restore it. If we need
+ // to save the address array too we will
+ // do that later.
+ //
+
+ MoveMemory(
+ TmpAddressArray,
+ (PVOID)Filter->MulticastShortAddresses,
+ Filter->NumberOfShortAddresses * FDDI_LENGTH_OF_SHORT_ADDRESS
+ );
+
+ InitialArraySize = Filter->NumberOfShortAddresses;
+
+
+ //
+ // Now modify the original array...
+ //
+
+ //
+ // First go through and turn off the bit for this
+ // binding throughout the array.
+ //
+
+ for (i=0; i<(Filter->NumberOfShortAddresses); i++) {
+
+ CLEAR_BIT_IN_MASK(
+ LocalOpen->FilterIndex,
+ &(Filter->BindingsUsingShortAddress[i])
+ );
+
+ }
+
+
+ //
+ // Now go through the new addresses for this binding,
+ // and insert them into the array.
+ //
+
+ for (i=0; i<AddressCount; i++) {
+
+ CurrentAddress = ((PCHAR)Addresses) + (i*FDDI_LENGTH_OF_SHORT_ADDRESS);
+
+ if (FindMulticastShortAddress(
+ Filter->NumberOfShortAddresses,
+ Filter->MulticastShortAddresses,
+ CurrentAddress,
+ &ArrayIndex)) {
+
+ //
+ // The address is there, so just turn the bit
+ // back on.
+ //
+
+ SET_BIT_IN_MASK(
+ LocalOpen->FilterIndex,
+ &Filter->BindingsUsingShortAddress[ArrayIndex]
+ );
+
+ } else {
+
+ //
+ // The address was not found, add it.
+ //
+ // NOTE: Here we temporarily need more array
+ // space then we may finally, but for now this
+ // will work.
+ //
+
+ if (Filter->NumberOfShortAddresses < Filter->MaximumMulticastShortAddresses) {
+
+ //
+ // Save the address array if it hasn't been.
+ //
+
+ AddressesChanged = TRUE;
+
+ MoveMemory(
+ Filter->MulticastShortAddresses[ArrayIndex+1],
+ Filter->MulticastShortAddresses[ArrayIndex],
+ (Filter->NumberOfShortAddresses-ArrayIndex)*FDDI_LENGTH_OF_SHORT_ADDRESS
+ );
+
+ FDDI_COPY_NETWORK_ADDRESS(
+ Filter->MulticastShortAddresses[ArrayIndex],
+ CurrentAddress,
+ FDDI_LENGTH_OF_SHORT_ADDRESS
+ );
+
+ MoveMemory(
+ &(Filter->BindingsUsingShortAddress[ArrayIndex+1]),
+ &(Filter->BindingsUsingShortAddress[ArrayIndex]),
+ (Filter->NumberOfShortAddresses-ArrayIndex)*sizeof(FDDI_MASK)
+ );
+
+ CLEAR_MASK(&Filter->BindingsUsingShortAddress[ArrayIndex]);
+
+ SET_BIT_IN_MASK(
+ LocalOpen->FilterIndex,
+ &Filter->BindingsUsingShortAddress[ArrayIndex]
+ );
+
+ Filter->NumberOfShortAddresses++;
+
+ } else {
+
+ //
+ // No room in the array, oh well.
+ //
+
+ MoveMemory(
+ (PVOID)Filter->MulticastShortAddresses,
+ TmpAddressArray,
+ InitialArraySize * FDDI_LENGTH_OF_SHORT_ADDRESS
+ );
+
+ MoveMemory(
+ (PVOID)Filter->BindingsUsingShortAddress,
+ TmpMaskArray,
+ InitialArraySize * sizeof(FDDI_MASK)
+ );
+
+ Filter->NumberOfShortAddresses = InitialArraySize;
+
+ return NDIS_STATUS_MULTICAST_FULL;
+
+ }
+
+ }
+
+ }
+
+
+ //
+ // Finally we have to remove any addresses from
+ // the multicast array if they have no bits on any more.
+ //
+ for (ArrayIndex = 0; ArrayIndex < Filter->NumberOfShortAddresses; ) {
+
+ if (IS_MASK_CLEAR(Filter->BindingsUsingShortAddress[ArrayIndex])) {
+
+ //
+ // yes it is clear, so we have to shift everything
+ // above it down one.
+ //
+
+ AddressesChanged = TRUE;
+
+ MoveMemory(
+ Filter->MulticastShortAddresses[ArrayIndex],
+ Filter->MulticastShortAddresses[ArrayIndex+1],
+ (Filter->NumberOfShortAddresses-(ArrayIndex+1))
+ *FDDI_LENGTH_OF_SHORT_ADDRESS
+ );
+
+ MoveMemory(
+ &Filter->BindingsUsingShortAddress[ArrayIndex],
+ &Filter->BindingsUsingShortAddress[ArrayIndex+1],
+ (Filter->NumberOfShortAddresses-(ArrayIndex+1))*(sizeof(FDDI_MASK))
+ );
+
+ Filter->NumberOfShortAddresses--;
+
+ } else {
+
+ ArrayIndex++;
+
+ }
+
+ }
+
+ //
+ // If the address array has changed, we have to call the
+ // action array to inform the adapter of this.
+ //
+
+ if (AddressesChanged) {
+
+ StatusOfChange = Filter->AddressChangeAction(
+ Filter->NumberOfLongAddresses,
+ Filter->MulticastLongAddresses,
+ Filter->NumberOfLongAddresses,
+ Filter->MulticastLongAddresses,
+ InitialArraySize,
+ TmpAddressArray,
+ Filter->NumberOfShortAddresses,
+ Filter->MulticastShortAddresses,
+ LocalOpen->MacBindingHandle,
+ NdisRequest,
+ Set
+ );
+
+ if ((StatusOfChange != NDIS_STATUS_SUCCESS) &&
+ (StatusOfChange != NDIS_STATUS_PENDING)) {
+
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+
+ MoveMemory(
+ (PVOID)Filter->MulticastShortAddresses,
+ TmpAddressArray,
+ InitialArraySize * FDDI_LENGTH_OF_SHORT_ADDRESS
+ );
+
+ MoveMemory(
+ (PVOID)Filter->MulticastShortAddresses,
+ TmpAddressArray,
+ InitialArraySize * FDDI_LENGTH_OF_SHORT_ADDRESS
+ );
+
+ }
+
+ } else {
+
+ StatusOfChange = NDIS_STATUS_SUCCESS;
+
+ }
+
+
+ return StatusOfChange;
+
+}
+
+
+NDIS_STATUS
+FddiFilterAdjust(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT FilterClasses,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ The FilterAdjust routine will call an action routine when a
+ particular filter class is changes from not being used by any
+ binding to being used by at least one binding or vice versa.
+
+ If the action routine returns a value other than pending or
+ success then this routine has no effect on the packet filters
+ for the open or for the adapter as a whole.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - A pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routine,
+ this will be passed to it.
+
+ FilterClasses - The filter classes that are to be added or
+ deleted.
+
+ Set - A boolean that determines whether the filter classes
+ are being adjusted due to a set or because of a close. (The filtering
+ routines don't care, the MAC might.)
+
+Return Value:
+
+ If it calls the action routine then it will return the
+ status returned by the action routine. If the status
+ returned by the action routine is anything other than
+ NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
+ will be returned to the state it was in upon entrance to this
+ routine.
+
+ If the action routine is not called this routine will return
+ the following statum:
+
+ NDIS_STATUS_SUCCESS - If the new packet filters doesn't change
+ the combined mask of all bindings packet filters.
+
+--*/
+
+{
+ //
+ // Contains the value of the combined filter classes before
+ // it is adjusted.
+ //
+ UINT OldCombined = Filter->CombinedPacketFilter;
+
+ PFDDI_BINDING_INFO LocalOpen = (PFDDI_BINDING_INFO)NdisFilterHandle;
+ PFDDI_BINDING_INFO OpenList;
+
+ //
+ // Contains the value of the particlar opens packet filters
+ // prior to the change. We save this incase the action
+ // routine (if called) returns an "error" status.
+ //
+ UINT OldOpenFilters = LocalOpen->PacketFilters;
+
+ //
+ // Holds the status returned to the user of this routine, if the
+ // action routine is not called then the status will be success,
+ // otherwise, it is whatever the action routine returns.
+ //
+ NDIS_STATUS StatusOfAdjust;
+
+ //
+ // Set the new filter information for the open.
+ //
+
+ LocalOpen->PacketFilters = FilterClasses;
+
+ //
+ // We always have to reform the compbined filter since
+ // this filter index may have been the only filter index
+ // to use a particular bit.
+ //
+
+
+ for (
+ OpenList = Filter->OpenList,
+ Filter->CombinedPacketFilter = 0;
+ OpenList != NULL;
+ OpenList = OpenList->NextOpen
+ ) {
+
+ Filter->CombinedPacketFilter |=
+ OpenList->PacketFilters;
+
+ }
+
+ if (OldCombined != Filter->CombinedPacketFilter) {
+
+ StatusOfAdjust = Filter->FilterChangeAction(
+ OldCombined,
+ Filter->CombinedPacketFilter,
+ LocalOpen->MacBindingHandle,
+ NdisRequest,
+ Set
+ );
+
+ if ((StatusOfAdjust != NDIS_STATUS_SUCCESS) &&
+ (StatusOfAdjust != NDIS_STATUS_PENDING)) {
+
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+
+ LocalOpen->PacketFilters = OldOpenFilters;
+ Filter->CombinedPacketFilter = OldCombined;
+
+ }
+
+ } else {
+
+ StatusOfAdjust = NDIS_STATUS_SUCCESS;
+
+ }
+
+ return StatusOfAdjust;
+
+}
+
+
+UINT
+FddiNumberOfOpenFilterLongAddresses(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine counts the number of multicast addresses that a specific
+ open has.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to open block.
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ UINT IndexOfAddress;
+ UINT CountOfAddresses = 0;
+
+ UINT FilterIndex = ((PFDDI_BINDING_INFO)NdisFilterHandle)->FilterIndex;
+
+ for(IndexOfAddress=0;
+ IndexOfAddress < Filter->NumberOfLongAddresses;
+ IndexOfAddress++
+ ){
+
+ if (IS_BIT_SET_IN_MASK(FilterIndex,
+ Filter->BindingsUsingLongAddress[IndexOfAddress])) {
+
+ CountOfAddresses++;
+
+
+ }
+
+ }
+
+ return(CountOfAddresses);
+
+}
+
+
+UINT
+FddiNumberOfOpenFilterShortAddresses(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine counts the number of multicast addresses that a specific
+ open has.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to open block.
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ UINT IndexOfAddress;
+ UINT CountOfAddresses = 0;
+
+ UINT FilterIndex = ((PFDDI_BINDING_INFO)NdisFilterHandle)->FilterIndex;
+
+ for(IndexOfAddress=0;
+ IndexOfAddress < Filter->NumberOfShortAddresses;
+ IndexOfAddress++
+ ){
+
+ if (IS_BIT_SET_IN_MASK(FilterIndex,
+ Filter->BindingsUsingShortAddress[IndexOfAddress])) {
+
+ CountOfAddresses++;
+
+
+ }
+
+ }
+
+ return(CountOfAddresses);
+
+}
+
+
+VOID
+FddiQueryOpenFilterLongAddresses(
+ OUT PNDIS_STATUS Status,
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN UINT SizeOfArray,
+ OUT PUINT NumberOfAddresses,
+ OUT CHAR AddressArray[][FDDI_LENGTH_OF_LONG_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ The routine should be used by the MAC before
+ it actually alters the hardware registers to effect a
+ filtering hardware. This is usefull if another binding
+ has altered the address list since the action routine
+ is called.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Status - A pointer to the status of the call, NDIS_STATUS_SUCCESS or
+ NDIS_STATUS_FAILURE. Use EthNumberOfOpenAddresses() to get the
+ size that is needed.
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to the open block
+
+ SizeOfArray - The byte count of the AddressArray.
+
+ NumberOfAddresses - The number of addresses written to the array.
+
+ AddressArray - Will be filled with the addresses currently in the
+ multicast address list.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ UINT IndexOfAddress;
+ UINT CountOfAddresses = 0;
+ UINT FilterIndex = ((PFDDI_BINDING_INFO)NdisFilterHandle)->FilterIndex;
+
+ for(IndexOfAddress=0;
+ IndexOfAddress < Filter->NumberOfLongAddresses;
+ IndexOfAddress++
+ ){
+
+ if (IS_BIT_SET_IN_MASK(FilterIndex,
+ Filter->BindingsUsingLongAddress[IndexOfAddress])) {
+
+ if (SizeOfArray < FDDI_LENGTH_OF_LONG_ADDRESS) {
+
+ *Status = NDIS_STATUS_FAILURE;
+
+ *NumberOfAddresses = 0;
+
+ return;
+
+ }
+
+ SizeOfArray -= FDDI_LENGTH_OF_LONG_ADDRESS;
+
+ MoveMemory(
+ AddressArray[CountOfAddresses],
+ Filter->MulticastLongAddresses[IndexOfAddress],
+ FDDI_LENGTH_OF_LONG_ADDRESS
+ );
+
+ CountOfAddresses++;
+
+ }
+
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ *NumberOfAddresses = CountOfAddresses;
+
+ return;
+
+}
+
+
+VOID
+FddiQueryOpenFilterShortAddresses(
+ OUT PNDIS_STATUS Status,
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN UINT SizeOfArray,
+ OUT PUINT NumberOfAddresses,
+ OUT CHAR AddressArray[][FDDI_LENGTH_OF_SHORT_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ The routine should be used by the MAC before
+ it actually alters the hardware registers to effect a
+ filtering hardware. This is usefull if another binding
+ has altered the address list since the action routine
+ is called.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Status - A pointer to the status of the call, NDIS_STATUS_SUCCESS or
+ NDIS_STATUS_FAILURE. Use EthNumberOfOpenAddresses() to get the
+ size that is needed.
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to the open block
+
+ SizeOfArray - The byte count of the AddressArray.
+
+ NumberOfAddresses - The number of addresses written to the array.
+
+ AddressArray - Will be filled with the addresses currently in the
+ multicast address list.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ UINT IndexOfAddress;
+ UINT CountOfAddresses = 0;
+ UINT FilterIndex = ((PFDDI_BINDING_INFO)NdisFilterHandle)->FilterIndex;
+
+ for(IndexOfAddress=0;
+ IndexOfAddress < Filter->NumberOfShortAddresses;
+ IndexOfAddress++
+ ){
+
+ if (IS_BIT_SET_IN_MASK(FilterIndex,
+ Filter->BindingsUsingShortAddress[IndexOfAddress])) {
+
+ if (SizeOfArray < FDDI_LENGTH_OF_SHORT_ADDRESS) {
+
+ *Status = NDIS_STATUS_FAILURE;
+
+ *NumberOfAddresses = 0;
+
+ return;
+
+ }
+
+ SizeOfArray -= FDDI_LENGTH_OF_SHORT_ADDRESS;
+
+ MoveMemory(
+ AddressArray[CountOfAddresses],
+ Filter->MulticastShortAddresses[IndexOfAddress],
+ FDDI_LENGTH_OF_SHORT_ADDRESS
+ );
+
+ CountOfAddresses++;
+
+ }
+
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ *NumberOfAddresses = CountOfAddresses;
+
+ return;
+
+}
+
+
+VOID
+FddiQueryGlobalFilterLongAddresses(
+ OUT PNDIS_STATUS Status,
+ IN PFDDI_FILTER Filter,
+ IN UINT SizeOfArray,
+ OUT PUINT NumberOfAddresses,
+ IN OUT CHAR AddressArray[][FDDI_LENGTH_OF_LONG_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ The routine should be used by the MAC before
+ it actually alters the hardware registers to effect a
+ filtering hardware. This is usefull if another binding
+ has altered the address list since the action routine
+ is called.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Status - A pointer to the status of the call, NDIS_STATUS_SUCCESS or
+ NDIS_STATUS_FAILURE. Use FDDI_NUMBER_OF_GLOBAL_LONG_ADDRESSES() to get the
+ size that is needed.
+
+ Filter - A pointer to the filter database.
+
+ SizeOfArray - The byte count of the AddressArray.
+
+ NumberOfAddresses - A pointer to the number of addresses written to the
+ array.
+
+ AddressArray - Will be filled with the addresses currently in the
+ multicast address list.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ if (SizeOfArray < (Filter->NumberOfLongAddresses * FDDI_LENGTH_OF_LONG_ADDRESS)) {
+
+ *Status = NDIS_STATUS_FAILURE;
+
+ *NumberOfAddresses = 0;
+
+ } else {
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ *NumberOfAddresses = Filter->NumberOfLongAddresses;
+
+ MoveMemory(
+ AddressArray[0],
+ Filter->MulticastLongAddresses[0],
+ Filter->NumberOfLongAddresses*FDDI_LENGTH_OF_LONG_ADDRESS
+ );
+
+ }
+
+}
+
+
+VOID
+FddiQueryGlobalFilterShortAddresses(
+ OUT PNDIS_STATUS Status,
+ IN PFDDI_FILTER Filter,
+ IN UINT SizeOfArray,
+ OUT PUINT NumberOfAddresses,
+ IN OUT CHAR AddressArray[][FDDI_LENGTH_OF_SHORT_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ The routine should be used by the MAC before
+ it actually alters the hardware registers to effect a
+ filtering hardware. This is usefull if another binding
+ has altered the address list since the action routine
+ is called.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Status - A pointer to the status of the call, NDIS_STATUS_SUCCESS or
+ NDIS_STATUS_FAILURE. Use FDDI_NUMBER_OF_GLOBAL_SHORT_ADDRESSES() to get the
+ size that is needed.
+
+ Filter - A pointer to the filter database.
+
+ SizeOfArray - The byte count of the AddressArray.
+
+ NumberOfAddresses - A pointer to the number of addresses written to the
+ array.
+
+ AddressArray - Will be filled with the addresses currently in the
+ multicast address list.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ if (SizeOfArray < (Filter->NumberOfShortAddresses * FDDI_LENGTH_OF_SHORT_ADDRESS)) {
+
+ *Status = NDIS_STATUS_FAILURE;
+
+ *NumberOfAddresses = 0;
+
+ } else {
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ *NumberOfAddresses = Filter->NumberOfShortAddresses;
+
+ MoveMemory(
+ AddressArray[0],
+ Filter->MulticastShortAddresses[0],
+ Filter->NumberOfShortAddresses*FDDI_LENGTH_OF_SHORT_ADDRESS
+ );
+
+ }
+
+}
+
+
+VOID
+FddiFilterIndicateReceive(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PCHAR Address,
+ IN UINT AddressLength,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate a packet to
+ all bindings. The packet will be filtered so that only the
+ appropriate bindings will receive the packet.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ MacReceiveContext - A MAC supplied context value that must be
+ returned by the protocol if it calls MacTransferData.
+
+ Address - The destination address from the received packet.
+
+ AddressLength - The length of the above address.
+
+ HeaderBuffer - A virtual address of the virtually contiguous
+ buffer containing the MAC header of the packet.
+
+ HeaderBufferSize - An unsigned integer indicating the size of
+ the header buffer, in bytes.
+
+ LookaheadBuffer - A virtual address of the virtually contiguous
+ buffer containing the first LookaheadBufferSize bytes of data
+ of the packet. The packet buffer is valid only within the current
+ call to the receive event handler.
+
+ LookaheadBufferSize - An unsigned integer indicating the size of
+ the lookahead buffer, in bytes.
+
+ PacketSize - An unsigned integer indicating the size of the received
+ packet, in bytes. This number has nothing to do with the lookahead
+ buffer, but indicates how large the arrived packet is so that a
+ subsequent MacTransferData request can be made to transfer the entire
+ packet as necessary.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ KIRQL oldIrql;
+ KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ FddiFilterDprIndicateReceive(
+ Filter,
+ MacReceiveContext,
+ Address,
+ AddressLength,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize
+ );
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ KeLowerIrql( oldIrql );
+ return;
+}
+
+
+VOID
+FddiFilterDprIndicateReceive(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PCHAR Address,
+ IN UINT AddressLength,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate a packet to
+ all bindings. The packet will be filtered so that only the
+ appropriate bindings will receive the packet.
+
+ Called at DPC_LEVEL.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ MacReceiveContext - A MAC supplied context value that must be
+ returned by the protocol if it calls MacTransferData.
+
+ Address - The destination address from the received packet.
+
+ AddressLength - The length of the above address.
+
+ HeaderBuffer - A virtual address of the virtually contiguous
+ buffer containing the MAC header of the packet.
+
+ HeaderBufferSize - An unsigned integer indicating the size of
+ the header buffer, in bytes.
+
+ LookaheadBuffer - A virtual address of the virtually contiguous
+ buffer containing the first LookaheadBufferSize bytes of data
+ of the packet. The packet buffer is valid only within the current
+ call to the receive event handler.
+
+ LookaheadBufferSize - An unsigned integer indicating the size of
+ the lookahead buffer, in bytes.
+
+ PacketSize - An unsigned integer indicating the size of the received
+ packet, in bytes. This number has nothing to do with the lookahead
+ buffer, but indicates how large the arrived packet is so that a
+ subsequent MacTransferData request can be made to transfer the entire
+ packet as necessary.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Will hold the type of address that we know we've got.
+ //
+ UINT AddressType;
+
+ //
+ // Will hold the status of indicating the receive packet.
+ // ZZZ For now this isn't used.
+ //
+ NDIS_STATUS StatusOfReceive;
+
+ //
+ // Will hold the filter classes of the binding being indicated.
+ //
+ UINT BindingFilters;
+
+ //
+ // Holds BindingFilters intersected with the packet type
+ //
+ UINT IntersectionOfFilters;
+
+ //
+ // Current Open to indicate to.
+ //
+ PFDDI_BINDING_INFO LocalOpen;
+
+ //
+ // Holds the result of address determinations.
+ //
+ INT ResultOfAddressCheck;
+
+ //
+ // If the packet is a runt packet, then only indicate to PROMISCUOUS
+ //
+
+ if ( HeaderBufferSize > (2 * AddressLength) && PacketSize != 0 ) {
+
+ //
+ //
+ // Determine whether the input address is a simple direct,
+ // a broadcast, a multicast, or an SMT address.
+ //
+
+ //
+ // First check if it *at least* has the multicast address bit.
+ //
+
+ FDDI_IS_SMT(
+ *((PCHAR)HeaderBuffer),
+ &ResultOfAddressCheck
+ );
+
+ if (ResultOfAddressCheck) {
+
+ AddressType = NDIS_PACKET_TYPE_SMT;
+
+ } else {
+
+ FDDI_IS_MULTICAST(
+ Address,
+ AddressLength,
+ &ResultOfAddressCheck
+ );
+
+ if (ResultOfAddressCheck) {
+
+ //
+ // It is at least a multicast address. Check to see if
+ // it is a broadcast address.
+ //
+
+ FDDI_IS_BROADCAST(
+ Address,
+ AddressLength,
+ &ResultOfAddressCheck
+ );
+
+ if (ResultOfAddressCheck) {
+
+
+#if DBG
+
+if (NdisCheckBadDrivers) {
+
+ if (!(Filter->CombinedPacketFilter & NDIS_PACKET_TYPE_BROADCAST)) {
+
+ //
+ // We should never receive directed packets
+ // to someone else unless in p-mode.
+ //
+ DbgPrint("NDIS: Bad driver, indicating broadcast\n");
+ DbgPrint("NDIS: packets when not set to.\n");
+ DbgBreakPoint();
+
+ }
+
+}
+
+#endif
+
+ AddressType = NDIS_PACKET_TYPE_BROADCAST;
+
+ } else {
+
+ AddressType = NDIS_PACKET_TYPE_MULTICAST;
+
+ }
+
+ } else {
+
+ //
+ // Verify that the address is directed to the adapter. We
+ // have to check for this because of the following senario.
+ //
+ // Adapter A is in promiscuous mode.
+ // Adapter B only wants directed packets to this adapter.
+ //
+ // The MAC will indicate *all* packets.
+ //
+ // The filter package needs to filter directed packets to
+ // other adapters from ones directed to this adapter.
+ //
+
+ if (Filter->CombinedPacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS) {
+
+ //
+ // The result of comparing an element of the address
+ // array and the multicast address.
+ //
+ // Result < 0 Implies the adapter address is greater.
+ // Result > 0 Implies the address is greater.
+ // Result = 0 Implies that the they are equal.
+ //
+ INT Result;
+
+ if (AddressLength == FDDI_LENGTH_OF_LONG_ADDRESS) {
+
+ FDDI_COMPARE_NETWORK_ADDRESSES_EQ(
+ Filter->AdapterLongAddress,
+ Address,
+ FDDI_LENGTH_OF_LONG_ADDRESS,
+ &Result
+ );
+
+ if (Result == 0) {
+
+ AddressType = NDIS_PACKET_TYPE_DIRECTED;
+
+ } else {
+
+ AddressType = 0;
+
+ }
+
+ } else if (AddressLength == FDDI_LENGTH_OF_SHORT_ADDRESS) {
+
+ FDDI_COMPARE_NETWORK_ADDRESSES_EQ(
+ Filter->AdapterShortAddress,
+ Address,
+ FDDI_LENGTH_OF_SHORT_ADDRESS,
+ &Result
+ );
+
+ if (Result == 0) {
+
+ AddressType = NDIS_PACKET_TYPE_DIRECTED;
+
+ } else {
+
+ AddressType = 0;
+
+ }
+
+ } else {
+
+ //
+ // This will cause binding that only want a specific
+ // address type to not be indicated.
+ //
+
+ AddressType = 0;
+
+ }
+
+ } else {
+
+#if DBG
+
+if (NdisCheckBadDrivers) {
+
+ //
+ // The result of comparing an element of the address
+ // array and the multicast address.
+ //
+ // Result < 0 Implies the adapter address is greater.
+ // Result > 0 Implies the address is greater.
+ // Result = 0 Implies that the they are equal.
+ //
+ INT Result = 0;
+
+ if (AddressLength == FDDI_LENGTH_OF_LONG_ADDRESS) {
+
+ FDDI_COMPARE_NETWORK_ADDRESSES_EQ(
+ Filter->AdapterLongAddress,
+ Address,
+ FDDI_LENGTH_OF_LONG_ADDRESS,
+ &Result
+ );
+
+ } else if (AddressLength == FDDI_LENGTH_OF_SHORT_ADDRESS) {
+
+ FDDI_COMPARE_NETWORK_ADDRESSES_EQ(
+ Filter->AdapterShortAddress,
+ Address,
+ FDDI_LENGTH_OF_SHORT_ADDRESS,
+ &Result
+ );
+
+ }
+
+ if (Result != 0) {
+
+ //
+ // We should never receive directed packets
+ // to someone else unless in p-mode.
+ //
+ DbgPrint("NDIS: Bad driver, indicating packets\n");
+ DbgPrint("NDIS: to another station when not in\n");
+ DbgPrint("NDIS: promiscuous mode.\n");
+ DbgBreakPoint();
+
+
+ }
+
+}
+
+#endif
+
+ AddressType = NDIS_PACKET_TYPE_DIRECTED;
+
+ }
+
+ }
+
+ }
+
+ } else {
+
+ //
+ // Runt
+ //
+
+ AddressType = NDIS_PACKET_TYPE_PROMISCUOUS;
+
+ }
+
+ //
+ // We need to acquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+
+ LocalOpen = Filter->OpenList;
+
+ while (LocalOpen != NULL) {
+
+ BindingFilters = LocalOpen->PacketFilters;
+
+ IntersectionOfFilters = BindingFilters & AddressType;
+
+ //
+ // if the binding wants direct packets and this is a directly
+ // addressed packet then the binding gets the packet.
+ // if Smt and wanted, or broadcast and wanted, indicate it.
+ //
+
+ if (IntersectionOfFilters & (NDIS_PACKET_TYPE_SMT |
+ NDIS_PACKET_TYPE_DIRECTED |
+ NDIS_PACKET_TYPE_BROADCAST)) {
+
+ goto IndicatePacket;
+
+ }
+
+
+ //
+ // if the binding wants multicast packets and the packet
+ // is a multicast packet and it's in the list of addresses
+ // it will get the packet.
+ //
+
+ if (AddressType & (BindingFilters & NDIS_PACKET_TYPE_MULTICAST)) {
+
+ //
+ // Will hold the index of the multicast
+ // address if it finds it.
+ //
+ UINT IndexOfAddress;
+
+ if (AddressLength == FDDI_LENGTH_OF_LONG_ADDRESS) {
+
+ if (FindMulticastLongAddress(
+ Filter->NumberOfLongAddresses,
+ Filter->MulticastLongAddresses,
+ Address,
+ &IndexOfAddress
+ )) {
+
+ if (IS_BIT_SET_IN_MASK(
+ LocalOpen->FilterIndex,
+ Filter->BindingsUsingLongAddress[IndexOfAddress]
+ )) {
+
+ goto IndicatePacket;
+
+ }
+
+ }
+
+ } else {
+
+ if (FindMulticastShortAddress(
+ Filter->NumberOfShortAddresses,
+ Filter->MulticastShortAddresses,
+ Address,
+ &IndexOfAddress
+ )) {
+
+ if (IS_BIT_SET_IN_MASK(
+ LocalOpen->FilterIndex,
+ Filter->BindingsUsingShortAddress[IndexOfAddress]
+ )) {
+
+ goto IndicatePacket;
+
+ }
+
+ }
+
+ }
+ }
+
+ //
+ // if the binding wants all multicast packets and the packet
+ // has a multicast address it will get the packet
+ //
+
+ if ((AddressType & NDIS_PACKET_TYPE_MULTICAST) &&
+ (BindingFilters & NDIS_PACKET_TYPE_ALL_MULTICAST)) {
+
+ goto IndicatePacket;
+
+ }
+
+ //
+ // if the binding is promiscuous then it will get the packet
+ //
+
+ if (BindingFilters & NDIS_PACKET_TYPE_PROMISCUOUS) {
+
+ goto IndicatePacket;
+
+ }
+
+ goto GetNextBinding;
+
+IndicatePacket:;
+
+ LocalOpen->References++;
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ //
+ // Indicate the packet to the binding.
+ //
+
+ FilterIndicateReceive(
+ &StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ if ((--(LocalOpen->References)) == 0) {
+
+ PFDDI_BINDING_INFO NextOpen = LocalOpen->NextOpen;
+
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+
+ //
+ // Remove it from the list.
+ //
+
+ if (LocalOpen->NextOpen != NULL) {
+
+ LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen;
+
+ }
+
+ if (LocalOpen->PrevOpen != NULL) {
+
+ LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen;
+
+ } else {
+
+ Filter->OpenList = LocalOpen->NextOpen;
+
+ }
+
+
+
+ //
+ // Call the IndicateComplete routine.
+ //
+
+
+ if (LocalOpen->ReceivedAPacket) {
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ }
+
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+
+ Filter->CloseAction(LocalOpen->MacBindingHandle);
+
+
+ FDDI_FILTER_FREE_OPEN(Filter, LocalOpen);
+
+ LocalOpen = NextOpen;
+
+ continue;
+
+ }
+
+GetNextBinding:
+
+ LocalOpen = LocalOpen->NextOpen;
+
+ }
+
+}
+
+
+VOID
+FddiFilterIndicateReceiveComplete(
+ IN PFDDI_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate that the receive
+ process is complete to all bindings. Only those bindings which
+ have received packets will be notified.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ KIRQL oldIrql;
+ KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ FddiFilterDprIndicateReceiveComplete(
+ Filter
+ );
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ KeLowerIrql( oldIrql );
+ return;
+}
+
+
+VOID
+FddiFilterDprIndicateReceiveComplete(
+ IN PFDDI_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate that the receive
+ process is complete to all bindings. Only those bindings which
+ have received packets will be notified.
+
+ Called at DPC_LEVEL.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PFDDI_BINDING_INFO LocalOpen;
+
+ //
+ // We need to aquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+
+ LocalOpen = Filter->OpenList;
+
+ while (LocalOpen != NULL) {
+
+ if (LocalOpen->ReceivedAPacket) {
+
+ //
+ // Indicate the binding.
+ //
+
+ LocalOpen->ReceivedAPacket = FALSE;
+
+ LocalOpen->References++;
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ if ((--(LocalOpen->References)) == 0) {
+
+ PFDDI_BINDING_INFO NextOpen = LocalOpen->NextOpen;
+
+ //
+ // This binding is shutting down. We have to kill it.
+ //
+
+ //
+ // Remove it from the list.
+ //
+
+ if (LocalOpen->NextOpen != NULL) {
+
+ LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen;
+
+ }
+
+ if (LocalOpen->PrevOpen != NULL) {
+
+ LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen;
+
+ } else {
+
+ Filter->OpenList = LocalOpen->NextOpen;
+
+ }
+
+
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+
+ Filter->CloseAction(LocalOpen->MacBindingHandle);
+
+
+ FDDI_FILTER_FREE_OPEN(Filter, LocalOpen);
+
+ LocalOpen = NextOpen;
+
+ continue;
+ }
+
+ }
+
+ LocalOpen = LocalOpen->NextOpen;
+
+ }
+
+}
+
+
+BOOLEAN
+FindMulticastLongAddress(
+ IN UINT NumberOfAddresses,
+ IN CHAR AddressArray[][FDDI_LENGTH_OF_LONG_ADDRESS],
+ IN CHAR MulticastAddress[FDDI_LENGTH_OF_LONG_ADDRESS],
+ OUT PUINT ArrayIndex
+ )
+
+/*++
+
+Routine Description:
+
+ Given an array of multicast addresses search the array for
+ a particular multicast address. It is assumed that the
+ address array is already sorted.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+ NOTE: This ordering is arbitrary but consistant.
+
+Arguments:
+
+ NumberOfAddresses - The number of addresses currently in the
+ address array.
+
+ AddressArray - An array of multicast addresses.
+
+ MulticastAddress - The address to search for in the address array.
+
+ ArrayIndex - Will point to where the MulticastAddress is in
+ the AddressArray, or if it isn't in the array, where it should
+ be in the array.
+
+Return Value:
+
+ If the address is in the sorted list this routine will return
+ TRUE, otherwise FALSE.
+
+--*/
+
+{
+
+ //
+ // Indices into the address array so that we may do a binary
+ // search.
+ //
+ UINT Bottom = 0;
+ UINT Middle = NumberOfAddresses / 2;
+ UINT Top;
+
+ if (NumberOfAddresses) {
+
+ Top = NumberOfAddresses - 1;
+
+ while ((Middle <= Top) && (Middle >= Bottom)) {
+
+ //
+ // The result of comparing an element of the address
+ // array and the multicast address.
+ //
+ // Result < 0 Implies the multicast address is greater.
+ // Result > 0 Implies the address array element is greater.
+ // Result = 0 Implies that the array element and the address
+ // are equal.
+ //
+ INT Result;
+
+ FDDI_COMPARE_NETWORK_ADDRESSES(
+ AddressArray[Middle],
+ MulticastAddress,
+ FDDI_LENGTH_OF_LONG_ADDRESS,
+ &Result
+ );
+
+ if (Result == 0) {
+
+ *ArrayIndex = Middle;
+ return(TRUE);
+
+ } else if (Result > 0) {
+
+ if (Middle == 0) break;
+ Top = Middle - 1;
+
+
+ } else {
+
+ Bottom = Middle+1;
+
+ }
+
+ Middle = Bottom + (((Top+1) - Bottom)/2);
+
+ }
+
+ }
+
+ *ArrayIndex = Middle;
+
+ return(FALSE);
+
+}
+
+
+BOOLEAN
+FindMulticastShortAddress(
+ IN UINT NumberOfAddresses,
+ IN CHAR AddressArray[][FDDI_LENGTH_OF_SHORT_ADDRESS],
+ IN CHAR MulticastAddress[FDDI_LENGTH_OF_SHORT_ADDRESS],
+ OUT PUINT ArrayIndex
+ )
+
+/*++
+
+Routine Description:
+
+ Given an array of multicast addresses search the array for
+ a particular multicast address. It is assumed that the
+ address array is already sorted.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+ NOTE: This ordering is arbitrary but consistant.
+
+Arguments:
+
+ NumberOfAddresses - The number of addresses currently in the
+ address array.
+
+ AddressArray - An array of multicast addresses.
+
+ MulticastAddress - The address to search for in the address array.
+
+ ArrayIndex - Will point to where the MulticastAddress is in
+ the AddressArray, or if it isn't in the array, where it should
+ be in the array.
+
+Return Value:
+
+ If the address is in the sorted list this routine will return
+ TRUE, otherwise FALSE.
+
+--*/
+
+{
+
+ //
+ // Indices into the address array so that we may do a binary
+ // search.
+ //
+ UINT Bottom = 0;
+ UINT Middle = NumberOfAddresses / 2;
+ UINT Top;
+
+ if (NumberOfAddresses) {
+
+ Top = NumberOfAddresses - 1;
+
+ while ((Middle <= Top) && (Middle >= Bottom)) {
+
+ //
+ // The result of comparing an element of the address
+ // array and the multicast address.
+ //
+ // Result < 0 Implies the multicast address is greater.
+ // Result > 0 Implies the address array element is greater.
+ // Result = 0 Implies that the array element and the address
+ // are equal.
+ //
+ INT Result;
+
+ FDDI_COMPARE_NETWORK_ADDRESSES(
+ AddressArray[Middle],
+ MulticastAddress,
+ FDDI_LENGTH_OF_SHORT_ADDRESS,
+ &Result
+ );
+
+ if (Result == 0) {
+
+ *ArrayIndex = Middle;
+ return(TRUE);
+
+ } else if (Result > 0) {
+
+ if (Middle == 0) break;
+ Top = Middle - 1;
+
+
+ } else {
+
+ Bottom = Middle+1;
+
+ }
+
+ Middle = Bottom + (((Top+1) - Bottom)/2);
+
+ }
+
+ }
+
+ *ArrayIndex = Middle;
+
+ return(FALSE);
+
+}
+
+
+BOOLEAN
+FddiShouldAddressLoopBack(
+ IN PFDDI_FILTER Filter,
+ IN CHAR Address[],
+ IN UINT AddressLength
+ )
+
+/*++
+
+Routine Description:
+
+ Do a quick check to see whether the input address should
+ loopback.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+ NOTE: THIS ROUTINE DOES NOT CHECK THE SPECIAL CASE OF SOURCE
+ EQUALS DESTINATION.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ Address - A network address to check for loopback.
+
+ AddressLength - Length of the above address in bytes.
+
+Return Value:
+
+ Returns TRUE if the address needs to be loopback. It
+ will return FALSE if there is *no* chance that the address would
+ require loopback.
+
+--*/
+{
+ BOOLEAN fLoopback, fSelfDirected;
+
+ FddiShouldAddressLoopBackMacro(Filter, Address, AddressLength, &fLoopback, &fSelfDirected);
+
+ return(fLoopback);
+}
diff --git a/private/ntos/ndis/ndis30/ffilter.h b/private/ntos/ndis/ndis30/ffilter.h
new file mode 100644
index 000000000..ae3ae8120
--- /dev/null
+++ b/private/ntos/ndis/ndis30/ffilter.h
@@ -0,0 +1,692 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ffilter.h
+
+Abstract:
+
+ Header file for the address filtering library for NDIS MAC's.
+
+Author:
+
+ Anthony V. Ercolano (tonye) creation-date 3-Aug-1990
+
+Environment:
+
+ Runs in the context of a single MAC driver.
+
+Notes:
+
+ None.
+
+Revision History:
+
+ Sean Selitrennikoff (SeanSe) - converter efilter.* for FDDI support.
+
+
+--*/
+
+#ifndef _FDDI_FILTER_DEFS_
+#define _FDDI_FILTER_DEFS_
+
+#define FDDI_LENGTH_OF_LONG_ADDRESS 6
+#define FDDI_LENGTH_OF_SHORT_ADDRESS 2
+
+
+//
+// ZZZ This is a little-endian specific check.
+//
+#define FDDI_IS_MULTICAST(Address, AddressLength, Result) \
+{ \
+ PUCHAR _A = Address; \
+ *Result = (BOOLEAN)(_A[0] & ((UCHAR)0x01)); \
+}
+
+//
+// Check whether the frame is SMT or not.
+//
+#define FDDI_IS_SMT(FcByte, Result) \
+{ \
+ *Result = ((FcByte & ((UCHAR)0xf0)) == 0x40); \
+}
+
+
+//
+// Check whether an address is broadcast.
+//
+#define FDDI_IS_BROADCAST(Address, AddressLength, Result) \
+{ \
+ PUCHAR _A = Address; \
+ PUCHAR _E = _A + AddressLength;\
+ *Result = TRUE;\
+ for (; _A < _E ; _A++) {\
+ if (*_A != 0xFF) {\
+ *Result = FALSE;\
+ break;\
+ }\
+ }\
+}
+
+
+//
+// This macro will compare network addresses.
+//
+// A - Is a network address.
+//
+// B - Is a network address.
+//
+// Result - The result of comparing two network address.
+//
+// Result < 0 Implies the B address is greater.
+// Result > 0 Implies the A element is greater.
+// Result = 0 Implies equality.
+//
+// Note that this is an arbitrary ordering. There is not
+// defined relation on network addresses. This is ad-hoc!
+//
+//
+#define FDDI_COMPARE_NETWORK_ADDRESSES(A,B,_AddressLength,Result) \
+{ \
+ PUCHAR _A = (PUCHAR)(A); \
+ PUCHAR _B = (PUCHAR)(B); \
+ if ( *(USHORT UNALIGNED *)_A > \
+ *(USHORT UNALIGNED *)_B ) { \
+ *Result = 1; \
+ } else if ( *(USHORT UNALIGNED *)_A < \
+ *(USHORT UNALIGNED *)_B ) { \
+ *Result = (UINT)-1; \
+ } else if (_AddressLength == 2) { \
+ *Result = 0; \
+ } else if ( *(ULONG UNALIGNED *)&_A[2] > \
+ *(ULONG UNALIGNED *)&_B[2] ) { \
+ *Result = 1; \
+ } else if ( *(ULONG UNALIGNED *)&_A[2] < \
+ *(ULONG UNALIGNED *)&_B[2] ) { \
+ *Result = (UINT)-1; \
+ } else { \
+ *Result = 0; \
+ } \
+}
+
+//
+// This macro will compare network addresses.
+//
+// A - Is a network address.
+//
+// B - Is a network address.
+//
+// Result - The result of comparing two network address.
+//
+// Result != 0 Implies inequality.
+// Result == 0 Implies equality.
+//
+//
+#define FDDI_COMPARE_NETWORK_ADDRESSES_EQ(A,B,_AddressLength,Result) \
+{ \
+ PUCHAR _A = (PUCHAR)(A); \
+ PUCHAR _B = (PUCHAR)(B); \
+ if ( ( *(USHORT UNALIGNED *)_A == \
+ *(USHORT UNALIGNED *)_B ) && \
+ ( ( (_AddressLength) == 2 ) || \
+ ( *(ULONG UNALIGNED *)&_A[2] == \
+ *(ULONG UNALIGNED *)&_B[2] ) ) ) { \
+ *Result = 0; \
+ } else { \
+ *Result = 1; \
+ } \
+}
+
+
+//
+// This macro is used to copy from one network address to
+// another.
+//
+#define FDDI_COPY_NETWORK_ADDRESS(D,S,AddressLength) \
+{ \
+ PCHAR _D = (D); \
+ PCHAR _S = (S); \
+ UINT _C = (AddressLength);\
+ for ( ; _C > 0 ; _D++, _S++, _C--) {\
+ *_D = *_S;\
+ }\
+}
+
+
+//
+//UINT
+//FDDI_QUERY_FILTER_CLASSES(
+// IN PFDDI_FILTER Filter
+// )
+//
+// This macro returns the currently enabled filter classes.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define FDDI_QUERY_FILTER_CLASSES(Filter) ((Filter)->CombinedPacketFilter)
+
+
+//
+//UINT
+//FDDI_QUERY_PACKET_FILTER(
+// IN PFDDI_FILTER Filter,
+// IN NDIS_HANDLE NdisFilterHandle
+// )
+//
+// This macro returns the currently enabled filter classes for a specific
+// open instance.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define FDDI_QUERY_PACKET_FILTER(Filter, NdisFilterHandle) \
+ (((PFDDI_BINDING_INFO)(NdisFilterHandle))->PacketFilters)
+
+
+//
+//UINT
+//FDDI_NUMBER_OF_GLOBAL_FILTER_LONG_ADDRESSES(
+// IN PFDDI_FILTER Filter
+// )
+//
+// This macro returns the number of multicast addresses in the
+// multicast address list.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define FDDI_NUMBER_OF_GLOBAL_FILTER_LONG_ADDRESSES(Filter) ((Filter)->NumberOfLongAddresses)
+
+
+//
+//UINT
+//FDDI_NUMBER_OF_GLOBAL_FILTER_SHORT_ADDRESSES(
+// IN PFDDI_FILTER Filter
+// )
+//
+// This macro returns the number of multicast addresses in the
+// multicast address list.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define FDDI_NUMBER_OF_GLOBAL_FILTER_SHORT_ADDRESSES(Filter) ((Filter)->NumberOfShortAddresses)
+
+
+//
+// An action routine type. The routines are called
+// when a filter type is set for the first time or
+// no more bindings require a particular type of filter.
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+NDIS_STATUS
+(*FDDI_FILTER_CHANGE)(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+//
+// This action routine is called when a new multicast address
+// list is given to the filter. The action routine is given
+// arrays containing the old and new multicast addresses.
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+NDIS_STATUS
+(*FDDI_ADDRESS_CHANGE)(
+ IN UINT OldLongAddressCount,
+ IN CHAR OldLongAddresses[][FDDI_LENGTH_OF_LONG_ADDRESS],
+ IN UINT NewLongAddressCount,
+ IN CHAR NewLongAddresses[][FDDI_LENGTH_OF_LONG_ADDRESS],
+ IN UINT OldShortAddressCount,
+ IN CHAR OldShortAddresses[][FDDI_LENGTH_OF_SHORT_ADDRESS],
+ IN UINT NewShortAddressCount,
+ IN CHAR NewShortAddresses[][FDDI_LENGTH_OF_SHORT_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+//
+// This action routine is called when the mac requests a close for
+// a particular binding *WHILE THE BINDING IS BEING INDICATED TO
+// THE PROTOCOL*. The filtering package can't get rid of the open
+// right away. So this routine will be called as soon as the
+// NdisIndicateReceive returns.
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+VOID
+(*FDDI_DEFERRED_CLOSE)(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+typedef ULONG FDDI_MASK,*PFDDI_MASK;
+
+//
+// Maximum number of opens the filter package will support. This is
+// the max so that bit masks can be used instead of a spaghetti of
+// pointers.
+//
+#define FDDI_FILTER_MAX_OPENS (sizeof(ULONG) * 8)
+
+//
+// The binding info is threaded on two lists. When
+// the binding is free it is on a single freelist.
+//
+// When the binding is being used it is on a doubly linked
+// index list.
+//
+typedef struct _FDDI_BINDING_INFO {
+ NDIS_HANDLE MacBindingHandle;
+ NDIS_HANDLE NdisBindingContext;
+ UINT PacketFilters;
+ ULONG References;
+ struct _FDDI_BINDING_INFO *NextOpen;
+ struct _FDDI_BINDING_INFO *PrevOpen;
+ BOOLEAN ReceivedAPacket;
+ UCHAR FilterIndex;
+} FDDI_BINDING_INFO,*PFDDI_BINDING_INFO;
+
+//
+// An opaque type that contains a filter database.
+// The MAC need not know how it is structured.
+//
+typedef struct _FDDI_FILTER {
+
+ //
+ // Spin lock used to protect the filter from multiple accesses.
+ //
+ PNDIS_SPIN_LOCK Lock;
+
+ //
+ // Pointer to an array of 6 character arrays holding the
+ // multicast addresses requested for filtering.
+ //
+ CHAR (*MulticastLongAddresses)[FDDI_LENGTH_OF_LONG_ADDRESS];
+
+ //
+ // Pointer to an array of FDDI_MASKS that work in conjuction with
+ // the MulticastLongAddress array. In the masks, a bit being enabled
+ // indicates that the binding with the given FilterIndex is using
+ // the corresponding address.
+ //
+ FDDI_MASK *BindingsUsingLongAddress;
+
+ //
+ // Pointer to an array of 2 character arrays holding the
+ // multicast addresses requested for filtering.
+ //
+ CHAR (*MulticastShortAddresses)[FDDI_LENGTH_OF_SHORT_ADDRESS];
+
+ //
+ // Pointer to an array of FDDI_MASKS that work in conjuction with
+ // the MulticastShortAddress array. In the masks, a bit being enabled
+ // indicates that the binding with the given FilterIndex is using
+ // the corresponding address.
+ //
+ FDDI_MASK *BindingsUsingShortAddress;
+
+ //
+ // Combination of all the filters of all the open bindings.
+ //
+ UINT CombinedPacketFilter;
+
+ //
+ // Pointer for traversing the open list.
+ //
+ PFDDI_BINDING_INFO OpenList;
+
+
+ //
+ // Action routines to be invoked on notable changes in the filter.
+ //
+
+ FDDI_ADDRESS_CHANGE AddressChangeAction;
+ FDDI_FILTER_CHANGE FilterChangeAction;
+ FDDI_DEFERRED_CLOSE CloseAction;
+
+ //
+ // The maximum number of long addresses used for filtering.
+ //
+ UINT MaximumMulticastLongAddresses;
+
+ //
+ // The maximum number of short addresses used for filtering.
+ //
+ UINT MaximumMulticastShortAddresses;
+
+ //
+ // The current number of addresses in the LongAddress filter.
+ //
+ UINT NumberOfLongAddresses;
+
+ //
+ // The current number of addresses in the ShortAddress filter.
+ //
+ UINT NumberOfShortAddresses;
+
+ //
+ // Bit mask of opens that are available.
+ //
+ ULONG FreeBindingMask;
+
+ //
+ // Long Address of the adapter.
+ //
+ UCHAR AdapterLongAddress[FDDI_LENGTH_OF_LONG_ADDRESS];
+
+ //
+ // Short Address of the adapter.
+ //
+ UCHAR AdapterShortAddress[FDDI_LENGTH_OF_SHORT_ADDRESS];
+
+} FDDI_FILTER,*PFDDI_FILTER;
+
+//
+// Only for internal wrapper use.
+//
+VOID
+FddiInitializePackage(
+ VOID
+ );
+
+VOID
+FddiReferencePackage(
+ VOID
+ );
+
+VOID
+FddiDereferencePackage(
+ VOID
+ );
+
+//
+// Exported routines
+//
+
+EXPORT
+BOOLEAN
+FddiCreateFilter(
+ IN UINT MaximumMulticastLongAddresses,
+ IN UINT MaximumMulticastShortAddresses,
+ IN FDDI_ADDRESS_CHANGE AddressChangeAction,
+ IN FDDI_FILTER_CHANGE FilterChangeAction,
+ IN FDDI_DEFERRED_CLOSE CloseAction,
+ IN PUCHAR AdapterLongAddress,
+ IN PUCHAR AdapterShortAddress,
+ IN PNDIS_SPIN_LOCK Lock,
+ OUT PFDDI_FILTER *Filter
+ );
+
+EXPORT
+VOID
+FddiDeleteFilter(
+ IN PFDDI_FILTER Filter
+ );
+
+EXPORT
+BOOLEAN
+FddiNoteFilterOpenAdapter(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE NdisBindingContext,
+ OUT PNDIS_HANDLE NdisFilterHandle
+ );
+
+EXPORT
+NDIS_STATUS
+FddiDeleteFilterOpenAdapter(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+EXPORT
+NDIS_STATUS
+FddiChangeFilterLongAddresses(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT AddressCount,
+ IN CHAR Addresses[][FDDI_LENGTH_OF_LONG_ADDRESS],
+ IN BOOLEAN Set
+ );
+
+EXPORT
+NDIS_STATUS
+FddiChangeFilterShortAddresses(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT AddressCount,
+ IN CHAR Addresses[][FDDI_LENGTH_OF_SHORT_ADDRESS],
+ IN BOOLEAN Set
+ );
+
+
+#define FddiShouldAddressLoopBackMacro(_Filter, _Address, _AddressLength, _pfLoopBack, _pfSelfDirected)\
+{ \
+ /* \
+ * Holds the result of address determinations. \
+ */ \
+ INT ResultOfAddressCheck; \
+ \
+ UINT CombinedFilters; \
+ \
+ CombinedFilters = FDDI_QUERY_FILTER_CLASSES(_Filter); \
+ \
+ *(_pfLoopBack) = FALSE; \
+ *(_pfSelfDirected) = FALSE; \
+ \
+ do \
+ { \
+ if (CombinedFilters & NDIS_PACKET_TYPE_PROMISCUOUS) \
+ { \
+ *(_pfLoopBack) = TRUE; \
+ break; \
+ } \
+ \
+ /* \
+ * First check if it *at least* has the multicast address bit. \
+ */ \
+ \
+ FDDI_IS_MULTICAST( \
+ _Address, \
+ _AddressLength, \
+ &ResultOfAddressCheck \
+ ); \
+ \
+ if (ResultOfAddressCheck) \
+ { \
+ /* \
+ * It is at least a multicast address. Check to see if \
+ * it is a broadcast address. \
+ */ \
+ \
+ FDDI_IS_BROADCAST( \
+ _Address, \
+ _AddressLength, \
+ &ResultOfAddressCheck \
+ ); \
+ \
+ if (ResultOfAddressCheck) \
+ { \
+ if (CombinedFilters & NDIS_PACKET_TYPE_BROADCAST) \
+ { \
+ *(_pfLoopBack) = TRUE; \
+ break; \
+ } \
+ else \
+ { \
+ break; \
+ } \
+ \
+ } else { \
+ \
+ if ((CombinedFilters & NDIS_PACKET_TYPE_ALL_MULTICAST) || \
+ (CombinedFilters & NDIS_PACKET_TYPE_MULTICAST)) \
+ { \
+ *(_pfLoopBack) = TRUE; \
+ break; \
+ } \
+ else \
+ { \
+ break; \
+ } \
+ } \
+ } \
+ else \
+ { \
+ /* \
+ * Directed to ourself? \
+ */ \
+ if (AddressLength == FDDI_LENGTH_OF_LONG_ADDRESS) \
+ { \
+ FDDI_COMPARE_NETWORK_ADDRESSES_EQ((_Filter)->AdapterLongAddress, \
+ _Address, \
+ FDDI_LENGTH_OF_LONG_ADDRESS, \
+ &ResultOfAddressCheck \
+ ); \
+ } \
+ else \
+ { \
+ FDDI_COMPARE_NETWORK_ADDRESSES_EQ((_Filter)->AdapterShortAddress, \
+ _Address, \
+ FDDI_LENGTH_OF_SHORT_ADDRESS, \
+ &ResultOfAddressCheck \
+ ); \
+ } \
+ \
+ if (ResultOfAddressCheck == 0) \
+ { \
+ *(_pfLoopBack) = TRUE; \
+ *(_pfSelfDirected) = TRUE; \
+ break; \
+ } \
+ } \
+ } while (FALSE); \
+}
+
+EXPORT
+BOOLEAN
+FddiShouldAddressLoopBack(
+ IN PFDDI_FILTER Filter,
+ IN CHAR Address[],
+ IN UINT LengthOfAddress
+ );
+
+EXPORT
+NDIS_STATUS
+FddiFilterAdjust(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT FilterClasses,
+ IN BOOLEAN Set
+ );
+
+EXPORT
+UINT
+FddiNumberOfOpenFilterLongAddresses(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle
+ );
+
+EXPORT
+UINT
+FddiNumberOfOpenFilterShortAddresses(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle
+ );
+
+EXPORT
+VOID
+FddiQueryGlobalFilterLongAddresses(
+ OUT PNDIS_STATUS Status,
+ IN PFDDI_FILTER Filter,
+ IN UINT SizeOfArray,
+ OUT PUINT NumberOfAddresses,
+ IN OUT CHAR AddressArray[][FDDI_LENGTH_OF_LONG_ADDRESS]
+ );
+
+EXPORT
+VOID
+FddiQueryGlobalFilterShortAddresses(
+ OUT PNDIS_STATUS Status,
+ IN PFDDI_FILTER Filter,
+ IN UINT SizeOfArray,
+ OUT PUINT NumberOfAddresses,
+ IN OUT CHAR AddressArray[][FDDI_LENGTH_OF_SHORT_ADDRESS]
+ );
+
+EXPORT
+VOID
+FddiQueryOpenFilterLongAddresses(
+ OUT PNDIS_STATUS Status,
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN UINT SizeOfArray,
+ OUT PUINT NumberOfAddresses,
+ IN OUT CHAR AddressArray[][FDDI_LENGTH_OF_LONG_ADDRESS]
+ );
+
+EXPORT
+VOID
+FddiQueryOpenFilterShortAddresses(
+ OUT PNDIS_STATUS Status,
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN UINT SizeOfArray,
+ OUT PUINT NumberOfAddresses,
+ IN OUT CHAR AddressArray[][FDDI_LENGTH_OF_SHORT_ADDRESS]
+ );
+
+EXPORT
+VOID
+FddiFilterIndicateReceive(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PCHAR Address,
+ IN UINT AddressLength,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+EXPORT
+VOID
+FddiFilterDprIndicateReceive(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PCHAR Address,
+ IN UINT AddressLength,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+EXPORT
+VOID
+FddiFilterIndicateReceiveComplete(
+ IN PFDDI_FILTER Filter
+ );
+
+EXPORT
+VOID
+FddiFilterDprIndicateReceiveComplete(
+ IN PFDDI_FILTER Filter
+ );
+
+#endif // _FDDI_FILTER_DEFS_
+
diff --git a/private/ntos/ndis/ndis30/makefile b/private/ntos/ndis/ndis30/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/ndis30/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/ndis30/makefile.inc b/private/ntos/ndis/ndis30/makefile.inc
new file mode 100644
index 000000000..9462059e7
--- /dev/null
+++ b/private/ntos/ndis/ndis30/makefile.inc
@@ -0,0 +1,2 @@
+obj\$(TARGET_DIRECTORY)\ndis.def: ndis.src
+ $(TARGET_CPP) -nologo -EP $(TARGET_DEFINES) $(TARGET_DBG_DEFINES) ndis.src > obj\$(TARGET_DIRECTORY)\ndis.def
diff --git a/private/ntos/ndis/ndis30/miniport.c b/private/ntos/ndis/ndis30/miniport.c
new file mode 100644
index 000000000..efef74ebb
--- /dev/null
+++ b/private/ntos/ndis/ndis30/miniport.c
@@ -0,0 +1,10214 @@
+/*++
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ miniport.c
+
+Abstract:
+
+ NDIS wrapper functions
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 05-Oct-93
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+--*/
+
+
+#include <precomp.h>
+#pragma hdrstop
+
+PNDIS_M_DRIVER_BLOCK NdisDriverList = NULL;
+NDIS_SPIN_LOCK NdisDriverListLock = {0};
+
+extern UCHAR NdisInternalEaName[4];
+extern UCHAR NdisInternalEaValue[8];
+
+#define BYTE_SWAP(_word) (\
+ (USHORT) (((_word) >> 8) | ((_word) << 8)) )
+
+#define LOW_WORD(_dword) (\
+ (USHORT) ((_dword) & 0x0000FFFF) )
+
+#define HIGH_WORD(_dword) (\
+ (USHORT) (((_dword) >> 16) & 0x0000FFFF) )
+
+#define BYTE_SWAP_ULONG(_ulong) (\
+ (ULONG)((ULONG)(BYTE_SWAP(LOW_WORD(_ulong)) << 16) + \
+ BYTE_SWAP(HIGH_WORD(_ulong))))
+
+//
+// This is the number of extra OIDs that ARCnet with Ethernet encapsulation
+// supports.
+//
+#define ARC_NUMBER_OF_EXTRA_OIDS 2
+
+
+
+#if DBG
+
+#define MINIPORT_DEBUG_LOUD 0x01
+#define MINIPORT_DEBUG_VERY_LOUD 0x02
+#define MINIPORT_DEBUG_PACKETS 0x04
+ULONG MiniportDebug = 0; // MINIPORT_DEBUG_LOUD;
+#define LOUD_DEBUG(A) if (MiniportDebug & MINIPORT_DEBUG_LOUD) { A ; }
+#define VERY_LOUD_DEBUG(A) if (MiniportDebug & MINIPORT_DEBUG_VERY_LOUD) { A ; }
+#define PACKET_DEBUG(A) if (MiniportDebug & MINIPORT_DEBUG_PACKETS) { A ; }
+
+#else
+
+#define LOUD_DEBUG(A)
+#define VERY_LOUD_DEBUG(A)
+#define PACKET_DEBUG(A)
+
+#endif
+
+//
+// Define constants used internally to identify regular opens from
+// query global statistics ones.
+//
+
+#define NDIS_OPEN_INTERNAL 1
+#define NDIS_OPEN_QUERY_STATISTICS 2
+
+//
+// An active query single statistic request.
+//
+
+typedef struct _NDIS_QUERY_GLOBAL_REQUEST {
+ PIRP Irp;
+ NDIS_REQUEST Request;
+} NDIS_QUERY_GLOBAL_REQUEST, *PNDIS_QUERY_GLOBAL_REQUEST;
+
+//
+// An active query all statistics request.
+//
+
+typedef struct _NDIS_QUERY_ALL_REQUEST {
+ PIRP Irp;
+ NDIS_REQUEST Request;
+ NDIS_STATUS NdisStatus;
+ KEVENT Event;
+} NDIS_QUERY_ALL_REQUEST, *PNDIS_QUERY_ALL_REQUEST;
+
+
+//
+// An temporary request used during an open.
+//
+
+typedef struct _NDIS_QUERY_OPEN_REQUEST {
+ PIRP Irp;
+ NDIS_REQUEST Request;
+ NDIS_STATUS NdisStatus;
+ KEVENT Event;
+} NDIS_QUERY_OPEN_REQUEST, *PNDIS_QUERY_OPEN_REQUEST;
+
+
+#define NDIS_STATISTICS_HEADER_SIZE FIELD_OFFSET(NDIS_STATISTICS_VALUE,Data[0])
+
+
+//
+// Timeout values
+//
+#define NDIS_MINIPORT_WAKEUP_TIMEOUT 2000 // Wakeup DPC
+#define NDIS_MINIPORT_TR_RESET_TIMEOUT 15 // Number of WakeUps per reset attempt
+
+extern
+NTSTATUS
+WrapperSaveParameters(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+extern
+NTSTATUS
+WrapperSaveLinkage(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+extern
+NTSTATUS
+WrapperCheckRoute(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+
+NTSTATUS
+NdisCreateIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ );
+
+NTSTATUS
+NdisDeviceControlIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ );
+
+NTSTATUS
+NdisCloseIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ );
+
+NTSTATUS
+NdisSuccessIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ );
+
+VOID
+HaltOneMiniport(
+ PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+VOID
+MiniportArcCopyFromBufferToPacket(
+ IN PCHAR Buffer,
+ IN UINT BytesToCopy,
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ OUT PUINT BytesCopied
+ );
+
+VOID
+NdisInitReferencePackage(VOID);
+
+VOID
+NdisInitDereferencePackage(VOID);
+
+VOID
+MiniportFinishPendingOpens(
+ PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+//
+// Some Wan functions that crept in because
+// the send/receive paths for WAN drivers is different
+//
+
+VOID
+NdisMWanSendComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ );
+
+NDIS_STATUS
+NdisMWanSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE NdisLinkHandle,
+ IN PVOID Packet
+ );
+
+VOID
+NdisMWanIndicateReceive(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE NdisLinkContext,
+ IN PUCHAR Packet,
+ IN ULONG PacketSize
+ );
+
+VOID
+NdisMWanIndicateReceiveComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE NdisLinkContext
+ );
+
+//
+// Internal definitions
+//
+
+typedef struct _NDIS_PACKET_RESERVED {
+ PNDIS_PACKET Next;
+ PNDIS_M_OPEN_BLOCK Open;
+} NDIS_PACKET_RESERVED, *PNDIS_PACKET_RESERVED;
+
+
+#define PNDIS_RESERVED_FROM_PNDIS_PACKET(_packet) \
+ ((PNDIS_PACKET_RESERVED)((_packet)->WrapperReserved))
+
+
+#define MINIPORT_ENABLE_INTERRUPT(_M_) \
+{ \
+ if (_M_->DriverHandle->MiniportCharacteristics.EnableInterruptHandler != NULL) { \
+ (_M_->DriverHandle->MiniportCharacteristics.EnableInterruptHandler)( \
+ _M_->MiniportAdapterContext \
+ ); \
+ } \
+}
+
+#define MINIPORT_SYNC_ENABLE_INTERRUPT(_M_) \
+{ \
+ if (_M_->DriverHandle->MiniportCharacteristics.EnableInterruptHandler != NULL) { \
+ KeSynchronizeExecution( \
+ (_M_)->Interrupt->InterruptObject, \
+ (PKSYNCHRONIZE_ROUTINE)(_M_->DriverHandle->MiniportCharacteristics.EnableInterruptHandler),\
+ _M_->MiniportAdapterContext \
+ ); \
+ } \
+}
+
+
+#define ARC_PACKET_IS_ENCAPSULATED(Packet) \
+ ( PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Open->UsingEthEncapsulation )
+
+
+#if DBG
+
+//
+// Packet log.
+//
+
+typedef struct _PACKET_LOG {
+
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PNDIS_PACKET Packet;
+ ULONG Ident;
+ ULONG Time;
+} PACKET_LOG, *PPACKET_LOG;
+
+#define PACKET_LOG_SIZE 1024
+
+UINT CurrentLogEntry = (PACKET_LOG_SIZE - 1);
+PPACKET_LOG PacketLogHead = NULL;
+PACKET_LOG PacketLog[PACKET_LOG_SIZE] = {0};
+NDIS_SPIN_LOCK PacketLogSpinLock = { 0 };
+
+VOID NDIS_LOG_PACKET(PNDIS_MINIPORT_BLOCK Miniport, PNDIS_PACKET Packet, UINT Ident)
+{
+ LARGE_INTEGER li;
+
+ ACQUIRE_SPIN_LOCK(&PacketLogSpinLock);
+
+ PacketLogHead = &PacketLog[CurrentLogEntry];
+ PacketLogHead->Miniport = Miniport;
+ PacketLogHead->Packet = Packet;
+ PacketLogHead->Ident = Ident;
+ KeQuerySystemTime(&li);
+ PacketLogHead->Time = li.LowPart;
+
+ if ( CurrentLogEntry-- == 0 ) {
+
+ CurrentLogEntry = (PACKET_LOG_SIZE - 1);
+ }
+
+ RELEASE_SPIN_LOCK(&PacketLogSpinLock);
+}
+
+//
+// Send log.
+//
+
+UCHAR SendLog[256] = {0};
+UCHAR SendLogPlace = 0;
+#define LOG(ch) \
+{\
+ SendLog[SendLogPlace++] = (UCHAR)ch;\
+ SendLog[SendLogPlace] = ' ';\
+ if (SendLogPlace > 250) {\
+ SendLogPlace = 0;\
+ }\
+}
+
+UCHAR SendResourcesBuffer[512] = {0};
+ULONG SendResourcesPlace = 0;
+
+ULONG StartCount = 0x7C;
+
+ULONG
+CountMiniportPackets(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+{
+ ULONG Foo = 0;
+ PNDIS_PACKET Tmp;
+
+ Tmp = Miniport->FirstPacket;
+
+ while (Tmp != Miniport->FirstPendingPacket) {
+ Foo++;
+ Tmp = PNDIS_RESERVED_FROM_PNDIS_PACKET(Tmp)->Next;
+ }
+ return(Foo);
+}
+
+#define REMOVE_RESOURCE(W, C) {\
+ W->SendResourcesAvailable--; \
+ SendResourcesBuffer[SendResourcesPlace++] = (UCHAR)C; \
+ SendResourcesBuffer[SendResourcesPlace++] = (UCHAR)'R'; \
+ SendResourcesBuffer[SendResourcesPlace++] = (UCHAR)W->SendResourcesAvailable;\
+ SendResourcesBuffer[SendResourcesPlace] = (UCHAR)'X'; \
+ if (SendResourcesPlace >= 500) {\
+ SendResourcesPlace = 0;\
+ }\
+}
+
+#define ADD_RESOURCE(W, C) {\
+ W->SendResourcesAvailable=0xffffff;\
+ SendResourcesBuffer[SendResourcesPlace++] = (UCHAR)C; \
+ SendResourcesBuffer[SendResourcesPlace++] = (UCHAR)'A';\
+ SendResourcesBuffer[SendResourcesPlace++] = (UCHAR)W->SendResourcesAvailable;\
+ SendResourcesBuffer[SendResourcesPlace] = (UCHAR)'X'; \
+ if (SendResourcesPlace >= 500) {\
+ SendResourcesPlace = 0;\
+ }\
+}
+
+#define CLEAR_RESOURCE(W, C) {\
+ W->SendResourcesAvailable = 0;\
+ SendResourcesBuffer[SendResourcesPlace++] = (UCHAR)C; \
+ SendResourcesBuffer[SendResourcesPlace++] = (UCHAR)'C';\
+ SendResourcesBuffer[SendResourcesPlace++] = (UCHAR)W->SendResourcesAvailable;\
+ if (SendResourcesPlace >= 500) {\
+ SendResourcesPlace = 0;\
+ }\
+}
+
+#else
+
+#define NDIS_LOG_PACKET(Miniport, Packet, Ident)
+#define LOG(ch)
+
+#define REMOVE_RESOURCE(W, C) W->SendResourcesAvailable--
+#define ADD_RESOURCE(W, C) W->SendResourcesAvailable = 0xffffff
+#define CLEAR_RESOURCE(W, C) W->SendResourcesAvailable = 0
+
+#endif
+
+/*++
+
+VOID
+MiniportFindPacket(
+ PNDIS_MINIPORT_BLOCK Miniport,
+ PNDIS_PACKET Packet,
+ PNDIS_PACKET *PrevPacket
+ )
+
+Routine Description:
+
+ Searchs the miniport send queue for a packet.
+
+Arguments:
+
+ Miniport - Miniport to send to.
+ Packet - Packet to find.
+
+Return Value:
+
+ Pointer to packet which immediately preceeds the packet to search for or
+ NULL if the packet is not found.
+
+--*/
+
+#define MiniportFindPacket(_Miniport, _Packet, _PrevPacket) \
+{ \
+ PNDIS_PACKET CurrPacket = ((PNDIS_MINIPORT_BLOCK)(_Miniport))->FirstPacket; \
+ PNDIS_PACKET TempPacket = NULL; \
+ \
+ ASSERT( CurrPacket != NULL ); \
+ \
+ do { \
+ \
+ if ( CurrPacket == ((PNDIS_PACKET)(_Packet)) ) { \
+ \
+ break; \
+ } \
+ \
+ TempPacket = CurrPacket; \
+ CurrPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(CurrPacket)->Next; \
+ } \
+ while( CurrPacket != NULL ); \
+ \
+ *((PNDIS_PACKET *)(_PrevPacket)) = TempPacket; \
+ \
+ ASSERT( CurrPacket != NULL ); \
+}
+
+//
+// Routines for dealing with making the entire miniport package pagable
+//
+
+NDIS_SPIN_LOCK MiniportReferenceLock = {0};
+KEVENT MiniportPagedInEvent = {0};
+ULONG MiniportReferenceCount = 0;
+PVOID MiniportImageHandle = {0};
+
+VOID
+MiniportInitializePackage(VOID)
+{
+ //
+ // Allocate the spin lock
+ //
+ NdisAllocateSpinLock(&MiniportReferenceLock);
+
+ //
+ // Initialize the "in page" event.
+ //
+ KeInitializeEvent(
+ &MiniportPagedInEvent,
+ NotificationEvent,
+ FALSE
+ );
+}
+
+VOID
+MiniportReferencePackage(VOID)
+{
+
+ //
+ // Grab the spin lock
+ //
+ ACQUIRE_SPIN_LOCK(&MiniportReferenceLock);
+
+ //
+ // Increment the reference count
+ //
+ MiniportReferenceCount++;
+
+ if (MiniportReferenceCount == 1) {
+
+ //
+ // We are the first reference. Page everything in.
+ //
+
+ //
+ // Clear the event
+ //
+ KeResetEvent(
+ &MiniportPagedInEvent
+ );
+
+ //
+ // Set the spin lock free
+ //
+ RELEASE_SPIN_LOCK(&MiniportReferenceLock);
+
+ //
+ // Page in all the functions
+ //
+ MiniportImageHandle = MmLockPagableCodeSection(NdisMReset);
+
+ //
+ // Signal to everyone to go
+ //
+ KeSetEvent(
+ &MiniportPagedInEvent,
+ 0L,
+ FALSE
+ );
+
+ } else {
+
+ //
+ // Set the spin lock free
+ //
+ RELEASE_SPIN_LOCK(&MiniportReferenceLock);
+
+ //
+ // Wait for everything to be paged in
+ //
+ KeWaitForSingleObject(
+ &MiniportPagedInEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ NULL
+ );
+
+ }
+
+}
+
+VOID
+MiniportDereferencePackage(VOID)
+{
+
+ //
+ // Get the spin lock
+ //
+ ACQUIRE_SPIN_LOCK(&MiniportReferenceLock);
+
+ MiniportReferenceCount--;
+
+ if (MiniportReferenceCount == 0) {
+
+ //
+ // Let next one in
+ //
+ RELEASE_SPIN_LOCK(&MiniportReferenceLock);
+
+ //
+ // Page out all the functions
+ //
+ MmUnlockPagableImageSection(MiniportImageHandle);
+
+ } else {
+
+ //
+ // Let next one in
+ //
+ RELEASE_SPIN_LOCK(&MiniportReferenceLock);
+
+ }
+
+}
+
+
+//
+// Forward declarations
+//
+
+VOID
+MiniportArcCopyFromBufferToPacket(
+ IN PCHAR Buffer,
+ IN UINT BytesToCopy,
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ OUT PUINT BytesCopied
+ );
+
+
+VOID
+NdisMTimerDpc(
+ PKDPC Dpc,
+ PVOID Context,
+ PVOID SystemContext1,
+ PVOID SystemContext2
+ );
+
+VOID
+AbortMiniportPacketsAndPending(
+ PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+VOID
+AbortQueryStatisticsRequest(
+ PNDIS_REQUEST Request,
+ NDIS_STATUS Status
+ );
+
+VOID
+FASTCALL
+MiniportStartSends(
+ PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+BOOLEAN
+FASTCALL
+MiniportSendLoopback(
+ PNDIS_MINIPORT_BLOCK Miniport,
+ PNDIS_PACKET Packet
+ );
+
+VOID
+MiniportDoRequests(
+ PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+NDIS_STATUS
+MiniportAdjustMaximumLookahead(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+VOID
+MiniportCopyFromPacketToBuffer(
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ IN UINT BytesToCopy,
+ OUT PCHAR Buffer,
+ OUT PUINT BytesCopied
+ );
+
+NTSTATUS
+NdisMShutdown(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ );
+
+VOID
+NdisMUnload(
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+NTSTATUS
+NdisMQueryOidList(
+ PNDIS_M_USER_OPEN_CONTEXT OpenContext,
+ PIRP Irp
+ );
+
+VOID
+FinishClose(
+ PNDIS_MINIPORT_BLOCK Miniport,
+ PNDIS_M_OPEN_BLOCK Open
+ );
+
+BOOLEAN
+NdisMKillOpen(
+ PNDIS_OPEN_BLOCK OldOpenP
+ );
+
+#if !defined(BUILD_FOR_3_1)
+VOID
+NdisBugcheckHandler(
+ IN PNDIS_WRAPPER_CONTEXT WrapperContext,
+ IN ULONG Size
+ );
+#endif
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGENDSM, NdisMReadDmaCounter)
+#pragma alloc_text(PAGENDSM, NdisMCancelTimer)
+#pragma alloc_text(PAGENDSM, MiniportArcCopyFromBufferToPacket)
+#pragma alloc_text(PAGENDSM, NdisMArcTransferData)
+#pragma alloc_text(PAGENDSM, NdisMArcIndicateEthEncapsulatedReceive)
+#pragma alloc_text(PAGENDSM, HaltOneMiniport)
+#pragma alloc_text(PAGENDSM, NdisMDeregisterDmaChannel)
+#pragma alloc_text(PAGENDSM, NdisMRegisterDmaChannel)
+#pragma alloc_text(PAGENDSM, NdisMFreeSharedMemory)
+#pragma alloc_text(PAGENDSM, NdisMAllocateSharedMemory)
+#pragma alloc_text(PAGENDSM, NdisMSynchronizeWithInterrupt)
+#pragma alloc_text(PAGENDSM, NdisMDeregisterInterrupt)
+#pragma alloc_text(PAGENDSM, NdisMRegisterInterrupt)
+#pragma alloc_text(PAGENDSM, NdisMUnmapIoSpace)
+#pragma alloc_text(PAGENDSM, NdisMMapIoSpace)
+#pragma alloc_text(PAGENDSM, NdisMRequest)
+#pragma alloc_text(PAGENDSM, NdisMReset)
+//#pragma alloc_text(PAGENDSM, NdisMTransferDataSync)
+//#pragma alloc_text(PAGENDSM, NdisMTransferData)
+//#pragma alloc_text(PAGENDSM, NdisMSend)
+#pragma alloc_text(PAGENDSM, NdisMQueryInformationComplete)
+#pragma alloc_text(PAGENDSM, NdisMTransferDataComplete)
+#pragma alloc_text(PAGENDSM, NdisMResetComplete)
+#pragma alloc_text(PAGENDSM, NdisMSetInformationComplete)
+#pragma alloc_text(PAGENDSM, NdisMSendResourcesAvailable)
+//#pragma alloc_text(PAGENDSM, NdisMSendComplete)
+#pragma alloc_text(PAGENDSM, NdisMIndicateStatusComplete)
+#pragma alloc_text(PAGENDSM, NdisMIndicateStatus)
+#pragma alloc_text(PAGENDSI, NdisMSetAttributes)
+#pragma alloc_text(PAGENDSM, NdisMDeregisterIoPortRange)
+#pragma alloc_text(PAGENDSM, NdisMRegisterIoPortRange)
+#pragma alloc_text(PAGENDSM, NdisMDpcTimer)
+//#pragma alloc_text(PAGENDSM, NdisMDpc)
+//#pragma alloc_text(PAGENDSM, NdisMIsr)
+#pragma alloc_text(PAGENDSM, NdisMFreeMapRegisters)
+#pragma alloc_text(PAGENDSI, NdisMAllocateMapRegisters)
+//#pragma alloc_text(PAGENDSM, NdisMWakeUpDpc)
+#pragma alloc_text(PAGENDSM, NdisMInitializeTimer)
+#pragma alloc_text(PAGENDSM, NdisMTimerDpc)
+//#pragma alloc_text(PAGENDSM, MiniportProcessDeferred)
+#pragma alloc_text(PAGENDSM, AbortMiniportPacketsAndPending)
+#pragma alloc_text(PAGENDSM, AbortQueryStatisticsRequest)
+//#pragma alloc_text(PAGENDSM, MiniportStartSends)
+//#pragma alloc_text(PAGENDSM, MiniportSendLoopback)
+#pragma alloc_text(PAGENDSM, MiniportDoRequests)
+#pragma alloc_text(PAGENDSM, MiniportAdjustMaximumLookahead)
+//#pragma alloc_text(PAGENDSM, MiniportCopyFromPacketToBuffer)
+#pragma alloc_text(PAGENDSM, NdisMShutdown)
+#pragma alloc_text(PAGENDSM, NdisMUnload)
+#pragma alloc_text(PAGENDSM, NdisDequeueMiniportOnDriver)
+#pragma alloc_text(PAGENDSM, NdisQueueMiniportOnDriver)
+#pragma alloc_text(PAGENDSM, NdisDereferenceMiniport)
+#pragma alloc_text(PAGENDSM, NdisDereferenceDriver)
+#pragma alloc_text(PAGENDSM, NdisMQueryOidList)
+#pragma alloc_text(PAGENDSM, NdisMChangeFddiAddresses)
+#pragma alloc_text(PAGENDSM, NdisMChangeGroupAddress)
+#pragma alloc_text(PAGENDSM, NdisMChangeFunctionalAddress)
+#pragma alloc_text(PAGENDSM, NdisMCloseAction)
+#pragma alloc_text(PAGENDSM, FinishClose)
+#pragma alloc_text(PAGENDSM, NdisMChangeClass)
+#pragma alloc_text(PAGENDSM, NdisMChangeEthAddresses)
+#pragma alloc_text(PAGENDSM, NdisMKillOpen)
+
+#pragma alloc_text(PAGENDSM, NdisMWanSend)
+#pragma alloc_text(PAGENDSM, NdisMWanSendComplete)
+#pragma alloc_text(PAGENDSM, NdisMWanIndicateReceive)
+#pragma alloc_text(PAGENDSM, NdisMWanIndicateReceiveComplete)
+
+#pragma alloc_text(PAGENDSM, NdisMRegisterAdapterShutdownHandler)
+#pragma alloc_text(PAGENDSM, NdisMDeregisterAdapterShutdownHandler)
+#pragma alloc_text(PAGENDSM, NdisMPciAssignResources)
+
+#endif
+
+//
+// Routines for dealing with opens
+//
+
+
+BOOLEAN
+NdisMKillOpen(
+ PNDIS_OPEN_BLOCK OldOpenP
+ )
+
+/*++
+
+Routine Description:
+
+ Closes an open. Used when NdisCloseAdapter is called, and also
+ for internally generated closes.
+
+Arguments:
+
+ OldOpenP - The open to be closed.
+
+Return Value:
+
+ TRUE if the open finished, FALSE if it pended.
+
+--*/
+
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(OldOpenP->AdapterHandle);
+ PNDIS_M_OPEN_BLOCK MiniportOpen;
+ BOOLEAN LocalLock;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+
+ //
+ // Find the Miniport open block
+ //
+ MiniportOpen = Miniport->OpenQueue;
+ while (MiniportOpen != NULL) {
+
+ if (MiniportOpen->FakeOpen == OldOpenP) {
+
+ break;
+
+ }
+
+ MiniportOpen = MiniportOpen->MiniportNextOpen;
+ }
+
+ ASSERT(MiniportOpen != NULL);
+
+ ACQUIRE_SPIN_LOCK(&MiniportOpen->SpinLock);
+
+ //
+ // See if this open is already closing.
+ //
+
+ if (MiniportOpen->Closing) {
+ RELEASE_SPIN_LOCK(&MiniportOpen->SpinLock);
+ return TRUE;
+ }
+
+
+ //
+ // Indicate to others that this open is closing.
+ //
+
+ MiniportOpen->Closing = TRUE;
+ RELEASE_SPIN_LOCK(&MiniportOpen->SpinLock);
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Remove us from the filter package
+ //
+ switch (Miniport->MediaType) {
+
+ case NdisMediumArcnet878_2:
+
+ if ( !MiniportOpen->UsingEthEncapsulation ) {
+
+ Status = ArcDeleteFilterOpenAdapter(
+ Miniport->ArcDB,
+ MiniportOpen->FilterHandle,
+ NULL
+ );
+
+ break;
+ }
+
+ //
+ // If we're using encapsulation then we
+ // didn't open an arcnet filter but rather
+ // an ethernet filter.
+ //
+
+ case NdisMedium802_3:
+
+ Status = EthDeleteFilterOpenAdapter(
+ Miniport->EthDB,
+ MiniportOpen->FilterHandle,
+ NULL
+ );
+ break;
+
+ case NdisMedium802_5:
+
+ Status = TrDeleteFilterOpenAdapter(
+ Miniport->TrDB,
+ MiniportOpen->FilterHandle,
+ NULL
+ );
+ break;
+
+ case NdisMediumFddi:
+
+ Status = FddiDeleteFilterOpenAdapter(
+ Miniport->FddiDB,
+ MiniportOpen->FilterHandle,
+ NULL
+ );
+ break;
+ }
+
+ if (Status != NDIS_STATUS_CLOSING_INDICATING) {
+
+ //
+ // Otherwise the close action routine will fix this up.
+ //
+ MiniportOpen->References--;
+ }
+
+ //
+ // If we're able to grab the local lock then we can do some
+ // deferred processing now.
+ //
+
+ if ( LocalLock ) {
+
+ //
+ // Process any changes that may have occured.
+ //
+
+ if (!Miniport->ProcessingDeferred) {
+
+ MiniportProcessDeferred(Miniport);
+
+ }
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Remove us from the adapter and protocol open queues.
+ //
+
+ if (MiniportOpen->References != 0) {
+
+ //
+ // Wait for close to complete, reference count will drop to 0.
+ //
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ return FALSE;
+
+ } else {
+
+ //
+ // This sends an IRP_MJ_CLOSE IRP.
+ //
+ ObDereferenceObject((PVOID)(OldOpenP->FileObject));
+
+ NdisDeQueueOpenOnProtocol(OldOpenP, OldOpenP->ProtocolHandle);
+ NdisDeQueueOpenOnMiniport(MiniportOpen, MiniportOpen->MiniportHandle);
+
+ NdisDereferenceProtocol(OldOpenP->ProtocolHandle);
+ NdisDereferenceMiniport(MiniportOpen->MiniportHandle);
+
+ NdisFreeSpinLock(&MiniportOpen->SpinLock);
+ ExFreePool((PVOID)MiniportOpen);
+ ExFreePool(OldOpenP);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ return TRUE;
+ }
+
+}
+
+
+//
+// Filter package callback handlers
+//
+
+#define PNDIS_M_OPEN_FROM_BINDING_HANDLE(_handle) ((PNDIS_M_OPEN_BLOCK)(_handle))
+
+
+NDIS_STATUS
+NdisMChangeEthAddresses(
+ IN UINT OldAddressCount,
+ IN CHAR OldAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN UINT NewAddressCount,
+ IN CHAR NewAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when the multicast address
+ list has changed.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ OldAddressCount - The number of addresses in OldAddresses.
+
+ OldAddresses - The old multicast address list.
+
+ NewAddressCount - The number of addresses in NewAddresses.
+
+ NewAddresses - The new multicast address list.
+
+ MacBindingHandle - The context value returned by the driver when the
+ adapter was opened. In reality, it is a pointer to W_OPEN_BLOCK.
+
+ RequestHandle - A value supplied by the NDIS interface that the driver
+ must use when completing this request.
+
+ Set - If true the change resulted from a set, otherwise the
+ change resulted from a open closing.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ PNDIS_M_OPEN_BLOCK Open = PNDIS_M_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter ChangeEthAddresses\n");)
+
+ if ((Open->MiniportHandle->MediaType == NdisMediumArcnet878_2) &&
+ (Open->UsingEthEncapsulation)) {
+
+ if (NewAddressCount > 0) {
+
+ //
+ // Turn on broadcast acceptance.
+ //
+ Open->MiniportHandle->ArcnetBroadcastSet = TRUE;
+
+ } else {
+
+ //
+ // Unset the broadcast filter.
+ //
+ Open->MiniportHandle->ArcnetBroadcastSet = FALSE;
+
+ }
+
+ Open->MiniportHandle->NeedToUpdatePacketFilter = TRUE;
+ Open->MiniportHandle->RunDoRequests = TRUE;
+ Open->MiniportHandle->ProcessOddDeferredStuff = TRUE;
+
+ return(NDIS_STATUS_SUCCESS);
+ }
+
+ //
+ // Queue a call to fix this up.
+ //
+ Open->MiniportHandle->NeedToUpdateEthAddresses = TRUE;
+ Open->MiniportHandle->RunDoRequests = TRUE;
+ Open->MiniportHandle->ProcessOddDeferredStuff = TRUE;
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit ChangeEthAddresses\n");)
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+NdisMChangeClass(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when a particular filter
+ class is first used or last cleared.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ OldFilterClasses - The values of the class filter before it
+ was changed.
+
+ NewFilterClasses - The current value of the class filter
+
+ MacBindingHandle - The context value returned by the driver when the
+ adapter was opened. In reality, it is a pointer to W_OPEN_BLOCK.
+
+ RequestHandle - A value supplied by the NDIS interface that the driver
+ must use when completing this request.
+
+ Set - If true the change resulted from a set, otherwise the
+ change resulted from a open closing.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ PNDIS_M_OPEN_BLOCK Open = PNDIS_M_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter change class\n");)
+
+ //
+ // Queue a call to fix this up.
+ //
+ Open->MiniportHandle->NeedToUpdatePacketFilter = TRUE;
+ Open->MiniportHandle->RunDoRequests = TRUE;
+ Open->MiniportHandle->ProcessOddDeferredStuff = TRUE;
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit change class\n");)
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+VOID
+FinishClose(
+ PNDIS_MINIPORT_BLOCK Miniport,
+ PNDIS_M_OPEN_BLOCK Open
+ )
+
+/*++
+
+Routine Description:
+
+ Finishes off a close adapter call.
+
+ CALLED WITH LOCK HELD!!
+
+Arguments:
+
+ Miniport - The mini-port the open is queued on.
+
+ Open - The open to close
+
+Return Value:
+
+ None.
+
+
+--*/
+
+
+{
+
+ ASSERT(Open->Closing);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.CloseAdapterCompleteHandler) (
+ Open->ProtocolBindingContext,
+ NDIS_STATUS_SUCCESS
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ NdisDeQueueOpenOnProtocol(Open->FakeOpen, Open->ProtocolHandle);
+ NdisDeQueueOpenOnMiniport(Open, Open->MiniportHandle);
+ ExFreePool(Open->FakeOpen);
+
+ NdisDereferenceMiniport(Open->MiniportHandle);
+ NdisDereferenceProtocol(Open->ProtocolHandle);
+
+ NdisFreeSpinLock(&Open->SpinLock);
+
+ //
+ // This sends an IRP_MJ_CLOSE IRP.
+ //
+
+ ObDereferenceObject((PVOID)(Open->FileObject));
+
+ ExFreePool((PVOID)Open);
+
+}
+
+
+VOID
+NdisMCloseAction(
+ IN NDIS_HANDLE MacBindingHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when a particular binding
+ was closed while it was indicating through NdisIndicateReceive
+
+ All this routine needs to do is to decrement the reference count
+ of the binding.
+
+ NOTE: This routine assumes that it is called with the lock acquired.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the driver when the
+ adapter was opened. In reality, it is a pointer to W_OPEN_BLOCK.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ PNDIS_M_OPEN_BLOCK Open = PNDIS_M_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+ PNDIS_MINIPORT_BLOCK Miniport = Open->MiniportHandle;
+
+ Open->References--;
+ if (Open->References == 0) {
+
+ FinishClose(Miniport,Open);
+
+ }
+
+}
+
+
+NDIS_STATUS
+NdisMChangeFunctionalAddress(
+ IN TR_FUNCTIONAL_ADDRESS OldFunctionalAddress,
+ IN TR_FUNCTIONAL_ADDRESS NewFunctionalAddress,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when an address is added to
+ the filter that wasn't referenced by any other open binding.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ OldFunctionalAddress - The previous functional address.
+
+ NewFunctionalAddress - The new functional address.
+
+ MacBindingHandle - The context value returned by the driver when the
+ adapter was opened. In reality, it is a pointer to W_OPEN_BLOCK.
+
+ NdisRequest - A pointer to the Request that submitted the set command.
+
+ Set - If true the change resulted from a set, otherwise the
+ change resulted from a open closing.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ PNDIS_M_OPEN_BLOCK Open = PNDIS_M_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter change functional\n");)
+
+ //
+ // Queue a call to fix this up.
+ //
+ Open->MiniportHandle->NeedToUpdateFunctionalAddress = TRUE;
+ Open->MiniportHandle->RunDoRequests = TRUE;
+ Open->MiniportHandle->ProcessOddDeferredStuff = TRUE;
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit change functional\n");)
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+NdisMChangeGroupAddress(
+ IN TR_FUNCTIONAL_ADDRESS OldGroupAddress,
+ IN TR_FUNCTIONAL_ADDRESS NewGroupAddress,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when a group address is to
+ be changed.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ OldGroupAddress - The previous group address.
+
+ NewGroupAddress - The new group address.
+
+ MacBindingHandle - The context value returned by the driver when the
+ adapter was opened. In reality, it is a pointer to W_OPEN_BLOCK.
+
+ NdisRequest - A pointer to the Request that submitted the set command.
+
+ Set - If true the change resulted from a set, otherwise the
+ change resulted from a open closing.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ PNDIS_M_OPEN_BLOCK Open = PNDIS_M_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter change group\n");)
+
+ //
+ // Queue a call to fix this up.
+ //
+ Open->MiniportHandle->NeedToUpdateGroupAddress = TRUE;
+ Open->MiniportHandle->RunDoRequests = TRUE;
+ Open->MiniportHandle->ProcessOddDeferredStuff = TRUE;
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit change group\n");)
+
+ return(NDIS_STATUS_SUCCESS);
+
+}
+
+
+NDIS_STATUS
+NdisMChangeFddiAddresses(
+ IN UINT oldLongAddressCount,
+ IN CHAR oldLongAddresses[][FDDI_LENGTH_OF_LONG_ADDRESS],
+ IN UINT newLongAddressCount,
+ IN CHAR newLongAddresses[][FDDI_LENGTH_OF_LONG_ADDRESS],
+ IN UINT oldShortAddressCount,
+ IN CHAR oldShortAddresses[][FDDI_LENGTH_OF_SHORT_ADDRESS],
+ IN UINT newShortAddressCount,
+ IN CHAR newShortAddresses[][FDDI_LENGTH_OF_SHORT_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when the multicast address
+ list has changed.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ oldAddressCount - The number of addresses in oldAddresses.
+
+ oldAddresses - The old multicast address list.
+
+ newAddressCount - The number of addresses in newAddresses.
+
+ newAddresses - The new multicast address list.
+
+ macBindingHandle - The context value returned by the driver when the
+ adapter was opened. In reality, it is a pointer to W_OPEN_BLOCK.
+
+ requestHandle - A value supplied by the NDIS interface that the driver
+ must use when completing this request.
+
+ Set - If true the change resulted from a set, otherwise the
+ change resulted from a open closing.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ PNDIS_M_OPEN_BLOCK Open = PNDIS_M_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter change fddi addresses\n");)
+
+ //
+ // Queue a call to fix this up.
+ //
+ Open->MiniportHandle->NeedToUpdateFddiLongAddresses = TRUE;
+ Open->MiniportHandle->NeedToUpdateFddiShortAddresses = TRUE;
+ Open->MiniportHandle->RunDoRequests = TRUE;
+ Open->MiniportHandle->ProcessOddDeferredStuff = TRUE;
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit change fddi addresses\n");)
+
+ return(NDIS_STATUS_SUCCESS);
+
+}
+
+//
+// IRP handlers established on behalf of NDIS devices by
+// the wrapper.
+//
+
+
+
+NTSTATUS
+NdisMQueryOidList(
+ PNDIS_M_USER_OPEN_CONTEXT OpenContext,
+ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will take care of querying the complete OID
+ list for the driver and filling in OpenContext->OidArray
+ with the ones that are statistics. It blocks when the
+ driver pends and so is synchronous.
+
+Arguments:
+
+ OpenContext - The open context.
+ Irp = The IRP that the open was done on (used at completion
+ to distinguish the request).
+
+Return Value:
+
+ STATUS_SUCCESS if it should be.
+
+--*/
+
+{
+ NDIS_QUERY_OPEN_REQUEST OpenRequest;
+ NDIS_STATUS NdisStatus;
+ PNDIS_OID TmpBuffer;
+ ULONG TmpBufferLength;
+ UINT i, j;
+ PNDIS_REQUEST_RESERVED Reserved;
+ BOOLEAN LocalLock;
+ PNDIS_MINIPORT_BLOCK Miniport = OpenContext->MiniportBlock;
+ KIRQL OldIrql;
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter query oid list\n");)
+
+ KeRaiseIrql( DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // First query the OID list with no buffer, to find out
+ // how big it should be.
+ //
+
+ KeInitializeEvent(
+ &OpenRequest.Event,
+ NotificationEvent,
+ FALSE
+ );
+
+ OpenRequest.Irp = Irp;
+
+ //
+ // Build fake request
+ //
+
+ OpenRequest.Request.RequestType = NdisRequestQueryStatistics;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_SUPPORTED_LIST;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBuffer = NULL;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBufferLength = 0;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded = 0;
+
+ //
+ // Put request on queue
+ //
+
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(&(OpenRequest.Request));
+ Reserved->Next = NULL;
+ Miniport->LastPendingRequest = &(OpenRequest.Request);
+
+ if (Miniport->FirstPendingRequest == NULL) {
+
+ Miniport->FirstPendingRequest = &(OpenRequest.Request);
+
+ } else {
+
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Miniport->LastPendingRequest)->Next =
+ &(OpenRequest.Request);
+
+ }
+
+ if (Miniport->MiniportRequest == NULL) {
+
+ Miniport->RunDoRequests = TRUE;
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+ }
+
+ if ( LocalLock ) {
+
+ if (!Miniport->ProcessingDeferred) {
+
+ MiniportProcessDeferred(Miniport);
+ }
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ KeLowerIrql(OldIrql);
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &OpenRequest.Event,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ KeRaiseIrql( DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisStatus = OpenRequest.NdisStatus;
+
+ if ((NdisStatus != NDIS_STATUS_INVALID_LENGTH) &&
+ (NdisStatus != NDIS_STATUS_BUFFER_TOO_SHORT)) {
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ KeLowerIrql(OldIrql);
+ return(NdisStatus);
+
+ }
+
+ //
+ // Now we know how much is needed, allocate temp storage...
+ //
+
+ TmpBufferLength = OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded;
+ TmpBuffer = ExAllocatePool(NonPagedPool, TmpBufferLength);
+
+ if (TmpBuffer == NULL) {
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ KeLowerIrql(OldIrql);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // ...and query the real list.
+ //
+
+ KeResetEvent(
+ &OpenRequest.Event
+ );
+
+ OpenRequest.Request.RequestType = NdisRequestQueryStatistics;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_SUPPORTED_LIST;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBuffer = TmpBuffer;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBufferLength = TmpBufferLength;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded = 0;
+
+ //
+ // Put request on queue
+ //
+
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(&(OpenRequest.Request));
+ Reserved->Next = NULL;
+ Miniport->LastPendingRequest = &(OpenRequest.Request);
+
+ if (Miniport->FirstPendingRequest == NULL) {
+
+ Miniport->FirstPendingRequest = &(OpenRequest.Request);
+
+ } else {
+
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Miniport->LastPendingRequest)->Next =
+ &(OpenRequest.Request);
+
+ }
+
+ if (Miniport->MiniportRequest == NULL) {
+
+ Miniport->RunDoRequests = TRUE;
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+ }
+
+ if ( LocalLock ) {
+
+ if (!Miniport->ProcessingDeferred) {
+
+ MiniportProcessDeferred(Miniport);
+ }
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ KeLowerIrql(OldIrql);
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &OpenRequest.Event,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ KeRaiseIrql( DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisStatus = OpenRequest.NdisStatus;
+
+ ASSERT (NdisStatus == NDIS_STATUS_SUCCESS);
+
+
+ //
+ // Now go through the buffer, counting the statistics OIDs.
+ //
+
+ for (i=0; i<TmpBufferLength/sizeof(NDIS_OID); i++) {
+ if ((TmpBuffer[i] & 0x00ff0000) == 0x00020000) {
+ ++OpenContext->OidCount;
+ }
+ }
+
+ //
+ // Now allocate storage for the real OID array.
+ //
+
+ OpenContext->OidArray = ExAllocatePool (NonPagedPool, OpenContext->OidCount * sizeof(NDIS_OID));
+
+ if (OpenContext->OidArray == NULL) {
+ ExFreePool (TmpBuffer);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ KeLowerIrql(OldIrql);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Now go through the buffer, copying the statistics OIDs.
+ //
+
+ j = 0;
+ for (i=0; i<TmpBufferLength/sizeof(NDIS_OID); i++) {
+
+ if ((TmpBuffer[i] & 0x00ff0000) == 0x00020000) {
+ OpenContext->OidArray[j] = TmpBuffer[i];
+ ++j;
+ }
+ }
+
+ ASSERT (j == OpenContext->OidCount);
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit query oid list\n");)
+
+ ExFreePool (TmpBuffer);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ KeLowerIrql(OldIrql);
+ return STATUS_SUCCESS;
+}
+
+VOID
+NdisLastCountRemovedFunction(
+ IN struct _KDPC *Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+
+#define NdisReferenceDriver(WDriver) NdisReferenceRef(&(WDriver)->Ref)
+
+
+VOID
+NdisDereferenceDriver(
+ PNDIS_M_DRIVER_BLOCK WDriver
+ )
+/*++
+
+Routine Description:
+
+ Removes a reference from the mini-port driver, deleting it if the count goes to 0.
+
+Arguments:
+
+ Miniport - The mini-port block to dereference.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ if (NdisDereferenceRef(&(WDriver)->Ref)) {
+
+ //
+ // Remove it from the global list.
+ //
+
+ ACQUIRE_SPIN_LOCK(&NdisDriverListLock);
+
+ if (NdisDriverList == WDriver) {
+
+ NdisDriverList = WDriver->NextDriver;
+
+ } else {
+
+ PNDIS_M_DRIVER_BLOCK TmpDriver = NdisDriverList;
+
+ while(TmpDriver->NextDriver != WDriver) {
+
+ TmpDriver = TmpDriver->NextDriver;
+
+ }
+
+ TmpDriver->NextDriver = TmpDriver->NextDriver->NextDriver;
+
+ }
+
+ RELEASE_SPIN_LOCK(&NdisDriverListLock);
+
+ if (WDriver->FakeMac != NULL) {
+ ExFreePool((PVOID)(WDriver->FakeMac));
+ }
+
+ ExFreePool((PVOID)(WDriver));
+
+ }
+}
+
+
+VOID
+NdisDereferenceMiniport(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+/*++
+
+Routine Description:
+
+ Removes a reference from the mini-port driver, deleting it if the count goes to 0.
+
+Arguments:
+
+ Miniport - The mini-port block to dereference.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ if (NdisDereferenceRef(&(Miniport)->Ref)) {
+
+ if (Miniport->EthDB) {
+ EthDeleteFilter(Miniport->EthDB);
+ }
+
+ if (Miniport->TrDB) {
+ TrDeleteFilter(Miniport->TrDB);
+ }
+
+ if (Miniport->FddiDB) {
+ FddiDeleteFilter(Miniport->FddiDB);
+ }
+
+ if (Miniport->ArcDB) {
+ ArcDeleteFilter(Miniport->ArcDB);
+ }
+
+ if (((PNDIS_WRAPPER_CONTEXT)Miniport->WrapperContext)->AssignedSlotResources != NULL ) {
+ ExFreePool( ((PNDIS_WRAPPER_CONTEXT)Miniport->WrapperContext)->AssignedSlotResources );
+ }
+
+ NdisDequeueMiniportOnDriver(Miniport, Miniport->DriverHandle);
+ NdisDereferenceDriver(Miniport->DriverHandle);
+ NdisMDeregisterAdapterShutdownHandler( Miniport );
+ IoUnregisterShutdownNotification(Miniport->DeviceObject);
+ IoDeleteDevice(Miniport->DeviceObject);
+
+ }
+}
+
+
+
+BOOLEAN
+NdisQueueMiniportOnDriver(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_M_DRIVER_BLOCK WDriver
+ )
+
+/*++
+
+Routine Description:
+
+ Adds an mini-port to a list of mini-port for a driver.
+
+Arguments:
+
+ Miniport - The mini-port block to queue.
+ WDriver - The driver block to queue it to.
+
+Return Value:
+
+ FALSE if the driver is closing.
+ TRUE otherwise.
+
+--*/
+
+{
+ ACQUIRE_SPIN_LOCK(&WDriver->Ref.SpinLock);
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter queue mini-port on driver\n");)
+ LOUD_DEBUG(DbgPrint("NdisM: queue mini-port 0x%x\n", Miniport);)
+ LOUD_DEBUG(DbgPrint("NdisM: driver 0x%x\n", WDriver);)
+
+
+ //
+ // Make sure the driver is not closing.
+ //
+
+ if (WDriver->Ref.Closing) {
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit queue mini-port on driver\n");)
+
+ RELEASE_SPIN_LOCK(&WDriver->Ref.SpinLock);
+ return FALSE;
+ }
+
+
+ //
+ // Add this adapter at the head of the queue
+ //
+
+ Miniport->NextMiniport = WDriver->MiniportQueue;
+ WDriver->MiniportQueue = Miniport;
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit queue mini-port on driver\n");)
+
+ RELEASE_SPIN_LOCK(&WDriver->Ref.SpinLock);
+ return TRUE;
+}
+
+
+VOID
+NdisDequeueMiniportOnDriver(
+ PNDIS_MINIPORT_BLOCK Miniport,
+ PNDIS_M_DRIVER_BLOCK WDriver
+ )
+
+/*++
+
+Routine Description:
+
+ Removes an mini-port from a list of mini-port for a driver.
+
+Arguments:
+
+ Miniport - The mini-port block to dequeue.
+ WDriver - The driver block to dequeue it from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ACQUIRE_SPIN_LOCK(&WDriver->Ref.SpinLock);
+
+ LOUD_DEBUG(DbgPrint("NdisM: Dequeue on driver\n");)
+ LOUD_DEBUG(DbgPrint("NdisM: dequeue mini-port 0x%x\n", Miniport);)
+ LOUD_DEBUG(DbgPrint("NdisM: driver 0x%x\n", WDriver);)
+
+ //
+ // Find the driver on the queue, and remove it.
+ //
+
+ if (WDriver->MiniportQueue == Miniport) {
+ WDriver->MiniportQueue = Miniport->NextMiniport;
+ } else {
+ PNDIS_MINIPORT_BLOCK MP = WDriver->MiniportQueue;
+
+ while (MP->NextMiniport != Miniport) {
+ MP = MP->NextMiniport;
+ }
+
+ MP->NextMiniport = MP->NextMiniport->NextMiniport;
+ }
+
+ RELEASE_SPIN_LOCK(&WDriver->Ref.SpinLock);
+
+ if (WDriver->Unloading && (WDriver->MiniportQueue == (PNDIS_MINIPORT_BLOCK)NULL)) {
+
+ KeSetEvent(
+ &WDriver->MiniportsRemovedEvent,
+ 0L,
+ FALSE
+ );
+
+ }
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit dequeue mini-port on driver\n");)
+}
+
+
+
+
+VOID
+NdisMUnload(
+ IN PDRIVER_OBJECT DriverObject
+ )
+/*++
+
+Routine Description:
+
+ This routine is called when a driver is supposed to unload. Ndis
+ converts this into a set of calls to MiniportHalt() for each
+ adapter that the driver has open.
+
+Arguments:
+
+ DriverObject - the driver object for the mac that is to unload.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_M_DRIVER_BLOCK WDriver;
+ PNDIS_MINIPORT_BLOCK Miniport, NextMiniport;
+ KIRQL OldIrql;
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter unload\n");)
+
+ //
+ // Search for the driver
+ //
+
+ ACQUIRE_SPIN_LOCK(&NdisDriverListLock);
+
+ WDriver = NdisDriverList;
+
+ while (WDriver != (PNDIS_M_DRIVER_BLOCK)NULL) {
+
+ if (WDriver->NdisDriverInfo->NdisWrapperDriver == DriverObject) {
+
+ break;
+
+ }
+
+ WDriver = WDriver->NextDriver;
+
+ }
+
+ RELEASE_SPIN_LOCK(&NdisDriverListLock);
+
+ if (WDriver == (PNDIS_M_DRIVER_BLOCK)NULL) {
+
+ //
+ // It is already gone. Just return.
+ //
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit unload\n");)
+
+ return;
+
+ }
+
+ WDriver->Unloading = TRUE;
+
+
+ LOUD_DEBUG(DbgPrint("NdisM: Halting mini-port\n");)
+
+ //
+ // Now call MiniportHalt() for each Miniport.
+ //
+
+ Miniport = WDriver->MiniportQueue;
+
+ while (Miniport != (PNDIS_MINIPORT_BLOCK)NULL) {
+
+ NextMiniport = Miniport->NextMiniport; // since queue may change
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter shutdown\n");)
+
+ Miniport->HaltingMiniport = TRUE;
+ Miniport->NormalInterrupts = FALSE;
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ HaltOneMiniport(Miniport);
+
+ Miniport = NextMiniport;
+ }
+
+ //
+ // Wait for all adapters to be gonzo.
+ //
+
+ KeWaitForSingleObject(
+ &WDriver->MiniportsRemovedEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PTIME)NULL
+ );
+
+ KeResetEvent(
+ &WDriver->MiniportsRemovedEvent
+ );
+
+ //
+ // Now remove the last reference (this will remove it from the list)
+ //
+
+ ASSERT(WDriver->Ref.ReferenceCount == 1);
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit unload\n");)
+
+ NdisDereferenceDriver(WDriver);
+}
+
+
+NTSTATUS
+NdisMShutdown(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ The "shutdown handler" for the SHUTDOWN Irp. Will call the Ndis
+ shutdown routine, if one is registered.
+
+Arguments:
+
+ DeviceObject - The adapter's device object.
+ Irp - The IRP.
+
+Return Value:
+
+ Always STATUS_SUCCESS.
+
+--*/
+
+{
+ PNDIS_WRAPPER_CONTEXT WrapperContext = (PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(WrapperContext + 1);
+ KIRQL OldIrql;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ Miniport->HaltingMiniport = TRUE;
+ Miniport->NormalInterrupts = FALSE;
+
+ if (WrapperContext->ShutdownHandler != NULL) {
+
+ while (Miniport->LockAcquired) {
+
+ //
+ // This can only happen on an MP system. We must now
+ // wait for the other processor to exit the mini-port.
+ //
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ NdisStallExecution(1000);
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+ }
+
+ //
+ // Lock miniport so that nothing will enter it.
+ //
+
+ Miniport->LockAcquired = TRUE;
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ //
+ // Call the shutdown routine.
+ //
+
+ if (WrapperContext->ShutdownHandler != NULL) {
+ WrapperContext->ShutdownHandler(WrapperContext->ShutdownContext);
+ }
+
+ Miniport->LockAcquired = FALSE;
+
+ } else {
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ }
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisMShutdown\n");
+
+ return STATUS_SUCCESS;
+}
+
+//
+// This constant is used for places where NdisAllocateMemory
+// needs to be called and the HighestAcceptableAddress does
+// not matter.
+//
+
+static const NDIS_PHYSICAL_ADDRESS HighestAcceptableMax =
+ NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
+
+
+
+
+VOID
+MiniportCopyFromPacketToBuffer(
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ IN UINT BytesToCopy,
+ OUT PCHAR Buffer,
+ OUT PUINT BytesCopied
+ )
+
+/*++
+
+Routine Description:
+
+ Copy from an ndis packet into a buffer.
+
+Arguments:
+
+ Packet - The packet to copy from.
+
+ Offset - The offset from which to start the copy.
+
+ BytesToCopy - The number of bytes to copy from the packet.
+
+ Buffer - The destination of the copy.
+
+ BytesCopied - The number of bytes actually copied. Can be less then
+ BytesToCopy if the packet is shorter than BytesToCopy.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ //
+ // Holds the number of ndis buffers comprising the packet.
+ //
+ UINT NdisBufferCount;
+
+ //
+ // Points to the buffer from which we are extracting data.
+ //
+ PNDIS_BUFFER CurrentBuffer;
+
+ //
+ // Holds the virtual address of the current buffer.
+ //
+ PVOID VirtualAddress;
+
+ //
+ // Holds the length of the current buffer of the packet.
+ //
+ UINT CurrentLength;
+
+ //
+ // Keep a local variable of BytesCopied so we aren't referencing
+ // through a pointer.
+ //
+ UINT LocalBytesCopied = 0;
+
+ //
+ // Take care of boundary condition of zero length copy.
+ //
+
+ *BytesCopied = 0;
+ if (!BytesToCopy) return;
+
+ //
+ // Get the first buffer.
+ //
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ &NdisBufferCount,
+ &CurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet.
+ //
+
+ if (!NdisBufferCount) return;
+
+ NdisQueryBuffer(
+ CurrentBuffer,
+ &VirtualAddress,
+ &CurrentLength
+ );
+
+ while (LocalBytesCopied < BytesToCopy) {
+
+ if (CurrentLength == 0) {
+
+ NdisGetNextBuffer(
+ CurrentBuffer,
+ &CurrentBuffer
+ );
+
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.
+ //
+
+ if (!CurrentBuffer) break;
+
+ NdisQueryBuffer(
+ CurrentBuffer,
+ &VirtualAddress,
+ &CurrentLength
+ );
+ continue;
+
+ }
+
+ //
+ // Try to get us up to the point to start the copy.
+ //
+
+ if (Offset) {
+
+ if (Offset > CurrentLength) {
+
+ //
+ // What we want isn't in this buffer.
+ //
+
+ Offset -= CurrentLength;
+ CurrentLength = 0;
+ continue;
+
+ } else {
+
+ VirtualAddress = (PCHAR)VirtualAddress + Offset;
+ CurrentLength -= Offset;
+ Offset = 0;
+
+ }
+
+ }
+
+ //
+ // Copy the data.
+ //
+
+
+ {
+
+ //
+ // Holds the amount of data to move.
+ //
+ UINT AmountToMove;
+
+ AmountToMove =
+ ((CurrentLength <= (BytesToCopy - LocalBytesCopied))?
+ (CurrentLength):(BytesToCopy - LocalBytesCopied));
+
+ NdisMoveMemory(
+ Buffer,
+ VirtualAddress,
+ AmountToMove
+ );
+
+ Buffer = (PCHAR)Buffer + AmountToMove;
+ VirtualAddress = (PCHAR)VirtualAddress + AmountToMove;
+
+ LocalBytesCopied += AmountToMove;
+ CurrentLength -= AmountToMove;
+
+ }
+
+ }
+
+ *BytesCopied = LocalBytesCopied;
+
+}
+
+
+
+NDIS_STATUS
+MiniportAdjustMaximumLookahead(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ )
+/*++
+
+Routine Description:
+
+ This routine finds the open with the maximum lookahead value and
+ stores that in the mini-port block.
+
+Arguments:
+
+ Miniport - A pointer to the mini-port block.
+
+Returns:
+
+ Status of the operation
+
+--*/
+{
+ ULONG CurrentMax = 0;
+ PNDIS_M_OPEN_BLOCK CurrentOpen;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ CurrentOpen = Miniport->OpenQueue;
+
+ while (CurrentOpen != NULL) {
+
+ if (CurrentOpen->CurrentLookahead > CurrentMax) {
+
+ CurrentMax = CurrentOpen->CurrentLookahead;
+
+ }
+
+ CurrentOpen = CurrentOpen->MiniportNextOpen;
+ }
+
+ if (CurrentMax == 0) {
+
+ CurrentMax = Miniport->MaximumLookahead;
+
+ } else if (CurrentMax > Miniport->MaximumLookahead) {
+
+ CurrentMax = Miniport->MaximumLookahead;
+
+ }
+
+ if (Miniport->CurrentLookahead != CurrentMax) {
+
+ BOOLEAN CompleteRequestMyself = TRUE;
+
+ if (Miniport->MiniportRequest) {
+
+ CompleteRequestMyself = FALSE;
+
+ //
+ // This is due to a request -- complete it before submitting a
+ // new one to the mini-port.
+ //
+ NdisMSetInformationComplete(
+ (NDIS_HANDLE)Miniport,
+ NDIS_STATUS_SUCCESS
+ );
+ }
+
+ //
+ // Change it
+ //
+
+ NdisMoveMemory(Miniport->MulticastBuffer, &CurrentMax, sizeof(CurrentMax));
+
+ Miniport->CurrentLookahead = CurrentMax;
+ Miniport->MiniportRequest = &(Miniport->InternalRequest);
+ Miniport->InternalRequest.RequestType = NdisRequestSetInformation;
+
+ Status =
+ (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ Miniport->MulticastBuffer,
+ sizeof(CurrentMax),
+ &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesRead,
+ &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesNeeded
+ );
+
+ if (CompleteRequestMyself && (Status != NDIS_STATUS_PENDING)) {
+
+ //
+ // This is not called from within a request, so no-one will be
+ // expecting to complete this, so we must do it now.
+ //
+
+ NdisMSetInformationComplete(
+ (NDIS_HANDLE)Miniport,
+ Status
+ );
+
+ }
+
+ }
+
+ return Status;
+
+}
+
+NDIS_STATUS FilterOutOidStatistics(
+ PNDIS_MINIPORT_BLOCK Miniport,
+ PNDIS_REQUEST pRequest,
+ PNDIS_OID pDstOid,
+ PULONG pcbDestination,
+ PNDIS_OID pSrcOid,
+ ULONG cbSource
+)
+{
+ BOOLEAN fARCnet;
+ ULONG cGlobalOids;
+ ULONG cInfoOids;
+ ULONG cbListSizeNeeded;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PNDIS_REQUEST_RESERVED pReserved =
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(pRequest);
+
+ //????
+ // Currently there are two different mappings:
+ // ARCnet -> Map Ethernet OIDs to ARCnet & remove
+ // non-statistics OIDs.
+ // Other -> Everything else is just the removal of
+ // statistics OIDs.
+ //
+ // Since we need to remove statistics OIDs from both we copy
+ // the OIDs that we want into the buffer passed to us.
+ // Then if the request is from an ARCnet NIC we filter into
+ // our temp buffer and copy it back to the callers buffer....
+ // I think that this will be better than an inplace shuffle for
+ // the ARCnet OIDs.
+ //????
+
+ //
+ // Are we using ARCnet with Ethernet encapsulation>
+ //
+ fARCnet = ((Miniport->MediaType == NdisMediumArcnet878_2) &&
+ pReserved->Open->UsingEthEncapsulation) ? TRUE : FALSE;
+
+ //
+ // Count the number of non-statistics OIDs.
+ //
+ for
+ (
+ cGlobalOids = 0, cInfoOids = 0;
+ cGlobalOids < (cbSource / sizeof(NDIS_OID));
+ cGlobalOids++
+ )
+ {
+ if ((pSrcOid[cGlobalOids] & 0x00FF0000) != 0x00020000)
+ cInfoOids++;
+ }
+
+ //
+ // Determine the list size that is needed.
+ //
+ cbListSizeNeeded = (cInfoOids * sizeof(NDIS_OID));
+ if (fARCnet)
+ cbListSizeNeeded += (ARC_NUMBER_OF_EXTRA_OIDS * sizeof(NDIS_OID));
+
+ //
+ // Verify that the buffer passed in on the original request
+ // is large enough for the OID list.
+ //
+ if (cbListSizeNeeded > *pcbDestination)
+ {
+ //
+ // Save the correct buffer size in the
+ // appropriate spot.
+ //
+ *pcbDestination = cInfoOids * sizeof(NDIS_OID);
+
+ return(NDIS_STATUS_BUFFER_TOO_SHORT);
+ }
+
+ //
+ // Copy the information OIDs to the buffer that
+ // was passed with the original request.
+ //
+ for
+ (
+ cGlobalOids = 0, cInfoOids = 0;
+ cGlobalOids < (cbSource / sizeof(NDIS_OID));
+ cGlobalOids++
+ )
+ {
+ //
+ // If its not a statistic OID then save it.
+ //
+ if ((pSrcOid[cGlobalOids] & 0x00FF0000) != 0x00020000)
+ {
+ pDstOid[cInfoOids] = pSrcOid[cGlobalOids];
+ cInfoOids++;
+ }
+ }
+
+ //
+ // If ARCnet then do the filtering.
+ //
+ if (fARCnet)
+ {
+ Status = ArcConvertOidListToEthernet(
+ pDstOid,
+ &cInfoOids,
+ pSrcOid
+ );
+ }
+
+ //
+ // Save the amount of data that was kept.
+ //
+ *pcbDestination = cInfoOids * sizeof(NDIS_OID);
+
+ return(Status);
+}
+
+
+VOID
+MiniportDoRequests(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Submits a request to the mini-port.
+
+Arguments:
+
+ Miniport - Miniport to send to.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS Status;
+ BOOLEAN DoneSomething = TRUE;
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter do requests\n");)
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ while (DoneSomething)
+ {
+ DoneSomething = FALSE;
+ Status = NDIS_STATUS_SUCCESS;
+
+ if (Miniport->NeedToUpdateEthAddresses)
+ {
+ UINT NumberOfAddresses;
+
+ DoneSomething = TRUE;
+ //
+ // This is an internal update that is needed.
+ //
+
+ Miniport->MiniportRequest = &(Miniport->InternalRequest);
+ Miniport->NeedToUpdateEthAddresses = FALSE;
+
+ //
+ // Get information needed
+ //
+
+ LOUD_DEBUG(DbgPrint("NdisM: Updating eth multicast list\n");)
+
+ EthQueryGlobalFilterAddresses(
+ &Status,
+ Miniport->EthDB,
+ NDIS_M_MAX_MULTI_LIST * ETH_LENGTH_OF_ADDRESS,
+ &NumberOfAddresses,
+ (PVOID)Miniport->MulticastBuffer
+ );
+
+ //
+ // Submit Request
+ //
+ Miniport->InternalRequest.RequestType = NdisRequestSetInformation;
+
+ Status =
+ (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ OID_802_3_MULTICAST_LIST,
+ Miniport->MulticastBuffer,
+ NumberOfAddresses * ETH_LENGTH_OF_ADDRESS,
+ &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesRead,
+ &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesNeeded
+ );
+
+ if ((Status == NDIS_STATUS_PENDING) && (Miniport->MiniportRequest)) {
+
+ //
+ // Still outstanding
+ //
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit do requests\n");)
+
+ Miniport->RunDoRequests = FALSE;
+
+ return;
+
+ }
+
+ if (Status != NDIS_STATUS_PENDING) {
+ NdisMSetInformationComplete(
+ (NDIS_HANDLE)Miniport,
+ Status
+ );
+ }
+
+ }
+
+ if (Miniport->NeedToUpdatePacketFilter) {
+
+ UINT PacketFilter;
+
+ DoneSomething = TRUE;
+ //
+ // This is an internal update that is needed.
+ //
+
+ Miniport->MiniportRequest = &(Miniport->InternalRequest);
+ Miniport->NeedToUpdatePacketFilter = FALSE;
+
+ //
+ // Get information needed
+ //
+ switch (Miniport->MediaType) {
+
+ case NdisMedium802_3:
+
+ PacketFilter = ETH_QUERY_FILTER_CLASSES(Miniport->EthDB);
+ break;
+
+ case NdisMedium802_5:
+
+ PacketFilter = TR_QUERY_FILTER_CLASSES(Miniport->TrDB);
+ break;
+
+ case NdisMediumFddi:
+
+ PacketFilter = FDDI_QUERY_FILTER_CLASSES(Miniport->FddiDB);
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ PacketFilter = ARC_QUERY_FILTER_CLASSES(Miniport->ArcDB);
+ PacketFilter |= ETH_QUERY_FILTER_CLASSES(Miniport->EthDB);
+
+ if ( Miniport->ArcnetBroadcastSet ||
+ (PacketFilter & NDIS_PACKET_TYPE_MULTICAST) ) {
+
+ PacketFilter &= ~NDIS_PACKET_TYPE_MULTICAST;
+ PacketFilter |= NDIS_PACKET_TYPE_BROADCAST;
+ }
+ break;
+ }
+
+ NdisMoveMemory(
+ Miniport->MulticastBuffer,
+ &PacketFilter,
+ sizeof(PacketFilter)
+ );
+
+ LOUD_DEBUG(DbgPrint("NdisM: Updating packet filter\n");)
+
+ //
+ // Submit Request
+ //
+ Miniport->InternalRequest.RequestType = NdisRequestSetInformation;
+
+ Status =
+ (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ Miniport->MulticastBuffer,
+ sizeof(PacketFilter),
+ &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesRead,
+ &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesNeeded
+ );
+
+ if ((Status == NDIS_STATUS_PENDING) && (Miniport->MiniportRequest)) {
+
+ //
+ // Still outstanding
+ //
+ LOUD_DEBUG(DbgPrint("NdisM: Exit do requests\n");)
+
+ Miniport->RunDoRequests = FALSE;
+
+ return;
+
+ }
+
+ if (Status != NDIS_STATUS_PENDING) {
+ NdisMSetInformationComplete(
+ (NDIS_HANDLE)Miniport,
+ Status
+ );
+ }
+
+ }
+
+ if (Miniport->NeedToUpdateFunctionalAddress) {
+ UINT FunctionalAddress;
+
+ DoneSomething = TRUE;
+ //
+ // This is an internal update that is needed.
+ //
+
+ Miniport->MiniportRequest = &(Miniport->InternalRequest);
+ Miniport->NeedToUpdateFunctionalAddress = FALSE;
+
+ //
+ // Get information needed
+ //
+ FunctionalAddress = TR_QUERY_FILTER_ADDRESSES(Miniport->TrDB);
+ FunctionalAddress = BYTE_SWAP_ULONG(FunctionalAddress);
+ NdisMoveMemory(Miniport->MulticastBuffer,
+ &FunctionalAddress,
+ sizeof(FunctionalAddress)
+ );
+
+ //
+ // Submit Request
+ //
+ LOUD_DEBUG(DbgPrint("NdisM: Updating functional address\n");)
+
+ Miniport->InternalRequest.RequestType = NdisRequestSetInformation;
+
+ Status =
+ (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ OID_802_5_CURRENT_FUNCTIONAL,
+ Miniport->MulticastBuffer,
+ sizeof(FunctionalAddress),
+ &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesRead,
+ &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesNeeded
+ );
+
+ if ((Status == NDIS_STATUS_PENDING) && (Miniport->MiniportRequest)) {
+
+ //
+ // Still outstanding
+ //
+ LOUD_DEBUG(DbgPrint("NdisM: Exit do requests\n");)
+
+ Miniport->RunDoRequests = FALSE;
+
+ return;
+
+ }
+
+ if (Status != NDIS_STATUS_PENDING) {
+ NdisMSetInformationComplete(
+ (NDIS_HANDLE)Miniport,
+ Status
+ );
+ }
+
+ }
+
+ if (Miniport->NeedToUpdateGroupAddress) {
+ UINT GroupAddress;
+
+ DoneSomething = TRUE;
+ //
+ // This is an internal update that is needed.
+ //
+
+ Miniport->MiniportRequest = &(Miniport->InternalRequest);
+ Miniport->NeedToUpdateGroupAddress = FALSE;
+
+ //
+ // Get information needed
+ //
+ GroupAddress = TR_QUERY_FILTER_GROUP(Miniport->TrDB);
+ GroupAddress = BYTE_SWAP_ULONG(GroupAddress);
+ NdisMoveMemory(Miniport->MulticastBuffer,
+ &GroupAddress,
+ sizeof(GroupAddress)
+ );
+
+ //
+ // Submit Request
+ //
+ LOUD_DEBUG(DbgPrint("NdisM: Updating group address\n");)
+
+ Miniport->InternalRequest.RequestType = NdisRequestSetInformation;
+
+ Status =
+ (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ OID_802_5_CURRENT_GROUP,
+ Miniport->MulticastBuffer,
+ sizeof(GroupAddress),
+ &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesRead,
+ &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesNeeded
+ );
+
+ if ((Status == NDIS_STATUS_PENDING) && (Miniport->MiniportRequest)) {
+
+ //
+ // Still outstanding
+ //
+ LOUD_DEBUG(DbgPrint("NdisM: Exit do requests\n");)
+
+ Miniport->RunDoRequests = FALSE;
+
+ return;
+
+ }
+
+ if (Status != NDIS_STATUS_PENDING) {
+ NdisMSetInformationComplete(
+ (NDIS_HANDLE)Miniport,
+ Status
+ );
+ }
+
+ }
+
+ if (Miniport->NeedToUpdateFddiLongAddresses) {
+ UINT NumberOfAddresses;
+
+ DoneSomething = TRUE;
+ //
+ // This is an internal update that is needed.
+ //
+
+ Miniport->MiniportRequest = &(Miniport->InternalRequest);
+ Miniport->NeedToUpdateFddiLongAddresses = FALSE;
+
+ //
+ // Get information needed
+ //
+
+ FddiQueryGlobalFilterLongAddresses(
+ &Status,
+ Miniport->FddiDB,
+ NDIS_M_MAX_MULTI_LIST * FDDI_LENGTH_OF_LONG_ADDRESS,
+ &NumberOfAddresses,
+ (PVOID)Miniport->MulticastBuffer
+ );
+
+ //
+ // Submit Request
+ //
+ LOUD_DEBUG(DbgPrint("NdisM: Updating fddi long addresses\n");)
+
+ Miniport->InternalRequest.RequestType = NdisRequestSetInformation;
+
+ Status =
+ (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ OID_FDDI_LONG_MULTICAST_LIST,
+ Miniport->MulticastBuffer,
+ NumberOfAddresses * FDDI_LENGTH_OF_LONG_ADDRESS,
+ &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesRead,
+ &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesNeeded
+ );
+
+ if ((Status == NDIS_STATUS_PENDING) && (Miniport->MiniportRequest)) {
+
+ //
+ // Still outstanding
+ //
+ LOUD_DEBUG(DbgPrint("NdisM: Exit do requests\n");)
+
+ Miniport->RunDoRequests = FALSE;
+
+ return;
+
+ }
+
+ if (Status != NDIS_STATUS_PENDING) {
+ NdisMSetInformationComplete(
+ (NDIS_HANDLE)Miniport,
+ Status
+ );
+ }
+
+ }
+
+ if (Miniport->NeedToUpdateFddiShortAddresses) {
+ UINT NumberOfAddresses;
+
+ DoneSomething = TRUE;
+ //
+ // This is an internal update that is needed.
+ //
+
+ Miniport->MiniportRequest = &(Miniport->InternalRequest);
+ Miniport->NeedToUpdateFddiShortAddresses = FALSE;
+
+ //
+ // Get information needed
+ //
+
+ FddiQueryGlobalFilterShortAddresses(
+ &Status,
+ Miniport->FddiDB,
+ NDIS_M_MAX_MULTI_LIST * FDDI_LENGTH_OF_SHORT_ADDRESS,
+ &NumberOfAddresses,
+ (PVOID)Miniport->MulticastBuffer
+ );
+
+ //
+ // Submit Request
+ //
+ LOUD_DEBUG(DbgPrint("NdisM: Updating fddi short addresses\n");)
+
+ Miniport->InternalRequest.RequestType = NdisRequestSetInformation;
+
+ Status =
+ (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ OID_FDDI_SHORT_MULTICAST_LIST,
+ Miniport->MulticastBuffer,
+ NumberOfAddresses * FDDI_LENGTH_OF_SHORT_ADDRESS,
+ &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesRead,
+ &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesNeeded
+ );
+
+ if ((Status == NDIS_STATUS_PENDING) && (Miniport->MiniportRequest)) {
+
+ //
+ // Still outstanding
+ //
+ LOUD_DEBUG(DbgPrint("NdisM: Exit do requests\n");)
+
+ Miniport->RunDoRequests = FALSE;
+
+ return;
+
+ }
+
+ if (Status != NDIS_STATUS_PENDING) {
+ NdisMSetInformationComplete(
+ (NDIS_HANDLE)Miniport,
+ Status
+ );
+ }
+
+ }
+
+ if ( Miniport->FirstPendingRequest != NULL ) {
+
+ PNDIS_REQUEST_RESERVED Reserved;
+ PNDIS_REQUEST NdisRequest;
+ UINT MulticastAddresses;
+ ULONG PacketFilter;
+ BOOLEAN DoMove;
+ PVOID MoveSource;
+ UINT MoveBytes;
+ UINT Lookahead;
+ ULONG GenericULong;
+ UCHAR Address[ETH_LENGTH_OF_ADDRESS];
+
+ //
+ // Set defaults.
+ //
+ DoMove = TRUE;
+ DoneSomething = TRUE;
+ Status = NDIS_STATUS_SUCCESS;
+
+ //
+ // Remove first request
+ //
+ NdisRequest = Miniport->FirstPendingRequest;
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(NdisRequest);
+ Miniport->FirstPendingRequest = Reserved->Next;
+
+ //
+ // Reset the pending request timeout.
+ //
+ Miniport->PendingRequestTimeout = FALSE;
+
+ LOUD_DEBUG(DbgPrint("NdisM: Starting protocol request 0x%x\n", NdisRequest);)
+
+ //
+ // Put it on mini-port queue
+ //
+ Miniport->MiniportRequest = NdisRequest;
+
+ //
+ // Submit to mini-port
+ //
+ switch (NdisRequest->RequestType)
+ {
+ case NdisRequestQueryInformation:
+
+ MoveSource = &GenericULong;
+ MoveBytes = sizeof(GenericULong);
+
+ //
+ // We intercept some calls
+ //
+ switch (NdisRequest->DATA.QUERY_INFORMATION.Oid)
+ {
+ case OID_GEN_SUPPORTED_LIST:
+ {
+ PNDIS_OID pOidList;
+ PNDIS_REQUEST pFakeRequest;
+ PNDIS_REQUEST_RESERVED pFakeReserved;
+ PNDIS_M_OPEN_BLOCK Open;
+ ULONG cbDestination;
+ BOOLEAN fAllocFailed;
+
+ do
+ {
+ //
+ // Allocate our own request structure.
+ // We can't use the internal request structure
+ // since we don't have any way differentiate between
+ // internal requests that are blocking on an event
+ // and those that are not.
+ //
+ pFakeRequest = ExAllocatePool(
+ NonPagedPool,
+ sizeof(NDIS_REQUEST)
+ );
+ if (NULL == pFakeRequest)
+ {
+ fAllocFailed = TRUE;
+ break;
+ }
+
+ //
+ // Allocate a buffer to hold all possible OIDs.
+ // Currently there are about 196 possible OIDs for the
+ // FDDI case. In order to be sure that i get the whole
+ // OID list i allocate a buffer that can hold 250.
+ //
+ pOidList = ExAllocatePool(
+ NonPagedPool,
+ 250 * sizeof(NDIS_OID)
+ );
+ if (NULL == pOidList)
+ {
+ fAllocFailed = TRUE;
+ break;
+ }
+
+ //
+ // We succeeded with the allocations.
+ //
+ DoMove = FALSE;
+ fAllocFailed = FALSE;
+ NdisZeroMemory(pFakeRequest, sizeof(NDIS_REQUEST));
+ NdisZeroMemory(pOidList, 250 * sizeof(NDIS_OID));
+
+ //
+ // Save our fake request with the miniport.
+ //
+ Miniport->MiniportRequest = pFakeRequest;
+
+ //
+ // Save relevant information in the internal request structure
+ // in case this pends.
+ //
+ pFakeRequest->RequestType = NdisRequestQueryInformation;
+ pFakeRequest->DATA.QUERY_INFORMATION.Oid = OID_GEN_SUPPORTED_LIST;
+ pFakeRequest->DATA.QUERY_INFORMATION.InformationBuffer = pOidList;
+ pFakeRequest->DATA.QUERY_INFORMATION.InformationBufferLength = 250 * sizeof(NDIS_OID);
+
+ //
+ // Since we are faking the request we need to save the
+ // pointer to the original request that was passed by
+ // the caller.
+ //
+ pFakeReserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(pFakeRequest);
+ pFakeReserved->Next = NdisRequest;
+
+ //
+ // Fire off the request to the miniport.
+ // We let NdisMQueryInformationComplete() handle
+ // all situations of the return value.
+ //
+ Status = (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ OID_GEN_SUPPORTED_LIST,
+ pOidList,
+ 250 * sizeof(NDIS_OID),
+ &pFakeRequest->DATA.QUERY_INFORMATION.BytesWritten,
+ &pFakeRequest->DATA.QUERY_INFORMATION.BytesNeeded
+ );
+ } while (FALSE);
+
+ //
+ // Did our allocations fail?
+ //
+ if (fAllocFailed)
+ {
+ //
+ // This is the only resource that could have
+ // been allocated above.
+ //
+ if (NULL != pFakeRequest)
+ ExFreePool(pFakeRequest);
+
+ //
+ // We have to notify the protocol and return
+ // from here. NdisMQueryInformationComplete()
+ // cannot handle the case where memory allocations
+ // failed.
+ //
+ Miniport->Timeout = FALSE;
+ Miniport->MiniportRequest = NULL;
+ Open = Reserved->Open;
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.RequestCompleteHandler)(
+ Open->ProtocolBindingContext,
+ NdisRequest,
+ NDIS_STATUS_RESOURCES
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ Open->References--;
+
+ if (Open->References == 0)
+ {
+ FinishClose(Miniport, Open);
+ }
+
+ Miniport->RunDoRequests = FALSE;
+
+ if (Miniport->NeedToUpdateEthAddresses ||
+ Miniport->NeedToUpdatePacketFilter ||
+ Miniport->NeedToUpdateFunctionalAddress ||
+ Miniport->NeedToUpdateGroupAddress ||
+ Miniport->NeedToUpdateFddiLongAddresses ||
+ Miniport->NeedToUpdateFddiShortAddresses ||
+ (Miniport->FirstPendingRequest != NULL)
+ )
+ {
+ Miniport->RunDoRequests = TRUE;
+ Miniport->ProcessOddDeferredStuff = TRUE;
+ }
+
+ return;
+ }
+ }
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ switch (Miniport->MediaType) {
+ case NdisMedium802_3:
+ PacketFilter = ETH_QUERY_PACKET_FILTER(
+ Miniport->EthDB,
+ Reserved->Open->FilterHandle
+ );
+ break;
+ case NdisMedium802_5:
+ PacketFilter = TR_QUERY_PACKET_FILTER(
+ Miniport->TrDB,
+ Reserved->Open->FilterHandle
+ );
+ break;
+ case NdisMediumFddi:
+ PacketFilter = FDDI_QUERY_PACKET_FILTER(
+ Miniport->FddiDB,
+ Reserved->Open->FilterHandle
+ );
+ break;
+ case NdisMediumArcnet878_2:
+
+ if (Reserved->Open->UsingEthEncapsulation) {
+
+ PacketFilter = ETH_QUERY_PACKET_FILTER(
+ Miniport->EthDB,
+ Reserved->Open->FilterHandle
+ );
+ } else {
+
+ PacketFilter = ARC_QUERY_PACKET_FILTER(
+ Miniport->ArcDB,
+ Reserved->Open->FilterHandle
+ );
+ }
+ break;
+ }
+ GenericULong = (ULONG)(PacketFilter);
+ break;
+
+ case OID_GEN_MEDIA_IN_USE:
+ case OID_GEN_MEDIA_SUPPORTED:
+
+ if (Miniport->MediaType == NdisMediumArcnet878_2) {
+
+ if (Reserved->Open->UsingEthEncapsulation) {
+
+ GenericULong = (ULONG)(NdisMedium802_3);
+
+ } else {
+
+ GenericULong = (ULONG)(NdisMediumArcnet878_2);
+
+ }
+
+ } else {
+
+ GenericULong = (ULONG)(Miniport->MediaType);
+
+ }
+ MoveBytes = sizeof(NDIS_MEDIUM);
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ GenericULong = (ULONG)(Reserved->Open->CurrentLookahead);
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+ GenericULong = (ULONG)(Miniport->MaximumLookahead);
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+
+ if ( (NdisRequest->DATA.SET_INFORMATION.InformationBufferLength %
+ ETH_LENGTH_OF_ADDRESS) == 0) {
+
+ EthQueryOpenFilterAddresses(
+ &Status,
+ Miniport->EthDB,
+ Reserved->Open->FilterHandle,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &MulticastAddresses,
+ (PVOID)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer)
+ );
+
+ MoveSource = (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
+ MoveBytes = MulticastAddresses * ETH_LENGTH_OF_ADDRESS;
+ } else {
+ //
+ // The data must be a multiple of the Ethernet address size.
+ //
+
+ Status = NDIS_STATUS_INVALID_DATA;
+ }
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+ GenericULong = Miniport->MaximumLongAddresses;
+ break;
+
+ case OID_802_5_CURRENT_FUNCTIONAL:
+ GenericULong = TR_QUERY_FILTER_BINDING_ADDRESS(
+ Miniport->TrDB,
+ Reserved->Open->FilterHandle
+ );
+ GenericULong = BYTE_SWAP_ULONG(GenericULong);
+ break;
+
+ case OID_802_5_CURRENT_GROUP:
+ GenericULong = TR_QUERY_FILTER_GROUP(
+ Miniport->TrDB
+ );
+ GenericULong = BYTE_SWAP_ULONG(GenericULong);
+ break;
+
+ case OID_FDDI_LONG_MULTICAST_LIST:
+ FddiQueryOpenFilterLongAddresses(
+ &Status,
+ Miniport->FddiDB,
+ Reserved->Open->FilterHandle,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &MulticastAddresses,
+ (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer
+ );
+
+ MoveSource = (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
+ MoveBytes = FDDI_LENGTH_OF_LONG_ADDRESS *
+ FddiNumberOfOpenFilterLongAddresses(
+ Miniport->FddiDB,
+ Reserved->Open->FilterHandle);
+ break;
+
+ case OID_FDDI_LONG_MAX_LIST_SIZE:
+ GenericULong = Miniport->MaximumLongAddresses;
+ break;
+
+ case OID_FDDI_SHORT_MULTICAST_LIST:
+ FddiQueryOpenFilterShortAddresses(
+ &Status,
+ Miniport->FddiDB,
+ Reserved->Open->FilterHandle,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &MulticastAddresses,
+ (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer
+ );
+
+ MoveSource = (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
+ MoveBytes = FDDI_LENGTH_OF_SHORT_ADDRESS *
+ FddiNumberOfOpenFilterShortAddresses(
+ Miniport->FddiDB,
+ Reserved->Open->FilterHandle);
+ break;
+
+ case OID_FDDI_SHORT_MAX_LIST_SIZE:
+ GenericULong = Miniport->MaximumShortAddresses;
+ break;
+
+ //
+ //
+ // Start interceptions for running an ethernet
+ // protocol on top of an arcnet mini-port.
+ //
+ //
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+
+ if (Miniport->MediaType == NdisMediumArcnet878_2) {
+
+ if (Reserved->Open->UsingEthEncapsulation) {
+
+ //
+ // 504 - 14 (ethernet header) == 490.
+ //
+
+ GenericULong = ARC_MAX_FRAME_SIZE - 14;
+
+ break;
+ }
+ }
+ goto SubmitToMiniportDriver;
+
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+
+ if (Miniport->MediaType == NdisMediumArcnet878_2) {
+
+ if (Reserved->Open->UsingEthEncapsulation) {
+
+ GenericULong = ARC_MAX_FRAME_SIZE;
+
+ break;
+ }
+ }
+ goto SubmitToMiniportDriver;
+
+ case OID_802_3_PERMANENT_ADDRESS:
+ case OID_802_3_CURRENT_ADDRESS:
+
+ if ( Miniport->MediaType == NdisMediumArcnet878_2 ) {
+
+ if (Reserved->Open->UsingEthEncapsulation) {
+
+ //
+ // The following stuff makes the copy code
+ // below copy the source address into the
+ // the users request buffer.
+ //
+
+ MoveSource = Address;
+ MoveBytes = ETH_LENGTH_OF_ADDRESS;
+
+ //
+ // Arcnet-to-ethernet conversion.
+ //
+
+ NdisZeroMemory(
+ Address,
+ ETH_LENGTH_OF_ADDRESS
+ );
+
+ Address[5] = Miniport->ArcnetAddress;
+
+ break;
+ }
+ }
+
+ goto SubmitToMiniportDriver;
+
+ default:
+
+SubmitToMiniportDriver:
+
+ DoMove = FALSE;
+
+ Status =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ NdisRequest->DATA.QUERY_INFORMATION.Oid,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &(NdisRequest->DATA.QUERY_INFORMATION.BytesWritten),
+ &(NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded)
+ );
+
+ break;
+
+ }
+
+ if (DoMove) {
+
+ //
+ // This was an intercepted request. Finish it off
+ //
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ if (MoveBytes >
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength) {
+
+ //
+ // Not enough room in InformationBuffer. Punt
+ //
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = MoveBytes;
+
+ Status = NDIS_STATUS_INVALID_LENGTH;
+
+ } else {
+
+ //
+ // Copy result into InformationBuffer
+ //
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesWritten = MoveBytes;
+
+ if ((MoveBytes > 0) &&
+ (MoveSource != NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer)) {
+
+ NdisMoveMemory(
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
+ MoveSource,
+ MoveBytes
+ );
+ }
+ }
+
+ } else {
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = MoveBytes;
+
+ }
+
+ }
+
+ break;
+
+ case NdisRequestQueryStatistics:
+
+ //
+ // Query GLOBAL statistics
+ //
+ MoveSource = &GenericULong;
+ MoveBytes = sizeof(GenericULong);
+
+ //
+ // We intercept some calls
+ //
+
+ switch (NdisRequest->DATA.QUERY_INFORMATION.Oid) {
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ switch (Miniport->MediaType) {
+ case NdisMedium802_3:
+ PacketFilter = ETH_QUERY_FILTER_CLASSES(Miniport->EthDB);
+ break;
+ case NdisMedium802_5:
+ PacketFilter = TR_QUERY_FILTER_CLASSES(Miniport->TrDB);
+ break;
+ case NdisMediumFddi:
+ PacketFilter = FDDI_QUERY_FILTER_CLASSES(Miniport->FddiDB);
+ break;
+ case NdisMediumArcnet878_2:
+ PacketFilter = ARC_QUERY_FILTER_CLASSES(Miniport->ArcDB);
+ PacketFilter |= ETH_QUERY_FILTER_CLASSES(Miniport->EthDB);
+ break;
+ }
+ GenericULong = (ULONG)(PacketFilter);
+ break;
+
+ case OID_GEN_MEDIA_IN_USE:
+ case OID_GEN_MEDIA_SUPPORTED:
+ MoveSource = (PVOID) (&(Miniport->MediaType));
+ MoveBytes = sizeof(NDIS_MEDIUM);
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ GenericULong = (ULONG)(Miniport->CurrentLookahead);
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+ GenericULong = (ULONG)(Miniport->MaximumLookahead);
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+
+ EthQueryGlobalFilterAddresses(
+ &Status,
+ Miniport->EthDB,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &MulticastAddresses,
+ (PVOID)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer)
+ );
+
+ MoveSource = (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
+ MoveBytes = MulticastAddresses * ETH_LENGTH_OF_ADDRESS;
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+ GenericULong = Miniport->MaximumLongAddresses;
+ break;
+
+ case OID_802_5_CURRENT_FUNCTIONAL:
+ GenericULong = TR_QUERY_FILTER_ADDRESSES(
+ Miniport->TrDB
+ );
+ GenericULong = BYTE_SWAP_ULONG(GenericULong);
+ break;
+
+ case OID_802_5_CURRENT_GROUP:
+ GenericULong = TR_QUERY_FILTER_GROUP(
+ Miniport->TrDB
+ );
+ GenericULong = BYTE_SWAP_ULONG(GenericULong);
+ break;
+
+ case OID_FDDI_LONG_MULTICAST_LIST:
+ FddiQueryGlobalFilterLongAddresses(
+ &Status,
+ Miniport->FddiDB,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &MulticastAddresses,
+ (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+
+ MoveSource = (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
+ MoveBytes = FDDI_LENGTH_OF_LONG_ADDRESS * MulticastAddresses;
+ break;
+
+ case OID_FDDI_LONG_MAX_LIST_SIZE:
+ GenericULong = Miniport->MaximumLongAddresses;
+ break;
+
+ case OID_FDDI_SHORT_MULTICAST_LIST:
+ FddiQueryGlobalFilterShortAddresses(
+ &Status,
+ Miniport->FddiDB,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &MulticastAddresses,
+ (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+
+ MoveSource = (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
+ MoveBytes = FDDI_LENGTH_OF_SHORT_ADDRESS * MulticastAddresses;
+ break;
+
+ case OID_FDDI_SHORT_MAX_LIST_SIZE:
+ GenericULong = Miniport->MaximumShortAddresses;
+ break;
+
+ default:
+
+ DoMove = FALSE;
+
+ Status =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ NdisRequest->DATA.QUERY_INFORMATION.Oid,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &(NdisRequest->DATA.QUERY_INFORMATION.BytesWritten),
+ &(NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded)
+ );
+
+ break;
+
+ }
+
+ if (DoMove) {
+
+ //
+ // This was an intercepted request. Finish it off
+ //
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ if (MoveBytes >
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength) {
+
+ //
+ // Not enough room in InformationBuffer. Punt
+ //
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = MoveBytes;
+
+ Status = NDIS_STATUS_INVALID_LENGTH;
+
+ } else {
+
+ //
+ // Copy result into InformationBuffer
+ //
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesWritten = MoveBytes;
+
+ if ((MoveBytes > 0) &&
+ (MoveSource != NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer)) {
+ NdisMoveMemory(
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
+ MoveSource,
+ MoveBytes
+ );
+ }
+
+ }
+
+ } else {
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = MoveBytes;
+
+ }
+
+ }
+ break;
+
+
+
+
+ case NdisRequestSetInformation:
+
+ //
+ // We intercept some calls
+ //
+
+ switch (NdisRequest->DATA.SET_INFORMATION.Oid) {
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ if (NdisRequest->DATA.SET_INFORMATION.InformationBufferLength
+ != 4) {
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+ break;
+ }
+
+ //
+ // Now call the filter package to set the packet filter.
+ //
+ NdisMoveMemory ((PVOID)&PacketFilter,
+ NdisRequest->DATA.SET_INFORMATION.InformationBuffer,
+ sizeof(ULONG)
+ );
+
+ if (PacketFilter & ~(Miniport->SupportedPacketFilters)) {
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 4;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+ break;
+ }
+
+ switch (Miniport->MediaType) {
+ case NdisMedium802_3:
+ Status = EthFilterAdjust(
+ Miniport->EthDB,
+ Reserved->Open->FilterHandle,
+ (PNDIS_REQUEST)NdisRequest,
+ PacketFilter,
+ TRUE
+ );
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 4;
+ break;
+
+ case NdisMedium802_5:
+ Status = TrFilterAdjust(
+ Miniport->TrDB,
+ Reserved->Open->FilterHandle,
+ (PNDIS_REQUEST)NdisRequest,
+ PacketFilter,
+ TRUE
+ );
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 4;
+ break;
+
+ case NdisMediumFddi:
+ Status = FddiFilterAdjust(
+ Miniport->FddiDB,
+ Reserved->Open->FilterHandle,
+ (PNDIS_REQUEST)NdisRequest,
+ PacketFilter,
+ TRUE
+ );
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 4;
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ if (Reserved->Open->UsingEthEncapsulation) {
+
+ Status = EthFilterAdjust(
+ Miniport->EthDB,
+ Reserved->Open->FilterHandle,
+ (PNDIS_REQUEST)NdisRequest,
+ PacketFilter,
+ TRUE
+ );
+
+ } else {
+
+ Status = ArcFilterAdjust(
+ Miniport->ArcDB,
+ Reserved->Open->FilterHandle,
+ (PNDIS_REQUEST)NdisRequest,
+ PacketFilter,
+ TRUE
+ );
+ }
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 4;
+ break;
+ }
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ //
+ // Verify length
+ //
+ if (NdisRequest->DATA.SET_INFORMATION.InformationBufferLength
+ != 4) {
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+ break;
+ }
+
+ NdisMoveMemory(&Lookahead,
+ NdisRequest->DATA.SET_INFORMATION.InformationBuffer,
+ 4
+ );
+
+ if (Lookahead > Miniport->MaximumLookahead) {
+
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+ break;
+
+ }
+
+ Reserved->Open->CurrentLookahead = Lookahead;
+ Status = MiniportAdjustMaximumLookahead(Miniport);
+
+ //
+ // Since this routine may submit another request, update our
+ // pointer to the currently executing request.
+ //
+ NdisRequest = Miniport->MiniportRequest;
+
+ break;
+
+ case OID_GEN_PROTOCOL_OPTIONS:
+
+ if (NdisRequest->DATA.SET_INFORMATION.InformationBufferLength
+ != 4) {
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+ break;
+ }
+
+ NdisMoveMemory(&(Reserved->Open->ProtocolOptions),
+ NdisRequest->DATA.SET_INFORMATION.InformationBuffer,
+ 4
+ );
+
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+
+ if ( (NdisRequest->DATA.SET_INFORMATION.InformationBufferLength
+ % ETH_LENGTH_OF_ADDRESS) != 0) {
+
+ //
+ // The data must be a multiple of the Ethernet
+ // address size.
+ //
+
+ Status = NDIS_STATUS_INVALID_DATA;
+ break;
+
+ }
+
+ if ((Miniport->MediaType != NdisMedium802_3) &&
+ !((Miniport->MediaType == NdisMediumArcnet878_2) &&
+ (Reserved->Open->UsingEthEncapsulation))) {
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ //
+ // Now call the filter package to set up the addresses.
+ //
+
+ Status = EthChangeFilterAddresses(
+ Miniport->EthDB,
+ Reserved->Open->FilterHandle,
+ (PNDIS_REQUEST)NdisRequest,
+ NdisRequest->DATA.SET_INFORMATION.InformationBufferLength
+ / ETH_LENGTH_OF_ADDRESS,
+ NdisRequest->DATA.SET_INFORMATION.InformationBuffer,
+ TRUE
+ );
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead =
+ NdisRequest->DATA.SET_INFORMATION.InformationBufferLength;
+ break;
+
+ case OID_802_5_CURRENT_FUNCTIONAL:
+ if (Miniport->MediaType != NdisMedium802_5) {
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if (NdisRequest->DATA.SET_INFORMATION.InformationBufferLength
+ != 4) {
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+ break;
+ }
+
+ Status = TrChangeFunctionalAddress(
+ Reserved->Open->MiniportHandle->TrDB,
+ Reserved->Open->FilterHandle,
+ NdisRequest,
+ (PUCHAR)(NdisRequest->DATA.SET_INFORMATION.InformationBuffer),
+ TRUE
+ );
+ break;
+
+ case OID_802_5_CURRENT_GROUP:
+ if (Miniport->MediaType != NdisMedium802_5) {
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if (NdisRequest->DATA.SET_INFORMATION.InformationBufferLength
+ != 4) {
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+ break;
+ }
+
+ Status = TrChangeGroupAddress(
+ Reserved->Open->MiniportHandle->TrDB,
+ Reserved->Open->FilterHandle,
+ NdisRequest,
+ (PUCHAR)(NdisRequest->DATA.SET_INFORMATION.InformationBuffer),
+ TRUE
+ );
+ break;
+
+ case OID_FDDI_LONG_MULTICAST_LIST:
+ if (Miniport->MediaType != NdisMediumFddi) {
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if (NdisRequest->DATA.SET_INFORMATION.InformationBufferLength
+ % FDDI_LENGTH_OF_LONG_ADDRESS != 0) {
+
+ //
+ // The data must be a multiple of the Ethernet
+ // address size.
+ //
+
+ Status = NDIS_STATUS_INVALID_DATA;
+ break;
+
+ }
+
+ //
+ // Now call the filter package to set up the addresses.
+ //
+ Status = FddiChangeFilterLongAddresses(
+ Miniport->FddiDB,
+ Reserved->Open->FilterHandle,
+ (PNDIS_REQUEST)NdisRequest,
+ NdisRequest->DATA.SET_INFORMATION.InformationBufferLength
+ / FDDI_LENGTH_OF_LONG_ADDRESS,
+ NdisRequest->DATA.SET_INFORMATION.InformationBuffer,
+ TRUE
+ );
+ NdisRequest->DATA.SET_INFORMATION.BytesRead =
+ NdisRequest->DATA.SET_INFORMATION.InformationBufferLength;
+ break;
+
+ case OID_FDDI_SHORT_MULTICAST_LIST:
+ if (Miniport->MediaType != NdisMediumFddi) {
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if (NdisRequest->DATA.SET_INFORMATION.InformationBufferLength
+ % FDDI_LENGTH_OF_SHORT_ADDRESS != 0) {
+
+ //
+ // The data must be a multiple of the Ethernet
+ // address size.
+ //
+
+ Status = NDIS_STATUS_INVALID_DATA;
+ break;
+
+ }
+
+ //
+ // Now call the filter package to set up the addresses.
+ //
+ Status = FddiChangeFilterShortAddresses(
+ Miniport->FddiDB,
+ Reserved->Open->FilterHandle,
+ (PNDIS_REQUEST)NdisRequest,
+ NdisRequest->DATA.SET_INFORMATION.InformationBufferLength
+ / FDDI_LENGTH_OF_SHORT_ADDRESS,
+ NdisRequest->DATA.SET_INFORMATION.InformationBuffer,
+ TRUE
+ );
+ NdisRequest->DATA.SET_INFORMATION.BytesRead =
+ NdisRequest->DATA.SET_INFORMATION.InformationBufferLength;
+ break;
+
+ default:
+
+ Status =
+ (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ NdisRequest->DATA.SET_INFORMATION.Oid,
+ NdisRequest->DATA.SET_INFORMATION.InformationBuffer,
+ NdisRequest->DATA.SET_INFORMATION.InformationBufferLength,
+ &(NdisRequest->DATA.SET_INFORMATION.BytesRead),
+ &(NdisRequest->DATA.SET_INFORMATION.BytesNeeded)
+ );
+
+ break;
+
+ }
+ break;
+
+ }
+
+ if ((Status == NDIS_STATUS_PENDING) && (Miniport->MiniportRequest)) {
+
+ //
+ // Still outstanding
+ //
+ LOUD_DEBUG(DbgPrint("NdisM: Exit do requests\n");)
+
+ Miniport->RunDoRequests = FALSE;
+
+ return;
+
+ }
+
+ //
+ // Complete request
+ //
+
+ if (Status != NDIS_STATUS_PENDING) {
+
+ switch (NdisRequest->RequestType) {
+
+ case NdisRequestQueryStatistics:
+ case NdisRequestQueryInformation:
+
+ NdisMQueryInformationComplete(
+ (NDIS_HANDLE)Miniport,
+ Status
+ );
+ break;
+
+ case NdisRequestSetInformation:
+
+ NdisMSetInformationComplete(
+ (NDIS_HANDLE)Miniport,
+ Status
+ );
+ break;
+ }
+ }
+ }
+ }
+
+ if ((Miniport->NeedToUpdateEthAddresses ||
+ Miniport->NeedToUpdatePacketFilter ||
+ Miniport->NeedToUpdateFunctionalAddress ||
+ Miniport->NeedToUpdateGroupAddress ||
+ Miniport->NeedToUpdateFddiLongAddresses ||
+ Miniport->NeedToUpdateFddiShortAddresses ||
+ (Miniport->FirstPendingRequest != NULL))
+ &&
+ (Miniport->MiniportRequest == NULL))
+ {
+ Miniport->RunDoRequests = TRUE;
+ Miniport->ProcessOddDeferredStuff = TRUE;
+ }
+ else
+ {
+ Miniport->RunDoRequests = FALSE;
+ }
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit do requests\n");)
+ return;
+
+}
+
+
+
+BOOLEAN
+FASTCALL
+MiniportSendLoopback(
+ PNDIS_MINIPORT_BLOCK Miniport,
+ PNDIS_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ Checks if a packet needs to be loopbacked and does so if necessary.
+
+ NOTE: Must be called at DPC_LEVEL with lock HELD!
+
+Arguments:
+
+ Miniport - Miniport to send to.
+
+ Packet - Packet to loopback.
+
+Return Value:
+
+ FALSE if the packet should be sent on the net, TRUE if it is
+ a self-directed packet.
+
+--*/
+
+{
+
+ BOOLEAN Loopback;
+ BOOLEAN SelfDirected;
+ INT FddiAddressCheck;
+ PNDIS_BUFFER FirstBuffer;
+ UINT BufferLength;
+ PUCHAR BufferAddress;
+ UINT Length;
+ UINT AddressLength;
+
+ // We should not be here if the driver handles loopback
+ ASSERT(Miniport->MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK);
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ FirstBuffer = Packet->Private.Head;
+ BufferAddress = MmGetSystemAddressForMdl(FirstBuffer);
+
+ switch (Miniport->MediaType) {
+
+ case NdisMedium802_3:
+
+ //
+ // If the card does not do loopback, then we check if
+ // we need to send it to ourselves, then if that is the
+ // case we also check for it being self-directed.
+ //
+
+ EthShouldAddressLoopBackMacro(Miniport->EthDB, BufferAddress, &Loopback, &SelfDirected);
+
+ if (!Loopback) {
+ ASSERT(!SelfDirected);
+ return FALSE;
+ }
+ break;
+
+ case NdisMedium802_5:
+
+ Loopback = TrShouldAddressLoopBack(
+ Miniport->TrDB,
+ BufferAddress + 2, // Skip FC & AC bytes.
+ BufferAddress + 8 // Destination address.
+ );
+
+ if (!Loopback) {
+ return FALSE;
+ }
+
+ //
+ // See if it is self-directed.
+ //
+
+ if ((*(ULONG UNALIGNED *)&BufferAddress[4] ==
+ *(ULONG UNALIGNED *)&Miniport->TrDB->AdapterAddress[2]) &&
+ (*(USHORT UNALIGNED *)&BufferAddress[2] ==
+ *(USHORT UNALIGNED *)&Miniport->TrDB->AdapterAddress[0])) {
+
+ SelfDirected = TRUE;
+ Loopback = TRUE;
+
+ } else {
+
+ SelfDirected = FALSE;
+ }
+
+ break;
+
+ case NdisMediumFddi:
+
+ AddressLength = (BufferAddress[0] & 0x40)? FDDI_LENGTH_OF_LONG_ADDRESS:
+ FDDI_LENGTH_OF_SHORT_ADDRESS;
+
+ FddiShouldAddressLoopBackMacro(Miniport->FddiDB,
+ BufferAddress + 1, // Skip FC byte to dest address.
+ AddressLength,
+ &Loopback,
+ &SelfDirected);
+
+ if (!Loopback) {
+ return FALSE;
+ }
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ if ( ARC_PACKET_IS_ENCAPSULATED(Packet) ) {
+
+ //
+ // The second buffer in the packet is the ethernet
+ // header so we need to get that one before we can
+ // proceed.
+ //
+
+ NdisGetNextBuffer(FirstBuffer, &FirstBuffer);
+
+ BufferAddress = MmGetSystemAddressForMdl(FirstBuffer);
+
+ // Length -= 3; Length is not valid at this point. Do this later when
+ // we determine that we need to loopback for certain
+
+ //
+ // Now we can continue as though this were ethernet.
+ //
+
+ EthShouldAddressLoopBackMacro(
+ Miniport->EthDB,
+ BufferAddress,
+ &Loopback,
+ &SelfDirected);
+
+ if (!Loopback) {
+ return FALSE;
+ }
+ } else {
+
+ Loopback = ((BufferAddress[0] == BufferAddress[1]) ||
+ ((BufferAddress[1] == 0x00) &&
+ (ARC_QUERY_FILTER_CLASSES(Miniport->ArcDB) |
+ NDIS_PACKET_TYPE_BROADCAST)));
+
+ if (BufferAddress[0] == BufferAddress[1]) {
+ SelfDirected = TRUE;
+ Loopback = TRUE;
+ } else {
+ SelfDirected = FALSE;
+ }
+ }
+
+ break;
+ }
+
+ if (Loopback) {
+
+ //
+ // Get the buffer length
+ //
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ NULL,
+ NULL,
+ &Length
+ );
+
+ if ((Miniport->MediaType == NdisMediumArcnet878_2) &&
+ ARC_PACKET_IS_ENCAPSULATED(Packet))
+ {
+ Length -= 3;
+ }
+
+ //
+ // See if we need to copy the data from the packet
+ // into the loopback buffer.
+ //
+ // We need to copy to the local loopback buffer if
+ // the first buffer of the packet is less than the
+ // minimum loopback size AND the first buffer isn't
+ // the total packet.
+ //
+
+ BufferLength = MmGetMdlByteCount(FirstBuffer);
+
+ if ((BufferLength < NDIS_M_MAX_LOOKAHEAD) && (BufferLength != Length)) {
+
+ UINT BytesToCopy;
+ UINT Offset = 0;
+
+ switch( Miniport->MediaType ) {
+
+ case NdisMedium802_3:
+ case NdisMedium802_5:
+
+ BytesToCopy = 14;
+ break;
+
+ case NdisMediumFddi:
+
+ BytesToCopy = 1 + (2 * AddressLength);
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ if ( ARC_PACKET_IS_ENCAPSULATED(Packet) ) {
+
+ BytesToCopy = 14; // Copy encapsulated ethernet header.
+ Offset = 3; // Skip fake arcnet header.
+
+ } else {
+
+ BytesToCopy = 3; // Copy arcnet header.
+ }
+ break;
+ }
+
+ BytesToCopy += Miniport->CurrentLookahead;
+
+ BufferAddress = Miniport->LookaheadBuffer;
+
+ MiniportCopyFromPacketToBuffer(
+ Packet, // Packet to copy from.
+ Offset, // Offset from beginning of packet.
+ BytesToCopy, // Number of bytes to copy.
+ BufferAddress, // The destination buffer.
+ &BufferLength // The number of bytes copied.
+ );
+ }
+
+ Miniport->LoopbackPacket = Packet;
+
+ NDIS_LOG_PACKET(Miniport, Packet, 'L');
+
+ if (BufferLength >= 14) {
+
+ //
+ // Not a runt packet
+ //
+ //
+ // Indicate the packet to every open binding
+ // that could want it.
+ //
+
+ switch (Miniport->MediaType) {
+
+ case NdisMedium802_3:
+
+ //
+ // NOTE: Code re-use for 878.2 (arcnet) encapsulated
+ // ethernet packets.
+ //
+
+EthIndicateLoopbackFullPacket:
+
+ Miniport->LoopbackPacketHeaderSize = 14;
+
+ EthFilterDprIndicateReceive(
+ Miniport->EthDB,
+ Packet,
+ ((PCHAR)BufferAddress),
+ BufferAddress,
+ 14,
+ ((PUCHAR)BufferAddress) + 14,
+ BufferLength - 14,
+ Length - 14
+ );
+
+ EthFilterDprIndicateReceiveComplete(
+ Miniport->EthDB
+ );
+
+ break;
+
+ case NdisMedium802_5:
+
+ Miniport->LoopbackPacketHeaderSize = 14;
+
+ TrFilterDprIndicateReceive(
+ Miniport->TrDB,
+ Packet,
+ BufferAddress,
+ 14,
+ ((PUCHAR)BufferAddress) + 14,
+ BufferLength - 14,
+ Length - 14
+ );
+
+ TrFilterDprIndicateReceiveComplete(
+ Miniport->TrDB
+ );
+
+ break;
+
+ case NdisMediumFddi:
+
+ Miniport->LoopbackPacketHeaderSize = 1+(2*AddressLength);
+
+ FddiFilterDprIndicateReceive(
+ Miniport->FddiDB,
+ Packet,
+ ((PCHAR)BufferAddress) + 1,
+ AddressLength,
+ BufferAddress,
+ Miniport->LoopbackPacketHeaderSize,
+ ((PUCHAR)BufferAddress) + Miniport->LoopbackPacketHeaderSize,
+ BufferLength - Miniport->LoopbackPacketHeaderSize,
+ Length - Miniport->LoopbackPacketHeaderSize
+ );
+
+ FddiFilterDprIndicateReceiveComplete(
+ Miniport->FddiDB
+ );
+
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ if ( ARC_PACKET_IS_ENCAPSULATED(Packet) ) {
+
+ goto EthIndicateLoopbackFullPacket;
+
+ } else {
+
+ PUCHAR PlaceInBuffer;
+ PUCHAR ArcDataBuffer;
+ UINT ArcDataLength;
+ UINT PacketDataOffset;
+ UCHAR FrameCount;
+ UCHAR i;
+ UINT IndicateDataLength;
+ //
+ // Calculate how many frames we will need.
+ //
+
+ ArcDataLength = Length - 3;
+ PacketDataOffset = 3;
+
+ FrameCount = (UCHAR) (ArcDataLength / ARC_MAX_FRAME_SIZE);
+
+ if ( (ArcDataLength % ARC_MAX_FRAME_SIZE) != 0) {
+
+ FrameCount++;
+ }
+
+ for (i = 0; i < FrameCount; ++i) {
+
+ PlaceInBuffer = Miniport->LookaheadBuffer;
+
+ //
+ // Point data buffer to start of 'data'
+ //
+
+ ArcDataBuffer = Miniport->LookaheadBuffer + 2;
+
+ //
+ // Copy Header (SrcId/DestId/ProtId)
+ //
+
+ MiniportCopyFromPacketToBuffer(
+ Packet,
+ 0,
+ 3,
+ PlaceInBuffer,
+ &BufferLength
+ );
+
+ PlaceInBuffer += 3;
+
+ //
+ // Put in split flag
+ //
+
+ if ( FrameCount > 1 ) {
+
+ //
+ // Multi-frame indication...
+ //
+
+ if ( i == 0 ) {
+
+ //
+ // first frame
+ //
+
+ // *PlaceInBuffer = ( (FrameCount - 2) * 2 ) + 1;
+
+ *PlaceInBuffer = 2 * FrameCount - 3;
+ } else {
+
+ //
+ // Subsequent frame
+ //
+ *PlaceInBuffer = ( i * 2 );
+ }
+
+ } else {
+
+ //
+ // Only frame in the indication
+ //
+
+ *PlaceInBuffer = 0;
+ }
+
+ //
+ // Skip split flag
+ //
+
+ PlaceInBuffer++;
+
+ //
+ // Put in packet number.
+ //
+
+ *PlaceInBuffer++ = 0;
+ *PlaceInBuffer++ = 0;
+
+ //
+ // Copy data
+ //
+
+ if ( ArcDataLength > ARC_MAX_FRAME_SIZE ) {
+
+ IndicateDataLength = ARC_MAX_FRAME_SIZE;
+ } else {
+
+ IndicateDataLength = ArcDataLength;
+ }
+
+ MiniportCopyFromPacketToBuffer(
+ Packet,
+ PacketDataOffset,
+ IndicateDataLength,
+ PlaceInBuffer,
+ &BufferLength
+ );
+
+ ArcFilterDprIndicateReceive(
+ Miniport->ArcDB,
+ Miniport->LookaheadBuffer,
+ ArcDataBuffer,
+ IndicateDataLength + 4
+ );
+
+ ArcDataLength -= ARC_MAX_FRAME_SIZE;
+ PacketDataOffset += ARC_MAX_FRAME_SIZE;
+ }
+ }
+
+ ArcFilterDprIndicateReceiveComplete(
+ Miniport->ArcDB
+ );
+
+ break;
+
+ }
+
+ } else {
+
+ //
+ // A runt packet
+ //
+ //
+ // Indicate the packet to every open binding
+ // that could want it.
+ //
+
+ Miniport->LoopbackPacketHeaderSize = BufferLength;
+
+ switch (Miniport->MediaType) {
+ case NdisMedium802_3:
+
+ //
+ // NOTE: Code re-use for 878.2 (arcnet) encapsulated
+ // ethernet packets.
+ //
+
+EthIndicateLoopbackRuntPacket:
+
+ EthFilterDprIndicateReceive(
+ Miniport->EthDB,
+ Packet,
+ ((PCHAR)BufferAddress),
+ BufferAddress,
+ BufferLength,
+ NULL,
+ 0,
+ 0
+ );
+
+ EthFilterDprIndicateReceiveComplete(
+ Miniport->EthDB
+ );
+
+ break;
+
+ case NdisMedium802_5:
+
+ TrFilterDprIndicateReceive(
+ Miniport->TrDB,
+ Packet,
+ BufferAddress,
+ BufferLength,
+ NULL,
+ 0,
+ 0
+ );
+
+ TrFilterDprIndicateReceiveComplete(
+ Miniport->TrDB
+ );
+
+ break;
+
+ case NdisMediumFddi:
+
+ FddiFilterDprIndicateReceive(
+ Miniport->FddiDB,
+ Packet,
+ ((PCHAR)BufferAddress) + 1,
+ 0,
+ BufferAddress,
+ BufferLength,
+ NULL,
+ 0,
+ 0
+ );
+
+ FddiFilterDprIndicateReceiveComplete(
+ Miniport->FddiDB
+ );
+
+ break;
+
+ case NdisMediumArcnet878_2:
+
+
+ if ( ARC_PACKET_IS_ENCAPSULATED(Packet) ) {
+
+ goto EthIndicateLoopbackRuntPacket;
+
+ } else {
+
+ ArcFilterDprIndicateReceive(
+ Miniport->ArcDB,
+ BufferAddress,
+ ((PCHAR)BufferAddress) + Miniport->LoopbackPacketHeaderSize,
+ Length - Miniport->LoopbackPacketHeaderSize
+ );
+
+ ArcFilterDprIndicateReceiveComplete(
+ Miniport->ArcDB
+ );
+ }
+
+ break;
+
+ }
+
+ }
+
+ Miniport->LoopbackPacket = NULL;
+
+ }
+
+ return SelfDirected;
+
+}
+
+VOID
+MiniportFreeArcnetHeader(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+ This function strips off the arcnet header appended to
+ ethernet encapsulated packets
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+ Packet - Ndis packet.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_M_OPEN_BLOCK Open;
+ PARC_BUFFER_LIST Buffer, TmpBuffer;
+ PNDIS_BUFFER NdisBuffer;
+ PVOID BufferVa;
+ UINT Length;
+
+ Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Open;
+
+ if ( Open->UsingEthEncapsulation ) {
+
+ NdisUnchainBufferAtFront(
+ Packet,
+ &NdisBuffer
+ );
+
+ NdisQueryBuffer(NdisBuffer,
+ (PVOID *) &BufferVa,
+ &Length
+ );
+
+ NdisFreeBuffer(NdisBuffer);
+
+ Buffer = Miniport->ArcnetUsedBufferList;
+
+ if (Buffer->Buffer == BufferVa) {
+
+ Miniport->ArcnetUsedBufferList = Buffer->Next;
+
+ } else {
+
+ while (Buffer->Next->Buffer != BufferVa) {
+
+ Buffer = Buffer->Next;
+ }
+
+ TmpBuffer = Buffer->Next;
+ Buffer->Next = Buffer->Next->Next;
+ Buffer = TmpBuffer;
+
+ }
+
+ Buffer->Next = Miniport->ArcnetFreeBufferList;
+ Miniport->ArcnetFreeBufferList = Buffer;
+ }
+}
+
+
+VOID
+FASTCALL
+MiniportStartSends(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Submits as many sends as possible to the mini-port.
+
+Arguments:
+
+ Miniport - Miniport to send to.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PARC_BUFFER_LIST Buffer;
+ PNDIS_BUFFER NdisBuffer;
+ PNDIS_BUFFER TmpBuffer;
+ PNDIS_PACKET Packet;
+ PNDIS_PACKET PrevPacket;
+ NDIS_STATUS Status;
+ PNDIS_PACKET_RESERVED Reserved;
+ PNDIS_M_OPEN_BLOCK Open;
+ UINT Flags;
+ PUCHAR Address;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter sends\n");)
+
+ LOG('s');
+
+ Miniport->SendCompleteCalled = FALSE;
+
+ do {
+ Packet = Miniport->FirstPendingPacket;
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ Open = Reserved->Open;
+
+ NDIS_LOG_PACKET(Miniport, Packet, 's');
+
+ if (Miniport->MediaType == NdisMediumArcnet878_2) {
+
+ goto BuildArcnetHeader;
+
+ }
+
+DoneBuildingArcnetHeader:
+
+ //
+ // Remove from Queue
+ //
+ Miniport->FirstPendingPacket = Reserved->Next;
+
+ //
+ // Put on finish queue
+ //
+
+ PrevPacket = Miniport->LastMiniportPacket;
+ Miniport->LastMiniportPacket = Packet;
+
+ //
+ // Indicate the packet loopback if necessary.
+ //
+
+ if ((Miniport->MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK) &&
+ (!Miniport->AlreadyLoopedBack) &&
+ MiniportSendLoopback(Miniport, Packet)
+ )
+ {
+
+ LOUD_DEBUG(DbgPrint("NdisM: Not sending packet 0x%x\n", Packet);)
+
+ LOG('l');
+ NDIS_LOG_PACKET(Miniport, Packet, 'l');
+
+ Status = NDIS_STATUS_SUCCESS;
+ goto NoCardSend;
+ }
+
+ //
+ // Submit to card
+ //
+
+ LOUD_DEBUG(DbgPrint("NdisM: Sending packet 0x%x\n", Packet);)
+
+ REMOVE_RESOURCE(Miniport, 'S');
+
+ NdisQuerySendFlags(Packet, &Flags);
+
+ LOG('M');
+
+ NDIS_LOG_PACKET(Miniport, Packet, 'M');
+
+ Status = (Open->SendHandler)(
+ Open->MiniportAdapterContext,
+ Packet,
+ Flags
+ );
+ if (Status == NDIS_STATUS_PENDING)
+ {
+ LOG('p');
+ NDIS_LOG_PACKET(Miniport, Packet, 'p');
+
+ LOUD_DEBUG(DbgPrint("NdisM: Complete is pending\n");)
+
+ //
+ // We need to clear the loop back flag here also.
+ //
+ Miniport->AlreadyLoopedBack = FALSE;
+
+ continue;
+
+ }
+
+NoCardSend:
+
+ if (Miniport->MediaType == NdisMediumArcnet878_2) {
+
+ MiniportFreeArcnetHeader(Miniport, Packet);
+ }
+
+ if (Status != NDIS_STATUS_RESOURCES)
+ {
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ ADD_RESOURCE(Miniport, 'F');
+
+ LOG('F');
+ NDIS_LOG_PACKET(Miniport, Packet, 'F');
+ }
+
+ //
+ // Remove from finish queue
+ //
+
+ LOUD_DEBUG(DbgPrint("NdisM: Completed 0x%x\n", Status);)
+
+ //
+ // If send complete was called from the miniport's send handler
+ // then our local PrevPacket pointer may no longer be valid.
+ //
+
+ if ( Miniport->SendCompleteCalled )
+ {
+ Miniport->SendCompleteCalled = FALSE;
+ MiniportFindPacket(Miniport, Packet, &PrevPacket);
+ }
+
+ Miniport->LastMiniportPacket = PrevPacket;
+
+ if ( PrevPacket == NULL ) {
+
+ Miniport->FirstPacket = Reserved->Next;
+ Miniport->DeadPacket = NULL;
+
+ } else {
+
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next = Reserved->Next;
+
+ //
+ // If we just unlinked the last packet then we need to update
+ // our last packet pointer.
+ //
+
+ if ( Packet == Miniport->LastPacket ) {
+
+ Miniport->LastPacket = PrevPacket;
+ }
+ }
+
+ //
+ // Reset for the next packet in the pending queue.
+ //
+ Miniport->AlreadyLoopedBack = FALSE;
+
+ //
+ // Indicate the completion to the protocol.
+ //
+ NDIS_LOG_PACKET(Miniport, Packet, 'C');
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler) (
+ Open->ProtocolBindingContext,
+ Packet,
+ Status
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ Open->References--;
+
+ if (Open->References == 0) {
+
+ FinishClose(Miniport, Open);
+ }
+
+ } else {
+
+ LOUD_DEBUG(DbgPrint("NdisM: Deferring send\n");)
+
+ //
+ // If send complete was called from the miniport's send handler
+ // then our local PrevPacket pointer may no longer be valid.
+ //
+
+ if ( Miniport->SendCompleteCalled ) {
+
+ Miniport->SendCompleteCalled = FALSE;
+ MiniportFindPacket(Miniport, Packet, &PrevPacket);
+ }
+
+ //
+ // Remove from finish queue
+ //
+ Miniport->LastMiniportPacket = PrevPacket;
+
+ //
+ // Put on pending queue
+ //
+ Miniport->FirstPendingPacket = Packet;
+
+ //
+ // Mark the packet at the head of the pending queue as having
+ // been looped back.
+ //
+ Miniport->AlreadyLoopedBack = TRUE;
+
+ LOG('o');
+ NDIS_LOG_PACKET(Miniport, Packet, 'o');
+
+ //
+ // Set flag
+ //
+ CLEAR_RESOURCE(Miniport, 'S');
+ }
+
+ } while ((Miniport->SendResourcesAvailable != 0) && (Miniport->FirstPendingPacket));
+
+ LOG('S');
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit sends\n");)
+
+ return;
+
+BuildArcnetHeader:
+
+ if (Open->UsingEthEncapsulation) {
+
+ if (Miniport->ArcnetFreeBufferList == NULL) {
+
+ //
+ // Set flag
+ //
+ CLEAR_RESOURCE(Miniport, 'S');
+ return;
+
+ }
+
+ NdisQueryPacket(Packet,
+ NULL,
+ NULL,
+ &TmpBuffer,
+ NULL
+ );
+
+ NdisQueryBuffer(TmpBuffer, &Address, &Flags);
+
+ Buffer = Miniport->ArcnetFreeBufferList;
+ Miniport->ArcnetFreeBufferList = Buffer->Next;
+
+ NdisAllocateBuffer(
+ &Status,
+ &NdisBuffer,
+ Miniport->ArcnetBufferPool,
+ Buffer->Buffer,
+ 3
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ Buffer->Next = Miniport->ArcnetFreeBufferList;
+ Miniport->ArcnetFreeBufferList = Buffer;
+ CLEAR_RESOURCE(Miniport, 'S');
+ return;
+
+ }
+
+ Buffer->Next = Miniport->ArcnetUsedBufferList;
+ Miniport->ArcnetUsedBufferList = Buffer;
+
+ NdisChainBufferAtFront(Packet, NdisBuffer);
+
+ ((PUCHAR)Buffer->Buffer)[0] = Miniport->ArcnetAddress;
+
+ if (Address[0] & 0x01) {
+
+ //
+ // Broadcast
+ //
+ ((PUCHAR)Buffer->Buffer)[1] = 0x00;
+
+ } else {
+
+ ((PUCHAR)Buffer->Buffer)[1] = Address[5];
+
+ }
+
+ ((PUCHAR) Buffer->Buffer)[2] = 0xE8;
+
+ }
+
+ goto DoneBuildingArcnetHeader;
+}
+
+
+
+VOID
+AbortMiniportPacketsAndPending(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Aborts all outstanding requests on a mini-port.
+
+ CALLED WITH THE LOCK HELD!!
+
+Arguments:
+
+ Miniport - Miniport to abort.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_PACKET Packet;
+ PNDIS_PACKET TmpPacket;
+ PNDIS_REQUEST Request;
+ PNDIS_REQUEST TmpRequest;
+ PNDIS_M_OPEN_BLOCK Open;
+ PNDIS_PACKET ArcnetLimitPacket;
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter abort packets and pending\n");)
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ Miniport->Timeout = FALSE;
+
+ //
+ // Abort Packets
+ //
+
+ Packet = Miniport->FirstPacket;
+ ArcnetLimitPacket = Miniport->FirstPendingPacket;
+
+ Miniport->LastMiniportPacket = NULL;
+ Miniport->FirstPendingPacket = NULL;
+ Miniport->FirstPacket = NULL;
+ Miniport->LastPacket = NULL;
+ Miniport->DeadPacket = NULL;
+
+ NDIS_LOG_PACKET(Miniport, NULL, 'a');
+
+ while (Packet != NULL) {
+
+ TmpPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next;
+
+ Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Open;
+
+ //
+ // Set flag that we've reached the packets that are
+ // not on the mini-port.
+ //
+
+ if ( Packet == ArcnetLimitPacket ) {
+
+ ArcnetLimitPacket = NULL;
+ }
+
+ //
+ // Now free the arcnet header.
+ //
+
+ if ( Miniport->MediaType == NdisMediumArcnet878_2 && ArcnetLimitPacket ) {
+
+ MiniportFreeArcnetHeader(Miniport, Packet);
+ }
+
+ NDIS_LOG_PACKET(Miniport, Packet, 'C');
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler) (
+ Open->ProtocolBindingContext,
+ Packet,
+ NDIS_STATUS_REQUEST_ABORTED
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ Open->References--;
+
+ if (Open->References == 0) {
+
+ FinishClose(Miniport,Open);
+ }
+
+ Packet = TmpPacket;
+ }
+
+ NDIS_LOG_PACKET(Miniport, NULL, 'A');
+
+ //
+ // Abort Requests
+ //
+ Request = Miniport->MiniportRequest;
+ Miniport->MiniportRequest = NULL;
+
+ if (Request != NULL) {
+
+ Open = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open;
+
+ if (Request != &(Miniport->InternalRequest)) {
+
+ if (Request->RequestType == NdisRequestQueryStatistics) {
+
+ AbortQueryStatisticsRequest( Request, NDIS_STATUS_REQUEST_ABORTED );
+
+ } else {
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.RequestCompleteHandler) (
+ Open->ProtocolBindingContext,
+ Request,
+ NDIS_STATUS_REQUEST_ABORTED
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ Open->References--;
+
+ if (Open->References == 0) {
+
+ FinishClose(Miniport,Open);
+
+ }
+
+ }
+
+ } else {
+
+ if (Request->RequestType == NdisRequestSetInformation) {
+
+ NdisMSetInformationComplete(
+ (NDIS_HANDLE)Miniport,
+ NDIS_STATUS_FAILURE
+ );
+
+ } else {
+
+ NdisMQueryInformationComplete(
+ (NDIS_HANDLE)Miniport,
+ NDIS_STATUS_FAILURE
+ );
+
+ }
+
+ }
+
+ }
+
+ Request = Miniport->FirstPendingRequest;
+ Miniport->FirstPendingRequest = NULL;
+ Miniport->LastPendingRequest = NULL;
+ Miniport->PendingRequestTimeout = FALSE;
+
+ while (Request != NULL) {
+
+ TmpRequest = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Next;
+
+ Open = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open;
+
+ if (Request->RequestType == NdisRequestQueryStatistics) {
+
+ AbortQueryStatisticsRequest( Request, NDIS_STATUS_REQUEST_ABORTED );
+
+ } else {
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.RequestCompleteHandler) (
+ Open->ProtocolBindingContext,
+ Request,
+ NDIS_STATUS_REQUEST_ABORTED
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ Open->References--;
+
+ if (Open->References == 0) {
+
+ FinishClose(Miniport,Open);
+
+ }
+
+ }
+
+ Request = TmpRequest;
+
+ }
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit abort packets and pending\n");)
+
+}
+
+VOID
+AbortQueryStatisticsRequest(
+ PNDIS_REQUEST Request,
+ NDIS_STATUS Status
+ )
+{
+ PNDIS_QUERY_GLOBAL_REQUEST GlobalRequest;
+ PNDIS_QUERY_ALL_REQUEST AllRequest;
+ PNDIS_QUERY_OPEN_REQUEST OpenRequest;
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+
+ GlobalRequest = CONTAINING_RECORD (Request,
+ NDIS_QUERY_GLOBAL_REQUEST,
+ Request
+ );
+ Irp = GlobalRequest->Irp;
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ switch (IrpSp->MajorFunction) {
+
+ case IRP_MJ_CREATE:
+
+ //
+ // This request is one of the ones made during an open,
+ // while we are trying to determine the OID list. We
+ // set the event we are waiting for, the open code
+ // takes care of the rest.
+ //
+
+ OpenRequest = (PNDIS_QUERY_OPEN_REQUEST)GlobalRequest;
+
+ OpenRequest->NdisStatus = Status;
+ KeSetEvent(
+ &OpenRequest->Event,
+ 0L,
+ FALSE);
+
+ break;
+
+ case IRP_MJ_DEVICE_CONTROL:
+
+ //
+ // This is a real user request, process it as such.
+ //
+
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
+
+ case IOCTL_NDIS_QUERY_GLOBAL_STATS:
+
+ //
+ // A single query, complete the IRP.
+ //
+
+ Irp->IoStatus.Information =
+ Request->DATA.QUERY_INFORMATION.BytesWritten;
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ } else if (Status == NDIS_STATUS_INVALID_LENGTH) {
+ Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
+ } else {
+ Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; // what else
+ }
+
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ ExFreePool (GlobalRequest);
+ break;
+
+ case IOCTL_NDIS_QUERY_ALL_STATS:
+
+ //
+ // An "all" query.
+ //
+
+ AllRequest = (PNDIS_QUERY_ALL_REQUEST)GlobalRequest;
+
+ AllRequest->NdisStatus = Status;
+ KeSetEvent(
+ &AllRequest->Event,
+ 0L,
+ FALSE);
+
+ break;
+
+ }
+
+ break;
+
+ }
+
+ return;
+
+} // AbortQueryStatisticsRequest
+
+
+VOID
+FASTCALL
+MiniportProcessDeferred(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Processes all outstanding operations.
+
+ CALLED WITH THE LOCK HELD!!
+
+Arguments:
+
+ Miniport - Miniport to send to.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ BOOLEAN DoneSomething;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ VERY_LOUD_DEBUG(DbgPrint("NdisM: Enter processing deferred \n");)
+
+ Miniport->ProcessingDeferred = TRUE;
+
+ do
+ {
+ DoneSomething = FALSE;
+
+ //
+ // Check for outstanding timers and dpcs first.
+ //
+ if (Miniport->ProcessOddDeferredStuff)
+ {
+ Miniport->ProcessOddDeferredStuff = FALSE;
+
+ if (Miniport->HaltingMiniport && Miniport->ResetInProgress == NULL)
+ {
+ //
+ // Do nothing
+ //
+ Miniport->ProcessingDeferred = FALSE;
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+ VERY_LOUD_DEBUG(DbgPrint("NdisM: Exit processing deferred\n");)
+
+ return;
+ }
+
+ if (Miniport->RunDpc && Miniport->ResetInProgress == NULL)
+ {
+ VERY_LOUD_DEBUG(DbgPrint("NdisM: queuing dpc timer\n");)
+ Miniport->RunDpc = FALSE;
+ Miniport->ProcessingDeferred = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 0);
+
+ if (Miniport->RunTimer ||
+ Miniport->HaltingMiniport ||
+ Miniport->ResetRequested ||
+ Miniport->RunDoRequests) {
+
+ Miniport->ProcessOddDeferredStuff = TRUE;
+ }
+
+ return;
+ }
+
+ if (Miniport->RunTimer != NULL)
+ {
+ PNDIS_MINIPORT_TIMER MiniportTimer;
+
+ VERY_LOUD_DEBUG(DbgPrint("NdisM: queueing timer timer\n");)
+
+ MiniportTimer = Miniport->RunTimer;
+ Miniport->RunTimer = MiniportTimer->NextDeferredTimer;
+ Miniport->ProcessingDeferred = FALSE;
+
+ NdisMSetTimer(MiniportTimer, 0);
+
+ if (Miniport->RunTimer ||
+ Miniport->HaltingMiniport ||
+ Miniport->ResetRequested ||
+ Miniport->RunDoRequests) {
+
+ Miniport->ProcessOddDeferredStuff = TRUE;
+ }
+
+ return;
+ }
+
+ //
+ // If we have a reset in progress then bail now.
+ //
+
+ if ( Miniport->ResetInProgress != NULL ) {
+
+ Miniport->ProcessOddDeferredStuff = TRUE;
+ return;
+ }
+
+ //
+ // If we have any pending opens, complete them now.
+ //
+
+ if ( Miniport->FirstPendingOpen != NULL )
+ {
+ MiniportFinishPendingOpens(Miniport);
+ }
+
+ //
+ // Do we need to reset?
+ //
+
+ if (Miniport->ResetRequested != NULL)
+ {
+ NDIS_STATUS Status;
+ BOOLEAN AddressingReset;
+ PNDIS_M_OPEN_BLOCK Open = Miniport->ResetRequested;
+
+ VERY_LOUD_DEBUG(DbgPrint("NdisM: Reset requested \n");)
+
+ if (Open != (PNDIS_M_OPEN_BLOCK)(Miniport)) {
+
+ //
+ // Real reset. Wait for card to go slow
+ //
+
+ if ((Miniport->LastMiniportPacket != NULL) ||
+ (Miniport->MiniportRequest != NULL)) {
+
+ //
+ // Wait for send/request to complete
+ //
+
+ VERY_LOUD_DEBUG(DbgPrint("NdisM: Card is busy\n");)
+ VERY_LOUD_DEBUG(DbgPrint("NdisM: Exit do deferred\n");)
+
+ Miniport->ProcessingDeferred = FALSE;
+
+ if (Miniport->RunTimer ||
+ Miniport->HaltingMiniport ||
+ Miniport->ResetRequested ||
+ Miniport->RunDoRequests) {
+
+ Miniport->ProcessOddDeferredStuff = TRUE;
+ }
+
+ return;
+ }
+
+ }
+
+ //
+ // Start Miniport reset.
+ //
+
+ DoneSomething = TRUE;
+
+ Miniport->ResetInProgress = Miniport->ResetRequested;
+ Miniport->ResetRequested = NULL;
+
+ //
+ // Indicate status to protocols
+ //
+
+ NdisMIndicateStatus(Miniport,
+ NDIS_STATUS_RESET_START,
+ NULL,
+ 0
+ );
+
+ NdisMIndicateStatusComplete(Miniport);
+
+ VERY_LOUD_DEBUG(DbgPrint("NdisM: calling mini-port reset\n");)
+
+ Status =
+ (Miniport->DriverHandle->MiniportCharacteristics.ResetHandler)(
+ &AddressingReset,
+ Miniport->MiniportAdapterContext
+ );
+
+ if (Status != NDIS_STATUS_PENDING) {
+
+ AbortMiniportPacketsAndPending(Miniport);
+
+ VERY_LOUD_DEBUG(DbgPrint("NdisM: Reset completed\n");)
+
+ //
+ // Check if we are going to have to reset the
+ // adapter again. This happens when we are doing
+ // the reset because of a ring failure.
+ //
+ if (Miniport->TrResetRing == 1) {
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ Miniport->TrResetRing = 0;
+
+ } else {
+
+ Miniport->TrResetRing = NDIS_MINIPORT_TR_RESET_TIMEOUT;
+
+ }
+
+ }
+
+ //
+ // Finish off reset
+ //
+
+ Miniport->ResetInProgress = NULL;
+
+ NdisMIndicateStatus(Miniport,
+ NDIS_STATUS_RESET_END,
+ &Status,
+ sizeof(Status)
+ );
+
+ NdisMIndicateStatusComplete(Miniport);
+
+ if (Open != (PNDIS_M_OPEN_BLOCK)(Miniport)) {
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.ResetCompleteHandler)(
+ Open->ProtocolBindingContext,
+ Status
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ Open->References--;
+
+ if (Open->References == 0) {
+
+ FinishClose(Miniport, Open);
+
+ }
+
+ }
+
+ if (AddressingReset &&
+ (Status == NDIS_STATUS_SUCCESS) &&
+ ((Miniport->EthDB != NULL) ||
+ (Miniport->TrDB != NULL) ||
+ (Miniport->FddiDB != NULL) ||
+ (Miniport->ArcDB != NULL))) {
+
+ Miniport->NeedToUpdatePacketFilter = TRUE;
+ switch (Miniport->MediaType) {
+ case NdisMedium802_3:
+ Miniport->NeedToUpdateEthAddresses = TRUE;
+ break;
+ case NdisMedium802_5:
+ Miniport->NeedToUpdateFunctionalAddress = TRUE;
+ Miniport->NeedToUpdateGroupAddress = TRUE;
+ break;
+ case NdisMediumFddi:
+ Miniport->NeedToUpdateFddiLongAddresses = TRUE;
+ Miniport->NeedToUpdateFddiShortAddresses = TRUE;
+ break;
+ case NdisMediumArcnet878_2:
+ break;
+ }
+
+ Miniport->RunDoRequests = TRUE;
+
+ }
+
+ if (Miniport->RunTimer ||
+ Miniport->HaltingMiniport ||
+ Miniport->ResetRequested ||
+ Miniport->RunDoRequests) {
+
+ Miniport->ProcessOddDeferredStuff = TRUE;
+ }
+ }
+ else
+ {
+ VERY_LOUD_DEBUG(DbgPrint("NdisM: Reset is pending\n");)
+ VERY_LOUD_DEBUG(DbgPrint("NdisM: Exit do deferred\n");)
+
+ //
+ // Lock everything else out while processing
+ //
+ Miniport->ProcessingDeferred = FALSE;
+
+ if (Miniport->RunDpc)
+ {
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 0);
+ }
+
+ if (Miniport->RunTimer ||
+ Miniport->HaltingMiniport ||
+ Miniport->ResetRequested ||
+ Miniport->RunDoRequests) {
+
+ Miniport->ProcessOddDeferredStuff = TRUE;
+ }
+
+ return;
+ }
+ }
+
+ if ((Miniport->RunDoRequests) &&
+ (Miniport->ResetInProgress == NULL)
+ )
+ {
+ MiniportDoRequests(Miniport);
+ DoneSomething = TRUE;
+ }
+ }
+
+ if ((Miniport->FirstPendingPacket != NULL) &&
+ (Miniport->SendResourcesAvailable != 0) &&
+ (Miniport->ResetInProgress == NULL)
+ )
+ {
+ MiniportStartSends(Miniport);
+ DoneSomething = TRUE;
+ }
+
+ } while ( DoneSomething );
+
+ Miniport->ProcessingDeferred = FALSE;
+
+ VERY_LOUD_DEBUG(DbgPrint("NdisM: Exit do deferred\n");)
+
+}
+
+//
+// Timers
+//
+
+
+VOID
+NdisMTimerDpc(
+ PKDPC Dpc,
+ PVOID Context,
+ PVOID SystemContext1,
+ PVOID SystemContext2
+ )
+/*++
+
+Routine Description:
+
+ This function services all mini-port timer interrupts. It then calls the
+ appropriate function that mini-port consumers have registered in the
+ call to NdisMInitializeTimer.
+
+Arguments:
+
+ Dpc - Not used.
+
+ Context - A pointer to the NDIS_MINIPORT_TIMER which is bound to this DPC.
+
+ SystemContext1,2 - not used.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MINIPORT_TIMER MiniportTimer = (PNDIS_MINIPORT_TIMER)(Context);
+ PNDIS_TIMER_FUNCTION TimerFunction;
+ PNDIS_MINIPORT_BLOCK Miniport = MiniportTimer->Miniport;
+ BOOLEAN LocalLock;
+
+ UNREFERENCED_PARAMETER(Dpc);
+ UNREFERENCED_PARAMETER(SystemContext1);
+ UNREFERENCED_PARAMETER(SystemContext2);
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ if (Miniport->HaltingMiniport) {
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ return;
+
+ }
+
+ if ((Miniport->LockAcquired) || (Miniport->InInitialize)) {
+
+ PNDIS_MINIPORT_TIMER TmpTimer;
+
+ //
+ // Make sure it is not already on the list
+ //
+ TmpTimer = Miniport->RunTimer;
+
+ while (TmpTimer != NULL) {
+
+ if (TmpTimer == MiniportTimer) {
+
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ return;
+
+ }
+
+ TmpTimer = TmpTimer->NextDeferredTimer;
+ }
+
+ //
+ // A DPC or timer is already running, queue this for later.
+ //
+
+ MiniportTimer->NextDeferredTimer = Miniport->RunTimer;
+ Miniport->RunTimer = MiniportTimer;
+
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ return;
+
+ }
+
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Call Miniport timer function
+ //
+
+ TimerFunction = MiniportTimer->MiniportTimerFunction;
+
+ (*TimerFunction)(NULL, MiniportTimer->MiniportTimerContext, NULL, NULL);
+
+ if (!Miniport->ProcessingDeferred) {
+
+ MiniportProcessDeferred(Miniport);
+
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+}
+
+
+VOID
+NdisMInitializeTimer(
+ IN OUT PNDIS_MINIPORT_TIMER MiniportTimer,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_TIMER_FUNCTION TimerFunction,
+ IN PVOID FunctionContext
+ )
+/*++
+
+Routine Description:
+
+ Sets up an Miniport Timer object, initializing the DPC in the timer to
+ the function and context.
+
+Arguments:
+
+ MiniportTimer - the timer object.
+ MiniportAdapterHandle - pointer to the mini-port block;
+ TimerFunction - Routine to start.
+ FunctionContext - Context of TimerFunction.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ KeInitializeTimer(&(MiniportTimer->Timer));
+
+ MiniportTimer->Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ MiniportTimer->MiniportTimerFunction = TimerFunction;
+ MiniportTimer->MiniportTimerContext = FunctionContext;
+
+ //
+ // Initialize our dpc. If Dpc was previously initialized, this will
+ // reinitialize it.
+ //
+
+ KeInitializeDpc(
+ &(MiniportTimer->Dpc),
+ (PKDEFERRED_ROUTINE) NdisMTimerDpc,
+ (PVOID)MiniportTimer
+ );
+}
+
+
+
+
+VOID
+NdisMWakeUpDpc(
+ PKDPC Dpc,
+ PVOID Context,
+ PVOID SystemContext1,
+ PVOID SystemContext2
+ )
+/*++
+
+Routine Description:
+
+ This function services all mini-port. It checks to see if a mini-port is
+ ever stalled.
+
+Arguments:
+
+ Dpc - Not used.
+
+ Context - A pointer to the NDIS_TIMER which is bound to this DPC.
+
+ SystemContext1,2 - not used.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(Context);
+ BOOLEAN Hung = FALSE;
+ BOOLEAN LocalLock;
+
+ UNREFERENCED_PARAMETER(Dpc);
+ UNREFERENCED_PARAMETER(SystemContext1);
+ UNREFERENCED_PARAMETER(SystemContext2);
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ if (Miniport->HaltingMiniport)
+ {
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ return;
+ }
+
+ //
+ // Slam the window open
+ //
+ Miniport->SendResourcesAvailable = 0xffffff;
+
+ if (Miniport->LockAcquired)
+ {
+ //
+ // A DPC or timer is already running, assume that means things are fine.
+ //
+
+ NdisSetTimer(&Miniport->WakeUpDpcTimer, NDIS_MINIPORT_WAKEUP_TIMEOUT);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ return;
+ }
+
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Call Miniport stall checker.
+ //
+ if (Miniport->DriverHandle->MiniportCharacteristics.CheckForHangHandler != NULL)
+ {
+ Hung = (Miniport->DriverHandle->MiniportCharacteristics.CheckForHangHandler)(
+ Miniport->MiniportAdapterContext
+ );
+ }
+
+ //
+ // Did a request pend to long?
+ //
+ if (Miniport->MiniportRequest != NULL)
+ {
+ if (Miniport->Timeout)
+ Hung = TRUE;
+ else
+ Miniport->Timeout = TRUE;
+ }
+
+ //
+ // Did a packet send pend to long?
+ //
+ if (Miniport->FirstPacket != NULL)
+ {
+ if ((Miniport->Timeout) &&
+ (Miniport->FirstPacket == Miniport->DeadPacket)
+ )
+ {
+ Hung = TRUE;
+ }
+ else
+ {
+ Miniport->Timeout = TRUE;
+ Miniport->DeadPacket = Miniport->FirstPacket;
+ }
+ }
+
+ if ((Miniport->TrResetRing == 1) && (Miniport->ResetRequested == NULL))
+ {
+ Hung = TRUE;
+ }
+ else if (Miniport->TrResetRing > 1)
+ {
+ Miniport->TrResetRing--;
+ }
+
+ //
+ // Check to see if we have a request that is pending to long.
+ //
+ if (Miniport->FirstPendingRequest != NULL)
+ {
+ if (Miniport->PendingRequestTimeout)
+ {
+ Hung = TRUE;
+ }
+ else
+ {
+ Miniport->PendingRequestTimeout = TRUE;
+ }
+ }
+
+ if (Hung)
+ {
+ if (Miniport->InAddDriver)
+ {
+ //
+ // Just abort everything
+ //
+ AbortMiniportPacketsAndPending(Miniport);
+ }
+ else
+ {
+ PNDIS_M_OPEN_BLOCK Open = Miniport->ResetRequested;
+
+ LOUD_DEBUG(DbgPrint("NdisM: WakeUpDpc is resetting mini-port\n");)
+
+ if ((Open != NULL) && (Open != (PNDIS_M_OPEN_BLOCK)Miniport))
+ {
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.ResetCompleteHandler)(
+ Open->ProtocolBindingContext,
+ NDIS_STATUS_REQUEST_ABORTED
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+ }
+
+ //
+ // If there isn't already a reset in progress, issue a
+ // reset, otherwise let the current reset complete.
+ //
+
+ if ( !Miniport->ResetInProgress )
+ {
+ Miniport->ResetRequested = (PNDIS_M_OPEN_BLOCK)Miniport;
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+ if (!Miniport->ProcessingDeferred)
+ {
+ MiniportProcessDeferred(Miniport);
+ }
+ }
+ }
+ }
+ else
+ {
+ //
+ // Process any changes that may have occured.
+ //
+ if (!Miniport->ProcessingDeferred)
+ {
+ MiniportProcessDeferred(Miniport);
+ }
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisSetTimer(&Miniport->WakeUpDpcTimer, NDIS_MINIPORT_WAKEUP_TIMEOUT);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+}
+
+//
+// Dma operations
+//
+
+extern
+IO_ALLOCATION_ACTION
+NdisDmaExecutionRoutine(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ );
+
+
+//
+// Map Registers
+//
+
+extern
+IO_ALLOCATION_ACTION
+NdisAllocationExecutionRoutine(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ );
+
+
+NDIS_STATUS
+NdisMAllocateMapRegisters(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN UINT DmaChannel,
+ IN BOOLEAN Dma32BitAddresses,
+ IN ULONG PhysicalMapRegistersNeeded,
+ IN ULONG MaximumPhysicalMapping
+ )
+
+/*++
+
+Routine Description:
+
+ Allocates map registers for bus mastering devices.
+
+Arguments:
+
+ MiniportAdapterHandle - Handle passed to MiniportInitialize.
+
+ PhysicalMapRegistersNeeded - The maximum number of map registers needed
+ by the Miniport at any one time.
+
+ MaximumPhysicalMapping - Maximum length of a buffer that will have to be mapped.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Convert the handle to our internal structure.
+ //
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportAdapterHandle;
+
+ //
+ // This is needed by HalGetAdapter.
+ //
+ DEVICE_DESCRIPTION DeviceDescription;
+
+ //
+ // Returned by HalGetAdapter.
+ //
+ ULONG MapRegistersAllowed;
+
+ //
+ // Returned by HalGetAdapter.
+ //
+ PADAPTER_OBJECT AdapterObject;
+
+ //
+ // Map registers needed per channel.
+ //
+ ULONG MapRegistersPerChannel;
+
+ NTSTATUS NtStatus;
+
+ KIRQL OldIrql;
+
+ UINT i;
+
+ LARGE_INTEGER TimeoutValue;
+
+ //
+ // If the device is a busmaster, we get an adapter
+ // object for it.
+ // If map registers are needed, we loop, allocating an
+ // adapter channel for each map register needed.
+ //
+
+ if ((Miniport->Master) &&
+ (Miniport->BusType != (NDIS_INTERFACE_TYPE)-1) &&
+ (Miniport->BusNumber != (ULONG)-1)) {
+
+ TimeoutValue.QuadPart = Int32x32To64(2 * 1000, -10000);
+
+ Miniport->PhysicalMapRegistersNeeded = PhysicalMapRegistersNeeded;
+ Miniport->MaximumPhysicalMapping = MaximumPhysicalMapping;
+
+ //
+ // Allocate storage for holding the appropriate
+ // information for each map register.
+ //
+
+ Miniport->MapRegisters = (PMAP_REGISTER_ENTRY)
+ ExAllocatePool(
+ NonPagedPool,
+ sizeof(MAP_REGISTER_ENTRY) * PhysicalMapRegistersNeeded
+ );
+
+ if (Miniport->MapRegisters == (PMAP_REGISTER_ENTRY)NULL) {
+
+ //
+ // Error out
+ //
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 1,
+ 0xFFFFFFFF
+ );
+
+ return (NDIS_STATUS_RESOURCES);
+
+ }
+
+ //
+ // Use this event to tell us when NdisAllocationExecutionRoutine
+ // has been called.
+ //
+
+ KeInitializeEvent(
+ &Miniport->AllocationEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+
+ //
+ // Set up the device description; zero it out in case its
+ // size changes.
+ //
+
+ RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
+
+ DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
+ DeviceDescription.Master = TRUE;
+ DeviceDescription.ScatterGather = TRUE;
+
+ DeviceDescription.BusNumber = Miniport->BusNumber;
+ DeviceDescription.DmaChannel = DmaChannel;
+ DeviceDescription.InterfaceType = Miniport->AdapterType;
+
+ if (DeviceDescription.InterfaceType == NdisInterfaceIsa) {
+
+ //
+ // For ISA devices, the width is based on the DMA channel:
+ // 0-3 == 8 bits, 5-7 == 16 bits. Timing is compatibility
+ // mode.
+ //
+
+ if (DmaChannel > 4) {
+ DeviceDescription.DmaWidth = Width16Bits;
+ } else {
+ DeviceDescription.DmaWidth = Width8Bits;
+ }
+ DeviceDescription.DmaSpeed = Compatible;
+
+ } else if ((DeviceDescription.InterfaceType == NdisInterfaceEisa) ||
+ (DeviceDescription.InterfaceType == NdisInterfacePci) ||
+ (DeviceDescription.InterfaceType == NdisInterfaceMca)) {
+
+ DeviceDescription.Dma32BitAddresses = Dma32BitAddresses;
+ }
+
+ DeviceDescription.MaximumLength = MaximumPhysicalMapping;
+
+ //
+ // Get the adapter object.
+ //
+
+ AdapterObject = HalGetAdapter (&DeviceDescription, &MapRegistersAllowed);
+
+ if (AdapterObject == NULL) {
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 1,
+ 0xFFFFFFFF
+ );
+
+ ExFreePool(Miniport->MapRegisters);
+ Miniport->MapRegisters = NULL;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return(NDIS_STATUS_RESOURCES);
+
+ }
+
+ //
+ // We save this to call IoFreeMapRegisters later.
+ //
+
+ Miniport->SystemAdapterObject = AdapterObject;
+
+ //
+ // Determine how many map registers we need per channel.
+ //
+
+ MapRegistersPerChannel = ((MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2;
+
+ ASSERT (MapRegistersAllowed >= MapRegistersPerChannel);
+
+ //
+ // Now loop, allocating an adapter channel each time, then
+ // freeing everything but the map registers.
+ //
+
+ for (i=0; i<Miniport->PhysicalMapRegistersNeeded; i++) {
+
+ Miniport->CurrentMapRegister = i;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NtStatus = IoAllocateAdapterChannel(
+ AdapterObject,
+ Miniport->DeviceObject,
+ MapRegistersPerChannel,
+ NdisAllocationExecutionRoutine,
+ (PVOID)Miniport
+ );
+
+ KeLowerIrql(OldIrql);
+
+ if (!NT_SUCCESS(NtStatus)) {
+
+ NdisPrint2("AllocateAdapterChannel: %lx\n", NtStatus);
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ for (; i != 0; i--) {
+ IoFreeMapRegisters(
+ Miniport->SystemAdapterObject,
+ Miniport->MapRegisters[i-1].MapRegister,
+ MapRegistersPerChannel
+ );
+ }
+
+ KeLowerIrql(OldIrql);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 1,
+ 0xFFFFFFFF
+ );
+
+ ExFreePool(Miniport->MapRegisters);
+ Miniport->MapRegisters = NULL;
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ TimeoutValue.QuadPart = Int32x32To64(2 * 1000, -10000);
+
+ //
+ // NdisAllocationExecutionRoutine will set this event
+ // when it has gotten FirstTranslationEntry.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->AllocationEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ NdisPrint2("NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus);
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ for (; i != 0; i--) {
+ IoFreeMapRegisters(
+ Miniport->SystemAdapterObject,
+ Miniport->MapRegisters[i-1].MapRegister,
+ MapRegistersPerChannel
+ );
+ }
+
+ KeLowerIrql(OldIrql);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 1,
+ 0xFFFFFFFF
+ );
+
+ ExFreePool(Miniport->MapRegisters);
+ Miniport->MapRegisters = NULL;
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ KeResetEvent(
+ &Miniport->AllocationEvent
+ );
+
+ }
+
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+VOID
+NdisMFreeMapRegisters(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Releases allocated map registers
+
+Arguments:
+
+ MiniportAdapterHandle - Handle passed to MiniportInitialize.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Convert the handle to our internal structure.
+ //
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportAdapterHandle;
+
+ KIRQL OldIrql;
+
+ ULONG i;
+
+ if (Miniport->Master && (Miniport->MapRegisters != NULL)) {
+
+ ULONG MapRegistersPerChannel =
+ ((Miniport->MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2;
+
+ for (i=0; i<Miniport->PhysicalMapRegistersNeeded; i++) {
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ IoFreeMapRegisters(
+ Miniport->SystemAdapterObject,
+ Miniport->MapRegisters[i].MapRegister,
+ MapRegistersPerChannel
+ );
+
+ KeLowerIrql(OldIrql);
+ }
+
+ ExFreePool(Miniport->MapRegisters);
+
+ Miniport->MapRegisters = NULL;
+
+ }
+
+}
+
+
+
+
+//
+// Interrupt stuff
+//
+
+
+BOOLEAN
+NdisMIsr(
+ IN PKINTERRUPT KInterrupt,
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ Handles ALL Miniport interrupts, calling the appropriate Miniport ISR and DPC
+ depending on the context.
+
+Arguments:
+
+ Interrupt - Interrupt object for the Mac.
+
+ Context - Really a pointer to the interrupt.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Get adapter from context.
+ //
+
+ PNDIS_MINIPORT_INTERRUPT Interrupt = (PNDIS_MINIPORT_INTERRUPT)Context;
+ PNDIS_MINIPORT_BLOCK Miniport = Interrupt->Miniport;
+
+ BOOLEAN InterruptRecognized;
+ BOOLEAN QueueDpc;
+
+ if (Miniport->NormalInterrupts) {
+
+ //
+ // Call to disable the interrupt
+ //
+
+ ASSERT(Miniport->DriverHandle->MiniportCharacteristics.DisableInterruptHandler != NULL);
+
+ MINIPORT_DISABLE_INTERRUPT(Miniport);
+
+ InterruptRecognized = TRUE;
+
+queue_dpc:
+
+ Increment((PLONG)&Interrupt->DpcCount,&Interrupt->DpcCountLock);
+
+ if (KeInsertQueueDpc(&Interrupt->InterruptDpc,NULL,NULL)) {
+ return InterruptRecognized;
+ }
+
+ //
+ // The DPC was already queued, so we have an extra reference (we
+ // do it this way to ensure that the reference is added *before*
+ // the DPC is queued).
+ //
+
+ Decrement((PLONG)&Interrupt->DpcCount,&Interrupt->DpcCountLock);
+
+ if (Miniport->HaltingMiniport && (Interrupt->DpcCount==0)) {
+
+ //
+ // We need to queue a DPC to set the event because we
+ // can't do it from the ISR. We know that the interrupt
+ // DPC won't fire because the refcount is 0, so we reuse it.
+ //
+
+ KeInitializeDpc(
+ &Interrupt->InterruptDpc,
+ NdisLastCountRemovedFunction,
+ (PVOID)&Interrupt->DpcsCompletedEvent
+ );
+
+ //
+ // When NdisLastCountRemovedFunction runs it will set
+ // the event.
+ //
+
+ KeInsertQueueDpc(&Interrupt->InterruptDpc, NULL, NULL);
+
+ }
+
+ return InterruptRecognized;
+
+ }
+
+ if (!Miniport->HaltingMiniport) {
+
+ //
+ // Call MiniportIsr
+ //
+
+ Interrupt->MiniportIsr(&InterruptRecognized,
+ &QueueDpc,
+ Miniport->MiniportAdapterContext
+ );
+ if (QueueDpc) goto queue_dpc;
+ return InterruptRecognized;
+
+ }
+
+ if (!Interrupt->SharedInterrupt &&
+ !Interrupt->IsrRequested &&
+ !Miniport->InInitialize) {
+
+ //
+ // Call to disable the interrupt
+ //
+
+ ASSERT(Miniport->DriverHandle->MiniportCharacteristics.DisableInterruptHandler != NULL);
+
+ MINIPORT_DISABLE_INTERRUPT(Miniport);
+ return TRUE;
+
+ }
+
+ //
+ // Call MiniportIsr, but don't queue a DPC.
+ //
+
+ Interrupt->MiniportIsr(&InterruptRecognized,
+ &QueueDpc,
+ Miniport->MiniportAdapterContext
+ );
+ return InterruptRecognized;
+
+}
+
+
+VOID
+NdisMDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+/*++
+
+Routine Description:
+
+ Handles ALL Miniport interrupt DPCs, calling the appropriate Miniport DPC
+ depending on the context.
+
+Arguments:
+
+ Interrupt - Interrupt object for the Mac.
+
+ Context - Really a pointer to the Interrupt.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Get adapter from context.
+ //
+
+ PNDIS_MINIPORT_INTERRUPT Interrupt = (PNDIS_MINIPORT_INTERRUPT)(InterruptContext);
+ PNDIS_MINIPORT_BLOCK Miniport = Interrupt->Miniport;
+ BOOLEAN LocalLock;
+
+ W_HANDLE_INTERRUPT_HANDLER MiniportDpc = Interrupt->MiniportDpc;
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ LOG('d');
+
+ if (Miniport->HaltingMiniport) {
+
+ Decrement((PLONG)&Interrupt->DpcCount,&Interrupt->DpcCountLock);
+
+ if (Interrupt->DpcCount==0) {
+
+ KeSetEvent(
+ &Interrupt->DpcsCompletedEvent,
+ 0L,
+ FALSE
+ );
+
+ }
+
+ LOG('h');
+ LOG('D');
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ return;
+ }
+
+ if (Miniport->LockAcquired) {
+
+ //
+ // A DPC is already running, queue this for later.
+ //
+
+ Miniport->RunDpc = TRUE;
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+ Decrement((PLONG)&Interrupt->DpcCount,&Interrupt->DpcCountLock);
+
+ LOG('L');
+ LOG('D');
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ return;
+
+ }
+
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Call MiniportDpc
+ //
+
+ (*MiniportDpc)(Miniport->MiniportAdapterContext);
+
+ Decrement((PLONG)&Interrupt->DpcCount,&Interrupt->DpcCountLock);
+
+ if (!Miniport->HaltingMiniport) {
+
+ //
+ // Enable interrupts
+ //
+
+ MINIPORT_SYNC_ENABLE_INTERRUPT(Miniport);
+
+ if (!Miniport->ProcessingDeferred) {
+
+ MiniportProcessDeferred(Miniport);
+
+ }
+
+ } else {
+
+ if (Interrupt->DpcCount == 0) {
+
+ KeSetEvent(
+ &Interrupt->DpcsCompletedEvent,
+ 0L,
+ FALSE
+ );
+
+ }
+
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ LOG('D');
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+}
+
+
+VOID
+NdisMDpcTimer(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+/*++
+
+Routine Description:
+
+ Handles a deferred interrupt dpc.
+
+Arguments:
+
+ Context - Really a pointer to the Miniport block.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Get adapter from context.
+ //
+
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(InterruptContext);
+ BOOLEAN LocalLock;
+
+ W_HANDLE_INTERRUPT_HANDLER MiniportDpc =
+ Miniport->DriverHandle->MiniportCharacteristics.HandleInterruptHandler;
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ if ((Miniport->HaltingMiniport) ||
+ (Miniport->InInitialize)) {
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ return;
+ }
+
+ if (Miniport->LockAcquired) {
+
+ //
+ // A DPC is already running, queue this for later.
+ //
+
+ Miniport->RunDpc = TRUE;
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ return;
+
+ }
+
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ MINIPORT_SYNC_DISABLE_INTERRUPT(Miniport);
+
+ //
+ // Call MiniportDpc
+ //
+
+ if (MiniportDpc != NULL) {
+
+ (*MiniportDpc)(Miniport->MiniportAdapterContext);
+
+ }
+
+ //
+ // Enable interrupts
+ //
+ MINIPORT_SYNC_ENABLE_INTERRUPT(Miniport);
+
+ //
+ // Check if we need to shutdown.
+ //
+ if (!Miniport->HaltingMiniport) {
+
+ if (!Miniport->ProcessingDeferred) {
+
+ MiniportProcessDeferred(Miniport);
+
+ }
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ return;
+
+}
+
+//
+// Io Port stuff
+//
+
+
+NDIS_STATUS
+NdisMRegisterIoPortRange(
+ OUT PVOID *PortOffset,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN UINT InitialPort,
+ IN UINT NumberOfPorts
+ )
+
+/*++
+
+Routine Description:
+
+ Sets up an IO port for operations.
+
+Arguments:
+
+ PortOffset - The mapped port address the Miniport uses for NdisRaw functions.
+
+ MiniportAdapterHandle - Handle passed to Miniport Initialize.
+
+ InitialPort - Physical address of the starting port number.
+
+ NumberOfPorts - Number of ports to map.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(MiniportAdapterHandle);
+ PHYSICAL_ADDRESS PortAddress;
+ PHYSICAL_ADDRESS InitialPortAddress;
+ ULONG addressSpace;
+ ULONG NumberOfElements;
+
+ BOOLEAN Conflict;
+ PCM_RESOURCE_LIST Resources;
+ NDIS_STATUS Status;
+
+ //
+ // First check if any bus access is allowed
+ //
+
+ if ((Miniport->BusType == (NDIS_INTERFACE_TYPE)-1) ||
+ (Miniport->BusNumber == (ULONG)-1)) {
+
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ //
+ // First check for resource conflict by expanding current resource list,
+ // adding in the mapped space, and then re-submitting the resource list.
+ //
+
+ if (Miniport->Resources != NULL) {
+
+ NumberOfElements = Miniport->Resources->List[0].PartialResourceList.Count + 1;
+
+ } else {
+
+ NumberOfElements = 1;
+ }
+
+ Resources = (PCM_RESOURCE_LIST)ExAllocatePool(
+ NonPagedPool,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ NumberOfElements
+ );
+
+ if (Resources == NULL) {
+
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ if (Miniport->Resources != NULL) {
+
+ RtlMoveMemory (Resources,
+ Miniport->Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ Miniport->Resources->List[0].PartialResourceList.Count
+ );
+
+ } else {
+
+ //
+ // Setup initial resource info
+ //
+ Resources->Count = 1;
+ Resources->List[0].InterfaceType = Miniport->AdapterType;
+ Resources->List[0].BusNumber = Miniport->BusNumber;
+ Resources->List[0].PartialResourceList.Version = 0;
+ Resources->List[0].PartialResourceList.Revision = 0;
+ Resources->List[0].PartialResourceList.Count = 0;
+
+ }
+
+ //
+ // Setup port
+ //
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Type =
+ CmResourceTypePort;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].ShareDisposition =
+ CmResourceShareDeviceExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Flags =
+ (Miniport->AdapterType == NdisInterfaceInternal)?
+ CM_RESOURCE_PORT_MEMORY : CM_RESOURCE_PORT_IO;
+#if !defined(BUILD_FOR_3_1)
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Port.Start.QuadPart =
+ (ULONG)InitialPort;
+#else
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Port.Start =
+ RtlConvertUlongToLargeInteger((ULONG)(InitialPort));
+#endif
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Port.Length =
+ NumberOfPorts;
+ Resources->List[0].PartialResourceList.Count++;
+
+ //
+ // Make the call
+ //
+
+ Status = IoReportResourceUsage(
+ NULL,
+ Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver,
+ NULL,
+ 0,
+ Miniport->DeviceObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ Resources->List[0].PartialResourceList.Count,
+ TRUE,
+ &Conflict
+ );
+
+ if (Miniport->Resources != NULL) {
+ ExFreePool(Miniport->Resources);
+ }
+
+ Miniport->Resources = Resources;
+
+ //
+ // Check for conflict.
+ //
+
+ if (Conflict || (Status != STATUS_SUCCESS)) {
+
+
+ if (Conflict) {
+
+
+ //
+ // Log an error
+ //
+
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ ULONG i;
+ ULONG StringSize;
+ PUCHAR Place;
+ PWCH baseFileName;
+
+ baseFileName = Miniport->MiniportName.Buffer;
+
+ //
+ // Parse out the path name, leaving only the device name.
+ //
+
+ for ( i = 0; i < Miniport->MiniportName.Length / sizeof(WCHAR); i++ ) {
+
+ //
+ // If s points to a directory separator, set baseFileName to
+ // the character after the separator.
+ //
+
+ if ( Miniport->MiniportName.Buffer[i] == OBJ_NAME_PATH_SEPARATOR ) {
+ baseFileName = &(Miniport->MiniportName.Buffer[++i]);
+ }
+
+ }
+
+ StringSize = Miniport->MiniportName.MaximumLength -
+ (((ULONG)baseFileName) - ((ULONG)Miniport->MiniportName.Buffer)) ;
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ Miniport->DeviceObject,
+ (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize +
+ 6) // wstrlen("99") * sizeof(WHCAR) + sizeof(UNICODE_NULL)
+ );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->ErrorCode = EVENT_NDIS_IO_PORT_CONFLICT;
+
+ //
+ // store the time
+ //
+
+ errorLogEntry->MajorFunctionCode = 0;
+ errorLogEntry->RetryCount = 0;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = 0;
+ errorLogEntry->SequenceNumber = 0;
+ errorLogEntry->IoControlCode = 0;
+
+ //
+ // Set string information
+ //
+
+ if (StringSize != 0) {
+
+ errorLogEntry->NumberOfStrings = 1;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+
+ RtlMoveMemory (
+ ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET),
+ (PVOID)baseFileName,
+ StringSize
+ );
+
+ Place = ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize;
+
+ } else {
+
+ Place = ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET);
+
+ errorLogEntry->NumberOfStrings = 0;
+
+ }
+
+ //
+ // write it out
+ //
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+ return NDIS_STATUS_RESOURCE_CONFLICT;
+
+ }
+
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ //
+ // Now Map the ports
+ //
+
+
+
+ //
+ // Get the system physical address for this card. The card uses
+ // I/O space, except for "internal" Jazz devices which use
+ // memory space.
+ //
+
+ addressSpace = (Miniport->AdapterType == NdisInterfaceInternal) ? 0 : 1;
+
+ InitialPortAddress.LowPart = InitialPort;
+ InitialPortAddress.HighPart = 0;
+
+ if ( !HalTranslateBusAddress(
+ Miniport->BusType, // InterfaceType
+ Miniport->BusNumber, // BusNumber
+ InitialPortAddress, // Bus Address
+ &addressSpace, // AddressSpace
+ &PortAddress // Translated address
+ ) ) {
+
+ //
+ // It would be nice to return a better status here, but we only get
+ // TRUE/FALSE back from HalTranslateBusAddress.
+ //
+
+ return NDIS_STATUS_FAILURE;
+ }
+
+ if (addressSpace == 0) {
+
+ //
+ // memory space
+ //
+
+ *(PortOffset) = (PULONG)MmMapIoSpace(
+ PortAddress,
+ NumberOfPorts,
+ FALSE
+ );
+
+ if (*(PortOffset) == (PULONG)NULL) {
+
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ } else {
+
+ //
+ // I/O space
+ //
+
+ *(PortOffset) = (PULONG)PortAddress.LowPart;
+
+ }
+
+ return NDIS_STATUS_SUCCESS;
+
+}
+
+
+
+VOID
+NdisMDeregisterIoPortRange(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN UINT InitialPort,
+ IN UINT NumberOfPorts,
+ IN PVOID PortOffset
+ )
+
+/*++
+
+Routine Description:
+
+ Sets up an IO port for operations.
+
+Arguments:
+
+ MiniportAdapterHandle - Handle passed to Miniport Initialize.
+
+ InitialPort - Physical address of the starting port number.
+
+ NumberOfPorts - Number of ports to map.
+
+ PortOffset - The mapped port address the Miniport uses for NdisRaw functions.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(MiniportAdapterHandle);
+ PHYSICAL_ADDRESS PortAddress;
+ PHYSICAL_ADDRESS InitialPortAddress;
+ ULONG addressSpace;
+
+ //
+ // Get the system physical address for this card. The card uses
+ // I/O space, except for "internal" Jazz devices which use
+ // memory space.
+ //
+
+ addressSpace = (Miniport->AdapterType == NdisInterfaceInternal) ? 0 : 1;
+
+ InitialPortAddress.LowPart = InitialPort;
+ InitialPortAddress.HighPart = 0;
+
+ if ( !HalTranslateBusAddress(
+ Miniport->BusType, // InterfaceType
+ Miniport->BusNumber, // BusNumber
+ InitialPortAddress, // Bus Address
+ &addressSpace, // AddressSpace
+ &PortAddress // Translated address
+ ) ) {
+
+ //
+ // It would be nice to return a better status here, but we only get
+ // TRUE/FALSE back from HalTranslateBusAddress.
+ //
+
+ return;
+ }
+
+ if (addressSpace == 0) {
+
+ //
+ // memory space
+ //
+
+ MmUnmapIoSpace(
+ PortOffset,
+ NumberOfPorts
+ );
+
+ } else {
+
+ //
+ // I/O space
+ //
+
+ }
+
+}
+
+
+//
+// Attribute functions
+//
+
+
+VOID
+NdisMSetAttributes(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN BOOLEAN BusMaster,
+ IN NDIS_INTERFACE_TYPE AdapterType
+ )
+/*++
+
+Routine Description:
+
+ This function sets specific information about an adapter.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+ MiniportAdapterContext - Context to pass to all Miniport driver functions.
+
+ BusMaster - TRUE if a bus mastering adapter.
+
+ AdapterType - Eisa, Isa, Mca or Internal.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+
+ Miniport->MiniportAdapterContext = MiniportAdapterContext;
+ Miniport->Master = BusMaster;
+ Miniport->AdapterType = AdapterType;
+
+ MiniportReferencePackage();
+}
+
+
+
+//
+// Interface functions
+//
+
+
+
+VOID
+NdisMIndicateStatus(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ )
+/*++
+
+Routine Description:
+
+ This function indicates a new status of the media/mini-port.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+ GeneralStatus - The status to indicate.
+
+ StatusBuffer - Additional information.
+
+ StatusBufferSize - Length of the buffer.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+ NDIS_STATUS Status;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ if ((GeneralStatus == NDIS_STATUS_RING_STATUS) &&
+ (StatusBufferSize == sizeof(NDIS_STATUS))) {
+
+ Status = *((PNDIS_STATUS)StatusBuffer);
+
+ if (Status & (NDIS_RING_LOBE_WIRE_FAULT |
+ NDIS_RING_HARD_ERROR |
+ NDIS_RING_SIGNAL_LOSS)) {
+
+ Miniport->TrResetRing = NDIS_MINIPORT_TR_RESET_TIMEOUT;
+
+ }
+
+ }
+
+ Open = Miniport->OpenQueue;
+
+ while (Open != NULL) {
+
+ //
+ // Call Protocol to indicate status
+ //
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.StatusHandler) (
+ Open->ProtocolBindingContext,
+ GeneralStatus,
+ StatusBuffer,
+ StatusBufferSize
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ Open = Open->MiniportNextOpen;
+
+ }
+
+}
+
+
+
+VOID
+NdisMIndicateStatusComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ )
+/*++
+
+Routine Description:
+
+ This function indicates the status is complete.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ Open = Miniport->OpenQueue;
+
+ while (Open != NULL) {
+
+ //
+ // Call Protocol to indicate status
+ //
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.StatusCompleteHandler) (
+ Open->ProtocolBindingContext
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ Open = Open->MiniportNextOpen;
+
+ }
+
+}
+
+
+VOID
+NdisMSendComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ This function indicates the completion of a send.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+ PNDIS_PACKET_RESERVED Reserved;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter send complete\n");)
+ LOUD_DEBUG(DbgPrint("NdisM: packet 0x%x\n", Packet);)
+
+ Miniport->SendCompleteCalled = TRUE;
+
+ //
+ // If the packet is not equal to the first packet then we have to find
+ // it because it may have completed out of order.
+ //
+
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+
+ if ( Miniport->FirstPacket == Packet )
+ {
+ Miniport->FirstPacket = Reserved->Next;
+ Miniport->DeadPacket = NULL;
+
+ if ( Miniport->LastMiniportPacket == Packet )
+ {
+ Miniport->LastMiniportPacket = NULL;
+ }
+ }
+ else
+ {
+ PNDIS_PACKET PrevPacket;
+
+ //
+ // Search for the packet.
+ //
+ MiniportFindPacket(Miniport, Packet, &PrevPacket);
+
+ ASSERT( PrevPacket != NULL );
+
+ //
+ // If we just completed the last packet then
+ // we need to update our last packet pointer.
+ //
+ if (Packet != Miniport->LastPacket)
+ {
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next = Reserved->Next;
+ }
+ else
+ {
+ Miniport->LastPacket = PrevPacket;
+ }
+
+ //
+ // If we just completed the last miniport packet then
+ // last miniport packet is the previous packet.
+ //
+
+ if ( Miniport->LastMiniportPacket == Packet )
+ {
+ Miniport->LastMiniportPacket = PrevPacket;
+ }
+ }
+
+ //
+ // Indicate to Protocol;
+ //
+
+ Open = Reserved->Open;
+
+ Miniport->Timeout = FALSE;
+
+ //
+ // If this is arcnet, then free the appended header.
+ //
+ if ( Miniport->MediaType == NdisMediumArcnet878_2 )
+ {
+ MiniportFreeArcnetHeader(Miniport, Packet);
+ }
+
+ LOG('C');
+ NDIS_LOG_PACKET(Miniport, Packet, 'C');
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)(
+ Open->ProtocolBindingContext,
+ Packet,
+ Status
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ ADD_RESOURCE(Miniport, 'P');
+
+ Open->References--;
+
+ if (Open->References == 0)
+ {
+ FinishClose(Miniport,Open);
+ }
+
+ if (!Miniport->ProcessingDeferred)
+ MiniportProcessDeferred(Miniport);
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit send complete\n");)
+}
+
+
+VOID
+NdisMWanSendComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ )
+
+/*++
+
+Routine Description:
+
+ This function indicates the status is complete.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ Open = Miniport->OpenQueue;
+
+ while (Open != NULL) {
+
+ //
+ // Call Protocol to indicate status
+ //
+
+ NDIS_LOG_PACKET(Miniport, Packet, 'C');
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler) (
+ Open->ProtocolBindingContext,
+ Packet,
+ Status
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ Open = Open->MiniportNextOpen;
+
+ }
+
+}
+
+
+
+typedef
+NDIS_STATUS
+(*WAN_RECEIVE_HANDLER) (
+ IN NDIS_HANDLE NdisLinkContext,
+ IN PUCHAR Packet,
+ IN ULONG PacketSize
+ );
+
+VOID
+NdisMWanIndicateReceive(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE NdisLinkContext,
+ IN PUCHAR Packet,
+ IN ULONG PacketSize
+ )
+/*++
+
+Routine Description:
+
+ This function indicates the status is complete.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ Open = Miniport->OpenQueue;
+
+ while (Open != NULL) {
+
+ //
+ // Call Protocol to indicate status
+ //
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ *Status =
+ ((WAN_RECEIVE_HANDLER)(Open->ProtocolHandle->ProtocolCharacteristics.ReceiveHandler)) (
+ NdisLinkContext,
+ Packet,
+ PacketSize);
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ Open = Open->MiniportNextOpen;
+
+ }
+}
+
+
+
+VOID
+NdisMWanIndicateReceiveComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE NdisLinkContext
+ )
+/*++
+
+Routine Description:
+
+ This function indicates the status is complete.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ Open = Miniport->OpenQueue;
+
+ while (Open != NULL) {
+
+ //
+ // Call Protocol to indicate status
+ //
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.ReceiveCompleteHandler) (
+ NdisLinkContext);
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ Open = Open->MiniportNextOpen;
+
+ }
+}
+
+
+VOID
+NdisMSendResourcesAvailable(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ )
+/*++
+
+Routine Description:
+
+ This function indicates that some send resources are available and are free for
+ processing more sends.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ LOG('a');
+
+ ADD_RESOURCE(Miniport, 'V');
+
+ Miniport->Timeout = FALSE;
+
+ if (!Miniport->ProcessingDeferred) {
+
+ MiniportProcessDeferred(Miniport);
+ }
+}
+
+
+VOID
+NdisMSetInformationComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ This function indicates the completion of a set information operation.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+ Status - Status of the operation
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_REQUEST Request;
+ PNDIS_M_OPEN_BLOCK Open;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+ LOUD_DEBUG(DbgPrint("NdisM: Enter set information complete\n");)
+
+ //
+ // Remove request.
+ //
+
+ Miniport->Timeout = FALSE;
+
+ if (Miniport->MiniportRequest == NULL) {
+
+ //
+ // Assume this is a complete that was aborted due to the wake up dpc
+ //
+ return;
+
+ }
+
+ Request = Miniport->MiniportRequest;
+ Miniport->MiniportRequest = NULL;
+
+ LOUD_DEBUG(DbgPrint("NdisM: Request 0x%x\n", Request);)
+
+ Open = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open;
+
+ if (Request != &(Miniport->InternalRequest)) {
+
+ //
+ // Indicate to Protocol;
+ //
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.RequestCompleteHandler) (
+ Open->ProtocolBindingContext,
+ Request,
+ Status
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ Open->References--;
+
+ if (Open->References == 0) {
+
+ FinishClose(Miniport,Open);
+
+ }
+
+ } else if (Request->RequestType == NdisRequestQueryStatistics) {
+
+ //
+ // Flag meaning that we need to set the request event
+ //
+ Miniport->RequestStatus = Status;
+ KeSetEvent(
+ &Miniport->RequestEvent,
+ 0L,
+ FALSE
+ );
+
+ } else if ((Open != NULL) && (Open->Closing)) {
+
+ Open->References--;
+
+ if (Open->References == 0) {
+
+ FinishClose(Miniport,Open);
+
+ }
+
+ } else {
+
+ //
+ // Internal request, check if we need to do more work now.
+ //
+ if ((Miniport->NeedToUpdateEthAddresses ||
+ Miniport->NeedToUpdatePacketFilter ||
+ Miniport->NeedToUpdateFunctionalAddress ||
+ Miniport->NeedToUpdateGroupAddress ||
+ Miniport->NeedToUpdateFddiLongAddresses ||
+ Miniport->NeedToUpdateFddiShortAddresses ||
+ (Miniport->FirstPendingRequest != NULL))
+ &&
+ (Miniport->MiniportRequest == NULL)) {
+ Miniport->RunDoRequests = TRUE;
+ Miniport->ProcessOddDeferredStuff = TRUE;
+ } else {
+ Miniport->RunDoRequests = FALSE;
+ }
+
+
+ }
+
+ if (!Miniport->ProcessingDeferred) {
+
+ MiniportProcessDeferred(Miniport);
+
+ }
+ LOUD_DEBUG(DbgPrint("NdisM: Exit set information complete\n");)
+
+}
+
+
+VOID
+NdisMResetComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_STATUS Status,
+ IN BOOLEAN AddressingReset
+ )
+/*++
+
+Routine Description:
+
+ This function indicates the completion of a reset.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+ Status - Status of the reset.
+
+ AddressingReset - Do we have to submit a request to reload the address
+ information. This includes packet filter, and multicast/functional addresses.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ //
+ // Destroy all outstanding packets and requests.
+ //
+ AbortMiniportPacketsAndPending(Miniport);
+
+ //
+ // Check if we are going to have to reset the
+ // adapter again. This happens when we are doing
+ // the reset because of a ring failure.
+ //
+ if (Miniport->TrResetRing == 1) {
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ Miniport->TrResetRing = 0;
+
+ } else {
+
+ Miniport->TrResetRing = NDIS_MINIPORT_TR_RESET_TIMEOUT;
+
+ }
+
+ }
+
+ //
+ // Indicate to Protocols the reset is complete
+ //
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter reset complete\n");)
+
+ Open = Miniport->ResetInProgress;
+ Miniport->ResetInProgress = NULL;
+ Miniport->ProcessingDeferred = FALSE;
+
+ NdisMIndicateStatus(Miniport,
+ NDIS_STATUS_RESET_END,
+ &Status,
+ sizeof(Status)
+ );
+
+ NdisMIndicateStatusComplete(Miniport);
+
+ if ( Open != (PNDIS_M_OPEN_BLOCK) Miniport && Open != NULL ) {
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.ResetCompleteHandler) (
+ Open->ProtocolBindingContext,
+ Status
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ Open->References--;
+
+ if (Open->References == 0) {
+
+ FinishClose(Miniport,Open);
+ }
+ }
+
+ if (AddressingReset &&
+ (Status == NDIS_STATUS_SUCCESS) &&
+ ((Miniport->EthDB != NULL) ||
+ (Miniport->TrDB != NULL) ||
+ (Miniport->FddiDB != NULL) ||
+ (Miniport->ArcDB != NULL))) {
+
+
+ Miniport->NeedToUpdatePacketFilter = TRUE;
+ switch (Miniport->MediaType) {
+ case NdisMedium802_3:
+ Miniport->NeedToUpdateEthAddresses = TRUE;
+ break;
+ case NdisMedium802_5:
+ Miniport->NeedToUpdateFunctionalAddress = TRUE;
+ Miniport->NeedToUpdateGroupAddress = TRUE;
+ break;
+ case NdisMediumFddi:
+ Miniport->NeedToUpdateFddiLongAddresses = TRUE;
+ Miniport->NeedToUpdateFddiShortAddresses = TRUE;
+ break;
+ case NdisMediumArcnet878_2:
+ break;
+ }
+
+ Miniport->RunDoRequests = TRUE;
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+ }
+
+ if (!Miniport->ProcessingDeferred) {
+
+ MiniportProcessDeferred(Miniport);
+
+ }
+ LOUD_DEBUG(DbgPrint("NdisM: Exit reset complete\n");)
+
+}
+
+
+
+VOID
+NdisMTransferDataComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ )
+/*++
+
+Routine Description:
+
+ This function indicates the completion of a transfer data request.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+ Packet - The packet the data was copied into.
+
+ Status - Status of the operation.
+
+ BytesTransferred - Total number of bytes transferred.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+ PNDIS_PACKET PrevPacket;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+ ASSERT(Miniport->FirstTDPacket != NULL);
+
+ //
+ // Find the packet
+ //
+
+ if (Packet == Miniport->FirstTDPacket) {
+
+ Miniport->FirstTDPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next;
+
+ } else {
+
+ PrevPacket = Miniport->FirstTDPacket;
+
+ while (PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next != Packet) {
+
+ PrevPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next;
+
+ ASSERT(PrevPacket != NULL);
+ }
+
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next =
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next;
+
+ if (Packet == Miniport->LastTDPacket) {
+
+ Miniport->LastTDPacket = PrevPacket;
+
+ }
+
+ }
+
+ //
+ // Indicate to Protocol;
+ //
+
+ Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Open;
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.TransferDataCompleteHandler) (
+ Open->ProtocolBindingContext,
+ Packet,
+ Status,
+ BytesTransferred
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+}
+
+
+
+VOID
+NdisMQueryInformationComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ This function indicates the completion of a query information operation.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+ Status - Status of the operation
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_REQUEST Request;
+ PNDIS_M_OPEN_BLOCK Open;
+ PNDIS_REQUEST_RESERVED Reserved;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+ LOUD_DEBUG(DbgPrint("NdisM: Enter query information complete\n");)
+
+ //
+ // Check for global statistics request
+ //
+ Miniport->Timeout = FALSE;
+
+ if (Miniport->MiniportRequest == NULL)
+ {
+ //
+ // Assume this is a complete that was aborted due to the wake up dpc
+ //
+ return;
+ }
+
+ //
+ // Get the request that was completed.
+ //
+ Request = Miniport->MiniportRequest;
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request);
+ Miniport->MiniportRequest = NULL;
+
+ if (Request->RequestType == NdisRequestQueryStatistics)
+ {
+ PNDIS_QUERY_GLOBAL_REQUEST GlobalRequest;
+ PNDIS_QUERY_ALL_REQUEST AllRequest;
+ PNDIS_QUERY_OPEN_REQUEST OpenRequest;
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+
+ GlobalRequest = CONTAINING_RECORD (Request,
+ NDIS_QUERY_GLOBAL_REQUEST,
+ Request
+ );
+ Irp = GlobalRequest->Irp;
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ switch (IrpSp->MajorFunction) {
+
+ case IRP_MJ_CREATE:
+
+ //
+ // This request is one of the ones made during an open,
+ // while we are trying to determine the OID list. We
+ // set the event we are waiting for, the open code
+ // takes care of the rest.
+ //
+
+ OpenRequest = (PNDIS_QUERY_OPEN_REQUEST)GlobalRequest;
+
+ OpenRequest->NdisStatus = Status;
+ KeSetEvent(
+ &OpenRequest->Event,
+ 0L,
+ FALSE);
+
+ break;
+
+ case IRP_MJ_DEVICE_CONTROL:
+
+ //
+ // This is a real user request, process it as such.
+ //
+
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
+
+ case IOCTL_NDIS_QUERY_GLOBAL_STATS:
+
+ //
+ // A single query, complete the IRP.
+ //
+
+ Irp->IoStatus.Information =
+ Request->DATA.QUERY_INFORMATION.BytesWritten;
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ } else if (Status == NDIS_STATUS_INVALID_LENGTH) {
+ Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
+ } else {
+ Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; // BUGBUG
+ }
+
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ ExFreePool (GlobalRequest);
+ break;
+
+ case IOCTL_NDIS_QUERY_ALL_STATS:
+
+ //
+ // An "all" query.
+ //
+
+ AllRequest = (PNDIS_QUERY_ALL_REQUEST)GlobalRequest;
+
+ AllRequest->NdisStatus = Status;
+ KeSetEvent(
+ &AllRequest->Event,
+ 0L,
+ FALSE);
+
+ break;
+
+ }
+
+ break;
+
+ }
+
+ if (!Miniport->ProcessingDeferred) {
+
+ MiniportProcessDeferred(Miniport);
+
+ }
+ LOUD_DEBUG(DbgPrint("NdisM: Exit qeury information complete\n");)
+ return;
+
+ }
+
+ //
+ // Remove request.
+ //
+ LOUD_DEBUG(DbgPrint("NdisM: Request 0x%x\n", Request);)
+
+ //
+ // Was this an internal request?
+ //
+ if (Request == &(Miniport->InternalRequest))
+ {
+ Miniport->RequestStatus = Status;
+ KeSetEvent(
+ &Miniport->RequestEvent,
+ 0L,
+ FALSE
+ );
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit qeury information complete\n");)
+ return;
+ }
+
+ //
+ // If the request is OID_GEN_SUPPORTED_LIST
+ //
+ if (OID_GEN_SUPPORTED_LIST == Request->DATA.QUERY_INFORMATION.Oid)
+ {
+ ULONG cbDestination;
+ PNDIS_REQUEST pFakeRequest;
+ PNDIS_REQUEST_RESERVED pFakeReserved;
+
+ //
+ // Restore the original request.
+ //
+ pFakeRequest = Request;
+ pFakeReserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(pFakeRequest);
+ Request = pFakeReserved->Next;
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request);
+
+ //
+ // If the request succeeded then filter out the statistics oids.
+ // Otherwise pass the relevant information back to the protocol.
+ //
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ //
+ // There was an error....
+ //
+ Request->DATA.QUERY_INFORMATION.BytesWritten =
+ pFakeRequest->DATA.QUERY_INFORMATION.BytesWritten;
+ Request->DATA.QUERY_INFORMATION.BytesNeeded =
+ pFakeRequest->DATA.QUERY_INFORMATION.BytesNeeded;
+ }
+ else
+ {
+ //
+ // Size of the request originators buffer.
+ //
+ cbDestination =
+ Request->DATA.QUERY_INFORMATION.InformationBufferLength;
+
+ //
+ // Do the OID fix ups.
+ //
+ Status = FilterOutOidStatistics(
+ Miniport,
+ Request,
+ Request->DATA.QUERY_INFORMATION.InformationBuffer,
+ &cbDestination,
+ pFakeRequest->DATA.QUERY_INFORMATION.InformationBuffer,
+ pFakeRequest->DATA.QUERY_INFORMATION.BytesWritten
+ );
+ if (NDIS_STATUS_BUFFER_TOO_SHORT == Status)
+ {
+ //
+ // Save the size needed with the original request.
+ //
+ Request->DATA.QUERY_INFORMATION.BytesNeeded = cbDestination;
+ Request->DATA.QUERY_INFORMATION.BytesWritten = 0;
+ }
+ else
+ {
+ //
+ // Save the bytes written with the original request.
+ //
+ Request->DATA.QUERY_INFORMATION.BytesNeeded = 0;
+ Request->DATA.QUERY_INFORMATION.BytesWritten = cbDestination;
+ }
+
+ //
+ // Free the allocated resources.
+ //
+ ExFreePool(pFakeRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+ ExFreePool(pFakeRequest);
+ }
+
+ //
+ // Fall through to protocol indication.
+ //
+ }
+
+ //
+ // Indicate to Protocol;
+ //
+ Open = Reserved->Open;
+
+ LOUD_DEBUG(DbgPrint("NdisM: Open 0x%x\n", Open);)
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.RequestCompleteHandler)(
+ Open->ProtocolBindingContext,
+ Request,
+ Status
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ Open->References--;
+
+ if (Open->References == 0)
+ {
+ FinishClose(Miniport,Open);
+ }
+
+ if (!Miniport->ProcessingDeferred)
+ {
+ MiniportProcessDeferred(Miniport);
+ }
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit query information complete\n");)
+}
+
+NDIS_STATUS
+NdisMRegisterMiniport(
+ IN NDIS_HANDLE NdisWrapperHandle,
+ IN PNDIS_MINIPORT_CHARACTERISTICS MiniportCharacteristics,
+ IN UINT CharacteristicsLength
+ )
+
+/*++
+
+Routine Description:
+
+ Used to register a Miniport driver with the wrapper.
+
+Arguments:
+
+ Status - Status of the operation.
+
+ NdisWrapperHandle - Handle returned by NdisWInitializeWrapper.
+
+ MiniportCharacteritics - The NDIS_MINIPORT_CHARACTERISTICS table.
+
+ CharacteristicsLength - The length of MiniportCharacteristics.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_M_DRIVER_BLOCK WDriver;
+ PNDIS_WRAPPER_HANDLE DriverInfo = (PNDIS_WRAPPER_HANDLE)(NdisWrapperHandle);
+ UINT MemNeeded;
+ UINT charLength;
+ NDIS_STATUS Status;
+
+ //
+ // Do any initial initialization that may be necessary. Note: this
+ // routine will notice if this is the second or later call to it.
+ //
+ Status = NdisInitialInit( DriverInfo->NdisWrapperDriver );
+ if (!NT_SUCCESS(Status)) {
+ return Status;
+ }
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter mini-port register\n");)
+
+ if (DriverInfo == NULL) {
+
+ return NDIS_STATUS_FAILURE;
+
+
+ }
+
+ if (MiniportCharacteristics->MajorNdisVersion != 3 ||
+ MiniportCharacteristics->MinorNdisVersion != 0) {
+
+ return NDIS_STATUS_BAD_VERSION;
+ }
+
+ //
+ // Check that CharacteristicsLength is enough.
+ //
+
+ charLength = sizeof(NDIS_MINIPORT_CHARACTERISTICS);
+ if (CharacteristicsLength < charLength) {
+ return NDIS_STATUS_BAD_CHARACTERISTICS;
+ }
+
+ //
+ // Allocate memory for the NDIS MINIPORT block.
+ //
+ MemNeeded = sizeof(NDIS_M_DRIVER_BLOCK);
+
+ WDriver = (PNDIS_M_DRIVER_BLOCK)ExAllocatePool(NonPagedPool, MemNeeded);
+
+ if (WDriver == (PNDIS_M_DRIVER_BLOCK)NULL) {
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ NdisZeroMemory(WDriver, MemNeeded);
+
+ WDriver->Length = MemNeeded;
+
+
+ //
+ // Copy over the characteristics table.
+ //
+
+ RtlMoveMemory((PVOID)&WDriver->MiniportCharacteristics,
+ (PVOID)MiniportCharacteristics, charLength);
+
+ //
+ // No adapters yet registered for this Miniport.
+ //
+
+ WDriver->MiniportQueue = (PNDIS_MINIPORT_BLOCK)NULL;
+
+ //
+ // Set up unload handler
+ //
+
+ DriverInfo->NdisWrapperDriver->DriverUnload = NdisMUnload;
+
+ //
+ // Set up shutdown handler
+ //
+ DriverInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_SHUTDOWN] = NdisMShutdown;
+
+ //
+ // Set up the handlers for this driver (they all do nothing).
+ //
+
+ DriverInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_CREATE] = NdisCreateIrpHandler;
+ DriverInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = NdisDeviceControlIrpHandler;
+ DriverInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_CLEANUP] = NdisSuccessIrpHandler;
+ DriverInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_CLOSE] = NdisCloseIrpHandler;
+
+ //
+ // Put Driver on global list.
+ //
+
+ ACQUIRE_SPIN_LOCK(&NdisDriverListLock);
+
+ WDriver->NextDriver = NdisDriverList;
+ NdisDriverList = WDriver;
+
+ RELEASE_SPIN_LOCK(&NdisDriverListLock);
+
+ //
+ // Use this event to tell us when all adapters are removed from the mac
+ // during an unload
+ //
+
+ KeInitializeEvent(
+ &WDriver->MiniportsRemovedEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ WDriver->Unloading = FALSE;
+ WDriver->NdisDriverInfo = DriverInfo;
+ WDriver->MiniportIdField = (NDIS_HANDLE)0x1;
+
+ NdisInitializeRef(&WDriver->Ref);
+ NdisInitReferencePackage();
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit mini-port register\n");)
+
+ if (DriverInfo->NdisWrapperConfigurationHandle) {
+
+ if (NdisCallDriverAddAdapter((PNDIS_MAC_BLOCK)WDriver) == NDIS_STATUS_SUCCESS) {
+
+ NdisInitDereferencePackage();
+ return NDIS_STATUS_SUCCESS;
+ } else {
+ NdisDereferenceDriver(WDriver);
+ NdisInitDereferencePackage();
+ return NDIS_STATUS_FAILURE;
+ }
+ } else {
+ NdisInitDereferencePackage();
+ return NDIS_STATUS_FAILURE;
+ }
+
+}
+
+//
+// Protocol entry points
+//
+NDIS_STATUS FASTCALL MiniportSyncSend(
+ PNDIS_MINIPORT_BLOCK Miniport,
+ PNDIS_PACKET Packet
+)
+
+/*++
+
+Routine Description:
+
+ Submits an immediate send to a miniport. The miniport has
+ the send on the pending queue, and it is the only element on the send
+ queue. This routine is also called with the lock held.
+
+Arguments:
+
+ Miniport - Miniport to send to.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PARC_BUFFER_LIST Buffer;
+ PARC_BUFFER_LIST ArcTmpBuffer;
+ PNDIS_BUFFER NdisBuffer;
+ PNDIS_BUFFER TmpBuffer;
+ PNDIS_PACKET PrevPacket;
+ NDIS_STATUS Status;
+ PNDIS_PACKET_RESERVED Reserved;
+ PNDIS_M_OPEN_BLOCK Open;
+ UINT Flags;
+ PVOID BufferVa;
+ PUCHAR Address;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter Sync send.\n");)
+
+ LOG('+');
+ NDIS_LOG_PACKET(Miniport, Packet, '+');
+
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ Open = Reserved->Open;
+
+ if (Miniport->MediaType == NdisMediumArcnet878_2)
+ goto BuildArcnetHeader;
+
+DoneBuildingArcnetHeader:
+
+ //
+ // Remove from Queue
+ //
+ Miniport->FirstPendingPacket = Reserved->Next;
+
+ //
+ // Put on finish queue
+ //
+ PrevPacket = Miniport->LastMiniportPacket;
+ Miniport->LastMiniportPacket = Packet;
+ Miniport->SendCompleteCalled = FALSE;
+
+ //
+ // Indicate the packet loopback if necessary.
+ //
+ if ((Miniport->MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK) &&
+ MiniportSendLoopback(Miniport, Packet)
+ )
+ {
+ LOUD_DEBUG(DbgPrint("NdisM: Not sending packet 0x%x\n", Packet);)
+
+ LOG('l');
+ NDIS_LOG_PACKET(Miniport, Packet, 'l');
+
+ Status = NDIS_STATUS_SUCCESS;
+ goto SyncNoCardSend;
+ }
+
+ //
+ // Submit to card
+ //
+ LOUD_DEBUG(DbgPrint("NdisM: Sending packet 0x%x\n", Packet);)
+
+ REMOVE_RESOURCE(Miniport, 'S');
+
+ NdisQuerySendFlags(Packet, &Flags);
+
+ LOG('M');
+
+ NDIS_LOG_PACKET(Miniport, Packet, 'M');
+
+ Status = (Open->SendHandler)(
+ Open->MiniportAdapterContext,
+ Packet,
+ Flags
+ );
+ if (Status == NDIS_STATUS_PENDING)
+ {
+ LOG('p');
+ NDIS_LOG_PACKET(Miniport, Packet, 'p');
+
+ LOUD_DEBUG(DbgPrint("NdisM: Complete sync send is pending\n");)
+
+ return(Status);
+ }
+
+SyncNoCardSend:
+
+ if (Miniport->MediaType == NdisMediumArcnet878_2)
+ MiniportFreeArcnetHeader(Miniport, Packet);
+
+ if (Status != NDIS_STATUS_RESOURCES)
+ {
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ ADD_RESOURCE(Miniport, 'F');
+
+ LOG('F');
+ NDIS_LOG_PACKET(Miniport, Packet, 'F');
+ }
+
+ //
+ // Remove from finish queue
+ //
+ LOUD_DEBUG(DbgPrint("NdisM: Completed 0x%x\n", Status);)
+
+ //
+ // If send complete was called from the miniport's send handler
+ // then our local PrevPacket pointer may no longer be valid....
+ //
+ MiniportFindPacket(Miniport, Packet, &PrevPacket);
+
+ Miniport->LastMiniportPacket = PrevPacket;
+
+ if (PrevPacket == NULL)
+ {
+ Miniport->FirstPacket = Reserved->Next;
+ Miniport->DeadPacket = NULL;
+ }
+ else
+ {
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next = Reserved->Next;
+
+ if ( Packet == Miniport->LastPacket ) {
+
+ Miniport->LastPacket = PrevPacket;
+ }
+ }
+
+ Open->References--;
+
+ if (Open->References == 0)
+ FinishClose(Miniport, Open);
+
+ NDIS_LOG_PACKET(Miniport, Packet, 'C');
+ return(Status);
+ }
+
+ // Status == NDIS_STATUS_RESOURCES!!!!
+
+ LOUD_DEBUG(DbgPrint("NdisM: Deferring send\n");)
+
+ //
+ // If send complete was called from the miniport's send handler
+ // then our local PrevPacket pointer may no longer be valid.
+ //
+ MiniportFindPacket(Miniport, Packet, &PrevPacket);
+
+ //
+ // Remove from finish queue
+ //
+ Miniport->LastMiniportPacket = PrevPacket;
+
+ //
+ // Put on pending queue
+ //
+ Miniport->FirstPendingPacket = Packet;
+
+ //
+ // Mark the packet at the head of the pending queue as having
+ // been looped back.
+ //
+ Miniport->AlreadyLoopedBack = TRUE;
+
+ LOG('o');
+ NDIS_LOG_PACKET(Miniport, Packet, 'o');
+
+ //
+ // Set flag
+ //
+ CLEAR_RESOURCE(Miniport, 'S');
+
+ return(NDIS_STATUS_PENDING);
+
+BuildArcnetHeader:
+
+ if (Open->UsingEthEncapsulation)
+ {
+ if (Miniport->ArcnetFreeBufferList == NULL)
+ {
+ //
+ // Set flag
+ //
+ CLEAR_RESOURCE(Miniport, 'S');
+ return(NDIS_STATUS_PENDING);
+ }
+
+ NdisQueryPacket(Packet, NULL, NULL, &TmpBuffer, NULL);
+ NdisQueryBuffer(TmpBuffer, &Address, &Flags);
+
+ Buffer = Miniport->ArcnetFreeBufferList;
+ Miniport->ArcnetFreeBufferList = Buffer->Next;
+
+ NdisAllocateBuffer(
+ &Status,
+ &NdisBuffer,
+ Miniport->ArcnetBufferPool,
+ Buffer->Buffer,
+ 3
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ Buffer->Next = Miniport->ArcnetFreeBufferList;
+ Miniport->ArcnetFreeBufferList = Buffer;
+ CLEAR_RESOURCE(Miniport, 'S');
+ return(NDIS_STATUS_PENDING);
+ }
+
+ Buffer->Next = Miniport->ArcnetUsedBufferList;
+ Miniport->ArcnetUsedBufferList = Buffer;
+
+ NdisChainBufferAtFront(Packet, NdisBuffer);
+
+ ((PUCHAR)Buffer->Buffer)[0] = Miniport->ArcnetAddress;
+
+ if (Address[0] & 0x01)
+ {
+ //
+ // Broadcast
+ //
+ ((PUCHAR)Buffer->Buffer)[1] = 0x00;
+ }
+ else
+ {
+ ((PUCHAR)Buffer->Buffer)[1] = Address[5];
+ }
+
+ ((PUCHAR)Buffer->Buffer)[2] = 0xE8;
+ }
+
+ goto DoneBuildingArcnetHeader;
+}
+
+
+
+NDIS_STATUS NdisMSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+)
+{
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ PNDIS_PACKET_RESERVED Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ BOOLEAN LocalLock;
+ KIRQL OldIrql;
+ BOOLEAN FirstSend = FALSE;
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_PENDING;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ if (!Miniport->HaltingMiniport)
+ {
+ NDIS_LOG_PACKET(Miniport, Packet, 'w');
+
+ ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++;
+
+ //
+ // Handle protocol requests
+ //
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ Reserved->Next = NULL;
+ Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+
+ if ( Miniport->FirstPacket == NULL )
+ {
+ Miniport->FirstPacket = Packet;
+ Miniport->DeadPacket = NULL;
+ }
+ else
+ {
+#if DBG
+ {
+ PNDIS_PACKET p;
+
+ for (p = Miniport->FirstPacket; p != NULL; p = PNDIS_RESERVED_FROM_PNDIS_PACKET(p)->Next)
+ {
+ if (Packet == p)
+ {
+ DbgBreakPoint();
+ }
+ }
+ }
+#endif
+
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = Packet;
+ }
+
+ Miniport->LastPacket = Packet;
+
+ //
+ // Initialize some variables.
+ //
+ FirstSend = FALSE;
+ StatusToReturn = NDIS_STATUS_PENDING;
+
+ if (Miniport->FirstPendingPacket == NULL)
+ {
+ FirstSend = TRUE;
+ Miniport->FirstPendingPacket = Packet;
+ Miniport->AlreadyLoopedBack = FALSE;
+ }
+
+ if (LocalLock)
+ {
+ //
+ // If we did not lock down the mini-port, then some other routine will
+ // do this processing for us. Otherwise we need to do this processing.
+ //
+ if (!Miniport->ProcessingDeferred)
+ {
+ Miniport->ProcessingDeferred = TRUE;
+
+ if (FirstSend &&
+ !(Miniport->RunTimer ||
+ Miniport->HaltingMiniport ||
+ Miniport->ResetRequested ||
+ Miniport->ResetInProgress ||
+ Miniport->RunDoRequests ||
+ Miniport->ProcessOddDeferredStuff)
+ )
+ {
+ //
+ // There aren't any pending sends, we are not processing
+ // odd deferred stuff (i.e. we are obeying the priority
+ // in processdeferred, and we have the lock. If all is
+ // not perfect we will defer and try again later.)
+ //
+ StatusToReturn = MiniportSyncSend(Miniport, Packet);
+ Miniport->ProcessingDeferred = FALSE;
+ }
+ else
+ {
+ MiniportProcessDeferred(Miniport);
+ }
+ }
+ }
+
+ NDIS_LOG_PACKET(Miniport, Packet, 'W');
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ return(StatusToReturn);
+ }
+ else
+ {
+ NDIS_LOG_PACKET(Miniport, Packet, 'F');
+ NDIS_LOG_PACKET(Miniport, Packet, 'W');
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ return(NDIS_STATUS_FAILURE);
+ }
+}
+
+typedef
+NDIS_STATUS
+(*PNDIS_M_WAN_SEND) (
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE NdisLinkHandle,
+ IN PVOID Packet
+ );
+
+//
+// Protocol entry point for WAN miniport
+//
+
+NDIS_STATUS
+NdisMWanSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE NdisLinkHandle,
+ IN PVOID Packet
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ BOOLEAN LocalLock;
+ KIRQL OldIrql;
+ NDIS_STATUS Status;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Call MAC to send WAN packet
+ //
+
+ Status=
+ ((PNDIS_M_WAN_SEND)(Miniport->DriverHandle->MiniportCharacteristics.SendHandler)) (
+ Miniport->MiniportAdapterContext,
+ NdisLinkHandle,
+ Packet);
+
+ if (LocalLock) {
+
+ //
+ // Process any changes that may have occured.
+ //
+
+ if (!Miniport->ProcessingDeferred) {
+ MiniportProcessDeferred(Miniport);
+ }
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+ return(Status);
+}
+
+
+NDIS_STATUS
+NdisMTransferDataSync(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ PNDIS_PACKET_RESERVED Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+ ASSERT((Miniport->MacOptions & NDIS_MAC_OPTION_TRANSFERS_NOT_PEND) != 0);
+
+ //
+ // Handle non-loopback as the default case.
+ //
+
+ if (Miniport->LoopbackPacket == NULL) {
+
+ Reserved->Next = NULL;
+ Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+
+ //
+ // Call Miniport.
+ //
+
+ Status =
+ (Reserved->Open->TransferDataHandler)(
+ Packet,
+ BytesTransferred,
+ Reserved->Open->MiniportAdapterContext,
+ MacReceiveContext,
+ ByteOffset,
+ BytesToTransfer
+ );
+
+ //
+ // This miniport better not pend this send.
+ //
+
+ ASSERT(Status != NDIS_STATUS_PENDING);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ return Status;
+ }
+
+ //
+ // This packet is a loopback packet!
+ //
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ NdisCopyFromPacketToPacket(
+ Packet,
+ 0,
+ BytesToTransfer,
+ Miniport->LoopbackPacket,
+ ByteOffset + Miniport->LoopbackPacketHeaderSize,
+ BytesTransferred
+ );
+
+ if ( *BytesTransferred == BytesToTransfer ) {
+
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ return NDIS_STATUS_FAILURE;
+}
+
+NDIS_STATUS
+NdisMTransferData(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ PNDIS_PACKET_RESERVED Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ PNDIS_PACKET PrevLast;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ //
+ // Handle non-loopback as the default case.
+ //
+
+ if (Miniport->LoopbackPacket == NULL) {
+
+ Reserved->Next = NULL;
+ Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+
+ //
+ // Put this guy on the transfer data queue.
+ //
+
+ PrevLast = Miniport->LastTDPacket;
+
+ if (Miniport->FirstTDPacket == NULL) {
+
+ Miniport->FirstTDPacket = Packet;
+
+ } else {
+
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastTDPacket)->Next = Packet;
+ }
+
+ Miniport->LastTDPacket = Packet;
+
+ //
+ // Call Miniport
+ //
+
+ Status =
+ (Reserved->Open->TransferDataHandler)(
+ Packet,
+ BytesTransferred,
+ Reserved->Open->MiniportAdapterContext,
+ MacReceiveContext,
+ ByteOffset,
+ BytesToTransfer
+ );
+
+ //
+ // If it didn't pend then we won't get a transfer data complte call
+ // so we need to remove this guy now.
+ //
+
+ if ( Status != NDIS_STATUS_PENDING ) {
+
+ //
+ // Remove from queue
+ //
+
+ if (Miniport->FirstTDPacket != Packet) {
+
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevLast)->Next = NULL;
+ Miniport->LastTDPacket = PrevLast;
+
+ } else {
+
+ Miniport->FirstTDPacket = NULL;
+ Miniport->LastTDPacket = NULL;
+
+ }
+ }
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ return Status;
+ }
+
+ //
+ // This packet is a loopback packet!
+ //
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ NdisCopyFromPacketToPacket(
+ Packet,
+ 0,
+ BytesToTransfer,
+ Miniport->LoopbackPacket,
+ ByteOffset + Miniport->LoopbackPacketHeaderSize,
+ BytesTransferred
+ );
+
+ if ( *BytesTransferred == BytesToTransfer ) {
+
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ return NDIS_STATUS_FAILURE;
+}
+
+NDIS_STATUS
+NdisMReset(
+ IN NDIS_HANDLE NdisBindingHandle
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ BOOLEAN LocalLock;
+ KIRQL OldIrql;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ if (Miniport->HaltingMiniport) {
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ return(NDIS_STATUS_FAILURE);
+
+ }
+
+ Miniport->ResetRequested = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+ ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++;
+
+ if (LocalLock) {
+
+ //
+ // If we did not lock down the mini-port, then some other routine will
+ // do this processing for us. Otherwise we need to do this processing.
+ //
+ if (!Miniport->ProcessingDeferred) {
+
+ MiniportProcessDeferred(Miniport);
+
+ }
+
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ return(NDIS_STATUS_PENDING);
+}
+
+
+NDIS_STATUS
+NdisMRequest(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ PNDIS_REQUEST_RESERVED Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(NdisRequest);
+ BOOLEAN LocalLock;
+ KIRQL OldIrql;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ if (Miniport->HaltingMiniport) {
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ return(NDIS_STATUS_FAILURE);
+
+ }
+
+ LOUD_DEBUG(DbgPrint("NdisM: Got request 0x%x\n",NdisRequest);)
+
+ //
+ // Handle protocol requests
+ //
+
+ Reserved->Next = NULL;
+ Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+ ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++;
+
+ if (Miniport->FirstPendingRequest == NULL) {
+
+ Miniport->FirstPendingRequest = NdisRequest;
+
+ } else {
+
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Miniport->LastPendingRequest)->Next = NdisRequest;
+
+ }
+
+ Miniport->LastPendingRequest = NdisRequest;
+
+ if (Miniport->MiniportRequest == NULL)
+ {
+ Miniport->RunDoRequests = TRUE;
+ Miniport->ProcessOddDeferredStuff = TRUE;
+ }
+
+ if (LocalLock)
+ {
+ //
+ // If we did not lock down the mini-port, then some other routine will
+ // do this processing for us. Otherwise we need to do this processing.
+ //
+ if (!Miniport->ProcessingDeferred) {
+
+ MiniportProcessDeferred(Miniport);
+
+ }
+
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ return (NDIS_STATUS_PENDING);
+}
+
+
+NDIS_STATUS
+NdisMMapIoSpace(
+ OUT PVOID * VirtualAddress,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress,
+ IN UINT Length
+ )
+{
+ NDIS_STATUS Status;
+ NdisMapIoSpace(&Status,
+ VirtualAddress,
+ MiniportAdapterHandle,
+ PhysicalAddress,
+ Length
+ );
+ return(Status);
+}
+
+
+VOID
+NdisMUnmapIoSpace(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PVOID VirtualAddress,
+ IN UINT Length
+ )
+{
+
+#ifdef _ALPHA_
+
+#else
+ MmUnmapIoSpace(VirtualAddress, Length);
+#endif
+
+}
+
+
+NDIS_STATUS
+NdisMRegisterInterrupt(
+ OUT PNDIS_MINIPORT_INTERRUPT Interrupt,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN UINT InterruptVector,
+ IN UINT InterruptLevel,
+ IN BOOLEAN RequestIsr,
+ IN BOOLEAN SharedInterrupt,
+ IN NDIS_INTERRUPT_MODE InterruptMode
+ )
+{
+ NDIS_STATUS Status;
+ NdisInitializeInterrupt(&Status,
+ (PNDIS_INTERRUPT)Interrupt,
+ MiniportAdapterHandle,
+ NULL,
+ NULL,
+ (PNDIS_DEFERRED_PROCESSING)RequestIsr,
+ InterruptVector,
+ InterruptLevel,
+ SharedInterrupt,
+ InterruptMode
+ );
+
+ return(Status);
+}
+
+
+VOID
+NdisMDeregisterInterrupt(
+ IN PNDIS_MINIPORT_INTERRUPT Interrupt
+ )
+{
+ NdisRemoveInterrupt((PNDIS_INTERRUPT)Interrupt);
+}
+
+
+BOOLEAN
+NdisMSynchronizeWithInterrupt(
+ IN PNDIS_MINIPORT_INTERRUPT Interrupt,
+ IN PVOID SynchronizeFunction,
+ IN PVOID SynchronizeContext
+ )
+{
+ return (KeSynchronizeExecution(
+ (Interrupt)->InterruptObject,
+ (PKSYNCHRONIZE_ROUTINE)SynchronizeFunction,
+ SynchronizeContext
+ )
+ );
+}
+
+
+
+VOID
+NdisMAllocateSharedMemory(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN ULONG Length,
+ IN BOOLEAN Cached,
+ OUT PVOID *VirtualAddress,
+ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress
+ )
+{
+ //
+ // Convert the handle to our internal structure.
+ //
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportAdapterHandle;
+
+ if (Miniport->SystemAdapterObject == NULL) {
+
+ *VirtualAddress = NULL;
+ return;
+
+ }
+
+ NdisAllocateSharedMemory(MiniportAdapterHandle,
+ Length,
+ Cached,
+ VirtualAddress,
+ PhysicalAddress
+ );
+}
+
+VOID
+NdisMFreeSharedMemory(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN ULONG Length,
+ IN BOOLEAN Cached,
+ IN PVOID VirtualAddress,
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress
+ )
+{
+ NdisFreeSharedMemory(MiniportAdapterHandle,
+ Length,
+ Cached,
+ VirtualAddress,
+ PhysicalAddress);
+}
+
+
+
+NDIS_STATUS
+NdisMRegisterDmaChannel(
+ OUT PNDIS_HANDLE MiniportDmaHandle,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN UINT DmaChannel,
+ IN BOOLEAN Dma32BitAddresses,
+ IN PNDIS_DMA_DESCRIPTION DmaDescription,
+ IN ULONG MaximumLength
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(MiniportAdapterHandle);
+ NDIS_STATUS Status;
+ Miniport->ChannelNumber = (DmaChannel);
+ Miniport->Dma32BitAddresses = (Dma32BitAddresses);
+ NdisAllocateDmaChannel(&Status,
+ MiniportDmaHandle,
+ (NDIS_HANDLE)Miniport,
+ DmaDescription,
+ MaximumLength
+ );
+ return(Status);
+}
+
+
+
+VOID
+NdisMDeregisterDmaChannel(
+ IN PNDIS_HANDLE MiniportDmaHandle
+ )
+{
+ NdisFreeDmaChannel(MiniportDmaHandle);
+}
+
+
+VOID
+HaltOneMiniport(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Does all the clean up for a mini-port.
+
+Arguments:
+
+ Miniport - pointer to the mini-port to halt
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ BOOLEAN LocalLock;
+ BOOLEAN Canceled;
+ KIRQL OldIrql;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ while (Miniport->LockAcquired) {
+
+ //
+ // This can only happen on an MP system. We must now
+ // wait for the other processor to exit the mini-port.
+ //
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ NdisStallExecution(1000);
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ }
+
+ //
+ // Lock mini-port so that nothing will enter it.
+ //
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // We can now release safely
+ //
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ NdisCancelTimer(&Miniport->WakeUpDpcTimer, &Canceled);
+
+ if (!Canceled) {
+
+ NdisStallExecution(500000);
+ }
+
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler)(
+ Miniport->MiniportAdapterContext
+ );
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ AbortMiniportPacketsAndPending(Miniport);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ //
+ // If a shutdown handler was registered then deregister it.
+ //
+
+ NdisMDeregisterAdapterShutdownHandler(Miniport);
+
+ NdisDereferenceMiniport(Miniport);
+ MiniportDereferencePackage();
+
+ return;
+
+}
+
+//
+// Arcnet support routines
+//
+
+VOID
+NdisMArcIndicateEthEncapsulatedReceive(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PVOID HeaderBuffer,
+ IN PVOID DataBuffer,
+ IN UINT Length
+ )
+/*++
+
+ HeaderBuffer - This is the 878.2 header.
+ DataBuffer - This is the 802.3 header.
+ Length - This is the length of the ethernet frame.
+
+--*/
+
+{
+ ULONG MacReceiveContext[2];
+
+ //
+ // Indicate the packet.
+ //
+
+ MacReceiveContext[0] = (ULONG) DataBuffer;
+ MacReceiveContext[1] = (ULONG) Length;
+
+ if (Length > 14) {
+
+ NdisMEthIndicateReceive(
+ (NDIS_HANDLE) Miniport, // miniport handle.
+ (NDIS_HANDLE) MacReceiveContext, // receive context.
+ DataBuffer, // ethernet header.
+ 14, // ethernet header length.
+ (PUCHAR)DataBuffer + 14, // ethernet data.
+ Length - 14, // ethernet data length.
+ Length - 14 // ethernet data length.
+ );
+
+ } else {
+
+ NdisMEthIndicateReceive(
+ (NDIS_HANDLE) Miniport, // miniport handle.
+ (NDIS_HANDLE) MacReceiveContext, // receive context.
+ DataBuffer, // ethernet header.
+ Length, // ethernet header length.
+ NULL, // ethernet data.
+ 0, // ethernet data length.
+ 0 // ethernet data length.
+ );
+ }
+}
+
+
+NDIS_STATUS
+NdisMArcTransferData(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET DstPacket,
+ OUT PUINT BytesTransferred
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the transfer data calls to arcnet mini-port.
+
+Arguments:
+
+ NdisBindingHandle - Pointer to open block.
+
+ MacReceiveContext - Context given for the indication
+
+ ByteOffset - Offset to start transfer at.
+
+ BytesToTransfer - Number of bytes to transfer
+
+ Packet - Packet to transfer into
+
+ BytesTransferred - the number of actual bytes copied
+
+Return values:
+
+ NDIS_STATUS_SUCCESS, if successful, else NDIS_STATUS_FAILURE.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PNDIS_M_OPEN_BLOCK MiniportOpen;
+ KIRQL OldIrql;
+ PNDIS_PACKET SrcPacket;
+ PNDIS_BUFFER NdisBuffer;
+ NDIS_STATUS Status;
+ NDIS_PACKET TempPacket;
+
+ MiniportOpen = (PNDIS_M_OPEN_BLOCK) NdisBindingHandle;
+ Miniport = MiniportOpen->MiniportHandle;
+ NdisBuffer = NULL;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ //
+ // If this is encapsulated ethernet then we don't currently
+ // have the source packet from which to copy from.
+ //
+
+ if ( MiniportOpen->UsingEthEncapsulation ) {
+
+ //
+ // If this is not loopback then we need to create a
+ // temp NDIS_PACKET for the packet-to-packet copy.
+ //
+
+ if ( !Miniport->LoopbackPacket ) {
+
+ PUCHAR DataBuffer = (PUCHAR) ((PULONG) MacReceiveContext)[0];
+ UINT DataLength = (UINT) ((PULONG) MacReceiveContext)[1];
+
+ //
+ // We'll always be in the scope of this function so we
+ // can use local stack space rather than allocating dynamic
+ // memory.
+ //
+
+ SrcPacket = &TempPacket; // Use the local stack for packet store.
+
+ NdisZeroMemory(
+ SrcPacket,
+ sizeof(NDIS_PACKET)
+ );
+
+ NdisAllocateBuffer(
+ &Status, // Status code.
+ &NdisBuffer, // NDIS buffer to chain onto the packet.
+ NULL, // On NT, this parameter is ignored.
+ DataBuffer, // The ethernet frame.
+ DataLength // The ethernet frame length.
+ );
+
+ NdisChainBufferAtFront(SrcPacket, NdisBuffer);
+
+ } else {
+
+ SrcPacket = Miniport->LoopbackPacket;
+
+ ByteOffset += 3; // Skip fake arcnet header.
+ }
+
+ //
+ // Skip the ethernet header.
+ //
+
+ ByteOffset += 14;
+
+ } else {
+
+ SrcPacket = (PNDIS_PACKET) MacReceiveContext;
+ }
+
+ //
+ // Now we can simply copy from the source packet to the
+ // destination packet.
+ //
+
+ NdisCopyFromPacketToPacket(
+ DstPacket, // destination packet.
+ 0, // destination offset.
+ BytesToTransfer, // bytes to copy.
+ SrcPacket, // source packet.
+ ByteOffset, // source offset.
+ BytesTransferred // bytes copied.
+ );
+
+ //
+ // If we allocated an NDIS_BUFFER then we need to free it. We don't
+ // need to unchain the buffer from the packet since the packet is
+ // a local stack variable the will just get trashed anyway.
+ //
+
+ if ( NdisBuffer != NULL ) {
+
+ NdisFreeBuffer(NdisBuffer);
+ }
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+VOID
+MiniportArcCopyFromBufferToPacket(
+ IN PCHAR Buffer,
+ IN UINT BytesToCopy,
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ OUT PUINT BytesCopied
+ )
+
+/*++
+
+Routine Description:
+
+ Copy from a buffer into an ndis packet.
+
+Arguments:
+
+ Buffer - The packet to copy from.
+
+ Offset - The offset from which to start the copy.
+
+ BytesToCopy - The number of bytes to copy from the buffer.
+
+ Packet - The destination of the copy.
+
+ BytesCopied - The number of bytes actually copied. Will be less
+ than BytesToCopy if the packet is not large enough.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ //
+ // Holds the count of the number of ndis buffers comprising the
+ // destination packet.
+ //
+ UINT DestinationBufferCount;
+
+ //
+ // Points to the buffer into which we are putting data.
+ //
+ PNDIS_BUFFER DestinationCurrentBuffer;
+
+ //
+ // Points to the location in Buffer from which we are extracting data.
+ //
+ PUCHAR SourceCurrentAddress;
+
+ //
+ // Holds the virtual address of the current destination buffer.
+ //
+ PVOID DestinationVirtualAddress;
+
+ //
+ // Holds the length of the current destination buffer.
+ //
+ UINT DestinationCurrentLength;
+
+ //
+ // Keep a local variable of BytesCopied so we aren't referencing
+ // through a pointer.
+ //
+ UINT LocalBytesCopied = 0;
+
+
+ //
+ // Take care of boundary condition of zero length copy.
+ //
+
+ *BytesCopied = 0;
+ if (!BytesToCopy) return;
+
+ //
+ // Get the first buffer of the destination.
+ //
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ &DestinationBufferCount,
+ &DestinationCurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet.
+ //
+
+ if (!DestinationBufferCount) return;
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+
+ //
+ // Set up the source address.
+ //
+
+ SourceCurrentAddress = Buffer;
+
+
+ while (LocalBytesCopied < BytesToCopy) {
+
+ //
+ // Check to see whether we've exhausted the current destination
+ // buffer. If so, move onto the next one.
+ //
+
+ if (!DestinationCurrentLength) {
+
+ NdisGetNextBuffer(
+ DestinationCurrentBuffer,
+ &DestinationCurrentBuffer
+ );
+
+ if (!DestinationCurrentBuffer) {
+
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.)
+ //
+
+ break;
+
+ }
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+
+ continue;
+
+ }
+
+ //
+ // Try to get us up to the point to start the copy.
+ //
+
+ if (Offset) {
+
+ if (Offset > DestinationCurrentLength) {
+
+ //
+ // What we want isn't in this buffer.
+ //
+
+ Offset -= DestinationCurrentLength;
+ DestinationCurrentLength = 0;
+ continue;
+
+ } else {
+
+ DestinationVirtualAddress = (PCHAR)DestinationVirtualAddress
+ + Offset;
+ DestinationCurrentLength -= Offset;
+ Offset = 0;
+
+ }
+
+ }
+
+
+ //
+ // Copy the data.
+ //
+
+ {
+
+ //
+ // Holds the amount of data to move.
+ //
+ UINT AmountToMove;
+
+ //
+ // Holds the amount desired remaining.
+ //
+ UINT Remaining = BytesToCopy - LocalBytesCopied;
+
+
+ AmountToMove = DestinationCurrentLength;
+
+ AmountToMove = ((Remaining < AmountToMove)?
+ (Remaining):(AmountToMove));
+
+ NdisMoveFromMappedMemory(
+ DestinationVirtualAddress,
+ SourceCurrentAddress,
+ AmountToMove
+ );
+
+ SourceCurrentAddress += AmountToMove;
+ LocalBytesCopied += AmountToMove;
+ DestinationCurrentLength -= AmountToMove;
+
+ }
+
+ }
+
+ *BytesCopied = LocalBytesCopied;
+
+
+}
+
+
+VOID
+NdisMCancelTimer(
+ IN PNDIS_MINIPORT_TIMER Timer,
+ OUT PBOOLEAN TimerCancelled
+ )
+/*++
+
+Routine Description:
+
+ Cancels a timer.
+
+Arguments:
+
+ Timer - The timer to cancel.
+
+ TimerCancelled - TRUE if the timer was canceled, else FALSE.
+
+Return Value:
+
+ None
+
+--*/
+{
+ *TimerCancelled = KeCancelTimer(&((((PNDIS_TIMER)(Timer))->Timer)));
+}
+
+
+ULONG
+NdisMReadDmaCounter(
+ IN NDIS_HANDLE MiniportDmaHandle
+ )
+/*++
+
+Routine Description:
+
+ Reads the current value of the dma counter
+
+Arguments:
+
+ MiniportDmaHandle - Handle for the DMA transfer.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ return HalReadDmaCounter(((PNDIS_DMA_BLOCK)(MiniportDmaHandle))->SystemAdapterObject);
+}
+
+
+#if !defined(BUILD_FOR_3_1)
+VOID
+NdisBugcheckHandler(
+ IN PNDIS_WRAPPER_CONTEXT WrapperContext,
+ IN ULONG Size
+ )
+/*++
+
+Routine Description:
+
+ This routine is called when a bugcheck occurs in the system.
+
+Arguments:
+
+ Buffer -- Ndis wrapper context.
+
+ Size -- Size of wrapper context
+
+Return Value:
+
+ Void.
+
+--*/
+{
+ if ( Size == sizeof(NDIS_WRAPPER_CONTEXT) ) {
+
+ if ( WrapperContext->ShutdownHandler != NULL ) {
+
+ WrapperContext->ShutdownHandler(WrapperContext->ShutdownContext);
+ }
+ }
+}
+#endif
+
+VOID
+NdisMRegisterAdapterShutdownHandler(
+ IN NDIS_HANDLE MiniportHandle,
+ IN PVOID ShutdownContext,
+ IN ADAPTER_SHUTDOWN_HANDLER ShutdownHandler
+ )
+/*++
+
+Routine Description:
+
+ Deregisters an NDIS adapter.
+
+Arguments:
+
+ MiniportHandle - The miniport.
+
+ ShutdownHandler - The Handler for the Adapter, to be called on shutdown.
+
+Return Value:
+
+ none.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportHandle;
+ PNDIS_WRAPPER_CONTEXT WrapperContext = Miniport->WrapperContext;
+
+ if (WrapperContext->ShutdownHandler == NULL) {
+
+ //
+ // Store information
+ //
+
+ WrapperContext->ShutdownHandler = ShutdownHandler;
+ WrapperContext->ShutdownContext = ShutdownContext;
+
+#if !defined(BUILD_FOR_3_1)
+ //
+ // Register our shutdown handler for a bugcheck. (Note that we are
+ // already registered for shutdown notification.)
+ //
+
+ KeInitializeCallbackRecord(&WrapperContext->BugcheckCallbackRecord);
+
+ KeRegisterBugCheckCallback(
+ &WrapperContext->BugcheckCallbackRecord, // callback record.
+ (PVOID) NdisBugcheckHandler, // callback routine.
+ (PVOID) WrapperContext, // free form buffer.
+ sizeof(NDIS_WRAPPER_CONTEXT), // buffer size.
+ "Ndis miniport" // component id.
+ );
+#endif
+ }
+}
+
+
+VOID
+NdisMDeregisterAdapterShutdownHandler(
+ IN NDIS_HANDLE MiniportHandle
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+ MiniportHandle - The miniport.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportHandle;
+ PNDIS_WRAPPER_CONTEXT WrapperContext = Miniport->WrapperContext;
+
+ //
+ // Clear information
+ //
+
+ if ( WrapperContext->ShutdownHandler != NULL ) {
+
+#if !defined(BUILD_FOR_3_1)
+ KeDeregisterBugCheckCallback(&WrapperContext->BugcheckCallbackRecord);
+#endif
+
+ WrapperContext->ShutdownHandler = NULL;
+ }
+}
+
+#if !defined(BUILD_FOR_3_1)
+
+NDIS_STATUS
+NdisMPciAssignResources(
+ IN NDIS_HANDLE MiniportHandle,
+ IN ULONG SlotNumber,
+ OUT PNDIS_RESOURCE_LIST *AssignedResources
+ )
+/*++
+
+Routine Description:
+
+ This routine uses the Hal to assign a set of resources to a PCI
+ device.
+
+Arguments:
+
+ MiniportHandle - The miniport.
+
+ SlotNumber - Slot number of the device.
+
+ AssignedResources - The returned resources.
+
+Return Value:
+
+ Status of the operation
+
+--*/
+{
+ NTSTATUS NtStatus;
+ PCM_RESOURCE_LIST AllocatedResources = NULL;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportHandle;
+
+ NtStatus = HalAssignSlotResources (
+ (PUNICODE_STRING)(Miniport->DriverHandle->NdisDriverInfo->NdisWrapperConfigurationHandle),
+ NULL,
+ Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver,
+ Miniport->DeviceObject,
+ Miniport->BusType,
+ Miniport->BusNumber,
+ SlotNumber,
+ &AllocatedResources
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+ *AssignedResources = NULL;
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // Store resources into the driver wide block
+ //
+ ((PNDIS_WRAPPER_CONTEXT)Miniport->WrapperContext)->AssignedSlotResources = AllocatedResources;
+
+ *AssignedResources = &(AllocatedResources->List[0].PartialResourceList);
+
+ return(NDIS_STATUS_SUCCESS);
+
+}
+
+#else // !defined(BUILD_FOR_3_1)
+
+NDIS_STATUS
+NdisMPciAssignResources(
+ IN NDIS_HANDLE MiniportHandle,
+ IN ULONG SlotNumber,
+ OUT PNDIS_RESOURCE_LIST *AssignedResources
+ )
+{
+ return NDIS_STATUS_FAILURE;
+}
+
+#endif // else !defined(BUILD_FOR_3_1)
+
+NDIS_STATUS
+NdisMQueryAdapterResources(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PNDIS_RESOURCE_LIST ResourceList,
+ IN OUT PUINT BufferSize
+ )
+{
+ return NDIS_STATUS_NOT_SUPPORTED;
+}
+
diff --git a/private/ntos/ndis/ndis30/minisub.c b/private/ntos/ndis/ndis30/minisub.c
new file mode 100644
index 000000000..4454cd129
--- /dev/null
+++ b/private/ntos/ndis/ndis30/minisub.c
@@ -0,0 +1,280 @@
+/*++
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ miniport.c
+
+Abstract:
+
+ NDIS wrapper functions
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 05-Oct-93
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#undef NdisAllocateSpinLock
+#undef NdisFreeSpinLock
+#undef NdisAcquireSpinLock
+#undef NdisReleaseSpinLock
+#undef NdisDprAcquireSpinLock
+#undef NdisDprReleaseSpinLock
+#undef NdisFreeBuffer
+#undef NdisQueryBuffer
+#undef NdisQueryBufferOffset
+#undef NDIS_BUFFER_TO_SPAN_PAGES
+#undef NdisGetBufferPhysicalArraySize
+#undef NdisEqualString
+#undef NdisMStartBufferPhysicalMapping
+#undef NdisMCompleteBufferPhysicalMapping
+
+VOID
+NdisAllocateSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+VOID
+NdisFreeSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+VOID
+NdisAcquireSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+VOID
+NdisReleaseSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+VOID
+NdisDprAcquireSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+VOID
+NdisDprReleaseSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+VOID
+NdisFreeBuffer(
+ IN PNDIS_BUFFER Buffer
+ );
+
+VOID
+NdisQueryBuffer(
+ IN PNDIS_BUFFER Buffer,
+ OUT PVOID *VirtualAddress OPTIONAL,
+ OUT PUINT Length
+ );
+
+VOID
+NdisQueryBufferOffset(
+ IN PNDIS_BUFFER Buffer,
+ OUT PUINT Offset,
+ OUT PUINT Length
+ );
+
+ULONG
+NDIS_BUFFER_TO_SPAN_PAGES(
+ IN PNDIS_BUFFER Buffer
+ );
+
+VOID
+NdisGetBufferPhysicalArraySize(
+ IN PNDIS_BUFFER Buffer,
+ OUT PUINT ArraySize
+ );
+
+BOOLEAN
+NdisEqualString(
+ IN PNDIS_STRING String1,
+ IN PNDIS_STRING String2,
+ IN BOOLEAN CaseInsensitive
+ );
+
+VOID
+NdisMStartBufferPhysicalMapping(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG PhysicalMapRegister,
+ IN BOOLEAN WriteToDevice,
+ OUT PNDIS_PHYSICAL_ADDRESS_UNIT PhysicalAddressArray,
+ OUT PUINT ArraySize
+ );
+
+VOID
+NdisMCompleteBufferPhysicalMapping(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG PhysicalMapRegister
+ );
+
+
+VOID
+NdisAllocateSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+ KeInitializeSpinLock(&SpinLock->SpinLock);
+}
+
+VOID
+NdisFreeSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+ UNREFERENCED_PARAMETER (SpinLock);
+}
+
+VOID
+NdisAcquireSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+ KeAcquireSpinLock(&SpinLock->SpinLock, &SpinLock->OldIrql);
+}
+
+VOID
+NdisReleaseSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+ KeReleaseSpinLock(&SpinLock->SpinLock, SpinLock->OldIrql);
+}
+
+VOID
+NdisDprAcquireSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+ KeAcquireSpinLockAtDpcLevel(&SpinLock->SpinLock);
+ SpinLock->OldIrql = DISPATCH_LEVEL;
+}
+
+VOID
+NdisDprReleaseSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+ KeReleaseSpinLockFromDpcLevel(&SpinLock->SpinLock);
+}
+VOID
+NdisFreeBuffer(
+ IN PNDIS_BUFFER Buffer
+ )
+{
+ IoFreeMdl(Buffer);
+}
+
+VOID
+NdisQueryBuffer(
+ IN PNDIS_BUFFER Buffer,
+ OUT PVOID *VirtualAddress OPTIONAL,
+ OUT PUINT Length
+ )
+{
+ if ( ARGUMENT_PRESENT(VirtualAddress) ) {
+ *VirtualAddress = MmGetSystemAddressForMdl(Buffer);
+ }
+ *Length = MmGetMdlByteCount(Buffer);
+}
+
+VOID
+NdisQueryBufferOffset(
+ IN PNDIS_BUFFER Buffer,
+ OUT PUINT Offset,
+ OUT PUINT Length
+ )
+{
+ *Offset = MmGetMdlByteOffset(Buffer);
+ *Length = MmGetMdlByteCount(Buffer);
+}
+
+ULONG
+NDIS_BUFFER_TO_SPAN_PAGES(
+ IN PNDIS_BUFFER Buffer
+ )
+{
+ if (MmGetMdlByteCount(Buffer) == 0) {
+ return 1;
+ }
+ return COMPUTE_PAGES_SPANNED(
+ MmGetMdlVirtualAddress(Buffer),
+ MmGetMdlByteCount(Buffer)
+ );
+}
+
+VOID
+NdisGetBufferPhysicalArraySize(
+ IN PNDIS_BUFFER Buffer,
+ OUT PUINT ArraySize
+ )
+{
+ if (MmGetMdlByteCount(Buffer) == 0) {
+ *ArraySize = 1;
+ } else {
+ *ArraySize = COMPUTE_PAGES_SPANNED(
+ MmGetMdlVirtualAddress(Buffer),
+ MmGetMdlByteCount(Buffer)
+ );
+ }
+}
+
+BOOLEAN
+NdisEqualString(
+ IN PNDIS_STRING String1,
+ IN PNDIS_STRING String2,
+ IN BOOLEAN CaseInsensitive
+ )
+{
+ return RtlEqualUnicodeString(String1, String2, CaseInsensitive);
+}
+
+VOID
+NdisMStartBufferPhysicalMapping(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG PhysicalMapRegister,
+ IN BOOLEAN WriteToDevice,
+ OUT PNDIS_PHYSICAL_ADDRESS_UNIT PhysicalAddressArray,
+ OUT PUINT ArraySize
+ )
+{
+ NdisMStartBufferPhysicalMappingMacro(
+ MiniportAdapterHandle,
+ Buffer,
+ PhysicalMapRegister,
+ WriteToDevice,
+ PhysicalAddressArray,
+ ArraySize
+ );
+}
+
+VOID
+NdisMCompleteBufferPhysicalMapping(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG PhysicalMapRegister
+ )
+{
+ NdisMCompleteBufferPhysicalMappingMacro(
+ MiniportAdapterHandle,
+ Buffer,
+ PhysicalMapRegister
+ );
+}
+
diff --git a/private/ntos/ndis/ndis30/ndis.prf b/private/ntos/ndis/ndis30/ndis.prf
new file mode 100644
index 000000000..cf7a25416
--- /dev/null
+++ b/private/ntos/ndis/ndis30/ndis.prf
@@ -0,0 +1,102 @@
+NdisMTimerDpc@16
+NDIS_BUFFER_TO_SPAN_PAGES@4
+NdisMSendComplete@12
+NdisMSend@8
+NdisMIsr@8
+NdisSetTimer@8
+EthFilterDprIndicateReceiveComplete@4
+@MiniportProcessDeferred@4
+EthFilterDprIndicateReceive@32
+NdisMDpc@16
+@MiniportStartSends@4
+NdisMWakeUpDpc@16
+NdisMCompleteBufferPhysicalMapping@12
+NdisMStartBufferPhysicalMapping@24
+NdisQueryBuffer@12
+@InterlockedIncrement@4
+@MiniportSyncSend@8
+@InterlockedDecrement@4
+_allmul
+NdisMSendResourcesAvailable@4
+NdisAllocateBuffer@20
+NdisUnchainBufferAtFront@8
+NdisMTransferDataSync@24
+MiniportDereferencePackage@0
+NdisMRegisterMiniport@12
+NdisMacDereferencePackage@0
+EthDereferencePackage@0
+NdisMacInitializePackage@0
+NdisInitDereferencePackage@0
+NdisInitializeTimer@12
+NdisAllocateSharedMemory@20
+NdisInitReferencePackage@0
+EthInitializePackage@0
+NdisInitInitializePackage@0
+EthReferencePackage@0
+MiniportReferencePackage@0
+NdisUnmapFile@4
+WrapperCheckRoute@24
+NdisOpenFile@24
+NdisCloseFile@4
+NdisMapFile@12
+NdisAllocateBufferPool@12
+FddiDeleteFilter@4
+FddiDereferencePackage@0
+FddiReferencePackage@0
+FddiInitializePackage@0
+TrDeleteFilter@4
+TrDereferencePackage@0
+TrReferencePackage@0
+ArcDeleteFilter@4
+ArcInitializePackage@0
+ArcReferencePackage@0
+ArcDereferencePackage@0
+NdisAllocateMemory@20
+NdisFreeMemory@12
+NdisInitialInit@4
+MiniportOpenAdapter@48
+NdisRegisterProtocol@16
+NdisOpenAdapter@44
+NdisFreeBufferPool@4
+TrInitializePackage@0
+NdisAllocationExecutionRoutine@16
+NdisMacReferencePackage@0
+MiniportInitializePackage@0
+EthDeleteFilter@4
+NdisReferenceRef@4
+NdisInitializeRef@4
+memmove
+NdisQueueOpenOnProtocol@8
+NdisCreateIrpHandler@8
+NdisSuccessIrpHandler@8
+WrapperSaveLinkage@24
+NdisMRegisterAdapterShutdownHandler@12
+EthNoteFilterOpenAdapter@16
+EthFilterAdjust@20
+NdisMAllocateSharedMemory@20
+NdisMAllocateMapRegisters@20
+NdisInitializeWrapper@16
+NdisCloseConfiguration@4
+NdisReadConfiguration@20
+NdisMSetAttributes@16
+NdisInitializeInterrupt@40
+NdisOpenConfiguration@12
+NdisReadNetworkAddress@16
+NdisCallDriverAddAdapter@4
+WrapperSaveParameters@24
+NdisMRegisterInterrupt@28
+MiniportDoRequests@4
+ArcCreateFilter@24
+NdisMQueryInformationComplete@8
+NdisMSetInformationComplete@8
+NdisMRequest@8
+NdisMChangeClass@20
+NdisMInitializeTimer@16
+MiniportAdjustMaximumLookahead@4
+NdisMDpcTimer@16
+NdisQueueMiniportOnDriver@8
+FddiCreateFilter@36
+TrCreateFilter@28
+EthCreateFilter@28
+NdisMRegisterIoPortRange@16
+NdisReadEisaSlotInformation@16
diff --git a/private/ntos/ndis/ndis30/ndis.rc b/private/ntos/ndis/ndis30/ndis.rc
new file mode 100644
index 000000000..3d5b057d2
--- /dev/null
+++ b/private/ntos/ndis/ndis30/ndis.rc
@@ -0,0 +1,39 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "NDIS 3.0 wrapper driver"
+#define VER_INTERNALNAME_STR "NDIS.SYS"
+#define VER_ORIGINALFILENAME_STR "NDIS.SYS"
+
+#include "common.ver"
+
diff --git a/private/ntos/ndis/ndis30/ndis.src b/private/ntos/ndis/ndis30/ndis.src
new file mode 100644
index 000000000..bdbfdff44
--- /dev/null
+++ b/private/ntos/ndis/ndis30/ndis.src
@@ -0,0 +1,185 @@
+NAME NDIS.SYS
+
+DESCRIPTION 'NDIS.SYS'
+
+EXPORTS
+ ArcFilterDprIndicateReceive
+ ArcFilterDprIndicateReceiveComplete
+ EthChangeFilterAddresses
+ EthCreateFilter
+ EthDeleteFilter
+ EthDeleteFilterOpenAdapter
+ EthFilterAdjust
+ EthFilterDprIndicateReceive
+ EthFilterDprIndicateReceiveComplete
+ EthFilterIndicateReceive
+ EthFilterIndicateReceiveComplete
+ EthNoteFilterOpenAdapter
+ EthNumberOfOpenFilterAddresses
+ EthQueryGlobalFilterAddresses
+ EthQueryOpenFilterAddresses
+ EthShouldAddressLoopBack
+ FddiChangeFilterLongAddresses
+ FddiChangeFilterShortAddresses
+ FddiCreateFilter
+ FddiDeleteFilter
+ FddiDeleteFilterOpenAdapter
+ FddiFilterAdjust
+ FddiFilterDprIndicateReceive
+ FddiFilterDprIndicateReceiveComplete
+ FddiFilterIndicateReceive
+ FddiFilterIndicateReceiveComplete
+ FddiNoteFilterOpenAdapter
+ FddiNumberOfOpenFilterLongAddresses
+ FddiNumberOfOpenFilterShortAddresses
+ FddiQueryGlobalFilterLongAddresses
+ FddiQueryGlobalFilterShortAddresses
+ FddiQueryOpenFilterLongAddresses
+ FddiQueryOpenFilterShortAddresses
+ FddiShouldAddressLoopBack
+ NdisAllocateBuffer
+ NdisAllocateBufferPool
+ NdisAllocateDmaChannel
+ NdisAllocateMemory
+ NdisAllocatePacket
+ NdisAllocatePacketPool
+ NdisAllocateSharedMemory
+ NdisCloseAdapter
+ NdisCloseConfiguration
+ NdisCloseFile
+ NdisCloseRef
+ NdisCompleteCloseAdapter
+ NdisCompleteDmaTransfer
+ NdisCompleteOpenAdapter
+ NdisCompleteQueryStatistics
+ NdisCopyBuffer
+ NdisCopyFromPacketToPacket
+ NdisDereferenceRef
+#if ALPHA
+ NdisCreateLookaheadBufferFromSharedMemory
+ NdisDestroyLookaheadBufferFromSharedMemory
+#endif
+ NdisDeregisterAdapter
+ NdisDeregisterAdapterShutdownHandler
+ NdisDeregisterMac
+ NdisDeregisterProtocol
+ NdisFinishOpen
+ NdisFreeBufferPool
+ NdisFreeDmaChannel
+ NdisFreeMemory
+ NdisFreeSharedMemory
+ NdisImmediateReadPciSlotInformation
+ NdisImmediateReadPortUchar
+ NdisImmediateReadPortUshort
+ NdisImmediateReadPortUlong
+ NdisImmediateReadSharedMemory
+ NdisImmediateWritePciSlotInformation
+ NdisImmediateWritePortUchar
+ NdisImmediateWritePortUshort
+ NdisImmediateWritePortUlong
+ NdisImmediateWriteSharedMemory
+ NdisInitializeInterrupt
+ NdisInitializePacketPool
+ NdisInitializeRef
+ NdisInitializeTimer
+ NdisInitializeWrapper
+ NdisMapFile
+ NdisMapIoSpace
+ NdisOpenAdapter
+ NdisOpenConfiguration
+ NdisOpenFile
+ NdisPciAssignResources
+ NdisReadConfiguration
+ NdisReadBindingInformation
+ NdisReadEisaSlotInformation
+ NdisReadEisaSlotInformationEx
+ NdisReadMcaPosInformation
+ NdisReadNetworkAddress
+ NdisReadPciSlotInformation
+ NdisReferenceRef
+ NdisRegisterAdapter
+ NdisRegisterAdapterShutdownHandler
+ NdisRegisterMac
+ NdisRegisterProtocol
+ NdisReleaseAdapterResources
+ NdisRemoveInterrupt
+ NdisSetTimer
+ NdisSetupDmaTransfer
+ NdisTerminateWrapper
+ NdisUnchainBufferAtFront
+ NdisUnchainBufferAtBack
+ NdisUnmapFile
+ NdisUpdateSharedMemory
+ NdisWriteErrorLogEntry
+ NdisWritePciSlotInformation
+
+ NdisMAllocateMapRegisters
+ NdisMCancelTimer
+ NdisMDeregisterIoPortRange
+ NdisMFreeMapRegisters
+ NdisMIndicateStatus
+ NdisMIndicateStatusComplete
+ NdisMInitializeTimer
+ NdisMQueryInformationComplete
+ NdisMRegisterIoPortRange
+ NdisMRegisterMiniport
+ NdisMResetComplete
+ NdisMSendComplete
+ NdisMSendResourcesAvailable
+ NdisMSetAttributes
+ NdisMSetInformationComplete
+ NdisMTransferDataComplete
+
+ NdisAllocateSpinLock
+ NdisFreeSpinLock
+ NdisAcquireSpinLock
+ NdisReleaseSpinLock
+ NdisDprAcquireSpinLock
+ NdisDprReleaseSpinLock
+ NdisFreeBuffer
+ NdisQueryBuffer
+ NdisQueryBufferOffset
+ NDIS_BUFFER_TO_SPAN_PAGES
+ NdisGetBufferPhysicalArraySize
+ NdisEqualString
+
+ NdisMMapIoSpace
+ NdisMUnmapIoSpace
+ NdisMRegisterInterrupt
+ NdisMDeregisterInterrupt
+ NdisMSynchronizeWithInterrupt
+ NdisMAllocateSharedMemory
+ NdisMFreeSharedMemory
+ NdisMRegisterDmaChannel
+ NdisMDeregisterDmaChannel
+ NdisMReadDmaCounter
+
+ TrChangeFunctionalAddress
+ TrChangeGroupAddress
+ TrCreateFilter
+ TrDeleteFilter
+ TrDeleteFilterOpenAdapter
+ TrFilterAdjust
+ TrFilterDprIndicateReceive
+ TrFilterDprIndicateReceiveComplete
+ TrFilterIndicateReceive
+ TrFilterIndicateReceiveComplete
+ TrNoteFilterOpenAdapter
+ TrShouldAddressLoopBack
+
+ NdisMWanSendComplete
+ NdisMWanIndicateReceive
+ NdisMWanIndicateReceiveComplete
+
+ NdisMStartBufferPhysicalMapping
+ NdisMCompleteBufferPhysicalMapping
+ NdisSystemProcessorCount
+ NdisWriteConfiguration
+
+ NdisMRegisterAdapterShutdownHandler
+ NdisMDeregisterAdapterShutdownHandler
+
+ NdisMPciAssignResources
+ NdisOverrideBusNumber
+
+ NdisMQueryAdapterResources
diff --git a/private/ntos/ndis/ndis30/ndismac.h b/private/ntos/ndis/ndis30/ndismac.h
new file mode 100644
index 000000000..a5395883a
--- /dev/null
+++ b/private/ntos/ndis/ndis30/ndismac.h
@@ -0,0 +1,1218 @@
+typedef
+BOOLEAN
+(*PNDIS_INTERRUPT_SERVICE) (
+ IN PVOID InterruptContext
+ );
+
+typedef
+VOID
+(*PNDIS_DEFERRED_PROCESSING) (
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+
+typedef struct _NDIS_INTERRUPT {
+ PKINTERRUPT InterruptObject;
+ KSPIN_LOCK DpcCountLock;
+ PNDIS_INTERRUPT_SERVICE MacIsr; // Pointer to Mac ISR routine
+ PNDIS_DEFERRED_PROCESSING MacDpc; // Pointer to Mac DPC routine
+ KDPC InterruptDpc;
+ PVOID InterruptContext; // Pointer to context for calling
+ // adapters ISR and DPC.
+ UCHAR DpcCount;
+ BOOLEAN Removing; // TRUE if removing interrupt
+
+ //
+ // This is used to tell when all the Dpcs for the adapter are completed.
+ //
+ KEVENT DpcsCompletedEvent;
+
+} NDIS_INTERRUPT, *PNDIS_INTERRUPT;
+
+//
+// Ndis Adapter Information
+//
+
+typedef
+NDIS_STATUS
+(*PNDIS_ACTIVATE_CALLBACK) (
+ IN NDIS_HANDLE NdisAdatperHandle,
+ IN NDIS_HANDLE MacAdapterContext,
+ IN ULONG DmaChannel
+ );
+
+typedef struct _NDIS_PORT_DESCRIPTOR {
+ ULONG InitialPort;
+ ULONG NumberOfPorts;
+ PVOID *PortOffset;
+} NDIS_PORT_DESCRIPTOR, *PNDIS_PORT_DESCRIPTOR;
+
+typedef struct _NDIS_ADAPTER_INFORMATION {
+ ULONG DmaChannel;
+ BOOLEAN Master;
+ BOOLEAN Dma32BitAddresses;
+ PNDIS_ACTIVATE_CALLBACK ActivateCallback;
+ NDIS_INTERFACE_TYPE AdapterType;
+ ULONG PhysicalMapRegistersNeeded;
+ ULONG MaximumPhysicalMapping;
+ ULONG NumberOfPortDescriptors;
+ NDIS_PORT_DESCRIPTOR PortDescriptors[1]; // as many as needed
+} NDIS_ADAPTER_INFORMATION, *PNDIS_ADAPTER_INFORMATION;
+
+//
+// Function types for NDIS_MAC_CHARACTERISTICS
+//
+
+typedef
+NDIS_STATUS
+(*OPEN_ADAPTER_HANDLER) (
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT NDIS_HANDLE *MacBindingHandle,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_HANDLE MacAdapterContext,
+ IN UINT OpenOptions,
+ IN PSTRING AddressingInformation OPTIONAL
+ );
+
+typedef
+NDIS_STATUS
+(*CLOSE_ADAPTER_HANDLER) (
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+typedef
+NDIS_STATUS
+(*SEND_HANDLER) (
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_PACKET Packet
+ );
+
+typedef
+NDIS_STATUS
+(*TRANSFER_DATA_HANDLER) (
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+typedef
+NDIS_STATUS
+(*RESET_HANDLER) (
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+typedef
+NDIS_STATUS
+(*REQUEST_HANDLER) (
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+typedef
+NDIS_STATUS
+(*QUERY_GLOBAL_STATISTICS_HANDLER) (
+ IN NDIS_HANDLE MacAdapterContext,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+typedef
+VOID
+(*UNLOAD_MAC_HANDLER) (
+ IN NDIS_HANDLE MacMacContext
+ );
+
+typedef
+NDIS_STATUS
+(*ADD_ADAPTER_HANDLER) (
+ IN NDIS_HANDLE MacMacContext,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN PNDIS_STRING AdapterName
+ );
+
+typedef
+VOID
+(*REMOVE_ADAPTER_HANDLER) (
+ IN NDIS_HANDLE MacAdapterContext
+ );
+
+
+typedef struct _NDIS_MAC_CHARACTERISTICS {
+ UCHAR MajorNdisVersion;
+ UCHAR MinorNdisVersion;
+ UINT Reserved;
+ OPEN_ADAPTER_HANDLER OpenAdapterHandler;
+ CLOSE_ADAPTER_HANDLER CloseAdapterHandler;
+ SEND_HANDLER SendHandler;
+ TRANSFER_DATA_HANDLER TransferDataHandler;
+ RESET_HANDLER ResetHandler;
+ REQUEST_HANDLER RequestHandler;
+ QUERY_GLOBAL_STATISTICS_HANDLER QueryGlobalStatisticsHandler;
+ UNLOAD_MAC_HANDLER UnloadMacHandler;
+ ADD_ADAPTER_HANDLER AddAdapterHandler;
+ REMOVE_ADAPTER_HANDLER RemoveAdapterHandler;
+ NDIS_STRING Name;
+} NDIS_MAC_CHARACTERISTICS, *PNDIS_MAC_CHARACTERISTICS;
+
+
+//
+// Function types for NDIS_PROTOCOL_CHARACTERISTICS
+//
+//
+
+typedef
+VOID
+(*OPEN_ADAPTER_COMPLETE_HANDLER) (
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status,
+ IN NDIS_STATUS OpenErrorStatus
+ );
+
+typedef
+VOID
+(*CLOSE_ADAPTER_COMPLETE_HANDLER) (
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status
+ );
+
+typedef
+VOID
+(*RESET_COMPLETE_HANDLER) (
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status
+ );
+
+typedef
+VOID
+(*REQUEST_COMPLETE_HANDLER) (
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS Status
+ );
+
+typedef
+VOID
+(*STATUS_HANDLER) (
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ );
+
+typedef
+VOID
+(*STATUS_COMPLETE_HANDLER) (
+ IN NDIS_HANDLE ProtocolBindingContext
+ );
+
+typedef struct _NDIS_PROTOCOL_CHARACTERISTICS {
+ UCHAR MajorNdisVersion;
+ UCHAR MinorNdisVersion;
+ UINT Reserved;
+ OPEN_ADAPTER_COMPLETE_HANDLER OpenAdapterCompleteHandler;
+ CLOSE_ADAPTER_COMPLETE_HANDLER CloseAdapterCompleteHandler;
+ SEND_COMPLETE_HANDLER SendCompleteHandler;
+ TRANSFER_DATA_COMPLETE_HANDLER TransferDataCompleteHandler;
+ RESET_COMPLETE_HANDLER ResetCompleteHandler;
+ REQUEST_COMPLETE_HANDLER RequestCompleteHandler;
+ RECEIVE_HANDLER ReceiveHandler;
+ RECEIVE_COMPLETE_HANDLER ReceiveCompleteHandler;
+ STATUS_HANDLER StatusHandler;
+ STATUS_COMPLETE_HANDLER StatusCompleteHandler;
+ NDIS_STRING Name;
+} NDIS_PROTOCOL_CHARACTERISTICS, *PNDIS_PROTOCOL_CHARACTERISTICS;
+
+//
+// MAC specific considerations.
+//
+
+struct _NDIS_WRAPPER_HANDLE {
+
+ //
+ // These store the PDRIVER_OBJECT that
+ // the MAC passes to NdisInitializeWrapper until it can be
+ // used by NdisRegisterMac and NdisTerminateWrapper.
+ //
+
+ PDRIVER_OBJECT NdisWrapperDriver;
+
+ HANDLE NdisWrapperConfigurationHandle;
+
+};
+
+
+
+
+//
+// one of these per MAC
+//
+
+struct _NDIS_MAC_BLOCK {
+ PNDIS_ADAPTER_BLOCK AdapterQueue; // queue of adapters for this MAC
+ NDIS_HANDLE MacMacContext; // Context for calling MACUnload and
+ // MACAddAdapter.
+
+ REFERENCE Ref; // contains spinlock for AdapterQueue
+ UINT Length; // of this NDIS_MAC_BLOCK structure
+ NDIS_MAC_CHARACTERISTICS MacCharacteristics; // handler addresses
+ PNDIS_WRAPPER_HANDLE NdisMacInfo; // Mac information.
+ PNDIS_MAC_BLOCK NextMac;
+ KEVENT AdaptersRemovedEvent; // used to find when all adapters are gone.
+ BOOLEAN Unloading; // TRUE if unloading
+
+ //
+ // Extensions added for NT 3.5 support
+ //
+ PCM_RESOURCE_LIST PciAssignedResources;
+};
+
+//
+// one of these per adapter registered on a MAC
+//
+
+struct _NDIS_ADAPTER_BLOCK {
+ PDEVICE_OBJECT DeviceObject; // created by NdisRegisterAdapter
+ PNDIS_MAC_BLOCK MacHandle; // pointer to our MAC block
+ NDIS_HANDLE MacAdapterContext; // context when calling MacOpenAdapter
+ NDIS_STRING AdapterName; // how NdisOpenAdapter refers to us
+ PNDIS_OPEN_BLOCK OpenQueue; // queue of opens for this adapter
+ PNDIS_ADAPTER_BLOCK NextAdapter; // used by MAC's AdapterQueue
+ REFERENCE Ref; // contains spinlock for OpenQueue
+ BOOLEAN BeingRemoved; // TRUE if adapter is being removed
+
+ //
+ // Resource information
+ //
+ PCM_RESOURCE_LIST Resources;
+
+ //
+ // Obsolete field.
+ //
+ ULONG NotUsed;
+
+ //
+ // Wrapper context.
+ //
+ PVOID WrapperContext;
+
+ //
+ // contains adapter information
+ //
+ ULONG BusNumber;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG ChannelNumber;
+ NDIS_INTERFACE_TYPE AdapterType;
+ BOOLEAN Master;
+ ULONG PhysicalMapRegistersNeeded;
+ ULONG MaximumPhysicalMapping;
+ ULONG InitialPort;
+ ULONG NumberOfPorts;
+
+ //
+ // Holds the mapping for ports, if needed.
+ //
+ PUCHAR InitialPortMapping;
+
+ //
+ // TRUE if InitialPortMapping was mapped with NdisMapIoSpace.
+ //
+ BOOLEAN InitialPortMapped;
+
+ //
+ // This is the offset added to the port passed to NdisXXXPort to
+ // get to the real value to be passed to the NDIS_XXX_PORT macros.
+ // It equals InitialPortMapping - InitialPort; that is, the
+ // mapped "address" of port 0, even if we didn't actually
+ // map port 0.
+ //
+ PUCHAR PortOffset;
+
+ //
+ // Holds the map registers for this adapter.
+ //
+ PMAP_REGISTER_ENTRY MapRegisters;
+
+ //
+ // These two are used temporarily while allocating
+ // the map registers.
+ //
+ KEVENT AllocationEvent;
+ UINT CurrentMapRegister;
+ PADAPTER_OBJECT SystemAdapterObject;
+};
+
+//
+// one of these per protocol registered
+//
+
+struct _NDIS_PROTOCOL_BLOCK {
+ PNDIS_OPEN_BLOCK OpenQueue; // queue of opens for this protocol
+ REFERENCE Ref; // contains spinlock for OpenQueue
+ UINT Length; // of this NDIS_PROTOCOL_BLOCK struct
+ NDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics; // handler addresses
+};
+
+//
+// one of these per open on an adapter/protocol
+//
+
+struct _NDIS_OPEN_BLOCK {
+ PNDIS_MAC_BLOCK MacHandle; // pointer to our MAC
+ NDIS_HANDLE MacBindingHandle; // context when calling MacXX funcs
+ PNDIS_ADAPTER_BLOCK AdapterHandle; // pointer to our adapter
+ PNDIS_PROTOCOL_BLOCK ProtocolHandle; // pointer to our protocol
+ NDIS_HANDLE ProtocolBindingContext; // context when calling ProtXX funcs
+ PNDIS_OPEN_BLOCK AdapterNextOpen; // used by adapter's OpenQueue
+ PNDIS_OPEN_BLOCK ProtocolNextOpen; // used by protocol's OpenQueue
+ PFILE_OBJECT FileObject; // created by operating system
+ BOOLEAN Closing; // TRUE when removing this struct
+ NDIS_HANDLE CloseRequestHandle; // 0 indicates an internal close
+ NDIS_SPIN_LOCK SpinLock; // guards Closing
+
+ //
+ // These are optimizations for getting to MAC routines. They are not
+ // necessary, but are here to save a dereference through the MAC block.
+ //
+
+ SEND_HANDLER SendHandler;
+ TRANSFER_DATA_HANDLER TransferDataHandler;
+
+ //
+ // These are optimizations for getting to PROTOCOL routines. They are not
+ // necessary, but are here to save a dereference through the PROTOCOL block.
+ //
+
+ SEND_COMPLETE_HANDLER SendCompleteHandler;
+ TRANSFER_DATA_COMPLETE_HANDLER TransferDataCompleteHandler;
+ RECEIVE_HANDLER ReceiveHandler;
+ RECEIVE_COMPLETE_HANDLER ReceiveCompleteHandler;
+
+ //
+ // Extentions to the OPEN_BLOCK since Product 1.
+ //
+ RECEIVE_HANDLER PostNt31ReceiveHandler;
+ RECEIVE_COMPLETE_HANDLER PostNt31ReceiveCompleteHandler;
+ PNDIS_OPEN_BLOCK NextGlobalOpen;
+
+};
+
+//
+// Routines to access packet flags
+//
+
+/*++
+
+VOID
+NdisSetSendFlags(
+ IN PNDIS_PACKET Packet,
+ IN UINT Flags
+ );
+
+--*/
+
+#define NdisSetSendFlags(_Packet,_Flags) \
+ (_Packet)->Private.Flags = (_Flags)
+
+/*++
+
+VOID
+NdisQuerySendFlags(
+ IN PNDIS_PACKET Packet,
+ OUT PUINT Flags
+ );
+
+--*/
+
+#define NdisQuerySendFlags(_Packet,_Flags) \
+ *(_Flags) = (_Packet)->Private.Flags
+
+
+//
+// Packet Pool
+//
+
+EXPORT
+VOID
+NdisAllocatePacketPool(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE PoolHandle,
+ IN UINT NumberOfDescriptors,
+ IN UINT ProtocolReservedLength
+ );
+
+// VOID
+// NdisFreePacketPool(
+// IN NDIS_HANDLE PoolHandle
+// );
+#define NdisFreePacketPool(PoolHandle) {\
+ NdisFreeSpinLock(&((PNDIS_PACKET_POOL)PoolHandle)->SpinLock);\
+ ExFreePool(PoolHandle); \
+}
+
+EXPORT
+VOID
+NdisAllocatePacket(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_PACKET * Packet,
+ IN NDIS_HANDLE PoolHandle
+ );
+
+// VOID
+// NdisFreePacket(
+// IN PNDIS_PACKET Packet
+// );
+#define NdisFreePacket(Packet) {\
+ NdisAcquireSpinLock(&(Packet)->Private.Pool->SpinLock); \
+ (Packet)->Private.Head = (PNDIS_BUFFER)(Packet)->Private.Pool->FreeList; \
+ (Packet)->Private.Pool->FreeList = (Packet); \
+ NdisReleaseSpinLock(&(Packet)->Private.Pool->SpinLock); \
+}
+
+
+// VOID
+// NdisReinitializePacket(
+// IN OUT PNDIS_PACKET Packet
+// );
+#define NdisReinitializePacket(Packet) { \
+ (Packet)->Private.Head = (PNDIS_BUFFER)NULL; \
+ (Packet)->Private.ValidCounts = FALSE; \
+}
+
+
+EXPORT
+VOID
+NdisInitializeTimer(
+ IN OUT PNDIS_TIMER Timer,
+ IN PNDIS_TIMER_FUNCTION TimerFunction,
+ IN PVOID FunctionContext
+ );
+
+/*++
+VOID
+NdisCancelTimer(
+ IN PNDIS_TIMER Timer,
+ OUT PBOOLEAN TimerCancelled
+ )
+--*/
+#define NdisCancelTimer(NdisTimer,TimerCancelled) \
+ (*(TimerCancelled) = KeCancelTimer(&((NdisTimer)->Timer)))
+
+//
+// Shared memory
+//
+
+EXPORT
+VOID
+NdisAllocateSharedMemory(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Length,
+ IN BOOLEAN Cached,
+ OUT PVOID *VirtualAddress,
+ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress
+ );
+
+EXPORT
+VOID
+NdisFreeSharedMemory(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Length,
+ IN BOOLEAN Cached,
+ IN PVOID VirtualAddress,
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress
+ );
+
+
+//
+// Requests used by Protocol Modules
+//
+
+EXPORT
+VOID
+NdisRegisterProtocol(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE NdisProtocolHandle,
+ IN PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics,
+ IN UINT CharacteristicsLength
+ );
+
+EXPORT
+VOID
+NdisDeregisterProtocol(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisProtocolHandle
+ );
+
+
+EXPORT
+VOID
+NdisOpenAdapter(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PNDIS_HANDLE NdisBindingHandle,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE NdisProtocolHandle,
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_STRING AdapterName,
+ IN UINT OpenOptions,
+ IN PSTRING AddressingInformation OPTIONAL
+ );
+
+
+EXPORT
+VOID
+NdisCloseAdapter(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisBindingHandle
+ );
+
+
+// VOID
+// NdisSend(
+// OUT PNDIS_STATUS Status,
+// IN NDIS_HANDLE NdisBindingHandle,
+// IN PNDIS_PACKET Packet
+// );
+#define NdisSend(Status, \
+ NdisBindingHandle, \
+ Packet \
+ ) \
+{\
+ *(Status) = \
+ (((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->SendHandler) ( \
+ ((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->MacBindingHandle, \
+ (Packet)); \
+}
+
+
+// VOID
+// NdisTransferData(
+// OUT PNDIS_STATUS Status,
+// IN NDIS_HANDLE NdisBindingHandle,
+// IN NDIS_HANDLE MacReceiveContext,
+// IN UINT ByteOffset,
+// IN UINT BytesToTransfer,
+// IN OUT PNDIS_PACKET Packet,
+// OUT PUINT BytesTransferred
+// );
+#define NdisTransferData( \
+ Status, \
+ NdisBindingHandle, \
+ MacReceiveContext, \
+ ByteOffset, \
+ BytesToTransfer, \
+ Packet, \
+ BytesTransferred \
+ ) \
+{\
+ *(Status) = \
+ (((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->TransferDataHandler) ( \
+ ((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->MacBindingHandle, \
+ (MacReceiveContext), \
+ (ByteOffset), \
+ (BytesToTransfer), \
+ (Packet), \
+ (BytesTransferred)); \
+}
+
+
+// VOID
+// NdisReset(
+// OUT PNDIS_STATUS Status,
+// IN NDIS_HANDLE NdisBindingHandle
+// );
+#define NdisReset( \
+ Status, \
+ NdisBindingHandle \
+ ) \
+{ \
+ *(Status) = \
+ (((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->MacHandle->MacCharacteristics.ResetHandler) ( \
+ ((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->MacBindingHandle); \
+}
+
+// VOID
+// NdisRequest(
+// OUT PNDIS_STATUS Status,
+// IN NDIS_HANDLE NdisBindingHandle,
+// IN PNDIS_REQUEST NdisRequest
+// );
+#define NdisRequest( \
+ Status,\
+ NdisBindingHandle, \
+ NdisRequest \
+ ) \
+{ \
+ *(Status) = \
+ (((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->MacHandle->MacCharacteristics.RequestHandler) ( \
+ ((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->MacBindingHandle, \
+ (NdisRequest)); \
+}
+
+//
+// DMA operations.
+//
+
+EXPORT
+VOID
+NdisAllocateDmaChannel(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE NdisDmaHandle,
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN PNDIS_DMA_DESCRIPTION DmaDescription,
+ IN ULONG MaximumLength
+ );
+
+EXPORT
+VOID
+NdisFreeDmaChannel(
+ IN PNDIS_HANDLE NdisDmaHandle
+ );
+
+EXPORT
+VOID
+NdisSetupDmaTransfer(
+ OUT PNDIS_STATUS Status,
+ IN PNDIS_HANDLE NdisDmaHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG Offset,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ );
+
+EXPORT
+VOID
+NdisCompleteDmaTransfer(
+ OUT PNDIS_STATUS Status,
+ IN PNDIS_HANDLE NdisDmaHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG Offset,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ );
+
+/*++
+ULONG
+NdisReadDmaCounter(
+ IN NDIS_HANDLE NdisDmaHandle
+ )
+--*/
+
+#define NdisReadDmaCounter(_NdisDmaHandle) \
+ HalReadDmaCounter(((PNDIS_DMA_BLOCK)(_NdisDmaHandle))->SystemAdapterObject)
+
+//
+// Requests Used by MAC Drivers
+//
+
+EXPORT
+VOID
+NdisRegisterMac(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE NdisMacHandle,
+ IN NDIS_HANDLE NdisWrapperHandle,
+ IN NDIS_HANDLE MacMacContext,
+ IN PNDIS_MAC_CHARACTERISTICS MacCharacteristics,
+ IN UINT CharacteristicsLength
+ );
+
+EXPORT
+VOID
+NdisDeregisterMac(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisMacHandle
+ );
+
+
+EXPORT
+NDIS_STATUS
+NdisRegisterAdapter(
+ OUT PNDIS_HANDLE NdisAdapterHandle,
+ IN NDIS_HANDLE NdisMacHandle,
+ IN NDIS_HANDLE MacAdapterContext,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN PNDIS_STRING AdapterName,
+ IN PVOID AdapterInformation
+ );
+
+EXPORT
+NDIS_STATUS
+NdisDeregisterAdapter(
+ IN NDIS_HANDLE NdisAdapterHandle
+ );
+
+EXPORT
+VOID
+NdisRegisterAdapterShutdownHandler(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN PVOID ShutdownContext,
+ IN ADAPTER_SHUTDOWN_HANDLER ShutdownHandler
+ );
+
+EXPORT
+VOID
+NdisDeregisterAdapterShutdownHandler(
+ IN NDIS_HANDLE NdisAdapterHandle
+ );
+
+EXPORT
+VOID
+NdisReleaseAdapterResources(
+ IN NDIS_HANDLE NdisAdapterHandle
+ );
+
+EXPORT
+VOID
+NdisCompleteOpenAdapter(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS Status,
+ IN NDIS_STATUS OpenErrorStatus
+ );
+
+
+EXPORT
+VOID
+NdisCompleteCloseAdapter(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS Status
+ );
+
+
+// VOID
+// NdisCompleteSend(
+// IN NDIS_HANDLE NdisBindingContext,
+// IN PNDIS_PACKET Packet,
+// IN NDIS_STATUS Status
+// );
+#define NdisCompleteSend( \
+ NdisBindingContext, \
+ Packet, \
+ Status \
+ ) \
+{\
+ (((PNDIS_OPEN_BLOCK)(NdisBindingContext))->SendCompleteHandler) ( \
+ ((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolBindingContext, \
+ (Packet), \
+ (Status)); \
+}
+
+
+// VOID
+// NdisCompleteTransferData(
+// IN NDIS_HANDLE NdisBindingContext,
+// IN PNDIS_PACKET Packet,
+// IN NDIS_STATUS Status,
+// IN UINT BytesTransferred
+// );
+#define NdisCompleteTransferData( \
+ NdisBindingContext, \
+ Packet, \
+ Status, \
+ BytesTransferred \
+ ) \
+{\
+ (((PNDIS_OPEN_BLOCK)(NdisBindingContext))->TransferDataCompleteHandler) ( \
+ ((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolBindingContext, \
+ (Packet), \
+ (Status), \
+ (BytesTransferred)); \
+}
+
+// VOID
+// NdisCompleteReset(
+// IN NDIS_HANDLE NdisBindingContext,
+// IN NDIS_STATUS Status
+// );
+#define NdisCompleteReset( \
+ NdisBindingContext, \
+ Status \
+ ) \
+{ \
+ (((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolHandle->ProtocolCharacteristics.ResetCompleteHandler) ( \
+ ((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolBindingContext, \
+ Status); \
+}
+
+
+// VOID
+// NdisCompleteRequest(
+// IN NDIS_HANDLE NdisBindingContext,
+// IN PNDIS_REQUEST NdisRequest,
+// IN NDIS_STATUS Status
+// );
+#define NdisCompleteRequest( \
+ NdisBindingContext, \
+ NdisRequest, \
+ Status) \
+{ \
+ (((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolHandle->ProtocolCharacteristics.RequestCompleteHandler) ( \
+ ((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolBindingContext, \
+ NdisRequest, \
+ Status); \
+}
+
+// VOID
+// NdisIndicateReceive(
+// OUT PNDIS_STATUS Status,
+// IN NDIS_HANDLE NdisBindingContext,
+// IN NDIS_HANDLE MacReceiveContext,
+// IN PVOID HeaderBuffer,
+// IN UINT HeaderBufferSize,
+// IN PVOID LookaheadBuffer,
+// IN UINT LookaheadBufferSize,
+// IN UINT PacketSize
+// );
+#define NdisIndicateReceive( \
+ Status, \
+ NdisBindingContext, \
+ MacReceiveContext, \
+ HeaderBuffer, \
+ HeaderBufferSize, \
+ LookaheadBuffer, \
+ LookaheadBufferSize, \
+ PacketSize \
+ ) \
+{\
+ KIRQL oldIrql;\
+ KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );\
+ *(Status) = \
+ (((PNDIS_OPEN_BLOCK)(NdisBindingContext))->PostNt31ReceiveHandler) ( \
+ ((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolBindingContext, \
+ (MacReceiveContext), \
+ (HeaderBuffer), \
+ (HeaderBufferSize), \
+ (LookaheadBuffer), \
+ (LookaheadBufferSize), \
+ (PacketSize)); \
+ KeLowerIrql( oldIrql );\
+}
+
+//
+// Used by the filter packages for indicating receives
+//
+
+#define FilterIndicateReceive( \
+ Status, \
+ NdisBindingContext, \
+ MacReceiveContext, \
+ HeaderBuffer, \
+ HeaderBufferSize, \
+ LookaheadBuffer, \
+ LookaheadBufferSize, \
+ PacketSize \
+ ) \
+{\
+ *(Status) = \
+ (((PNDIS_OPEN_BLOCK)(NdisBindingContext))->PostNt31ReceiveHandler) ( \
+ ((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolBindingContext, \
+ (MacReceiveContext), \
+ (HeaderBuffer), \
+ (HeaderBufferSize), \
+ (LookaheadBuffer), \
+ (LookaheadBufferSize), \
+ (PacketSize)); \
+}
+
+
+// VOID
+// NdisIndicateReceiveComplete(
+// IN NDIS_HANDLE NdisBindingContext
+// );
+#define NdisIndicateReceiveComplete(NdisBindingContext) \
+{\
+ KIRQL oldIrql;\
+ KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );\
+ (((PNDIS_OPEN_BLOCK)(NdisBindingContext))->PostNt31ReceiveCompleteHandler) ( \
+ ((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolBindingContext);\
+ KeLowerIrql( oldIrql );\
+}
+
+//
+// Used by the filter packages for indicating receive completion
+//
+
+#define FilterIndicateReceiveComplete(NdisBindingContext) \
+{\
+ (((PNDIS_OPEN_BLOCK)(NdisBindingContext))->PostNt31ReceiveCompleteHandler) ( \
+ ((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolBindingContext);\
+}
+
+// VOID
+// NdisIndicateStatus(
+// IN NDIS_HANDLE NdisBindingContext,
+// IN NDIS_STATUS GeneralStatus,
+// IN PVOID StatusBuffer,
+// IN UINT StatusBufferSize
+// );
+#define NdisIndicateStatus( \
+ NdisBindingContext, \
+ GeneralStatus, \
+ StatusBuffer, \
+ StatusBufferSize \
+ ) \
+{\
+ (((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolHandle->ProtocolCharacteristics.StatusHandler) ( \
+ ((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolBindingContext, \
+ (GeneralStatus), \
+ (StatusBuffer), \
+ (StatusBufferSize)); \
+}
+
+
+// VOID
+// NdisIndicateStatusComplete(
+// IN NDIS_HANDLE NdisBindingContext
+// );
+#define NdisIndicateStatusComplete( \
+ NdisBindingContext \
+ ) \
+{ \
+ (((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolHandle->ProtocolCharacteristics.StatusCompleteHandler) ( \
+ ((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolBindingContext); \
+}
+
+EXPORT
+VOID
+NdisCompleteQueryStatistics(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS Status
+ );
+
+//
+// Interlocked support functions
+//
+
+/*++
+
+VOID
+NdisInterlockedAddUlong(
+ IN PULONG Addend,
+ IN ULONG Increment,
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+--*/
+
+#define NdisInterlockedAddUlong(_Addend, _Increment, _SpinLock) \
+ ExInterlockedAddUlong(_Addend, _Increment, &(_SpinLock)->SpinLock)
+
+/*++
+
+PLIST_ENTRY
+NdisInterlockedInsertHeadList(
+ IN PLIST_ENTRY ListHead,
+ IN PLIST_ENTRY ListEntry,
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+--*/
+
+#define NdisInterlockedInsertHeadList(_ListHead, _ListEntry, _SpinLock) \
+ ExInterlockedInsertHeadList(_ListHead, _ListEntry, &(_SpinLock)->SpinLock)
+
+/*++
+
+PLIST_ENTRY
+NdisInterlockedInsertTailList(
+ IN PLIST_ENTRY ListHead,
+ IN PLIST_ENTRY ListEntry,
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+--*/
+
+#define NdisInterlockedInsertTailList(_ListHead, _ListEntry, _SpinLock) \
+ ExInterlockedInsertTailList(_ListHead, _ListEntry, &(_SpinLock)->SpinLock)
+
+/*++
+
+PLIST_ENTRY
+NdisInterlockedRemoveHeadList(
+ IN PLIST_ENTRY ListHead,
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+--*/
+
+#define NdisInterlockedRemoveHeadList(_ListHead, _SpinLock) \
+ ExInterlockedRemoveHeadList(_ListHead, &(_SpinLock)->SpinLock)
+
+/*++
+
+VOID
+NdisAdjustBufferLength(
+ IN PNDIS_BUFFER Buffer,
+ IN UINT Length
+ );
+
+--*/
+
+#define NdisAdjustBufferLength(Buffer, Length) \
+ (((Buffer)->ByteCount) = (Length))
+
+//
+// Operating System Requests
+//
+
+EXPORT
+VOID
+NdisMapIoSpace(
+ OUT PNDIS_STATUS Status,
+ OUT PVOID * VirtualAddress,
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress,
+ IN UINT Length
+ );
+
+#if defined(_ALPHA_)
+
+/*++
+VOID
+NdisUnmapIoSpace(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN PVOID VirtualAddress,
+ IN UINT Length
+ )
+--*/
+#define NdisUnmapIoSpace(Handle,VirtualAddress,Length) {}
+
+#else
+
+/*++
+VOID
+NdisUnmapIoSpace(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN PVOID VirtualAddress,
+ IN UINT Length
+ )
+--*/
+#define NdisUnmapIoSpace(Handle,VirtualAddress,Length) \
+ MmUnmapIoSpace((VirtualAddress), (Length));
+
+#endif
+
+EXPORT
+VOID
+NdisInitializeInterrupt(
+ OUT PNDIS_STATUS Status,
+ IN OUT PNDIS_INTERRUPT Interrupt,
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN PNDIS_INTERRUPT_SERVICE InterruptServiceRoutine,
+ IN PVOID InterruptContext,
+ IN PNDIS_DEFERRED_PROCESSING DeferredProcessingRoutine,
+ IN UINT InterruptVector,
+ IN UINT InterruptLevel,
+ IN BOOLEAN SharedInterrupt,
+ IN NDIS_INTERRUPT_MODE InterruptMode
+ );
+
+EXPORT
+VOID
+NdisRemoveInterrupt(
+ IN PNDIS_INTERRUPT Interrupt
+ );
+
+/*++
+BOOLEAN
+NdisSynchronizeWithInterrupt(
+ IN PNDIS_INTERRUPT Interrupt,
+ IN PVOID SynchronizeFunction,
+ IN PVOID SynchronizeContext
+ )
+--*/
+
+#define NdisSynchronizeWithInterrupt(Interrupt,Function,Context) \
+ KeSynchronizeExecution( \
+ (Interrupt)->InterruptObject,\
+ (PKSYNCHRONIZE_ROUTINE)Function,\
+ Context \
+ )
+
+//
+// Physical Mapping
+//
+
+//
+// VOID
+// NdisStartBufferPhysicalMapping(
+// IN NDIS_HANDLE NdisAdapterHandle,
+// IN PNDIS_BUFFER Buffer,
+// IN ULONG PhysicalMapRegister,
+// IN BOOLEAN WriteToDevice,
+// OUT PNDIS_PHYSICAL_ADDRESS_UNIT PhysicalAddressArray,
+// OUT PUINT ArraySize
+// );
+//
+
+#define NdisStartBufferPhysicalMapping( \
+ _NdisAdapterHandle, \
+ _Buffer, \
+ _PhysicalMapRegister, \
+ _Write, \
+ _PhysicalAddressArray, \
+ _ArraySize \
+ ) \
+{ \
+ PNDIS_ADAPTER_BLOCK _AdaptP = (PNDIS_ADAPTER_BLOCK)(_NdisAdapterHandle); \
+ PHYSICAL_ADDRESS _LogicalAddress; \
+ PUCHAR _VirtualAddress; \
+ ULONG _LengthRemaining; \
+ ULONG _LengthMapped; \
+ UINT _CurrentArrayLocation; \
+ _VirtualAddress = MmGetMdlVirtualAddress(_Buffer); \
+ _LengthRemaining = MmGetMdlByteCount(_Buffer); \
+ _CurrentArrayLocation = 0; \
+ while (_LengthRemaining > 0) { \
+ _LengthMapped = _LengthRemaining; \
+ _LogicalAddress = IoMapTransfer( \
+ NULL, \
+ _Buffer, \
+ _AdaptP->MapRegisters[_PhysicalMapRegister].MapRegister, \
+ _VirtualAddress, \
+ &_LengthMapped, \
+ _Write); \
+ _PhysicalAddressArray[_CurrentArrayLocation].PhysicalAddress = _LogicalAddress; \
+ _PhysicalAddressArray[_CurrentArrayLocation].Length = _LengthMapped; \
+ _LengthRemaining -= _LengthMapped; \
+ _VirtualAddress += _LengthMapped; \
+ ++_CurrentArrayLocation; \
+ } \
+ _AdaptP->MapRegisters[_PhysicalMapRegister].WriteToDevice = _Write; \
+ *(_ArraySize) = _CurrentArrayLocation; \
+}
+
+
+//
+// VOID
+// NdisCompleteBufferPhysicalMapping(
+// IN NDIS_HANDLE NdisAdapterHandle,
+// IN PNDIS_BUFFER Buffer,
+// IN ULONG PhysicalMapRegister
+// );
+//
+
+#define NdisCompleteBufferPhysicalMapping( \
+ NdisAdapterHandle, \
+ Buffer, \
+ PhysicalMapRegister \
+ ) \
+{ \
+ PNDIS_ADAPTER_BLOCK _AdaptP = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle; \
+ IoFlushAdapterBuffers( \
+ NULL, \
+ Buffer, \
+ _AdaptP->MapRegisters[PhysicalMapRegister].MapRegister, \
+ MmGetMdlVirtualAddress(Buffer), \
+ MmGetMdlByteCount(Buffer), \
+ _AdaptP->MapRegisters[PhysicalMapRegister].WriteToDevice); \
+}
diff --git a/private/ntos/ndis/ndis30/ndismain.h b/private/ntos/ndis/ndis30/ndismain.h
new file mode 100644
index 000000000..b96557a19
--- /dev/null
+++ b/private/ntos/ndis/ndis30/ndismain.h
@@ -0,0 +1,1976 @@
+//
+// Indicate that we're building for NT. NDIS_NT is always used for
+// miniport builds.
+//
+
+#define NDIS_NT 1
+
+#if defined(NDIS_DOS)
+#undef NDIS_DOS
+#endif
+
+
+//
+// Define status codes and event log codes.
+//
+
+#include <ntstatus.h>
+#include <netevent.h>
+
+//
+// Define a couple of extra types.
+//
+
+#if !defined(_WINDEF_) // these are defined in windows.h too
+typedef signed int INT, *PINT;
+typedef unsigned int UINT, *PUINT;
+#endif
+
+typedef UNICODE_STRING NDIS_STRING, *PNDIS_STRING;
+
+
+//
+// Portability extentions
+//
+
+#define NDIS_INIT_FUNCTION(_F) alloc_text(INIT,_F)
+#define NDIS_PAGABLE_FUNCTION(_F)
+
+
+//
+// This file contains the definition of an NDIS_OID as
+// well as #defines for all the current OID values.
+//
+
+#include <ntddndis.h>
+
+
+//
+// Ndis defines for configuration manager data structures
+//
+
+typedef CM_MCA_POS_DATA NDIS_MCA_POS_DATA, *PNDIS_MCA_POS_DATA;
+typedef CM_EISA_SLOT_INFORMATION NDIS_EISA_SLOT_INFORMATION,
+ *PNDIS_EISA_SLOT_INFORMATION;
+typedef CM_EISA_FUNCTION_INFORMATION NDIS_EISA_FUNCTION_INFORMATION,
+ *PNDIS_EISA_FUNCTION_INFORMATION;
+
+//
+// Define an exported function.
+//
+#if defined(NDIS_WRAPPER)
+#define EXPORT
+#else
+#define EXPORT DECLSPEC_IMPORT
+#endif
+
+//
+// Memory manipulation functions.
+//
+
+#define NdisMoveMemory(Destination,Source,Length) RtlCopyMemory(Destination,Source,Length)
+#define NdisZeroMemory(Destination,Length) RtlZeroMemory(Destination,Length)
+#define NdisRetrieveUlong(Destination,Source) RtlRetrieveUlong(Destination,Source)
+#define NdisStoreUlong(Destination,Value) RtlStoreUlong(Destination,Value)
+
+#define NDIS_STRING_CONST(x) {sizeof(L##x)-2, sizeof(L##x), L##x}
+
+//
+// On a MIPS machine, I/O mapped memory can't be accessed with
+// the Rtl routines.
+//
+
+#if defined(_M_IX86)
+
+#define NdisMoveMappedMemory(Destination,Source,Length) RtlCopyMemory(Destination,Source,Length)
+#define NdisZeroMappedMemory(Destination,Length) RtlZeroMemory(Destination,Length)
+
+#elif defined(_M_MRX000)
+
+#define NdisMoveMappedMemory(Destination,Source,Length) \
+{ \
+ PUCHAR _Src = (Source); \
+ PUCHAR _Dest = (Destination); \
+ PUCHAR _End = _Dest + (Length); \
+ while (_Dest < _End) { \
+ *_Dest++ = *_Src++; \
+ } \
+}
+#define NdisZeroMappedMemory(Destination,Length) \
+{ \
+ PUCHAR _Dest = (Destination); \
+ PUCHAR _End = _Dest + (Length); \
+ while (_Dest < _End) { \
+ *_Dest++ = 0; \
+ } \
+}
+
+#elif defined(_PPC_)
+
+#define NdisMoveMappedMemory(Destination,Source,Length) RtlCopyMemory32( Destination, Source, Length );
+#define NdisZeroMappedMemory(Destination,Length) \
+{ \
+ PUCHAR _Dest = (Destination); \
+ PUCHAR _End = _Dest + (Length); \
+ while (_Dest < _End) { \
+ *_Dest++ = 0; \
+ } \
+}
+
+#elif defined(_ALPHA_)
+
+#define NdisMoveMappedMemory(Destination,Source,Length) \
+{ \
+ PUCHAR _Src = (Source); \
+ PUCHAR _Dest = (Destination); \
+ PUCHAR _End = _Dest + (Length); \
+ while (_Dest < _End) \
+ { \
+ NdisReadRegisterUchar(_Src, _Dest); \
+ _Src++; \
+ _Dest++; \
+ } \
+}
+#define NdisZeroMappedMemory(Destination,Length) \
+{ \
+ PUCHAR _Dest = (Destination); \
+ PUCHAR _End = _Dest + (Length); \
+ while (_Dest < _End) { \
+ NdisWriteRegisterUchar(_Dest,0); \
+ _Dest++; \
+ } \
+}
+
+#endif
+
+
+//
+// On Mips and Intel systems, these are the same. On Alpha, they are different.
+//
+
+#if defined(_ALPHA_)
+
+#define NdisMoveToMappedMemory(Destination,Source,Length) WRITE_REGISTER_BUFFER_UCHAR(Destination,Source,Length)
+#define NdisMoveFromMappedMemory(Destination,Source,Length) READ_REGISTER_BUFFER_UCHAR(Source,Destination,Length)
+
+#else
+
+#define NdisMoveToMappedMemory(Destination,Source,Length) NdisMoveMappedMemory(Destination,Source,Length)
+#define NdisMoveFromMappedMemory(Destination,Source,Length) NdisMoveMappedMemory(Destination,Source,Length)
+
+#endif
+
+
+//
+// definition of the basic spin lock structure
+//
+
+typedef struct _NDIS_SPIN_LOCK {
+ KSPIN_LOCK SpinLock;
+ KIRQL OldIrql;
+} NDIS_SPIN_LOCK, * PNDIS_SPIN_LOCK;
+
+
+typedef PVOID NDIS_HANDLE, *PNDIS_HANDLE;
+
+typedef int NDIS_STATUS, *PNDIS_STATUS; // note default size
+
+#define NdisInterruptLatched Latched
+#define NdisInterruptLevelSensitive LevelSensitive
+typedef KINTERRUPT_MODE NDIS_INTERRUPT_MODE, *PNDIS_INTERRUPT_MODE;
+
+//
+// Configuration definitions
+//
+
+//
+// Possible data types
+//
+
+typedef enum _NDIS_PARAMETER_TYPE {
+ NdisParameterInteger,
+ NdisParameterHexInteger,
+ NdisParameterString,
+ NdisParameterMultiString
+} NDIS_PARAMETER_TYPE, *PNDIS_PARAMETER_TYPE;
+
+//
+// To store configuration information
+//
+typedef struct _NDIS_CONFIGURATION_PARAMETER {
+ NDIS_PARAMETER_TYPE ParameterType;
+ union {
+ ULONG IntegerData;
+ NDIS_STRING StringData;
+ } ParameterData;
+} NDIS_CONFIGURATION_PARAMETER, *PNDIS_CONFIGURATION_PARAMETER;
+
+
+//
+// Definitions for the "ProcessorType" keyword
+//
+typedef enum _NDIS_PROCESSOR_TYPE {
+ NdisProcessorX86,
+ NdisProcessorMips,
+ NdisProcessorAlpha,
+ NdisProcessorPpc
+} NDIS_PROCESSOR_TYPE, *PNDIS_PROCESSOR_TYPE;
+
+//
+// Definitions for the "Environment" keyword
+//
+typedef enum _NDIS_ENVIRONMENT_TYPE {
+ NdisEnvironmentWindows,
+ NdisEnvironmentWindowsNt
+} NDIS_ENVIRONMENT_TYPE, *PNDIS_ENVIRONMENT_TYPE;
+
+
+//
+// Possible Hardware Architecture. Define these to
+// match the HAL INTERFACE_TYPE enum.
+//
+typedef enum _NDIS_INTERFACE_TYPE {
+ NdisInterfaceInternal = Internal,
+ NdisInterfaceIsa = Isa,
+ NdisInterfaceEisa = Eisa,
+ NdisInterfaceMca = MicroChannel,
+ NdisInterfaceTurboChannel = TurboChannel,
+ NdisInterfacePci = PCIBus,
+ NdisInterfacePcMcia = PCMCIABus
+} NDIS_INTERFACE_TYPE, *PNDIS_INTERFACE_TYPE;
+
+//
+// Definition for shutdown handler
+//
+
+typedef
+VOID
+(*ADAPTER_SHUTDOWN_HANDLER) (
+ IN PVOID ShutdownContext
+ );
+
+//
+// Stuff for PCI configuring
+//
+
+typedef CM_PARTIAL_RESOURCE_LIST NDIS_RESOURCE_LIST, *PNDIS_RESOURCE_LIST;
+
+
+//
+// The structure passed up on a WAN_LINE_UP indication
+//
+
+typedef struct _NDIS_WAN_LINE_UP {
+ ULONG LinkSpeed; // 100 bps units
+ ULONG MaximumTotalSize; // suggested max for send packets
+ NDIS_WAN_QUALITY Quality;
+ USHORT SendWindow; // suggested by the MAC
+ UCHAR Address[1]; // variable length, depends on address type
+} NDIS_WAN_LINE_UP, *PNDIS_WAN_LINE_UP;
+
+//
+// The structure passed up on a WAN_LINE_DOWN indication
+//
+
+typedef struct _NDIS_WAN_LINE_DOWN {
+ UCHAR Address[1]; // variable length, depends on address type
+} NDIS_WAN_LINE_DOWN, *PNDIS_WAN_LINE_DOWN;
+
+//
+// The structure passed up on a WAN_FRAGMENT indication
+//
+
+typedef struct _NDIS_WAN_FRAGMENT {
+ UCHAR Address[1]; // variable length, depends on address type
+} NDIS_WAN_FRAGMENT, *PNDIS_WAN_FRAGMENT;
+
+
+//
+// DMA Channel information
+//
+typedef struct _NDIS_DMA_DESCRIPTION {
+ BOOLEAN DemandMode;
+ BOOLEAN AutoInitialize;
+ BOOLEAN DmaChannelSpecified;
+ DMA_WIDTH DmaWidth;
+ DMA_SPEED DmaSpeed;
+ ULONG DmaPort;
+ ULONG DmaChannel;
+} NDIS_DMA_DESCRIPTION, *PNDIS_DMA_DESCRIPTION;
+
+//
+// Internal structure representing an NDIS DMA channel
+//
+typedef struct _NDIS_DMA_BLOCK {
+ PVOID MapRegisterBase;
+ KEVENT AllocationEvent;
+ PADAPTER_OBJECT SystemAdapterObject;
+ BOOLEAN InProgress;
+} NDIS_DMA_BLOCK, *PNDIS_DMA_BLOCK;
+
+
+//
+// Ndis Buffer is actually an Mdl
+//
+typedef MDL NDIS_BUFFER, * PNDIS_BUFFER;
+
+//
+// Include an incomplete type for NDIS_PACKET structure so that
+// function types can refer to a type to be defined later.
+//
+struct _NDIS_PACKET;
+
+//
+// packet pool definition
+//
+typedef struct _NDIS_PACKET_POOL {
+ NDIS_SPIN_LOCK SpinLock;
+ struct _NDIS_PACKET *FreeList; // linked list of free slots in pool
+ UINT PacketLength; // amount needed in each packet
+ UCHAR Buffer[1]; // actual pool memory
+} NDIS_PACKET_POOL, * PNDIS_PACKET_POOL;
+
+
+//
+// wrapper-specific part of a packet
+//
+
+typedef struct _NDIS_PACKET_PRIVATE {
+ UINT PhysicalCount; // number of physical pages in packet.
+ UINT TotalLength; // Total amount of data in the packet.
+ PNDIS_BUFFER Head; // first buffer in the chain
+ PNDIS_BUFFER Tail; // last buffer in the chain
+
+ // if Head is NULL the chain is empty; Tail doesn't have to be NULL also
+
+ PNDIS_PACKET_POOL Pool; // so we know where to free it back to
+ UINT Count;
+ ULONG Flags;
+ BOOLEAN ValidCounts;
+} NDIS_PACKET_PRIVATE, * PNDIS_PACKET_PRIVATE;
+
+
+//
+// packet definition
+//
+
+typedef struct _NDIS_PACKET {
+ NDIS_PACKET_PRIVATE Private;
+
+ union {
+
+ struct {
+ UCHAR MiniportReserved[8];
+ UCHAR WrapperReserved[8];
+ };
+
+ struct {
+ UCHAR MacReserved[16];
+ };
+
+ };
+
+ UCHAR ProtocolReserved[1];
+
+} NDIS_PACKET, * PNDIS_PACKET;
+
+//
+// Request types used by NdisRequest; constants are added for
+// all entry points in the MAC, for those that want to create
+// their own internal requests.
+//
+
+typedef enum _NDIS_REQUEST_TYPE {
+ NdisRequestQueryInformation,
+ NdisRequestSetInformation,
+ NdisRequestQueryStatistics,
+ NdisRequestOpen,
+ NdisRequestClose,
+ NdisRequestSend,
+ NdisRequestTransferData,
+ NdisRequestReset,
+ NdisRequestGeneric1,
+ NdisRequestGeneric2,
+ NdisRequestGeneric3,
+ NdisRequestGeneric4
+} NDIS_REQUEST_TYPE, *PNDIS_REQUEST_TYPE;
+
+
+//
+// Structure of requests sent via NdisRequest
+//
+
+typedef struct _NDIS_REQUEST {
+ UCHAR MacReserved[16];
+ NDIS_REQUEST_TYPE RequestType;
+ union _DATA {
+
+ struct _QUERY_INFORMATION {
+ NDIS_OID Oid;
+ PVOID InformationBuffer;
+ UINT InformationBufferLength;
+ UINT BytesWritten;
+ UINT BytesNeeded;
+ } QUERY_INFORMATION;
+
+ struct _SET_INFORMATION {
+ NDIS_OID Oid;
+ PVOID InformationBuffer;
+ UINT InformationBufferLength;
+ UINT BytesRead;
+ UINT BytesNeeded;
+ } SET_INFORMATION;
+
+ } DATA;
+
+} NDIS_REQUEST, *PNDIS_REQUEST;
+
+//
+// Definitions for physical address.
+//
+
+typedef PHYSICAL_ADDRESS NDIS_PHYSICAL_ADDRESS, *PNDIS_PHYSICAL_ADDRESS;
+typedef struct _NDIS_PHYSICAL_ADDRESS_UNIT {
+ NDIS_PHYSICAL_ADDRESS PhysicalAddress;
+ UINT Length;
+} NDIS_PHYSICAL_ADDRESS_UNIT, *PNDIS_PHYSICAL_ADDRESS_UNIT;
+
+
+/*++
+
+ULONG
+NdisGetPhysicalAddressHigh(
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress
+ );
+
+--*/
+
+#define NdisGetPhysicalAddressHigh(_PhysicalAddress)\
+ ((_PhysicalAddress).HighPart)
+
+/*++
+
+VOID
+NdisSetPhysicalAddressHigh(
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress,
+ IN ULONG Value
+ );
+
+--*/
+
+#define NdisSetPhysicalAddressHigh(_PhysicalAddress, _Value)\
+ ((_PhysicalAddress).HighPart) = (_Value)
+
+
+/*++
+
+ULONG
+NdisGetPhysicalAddressLow(
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress
+ );
+
+--*/
+
+#define NdisGetPhysicalAddressLow(_PhysicalAddress) \
+ ((_PhysicalAddress).LowPart)
+
+
+/*++
+
+VOID
+NdisSetPhysicalAddressLow(
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress,
+ IN ULONG Value
+ );
+
+--*/
+
+#define NdisSetPhysicalAddressLow(_PhysicalAddress, _Value) \
+ ((_PhysicalAddress).LowPart) = (_Value)
+
+//
+// Macro to initialize an NDIS_PHYSICAL_ADDRESS constant
+//
+
+#define NDIS_PHYSICAL_ADDRESS_CONST(_Low, _High) \
+ { (ULONG)(_Low), (LONG)(_High) }
+
+
+//
+// block used for references...
+//
+
+typedef struct _REFERENCE {
+ NDIS_SPIN_LOCK SpinLock;
+ USHORT ReferenceCount;
+ BOOLEAN Closing;
+} REFERENCE, * PREFERENCE;
+
+
+//
+// This holds a map register entry.
+//
+
+typedef struct _MAP_REGISTER_ENTRY {
+ PVOID MapRegister;
+ BOOLEAN WriteToDevice;
+} MAP_REGISTER_ENTRY, * PMAP_REGISTER_ENTRY;
+
+//
+// Types of Memory (not mutually exclusive)
+//
+
+#define NDIS_MEMORY_CONTIGUOUS 0x00000001
+#define NDIS_MEMORY_NONCACHED 0x00000002
+
+//
+// Open options
+//
+#define NDIS_OPEN_RECEIVE_NOT_REENTRANT 0x00000001
+
+//
+// NDIS_STATUS values
+//
+
+#define NDIS_STATUS_SUCCESS ((NDIS_STATUS) STATUS_SUCCESS)
+#define NDIS_STATUS_PENDING ((NDIS_STATUS) STATUS_PENDING)
+#define NDIS_STATUS_NOT_RECOGNIZED ((NDIS_STATUS)0x00010001L)
+#define NDIS_STATUS_NOT_COPIED ((NDIS_STATUS)0x00010002L)
+#define NDIS_STATUS_NOT_ACCEPTED ((NDIS_STATUS)0x00010003L)
+
+#define NDIS_STATUS_ONLINE ((NDIS_STATUS)0x40010003L)
+#define NDIS_STATUS_RESET_START ((NDIS_STATUS)0x40010004L)
+#define NDIS_STATUS_RESET_END ((NDIS_STATUS)0x40010005L)
+#define NDIS_STATUS_RING_STATUS ((NDIS_STATUS)0x40010006L)
+#define NDIS_STATUS_CLOSED ((NDIS_STATUS)0x40010007L)
+#define NDIS_STATUS_WAN_LINE_UP ((NDIS_STATUS)0x40010008L)
+#define NDIS_STATUS_WAN_LINE_DOWN ((NDIS_STATUS)0x40010009L)
+#define NDIS_STATUS_WAN_FRAGMENT ((NDIS_STATUS)0x4001000AL)
+
+#define NDIS_STATUS_NOT_RESETTABLE ((NDIS_STATUS)0x80010001L)
+#define NDIS_STATUS_SOFT_ERRORS ((NDIS_STATUS)0x80010003L)
+#define NDIS_STATUS_HARD_ERRORS ((NDIS_STATUS)0x80010004L)
+
+#define NDIS_STATUS_FAILURE ((NDIS_STATUS) STATUS_UNSUCCESSFUL)
+#define NDIS_STATUS_RESOURCES ((NDIS_STATUS) \
+ STATUS_INSUFFICIENT_RESOURCES)
+#define NDIS_STATUS_CLOSING ((NDIS_STATUS)0xC0010002L)
+#define NDIS_STATUS_BAD_VERSION ((NDIS_STATUS)0xC0010004L)
+#define NDIS_STATUS_BAD_CHARACTERISTICS ((NDIS_STATUS)0xC0010005L)
+#define NDIS_STATUS_ADAPTER_NOT_FOUND ((NDIS_STATUS)0xC0010006L)
+#define NDIS_STATUS_OPEN_FAILED ((NDIS_STATUS)0xC0010007L)
+#define NDIS_STATUS_DEVICE_FAILED ((NDIS_STATUS)0xC0010008L)
+#define NDIS_STATUS_MULTICAST_FULL ((NDIS_STATUS)0xC0010009L)
+#define NDIS_STATUS_MULTICAST_EXISTS ((NDIS_STATUS)0xC001000AL)
+#define NDIS_STATUS_MULTICAST_NOT_FOUND ((NDIS_STATUS)0xC001000BL)
+#define NDIS_STATUS_REQUEST_ABORTED ((NDIS_STATUS)0xC001000CL)
+#define NDIS_STATUS_RESET_IN_PROGRESS ((NDIS_STATUS)0xC001000DL)
+#define NDIS_STATUS_CLOSING_INDICATING ((NDIS_STATUS)0xC001000EL)
+#define NDIS_STATUS_NOT_SUPPORTED ((NDIS_STATUS)STATUS_NOT_SUPPORTED)
+#define NDIS_STATUS_INVALID_PACKET ((NDIS_STATUS)0xC001000FL)
+#define NDIS_STATUS_OPEN_LIST_FULL ((NDIS_STATUS)0xC0010010L)
+#define NDIS_STATUS_ADAPTER_NOT_READY ((NDIS_STATUS)0xC0010011L)
+#define NDIS_STATUS_ADAPTER_NOT_OPEN ((NDIS_STATUS)0xC0010012L)
+#define NDIS_STATUS_NOT_INDICATING ((NDIS_STATUS)0xC0010013L)
+#define NDIS_STATUS_INVALID_LENGTH ((NDIS_STATUS)0xC0010014L)
+#define NDIS_STATUS_INVALID_DATA ((NDIS_STATUS)0xC0010015L)
+#define NDIS_STATUS_BUFFER_TOO_SHORT ((NDIS_STATUS)0xC0010016L)
+#define NDIS_STATUS_INVALID_OID ((NDIS_STATUS)0xC0010017L)
+#define NDIS_STATUS_ADAPTER_REMOVED ((NDIS_STATUS)0xC0010018L)
+#define NDIS_STATUS_UNSUPPORTED_MEDIA ((NDIS_STATUS)0xC0010019L)
+#define NDIS_STATUS_GROUP_ADDRESS_IN_USE ((NDIS_STATUS)0xC001001AL)
+#define NDIS_STATUS_FILE_NOT_FOUND ((NDIS_STATUS)0xC001001BL)
+#define NDIS_STATUS_ERROR_READING_FILE ((NDIS_STATUS)0xC001001CL)
+#define NDIS_STATUS_ALREADY_MAPPED ((NDIS_STATUS)0xC001001DL)
+#define NDIS_STATUS_RESOURCE_CONFLICT ((NDIS_STATUS)0xC001001EL)
+#define NDIS_STATUS_NO_CABLE ((NDIS_STATUS)0xC001001FL)
+
+#define NDIS_STATUS_TOKEN_RING_OPEN_ERROR ((NDIS_STATUS)0xC0011000L)
+
+
+//
+// used in error logging
+//
+
+#define NDIS_ERROR_CODE ULONG
+
+#define NDIS_ERROR_CODE_RESOURCE_CONFLICT EVENT_NDIS_RESOURCE_CONFLICT
+#define NDIS_ERROR_CODE_OUT_OF_RESOURCES EVENT_NDIS_OUT_OF_RESOURCE
+#define NDIS_ERROR_CODE_HARDWARE_FAILURE EVENT_NDIS_HARDWARE_FAILURE
+#define NDIS_ERROR_CODE_ADAPTER_NOT_FOUND EVENT_NDIS_ADAPTER_NOT_FOUND
+#define NDIS_ERROR_CODE_INTERRUPT_CONNECT EVENT_NDIS_INTERRUPT_CONNECT
+#define NDIS_ERROR_CODE_DRIVER_FAILURE EVENT_NDIS_DRIVER_FAILURE
+#define NDIS_ERROR_CODE_BAD_VERSION EVENT_NDIS_BAD_VERSION
+#define NDIS_ERROR_CODE_TIMEOUT EVENT_NDIS_TIMEOUT
+#define NDIS_ERROR_CODE_NETWORK_ADDRESS EVENT_NDIS_NETWORK_ADDRESS
+#define NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION EVENT_NDIS_UNSUPPORTED_CONFIGURATION
+#define NDIS_ERROR_CODE_INVALID_VALUE_FROM_ADAPTER EVENT_NDIS_INVALID_VALUE_FROM_ADAPTER
+#define NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER EVENT_NDIS_MISSING_CONFIGURATION_PARAMETER
+#define NDIS_ERROR_CODE_BAD_IO_BASE_ADDRESS EVENT_NDIS_BAD_IO_BASE_ADDRESS
+#define NDIS_ERROR_CODE_RECEIVE_SPACE_SMALL EVENT_NDIS_RECEIVE_SPACE_SMALL
+#define NDIS_ERROR_CODE_ADAPTER_DISABLED EVENT_NDIS_ADAPTER_DISABLED
+
+
+//
+// Ndis Spin Locks
+//
+
+#if BINARY_COMPATIBLE
+
+EXPORT
+VOID
+NdisAllocateSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+EXPORT
+VOID
+NdisFreeSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+EXPORT
+VOID
+NdisAcquireSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+EXPORT
+VOID
+NdisReleaseSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+EXPORT
+VOID
+NdisDprAcquireSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+EXPORT
+VOID
+NdisDprReleaseSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+#else
+
+#define NdisAllocateSpinLock(_SpinLock) \
+ KeInitializeSpinLock(&(_SpinLock)->SpinLock)
+
+#define NdisFreeSpinLock(_SpinLock)
+
+#define NdisAcquireSpinLock(_SpinLock) \
+ KeAcquireSpinLock(&(_SpinLock)->SpinLock, &(_SpinLock)->OldIrql)
+
+#define NdisReleaseSpinLock(_SpinLock) \
+ KeReleaseSpinLock(&(_SpinLock)->SpinLock,(_SpinLock)->OldIrql)
+
+#define NdisDprAcquireSpinLock(_SpinLock) { \
+ KeAcquireSpinLockAtDpcLevel(&(_SpinLock)->SpinLock); \
+ (_SpinLock)->OldIrql = DISPATCH_LEVEL; \
+}
+
+#define NdisDprReleaseSpinLock(_SpinLock) \
+ KeReleaseSpinLockFromDpcLevel(&(_SpinLock)->SpinLock)
+
+#endif
+
+//
+// List manipulation
+//
+
+/*++
+
+VOID
+NdisInitializeListHead(
+ IN PLIST_ENTRY ListHead
+ );
+
+--*/
+#define NdisInitializeListHead(_ListHead) InitializeListHead(_ListHead)
+
+
+
+//
+// Configuration Requests
+//
+
+EXPORT
+VOID
+NdisOpenConfiguration(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE ConfigurationHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ );
+
+EXPORT
+VOID
+NdisReadConfiguration(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_CONFIGURATION_PARAMETER *ParameterValue,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING Keyword,
+ IN NDIS_PARAMETER_TYPE ParameterType
+ );
+
+EXPORT
+VOID
+NdisWriteConfiguration(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN PNDIS_STRING Keyword,
+ IN PNDIS_CONFIGURATION_PARAMETER ParameterValue
+ );
+
+EXPORT
+VOID
+NdisCloseConfiguration(
+ IN NDIS_HANDLE ConfigurationHandle
+ );
+
+EXPORT
+VOID
+NdisReadNetworkAddress(
+ OUT PNDIS_STATUS Status,
+ OUT PVOID * NetworkAddress,
+ OUT PUINT NetworkAddressLength,
+ IN NDIS_HANDLE ConfigurationHandle
+ );
+
+EXPORT
+VOID
+NdisReadBindingInformation(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_STRING * Binding,
+ IN NDIS_HANDLE ConfigurationHandle
+ );
+
+
+EXPORT
+VOID
+NdisReadEisaSlotInformation(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PUINT SlotNumber,
+ OUT PNDIS_EISA_FUNCTION_INFORMATION EisaData
+ );
+
+EXPORT
+VOID
+NdisReadEisaSlotInformationEx(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PUINT SlotNumber,
+ OUT PNDIS_EISA_FUNCTION_INFORMATION *EisaData,
+ OUT PUINT NumberOfFunctions
+ );
+
+EXPORT
+VOID
+NdisReadMcaPosInformation(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN PUINT ChannelNumber,
+ OUT PNDIS_MCA_POS_DATA McaData
+ );
+
+EXPORT
+ULONG
+NdisReadPciSlotInformation(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ );
+
+EXPORT
+ULONG
+NdisWritePciSlotInformation(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ );
+
+EXPORT
+NDIS_STATUS
+NdisPciAssignResources(
+ IN NDIS_HANDLE NdisMacHandle,
+ IN NDIS_HANDLE NdisWrapperHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SlotNumber,
+ OUT PNDIS_RESOURCE_LIST *AssignedResources
+ );
+
+//
+// Buffer Pool
+//
+
+EXPORT
+VOID
+NdisAllocateBufferPool(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE PoolHandle,
+ IN UINT NumberOfDescriptors
+ );
+
+EXPORT
+VOID
+NdisFreeBufferPool(
+ IN NDIS_HANDLE PoolHandle
+ );
+
+EXPORT
+VOID
+NdisAllocateBuffer(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_BUFFER * Buffer,
+ IN NDIS_HANDLE PoolHandle,
+ IN PVOID VirtualAddress,
+ IN UINT Length
+ );
+
+EXPORT
+VOID
+NdisCopyBuffer(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_BUFFER * Buffer,
+ IN NDIS_HANDLE PoolHandle,
+ IN PVOID MemoryDescriptor,
+ IN UINT Offset,
+ IN UINT Length
+ );
+
+
+#if BINARY_COMPATIBLE
+
+EXPORT
+VOID
+NdisFreeBuffer(
+ IN PNDIS_BUFFER Buffer
+ );
+
+EXPORT
+VOID
+NdisQueryBuffer(
+ IN PNDIS_BUFFER Buffer,
+ OUT PVOID *VirtualAddress OPTIONAL,
+ OUT PUINT Length
+ );
+
+EXPORT
+VOID
+NdisQueryBufferOffset(
+ IN PNDIS_BUFFER Buffer,
+ OUT PUINT Offset,
+ OUT PUINT Length
+ );
+
+#else
+
+#define NdisFreeBuffer(Buffer) IoFreeMdl(Buffer)
+
+#define NdisQueryBuffer(_Buffer, _VirtualAddress, _Length) \
+{ \
+ if ( ARGUMENT_PRESENT(_VirtualAddress) ) { \
+ *(PVOID *)(_VirtualAddress) = MmGetSystemAddressForMdl(_Buffer); \
+ } \
+ *(_Length) = MmGetMdlByteCount(_Buffer); \
+}
+
+#define NdisQueryBufferOffset(_Buffer, _Offset, _Length) \
+{ \
+ *(_Offset) = MmGetMdlByteOffset(_Buffer); \
+ *(_Length) = MmGetMdlByteCount(_Buffer); \
+}
+
+#endif
+
+
+//
+// This macro is used to determine how many physical pieces
+// an NDIS_BUFFER will take up when mapped.
+//
+
+#if BINARY_COMPATIBLE
+
+EXPORT
+ULONG
+NDIS_BUFFER_TO_SPAN_PAGES(
+ IN PNDIS_BUFFER Buffer
+ );
+
+EXPORT
+VOID
+NdisGetBufferPhysicalArraySize(
+ IN PNDIS_BUFFER Buffer,
+ OUT PUINT ArraySize
+ );
+
+#else
+
+#define NDIS_BUFFER_TO_SPAN_PAGES(_Buffer) \
+ (MmGetMdlByteCount(_Buffer)==0 ? \
+ 1 : \
+ (COMPUTE_PAGES_SPANNED(\
+ MmGetMdlVirtualAddress(_Buffer), \
+ MmGetMdlByteCount(_Buffer))))
+
+#define NdisGetBufferPhysicalArraySize(Buffer, ArraySize) \
+ (*(ArraySize) = NDIS_BUFFER_TO_SPAN_PAGES(Buffer))
+
+#endif
+
+/*++
+VOID
+NdisBufferGetSystemSpecific(
+ IN PNDIS_BUFFER Buffer,
+ OUT PVOID * SystemSpecific
+ );
+--*/
+
+#define NdisBufferGetSystemSpecific(Buffer, SystemSpecific) \
+ *(SystemSpecific) = (Buffer)
+
+
+/*++
+
+NDIS_BUFFER_LINKAGE(
+ IN PNDIS_BUFFER Buffer
+ );
+
+--*/
+
+#define NDIS_BUFFER_LINKAGE(Buffer) \
+ ((Buffer)->Next)
+
+
+/*++
+
+VOID
+NdisRecalculatePacketCounts(
+ IN OUT PNDIS_PACKET Packet
+ );
+
+--*/
+
+#define NdisRecalculatePacketCounts(Packet) { \
+ { \
+ PNDIS_BUFFER TmpBuffer = (Packet)->Private.Head; \
+ if (TmpBuffer) { \
+ while (TmpBuffer->Next) { \
+ TmpBuffer = TmpBuffer->Next; \
+ } \
+ (Packet)->Private.Tail = TmpBuffer; \
+ } \
+ (Packet)->Private.ValidCounts = FALSE; \
+ } \
+}
+
+
+/*++
+
+VOID
+NdisChainBufferAtFront(
+ IN OUT PNDIS_PACKET Packet,
+ IN OUT PNDIS_BUFFER Buffer
+ );
+
+--*/
+
+#define NdisChainBufferAtFront(Packet, Buffer) { \
+ PNDIS_BUFFER TmpBuffer = (Buffer); \
+\
+ for (;;) { \
+ if (TmpBuffer->Next == (PNDIS_BUFFER)NULL) \
+ break; \
+ TmpBuffer = TmpBuffer->Next; \
+ } \
+ if ((Packet)->Private.Head == (PNDIS_BUFFER)NULL) { \
+ (Packet)->Private.Tail = TmpBuffer; \
+ } \
+ TmpBuffer->Next = (Packet)->Private.Head; \
+ (Packet)->Private.Head = (Buffer); \
+ (Packet)->Private.ValidCounts = FALSE; \
+}
+
+/*++
+
+VOID
+NdisChainBufferAtBack(
+ IN OUT PNDIS_PACKET Packet,
+ IN OUT PNDIS_BUFFER Buffer
+ );
+
+--*/
+
+#define NdisChainBufferAtBack(Packet, Buffer) { \
+ PNDIS_BUFFER TmpBuffer = (Buffer); \
+\
+ for (;;) { \
+ if (TmpBuffer->Next == (PNDIS_BUFFER)NULL) \
+ break; \
+ TmpBuffer = TmpBuffer->Next; \
+ } \
+ if ((Packet)->Private.Head != (PNDIS_BUFFER)NULL) { \
+ (Packet)->Private.Tail->Next = (Buffer); \
+ } else { \
+ (Packet)->Private.Head = (Buffer); \
+ } \
+ (Packet)->Private.Tail = TmpBuffer; \
+ TmpBuffer->Next = (PNDIS_BUFFER)NULL; \
+ (Packet)->Private.ValidCounts = FALSE; \
+}
+
+EXPORT
+VOID
+NdisUnchainBufferAtFront(
+ IN OUT PNDIS_PACKET Packet,
+ OUT PNDIS_BUFFER * Buffer
+ );
+
+EXPORT
+VOID
+NdisUnchainBufferAtBack(
+ IN OUT PNDIS_PACKET Packet,
+ OUT PNDIS_BUFFER * Buffer
+ );
+
+
+/*++
+
+VOID
+NdisQueryPacket(
+ IN PNDIS_PACKET _Packet,
+ OUT PUINT _PhysicalBufferCount OPTIONAL,
+ OUT PUINT _BufferCount OPTIONAL,
+ OUT PNDIS_BUFFER * _FirstBuffer OPTIONAL,
+ OUT PUINT _TotalPacketLength OPTIONAL
+ );
+
+--*/
+
+#define NdisQueryPacket(_Packet, _PhysicalBufferCount, _BufferCount, _FirstBuffer, _TotalPacketLength) \
+{ \
+ \
+ if ((_FirstBuffer) != NULL) \
+ { \
+ PNDIS_BUFFER * __FirstBuffer = (_FirstBuffer); \
+ *(__FirstBuffer) = (_Packet)->Private.Head; \
+ } \
+ if ((_PhysicalBufferCount) || (_BufferCount) || (_TotalPacketLength)) { \
+ if (!(_Packet)->Private.ValidCounts) { \
+ PNDIS_BUFFER TmpBuffer = (_Packet)->Private.Head; \
+ UINT PTotalLength = 0, PPhysicalCount = 0, PAddedCount = 0; \
+ UINT PacketLength; \
+ \
+ while (TmpBuffer != (PNDIS_BUFFER)NULL) { \
+ NdisQueryBuffer(TmpBuffer, NULL, &PacketLength); \
+ PTotalLength += PacketLength; \
+ PPhysicalCount += NDIS_BUFFER_TO_SPAN_PAGES(TmpBuffer); \
+ ++PAddedCount; \
+ TmpBuffer = TmpBuffer->Next; \
+ } \
+ (_Packet)->Private.Count = PAddedCount; \
+ (_Packet)->Private.TotalLength = PTotalLength; \
+ (_Packet)->Private.PhysicalCount = PPhysicalCount; \
+ (_Packet)->Private.ValidCounts = TRUE; \
+ } \
+ if (_PhysicalBufferCount) \
+ { \
+ PUINT __PhysicalBufferCount = (_PhysicalBufferCount); \
+ *(__PhysicalBufferCount) = (_Packet)->Private.PhysicalCount; \
+ } \
+ if (_BufferCount) \
+ { \
+ PUINT __BufferCount = (_BufferCount); \
+ *(__BufferCount) = (_Packet)->Private.Count; \
+ } \
+ if (_TotalPacketLength) \
+ { \
+ PUINT __TotalPacketLength = (_TotalPacketLength); \
+ *(__TotalPacketLength) = (_Packet)->Private.TotalLength; \
+ } \
+ } \
+}
+
+
+/*++
+
+VOID
+NdisGetNextBuffer(
+ IN PNDIS_BUFFER CurrentBuffer,
+ OUT PNDIS_BUFFER * NextBuffer
+ );
+
+--*/
+
+#define NdisGetNextBuffer(CurrentBuffer, NextBuffer) {\
+ *(NextBuffer) = (CurrentBuffer)->Next; \
+}
+
+
+EXPORT
+VOID
+NdisCopyFromPacketToPacket(
+ IN PNDIS_PACKET Destination,
+ IN UINT DestinationOffset,
+ IN UINT BytesToCopy,
+ IN PNDIS_PACKET Source,
+ IN UINT SourceOffset,
+ OUT PUINT BytesCopied
+ );
+
+
+EXPORT
+NDIS_STATUS
+NdisAllocateMemory(
+ OUT PVOID *VirtualAddress,
+ IN UINT Length,
+ IN UINT MemoryFlags,
+ IN NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress
+ );
+
+EXPORT
+VOID
+NdisFreeMemory(
+ IN PVOID VirtualAddress,
+ IN UINT Length,
+ IN UINT MemoryFlags
+ );
+
+
+/*++
+VOID
+NdisStallExecution(
+ IN UINT MicrosecondsToStall
+ )
+--*/
+
+#define NdisStallExecution(MicroSecondsToStall) \
+ KeStallExecutionProcessor(MicroSecondsToStall)
+
+
+//
+// Simple I/O support
+//
+
+EXPORT
+VOID
+NdisOpenFile(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE FileHandle,
+ OUT PUINT FileLength,
+ IN PNDIS_STRING FileName,
+ IN NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress
+ );
+
+EXPORT
+VOID
+NdisCloseFile(
+ IN NDIS_HANDLE FileHandle
+ );
+
+EXPORT
+VOID
+NdisMapFile(
+ OUT PNDIS_STATUS Status,
+ OUT PVOID * MappedBuffer,
+ IN NDIS_HANDLE FileHandle
+ );
+
+EXPORT
+VOID
+NdisUnmapFile(
+ IN NDIS_HANDLE FileHandle
+ );
+
+
+//
+// Portability extensions
+//
+
+/*++
+VOID
+NdisFlushBuffer(
+ IN PNDIS_BUFFER Buffer,
+ IN BOOLEAN WriteToDevice
+ )
+--*/
+
+#define NdisFlushBuffer(Buffer,WriteToDevice) \
+ KeFlushIoBuffers((Buffer),!(WriteToDevice), TRUE)
+
+/*++
+ULONG
+NdisGetCacheFillSize(
+ )
+--*/
+#define NdisGetCacheFillSize() \
+ HalGetDmaAlignmentRequirement()
+
+//
+// This macro is used to convert a port number as the caller
+// thinks of it, to a port number as it should be passed to
+// READ/WRITE_PORT.
+//
+
+#define NDIS_PORT_TO_PORT(Handle,Port) (((PNDIS_ADAPTER_BLOCK)(Handle))->PortOffset + (Port))
+
+
+//
+// Write Port
+//
+
+/*++
+VOID
+NdisWritePortUchar(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Port,
+ IN UCHAR Data
+ )
+--*/
+#define NdisWritePortUchar(Handle,Port,Data) \
+ WRITE_PORT_UCHAR((PUCHAR)(NDIS_PORT_TO_PORT(Handle,Port)),(UCHAR)(Data))
+
+/*++
+VOID
+NdisWritePortUshort(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Port,
+ IN USHORT Data
+ )
+--*/
+#define NdisWritePortUshort(Handle,Port,Data) \
+ WRITE_PORT_USHORT((PUSHORT)(NDIS_PORT_TO_PORT(Handle,Port)),(USHORT)(Data))
+
+
+/*++
+VOID
+NdisWritePortUlong(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Port,
+ IN ULONG Data
+ )
+--*/
+#define NdisWritePortUlong(Handle,Port,Data) \
+ WRITE_PORT_ULONG((PULONG)(NDIS_PORT_TO_PORT(Handle,Port)),(ULONG)(Data))
+
+
+//
+// Write Port Buffers
+//
+
+/*++
+VOID
+NdisWritePortBufferUchar(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Port,
+ IN PUCHAR Buffer,
+ IN ULONG Length
+ )
+--*/
+#define NdisWritePortBufferUchar(Handle,Port,Buffer,Length) \
+ NdisRawWritePortBufferUchar(NDIS_PORT_TO_PORT((Handle),(Port)),(Buffer),(Length))
+
+/*++
+VOID
+NdisWritePortBufferUshort(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Port,
+ IN PUSHORT Buffer,
+ IN ULONG Length
+ )
+--*/
+#define NdisWritePortBufferUshort(Handle,Port,Buffer,Length) \
+ NdisRawWritePortBufferUshort(NDIS_PORT_TO_PORT((Handle),(Port)),(Buffer),(Length))
+
+
+/*++
+VOID
+NdisWritePortBufferUlong(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Port,
+ IN PULONG Buffer,
+ IN ULONG Length
+ )
+--*/
+#define NdisWritePortBufferUlong(Handle,Port,Buffer,Length) \
+ NdisRawWritePortBufferUlong(NDIS_PORT_TO_PORT((Handle),(Port)),(Buffer),(Length))
+
+
+//
+// Read Ports
+//
+
+/*++
+VOID
+NdisReadPortUchar(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Port,
+ OUT PUCHAR Data
+ )
+--*/
+#define NdisReadPortUchar(Handle,Port, Data) \
+ NdisRawReadPortUchar(NDIS_PORT_TO_PORT((Handle),(Port)),(Data))
+
+/*++
+VOID
+NdisReadPortUshort(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Port,
+ OUT PUSHORT Data
+ )
+--*/
+#define NdisReadPortUshort(Handle,Port,Data) \
+ NdisRawReadPortUshort(NDIS_PORT_TO_PORT((Handle),(Port)),(Data))
+
+
+/*++
+VOID
+NdisReadPortUlong(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Port,
+ OUT PULONG Data
+ )
+--*/
+#define NdisReadPortUlong(Handle,Port,Data) \
+ NdisRawReadPortUlong(NDIS_PORT_TO_PORT((Handle),(Port)),(Data))
+
+//
+// Read Buffer Ports
+//
+
+/*++
+VOID
+NdisReadPortBufferUchar(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Port,
+ OUT PUCHAR Buffer,
+ IN ULONG Length
+ )
+--*/
+#define NdisReadPortBufferUchar(Handle,Port,Buffer,Length) \
+ NdisRawReadPortBufferUchar(NDIS_PORT_TO_PORT((Handle),(Port)),(Buffer),(Length))
+
+/*++
+VOID
+NdisReadPortBufferUshort(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Port,
+ OUT PUSHORT Buffer,
+ IN ULONG Length
+ )
+--*/
+#define NdisReadPortBufferUshort(Handle,Port,Buffer,Length) \
+ NdisRawReadPortBufferUshort(NDIS_PORT_TO_PORT((Handle),(Port)),(Buffer),(Length))
+
+/*++
+VOID
+NdisReadPortBufferUlong(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Port,
+ OUT PULONG Buffer,
+ IN ULONG Length
+ )
+--*/
+#define NdisReadPortBufferUlong(Handle,Port,Buffer) \
+ NdisRawReadPortBufferUlong(NDIS_PORT_TO_PORT((Handle),(Port)),(Buffer),(Length))
+
+//
+// Raw Routines
+//
+
+//
+// Write Port Raw
+//
+
+/*++
+VOID
+NdisRawWritePortUchar(
+ IN ULONG Port,
+ IN UCHAR Data
+ )
+--*/
+#define NdisRawWritePortUchar(Port,Data) \
+ WRITE_PORT_UCHAR((PUCHAR)(Port),(UCHAR)(Data))
+
+/*++
+VOID
+NdisRawWritePortUshort(
+ IN ULONG Port,
+ IN USHORT Data
+ )
+--*/
+#define NdisRawWritePortUshort(Port,Data) \
+ WRITE_PORT_USHORT((PUSHORT)(Port),(USHORT)(Data))
+
+/*++
+VOID
+NdisRawWritePortUlong(
+ IN ULONG Port,
+ IN ULONG Data
+ )
+--*/
+#define NdisRawWritePortUlong(Port,Data) \
+ WRITE_PORT_ULONG((PULONG)(Port),(ULONG)(Data))
+
+
+//
+// Raw Write Port Buffers
+//
+
+/*++
+VOID
+NdisRawWritePortBufferUchar(
+ IN ULONG Port,
+ IN PUCHAR Buffer,
+ IN ULONG Length
+ )
+--*/
+#define NdisRawWritePortBufferUchar(Port,Buffer,Length) \
+ WRITE_PORT_BUFFER_UCHAR((PUCHAR)(Port),(PUCHAR)(Buffer),(Length))
+
+/*++
+VOID
+NdisRawWritePortBufferUshort(
+ IN ULONG Port,
+ IN PUSHORT Buffer,
+ IN ULONG Length
+ )
+--*/
+#if defined(_M_IX86)
+#define NdisRawWritePortBufferUshort(Port,Buffer,Length) \
+ WRITE_PORT_BUFFER_USHORT((PUSHORT)(Port),(PUSHORT)(Buffer),(Length))
+#else
+#define NdisRawWritePortBufferUshort(Port,Buffer,Length) \
+{ \
+ ULONG _Port = (ULONG)(Port); \
+ PUSHORT _Current = (Buffer); \
+ PUSHORT _End = _Current + (Length); \
+ for ( ; _Current < _End; ++_Current) { \
+ WRITE_PORT_USHORT((PUSHORT)_Port,*(UNALIGNED USHORT *)_Current); \
+ } \
+}
+#endif
+
+
+/*++
+VOID
+NdisRawWritePortBufferUlong(
+ IN ULONG Port,
+ IN PULONG Buffer,
+ IN ULONG Length
+ )
+--*/
+#if defined(_M_IX86)
+#define NdisRawWritePortBufferUlong(Port,Buffer,Length) \
+ WRITE_PORT_BUFFER_ULONG((PULONG)(Port),(PULONG)(Buffer),(Length))
+#else
+#define NdisRawWritePortBufferUlong(Port,Buffer,Length) \
+{ \
+ ULONG _Port = (ULONG)(Port); \
+ PULONG _Current = (Buffer); \
+ PULONG _End = _Current + (Length); \
+ for ( ; _Current < _End; ++_Current) { \
+ WRITE_PORT_ULONG((PULONG)_Port,*(UNALIGNED ULONG *)_Current); \
+ } \
+}
+#endif
+
+
+//
+// Raw Read Ports
+//
+
+/*++
+VOID
+NdisRawReadPortUchar(
+ IN ULONG Port,
+ OUT PUCHAR Data
+ )
+--*/
+#define NdisRawReadPortUchar(Port, Data) \
+ *(Data) = READ_PORT_UCHAR((PUCHAR)(Port))
+
+/*++
+VOID
+NdisRawReadPortUshort(
+ IN ULONG Port,
+ OUT PUSHORT Data
+ )
+--*/
+#define NdisRawReadPortUshort(Port,Data) \
+ *(Data) = READ_PORT_USHORT((PUSHORT)(Port))
+
+/*++
+VOID
+NdisRawReadPortUlong(
+ IN ULONG Port,
+ OUT PULONG Data
+ )
+--*/
+#define NdisRawReadPortUlong(Port,Data) \
+ *(Data) = READ_PORT_ULONG((PULONG)(Port))
+
+
+//
+// Raw Read Buffer Ports
+//
+
+/*++
+VOID
+NdisRawReadPortBufferUchar(
+ IN ULONG Port,
+ OUT PUCHAR Buffer,
+ IN ULONG Length
+ )
+--*/
+#define NdisRawReadPortBufferUchar(Port,Buffer,Length) \
+ READ_PORT_BUFFER_UCHAR((PUCHAR)(Port),(PUCHAR)(Buffer),(Length))
+
+
+/*++
+VOID
+NdisRawReadPortBufferUshort(
+ IN ULONG Port,
+ OUT PUSHORT Buffer,
+ IN ULONG Length
+ )
+--*/
+#if defined(_M_IX86)
+#define NdisRawReadPortBufferUshort(Port,Buffer,Length) \
+ READ_PORT_BUFFER_USHORT((PUSHORT)(Port),(PUSHORT)(Buffer),(Length))
+#else
+#define NdisRawReadPortBufferUshort(Port,Buffer,Length) \
+{ \
+ ULONG _Port = (ULONG)(Port); \
+ PUSHORT _Current = (Buffer); \
+ PUSHORT _End = _Current + (Length); \
+ for ( ; _Current < _End; ++_Current) { \
+ *(UNALIGNED USHORT *)_Current = READ_PORT_USHORT((PUSHORT)_Port); \
+ } \
+}
+#endif
+
+
+/*++
+VOID
+NdisRawReadPortBufferUlong(
+ IN ULONG Port,
+ OUT PULONG Buffer,
+ IN ULONG Length
+ )
+--*/
+#if defined(_M_IX86)
+#define NdisRawReadPortBufferUlong(Port,Buffer,Length) \
+ READ_PORT_BUFFER_ULONG((PULONG)(Port),(PULONG)(Buffer),(Length))
+#else
+#define NdisRawReadPortBufferUlong(Port,Buffer,Length) \
+{ \
+ ULONG _Port = (ULONG)(Port); \
+ PULONG _Current = (Buffer); \
+ PULONG _End = _Current + (Length); \
+ for ( ; _Current < _End; ++_Current) { \
+ *(UNALIGNED ULONG *)_Current = READ_PORT_ULONG((PULONG)_Port); \
+ } \
+}
+#endif
+
+
+//
+// Write Registers
+//
+
+/*++
+VOID
+NdisWriteRegisterUchar(
+ IN PUCHAR Register,
+ IN UCHAR Data
+ )
+--*/
+
+#if defined(_M_IX86)
+#define NdisWriteRegisterUchar(Register,Data) \
+ WRITE_REGISTER_UCHAR((Register),(Data))
+#else
+#define NdisWriteRegisterUchar(Register,Data) { \
+ WRITE_REGISTER_UCHAR((Register),(Data)); \
+ READ_REGISTER_UCHAR(Register); \
+ }
+#endif
+
+/*++
+VOID
+NdisWriteRegisterUshort(
+ IN PUSHORT Register,
+ IN USHORT Data
+ )
+--*/
+
+#if defined(_M_IX86)
+#define NdisWriteRegisterUshort(Register,Data) \
+ WRITE_REGISTER_USHORT((Register),(Data))
+#else
+#define NdisWriteRegisterUshort(Register,Data) { \
+ WRITE_REGISTER_USHORT((Register),(Data)); \
+ READ_REGISTER_USHORT(Register); \
+ }
+#endif
+
+/*++
+VOID
+NdisWriteRegisterUlong(
+ IN PULONG Register,
+ IN ULONG Data
+ )
+--*/
+
+#if defined(_M_IX86)
+#define NdisWriteRegisterUlong(Register,Data) \
+ WRITE_REGISTER_ULONG((Register),(Data))
+#else
+#define NdisWriteRegisterUlong(Register,Data) { \
+ WRITE_REGISTER_ULONG((Register),(Data)); \
+ READ_REGISTER_ULONG(Register); \
+ }
+#endif
+
+/*++
+VOID
+NdisReadRegisterUchar(
+ IN PUCHAR Register,
+ OUT PUCHAR Data
+ )
+--*/
+#if defined(_M_IX86)
+#define NdisReadRegisterUchar(Register,Data) \
+ *((PUCHAR)(Data)) = *(Register)
+#else
+#define NdisReadRegisterUchar(Register,Data) \
+ *(Data) = READ_REGISTER_UCHAR((PUCHAR)(Register))
+#endif
+
+/*++
+VOID
+NdisReadRegisterUshort(
+ IN PUSHORT Register,
+ OUT PUSHORT Data
+ )
+--*/
+#if defined(_M_IX86)
+#define NdisReadRegisterUshort(Register,Data) \
+ *((PUSHORT)(Data)) = *(Register)
+#else
+#define NdisReadRegisterUshort(Register,Data) \
+ *(Data) = READ_REGISTER_USHORT((PUSHORT)(Register))
+#endif
+
+/*++
+VOID
+NdisReadRegisterUlong(
+ IN PULONG Register,
+ OUT PULONG Data
+ )
+--*/
+#if defined(_M_IX86)
+#define NdisReadRegisterUlong(Register,Data) \
+ *((PULONG)(Data)) = *(Register)
+#else
+#define NdisReadRegisterUlong(Register,Data) \
+ *(Data) = READ_REGISTER_ULONG((PULONG)(Register))
+#endif
+
+#if BINARY_COMPATIBLE
+
+EXPORT
+BOOLEAN
+NdisEqualString(
+ IN PNDIS_STRING String1,
+ IN PNDIS_STRING String2,
+ IN BOOLEAN CaseInsensitive
+ );
+
+#else
+
+#define NdisEqualString(_String1,_String2,CaseInsensitive) \
+ RtlEqualUnicodeString((_String1), (_String2), CaseInsensitive)
+
+#endif
+
+EXPORT
+VOID
+NdisWriteErrorLogEntry(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN NDIS_ERROR_CODE ErrorCode,
+ IN ULONG NumberOfErrorValues,
+ ...
+ );
+
+#define NdisInitializeString(Destination,Source) \
+{\
+ PNDIS_STRING _D = (Destination);\
+ UCHAR *_S = (Source);\
+ WCHAR *_P;\
+ _D->Length = (strlen(_S)) * sizeof(WCHAR);\
+ _D->MaximumLength = _D->Length + sizeof(WCHAR);\
+ NdisAllocateMemory((PVOID *)&(_D->Buffer), _D->MaximumLength, 0, (-1));\
+ _P = _D->Buffer;\
+ while(*_S != '\0'){\
+ *_P = (WCHAR)(*_S);\
+ _S++;\
+ _P++;\
+ }\
+ *_P = UNICODE_NULL;\
+}
+
+#define NdisFreeString(String) NdisFreeMemory((String).Buffer, (String).MaximumLength, 0)
+
+#define NdisPrintString(String) DbgPrint("%ls",(String).Buffer)
+
+
+#if !defined(_ALPHA_)
+/*++
+
+ VOID
+ NdisCreateLookaheadBufferFromSharedMemory(
+ IN PVOID pSharedMemory,
+ IN UINT LookaheadLength,
+ OUT PVOID *pLookaheadBuffer
+ );
+
+--*/
+
+#define NdisCreateLookaheadBufferFromSharedMemory(_S, _L, _B) \
+ ((*(_B)) = (_S))
+
+/*++
+
+ VOID
+ NdisDestroyLookaheadBufferFromSharedMemory(
+ IN PVOID pLookaheadBuffer
+ );
+
+--*/
+
+#define NdisDestroyLookaheadBufferFromSharedMemory(_B)
+
+#else // Alpha
+
+EXPORT
+VOID
+NdisCreateLookaheadBufferFromSharedMemory(
+ IN PVOID pSharedMemory,
+ IN UINT LookaheadLength,
+ OUT PVOID *pLookaheadBuffer
+ );
+
+EXPORT
+VOID
+NdisDestroyLookaheadBufferFromSharedMemory(
+ IN PVOID pLookaheadBuffer
+ );
+
+#endif
+
+
+//
+// The following declarations are shared between ndismac.h and ndismini.h. They
+// are meant to be for internal use only. They should not be used directly by
+// miniport drivers.
+//
+
+//
+// declare these first since they point to each other
+//
+
+typedef struct _NDIS_WRAPPER_HANDLE NDIS_WRAPPER_HANDLE, * PNDIS_WRAPPER_HANDLE;
+typedef struct _NDIS_MAC_BLOCK NDIS_MAC_BLOCK, * PNDIS_MAC_BLOCK;
+typedef struct _NDIS_ADAPTER_BLOCK NDIS_ADAPTER_BLOCK, * PNDIS_ADAPTER_BLOCK;
+typedef struct _NDIS_PROTOCOL_BLOCK NDIS_PROTOCOL_BLOCK, * PNDIS_PROTOCOL_BLOCK;
+typedef struct _NDIS_OPEN_BLOCK NDIS_OPEN_BLOCK, * PNDIS_OPEN_BLOCK;
+
+//
+// Timers.
+//
+
+typedef
+VOID
+(*PNDIS_TIMER_FUNCTION) (
+ IN PVOID SystemSpecific1,
+ IN PVOID FunctionContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+typedef struct _NDIS_TIMER {
+ KTIMER Timer;
+ KDPC Dpc;
+} NDIS_TIMER, *PNDIS_TIMER;
+
+EXPORT
+VOID
+NdisSetTimer(
+ IN PNDIS_TIMER Timer,
+ IN UINT MillisecondsToDelay
+ );
+
+//
+// Function types for NDIS_PROTOCOL_CHARACTERISTICS
+//
+
+typedef
+VOID
+(*SEND_COMPLETE_HANDLER) (
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ );
+
+typedef
+VOID
+(*TRANSFER_DATA_COMPLETE_HANDLER) (
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ );
+
+typedef
+NDIS_STATUS
+(*RECEIVE_HANDLER) (
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookAheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+typedef
+VOID
+(*RECEIVE_COMPLETE_HANDLER) (
+ IN NDIS_HANDLE ProtocolBindingContext
+ );
+
+//
+// Wrapper initialization and termination.
+//
+
+EXPORT
+VOID
+NdisInitializeWrapper(
+ OUT PNDIS_HANDLE NdisWrapperHandle,
+ IN PVOID SystemSpecific1,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+EXPORT
+VOID
+NdisTerminateWrapper(
+ IN NDIS_HANDLE NdisWrapperHandle,
+ IN PVOID SystemSpecific
+ );
+
+//
+// Shared memory
+//
+
+#define NdisUpdateSharedMemory(_H, _L, _V, _P)
+
+//
+// System processor count
+//
+
+EXPORT
+CCHAR
+NdisSystemProcessorCount(
+ VOID
+ );
+
+//
+// Override bus number
+//
+
+EXPORT
+VOID
+NdisOverrideBusNumber(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN NDIS_HANDLE MiniportAdapterHandle OPTIONAL,
+ IN ULONG BusNumber
+ );
+
+
+EXPORT
+VOID
+NdisImmediateReadPortUchar(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ OUT PUCHAR Data
+ );
+
+EXPORT
+VOID
+NdisImmediateReadPortUshort(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ OUT PUSHORT Data
+ );
+
+EXPORT
+VOID
+NdisImmediateReadPortUlong(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ OUT PULONG Data
+ );
+
+EXPORT
+VOID
+NdisImmediateWritePortUchar(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ IN UCHAR Data
+ );
+
+EXPORT
+VOID
+NdisImmediateWritePortUshort(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ IN USHORT Data
+ );
+
+EXPORT
+VOID
+NdisImmediateWritePortUlong(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ IN ULONG Data
+ );
+
+EXPORT
+ULONG
+NdisImmediateReadPciSlotInformation(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ );
+
+EXPORT
+ULONG
+NdisImmediateWritePciSlotInformation(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ );
+
diff --git a/private/ntos/ndis/ndis30/ndismini.h b/private/ntos/ndis/ndis30/ndismini.h
new file mode 100644
index 000000000..38892897d
--- /dev/null
+++ b/private/ntos/ndis/ndis30/ndismini.h
@@ -0,0 +1,1216 @@
+#include <afilter.h>
+#include <efilter.h>
+#include <tfilter.h>
+#include <ffilter.h>
+
+#define NDIS_M_MAX_MULTI_LIST 32
+#define NDIS_M_MAX_LOOKAHEAD 526
+
+//
+// declare these first since they point to each other
+//
+
+typedef struct _NDIS_M_DRIVER_BLOCK NDIS_M_DRIVER_BLOCK, * PNDIS_M_DRIVER_BLOCK;
+typedef struct _NDIS_MINIPORT_BLOCK NDIS_MINIPORT_BLOCK, * PNDIS_MINIPORT_BLOCK;
+typedef struct _NDIS_M_PROTOCOL_BLOCK NDIS_M_PROTOCOL_BLOCK, * PNDIS_M_PROTOCOL_BLOCK;
+typedef struct _NDIS_M_OPEN_BLOCK NDIS_M_OPEN_BLOCK, * PNDIS_M_OPEN_BLOCK;
+
+
+//
+// Function types for NDIS_MINIPORT_CHARACTERISTICS
+//
+
+
+typedef
+BOOLEAN
+(*W_CHECK_FOR_HANG_HANDLER) (
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+typedef
+VOID
+(*W_DISABLE_INTERRUPT_HANDLER) (
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+typedef
+VOID
+(*W_ENABLE_INTERRUPT_HANDLER) (
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+typedef
+VOID
+(*W_HALT_HANDLER) (
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+typedef
+VOID
+(*W_HANDLE_INTERRUPT_HANDLER) (
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+typedef
+NDIS_STATUS
+(*W_INITIALIZE_HANDLER) (
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ );
+
+typedef
+VOID
+(*W_ISR_HANDLER) (
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueMiniportHandleInterrupt,
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+typedef
+NDIS_STATUS
+(*W_QUERY_INFORMATION_HANDLER) (
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+ );
+
+typedef
+NDIS_STATUS
+(*W_RECONFIGURE_HANDLER) (
+ OUT PNDIS_STATUS OpenErrorStatus,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ );
+
+typedef
+NDIS_STATUS
+(*W_RESET_HANDLER) (
+ OUT PBOOLEAN AddressingReset,
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+typedef
+NDIS_STATUS
+(*W_SEND_HANDLER) (
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET Packet,
+ IN UINT Flags
+ );
+
+typedef
+NDIS_STATUS
+(*W_SET_INFORMATION_HANDLER) (
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ );
+
+typedef
+NDIS_STATUS
+(*W_TRANSFER_DATA_HANDLER) (
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+ );
+
+typedef struct _NDIS_MINIPORT_CHARACTERISTICS {
+ UCHAR MajorNdisVersion;
+ UCHAR MinorNdisVersion;
+ UINT Reserved;
+ W_CHECK_FOR_HANG_HANDLER CheckForHangHandler;
+ W_DISABLE_INTERRUPT_HANDLER DisableInterruptHandler;
+ W_ENABLE_INTERRUPT_HANDLER EnableInterruptHandler;
+ W_HALT_HANDLER HaltHandler;
+ W_HANDLE_INTERRUPT_HANDLER HandleInterruptHandler;
+ W_INITIALIZE_HANDLER InitializeHandler;
+ W_ISR_HANDLER ISRHandler;
+ W_QUERY_INFORMATION_HANDLER QueryInformationHandler;
+ W_RECONFIGURE_HANDLER ReconfigureHandler;
+ W_RESET_HANDLER ResetHandler;
+ W_SEND_HANDLER SendHandler;
+ W_SET_INFORMATION_HANDLER SetInformationHandler;
+ W_TRANSFER_DATA_HANDLER TransferDataHandler;
+} NDIS_MINIPORT_CHARACTERISTICS, *PNDIS_MINIPORT_CHARACTERISTICS;
+
+//
+// one of these per Driver
+//
+
+struct _NDIS_M_DRIVER_BLOCK {
+ PNDIS_MINIPORT_BLOCK MiniportQueue; // queue of mini-ports for this driver
+ NDIS_HANDLE MiniportIdField;
+
+ REFERENCE Ref; // contains spinlock for MiniportQueue
+ UINT Length; // of this NDIS_DRIVER_BLOCK structure
+ NDIS_MINIPORT_CHARACTERISTICS MiniportCharacteristics; // handler addresses
+ PNDIS_WRAPPER_HANDLE NdisDriverInfo; // Driver information.
+ PNDIS_M_DRIVER_BLOCK NextDriver;
+ PNDIS_MAC_BLOCK FakeMac;
+ KEVENT MiniportsRemovedEvent; // used to find when all mini-ports are gone.
+ BOOLEAN Unloading; // TRUE if unloading
+
+};
+
+typedef struct _NDIS_MINIPORT_INTERRUPT {
+ PKINTERRUPT InterruptObject;
+ KSPIN_LOCK DpcCountLock;
+ PVOID MiniportIdField;
+ W_ISR_HANDLER MiniportIsr;
+ W_HANDLE_INTERRUPT_HANDLER MiniportDpc;
+ KDPC InterruptDpc;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ UCHAR DpcCount;
+ BOOLEAN Filler1;
+
+ //
+ // This is used to tell when all the Dpcs for the adapter are completed.
+ //
+
+ KEVENT DpcsCompletedEvent;
+
+ BOOLEAN SharedInterrupt;
+ BOOLEAN IsrRequested;
+
+} NDIS_MINIPORT_INTERRUPT, *PNDIS_MINIPORT_INTERRUPT;
+
+
+typedef struct _NDIS_MINIPORT_TIMER {
+ KTIMER Timer;
+ KDPC Dpc;
+ PNDIS_TIMER_FUNCTION MiniportTimerFunction;
+ PVOID MiniportTimerContext;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ struct _NDIS_MINIPORT_TIMER *NextDeferredTimer;
+} NDIS_MINIPORT_TIMER, *PNDIS_MINIPORT_TIMER;
+
+//
+// Pending NdisOpenAdapter() structure (for miniports only).
+//
+
+typedef struct _MINIPORT_PENDING_OPEN *PMINIPORT_PENDING_OPEN;
+
+typedef struct _MINIPORT_PENDING_OPEN {
+
+ PMINIPORT_PENDING_OPEN NextPendingOpen;
+ PNDIS_HANDLE NdisBindingHandle;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PVOID NewOpenP;
+ PVOID FileObject;
+ NDIS_HANDLE NdisProtocolHandle;
+ NDIS_HANDLE ProtocolBindingContext;
+ PNDIS_STRING AdapterName;
+ UINT OpenOptions;
+ PSTRING AddressingInformation;
+ BOOLEAN UsingEncapsulation;
+} MINIPORT_PENDING_OPEN;
+
+
+//
+// one of these per mini-port registered on a Driver
+//
+
+struct _NDIS_MINIPORT_BLOCK {
+ ULONG Flags; // used to distinquish between MACs and mini-ports
+ PDEVICE_OBJECT DeviceObject; // created by the wrapper
+ PNDIS_M_DRIVER_BLOCK DriverHandle; // pointer to our Driver block
+ NDIS_HANDLE MiniportAdapterContext; // context when calling mini-port functions
+ NDIS_STRING MiniportName; // how mini-port refers to us
+ PNDIS_M_OPEN_BLOCK OpenQueue; // queue of opens for this mini-port
+ PNDIS_MINIPORT_BLOCK NextMiniport; // used by driver's MiniportQueue
+ REFERENCE Ref; // contains spinlock for OpenQueue
+ BOOLEAN NormalInterrupts;
+ BOOLEAN ProcessingDeferred; // TRUE if processing deferred operations
+
+ //
+ // Synchronization stuff.
+ //
+ // The boolean is used to lock out several DPCs from running at the
+ // same time. The difficultly is if DPC A releases the spin lock
+ // and DPC B tries to run, we want to defer B until after A has
+ // exited.
+ //
+ BOOLEAN LockAcquired;
+ NDIS_SPIN_LOCK Lock;
+ PNDIS_MINIPORT_INTERRUPT Interrupt;
+
+ //
+ // Stuff that got deferred.
+ //
+ BOOLEAN RunDpc;
+ BOOLEAN Timeout;
+ BOOLEAN InAddDriver;
+ BOOLEAN InInitialize;
+ PNDIS_MINIPORT_TIMER RunTimer;
+ NDIS_TIMER DpcTimer;
+ NDIS_TIMER WakeUpDpcTimer;
+
+ //
+ // Holds media specific information
+ //
+ PETH_FILTER EthDB;
+ PTR_FILTER TrDB;
+ PFDDI_FILTER FddiDB;
+ PARC_FILTER ArcDB;
+ NDIS_MEDIUM MediaType;
+
+ UCHAR TrResetRing;
+ UCHAR ArcnetAddress;
+ BOOLEAN ArcnetBroadcastSet;
+ BOOLEAN SendCompleteCalled;
+
+ PVOID WrapperContext;
+
+ NDIS_HANDLE ArcnetBufferPool;
+ PARC_BUFFER_LIST ArcnetFreeBufferList;
+ PARC_BUFFER_LIST ArcnetUsedBufferList;
+
+ //
+ // Resource information
+ //
+ PCM_RESOURCE_LIST Resources;
+
+ //
+ // contains mini-port information
+ //
+ ULONG BusNumber;
+ NDIS_INTERFACE_TYPE BusType;
+ NDIS_INTERFACE_TYPE AdapterType;
+ BOOLEAN Master;
+
+ //
+ // Holds the map registers for this mini-port.
+ //
+ BOOLEAN Dma32BitAddresses;
+ PMAP_REGISTER_ENTRY MapRegisters;
+ ULONG PhysicalMapRegistersNeeded;
+ ULONG MaximumPhysicalMapping;
+
+ //
+ // These two are used temporarily while allocating
+ // the map registers.
+ //
+ KEVENT AllocationEvent;
+ UINT CurrentMapRegister;
+ PADAPTER_OBJECT SystemAdapterObject;
+
+ //
+ // Send information
+ //
+ PNDIS_PACKET FirstPacket; // This pointer serves two purposes;
+ // it is the head of the queue of ALL
+ // packets that have been sent to
+ // the miniport, it is also the head
+ // of the packets that have been sent
+ // down to the miniport by the wrapper.
+ PNDIS_PACKET LastPacket; // This is tail pointer for the global
+ // packet queue and this is the tail
+ // pointer to the queue of packets
+ // waiting to be sent to the miniport.
+ PNDIS_PACKET FirstPendingPacket; // This is head of the queue of packets
+ // waiting to be sent to miniport.
+ PNDIS_PACKET LastMiniportPacket; // This is the tail pointer of the
+ // queue of packets that have been
+ // sent to the miniport by the wrapper.
+ ULONG SendResourcesAvailable;
+ PNDIS_PACKET DeadPacket; // This pointer is used by the wake-up
+ // dpc to make sure that a packet that
+ // was sent to the miniport has been
+ // completed with-in a decent amount
+ // of time.
+ BOOLEAN AlreadyLoopedBack; // This flag is set if a packet that
+ // is waiting to be sent to the
+ // miniport has already been looped-
+ // back;
+
+
+ //
+ // Transfer data information
+ //
+ PNDIS_PACKET FirstTDPacket;
+ PNDIS_PACKET LastTDPacket;
+ PNDIS_PACKET LoopbackPacket;
+ UINT LoopbackPacketHeaderSize;
+
+ //
+ // Reset information
+ //
+ PNDIS_M_OPEN_BLOCK ResetRequested;
+ PNDIS_M_OPEN_BLOCK ResetInProgress;
+
+ //
+ // RequestInformation
+ //
+ KEVENT RequestEvent;
+ PNDIS_REQUEST FirstPendingRequest;
+ PNDIS_REQUEST LastPendingRequest;
+ PNDIS_REQUEST MiniportRequest;
+ NDIS_REQUEST InternalRequest;
+ NDIS_STATUS RequestStatus;
+ UINT MaximumLongAddresses;
+ UINT MaximumShortAddresses;
+ UINT CurrentLookahead;
+ UINT MaximumLookahead;
+ UINT MacOptions;
+ ULONG SupportedPacketFilters;
+ BOOLEAN NeedToUpdateEthAddresses;
+ BOOLEAN NeedToUpdatePacketFilter;
+ BOOLEAN NeedToUpdateFunctionalAddress;
+ BOOLEAN NeedToUpdateGroupAddress;
+ BOOLEAN NeedToUpdateFddiLongAddresses;
+ BOOLEAN NeedToUpdateFddiShortAddresses;
+ BOOLEAN RunDoRequests;
+ BOOLEAN ProcessOddDeferredStuff;
+ UCHAR MulticastBuffer[NDIS_M_MAX_MULTI_LIST][6];
+ UCHAR LookaheadBuffer[NDIS_M_MAX_LOOKAHEAD];
+
+ BOOLEAN BeingRemoved; // TRUE if mini-port is being removed
+ BOOLEAN HaltingMiniport; // TRUE if mini-port halt handler needs to be called
+
+ //
+ // Temp stuff for using the old NDIS functions
+ //
+ ULONG ChannelNumber;
+
+ PMINIPORT_PENDING_OPEN FirstPendingOpen;
+ PMINIPORT_PENDING_OPEN LastPendingOpen;
+ BOOLEAN PendingRequestTimeout;
+};
+
+#define MINIPORT_LOCK_ACQUIRED(_Miniport) ((_Miniport)->LockAcquired)
+
+
+//
+// one of these per open on an mini-port/protocol
+//
+
+struct _NDIS_M_OPEN_BLOCK {
+ PNDIS_M_DRIVER_BLOCK DriverHandle; // pointer to our driver
+ PNDIS_MINIPORT_BLOCK MiniportHandle; // pointer to our mini-port
+ PNDIS_PROTOCOL_BLOCK ProtocolHandle; // pointer to our protocol
+ PNDIS_OPEN_BLOCK FakeOpen; // Pointer to fake open block
+ NDIS_HANDLE ProtocolBindingContext; // context when calling ProtXX funcs
+ NDIS_HANDLE MiniportAdapterContext; // context when calling MiniportXX funcs
+ PNDIS_M_OPEN_BLOCK MiniportNextOpen; // used by mini-port's OpenQueue
+ PFILE_OBJECT FileObject; // created by operating system
+ BOOLEAN Closing; // TRUE when removing this struct
+ BOOLEAN UsingEthEncapsulation; // TRUE if running 802.3 on 878.2
+ NDIS_HANDLE CloseRequestHandle; // 0 indicates an internal close
+ NDIS_HANDLE FilterHandle;
+ NDIS_SPIN_LOCK SpinLock; // guards Closing
+ ULONG References;
+ UINT CurrentLookahead;
+ ULONG ProtocolOptions;
+
+ //
+ // These are optimizations for getting to driver routines. They are not
+ // necessary, but are here to save a dereference through the Driver block.
+ //
+
+ W_SEND_HANDLER SendHandler;
+ W_TRANSFER_DATA_HANDLER TransferDataHandler;
+
+ //
+ // These are optimizations for getting to PROTOCOL routines. They are not
+ // necessary, but are here to save a dereference through the PROTOCOL block.
+ //
+
+ SEND_COMPLETE_HANDLER SendCompleteHandler;
+ TRANSFER_DATA_COMPLETE_HANDLER TransferDataCompleteHandler;
+ RECEIVE_HANDLER ReceiveHandler;
+ RECEIVE_COMPLETE_HANDLER ReceiveCompleteHandler;
+
+};
+
+//
+// NOTE: THIS STRUCTURE MUST, MUST, MUST ALIGN WITH THE
+// NDIS_USER_OPEN_CONTEXT STRUCTURE defined in the wrapper.
+//
+typedef struct _NDIS_M_USER_OPEN_CONTEXT {
+ PDEVICE_OBJECT DeviceObject;
+ PNDIS_MINIPORT_BLOCK MiniportBlock;
+ ULONG OidCount;
+ PNDIS_OID OidArray;
+} NDIS_M_USER_OPEN_CONTEXT, *PNDIS_M_USER_OPEN_CONTEXT;
+
+
+typedef struct _NDIS_REQUEST_RESERVED {
+ PNDIS_REQUEST Next;
+ struct _NDIS_M_OPEN_BLOCK * Open;
+} NDIS_REQUEST_RESERVED, *PNDIS_REQUEST_RESERVED;
+
+#define PNDIS_RESERVED_FROM_PNDIS_REQUEST(_request) \
+ ((PNDIS_REQUEST_RESERVED)((_request)->MacReserved))
+
+
+BOOLEAN
+NdisMIsr(
+ IN PKINTERRUPT KInterrupt,
+ IN PVOID Context
+ );
+
+VOID
+NdisMDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+VOID
+NdisMDpcTimer(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+VOID
+NdisMWakeUpDpc(
+ PKDPC Dpc,
+ PVOID Context,
+ PVOID SystemContext1,
+ PVOID SystemContext2
+ );
+
+NDIS_STATUS
+NdisMChangeEthAddresses(
+ IN UINT OldAddressCount,
+ IN CHAR OldAddresses[][6],
+ IN UINT NewAddressCount,
+ IN CHAR NewAddresses[][6],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+NDIS_STATUS
+NdisMChangeClass(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+VOID
+NdisMCloseAction(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+NDIS_STATUS
+NdisMChangeFunctionalAddress(
+ IN TR_FUNCTIONAL_ADDRESS OldFunctionalAddress,
+ IN TR_FUNCTIONAL_ADDRESS NewFunctionalAddress,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+NDIS_STATUS
+NdisMChangeGroupAddress(
+ IN TR_FUNCTIONAL_ADDRESS OldGroupAddress,
+ IN TR_FUNCTIONAL_ADDRESS NewGroupAddress,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+NDIS_STATUS
+NdisMChangeFddiAddresses(
+ IN UINT oldLongAddressCount,
+ IN CHAR oldLongAddresses[][6],
+ IN UINT newLongAddressCount,
+ IN CHAR newLongAddresses[][6],
+ IN UINT oldShortAddressCount,
+ IN CHAR oldShortAddresses[][2],
+ IN UINT newShortAddressCount,
+ IN CHAR newShortAddresses[][2],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+NDIS_STATUS
+NdisMSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ );
+
+NDIS_STATUS
+NdisMTransferData(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+NDIS_STATUS
+NdisMArcTransferData(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+NDIS_STATUS
+NdisMReset(
+ IN NDIS_HANDLE NdisBindingHandle
+ );
+
+NDIS_STATUS
+NdisMRequest(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+
+//
+// Operating System Requests
+//
+
+EXPORT
+NDIS_STATUS
+NdisMAllocateMapRegisters(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN UINT DmaChannel,
+ IN BOOLEAN Dma32BitAddresses,
+ IN ULONG PhysicalMapRegistersNeeded,
+ IN ULONG MaximumPhysicalMapping
+ );
+
+EXPORT
+VOID
+NdisMFreeMapRegisters(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ );
+
+EXPORT
+NDIS_STATUS
+NdisMRegisterIoPortRange(
+ OUT PVOID *PortOffset,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN UINT InitialPort,
+ IN UINT NumberOfPorts
+ );
+
+EXPORT
+VOID
+NdisMDeregisterIoPortRange(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN UINT InitialPort,
+ IN UINT NumberOfPorts,
+ IN PVOID PortOffset
+ );
+
+EXPORT
+NDIS_STATUS
+NdisMMapIoSpace(
+ OUT PVOID * VirtualAddress,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress,
+ IN UINT Length
+ );
+
+EXPORT
+VOID
+NdisMUnmapIoSpace(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PVOID VirtualAddress,
+ IN UINT Length
+ );
+
+EXPORT
+NDIS_STATUS
+NdisMRegisterInterrupt(
+ OUT PNDIS_MINIPORT_INTERRUPT Interrupt,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN UINT InterruptVector,
+ IN UINT InterruptLevel,
+ IN BOOLEAN RequestIsr,
+ IN BOOLEAN SharedInterrupt,
+ IN NDIS_INTERRUPT_MODE InterruptMode
+ );
+
+EXPORT
+VOID
+NdisMDeregisterInterrupt(
+ IN PNDIS_MINIPORT_INTERRUPT Interrupt
+ );
+
+EXPORT
+BOOLEAN
+NdisMSynchronizeWithInterrupt(
+ IN PNDIS_MINIPORT_INTERRUPT Interrupt,
+ IN PVOID SynchronizeFunction,
+ IN PVOID SynchronizeContext
+ );
+
+
+EXPORT
+NDIS_STATUS
+NdisMQueryAdapterResources(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PNDIS_RESOURCE_LIST ResourceList,
+ IN OUT PUINT BufferSize
+ );
+
+//
+// Timers
+//
+
+/*++
+VOID
+NdisMSetTimer(
+ IN PNDIS_MINIPORT_TIMER Timer,
+ IN UINT MillisecondsToDelay
+ );
+--*/
+#define NdisMSetTimer(_Timer, _Delay) NdisSetTimer((PNDIS_TIMER)(_Timer), _Delay)
+
+EXPORT
+VOID
+NdisMInitializeTimer(
+ IN OUT PNDIS_MINIPORT_TIMER Timer,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_TIMER_FUNCTION TimerFunction,
+ IN PVOID FunctionContext
+ );
+
+EXPORT
+VOID
+NdisMCancelTimer(
+ IN PNDIS_MINIPORT_TIMER Timer,
+ OUT PBOOLEAN TimerCancelled
+ );
+
+//
+// Physical Mapping
+//
+
+#define NdisMStartBufferPhysicalMappingMacro( \
+ _MiniportAdapterHandle, \
+ _Buffer, \
+ _PhysicalMapRegister, \
+ _Write, \
+ _PhysicalAddressArray, \
+ _ArraySize \
+ ) \
+{ \
+ PNDIS_MINIPORT_BLOCK _Miniport = (PNDIS_MINIPORT_BLOCK)(_MiniportAdapterHandle); \
+ PHYSICAL_ADDRESS _LogicalAddress; \
+ PUCHAR _VirtualAddress; \
+ ULONG _LengthRemaining; \
+ ULONG _LengthMapped; \
+ UINT _CurrentArrayLocation; \
+ _VirtualAddress = MmGetMdlVirtualAddress(_Buffer); \
+ _LengthRemaining = MmGetMdlByteCount(_Buffer); \
+ _CurrentArrayLocation = 0; \
+ while (_LengthRemaining > 0) { \
+ _LengthMapped = _LengthRemaining; \
+ _LogicalAddress = \
+ IoMapTransfer( \
+ NULL, \
+ (_Buffer), \
+ _Miniport->MapRegisters[_PhysicalMapRegister].MapRegister, \
+ _VirtualAddress, \
+ &_LengthMapped, \
+ (_Write)); \
+ (_PhysicalAddressArray)[_CurrentArrayLocation].PhysicalAddress = _LogicalAddress; \
+ (_PhysicalAddressArray)[_CurrentArrayLocation].Length = _LengthMapped; \
+ _LengthRemaining -= _LengthMapped; \
+ _VirtualAddress += _LengthMapped; \
+ ++_CurrentArrayLocation; \
+ } \
+ _Miniport->MapRegisters[_PhysicalMapRegister].WriteToDevice = (_Write); \
+ *(_ArraySize) = _CurrentArrayLocation; \
+}
+
+#if BINARY_COMPATIBLE
+
+EXPORT
+VOID
+NdisMStartBufferPhysicalMapping(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG PhysicalMapRegister,
+ IN BOOLEAN WriteToDevice,
+ OUT PNDIS_PHYSICAL_ADDRESS_UNIT PhysicalAddressArray,
+ OUT PUINT ArraySize
+ );
+
+#else
+
+#define NdisMStartBufferPhysicalMapping( \
+ _MiniportAdapterHandle, \
+ _Buffer, \
+ _PhysicalMapRegister, \
+ _Write, \
+ _PhysicalAddressArray, \
+ _ArraySize \
+ ) \
+ NdisMStartBufferPhysicalMappingMacro( \
+ (_MiniportAdapterHandle), \
+ (_Buffer), \
+ (_PhysicalMapRegister), \
+ (_Write), \
+ (_PhysicalAddressArray), \
+ (_ArraySize) \
+ )
+
+#endif
+
+#define NdisMCompleteBufferPhysicalMappingMacro( \
+ _MiniportAdapterHandle, \
+ _Buffer, \
+ _PhysicalMapRegister \
+ ) { \
+ PNDIS_MINIPORT_BLOCK _Miniport = (PNDIS_MINIPORT_BLOCK)(_MiniportAdapterHandle); \
+ IoFlushAdapterBuffers( \
+ NULL, \
+ _Buffer, \
+ _Miniport->MapRegisters[_PhysicalMapRegister].MapRegister, \
+ MmGetMdlVirtualAddress(_Buffer), \
+ MmGetMdlByteCount(_Buffer), \
+ _Miniport->MapRegisters[_PhysicalMapRegister].WriteToDevice); \
+}
+
+#if BINARY_COMPATIBLE
+
+EXPORT
+VOID
+NdisMCompleteBufferPhysicalMapping(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG PhysicalMapRegister
+ );
+
+#else
+
+#define NdisMCompleteBufferPhysicalMapping( \
+ _MiniportAdapterHandle, \
+ _Buffer, \
+ _PhysicalMapRegister \
+ ) \
+ NdisMCompleteBufferPhysicalMappingMacro( \
+ (_MiniportAdapterHandle), \
+ (_Buffer), \
+ (_PhysicalMapRegister) \
+ )
+
+#endif
+
+//
+// Shared memory
+//
+
+EXPORT
+VOID
+NdisMAllocateSharedMemory(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN ULONG Length,
+ IN BOOLEAN Cached,
+ OUT PVOID *VirtualAddress,
+ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress
+ );
+
+/*++
+VOID
+NdisMUpdateSharedMemory(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN ULONG Length,
+ IN PVOID VirtualAddress,
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress
+ )
+--*/
+#define NdisMUpdateSharedMemory(_H, _L, _V, _P) NdisUpdateSharedMemory(_H, _L, _V, _P)
+
+
+EXPORT
+VOID
+NdisMFreeSharedMemory(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN ULONG Length,
+ IN BOOLEAN Cached,
+ IN PVOID VirtualAddress,
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress
+ );
+
+
+//
+// DMA operations.
+//
+
+EXPORT
+NDIS_STATUS
+NdisMRegisterDmaChannel(
+ OUT PNDIS_HANDLE MiniportDmaHandle,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN UINT DmaChannel,
+ IN BOOLEAN Dma32BitAddresses,
+ IN PNDIS_DMA_DESCRIPTION DmaDescription,
+ IN ULONG MaximumLength
+ );
+
+
+EXPORT
+VOID
+NdisMDeregisterDmaChannel(
+ IN PNDIS_HANDLE MiniportDmaHandle
+ );
+
+/*++
+VOID
+NdisMSetupDmaTransfer(
+ OUT PNDIS_STATUS Status,
+ IN PNDIS_HANDLE MiniportDmaHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG Offset,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ )
+--*/
+#define NdisMSetupDmaTransfer(_S, _H, _B, _O, _L, _M_) \
+ NdisSetupDmaTransfer(_S, _H, _B, _O, _L, _M_)
+
+/*++
+VOID
+NdisMCompleteDmaTransfer(
+ OUT PNDIS_STATUS Status,
+ IN PNDIS_HANDLE MiniportDmaHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG Offset,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ )
+--*/
+#define NdisMCompleteDmaTransfer(_S, _H, _B, _O, _L, _M_) \
+ NdisCompleteDmaTransfer(_S, _H, _B, _O, _L, _M_)
+
+EXPORT
+ULONG
+NdisMReadDmaCounter(
+ IN NDIS_HANDLE MiniportDmaHandle
+ );
+
+
+//
+// Requests Used by Miniport Drivers
+//
+
+
+#define NdisMInitializeWrapper(_a,_b,_c,_d) NdisInitializeWrapper((_a),(_b),(_c),(_d))
+
+EXPORT
+NDIS_STATUS
+NdisMRegisterMiniport(
+ IN NDIS_HANDLE NdisWrapperHandle,
+ IN PNDIS_MINIPORT_CHARACTERISTICS MiniportCharacteristics,
+ IN UINT CharacteristicsLength
+ );
+
+EXPORT
+VOID
+NdisMSetAttributes(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN BOOLEAN BusMaster,
+ IN NDIS_INTERFACE_TYPE AdapterType
+ );
+
+EXPORT
+VOID
+NdisMSendComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ );
+
+EXPORT
+VOID
+NdisMSendResourcesAvailable(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ );
+
+EXPORT
+VOID
+NdisMTransferDataComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ );
+
+EXPORT
+VOID
+NdisMResetComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_STATUS Status,
+ IN BOOLEAN AddressingReset
+ );
+
+EXPORT
+VOID
+NdisMSetInformationComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_STATUS Status
+ );
+
+EXPORT
+VOID
+NdisMQueryInformationComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_STATUS Status
+ );
+
+
+/*++
+
+VOID
+NdisMEthIndicateReceive(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+--*/
+#define NdisMEthIndicateReceive( _H, _C, _B, _SZ, _L, _LSZ, _PSZ ) \
+{ \
+ ASSERT(MINIPORT_LOCK_ACQUIRED((PNDIS_MINIPORT_BLOCK)(_H))); \
+ EthFilterDprIndicateReceive( \
+ ((PNDIS_MINIPORT_BLOCK)(_H))->EthDB, \
+ _C, \
+ _B, \
+ _B, \
+ _SZ, \
+ _L, \
+ _LSZ, \
+ _PSZ \
+ ); \
+}
+
+/*++
+
+VOID
+NdisMTrIndicateReceive(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+--*/
+#define NdisMTrIndicateReceive( _H, _C, _B, _SZ, _L, _LSZ, _PSZ ) \
+{ \
+ ASSERT(MINIPORT_LOCK_ACQUIRED((PNDIS_MINIPORT_BLOCK)(_H))); \
+ TrFilterDprIndicateReceive( \
+ ((PNDIS_MINIPORT_BLOCK)(_H))->TrDB, \
+ _C, \
+ _B, \
+ _SZ, \
+ _L, \
+ _LSZ, \
+ _PSZ \
+ ); \
+}
+
+/*++
+
+VOID
+NdisMFddiIndicateReceive(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+--*/
+
+#define NdisMFddiIndicateReceive( _H, _C, _B, _SZ, _L, _LSZ, _PSZ ) \
+{ \
+ ASSERT(MINIPORT_LOCK_ACQUIRED((PNDIS_MINIPORT_BLOCK)(_H))); \
+ \
+ FddiFilterDprIndicateReceive( \
+ ((PNDIS_MINIPORT_BLOCK)(_H))->FddiDB, \
+ _C, \
+ (PUCHAR)_B + 1, \
+ ((((PUCHAR)_B)[0] & 0x40) ? FDDI_LENGTH_OF_LONG_ADDRESS \
+ : FDDI_LENGTH_OF_SHORT_ADDRESS), \
+ _B, \
+ _SZ, \
+ _L, \
+ _LSZ, \
+ _PSZ \
+ ); \
+}
+
+/*++
+
+VOID
+NdisMArcIndicateReceive(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PUCHAR pRawHeader, // Pointer to Arcnet frame header
+ IN PUCHAR pData, // Pointer to data portion of Arcnet frame
+ IN UINT Length // Data Length
+ )
+
+--*/
+#define NdisMArcIndicateReceive( _H, _HD, _D, _SZ) \
+{ \
+ ASSERT(MINIPORT_LOCK_ACQUIRED((PNDIS_MINIPORT_BLOCK)(_H))); \
+ ArcFilterDprIndicateReceive( \
+ ((PNDIS_MINIPORT_BLOCK)(_H))->ArcDB, \
+ _HD, \
+ _D, \
+ _SZ \
+ ); \
+}
+
+//
+// Used only internally by the wrapper and filter package.
+//
+VOID
+NdisMArcIndicateEthEncapsulatedReceive(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PVOID HeaderBuffer,
+ IN PVOID DataBuffer,
+ IN UINT Length
+ );
+
+
+
+
+/*++
+
+VOID
+NdisMEthIndicateReceiveComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ );
+
+--*/
+
+#define NdisMEthIndicateReceiveComplete( _H ) \
+{ \
+ PNDIS_MINIPORT_BLOCK _M_ = (PNDIS_MINIPORT_BLOCK)_H; \
+ ASSERT(MINIPORT_LOCK_ACQUIRED(_M_)); \
+ EthFilterDprIndicateReceiveComplete(_M_->EthDB); \
+}
+
+/*++
+
+VOID
+NdisMTrIndicateReceiveComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ );
+
+--*/
+
+#define NdisMTrIndicateReceiveComplete( _H ) \
+{ \
+ PNDIS_MINIPORT_BLOCK _M_ = (PNDIS_MINIPORT_BLOCK)_H; \
+ ASSERT(MINIPORT_LOCK_ACQUIRED(_M_)); \
+ TrFilterDprIndicateReceiveComplete(_M_->TrDB); \
+}
+
+/*++
+
+VOID
+NdisMFddiIndicateReceiveComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ );
+
+--*/
+
+#define NdisMFddiIndicateReceiveComplete( _H ) \
+{ \
+ PNDIS_MINIPORT_BLOCK _M_ = (PNDIS_MINIPORT_BLOCK)_H; \
+ ASSERT(MINIPORT_LOCK_ACQUIRED(_M_)); \
+ FddiFilterDprIndicateReceiveComplete(_M_->FddiDB); \
+}
+
+/*++
+
+VOID
+NdisMArcIndicateReceiveComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ );
+
+--*/
+
+#define NdisMArcIndicateReceiveComplete( _H ) \
+{ \
+ PNDIS_MINIPORT_BLOCK _M_ = (PNDIS_MINIPORT_BLOCK)_H; \
+ ASSERT(MINIPORT_LOCK_ACQUIRED(_M_)); \
+ \
+ if ( _M_->EthDB ) { \
+ EthFilterDprIndicateReceiveComplete(_M_->EthDB); \
+ } \
+ \
+ ArcFilterDprIndicateReceiveComplete(_M_->ArcDB); \
+}
+
+EXPORT
+VOID
+NdisMIndicateStatus(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ );
+
+EXPORT
+VOID
+NdisMIndicateStatusComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ );
+
+EXPORT
+VOID
+NdisMRegisterAdapterShutdownHandler(
+ IN NDIS_HANDLE MiniportHandle,
+ IN PVOID ShutdownContext,
+ IN ADAPTER_SHUTDOWN_HANDLER ShutdownHandler
+ );
+
+EXPORT
+VOID
+NdisMDeregisterAdapterShutdownHandler(
+ IN NDIS_HANDLE MiniportHandle
+ );
+
+EXPORT
+NDIS_STATUS
+NdisMPciAssignResources(
+ IN NDIS_HANDLE MiniportHandle,
+ IN ULONG SlotNumber,
+ IN PNDIS_RESOURCE_LIST *AssignedResources
+ );
+
+
diff --git a/private/ntos/ndis/ndis30/precomp.h b/private/ntos/ndis/ndis30/precomp.h
new file mode 100644
index 000000000..9521fc237
--- /dev/null
+++ b/private/ntos/ndis/ndis30/precomp.h
@@ -0,0 +1,6 @@
+#include "wrapper.h"
+
+#include <afilter.h>
+#include <efilter.h>
+#include <ffilter.h>
+#include <tfilter.h>
diff --git a/private/ntos/ndis/ndis30/sources b/private/ntos/ndis/ndis30/sources
new file mode 100644
index 000000000..1d31c6f72
--- /dev/null
+++ b/private/ntos/ndis/ndis30/sources
@@ -0,0 +1,59 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+NT_UP=0
+
+TARGETNAME=ndis
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=EXPORT_DRIVER
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+INCLUDES=..\..\inc
+C_DEFINES= $(C_DEFINES) -DNDIS_WRAPPER -D_NTDRIVER_
+
+NTPROFILEINPUT=yes
+
+
+SOURCES= \
+ miniport.c \
+ wrapper.c \
+ minisub.c \
+ afilter.c \
+ efilter.c \
+ tfilter.c \
+ ffilter.c \
+ ndis.rc
+
+PRECOMPILED_INCLUDE=precomp.h
+PRECOMPILED_PCH=precomp.pch
+PRECOMPILED_OBJ=precomp.obj
+
+DLLDEF=obj\*\ndis.def
+
+NTTARGETFILE0=obj\$(TARGET_DIRECTORY)\ndis.def
+
diff --git a/private/ntos/ndis/ndis30/tfilter.c b/private/ntos/ndis/ndis30/tfilter.c
new file mode 100644
index 000000000..6d0b98a82
--- /dev/null
+++ b/private/ntos/ndis/ndis30/tfilter.c
@@ -0,0 +1,2119 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ tfilter.c
+
+Abstract:
+
+ This module implements a set of library routines to handle packet
+ filtering for NDIS MAC drivers.
+
+Author:
+
+ Anthony V. Ercolano (Tonye) 03-Aug-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+ Adam Barr (adamba) 19-Mar-1991
+
+ - Modified for Token-Ring
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+//
+// This constant is used for places where NdisAllocateMemory
+// needs to be called and the HighestAcceptableAddress does
+// not matter.
+//
+
+static const NDIS_PHYSICAL_ADDRESS HighestAcceptableMax =
+ NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
+
+//
+// ZZZ NonPortable definitions.
+//
+#define AllocPhys(s, l) NdisAllocateMemory((PVOID *)(s), (l), 0, HighestAcceptableMax)
+#define FreePhys(s, l) NdisFreeMemory((PVOID)(s), (l), 0)
+
+#define RetrieveUlong(Destination, Source)\
+{\
+ PUCHAR _S = (Source);\
+ *(Destination) = ((ULONG)(*_S) << 24) | \
+ ((ULONG)(*(_S+1)) << 16) | \
+ ((ULONG)(*(_S+2)) << 8) | \
+ ((ULONG)(*(_S+3)));\
+}
+
+#ifdef NDIS_NT
+#define MoveMemory(Destination,Source,Length) RtlMoveMemory(Destination,Source,Length)
+#define ZeroMemory(Destination,Length) RtlZeroMemory(Destination,Length)
+#endif
+
+#ifdef NDIS_DOS
+#define MoveMemory(Destination,Source,Length) \
+{\
+ int _i = Length;\
+ while( _i--) ((PUCHAR)(Destination))[_i] = ((PUCHAR)(Source))[_i]; \
+}
+
+#define ZeroMemory(Destination,Length) \
+{\
+ int _i = Length;\
+ while (_i--) ((PUCHAR)(Destination))[_i] = 0;\
+}
+#endif
+
+//
+// Used in case we have to call TrChangeFunctionalAddress or
+// TrChangeGroupAddress with a NULL address.
+//
+static CHAR NullFunctionalAddress[4] = { 0x00 };
+
+
+//
+// Maximum number of supported opens
+//
+#define TR_FILTER_MAX_OPENS 32
+
+
+
+#if DBG
+extern BOOLEAN NdisCheckBadDrivers;
+#endif
+
+//VOID
+//CLEAR_BIT_IN_MASK(
+// IN UINT Offset,
+// IN OUT PULONG MaskToClear
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Clear a bit in the bitmask pointed to by the parameter.
+//
+//Arguments:
+//
+// Offset - The offset (from 0) of the bit to altered.
+//
+// MaskToClear - Pointer to the mask to be adjusted.
+//
+//Return Value:
+//
+// None.
+//
+//--*/
+//
+#define CLEAR_BIT_IN_MASK(Offset,MaskToClear) *MaskToClear &= (~(1 << Offset))
+
+//VOID
+//SET_BIT_IN_MASK(
+// IN UINT Offset,
+// IN OUT PULONG MaskToSet
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Set a bit in the bitmask pointed to by the parameter.
+//
+//Arguments:
+//
+// Offset - The offset (from 0) of the bit to altered.
+//
+// MaskToSet - Pointer to the mask to be adjusted.
+//
+//Return Value:
+//
+// None.
+//
+//--*/
+#define SET_BIT_IN_MASK(Offset,MaskToSet) *MaskToSet |= (1 << Offset)
+
+//BOOLEAN
+//IS_BIT_SET_IN_MASK(
+// IN UINT Offset,
+// IN ULONG MaskToTest
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Tests if a particular bit in the bitmask pointed to by the parameter is
+// set.
+//
+//Arguments:
+//
+// Offset - The offset (from 0) of the bit to test.
+//
+// MaskToTest - The mask to be tested.
+//
+//Return Value:
+//
+// Returns TRUE if the bit is set.
+//
+//--*/
+#define IS_BIT_SET_IN_MASK(Offset,MaskToTest) \
+((MaskToTest & (1 << Offset))?(TRUE):(FALSE))
+
+//
+// VOID
+// TR_FILTER_ALLOC_OPEN(
+// IN PTR_FILTER Filter,
+// OUT PUINT FilterIndex
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Allocates an open block. This only allocate the index, not memory for
+// the open block.
+//
+//Arguments:
+//
+// Filter - DB from which to allocate the space
+//
+// FilterIndex - pointer to place to store the index.
+//
+//Return Value:
+//
+// FilterIndex of the new open
+//
+//--*/
+#define TR_FILTER_ALLOC_OPEN(Filter, FilterIndex)\
+{\
+ UINT i; \
+ for (i=0; i < TR_FILTER_MAX_OPENS; i++) { \
+ if (IS_BIT_SET_IN_MASK(i,(Filter)->FreeBindingMask)) { \
+ *(FilterIndex) = i; \
+ CLEAR_BIT_IN_MASK(i, &((Filter)->FreeBindingMask)); \
+ break; \
+ } \
+ } \
+}
+
+//
+// VOID
+// TR_FILTER_FREE_OPEN(
+// IN PTR_FILTER Filter,
+// IN PTR_BINDING_INFO LocalOpen
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Frees an open block. Also frees the memory associated with the open.
+//
+//Arguments:
+//
+// Filter - DB from which to allocate the space
+//
+// FilterIndex - Index to free
+//
+//Return Value:
+//
+// FilterIndex of the new open
+//
+//--*/
+#define TR_FILTER_FREE_OPEN(Filter, LocalOpen)\
+{\
+ SET_BIT_IN_MASK(((LocalOpen)->FilterIndex), &((Filter)->FreeBindingMask)); \
+ FreePhys((LocalOpen), sizeof(TR_BINDING_INFO));\
+}
+
+NDIS_SPIN_LOCK TrReferenceLock = {0};
+KEVENT TrPagedInEvent = {0};
+ULONG TrReferenceCount = 0;
+PVOID TrImageHandle = {0};
+
+VOID
+TrInitializePackage(VOID)
+{
+ NdisAllocateSpinLock(&TrReferenceLock);
+ KeInitializeEvent(
+ &TrPagedInEvent,
+ NotificationEvent,
+ FALSE
+ );
+}
+
+VOID
+TrReferencePackage(VOID)
+{
+
+ ACQUIRE_SPIN_LOCK(&TrReferenceLock);
+
+ TrReferenceCount++;
+
+ if (TrReferenceCount == 1) {
+
+ KeResetEvent(
+ &TrPagedInEvent
+ );
+
+ RELEASE_SPIN_LOCK(&TrReferenceLock);
+
+ //
+ // Page in all the functions
+ //
+ TrImageHandle = MmLockPagableCodeSection(TrCreateFilter);
+
+ //
+ // Signal to everyone to go
+ //
+ KeSetEvent(
+ &TrPagedInEvent,
+ 0L,
+ FALSE
+ );
+
+ } else {
+
+ RELEASE_SPIN_LOCK(&TrReferenceLock);
+
+ //
+ // Wait for everything to be paged in
+ //
+ KeWaitForSingleObject(
+ &TrPagedInEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ NULL
+ );
+
+ }
+
+}
+
+VOID
+TrDereferencePackage(VOID)
+{
+ ACQUIRE_SPIN_LOCK(&TrReferenceLock);
+
+ TrReferenceCount--;
+
+ if (TrReferenceCount == 0) {
+
+ RELEASE_SPIN_LOCK(&TrReferenceLock);
+
+ //
+ // Page out all the functions
+ //
+ MmUnlockPagableImageSection(TrImageHandle);
+
+ } else {
+
+ RELEASE_SPIN_LOCK(&TrReferenceLock);
+
+ }
+
+}
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGENDST, TrShouldAddressLoopBack)
+#pragma alloc_text(PAGENDST, TrFilterDprIndicateReceiveComplete)
+#pragma alloc_text(PAGENDST, TrFilterIndicateReceiveComplete)
+#pragma alloc_text(PAGENDST, TrFilterDprIndicateReceive)
+#pragma alloc_text(PAGENDST, TrFilterIndicateReceive)
+#pragma alloc_text(PAGENDST, TrFilterAdjust)
+#pragma alloc_text(PAGENDST, TrChangeGroupAddress)
+#pragma alloc_text(PAGENDST, TrChangeFunctionalAddress)
+#pragma alloc_text(PAGENDST, TrDeleteFilterOpenAdapter)
+#pragma alloc_text(PAGENDST, TrNoteFilterOpenAdapter)
+#pragma alloc_text(PAGENDST, TrCreateFilter)
+
+#endif
+
+
+
+
+BOOLEAN
+TrCreateFilter(
+ IN TR_ADDRESS_CHANGE AddressChangeAction,
+ IN TR_GROUP_CHANGE GroupChangeAction,
+ IN TR_FILTER_CHANGE FilterChangeAction,
+ IN TR_DEFERRED_CLOSE CloseAction,
+ IN PUCHAR AdapterAddress,
+ IN PNDIS_SPIN_LOCK Lock,
+ OUT PTR_FILTER *Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to create and initialize the filter database.
+
+Arguments:
+
+ AddressChangeAction - Action routine to call when the ORing together
+ of the functional address desired by all the bindings had changed.
+
+ GroupChangeAction - Action routine to call when the group address
+ desired by all the bindings had changed.
+
+ FilterChangeAction - Action routine to call when a binding sets or clears
+ a particular filter class and it is the first or only binding using
+ the filter class.
+
+ CloseAction - This routine is called if a binding closes while
+ it is being indicated to via NdisIndicateReceive. It will be
+ called upon return from NdisIndicateReceive.
+
+ AdapterAddress - the address of the adapter associated with this filter
+ database.
+
+ Lock - Pointer to the lock that should be held when mutual exclusion
+ is required.
+
+ Filter - A pointer to a TR_FILTER. This is what is allocated and
+ created by this routine.
+
+Return Value:
+
+ If the function returns false then one of the parameters exceeded
+ what the filter was willing to support.
+
+--*/
+
+{
+
+ PTR_FILTER LocalFilter;
+ NDIS_STATUS AllocStatus;
+
+
+ //
+ // Allocate the database and it's associated arrays.
+ //
+
+ AllocStatus = AllocPhys(&LocalFilter, sizeof(TR_FILTER));
+ *Filter = LocalFilter;
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+ return FALSE;
+ }
+
+ TrReferencePackage();
+
+ ZeroMemory(
+ LocalFilter,
+ sizeof(TR_FILTER)
+ );
+
+
+ LocalFilter->GroupReferences = 0;
+ LocalFilter->GroupAddress = 0;
+ LocalFilter->OpenList = NULL;
+ LocalFilter->FreeBindingMask = (ULONG)-1;
+
+ LocalFilter->Lock = Lock;
+
+ TR_COPY_NETWORK_ADDRESS(LocalFilter->AdapterAddress, AdapterAddress);
+ LocalFilter->AddressChangeAction = AddressChangeAction;
+ LocalFilter->GroupChangeAction = GroupChangeAction;
+ LocalFilter->FilterChangeAction = FilterChangeAction;
+ LocalFilter->CloseAction = CloseAction;
+
+ return TRUE;
+}
+
+//
+// NOTE : THIS ROUTINE CANNOT BE PAGEABLE
+//
+
+VOID
+TrDeleteFilter(
+ IN PTR_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to delete the memory associated with a filter
+ database. Note that this routines *ASSUMES* that the database
+ has been cleared of any active filters.
+
+Arguments:
+
+ Filter - A pointer to a TR_FILTER to be deleted.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ASSERT(Filter->OpenList == NULL);
+
+ FreePhys(Filter, sizeof(TR_FILTER));
+
+ TrDereferencePackage();
+
+}
+
+
+BOOLEAN
+TrNoteFilterOpenAdapter(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE NdisBindingContext,
+ OUT PNDIS_HANDLE NdisFilterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to add a new binding to the filter database.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE DATABASE IS LOCKED WHEN
+ IT IS CALLED.
+
+Arguments:
+
+ Filter - A pointer to the previously created and initialized filter
+ database.
+
+ MacBindingHandle - The MAC supplied value to the protocol in response
+ to a call to MacOpenAdapter.
+
+ NdisBindingContext - An NDIS supplied value to the call to MacOpenAdapter.
+
+ NdisFilterHandle - A pointer to the open block.
+
+Return Value:
+
+ Will return false if creating a new filter index will cause the maximum
+ number of filter indexes to be exceeded.
+
+--*/
+
+{
+ NDIS_STATUS AllocStatus;
+
+ //
+ // Will hold the value of the filter index so that we
+ // need not indirectly address through pointer parameter.
+ //
+ UINT LocalIndex;
+
+ //
+ // This new open
+ //
+ PTR_BINDING_INFO LocalOpen;
+
+ PNDIS_OPEN_BLOCK NdisOpen = (PNDIS_OPEN_BLOCK)NdisBindingContext;
+
+ if (Filter->FreeBindingMask == 0) {
+
+ return FALSE;
+
+ }
+
+ AllocStatus = AllocPhys(
+ &LocalOpen,
+ sizeof(TR_BINDING_INFO)
+ );
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Get place for the open and insert it.
+ //
+
+ TR_FILTER_ALLOC_OPEN(Filter, &LocalIndex);
+
+ LocalOpen->NextOpen = Filter->OpenList;
+
+ if (Filter->OpenList != NULL) {
+ Filter->OpenList->PrevOpen = LocalOpen;
+ }
+
+ LocalOpen->PrevOpen = NULL;
+
+ Filter->OpenList = LocalOpen;
+
+ LocalOpen->References = 1;
+ LocalOpen->FilterIndex = (UCHAR)LocalIndex;
+ LocalOpen->MacBindingHandle = MacBindingHandle;
+ LocalOpen->NdisBindingContext = NdisBindingContext;
+ LocalOpen->UsingGroupAddress = FALSE;
+ LocalOpen->PacketFilters = 0;
+ LocalOpen->ReceivedAPacket = FALSE;
+
+ LocalOpen->FunctionalAddress = (TR_FUNCTIONAL_ADDRESS)0;
+
+ *NdisFilterHandle = (PTR_BINDING_INFO)LocalOpen;
+
+ return TRUE;
+
+}
+
+
+NDIS_STATUS
+TrDeleteFilterOpenAdapter(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ When an adapter is being closed this routine should
+ be called to delete knowledge of the adapter from
+ the filter database. This routine is likely to call
+ action routines associated with clearing filter classes
+ and addresses.
+
+ NOTE: THIS ROUTINE SHOULD ****NOT**** BE CALLED IF THE ACTION
+ ROUTINES FOR DELETING THE FILTER CLASSES OR THE FUNCTIONAL ADDRESSES
+ HAVE ANY POSSIBILITY OF RETURNING A STATUS OTHER THAN NDIS_STATUS_PENDING
+ OR NDIS_STATUS_SUCCESS. WHILE THESE ROUTINES WILL NOT BUGCHECK IF
+ SUCH A THING IS DONE, THE CALLER WILL PROBABLY FIND IT DIFFICULT
+ TO CODE A CLOSE ROUTINE!
+
+ NOTE: THIS ROUTINE ASSUMES THAT IT IS CALLED WITH THE LOCK HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - A pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routines,
+ this will be passed to it.
+
+Return Value:
+
+ If action routines are called by the various address and filtering
+ routines the this routine will likely return the status returned
+ by those routines. The exception to this rule is noted below.
+
+ Given that the filter and address deletion routines return a status
+ NDIS_STATUS_PENDING or NDIS_STATUS_SUCCESS this routine will then
+ try to return the filter index to the freelist. If the routine
+ detects that this binding is currently being indicated to via
+ NdisIndicateReceive, this routine will return a status of
+ NDIS_STATUS_CLOSING_INDICATING.
+
+--*/
+
+{
+
+ //
+ // Holds the status returned from the packet filter and address
+ // deletion routines. Will be used to return the status to
+ // the caller of this routine.
+ //
+ NDIS_STATUS StatusToReturn;
+
+ PTR_BINDING_INFO LocalOpen = (PTR_BINDING_INFO)NdisFilterHandle;
+
+ StatusToReturn = TrFilterAdjust(
+ Filter,
+ NdisFilterHandle,
+ NdisRequest,
+ (UINT)0,
+ FALSE
+ );
+
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS ||
+ StatusToReturn == NDIS_STATUS_PENDING) {
+
+ NDIS_STATUS StatusToReturn2;
+
+ StatusToReturn2 = TrChangeFunctionalAddress(
+ Filter,
+ NdisFilterHandle,
+ NdisRequest,
+ NullFunctionalAddress,
+ FALSE
+ );
+
+ if (StatusToReturn2 != NDIS_STATUS_SUCCESS) {
+
+ StatusToReturn = StatusToReturn2;
+
+
+ }
+
+ }
+
+ if (((StatusToReturn == NDIS_STATUS_SUCCESS) ||
+ (StatusToReturn == NDIS_STATUS_PENDING)) &&
+ (LocalOpen->UsingGroupAddress)) {
+
+ Filter->GroupReferences--;
+
+ LocalOpen->UsingGroupAddress = FALSE;
+
+ if (Filter->GroupReferences == 0) {
+
+ NDIS_STATUS StatusToReturn2;
+
+ StatusToReturn2 = TrChangeGroupAddress(
+ Filter,
+ NdisFilterHandle,
+ NdisRequest,
+ NullFunctionalAddress,
+ FALSE
+ );
+
+ if (StatusToReturn2 != NDIS_STATUS_SUCCESS) {
+
+ StatusToReturn = StatusToReturn2;
+
+ }
+
+ }
+
+ }
+
+ if ((StatusToReturn == NDIS_STATUS_SUCCESS) ||
+ (StatusToReturn == NDIS_STATUS_PENDING)) {
+
+ //
+ // If this is the last reference to the open - remove it.
+ //
+
+ if ((--(LocalOpen->References)) == 0) {
+
+ //
+ // Remove it from the list of opens.
+ //
+
+ if (LocalOpen->NextOpen != NULL) {
+
+ LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen;
+
+ }
+
+ if (LocalOpen->PrevOpen != NULL) {
+
+ LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen;
+
+ } else {
+
+ Filter->OpenList = LocalOpen->NextOpen;
+
+ }
+
+ //
+ // Check if we need to clean up an IndicateReceiveComplete
+ //
+
+ if (LocalOpen->ReceivedAPacket) {
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ }
+
+ //
+ // Destroy it.
+ //
+
+ TR_FILTER_FREE_OPEN(Filter, LocalOpen);
+
+ } else {
+
+ //
+ // Let the caller know that this "reference" to the open
+ // is still "active". The close action routine will be
+ // called upon return from NdisIndicateReceive.
+ //
+
+ StatusToReturn = NDIS_STATUS_CLOSING_INDICATING;
+
+ }
+
+ }
+
+ return StatusToReturn;
+
+}
+
+
+NDIS_STATUS
+TrChangeFunctionalAddress(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN CHAR FunctionalAddressArray[TR_LENGTH_OF_FUNCTIONAL],
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ The ChangeFunctionalAddress routine will call an action
+ routine when the overall functional address for the adapter
+ has changed.
+
+ If the action routine returns a value other than pending or
+ success then this routine has no effect on the functional address
+ for the open or for the adapter as a whole.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - A pointer to the open
+
+ NdisRequest - If it is necessary to call the action routine,
+ this will be passed to it.
+
+ FunctionalAddress - The new functional address for this binding.
+
+ Set - A boolean that determines whether the filter classes
+ are being adjusted due to a set or because of a close. (The filtering
+ routines don't care, the MAC might.)
+
+Return Value:
+
+ If it calls the action routine then it will return the
+ status returned by the action routine. If the status
+ returned by the action routine is anything other than
+ NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
+ will be returned to the state it was in upon entrance to this
+ routine.
+
+ If the action routine is not called this routine will return
+ the following statum:
+
+ NDIS_STATUS_SUCCESS - If the new packet filters doesn't change
+ the combined mask of all bindings packet filters.
+
+--*/
+
+{
+ //
+ // Holds the functional address as a longword.
+ //
+ TR_FUNCTIONAL_ADDRESS FunctionalAddress;
+
+ //
+ // Contains the value of the combined functional address before
+ // it is adjusted.
+ //
+ UINT OldCombined = Filter->CombinedFunctionalAddress;
+
+ //
+ // Pointer to the open.
+ //
+ PTR_BINDING_INFO LocalOpen = (PTR_BINDING_INFO)NdisFilterHandle;
+
+ //
+ // Contains the value of the particlar open's packet filters
+ // prior to the change. We save this in case the action
+ // routine (if called) returns an "error" status.
+ //
+ UINT OldFunctionalAddress =
+ LocalOpen->FunctionalAddress;
+
+ //
+ // Holds the status returned to the user of this routine, if the
+ // action routine is not called then the status will be success,
+ // otherwise, it is whatever the action routine returns.
+ //
+ NDIS_STATUS StatusOfAdjust;
+
+ //
+ // Simple iteration variable.
+ //
+ PTR_BINDING_INFO OpenList;
+
+
+ //
+ // Convert the 32 bits of the address to a longword.
+ //
+ RetrieveUlong(&FunctionalAddress, FunctionalAddressArray);
+
+ //
+ // Set the new filter information for the open.
+ //
+
+ LocalOpen->FunctionalAddress = FunctionalAddress;
+
+ //
+ // We always have to reform the compbined filter since
+ // this filter index may have been the only filter index
+ // to use a particular bit.
+ //
+
+ for (
+ OpenList = Filter->OpenList,Filter->CombinedFunctionalAddress = 0;
+ OpenList != NULL;
+ OpenList = OpenList->NextOpen
+ ) {
+
+ Filter->CombinedFunctionalAddress |=
+ OpenList->FunctionalAddress;
+
+ }
+
+ if (OldCombined != Filter->CombinedFunctionalAddress) {
+
+ StatusOfAdjust = Filter->AddressChangeAction(
+ OldCombined,
+ Filter->CombinedFunctionalAddress,
+ LocalOpen->MacBindingHandle,
+ NdisRequest,
+ Set
+ );
+
+ if ((StatusOfAdjust != NDIS_STATUS_SUCCESS) &&
+ (StatusOfAdjust != NDIS_STATUS_PENDING)) {
+
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+
+ LocalOpen->FunctionalAddress = OldFunctionalAddress;
+ Filter->CombinedFunctionalAddress = OldCombined;
+
+ }
+
+ } else {
+
+ StatusOfAdjust = NDIS_STATUS_SUCCESS;
+
+ }
+
+ return StatusOfAdjust;
+
+}
+
+
+NDIS_STATUS
+TrChangeGroupAddress(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN CHAR GroupAddressArray[TR_LENGTH_OF_FUNCTIONAL],
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ The ChangeGroupAddress routine will call an action
+ routine when the overall group address for the adapter
+ has changed.
+
+ If the action routine returns a value other than pending or
+ success then this routine has no effect on the group address
+ for the open or for the adapter as a whole.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - A pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routine,
+ this will be passed to it.
+
+ GroupAddressArray - The new group address for this binding.
+
+ Set - A boolean that determines whether the filter classes
+ are being adjusted due to a set or because of a close. (The filtering
+ routines don't care, the MAC might.)
+
+Return Value:
+
+ If it calls the action routine then it will return the
+ status returned by the action routine. If the status
+ returned by the action routine is anything other than
+ NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
+ will be returned to the state it was in upon entrance to this
+ routine.
+
+ If the action routine is not called this routine will return
+ the following statum:
+
+ NDIS_STATUS_SUCCESS - If the new packet filters doesn't change
+ the combined mask of all bindings packet filters.
+
+--*/
+
+{
+ //
+ // Holds the Group address as a longword.
+ //
+ TR_FUNCTIONAL_ADDRESS GroupAddress;
+
+ PTR_BINDING_INFO LocalOpen = (PTR_BINDING_INFO)NdisFilterHandle;
+
+ UINT OldGroupAddress = Filter->GroupAddress;
+ UINT OldReferenceCount = Filter->GroupReferences;
+
+ //
+ // Holds the status returned to the user of this routine, if the
+ // action routine is not called then the status will be success,
+ // otherwise, it is whatever the action routine returns.
+ //
+ NDIS_STATUS StatusOfAdjust;
+
+ //
+ // Convert the 32 bits of the address to a longword.
+ //
+ RetrieveUlong(&GroupAddress, GroupAddressArray);
+
+ //
+ // See if this is a deletion
+ //
+ if ((GroupAddressArray[0] == NullFunctionalAddress[0]) &&
+ (GroupAddressArray[1] == NullFunctionalAddress[1]) &&
+ (GroupAddressArray[2] == NullFunctionalAddress[2]) &&
+ (GroupAddressArray[3] == NullFunctionalAddress[3])) {
+
+ if (LocalOpen->UsingGroupAddress) {
+
+ Filter->GroupReferences--;
+
+ LocalOpen->UsingGroupAddress = FALSE;
+
+ if (Filter->GroupReferences != 0) {
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+ } else if (Filter->GroupReferences != 0) {
+
+ return(NDIS_STATUS_GROUP_ADDRESS_IN_USE);
+
+ } else {
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+ } else {
+
+ //
+ // See if this address is already the current address.
+ //
+
+ if (GroupAddress == Filter->GroupAddress) {
+
+ if (LocalOpen->UsingGroupAddress) {
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+ if (Filter->GroupReferences != 0) {
+
+ LocalOpen->UsingGroupAddress = TRUE;
+
+ Filter->GroupReferences++;
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+ } else {
+
+ if (Filter->GroupReferences > 1) {
+
+ return(NDIS_STATUS_GROUP_ADDRESS_IN_USE);
+
+ }
+
+ if ((Filter->GroupReferences == 1) && !(LocalOpen->UsingGroupAddress)) {
+
+ return(NDIS_STATUS_GROUP_ADDRESS_IN_USE);
+
+ }
+
+ if ((Filter->GroupReferences == 1) && (LocalOpen->UsingGroupAddress)) {
+
+ //
+ // Remove old reference
+ //
+
+ Filter->GroupReferences--;
+ LocalOpen->UsingGroupAddress = FALSE;
+
+ }
+
+ }
+
+ }
+
+ //
+ // Set the new filter information for the open.
+ //
+
+ Filter->GroupAddress = GroupAddress;
+
+ StatusOfAdjust = Filter->GroupChangeAction(
+ OldGroupAddress,
+ Filter->GroupAddress,
+ LocalOpen->MacBindingHandle,
+ NdisRequest,
+ Set
+ );
+
+ if ((StatusOfAdjust != NDIS_STATUS_SUCCESS) &&
+ (StatusOfAdjust != NDIS_STATUS_PENDING)) {
+
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+
+ Filter->GroupAddress = OldGroupAddress;
+ Filter->GroupReferences = OldReferenceCount;
+
+ } else if (GroupAddress == 0x00000000) {
+
+ LocalOpen->UsingGroupAddress = FALSE;
+ Filter->GroupReferences = 0;
+
+ } else {
+
+ LocalOpen->UsingGroupAddress = TRUE;
+
+ Filter->GroupReferences = 1;
+
+ }
+
+ return StatusOfAdjust;
+
+}
+
+
+NDIS_STATUS
+TrFilterAdjust(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT FilterClasses,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ The FilterAdjust routine will call an action routine when a
+ particular filter class is changes from not being used by any
+ binding to being used by at least one binding or vice versa.
+
+ If the action routine returns a value other than pending or
+ success then this routine has no effect on the packet filters
+ for the open or for the adapter as a whole.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - A pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routine,
+ this will be passed to it.
+
+ FilterClasses - The filter classes that are to be added or
+ deleted.
+
+ Set - A boolean that determines whether the filter classes
+ are being adjusted due to a set or because of a close. (The filtering
+ routines don't care, the MAC might.)
+
+Return Value:
+
+ If it calls the action routine then it will return the
+ status returned by the action routine. If the status
+ returned by the action routine is anything other than
+ NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
+ will be returned to the state it was in upon entrance to this
+ routine.
+
+ If the action routine is not called this routine will return
+ the following statum:
+
+ NDIS_STATUS_SUCCESS - If the new packet filters doesn't change
+ the combined mask of all bindings packet filters.
+
+--*/
+
+{
+ //
+ // Contains the value of the combined filter classes before
+ // it is adjusted.
+ //
+ UINT OldCombined = Filter->CombinedPacketFilter;
+
+ //
+ // Pointer to the open
+ //
+ PTR_BINDING_INFO LocalOpen = (PTR_BINDING_INFO)NdisFilterHandle;
+
+ //
+ // Contains the value of the particlar opens packet filters
+ // prior to the change. We save this incase the action
+ // routine (if called) returns an "error" status.
+ //
+ UINT OldOpenFilters = LocalOpen->PacketFilters;
+
+ //
+ // Holds the status returned to the user of this routine, if the
+ // action routine is not called then the status will be success,
+ // otherwise, it is whatever the action routine returns.
+ //
+ NDIS_STATUS StatusOfAdjust;
+
+ //
+ // Simple iteration variable.
+ //
+ PTR_BINDING_INFO OpenList;
+
+ //
+ // Set the new filter information for the open.
+ //
+
+ LocalOpen->PacketFilters = FilterClasses;
+
+ //
+ // We always have to reform the compbined filter since
+ // this filter index may have been the only filter index
+ // to use a particular bit.
+ //
+
+ for (
+ OpenList = Filter->OpenList,Filter->CombinedPacketFilter = 0;
+ OpenList != NULL;
+ OpenList = OpenList->NextOpen
+ ) {
+
+ Filter->CombinedPacketFilter |=
+ OpenList->PacketFilters;
+
+ }
+
+ if (OldCombined != Filter->CombinedPacketFilter) {
+
+ StatusOfAdjust = Filter->FilterChangeAction(
+ OldCombined,
+ Filter->CombinedPacketFilter,
+ LocalOpen->MacBindingHandle,
+ NdisRequest,
+ Set
+ );
+
+ if ((StatusOfAdjust != NDIS_STATUS_SUCCESS) &&
+ (StatusOfAdjust != NDIS_STATUS_PENDING)) {
+
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+
+ LocalOpen->PacketFilters = OldOpenFilters;
+ Filter->CombinedPacketFilter = OldCombined;
+
+ }
+
+ } else {
+
+ StatusOfAdjust = NDIS_STATUS_SUCCESS;
+
+ }
+
+ return StatusOfAdjust;
+
+}
+
+
+VOID
+TrFilterIndicateReceive(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate a packet to
+ all bindings. The packet will be filtered so that only the
+ appropriate bindings will receive the packet.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ MacReceiveContext - A MAC supplied context value that must be
+ returned by the protocol if it calls MacTransferData.
+
+ HeaderBuffer - A virtual address of the virtually contiguous
+ buffer containing the MAC header of the packet.
+
+ HeaderBufferSize - An unsigned integer indicating the size of
+ the header buffer, in bytes.
+
+ LookaheadBuffer - A virtual address of the virtually contiguous
+ buffer containing the first LookaheadBufferSize bytes of data
+ of the packet. The packet buffer is valid only within the current
+ call to the receive event handler.
+
+ LookaheadBufferSize - An unsigned integer indicating the size of
+ the lookahead buffer, in bytes.
+
+ PacketSize - An unsigned integer indicating the size of the received
+ packet, in bytes. This number has nothing to do with the lookahead
+ buffer, but indicates how large the arrived packet is so that a
+ subsequent MacTransferData request can be made to transfer the entire
+ packet as necessary.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ KIRQL oldIrql;
+ KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ TrFilterDprIndicateReceive(
+ Filter,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize
+ );
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ KeLowerIrql( oldIrql );
+ return;
+}
+
+
+VOID
+TrFilterDprIndicateReceive(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate a packet to
+ all bindings. The packet will be filtered so that only the
+ appropriate bindings will receive the packet.
+
+ Called at DPC_LEVEL.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ MacReceiveContext - A MAC supplied context value that must be
+ returned by the protocol if it calls MacTransferData.
+
+ HeaderBuffer - A virtual address of the virtually contiguous
+ buffer containing the MAC header of the packet.
+
+ HeaderBufferSize - An unsigned integer indicating the size of
+ the header buffer, in bytes.
+
+ LookaheadBuffer - A virtual address of the virtually contiguous
+ buffer containing the first LookaheadBufferSize bytes of data
+ of the packet. The packet buffer is valid only within the current
+ call to the receive event handler.
+
+ LookaheadBufferSize - An unsigned integer indicating the size of
+ the lookahead buffer, in bytes.
+
+ PacketSize - An unsigned integer indicating the size of the received
+ packet, in bytes. This number has nothing to do with the lookahead
+ buffer, but indicates how large the arrived packet is so that a
+ subsequent MacTransferData request can be made to transfer the entire
+ packet as necessary.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // The destination address in the lookahead buffer.
+ //
+ PCHAR DestinationAddress = (PCHAR)HeaderBuffer + 2;
+
+ //
+ // The source address in the lookahead buffer.
+ //
+ PCHAR SourceAddress = (PCHAR)HeaderBuffer + 8;
+
+ //
+ // Will hold the type of address that we know we've got.
+ //
+ UINT AddressType;
+
+ //
+ // TRUE if the packet is source routing packet.
+ //
+ BOOLEAN IsSourceRouting;
+
+ //
+ // The functional address as a longword, if the packet
+ // is addressed to one.
+ //
+ TR_FUNCTIONAL_ADDRESS FunctionalAddress;
+
+ //
+ // Will hold the status of indicating the receive packet.
+ // ZZZ For now this isn't used.
+ //
+ NDIS_STATUS StatusOfReceive;
+
+ //
+ // Will hold the open being indicated.
+ //
+ PTR_BINDING_INFO LocalOpen;
+
+ //
+ // Will hold the filter classes of the binding being indicated.
+ //
+ UINT BindingFilters;
+
+ //
+ // Holds intersection of open filters and this packet's type
+ //
+ UINT IntersectionOfFilters;
+
+ //
+ // If the packet is a runt packet, then only indicate to PROMISCUOUS
+ //
+
+ if ( HeaderBufferSize >= 14 && PacketSize != 0 ) {
+
+ //
+ // Holds the result of address determinations.
+ //
+ BOOLEAN ResultOfAddressCheck;
+
+ TR_IS_SOURCE_ROUTING(
+ SourceAddress,
+ &IsSourceRouting
+ );
+
+ //
+ // First check if it *at least* has the functional address bit.
+ //
+
+ TR_IS_NOT_DIRECTED(
+ DestinationAddress,
+ &ResultOfAddressCheck
+ );
+
+ if (ResultOfAddressCheck) {
+
+ //
+ // It is at least a functional address. Check to see if
+ // it is a broadcast address.
+ //
+
+ TR_IS_BROADCAST(
+ DestinationAddress,
+ &ResultOfAddressCheck
+ );
+
+ if (ResultOfAddressCheck) {
+
+#if DBG
+
+if (NdisCheckBadDrivers) {
+
+ if (!(Filter->CombinedPacketFilter & NDIS_PACKET_TYPE_BROADCAST)) {
+
+ //
+ // We should never receive directed packets
+ // to someone else unless in p-mode.
+ //
+ DbgPrint("NDIS: Bad driver, indicating broadcast\n");
+ DbgPrint("NDIS: packets when not set to.\n");
+ DbgBreakPoint();
+
+ }
+
+}
+
+#endif
+
+ AddressType = NDIS_PACKET_TYPE_BROADCAST;
+
+ } else {
+
+ TR_IS_GROUP(
+ DestinationAddress,
+ &ResultOfAddressCheck
+ );
+
+ if (ResultOfAddressCheck) {
+
+ AddressType = NDIS_PACKET_TYPE_GROUP;
+
+ } else {
+
+ AddressType = NDIS_PACKET_TYPE_FUNCTIONAL;
+
+ }
+
+ RetrieveUlong(&FunctionalAddress,
+ (DestinationAddress + 2));
+
+
+ }
+
+ } else {
+
+ //
+ // Verify that the address is directed to the adapter. We
+ // have to check for this because of the following senario.
+ //
+ // Adapter A is in promiscuous mode.
+ // Adapter B only wants directed packets to this adapter.
+ //
+ // The MAC will indicate *all* packets.
+ //
+ // The filter package needs to filter directed packets to
+ // other adapters from ones directed to this adapter.
+ //
+
+ if (Filter->CombinedPacketFilter &
+ (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_SOURCE_ROUTING)) {
+
+ //
+ // The result of comparing an element of the address
+ // array and the multicast address.
+ //
+ // Result < 0 Implies the adapter address is greater.
+ // Result > 0 Implies the address is greater.
+ // Result = 0 Implies that the they are equal.
+ //
+ INT Result;
+
+ TR_COMPARE_NETWORK_ADDRESSES_EQ(
+ Filter->AdapterAddress,
+ DestinationAddress,
+ &Result
+ );
+
+ if (Result == 0) {
+
+ AddressType = NDIS_PACKET_TYPE_DIRECTED;
+
+ } else {
+
+ //
+ // This will cause binding that only want a specific
+ // address type to not be indicated.
+ //
+
+ AddressType = 0;
+
+ }
+
+ } else {
+
+#if DBG
+
+if (NdisCheckBadDrivers) {
+
+ //
+ // The result of comparing an element of the address
+ // array and the multicast address.
+ //
+ // Result < 0 Implies the adapter address is greater.
+ // Result > 0 Implies the address is greater.
+ // Result = 0 Implies that the they are equal.
+ //
+ INT Result;
+
+ TR_COMPARE_NETWORK_ADDRESSES_EQ(
+ Filter->AdapterAddress,
+ DestinationAddress,
+ &Result
+ );
+
+ if (Result != 0) {
+
+ //
+ // We should never receive directed packets
+ // to someone else unless in p-mode.
+ //
+ DbgPrint("NDIS: Bad driver, indicating packets\n");
+ DbgPrint("NDIS: to another station when not in\n");
+ DbgPrint("NDIS: promiscuous mode.\n");
+ DbgBreakPoint();
+
+
+ }
+
+}
+
+#endif
+
+ AddressType = NDIS_PACKET_TYPE_DIRECTED;
+
+ }
+
+ }
+
+ } else {
+
+ //
+ // Runt Packet
+ //
+
+ AddressType = NDIS_PACKET_TYPE_PROMISCUOUS;
+ IsSourceRouting = FALSE;
+
+ }
+
+ //
+ // We need to aquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+
+ LocalOpen = Filter->OpenList;
+
+ while (LocalOpen != NULL) {
+
+ BindingFilters = LocalOpen->PacketFilters;
+ IntersectionOfFilters = BindingFilters & AddressType;
+
+ //
+ // Can check directed and broadcast at the same time, just
+ // mask off all but those two bits in BindingFilters and
+ // then see if one of them corresponds to AddressType.
+ //
+
+ if (IntersectionOfFilters &
+ (NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_BROADCAST)) {
+
+ goto IndicatePacket;
+
+ }
+
+ //
+ // if the binding wants functional packets and the packet
+ // is a functional packet and it's in the list of addresses
+ // it will get the packet.
+ //
+
+ if (IntersectionOfFilters & NDIS_PACKET_TYPE_FUNCTIONAL) {
+
+ //
+ // See if the bit from the frame's address is also
+ // part of this bindings registered functional address.
+ //
+ if (FunctionalAddress &
+ LocalOpen->FunctionalAddress) {
+
+ goto IndicatePacket;
+
+ }
+
+ }
+
+ //
+ // if the binding wants all functional packets and the packet
+ // has a functional address it will get the packet
+ //
+
+ if ((AddressType & NDIS_PACKET_TYPE_FUNCTIONAL) &&
+ (BindingFilters & NDIS_PACKET_TYPE_ALL_FUNCTIONAL)) {
+
+ goto IndicatePacket;
+
+ }
+
+ //
+ // If the packet is a group packet and the binding is using the
+ // group address then it will get the packet.
+ //
+
+ if ((AddressType & NDIS_PACKET_TYPE_GROUP) &&
+ (BindingFilters & NDIS_PACKET_TYPE_GROUP) &&
+ (LocalOpen->UsingGroupAddress)) {
+
+ goto IndicatePacket;
+
+ }
+
+ //
+ // if this is a source routing packet and the binding
+ // wants it, indicate it.
+ //
+
+ if ((BindingFilters & NDIS_PACKET_TYPE_SOURCE_ROUTING) &&
+ IsSourceRouting) {
+
+ goto IndicatePacket;
+
+ }
+
+ //
+ // if the binding is promiscuous then it will get the packet
+ //
+
+ if (BindingFilters & NDIS_PACKET_TYPE_PROMISCUOUS) {
+
+ goto IndicatePacket;
+
+ }
+
+ //
+ // Nothing satisfied, so don't indicate the packet to
+ // this binding.
+ //
+
+ goto GetNextBinding;
+
+IndicatePacket:;
+
+ LocalOpen->References++;
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ //
+ // Indicate the packet to the binding.
+ //
+
+ FilterIndicateReceive(
+ &StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ if ((--(LocalOpen->References)) == 0) {
+
+ PTR_BINDING_INFO NextOpen = LocalOpen->NextOpen;
+
+ //
+ // This binding is shutting down.
+ //
+
+
+ //
+ // Remove it from the list of opens.
+ //
+
+ if (LocalOpen->NextOpen != NULL) {
+
+ LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen;
+
+ }
+
+ if (LocalOpen->PrevOpen != NULL) {
+
+ LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen;
+
+ } else {
+
+ Filter->OpenList = LocalOpen->NextOpen;
+
+ }
+
+ //
+ // Call the IndicateComplete routine.
+ //
+
+ if (LocalOpen->ReceivedAPacket) {
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ }
+
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+
+ Filter->CloseAction(
+ LocalOpen->MacBindingHandle
+ );
+
+ TR_FILTER_FREE_OPEN(Filter, LocalOpen);
+
+ LocalOpen = NextOpen;
+
+ continue;
+
+ }
+
+GetNextBinding:
+
+ LocalOpen = LocalOpen->NextOpen;
+
+ }
+
+}
+
+
+VOID
+TrFilterIndicateReceiveComplete(
+ IN PTR_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate that the receive
+ process is done and to indicate to all protocols which received
+ a packet that receive is complete.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ KIRQL oldIrql;
+ KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ TrFilterDprIndicateReceiveComplete(
+ Filter
+ );
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ KeLowerIrql( oldIrql );
+ return;
+}
+
+
+VOID
+TrFilterDprIndicateReceiveComplete(
+ IN PTR_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate that the receive
+ process is done and to indicate to all protocols which received
+ a packet that receive is complete.
+
+ Called at DPC_LEVEL.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Pointer to currently indicated binding.
+ //
+ PTR_BINDING_INFO LocalOpen;
+
+ //
+ // We need to aquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+
+ LocalOpen = Filter->OpenList;
+
+ while (LocalOpen != NULL) {
+
+ LocalOpen->References++;
+
+ if (LocalOpen->ReceivedAPacket) {
+
+ //
+ // Indicate the binding.
+ //
+
+ LocalOpen->ReceivedAPacket = FALSE;
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ }
+
+ if ((--(LocalOpen->References)) == 0) {
+
+ //
+ // This binding is shutting down.
+ //
+
+ PTR_BINDING_INFO NextOpen = LocalOpen->NextOpen;
+
+ //
+ // Remove it from the list.
+ //
+
+ if (LocalOpen->NextOpen != NULL) {
+
+ LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen;
+
+ }
+
+ if (LocalOpen->PrevOpen != NULL) {
+
+ LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen;
+
+ } else {
+
+ Filter->OpenList = LocalOpen->NextOpen;
+
+ }
+
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+
+ Filter->CloseAction(
+ LocalOpen->MacBindingHandle
+ );
+
+ TR_FILTER_FREE_OPEN(Filter, LocalOpen);
+
+ LocalOpen = NextOpen;
+
+ } else {
+
+ LocalOpen = LocalOpen->NextOpen;
+
+ }
+
+ }
+
+}
+
+
+BOOLEAN
+TrShouldAddressLoopBack(
+ IN PTR_FILTER Filter,
+ IN CHAR DestinationAddress[TR_LENGTH_OF_ADDRESS],
+ IN CHAR SourceAddress[TR_LENGTH_OF_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ Do a quick check to see whether the input address should
+ loopback.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+ NOTE: THIS ROUTINE DOES NOT CHECK THE SPECIAL CASE OF SOURCE
+ EQUALS DESTINATION.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ Address - A network address to check for loopback.
+
+
+Return Value:
+
+ Returns TRUE if the address is *likely* to need loopback. It
+ will return FALSE if there is *no* chance that the address would
+ require loopback.
+
+--*/
+{
+
+ //
+ // Holds the result of address determinations.
+ //
+ BOOLEAN ResultOfAddressCheck;
+
+ BOOLEAN IsSourceRouting;
+
+ UINT CombinedFilters;
+
+ ULONG GroupAddress;
+
+ //
+ // Convert the 32 bits of the address to a longword.
+ //
+ RetrieveUlong(&GroupAddress, (SourceAddress + 2));
+
+ //
+ // Check if the destination is a preexisting group address
+ //
+
+ TR_IS_GROUP(
+ SourceAddress,
+ &ResultOfAddressCheck
+ );
+
+ if ((ResultOfAddressCheck) &&
+ (GroupAddress == Filter->GroupAddress) &&
+ (Filter->GroupReferences != 0)) {
+
+ return(TRUE);
+
+ }
+
+
+ CombinedFilters = TR_QUERY_FILTER_CLASSES(Filter);
+
+ if ((!CombinedFilters) || (CombinedFilters & NDIS_PACKET_TYPE_PROMISCUOUS)) {
+
+ return FALSE;
+
+ }
+
+ TR_IS_SOURCE_ROUTING(
+ SourceAddress,
+ &IsSourceRouting
+ );
+
+ if (IsSourceRouting && (CombinedFilters & NDIS_PACKET_TYPE_SOURCE_ROUTING)) {
+
+ return TRUE;
+
+ }
+
+ //
+ // First check if it *at least* has the functional address bit.
+ //
+
+ TR_IS_NOT_DIRECTED(
+ DestinationAddress,
+ &ResultOfAddressCheck
+ );
+
+ if (ResultOfAddressCheck) {
+
+ //
+ // It is at least a functional address. Check to see if
+ // it is a broadcast address.
+ //
+
+ TR_IS_BROADCAST(
+ DestinationAddress,
+ &ResultOfAddressCheck
+ );
+
+ if (ResultOfAddressCheck) {
+
+ if (CombinedFilters & NDIS_PACKET_TYPE_BROADCAST) {
+
+ return TRUE;
+
+ } else {
+
+ return FALSE;
+
+ }
+
+ } else {
+
+ if (CombinedFilters &
+ (NDIS_PACKET_TYPE_ALL_FUNCTIONAL |
+ NDIS_PACKET_TYPE_FUNCTIONAL)) {
+
+ return TRUE;
+
+ } else {
+
+ return FALSE;
+
+ }
+
+ }
+
+ } else {
+
+ //
+ // Directed address never loops back.
+ //
+
+ return FALSE;
+
+ }
+
+}
diff --git a/private/ntos/ndis/ndis30/tfilter.h b/private/ntos/ndis/ndis30/tfilter.h
new file mode 100644
index 000000000..ea7b0a20d
--- /dev/null
+++ b/private/ntos/ndis/ndis30/tfilter.h
@@ -0,0 +1,558 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ tfilter.h
+
+Abstract:
+
+ Header file for the address filtering library for NDIS MAC's.
+
+Author:
+
+ Anthony V. Ercolano (tonye) creation-date 3-Aug-1990
+
+Environment:
+
+ Runs in the context of a single MAC driver.
+
+Notes:
+
+ None.
+
+Revision History:
+
+ Adam Barr (adamba) 19-Mar-1991
+
+ - Modified for Token-Ring
+
+--*/
+
+#ifndef _TR_FILTER_DEFS_
+#define _TR_FILTER_DEFS_
+
+#define TR_LENGTH_OF_FUNCTIONAL 4
+#define TR_LENGTH_OF_ADDRESS 6
+
+
+//
+// Only the low 32 bits of the functional/group address
+// are needed since the upper 16 bits is always c0-00.
+//
+typedef ULONG TR_FUNCTIONAL_ADDRESS;
+typedef ULONG TR_GROUP_ADDRESS;
+
+
+
+//
+//
+#define TR_IS_NOT_DIRECTED(Address, Result) \
+{ \
+ PUCHAR _A = Address; \
+ PBOOLEAN _R = Result; \
+ *_R = (BOOLEAN)(_A[0] & ((UCHAR)0x80));\
+}
+
+//
+//
+#define TR_IS_FUNCTIONAL(Address, Result) \
+{ \
+ PUCHAR _A = Address; \
+ PBOOLEAN _R = Result; \
+ *_R = (BOOLEAN)((_A[0] & ((UCHAR)0x80)) &&\
+ !(_A[2] & ((UCHAR)0x80))); \
+}
+
+//
+//
+#define TR_IS_GROUP(Address, Result) \
+{ \
+ PUCHAR _A = Address; \
+ PBOOLEAN _R = Result; \
+ *_R = (BOOLEAN)(_A[0] & _A[2] & ((UCHAR)0x80)); \
+}
+
+//
+//
+#define TR_IS_SOURCE_ROUTING(Address, Result) \
+{ \
+ PUCHAR _A = Address; \
+ PBOOLEAN _R = Result; \
+ *_R = (BOOLEAN)(_A[0] >> 7);\
+}
+
+
+//
+// Check whether an address is broadcast.
+//
+#define TR_IS_BROADCAST(Address, Result) \
+{ \
+ PUCHAR _A = Address; \
+ PBOOLEAN _R = Result; \
+ *_R = (BOOLEAN)((((_A[0] == ((UCHAR)0xff)) && \
+ (_A[1] == ((UCHAR)0xff))) || \
+ ((_A[0] == ((UCHAR)0xc0)) && \
+ (_A[1] == ((UCHAR)0x00)))) && \
+ (_A[2] == ((UCHAR)0xff)) && \
+ (_A[3] == ((UCHAR)0xff)) && \
+ (_A[4] == ((UCHAR)0xff)) && \
+ (_A[5] == ((UCHAR)0xff))); \
+}
+
+
+//
+// This macro will compare network addresses.
+//
+// A - Is a network address.
+//
+// B - Is a network address.
+//
+// Result - The result of comparing two network address.
+//
+// Result < 0 Implies the B address is greater.
+// Result > 0 Implies the A element is greater.
+// Result = 0 Implies equality.
+//
+// Note that this is an arbitrary ordering. There is not
+// defined relation on network addresses. This is ad-hoc!
+//
+//
+#define TR_COMPARE_NETWORK_ADDRESSES(A, B, Result) \
+{ \
+ PUCHAR _A = (PUCHAR)(A); \
+ PUCHAR _B = (PUCHAR)(B); \
+ if ( *(ULONG UNALIGNED *)&_A[2] > \
+ *(ULONG UNALIGNED *)&_B[2] ) { \
+ *Result = 1; \
+ } else if ( *(ULONG UNALIGNED *)&_A[2] < \
+ *(ULONG UNALIGNED *)&_B[2] ) { \
+ *Result = (UINT)-1; \
+ } else if ( *(USHORT UNALIGNED *)_A > \
+ *(USHORT UNALIGNED *)_B ) { \
+ *Result = 1; \
+ } else if ( *(USHORT UNALIGNED *)_A < \
+ *(USHORT UNALIGNED *)_B ) { \
+ *Result = (UINT)-1; \
+ } else { \
+ *Result = 0; \
+ } \
+}
+
+//
+// This macro will compare network addresses.
+//
+// A - Is a network address.
+//
+// B - Is a network address.
+//
+// Result - The result of comparing two network address.
+//
+// Result != 0 Implies inequality.
+// Result == 0 Implies equality.
+//
+//
+#define TR_COMPARE_NETWORK_ADDRESSES_EQ(A,B,Result) \
+{ \
+ PUCHAR _A = (PUCHAR)(A); \
+ PUCHAR _B = (PUCHAR)(B); \
+ if ( ( *(ULONG UNALIGNED *)&_A[2] == \
+ *(ULONG UNALIGNED *)&_B[2] ) && \
+ ( *(USHORT UNALIGNED *)_A == \
+ *(USHORT UNALIGNED *)_B ) ) { \
+ *Result = 0; \
+ } else { \
+ *Result = 1; \
+ } \
+}
+
+
+//
+// This macro is used to copy from one network address to
+// another.
+//
+#define TR_COPY_NETWORK_ADDRESS(D, S) \
+{ \
+ PCHAR _D = (D); \
+ PCHAR _S = (S); \
+ _D[0] = _S[0]; \
+ _D[1] = _S[1]; \
+ _D[2] = _S[2]; \
+ _D[3] = _S[3]; \
+ _D[4] = _S[4]; \
+ _D[5] = _S[5]; \
+}
+
+
+//
+//UINT
+//TR_QUERY_FILTER_CLASSES(
+// IN PTR_FILTER Filter
+// )
+//
+// This macro returns the currently enabled filter classes.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define TR_QUERY_FILTER_CLASSES(Filter) ((Filter)->CombinedPacketFilter)
+
+
+//
+//UINT
+//TR_QUERY_PACKET_FILTER(
+// IN PTR_FILTER Filter,
+// IN NDIS_HANDLE NdisFilterHandle
+// )
+//
+// This macro returns the currently enabled filter classes for a specific
+// open instance.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define TR_QUERY_PACKET_FILTER(Filter, NdisFilterHandle) \
+ (((PTR_BINDING_INFO)NdisFilterHandle)->PacketFilters)
+
+
+
+//
+//UINT
+//TR_QUERY_FILTER_ADDRESSES(
+// IN PTR_FILTER Filter
+// )
+//
+// This macro returns the currently enabled functional address.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define TR_QUERY_FILTER_ADDRESSES(Filter) ((Filter)->CombinedFunctionalAddress)
+
+
+
+//
+//UINT
+//TR_QUERY_FILTER_GROUP(
+// IN PTR_FILTER Filter
+// )
+//
+// This macro returns the currently enabled Group address.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define TR_QUERY_FILTER_Group(Filter) ((Filter)->GroupAddress)
+#define TR_QUERY_FILTER_GROUP(Filter) ((Filter)->GroupAddress)
+
+
+
+//
+//UINT
+//TR_QUERY_FILTER_BINDING_ADDRESS(
+// IN PTR_FILTER Filter
+// IN NDIS_HANDLE NdisFilterHandle,
+// )
+//
+// This macro returns the currently desired functional addresses
+// for the specified binding.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define TR_QUERY_FILTER_BINDING_ADDRESS(Filter, NdisFilterHandle) \
+ (((PTR_BINDING_INFO)NdisFilterHandle)->FunctionalAddress)
+
+
+
+
+//
+//BOOLEAN
+//TR_QUERY_FILTER_BINDING_GROUP(
+// IN PTR_FILTER Filter
+// IN NDIS_HANDLE NdisFilterHandle,
+// )
+//
+// This macro returns TRUE if the specified binding is using the
+// current group address.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define TR_QUERY_FILTER_BINDING_GROUP(Filter, NdisFilterHandle) \
+ (((PTR_BINDING_INFO)NdisFilterHandle)->UsingGroupAddress)
+
+
+//
+// An action routine type. The routines are called
+// when a filter type is set for the first time or
+// no more bindings require a particular type of filter.
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+NDIS_STATUS
+(*TR_FILTER_CHANGE)(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+//
+// This action routine is called when the functional address
+// for the card has changed. It is passed the old functional
+// address as well as the new one.
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+NDIS_STATUS
+(*TR_ADDRESS_CHANGE)(
+ IN TR_FUNCTIONAL_ADDRESS OldFunctionalAddress,
+ IN TR_FUNCTIONAL_ADDRESS NewFunctionalAddress,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+
+//
+// This action routine is called when the group address
+// for the card has changed. It is passed the old group
+// address as well as the new one.
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+NDIS_STATUS
+(*TR_GROUP_CHANGE)(
+ IN TR_GROUP_ADDRESS OldGroupAddress,
+ IN TR_GROUP_ADDRESS NewGroupAddress,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+
+
+//
+// This action routine is called when the mac requests a close for
+// a particular binding *WHILE THE BINDING IS BEING INDICATED TO
+// THE PROTOCOL*. The filtering package can't get rid of the open
+// right away. So this routine will be called as soon as the
+// NdisIndicateReceive returns.
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+VOID
+(*TR_DEFERRED_CLOSE)(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+
+//
+// The binding info is threaded on two lists. When
+// the binding is free it is on a single freelist.
+//
+// When the binding is being used it is on a doubly linked
+// index list.
+//
+typedef struct _TR_BINDING_INFO {
+ NDIS_HANDLE MacBindingHandle;
+ NDIS_HANDLE NdisBindingContext;
+ UINT PacketFilters;
+ TR_FUNCTIONAL_ADDRESS FunctionalAddress;
+ struct _TR_BINDING_INFO *NextOpen;
+ struct _TR_BINDING_INFO *PrevOpen;
+ UINT References;
+ UCHAR FilterIndex;
+ BOOLEAN UsingGroupAddress;
+ BOOLEAN ReceivedAPacket;
+} TR_BINDING_INFO,*PTR_BINDING_INFO;
+
+//
+// An opaque type that contains a filter database.
+// The MAC need not know how it is structured.
+//
+typedef struct _TR_FILTER {
+
+ //
+ // Spin lock used to protect the filter from multiple accesses.
+ //
+ PNDIS_SPIN_LOCK Lock;
+
+ //
+ // ORing together of all the FunctionalAddresses.
+ //
+ TR_FUNCTIONAL_ADDRESS CombinedFunctionalAddress;
+
+ //
+ // Current group address in use.
+ //
+ TR_FUNCTIONAL_ADDRESS GroupAddress;
+
+ //
+ // Reference count on group address;
+ //
+ UINT GroupReferences;
+
+ //
+ // Combination of all the filters of all the open bindings.
+ //
+ UINT CombinedPacketFilter;
+
+ //
+ // Pointer to list of current opens.
+ //
+ PTR_BINDING_INFO OpenList;
+
+ //
+ // Address of the adapter associated with this filter.
+ //
+ UCHAR AdapterAddress[TR_LENGTH_OF_ADDRESS];
+
+ //
+ // Action routines to be invoked on notable changes in the filter.
+ //
+ TR_ADDRESS_CHANGE AddressChangeAction;
+ TR_GROUP_CHANGE GroupChangeAction;
+ TR_FILTER_CHANGE FilterChangeAction;
+ TR_DEFERRED_CLOSE CloseAction;
+
+ //
+ // Bit mask of opens that are available.
+ //
+ ULONG FreeBindingMask;
+
+} TR_FILTER,*PTR_FILTER;
+
+//
+// Only for internal wrapper use.
+//
+VOID
+TrInitializePackage(
+ VOID
+ );
+
+VOID
+TrReferencePackage(
+ VOID
+ );
+
+VOID
+TrDereferencePackage(
+ VOID
+ );
+
+//
+// Exported functions
+//
+EXPORT
+BOOLEAN
+TrCreateFilter(
+ IN TR_ADDRESS_CHANGE AddressChangeAction,
+ IN TR_GROUP_CHANGE GroupChangeAction,
+ IN TR_FILTER_CHANGE FilterChangeAction,
+ IN TR_DEFERRED_CLOSE CloseAction,
+ IN PUCHAR AdapterAddress,
+ IN PNDIS_SPIN_LOCK Lock,
+ OUT PTR_FILTER *Filter
+ );
+
+EXPORT
+VOID
+TrDeleteFilter(
+ IN PTR_FILTER Filter
+ );
+
+EXPORT
+BOOLEAN
+TrNoteFilterOpenAdapter(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE NdisBindingContext,
+ OUT PNDIS_HANDLE NdisFilterHandle
+ );
+
+EXPORT
+NDIS_STATUS
+TrDeleteFilterOpenAdapter(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+EXPORT
+NDIS_STATUS
+TrChangeFunctionalAddress(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN CHAR FunctionalAddressArray[TR_LENGTH_OF_FUNCTIONAL],
+ IN BOOLEAN Set
+ );
+
+EXPORT
+NDIS_STATUS
+TrChangeGroupAddress(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN CHAR GroupAddressArray[TR_LENGTH_OF_FUNCTIONAL],
+ IN BOOLEAN Set
+ );
+
+EXPORT
+BOOLEAN
+TrShouldAddressLoopBack(
+ IN PTR_FILTER Filter,
+ IN CHAR DestinationAddress[TR_LENGTH_OF_ADDRESS],
+ IN CHAR SourceAddress[TR_LENGTH_OF_ADDRESS]
+ );
+
+EXPORT
+NDIS_STATUS
+TrFilterAdjust(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT FilterClasses,
+ IN BOOLEAN Set
+ );
+
+EXPORT
+VOID
+TrFilterIndicateReceive(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+EXPORT
+VOID
+TrFilterDprIndicateReceive(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+EXPORT
+VOID
+TrFilterIndicateReceiveComplete(
+ IN PTR_FILTER Filter
+ );
+
+EXPORT
+VOID
+TrFilterDprIndicateReceiveComplete(
+ IN PTR_FILTER Filter
+ );
+
+
+#endif // _TR_FILTER_DEFS_
diff --git a/private/ntos/ndis/ndis30/wrapper.c b/private/ntos/ndis/ndis30/wrapper.c
new file mode 100644
index 000000000..9373647c4
--- /dev/null
+++ b/private/ntos/ndis/ndis30/wrapper.c
@@ -0,0 +1,17480 @@
+/*++
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ wrapper.c
+
+Abstract:
+
+ NDIS wrapper functions
+
+Author:
+
+ Adam Barr (adamba) 11-Jul-1990
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ 26-Feb-1991 JohnsonA Added Debugging Code
+ 10-Jul-1991 JohnsonA Implement revised Ndis Specs
+
+--*/
+
+
+#include <precomp.h>
+#pragma hdrstop
+
+#include <stdarg.h>
+
+//
+// The following are counters used for debugging
+//
+
+#if NDISDBG
+BOOLEAN NdisChkErrorFlag=TRUE; // parameter checking on
+int NdisMsgLevel=TRACE_ALL; // no trace
+#endif
+
+PNDIS_MAC_BLOCK NdisMacList = (PNDIS_MAC_BLOCK)NULL;
+NDIS_SPIN_LOCK NdisMacListLock = {0};
+
+BOOLEAN NdisInitialInitNeeded = TRUE;
+BOOLEAN NdisUpOnlyEventLogged = FALSE;
+
+//
+// Global variables for tracking memory allocated for shared memory
+//
+ERESOURCE SharedMemoryResource = {0};
+
+//
+// Global variables for tracking on NT 3.1 protocols that do not
+// use any of the filter packages.
+//
+PNDIS_OPEN_BLOCK GlobalOpenList = NULL;
+NDIS_SPIN_LOCK GlobalOpenListLock = {0};
+
+//
+// Debug variable for filter packages
+//
+#if DBG
+BOOLEAN NdisCheckBadDrivers = FALSE;
+
+extern NDIS_SPIN_LOCK PacketLogSpinLock;
+#endif
+
+//
+// Arcnet specific stuff
+//
+#define WRAPPER_ARC_BUFFERS 8
+#define WRAPPER_ARC_HEADER_SIZE 4
+
+//
+// Define constants used internally to identify regular opens from
+// query global statistics ones.
+//
+
+#define NDIS_OPEN_INTERNAL 1
+#define NDIS_OPEN_QUERY_STATISTICS 2
+
+//
+// This is the structure pointed to by the FsContext of an
+// open used for query statistics.
+//
+// NOTE: THIS STRUCTURE MUST, MUST, MUST ALIGN WITH THE
+// NDIS_M_USER_OPEN_CONTEXT STRUCTURE!!!
+//
+
+typedef struct _NDIS_USER_OPEN_CONTEXT {
+ PDEVICE_OBJECT DeviceObject;
+ PNDIS_ADAPTER_BLOCK AdapterBlock;
+ ULONG OidCount;
+ PNDIS_OID OidArray;
+} NDIS_USER_OPEN_CONTEXT, *PNDIS_USER_OPEN_CONTEXT;
+
+//
+// An active query single statistic request.
+//
+
+typedef struct _NDIS_QUERY_GLOBAL_REQUEST {
+ PIRP Irp;
+ NDIS_REQUEST Request;
+} NDIS_QUERY_GLOBAL_REQUEST, *PNDIS_QUERY_GLOBAL_REQUEST;
+
+
+//
+// An active query all statistics request.
+//
+
+typedef struct _NDIS_QUERY_ALL_REQUEST {
+ PIRP Irp;
+ NDIS_REQUEST Request;
+ NDIS_STATUS NdisStatus;
+ KEVENT Event;
+} NDIS_QUERY_ALL_REQUEST, *PNDIS_QUERY_ALL_REQUEST;
+
+
+//
+// An temporary request used during an open.
+//
+
+typedef struct _NDIS_QUERY_OPEN_REQUEST {
+ PIRP Irp;
+ NDIS_REQUEST Request;
+ NDIS_STATUS NdisStatus;
+ KEVENT Event;
+} NDIS_QUERY_OPEN_REQUEST, *PNDIS_QUERY_OPEN_REQUEST;
+
+
+//
+// Used to queue configuration parameters
+//
+
+typedef struct _NDIS_CONFIGURATION_PARAMETER_QUEUE {
+ struct _NDIS_CONFIGURATION_PARAMETER_QUEUE* Next;
+ NDIS_CONFIGURATION_PARAMETER Parameter;
+} NDIS_CONFIGURATION_PARAMETER_QUEUE, *PNDIS_CONFIGURATION_PARAMETER_QUEUE;
+
+//
+// Configuration Handle
+//
+
+typedef struct _NDIS_CONFIGURATION_HANDLE {
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable;
+ PNDIS_CONFIGURATION_PARAMETER_QUEUE ParameterList;
+} NDIS_CONFIGURATION_HANDLE, *PNDIS_CONFIGURATION_HANDLE;
+
+//
+// This is used during addadapter/miniportinitialize so that when the
+// driver calls any NdisImmediatexxx routines we can access its driverobj.
+//
+typedef struct _NDIS_WRAPPER_CONFIGURATION_HANDLE
+{
+ RTL_QUERY_REGISTRY_TABLE ParametersQueryTable[4];
+ PDRIVER_OBJECT DriverObject;
+}
+ NDIS_WRAPPER_CONFIGURATION_HANDLE,
+ *PNDIS_WRAPPER_CONFIGURATION_HANDLE;
+
+//
+// Describes an open NDIS file
+//
+
+typedef struct _NDIS_FILE_DESCRIPTOR {
+ PVOID Data;
+ NDIS_SPIN_LOCK Lock;
+ BOOLEAN Mapped;
+} NDIS_FILE_DESCRIPTOR, *PNDIS_FILE_DESCRIPTOR;
+
+//
+// IRP handlers established on behalf of NDIS devices by
+// the wrapper.
+//
+
+NTSTATUS
+NdisCreateIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ );
+
+NTSTATUS
+NdisDeviceControlIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ );
+
+NTSTATUS
+NdisCloseIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ );
+
+NTSTATUS
+NdisSuccessIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ );
+
+
+NTSTATUS
+NdisQueryOidList(
+ PNDIS_USER_OPEN_CONTEXT OpenContext,
+ PIRP Irp
+ );
+
+NTSTATUS
+NdisMQueryOidList(
+ PNDIS_M_USER_OPEN_CONTEXT OpenContext,
+ PIRP Irp
+ );
+
+VOID
+NdisLastCountRemovedFunction(
+ IN struct _KDPC *Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+
+
+BOOLEAN
+NdisQueueOpenOnProtocol(
+ IN PNDIS_OPEN_BLOCK OpenP,
+ IN PNDIS_PROTOCOL_BLOCK ProtP
+ );
+
+NDIS_STATUS
+MiniportAdjustMaximumLookahead(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+BOOLEAN
+NdisMKillOpen(
+ PNDIS_OPEN_BLOCK OldOpenP
+ );
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+NDIS_STATUS
+NdisMacReceiveHandler(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+VOID
+NdisMacReceiveCompleteHandler(
+ IN NDIS_HANDLE NdisBindingContext
+ );
+
+PNDIS_OPEN_BLOCK
+GetOpenBlockFromProtocolBindingContext(
+ IN NDIS_HANDLE ProtocolBindingContext
+ );
+
+NTSTATUS
+NdisShutdown(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ );
+
+VOID
+NdisUnload(
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+BOOLEAN
+NdisIsr(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID Context
+ );
+
+VOID
+NdisDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+VOID
+NdisOpenConfiguration(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE ConfigurationHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ );
+
+NTSTATUS
+WrapperSaveParameters(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+VOID
+NdisReadNetworkAddress(
+ OUT PNDIS_STATUS Status,
+ OUT PVOID * NetworkAddress,
+ OUT PUINT NetworkAddressLength,
+ IN NDIS_HANDLE ConfigurationHandle
+ );
+
+VOID
+NdisReadEisaSlotInformation(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PUINT SlotNumber,
+ OUT PNDIS_EISA_FUNCTION_INFORMATION EisaData
+ );
+
+VOID
+NdisReadEisaSlotInformationEx(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PUINT SlotNumber,
+ OUT PNDIS_EISA_FUNCTION_INFORMATION *EisaData,
+ OUT PUINT NumberOfFunctions
+ );
+
+VOID
+NdisReadMcaPosInformation(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PUINT ChannelNumber,
+ OUT PNDIS_MCA_POS_DATA McaData
+ );
+
+NDIS_STATUS
+NdisCallDriverAddAdapter(
+ IN PNDIS_MAC_BLOCK NewMacP
+ );
+
+NDIS_STATUS
+NdisMWanSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE NdisLinkHandle,
+ IN PVOID Packet
+ );
+
+
+CCHAR NdisMacAdapterDpcTargetProcessor = -1;
+
+//
+// Routines for dealing with making the MAC specific routines pagable
+//
+
+NDIS_SPIN_LOCK NdisMacReferenceLock = {0};
+KEVENT NdisMacPagedInEvent = {0};
+ULONG NdisMacReferenceCount = 0;
+PVOID NdisMacImageHandle = {0};
+
+VOID
+NdisMacInitializePackage(VOID)
+{
+ //
+ // Allocate the spin lock
+ //
+ NdisAllocateSpinLock(&NdisMacReferenceLock);
+
+ //
+ // Initialize the "in page" event.
+ //
+ KeInitializeEvent(
+ &NdisMacPagedInEvent,
+ NotificationEvent,
+ FALSE
+ );
+}
+
+VOID
+NdisMacReferencePackage(VOID)
+{
+
+ //
+ // Grab the spin lock
+ //
+ ACQUIRE_SPIN_LOCK(&NdisMacReferenceLock);
+
+ //
+ // Increment the reference count
+ //
+ NdisMacReferenceCount++;
+
+ if (NdisMacReferenceCount == 1) {
+
+ //
+ // We are the first reference. Page everything in.
+ //
+
+ //
+ // Clear the event
+ //
+ KeResetEvent(
+ &NdisMacPagedInEvent
+ );
+
+ //
+ // Set the spin lock free
+ //
+ RELEASE_SPIN_LOCK(&NdisMacReferenceLock);
+
+ //
+ // Page in all the functions
+ //
+ NdisMacImageHandle = MmLockPagableCodeSection(NdisIsr);
+
+ //
+ // Signal to everyone to go
+ //
+ KeSetEvent(
+ &NdisMacPagedInEvent,
+ 0L,
+ FALSE
+ );
+
+ } else {
+
+ //
+ // Set the spin lock free
+ //
+ RELEASE_SPIN_LOCK(&NdisMacReferenceLock);
+
+ //
+ // Wait for everything to be paged in
+ //
+ KeWaitForSingleObject(
+ &NdisMacPagedInEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ NULL
+ );
+
+ }
+
+}
+
+VOID
+NdisMacDereferencePackage(VOID)
+{
+
+ //
+ // Get the spin lock
+ //
+ ACQUIRE_SPIN_LOCK(&NdisMacReferenceLock);
+
+ NdisMacReferenceCount--;
+
+ if (NdisMacReferenceCount == 0) {
+
+ //
+ // Let next one in
+ //
+ RELEASE_SPIN_LOCK(&NdisMacReferenceLock);
+
+ //
+ // Page out all the functions
+ //
+ MmUnlockPagableImageSection(NdisMacImageHandle);
+
+ } else {
+
+ //
+ // Let next one in
+ //
+ RELEASE_SPIN_LOCK(&NdisMacReferenceLock);
+
+ }
+
+}
+
+
+
+//
+// Routines for dealing with making the initialization routines pagable
+//
+
+NDIS_SPIN_LOCK NdisInitReferenceLock = {0};
+KEVENT NdisInitPagedInEvent = {0};
+ULONG NdisInitReferenceCount = 0;
+PVOID NdisInitImageHandle = {0};
+
+VOID
+NdisInitInitializePackage(VOID)
+{
+ //
+ // Allocate the spin lock
+ //
+ NdisAllocateSpinLock(&NdisInitReferenceLock);
+
+ //
+ // Initialize the "in page" event.
+ //
+ KeInitializeEvent(
+ &NdisInitPagedInEvent,
+ NotificationEvent,
+ FALSE
+ );
+}
+
+VOID
+NdisInitReferencePackage(VOID)
+{
+
+ //
+ // Grab the spin lock
+ //
+ ACQUIRE_SPIN_LOCK(&NdisInitReferenceLock);
+
+ //
+ // Increment the reference count
+ //
+ NdisInitReferenceCount++;
+
+ if (NdisInitReferenceCount == 1) {
+
+ //
+ // We are the first reference. Page everything in.
+ //
+
+ //
+ // Clear the event
+ //
+ KeResetEvent(
+ &NdisInitPagedInEvent
+ );
+
+ //
+ // Set the spin lock free
+ //
+ RELEASE_SPIN_LOCK(&NdisInitReferenceLock);
+
+ //
+ // Page in all the functions
+ //
+ NdisInitImageHandle = MmLockPagableCodeSection(NdisReadConfiguration);
+
+ //
+ // Signal to everyone to go
+ //
+ KeSetEvent(
+ &NdisInitPagedInEvent,
+ 0L,
+ FALSE
+ );
+
+ } else {
+
+ //
+ // Set the spin lock free
+ //
+ RELEASE_SPIN_LOCK(&NdisInitReferenceLock);
+
+ //
+ // Wait for everything to be paged in
+ //
+ KeWaitForSingleObject(
+ &NdisInitPagedInEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ NULL
+ );
+
+ }
+
+}
+
+VOID
+NdisInitDereferencePackage(VOID)
+{
+
+ //
+ // Get the spin lock
+ //
+ ACQUIRE_SPIN_LOCK(&NdisInitReferenceLock);
+
+ NdisInitReferenceCount--;
+
+ if (NdisInitReferenceCount == 0) {
+
+ //
+ // Let next one in
+ //
+ RELEASE_SPIN_LOCK(&NdisInitReferenceLock);
+
+ //
+ // Page out all the functions
+ //
+ MmUnlockPagableImageSection(NdisInitImageHandle);
+
+ } else {
+
+ //
+ // Let next one in
+ //
+ RELEASE_SPIN_LOCK(&NdisInitReferenceLock);
+
+ }
+}
+
+
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGENDSI, NdisPciAssignResources)
+#pragma alloc_text(PAGENDSI, NdisReadMcaPosInformation)
+#pragma alloc_text(PAGENDSI, NdisReadEisaSlotInformationEx)
+#pragma alloc_text(PAGENDSI, NdisReadEisaSlotInformation)
+#pragma alloc_text(PAGENDSI, NdisCallDriverAddAdapter)
+#pragma alloc_text(PAGENDSW, NdisDereferenceMac)
+#pragma alloc_text(PAGENDSW, NdisDereferenceAdapter)
+#pragma alloc_text(PAGENDSW, NdisKillAdapter)
+#pragma alloc_text(PAGENDSW, NdisDeQueueAdapterOnMac)
+#pragma alloc_text(PAGENDSW, NdisQueueAdapterOnMac)
+#pragma alloc_text(PAGENDSW, NdisKillOpen)
+#pragma alloc_text(PAGENDSW, NdisKillOpenAndNotifyProtocol)
+#pragma alloc_text(PAGENDSW, NdisCloseIrpHandler)
+#pragma alloc_text(PAGENDSW, NdisCompleteQueryStatistics)
+#pragma alloc_text(PAGENDSW, NdisQueryOidList)
+#pragma alloc_text(PAGENDSW, NdisFinishOpen)
+#pragma alloc_text(PAGENDSW, NdisCompleteCloseAdapter)
+#pragma alloc_text(PAGENDSW, NdisCompleteOpenAdapter)
+#pragma alloc_text(PAGENDSI, NdisRegisterAdapterShutdownHandler)
+#pragma alloc_text(PAGENDSI, NdisRegisterAdapter)
+#pragma alloc_text(PAGENDSI, NdisInitializeWrapper)
+#pragma alloc_text(PAGENDSW, NdisMacReceiveCompleteHandler)
+#pragma alloc_text(PAGENDSW, NdisMacReceiveHandler)
+#pragma alloc_text(PAGENDSW, GetOpenBlockFromProtocolBindingContext)
+#pragma alloc_text(PAGENDSI, NdisAllocateDmaChannel)
+#pragma alloc_text(PAGENDSW, NdisShutdown)
+#pragma alloc_text(PAGENDSW, NdisUnload)
+#pragma alloc_text(PAGENDSI, NdisInitializeInterrupt)
+#pragma alloc_text(PAGENDSW, NdisDpc)
+#pragma alloc_text(PAGENDSW, NdisIsr)
+#pragma alloc_text(PAGENDSI, NdisMapIoSpace)
+#pragma alloc_text(PAGENDSI, NdisReadNetworkAddress)
+#pragma alloc_text(PAGENDSI, NdisCloseConfiguration)
+#pragma alloc_text(PAGENDSI, NdisReadConfiguration)
+#pragma alloc_text(PAGENDSI, WrapperSaveParameters)
+#pragma alloc_text(PAGENDSI, NdisOpenConfiguration)
+#pragma alloc_text(PAGENDSI, NdisOverrideBusNumber)
+#pragma alloc_text(INIT, DriverEntry)
+
+#endif
+
+
+//
+// This constant is used for places where NdisAllocateMemory
+// needs to be called and the HighestAcceptableAddress does
+// not matter.
+//
+
+static const NDIS_PHYSICAL_ADDRESS HighestAcceptableMax =
+ NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
+
+#if defined(_ALPHA_)
+
+typedef struct _NDIS_LOOKAHEAD_ELEMENT {
+
+ ULONG Length;
+ struct _NDIS_LOOKAHEAD_ELEMENT *Next;
+
+} NDIS_LOOKAHEAD_ELEMENT, *PNDIS_LOOKAHEAD_ELEMENT;
+
+NDIS_SPIN_LOCK NdisLookaheadBufferLock = {0};
+ULONG NdisLookaheadBufferLength = 0;
+PNDIS_LOOKAHEAD_ELEMENT NdisLookaheadBufferList = NULL;
+
+#endif
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ Temporary entry point needed to initialize the NDIS wrapper driver.
+
+Arguments:
+
+ DriverObject - Pointer to the driver object created by the system.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(RegistryPath);
+
+ return STATUS_SUCCESS;
+
+} // DriverEntry
+
+
+NDIS_STATUS
+NdisInitialInit(
+ IN PDRIVER_OBJECT Driver OPTIONAL
+ )
+/*++
+
+Routine Description:
+
+ This routine is used for all one time initialization of NDIS variables.
+ It seems that DriverEntry is *not* called for ndis.sys due to its type.
+
+Arguments:
+
+ Driver - Optional pointer to an NT driver object. Used to log an error,
+ if necessary.
+
+Return Value:
+
+ NTSTATUS - Status of initialization. Currently, this routine can only
+ fail if built for UP and loaded on MP.
+
+--*/
+
+{
+ Driver;
+
+ if (NdisInitialInitNeeded) {
+
+#if defined(UP_DRIVER)
+ //
+ // If built for UP, ensure that this is a UP system.
+ //
+
+ if (*KeNumberProcessors != 1) {
+
+ if (ARGUMENT_PRESENT(Driver) && !NdisUpOnlyEventLogged) {
+
+ //
+ // Log an error
+ //
+
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+
+ errorLogEntry = IoAllocateErrorLogEntry( Driver, sizeof(IO_ERROR_LOG_PACKET) );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->ErrorCode = EVENT_UP_DRIVER_ON_MP;
+ errorLogEntry->MajorFunctionCode = 0;
+ errorLogEntry->RetryCount = 0;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = 0;
+ errorLogEntry->SequenceNumber = 0;
+ errorLogEntry->IoControlCode = 0;
+ errorLogEntry->NumberOfStrings = 0;
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ NdisUpOnlyEventLogged = TRUE;
+ }
+
+ }
+
+ return NDIS_STATUS_BAD_VERSION; //!!! better status?
+ }
+
+#endif // defined(UP_DRIVER)
+
+ NdisInitialInitNeeded = FALSE;
+ NdisAllocateSpinLock(&NdisMacListLock);
+
+ ArcInitializePackage();
+ EthInitializePackage();
+ FddiInitializePackage();
+ TrInitializePackage();
+ MiniportInitializePackage();
+ NdisInitInitializePackage();
+ NdisMacInitializePackage();
+
+#if defined(_ALPHA_)
+ NdisAllocateSpinLock(&NdisLookaheadBufferLock);
+#endif
+
+ ExInitializeResource(&SharedMemoryResource);
+
+ NdisAllocateSpinLock(&GlobalOpenListLock);
+
+#if DBG
+ NdisAllocateSpinLock(&PacketLogSpinLock);
+#endif
+ }
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+//
+// Configuration Requests
+//
+
+VOID
+NdisOpenConfiguration(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE ConfigurationHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to open the parameter subkey of the
+ adapter registry tree.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ ConfigurationHandle - Returns a handle which is used in calls to
+ NdisReadConfiguration and NdisCloseConfiguration.
+
+ WrapperConfigurationContext - a handle pointing to an RTL_QUERY_REGISTRY_TABLE
+ that is set up for this driver's parameters.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Handle to be returned
+ //
+ PNDIS_CONFIGURATION_HANDLE HandleToReturn;
+
+
+ //
+ // Allocate the configuration handle
+ //
+
+ *Status = NdisAllocateMemory(
+ (PVOID*) &HandleToReturn,
+ sizeof(NDIS_CONFIGURATION_HANDLE),
+ 0,
+ HighestAcceptableMax);
+
+ if (*Status != NDIS_STATUS_SUCCESS) {
+ return;
+ }
+
+ HandleToReturn->KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ HandleToReturn->ParameterList = NULL;
+ *ConfigurationHandle = (NDIS_HANDLE) HandleToReturn;
+
+ return;
+}
+
+
+NTSTATUS
+WrapperSaveParameters(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called with the value for a specified parameter. It allocates
+ memory to hold the data and copies it over.
+
+Arguments:
+
+ ValueName - The name of the value (ignored).
+
+ ValueType - The type of the value.
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - Points to the head of the parameter chain.
+
+ EntryContext - A pointer to
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ NDIS_STATUS Status;
+
+ //
+ // Obtain the actual configuration handle structure
+ //
+
+ PNDIS_CONFIGURATION_HANDLE NdisConfigHandle =
+ (PNDIS_CONFIGURATION_HANDLE)Context;
+
+ //
+ // Where the user wants a pointer returned to the data.
+ //
+
+ PNDIS_CONFIGURATION_PARAMETER *ParameterValue =
+ (PNDIS_CONFIGURATION_PARAMETER *)EntryContext;
+
+ //
+ // Use this to link parameters allocated to this open
+ //
+
+ PNDIS_CONFIGURATION_PARAMETER_QUEUE ParameterNode;
+
+
+
+ //
+ // Allocate our parameter node
+ //
+
+ Status = NdisAllocateMemory(
+ (PVOID*)&ParameterNode,
+ sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE),
+ 0,
+ HighestAcceptableMax);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ return (NTSTATUS)Status;
+ }
+
+
+ *ParameterValue = &ParameterNode->Parameter;
+
+ //
+ // Map registry datatypes to ndis data types
+ //
+
+ if (ValueType == REG_DWORD) {
+
+ //
+ // The registry says that the data is in a dword boundary.
+ //
+
+ (*ParameterValue)->ParameterType = NdisParameterInteger;
+ (*ParameterValue)->ParameterData.IntegerData =
+ *((PULONG) ValueData);
+
+ } else if ((ValueType == REG_SZ) || (ValueType == REG_MULTI_SZ)) {
+
+ (*ParameterValue)->ParameterType =
+ (ValueType == REG_SZ) ? NdisParameterString : NdisParameterMultiString;
+
+ (*ParameterValue)->ParameterData.StringData.Buffer =
+ ExAllocatePoolWithTag(NonPagedPool, ValueLength, ' DN');
+
+ if (((*ParameterValue)->ParameterData.StringData.Buffer) == NULL) {
+ NdisFreeMemory (ParameterNode, sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE), 0);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory ((*ParameterValue)->ParameterData.StringData.Buffer,
+ ValueData, ValueLength);
+ (*ParameterValue)->ParameterData.StringData.Length = (USHORT)ValueLength;
+ (*ParameterValue)->ParameterData.StringData.MaximumLength = (USHORT)ValueLength;
+
+ //
+ // Special fix; if a string ends in a NULL and that is included
+ // in the length, remove it.
+ //
+
+ if (ValueType == REG_SZ) {
+ if ((((PUCHAR)ValueData)[ValueLength-1] == 0) &&
+ (((PUCHAR)ValueData)[ValueLength-2] == 0)) {
+ (*ParameterValue)->ParameterData.StringData.Length -= 2;
+ }
+ }
+
+ } else {
+
+ NdisFreeMemory(
+ ParameterNode,
+ sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE),
+ 0
+ );
+
+ return STATUS_OBJECT_NAME_NOT_FOUND;
+
+ }
+
+
+ //
+ // Queue this parameter node
+ //
+
+ ParameterNode->Next = NdisConfigHandle->ParameterList;
+ NdisConfigHandle->ParameterList = ParameterNode;
+
+ return STATUS_SUCCESS;
+
+}
+
+
+VOID
+NdisReadConfiguration(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_CONFIGURATION_PARAMETER *ParameterValue,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING Keyword,
+ IN NDIS_PARAMETER_TYPE ParameterType
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to read the parameter for a configuration
+ keyword from the configuration database.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ ParameterValue - Returns the value for this keyword.
+
+ ConfigurationHandle - Handle returned by NdisOpenConfiguration. Points
+ to the parameter subkey.
+
+ Keyword - The keyword to search for.
+
+ ParameterType - Ignored on NT, specifies the type of the value.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ //
+ // Status of our requests
+ //
+ NTSTATUS RegistryStatus;
+
+ //
+ // There are some built-in parameters which can always be
+ // read, even if not present in the registry. This is the
+ // number of them.
+ //
+
+#define BUILT_IN_COUNT 2
+
+ //
+ // The names of the built-in parameters.
+ //
+
+ static NDIS_STRING BuiltInStrings[BUILT_IN_COUNT] =
+ { NDIS_STRING_CONST ("Environment"),
+ NDIS_STRING_CONST ("ProcessorType") };
+
+ //
+ // The values to return for the built-in parameters.
+ //
+
+ static NDIS_CONFIGURATION_PARAMETER BuiltInParameters[BUILT_IN_COUNT] =
+ { { NdisParameterInteger, NdisEnvironmentWindowsNt },
+ { NdisParameterInteger,
+#if defined(_M_IX86)
+ NdisProcessorX86
+#elif defined(_M_MRX000)
+ NdisProcessorMips
+#elif defined(_ALPHA_)
+ NdisProcessorAlpha
+#else
+ NdisProcessorPpc
+#endif
+ } };
+
+
+ //
+ // Holds a null-terminated version of the keyword.
+ //
+ PWSTR KeywordBuffer;
+
+ //
+ // index variable
+ //
+ UINT i;
+
+ //
+ // Obtain the actual configuration handle structure
+ //
+ PNDIS_CONFIGURATION_HANDLE NdisConfigHandle =
+ (PNDIS_CONFIGURATION_HANDLE) ConfigurationHandle;
+
+
+
+ //
+ // First check if this is one of the built-in parameters.
+ //
+
+ for (i = 0; i < BUILT_IN_COUNT; i++) {
+ if (RtlEqualUnicodeString(Keyword, &BuiltInStrings[i], TRUE)) {
+ *Status = NDIS_STATUS_SUCCESS;
+ *ParameterValue = &BuiltInParameters[i];
+ return;
+ }
+ }
+
+
+ //
+ // Allocate room for a null-terminated version of the keyword
+ //
+
+ KeywordBuffer = (PWSTR)ExAllocatePoolWithTag(
+ NonPagedPool,
+ Keyword->Length + sizeof(WCHAR),
+ ' DN');
+ if (KeywordBuffer == NULL) {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+ RtlCopyMemory (KeywordBuffer, Keyword->Buffer, Keyword->Length);
+ *(PWCHAR)(((PUCHAR)KeywordBuffer)+Keyword->Length) = (WCHAR)L'\0';
+
+
+ //
+ // Finish initializing the table for this query.
+ //
+
+ NdisConfigHandle->KeyQueryTable[1].Name = KeywordBuffer;
+ NdisConfigHandle->KeyQueryTable[1].EntryContext = ParameterValue;
+
+ //
+ // Get the value from the registry; this chains it on to the
+ // parameter list at NdisConfigHandle.
+ //
+
+ RegistryStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ NdisConfigHandle->KeyQueryTable[3].Name,
+ NdisConfigHandle->KeyQueryTable,
+ NdisConfigHandle, // context
+ NULL);
+
+
+ ExFreePool (KeywordBuffer); // no longer needed
+
+ if (!NT_SUCCESS(RegistryStatus)) {
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+ return;
+
+}
+
+
+VOID
+NdisWriteConfiguration(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING Keyword,
+ PNDIS_CONFIGURATION_PARAMETER ParameterValue
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to write a parameter to the configuration database.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ ConfigurationHandle - Handle passed to the driver's AddAdapter routine.
+
+ Keyword - The keyword to set.
+
+ ParameterValue - Specifies the new value for this keyword.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ //
+ // Status of our requests
+ //
+ NTSTATUS RegistryStatus;
+
+ //
+ // The ConfigurationHandle is really a pointer to a registry query table.
+ //
+ PNDIS_CONFIGURATION_HANDLE NdisConfigHandle =
+ (PNDIS_CONFIGURATION_HANDLE) ConfigurationHandle;
+
+ //
+ // The name of the Parameters key.
+ //
+ PWSTR Parameters = L"\\Parameters";
+ ULONG ParametersLength = (wcslen(Parameters) + 1) * sizeof(WCHAR);
+
+ ULONG DriverLength = wcslen(NdisConfigHandle->KeyQueryTable[3].Name) * sizeof(WCHAR);
+
+ //
+ // Holds a null-terminated version of the name of the Parameters key.
+ //
+ PWSTR KeyNameBuffer;
+
+ //
+ // Holds a null-terminated version of the keyword.
+ //
+ PWSTR KeywordBuffer;
+
+ //
+ // Variables describing the parameter value.
+ //
+ PVOID ValueData;
+ ULONG ValueLength;
+ ULONG ValueType;
+
+ //
+ // Get the value data.
+ //
+ if ( ParameterValue->ParameterType == NdisParameterInteger ) {
+ ValueData = &ParameterValue->ParameterData.IntegerData;
+ ValueLength = sizeof(ParameterValue->ParameterData.IntegerData);
+ ValueType = REG_DWORD;
+ } else if ( (ParameterValue->ParameterType == NdisParameterString) ||
+ (ParameterValue->ParameterType == NdisParameterMultiString) ) {
+ ValueData = ParameterValue->ParameterData.StringData.Buffer;
+ ValueLength = ParameterValue->ParameterData.StringData.Length;
+ ValueType = ParameterValue->ParameterType == NdisParameterString ?
+ REG_SZ : REG_MULTI_SZ;
+ } else {
+ *Status = NDIS_STATUS_NOT_SUPPORTED;
+ return;
+ }
+
+ //
+ // Allocate room for the Parameters key name (e.g., L"Elnk3\Parameters").
+ //
+
+ KeyNameBuffer = (PWSTR)ExAllocatePoolWithTag(
+ NonPagedPool,
+ DriverLength + ParametersLength,
+ ' DN');
+ if (KeyNameBuffer == NULL) {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ RtlCopyMemory (KeyNameBuffer, NdisConfigHandle->KeyQueryTable[3].Name, DriverLength);
+ RtlCopyMemory ((PCHAR)KeyNameBuffer + DriverLength, Parameters, ParametersLength);
+
+ //
+ // Allocate room for a null-terminated version of the keyword
+ //
+
+ KeywordBuffer = (PWSTR)ExAllocatePoolWithTag(
+ NonPagedPool,
+ Keyword->Length + sizeof(WCHAR),
+ ' DN');
+ if (KeywordBuffer == NULL) {
+ ExFreePool (KeyNameBuffer);
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ RtlCopyMemory (KeywordBuffer, Keyword->Buffer, Keyword->Length);
+ *(PWCHAR)((PUCHAR)KeywordBuffer+Keyword->Length) = (WCHAR)L'\0';
+
+ //
+ // Write the value to the registry.
+ //
+
+ RegistryStatus = RtlWriteRegistryValue(
+ RTL_REGISTRY_SERVICES,
+ KeyNameBuffer,
+ KeywordBuffer,
+ ValueType,
+ ValueData,
+ ValueLength
+ );
+
+ ExFreePool (KeywordBuffer); // no longer needed
+ ExFreePool (KeyNameBuffer);
+
+ if (!NT_SUCCESS(RegistryStatus)) {
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+ return;
+
+}
+
+
+
+VOID
+NdisCloseConfiguration(
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to close a configuration database opened by
+ NdisOpenConfiguration.
+
+Arguments:
+
+ ConfigurationHandle - Handle returned by NdisOpenConfiguration.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Obtain the actual configuration handle structure
+ //
+ PNDIS_CONFIGURATION_HANDLE NdisConfigHandle =
+ (PNDIS_CONFIGURATION_HANDLE) ConfigurationHandle;
+
+ //
+ // Pointer to a parameter node
+ //
+ PNDIS_CONFIGURATION_PARAMETER_QUEUE ParameterNode;
+
+ //
+ // deallocate the parameter nodes
+ //
+
+ ParameterNode = NdisConfigHandle->ParameterList;
+
+ while (ParameterNode != NULL) {
+
+ NdisConfigHandle->ParameterList = ParameterNode->Next;
+
+ if ((ParameterNode->Parameter.ParameterType == NdisParameterString) ||
+ (ParameterNode->Parameter.ParameterType == NdisParameterMultiString)) {
+ ExFreePool (ParameterNode->Parameter.ParameterData.StringData.Buffer);
+ }
+
+ NdisFreeMemory(
+ ParameterNode,
+ sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE),
+ 0
+ );
+
+ ParameterNode = NdisConfigHandle->ParameterList;
+ }
+
+ NdisFreeMemory(
+ ConfigurationHandle,
+ sizeof(NDIS_CONFIGURATION_HANDLE),
+ 0);
+}
+
+
+
+VOID
+NdisReadNetworkAddress(
+ OUT PNDIS_STATUS Status,
+ OUT PVOID * NetworkAddress,
+ OUT PUINT NetworkAddressLength,
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to read the "NetworkAddress" parameter
+ from the configuration database. It reads the value as a
+ string separated by hyphens, then converts it to a binary
+ array and stores the result.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ NetworkAddress - Returns a pointer to the address.
+
+ NetworkAddressLength - Returns the length of the address.
+
+ ConfigurationHandle - Handle returned by NdisOpenConfiguration. Points
+ to the parameter subkey.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Convert the handle to its real value
+ //
+
+ PNDIS_CONFIGURATION_HANDLE NdisConfigHandle =
+ (PNDIS_CONFIGURATION_HANDLE) ConfigurationHandle;
+
+ //
+ // Variables used in reading the data from the registry
+ //
+
+ NTSTATUS NtStatus;
+ PWSTR NetworkAddressString = L"NetworkAddress";
+ PNDIS_CONFIGURATION_PARAMETER ParameterValue;
+
+ //
+ // Variables used in converting the address
+ //
+
+ UCHAR ConvertArray[3];
+ PWSTR CurrentReadLoc;
+ PWSTR AddressEnd;
+ PUCHAR CurrentWriteLoc;
+ UINT TotalBytesRead;
+ ULONG TempUlong;
+ ULONG AddressLength;
+
+
+ //
+ // Finish initializing the table for this query.
+ //
+
+ NdisConfigHandle->KeyQueryTable[1].Name = NetworkAddressString;
+ NdisConfigHandle->KeyQueryTable[1].EntryContext = &ParameterValue;
+
+ //
+ // Get the value from the registry; this chains it on to the
+ // parameter list at NdisConfigHandle.
+ //
+
+ NtStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ NdisConfigHandle->KeyQueryTable[3].Name,
+ NdisConfigHandle->KeyQueryTable,
+ NdisConfigHandle, // context
+ NULL);
+
+ if (NtStatus != NDIS_STATUS_SUCCESS) {
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+ if (ParameterValue->ParameterType != NdisParameterString) {
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+
+ //
+ // Now convert the address to binary (we do this
+ // in-place, since this allows us to use the memory
+ // already allocated which is automatically freed
+ // by NdisCloseConfiguration).
+ //
+
+ ConvertArray[2] = '\0';
+ CurrentReadLoc = (PWSTR)ParameterValue->ParameterData.StringData.Buffer;
+ CurrentWriteLoc = (PUCHAR)CurrentReadLoc;
+ TotalBytesRead = ParameterValue->ParameterData.StringData.Length;
+ AddressEnd = CurrentReadLoc + (TotalBytesRead / sizeof(WCHAR));
+ AddressLength = 0;
+
+ while ((CurrentReadLoc+2) <= AddressEnd) {
+
+ //
+ // Copy the current two-character value into ConvertArray
+ //
+
+ ConvertArray[0] = (UCHAR)(*(CurrentReadLoc++));
+ ConvertArray[1] = (UCHAR)(*(CurrentReadLoc++));
+
+ //
+ // Convert it to a Ulong and update
+ //
+
+ NtStatus = RtlCharToInteger (
+ ConvertArray,
+ 16,
+ &TempUlong);
+
+ if (!NT_SUCCESS(NtStatus)) {
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+ *(CurrentWriteLoc++) = (UCHAR)TempUlong;
+ ++AddressLength;
+
+ //
+ // If the next character is a hyphen, skip it.
+ //
+
+ if (CurrentReadLoc < AddressEnd) {
+ if (*CurrentReadLoc == (WCHAR)L'-') {
+ ++CurrentReadLoc;
+ }
+ }
+ }
+
+
+ *Status = STATUS_SUCCESS;
+ *NetworkAddress = ParameterValue->ParameterData.StringData.Buffer;
+ *NetworkAddressLength = AddressLength;
+
+}
+
+
+VOID
+NdisReadBindingInformation(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_STRING * Binding,
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to read the binding information for
+ this adapter from the configuration database. The value
+ returned is a pointer to a string containing the bind
+ that matches the export for the current AddAdapter call.
+
+ This function is meant for NDIS drivers that are layered
+ on top of other NDIS drivers. Binding would be passed to
+ NdisOpenAdapter as the AdapterName.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ Binding - Returns the binding data.
+
+ ConfigurationHandle - Handle returned by NdisOpenConfiguration. Points
+ to the parameter subkey.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Convert the handle to its real value
+ //
+
+ PNDIS_CONFIGURATION_HANDLE NdisConfigHandle =
+ (PNDIS_CONFIGURATION_HANDLE) ConfigurationHandle;
+
+ //
+ // Use this to link parameters allocated to this open
+ //
+
+ PNDIS_CONFIGURATION_PARAMETER_QUEUE ParameterNode;
+
+
+ //
+ // For layered drivers, this points to the binding. For
+ // non-layered drivers, it is NULL. This is set up before
+ // the call to AddAdapter.
+ //
+
+ if (NdisConfigHandle->KeyQueryTable[3].EntryContext == NULL) {
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+
+ //
+ // Allocate our parameter node
+ //
+
+ *Status = NdisAllocateMemory(
+ (PVOID*)&ParameterNode,
+ sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE),
+ 0,
+ HighestAcceptableMax);
+
+ if (*Status != NDIS_STATUS_SUCCESS) {
+ return;
+ }
+
+
+ //
+ // We set this to Integer because if we set it to String
+ // then CloseConfiguration would try to free the string,
+ // which we don't want.
+ //
+
+ ParameterNode->Parameter.ParameterType = NdisParameterInteger;
+
+ RtlInitUnicodeString(
+ &ParameterNode->Parameter.ParameterData.StringData,
+ NdisConfigHandle->KeyQueryTable[3].EntryContext);
+
+ //
+ // Queue this parameter node
+ //
+
+ ParameterNode->Next = NdisConfigHandle->ParameterList;
+ NdisConfigHandle->ParameterList = ParameterNode;
+
+ *Binding = &ParameterNode->Parameter.ParameterData.StringData;
+ *Status = NDIS_STATUS_SUCCESS;
+
+}
+
+//
+// Packet and Buffer requests
+//
+
+
+VOID
+NdisAllocatePacketPool(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE PoolHandle,
+ IN UINT NumberOfDescriptors,
+ IN UINT ProtocolReservedLength
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes a packet pool. All packets are the same
+ size for a given pool (as determined by ProtocolReservedLength),
+ so a simple linked list of free packets is set up initially.
+
+Arguments:
+
+ Status - Returns the final status (always NDIS_STATUS_SUCCESS).
+ PoolHandle - Returns a pointer to the pool.
+ NumberOfDescriptors - Number of packet descriptors needed.
+ ProtocolReservedLength - How long the ProtocolReserved field
+ should be for packets in this pool.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_PACKET_POOL TmpPool;
+ PUCHAR FreeEntry;
+ UINT PacketLength;
+ UINT i;
+
+ //
+ // Set up the size of packets in this pool (rounded
+ // up to sizeof(ULONG) for alignment).
+ //
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("==>NdisAllocatePacketPool\n");
+
+ PacketLength = sizeof(NDIS_PACKET) - 1 + ProtocolReservedLength;
+ PacketLength = ((PacketLength+(sizeof(ULONG)-1)) / sizeof(ULONG))
+ * sizeof(ULONG);
+
+ //
+ // Allocate space needed
+ //
+ TmpPool = (PNDIS_PACKET_POOL) ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(NDIS_PACKET_POOL) +
+ PacketLength * NumberOfDescriptors -
+ 1,
+ 'ppDN'
+ );
+
+ if (TmpPool == NULL) {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ TmpPool->PacketLength = PacketLength;
+
+ //
+ // First entry in free list is at beginning of pool space.
+ //
+
+ TmpPool->FreeList = (PNDIS_PACKET)TmpPool->Buffer;
+ FreeEntry = TmpPool->Buffer;
+
+ for (i = 1; i < NumberOfDescriptors; i++) {
+
+ //
+ // Each entry is linked to the "packet" PacketLength bytes
+ // ahead of it, using the Private.Head field.
+ //
+
+ ((PNDIS_PACKET)FreeEntry)->Private.Head =
+ (PNDIS_BUFFER)(FreeEntry + PacketLength);
+ FreeEntry += PacketLength;
+ }
+
+ //
+ // Final free list entry.
+ //
+
+ ((PNDIS_PACKET)FreeEntry)->Private.Head = (PNDIS_BUFFER)NULL;
+
+
+ NdisAllocateSpinLock(&TmpPool->SpinLock);
+
+ *Status = NDIS_STATUS_SUCCESS;
+ *PoolHandle = (NDIS_HANDLE)TmpPool;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisAllocatePacketPool\n");
+}
+
+
+
+VOID
+NdisAllocateBufferPool(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE PoolHandle,
+ IN UINT NumberOfDescriptors
+ )
+/*++
+
+Routine Description:
+
+ Initializes a block of storage so that buffer descriptors can be
+ allocated.
+
+Arguments:
+
+ Status - status of the request.
+ PoolHandle - handle that is used to specify the pool
+ NumberOfDescriptors - Number of buffer descriptors in the pool.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ //
+ // A nop for NT
+ //
+ UNREFERENCED_PARAMETER(NumberOfDescriptors);
+ *PoolHandle = NULL;
+ *Status = NDIS_STATUS_SUCCESS;
+
+}
+
+VOID
+NdisFreeBufferPool(
+ IN NDIS_HANDLE PoolHandle
+ )
+/*++
+
+Routine Description:
+
+ Terminates usage of a buffer descriptor pool.
+
+Arguments:
+
+ PoolHandle - handle that is used to specify the pool
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(PoolHandle);
+}
+
+VOID
+NdisAllocateBuffer(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_BUFFER * Buffer,
+ IN NDIS_HANDLE PoolHandle,
+ IN PVOID VirtualAddress,
+ IN UINT Length
+ )
+/*++
+
+Routine Description:
+
+ Creates a buffer descriptor to describe a segment of virtual memory
+ allocated via NdisAllocateMemory (which always allocates nonpaged).
+
+Arguments:
+
+ Status - Status of the request.
+ Buffer - Pointer to the allocated buffer descriptor.
+ PoolHandle - Handle that is used to specify the pool.
+ VirtualAddress - The virtual address of the buffer.
+ Length - The Length of the buffer.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ UNREFERENCED_PARAMETER(PoolHandle);
+
+ if ((*Buffer = IoAllocateMdl(
+ VirtualAddress,
+ Length,
+ FALSE,
+ FALSE,
+ NULL
+ )) == NULL) {
+
+ *Status = NDIS_STATUS_FAILURE;
+
+ } else {
+
+ MmBuildMdlForNonPagedPool(*Buffer);
+ (*Buffer)->Next = NULL;
+ *Status = NDIS_STATUS_SUCCESS;
+
+ }
+
+}
+
+
+VOID
+NdisCopyBuffer(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_BUFFER * Buffer,
+ IN NDIS_HANDLE PoolHandle,
+ IN PVOID MemoryDescriptor,
+ IN UINT Offset,
+ IN UINT Length
+ )
+/*++
+
+Routine Description:
+
+ Used to create a buffer descriptor given a memory descriptor.
+
+Arguments:
+
+ Status - Status of the request.
+ Buffer - Pointer to the allocated buffer descriptor.
+ PoolHandle - Handle that is used to specify the pool.
+ MemoryDescriptor - Pointer to the descriptor of the source memory.
+ Offset - The Offset in the sources memory from which the copy is to
+ begin
+ Length - Number of Bytes to copy.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PNDIS_BUFFER SourceDescriptor = (PNDIS_BUFFER)MemoryDescriptor;
+ PVOID BaseVa = (((PUCHAR)MmGetMdlVirtualAddress(SourceDescriptor)) + Offset);
+
+ UNREFERENCED_PARAMETER(PoolHandle);
+
+ if ((*Buffer = IoAllocateMdl(
+ BaseVa,
+ Length,
+ FALSE,
+ FALSE,
+ NULL
+ )) == NULL ) {
+
+ *Status = NDIS_STATUS_FAILURE;
+
+ } else {
+
+ IoBuildPartialMdl(
+ SourceDescriptor,
+ *Buffer,
+ BaseVa,
+ Length);
+
+ (*Buffer)->Next = NULL;
+ *Status = NDIS_STATUS_SUCCESS;
+
+ }
+
+}
+
+
+VOID
+NdisAllocatePacket(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_PACKET * Packet,
+ IN NDIS_HANDLE PoolHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Allocates a packet out of a packet pool.
+
+Arguments:
+
+ Status - Returns the final status.
+ Packet - Return a pointer to the packet.
+ PoolHandle - The packet pool to allocate from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_PACKET_POOL TmpPool = (PNDIS_PACKET_POOL)PoolHandle;
+
+ ACQUIRE_SPIN_LOCK(&TmpPool->SpinLock);
+
+
+ //
+ // See if any packets are on pool free list.
+ //
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisAllocatePacket\n");
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(PoolHandle)) {
+ NdisPrint1("AllocatePacket: NULL Pool address\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(PoolHandle)) {
+ NdisPrint1("AllocatePacket: Pool not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ if (TmpPool->FreeList == (PNDIS_PACKET)NULL) {
+
+ //
+ // No, cannot satisfy request.
+ //
+
+ RELEASE_SPIN_LOCK(&TmpPool->SpinLock);
+ *Status = NDIS_STATUS_RESOURCES;
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisAllocatePacket\n");
+ return;
+ }
+
+ //
+ // Yes, take free packet off head of list and return it.
+ //
+
+ *Packet = TmpPool->FreeList;
+ TmpPool->FreeList = (PNDIS_PACKET)(*Packet)->Private.Head;
+ RELEASE_SPIN_LOCK(&TmpPool->SpinLock);
+
+
+ //
+ // Clear packet elements.
+ //
+
+ RtlZeroMemory((PVOID)*Packet, TmpPool->PacketLength);
+ (*Packet)->Private.Head = (PNDIS_BUFFER)NULL; // don't need to set Tail
+ (*Packet)->Private.Pool = (PNDIS_PACKET_POOL)PoolHandle;
+ (*Packet)->Private.Count = 0;
+ (*Packet)->Private.PhysicalCount = 0;
+ (*Packet)->Private.TotalLength = 0;
+ (*Packet)->Private.ValidCounts = TRUE;
+
+ *Status = NDIS_STATUS_SUCCESS;
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisAllocatePacket\n");
+}
+
+
+VOID
+NdisUnchainBufferAtFront(
+ IN OUT PNDIS_PACKET Packet,
+ OUT PNDIS_BUFFER * Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ Takes a buffer off the front of a packet.
+
+Arguments:
+
+ Packet - The packet to be modified.
+ Buffer - Returns the packet on the front, or NULL.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ *Buffer = Packet->Private.Head;
+
+ //
+ // If packet is not empty, remove head buffer.
+ //
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisUnchainBufferAtFront\n");
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(Packet)) {
+ NdisPrint1("UnchainBufferAtFront: Null Packet Pointer\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(Packet)) {
+ NdisPrint1("UnchainBufferAtFront: Packet not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsPacket(Packet)) {
+ NdisPrint1("UnchainBufferAtFront: Illegal Packet Size\n");
+ DbgBreakPoint();
+ }
+ }
+
+ if (*Buffer != (PNDIS_BUFFER)NULL) {
+ Packet->Private.Head = (*Buffer)->Next; // may be NULL
+ (*Buffer)->Next = (PNDIS_BUFFER)NULL;
+ Packet->Private.ValidCounts = FALSE;
+ }
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisUnchainBufferAtFront\n");
+}
+
+VOID
+NdisUnchainBufferAtBack(
+ IN OUT PNDIS_PACKET Packet,
+ OUT PNDIS_BUFFER * Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ Takes a buffer off the end of a packet.
+
+Arguments:
+
+ Packet - The packet to be modified.
+ Buffer - Returns the packet on the end, or NULL.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_BUFFER TmpBufP = Packet->Private.Head;
+ PNDIS_BUFFER Result;
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisUnchainBufferAtBack\n");
+ IF_ERROR_CHK {
+ if (DbgIsNull(Packet)) {
+ NdisPrint1("UnchainBufferAtBack: Null Packet Pointer\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(Packet)) {
+ NdisPrint1("UnchainBufferAtBack: Packet not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsPacket(Packet)) {
+ NdisPrint1("UnchainBufferAtBack: Illegal Packet Size\n");
+ DbgBreakPoint();
+ }
+ }
+ if (TmpBufP != (PNDIS_BUFFER)NULL) {
+
+ //
+ // The packet is not empty, return the tail buffer.
+ //
+
+ Result = Packet->Private.Tail;
+ if (TmpBufP == Result) {
+
+ //
+ // There was only one buffer on the queue.
+ //
+
+ Packet->Private.Head = (PNDIS_BUFFER)NULL;
+ } else {
+
+ //
+ // Determine the new tail buffer.
+ //
+
+ while (TmpBufP->Next != Result) {
+ TmpBufP = TmpBufP->Next;
+ }
+ Packet->Private.Tail = TmpBufP;
+ TmpBufP->Next = NULL;
+ }
+
+ Result->Next = (PNDIS_BUFFER)NULL;
+ Packet->Private.ValidCounts = FALSE;
+ } else {
+
+ //
+ // Packet is empty.
+ //
+
+ Result = (PNDIS_BUFFER)NULL;
+ }
+
+ *Buffer = Result;
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisUnchainBufferAtBack\n");
+}
+
+
+
+VOID
+NdisCopyFromPacketToPacket(
+ IN PNDIS_PACKET Destination,
+ IN UINT DestinationOffset,
+ IN UINT BytesToCopy,
+ IN PNDIS_PACKET Source,
+ IN UINT SourceOffset,
+ OUT PUINT BytesCopied
+ )
+
+/*++
+
+Routine Description:
+
+ Copy from an ndis packet to an ndis packet.
+
+Arguments:
+
+ Destination - The packet should be copied in to.
+
+ DestinationOffset - The offset from the beginning of the packet
+ into which the data should start being placed.
+
+ BytesToCopy - The number of bytes to copy from the source packet.
+
+ Source - The ndis packet from which to copy data.
+
+ SourceOffset - The offset from the start of the packet from which
+ to start copying data.
+
+ BytesCopied - The number of bytes actually copied from the source
+ packet. This can be less than BytesToCopy if the source or destination
+ packet is too short.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ //
+ // Holds the count of the number of ndis buffers comprising the
+ // destination packet.
+ //
+ UINT DestinationBufferCount;
+
+ //
+ // Holds the count of the number of ndis buffers comprising the
+ // source packet.
+ //
+ UINT SourceBufferCount;
+
+ //
+ // Points to the buffer into which we are putting data.
+ //
+ PNDIS_BUFFER DestinationCurrentBuffer;
+
+ //
+ // Points to the buffer from which we are extracting data.
+ //
+ PNDIS_BUFFER SourceCurrentBuffer;
+
+ //
+ // Holds the virtual address of the current destination buffer.
+ //
+ PVOID DestinationVirtualAddress;
+
+ //
+ // Holds the virtual address of the current source buffer.
+ //
+ PVOID SourceVirtualAddress;
+
+ //
+ // Holds the length of the current destination buffer.
+ //
+ UINT DestinationCurrentLength;
+
+ //
+ // Holds the length of the current source buffer.
+ //
+ UINT SourceCurrentLength;
+
+ //
+ // Keep a local variable of BytesCopied so we aren't referencing
+ // through a pointer.
+ //
+ UINT LocalBytesCopied = 0;
+
+ //
+ // Take care of boundary condition of zero length copy.
+ //
+
+ *BytesCopied = 0;
+ if (!BytesToCopy) return;
+
+ //
+ // Get the first buffer of the destination.
+ //
+
+ NdisQueryPacket(
+ Destination,
+ NULL,
+ &DestinationBufferCount,
+ &DestinationCurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet.
+ //
+
+ if (!DestinationBufferCount) return;
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+
+ //
+ // Get the first buffer of the source.
+ //
+
+ NdisQueryPacket(
+ Source,
+ NULL,
+ &SourceBufferCount,
+ &SourceCurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet.
+ //
+
+ if (!SourceBufferCount) return;
+
+ NdisQueryBuffer(
+ SourceCurrentBuffer,
+ &SourceVirtualAddress,
+ &SourceCurrentLength
+ );
+
+ while (LocalBytesCopied < BytesToCopy) {
+
+ //
+ // Check to see whether we've exhausted the current destination
+ // buffer. If so, move onto the next one.
+ //
+
+ if (!DestinationCurrentLength) {
+
+ NdisGetNextBuffer(
+ DestinationCurrentBuffer,
+ &DestinationCurrentBuffer
+ );
+
+ if (!DestinationCurrentBuffer) {
+
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.)
+ //
+
+ break;
+
+ }
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+ continue;
+
+ }
+
+
+ //
+ // Check to see whether we've exhausted the current source
+ // buffer. If so, move onto the next one.
+ //
+
+ if (!SourceCurrentLength) {
+
+ NdisGetNextBuffer(
+ SourceCurrentBuffer,
+ &SourceCurrentBuffer
+ );
+
+ if (!SourceCurrentBuffer) {
+
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.)
+ //
+
+ break;
+
+ }
+
+ NdisQueryBuffer(
+ SourceCurrentBuffer,
+ &SourceVirtualAddress,
+ &SourceCurrentLength
+ );
+ continue;
+
+ }
+
+ //
+ // Try to get us up to the point to start the copy.
+ //
+
+ if (DestinationOffset) {
+
+ if (DestinationOffset > DestinationCurrentLength) {
+
+ //
+ // What we want isn't in this buffer.
+ //
+
+ DestinationOffset -= DestinationCurrentLength;
+ DestinationCurrentLength = 0;
+ continue;
+
+ } else {
+
+ DestinationVirtualAddress = (PCHAR)DestinationVirtualAddress
+ + DestinationOffset;
+ DestinationCurrentLength -= DestinationOffset;
+ DestinationOffset = 0;
+
+ }
+
+ }
+
+ //
+ // Try to get us up to the point to start the copy.
+ //
+
+ if (SourceOffset) {
+
+ if (SourceOffset > SourceCurrentLength) {
+
+ //
+ // What we want isn't in this buffer.
+ //
+
+ SourceOffset -= SourceCurrentLength;
+ SourceCurrentLength = 0;
+ continue;
+
+ } else {
+
+ SourceVirtualAddress = (PCHAR)SourceVirtualAddress
+ + SourceOffset;
+ SourceCurrentLength -= SourceOffset;
+ SourceOffset = 0;
+
+ }
+
+ }
+
+ //
+ // Copy the data.
+ //
+
+ {
+
+ //
+ // Holds the amount of data to move.
+ //
+ UINT AmountToMove;
+
+ //
+ // Holds the amount desired remaining.
+ //
+ UINT Remaining = BytesToCopy - LocalBytesCopied;
+
+ AmountToMove =
+ ((SourceCurrentLength <= DestinationCurrentLength)?
+ (SourceCurrentLength):(DestinationCurrentLength));
+
+ AmountToMove = ((Remaining < AmountToMove)?
+ (Remaining):(AmountToMove));
+
+ RtlCopyMemory(
+ DestinationVirtualAddress,
+ SourceVirtualAddress,
+ AmountToMove
+ );
+
+ DestinationVirtualAddress =
+ (PCHAR)DestinationVirtualAddress + AmountToMove;
+ SourceVirtualAddress =
+ (PCHAR)SourceVirtualAddress + AmountToMove;
+
+ LocalBytesCopied += AmountToMove;
+ SourceCurrentLength -= AmountToMove;
+ DestinationCurrentLength -= AmountToMove;
+
+ }
+
+ }
+
+ *BytesCopied = LocalBytesCopied;
+
+}
+
+//
+// Operating System Requests
+//
+//
+
+
+VOID
+NdisMapIoSpace(
+ OUT PNDIS_STATUS Status,
+ OUT PVOID * VirtualAddress,
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress,
+ IN UINT Length
+ )
+/*++
+
+Routine Description:
+
+ Map virtual memory address space onto a physical address.
+
+Arguments:
+
+ Status - resulting status
+ VirtualAddress - resulting address in virtual space.
+ NdisAdapterHandle - value returned by NdisRegisterAdapter.
+ PhysicalAddress - Physical address.
+ Length - Size of requested memory mapping
+
+Return Value:
+
+ none.
+
+--*/
+{
+ ULONG addressSpace = 0;
+ ULONG NumberOfElements;
+ PHYSICAL_ADDRESS PhysicalTemp;
+ PCM_RESOURCE_LIST Resources;
+ BOOLEAN Conflict;
+ NTSTATUS NtStatus;
+ PNDIS_ADAPTER_BLOCK AdptrP = (PNDIS_ADAPTER_BLOCK)(NdisAdapterHandle);
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(NdisAdapterHandle);
+
+ //
+ // First check if any bus access is allowed
+ //
+
+ if ((((AdptrP->DeviceObject != NULL) ?
+ AdptrP->BusType :
+ Miniport->BusType) == (NDIS_INTERFACE_TYPE)-1) ||
+ (((AdptrP->DeviceObject != NULL) ?
+ AdptrP->BusNumber :
+ Miniport->BusNumber) == (ULONG)-1)) {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ //
+ // First check for resource conflict by expanding current resource list,
+ // adding in the mapped space, and then re-submitting the resource list.
+ //
+
+ if (((AdptrP->DeviceObject != NULL) ?
+ AdptrP->Resources :
+ Miniport->Resources) != NULL) {
+
+ NumberOfElements = ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->Resources->List[0].PartialResourceList.Count + 1:
+ Miniport->Resources->List[0].PartialResourceList.Count + 1);
+
+ } else {
+
+ NumberOfElements = 1;
+ }
+
+ //
+ // First check for resource conflict by expanding current resource list,
+ // adding in the mapped space, and then re-submitting the resource list.
+ //
+
+ Resources = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ NumberOfElements,
+ 'lrDN'
+ );
+
+ if (Resources == NULL) {
+
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+
+ }
+
+ if (((AdptrP->DeviceObject != NULL) ?
+ AdptrP->Resources :
+ Miniport->Resources) != NULL) {
+
+ RtlCopyMemory (Resources,
+ ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->Resources:
+ Miniport->Resources),
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ (NumberOfElements-1)
+ );
+ } else {
+
+ //
+ // Setup initial resource info -- NOTE: This is definitely a mini-port
+ //
+ ASSERT(AdptrP->DeviceObject == NULL);
+ Resources->Count = 1;
+ Resources->List[0].InterfaceType = Miniport->AdapterType;
+ Resources->List[0].BusNumber = Miniport->BusNumber;
+ Resources->List[0].PartialResourceList.Version = 0;
+ Resources->List[0].PartialResourceList.Revision = 0;
+ Resources->List[0].PartialResourceList.Count = 0;
+
+ }
+
+ //
+ // Setup memory
+ //
+
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Type =
+ CmResourceTypeMemory;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].ShareDisposition =
+ CmResourceShareDeviceExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Flags =
+ CM_RESOURCE_MEMORY_READ_WRITE;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Memory.Start =
+ PhysicalAddress;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Memory.Length =
+ Length;
+ Resources->List[0].PartialResourceList.Count++;
+
+
+ //
+ // Make the call
+ //
+
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->MacHandle->NdisMacInfo->NdisWrapperDriver :
+ Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver),
+ NULL,
+ 0,
+ ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->DeviceObject:
+ Miniport->DeviceObject),
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ Resources->List[0].PartialResourceList.Count,
+ TRUE,
+ &Conflict
+ );
+
+ //
+ // Check for conflict.
+ //
+
+ if (((AdptrP->DeviceObject != NULL) ?
+ AdptrP->Resources :
+ Miniport->Resources) != NULL) {
+ ExFreePool(((AdptrP->DeviceObject != NULL) ?
+ AdptrP->Resources:
+ Miniport->Resources));
+ }
+
+ if (AdptrP->DeviceObject != NULL) {
+ AdptrP->Resources = Resources;
+ } else {
+ Miniport->Resources = Resources;
+ }
+
+ if (Conflict || (NtStatus != STATUS_SUCCESS)) {
+
+
+ if (Conflict) {
+
+
+ //
+ // Log an error
+ //
+
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ volatile ULONG i;
+ ULONG StringSize;
+ PUCHAR Place;
+ PWCH baseFileName;
+ WCHAR Character;
+ ULONG Value;
+
+ baseFileName = ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.Buffer :
+ Miniport->MiniportName.Buffer);
+
+ //
+ // Parse out the path name, leaving only the device name.
+ //
+
+ for ( i = 0;
+ i < ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.Length :
+ Miniport->MiniportName.Length) / sizeof(WCHAR);
+ i++ ) {
+
+ //
+ // If s points to a directory separator, set baseFileName to
+ // the character after the separator.
+ //
+
+ if ( ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.Buffer[i] :
+ Miniport->MiniportName.Buffer[i]) == OBJ_NAME_PATH_SEPARATOR ) {
+ baseFileName = ((AdptrP->DeviceObject != NULL) ?
+ &(AdptrP->AdapterName.Buffer[++i]):
+ &(Miniport->MiniportName.Buffer[++i]));
+ }
+
+ }
+
+ StringSize = ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.MaximumLength :
+ Miniport->MiniportName.MaximumLength) -
+ (((ULONG)baseFileName) -
+ ((AdptrP->DeviceObject != NULL) ?
+ ((ULONG)AdptrP->AdapterName.Buffer) :
+ ((ULONG)Miniport->MiniportName.Buffer)));
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->DeviceObject:
+ Miniport->DeviceObject),
+ (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize +
+ 34) // wstrlen("FFFFFFFFFFFFFFFF") * sizeof(WHCAR) + sizeof(UNICODE_NULL)
+ );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->ErrorCode = EVENT_NDIS_MEMORY_CONFLICT;
+
+ //
+ // store the time
+ //
+
+ errorLogEntry->MajorFunctionCode = 0;
+ errorLogEntry->RetryCount = 0;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = 0;
+ errorLogEntry->SequenceNumber = 0;
+ errorLogEntry->IoControlCode = 0;
+
+ //
+ // Set string information
+ //
+
+ if (StringSize != 0) {
+
+ errorLogEntry->NumberOfStrings = 1;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+
+ RtlCopyMemory (
+ ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET),
+ (PVOID)baseFileName,
+ StringSize
+ );
+
+ Place = ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize;
+
+ } else {
+
+ Place = ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET);
+
+ errorLogEntry->NumberOfStrings = 0;
+
+ }
+
+ errorLogEntry->NumberOfStrings++;
+
+ //
+ // Put in memory address
+ //
+
+ for (StringSize = 0; StringSize < 2; StringSize++) {
+
+ if (StringSize == 0) {
+
+ //
+ // Do high part
+ //
+
+ Value = NdisGetPhysicalAddressHigh(PhysicalAddress);
+
+ } else {
+
+ //
+ // Do Low part
+ //
+
+ Value = NdisGetPhysicalAddressLow(PhysicalAddress);
+
+ }
+
+ //
+ // Convert value
+ //
+
+ for (i = 1; i <= (sizeof(ULONG) * 2); i++) {
+
+ switch ((Value >> (((sizeof(ULONG) * 2) - i) * 4)) & 0x0F) {
+
+ case 0:
+ Character = L'0';
+ break;
+ case 1:
+ Character = L'1';
+ break;
+ case 2:
+ Character = L'2';
+ break;
+ case 3:
+ Character = L'3';
+ break;
+ case 4:
+ Character = L'4';
+ break;
+ case 5:
+ Character = L'5';
+ break;
+ case 6:
+ Character = L'6';
+ break;
+ case 7:
+ Character = L'7';
+ break;
+ case 8:
+ Character = L'8';
+ break;
+ case 9:
+ Character = L'9';
+ break;
+ case 10:
+ Character = L'A';
+ break;
+ case 11:
+ Character = L'B';
+ break;
+ case 12:
+ Character = L'C';
+ break;
+ case 13:
+ Character = L'D';
+ break;
+ case 14:
+ Character = L'E';
+ break;
+ case 15:
+ Character = L'F';
+ break;
+ }
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ Place += sizeof(WCHAR);
+
+ }
+
+ }
+
+ Character = UNICODE_NULL;
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ //
+ // write it out
+ //
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+ *Status = NDIS_STATUS_RESOURCE_CONFLICT;
+ return;
+
+ }
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+
+ if ( !HalTranslateBusAddress(
+ ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->BusType:
+ Miniport->BusType),
+ ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->BusNumber :
+ Miniport->BusNumber),
+ PhysicalAddress,
+ &addressSpace,
+ &PhysicalTemp
+ ) ) {
+
+ //
+ // It would be nice to return a better status here, but we only get
+ // TRUE/FALSE back from HalTranslateBusAddress.
+ //
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+ if (addressSpace == 0) {
+
+ //
+ // memory space
+ //
+
+ *VirtualAddress = MmMapIoSpace(PhysicalTemp, (Length), FALSE);
+
+ } else {
+
+ //
+ // I/O space
+ //
+
+ *VirtualAddress = (PVOID)(PhysicalTemp.LowPart);
+
+ }
+
+ if (*VirtualAddress == NULL) {
+ *Status = NDIS_STATUS_RESOURCES;
+ } else {
+ *Status = NDIS_STATUS_SUCCESS;
+ }
+}
+
+NDIS_STATUS
+NdisAllocateMemory(
+ OUT PVOID *VirtualAddress,
+ IN UINT Length,
+ IN UINT MemoryFlags,
+ IN NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress
+ )
+/*++
+
+Routine Description:
+
+ Allocate memory for use by a protocol or a MAC driver
+
+Arguments:
+
+ VirtualAddress - Returns a pointer to the allocated memory.
+ Length - Size of requested allocation in bytes.
+ MaximumPhysicalAddress - Highest addressable address of the allocated
+ memory.. 0 means highest system memory possible.
+ MemoryFlags - Bit mask that allows the caller to specify attributes
+ of the allocated memory. 0 means standard memory.
+
+ other options:
+
+ NDIS_MEMORY_CONTIGUOUS
+ NDIS_MEMORY_NONCACHED
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if successful.
+ NDIS_STATUS_FAILURE if not successful. *VirtualAddress will be NULL.
+
+
+--*/
+{
+ //
+ // Depending on the value of MemoryFlags, we allocate three different
+ // types of memory.
+ //
+
+ if (MemoryFlags == 0) {
+
+ *VirtualAddress = ExAllocatePoolWithTag(NonPagedPool, Length, 'maDN');
+
+ } else if (MemoryFlags & NDIS_MEMORY_NONCACHED) {
+
+ *VirtualAddress = MmAllocateNonCachedMemory(Length);
+
+ } else if (MemoryFlags & NDIS_MEMORY_CONTIGUOUS) {
+
+ *VirtualAddress = MmAllocateContiguousMemory(Length, HighestAcceptableAddress);
+
+ }
+
+ if (*VirtualAddress == NULL) {
+
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ return NDIS_STATUS_SUCCESS;
+
+}
+
+
+VOID
+NdisFreeMemory(
+ IN PVOID VirtualAddress,
+ IN UINT Length,
+ IN UINT MemoryFlags
+ )
+/*++
+
+Routine Description:
+
+ Releases memory allocated using NdisAllocateMemory.
+
+Arguments:
+
+ VirtualAddress - Pointer to the memory to be freed.
+ Length - Size of allocation in bytes.
+ MemoryFlags - Bit mask that allows the caller to specify attributes
+ of the allocated memory. 0 means standard memory.
+
+ other options:
+
+ NDIS_MEMORY_CONTIGUOUS
+ NDIS_MEMORY_NONCACHED
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Depending on the value of MemoryFlags, we allocate three free 3
+ // types of memory.
+ //
+
+ if (MemoryFlags == 0) {
+
+ ExFreePool(VirtualAddress);
+
+ } else if (MemoryFlags & NDIS_MEMORY_NONCACHED) {
+
+ MmFreeNonCachedMemory(VirtualAddress, Length);
+
+ } else if (MemoryFlags & NDIS_MEMORY_CONTIGUOUS) {
+
+ MmFreeContiguousMemory(VirtualAddress);
+
+ }
+
+}
+
+VOID
+NdisInitializeTimer(
+ IN OUT PNDIS_TIMER NdisTimer,
+ IN PNDIS_TIMER_FUNCTION TimerFunction,
+ IN PVOID FunctionContext
+ )
+/*++
+
+Routine Description:
+
+ Sets up an NdisTimer object, initializing the DPC in the timer to
+ the function and context.
+
+Arguments:
+
+ NdisTimer - the timer object.
+ TimerFunction - Routine to start.
+ FunctionContext - Context of TimerFunction.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ KeInitializeTimer(&(NdisTimer)->Timer);
+
+ //
+ // Initialize our dpc. If Dpc was previously initialized, this will
+ // reinitialize it.
+ //
+
+ KeInitializeDpc(
+ &NdisTimer->Dpc,
+ (PKDEFERRED_ROUTINE) TimerFunction,
+ FunctionContext
+ );
+
+ KeSetImportanceDpc(
+ &NdisTimer->Dpc,
+ LowImportance
+ );
+}
+
+
+VOID
+NdisSetTimer(
+ IN PNDIS_TIMER NdisTimer,
+ IN UINT MillisecondsToDelay
+ )
+/*++
+
+Routine Description:
+
+ Sets up TimerFunction to fire after MillisecondsToDelay.
+
+Arguments:
+
+ NdisTimer - the timer object.
+ MillisecondsToDelay - Amount of time before TimerFunction is started.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ LARGE_INTEGER FireUpTime;
+
+ FireUpTime.QuadPart = Int32x32To64((LONG)MillisecondsToDelay, -10000);
+
+ //
+ // Set the timer
+ //
+ KeSetTimer(
+ &NdisTimer->Timer,
+ FireUpTime,
+ &NdisTimer->Dpc
+ );
+}
+
+
+BOOLEAN
+NdisIsr(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ Handles ALL Mac interrupts, calling the appropriate Mac ISR and DPC
+ depending on the context.
+
+Arguments:
+
+ Interrupt - Interrupt object for the Mac.
+
+ Context - Really a pointer to the interrupt.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Get adapter from context.
+ //
+
+ PNDIS_INTERRUPT NdisInterrupt = (PNDIS_INTERRUPT)(Context);
+
+ BOOLEAN (*InterruptIsr)(PVOID) = (BOOLEAN (*) (PVOID))(NdisInterrupt->MacIsr);
+
+ UNREFERENCED_PARAMETER(Interrupt);
+
+ //
+ // Call MacIsr
+ //
+
+ if((*InterruptIsr)(NdisInterrupt->InterruptContext) != FALSE){
+
+ //
+ // Queue MacDpc if needed
+ //
+
+ Increment((PLONG)&NdisInterrupt->DpcCount,&NdisInterrupt->DpcCountLock);
+
+ if (!(KeInsertQueueDpc(&(NdisInterrupt->InterruptDpc),NULL,NULL))) {
+
+ //
+ // If the DPC was already queued, then we have an extra
+ // reference (we do it this way to ensure that the reference
+ // is added *before* the DPC is queued).
+ //
+
+ Decrement((PLONG)&NdisInterrupt->DpcCount,&NdisInterrupt->DpcCountLock);
+
+ if (NdisInterrupt->Removing && (NdisInterrupt->DpcCount==0)) {
+
+ //
+ // We need to queue a DPC to set the event because we
+ // can't do it from the ISR. We know that the interrupt
+ // DPC won't fire because the refcount is 0, so we reuse it.
+ //
+
+ KeInitializeDpc(
+ &NdisInterrupt->InterruptDpc,
+ NdisLastCountRemovedFunction,
+ (PVOID)(&NdisInterrupt->DpcsCompletedEvent)
+ );
+
+ //
+ // When NdisLastCountRemovedFunction runs it will set
+ // the event.
+ //
+
+ KeInsertQueueDpc (&(NdisInterrupt->InterruptDpc), NULL, NULL);
+
+ }
+ }
+
+ return TRUE;
+
+ }
+
+ return FALSE;
+
+}
+
+VOID
+NdisLastCountRemovedFunction(
+ IN struct _KDPC *Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+
+/*++
+
+Routine Description:
+
+ Queued from NdisIsr if the refcount is zero and we need to
+ set the event, since we can't do that from an ISR.
+
+Arguments:
+
+ Dpc - Will be NdisInterrupt->InterruptDpc.
+
+ DeferredContext - Points to the event to set.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UNREFERENCED_PARAMETER (Dpc);
+ UNREFERENCED_PARAMETER (SystemArgument1);
+ UNREFERENCED_PARAMETER (SystemArgument2);
+
+ KeSetEvent(
+ (PKEVENT)DeferredContext,
+ 0L,
+ FALSE
+ );
+}
+
+
+VOID
+NdisDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+/*++
+
+Routine Description:
+
+ Handles ALL Mac interrupt DPCs, calling the appropriate Mac DPC
+ depending on the context.
+
+Arguments:
+
+ Interrupt - Interrupt object for the Mac.
+
+ Context - Really a pointer to the Interrupt.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Get adapter from context.
+ //
+
+ PNDIS_INTERRUPT NdisInterrupt = (PNDIS_INTERRUPT)(InterruptContext);
+
+ VOID (*MacDpc)(PVOID) = (VOID (*) (PVOID))(NdisInterrupt->MacDpc);
+
+ //
+ // Call MacDpc
+ //
+
+ (*((PNDIS_DEFERRED_PROCESSING)MacDpc))(SystemSpecific1,
+ NdisInterrupt->InterruptContext,
+ SystemSpecific2,
+ SystemSpecific3
+ );
+
+ Decrement((PLONG)&NdisInterrupt->DpcCount,&NdisInterrupt->DpcCountLock);
+
+ if (NdisInterrupt->Removing && (NdisInterrupt->DpcCount==0)) {
+
+ KeSetEvent(
+ &NdisInterrupt->DpcsCompletedEvent,
+ 0L,
+ FALSE
+ );
+ }
+
+
+}
+
+
+VOID
+NdisInitializeInterrupt(
+ OUT PNDIS_STATUS Status,
+ IN OUT PNDIS_INTERRUPT NdisInterrupt,
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN PNDIS_INTERRUPT_SERVICE InterruptServiceRoutine,
+ IN PVOID InterruptContext,
+ IN PNDIS_DEFERRED_PROCESSING DeferredProcessingRoutine,
+ IN UINT InterruptVector,
+ IN UINT InterruptLevel,
+ IN BOOLEAN SharedInterrupt,
+ IN NDIS_INTERRUPT_MODE InterruptMode
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes the interrupt and sets up the Dpc.
+
+Arguments:
+
+ Status - Status of this request.
+ InterruptDpc - The Dpc object corresponding to DeferredProcessingRoutine.
+ Interrupt - Points to driver allocated memory that the wrapper fills in
+ with information about the interrupt handler.
+ InterruptServiceRoutine - The ISR that is called for this interrupt.
+ InterruptContext - Value passed to the ISR.
+ DeferredProcessingRoutine - The DPC queued by the ISR.
+ InterruptVector - Interrupt number used by the ISR.
+ InterruptMode - Type of interrupt the adapter generates.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ NTSTATUS NtStatus;
+ PNDIS_ADAPTER_BLOCK AdptrP = (PNDIS_ADAPTER_BLOCK)(NdisAdapterHandle);
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(NdisAdapterHandle);
+ ULONG Vector;
+ ULONG NumberOfElements;
+ KIRQL Irql;
+ KAFFINITY InterruptAffinity;
+ PCM_RESOURCE_LIST Resources;
+ BOOLEAN Conflict;
+ BOOLEAN IsAMiniport;
+ PNDIS_MINIPORT_INTERRUPT MiniportInterrupt = (PNDIS_MINIPORT_INTERRUPT)(NdisInterrupt);
+
+ IsAMiniport = (AdptrP->DeviceObject == NULL);
+
+ //
+ // First check if any bus access is allowed
+ //
+
+ if (((IsAMiniport ?
+ Miniport->BusType:
+ AdptrP->BusType) == (NDIS_INTERFACE_TYPE)-1) ||
+ ((IsAMiniport ?
+ Miniport->BusNumber:
+ AdptrP->BusNumber) == (ULONG)-1)) {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ //
+ // First check for resource conflict by expanding current resource list,
+ // adding in the interrupt, and then re-submitting the resource list.
+ //
+
+ if ((IsAMiniport ?
+ Miniport->Resources:
+ AdptrP->Resources) != NULL) {
+
+ NumberOfElements = (IsAMiniport ?
+ Miniport->Resources->List[0].PartialResourceList.Count + 1 :
+ AdptrP->Resources->List[0].PartialResourceList.Count + 1);
+
+ } else {
+
+ NumberOfElements = 1;
+ }
+
+ Resources = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ NumberOfElements,
+ 'lrDN'
+ );
+
+ if (Resources == NULL) {
+
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+
+ }
+
+ if ((IsAMiniport ?
+ Miniport->Resources :
+ AdptrP->Resources) != NULL) {
+
+ RtlCopyMemory (Resources,
+ (IsAMiniport ?
+ Miniport->Resources :
+ AdptrP->Resources),
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ (NumberOfElements - 1)
+ );
+
+ } else {
+
+ //
+ // Setup initial resource info
+ //
+ ASSERT(IsAMiniport);
+ Resources->Count = 1;
+ Resources->List[0].InterfaceType = Miniport->AdapterType;
+ Resources->List[0].BusNumber = Miniport->BusNumber;
+ Resources->List[0].PartialResourceList.Version = 0;
+ Resources->List[0].PartialResourceList.Revision = 0;
+ Resources->List[0].PartialResourceList.Count = 0;
+
+ }
+
+ //
+ // Setup interrupt
+ //
+
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Type =
+ CmResourceTypeInterrupt;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].ShareDisposition =
+ SharedInterrupt ? CmResourceShareShared : CmResourceShareDeviceExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Flags =
+ (InterruptMode == NdisInterruptLatched) ?
+ CM_RESOURCE_INTERRUPT_LATCHED :
+ CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Interrupt.Level =
+ InterruptLevel;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Interrupt.Vector =
+ InterruptVector;
+ Resources->List[0].PartialResourceList.Count++;
+
+ //
+ // Make the call
+ //
+
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ (IsAMiniport ?
+ Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver :
+ AdptrP->MacHandle->NdisMacInfo->NdisWrapperDriver),
+ NULL,
+ 0,
+ (IsAMiniport ?
+ Miniport->DeviceObject :
+ AdptrP->DeviceObject),
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ Resources->List[0].PartialResourceList.Count,
+ TRUE,
+ &Conflict
+ );
+
+ //
+ // Check for conflict.
+ //
+
+ if ((IsAMiniport ?
+ Miniport->Resources:
+ AdptrP->Resources) != NULL) {
+ ExFreePool((IsAMiniport ?
+ Miniport->Resources:
+ AdptrP->Resources));
+ }
+
+ if (IsAMiniport) {
+
+ Miniport->Resources = Resources;
+
+ } else {
+
+ AdptrP->Resources = Resources;
+
+
+ }
+ if (Conflict || (NtStatus != STATUS_SUCCESS)) {
+
+ if (Conflict) {
+
+ //
+ // Log an error
+ //
+
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ ULONG i;
+ ULONG StringSize;
+ PUCHAR Place;
+ PWCH baseFileName;
+ WCHAR Character;
+ ULONG Value;
+
+ baseFileName = ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.Buffer :
+ Miniport->MiniportName.Buffer);
+
+ //
+ // Parse out the path name, leaving only the device name.
+ //
+
+ for ( i = 0;
+ i < ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.Length :
+ Miniport->MiniportName.Length) / sizeof(WCHAR);
+ i++ ) {
+
+ //
+ // If s points to a directory separator, set baseFileName to
+ // the character after the separator.
+ //
+
+ if ( ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.Buffer[i] :
+ Miniport->MiniportName.Buffer[i]) == OBJ_NAME_PATH_SEPARATOR ) {
+ baseFileName = ((AdptrP->DeviceObject != NULL) ?
+ &(AdptrP->AdapterName.Buffer[++i]):
+ &(Miniport->MiniportName.Buffer[++i]));
+ }
+
+ }
+
+ StringSize = ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.MaximumLength :
+ Miniport->MiniportName.MaximumLength) -
+ (((ULONG)baseFileName) -
+ ((AdptrP->DeviceObject != NULL) ?
+ ((ULONG)AdptrP->AdapterName.Buffer) :
+ ((ULONG)Miniport->MiniportName.Buffer)));
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (IsAMiniport ?
+ Miniport->DeviceObject :
+ AdptrP->DeviceObject),
+ (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize +
+ 6) // wstrlen("99") * sizeof(WHCAR) + sizeof(UNICODE_NULL)
+ );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->ErrorCode = EVENT_NDIS_INTERRUPT_CONFLICT;
+
+ //
+ // store the time
+ //
+
+ errorLogEntry->MajorFunctionCode = 0;
+ errorLogEntry->RetryCount = 0;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = 0;
+ errorLogEntry->SequenceNumber = 0;
+ errorLogEntry->IoControlCode = 0;
+
+ //
+ // Set string information
+ //
+
+ if (StringSize != 0) {
+
+ errorLogEntry->NumberOfStrings = 1;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+
+ RtlCopyMemory (
+ ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET),
+ (PVOID)baseFileName,
+ StringSize
+ );
+
+ Place = ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize;
+
+ } else {
+
+ Place = ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET);
+
+ errorLogEntry->NumberOfStrings = 0;
+
+ }
+
+ errorLogEntry->NumberOfStrings++;
+
+ //
+ // Put in interrupt level
+ //
+
+ Value = InterruptLevel;
+
+ //
+ // Convert value
+ //
+ // I couldn't think of a better way to do this (with some
+ // loop). If you find one, plz put it in.
+ //
+
+ if (Value > 9) {
+
+ switch (Value / 10) {
+
+ case 0:
+ Character = L'0';
+ break;
+ case 1:
+ Character = L'1';
+ break;
+ case 2:
+ Character = L'2';
+ break;
+ case 3:
+ Character = L'3';
+ break;
+ case 4:
+ Character = L'4';
+ break;
+ case 5:
+ Character = L'5';
+ break;
+ case 6:
+ Character = L'6';
+ break;
+ case 7:
+ Character = L'7';
+ break;
+ case 8:
+ Character = L'8';
+ break;
+ case 9:
+ Character = L'9';
+ break;
+ }
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ Place += sizeof(WCHAR);
+
+ Value -= 10;
+
+ }
+
+ switch (Value) {
+
+ case 0:
+ Character = L'0';
+ break;
+ case 1:
+ Character = L'1';
+ break;
+ case 2:
+ Character = L'2';
+ break;
+ case 3:
+ Character = L'3';
+ break;
+ case 4:
+ Character = L'4';
+ break;
+ case 5:
+ Character = L'5';
+ break;
+ case 6:
+ Character = L'6';
+ break;
+ case 7:
+ Character = L'7';
+ break;
+ case 8:
+ Character = L'8';
+ break;
+ case 9:
+ Character = L'9';
+ break;
+ }
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ Place += sizeof(WCHAR);
+
+ Character = UNICODE_NULL;
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ //
+ // write it out
+ //
+
+ IoWriteErrorLogEntry(errorLogEntry);
+ }
+
+ *Status = NDIS_STATUS_RESOURCE_CONFLICT;
+ return;
+
+ }
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ //
+ // We must do this stuff first because if we connect the
+ // interrupt first then an interrupt could occur before
+ // the MacISR is recorded in the Ndis interrupt structure.
+ //
+
+ if (IsAMiniport) {
+
+ KeInitializeSpinLock(&(MiniportInterrupt->DpcCountLock));
+ Miniport->Interrupt = MiniportInterrupt;
+ MiniportInterrupt->DpcCount = 0;
+ MiniportInterrupt->MiniportIdField = NULL;
+ MiniportInterrupt->Miniport = Miniport;
+ MiniportInterrupt->MiniportIsr = Miniport->DriverHandle->MiniportCharacteristics.ISRHandler;
+ MiniportInterrupt->MiniportDpc = Miniport->DriverHandle->MiniportCharacteristics.HandleInterruptHandler;
+ MiniportInterrupt->SharedInterrupt = SharedInterrupt;
+ MiniportInterrupt->IsrRequested = (BOOLEAN)DeferredProcessingRoutine;
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ } else {
+
+ NdisInterrupt->MacIsr = InterruptServiceRoutine;
+ NdisInterrupt->MacDpc = DeferredProcessingRoutine;
+ NdisInterrupt->InterruptContext = InterruptContext;
+ KeInitializeSpinLock(&(NdisInterrupt->DpcCountLock));
+ NdisInterrupt->DpcCount = 0;
+ NdisInterrupt->Removing = FALSE;
+
+ }
+
+ //
+ // This is used to tell when all Dpcs are completed after the
+ // interrupt has been removed.
+ //
+
+ KeInitializeEvent(
+ (IsAMiniport ?
+ &MiniportInterrupt->DpcsCompletedEvent :
+ &NdisInterrupt->DpcsCompletedEvent),
+ NotificationEvent,
+ FALSE
+ );
+
+ //
+ // Initialize our dpc.
+ //
+
+ if (NdisMacAdapterDpcTargetProcessor < 0) {
+ NdisMacAdapterDpcTargetProcessor = (**(PCCHAR *)&KeNumberProcessors) - 1;
+ }
+
+ if (IsAMiniport) {
+
+ KeInitializeDpc(
+ &MiniportInterrupt->InterruptDpc,
+ (PKDEFERRED_ROUTINE) NdisMDpc,
+ MiniportInterrupt
+ );
+
+ KeSetImportanceDpc(
+ &MiniportInterrupt->InterruptDpc,
+ LowImportance
+ );
+
+ KeSetTargetProcessorDpc (
+ &MiniportInterrupt->InterruptDpc,
+ NdisMacAdapterDpcTargetProcessor
+ );
+ } else {
+
+ KeInitializeDpc(
+ &NdisInterrupt->InterruptDpc,
+ (PKDEFERRED_ROUTINE) NdisDpc,
+ NdisInterrupt
+ );
+
+ KeSetImportanceDpc(
+ &NdisInterrupt->InterruptDpc,
+ LowImportance
+ );
+
+ KeSetTargetProcessorDpc (
+ &NdisInterrupt->InterruptDpc,
+ NdisMacAdapterDpcTargetProcessor
+ );
+ }
+
+ NdisMacAdapterDpcTargetProcessor -= 1;
+
+ //
+ // Get the system interrupt vector and IRQL.
+ //
+
+ Vector = HalGetInterruptVector(
+ (IsAMiniport ?
+ Miniport->BusType :
+ AdptrP->BusType), // InterfaceType
+ (IsAMiniport ?
+ Miniport->BusNumber :
+ AdptrP->BusNumber), // BusNumber
+ (ULONG)InterruptLevel, // BusInterruptLevel
+ (ULONG)InterruptVector, // BusInterruptVector
+ &Irql, // Irql
+ &InterruptAffinity
+ );
+
+ if (IsAMiniport) {
+
+ NtStatus = IoConnectInterrupt(
+ &MiniportInterrupt->InterruptObject,
+ (PKSERVICE_ROUTINE)NdisMIsr,
+ MiniportInterrupt,
+ NULL,
+ Vector,
+ Irql,
+ Irql,
+ (KINTERRUPT_MODE)InterruptMode,
+ SharedInterrupt,
+ InterruptAffinity,
+ FALSE
+ );
+
+ } else {
+
+ NtStatus = IoConnectInterrupt(
+ &NdisInterrupt->InterruptObject,
+ (PKSERVICE_ROUTINE)NdisIsr,
+ NdisInterrupt,
+ NULL,
+ Vector,
+ Irql,
+ Irql,
+ (KINTERRUPT_MODE)InterruptMode,
+ SharedInterrupt,
+ InterruptAffinity,
+ FALSE
+ );
+ }
+
+
+ if (!NT_SUCCESS(NtStatus)) {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+}
+
+VOID
+NdisRemoveInterrupt(
+ IN PNDIS_INTERRUPT Interrupt
+ )
+/*++
+
+Routine Description:
+
+ Removes the interrupt, will not return until all interrupts and
+ interrupt dpcs are completed.
+
+Arguments:
+
+ Interrupt - Points to driver allocated memory that the wrapper filled
+ with information about the interrupt handler.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MINIPORT_INTERRUPT MiniportInterrupt = (PNDIS_MINIPORT_INTERRUPT)Interrupt;
+
+ if (MiniportInterrupt->MiniportIdField == NULL) {
+
+ MiniportInterrupt->Miniport->BeingRemoved = TRUE;
+
+ } else {
+
+ Interrupt->Removing = TRUE;
+
+ }
+
+ //
+ // Now we disconnect the interrupt. NOTE: they are aligned in both structures
+ //
+
+ IoDisconnectInterrupt(
+ Interrupt->InterruptObject
+ );
+
+ //
+ // Right now we know that any Dpcs that may fire are counted.
+ // We don't have to guard this with a spin lock because the
+ // Dpc will set the event if if completes first, or we may
+ // wait for a little while for it to complete.
+ //
+
+ if (Interrupt->DpcCount > 0) {
+
+ //
+ // Now we wait for all dpcs to complete.
+ //
+
+ KeWaitForSingleObject(
+ &Interrupt->DpcsCompletedEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PTIME)NULL
+ );
+
+ KeResetEvent(
+ &Interrupt->DpcsCompletedEvent
+ );
+
+
+ }
+
+}
+
+
+
+VOID
+NdisUnload(
+ IN PDRIVER_OBJECT DriverObject
+ )
+/*++
+
+Routine Description:
+
+ This routine is called when a driver is supposed to unload. Ndis
+ converts this into a set of calls to MacRemoveAdapter() for each
+ adapter that the Mac has open. When the last adapter deregisters
+ itself it will call MacUnload().
+
+Arguments:
+
+ DriverObject - the driver object for the mac that is to unload.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MAC_BLOCK MacP;
+ PNDIS_ADAPTER_BLOCK Adapter, NextAdapter;
+
+ ACQUIRE_SPIN_LOCK(&NdisMacListLock);
+
+ //
+ // Search for the MacP
+ //
+
+ MacP = NdisMacList;
+
+ while (MacP != (PNDIS_MAC_BLOCK)NULL) {
+
+ if (MacP->NdisMacInfo->NdisWrapperDriver == DriverObject) {
+
+ break;
+
+ }
+
+ MacP = MacP->NextMac;
+
+ }
+
+ RELEASE_SPIN_LOCK(&NdisMacListLock);
+
+ if (MacP == (PNDIS_MAC_BLOCK)NULL) {
+
+ //
+ // It is already gone. Just return.
+ //
+
+ return;
+
+ }
+
+ MacP->Unloading = TRUE;
+
+
+ //
+ // Now call MACRemoveAdapter() for each Adapter.
+ //
+
+ Adapter = MacP->AdapterQueue;
+
+ while (Adapter != (PNDIS_ADAPTER_BLOCK)NULL) {
+
+ NextAdapter = Adapter->NextAdapter; // since queue may change
+
+ (MacP->MacCharacteristics.RemoveAdapterHandler)(
+ Adapter->MacAdapterContext
+ );
+
+ //
+ // If a shutdown handler was registered then deregister it.
+ //
+ NdisDeregisterAdapterShutdownHandler(Adapter);
+
+ Adapter = NextAdapter;
+
+ }
+
+
+ //
+ // Wait for all adapters to be gonzo.
+ //
+
+ KeWaitForSingleObject(
+ &MacP->AdaptersRemovedEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PTIME)NULL
+ );
+
+ KeResetEvent(
+ &MacP->AdaptersRemovedEvent
+ );
+
+
+ //
+ // Now call the MACUnload routine
+ //
+
+ (MacP->MacCharacteristics.UnloadMacHandler)(MacP->MacMacContext);
+
+
+ //
+ // Now remove the last reference (this will remove it from the list)
+ //
+ ASSERT(MacP->Ref.ReferenceCount == 1);
+
+ NdisDereferenceMac(MacP);
+}
+
+
+NTSTATUS
+NdisShutdown(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ The "shutdown handler" for the SHUTDOWN Irp. Will call the Ndis
+ shutdown routine, if one is registered.
+
+Arguments:
+
+ DeviceObject - The adapter's device object.
+ Irp - The IRP.
+
+Return Value:
+
+ Always STATUS_SUCCESS.
+
+--*/
+
+{
+ PNDIS_WRAPPER_CONTEXT WrapperContext = (PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension;
+ PNDIS_ADAPTER_BLOCK Miniport = (PNDIS_ADAPTER_BLOCK)(WrapperContext + 1);
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisShutdown\n");
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(Irp)) {
+ NdisPrint1(": Null Irp\n");
+ DbgBreakPoint();
+ }
+
+ if (!DbgIsNonPaged(Irp)) {
+ NdisPrint1(": Irp not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+
+ }
+
+ if (WrapperContext->ShutdownHandler != NULL) {
+
+ //
+ // Call the shutdown routine
+ //
+
+ WrapperContext->ShutdownHandler(WrapperContext->ShutdownContext);
+ }
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisShutdown\n");
+
+ return STATUS_SUCCESS;
+}
+
+VOID
+NdisAllocateSharedMemory(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Length,
+ IN BOOLEAN Cached,
+ OUT PVOID *VirtualAddress,
+ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Allocates memory to be shared between the driver and the adapter.
+
+Arguments:
+
+ NdisAdapterHandle - handle returned by NdisRegisterAdapter.
+ Length - Length of the memory to allocate.
+ Cached - TRUE if memory is to be cached.
+ VirtualAddress - Returns the virtual address of the memory,
+ or NULL if the memory cannot be allocated.
+ PhysicalAddress - Returns the physical address of the memory.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG Alignment;
+ PNDIS_ADAPTER_BLOCK AdaptP = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle;
+ PADAPTER_OBJECT SystemAdapterObject;
+ PNDIS_WRAPPER_CONTEXT WrapperContext;
+ PULONG Page;
+ ULONG Type;
+
+ //
+ // Get interesting information from the adapter/miniport.
+ //
+
+ if ( AdaptP->DeviceObject != NULL ) {
+ SystemAdapterObject = AdaptP->SystemAdapterObject;
+ WrapperContext = AdaptP->WrapperContext;
+ } else {
+ SystemAdapterObject = Miniport->SystemAdapterObject;
+ WrapperContext = Miniport->WrapperContext;
+ }
+
+ //
+ // Non-busmasters shouldn't call this routine.
+ //
+
+ if (SystemAdapterObject == NULL) {
+ *VirtualAddress = NULL;
+ KdPrint(("NDIS: You are not a busmaster\n"));
+ return;
+ }
+
+ //
+ // Compute allocation size by aligning to the proper boundary.
+ //
+
+ ASSERT(Length != 0);
+
+ Alignment = HalGetDmaAlignmentRequirement();
+ if (sizeof(ULONG) > Alignment) {
+ Alignment = sizeof(ULONG);
+ }
+
+ Length = (Length + Alignment - 1) & ~(Alignment - 1);
+
+ //
+ // Check to determine is there is enough room left in the current page
+ // to satisfy the allocation.
+ //
+
+ Type = Cached ? 1 : 0;
+ ExAcquireResourceExclusive(&SharedMemoryResource, TRUE);
+ if (WrapperContext->SharedMemoryLeft[Type] < Length) {
+ if ((Length + sizeof(ULONG)) >= PAGE_SIZE) {
+
+ //
+ // The allocation is greater than a page.
+ //
+
+ *VirtualAddress = HalAllocateCommonBuffer(
+ SystemAdapterObject,
+ Length,
+ PhysicalAddress,
+ Cached);
+
+ ExReleaseResource(&SharedMemoryResource);
+ return;
+ }
+
+ //
+ // Allocate a new page for shared alocation.
+ //
+
+ WrapperContext->SharedMemoryPage[Type] =
+ HalAllocateCommonBuffer(
+ SystemAdapterObject,
+ PAGE_SIZE,
+ &WrapperContext->SharedMemoryAddress[Type],
+ Cached);
+
+ if (WrapperContext->SharedMemoryPage[Type] == NULL) {
+ WrapperContext->SharedMemoryLeft[Type] = 0;
+ *VirtualAddress = NULL;
+ ExReleaseResource(&SharedMemoryResource);
+ return;
+ }
+
+ //
+ // Initialize the reference count in the last ULONG of the page.
+ //
+
+ Page = (PULONG)WrapperContext->SharedMemoryPage[Type];
+ Page[(PAGE_SIZE / sizeof(ULONG)) - 1] = 0;
+ WrapperContext->SharedMemoryLeft[Type] = PAGE_SIZE - sizeof(ULONG);
+ }
+
+ //
+ // Increment the reference count, set the address of the allocation,
+ // compute the physical address, and reduce the space remaining.
+ //
+
+ Page = (PULONG)WrapperContext->SharedMemoryPage[Type];
+ Page[(PAGE_SIZE / sizeof(ULONG)) - 1] += 1;
+ *VirtualAddress = (PVOID)((PUCHAR)Page +
+ (PAGE_SIZE - sizeof(ULONG) - WrapperContext->SharedMemoryLeft[Type]));
+
+#if !defined(BUILD_FOR_3_1)
+ PhysicalAddress->QuadPart = WrapperContext->SharedMemoryAddress[Type].QuadPart +
+ ((ULONG)*VirtualAddress & (PAGE_SIZE - 1));
+#else
+ *PhysicalAddress = RtlLargeIntegerAdd(
+ WrapperContext->SharedMemoryAddress[Type],
+ RtlConvertUlongToLargeInteger((ULONG)*VirtualAddress & (PAGE_SIZE - 1))
+ );
+#endif
+
+ WrapperContext->SharedMemoryLeft[Type] -= Length;
+ ExReleaseResource(&SharedMemoryResource);
+ return;
+}
+
+
+#undef NdisUpdateSharedMemory
+
+VOID
+NdisUpdateSharedMemory(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Length,
+ IN PVOID VirtualAddress,
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Ensures that the data to be read from a shared memory region is
+ fully up-to-date.
+
+Arguments:
+
+ NdisAdapterHandle - handle returned by NdisRegisterAdapter.
+ Length - The length of the shared memory.
+ VirtualAddress - Virtual address returned by NdisAllocateSharedMemory.
+ PhysicalAddress - The physical address returned by NdisAllocateSharedMemory.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // There is no underlying HAL routine for this anymore,
+ // it is not needed. This is macro'd to nothing in the
+ // header file now. This is there for backward compatibility
+
+ NdisAdapterHandle; Length; VirtualAddress; PhysicalAddress;
+
+}
+
+
+VOID
+NdisFreeSharedMemory(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Length,
+ IN BOOLEAN Cached,
+ IN PVOID VirtualAddress,
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Allocates memory to be shared between the driver and the adapter.
+
+Arguments:
+
+ NdisAdapterHandle - handle returned by NdisRegisterAdapter.
+ Length - Length of the memory to allocate.
+ Cached - TRUE if memory was allocated cached.
+ VirtualAddress - Virtual address returned by NdisAllocateSharedMemory.
+ PhysicalAddress - The physical address returned by NdisAllocateSharedMemory.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG Alignment;
+ PNDIS_ADAPTER_BLOCK AdaptP = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle;
+ PADAPTER_OBJECT SystemAdapterObject;
+ PNDIS_WRAPPER_CONTEXT WrapperContext;
+ PULONG Page;
+ ULONG Type;
+
+ //
+ // Get interesting information from the adapter/miniport.
+ //
+
+ if ( AdaptP->DeviceObject != NULL ) {
+ SystemAdapterObject = AdaptP->SystemAdapterObject;
+ WrapperContext = AdaptP->WrapperContext;
+ } else {
+ SystemAdapterObject = Miniport->SystemAdapterObject;
+ WrapperContext = Miniport->WrapperContext;
+ }
+
+ //
+ // Non-busmasters shouldn't call this routine.
+ //
+
+ ASSERT(SystemAdapterObject != NULL);
+
+ //
+ // Compute allocation size by aligning to the proper boundary.
+ //
+
+ ASSERT(Length != 0);
+
+ Alignment = HalGetDmaAlignmentRequirement();
+ if (sizeof(ULONG) > Alignment) {
+ Alignment = sizeof(ULONG);
+ }
+
+ Length = (Length + Alignment - 1) & ~(Alignment - 1);
+
+ //
+ // Free the specified memory.
+ //
+
+ ExAcquireResourceExclusive(&SharedMemoryResource, TRUE);
+ if ((Length + sizeof(ULONG)) >= PAGE_SIZE) {
+
+ //
+ // The allocation is greater than a page free the page directly.
+ //
+
+ HalFreeCommonBuffer(
+ SystemAdapterObject,
+ Length,
+ PhysicalAddress,
+ VirtualAddress,
+ Cached);
+
+ } else {
+
+ //
+ // Decrement the reference count and if the result is zero, then free
+ // the page.
+ //
+
+ Page = (PULONG)((ULONG)VirtualAddress & ~(PAGE_SIZE - 1));
+ Page[(PAGE_SIZE / sizeof(ULONG)) - 1] -= 1;
+ if (Page[(PAGE_SIZE / sizeof(ULONG)) - 1] == 0) {
+
+ //
+ // Compute the physical address of the page and free it.
+ //
+
+ PhysicalAddress.LowPart &= ~(PAGE_SIZE - 1);
+ HalFreeCommonBuffer(
+ SystemAdapterObject,
+ PAGE_SIZE,
+ PhysicalAddress,
+ Page,
+ Cached);
+
+ Type = Cached ? 1 : 0;
+ if ((PVOID)Page == WrapperContext->SharedMemoryPage[Type]) {
+ WrapperContext->SharedMemoryLeft[Type] = 0;
+ WrapperContext->SharedMemoryPage[Type] = NULL;
+ }
+ }
+ }
+
+ ExReleaseResource(&SharedMemoryResource);
+ return;
+}
+
+
+IO_ALLOCATION_ACTION
+NdisDmaExecutionRoutine(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is an execution routine for AllocateAdapterChannel,
+ if is called when an adapter channel allocated by NdisAllocate
+ DmaChannel is available.
+
+Arguments:
+
+ DeviceObject - The device object of the adapter.
+
+ Irp - ??.
+
+ MapRegisterBase - The address of the first translation table
+ assigned to us.
+
+ Context - A pointer to the NDIS_DMA_BLOCK in question.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_DMA_BLOCK DmaBlock = (PNDIS_DMA_BLOCK)Context;
+
+ UNREFERENCED_PARAMETER (Irp);
+ UNREFERENCED_PARAMETER (DeviceObject);
+
+
+ //
+ // Save the map register base.
+ //
+
+ DmaBlock->MapRegisterBase = MapRegisterBase;
+
+ //
+ // This will free the thread that is waiting for this callback.
+ //
+
+ KeSetEvent(
+ &DmaBlock->AllocationEvent,
+ 0L,
+ FALSE
+ );
+
+ return KeepObject;
+}
+
+
+
+VOID
+NdisAllocateDmaChannel(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE NdisDmaHandle,
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN PNDIS_DMA_DESCRIPTION DmaDescription,
+ IN ULONG MaximumLength
+ )
+
+/*++
+
+Routine Description:
+
+ Sets up a DMA channel for future DMA operations.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ NdisDmaHandle - Returns a handle used to specify this channel to
+ future operations.
+
+ NdisAdapterHandle - handle returned by NdisRegisterAdapter.
+
+ DmaDescription - Details of the DMA channel.
+
+ MaximumLength - The maximum length DMA transfer that will be done
+ using this channel.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // For registering this set of resources
+ //
+ PCM_RESOURCE_LIST Resources;
+ BOOLEAN Conflict;
+
+ //
+ // Needed to call HalGetAdapter.
+ //
+ DEVICE_DESCRIPTION DeviceDescription;
+
+ //
+ // Returned by HalGetAdapter.
+ //
+ PADAPTER_OBJECT AdapterObject;
+
+ //
+ // Map registers needed per channel.
+ //
+ ULONG MapRegistersNeeded;
+
+ //
+ // Map registers allowed per channel.
+ //
+ ULONG MapRegistersAllowed;
+
+ //
+ // Saves the structure we allocate for this channel.
+ //
+ PNDIS_DMA_BLOCK DmaBlock;
+
+ //
+ // Convert the handle to our internal structure.
+ PNDIS_ADAPTER_BLOCK AdapterBlock =
+ (PNDIS_ADAPTER_BLOCK) NdisAdapterHandle;
+
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) NdisAdapterHandle;
+ BOOLEAN IsAMiniport;
+
+ //
+ // Save our IRQL when we raise it to call IoAllocateAdapterChannel.
+ //
+ KIRQL OldIrql;
+ ULONG NumberOfElements;
+
+ NTSTATUS NtStatus;
+
+ LARGE_INTEGER TimeoutValue;
+
+ IsAMiniport = (AdapterBlock->DeviceObject == NULL);
+
+ //
+ // First check if any bus access is allowed
+ //
+
+ if (((IsAMiniport ?
+ Miniport->BusType :
+ AdapterBlock->BusType) == (NDIS_INTERFACE_TYPE)-1) ||
+ ((IsAMiniport ?
+ Miniport->BusNumber :
+ AdapterBlock->BusNumber) == (ULONG)-1)) {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+ //
+ // First check for resource conflict by expanding current resource list,
+ // adding in the mapped space, and then re-submitting the resource list.
+ //
+
+ if ((IsAMiniport ? Miniport->Resources : AdapterBlock->Resources) != NULL) {
+
+ NumberOfElements =
+ (IsAMiniport ?
+ Miniport->Resources->List[0].PartialResourceList.Count :
+ AdapterBlock->Resources->List[0].PartialResourceList.Count) + 1;
+
+ } else {
+
+ NumberOfElements = 1;
+ }
+
+ //
+ // First check for resource conflict by expanding current resource list,
+ // adding in the mapped space, and then re-submitting the resource list.
+ //
+
+ Resources = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ NumberOfElements,
+ 'lrDN'
+ );
+
+ if (Resources == NULL) {
+
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+
+ }
+
+ if ((IsAMiniport ? Miniport->Resources : AdapterBlock->Resources) != NULL) {
+
+ RtlCopyMemory (Resources,
+ (IsAMiniport ? Miniport->Resources : AdapterBlock->Resources),
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ (NumberOfElements - 1)
+ );
+ } else {
+
+ //
+ // Setup initial resource info
+ //
+ ASSERT(IsAMiniport);
+ Resources->Count = 1;
+ Resources->List[0].InterfaceType = Miniport->AdapterType;
+ Resources->List[0].BusNumber = Miniport->BusNumber;
+ Resources->List[0].PartialResourceList.Version = 0;
+ Resources->List[0].PartialResourceList.Revision = 0;
+ Resources->List[0].PartialResourceList.Count = 0;
+
+ }
+
+ //
+ // Setup DMA Channel
+ //
+
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Type =
+ CmResourceTypeDma;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].ShareDisposition =
+ CmResourceShareDeviceExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Flags =
+ 0;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Dma.Channel =
+ (IsAMiniport ? Miniport->ChannelNumber :
+ (DmaDescription->DmaChannelSpecified ?
+ DmaDescription->DmaChannel : AdapterBlock->ChannelNumber));
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Dma.Port =
+ DmaDescription->DmaPort;
+ Resources->List[0].PartialResourceList.Count++;
+
+
+ //
+ // Make the call
+ //
+
+ *Status = IoReportResourceUsage(
+ NULL,
+ (IsAMiniport ?
+ Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver :
+ AdapterBlock->MacHandle->NdisMacInfo->NdisWrapperDriver),
+ NULL,
+ 0,
+ (IsAMiniport ? Miniport->DeviceObject : AdapterBlock->DeviceObject),
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ Resources->List[0].PartialResourceList.Count,
+ TRUE,
+ &Conflict
+ );
+
+ if ((IsAMiniport ? Miniport->Resources : AdapterBlock->Resources) != NULL) {
+
+ ExFreePool((IsAMiniport ? Miniport->Resources : AdapterBlock->Resources));
+
+ }
+
+ if (IsAMiniport) {
+
+ Miniport->Resources = Resources;
+
+ } else {
+
+ AdapterBlock->Resources = Resources;
+
+ }
+
+ //
+ // Check for conflict.
+ //
+
+ if (Conflict || (*Status != STATUS_SUCCESS)) {
+
+
+ if (Conflict) {
+
+
+ //
+ // Log an error
+ //
+
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ ULONG i;
+ ULONG StringSize;
+ PUCHAR Place;
+ PWCH baseFileName;
+ WCHAR Character;
+ ULONG Value;
+
+ baseFileName = (IsAMiniport ?
+ Miniport->MiniportName.Buffer :
+ AdapterBlock->AdapterName.Buffer);
+
+ //
+ // Parse out the path name, leaving only the device name.
+ //
+
+ for ( i = 0;
+ i < (IsAMiniport ? Miniport->MiniportName.Length :
+ AdapterBlock->AdapterName.Length)
+ / sizeof(WCHAR);
+ i++ ) {
+
+ //
+ // If s points to a directory separator, set baseFileName to
+ // the character after the separator.
+ //
+
+ if ((IsAMiniport ?
+ Miniport->MiniportName.Buffer[i] :
+ AdapterBlock->AdapterName.Buffer[i]) == OBJ_NAME_PATH_SEPARATOR ) {
+
+ baseFileName = (IsAMiniport ?
+ &(Miniport->MiniportName.Buffer[++i]) :
+ &(AdapterBlock->AdapterName.Buffer[++i]));
+
+ }
+
+ }
+
+ StringSize = (IsAMiniport ?
+ Miniport->MiniportName.MaximumLength :
+ AdapterBlock->AdapterName.MaximumLength) -
+ (((ULONG)baseFileName) -
+ (IsAMiniport ?
+ ((ULONG)Miniport->MiniportName.Buffer) :
+ ((ULONG)AdapterBlock->AdapterName.Buffer)));
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (IsAMiniport ?
+ Miniport->DeviceObject :
+ AdapterBlock->DeviceObject),
+ (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize +
+ 6) // wstrlen("99") * sizeof(WHCAR) + sizeof(UNICODE_NULL)
+ );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->ErrorCode = EVENT_NDIS_DMA_CONFLICT;
+
+ //
+ // store the time
+ //
+
+ errorLogEntry->MajorFunctionCode = 0;
+ errorLogEntry->RetryCount = 0;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = 0;
+ errorLogEntry->SequenceNumber = 0;
+ errorLogEntry->IoControlCode = 0;
+
+ //
+ // Set string information
+ //
+
+ if (StringSize != 0) {
+
+ errorLogEntry->NumberOfStrings = 1;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+
+ RtlCopyMemory (
+ ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET),
+ (PVOID)baseFileName,
+ StringSize
+ );
+
+ Place = ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize;
+
+ } else {
+
+ Place = ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET);
+
+ errorLogEntry->NumberOfStrings = 0;
+
+ }
+
+ errorLogEntry->NumberOfStrings++;
+
+ //
+ // Put in dma channel
+ //
+
+ Value = (IsAMiniport ? Miniport->ChannelNumber :
+ AdapterBlock->ChannelNumber);
+
+ //
+ // Convert value
+ //
+ // I couldn't think of a better way to do this (with some
+ // loop). If you find one, plz put it in.
+ //
+
+ if (Value > 9) {
+
+ switch (Value / 10) {
+
+ case 0:
+ Character = L'0';
+ break;
+ case 1:
+ Character = L'1';
+ break;
+ case 2:
+ Character = L'2';
+ break;
+ case 3:
+ Character = L'3';
+ break;
+ case 4:
+ Character = L'4';
+ break;
+ case 5:
+ Character = L'5';
+ break;
+ case 6:
+ Character = L'6';
+ break;
+ case 7:
+ Character = L'7';
+ break;
+ case 8:
+ Character = L'8';
+ break;
+ case 9:
+ Character = L'9';
+ break;
+ }
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ Place += sizeof(WCHAR);
+
+ Value -= 10;
+
+ }
+
+ switch (Value) {
+
+ case 0:
+ Character = L'0';
+ break;
+ case 1:
+ Character = L'1';
+ break;
+ case 2:
+ Character = L'2';
+ break;
+ case 3:
+ Character = L'3';
+ break;
+ case 4:
+ Character = L'4';
+ break;
+ case 5:
+ Character = L'5';
+ break;
+ case 6:
+ Character = L'6';
+ break;
+ case 7:
+ Character = L'7';
+ break;
+ case 8:
+ Character = L'8';
+ break;
+ case 9:
+ Character = L'9';
+ break;
+ }
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ Place += sizeof(WCHAR);
+
+ Character = UNICODE_NULL;
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ //
+ // write it out
+ //
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+ *Status = NDIS_STATUS_RESOURCE_CONFLICT;
+ return;
+
+ }
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ //
+ // Set up the device description; zero it out in case its
+ // size changes.
+ //
+
+ RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
+
+ DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
+ DeviceDescription.Master = (IsAMiniport ? Miniport->Master : FALSE);
+ DeviceDescription.ScatterGather = (IsAMiniport ? Miniport->Master : FALSE);
+ DeviceDescription.DemandMode = DmaDescription->DemandMode;
+ DeviceDescription.AutoInitialize = DmaDescription->AutoInitialize;
+ DeviceDescription.Dma32BitAddresses = (IsAMiniport ? Miniport->Dma32BitAddresses : FALSE);
+ DeviceDescription.BusNumber = (IsAMiniport ? Miniport->BusNumber : AdapterBlock->BusNumber);
+ DeviceDescription.DmaChannel = (IsAMiniport ? Miniport->ChannelNumber :
+ (DmaDescription->DmaChannelSpecified ?
+ DmaDescription->DmaChannel : AdapterBlock->ChannelNumber));
+ DeviceDescription.InterfaceType = (IsAMiniport ? Miniport->BusType : AdapterBlock->BusType);
+ DeviceDescription.DmaWidth = DmaDescription->DmaWidth;
+ DeviceDescription.DmaSpeed = DmaDescription->DmaSpeed;
+ DeviceDescription.MaximumLength = MaximumLength;
+ DeviceDescription.DmaPort = DmaDescription->DmaPort;
+
+
+ MapRegistersNeeded = ((MaximumLength - 2) / PAGE_SIZE) + 2;
+
+ //
+ // Get the adapter object.
+ //
+
+ AdapterObject = HalGetAdapter (&DeviceDescription, &MapRegistersAllowed);
+
+ if ((AdapterObject == NULL) || (MapRegistersAllowed < MapRegistersNeeded)) {
+
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+
+ //
+ // Allocate storage for our DMA block.
+ //
+
+ DmaBlock = (PNDIS_DMA_BLOCK)ExAllocatePoolWithTag (NonPagedPool, sizeof(NDIS_DMA_BLOCK), 'bdDN');
+
+ if (DmaBlock == (PNDIS_DMA_BLOCK)NULL) {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+
+ //
+ // Use this event to tell us when NdisAllocationExecutionRoutine
+ // has been called.
+ //
+
+ KeInitializeEvent(
+ &DmaBlock->AllocationEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ //
+ // We save this to call IoFreeAdapterChannel later.
+ //
+
+ DmaBlock->SystemAdapterObject = AdapterObject;
+
+
+ //
+ // Now allocate the adapter channel.
+ //
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NtStatus = IoAllocateAdapterChannel(
+ AdapterObject,
+ (IsAMiniport ? Miniport->DeviceObject : AdapterBlock->DeviceObject),
+ MapRegistersNeeded,
+ NdisDmaExecutionRoutine,
+ (PVOID)DmaBlock
+ );
+
+ KeLowerIrql(OldIrql);
+
+ if (!NT_SUCCESS(NtStatus)) {
+ NdisPrint2("NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus);
+ ExFreePool (DmaBlock);
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ TimeoutValue.QuadPart = Int32x32To64(2 * 1000, -10000);
+
+ //
+ // NdisDmaExecutionRoutine will set this event
+ // when it has been called.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &DmaBlock->AllocationEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ NdisPrint2("NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus);
+ ExFreePool (DmaBlock);
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+
+ }
+
+ KeResetEvent(
+ &DmaBlock->AllocationEvent
+ );
+
+
+ //
+ // We now have the DMA channel allocated, we are done.
+ //
+
+ DmaBlock->InProgress = FALSE;
+
+ *NdisDmaHandle = (NDIS_HANDLE)DmaBlock;
+ *Status = NDIS_STATUS_SUCCESS;
+
+}
+
+
+VOID
+NdisFreeDmaChannel(
+ IN PNDIS_HANDLE NdisDmaHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Frees a DMA channel allocated with NdisAllocateDmaChannel.
+
+Arguments:
+
+ NdisDmaHandle - Handle returned by NdisAllocateDmaChannel, indicating the
+ DMA channel that is to be freed.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ KIRQL OldIrql;
+ PNDIS_DMA_BLOCK DmaBlock = (PNDIS_DMA_BLOCK)NdisDmaHandle;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ IoFreeAdapterChannel (DmaBlock->SystemAdapterObject);
+ KeLowerIrql(OldIrql);
+
+ ExFreePool (DmaBlock);
+
+}
+
+
+VOID
+NdisSetupDmaTransfer(
+ OUT PNDIS_STATUS Status,
+ IN PNDIS_HANDLE NdisDmaHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG Offset,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ )
+
+/*++
+
+Routine Description:
+
+ Sets up the host DMA controller for a DMA transfer. The
+ DMA controller is set up to transfer the specified MDL.
+ Since we register all DMA channels as non-scatter/gather,
+ IoMapTransfer will ensure that the entire MDL is
+ in a single logical piece for transfer.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ NdisDmaHandle - Handle returned by NdisAllocateDmaChannel.
+
+ Buffer - An NDIS_BUFFER which describes the host memory involved in the
+ transfer.
+
+ Offset - An offset within buffer where the transfer should
+ start.
+
+ Length - The length of the transfer. VirtualAddress plus Length must not
+ extend beyond the end of the buffer.
+
+ WriteToDevice - TRUE for a download operation (host to adapter); FALSE
+ for an upload operation (adapter to host).
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PNDIS_DMA_BLOCK DmaBlock = (PNDIS_DMA_BLOCK)NdisDmaHandle;
+ PHYSICAL_ADDRESS LogicalAddress;
+ ULONG LengthMapped;
+
+
+ //
+ // Make sure another request is not in progress.
+ //
+
+ if (DmaBlock->InProgress) {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ DmaBlock->InProgress = TRUE;
+
+ //
+ // Use IoMapTransfer to set up the transfer.
+ //
+
+ LengthMapped = Length;
+
+ LogicalAddress = IoMapTransfer(
+ DmaBlock->SystemAdapterObject,
+ (PMDL)Buffer,
+ DmaBlock->MapRegisterBase,
+ (PUCHAR)(MmGetMdlVirtualAddress(Buffer)) + Offset,
+ &LengthMapped,
+ WriteToDevice
+ );
+
+ if (LengthMapped != Length) {
+
+ //
+ // Somehow the request could not be mapped competely,
+ // this should not happen for a non-scatter/gather adapter.
+ //
+
+ (VOID)IoFlushAdapterBuffers(
+ DmaBlock->SystemAdapterObject,
+ (PMDL)Buffer,
+ DmaBlock->MapRegisterBase,
+ (PUCHAR)(MmGetMdlVirtualAddress(Buffer)) + Offset,
+ LengthMapped,
+ WriteToDevice
+ );
+
+ DmaBlock->InProgress = FALSE;
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+}
+
+
+VOID
+NdisCompleteDmaTransfer(
+ OUT PNDIS_STATUS Status,
+ IN PNDIS_HANDLE NdisDmaHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG Offset,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ )
+
+/*++
+
+Routine Description:
+
+ Completes a previously started DMA transfer.
+
+Arguments:
+
+ Status - Returns the status of the transfer.
+
+ NdisDmaHandle - Handle returned by NdisAllocateDmaChannel.
+
+ Buffer - An NDIS_BUFFER which was passed to NdisSetupDmaTransfer.
+
+ Offset - the offset passed to NdisSetupDmaTransfer.
+
+ Length - The length passed to NdisSetupDmaTransfer.
+
+ WriteToDevice - TRUE for a download operation (host to adapter); FALSE
+ for an upload operation (adapter to host).
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNDIS_DMA_BLOCK DmaBlock = (PNDIS_DMA_BLOCK)NdisDmaHandle;
+ BOOLEAN Successful;
+
+ Successful = IoFlushAdapterBuffers(
+ DmaBlock->SystemAdapterObject,
+ (PMDL)Buffer,
+ DmaBlock->MapRegisterBase,
+ (PUCHAR)(MmGetMdlVirtualAddress(Buffer)) + Offset,
+ Length,
+ WriteToDevice);
+
+ *Status = (Successful ? NDIS_STATUS_SUCCESS : NDIS_STATUS_RESOURCES);
+ DmaBlock->InProgress = FALSE;
+
+}
+
+//
+// Requests used by protocol modules
+//
+//
+
+VOID
+NdisRegisterProtocol(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE NdisProtocolHandle,
+ IN PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics,
+ IN UINT CharacteristicsLength
+ )
+
+/*++
+
+Routine Description:
+
+ Register an NDIS protocol.
+
+Arguments:
+
+ Status - Returns the final status.
+ NdisProtocolHandle - Returns a handle referring to this protocol.
+ ProtocolCharacteritics - The NDIS_PROTOCOL_CHARACTERISTICS table.
+ CharacteristicsLength - The length of ProtocolCharacteristics.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_PROTOCOL_BLOCK NewProtP;
+ UINT MemNeeded;
+
+ //
+ // Do any initial initialization that may be necessary. Note: this
+ // routine will notice if this is the second or later call to it.
+ //
+ *Status = NdisInitialInit( NULL );
+ if (!NT_SUCCESS(*Status)) {
+ return;
+ }
+
+ //
+ // Check that this is an NDIS 3.1 protocol.
+ //
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("==>NdisRegisterProtocol\n");
+ IF_ERROR_CHK {
+ if (DbgIsNull(ProtocolCharacteristics->OpenAdapterCompleteHandler)) {
+ NdisPrint1("RegisterProtocol: OpenAdapterCompleteHandler Null\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(ProtocolCharacteristics->CloseAdapterCompleteHandler)) {
+ NdisPrint1("RegisterProtocol: CloseAdapterCompleteHandler Null\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(ProtocolCharacteristics->SendCompleteHandler)) {
+ NdisPrint1("RegisterProtocol: SendCompleteHandler Null\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(ProtocolCharacteristics->TransferDataCompleteHandler)) {
+ NdisPrint1("RegisterProtocol: TransferDataCompleteHandler Null\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(ProtocolCharacteristics->ResetCompleteHandler)) {
+ NdisPrint1("RegisterProtocol: ResetCompleteHandler Null\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(ProtocolCharacteristics->RequestCompleteHandler)) {
+ NdisPrint1("RegisterProtocol: RequestCompleteHandler Null\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(ProtocolCharacteristics->ReceiveHandler)) {
+ NdisPrint1("RegisterProtocol: ReceiveHandler Null\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(ProtocolCharacteristics->ReceiveCompleteHandler)) {
+ NdisPrint1("RegisterProtocol: ReceiveCompleteHandler Null\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(ProtocolCharacteristics->StatusHandler)) {
+ NdisPrint1("RegisterProtocol: StatusHandler Null\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(ProtocolCharacteristics->StatusCompleteHandler)) {
+ NdisPrint1("RegisterProtocol: StatusCompleteHandler Null\n");
+ DbgBreakPoint();
+ }
+ }
+
+
+ if (ProtocolCharacteristics->MajorNdisVersion != 3 ||
+ ProtocolCharacteristics->MinorNdisVersion != 0) {
+ *Status = NDIS_STATUS_BAD_VERSION;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterProtocol\n");
+ return;
+ }
+
+
+ //
+ // Check that CharacteristicsLength is enough.
+ //
+
+ if (CharacteristicsLength < sizeof(NDIS_PROTOCOL_CHARACTERISTICS)) {
+ *Status = NDIS_STATUS_BAD_CHARACTERISTICS;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterProtocol\n");
+ return;
+ }
+
+
+ //
+ // Allocate memory for the NDIS protocol block.
+ //
+
+ MemNeeded = sizeof(NDIS_PROTOCOL_BLOCK);
+ NewProtP = (PNDIS_PROTOCOL_BLOCK)ExAllocatePoolWithTag(NonPagedPool, MemNeeded, 'bpDN');
+ if (NewProtP == (PNDIS_PROTOCOL_BLOCK)NULL) {
+ *Status = NDIS_STATUS_RESOURCES;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterProtocol\n");
+ return;
+ }
+ RtlZeroMemory(NewProtP, sizeof(NDIS_PROTOCOL_BLOCK));
+
+ NewProtP->Length = MemNeeded;
+
+ //
+ // Copy over the characteristics table.
+ //
+
+ RtlCopyMemory((PVOID)&NewProtP->ProtocolCharacteristics,
+ (PVOID)ProtocolCharacteristics, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
+
+#if NDISDBG
+ IF_TRACE(TRACE_IMPT) NdisPrint2(" Protocol: %s\n",ProtocolCharacteristics->Name);
+#endif
+
+ //
+ // No opens for this protocol yet.
+ //
+
+ NewProtP->OpenQueue = (PNDIS_OPEN_BLOCK)NULL;
+
+ NdisInitializeRef(&NewProtP->Ref);
+ *NdisProtocolHandle = (NDIS_HANDLE)NewProtP;
+ *Status = NDIS_STATUS_SUCCESS;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterProtocol\n");
+}
+
+VOID
+NdisDeregisterProtocol(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisProtocolHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Deregisters an NDIS protocol.
+
+Arguments:
+
+ Status - Returns the final status.
+ NdisProtocolHandle - The handle returned by NdisRegisterProtocol.
+
+Return Value:
+
+ None.
+
+Note:
+
+ This will kill all the opens for this protocol.
+
+--*/
+
+{
+
+ PNDIS_PROTOCOL_BLOCK OldProtP = (PNDIS_PROTOCOL_BLOCK)NdisProtocolHandle;
+
+ //
+ // If the protocol is already closing, return.
+ //
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisDeregisterProtocol\n");
+ NdisPrint2(" Protocol: %wZ\n",&OldProtP->ProtocolCharacteristics.Name);
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(NdisProtocolHandle)) {
+ NdisPrint1("DeregisterProtocol: Null Handle\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(NdisProtocolHandle)) {
+ NdisPrint1("DeregisterProtocol: Handle not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+ if (!NdisCloseRef(&OldProtP->Ref)) {
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeregisterProtocol\n");
+ return;
+ }
+
+
+ //
+ // Kill all the opens for this protocol.
+ //
+
+ while (OldProtP->OpenQueue != (PNDIS_OPEN_BLOCK)NULL) {
+
+ //
+ // This removes it from the protocol's OpenQueue etc.
+ //
+
+ NdisKillOpenAndNotifyProtocol(OldProtP->OpenQueue);
+ }
+
+ NdisDereferenceProtocol(OldProtP);
+
+ *Status = NDIS_STATUS_SUCCESS;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeregisterProtocol\n");
+}
+
+
+NDIS_STATUS
+NdisMacReceiveHandler(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+{
+ PNDIS_OPEN_BLOCK Open;
+ NDIS_STATUS Status;
+ KIRQL oldIrql;
+
+ KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
+
+ //
+ // Find protocol binding context and get associated open for it.
+ //
+ Open = GetOpenBlockFromProtocolBindingContext(ProtocolBindingContext);
+ ASSERT(Open != NULL);
+
+ Status =
+ (Open->PostNt31ReceiveHandler) (
+ ProtocolBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize);
+
+ KeLowerIrql( oldIrql );
+ return Status;
+}
+
+
+VOID
+NdisMacReceiveCompleteHandler(
+ IN NDIS_HANDLE ProtocolBindingContext
+ )
+{
+ PNDIS_OPEN_BLOCK Open;
+ KIRQL oldIrql;
+ KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
+
+ //
+ // Find protocol binding context and get associated open for it.
+ //
+ Open = GetOpenBlockFromProtocolBindingContext(ProtocolBindingContext);
+ ASSERT(Open != NULL);
+
+ (Open->PostNt31ReceiveCompleteHandler) (
+ ProtocolBindingContext
+ );
+ KeLowerIrql( oldIrql );
+ return;
+}
+
+PNDIS_OPEN_BLOCK
+GetOpenBlockFromProtocolBindingContext(
+ IN NDIS_HANDLE ProtocolBindingContext
+ )
+{
+ PNDIS_OPEN_BLOCK TmpOpen;
+ PNDIS_OPEN_BLOCK PrvOpen = NULL;
+
+ ACQUIRE_SPIN_LOCK(&GlobalOpenListLock);
+
+ TmpOpen = GlobalOpenList;
+
+ while (TmpOpen != NULL) {
+
+ if (TmpOpen->ProtocolBindingContext == ProtocolBindingContext) {
+
+ if (TmpOpen != GlobalOpenList) {
+
+ //
+ // Put this one at the front of the list
+ //
+
+ PrvOpen->NextGlobalOpen = TmpOpen->NextGlobalOpen;
+ TmpOpen->NextGlobalOpen = GlobalOpenList;
+ GlobalOpenList = TmpOpen;
+
+
+ }
+
+ RELEASE_SPIN_LOCK(&GlobalOpenListLock);
+
+ return(TmpOpen);
+
+ }
+
+ PrvOpen = TmpOpen;
+ TmpOpen = TmpOpen->NextGlobalOpen;
+
+ }
+
+ RELEASE_SPIN_LOCK(&GlobalOpenListLock);
+
+ return((PNDIS_OPEN_BLOCK)NULL);
+
+}
+
+VOID
+MiniportOpenAdapter(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PNDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE NdisProtocolHandle,
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_STRING AdapterName,
+ IN UINT OpenOptions,
+ IN PSTRING AddressingInformation,
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_OPEN_BLOCK NewOpenP,
+ IN PFILE_OBJECT FileObject,
+ IN BOOLEAN UsingEncapsulation
+ )
+/*++
+
+Routine Description:
+
+ This routine handles opening a miniport either directly from NdisOpenAdapter()
+ of from our deferred processing routine if the open had to pend.
+
+ NOTE: Must be called with spin lock held.
+ NOTE: Must be called with lock acquired flag set.
+
+Arguments:
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_M_OPEN_BLOCK MiniportOpen;
+ PNDIS_MAC_BLOCK FakeMac;
+ BOOLEAN FilterOpen;
+ PNDIS_PROTOCOL_BLOCK TmpProtP;
+
+ ASSERT( MINIPORT_LOCK_ACQUIRED(Miniport) );
+
+ if (!NdisReferenceMiniport(Miniport)) {
+
+ //
+ // The adapter is closing.
+ //
+
+ ObDereferenceObject((PVOID)FileObject);
+ ExFreePool((PVOID)NewOpenP);
+
+ *Status = NDIS_STATUS_CLOSING;
+
+ return;
+ }
+
+ //
+ // Increment the protocol's reference count.
+ //
+
+ TmpProtP = (PNDIS_PROTOCOL_BLOCK)NdisProtocolHandle;
+
+ if (!NdisReferenceProtocol(TmpProtP)) {
+
+ //
+ // The protocol is closing.
+ //
+
+ NdisDereferenceMiniport(Miniport);
+ ObDereferenceObject((PVOID)FileObject);
+ ExFreePool((PVOID)NewOpenP);
+ *Status = NDIS_STATUS_CLOSING;
+ return;
+ }
+
+
+ //
+ // Now allocate a complete set of MAC structures for the protocol
+ // and set them up to transfer to the Miniport handler routines.
+ //
+
+ if (Miniport->DriverHandle->FakeMac == NULL) {
+
+ FakeMac = (PNDIS_MAC_BLOCK)ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(NDIS_MAC_BLOCK),
+ ' DN'
+ );
+
+ if (FakeMac == NULL) {
+ ObDereferenceObject((PVOID)FileObject);
+ NdisDereferenceMiniport(Miniport);
+ NdisDereferenceProtocol(TmpProtP);
+ ExFreePool((PVOID)NewOpenP);
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ RtlZeroMemory(FakeMac, sizeof(NDIS_MAC_BLOCK));
+ Miniport->DriverHandle->FakeMac = FakeMac;
+ FakeMac->MacCharacteristics.OpenAdapterHandler = NULL;
+ FakeMac->MacCharacteristics.CloseAdapterHandler = NULL;
+ FakeMac->MacCharacteristics.SendHandler = NdisMSend;
+ FakeMac->MacCharacteristics.ResetHandler = NdisMReset;
+ FakeMac->MacCharacteristics.RequestHandler = NdisMRequest;
+ FakeMac->MacCharacteristics.QueryGlobalStatisticsHandler = NULL;
+ FakeMac->MacCharacteristics.UnloadMacHandler = NULL;
+ FakeMac->MacCharacteristics.AddAdapterHandler = NULL;
+ FakeMac->MacCharacteristics.RemoveAdapterHandler = NULL;
+
+ //
+ // If transfer data calls don't pend then we'll use the faster
+ // NdisMTransferDataSync().
+ //
+
+ if ( (Miniport->MacOptions & NDIS_MAC_OPTION_TRANSFERS_NOT_PEND) != 0 ) {
+ FakeMac->MacCharacteristics.TransferDataHandler = NdisMTransferDataSync;
+ } else {
+ FakeMac->MacCharacteristics.TransferDataHandler = NdisMTransferData;
+ }
+
+ //
+ // Keep the SendHandler the same for WAN miniports
+ //
+
+ if (Miniport->MediaType == NdisMediumWan) {
+
+ FakeMac->MacCharacteristics.SendHandler =
+ (PVOID)Miniport->DriverHandle->MiniportCharacteristics.SendHandler;
+ }
+
+ } else {
+
+ FakeMac = Miniport->DriverHandle->FakeMac;
+
+ }
+
+ //
+ // Allocate an open within the Miniport context
+ //
+ MiniportOpen = (PNDIS_M_OPEN_BLOCK)ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(NDIS_M_OPEN_BLOCK),
+ ' DN'
+ );
+
+ if (MiniportOpen == (PNDIS_M_OPEN_BLOCK)NULL) {
+ ObDereferenceObject((PVOID)FileObject);
+ NdisDereferenceMiniport(Miniport);
+ NdisDereferenceProtocol(TmpProtP);
+ ExFreePool((PVOID)NewOpenP);
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ NdisZeroMemory(MiniportOpen, sizeof(NDIS_M_OPEN_BLOCK));
+
+ MiniportOpen->DriverHandle = Miniport->DriverHandle;
+ MiniportOpen->MiniportHandle = Miniport;
+ MiniportOpen->ProtocolHandle = TmpProtP;
+ MiniportOpen->FakeOpen = NewOpenP;
+ MiniportOpen->ProtocolBindingContext = ProtocolBindingContext;
+ MiniportOpen->MiniportAdapterContext = Miniport->MiniportAdapterContext;
+ MiniportOpen->FileObject = FileObject;
+ MiniportOpen->Closing = FALSE;
+ MiniportOpen->CloseRequestHandle = 0;
+ MiniportOpen->CurrentLookahead = Miniport->CurrentLookahead;
+
+ NdisAllocateSpinLock(&(MiniportOpen->SpinLock));
+
+ MiniportOpen->References = 1;
+ MiniportOpen->UsingEthEncapsulation = UsingEncapsulation;
+ MiniportOpen->SendHandler =
+ Miniport->DriverHandle->MiniportCharacteristics.SendHandler;
+ MiniportOpen->TransferDataHandler =
+ Miniport->DriverHandle->MiniportCharacteristics.TransferDataHandler;
+ MiniportOpen->SendCompleteHandler =
+ TmpProtP->ProtocolCharacteristics.SendCompleteHandler;
+ MiniportOpen->TransferDataCompleteHandler =
+ TmpProtP->ProtocolCharacteristics.TransferDataCompleteHandler;
+ MiniportOpen->ReceiveHandler =
+ TmpProtP->ProtocolCharacteristics.ReceiveHandler;
+ MiniportOpen->ReceiveCompleteHandler =
+ TmpProtP->ProtocolCharacteristics.ReceiveCompleteHandler;
+
+ //
+ // Set up the elements of the open structure.
+ //
+
+ NdisAllocateSpinLock(&NewOpenP->SpinLock);
+ NewOpenP->Closing = FALSE;
+
+ NewOpenP->AdapterHandle = (NDIS_HANDLE) Miniport;
+ NewOpenP->ProtocolHandle = TmpProtP;
+ NewOpenP->ProtocolBindingContext = ProtocolBindingContext;
+ NewOpenP->MacBindingHandle = (NDIS_HANDLE)MiniportOpen;
+
+ //
+ // for speed, instead of having to use AdapterHandle->MacHandle
+ //
+ NewOpenP->MacHandle = (NDIS_HANDLE)FakeMac;
+
+ //
+ // for even more speed....
+ //
+
+ if (Miniport->MediaType == NdisMediumArcnet878_2) {
+
+ NewOpenP->TransferDataHandler = NdisMArcTransferData;
+
+ } else {
+
+ if ( (Miniport->MacOptions & NDIS_MAC_OPTION_TRANSFERS_NOT_PEND) != 0 ) {
+ NewOpenP->TransferDataHandler = NdisMTransferDataSync;
+ } else {
+ NewOpenP->TransferDataHandler = NdisMTransferData;
+ }
+ }
+
+ NewOpenP->SendHandler = NdisMSend;
+
+ //
+ // For WAN miniports, the send handler is different
+ //
+
+ if ( Miniport->MediaType == NdisMediumWan ) {
+
+ NewOpenP->SendHandler = (PVOID)NdisMWanSend;
+ }
+
+ NewOpenP->SendCompleteHandler = TmpProtP->ProtocolCharacteristics.SendCompleteHandler;
+ NewOpenP->TransferDataCompleteHandler = TmpProtP->ProtocolCharacteristics.TransferDataCompleteHandler;
+ NewOpenP->ReceiveHandler = TmpProtP->ProtocolCharacteristics.ReceiveHandler;
+ NewOpenP->ReceiveCompleteHandler = TmpProtP->ProtocolCharacteristics.ReceiveCompleteHandler;
+ NewOpenP->PostNt31ReceiveHandler = TmpProtP->ProtocolCharacteristics.ReceiveHandler;
+ NewOpenP->PostNt31ReceiveCompleteHandler = TmpProtP->ProtocolCharacteristics.ReceiveCompleteHandler;
+
+ //
+ // Save a pointer to the file object in the open...
+ //
+
+ NewOpenP->FileObject = FileObject;
+
+ //
+ // ...and a pointer to the open in the file object.
+ //
+
+ FileObject->FsContext = (PVOID)NewOpenP;
+
+ *NdisBindingHandle = (NDIS_HANDLE)NewOpenP;
+
+ //
+ // Insert the open into the filter package
+ //
+
+ switch (Miniport->MediaType) {
+
+ case NdisMediumArcnet878_2:
+
+ if ( !UsingEncapsulation ) {
+
+ FilterOpen = ArcNoteFilterOpenAdapter(
+ Miniport->ArcDB,
+ MiniportOpen,
+ (NDIS_HANDLE)NewOpenP,
+ &MiniportOpen->FilterHandle
+ );
+
+ break;
+ }
+
+ //
+ // If we're using ethernet encapsulation then
+ // we simply fall through to the ethernet stuff.
+ //
+
+ case NdisMedium802_3:
+
+ FilterOpen = EthNoteFilterOpenAdapter(
+ Miniport->EthDB,
+ MiniportOpen,
+ (NDIS_HANDLE)NewOpenP,
+ &MiniportOpen->FilterHandle
+ );
+ break;
+
+ case NdisMedium802_5:
+
+ FilterOpen = TrNoteFilterOpenAdapter(
+ Miniport->TrDB,
+ MiniportOpen,
+ (NDIS_HANDLE)NewOpenP,
+ &MiniportOpen->FilterHandle
+ );
+ break;
+
+ case NdisMediumFddi:
+
+ FilterOpen = FddiNoteFilterOpenAdapter(
+ Miniport->FddiDB,
+ MiniportOpen,
+ (NDIS_HANDLE)NewOpenP,
+ &MiniportOpen->FilterHandle
+ );
+ break;
+
+
+ case NdisMediumWan:
+ //
+ // Bogus non-NULL value
+ //
+
+ FilterOpen = 1;
+ break;
+ }
+
+ //
+ // Check for an open filter failure.
+ //
+
+ if ( !FilterOpen ) {
+
+ //
+ // Something went wrong, clean up and exit.
+ //
+
+ ObDereferenceObject((PVOID)FileObject);
+ NdisDereferenceMiniport(Miniport);
+ NdisDereferenceProtocol(TmpProtP);
+ ExFreePool((PVOID)MiniportOpen);
+ ExFreePool((PVOID)NewOpenP);
+ *Status = NDIS_STATUS_OPEN_FAILED;
+ return;
+
+ }
+
+ NdisQueueOpenOnProtocol(NewOpenP, TmpProtP);
+
+ //
+ // Everything has been filled in. Synchronize access to the
+ // adapter block and link the new open adapter in.
+ //
+
+ MiniportOpen->MiniportNextOpen = Miniport->OpenQueue;
+ Miniport->OpenQueue = MiniportOpen;
+
+ //
+ // NOTE: This must be called at DPC_LEVEL, which it is.
+ //
+ MiniportAdjustMaximumLookahead(Miniport);
+
+ *Status = NDIS_STATUS_SUCCESS;
+}
+
+
+VOID
+MiniportFinishPendingOpens(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+/*++
+
+Routine Description:
+
+ Handles any pending NdisOpenAdapter() calls for miniports.
+
+ NOTE: Must be called with spin lock held.
+
+ NOTE: Must be called with lock acquired flag set.
+
+Arguments:
+
+ Miniport.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PMINIPORT_PENDING_OPEN MiniportPendingOpen;
+ NDIS_STATUS Status;
+ NDIS_STATUS OpenErrorStatus;
+
+ while( Miniport->FirstPendingOpen != NULL ) {
+
+ MiniportPendingOpen = Miniport->FirstPendingOpen;
+
+ //
+ // Do the open again.
+ //
+
+ MiniportOpenAdapter(
+ &Status,
+ &OpenErrorStatus,
+ MiniportPendingOpen->NdisBindingHandle,
+ MiniportPendingOpen->NdisProtocolHandle,
+ MiniportPendingOpen->ProtocolBindingContext,
+ MiniportPendingOpen->AdapterName,
+ MiniportPendingOpen->OpenOptions,
+ MiniportPendingOpen->AddressingInformation,
+ MiniportPendingOpen->Miniport,
+ MiniportPendingOpen->NewOpenP,
+ MiniportPendingOpen->FileObject,
+ MiniportPendingOpen->UsingEncapsulation
+ );
+
+ //
+ // If the open didn't pend then call the NdisCompleteOpenAdapter(),
+ //
+
+ if ( Status != NDIS_STATUS_PENDING ) {
+
+ PNDIS_OPEN_BLOCK OpenP = MiniportPendingOpen->NewOpenP;
+
+ (OpenP->ProtocolHandle->ProtocolCharacteristics.OpenAdapterCompleteHandler) (
+ OpenP->ProtocolBindingContext,
+ Status,
+ OpenErrorStatus
+ );
+ }
+
+ //
+ // Get the next pending open.
+ //
+
+ Miniport->FirstPendingOpen = MiniportPendingOpen->NextPendingOpen;
+
+ //
+ // We're done with this pending open context.
+ //
+
+ NdisFreeMemory(
+ MiniportPendingOpen,
+ sizeof(MINIPORT_PENDING_OPEN),
+ 0
+ );
+
+ }
+}
+
+
+
+UCHAR NdisInternalEaName[4] = "NDIS";
+UCHAR NdisInternalEaValue[8] = "INTERNAL";
+
+VOID
+NdisOpenAdapter(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PNDIS_HANDLE NdisBindingHandle,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE NdisProtocolHandle,
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_STRING AdapterName,
+ IN UINT OpenOptions,
+ IN PSTRING AddressingInformation OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ Opens a connection between a protocol and an adapter (MAC).
+
+Arguments:
+
+ Status - Returns the final status.
+ NdisBindingHandle - Returns a handle referring to this open.
+ SelectedMediumIndex - Index in MediumArray of the medium type that
+ the MAC wishes to be viewed as.
+ MediumArray - Array of medium types which a protocol supports.
+ MediumArraySize - Number of elements in MediumArray.
+ NdisProtocolHandle - The handle returned by NdisRegisterProtocol.
+ ProtocolBindingContext - A context for indications.
+ AdapterName - The name of the adapter to open.
+ OpenOptions - bit mask.
+ AddressingInformation - Information passed to MacOpenAdapter.
+
+Return Value:
+
+ None.
+
+Note:
+
+ This function opens the adapter which will cause an IRP_MJ_CREATE
+ to be sent to the adapter, which is ignored. However, after that we
+ can access the file object for the open, and fill it in as
+ appropriate. The work is done here rather than in the IRP_MJ_CREATE
+ handler because this avoids having to pass the parameters to
+ NdisOpenAdapter through to the adapter.
+
+--*/
+
+{
+ HANDLE FileHandle;
+ OBJECT_ATTRIBUTES ObjectAttr;
+ PFILE_OBJECT FileObject;
+ PDEVICE_OBJECT DeviceObject;
+ PNDIS_OPEN_BLOCK NewOpenP;
+ PNDIS_PROTOCOL_BLOCK TmpProtP;
+ PNDIS_ADAPTER_BLOCK TmpAdaptP;
+ NDIS_STATUS OpenStatus;
+ NTSTATUS NtOpenStatus;
+ IO_STATUS_BLOCK IoStatus;
+ PFILE_FULL_EA_INFORMATION OpenEa;
+ ULONG OpenEaLength;
+ BOOLEAN UsingEncapsulation;
+ KIRQL OldIrql;
+ BOOLEAN LocalLock;
+
+ //
+ // Allocate memory for the NDIS open block.
+ //
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisOpenAdapter\n");
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(NdisProtocolHandle)) {
+ NdisPrint1("OpenAdapter: Null ProtocolHandle\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(NdisProtocolHandle)) {
+ NdisPrint1("OpenAdapter: ProtocolHandle not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(ProtocolBindingContext)) {
+ NdisPrint1("OpenAdapter: Null Context\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(ProtocolBindingContext)) {
+ NdisPrint1("OpenAdapter: Context not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ NewOpenP = (PNDIS_OPEN_BLOCK) ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(NDIS_OPEN_BLOCK),
+ 'boDN'
+ );
+
+ if (NewOpenP == (PNDIS_OPEN_BLOCK)NULL) {
+
+ *Status = NDIS_STATUS_RESOURCES;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisOpenAdapter\n");
+
+ return;
+ }
+
+ RtlZeroMemory(NewOpenP, sizeof(NDIS_OPEN_BLOCK));
+
+ OpenEaLength = sizeof(FILE_FULL_EA_INFORMATION) +
+ sizeof(NdisInternalEaName) +
+ sizeof(NdisInternalEaValue);
+
+ OpenEa = ExAllocatePoolWithTag (NonPagedPool, OpenEaLength, ' DN');
+
+ if (OpenEa == NULL) {
+ ExFreePool (NewOpenP);
+ *Status = NDIS_STATUS_RESOURCES;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisOpenAdapter\n");
+ return;
+ }
+
+ OpenEa->NextEntryOffset = 0;
+ OpenEa->Flags = 0;
+ OpenEa->EaNameLength = sizeof(NdisInternalEaName);
+ OpenEa->EaValueLength = sizeof(NdisInternalEaValue);
+
+ RtlCopyMemory(
+ OpenEa->EaName,
+ NdisInternalEaName,
+ sizeof(NdisInternalEaName)
+ );
+
+ RtlCopyMemory(
+ &OpenEa->EaName[OpenEa->EaNameLength+1],
+ NdisInternalEaValue,
+ sizeof(NdisInternalEaValue)
+ );
+
+
+ //
+ // Obtain a handle to the driver's file object.
+ //
+
+ InitializeObjectAttributes(
+ &ObjectAttr,
+ AdapterName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL
+ );
+
+
+ NtOpenStatus = ZwCreateFile(&FileHandle,
+ FILE_READ_DATA | FILE_WRITE_DATA,
+ &ObjectAttr,
+ &IoStatus,
+ (PLARGE_INTEGER) NULL, // allocation size
+ 0L, // file attributes
+ FILE_SHARE_READ | FILE_SHARE_WRITE, // share access
+ FILE_OPEN, // create disposition
+ 0, // create options
+ OpenEa,
+ OpenEaLength);
+
+
+ ExFreePool(OpenEa);
+
+ if (NtOpenStatus != STATUS_SUCCESS) {
+ ExFreePool((PVOID)NewOpenP);
+ *Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisOpenAdapter\n");
+ return;
+ }
+
+
+ //
+ // Convert the file handle into a pointer to the adapter's
+ // file object.
+ //
+
+ ObReferenceObjectByHandle(FileHandle,
+ 0,
+ NULL,
+ KernelMode,
+ (PVOID *) &FileObject,
+ NULL
+ );
+
+ //
+ // Close the file handle, now that we have the object reference.
+ //
+
+ ZwClose(FileHandle);
+
+ //
+ // From the file object, obtain the device object.
+ //
+
+ DeviceObject = IoGetRelatedDeviceObject(FileObject);
+
+
+ //
+ // Increment the adapter's reference count.
+ //
+
+ TmpAdaptP = (PNDIS_ADAPTER_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1);
+
+ //
+ // Check if this is a Miniport or mac
+ //
+
+ if (TmpAdaptP->DeviceObject != DeviceObject) {
+
+ //
+ // It is a Miniport
+ //
+
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)TmpAdaptP;
+ ULONG i;
+
+ UsingEncapsulation = FALSE;
+
+ //
+ // Select the medium to use
+ //
+
+ for (i = 0; i < MediumArraySize; i++){
+
+ if (MediumArray[i] == Miniport->MediaType) {
+
+ break;
+
+ }
+
+ }
+
+ if (i == MediumArraySize){
+
+ //
+ // Check for ethernet encapsulation on Arcnet as
+ // a possible combination.
+ //
+ if (Miniport->MediaType == NdisMediumArcnet878_2) {
+
+ for (i = 0; i < MediumArraySize; i++){
+
+ if (MediumArray[i] == NdisMedium802_3) {
+ break;
+ }
+ }
+
+ if (i == MediumArraySize) {
+
+ *Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
+ return;
+
+ }
+
+ //
+ // encapsulated ethernet, so we add in the wrapper's
+ // ability to support (emulate) the multicast stuff
+ //
+
+ Miniport->SupportedPacketFilters |= (NDIS_PACKET_TYPE_MULTICAST |
+ NDIS_PACKET_TYPE_ALL_MULTICAST);
+
+ UsingEncapsulation = TRUE;
+
+ } else {
+
+ *Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
+ return;
+
+ }
+
+ }
+
+ *SelectedMediumIndex = i;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ //
+ // Lock the miniport. If the lock fails, then
+ // we must pend this open and try it later.
+ //
+
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ if ( LocalLock ) {
+
+ MiniportOpenAdapter(
+ Status,
+ OpenErrorStatus,
+ NdisBindingHandle,
+ NdisProtocolHandle,
+ ProtocolBindingContext,
+ AdapterName,
+ OpenOptions,
+ AddressingInformation,
+ Miniport,
+ NewOpenP,
+ FileObject,
+ UsingEncapsulation
+ );
+
+ } else {
+
+ PMINIPORT_PENDING_OPEN MiniportPendingOpen;
+
+ //
+ // Allocate some space for this pending structure.
+ // We free in after we call NdisOpenComplete.
+ //
+
+ *Status = NdisAllocateMemory(
+ (PVOID *) &MiniportPendingOpen,
+ sizeof(MINIPORT_PENDING_OPEN),
+ 0,
+ HighestAcceptableMax
+ );
+
+ if ( *Status == NDIS_STATUS_SUCCESS ) {
+
+ //
+ // Save off the parameters for this open so we can
+ // do the actual NdisOpenAdapter() later on.
+ //
+
+ MiniportPendingOpen->NextPendingOpen = NULL;
+ MiniportPendingOpen->NdisBindingHandle = NdisBindingHandle;
+ MiniportPendingOpen->NdisProtocolHandle = NdisProtocolHandle;
+ MiniportPendingOpen->ProtocolBindingContext = ProtocolBindingContext;
+ MiniportPendingOpen->AdapterName = AdapterName;
+ MiniportPendingOpen->OpenOptions = OpenOptions;
+ MiniportPendingOpen->AddressingInformation = AddressingInformation;
+ MiniportPendingOpen->Miniport = Miniport;
+ MiniportPendingOpen->NewOpenP = NewOpenP;
+ MiniportPendingOpen->FileObject = FileObject;
+ MiniportPendingOpen->UsingEncapsulation = UsingEncapsulation;
+
+ if ( Miniport->FirstPendingOpen == NULL ) {
+
+ Miniport->FirstPendingOpen = MiniportPendingOpen;
+
+ } else {
+
+ Miniport->LastPendingOpen->NextPendingOpen = MiniportPendingOpen;
+ }
+
+ Miniport->LastPendingOpen = MiniportPendingOpen;
+
+ //
+ // Make sure MiniportProcessDeferred() completes the open.
+ //
+
+ *Status = NDIS_STATUS_PENDING;
+
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+ } else {
+
+ ObDereferenceObject((PVOID) FileObject);
+ ExFreePool((PVOID) NewOpenP);
+ }
+ }
+
+ //
+ // Unlock the miniport.
+ //
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ return;
+ }
+
+ //
+ // It is a mac
+ //
+
+ IF_TRACE(TRACE_IMPT) NdisPrint2("openadapter: adaptername=%s\n",TmpAdaptP->AdapterName.Buffer);
+ if (!NdisReferenceAdapter(TmpAdaptP)) {
+
+ //
+ // The adapter is closing.
+ //
+
+ ObDereferenceObject((PVOID)FileObject);
+ ExFreePool((PVOID)NewOpenP);
+ *Status = NDIS_STATUS_CLOSING;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisOpenAdapter\n");
+ return;
+ }
+
+ //
+ // Increment the protocol's reference count.
+ //
+
+ TmpProtP = (PNDIS_PROTOCOL_BLOCK)NdisProtocolHandle;
+ if (!NdisReferenceProtocol(TmpProtP)) {
+
+ //
+ // The protocol is closing.
+ //
+
+ NdisDereferenceAdapter(TmpAdaptP);
+ ObDereferenceObject((PVOID)FileObject);
+ ExFreePool((PVOID)NewOpenP);
+ *Status = NDIS_STATUS_CLOSING;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisOpenAdapter\n");
+ return;
+ }
+
+
+ //
+ // Set up the elements of the open structure.
+ //
+
+ NdisAllocateSpinLock(&NewOpenP->SpinLock);
+ NewOpenP->Closing = FALSE;
+
+ NewOpenP->AdapterHandle = TmpAdaptP;
+ NewOpenP->ProtocolHandle = TmpProtP;
+
+ //
+ // for speed, instead of having to use AdapterHandle->MacHandle
+ //
+ NewOpenP->MacHandle = TmpAdaptP->MacHandle;
+
+ //
+ // for even more speed....
+ //
+
+ NewOpenP->SendHandler = TmpAdaptP->MacHandle->MacCharacteristics.SendHandler;
+ NewOpenP->TransferDataHandler = TmpAdaptP->MacHandle->MacCharacteristics.TransferDataHandler;
+
+ NewOpenP->SendCompleteHandler = TmpProtP->ProtocolCharacteristics.SendCompleteHandler;
+ NewOpenP->TransferDataCompleteHandler = TmpProtP->ProtocolCharacteristics.TransferDataCompleteHandler;
+
+ //
+ // Now we have to fake some stuff to get all indications to happen
+ // at DPC_LEVEL. What we do is start the pointer at an NDIS function
+ // which will guarantee that it occurs.
+ //
+ // Then, by extending the OPEN structure and adding the real handlers
+ // at the end we can use these for drivers compiled with this header.
+ //
+ NewOpenP->ProtocolBindingContext = ProtocolBindingContext;
+ NewOpenP->PostNt31ReceiveHandler = TmpProtP->ProtocolCharacteristics.ReceiveHandler;
+ NewOpenP->PostNt31ReceiveCompleteHandler = TmpProtP->ProtocolCharacteristics.ReceiveCompleteHandler;
+ NewOpenP->ReceiveHandler = NdisMacReceiveHandler;
+ NewOpenP->ReceiveCompleteHandler = NdisMacReceiveCompleteHandler;
+
+ //
+ // Patch the open into the global list of macs
+ //
+ ACQUIRE_SPIN_LOCK(&GlobalOpenListLock);
+
+ NewOpenP->NextGlobalOpen = GlobalOpenList;
+ GlobalOpenList = NewOpenP;
+
+ RELEASE_SPIN_LOCK(&GlobalOpenListLock);
+
+
+ //
+ // Save a pointer to the file object in the open...
+ //
+
+ NewOpenP->FileObject = FileObject;
+
+ //
+ // ...and a pointer to the open in the file object.
+ //
+
+ FileObject->FsContext = (PVOID)NewOpenP;
+
+
+ *NdisBindingHandle = (NDIS_HANDLE)NewOpenP;
+
+
+ //
+ // Call MacOpenAdapter, see what we shall see...
+ //
+
+ OpenStatus = (TmpAdaptP->MacHandle->MacCharacteristics.OpenAdapterHandler) (
+ OpenErrorStatus,
+ &NewOpenP->MacBindingHandle,
+ SelectedMediumIndex,
+ MediumArray,
+ MediumArraySize,
+ (NDIS_HANDLE)NewOpenP,
+ TmpAdaptP->MacAdapterContext,
+ OpenOptions,
+ AddressingInformation
+ );
+
+ if ((OpenStatus == NDIS_STATUS_SUCCESS) && NdisFinishOpen(NewOpenP)) {
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ } else if (OpenStatus == NDIS_STATUS_PENDING) {
+
+ *Status = NDIS_STATUS_PENDING;
+
+ } else {
+
+ PNDIS_OPEN_BLOCK TmpOpen;
+
+ //
+ // Something went wrong, clean up and exit.
+ //
+
+ ACQUIRE_SPIN_LOCK(&GlobalOpenListLock);
+
+ if (GlobalOpenList == NewOpenP) {
+
+ GlobalOpenList = NewOpenP->NextGlobalOpen;
+
+ } else {
+
+ TmpOpen = GlobalOpenList;
+
+ while (TmpOpen->NextGlobalOpen != NewOpenP) {
+
+ TmpOpen = TmpOpen->NextGlobalOpen;
+
+ }
+
+ TmpOpen->NextGlobalOpen = NewOpenP->NextGlobalOpen;
+
+ }
+
+ RELEASE_SPIN_LOCK(&GlobalOpenListLock);
+
+ ObDereferenceObject((PVOID)FileObject);
+ NdisDereferenceAdapter(TmpAdaptP);
+ NdisDereferenceProtocol(TmpProtP);
+ ExFreePool((PVOID)NewOpenP);
+ *Status = NDIS_STATUS_OPEN_FAILED;
+ }
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisOpenAdapter\n");
+ return;
+}
+
+
+VOID
+NdisCloseAdapter(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisBindingHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Closes a connection between a protocol and an adapter (MAC).
+
+Arguments:
+
+ Status - Returns the final status.
+ NdisBindingHandle - The handle returned by NdisOpenAdapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_OPEN_BLOCK OpenP = ((PNDIS_OPEN_BLOCK)NdisBindingHandle);
+
+ if (OpenP->AdapterHandle->DeviceObject == NULL) {
+
+ //
+ // This is a Miniport
+ // This returns TRUE if it finished synchronously.
+ //
+
+ if (NdisMKillOpen(OpenP)) {
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ } else {
+
+ *Status = NDIS_STATUS_PENDING; // will complete later
+
+ }
+ return;
+ }
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisCloseAdapter\n");
+ NdisPrint3(" Protocol %wZ is closing Adapter %wZ\n",
+ &(OpenP->ProtocolHandle)->ProtocolCharacteristics.Name,
+ &(OpenP->AdapterHandle)->AdapterName);
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(NdisBindingHandle)) {
+ NdisPrint1("OpenAdapter: Null BindingHandle\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(NdisBindingHandle)) {
+ NdisPrint1("OpenAdapter: BindingHandle not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ //
+ // This returns TRUE if it finished synchronously.
+ //
+
+ if (NdisKillOpen(OpenP)) {
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ } else {
+
+ *Status = NDIS_STATUS_PENDING; // will complete later
+
+ }
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisCloseAdapter\n");
+#undef OpenP
+}
+
+
+//
+// Requests Used by MAC Drivers
+//
+//
+
+
+
+VOID
+NdisInitializeWrapper(
+ OUT PNDIS_HANDLE NdisWrapperHandle,
+ IN PVOID SystemSpecific1,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+
+/*++
+
+Routine Description:
+
+ Called at the beginning of every MAC's initialization routine.
+
+Arguments:
+
+ NdisWrapperHandle - A MAC specific handle for the wrapper.
+
+ SystemSpecific1, a pointer to the driver object for the MAC.
+ SystemSpecific2, a PUNICODE_STRING containing the location of
+ the registry subtree for this driver.
+ SystemSpecific3, unused on NT.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS Status;
+
+ PNDIS_WRAPPER_HANDLE NdisMacInfo;
+
+ UNREFERENCED_PARAMETER (SystemSpecific3);
+
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("==>NdisInitializeWrapper\n");
+
+ Status = NdisAllocateMemory(
+ (PVOID*) (NdisWrapperHandle),
+ sizeof(NDIS_WRAPPER_HANDLE),
+ 0,
+ HighestAcceptableMax
+ );
+
+ if ( Status == NDIS_STATUS_SUCCESS ) {
+
+ NdisMacInfo = (PNDIS_WRAPPER_HANDLE) (*NdisWrapperHandle);
+ NdisMacInfo->NdisWrapperDriver = (PDRIVER_OBJECT) SystemSpecific1;
+ NdisMacInfo->NdisWrapperConfigurationHandle = (HANDLE) SystemSpecific2;
+
+ } else {
+
+ *NdisWrapperHandle = NULL;
+ }
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisInitializeWrapper\n");
+}
+
+VOID
+NdisTerminateWrapper(
+ IN NDIS_HANDLE NdisWrapperHandle,
+ IN PVOID SystemSpecific
+ )
+
+/*++
+
+Routine Description:
+
+ Called at the end of every MAC's termination routine.
+
+Arguments:
+
+ NdisWrapperHandle - The handle returned from NdisInitializeWrapper.
+
+ SystemSpecific - No defined value.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_WRAPPER_HANDLE NdisMacInfo = (PNDIS_WRAPPER_HANDLE)NdisWrapperHandle;
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("==>NdisTerminateWrapper\n");
+
+ UNREFERENCED_PARAMETER(SystemSpecific);
+
+
+ if (NdisMacInfo != NULL) {
+
+ NdisFreeMemory(NdisMacInfo, sizeof(NDIS_WRAPPER_HANDLE), 0);
+
+ }
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisTerminateWrapper\n");
+
+ return;
+}
+
+VOID
+NdisRegisterMac(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE NdisMacHandle,
+ IN NDIS_HANDLE NdisWrapperHandle,
+ IN NDIS_HANDLE MacMacContext,
+ IN PNDIS_MAC_CHARACTERISTICS MacCharacteristics,
+ IN UINT CharacteristicsLength
+ )
+
+/*++
+
+Routine Description:
+
+ Register an NDIS MAC.
+
+Arguments:
+
+ Status - Returns the final status.
+ NdisMacHandle - Returns a handle referring to this MAC.
+ NdisWrapperHandle - Handle returned by NdisInitializeWrapper.
+ MacMacContext - Context for calling MACUnloadMac and MACAddAdapter.
+ MacCharacteritics - The NDIS_MAC_CHARACTERISTICS table.
+ CharacteristicsLength - The length of MacCharacteristics.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_MAC_BLOCK NewMacP;
+ PNDIS_WRAPPER_HANDLE NdisMacInfo = (PNDIS_WRAPPER_HANDLE)(NdisWrapperHandle);
+ UINT MemNeeded;
+
+ //
+ // check that this is an NDIS 3.0 MAC.
+ //
+ IF_TRACE(TRACE_IMPT) NdisPrint1("==>NdisRegisterMac\n");
+
+ //
+ // Do any initial initialization that may be necessary. Note: this
+ // routine will notice if this is the second or later call to it.
+ //
+ *Status = NdisInitialInit( NdisMacInfo->NdisWrapperDriver );
+ if (!NT_SUCCESS(*Status)) {
+ return;
+ }
+
+ *NdisMacHandle = (NDIS_HANDLE)NULL;
+
+ if (NdisMacInfo == NULL) {
+
+ *Status = NDIS_STATUS_FAILURE;
+
+ return;
+
+ }
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(MacCharacteristics->OpenAdapterHandler)) {
+ NdisPrint1("RegisterMac: Null OpenAdapterHandler \n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(MacCharacteristics->CloseAdapterHandler)) {
+ NdisPrint1("RegisterMac: Null CloseAdapterHandler \n");
+ DbgBreakPoint();
+ }
+
+ if (DbgIsNull(MacCharacteristics->SendHandler)) {
+ NdisPrint1("RegisterMac: Null SendHandler \n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(MacCharacteristics->TransferDataHandler)) {
+ NdisPrint1("RegisterMac: Null TransferDataHandler \n");
+ DbgBreakPoint();
+ }
+
+ if (DbgIsNull(MacCharacteristics->ResetHandler)) {
+ NdisPrint1("RegisterMac: Null ResetHandler \n");
+ DbgBreakPoint();
+ }
+
+ if (DbgIsNull(MacCharacteristics->RequestHandler)) {
+ NdisPrint1("RegisterMac: Null RequestHandler \n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(MacCharacteristics->QueryGlobalStatisticsHandler)) {
+ NdisPrint1("RegisterMac: Null QueryGlobalStatisticsHandler \n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(MacCharacteristics->UnloadMacHandler)) {
+ NdisPrint1("RegisterMac: Null UnloadMacHandler \n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(MacCharacteristics->AddAdapterHandler)) {
+ NdisPrint1("RegisterMac: Null AddAdapterHandler \n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(MacCharacteristics->RemoveAdapterHandler)) {
+ NdisPrint1("RegisterMac: Null RemoveAdapterHandler \n");
+ DbgBreakPoint();
+ }
+ }
+
+ if (MacCharacteristics->MajorNdisVersion != 3 ||
+ MacCharacteristics->MinorNdisVersion != 0) {
+ *Status = NDIS_STATUS_BAD_VERSION;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterMac\n");
+ return;
+ }
+
+ //
+ // Check that CharacteristicsLength is enough.
+ //
+
+ if (CharacteristicsLength < sizeof(NDIS_MAC_CHARACTERISTICS)) {
+ NdisPrint3("char len = %d < %d\n",CharacteristicsLength,
+ sizeof(NDIS_MAC_CHARACTERISTICS));
+
+ *Status = NDIS_STATUS_BAD_CHARACTERISTICS;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterMac\n");
+ return;
+ }
+
+ //
+ // Allocate memory for the NDIS MAC block.
+ //
+ MemNeeded = sizeof(NDIS_MAC_BLOCK) + MacCharacteristics->Name.Length;
+ NewMacP = (PNDIS_MAC_BLOCK)ExAllocatePoolWithTag(NonPagedPool, MemNeeded, 'bmDN');
+ if (NewMacP == (PNDIS_MAC_BLOCK)NULL) {
+ *Status = NDIS_STATUS_RESOURCES;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterMac\n");
+ return;
+ }
+ RtlZeroMemory(NewMacP, sizeof(NDIS_MAC_BLOCK));
+
+ NewMacP->Length = MemNeeded;
+
+ //
+ // Copy over the characteristics table.
+ //
+
+ RtlCopyMemory((PVOID)&NewMacP->MacCharacteristics,
+ (PVOID)MacCharacteristics, sizeof(NDIS_MAC_CHARACTERISTICS));
+
+ //
+ // Move buffer pointer to correct location (extra space at the end of
+ // the characteristics table)
+ //
+
+ (NewMacP->MacCharacteristics).Name.Buffer =
+ (PWSTR)((PUCHAR)NewMacP + sizeof(NDIS_MAC_BLOCK));
+
+
+ //
+ // Copy String over.
+ //
+
+ RtlCopyMemory(
+ (NewMacP->MacCharacteristics).Name.Buffer,
+ (MacCharacteristics->Name).Buffer,
+ (MacCharacteristics->Name).Length
+ );
+
+ //
+ // No adapters yet registered for this MAC.
+ //
+
+ NewMacP->AdapterQueue = (PNDIS_ADAPTER_BLOCK)NULL;
+
+ NewMacP->MacMacContext = MacMacContext;
+
+ //
+ // Set up unload handler
+ //
+
+ NdisMacInfo->NdisWrapperDriver->DriverUnload = NdisUnload;
+
+ //
+ // Set up shutdown handler
+ //
+ NdisMacInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_SHUTDOWN] = NdisShutdown;
+
+ //
+ // Set up the handlers for this driver (they all do nothing).
+ //
+
+ NdisMacInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_CREATE] = NdisCreateIrpHandler;
+ NdisMacInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = NdisDeviceControlIrpHandler;
+ NdisMacInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_CLEANUP] = NdisSuccessIrpHandler;
+ NdisMacInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_CLOSE] = NdisCloseIrpHandler;
+
+ NewMacP->NdisMacInfo = NdisMacInfo;
+
+ //
+ // Put MAC on global list.
+ //
+
+ ACQUIRE_SPIN_LOCK(&NdisMacListLock);
+
+ NewMacP->NextMac = NdisMacList;
+ NdisMacList = NewMacP;
+
+ RELEASE_SPIN_LOCK(&NdisMacListLock);
+
+ //
+ // Use this event to tell us when all adapters are removed from the mac
+ // during an unload
+ //
+
+ KeInitializeEvent(
+ &NewMacP->AdaptersRemovedEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ NewMacP->Unloading = FALSE;
+
+ NdisInitializeRef(&NewMacP->Ref);
+
+ *NdisMacHandle = (NDIS_HANDLE)NewMacP;
+
+ NdisInitReferencePackage();
+
+ if (NdisMacInfo->NdisWrapperConfigurationHandle) {
+
+ if (NdisCallDriverAddAdapter(NewMacP) == NDIS_STATUS_SUCCESS) {
+ *Status = NDIS_STATUS_SUCCESS;
+ } else {
+ *Status = NDIS_STATUS_FAILURE;
+ NdisDereferenceMac(NewMacP);
+ }
+ } else {
+ *Status = NDIS_STATUS_FAILURE;
+ }
+
+ NdisInitDereferencePackage();
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterMac\n");
+}
+
+
+VOID
+NdisDeregisterMac(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisMacHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Deregisters an NDIS MAC.
+
+Arguments:
+
+ Status - Returns the status of the request.
+ NdisMacHandle - The handle returned by NdisRegisterMac.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNDIS_MAC_BLOCK OldMacP = (PNDIS_MAC_BLOCK)NdisMacHandle;
+
+ //
+ // If the MAC is already closing, return.
+ //
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ if (OldMacP == NULL) {
+
+ return;
+ }
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisDeregisterMac\n");
+ NdisPrint2(" Mac %wZ being deregistered\n",&OldMacP->MacCharacteristics.Name);
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(NdisMacHandle)) {
+ NdisPrint1("DeregisterMac: Null Handle\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(NdisMacHandle)) {
+ NdisPrint1("DeregisterMac: Handle not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+ if (!NdisCloseRef(&OldMacP->Ref)) {
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeregisterMac\n");
+ return;
+ }
+
+
+ ASSERT(OldMacP->AdapterQueue == (PNDIS_ADAPTER_BLOCK)NULL);
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeregisterMac\n");
+}
+
+IO_ALLOCATION_ACTION
+NdisAllocationExecutionRoutine(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the execution routine for AllocateAdapterChannel,
+ if is called when the map registers have been assigned.
+
+Arguments:
+
+ DeviceObject - The device object of the adapter.
+
+ Irp - ??.
+
+ MapRegisterBase - The address of the first translation table
+ assigned to us.
+
+ Context - A pointer to the Adapter in question.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_ADAPTER_BLOCK AdaptP = (PNDIS_ADAPTER_BLOCK)Context;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)Context;
+
+ Irp; DeviceObject;
+
+ //
+ // Save this translation entry in the correct spot.
+ //
+
+ if (AdaptP->DeviceObject == NULL) {
+
+ Miniport->MapRegisters[Miniport->CurrentMapRegister].MapRegister = MapRegisterBase;
+
+ } else {
+
+ AdaptP->MapRegisters[AdaptP->CurrentMapRegister].MapRegister = MapRegisterBase;
+
+ }
+
+ //
+ // This will free the thread that is waiting for this callback.
+ //
+
+ KeSetEvent(
+ ((AdaptP->DeviceObject == NULL) ?
+ &Miniport->AllocationEvent :
+ &AdaptP->AllocationEvent),
+ 0L,
+ FALSE
+ );
+
+ return DeallocateObjectKeepRegisters;
+}
+
+
+
+NDIS_STATUS
+NdisRegisterAdapter(
+ OUT PNDIS_HANDLE NdisAdapterHandle,
+ IN NDIS_HANDLE NdisMacHandle,
+ IN NDIS_HANDLE MacAdapterContext,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN PNDIS_STRING AdapterName,
+ IN PVOID AdapterInformation
+ )
+
+/*++
+
+Routine Description:
+
+ Register an NDIS adapter.
+
+Arguments:
+
+ NdisAdapterHandle - Returns a handle referring to this adapter.
+ NdisMacHandle - A handle for a previously registered MAC.
+ MacAdapterContext - A context for calls into this MAC.
+ WrapperConfigurationContext - Context passed to MacAddAdapter.
+ AdapterName - The name the adapter should be registered under.
+ AdapterInformation - Contains adapter information. For future
+ use. NULL for the meantime. Storage for it
+ must be allocated by the caller.
+
+Return Value:
+
+ The final status.
+
+--*/
+
+{
+ PNDIS_ADAPTER_BLOCK NewAdaptP;
+ PDEVICE_OBJECT TmpDeviceP;
+ PNDIS_MAC_BLOCK TmpMacP;
+ NTSTATUS NtStatus;
+ NDIS_STRING NdisAdapterName;
+ PHYSICAL_ADDRESS PortAddress;
+ PHYSICAL_ADDRESS InitialPortAddress;
+ ULONG addressSpace;
+ PNDIS_ADAPTER_INFORMATION AdapterInfo = (PNDIS_ADAPTER_INFORMATION)AdapterInformation;
+ BOOLEAN Conflict;
+ PCM_RESOURCE_LIST Resources;
+ LARGE_INTEGER TimeoutValue;
+ BOOLEAN AllocateIndividualPorts = TRUE;
+ ULONG i;
+ ULONG BusNumber;
+ NDIS_INTERFACE_TYPE BusType;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisRegisterAdapter\n");
+ }
+
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(NdisMacHandle)) {
+ NdisPrint1("RegisterAdapter: Null Handle\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(NdisMacHandle)) {
+ NdisPrint1("RegisterAdapter: Handle not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(MacAdapterContext)) {
+ NdisPrint1("RegisterAdapter: Null Context\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(MacAdapterContext)) {
+ NdisPrint1("RegisterAdapter: Context not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ //
+ // Increment the MAC's refernce count.
+ //
+
+ if (!NdisReferenceMac((PNDIS_MAC_BLOCK)NdisMacHandle)) {
+
+ //
+ // The MAC is closing.
+ //
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_CLOSING;
+ }
+
+ //
+ // Allocate the string structure and space for the string. This
+ // must be allocated from nonpaged pool, because it is touched by
+ // NdisWriteErrorLogEntry, which may be called from DPC level.
+ //
+
+ NdisAdapterName.Buffer = (PWSTR)ExAllocatePoolWithTag(
+ NonPagedPool,
+ AdapterName->MaximumLength,
+ 'naDN'
+ );
+ if (NdisAdapterName.Buffer == NULL) {
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ NdisAdapterName.MaximumLength = AdapterName->MaximumLength;
+ NdisAdapterName.Length = AdapterName->Length;
+
+ RtlCopyMemory(NdisAdapterName.Buffer,
+ AdapterName->Buffer,
+ AdapterName->MaximumLength
+ );
+
+ //
+ // Create a device object for this adapter.
+ //
+
+ NtStatus = IoCreateDevice(
+ ((PNDIS_MAC_BLOCK)NdisMacHandle)->NdisMacInfo->NdisWrapperDriver,
+ sizeof(NDIS_ADAPTER_BLOCK) + sizeof(NDIS_WRAPPER_CONTEXT), // device extension size
+ AdapterName,
+ FILE_DEVICE_PHYSICAL_NETCARD,
+ 0,
+ FALSE, // exclusive flag
+ &TmpDeviceP
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ ExFreePool( NdisAdapterName.Buffer );
+ return NDIS_STATUS_DEVICE_FAILED;
+ }
+
+
+ //
+ // Initialize the NDIS adapter block in the device object extension
+ //
+ // *** NDIS_WRAPPER_CONTEXT has a higher alignment requirement than
+ // NDIS_ADAPTER_BLOCK, so we put it first in the extension.
+ //
+
+ ASSERT( (sizeof(NDIS_WRAPPER_CONTEXT) & 3) <= (sizeof(NDIS_ADAPTER_BLOCK) & 3) );
+
+ NewAdaptP = (PNDIS_ADAPTER_BLOCK)((PNDIS_WRAPPER_CONTEXT)TmpDeviceP->DeviceExtension + 1);
+ RtlZeroMemory(NewAdaptP, sizeof(NDIS_ADAPTER_BLOCK));
+
+ NewAdaptP->DeviceObject = TmpDeviceP;
+ NewAdaptP->MacHandle = TmpMacP = (PNDIS_MAC_BLOCK)NdisMacHandle;
+ NewAdaptP->MacAdapterContext = MacAdapterContext;
+ NewAdaptP->AdapterName = NdisAdapterName;
+ // NewAdaptP->OpenQueue = (PNDIS_OPEN_BLOCK)NULL;
+
+ NewAdaptP->WrapperContext = TmpDeviceP->DeviceExtension;
+
+ //
+ // Get the BusNumber and BusType from the context
+ //
+
+ if (((PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext)[3].DefaultType ==
+ (NDIS_INTERFACE_TYPE)-1) {
+
+ BusType = (NDIS_INTERFACE_TYPE)-1;
+
+ } else {
+
+ BusType = AdapterInfo->AdapterType;
+
+ }
+
+ BusNumber = ((PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext)[3].DefaultLength;
+
+ //
+ // Check that if there is no bus number or no bus type that the driver is not
+ // going to try to acquire any hardware resources
+ //
+
+ if ((BusType == (NDIS_INTERFACE_TYPE)-1) || (BusNumber == (ULONG)-1)) {
+
+ if ((AdapterInfo != NULL) &&
+ ((AdapterInfo->NumberOfPortDescriptors != 0) ||
+ (AdapterInfo->Master))) {
+
+ //
+ // Error out
+ //
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ return NDIS_STATUS_BAD_CHARACTERISTICS;
+
+ }
+
+ }
+
+ //
+ // Copy over any PCI assigned resources
+ //
+ if ((BusType == NdisInterfacePci) &&
+ (BusNumber != -1) &&
+ (AdapterInfo != NULL) &&
+ (TmpMacP->PciAssignedResources != NULL)) {
+
+ //
+ // Reassign old resources to this device
+ //
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ ((PNDIS_MAC_BLOCK)NdisMacHandle)->NdisMacInfo->NdisWrapperDriver,
+ NULL,
+ 0,
+ NewAdaptP->DeviceObject,
+ TmpMacP->PciAssignedResources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ TmpMacP->PciAssignedResources->List[0].PartialResourceList.Count,
+ TRUE,
+ &Conflict
+ );
+
+ //
+ // Allocate a new buffer
+ //
+ Resources = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ (AdapterInfo->NumberOfPortDescriptors +
+ TmpMacP->PciAssignedResources->List[0].PartialResourceList.Count +
+ (((AdapterInfo->Master == TRUE) &&
+ (AdapterInfo->AdapterType == NdisInterfaceIsa))
+ ?1
+ :0)),
+ 'lrDN'
+ );
+
+ if (Resources == NULL) {
+
+ //
+ // Error out
+ //
+
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ ExFreePool( TmpMacP->PciAssignedResources );
+ NdisDereferenceMac(TmpMacP);
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ //
+ // Copy over old resource list
+ //
+ NdisMoveMemory(Resources,
+ TmpMacP->PciAssignedResources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ TmpMacP->PciAssignedResources->List[0].PartialResourceList.Count
+ );
+
+ TmpMacP->PciAssignedResources->Count = 0;
+
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ ((PNDIS_MAC_BLOCK)NdisMacHandle)->NdisMacInfo->NdisWrapperDriver,
+ TmpMacP->PciAssignedResources,
+ sizeof(CM_RESOURCE_LIST),
+ NULL,
+ NULL,
+ 0,
+ TRUE,
+ &Conflict
+ );
+
+ ExFreePool( TmpMacP->PciAssignedResources);
+
+ TmpMacP->PciAssignedResources = NULL;
+
+ } else {
+
+ //
+ // Allocate a new buffer for non-pci devices
+ //
+ Resources = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ (AdapterInfo->NumberOfPortDescriptors +
+ (((AdapterInfo->Master == TRUE) &&
+ (AdapterInfo->AdapterType == NdisInterfaceIsa))
+ ?1
+ :0)),
+ 'lrDN'
+ );
+
+ if (Resources == NULL) {
+
+ //
+ // Error out
+ //
+
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ //
+ // Fix up counts for non-pci devices
+ //
+ Resources->List[0].PartialResourceList.Count = 0;
+
+ }
+
+ //
+ // Setup resources for the ports
+ //
+
+ if ((BusType != (NDIS_INTERFACE_TYPE)-1) &&
+ (BusNumber != (ULONG)-1)) {
+
+ if (AdapterInfo != NULL) {
+
+ ULONG HighestPort;
+ ULONG LowestPort;
+
+ Resources->Count = 1;
+ Resources->List[0].InterfaceType = AdapterInfo->AdapterType;
+ Resources->List[0].BusNumber = BusNumber;
+ Resources->List[0].PartialResourceList.Version = 0;
+ Resources->List[0].PartialResourceList.Revision = 0;
+
+ NewAdaptP->Resources = Resources;
+ NewAdaptP->BusNumber = BusNumber;
+ NewAdaptP->BusType = BusType;
+ NewAdaptP->AdapterType = AdapterInfo->AdapterType;
+ NewAdaptP->Master = AdapterInfo->Master;
+
+ //
+ // NewAdaptP->InitialPort and NumberOfPorts refer to the
+ // union of all port mappings specified; the area must
+ // cover all possible ports. We scan the list, keeping track
+ // of the highest and lowest ports used.
+ //
+
+ if (AdapterInfo->NumberOfPortDescriptors > 0) {
+
+
+ //
+ // Setup port
+ //
+ LowestPort = AdapterInfo->PortDescriptors[0].InitialPort;
+ HighestPort = LowestPort + AdapterInfo->PortDescriptors[0].NumberOfPorts;
+
+ if (AdapterInfo->PortDescriptors[0].PortOffset == NULL) {
+
+ AllocateIndividualPorts = FALSE;
+
+ }
+
+ for (i = 0; i < AdapterInfo->NumberOfPortDescriptors; i++) {
+
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].Type =
+ CmResourceTypePort;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].ShareDisposition =
+ CmResourceShareDeviceExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].Flags =
+ (AdapterInfo->AdapterType == NdisInterfaceInternal)?
+ CM_RESOURCE_PORT_MEMORY : CM_RESOURCE_PORT_IO;
+#if !defined(BUILD_FOR_3_1)
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].u.Port.Start.QuadPart =
+ (ULONG)AdapterInfo->PortDescriptors[i].InitialPort;
+#else
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].u.Port.Start =
+ RtlConvertUlongToLargeInteger((ULONG)(AdapterInfo->PortDescriptors[i].InitialPort));
+#endif
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].u.Port.Length =
+ AdapterInfo->PortDescriptors[i].NumberOfPorts;
+
+ if (AdapterInfo->PortDescriptors[i].PortOffset == NULL) {
+
+ AllocateIndividualPorts = FALSE;
+
+ }
+
+ if (AdapterInfo->PortDescriptors[i].InitialPort < LowestPort) {
+ LowestPort = AdapterInfo->PortDescriptors[i].InitialPort;
+ }
+ if ((AdapterInfo->PortDescriptors[i].InitialPort +
+ AdapterInfo->PortDescriptors[i].NumberOfPorts) > HighestPort) {
+ HighestPort = AdapterInfo->PortDescriptors[i].InitialPort +
+ AdapterInfo->PortDescriptors[i].NumberOfPorts;
+ }
+ }
+
+ NewAdaptP->InitialPort = LowestPort;
+ NewAdaptP->NumberOfPorts = HighestPort - LowestPort;
+
+ } else {
+
+ NewAdaptP->NumberOfPorts = 0;
+
+ }
+
+ Resources->List[0].PartialResourceList.Count += AdapterInfo->NumberOfPortDescriptors;
+
+ } else {
+
+ //
+ // Error out
+ //
+
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ }
+
+ NewAdaptP->BeingRemoved = FALSE;
+
+ if ((BusType != (NDIS_INTERFACE_TYPE)-1) &&
+ (BusNumber != (ULONG)-1)) {
+
+ //
+ // Submit Resources
+ //
+
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ ((PNDIS_MAC_BLOCK)NdisMacHandle)->NdisMacInfo->NdisWrapperDriver,
+ NULL,
+ 0,
+ NewAdaptP->DeviceObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ Resources->List[0].PartialResourceList.Count,
+ TRUE,
+ &Conflict
+ );
+
+ //
+ // Check for conflict.
+ //
+
+ if (Conflict || (NtStatus != STATUS_SUCCESS)) {
+
+ if (Conflict) {
+
+ //
+ // Log an error
+ //
+
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ ULONG StringSize;
+ PWCH baseFileName;
+
+ baseFileName = NewAdaptP->AdapterName.Buffer;
+
+ //
+ // Parse out the path name, leaving only the device name.
+ //
+
+ for ( i = 0; i < NewAdaptP->AdapterName.Length / sizeof(WCHAR); i++ ) {
+
+ //
+ // If s points to a directory separator, set baseFileName to
+ // the character after the separator.
+ //
+
+ if ( NewAdaptP->AdapterName.Buffer[i] == OBJ_NAME_PATH_SEPARATOR ) {
+ baseFileName = &(NewAdaptP->AdapterName.Buffer[++i]);
+ }
+
+ }
+
+ StringSize = NewAdaptP->AdapterName.MaximumLength -
+ (((ULONG)baseFileName) - ((ULONG)NewAdaptP->AdapterName.Buffer)) ;
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ TmpDeviceP,
+ (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize)
+ );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->ErrorCode = EVENT_NDIS_IO_PORT_CONFLICT;
+
+ //
+ // store the time
+ //
+
+ errorLogEntry->MajorFunctionCode = 0;
+ errorLogEntry->RetryCount = 0;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = 0;
+ errorLogEntry->SequenceNumber = 0;
+ errorLogEntry->IoControlCode = 0;
+
+ //
+ // Set string information
+ //
+
+ if (StringSize != 0) {
+
+ errorLogEntry->NumberOfStrings = 1;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+
+ RtlCopyMemory (
+ ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET),
+ (PVOID)baseFileName,
+ StringSize
+ );
+
+ } else {
+
+ errorLogEntry->NumberOfStrings = 0;
+
+ }
+
+ //
+ // write it out
+ //
+
+ IoWriteErrorLogEntry(errorLogEntry);
+ }
+
+ //
+ // Free memory
+ //
+
+ ExFreePool(Resources);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+
+ return(NDIS_STATUS_RESOURCE_CONFLICT);
+
+ }
+
+ //
+ // Free memory
+ //
+
+ ExFreePool(Resources);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+
+
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // If port mapping is needed, we do that. If the result
+ // is in memory, we have to map it. We map only the
+ // ports specified in AdapterInformation; the default
+ // is to map the first 4K.
+ //
+ // Note that NumberOfPorts can only be 0 if AdapterInfo
+ // is provided and explicitly sets it to 0, so in that
+ // case it is OK to leave the adapter in a state where
+ // a call to NdisXXXPort will probably crash (because
+ // PortOffset will be undefined).
+ //
+
+ if (NewAdaptP->NumberOfPorts > 0) {
+
+ if (AllocateIndividualPorts) {
+
+ //
+ // We get here if we are supposed to allocate ports on an
+ // individual bases -- which implies that the driver will
+ // be using the Raw functions.
+ //
+ // Get the system physical address for this card. The card uses
+ // I/O space, except for "internal" Jazz devices which use
+ // memory space.
+ //
+
+ for (i = 0; i < AdapterInfo->NumberOfPortDescriptors; i++) {
+
+ addressSpace = (NewAdaptP->AdapterType == NdisInterfaceInternal) ? 0 : 1;
+
+ InitialPortAddress.LowPart = AdapterInfo->PortDescriptors[i].InitialPort;
+ InitialPortAddress.HighPart = 0;
+
+ if ( !HalTranslateBusAddress(
+ NewAdaptP->BusType, // InterfaceType
+ NewAdaptP->BusNumber, // BusNumber
+ InitialPortAddress, // Bus Address
+ &addressSpace, // AddressSpace
+ &PortAddress // Translated address
+ ) ) {
+
+ //
+ // Free memory
+ //
+
+ ExFreePool(Resources);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+
+
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ if (addressSpace == 0) {
+
+ //
+ // memory space
+ //
+
+ *(AdapterInfo->PortDescriptors[i].PortOffset) = MmMapIoSpace(
+ PortAddress,
+ AdapterInfo->PortDescriptors[i].NumberOfPorts,
+ FALSE
+ );
+
+ if (*(AdapterInfo->PortDescriptors[i].PortOffset) == NULL) {
+
+ ExFreePool(Resources);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ } else {
+
+ //
+ // I/O space
+ //
+
+ *(AdapterInfo->PortDescriptors[i].PortOffset) = (PUCHAR)PortAddress.LowPart;
+
+ }
+
+ }
+
+ } else {
+
+ //
+ // The driver will not use the Raw functions, only the
+ // old NdisRead and NdisWrite port functions.
+ //
+ // Get the system physical address for this card. The card uses
+ // I/O space, except for "internal" Jazz devices which use
+ // memory space.
+ //
+
+ addressSpace = (NewAdaptP->AdapterType == NdisInterfaceInternal) ? 0 : 1;
+ InitialPortAddress.LowPart = NewAdaptP->InitialPort;
+ InitialPortAddress.HighPart = 0;
+ if ( !HalTranslateBusAddress(
+ NewAdaptP->BusType, // InterfaceType
+ NewAdaptP->BusNumber, // BusNumber
+ InitialPortAddress, // Bus Address
+ &addressSpace, // AddressSpace
+ &PortAddress // Translated address
+ ) ) {
+
+ //
+ // Free memory
+ //
+
+ ExFreePool(Resources);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+
+
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ if (addressSpace == 0) {
+
+ //
+ // memory space
+ //
+
+ NewAdaptP->InitialPortMapping = MmMapIoSpace(
+ PortAddress,
+ NewAdaptP->NumberOfPorts,
+ FALSE
+ );
+
+ if (NewAdaptP->InitialPortMapping == NULL) {
+ ExFreePool(Resources);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ NewAdaptP->InitialPortMapped = TRUE;
+
+ } else {
+
+ //
+ // I/O space
+ //
+
+ NewAdaptP->InitialPortMapping = (PUCHAR)PortAddress.LowPart;
+ NewAdaptP->InitialPortMapped = FALSE;
+
+ }
+
+ //
+ // PortOffset holds the mapped address of port 0.
+ //
+
+ NewAdaptP->PortOffset = NewAdaptP->InitialPortMapping - NewAdaptP->InitialPort;
+
+ }
+
+ } else {
+
+ //
+ // Technically should not allow this, but do it until
+ // all drivers register their info correctly.
+ //
+
+ NewAdaptP->PortOffset = 0;
+
+ }
+
+ }
+
+ //
+ // If the driver want to be called back now, use
+ // supplied callback routine.
+ //
+
+ if ((AdapterInfo != NULL) && (AdapterInfo->ActivateCallback != NULL)) {
+
+ Status = (*(AdapterInfo->ActivateCallback))((NDIS_HANDLE)NewAdaptP,
+ MacAdapterContext,
+ AdapterInfo->DmaChannel
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Exit
+ //
+
+ ExFreePool(Resources);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return Status;
+
+ }
+
+ }
+
+ //
+ // Set information from AdapterInformation. The call back
+ // routine can set these values.
+ //
+
+ NewAdaptP->ChannelNumber = AdapterInfo->DmaChannel;
+ NewAdaptP->PhysicalMapRegistersNeeded =
+ AdapterInfo->PhysicalMapRegistersNeeded;
+ NewAdaptP->MaximumPhysicalMapping =
+ AdapterInfo->MaximumPhysicalMapping;
+
+
+ //
+ // Check for resource conflic on DmaChannel.
+ //
+
+ if ((NewAdaptP->Master) &&
+ (BusType != (NDIS_INTERFACE_TYPE)-1) &&
+ (BusNumber != (ULONG)-1)) {
+
+ if (NewAdaptP->AdapterType == NdisInterfaceIsa) {
+
+ //
+ // Put the DMA channel in the resource list.
+ //
+
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Type =
+ CmResourceTypeDma;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].ShareDisposition =
+ CmResourceShareDeviceExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Flags =
+ 0;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Dma.Channel =
+ NewAdaptP->ChannelNumber;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Dma.Port =
+ 0;
+ Resources->List[0].PartialResourceList.Count++;
+
+ }
+
+ //
+ // Submit Resources
+ //
+
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ ((PNDIS_MAC_BLOCK)NdisMacHandle)->NdisMacInfo->NdisWrapperDriver,
+ NULL,
+ 0,
+ NewAdaptP->DeviceObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ Resources->List[0].PartialResourceList.Count,
+ TRUE,
+ &Conflict
+ );
+
+ //
+ // Check for conflict.
+ //
+
+ if (Conflict || (NtStatus != STATUS_SUCCESS)) {
+
+ if (Conflict) {
+
+ //
+ // Log an error
+ //
+
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ ULONG StringSize;
+ PWCH baseFileName;
+
+ baseFileName = NewAdaptP->AdapterName.Buffer;
+
+ //
+ // Parse out the path name, leaving only the device name.
+ //
+
+ for ( i = 0; i < NewAdaptP->AdapterName.Length / sizeof(WCHAR); i++ ) {
+
+ //
+ // If s points to a directory separator, set baseFileName to
+ // the character after the separator.
+ //
+
+ if ( NewAdaptP->AdapterName.Buffer[i] == OBJ_NAME_PATH_SEPARATOR ) {
+ baseFileName = &(NewAdaptP->AdapterName.Buffer[++i]);
+ }
+
+ }
+
+ StringSize = NewAdaptP->AdapterName.MaximumLength -
+ (((ULONG)baseFileName) - ((ULONG)NewAdaptP->AdapterName.Buffer)) ;
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ TmpDeviceP,
+ (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize)
+ );
+
+ if (errorLogEntry != NULL) {
+
+ if ((NewAdaptP->Master) &&
+ (NewAdaptP->AdapterType == Isa)){
+
+ errorLogEntry->ErrorCode = EVENT_NDIS_PORT_OR_DMA_CONFLICT;
+
+ } else {
+
+ errorLogEntry->ErrorCode = EVENT_NDIS_IO_PORT_CONFLICT;
+
+ }
+
+ //
+ // store the time
+ //
+
+ errorLogEntry->MajorFunctionCode = 0;
+ errorLogEntry->RetryCount = 0;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = 0;
+ errorLogEntry->SequenceNumber = 0;
+ errorLogEntry->IoControlCode = 0;
+
+ //
+ // Set string information
+ //
+
+ if (StringSize != 0) {
+
+ errorLogEntry->NumberOfStrings = 1;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+
+ RtlCopyMemory (
+ ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET),
+ (PVOID)baseFileName,
+ StringSize
+ );
+
+ } else {
+
+ errorLogEntry->NumberOfStrings = 0;
+
+ }
+
+ //
+ // write it out
+ //
+
+ IoWriteErrorLogEntry(errorLogEntry);
+ }
+
+ //
+ // Free memory
+ //
+
+ ExFreePool(Resources);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+
+ return(NDIS_STATUS_RESOURCE_CONFLICT);
+
+ }
+
+ //
+ // Free memory
+ //
+
+ ExFreePool(Resources);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+
+
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ }
+
+ //
+ // If the device is a busmaster, we get an adapter
+ // object for it.
+ // If map registers are needed, we loop, allocating an
+ // adapter channel for each map register needed.
+ //
+
+ if ((NewAdaptP->Master) &&
+ (BusType != (NDIS_INTERFACE_TYPE)-1) &&
+ (BusNumber != (ULONG)-1)) {
+
+ //
+ // This is needed by HalGetAdapter.
+ //
+ DEVICE_DESCRIPTION DeviceDescription;
+
+ //
+ // Returned by HalGetAdapter.
+ //
+ ULONG MapRegistersAllowed;
+
+ //
+ // Returned by HalGetAdapter.
+ //
+ PADAPTER_OBJECT AdapterObject;
+
+ //
+ // Map registers needed per channel.
+ //
+ ULONG MapRegistersPerChannel;
+
+ NTSTATUS Status;
+
+ //
+ // Allocate storage for holding the appropriate
+ // information for each map register.
+ //
+
+ NewAdaptP->MapRegisters = (PMAP_REGISTER_ENTRY)
+ ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(MAP_REGISTER_ENTRY) *
+ NewAdaptP->PhysicalMapRegistersNeeded,
+ 'rmDN');
+
+ if (NewAdaptP->MapRegisters == (PMAP_REGISTER_ENTRY)NULL) {
+
+ //
+ // Error out
+ //
+
+ ExFreePool(Resources);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ //
+ // Use this event to tell us when NdisAllocationExecutionRoutine
+ // has been called.
+ //
+
+ KeInitializeEvent(
+ &NewAdaptP->AllocationEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+
+ //
+ // Set up the device description; zero it out in case its
+ // size changes.
+ //
+
+ RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
+
+ DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
+ DeviceDescription.Master = TRUE;
+ DeviceDescription.ScatterGather = TRUE;
+
+ DeviceDescription.BusNumber = NewAdaptP->BusNumber;
+ DeviceDescription.DmaChannel = NewAdaptP->ChannelNumber;
+ DeviceDescription.InterfaceType = NewAdaptP->AdapterType;
+
+ if (DeviceDescription.InterfaceType == NdisInterfaceIsa) {
+
+ //
+ // For ISA devices, the width is based on the DMA channel:
+ // 0-3 == 8 bits, 5-7 == 16 bits. Timing is compatibility
+ // mode.
+ //
+
+ if (NewAdaptP->ChannelNumber > 4) {
+ DeviceDescription.DmaWidth = Width16Bits;
+ } else {
+ DeviceDescription.DmaWidth = Width8Bits;
+ }
+ DeviceDescription.DmaSpeed = Compatible;
+
+ } else if ((DeviceDescription.InterfaceType == NdisInterfaceMca) ||
+ (DeviceDescription.InterfaceType == NdisInterfaceEisa) ||
+ (DeviceDescription.InterfaceType == NdisInterfacePci))
+ {
+ DeviceDescription.Dma32BitAddresses = AdapterInfo->Dma32BitAddresses;
+ DeviceDescription.DmaPort = 0;
+
+ }
+
+ DeviceDescription.MaximumLength = NewAdaptP->MaximumPhysicalMapping;
+
+
+ //
+ // Determine how many map registers we need per channel.
+ //
+
+ MapRegistersPerChannel =
+ ((NewAdaptP->MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2;
+
+ //
+ // Get the adapter object.
+ //
+
+ AdapterObject = HalGetAdapter (&DeviceDescription, &MapRegistersAllowed);
+
+ if (AdapterObject == NULL) {
+
+ ExFreePool(Resources);
+ ExFreePool(NewAdaptP->MapRegisters);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ ASSERT (MapRegistersAllowed >= MapRegistersPerChannel);
+
+ //
+ // We save this to call IoFreeMapRegisters later.
+ //
+
+ NewAdaptP->SystemAdapterObject = AdapterObject;
+
+
+ //
+ // Now loop, allocating an adapter channel each time, then
+ // freeing everything but the map registers.
+ //
+
+ for (i=0; i<NewAdaptP->PhysicalMapRegistersNeeded; i++) {
+
+ NewAdaptP->CurrentMapRegister = i;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ Status = IoAllocateAdapterChannel(
+ AdapterObject,
+ NewAdaptP->DeviceObject,
+ MapRegistersPerChannel,
+ NdisAllocationExecutionRoutine,
+ (PVOID)NewAdaptP
+ );
+
+ KeLowerIrql(OldIrql);
+
+ if (!NT_SUCCESS(Status)) {
+
+#if DBG
+ DbgPrint("NDIS: Failed to load driver because of\n");
+ DbgPrint("NDIS: insufficient map registers.\n");
+ DbgPrint("NDIS: AllocateAdapterChannel: %lx\n", Status);
+#endif
+
+ ExFreePool(Resources);
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ for (; i != 0; i--) {
+ IoFreeMapRegisters(
+ NewAdaptP->SystemAdapterObject,
+ NewAdaptP->MapRegisters[i-1].MapRegister,
+ MapRegistersPerChannel
+ );
+ }
+
+ KeLowerIrql(OldIrql);
+
+ ExFreePool(NewAdaptP->MapRegisters);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ TimeoutValue.QuadPart = Int32x32To64(2 * 1000, -10000);
+
+ //
+ // NdisAllocationExecutionRoutine will set this event
+ // when it has gotten FirstTranslationEntry.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &NewAdaptP->AllocationEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ NdisPrint2("NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus);
+ ExFreePool(Resources);
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ for (; i != 0; i--) {
+ IoFreeMapRegisters(
+ NewAdaptP->SystemAdapterObject,
+ NewAdaptP->MapRegisters[i-1].MapRegister,
+ MapRegistersPerChannel
+ );
+ }
+
+ KeLowerIrql(OldIrql);
+
+ ExFreePool(NewAdaptP->MapRegisters);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ return(NDIS_STATUS_RESOURCES);
+
+ }
+
+ KeResetEvent(
+ &NewAdaptP->AllocationEvent
+ );
+
+ }
+
+ }
+
+
+
+ NdisInitializeRef(&NewAdaptP->Ref);
+
+
+ if (!NdisQueueAdapterOnMac(NewAdaptP, TmpMacP)) {
+
+ //
+ // The MAC is closing, undo what we have done.
+ //
+
+ ExFreePool(Resources);
+ if (NewAdaptP->Master) {
+ ULONG MapRegistersPerChannel =
+ ((NewAdaptP->MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2;
+
+ for (i=0; i<NewAdaptP->PhysicalMapRegistersNeeded; i++) {
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ IoFreeMapRegisters(
+ NewAdaptP->SystemAdapterObject,
+ NewAdaptP->MapRegisters[i].MapRegister,
+ MapRegistersPerChannel
+ );
+
+ KeLowerIrql(OldIrql);
+ }
+
+ ExFreePool(NewAdaptP->MapRegisters);
+ }
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_CLOSING;
+ }
+
+ NdisMacReferencePackage();
+
+ //
+ // Add an extra reference because the wrapper is using the MAC
+ //
+ NdisReferenceAdapter(NewAdaptP);
+
+ *NdisAdapterHandle = (NDIS_HANDLE)NewAdaptP;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+NDIS_STATUS
+NdisDeregisterAdapter(
+ IN NDIS_HANDLE NdisAdapterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Deregisters an NDIS adapter.
+
+Arguments:
+
+ NdisAdapterHandle - The handle returned by NdisRegisterAdapter.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS.
+
+--*/
+
+{
+
+ //
+ // KillAdapter does all the work.
+ //
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisDeregisterAdapter\n");
+ NdisPrint2(" Deregistering Adapter %s\n",
+ ((PNDIS_ADAPTER_BLOCK)NdisAdapterHandle)->AdapterName.Buffer);
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(NdisAdapterHandle)) {
+ NdisPrint1("DeregisterAdapter: Null Handle\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(NdisAdapterHandle)) {
+ NdisPrint1("DeregisterAdapter: Handle not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+ NdisKillAdapter((PNDIS_ADAPTER_BLOCK)NdisAdapterHandle);
+
+ //
+ // Remove reference from wrapper
+ //
+ NdisDereferenceAdapter((PNDIS_ADAPTER_BLOCK)NdisAdapterHandle);
+
+ NdisMacDereferencePackage();
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeregisterAdapter\n");
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+VOID
+NdisRegisterAdapterShutdownHandler(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN PVOID ShutdownContext,
+ IN ADAPTER_SHUTDOWN_HANDLER ShutdownHandler
+ )
+
+/*++
+
+Routine Description:
+
+ Deregisters an NDIS adapter.
+
+Arguments:
+
+ NdisAdapterHandle - The handle returned by NdisRegisterAdapter.
+
+ ShutdownContext - Context to pass the the handler, when called.
+
+ ShutdownHandler - The Handler for the Adapter, to be called on shutdown.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS.
+
+--*/
+
+{
+ PNDIS_ADAPTER_BLOCK Adapter = (PNDIS_ADAPTER_BLOCK) NdisAdapterHandle;
+ PNDIS_WRAPPER_CONTEXT WrapperContext = Adapter->WrapperContext;
+
+ if (WrapperContext->ShutdownHandler == NULL) {
+
+ //
+ // Store information
+ //
+
+ WrapperContext->ShutdownHandler = ShutdownHandler;
+ WrapperContext->ShutdownContext = ShutdownContext;
+
+ //
+ // Register our shutdown handler for either a system shutdown
+ // notification or a bugcheck.
+ //
+
+ IoRegisterShutdownNotification(Adapter->DeviceObject);
+
+#if !defined(BUILD_FOR_3_1)
+ KeInitializeCallbackRecord(&WrapperContext->BugcheckCallbackRecord);
+
+ KeRegisterBugCheckCallback(
+ &WrapperContext->BugcheckCallbackRecord, // callback record.
+ (PVOID) NdisBugcheckHandler, // callback routine.
+ (PVOID) WrapperContext, // free form buffer.
+ sizeof(NDIS_WRAPPER_CONTEXT), // buffer size.
+ "Ndis mac" // component id.
+ );
+#endif
+
+ }
+}
+
+
+VOID
+NdisDeregisterAdapterShutdownHandler(
+ IN NDIS_HANDLE NdisAdapterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Deregisters an NDIS adapter.
+
+Arguments:
+
+ NdisAdapterHandle - The handle returned by NdisRegisterAdapter.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS.
+
+--*/
+
+{
+ PNDIS_ADAPTER_BLOCK Adapter = (PNDIS_ADAPTER_BLOCK) NdisAdapterHandle;
+ PNDIS_WRAPPER_CONTEXT WrapperContext = Adapter->WrapperContext;
+
+ if (WrapperContext->ShutdownHandler != NULL) {
+
+ //
+ // Clear information
+ //
+
+ WrapperContext->ShutdownHandler = NULL;
+
+ IoUnregisterShutdownNotification(Adapter->DeviceObject);
+
+#if !defined(BUILD_FOR_3_1)
+ KeDeregisterBugCheckCallback(&WrapperContext->BugcheckCallbackRecord);
+#endif
+
+ }
+}
+
+
+VOID
+NdisReleaseAdapterResources(
+ IN NDIS_HANDLE NdisAdapterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Informs the wrapper that the resources (such as interrupt,
+ I/O ports, etc.) have been shut down in some way such that
+ they will not interfere with other devices in the system.
+
+Arguments:
+
+ NdisAdapterHandle - The handle returned by NdisRegisterAdapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PCM_RESOURCE_LIST Resources;
+ BOOLEAN Conflict;
+ NTSTATUS NtStatus;
+ PNDIS_ADAPTER_BLOCK AdptrP = (PNDIS_ADAPTER_BLOCK)(NdisAdapterHandle);
+
+ Resources = AdptrP->Resources;
+
+ //
+ // Clear count
+ //
+
+ Resources->List[0].PartialResourceList.Count = 0;
+
+ //
+ // Make the call
+ //
+
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ AdptrP->MacHandle->NdisMacInfo->NdisWrapperDriver,
+ NULL,
+ 0,
+ AdptrP->DeviceObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ TRUE,
+ &Conflict
+ );
+
+
+ return;
+
+}
+
+
+VOID
+NdisWriteErrorLogEntry(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN NDIS_ERROR_CODE ErrorCode,
+ IN ULONG NumberOfErrorValues,
+ ...
+ )
+/*++
+
+Routine Description:
+
+ This function allocates an I/O error log record, fills it in and writes it
+ to the I/O error log.
+
+
+Arguments:
+
+ NdisAdapterHandle - points to the adapter block.
+
+ ErrorCode - Ndis code mapped to a string.
+
+ NumberOfErrorValues - number of ULONGS to store for the error.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+
+ va_list ArgumentPointer;
+
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ PNDIS_ADAPTER_BLOCK AdapterBlock = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle;
+ ULONG i;
+ ULONG StringSize;
+ PWCH baseFileName;
+
+ if (AdapterBlock == NULL) {
+
+ return;
+
+ }
+
+ if (AdapterBlock->DeviceObject != NULL) {
+ baseFileName = AdapterBlock->AdapterName.Buffer;
+ } else {
+ baseFileName = Miniport->MiniportName.Buffer;
+ }
+
+ //
+ // Parse out the path name, leaving only the device name.
+ //
+
+ for ( i = 0;
+ i < ((AdapterBlock->DeviceObject != NULL) ?
+ AdapterBlock->AdapterName.Length :
+ Miniport->MiniportName.Length) / sizeof(WCHAR); i++ ) {
+
+ //
+ // If s points to a directory separator, set baseFileName to
+ // the character after the separator.
+ //
+
+ if ( ((AdapterBlock->DeviceObject != NULL) ?
+ AdapterBlock->AdapterName.Buffer[i] :
+ Miniport->MiniportName.Buffer[i]) == OBJ_NAME_PATH_SEPARATOR ) {
+ baseFileName = ((AdapterBlock->DeviceObject != NULL) ?
+ &(AdapterBlock->AdapterName.Buffer[++i]) :
+ &(Miniport->MiniportName.Buffer[++i]));
+ }
+
+ }
+
+ StringSize = ((AdapterBlock->DeviceObject != NULL) ?
+ AdapterBlock->AdapterName.MaximumLength :
+ Miniport->MiniportName.MaximumLength) -
+ (((ULONG)baseFileName) -
+ ((AdapterBlock->DeviceObject != NULL) ?
+ ((ULONG)AdapterBlock->AdapterName.Buffer) :
+ ((ULONG)Miniport->MiniportName.Buffer))) ;
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ ((AdapterBlock->DeviceObject != NULL) ?
+ AdapterBlock->DeviceObject :
+ Miniport->DeviceObject),
+ (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
+ NumberOfErrorValues * sizeof(ULONG) +
+ StringSize)
+ );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->ErrorCode = ErrorCode;
+
+ //
+ // store the time
+ //
+
+ errorLogEntry->MajorFunctionCode = 0;
+ errorLogEntry->RetryCount = 0;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = 0;
+ errorLogEntry->SequenceNumber = 0;
+ errorLogEntry->IoControlCode = 0;
+
+ //
+ // Store Data
+ //
+
+ errorLogEntry->DumpDataSize = (USHORT)(NumberOfErrorValues * sizeof(ULONG));
+
+ va_start(ArgumentPointer, NumberOfErrorValues);
+
+ for (i = 0; i < NumberOfErrorValues; i++) {
+
+ errorLogEntry->DumpData[i] = va_arg(ArgumentPointer, ULONG);
+
+ }
+
+ va_end(ArgumentPointer);
+
+
+ //
+ // Set string information
+ //
+
+ if (StringSize != 0) {
+
+ errorLogEntry->NumberOfStrings = 1;
+ errorLogEntry->StringOffset =
+ sizeof(IO_ERROR_LOG_PACKET) +
+ NumberOfErrorValues * sizeof(ULONG);
+
+
+ RtlCopyMemory (
+ ((PUCHAR)errorLogEntry) +
+ (sizeof(IO_ERROR_LOG_PACKET) +
+ NumberOfErrorValues * sizeof(ULONG)),
+ (PVOID)baseFileName,
+ StringSize
+ );
+
+ } else {
+
+ errorLogEntry->NumberOfStrings = 0;
+
+ }
+
+ //
+ // write it out
+ //
+
+ IoWriteErrorLogEntry(errorLogEntry);
+ }
+
+}
+
+
+VOID
+NdisCompleteOpenAdapter(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS Status,
+ IN NDIS_STATUS OpenErrorStatus
+ )
+
+{
+ PNDIS_OPEN_BLOCK OpenP = (PNDIS_OPEN_BLOCK)NdisBindingContext;
+ PNDIS_OPEN_BLOCK TmpOpen;
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisCompleteOpenAdapter\n");
+ }
+ IF_ERROR_CHK {
+ if (!DbgIsNonPaged(NdisBindingContext)) {
+ NdisPrint1("NdisCompleteOpenAdapter: Handle not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(NdisBindingContext)) {
+ NdisPrint1("NdisCompleteOpenAdapter: Binding Context not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+ if (!NdisFinishOpen(OpenP)) {
+ Status = NDIS_STATUS_CLOSING;
+ }
+ }
+
+ (OpenP->ProtocolHandle->ProtocolCharacteristics.OpenAdapterCompleteHandler) (
+ OpenP->ProtocolBindingContext,
+ Status,
+ OpenErrorStatus
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Something went wrong, clean up and exit.
+ //
+
+ ACQUIRE_SPIN_LOCK(&GlobalOpenListLock);
+
+ if (GlobalOpenList == OpenP) {
+
+ GlobalOpenList = OpenP->NextGlobalOpen;
+
+ } else {
+
+ TmpOpen = GlobalOpenList;
+
+ while (TmpOpen->NextGlobalOpen != OpenP) {
+
+ TmpOpen = TmpOpen->NextGlobalOpen;
+
+ }
+
+ TmpOpen->NextGlobalOpen = OpenP->NextGlobalOpen;
+
+ }
+
+ RELEASE_SPIN_LOCK(&GlobalOpenListLock);
+
+ ObDereferenceObject((PVOID)OpenP->FileObject);
+ NdisDereferenceAdapter(OpenP->AdapterHandle);
+ NdisDereferenceProtocol(OpenP->ProtocolHandle);
+ ExFreePool((PVOID)OpenP);
+
+ }
+
+}
+
+
+VOID
+NdisCompleteCloseAdapter(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS Status
+ )
+
+{
+ PNDIS_OPEN_BLOCK Open = (PNDIS_OPEN_BLOCK) NdisBindingContext;
+ PNDIS_OPEN_BLOCK TmpOpen;
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisCompleteCloseAdapter\n");
+ }
+ IF_ERROR_CHK {
+ if (!DbgIsNonPaged(NdisBindingContext)) {
+ NdisPrint1("NdisCompleteCloseAdapter: Handle not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(NdisBindingContext)) {
+ NdisPrint1("NdisCompleteCloseAdapter: Binding Context not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.CloseAdapterCompleteHandler) (
+ Open->ProtocolBindingContext,
+ Status
+ );
+
+ NdisDeQueueOpenOnAdapter(Open, Open->AdapterHandle);
+ NdisDeQueueOpenOnProtocol(Open, Open->ProtocolHandle);
+
+ NdisDereferenceProtocol(Open->ProtocolHandle);
+ NdisDereferenceAdapter(Open->AdapterHandle);
+ NdisFreeSpinLock(&Open->SpinLock);
+
+ //
+ // This sends an IRP_MJ_CLOSE IRP.
+ //
+
+ ObDereferenceObject((PVOID)(Open->FileObject));
+
+ //
+ // Remove from global list
+ //
+ ACQUIRE_SPIN_LOCK(&GlobalOpenListLock);
+
+ if (GlobalOpenList == Open) {
+
+ GlobalOpenList = Open->NextGlobalOpen;
+
+ } else {
+
+ TmpOpen = GlobalOpenList;
+
+ while (TmpOpen->NextGlobalOpen != Open) {
+
+ TmpOpen = TmpOpen->NextGlobalOpen;
+
+ }
+
+ TmpOpen->NextGlobalOpen = Open->NextGlobalOpen;
+
+ }
+
+ RELEASE_SPIN_LOCK(&GlobalOpenListLock);
+
+ ExFreePool((PVOID)(NdisBindingContext));
+}
+
+
+
+
+BOOLEAN
+NdisReferenceRef(
+ IN PREFERENCE RefP
+ )
+
+/*++
+
+Routine Description:
+
+ Adds a reference to an object.
+
+Arguments:
+
+ RefP - A pointer to the REFERENCE portion of the object.
+
+Return Value:
+
+ TRUE if the reference was added.
+ FALSE if the object was closing.
+
+--*/
+
+{
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisReferenceRef\n");
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(RefP)) {
+ NdisPrint1("NdisReferenceRef: NULL Reference address\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(RefP)) {
+ NdisPrint1("NdisReferenceRef: Reference not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+ ACQUIRE_SPIN_LOCK(&RefP->SpinLock);
+
+ if (RefP->Closing) {
+ RELEASE_SPIN_LOCK(&RefP->SpinLock);
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisReferenceRef\n");
+ return FALSE;
+ }
+
+ ++(RefP->ReferenceCount);
+
+ RELEASE_SPIN_LOCK(&RefP->SpinLock);
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisReferenceRef\n");
+ return TRUE;
+}
+
+BOOLEAN
+NdisDereferenceRef(
+ PREFERENCE RefP
+ )
+
+/*++
+
+Routine Description:
+
+ Removes a reference to an object.
+
+Arguments:
+
+ RefP - A pointer to the REFERENCE portion of the object.
+
+Return Value:
+
+ TRUE if the reference count is now 0.
+ FALSE otherwise.
+
+--*/
+
+{
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisDereferenceRef\n");
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(RefP)) {
+ NdisPrint1("NdisDereferenceRef: NULL Reference address\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(RefP)) {
+ NdisPrint1("NdisDereferenceRef: Reference not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ ACQUIRE_SPIN_LOCK(&RefP->SpinLock);
+ --(RefP->ReferenceCount);
+ if (RefP->ReferenceCount == 0) {
+ RELEASE_SPIN_LOCK(&RefP->SpinLock);
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisDereferenceRef\n");
+ return TRUE;
+ }
+
+ RELEASE_SPIN_LOCK(&RefP->SpinLock);
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisDereferenceRef\n");
+ return FALSE;
+}
+
+
+VOID
+NdisInitializeRef(
+ PREFERENCE RefP
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize a reference count structure.
+
+Arguments:
+
+ RefP - The structure to be initialized.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisInitializeRef\n");
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(RefP)) {
+ NdisPrint1("NdisInitializeRef: NULL Reference address\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(RefP)) {
+ NdisPrint1("NdisInitializeRef: Reference not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ RefP->Closing = FALSE;
+ RefP->ReferenceCount = 1;
+ NdisAllocateSpinLock(&RefP->SpinLock);
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisInitializeRef\n");
+}
+
+BOOLEAN
+NdisCloseRef(
+ PREFERENCE RefP
+ )
+
+/*++
+
+Routine Description:
+
+ Closes a reference count structure.
+
+Arguments:
+
+ RefP - The structure to be closed.
+
+Return Value:
+
+ FALSE if it was already closing.
+ TRUE otherwise.
+
+--*/
+
+{
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisCloseRef\n");
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(RefP)) {
+ NdisPrint1("NdisCloseRef: NULL Reference address\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(RefP)) {
+ NdisPrint1("NdisCloseRef: Reference not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+ ACQUIRE_SPIN_LOCK(&RefP->SpinLock);
+
+ if (RefP->Closing) {
+ RELEASE_SPIN_LOCK(&RefP->SpinLock);
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisCloseRef\n");
+ return FALSE;
+ }
+
+ RefP->Closing = TRUE;
+
+ RELEASE_SPIN_LOCK(&RefP->SpinLock);
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisCloseRef\n");
+ return TRUE;
+}
+
+
+
+BOOLEAN
+NdisQueueOpenOnProtocol(
+ IN PNDIS_OPEN_BLOCK OpenP,
+ IN PNDIS_PROTOCOL_BLOCK ProtP
+ )
+
+/*++
+
+Routine Description:
+
+ Attaches an open block to the list of opens for a protocol.
+
+Arguments:
+
+ OpenP - The open block to be queued.
+ ProtP - The protocol block to queue it to.
+
+Return Value:
+
+ TRUE if the operation is successful.
+ FALSE if the protocol is closing.
+
+--*/
+
+{
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisQueueOpenOnProtocol\n");
+ NdisPrint2(" Protocol: %wZ\n",&ProtP->ProtocolCharacteristics.Name);
+ }
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(OpenP)) {
+ NdisPrint1("NdisQueueOpenOnProtocol: Null Open Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(OpenP)) {
+ NdisPrint1("NdisQueueOpenOnProtocol: Open Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+
+ if (DbgIsNull(ProtP)) {
+ NdisPrint1("NdisQueueOpenOnProtocol: Null Protocol Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(ProtP)) {
+ NdisPrint1("NdisQueueOpenOnProtocol: Protocol Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+
+ }
+ ACQUIRE_SPIN_LOCK(&ProtP->Ref.SpinLock);
+
+ //
+ // Make sure the protocol is not closing.
+ //
+
+ if (ProtP->Ref.Closing) {
+ RELEASE_SPIN_LOCK(&ProtP->Ref.SpinLock);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisQueueOpenOnProtocol\n");
+ return FALSE;
+ }
+
+
+ //
+ // Attach this open at the head of the queue.
+ //
+
+ OpenP->ProtocolNextOpen = ProtP->OpenQueue;
+ ProtP->OpenQueue = OpenP;
+
+
+ RELEASE_SPIN_LOCK(&ProtP->Ref.SpinLock);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisQueueOpenOnProtocol\n");
+ return TRUE;
+}
+
+VOID
+NdisDeQueueOpenOnProtocol(
+ IN PNDIS_OPEN_BLOCK OpenP,
+ IN PNDIS_PROTOCOL_BLOCK ProtP
+ )
+
+/*++
+
+Routine Description:
+
+ Detaches an open block from the list of opens for a protocol.
+
+Arguments:
+
+ OpenP - The open block to be dequeued.
+ ProtP - The protocol block to dequeue it from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisDeQueueOpenOnProtocol\n");
+ NdisPrint2(" Protocol: %wZ\n",&ProtP->ProtocolCharacteristics.Name);
+ }
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(OpenP)) {
+ NdisPrint1("NdisDeQueueOpenOnProtocol: Null Open Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(OpenP)) {
+ NdisPrint1("NdisDeQueueOpenOnProtocol: Open Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+
+ if (DbgIsNull(ProtP)) {
+ NdisPrint1("NdisDeQueueOpenOnProtocol: Null Protocol Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(ProtP)) {
+ NdisPrint1("NdisDeQueueOpenOnProtocol: Protocol Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+
+ }
+
+ ACQUIRE_SPIN_LOCK(&ProtP->Ref.SpinLock);
+
+ //
+ // Find the open on the queue, and remove it.
+ //
+
+ if (ProtP->OpenQueue == OpenP) {
+ ProtP->OpenQueue = OpenP->ProtocolNextOpen;
+ } else {
+ PNDIS_OPEN_BLOCK PP = ProtP->OpenQueue;
+
+ while (PP->ProtocolNextOpen != OpenP) {
+ PP = PP->ProtocolNextOpen;
+ }
+
+ PP->ProtocolNextOpen = PP->ProtocolNextOpen->ProtocolNextOpen;
+ }
+
+ RELEASE_SPIN_LOCK(&ProtP->Ref.SpinLock);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeQueueOpenOnProtocol\n");
+}
+
+VOID
+NdisDeQueueOpenOnMiniport(
+ IN PNDIS_M_OPEN_BLOCK OpenP,
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Detaches an open block from the list of opens for a Miniport.
+
+Arguments:
+
+ OpenP - The open block to be dequeued.
+ Miniport - The Miniport block to dequeue it from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ACQUIRE_SPIN_LOCK(&Miniport->Ref.SpinLock);
+
+ OpenP->References--;
+
+ //
+ // Find the open on the queue, and remove it.
+ //
+
+ if (Miniport->OpenQueue == OpenP) {
+ Miniport->OpenQueue = OpenP->MiniportNextOpen;
+ } else {
+ PNDIS_M_OPEN_BLOCK PP = Miniport->OpenQueue;
+
+ while (PP->MiniportNextOpen != OpenP) {
+ PP = PP->MiniportNextOpen;
+ }
+
+ PP->MiniportNextOpen = PP->MiniportNextOpen->MiniportNextOpen;
+ }
+
+ RELEASE_SPIN_LOCK(&Miniport->Ref.SpinLock);
+}
+
+
+
+BOOLEAN
+NdisFinishOpen(
+ IN PNDIS_OPEN_BLOCK OpenP
+ )
+
+/*++
+
+Routine Description:
+
+ Performs the final functions of NdisOpenAdapter. Called when
+ MacOpenAdapter is done.
+
+Arguments:
+
+ OpenP - The open block to finish up.
+
+Return Value:
+
+ FALSE if the adapter or the protocol is closing.
+ TRUE otherwise.
+
+--*/
+
+{
+ //
+ // Add us to the adapter's queue of opens.
+ //
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisFinishOpen\n");
+ NdisPrint3(" Protocol %wZ is being bound to Adapter %wZ\n",
+ &(OpenP->ProtocolHandle)->ProtocolCharacteristics.Name,
+ &OpenP->AdapterHandle->AdapterName);
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(OpenP)) {
+ NdisPrint1("NdisFinishOpen: Null Open Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(OpenP)) {
+ NdisPrint1("NdisFinishOpen: Open Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ if (!NdisQueueOpenOnAdapter(OpenP, OpenP->AdapterHandle)) {
+
+ //
+ // The adapter is closing.
+ //
+ // Call MacCloseAdapter(), don't worry about it completing.
+ //
+
+ (OpenP->MacHandle->MacCharacteristics.CloseAdapterHandler) (
+ OpenP->MacBindingHandle);
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisFinishOpen\n");
+ return FALSE;
+ }
+
+
+ //
+ // Add us to the protocol's queue of opens.
+ //
+
+ if (!NdisQueueOpenOnProtocol(OpenP, OpenP->ProtocolHandle)) {
+
+ //
+ // The protocol is closing.
+ //
+ // Call MacCloseAdapter(), don't worry about it completing.
+ //
+
+ (OpenP->MacHandle->MacCharacteristics.CloseAdapterHandler) (
+ OpenP->MacBindingHandle);
+
+ //
+ // Undo the queueing we just did.
+ //
+
+ NdisDeQueueOpenOnAdapter(OpenP, OpenP->AdapterHandle);
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisFinishOpen\n");
+ return FALSE;
+ }
+
+
+ //
+ // Both queueings succeeded.
+ //
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisFinishOpen\n");
+ return TRUE;
+}
+
+NTSTATUS
+NdisCreateIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ The handle for IRP_MJ_CREATE IRPs.
+
+Arguments:
+
+ DeviceObject - The adapter's device object.
+ Irp - The IRP.
+
+Return Value:
+
+ STATUS_SUCCESS if it should be.
+
+--*/
+
+{
+
+ PIO_STACK_LOCATION IrpSp;
+ PFILE_FULL_EA_INFORMATION IrpEaInfo;
+ PNDIS_USER_OPEN_CONTEXT OpenContext;
+ NTSTATUS Status = STATUS_SUCCESS;
+ PNDIS_ADAPTER_BLOCK AdapterBlock;
+ BOOLEAN IsAMiniport;
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisCreateIrpHandler\n");
+ IF_ERROR_CHK {
+ if (DbgIsNull(Irp)) {
+ NdisPrint1(": Null Irp\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(Irp)) {
+ NdisPrint1(": Irp not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ AdapterBlock = (PNDIS_ADAPTER_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1);
+ IsAMiniport = (AdapterBlock->DeviceObject == NULL);
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+ IrpEaInfo = (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
+
+ if (IrpEaInfo == NULL) {
+
+ //
+ // This is a user-mode open, do whatever.
+ //
+
+ OpenContext = (PNDIS_USER_OPEN_CONTEXT)
+ ExAllocatePoolWithTag(NonPagedPool, sizeof(NDIS_USER_OPEN_CONTEXT), ' DN');
+
+ if (OpenContext == NULL) {
+
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ } else {
+
+ OpenContext->DeviceObject = DeviceObject;
+
+ OpenContext->AdapterBlock = AdapterBlock;
+ OpenContext->OidCount = 0;
+ OpenContext->OidArray = NULL;
+
+ IrpSp->FileObject->FsContext = (PVOID)OpenContext;
+ IrpSp->FileObject->FsContext2 = (PVOID)NDIS_OPEN_QUERY_STATISTICS;
+
+ if (IsAMiniport) {
+ Status = NdisMQueryOidList((PNDIS_M_USER_OPEN_CONTEXT)OpenContext, Irp);
+ } else {
+ Status = NdisQueryOidList(OpenContext, Irp);
+ }
+
+ if (Status != STATUS_SUCCESS) {
+ ExFreePool (OpenContext);
+ }
+
+ }
+
+ } else {
+
+ //
+ // This is an internal open, verify the EA.
+ //
+
+ if ((IrpEaInfo->EaNameLength != sizeof(NdisInternalEaName)) ||
+ (RtlCompareMemory(IrpEaInfo->EaName, NdisInternalEaName, sizeof(NdisInternalEaName)) !=
+ sizeof(NdisInternalEaName)) ||
+ (IrpEaInfo->EaValueLength != sizeof(NdisInternalEaValue)) ||
+ (RtlCompareMemory(&IrpEaInfo->EaName[IrpEaInfo->EaNameLength+1],
+ NdisInternalEaValue, sizeof(NdisInternalEaValue)) !=
+ sizeof(NdisInternalEaValue))) {
+
+ //
+ // Something is wrong, reject it.
+ //
+
+ Status = STATUS_UNSUCCESSFUL;
+
+ } else {
+
+ //
+ // It checks out, just return success and everything
+ // else is done directly using the device object.
+ //
+
+ IrpSp->FileObject->FsContext = NULL;
+ IrpSp->FileObject->FsContext2 = (PVOID)NDIS_OPEN_INTERNAL;
+
+ }
+ }
+
+ Irp->IoStatus.Status = Status;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisCreateIrplHandler\n");
+ return Status;
+}
+
+
+
+NTSTATUS
+NdisQueryOidList(
+ PNDIS_USER_OPEN_CONTEXT OpenContext,
+ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will take care of querying the complete OID
+ list for the MAC and filling in OpenContext->OidArray
+ with the ones that are statistics. It blocks when the
+ MAC pends and so is synchronous.
+
+Arguments:
+
+ OpenContext - The open context.
+ Irp = The IRP that the open was done on (used at completion
+ to distinguish the request).
+
+Return Value:
+
+ STATUS_SUCCESS if it should be.
+
+--*/
+
+{
+
+ NDIS_QUERY_OPEN_REQUEST OpenRequest;
+ NDIS_STATUS NdisStatus;
+ PNDIS_OID TmpBuffer;
+ ULONG TmpBufferLength;
+ UINT i, j;
+
+ //
+ // First query the OID list with no buffer, to find out
+ // how big it should be.
+ //
+
+ KeInitializeEvent(
+ &OpenRequest.Event,
+ NotificationEvent,
+ FALSE
+ );
+
+ OpenRequest.Irp = Irp;
+
+ OpenRequest.Request.RequestType = NdisRequestQueryStatistics;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_SUPPORTED_LIST;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBuffer = NULL;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBufferLength = 0;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded = 0;
+
+ NdisStatus =
+ (OpenContext->AdapterBlock->MacHandle->MacCharacteristics.QueryGlobalStatisticsHandler) (
+ OpenContext->AdapterBlock->MacAdapterContext,
+ &OpenRequest.Request);
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &OpenRequest.Event,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ NdisStatus = OpenRequest.NdisStatus;
+
+ } else if ((NdisStatus != NDIS_STATUS_INVALID_LENGTH) &&
+ (NdisStatus != NDIS_STATUS_BUFFER_TOO_SHORT)) {
+
+ return(NdisStatus);
+
+ }
+
+ //
+ // Now we know how much is needed, allocate temp storage...
+ //
+
+ TmpBufferLength = OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded;
+ TmpBuffer = ExAllocatePoolWithTag(NonPagedPool, TmpBufferLength, ' DN');
+
+ if (TmpBuffer == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // ...and query the real list.
+ //
+
+ KeResetEvent(
+ &OpenRequest.Event
+ );
+
+
+ OpenRequest.Request.RequestType = NdisRequestQueryStatistics;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_SUPPORTED_LIST;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBuffer = TmpBuffer;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBufferLength = TmpBufferLength;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded = 0;
+
+ NdisStatus =
+ (OpenContext->AdapterBlock->MacHandle->MacCharacteristics.QueryGlobalStatisticsHandler) (
+ OpenContext->AdapterBlock->MacAdapterContext,
+ &OpenRequest.Request);
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &OpenRequest.Event,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ NdisStatus = OpenRequest.NdisStatus;
+
+ }
+
+ ASSERT (NdisStatus == NDIS_STATUS_SUCCESS);
+
+
+ //
+ // Now go through the buffer, counting the statistics OIDs.
+ //
+
+ for (i=0; i<TmpBufferLength/sizeof(NDIS_OID); i++) {
+ if ((TmpBuffer[i] & 0x00ff0000) == 0x00020000) {
+ ++OpenContext->OidCount;
+ }
+ }
+
+ //
+ // Now allocate storage for the real OID array.
+ //
+
+ OpenContext->OidArray = ExAllocatePoolWithTag (NonPagedPool, OpenContext->OidCount * sizeof(NDIS_OID), ' DN');
+
+ if (OpenContext->OidArray == NULL) {
+ ExFreePool (TmpBuffer);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Now go through the buffer, copying the statistics OIDs.
+ //
+
+ j = 0;
+ for (i=0; i<TmpBufferLength/sizeof(NDIS_OID); i++) {
+
+ if ((TmpBuffer[i] & 0x00ff0000) == 0x00020000) {
+ OpenContext->OidArray[j] = TmpBuffer[i];
+ ++j;
+ }
+ }
+
+ ASSERT (j == OpenContext->OidCount);
+
+ ExFreePool (TmpBuffer);
+ return STATUS_SUCCESS;
+}
+
+#define NDIS_STATISTICS_HEADER_SIZE FIELD_OFFSET(NDIS_STATISTICS_VALUE,Data[0])
+
+
+
+NTSTATUS
+NdisDeviceControlIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ The handle for IRP_MJ_DEVICE_CONTROL IRPs.
+
+Arguments:
+
+ DeviceObject - The adapter's device object.
+ Irp - The IRP.
+
+Return Value:
+
+ STATUS_SUCCESS if it should be.
+
+--*/
+
+{
+
+ PIO_STACK_LOCATION IrpSp;
+ PNDIS_USER_OPEN_CONTEXT OpenContext;
+ PNDIS_QUERY_GLOBAL_REQUEST GlobalRequest;
+ PNDIS_QUERY_ALL_REQUEST AllRequest;
+ NDIS_STATUS NdisStatus;
+ UINT CurrentOid;
+ ULONG BytesWritten, BytesWrittenThisOid;
+ PUCHAR Buffer;
+ ULONG BufferLength;
+ NTSTATUS Status = STATUS_SUCCESS;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ BOOLEAN LocalLock;
+ KIRQL OldIrql;
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisDeviceControlIrpHandler\n");
+ IF_ERROR_CHK {
+ if (DbgIsNull(Irp)) {
+ NdisPrint1(": Null Irp\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(Irp)) {
+ NdisPrint1(": Irp not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ IoMarkIrpPending (Irp);
+ Irp->IoStatus.Status = STATUS_PENDING;
+ Irp->IoStatus.Information = 0;
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ if (IrpSp->FileObject->FsContext2 != (PVOID)NDIS_OPEN_QUERY_STATISTICS) {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
+
+ case IOCTL_NDIS_QUERY_GLOBAL_STATS:
+
+ //
+ // Allocate a request.
+ //
+
+ OpenContext = IrpSp->FileObject->FsContext;
+ GlobalRequest = (PNDIS_QUERY_GLOBAL_REQUEST)
+ ExAllocatePoolWithTag(NonPagedPool, sizeof(NDIS_QUERY_GLOBAL_REQUEST), ' DN');
+
+ if (GlobalRequest == NULL) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ GlobalRequest->Irp = Irp;
+
+ if (OpenContext->AdapterBlock->DeviceObject == NULL) {
+
+ Miniport = (PNDIS_MINIPORT_BLOCK)(OpenContext->AdapterBlock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ } else {
+
+ Miniport = NULL;
+
+ }
+
+ //
+ // Fill in the NDIS request.
+ //
+
+ GlobalRequest->Request.RequestType = NdisRequestQueryStatistics;
+ GlobalRequest->Request.DATA.QUERY_INFORMATION.Oid =
+ *((PULONG)(Irp->AssociatedIrp.SystemBuffer));
+ GlobalRequest->Request.DATA.QUERY_INFORMATION.InformationBuffer =
+ MmGetSystemAddressForMdl (Irp->MdlAddress);
+ GlobalRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength =
+ MmGetMdlByteCount (Irp->MdlAddress);
+ GlobalRequest->Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
+ GlobalRequest->Request.DATA.QUERY_INFORMATION.BytesNeeded = 0;
+
+
+ if (Miniport != NULL) {
+ PNDIS_REQUEST_RESERVED Reserved;
+
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(&(GlobalRequest->Request));
+ Reserved->Next = NULL;
+ Miniport->LastPendingRequest = &(GlobalRequest->Request);
+
+ if (Miniport->FirstPendingRequest == NULL) {
+
+ Miniport->FirstPendingRequest = &(GlobalRequest->Request);
+
+ } else {
+
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Miniport->LastPendingRequest)->Next =
+ &(GlobalRequest->Request);
+
+ }
+
+ if (Miniport->MiniportRequest == NULL) {
+
+ Miniport->RunDoRequests = TRUE;
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+
+ }
+
+ //
+ // If we were able to grab the local lock then we can do some
+ // deferred processing now.
+ //
+
+ if ( LocalLock ) {
+ if (!Miniport->ProcessingDeferred) {
+ MiniportProcessDeferred(Miniport);
+ }
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ KeLowerIrql(OldIrql);
+
+ } else {
+
+ //
+ // Pass the request to the MAC.
+ //
+
+ NdisStatus =
+ (OpenContext->AdapterBlock->MacHandle->MacCharacteristics.QueryGlobalStatisticsHandler) (
+ OpenContext->AdapterBlock->MacAdapterContext,
+ &GlobalRequest->Request);
+
+ //
+ // NdisCompleteQueryStatistics handles the completion.
+ //
+
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+ NdisCompleteQueryStatistics(
+ (NDIS_HANDLE)OpenContext->AdapterBlock,
+ &GlobalRequest->Request,
+ NdisStatus);
+ }
+
+ }
+
+ Status = STATUS_PENDING;
+
+ break;
+
+ case IOCTL_NDIS_QUERY_ALL_STATS:
+
+
+ //
+ // Allocate a request.
+ //
+
+ OpenContext = IrpSp->FileObject->FsContext;
+ AllRequest = (PNDIS_QUERY_ALL_REQUEST)
+ ExAllocatePoolWithTag(NonPagedPool, sizeof(NDIS_QUERY_ALL_REQUEST), ' DN');
+
+ if (AllRequest == NULL) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ if (OpenContext->AdapterBlock->DeviceObject == NULL) {
+
+ Miniport = (PNDIS_MINIPORT_BLOCK)(OpenContext->AdapterBlock);
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ } else {
+
+ Miniport = NULL;
+
+ }
+
+ AllRequest->Irp = Irp;
+
+ Buffer = (PUCHAR)MmGetSystemAddressForMdl (Irp->MdlAddress);
+ BufferLength = MmGetMdlByteCount (Irp->MdlAddress);
+ BytesWritten = 0;
+
+ KeInitializeEvent(
+ &AllRequest->Event,
+ NotificationEvent,
+ FALSE
+ );
+
+ NdisStatus = NDIS_STATUS_SUCCESS;
+
+ for (CurrentOid = 0; CurrentOid<OpenContext->OidCount; CurrentOid++) {
+
+ //
+ // We need room for an NDIS_STATISTICS_VALUE (OID,
+ // Length, Data).
+ //
+
+ if (BufferLength < (ULONG)NDIS_STATISTICS_HEADER_SIZE) {
+ NdisStatus = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ AllRequest->Request.RequestType = NdisRequestQueryStatistics;
+
+ AllRequest->Request.DATA.QUERY_INFORMATION.Oid =
+ OpenContext->OidArray[CurrentOid];
+ AllRequest->Request.DATA.QUERY_INFORMATION.InformationBuffer =
+ Buffer + NDIS_STATISTICS_HEADER_SIZE;
+ AllRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength =
+ BufferLength - NDIS_STATISTICS_HEADER_SIZE;
+
+ AllRequest->Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
+ AllRequest->Request.DATA.QUERY_INFORMATION.BytesNeeded = 0;
+
+ if (Miniport != NULL) {
+
+ PNDIS_REQUEST_RESERVED Reserved;
+
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(&(AllRequest->Request));
+ Reserved->Next = NULL;
+ Miniport->LastPendingRequest = &(AllRequest->Request);
+
+ if (Miniport->FirstPendingRequest == NULL) {
+
+ Miniport->FirstPendingRequest = &(AllRequest->Request);
+
+ } else {
+
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Miniport->LastPendingRequest)->Next =
+ &(AllRequest->Request);
+
+ }
+
+ if (Miniport->MiniportRequest == NULL) {
+
+ Miniport->RunDoRequests = TRUE;
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+ }
+
+ //
+ // If we were able to grab the local lock then we can do some
+ // deferred processing now.
+ //
+
+ if ( LocalLock ) {
+ if (!Miniport->ProcessingDeferred) {
+ MiniportProcessDeferred(Miniport);
+ }
+ }
+
+ NdisStatus = NDIS_STATUS_PENDING;
+
+ } else {
+
+ NdisStatus =
+ (OpenContext->AdapterBlock->MacHandle->MacCharacteristics.QueryGlobalStatisticsHandler) (
+ OpenContext->AdapterBlock->MacAdapterContext,
+ &AllRequest->Request);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ if (Miniport != NULL) {
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ KeLowerIrql(OldIrql);
+ }
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &AllRequest->Event,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ NdisStatus = AllRequest->NdisStatus;
+
+ if (Miniport != NULL) {
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ LOCK_MINIPORT(Miniport, LocalLock);
+ }
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ PNDIS_STATISTICS_VALUE StatisticsValue =
+ (PNDIS_STATISTICS_VALUE)Buffer;
+
+ //
+ // Create the equivalent of an NDIS_STATISTICS_VALUE
+ // element for this OID value (the data itself was
+ // already written in the right place.
+ //
+
+ StatisticsValue->Oid = OpenContext->OidArray[CurrentOid];
+ StatisticsValue->DataLength = AllRequest->Request.DATA.QUERY_INFORMATION.BytesWritten;
+
+ //
+ // Advance our pointers.
+ //
+
+ BytesWrittenThisOid =
+ AllRequest->Request.DATA.QUERY_INFORMATION.BytesWritten +
+ NDIS_STATISTICS_HEADER_SIZE;
+ Buffer += BytesWrittenThisOid;
+ BufferLength -= BytesWrittenThisOid;
+ BytesWritten += BytesWrittenThisOid;
+
+ } else {
+
+ break;
+
+ }
+
+ KeResetEvent(
+ &AllRequest->Event
+ );
+
+ }
+
+ if (Miniport != NULL) {
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ KeLowerIrql(OldIrql);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_INVALID_LENGTH) {
+ Status = STATUS_BUFFER_OVERFLOW;
+ } else if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ Status = STATUS_UNSUCCESSFUL;
+ }
+
+ Irp->IoStatus.Information = BytesWritten;
+ Irp->IoStatus.Status = Status;
+
+ break;
+
+ default:
+
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+
+ }
+
+ if (Status != STATUS_PENDING) {
+ IrpSp->Control &= ~SL_PENDING_RETURNED;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ }
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisCreateIrplHandler\n");
+ return Status;
+}
+
+
+
+VOID
+NdisCompleteQueryStatistics(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS Status
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by MACs when they have completed
+ processing of a MacQueryGlobalStatistics call.
+
+Arguments:
+
+ NdisAdapterHandle - The NDIS adapter context.
+ NdisRequest - The request that has been completed.
+ Status - The status of the request.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNDIS_ADAPTER_BLOCK AdapterBlock = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle;
+ PNDIS_QUERY_GLOBAL_REQUEST GlobalRequest;
+ PNDIS_QUERY_ALL_REQUEST AllRequest;
+ PNDIS_QUERY_OPEN_REQUEST OpenRequest;
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+
+ //
+ // Rely on the fact that all our request structures start with
+ // the same fields: Irp followed by the NdisRequest.
+ //
+
+ GlobalRequest = CONTAINING_RECORD (NdisRequest, NDIS_QUERY_GLOBAL_REQUEST, Request);
+ Irp = GlobalRequest->Irp;
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ switch (IrpSp->MajorFunction) {
+
+ case IRP_MJ_CREATE:
+
+ //
+ // This request is one of the ones made during an open,
+ // while we are trying to determine the OID list. We
+ // set the event we are waiting for, the open code
+ // takes care of the rest.
+ //
+
+ OpenRequest = (PNDIS_QUERY_OPEN_REQUEST)GlobalRequest;
+
+ OpenRequest->NdisStatus = Status;
+ KeSetEvent(
+ &OpenRequest->Event,
+ 0L,
+ FALSE);
+
+ break;
+
+ case IRP_MJ_DEVICE_CONTROL:
+
+ //
+ // This is a real user request, process it as such.
+ //
+
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
+
+ case IOCTL_NDIS_QUERY_GLOBAL_STATS:
+
+ //
+ // A single query, complete the IRP.
+ //
+
+ Irp->IoStatus.Information =
+ NdisRequest->DATA.QUERY_INFORMATION.BytesWritten;
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ } else if (Status == NDIS_STATUS_INVALID_LENGTH) {
+ Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
+ } else {
+ Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; // what else ?
+ }
+
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ ExFreePool (GlobalRequest);
+ break;
+
+ case IOCTL_NDIS_QUERY_ALL_STATS:
+
+ //
+ // An "all" query.
+ //
+
+ AllRequest = (PNDIS_QUERY_ALL_REQUEST)GlobalRequest;
+
+ AllRequest->NdisStatus = Status;
+ KeSetEvent(
+ &AllRequest->Event,
+ 0L,
+ FALSE);
+
+ break;
+
+ }
+
+ break;
+
+ }
+
+}
+
+
+
+NTSTATUS
+NdisCloseIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ The handle for IRP_MJ_CLOSE IRPs.
+
+Arguments:
+
+ DeviceObject - The adapter's device object.
+ Irp - The IRP.
+
+Return Value:
+
+ STATUS_SUCCESS if it should be.
+
+--*/
+
+{
+
+ PIO_STACK_LOCATION IrpSp;
+ PNDIS_USER_OPEN_CONTEXT OpenContext;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisCloseIrpHandler\n");
+ IF_ERROR_CHK {
+ if (DbgIsNull(Irp)) {
+ NdisPrint1(": Null Irp\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(Irp)) {
+ NdisPrint1(": Irp not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ if (IrpSp->FileObject->FsContext2 == (PVOID)NDIS_OPEN_INTERNAL) {
+
+ //
+ // An internal open, nothing needs to be done.
+ //
+
+ } else {
+
+ //
+ // Free the query context.
+ //
+
+ ASSERT (IrpSp->FileObject->FsContext2 == (PVOID)NDIS_OPEN_QUERY_STATISTICS);
+
+ OpenContext = IrpSp->FileObject->FsContext;
+ ExFreePool (OpenContext->OidArray);
+ ExFreePool (OpenContext);
+
+ }
+
+ Irp->IoStatus.Status = Status;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisCloseIrplHandler\n");
+ return Status;
+}
+
+NTSTATUS
+NdisSuccessIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ The "success handler" for any IRPs that we can ignore.
+
+Arguments:
+
+ DeviceObject - The adapter's device object.
+ Irp - The IRP.
+
+Return Value:
+
+ Always STATUS_SUCCESS.
+
+--*/
+
+{
+
+ DeviceObject; // to avoid "unused formal parameter" warning
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisSuccessIrplHandler\n");
+ IF_ERROR_CHK {
+ if (DbgIsNull(Irp)) {
+ NdisPrint1(": Null Irp\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(Irp)) {
+ NdisPrint1(": Irp not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisSuccessIrplHandler\n");
+ return STATUS_SUCCESS;
+}
+
+
+VOID
+NdisKillOpenAndNotifyProtocol(
+ IN PNDIS_OPEN_BLOCK OldOpenP
+ )
+
+/*++
+
+Routine Description:
+
+ Closes an open and notifies the protocol; used when the
+ close is internally generated by the NDIS wrapper (due to
+ a protocol or adapter deregistering with outstanding opens).
+
+Arguments:
+
+ OldOpenP - The open to be closed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Indicate the status to the protocol.
+ //
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisKillOpenAndNotifyProtocol\n");
+ NdisPrint3(" Closing Adapter %wZ and notifying Protocol %wZ\n",
+ &OldOpenP->AdapterHandle->AdapterName,
+ &(OldOpenP->ProtocolHandle)->ProtocolCharacteristics.Name);
+ }
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(OldOpenP)) {
+ NdisPrint1("NdisKillOpenAndNotifyProtocol: Null Open Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(OldOpenP)) {
+ NdisPrint1("NdisKillOpenAndNotifyProtocol: Open Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ (OldOpenP->ProtocolHandle->ProtocolCharacteristics.StatusHandler) (
+ OldOpenP->ProtocolBindingContext,
+ NDIS_STATUS_CLOSING,
+ NULL,
+ 0); // need real reason here
+
+
+ //
+ // Now KillOpen will do the real work.
+ //
+
+ if (OldOpenP->AdapterHandle->DeviceObject == NULL) {
+ //
+ // Miniport
+ //
+ (void)NdisMKillOpen(OldOpenP);
+ } else {
+ //
+ // Mac
+ //
+ (void)NdisKillOpen(OldOpenP);
+ }
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisKillOpenAndNotifyProtocol\n");
+}
+
+
+BOOLEAN
+NdisKillOpen(
+ PNDIS_OPEN_BLOCK OldOpenP
+ )
+
+/*++
+
+Routine Description:
+
+ Closes an open. Used when NdisCloseAdapter is called, and also
+ for internally generated closes.
+
+Arguments:
+
+ OldOpenP - The open to be closed.
+
+Return Value:
+
+ TRUE if the open finished, FALSE if it pended.
+
+--*/
+
+{
+ PNDIS_OPEN_BLOCK TmpOpen;
+ PFILE_OBJECT FileObject = OldOpenP->FileObject;
+
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisKillOpen\n");
+ NdisPrint3(" Closing Adapter %wZ as requested by %wZ\n",
+ &OldOpenP->AdapterHandle->AdapterName,
+ &(OldOpenP->ProtocolHandle)->ProtocolCharacteristics.Name);
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(OldOpenP)) {
+ NdisPrint1("NdisKillOpen: Null Open Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(OldOpenP)) {
+ NdisPrint1("NdisKillOpen: Open Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+ ACQUIRE_SPIN_LOCK(&OldOpenP->SpinLock);
+
+ //
+ // See if this open is already closing.
+ //
+
+ if (OldOpenP->Closing) {
+ RELEASE_SPIN_LOCK(&OldOpenP->SpinLock);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisKillOpen\n");
+ return TRUE;
+ }
+
+
+ //
+ // Indicate to others that this open is closing.
+ //
+
+ OldOpenP->Closing = TRUE;
+ RELEASE_SPIN_LOCK(&OldOpenP->SpinLock);
+
+ //
+ // Inform the MAC.
+ //
+
+ if ((OldOpenP->MacHandle->MacCharacteristics.CloseAdapterHandler) (
+ OldOpenP->MacBindingHandle) == NDIS_STATUS_PENDING) {
+
+ //
+ // MacCloseAdapter pended, will complete later.
+ //
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisKillOpen\n");
+ return FALSE;
+ }
+
+ //
+ // Remove the reference for this open.
+ //
+ ObDereferenceObject((PVOID)FileObject);
+
+ //
+ // Remove us from the adapter and protocol open queues.
+ //
+
+ NdisDeQueueOpenOnAdapter(OldOpenP, OldOpenP->AdapterHandle);
+ NdisDeQueueOpenOnProtocol(OldOpenP, OldOpenP->ProtocolHandle);
+
+
+ //
+ // MacCloseAdapter did not pend; we ignore the return code.
+ //
+
+ NdisDereferenceProtocol(OldOpenP->ProtocolHandle);
+ NdisDereferenceAdapter(OldOpenP->AdapterHandle);
+
+ NdisFreeSpinLock(&OldOpenP->SpinLock);
+
+ //
+ // Remove from global adpater list
+ //
+ ACQUIRE_SPIN_LOCK(&GlobalOpenListLock);
+
+ if (GlobalOpenList == OldOpenP) {
+
+ GlobalOpenList = OldOpenP->NextGlobalOpen;
+
+ } else {
+
+ TmpOpen = GlobalOpenList;
+
+ while (TmpOpen->NextGlobalOpen != OldOpenP) {
+
+ TmpOpen = TmpOpen->NextGlobalOpen;
+
+ }
+
+ TmpOpen->NextGlobalOpen = OldOpenP->NextGlobalOpen;
+
+ }
+
+ RELEASE_SPIN_LOCK(&GlobalOpenListLock);
+
+ ExFreePool((PVOID)OldOpenP);
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisKillOpen\n");
+ return TRUE;
+}
+
+
+BOOLEAN
+NdisQueueAdapterOnMac(
+ IN PNDIS_ADAPTER_BLOCK AdaptP,
+ IN PNDIS_MAC_BLOCK MacP
+ )
+
+/*++
+
+Routine Description:
+
+ Adds an adapter to a list of adapters for a MAC.
+
+Arguments:
+
+ AdaptP - The adapter block to queue.
+ MacP - The MAC block to queue it to.
+
+Return Value:
+
+ FALSE if the MAC is closing.
+ TRUE otherwise.
+
+--*/
+
+{
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisQueueAdapterOnMac\n");
+ NdisPrint2(" Adapter %wZ being added to MAC list\n",&AdaptP->MacHandle->MacCharacteristics.Name);
+ }
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(AdaptP)) {
+ NdisPrint1("NdisQueueAdapterOnMac: Null Adapter Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(AdaptP)) {
+ NdisPrint1("NdisQueueAdapterOnMac: Adapter Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(MacP)) {
+ NdisPrint1("NdisQueueAdapterOnMac: Null Mac Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(MacP)) {
+ NdisPrint1("NdisQueueAdapterOnMac: Mac Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+ ACQUIRE_SPIN_LOCK(&MacP->Ref.SpinLock);
+
+ //
+ // Make sure the MAC is not closing.
+ //
+
+ if (MacP->Ref.Closing) {
+ RELEASE_SPIN_LOCK(&MacP->Ref.SpinLock);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisQueueAdapterOnMac\n");
+ return FALSE;
+ }
+
+
+ //
+ // Add this adapter at the head of the queue
+ //
+
+ AdaptP->NextAdapter = MacP->AdapterQueue;
+ MacP->AdapterQueue = AdaptP;
+
+ RELEASE_SPIN_LOCK(&MacP->Ref.SpinLock);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisQueueAdapterOnMac\n");
+ return TRUE;
+}
+
+
+VOID
+NdisDeQueueAdapterOnMac(
+ PNDIS_ADAPTER_BLOCK AdaptP,
+ PNDIS_MAC_BLOCK MacP
+ )
+
+/*++
+
+Routine Description:
+
+ Removes an adapter from a list of adapters for a MAC.
+
+Arguments:
+
+ AdaptP - The adapter block to dequeue.
+ MacP - The MAC block to dequeue it from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisDeQueueAdapterOnMac\n");
+ NdisPrint2(" Adapter %wZ being removed from MAC list\n",&AdaptP->MacHandle->MacCharacteristics.Name);
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(AdaptP)) {
+ NdisPrint1("NdisDeQueueAdapterOnMac: Null Adapter Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(AdaptP)) {
+ NdisPrint1("NdisDeQueueAdapterOnMac: Adapter Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(MacP)) {
+ NdisPrint1("NdisDeQueueAdapterOnMac: Null Mac Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(MacP)) {
+ NdisPrint1("NdisDeQueueAdapterOnMac: Mac Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+ ACQUIRE_SPIN_LOCK(&MacP->Ref.SpinLock);
+
+ //
+ // Find the MAC on the queue, and remove it.
+ //
+
+ if (MacP->AdapterQueue == AdaptP) {
+ MacP->AdapterQueue = AdaptP->NextAdapter;
+ } else {
+ PNDIS_ADAPTER_BLOCK MP = MacP->AdapterQueue;
+
+ while (MP->NextAdapter != AdaptP) {
+ MP = MP->NextAdapter;
+ }
+
+ MP->NextAdapter = MP->NextAdapter->NextAdapter;
+ }
+
+ RELEASE_SPIN_LOCK(&MacP->Ref.SpinLock);
+
+ if (MacP->Unloading && (MacP->AdapterQueue == (PNDIS_ADAPTER_BLOCK)NULL)) {
+
+ KeSetEvent(
+ &MacP->AdaptersRemovedEvent,
+ 0L,
+ FALSE
+ );
+
+ }
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeQueueAdapterOnMac\n");
+}
+
+
+
+VOID
+NdisKillAdapter(
+ PNDIS_ADAPTER_BLOCK OldAdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ Removes an adapter. Called by NdisDeregisterAdapter and also
+ for internally generated deregistrations.
+
+Arguments:
+
+ OldAdaptP - The adapter to be removed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // If the adapter is already closing, return.
+ //
+
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisKillAdapter\n");
+ NdisPrint2(" Removing Adapter %s\n",OldAdaptP->AdapterName.Buffer);
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(OldAdaptP)) {
+ NdisPrint1("NdisKillAdapter: Null Adapter Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(OldAdaptP)) {
+ NdisPrint1("NdisKillAdapter: Adapter Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+ if (!NdisCloseRef(&OldAdaptP->Ref)) {
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisKillAdapter\n");
+ return;
+ }
+
+
+ //
+ // Kill all the opens for this adapter.
+ //
+
+ while (OldAdaptP->OpenQueue != (PNDIS_OPEN_BLOCK)NULL) {
+
+ //
+ // This removes it from the adapter's OpenQueue etc.
+ //
+
+ NdisKillOpenAndNotifyProtocol(OldAdaptP->OpenQueue);
+ }
+
+
+ //
+ // Remove the adapter from the MAC's list.
+ //
+
+ NdisDeQueueAdapterOnMac(OldAdaptP, OldAdaptP->MacHandle);
+
+ NdisDereferenceAdapter(OldAdaptP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisKillAdapter\n");
+}
+
+
+
+VOID
+NdisDereferenceAdapter(
+ PNDIS_ADAPTER_BLOCK AdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ Dereferences an adapter. If the reference count goes to zero,
+ it frees resources associated with the adapter.
+
+Arguments:
+
+ AdaptP - The adapter to be dereferenced.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if (NdisDereferenceRef(&AdaptP->Ref)) {
+
+ //
+ // Free resource memory
+ //
+
+ if (AdaptP->Resources != NULL) {
+
+ ExFreePool(AdaptP->Resources);
+
+ }
+
+ ExFreePool(AdaptP->AdapterName.Buffer);
+
+ if (AdaptP->Master) {
+ UINT i;
+ ULONG MapRegistersPerChannel =
+ ((AdaptP->MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2;
+ KIRQL OldIrql;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ for (i=0; i<AdaptP->PhysicalMapRegistersNeeded; i++) {
+ IoFreeMapRegisters(
+ AdaptP->SystemAdapterObject,
+ AdaptP->MapRegisters[i].MapRegister,
+ MapRegistersPerChannel);
+ }
+
+ KeLowerIrql(OldIrql);
+ }
+
+ if ((AdaptP->NumberOfPorts > 0) && AdaptP->InitialPortMapped) {
+ MmUnmapIoSpace (AdaptP->InitialPortMapping, AdaptP->NumberOfPorts);
+ }
+
+ NdisDereferenceMac(AdaptP->MacHandle);
+ IoDeleteDevice(AdaptP->DeviceObject);
+
+ }
+}
+
+
+BOOLEAN
+NdisQueueOpenOnAdapter(
+ IN PNDIS_OPEN_BLOCK OpenP,
+ IN PNDIS_ADAPTER_BLOCK AdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ Adds an open to a list of opens for an adapter.
+
+Arguments:
+
+ OpenP - The open block to queue.
+ AdaptP - The adapter block to queue it to.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ // attach ourselves to the adapter object linked list of opens
+ ACQUIRE_SPIN_LOCK(&AdaptP->Ref.SpinLock);
+
+ //
+ // Make sure the adapter is not closing.
+ //
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisQueueAdapterOnAdapter\n");
+ NdisPrint2(" Open being added to list for Adapter %s\n",AdaptP->AdapterName.Buffer);
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(OpenP)) {
+ NdisPrint1("NdisQueueOpenOnAdapter: Null Open Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(OpenP)) {
+ NdisPrint1("NdisQueueOpenOnAdapter: Open Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(AdaptP)) {
+ NdisPrint1("NdisQueueOpenOnAdapter: Null Adapter Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(AdaptP)) {
+ NdisPrint1("NdisQueueOpenOnAdapter: Adapter Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+ if (AdaptP->Ref.Closing) {
+ RELEASE_SPIN_LOCK(&AdaptP->Ref.SpinLock);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisQueueAdapterOnAdapter\n");
+ return FALSE;
+ }
+
+
+ //
+ // Attach this open at the head of the queue.
+ //
+
+ OpenP->AdapterNextOpen = AdaptP->OpenQueue;
+ AdaptP->OpenQueue = OpenP;
+
+
+ RELEASE_SPIN_LOCK(&AdaptP->Ref.SpinLock);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisQueueAdapterOnAdapter\n");
+ return TRUE;
+}
+
+VOID
+NdisDeQueueOpenOnAdapter(
+ PNDIS_OPEN_BLOCK OpenP,
+ PNDIS_ADAPTER_BLOCK AdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ Removes an open from a list of opens for an adapter.
+
+Arguments:
+
+ OpenP - The open block to dequeue.
+ AdaptP - The adapter block to dequeue it from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisDeQueueAdapterOnAdapter\n");
+ NdisPrint2(" Open being removed from list for Adapter %s\n",AdaptP->AdapterName.Buffer);
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(OpenP)) {
+ NdisPrint1("NdisDeQueueOpenOnAdapter: Null Open Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(OpenP)) {
+ NdisPrint1("NdisDeQueueOpenOnAdapter: Open Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(AdaptP)) {
+ NdisPrint1("NdisDeQueueOpenOnAdapter: Null Adapter Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(AdaptP)) {
+ NdisPrint1("NdisDeQueueOpenOnAdapter: Adapter Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ ACQUIRE_SPIN_LOCK(&AdaptP->Ref.SpinLock);
+ //
+ // Find the open on the queue, and remove it.
+ //
+
+ if (AdaptP->OpenQueue == OpenP) {
+ AdaptP->OpenQueue = OpenP->AdapterNextOpen;
+ } else {
+ PNDIS_OPEN_BLOCK AP = AdaptP->OpenQueue;
+
+ while (AP->AdapterNextOpen != OpenP) {
+ AP = AP->AdapterNextOpen;
+ }
+
+ AP->AdapterNextOpen = AP->AdapterNextOpen->AdapterNextOpen;
+ }
+
+ RELEASE_SPIN_LOCK(&AdaptP->Ref.SpinLock);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeQueueAdapterOnAdapter\n");
+}
+
+
+VOID
+NdisDereferenceMac(
+ PNDIS_MAC_BLOCK MacP
+ )
+/*++
+
+Routine Description:
+
+ Removes a reference from the mac, deleting it if the count goes to 0.
+
+Arguments:
+
+ MacP - The Mac block to dereference.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ if (NdisDereferenceRef(&(MacP)->Ref)) {
+
+ //
+ // Remove it from the global list.
+ //
+
+ ACQUIRE_SPIN_LOCK(&NdisMacListLock);
+
+ if (NdisMacList == MacP) {
+
+ NdisMacList = MacP->NextMac;
+
+ } else {
+
+ PNDIS_MAC_BLOCK TmpMacP = NdisMacList;
+
+ while(TmpMacP->NextMac != MacP) {
+
+ TmpMacP = TmpMacP->NextMac;
+
+ }
+
+ TmpMacP->NextMac = TmpMacP->NextMac->NextMac;
+
+ }
+
+ RELEASE_SPIN_LOCK(&NdisMacListLock);
+
+ if ( MacP->PciAssignedResources != NULL ) {
+ ExFreePool( MacP->PciAssignedResources );
+ }
+
+ ExFreePool((PVOID)(MacP));
+ }
+
+
+}
+
+
+
+//
+// Stubs to compile with Ndis 3.0 kernel.
+//
+
+NDIS_STATUS
+EthAddFilterAddress() {
+ return(NDIS_STATUS_FAILURE);
+}
+
+NDIS_STATUS
+EthDeleteFilterAddress() {
+ return(NDIS_STATUS_FAILURE);
+}
+
+NDIS_STATUS
+NdisInitializePacketPool() {
+ return(NDIS_STATUS_FAILURE);
+}
+
+
+
+NTSTATUS
+WrapperSaveLinkage(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called with the values for the "Bind" and "Export" multi-strings
+ for a given driver. It allocates memory to hold the data and copies
+ it over.
+
+Arguments:
+
+ ValueName - The name of the value ("Bind" or "Export" -- ignored).
+
+ ValueType - The type of the value (REG_MULTI_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - Unused.
+
+ EntryContext - A pointer to the pointer that holds the copied data.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PWSTR * Data = ((PWSTR *)EntryContext);
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+ UNREFERENCED_PARAMETER(Context);
+
+
+ *Data = ExAllocatePoolWithTag (NonPagedPool, ValueLength, ' DN');
+
+ if (*Data == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory (*Data, ValueData, ValueLength);
+
+ return STATUS_SUCCESS;
+
+}
+
+
+NTSTATUS
+WrapperCheckRoute(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called with the value for the "Route" multi-string. It
+ counts the number of "'s in the first string and if it is
+ more than two than it knows that this is a layered driver.
+
+Arguments:
+
+ ValueName - The name of the value ("Route" -- ignored).
+
+ ValueType - The type of the value (REG_MULTI_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - Unused.
+
+ EntryContext - A pointer to a BOOLEAN that is set to TRUE
+ if the driver is layered.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+
+ PWSTR CurRouteLoc = (PWSTR)ValueData;
+ UINT QuoteCount = 0;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+ UNREFERENCED_PARAMETER(ValueLength);
+ UNREFERENCED_PARAMETER(Context);
+
+ while (*CurRouteLoc != 0) {
+
+ if (*CurRouteLoc == (WCHAR)L'"') {
+ ++QuoteCount;
+ }
+ ++CurRouteLoc;
+ }
+
+ if (QuoteCount > 2) {
+ *(PBOOLEAN)EntryContext = TRUE;
+ }
+
+ return STATUS_SUCCESS;
+
+}
+
+NDIS_STATUS
+NdisCallDriverAddAdapter(
+ IN PNDIS_MAC_BLOCK NewMacP
+ )
+
+/*++
+
+Routine Description:
+
+ Reads the driver registry bindings and calls add adapter for each
+ one.
+
+Arguments:
+
+ NewMacP - Pointer to the Mac block allocated for this Mac.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Pointer to a Miniport
+ //
+ PNDIS_M_DRIVER_BLOCK WDriver = (PNDIS_M_DRIVER_BLOCK)NewMacP;
+
+ //
+ // Number of adapters added successfully
+ //
+ UINT AdaptersAdded = 0;
+
+ //
+ // Status of calls to MacAddAdapter
+ //
+ NDIS_STATUS AddAdapterStatus;
+
+ //
+ // Status of calls to MiniportInitialize
+ //
+ NDIS_STATUS MiniportInitializeStatus;
+ NDIS_STATUS OpenErrorStatus;
+
+ UINT SelectedMediumIndex;
+
+ NDIS_MEDIUM MediumArray[] = {NdisMedium802_3,
+ NdisMedium802_5,
+ NdisMediumFddi,
+ NdisMediumArcnet878_2,
+ NdisMediumWan };
+
+ UINT MediumArraySize = 5;
+
+ //
+ // Status of registry requests.
+ //
+ NTSTATUS RegistryStatus;
+ NTSTATUS NtStatus;
+
+ //
+ // subkey containing the card parameters
+ //
+ PWSTR Linkage = L"Linkage";
+
+ //
+ // subkeys below "Linkage"
+ //
+
+ PWSTR Bind = L"Bind";
+ PWSTR Export = L"Export";
+ PWSTR Route = L"Route";
+
+ //
+ // These hold the REG_MULTI_SZ read from "Bind" and "Export".
+ //
+
+ PWSTR BindData;
+ PWSTR ExportData;
+
+ //
+ // These hold our place in the REG_MULTI_SZ read for
+ // "Bind" and "Export".
+ //
+
+ PWSTR CurBindValue;
+ PWSTR CurExportValue;
+
+ //
+ // Will be set to TRUE if the driver is layered (that is,
+ // it binds to another NDIS driver, not to an adapter).
+ //
+
+ BOOLEAN LayeredDriver;
+
+ //
+ // subkey below the driver's service key.
+ //
+
+ PWSTR Parameters = L"Parameters";
+
+ //
+ // The path to our configuration data.
+ //
+ PUNICODE_STRING ConfigurationString;
+
+ //
+ // Holds a null-terminated copy of ConfigurationString
+ //
+ PWSTR ConfigurationPath;
+
+ ULONG i;
+ ULONG BusNumber;
+ NDIS_INTERFACE_TYPE BusType;
+
+ //
+ // Holds the key below services where Parameters are stored.
+ //
+ PWCH BaseFileName;
+
+ //
+ // Used to instruct RtlQueryRegistryValues to read the
+ // Linkage\Bind and Linkage\Export keys
+ //
+ RTL_QUERY_REGISTRY_TABLE LinkageQueryTable[5];
+
+ //
+ // Used to instruct RtlQueryRegistryValues to read the
+ // [Driver]\Parameters keys. This is passed as the
+ // ConfigContext to the MacAddAdapter routine.
+ //
+
+ NDIS_WRAPPER_CONFIGURATION_HANDLE ConfigurationHandle;
+
+ NDIS_WRAPPER_CONFIGURATION_HANDLE WrapperConfigurationHandle;
+
+ //
+ // Used for calls to other Ndis routines
+ //
+ NDIS_STATUS NdisStatus;
+
+ BOOLEAN IsAMiniport;
+
+#define BLOCK_LOCK_MINIPORT(_M, _L) \
+ { \
+ ACQUIRE_SPIN_LOCK(&_M->Lock); \
+ LOCK_MINIPORT(_M, _L); \
+ while (!_L) { \
+ UNLOCK_MINIPORT(_M, _L); \
+ RELEASE_SPIN_LOCK(&_M->Lock); \
+ ACQUIRE_SPIN_LOCK(&_M->Lock); \
+ LOCK_MINIPORT(_M, _L); \
+ } \
+ RELEASE_SPIN_LOCK(&_M->Lock); \
+ }
+
+ IsAMiniport = (WDriver->MiniportIdField == (NDIS_HANDLE)0x01);
+
+ //
+ // Set up LinkageQueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Linkage key below this driver's key
+ //
+
+ LinkageQueryTable[0].QueryRoutine = NULL;
+ LinkageQueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ LinkageQueryTable[0].Name = Linkage;
+
+ //
+ // 2) Call WrapperSaveLinkage for "Bind" (as a single multi-string),
+ // which will allocate storage and save the data in BindData.
+ //
+
+ LinkageQueryTable[1].QueryRoutine = WrapperSaveLinkage;
+ LinkageQueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ LinkageQueryTable[1].Name = Bind;
+ LinkageQueryTable[1].EntryContext = (PVOID)&BindData;
+ LinkageQueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 3) Call WrapperSaveLinkage for "Export" (as a single multi-string)
+ // which will allocate storage and save the data in ExportData.
+ //
+
+ LinkageQueryTable[2].QueryRoutine = WrapperSaveLinkage;
+ LinkageQueryTable[2].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ LinkageQueryTable[2].Name = Export;
+ LinkageQueryTable[2].EntryContext = (PVOID)&ExportData;
+ LinkageQueryTable[2].DefaultType = REG_NONE;
+
+ //
+ // 4) Call WrapperCheckRoute for "Route" (as a single multi-string)
+ // which will set LayeredDriver to TRUE for a layered driver (this
+ // is optional, the default is FALSE).
+ //
+
+ LinkageQueryTable[3].QueryRoutine = WrapperCheckRoute;
+ LinkageQueryTable[3].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
+ LinkageQueryTable[3].Name = Route;
+ LinkageQueryTable[3].EntryContext = (PVOID)&LayeredDriver;
+ LinkageQueryTable[3].DefaultType = REG_NONE;
+
+ LayeredDriver = FALSE;
+
+ //
+ // 5) Stop
+ //
+
+ LinkageQueryTable[4].QueryRoutine = NULL;
+ LinkageQueryTable[4].Flags = 0;
+ LinkageQueryTable[4].Name = NULL;
+
+
+ //
+ // Allocate room for a null-terminated version of the config path
+ //
+
+ if (IsAMiniport) {
+
+ ConfigurationString = (PUNICODE_STRING)(WDriver->NdisDriverInfo->NdisWrapperConfigurationHandle);
+
+ } else {
+
+ ConfigurationString = (PUNICODE_STRING)(NewMacP->NdisMacInfo->NdisWrapperConfigurationHandle);
+
+ }
+
+ ConfigurationPath = (PWSTR)ExAllocatePoolWithTag(
+ NonPagedPool,
+ ConfigurationString->Length + sizeof(WCHAR),
+ ' DN');
+ if (ConfigurationPath == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ RtlCopyMemory (ConfigurationPath, ConfigurationString->Buffer, ConfigurationString->Length);
+ *(PWCHAR)(((PUCHAR)ConfigurationPath)+ConfigurationString->Length) = (WCHAR)L'\0';
+
+ BindData = NULL;
+ ExportData = NULL;
+
+ RegistryStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ ConfigurationPath,
+ LinkageQueryTable,
+ (PVOID)NULL, // no context needed
+ NULL);
+
+ if (!NT_SUCCESS(RegistryStatus)) {
+
+ //
+ // Free memory if needed, exit.
+ //
+
+ ExFreePool (ConfigurationPath);
+
+ if (BindData != NULL) {
+ ExFreePool (BindData);
+ }
+ if (ExportData != NULL) {
+ ExFreePool (ExportData);
+ }
+
+#if DBG
+ if (IsAMiniport) {
+
+ DbgPrint("NDIS: Could not read Bind/Export for %Z: %lx\n",
+ (PUNICODE_STRING)(WDriver->NdisDriverInfo->NdisWrapperConfigurationHandle),
+ RegistryStatus);
+
+ } else {
+
+ DbgPrint("NDIS: Could not read Bind/Export for %Z: %lx\n",
+ (PUNICODE_STRING)(NewMacP->NdisMacInfo->NdisWrapperConfigurationHandle),
+ RegistryStatus);
+
+ }
+#endif
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ //
+ // NdisReadConfiguration assumes that ParametersQueryTable[3].Name is
+ // a key below the services key where the Parameters should be read,
+ // for layered drivers we store the last piece of Configuration
+ // Path there, leading to the desired effect.
+ //
+ // I.e, ConfigurationPath == "...\Services\Driver".
+ //
+ // For a layered driver, ParameterQueryTable[3].Name is "Driver"
+ // for all calls to AddAdapter, and parameters are read from
+ // "...\Services\Driver\Parameters" for all calls.
+ //
+ // For a non-layered driver, ParametersQueryTable[3].Name might be
+ // "Driver01" for the first call to AddAdapter, "Driver02" for the
+ // second, etc., and parameters are read from
+ // "..\Services\Driver01\Parameters" for the first call to
+ // AddAdapter, "...\Services\Driver02\Parameters" for the second
+ // call, etc.
+ //
+
+ if (LayeredDriver) {
+
+ BaseFileName = ConfigurationPath;
+
+ for ( i = 0; i < ConfigurationString->Length / sizeof(WCHAR); i++ ) {
+
+ //
+ // If s points to a directory separator, set BaseFileName to
+ // the character after the separator.
+ //
+
+ if ( ConfigurationPath[i] == OBJ_NAME_PATH_SEPARATOR ) {
+ BaseFileName = &(ConfigurationPath[++i]);
+ }
+
+ }
+
+#if DBG
+ DbgPrint ("NDIS: Loading layered driver %ws\n", BaseFileName);
+#endif
+
+ }
+
+
+ //
+ // Set up ParametersQueryTable. We set most of it up here,
+ // then call the MAC's AddAdapter routine with its address
+ // as a ConfigContext. Inside ReadConfiguration, we get
+ // the ConfigContext back and can then finish initializing
+ // the table and use RtlQueryRegistryValues (with a
+ // callback to WrapperSaveParameter) to read the value
+ // specified.
+ //
+
+
+ //
+ // 1) Switch to the Parameters key below the [DriverName] key
+ // (DriverName is passed as a parameter to RtlQueryRegistryValues).
+ //
+
+ ConfigurationHandle.ParametersQueryTable[0].QueryRoutine = NULL;
+ ConfigurationHandle.ParametersQueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ ConfigurationHandle.ParametersQueryTable[0].Name = Parameters;
+
+ //
+ // 2) Call WrapperSaveParameter for a parameter, which
+ // will allocate storage for it.
+ //
+ // ParametersQueryTable[1].Name and ParametersQueryTable[1].EntryContext
+ // are filled in inside ReadConfiguration, in preparation
+ // for the callback.
+ //
+
+ ConfigurationHandle.ParametersQueryTable[1].QueryRoutine = WrapperSaveParameters;
+ ConfigurationHandle.ParametersQueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ ConfigurationHandle.ParametersQueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 3) Stop
+ //
+
+ ConfigurationHandle.ParametersQueryTable[2].QueryRoutine = NULL;
+ ConfigurationHandle.ParametersQueryTable[2].Flags = 0;
+ ConfigurationHandle.ParametersQueryTable[2].Name = NULL;
+
+ //
+ // NOTE: Some fields in ParametersQueryTable[3] are used to
+ // store information for later retrieval.
+ //
+
+
+
+ //
+ // OK, Now lock down all the filter packages. If a MAC or
+ // Miniport driver uses any of these, then the filter package
+ // will reference itself, to keep the image in memory.
+ //
+ ArcReferencePackage();
+ EthReferencePackage();
+ FddiReferencePackage();
+ TrReferencePackage();
+ MiniportReferencePackage();
+ NdisMacReferencePackage();
+
+ //
+ // For each binding, get the handle to the card object.
+ // Call the driver's addadapter routine.
+ //
+
+ CurBindValue = BindData;
+ CurExportValue = ExportData;
+
+ while ((*CurBindValue != 0) && (*CurExportValue != 0)) {
+
+ UNICODE_STRING CurBindString;
+ UNICODE_STRING CurExportString;
+ NDIS_CONFIGURATION_HANDLE TmpConfigHandle;
+ NDIS_STRING BusTypeStr = NDIS_STRING_CONST("BusType");
+ NDIS_STRING BusNumberStr = NDIS_STRING_CONST("BusNumber");
+ PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
+ PDEVICE_OBJECT TmpDeviceP;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ LARGE_INTEGER TimeoutValue;
+
+ TimeoutValue.QuadPart = Int32x32To64(100 * 1000, -10000);
+
+ //
+ // Setup the query table to point to the section in
+ // the registry corresponding to what was specified
+ // in "Bind". The "Parameters" key below this is where
+ // config parameters are read from.
+ //
+
+ RtlInitUnicodeString (&CurBindString, CurBindValue);
+
+ //
+ // For layered drivers, BaseFileName is already
+ // initialized.
+ //
+
+ if (!LayeredDriver) {
+
+ //
+ // Parse out the path name, leaving only the driver name.
+ //
+
+ BaseFileName = CurBindString.Buffer;
+
+ for ( i = 0; i < CurBindString.Length / sizeof(WCHAR); i++ ) {
+
+ //
+ // If s points to a directory separator, set fileBaseName to
+ // the character after the separator.
+ //
+
+ if ( CurBindString.Buffer[i] == OBJ_NAME_PATH_SEPARATOR ) {
+ BaseFileName = &(CurBindString.Buffer[++i]);
+ }
+
+ }
+
+ //
+ // Set this to NULL, in case NdisReadBindingInformation
+ // is called.
+ //
+
+ ConfigurationHandle.ParametersQueryTable[3].EntryContext = NULL;
+
+ } else {
+
+ //
+ // This will be returned by NdisReadBindingInformation.
+ //
+
+ ConfigurationHandle.ParametersQueryTable[3].EntryContext = CurBindValue;
+
+ }
+
+
+ //
+ // Save the driver name here; later we will use this as
+ // a parameter to RtlQueryRegistryValues.
+ //
+
+ ConfigurationHandle.ParametersQueryTable[3].Name = BaseFileName;
+
+ //
+ // Also, save the BusType and BusNumber so that we can pull them
+ // out in NdisRegisterAdapter(), NdisReadEisaSlotInformation() and
+ // NdisReadPosInformation().
+ //
+
+ TmpConfigHandle.KeyQueryTable = ConfigurationHandle.ParametersQueryTable;
+ TmpConfigHandle.ParameterList = NULL;
+
+ //
+ // Read Bus Number
+ //
+
+ NdisReadConfiguration(
+ &NdisStatus,
+ &ReturnedValue,
+ &TmpConfigHandle,
+ &BusNumberStr,
+ NdisParameterInteger
+ );
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ BusNumber = ReturnedValue->ParameterData.IntegerData;
+
+ } else {
+
+ BusNumber = (ULONG)(-1);
+ }
+
+ //
+ // Read Bus Type
+ //
+
+ NdisReadConfiguration(
+ &NdisStatus,
+ &ReturnedValue,
+ &TmpConfigHandle,
+ &BusTypeStr,
+ NdisParameterInteger
+ );
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ BusType = (NDIS_INTERFACE_TYPE)(ReturnedValue->ParameterData.IntegerData);
+
+ } else {
+
+ BusType = (NDIS_INTERFACE_TYPE)(-1);
+
+ }
+
+ ConfigurationHandle.ParametersQueryTable[3].DefaultType = (ULONG)(BusType);
+ ConfigurationHandle.ParametersQueryTable[3].DefaultLength = (ULONG)(BusNumber);
+ ConfigurationHandle.ParametersQueryTable[3].DefaultData = NULL;
+
+ //
+ // Call adapter callback. The current value for "Export"
+ // is what we tell him to name this device.
+ //
+
+ RtlInitUnicodeString (&CurExportString, CurExportValue);
+
+ if (IsAMiniport)
+ {
+ ConfigurationHandle.DriverObject = WDriver->NdisDriverInfo->NdisWrapperDriver;
+ }
+ else
+ {
+ ConfigurationHandle.DriverObject = NewMacP->NdisMacInfo->NdisWrapperDriver;
+ }
+
+ if (IsAMiniport)
+ {
+ KIRQL OldIrql;
+ ULONG MaximumLongAddresses;
+ UCHAR CurrentLongAddress[6];
+ ULONG MaximumShortAddresses;
+ UCHAR CurrentShortAddress[2];
+ UINT BytesWritten;
+ UINT BytesNeeded;
+ UINT PacketFilter = 0x1;
+ UCHAR i;
+ BOOLEAN LocalLock;
+ PARC_BUFFER_LIST Buffer;
+ PVOID DataBuffer;
+
+ //
+ // Initialize device.
+ //
+
+ if (!NdisReferenceDriver((PNDIS_M_DRIVER_BLOCK)WDriver)) {
+
+ //
+ // The driver is closing.
+ //
+
+ goto LoopBottom;
+
+ }
+
+ NtStatus = IoCreateDevice(
+ WDriver->NdisDriverInfo->NdisWrapperDriver,
+ sizeof(NDIS_MINIPORT_BLOCK) + sizeof(NDIS_WRAPPER_CONTEXT), // device extension size
+ &CurExportString,
+ FILE_DEVICE_PHYSICAL_NETCARD,
+ 0,
+ FALSE, // exclusive flag
+ &TmpDeviceP
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+
+ //
+ // Initialize the Miniport adapter block in the device object extension
+ //
+ // *** NDIS_WRAPPER_CONTEXT has a higher alignment requirement than
+ // NDIS_MINIPORT_BLOCK, so we put it first in the extension.
+ //
+
+ Miniport = (PNDIS_MINIPORT_BLOCK)((PNDIS_WRAPPER_CONTEXT)TmpDeviceP->DeviceExtension + 1);
+
+ Miniport->WrapperContext = TmpDeviceP->DeviceExtension;
+
+ Miniport->BusType = BusType;
+ Miniport->BusNumber = BusNumber;
+ Miniport->DeviceObject = TmpDeviceP;
+ Miniport->DriverHandle = WDriver;
+ Miniport->MiniportName.Buffer = (PWSTR)ExAllocatePoolWithTag(
+ NonPagedPool,
+ CurExportString.MaximumLength,
+ 'naDN'
+ );
+
+ if (Miniport->MiniportName.Buffer == NULL) {
+ NdisDereferenceDriver(WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ goto LoopBottom;
+ }
+
+ Miniport->MiniportName.MaximumLength = CurExportString.MaximumLength;
+ Miniport->MiniportName.Length = CurExportString.Length;
+
+ RtlCopyMemory(Miniport->MiniportName.Buffer,
+ CurExportString.Buffer,
+ CurExportString.MaximumLength
+ );
+
+ Miniport->OpenQueue = (PNDIS_M_OPEN_BLOCK)NULL;
+ Miniport->EthDB = NULL;
+ Miniport->TrDB = NULL;
+ Miniport->FddiDB = NULL;
+ Miniport->ArcDB = NULL;
+ Miniport->BeingRemoved = FALSE;
+ Miniport->SendResourcesAvailable = 0xffffff;
+ Miniport->Flags = 0; // a value that cannot be a pointer.
+ Miniport->InAddDriver = TRUE;
+ NdisAllocateSpinLock(&Miniport->Lock);
+ //KeSetSpecialSpinLock(&Miniport->Lock, "miniport lock" );
+
+ NdisInitializeRef(&Miniport->Ref);
+
+ NdisInitializeTimer(
+ &Miniport->DpcTimer,
+ (PVOID) NdisMDpcTimer,
+ (PVOID) Miniport
+ );
+
+ NdisInitializeTimer(
+ &Miniport->WakeUpDpcTimer,
+ (PVOID) NdisMWakeUpDpc,
+ (PVOID) Miniport
+ );
+
+ if (!NdisQueueMiniportOnDriver(Miniport, WDriver)) {
+
+ //
+ // The Driver is closing, undo what we have done.
+ //
+
+ ExFreePool(Miniport->MiniportName.Buffer);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+
+ //
+ // Now we do something really bogus. We create many
+ // temporary filter databases, just in case any indications
+ // happen.
+ //
+
+ if (!EthCreateFilter(
+ 1,
+ NdisMChangeEthAddresses,
+ NdisMChangeClass,
+ NdisMCloseAction,
+ CurrentLongAddress,
+ &Miniport->Lock,
+ &(Miniport->EthDB)
+ )) {
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ if (!TrCreateFilter(
+ NdisMChangeFunctionalAddress,
+ NdisMChangeGroupAddress,
+ NdisMChangeClass,
+ NdisMCloseAction,
+ CurrentLongAddress,
+ &Miniport->Lock,
+ &(Miniport->TrDB)
+ )) {
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ if (!FddiCreateFilter(
+ 1,
+ 1,
+ NdisMChangeFddiAddresses,
+ NdisMChangeClass,
+ NdisMCloseAction,
+ CurrentLongAddress,
+ CurrentShortAddress,
+ &Miniport->Lock,
+ &(Miniport->FddiDB)
+ )) {
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ if (!ArcCreateFilter(
+ Miniport,
+ NdisMChangeClass,
+ NdisMCloseAction,
+ CurrentLongAddress[0],
+ &Miniport->Lock,
+ &(Miniport->ArcDB)
+ )) {
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ //
+ // Call adapter callback. The current value for "Export"
+ // is what we tell him to name this device.
+ //
+
+ Miniport->InInitialize = TRUE;
+ Miniport->NormalInterrupts = FALSE;
+
+ MiniportInitializeStatus =
+ (WDriver->MiniportCharacteristics.InitializeHandler)(
+ &OpenErrorStatus,
+ &SelectedMediumIndex,
+ MediumArray,
+ MediumArraySize,
+ (NDIS_HANDLE)(Miniport),
+ (NDIS_HANDLE)&ConfigurationHandle
+ );
+
+ Miniport->InInitialize = FALSE;
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ //
+ // Free the slot information buffer
+ //
+
+ if (ConfigurationHandle.ParametersQueryTable[3].DefaultData != NULL ) {
+
+ ExFreePool(ConfigurationHandle.ParametersQueryTable[3].DefaultData);
+
+ }
+
+ if (MiniportInitializeStatus == NDIS_STATUS_SUCCESS) {
+
+ ASSERT(SelectedMediumIndex < MediumArraySize);
+
+ Miniport->MediaType = MediumArray[SelectedMediumIndex];
+
+ KeInitializeEvent(
+ &Miniport->RequestEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ //
+ // Query maximum lookahead
+ //
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryInformation;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ &MaximumLongAddresses,
+ sizeof(MaximumLongAddresses),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x1
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x2
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ //
+ // Now adjust based on media type
+ //
+
+ switch(Miniport->MediaType) {
+
+ case NdisMedium802_3:
+
+ Miniport->MaximumLookahead = (NDIS_M_MAX_LOOKAHEAD - 14 < MaximumLongAddresses) ?
+ NDIS_M_MAX_LOOKAHEAD - 14 :
+ MaximumLongAddresses;
+ break;
+
+ case NdisMedium802_5:
+
+ Miniport->MaximumLookahead = (NDIS_M_MAX_LOOKAHEAD - 32 < MaximumLongAddresses) ?
+ NDIS_M_MAX_LOOKAHEAD - 32 :
+ MaximumLongAddresses;
+ break;
+
+ case NdisMediumFddi:
+ Miniport->MaximumLookahead = (NDIS_M_MAX_LOOKAHEAD - 16 < MaximumLongAddresses) ?
+ NDIS_M_MAX_LOOKAHEAD - 16 :
+ MaximumLongAddresses;
+ break;
+
+ case NdisMediumArcnet878_2:
+ Miniport->MaximumLookahead = (NDIS_M_MAX_LOOKAHEAD - 50 < MaximumLongAddresses) ?
+ NDIS_M_MAX_LOOKAHEAD - 50 :
+ MaximumLongAddresses;
+ break;
+
+ case NdisMediumWan:
+ Miniport->MaximumLookahead = 1514;
+
+ }
+
+ Miniport->CurrentLookahead = Miniport->MaximumLookahead;
+
+ //
+ // Query mac options
+ //
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryInformation;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_GEN_MAC_OPTIONS,
+ &MaximumLongAddresses,
+ sizeof(MaximumLongAddresses),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x3
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ Miniport->MacOptions = (UINT)MaximumLongAddresses;
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x4
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ //
+ // Create filter package
+ //
+ switch(Miniport->MediaType) {
+
+ case NdisMedium802_3:
+
+ //
+ // Query maximum MulticastAddress
+ //
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryInformation;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ &MaximumLongAddresses,
+ sizeof(MaximumLongAddresses),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x5
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ if (MaximumLongAddresses > NDIS_M_MAX_MULTI_LIST) {
+
+ MaximumLongAddresses = NDIS_M_MAX_MULTI_LIST;
+
+ }
+
+ Miniport->MaximumLongAddresses = MaximumLongAddresses;
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x6
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryInformation;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_802_3_CURRENT_ADDRESS,
+ &(CurrentLongAddress),
+ sizeof(CurrentLongAddress),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x7
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x8
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ //
+ // Now undo the bogus filter package. We lock
+ // the miniport so that no dpcs will get queued.
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ Miniport->InInitialize = TRUE;
+ Miniport->NormalInterrupts = FALSE;
+
+ EthDeleteFilter(Miniport->EthDB);
+ Miniport->EthDB = NULL;
+ TrDeleteFilter(Miniport->TrDB);
+ Miniport->TrDB = NULL;
+ FddiDeleteFilter(Miniport->FddiDB);
+ Miniport->FddiDB = NULL;
+ ArcDeleteFilter(Miniport->ArcDB);
+ Miniport->ArcDB = NULL;
+
+ if (!EthCreateFilter(
+ MaximumLongAddresses,
+ NdisMChangeEthAddresses,
+ NdisMChangeClass,
+ NdisMCloseAction,
+ CurrentLongAddress,
+ &Miniport->Lock,
+ &Miniport->EthDB
+ )) {
+
+ //
+ // Halt the miniport driver
+ //
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ 0xFF00FF00,
+ 0x9
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ Miniport->InInitialize = FALSE;
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ break;
+
+ case NdisMedium802_5:
+
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryInformation;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_802_5_CURRENT_ADDRESS,
+ &(CurrentLongAddress),
+ sizeof(CurrentLongAddress),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0xA
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0xB
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ //
+ // Now undo the bogus filter package. We lock
+ // the miniport so that no dpcs will get queued.
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ Miniport->InInitialize = TRUE;
+ Miniport->NormalInterrupts = FALSE;
+
+ EthDeleteFilter(Miniport->EthDB);
+ Miniport->EthDB = NULL;
+ TrDeleteFilter(Miniport->TrDB);
+ Miniport->TrDB = NULL;
+ FddiDeleteFilter(Miniport->FddiDB);
+ Miniport->FddiDB = NULL;
+ ArcDeleteFilter(Miniport->ArcDB);
+ Miniport->ArcDB = NULL;
+
+ if (!TrCreateFilter(
+ NdisMChangeFunctionalAddress,
+ NdisMChangeGroupAddress,
+ NdisMChangeClass,
+ NdisMCloseAction,
+ CurrentLongAddress,
+ &Miniport->Lock,
+ &Miniport->TrDB
+ )) {
+
+ //
+ // Halt the miniport driver
+ //
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ 0xFF00FF00,
+ 0xC
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ Miniport->InInitialize = FALSE;
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ break;
+
+ case NdisMediumFddi:
+
+ //
+ // Query maximum MulticastAddress
+ //
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryInformation;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_FDDI_LONG_MAX_LIST_SIZE,
+ &MaximumLongAddresses,
+ sizeof(MaximumLongAddresses),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0xD
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ if (MaximumLongAddresses > NDIS_M_MAX_MULTI_LIST) {
+
+ MaximumLongAddresses = NDIS_M_MAX_MULTI_LIST;
+
+ }
+
+ Miniport->MaximumLongAddresses = MaximumLongAddresses;
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0xE
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ //
+ // Query maximum MulticastAddress
+ //
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryInformation;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_FDDI_SHORT_MAX_LIST_SIZE,
+ &MaximumShortAddresses,
+ sizeof(MaximumShortAddresses),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0xF
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ if (MaximumShortAddresses > NDIS_M_MAX_MULTI_LIST) {
+
+ MaximumShortAddresses = NDIS_M_MAX_MULTI_LIST;
+
+ }
+
+ Miniport->MaximumShortAddresses = MaximumShortAddresses;
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x10
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_FDDI_LONG_CURRENT_ADDR,
+ &(CurrentLongAddress),
+ sizeof(CurrentLongAddress),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x11
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x12
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryInformation;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_FDDI_SHORT_CURRENT_ADDR,
+ &(CurrentShortAddress),
+ sizeof(CurrentShortAddress),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x13
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x14
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ //
+ // Now undo the bogus filter package. We lock
+ // the miniport so that no dpcs will get queued.
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ Miniport->InInitialize = TRUE;
+ Miniport->NormalInterrupts = FALSE;
+
+ EthDeleteFilter(Miniport->EthDB);
+ Miniport->EthDB = NULL;
+ TrDeleteFilter(Miniport->TrDB);
+ Miniport->TrDB = NULL;
+ FddiDeleteFilter(Miniport->FddiDB);
+ Miniport->FddiDB = NULL;
+ ArcDeleteFilter(Miniport->ArcDB);
+ Miniport->ArcDB = NULL;
+
+ if (!FddiCreateFilter(
+ MaximumLongAddresses,
+ MaximumShortAddresses,
+ NdisMChangeFddiAddresses,
+ NdisMChangeClass,
+ NdisMCloseAction,
+ CurrentLongAddress,
+ CurrentShortAddress,
+ &Miniport->Lock,
+ &Miniport->FddiDB
+ )) {
+
+ //
+ // Halt the miniport driver
+ //
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ 0xFF00FF00,
+ 0x15
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ Miniport->InInitialize = FALSE;
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ //
+ // In case of an encapsulated ethernet binding, we need
+ // to return the maximum number of multicast addresses
+ // possible.
+ //
+
+ Miniport->MaximumLongAddresses = NDIS_M_MAX_MULTI_LIST;
+
+ //
+ // Allocate Buffer pools
+ //
+ NdisAllocateBufferPool(&NdisStatus,
+ &Miniport->ArcnetBufferPool,
+ WRAPPER_ARC_BUFFERS
+ );
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ 0xFF00FF00,
+ 0x16
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ NdisAllocateMemory((PVOID)&Buffer,
+ sizeof(ARC_BUFFER_LIST) *
+ WRAPPER_ARC_BUFFERS,
+ 0,
+ HighestAcceptableMax
+ );
+
+ if (Buffer == NULL) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ 0xFF00FF00,
+ 0x18
+ );
+ NdisFreeBufferPool(Miniport->ArcnetBufferPool);
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ NdisAllocateMemory((PVOID)&DataBuffer,
+ WRAPPER_ARC_HEADER_SIZE *
+ WRAPPER_ARC_BUFFERS,
+ 0,
+ HighestAcceptableMax
+ );
+
+
+ if (DataBuffer == NULL) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ 0xFF00FF00,
+ 0x19
+ );
+ NdisFreeMemory(Buffer,
+ sizeof(ARC_BUFFER_LIST) *
+ WRAPPER_ARC_BUFFERS,
+ 0
+ );
+ NdisFreeBufferPool(Miniport->ArcnetBufferPool);
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ for (i = WRAPPER_ARC_BUFFERS; i != 0 ; i--) {
+
+ Buffer->BytesLeft = Buffer->Size = WRAPPER_ARC_HEADER_SIZE;
+ Buffer->Buffer = DataBuffer;
+ Buffer->Next = Miniport->ArcnetFreeBufferList;
+ Miniport->ArcnetFreeBufferList = Buffer;
+
+ Buffer++;
+ DataBuffer = (PVOID)(((PUCHAR)DataBuffer) +
+ WRAPPER_ARC_HEADER_SIZE);
+
+ }
+
+
+ //
+ // Get current address
+ //
+
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryInformation;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_ARCNET_CURRENT_ADDRESS,
+ &CurrentLongAddress[5], // address = 00-00-00-00-00-XX
+ 1,
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x1A
+ );
+ NdisFreeMemory(Buffer,
+ sizeof(ARC_BUFFER_LIST) *
+ WRAPPER_ARC_BUFFERS,
+ 0
+ );
+ NdisFreeMemory(DataBuffer,
+ WRAPPER_ARC_HEADER_SIZE *
+ WRAPPER_ARC_BUFFERS,
+ 0
+ );
+ NdisFreeBufferPool(Miniport->ArcnetBufferPool);
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x1B
+ );
+ NdisFreeMemory(Buffer,
+ sizeof(ARC_BUFFER_LIST) *
+ WRAPPER_ARC_BUFFERS,
+ 0
+ );
+ NdisFreeMemory(DataBuffer,
+ WRAPPER_ARC_HEADER_SIZE *
+ WRAPPER_ARC_BUFFERS,
+ 0
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ Miniport->ArcnetAddress = CurrentLongAddress[5];
+
+ //
+ // Now undo the bogus filter package. We lock
+ // the miniport so that no dpcs will get queued.
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ Miniport->InInitialize = TRUE;
+ Miniport->NormalInterrupts = FALSE;
+
+ EthDeleteFilter(Miniport->EthDB);
+ Miniport->EthDB = NULL;
+ TrDeleteFilter(Miniport->TrDB);
+ Miniport->TrDB = NULL;
+ FddiDeleteFilter(Miniport->FddiDB);
+ Miniport->FddiDB = NULL;
+ ArcDeleteFilter(Miniport->ArcDB);
+ Miniport->ArcDB = NULL;
+
+ if (!ArcCreateFilter(
+ Miniport,
+ NdisMChangeClass,
+ NdisMCloseAction,
+ CurrentLongAddress[5],
+ &Miniport->Lock,
+ &(Miniport->ArcDB)
+ )) {
+
+ //
+ // Halt the miniport driver
+ //
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ 0xFF00FF00,
+ 0x1C
+ );
+ NdisFreeMemory(Buffer,
+ sizeof(ARC_BUFFER_LIST) *
+ WRAPPER_ARC_BUFFERS,
+ 0
+ );
+ NdisFreeMemory(DataBuffer,
+ WRAPPER_ARC_HEADER_SIZE *
+ WRAPPER_ARC_BUFFERS,
+ 0
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ // Zero all but the last one.
+
+ CurrentLongAddress[0] = 0;
+ CurrentLongAddress[1] = 0;
+ CurrentLongAddress[2] = 0;
+ CurrentLongAddress[3] = 0;
+ CurrentLongAddress[4] = 0;
+
+ if (!EthCreateFilter(
+ 32,
+ NdisMChangeEthAddresses,
+ NdisMChangeClass,
+ NdisMCloseAction,
+ CurrentLongAddress,
+ &Miniport->Lock,
+ &Miniport->EthDB
+ )) {
+
+ //
+ // Halt the miniport driver
+ //
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ 0xFF00FF00,
+ 0x1D
+ );
+ NdisFreeMemory(Buffer,
+ sizeof(ARC_BUFFER_LIST) *
+ WRAPPER_ARC_BUFFERS,
+ 0
+ );
+ NdisFreeMemory(DataBuffer,
+ WRAPPER_ARC_HEADER_SIZE *
+ WRAPPER_ARC_BUFFERS,
+ 0
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ Miniport->InInitialize = FALSE;
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ break;
+
+ case NdisMediumWan:
+
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryInformation;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_WAN_CURRENT_ADDRESS,
+ &(CurrentLongAddress),
+ sizeof(CurrentLongAddress),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x7
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x8
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ //
+ // Now undo the bogus filter package. We lock
+ // the miniport so that no dpcs will get queued.
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ Miniport->InInitialize = TRUE;
+ Miniport->NormalInterrupts = FALSE;
+
+ EthDeleteFilter(Miniport->EthDB);
+ Miniport->EthDB = NULL;
+ TrDeleteFilter(Miniport->TrDB);
+ Miniport->TrDB = NULL;
+ FddiDeleteFilter(Miniport->FddiDB);
+ Miniport->FddiDB = NULL;
+ ArcDeleteFilter(Miniport->ArcDB);
+ Miniport->ArcDB = NULL;
+
+ Miniport->InInitialize = FALSE;
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ break;
+
+ }
+
+ //
+ // Get supported packet filters
+ //
+ Miniport->SupportedPacketFilters = 0;
+
+ //
+ // Set the filter packages bit mask to fake it out.
+ //
+ if (Miniport->EthDB) {
+ Miniport->EthDB->CombinedPacketFilter = 0xFFFFFFFF;
+ }
+ if (Miniport->TrDB) {
+ Miniport->TrDB->CombinedPacketFilter = 0xFFFFFFFF;
+ }
+ if (Miniport->FddiDB) {
+ Miniport->FddiDB->CombinedPacketFilter = 0xFFFFFFFF;
+ }
+
+ //
+ // For WAN there is no packet filter
+ //
+
+ if (Miniport->MediaType==NdisMediumWan) {
+ goto SkipFilter;
+ }
+
+ for (i=0; i<31; i++) {
+
+ //
+ // Set packet filter
+ //
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryStatistics;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ &PacketFilter,
+ sizeof(PacketFilter),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x1E
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+ Miniport->SupportedPacketFilters |= PacketFilter;
+ }
+
+ PacketFilter = PacketFilter << 1;
+
+ }
+
+ //
+ // Set packet filter
+ //
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ PacketFilter = 0;
+
+ Miniport->InternalRequest.RequestType = NdisRequestQueryStatistics;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ &PacketFilter,
+ sizeof(PacketFilter),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ //
+ // Set the filter packages bit mask to fake it out.
+ //
+ if (Miniport->EthDB) {
+ Miniport->EthDB->CombinedPacketFilter = 0;
+ }
+ if (Miniport->TrDB) {
+ Miniport->TrDB->CombinedPacketFilter = 0;
+ }
+ if (Miniport->FddiDB) {
+ Miniport->FddiDB->CombinedPacketFilter = 0;
+ }
+
+SkipFilter:
+
+ //
+ // Start wake up timer
+ //
+ NdisSetTimer(&(Miniport->WakeUpDpcTimer), 2000);
+
+ //
+ // Done with adding this MINIPORT!!!
+ //
+ Miniport->MiniportRequest = NULL;
+ Miniport->InAddDriver = FALSE;
+
+ IoRegisterShutdownNotification(Miniport->DeviceObject);
+
+ ++AdaptersAdded;
+
+ } else{
+
+ //
+ // Undo all the stuff from this mini-port
+ //
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ } else {
+
+ //
+ // NDIS 3.0 MAC
+ //
+ AddAdapterStatus =
+ (NewMacP->MacCharacteristics.AddAdapterHandler)(
+ NewMacP->MacMacContext,
+ &ConfigurationHandle,
+ &CurExportString
+ );
+
+
+ //
+ // Free the slot information buffer
+ //
+
+ if (ConfigurationHandle.ParametersQueryTable[3].DefaultData != NULL ) {
+
+ ExFreePool(ConfigurationHandle.ParametersQueryTable[3].DefaultData);
+
+ }
+
+ if (AddAdapterStatus == NDIS_STATUS_SUCCESS) {
+ ++AdaptersAdded;
+ }
+
+ }
+
+LoopBottom:
+
+
+ //
+ // Now advance the "Bind" and "Export" values.
+ //
+
+ CurBindValue = (PWCHAR)((PUCHAR)CurBindValue + CurBindString.MaximumLength);
+ CurExportValue = (PWCHAR)((PUCHAR)CurExportValue + CurExportString.MaximumLength);
+
+ }
+
+
+ //
+ // OK, Now dereference all the filter packages. If a MAC or
+ // Miniport driver uses any of these, then the filter package
+ // will reference itself, to keep the image in memory.
+ //
+ ArcDereferencePackage();
+ EthDereferencePackage();
+ FddiDereferencePackage();
+ TrDereferencePackage();
+ MiniportDereferencePackage();
+ NdisMacDereferencePackage();
+
+ //
+ // Now close the handles we opened at the beginning.
+ //
+
+
+ ExFreePool (ConfigurationPath);
+ ExFreePool (BindData);
+ ExFreePool (ExportData);
+
+ //
+ // Succeed if any adapters were added.
+ //
+
+ if (AdaptersAdded > 0) {
+ return NDIS_STATUS_SUCCESS;
+ } else {
+ return NDIS_STATUS_FAILURE;
+ }
+
+#undef BLOCK_LOCK_MINIPORT
+
+}
+
+
+VOID
+NdisReadEisaSlotInformation(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PUINT SlotNumber,
+ OUT PNDIS_EISA_FUNCTION_INFORMATION EisaData
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads the EISA data from the slot given.
+
+Arguments:
+
+ Status - Status of request to be returned to the user.
+ WrapperConfigurationContext - Context passed to MacAddAdapter.
+ SlotNumber - the EISA Slot where the card is at.
+ EisaData - pointer to a buffer where the EISA configuration is to be
+ returned.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_EISA_FUNCTION_INFORMATION EisaBlockPointer;
+ PNDIS_EISA_SLOT_INFORMATION SlotInformation;
+ NTSTATUS NtStatus;
+ ULONG BusNumber;
+ ULONG DataLength;
+ ULONG SearchSlotNumber;
+ ULONG FoundSlotNumber;
+ BOOLEAN Found;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG CompressedId = 0;
+ PWSTR CompressedIDString = L"EisaCompressedId";
+ PWSTR SlotNumberString = L"SlotNumber";
+ PWSTR Parameters = L"\\Parameters";
+ PNDIS_CONFIGURATION_PARAMETER ParameterValue;
+ NDIS_CONFIGURATION_HANDLE NdisConfiguration;
+ ULONG Length;
+ PWSTR PathName;
+
+ //
+ // Get the BusNumber and the BusType from the Context here!!
+ //
+
+ NdisConfiguration.KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+
+ BusType = (NDIS_INTERFACE_TYPE)(NdisConfiguration.KeyQueryTable[3].DefaultType);
+
+ BusNumber = NdisConfiguration.KeyQueryTable[3].DefaultLength;
+
+ //
+ // First check if any bus access is allowed
+ //
+
+ if ((BusType == (NDIS_INTERFACE_TYPE)-1) ||
+ (BusNumber == (ULONG)-1)) {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ SlotInformation = NdisConfiguration.KeyQueryTable[3].DefaultData;
+
+ *SlotNumber = 0;
+
+ if (BusType != Eisa) {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+
+ //
+ // Find the CompressedId for this board.
+ //
+
+ NdisConfiguration.KeyQueryTable[1].Name = CompressedIDString;
+ NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue;
+
+ //
+ // Get the value from the registry; this chains it on to the
+ // parameter list at NdisConfiguration.
+ //
+
+ NtStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ NdisConfiguration.KeyQueryTable[3].Name,
+ NdisConfiguration.KeyQueryTable,
+ &NdisConfiguration, // context
+ NULL);
+
+ if (NtStatus != NDIS_STATUS_SUCCESS) {
+ CompressedId = 0xffffffff;
+ } else if (ParameterValue->ParameterType != NdisParameterInteger) {
+ CompressedId = 0xffffffff;
+ } else {
+ CompressedId = ParameterValue->ParameterData.IntegerData;
+ }
+
+ //
+ // Was there already a buffer allocated?
+ //
+
+ if (SlotInformation == NULL) {
+
+ //
+ // No, allocate a buffer
+ //
+
+ SlotInformation = (PNDIS_EISA_SLOT_INFORMATION)ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ sizeof(NDIS_EISA_FUNCTION_INFORMATION),
+ 'isDN'
+ );
+
+ if (SlotInformation == NULL) {
+
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+
+ }
+
+ //
+ // Free any old buffer
+ //
+
+ if (NdisConfiguration.KeyQueryTable[3].DefaultData != NULL) {
+
+ ExFreePool(NdisConfiguration.KeyQueryTable[3].DefaultData);
+
+ }
+
+ NdisConfiguration.KeyQueryTable[3].DefaultData = SlotInformation;
+
+ }
+
+ //
+ // Now read the slot number
+ //
+
+ NdisConfiguration.KeyQueryTable[1].Name = SlotNumberString;
+ NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue;
+
+ //
+ // Get the value from the registry; this chains it on to the
+ // parameter list at NdisConfiguration.
+ //
+
+ NtStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ NdisConfiguration.KeyQueryTable[3].Name,
+ NdisConfiguration.KeyQueryTable,
+ &NdisConfiguration, // context
+ NULL);
+
+ if ((NtStatus == NDIS_STATUS_SUCCESS) &&
+ (ParameterValue->ParameterType == NdisParameterInteger)) {
+
+ *SlotNumber = ParameterValue->ParameterData.IntegerData;
+
+ } else {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ DataLength = HalGetBusData(
+ EisaConfiguration,
+ BusNumber,
+ *SlotNumber,
+ (PVOID)SlotInformation,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ sizeof(NDIS_EISA_FUNCTION_INFORMATION)
+ );
+
+ if ((CompressedId != 0xFFFFFFFF) &&
+ ((SlotInformation->CompressedId & 0xFFFFFF) != CompressedId)) {
+
+ //
+ // The card seems to have been moved on us. Now we search for it.
+ //
+
+ SearchSlotNumber = 1;
+ Found = FALSE;
+
+ while (TRUE) {
+
+ //
+ // Search this slot
+ //
+ DataLength = HalGetBusData(
+ EisaConfiguration,
+ BusNumber,
+ SearchSlotNumber,
+ (PVOID)SlotInformation,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ sizeof(NDIS_EISA_FUNCTION_INFORMATION)
+ );
+
+ if ((DataLength == 0) ||
+ (SearchSlotNumber == 0xFF)) {
+ //
+ // End of slots.
+ //
+ break;
+
+ }
+
+ if ((SlotInformation->CompressedId & 0xFFFFFF) == CompressedId) {
+
+ //
+ // Found one!
+ //
+
+ if (Found) {
+
+ //
+ // Uh-oh, found two of them! Fail
+ //
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ Found = TRUE;
+ FoundSlotNumber = SearchSlotNumber;
+
+ }
+
+ SearchSlotNumber++;
+
+ }
+
+ if (!Found) {
+ //
+ // No card found
+ //
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ //
+ // Find the SlotNumber parameter in the registry.
+ //
+
+ *SlotNumber = FoundSlotNumber;
+
+ NdisConfiguration.KeyQueryTable[1].Name = SlotNumberString;
+ NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue;
+
+ Length = wcslen(NdisConfiguration.KeyQueryTable[3].Name);
+
+ PathName = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(L"\\Parameters") +
+ (Length * sizeof(WCHAR)) +
+ sizeof(WCHAR),
+ ' DN'
+ );
+
+ if (PathName != NULL) {
+
+ NdisZeroMemory(PathName, sizeof(L"\\Parameters") +
+ (Length * sizeof(WCHAR)) +
+ sizeof(WCHAR)
+ );
+
+ NdisMoveMemory(PathName,
+ NdisConfiguration.KeyQueryTable[3].Name,
+ Length * sizeof(WCHAR)
+ );
+
+ NdisMoveMemory(PathName + Length, Parameters, sizeof(L"\\Parameters"));
+
+ //
+ // Update the value
+ //
+
+ NtStatus = RtlWriteRegistryValue(
+ RTL_REGISTRY_SERVICES,
+ PathName,
+ SlotNumberString,
+ REG_DWORD,
+ &FoundSlotNumber,
+ sizeof(FoundSlotNumber)
+ );
+
+ ExFreePool(PathName);
+
+ }
+
+ //
+ // Get the new information
+ //
+
+ DataLength = HalGetBusData(
+ EisaConfiguration,
+ BusNumber,
+ FoundSlotNumber,
+ (PVOID)SlotInformation,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ sizeof(NDIS_EISA_FUNCTION_INFORMATION)
+ );
+
+ }
+
+ EisaBlockPointer = (PNDIS_EISA_FUNCTION_INFORMATION)
+ ((PUCHAR)SlotInformation + sizeof(CM_EISA_SLOT_INFORMATION));
+
+ *EisaData = *EisaBlockPointer;
+ *Status = NDIS_STATUS_SUCCESS;
+
+}
+
+
+VOID
+NdisReadEisaSlotInformationEx(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PUINT SlotNumber,
+ OUT PNDIS_EISA_FUNCTION_INFORMATION *EisaData,
+ OUT PUINT NumberOfFunctions
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads the EISA data from the slot given.
+
+Arguments:
+
+ Status - Status of request to be returned to the user.
+ WrapperConfigurationContext - Context passed to MacAddAdapter.
+ SlotNumber - the EISA Slot where the card is at.
+ EisaData - pointer to a buffer where the EISA configuration is to be
+ returned.
+ NumberOfFunctions - Returns the number of function structures in the EisaData.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_EISA_FUNCTION_INFORMATION EisaBlockPointer;
+ PNDIS_EISA_SLOT_INFORMATION SlotInformation;
+ NTSTATUS NtStatus;
+ ULONG BusNumber;
+ ULONG DataLength;
+ ULONG SearchSlotNumber;
+ ULONG FoundSlotNumber;
+ BOOLEAN Found;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG CompressedId = 0;
+ PWSTR CompressedIDString = L"EisaCompressedId";
+ PWSTR SlotNumberString = L"SlotNumber";
+ PWSTR Parameters = L"\\Parameters";
+ PNDIS_CONFIGURATION_PARAMETER ParameterValue;
+ NDIS_CONFIGURATION_HANDLE NdisConfiguration;
+ ULONG Length;
+ PWSTR PathName;
+
+ //
+ // Get the BusNumber and the BusType from the Context here!!
+ //
+
+ NdisConfiguration.KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+
+ BusType = (NDIS_INTERFACE_TYPE)(NdisConfiguration.KeyQueryTable[3].DefaultType);
+
+ BusNumber = NdisConfiguration.KeyQueryTable[3].DefaultLength;
+
+ //
+ // First check if any bus access is allowed
+ //
+
+ if ((BusType == (NDIS_INTERFACE_TYPE)-1) ||
+ (BusNumber == (ULONG)-1)) {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ SlotInformation = NdisConfiguration.KeyQueryTable[3].DefaultData;
+
+ *SlotNumber = 0;
+ *NumberOfFunctions = 2;
+
+ if (BusType != Eisa) {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+
+ //
+ // Find the CompressedId for this board.
+ //
+
+ NdisConfiguration.KeyQueryTable[1].Name = CompressedIDString;
+ NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue;
+
+ //
+ // Get the value from the registry; this chains it on to the
+ // parameter list at NdisConfiguration.
+ //
+
+ NtStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ NdisConfiguration.KeyQueryTable[3].Name,
+ NdisConfiguration.KeyQueryTable,
+ &NdisConfiguration, // context
+ NULL);
+
+ if (NtStatus != NDIS_STATUS_SUCCESS) {
+ CompressedId = 0xffffffff;
+ } else if (ParameterValue->ParameterType != NdisParameterInteger) {
+ CompressedId = 0xffffffff;
+ } else {
+ CompressedId = ParameterValue->ParameterData.IntegerData;
+ }
+
+ //
+ // Was there already a buffer allocated?
+ //
+
+ if (SlotInformation == NULL) {
+
+ //
+ // No, allocate a buffer
+ //
+
+ SlotInformation = (PNDIS_EISA_SLOT_INFORMATION)ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ (*NumberOfFunctions *
+ sizeof(NDIS_EISA_FUNCTION_INFORMATION)),
+ 'isDN'
+ );
+
+ if (SlotInformation == NULL) {
+
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+
+ }
+
+ //
+ // Free any old buffer
+ //
+
+ if (NdisConfiguration.KeyQueryTable[3].DefaultData != NULL) {
+
+ ExFreePool(NdisConfiguration.KeyQueryTable[3].DefaultData);
+
+ }
+
+ NdisConfiguration.KeyQueryTable[3].DefaultData = SlotInformation;
+
+ }
+
+ //
+ // Now read the slot number
+ //
+
+ NdisConfiguration.KeyQueryTable[1].Name = SlotNumberString;
+ NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue;
+
+ //
+ // Get the value from the registry; this chains it on to the
+ // parameter list at NdisConfiguration.
+ //
+
+ NtStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ NdisConfiguration.KeyQueryTable[3].Name,
+ NdisConfiguration.KeyQueryTable,
+ &NdisConfiguration, // context
+ NULL);
+
+ if ((NtStatus == NDIS_STATUS_SUCCESS) &&
+ (ParameterValue->ParameterType == NdisParameterInteger)) {
+
+ *SlotNumber = ParameterValue->ParameterData.IntegerData;
+
+ } else {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ DataLength = HalGetBusData(
+ EisaConfiguration,
+ BusNumber,
+ *SlotNumber,
+ (PVOID)SlotInformation,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION))
+ );
+
+ if ((CompressedId != 0xFFFFFFFF) &&
+ ((SlotInformation->CompressedId & 0xFFFFFF) != CompressedId)) {
+
+ //
+ // The card seems to have been moved on us. Now we search for it.
+ //
+
+ SearchSlotNumber = 1;
+ Found = FALSE;
+
+ while (TRUE) {
+
+ //
+ // Search this slot
+ //
+ DataLength = HalGetBusData(
+ EisaConfiguration,
+ BusNumber,
+ SearchSlotNumber,
+ (PVOID)SlotInformation,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION))
+ );
+
+ if ((DataLength == 0) ||
+ (SearchSlotNumber == 0xFF)) {
+ //
+ // End of slots.
+ //
+ break;
+
+ }
+
+ if ((SlotInformation->CompressedId & 0xFFFFFF) == CompressedId) {
+
+ //
+ // Found one!
+ //
+
+ if (Found) {
+
+ //
+ // Uh-oh, found two of them! Fail
+ //
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ Found = TRUE;
+ FoundSlotNumber = SearchSlotNumber;
+
+ }
+
+ SearchSlotNumber++;
+
+ }
+
+ if (!Found) {
+ //
+ // No card found
+ //
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ //
+ // Find the SlotNumber parameter in the registry.
+ //
+
+ *SlotNumber = FoundSlotNumber;
+
+ NdisConfiguration.KeyQueryTable[1].Name = SlotNumberString;
+ NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue;
+
+ Length = wcslen(NdisConfiguration.KeyQueryTable[3].Name);
+
+ PathName = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(L"\\Parameters") +
+ (Length * sizeof(WCHAR)) +
+ sizeof(WCHAR),
+ ' DN'
+ );
+
+ if (PathName != NULL) {
+
+ NdisZeroMemory(PathName, sizeof(L"\\Parameters") +
+ (Length * sizeof(WCHAR)) +
+ sizeof(WCHAR)
+ );
+
+ NdisMoveMemory(PathName,
+ NdisConfiguration.KeyQueryTable[3].Name,
+ Length * sizeof(WCHAR)
+ );
+
+ NdisMoveMemory(PathName + Length, Parameters, sizeof(L"\\Parameters"));
+
+ //
+ // Update the value
+ //
+
+ NtStatus = RtlWriteRegistryValue(
+ RTL_REGISTRY_SERVICES,
+ PathName,
+ SlotNumberString,
+ REG_DWORD,
+ &FoundSlotNumber,
+ sizeof(FoundSlotNumber)
+ );
+
+ ExFreePool(PathName);
+
+ }
+
+ //
+ // Get the new information
+ //
+
+ DataLength = HalGetBusData(
+ EisaConfiguration,
+ BusNumber,
+ FoundSlotNumber,
+ (PVOID)SlotInformation,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION))
+ );
+
+ }
+
+
+ //
+ // Now check for multiple functions in the Eisa data.
+ //
+
+ while (DataLength == (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION))) {
+
+ *NumberOfFunctions++;
+
+ //
+ // Now allocate a new buffer
+ //
+
+ SlotInformation = (PNDIS_EISA_SLOT_INFORMATION)ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ (*NumberOfFunctions *
+ sizeof(NDIS_EISA_FUNCTION_INFORMATION)),
+ 'isDN'
+ );
+
+ if (SlotInformation == NULL) {
+
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+
+ }
+
+ //
+ // Free any old buffer
+ //
+
+ if (NdisConfiguration.KeyQueryTable[3].DefaultData != NULL) {
+
+ ExFreePool(NdisConfiguration.KeyQueryTable[3].DefaultData);
+
+ }
+
+ NdisConfiguration.KeyQueryTable[3].DefaultData = SlotInformation;
+
+ //
+ // Get new information
+ //
+
+ DataLength = HalGetBusData(
+ EisaConfiguration,
+ BusNumber,
+ FoundSlotNumber,
+ (PVOID)SlotInformation,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION))
+ );
+
+ }
+
+ EisaBlockPointer = (PNDIS_EISA_FUNCTION_INFORMATION)
+ ((PUCHAR)SlotInformation + sizeof(CM_EISA_SLOT_INFORMATION));
+
+ *EisaData = EisaBlockPointer;
+ *NumberOfFunctions--; // We overshoot by 1 to verify last one found.
+ *Status = NDIS_STATUS_SUCCESS;
+
+}
+
+
+VOID
+NdisReadMcaPosInformation(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PUINT ChannelNumber,
+ OUT PNDIS_MCA_POS_DATA McaData
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads the MCA data from the POS corresponding to
+ the channel specified.
+
+Arguments:
+
+ WrapperConfigurationContext - Context passed to MacAddAdapter.
+ ChannelNumber - the MCA channel number.
+ McaData - pointer to a buffer where the channel information is to be
+ returned.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ OBJECT_ATTRIBUTES BusObjectAttributes;
+ PWSTR McaPath = L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter";
+ PWSTR ConfigData = L"Configuration Data";
+ PWSTR PosIdString = L"McaPosId";
+ PWSTR SlotNumberString = L"SlotNumber";
+ UNICODE_STRING RootName;
+ UNICODE_STRING BusName;
+ UNICODE_STRING ConfigDataName;
+ NTSTATUS NtStatus;
+ PKEY_BASIC_INFORMATION BasicInformation;
+ PKEY_VALUE_FULL_INFORMATION ValueInformation;
+ PUCHAR BufferPointer;
+ PCM_FULL_RESOURCE_DESCRIPTOR FullResource;
+ PCM_PARTIAL_RESOURCE_LIST ResourceList;
+ PNDIS_MCA_POS_DATA McaBlockPointer;
+ HANDLE McaHandle, BusHandle;
+ ULONG BytesWritten, BytesNeeded;
+ ULONG Index;
+ ULONG i;
+ ULONG BusNumber;
+ ULONG MaxSlotNumber;
+ ULONG SearchSlotNumber;
+ ULONG FoundSlotNumber;
+ BOOLEAN Found;
+ USHORT PosId;
+ NDIS_INTERFACE_TYPE BusType;
+ NDIS_CONFIGURATION_HANDLE NdisConfiguration;
+ PNDIS_CONFIGURATION_PARAMETER ParameterValue;
+ PWSTR Parameters = L"\\Parameters";
+ ULONG Length;
+ PWSTR PathName;
+
+ *Status = NDIS_STATUS_FAILURE;
+
+ NdisConfiguration.KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+
+ //
+ // Get the BusNumber and the BusType from the Context here!!
+ //
+
+ BusType = (NDIS_INTERFACE_TYPE)(NdisConfiguration.KeyQueryTable[3].DefaultType);
+ BusNumber = NdisConfiguration.KeyQueryTable[3].DefaultLength;
+
+ //
+ // First check if any bus access is allowed
+ //
+
+ if ((BusType == (NDIS_INTERFACE_TYPE)-1) ||
+ (BusNumber == (ULONG)-1)) {
+
+ return;
+
+ }
+
+
+ if (BusType != MicroChannel) {
+
+ return;
+
+ }
+
+ *ChannelNumber = 0;
+
+ //
+ // Find the PosId for this board.
+ //
+
+ NdisConfiguration.KeyQueryTable[1].Name = PosIdString;
+ NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue;
+
+ //
+ // Get the value from the registry; this chains it on to the
+ // parameter list at NdisConfiguration.
+ //
+
+ NtStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ NdisConfiguration.KeyQueryTable[3].Name,
+ NdisConfiguration.KeyQueryTable,
+ &NdisConfiguration, // context
+ NULL);
+
+ if (NtStatus != NDIS_STATUS_SUCCESS) {
+ PosId = 0xffff;
+ } else if (ParameterValue->ParameterType != NdisParameterInteger) {
+ PosId = 0xffff;
+ } else {
+ PosId = (USHORT)(ParameterValue->ParameterData.IntegerData);
+ }
+
+ RtlInitUnicodeString(
+ &RootName,
+ McaPath
+ );
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &RootName,
+ OBJ_CASE_INSENSITIVE,
+ (HANDLE)NULL,
+ NULL
+ );
+
+ //
+ // Open the root.
+ //
+
+ NtStatus = ZwOpenKey(
+ &McaHandle,
+ KEY_READ,
+ &ObjectAttributes
+ );
+
+ if (!NT_SUCCESS(NtStatus)) {
+
+ return;
+
+ }
+
+ Index = 0;
+
+ while (TRUE) {
+
+ //
+ // Enumerate through keys, searching for the proper bus number
+ //
+
+ NtStatus = ZwEnumerateKey(
+ McaHandle,
+ Index,
+ KeyBasicInformation,
+ NULL,
+ 0,
+ &BytesNeeded
+ );
+
+ //
+ // That should fail!
+ //
+
+ if (BytesNeeded == 0) {
+
+ Index++;
+ continue;
+
+ }
+
+ BasicInformation = (PKEY_BASIC_INFORMATION)ExAllocatePoolWithTag(
+ NonPagedPool,
+ BytesNeeded,
+ ' DN'
+ );
+
+ if (BasicInformation == NULL) {
+
+ ZwClose(McaHandle);
+
+ return;
+ }
+
+ NtStatus = ZwEnumerateKey(
+ McaHandle,
+ Index,
+ KeyBasicInformation,
+ BasicInformation,
+ BytesNeeded,
+ &BytesWritten
+ );
+
+ if (!NT_SUCCESS(NtStatus)) {
+
+ ExFreePool(BasicInformation);
+
+ ZwClose(McaHandle);
+
+ return;
+ }
+
+
+ //
+ // Init the BusName String
+ //
+
+ BusName.MaximumLength = (USHORT)BasicInformation->NameLength;
+ BusName.Length = (USHORT)BasicInformation->NameLength;
+ BusName.Buffer = BasicInformation->Name;
+
+ //
+ // Now try to find Configuration Data within this Key
+ //
+
+ InitializeObjectAttributes(
+ &BusObjectAttributes,
+ &BusName,
+ OBJ_CASE_INSENSITIVE,
+ (HANDLE)McaHandle,
+ NULL
+ );
+
+ //
+ // Open the MCA root + Bus Number
+ //
+
+ NtStatus = ZwOpenKey(
+ &BusHandle,
+ KEY_READ,
+ &BusObjectAttributes
+ );
+
+ ExFreePool(BasicInformation);
+
+ if (!NT_SUCCESS(NtStatus)) {
+
+ Index++;
+
+ continue;
+
+ }
+
+ //
+ // opening the configuration data. This first call tells us how
+ // much memory we need to allocate
+ //
+
+ RtlInitUnicodeString(
+ &ConfigDataName,
+ ConfigData
+ );
+
+ //
+ // This should fail
+ //
+
+ NtStatus = ZwQueryValueKey(
+ BusHandle,
+ &ConfigDataName,
+ KeyValueFullInformation,
+ NULL,
+ 0,
+ &BytesNeeded
+ );
+
+
+ ValueInformation = (PKEY_VALUE_FULL_INFORMATION)ExAllocatePoolWithTag(
+ NonPagedPool,
+ BytesNeeded,
+ ' DN'
+ );
+
+
+ if (ValueInformation == NULL) {
+
+ Index++;
+
+ ZwClose(BusHandle);
+
+ continue;
+
+ }
+
+ NtStatus = ZwQueryValueKey(
+ BusHandle,
+ &ConfigDataName,
+ KeyValueFullInformation,
+ ValueInformation,
+ BytesNeeded,
+ &BytesWritten
+ );
+
+ if (!NT_SUCCESS(NtStatus)) {
+
+ Index++;
+
+ ExFreePool(ValueInformation);
+
+ ZwClose(BusHandle);
+
+ continue;
+
+ }
+
+ //
+ // Search for our bus number and type
+ //
+
+
+ //
+ // What we got back from the registry is actually a blob of data that
+ // looks like this
+ //
+ // ------------------------------------------
+ // |FULL |PAR |PAR |MCA |MCA |MCA |
+ // |RES. |RES |RES |POS |POS |POS | . . .
+ // |DESC |LIST|DESC|DATA|DATA|DATA|
+ // ------------------------------------------
+ // slot 0 1 2 . . .
+ //
+ // Out of this mess we need to grovel a pointer to the first block
+ // of MCA_POS_DATA, then we can just index by slot number.
+ //
+
+ BufferPointer = ((PUCHAR)ValueInformation) + ValueInformation->DataOffset;
+ FullResource = (PCM_FULL_RESOURCE_DESCRIPTOR) BufferPointer;
+
+ if (FullResource->InterfaceType != MicroChannel) {
+
+ //
+ // Get next key
+ //
+
+ ExFreePool(ValueInformation);
+
+ Index++;
+
+ ZwClose(BusHandle);
+
+ continue;
+
+ }
+
+ if (FullResource->BusNumber != BusNumber) {
+
+ //
+ // Get next key
+ //
+
+ ExFreePool(ValueInformation);
+
+ Index++;
+
+ ZwClose(BusHandle);
+
+ continue;
+
+ }
+
+
+ //
+ // Found it!!
+ //
+
+ ResourceList = &FullResource->PartialResourceList;
+
+ //
+ // Find the device-specific information, which is where the POS data is.
+ //
+
+ for (i=0; i<ResourceList->Count; i++) {
+ if (ResourceList->PartialDescriptors[i].Type == CmResourceTypeDeviceSpecific) {
+ break;
+ }
+ }
+
+ if (i == ResourceList->Count) {
+ //
+ // Couldn't find device-specific information.
+ //
+
+#if DBG
+ DbgPrint("NDIS: couldn't find POS data in registry\n");
+#endif
+
+ ExFreePool(ValueInformation);
+ *Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+ return;
+
+ }
+
+ //
+ // Was there a buffer already there?
+ //
+
+ if (NdisConfiguration.KeyQueryTable[3].DefaultData != NULL) {
+
+ //
+ // Free it
+ //
+
+ ExFreePool(NdisConfiguration.KeyQueryTable[3].DefaultData);
+
+ }
+
+ //
+ // Now read the slot number
+ //
+
+ NdisConfiguration.KeyQueryTable[1].Name = SlotNumberString;
+ NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue;
+
+ //
+ // Get the value from the registry; this chains it on to the
+ // parameter list at NdisConfiguration.
+ //
+
+ NtStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ NdisConfiguration.KeyQueryTable[3].Name,
+ NdisConfiguration.KeyQueryTable,
+ &NdisConfiguration, // context
+ NULL);
+
+ if ((NtStatus == NDIS_STATUS_SUCCESS) &&
+ (ParameterValue->ParameterType == NdisParameterInteger)) {
+
+ *ChannelNumber = ParameterValue->ParameterData.IntegerData;
+
+ } else {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ //
+ // Store buffer
+ //
+
+ NdisConfiguration.KeyQueryTable[3].DefaultData = ValueInformation;
+
+ McaBlockPointer = (PNDIS_MCA_POS_DATA)(&ResourceList->PartialDescriptors[i+1]);
+ MaxSlotNumber = ResourceList->PartialDescriptors[i].u.DeviceSpecificData.DataSize /
+ sizeof(NDIS_MCA_POS_DATA);
+
+ *McaData = *(McaBlockPointer + (*ChannelNumber) - 1);
+
+ if ((PosId != 0xFFFF) &&
+ (McaData->AdapterId != PosId)) {
+
+ //
+ // The card seems to have been moved on us. Now we search for it.
+ //
+
+ SearchSlotNumber = 1;
+ Found = FALSE;
+
+ while (SearchSlotNumber <= MaxSlotNumber) {
+
+ *McaData = *(McaBlockPointer + (SearchSlotNumber - 1));
+
+ if (McaData->AdapterId == PosId) {
+
+ //
+ // Found one!
+ //
+
+ if (Found) {
+
+ //
+ // Uh-oh, found two of them! Fail
+ //
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ Found = TRUE;
+ FoundSlotNumber = SearchSlotNumber;
+
+ }
+
+ SearchSlotNumber++;
+
+ }
+
+ if (!Found) {
+ //
+ // No card found
+ //
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ //
+ // Find the SlotNumber parameter in the registry.
+ //
+
+ *ChannelNumber = FoundSlotNumber;
+
+ NdisConfiguration.KeyQueryTable[1].Name = SlotNumberString;
+ NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue;
+
+ Length = wcslen(NdisConfiguration.KeyQueryTable[3].Name);
+
+ PathName = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(L"\\Parameters") +
+ (Length * sizeof(WCHAR)) +
+ sizeof(WCHAR),
+ ' DN'
+ );
+
+ if (PathName != NULL) {
+
+ NdisZeroMemory(PathName, sizeof(L"\\Parameters") +
+ (Length * sizeof(WCHAR)) +
+ sizeof(WCHAR)
+ );
+
+ NdisMoveMemory(PathName,
+ NdisConfiguration.KeyQueryTable[3].Name,
+ Length * sizeof(WCHAR)
+ );
+
+ NdisMoveMemory(PathName + Length, Parameters, sizeof(L"\\Parameters"));
+
+ //
+ // Update the value
+ //
+
+ NtStatus = RtlWriteRegistryValue(
+ RTL_REGISTRY_SERVICES,
+ PathName,
+ SlotNumberString,
+ REG_DWORD,
+ &FoundSlotNumber,
+ sizeof(FoundSlotNumber)
+ );
+
+ ExFreePool(PathName);
+
+ }
+
+ //
+ // Update the value
+ //
+ NtStatus = RtlWriteRegistryValue(
+ RTL_REGISTRY_SERVICES,
+ NdisConfiguration.KeyQueryTable[3].Name,
+ SlotNumberString,
+ REG_DWORD,
+ &FoundSlotNumber,
+ sizeof(FoundSlotNumber)
+ );
+
+ //
+ // Get the new information
+ //
+
+ *McaData = *(McaBlockPointer + (FoundSlotNumber - 1));
+
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ ZwClose(McaHandle);
+
+ return;
+
+ }
+
+}
+
+#if !defined(BUILD_FOR_3_1)
+
+NDIS_STATUS
+NdisPciAssignResources(
+ IN NDIS_HANDLE NdisMacHandle,
+ IN NDIS_HANDLE NdisWrapperHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SlotNumber,
+ OUT PNDIS_RESOURCE_LIST *AssignedResources
+ )
+/*++
+
+Routine Description:
+
+ This routine uses the Hal to assign a set of resources to a PCI
+ device.
+
+Arguments:
+
+ NdisMacHandle - Handle returned from NdisRegisterMac.
+
+ NdisWrapperHandle - Handle returned from NdisInitializeWrapper.
+
+ WrapperConfigurationContext - Handle passed to MacAddAdapter.
+
+ SlotNumber - Slot number of the device.
+
+ AssignedResources - The returned resources.
+
+Return Value:
+
+ Status of the operation
+
+--*/
+{
+ NTSTATUS NtStatus;
+ ULONG BusNumber;
+ NDIS_INTERFACE_TYPE BusType;
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable;
+ PCM_RESOURCE_LIST AllocatedResources = NULL;
+ PNDIS_WRAPPER_HANDLE NdisMacInfo = (PNDIS_WRAPPER_HANDLE)NdisWrapperHandle;
+
+ //
+ // Get the BusNumber and the BusType from the Context here!!
+ //
+
+ KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+
+ BusType = (NDIS_INTERFACE_TYPE)KeyQueryTable[3].DefaultType;
+
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ NtStatus = HalAssignSlotResources (
+ (PUNICODE_STRING)(NdisMacInfo->NdisWrapperConfigurationHandle),
+ NULL,
+ NdisMacInfo->NdisWrapperDriver,
+ NULL,
+ BusType,
+ BusNumber,
+ SlotNumber,
+ &AllocatedResources
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+ *AssignedResources = NULL;
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // Store resources into the driver wide block
+ //
+ ((PNDIS_MAC_BLOCK)NdisMacHandle)->PciAssignedResources = AllocatedResources;
+
+ *AssignedResources = &(AllocatedResources->List[0].PartialResourceList);
+
+ return(NDIS_STATUS_SUCCESS);
+
+}
+
+
+
+ULONG
+NdisReadPciSlotInformation(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This routine reads from the PCI configuration space a specified
+ length of bytes at a certain offset.
+
+Arguments:
+
+ NdisAdapterHandle - Adapter we are talking about.
+
+ SlotNumber - The slot number of the device.
+
+ Offset - Offset to read from
+
+ Buffer - Place to store the bytes
+
+ Length - Number of bytes to read
+
+Return Value:
+
+ Returns the number of bytes read.
+
+--*/
+{
+ PNDIS_ADAPTER_BLOCK Adapter = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle;
+ ULONG DataLength;
+
+ if (Adapter->DeviceObject == NULL) {
+
+ //
+ // This is a mini-port
+ //
+
+#if DBG
+ ASSERT(Miniport->BusType == NdisInterfacePci);
+#endif
+
+ DataLength = HalGetBusDataByOffset(
+ PCIConfiguration,
+ Miniport->BusNumber,
+ SlotNumber,
+ Buffer,
+ Offset,
+ Length
+ );
+
+ return(DataLength);
+
+ } else {
+
+#if DBG
+ ASSERT(Adapter->BusType == NdisInterfacePci);
+#endif
+
+ DataLength = HalGetBusDataByOffset(
+ PCIConfiguration,
+ Adapter->BusNumber,
+ SlotNumber,
+ Buffer,
+ Offset,
+ Length
+ );
+
+ return(DataLength);
+
+ }
+
+}
+
+ULONG
+NdisWritePciSlotInformation(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This routine writes to the PCI configuration space a specified
+ length of bytes at a certain offset.
+
+Arguments:
+
+ NdisAdapterHandle - Adapter we are talking about.
+
+ SlotNumber - The slot number of the device.
+
+ Offset - Offset to read from
+
+ Buffer - Place to store the bytes
+
+ Length - Number of bytes to read
+
+Return Value:
+
+ Returns the number of bytes written.
+
+--*/
+{
+ PNDIS_ADAPTER_BLOCK Adapter = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle;
+ ULONG DataLength;
+
+ if (Adapter->DeviceObject == NULL) {
+
+ //
+ // This is a mini-port
+ //
+
+#if DBG
+ ASSERT(Miniport->BusType == NdisInterfacePci);
+#endif
+
+ DataLength = HalSetBusDataByOffset(
+ PCIConfiguration,
+ Miniport->BusNumber,
+ SlotNumber,
+ Buffer,
+ Offset,
+ Length
+ );
+
+ return(DataLength);
+
+ } else {
+
+#if DBG
+ ASSERT(Adapter->BusType == NdisInterfacePci);
+#endif
+
+ DataLength = HalSetBusDataByOffset(
+ PCIConfiguration,
+ Adapter->BusNumber,
+ SlotNumber,
+ Buffer,
+ Offset,
+ Length
+ );
+
+ return(DataLength);
+
+ }
+
+}
+
+#else // !defined(BUILD_FOR_3_1)
+
+NDIS_STATUS
+NdisPciAssignResources(
+ IN NDIS_HANDLE NdisMacHandle,
+ IN NDIS_HANDLE NdisWrapperHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SlotNumber,
+ OUT PNDIS_RESOURCE_LIST *AssignedResources
+ )
+{
+ return NDIS_STATUS_FAILURE;
+}
+
+ULONG
+NdisReadPciSlotInformation(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+{
+ return 0;
+}
+
+ULONG
+NdisWritePciSlotInformation(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+{
+ return 0;
+}
+
+#endif // else !defined(BUILD_FOR_3_1)
+
+
+VOID
+NdisOpenFile(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE FileHandle,
+ OUT PUINT FileLength,
+ IN PNDIS_STRING FileName,
+ IN NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine opens a file for future mapping and reads its contents
+ into allocated memory.
+
+Arguments:
+
+ Status - The status of the operation
+
+ FileHandle - A handle to be associated with this open
+
+ FileLength - Returns the length of the file
+
+ FileName - The name of the file
+
+ HighestAcceptableAddress - The highest physical address at which
+ the memory for the file can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ NTSTATUS NtStatus;
+ IO_STATUS_BLOCK IoStatus;
+ HANDLE NtFileHandle;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ ULONG LengthOfFile;
+ WCHAR PathPrefix[] = L"\\SystemRoot\\system32\\drivers\\";
+ NDIS_STRING FullFileName;
+ ULONG FullFileNameLength;
+ PNDIS_FILE_DESCRIPTOR FileDescriptor;
+ PVOID FileImage;
+
+ //
+ // This structure represents the data from the
+ // NtQueryInformationFile API with an information
+ // class of FileStandardInformation.
+ //
+
+ FILE_STANDARD_INFORMATION StandardInfo;
+
+
+ //
+ // Insert the correct path prefix.
+ //
+
+ FullFileNameLength = sizeof(PathPrefix) + FileName->MaximumLength;
+ FullFileName.Buffer = ExAllocatePoolWithTag (NonPagedPool, FullFileNameLength, ' DN');
+
+ if (FullFileName.Buffer == NULL) {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+ FullFileName.Length = sizeof (PathPrefix) - sizeof(WCHAR);
+ FullFileName.MaximumLength = (USHORT)FullFileNameLength;
+ RtlCopyMemory (FullFileName.Buffer, PathPrefix, sizeof(PathPrefix));
+
+ RtlAppendUnicodeStringToString (&FullFileName, FileName);
+
+#if DBG
+ DbgPrint ("NDIS: Attempting to open %Z\n", &FullFileName);
+#endif
+
+ InitializeObjectAttributes (
+ &ObjectAttributes,
+ &FullFileName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ NtStatus = ZwCreateFile(
+ &NtFileHandle,
+ SYNCHRONIZE | FILE_READ_DATA,
+ &ObjectAttributes,
+ &IoStatus,
+ NULL,
+ 0,
+ FILE_SHARE_READ,
+ FILE_OPEN,
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0
+ );
+
+ if (!NT_SUCCESS(NtStatus)) {
+#if DBG
+ DbgPrint ("Error opening file %x\n", NtStatus);
+#endif
+ ExFreePool (FullFileName.Buffer);
+ *Status = NDIS_STATUS_FILE_NOT_FOUND;
+ return;
+ }
+
+ ExFreePool (FullFileName.Buffer);
+
+ //
+ // Query the object to determine its length.
+ //
+
+ NtStatus = ZwQueryInformationFile(
+ NtFileHandle,
+ &IoStatus,
+ &StandardInfo,
+ sizeof(FILE_STANDARD_INFORMATION),
+ FileStandardInformation
+ );
+
+ if (!NT_SUCCESS(NtStatus)) {
+#if DBG
+ DbgPrint ("Error querying info on file %x\n", NtStatus);
+#endif
+ ZwClose(NtFileHandle);
+ *Status = NDIS_STATUS_ERROR_READING_FILE;
+ return;
+ }
+
+ LengthOfFile = StandardInfo.EndOfFile.LowPart;
+
+#if DBG
+ DbgPrint ("File length is %d\n", LengthOfFile);
+#endif
+
+ //
+ // Might be corrupted.
+ //
+
+ if (LengthOfFile < 1) {
+#if DBG
+ DbgPrint ("Bad file length %d\n", LengthOfFile);
+#endif
+ ZwClose(NtFileHandle);
+ *Status = NDIS_STATUS_ERROR_READING_FILE;
+ return;
+ }
+
+ //
+ // Allocate buffer for this file
+ //
+
+ FileImage = ExAllocatePoolWithTag(NonPagedPool, LengthOfFile, ' DN');
+
+ if (FileImage == NULL) {
+
+#if DBG
+ DbgPrint ("Could not allocate buffer\n");
+#endif
+ ZwClose(NtFileHandle);
+ *Status = NDIS_STATUS_ERROR_READING_FILE;
+ return;
+
+ }
+
+ //
+ // Read the file into our buffer.
+ //
+
+ NtStatus = ZwReadFile(
+ NtFileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ FileImage,
+ LengthOfFile,
+ NULL,
+ NULL
+ );
+
+ ZwClose(NtFileHandle);
+
+ if ((!NT_SUCCESS(NtStatus)) || (IoStatus.Information != LengthOfFile)) {
+#if DBG
+ DbgPrint ("error reading file %x\n", NtStatus);
+#endif
+ *Status = NDIS_STATUS_ERROR_READING_FILE;
+ ExFreePool(FileImage);
+ return;
+ }
+
+ //
+ // Allocate a structure to describe the file.
+ //
+
+ FileDescriptor = ExAllocatePoolWithTag (NonPagedPool, sizeof(NDIS_FILE_DESCRIPTOR), ' DN');
+
+ if (FileDescriptor == NULL) {
+ *Status = NDIS_STATUS_RESOURCES;
+ ExFreePool(FileImage);
+ return;
+ }
+
+
+ FileDescriptor->Data = FileImage;
+ NdisAllocateSpinLock (&FileDescriptor->Lock);
+ FileDescriptor->Mapped = FALSE;
+
+ *FileHandle = (NDIS_HANDLE)FileDescriptor;
+ *FileLength = LengthOfFile;
+ *Status = STATUS_SUCCESS;
+
+}
+
+
+VOID
+NdisCloseFile(
+ IN NDIS_HANDLE FileHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine closes a file previously opened with NdisOpenFile.
+ The file is unmapped if needed and the memory is freed.
+
+Arguments:
+
+ FileHandle - The handle returned by NdisOpenFile
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_FILE_DESCRIPTOR FileDescriptor = (PNDIS_FILE_DESCRIPTOR)FileHandle;
+
+ ExFreePool (FileDescriptor->Data);
+ ExFreePool (FileDescriptor);
+
+}
+
+
+VOID
+NdisMapFile(
+ OUT PNDIS_STATUS Status,
+ OUT PVOID * MappedBuffer,
+ IN NDIS_HANDLE FileHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine maps an open file, so that the contents can be accessed.
+ Files can only have one active mapping at any time.
+
+Arguments:
+
+ Status - The status of the operation
+
+ MappedBuffer - Returns the virtual address of the mapping.
+
+ FileHandle - The handle returned by NdisOpenFile.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_FILE_DESCRIPTOR FileDescriptor = (PNDIS_FILE_DESCRIPTOR)FileHandle;
+
+ ACQUIRE_SPIN_LOCK(&FileDescriptor->Lock);
+
+ if (FileDescriptor->Mapped == TRUE) {
+ *Status = NDIS_STATUS_ALREADY_MAPPED;
+ RELEASE_SPIN_LOCK (&FileDescriptor->Lock);
+ return;
+ }
+
+ FileDescriptor->Mapped = TRUE;
+ RELEASE_SPIN_LOCK (&FileDescriptor->Lock);
+
+ *MappedBuffer = FileDescriptor->Data;
+ *Status = STATUS_SUCCESS;
+
+}
+
+
+VOID
+NdisUnmapFile(
+ IN NDIS_HANDLE FileHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine unmaps a file previously mapped with NdisOpenFile.
+ The file is unmapped if needed and the memory is freed.
+
+Arguments:
+
+ FileHandle - The handle returned by NdisOpenFile
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_FILE_DESCRIPTOR FileDescriptor = (PNDIS_FILE_DESCRIPTOR)FileHandle;
+
+ FileDescriptor->Mapped = FALSE;
+
+}
+
+
+#if defined(_ALPHA_)
+VOID
+NdisCreateLookaheadBufferFromSharedMemory(
+ IN PVOID pSharedMemory,
+ IN UINT LookaheadLength,
+ OUT PVOID *pLookaheadBuffer
+ )
+/*++
+
+Routine Description:
+
+ This routine creates a lookahead buffer from a pointer to shared
+ RAM because some architectures (like ALPHA) do not allow access
+ through a pointer to shared ram.
+
+Arguments:
+
+ pSharedMemory - Pointer to shared ram space.
+
+ LookaheadLength - Amount of Lookahead to copy.
+
+ pLookaheadBuffer - Pointer to host memory space with a copy of the
+ stuff in pSharedMemory.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_LOOKAHEAD_ELEMENT TmpElement;
+
+ ACQUIRE_SPIN_LOCK(&NdisLookaheadBufferLock);
+
+ if (NdisLookaheadBufferLength < (LookaheadLength +
+ sizeof(NDIS_LOOKAHEAD_ELEMENT))) {
+
+ //
+ // Free current list
+ //
+ while (NdisLookaheadBufferList != NULL) {
+
+ TmpElement = NdisLookaheadBufferList;
+ NdisLookaheadBufferList = NdisLookaheadBufferList->Next;
+
+ ExFreePool ( TmpElement ) ;
+
+ }
+
+ NdisLookaheadBufferLength = LookaheadLength +
+ sizeof(NDIS_LOOKAHEAD_ELEMENT);
+
+ }
+
+ if (NdisLookaheadBufferList == NULL) {
+
+ NdisLookaheadBufferList = (PNDIS_LOOKAHEAD_ELEMENT)ExAllocatePoolWithTag(
+ NonPagedPool,
+ NdisLookaheadBufferLength,
+ 'blDN'
+ );
+
+ if (NdisLookaheadBufferList == NULL) {
+
+ *pLookaheadBuffer = NULL;
+ RELEASE_SPIN_LOCK(&NdisLookaheadBufferLock);
+ return;
+
+ }
+
+ NdisLookaheadBufferList->Next = NULL;
+ NdisLookaheadBufferList->Length = NdisLookaheadBufferLength;
+
+ }
+
+
+ //
+ // Get the buffer
+ //
+
+ *pLookaheadBuffer = (PVOID)(NdisLookaheadBufferList + 1);
+ NdisLookaheadBufferList = NdisLookaheadBufferList->Next;
+
+ RELEASE_SPIN_LOCK(&NdisLookaheadBufferLock);
+
+ //
+ // Copy the stuff across
+ //
+
+ READ_REGISTER_BUFFER_UCHAR(pSharedMemory, *pLookaheadBuffer, LookaheadLength);
+
+}
+
+
+VOID
+NdisDestroyLookaheadBufferFromSharedMemory(
+ IN PVOID pLookaheadBuffer
+ )
+/*++
+
+Routine Description:
+
+ This routine returns resources associated with a lookahead buffer.
+
+Arguments:
+
+ pLookaheadBuffer - Lookahead buffer created by
+ CreateLookaheadBufferFromSharedMemory.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_LOOKAHEAD_ELEMENT Element = (PNDIS_LOOKAHEAD_ELEMENT)pLookaheadBuffer;
+
+ Element--;
+
+ if (Element->Length != NdisLookaheadBufferLength) {
+
+ ExFreePool(Element);
+
+ } else {
+
+ ACQUIRE_SPIN_LOCK(&NdisLookaheadBufferLock);
+
+ Element->Next = NdisLookaheadBufferList;
+ NdisLookaheadBufferList = Element;
+
+ RELEASE_SPIN_LOCK(&NdisLookaheadBufferLock);
+
+ }
+
+}
+
+#endif // _ALPHA_
+
+
+BOOLEAN CheckPortUsage(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG PortNumber,
+ IN ULONG Length,
+ IN PDRIVER_OBJECT DriverObject
+)
+/*++
+
+Routine Description:
+
+ This routine checks if a port is currently in use somewhere in the
+ system via IoReportUsage -- which fails if there is a conflict.
+
+Arguments:
+
+ InterfaceType - The bus type (ISA, EISA)
+ BusNumber - Bus number in the system
+ PortNumber - Address of the port to access.
+ Length - Number of ports from the base address to access.
+
+Return Value:
+
+ FALSE if there is a conflict, else TRUE
+
+--*/
+
+{
+ NTSTATUS NtStatus;
+ BOOLEAN Conflict;
+ NTSTATUS FirstNtStatus;
+ BOOLEAN FirstConflict;
+ PCM_RESOURCE_LIST Resources;
+
+ //
+ // Allocate space for resources
+ //
+
+ Resources = (PCM_RESOURCE_LIST)ExAllocatePool(
+ NonPagedPool,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)
+ );
+
+ if (Resources == NULL) {
+
+ //
+ // Error out
+ //
+
+ return(FALSE);
+
+ }
+
+ Resources->Count = 1;
+ Resources->List[0].InterfaceType = InterfaceType;
+ Resources->List[0].BusNumber = BusNumber;
+ Resources->List[0].PartialResourceList.Version = 0;
+ Resources->List[0].PartialResourceList.Revision = 0;
+ Resources->List[0].PartialResourceList.Count = 1;
+
+ //
+ // Setup port
+ //
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].Type = CmResourceTypePort;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].ShareDisposition = CmResourceShareDriverExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].Flags =
+ (InterfaceType == Internal)?
+ CM_RESOURCE_PORT_MEMORY :
+ CM_RESOURCE_PORT_IO;
+#if !defined(BUILD_FOR_3_1)
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Start.QuadPart = PortNumber;
+#else
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Start =
+ RtlConvertUlongToLargeInteger((ULONG)(PortNumber));
+#endif
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Length =
+ Length;
+
+ //
+ // Submit Resources
+ //
+
+ FirstNtStatus = IoReportResourceUsage(
+ NULL,
+ DriverObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ NULL,
+ NULL,
+ 0,
+ TRUE,
+ &FirstConflict
+ );
+
+ //
+ // Now clear it out
+ //
+ Resources->List[0].PartialResourceList.Count = 0;
+
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ DriverObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ NULL,
+ NULL,
+ 0,
+ TRUE,
+ &Conflict
+ );
+
+ ExFreePool(Resources);
+
+ //
+ // Check for conflict.
+ //
+
+ if (FirstConflict || (FirstNtStatus != STATUS_SUCCESS)) {
+
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+NTSTATUS
+StartMapping(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG InitialAddress,
+ IN ULONG Length,
+ OUT PVOID *InitialMapping,
+ OUT PBOOLEAN Mapped
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initialize the mapping of a address into virtual
+ space dependent on the bus number, etc.
+
+Arguments:
+
+ InterfaceType - The bus type (ISA, EISA)
+ BusNumber - Bus number in the system
+ InitialAddress - Address to access.
+ Length - Number of bytes from the base address to access.
+ InitialMapping - The virtual address space to use when accessing the
+ address.
+ Mapped - Did an MmMapIoSpace() take place.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ PHYSICAL_ADDRESS Address;
+ PHYSICAL_ADDRESS InitialPhysAddress;
+ ULONG addressSpace;
+
+ //
+ // Get the system physical address for this card. The card uses
+ // I/O space, except for "internal" Jazz devices which use
+ // memory space.
+ //
+
+ *Mapped = FALSE;
+
+ addressSpace = (InterfaceType == Internal) ? 0 : 1;
+
+ InitialPhysAddress.LowPart = InitialAddress;
+
+ InitialPhysAddress.HighPart = 0;
+
+ if ( !HalTranslateBusAddress(
+ InterfaceType, // InterfaceType
+ BusNumber, // BusNumber
+ InitialPhysAddress, // Bus Address
+ &addressSpace, // AddressSpace
+ &Address // Translated address
+ ) ) {
+
+ //
+ // It would be nice to return a better status here, but we only get
+ // TRUE/FALSE back from HalTranslateBusAddress.
+ //
+
+ return NDIS_STATUS_FAILURE;
+ }
+
+ if (addressSpace == 0) {
+
+ //
+ // memory space
+ //
+
+ *InitialMapping = MmMapIoSpace(
+ Address,
+ Length,
+ FALSE
+ );
+
+ if (*InitialMapping == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ *Mapped = TRUE;
+
+ } else {
+
+ //
+ // I/O space
+ //
+
+ *InitialMapping = (PVOID)Address.LowPart;
+
+ }
+
+ return(STATUS_SUCCESS);
+
+}
+
+
+NTSTATUS
+EndMapping(
+ IN PVOID InitialMapping,
+ IN ULONG Length,
+ IN BOOLEAN Mapped
+ )
+
+/*++
+
+Routine Description:
+
+ This routine undoes the mapping of an address into virtual
+ space dependent on the bus number, etc.
+
+Arguments:
+
+ InitialMapping - The virtual address space to use when accessing the
+ address.
+ Length - Number of bytes from the base address to access.
+ Mapped - Do we need to call MmUnmapIoSpace.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+
+ if (Mapped) {
+
+ //
+ // memory space
+ //
+
+ MmUnmapIoSpace(InitialMapping, Length);
+
+ }
+
+ return(STATUS_SUCCESS);
+
+}
+
+
+VOID
+NdisImmediateReadPortUchar(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ OUT PUCHAR Data
+ )
+/*++
+
+Routine Description:
+
+ This routine reads from a port a UCHAR. It does all the mapping,
+ etc, to do the read here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ Port - Port number to read from.
+
+ Data - Pointer to place to store the result.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID PortMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NTSTATUS Status;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the port is available.
+ //
+ if (CheckPortUsage(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(UCHAR),
+ DriverObject
+ ) == FALSE) {
+
+ *Data = (UCHAR)0xFF;
+ return;
+
+ }
+
+ //
+ // Map the space
+ //
+
+ Status = StartMapping(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(UCHAR),
+ &PortMapping,
+ &Mapped
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ *Data = (UCHAR)0xFF;
+ return;
+
+ }
+
+ //
+ // Read from the port
+ //
+
+ *Data = READ_PORT_UCHAR((PUCHAR)PortMapping);
+
+ //
+ // End port mapping
+ //
+
+ EndMapping(
+ PortMapping,
+ sizeof(UCHAR),
+ Mapped
+ );
+
+}
+
+VOID
+NdisImmediateReadPortUshort(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ OUT PUSHORT Data
+ )
+/*++
+
+Routine Description:
+
+ This routine reads from a port a USHORT. It does all the mapping,
+ etc, to do the read here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ Port - Port number to read from.
+
+ Data - Pointer to place to store the result.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID PortMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NTSTATUS Status;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the port is available.
+ //
+ if (CheckPortUsage(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(USHORT),
+ DriverObject
+ ) == FALSE) {
+
+ *Data = (USHORT)0xFFFF;
+ return;
+
+ }
+
+ //
+ // Map the space
+ //
+
+ Status = StartMapping(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(USHORT),
+ &PortMapping,
+ &Mapped
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ *Data = (USHORT)0xFFFF;
+ return;
+
+ }
+
+ //
+ // Read from the port
+ //
+
+ *Data = READ_PORT_USHORT((PUSHORT)PortMapping);
+
+ //
+ // End port mapping
+ //
+
+ EndMapping(
+ PortMapping,
+ sizeof(USHORT),
+ Mapped
+ );
+
+}
+
+VOID
+NdisImmediateReadPortUlong(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ OUT PULONG Data
+ )
+/*++
+
+Routine Description:
+
+ This routine reads from a port a ULONG. It does all the mapping,
+ etc, to do the read here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ Port - Port number to read from.
+
+ Data - Pointer to place to store the result.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID PortMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NTSTATUS Status;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the port is available.
+ //
+ if (CheckPortUsage(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(ULONG),
+ DriverObject
+ ) == FALSE) {
+
+ *Data = (ULONG)0xFFFFFFFF;
+ return;
+
+ }
+
+ //
+ // Map the space
+ //
+
+ Status = StartMapping(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(ULONG),
+ &PortMapping,
+ &Mapped
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ *Data = (ULONG)0xFFFFFFFF;
+ return;
+
+ }
+
+ //
+ // Read from the port
+ //
+
+ *Data = READ_PORT_ULONG((PULONG)PortMapping);
+
+ //
+ // End port mapping
+ //
+
+ EndMapping(
+ PortMapping,
+ sizeof(ULONG),
+ Mapped
+ );
+
+}
+
+VOID
+NdisImmediateWritePortUchar(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ IN UCHAR Data
+ )
+/*++
+
+Routine Description:
+
+ This routine writes to a port a UCHAR. It does all the mapping,
+ etc, to do the write here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ Port - Port number to read from.
+
+ Data - Pointer to place to store the result.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID PortMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NTSTATUS Status;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the port is available.
+ //
+ if (CheckPortUsage(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(UCHAR),
+ DriverObject
+ ) == FALSE) {
+
+ return;
+
+ }
+
+ //
+ // Map the space
+ //
+
+ Status = StartMapping(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(UCHAR),
+ &PortMapping,
+ &Mapped
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ return;
+
+ }
+
+ //
+ // Read from the port
+ //
+
+ WRITE_PORT_UCHAR((PUCHAR)PortMapping, Data);
+
+ //
+ // End port mapping
+ //
+
+ EndMapping(
+ PortMapping,
+ sizeof(UCHAR),
+ Mapped
+ );
+
+}
+
+VOID
+NdisImmediateWritePortUshort(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ IN USHORT Data
+ )
+/*++
+
+Routine Description:
+
+ This routine writes to a port a USHORT. It does all the mapping,
+ etc, to do the write here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ Port - Port number to read from.
+
+ Data - Pointer to place to store the result.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID PortMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NTSTATUS Status;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the port is available.
+ //
+ if (CheckPortUsage(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(USHORT),
+ DriverObject
+ ) == FALSE) {
+
+ return;
+
+ }
+
+ //
+ // Map the space
+ //
+
+ Status = StartMapping(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(USHORT),
+ &PortMapping,
+ &Mapped
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ return;
+
+ }
+
+ //
+ // Read from the port
+ //
+
+ WRITE_PORT_USHORT((PUSHORT)PortMapping, Data);
+
+ //
+ // End port mapping
+ //
+
+ EndMapping(
+ PortMapping,
+ sizeof(USHORT),
+ Mapped
+ );
+
+}
+
+VOID
+NdisImmediateWritePortUlong(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ IN ULONG Data
+ )
+/*++
+
+Routine Description:
+
+ This routine writes to a port a ULONG. It does all the mapping,
+ etc, to do the write here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ Port - Port number to read from.
+
+ Data - Pointer to place to store the result.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID PortMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NTSTATUS Status;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the port is available.
+ //
+ if (CheckPortUsage(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(ULONG),
+ DriverObject
+ ) == FALSE) {
+
+ return;
+
+ }
+
+ //
+ // Map the space
+ //
+
+ Status = StartMapping(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(ULONG),
+ &PortMapping,
+ &Mapped
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ return;
+
+ }
+
+ //
+ // Read from the port
+ //
+
+ WRITE_PORT_ULONG((PULONG)PortMapping, Data);
+
+ //
+ // End port mapping
+ //
+
+ EndMapping(
+ PortMapping,
+ sizeof(ULONG),
+ Mapped
+ );
+
+}
+
+BOOLEAN CheckMemoryUsage(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG Address,
+ IN ULONG Length,
+ IN PDRIVER_OBJECT DriverObject
+)
+/*++
+Routine Description:
+
+ This routine checks if a range of memory is currently in use somewhere
+ in the system via IoReportUsage -- which fails if there is a conflict.
+
+Arguments:
+
+ InterfaceType - The bus type (ISA, EISA)
+ BusNumber - Bus number in the system
+ Address - Starting Address of the memory to access.
+ Length - Length of memory from the base address to access.
+
+Return Value:
+
+ FALSE if there is a conflict, else TRUE
+
+--*/
+{
+ NTSTATUS NtStatus;
+ BOOLEAN Conflict;
+ NTSTATUS FirstNtStatus;
+ BOOLEAN FirstConflict;
+ PCM_RESOURCE_LIST Resources;
+
+ //
+ // Allocate space for resources
+ //
+
+ Resources = (PCM_RESOURCE_LIST)ExAllocatePool(
+ NonPagedPool,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)
+ );
+
+ if (Resources == NULL) {
+
+ //
+ // Error out
+ //
+
+ return(FALSE);
+
+ }
+
+ Resources->Count = 1;
+ Resources->List[0].InterfaceType = InterfaceType;
+ Resources->List[0].BusNumber = BusNumber;
+ Resources->List[0].PartialResourceList.Version = 0;
+ Resources->List[0].PartialResourceList.Revision = 0;
+ Resources->List[0].PartialResourceList.Count = 1;
+
+ //
+ // Setup memory
+ //
+
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].Type =
+ CmResourceTypeMemory;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].ShareDisposition =
+ CmResourceShareDriverExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].Flags =
+ CM_RESOURCE_MEMORY_READ_WRITE;
+#if !defined(BUILD_FOR_3_1)
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Memory.Start.QuadPart = Address;
+#else
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Memory.Start =
+ RtlConvertUlongToLargeInteger((ULONG)(Address));
+#endif
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Memory.Length =
+ Length;
+
+
+ //
+ // Submit Resources
+ //
+
+ FirstNtStatus = IoReportResourceUsage(
+ NULL,
+ DriverObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ NULL,
+ NULL,
+ 0,
+ TRUE,
+ &FirstConflict
+ );
+
+ //
+ // Now clear it out
+ //
+ Resources->List[0].PartialResourceList.Count = 0;
+
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ DriverObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ NULL,
+ NULL,
+ 0,
+ TRUE,
+ &Conflict
+ );
+
+ ExFreePool(Resources);
+
+ //
+ // Check for conflict.
+ //
+
+ if (FirstConflict || (FirstNtStatus != STATUS_SUCCESS)) {
+
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+VOID
+NdisImmediateReadSharedMemory(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SharedMemoryAddress,
+ OUT PUCHAR Buffer,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This routine read into a buffer from shared ram. It does all the mapping,
+ etc, to do the read here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ SharedMemoryAddress - The physical address to read from.
+
+ Buffer - The buffer to read into.
+
+ Length - Length of the buffer in bytes.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID MemoryMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NTSTATUS Status;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the memory is available.
+ //
+ if (CheckMemoryUsage(
+ BusType,
+ BusNumber,
+ SharedMemoryAddress,
+ Length,
+ DriverObject
+ ) == FALSE) {
+
+ return;
+
+ }
+
+ //
+ // Map the space
+ //
+
+ Status = StartMapping(
+ BusType,
+ BusNumber,
+ SharedMemoryAddress,
+ Length,
+ &MemoryMapping,
+ &Mapped
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ return;
+
+ }
+
+ //
+ // Read from memory
+ //
+
+#ifdef _M_IX86
+
+ memcpy(Buffer, MemoryMapping, Length);
+
+#else
+
+ READ_REGISTER_BUFFER_UCHAR(MemoryMapping,Buffer,Length);
+
+#endif
+
+ //
+ // End mapping
+ //
+
+ EndMapping(
+ MemoryMapping,
+ Length,
+ Mapped
+ );
+
+}
+
+VOID
+NdisImmediateWriteSharedMemory(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SharedMemoryAddress,
+ IN PUCHAR Buffer,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This routine writes a buffer to shared ram. It does all the mapping,
+ etc, to do the write here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ SharedMemoryAddress - The physical address to write to.
+
+ Buffer - The buffer to write.
+
+ Length - Length of the buffer in bytes.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID MemoryMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NTSTATUS Status;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the memory is available.
+ //
+ if (CheckMemoryUsage(
+ BusType,
+ BusNumber,
+ SharedMemoryAddress,
+ Length,
+ DriverObject
+ ) == FALSE) {
+
+ return;
+
+ }
+
+ //
+ // Map the space
+ //
+
+ Status = StartMapping(
+ BusType,
+ BusNumber,
+ SharedMemoryAddress,
+ Length,
+ &MemoryMapping,
+ &Mapped
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ return;
+
+ }
+
+ //
+ // Write to memory
+ //
+
+#ifdef _M_IX86
+
+ memcpy(MemoryMapping, Buffer, Length);
+
+#else
+
+ WRITE_REGISTER_BUFFER_UCHAR(MemoryMapping,Buffer,Length);
+
+#endif
+
+ //
+ // End mapping
+ //
+
+ EndMapping(
+ MemoryMapping,
+ Length,
+ Mapped
+ );
+
+}
+
+#if !defined(BUILD_FOR_3_1)
+
+ULONG
+NdisImmediateReadPciSlotInformation(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This routine reads from the PCI configuration space a specified
+ length of bytes at a certain offset.
+
+Arguments:
+
+ WrapperConfigurationContext - Context passed to MacAddAdapter.
+
+ SlotNumber - The slot number of the device.
+
+ Offset - Offset to read from
+
+ Buffer - Place to store the bytes
+
+ Length - Number of bytes to read
+
+Return Value:
+
+ Returns the number of bytes read.
+
+--*/
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ ULONG BusNumber;
+ ULONG DataLength;
+
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+#if DBG
+ {
+ NDIS_INTERFACE_TYPE BusType;
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ ASSERT(BusType == NdisInterfacePci);
+ }
+#endif
+
+ DataLength = HalGetBusDataByOffset(
+ PCIConfiguration,
+ BusNumber,
+ SlotNumber,
+ Buffer,
+ Offset,
+ Length
+ );
+
+ return(DataLength);
+}
+
+ULONG
+NdisImmediateWritePciSlotInformation(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This routine writes to the PCI configuration space a specified
+ length of bytes at a certain offset.
+
+Arguments:
+
+ WrapperConfigurationContext - Context passed to MacAddAdapter.
+
+ SlotNumber - The slot number of the device.
+
+ Offset - Offset to read from
+
+ Buffer - Place to store the bytes
+
+ Length - Number of bytes to read
+
+Return Value:
+
+ Returns the number of bytes written.
+
+--*/
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ ULONG BusNumber;
+ ULONG DataLength;
+
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+#if DBG
+ {
+ NDIS_INTERFACE_TYPE BusType;
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ ASSERT(BusType == NdisInterfacePci);
+ }
+#endif
+
+ DataLength = HalSetBusDataByOffset(
+ PCIConfiguration,
+ BusNumber,
+ SlotNumber,
+ Buffer,
+ Offset,
+ Length
+ );
+
+ return(DataLength);
+}
+
+#else // !defined(BUILD_FOR_3_1)
+
+ULONG
+NdisImmediateReadPciSlotInformation(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+{
+ return 0;
+}
+
+ULONG
+NdisImmediateWritePciSlotInformation(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+{
+ return 0;
+}
+
+#endif // !defined(BUILD_FOR_3_1)
+
+
+CCHAR
+NdisSystemProcessorCount(
+ VOID
+ )
+{
+ return *KeNumberProcessors;
+}
+
+
+VOID
+NdisOverrideBusNumber(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN NDIS_HANDLE MiniportAdapterHandle OPTIONAL,
+ IN ULONG BusNumber
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to override the BusNumber value retrieved
+ from the registry. It is expected to be used by PCI drivers
+ that discover that their adapter's bus number has changed.
+
+Arguments:
+
+ WrapperConfigurationContext - a handle pointing to an RTL_QUERY_REGISTRY_TABLE
+ that is set up for this driver's parameters.
+
+ MiniportAdapterHandle - points to the adapter block, if the calling
+ driver is a miniport. If the calling driver is a full MAC, this
+ parameter must be NULL.
+
+ BusNumber - the new bus number.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+
+ ((PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext)[3].DefaultLength = BusNumber;
+
+ if (Miniport != NULL) {
+ Miniport->BusNumber = BusNumber;
+ }
+
+ return;
+}
+
diff --git a/private/ntos/ndis/ndis30/wrapper.h b/private/ntos/ndis/ndis30/wrapper.h
new file mode 100644
index 000000000..8885bd800
--- /dev/null
+++ b/private/ntos/ndis/ndis30/wrapper.h
@@ -0,0 +1,473 @@
+#include <ntddk.h>
+#include <ndismain.h>
+#include <ndismac.h>
+#include <ndismini.h>
+
+
+#if defined(BUILD_FOR_3_5) || defined(BUILD_FOR_3_1)
+
+#define Increment(a,b) ExInterlockedIncrementLong(a,b)
+#define Decrement(a,b) ExInterlockedDecrementLong(a,b)
+
+#else
+
+#define Increment(a,b) InterlockedIncrement(a)
+#define Decrement(a,b) InterlockedDecrement(a)
+
+#endif
+
+#if defined(BUILD_FOR_3_1)
+
+#define FASTCALL
+
+#define MmLockPagableImageSection(a) NULL
+#define MmUnlockPagableImageSection(a)
+
+#define COMPUTE_PAGES_SPANNED(Va, Size) \
+ ((((ULONG)Va & (PAGE_SIZE -1)) + (Size) + (PAGE_SIZE - 1)) >> PAGE_SHIFT)
+
+#define Int32x32To64(a,b) RtlEnlargedIntegerMultiply((a),(b)).QuadPart
+
+#define ExAllocatePoolWithTag(a,b,c) ExAllocatePool((a),(b))
+
+NTSTATUS
+NTAPI
+RtlCharToInteger (
+ PCSZ String,
+ ULONG Base,
+ PULONG Value
+ );
+
+#endif
+
+#if defined(BUILD_FOR_3_5)
+#define MmLockPagableCodeSection(x) MmLockPagableImageSection(x)
+#endif
+
+#define ACQUIRE_SPIN_LOCK(_SpinLock) KeAcquireSpinLock(&(_SpinLock)->SpinLock, &(_SpinLock)->OldIrql)
+#define RELEASE_SPIN_LOCK(_SpinLock) KeReleaseSpinLock(&(_SpinLock)->SpinLock, (_SpinLock)->OldIrql)
+#define ACQUIRE_SPIN_LOCK_DPC(_SpinLock) KeAcquireSpinLockAtDpcLevel(&(_SpinLock)->SpinLock)
+#define RELEASE_SPIN_LOCK_DPC(_SpinLock) KeReleaseSpinLockFromDpcLevel(&(_SpinLock)->SpinLock)
+
+
+#if DBG
+#define NDISDBG 0
+#endif
+#if !defined(NDISDBG)
+#define NDISDBG 0
+#endif
+
+#if NDISDBG
+
+#if defined(MEMPRINT)
+#include "memprint.h" //DavidTr's memprint program at ntos\srv
+#endif // MEMPRINT
+
+extern int NdisMsgLevel;
+extern BOOLEAN NdisChkErrorFlag;
+
+#define TRACE_NONE 0x0000
+#define TRACE_IMPT 0x0001
+#define TRACE_ALL 0x0002
+
+#define IF_TRACE(level) if ( NdisMsgLevel >= (level) ) //for tracing
+
+#define IF_ERROR_CHK if (NdisChkErrorFlag) // for parameter checking
+
+#define DbgIsNonPaged(_Address) \
+ ( MmIsNonPagedSystemAddressValid((PVOID)(_Address)) )
+
+#define DbgIsPacket(_Packet) \
+ ( ((_Packet)->Private.Pool->PacketLength) > sizeof(_Packet) )
+
+#define DbgIsNull(_Ptr) ( ((PVOID)(_Ptr)) == NULL )
+
+#define NdisPrint1(fmt) DbgPrint(fmt)
+#define NdisPrint2(fmt,v1) DbgPrint(fmt,v1)
+#define NdisPrint3(fmt,v1,v2) DbgPrint(fmt,v1,v2)
+#define NdisPrint4(fmt,v1,v2,v3) DbgPrint(fmt,v1,v2,v3)
+#define NdisPrint5(fmt,v1,v2,v3,v4) DbgPrint(fmt,v1,v2,v3,v4)
+
+#else // NDISDBG
+
+#define IF_TRACE(level) if (FALSE)
+#define IF_ERROR_CHK if (FALSE)
+
+#define DbgIsNonPaged(_Address) TRUE
+#define DbgIsPacket(_Packet) TRUE
+#define DbgIsNull(_Ptr) FALSE
+
+#define NdisPrint1(fmt)
+#define NdisPrint2(fmt,v1)
+#define NdisPrint3(fmt,v1,v2)
+#define NdisPrint4(fmt,v1,v2,v3)
+#define NdisPrint5(fmt,v1,v2,v3,v4)
+
+#endif // NDISDBG
+
+
+#if DBG
+#define MINIPORT_AT_DPC_LEVEL (KeGetCurrentIrql() == DISPATCH_LEVEL)
+#else
+#define MINIPORT_AT_DPC_LEVEL 1
+#endif
+
+
+//
+// This is the number of extra OIDs that ARCnet with Ethernet encapsulation
+// supports.
+//
+#define ARC_NUMBER_OF_EXTRA_OIDS 2
+
+
+
+//
+// Internal wrapper data structures.
+//
+
+//
+// NDIS_WRAPPER_CONTEXT
+//
+// This data structure contains internal data items for use by the wrapper.
+//
+
+typedef struct _NDIS_WRAPPER_CONTEXT {
+
+ //
+ // Mac/miniport defined shutdown context.
+ //
+
+ PVOID ShutdownContext;
+
+ //
+ // Mac/miniport registered shutdown handler.
+ //
+
+ ADAPTER_SHUTDOWN_HANDLER ShutdownHandler;
+
+#if !defined(BUILD_FOR_3_1)
+ //
+ // Kernel bugcheck record for bugcheck handling.
+ //
+
+ KBUGCHECK_CALLBACK_RECORD BugcheckCallbackRecord;
+#endif
+
+ //
+ // Miniport assigned resources for PCI, PCMCIA, EISA, etc.
+ //
+
+ PCM_RESOURCE_LIST AssignedSlotResources;
+
+ //
+ // HAL common buffer cache.
+ //
+
+ PVOID SharedMemoryPage[2];
+ ULONG SharedMemoryLeft[2];
+ NDIS_PHYSICAL_ADDRESS SharedMemoryAddress[2];
+
+} NDIS_WRAPPER_CONTEXT, *PNDIS_WRAPPER_CONTEXT;
+
+//
+// Lock/unlock miniport macros.
+//
+
+#define LOCK_MINIPORT(_M_, _L) \
+{ \
+ if (_M_->LockAcquired) { \
+ _L = FALSE; \
+ } else { \
+ _L = TRUE; \
+ _M_->LockAcquired = TRUE; \
+ } \
+}
+
+#define UNLOCK_MINIPORT(_M_, _L) \
+{ \
+ if (_L) { \
+ _M_->LockAcquired = FALSE; \
+ } \
+}
+
+
+NDIS_STATUS
+NdisInitialInit(
+ PDRIVER_OBJECT Driver OPTIONAL
+ );
+
+VOID
+FASTCALL
+MiniportProcessDeferred(
+ PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+NDIS_STATUS
+NdisMTransferDataSync(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+#define MINIPORT_DISABLE_INTERRUPT(_M_) \
+{ \
+ ASSERT(_M_->DriverHandle->MiniportCharacteristics.DisableInterruptHandler != NULL); \
+ (_M_->DriverHandle->MiniportCharacteristics.DisableInterruptHandler)( \
+ _M_->MiniportAdapterContext \
+ ); \
+}
+
+#define MINIPORT_SYNC_DISABLE_INTERRUPT(_M_) \
+{ \
+ if (_M_->DriverHandle->MiniportCharacteristics.DisableInterruptHandler != NULL) { \
+ KeSynchronizeExecution( \
+ (_M_)->Interrupt->InterruptObject, \
+ (PKSYNCHRONIZE_ROUTINE)(_M_->DriverHandle->MiniportCharacteristics.DisableInterruptHandler),\
+ _M_->MiniportAdapterContext \
+ ); \
+ } \
+}
+
+#define CHECK_FOR_NORMAL_INTERRUPTS(_Miniport) \
+ _Miniport->NormalInterrupts = (BOOLEAN)(!_Miniport->HaltingMiniport && \
+ !_Miniport->InInitialize && \
+ (_Miniport->Interrupt != NULL) && \
+ !_Miniport->Interrupt->IsrRequested && \
+ !_Miniport->Interrupt->SharedInterrupt)
+
+//
+// general reference/dereference functions
+//
+
+BOOLEAN
+NdisReferenceRef(
+ IN PREFERENCE RefP
+ );
+
+
+BOOLEAN
+NdisDereferenceRef(
+ PREFERENCE RefP
+ );
+
+
+VOID
+NdisInitializeRef(
+ PREFERENCE RefP
+ );
+
+
+BOOLEAN
+NdisCloseRef(
+ PREFERENCE RefP
+ );
+
+
+/*++
+BOOLEAN
+NdisReferenceProtocol(
+ IN PNDIS_PROTOCOL_BLOCK ProtP
+ );
+--*/
+
+#define NdisReferenceProtocol(ProtP) \
+ NdisReferenceRef(&(ProtP)->Ref)
+
+
+
+BOOLEAN
+QueueOpenOnProtocol(
+ IN PNDIS_OPEN_BLOCK OpenP,
+ IN PNDIS_PROTOCOL_BLOCK ProtP
+ );
+
+
+/*++
+VOID
+NdisDereferenceProtocol(
+ PNDIS_PROTOCOL_BLOCK ProtP
+ );
+--*/
+#define NdisDereferenceProtocol(ProtP) { \
+ if (NdisDereferenceRef(&(ProtP)->Ref)) { \
+ ExFreePool((PVOID)(ProtP)); \
+ } \
+}
+
+
+
+VOID
+NdisDeQueueOpenOnProtocol(
+ PNDIS_OPEN_BLOCK OpenP,
+ PNDIS_PROTOCOL_BLOCK ProtP
+ );
+
+
+BOOLEAN
+NdisFinishOpen(
+ PNDIS_OPEN_BLOCK OpenP
+ );
+
+
+VOID
+NdisKillOpenAndNotifyProtocol(
+ PNDIS_OPEN_BLOCK OldOpenP
+ );
+
+
+BOOLEAN
+NdisKillOpen(
+ PNDIS_OPEN_BLOCK OldOpenP
+ );
+
+/*++
+BOOLEAN
+NdisReferenceMac(
+ IN PNDIS_MAC_BLOCK MacP
+ );
+--*/
+#define NdisReferenceMac(MacP) \
+ NdisReferenceRef(&(MacP)->Ref)
+
+static
+VOID
+NdisDereferenceMac(
+ PNDIS_MAC_BLOCK MacP
+ );
+
+BOOLEAN
+NdisQueueAdapterOnMac(
+ PNDIS_ADAPTER_BLOCK AdaptP,
+ PNDIS_MAC_BLOCK MacP
+ );
+
+VOID
+NdisDeQueueAdapterOnMac(
+ PNDIS_ADAPTER_BLOCK AdaptP,
+ PNDIS_MAC_BLOCK MacP
+ );
+
+/*++
+BOOLEAN
+NdisReferenceAdapter(
+ IN PNDIS_ADAPTER_BLOCK AdaptP
+ );
+--*/
+#define NdisReferenceAdapter(AdaptP) \
+ NdisReferenceRef(&(AdaptP)->Ref)
+
+
+BOOLEAN
+NdisQueueOpenOnAdapter(
+ PNDIS_OPEN_BLOCK OpenP,
+ PNDIS_ADAPTER_BLOCK AdaptP
+ );
+
+VOID
+NdisKillAdapter(
+ PNDIS_ADAPTER_BLOCK OldAdaptP
+ );
+
+VOID
+NdisDereferenceAdapter(
+ PNDIS_ADAPTER_BLOCK AdaptP
+ );
+
+VOID
+NdisDeQueueOpenOnAdapter(
+ PNDIS_OPEN_BLOCK OpenP,
+ PNDIS_ADAPTER_BLOCK AdaptP
+ );
+
+NDIS_STATUS
+NdisCallDriverAddAdapter(
+ IN PNDIS_MAC_BLOCK NewMacP
+ );
+
+/*++
+BOOLEAN
+NdisReferenceDriver(
+ IN PNDIS_M_DRIVER_BLOCK DriverP
+ );
+--*/
+#define NdisReferenceDriver(DriverP) \
+ NdisReferenceRef(&(DriverP)->Ref)
+
+
+VOID
+NdisDereferenceDriver(
+ PNDIS_M_DRIVER_BLOCK DriverP
+ );
+
+BOOLEAN
+NdisQueueMiniportOnDriver(
+ PNDIS_MINIPORT_BLOCK MiniportP,
+ PNDIS_M_DRIVER_BLOCK DriverP
+ );
+
+VOID
+NdisDequeueMiniportOnDriver(
+ PNDIS_MINIPORT_BLOCK MiniportP,
+ PNDIS_M_DRIVER_BLOCK DriverP
+ );
+
+BOOLEAN
+NdisQueueOpenOnMiniport(
+ PNDIS_M_OPEN_BLOCK OpenP,
+ PNDIS_MINIPORT_BLOCK MiniportP
+ );
+
+VOID
+NdisKillMiniport(
+ PNDIS_MINIPORT_BLOCK OldMiniportP
+ );
+
+/*++
+BOOLEAN
+NdisReferenceMiniport(
+ IN PNDIS_MINIPORT_BLOCK MiniportP
+ );
+--*/
+#define NdisReferenceMiniport(MiniportP) \
+ NdisReferenceRef(&(MiniportP)->Ref)
+
+VOID
+NdisDereferenceMiniport(
+ PNDIS_MINIPORT_BLOCK MiniportP
+ );
+
+VOID
+NdisDeQueueOpenOnMiniport(
+ PNDIS_M_OPEN_BLOCK OpenP,
+ PNDIS_MINIPORT_BLOCK MiniportP
+ );
+
+VOID
+MiniportInitializePackage(
+ VOID
+ );
+
+VOID
+MiniportReferencePackage(
+ VOID
+ );
+
+VOID
+MiniportDereferencePackage(
+ VOID
+ );
+
+NDIS_STATUS ArcConvertOidListToEthernet(
+ IN PNDIS_OID pOidList,
+ IN PULONG pcbOidList,
+ IN PNDIS_OID pTmpBuffer
+);
+
+VOID
+NdisBugcheckHandler(
+ IN PNDIS_WRAPPER_CONTEXT WrapperContext,
+ IN ULONG Size
+ );
diff --git a/private/ntos/ndis/ndis30/wrapper.txt b/private/ntos/ndis/ndis30/wrapper.txt
new file mode 100644
index 000000000..2e52189f0
--- /dev/null
+++ b/private/ntos/ndis/ndis30/wrapper.txt
@@ -0,0 +1,120 @@
+Debug Wrapper
+
+Johnson Apacible (johnsona)
+3-11-91
+
+
+
+The debug version of the wrapper allows developers to
+1. turn on/off error checking
+2. control level of tracing. There are currently 2 levels of tracing:
+Level 2 tracing turns on tracing on all wrapper functions; while level
+1 tracing turns on tracing only on the more interesting functions.
+Level 1 and 2 functions are enumerated below:
+
+
+Level 1 Tracing enables tracing on the following functions:
+
+ NdisInitializePacketPool
+ NdisTerminatePacketPool
+
+ NdisRegisterProtocol
+ NdisDeregisterProtocol
+
+ NdisOpenAdapter
+ NdisCloseAdapter
+ FinishOpen
+
+ KillOpenAndNotifyProtocol
+ KillOpen
+
+ NdisInitializeWrapper
+ NdisTerminateWrapper
+
+ NdisRegisterMac
+ NdisDeregisterMac
+ DeQueueAdapterOnMac
+ QueueAdapterOnMac
+
+ QueueOpenOnProtocol
+ DeQueueOpenOnProtocol
+ NdisRegisterAdapter
+ NdisDeregisterAdapter
+ KillAdapter
+ QueueAdapterOnAdapter
+ DeQueueAdapterOnAdapter
+ NdisSetPacketFilter
+ NdisAddMulticastAddress
+ NdisDeleteMulticastAddress
+ NdisSend
+ NdisTransferData
+ NdisQueryInformation
+ NdisSetInformation
+ NdisReset
+ NdisTest
+ NdisCompleteRequest
+ NdisCompleteSend
+ NdisCompleteTransferData
+ NdisIndicateStatus
+ NdisIndicateStatusComplete
+
+
+Level 2 tracing enables tracing the functions listedbelow in addition
+to all Level 1 functions:
+
+ NdisQueryBuffer
+ NdisAllocatePacket
+ NdisDeallocatePacket
+ NdisReinitializePacket
+ NdisChainBufferAtFront
+ NdisChainBufferAtBack
+ NdisUnchainBufferAtFront
+ NdisUnchainBufferAtBack
+ NdisQueryPacket
+ NdisGetNextBuffer
+ ReferenceRef
+ DereferenceRef
+ InitializeRef
+ CloseRef
+ ReferenceProtocol
+ DereferenceProtocol
+ NdisSuccessIrplHandler
+ ReferencMac
+ ReferenceAdapter
+ DereferenceAdapter
+
+ NdisIndicateReceive
+ NdisIndicateReceiveComplete
+
+
+
+Turning on/off error checking
+
+Error checking may be turned on/off during run-time by changing the
+value of the flag NdisChkErrorFlag. A zero value turns off error
+checking and a non-zero value turn it on. This flag is turned on
+by default.
+
+
+Controlling level of messages
+
+Message level may by specified by changing the NdisMsgLevel variable.
+
+ Value of NdisMsgLevel Meaning
+ 0x000 Turn off all messages
+ 0x001 Turn on tracing on Level 1 functions
+ 0x002 Turn on all tracing
+
+NdisMsgLevel is set to 0 by default
+
+
+
+The debug code will be included only if the NDISDBG flag is turned on (== 1).
+
+If you do change this flag, be sure to delete (1) all nbf .obj files,
+(2) ntos\dd\init\obj\i386\ddinit.obj, (3) ntos\init\obj\i386\init.obj, and
+(4) recompile everything under ndis, since this flag will change a lot
+of goings on inside ndis.h
+
+
+ \ No newline at end of file
diff --git a/private/ntos/ndis/ndis40/afilter.c b/private/ntos/ndis/ndis40/afilter.c
new file mode 100644
index 000000000..f0b8c972a
--- /dev/null
+++ b/private/ntos/ndis/ndis40/afilter.c
@@ -0,0 +1,2617 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ afilter.c
+
+Abstract:
+
+ This module implements a set of library routines to handle packet
+ filtering for NDIS MAC drivers. It also provides routines for collecting fragmented packets and
+ breaking up a packet into fragmented packets
+
+Author:
+
+ Alireza Dabagh 3-22-1993, (partially borrowed from EFILTER.C)
+
+
+Revision History:
+
+ Jameel Hyder (JameelH) Re-organization 01-Jun-95
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+#include "sendm.h"
+
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_AFILTER
+
+//
+// Given an NDIS_PACKET this macro will tell us if it is
+// encapsulated ethernet.
+//
+#define ARC_PACKET_IS_ENCAPSULATED(Packet) \
+ (PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Open->Flags & fMINIPORT_OPEN_USING_ETH_ENCAPSULATION)
+
+//
+// VOID
+// ARC_FILTER_ALLOC_OPEN(
+// IN PETH_FILTER Filter,
+// OUT PUINT FilterIndex
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Allocates an open block. This only allocate the index, not memory for
+// the open block.
+//
+//Arguments:
+//
+// Filter - DB from which to allocate the space
+//
+// FilterIndex - pointer to place to store the index.
+//
+//Return Value:
+//
+// FilterIndex of the new open
+//
+//--*/
+#define ARC_FILTER_ALLOC_OPEN(Filter, FilterIndex) \
+{ \
+ UINT i; \
+ for (i=0; i < ARC_FILTER_MAX_OPENS; i++) \
+ { \
+ if (IS_BIT_SET_IN_MASK(i,(Filter)->FreeBindingMask))\
+ { \
+ *(FilterIndex) = i; \
+ CLEAR_BIT_IN_MASK(i, &((Filter)->FreeBindingMask));\
+ break; \
+ } \
+ } \
+}
+
+//
+// VOID
+// ARC_FILTER_FREE_OPEN(
+// IN PETH_FILTER Filter,
+// IN PARC_BINDING_INFO LocalOpen
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Frees an open block. Also frees the memory associated with the open.
+//
+//Arguments:
+//
+// Filter - DB from which to allocate the space
+//
+// FilterIndex - Index to free
+//
+//Return Value:
+//
+// None
+//
+//--*/
+#define ARC_FILTER_FREE_OPEN(Filter, LocalOpen)\
+{\
+ SET_BIT_IN_MASK(((LocalOpen)->FilterIndex), &((Filter)->FreeBindingMask)); \
+ NdisFreeMemory((LocalOpen), sizeof(ARC_BINDING_INFO), 0);\
+}
+
+
+//
+// Defines for resource growth
+//
+#define ARC_BUFFER_SIZE 1024
+#define ARC_BUFFER_ALLOCATION_UNIT 8
+#define ARC_PACKET_ALLOCATION_UNIT 2
+
+
+NDIS_STATUS
+ArcAllocateBuffers(
+ IN PARC_FILTER Filter
+ )
+/*++
+
+Routine Description:
+
+ This routine allocates Receive buffers for the filter database.
+
+Arguments:
+
+ Filter - The filter db to allocate for.
+
+Returns:
+
+ NDIS_STATUS_SUCCESS if any buffer was allocated.
+
+--*/
+{
+ ULONG i;
+ PARC_BUFFER_LIST Buffer;
+ PVOID DataBuffer;
+
+ for (i = ARC_BUFFER_ALLOCATION_UNIT; i != 0; i--)
+ {
+ NdisAllocateMemory((PVOID)&Buffer,
+ sizeof(ARC_BUFFER_LIST),
+ 0,
+ HighestAcceptableMax);
+
+ if (Buffer == NULL)
+ {
+ if (i == ARC_BUFFER_ALLOCATION_UNIT)
+ {
+ return(NDIS_STATUS_FAILURE);
+ }
+ return(NDIS_STATUS_SUCCESS);
+ }
+
+ NdisAllocateMemory((PVOID)&DataBuffer,
+ ARC_BUFFER_SIZE,
+ 0,
+ HighestAcceptableMax);
+
+ if (DataBuffer == NULL)
+ {
+ NdisFreeMemory(Buffer, sizeof(ARC_BUFFER_LIST), 0);
+
+ if (i == ARC_BUFFER_ALLOCATION_UNIT)
+ {
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // We allocated some packets, that is good enough for now
+ //
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+ Buffer->BytesLeft = Buffer->Size = ARC_BUFFER_SIZE;
+ Buffer->Buffer = DataBuffer;
+ Buffer->Next = Filter->FreeBufferList;
+ Filter->FreeBufferList = Buffer;
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+ArcAllocatePackets(
+ IN PARC_FILTER Filter
+ )
+/*++
+
+Routine Description:
+
+ This routine allocates Receive packets for the filter database.
+
+Arguments:
+
+ Filter - The filter db to allocate for.
+
+Returns:
+
+ NDIS_STATUS_SUCCESS if any packet was allocated.
+
+--*/
+{
+ ULONG i;
+ PARC_PACKET Packet;
+
+ for (i = ARC_PACKET_ALLOCATION_UNIT; i != 0; i--)
+ {
+ NdisAllocateMemory((PVOID)&Packet,
+ sizeof(ARC_PACKET),
+ 0,
+ HighestAcceptableMax);
+
+ if (Packet == NULL)
+ {
+ if (i == ARC_BUFFER_ALLOCATION_UNIT)
+ {
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+ }
+
+ ZeroMemory(Packet, sizeof(ARC_PACKET));
+
+ NdisReinitializePacket(&(Packet->TmpNdisPacket));
+
+ Packet->Next = Filter->FreePackets;
+ Filter->FreePackets = Packet;
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+VOID
+ArcDiscardPacketBuffers(
+ IN PARC_FILTER Filter,
+ IN PARC_PACKET Packet
+ )
+/*++
+
+Routine description:
+
+ This routine takes an arcnet packet that contains buffers of data and
+ puts the buffers on the free list.
+
+ NOTE: This assumes that LastBuffer points to the real last buffer
+ in the chain.
+
+Arguments:
+
+ Filter - The filter to free the buffers to.
+
+ Packet - The packet to free up.
+
+Return values:
+
+ None
+
+--*/
+{
+ PARC_BUFFER_LIST Buffer;
+
+ //
+ // Reset Packet info
+ //
+ Packet->LastFrame = FALSE;
+ Packet->TotalLength = 0;
+
+ //
+ // Reset buffer sizes
+ //
+ Buffer = Packet->FirstBuffer;
+ while (Buffer != NULL)
+ {
+ Buffer->BytesLeft = Buffer->Size;
+ Buffer = Buffer->Next;
+ }
+
+ //
+ // Put buffers on free list
+ //
+ if (Packet->LastBuffer != NULL)
+ {
+ Packet->LastBuffer->Next = Filter->FreeBufferList;
+ Filter->FreeBufferList = Packet->FirstBuffer;
+ Packet->FirstBuffer = Packet->LastBuffer = NULL;
+ }
+}
+
+
+VOID
+ArcFreeNdisPacket(
+ IN PARC_PACKET Packet
+ )
+/*++
+
+Routine description:
+
+ This routine takes an arcnet packet and frees up the corresponding
+ Ndis packet built for it.
+
+Arguments:
+
+ Packet - The packet to free up.
+
+Return values:
+
+ None
+
+--*/
+{
+ PNDIS_BUFFER NdisBuffer, NextNdisBuffer;
+
+ NdisQueryPacket(&(Packet->TmpNdisPacket),
+ NULL,
+ NULL,
+ &NdisBuffer,
+ NULL);
+
+ while (NdisBuffer != NULL)
+ {
+ NdisGetNextBuffer(NdisBuffer, &NextNdisBuffer);
+
+ NdisFreeBuffer(NdisBuffer);
+
+ NdisBuffer = NextNdisBuffer;
+ }
+
+ NdisReinitializePacket(&(Packet->TmpNdisPacket));
+}
+
+
+VOID
+ArcDestroyPacket(
+ IN PARC_FILTER Filter,
+ IN PARC_PACKET Packet
+ )
+/*++
+
+Routine description:
+
+ This routine takes an arcnet packet and frees up the entire packet.
+
+Arguments:
+
+ Filter - Filter to free to.
+
+ Packet - The packet to free up.
+
+Return values:
+
+ None
+
+--*/
+{
+ ArcFreeNdisPacket(Packet);
+ ArcDiscardPacketBuffers(Filter, Packet);
+
+ //
+ // Now put packet on free list
+ //
+ Packet->Next = Filter->FreePackets;
+ Filter->FreePackets = Packet;
+}
+
+
+BOOLEAN
+ArcConvertToNdisPacket(
+ IN PARC_FILTER Filter,
+ IN PARC_PACKET Packet,
+ IN BOOLEAN ConvertWholePacket
+ )
+/*++
+
+Routine description:
+
+ This routine builds a corresponding NDIS_PACKET in TmpNdisPacket,
+ that corresponds to the arcnet packet. The flag ConvertWholePacket
+ is used to convert only part of the arcnet packet, or the whole
+ stream. If the flag is FALSE, then only the buffers that have
+ free space (starting with buffer LastBuffer on up) are converted.
+
+ NOTE: It assumes TmpNdisPacket is an initialized ndis_packet structure.
+
+Arguments:
+
+ Filter - Filter to allocate from.
+
+ Packet - The packet to convert.
+
+ ConvertWholePacket - Convert the whole stream, or only part?
+
+Return values:
+
+ TRUE - If successful, else FALSE
+
+--*/
+{
+ PNDIS_BUFFER NdisBuffer;
+ PARC_BUFFER_LIST Buffer;
+ NDIS_STATUS NdisStatus;
+
+ Buffer = Packet->FirstBuffer;
+
+ while (Buffer != NULL)
+ {
+ NdisAllocateBuffer(&NdisStatus,
+ &NdisBuffer,
+ Filter->ReceiveBufferPool,
+ Buffer->Buffer,
+ Buffer->Size - Buffer->BytesLeft);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS)
+ {
+ return(FALSE);
+ }
+
+ NdisChainBufferAtBack(&(Packet->TmpNdisPacket), NdisBuffer);
+
+ Buffer = Buffer->Next;
+ }
+
+ return(TRUE);
+}
+
+
+VOID
+ArcFilterDprIndicateReceive(
+ IN PARC_FILTER Filter, // Pointer to filter database
+ IN PUCHAR pRawHeader, // Pointer to Arcnet frame header
+ IN PUCHAR pData, // Pointer to data portion of Arcnet frame
+ IN UINT Length // Data Length
+ )
+{
+ ARC_PACKET_HEADER NewFrameInfo;
+ PARC_PACKET Packet, PrevPacket;
+ BOOLEAN FrameOk, NewFrame, LastFrame;
+ PARC_BUFFER_LIST Buffer;
+ UCHAR TmpUchar;
+ UINT TmpLength;
+ UINT TotalLength = Length;
+ PUCHAR OrigpData = pData;
+ USHORT TmpUshort;
+
+ //
+ // Check for ethernet encapsulation first
+ //
+ TmpUchar = ((ARC_PROTOCOL_HEADER *)pRawHeader)->ProtId;
+
+ if ( TmpUchar == 0xE8 )
+ {
+ if ((Length < (ARC_MAX_FRAME_SIZE + 4)) && (Length > 0))
+ {
+ //
+ // Yes! Indicate it to the wrapper for indicating to all
+ // protocols running ethernet on top of the arcnet miniport
+ // driver.
+ //
+ ndisMArcIndicateEthEncapsulatedReceive(
+ Filter->Miniport, // miniport.
+ pRawHeader, // 878.2 header.
+ pData, // ethernet header.
+ Length); // length of ethernet frame.
+ //
+ // Ethernet header should be pData now
+ // Length should be data now
+ // We're done.
+ //
+ }
+
+ return;
+
+ }
+
+ // If the data portion is greater than 507 its a bad deal
+ if ((Length > ARC_MAX_FRAME_SIZE + 3) || (Length == 0))
+ {
+ return;
+ }
+
+ //
+ // Get information from packet
+ //
+ NewFrameInfo.ProtHeader.SourceId[0] = *((PUCHAR)pRawHeader);
+ NewFrameInfo.ProtHeader.DestId[0] = *((PUCHAR)pRawHeader + 1);
+
+ NewFrameInfo.ProtHeader.ProtId = TmpUchar;
+
+ //
+ // Read the split flag. If this is an exception packet (i.e.
+ // TmpUChar == 0xFF then we need to add an extra 3 onto
+ // pData to skip the series of 0xFF 0xFF 0xFF.
+ //
+ TmpUchar = *((PUCHAR)pData);
+
+ if (TmpUchar == 0xFF)
+ {
+ pData += 4;
+ Length -= 4;
+
+ //
+ // Re-read the split flag.
+ //
+ TmpUchar = *((PUCHAR)pData);
+ }
+
+ //
+ // Save off the split flag.
+ //
+ NewFrameInfo.SplitFlag = TmpUchar;
+
+ //
+ // Read the sequence number, which follows the split flag.
+ //
+ TmpUshort = 0;
+ TmpUshort = *((PUCHAR)pData + 1);
+ TmpUchar = *((PUCHAR)pData + 2);
+
+ TmpUshort = TmpUshort | (TmpUchar << 8);
+ NewFrameInfo.FrameSequence = TmpUshort;
+ //
+ // Point pData at protocol data.
+ //
+ Length -= 3; //... Length of protocol data.
+ pData += 3; //... Beginning of protocol data.
+ // Length is decreased by SF + SEQ0 + SEQ 1 = 3
+
+ //
+ // NOTE: Length is now the Length of the data portion of this packet
+ //
+ DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_INFO,
+ ("ArcFilter: Frame received: SourceId= %#1x\nDestId=%#1x\nProtId=%#1x\nSplitFlag=%#1x\nFrameSeq=%d\n",
+ (USHORT)NewFrameInfo.ProtHeader.SourceId[0],
+ (USHORT)NewFrameInfo.ProtHeader.DestId[0],
+ (USHORT)NewFrameInfo.ProtHeader.ProtId,
+ (USHORT)NewFrameInfo.SplitFlag,
+ NewFrameInfo.FrameSequence));
+ DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_INFO,
+ ("ArcFilter: Data at address: %lx, Length = %ld\n", pData, Length));
+
+ FrameOk = TRUE;
+ NewFrame = TRUE;
+ LastFrame = TRUE;
+
+ PrevPacket = NULL;
+ Packet = Filter->OutstandingPackets;
+
+ //
+ // Walk throgh all outstanding packet to see if this frame belongs to any one of them
+ //
+
+ while ( Packet != NULL )
+ {
+ if (Packet->Header.ProtHeader.SourceId[0] == NewFrameInfo.ProtHeader.SourceId[0])
+ {
+ //
+ // A packet received from the same source, check packet Sequence number and throw away
+ // outstanding packet if they don't match. We are allowed to do this since we know
+ // all the frames belonging to one packet are sent before starting a new packet. We
+ // HAVE to do this, because this is how we find out that a send at the other end, was aborted
+ // after some of the frames were already sent and received here.
+ //
+
+ if((Packet->Header.FrameSequence == NewFrameInfo.FrameSequence) &&
+ (Packet->Header.ProtHeader.DestId[0] == NewFrameInfo.ProtHeader.DestId[0]) &&
+ (Packet->Header.ProtHeader.ProtId == NewFrameInfo.ProtHeader.ProtId))
+ {
+ //
+ // We found a packet that this frame belongs to, check split flag
+ //
+ if (Packet->Header.FramesReceived * 2 == NewFrameInfo.SplitFlag)
+ {
+ //
+ // A packet found for this frame and SplitFlag is OK, check to see if it is
+ // the last frame of the packet
+ //
+ NewFrame = FALSE;
+ LastFrame = (BOOLEAN)(NewFrameInfo.SplitFlag == Packet->Header.LastSplitFlag);
+ }
+ else
+ {
+ //
+ // compare current split flag with the one from the last frame, if not equal
+ // the whole packet should be dropped.
+ //
+
+ if (Packet->Header.SplitFlag != NewFrameInfo.SplitFlag)
+ {
+ //
+ // Corrupted incomplete packet, get rid of it, but keep the new frame
+ // and we will re-use this Packet pointer.
+ //
+ ArcDiscardPacketBuffers(Filter, Packet);
+ break;
+ }
+ else
+ {
+ //
+ // We see to have received a duplicate frame. Ignore it.
+ //
+ return;
+ }
+ }
+ }
+ else
+ {
+ //
+ // We received a frame from a source that already has an incomplete packet outstanding
+ // But Frame Seq. or DestId or ProtId are not the same.
+ // We have to discard the old packet and check the new frame for validity,
+ // we will re-use this packet pointer below.
+ //
+ ArcDiscardPacketBuffers(Filter, Packet);
+ }
+
+ break;
+ }
+ else
+ {
+ PrevPacket = Packet;
+ Packet = Packet->Next;
+ }
+ }
+
+ if (NewFrame)
+ {
+ //
+ // first frame of a packet, split flag must be odd or zero
+ // NewFrame is already TRUE
+ // LastFrame is already TRUE
+ //
+ if (NewFrameInfo.SplitFlag)
+ {
+ if (!(NewFrameInfo.SplitFlag & 0x01))
+ {
+ //
+ // This frame is the middle of another split, but we
+ // don't have it on file. Drop the frame.
+ //
+ return;
+ }
+
+ //
+ // First Frame of a multiple frame packet
+ //
+ NewFrameInfo.LastSplitFlag = NewFrameInfo.SplitFlag + 1;
+ NewFrameInfo.FramesReceived = 1;
+ LastFrame = FALSE; // New packet and SplitFlag not zero
+ }
+ else
+ {
+ //
+ // The frame is fully contained in this packet.
+ //
+ }
+
+ //
+ // allocate a new packet descriptor if it is a new packet
+ //
+ if (Packet == NULL)
+ {
+ if (Filter->FreePackets == NULL)
+ {
+ ArcAllocatePackets(Filter);
+
+ if (Filter->FreePackets == NULL)
+ {
+ return;
+ }
+ }
+
+ Packet = Filter->FreePackets;
+ Filter->FreePackets = Packet->Next;
+
+ if (!LastFrame)
+ {
+ //
+ // Insert the packet in list of outstanding packets
+ //
+ Packet->Next = Filter->OutstandingPackets;
+ Filter->OutstandingPackets = Packet;
+ }
+ }
+ else
+ {
+ if (LastFrame)
+ {
+ //
+ // remove it from the list
+ //
+ if (PrevPacket == NULL)
+ {
+ Filter->OutstandingPackets = Packet->Next;
+ }
+ else
+ {
+ PrevPacket->Next = Packet->Next;
+ }
+ }
+ }
+
+ Packet->Header = NewFrameInfo;
+ }
+ else
+ {
+ if (LastFrame)
+ {
+ //
+ // Remove it from the queue
+ //
+
+ if (PrevPacket == NULL)
+ {
+ Filter->OutstandingPackets = Packet->Next;
+ }
+ else
+ {
+ PrevPacket->Next = Packet->Next;
+ }
+ }
+
+ Packet->Header.FramesReceived++;
+
+ //
+ // keep track of last split flag to detect duplicate frames
+ //
+ Packet->Header.SplitFlag=NewFrameInfo.SplitFlag;
+ }
+
+ //
+ // At this point we know Packet points to the packet to receive
+ // the buffer into. If this is the LastFrame, then Packet will
+ // have been removed from the OutstandingPackets list, otw it will
+ // be in the list.
+ //
+ // Now get around to getting space for the buffer.
+ //
+
+ //
+ // Find the last buffer in the packet
+ //
+ Buffer = Packet->LastBuffer;
+
+ if (Buffer == NULL)
+ {
+ //
+ // Allocate a new buffer to hold the packet
+ //
+ if (Filter->FreeBufferList == NULL)
+ {
+ if (ArcAllocateBuffers(Filter) != NDIS_STATUS_SUCCESS)
+ {
+ ArcDiscardPacketBuffers(Filter,Packet);
+ //
+ // Do not have to discard any packet that may have
+ // been allocated above, as it will get discarded
+ // the next time a packet comes in from that source.
+ //
+ return;
+ }
+ }
+
+ Buffer = Filter->FreeBufferList;
+ Filter->FreeBufferList = Buffer->Next;
+
+ Packet->FirstBuffer = Packet->LastBuffer = Buffer;
+ Buffer->Next = NULL;
+ }
+
+ // Copy the data off into the ARC_PACKET list.
+ // If it doesn't fit within the current buffer, we'll need to
+ // allocate more
+
+ TmpLength = Length;
+
+ while ( Buffer->BytesLeft < TmpLength )
+ {
+ //
+ // Copy the data
+ //
+
+ NdisMoveFromMappedMemory((PUCHAR) Buffer->Buffer + (Buffer->Size - Buffer->BytesLeft),
+ pData,
+ Buffer->BytesLeft);
+
+ pData += Buffer->BytesLeft;
+ TmpLength -= Buffer->BytesLeft;
+ Buffer->BytesLeft = 0;
+
+ //
+ // Need to allocate more
+ //
+ if (Filter->FreeBufferList == NULL)
+ {
+ if (ArcAllocateBuffers(Filter) != NDIS_STATUS_SUCCESS)
+ {
+ ArcDiscardPacketBuffers(Filter,Packet);
+ //
+ // Do not have to discard any packet that may have
+ // been allocated above, as it will get discarded
+ // the next time a packet comes in from that source.
+ //
+ return;
+ }
+ }
+
+ Buffer->Next = Filter->FreeBufferList;
+ Filter->FreeBufferList = Filter->FreeBufferList->Next;
+ Buffer = Buffer->Next;
+ Buffer->Next = NULL;
+
+ Packet->LastBuffer->Next = Buffer;
+ Packet->LastBuffer = Buffer;
+ }
+
+ //
+ // Copy the last bit
+ //
+
+ NdisMoveFromMappedMemory((PUCHAR) Buffer->Buffer + (Buffer->Size - Buffer->BytesLeft),
+ pData,
+ TmpLength);
+
+
+ Buffer->BytesLeft -= TmpLength;
+ Packet->TotalLength += Length;
+
+ //
+ // And now we can start indicating the packet to the bindings that want it
+ //
+ if (LastFrame)
+ {
+ ArcFilterDoIndication(Filter, Packet);
+ ArcDestroyPacket(Filter, Packet);
+ }
+}
+
+
+
+BOOLEAN
+ArcCreateFilter(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN ARC_FILTER_CHANGE FilterChangeAction,
+ IN ARC_DEFERRED_CLOSE CloseAction,
+ UCHAR AdapterAddress,
+ IN PNDIS_SPIN_LOCK Lock,
+ OUT PARC_FILTER *Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to create and initialize the Arcnet filter database.
+
+Arguments:
+
+ Miniport - Pointer to the mini-port object.
+
+ ChangeAction - Action routine to call when a binding sets or clears
+ a particular filter class and it is the first or only binding using
+ the filter class.
+
+ CloseAction - This routine is called if a binding closes while
+ it is being indicated to via NdisIndicateReceive. It will be
+ called upon return from NdisIndicateReceive.
+
+ AdapterAddress - the address of the adapter associated with this filter
+ database.
+
+ Lock - Pointer to the lock that should be held when mutual exclusion
+ is required.
+
+ Filter - A pointer to an ARC_FILTER. This is what is allocated and
+ created by this routine.
+
+Return Value:
+
+ If the function returns false then one of the parameters exceeded
+ what the filter was willing to support.
+
+--*/
+
+{
+
+ PARC_FILTER LocalFilter;
+ NDIS_STATUS AllocStatus;
+
+ //
+ // Allocate the database and it's associated arrays.
+ //
+
+ AllocStatus = NdisAllocateMemory(&LocalFilter,
+ sizeof(ARC_FILTER),
+ 0,
+ HighestAcceptableMax);
+ *Filter = LocalFilter;
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ {
+ return FALSE;
+ }
+
+ ZeroMemory(LocalFilter, sizeof(ARC_FILTER));
+
+ LocalFilter->Miniport = Miniport;
+ LocalFilter->FreeBindingMask = (ULONG)(-1);
+ LocalFilter->OpenList = NULL;
+ LocalFilter->AdapterAddress = AdapterAddress;
+ LocalFilter->Lock = Lock;
+ LocalFilter->FilterChangeAction = FilterChangeAction;
+ LocalFilter->CloseAction = CloseAction;
+
+ NdisAllocateBufferPool(&AllocStatus,
+ (PNDIS_HANDLE)(&LocalFilter->ReceiveBufferPool),
+ ARC_RECEIVE_BUFFERS);
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ {
+ NdisFreeMemory(LocalFilter, sizeof(ARC_FILTER), 0);
+ return(FALSE);
+ }
+
+ ArcReferencePackage();
+
+ return TRUE;
+}
+
+//
+// NOTE: THIS CANNOT BE PAGEABLE
+//
+VOID
+ArcDeleteFilter(
+ IN PARC_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to delete the memory associated with a filter
+ database. Note that this routines *ASSUMES* that the database
+ has been cleared of any active filters.
+
+Arguments:
+
+ Filter - A pointer to an ARC_FILTER to be deleted.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PARC_PACKET Packet;
+ PARC_BUFFER_LIST Buffer;
+
+ ASSERT(Filter->FreeBindingMask == (MASK)-1);
+ ASSERT(Filter->OpenList == NULL);
+
+
+ NdisFreeBufferPool(Filter->ReceiveBufferPool);
+
+ //
+ // Free all ARC_PACKETS
+ //
+
+ while (Filter->OutstandingPackets != NULL)
+ {
+ Packet = Filter->OutstandingPackets;
+ Filter->OutstandingPackets = Packet->Next;
+
+ //
+ // This puts all the component parts on the free lists.
+ //
+ ArcDestroyPacket(Filter, Packet);
+ }
+
+ while (Filter->FreePackets != NULL)
+ {
+ Packet = Filter->FreePackets;
+ Filter->FreePackets = Packet->Next;
+
+ NdisFreeMemory(Packet, sizeof(ARC_PACKET), 0);
+ }
+
+ while (Filter->FreeBufferList)
+ {
+ Buffer = Filter->FreeBufferList;
+ Filter->FreeBufferList = Buffer->Next;
+
+ NdisFreeMemory(Buffer->Buffer, ARC_BUFFER_SIZE, 0);
+ NdisFreeMemory(Buffer, sizeof(ARC_BUFFER_LIST), 0);
+ }
+
+ NdisFreeMemory(Filter, sizeof(ARC_FILTER), 0);
+
+ ArcDereferencePackage();
+}
+
+
+BOOLEAN
+ArcNoteFilterOpenAdapter(
+ IN PARC_FILTER Filter,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE NdisBindingContext,
+ OUT PNDIS_HANDLE NdisFilterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to add a new binding to the filter database.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE DATABASE IS LOCKED WHEN
+ IT IS CALLED.
+
+Arguments:
+
+ Filter - A pointer to the previously created and initialized filter
+ database.
+
+ MacBindingHandle - The MAC supplied value to the protocol in response
+ to a call to NdisOpenAdapter.
+
+ NdisBindingContext - An NDIS supplied value to the call to NdisOpenAdapter.
+
+ NdisFilterHandle - A pointer to this open.
+
+Return Value:
+
+ Will return false if creating a new filter index will cause the maximum
+ number of filter indexes to be exceeded.
+
+--*/
+
+{
+
+ //
+ // Will hold the value of the filter index so that we
+ // need not indirectly address through pointer parameter.
+ //
+ UINT LocalIndex;
+
+ NDIS_STATUS AllocStatus;
+
+ //
+ // Pointer to new open block.
+ //
+ PARC_BINDING_INFO LocalOpen;
+
+
+ //
+ // Get the first free binding slot and remove that slot from
+ // the free list. We check to see if the list is empty.
+ //
+
+
+ if (Filter->FreeBindingMask == 0)
+ {
+ return FALSE;
+ }
+
+ AllocStatus = NdisAllocateMemory(&LocalOpen,
+ sizeof(ARC_BINDING_INFO),
+ 0,
+ HighestAcceptableMax);
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ {
+ return FALSE;
+ }
+
+ //
+ // Get place for the open and insert it.
+ //
+
+ ARC_FILTER_ALLOC_OPEN(Filter, &LocalIndex);
+
+ LocalOpen->NextOpen = Filter->OpenList;
+ Filter->OpenList = LocalOpen;
+
+ LocalOpen->FilterIndex = (UCHAR)LocalIndex;
+ LocalOpen->References = 1;
+ LocalOpen->MacBindingHandle = MacBindingHandle;
+ LocalOpen->NdisBindingContext = NdisBindingContext;
+ LocalOpen->PacketFilters = 0;
+ LocalOpen->ReceivedAPacket = FALSE;
+
+ *NdisFilterHandle = (NDIS_HANDLE)LocalOpen;
+
+ return TRUE;
+}
+
+
+NDIS_STATUS
+ArcDeleteFilterOpenAdapter(
+ IN PARC_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ When an adapter is being closed this routine should
+ be called to delete knowledge of the adapter from
+ the filter database. This routine is likely to call
+ action routines associated with clearing filter classes
+ and addresses.
+
+ NOTE: THIS ROUTINE SHOULD ****NOT**** BE CALLED IF THE ACTION
+ ROUTINES FOR DELETING THE FILTER CLASSES OR THE MULTICAST ADDRESSES
+ HAVE ANY POSSIBILITY OF RETURNING A STATUS OTHER THAN NDIS_STATUS_PENDING
+ OR NDIS_STATUS_SUCCESS. WHILE THESE ROUTINES WILL NOT BUGCHECK IF
+ SUCH A THING IS DONE, THE CALLER WILL PROBABLY FIND IT DIFFICULT
+ TO CODE A CLOSE ROUTINE!
+
+ NOTE: THIS ROUTINE ASSUMES THAT IT IS CALLED WITH THE LOCK HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routines,
+ this will be passed to it.
+
+Return Value:
+
+ If action routines are called by the various address and filtering
+ routines the this routine will likely return the status returned
+ by those routines. The exception to this rule is noted below.
+
+ Given that the filter and address deletion routines return a status
+ NDIS_STATUS_PENDING or NDIS_STATUS_SUCCESS this routine will then
+ try to return the filter index to the freelist. If the routine
+ detects that this binding is currently being indicated to via
+ NdisIndicateReceive, this routine will return a status of
+ NDIS_STATUS_CLOSING_INDICATING.
+
+--*/
+
+{
+ //
+ // Holds the status returned from the packet filter and address
+ // deletion routines. Will be used to return the status to
+ // the caller of this routine.
+ //
+ NDIS_STATUS StatusToReturn;
+
+ //
+ // Local variable.
+ //
+ PARC_BINDING_INFO LocalOpen = (PARC_BINDING_INFO)NdisFilterHandle;
+
+ StatusToReturn = ArcFilterAdjust(
+ Filter,
+ NdisFilterHandle,
+ NdisRequest,
+ (UINT)0,
+ FALSE
+ );
+
+ if ((StatusToReturn == NDIS_STATUS_SUCCESS) ||
+ (StatusToReturn == NDIS_STATUS_PENDING))
+ {
+ //
+ // Remove the reference from the original open.
+ //
+
+ if (--(LocalOpen->References) == 0)
+ {
+ PARC_BINDING_INFO *ppBI;
+
+ //
+ // Remove it from the list.
+ //
+
+ for (ppBI = &Filter->OpenList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextOpen)
+ {
+ if (*ppBI == LocalOpen)
+ {
+ *ppBI = LocalOpen->NextOpen;
+ break;
+ }
+ }
+ ASSERT(*ppBI == LocalOpen->NextOpen);
+
+ //
+ // First we finish any NdisIndicateReceiveComplete that
+ // may be needed for this binding.
+ //
+
+ if (LocalOpen->ReceivedAPacket)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+ }
+
+ ARC_FILTER_FREE_OPEN(Filter, LocalOpen);
+ }
+ else
+ {
+ //
+ // Let the caller know that there is a reference to the open
+ // by the receive indication. The close action routine will be
+ // called upon return from NdisIndicateReceive.
+ //
+
+ StatusToReturn = NDIS_STATUS_CLOSING_INDICATING;
+ }
+ }
+
+ return StatusToReturn;
+}
+
+
+VOID
+arcUndoFilterAdjust(
+ IN PARC_FILTER Filter,
+ IN PARC_BINDING_INFO Binding
+ )
+{
+ Binding->PacketFilters = Binding->OldPacketFilters;
+ Filter->CombinedPacketFilter = Filter->OldCombinedPacketFilter;
+}
+
+
+
+NDIS_STATUS
+ArcFilterAdjust(
+ IN PARC_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT FilterClasses,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ The FilterAdjust routine will call an action routine when a
+ particular filter class is changes from not being used by any
+ binding to being used by at least one binding or vice versa.
+
+ If the action routine returns a value other than pending or
+ success then this routine has no effect on the packet filters
+ for the open or for the adapter as a whole.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - A pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routine,
+ this will be passed to it.
+
+ FilterClasses - The filter classes that are to be added or
+ deleted.
+
+ Set - A boolean that determines whether the filter classes
+ are being adjusted due to a set or because of a close. (The filtering
+ routines don't care, the MAC might.)
+
+Return Value:
+
+ If it calls the action routine then it will return the
+ status returned by the action routine. If the status
+ returned by the action routine is anything other than
+ NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
+ will be returned to the state it was in upon entrance to this
+ routine.
+
+ If the action routine is not called this routine will return
+ the following statum:
+
+ NDIS_STATUS_SUCCESS - If the new packet filters doesn't change
+ the combined mask of all bindings packet filters.
+
+--*/
+
+{
+ //
+ // Contains the value of the combined filter classes before
+ // it is adjusted.
+ //
+ UINT OldCombined = Filter->CombinedPacketFilter;
+
+ PARC_BINDING_INFO LocalOpen = (PARC_BINDING_INFO)NdisFilterHandle;
+ PARC_BINDING_INFO OpenList;
+
+ //
+ // Contains the value of the particlar opens packet filters
+ // prior to the change. We save this incase the action
+ // routine (if called) returns an "error" status.
+ //
+ UINT OldOpenFilters = LocalOpen->PacketFilters;
+
+ //
+ // Holds the status returned to the user of this routine, if the
+ // action routine is not called then the status will be success,
+ // otherwise, it is whatever the action routine returns.
+ //
+ NDIS_STATUS StatusOfAdjust;
+
+ //
+ // Set the new filter information for the open.
+ //
+ LocalOpen->OldPacketFilters = LocalOpen->PacketFilters;
+ LocalOpen->PacketFilters = FilterClasses;
+
+ //
+ // We always have to reform the compbined filter since
+ // this filter index may have been the only filter index
+ // to use a particular bit.
+ //
+ Filter->OldCombinedPacketFilter = Filter->CombinedPacketFilter;
+
+
+ for (OpenList = Filter->OpenList, Filter->CombinedPacketFilter = 0;
+ OpenList != NULL;
+ OpenList = OpenList->NextOpen)
+ {
+ Filter->CombinedPacketFilter |= OpenList->PacketFilters;
+ }
+
+ if (OldCombined != Filter->CombinedPacketFilter)
+ {
+ StatusOfAdjust = Filter->FilterChangeAction(
+ OldCombined,
+ Filter->CombinedPacketFilter,
+ LocalOpen->MacBindingHandle,
+ NdisRequest,
+ Set
+ );
+
+ if ((StatusOfAdjust != NDIS_STATUS_SUCCESS) &&
+ (StatusOfAdjust != NDIS_STATUS_PENDING))
+ {
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+
+ LocalOpen->PacketFilters = OldOpenFilters;
+ Filter->CombinedPacketFilter = OldCombined;
+ }
+ }
+ else
+ {
+ StatusOfAdjust = NDIS_STATUS_SUCCESS;
+ }
+
+ return StatusOfAdjust;
+}
+
+
+
+VOID
+ArcFilterDoIndication(
+ IN PARC_FILTER Filter,
+ IN PARC_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the filter package only to indicate
+ that a packet is ready to be indicated to procotols.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ Packet - Packet to indicate.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Will hold the type of address that we know we've got.
+ //
+ UINT AddressType;
+
+ NDIS_STATUS StatusOfReceive;
+
+ //
+ // Will hold the filter classes of the binding being indicated.
+ //
+ UINT BindingFilters;
+
+ //
+ // Current Open to indicate to.
+ //
+ PARC_BINDING_INFO LocalOpen, NextOpen;
+
+ if (Packet->Header.ProtHeader.DestId[0] != 0x00)
+ {
+ AddressType = NDIS_PACKET_TYPE_DIRECTED;
+ }
+ else
+ {
+ AddressType = NDIS_PACKET_TYPE_BROADCAST;
+ }
+
+ //
+ // We need to acquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+
+ if (!ArcConvertToNdisPacket(Filter, Packet, TRUE))
+ {
+ //
+ // Out of resources, abort.
+ //
+ return;
+ }
+
+ for (LocalOpen = Filter->OpenList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ NextOpen = LocalOpen->NextOpen;
+
+ //
+ // Reference the open during indication.
+ //
+
+ BindingFilters = LocalOpen->PacketFilters;
+
+ if (BindingFilters & AddressType)
+ {
+ LocalOpen->References++;
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ //
+ // Indicate the packet to the binding.
+ //
+ FilterIndicateReceive(&StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ &Packet->TmpNdisPacket,
+ &(Packet->Header.ProtHeader),
+ 3,
+ Packet->FirstBuffer->Buffer,
+ Packet->FirstBuffer->Size - Packet->FirstBuffer->BytesLeft,
+ Packet->TotalLength);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ if ((--(LocalOpen->References)) == 0)
+ {
+ PARC_BINDING_INFO *ppBI;
+
+ //
+ // This binding is shutting down. We have to kill it.
+ //
+
+ //
+ // Remove it from the list.
+ //
+
+ for (ppBI = &Filter->OpenList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextOpen)
+ {
+ if (*ppBI == LocalOpen)
+ {
+ *ppBI = LocalOpen->NextOpen;
+ break;
+ }
+ }
+ ASSERT(*ppBI == LocalOpen->NextOpen);
+
+ //
+ // Call the IndicateComplete routine.
+ //
+
+
+ if (LocalOpen->ReceivedAPacket)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+ }
+
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+
+ Filter->CloseAction(LocalOpen->MacBindingHandle);
+
+
+ ARC_FILTER_FREE_OPEN(Filter, LocalOpen);
+ } // end of if binding is shutting down
+
+ } // end of if any binding wants the packet
+ } // end of there are more open bindings
+}
+
+
+VOID
+ArcFilterDprIndicateReceiveComplete(
+ IN PARC_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by to indicate that the receive
+ process is complete to all bindings. Only those bindings which
+ have received packets will be notified.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PARC_BINDING_INFO LocalOpen, NextOpen;
+
+ //
+ // We need to acquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+
+
+
+ for (LocalOpen = Filter->OpenList; LocalOpen != NULL; LocalOpen = NextOpen)
+ {
+ NextOpen = LocalOpen->NextOpen;
+
+ if (LocalOpen->ReceivedAPacket)
+ {
+ //
+ // Indicate the binding.
+ //
+
+ LocalOpen->ReceivedAPacket = FALSE;
+
+ LocalOpen->References++;
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ if ((--(LocalOpen->References)) == 0)
+ {
+ PARC_BINDING_INFO *ppBI;
+
+ //
+ // This binding is shutting down. We have to kill it.
+ //
+
+ //
+ // Remove it from the list.
+ //
+
+ for (ppBI = &Filter->OpenList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextOpen)
+ {
+ if (*ppBI == LocalOpen)
+ {
+ *ppBI = LocalOpen->NextOpen;
+ break;
+ }
+ }
+ ASSERT(*ppBI == LocalOpen->NextOpen);
+
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+ Filter->CloseAction(LocalOpen->MacBindingHandle);
+
+ ARC_FILTER_FREE_OPEN(Filter, LocalOpen);
+ }
+ }
+ }
+}
+
+
+NDIS_STATUS
+ArcConvertOidListToEthernet(
+ IN PNDIS_OID OidList,
+ IN PULONG NumberOfOids
+)
+
+/*++
+
+Routine Description:
+
+ This routine converts an arcnet supported OID list into
+ an ethernet OID list by replacing or removing arcnet
+ OID's.
+
+Arguments:
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG c;
+ ULONG cArcOids;
+ ULONG cMaxOids;
+ NDIS_OID EthernetOidList[ARC_NUMBER_OF_EXTRA_OIDS] = {
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE
+ };
+
+ //
+ // Now we need to copy the returned results into the callers buffer,
+ // removing arcnet OID's and adding in ethernet OID's. At this point
+ // we do not know if the callers buffer is big enough since we may
+ // remove some entries, checking it up front may not yield correct
+ // results (i.e. it may actually be big enough).
+ //
+ for (c = 0, cArcOids = 0; c < *NumberOfOids; c++)
+ {
+ switch (OidList[c])
+ {
+ case OID_ARCNET_PERMANENT_ADDRESS:
+ OidList[cArcOids++] = OID_802_3_PERMANENT_ADDRESS;
+ break;
+
+ case OID_ARCNET_CURRENT_ADDRESS:
+ OidList[cArcOids++] = OID_802_3_CURRENT_ADDRESS;
+ break;
+
+ case OID_ARCNET_RECONFIGURATIONS:
+ break;
+
+ default:
+ if ((OidList[c] & 0xFFF00000) != 0x06000000)
+ OidList[cArcOids++] = OidList[c];
+ break;
+ }
+ }
+
+ //
+ // Add the ethernet OIDs.
+ //
+ CopyMemory((PUCHAR)OidList + (cArcOids * sizeof(NDIS_OID)),
+ EthernetOidList,
+ ARC_NUMBER_OF_EXTRA_OIDS * sizeof(NDIS_OID));
+
+ //
+ // Update the size of the buffer to send back to the caller.
+ //
+ *NumberOfOids = cArcOids + ARC_NUMBER_OF_EXTRA_OIDS;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+VOID
+ndisMArcCopyFromBufferToPacket(
+ IN PCHAR Buffer,
+ IN UINT BytesToCopy,
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ OUT PUINT BytesCopied
+ )
+
+/*++
+
+Routine Description:
+
+ Copy from a buffer into an ndis packet.
+
+Arguments:
+
+ Buffer - The packet to copy from.
+
+ Offset - The offset from which to start the copy.
+
+ BytesToCopy - The number of bytes to copy from the buffer.
+
+ Packet - The destination of the copy.
+
+ BytesCopied - The number of bytes actually copied. Will be less
+ than BytesToCopy if the packet is not large enough.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ //
+ // Holds the count of the number of ndis buffers comprising the
+ // destination packet.
+ //
+ UINT DestinationBufferCount;
+
+ //
+ // Points to the buffer into which we are putting data.
+ //
+ PNDIS_BUFFER DestinationCurrentBuffer;
+
+ //
+ // Points to the location in Buffer from which we are extracting data.
+ //
+ PUCHAR SourceCurrentAddress;
+
+ //
+ // Holds the virtual address of the current destination buffer.
+ //
+ PVOID DestinationVirtualAddress;
+
+ //
+ // Holds the length of the current destination buffer.
+ //
+ UINT DestinationCurrentLength;
+
+ //
+ // Keep a local variable of BytesCopied so we aren't referencing
+ // through a pointer.
+ //
+ UINT LocalBytesCopied = 0;
+
+
+ //
+ // Take care of boundary condition of zero length copy.
+ //
+
+ *BytesCopied = 0;
+ if (!BytesToCopy)
+ return;
+
+ //
+ // Get the first buffer of the destination.
+ //
+
+ NdisQueryPacket(Packet,
+ NULL,
+ &DestinationBufferCount,
+ &DestinationCurrentBuffer,
+ NULL);
+
+ //
+ // Could have a null packet.
+ //
+
+ if (!DestinationBufferCount)
+ return;
+
+ NdisQueryBuffer(DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength);
+
+ //
+ // Set up the source address.
+ //
+
+ SourceCurrentAddress = Buffer;
+
+ while (LocalBytesCopied < BytesToCopy)
+ {
+ //
+ // Check to see whether we've exhausted the current destination
+ // buffer. If so, move onto the next one.
+ //
+
+ if (!DestinationCurrentLength)
+ {
+ NdisGetNextBuffer(DestinationCurrentBuffer, &DestinationCurrentBuffer);
+
+ if (!DestinationCurrentBuffer)
+ {
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.)
+ //
+
+ break;
+ }
+
+ NdisQueryBuffer(DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength);
+
+ continue;
+ }
+
+ //
+ // Try to get us up to the point to start the copy.
+ //
+
+ if (Offset)
+ {
+ if (Offset > DestinationCurrentLength)
+ {
+ //
+ // What we want isn't in this buffer.
+ //
+
+ Offset -= DestinationCurrentLength;
+ DestinationCurrentLength = 0;
+ continue;
+ }
+ else
+ {
+ DestinationVirtualAddress = (PCHAR)DestinationVirtualAddress + Offset;
+ DestinationCurrentLength -= Offset;
+ Offset = 0;
+ }
+ }
+
+ //
+ // Copy the data.
+ //
+ {
+
+ //
+ // Holds the amount of data to move.
+ //
+ UINT AmountToMove;
+
+ //
+ // Holds the amount desired remaining.
+ //
+ UINT Remaining = BytesToCopy - LocalBytesCopied;
+
+
+ AmountToMove = DestinationCurrentLength;
+
+ AmountToMove = ((Remaining < AmountToMove)?
+ (Remaining):(AmountToMove));
+
+ NdisMoveFromMappedMemory(DestinationVirtualAddress,
+ SourceCurrentAddress,
+ AmountToMove);
+
+ SourceCurrentAddress += AmountToMove;
+ LocalBytesCopied += AmountToMove;
+ DestinationCurrentLength -= AmountToMove;
+
+ }
+ }
+
+ *BytesCopied = LocalBytesCopied;
+}
+
+VOID
+ndisMArcIndicateEthEncapsulatedReceive(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PVOID HeaderBuffer,
+ IN PVOID DataBuffer,
+ IN UINT Length
+ )
+/*++
+
+ HeaderBuffer - This is the 878.2 header.
+ DataBuffer - This is the 802.3 header.
+ Length - This is the length of the ethernet frame.
+
+--*/
+{
+ ULONG MacReceiveContext[2];
+
+ //
+ // Indicate the packet.
+ //
+
+ MacReceiveContext[0] = (ULONG) DataBuffer;
+ MacReceiveContext[1] = (ULONG) Length;
+
+ if (Length > 14)
+ {
+ ULONG PacketLength = 0;
+ PUCHAR Header = DataBuffer;
+
+ PacketLength = (ULONG)(((USHORT)Header[12] << 8) | (USHORT)Header[13]);
+
+ NdisMEthIndicateReceive(
+ (NDIS_HANDLE)Miniport, // miniport handle.
+ (NDIS_HANDLE)MacReceiveContext, // receive context.
+ DataBuffer, // ethernet header.
+ 14, // ethernet header length.
+ (PUCHAR)DataBuffer + 14, // ethernet data.
+ PacketLength, // ethernet data length.
+ PacketLength); // ethernet data length.
+ }
+ else
+ {
+ NdisMEthIndicateReceive(
+ (NDIS_HANDLE)Miniport, // miniport handle.
+ (NDIS_HANDLE)MacReceiveContext, // receive context.
+ DataBuffer, // ethernet header.
+ Length, // ethernet header length.
+ NULL, // ethernet data.
+ 0, // ethernet data length.
+ 0); // ethernet data length.
+ }
+}
+
+NDIS_STATUS
+ndisMArcTransferData(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET DstPacket,
+ OUT PUINT BytesTransferred
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the transfer data calls to arcnet mini-port.
+
+Arguments:
+
+ NdisBindingHandle - Pointer to open block.
+
+ MacReceiveContext - Context given for the indication
+
+ ByteOffset - Offset to start transfer at.
+
+ BytesToTransfer - Number of bytes to transfer
+
+ Packet - Packet to transfer into
+
+ BytesTransferred - the number of actual bytes copied
+
+Return values:
+
+ NDIS_STATUS_SUCCESS, if successful, else NDIS_STATUS_FAILURE.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PNDIS_M_OPEN_BLOCK MiniportOpen;
+ PNDIS_PACKET SrcPacket;
+ PNDIS_BUFFER NdisBuffer;
+ NDIS_STATUS Status;
+ NDIS_PACKET TempPacket;
+ KIRQL OldIrql;
+
+ MiniportOpen = (PNDIS_M_OPEN_BLOCK) NdisBindingHandle;
+ Miniport = MiniportOpen->MiniportHandle;
+ NdisBuffer = NULL;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ //
+ // If this is encapsulated ethernet then we don't currently
+ // have the source packet from which to copy from.
+ //
+
+ if (MINIPORT_TEST_FLAG(MiniportOpen, fMINIPORT_OPEN_USING_ETH_ENCAPSULATION))
+ {
+ //
+ // If this is not loopback then we need to create a
+ // temp NDIS_PACKET for the packet-to-packet copy.
+ //
+ if (!Miniport->LoopbackPacket)
+ {
+ PUCHAR DataBuffer = (PUCHAR)((PULONG) MacReceiveContext)[0];
+ UINT DataLength = (UINT)((PULONG) MacReceiveContext)[1];
+
+ //
+ // We'll always be in the scope of this function so we
+ // can use local stack space rather than allocating dynamic
+ // memory.
+ //
+ SrcPacket = &TempPacket; // Use the local stack for packet store.
+
+ ZeroMemory(SrcPacket, sizeof(NDIS_PACKET));
+
+ NdisAllocateBuffer(&Status, // Status code.
+ &NdisBuffer, // NDIS buffer to chain onto the packet.
+ NULL, // On NT, this parameter is ignored.
+ DataBuffer, // The ethernet frame.
+ DataLength); // The ethernet frame length.
+
+ NdisChainBufferAtFront(SrcPacket, NdisBuffer);
+ }
+ else
+ {
+ SrcPacket = Miniport->LoopbackPacket;
+
+ ByteOffset += 3; // Skip fake arcnet header.
+ }
+
+ //
+ // Skip the ethernet header.
+ //
+
+ ByteOffset += 14;
+ }
+ else
+ {
+ SrcPacket = (PNDIS_PACKET) MacReceiveContext;
+ }
+
+ //
+ // Now we can simply copy from the source packet to the
+ // destination packet.
+ //
+ NdisCopyFromPacketToPacket(DstPacket, // destination packet.
+ 0, // destination offset.
+ BytesToTransfer, // bytes to copy.
+ SrcPacket, // source packet.
+ ByteOffset, // source offset.
+ BytesTransferred);// bytes copied.
+
+ //
+ // If we allocated an NDIS_BUFFER then we need to free it. We don't
+ // need to unchain the buffer from the packet since the packet is
+ // a local stack variable the will just get trashed anyway.
+ //
+
+ if (NdisBuffer != NULL)
+ {
+ NdisFreeBuffer(NdisBuffer);
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+NDIS_STATUS
+ndisMArcnetSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ PNDIS_PACKET_RESERVED Reserved;
+ KIRQL OldIrql;
+ BOOLEAN LocalLock;
+ PSINGLE_LIST_ENTRY Link;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'w');
+
+ ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++;
+
+ //
+ // Handle protocol requests
+ //
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ Reserved->Next = NULL;
+ Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+
+ //
+ // Place the packet on the packet queue.
+ //
+ if (Miniport->FirstPacket == NULL)
+ {
+ //
+ // Place the packet at the head of the queue.
+ //
+ Miniport->FirstPacket = Packet;
+ }
+ else
+ {
+ CHECK_FOR_DUPLICATE_PACKET(Miniport, Packet);
+
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = Packet;
+ }
+
+ Miniport->LastPacket = Packet;
+
+ MINIPORT_CLEAR_PACKET_FLAG(Packet, fPACKET_HAS_BEEN_LOOPED_BACK);
+
+ if (Miniport->FirstPendingPacket == NULL)
+ {
+ Miniport->FirstPendingPacket = Packet;
+ }
+
+ //
+ // Queue a workitem to process the send.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+
+ //
+ // Can we get the lock?
+ //
+ if (LocalLock)
+ {
+ //
+ // If we did not lock down the mini-port, then some other routine will
+ // do this processing for us. Otherwise we need to do this processing.
+ //
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'W');
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ return(NDIS_STATUS_PENDING);
+}
+
+NDIS_STATUS
+ndisMBuildArcnetHeader(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_M_OPEN_BLOCK Open,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_BUFFER TmpBuffer;
+ UINT Flags;
+ PUCHAR Address;
+ PARC_BUFFER_LIST Buffer;
+ PNDIS_BUFFER NdisBuffer;
+ NDIS_STATUS Status;
+
+ //
+ // Only ethernet encapsulation needs this.
+ //
+ if (!MINIPORT_TEST_FLAG(Open, fMINIPORT_OPEN_USING_ETH_ENCAPSULATION))
+ {
+ return(NDIS_STATUS_SUCCESS);
+ }
+
+ if (NULL == Miniport->ArcnetFreeBufferList)
+ {
+ //
+ // Set flag
+ //
+ CLEAR_RESOURCE(Miniport, 'S');
+
+ return(NDIS_STATUS_PENDING);
+ }
+
+ NdisQueryPacket(Packet, NULL, NULL, &TmpBuffer, NULL);
+ NdisQueryBuffer(TmpBuffer, &Address, &Flags);
+
+ Buffer = Miniport->ArcnetFreeBufferList;
+ Miniport->ArcnetFreeBufferList = Buffer->Next;
+
+ NdisAllocateBuffer(&Status,
+ &NdisBuffer,
+ Miniport->ArcnetBufferPool,
+ Buffer->Buffer,
+ 3);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ Buffer->Next = Miniport->ArcnetFreeBufferList;
+ Miniport->ArcnetFreeBufferList = Buffer;
+ CLEAR_RESOURCE(Miniport, 'S');
+
+ return(NDIS_STATUS_PENDING);
+ }
+
+ Buffer->Next = Miniport->ArcnetUsedBufferList;
+ Miniport->ArcnetUsedBufferList = Buffer;
+
+ NdisChainBufferAtFront(Packet, NdisBuffer);
+
+ ((PUCHAR)Buffer->Buffer)[0] = Miniport->ArcnetAddress;
+
+ if (Address[0] & 0x01)
+ {
+ //
+ // Broadcast
+ //
+ ((PUCHAR)Buffer->Buffer)[1] = 0x00;
+ }
+ else
+ {
+ ((PUCHAR)Buffer->Buffer)[1] = Address[5];
+ }
+
+ ((PUCHAR) Buffer->Buffer)[2] = 0xE8;
+
+}
+
+VOID
+ndisMFreeArcnetHeader(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+ This function strips off the arcnet header appended to
+ ethernet encapsulated packets
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+ Packet - Ndis packet.
+
+
+ None.
+
+--*/
+{
+ PNDIS_M_OPEN_BLOCK Open;
+ PARC_BUFFER_LIST Buffer, TmpBuffer;
+ PNDIS_BUFFER NdisBuffer;
+ PVOID BufferVa;
+ UINT Length;
+
+ Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Open;
+
+ if (MINIPORT_TEST_FLAG(Open, fMINIPORT_OPEN_USING_ETH_ENCAPSULATION))
+ {
+ NdisUnchainBufferAtFront(Packet, &NdisBuffer);
+
+ NdisQueryBuffer(NdisBuffer, (PVOID *)&BufferVa, &Length);
+
+ NdisFreeBuffer(NdisBuffer);
+
+ Buffer = Miniport->ArcnetUsedBufferList;
+
+ if (Buffer->Buffer == BufferVa)
+ {
+ Miniport->ArcnetUsedBufferList = Buffer->Next;
+ }
+ else
+ {
+ while (Buffer->Next->Buffer != BufferVa)
+ {
+ Buffer = Buffer->Next;
+ }
+
+ TmpBuffer = Buffer->Next;
+ Buffer->Next = Buffer->Next->Next;
+ Buffer = TmpBuffer;
+ }
+
+ Buffer->Next = Miniport->ArcnetFreeBufferList;
+ Miniport->ArcnetFreeBufferList = Buffer;
+ }
+}
+
+BOOLEAN
+FASTCALL
+ndisMArcnetSendLoopback(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_PACKET Packet
+ )
+
+/*++
+
+ Routine Description:
+
+ Checks if a packet needs to be loopbacked and does so if necessary.
+
+ NOTE: Must be called at DPC_LEVEL with lock HELD!
+
+ Arguments:
+
+ Miniport - Miniport to send to.
+ Packet - Packet to loopback.
+
+ Return Value:
+
+ FALSE if the packet should be sent on the net, TRUE if it is
+ a self-directed packet.
+
+--*/
+
+{
+ BOOLEAN Loopback;
+ BOOLEAN SelfDirected;
+ PNDIS_BUFFER FirstBuffer;
+ UINT BufferLength;
+ PUCHAR BufferAddress;
+ UINT Length;
+ UINT AddressLength;
+
+ // We should not be here if the driver handles loopback
+ ASSERT(Miniport->MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK);
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(NdisMediumArcnet878_2 == Miniport->MediaType);
+
+ FirstBuffer = Packet->Private.Head;
+ BufferAddress = MDL_ADDRESS(FirstBuffer);
+
+ //
+ // Is this an ethernet encapsulated packet?
+ //
+ if (ARC_PACKET_IS_ENCAPSULATED(Packet))
+ {
+ //
+ // The second buffer in the packet is the ethernet
+ // header so we need to get that one before we can
+ // proceed.
+ //
+ NdisGetNextBuffer(FirstBuffer, &FirstBuffer);
+
+ BufferAddress = MDL_ADDRESS(FirstBuffer);
+
+ // Length -= 3; Length is not valid at this point. Do this later when
+ // we determine that we need to loopback for certain
+
+ //
+ // Now we can continue as though this were ethernet.
+ //
+ EthShouldAddressLoopBackMacro(
+ Miniport->EthDB,
+ BufferAddress,
+ &Loopback,
+ &SelfDirected);
+ }
+ else
+ {
+ Loopback = ((BufferAddress[0] == BufferAddress[1]) ||
+ ((BufferAddress[1] == 0x00) &&
+ (ARC_QUERY_FILTER_CLASSES(Miniport->ArcDB) |
+ NDIS_PACKET_TYPE_BROADCAST)));
+
+ if (BufferAddress[0] == BufferAddress[1])
+ {
+ SelfDirected = TRUE;
+ Loopback = TRUE;
+ }
+ else
+ {
+ SelfDirected = FALSE;
+ }
+ }
+
+ //
+ // If it's not a loopback packet then get out of here!
+ //
+ if (!Loopback)
+ {
+ ASSERT(!SelfDirected);
+ return(SelfDirected);
+ }
+
+ //
+ // Get the buffer length
+ //
+ NdisQueryPacket(Packet, NULL, NULL, NULL, &Length);
+
+ //
+ // If the packet is encapsulated ethernet then don't count the
+ // arcnet header in with the length.
+ //
+ if (ARC_PACKET_IS_ENCAPSULATED(Packet))
+ {
+ Length -= ARC_PROTOCOL_HEADER_SIZE;
+ }
+
+ //
+ // See if we need to copy the data from the packet
+ // into the loopback buffer.
+ //
+ // We need to copy to the local loopback buffer if
+ // the first buffer of the packet is less than the
+ // minimum loopback size AND the first buffer isn't
+ // the total packet.
+ //
+ BufferLength = MDL_SIZE(FirstBuffer);
+// BufferLength = (UINT)((PUSHORT)BufferAddress)[6]; // Hack around.
+
+ if ((BufferLength < NDIS_M_MAX_LOOKAHEAD) && (BufferLength != Length))
+ {
+ UINT BytesToCopy;
+ UINT Offset;
+
+ if (ARC_PACKET_IS_ENCAPSULATED(Packet))
+ {
+ //
+ // Copy the encapsulated ethernet header.
+ //
+ BytesToCopy = 14;
+
+ //
+ // Skip the fake arcnet header.
+ //
+ Offset = 3;
+ }
+ else
+ {
+ //
+ // Copy the arcnet header.
+ //
+ BytesToCopy = ARC_PROTOCOL_HEADER_SIZE;
+
+ //
+ // Don't skip anything.
+ //
+ Offset = 0;
+ }
+
+ BufferAddress = Miniport->ArcnetLookaheadBuffer;
+ BytesToCopy += Miniport->CurrentLookahead;
+
+ ndisMCopyFromPacketToBuffer(
+ Packet, // Packet to copy from.
+ Offset, // Offset from beginning of packet.
+ BytesToCopy, // Number of bytes to copy.
+ BufferAddress, // The destination buffer.
+ &BufferLength); // The number of bytes copied.
+ }
+
+ Miniport->LoopbackPacket = Packet;
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'L');
+
+ //
+ // Indicate the packet to every open binding
+ // that could want it.
+ //
+ if (ARC_PACKET_IS_ENCAPSULATED(Packet))
+ {
+ EthFilterDprIndicateReceive(
+ Miniport->EthDB,
+ Packet,
+ BufferAddress,
+ BufferAddress,
+ 14,
+ BufferAddress + 14,
+ BufferLength - 14,
+ Length - 14);
+
+ EthFilterDprIndicateReceiveComplete(Miniport->EthDB);
+ }
+ else
+ {
+ PUCHAR PlaceInBuffer;
+ PUCHAR ArcDataBuffer;
+ UINT ArcDataLength;
+ UINT PacketDataOffset;
+ UCHAR FrameCount;
+ UCHAR i;
+ UINT IndicateDataLength;
+
+ //
+ // Calculate how many frames we will need.
+ //
+ ArcDataLength = Length - ARC_PROTOCOL_HEADER_SIZE;
+ PacketDataOffset = ARC_PROTOCOL_HEADER_SIZE;
+
+ FrameCount = (UCHAR)(ArcDataLength / ARC_MAX_FRAME_SIZE);
+
+ if ((ArcDataLength % ARC_MAX_FRAME_SIZE) != 0)
+ {
+ FrameCount++;
+ }
+
+ for (i = 0; i < FrameCount; ++i)
+ {
+ PlaceInBuffer = Miniport->ArcnetLookaheadBuffer;
+
+ //
+ // Point data buffer to start of 'data'
+ // Don't include system code as part of data
+ //
+ ArcDataBuffer = Miniport->ArcnetLookaheadBuffer +
+ ARC_PROTOCOL_HEADER_SIZE;
+
+ //
+ // Copy Header (SrcId/DestId/ProtId)
+ //
+ ndisMCopyFromPacketToBuffer(
+ Packet,
+ 0,
+ ARC_PROTOCOL_HEADER_SIZE,
+ PlaceInBuffer,
+ &BufferLength);
+
+ PlaceInBuffer += ARC_PROTOCOL_HEADER_SIZE;
+
+ //
+ // Put in split flag
+ //
+ if (FrameCount > 1)
+ {
+ //
+ // Multi-frame indication...
+ //
+ if ( i == 0 )
+ {
+ //
+ // first frame
+ //
+
+ // *PlaceInBuffer = ( (FrameCount - 2) * 2 ) + 1;
+
+ *PlaceInBuffer = 2 * FrameCount - 3;
+ }
+ else
+ {
+ //
+ // Subsequent frame
+ //
+ *PlaceInBuffer = ( i * 2 );
+ }
+ }
+ else
+ {
+ //
+ // Only frame in the indication
+ //
+ *PlaceInBuffer = 0;
+ }
+
+ //
+ // Skip split flag
+ //
+ PlaceInBuffer++;
+
+ //
+ // Put in packet number.
+ //
+ *PlaceInBuffer++ = 0;
+ *PlaceInBuffer++ = 0;
+
+ //
+ // Copy data
+ //
+ if (ArcDataLength > ARC_MAX_FRAME_SIZE)
+ {
+ IndicateDataLength = ARC_MAX_FRAME_SIZE;
+ }
+ else
+ {
+ IndicateDataLength = ArcDataLength;
+ }
+
+ ndisMCopyFromPacketToBuffer(
+ Packet,
+ PacketDataOffset,
+ IndicateDataLength,
+ PlaceInBuffer,
+ &BufferLength);
+
+ //
+ // Indicate the actual data length which should not
+ // include the system code.
+ //
+ ArcFilterDprIndicateReceive(
+ Miniport->ArcDB,
+ Miniport->ArcnetLookaheadBuffer,
+ ArcDataBuffer,
+ IndicateDataLength + ARC_PROTOCOL_HEADER_SIZE);
+
+ ArcDataLength -= ARC_MAX_FRAME_SIZE;
+ PacketDataOffset += ARC_MAX_FRAME_SIZE;
+ }
+
+ ArcFilterDprIndicateReceiveComplete(Miniport->ArcDB);
+ }
+
+ Miniport->LoopbackPacket = NULL;
+
+ return(SelfDirected);
+}
+
+
diff --git a/private/ntos/ndis/ndis40/bus.c b/private/ntos/ndis/ndis40/bus.c
new file mode 100644
index 000000000..4cc6b0d29
--- /dev/null
+++ b/private/ntos/ndis/ndis40/bus.c
@@ -0,0 +1,1009 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ bus.c
+
+Abstract:
+
+ NDIS wrapper functions to handle specific buses
+
+Author:
+
+ Adam Barr (adamba) 11-Jul-1990
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ 26-Feb-1991 JohnsonA Added Debugging Code
+ 10-Jul-1991 JohnsonA Implement revised Ndis Specs
+ 01-Jun-1995 JameelH Re-organization/optimization
+ 06-Dec-1996 KyleB Placed a sanity check for MCA SlotNumber in
+ ndisFixBusInformation.
+
+--*/
+
+
+#include <precomp.h>
+#pragma hdrstop
+
+#include <stdarg.h>
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_BUS
+
+VOID
+NdisReadEisaSlotInformation(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PUINT SlotNumber,
+ OUT PNDIS_EISA_FUNCTION_INFORMATION EisaData
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads the EISA data from the slot given.
+
+Arguments:
+
+ Status - Status of request to be returned to the user.
+ WrapperConfigurationContext - Context passed to MacAddAdapter.
+ SlotNumber - the EISA Slot where the card is at.
+ EisaData - pointer to a buffer where the EISA configuration is to be returned.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_EISA_FUNCTION_INFORMATION pData;
+ UINT NumberOfFunctions;
+
+ NdisReadEisaSlotInformationEx(Status,
+ WrapperConfigurationContext,
+ SlotNumber,
+ &pData,
+ &NumberOfFunctions);
+ if (*Status == NDIS_STATUS_SUCCESS)
+ {
+ ASSERT(NumberOfFunctions > 0);
+ *EisaData = *pData;
+ }
+}
+
+
+VOID
+NdisReadEisaSlotInformationEx(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PUINT SlotNumber,
+ OUT PNDIS_EISA_FUNCTION_INFORMATION *EisaData,
+ OUT PUINT NumberOfFunctions
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads the EISA data from the slot given.
+
+Arguments:
+
+ Status - Status of request to be returned to the user.
+ WrapperConfigurationContext - Context passed to MacAddAdapter.
+ SlotNumber - the EISA Slot where the card is at.
+ EisaData - pointer to a buffer where the EISA configuration is to be returned.
+ NumberOfFunctions - Returns the number of function structures in the EisaData.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_EISA_FUNCTION_INFORMATION EisaBlockPointer;
+ PNDIS_EISA_SLOT_INFORMATION SlotInformation;
+ NTSTATUS NtStatus;
+ ULONG BusNumber;
+ ULONG DataLength;
+ NDIS_INTERFACE_TYPE BusType;
+ NDIS_CONFIGURATION_HANDLE NdisConfiguration;
+
+ //
+ // Get the BusNumber and the BusType from the Context here!!
+ //
+ NdisConfiguration.KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ BusType = (NDIS_INTERFACE_TYPE)(NdisConfiguration.KeyQueryTable[3].DefaultType);
+ BusNumber = NdisConfiguration.KeyQueryTable[3].DefaultLength;
+
+ *Status = NDIS_STATUS_FAILURE; // Assume failure
+
+ do
+ {
+ //
+ // First check if any bus access is allowed
+ //
+ if (BusType != Eisa)
+ {
+ break;
+ }
+
+ SlotInformation = NdisConfiguration.KeyQueryTable[3].DefaultData;
+ *NumberOfFunctions = 2;
+
+ //
+ // Was there already a buffer allocated?
+ //
+
+ if (SlotInformation == NULL)
+ {
+ //
+ // No, allocate a buffer
+ //
+
+ SlotInformation = (PNDIS_EISA_SLOT_INFORMATION)
+ ALLOC_FROM_POOL(sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION)),
+ NDIS_TAG_SLOT_INFO);
+
+ if (SlotInformation == NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ //
+ // Free any old buffer
+ //
+
+ if (NdisConfiguration.KeyQueryTable[3].DefaultData != NULL)
+ {
+ FREE_POOL(NdisConfiguration.KeyQueryTable[3].DefaultData);
+ }
+
+ NdisConfiguration.KeyQueryTable[3].DefaultData = SlotInformation;
+ }
+
+ //
+ // Now get the slot number that we read in earlier
+ //
+ *SlotNumber = NdisConfiguration.KeyQueryTable[4].DefaultLength;
+ DataLength = HalGetBusDataByOffset(EisaConfiguration,
+ BusNumber,
+ *SlotNumber,
+ (PVOID)SlotInformation,
+ 0,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION)));
+
+ //
+ // Check for multiple functions in the Eisa data.
+ //
+ while (DataLength == (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION)))
+ {
+ *NumberOfFunctions++;
+
+ //
+ // Now allocate a new buffer
+ //
+
+ SlotInformation = (PNDIS_EISA_SLOT_INFORMATION)
+ ALLOC_FROM_POOL(sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ (*NumberOfFunctions *sizeof(NDIS_EISA_FUNCTION_INFORMATION)),
+ NDIS_TAG_SLOT_INFO);
+
+ if (SlotInformation == NULL)
+ {
+ break;
+ }
+
+ //
+ // Free any old buffer
+ //
+
+ if (NdisConfiguration.KeyQueryTable[3].DefaultData != NULL)
+ {
+ FREE_POOL(NdisConfiguration.KeyQueryTable[3].DefaultData);
+ }
+
+ NdisConfiguration.KeyQueryTable[3].DefaultData = SlotInformation;
+
+ //
+ // Get new information
+ //
+
+ DataLength = HalGetBusDataByOffset(EisaConfiguration,
+ BusNumber,
+ *SlotNumber,
+ (PVOID)SlotInformation,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ 0,
+ (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION)));
+ }
+
+ if (SlotInformation == NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+
+ EisaBlockPointer = (PNDIS_EISA_FUNCTION_INFORMATION)
+ ((PUCHAR)SlotInformation + sizeof(CM_EISA_SLOT_INFORMATION));
+
+ *EisaData = EisaBlockPointer;
+ *NumberOfFunctions--; // We overshoot by 1 to verify last one found.
+ *Status = NDIS_STATUS_SUCCESS;
+ } while (FALSE);
+}
+
+
+VOID
+NdisReadMcaPosInformation(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PUINT ChannelNumber,
+ OUT PNDIS_MCA_POS_DATA McaData
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads the MCA data from the POS corresponding to
+ the channel specified.
+
+Arguments:
+
+ WrapperConfigurationContext - Context passed to MacAddAdapter.
+ ChannelNumber - the MCA channel number.
+ McaData - pointer to a buffer where the channel information is to be
+ returned.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NDIS_CONFIGURATION_HANDLE NdisConfiguration;
+ ULONG DataLength;
+
+ //
+ // Get the BusNumber and the BusType from the Context here!!
+ //
+ NdisConfiguration.KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ BusType = (NDIS_INTERFACE_TYPE)(NdisConfiguration.KeyQueryTable[3].DefaultType);
+ BusNumber = NdisConfiguration.KeyQueryTable[3].DefaultLength;
+
+ *Status = NDIS_STATUS_FAILURE;
+ *ChannelNumber = 0;
+
+ do
+ {
+ //
+ // First check if any bus access is allowed
+ //
+ if (BusType != MicroChannel)
+ {
+ break;
+ }
+
+ //
+ // Get the channel number that we read in earlier. Note that the HAL
+ // apis expect the channel to be zero based.
+ //
+ *ChannelNumber = NdisConfiguration.KeyQueryTable[4].DefaultLength;
+
+ DataLength = HalGetBusDataByOffset(Pos,
+ BusNumber,
+ *ChannelNumber - 1,
+ (PVOID)McaData,
+ 0,
+ sizeof(NDIS_MCA_POS_DATA));
+ *Status = NDIS_STATUS_SUCCESS;
+ } while (FALSE);
+}
+
+
+ULONG
+NdisImmediateReadPciSlotInformation(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This routine reads from the PCI configuration space a specified
+ length of bytes at a certain offset.
+
+Arguments:
+
+ WrapperConfigurationContext - Context passed to MacAddAdapter.
+
+ SlotNumber - The slot number of the device.
+
+ Offset - Offset to read from
+
+ Buffer - Place to store the bytes
+
+ Length - Number of bytes to read
+
+Return Value:
+
+ Returns the number of bytes read.
+
+--*/
+{
+ ULONG DataLength = 0;
+ ULONG BusNumber;
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable;
+ KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ ASSERT((NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType) == NdisInterfacePci);
+ DataLength = HalGetBusDataByOffset(PCIConfiguration,
+ BusNumber,
+ SlotNumber,
+ Buffer,
+ Offset,
+ Length);
+ return DataLength;
+}
+
+
+ULONG
+NdisImmediateWritePciSlotInformation(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This routine writes to the PCI configuration space a specified
+ length of bytes at a certain offset.
+
+Arguments:
+
+ WrapperConfigurationContext - Context passed to MacAddAdapter.
+
+ SlotNumber - The slot number of the device.
+
+ Offset - Offset to read from
+
+ Buffer - Place to store the bytes
+
+ Length - Number of bytes to read
+
+Return Value:
+
+ Returns the number of bytes written.
+
+--*/
+{
+ ULONG DataLength = 0;
+ ULONG BusNumber;
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable;
+ KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ ASSERT((NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType) == NdisInterfacePci);
+ DataLength = HalSetBusDataByOffset(PCIConfiguration,
+ BusNumber,
+ SlotNumber,
+ Buffer,
+ Offset,
+ Length);
+ return DataLength;
+}
+
+
+ULONG
+NdisReadPciSlotInformation(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This routine reads from the PCI configuration space a specified
+ length of bytes at a certain offset.
+
+Arguments:
+
+ NdisAdapterHandle - Adapter we are talking about.
+
+ SlotNumber - The slot number of the device.
+
+ Offset - Offset to read from
+
+ Buffer - Place to store the bytes
+
+ Length - Number of bytes to read
+
+Return Value:
+
+ Returns the number of bytes read.
+
+--*/
+{
+ ULONG DataLength = 0;
+ PNDIS_ADAPTER_BLOCK Adapter = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle;
+
+ if (Adapter->DeviceObject == NULL)
+ {
+ //
+ // This is a mini-port
+ //
+ ASSERT(Miniport->BusType == NdisInterfacePci);
+
+ DataLength = HalGetBusDataByOffset(PCIConfiguration,
+ Miniport->BusNumber,
+ SlotNumber,
+ Buffer,
+ Offset,
+ Length);
+ }
+ else
+ {
+ ASSERT(Adapter->BusType == NdisInterfacePci);
+ DataLength = HalGetBusDataByOffset(PCIConfiguration,
+ Adapter->BusNumber,
+ SlotNumber,
+ Buffer,
+ Offset,
+ Length);
+ }
+ return DataLength;
+}
+
+
+ULONG
+NdisWritePciSlotInformation(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This routine writes to the PCI configuration space a specified
+ length of bytes at a certain offset.
+
+Arguments:
+
+ NdisAdapterHandle - Adapter we are talking about.
+
+ SlotNumber - The slot number of the device.
+
+ Offset - Offset to read from
+
+ Buffer - Place to store the bytes
+
+ Length - Number of bytes to read
+
+Return Value:
+
+ Returns the number of bytes written.
+
+--*/
+{
+ ULONG DataLength = 0;
+ PNDIS_ADAPTER_BLOCK Adapter = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle;
+
+ if (Adapter->DeviceObject == NULL)
+ {
+ //
+ // This is a mini-port
+ //
+ ASSERT(Miniport->BusType == NdisInterfacePci);
+ DataLength = HalSetBusDataByOffset(PCIConfiguration,
+ Miniport->BusNumber,
+ SlotNumber,
+ Buffer,
+ Offset,
+ Length);
+ }
+ else
+ {
+ ASSERT(Adapter->BusType == NdisInterfacePci);
+ DataLength = HalSetBusDataByOffset(PCIConfiguration,
+ Adapter->BusNumber,
+ SlotNumber,
+ Buffer,
+ Offset,
+ Length);
+ }
+ return DataLength;
+}
+
+
+VOID
+NdisOverrideBusNumber(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN NDIS_HANDLE MiniportAdapterHandle OPTIONAL,
+ IN ULONG BusNumber
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to override the BusNumber value retrieved
+ from the registry. It is expected to be used by PCI drivers
+ that discover that their adapter's bus number has changed.
+
+Arguments:
+
+ WrapperConfigurationContext - a handle pointing to an RTL_QUERY_REGISTRY_TABLE
+ that is set up for this driver's parameters.
+
+ MiniportAdapterHandle - points to the adapter block, if the calling
+ driver is a miniport. If the calling driver is a full MAC, this
+ parameter must be NULL.
+
+ BusNumber - the new bus number.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+
+ ((PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext)[3].DefaultLength = BusNumber;
+
+ if (Miniport != NULL)
+ {
+ Miniport->BusNumber = BusNumber;
+ }
+}
+
+
+
+NDIS_STATUS
+ndisFixBusInformation(
+ IN PNDIS_CONFIGURATION_HANDLE ConfigHandle,
+ IN PBUS_SLOT_DB pDb
+ )
+/*++
+
+ Make sure that the card is in the slot that the registry says it is. If it is not,
+ scan the bus to see if we find the card. If we do, then fix up the registry so that
+ next time we do not have to do this. Also keep track of the cards so that we handle
+ multiple instances.
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_FAILURE;
+ ULONGLONG Buffer[(sizeof(NDIS_EISA_SLOT_INFORMATION)+sizeof(NDIS_EISA_FUNCTION_INFORMATION))/sizeof(ULONGLONG) + 1];
+ PNDIS_EISA_SLOT_INFORMATION SlotInformation;
+ PNDIS_MCA_POS_DATA McaData;
+ NDIS_CONFIGURATION_PARAMETER ParmValue;
+ ULONG BusId, Mask = 0xFFFFFFFF;
+ ULONG DataLength;
+ ULONG Bus, Slot, MaxSlot = 0xFF;
+
+ SlotInformation = (PNDIS_EISA_SLOT_INFORMATION)Buffer;
+ McaData = (PNDIS_MCA_POS_DATA)Buffer;
+
+ //
+ // Read the slot information for the slot specified in the registry
+ //
+ switch (pDb->BusType)
+ {
+ case NdisInterfaceEisa:
+ Mask = 0xFFFFFF;
+ DataLength = HalGetBusDataByOffset(EisaConfiguration,
+ pDb->BusNumber,
+ pDb->SlotNumber,
+ SlotInformation,
+ 0,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ sizeof(NDIS_EISA_FUNCTION_INFORMATION));
+ BusId = SlotInformation->CompressedId;
+ break;
+
+ case NdisInterfaceMca:
+ MaxSlot = 7;
+ DataLength = 0;
+ if ((pDb->SlotNumber <= MaxSlot) && (pDb->SlotNumber > 0))
+ {
+ DataLength = HalGetBusDataByOffset(Pos,
+ pDb->BusNumber,
+ pDb->SlotNumber - 1,
+ McaData,
+ 0,
+ sizeof(NDIS_MCA_POS_DATA));
+ BusId = McaData->AdapterId;
+ }
+
+ break;
+
+ case NdisInterfacePci:
+ DataLength = HalGetBusDataByOffset(PCIConfiguration,
+ pDb->BusNumber,
+ pDb->SlotNumber,
+ &BusId,
+ 0,
+ sizeof(ULONG));
+ }
+
+ if ((DataLength != 0) &&
+ ((BusId & Mask) == (pDb->BusId & Mask)))
+ {
+ //
+ // The card seems to be where it is supposed to be. Make sure that is the
+ // case by searching our db to see if this is already installed. Use BusId
+ // and not the masked busid for search and in our database.
+ //
+ // If we found an EISA card where the registry says it should be but found another
+ // loaded instance, allow it - for multifunction EISA cards, we can have two cards
+ // with the same bus#/slot#.
+ //
+ if (!ndisSearchGlobalDb(pDb->BusType,
+ BusId,
+ pDb->BusNumber,
+ pDb->SlotNumber) ||
+ (pDb->BusType == NdisInterfaceEisa))
+ {
+ if (ndisAddGlobalDb(pDb->BusType,
+ BusId,
+ pDb->BusNumber,
+ pDb->SlotNumber))
+ {
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ //
+ // We could not add to global list. Unlikely we can proceed anyway.
+ //
+ return NDIS_STATUS_RESOURCES;
+ }
+ }
+
+ //
+ // The card is not where it ought to be. Scan the bus and find out where it is.
+ //
+ for (Bus = 0; NOTHING; Bus ++)
+ {
+ for (Slot = 0; Slot < MaxSlot; Slot ++)
+ {
+ switch (pDb->BusType)
+ {
+ case NdisInterfaceEisa:
+ DataLength = HalGetBusDataByOffset(EisaConfiguration,
+ Bus,
+ Slot,
+ SlotInformation,
+ 0,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ sizeof(NDIS_EISA_FUNCTION_INFORMATION));
+ BusId = SlotInformation->CompressedId;
+ break;
+
+ case NdisInterfaceMca:
+ DataLength = HalGetBusDataByOffset(Pos,
+ Bus,
+ Slot,
+ McaData,
+ 0,
+ sizeof(NDIS_MCA_POS_DATA));
+ BusId = McaData->AdapterId;
+ break;
+
+ case NdisInterfacePci:
+ DataLength = HalGetBusDataByOffset(PCIConfiguration,
+ Bus,
+ Slot,
+ &BusId,
+ 0,
+ sizeof(ULONG));
+ break;
+ }
+
+ if (DataLength == 0)
+ {
+ //
+ // No more buses, we failed
+ //
+ return NDIS_STATUS_FAILURE;
+ }
+
+ if ((BusId & Mask) == (pDb->BusId & Mask))
+ {
+ if (pDb->BusType == NdisInterfaceMca)
+ {
+ //
+ // MCA Slot #s are 0 based for HAL and 1 based for registry
+ //
+ Slot ++;
+ }
+
+ //
+ // Found one, make sure we do not already know about it
+ //
+ if (!ndisSearchGlobalDb(pDb->BusType,
+ pDb->BusId,
+ Bus,
+ Slot))
+ {
+ NDIS_STRING BusNumStr = NDIS_STRING_CONST("BusNumber");
+ NDIS_STRING SlotNumStr = NDIS_STRING_CONST("SlotNumber");
+ //
+ // This is it. First write it back to the registry. Then
+ // to the global db.
+ //
+ ParmValue.ParameterType = NdisParameterInteger;
+ ParmValue.ParameterData.IntegerData = Bus;
+ NdisWriteConfiguration(&Status,
+ ConfigHandle,
+ &BusNumStr,
+ &ParmValue);
+
+ ParmValue.ParameterData.IntegerData = Slot;
+ NdisWriteConfiguration(&Status,
+ ConfigHandle,
+ &SlotNumStr,
+ &ParmValue);
+
+ if (ndisAddGlobalDb(pDb->BusType,
+ pDb->BusId,
+ Bus,
+ Slot))
+ {
+ pDb->BusNumber = Bus;
+ pDb->SlotNumber = Slot;
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ //
+ // We could not add to global list. Unlikely we can proceed anyway.
+ //
+ return NDIS_STATUS_RESOURCES;
+ }
+ }
+
+ }
+ }
+
+ return Status;
+}
+
+
+VOID
+ndisAddBusInformation(
+ IN PNDIS_CONFIGURATION_HANDLE ConfigHandle,
+ IN PBUS_SLOT_DB pDb
+ )
+/*++
+
+ For OEM adapters that do not have their bus-id in the registry, do them a favor and add it.
+
+--*/
+{
+ ULONGLONG Buffer[(sizeof(NDIS_EISA_SLOT_INFORMATION)+sizeof(NDIS_EISA_FUNCTION_INFORMATION))/sizeof(ULONGLONG) + 1];
+ PNDIS_STRING BusIdStr;
+ NDIS_STRING PciIdStr = NDIS_STRING_CONST("AdapterCFID");
+ NDIS_STRING EisaIdStr = NDIS_STRING_CONST("EisaCompressedId");
+ NDIS_STRING McaIdStr = NDIS_STRING_CONST("McaPosId");
+ PNDIS_EISA_SLOT_INFORMATION SlotInformation;
+ NDIS_CONFIGURATION_PARAMETER ParmValue;
+ PNDIS_MCA_POS_DATA McaData;
+ NDIS_STATUS Status;
+ ULONG BusId, DataLength = 0;
+
+ //
+ // Read the bus-id by politely asking the HAL
+ //
+ switch (pDb->BusType)
+ {
+ case NdisInterfaceEisa:
+ SlotInformation = (PNDIS_EISA_SLOT_INFORMATION)Buffer;
+ DataLength = HalGetBusDataByOffset(EisaConfiguration,
+ pDb->BusNumber,
+ pDb->SlotNumber,
+ SlotInformation,
+ 0,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ sizeof(NDIS_EISA_FUNCTION_INFORMATION));
+ BusId = SlotInformation->CompressedId;
+ break;
+
+ case NdisInterfaceMca:
+ McaData = (PNDIS_MCA_POS_DATA)Buffer;
+ DataLength = HalGetBusDataByOffset(Pos,
+ pDb->BusNumber,
+ pDb->SlotNumber - 1,
+ McaData,
+ 0,
+ sizeof(NDIS_MCA_POS_DATA));
+ BusId = McaData->AdapterId;
+ break;
+
+ case NdisInterfacePci:
+ DataLength = HalGetBusDataByOffset(PCIConfiguration,
+ pDb->BusNumber,
+ pDb->SlotNumber,
+ &BusId,
+ 0,
+ sizeof(ULONG));
+ }
+ if (DataLength != 0)
+ {
+ ParmValue.ParameterType = NdisParameterInteger;
+ ParmValue.ParameterData.IntegerData = BusId;
+
+ switch (pDb->BusType)
+ {
+ case NdisInterfaceEisa:
+ BusIdStr = &EisaIdStr;
+ break;
+
+ case NdisInterfaceMca:
+ BusIdStr = &McaIdStr;
+ break;
+
+ case NdisInterfacePci:
+ BusIdStr = &PciIdStr;
+ break;
+ }
+
+ if (pDb->BusType != NdisInterfacePci)
+ {
+ //
+ // Do not do it for Pci buses just yet. Some OEM cards do bogus things.
+ //
+ NdisWriteConfiguration(&Status,
+ ConfigHandle,
+ BusIdStr,
+ &ParmValue);
+
+ //
+ // Finally create a data-base entry for this
+ //
+ ndisAddGlobalDb(pDb->BusType,
+ pDb->BusId,
+ pDb->BusNumber,
+ pDb->SlotNumber);
+ }
+ }
+}
+
+
+BOOLEAN
+ndisSearchGlobalDb(
+ IN NDIS_INTERFACE_TYPE BusType,
+ IN ULONG BusId,
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber
+ )
+{
+ PBUS_SLOT_DB pScan;
+ KIRQL OldIrql;
+ BOOLEAN rc = FALSE;
+
+ ACQUIRE_SPIN_LOCK(&ndisGlobalDbLock, &OldIrql);
+
+ for (pScan = ndisGlobalDb;
+ pScan != NULL;
+ pScan = pScan->Next)
+ {
+ if ((pScan->BusType == BusType) &&
+ (pScan->BusId == BusId) &&
+ (pScan->BusNumber == BusNumber) &&
+ (pScan->SlotNumber == SlotNumber))
+ {
+ rc = TRUE;
+ break;
+ }
+ }
+
+ RELEASE_SPIN_LOCK(&ndisGlobalDbLock, OldIrql);
+
+ return rc;
+}
+
+
+BOOLEAN
+ndisAddGlobalDb(
+ IN NDIS_INTERFACE_TYPE BusType,
+ IN ULONG BusId,
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber
+ )
+{
+ PBUS_SLOT_DB pDb;
+ KIRQL OldIrql;
+ BOOLEAN rc = FALSE;
+
+ pDb = ALLOC_FROM_POOL(sizeof(BUS_SLOT_DB), NDIS_TAG_DEFAULT);
+ if (pDb != NULL)
+ {
+ pDb->BusType = BusType;
+ pDb->BusId = BusId;
+ pDb->BusNumber = BusNumber;
+ pDb->SlotNumber = SlotNumber;
+ ACQUIRE_SPIN_LOCK(&ndisGlobalDbLock, &OldIrql);
+
+ pDb->Next = ndisGlobalDb;
+ ndisGlobalDb = pDb;
+
+ RELEASE_SPIN_LOCK(&ndisGlobalDbLock, OldIrql);
+
+ rc = TRUE;
+ }
+
+ return rc;
+}
+
+BOOLEAN
+ndisDeleteGlobalDb(
+ IN NDIS_INTERFACE_TYPE BusType,
+ IN ULONG BusId,
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber
+ )
+{
+ PBUS_SLOT_DB pScan, *ppScan;
+ KIRQL OldIrql;
+
+ ACQUIRE_SPIN_LOCK(&ndisGlobalDbLock, &OldIrql);
+
+ for (ppScan = &ndisGlobalDb;
+ (pScan = *ppScan) != NULL;
+ ppScan = &pScan->Next)
+ {
+ if ((pScan->BusType == BusType) &&
+ (pScan->BusId == BusId) &&
+ (pScan->BusNumber == BusNumber) &&
+ (pScan->SlotNumber == SlotNumber))
+ {
+ *ppScan = pScan->Next;
+ break;
+ }
+ }
+
+ RELEASE_SPIN_LOCK(&ndisGlobalDbLock, OldIrql);
+
+ if (pScan != NULL)
+ {
+ FREE_POOL(pScan);
+ }
+
+ return (pScan != NULL);
+}
+
+
diff --git a/private/ntos/ndis/ndis40/common.c b/private/ntos/ndis/ndis40/common.c
new file mode 100644
index 000000000..d9ef88449
--- /dev/null
+++ b/private/ntos/ndis/ndis40/common.c
@@ -0,0 +1,3452 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ common.c
+
+Abstract:
+
+ NDIS wrapper functions common to miniports and full mac drivers
+
+Author:
+
+ Adam Barr (adamba) 11-Jul-1990
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ 26-Feb-1991 JohnsonA Added Debugging Code
+ 10-Jul-1991 JohnsonA Implement revised Ndis Specs
+ 01-Jun-1995 JameelH Re-organization/optimization
+ 09-Apr-1996 KyleB Added resource remove and acquisition routines.
+
+--*/
+
+
+#include <precomp.h>
+#pragma hdrstop
+
+#include <stdarg.h>
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_COMMON
+
+//
+// Routines for dealing with making the PKG specific routines pagable
+//
+
+VOID
+ndisInitializePackage(
+ IN PPKG_REF pPkg,
+ IN PVOID RoutineName
+ )
+{
+ //
+ // Allocate the spin lock
+ //
+ INITIALIZE_SPIN_LOCK(&pPkg->ReferenceLock);
+
+ //
+ // Initialize the "in page" event.
+ //
+ INITIALIZE_EVENT(&pPkg->PagedInEvent);
+
+ // Lock and unlock the section to obtain the handle. Subsequent locks will be faster
+ pPkg->ImageHandle = MmLockPagableCodeSection(RoutineName);
+ MmUnlockPagableImageSection(pPkg->ImageHandle);
+}
+
+
+VOID
+ndisReferencePackage(
+ IN PPKG_REF pPkg
+)
+{
+ KIRQL OldIrql;
+
+ //
+ // Grab the spin lock
+ //
+ ACQUIRE_SPIN_LOCK(&pPkg->ReferenceLock, &OldIrql);
+
+ //
+ // Increment the reference count
+ //
+ pPkg->ReferenceCount++;
+
+ if (pPkg->ReferenceCount == 1)
+ {
+ //
+ // We are the first reference. Page everything in.
+ //
+
+ //
+ // Clear the event
+ //
+ RESET_EVENT(&pPkg->PagedInEvent);
+
+ //
+ // Set the spin lock free
+ //
+ RELEASE_SPIN_LOCK(&pPkg->ReferenceLock, OldIrql);
+
+ //
+ // Page in all the functions
+ //
+ MmLockPagableSectionByHandle(pPkg->ImageHandle);
+
+ //
+ // Signal to everyone to go
+ //
+ SET_EVENT(&pPkg->PagedInEvent);
+ }
+ else
+ {
+ //
+ // Set the spin lock free
+ //
+ RELEASE_SPIN_LOCK(&pPkg->ReferenceLock, OldIrql);
+
+ //
+ // Wait for everything to be paged in
+ //
+ WAIT_FOR_OBJECT(&pPkg->PagedInEvent, NULL);
+ }
+}
+
+
+VOID
+ndisDereferencePackage(
+ IN PPKG_REF pPkg
+ )
+{
+ KIRQL OldIrql;
+
+ //
+ // Get the spin lock
+ //
+ ACQUIRE_SPIN_LOCK(&pPkg->ReferenceLock, &OldIrql);
+
+ pPkg->ReferenceCount--;
+
+ if (pPkg->ReferenceCount == 0)
+ {
+ //
+ // Let next one in
+ //
+ RELEASE_SPIN_LOCK(&pPkg->ReferenceLock, OldIrql);
+
+ //
+ // Page out all the functions
+ //
+ MmUnlockPagableImageSection(pPkg->ImageHandle);
+ }
+ else
+ {
+ //
+ // Let next one in
+ //
+ RELEASE_SPIN_LOCK(&pPkg->ReferenceLock, OldIrql);
+ }
+}
+
+
+
+NDIS_STATUS
+NdisAllocateMemory(
+ OUT PVOID * VirtualAddress,
+ IN UINT Length,
+ IN UINT MemoryFlags,
+ IN NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress
+ )
+/*++
+
+Routine Description:
+
+ Allocate memory for use by a protocol or a MAC driver
+
+Arguments:
+
+ VirtualAddress - Returns a pointer to the allocated memory.
+ Length - Size of requested allocation in bytes.
+ MaximumPhysicalAddress - Highest addressable address of the allocated
+ memory.. 0 means highest system memory possible.
+ MemoryFlags - Bit mask that allows the caller to specify attributes
+ of the allocated memory. 0 means standard memory.
+
+ other options:
+
+ NDIS_MEMORY_CONTIGUOUS
+ NDIS_MEMORY_NONCACHED
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if successful.
+ NDIS_STATUS_FAILURE if not successful. *VirtualAddress will be NULL.
+
+
+--*/
+{
+ //
+ // Depending on the value of MemoryFlags, we allocate three different
+ // types of memory.
+ //
+
+ if (MemoryFlags == 0)
+ {
+ *VirtualAddress = ALLOC_FROM_POOL(Length, NDIS_TAG_ALLOC_MEM);
+ }
+ else if (MemoryFlags & NDIS_MEMORY_NONCACHED)
+ {
+ *VirtualAddress = MmAllocateNonCachedMemory(Length);
+ }
+ else if (MemoryFlags & NDIS_MEMORY_CONTIGUOUS)
+ {
+ *VirtualAddress = MmAllocateContiguousMemory(Length, HighestAcceptableAddress);
+ }
+
+ return (*VirtualAddress == NULL) ? NDIS_STATUS_FAILURE : NDIS_STATUS_SUCCESS;
+}
+
+
+NDIS_STATUS
+NdisAllocateMemoryWithTag(
+ OUT PVOID * VirtualAddress,
+ IN UINT Length,
+ IN ULONG Tag
+ )
+/*++
+
+Routine Description:
+
+ Allocate memory for use by a protocol or a MAC driver
+
+Arguments:
+
+ VirtualAddress - Returns a pointer to the allocated memory.
+ Length - Size of requested allocation in bytes.
+ Tag - tag to associate with this memory.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if successful.
+ NDIS_STATUS_FAILURE if not successful. *VirtualAddress will be NULL.
+
+
+--*/
+{
+
+ *VirtualAddress = ALLOC_FROM_POOL(Length, Tag);
+ return (*VirtualAddress == NULL) ? NDIS_STATUS_FAILURE : NDIS_STATUS_SUCCESS;
+}
+
+
+VOID
+NdisFreeMemory(
+ IN PVOID VirtualAddress,
+ IN UINT Length,
+ IN UINT MemoryFlags
+ )
+/*++
+
+Routine Description:
+
+ Releases memory allocated using NdisAllocateMemory.
+
+Arguments:
+
+ VirtualAddress - Pointer to the memory to be freed.
+ Length - Size of allocation in bytes.
+ MemoryFlags - Bit mask that allows the caller to specify attributes
+ of the allocated memory. 0 means standard memory.
+
+ other options:
+
+ NDIS_MEMORY_CONTIGUOUS
+ NDIS_MEMORY_NONCACHED
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Depending on the value of MemoryFlags, we allocate three free 3
+ // types of memory.
+ //
+
+ if (MemoryFlags == 0)
+ {
+ FREE_POOL(VirtualAddress);
+ }
+ else if (MemoryFlags & NDIS_MEMORY_NONCACHED)
+ {
+ MmFreeNonCachedMemory(VirtualAddress, Length);
+ }
+ else if (MemoryFlags & NDIS_MEMORY_CONTIGUOUS)
+ {
+ MmFreeContiguousMemory(VirtualAddress);
+ }
+}
+
+//
+// Packet and Buffer requests
+//
+
+VOID
+NdisAllocatePacketPool(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE PoolHandle,
+ IN UINT NumberOfDescriptors,
+ IN UINT ProtocolReservedLength
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes a packet pool. All packets are the same
+ size for a given pool (as determined by ProtocolReservedLength),
+ so a simple linked list of free packets is set up initially.
+
+Arguments:
+
+ Status - Returns the final status (always NDIS_STATUS_SUCCESS).
+ PoolHandle - Returns a pointer to the pool.
+ NumberOfDescriptors - Number of packet descriptors needed.
+ ProtocolReservedLength - How long the ProtocolReserved field
+ should be for packets in this pool.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_PACKET_POOL TmpPool;
+ PUCHAR FreeEntry;
+ UINT PacketLength;
+ UINT i;
+
+ //
+ // Set up the size of packets in this pool (rounded
+ // up to sizeof(ULONG) for alignment).
+ //
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisAllocatePacketPool\n"));
+
+ PacketLength = FIELD_OFFSET(NDIS_PACKET, ProtocolReserved) +
+ sizeof(NDIS_PACKET_OOB_DATA) +
+ sizeof(NDIS_PACKET_PRIVATE_EXTENSION) +
+ ((ProtocolReservedLength + sizeof(ULONGLONG) - 1) & ~(sizeof(ULONGLONG) -1));
+
+ //
+ // Allocate space needed
+ //
+ TmpPool = (PNDIS_PACKET_POOL)ALLOC_FROM_POOL(sizeof(NDIS_PACKET_POOL) +
+ (PacketLength * NumberOfDescriptors),
+ NDIS_TAG_PKT_POOL);
+ if (TmpPool == NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ ZeroMemory(TmpPool, PacketLength * NumberOfDescriptors);
+ TmpPool->PacketLength = PacketLength;
+
+ //
+ // First entry in free list is at beginning of pool space.
+ //
+ TmpPool->FreeList = (PNDIS_PACKET)TmpPool->Buffer;
+ FreeEntry = TmpPool->Buffer;
+
+ for (i = 1; i < NumberOfDescriptors; i++)
+ {
+ //
+ // Each entry is linked to the "packet" PacketLength bytes
+ // ahead of it, using the Private.Head field.
+ //
+ ((PNDIS_PACKET)FreeEntry)->Private.Head = (PNDIS_BUFFER)(FreeEntry + PacketLength);
+ FreeEntry += PacketLength;
+ }
+
+ //
+ // Final free list entry.
+ //
+ ((PNDIS_PACKET)FreeEntry)->Private.Head = (PNDIS_BUFFER)NULL;
+
+ NdisAllocateSpinLock(&TmpPool->SpinLock);
+
+ *Status = NDIS_STATUS_SUCCESS;
+ *PoolHandle = (NDIS_HANDLE)TmpPool;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisAllocatePacketPool\n"));
+}
+
+
+#undef NdisFreePacketPool
+
+VOID
+NdisFreePacketPool(
+ IN NDIS_HANDLE PoolHandle
+ )
+{
+ NdisFreeSpinLock(&((PNDIS_PACKET_POOL)PoolHandle)->SpinLock);
+ FREE_POOL(PoolHandle);
+}
+
+
+VOID
+NdisAllocateBufferPool(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE PoolHandle,
+ IN UINT NumberOfDescriptors
+ )
+/*++
+
+Routine Description:
+
+ Initializes a block of storage so that buffer descriptors can be
+ allocated.
+
+Arguments:
+
+ Status - status of the request.
+ PoolHandle - handle that is used to specify the pool
+ NumberOfDescriptors - Number of buffer descriptors in the pool.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // A nop for NT
+ //
+ UNREFERENCED_PARAMETER(NumberOfDescriptors);
+
+ *PoolHandle = NULL;
+ *Status = NDIS_STATUS_SUCCESS;
+}
+
+
+VOID
+NdisFreeBufferPool(
+ IN NDIS_HANDLE PoolHandle
+ )
+/*++
+
+Routine Description:
+
+ Terminates usage of a buffer descriptor pool.
+
+Arguments:
+
+ PoolHandle - handle that is used to specify the pool
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(PoolHandle);
+}
+
+
+VOID
+NdisAllocateBuffer(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_BUFFER * Buffer,
+ IN NDIS_HANDLE PoolHandle,
+ IN PVOID VirtualAddress,
+ IN UINT Length
+ )
+/*++
+
+Routine Description:
+
+ Creates a buffer descriptor to describe a segment of virtual memory
+ allocated via NdisAllocateMemory (which always allocates nonpaged).
+
+Arguments:
+
+ Status - Status of the request.
+ Buffer - Pointer to the allocated buffer descriptor.
+ PoolHandle - Handle that is used to specify the pool.
+ VirtualAddress - The virtual address of the buffer.
+ Length - The Length of the buffer.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(PoolHandle);
+
+ *Status = NDIS_STATUS_FAILURE;
+ if ((*Buffer = IoAllocateMdl(VirtualAddress,
+ Length,
+ FALSE,
+ FALSE,
+ NULL)) != NULL)
+ {
+ MmBuildMdlForNonPagedPool(*Buffer);
+ (*Buffer)->Next = NULL;
+ *Status = NDIS_STATUS_SUCCESS;
+ }
+}
+
+
+#undef NdisAdjustBufferLength
+VOID
+NdisAdjustBufferLength(
+ IN PNDIS_BUFFER Buffer,
+ IN UINT Length
+ )
+{
+ Buffer->ByteCount = Length;
+}
+
+
+VOID
+NdisCopyBuffer(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_BUFFER * Buffer,
+ IN NDIS_HANDLE PoolHandle,
+ IN PVOID MemoryDescriptor,
+ IN UINT Offset,
+ IN UINT Length
+ )
+/*++
+
+Routine Description:
+
+ Used to create a buffer descriptor given a memory descriptor.
+
+Arguments:
+
+ Status - Status of the request.
+ Buffer - Pointer to the allocated buffer descriptor.
+ PoolHandle - Handle that is used to specify the pool.
+ MemoryDescriptor - Pointer to the descriptor of the source memory.
+ Offset - The Offset in the sources memory from which the copy is to begin
+ Length - Number of Bytes to copy.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_BUFFER SourceDescriptor = (PNDIS_BUFFER)MemoryDescriptor;
+ PVOID BaseVa = (((PUCHAR)MDL_VA(SourceDescriptor)) + Offset);
+
+ UNREFERENCED_PARAMETER(PoolHandle);
+
+ *Status = NDIS_STATUS_FAILURE;
+ if ((*Buffer = IoAllocateMdl(BaseVa,
+ Length,
+ FALSE,
+ FALSE,
+ NULL)) != NULL)
+ {
+ IoBuildPartialMdl(SourceDescriptor,
+ *Buffer,
+ BaseVa,
+ Length);
+
+ (*Buffer)->Next = NULL;
+ *Status = NDIS_STATUS_SUCCESS;
+ }
+}
+
+
+#define ndisAllocatePacketFromPool(_Pool, _ppPacket) \
+ { \
+ \
+ /* \
+ * See if any packets are on pool free list. \
+ */ \
+ \
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO, \
+ ("==>NdisAllocatePacket\n")); \
+ \
+ IF_DBG(DBG_COMP_CONFIG, DBG_LEVEL_ERR) \
+ { \
+ if (DbgIsNull(PoolHandle)) \
+ { \
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR, \
+ ("AllocatePacket: NULL Pool address\n")); \
+ DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR); \
+ } \
+ if (!DbgIsNonPaged(PoolHandle)) \
+ { \
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR, \
+ ("AllocatePacket: Pool not in NonPaged Memory\n")); \
+ DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR); \
+ } \
+ } \
+ \
+ *(_ppPacket) = Pool->FreeList; \
+ if (Pool->FreeList != (PNDIS_PACKET)NULL) \
+ { \
+ /* \
+ * Take free packet off head of list and return it. \
+ */ \
+ \
+ Pool->FreeList = (PNDIS_PACKET)(*(_ppPacket))->Private.Head; \
+ } \
+ }
+
+#define ndisInitializePacket(_Pool, _Packet) \
+ { \
+ PNDIS_PACKET_PRIVATE_EXTENSION PacketExt; \
+ \
+ ZeroMemory((_Packet), (_Pool)->PacketLength); \
+ (_Packet)->Private.Pool = (PNDIS_PACKET_POOL)(_Pool); \
+ (_Packet)->Private.ValidCounts = TRUE; \
+ (_Packet)->Private.NdisPacketFlags = fPACKET_ALLOCATED_BY_NDIS; \
+ \
+ /* \
+ * Set the offset to the out of band data. \
+ */ \
+ (_Packet)->Private.NdisPacketOobOffset = (USHORT)( \
+ (_Pool)->PacketLength - \
+ sizeof(NDIS_PACKET_OOB_DATA) - \
+ sizeof(NDIS_PACKET_PRIVATE_EXTENSION));\
+ \
+ /* \
+ * Set the pointer to the packet linkage information for ndis. \
+ */ \
+ PacketExt = (PNDIS_PACKET_PRIVATE_EXTENSION)((PUCHAR)(_Packet) + \
+ (_Packet)->Private.NdisPacketOobOffset + \
+ sizeof(NDIS_PACKET_OOB_DATA)); \
+ PacketExt->Packet = (_Packet); \
+ }
+
+VOID
+NdisAllocatePacket(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_PACKET * Packet,
+ IN NDIS_HANDLE PoolHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Allocates a packet out of a packet pool.
+
+Arguments:
+
+ Status - Returns the final status.
+ Packet - Return a pointer to the packet.
+ PoolHandle - The packet pool to allocate from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_PACKET_POOL Pool = (PNDIS_PACKET_POOL)PoolHandle;
+ KIRQL OldIrql;
+
+ NDIS_ACQUIRE_SPIN_LOCK(&Pool->SpinLock, &OldIrql);
+
+ ndisAllocatePacketFromPool(PoolHandle, Packet);
+
+ NDIS_RELEASE_SPIN_LOCK(&Pool->SpinLock, OldIrql);
+
+ if (*Packet != (PNDIS_PACKET)NULL)
+ {
+ //
+ // Clear packet elements.
+ //
+ ndisInitializePacket(Pool, *Packet);
+
+ *Status = NDIS_STATUS_SUCCESS;
+ }
+ else
+ {
+ //
+ // No, cannot satisfy request.
+ //
+
+ *Status = NDIS_STATUS_RESOURCES;
+ }
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisAllocatePacket\n"));
+}
+
+
+VOID
+NdisDprAllocatePacket(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_PACKET * Packet,
+ IN NDIS_HANDLE PoolHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Allocates a packet out of a packet pool. Similar to NdisAllocatePacket
+ but can only be called at raised irql.
+
+Arguments:
+
+ Status - Returns the final status.
+ Packet - Return a pointer to the packet.
+ PoolHandle - The packet pool to allocate from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_PACKET_POOL Pool = (PNDIS_PACKET_POOL)PoolHandle;
+
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(&Pool->SpinLock);
+
+ ndisAllocatePacketFromPool(PoolHandle, Packet);
+
+ NDIS_RELEASE_SPIN_LOCK_DPC(&Pool->SpinLock);
+
+ if (*Packet != (PNDIS_PACKET)NULL)
+ {
+ //
+ // Clear packet elements.
+ //
+ ndisInitializePacket(Pool, *Packet);
+
+ *Status = NDIS_STATUS_SUCCESS;
+ }
+ else
+ {
+ //
+ // No, cannot satisfy request.
+ //
+
+ *Status = NDIS_STATUS_RESOURCES;
+ }
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisDprAllocatePacket\n"));
+}
+
+
+VOID
+NdisDprAllocatePacketNonInterlocked(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_PACKET * Packet,
+ IN NDIS_HANDLE PoolHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Allocates a packet out of a packet pool. Similar to NdisAllocatePacket
+ but is not interlocked. Caller guarantees synchronization.
+
+Arguments:
+
+ Status - Returns the final status.
+ Packet - Return a pointer to the packet.
+ PoolHandle - The packet pool to allocate from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_PACKET_POOL Pool = (PNDIS_PACKET_POOL)PoolHandle;
+
+ ndisAllocatePacketFromPool(PoolHandle, Packet);
+
+ if (*Packet != (PNDIS_PACKET)NULL)
+ {
+ //
+ // Clear packet elements.
+ //
+ ndisInitializePacket(Pool, *Packet);
+
+ *Status = NDIS_STATUS_SUCCESS;
+ }
+ else
+ {
+ //
+ // No, cannot satisfy request.
+ //
+
+ *Status = NDIS_STATUS_RESOURCES;
+ }
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisDprAllocatePacketNonInterlocked\n"));
+}
+
+
+#undef NdisFreePacket
+
+VOID
+NdisFreePacket(
+ IN PNDIS_PACKET Packet
+ )
+{
+ Packet->Private.Head = (PNDIS_BUFFER)(Packet->Private.Pool->FreeList);
+ Packet->Private.Pool->FreeList = Packet;
+}
+
+#undef NdisDprFreePacket
+
+VOID
+NdisDprFreePacket(
+ IN PNDIS_PACKET Packet
+ )
+{
+ NdisDprAcquireSpinLock(&Packet->Private.Pool->SpinLock);
+
+ Packet->Private.Head = (PNDIS_BUFFER)(Packet->Private.Pool->FreeList);
+ Packet->Private.Pool->FreeList = Packet;
+
+ NdisDprReleaseSpinLock(&Packet->Private.Pool->SpinLock);
+}
+
+#undef NdisDprFreePacketNonInterlocked
+
+VOID
+NdisDprFreePacketNonInterlocked(
+ IN PNDIS_PACKET Packet
+ )
+{
+ Packet->Private.Head = (PNDIS_BUFFER)(Packet->Private.Pool->FreeList);
+ Packet->Private.Pool->FreeList = Packet;
+}
+
+
+VOID
+NdisUnchainBufferAtFront(
+ IN OUT PNDIS_PACKET Packet,
+ OUT PNDIS_BUFFER * Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ Takes a buffer off the front of a packet.
+
+Arguments:
+
+ Packet - The packet to be modified.
+ Buffer - Returns the packet on the front, or NULL.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ *Buffer = Packet->Private.Head;
+
+ //
+ // If packet is not empty, remove head buffer.
+ //
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisUnchainBufferAtFront\n"));
+
+ IF_DBG(DBG_COMP_CONFIG, DBG_LEVEL_ERR)
+ {
+ BOOLEAN f = FALSE;
+ if (DbgIsNull(Packet))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("UnchainBufferAtFront: Null Packet Pointer\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(Packet))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("UnchainBufferAtFront: Packet not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (!DbgIsPacket(Packet))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("UnchainBufferAtFront: Illegal Packet Size\n"));
+ f = TRUE;
+ }
+ if (f)
+ DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR);
+ }
+
+ if (*Buffer != (PNDIS_BUFFER)NULL)
+ {
+ Packet->Private.Head = (*Buffer)->Next; // may be NULL
+ (*Buffer)->Next = (PNDIS_BUFFER)NULL;
+ Packet->Private.ValidCounts = FALSE;
+ }
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisUnchainBufferAtFront\n"));
+}
+
+
+VOID
+NdisUnchainBufferAtBack(
+ IN OUT PNDIS_PACKET Packet,
+ OUT PNDIS_BUFFER * Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ Takes a buffer off the end of a packet.
+
+Arguments:
+
+ Packet - The packet to be modified.
+ Buffer - Returns the packet on the end, or NULL.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_BUFFER BufP = Packet->Private.Head;
+ PNDIS_BUFFER Result;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisUnchainBufferAtBack\n"));
+
+ IF_DBG(DBG_COMP_CONFIG, DBG_LEVEL_ERR)
+ {
+ BOOLEAN f = FALSE;
+ if (DbgIsNull(Packet))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("UnchainBufferAtBack: Null Packet Pointer\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(Packet))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("UnchainBufferAtBack: Packet not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (!DbgIsPacket(Packet))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("UnchainBufferAtBack: Illegal Packet Size\n"));
+ f = TRUE;
+ }
+ if (f)
+ DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR);
+ }
+ if (BufP != (PNDIS_BUFFER)NULL)
+ {
+ //
+ // The packet is not empty, return the tail buffer.
+ //
+
+ Result = Packet->Private.Tail;
+ if (BufP == Result)
+ {
+ //
+ // There was only one buffer on the queue.
+ //
+
+ Packet->Private.Head = (PNDIS_BUFFER)NULL;
+ }
+ else
+ {
+ //
+ // Determine the new tail buffer.
+ //
+
+ while (BufP->Next != Result)
+ {
+ BufP = BufP->Next;
+ }
+ Packet->Private.Tail = BufP;
+ BufP->Next = NULL;
+ }
+
+ Result->Next = (PNDIS_BUFFER)NULL;
+ Packet->Private.ValidCounts = FALSE;
+ }
+ else
+ {
+ //
+ // Packet is empty.
+ //
+
+ Result = (PNDIS_BUFFER)NULL;
+ }
+
+ *Buffer = Result;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisUnchainBufferAtBack\n"));
+}
+
+
+
+VOID
+NdisCopyFromPacketToPacket(
+ IN PNDIS_PACKET Destination,
+ IN UINT DestinationOffset,
+ IN UINT BytesToCopy,
+ IN PNDIS_PACKET Source,
+ IN UINT SourceOffset,
+ OUT PUINT BytesCopied
+ )
+
+/*++
+
+Routine Description:
+
+ Copy from an ndis packet to an ndis packet.
+
+Arguments:
+
+ Destination - The packet should be copied in to.
+
+ DestinationOffset - The offset from the beginning of the packet
+ into which the data should start being placed.
+
+ BytesToCopy - The number of bytes to copy from the source packet.
+
+ Source - The ndis packet from which to copy data.
+
+ SourceOffset - The offset from the start of the packet from which
+ to start copying data.
+
+ BytesCopied - The number of bytes actually copied from the source
+ packet. This can be less than BytesToCopy if the source or destination
+ packet is too short.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ //
+ // Holds the count of the number of ndis buffers comprising the
+ // destination packet.
+ //
+ UINT DestinationBufferCount;
+
+ //
+ // Holds the count of the number of ndis buffers comprising the
+ // source packet.
+ //
+ UINT SourceBufferCount;
+
+ //
+ // Points to the buffer into which we are putting data.
+ //
+ PNDIS_BUFFER DestinationCurrentBuffer;
+
+ //
+ // Points to the buffer from which we are extracting data.
+ //
+ PNDIS_BUFFER SourceCurrentBuffer;
+
+ //
+ // Holds the virtual address of the current destination buffer.
+ //
+ PVOID DestinationVirtualAddress;
+
+ //
+ // Holds the virtual address of the current source buffer.
+ //
+ PVOID SourceVirtualAddress;
+
+ //
+ // Holds the length of the current destination buffer.
+ //
+ UINT DestinationCurrentLength;
+
+ //
+ // Holds the length of the current source buffer.
+ //
+ UINT SourceCurrentLength;
+
+ //
+ // Keep a local variable of BytesCopied so we aren't referencing
+ // through a pointer.
+ //
+ UINT LocalBytesCopied = 0;
+
+ //
+ // Take care of boundary condition of zero length copy.
+ //
+
+ *BytesCopied = 0;
+ if (!BytesToCopy)
+ return;
+
+ //
+ // Get the first buffer of the destination.
+ //
+
+ NdisQueryPacket(Destination,
+ NULL,
+ &DestinationBufferCount,
+ &DestinationCurrentBuffer,
+ NULL);
+
+ //
+ // Could have a null packet.
+ //
+
+ if (!DestinationBufferCount)
+ return;
+
+ NdisQueryBuffer(DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength);
+
+ //
+ // Get the first buffer of the source.
+ //
+
+ NdisQueryPacket(Source,
+ NULL,
+ &SourceBufferCount,
+ &SourceCurrentBuffer,
+ NULL);
+
+ //
+ // Could have a null packet.
+ //
+
+ if (!SourceBufferCount)
+ return;
+
+ NdisQueryBuffer(SourceCurrentBuffer,
+ &SourceVirtualAddress,
+ &SourceCurrentLength);
+
+ while (LocalBytesCopied < BytesToCopy)
+ {
+ //
+ // Check to see whether we've exhausted the current destination
+ // buffer. If so, move onto the next one.
+ //
+
+ if (!DestinationCurrentLength)
+ {
+ NdisGetNextBuffer(DestinationCurrentBuffer, &DestinationCurrentBuffer);
+
+ if (!DestinationCurrentBuffer)
+ {
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.)
+ //
+
+ break;
+
+ }
+
+ NdisQueryBuffer(DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength);
+ continue;
+ }
+
+
+ //
+ // Check to see whether we've exhausted the current source
+ // buffer. If so, move onto the next one.
+ //
+
+ if (!SourceCurrentLength)
+ {
+ NdisGetNextBuffer(SourceCurrentBuffer, &SourceCurrentBuffer);
+
+ if (!SourceCurrentBuffer)
+ {
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.)
+ //
+
+ break;
+ }
+
+ NdisQueryBuffer(SourceCurrentBuffer,
+ &SourceVirtualAddress,
+ &SourceCurrentLength);
+ continue;
+ }
+
+ //
+ // Try to get us up to the point to start the copy.
+ //
+
+ if (DestinationOffset)
+ {
+ if (DestinationOffset > DestinationCurrentLength)
+ {
+ //
+ // What we want isn't in this buffer.
+ //
+
+ DestinationOffset -= DestinationCurrentLength;
+ DestinationCurrentLength = 0;
+ continue;
+ }
+ else
+ {
+ DestinationVirtualAddress = (PCHAR)DestinationVirtualAddress
+ + DestinationOffset;
+ DestinationCurrentLength -= DestinationOffset;
+ DestinationOffset = 0;
+ }
+ }
+
+ //
+ // Try to get us up to the point to start the copy.
+ //
+
+ if (SourceOffset)
+ {
+ if (SourceOffset > SourceCurrentLength)
+ {
+ //
+ // What we want isn't in this buffer.
+ //
+
+ SourceOffset -= SourceCurrentLength;
+ SourceCurrentLength = 0;
+ continue;
+ }
+ else
+ {
+ SourceVirtualAddress = (PCHAR)SourceVirtualAddress
+ + SourceOffset;
+ SourceCurrentLength -= SourceOffset;
+ SourceOffset = 0;
+ }
+ }
+
+ //
+ // Copy the data.
+ //
+
+ {
+ //
+ // Holds the amount of data to move.
+ //
+ UINT AmountToMove;
+
+ //
+ // Holds the amount desired remaining.
+ //
+ UINT Remaining = BytesToCopy - LocalBytesCopied;
+
+ AmountToMove =
+ ((SourceCurrentLength <= DestinationCurrentLength)?
+ (SourceCurrentLength):(DestinationCurrentLength));
+
+ AmountToMove = ((Remaining < AmountToMove)?
+ (Remaining):(AmountToMove));
+
+ CopyMemory(DestinationVirtualAddress, SourceVirtualAddress, AmountToMove);
+
+ DestinationVirtualAddress =
+ (PCHAR)DestinationVirtualAddress + AmountToMove;
+ SourceVirtualAddress =
+ (PCHAR)SourceVirtualAddress + AmountToMove;
+
+ LocalBytesCopied += AmountToMove;
+ SourceCurrentLength -= AmountToMove;
+ DestinationCurrentLength -= AmountToMove;
+ }
+ }
+
+ *BytesCopied = LocalBytesCopied;
+}
+
+VOID
+NdisAllocateSharedMemory(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Length,
+ IN BOOLEAN Cached,
+ OUT PVOID * VirtualAddress,
+ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Allocates memory to be shared between the driver and the adapter.
+
+Arguments:
+
+ NdisAdapterHandle - handle returned by NdisRegisterAdapter.
+ Length - Length of the memory to allocate.
+ Cached - TRUE if memory is to be cached.
+ VirtualAddress - Returns the virtual address of the memory,
+ or NULL if the memory cannot be allocated.
+ PhysicalAddress - Returns the physical address of the memory.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_ADAPTER_BLOCK AdaptP = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle;
+ PADAPTER_OBJECT SystemAdapterObject;
+ PNDIS_WRAPPER_CONTEXT WrapperContext;
+ PULONG Page;
+ ULONG Type;
+
+ //
+ // Get interesting information from the adapter/miniport.
+ //
+
+ if (AdaptP->DeviceObject != NULL)
+ {
+ SystemAdapterObject = AdaptP->SystemAdapterObject;
+ WrapperContext = AdaptP->WrapperContext;
+ }
+ else
+ {
+ SystemAdapterObject = Miniport->SystemAdapterObject;
+ WrapperContext = Miniport->WrapperContext;
+ }
+
+ //
+ // Non-busmasters shouldn't call this routine.
+ //
+
+ if (SystemAdapterObject == NULL)
+ {
+ *VirtualAddress = NULL;
+ KdPrint(("You are not a busmaster\n"));
+ return;
+ }
+
+ //
+ // Compute allocation size by aligning to the proper boundary.
+ //
+
+ ASSERT(Length != 0);
+
+ Length = (Length + ndisDmaAlignment - 1) & ~(ndisDmaAlignment - 1);
+
+ //
+ // Check to determine is there is enough room left in the current page
+ // to satisfy the allocation.
+ //
+
+ Type = Cached ? 1 : 0;
+ ExAcquireResourceExclusive(&SharedMemoryResource, TRUE);
+
+ do
+ {
+ if (WrapperContext->SharedMemoryLeft[Type] < Length)
+ {
+ if ((Length + sizeof(ULONG)) >= PAGE_SIZE)
+ {
+ //
+ // The allocation is greater than a page.
+ //
+
+ *VirtualAddress = HalAllocateCommonBuffer(SystemAdapterObject,
+ Length,
+ PhysicalAddress,
+ Cached);
+ break;
+ }
+
+ //
+ // Allocate a new page for shared alocation.
+ //
+
+ WrapperContext->SharedMemoryPage[Type] =
+ HalAllocateCommonBuffer(SystemAdapterObject,
+ PAGE_SIZE,
+ &WrapperContext->SharedMemoryAddress[Type],
+ Cached);
+
+ if (WrapperContext->SharedMemoryPage[Type] == NULL)
+ {
+ WrapperContext->SharedMemoryLeft[Type] = 0;
+ *VirtualAddress = NULL;
+ break;
+ }
+
+ //
+ // Initialize the reference count in the last ULONG of the page.
+ //
+
+ Page = (PULONG)WrapperContext->SharedMemoryPage[Type];
+ Page[(PAGE_SIZE / sizeof(ULONG)) - 1] = 0;
+ WrapperContext->SharedMemoryLeft[Type] = PAGE_SIZE - sizeof(ULONG);
+ }
+
+ //
+ // Increment the reference count, set the address of the allocation,
+ // compute the physical address, and reduce the space remaining.
+ //
+
+ Page = (PULONG)WrapperContext->SharedMemoryPage[Type];
+ Page[(PAGE_SIZE / sizeof(ULONG)) - 1] += 1;
+ *VirtualAddress = (PVOID)((PUCHAR)Page +
+ (PAGE_SIZE - sizeof(ULONG) - WrapperContext->SharedMemoryLeft[Type]));
+
+ PhysicalAddress->QuadPart = WrapperContext->SharedMemoryAddress[Type].QuadPart +
+ ((ULONG)*VirtualAddress & (PAGE_SIZE - 1));
+
+ WrapperContext->SharedMemoryLeft[Type] -= Length;
+ } while (FALSE);
+
+ ExReleaseResource(&SharedMemoryResource);
+}
+
+
+#undef NdisUpdateSharedMemory
+
+VOID
+NdisUpdateSharedMemory(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Length,
+ IN PVOID VirtualAddress,
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Ensures that the data to be read from a shared memory region is
+ fully up-to-date.
+
+Arguments:
+
+ NdisAdapterHandle - handle returned by NdisRegisterAdapter.
+ Length - The length of the shared memory.
+ VirtualAddress - Virtual address returned by NdisAllocateSharedMemory.
+ PhysicalAddress - The physical address returned by NdisAllocateSharedMemory.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // There is no underlying HAL routine for this anymore,
+ // it is not needed.
+ //
+
+ NdisAdapterHandle; Length; VirtualAddress; PhysicalAddress;
+}
+
+
+VOID
+NdisFreeSharedMemory(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Length,
+ IN BOOLEAN Cached,
+ IN PVOID VirtualAddress,
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Frees shared memory allocated via NdisAllocateSharedMemory.
+
+Arguments:
+
+ NdisAdapterHandle - handle returned by NdisRegisterAdapter.
+ Length - Length of the memory to allocate.
+ Cached - TRUE if memory was allocated cached.
+ VirtualAddress - Virtual address returned by NdisAllocateSharedMemory.
+ PhysicalAddress - The physical address returned by NdisAllocateSharedMemory.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_ADAPTER_BLOCK AdaptP = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle;
+ PADAPTER_OBJECT SystemAdapterObject;
+ PNDIS_WRAPPER_CONTEXT WrapperContext;
+ PULONG Page;
+ ULONG Type;
+
+ //
+ // Get interesting information from the adapter/miniport.
+ //
+
+ if (AdaptP->DeviceObject != NULL)
+ {
+ SystemAdapterObject = AdaptP->SystemAdapterObject;
+ WrapperContext = AdaptP->WrapperContext;
+ }
+ else
+ {
+ SystemAdapterObject = Miniport->SystemAdapterObject;
+ WrapperContext = Miniport->WrapperContext;
+ }
+
+ //
+ // Non-busmasters shouldn't call this routine.
+ //
+
+ ASSERT(SystemAdapterObject != NULL);
+
+ //
+ // Compute allocation size by aligning to the proper boundary.
+ //
+
+ ASSERT(Length != 0);
+
+ Length = (Length + ndisDmaAlignment - 1) & ~(ndisDmaAlignment - 1);
+
+ //
+ // Free the specified memory.
+ //
+
+ ExAcquireResourceExclusive(&SharedMemoryResource, TRUE);
+ if ((Length + sizeof(ULONG)) >= PAGE_SIZE)
+ {
+ //
+ // The allocation is greater than a page free the page directly.
+ //
+
+ HalFreeCommonBuffer(SystemAdapterObject,
+ Length,
+ PhysicalAddress,
+ VirtualAddress,
+ Cached);
+ }
+ else
+ {
+ //
+ // Decrement the reference count and if the result is zero, then free
+ // the page.
+ //
+
+ Page = (PULONG)((ULONG)VirtualAddress & ~(PAGE_SIZE - 1));
+ Page[(PAGE_SIZE / sizeof(ULONG)) - 1] -= 1;
+ if (Page[(PAGE_SIZE / sizeof(ULONG)) - 1] == 0)
+ {
+ //
+ // Compute the physical address of the page and free it.
+ //
+
+ PhysicalAddress.LowPart &= ~(PAGE_SIZE - 1);
+ HalFreeCommonBuffer(SystemAdapterObject,
+ PAGE_SIZE,
+ PhysicalAddress,
+ Page,
+ Cached);
+
+ Type = Cached ? 1 : 0;
+ if ((PVOID)Page == WrapperContext->SharedMemoryPage[Type])
+ {
+ WrapperContext->SharedMemoryLeft[Type] = 0;
+ WrapperContext->SharedMemoryPage[Type] = NULL;
+ }
+ }
+ }
+
+ ExReleaseResource(&SharedMemoryResource);
+}
+
+
+BOOLEAN
+ndisCheckPortUsage(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG PortNumber,
+ IN ULONG Length,
+ IN PDRIVER_OBJECT DriverObject
+)
+/*++
+
+Routine Description:
+
+ This routine checks if a port is currently in use somewhere in the
+ system via IoReportUsage -- which fails if there is a conflict.
+
+Arguments:
+
+ InterfaceType - The bus type (ISA, EISA)
+ BusNumber - Bus number in the system
+ PortNumber - Address of the port to access.
+ Length - Number of ports from the base address to access.
+
+Return Value:
+
+ FALSE if there is a conflict, else TRUE
+
+--*/
+
+{
+ NTSTATUS NtStatus;
+ BOOLEAN Conflict;
+ NTSTATUS FirstNtStatus;
+ BOOLEAN FirstConflict;
+ PCM_RESOURCE_LIST Resources;
+
+ //
+ // Allocate space for resources
+ //
+ Resources = (PCM_RESOURCE_LIST)ALLOC_FROM_POOL(sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ NDIS_TAG_DEFAULT);
+
+ if (Resources == NULL)
+ {
+ //
+ // Error out
+ //
+
+ return FALSE;
+ }
+
+ Resources->Count = 1;
+ Resources->List[0].InterfaceType = InterfaceType;
+ Resources->List[0].BusNumber = BusNumber;
+ Resources->List[0].PartialResourceList.Version = 0;
+ Resources->List[0].PartialResourceList.Revision = 0;
+ Resources->List[0].PartialResourceList.Count = 1;
+
+ //
+ // Setup port
+ //
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].Type = CmResourceTypePort;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].ShareDisposition = CmResourceShareDriverExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].Flags =
+ (InterfaceType == Internal)?
+ CM_RESOURCE_PORT_MEMORY :
+ CM_RESOURCE_PORT_IO;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Start.QuadPart = PortNumber;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Length = Length;
+
+ //
+ // Submit Resources
+ //
+ FirstNtStatus = IoReportResourceUsage(NULL,
+ DriverObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ NULL,
+ NULL,
+ 0,
+ TRUE,
+ &FirstConflict);
+
+ //
+ // Now clear it out
+ //
+ Resources->List[0].PartialResourceList.Count = 0;
+
+ NtStatus = IoReportResourceUsage(NULL,
+ DriverObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ NULL,
+ NULL,
+ 0,
+ TRUE,
+ &Conflict);
+
+ FREE_POOL(Resources);
+
+ //
+ // Check for conflict.
+ //
+
+ if (FirstConflict || (FirstNtStatus != STATUS_SUCCESS))
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+NTSTATUS
+ndisStartMapping(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG InitialAddress,
+ IN ULONG Length,
+ OUT PVOID * InitialMapping,
+ OUT PBOOLEAN Mapped
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initialize the mapping of a address into virtual
+ space dependent on the bus number, etc.
+
+Arguments:
+
+ InterfaceType - The bus type (ISA, EISA)
+ BusNumber - Bus number in the system
+ InitialAddress - Address to access.
+ Length - Number of bytes from the base address to access.
+ InitialMapping - The virtual address space to use when accessing the
+ address.
+ Mapped - Did an MmMapIoSpace() take place.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ PHYSICAL_ADDRESS Address;
+ PHYSICAL_ADDRESS InitialPhysAddress;
+ ULONG addressSpace;
+
+ //
+ // Get the system physical address for this card. The card uses
+ // I/O space, except for "internal" Jazz devices which use
+ // memory space.
+ //
+
+ *Mapped = FALSE;
+
+ addressSpace = (InterfaceType == Internal) ? 0 : 1;
+
+ InitialPhysAddress.LowPart = InitialAddress;
+
+ InitialPhysAddress.HighPart = 0;
+
+ if (!HalTranslateBusAddress(InterfaceType, // InterfaceType
+ BusNumber, // BusNumber
+ InitialPhysAddress, // Bus Address
+ &addressSpace, // AddressSpace
+ &Address)) // Translated address
+ {
+ //
+ // It would be nice to return a better status here, but we only get
+ // TRUE/FALSE back from HalTranslateBusAddress.
+ //
+
+ return NDIS_STATUS_FAILURE;
+ }
+
+ if (addressSpace == 0)
+ {
+ //
+ // memory space
+ //
+
+ *InitialMapping = MmMapIoSpace(Address, Length, FALSE);
+
+ if (*InitialMapping == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ *Mapped = TRUE;
+ }
+ else
+ {
+ //
+ // I/O space
+ //
+
+ *InitialMapping = (PVOID)Address.LowPart;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+ndisEndMapping(
+ IN PVOID InitialMapping,
+ IN ULONG Length,
+ IN BOOLEAN Mapped
+ )
+
+/*++
+
+Routine Description:
+
+ This routine undoes the mapping of an address into virtual
+ space dependent on the bus number, etc.
+
+Arguments:
+
+ InitialMapping - The virtual address space to use when accessing the
+ address.
+ Length - Number of bytes from the base address to access.
+ Mapped - Do we need to call MmUnmapIoSpace.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+
+ if (Mapped)
+ {
+ //
+ // memory space
+ //
+
+ MmUnmapIoSpace(InitialMapping, Length);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+VOID
+NdisImmediateReadPortUchar(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ OUT PUCHAR Data
+ )
+/*++
+
+Routine Description:
+
+ This routine reads from a port a UCHAR. It does all the mapping,
+ etc, to do the read here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ Port - Port number to read from.
+
+ Data - Pointer to place to store the result.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID PortMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NTSTATUS Status;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the port is available. If so map the space.
+ //
+ if ((ndisCheckPortUsage(BusType,
+ BusNumber,
+ Port,
+ sizeof(UCHAR),
+ DriverObject) == FALSE) ||
+ !NT_SUCCESS(Status = ndisStartMapping(BusType,
+ BusNumber,
+ Port,
+ sizeof(UCHAR),
+ &PortMapping,
+ &Mapped)))
+ {
+ *Data = (UCHAR)0xFF;
+ return;
+ }
+ //
+ // Read from the port
+ //
+
+ *Data = READ_PORT_UCHAR((PUCHAR)PortMapping);
+
+ //
+ // End port mapping
+ //
+
+ ndisEndMapping(PortMapping, sizeof(UCHAR), Mapped);
+}
+
+VOID
+NdisImmediateReadPortUshort(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ OUT PUSHORT Data
+ )
+/*++
+
+Routine Description:
+
+ This routine reads from a port a USHORT. It does all the mapping,
+ etc, to do the read here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ Port - Port number to read from.
+
+ Data - Pointer to place to store the result.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID PortMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NTSTATUS Status;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the port is available. If so map the space.
+ //
+ if ((ndisCheckPortUsage(BusType,
+ BusNumber,
+ Port,
+ sizeof(USHORT),
+ DriverObject) == FALSE) ||
+ !NT_SUCCESS(Status = ndisStartMapping(BusType,
+ BusNumber,
+ Port,
+ sizeof(USHORT),
+ &PortMapping,
+ &Mapped)))
+ {
+ *Data = (USHORT)0xFFFF;
+ return;
+ }
+
+ //
+ // Read from the port
+ //
+
+ *Data = READ_PORT_USHORT((PUSHORT)PortMapping);
+
+ //
+ // End port mapping
+ //
+
+ ndisEndMapping(PortMapping, sizeof(USHORT), Mapped);
+}
+
+
+VOID
+NdisImmediateReadPortUlong(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ OUT PULONG Data
+ )
+/*++
+
+Routine Description:
+
+ This routine reads from a port a ULONG. It does all the mapping,
+ etc, to do the read here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ Port - Port number to read from.
+
+ Data - Pointer to place to store the result.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID PortMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NTSTATUS Status;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the port is available. If so map the space.
+ //
+ if ((ndisCheckPortUsage(BusType,
+ BusNumber,
+ Port,
+ sizeof(ULONG),
+ DriverObject) == FALSE) ||
+ !NT_SUCCESS(Status = ndisStartMapping(BusType,
+ BusNumber,
+ Port,
+ sizeof(ULONG),
+ &PortMapping,
+ &Mapped)))
+ {
+ *Data = (ULONG)0xFFFFFFFF;
+ return;
+ }
+
+ //
+ // Read from the port
+ //
+
+ *Data = READ_PORT_ULONG((PULONG)PortMapping);
+
+ //
+ // End port mapping
+ //
+
+ ndisEndMapping(PortMapping, sizeof(ULONG), Mapped);
+}
+
+VOID
+NdisImmediateWritePortUchar(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ IN UCHAR Data
+ )
+/*++
+
+Routine Description:
+
+ This routine writes to a port a UCHAR. It does all the mapping,
+ etc, to do the write here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ Port - Port number to read from.
+
+ Data - Pointer to place to store the result.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID PortMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NTSTATUS Status;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the port is available. If so map the space.
+ //
+ if ((ndisCheckPortUsage(BusType,
+ BusNumber,
+ Port,
+ sizeof(UCHAR),
+ DriverObject) == FALSE) ||
+ !NT_SUCCESS(Status = ndisStartMapping(BusType,
+ BusNumber,
+ Port,
+ sizeof(UCHAR),
+ &PortMapping,
+ &Mapped)))
+ {
+ return;
+ }
+
+ //
+ // Read from the port
+ //
+
+ WRITE_PORT_UCHAR((PUCHAR)PortMapping, Data);
+
+ //
+ // End port mapping
+ //
+
+ ndisEndMapping(PortMapping, sizeof(UCHAR), Mapped);
+}
+
+VOID
+NdisImmediateWritePortUshort(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ IN USHORT Data
+ )
+/*++
+
+Routine Description:
+
+ This routine writes to a port a USHORT. It does all the mapping,
+ etc, to do the write here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ Port - Port number to read from.
+
+ Data - Pointer to place to store the result.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID PortMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NTSTATUS Status;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the port is available. If so map the space.
+ //
+ if ((ndisCheckPortUsage(BusType,
+ BusNumber,
+ Port,
+ sizeof(USHORT),
+ DriverObject) == FALSE) ||
+ !NT_SUCCESS(Status = ndisStartMapping(BusType,
+ BusNumber,
+ Port,
+ sizeof(USHORT),
+ &PortMapping,
+ &Mapped)))
+ {
+ return;
+ }
+
+ //
+ // Read from the port
+ //
+
+ WRITE_PORT_USHORT((PUSHORT)PortMapping, Data);
+
+ //
+ // End port mapping
+ //
+
+ ndisEndMapping(PortMapping, sizeof(USHORT), Mapped);
+}
+
+VOID
+NdisImmediateWritePortUlong(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ IN ULONG Data
+ )
+/*++
+
+Routine Description:
+
+ This routine writes to a port a ULONG. It does all the mapping,
+ etc, to do the write here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ Port - Port number to read from.
+
+ Data - Pointer to place to store the result.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID PortMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NTSTATUS Status;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the port is available. If so map the space.
+ //
+ if ((ndisCheckPortUsage(BusType,
+ BusNumber,
+ Port,
+ sizeof(ULONG),
+ DriverObject) == FALSE) ||
+ !NT_SUCCESS(Status = ndisStartMapping(BusType,
+ BusNumber,
+ Port,
+ sizeof(ULONG),
+ &PortMapping,
+ &Mapped)))
+ //
+ // Read from the port
+ //
+
+ WRITE_PORT_ULONG((PULONG)PortMapping, Data);
+
+ //
+ // End port mapping
+ //
+
+ ndisEndMapping(PortMapping, sizeof(ULONG), Mapped);
+}
+
+
+BOOLEAN
+ndisCheckMemoryUsage(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG Address,
+ IN ULONG Length,
+ IN PDRIVER_OBJECT DriverObject
+)
+/*++
+Routine Description:
+
+ This routine checks if a range of memory is currently in use somewhere
+ in the system via IoReportUsage -- which fails if there is a conflict.
+
+Arguments:
+
+ InterfaceType - The bus type (ISA, EISA)
+ BusNumber - Bus number in the system
+ Address - Starting Address of the memory to access.
+ Length - Length of memory from the base address to access.
+
+Return Value:
+
+ FALSE if there is a conflict, else TRUE
+
+--*/
+{
+ NTSTATUS NtStatus;
+ BOOLEAN Conflict;
+ NTSTATUS FirstNtStatus;
+ BOOLEAN FirstConflict;
+ PCM_RESOURCE_LIST Resources;
+
+ //
+ // Allocate space for resources
+ //
+
+ Resources = (PCM_RESOURCE_LIST)ALLOC_FROM_POOL(sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ NDIS_TAG_DEFAULT);
+
+ if (Resources == NULL)
+ {
+ //
+ // Error out
+ //
+
+ return FALSE;
+ }
+
+ Resources->Count = 1;
+ Resources->List[0].InterfaceType = InterfaceType;
+ Resources->List[0].BusNumber = BusNumber;
+ Resources->List[0].PartialResourceList.Version = 0;
+ Resources->List[0].PartialResourceList.Revision = 0;
+ Resources->List[0].PartialResourceList.Count = 1;
+
+ //
+ // Setup memory
+ //
+
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].Type =
+ CmResourceTypeMemory;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].ShareDisposition =
+ CmResourceShareDriverExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].Flags =
+ CM_RESOURCE_MEMORY_READ_WRITE;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Memory.Start.QuadPart = Address;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Memory.Length = Length;
+
+
+ //
+ // Submit Resources
+ //
+ FirstNtStatus = IoReportResourceUsage(NULL,
+ DriverObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ NULL,
+ NULL,
+ 0,
+ TRUE,
+ &FirstConflict);
+
+ //
+ // Now clear it out
+ //
+ Resources->List[0].PartialResourceList.Count = 0;
+
+ NtStatus = IoReportResourceUsage(NULL,
+ DriverObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ NULL,
+ NULL,
+ 0,
+ TRUE,
+ &Conflict);
+
+ FREE_POOL(Resources);
+
+ //
+ // Check for conflict.
+ //
+
+ return (FirstConflict || (FirstNtStatus != STATUS_SUCCESS)) ? FALSE : TRUE;
+}
+
+
+VOID
+NdisImmediateReadSharedMemory(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SharedMemoryAddress,
+ OUT PUCHAR Buffer,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This routine read into a buffer from shared ram. It does all the mapping,
+ etc, to do the read here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ SharedMemoryAddress - The physical address to read from.
+
+ Buffer - The buffer to read into.
+
+ Length - Length of the buffer in bytes.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID MemoryMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the memory is available. Map the space
+ //
+
+ if ((ndisCheckMemoryUsage(BusType,
+ BusNumber,
+ SharedMemoryAddress,
+ Length,
+ DriverObject) == FALSE) ||
+ !NT_SUCCESS(ndisStartMapping(BusType,
+ BusNumber,
+ SharedMemoryAddress,
+ Length,
+ &MemoryMapping,
+ &Mapped)))
+ {
+ return;
+ }
+
+ //
+ // Read from memory
+ //
+
+#ifdef _M_IX86
+
+ memcpy(Buffer, MemoryMapping, Length);
+
+#else
+
+ READ_REGISTER_BUFFER_UCHAR(MemoryMapping,Buffer,Length);
+
+#endif
+
+ //
+ // End mapping
+ //
+
+ ndisEndMapping(MemoryMapping,
+ Length,
+ Mapped);
+}
+
+
+VOID
+NdisImmediateWriteSharedMemory(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SharedMemoryAddress,
+ IN PUCHAR Buffer,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This routine writes a buffer to shared ram. It does all the mapping,
+ etc, to do the write here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ SharedMemoryAddress - The physical address to write to.
+
+ Buffer - The buffer to write.
+
+ Length - Length of the buffer in bytes.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID MemoryMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the memory is available. Map the space
+ //
+ if ((ndisCheckMemoryUsage(BusType,
+ BusNumber,
+ SharedMemoryAddress,
+ Length,
+ DriverObject) == FALSE) ||
+ !NT_SUCCESS(ndisStartMapping(BusType,
+ BusNumber,
+ SharedMemoryAddress,
+ Length,
+ &MemoryMapping,
+ &Mapped)))
+ {
+ return;
+ }
+
+ //
+ // Write to memory
+ //
+
+#ifdef _M_IX86
+
+ memcpy(MemoryMapping, Buffer, Length);
+
+#else
+
+ WRITE_REGISTER_BUFFER_UCHAR(MemoryMapping,Buffer,Length);
+
+#endif
+
+ //
+ // End mapping
+ //
+
+ ndisEndMapping(MemoryMapping, Length, Mapped);
+}
+
+
+VOID
+NdisOpenFile(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE FileHandle,
+ OUT PUINT FileLength,
+ IN PNDIS_STRING FileName,
+ IN NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine opens a file for future mapping and reads its contents
+ into allocated memory.
+
+Arguments:
+
+ Status - The status of the operation
+
+ FileHandle - A handle to be associated with this open
+
+ FileLength - Returns the length of the file
+
+ FileName - The name of the file
+
+ HighestAcceptableAddress - The highest physical address at which
+ the memory for the file can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ NTSTATUS NtStatus;
+ IO_STATUS_BLOCK IoStatus;
+ HANDLE NtFileHandle;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ ULONG LengthOfFile;
+ WCHAR PathPrefix[] = L"\\SystemRoot\\system32\\drivers\\";
+ NDIS_STRING FullFileName;
+ ULONG FullFileNameLength;
+ PNDIS_FILE_DESCRIPTOR FileDescriptor;
+ PVOID FileImage;
+
+ //
+ // This structure represents the data from the
+ // NtQueryInformationFile API with an information
+ // class of FileStandardInformation.
+ //
+
+ FILE_STANDARD_INFORMATION StandardInfo;
+
+
+ //
+ // Insert the correct path prefix.
+ //
+
+ FullFileNameLength = sizeof(PathPrefix) + FileName->MaximumLength;
+ FullFileName.Buffer = ALLOC_FROM_POOL(FullFileNameLength, NDIS_TAG_DEFAULT);
+
+ do
+ {
+ if (FullFileName.Buffer == NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+ FullFileName.Length = sizeof (PathPrefix) - sizeof(WCHAR);
+ FullFileName.MaximumLength = (USHORT)FullFileNameLength;
+ CopyMemory (FullFileName.Buffer, PathPrefix, sizeof(PathPrefix));
+
+ RtlAppendUnicodeStringToString (&FullFileName, FileName);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("Attempting to open %Z\n", &FullFileName));
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ &FullFileName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ NtStatus = ZwCreateFile(&NtFileHandle,
+ SYNCHRONIZE | FILE_READ_DATA,
+ &ObjectAttributes,
+ &IoStatus,
+ NULL,
+ 0,
+ FILE_SHARE_READ,
+ FILE_OPEN,
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0);
+
+ FREE_POOL(FullFileName.Buffer);
+
+ if (!NT_SUCCESS(NtStatus))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("Error opening file %x\n", NtStatus));
+ *Status = NDIS_STATUS_FILE_NOT_FOUND;
+ break;
+ }
+
+ //
+ // Query the object to determine its length.
+ //
+
+ NtStatus = ZwQueryInformationFile(NtFileHandle,
+ &IoStatus,
+ &StandardInfo,
+ sizeof(FILE_STANDARD_INFORMATION),
+ FileStandardInformation);
+
+ if (!NT_SUCCESS(NtStatus))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("Error querying info on file %x\n", NtStatus));
+ ZwClose(NtFileHandle);
+ *Status = NDIS_STATUS_ERROR_READING_FILE;
+ break;
+ }
+
+ LengthOfFile = StandardInfo.EndOfFile.LowPart;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("File length is %d\n", LengthOfFile));
+
+ //
+ // Might be corrupted.
+ //
+
+ if (LengthOfFile < 1)
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("Bad file length %d\n", LengthOfFile));
+ ZwClose(NtFileHandle);
+ *Status = NDIS_STATUS_ERROR_READING_FILE;
+ break;
+ }
+
+ //
+ // Allocate buffer for this file
+ //
+
+ FileImage = ALLOC_FROM_POOL(LengthOfFile, NDIS_TAG_DEFAULT);
+
+ if (FileImage == NULL)
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("Could not allocate buffer\n"));
+ ZwClose(NtFileHandle);
+ *Status = NDIS_STATUS_ERROR_READING_FILE;
+ break;
+ }
+
+ //
+ // Read the file into our buffer.
+ //
+
+ NtStatus = ZwReadFile(NtFileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ FileImage,
+ LengthOfFile,
+ NULL,
+ NULL);
+
+ ZwClose(NtFileHandle);
+
+ if ((!NT_SUCCESS(NtStatus)) || (IoStatus.Information != LengthOfFile))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("error reading file %x\n", NtStatus));
+ *Status = NDIS_STATUS_ERROR_READING_FILE;
+ FREE_POOL(FileImage);
+ break;
+ }
+
+ //
+ // Allocate a structure to describe the file.
+ //
+
+ FileDescriptor = ALLOC_FROM_POOL(sizeof(NDIS_FILE_DESCRIPTOR), NDIS_TAG_DEFAULT);
+
+ if (FileDescriptor == NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ FREE_POOL(FileImage);
+ break;
+ }
+
+ FileDescriptor->Data = FileImage;
+ INITIALIZE_SPIN_LOCK (&FileDescriptor->Lock);
+ FileDescriptor->Mapped = FALSE;
+
+ *FileHandle = (NDIS_HANDLE)FileDescriptor;
+ *FileLength = LengthOfFile;
+ *Status = STATUS_SUCCESS;
+ } while (FALSE);
+}
+
+
+VOID
+NdisCloseFile(
+ IN NDIS_HANDLE FileHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine closes a file previously opened with NdisOpenFile.
+ The file is unmapped if needed and the memory is freed.
+
+Arguments:
+
+ FileHandle - The handle returned by NdisOpenFile
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_FILE_DESCRIPTOR FileDescriptor = (PNDIS_FILE_DESCRIPTOR)FileHandle;
+
+ FREE_POOL(FileDescriptor->Data);
+ FREE_POOL(FileDescriptor);
+}
+
+
+VOID
+NdisMapFile(
+ OUT PNDIS_STATUS Status,
+ OUT PVOID * MappedBuffer,
+ IN NDIS_HANDLE FileHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine maps an open file, so that the contents can be accessed.
+ Files can only have one active mapping at any time.
+
+Arguments:
+
+ Status - The status of the operation
+
+ MappedBuffer - Returns the virtual address of the mapping.
+
+ FileHandle - The handle returned by NdisOpenFile.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ KIRQL OldIrql;
+
+ PNDIS_FILE_DESCRIPTOR FileDescriptor = (PNDIS_FILE_DESCRIPTOR)FileHandle;
+
+ ACQUIRE_SPIN_LOCK(&FileDescriptor->Lock, &OldIrql);
+
+ if (FileDescriptor->Mapped == TRUE)
+ {
+ *Status = NDIS_STATUS_ALREADY_MAPPED;
+ RELEASE_SPIN_LOCK (&FileDescriptor->Lock, OldIrql);
+ return;
+ }
+
+ FileDescriptor->Mapped = TRUE;
+ RELEASE_SPIN_LOCK (&FileDescriptor->Lock, OldIrql);
+
+ *MappedBuffer = FileDescriptor->Data;
+ *Status = STATUS_SUCCESS;
+}
+
+
+VOID
+NdisUnmapFile(
+ IN NDIS_HANDLE FileHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine unmaps a file previously mapped with NdisOpenFile.
+ The file is unmapped if needed and the memory is freed.
+
+Arguments:
+
+ FileHandle - The handle returned by NdisOpenFile
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_FILE_DESCRIPTOR FileDescriptor = (PNDIS_FILE_DESCRIPTOR)FileHandle;
+ KIRQL OldIrql;
+
+ ACQUIRE_SPIN_LOCK(&FileDescriptor->Lock, &OldIrql);
+ FileDescriptor->Mapped = FALSE;
+ RELEASE_SPIN_LOCK (&FileDescriptor->Lock, OldIrql);
+}
+
+
+CCHAR
+NdisSystemProcessorCount(
+ VOID
+ )
+{
+ return **((PCHAR *)&KeNumberProcessors);
+}
+
+
+VOID
+NdisGetSystemUpTime(
+ OUT PULONG pSystemUpTime
+ )
+{
+ LARGE_INTEGER TickCount;
+
+ //
+ // Get tick count and convert to hundreds of nanoseconds.
+ //
+ KeQueryTickCount(&TickCount);
+ TickCount = RtlExtendedIntegerMultiply(TickCount,
+ KeQueryTimeIncrement());
+ TickCount = RtlExtendedIntegerMultiply(TickCount, 10000);
+
+ ASSERT(TickCount.HighPart == 0);
+ *pSystemUpTime = TickCount.LowPart;
+}
+
+VOID
+NdisGetCurrentProcessorCpuUsage(
+ IN PULONG pCpuUsage
+)
+{
+ PKPRCB Prcb;
+
+ Prcb = KeGetCurrentPrcb();
+ *pCpuUsage = 100 - (ULONG)(UInt32x32To64(Prcb->IdleThread->KernelTime, 100) /
+ (ULONGLONG)(Prcb->KernelTime + Prcb->UserTime));
+}
+
+
+VOID
+NdisGetCurrentProcessorCounts(
+ OUT PULONG pIdleCount,
+ OUT PULONG pKernelAndUser,
+ OUT PULONG pIndex
+ )
+{
+ PKPRCB Prcb;
+
+ Prcb = KeGetCurrentPrcb();
+ *pIdleCount = Prcb->IdleThread->KernelTime;
+ *pKernelAndUser = Prcb->KernelTime + Prcb->UserTime;
+ *pIndex = (ULONG)Prcb->Number;
+}
+
+#undef NdisGetCurrentSystemTime
+VOID
+NdisGetCurrentSystemTime(
+ IN PLARGE_INTEGER pCurrentTime
+)
+{
+ KeQuerySystemTime(pCurrentTime);
+}
+
+
+
+NDIS_STATUS
+NdisQueryMapRegisterCount(
+ IN NDIS_INTERFACE_TYPE BusType,
+ OUT PUINT MapRegisterCount
+)
+{
+ NTSTATUS Status;
+ UINT Count, Tmp;
+
+ Count = (UINT)BusType;
+ Status = HalQuerySystemInformation(HalMapRegisterInformation,
+ sizeof(UINT),
+ &Count,
+ &Tmp);
+ if (NT_SUCCESS(Status))
+ {
+ *MapRegisterCount = Count;
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ return NDIS_STATUS_NOT_SUPPORTED;
+}
+
+
+//
+// NDIS Event support
+//
+
+VOID
+NdisInitializeEvent(
+ IN PNDIS_EVENT Event
+ )
+{
+ INITIALIZE_EVENT(&Event->Event);
+}
+
+VOID
+NdisSetEvent(
+ IN PNDIS_EVENT Event
+ )
+{
+ SET_EVENT(&Event->Event);
+}
+
+VOID
+NdisResetEvent(
+ IN PNDIS_EVENT Event
+ )
+{
+ RESET_EVENT(&Event->Event);
+}
+
+BOOLEAN
+NdisWaitEvent(
+ IN PNDIS_EVENT Event,
+ IN UINT MsToWait
+ )
+{
+ NTSTATUS Status;
+ TIME Time, *pTime;
+
+ pTime = NULL;
+ if (MsToWait != 0)
+ {
+ ASSERT(CURRENT_IRQL < DISPATCH_LEVEL);
+ Time.QuadPart = Int32x32To64(MsToWait, -10000);
+ pTime = &Time;
+ }
+
+ Status = WAIT_FOR_OBJECT(&Event->Event, pTime);
+
+ return(Status == NDIS_STATUS_SUCCESS);
+}
+
+VOID
+NdisInitializeString(
+ OUT PNDIS_STRING Destination,
+ IN PUCHAR Source
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ WCHAR *strptr;
+
+ Destination->Length = strlen(Source) * sizeof(WCHAR);
+ Destination->MaximumLength = Destination->Length + sizeof(WCHAR);
+ Destination->Buffer = ALLOC_FROM_POOL(Destination->MaximumLength, NDIS_TAG_STRING);
+
+ strptr = Destination->Buffer;
+ while (*Source != '\0')
+ {
+ *strptr = (WCHAR)*Source;
+ Source++;
+ strptr++;
+ }
+ *strptr = UNICODE_NULL;
+}
+
+
+NDIS_STATUS
+ndisReportResources(
+ PCM_RESOURCE_LIST Resources,
+ PDRIVER_OBJECT DriverObject,
+ PDEVICE_OBJECT DeviceObject,
+ PNDIS_STRING AdapterName,
+ ULONG NewResourceType
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+ BOOLEAN Conflict;
+
+ //
+ // When we report the resources we need to subtract 1 from the
+ // count. this is because the sizeof(CM_RESOURCE_LIST) already includes
+ // one CM_PARTIAL_RESOURCE_DESCRIPTOR and if we multiply by the current
+ // Count the size passed to IoReportResourceUsage will be one descriptor
+ // too many.
+ //
+ Status = IoReportResourceUsage(NULL,
+ DriverObject,
+ NULL,
+ 0,
+ DeviceObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ (sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ (Resources->List->PartialResourceList.Count - 1)),
+ TRUE,
+ &Conflict);
+
+ //
+ // Check for conflict.
+ //
+ if (Conflict || (Status != STATUS_SUCCESS))
+ {
+ if (Conflict)
+ {
+ //
+ // Log an error
+ //
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ ULONG i;
+ ULONG StringSize;
+ PUCHAR Place;
+ PWCH baseFileName;
+ USHORT logsize;
+
+ baseFileName = AdapterName->Buffer;
+
+ //
+ // Parse out the path name, leaving only the device name.
+ //
+ for (i = 0; i < AdapterName->Length / sizeof(WCHAR); i++)
+ {
+ //
+ // If s points to a directory separator, set baseFileName to
+ // the character after the separator.
+ //
+ if (AdapterName->Buffer[i] == OBJ_NAME_PATH_SEPARATOR)
+ {
+ baseFileName = &(AdapterName->Buffer[++i]);
+ }
+ }
+
+ StringSize = AdapterName->MaximumLength -
+ ((ULONG)baseFileName - (ULONG)AdapterName->Buffer);
+ logsize = sizeof(IO_ERROR_LOG_PACKET) + StringSize + 6;
+ if (logsize > 255)
+ {
+ logsize = 255;
+ }
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ DeviceObject,
+ (UCHAR)logsize);
+ if (errorLogEntry != NULL)
+ {
+ switch (NewResourceType)
+ {
+ case CmResourceTypePort:
+
+ errorLogEntry->ErrorCode = EVENT_NDIS_IO_PORT_CONFLICT;
+
+ break;
+
+ case CmResourceTypeDma:
+
+ errorLogEntry->ErrorCode = EVENT_NDIS_DMA_CONFLICT;
+
+ break;
+
+ case CmResourceTypeMemory:
+
+ errorLogEntry->ErrorCode = EVENT_NDIS_MEMORY_CONFLICT;
+
+ break;
+
+ case CmResourceTypeInterrupt:
+
+ errorLogEntry->ErrorCode = EVENT_NDIS_INTERRUPT_CONFLICT;
+
+ break;
+ }
+
+ //
+ // store the time
+ //
+ errorLogEntry->MajorFunctionCode = 0;
+ errorLogEntry->RetryCount = 0;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = 0;
+ errorLogEntry->SequenceNumber = 0;
+ errorLogEntry->IoControlCode = 0;
+
+ //
+ // Set string information
+ //
+ if (StringSize != 0)
+ {
+ errorLogEntry->NumberOfStrings = 1;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+
+ MoveMemory(((PUCHAR)errorLogEntry) + sizeof(IO_ERROR_LOG_PACKET),
+ baseFileName,
+ logsize - (sizeof(IO_ERROR_LOG_PACKET) + 6));
+
+ Place = ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize;
+ }
+ else
+ {
+ Place = ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET);
+
+ errorLogEntry->NumberOfStrings = 0;
+ }
+
+ //
+ // write it out
+ //
+ IoWriteErrorLogEntry(errorLogEntry);
+ }
+
+ return(NDIS_STATUS_RESOURCE_CONFLICT);
+ }
+
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+ndisRemoveResource(
+ OUT PCM_RESOURCE_LIST *pResources,
+ IN PCM_PARTIAL_RESOURCE_DESCRIPTOR DeadResource,
+ IN PDRIVER_OBJECT DriverObject,
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PNDIS_STRING AdapterName
+ )
+/*++
+
+Routine Description:
+
+ this routine will walk the current resource list looking for the
+ dead resource. it will construct a new resource list without the
+ dead resource and report this new list to the system.
+
+Arguments:
+
+ pResource - On entry this is the current resource list.
+ On exit this is the newly constructed resource list.
+ DriverObject - Driver object to report the resources for.
+ DeviceObject - Device object to report the resources for.
+ DeadResource - This is the resource to remove.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if the routine succeeded.
+
+--*/
+{
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR Dst;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR Partial;
+ PCM_RESOURCE_LIST CurrentList = *pResources;
+ PCM_RESOURCE_LIST Resources;
+ UINT c;
+ UINT Remaining;
+ BOOLEAN Conflict;
+ NDIS_STATUS Status;
+ BOOLEAN fFoundResource;
+
+ //
+ // Sanity check!
+ //
+ if ((NULL == pResources) || (NULL == *pResources))
+ {
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // Allocate a new resource map.
+ //
+ Resources = (PCM_RESOURCE_LIST)ALLOC_FROM_POOL(
+ sizeof(CM_RESOURCE_LIST) +
+ (sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ (CurrentList->List->PartialResourceList.Count - 1)),
+ NDIS_TAG_RSRC_LIST);
+ if (NULL == Resources)
+ {
+ //
+ // Leave it there...
+ //
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ //
+ // Copy the head information.
+ //
+ MoveMemory(Resources, CurrentList, sizeof(CM_RESOURCE_LIST));
+
+ Resources->List->PartialResourceList.Count--;
+
+ //
+ // Get our destination pointer.
+ //
+ Dst = Resources->List->PartialResourceList.PartialDescriptors;
+
+ //
+ // Find the resource in our resource list.
+ //
+ Partial = CurrentList->List->PartialResourceList.PartialDescriptors;
+ for (c = 0, fFoundResource = FALSE;
+ (c < CurrentList->List->PartialResourceList.Count) && !fFoundResource;
+ c++, Partial++)
+ {
+ //
+ // Is this the resource we are supposed to remove?
+ //
+ if (RtlEqualMemory(
+ Partial,
+ DeadResource,
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)))
+ {
+ //
+ // copy the remaining portion of the list.
+ //
+ fFoundResource = TRUE;
+
+ //
+ // Copy any remaining resources into the list.
+ //
+ Remaining = CurrentList->List->PartialResourceList.Count - (c+1);
+ if (Remaining > 0)
+ {
+ MoveMemory(Dst, Partial+1, Remaining * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
+ }
+ }
+ else
+ {
+ //
+ // Copy this resource to our new list!
+ //
+ MoveMemory(Dst, Partial, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
+ Dst++;
+ }
+
+ }
+
+ //
+ // Did we find the resource?
+ //
+ if (!fFoundResource)
+ {
+ FREE_POOL(Resources);
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // Free the old resource list and save the new one.
+ //
+ FREE_POOL(*pResources);
+
+ *pResources = Resources;
+
+ //
+ // Report the resources to the system.
+ //
+ Status = ndisReportResources(
+ Resources,
+ DriverObject,
+ DeviceObject,
+ AdapterName,
+ DeadResource->Type);
+
+ return(Status);
+}
+
+
+NDIS_STATUS
+ndisAddResource(
+ OUT PCM_RESOURCE_LIST *pResources,
+ IN PCM_PARTIAL_RESOURCE_DESCRIPTOR NewResource,
+ IN NDIS_INTERFACE_TYPE AdapterType,
+ IN ULONG BusNumber,
+ IN PDRIVER_OBJECT DriverObject,
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PNDIS_STRING AdapterName
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PCM_RESOURCE_LIST Resources;
+ UINT NumberOfElements;
+ BOOLEAN Conflict;
+ NDIS_STATUS Status;
+
+ if (*pResources != NULL)
+ {
+ NumberOfElements = (*pResources)->List->PartialResourceList.Count;
+ }
+ else
+ {
+ NumberOfElements = 0;
+ }
+
+ //
+ // Allocate room for the new list. Note that we don't have to add one
+ // to the NumberOfElements since a CM_RESOURCE_LIST already contains a
+ // single CM_PARTIAL_RESOURCE_DESCRIPTOR.
+ //
+ Resources = (PCM_RESOURCE_LIST)ALLOC_FROM_POOL(
+ sizeof(CM_RESOURCE_LIST) +
+ (sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * NumberOfElements),
+ NDIS_TAG_RSRC_LIST);
+ if (NULL == Resources)
+ {
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ if (*pResources != NULL)
+ {
+ //
+ // We need to subtract the size of a CM_PARTIAL_RESOURCE_DESCRIPTOR
+ // from the size of the CM_RESOURCE_LIST.
+ //
+ MoveMemory(Resources,
+ *pResources,
+ (sizeof(CM_RESOURCE_LIST) -
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)) +
+ (sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ (*pResources)->List->PartialResourceList.Count));
+ }
+ else
+ {
+ //
+ // Setup initial resource information.
+ //
+ Resources->Count = 1;
+ Resources->List->InterfaceType = AdapterType;
+ Resources->List->BusNumber = BusNumber;
+ Resources->List->PartialResourceList.Version = 0;
+ Resources->List->PartialResourceList.Revision = 0;
+ Resources->List->PartialResourceList.Count = 0;
+ }
+
+ //
+ // Add the new resource.
+ //
+ Resources->List->PartialResourceList.PartialDescriptors[Resources->List->PartialResourceList.Count] = *NewResource;
+ Resources->List->PartialResourceList.Count++;
+
+ if (*pResources != NULL)
+ {
+ FREE_POOL(*pResources);
+ }
+
+ *pResources = Resources;
+
+ //
+ // Report the resources to the system.
+ //
+ Status = ndisReportResources(
+ Resources,
+ DriverObject,
+ DeviceObject,
+ AdapterName,
+ NewResource->Type);
+
+ return(Status);
+}
+
+
+
diff --git a/private/ntos/ndis/ndis40/config.c b/private/ntos/ndis/ndis40/config.c
new file mode 100644
index 000000000..12840f032
--- /dev/null
+++ b/private/ntos/ndis/ndis40/config.c
@@ -0,0 +1,2788 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ config.c
+
+Abstract:
+
+ NDIS wrapper functions for full mac drivers configuration/initialization
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 05-Oct-93
+ Jameel Hyder (JameelH) 01-Jun-95 Re-organization/optimization
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+#include <stdarg.h>
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_CONFIG
+
+//
+// Requests Used by MAC Drivers
+//
+//
+
+VOID
+NdisInitializeWrapper(
+ OUT PNDIS_HANDLE NdisWrapperHandle,
+ IN PVOID SystemSpecific1,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+/*++
+
+Routine Description:
+
+ Called at the beginning of every MAC's initialization routine.
+
+Arguments:
+
+ NdisWrapperHandle - A MAC specific handle for the wrapper.
+
+ SystemSpecific1, a pointer to the driver object for the MAC.
+ SystemSpecific2, a PUNICODE_STRING containing the location of
+ the registry subtree for this driver.
+ SystemSpecific3, unused on NT.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ NDIS_STATUS Status;
+ PUNICODE_STRING RegPath;
+
+ PNDIS_WRAPPER_HANDLE WrapperHandle;
+
+ UNREFERENCED_PARAMETER (SystemSpecific3);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisInitializeWrapper\n"));
+
+ *NdisWrapperHandle = NULL;
+ Status = NdisAllocateMemory((PVOID*)NdisWrapperHandle,
+ sizeof(NDIS_WRAPPER_HANDLE) +
+ sizeof(UNICODE_STRING) +
+ ((PUNICODE_STRING)SystemSpecific2)->Length +
+ sizeof(WCHAR),
+ 0,
+ HighestAcceptableMax);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ WrapperHandle = (PNDIS_WRAPPER_HANDLE)(*NdisWrapperHandle);
+ WrapperHandle->NdisWrapperDriver = (PDRIVER_OBJECT)SystemSpecific1;
+ RegPath = (PUNICODE_STRING)((PUCHAR)WrapperHandle + sizeof(NDIS_WRAPPER_HANDLE));
+ RegPath->Buffer = (PWSTR)((PUCHAR)RegPath + sizeof(UNICODE_STRING));
+ RegPath->MaximumLength =
+ RegPath->Length = ((PUNICODE_STRING)SystemSpecific2)->Length;
+ NdisMoveMemory(RegPath->Buffer,
+ ((PUNICODE_STRING)SystemSpecific2)->Buffer,
+ RegPath->Length);
+ WrapperHandle->NdisWrapperConfigurationHandle = RegPath;
+ }
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisInitializeWrapper\n"));
+}
+
+
+VOID
+NdisTerminateWrapper(
+ IN NDIS_HANDLE NdisWrapperHandle,
+ IN PVOID SystemSpecific
+ )
+/*++
+
+Routine Description:
+
+ Called at the end of every MAC's termination routine.
+
+Arguments:
+
+ NdisWrapperHandle - The handle returned from NdisInitializeWrapper.
+
+ SystemSpecific - No defined value.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_WRAPPER_HANDLE NdisMacInfo = (PNDIS_WRAPPER_HANDLE)NdisWrapperHandle;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisTerminateWrapper\n"));
+
+ UNREFERENCED_PARAMETER(SystemSpecific);
+
+
+ if (NdisMacInfo != NULL)
+ {
+ NdisFreeMemory(NdisMacInfo, sizeof(NDIS_WRAPPER_HANDLE), 0);
+ }
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisTerminateWrapper\n"));
+}
+
+
+
+//
+// Operating System Requests
+//
+//
+
+VOID
+NdisMapIoSpace(
+ OUT PNDIS_STATUS Status,
+ OUT PVOID * VirtualAddress,
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress,
+ IN UINT Length
+ )
+/*++
+
+Routine Description:
+
+ Map virtual memory address space onto a physical address.
+
+Arguments:
+
+ Status - resulting status
+ VirtualAddress - resulting address in virtual space.
+ NdisAdapterHandle - value returned by NdisRegisterAdapter.
+ PhysicalAddress - Physical address.
+ Length - Size of requested memory mapping
+
+Return Value:
+
+ none.
+
+--*/
+{
+ ULONG addressSpace = 0;
+ ULONG NumberOfElements;
+ ULONG BusNumber;
+ NDIS_INTERFACE_TYPE BusType;
+ PHYSICAL_ADDRESS PhysicalTemp;
+ PCM_RESOURCE_LIST Resources, Resc;
+ BOOLEAN Conflict;
+ NTSTATUS NtStatus;
+ PNDIS_ADAPTER_BLOCK AdptrP = (PNDIS_ADAPTER_BLOCK)(NdisAdapterHandle);
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(NdisAdapterHandle);
+
+ //
+ // First check if any bus access is allowed
+ //
+
+ BusType = (AdptrP->DeviceObject != NULL) ? AdptrP->BusType : Miniport->BusType;
+ BusNumber = (AdptrP->DeviceObject != NULL) ? AdptrP->BusNumber : Miniport->BusNumber;
+
+ do
+ {
+ if ((BusType == (NDIS_INTERFACE_TYPE)-1) || (BusNumber == (ULONG)-1))
+ {
+ *Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // First check for resource conflict by expanding current resource list,
+ // adding in the mapped space, and then re-submitting the resource list.
+ //
+
+ Resc = (AdptrP->DeviceObject != NULL) ? AdptrP->Resources : Miniport->Resources;
+ if (Resc != NULL)
+ {
+ NumberOfElements = Resc->List[0].PartialResourceList.Count + 1;
+ }
+ else
+ {
+ NumberOfElements = 1;
+ }
+
+ //
+ // First check for resource conflict by expanding current resource list,
+ // adding in the mapped space, and then re-submitting the resource list.
+ //
+
+ Resources = (PCM_RESOURCE_LIST)ALLOC_FROM_POOL(sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ NumberOfElements,
+ NDIS_TAG_RSRC_LIST);
+
+ if (Resources == NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ if (Resc != NULL)
+ {
+ CopyMemory(Resources,
+ Resc,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ (NumberOfElements-1));
+ }
+ else
+ {
+ //
+ // Setup initial resource info -- NOTE: This is definitely a mini-port
+ //
+ ASSERT(AdptrP->DeviceObject == NULL);
+ Resources->Count = 1;
+ Resources->List[0].InterfaceType = Miniport->AdapterType;
+ Resources->List[0].BusNumber = BusNumber;
+ Resources->List[0].PartialResourceList.Version = 0;
+ Resources->List[0].PartialResourceList.Revision = 0;
+ Resources->List[0].PartialResourceList.Count = 0;
+ }
+
+ //
+ // Setup memory
+ //
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Type =
+ CmResourceTypeMemory;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].ShareDisposition =
+ CmResourceShareDeviceExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Flags =
+ CM_RESOURCE_MEMORY_READ_WRITE;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Memory.Start =
+ PhysicalAddress;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Memory.Length =
+ Length;
+ Resources->List[0].PartialResourceList.Count++;
+
+
+ //
+ // Make the call
+ //
+ NtStatus = IoReportResourceUsage(NULL,
+ ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->MacHandle->NdisMacInfo->NdisWrapperDriver :
+ Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver),
+ NULL,
+ 0,
+ (AdptrP->DeviceObject != NULL) ?
+ AdptrP->DeviceObject:
+ Miniport->DeviceObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ (sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)*Resources->List[0].PartialResourceList.Count),
+ TRUE,
+ &Conflict);
+
+ //
+ // Check for conflict.
+ //
+ if (Resc != NULL)
+ {
+ FREE_POOL(Resc);
+ }
+
+ if (AdptrP->DeviceObject != NULL)
+ {
+ AdptrP->Resources = Resources;
+ }
+ else
+ {
+ Miniport->Resources = Resources;
+ }
+
+ if (Conflict || (NtStatus != STATUS_SUCCESS))
+ {
+ if (Conflict)
+ {
+ //
+ // Log an error
+ //
+
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ volatile ULONG i;
+ ULONG StringSize;
+ PUCHAR Place;
+ PWCH baseFileName;
+ WCHAR Character;
+ ULONG Value;
+
+ baseFileName = ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.Buffer :
+ Miniport->MiniportName.Buffer);
+
+ //
+ // Parse out the path name, leaving only the device name.
+ //
+
+ for (i = 0;
+ i < ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.Length :
+ Miniport->MiniportName.Length) / sizeof(WCHAR);
+ i++)
+ {
+ //
+ // If s points to a directory separator, set baseFileName to
+ // the character after the separator.
+ //
+
+ if (((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.Buffer[i] :
+ Miniport->MiniportName.Buffer[i]) == OBJ_NAME_PATH_SEPARATOR)
+ {
+ baseFileName = ((AdptrP->DeviceObject != NULL) ?
+ &(AdptrP->AdapterName.Buffer[++i]):
+ &(Miniport->MiniportName.Buffer[++i]));
+ }
+ }
+
+ StringSize = ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.MaximumLength :
+ Miniport->MiniportName.MaximumLength) -
+ (((ULONG)baseFileName) -
+ ((AdptrP->DeviceObject != NULL) ?
+ ((ULONG)AdptrP->AdapterName.Buffer) :
+ ((ULONG)Miniport->MiniportName.Buffer)));
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(((AdptrP->DeviceObject != NULL) ?
+ AdptrP->DeviceObject : Miniport->DeviceObject),
+ (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) + StringSize + 34));
+ // wstrlen("FFFFFFFFFFFFFFFF") * sizeof(WHCAR) + sizeof(UNICODE_NULL)
+
+ if (errorLogEntry != NULL)
+ {
+ errorLogEntry->ErrorCode = EVENT_NDIS_MEMORY_CONFLICT;
+
+ //
+ // store the time
+ //
+ errorLogEntry->MajorFunctionCode = 0;
+ errorLogEntry->RetryCount = 0;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = 0;
+ errorLogEntry->SequenceNumber = 0;
+ errorLogEntry->IoControlCode = 0;
+
+ //
+ // Set string information
+ //
+ if (StringSize != 0)
+ {
+ errorLogEntry->NumberOfStrings = 1;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+
+ CopyMemory (((PUCHAR)errorLogEntry) + sizeof(IO_ERROR_LOG_PACKET),
+ (PVOID)baseFileName,
+ StringSize);
+
+ Place = ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize;
+ }
+ else
+ {
+ Place = ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET);
+
+ errorLogEntry->NumberOfStrings = 0;
+ }
+
+ errorLogEntry->NumberOfStrings++;
+
+ //
+ // Put in memory address
+ //
+ for (StringSize = 0; StringSize < 2; StringSize++)
+ {
+ if (StringSize == 0)
+ {
+ //
+ // Do high part
+ //
+ Value = NdisGetPhysicalAddressHigh(PhysicalAddress);
+ }
+ else
+ {
+ //
+ // Do Low part
+ //
+ Value = NdisGetPhysicalAddressLow(PhysicalAddress);
+ }
+
+ //
+ // Convert value
+ //
+ for (i = 1; i <= (sizeof(ULONG) * 2); i++)
+ {
+ WCHAR c;
+
+ c = (WCHAR)((Value >> (((sizeof(ULONG) * 2) - i) * 4)) & 0x0F);
+ if (c <= 9)
+ {
+ Character = L'0' + c;
+ }
+ else
+ {
+ Character = L'A' + c - 10;
+ }
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ Place += sizeof(WCHAR);
+ }
+ }
+
+ Character = UNICODE_NULL;
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ //
+ // write it out
+ //
+ IoWriteErrorLogEntry(errorLogEntry);
+ }
+
+ *Status = NDIS_STATUS_RESOURCE_CONFLICT;
+ break;
+ }
+
+ *Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ if (!HalTranslateBusAddress(BusType,
+ BusNumber,
+ PhysicalAddress,
+ &addressSpace,
+ &PhysicalTemp))
+ {
+ //
+ // It would be nice to return a better status here, but we only get
+ // TRUE/FALSE back from HalTranslateBusAddress.
+ //
+
+ *Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ if (addressSpace == 0)
+ {
+ //
+ // memory space
+ //
+
+ *VirtualAddress = MmMapIoSpace(PhysicalTemp, (Length), FALSE);
+ }
+ else
+ {
+ //
+ // I/O space
+ //
+
+ *VirtualAddress = (PVOID)(PhysicalTemp.LowPart);
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+ if (*VirtualAddress == NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ }
+ } while (FALSE);
+}
+
+
+VOID
+NdisAllocateDmaChannel(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE NdisDmaHandle,
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN PNDIS_DMA_DESCRIPTION DmaDescription,
+ IN ULONG MaximumLength
+ )
+/*++
+
+Routine Description:
+
+ Sets up a DMA channel for future DMA operations.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ NdisDmaHandle - Returns a handle used to specify this channel to
+ future operations.
+
+ NdisAdapterHandle - handle returned by NdisRegisterAdapter.
+
+ DmaDescription - Details of the DMA channel.
+
+ MaximumLength - The maximum length DMA transfer that will be done
+ using this channel.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // For registering this set of resources
+ //
+ PCM_RESOURCE_LIST Resources;
+ BOOLEAN Conflict;
+
+ //
+ // Needed to call HalGetAdapter.
+ //
+ DEVICE_DESCRIPTION DeviceDescription;
+
+ //
+ // Returned by HalGetAdapter.
+ //
+ PADAPTER_OBJECT AdapterObject;
+
+ //
+ // Map registers needed per channel.
+ //
+ ULONG MapRegistersNeeded;
+
+ //
+ // Map registers allowed per channel.
+ //
+ ULONG MapRegistersAllowed;
+
+ //
+ // Saves the structure we allocate for this channel.
+ //
+ PNDIS_DMA_BLOCK DmaBlock;
+
+ //
+ // Convert the handle to our internal structure.
+ PNDIS_ADAPTER_BLOCK AdapterBlock =
+ (PNDIS_ADAPTER_BLOCK) NdisAdapterHandle;
+
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) NdisAdapterHandle;
+ BOOLEAN IsAMiniport;
+
+ //
+ // Save our IRQL when we raise it to call IoAllocateAdapterChannel.
+ //
+ KIRQL OldIrql;
+ ULONG NumberOfElements;
+
+ NTSTATUS NtStatus;
+
+ LARGE_INTEGER TimeoutValue;
+
+ IsAMiniport = (AdapterBlock->DeviceObject == NULL);
+
+ //
+ // First check if any bus access is allowed
+ //
+ if (((IsAMiniport ?
+ Miniport->BusType :
+ AdapterBlock->BusType) == (NDIS_INTERFACE_TYPE)-1) ||
+ ((IsAMiniport ?
+ Miniport->BusNumber :
+ AdapterBlock->BusNumber) == (ULONG)-1))
+ {
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+ //
+ // First check for resource conflict by expanding current resource list,
+ // adding in the mapped space, and then re-submitting the resource list.
+ //
+ if ((IsAMiniport ? Miniport->Resources : AdapterBlock->Resources) != NULL)
+ {
+ NumberOfElements =
+ (IsAMiniport ?
+ Miniport->Resources->List[0].PartialResourceList.Count :
+ AdapterBlock->Resources->List[0].PartialResourceList.Count) + 1;
+ }
+ else
+ {
+ NumberOfElements = 1;
+ }
+
+ //
+ // First check for resource conflict by expanding current resource list,
+ // adding in the mapped space, and then re-submitting the resource list.
+ //
+
+ Resources = (PCM_RESOURCE_LIST)ALLOC_FROM_POOL(sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ NumberOfElements,
+ NDIS_TAG_RSRC_LIST);
+
+ if (Resources == NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+
+ }
+
+ if ((IsAMiniport ? Miniport->Resources : AdapterBlock->Resources) != NULL)
+ {
+ CopyMemory(Resources,
+ (IsAMiniport ? Miniport->Resources : AdapterBlock->Resources),
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ (NumberOfElements - 1));
+ }
+ else
+ {
+ //
+ // Setup initial resource info
+ //
+ ASSERT(IsAMiniport);
+ Resources->Count = 1;
+ Resources->List[0].InterfaceType = Miniport->AdapterType;
+ Resources->List[0].BusNumber = Miniport->BusNumber;
+ Resources->List[0].PartialResourceList.Version = 0;
+ Resources->List[0].PartialResourceList.Revision = 0;
+ Resources->List[0].PartialResourceList.Count = 0;
+
+ }
+
+ //
+ // Setup DMA Channel
+ //
+
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Type =
+ CmResourceTypeDma;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].ShareDisposition =
+ CmResourceShareDeviceExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Flags =
+ 0;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Dma.Channel =
+ (IsAMiniport ? Miniport->ChannelNumber :
+ (DmaDescription->DmaChannelSpecified ?
+ DmaDescription->DmaChannel : AdapterBlock->ChannelNumber));
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Dma.Port =
+ DmaDescription->DmaPort;
+ Resources->List[0].PartialResourceList.Count++;
+
+
+ //
+ // Make the call
+ //
+ *Status = IoReportResourceUsage(NULL,
+ (IsAMiniport ?
+ Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver :
+ AdapterBlock->MacHandle->NdisMacInfo->NdisWrapperDriver),
+ NULL,
+ 0,
+ (IsAMiniport ? Miniport->DeviceObject : AdapterBlock->DeviceObject),
+ Resources,
+ sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * Resources->List[0].PartialResourceList.Count,
+ TRUE,
+ &Conflict);
+
+ if ((IsAMiniport ? Miniport->Resources : AdapterBlock->Resources) != NULL)
+ {
+ FREE_POOL((IsAMiniport ? Miniport->Resources : AdapterBlock->Resources));
+ }
+
+ if (IsAMiniport)
+ {
+ Miniport->Resources = Resources;
+ }
+ else
+ {
+ AdapterBlock->Resources = Resources;
+ }
+
+ //
+ // Check for conflict.
+ //
+
+ if (Conflict || (*Status != STATUS_SUCCESS))
+ {
+ if (Conflict)
+ {
+ //
+ // Log an error
+ //
+
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ ULONG i;
+ ULONG StringSize;
+ PUCHAR Place;
+ PWCH baseFileName;
+ WCHAR Character;
+ ULONG Value;
+
+ baseFileName = (IsAMiniport ?
+ Miniport->MiniportName.Buffer :
+ AdapterBlock->AdapterName.Buffer);
+
+ //
+ // Parse out the path name, leaving only the device name.
+ //
+
+ for (i = 0;
+ i < (IsAMiniport ? Miniport->MiniportName.Length :
+ AdapterBlock->AdapterName.Length)
+ / sizeof(WCHAR);
+ i++)
+ {
+ //
+ // If s points to a directory separator, set baseFileName to
+ // the character after the separator.
+ //
+
+ if ((IsAMiniport ?
+ Miniport->MiniportName.Buffer[i] :
+ AdapterBlock->AdapterName.Buffer[i]) == OBJ_NAME_PATH_SEPARATOR)
+ {
+ baseFileName = (IsAMiniport ?
+ &(Miniport->MiniportName.Buffer[++i]) :
+ &(AdapterBlock->AdapterName.Buffer[++i]));
+ }
+ }
+
+ StringSize = (IsAMiniport ?
+ Miniport->MiniportName.MaximumLength :
+ AdapterBlock->AdapterName.MaximumLength) -
+ (((ULONG)baseFileName) -
+ (IsAMiniport ?
+ ((ULONG)Miniport->MiniportName.Buffer) :
+ ((ULONG)AdapterBlock->AdapterName.Buffer)));
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (IsAMiniport ?
+ Miniport->DeviceObject :
+ AdapterBlock->DeviceObject),
+ (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize +
+ 6)); // wstrlen("99") * sizeof(WHCAR) + sizeof(UNICODE_NULL)
+
+ if (errorLogEntry != NULL)
+ {
+ errorLogEntry->ErrorCode = EVENT_NDIS_DMA_CONFLICT;
+
+ //
+ // store the time
+ //
+
+ errorLogEntry->MajorFunctionCode = 0;
+ errorLogEntry->RetryCount = 0;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = 0;
+ errorLogEntry->SequenceNumber = 0;
+ errorLogEntry->IoControlCode = 0;
+
+ //
+ // Set string information
+ //
+
+ if (StringSize != 0)
+ {
+ errorLogEntry->NumberOfStrings = 1;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+
+ CopyMemory(((PUCHAR)errorLogEntry) + sizeof(IO_ERROR_LOG_PACKET),
+ (PVOID)baseFileName,
+ StringSize);
+
+ Place = ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize;
+ }
+ else
+ {
+ Place = ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET);
+
+ errorLogEntry->NumberOfStrings = 0;
+ }
+
+ errorLogEntry->NumberOfStrings++;
+
+ //
+ // Put in dma channel
+ //
+
+ Value = (IsAMiniport ? Miniport->ChannelNumber :
+ AdapterBlock->ChannelNumber);
+
+ //
+ // Convert value
+ //
+ // I couldn't think of a better way to do this (with some
+ // loop). If you find one, plz put it in.
+ //
+
+ if (Value > 9)
+ {
+ Character = L'0' + (WCHAR)(Value / 10);
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ Place += sizeof(WCHAR);
+
+ Value -= 10;
+ }
+
+ Character = L'0' + (WCHAR)Value;
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ Place += sizeof(WCHAR);
+
+ Character = UNICODE_NULL;
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ //
+ // write it out
+ //
+ IoWriteErrorLogEntry(errorLogEntry);
+ }
+
+ *Status = NDIS_STATUS_RESOURCE_CONFLICT;
+ return;
+ }
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+ //
+ // Set up the device description; zero it out in case its
+ // size changes.
+ //
+
+ ZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
+
+ DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
+
+ DeviceDescription.Master =
+ (BOOLEAN)(IsAMiniport ?
+ MINIPORT_TEST_FLAG(Miniport, fMINIPORT_BUS_MASTER) : FALSE);
+
+ DeviceDescription.ScatterGather =
+ (BOOLEAN)(IsAMiniport ?
+ MINIPORT_TEST_FLAG(Miniport, fMINIPORT_BUS_MASTER) : FALSE);
+
+ DeviceDescription.DemandMode = DmaDescription->DemandMode;
+ DeviceDescription.AutoInitialize = DmaDescription->AutoInitialize;
+
+ DeviceDescription.Dma32BitAddresses =
+ (BOOLEAN)(IsAMiniport ?
+ MINIPORT_TEST_FLAG(Miniport, fMINIPORT_DMA_32_BIT_ADDRESSES) : FALSE);
+
+ DeviceDescription.BusNumber = (IsAMiniport ? Miniport->BusNumber : AdapterBlock->BusNumber);
+ DeviceDescription.DmaChannel = (IsAMiniport ? Miniport->ChannelNumber :
+ (DmaDescription->DmaChannelSpecified ?
+ DmaDescription->DmaChannel : AdapterBlock->ChannelNumber));
+ DeviceDescription.InterfaceType = (IsAMiniport ? Miniport->BusType : AdapterBlock->BusType);
+ DeviceDescription.DmaWidth = DmaDescription->DmaWidth;
+ DeviceDescription.DmaSpeed = DmaDescription->DmaSpeed;
+ DeviceDescription.MaximumLength = MaximumLength;
+ DeviceDescription.DmaPort = DmaDescription->DmaPort;
+
+ MapRegistersNeeded = ((MaximumLength - 2) / PAGE_SIZE) + 2;
+
+ //
+ // Get the adapter object.
+ //
+ AdapterObject = HalGetAdapter (&DeviceDescription, &MapRegistersAllowed);
+
+ if ((AdapterObject == NULL) || (MapRegistersAllowed < MapRegistersNeeded))
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ //
+ // Allocate storage for our DMA block.
+ //
+ DmaBlock = (PNDIS_DMA_BLOCK)ALLOC_FROM_POOL(sizeof(NDIS_DMA_BLOCK), NDIS_TAG_DMA);
+
+ if (DmaBlock == (PNDIS_DMA_BLOCK)NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ //
+ // Use this event to tell us when ndisAllocationExecutionRoutine
+ // has been called.
+ //
+ INITIALIZE_EVENT(&DmaBlock->AllocationEvent);
+
+ //
+ // We save this to call IoFreeAdapterChannel later.
+ //
+ DmaBlock->SystemAdapterObject = AdapterObject;
+
+ //
+ // Now allocate the adapter channel.
+ //
+ RAISE_IRQL_TO_DISPATCH(&OldIrql);
+
+ NtStatus = IoAllocateAdapterChannel(
+ AdapterObject,
+ (IsAMiniport ? Miniport->DeviceObject : AdapterBlock->DeviceObject),
+ MapRegistersNeeded,
+ ndisDmaExecutionRoutine,
+ (PVOID)DmaBlock);
+
+ LOWER_IRQL(OldIrql);
+
+ if (!NT_SUCCESS(NtStatus))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus));
+ FREE_POOL(DmaBlock);
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ TimeoutValue.QuadPart = Int32x32To64(100 * 1000, -10000);
+
+ //
+ // ndisDmaExecutionRoutine will set this event
+ // when it has been called.
+ //
+ NtStatus = WAIT_FOR_OBJECT(&DmaBlock->AllocationEvent, &TimeoutValue);
+
+ if (NtStatus != STATUS_SUCCESS)
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus));
+ FREE_POOL(DmaBlock);
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ RESET_EVENT(&DmaBlock->AllocationEvent);
+
+
+ //
+ // We now have the DMA channel allocated, we are done.
+ //
+ DmaBlock->InProgress = FALSE;
+
+ *NdisDmaHandle = (NDIS_HANDLE)DmaBlock;
+ *Status = NDIS_STATUS_SUCCESS;
+}
+
+
+VOID
+NdisFreeDmaChannel(
+ IN NDIS_HANDLE NdisDmaHandle
+ )
+/*++
+
+Routine Description:
+
+ Frees a DMA channel allocated with NdisAllocateDmaChannel.
+
+Arguments:
+
+ NdisDmaHandle - Handle returned by NdisAllocateDmaChannel, indicating the
+ DMA channel that is to be freed.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ KIRQL OldIrql;
+ PNDIS_DMA_BLOCK DmaBlock = (PNDIS_DMA_BLOCK)NdisDmaHandle;
+
+ RAISE_IRQL_TO_DISPATCH(&OldIrql);
+ IoFreeAdapterChannel (DmaBlock->SystemAdapterObject);
+ LOWER_IRQL(OldIrql);
+
+ FREE_POOL(DmaBlock);
+}
+
+
+VOID
+NdisSetupDmaTransfer(
+ OUT PNDIS_STATUS Status,
+ IN PNDIS_HANDLE NdisDmaHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG Offset,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ )
+/*++
+
+Routine Description:
+
+ Sets up the host DMA controller for a DMA transfer. The
+ DMA controller is set up to transfer the specified MDL.
+ Since we register all DMA channels as non-scatter/gather,
+ IoMapTransfer will ensure that the entire MDL is
+ in a single logical piece for transfer.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ NdisDmaHandle - Handle returned by NdisAllocateDmaChannel.
+
+ Buffer - An NDIS_BUFFER which describes the host memory involved in the
+ transfer.
+
+ Offset - An offset within buffer where the transfer should
+ start.
+
+ Length - The length of the transfer. VirtualAddress plus Length must not
+ extend beyond the end of the buffer.
+
+ WriteToDevice - TRUE for a download operation (host to adapter); FALSE
+ for an upload operation (adapter to host).
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_DMA_BLOCK DmaBlock = (PNDIS_DMA_BLOCK)NdisDmaHandle;
+ PHYSICAL_ADDRESS LogicalAddress;
+ ULONG LengthMapped;
+
+ //
+ // Make sure another request is not in progress.
+ //
+ if (DmaBlock->InProgress)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ DmaBlock->InProgress = TRUE;
+
+ //
+ // Use IoMapTransfer to set up the transfer.
+ //
+ LengthMapped = Length;
+
+ LogicalAddress = IoMapTransfer(DmaBlock->SystemAdapterObject,
+ (PMDL)Buffer,
+ DmaBlock->MapRegisterBase,
+ (PUCHAR)(MDL_VA(Buffer)) + Offset,
+ &LengthMapped,
+ WriteToDevice);
+ if (LengthMapped != Length)
+ {
+ //
+ // Somehow the request could not be mapped competely,
+ // this should not happen for a non-scatter/gather adapter.
+ //
+
+ (VOID)IoFlushAdapterBuffers(DmaBlock->SystemAdapterObject,
+ (PMDL)Buffer,
+ DmaBlock->MapRegisterBase,
+ (PUCHAR)(MDL_VA(Buffer)) + Offset,
+ LengthMapped,
+ WriteToDevice);
+
+ DmaBlock->InProgress = FALSE;
+ *Status = NDIS_STATUS_RESOURCES;
+ }
+
+ else *Status = NDIS_STATUS_SUCCESS;
+}
+
+
+VOID
+NdisCompleteDmaTransfer(
+ OUT PNDIS_STATUS Status,
+ IN PNDIS_HANDLE NdisDmaHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG Offset,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ )
+
+/*++
+
+Routine Description:
+
+ Completes a previously started DMA transfer.
+
+Arguments:
+
+ Status - Returns the status of the transfer.
+
+ NdisDmaHandle - Handle returned by NdisAllocateDmaChannel.
+
+ Buffer - An NDIS_BUFFER which was passed to NdisSetupDmaTransfer.
+
+ Offset - the offset passed to NdisSetupDmaTransfer.
+
+ Length - The length passed to NdisSetupDmaTransfer.
+
+ WriteToDevice - TRUE for a download operation (host to adapter); FALSE
+ for an upload operation (adapter to host).
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_DMA_BLOCK DmaBlock = (PNDIS_DMA_BLOCK)NdisDmaHandle;
+ BOOLEAN Successful;
+
+ Successful = IoFlushAdapterBuffers(DmaBlock->SystemAdapterObject,
+ (PMDL)Buffer,
+ DmaBlock->MapRegisterBase,
+ (PUCHAR)(MDL_VA(Buffer)) + Offset,
+ Length,
+ WriteToDevice);
+
+ *Status = (Successful ? NDIS_STATUS_SUCCESS : NDIS_STATUS_RESOURCES);
+ DmaBlock->InProgress = FALSE;
+}
+
+VOID
+NdisRegisterMac(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE NdisMacHandle,
+ IN NDIS_HANDLE NdisWrapperHandle,
+ IN NDIS_HANDLE MacMacContext,
+ IN PNDIS_MAC_CHARACTERISTICS MacCharacteristics,
+ IN UINT CharacteristicsLength
+ )
+/*++
+
+Routine Description:
+
+ Register an NDIS MAC.
+
+Arguments:
+
+ Status - Returns the final status.
+ NdisMacHandle - Returns a handle referring to this MAC.
+ NdisWrapperHandle - Handle returned by NdisInitializeWrapper.
+ MacMacContext - Context for calling MACUnloadMac and MACAddAdapter.
+ MacCharacteritics - The NDIS_MAC_CHARACTERISTICS table.
+ CharacteristicsLength - The length of MacCharacteristics.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_WRAPPER_HANDLE NdisMacInfo = (PNDIS_WRAPPER_HANDLE)(NdisWrapperHandle);
+ PNDIS_MAC_BLOCK MacBlock;
+ UNICODE_STRING Us;
+ PWSTR pWch;
+ USHORT i;
+ UINT MemNeeded;
+ KIRQL OldIrql;
+
+ //
+ // check that this is an NDIS 3.0 MAC.
+ //
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisRegisterMac\n"));
+
+ do
+ {
+ *NdisMacHandle = (NDIS_HANDLE)NULL;
+
+ if (NdisMacInfo == NULL)
+ {
+ *Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ IF_DBG(DBG_COMP_CONFIG, DBG_LEVEL_ERR)
+ {
+ BOOLEAN f = FALSE;
+
+ if (DbgIsNull(MacCharacteristics->OpenAdapterHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterMac: Null OpenAdapterHandler \n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(MacCharacteristics->CloseAdapterHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterMac: Null CloseAdapterHandler \n"));
+ f = TRUE;
+ }
+
+ if (DbgIsNull(MacCharacteristics->SendHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterMac: Null SendHandler \n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(MacCharacteristics->TransferDataHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterMac: Null TransferDataHandler \n"));
+ f = TRUE;
+ }
+
+ if (DbgIsNull(MacCharacteristics->ResetHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterMac: Null ResetHandler \n"));
+ f = TRUE;
+ }
+
+ if (DbgIsNull(MacCharacteristics->RequestHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterMac: Null RequestHandler \n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(MacCharacteristics->QueryGlobalStatisticsHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterMac: Null QueryGlobalStatisticsHandler \n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(MacCharacteristics->UnloadMacHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterMac: Null UnloadMacHandler \n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(MacCharacteristics->AddAdapterHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterMac: Null AddAdapterHandler \n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(MacCharacteristics->RemoveAdapterHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterMac: Null RemoveAdapterHandler \n"));
+ f = TRUE;
+ }
+
+ if (f)
+ DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR);
+ }
+
+ if ((MacCharacteristics->MajorNdisVersion != 3) ||
+ (MacCharacteristics->MinorNdisVersion != 0))
+ {
+ *Status = NDIS_STATUS_BAD_VERSION;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisRegisterMac\n"));
+ break;
+ }
+
+ //
+ // Check that CharacteristicsLength is enough.
+ //
+
+ if (CharacteristicsLength < sizeof(NDIS_MAC_CHARACTERISTICS))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("char len = %d < %d\n",
+ CharacteristicsLength,
+ sizeof(NDIS_MAC_CHARACTERISTICS)));
+
+ *Status = NDIS_STATUS_BAD_CHARACTERISTICS;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisRegisterMac\n"));
+ break;
+ }
+
+ //
+ // Allocate memory for the NDIS MAC block.
+ //
+ MemNeeded = sizeof(NDIS_MAC_BLOCK) + MacCharacteristics->Name.Length;
+
+ //
+ // Extract the base-name, determine its length and allocate that much more
+ //
+ Us = *(PUNICODE_STRING)(NdisMacInfo->NdisWrapperConfigurationHandle);
+
+ for (i = Us.Length/sizeof(WCHAR), pWch = Us.Buffer + i - 1;
+ i > 0;
+ pWch --, i--)
+ {
+ if (*pWch == L'\\')
+ {
+ Us.Buffer = pWch + 1;
+ Us.Length -= i*sizeof(WCHAR);
+ Us.MaximumLength = Us.Length + sizeof(WCHAR);
+ break;
+ }
+ }
+ MemNeeded += Us.MaximumLength;
+ MacBlock = (PNDIS_MAC_BLOCK)ALLOC_FROM_POOL(MemNeeded, NDIS_TAG_MAC_BLOCK);
+ if (MacBlock == (PNDIS_MAC_BLOCK)NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisRegisterMac\n"));
+ break;
+ }
+ ZeroMemory(MacBlock, MemNeeded);
+ MacBlock->Length = MemNeeded;
+
+ //
+ // Copy over the characteristics table.
+ //
+
+ CopyMemory((PVOID)&MacBlock->MacCharacteristics,
+ (PVOID)MacCharacteristics,
+ sizeof(NDIS_MAC_CHARACTERISTICS));
+
+ //
+ // Move buffer pointer to correct location (extra space at the end of
+ // the characteristics table)
+ //
+ MacBlock->MacCharacteristics.Name.Buffer = (PWSTR)((PUCHAR)MacBlock + sizeof(NDIS_MAC_BLOCK));
+
+ //
+ // Copy String over.
+ //
+ MacBlock->MacCharacteristics.Name.Length =
+ MacBlock->MacCharacteristics.Name.MaximumLength = MacCharacteristics->Name.Length;
+ CopyMemory(MacBlock->MacCharacteristics.Name.Buffer,
+ MacCharacteristics->Name.Buffer,
+ MacCharacteristics->Name.Length);
+
+ //
+ // Upcase the base-name and save it in the MiniBlock
+ //
+ MacBlock->BaseName.Buffer = (PWSTR)((PUCHAR)MacBlock->MacCharacteristics.Name.Buffer +
+ MacCharacteristics->Name.Length);
+ MacBlock->BaseName.Length = Us.Length;
+ MacBlock->BaseName.MaximumLength = Us.MaximumLength;
+ RtlUpcaseUnicodeString(&MacBlock->BaseName,
+ &Us,
+ FALSE);
+ //
+ // No adapters yet registered for this MAC.
+ //
+ MacBlock->AdapterQueue = (PNDIS_ADAPTER_BLOCK)NULL;
+
+ MacBlock->MacMacContext = MacMacContext;
+
+ //
+ // Set up unload handler
+ //
+ NdisMacInfo->NdisWrapperDriver->DriverUnload = ndisUnload;
+
+ //
+ // Set up shutdown handler
+ //
+ NdisMacInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_SHUTDOWN] = ndisShutdown;
+
+ //
+ // Set up the handlers for this driver (they all do nothing).
+ //
+ NdisMacInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_CREATE] = ndisCreateIrpHandler;
+ NdisMacInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ndisDeviceControlIrpHandler;
+ NdisMacInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_CLEANUP] = ndisSuccessIrpHandler;
+ NdisMacInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_CLOSE] = ndisCloseIrpHandler;
+
+ MacBlock->NdisMacInfo = NdisMacInfo;
+
+ //
+ // Use this event to tell us when all adapters are removed from the mac
+ // during an unload
+ //
+ INITIALIZE_EVENT(&MacBlock->AdaptersRemovedEvent);
+
+ MacBlock->Unloading = FALSE;
+
+ NdisInitializeRef(&MacBlock->Ref);
+
+ // Lock the init code down now - before we take the lock below
+ InitReferencePackage();
+
+ //
+ // Put MAC on global list.
+ //
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+
+ MacBlock->NextMac = ndisMacDriverList;
+ ndisMacDriverList = MacBlock;
+
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ *NdisMacHandle = (NDIS_HANDLE)MacBlock;
+
+ if (NdisMacInfo->NdisWrapperConfigurationHandle)
+ {
+ *Status = ndisInitializeAllAdapterInstances(MacBlock, NULL);
+
+ if (*Status != NDIS_STATUS_SUCCESS)
+ {
+ *Status = NDIS_STATUS_FAILURE;
+ ndisDereferenceMac(MacBlock);
+ }
+ }
+ else
+ {
+ *Status = NDIS_STATUS_FAILURE;
+ }
+
+ InitDereferencePackage();
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisRegisterMac\n"));
+ } while (FALSE);
+
+ ASSERT(CURRENT_IRQL < DISPATCH_LEVEL);
+}
+
+
+VOID
+NdisDeregisterMac(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisMacHandle
+ )
+/*++
+
+Routine Description:
+
+ Deregisters an NDIS MAC.
+
+Arguments:
+
+ Status - Returns the status of the request.
+ NdisMacHandle - The handle returned by NdisRegisterMac.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PNDIS_MAC_BLOCK OldMacP = (PNDIS_MAC_BLOCK)NdisMacHandle;
+
+ //
+ // If the MAC is already closing, return.
+ //
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ if (OldMacP == NULL)
+ {
+ return;
+ }
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisDeregisterMac\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ (" Mac %wZ being deregistered\n",&OldMacP->MacCharacteristics.Name));
+
+ IF_DBG(DBG_COMP_CONFIG, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(NdisMacHandle))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("DeregisterMac: Null Handle\n"));
+ DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(NdisMacHandle))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("DeregisterMac: Handle not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR);
+ }
+ }
+ if (!NdisCloseRef(&OldMacP->Ref))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisDeregisterMac\n"));
+ return;
+ }
+
+ ASSERT(OldMacP->AdapterQueue == (PNDIS_ADAPTER_BLOCK)NULL);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisDeregisterMac\n"));
+}
+
+
+NDIS_STATUS
+NdisRegisterAdapter(
+ OUT PNDIS_HANDLE NdisAdapterHandle,
+ IN NDIS_HANDLE NdisMacHandle,
+ IN NDIS_HANDLE MacAdapterContext,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN PNDIS_STRING AdapterName,
+ IN PVOID AdapterInformation
+ )
+/*++
+
+Routine Description:
+
+ Register an NDIS adapter.
+
+Arguments:
+
+ NdisAdapterHandle - Returns a handle referring to this adapter.
+ NdisMacHandle - A handle for a previously registered MAC.
+ MacAdapterContext - A context for calls into this MAC.
+ WrapperConfigurationContext - Context passed to MacAddAdapter.
+ AdapterName - The name the adapter should be registered under.
+ AdapterInformation - Contains adapter information. For future
+ use. NULL for the meantime. Storage for it
+ must be allocated by the caller.
+
+Return Value:
+
+ The final status.
+
+--*/
+{
+ PNDIS_ADAPTER_BLOCK NewAdaptP = NULL;
+ PDEVICE_OBJECT TmpDeviceP = NULL;
+ PNDIS_WRAPPER_CONFIGURATION_HANDLE ConfigurationHandle;
+ PNDIS_MAC_BLOCK TmpMacP;
+ NTSTATUS NtStatus;
+ NDIS_STRING NdisAdapterName = { 0 };
+ PHYSICAL_ADDRESS PortAddress;
+ PHYSICAL_ADDRESS InitialPortAddress;
+ ULONG addressSpace;
+ PNDIS_ADAPTER_INFORMATION AdapterInfo = (PNDIS_ADAPTER_INFORMATION)AdapterInformation;
+ BOOLEAN Conflict, ValidBus;
+ PCM_RESOURCE_LIST Resources = NULL;
+ LARGE_INTEGER TimeoutValue;
+ BOOLEAN AllocateIndividualPorts = TRUE, DerefMacOnError = FALSE;
+ ULONG i, Size;
+ ULONG BusNumber;
+ NDIS_INTERFACE_TYPE BusType;
+ NDIS_STATUS Status;
+ UNICODE_STRING DeviceName, UpcaseDeviceName;
+ UNICODE_STRING SymbolicLink;
+ WCHAR SymLnkBuf[40];
+ KIRQL OldIrql;
+
+ ConfigurationHandle = (PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisRegisterAdapter\n"));
+
+ IF_DBG(DBG_COMP_CONFIG, DBG_LEVEL_ERR)
+ {
+ BOOLEAN f = FALSE;
+ if (DbgIsNull(NdisMacHandle))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterAdapter: Null Handle\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(NdisMacHandle))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterAdapter: Handle not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(MacAdapterContext))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterAdapter: Null Context\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(MacAdapterContext))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterAdapter: Context not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (f)
+ DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR);
+ }
+
+ do
+ {
+ //
+ // Increment the MAC's refernce count.
+ //
+ if (!ndisReferenceMac((PNDIS_MAC_BLOCK)NdisMacHandle))
+ {
+ //
+ // The MAC is closing.
+ //
+
+ Status = NDIS_STATUS_CLOSING;
+ break;
+ }
+ DerefMacOnError = TRUE;
+
+ //
+ // Allocate the string structure and space for the string. This
+ // must be allocated from nonpaged pool, because it is touched by
+ // NdisWriteErrorLogEntry, which may be called from DPC level.
+ //
+ NdisAdapterName.Buffer = (PWSTR)ALLOC_FROM_POOL(AdapterName->MaximumLength,
+ NDIS_TAG_NAME_BUF);
+ if (NdisAdapterName.Buffer == NULL)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ NdisAdapterName.MaximumLength = AdapterName->MaximumLength;
+ NdisAdapterName.Length = AdapterName->Length;
+
+ CopyMemory(NdisAdapterName.Buffer,
+ AdapterName->Buffer,
+ AdapterName->MaximumLength);
+
+ //
+ // Create a device object for this adapter.
+ //
+ NtStatus = IoCreateDevice(((PNDIS_MAC_BLOCK)NdisMacHandle)->NdisMacInfo->NdisWrapperDriver,
+ sizeof(NDIS_ADAPTER_BLOCK) +
+ ConfigurationHandle->DriverBaseName->Length +
+ sizeof(NDIS_WRAPPER_CONTEXT),
+ AdapterName,
+ FILE_DEVICE_PHYSICAL_NETCARD,
+ 0,
+ FALSE, // exclusive flag
+ &TmpDeviceP);
+
+ if (NtStatus != STATUS_SUCCESS)
+ {
+ Status = NDIS_STATUS_DEVICE_FAILED;
+ break;
+ }
+
+ //
+ // Create symbolic link for the device
+ //
+ SymbolicLink.Buffer = SymLnkBuf;
+ SymbolicLink.Length = sizeof(L"\\DosDevices\\") - sizeof(WCHAR);
+ SymbolicLink.MaximumLength = sizeof(SymLnkBuf);
+ RtlCopyMemory(SymLnkBuf, L"\\DosDevices\\", sizeof(L"\\DosDevices\\"));
+ RtlAppendUnicodeStringToString(&SymbolicLink, ConfigurationHandle->DriverBaseName);
+ IoCreateSymbolicLink(&SymbolicLink, AdapterName);
+
+ //
+ // Initialize the NDIS adapter block in the device object extension
+ //
+ // *** NDIS_WRAPPER_CONTEXT has a higher alignment requirement than
+ // NDIS_ADAPTER_BLOCK, so we put it first in the extension.
+ //
+ ASSERT((sizeof(NDIS_WRAPPER_CONTEXT) & 3) <= (sizeof(NDIS_ADAPTER_BLOCK) & 3));
+
+ NewAdaptP = (PNDIS_ADAPTER_BLOCK)((PNDIS_WRAPPER_CONTEXT)TmpDeviceP->DeviceExtension + 1);
+ ZeroMemory(NewAdaptP, sizeof(NDIS_ADAPTER_BLOCK));
+
+ NewAdaptP->BaseName.Buffer = (PWSTR)((PUCHAR)NewAdaptP + sizeof(NDIS_ADAPTER_BLOCK));
+ NewAdaptP->BaseName.MaximumLength =
+ NewAdaptP->BaseName.Length = ConfigurationHandle->DriverBaseName->Length;
+ RtlUpcaseUnicodeString(&NewAdaptP->BaseName,
+ ConfigurationHandle->DriverBaseName,
+ FALSE);
+
+ NewAdaptP->DeviceObject = TmpDeviceP;
+ NewAdaptP->MacHandle = TmpMacP = (PNDIS_MAC_BLOCK)NdisMacHandle;
+ NewAdaptP->MacAdapterContext = MacAdapterContext;
+ NewAdaptP->AdapterName = NdisAdapterName;
+ NewAdaptP->OpenQueue = (PNDIS_OPEN_BLOCK)NULL;
+
+ NewAdaptP->WrapperContext = TmpDeviceP->DeviceExtension;
+
+ //
+ // Save the bus information in the adapter block
+ //
+ NewAdaptP->BusType = ConfigurationHandle->Db.BusType;
+ NewAdaptP->BusId = ConfigurationHandle->Db.BusId;
+ NewAdaptP->BusNumber = ConfigurationHandle->Db.BusNumber;
+ NewAdaptP->SlotNumber = ConfigurationHandle->Db.SlotNumber;
+
+ //
+ // Get the BusNumber and BusType from the context
+ //
+ BusNumber = ConfigurationHandle->ParametersQueryTable[3].DefaultLength;
+ if (ConfigurationHandle->ParametersQueryTable[3].DefaultType == (NDIS_INTERFACE_TYPE)-1)
+ {
+ BusType = (NDIS_INTERFACE_TYPE)-1;
+ }
+ else
+ {
+ BusType = AdapterInfo->AdapterType;
+ }
+
+ //
+ // Check that if there is no bus number or no bus type that the driver is not
+ // going to try to acquire any hardware resources
+ //
+ ValidBus = ((BusType != (NDIS_INTERFACE_TYPE)-1) && (BusNumber != (ULONG)-1));
+
+ if ((BusType == (NDIS_INTERFACE_TYPE)-1) || (BusNumber == (ULONG)-1))
+ {
+ if ((AdapterInfo != NULL) && ((AdapterInfo->NumberOfPortDescriptors != 0) || (AdapterInfo->Master)))
+ {
+ //
+ // Error out
+ //
+ Status = NDIS_STATUS_BAD_CHARACTERISTICS;
+ break;
+ }
+ }
+
+ //
+ // Free up previously assigned Resource memory
+ //
+ if ((BusType == NdisInterfacePci) &&
+ (BusNumber != -1) &&
+ (AdapterInfo != NULL) &&
+ (TmpMacP->PciAssignedResources != NULL))
+ {
+ TmpMacP->PciAssignedResources->Count = 0;
+ NtStatus = IoReportResourceUsage(NULL,
+ ((PNDIS_MAC_BLOCK)NdisMacHandle)->NdisMacInfo->NdisWrapperDriver,
+ TmpMacP->PciAssignedResources,
+ sizeof(CM_RESOURCE_LIST),
+ NULL,
+ NULL,
+ 0,
+ TRUE,
+ &Conflict);
+ FREE_POOL(TmpMacP->PciAssignedResources);
+ TmpMacP->PciAssignedResources = NULL;
+ }
+
+ //
+ // Calculate size of new buffer
+ //
+ Size = sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ (AdapterInfo->NumberOfPortDescriptors +
+ (((AdapterInfo->Master == TRUE) && (AdapterInfo->AdapterType == NdisInterfaceIsa)) ? 1 : 0));
+ Resources = (PCM_RESOURCE_LIST)ALLOC_FROM_POOL(Size, NDIS_TAG_RSRC_LIST);
+
+ if (Resources == NULL)
+ {
+ //
+ // Error out
+ //
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ //
+ // Fix up counts
+ //
+ Resources->List[0].PartialResourceList.Count = 0;
+
+ //
+ // Setup resources for the ports
+ //
+ if (ValidBus)
+ {
+ if (AdapterInfo != NULL)
+ {
+ ULONG HighestPort;
+ ULONG LowestPort;
+
+ Resources->Count = 1;
+ Resources->List[0].InterfaceType = AdapterInfo->AdapterType;
+ Resources->List[0].BusNumber = BusNumber;
+ Resources->List[0].PartialResourceList.Version = 0;
+ Resources->List[0].PartialResourceList.Revision = 0;
+
+ NewAdaptP->Resources = Resources;
+ NewAdaptP->BusNumber = BusNumber;
+ NewAdaptP->BusType = BusType;
+ NewAdaptP->AdapterType = AdapterInfo->AdapterType;
+ NewAdaptP->Master = AdapterInfo->Master;
+
+ //
+ // NewAdaptP->InitialPort and NumberOfPorts refer to the
+ // union of all port mappings specified; the area must
+ // cover all possible ports. We scan the list, keeping track
+ // of the highest and lowest ports used.
+ //
+
+ if (AdapterInfo->NumberOfPortDescriptors > 0)
+ {
+ //
+ // Setup port
+ //
+ LowestPort = AdapterInfo->PortDescriptors[0].InitialPort;
+ HighestPort = LowestPort + AdapterInfo->PortDescriptors[0].NumberOfPorts;
+
+ if (AdapterInfo->PortDescriptors[0].PortOffset == NULL)
+ {
+ AllocateIndividualPorts = FALSE;
+ }
+
+ for (i = 0; i < AdapterInfo->NumberOfPortDescriptors; i++)
+ {
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].Type =
+ CmResourceTypePort;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].ShareDisposition =
+ CmResourceShareDeviceExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].Flags =
+ (AdapterInfo->AdapterType == NdisInterfaceInternal)?
+ CM_RESOURCE_PORT_MEMORY : CM_RESOURCE_PORT_IO;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].u.Port.Start.QuadPart =
+ (ULONG)AdapterInfo->PortDescriptors[i].InitialPort;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].u.Port.Length =
+ AdapterInfo->PortDescriptors[i].NumberOfPorts;
+
+ if (AdapterInfo->PortDescriptors[i].PortOffset == NULL)
+ {
+ AllocateIndividualPorts = FALSE;
+ }
+
+ if (AdapterInfo->PortDescriptors[i].InitialPort < LowestPort)
+ {
+ LowestPort = AdapterInfo->PortDescriptors[i].InitialPort;
+ }
+ if ((AdapterInfo->PortDescriptors[i].InitialPort +
+ AdapterInfo->PortDescriptors[i].NumberOfPorts) > HighestPort)
+ {
+ HighestPort = AdapterInfo->PortDescriptors[i].InitialPort +
+ AdapterInfo->PortDescriptors[i].NumberOfPorts;
+ }
+ }
+
+ NewAdaptP->InitialPort = LowestPort;
+ NewAdaptP->NumberOfPorts = HighestPort - LowestPort;
+
+ }
+ else
+ {
+ NewAdaptP->NumberOfPorts = 0;
+ }
+
+ Resources->List[0].PartialResourceList.Count += AdapterInfo->NumberOfPortDescriptors;
+ }
+ else
+ {
+ //
+ // Error out
+ //
+
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+ }
+
+ NewAdaptP->BeingRemoved = FALSE;
+
+ if (ValidBus)
+ {
+ //
+ // Submit Resources
+ //
+ NtStatus = IoReportResourceUsage(NULL,
+ ((PNDIS_MAC_BLOCK)NdisMacHandle)->NdisMacInfo->NdisWrapperDriver,
+ NULL,
+ 0,
+ NewAdaptP->DeviceObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ Resources->List[0].PartialResourceList.Count,
+ TRUE,
+ &Conflict);
+
+ //
+ // Check for conflict.
+ //
+ if (Conflict || (NtStatus != STATUS_SUCCESS))
+ {
+ if (Conflict)
+ {
+ //
+ // Log an error
+ //
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ ULONG StringSize;
+ PWCH baseFileName;
+
+ baseFileName = NewAdaptP->AdapterName.Buffer;
+
+ //
+ // Parse out the path name, leaving only the device name.
+ //
+ for (i = 0; i < NewAdaptP->AdapterName.Length / sizeof(WCHAR); i++)
+ {
+ //
+ // If s points to a directory separator, set baseFileName to
+ // the character after the separator.
+ //
+ if (NewAdaptP->AdapterName.Buffer[i] == OBJ_NAME_PATH_SEPARATOR)
+ {
+ baseFileName = &(NewAdaptP->AdapterName.Buffer[++i]);
+ }
+ }
+
+ StringSize = NewAdaptP->AdapterName.MaximumLength -
+ (((ULONG)baseFileName) - ((ULONG)NewAdaptP->AdapterName.Buffer)) ;
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(TmpDeviceP,
+ (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) + StringSize));
+
+ if (errorLogEntry != NULL)
+ {
+ errorLogEntry->ErrorCode = EVENT_NDIS_IO_PORT_CONFLICT;
+
+ //
+ // store the time
+ //
+ errorLogEntry->MajorFunctionCode = 0;
+ errorLogEntry->RetryCount = 0;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = 0;
+ errorLogEntry->SequenceNumber = 0;
+ errorLogEntry->IoControlCode = 0;
+
+ //
+ // Set string information
+ //
+ if (StringSize != 0)
+ {
+ errorLogEntry->NumberOfStrings = 1;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+
+ CopyMemory (((PUCHAR)errorLogEntry) + sizeof(IO_ERROR_LOG_PACKET),
+ (PVOID)baseFileName,
+ StringSize);
+ }
+ else
+ {
+ errorLogEntry->NumberOfStrings = 0;
+ }
+
+ //
+ // write it out
+ //
+ IoWriteErrorLogEntry(errorLogEntry);
+ }
+
+ Status = NDIS_STATUS_RESOURCE_CONFLICT;
+ break;
+ }
+
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // If port mapping is needed, we do that. If the result
+ // is in memory, we have to map it. We map only the
+ // ports specified in AdapterInformation; the default
+ // is to map the first 4K.
+ //
+ // Note that NumberOfPorts can only be 0 if AdapterInfo
+ // is provided and explicitly sets it to 0, so in that
+ // case it is OK to leave the adapter in a state where
+ // a call to NdisXXXPort will probably crash (because
+ // PortOffset will be undefined).
+ //
+ if (NewAdaptP->NumberOfPorts > 0)
+ {
+ if (AllocateIndividualPorts)
+ {
+ Status = NDIS_STATUS_SUCCESS;
+
+ //
+ // We get here if we are supposed to allocate ports on an
+ // individual bases -- which implies that the driver will
+ // be using the Raw functions.
+ //
+ // Get the system physical address for this card. The card uses
+ // I/O space, except for "internal" Jazz devices which use
+ // memory space.
+ //
+
+ for (i = 0; i < AdapterInfo->NumberOfPortDescriptors; i++)
+ {
+ addressSpace = (NewAdaptP->AdapterType == NdisInterfaceInternal) ? 0 : 1;
+
+ InitialPortAddress.LowPart = AdapterInfo->PortDescriptors[i].InitialPort;
+ InitialPortAddress.HighPart = 0;
+
+ if (!HalTranslateBusAddress(NewAdaptP->BusType, // InterfaceType
+ NewAdaptP->BusNumber, // BusNumber
+ InitialPortAddress, // Bus Address
+ &addressSpace, // AddressSpace
+ &PortAddress)) // Translated address
+ {
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ if (addressSpace == 0)
+ {
+ //
+ // memory space
+ //
+ *(AdapterInfo->PortDescriptors[i].PortOffset) =
+ MmMapIoSpace(PortAddress,
+ AdapterInfo->PortDescriptors[i].NumberOfPorts,
+ FALSE);
+
+ if (*(AdapterInfo->PortDescriptors[i].PortOffset) == NULL)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+ }
+ else
+ {
+ //
+ // I/O space
+ //
+ *(AdapterInfo->PortDescriptors[i].PortOffset) = (PUCHAR)PortAddress.LowPart;
+ }
+ }
+ if (!NT_SUCCESS(Status))
+ break;
+ }
+ else
+ {
+ //
+ // The driver will not use the Raw functions, only the
+ // old NdisRead and NdisWrite port functions.
+ //
+ // Get the system physical address for this card. The card uses
+ // I/O space, except for "internal" Jazz devices which use
+ // memory space.
+ //
+ addressSpace = (NewAdaptP->AdapterType == NdisInterfaceInternal) ? 0 : 1;
+ InitialPortAddress.LowPart = NewAdaptP->InitialPort;
+ InitialPortAddress.HighPart = 0;
+ if (!HalTranslateBusAddress(NewAdaptP->BusType, // InterfaceType
+ NewAdaptP->BusNumber, // BusNumber
+ InitialPortAddress, // Bus Address
+ &addressSpace, // AddressSpace
+ &PortAddress)) // Translated address
+ {
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ if (addressSpace == 0)
+ {
+ //
+ // memory space
+ //
+ NewAdaptP->InitialPortMapping = MmMapIoSpace(PortAddress,
+ NewAdaptP->NumberOfPorts,
+ FALSE);
+
+ if (NewAdaptP->InitialPortMapping == NULL)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ NewAdaptP->InitialPortMapped = TRUE;
+ }
+ else
+ {
+ //
+ // I/O space
+ //
+ NewAdaptP->InitialPortMapping = (PUCHAR)PortAddress.LowPart;
+ NewAdaptP->InitialPortMapped = FALSE;
+ }
+
+ //
+ // PortOffset holds the mapped address of port 0.
+ //
+
+ NewAdaptP->PortOffset = NewAdaptP->InitialPortMapping - NewAdaptP->InitialPort;
+ }
+ }
+ else
+ {
+ //
+ // Technically should not allow this, but do it until
+ // all drivers register their info correctly.
+ //
+ NewAdaptP->PortOffset = 0;
+ }
+ }
+
+ //
+ // If the driver want to be called back now, use
+ // supplied callback routine.
+ //
+ if ((AdapterInfo != NULL) && (AdapterInfo->ActivateCallback != NULL))
+ {
+ Status = (*(AdapterInfo->ActivateCallback))((NDIS_HANDLE)NewAdaptP,
+ MacAdapterContext,
+ AdapterInfo->DmaChannel);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+ }
+
+ //
+ // Set information from AdapterInformation. The call back
+ // routine can set these values.
+ //
+ NewAdaptP->ChannelNumber = AdapterInfo->DmaChannel;
+ NewAdaptP->PhysicalMapRegistersNeeded = AdapterInfo->PhysicalMapRegistersNeeded;
+ NewAdaptP->MaximumPhysicalMapping = AdapterInfo->MaximumPhysicalMapping;
+
+ //
+ // Check for resource conflic on DmaChannel.
+ //
+ if (NewAdaptP->Master && ValidBus && (NewAdaptP->AdapterType == NdisInterfaceIsa))
+ {
+ //
+ // Put the DMA channel in the resource list.
+ //
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Type =
+ CmResourceTypeDma;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].ShareDisposition =
+ CmResourceShareDeviceExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Flags =
+ 0;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Dma.Channel =
+ NewAdaptP->ChannelNumber;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Dma.Port =
+ 0;
+ Resources->List[0].PartialResourceList.Count++;
+
+ //
+ // Submit Resources
+ //
+ NtStatus = IoReportResourceUsage(NULL,
+ ((PNDIS_MAC_BLOCK)NdisMacHandle)->NdisMacInfo->NdisWrapperDriver,
+ NULL,
+ 0,
+ NewAdaptP->DeviceObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ Resources->List[0].PartialResourceList.Count,
+ TRUE,
+ &Conflict);
+
+ //
+ // Check for conflict.
+ //
+ if (Conflict || (NtStatus != STATUS_SUCCESS))
+ {
+ if (Conflict)
+ {
+ //
+ // Log an error
+ //
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ ULONG StringSize;
+ PWCH baseFileName;
+
+ baseFileName = NewAdaptP->AdapterName.Buffer;
+
+ //
+ // Parse out the path name, leaving only the device name.
+ //
+ for (i = 0; i < NewAdaptP->AdapterName.Length / sizeof(WCHAR); i++)
+ {
+ //
+ // If s points to a directory separator, set baseFileName to
+ // the character after the separator.
+ //
+ if (NewAdaptP->AdapterName.Buffer[i] == OBJ_NAME_PATH_SEPARATOR)
+ {
+ baseFileName = &(NewAdaptP->AdapterName.Buffer[++i]);
+ }
+ }
+
+ StringSize = NewAdaptP->AdapterName.MaximumLength -
+ (((ULONG)baseFileName) - ((ULONG)NewAdaptP->AdapterName.Buffer)) ;
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(TmpDeviceP,
+ (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) + StringSize));
+
+ if (errorLogEntry != NULL)
+ {
+ if ((NewAdaptP->Master) &&
+ (NewAdaptP->AdapterType == Isa))
+ {
+ errorLogEntry->ErrorCode = EVENT_NDIS_PORT_OR_DMA_CONFLICT;
+ }
+ else
+ {
+ errorLogEntry->ErrorCode = EVENT_NDIS_IO_PORT_CONFLICT;
+ }
+
+ //
+ // store the time
+ //
+ errorLogEntry->MajorFunctionCode = 0;
+ errorLogEntry->RetryCount = 0;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = 0;
+ errorLogEntry->SequenceNumber = 0;
+ errorLogEntry->IoControlCode = 0;
+
+ //
+ // Set string information
+ //
+ if (StringSize != 0)
+ {
+ errorLogEntry->NumberOfStrings = 1;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+
+ CopyMemory (((PUCHAR)errorLogEntry) + sizeof(IO_ERROR_LOG_PACKET),
+ (PVOID)baseFileName,
+ StringSize);
+ }
+ else
+ {
+ errorLogEntry->NumberOfStrings = 0;
+ }
+
+ //
+ // write it out
+ //
+ IoWriteErrorLogEntry(errorLogEntry);
+ }
+
+ Status = NDIS_STATUS_RESOURCE_CONFLICT;
+ break;
+ }
+
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+ }
+
+ //
+ // If the device is a busmaster, we get an adapter
+ // object for it.
+ // If map registers are needed, we loop, allocating an
+ // adapter channel for each map register needed.
+ //
+
+ if ((NewAdaptP->Master) && ValidBus)
+ {
+ //
+ // This is needed by HalGetAdapter.
+ //
+ DEVICE_DESCRIPTION DeviceDescription;
+
+ //
+ // Returned by HalGetAdapter.
+ //
+ ULONG MapRegistersAllowed;
+
+ //
+ // Returned by HalGetAdapter.
+ //
+ PADAPTER_OBJECT AdapterObject;
+
+ //
+ // Map registers needed per channel.
+ //
+ ULONG MapRegistersPerChannel;
+
+ NTSTATUS Status;
+
+ //
+ // Allocate storage for holding the appropriate
+ // information for each map register.
+ //
+ NewAdaptP->MapRegisters = (PMAP_REGISTER_ENTRY)ALLOC_FROM_POOL(sizeof(MAP_REGISTER_ENTRY) *
+ NewAdaptP->PhysicalMapRegistersNeeded,
+ NDIS_TAG_MAP_REG);
+
+ if (NewAdaptP->MapRegisters == (PMAP_REGISTER_ENTRY)NULL)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ //
+ // Use this event to tell us when ndisAllocationExecutionRoutine
+ // has been called.
+ //
+ INITIALIZE_EVENT(&NewAdaptP->AllocationEvent);
+
+ //
+ // Set up the device description; zero it out in case its
+ // size changes.
+ //
+ ZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
+
+ DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
+ DeviceDescription.Master = TRUE;
+ DeviceDescription.ScatterGather = TRUE;
+
+ DeviceDescription.BusNumber = NewAdaptP->BusNumber;
+ DeviceDescription.DmaChannel = NewAdaptP->ChannelNumber;
+ DeviceDescription.InterfaceType = NewAdaptP->AdapterType;
+
+ if (DeviceDescription.InterfaceType == NdisInterfaceIsa)
+ {
+ //
+ // For ISA devices, the width is based on the DMA channel:
+ // 0-3 == 8 bits, 5-7 == 16 bits. Timing is compatibility
+ // mode.
+ //
+ if (NewAdaptP->ChannelNumber > 4)
+ {
+ DeviceDescription.DmaWidth = Width16Bits;
+ }
+ else
+ {
+ DeviceDescription.DmaWidth = Width8Bits;
+ }
+ DeviceDescription.DmaSpeed = Compatible;
+ }
+ else if ((DeviceDescription.InterfaceType == NdisInterfaceMca) ||
+ (DeviceDescription.InterfaceType == NdisInterfaceEisa) ||
+ (DeviceDescription.InterfaceType == NdisInterfacePci))
+ {
+ DeviceDescription.Dma32BitAddresses = AdapterInfo->Dma32BitAddresses;
+ DeviceDescription.DmaPort = 0;
+ }
+
+ DeviceDescription.MaximumLength = NewAdaptP->MaximumPhysicalMapping;
+
+
+ //
+ // Determine how many map registers we need per channel.
+ //
+ MapRegistersPerChannel =
+ ((NewAdaptP->MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2;
+
+ //
+ // Get the adapter object.
+ //
+ AdapterObject = HalGetAdapter (&DeviceDescription, &MapRegistersAllowed);
+
+ if (AdapterObject == NULL)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ ASSERT (MapRegistersAllowed >= MapRegistersPerChannel);
+
+ //
+ // We save this to call IoFreeMapRegisters later.
+ //
+ NewAdaptP->SystemAdapterObject = AdapterObject;
+
+
+ //
+ // Now loop, allocating an adapter channel each time, then
+ // freeing everything but the map registers.
+ //
+ for (i=0; i<NewAdaptP->PhysicalMapRegistersNeeded; i++)
+ {
+ NewAdaptP->CurrentMapRegister = i;
+
+ RAISE_IRQL_TO_DISPATCH(&OldIrql);
+
+ Status = IoAllocateAdapterChannel(AdapterObject,
+ NewAdaptP->DeviceObject,
+ MapRegistersPerChannel,
+ ndisAllocationExecutionRoutine,
+ (PVOID)NewAdaptP);
+ if (!NT_SUCCESS(Status))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("Failed to load driver because of\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("insufficient map registers.\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("AllocateAdapterChannel: %lx\n", Status));
+
+ FREE_POOL(Resources);
+
+ for (; i != 0; i--)
+ {
+ IoFreeMapRegisters(NewAdaptP->SystemAdapterObject,
+ NewAdaptP->MapRegisters[i-1].MapRegister,
+ MapRegistersPerChannel);
+ }
+
+ LOWER_IRQL(OldIrql);
+
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ LOWER_IRQL(OldIrql);
+
+ TimeoutValue.QuadPart = Int32x32To64(10 * 1000, -10000);
+
+ //
+ // ndisAllocationExecutionRoutine will set this event
+ // when it has gotten FirstTranslationEntry.
+ //
+ NtStatus = WAIT_FOR_OBJECT(&NewAdaptP->AllocationEvent, &TimeoutValue);
+
+ if (NtStatus != STATUS_SUCCESS)
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus));
+ FREE_POOL(Resources);
+
+ RAISE_IRQL_TO_DISPATCH(&OldIrql);
+
+ for (; i != 0; i--)
+ {
+ IoFreeMapRegisters(NewAdaptP->SystemAdapterObject,
+ NewAdaptP->MapRegisters[i-1].MapRegister,
+ MapRegistersPerChannel);
+ }
+
+ LOWER_IRQL(OldIrql);
+
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ RESET_EVENT(&NewAdaptP->AllocationEvent);
+ }
+
+ if (!NT_SUCCESS(Status))
+ break;
+ }
+
+ NdisInitializeRef(&NewAdaptP->Ref);
+
+ if (!ndisQueueAdapterOnMac(NewAdaptP, TmpMacP))
+ {
+ //
+ // The MAC is closing, undo what we have done.
+ //
+ if (NewAdaptP->Master)
+ {
+ ULONG MapRegistersPerChannel =
+ ((NewAdaptP->MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2;
+
+ for (i=0; i<NewAdaptP->PhysicalMapRegistersNeeded; i++)
+ {
+ RAISE_IRQL_TO_DISPATCH(&OldIrql);
+
+ IoFreeMapRegisters(NewAdaptP->SystemAdapterObject,
+ NewAdaptP->MapRegisters[i].MapRegister,
+ MapRegistersPerChannel);
+
+ LOWER_IRQL(OldIrql);
+ }
+ }
+ Status = NDIS_STATUS_CLOSING;
+ break;
+ }
+
+ //
+ // Add an extra reference because the wrapper is using the MAC
+ //
+ ndisReferenceAdapter(NewAdaptP);
+ MacReferencePackage();
+
+ *NdisAdapterHandle = (NDIS_HANDLE)NewAdaptP;
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisRegisterAdapter\n"));
+ } while (FALSE);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisRegisterAdapter\n"));
+
+ if (NewAdaptP != NULL)
+ {
+ NdisWriteErrorLogEntry(NewAdaptP,
+ Status,
+ 0);
+ }
+ if (DerefMacOnError)
+ {
+ ndisDereferenceMac(TmpMacP);
+ }
+ if (NdisAdapterName.Buffer != NULL)
+ {
+ FREE_POOL(NdisAdapterName.Buffer);
+ }
+ if (TmpDeviceP != NULL)
+ {
+ IoDeleteDevice(TmpDeviceP);
+ if (NewAdaptP->MapRegisters != NULL)
+ {
+ FREE_POOL(NewAdaptP->MapRegisters);
+ }
+ if (Resources != NULL)
+ {
+ FREE_POOL(Resources);
+ }
+ }
+ }
+
+ return Status;
+}
+
+
+NDIS_STATUS
+NdisDeregisterAdapter(
+ IN NDIS_HANDLE NdisAdapterHandle
+ )
+/*++
+
+Routine Description:
+
+ Deregisters an NDIS adapter.
+
+Arguments:
+
+ NdisAdapterHandle - The handle returned by NdisRegisterAdapter.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS.
+
+--*/
+{
+ //
+ // KillAdapter does all the work.
+ //
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisDeregisterAdapter\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ (" Deregistering Adapter %s\n",
+ ((PNDIS_ADAPTER_BLOCK)NdisAdapterHandle)->AdapterName.Buffer));
+
+ IF_DBG(DBG_COMP_CONFIG, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(NdisAdapterHandle))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("DeregisterAdapter: Null Handle\n"));
+ DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(NdisAdapterHandle))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("DeregisterAdapter: Handle not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR);
+ }
+ }
+ ndisKillAdapter((PNDIS_ADAPTER_BLOCK)NdisAdapterHandle);
+
+ //
+ // Remove reference from wrapper
+ //
+ ndisDereferenceAdapter((PNDIS_ADAPTER_BLOCK)NdisAdapterHandle);
+
+ MacDereferencePackage();
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisDeregisterAdapter\n"));
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+VOID
+NdisRegisterAdapterShutdownHandler(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN PVOID ShutdownContext,
+ IN ADAPTER_SHUTDOWN_HANDLER ShutdownHandler
+ )
+/*++
+
+Routine Description:
+
+ Registers an NDIS adapter.
+
+Arguments:
+
+ NdisAdapterHandle - The handle returned by NdisRegisterAdapter.
+
+ ShutdownContext - Context to pass the the handler, when called.
+
+ ShutdownHandler - The Handler for the Adapter, to be called on shutdown.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS.
+
+--*/
+{
+ PNDIS_ADAPTER_BLOCK Adapter = (PNDIS_ADAPTER_BLOCK) NdisAdapterHandle;
+ PNDIS_WRAPPER_CONTEXT WrapperContext = Adapter->WrapperContext;
+
+ if (WrapperContext->ShutdownHandler == NULL)
+ {
+ //
+ // Store information
+ //
+
+ WrapperContext->ShutdownHandler = ShutdownHandler;
+ WrapperContext->ShutdownContext = ShutdownContext;
+
+ //
+ // Register our shutdown handler for either a system shutdown
+ // notification or a bugcheck.
+ //
+
+ IoRegisterShutdownNotification(Adapter->DeviceObject);
+
+ KeInitializeCallbackRecord(&WrapperContext->BugcheckCallbackRecord);
+
+ KeRegisterBugCheckCallback(
+ &WrapperContext->BugcheckCallbackRecord,// callback record.
+ (PVOID) ndisBugcheckHandler, // callback routine.
+ (PVOID) WrapperContext, // free form buffer.
+ sizeof(NDIS_WRAPPER_CONTEXT), // buffer size.
+ "Ndis mac"); // component id.
+ }
+}
+
+
+VOID
+NdisDeregisterAdapterShutdownHandler(
+ IN NDIS_HANDLE NdisAdapterHandle
+ )
+/*++
+
+Routine Description:
+
+ Deregisters an NDIS adapter.
+
+Arguments:
+
+ NdisAdapterHandle - The handle returned by NdisRegisterAdapter.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS.
+
+--*/
+{
+ PNDIS_ADAPTER_BLOCK Adapter = (PNDIS_ADAPTER_BLOCK) NdisAdapterHandle;
+ PNDIS_WRAPPER_CONTEXT WrapperContext = Adapter->WrapperContext;
+
+ if (WrapperContext->ShutdownHandler != NULL)
+ {
+ //
+ // Clear information
+ //
+
+ WrapperContext->ShutdownHandler = NULL;
+
+ IoUnregisterShutdownNotification(Adapter->DeviceObject);
+
+ KeDeregisterBugCheckCallback(&WrapperContext->BugcheckCallbackRecord);
+ }
+}
+
+
+NDIS_STATUS
+NdisPciAssignResources(
+ IN NDIS_HANDLE NdisMacHandle,
+ IN NDIS_HANDLE NdisWrapperHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SlotNumber,
+ OUT PNDIS_RESOURCE_LIST * AssignedResources
+ )
+/*++
+
+Routine Description:
+
+ This routine uses the Hal to assign a set of resources to a PCI
+ device.
+
+Arguments:
+
+ NdisMacHandle - Handle returned from NdisRegisterMac.
+
+ NdisWrapperHandle - Handle returned from NdisInitializeWrapper.
+
+ WrapperConfigurationContext - Handle passed to MacAddAdapter.
+
+ SlotNumber - Slot number of the device.
+
+ AssignedResources - The returned resources.
+
+Return Value:
+
+ Status of the operation
+
+--*/
+{
+ NTSTATUS NdisStatus = NDIS_STATUS_FAILURE;
+ NTSTATUS NtStatus;
+ ULONG BusNumber;
+ NDIS_INTERFACE_TYPE BusType;
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable;
+ PCM_RESOURCE_LIST AllocatedResources = NULL;
+ PNDIS_WRAPPER_HANDLE NdisMacInfo = (PNDIS_WRAPPER_HANDLE)NdisWrapperHandle;
+
+ //
+ // Get the BusNumber and the BusType from the Context here!!
+ //
+ KeyQueryTable = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->ParametersQueryTable;
+
+ BusType = (NDIS_INTERFACE_TYPE)KeyQueryTable[3].DefaultType;
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ NtStatus = HalAssignSlotResources((PUNICODE_STRING)(NdisMacInfo->NdisWrapperConfigurationHandle),
+ NULL,
+ NdisMacInfo->NdisWrapperDriver,
+ NULL,
+ BusType,
+ BusNumber,
+ SlotNumber,
+ &AllocatedResources);
+
+ *AssignedResources = NULL; // Assume failure
+ if (NtStatus == STATUS_SUCCESS)
+ {
+ //
+ // Store resources into the driver wide block
+ //
+ ((PNDIS_MAC_BLOCK)NdisMacHandle)->PciAssignedResources = AllocatedResources;
+
+ *AssignedResources = &(AllocatedResources->List[0].PartialResourceList);
+
+ //
+ // Update slot number since the driver can also scan and so the one
+ // in the registry is probably invalid
+ //
+ KeyQueryTable[4].DefaultLength = SlotNumber;
+
+ NdisStatus = NDIS_STATUS_SUCCESS;
+ }
+
+ return NdisStatus;
+}
+
diff --git a/private/ntos/ndis/ndis40/configm.c b/private/ntos/ndis/ndis40/configm.c
new file mode 100644
index 000000000..b155d1a90
--- /dev/null
+++ b/private/ntos/ndis/ndis40/configm.c
@@ -0,0 +1,2077 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ configm.c
+
+Abstract:
+
+ NDIS wrapper functions for miniport configuration/initialization
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 05-Oct-93
+ Jameel Hyder (JameelH) 01-Jun-95
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_CONFIGM
+
+
+NDIS_STATUS
+NdisMRegisterMiniport(
+ IN NDIS_HANDLE NdisWrapperHandle,
+ IN PNDIS_MINIPORT_CHARACTERISTICS MiniportCharacteristics,
+ IN UINT CharacteristicsLength
+ )
+
+/*++
+
+Routine Description:
+
+ Used to register a Miniport driver with the wrapper.
+
+Arguments:
+
+ Status - Status of the operation.
+
+ NdisWrapperHandle - Handle returned by NdisWInitializeWrapper.
+
+ MiniportCharacteritics - The NDIS_MINIPORT_CHARACTERISTICS table.
+
+ CharacteristicsLength - The length of MiniportCharacteristics.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS Status;
+ PNDIS_M_DRIVER_BLOCK MiniBlock;
+ PNDIS_WRAPPER_HANDLE DriverInfo = (PNDIS_WRAPPER_HANDLE)(NdisWrapperHandle);
+
+ Status = NdisIMRegisterLayeredMiniport(NdisWrapperHandle,
+ MiniportCharacteristics,
+ CharacteristicsLength,
+ &MiniBlock);
+
+ DBGPRINT(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
+ ("Exit mini-port register\n"));
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ InitReferencePackage();
+ if (DriverInfo->NdisWrapperConfigurationHandle)
+ {
+ Status = ndisInitializeAllAdapterInstances((PNDIS_MAC_BLOCK)MiniBlock, NULL);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ ndisDereferenceDriver(MiniBlock);
+ Status = NDIS_STATUS_FAILURE;
+ }
+ }
+ else
+ {
+ Status = NDIS_STATUS_FAILURE;
+ }
+ InitDereferencePackage();
+ }
+
+ ASSERT (CURRENT_IRQL < DISPATCH_LEVEL);
+
+ return Status;
+}
+
+NDIS_STATUS
+NdisIMRegisterLayeredMiniport(
+ IN NDIS_HANDLE NdisWrapperHandle,
+ IN PNDIS_MINIPORT_CHARACTERISTICS MiniportCharacteristics,
+ IN UINT CharacteristicsLength,
+ OUT PNDIS_HANDLE DriverHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Used to register a layered Miniport driver with the wrapper.
+
+Arguments:
+
+ Status - Status of the operation.
+
+ NdisWrapperHandle - Handle returned by NdisWInitializeWrapper.
+
+ MiniportCharacteritics - The NDIS_MINIPORT_CHARACTERISTICS table.
+
+ CharacteristicsLength - The length of MiniportCharacteristics.
+
+ DriverHandle - Returns a handle which can be used to call NdisMInitializeDeviceInstance.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_M_DRIVER_BLOCK MiniBlock;
+ PNDIS_WRAPPER_HANDLE DriverInfo = (PNDIS_WRAPPER_HANDLE)(NdisWrapperHandle);
+ UNICODE_STRING Us;
+ PWSTR pWch;
+ USHORT i, size;
+ UINT MemNeeded;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+
+ DBGPRINT(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
+ ("Enter mini-port register\n"));
+
+ do
+ {
+ if (DriverInfo == NULL)
+ {
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // Check version numbers and CharacteristicsLength.
+ //
+
+ size = 0; // Used to indicate bad version below
+ if (MiniportCharacteristics->MajorNdisVersion == 3)
+ {
+ if (MiniportCharacteristics->MinorNdisVersion == 0)
+ size = sizeof(NDIS30_MINIPORT_CHARACTERISTICS);
+ }
+
+ else if (MiniportCharacteristics->MajorNdisVersion == 4)
+ {
+ if (MiniportCharacteristics->MinorNdisVersion == 0)
+ {
+ size = sizeof(NDIS40_MINIPORT_CHARACTERISTICS);
+ }
+ else if (MiniportCharacteristics->MinorNdisVersion == 1)
+ {
+ size = sizeof(NDIS41_MINIPORT_CHARACTERISTICS);
+ }
+ }
+
+ //
+ // Check that this is an NDIS 3.0/4.0/4.1 miniport.
+ //
+ if (size == 0)
+ {
+ Status = NDIS_STATUS_BAD_VERSION;
+ break;
+ }
+
+ //
+ // Check that CharacteristicsLength is enough.
+ //
+ if (CharacteristicsLength < size)
+ {
+ Status = NDIS_STATUS_BAD_CHARACTERISTICS;
+ break;
+ }
+
+ //
+ // Allocate memory for the NDIS MINIPORT block.
+ //
+ MemNeeded = sizeof(NDIS_M_DRIVER_BLOCK);
+
+ //
+ // Extract the base-name, determine its length and allocate that much more
+ //
+ Us = *(PUNICODE_STRING)(DriverInfo->NdisWrapperConfigurationHandle);
+
+ for (i = Us.Length/sizeof(WCHAR), pWch = Us.Buffer + i - 1;
+ i > 0;
+ pWch --, i--)
+ {
+ if (*pWch == L'\\')
+ {
+ Us.Buffer = pWch + 1;
+ Us.Length -= i*sizeof(WCHAR);
+ Us.MaximumLength = Us.Length + sizeof(WCHAR);
+ break;
+ }
+ }
+ MemNeeded += Us.MaximumLength;
+
+ MiniBlock = (PNDIS_M_DRIVER_BLOCK)ALLOC_FROM_POOL(MemNeeded, NDIS_TAG_MINI_BLOCK);
+
+ if (MiniBlock == (PNDIS_M_DRIVER_BLOCK)NULL)
+ {
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ ZeroMemory(MiniBlock, MemNeeded);
+
+ MiniBlock->Length = MemNeeded;
+
+ //
+ // Copy over the characteristics table.
+ //
+
+ CopyMemory(&MiniBlock->MiniportCharacteristics,
+ MiniportCharacteristics,
+ size);
+
+ //
+ // Upcase the base-name and save it in the MiniBlock
+ //
+ MiniBlock->BaseName.Buffer = (PWSTR)((PUCHAR)MiniBlock + sizeof(NDIS_M_DRIVER_BLOCK));
+ MiniBlock->BaseName.Length =
+ MiniBlock->BaseName.MaximumLength = Us.Length;
+ RtlUpcaseUnicodeString(&MiniBlock->BaseName,
+ &Us,
+ FALSE);
+ //
+ // No adapters yet registered for this Miniport.
+ //
+
+ MiniBlock->MiniportQueue = (PNDIS_MINIPORT_BLOCK)NULL;
+
+ //
+ // Set up unload handler
+ //
+
+ DriverInfo->NdisWrapperDriver->DriverUnload = ndisMUnload;
+
+ //
+ // Set up shutdown handler
+ //
+ DriverInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_SHUTDOWN] = ndisMShutdown;
+
+ //
+ // Set up the handlers for this driver (they all do nothing).
+ //
+
+ DriverInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_CREATE] = ndisCreateIrpHandler;
+ DriverInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ndisDeviceControlIrpHandler;
+ DriverInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_CLEANUP] = ndisSuccessIrpHandler;
+ DriverInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_CLOSE] = ndisCloseIrpHandler;
+
+ //
+ // Use this event to tell us when all adapters are removed from the mac
+ // during an unload
+ //
+ INITIALIZE_EVENT(&MiniBlock->MiniportsRemovedEvent);
+
+ MiniBlock->Unloading = FALSE;
+ MiniBlock->NdisDriverInfo = DriverInfo;
+ MiniBlock->MiniportIdField = (NDIS_HANDLE)0x1;
+
+ NdisInitializeRef(&MiniBlock->Ref);
+
+ // Lock the init code down now - before we take the lock below
+ MiniportReferencePackage();
+
+ //
+ // Put Driver on global list.
+ //
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+
+ MiniBlock->NextDriver = ndisMiniDriverList;
+ ndisMiniDriverList = MiniBlock;
+
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ MiniportDereferencePackage();
+
+ *DriverHandle = MiniBlock;
+
+ Status = NDIS_STATUS_SUCCESS;
+ } while (FALSE);
+
+ return Status;
+}
+
+
+NDIS_STATUS
+NdisIMDeInitializeDeviceInstance(
+ IN NDIS_HANDLE NdisMiniportHandle
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport;
+ NDIS_STATUS Status = NDIS_STATUS_FAILURE;
+
+ Miniport = (PNDIS_MINIPORT_BLOCK)NdisMiniportHandle;
+
+ if (ndisReferenceMiniport(Miniport))
+ {
+ Status = ndisUnloadMiniport(Miniport);
+ ndisDereferenceMiniport(Miniport);
+ }
+
+ return Status;
+}
+
+VOID
+ndisMOpenAdapter(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PNDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE NdisProtocolHandle,
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_STRING AdapterName,
+ IN UINT OpenOptions,
+ IN PSTRING AddressingInformation,
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_OPEN_BLOCK NewOpenP,
+ IN PFILE_OBJECT FileObject,
+ IN BOOLEAN UsingEncapsulation
+ )
+/*++
+
+Routine Description:
+
+ This routine handles opening a miniport either directly from NdisOpenAdapter()
+ of from our deferred processing routine if the open had to pend.
+
+ NOTE: Must be called with spin lock held.
+ NOTE: Must be called with lock acquired flag set.
+
+Arguments:
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_M_OPEN_BLOCK MiniportOpen;
+ PNDIS_MAC_BLOCK FakeMac;
+ BOOLEAN FilterOpen;
+ PNDIS_PROTOCOL_BLOCK TmpProtP;
+ BOOLEAN DerefMini = FALSE, FreeOpen = FALSE,
+ DerefProt = FALSE;
+
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ do
+ {
+ if (!ndisReferenceMiniport(Miniport))
+ {
+ //
+ // The adapter is closing.
+ //
+ *Status = NDIS_STATUS_CLOSING;
+ break;
+ }
+ DerefMini = TRUE;
+
+ //
+ // Increment the protocol's reference count.
+ //
+ TmpProtP = (PNDIS_PROTOCOL_BLOCK)NdisProtocolHandle;
+
+ if (!ndisReferenceProtocol(TmpProtP))
+ {
+ //
+ // The protocol is closing.
+ //
+ *Status = NDIS_STATUS_CLOSING;
+ break;
+ }
+ DerefProt = TRUE;
+
+ //
+ // Now allocate a complete set of MAC structures for the protocol
+ // and set them up to transfer to the Miniport handler routines.
+ //
+ if (Miniport->FakeMac == NULL)
+ {
+ //
+ // Allocate a fake MAC block for the characteristics.
+ //
+ FakeMac = (PNDIS_MAC_BLOCK)ALLOC_FROM_POOL(sizeof(NDIS_MAC_BLOCK), NDIS_TAG_DEFAULT);
+ if (FakeMac == NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ //
+ // Initialize the fake mac block.
+ //
+ ZeroMemory(FakeMac, sizeof(NDIS_MAC_BLOCK));
+
+ //
+ // Save the fake mac block with the miniport.
+ //
+ Miniport->FakeMac = FakeMac;
+
+ //
+ // If transfer data calls don't pend then we'll use the faster
+ // ndisMTransferDataSync().
+ //
+ if ((Miniport->MacOptions & NDIS_MAC_OPTION_TRANSFERS_NOT_PEND) != 0)
+ {
+ FakeMac->MacCharacteristics.TransferDataHandler = ndisMTransferDataSync;
+ }
+ else
+ {
+ FakeMac->MacCharacteristics.TransferDataHandler = ndisMTransferData;
+ }
+
+ //
+ // Initialize the reset handler.
+ //
+ FakeMac->MacCharacteristics.ResetHandler = ndisMReset;
+
+ //
+ // Initialize the request handler.
+ //
+ FakeMac->MacCharacteristics.RequestHandler = ndisMRequest;
+
+ //
+ // Initialize the send handler.
+ //
+ switch (Miniport->MediaType)
+ {
+ case NdisMediumArcnet878_2:
+
+ FakeMac->MacCharacteristics.SendHandler = ndisMArcnetSend;
+ break;
+
+ case NdisMediumWan:
+
+ FakeMac->MacCharacteristics.SendHandler = (PVOID)ndisMWanSend;
+ break;
+
+ default:
+ //
+ // If this is a fullduplex miniport then change the reset handler.
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ FakeMac->MacCharacteristics.ResetHandler = ndisMResetFullDuplex;
+ }
+
+ //
+ // Set up the send packet handlers miniports that support
+ // the new NDIS 4.0 SendPackets handler.
+ //
+ if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_PACKET_ARRAY))
+ {
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Using ndisMSendFullDuplexToSendPackets\n"));
+ FakeMac->MacCharacteristics.SendHandler = ndisMSendFullDuplexToSendPackets;
+ }
+ else
+ {
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Using ndisMSendToSendPackets\n"));
+ FakeMac->MacCharacteristics.SendHandler = ndisMSendToSendPackets;
+ }
+ }
+ else
+ {
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Using ndisMSendFullDuplex\n"));
+ FakeMac->MacCharacteristics.SendHandler = ndisMSendFullDuplex;
+ }
+ else
+ {
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Using ndisMSend\n"));
+ FakeMac->MacCharacteristics.SendHandler = ndisMSend;
+ }
+ }
+ break;
+ }
+
+ //
+ // If the miniport indicates packets the we have a dummy
+ // transfer data.
+ //
+ if (Miniport->DriverHandle->MiniportCharacteristics.ReturnPacketHandler != NULL)
+ {
+ // This driver supports the receive packet paradigm
+ // Fake the transferdata handler so if any xport calls
+ // this, we're still ok
+ FakeMac->MacCharacteristics.TransferDataHandler = ndisMDummyTransferData;
+ }
+ }
+ else
+ {
+ FakeMac = Miniport->FakeMac;
+ }
+
+ //
+ // Allocate an open within the Miniport context
+ //
+ MiniportOpen = (PNDIS_M_OPEN_BLOCK)ALLOC_FROM_POOL(sizeof(NDIS_M_OPEN_BLOCK), NDIS_TAG_DEFAULT);
+ if (MiniportOpen == (PNDIS_M_OPEN_BLOCK)NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ FreeOpen = TRUE;
+
+ //
+ // Initialize the open block.
+ //
+ ZeroMemory(MiniportOpen, sizeof(NDIS_M_OPEN_BLOCK));
+
+ MiniportOpen->DriverHandle = Miniport->DriverHandle;
+ MiniportOpen->MiniportHandle = Miniport;
+ MiniportOpen->ProtocolHandle = TmpProtP;
+ MiniportOpen->FakeOpen = NewOpenP;
+ MiniportOpen->ProtocolBindingContext = ProtocolBindingContext;
+ MiniportOpen->MiniportAdapterContext = Miniport->MiniportAdapterContext;
+ MiniportOpen->FileObject = FileObject;
+ MiniportOpen->CurrentLookahead = Miniport->CurrentLookahead;
+
+ NdisAllocateSpinLock(&(MiniportOpen->SpinLock));
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO, ("=1 0x%x\n", MiniportOpen));
+
+ MiniportOpen->References = 1;
+
+ if (UsingEncapsulation)
+ {
+ MINIPORT_SET_FLAG(MiniportOpen, fMINIPORT_OPEN_USING_ETH_ENCAPSULATION);
+ }
+
+ //
+ // Save the handlers with the open block.
+ //
+ MiniportOpen->SendHandler = Miniport->DriverHandle->MiniportCharacteristics.SendHandler;
+ MiniportOpen->TransferDataHandler = Miniport->DriverHandle->MiniportCharacteristics.TransferDataHandler;
+ MiniportOpen->SendCompleteHandler = TmpProtP->ProtocolCharacteristics.SendCompleteHandler;
+ MiniportOpen->TransferDataCompleteHandler = TmpProtP->ProtocolCharacteristics.TransferDataCompleteHandler;
+ MiniportOpen->ReceiveHandler = TmpProtP->ProtocolCharacteristics.ReceiveHandler;
+ MiniportOpen->ReceiveCompleteHandler = TmpProtP->ProtocolCharacteristics.ReceiveCompleteHandler;
+
+ //
+ // NDIS 4.0 miniport extensions
+ //
+ MiniportOpen->SendPacketsHandler = Miniport->DriverHandle->MiniportCharacteristics.SendPacketsHandler;
+
+ //
+ // NDIS 4.0 protocol extensions
+ //
+ MiniportOpen->ReceivePacketHandler =
+ (Miniport->DriverHandle->MiniportCharacteristics.ReturnPacketHandler == NULL) ?
+ NULL :
+ TmpProtP->ProtocolCharacteristics.ReceivePacketHandler;
+
+ //
+ // NDIS 4.1 miniport extensions
+ //
+ MiniportOpen->MiniportCoRequestHandler = Miniport->DriverHandle->MiniportCharacteristics.CoRequestHandler;
+ MiniportOpen->MiniportCoCreateVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoCreateVcHandler;
+
+ //
+ // NDIS 4.1 protocol extensions
+ //
+ MiniportOpen->CoRequestCompleteHandler =
+ TmpProtP->ProtocolCharacteristics.CoRequestCompleteHandler;
+
+ //
+ // initialize Lists
+ //
+ InitializeListHead(&MiniportOpen->ActiveVcHead);
+ InitializeListHead(&MiniportOpen->InactiveVcHead);
+
+ //
+ // Set up the elements of the open structure.
+ //
+ INITIALIZE_SPIN_LOCK(&NewOpenP->SpinLock);
+ NewOpenP->Closing = FALSE;
+
+ NewOpenP->AdapterHandle = (NDIS_HANDLE) Miniport;
+ NewOpenP->ProtocolHandle = TmpProtP;
+ NewOpenP->ProtocolBindingContext = ProtocolBindingContext;
+ NewOpenP->MacBindingHandle = (NDIS_HANDLE)MiniportOpen;
+
+ //
+ // for speed, instead of having to use AdapterHandle->MacHandle
+ //
+ NewOpenP->MacHandle = (NDIS_HANDLE)FakeMac;
+
+ //
+ // for even more speed...
+ //
+ if (NdisMediumArcnet878_2 == Miniport->MediaType)
+ {
+ NewOpenP->TransferDataHandler = ndisMArcTransferData;
+ }
+ else
+ {
+ NewOpenP->TransferDataHandler = FakeMac->MacCharacteristics.TransferDataHandler;
+ }
+
+ //
+ // Set the send handler in the open block.
+ //
+ NewOpenP->SendHandler = FakeMac->MacCharacteristics.SendHandler;
+ NewOpenP->RequestHandler = ndisMRequest;
+
+ //
+ // Set up the send packets handler.
+ //
+ if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_PACKET_ARRAY))
+ {
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Using ndisMSendPacketsFullDuplex\n"));
+ NewOpenP->SendPacketsHandler = ndisMSendPacketsFullDuplex;
+ }
+ else
+ {
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Using ndisMSendPackets\n"));
+ NewOpenP->SendPacketsHandler = ndisMSendPackets;
+ }
+ }
+ else
+ {
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Using ndisMSendPacketsFullDuplexToSend\n"));
+ NewOpenP->SendPacketsHandler = ndisMSendPacketsFullDuplexToSend;
+ }
+ else
+ {
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Using ndisMSendPacketsToSend\n"));
+ NewOpenP->SendPacketsHandler = ndisMSendPacketsToSend;
+ }
+ }
+
+ //
+ // For WAN miniports, the send handler is different.
+ //
+ if (NdisMediumWan == Miniport->MediaType)
+ {
+ NewOpenP->SendHandler = (PVOID)ndisMWanSend;
+ }
+ else if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
+ {
+ //
+ // the convential send function is not available for CO miniports
+ // since this send function does not specify the Vc to send upon
+ // However for components which want to use this let them.
+ //
+ if ((NewOpenP->SendHandler == NULL) && (NewOpenP->SendPacketsHandler == NULL))
+ {
+ NewOpenP->SendHandler = ndisMRejectSend;
+ FakeMac->MacCharacteristics.SendHandler = ndisMRejectSend;
+ }
+
+ //
+ // Trap the conventional request handlers if they are not specified.
+ //
+ if ((Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler == NULL) ||
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler == NULL))
+ {
+ FakeMac->MacCharacteristics.RequestHandler = ndisMWrappedRequest;
+ NewOpenP->RequestHandler = ndisMWrappedRequest;
+ }
+ }
+
+ NewOpenP->SendCompleteHandler = TmpProtP->ProtocolCharacteristics.SendCompleteHandler;
+ NewOpenP->TransferDataCompleteHandler = TmpProtP->ProtocolCharacteristics.TransferDataCompleteHandler;
+ NewOpenP->ReceiveHandler = TmpProtP->ProtocolCharacteristics.ReceiveHandler;
+ NewOpenP->ReceiveCompleteHandler = TmpProtP->ProtocolCharacteristics.ReceiveCompleteHandler;
+ NewOpenP->PostNt31ReceiveHandler = TmpProtP->ProtocolCharacteristics.ReceiveHandler;
+ NewOpenP->PostNt31ReceiveCompleteHandler = TmpProtP->ProtocolCharacteristics.ReceiveCompleteHandler;
+ NewOpenP->ResetHandler = ndisMReset;
+ NewOpenP->ReceivePacketHandler =
+ (Miniport->DriverHandle->MiniportCharacteristics.ReturnPacketHandler == NULL) ?
+ NULL :
+ TmpProtP->ProtocolCharacteristics.ReceivePacketHandler;
+
+ //
+ // Save a pointer to the file object in the open...
+ //
+ NewOpenP->FileObject = FileObject;
+
+ //
+ // ...and a pointer to the open in the file object.
+ //
+ FileObject->FsContext = NewOpenP;
+
+ *NdisBindingHandle = (NDIS_HANDLE)NewOpenP;
+
+ //
+ // Insert the open into the filter package
+ //
+ switch (Miniport->MediaType)
+ {
+ case NdisMediumArcnet878_2:
+
+ if (!UsingEncapsulation)
+ {
+ FilterOpen = ArcNoteFilterOpenAdapter(Miniport->ArcDB,
+ MiniportOpen,
+ (NDIS_HANDLE)NewOpenP,
+ &MiniportOpen->FilterHandle);
+ break;
+ }
+
+ //
+ // If we're using ethernet encapsulation then
+ // we simply fall through to the ethernet stuff.
+ //
+
+ case NdisMedium802_3:
+
+ FilterOpen = EthNoteFilterOpenAdapter(Miniport->EthDB,
+ MiniportOpen,
+ (NDIS_HANDLE)NewOpenP,
+ &MiniportOpen->FilterHandle);
+
+ break;
+
+ case NdisMedium802_5:
+
+ FilterOpen = TrNoteFilterOpenAdapter(Miniport->TrDB,
+ MiniportOpen,
+ (NDIS_HANDLE)NewOpenP,
+ &MiniportOpen->FilterHandle);
+
+ break;
+
+ case NdisMediumFddi:
+
+ FilterOpen = FddiNoteFilterOpenAdapter(Miniport->FddiDB,
+ MiniportOpen,
+ (NDIS_HANDLE)NewOpenP,
+ &MiniportOpen->FilterHandle);
+
+ break;
+
+
+ default:
+ //
+ // Bogus non-NULL value
+ //
+ FilterOpen = 1;
+ break;
+ }
+
+ //
+ // Check for an open filter failure.
+ //
+ if (!FilterOpen)
+ {
+ //
+ // Something went wrong, clean up and exit.
+ //
+ *Status = NDIS_STATUS_OPEN_FAILED;
+ break;
+ }
+
+ ndisQueueOpenOnProtocol(NewOpenP, TmpProtP);
+
+ //
+ // Everything has been filled in. Synchronize access to the
+ // adapter block and link the new open adapter in.
+ //
+ MiniportOpen->MiniportNextOpen = Miniport->OpenQueue;
+ Miniport->OpenQueue = MiniportOpen;
+
+ //
+ // If this is the first open on the adapter then fire the
+ // wake-up-dpc timer.
+ //
+ if (NULL == MiniportOpen->MiniportNextOpen)
+ {
+ //
+ // Start wake up timer
+ //
+ NdisMSetPeriodicTimer((PNDIS_MINIPORT_TIMER)(&Miniport->WakeUpDpcTimer),
+ Miniport->CheckForHangTimeout);
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+ } while (FALSE);
+
+ //
+ // Cleanup failure case
+ //
+ if (*Status != NDIS_STATUS_SUCCESS)
+ {
+ if (DerefMini)
+ {
+ ndisDereferenceMiniport(Miniport);
+ }
+ if (DerefProt)
+ {
+ ndisDereferenceProtocol(TmpProtP);
+ }
+ if (FreeOpen)
+ {
+ FREE_POOL(MiniportOpen);
+ }
+ ObDereferenceObject(FileObject);
+ FREE_POOL(NewOpenP);
+ }
+}
+
+NDIS_STATUS
+ndisMFinishPendingOpen(
+ IN PMINIPORT_PENDING_OPEN MiniportPendingOpen
+ )
+/*++
+
+Routine Description:
+
+ Handles any pending NdisOpenAdapter() calls for miniports.
+
+ NOTE: Must be called with spin lock held.
+
+ NOTE: Must be called with lock acquired flag set.
+
+Arguments:
+
+ Miniport.
+
+Return Value:
+
+ Returns the status code of the open.
+
+--*/
+
+{
+ //
+ // Do the open again.
+ //
+ ndisMOpenAdapter(&MiniportPendingOpen->Status,
+ &MiniportPendingOpen->OpenErrorStatus,
+ MiniportPendingOpen->NdisBindingHandle,
+ MiniportPendingOpen->NdisProtocolHandle,
+ MiniportPendingOpen->ProtocolBindingContext,
+ MiniportPendingOpen->AdapterName,
+ MiniportPendingOpen->OpenOptions,
+ MiniportPendingOpen->AddressingInformation,
+ MiniportPendingOpen->Miniport,
+ MiniportPendingOpen->NewOpenP,
+ MiniportPendingOpen->FileObject,
+ (BOOLEAN)(MINIPORT_TEST_FLAG(MiniportPendingOpen,
+ fPENDING_OPEN_USING_ENCAPSULATION) ? TRUE : FALSE));
+
+ //
+ // If the open didn't pend then call the NdisCompleteOpenAdapter(),
+ //
+ if (MiniportPendingOpen->Status != NDIS_STATUS_PENDING)
+ {
+ //
+ // Complete the open to the protocol in a worker thread since we want this
+ // to happen at passive irql.
+ //
+ INITIALIZE_WORK_ITEM(&MiniportPendingOpen->WorkItem,
+ ndisMFinishQueuedPendingOpen,
+ MiniportPendingOpen);
+ QUEUE_WORK_ITEM(&MiniportPendingOpen->WorkItem, HyperCriticalWorkQueue);
+ }
+
+ return(MiniportPendingOpen->Status);
+}
+
+VOID
+ndisMFinishQueuedPendingOpen(
+ IN PMINIPORT_PENDING_OPEN MiniportPendingOpen
+ )
+/*++
+
+Routine Description:
+
+ Handles any pending NdisOpenAdapter() calls for miniports.
+
+ NOTE: Must be called with spin lock held.
+
+ NOTE: Must be called with lock acquired flag set.
+
+Arguments:
+
+ Miniport.
+
+Return Value:
+
+ Returns the status code of the open.
+
+--*/
+
+{
+ PNDIS_OPEN_BLOCK OpenP = MiniportPendingOpen->NewOpenP;
+
+ (OpenP->ProtocolHandle->ProtocolCharacteristics.OpenAdapterCompleteHandler) (
+ OpenP->ProtocolBindingContext,
+ MiniportPendingOpen->Status,
+ MiniportPendingOpen->OpenErrorStatus);
+
+ //
+ // We're done with this pending open context.
+ //
+ NdisFreeMemory(MiniportPendingOpen, sizeof(MINIPORT_PENDING_OPEN), 0);
+}
+
+//
+// Io Port stuff
+//
+
+NDIS_STATUS
+NdisMRegisterIoPortRange(
+ OUT PVOID * PortOffset,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN UINT InitialPort,
+ IN UINT NumberOfPorts
+ )
+
+/*++
+
+Routine Description:
+
+ Sets up an IO port for operations.
+
+Arguments:
+
+ PortOffset - The mapped port address the Miniport uses for NdisRaw functions.
+
+ MiniportAdapterHandle - Handle passed to Miniport Initialize.
+
+ InitialPort - Physical address of the starting port number.
+
+ NumberOfPorts - Number of ports to map.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(MiniportAdapterHandle);
+ PHYSICAL_ADDRESS PortAddress;
+ PHYSICAL_ADDRESS InitialPortAddress;
+ ULONG addressSpace;
+ NDIS_STATUS Status;
+
+ CM_PARTIAL_RESOURCE_DESCRIPTOR Resource;
+
+ //
+ // First check if any bus access is allowed
+ //
+ if ((Miniport->BusType == (NDIS_INTERFACE_TYPE)-1) ||
+ (Miniport->BusNumber == (ULONG)-1))
+ {
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // Setup port
+ //
+ Resource.Type = CmResourceTypePort;
+ Resource.ShareDisposition = CmResourceShareDeviceExclusive;
+ Resource.Flags = (Miniport->AdapterType == NdisInterfaceInternal) ?
+ CM_RESOURCE_PORT_MEMORY : CM_RESOURCE_PORT_IO;
+ Resource.u.Port.Start.QuadPart = InitialPort;
+ Resource.u.Port.Length = NumberOfPorts;
+
+ //
+ // Add the new resource.
+ //
+ Status = ndisAddResource(
+ &Miniport->Resources,
+ &Resource,
+ Miniport->AdapterType,
+ Miniport->BusNumber,
+ Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver,
+ Miniport->DeviceObject,
+ &Miniport->MiniportName);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ return(Status);
+ }
+
+ //
+ // Now Map the ports
+ //
+
+ //
+ // Get the system physical address for this card. The card uses
+ // I/O space, except for "internal" Jazz devices which use
+ // memory space.
+ //
+ addressSpace = (Miniport->AdapterType == NdisInterfaceInternal) ? 0 : 1;
+
+ InitialPortAddress.LowPart = InitialPort;
+ InitialPortAddress.HighPart = 0;
+
+ if (!HalTranslateBusAddress(Miniport->BusType, // InterfaceType
+ Miniport->BusNumber, // BusNumber
+ InitialPortAddress, // Bus Address
+ &addressSpace, // AddressSpace
+ &PortAddress)) // Translated address
+ {
+ //
+ // It would be nice to return a better status here, but we only get
+ // TRUE/FALSE back from HalTranslateBusAddress.
+ //
+
+ return NDIS_STATUS_FAILURE;
+ }
+
+ if (addressSpace == 0)
+ {
+ //
+ // memory space
+ //
+
+ *(PortOffset) = (PULONG)MmMapIoSpace(PortAddress,
+ NumberOfPorts,
+ FALSE);
+
+ if (*(PortOffset) == (PULONG)NULL)
+ {
+ return NDIS_STATUS_RESOURCES;
+ }
+ }
+ else
+ {
+ //
+ // I/O space
+ //
+
+ *(PortOffset) = (PULONG)PortAddress.LowPart;
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+VOID
+NdisMDeregisterIoPortRange(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN UINT InitialPort,
+ IN UINT NumberOfPorts,
+ IN PVOID PortOffset
+ )
+
+/*++
+
+Routine Description:
+
+ Sets up an IO port for operations.
+
+Arguments:
+
+ MiniportAdapterHandle - Handle passed to Miniport Initialize.
+
+ InitialPort - Physical address of the starting port number.
+
+ NumberOfPorts - Number of ports to map.
+
+ PortOffset - The mapped port address the Miniport uses for NdisRaw functions.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(MiniportAdapterHandle);
+ PHYSICAL_ADDRESS PortAddress;
+ PHYSICAL_ADDRESS InitialPortAddress;
+ ULONG addressSpace;
+ CM_PARTIAL_RESOURCE_DESCRIPTOR Resource;
+ NDIS_STATUS Status;
+
+ //
+ // Get the system physical address for this card. The card uses
+ // I/O space, except for "internal" Jazz devices which use
+ // memory space.
+ //
+ addressSpace = (Miniport->AdapterType == NdisInterfaceInternal) ? 0 : 1;
+
+ InitialPortAddress.LowPart = InitialPort;
+ InitialPortAddress.HighPart = 0;
+
+ HalTranslateBusAddress(Miniport->BusType, // InterfaceType
+ Miniport->BusNumber, // BusNumber
+ InitialPortAddress, // Bus Address
+ &addressSpace, // AddressSpace
+ &PortAddress); // Translated address
+ if (addressSpace == 0)
+ {
+ //
+ // memory space
+ //
+ MmUnmapIoSpace(PortOffset, NumberOfPorts);
+ }
+
+ //
+ // Build the resource to remove.
+ //
+ Resource.Type = CmResourceTypePort;
+ Resource.ShareDisposition = CmResourceShareDeviceExclusive;
+ Resource.Flags = (Miniport->AdapterType == NdisInterfaceInternal) ?
+ CM_RESOURCE_PORT_MEMORY : CM_RESOURCE_PORT_IO;
+ Resource.u.Port.Start.QuadPart = InitialPort;
+ Resource.u.Port.Length = NumberOfPorts;
+
+ //
+ // Remove the resource.
+ //
+ Status = ndisRemoveResource(
+ &Miniport->Resources,
+ &Resource,
+ Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver,
+ Miniport->DeviceObject,
+ &Miniport->MiniportName);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DBGPRINT(DBG_COMP_UNLOAD, DBG_LEVEL_INFO,
+ ("NdisMDeregisterIoPortRange failed to remove the resource\n"));
+ }
+}
+
+
+//
+// Attribute functions
+//
+
+VOID
+NdisMSetAttributes(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN BOOLEAN BusMaster,
+ IN NDIS_INTERFACE_TYPE AdapterType
+ )
+/*++
+
+Routine Description:
+
+ This function sets specific information about an adapter.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+ MiniportAdapterContext - Context to pass to all Miniport driver functions.
+
+ BusMaster - TRUE if a bus mastering adapter.
+
+ AdapterType - Eisa, Isa, Mca or Internal.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+
+ Miniport->MiniportAdapterContext = MiniportAdapterContext;
+
+ if (BusMaster)
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_BUS_MASTER);
+
+ Miniport->AdapterType = AdapterType;
+
+ MiniportReferencePackage();
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
+ {
+ CoReferencePackage();
+ }
+}
+
+VOID
+NdisMSetAttributesEx(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN UINT CheckForHangTimeInSeconds OPTIONAL,
+ IN ULONG AttributeFlags,
+ IN NDIS_INTERFACE_TYPE AdapterType OPTIONAL
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+
+ Miniport->MiniportAdapterContext = MiniportAdapterContext;
+
+ Miniport->AdapterType = AdapterType;
+
+ //
+ // Set the new timeout value.
+ //
+ if (!ARGUMENT_PRESENT(CheckForHangTimeInSeconds))
+ {
+ CheckForHangTimeInSeconds = 2;
+ }
+
+ Miniport->CheckForHangTimeout = CheckForHangTimeInSeconds * 1000;
+
+ //
+ // Is this a bus master.
+ //
+ if (AttributeFlags & NDIS_ATTRIBUTE_BUS_MASTER)
+ {
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_BUS_MASTER);
+ }
+
+ //
+ // Should we ignore the packet queues?
+ //
+ if (AttributeFlags & NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT)
+ {
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_IGNORE_PACKET_QUEUE);
+ }
+
+ //
+ // Should we ignore the request queues?
+ //
+ if (AttributeFlags & NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT)
+ {
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_IGNORE_REQUEST_QUEUE);
+ }
+
+ //
+ // Should we ignore token ring errors?
+ //
+ if (AttributeFlags & NDIS_ATTRIBUTE_IGNORE_TOKEN_RING_ERRORS)
+ {
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_IGNORE_TOKEN_RING_ERRORS);
+ }
+
+ //
+ // Is this an intermediate miniport?
+ //
+ if (AttributeFlags & NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER)
+ {
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_INTERMEDIATE_DRIVER);
+ }
+
+ MiniportReferencePackage();
+}
+
+
+NDIS_STATUS
+NdisMMapIoSpace(
+ OUT PVOID * VirtualAddress,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress,
+ IN UINT Length
+ )
+{
+ NDIS_STATUS Status;
+ NdisMapIoSpace(&Status,
+ VirtualAddress,
+ MiniportAdapterHandle,
+ PhysicalAddress,
+ Length);
+ return Status;
+}
+
+
+VOID
+NdisMUnmapIoSpace(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PVOID VirtualAddress,
+ IN UINT Length
+ )
+{
+#ifndef _ALPHA_
+ MmUnmapIoSpace(VirtualAddress, Length);
+#endif
+}
+
+
+VOID
+NdisMAllocateSharedMemory(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN ULONG Length,
+ IN BOOLEAN Cached,
+ OUT PVOID * VirtualAddress,
+ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress
+ )
+{
+ //
+ // Convert the handle to our internal structure.
+ //
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportAdapterHandle;
+
+ if (Miniport->SystemAdapterObject == NULL)
+ {
+ *VirtualAddress = NULL;
+ return;
+ }
+
+ NdisAllocateSharedMemory(MiniportAdapterHandle,
+ Length,
+ Cached,
+ VirtualAddress,
+ PhysicalAddress);
+}
+
+NDIS_STATUS
+NdisMAllocateSharedMemoryAsync(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN ULONG Length,
+ IN BOOLEAN Cached,
+ IN PVOID Context
+ )
+{
+ //
+ // Convert the handle to our internal structure.
+ //
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportAdapterHandle;
+ PASYNC_WORKITEM pWorkItem = NULL;
+
+ // Allocate a workitem
+ if ((Miniport->SystemAdapterObject != NULL) &&
+ (Miniport->DriverHandle->MiniportCharacteristics.AllocateCompleteHandler != NULL))
+ {
+ NdisAllocateMemory(&pWorkItem,
+ sizeof(ASYNC_WORKITEM),
+ 0,
+ HighestAcceptableMax);
+ }
+
+ if ((pWorkItem == NULL) ||
+ !ndisReferenceMiniport(Miniport))
+ {
+ if (pWorkItem != NULL)
+ NdisFreeMemory(pWorkItem, sizeof(ASYNC_WORKITEM), 0);
+ return NDIS_STATUS_FAILURE;
+ }
+
+ // Initialize the workitem and queue it up to a worker thread
+ pWorkItem->Miniport = Miniport;
+ pWorkItem->Length = Length;
+ pWorkItem->Cached = Cached;
+ pWorkItem->Context = Context;
+ INITIALIZE_WORK_ITEM(&pWorkItem->ExWorkItem, ndisMQueuedAllocateSharedHandler, pWorkItem);
+ QUEUE_WORK_ITEM(&pWorkItem->ExWorkItem, CriticalWorkQueue);
+
+ return NDIS_STATUS_PENDING;
+}
+
+
+VOID
+ndisMQueuedAllocateSharedHandler(
+ IN PASYNC_WORKITEM pWorkItem
+ )
+{
+ KIRQL OldIrql;
+
+ // Allocate the memory
+ NdisMAllocateSharedMemory(pWorkItem->Miniport,
+ pWorkItem->Length,
+ pWorkItem->Cached,
+ &pWorkItem->VAddr,
+ &pWorkItem->PhyAddr);
+
+ if (pWorkItem->Miniport->Flags & fMINIPORT_IS_CO)
+ {
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(pWorkItem->Miniport, &OldIrql);
+ }
+ else
+ {
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ }
+
+ // Call the miniport back
+ (*pWorkItem->Miniport->DriverHandle->MiniportCharacteristics.AllocateCompleteHandler)(
+ pWorkItem->Miniport->MiniportAdapterContext,
+ pWorkItem->VAddr,
+ &pWorkItem->PhyAddr,
+ pWorkItem->Length,
+ pWorkItem->Context);
+
+ if (pWorkItem->Miniport->Flags & fMINIPORT_IS_CO)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(pWorkItem->Miniport, OldIrql);
+ }
+ else
+ {
+ KeLowerIrql(OldIrql);
+ }
+
+ // Dereference the miniport
+ ndisDereferenceMiniport(pWorkItem->Miniport);
+
+ // And finally free the work-item
+ NdisFreeMemory(pWorkItem, sizeof(ASYNC_WORKITEM), 0);
+}
+
+VOID
+NdisMFreeSharedMemory(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN ULONG Length,
+ IN BOOLEAN Cached,
+ IN PVOID VirtualAddress,
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+
+ if (CURRENT_IRQL < DISPATCH_LEVEL)
+ {
+ NdisFreeSharedMemory(MiniportAdapterHandle,
+ Length,
+ Cached,
+ VirtualAddress,
+ PhysicalAddress);
+ }
+ else if (ndisReferenceMiniport(Miniport))
+ {
+ PASYNC_WORKITEM pWorkItem = NULL;
+
+ // Allocate a work-item and queue it up to a worker thread
+ NdisAllocateMemory(&pWorkItem,
+ sizeof(ASYNC_WORKITEM),
+ 0,
+ HighestAcceptableMax);
+
+ if (pWorkItem != NULL)
+ {
+ // Initialize the workitem and queue it up to a worker thread
+ pWorkItem->Miniport = Miniport;
+ pWorkItem->Length = Length;
+ pWorkItem->Cached = Cached;
+ pWorkItem->VAddr = VirtualAddress;
+ pWorkItem->PhyAddr = PhysicalAddress;
+ INITIALIZE_WORK_ITEM(&pWorkItem->ExWorkItem, ndisMQueuedFreeSharedHandler, pWorkItem);
+ QUEUE_WORK_ITEM(&pWorkItem->ExWorkItem, CriticalWorkQueue);
+ }
+
+ // What do we do now ?
+ }
+}
+
+VOID
+ndisMQueuedFreeSharedHandler(
+ IN PASYNC_WORKITEM pWorkItem
+ )
+{
+ // Free the memory
+ NdisFreeSharedMemory(pWorkItem->Miniport,
+ pWorkItem->Length,
+ pWorkItem->Cached,
+ pWorkItem->VAddr,
+ pWorkItem->PhyAddr);
+
+ // Dereference the miniport
+ ndisDereferenceMiniport(pWorkItem->Miniport);
+
+ // And finally free the work-item
+ NdisFreeMemory(pWorkItem, sizeof(ASYNC_WORKITEM), 0);
+}
+
+
+NDIS_STATUS
+NdisMRegisterDmaChannel(
+ OUT PNDIS_HANDLE MiniportDmaHandle,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN UINT DmaChannel,
+ IN BOOLEAN Dma32BitAddresses,
+ IN PNDIS_DMA_DESCRIPTION DmaDescription,
+ IN ULONG MaximumLength
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(MiniportAdapterHandle);
+ NDIS_STATUS Status;
+ Miniport->ChannelNumber = (DmaChannel);
+
+ if (Dma32BitAddresses)
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_DMA_32_BIT_ADDRESSES);
+
+ NdisAllocateDmaChannel(&Status,
+ MiniportDmaHandle,
+ (NDIS_HANDLE)Miniport,
+ DmaDescription,
+ MaximumLength);
+
+ return Status;
+}
+
+
+
+VOID
+NdisMDeregisterDmaChannel(
+ IN NDIS_HANDLE MiniportDmaHandle
+ )
+{
+ NdisFreeDmaChannel(MiniportDmaHandle);
+}
+
+
+NDIS_STATUS
+NdisMAllocateMapRegisters(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN UINT DmaChannel,
+ IN BOOLEAN Dma32BitAddresses,
+ IN ULONG PhysicalMapRegistersNeeded,
+ IN ULONG MaximumPhysicalMapping
+ )
+
+/*++
+
+Routine Description:
+
+ Allocates map registers for bus mastering devices.
+
+Arguments:
+
+ MiniportAdapterHandle - Handle passed to MiniportInitialize.
+
+ PhysicalMapRegistersNeeded - The maximum number of map registers needed
+ by the Miniport at any one time.
+
+ MaximumPhysicalMapping - Maximum length of a buffer that will have to be mapped.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Convert the handle to our internal structure.
+ //
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportAdapterHandle;
+
+ //
+ // This is needed by HalGetAdapter.
+ //
+ DEVICE_DESCRIPTION DeviceDescription;
+
+ //
+ // Returned by HalGetAdapter.
+ //
+ ULONG MapRegistersAllowed;
+
+ //
+ // Returned by HalGetAdapter.
+ //
+ PADAPTER_OBJECT AdapterObject;
+
+ //
+ // Map registers needed per channel.
+ //
+ ULONG MapRegistersPerChannel;
+
+ NTSTATUS NtStatus;
+
+ KIRQL OldIrql;
+
+ UINT i;
+
+ LARGE_INTEGER TimeoutValue;
+
+ //
+ // If the device is a busmaster, we get an adapter
+ // object for it.
+ // If map registers are needed, we loop, allocating an
+ // adapter channel for each map register needed.
+ //
+
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_BUS_MASTER) &&
+ (Miniport->BusType != (NDIS_INTERFACE_TYPE)-1) &&
+ (Miniport->BusNumber != (ULONG)-1))
+ {
+ TimeoutValue.QuadPart = Int32x32To64(2 * 1000, -10000);
+
+ Miniport->PhysicalMapRegistersNeeded = PhysicalMapRegistersNeeded;
+ Miniport->MaximumPhysicalMapping = MaximumPhysicalMapping;
+
+ //
+ // Allocate storage for holding the appropriate
+ // information for each map register.
+ //
+
+ Miniport->MapRegisters = (PMAP_REGISTER_ENTRY)
+ ALLOC_FROM_POOL(sizeof(MAP_REGISTER_ENTRY) * PhysicalMapRegistersNeeded,
+ NDIS_TAG_DEFAULT);
+
+ if (Miniport->MapRegisters == (PMAP_REGISTER_ENTRY)NULL)
+ {
+ //
+ // Error out
+ //
+
+ NdisWriteErrorLogEntry((NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 1,
+ 0xFFFFFFFF);
+
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ //
+ // Use this event to tell us when ndisAllocationExecutionRoutine
+ // has been called.
+ //
+
+ INITIALIZE_EVENT(&Miniport->AllocationEvent);
+
+ //
+ // Set up the device description; zero it out in case its
+ // size changes.
+ //
+
+ ZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
+
+ DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
+ DeviceDescription.Master = TRUE;
+ DeviceDescription.ScatterGather = TRUE;
+
+ DeviceDescription.BusNumber = Miniport->BusNumber;
+ DeviceDescription.DmaChannel = DmaChannel;
+ DeviceDescription.InterfaceType = Miniport->AdapterType;
+
+ if (DeviceDescription.InterfaceType == NdisInterfaceIsa)
+ {
+ //
+ // For ISA devices, the width is based on the DMA channel:
+ // 0-3 == 8 bits, 5-7 == 16 bits. Timing is compatibility
+ // mode.
+ //
+
+ if (DmaChannel > 4)
+ {
+ DeviceDescription.DmaWidth = Width16Bits;
+ }
+ else
+ {
+ DeviceDescription.DmaWidth = Width8Bits;
+ }
+ DeviceDescription.DmaSpeed = Compatible;
+
+ }
+ else if ((DeviceDescription.InterfaceType == NdisInterfaceEisa) ||
+ (DeviceDescription.InterfaceType == NdisInterfacePci) ||
+ (DeviceDescription.InterfaceType == NdisInterfaceMca))
+ {
+ DeviceDescription.Dma32BitAddresses = Dma32BitAddresses;
+ }
+
+ DeviceDescription.MaximumLength = MaximumPhysicalMapping;
+
+ //
+ // Get the adapter object.
+ //
+
+ AdapterObject = HalGetAdapter (&DeviceDescription, &MapRegistersAllowed);
+
+ if (AdapterObject == NULL)
+ {
+ NdisWriteErrorLogEntry((NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 1,
+ 0xFFFFFFFF);
+
+ FREE_POOL(Miniport->MapRegisters);
+ Miniport->MapRegisters = NULL;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisRegisterAdapter\n"));
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ //
+ // We save this to call IoFreeMapRegisters later.
+ //
+
+ Miniport->SystemAdapterObject = AdapterObject;
+
+ //
+ // Determine how many map registers we need per channel.
+ //
+
+ MapRegistersPerChannel = ((MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2;
+
+ ASSERT (MapRegistersAllowed >= MapRegistersPerChannel);
+
+ //
+ // Now loop, allocating an adapter channel each time, then
+ // freeing everything but the map registers.
+ //
+
+ for (i=0; i<Miniport->PhysicalMapRegistersNeeded; i++)
+ {
+ Miniport->CurrentMapRegister = i;
+
+ RAISE_IRQL_TO_DISPATCH(&OldIrql);
+
+ NtStatus = IoAllocateAdapterChannel(AdapterObject,
+ Miniport->DeviceObject,
+ MapRegistersPerChannel,
+ ndisAllocationExecutionRoutine,
+ Miniport);
+
+ if (!NT_SUCCESS(NtStatus))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("AllocateAdapterChannel: %lx\n", NtStatus));
+
+ for (; i != 0; i--)
+ {
+ IoFreeMapRegisters(Miniport->SystemAdapterObject,
+ Miniport->MapRegisters[i-1].MapRegister,
+ MapRegistersPerChannel);
+ }
+
+ LOWER_IRQL(OldIrql);
+
+ NdisWriteErrorLogEntry((NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 1,
+ 0xFFFFFFFF);
+
+ FREE_POOL(Miniport->MapRegisters);
+ Miniport->MapRegisters = NULL;
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ LOWER_IRQL(OldIrql);
+
+ TimeoutValue.QuadPart = Int32x32To64(2 * 1000, -10000);
+
+ //
+ // ndisAllocationExecutionRoutine will set this event
+ // when it has gotten FirstTranslationEntry.
+ //
+
+ NtStatus = WAIT_FOR_OBJECT(&Miniport->AllocationEvent, &TimeoutValue);
+
+ if (NtStatus != STATUS_SUCCESS)
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus));
+
+ RAISE_IRQL_TO_DISPATCH(&OldIrql);
+
+ for (; i != 0; i--)
+ {
+ IoFreeMapRegisters(Miniport->SystemAdapterObject,
+ Miniport->MapRegisters[i-1].MapRegister,
+ MapRegistersPerChannel);
+ }
+
+ LOWER_IRQL(OldIrql);
+
+ NdisWriteErrorLogEntry((NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 1,
+ 0xFFFFFFFF);
+
+ FREE_POOL(Miniport->MapRegisters);
+ Miniport->MapRegisters = NULL;
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ RESET_EVENT(&Miniport->AllocationEvent);
+ }
+ }
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+VOID
+NdisMFreeMapRegisters(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Releases allocated map registers
+
+Arguments:
+
+ MiniportAdapterHandle - Handle passed to MiniportInitialize.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Convert the handle to our internal structure.
+ //
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportAdapterHandle;
+
+ KIRQL OldIrql;
+
+ ULONG i;
+
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_BUS_MASTER) &&
+ (Miniport->MapRegisters != NULL)
+ )
+ {
+ ULONG MapRegistersPerChannel =
+ ((Miniport->MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2;
+
+ for (i=0; i<Miniport->PhysicalMapRegistersNeeded; i++)
+ {
+ RAISE_IRQL_TO_DISPATCH(&OldIrql);
+
+ IoFreeMapRegisters(Miniport->SystemAdapterObject,
+ Miniport->MapRegisters[i].MapRegister,
+ MapRegistersPerChannel);
+
+ LOWER_IRQL(OldIrql);
+ }
+
+ FREE_POOL(Miniport->MapRegisters);
+
+ Miniport->MapRegisters = NULL;
+ }
+}
+
+
+
+ULONG
+NdisMReadDmaCounter(
+ IN NDIS_HANDLE MiniportDmaHandle
+ )
+/*++
+
+Routine Description:
+
+ Reads the current value of the dma counter
+
+Arguments:
+
+ MiniportDmaHandle - Handle for the DMA transfer.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ return HalReadDmaCounter(((PNDIS_DMA_BLOCK)(MiniportDmaHandle))->SystemAdapterObject);
+}
+
+
+VOID
+ndisBugcheckHandler(
+ IN PNDIS_WRAPPER_CONTEXT WrapperContext,
+ IN ULONG Size
+ )
+/*++
+
+Routine Description:
+
+ This routine is called when a bugcheck occurs in the system.
+
+Arguments:
+
+ Buffer -- Ndis wrapper context.
+
+ Size -- Size of wrapper context
+
+Return Value:
+
+ Void.
+
+--*/
+{
+ if (Size == sizeof(NDIS_WRAPPER_CONTEXT))
+ {
+ if (WrapperContext->ShutdownHandler != NULL)
+ {
+ WrapperContext->ShutdownHandler(WrapperContext->ShutdownContext);
+ }
+ }
+}
+
+
+VOID
+NdisMRegisterAdapterShutdownHandler(
+ IN NDIS_HANDLE MiniportHandle,
+ IN PVOID ShutdownContext,
+ IN ADAPTER_SHUTDOWN_HANDLER ShutdownHandler
+ )
+/*++
+
+Routine Description:
+
+ Deregisters an NDIS adapter.
+
+Arguments:
+
+ MiniportHandle - The miniport.
+
+ ShutdownHandler - The Handler for the Adapter, to be called on shutdown.
+
+Return Value:
+
+ none.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportHandle;
+ PNDIS_WRAPPER_CONTEXT WrapperContext = Miniport->WrapperContext;
+
+ if (WrapperContext->ShutdownHandler == NULL)
+ {
+ //
+ // Store information
+ //
+
+ WrapperContext->ShutdownHandler = ShutdownHandler;
+ WrapperContext->ShutdownContext = ShutdownContext;
+
+ //
+ // Register our shutdown handler for a bugcheck. (Note that we are
+ // already registered for shutdown notification.)
+ //
+
+ KeInitializeCallbackRecord(&WrapperContext->BugcheckCallbackRecord);
+
+ KeRegisterBugCheckCallback(&WrapperContext->BugcheckCallbackRecord, // callback record.
+ ndisBugcheckHandler, // callback routine.
+ WrapperContext, // free form buffer.
+ sizeof(NDIS_WRAPPER_CONTEXT), // buffer size.
+ "Ndis miniport"); // component id.
+ }
+}
+
+
+VOID
+NdisMDeregisterAdapterShutdownHandler(
+ IN NDIS_HANDLE MiniportHandle
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+ MiniportHandle - The miniport.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportHandle;
+ PNDIS_WRAPPER_CONTEXT WrapperContext = Miniport->WrapperContext;
+
+ //
+ // Clear information
+ //
+
+ if (WrapperContext->ShutdownHandler != NULL)
+ {
+ KeDeregisterBugCheckCallback(&WrapperContext->BugcheckCallbackRecord);
+ WrapperContext->ShutdownHandler = NULL;
+ }
+}
+
+
+NDIS_STATUS
+NdisMPciAssignResources(
+ IN NDIS_HANDLE MiniportHandle,
+ IN ULONG SlotNumber,
+ OUT PNDIS_RESOURCE_LIST * AssignedResources
+ )
+/*++
+
+Routine Description:
+
+ This routine uses the Hal to assign a set of resources to a PCI
+ device.
+
+Arguments:
+
+ MiniportHandle - The miniport.
+
+ SlotNumber - Slot number of the device.
+
+ AssignedResources - The returned resources.
+
+Return Value:
+
+ Status of the operation
+
+--*/
+{
+ NTSTATUS NtStatus;
+ PCM_RESOURCE_LIST AllocatedResources = NULL;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportHandle;
+
+ NtStatus = HalAssignSlotResources ((PUNICODE_STRING)(Miniport->DriverHandle->NdisDriverInfo->NdisWrapperConfigurationHandle),
+ NULL,
+ Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver,
+ Miniport->DeviceObject,
+ Miniport->BusType,
+ Miniport->BusNumber,
+ SlotNumber,
+ &AllocatedResources);
+
+ if (NtStatus != STATUS_SUCCESS)
+ {
+ *AssignedResources = NULL;
+ return NDIS_STATUS_FAILURE;
+ }
+
+ //
+ // Store resources into the driver wide block
+ //
+ ((PNDIS_WRAPPER_CONTEXT)Miniport->WrapperContext)->AssignedSlotResources = AllocatedResources;
+
+ *AssignedResources = &(AllocatedResources->List[0].PartialResourceList);
+
+ //
+ // Update slot number since the driver can also scan and so the one
+ // in the registry is probably invalid
+ //
+ Miniport->SlotNumber = SlotNumber;
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+VOID
+NdisMQueryAdapterResources(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PNDIS_RESOURCE_LIST ResourceList,
+ IN IN PUINT BufferSize
+ )
+{
+ *Status = NDIS_STATUS_NOT_SUPPORTED;
+}
+
+
+
diff --git a/private/ntos/ndis/ndis40/data.c b/private/ntos/ndis/ndis40/data.c
new file mode 100644
index 000000000..e65838217
--- /dev/null
+++ b/private/ntos/ndis/ndis40/data.c
@@ -0,0 +1,190 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ data.c
+
+Abstract:
+
+ NDIS wrapper Data
+
+Author:
+
+ 01-Jun-1995 JameelH Re-organization
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ 10-July-1995 KyleB Added spinlock logging debug code.
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_DATA
+
+#if DBG
+ULONG ndisDebugSystems = 0;
+LONG ndisDebugLevel = DBG_LEVEL_FATAL;
+ULONG ndisDebugInformationOffset;
+#endif
+
+UCHAR ndisValidProcessors[32] = { 0 };
+ULONG ndisMaximumProcessor = 0;
+ULONG ndisCurrentProcessor = 0;
+UCHAR ndisInternalEaName[4] = "NDIS";
+UCHAR ndisInternalEaValue[8] = "INTERNAL";
+const NDIS_PHYSICAL_ADDRESS HighestAcceptableMax = NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
+PKG_REF ProtocolPkg = {0};
+PKG_REF MacPkg = {0};
+PKG_REF CoPkg = {0};
+PKG_REF InitPkg = {0};
+PKG_REF PnPPkg = {0};
+PKG_REF MiniportPkg = {0};
+PKG_REF ArcPkg = {0};
+PKG_REF EthPkg = {0};
+PKG_REF TrPkg = {0};
+PKG_REF FddiPkg = {0};
+KSPIN_LOCK ndisDriverListLock = {0};
+PNDIS_MAC_BLOCK ndisMacDriverList = (PNDIS_MAC_BLOCK)NULL;
+PNDIS_M_DRIVER_BLOCK ndisMiniDriverList = NULL;
+PNDIS_PROTOCOL_BLOCK ndisProtocolList = NULL;
+PNDIS_OPEN_BLOCK ndisGlobalOpenList = NULL;
+PNDIS_AF_LIST ndisAfList = NULL;
+KSPIN_LOCK ndisGlobalOpenListLock = {0};
+TDI_REGISTER_CALLBACK ndisTdiRegisterCallback = NULL;
+ULONG ndisDmaAlignment = 0;
+ERESOURCE SharedMemoryResource = {0};
+KSPIN_LOCK ndisLookaheadBufferLock = {0};
+ULONG ndisLookaheadBufferLength = 0;
+#if defined(_ALPHA_)
+PNDIS_LOOKAHEAD_ELEMENT ndisLookaheadBufferList = NULL;
+#endif
+ULONG MiniportDebug = 0; // MINIPORT_DEBUG_LOUD;
+
+UCHAR ndisMSendRescBuffer[512] = {0};
+ULONG ndisMSendRescIndex = 0;
+UCHAR ndisMSendLog[256] = {0};
+UCHAR ndisMSendLogIndex = 0;
+BOOLEAN ndisSkipProcessorAffinity = FALSE;
+BOOLEAN ndisMediaTypeCl[NdisMediumMax] =
+ {
+ TRUE,
+ TRUE,
+ TRUE,
+ FALSE,
+ TRUE,
+ TRUE,
+ TRUE,
+ TRUE,
+ FALSE,
+ TRUE,
+ TRUE
+ };
+NDIS_MEDIUM ndisMediumBuffer[NdisMediumMax + EXPERIMENTAL_SIZE] = // Keep some space for experimental media
+ {
+ NdisMedium802_3,
+ NdisMedium802_5,
+ NdisMediumFddi,
+ NdisMediumWan,
+ NdisMediumLocalTalk,
+ NdisMediumDix,
+ NdisMediumArcnetRaw,
+ NdisMediumArcnet878_2,
+ NdisMediumAtm,
+ NdisMediumWirelessWan,
+ NdisMediumIrda
+ };
+NDIS_MEDIUM * ndisMediumArray = ndisMediumBuffer;
+UINT ndisMediumArraySize = NdisMediumMax * sizeof(NDIS_MEDIUM);
+UINT ndisMediumArrayMaxSize = sizeof(ndisMediumBuffer);
+PBUS_SLOT_DB ndisGlobalDb = NULL;
+KSPIN_LOCK ndisGlobalDbLock = {0};
+
+
+#if TRACK_MEMORY
+
+KSPIN_LOCK ALock = 0;
+#define MAX_PTR_COUNT 2048
+
+struct _MemPtr
+{
+ PVOID Ptr;
+ ULONG Size;
+ ULONG ModLine;
+ ULONG Tag;
+} ndisMemPtrs[MAX_PTR_COUNT] = { 0 };
+
+PVOID
+AllocateM(
+ IN UINT Size,
+ IN ULONG ModLine,
+ IN ULONG Tag
+ )
+{
+ PVOID p;
+
+ p = ExAllocatePoolWithTag(NonPagedPool, Size, Tag);
+
+ if (p != NULL)
+ {
+ KIRQL OldIrql;
+ UINT i;
+
+ ACQUIRE_SPIN_LOCK(&ALock, &OldIrql);
+
+ for (i = 0; i < MAX_PTR_COUNT; i++)
+ {
+ if (ndisMemPtrs[i].Ptr == NULL)
+ {
+ ndisMemPtrs[i].Ptr = p;
+ ndisMemPtrs[i].Size = Size;
+ ndisMemPtrs[i].ModLine = ModLine;
+ ndisMemPtrs[i].Tag = Tag;
+ break;
+ }
+ }
+
+ RELEASE_SPIN_LOCK(&ALock, OldIrql);
+ }
+
+ return(p);
+}
+
+VOID
+FreeM(
+ IN PVOID MemPtr
+ )
+{
+ KIRQL OldIrql;
+ UINT i;
+
+ ACQUIRE_SPIN_LOCK(&ALock, &OldIrql);
+
+ for (i = 0; i < MAX_PTR_COUNT; i++)
+ {
+ if (ndisMemPtrs[i].Ptr == MemPtr)
+ {
+ ndisMemPtrs[i].Ptr = NULL;
+ ndisMemPtrs[i].Size = 0;
+ ndisMemPtrs[i].ModLine = 0;
+ ndisMemPtrs[i].Tag = 0;
+ }
+ }
+
+ RELEASE_SPIN_LOCK(&ALock, OldIrql);
+
+ ExFreePool(MemPtr);
+}
+
+#endif
+
diff --git a/private/ntos/ndis/ndis40/debug.c b/private/ntos/ndis/ndis40/debug.c
new file mode 100644
index 000000000..c3e6feb05
--- /dev/null
+++ b/private/ntos/ndis/ndis40/debug.c
@@ -0,0 +1,422 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ debug.c
+
+Abstract:
+
+ NDIS wrapper definitions
+
+Author:
+
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ 10/22/95 Kyle Brandon Created.
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+//
+// Define module number for debug code
+//
+#define MODULE_NUMBER MODULE_DEBUG
+
+#if DBG && _DBG
+
+
+VOID
+ndisMInitializeDebugInformation(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_MOJO NdisMojo;
+
+ //
+ // Allocate the initial debug structure.
+ //
+ NdisMojo = ALLOC_FROM_POOL(sizeof(NDIS_MOJO), NDIS_TAG_DBG);
+
+ ASSERT(NdisMojo != NULL);
+
+ //
+ // Clear out the log memory.
+ //
+ ZeroMemory(NdisMojo, sizeof(NDIS_MOJO));
+
+ //
+ // Allocate memory for the spin lock log.
+ //
+ NdisMojo->SpinLockLog = ALLOC_FROM_POOL(sizeof(SPIN_LOCK_LOG) +
+ (sizeof(SPIN_LOCK_LOG_ENTRY) * LOG_SIZE),
+ NDIS_TAG_DBG_S);
+
+ ASSERT(NdisMojo->SpinLockLog != NULL);
+
+ //
+ // Initialize the spin lock log.
+ //
+ NdisZeroMemory(
+ NdisMojo->SpinLockLog,
+ sizeof(SPIN_LOCK_LOG) + (sizeof(SPIN_LOCK_LOG_ENTRY) * LOG_SIZE));
+
+ NdisMojo->SpinLockLog->Buffer = (PSPIN_LOCK_LOG_ENTRY)((PUCHAR)NdisMojo->SpinLockLog + sizeof(SPIN_LOCK_LOG));
+ NdisMojo->SpinLockLog->CurrentEntry = (LOG_SIZE - 1);
+
+
+ //
+ // Allocate memory for the local lock log.
+ //
+ NdisMojo->LocalLockLog = ALLOC_FROM_POOL(sizeof(LOCAL_LOCK_LOG) +
+ (sizeof(LOCAL_LOCK_LOG_ENTRY) * LOG_SIZE),
+ NDIS_TAG_DBG_L);
+ ASSERT(NdisMojo->LocalLockLog != NULL);
+
+ //
+ // Initialize the local lock log.
+ //
+ NdisZeroMemory(
+ NdisMojo->LocalLockLog,
+ sizeof(LOCAL_LOCK_LOG) + (sizeof(LOCAL_LOCK_LOG_ENTRY) * LOG_SIZE));
+
+ NdisMojo->LocalLockLog->Buffer = (PLOCAL_LOCK_LOG_ENTRY)((PUCHAR)NdisMojo->LocalLockLog + sizeof(LOCAL_LOCK_LOG));
+ NdisMojo->LocalLockLog->CurrentEntry = (LOG_SIZE - 1);
+
+ //
+ // Allocate memory for the send packet log.
+ //
+ NdisMojo->SendPacketLog = ALLOC_FROM_POOL(
+ sizeof(PACKET_LOG) +
+ (sizeof(PACKET_LOG_ENTRY) * LOG_SIZE),
+ NDIS_TAG_DBG_P);
+ ASSERT(NdisMojo->SendPacketLog != NULL);
+
+ //
+ // Initialize the packet log.
+ //
+ NdisZeroMemory(
+ NdisMojo->SendPacketLog,
+ sizeof(PACKET_LOG) + (sizeof(PACKET_LOG_ENTRY) * LOG_SIZE));
+
+ NdisMojo->SendPacketLog->Buffer = (PPACKET_LOG_ENTRY)((PUCHAR)NdisMojo->SendPacketLog + sizeof(PACKET_LOG));
+ NdisMojo->SendPacketLog->CurrentEntry = (LOG_SIZE - 1);
+
+ //
+ // Allocate memory for the receive packet log.
+ //
+ NdisMojo->RecvPacketLog = ALLOC_FROM_POOL(
+ sizeof(PACKET_LOG) +
+ (sizeof(PACKET_LOG_ENTRY) * LOG_SIZE),
+ NDIS_TAG_DBG_P);
+ ASSERT(NdisMojo->RecvPacketLog != NULL);
+
+ //
+ // Initialize the packet log.
+ //
+ NdisZeroMemory(
+ NdisMojo->RecvPacketLog,
+ sizeof(PACKET_LOG) + (sizeof(PACKET_LOG_ENTRY) * LOG_SIZE));
+
+ NdisMojo->RecvPacketLog->Buffer = (PPACKET_LOG_ENTRY)((PUCHAR)NdisMojo->RecvPacketLog + sizeof(PACKET_LOG));
+ NdisMojo->RecvPacketLog->CurrentEntry = (LOG_SIZE - 1);
+
+
+ //
+ // Initialize the spin locks.
+ //
+ INITIALIZE_SPIN_LOCK(&NdisMojo->SpinLockLog->Lock);
+ INITIALIZE_SPIN_LOCK(&NdisMojo->LocalLockLog->Lock);
+ INITIALIZE_SPIN_LOCK(&NdisMojo->SendPacketLog->Lock);
+ INITIALIZE_SPIN_LOCK(&NdisMojo->RecvPacketLog->Lock);
+
+ //
+ // Save the debug information with the miniport.
+ //
+ Miniport->Reserved = NdisMojo;
+
+}
+
+VOID
+NDISM_LOG_RECV_PACKET(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PVOID Context1,
+ IN PVOID Context2,
+ IN ULONG Ident
+ )
+{
+ KIRQL OldIrql;
+
+ IF_DBG(DBG_COMP_RECV, DBG_LEVEL_LOG)
+ {
+ ACQUIRE_SPIN_LOCK(&RPL_LOCK(Miniport), &OldIrql);
+
+ RPL_HEAD(Miniport) = &RPL_LOG(Miniport)[RPL_CURRENT_ENTRY(Miniport)];
+ RPL_HEAD(Miniport)->Miniport = Miniport;
+ RPL_HEAD(Miniport)->Context1 = Context1;
+ RPL_HEAD(Miniport)->Context2 = Context2;
+ RPL_HEAD(Miniport)->Ident = Ident;
+
+ if (RPL_CURRENT_ENTRY(Miniport)-- == 0)
+ {
+ RPL_CURRENT_ENTRY(Miniport) = (LOG_SIZE - 1);
+ }
+
+ RELEASE_SPIN_LOCK(&RPL_LOCK(Miniport), OldIrql);
+ }
+}
+
+VOID
+NDISM_LOG_PACKET(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_PACKET Context1,
+ IN PVOID Context2,
+ IN ULONG Ident
+ )
+{
+ KIRQL OldIrql;
+
+ IF_DBG(DBG_COMP_SEND, DBG_LEVEL_LOG)
+ {
+ ACQUIRE_SPIN_LOCK(&SPL_LOCK(Miniport), &OldIrql);
+
+ SPL_HEAD(Miniport) = &SPL_LOG(Miniport)[SPL_CURRENT_ENTRY(Miniport)];
+ SPL_HEAD(Miniport)->Miniport = Miniport;
+ SPL_HEAD(Miniport)->Context1 = Context1;
+ SPL_HEAD(Miniport)->Context2 = Context2;
+ SPL_HEAD(Miniport)->Ident = Ident;
+
+ if (SPL_CURRENT_ENTRY(Miniport)-- == 0)
+ {
+ SPL_CURRENT_ENTRY(Miniport) = (LOG_SIZE - 1);
+ }
+
+ RELEASE_SPIN_LOCK(&SPL_LOCK(Miniport), OldIrql);
+ }
+}
+
+#if defined(_M_IX86) && defined(_NDIS_INTERNAL_DEBUG)
+
+//
+// gWatchMask[x][y]
+// x is the break point to set 0-3.
+// y is the following:
+// 0 - Mask to OR with dr7 to enable breakpoint x.
+// 1 - Mask to AND ~ with dr7 to disable breakpoint x.
+// 2 - The linear address that is currently in drX.
+// This is 0 if drX is clear.
+//
+ULONG gWatch[4][3] =
+{
+ {
+ 0xD0303,
+ 0xD0003,
+ 0
+ },
+ {
+ 0xD0030C,
+ 0xD0000C,
+ 0
+ },
+ {
+ 0xD000330,
+ 0xD000030,
+ 0
+ },
+ {
+ 0xD00003C0,
+ 0xD00000C0,
+ 0
+ }
+};
+
+#define SET_WATCH 0
+#define CLEAR_WATCH 1
+#define CURRENT_WATCH 2
+
+#define NO_ADDRESS_SET 0
+#define NO_DEBUG_REGISTERS_AVAILABLE 4
+
+VOID
+NdisMSetWriteBreakPoint(
+ IN PVOID LinearAddress
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ UINT c;
+ ULONG Mask;
+
+ //
+ // Find the first free debug register that we can use.
+ //
+ for (c = 0; c < NO_DEBUG_REGISTERS_AVAILABLE; c++)
+ {
+ if (NO_ADDRESS_SET == gWatch[c][CURRENT_WATCH])
+ {
+ break;
+ }
+ }
+
+ //
+ // Did we get a debug register?
+ //
+ if (NO_DEBUG_REGISTERS_AVAILABLE == c)
+ {
+ DbgPrint("Attempted to set a write breakpoint with no registers available\n");
+ DbgBreakPoint();
+ return;
+ }
+
+ //
+ // Separate code for each debug register.
+ //
+ switch (c)
+ {
+ case 0:
+
+ _asm {
+
+ mov eax, LinearAddress
+ mov dr0, eax
+ }
+
+ break;
+
+ case 1:
+
+ _asm {
+
+ mov eax, LinearAddress
+ mov dr1, eax
+ }
+
+ break;
+
+ case 2:
+
+ _asm {
+
+ mov eax, LinearAddress
+ mov dr2, eax
+ }
+
+ break;
+
+ case 3:
+
+ _asm {
+
+ mov eax, LinearAddress
+ mov dr3, eax
+ }
+
+ break;
+
+
+ default:
+
+ DbgPrint("Invalid debug register selected!!\n");
+ DbgBreakPoint();
+ }
+
+ //
+ // Enable the break point.
+ //
+ Mask = gWatch[c][SET_WATCH];
+
+ _asm {
+ mov eax, dr7
+ or eax, Mask
+ mov dr7, eax
+ }
+
+}
+
+
+VOID
+NdisMClearWriteBreakPoint(
+ IN PVOID LinearAddress
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ UINT c;
+ ULONG Mask;
+
+ //
+ // Find the register that this address is in.
+ //
+ for (c = 0; c < NO_DEBUG_REGISTERS_AVAILABLE; c++)
+ {
+ if (gWatch[c][CURRENT_WATCH] == (ULONG)LinearAddress)
+ {
+ break;
+ }
+ }
+
+ //
+ // Did we get a debug register?
+ //
+ if (NO_DEBUG_REGISTERS_AVAILABLE == c)
+ {
+ DbgPrint("Attempted to set a write breakpoint with no registers available\n");
+ DbgBreakPoint();
+ return;
+ }
+
+ //
+ // Clear the address from our state array.
+ //
+ gWatch[c][CURRENT_WATCH] = 0;
+
+ //
+ // Enable the break point.
+ //
+ Mask = gWatch[c][CLEAR_WATCH];
+
+ _asm {
+ mov eax, dr7
+ mov ebx, Mask
+ not ebx
+ and eax, ebx
+ mov dr7, eax
+ }
+}
+
+#endif
+
+#else
+
+#endif
+
diff --git a/private/ntos/ndis/ndis40/dirs b/private/ntos/ndis/ndis40/dirs
new file mode 100644
index 000000000..b3d6b7888
--- /dev/null
+++ b/private/ntos/ndis/ndis40/dirs
@@ -0,0 +1,23 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=up \
+ mp
diff --git a/private/ntos/ndis/ndis40/dummy.c b/private/ntos/ndis/ndis40/dummy.c
new file mode 100644
index 000000000..350258c2e
--- /dev/null
+++ b/private/ntos/ndis/ndis40/dummy.c
@@ -0,0 +1,56 @@
+/*++
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ wrapper.c
+
+Abstract:
+
+ NDIS wrapper functions
+
+Author:
+
+ Adam Barr (adamba) 11-Jul-1990
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ 26-Feb-1991 JohnsonA Added Debugging Code
+ 10-Jul-1991 JohnsonA Implement revised Ndis Specs
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ Temporary entry point needed to initialize the NDIS wrapper driver.
+
+Arguments:
+
+ DriverObject - Pointer to the driver object created by the system.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+
+ return STATUS_SUCCESS;
+
+} // DriverEntry
diff --git a/private/ntos/ndis/ndis40/efilter.c b/private/ntos/ndis/ndis40/efilter.c
new file mode 100644
index 000000000..1e3b985df
--- /dev/null
+++ b/private/ntos/ndis/ndis40/efilter.c
@@ -0,0 +1,2845 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ efilter.c
+
+Abstract:
+
+ This module implements a set of library routines to handle packet
+ filtering for NDIS MAC drivers.
+
+Author:
+
+ Anthony V. Ercolano (Tonye) 03-Aug-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+ Adam Barr (adamba) 28-Nov-1990
+
+ - Added AddressContexts
+
+ Adam Barr (adamba) 28-May-1991
+
+ - renamed MacXXX to EthXXX, changed filter.c to efilter.c
+
+ 10-July-1995 KyleB Added separate queues for bindings
+ that receive directed and broadcast
+ packets. Also fixed the request code
+ that requires the filter database.
+
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_EFILTER
+
+#define ETH_CHECK_FOR_INVALID_BROADCAST_INDICATION(_F) \
+IF_DBG(DBG_COMP_FILTER, DBG_LEVEL_WARN) \
+{ \
+ if (!((_F)->CombinedPacketFilter & NDIS_PACKET_TYPE_BROADCAST)) \
+ { \
+ /* \
+ We should never receive directed packets \
+ to someone else unless in p-mode. \
+ */ \
+ DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_ERR, \
+ ("Bad driver, indicating broadcast when not set to.\n"));\
+ DBGBREAK(DBG_COMP_FILTER, DBG_LEVEL_ERR); \
+ } \
+}
+
+#define ETH_CHECK_FOR_INVALID_DIRECTED_INDICATION(_F, _A) \
+IF_DBG(DBG_COMP_FILTER, DBG_LEVEL_WARN) \
+{ \
+ /* \
+ The result of comparing an element of the address \
+ array and the multicast address. \
+ \
+ Result < 0 Implies the adapter address is greater. \
+ Result > 0 Implies the address is greater. \
+ Result = 0 Implies that the they are equal. \
+ */ \
+ INT Result; \
+ \
+ ETH_COMPARE_NETWORK_ADDRESSES_EQ((_F)->AdapterAddress, (_A), &Result);\
+ if (Result != 0) \
+ { \
+ /* \
+ We should never receive directed packets \
+ to someone else unless in p-mode. \
+ */ \
+ DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_ERR, \
+ ("Bad driver, indicating packets to another station when not in promiscuous mode.\n"));\
+ DBGBREAK(DBG_COMP_FILTER, DBG_LEVEL_ERR); \
+ } \
+}
+
+
+//
+// VOID
+// ETH_FILTER_ALLOC_OPEN(
+// IN PETH_FILTER Filter,
+// OUT PUINT FilterIndex
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Allocates an open block. This only allocates the index, not memory for
+// the open block.
+//
+//Arguments:
+//
+// Filter - DB from which to allocate the space
+//
+// FilterIndex - pointer to place to store the index.
+//
+//Return Value:
+//
+// FilterIndex of the new open
+//
+//--*/
+#define ETH_FILTER_ALLOC_OPEN(Filter, FilterIndex) \
+{ \
+ UINT i; \
+ for (i = 0; i < ETH_FILTER_MAX_OPENS; i++) \
+ { \
+ if (IS_BIT_SET_IN_MASK(i,(Filter)->FreeBindingMask)) \
+ { \
+ *(FilterIndex) = i; \
+ CLEAR_BIT_IN_MASK(i, &((Filter)->FreeBindingMask)); \
+ break; \
+ } \
+ } \
+}
+
+//
+// VOID
+// ETH_FILTER_FREE_OPEN(
+// IN PETH_FILTER Filter,
+// IN PETH_BINDING_INFO LocalOpen
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Frees an open block. Also frees the memory associated with the open.
+//
+//Arguments:
+//
+// Filter - DB from which to allocate the space
+//
+// FilterIndex - Index to free
+//
+//Return Value:
+//
+// None
+//
+//--*/
+#define ETH_FILTER_FREE_OPEN(Filter, LocalOpen) \
+{ \
+ SET_BIT_IN_MASK(((LocalOpen)->FilterIndex), &((Filter)->FreeBindingMask));\
+ FreePhys((LocalOpen), sizeof(ETH_BINDING_INFO));\
+}
+
+
+VOID
+ethRemoveBindingFromLists(
+ IN PETH_FILTER Filter,
+ IN PETH_BINDING_INFO Binding
+ )
+/*++
+
+ This routine will remove a binding from all of the list in a
+ filter database. These lists include the list of bindings,
+ the directed filter list and the broadcast filter list.
+
+Arguments:
+
+ Filter - Pointer to the filter database to remove the binding from.
+ Binding - Pointer to the binding to remove.
+
+--*/
+{
+ PETH_BINDING_INFO *ppBI;
+
+ //
+ // Remove the binding from the filters list
+ // of all bindings.
+ //
+ for (ppBI = &Filter->OpenList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextOpen)
+ {
+ if (*ppBI == Binding)
+ {
+ *ppBI = Binding->NextOpen;
+ break;
+ }
+ }
+ ASSERT(*ppBI == Binding->NextOpen);
+
+ //
+ // Remove it from the directed binding list - conditionally
+ //
+ for (ppBI = &Filter->DirectedList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextDirected)
+ {
+ if (*ppBI == Binding)
+ {
+ *ppBI = Binding->NextDirected;
+ break;
+ }
+ }
+
+ //
+ // Remove it from the broadcast/multicast binding list - conditionally
+ //
+ for (ppBI = &Filter->BMList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextBM)
+ {
+ if (*ppBI == Binding)
+ {
+ *ppBI = Binding->NextBM;
+ break;
+ }
+ }
+
+ Binding->NextDirected = NULL;
+ Binding->NextBM = NULL;
+ Binding->NextOpen = NULL;
+}
+
+VOID
+ethRemoveAndFreeBinding(
+ IN PETH_FILTER Filter,
+ IN PETH_BINDING_INFO Binding,
+ IN BOOLEAN fCallCloseAction
+ )
+/*++
+
+Routine Description:
+
+ This routine will remove a binding from the filter database and
+ indicate a receive complete if necessary. This was made a function
+ to remove code redundancey in following routines. Its not time
+ critical so it's cool.
+
+Arguments:
+
+ Filter - Pointer to the filter database to remove the binding from.
+ Binding - Pointer to the binding to remove.
+ fCallCloseAction - TRUE if we should call the filter's close
+ action routine. FALSE if not.
+--*/
+{
+ //
+ // Remove the binding.
+ //
+ ethRemoveBindingFromLists(Filter, Binding);
+
+ //
+ // If we have received and packet indications then
+ // notify the binding of the indication completion.
+ //
+ if (Binding->ReceivedAPacket)
+ {
+ if (NULL != Filter->Miniport)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+ }
+ else
+ {
+ NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ }
+
+ FilterIndicateReceiveComplete(Binding->NdisBindingContext);
+
+ if (NULL != Filter->Miniport)
+ {
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+ }
+ else
+ {
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ }
+ }
+
+ //
+ // Do we need to call the driver's close action routine?
+ //
+ if (fCallCloseAction)
+ {
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+ Filter->CloseAction(Binding->MacBindingHandle);
+ }
+
+ //
+ // Free the open.
+ //
+ ETH_FILTER_FREE_OPEN(Filter, Binding);
+}
+
+
+
+BOOLEAN
+EthCreateFilter(
+ IN UINT MaximumMulticastAddresses,
+ IN ETH_ADDRESS_CHANGE AddressChangeAction,
+ IN ETH_FILTER_CHANGE FilterChangeAction,
+ IN ETH_DEFERRED_CLOSE CloseAction,
+ IN PUCHAR AdapterAddress,
+ IN PNDIS_SPIN_LOCK Lock,
+ OUT PETH_FILTER *Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to create and initialize the filter database.
+
+Arguments:
+
+ MaximumMulticastAddresses - The maximum number of multicast addresses
+ that the MAC will support.
+
+ AddressChangeAction - Action routine to call when the list of
+ multicast addresses the card must enable has changed.
+
+ ChangeAction - Action routine to call when a binding sets or clears
+ a particular filter class and it is the first or only binding using
+ the filter class.
+
+ CloseAction - This routine is called if a binding closes while
+ it is being indicated to via NdisIndicateReceive. It will be
+ called upon return from NdisIndicateReceive.
+
+ AdapterAddress - the address of the adapter associated with this filter
+ database.
+
+ Lock - Pointer to the lock that should be held when mutual exclusion
+ is required.
+
+ Filter - A pointer to an ETH_FILTER. This is what is allocated and
+ created by this routine.
+
+Return Value:
+
+ If the function returns false then one of the parameters exceeded
+ what the filter was willing to support.
+
+--*/
+
+{
+ PETH_FILTER LocalFilter;
+ NDIS_STATUS AllocStatus;
+
+ //
+ // Allocate the database and it's associated arrays.
+ //
+ AllocStatus = AllocPhys(&LocalFilter, sizeof(ETH_FILTER));
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ {
+ return(FALSE);
+ }
+
+ //
+ // Clear the memory.
+ //
+ ZeroMemory(LocalFilter, sizeof(ETH_FILTER));
+
+ //
+ // Allocate memory for the multicast array list.
+ //
+ if (MaximumMulticastAddresses == 0)
+ {
+ //
+ // Why 2 and not 1? Why not. A protocol is going to need at least
+ // one to run on this, so let's give one extra one for any user stuff
+ // that may need it.
+ //
+ MaximumMulticastAddresses = 2;
+ }
+
+ //
+ // Allocate memory for the multicast array.
+ //
+ AllocStatus = AllocPhys(
+ &LocalFilter->MulticastAddresses,
+ ETH_LENGTH_OF_ADDRESS * MaximumMulticastAddresses);
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ {
+ EthDeleteFilter(LocalFilter);
+ return(FALSE);
+ }
+
+ //
+ // Allocate memory for the OldMulticastAddresses list,
+ // this is incase we have to restore the original list.
+ //
+ AllocStatus = AllocPhys(
+ &LocalFilter->OldMulticastAddresses,
+ ETH_LENGTH_OF_ADDRESS * MaximumMulticastAddresses);
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ {
+ EthDeleteFilter(LocalFilter);
+ return(FALSE);
+ }
+
+ //
+ // Allocate memory for the bindings using the addresses.
+ //
+ AllocStatus = AllocPhys(
+ &LocalFilter->BindingsUsingAddress,
+ sizeof(ETH_MASK) * MaximumMulticastAddresses);
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ {
+ EthDeleteFilter(LocalFilter);
+ return(FALSE);
+ }
+
+ //
+ // Allocate memory for the old bindings using the addresses.
+ //
+ AllocStatus = AllocPhys(
+ &LocalFilter->OldBindingsUsingAddress,
+ sizeof(ETH_MASK) * MaximumMulticastAddresses);
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ {
+ EthDeleteFilter(LocalFilter);
+ return(FALSE);
+ }
+
+ EthReferencePackage();
+
+ LocalFilter->FreeBindingMask = (ULONG)(-1);
+
+ ETH_COPY_NETWORK_ADDRESS(LocalFilter->AdapterAddress, AdapterAddress);
+ LocalFilter->Lock = Lock;
+ LocalFilter->AddressChangeAction = AddressChangeAction;
+ LocalFilter->FilterChangeAction = FilterChangeAction;
+ LocalFilter->CloseAction = CloseAction;
+ LocalFilter->MaximumMulticastAddresses = MaximumMulticastAddresses;
+
+ *Filter = LocalFilter;
+ return(TRUE);
+}
+
+
+//
+// NOTE: THIS FUNCTION CANNOT BE PAGEABLE
+//
+VOID
+EthDeleteFilter(
+ IN PETH_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to delete the memory associated with a filter
+ database. Note that this routines *ASSUMES* that the database
+ has been cleared of any active filters.
+
+Arguments:
+
+ Filter - A pointer to an ETH_FILTER to be deleted.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ASSERT(Filter->FreeBindingMask == (ETH_MASK)-1);
+ ASSERT(Filter->OpenList == NULL);
+
+ //
+ // Free the memory that was allocated for the current multicast
+ // address list.
+ //
+ if (Filter->MulticastAddresses)
+ {
+ FreePhys(Filter->MulticastAddresses,
+ ETH_LENGTH_OF_ADDRESS * Filter->MaximumMulticastAddresses);
+ }
+
+ //
+ // Free the memory that was allocated for the old multicast
+ // address list.
+ //
+ if (Filter->OldMulticastAddresses)
+ {
+ FreePhys(Filter->OldMulticastAddresses,
+ ETH_LENGTH_OF_ADDRESS * Filter->MaximumMulticastAddresses);
+ }
+
+ //
+ // Free the memory that we allocted for the current bindings
+ // using address mask.
+ //
+ if (Filter->BindingsUsingAddress)
+ {
+ FreePhys(Filter->BindingsUsingAddress,
+ sizeof(ETH_MASK) * Filter->MaximumMulticastAddresses);
+ }
+
+ //
+ // Free the memory that we allocted for the old bindings
+ // using address mask.
+ //
+ if (Filter->OldBindingsUsingAddress)
+ {
+ FreePhys(Filter->OldBindingsUsingAddress,
+ sizeof(ETH_MASK) * Filter->MaximumMulticastAddresses);
+ }
+
+ FreePhys(Filter, sizeof(ETH_FILTER));
+
+ EthDereferencePackage();
+}
+
+
+BOOLEAN
+EthNoteFilterOpenAdapter(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE NdisBindingContext,
+ OUT PNDIS_HANDLE NdisFilterHandle
+)
+
+/*++
+
+Routine Description:
+
+ This routine is used to add a new binding to the filter database.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE DATABASE IS LOCKED WHEN
+ IT IS CALLED.
+
+Arguments:
+
+ Filter - A pointer to the previously created and initialized filter
+ database.
+
+ MacBindingHandle - The MAC supplied value to the protocol in response
+ to a call to EthOpenAdapter.
+
+ NdisBindingContext - An NDIS supplied value to the call to EthOpenAdapter.
+
+ NdisFilterHandle - A pointer to this open.
+
+Return Value:
+
+ Will return false if creating a new filter index will cause the maximum
+ number of filter indexes to be exceeded.
+
+--*/
+
+{
+ //
+ // Will hold the value of the filter index so that we
+ // need not indirectly address through pointer parameter.
+ //
+ UINT LocalIndex;
+
+ NDIS_STATUS AllocStatus;
+
+ //
+ // Pointer to new open block.
+ //
+ PETH_BINDING_INFO LocalOpen;
+
+ PNDIS_OPEN_BLOCK NdisOpen = (PNDIS_OPEN_BLOCK)NdisBindingContext;
+
+ //
+ // Get the first free binding slot and remove that slot from
+ // the free list. We check to see if the list is empty.
+ //
+
+ if (Filter->FreeBindingMask == 0)
+ return(FALSE);
+
+ //
+ // Allocate memory for the binding.
+ //
+ AllocStatus = AllocPhys(&LocalOpen, sizeof(ETH_BINDING_INFO));
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ return(FALSE);
+
+ //
+ // Zero the memory
+ //
+ ZeroMemory(LocalOpen, sizeof(ETH_BINDING_INFO));
+
+ //
+ // Get place for the open and insert it.
+ //
+ ETH_FILTER_ALLOC_OPEN(Filter, &LocalIndex);
+
+ LocalOpen->NextOpen = Filter->OpenList;
+ Filter->OpenList = LocalOpen;
+
+ LocalOpen->References = 1;
+ LocalOpen->FilterIndex = (UCHAR)LocalIndex;
+ LocalOpen->MacBindingHandle = MacBindingHandle;
+ LocalOpen->NdisBindingContext = NdisBindingContext;
+
+ *NdisFilterHandle = (NDIS_HANDLE)LocalOpen;
+
+ return(TRUE);
+}
+
+
+NDIS_STATUS
+EthDeleteFilterOpenAdapter(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ When an adapter is being closed this routine should
+ be called to delete knowledge of the adapter from
+ the filter database. This routine is likely to call
+ action routines associated with clearing filter classes
+ and addresses.
+
+ NOTE: THIS ROUTINE SHOULD ****NOT**** BE CALLED IF THE ACTION
+ ROUTINES FOR DELETING THE FILTER CLASSES OR THE MULTICAST ADDRESSES
+ HAVE ANY POSSIBILITY OF RETURNING A STATUS OTHER THAN NDIS_STATUS_PENDING
+ OR NDIS_STATUS_SUCCESS. WHILE THESE ROUTINES WILL NOT BUGCHECK IF
+ SUCH A THING IS DONE, THE CALLER WILL PROBABLY FIND IT DIFFICULT
+ TO CODE A CLOSE ROUTINE!
+
+ NOTE: THIS ROUTINE ASSUMES THAT IT IS CALLED WITH THE LOCK HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routines,
+ this will be passed to it.
+
+Return Value:
+
+ If action routines are called by the various address and filtering
+ routines the this routine will likely return the status returned
+ by those routines. The exception to this rule is noted below.
+
+ Given that the filter and address deletion routines return a status
+ NDIS_STATUS_PENDING or NDIS_STATUS_SUCCESS this routine will then
+ try to return the filter index to the freelist. If the routine
+ detects that this binding is currently being indicated to via
+ NdisIndicateReceive, this routine will return a status of
+ NDIS_STATUS_CLOSING_INDICATING.
+
+--*/
+
+{
+ //
+ // Holds the status returned from the packet filter and address
+ // deletion routines. Will be used to return the status to
+ // the caller of this routine.
+ //
+ NDIS_STATUS StatusToReturn;
+
+ //
+ // Local variable.
+ //
+ PETH_BINDING_INFO LocalOpen = (PETH_BINDING_INFO)NdisFilterHandle;
+
+ //
+ // Set the packet filter to NONE.
+ //
+ StatusToReturn = EthFilterAdjust(Filter,
+ NdisFilterHandle,
+ NdisRequest,
+ (UINT)0,
+ FALSE);
+ if ((StatusToReturn == NDIS_STATUS_SUCCESS) ||
+ (StatusToReturn == NDIS_STATUS_PENDING))
+ {
+ NDIS_STATUS StatusToReturn2;
+
+ //
+ // Clear the multicast addresses.
+ //
+ StatusToReturn2 = EthChangeFilterAddresses(Filter,
+ NdisFilterHandle,
+ NdisRequest,
+ 0,
+ NULL,
+ FALSE);
+ if (StatusToReturn2 != NDIS_STATUS_SUCCESS)
+ {
+ StatusToReturn = StatusToReturn2;
+ }
+ }
+
+ if ((StatusToReturn == NDIS_STATUS_SUCCESS) ||
+ (StatusToReturn == NDIS_STATUS_PENDING))
+ {
+ //
+ // Remove the reference from the original open.
+ //
+ if (--(LocalOpen->References) == 0)
+ {
+ //
+ // Remove the binding from the necessary lists.
+ //
+ ethRemoveAndFreeBinding(Filter, LocalOpen, FALSE);
+ }
+ else
+ {
+ //
+ // Let the caller know that there is a reference to the open
+ // by the receive indication. The close action routine will be
+ // called upon return from NdisIndicateReceive.
+ //
+ StatusToReturn = NDIS_STATUS_CLOSING_INDICATING;
+ }
+ }
+
+ return(StatusToReturn);
+}
+
+
+VOID
+ethUndoChangeFilterAddresses(
+ IN PETH_FILTER Filter
+ )
+/*++
+
+Routine Description:
+
+ Undo changes to the ethernet filter addresses. This routine is incase
+ of a failure that went down to the driver and pended.
+
+Arguments:
+
+ Filter - Pointer to the ethernet filter database.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Restore the original number of addresses.
+ //
+ Filter->NumberOfAddresses = Filter->OldNumberOfAddresses;
+
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+ MoveMemory((PVOID)Filter->MulticastAddresses,
+ (PVOID)Filter->OldMulticastAddresses,
+ Filter->NumberOfAddresses * ETH_LENGTH_OF_ADDRESS);
+
+ MoveMemory((PVOID)Filter->BindingsUsingAddress,
+ (PVOID)Filter->OldBindingsUsingAddress,
+ Filter->NumberOfAddresses * ETH_LENGTH_OF_ADDRESS);
+}
+
+
+
+NDIS_STATUS
+EthChangeFilterAddresses(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT AddressCount,
+ IN CHAR Addresses[][ETH_LENGTH_OF_ADDRESS],
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ The ChangeFilterAddress routine will call an action
+ routine when the overall multicast address list for the adapter
+ has changed.
+
+ If the action routine returns a value other than pending or
+ success then this routine has no effect on the multicast address
+ list for the open or for the adapter as a whole.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routine,
+ this will be passed to it.
+
+ AddressCount - The number of elements (addresses,
+ not bytes) in MulticastAddressList.
+
+ Addresses - The new multicast address list for this
+ binding. This is a sequence of ETH_LENGTH_OF_ADDRESS byte
+ addresses, with no padding between them.
+
+ Set - A boolean that determines whether the multicast addresses
+ are being adjusted due to a set or because of a close. (The filtering
+ routines don't care, the MAC might.)
+
+Return Value:
+
+ If it calls the action routine then it will return the
+ status returned by the action routine. If the status
+ returned by the action routine is anything other than
+ NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
+ will be returned to the state it was in upon entrance to this
+ routine.
+
+ If the action routine is not called this routine will return
+ the following statum:
+
+ NDIS_STATUS_SUCCESS - If the new packet filters doesn't change
+ the combined mask of all bindings packet filters.
+
+--*/
+
+{
+ //
+ // Holds the status returned to the user of this routine, if the
+ // action routine is not called then the status will be success,
+ // otherwise, it is whatever the action routine returns.
+ //
+ NDIS_STATUS StatusOfChange;
+
+ //
+ // Set true when the address array changes
+ //
+ UINT AddressesChanged = 0;
+
+ //
+ // Simple iteration variables.
+ //
+ UINT ArrayIndex;
+ UINT i;
+
+ //
+ // Simple Temp variable
+ //
+ PCHAR CurrentAddress;
+
+ PETH_BINDING_INFO LocalOpen = (PETH_BINDING_INFO)NdisFilterHandle;
+
+ //
+ // We have to save the old mask array in
+ // case we need to restore it. If we need
+ // to save the address array too we will
+ // do that later.
+ //
+ MoveMemory((PVOID)Filter->OldBindingsUsingAddress,
+ (PVOID)Filter->BindingsUsingAddress,
+ Filter->NumberOfAddresses * sizeof(ETH_MASK));
+
+ //
+ // We have to save the old address array in
+ // case we need to restore it. If we need
+ // to save the address array too we will
+ // do that later.
+ //
+ MoveMemory((PVOID)Filter->OldMulticastAddresses,
+ (PVOID)Filter->MulticastAddresses,
+ Filter->NumberOfAddresses * ETH_LENGTH_OF_ADDRESS);
+
+ //
+ // Save the number of addresses.
+ //
+ Filter->OldNumberOfAddresses = Filter->NumberOfAddresses;
+
+ //
+ // Now modify the original array...
+ //
+
+ //
+ // First go through and turn off the bit for this
+ // binding throughout the array.
+ //
+ for (i = 0; i < (Filter->NumberOfAddresses); i++)
+ {
+ CLEAR_BIT_IN_MASK(LocalOpen->FilterIndex, &(Filter->BindingsUsingAddress[i]));
+ }
+
+ //
+ // First we have to remove any addresses from
+ // the multicast array if they have no bits on any more.
+ //
+ for (ArrayIndex = 0; ArrayIndex < Filter->NumberOfAddresses; )
+ {
+ if (IS_MASK_CLEAR(Filter->BindingsUsingAddress[ArrayIndex]))
+ {
+ //
+ // yes it is clear, so we have to shift everything
+ // above it down one.
+ //
+#ifdef NDIS_NT
+ MoveMemory(Filter->MulticastAddresses[ArrayIndex],
+ Filter->MulticastAddresses[ArrayIndex+1],
+ (Filter->NumberOfAddresses - (ArrayIndex+1)) * ETH_LENGTH_OF_ADDRESS);
+#else // NDIS_WIN
+ MoveOverlappedMemory(Filter->MulticastAddresses[ArrayIndex],
+ Filter->MulticastAddresses[ArrayIndex+1],
+ (Filter->NumberOfAddresses - (ArrayIndex+1)) * ETH_LENGTH_OF_ADDRESS);
+#endif
+
+#ifdef NDIS_NT
+ MoveMemory(&Filter->BindingsUsingAddress[ArrayIndex],
+ &Filter->BindingsUsingAddress[ArrayIndex+1],
+ (Filter->NumberOfAddresses - (ArrayIndex + 1)) * (sizeof(ETH_MASK)));
+#else
+ MoveOverlappedMemory(&Filter->BindingsUsingAddress[ArrayIndex],
+ &Filter->BindingsUsingAddress[ArrayIndex+1],
+ (Filter->NumberOfAddresses - (ArrayIndex + 1)) * (sizeof(ETH_MASK)));
+#endif
+
+ Filter->NumberOfAddresses--;
+ }
+ else
+ {
+ ArrayIndex++;
+ }
+ }
+
+ //
+ // Now go through the new addresses for this binding,
+ // and insert them into the array.
+ //
+ for (i = 0; i < AddressCount; i++)
+ {
+ CurrentAddress = ((PCHAR)Addresses) + (i * ETH_LENGTH_OF_ADDRESS);
+
+ if (EthFindMulticast(Filter->NumberOfAddresses,
+ Filter->MulticastAddresses,
+ CurrentAddress,
+ &ArrayIndex))
+ {
+ //
+ // The address is there, so just turn the bit
+ // back on.
+ //
+ SET_BIT_IN_MASK(
+ LocalOpen->FilterIndex,
+ &Filter->BindingsUsingAddress[ArrayIndex]);
+ }
+ else
+ {
+ //
+ // The address was not found, add it.
+ //
+ if (Filter->NumberOfAddresses < Filter->MaximumMulticastAddresses)
+ {
+ //
+ // Save the address array if it hasn't been.
+ //
+#ifdef NDIS_NT
+ MoveMemory(Filter->MulticastAddresses[ArrayIndex + 1],
+ Filter->MulticastAddresses[ArrayIndex],
+ (Filter->NumberOfAddresses - ArrayIndex) * ETH_LENGTH_OF_ADDRESS);
+#else // NDIS_WIN
+ MoveOverlappedMemory(Filter->MulticastAddresses[ArrayIndex + 1],
+ Filter->MulticastAddresses[ArrayIndex],
+ (Filter->NumberOfAddresses - ArrayIndex) * ETH_LENGTH_OF_ADDRESS);
+#endif
+
+ ETH_COPY_NETWORK_ADDRESS(Filter->MulticastAddresses[ArrayIndex], CurrentAddress);
+
+#ifdef NDIS_NT
+ MoveMemory(&(Filter->BindingsUsingAddress[ArrayIndex+1]),
+ &(Filter->BindingsUsingAddress[ArrayIndex]),
+ (Filter->NumberOfAddresses - ArrayIndex) * sizeof(ETH_MASK));
+#else // NDIS_WIN
+ MoveOverlappedMemory(&(Filter->BindingsUsingAddress[ArrayIndex+1]),
+ &(Filter->BindingsUsingAddress[ArrayIndex]),
+ (Filter->NumberOfAddresses - ArrayIndex) * sizeof(ETH_MASK));
+#endif
+
+ CLEAR_MASK(&Filter->BindingsUsingAddress[ArrayIndex]);
+
+ SET_BIT_IN_MASK(LocalOpen->FilterIndex, &Filter->BindingsUsingAddress[ArrayIndex]);
+
+ Filter->NumberOfAddresses++;
+ }
+ else
+ {
+ //
+ // No room in the array, oh well.
+ //
+ ethUndoChangeFilterAddresses(Filter);
+
+ return(NDIS_STATUS_MULTICAST_FULL);
+ }
+ }
+ }
+
+ //
+ // Check to see if address array has chnaged
+ //
+ AddressesChanged = Filter->NumberOfAddresses -
+ Filter->OldNumberOfAddresses;
+ for (i = 0;
+ (i < Filter->OldNumberOfAddresses) && (AddressesChanged == 0);
+ i++
+ )
+ {
+ ETH_COMPARE_NETWORK_ADDRESSES_EQ(Filter->MulticastAddresses[i],
+ Filter->OldMulticastAddresses[i],
+ &AddressesChanged);
+ }
+
+ //
+ // If the address array has changed, we have to call the
+ // action array to inform the adapter of this.
+ //
+ if (AddressesChanged != 0)
+ {
+ StatusOfChange = Filter->AddressChangeAction(
+ Filter->OldNumberOfAddresses,
+ Filter->OldMulticastAddresses,
+ Filter->NumberOfAddresses,
+ Filter->MulticastAddresses,
+ LocalOpen->MacBindingHandle,
+ NdisRequest,
+ Set);
+ if ((StatusOfChange != NDIS_STATUS_SUCCESS) &&
+ (StatusOfChange != NDIS_STATUS_PENDING))
+ {
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+ ethUndoChangeFilterAddresses(Filter);
+ }
+ }
+ else
+ {
+ StatusOfChange = NDIS_STATUS_SUCCESS;
+ }
+
+ return(StatusOfChange);
+}
+
+
+VOID
+ethUpdateDirectedBindingList(
+ IN OUT PETH_FILTER Filter,
+ IN PETH_BINDING_INFO Binding,
+ IN BOOLEAN fAddBindingToList
+ )
+{
+ PETH_BINDING_INFO CurrentBinding;
+ BOOLEAN AlreadyOnList;
+
+ //
+ // Do we need to add it to the directed list?
+ //
+ if (fAddBindingToList)
+ {
+ //
+ // First we need to see if it is already on the
+ // directed list.
+ //
+ for (CurrentBinding = Filter->DirectedList, AlreadyOnList = FALSE;
+ CurrentBinding != NULL;
+ CurrentBinding = CurrentBinding->NextDirected
+ )
+ {
+ if (CurrentBinding == Binding)
+ {
+ AlreadyOnList = TRUE;
+ }
+ }
+
+ if (!AlreadyOnList)
+ {
+ Binding->NextDirected = Filter->DirectedList;
+ Filter->DirectedList = Binding;
+ }
+ }
+ else
+ {
+ PETH_BINDING_INFO *ppBI;
+
+ for (ppBI = &Filter->DirectedList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextDirected)
+ {
+ if (*ppBI == Binding)
+ {
+ *ppBI = Binding->NextDirected;
+ break;
+ }
+ }
+ Binding->NextDirected = NULL;
+ }
+}
+
+
+VOID
+ethUpdateBroadcastBindingList(
+ IN OUT PETH_FILTER Filter,
+ IN PETH_BINDING_INFO Binding,
+ IN BOOLEAN fAddToList
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PETH_BINDING_INFO CurrentBinding;
+ BOOLEAN AlreadyOnList;
+
+ //
+ // Do we need to add it to the directed list?
+ //
+ if (fAddToList)
+ {
+ //
+ // First we need to see if it is already on the
+ // broadcast/multicast list.
+ //
+ for (CurrentBinding = Filter->BMList, AlreadyOnList = FALSE;
+ CurrentBinding != NULL;
+ CurrentBinding = CurrentBinding->NextBM
+ )
+ {
+ if (CurrentBinding == Binding)
+ {
+ AlreadyOnList = TRUE;
+ }
+ }
+
+ if (!AlreadyOnList)
+ {
+ Binding->NextBM = Filter->BMList;
+ Filter->BMList = Binding;
+ }
+ }
+ else
+ {
+ PETH_BINDING_INFO *ppBI;
+
+ for (ppBI = &Filter->BMList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextBM)
+ {
+ if (*ppBI == Binding)
+ {
+ *ppBI = Binding->NextBM;
+ break;
+ }
+ }
+
+ Binding->NextBM = NULL;
+ }
+}
+
+
+VOID
+ethUpdateSpecificBindingLists(
+ IN OUT PETH_FILTER Filter,
+ IN PETH_BINDING_INFO Binding
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ BOOLEAN fOnDirectedList = FALSE;
+ BOOLEAN fOnBMList = FALSE;
+ BOOLEAN fAddToDirectedList = FALSE;
+ BOOLEAN fAddToBMList = FALSE;
+
+ //
+ // If the old filter is promsicuous then it is currently on
+ // both lists.
+ //
+ if (Binding->OldPacketFilters & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL))
+ {
+ fOnDirectedList = TRUE;
+ fOnBMList = TRUE;
+ }
+ else
+ {
+ //
+ // If the binding had the directed bit set then it is on
+ // the directed list.
+ //
+ if (Binding->OldPacketFilters & NDIS_PACKET_TYPE_DIRECTED)
+ {
+ fOnDirectedList = TRUE;
+ }
+
+ //
+ // If the binding had the broadcast bit set then it is on
+ // the broadcast list.
+ //
+ if (Binding->OldPacketFilters & (NDIS_PACKET_TYPE_BROADCAST |
+ NDIS_PACKET_TYPE_MULTICAST |
+ NDIS_PACKET_TYPE_ALL_MULTICAST))
+ {
+ fOnBMList = TRUE;
+ }
+ }
+
+ //
+ // If the current filter has the promsicuous bit set then we
+ // need to add it to both lists.
+ //
+ if (Binding->PacketFilters & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL))
+ {
+ fAddToDirectedList = TRUE;
+ fAddToBMList = TRUE;
+ }
+ else
+ {
+ //
+ // Was the directed bit set?
+ //
+ if (Binding->PacketFilters & NDIS_PACKET_TYPE_DIRECTED)
+ {
+ fAddToDirectedList = TRUE;
+ }
+
+ //
+ // Was the broadcast bit set?
+ //
+ if (Binding->PacketFilters & (NDIS_PACKET_TYPE_BROADCAST |
+ NDIS_PACKET_TYPE_MULTICAST |
+ NDIS_PACKET_TYPE_ALL_MULTICAST))
+ {
+ fAddToBMList = TRUE;
+ }
+ }
+
+ //
+ // Determine if the binding should be added or removed from
+ // the directed list.
+ //
+ if (!fOnDirectedList && fAddToDirectedList)
+ {
+ //
+ // Add the binding to the directed list.
+ //
+ ethUpdateDirectedBindingList(Filter, Binding, TRUE);
+ }
+ else if (fOnDirectedList && !fAddToDirectedList)
+ {
+ //
+ // Remove it from the directed list.
+ //
+ ethUpdateDirectedBindingList(Filter, Binding, FALSE);
+ }
+
+ //
+ // Determine if the binding should be added or removed from
+ // the broadcast list.
+ //
+ if (!fOnBMList && fAddToBMList)
+ {
+ //
+ // Add the binding to the broadcast list.
+ //
+ ethUpdateBroadcastBindingList(Filter, Binding, TRUE);
+ }
+ else if (fOnBMList && !fAddToBMList)
+ {
+ //
+ // Remove the binding from the broadcast list.
+ //
+ ethUpdateBroadcastBindingList(Filter, Binding, FALSE);
+ }
+}
+
+
+VOID
+ethUndoFilterAdjust(
+ IN PETH_FILTER Filter,
+ IN PETH_BINDING_INFO Binding
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ Binding->PacketFilters = Binding->OldPacketFilters;
+ Filter->CombinedPacketFilter = Filter->OldCombinedPacketFilter;
+
+ //
+ // Update the filter lists.
+ //
+ ethUpdateSpecificBindingLists(Filter, Binding);
+}
+
+
+NDIS_STATUS
+EthFilterAdjust(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT FilterClasses,
+ IN BOOLEAN Set
+)
+
+/*++
+
+Routine Description:
+
+ The FilterAdjust routine will call an action routine when a
+ particular filter class is changed from not being used by any
+ binding to being used by at least one binding or vice versa.
+
+ If the action routine returns a value other than pending or
+ success then this routine has no effect on the packet filters
+ for the open or for the adapter as a whole.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - A pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routine,
+ this will be passed to it.
+
+ FilterClasses - The filter classes that are to be added or
+ deleted.
+
+ Set - A boolean that determines whether the filter classes
+ are being adjusted due to a set or because of a close. (The filtering
+ routines don't care, the MAC might.)
+
+Return Value:
+
+ If it calls the action routine then it will return the
+ status returned by the action routine. If the status
+ returned by the action routine is anything other than
+ NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
+ will be returned to the state it was in upon entrance to this
+ routine.
+
+ If the action routine is not called this routine will return
+ the following statum:
+
+ NDIS_STATUS_SUCCESS - If the new packet filters doesn't change
+ the combined mask of all bindings packet filters.
+
+--*/
+
+{
+ PETH_BINDING_INFO LocalOpen = (PETH_BINDING_INFO)NdisFilterHandle;
+ PETH_BINDING_INFO OpenList;
+
+ //
+ // Holds the status returned to the user of this routine, if the
+ // action routine is not called then the status will be success,
+ // otherwise, it is whatever the action routine returns.
+ //
+ NDIS_STATUS StatusOfAdjust;
+
+ //
+ // Set the new filter information for the open.
+ //
+ LocalOpen->OldPacketFilters = LocalOpen->PacketFilters;
+ LocalOpen->PacketFilters = FilterClasses;
+
+ Filter->OldCombinedPacketFilter = Filter->CombinedPacketFilter;
+
+ //
+ // We always have to reform the combined filter since
+ // this filter index may have been the only filter index
+ // to use a particular bit.
+ //
+ for (OpenList = Filter->OpenList, Filter->CombinedPacketFilter = 0;
+ OpenList != NULL;
+ OpenList = OpenList->NextOpen)
+ {
+ Filter->CombinedPacketFilter |= OpenList->PacketFilters;
+ }
+
+ //
+ // Update the filter lists.
+ //
+ ethUpdateSpecificBindingLists(Filter, LocalOpen);
+
+ if ((Filter->OldCombinedPacketFilter & ~NDIS_PACKET_TYPE_ALL_LOCAL) !=
+ (Filter->CombinedPacketFilter & ~NDIS_PACKET_TYPE_ALL_LOCAL))
+ {
+ StatusOfAdjust = Filter->FilterChangeAction(
+ Filter->OldCombinedPacketFilter & ~NDIS_PACKET_TYPE_ALL_LOCAL,
+ Filter->CombinedPacketFilter & ~NDIS_PACKET_TYPE_ALL_LOCAL,
+ LocalOpen->MacBindingHandle,
+ NdisRequest,
+ Set);
+ if ((StatusOfAdjust != NDIS_STATUS_SUCCESS) &&
+ (StatusOfAdjust != NDIS_STATUS_PENDING))
+ {
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+ ethUndoFilterAdjust(Filter, LocalOpen);
+ }
+ }
+ else
+ {
+ StatusOfAdjust = NDIS_STATUS_SUCCESS;
+ }
+
+ return(StatusOfAdjust);
+}
+
+
+UINT
+EthNumberOfOpenFilterAddresses(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine counts the number of multicast addresses that a specific
+ open has.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to open block.
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UINT IndexOfAddress;
+ UINT CountOfAddresses;
+
+ UINT FilterIndex = ((PETH_BINDING_INFO)NdisFilterHandle)->FilterIndex;
+
+ for (IndexOfAddress = 0, CountOfAddresses = 0;
+ IndexOfAddress < Filter->NumberOfAddresses;
+ IndexOfAddress++)
+ {
+ if (IS_BIT_SET_IN_MASK(
+ FilterIndex,
+ Filter->BindingsUsingAddress[IndexOfAddress])
+ )
+ {
+ CountOfAddresses++;
+ }
+ }
+
+ return(CountOfAddresses);
+}
+
+
+VOID
+EthQueryOpenFilterAddresses(
+ OUT PNDIS_STATUS Status,
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN UINT SizeOfArray,
+ OUT PUINT NumberOfAddresses,
+ OUT CHAR AddressArray[][ETH_LENGTH_OF_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ The routine should be used by the MAC before
+ it actually alters the hardware registers to effect a
+ filtering hardware. This is usefull if another binding
+ has altered the address list since the action routine
+ is called.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Status - A pointer to the status of the call, NDIS_STATUS_SUCCESS or
+ NDIS_STATUS_FAILURE. Use EthNumberOfOpenAddresses() to get the
+ size that is needed.
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to the open block
+
+ SizeOfArray - The byte count of the AddressArray.
+
+ NumberOfAddresses - The number of addresses written to the array.
+
+ AddressArray - Will be filled with the addresses currently in the
+ multicast address list.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UINT IndexOfAddress;
+ UINT CountOfAddresses;
+ UINT FilterIndex = ((PETH_BINDING_INFO)NdisFilterHandle)->FilterIndex;
+
+ for (IndexOfAddress = 0, CountOfAddresses = 0;
+ IndexOfAddress < Filter->NumberOfAddresses;
+ IndexOfAddress++)
+ {
+ if (IS_BIT_SET_IN_MASK(
+ FilterIndex,
+ Filter->BindingsUsingAddress[IndexOfAddress]))
+ {
+ if (SizeOfArray < ETH_LENGTH_OF_ADDRESS)
+ {
+ *Status = NDIS_STATUS_FAILURE;
+ *NumberOfAddresses = 0;
+
+ return;
+ }
+
+ SizeOfArray -= ETH_LENGTH_OF_ADDRESS;
+
+ MoveMemory(AddressArray[CountOfAddresses],
+ Filter->MulticastAddresses[IndexOfAddress],
+ ETH_LENGTH_OF_ADDRESS);
+
+ CountOfAddresses++;
+ }
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ *NumberOfAddresses = CountOfAddresses;
+}
+
+
+VOID
+EthQueryGlobalFilterAddresses(
+ OUT PNDIS_STATUS Status,
+ IN PETH_FILTER Filter,
+ IN UINT SizeOfArray,
+ OUT PUINT NumberOfAddresses,
+ IN OUT CHAR AddressArray[][ETH_LENGTH_OF_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ The routine should be used by the MAC before
+ it actually alters the hardware registers to effect a
+ filtering hardware. This is usefull if another binding
+ has altered the address list since the action routine
+ is called.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Status - A pointer to the status of the call, NDIS_STATUS_SUCCESS or
+ NDIS_STATUS_FAILURE. Use ETH_NUMBER_OF_GLOBAL_ADDRESSES() to get the
+ size that is needed.
+
+ Filter - A pointer to the filter database.
+
+ SizeOfArray - The byte count of the AddressArray.
+
+ NumberOfAddresses - A pointer to the number of addresses written to the
+ array.
+
+ AddressArray - Will be filled with the addresses currently in the
+ multicast address list.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if (SizeOfArray < (Filter->NumberOfAddresses * ETH_LENGTH_OF_ADDRESS))
+ {
+ *Status = NDIS_STATUS_FAILURE;
+ *NumberOfAddresses = 0;
+ }
+ else
+ {
+ *Status = NDIS_STATUS_SUCCESS;
+ *NumberOfAddresses = Filter->NumberOfAddresses;
+
+ MoveMemory(AddressArray[0],
+ Filter->MulticastAddresses[0],
+ Filter->NumberOfAddresses*ETH_LENGTH_OF_ADDRESS);
+ }
+}
+
+
+VOID
+EthFilterDprIndicateReceiveFullMac(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PCHAR Address,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+)
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate a packet to
+ all bindings. The packet will be filtered so that only the
+ appropriate bindings will receive the packet. This is the
+ code path for ndis 3.0 miniport drivers.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ MacReceiveContext - A MAC supplied context value that must be
+ returned by the protocol if it calls MacTransferData.
+
+ Address - The destination address from the received packet.
+
+ HeaderBuffer - A virtual address of the virtually contiguous
+ buffer containing the MAC header of the packet.
+
+ HeaderBufferSize - An unsigned integer indicating the size of
+ the header buffer, in bytes.
+
+ LookaheadBuffer - A virtual address of the virtually contiguous
+ buffer containing the first LookaheadBufferSize bytes of data
+ of the packet. The packet buffer is valid only within the current
+ call to the receive event handler.
+
+ LookaheadBufferSize - An unsigned integer indicating the size of
+ the lookahead buffer, in bytes.
+
+ PacketSize - An unsigned integer indicating the size of the received
+ packet, in bytes. This number has nothing to do with the lookahead
+ buffer, but indicates how large the arrived packet is so that a
+ subsequent MacTransferData request can be made to transfer the entire
+ packet as necessary.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Will hold the type of address that we know we've got.
+ //
+ UINT AddressType;
+
+ //
+ // Will hold the status of indicating the receive packet.
+ // ZZZ For now this isn't used.
+ //
+ NDIS_STATUS StatusOfReceive;
+
+ //
+ // Will hold the filter classes of the binding being indicated.
+ //
+ UINT BindingFilters;
+
+ //
+ // Current Open to indicate to.
+ //
+ PETH_BINDING_INFO LocalOpen;
+ PETH_BINDING_INFO NextOpen;
+
+ //
+ // If the packet is a runt packet, then only indicate to PROMISCUOUS, ALL_LOCAL
+ //
+ if ((HeaderBufferSize >= 14) && (PacketSize != 0))
+ {
+ //
+ // Handle the directed packet case first
+ //
+ if (!ETH_IS_MULTICAST(Address))
+ {
+ UINT IsNotOurs;
+
+ //
+ // If it is a directed packet, then check if the combined packet
+ // filter is PROMISCUOUS, if it is check if it is directed towards
+ // us
+ //
+ IsNotOurs = FALSE; // Assume it is
+ if (Filter->CombinedPacketFilter & (NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_ALL_MULTICAST |
+ NDIS_PACKET_TYPE_ALL_LOCAL))
+ {
+ ETH_COMPARE_NETWORK_ADDRESSES_EQ(Filter->AdapterAddress,
+ Address,
+ &IsNotOurs);
+ }
+
+ //
+ // We definitely have a directed packet so lets indicate it now.
+ //
+ // Walk the directed list and indicate up the packets.
+ //
+ for (LocalOpen = Filter->DirectedList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextDirected;
+
+ //
+ // Ignore if not directed to us and if the binding is not promiscuous
+ //
+ if (((LocalOpen->PacketFilters & NDIS_PACKET_TYPE_PROMISCUOUS) == 0) &&
+ IsNotOurs)
+ {
+ continue;
+ }
+
+ LocalOpen->References++;
+
+ NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ //
+ // Indicate the packet to the binding.
+ //
+ ProtocolFilterIndicateReceive(&StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize,
+ NdisMedium802_3);
+
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ --LocalOpen->References;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+ ethRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+
+ return;
+ }
+
+ //
+ // It is at least a multicast address. Check to see if
+ // it is a broadcast address.
+ //
+ if (ETH_IS_BROADCAST(Address))
+ {
+ ETH_CHECK_FOR_INVALID_BROADCAST_INDICATION(Filter);
+
+ AddressType = NDIS_PACKET_TYPE_BROADCAST;
+ }
+ else
+ {
+ AddressType = NDIS_PACKET_TYPE_MULTICAST;
+ }
+ }
+ else
+ {
+ // Runt packet
+ AddressType = NDIS_PACKET_TYPE_PROMISCUOUS;
+ }
+
+ //
+ // At this point we know that the packet is either:
+ // - Runt packet - indicated by AddressType = NDIS_PACKET_TYPE_PROMISCUOUS (OR)
+ // - Broadcast packet - indicated by AddressType = NDIS_PACKET_TYPE_BROADCAST (OR)
+ // - Multicast packet - indicated by AddressType = NDIS_PACKET_TYPE_MULTICAST
+ //
+ // Walk the broadcast/multicast list and indicate up the packets.
+ //
+ // The packet is indicated if it meets the following criteria:
+ //
+ // if ((Binding is promiscuous) OR
+ // ((Packet is broadcast) AND (Binding is Broadcast)) OR
+ // ((Packet is multicast) AND
+ // ((Binding is all-multicast) OR
+ // ((Binding is multicast) AND (address in multicast list)))))
+ //
+ for (LocalOpen = Filter->BMList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ UINT LocalFilter = LocalOpen->PacketFilters;
+ UINT IndexOfAddress;
+
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextBM;
+
+ if ((LocalFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_BROADCAST) &&
+ (LocalFilter & NDIS_PACKET_TYPE_BROADCAST)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_MULTICAST) &&
+ ((LocalFilter & NDIS_PACKET_TYPE_ALL_MULTICAST) ||
+ ((LocalFilter & NDIS_PACKET_TYPE_MULTICAST) &&
+ EthFindMulticast(Filter->NumberOfAddresses,
+ Filter->MulticastAddresses,
+ Address,
+ &IndexOfAddress) &&
+ IS_BIT_SET_IN_MASK(
+ LocalOpen->FilterIndex,
+ Filter->BindingsUsingAddress[IndexOfAddress])
+ )
+ )
+ )
+ )
+ {
+ LocalOpen->References++;
+
+ NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ //
+ // Indicate the packet to the binding.
+ //
+
+ ProtocolFilterIndicateReceive(&StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize,
+ NdisMedium802_3);
+
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ --LocalOpen->References;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+ ethRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+ }
+}
+
+
+VOID
+EthFilterIndicateReceive(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PCHAR Address,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+)
+{
+ KIRQL OldIrql;
+
+ NDIS_ACQUIRE_SPIN_LOCK(Filter->Lock, &OldIrql);
+
+ EthFilterDprIndicateReceiveFullMac(Filter,
+ MacReceiveContext,
+ Address,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize);
+
+ NDIS_RELEASE_SPIN_LOCK(Filter->Lock, OldIrql);
+}
+
+
+VOID
+EthFilterDprIndicateReceive(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PCHAR Address,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+)
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate a packet to
+ all bindings. The packet will be filtered so that only the
+ appropriate bindings will receive the packet. This is the
+ code path for ndis 3.0 miniport drivers.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ MacReceiveContext - A MAC supplied context value that must be
+ returned by the protocol if it calls MacTransferData.
+
+ Address - The destination address from the received packet.
+
+ HeaderBuffer - A virtual address of the virtually contiguous
+ buffer containing the MAC header of the packet.
+
+ HeaderBufferSize - An unsigned integer indicating the size of
+ the header buffer, in bytes.
+
+ LookaheadBuffer - A virtual address of the virtually contiguous
+ buffer containing the first LookaheadBufferSize bytes of data
+ of the packet. The packet buffer is valid only within the current
+ call to the receive event handler.
+
+ LookaheadBufferSize - An unsigned integer indicating the size of
+ the lookahead buffer, in bytes.
+
+ PacketSize - An unsigned integer indicating the size of the received
+ packet, in bytes. This number has nothing to do with the lookahead
+ buffer, but indicates how large the arrived packet is so that a
+ subsequent MacTransferData request can be made to transfer the entire
+ packet as necessary.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Will hold the type of address that we know we've got.
+ //
+ UINT AddressType;
+
+ //
+ // Will hold the status of indicating the receive packet.
+ // ZZZ For now this isn't used.
+ //
+ NDIS_STATUS StatusOfReceive;
+
+ //
+ // Will hold the filter classes of the binding being indicated.
+ //
+ UINT BindingFilters;
+
+ //
+ // Current Open to indicate to.
+ //
+ PETH_BINDING_INFO LocalOpen;
+ PETH_BINDING_INFO NextOpen;
+
+ //
+ // If the packet is a runt packet, then only indicate to PROMISCUOUS, ALL_LOCAL
+ //
+ if ((HeaderBufferSize >= 14) && (PacketSize != 0))
+ {
+ //
+ // Handle the directed packet case first
+ //
+ if (!ETH_IS_MULTICAST(Address))
+ {
+ UINT IsNotOurs;
+
+ //
+ // If it is a directed packet, then check if the combined packet
+ // filter is PROMISCUOUS, if it is check if it is directed towards
+ // us
+ //
+ IsNotOurs = FALSE; // Assume it is
+ if (Filter->CombinedPacketFilter & (NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_ALL_MULTICAST |
+ NDIS_PACKET_TYPE_ALL_LOCAL))
+ {
+ ETH_COMPARE_NETWORK_ADDRESSES_EQ(Filter->AdapterAddress,
+ Address,
+ &IsNotOurs);
+ }
+
+ //
+ // We definitely have a directed packet so lets indicate it now.
+ //
+ // Walk the directed list and indicate up the packets.
+ //
+ for (LocalOpen = Filter->DirectedList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextDirected;
+
+ //
+ // Ignore if not directed to us and if the binding is not promiscuous
+ //
+ if (((LocalOpen->PacketFilters & NDIS_PACKET_TYPE_PROMISCUOUS) == 0) &&
+ IsNotOurs)
+ {
+ continue;
+ }
+
+ LocalOpen->References++;
+
+// NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ //
+ // Indicate the packet to the binding.
+ //
+ ProtocolFilterIndicateReceive(&StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize,
+ NdisMedium802_3);
+
+// NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ --LocalOpen->References;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+ ethRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+
+ return;
+ }
+
+ //
+ // It is at least a multicast address. Check to see if
+ // it is a broadcast address.
+ //
+ if (ETH_IS_BROADCAST(Address))
+ {
+ ETH_CHECK_FOR_INVALID_BROADCAST_INDICATION(Filter);
+
+ AddressType = NDIS_PACKET_TYPE_BROADCAST;
+ }
+ else
+ {
+ AddressType = NDIS_PACKET_TYPE_MULTICAST;
+ }
+ }
+ else
+ {
+ // Runt packet
+ AddressType = NDIS_PACKET_TYPE_PROMISCUOUS;
+ }
+
+ //
+ // At this point we know that the packet is either:
+ // - Runt packet - indicated by AddressType = NDIS_PACKET_TYPE_PROMISCUOUS (OR)
+ // - Broadcast packet - indicated by AddressType = NDIS_PACKET_TYPE_BROADCAST (OR)
+ // - Multicast packet - indicated by AddressType = NDIS_PACKET_TYPE_MULTICAST
+ //
+ // Walk the broadcast/multicast list and indicate up the packets.
+ //
+ // The packet is indicated if it meets the following criteria:
+ //
+ // if ((Binding is promiscuous) OR
+ // ((Packet is broadcast) AND (Binding is Broadcast)) OR
+ // ((Packet is multicast) AND
+ // ((Binding is all-multicast) OR
+ // ((Binding is multicast) AND (address in multicast list)))))
+ //
+ for (LocalOpen = Filter->BMList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ UINT LocalFilter = LocalOpen->PacketFilters;
+ UINT IndexOfAddress;
+
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextBM;
+
+ if ((LocalFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_BROADCAST) &&
+ (LocalFilter & NDIS_PACKET_TYPE_BROADCAST)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_MULTICAST) &&
+ ((LocalFilter & NDIS_PACKET_TYPE_ALL_MULTICAST) ||
+ ((LocalFilter & NDIS_PACKET_TYPE_MULTICAST) &&
+ EthFindMulticast(Filter->NumberOfAddresses,
+ Filter->MulticastAddresses,
+ Address,
+ &IndexOfAddress) &&
+ IS_BIT_SET_IN_MASK(
+ LocalOpen->FilterIndex,
+ Filter->BindingsUsingAddress[IndexOfAddress])
+ )
+ )
+ )
+ )
+ {
+ LocalOpen->References++;
+
+// NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ //
+ // Indicate the packet to the binding.
+ //
+
+ ProtocolFilterIndicateReceive(&StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize,
+ NdisMedium802_3);
+
+// NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ --LocalOpen->References;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+ ethRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+ }
+}
+
+
+
+VOID
+EthFilterDprIndicateReceivePacket(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+)
+
+/*++
+
+Routine Description:
+
+ This routine is called by the Miniport to indicate packets to
+ all bindings. The packets will be filtered so that only the
+ appropriate bindings will receive the individual packets.
+ This is the code path for ndis 4.0 miniport drivers.
+
+Arguments:
+
+ Miniport - The Miniport block.
+
+ PacketArray - An array of Packets indicated by the miniport.
+
+ NumberOfPackets - Self-explanatory.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // The Filter of interest
+ //
+ PETH_FILTER Filter = Miniport->EthDB;
+
+ //
+ // Current packet being processed
+ //
+ PPNDIS_PACKET pPktArray = PacketArray;
+
+ //
+ // Pointer to the buffer in the ndispacket
+ //
+ PNDIS_BUFFER Buffer;
+
+ //
+ // Pointer to the 1st segment of the buffer, points to dest address
+ //
+ PUCHAR Address;
+
+ //
+ // Total packet length
+ //
+ UINT i, LASize, PacketSize, NumIndicates = 0;
+
+ //
+ // Will hold the type of address that we know we've got.
+ //
+ UINT AddressType;
+
+ //
+ // Will hold the status of indicating the receive packet.
+ // ZZZ For now this isn't used.
+ //
+ NDIS_STATUS StatusOfReceive;
+
+ //
+ // Will hold the filter classes of the binding being indicated.
+ //
+ UINT BindingFilters;
+
+ //
+ // Decides whether we use the protocol's revpkt handler or fall
+ // back to old rcvindicate handler
+ //
+ BOOLEAN fFallBack, fPmode, FixRef;
+
+ //
+ // Current Open to indicate to.
+ //
+ PETH_BINDING_INFO LocalOpen, NextOpen;
+ PNDIS_OPEN_BLOCK pOpenBlock; \
+
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID);
+
+ // Walk all the packets
+ for (i = 0; i < NumberOfPackets; i++, pPktArray++)
+ {
+ PNDIS_PACKET Packet = *pPktArray;
+ PNDIS_PACKET_OOB_DATA pOob;
+
+ ASSERT(Packet != NULL);
+
+ pOob = NDIS_OOB_DATA_FROM_PACKET(Packet);
+
+ NdisGetFirstBufferFromPacket(Packet,
+ &Buffer,
+ &Address,
+ &LASize,
+ &PacketSize);
+ ASSERT(Buffer != NULL);
+
+ ASSERT (pOob->HeaderSize == 14);
+ ASSERT (PacketSize <= 1514);
+
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount = 0;
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->Miniport = Miniport;
+
+ //
+ // Set the status here that nobody is holding the packet. This will get
+ // overwritten by the real status from the protocol. Pay heed to what
+ // the miniport is saying.
+ //
+ if (pOob->Status != NDIS_STATUS_RESOURCES)
+ {
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount --;
+ pOob->Status = NDIS_STATUS_SUCCESS;
+ fFallBack = FALSE;
+ FixRef = TRUE;
+ }
+ else
+ {
+ fFallBack = TRUE;
+ FixRef = FALSE;
+ }
+
+ //
+ // Ensure that we force re-calculation.
+ //
+ Packet->Private.ValidCounts = FALSE;
+
+ //
+ // A quick check for Runt packets. These are only indicated to Promiscuous bindings
+ //
+ if (PacketSize >= 14)
+ {
+ //
+ // Handle the directed packet case first
+ //
+ if (!ETH_IS_MULTICAST(Address))
+ {
+ UINT IsNotOurs;
+
+ //
+ // If it is a directed packet, then check if the combined packet
+ // filter is PROMISCUOUS, if it is check if it is directed towards us
+ //
+ IsNotOurs = FALSE; // Assume it is
+ if (Filter->CombinedPacketFilter & (NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_ALL_LOCAL |
+ NDIS_PACKET_TYPE_ALL_MULTICAST))
+ {
+ ETH_COMPARE_NETWORK_ADDRESSES_EQ(Filter->AdapterAddress,
+ Address,
+ &IsNotOurs);
+ }
+
+ //
+ // We definitely have a directed packet so lets indicate it now.
+ //
+ // Walk the directed list and indicate up the packets.
+ //
+ for (LocalOpen = Filter->DirectedList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextDirected;
+
+ //
+ // Ignore if not directed to us and if the binding is not promiscuous
+ //
+ if (((LocalOpen->PacketFilters & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) == 0) &&
+ IsNotOurs)
+ {
+ continue;
+ }
+
+ pOpenBlock = (PNDIS_OPEN_BLOCK)(LocalOpen->NdisBindingContext);
+ LocalOpen->ReceivedAPacket = TRUE;
+ LocalOpen->References ++;
+ NumIndicates ++;
+
+ fPmode = (LocalOpen->PacketFilters & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) ?
+ TRUE : FALSE;
+ IndicateToProtocol(Miniport,
+ Filter,
+ pOpenBlock,
+ Packet,
+ Address,
+ PacketSize,
+ 14,
+ &fFallBack,
+ fPmode,
+ NdisMedium802_3);
+
+ LocalOpen->References --;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+ ethRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+
+ if (FixRef)
+ {
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount++;
+ if (PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount != 0)
+ {
+ NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_PENDING);
+ }
+ }
+ continue; // Done with this packet
+ }
+
+ //
+ // It is at least a multicast address. Check to see if
+ // it is a broadcast address.
+ //
+ if (ETH_IS_BROADCAST(Address))
+ {
+ ETH_CHECK_FOR_INVALID_BROADCAST_INDICATION(Filter);
+
+ AddressType = NDIS_PACKET_TYPE_BROADCAST;
+ }
+ else
+ {
+ AddressType = NDIS_PACKET_TYPE_MULTICAST;
+ }
+ }
+ else
+ {
+ // Runt packet
+ AddressType = NDIS_PACKET_TYPE_PROMISCUOUS;
+ }
+
+ //
+ // At this point we know that the packet is either:
+ // - Runt packet - indicated by AddressType = NDIS_PACKET_TYPE_PROMISCUOUS (OR)
+ // - Broadcast packet - indicated by AddressType = NDIS_PACKET_TYPE_BROADCAST (OR)
+ // - Multicast packet - indicated by AddressType = NDIS_PACKET_TYPE_MULTICAST
+ //
+ // Walk the broadcast/multicast list and indicate up the packets.
+ //
+ // The packet is indicated if it meets the following criteria:
+ //
+ // if ((Binding is promiscuous) OR
+ // ((Packet is broadcast) AND (Binding is Broadcast)) OR
+ // ((Packet is multicast) AND
+ // ((Binding is all-multicast) OR
+ // ((Binding is multicast) AND (address in multicast list)))))
+ //
+ for (LocalOpen = Filter->BMList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ UINT LocalFilter = LocalOpen->PacketFilters;
+ UINT IndexOfAddress;
+
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextBM;
+
+ if ((LocalFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_BROADCAST) &&
+ (LocalFilter & NDIS_PACKET_TYPE_BROADCAST)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_MULTICAST) &&
+ ((LocalFilter & NDIS_PACKET_TYPE_ALL_MULTICAST) ||
+ ((LocalFilter & NDIS_PACKET_TYPE_MULTICAST) &&
+ EthFindMulticast(Filter->NumberOfAddresses,
+ Filter->MulticastAddresses,
+ Address,
+ &IndexOfAddress) &&
+ IS_BIT_SET_IN_MASK(
+ LocalOpen->FilterIndex,
+ Filter->BindingsUsingAddress[IndexOfAddress])
+ )
+ )
+ )
+ )
+ {
+ pOpenBlock = (PNDIS_OPEN_BLOCK)(LocalOpen->NdisBindingContext);
+ LocalOpen->ReceivedAPacket = TRUE;
+ LocalOpen->References ++;
+ NumIndicates ++;
+
+ fPmode = (LocalFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) ?
+ TRUE : FALSE;
+ IndicateToProtocol(Miniport,
+ Filter,
+ pOpenBlock,
+ Packet,
+ Address,
+ PacketSize,
+ 14,
+ &fFallBack,
+ fPmode,
+ NdisMedium802_3);
+
+ LocalOpen->References --;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+ ethRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+ }
+
+ if (FixRef)
+ {
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount++;
+ if (PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount != 0)
+ {
+ NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_PENDING);
+ }
+ }
+ }
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID);
+
+ if (NumIndicates > 0)
+ {
+ EthFilterDprIndicateReceiveComplete(Filter);
+ }
+}
+
+
+
+VOID
+EthFilterDprIndicateReceiveCompleteFullMac(
+ IN PETH_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate that the receive
+ process is complete to all bindings. Only those bindings which
+ have received packets will be notified.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PETH_BINDING_INFO LocalOpen, NextOpen;
+
+ //
+ // We need to aquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+
+ for (LocalOpen = Filter->OpenList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ NextOpen = LocalOpen->NextOpen;
+
+ if (LocalOpen->ReceivedAPacket)
+ {
+ //
+ // Indicate the binding.
+ //
+
+ LocalOpen->ReceivedAPacket = FALSE;
+
+ LocalOpen->References++;
+
+ NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ if ((--(LocalOpen->References)) == 0)
+ {
+ //
+ // This binding is shutting down. We have to kill it.
+ //
+ ethRemoveBindingFromLists(Filter, LocalOpen);
+
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+ Filter->CloseAction(LocalOpen->MacBindingHandle);
+
+ ETH_FILTER_FREE_OPEN(Filter, LocalOpen);
+ }
+ }
+ }
+}
+
+
+VOID
+EthFilterIndicateReceiveComplete(
+ IN PETH_FILTER Filter
+ )
+{
+ KIRQL OldIrql;
+
+ NDIS_ACQUIRE_SPIN_LOCK(Filter->Lock, &OldIrql);
+
+ EthFilterDprIndicateReceiveCompleteFullMac(Filter);
+
+ NDIS_RELEASE_SPIN_LOCK(Filter->Lock, OldIrql);
+}
+
+
+
+VOID
+EthFilterDprIndicateReceiveComplete(
+ IN PETH_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate that the receive
+ process is complete to all bindings. Only those bindings which
+ have received packets will be notified.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PETH_BINDING_INFO LocalOpen, NextOpen;
+
+ //
+ // We need to aquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+
+ for (LocalOpen = Filter->OpenList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ NextOpen = LocalOpen->NextOpen;
+
+ if (LocalOpen->ReceivedAPacket)
+ {
+ //
+ // Indicate the binding.
+ //
+
+ LocalOpen->ReceivedAPacket = FALSE;
+
+ LocalOpen->References++;
+
+// NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+// NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ if ((--(LocalOpen->References)) == 0)
+ {
+ //
+ // This binding is shutting down. We have to kill it.
+ //
+ ethRemoveBindingFromLists(Filter, LocalOpen);
+
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+ Filter->CloseAction(LocalOpen->MacBindingHandle);
+
+ ETH_FILTER_FREE_OPEN(Filter, LocalOpen);
+ }
+ }
+ }
+}
+
+
+BOOLEAN
+EthFindMulticast(
+ IN UINT NumberOfAddresses,
+ IN CHAR AddressArray[][ETH_LENGTH_OF_ADDRESS],
+ IN CHAR MulticastAddress[ETH_LENGTH_OF_ADDRESS],
+ OUT PUINT ArrayIndex
+ )
+
+/*++
+
+Routine Description:
+
+ Given an array of multicast addresses search the array for
+ a particular multicast address. It is assumed that the
+ address array is already sorted.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+ NOTE: This ordering is arbitrary but consistant.
+
+Arguments:
+
+ NumberOfAddresses - The number of addresses currently in the
+ address array.
+
+ AddressArray - An array of multicast addresses.
+
+ MulticastAddress - The address to search for in the address array.
+
+ ArrayIndex - Will point to where the MulticastAddress is in
+ the AddressArray, or if it isn't in the array, where it should
+ be in the array.
+
+Return Value:
+
+ If the address is in the sorted list this routine will return
+ TRUE, otherwise FALSE.
+
+--*/
+
+{
+ //
+ // Indices into the address array so that we may do a binary
+ // search.
+ //
+ UINT Bottom = 0;
+ UINT Middle = NumberOfAddresses / 2;
+ UINT Top;
+
+ if (NumberOfAddresses)
+ {
+ Top = NumberOfAddresses - 1;
+
+ while ((Middle <= Top) && (Middle >= Bottom))
+ {
+ //
+ // The result of comparing an element of the address
+ // array and the multicast address.
+ //
+ // Result < 0 Implies the multicast address is greater.
+ // Result > 0 Implies the address array element is greater.
+ // Result = 0 Implies that the array element and the address
+ // are equal.
+ //
+ INT Result;
+
+ ETH_COMPARE_NETWORK_ADDRESSES(
+ AddressArray[Middle],
+ MulticastAddress,
+ &Result);
+
+ if (Result == 0)
+ {
+ *ArrayIndex = Middle;
+ return(TRUE);
+ }
+ else if (Result > 0)
+ {
+ if (Middle == 0)
+ break;
+ Top = Middle - 1;
+ }
+ else
+ {
+ Bottom = Middle+1;
+ }
+
+ Middle = Bottom + (((Top+1) - Bottom)/2);
+ }
+ }
+
+ *ArrayIndex = Middle;
+
+ return(FALSE);
+}
+
+
+BOOLEAN
+EthShouldAddressLoopBack(
+ IN PETH_FILTER Filter,
+ IN CHAR Address[ETH_LENGTH_OF_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ Do a quick check to see whether the input address should
+ loopback.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+ NOTE: THIS ROUTINE DOES NOT CHECK THE SPECIAL CASE OF SOURCE
+ EQUALS DESTINATION.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ Address - A network address to check for loopback.
+
+
+Return Value:
+
+ Returns TRUE if the address is *likely* to need loopback. It
+ will return FALSE if there is *no* chance that the address would
+ require loopback.
+
+--*/
+{
+ BOOLEAN fLoopback, fSelfDirected;
+
+ EthShouldAddressLoopBackMacro(Filter, Address, &fLoopback, &fSelfDirected);
+
+ return(fLoopback);
+}
+
+
diff --git a/private/ntos/ndis/ndis40/ffilter.c b/private/ntos/ndis/ndis40/ffilter.c
new file mode 100644
index 000000000..a3661d791
--- /dev/null
+++ b/private/ntos/ndis/ndis40/ffilter.c
@@ -0,0 +1,3869 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ ffilter.c
+
+Abstract:
+
+ This module implements a set of library routines to handle packet
+ filtering for NDIS MAC drivers.
+
+Author:
+
+ Anthony V. Ercolano (Tonye) 03-Aug-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+ Sean Selitrennikoff (SeanSe) converted Efilter.* for FDDI filtering.
+ Jameel Hyder (JameelH) Re-organization
+
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_FFILTER
+
+
+//
+// VOID
+// FDDI_FILTER_ALLOC_OPEN(
+// IN PFDDI_FILTER Filter,
+// OUT PUINT FilterIndex
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Allocates an open block. This only allocates the index, not memory for
+// the open block.
+//
+//Arguments:
+//
+// Filter - DB from which to allocate the space
+//
+// FilterIndex - pointer to place to store the index.
+//
+//Return Value:
+//
+// FilterIndex of the new open
+//
+//--*/
+#define FDDI_FILTER_ALLOC_OPEN(Filter, FilterIndex) \
+{ \
+ UINT i; \
+ for (i=0; i < FDDI_FILTER_MAX_OPENS; i++) \
+ { \
+ if (IS_BIT_SET_IN_MASK(i,(Filter)->FreeBindingMask)) \
+ { \
+ *(FilterIndex) = i; \
+ CLEAR_BIT_IN_MASK(i, &((Filter)->FreeBindingMask)); \
+ break; \
+ } \
+ } \
+}
+
+//
+// VOID
+// FDDI_FILTER_FREE_OPEN(
+// IN PFDDI_FILTER Filter,
+// IN PFDDI_BINDING_INFO LocalOpen
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Frees an open block. Also frees the memory associated with the open.
+//
+//Arguments:
+//
+// Filter - DB from which to allocate the space
+//
+// FilterIndex - Index to free
+//
+//Return Value:
+//
+// None
+//
+//--*/
+#define FDDI_FILTER_FREE_OPEN(Filter, LocalOpen) \
+{ \
+ SET_BIT_IN_MASK(((LocalOpen)->FilterIndex), &((Filter)->FreeBindingMask)); \
+ FreePhys((LocalOpen), sizeof(FDDI_BINDING_INFO)); \
+}
+
+#define FDDI_CHECK_FOR_INVALID_BROADCAST_INDICATION(_F) \
+IF_DBG(DBG_COMP_FILTER, DBG_LEVEL_WARN) \
+{ \
+ if (!((_F)->CombinedPacketFilter & NDIS_PACKET_TYPE_BROADCAST)) \
+ { \
+ /* \
+ We should never receive broadcast packets \
+ to someone else unless in p-mode. \
+ */ \
+ DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_ERR, \
+ ("Bad driver, indicating broadcast packets when not set to.\n"));\
+ DBGBREAK(DBG_COMP_FILTER, DBG_LEVEL_ERR); \
+ } \
+}
+
+#define FDDI_CHECK_FOR_INVALID_DIRECTED_INDICATION(_F, _A, _AL) \
+IF_DBG(DBG_COMP_FILTER, DBG_LEVEL_WARN) \
+{ \
+ /* \
+ The result of comparing an element of the address \
+ array and the multicast address. \
+ \
+ Result < 0 Implies the adapter address is greater. \
+ Result > 0 Implies the address is greater. \
+ Result = 0 Implies that the they are equal. \
+ */ \
+ INT Result = 0; \
+ if (FDDI_LENGTH_OF_LONG_ADDRESS == (_AL)) \
+ { \
+ FDDI_COMPARE_NETWORK_ADDRESSES_EQ( \
+ (_F)->AdapterLongAddress, \
+ (_A), \
+ FDDI_LENGTH_OF_LONG_ADDRESS, \
+ &Result); \
+ } \
+ else if (FDDI_LENGTH_OF_SHORT_ADDRESS == (_AL)) \
+ { \
+ FDDI_COMPARE_NETWORK_ADDRESSES_EQ( \
+ (_F)->AdapterShortAddress, \
+ (_A), \
+ FDDI_LENGTH_OF_SHORT_ADDRESS, \
+ &Result); \
+ } \
+ if (Result != 0) \
+ { \
+ /* \
+ We should never receive directed packets \
+ to someone else unless in p-mode. \
+ */ \
+ DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_ERR, \
+ ("Bad driver, indicating packets to another station when not in promiscuous mode.\n"));\
+ DBGBREAK(DBG_COMP_FILTER, DBG_LEVEL_ERR); \
+ } \
+}
+
+
+VOID
+fddiRemoveBindingFromLists(
+ IN PFDDI_FILTER Filter,
+ IN PFDDI_BINDING_INFO Binding
+ )
+/*++
+
+Routine Description:
+
+ This routine will remove a binding from all of the list in a
+ filter database. These lists include the list of bindings,
+ the directed filter list and the broadcast/multicast filter list.
+
+Arguments:
+
+ Filter - Pointer to the filter database to remove the binding from.
+ Binding - Pointer to the binding to remove.
+
+--*/
+
+{
+ PFDDI_BINDING_INFO *ppBI;
+
+ //
+ // Remove the binding from the filter's list
+ // of all bindings.
+ //
+ for (ppBI = &Filter->OpenList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextOpen)
+ {
+ if (*ppBI == Binding)
+ {
+ *ppBI = Binding->NextOpen;
+ break;
+ }
+ }
+ ASSERT(*ppBI == Binding->NextOpen);
+
+ //
+ // Remove it from the directed binding list - conditionally
+ //
+ for (ppBI = &Filter->DirectedList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextDirected)
+ {
+ if (*ppBI == Binding)
+ {
+ *ppBI = Binding->NextDirected;
+ break;
+ }
+ }
+
+ //
+ // Remove it from the broadcast/multicast binding list - conditionally
+ //
+ for (ppBI = &Filter->BMSList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextBMS)
+ {
+ if (*ppBI == Binding)
+ {
+ *ppBI = Binding->NextBMS;
+ break;
+ }
+ }
+
+ //
+ // Sanity checks.
+ //
+ Binding->NextDirected = NULL;
+ Binding->NextBMS = NULL;
+ Binding->NextOpen = NULL;
+}
+
+VOID
+fddiRemoveAndFreeBinding(
+ IN PFDDI_FILTER Filter,
+ IN PFDDI_BINDING_INFO Binding,
+ IN BOOLEAN fCallCloseAction
+ )
+/*++
+
+Routine Description:
+
+ This routine will remove a binding from the filter database and
+ indicate a receive complete if necessary. This was made a function
+ to remove code redundancey in following routines. Its not time
+ critical so it's cool.
+
+Arguments:
+
+ Filter - Pointer to the filter database to remove the binding from.
+ Binding - Pointer to the binding to remove.
+ fCallCloseAction - TRUE if we should call the filter's close
+ action routine. FALSE if not.
+
+--*/
+
+{
+ //
+ // Remove the binding.
+ //
+ fddiRemoveBindingFromLists(Filter, Binding);
+
+ //
+ // If we have received and packet indications then
+ // notify the binding of the indication completion.
+ //
+ if (Binding->ReceivedAPacket)
+ {
+ if (NULL != Filter->Miniport)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+ }
+ else
+ {
+ NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ }
+
+ FilterIndicateReceiveComplete(Binding->NdisBindingContext);
+
+ if (NULL != Filter->Miniport)
+ {
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+ }
+ else
+ {
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ }
+ }
+
+ //
+ // Should we call the close action routine?
+ //
+ if (fCallCloseAction)
+ {
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+ Filter->CloseAction(Binding->MacBindingHandle);
+ }
+
+ //
+ // Free the open.
+ //
+ FDDI_FILTER_FREE_OPEN(Filter, Binding);
+}
+
+
+
+BOOLEAN
+FddiCreateFilter(
+ IN UINT MaximumMulticastLongAddresses,
+ IN UINT MaximumMulticastShortAddresses,
+ IN FDDI_ADDRESS_CHANGE AddressChangeAction,
+ IN FDDI_FILTER_CHANGE FilterChangeAction,
+ IN FDDI_DEFERRED_CLOSE CloseAction,
+ IN PUCHAR AdapterLongAddress,
+ IN PUCHAR AdapterShortAddress,
+ IN PNDIS_SPIN_LOCK Lock,
+ OUT PFDDI_FILTER *Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to create and initialize the filter database.
+
+Arguments:
+
+ MaximumMulticastLongAddresses - The maximum number of Long multicast addresses
+ that the MAC will support.
+
+ MaximumMulticastShortAddresses - The maximum number of short multicast addresses
+ that the MAC will support.
+
+ AddressChangeAction - Action routine to call when the list of
+ multicast addresses the card must enable has changed.
+
+ ChangeAction - Action routine to call when a binding sets or clears
+ a particular filter class and it is the first or only binding using
+ the filter class.
+
+ CloseAction - This routine is called if a binding closes while
+ it is being indicated to via NdisIndicateReceive. It will be
+ called upon return from NdisIndicateReceive.
+
+ AdapterLongAddress - the long address of the adapter associated with this filter
+ database.
+
+ AdapterShortAddress - the short address of the adapter associated with this filter
+ database.
+
+ Lock - Pointer to the lock that should be held when mutual exclusion
+ is required.w
+
+ Filter - A pointer to an FDDI_FILTER. This is what is allocated and
+ created by this routine.
+
+Return Value:
+
+ If the function returns false then one of the parameters exceeded
+ what the filter was willing to support.
+
+--*/
+
+{
+ PFDDI_FILTER LocalFilter;
+ NDIS_STATUS AllocStatus;
+
+ //
+ // Allocate the database and it's associated arrays.
+ //
+ AllocStatus = AllocPhys(&LocalFilter, sizeof(FDDI_FILTER));
+ *Filter = LocalFilter;
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ {
+ return(FALSE);
+ }
+
+ //
+ // Zero out the memory allocated.
+ //
+ ZeroMemory(LocalFilter, sizeof(FDDI_FILTER));
+
+ //
+ // Determine the number of long multicast addresses to allocate.
+ //
+ if (MaximumMulticastLongAddresses == 0)
+ {
+ //
+ // Why 2 and not 1? Why not. A protocol is going to need at least
+ // one to run on this, so let's give one extra one for any user stuff
+ // that may need it.
+ //
+
+ MaximumMulticastLongAddresses = 2;
+ }
+
+ //
+ // Allocate the in-use long multicast address list.
+ //
+ AllocStatus = AllocPhys(&LocalFilter->MulticastLongAddresses,
+ FDDI_LENGTH_OF_LONG_ADDRESS * MaximumMulticastLongAddresses);
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ {
+ FddiDeleteFilter(LocalFilter);
+ return(FALSE);
+ }
+
+ //
+ // Zero it out.
+ //
+ ZeroMemory(LocalFilter->MulticastLongAddresses,
+ FDDI_LENGTH_OF_LONG_ADDRESS * MaximumMulticastLongAddresses);
+
+ //
+ // Allocate the old long multicast address list.
+ //
+ AllocStatus = AllocPhys(&LocalFilter->OldMulticastLongAddresses,
+ FDDI_LENGTH_OF_LONG_ADDRESS * MaximumMulticastLongAddresses);
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ {
+ FddiDeleteFilter(LocalFilter);
+ return(FALSE);
+ }
+
+ //
+ // Zero it out.
+ //
+ ZeroMemory(LocalFilter->OldMulticastLongAddresses,
+ FDDI_LENGTH_OF_LONG_ADDRESS * MaximumMulticastLongAddresses);
+
+ //
+ // Allocate the in-use FDDI mask list.
+ //
+ AllocStatus = AllocPhys(&LocalFilter->BindingsUsingLongAddress,
+ sizeof(FDDI_MASK) * MaximumMulticastLongAddresses);
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ {
+ FddiDeleteFilter(LocalFilter);
+ return(FALSE);
+ }
+
+ //
+ // Zero it out.
+ //
+ ZeroMemory(LocalFilter->BindingsUsingLongAddress,
+ sizeof(FDDI_MASK) * MaximumMulticastLongAddresses);
+
+ //
+ // Allocate the old FDDI mask list.
+ //
+ AllocStatus = AllocPhys(&LocalFilter->OldBindingsUsingLongAddress,
+ sizeof(FDDI_MASK) * MaximumMulticastLongAddresses);
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ {
+ FddiDeleteFilter(LocalFilter);
+ return(FALSE);
+ }
+
+ //
+ // Zero it out.
+ //
+ ZeroMemory(LocalFilter->OldBindingsUsingLongAddress,
+ sizeof(FDDI_MASK) * MaximumMulticastLongAddresses);
+
+ //
+ // Determine the number of short multicast addresses to allocate.
+ //
+ if (MaximumMulticastShortAddresses == 0)
+ {
+ //
+ // Why 2 and not 1? Why not. A protocol is going to need at least
+ // one to run on this, so let's give one extra one for any user stuff
+ // that may need it.
+ //
+
+ MaximumMulticastShortAddresses = 2;
+ }
+
+ //
+ // Allocate the in-use short multicast address list.
+ //
+ AllocStatus = AllocPhys(&LocalFilter->MulticastShortAddresses,
+ FDDI_LENGTH_OF_SHORT_ADDRESS * MaximumMulticastShortAddresses);
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ {
+ FddiDeleteFilter(LocalFilter);
+ return(FALSE);
+ }
+
+ //
+ // Zero it out.
+ //
+ ZeroMemory(LocalFilter->MulticastShortAddresses,
+ FDDI_LENGTH_OF_SHORT_ADDRESS * MaximumMulticastShortAddresses);
+
+ //
+ // Allocate the old shortmulticast address list.
+ //
+ AllocStatus = AllocPhys(&LocalFilter->OldMulticastShortAddresses,
+ FDDI_LENGTH_OF_SHORT_ADDRESS * MaximumMulticastShortAddresses);
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ {
+ FddiDeleteFilter(LocalFilter);
+ return(FALSE);
+ }
+
+ //
+ // Zero it out.
+ //
+ ZeroMemory(LocalFilter->OldMulticastShortAddresses,
+ FDDI_LENGTH_OF_SHORT_ADDRESS * MaximumMulticastShortAddresses);
+
+ //
+ // Allocate the in-use FDDI mask list.
+ //
+ AllocStatus = AllocPhys(&LocalFilter->BindingsUsingShortAddress,
+ sizeof(FDDI_MASK) * MaximumMulticastShortAddresses);
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ {
+ FddiDeleteFilter(LocalFilter);
+ return(FALSE);
+ }
+
+ //
+ // Zero it out.
+ //
+ ZeroMemory(LocalFilter->BindingsUsingShortAddress,
+ sizeof(FDDI_MASK) * MaximumMulticastShortAddresses);
+
+ //
+ // Allocate the old FDDI mask list.
+ //
+ AllocStatus = AllocPhys(&LocalFilter->OldBindingsUsingShortAddress,
+ sizeof(FDDI_MASK) * MaximumMulticastShortAddresses);
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ {
+ FddiDeleteFilter(LocalFilter);
+ return(FALSE);
+ }
+
+ //
+ // Zero it out.
+ //
+ ZeroMemory(LocalFilter->OldBindingsUsingShortAddress,
+ sizeof(FDDI_MASK) * MaximumMulticastShortAddresses);
+
+ FddiReferencePackage();
+
+ LocalFilter->FreeBindingMask = (ULONG)(-1);
+
+ FDDI_COPY_NETWORK_ADDRESS(LocalFilter->AdapterLongAddress,
+ AdapterLongAddress,
+ FDDI_LENGTH_OF_LONG_ADDRESS);
+
+ FDDI_COPY_NETWORK_ADDRESS(LocalFilter->AdapterShortAddress,
+ AdapterShortAddress,
+ FDDI_LENGTH_OF_SHORT_ADDRESS);
+
+ LocalFilter->Lock = Lock;
+ LocalFilter->AddressChangeAction = AddressChangeAction;
+ LocalFilter->FilterChangeAction = FilterChangeAction;
+ LocalFilter->CloseAction = CloseAction;
+ LocalFilter->MaximumMulticastLongAddresses = MaximumMulticastLongAddresses;
+ LocalFilter->MaximumMulticastShortAddresses = MaximumMulticastShortAddresses;
+
+ return(TRUE);
+}
+
+//
+// NOTE: THIS CANNOT BE PAGABLE
+//
+VOID
+FddiDeleteFilter(
+ IN PFDDI_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to delete the memory associated with a filter
+ database. Note that this routines *ASSUMES* that the database
+ has been cleared of any active filters.
+
+Arguments:
+
+ Filter - A pointer to an FDDI_FILTER to be deleted.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ASSERT(Filter->FreeBindingMask == (FDDI_MASK)-1);
+ ASSERT(Filter->OpenList == NULL);
+
+ //
+ // Kill the long address information.
+ //
+ if (Filter->MulticastLongAddresses)
+ {
+ FreePhys(Filter->MulticastLongAddresses,
+ FDDI_LENGTH_OF_LONG_ADDRESS*Filter->MaximumMulticastLongAddresses);
+ }
+
+ if (Filter->OldMulticastLongAddresses)
+ {
+ FreePhys(Filter->OldMulticastLongAddresses,
+ FDDI_LENGTH_OF_LONG_ADDRESS * Filter->MaximumMulticastLongAddresses);
+ }
+
+ if (Filter->BindingsUsingLongAddress)
+ {
+ FreePhys(Filter->BindingsUsingLongAddress,
+ sizeof(FDDI_MASK)*Filter->MaximumMulticastLongAddresses);
+ }
+
+ if (Filter->OldBindingsUsingLongAddress)
+ {
+ FreePhys(Filter->OldBindingsUsingLongAddress,
+ sizeof(FDDI_MASK) * Filter->MaximumMulticastLongAddresses);
+ }
+
+ //
+ // Kill the short address information.
+ //
+ if (Filter->MulticastShortAddresses)
+ {
+ FreePhys(Filter->MulticastShortAddresses,
+ FDDI_LENGTH_OF_SHORT_ADDRESS*Filter->MaximumMulticastShortAddresses);
+ }
+
+ if (Filter->OldMulticastShortAddresses)
+ {
+ FreePhys(Filter->OldMulticastShortAddresses,
+ FDDI_LENGTH_OF_SHORT_ADDRESS*Filter->MaximumMulticastShortAddresses);
+ }
+
+ if (Filter->BindingsUsingShortAddress)
+ {
+ FreePhys(Filter->BindingsUsingShortAddress,
+ sizeof(FDDI_MASK)*Filter->MaximumMulticastShortAddresses);
+ }
+
+ if (Filter->OldBindingsUsingShortAddress)
+ {
+ FreePhys(Filter->OldBindingsUsingShortAddress,
+ sizeof(FDDI_MASK) * Filter->MaximumMulticastShortAddresses);
+ }
+
+ FreePhys(Filter, sizeof(FDDI_FILTER));
+
+ FddiDereferencePackage();
+}
+
+
+BOOLEAN
+FddiNoteFilterOpenAdapter(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE NdisBindingContext,
+ OUT PNDIS_HANDLE NdisFilterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to add a new binding to the filter database.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE DATABASE IS LOCKED WHEN
+ IT IS CALLED.
+
+Arguments:
+
+ Filter - A pointer to the previously created and initialized filter
+ database.
+
+ MacBindingHandle - The MAC supplied value to the protocol in response
+ to a call to FddiOpenAdapter.
+
+ NdisBindingContext - An NDIS supplied value to the call to FddiOpenAdapter.
+
+ NdisFilterHandle - A pointer to this open.
+
+Return Value:
+
+ Will return false if creating a new filter index will cause the maximum
+ number of filter indexes to be exceeded.
+
+--*/
+
+{
+ //
+ // Will hold the value of the filter index so that we
+ // need not indirectly address through pointer parameter.
+ //
+ UINT LocalIndex;
+
+ NDIS_STATUS AllocStatus;
+
+ //
+ // Pointer to new open block.
+ //
+ PFDDI_BINDING_INFO LocalOpen;
+
+ PNDIS_OPEN_BLOCK NdisOpen = (PNDIS_OPEN_BLOCK)NdisBindingContext;
+
+ //
+ // Get the first free binding slot and remove that slot from
+ // the free list. We check to see if the list is empty.
+ //
+ if (Filter->FreeBindingMask == 0)
+ return(FALSE);
+
+ //
+ // Allocate memory for the new binding.
+ //
+ AllocStatus = AllocPhys(&LocalOpen, sizeof(FDDI_BINDING_INFO));
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ return(FALSE);
+
+ //
+ // Zero the memory
+ //
+ ZeroMemory(LocalOpen, sizeof(FDDI_BINDING_INFO));
+
+ //
+ // Get place for the open and insert it.
+ //
+ FDDI_FILTER_ALLOC_OPEN(Filter, &LocalIndex);
+
+ LocalOpen->NextOpen = Filter->OpenList;
+ Filter->OpenList = LocalOpen;
+
+ LocalOpen->References = 1;
+ LocalOpen->FilterIndex = (UCHAR)LocalIndex;
+ LocalOpen->MacBindingHandle = MacBindingHandle;
+ LocalOpen->NdisBindingContext = NdisBindingContext;
+
+ *NdisFilterHandle = (NDIS_HANDLE)LocalOpen;
+
+ return(TRUE);
+}
+
+
+NDIS_STATUS
+FddiDeleteFilterOpenAdapter(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ When an adapter is being closed this routine should
+ be called to delete knowledge of the adapter from
+ the filter database. This routine is likely to call
+ action routines associated with clearing filter classes
+ and addresses.
+
+ NOTE: THIS ROUTINE SHOULD ****NOT**** BE CALLED IF THE ACTION
+ ROUTINES FOR DELETING THE FILTER CLASSES OR THE MULTICAST ADDRESSES
+ HAVE ANY POSSIBILITY OF RETURNING A STATUS OTHER THAN NDIS_STATUS_PENDING
+ OR NDIS_STATUS_SUCCESS. WHILE THESE ROUTINES WILL NOT BUGCHECK IF
+ SUCH A THING IS DONE, THE CALLER WILL PROBABLY FIND IT DIFFICULT
+ TO CODE A CLOSE ROUTINE!
+
+ NOTE: THIS ROUTINE ASSUMES THAT IT IS CALLED WITH THE LOCK HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routines,
+ this will be passed to it.
+
+Return Value:
+
+ If action routines are called by the various address and filtering
+ routines the this routine will likely return the status returned
+ by those routines. The exception to this rule is noted below.
+
+ Given that the filter and address deletion routines return a status
+ NDIS_STATUS_PENDING or NDIS_STATUS_SUCCESS this routine will then
+ try to return the filter index to the freelist. If the routine
+ detects that this binding is currently being indicated to via
+ NdisIndicateReceive, this routine will return a status of
+ NDIS_STATUS_CLOSING_INDICATING.
+
+--*/
+
+{
+
+ //
+ // Holds the status returned from the packet filter and address
+ // deletion routines. Will be used to return the status to
+ // the caller of this routine.
+ //
+ NDIS_STATUS StatusToReturn;
+
+ //
+ // Local variable.
+ //
+ PFDDI_BINDING_INFO LocalOpen = (PFDDI_BINDING_INFO)NdisFilterHandle;
+
+ //
+ // Set the filter classes to NONE.
+ //
+ StatusToReturn = FddiFilterAdjust(Filter,
+ NdisFilterHandle,
+ NdisRequest,
+ (UINT)0,
+ FALSE);
+ if ((StatusToReturn == NDIS_STATUS_SUCCESS) ||
+ (StatusToReturn == NDIS_STATUS_PENDING))
+ {
+ NDIS_STATUS StatusToReturn2;
+
+ //
+ // Remove the long multicast addresses.
+ //
+ StatusToReturn2 = FddiChangeFilterLongAddresses(Filter,
+ NdisFilterHandle,
+ NdisRequest,
+ 0,
+ NULL,
+ FALSE);
+ if (StatusToReturn2 != NDIS_STATUS_SUCCESS)
+ {
+ StatusToReturn = StatusToReturn2;
+ }
+
+ if ((StatusToReturn == NDIS_STATUS_SUCCESS) ||
+ (StatusToReturn == NDIS_STATUS_PENDING))
+ {
+ StatusToReturn2 = FddiChangeFilterShortAddresses(Filter,
+ NdisFilterHandle,
+ NdisRequest,
+ 0,
+ NULL,
+ FALSE);
+ if (StatusToReturn2 != NDIS_STATUS_SUCCESS)
+ {
+ StatusToReturn = StatusToReturn2;
+ }
+ }
+ }
+
+ if ((StatusToReturn == NDIS_STATUS_SUCCESS) ||
+ (StatusToReturn == NDIS_STATUS_PENDING))
+ {
+ //
+ // Remove the reference from the original open.
+ //
+ if (--(LocalOpen->References) == 0)
+ {
+ //
+ // Remove it from the list.
+ //
+ fddiRemoveAndFreeBinding(Filter, LocalOpen, FALSE);
+ }
+ else
+ {
+ //
+ // Let the caller know that there is a reference to the open
+ // by the receive indication. The close action routine will be
+ // called upon return from NdisIndicateReceive.
+ //
+ StatusToReturn = NDIS_STATUS_CLOSING_INDICATING;
+ }
+ }
+
+ return(StatusToReturn);
+}
+
+
+VOID
+fddiUndoChangeFilterLongAddresses(
+ IN PFDDI_FILTER Filter
+)
+{
+ //
+ // Restore the original number of long addresses.
+ //
+ Filter->NumberOfLongAddresses = Filter->OldNumberOfLongAddresses;
+
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+ MoveMemory((PVOID)Filter->MulticastLongAddresses,
+ (PVOID)Filter->OldMulticastLongAddresses,
+ Filter->NumberOfLongAddresses * FDDI_LENGTH_OF_LONG_ADDRESS);
+
+ MoveMemory((PVOID)Filter->BindingsUsingLongAddress,
+ (PVOID)Filter->OldBindingsUsingLongAddress,
+ Filter->NumberOfLongAddresses * sizeof(FDDI_MASK));
+
+}
+
+
+NDIS_STATUS
+FddiChangeFilterLongAddresses(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT AddressCount,
+ IN CHAR Addresses[][FDDI_LENGTH_OF_LONG_ADDRESS],
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ The ChangeFilterAddress routine will call an action
+ routine when the overall multicast address list for the adapter
+ has changed.
+
+ If the action routine returns a value other than pending or
+ success then this routine has no effect on the multicast address
+ list for the open or for the adapter as a whole.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routine,
+ this will be passed to it.
+
+ AddressCount - The number of elements (addresses,
+ not bytes) in MulticastAddressList.
+
+ Addresses - The new multicast address list for this
+ binding. This is a sequence of FDDI_LENGTH_OF_LONG_ADDRESS byte
+ addresses, with no padding between them.
+
+ Set - A boolean that determines whether the multicast addresses
+ are being adjusted due to a set or because of a close. (The filtering
+ routines don't care, the MAC might.)
+
+Return Value:
+
+ If it calls the action routine then it will return the
+ status returned by the action routine. If the status
+ returned by the action routine is anything other than
+ NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
+ will be returned to the state it was in upon entrance to this
+ routine.
+
+ If the action routine is not called this routine will return
+ the following statum:
+
+ NDIS_STATUS_SUCCESS - If the new packet filters doesn't change
+ the combined mask of all bindings packet filters.
+
+--*/
+
+{
+ //
+ // Holds the status returned to the user of this routine, if the
+ // action routine is not called then the status will be success,
+ // otherwise, it is whatever the action routine returns.
+ //
+ NDIS_STATUS StatusOfChange;
+
+ //
+ // Set true when the address array changes
+ //
+ BOOLEAN AddressesChanged = FALSE;
+
+ //
+ // Simple iteration variables.
+ //
+ UINT ArrayIndex;
+ UINT i;
+
+ //
+ // Simple Temp variable
+ //
+ PCHAR CurrentAddress;
+
+ PFDDI_BINDING_INFO LocalOpen = (PFDDI_BINDING_INFO)NdisFilterHandle;
+
+ //
+ // We have to save the old mask array in
+ // case we need to restore it. If we need
+ // to save the address array too we will
+ // do that later.
+ //
+ MoveMemory((PVOID)Filter->OldBindingsUsingLongAddress,
+ (PVOID)Filter->BindingsUsingLongAddress,
+ Filter->NumberOfLongAddresses * sizeof(FDDI_MASK));
+
+ //
+ // We have to save the old address array in
+ // case we need to restore it. If we need
+ // to save the address array too we will
+ // do that later.
+ //
+ MoveMemory((PVOID)Filter->OldMulticastLongAddresses,
+ (PVOID)Filter->MulticastLongAddresses,
+ Filter->NumberOfLongAddresses * FDDI_LENGTH_OF_LONG_ADDRESS);
+
+ //
+ // Save the current number of multicast addresses.
+ //
+ Filter->OldNumberOfLongAddresses = Filter->NumberOfLongAddresses;
+
+ //
+ // First go through and turn off the bit for this
+ // binding throughout the array.
+ //
+ for (i = 0; i < Filter->NumberOfLongAddresses; i++)
+ {
+ CLEAR_BIT_IN_MASK(LocalOpen->FilterIndex, &(Filter->BindingsUsingLongAddress[i]));
+ }
+
+ //
+ // Finally we have to remove any addresses from
+ // the multicast array if they have no bits on any more.
+ //
+ for (ArrayIndex = 0; ArrayIndex < Filter->NumberOfLongAddresses; )
+ {
+ if (IS_MASK_CLEAR(Filter->BindingsUsingLongAddress[ArrayIndex]))
+ {
+ AddressesChanged = TRUE;
+
+ //
+ // yes it is clear, so we have to shift everything
+ // above it down one.
+ //
+#ifdef NDIS_NT
+ MoveMemory(Filter->MulticastLongAddresses[ArrayIndex],
+ Filter->MulticastLongAddresses[ArrayIndex+1],
+ (Filter->NumberOfLongAddresses-(ArrayIndex+1)) * FDDI_LENGTH_OF_LONG_ADDRESS);
+#else // NDIS_WIN
+ MoveOverlappedMemory(Filter->MulticastLongAddresses[ArrayIndex],
+ Filter->MulticastLongAddresses[ArrayIndex+1],
+ (Filter->NumberOfLongAddresses-(ArrayIndex+1)) * FDDI_LENGTH_OF_LONG_ADDRESS);
+#endif
+
+#ifdef NDIS_NT
+ MoveMemory(&Filter->BindingsUsingLongAddress[ArrayIndex],
+ &Filter->BindingsUsingLongAddress[ArrayIndex+1],
+ (Filter->NumberOfLongAddresses - (ArrayIndex + 1)) * (sizeof(FDDI_MASK)));
+#else // NDIS_WIN
+ MoveOverlappedMemory(&Filter->BindingsUsingLongAddress[ArrayIndex],
+ &Filter->BindingsUsingLongAddress[ArrayIndex+1],
+ (Filter->NumberOfLongAddresses - (ArrayIndex + 1)) * (sizeof(FDDI_MASK)));
+#endif
+
+ Filter->NumberOfLongAddresses--;
+ }
+ else
+ {
+ ArrayIndex++;
+ }
+ }
+
+ //
+ // Now go through the new addresses for this binding,
+ // and insert them into the array.
+ //
+ for (i = 0; i < AddressCount; i++)
+ {
+ CurrentAddress = ((PCHAR)Addresses) + (i*FDDI_LENGTH_OF_LONG_ADDRESS);
+
+ if (FddiFindMulticastLongAddress(Filter->NumberOfLongAddresses,
+ Filter->MulticastLongAddresses,
+ CurrentAddress,
+ &ArrayIndex))
+ {
+ //
+ // The address is there, so just turn the bit
+ // back on.
+ //
+ SET_BIT_IN_MASK(LocalOpen->FilterIndex, &Filter->BindingsUsingLongAddress[ArrayIndex]);
+ }
+ else
+ {
+ //
+ // The address was not found, add it.
+ //
+ // NOTE: Here we temporarily need more array
+ // space then we may finally, but for now this
+ // will work.
+ //
+
+ if (Filter->NumberOfLongAddresses < Filter->MaximumMulticastLongAddresses)
+ {
+ AddressesChanged = TRUE;
+
+ //
+ // Save the address array if it hasn't been.
+ //
+#ifdef NDIS_NT
+ MoveMemory(Filter->MulticastLongAddresses[ArrayIndex + 1],
+ Filter->MulticastLongAddresses[ArrayIndex],
+ (Filter->NumberOfLongAddresses - ArrayIndex) * FDDI_LENGTH_OF_LONG_ADDRESS);
+#else // NDIS_WIN
+ MoveOverlappedMemory(Filter->MulticastLongAddresses[ArrayIndex + 1],
+ Filter->MulticastLongAddresses[ArrayIndex],
+ (Filter->NumberOfLongAddresses - ArrayIndex) * FDDI_LENGTH_OF_LONG_ADDRESS);
+#endif
+
+ FDDI_COPY_NETWORK_ADDRESS(Filter->MulticastLongAddresses[ArrayIndex],
+ CurrentAddress,
+ FDDI_LENGTH_OF_LONG_ADDRESS);
+
+#ifdef NDIS_NT
+ MoveMemory(&(Filter->BindingsUsingLongAddress[ArrayIndex + 1]),
+ &(Filter->BindingsUsingLongAddress[ArrayIndex]),
+ (Filter->NumberOfLongAddresses-ArrayIndex)*sizeof(FDDI_MASK));
+#else // NDIS_WIN
+ MoveOverlappedMemory(&(Filter->BindingsUsingLongAddress[ArrayIndex + 1]),
+ &(Filter->BindingsUsingLongAddress[ArrayIndex]),
+ (Filter->NumberOfLongAddresses-ArrayIndex)*sizeof(FDDI_MASK));
+#endif
+
+ CLEAR_MASK(&Filter->BindingsUsingLongAddress[ArrayIndex]);
+
+ SET_BIT_IN_MASK(LocalOpen->FilterIndex, &Filter->BindingsUsingLongAddress[ArrayIndex]);
+
+ Filter->NumberOfLongAddresses++;
+ }
+ else
+ {
+ //
+ // No room in the array, oh well.
+ //
+ fddiUndoChangeFilterLongAddresses(Filter);
+
+ return(NDIS_STATUS_MULTICAST_FULL);
+ }
+ }
+ }
+
+
+ //
+ // If the address array has changed, we have to call the
+ // action array to inform the adapter of this.
+ //
+ if (AddressesChanged)
+ {
+ StatusOfChange = Filter->AddressChangeAction(
+ Filter->OldNumberOfLongAddresses,
+ Filter->OldMulticastLongAddresses,
+ Filter->NumberOfLongAddresses,
+ Filter->MulticastLongAddresses,
+ Filter->NumberOfShortAddresses,
+ Filter->MulticastShortAddresses,
+ Filter->NumberOfShortAddresses,
+ Filter->MulticastShortAddresses,
+ LocalOpen->MacBindingHandle,
+ NdisRequest,
+ Set);
+ if ((StatusOfChange != NDIS_STATUS_SUCCESS) &&
+ (StatusOfChange != NDIS_STATUS_PENDING))
+ {
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+ fddiUndoChangeFilterLongAddresses(Filter);
+ }
+ }
+ else
+ {
+ StatusOfChange = NDIS_STATUS_SUCCESS;
+ }
+
+ return(StatusOfChange);
+}
+
+
+VOID
+fddiUndoChangeFilterShortAddresses(
+ IN PFDDI_FILTER Filter
+)
+{
+ //
+ // Restore the original number of short addresses.
+ //
+ Filter->NumberOfShortAddresses = Filter->OldNumberOfShortAddresses;
+
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+ MoveMemory((PVOID)Filter->MulticastShortAddresses,
+ (PVOID)Filter->OldMulticastShortAddresses,
+ Filter->NumberOfShortAddresses * FDDI_LENGTH_OF_SHORT_ADDRESS);
+
+ MoveMemory((PVOID)Filter->BindingsUsingShortAddress,
+ (PVOID)Filter->OldBindingsUsingShortAddress,
+ Filter->NumberOfShortAddresses * sizeof(FDDI_MASK));
+}
+
+
+NDIS_STATUS
+FddiChangeFilterShortAddresses(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT AddressCount,
+ IN CHAR Addresses[][FDDI_LENGTH_OF_SHORT_ADDRESS],
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ The ChangeFilterAddress routine will call an action
+ routine when the overall multicast address list for the adapter
+ has changed.
+
+ If the action routine returns a value other than pending or
+ success then this routine has no effect on the multicast address
+ list for the open or for the adapter as a whole.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routine,
+ this will be passed to it.
+
+ AddressCount - The number of elements (addresses,
+ not bytes) in MulticastAddressList.
+
+ Addresses - The new multicast address list for this
+ binding. This is a sequence of FDDI_LENGTH_OF_SHORT_ADDRESS byte
+ addresses, with no padding between them.
+
+ Set - A boolean that determines whether the multicast addresses
+ are being adjusted due to a set or because of a close. (The filtering
+ routines don't care, the MAC might.)
+
+Return Value:
+
+ If it calls the action routine then it will return the
+ status returned by the action routine. If the status
+ returned by the action routine is anything other than
+ NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
+ will be returned to the state it was in upon entrance to this
+ routine.
+
+ If the action routine is not called this routine will return
+ the following statum:
+
+ NDIS_STATUS_SUCCESS - If the new packet filters doesn't change
+ the combined mask of all bindings packet filters.
+
+--*/
+
+{
+ //
+ // Holds the status returned to the user of this routine, if the
+ // action routine is not called then the status will be success,
+ // otherwise, it is whatever the action routine returns.
+ //
+ NDIS_STATUS StatusOfChange;
+
+ //
+ // Set true when the address array changes
+ //
+ BOOLEAN AddressesChanged = FALSE;
+
+ //
+ // Simple iteration variables.
+ //
+ UINT ArrayIndex;
+ UINT i;
+
+
+ //
+ // Simple Temp variable
+ //
+ PCHAR CurrentAddress;
+
+ PFDDI_BINDING_INFO LocalOpen = (PFDDI_BINDING_INFO)NdisFilterHandle;
+
+ //
+ // We have to save the old mask array in
+ // case we need to restore it. If we need
+ // to save the address array too we will
+ // do that later.
+ //
+ MoveMemory((PVOID)Filter->OldBindingsUsingShortAddress,
+ (PVOID)Filter->BindingsUsingShortAddress,
+ Filter->NumberOfShortAddresses * sizeof(FDDI_MASK));
+
+ //
+ // We have to save the old address array in
+ // case we need to restore it. If we need
+ // to save the address array too we will
+ // do that later.
+ //
+ MoveMemory((PVOID)Filter->OldMulticastShortAddresses,
+ (PVOID)Filter->MulticastShortAddresses,
+ Filter->NumberOfShortAddresses * FDDI_LENGTH_OF_SHORT_ADDRESS);
+
+ Filter->OldNumberOfShortAddresses = Filter->NumberOfShortAddresses;
+
+ //
+ // Now modify the original array...
+ //
+
+ //
+ // First go through and turn off the bit for this
+ // binding throughout the array.
+ //
+ for (i = 0; i < (Filter->NumberOfShortAddresses); i++)
+ {
+ CLEAR_BIT_IN_MASK(LocalOpen->FilterIndex, &(Filter->BindingsUsingShortAddress[i]));
+ }
+
+ //
+ // Now go through the new addresses for this binding,
+ // and insert them into the array.
+ //
+ for (i = 0; i < AddressCount; i++)
+ {
+ CurrentAddress = ((PCHAR)Addresses) + (i*FDDI_LENGTH_OF_SHORT_ADDRESS);
+
+ if (FddiFindMulticastShortAddress(Filter->NumberOfShortAddresses,
+ Filter->MulticastShortAddresses,
+ CurrentAddress,
+ &ArrayIndex))
+ {
+ //
+ // The address is there, so just turn the bit
+ // back on.
+ //
+ SET_BIT_IN_MASK(LocalOpen->FilterIndex, &Filter->BindingsUsingShortAddress[ArrayIndex]);
+ }
+ else
+ {
+ //
+ // The address was not found, add it.
+ //
+ // NOTE: Here we temporarily need more array
+ // space then we may finally, but for now this
+ // will work.
+ //
+
+ if (Filter->NumberOfShortAddresses < Filter->MaximumMulticastShortAddresses)
+ {
+ //
+ // Save the address array if it hasn't been.
+ //
+
+ AddressesChanged = TRUE;
+
+#ifdef NDIS_NT
+ MoveMemory(Filter->MulticastShortAddresses[ArrayIndex+1],
+ Filter->MulticastShortAddresses[ArrayIndex],
+ (Filter->NumberOfShortAddresses-ArrayIndex)*FDDI_LENGTH_OF_SHORT_ADDRESS);
+#else // NDIS_WIN
+ MoveOverlappedMemory(Filter->MulticastShortAddresses[ArrayIndex+1],
+ Filter->MulticastShortAddresses[ArrayIndex],
+ (Filter->NumberOfShortAddresses-ArrayIndex)*FDDI_LENGTH_OF_SHORT_ADDRESS);
+#endif
+
+ FDDI_COPY_NETWORK_ADDRESS(Filter->MulticastShortAddresses[ArrayIndex],
+ CurrentAddress,
+ FDDI_LENGTH_OF_SHORT_ADDRESS);
+
+#ifdef NDIS_NT
+ MoveMemory(&(Filter->BindingsUsingShortAddress[ArrayIndex+1]),
+ &(Filter->BindingsUsingShortAddress[ArrayIndex]),
+ (Filter->NumberOfShortAddresses-ArrayIndex)*sizeof(FDDI_MASK));
+#else // NDIS_WIN
+ MoveOverlappedMemory(&(Filter->BindingsUsingShortAddress[ArrayIndex+1]),
+ &(Filter->BindingsUsingShortAddress[ArrayIndex]),
+ (Filter->NumberOfShortAddresses-ArrayIndex)*sizeof(FDDI_MASK));
+#endif
+
+ CLEAR_MASK(&Filter->BindingsUsingShortAddress[ArrayIndex]);
+
+ SET_BIT_IN_MASK(LocalOpen->FilterIndex, &Filter->BindingsUsingShortAddress[ArrayIndex]);
+
+ Filter->NumberOfShortAddresses++;
+ }
+ else
+ {
+ //
+ // No room in the array, oh well.
+ //
+ fddiUndoChangeFilterShortAddresses(Filter);
+
+ return(NDIS_STATUS_MULTICAST_FULL);
+ }
+ }
+ }
+
+
+ //
+ // Finally we have to remove any addresses from
+ // the multicast array if they have no bits on any more.
+ //
+ for (ArrayIndex = 0; ArrayIndex < Filter->NumberOfShortAddresses; )
+ {
+ if (IS_MASK_CLEAR(Filter->BindingsUsingShortAddress[ArrayIndex]))
+ {
+ //
+ // yes it is clear, so we have to shift everything
+ // above it down one.
+ //
+ AddressesChanged = TRUE;
+
+#ifdef NDIS_NT
+ MoveMemory(Filter->MulticastShortAddresses[ArrayIndex],
+ Filter->MulticastShortAddresses[ArrayIndex+1],
+ (Filter->NumberOfShortAddresses-(ArrayIndex+1)) *FDDI_LENGTH_OF_SHORT_ADDRESS);
+#else // NDIS_WIN
+ MoveOverlappedMemory(Filter->MulticastShortAddresses[ArrayIndex],
+ Filter->MulticastShortAddresses[ArrayIndex+1],
+ (Filter->NumberOfShortAddresses-(ArrayIndex+1)) *FDDI_LENGTH_OF_SHORT_ADDRESS);
+#endif
+
+#ifdef NDIS_NT
+ MoveMemory(&Filter->BindingsUsingShortAddress[ArrayIndex],
+ &Filter->BindingsUsingShortAddress[ArrayIndex+1],
+ (Filter->NumberOfShortAddresses-(ArrayIndex+1))*(sizeof(FDDI_MASK)));
+#else // NDIS_WIN
+ MoveOverlappedMemory(&Filter->BindingsUsingShortAddress[ArrayIndex],
+ &Filter->BindingsUsingShortAddress[ArrayIndex+1],
+ (Filter->NumberOfShortAddresses-(ArrayIndex+1))*(sizeof(FDDI_MASK)));
+#endif
+
+ Filter->NumberOfShortAddresses--;
+ }
+ else
+ {
+ ArrayIndex++;
+ }
+ }
+
+ //
+ // If the address array has changed, we have to call the
+ // action array to inform the adapter of this.
+ //
+
+ if (AddressesChanged)
+ {
+ StatusOfChange = Filter->AddressChangeAction(
+ Filter->NumberOfLongAddresses,
+ Filter->MulticastLongAddresses,
+ Filter->NumberOfLongAddresses,
+ Filter->MulticastLongAddresses,
+ Filter->OldNumberOfShortAddresses,
+ Filter->OldMulticastShortAddresses,
+ Filter->NumberOfShortAddresses,
+ Filter->MulticastShortAddresses,
+ LocalOpen->MacBindingHandle,
+ NdisRequest,
+ Set);
+ if ((StatusOfChange != NDIS_STATUS_SUCCESS) &&
+ (StatusOfChange != NDIS_STATUS_PENDING))
+ {
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+ fddiUndoChangeFilterShortAddresses(Filter);
+ }
+ }
+ else
+ {
+ StatusOfChange = NDIS_STATUS_SUCCESS;
+ }
+
+ return(StatusOfChange);
+}
+
+
+VOID
+fddiUpdateDirectedBindingList(
+ IN OUT PFDDI_FILTER Filter,
+ IN PFDDI_BINDING_INFO Binding,
+ IN BOOLEAN fAddToList
+ )
+/*++
+
+Routine Description:
+
+ This routine will either add or remove a binding to or from the
+ directed filter list.
+
+Arguments:
+
+ Filter - Pointer to the filter database to add/remove the binding from.
+ Binding - Pointer to the binding.
+ fAdd - TRUE if we are to add the binding,
+ FALSE if we are removeing it.
+
+--*/
+{
+ PFDDI_BINDING_INFO CurrentBinding;
+ BOOLEAN AlreadyOnList;
+
+ //
+ // Do we need to add it to the directed list?
+ //
+ if (fAddToList)
+ {
+ //
+ // First we need to see if it is already on the
+ // directed list.
+ //
+ for (CurrentBinding = Filter->DirectedList, AlreadyOnList = FALSE;
+ CurrentBinding != NULL;
+ CurrentBinding = CurrentBinding->NextDirected)
+ {
+ if (CurrentBinding == Binding)
+ {
+ AlreadyOnList = TRUE;
+ }
+ }
+
+ if (!AlreadyOnList)
+ {
+ Binding->NextDirected = Filter->DirectedList;
+ Filter->DirectedList = Binding;
+ }
+ }
+ else
+ {
+ PFDDI_BINDING_INFO *ppBI;
+
+ for (ppBI = &Filter->DirectedList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextDirected)
+ {
+ if (*ppBI == Binding)
+ {
+ *ppBI = Binding->NextDirected;
+ break;
+ }
+ }
+ Binding->NextDirected = NULL;
+ }
+}
+
+
+VOID
+fddiUpdateBroadcastBindingList(
+ IN OUT PFDDI_FILTER Filter,
+ IN PFDDI_BINDING_INFO Binding,
+ IN BOOLEAN fAddToList
+ )
+/*++
+
+Routine Description:
+ This routine will either add or remove a binding to or from the
+ broadcast/multicast filter list.
+
+Arguments:
+
+ Filter - Pointer to the filter database to add/remove the binding from.
+ Binding - Pointer to the binding.
+ fAdd - TRUE if we are to add the binding,
+ FALSE if we are removeing it.
+--*/
+{
+ PFDDI_BINDING_INFO CurrentBinding;
+ BOOLEAN AlreadyOnList;
+
+ //
+ // Do we need to add it to the directed list?
+ //
+ if (fAddToList)
+ {
+ //
+ // First we need to see if it is already on the
+ // directed list.
+ //
+ for (CurrentBinding = Filter->BMSList, AlreadyOnList = FALSE;
+ CurrentBinding != NULL;
+ CurrentBinding = CurrentBinding->NextBMS)
+ {
+ if (CurrentBinding == Binding)
+ {
+ AlreadyOnList = TRUE;
+ }
+ }
+
+ if (!AlreadyOnList)
+ {
+ Binding->NextBMS = Filter->BMSList;
+ Filter->BMSList = Binding;
+ }
+ }
+ else
+ {
+ PFDDI_BINDING_INFO *ppBI;
+
+ for (ppBI = &Filter->BMSList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextBMS)
+ {
+ if (*ppBI == Binding)
+ {
+ *ppBI = Binding->NextBMS;
+ break;
+ }
+ }
+
+ Binding->NextBMS = NULL;
+ }
+}
+
+
+VOID
+fddiUpdateSpecificBindingLists(
+ IN OUT PFDDI_FILTER Filter,
+ IN PFDDI_BINDING_INFO Binding
+ )
+/*++
+
+Routine Description:
+
+ This routine will determine if we should add or remove a binding from
+ one of the filter lists (directed and broadcast).
+
+Arguments:
+
+ Filter - Pointer to the filter database that the binding belongs to.
+ Binding - Pointer to the binding to add or remove to lists.
+
+--*/
+{
+ BOOLEAN fOnDirectedList = FALSE;
+ BOOLEAN fOnBMSList = FALSE;
+ BOOLEAN fAddToDirectedList = FALSE;
+ BOOLEAN fAddToBMSList = FALSE;
+
+ //
+ // If the old filter is promsicuous then it is currently on
+ // both lists.
+ //
+ if (Binding->OldPacketFilters & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL))
+ {
+ fOnDirectedList = TRUE;
+ fOnBMSList = TRUE;
+ }
+ else
+ {
+ //
+ // If the binding had the directed bit set then it is on
+ // the directed list.
+ //
+ if (Binding->OldPacketFilters & NDIS_PACKET_TYPE_DIRECTED)
+ {
+ fOnDirectedList = TRUE;
+ }
+
+ //
+ // If the binding had the broadcast/multicast bit set then it is on
+ // the broadcast/multicast list.
+ //
+ if (Binding->OldPacketFilters & (NDIS_PACKET_TYPE_BROADCAST |
+ NDIS_PACKET_TYPE_SMT |
+ NDIS_PACKET_TYPE_MULTICAST |
+ NDIS_PACKET_TYPE_ALL_MULTICAST))
+ {
+ fOnBMSList = TRUE;
+ }
+ }
+
+ //
+ // If the current filter has the promsicuous bit set then we
+ // need to add it to both lists.
+ //
+ if (Binding->PacketFilters & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL))
+ {
+ fAddToDirectedList = TRUE;
+ fAddToBMSList = TRUE;
+ }
+ else
+ {
+ //
+ // Was the directed bit set?
+ //
+ if (Binding->PacketFilters & NDIS_PACKET_TYPE_DIRECTED)
+ {
+ fAddToDirectedList = TRUE;
+ }
+
+ //
+ // Was the broadcast bit set?
+ //
+ if (Binding->PacketFilters & (NDIS_PACKET_TYPE_BROADCAST |
+ NDIS_PACKET_TYPE_SMT |
+ NDIS_PACKET_TYPE_MULTICAST |
+ NDIS_PACKET_TYPE_ALL_MULTICAST))
+ {
+ fAddToBMSList = TRUE;
+ }
+ }
+
+ //
+ // Determine if the binding should be added or removed from
+ // the directed list.
+ //
+ if (!fOnDirectedList && fAddToDirectedList)
+ {
+ //
+ // Add the binding to the directed list.
+ //
+ fddiUpdateDirectedBindingList(Filter, Binding, TRUE);
+ }
+ else if (fOnDirectedList && !fAddToDirectedList)
+ {
+ //
+ // Remove it from the directed list.
+ //
+ fddiUpdateDirectedBindingList(Filter, Binding, FALSE);
+ }
+
+ //
+ // Determine if the binding should be added or removed from
+ // the broadcast/multicast list.
+ //
+ if (!fOnBMSList && fAddToBMSList)
+ {
+ //
+ // Add the binding to the broadcast/multicast list.
+ //
+ fddiUpdateBroadcastBindingList(Filter, Binding, TRUE);
+ }
+ else if (fOnBMSList && !fAddToBMSList)
+ {
+ //
+ // Remove the binding from the broadcast/multicast list.
+ //
+ fddiUpdateBroadcastBindingList(Filter, Binding, FALSE);
+ }
+}
+
+
+VOID
+fddiUndoFilterAdjust(
+ IN PFDDI_FILTER Filter,
+ IN PFDDI_BINDING_INFO Binding
+ )
+/*++
+
+Routine Description:
+
+ This routine will restore the original filter settings.
+
+Arguments:
+
+ Filter - Pointer to the filter database that the binding belongs to.
+ Binding - Pointer to the binding.
+
+--*/
+{
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+ Binding->PacketFilters = Binding->OldPacketFilters;
+ Filter->CombinedPacketFilter = Filter->OldCombinedPacketFilter;
+
+ //
+ // Update the filter lists.
+ //
+ fddiUpdateSpecificBindingLists(Filter, Binding);
+}
+
+
+
+NDIS_STATUS
+FddiFilterAdjust(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT FilterClasses,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ The FilterAdjust routine will call an action routine when a
+ particular filter class is changes from not being used by any
+ binding to being used by at least one binding or vice versa.
+
+ If the action routine returns a value other than pending or
+ success then this routine has no effect on the packet filters
+ for the open or for the adapter as a whole.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - A pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routine,
+ this will be passed to it.
+
+ FilterClasses - The filter classes that are to be added or
+ deleted.
+
+ Set - A boolean that determines whether the filter classes
+ are being adjusted due to a set or because of a close. (The filtering
+ routines don't care, the MAC might.)
+
+Return Value:
+
+ If it calls the action routine then it will return the
+ status returned by the action routine. If the status
+ returned by the action routine is anything other than
+ NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
+ will be returned to the state it was in upon entrance to this
+ routine.
+
+ If the action routine is not called this routine will return
+ the following statum:
+
+ NDIS_STATUS_SUCCESS - If the new packet filters doesn't change
+ the combined mask of all bindings packet filters.
+
+--*/
+
+{
+ PFDDI_BINDING_INFO LocalOpen = (PFDDI_BINDING_INFO)NdisFilterHandle;
+ PFDDI_BINDING_INFO OpenList;
+
+ //
+ // Holds the status returned to the user of this routine, if the
+ // action routine is not called then the status will be success,
+ // otherwise, it is whatever the action routine returns.
+ //
+ NDIS_STATUS StatusOfAdjust;
+
+ //
+ // Set the new filter information for the open.
+ //
+ LocalOpen->OldPacketFilters = LocalOpen->PacketFilters;
+ LocalOpen->PacketFilters = FilterClasses;
+
+ Filter->OldCombinedPacketFilter = Filter->CombinedPacketFilter;
+
+ //
+ // We always have to reform the compbined filter since
+ // this filter index may have been the only filter index
+ // to use a particular bit.
+ //
+ for (OpenList = Filter->OpenList, Filter->CombinedPacketFilter = 0;
+ OpenList != NULL;
+ OpenList = OpenList->NextOpen)
+ {
+ Filter->CombinedPacketFilter |= OpenList->PacketFilters;
+ }
+
+ //
+ // Update the filter lists.
+ //
+ fddiUpdateSpecificBindingLists(Filter, LocalOpen);
+
+ if ((Filter->OldCombinedPacketFilter & ~NDIS_PACKET_TYPE_ALL_LOCAL) !=
+ (Filter->CombinedPacketFilter & ~NDIS_PACKET_TYPE_ALL_LOCAL))
+ {
+ StatusOfAdjust = Filter->FilterChangeAction(Filter->OldCombinedPacketFilter & ~NDIS_PACKET_TYPE_ALL_LOCAL,
+ Filter->CombinedPacketFilter & ~NDIS_PACKET_TYPE_ALL_LOCAL,
+ LocalOpen->MacBindingHandle,
+ NdisRequest,
+ Set);
+
+ if ((StatusOfAdjust != NDIS_STATUS_SUCCESS) &&
+ (StatusOfAdjust != NDIS_STATUS_PENDING))
+ {
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+ fddiUndoFilterAdjust(Filter, LocalOpen);
+ }
+ }
+ else
+ {
+ StatusOfAdjust = NDIS_STATUS_SUCCESS;
+ }
+
+ return(StatusOfAdjust);
+}
+
+
+UINT
+FddiNumberOfOpenFilterLongAddresses(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine counts the number of multicast addresses that a specific
+ open has.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to open block.
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ UINT IndexOfAddress;
+ UINT CountOfAddresses = 0;
+
+ UINT FilterIndex = ((PFDDI_BINDING_INFO)NdisFilterHandle)->FilterIndex;
+
+ for(IndexOfAddress=0;
+ IndexOfAddress < Filter->NumberOfLongAddresses;
+ IndexOfAddress++
+ )
+ {
+ if (IS_BIT_SET_IN_MASK(FilterIndex,
+ Filter->BindingsUsingLongAddress[IndexOfAddress]))
+ {
+ CountOfAddresses++;
+ }
+ }
+
+ return(CountOfAddresses);
+}
+
+
+UINT
+FddiNumberOfOpenFilterShortAddresses(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine counts the number of multicast addresses that a specific
+ open has.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to open block.
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ UINT IndexOfAddress;
+ UINT CountOfAddresses = 0;
+
+ UINT FilterIndex = ((PFDDI_BINDING_INFO)NdisFilterHandle)->FilterIndex;
+
+ for(IndexOfAddress=0;
+ IndexOfAddress < Filter->NumberOfShortAddresses;
+ IndexOfAddress++
+ )
+ {
+ if (IS_BIT_SET_IN_MASK(FilterIndex,
+ Filter->BindingsUsingShortAddress[IndexOfAddress]))
+ {
+ CountOfAddresses++;
+ }
+ }
+
+ return(CountOfAddresses);
+}
+
+
+VOID
+FddiQueryOpenFilterLongAddresses(
+ OUT PNDIS_STATUS Status,
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN UINT SizeOfArray,
+ OUT PUINT NumberOfAddresses,
+ OUT CHAR AddressArray[][FDDI_LENGTH_OF_LONG_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ The routine should be used by the MAC before
+ it actually alters the hardware registers to effect a
+ filtering hardware. This is usefull if another binding
+ has altered the address list since the action routine
+ is called.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Status - A pointer to the status of the call, NDIS_STATUS_SUCCESS or
+ NDIS_STATUS_FAILURE. Use EthNumberOfOpenAddresses() to get the
+ size that is needed.
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to the open block
+
+ SizeOfArray - The byte count of the AddressArray.
+
+ NumberOfAddresses - The number of addresses written to the array.
+
+ AddressArray - Will be filled with the addresses currently in the
+ multicast address list.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ UINT IndexOfAddress;
+ UINT CountOfAddresses = 0;
+ UINT FilterIndex = ((PFDDI_BINDING_INFO)NdisFilterHandle)->FilterIndex;
+
+ for(IndexOfAddress=0;
+ IndexOfAddress < Filter->NumberOfLongAddresses;
+ IndexOfAddress++
+ )
+ {
+ if (IS_BIT_SET_IN_MASK(FilterIndex,
+ Filter->BindingsUsingLongAddress[IndexOfAddress]))
+ {
+ if (SizeOfArray < FDDI_LENGTH_OF_LONG_ADDRESS)
+ {
+ *Status = NDIS_STATUS_FAILURE;
+
+ *NumberOfAddresses = 0;
+
+ return;
+ }
+
+ SizeOfArray -= FDDI_LENGTH_OF_LONG_ADDRESS;
+
+ MoveMemory(
+ AddressArray[CountOfAddresses],
+ Filter->MulticastLongAddresses[IndexOfAddress],
+ FDDI_LENGTH_OF_LONG_ADDRESS);
+
+ CountOfAddresses++;
+ }
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ *NumberOfAddresses = CountOfAddresses;
+}
+
+
+VOID
+FddiQueryOpenFilterShortAddresses(
+ OUT PNDIS_STATUS Status,
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN UINT SizeOfArray,
+ OUT PUINT NumberOfAddresses,
+ OUT CHAR AddressArray[][FDDI_LENGTH_OF_SHORT_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ The routine should be used by the MAC before
+ it actually alters the hardware registers to effect a
+ filtering hardware. This is usefull if another binding
+ has altered the address list since the action routine
+ is called.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Status - A pointer to the status of the call, NDIS_STATUS_SUCCESS or
+ NDIS_STATUS_FAILURE. Use EthNumberOfOpenAddresses() to get the
+ size that is needed.
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to the open block
+
+ SizeOfArray - The byte count of the AddressArray.
+
+ NumberOfAddresses - The number of addresses written to the array.
+
+ AddressArray - Will be filled with the addresses currently in the
+ multicast address list.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ UINT IndexOfAddress;
+ UINT CountOfAddresses = 0;
+ UINT FilterIndex = ((PFDDI_BINDING_INFO)NdisFilterHandle)->FilterIndex;
+
+ for(IndexOfAddress=0;
+ IndexOfAddress < Filter->NumberOfShortAddresses;
+ IndexOfAddress++
+ )
+ {
+ if (IS_BIT_SET_IN_MASK(FilterIndex,
+ Filter->BindingsUsingShortAddress[IndexOfAddress]))
+ {
+ if (SizeOfArray < FDDI_LENGTH_OF_SHORT_ADDRESS)
+ {
+ *Status = NDIS_STATUS_FAILURE;
+
+ *NumberOfAddresses = 0;
+
+ return;
+ }
+
+ SizeOfArray -= FDDI_LENGTH_OF_SHORT_ADDRESS;
+
+ MoveMemory(AddressArray[CountOfAddresses],
+ Filter->MulticastShortAddresses[IndexOfAddress],
+ FDDI_LENGTH_OF_SHORT_ADDRESS);
+
+ CountOfAddresses++;
+ }
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ *NumberOfAddresses = CountOfAddresses;
+}
+
+
+VOID
+FddiQueryGlobalFilterLongAddresses(
+ OUT PNDIS_STATUS Status,
+ IN PFDDI_FILTER Filter,
+ IN UINT SizeOfArray,
+ OUT PUINT NumberOfAddresses,
+ IN OUT CHAR AddressArray[][FDDI_LENGTH_OF_LONG_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ The routine should be used by the MAC before
+ it actually alters the hardware registers to effect a
+ filtering hardware. This is usefull if another binding
+ has altered the address list since the action routine
+ is called.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Status - A pointer to the status of the call, NDIS_STATUS_SUCCESS or
+ NDIS_STATUS_FAILURE. Use FDDI_NUMBER_OF_GLOBAL_LONG_ADDRESSES() to get the
+ size that is needed.
+
+ Filter - A pointer to the filter database.
+
+ SizeOfArray - The byte count of the AddressArray.
+
+ NumberOfAddresses - A pointer to the number of addresses written to the
+ array.
+
+ AddressArray - Will be filled with the addresses currently in the
+ multicast address list.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ if (SizeOfArray < (Filter->NumberOfLongAddresses * FDDI_LENGTH_OF_LONG_ADDRESS))
+ {
+ *Status = NDIS_STATUS_FAILURE;
+
+ *NumberOfAddresses = 0;
+ }
+ else
+ {
+ *Status = NDIS_STATUS_SUCCESS;
+
+ *NumberOfAddresses = Filter->NumberOfLongAddresses;
+
+ MoveMemory(AddressArray[0],
+ Filter->MulticastLongAddresses[0],
+ Filter->NumberOfLongAddresses*FDDI_LENGTH_OF_LONG_ADDRESS);
+ }
+}
+
+
+VOID
+FddiQueryGlobalFilterShortAddresses(
+ OUT PNDIS_STATUS Status,
+ IN PFDDI_FILTER Filter,
+ IN UINT SizeOfArray,
+ OUT PUINT NumberOfAddresses,
+ IN OUT CHAR AddressArray[][FDDI_LENGTH_OF_SHORT_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ The routine should be used by the MAC before
+ it actually alters the hardware registers to effect a
+ filtering hardware. This is usefull if another binding
+ has altered the address list since the action routine
+ is called.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Status - A pointer to the status of the call, NDIS_STATUS_SUCCESS or
+ NDIS_STATUS_FAILURE. Use FDDI_NUMBER_OF_GLOBAL_SHORT_ADDRESSES() to get the
+ size that is needed.
+
+ Filter - A pointer to the filter database.
+
+ SizeOfArray - The byte count of the AddressArray.
+
+ NumberOfAddresses - A pointer to the number of addresses written to the
+ array.
+
+ AddressArray - Will be filled with the addresses currently in the
+ multicast address list.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ if (SizeOfArray < (Filter->NumberOfShortAddresses * FDDI_LENGTH_OF_SHORT_ADDRESS))
+ {
+ *Status = NDIS_STATUS_FAILURE;
+
+ *NumberOfAddresses = 0;
+ }
+ else
+ {
+ *Status = NDIS_STATUS_SUCCESS;
+
+ *NumberOfAddresses = Filter->NumberOfShortAddresses;
+
+ MoveMemory(AddressArray[0],
+ Filter->MulticastShortAddresses[0],
+ Filter->NumberOfShortAddresses*FDDI_LENGTH_OF_SHORT_ADDRESS);
+ }
+}
+
+
+VOID
+FddiFilterDprIndicateReceiveFullMac(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PCHAR Address,
+ IN UINT AddressLength,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate a packet to
+ all bindings. The packet will be filtered so that only the
+ appropriate bindings will receive the packet.
+
+ Called at DPC_LEVEL.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ MacReceiveContext - A MAC supplied context value that must be
+ returned by the protocol if it calls MacTransferData.
+
+ Address - The destination address from the received packet.
+
+ AddressLength - The length of the above address.
+
+ HeaderBuffer - A virtual address of the virtually contiguous
+ buffer containing the MAC header of the packet.
+
+ HeaderBufferSize - An unsigned integer indicating the size of
+ the header buffer, in bytes.
+
+ LookaheadBuffer - A virtual address of the virtually contiguous
+ buffer containing the first LookaheadBufferSize bytes of data
+ of the packet. The packet buffer is valid only within the current
+ call to the receive event handler.
+
+ LookaheadBufferSize - An unsigned integer indicating the size of
+ the lookahead buffer, in bytes.
+
+ PacketSize - An unsigned integer indicating the size of the received
+ packet, in bytes. This number has nothing to do with the lookahead
+ buffer, but indicates how large the arrived packet is so that a
+ subsequent MacTransferData request can be made to transfer the entire
+ packet as necessary.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Will hold the type of address that we know we've got.
+ //
+ UINT AddressType;
+
+ //
+ // Will hold the status of indicating the receive packet.
+ // ZZZ For now this isn't used.
+ //
+ NDIS_STATUS StatusOfReceive;
+
+ //
+ // Will hold the filter classes of the binding being indicated.
+ //
+ UINT BindingFilters;
+
+ //
+ // Current Open to indicate to.
+ //
+ PFDDI_BINDING_INFO LocalOpen, NextOpen;
+
+ //
+ // Holds the result of address determinations.
+ //
+ INT ResultOfAddressCheck;
+
+ //
+ // If the packet is a runt packet, then only indicate to PROMISCUOUS
+ //
+ if ((HeaderBufferSize > (2 * AddressLength)) && (PacketSize != 0))
+ {
+ BOOLEAN fDirected;
+
+ fDirected = FALSE;
+ FDDI_IS_SMT(*((PCHAR)HeaderBuffer), &ResultOfAddressCheck);
+ if (!ResultOfAddressCheck)
+ {
+ fDirected = (((UCHAR)Address[0] & 0x01) == 0);
+ }
+
+ //
+ // Handle the directed packet case first
+ //
+ if (fDirected)
+ {
+ BOOLEAN IsNotOurs;
+
+ //
+ // If it is a directed packet, then check if the combined packet
+ // filter is PROMISCUOUS, if it is check if it is directed towards
+ // us. Eliminate the SMT case.
+ //
+ IsNotOurs = FALSE; // Assume it is
+ if (Filter->CombinedPacketFilter & (NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_ALL_LOCAL |
+ NDIS_PACKET_TYPE_ALL_MULTICAST))
+ {
+ FDDI_COMPARE_NETWORK_ADDRESSES_EQ((AddressLength == FDDI_LENGTH_OF_LONG_ADDRESS) ?
+ Filter->AdapterLongAddress :
+ Filter->AdapterShortAddress,
+ Address,
+ AddressLength,
+ &IsNotOurs);
+ }
+
+ //
+ // Walk the directed list and indicate up the packets.
+ //
+ for (LocalOpen = Filter->DirectedList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextDirected;
+
+ //
+ // Ignore if not directed to us or if the binding is not promiscuous
+ //
+ if (((LocalOpen->PacketFilters & NDIS_PACKET_TYPE_PROMISCUOUS) == 0) &&
+ IsNotOurs)
+ {
+ continue;
+ }
+
+ LocalOpen->References++;
+
+ NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ //
+ // Indicate the packet to the binding.
+ //
+ ProtocolFilterIndicateReceive(&StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize,
+ NdisMediumFddi);
+
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ --LocalOpen->References;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+ fddiRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+
+ return;
+ }
+
+ //
+ // Determine whether the input address is a simple direct,
+ // a broadcast, a multicast, or an SMT address.
+ //
+ FDDI_IS_SMT(*((PCHAR)HeaderBuffer), &ResultOfAddressCheck);
+ if (ResultOfAddressCheck)
+ {
+ AddressType = NDIS_PACKET_TYPE_SMT;
+ }
+ else
+ {
+ //
+ // First check if it *at least* has the multicast address bit.
+ //
+ FDDI_IS_MULTICAST(Address, AddressLength, &ResultOfAddressCheck);
+ if (ResultOfAddressCheck)
+ {
+ //
+ // It is at least a multicast address. Check to see if
+ // it is a broadcast address.
+ //
+
+ FDDI_IS_BROADCAST(Address, AddressLength, &ResultOfAddressCheck);
+ if (ResultOfAddressCheck)
+ {
+ FDDI_CHECK_FOR_INVALID_BROADCAST_INDICATION(Filter);
+
+ AddressType = NDIS_PACKET_TYPE_BROADCAST;
+ }
+ else
+ {
+ AddressType = NDIS_PACKET_TYPE_MULTICAST;
+ }
+ }
+ }
+ }
+ else
+ {
+ // Runt Packet
+ AddressType = NDIS_PACKET_TYPE_PROMISCUOUS;
+ }
+
+ //
+ // At this point we know that the packet is either:
+ // - Runt packet - indicated by AddressType = NDIS_PACKET_TYPE_PROMISCUOUS (OR)
+ // - Broadcast packet - indicated by AddressType = NDIS_PACKET_TYPE_BROADCAST (OR)
+ // - Multicast packet - indicated by AddressType = NDIS_PACKET_TYPE_MULTICAST
+ // - SMT Packet - indicated by AddressType = NDIS_PACKET_TYPE_SMT
+ //
+ // Walk the broadcast/multicast/SMT list and indicate up the packets.
+ //
+ // The packet is indicated if it meets the following criteria:
+ //
+ // if ((Binding is promiscuous) OR
+ // ((Packet is broadcast) AND (Binding is Broadcast)) OR
+ // ((Packet is SMT) AND (Binding is SMT)) OR
+ // ((Packet is multicast) AND
+ // ((Binding is all-multicast) OR
+ // ((Binding is multicast) AND (address in approp. multicast list)))))
+ //
+ //
+ // Is this a directed packet?
+ //
+ for (LocalOpen = Filter->BMSList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ UINT LocalFilter = LocalOpen->PacketFilters;
+ UINT IndexOfAddress;
+
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextBMS;
+
+ if ((LocalFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_BROADCAST) &&
+ (LocalFilter & NDIS_PACKET_TYPE_BROADCAST)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_SMT) &&
+ (LocalFilter & NDIS_PACKET_TYPE_SMT)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_MULTICAST) &&
+ ((LocalFilter & NDIS_PACKET_TYPE_ALL_MULTICAST) ||
+ ((LocalFilter & NDIS_PACKET_TYPE_MULTICAST) &&
+ (((AddressLength == FDDI_LENGTH_OF_LONG_ADDRESS) &&
+ FddiFindMulticastLongAddress(Filter->NumberOfLongAddresses,
+ Filter->MulticastLongAddresses,
+ Address,
+ &IndexOfAddress) &&
+ IS_BIT_SET_IN_MASK(LocalOpen->FilterIndex,
+ Filter->BindingsUsingLongAddress[IndexOfAddress])
+ ) ||
+ ((AddressLength == FDDI_LENGTH_OF_SHORT_ADDRESS) &&
+ FddiFindMulticastShortAddress(Filter->NumberOfShortAddresses,
+ Filter->MulticastShortAddresses,
+ Address,
+ &IndexOfAddress) &&
+ IS_BIT_SET_IN_MASK(LocalOpen->FilterIndex,
+ Filter->BindingsUsingLongAddress[IndexOfAddress])
+ )
+ )
+ )
+ )
+ )
+ )
+ {
+ LocalOpen->References++;
+
+ NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ //
+ // Indicate the packet to the binding.
+ //
+
+ ProtocolFilterIndicateReceive(&StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize,
+ NdisMediumFddi);
+
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ LocalOpen->References--;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+ fddiRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+ }
+}
+
+
+
+VOID
+FddiFilterIndicateReceive(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PCHAR Address,
+ IN UINT AddressLength,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate a packet to
+ all bindings. The packet will be filtered so that only the
+ appropriate bindings will receive the packet.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ MacReceiveContext - A MAC supplied context value that must be
+ returned by the protocol if it calls MacTransferData.
+
+ Address - The destination address from the received packet.
+
+ AddressLength - The length of the above address.
+
+ HeaderBuffer - A virtual address of the virtually contiguous
+ buffer containing the MAC header of the packet.
+
+ HeaderBufferSize - An unsigned integer indicating the size of
+ the header buffer, in bytes.
+
+ LookaheadBuffer - A virtual address of the virtually contiguous
+ buffer containing the first LookaheadBufferSize bytes of data
+ of the packet. The packet buffer is valid only within the current
+ call to the receive event handler.
+
+ LookaheadBufferSize - An unsigned integer indicating the size of
+ the lookahead buffer, in bytes.
+
+ PacketSize - An unsigned integer indicating the size of the received
+ packet, in bytes. This number has nothing to do with the lookahead
+ buffer, but indicates how large the arrived packet is so that a
+ subsequent MacTransferData request can be made to transfer the entire
+ packet as necessary.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ KIRQL OldIrql;
+
+ NDIS_ACQUIRE_SPIN_LOCK(Filter->Lock, &OldIrql);
+
+ FddiFilterDprIndicateReceiveFullMac(Filter,
+ MacReceiveContext,
+ Address,
+ AddressLength,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize);
+
+ NDIS_RELEASE_SPIN_LOCK(Filter->Lock, OldIrql);
+}
+
+
+VOID
+FddiFilterDprIndicateReceive(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PCHAR Address,
+ IN UINT AddressLength,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate a packet to
+ all bindings. The packet will be filtered so that only the
+ appropriate bindings will receive the packet.
+
+ Called at DPC_LEVEL.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ MacReceiveContext - A MAC supplied context value that must be
+ returned by the protocol if it calls MacTransferData.
+
+ Address - The destination address from the received packet.
+
+ AddressLength - The length of the above address.
+
+ HeaderBuffer - A virtual address of the virtually contiguous
+ buffer containing the MAC header of the packet.
+
+ HeaderBufferSize - An unsigned integer indicating the size of
+ the header buffer, in bytes.
+
+ LookaheadBuffer - A virtual address of the virtually contiguous
+ buffer containing the first LookaheadBufferSize bytes of data
+ of the packet. The packet buffer is valid only within the current
+ call to the receive event handler.
+
+ LookaheadBufferSize - An unsigned integer indicating the size of
+ the lookahead buffer, in bytes.
+
+ PacketSize - An unsigned integer indicating the size of the received
+ packet, in bytes. This number has nothing to do with the lookahead
+ buffer, but indicates how large the arrived packet is so that a
+ subsequent MacTransferData request can be made to transfer the entire
+ packet as necessary.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Will hold the type of address that we know we've got.
+ //
+ UINT AddressType;
+
+ //
+ // Will hold the status of indicating the receive packet.
+ // ZZZ For now this isn't used.
+ //
+ NDIS_STATUS StatusOfReceive;
+
+ //
+ // Will hold the filter classes of the binding being indicated.
+ //
+ UINT BindingFilters;
+
+ //
+ // Current Open to indicate to.
+ //
+ PFDDI_BINDING_INFO LocalOpen, NextOpen;
+
+ //
+ // Holds the result of address determinations.
+ //
+ INT ResultOfAddressCheck;
+
+ //
+ // If the packet is a runt packet, then only indicate to PROMISCUOUS
+ //
+ if ((HeaderBufferSize > (2 * AddressLength)) && (PacketSize != 0))
+ {
+ BOOLEAN fDirected;
+
+ fDirected = FALSE;
+ FDDI_IS_SMT(*((PCHAR)HeaderBuffer), &ResultOfAddressCheck);
+ if (!ResultOfAddressCheck)
+ {
+ fDirected = (((UCHAR)Address[0] & 0x01) == 0);
+ }
+
+ //
+ // Handle the directed packet case first
+ //
+ if (fDirected)
+ {
+ BOOLEAN IsNotOurs;
+
+ //
+ // If it is a directed packet, then check if the combined packet
+ // filter is PROMISCUOUS, if it is check if it is directed towards
+ // us. Eliminate the SMT case.
+ //
+ IsNotOurs = FALSE; // Assume it is
+ if (Filter->CombinedPacketFilter & (NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_ALL_LOCAL |
+ NDIS_PACKET_TYPE_ALL_MULTICAST))
+ {
+ FDDI_COMPARE_NETWORK_ADDRESSES_EQ((AddressLength == FDDI_LENGTH_OF_LONG_ADDRESS) ?
+ Filter->AdapterLongAddress :
+ Filter->AdapterShortAddress,
+ Address,
+ AddressLength,
+ &IsNotOurs);
+ }
+
+ //
+ // Walk the directed list and indicate up the packets.
+ //
+ for (LocalOpen = Filter->DirectedList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextDirected;
+
+ //
+ // Ignore if not directed to us or if the binding is not promiscuous
+ //
+ if (((LocalOpen->PacketFilters & NDIS_PACKET_TYPE_PROMISCUOUS) == 0) &&
+ IsNotOurs)
+ {
+ continue;
+ }
+
+ LocalOpen->References++;
+
+// NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ //
+ // Indicate the packet to the binding.
+ //
+ ProtocolFilterIndicateReceive(&StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize,
+ NdisMediumFddi);
+
+// NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ --LocalOpen->References;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+ fddiRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+
+ return;
+ }
+
+ //
+ // Determine whether the input address is a simple direct,
+ // a broadcast, a multicast, or an SMT address.
+ //
+ FDDI_IS_SMT(*((PCHAR)HeaderBuffer), &ResultOfAddressCheck);
+ if (ResultOfAddressCheck)
+ {
+ AddressType = NDIS_PACKET_TYPE_SMT;
+ }
+ else
+ {
+ //
+ // First check if it *at least* has the multicast address bit.
+ //
+ FDDI_IS_MULTICAST(Address, AddressLength, &ResultOfAddressCheck);
+ if (ResultOfAddressCheck)
+ {
+ //
+ // It is at least a multicast address. Check to see if
+ // it is a broadcast address.
+ //
+
+ FDDI_IS_BROADCAST(Address, AddressLength, &ResultOfAddressCheck);
+ if (ResultOfAddressCheck)
+ {
+ FDDI_CHECK_FOR_INVALID_BROADCAST_INDICATION(Filter);
+
+ AddressType = NDIS_PACKET_TYPE_BROADCAST;
+ }
+ else
+ {
+ AddressType = NDIS_PACKET_TYPE_MULTICAST;
+ }
+ }
+ }
+ }
+ else
+ {
+ // Runt Packet
+ AddressType = NDIS_PACKET_TYPE_PROMISCUOUS;
+ }
+
+ //
+ // At this point we know that the packet is either:
+ // - Runt packet - indicated by AddressType = NDIS_PACKET_TYPE_PROMISCUOUS (OR)
+ // - Broadcast packet - indicated by AddressType = NDIS_PACKET_TYPE_BROADCAST (OR)
+ // - Multicast packet - indicated by AddressType = NDIS_PACKET_TYPE_MULTICAST
+ // - SMT Packet - indicated by AddressType = NDIS_PACKET_TYPE_SMT
+ //
+ // Walk the broadcast/multicast/SMT list and indicate up the packets.
+ //
+ // The packet is indicated if it meets the following criteria:
+ //
+ // if ((Binding is promiscuous) OR
+ // ((Packet is broadcast) AND (Binding is Broadcast)) OR
+ // ((Packet is SMT) AND (Binding is SMT)) OR
+ // ((Packet is multicast) AND
+ // ((Binding is all-multicast) OR
+ // ((Binding is multicast) AND (address in approp. multicast list)))))
+ //
+ //
+ // Is this a directed packet?
+ //
+ for (LocalOpen = Filter->BMSList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ UINT LocalFilter = LocalOpen->PacketFilters;
+ UINT IndexOfAddress;
+
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextBMS;
+
+ if ((LocalFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_BROADCAST) &&
+ (LocalFilter & NDIS_PACKET_TYPE_BROADCAST)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_SMT) &&
+ (LocalFilter & NDIS_PACKET_TYPE_SMT)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_MULTICAST) &&
+ ((LocalFilter & NDIS_PACKET_TYPE_ALL_MULTICAST) ||
+ ((LocalFilter & NDIS_PACKET_TYPE_MULTICAST) &&
+ (((AddressLength == FDDI_LENGTH_OF_LONG_ADDRESS) &&
+ FddiFindMulticastLongAddress(Filter->NumberOfLongAddresses,
+ Filter->MulticastLongAddresses,
+ Address,
+ &IndexOfAddress) &&
+ IS_BIT_SET_IN_MASK(LocalOpen->FilterIndex,
+ Filter->BindingsUsingLongAddress[IndexOfAddress])
+ ) ||
+ ((AddressLength == FDDI_LENGTH_OF_SHORT_ADDRESS) &&
+ FddiFindMulticastShortAddress(Filter->NumberOfShortAddresses,
+ Filter->MulticastShortAddresses,
+ Address,
+ &IndexOfAddress) &&
+ IS_BIT_SET_IN_MASK(LocalOpen->FilterIndex,
+ Filter->BindingsUsingLongAddress[IndexOfAddress])
+ )
+ )
+ )
+ )
+ )
+ )
+ {
+ LocalOpen->References++;
+
+// NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ //
+ // Indicate the packet to the binding.
+ //
+
+ ProtocolFilterIndicateReceive(&StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize,
+ NdisMediumFddi);
+
+// NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ LocalOpen->References--;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+ fddiRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+ }
+}
+
+
+VOID
+FddiFilterDprIndicateReceivePacket(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+)
+
+/*++
+
+Routine Description:
+
+ This routine is called by the Miniport to indicate packets to
+ all bindings. The packets will be filtered so that only the
+ appropriate bindings will receive the individual packets.
+ This is the code path for ndis 4.0 miniport drivers.
+
+Arguments:
+
+ Miniport - The Miniport block.
+
+ PacketArray - An array of Packets indicated by the miniport.
+
+ NumberOfPackets - Self-explanatory.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // The Filter of interest
+ //
+ PFDDI_FILTER Filter = Miniport->FddiDB;
+
+ //
+ // Current packet being processed
+ //
+ PPNDIS_PACKET pPktArray = PacketArray;
+
+ //
+ // Pointer to the buffer in the ndispacket
+ //
+ PNDIS_BUFFER Buffer;
+
+ //
+ // Total packet length
+ //
+ UINT i, LASize, PacketSize, NumIndicates = 0;
+
+ //
+ // Pointer to the 1st segment of the buffer, points to dest address
+ //
+ PUCHAR Address, Hdr;
+
+ UINT AddressLength;
+
+ //
+ // Will hold the type of address that we know we've got.
+ //
+ UINT AddressType;
+
+ //
+ // Will hold the status of indicating the receive packet.
+ // ZZZ For now this isn't used.
+ //
+ NDIS_STATUS StatusOfReceive;
+
+ //
+ // Will hold the filter classes of the binding being indicated.
+ //
+ UINT BindingFilters;
+
+ //
+ // Decides whether we use the protocol's revpkt handler or fall
+ // back to old rcvindicate handler
+ //
+ BOOLEAN fFallBack, fPmode, FixRef;
+
+ //
+ // Current Open to indicate to.
+ //
+ PFDDI_BINDING_INFO LocalOpen, NextOpen;
+ PNDIS_OPEN_BLOCK pOpenBlock; \
+
+ //
+ // Holds the result of address determinations.
+ //
+ INT ResultOfAddressCheck;
+
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID);
+
+ // Walk all the packets
+ for (i = 0; i < NumberOfPackets; i++, pPktArray++)
+ {
+ PNDIS_PACKET Packet = *pPktArray;
+ PNDIS_PACKET_OOB_DATA pOob;
+
+ ASSERT(Packet != NULL);
+
+ pOob = NDIS_OOB_DATA_FROM_PACKET(Packet);
+
+ NdisGetFirstBufferFromPacket(Packet,
+ &Buffer,
+ &Address,
+ &LASize,
+ &PacketSize);
+ ASSERT(Buffer != NULL);
+
+ Hdr = Address++;
+
+ AddressLength = (*Hdr & 0x40) ?
+ FDDI_LENGTH_OF_LONG_ADDRESS :
+ FDDI_LENGTH_OF_SHORT_ADDRESS;
+ ASSERT(pOob->HeaderSize == (AddressLength * 2 + 1));
+
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount = 0;
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->Miniport = Miniport;
+
+ //
+ // Set the status here that nobody is holding the packet. This will get
+ // overwritten by the real status from the protocol. Pay heed to what
+ // the miniport is saying.
+ //
+ if (pOob->Status != NDIS_STATUS_RESOURCES)
+ {
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount --;
+ pOob->Status = NDIS_STATUS_SUCCESS;
+ fFallBack = FALSE;
+ FixRef = TRUE;
+ }
+ else
+ {
+ fFallBack = TRUE;
+ FixRef = FALSE;
+ }
+
+ //
+ // Ensure that we force re-calculation.
+ //
+ Packet->Private.ValidCounts = FALSE;
+
+ //
+ // A quick check for Runt packets. These are only indicated to Promiscuous bindings
+ //
+ if (PacketSize > pOob->HeaderSize)
+ {
+ BOOLEAN fDirected;
+
+ fDirected = FALSE;
+ FDDI_IS_SMT(*Address, &ResultOfAddressCheck);
+ if (!ResultOfAddressCheck)
+ {
+ fDirected = (((UCHAR)Address[0] & 0x01) == 0);
+ }
+
+ //
+ // Handle the directed packet case first
+ //
+ if (fDirected)
+ {
+ BOOLEAN IsNotOurs;
+ //
+ // If it is a directed packet, then check if the combined packet
+ // filter is PROMISCUOUS, if it is check if it is directed towards
+ // us. Eliminate the SMT case.
+ //
+ IsNotOurs = FALSE; // Assume it is
+ if (Filter->CombinedPacketFilter & (NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_ALL_LOCAL |
+ NDIS_PACKET_TYPE_ALL_MULTICAST))
+ {
+ FDDI_COMPARE_NETWORK_ADDRESSES_EQ((AddressLength == FDDI_LENGTH_OF_LONG_ADDRESS) ?
+ Filter->AdapterLongAddress :
+ Filter->AdapterShortAddress,
+ Address,
+ AddressLength,
+ &IsNotOurs);
+ }
+
+ //
+ // We definitely have a directed packet so lets indicate it now.
+ //
+ // Walk the directed list and indicate up the packets.
+ //
+ for (LocalOpen = Filter->DirectedList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextDirected;
+
+ //
+ // Ignore if not directed to us or if the binding is not promiscuous
+ //
+ if (((LocalOpen->PacketFilters & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) == 0) &&
+ IsNotOurs)
+ {
+ continue;
+ }
+
+ pOpenBlock = (PNDIS_OPEN_BLOCK)(LocalOpen->NdisBindingContext);
+ LocalOpen->ReceivedAPacket = TRUE;
+ LocalOpen->References++;
+ NumIndicates ++;
+
+ fPmode = (LocalOpen->PacketFilters & (NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_ALL_LOCAL)) ?
+ TRUE : FALSE;
+ IndicateToProtocol(Miniport,
+ Filter,
+ pOpenBlock,
+ Packet,
+ Hdr,
+ PacketSize,
+ pOob->HeaderSize,
+ &fFallBack,
+ fPmode,
+ NdisMediumFddi);
+
+ LocalOpen->References--;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+ fddiRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+
+ if (FixRef)
+ {
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount++;
+ if (PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount != 0)
+ {
+ NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_PENDING);
+ }
+ }
+ continue; // Done with this packet
+ }
+
+ //
+ // Determine whether the input address is a simple direct,
+ // a broadcast, a multicast, or an SMT address.
+ //
+ FDDI_IS_SMT(*Address, &ResultOfAddressCheck);
+ if (ResultOfAddressCheck)
+ {
+ AddressType = NDIS_PACKET_TYPE_SMT;
+ }
+ else
+ {
+ //
+ // First check if it *at least* has the multicast address bit.
+ //
+ FDDI_IS_MULTICAST(Address, AddressLength, &ResultOfAddressCheck);
+ if (ResultOfAddressCheck)
+ {
+ //
+ // It is at least a multicast address. Check to see if
+ // it is a broadcast address.
+ //
+
+ FDDI_IS_BROADCAST(Address, AddressLength, &ResultOfAddressCheck);
+ if (ResultOfAddressCheck)
+ {
+ FDDI_CHECK_FOR_INVALID_BROADCAST_INDICATION(Filter);
+
+ AddressType = NDIS_PACKET_TYPE_BROADCAST;
+ }
+ else
+ {
+ AddressType = NDIS_PACKET_TYPE_MULTICAST;
+ }
+ }
+ }
+ }
+ else
+ {
+ // Runt Packet
+ AddressType = NDIS_PACKET_TYPE_PROMISCUOUS;
+ }
+
+ //
+ // At this point we know that the packet is either:
+ // - Runt packet - indicated by AddressType = NDIS_PACKET_TYPE_PROMISCUOUS (OR)
+ // - Broadcast packet - indicated by AddressType = NDIS_PACKET_TYPE_BROADCAST (OR)
+ // - Multicast packet - indicated by AddressType = NDIS_PACKET_TYPE_MULTICAST
+ // - SMT Packet - indicated by AddressType = NDIS_PACKET_TYPE_SMT
+ //
+ // Walk the broadcast/multicast/SMT list and indicate up the packets.
+ //
+ // The packet is indicated if it meets the following criteria:
+ //
+ // if ((Binding is promiscuous) OR
+ // ((Packet is broadcast) AND (Binding is Broadcast)) OR
+ // ((Packet is SMT) AND (Binding is SMT)) OR
+ // ((Packet is multicast) AND
+ // ((Binding is all-multicast) OR
+ // ((Binding is multicast) AND (address in approp. multicast list)))))
+ //
+ //
+ // Is this a directed packet?
+ //
+ for (LocalOpen = Filter->BMSList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ UINT LocalFilter = LocalOpen->PacketFilters;
+ UINT IndexOfAddress;
+
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextBMS;
+
+ if ((LocalFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_BROADCAST) &&
+ (LocalFilter & NDIS_PACKET_TYPE_BROADCAST)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_SMT) &&
+ (LocalFilter & NDIS_PACKET_TYPE_SMT)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_MULTICAST) &&
+ ((LocalFilter & NDIS_PACKET_TYPE_ALL_MULTICAST) ||
+ ((LocalFilter & NDIS_PACKET_TYPE_MULTICAST) &&
+ (((AddressLength == FDDI_LENGTH_OF_LONG_ADDRESS) &&
+ FddiFindMulticastLongAddress(Filter->NumberOfLongAddresses,
+ Filter->MulticastLongAddresses,
+ Address,
+ &IndexOfAddress) &&
+ IS_BIT_SET_IN_MASK(LocalOpen->FilterIndex,
+ Filter->BindingsUsingLongAddress[IndexOfAddress])
+ ) ||
+ ((AddressLength == FDDI_LENGTH_OF_SHORT_ADDRESS) &&
+ FddiFindMulticastShortAddress(Filter->NumberOfShortAddresses,
+ Filter->MulticastShortAddresses,
+ Address,
+ &IndexOfAddress) &&
+ IS_BIT_SET_IN_MASK(LocalOpen->FilterIndex,
+ Filter->BindingsUsingLongAddress[IndexOfAddress])
+ )
+ )
+ )
+ )
+ )
+ )
+ {
+ pOpenBlock = (PNDIS_OPEN_BLOCK)(LocalOpen->NdisBindingContext);
+ LocalOpen->ReceivedAPacket = TRUE;
+ LocalOpen->References++;
+ NumIndicates ++;
+
+ fPmode = (LocalFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) ?
+ TRUE : FALSE;
+ IndicateToProtocol(Miniport,
+ Filter,
+ pOpenBlock,
+ Packet,
+ Hdr,
+ PacketSize,
+ pOob->HeaderSize,
+ &fFallBack,
+ fPmode,
+ NdisMediumFddi);
+
+ LocalOpen->References--;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+ fddiRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+ }
+
+ if (FixRef)
+ {
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount++;
+ if (PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount != 0)
+ {
+ NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_PENDING);
+ }
+ }
+ }
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID);
+
+ if (NumIndicates > 0)
+ {
+ FddiFilterDprIndicateReceiveComplete(Filter);
+ }
+}
+
+
+VOID
+FddiFilterDprIndicateReceiveCompleteFullMac(
+ IN PFDDI_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate that the receive
+ process is complete to all bindings. Only those bindings which
+ have received packets will be notified.
+
+ Called at DPC_LEVEL.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PFDDI_BINDING_INFO LocalOpen, NextOpen;
+
+ //
+ // We need to aquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+ for (LocalOpen = Filter->OpenList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ NextOpen = LocalOpen->NextOpen;
+
+ if (LocalOpen->ReceivedAPacket)
+ {
+ //
+ // Indicate the binding.
+ //
+
+ LocalOpen->ReceivedAPacket = FALSE;
+
+ LocalOpen->References++;
+
+ NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ if ((--(LocalOpen->References)) == 0)
+ {
+ //
+ // This binding is shutting down. We have to kill it.
+ //
+ fddiRemoveBindingFromLists(Filter, LocalOpen);
+
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+ Filter->CloseAction(LocalOpen->MacBindingHandle);
+
+ FDDI_FILTER_FREE_OPEN(Filter, LocalOpen);
+ }
+ }
+ }
+}
+
+
+
+VOID
+FddiFilterIndicateReceiveComplete(
+ IN PFDDI_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate that the receive
+ process is complete to all bindings. Only those bindings which
+ have received packets will be notified.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ KIRQL OldIrql;
+
+ NDIS_ACQUIRE_SPIN_LOCK(Filter->Lock, &OldIrql);
+
+ FddiFilterDprIndicateReceiveCompleteFullMac(Filter);
+
+ NDIS_RELEASE_SPIN_LOCK(Filter->Lock, OldIrql);
+}
+
+
+VOID
+FddiFilterDprIndicateReceiveComplete(
+ IN PFDDI_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate that the receive
+ process is complete to all bindings. Only those bindings which
+ have received packets will be notified.
+
+ Called at DPC_LEVEL.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PFDDI_BINDING_INFO LocalOpen, NextOpen;
+
+ //
+ // We need to aquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+ for (LocalOpen = Filter->OpenList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ NextOpen = LocalOpen->NextOpen;
+
+ if (LocalOpen->ReceivedAPacket)
+ {
+ //
+ // Indicate the binding.
+ //
+
+ LocalOpen->ReceivedAPacket = FALSE;
+
+ LocalOpen->References++;
+
+// NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+// NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ if ((--(LocalOpen->References)) == 0)
+ {
+ //
+ // This binding is shutting down. We have to kill it.
+ //
+ fddiRemoveBindingFromLists(Filter, LocalOpen);
+
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+ Filter->CloseAction(LocalOpen->MacBindingHandle);
+
+ FDDI_FILTER_FREE_OPEN(Filter, LocalOpen);
+ }
+ }
+ }
+}
+
+
+BOOLEAN
+FddiFindMulticastLongAddress(
+ IN UINT NumberOfAddresses,
+ IN CHAR AddressArray[][FDDI_LENGTH_OF_LONG_ADDRESS],
+ IN CHAR MulticastAddress[FDDI_LENGTH_OF_LONG_ADDRESS],
+ OUT PUINT ArrayIndex
+ )
+
+/*++
+
+Routine Description:
+
+ Given an array of multicast addresses search the array for
+ a particular multicast address. It is assumed that the
+ address array is already sorted.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+ NOTE: This ordering is arbitrary but consistant.
+
+Arguments:
+
+ NumberOfAddresses - The number of addresses currently in the
+ address array.
+
+ AddressArray - An array of multicast addresses.
+
+ MulticastAddress - The address to search for in the address array.
+
+ ArrayIndex - Will point to where the MulticastAddress is in
+ the AddressArray, or if it isn't in the array, where it should
+ be in the array.
+
+Return Value:
+
+ If the address is in the sorted list this routine will return
+ TRUE, otherwise FALSE.
+
+--*/
+
+{
+
+ //
+ // Indices into the address array so that we may do a binary
+ // search.
+ //
+ UINT Bottom = 0;
+ UINT Middle = NumberOfAddresses / 2;
+ UINT Top;
+
+ if (NumberOfAddresses)
+ {
+ Top = NumberOfAddresses - 1;
+
+ while ((Middle <= Top) && (Middle >= Bottom))
+ {
+ //
+ // The result of comparing an element of the address
+ // array and the multicast address.
+ //
+ // Result < 0 Implies the multicast address is greater.
+ // Result > 0 Implies the address array element is greater.
+ // Result = 0 Implies that the array element and the address
+ // are equal.
+ //
+ INT Result;
+
+ FDDI_COMPARE_NETWORK_ADDRESSES(
+ AddressArray[Middle],
+ MulticastAddress,
+ FDDI_LENGTH_OF_LONG_ADDRESS,
+ &Result);
+
+ if (Result == 0)
+ {
+ *ArrayIndex = Middle;
+ return(TRUE);
+ }
+ else if (Result > 0)
+ {
+ if (Middle == 0) break;
+ Top = Middle - 1;
+ }
+ else
+ {
+ Bottom = Middle+1;
+ }
+
+ Middle = Bottom + (((Top+1) - Bottom)/2);
+ }
+ }
+
+ *ArrayIndex = Middle;
+
+ return(FALSE);
+}
+
+
+BOOLEAN
+FddiFindMulticastShortAddress(
+ IN UINT NumberOfAddresses,
+ IN CHAR AddressArray[][FDDI_LENGTH_OF_SHORT_ADDRESS],
+ IN CHAR MulticastAddress[FDDI_LENGTH_OF_SHORT_ADDRESS],
+ OUT PUINT ArrayIndex
+ )
+
+/*++
+
+Routine Description:
+
+ Given an array of multicast addresses search the array for
+ a particular multicast address. It is assumed that the
+ address array is already sorted.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+ NOTE: This ordering is arbitrary but consistant.
+
+Arguments:
+
+ NumberOfAddresses - The number of addresses currently in the
+ address array.
+
+ AddressArray - An array of multicast addresses.
+
+ MulticastAddress - The address to search for in the address array.
+
+ ArrayIndex - Will point to where the MulticastAddress is in
+ the AddressArray, or if it isn't in the array, where it should
+ be in the array.
+
+Return Value:
+
+ If the address is in the sorted list this routine will return
+ TRUE, otherwise FALSE.
+
+--*/
+
+{
+
+ //
+ // Indices into the address array so that we may do a binary
+ // search.
+ //
+ UINT Bottom = 0;
+ UINT Middle = NumberOfAddresses / 2;
+ UINT Top;
+
+ if (NumberOfAddresses)
+ {
+ Top = NumberOfAddresses - 1;
+
+ while ((Middle <= Top) && (Middle >= Bottom))
+ {
+ //
+ // The result of comparing an element of the address
+ // array and the multicast address.
+ //
+ // Result < 0 Implies the multicast address is greater.
+ // Result > 0 Implies the address array element is greater.
+ // Result = 0 Implies that the array element and the address
+ // are equal.
+ //
+ INT Result;
+
+ FDDI_COMPARE_NETWORK_ADDRESSES(
+ AddressArray[Middle],
+ MulticastAddress,
+ FDDI_LENGTH_OF_SHORT_ADDRESS,
+ &Result);
+
+ if (Result == 0)
+ {
+ *ArrayIndex = Middle;
+ return(TRUE);
+ }
+ else if (Result > 0)
+ {
+ if (Middle == 0) break;
+ Top = Middle - 1;
+ }
+ else
+ {
+ Bottom = Middle+1;
+ }
+
+ Middle = Bottom + (((Top+1) - Bottom)/2);
+ }
+ }
+
+ *ArrayIndex = Middle;
+
+ return(FALSE);
+}
+
+
+BOOLEAN
+FddiShouldAddressLoopBack(
+ IN PFDDI_FILTER Filter,
+ IN CHAR Address[],
+ IN UINT AddressLength
+ )
+
+/*++
+
+Routine Description:
+
+ Do a quick check to see whether the input address should
+ loopback.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+ NOTE: THIS ROUTINE DOES NOT CHECK THE SPECIAL CASE OF SOURCE
+ EQUALS DESTINATION.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ Address - A network address to check for loopback.
+
+ AddressLength - Length of the above address in bytes.
+
+Return Value:
+
+ Returns TRUE if the address needs to be loopback. It
+ will return FALSE if there is *no* chance that the address would
+ require loopback.
+
+--*/
+{
+ BOOLEAN fLoopback, fSelfDirected;
+
+ FddiShouldAddressLoopBackMacro(Filter, Address, AddressLength, &fLoopback, &fSelfDirected);
+ return(fLoopback);
+}
+
diff --git a/private/ntos/ndis/ndis40/filter.h b/private/ntos/ndis/ndis40/filter.h
new file mode 100644
index 000000000..416f57d0c
--- /dev/null
+++ b/private/ntos/ndis/ndis40/filter.h
@@ -0,0 +1,181 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ filter.h
+
+Abstract:
+
+ MACRO for protocol filters.
+
+Author:
+
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ Jun-95 Jameel Hyder New functionality
+--*/
+
+#define IndicateToProtocol(_Miniport, \
+ _Filter, \
+ _pOpenBlock, \
+ _Packet, \
+ _Hdr, \
+ _PktSize, \
+ _HdrSize, \
+ _fFallBack, \
+ _Pmode, \
+ _Medium) \
+{ \
+ UINT NumRef; \
+ UINT LookaheadBufferSize; \
+ \
+ /* \
+ * We indicate this via the IndicatePacketHandler if all of the following \
+ * conditions are met: \
+ * - The binding is not p-mode or all-local \
+ * - The binding specifies a ReceivePacketHandler \
+ * - The miniport indicates that it is willing to let go of the packet \
+ * - No binding has already claimed the packet \
+ */ \
+ \
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC((_Miniport)); \
+ \
+ /* \
+ * Indicate the packet to the binding. \
+ */ \
+ if (*(_fFallBack) || (_Pmode) || \
+ ((_pOpenBlock)->ReceivePacketHandler == NULL)) \
+ { \
+ /* \
+ * Revert back to old-style indication in this case \
+ */ \
+ NumRef = 0; \
+ NdisQueryBuffer((_Packet)->Private.Head, NULL, &LookaheadBufferSize); \
+ ProtocolFilterIndicateReceive(&StatusOfReceive, \
+ (_pOpenBlock), \
+ (_Packet), \
+ (_Hdr), \
+ (_HdrSize), \
+ (_Hdr) + (_HdrSize), \
+ LookaheadBufferSize - (_HdrSize), \
+ (_PktSize) - (_HdrSize), \
+ Medium); \
+ } \
+ else \
+ { \
+ NumRef = (*(_pOpenBlock)->ReceivePacketHandler)( \
+ (_pOpenBlock)->ProtocolBindingContext, \
+ (_Packet)); \
+ ASSERT(NumRef >= 0); \
+ } \
+ \
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC((_Miniport)); \
+ \
+ /* \
+ * Manipulate refcount on the packet with miniport lock held \
+ * Set the reference count on the packet to what the protocol \
+ * asked for. See NdisReturnPackets for how this is handled \
+ * when the packets are retrned. \
+ */ \
+ if (NumRef > 0) \
+ { \
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET((_Packet))->RefCount += NumRef; \
+ \
+ /* \
+ * Now that a binding has claimed it, make sure others do not get a chance \
+ * except if this protocol promises to behave and not use the protocol rsvd \
+ */ \
+ if ((_pOpenBlock)->NoProtRsvdOnRcvPkt == FALSE) \
+ { \
+ *(_fFallBack) = TRUE; \
+ } \
+ } \
+}
+
+#ifdef _PROTOCOL_FILTERS
+
+#define ProtocolFilterIndicateReceive(_pStatus, \
+ _OpenB, \
+ _MacReceiveContext, \
+ _HeaderBuffer, \
+ _HeaderBufferSize, \
+ _LookaheadBuffer, \
+ _LookaheadBufferSize, \
+ _PacketSize, \
+ _Medium) \
+ { \
+ PNDIS_PROTOCOL_BLOCK Prot; \
+ \
+ Prot = ((PNDIS_OPEN_BLOCK)(_OpenB))->ProtocolHandle; \
+ \
+ if ((Prot->ProtocolFilter == NULL) || \
+ (Prot->MaxPatternSize > (_LookaheadBufferSize))) \
+ { \
+ /* For protocols that do not set filters */ \
+ /* Or if the patten size exceeds the lookahead size */ \
+ FilterIndicateReceive(_pStatus, \
+ (_OpenB), \
+ _MacReceiveContext, \
+ _HeaderBuffer, \
+ _HeaderBufferSize, \
+ _LookaheadBuffer, \
+ _LookaheadBufferSize, \
+ _PacketSize); \
+ } \
+ else \
+ { \
+ PNDIS_PROTOCOL_FILTER pF; \
+ \
+ for (pF = Prot->ProtocolFilter; \
+ pF != NULL; \
+ pF = pF->Next) \
+ { \
+ if (RtlEqualMemory((PUCHAR)pF + sizeof(NDIS_PROTOCOL_FILTER), \
+ (PUCHAR)(_LookaheadBuffer) + pF->Offset, \
+ pF->Size)) \
+ { \
+ *(_pStatus) = (pF->ReceiveHandler)(((PNDIS_OPEN_BLOCK)(_OpenB))->ProtocolBindingContext,\
+ (_MacReceiveContext), \
+ (_HeaderBuffer), \
+ (_HeaderBufferSize), \
+ (_LookaheadBuffer), \
+ (_LookaheadBufferSize), \
+ (_PacketSize)); \
+ \
+ break; \
+ } \
+ } \
+ } \
+ }
+
+#else
+
+#define ProtocolFilterIndicateReceive(_pStatus, \
+ _OpenB, \
+ _MacReceiveContext, \
+ _HeaderBuffer, \
+ _HeaderBufferSize, \
+ _LookaheadBuffer, \
+ _LookaheadBufferSize, \
+ _PacketSize, \
+ _Medium) \
+ { \
+ FilterIndicateReceive(_pStatus, \
+ (_OpenB), \
+ _MacReceiveContext, \
+ _HeaderBuffer, \
+ _HeaderBufferSize, \
+ _LookaheadBuffer, \
+ _LookaheadBufferSize, \
+ _PacketSize); \
+ }
+
+#endif
+
diff --git a/private/ntos/ndis/ndis40/init.c b/private/ntos/ndis/ndis40/init.c
new file mode 100644
index 000000000..32661748e
--- /dev/null
+++ b/private/ntos/ndis/ndis40/init.c
@@ -0,0 +1,1415 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ init.c
+
+Abstract:
+
+ NDIS wrapper functions initializing drivers.
+
+Author:
+
+ Adam Barr (adamba) 11-Jul-1990
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ 26-Feb-1991 JohnsonA Added Debugging Code
+ 10-Jul-1991 JohnsonA Implement revised Ndis Specs
+ 01-Jun-1995 JameelH Re-organized
+
+--*/
+
+#include <precomp.h>
+#include <atm.h>
+#pragma hdrstop
+
+#include <stdarg.h>
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_INIT
+
+//
+// Configuration Requests
+//
+
+VOID
+NdisOpenConfiguration(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE ConfigurationHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to open the parameter subkey of the
+ adapter registry tree.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ ConfigurationHandle - Returns a handle which is used in calls to
+ NdisReadConfiguration and NdisCloseConfiguration.
+
+ WrapperConfigurationContext - a handle pointing to an RTL_QUERY_REGISTRY_TABLE
+ that is set up for this driver's parameters.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Handle to be returned
+ //
+ PNDIS_CONFIGURATION_HANDLE HandleToReturn;
+
+ //
+ // Allocate the configuration handle
+ //
+ *Status = NdisAllocateMemory((PVOID*)&HandleToReturn,
+ sizeof(NDIS_CONFIGURATION_HANDLE),
+ 0,
+ HighestAcceptableMax);
+
+ if (*Status == NDIS_STATUS_SUCCESS)
+ {
+ HandleToReturn->KeyQueryTable = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->ParametersQueryTable;
+ HandleToReturn->ParameterList = NULL;
+ *ConfigurationHandle = (NDIS_HANDLE)HandleToReturn;
+ }
+}
+
+
+VOID
+NdisOpenConfigurationKeyByName(
+ OUT PNDIS_STATUS Status,
+ IN PNDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING KeyName,
+ OUT PNDIS_HANDLE KeyHandle
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to open a subkey relative to the configuration handle.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ ConfigurationHandle - Handle to an already open section of the registry
+
+ KeyName - Name of the subkey to open
+
+ KeyHandle - Placeholder for the handle to the sub-key.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Handle to be returned
+ //
+ PNDIS_CONFIGURATION_HANDLE SKHandle, ConfigHandle = (PNDIS_CONFIGURATION_HANDLE)ConfigurationHandle;
+ PNDIS_WRAPPER_CONFIGURATION_HANDLE WConfigHandle;
+ UNICODE_STRING Parent, Child, Sep;
+#define PQueryTable WConfigHandle->ParametersQueryTable
+
+ ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+ //
+ // Allocate the configuration handle
+ //
+ RtlInitUnicodeString(&Parent, ConfigHandle->KeyQueryTable[3].Name);
+ RtlInitUnicodeString(&Sep, L"\\");
+ Child.Length = 0;
+ Child.MaximumLength = KeyName->Length + Parent.Length + Sep.Length + sizeof(WCHAR);
+ *Status = NdisAllocateMemory((PVOID*)&SKHandle,
+ sizeof(NDIS_CONFIGURATION_HANDLE) +
+ sizeof(NDIS_WRAPPER_CONFIGURATION_HANDLE) +
+ Child.MaximumLength,
+ 0,
+ HighestAcceptableMax);
+
+ if (*Status != NDIS_STATUS_SUCCESS)
+ {
+ *KeyHandle = (NDIS_HANDLE)NULL;
+ return;
+ }
+
+ WConfigHandle = (PNDIS_WRAPPER_CONFIGURATION_HANDLE)((PUCHAR)SKHandle + sizeof(NDIS_CONFIGURATION_HANDLE));
+ Child.Buffer = (PWSTR)((PUCHAR)WConfigHandle + sizeof(NDIS_WRAPPER_CONFIGURATION_HANDLE));
+
+ RtlCopyUnicodeString(&Child, &Parent);
+ RtlAppendUnicodeStringToString(&Child, &Sep);
+ RtlAppendUnicodeStringToString(&Child, KeyName);
+
+ SKHandle->KeyQueryTable = WConfigHandle->ParametersQueryTable;
+
+
+ //
+ // 1.
+ // Call ndisSaveParameter for a parameter, which will allocate storage for it.
+ //
+ PQueryTable[0].QueryRoutine = ndisSaveParameters;
+ PQueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ PQueryTable[0].DefaultType = REG_NONE;
+
+ //
+ // PQueryTable[0].Name and PQueryTable[0].EntryContext
+ // are filled in inside ReadConfiguration, in preparation
+ // for the callback.
+ //
+ // PQueryTable[0].Name = KeywordBuffer;
+ // PQueryTable[0].EntryContext = ParameterValue;
+
+ //
+ // 2.
+ // Stop
+ //
+ PQueryTable[1].QueryRoutine = NULL;
+ PQueryTable[1].Flags = 0;
+ PQueryTable[1].Name = NULL;
+
+ //
+ // NOTE: Some fields in ParametersQueryTable[3] are used to store information for later retrieval.
+ //
+ PQueryTable[3].QueryRoutine = NULL;
+ PQueryTable[3].Name = Child.Buffer;
+ PQueryTable[3].EntryContext = NULL;
+ PQueryTable[3].DefaultData = NULL;
+
+ SKHandle->ParameterList = NULL;
+ *KeyHandle = (NDIS_HANDLE)SKHandle;
+#undef PQueryTable
+}
+
+
+VOID
+NdisOpenConfigurationKeyByIndex(
+ OUT PNDIS_STATUS Status,
+ IN PNDIS_HANDLE ConfigurationHandle,
+ IN ULONG Index,
+ OUT PNDIS_STRING KeyName,
+ OUT PNDIS_HANDLE KeyHandle
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to open a subkey relative to the configuration handle.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ ConfigurationHandle - Handle to an already open section of the registry
+
+ Index - Index of the sub-key to open
+
+ KeyName - Placeholder for the name of subkey being opened
+
+ KeyHandle - Placeholder for the handle to the sub-key.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_CONFIGURATION_HANDLE ConfigHandle = (PNDIS_CONFIGURATION_HANDLE)ConfigurationHandle;
+ HANDLE Handle;
+ OBJECT_ATTRIBUTES ObjAttr;
+ UNICODE_STRING KeyPath, Services, AbsolutePath;
+ PKEY_BASIC_INFORMATION InfoBuf = NULL;
+ ULONG Len;
+
+ ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+ *KeyHandle = NULL;
+
+ do
+ {
+ //
+ // Open the current key and lookup the Nth subkey. But first conver the service relative
+ // path to absolute since this is what ZwOpenKey expects.
+ //
+ RtlInitUnicodeString(&KeyPath, ConfigHandle->KeyQueryTable[3].Name);
+ RtlInitUnicodeString(&Services, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
+ AbsolutePath.MaximumLength = KeyPath.Length + Services.Length + sizeof(WCHAR);
+ AbsolutePath.Buffer = (PWSTR)ALLOC_FROM_POOL(AbsolutePath.MaximumLength, NDIS_TAG_DEFAULT);
+ if (AbsolutePath.Buffer == NULL)
+ {
+ break;
+ }
+ NdisMoveMemory(AbsolutePath.Buffer, Services.Buffer, Services.Length);
+ AbsolutePath.Length = Services.Length;
+ RtlAppendUnicodeStringToString(&AbsolutePath, &KeyPath);
+
+ InitializeObjectAttributes(&ObjAttr,
+ &AbsolutePath,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ *Status = ZwOpenKey(&Handle,
+ GENERIC_READ | MAXIMUM_ALLOWED,
+ &ObjAttr);
+ if (*Status != STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ //
+ // Allocate memory for the call to ZwEnumerateKey
+ //
+ Len = sizeof(KEY_BASIC_INFORMATION) + 256;
+ InfoBuf = (PKEY_BASIC_INFORMATION)ALLOC_FROM_POOL(Len, NDIS_TAG_DEFAULT);
+ if (InfoBuf == NULL)
+ {
+ ZwClose(Handle);
+ *Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ //
+ // Get the Index(th) key, if it exists
+ //
+ *Status = ZwEnumerateKey(Handle,
+ Index,
+ KeyValueBasicInformation,
+ InfoBuf,
+ Len,
+ &Len);
+ ZwClose(Handle);
+ if (*Status == STATUS_SUCCESS)
+ {
+ //
+ // This worked. Now simply pick up the name and do a NdisOpenConfigurationKeyByName on it.
+ //
+ KeyPath.Length = KeyPath.MaximumLength = (USHORT)InfoBuf->NameLength;
+ KeyPath.Buffer = InfoBuf->Name;
+ NdisOpenConfigurationKeyByName(Status,
+ ConfigurationHandle,
+ &KeyPath,
+ KeyHandle);
+ if (*Status == NDIS_STATUS_SUCCESS)
+ {
+ PNDIS_CONFIGURATION_HANDLE NewHandle = *(PNDIS_CONFIGURATION_HANDLE *)KeyHandle;
+
+ //
+ // The path in the new handle has the name of the key. Extract it and return to caller
+ //
+ RtlInitUnicodeString(KeyName, NewHandle->KeyQueryTable[3].Name);
+ KeyName->Buffer = (PWSTR)((PUCHAR)KeyName->Buffer + KeyName->Length - KeyPath.Length);
+ KeyName->Length = KeyPath.Length;
+ KeyName->MaximumLength = KeyPath.MaximumLength;
+ }
+ }
+
+ } while (FALSE);
+
+ if (AbsolutePath.Buffer != NULL)
+ {
+ FREE_POOL(AbsolutePath.Buffer);
+ }
+
+ if (InfoBuf != NULL)
+ {
+ FREE_POOL(InfoBuf);
+ }
+}
+
+
+VOID
+NdisOpenGlobalConfiguration(
+ OUT PNDIS_STATUS Status,
+ IN PNDIS_HANDLE NdisWrapperHandle,
+ OUT PNDIS_HANDLE ConfigurationHandle
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to open global (as opposed to per-adapter) configuration key for an adapter.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ WrapperHandle - Handle returned by NdisInitializeWrapper.
+
+ ConfigurationHandle - Handle returned. Points to the global parameter subkey.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_WRAPPER_HANDLE WrapperHandle = (PNDIS_WRAPPER_HANDLE)NdisWrapperHandle;
+ PNDIS_CONFIGURATION_HANDLE HandleToReturn;
+ PNDIS_WRAPPER_CONFIGURATION_HANDLE ConfigHandle;
+ UNICODE_STRING Us, Params;
+ PWSTR pWch;
+ USHORT i;
+
+ //
+ // Extract the base name from the reg path and setup for open config handle
+ //
+ Us = *(PUNICODE_STRING)(WrapperHandle->NdisWrapperConfigurationHandle);
+ RtlInitUnicodeString(&Params, L"\\Parameters");
+ for (i = Us.Length/sizeof(WCHAR), pWch = Us.Buffer + i - 1;
+ i > 0;
+ pWch --, i--)
+ {
+ if (*pWch == L'\\')
+ {
+ Us.Buffer = pWch + 1;
+ Us.Length -= i*sizeof(WCHAR);
+ Us.MaximumLength = Us.Length + Params.Length + sizeof(WCHAR);
+ break;
+ }
+ }
+
+ //
+ // Allocate the configuration handle
+ //
+ *Status = NdisAllocateMemory((PVOID *)&HandleToReturn,
+ sizeof(NDIS_CONFIGURATION_HANDLE) +
+ sizeof(NDIS_WRAPPER_CONFIGURATION_HANDLE) +
+ Us.MaximumLength,
+ 0,
+ HighestAcceptableMax);
+
+ if (*Status == NDIS_STATUS_SUCCESS)
+ {
+#define PQueryTable ConfigHandle->ParametersQueryTable
+ NdisZeroMemory(HandleToReturn,
+ sizeof(NDIS_CONFIGURATION_HANDLE) + sizeof(NDIS_WRAPPER_CONFIGURATION_HANDLE) + Us.MaximumLength);
+ ConfigHandle = (PNDIS_WRAPPER_CONFIGURATION_HANDLE)((PUCHAR)HandleToReturn + sizeof(NDIS_CONFIGURATION_HANDLE));
+ pWch = (PWSTR)((PUCHAR)ConfigHandle + sizeof(NDIS_WRAPPER_CONFIGURATION_HANDLE));
+ NdisMoveMemory(pWch, Us.Buffer, Us.Length);
+ Us.Buffer = pWch;
+ RtlAppendUnicodeStringToString(&Us, &Params);
+ HandleToReturn->KeyQueryTable = ConfigHandle->ParametersQueryTable;
+ HandleToReturn->ParameterList = NULL;
+
+ //
+ // Setup the query-table appropriately
+ //
+ PQueryTable[0].QueryRoutine = ndisSaveParameters;
+ PQueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ PQueryTable[0].DefaultType = REG_NONE;
+
+ //
+ // The following fields are filled in during NdisReadConfiguration
+ //
+ // PQueryTable[0].Name = KeywordBuffer;
+ // PQueryTable[0].EntryContext = ParameterValue;
+
+ //
+ // NOTE: Some fields in ParametersQueryTable[3 & 4] are used to
+ // store information for later retrieval.
+ //
+ PQueryTable[3].Name = pWch;
+
+ *ConfigurationHandle = (NDIS_HANDLE)HandleToReturn;
+#undef PQueryTable
+ }
+}
+
+
+VOID
+NdisReadConfiguration(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_CONFIGURATION_PARAMETER * ParameterValue,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING Keyword,
+ IN NDIS_PARAMETER_TYPE ParameterType
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to read the parameter for a configuration
+ keyword from the configuration database.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ ParameterValue - Returns the value for this keyword.
+
+ ConfigurationHandle - Handle returned by NdisOpenConfiguration. Points
+ to the parameter subkey.
+
+ Keyword - The keyword to search for.
+
+ ParameterType - Ignored on NT, specifies the type of the value.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Status of our requests
+ //
+ NTSTATUS RegistryStatus;
+
+ //
+ // Holds a null-terminated version of the keyword.
+ //
+ PWSTR KeywordBuffer;
+
+ //
+ // index variable
+ //
+ UINT i;
+
+ //
+ // Obtain the actual configuration handle structure
+ //
+ PNDIS_CONFIGURATION_HANDLE ConfigHandle = (PNDIS_CONFIGURATION_HANDLE)ConfigurationHandle;
+#define PQueryTable ConfigHandle->KeyQueryTable
+
+ //
+ // There are some built-in parameters which can always be
+ // read, even if not present in the registry. This is the
+ // number of them.
+ //
+#define BUILT_IN_COUNT 3
+
+ //
+ // The names of the built-in parameters.
+ //
+ static NDIS_STRING BuiltInStrings[BUILT_IN_COUNT] =
+ {
+ NDIS_STRING_CONST ("Environment"),
+ NDIS_STRING_CONST ("ProcessorType"),
+ NDIS_STRING_CONST ("NdisVersion")
+ };
+
+ //
+ // The values to return for the built-in parameters.
+ //
+ static NDIS_CONFIGURATION_PARAMETER BuiltInParameters[BUILT_IN_COUNT] =
+ { { NdisParameterInteger, NdisEnvironmentWindowsNt },
+ { NdisParameterInteger,
+#if defined(_M_IX86)
+ NdisProcessorX86
+#elif defined(_M_MRX000)
+ NdisProcessorMips
+#elif defined(_ALPHA_)
+ NdisProcessorAlpha
+#else
+ NdisProcessorPpc
+#endif
+ },
+ { NdisParameterInteger, 0x00040001 }
+ };
+
+ ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+ do
+ {
+ //
+ // First check if this is one of the built-in parameters.
+ //
+ for (i = 0; i < BUILT_IN_COUNT; i++)
+ {
+ if (RtlEqualUnicodeString(Keyword, &BuiltInStrings[i], TRUE))
+ {
+ *Status = NDIS_STATUS_SUCCESS;
+ *ParameterValue = &BuiltInParameters[i];
+ break;
+ }
+ }
+ if (i < BUILT_IN_COUNT)
+ break;
+
+ //
+ // Allocate room for a null-terminated version of the keyword
+ //
+ KeywordBuffer = Keyword->Buffer;
+ if (Keyword->MaximumLength < (Keyword->Length + sizeof(WCHAR)))
+ {
+ KeywordBuffer = (PWSTR)ALLOC_FROM_POOL(Keyword->Length + sizeof(WCHAR), NDIS_TAG_DEFAULT);
+ if (KeywordBuffer == NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+ CopyMemory(KeywordBuffer, Keyword->Buffer, Keyword->Length);
+ }
+ *(PWCHAR)(((PUCHAR)KeywordBuffer)+Keyword->Length) = (WCHAR)L'\0';
+
+ //
+ // Finish initializing the table for this query.
+ //
+ PQueryTable[0].Name = KeywordBuffer;
+ PQueryTable[0].EntryContext = ParameterValue;
+
+ //
+ // Get the value from the registry; this chains it on to the
+ // parameter list at NdisConfigHandle.
+ //
+
+ RegistryStatus = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
+ PQueryTable[3].Name,
+ PQueryTable,
+ ConfigHandle, // context
+ NULL);
+
+ if (KeywordBuffer != Keyword->Buffer)
+ {
+ FREE_POOL(KeywordBuffer); // no longer needed
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+ if (!NT_SUCCESS(RegistryStatus))
+ {
+ *Status = NDIS_STATUS_FAILURE;
+ }
+ } while (FALSE);
+#undef PQueryTable
+}
+
+
+VOID
+NdisWriteConfiguration(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING Keyword,
+ PNDIS_CONFIGURATION_PARAMETER ParameterValue
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to write a parameter to the configuration database.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ ConfigurationHandle - Handle passed to the driver's AddAdapter routine.
+
+ Keyword - The keyword to set.
+
+ ParameterValue - Specifies the new value for this keyword.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Status of our requests
+ //
+ NTSTATUS RegistryStatus;
+
+ //
+ // The ConfigurationHandle is really a pointer to a registry query table.
+ //
+ PNDIS_CONFIGURATION_HANDLE NdisConfigHandle = (PNDIS_CONFIGURATION_HANDLE)ConfigurationHandle;
+
+ //
+ // Holds a null-terminated version of the keyword.
+ //
+ PWSTR KeywordBuffer;
+
+ //
+ // Variables describing the parameter value.
+ //
+ PVOID ValueData;
+ ULONG ValueLength;
+ ULONG ValueType;
+
+ ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+ *Status == NDIS_STATUS_SUCCESS;
+ do
+ {
+ //
+ // Get the value data.
+ //
+ switch (ParameterValue->ParameterType)
+ {
+ case NdisParameterInteger:
+ ValueData = &ParameterValue->ParameterData.IntegerData;
+ ValueLength = sizeof(ParameterValue->ParameterData.IntegerData);
+ ValueType = REG_DWORD;
+ break;
+
+ case NdisParameterString:
+ ValueData = ParameterValue->ParameterData.StringData.Buffer;
+ ValueLength = ParameterValue->ParameterData.StringData.Length;
+ ValueType = REG_SZ;
+ break;
+
+ case NdisParameterMultiString:
+ ValueData = ParameterValue->ParameterData.StringData.Buffer;
+ ValueLength = ParameterValue->ParameterData.StringData.Length;
+ ValueType = REG_MULTI_SZ;
+ break;
+
+ case NdisParameterBinary:
+ ValueData = ParameterValue->ParameterData.BinaryData.Buffer;
+ ValueLength = ParameterValue->ParameterData.BinaryData.Length;
+ ValueType = REG_BINARY;
+ break;
+
+ default:
+ *Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if (*Status != NDIS_STATUS_SUCCESS)
+ break;
+
+ KeywordBuffer = Keyword->Buffer;
+ if (Keyword->MaximumLength <= (Keyword->MaximumLength + sizeof(WCHAR)))
+ {
+ KeywordBuffer = (PWSTR)ALLOC_FROM_POOL(Keyword->Length + sizeof(WCHAR), NDIS_TAG_DEFAULT);
+ if (KeywordBuffer == NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+ CopyMemory(KeywordBuffer, Keyword->Buffer, Keyword->Length);
+ }
+ *(PWCHAR)(((PUCHAR)KeywordBuffer)+Keyword->Length) = (WCHAR)L'\0';
+
+ //
+ // Write the value to the registry.
+ //
+ RegistryStatus = RtlWriteRegistryValue(RTL_REGISTRY_SERVICES,
+ NdisConfigHandle->KeyQueryTable[3].Name,
+ KeywordBuffer,
+ ValueType,
+ ValueData,
+ ValueLength);
+
+ if (KeywordBuffer != Keyword->Buffer)
+ {
+ FREE_POOL(KeywordBuffer); // no longer needed
+ }
+
+ if (!NT_SUCCESS(RegistryStatus))
+ {
+ *Status = NDIS_STATUS_FAILURE;
+ }
+ } while (FALSE);
+}
+
+
+VOID
+NdisCloseConfiguration(
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to close a configuration database opened by
+ NdisOpenConfiguration.
+
+Arguments:
+
+ ConfigurationHandle - Handle returned by NdisOpenConfiguration.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Obtain the actual configuration handle structure
+ //
+ PNDIS_CONFIGURATION_HANDLE NdisConfigHandle = (PNDIS_CONFIGURATION_HANDLE)ConfigurationHandle;
+
+ //
+ // Pointer to a parameter node
+ //
+ PNDIS_CONFIGURATION_PARAMETER_QUEUE ParameterNode;
+
+ ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+ //
+ // deallocate the parameter nodes
+ //
+ ParameterNode = NdisConfigHandle->ParameterList;
+
+ while (ParameterNode != NULL)
+ {
+ NdisConfigHandle->ParameterList = ParameterNode->Next;
+
+ NdisFreeMemory(ParameterNode,
+ sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE),
+ 0);
+
+ ParameterNode = NdisConfigHandle->ParameterList;
+ }
+
+ NdisFreeMemory(ConfigurationHandle,
+ sizeof(NDIS_CONFIGURATION_HANDLE),
+ 0);
+}
+
+
+VOID
+NdisReadNetworkAddress(
+ OUT PNDIS_STATUS Status,
+ OUT PVOID * NetworkAddress,
+ OUT PUINT NetworkAddressLength,
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to read the "NetworkAddress" parameter
+ from the configuration database. It reads the value as a
+ string separated by hyphens, then converts it to a binary
+ array and stores the result.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ NetworkAddress - Returns a pointer to the address.
+
+ NetworkAddressLength - Returns the length of the address.
+
+ ConfigurationHandle - Handle returned by NdisOpenConfiguration. Points
+ to the parameter subkey.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ NDIS_STRING NetAddrStr = NDIS_STRING_CONST("NetworkAddress");
+ PNDIS_CONFIGURATION_PARAMETER ParameterValue;
+ NTSTATUS NtStatus;
+ UCHAR ConvertArray[3];
+ PWSTR CurrentReadLoc;
+ PWSTR AddressEnd;
+ PUCHAR CurrentWriteLoc;
+ UINT TotalBytesRead;
+ ULONG TempUlong;
+ ULONG AddressLength;
+
+ ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+ do
+ {
+ //
+ // First read the "NetworkAddress" from the registry
+ //
+ NdisReadConfiguration(Status, &ParameterValue, ConfigurationHandle, &NetAddrStr, NdisParameterString);
+
+ if ((*Status != NDIS_STATUS_SUCCESS) ||
+ (ParameterValue->ParameterType != NdisParameterString))
+ {
+ *Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // If there is not an address specified then exit now.
+ //
+ if (0 == ParameterValue->ParameterData.StringData.Length)
+ {
+ *Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // Now convert the address to binary (we do this
+ // in-place, since this allows us to use the memory
+ // already allocated which is automatically freed
+ // by NdisCloseConfiguration).
+ //
+
+ ConvertArray[2] = '\0';
+ CurrentReadLoc = (PWSTR)ParameterValue->ParameterData.StringData.Buffer;
+ CurrentWriteLoc = (PUCHAR)CurrentReadLoc;
+ TotalBytesRead = ParameterValue->ParameterData.StringData.Length;
+ AddressEnd = CurrentReadLoc + (TotalBytesRead / sizeof(WCHAR));
+ AddressLength = 0;
+
+ while ((CurrentReadLoc+2) <= AddressEnd)
+ {
+ //
+ // Copy the current two-character value into ConvertArray
+ //
+ ConvertArray[0] = (UCHAR)(*(CurrentReadLoc++));
+ ConvertArray[1] = (UCHAR)(*(CurrentReadLoc++));
+
+ //
+ // Convert it to a Ulong and update
+ //
+ NtStatus = RtlCharToInteger(ConvertArray, 16, &TempUlong);
+
+ if (!NT_SUCCESS(NtStatus))
+ {
+ *Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ *(CurrentWriteLoc++) = (UCHAR)TempUlong;
+ ++AddressLength;
+
+ //
+ // If the next character is a hyphen, skip it.
+ //
+ if (CurrentReadLoc < AddressEnd)
+ {
+ if (*CurrentReadLoc == (WCHAR)L'-')
+ {
+ ++CurrentReadLoc;
+ }
+ }
+ }
+
+ if (NtStatus != NDIS_STATUS_SUCCESS)
+ break;
+
+ *Status = STATUS_SUCCESS;
+ *NetworkAddress = ParameterValue->ParameterData.StringData.Buffer;
+ *NetworkAddressLength = AddressLength;
+ if (AddressLength == 0)
+ {
+ *Status = NDIS_STATUS_FAILURE;
+ }
+ } while (FALSE);
+}
+
+
+VOID
+NdisConvertStringToAtmAddress(
+ OUT PNDIS_STATUS Status,
+ IN PNDIS_STRING String,
+ OUT PATM_ADDRESS AtmAddress
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ String - String representation of the atm address.
+
+ * Format defined in Section 5.4,
+ * "Example Master File Format" in ATM95-1532R4 ATM Name System:
+ *
+ * AESA format: a string of hexadecimal digits, with '.' characters for punctuation, e.g.
+ *
+ * 39.246f.00.0e7c9c.0312.0001.0001.000012345678.00
+ *
+ * E164 format: A '+' character followed by a string of
+ * decimal digits, with '.' chars for punctuation, e.g.:
+ *
+ * +358.400.1234567
+
+ AtmAddress - The converted Atm address is returned here.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ USHORT i, j, NumDigits;
+ PWSTR p, q;
+ UNICODE_STRING Us;
+ ANSI_STRING As;
+
+ //
+ // Start off by stripping the punctuation characters from the string. We do this in place.
+ //
+ for (i = NumDigits = 0, j = String->Length/sizeof(WCHAR), p = q = String->Buffer;
+ (i < j) && (*p != 0);
+ i++, p++)
+ {
+ if ((*p == ATM_ADDR_BLANK_CHAR) ||
+ (*p == ATM_ADDR_PUNCTUATION_CHAR))
+ {
+ continue;
+ }
+ *q++ = *p;
+ NumDigits ++;
+ }
+
+ //
+ // Look at the first character to determine if the address is E.164 or NSAP
+ //
+ p = String->Buffer;
+ if (*p == ATM_ADDR_E164_START_CHAR)
+ {
+ p ++;
+ NumDigits --;
+ if ((NumDigits == 0) || (NumDigits > ATM_ADDRESS_LENGTH))
+ {
+ *Status = NDIS_STATUS_INVALID_LENGTH;
+ return;
+ }
+ AtmAddress->AddressType = ATM_E164;
+ AtmAddress->NumberOfDigits = NumDigits;
+ }
+ else
+ {
+ if (NumDigits != 2*ATM_ADDRESS_LENGTH)
+ {
+ *Status = NDIS_STATUS_INVALID_LENGTH;
+ return;
+ }
+ AtmAddress->AddressType = ATM_NSAP;
+ AtmAddress->NumberOfDigits = NumDigits/sizeof(WCHAR);
+ }
+
+ //
+ // Convert the address to Ansi now
+ //
+ Us.Buffer = p;
+ Us.Length = Us.MaximumLength = NumDigits*sizeof(WCHAR);
+ As.Buffer = ALLOC_FROM_POOL(NumDigits + 1, NDIS_TAG_CO);
+ As.Length = 0;
+ As.MaximumLength = NumDigits + 1;
+ if (As.Buffer == NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ *Status = NdisUnicodeStringToAnsiString(&As, &Us);
+ if (*Status != STATUS_SUCCESS)
+ {
+ FREE_POOL(As.Buffer);
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+ //
+ // Now get the bytes into the destination ATM Address structure.
+ //
+ if (AtmAddress->AddressType == ATM_E164)
+ {
+ //
+ // We just need to copy in the digits in ANSI form.
+ //
+ NdisMoveMemory(AtmAddress->Address, As.Buffer, NumDigits);
+ }
+ else
+ {
+ //
+ // This is in NSAP form. We need to pack the hex digits.
+ //
+ UCHAR xxString[3];
+ ULONG val;
+
+ xxString[2] = 0;
+ for (i = 0; i < ATM_ADDRESS_LENGTH; i++)
+ {
+ xxString[0] = As.Buffer[i*2];
+ xxString[1] = As.Buffer[i*2+1];
+ *Status = CHAR_TO_INT(xxString, 16, &val);
+ if (*Status != STATUS_SUCCESS)
+ {
+ FREE_POOL(As.Buffer);
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+ AtmAddress->Address[i] = (UCHAR)val;
+ }
+ }
+
+ FREE_POOL(As.Buffer);
+ *Status = NDIS_STATUS_SUCCESS;
+}
+
+
+VOID
+NdisReadBindingInformation(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_STRING * Binding,
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to read the binding information for
+ this adapter from the configuration database. The value
+ returned is a pointer to a string containing the bind
+ that matches the export for the current AddAdapter call.
+
+ This function is meant for NDIS drivers that are layered
+ on top of other NDIS drivers. Binding would be passed to
+ NdisOpenAdapter as the AdapterName.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ Binding - Returns the binding data.
+
+ ConfigurationHandle - Handle returned by NdisOpenConfiguration. Points
+ to the parameter subkey.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Convert the handle to its real value
+ //
+ PNDIS_CONFIGURATION_HANDLE NdisConfigHandle = (PNDIS_CONFIGURATION_HANDLE)ConfigurationHandle;
+
+ //
+ // Use this to link parameters allocated to this open
+ //
+ PNDIS_CONFIGURATION_PARAMETER_QUEUE ParameterNode;
+
+ //
+ // For layered drivers, this points to the binding. For
+ // non-layered drivers, it is NULL. This is set up before
+ // the call to AddAdapter.
+ //
+
+ do
+ {
+ if (NdisConfigHandle->KeyQueryTable[3].EntryContext == NULL)
+ {
+ *Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // Allocate our parameter node
+ //
+ *Status = NdisAllocateMemory((PVOID*)&ParameterNode,
+ sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE),
+ 0,
+ HighestAcceptableMax);
+
+ if (*Status != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ //
+ // We set this to Integer because if we set it to String
+ // then CloseConfiguration would try to free the string,
+ // which we don't want.
+ //
+
+ ParameterNode->Parameter.ParameterType = NdisParameterInteger;
+
+ RtlInitUnicodeString(&ParameterNode->Parameter.ParameterData.StringData,
+ NdisConfigHandle->KeyQueryTable[3].EntryContext);
+
+ //
+ // Queue this parameter node
+ //
+
+ ParameterNode->Next = NdisConfigHandle->ParameterList;
+ NdisConfigHandle->ParameterList = ParameterNode;
+
+ *Binding = &ParameterNode->Parameter.ParameterData.StringData;
+ *Status = NDIS_STATUS_SUCCESS;
+ } while (FALSE);
+}
+
+
+NTSTATUS
+ndisSaveParameters(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called with the value for a specified parameter. It allocates
+ memory to hold the data and copies it over.
+
+Arguments:
+
+ ValueName - The name of the value (ignored).
+
+ ValueType - The type of the value.
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - Points to the head of the parameter chain.
+
+ EntryContext - A pointer to
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+{
+ NDIS_STATUS Status;
+
+ //
+ // Obtain the actual configuration handle structure
+ //
+ PNDIS_CONFIGURATION_HANDLE NdisConfigHandle = (PNDIS_CONFIGURATION_HANDLE)Context;
+
+ //
+ // Where the user wants a pointer returned to the data.
+ //
+ PNDIS_CONFIGURATION_PARAMETER *ParameterValue = (PNDIS_CONFIGURATION_PARAMETER *)EntryContext;
+
+ //
+ // Use this to link parameters allocated to this open
+ //
+ PNDIS_CONFIGURATION_PARAMETER_QUEUE ParameterNode;
+
+ //
+ // Size of memory to allocate for parameter node
+ //
+ UINT Size;
+
+ //
+ // Allocate our parameter node
+ //
+ Size = sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE);
+ if ((ValueType == REG_SZ) || (ValueType == REG_MULTI_SZ) || (ValueType == REG_BINARY))
+ {
+ Size += ValueLength;
+ }
+ Status = NdisAllocateMemory((PVOID*)&ParameterNode,
+ Size,
+ 0,
+ HighestAcceptableMax);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ return (NTSTATUS)Status;
+ }
+
+
+ *ParameterValue = &ParameterNode->Parameter;
+
+ //
+ // Map registry datatypes to ndis data types
+ //
+ if (ValueType == REG_DWORD)
+ {
+ //
+ // The registry says that the data is in a dword boundary.
+ //
+ (*ParameterValue)->ParameterType = NdisParameterInteger;
+ (*ParameterValue)->ParameterData.IntegerData = *((PULONG) ValueData);
+ }
+ else if ((ValueType == REG_SZ) || (ValueType == REG_MULTI_SZ))
+ {
+ (*ParameterValue)->ParameterType =
+ (ValueType == REG_SZ) ? NdisParameterString : NdisParameterMultiString;
+
+ (*ParameterValue)->ParameterData.StringData.Buffer = (PWSTR)((PUCHAR)ParameterNode + sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE));
+
+ CopyMemory((*ParameterValue)->ParameterData.StringData.Buffer,
+ ValueData,
+ ValueLength);
+ (*ParameterValue)->ParameterData.StringData.Length = (USHORT)ValueLength;
+ (*ParameterValue)->ParameterData.StringData.MaximumLength = (USHORT)ValueLength;
+
+ //
+ // Special fix; if a string ends in a NULL and that is included
+ // in the length, remove it.
+ //
+ if (ValueType == REG_SZ)
+ {
+ if ((((PUCHAR)ValueData)[ValueLength-1] == 0) &&
+ (((PUCHAR)ValueData)[ValueLength-2] == 0))
+ {
+ (*ParameterValue)->ParameterData.StringData.Length -= 2;
+ }
+ }
+ }
+ else if (ValueType == REG_BINARY)
+ {
+ (*ParameterValue)->ParameterType = NdisParameterBinary;
+ (*ParameterValue)->ParameterData.BinaryData.Buffer = ValueData;
+ (*ParameterValue)->ParameterData.BinaryData.Length = (USHORT)ValueLength;
+ }
+ else
+ {
+ NdisFreeMemory(ParameterNode,
+ sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE),
+ 0);
+
+ return STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ //
+ // Queue this parameter node
+ //
+ ParameterNode->Next = NdisConfigHandle->ParameterList;
+ NdisConfigHandle->ParameterList = ParameterNode;
+
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+ndisCheckRoute(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called with the value for the "Route" multi-string. It
+ counts the number of "'s in the first string and if it is
+ more than two then it knows that this is a layered driver.
+
+Arguments:
+
+ ValueName - The name of the value ("Route" -- ignored).
+
+ ValueType - The type of the value (REG_MULTI_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - Unused.
+
+ EntryContext - A pointer to a BOOLEAN that is set to TRUE if the driver is layered.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+{
+ PWSTR CurRouteLoc = (PWSTR)ValueData;
+ UINT QuoteCount = 0;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+ UNREFERENCED_PARAMETER(ValueLength);
+ UNREFERENCED_PARAMETER(Context);
+
+ while (*CurRouteLoc != 0)
+ {
+ if (*CurRouteLoc == (WCHAR)L'"')
+ {
+ ++QuoteCount;
+ }
+ ++CurRouteLoc;
+ }
+
+ if (QuoteCount > 2)
+ {
+ *(PBOOLEAN)EntryContext = TRUE;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+ndisSaveLinkage(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called with the values for the "Bind" and "Export" multi-strings
+ for a given driver. It allocates memory to hold the data and copies
+ it over.
+
+Arguments:
+
+ ValueName - The name of the value ("Bind" or "Export" -- ignored).
+
+ ValueType - The type of the value (REG_MULTI_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - Unused.
+
+ EntryContext - A pointer to the pointer that holds the copied data.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+{
+ PWSTR * Data = ((PWSTR *)EntryContext);
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+ UNREFERENCED_PARAMETER(Context);
+
+
+ *Data = ALLOC_FROM_POOL(ValueLength, NDIS_TAG_DEFAULT);
+
+ if (*Data == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ CopyMemory(*Data, ValueData, ValueLength);
+
+ return STATUS_SUCCESS;
+
+}
+
+
+
diff --git a/private/ntos/ndis/ndis40/initpnp.c b/private/ntos/ndis/ndis40/initpnp.c
new file mode 100644
index 000000000..e604be48a
--- /dev/null
+++ b/private/ntos/ndis/ndis40/initpnp.c
@@ -0,0 +1,2463 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ initpnp.c
+
+Abstract:
+
+ NDIS wrapper functions initializing drivers.
+
+Author:
+
+ Jameel Hyder (jameelh) 11-Aug-1995
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+--*/
+
+
+#include <precomp.h>
+#pragma hdrstop
+
+#include <stdarg.h>
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_INITPNP
+
+NDIS_STATUS
+ndisInitializeAllAdapterInstances(
+ IN PNDIS_MAC_BLOCK MacBlock,
+ IN PNDIS_STRING DeviceInstance OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ Reads the driver registry bindings and calls add adapter for each one.
+
+Arguments:
+
+ MacBlock - Pointer to NDIS_MAC_BLOCK allocated for this Mac.
+ or NDIS_M_DRIVER_BLOCK for the miniport.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Number of adapters added successfully
+ //
+ UINT i, AdaptersAdded = 0;
+
+ //
+ // Status of registry requests.
+ //
+ NTSTATUS RegistryStatus;
+ NDIS_STATUS Status;
+
+ //
+ // These hold the REG_MULTI_SZ read from "Bind"
+ //
+ PWSTR BindData, ExportData, RouteData;
+
+ //
+ // These hold our place in the REG_MULTI_SZ read for "Bind".
+ //
+ PWSTR CurBind, CurExport, CurRoute;
+
+ //
+ // The path to our configuration data.
+ //
+ PUNICODE_STRING BaseNameString;
+
+ //
+ // Used to instruct RtlQueryRegistryValues to read the
+ // Linkage\Bind and Linkage\Export keys
+ //
+ RTL_QUERY_REGISTRY_TABLE LQueryTable[5];
+
+ PNDIS_M_DRIVER_BLOCK MiniBlock;
+
+ UNICODE_STRING BindString, ExportString, RouteString;
+ UNICODE_STRING InstanceString;
+ PWCHAR pPath, BaseFileName;
+ USHORT Len;
+ UINT Instances = 0;
+
+ MiniBlock = (PNDIS_M_DRIVER_BLOCK)MacBlock;
+
+ //
+ // Set up LQueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Linkage key below this driver's key
+ //
+ LQueryTable[0].QueryRoutine = NULL;
+ LQueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ LQueryTable[0].Name = L"Linkage";
+
+ //
+ // 2) Call ndisSaveLinkage for "Bind" (as a single multi-string),
+ // which will allocate storage and save the data in BindData.
+ //
+ LQueryTable[1].QueryRoutine = ndisSaveLinkage;
+ LQueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ LQueryTable[1].Name = L"Bind";
+ LQueryTable[1].EntryContext = (PVOID)&BindData;
+ LQueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 3) Call ndisSaveLinkage for "Export" (as a single multi-string),
+ // which will allocate storage and save the data in BindData.
+ //
+ LQueryTable[2].QueryRoutine = ndisSaveLinkage;
+ LQueryTable[2].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ LQueryTable[2].Name = L"Export";
+ LQueryTable[2].EntryContext = (PVOID)&ExportData;
+ LQueryTable[2].DefaultType = REG_NONE;
+
+ //
+ // 4) Call ndisSaveLinkage for "Route" (as a single multi-string),
+ // which will allocate storage and save the data in BindData.
+ //
+ LQueryTable[3].QueryRoutine = ndisSaveLinkage;
+ LQueryTable[3].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ LQueryTable[3].Name = L"Route";
+ LQueryTable[3].EntryContext = (PVOID)&RouteData;
+ LQueryTable[3].DefaultType = REG_NONE;
+
+ //
+ // 5) Stop
+ //
+ LQueryTable[4].QueryRoutine = NULL;
+ LQueryTable[4].Flags = 0;
+ LQueryTable[4].Name = NULL;
+
+
+ //
+ // Allocate room for a null-terminated version of the config path
+ //
+ if ((MiniBlock->MiniportIdField == (NDIS_HANDLE)0x01))
+ {
+ BaseNameString = &MiniBlock->BaseName;
+ }
+ else
+ {
+ BaseNameString = &MacBlock->BaseName;
+ }
+
+ BindData = NULL;
+ RouteData = NULL;
+ ExportData = NULL;
+
+ RegistryStatus = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
+ BaseNameString->Buffer,
+ LQueryTable,
+ (PVOID)NULL, // no context needed
+ NULL);
+
+ do
+ {
+ if (!NT_SUCCESS(RegistryStatus))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("Could not read Bind for %Z: %lx\n",
+ BaseNameString, RegistryStatus));
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // For each binding, initiate loading the driver
+ //
+
+ for (CurBind = BindData, CurExport = ExportData, CurRoute = RouteData;
+ *CurBind != 0;
+ CurBind = (PWCHAR)((PUCHAR)CurBind + BindString.MaximumLength),
+ CurExport = (PWCHAR)((PUCHAR)CurExport + ExportString.MaximumLength),
+ CurRoute = (PWCHAR)((PUCHAR)CurRoute + RouteString.MaximumLength))
+ {
+ RtlInitUnicodeString (&BindString, CurBind);
+ RtlInitUnicodeString (&ExportString, CurExport);
+ RtlInitUnicodeString (&RouteString, CurRoute);
+
+ Len = BindString.Length / sizeof(WCHAR);
+ pPath = BindString.Buffer + Len - 1;
+
+ //
+ // CurBindString is of the form '\Device\<DriverName><DriverInstance>
+ // e.g. \Device\Lance1.
+ // Get basename ("Lance1" in this example) from this and call
+ // ndisInitializeAdapter() to do the rest
+ //
+ BaseFileName = BindString.Buffer;
+
+ for (i = Len; i > 0; i--, pPath--)
+ {
+ //
+ // If pPath points to a directory separator, set fileBaseName to
+ // the character after the separator.
+ //
+
+ if (*pPath == OBJ_NAME_PATH_SEPARATOR)
+ {
+ BaseFileName = pPath + 1;
+ break;
+ }
+ }
+
+ RtlInitUnicodeString(&InstanceString, BaseFileName);
+ if ((DeviceInstance == NULL) ||
+ NDIS_EQUAL_UNICODE_STRING(DeviceInstance, &InstanceString))
+ {
+ Status = ndisUpdateDriverInstance(&InstanceString,
+ &BindString,
+ &ExportString,
+ &RouteString);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ Status = ndisInitializeAdapter(MiniBlock, &InstanceString);
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ ++Instances;
+
+ //
+ // Set the next available processor for the next
+ // NIC to use.
+ //
+ if (0 == ndisCurrentProcessor--)
+ {
+ ndisCurrentProcessor = ndisMaximumProcessor;
+ }
+ }
+ }
+ }
+ }
+ } while (FALSE);
+
+ if (BindData != NULL)
+ FREE_POOL(BindData);
+ if (ExportData != NULL)
+ FREE_POOL(ExportData);
+ if (RouteData != NULL)
+ FREE_POOL(RouteData);
+
+ return ((Instances > 0) ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE);
+}
+
+NDIS_STATUS
+ndisInitializeAdapter(
+ IN PNDIS_M_DRIVER_BLOCK pMiniBlock,
+ IN PUNICODE_STRING ServiceName // Relative to Services key
+ )
+{
+ PNDIS_MAC_BLOCK pMacBlock;
+ NDIS_WRAPPER_CONFIGURATION_HANDLE ConfigurationHandle;
+#define PQueryTable ConfigurationHandle.ParametersQueryTable
+#define Db ConfigurationHandle.Db
+ NDIS_CONFIGURATION_HANDLE TmpConfigHandle;
+ NDIS_STRING BusTypeStr = NDIS_STRING_CONST("BusType");
+ NDIS_STRING BusNumberStr = NDIS_STRING_CONST("BusNumber");
+ NDIS_STRING SlotNumberStr = NDIS_STRING_CONST("SlotNumber");
+ NDIS_STRING PcmciaStr = NDIS_STRING_CONST("Pcmcia");
+ NDIS_STRING PciIdStr = NDIS_STRING_CONST("AdapterCFID");
+ NDIS_STRING EisaIdStr = NDIS_STRING_CONST("EisaCompressedId");
+ NDIS_STRING McaIdStr = NDIS_STRING_CONST("McaPosId");
+ PWSTR Bind = NULL, Export = NULL;
+ UNICODE_STRING ExportName, ParmPath;
+ NDIS_STATUS NdisStatus;
+ NTSTATUS RegistryStatus;
+ BOOLEAN IsAMiniport, LayeredDriver, Pcmcia = FALSE;
+ PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
+#define LQueryTable ConfigurationHandle.ParametersQueryTable
+
+ do
+ {
+ pMacBlock = (PNDIS_MAC_BLOCK)pMiniBlock;
+ IsAMiniport = (pMiniBlock->MiniportIdField == (NDIS_HANDLE)0x01);
+
+ //
+ // Set up LQueryTable to do the following:
+ //
+
+ //
+ // 1.
+ // Switch to the Linkage key below this driver instance key
+ //
+
+ LQueryTable[0].QueryRoutine = NULL;
+ LQueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ LQueryTable[0].Name = L"Linkage";
+
+ //
+ // 2.
+ // Call ndisSaveLinkage for "Bind" (as a single multi-string),
+ // which will allocate storage and save the data in Bind.
+ //
+
+ LQueryTable[1].QueryRoutine = ndisSaveLinkage;
+ LQueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ LQueryTable[1].Name = L"Bind";
+ LQueryTable[1].EntryContext = (PVOID)&Bind;
+ LQueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 3.
+ // Call ndisSaveLinkage for "Export" (as a single multi-string)
+ // which will allocate storage and save the data in Export.
+ //
+
+ LQueryTable[2].QueryRoutine = ndisSaveLinkage;
+ LQueryTable[2].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ LQueryTable[2].Name = L"Export";
+ LQueryTable[2].EntryContext = (PVOID)&Export;
+ LQueryTable[2].DefaultType = REG_NONE;
+
+ //
+ // 4.
+ // Call ndisCheckRoute for "Route" (as a single multi-string)
+ // which will set LayeredDriver to TRUE for a layered driver (this
+ // is optional, the default is FALSE).
+ //
+
+ LQueryTable[3].QueryRoutine = ndisCheckRoute;
+ LQueryTable[3].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
+ LQueryTable[3].Name = L"Route";
+ LQueryTable[3].EntryContext = (PVOID)&LayeredDriver;
+ LQueryTable[3].DefaultType = REG_NONE;
+
+ LayeredDriver = FALSE;
+
+ //
+ // 5.
+ // Stop
+ //
+
+ LQueryTable[4].QueryRoutine = NULL;
+ LQueryTable[4].Flags = 0;
+ LQueryTable[4].Name = NULL;
+
+ LayeredDriver = FALSE;
+ ParmPath.Buffer = NULL;
+
+ RegistryStatus = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
+ ServiceName->Buffer,
+ LQueryTable,
+ (PVOID)NULL, // no context needed
+ NULL);
+
+ if (!NT_SUCCESS(RegistryStatus))
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("Could not read Bind/Export/Route for %Z: %lx\n",
+ IsAMiniport ?
+ pMiniBlock->BaseName.Buffer :
+ pMacBlock->BaseName.Buffer,
+ RegistryStatus));
+ NdisStatus = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // NdisReadConfiguration assumes that ParametersQueryTable[3].Name is
+ // a key below the services key where the Parameters should be read,
+ // for layered drivers we store the last piece of Configuration
+ // Path there, leading to the desired effect.
+ //
+ // I.e, ConfigurationPath == "...\Services\Driver".
+ //
+ // For a layered driver, ParameterQueryTable[3].Name is "Driver"
+ // for all calls to AddAdapter, and parameters are read from
+ // "...\Services\Driver\Parameters" for all calls.
+ //
+ // For a non-layered driver, ParametersQueryTable[3].Name might be
+ // "Driver1" for the first call to AddAdapter, "Driver2" for the
+ // second, etc., and parameters are read from
+ // "..\Services\Driver1\Parameters" for the first call to
+ // AddAdapter, "...\Services\Driver2\Parameters" for the second
+ // call, etc.
+ //
+ // Set up ParametersQueryTable. We set most of it up here,
+ // then call the MAC's AddAdapter (or Miniport's Initialize)
+ // routine with its address
+ // as a ConfigContext. Inside ReadConfiguration, we get
+ // the ConfigContext back and can then finish initializing
+ // the table and use RtlQueryRegistryValues (with a
+ // callback to ndisSaveParameter) to read the value
+ // specified.
+ //
+
+ //
+ // 1.
+ // Allocate space for the string "DriverInstance\Parameters" which is passed as a
+ // parameter to RtlQueryRegistryValues. Construct this string in that buffer and
+ // setup PQueryTable[3].
+ //
+ RtlInitUnicodeString(&ExportName, L"\\Parameters");
+ ParmPath.MaximumLength = ServiceName->Length + ExportName.Length + sizeof(WCHAR);
+ ParmPath.Length = 0;
+ if ((ParmPath.Buffer = (PWSTR)ALLOC_FROM_POOL(ParmPath.MaximumLength, NDIS_TAG_NAME_BUF)) == NULL)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("Could not read allocate space for path to parameters\n"));
+ NdisStatus = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ RtlCopyUnicodeString(&ParmPath, ServiceName);
+ RtlAppendUnicodeStringToString(&ParmPath, &ExportName);
+
+ //
+ // 2) Call ndisSaveParameter for a parameter, which
+ // will allocate storage for it.
+ //
+ // ParametersQueryTable[1].Name and ParametersQueryTable[1].EntryContext
+ // are filled in inside ReadConfiguration, in preparation
+ // for the callback.
+ //
+
+ PQueryTable[0].QueryRoutine = ndisSaveParameters;
+ PQueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ PQueryTable[0].DefaultType = REG_NONE;
+ //
+ // The following fields are filled in during NdisReadConfiguration
+ //
+ // PQueryTable[0].Name = KeywordBuffer;
+ // PQueryTable[0].EntryContext = ParameterValue;
+
+ //
+ // 3.
+ // Stop
+ //
+
+ PQueryTable[1].QueryRoutine = NULL;
+ PQueryTable[1].Flags = 0;
+ PQueryTable[1].Name = NULL;
+
+ //
+ // NOTE: Some fields in ParametersQueryTable[3 & 4] are used to
+ // store information for later retrieval.
+ //
+ PQueryTable[3].QueryRoutine = NULL;
+ PQueryTable[3].Name = ParmPath.Buffer;
+ PQueryTable[3].EntryContext = NULL;
+ PQueryTable[3].DefaultData = NULL;
+
+ //
+ // Save the driver name here; later we will use this as
+ // a parameter to RtlQueryRegistryValues.
+ //
+ if (LayeredDriver)
+ {
+ //
+ // This will be returned by NdisReadBindingInformation.
+ //
+ PQueryTable[3].EntryContext = Bind;
+ }
+
+ // Now read bustype/busnumber for this adapter and save it
+ TmpConfigHandle.KeyQueryTable = PQueryTable;
+ TmpConfigHandle.ParameterList = NULL;
+
+ Db.BusNumber = (ULONG)(-1);
+ Db.BusType = (NDIS_INTERFACE_TYPE)(-1);
+ Db.SlotNumber = (ULONG)(-1);
+ Db.BusId = 0;
+
+ //
+ // Read Bus Number
+ //
+ NdisReadConfiguration(&NdisStatus,
+ &ReturnedValue,
+ &TmpConfigHandle,
+ &BusNumberStr,
+ NdisParameterInteger);
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS)
+ {
+ Db.BusNumber = ReturnedValue->ParameterData.IntegerData;
+ }
+
+ //
+ // Read Slot Number
+ //
+ NdisReadConfiguration(&NdisStatus,
+ &ReturnedValue,
+ &TmpConfigHandle,
+ &SlotNumberStr,
+ NdisParameterInteger);
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS)
+ {
+ Db.SlotNumber = ReturnedValue->ParameterData.IntegerData;
+ }
+
+ //
+ // Read Bus Type
+ //
+ NdisReadConfiguration(&NdisStatus,
+ &ReturnedValue,
+ &TmpConfigHandle,
+ &BusTypeStr,
+ NdisParameterInteger);
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS)
+ {
+ Db.BusType = (NDIS_INTERFACE_TYPE)(ReturnedValue->ParameterData.IntegerData);
+ if (Db.BusType == NdisInterfacePcMcia)
+ Db.BusType = NdisInterfaceIsa; // Fix the folks who chose Pcmcia
+
+ //
+ // Now read the bus-id for Pci/Mca/Eisa
+ //
+ switch (Db.BusType)
+ {
+ case NdisInterfaceEisa:
+ NdisReadConfiguration(&NdisStatus,
+ &ReturnedValue,
+ &TmpConfigHandle,
+ &EisaIdStr,
+ NdisParameterInteger);
+ break;
+ case NdisInterfaceMca:
+ NdisReadConfiguration(&NdisStatus,
+ &ReturnedValue,
+ &TmpConfigHandle,
+ &McaIdStr,
+ NdisParameterInteger);
+ break;
+ case NdisInterfacePci:
+ NdisReadConfiguration(&NdisStatus,
+ &ReturnedValue,
+ &TmpConfigHandle,
+ &PciIdStr,
+ NdisParameterInteger);
+ break;
+ }
+ if (NdisStatus == NDIS_STATUS_SUCCESS)
+ {
+ Db.BusId = ReturnedValue->ParameterData.IntegerData;
+ }
+ }
+
+ if (Db.BusId != 0)
+ {
+ switch (Db.BusType)
+ {
+ case NdisInterfaceEisa:
+ case NdisInterfaceMca:
+ case NdisInterfacePci:
+ NdisStatus = ndisFixBusInformation(&TmpConfigHandle, &Db);
+ break;
+ default:
+ NdisStatus = NDIS_STATUS_SUCCESS;
+ break;
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+ }
+
+ //
+ // Check if this is pcmcia ?
+ //
+ NdisReadConfiguration(&NdisStatus,
+ &ReturnedValue,
+ &TmpConfigHandle,
+ &PcmciaStr,
+ NdisParameterInteger);
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS)
+ {
+ Pcmcia = (ReturnedValue->ParameterData.IntegerData != 0);
+ }
+
+ if (Pcmcia)
+ {
+ NdisStatus = ndisCheckIfPcmciaCardPresent(pMiniBlock);
+ if (NdisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+ }
+
+ PQueryTable[3].DefaultType = Db.BusType;
+ PQueryTable[3].DefaultLength = Db.BusNumber;
+ PQueryTable[3].DefaultData = NULL;
+ PQueryTable[3].Flags = 0;
+
+ PQueryTable[4].DefaultLength = Db.SlotNumber;
+
+ //
+ // OK, Now lock down all the filter packages. If a MAC or
+ // Miniport driver uses any of these, then the filter package
+ // will reference itself, to keep the image in memory.
+ //
+ ArcReferencePackage();
+ EthReferencePackage();
+ FddiReferencePackage();
+ TrReferencePackage();
+ MiniportReferencePackage();
+ MacReferencePackage();
+ CoReferencePackage();
+
+ RtlInitUnicodeString (&ExportName, Export);
+ ConfigurationHandle.DriverBaseName = ServiceName;
+
+ NdisStatus = NDIS_STATUS_SUCCESS;
+
+ if (IsAMiniport)
+ {
+ NdisStatus = ndisMInitializeAdapter(pMiniBlock,
+ &ConfigurationHandle,
+ &ExportName,
+ &Db);
+ }
+ else
+ {
+ //
+ // Save the Driver Object with the Configuration Handle.
+ //
+ ConfigurationHandle.DriverObject = pMacBlock->NdisMacInfo->NdisWrapperDriver;
+
+ //
+ // NDIS 3.0 MAC
+ //
+ NdisStatus = (pMacBlock->MacCharacteristics.AddAdapterHandler)(pMacBlock->MacMacContext,
+ &ConfigurationHandle,
+ &ExportName);
+ //
+ // Free the slot information buffer
+ //
+ if (PQueryTable[3].DefaultData != NULL)
+ {
+ FREE_POOL(PQueryTable[3].DefaultData);
+ }
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Update the Db from the Config context
+ //
+ Db.SlotNumber= PQueryTable[4].DefaultLength;
+ Db.BusNumber = PQueryTable[3].DefaultLength;
+ }
+ }
+
+ //
+ // If the initialization failed, cleanup
+ //
+ if ((NdisStatus != NDIS_STATUS_SUCCESS) && (Db.BusId != 0))
+ {
+ ndisDeleteGlobalDb(Db.BusType,
+ Db.BusId,
+ Db.BusNumber,
+ Db.SlotNumber);
+ }
+ else if ((NdisStatus == NDIS_STATUS_SUCCESS) &&
+ (Db.BusId == 0))
+ {
+ //
+ // If this adapter did not have a bus-id in the registry,
+ // do it a favor and write it.
+ //
+ switch (Db.BusType)
+ {
+ case NdisInterfaceEisa:
+ case NdisInterfaceMca:
+ case NdisInterfacePci:
+ ndisAddBusInformation(&TmpConfigHandle, &Db);
+ break;
+ }
+ }
+
+ //
+ // OK, Now dereference all the filter packages. If a MAC or
+ // Miniport driver uses any of these, then the filter package
+ // will reference itself, to keep the image in memory.
+ //
+ ArcDereferencePackage();
+ EthDereferencePackage();
+ FddiDereferencePackage();
+ TrDereferencePackage();
+ MiniportDereferencePackage();
+ MacDereferencePackage();
+ CoDereferencePackage();
+
+ } while (FALSE);
+
+ if (ParmPath.Buffer != NULL)
+ {
+ FREE_POOL(ParmPath.Buffer);
+ }
+
+ if (Bind != NULL)
+ {
+ FREE_POOL(Bind);
+ }
+
+ if (Export != NULL)
+ {
+ FREE_POOL(Export);
+ }
+
+ return NdisStatus;
+}
+
+NDIS_STATUS
+ndisMInitializeAdapter(
+ IN PNDIS_M_DRIVER_BLOCK pMiniBlock,
+ IN PNDIS_WRAPPER_CONFIGURATION_HANDLE pConfigurationHandle,
+ IN PUNICODE_STRING pExportName,
+ IN PBUS_SLOT_DB pDb
+ )
+{
+ BOOLEAN FreeDevice;
+ BOOLEAN DerefDriver;
+ BOOLEAN FreeBuffer;
+ BOOLEAN FreeArcnetLookaheadBuffer;
+ BOOLEAN Dequeue;
+ BOOLEAN ExtendedError;
+ BOOLEAN FreeWorkItemStorage;
+ BOOLEAN FreeDeferredTimer;
+ BOOLEAN FreePacketArray;
+ PDEVICE_OBJECT pTmpDevice;
+ NTSTATUS NtStatus;
+ LONG ErrorCode;
+ PNDIS_MINIPORT_BLOCK Miniport = NULL;
+ UNICODE_STRING SymbolicLink;
+ WCHAR SymLnkBuf[40];
+ NDIS_STATUS MiniportInitializeStatus = NDIS_STATUS_SUCCESS;
+ NDIS_STATUS OpenErrorStatus;
+ NDIS_STATUS NdisStatus;
+
+ UINT SelectedMediumIndex;
+
+ ULONG MaximumLongAddresses;
+ UCHAR CurrentLongAddress[6];
+ ULONG MaximumShortAddresses;
+ UCHAR CurrentShortAddress[2];
+ UINT PacketFilter;
+ UCHAR i;
+ BOOLEAN LocalLock;
+ PARC_BUFFER_LIST Buffer;
+ PVOID DataBuffer;
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+ PSINGLE_LIST_ENTRY Link;
+
+ //
+ // Initialize device.
+ //
+ if (!ndisReferenceDriver((PNDIS_M_DRIVER_BLOCK)pMiniBlock))
+ {
+ //
+ // The driver is closing.
+ //
+ return NDIS_STATUS_FAILURE;
+ }
+
+ //
+ // Initialize locals.
+ //
+ ErrorCode = 0;
+ FreeDevice = FALSE;
+ DerefDriver = FALSE;
+ FreeBuffer = FALSE;
+ FreeArcnetLookaheadBuffer = FALSE;
+ Dequeue = FALSE;
+ ExtendedError = FALSE;
+ FreeWorkItemStorage = FALSE;
+ FreeDeferredTimer = FALSE;
+ FreePacketArray = FALSE;
+ PacketFilter = 0x1;
+
+ do
+ {
+ //
+ // Save the Driver Object with the configuration handle.
+ //
+ pConfigurationHandle->DriverObject = pMiniBlock->NdisDriverInfo->NdisWrapperDriver;
+
+ DerefDriver = TRUE;
+ NtStatus = IoCreateDevice(pMiniBlock->NdisDriverInfo->NdisWrapperDriver,
+ sizeof(NDIS_MINIPORT_BLOCK) +
+ sizeof(NDIS_WRAPPER_CONTEXT) +
+ pConfigurationHandle->DriverBaseName->Length,
+ pExportName,
+ FILE_DEVICE_PHYSICAL_NETCARD,
+ 0,
+ FALSE, // exclusive flag
+ &pTmpDevice);
+ if (NtStatus != STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ FreeDevice = TRUE;
+
+ //
+ // Initialize the Miniport adapter block in the device object extension
+ //
+ // *** NDIS_WRAPPER_CONTEXT has a higher alignment requirement than
+ // NDIS_MINIPORT_BLOCK, so we put it first in the extension.
+ //
+
+ Miniport = (PNDIS_MINIPORT_BLOCK)((PNDIS_WRAPPER_CONTEXT)pTmpDevice->DeviceExtension + 1);
+ ZeroMemory(Miniport, sizeof(PNDIS_MINIPORT_BLOCK));
+
+ //
+ // Setup debug information if needed.
+ //
+ ndisMInitializeDebugInformation(Miniport);
+
+ Miniport->WrapperContext = pTmpDevice->DeviceExtension;
+ Miniport->BaseName.Buffer = (PWSTR)((PUCHAR)Miniport + sizeof(NDIS_MINIPORT_BLOCK));
+ Miniport->BaseName.MaximumLength =
+ Miniport->BaseName.Length = pConfigurationHandle->DriverBaseName->Length;
+ RtlUpcaseUnicodeString(&Miniport->BaseName,
+ pConfigurationHandle->DriverBaseName,
+ FALSE);
+
+ //
+ // Create symbolic link for the device
+ //
+ SymbolicLink.Buffer = SymLnkBuf;
+ SymbolicLink.Length = sizeof(L"\\DosDevices\\") - sizeof(WCHAR);
+ SymbolicLink.MaximumLength = sizeof(SymLnkBuf);
+ RtlCopyMemory(SymLnkBuf, L"\\DosDevices\\", sizeof(L"\\DosDevices\\"));
+ RtlAppendUnicodeStringToString(&SymbolicLink, &Miniport->BaseName);
+ IoCreateSymbolicLink(&SymbolicLink, pExportName);
+
+ Miniport->BusType = pDb->BusType;
+ Miniport->BusId = pDb->BusId;
+ Miniport->SlotNumber = pDb->SlotNumber;
+ Miniport->BusNumber = pDb->BusNumber;
+ Miniport->DeviceObject = pTmpDevice;
+ Miniport->DriverHandle = pMiniBlock;
+ Miniport->MiniportName.Buffer = (PWSTR)ALLOC_FROM_POOL(pExportName->MaximumLength,
+ NDIS_TAG_NAME_BUF);
+ if (Miniport->MiniportName.Buffer == NULL)
+ {
+ break;
+ }
+ FreeBuffer = TRUE;
+
+ Miniport->MiniportName.MaximumLength = pExportName->MaximumLength;
+ Miniport->MiniportName.Length = pExportName->Length;
+
+ CopyMemory(Miniport->MiniportName.Buffer,
+ pExportName->Buffer,
+ pExportName->MaximumLength);
+
+ Miniport->AssignedProcessor = ndisValidProcessors[ndisCurrentProcessor];
+ Miniport->SendResourcesAvailable = 0x00FFFFFF;
+ NdisAllocateSpinLock(&Miniport->Lock);
+
+ // Start off with the null filter
+ Miniport->PacketIndicateHandler = ndisMIndicatePacket;
+
+ //
+ // Initialize the handlers to non-full duplex
+ //
+ Miniport->ProcessDeferredHandler = ndisMProcessDeferred;
+ Miniport->QueueWorkItemHandler = ndisMQueueWorkItem;
+ Miniport->QueueNewWorkItemHandler = ndisMQueueNewWorkItem;
+ Miniport->DeQueueWorkItemHandler = ndisMDeQueueWorkItem;
+
+ Miniport->SendCompleteHandler = NdisMSendComplete;
+ Miniport->SendResourcesHandler = NdisMSendResourcesAvailable;
+ Miniport->ResetCompleteHandler = NdisMResetComplete;
+
+ //
+ // And optimize Dpc/Isr stuff
+ //
+ Miniport->HandleInterruptHandler = Miniport->DriverHandle->MiniportCharacteristics.HandleInterruptHandler;
+ Miniport->DisableInterruptHandler = Miniport->DriverHandle->MiniportCharacteristics.DisableInterruptHandler;
+ Miniport->EnableInterruptHandler = Miniport->DriverHandle->MiniportCharacteristics.EnableInterruptHandler;
+ Miniport->DeferredSendHandler = ndisMStartSends;
+
+ //
+ // Set some flags describing the miniport.
+ //
+ if (pMiniBlock->MiniportCharacteristics.MajorNdisVersion == 4)
+ {
+ if (pMiniBlock->MiniportCharacteristics.MinorNdisVersion >= 0)
+ {
+ //
+ // This is an NDIS 4.0 miniport.
+ //
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_IS_NDIS_4_0);
+
+ //
+ // Does this miniport indicate packets?
+ //
+ if (pMiniBlock->MiniportCharacteristics.ReturnPacketHandler)
+ {
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_INDICATES_PACKETS);
+ }
+
+ //
+ // Can this miniport handle multiple sends?
+ //
+ if (pMiniBlock->MiniportCharacteristics.SendPacketsHandler)
+ {
+ MINIPORT_SET_SEND_FLAG(Miniport, fMINIPORT_SEND_PACKET_ARRAY);
+ Miniport->DeferredSendHandler = ndisMStartSendPackets;
+ }
+ }
+
+ if (pMiniBlock->MiniportCharacteristics.MinorNdisVersion == 1)
+ {
+ //
+ // This is an NDIS 4.1 miniport.
+ //
+ MINIPORT_SET_FLAG(Miniport, (fMINIPORT_IS_NDIS_4_1 | fMINIPORT_INDICATES_PACKETS));
+ if (pMiniBlock->MiniportCharacteristics.CoCreateVcHandler != NULL)
+ {
+ //
+ // This is a connection-oriented miniport.
+ //
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_IS_CO);
+ }
+ }
+ }
+
+ NdisInitializeRef(&Miniport->Ref);
+
+ INITIALIZE_DPC(&Miniport->Dpc,
+ (Miniport->Flags & fMINIPORT_IS_CO) ?
+ ndisMCoDpcTimer : ndisMDpcTimer,
+ Miniport);
+
+ Miniport->CheckForHangTimeout = 2000;
+ NdisInitializeTimer(&Miniport->WakeUpDpcTimer, ndisMWakeUpDpc, Miniport);
+
+ //
+ // Allocate a pool of work items to start with.
+ //
+ for (i = 0, WorkItem = NULL; i < 10; i++)
+ {
+ //
+ // Allocate a work item.
+ //
+ WorkItem = ALLOC_FROM_POOL(sizeof(NDIS_MINIPORT_WORK_ITEM), NDIS_TAG_WORK_ITEM);
+ if (NULL == WorkItem)
+ {
+ break;
+ }
+
+ //
+ // Initialize the work item.
+ //
+ NdisZeroMemory(WorkItem, sizeof(NDIS_MINIPORT_WORK_ITEM));
+
+ //
+ // Place the work item on the free queue.
+ //
+ PushEntryList(&Miniport->WorkItemFreeQueue, &WorkItem->Link);
+ }
+
+ //
+ // Did we get work items allocate?
+ //
+ if (Miniport->WorkItemFreeQueue.Next != NULL)
+ {
+ FreeWorkItemStorage = TRUE;
+ }
+
+ //
+ // Did we get enough work items allocated?
+ // WorkItem will be NULL if we failed to allocate
+ // one of them.
+ //
+ if (NULL == WorkItem)
+ {
+ break;
+ }
+
+ //
+ // Set up the list of workitems that only require one
+ // workitem at any given time.
+ //
+ for (i = 0; i < NUMBER_OF_SINGLE_WORK_ITEMS; i++)
+ {
+ Link = PopEntryList(&Miniport->WorkItemFreeQueue);
+ PushEntryList(&Miniport->SingleWorkItems[i], Link);
+ }
+
+ //
+ // Enqueue the miniport on the driver block.
+ //
+ if (!ndisQueueMiniportOnDriver(Miniport, pMiniBlock))
+ {
+ //
+ // The Driver is closing, undo what we have done.
+ //
+ break;
+ }
+ Dequeue = TRUE;
+
+ //
+ // Allocate memory for a timer structure.
+ //
+ Miniport->DeferredTimer = ALLOC_FROM_POOL(sizeof(NDIS_TIMER), NDIS_TAG_DFRD_TMR);
+ ASSERT(Miniport->DeferredTimer != NULL);
+ if (NULL == Miniport->DeferredTimer)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Failed to allocate memory for the full-duplex timer.\n"));
+ break;
+ }
+
+ FreeDeferredTimer = TRUE;
+
+ //
+ // Initialize the timer with the
+ //
+ NdisInitializeTimer(Miniport->DeferredTimer,
+ (PVOID)ndisMDeferredTimerDpc,
+ (PVOID)Miniport);
+
+ //
+ // Initialize work-item for returning orphaned packets
+ //
+ INITIALIZE_WORK_ITEM(&Miniport->WorkItem, ndisMLazyReturnPackets, Miniport);
+
+ //
+ // Now we do something really bogus. We create many
+ // temporary filter databases, just in case any indications
+ // happen.
+ //
+
+ if (!EthCreateFilter(1,
+ ndisMChangeEthAddresses,
+ ndisMChangeClass,
+ ndisMCloseAction,
+ CurrentLongAddress,
+ &Miniport->Lock,
+ &(Miniport->EthDB)) ||
+ !TrCreateFilter(ndisMChangeFunctionalAddress,
+ ndisMChangeGroupAddress,
+ ndisMChangeClass,
+ ndisMCloseAction,
+ CurrentLongAddress,
+ &Miniport->Lock,
+ &(Miniport->TrDB)) ||
+ !FddiCreateFilter(1,
+ 1,
+ ndisMChangeFddiAddresses,
+ ndisMChangeClass,
+ ndisMCloseAction,
+ CurrentLongAddress,
+ CurrentShortAddress,
+ &Miniport->Lock,
+ &(Miniport->FddiDB)) ||
+ !ArcCreateFilter(Miniport,
+ ndisMChangeClass,
+ ndisMCloseAction,
+ CurrentLongAddress[0],
+ &Miniport->Lock,
+ &(Miniport->ArcDB)))
+ {
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0);
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Could not create the dummy filter!\n"));
+
+ break;
+ }
+
+ //
+ // Save the miniport block with the filter libraries.
+ //
+ Miniport->EthDB->Miniport = Miniport;
+ Miniport->TrDB->Miniport = Miniport;
+ Miniport->FddiDB->Miniport = Miniport;
+
+ //
+ // Call adapter callback. The current value for "Export"
+ // is what we tell him to name this device.
+ //
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS);
+
+ MiniportInitializeStatus =
+ (pMiniBlock->MiniportCharacteristics.InitializeHandler)(
+ &OpenErrorStatus,
+ &SelectedMediumIndex,
+ ndisMediumArray,
+ ndisMediumArraySize/sizeof(NDIS_MEDIUM),
+ (NDIS_HANDLE)(Miniport),
+ (NDIS_HANDLE)pConfigurationHandle);
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ //
+ // Free the slot information buffer
+ //
+ if (pConfigurationHandle->ParametersQueryTable[3].DefaultData != NULL)
+ {
+ FREE_POOL(pConfigurationHandle->ParametersQueryTable[3].DefaultData);
+ }
+
+ if (MiniportInitializeStatus == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Update the Db from the Miniport
+ //
+ pDb->BusNumber = Miniport->BusNumber;
+ pDb->SlotNumber = Miniport->SlotNumber;
+
+ ASSERT(SelectedMediumIndex < (ndisMediumArraySize/sizeof(NDIS_MEDIUM)));
+
+ Miniport->MediaType = ndisMediumArray[SelectedMediumIndex];
+
+ INITIALIZE_EVENT(&Miniport->RequestEvent);
+
+ RESET_EVENT(&Miniport->RequestEvent);
+
+ //
+ // Set Maximumlookahead to 0 as default. For lan media query the real
+ // stuff.
+ //
+ if ((Miniport->MediaType < NdisMediumMax) &&
+ ndisMediaTypeCl[Miniport->MediaType])
+ {
+ //
+ // Query maximum lookahead
+ //
+ ErrorCode = ndisMDoMiniportOp(Miniport,
+ TRUE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ &MaximumLongAddresses,
+ sizeof(MaximumLongAddresses),
+ 0x1);
+ if (ErrorCode != 0)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error querying the OID_GEN_MAXIMUM_LOOKAHEAD\n"));
+
+ break;
+ }
+ }
+
+ //
+ // Now adjust based on media type
+ //
+
+ switch(Miniport->MediaType)
+ {
+ case NdisMedium802_3:
+
+ Miniport->MaximumLookahead = ((NDIS_M_MAX_LOOKAHEAD - 14) < MaximumLongAddresses) ?
+ NDIS_M_MAX_LOOKAHEAD - 14 :
+ MaximumLongAddresses;
+ break;
+
+ case NdisMedium802_5:
+
+ Miniport->MaximumLookahead = ((NDIS_M_MAX_LOOKAHEAD - 32) < MaximumLongAddresses) ?
+ (NDIS_M_MAX_LOOKAHEAD - 32) :
+ MaximumLongAddresses;
+ break;
+
+ case NdisMediumFddi:
+ Miniport->MaximumLookahead = ((NDIS_M_MAX_LOOKAHEAD - 16) < MaximumLongAddresses) ?
+ (NDIS_M_MAX_LOOKAHEAD - 16) :
+ MaximumLongAddresses;
+ break;
+
+ case NdisMediumArcnet878_2:
+ Miniport->MaximumLookahead = ((NDIS_M_MAX_LOOKAHEAD - 50) < MaximumLongAddresses) ?
+ NDIS_M_MAX_LOOKAHEAD - 50 :
+ MaximumLongAddresses;
+
+ //
+ // Assume we will succeed with the lookahead allocation.
+ //
+ ExtendedError = FALSE;
+
+ //
+ // allocate a lookahead buffer for arcnet.
+ //
+ Miniport->ArcnetLookaheadBuffer = ALLOC_FROM_POOL(
+ NDIS_M_MAX_LOOKAHEAD,
+ NDIS_TAG_LA_BUF);
+
+ ASSERT(Miniport->ArcnetLookaheadBuffer != NULL);
+ if (Miniport->ArcnetLookaheadBuffer == NULL)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Could not allocate arcnet lookahead buffer\n"));
+
+ ExtendedError = TRUE;
+ }
+ else
+ {
+ FreeArcnetLookaheadBuffer = TRUE;
+
+ NdisZeroMemory(Miniport->ArcnetLookaheadBuffer,
+ Miniport->MaximumLookahead);
+ }
+
+ break;
+
+ case NdisMediumWan:
+ Miniport->MaximumLookahead = 1514;
+ break;
+
+ case NdisMediumIrda:
+ case NdisMediumWirelessWan:
+ case NdisMediumLocalTalk:
+ Miniport->MaximumLookahead = MaximumLongAddresses;
+ break;
+ }
+
+ //
+ // Was there an error?
+ //
+ if (ExtendedError)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Extended error when processing OID_GEN_MAXIMUM_LOOOKAHEAD\n"));
+ break;
+ }
+
+ //
+ // Set MacOptions to 0 as default. For lan media query the real
+ // stuff. We also need to call this for lan drivers.
+ //
+ Miniport->MacOptions = 0;
+ if (((Miniport->MediaType < NdisMediumMax) &&
+ ndisMediaTypeCl[Miniport->MediaType]) ||
+ (NdisMediumWan == Miniport->MediaType))
+ {
+ //
+ // Query mac options
+ //
+ ErrorCode = ndisMDoMiniportOp(Miniport,
+ TRUE,
+ OID_GEN_MAC_OPTIONS,
+ &MaximumLongAddresses,
+ sizeof(MaximumLongAddresses),
+ 0x3);
+ if (ErrorCode != 0)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error querying OID_GEN_MAC_OPTIONS\n"));
+
+ break;
+ }
+
+ Miniport->MacOptions = (UINT)MaximumLongAddresses;
+ }
+ else
+ {
+ KIRQL OldIrql;
+
+ //
+ // We can't call process deferred at a low irql and
+ // we need to get the local lock.
+ //
+ RAISE_IRQL_TO_DISPATCH(&OldIrql);
+ BLOCK_LOCK_MINIPORT_DPC(Miniport, LocalLock);
+
+ //
+ // Queue a dpc to fire.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemDpc, &Miniport->Dpc, NULL);
+ NDISM_PROCESS_DEFERRED(Miniport);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ LOWER_IRQL(OldIrql);
+ }
+
+ //
+ // This is a full duplex driver if the miniport says it is
+ // and they say they are going to handle loopback and the
+ // number of system processors is more than one.
+ //
+ if (((Miniport->MacOptions & NDIS_MAC_OPTION_FULL_DUPLEX) &&
+ (NdisSystemProcessorCount() > 1))
+ ||
+ MINIPORT_TEST_FLAG(Miniport, fMINIPORT_INTERMEDIATE_DRIVER))
+ {
+ //
+ // Allocate a workitem lock.
+ //
+ INITIALIZE_SPIN_LOCK(&Miniport->WorkLock);
+
+ //
+ // Is this an intermediate driver?
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_INTERMEDIATE_DRIVER))
+ {
+ Miniport->ProcessDeferredHandler = ndisMProcessDeferredFullDuplex;
+ Miniport->QueueWorkItemHandler = ndisIMQueueWorkItem;
+ Miniport->QueueNewWorkItemHandler = ndisIMQueueNewWorkItem;
+ }
+ else
+ {
+ //
+ // Regular full-duplex miniport.
+ //
+ Miniport->ProcessDeferredHandler = ndisMProcessDeferredFullDuplex;
+ Miniport->QueueWorkItemHandler = ndisMQueueWorkItemFullDuplex;
+ Miniport->QueueNewWorkItemHandler = ndisMQueueNewWorkItemFullDuplex;
+ }
+
+ //
+ // Allocate a separate spin lock for the send path.
+ //
+ NdisAllocateSpinLock(&Miniport->SendLock);
+
+ //
+ // Use the full duplex send complete and resources
+ // available handler.
+ //
+ Miniport->SendCompleteHandler = ndisMSendCompleteFullDuplex;
+ Miniport->SendResourcesHandler = ndisMSendResourcesAvailableFullDuplex;
+ Miniport->ResetCompleteHandler = ndisMResetCompleteFullDuplex;
+
+ //
+ // Do we need a send packets handler or a send handler?
+ //
+ if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_PACKET_ARRAY))
+ {
+ Miniport->DeferredSendHandler = ndisMStartSendPacketsFullDuplex;
+ }
+ else
+ {
+ Miniport->DeferredSendHandler = ndisMStartSendsFullDuplex;
+ }
+
+ //
+ // Set the full duplex flag.
+ //
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_FULL_DUPLEX);
+ }
+ else
+ {
+ //
+ // Make sure this is clear if something doesn't match.
+ //
+ Miniport->MacOptions &= ~NDIS_MAC_OPTION_FULL_DUPLEX;
+ }
+
+ if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_PACKET_ARRAY))
+ {
+ //
+ // If this is a NDIS 4.0 miniport that supports the
+ // SendPacketsHandler then we need to query the number of
+ // packets that the miniport supports.
+ //
+ ErrorCode = ndisMDoMiniportOp(Miniport,
+ TRUE,
+ OID_GEN_MAXIMUM_SEND_PACKETS,
+ &MaximumLongAddresses,
+ sizeof(MaximumLongAddresses),
+ 0x3);
+ if (ErrorCode != 0)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error querying OID_GEN_MAXIMUM_SEND_PACKETS\n"));
+
+ break;
+ }
+
+ Miniport->MaximumSendPackets = (UINT)MaximumLongAddresses;
+
+ //
+ // Allocate memory for the send packet array.
+ //
+ Miniport->PacketArray = ALLOC_FROM_POOL(
+ sizeof(PNDIS_PACKET) * MaximumLongAddresses,
+ NDIS_TAG_DEFAULT);
+ if (NULL == Miniport->PacketArray)
+ {
+ break;
+ }
+
+ ZeroMemory(Miniport->PacketArray,
+ sizeof(PNDIS_PACKET) * Miniport->MaximumSendPackets);
+
+ FreePacketArray = TRUE;
+ }
+
+
+ //
+ // Create filter package
+ //
+ switch(Miniport->MediaType)
+ {
+ case NdisMedium802_3:
+
+ //
+ // Query maximum MulticastAddress
+ //
+ ErrorCode = ndisMDoMiniportOp(Miniport,
+ TRUE,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ &MaximumLongAddresses,
+ sizeof(MaximumLongAddresses),
+ 0x5);
+ if (ErrorCode != 0)
+ {
+ ExtendedError = TRUE;
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error querying OID_802_3_MAXIMUM_LIST_SIZE\n"));
+
+ break;
+ }
+
+ if (MaximumLongAddresses > NDIS_M_MAX_MULTI_LIST)
+ {
+ MaximumLongAddresses = NDIS_M_MAX_MULTI_LIST;
+ }
+
+ Miniport->MaximumLongAddresses = MaximumLongAddresses;
+
+ ErrorCode = ndisMDoMiniportOp(Miniport,
+ TRUE,
+ OID_802_3_CURRENT_ADDRESS,
+ &CurrentLongAddress,
+ sizeof(CurrentLongAddress),
+ 0x7);
+ if (ErrorCode != 0)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error querying OID_802_3_CURRENT_ADDRESS\n"));
+
+ ExtendedError = TRUE;
+ break;
+ }
+
+ //
+ // Now undo the bogus filter package. We lock
+ // the miniport so that no dpcs will get queued.
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS);
+
+ ndisMUndoBogusFilters(Miniport);
+
+ if (!EthCreateFilter(MaximumLongAddresses,
+ ndisMChangeEthAddresses,
+ ndisMChangeClass,
+ ndisMCloseAction,
+ CurrentLongAddress,
+ &Miniport->Lock,
+ &Miniport->EthDB))
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error creating the Ethernet filter database\n"));
+
+
+ //
+ // Halt the miniport driver
+ //
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ ErrorCode = 0x9;
+ ExtendedError = TRUE;
+ break;
+ }
+
+ //
+ // Save the miniport block with the filter library.
+ //
+ Miniport->EthDB->Miniport = Miniport;
+
+ // Set the indicate handler
+ Miniport->PacketIndicateHandler = EthFilterDprIndicateReceivePacket;
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ break;
+
+ case NdisMedium802_5:
+
+ ErrorCode = ndisMDoMiniportOp(
+ Miniport,
+ TRUE,
+ OID_802_5_CURRENT_ADDRESS,
+ &CurrentLongAddress,
+ sizeof(CurrentLongAddress),
+ 0xA);
+ if (ErrorCode != 0)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error querying OID_802_5_CURRENT_ADDRESS\n"));
+
+ ExtendedError = TRUE;
+ break;
+ }
+
+ //
+ // Now undo the bogus filter package. We lock
+ // the miniport so that no dpcs will get queued.
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS);
+
+ ndisMUndoBogusFilters(Miniport);
+
+ if (!TrCreateFilter(
+ ndisMChangeFunctionalAddress,
+ ndisMChangeGroupAddress,
+ ndisMChangeClass,
+ ndisMCloseAction,
+ CurrentLongAddress,
+ &Miniport->Lock,
+ &Miniport->TrDB))
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error creating the Token Ring filter database\n"));
+
+ //
+ // Halt the miniport driver
+ //
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ ErrorCode = 0xC;
+ ExtendedError = TRUE;
+ break;
+ }
+
+ //
+ // Save the miniport block with the filter library.
+ //
+ Miniport->TrDB->Miniport = Miniport;
+
+ // Set the indicate handler
+ Miniport->PacketIndicateHandler = TrFilterDprIndicateReceivePacket;
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ break;
+
+ case NdisMediumFddi:
+
+ //
+ // Query maximum MulticastAddress
+ //
+ ErrorCode = ndisMDoMiniportOp(
+ Miniport,
+ TRUE,
+ OID_FDDI_LONG_MAX_LIST_SIZE,
+ &MaximumLongAddresses,
+ sizeof(MaximumLongAddresses),
+ 0xD);
+ if (ErrorCode != 0)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error querying OID_FDDI_LONG_MAX_LIST_SIZE\n"));
+
+ ExtendedError = TRUE;
+ break;
+ }
+
+ if (MaximumLongAddresses > NDIS_M_MAX_MULTI_LIST)
+ {
+ MaximumLongAddresses = NDIS_M_MAX_MULTI_LIST;
+ }
+
+ Miniport->MaximumLongAddresses = MaximumLongAddresses;
+
+ //
+ // Query maximum MulticastAddress
+ //
+ ErrorCode = ndisMDoMiniportOp(Miniport,
+ TRUE,
+ OID_FDDI_SHORT_MAX_LIST_SIZE,
+ &MaximumShortAddresses,
+ sizeof(MaximumShortAddresses),
+ 0xF);
+ if (ErrorCode != 0)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error querying OID_FDDI_SHORT_MAX_LIST_SIZE\n"));
+
+ ExtendedError = TRUE;
+ break;
+ }
+
+ if (MaximumShortAddresses > NDIS_M_MAX_MULTI_LIST)
+ {
+ MaximumShortAddresses = NDIS_M_MAX_MULTI_LIST;
+ }
+
+ Miniport->MaximumShortAddresses = MaximumShortAddresses;
+
+ ErrorCode = ndisMDoMiniportOp(Miniport,
+ TRUE,
+ OID_FDDI_LONG_CURRENT_ADDR,
+ &CurrentLongAddress,
+ sizeof(CurrentLongAddress),
+ 0x11);
+ if (ErrorCode != 0)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error querying OID_FDDI_LONG_CURRENT_ADDR\n"));
+
+ ExtendedError = TRUE;
+ break;
+ }
+
+ ErrorCode = ndisMDoMiniportOp(Miniport,
+ TRUE,
+ OID_FDDI_SHORT_CURRENT_ADDR,
+ &CurrentShortAddress,
+ sizeof(CurrentShortAddress),
+ 0x13);
+ if (ErrorCode != 0)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error querying OID_FDDI_SHORT_CURRENT_ADDR\n"));
+
+ ExtendedError = TRUE;
+ break;
+ }
+
+ //
+ // Now undo the bogus filter package. We lock
+ // the miniport so that no dpcs will get queued.
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS);
+
+ ndisMUndoBogusFilters(Miniport);
+
+ if (!FddiCreateFilter(MaximumLongAddresses,
+ MaximumShortAddresses,
+ ndisMChangeFddiAddresses,
+ ndisMChangeClass,
+ ndisMCloseAction,
+ CurrentLongAddress,
+ CurrentShortAddress,
+ &Miniport->Lock,
+ &Miniport->FddiDB))
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error creating the FDDI filter database\n"));
+
+ //
+ // Halt the miniport driver
+ //
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ ErrorCode = 0x15;
+ ExtendedError = TRUE;
+ break;
+ }
+
+ //
+ // Save the miniport block with the filter library.
+ //
+ Miniport->FddiDB->Miniport = Miniport;
+
+ // Set the indicate handler
+ Miniport->PacketIndicateHandler = FddiFilterDprIndicateReceivePacket;
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ //
+ // In case of an encapsulated ethernet binding, we need
+ // to return the maximum number of multicast addresses
+ // possible.
+ //
+
+ Miniport->MaximumLongAddresses = NDIS_M_MAX_MULTI_LIST;
+
+ //
+ // Allocate Buffer pools
+ //
+ NdisAllocateBufferPool(&NdisStatus,
+ &Miniport->ArcnetBufferPool,
+ WRAPPER_ARC_BUFFERS);
+ if (NdisStatus != NDIS_STATUS_SUCCESS)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Failed to allocate buffer pool for arcnet\n"));
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ ErrorCode = 0x16;
+ ExtendedError = TRUE;
+ break;
+ }
+
+ NdisAllocateMemory((PVOID)&Buffer,
+ sizeof(ARC_BUFFER_LIST) * WRAPPER_ARC_BUFFERS,
+ 0,
+ HighestAcceptableMax);
+ if (Buffer == NULL)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Failed to allocate memory for arcnet buffers\n"));
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisFreeBufferPool(Miniport->ArcnetBufferPool);
+ ErrorCode = 0x17;
+ ExtendedError = TRUE;
+ break;
+ }
+
+ NdisAllocateMemory((PVOID)&DataBuffer,
+ WRAPPER_ARC_HEADER_SIZE * WRAPPER_ARC_BUFFERS,
+ 0,
+ HighestAcceptableMax);
+ if (DataBuffer == NULL)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Failed to allocate memory for arcnet data buffers\n"));
+
+ //
+ // Halt the miniport driver.
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler)(
+ Miniport->MiniportAdapterContext);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisFreeMemory(
+ Buffer,
+ sizeof(ARC_BUFFER_LIST) * WRAPPER_ARC_BUFFERS,
+ 0);
+ NdisFreeBufferPool(Miniport->ArcnetBufferPool);
+ ErrorCode = 0x18;
+ ExtendedError = TRUE;
+ break;
+ }
+
+ for (i = WRAPPER_ARC_BUFFERS; i != 0; i--)
+ {
+ Buffer->BytesLeft = Buffer->Size = WRAPPER_ARC_HEADER_SIZE;
+ Buffer->Buffer = DataBuffer;
+ Buffer->Next = Miniport->ArcnetFreeBufferList;
+ Miniport->ArcnetFreeBufferList = Buffer;
+
+ Buffer++;
+ DataBuffer = (PVOID)(((PUCHAR)DataBuffer) +
+ WRAPPER_ARC_HEADER_SIZE);
+ }
+
+ //
+ // Get current address
+ //
+ ErrorCode = ndisMDoMiniportOp(Miniport,
+ TRUE,
+ OID_ARCNET_CURRENT_ADDRESS,
+ &CurrentLongAddress[5], // address = 00-00-00-00-00-XX
+ 1,
+ 0x19);
+ if (ErrorCode != 0)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error querying OID_ARCNET_CURRENT_ADDRESS\n"));
+
+ NdisFreeMemory(Buffer,
+ sizeof(ARC_BUFFER_LIST) * WRAPPER_ARC_BUFFERS,
+ 0);
+ NdisFreeMemory(DataBuffer,
+ WRAPPER_ARC_HEADER_SIZE * WRAPPER_ARC_BUFFERS,
+ 0);
+ NdisFreeBufferPool(Miniport->ArcnetBufferPool);
+ ExtendedError = TRUE;
+ break;
+ }
+
+ Miniport->ArcnetAddress = CurrentLongAddress[5];
+
+ //
+ // Now undo the bogus filter package. We lock
+ // the miniport so that no dpcs will get queued.
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS);
+
+ ndisMUndoBogusFilters(Miniport);
+
+ if (!ArcCreateFilter(Miniport,
+ ndisMChangeClass,
+ ndisMCloseAction,
+ CurrentLongAddress[5],
+ &Miniport->Lock,
+ &(Miniport->ArcDB)))
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error creating the Arcnet filter database\n"));
+
+ //
+ // Halt the miniport driver
+ //
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisFreeMemory(Buffer,
+ sizeof(ARC_BUFFER_LIST) * WRAPPER_ARC_BUFFERS,
+ 0);
+ NdisFreeMemory(DataBuffer,
+ WRAPPER_ARC_HEADER_SIZE * WRAPPER_ARC_BUFFERS,
+ 0);
+ NdisFreeBufferPool(Miniport->ArcnetBufferPool);
+ ErrorCode = 0x1B;
+ ExtendedError = TRUE;
+ break;
+ }
+
+ // Zero all but the last one.
+
+ CurrentLongAddress[0] = 0;
+ CurrentLongAddress[1] = 0;
+ CurrentLongAddress[2] = 0;
+ CurrentLongAddress[3] = 0;
+ CurrentLongAddress[4] = 0;
+
+ if (!EthCreateFilter(32,
+ ndisMChangeEthAddresses,
+ ndisMChangeClass,
+ ndisMCloseAction,
+ CurrentLongAddress,
+ &Miniport->Lock,
+ &Miniport->EthDB))
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error creating the Arcnet filter database for encapsulated ethernet\n"));
+
+ //
+ // Delete the arcnet filter.
+ //
+ ArcDeleteFilter(Miniport->ArcDB);
+
+ //
+ // Halt the miniport driver
+ //
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisFreeMemory(Buffer,
+ sizeof(ARC_BUFFER_LIST) * WRAPPER_ARC_BUFFERS,
+ 0);
+ NdisFreeMemory(DataBuffer,
+ WRAPPER_ARC_HEADER_SIZE * WRAPPER_ARC_BUFFERS,
+ 0);
+ NdisFreeBufferPool(Miniport->ArcnetBufferPool);
+ ErrorCode = 0x1C;
+ ExtendedError = TRUE;
+ break;
+ }
+
+ //
+ // Save a pointer to the miniport block with the
+ // ethernet filter.
+ //
+ Miniport->EthDB->Miniport = Miniport;
+
+ // Set the indicate handler
+ Miniport->PacketIndicateHandler = EthFilterDprIndicateReceivePacket;
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ break;
+
+ case NdisMediumWan:
+
+ ErrorCode = ndisMDoMiniportOp(Miniport,
+ TRUE,
+ OID_WAN_CURRENT_ADDRESS,
+ &CurrentLongAddress,
+ sizeof(CurrentLongAddress),
+ 0x1D);
+ if (ErrorCode != 0)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error querying OID_WAN_CURRENT_ADDRESS\n"));
+
+ ExtendedError = TRUE;
+ break;
+ }
+
+ //
+ // Fall through
+ //
+ case NdisMediumAtm:
+ //
+ // Now undo the bogus filter package. We lock
+ // the miniport so that no dpcs will get queued.
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS);
+
+ ndisMUndoBogusFilters(Miniport);
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ break;
+ }
+
+ //
+ // Do we need to log an error?
+ //
+ if (ExtendedError)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Extended error while initializing the miniport\n"));
+
+ NdisWriteErrorLogEntry((NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ ErrorCode);
+ break;
+ }
+
+ //
+ // Done with adding this MINIPORT!!!
+ //
+ Miniport->MiniportRequest = NULL;
+
+ IoRegisterShutdownNotification(Miniport->DeviceObject);
+
+ // Set to not cleanup
+ FreeDevice = DerefDriver = FreeBuffer = Dequeue = FALSE;
+ FreeWorkItemStorage = FALSE;
+ FreeArcnetLookaheadBuffer = FALSE;
+ FreeDeferredTimer = FALSE;
+ FreePacketArray = FALSE;
+
+ //
+ // Finally mark the device as *NOT* initializing. This is to let
+ // layered miniports initialize their device instance *OUTSIDE*
+ // of their driver entry. If this flag is on, then NdisOpenAdapter
+ // to this device will not work. This is also true of subsequent
+ // instances of a driver initializing outside of its DriverEntry
+ // as a result of a PnP event.
+ //
+ Miniport->DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+ }
+ else
+ {
+ ErrorCode = MiniportInitializeStatus;
+ }
+ } while (FALSE);
+
+ if ((Miniport != NULL) && (Miniport->Resources != NULL) && (ErrorCode != 0))
+ {
+ ndisMReleaseResources(Miniport);
+ }
+
+ //
+ // Perform any necessary cleanup.
+ //
+ //
+ if (FreeDevice)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("INIT FAILURE: Deleting the device.\n"));
+
+ IoDeleteDevice(pTmpDevice);
+ }
+
+ if (DerefDriver)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("INIT FAILURE: Dereferencing the miniport block.\n"));
+
+ ndisDereferenceDriver(pMiniBlock);
+ }
+
+ if (FreeBuffer)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("INIT FAILURE: Freeing the miniport name.\n"));
+
+ (Miniport->MiniportName.Buffer);
+ }
+
+ if (FreeArcnetLookaheadBuffer)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("INIT FAILURE: Freeing the arcnet lookahead buffer.\n"));
+
+ FREE_POOL(Miniport->ArcnetLookaheadBuffer);
+ }
+
+ if (FreeWorkItemStorage)
+ {
+ PSINGLE_LIST_ENTRY Link;
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("INIT FAILURE: Freeing the workitems.\n"));
+
+ //
+ // Walk the list and free the work items that
+ // were allocated.
+ //
+ while (Miniport->WorkItemFreeQueue.Next != NULL)
+ {
+ Link = PopEntryList(&Miniport->WorkItemFreeQueue);
+ WorkItem = CONTAINING_RECORD(Link, NDIS_MINIPORT_WORK_ITEM, Link);
+ FREE_POOL(WorkItem);
+ }
+
+ //
+ // Free the single workitem list.
+ //
+ for (i = 0; i < NUMBER_OF_SINGLE_WORK_ITEMS; i++)
+ {
+ //
+ // Is there a work item here?
+ //
+ Link = PopEntryList(&Miniport->SingleWorkItems[i]);
+ if (Link != NULL)
+ {
+ WorkItem = CONTAINING_RECORD(Link, NDIS_MINIPORT_WORK_ITEM, Link);
+ FREE_POOL(WorkItem);
+ }
+ }
+ }
+
+ if (FreeDeferredTimer)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("INIT FAILURE: Freeing memory allocated for the Full-Duplex timer.\n"));
+ FREE_POOL(Miniport->DeferredTimer);
+ }
+
+ if (FreePacketArray)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("INIT FAILURE: Freeing memory for the miniport's packet array\n"));
+ FREE_POOL(Miniport->PacketArray);
+ }
+
+ if (Dequeue)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("INIT FAILURE: Dequeueing the miniport from the driver block.\n"));
+
+ ndisDequeueMiniportOnDriver(Miniport, pMiniBlock);
+ }
+
+ return ErrorCode;
+}
+
+BOOLEAN
+ndisCheckProtocolBinding(
+ IN PNDIS_PROTOCOL_BLOCK Protocol,
+ IN PUNICODE_STRING DeviceName,
+ IN PUNICODE_STRING BaseName,
+ OUT PUNICODE_STRING ProtocolSection
+ )
+{
+ RTL_QUERY_REGISTRY_TABLE LinkQueryTable[3];
+ NTSTATUS Status;
+ BOOLEAN rc = FALSE;
+ PWSTR Bind = NULL;
+
+ //
+ // Set up LinkQueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Linkage key below the xports registry key
+ //
+
+ LinkQueryTable[0].QueryRoutine = NULL;
+ LinkQueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ LinkQueryTable[0].Name = L"Linkage";
+
+ //
+ // 2) Call ndisSaveLinkage for "Bind" (as a single multi-string),
+ // which will allocate storage and save the data in Bind.
+ //
+
+ LinkQueryTable[1].QueryRoutine = ndisSaveLinkage;
+ LinkQueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ LinkQueryTable[1].Name = L"Bind";
+ LinkQueryTable[1].EntryContext = (PVOID)&Bind;
+ LinkQueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 3) Stop
+ //
+
+ LinkQueryTable[2].QueryRoutine = NULL;
+ LinkQueryTable[2].Flags = 0;
+ LinkQueryTable[2].Name = NULL;
+
+ do
+ {
+ UNICODE_STRING Us, Parms;
+ PWSTR CurBind;
+
+ RtlInitUnicodeString(&Parms, L"\\Parameters\\");
+ Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
+ Protocol->ProtocolCharacteristics.Name.Buffer,
+ LinkQueryTable,
+ (PVOID)NULL, // no context needed
+ NULL);
+ if (!NT_SUCCESS(Status))
+ break;
+
+ // Walk the list of bindings and see if any match
+ for (CurBind = Bind;
+ *CurBind != 0;
+ CurBind = (PWCHAR)((PUCHAR)CurBind + Us.MaximumLength))
+ {
+ RtlInitUnicodeString (&Us, CurBind);
+
+ if (RtlEqualUnicodeString(&Us, DeviceName, TRUE))
+ {
+ //
+ // Allocate space for the protocol section under the adapter
+ // to pass to the protocol. The string looks like this.
+ //
+ // Sonic1\Parameters\tcpip
+ //
+ ProtocolSection->MaximumLength = BaseName->Length + // "Sonic1"
+ Parms.Length + // "\Parameters\"
+ Protocol->ProtocolCharacteristics.Name.Length +// "tcpip"
+ sizeof(WCHAR);
+ ProtocolSection->Length = BaseName->Length;
+ ProtocolSection->Buffer = (PWSTR)ALLOC_FROM_POOL(ProtocolSection->MaximumLength,
+ NDIS_TAG_DEFAULT);
+ if (ProtocolSection->Buffer != NULL)
+ {
+ ZeroMemory(ProtocolSection->Buffer, ProtocolSection->MaximumLength);
+ CopyMemory(ProtocolSection->Buffer,
+ BaseName->Buffer,
+ BaseName->Length);
+ RtlAppendUnicodeStringToString(ProtocolSection,
+ &Parms);
+ RtlAppendUnicodeStringToString(ProtocolSection,
+ &Protocol->ProtocolCharacteristics.Name);
+ rc = TRUE;
+ }
+ break;
+ }
+ }
+ } while (FALSE);
+
+ if (Bind != NULL)
+ FREE_POOL(Bind);
+
+ return rc;
+}
+
+BOOLEAN
+ndisProtocolAlreadyBound(
+ IN PNDIS_PROTOCOL_BLOCK Protocol,
+ IN PUNICODE_STRING AdapterName
+ )
+{
+ PNDIS_OPEN_BLOCK pOpen;
+ BOOLEAN rc = FALSE;
+ KIRQL OldIrql;
+
+ NDIS_ACQUIRE_SPIN_LOCK(&Protocol->Ref.SpinLock, &OldIrql);
+
+ for (pOpen = Protocol->OpenQueue;
+ pOpen != NULL;
+ pOpen = pOpen->ProtocolNextOpen)
+ {
+ if (NDIS_EQUAL_UNICODE_STRING(AdapterName, &pOpen->AdapterName))
+ {
+ rc = TRUE;
+ break;
+ }
+ }
+
+ NDIS_RELEASE_SPIN_LOCK(&Protocol->Ref.SpinLock, OldIrql);
+ return rc;
+}
+
+NDIS_STATUS
+ndisUpdateDriverInstance(
+ IN PUNICODE_STRING BaseString,
+ IN PUNICODE_STRING BindString,
+ IN PUNICODE_STRING ExportString,
+ IN PUNICODE_STRING RouteString
+ )
+{
+ UNICODE_STRING Path, Linkage;
+ UINT SavedLen;
+ NDIS_STATUS Status = NDIS_STATUS_RESOURCES;
+
+ RtlInitUnicodeString(&Linkage, L"\\Linkage");
+ Path.MaximumLength = BaseString->Length + Linkage.Length + sizeof(WCHAR);
+ Path.Length = 0;
+ Path.Buffer = (PWSTR)ALLOC_FROM_POOL(Path.MaximumLength, NDIS_TAG_DEFAULT);
+ if (Path.Buffer != NULL)
+ {
+ //
+ // Add the Bind/Route/Linkage sections to the driver instance
+ //
+ ZeroMemory(Path.Buffer, Path.MaximumLength);
+ RtlCopyUnicodeString(&Path, BaseString);
+ RtlAppendUnicodeStringToString(&Path, &Linkage);
+
+ RtlWriteRegistryValue(RTL_REGISTRY_SERVICES,
+ Path.Buffer,
+ L"Bind",
+ REG_MULTI_SZ,
+ BindString->Buffer,
+ BindString->Length);
+ RtlWriteRegistryValue(RTL_REGISTRY_SERVICES,
+ Path.Buffer,
+ L"Export",
+ REG_MULTI_SZ,
+ ExportString->Buffer,
+ ExportString->Length);
+ RtlWriteRegistryValue(RTL_REGISTRY_SERVICES,
+ Path.Buffer,
+ L"Route",
+ REG_MULTI_SZ,
+ RouteString->Buffer,
+ RouteString->Length);
+ FREE_POOL(Path.Buffer);
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ return Status;
+}
+
+NDIS_STATUS
+ndisCheckIfPcmciaCardPresent(
+ IN PNDIS_M_DRIVER_BLOCK pMiniBlock
+ )
+{
+ PNDIS_MAC_BLOCK pMacBlock = (PNDIS_MAC_BLOCK)pMiniBlock;
+ NTSTATUS RegStatus;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+ BOOLEAN Found = FALSE;
+#define PCMCIA_HW_SECTION L"\\Registry\\Machine\\Hardware\\Description\\System\\PCMCIA PCCARDs"
+
+ //
+ // Setup to enumerate the values in the registry section (shown above).
+ // For each such value, we'll check against the driver name.
+ //
+ QueryTable[0].QueryRoutine = ndisValidatePcmciaDriver;
+ QueryTable[0].DefaultType = REG_FULL_RESOURCE_DESCRIPTOR;
+ QueryTable[0].DefaultLength = 0;
+ QueryTable[0].EntryContext = &Found;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
+ QueryTable[0].Name = (pMiniBlock->MiniportIdField == (NDIS_HANDLE)0x01) ?
+ pMiniBlock->BaseName.Buffer : pMacBlock->BaseName.Buffer;
+
+ //
+ // Query terminator
+ //
+ QueryTable[1].QueryRoutine = NULL;
+ QueryTable[1].Flags = 0;
+ QueryTable[1].Name = NULL;
+
+ RegStatus = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
+ PCMCIA_HW_SECTION,
+ QueryTable,
+ (PVOID)NULL, // no context needed
+ NULL);
+ return(Found ? NDIS_STATUS_SUCCESS : NDIS_STATUS_ADAPTER_NOT_FOUND);
+#undef PCMCIA_HW_SECTION
+}
+
+NTSTATUS
+ndisValidatePcmciaDriver(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+{
+ if (ValueLength != 0)
+ *(BOOLEAN *)EntryContext = TRUE;
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+VOID
+ndisQueuedBindNotification(
+ IN PQUEUED_PROTOCOL_NOTIFICATION pQPN
+ )
+{
+ KIRQL OldIrql;
+ PNDIS_M_DRIVER_BLOCK MiniBlock = pQPN->MiniBlock;
+ PNDIS_MINIPORT_BLOCK Miniport, NextMiniport;
+
+ //
+ // Initiate upcalls to protocols to bind to it. First reference the
+ // miniport.
+ //
+ NDIS_ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
+
+ for (Miniport = MiniBlock->MiniportQueue;
+ Miniport != NULL;
+ Miniport = NextMiniport)
+ {
+ if (NDIS_EQUAL_UNICODE_STRING(&pQPN->UpCaseDeviceInstance, &Miniport->BaseName) &&
+ ndisReferenceMiniport(Miniport))
+ {
+ NDIS_RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
+
+ ndisInitializeBindings(&Miniport->MiniportName,
+ &Miniport->BaseName,
+ FALSE);
+
+ NDIS_ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
+ break;
+ }
+ else
+ {
+ NextMiniport = Miniport->NextMiniport;
+ }
+ }
+
+ NDIS_RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
+}
+
+
+NDIS_STATUS
+NdisIMInitializeDeviceInstance(
+ IN NDIS_HANDLE DriverHandle,
+ IN PNDIS_STRING DeviceInstance
+ )
+/*++
+
+Routine Description:
+
+ Initialize an instance of a miniport device.
+
+Arguments:
+
+ DriverHandle - Handle returned by NdisMRegisterLayeredMiniport.
+ It is a pointer to NDIS_M_DRIVER_BLOCK.
+ DeviceInstance -Points to the instance of the driver that must now
+ be initialized.
+
+Return Value:
+
+
+--*/
+{
+ NDIS_STATUS Status;
+ PNDIS_M_DRIVER_BLOCK MiniBlock = (PNDIS_M_DRIVER_BLOCK)DriverHandle;
+
+ Status = ndisInitializeAllAdapterInstances((PNDIS_MAC_BLOCK)MiniBlock,
+ DeviceInstance);
+
+ //
+ // Queue a thread to do protocol notifications
+ //
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ NTSTATUS s;
+ PQUEUED_PROTOCOL_NOTIFICATION pQPN;
+
+ pQPN = (PQUEUED_PROTOCOL_NOTIFICATION)ALLOC_FROM_POOL(sizeof(QUEUED_PROTOCOL_NOTIFICATION) +
+ DeviceInstance->MaximumLength,
+ NDIS_TAG_DEFAULT);
+ if (pQPN == NULL)
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("Cannot allocate memory for protocol notifications for intermediate driver %Z\n",
+ DeviceInstance));
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ pQPN->MiniBlock = MiniBlock;
+ pQPN->UpCaseDeviceInstance.Buffer = pQPN->Buffer;
+ pQPN->UpCaseDeviceInstance.Length = DeviceInstance->MaximumLength;
+ pQPN->UpCaseDeviceInstance.MaximumLength = DeviceInstance->MaximumLength;
+
+ s = RtlUpcaseUnicodeString(&pQPN->UpCaseDeviceInstance, DeviceInstance, FALSE);
+ if (!NT_SUCCESS(s))
+ {
+ return s;
+ }
+
+ INITIALIZE_WORK_ITEM(&pQPN->WorkItem, ndisQueuedBindNotification, pQPN);
+ QUEUE_WORK_ITEM(&pQPN->WorkItem, DelayedWorkQueue);
+ }
+
+ return Status;
+}
+
+
diff --git a/private/ntos/ndis/ndis40/mac.c b/private/ntos/ndis/ndis40/mac.c
new file mode 100644
index 000000000..9579d5e8e
--- /dev/null
+++ b/private/ntos/ndis/ndis40/mac.c
@@ -0,0 +1,3591 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ mac.c
+
+Abstract:
+
+ NDIS wrapper functions for full mac drivers
+
+Author:
+
+ Adam Barr (adamba) 11-Jul-1990
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ 26-Feb-1991 JohnsonA Added Debugging Code
+ 10-Jul-1991 JohnsonA Implement revised Ndis Specs
+ 01-Jun-1995 JameelH Re-organized
+
+--*/
+
+
+#include <precomp.h>
+#pragma hdrstop
+
+#include <stdarg.h>
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_MAC
+
+VOID
+ndisLastCountRemovedFunction(
+ IN struct _KDPC * Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+
+/*++
+
+Routine Description:
+
+ Queued from ndisIsr if the refcount is zero and we need to
+ set the event, since we can't do that from an ISR.
+
+Arguments:
+
+ Dpc - Will be NdisInterrupt->InterruptDpc.
+
+ DeferredContext - Points to the event to set.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(Dpc);
+ UNREFERENCED_PARAMETER(SystemArgument1);
+ UNREFERENCED_PARAMETER(SystemArgument2);
+
+ SET_EVENT((PKEVENT)DeferredContext);
+}
+
+
+VOID
+ndisUnload(
+ IN PDRIVER_OBJECT DriverObject
+ )
+/*++
+
+Routine Description:
+
+ This routine is called when a driver is supposed to unload. Ndis
+ converts this into a set of calls to MacRemoveAdapter() for each
+ adapter that the Mac has open. When the last adapter deregisters
+ itself it will call MacUnload().
+
+Arguments:
+
+ DriverObject - the driver object for the mac that is to unload.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MAC_BLOCK MacP;
+ PNDIS_ADAPTER_BLOCK Adapter, NextAdapter;
+ KIRQL OldIrql;
+
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+
+ //
+ // Search for the MacP
+ //
+
+ MacP = ndisMacDriverList;
+
+ while (MacP != (PNDIS_MAC_BLOCK)NULL)
+ {
+ if (MacP->NdisMacInfo->NdisWrapperDriver == DriverObject)
+ {
+ break;
+ }
+
+ MacP = MacP->NextMac;
+ }
+
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ if (MacP == (PNDIS_MAC_BLOCK)NULL)
+ {
+ //
+ // It is already gone. Just return.
+ //
+ return;
+ }
+
+ MacP->Unloading = TRUE;
+
+
+ //
+ // Now call MACRemoveAdapter() for each Adapter.
+ //
+
+ Adapter = MacP->AdapterQueue;
+
+ while (Adapter != (PNDIS_ADAPTER_BLOCK)NULL)
+ {
+ NextAdapter = Adapter->NextAdapter; // since queue may change
+
+ (MacP->MacCharacteristics.RemoveAdapterHandler)(
+ Adapter->MacAdapterContext);
+
+ //
+ // If a shutdown handler was registered then deregister it.
+ //
+ NdisDeregisterAdapterShutdownHandler(Adapter);
+
+ Adapter = NextAdapter;
+ }
+
+ //
+ // Wait for all adapters to be gonzo.
+ //
+
+ WAIT_FOR_OBJECT(&MacP->AdaptersRemovedEvent, NULL);
+
+ RESET_EVENT(&MacP->AdaptersRemovedEvent);
+
+ //
+ // Now call the MACUnload routine
+ //
+
+ (MacP->MacCharacteristics.UnloadMacHandler)(MacP->MacMacContext);
+
+ //
+ // Now remove the last reference (this will remove it from the list)
+ //
+ ASSERT(MacP->Ref.ReferenceCount == 1);
+
+ ndisDereferenceMac(MacP);
+}
+
+
+NTSTATUS
+ndisShutdown(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ The "shutdown handler" for the SHUTDOWN Irp. Will call the Ndis
+ shutdown routine, if one is registered.
+
+Arguments:
+
+ DeviceObject - The adapter's device object.
+ Irp - The IRP.
+
+Return Value:
+
+ Always STATUS_SUCCESS.
+
+--*/
+
+{
+ PNDIS_WRAPPER_CONTEXT WrapperContext = (PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension;
+ PNDIS_ADAPTER_BLOCK Miniport = (PNDIS_ADAPTER_BLOCK)(WrapperContext + 1);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>ndisShutdown\n"));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(Irp))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ (": Null Irp\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(Irp))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ (": Irp not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ }
+
+ if (WrapperContext->ShutdownHandler != NULL)
+ {
+ //
+ // Call the shutdown routine
+ //
+
+ WrapperContext->ShutdownHandler(WrapperContext->ShutdownContext);
+ }
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==ndisShutdown\n"));
+
+ return STATUS_SUCCESS;
+}
+
+
+IO_ALLOCATION_ACTION
+ndisDmaExecutionRoutine(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is an execution routine for AllocateAdapterChannel,
+ if is called when an adapter channel allocated by
+ NdisAllocateDmaChannel is available.
+
+Arguments:
+
+ DeviceObject - The device object of the adapter.
+
+ Irp - ??.
+
+ MapRegisterBase - The address of the first translation table
+ assigned to us.
+
+ Context - A pointer to the NDIS_DMA_BLOCK in question.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_DMA_BLOCK DmaBlock = (PNDIS_DMA_BLOCK)Context;
+
+ UNREFERENCED_PARAMETER (Irp);
+ UNREFERENCED_PARAMETER (DeviceObject);
+
+
+ //
+ // Save the map register base.
+ //
+
+ DmaBlock->MapRegisterBase = MapRegisterBase;
+
+ //
+ // This will free the thread that is waiting for this callback.
+ //
+
+ SET_EVENT(&DmaBlock->AllocationEvent);
+
+ return KeepObject;
+}
+
+
+
+NDIS_STATUS
+ndisMacReceiveHandler(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+{
+ PNDIS_OPEN_BLOCK Open;
+ NDIS_STATUS Status;
+ KIRQL oldIrql;
+
+ RAISE_IRQL_TO_DISPATCH(&oldIrql);
+
+ //
+ // Find protocol binding context and get associated open for it.
+ //
+ Open = ndisGetOpenBlockFromProtocolBindingContext(ProtocolBindingContext);
+ ASSERT(Open != NULL);
+
+ Status = (Open->PostNt31ReceiveHandler)(ProtocolBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize);
+ LOWER_IRQL(oldIrql);
+ return Status;
+}
+
+
+VOID
+ndisMacReceiveCompleteHandler(
+ IN NDIS_HANDLE ProtocolBindingContext
+ )
+{
+ PNDIS_OPEN_BLOCK Open;
+ KIRQL oldIrql;
+
+ RAISE_IRQL_TO_DISPATCH(&oldIrql);
+ //
+ // Find protocol binding context and get associated open for it.
+ //
+ Open = ndisGetOpenBlockFromProtocolBindingContext(ProtocolBindingContext);
+ ASSERT(Open != NULL);
+
+ (Open->PostNt31ReceiveCompleteHandler)(ProtocolBindingContext);
+ LOWER_IRQL(oldIrql);
+}
+
+
+PNDIS_OPEN_BLOCK
+ndisGetOpenBlockFromProtocolBindingContext(
+ IN NDIS_HANDLE ProtocolBindingContext
+ )
+{
+ PNDIS_OPEN_BLOCK *ppOpen;
+
+ ACQUIRE_SPIN_LOCK_DPC(&ndisGlobalOpenListLock);
+
+ for (ppOpen = &ndisGlobalOpenList;
+ *ppOpen != NULL;
+ ppOpen = &(*ppOpen)->NextGlobalOpen)
+ {
+ if ((*ppOpen)->ProtocolBindingContext == ProtocolBindingContext)
+ {
+ break;
+ }
+ }
+
+ RELEASE_SPIN_LOCK_DPC(&ndisGlobalOpenListLock);
+
+ return *ppOpen;
+}
+
+
+IO_ALLOCATION_ACTION
+ndisAllocationExecutionRoutine(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the execution routine for AllocateAdapterChannel,
+ if is called when the map registers have been assigned.
+
+Arguments:
+
+ DeviceObject - The device object of the adapter.
+
+ Irp - ??.
+
+ MapRegisterBase - The address of the first translation table
+ assigned to us.
+
+ Context - A pointer to the Adapter in question.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_ADAPTER_BLOCK AdaptP = (PNDIS_ADAPTER_BLOCK)Context;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)Context;
+
+ Irp; DeviceObject;
+
+ //
+ // Save this translation entry in the correct spot.
+ //
+
+ if (AdaptP->DeviceObject == NULL)
+ {
+ Miniport->MapRegisters[Miniport->CurrentMapRegister].MapRegister = MapRegisterBase;
+ }
+ else
+ {
+ AdaptP->MapRegisters[AdaptP->CurrentMapRegister].MapRegister = MapRegisterBase;
+ }
+
+ //
+ // This will free the thread that is waiting for this callback.
+ //
+
+ SET_EVENT(((AdaptP->DeviceObject == NULL) ?
+ &Miniport->AllocationEvent :
+ &AdaptP->AllocationEvent));
+
+ return DeallocateObjectKeepRegisters;
+}
+
+
+VOID
+NdisReleaseAdapterResources(
+ IN NDIS_HANDLE NdisAdapterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Informs the wrapper that the resources (such as interrupt,
+ I/O ports, etc.) have been shut down in some way such that
+ they will not interfere with other devices in the system.
+
+Arguments:
+
+ NdisAdapterHandle - The handle returned by NdisRegisterAdapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PCM_RESOURCE_LIST Resources;
+ BOOLEAN Conflict;
+ NTSTATUS NtStatus;
+ PNDIS_ADAPTER_BLOCK AdptrP = (PNDIS_ADAPTER_BLOCK)(NdisAdapterHandle);
+
+ Resources = AdptrP->Resources;
+
+ //
+ // Clear count
+ //
+ Resources->List[0].PartialResourceList.Count = 0;
+
+ //
+ // Make the call
+ //
+ NtStatus = IoReportResourceUsage(NULL,
+ AdptrP->MacHandle->NdisMacInfo->NdisWrapperDriver,
+ NULL,
+ 0,
+ AdptrP->DeviceObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST)+sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ TRUE,
+ &Conflict);
+}
+
+
+VOID
+NdisWriteErrorLogEntry(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN NDIS_ERROR_CODE ErrorCode,
+ IN ULONG NumberOfErrorValues,
+ ...
+ )
+/*++
+
+Routine Description:
+
+ This function allocates an I/O error log record, fills it in and writes it
+ to the I/O error log.
+
+
+Arguments:
+
+ NdisAdapterHandle - points to the adapter block.
+
+ ErrorCode - Ndis code mapped to a string.
+
+ NumberOfErrorValues - number of ULONGS to store for the error.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+
+ va_list ArgumentPointer;
+
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ PNDIS_ADAPTER_BLOCK AdapterBlock = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle;
+ PDEVICE_OBJECT DeviceObject;
+ ULONG i;
+ ULONG StringSize;
+ PWCH baseFileName;
+
+ if (AdapterBlock == NULL)
+ {
+ return;
+ }
+
+ DeviceObject = AdapterBlock->DeviceObject;
+
+ if (DeviceObject != NULL)
+ {
+ baseFileName = AdapterBlock->AdapterName.Buffer;
+ }
+ else
+ {
+ baseFileName = Miniport->MiniportName.Buffer;
+ }
+
+ //
+ // Parse out the path name, leaving only the device name.
+ //
+
+ for (i = 0;
+ i < ((DeviceObject != NULL) ?
+ AdapterBlock->AdapterName.Length :
+ Miniport->MiniportName.Length) / sizeof(WCHAR); i++)
+ {
+ //
+ // If s points to a directory separator, set baseFileName to
+ // the character after the separator.
+ //
+
+ if (((DeviceObject != NULL) ?
+ AdapterBlock->AdapterName.Buffer[i] :
+ Miniport->MiniportName.Buffer[i]) == OBJ_NAME_PATH_SEPARATOR)
+ {
+ baseFileName = ((DeviceObject != NULL) ?
+ &(AdapterBlock->AdapterName.Buffer[++i]) :
+ &(Miniport->MiniportName.Buffer[++i]));
+ }
+
+ }
+
+ StringSize = ((DeviceObject != NULL) ?
+ AdapterBlock->AdapterName.MaximumLength :
+ Miniport->MiniportName.MaximumLength) -
+ (((ULONG)baseFileName) -
+ ((DeviceObject != NULL) ?
+ ((ULONG)AdapterBlock->AdapterName.Buffer) :
+ ((ULONG)Miniport->MiniportName.Buffer)));
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ ((DeviceObject != NULL) ? AdapterBlock->DeviceObject : Miniport->DeviceObject),
+ (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
+ NumberOfErrorValues * sizeof(ULONG) + StringSize));
+
+ if (errorLogEntry != NULL)
+ {
+ errorLogEntry->ErrorCode = ErrorCode;
+
+ //
+ // store the time
+ //
+
+ errorLogEntry->MajorFunctionCode = 0;
+ errorLogEntry->RetryCount = 0;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = 0;
+ errorLogEntry->SequenceNumber = 0;
+ errorLogEntry->IoControlCode = 0;
+
+ //
+ // Store Data
+ //
+
+ errorLogEntry->DumpDataSize = (USHORT)(NumberOfErrorValues * sizeof(ULONG));
+
+ va_start(ArgumentPointer, NumberOfErrorValues);
+
+ for (i = 0; i < NumberOfErrorValues; i++)
+ {
+ errorLogEntry->DumpData[i] = va_arg(ArgumentPointer, ULONG);
+ }
+
+ va_end(ArgumentPointer);
+
+
+ //
+ // Set string information
+ //
+
+ if (StringSize != 0)
+ {
+ errorLogEntry->NumberOfStrings = 1;
+ errorLogEntry->StringOffset =
+ sizeof(IO_ERROR_LOG_PACKET) +
+ NumberOfErrorValues * sizeof(ULONG);
+
+
+ CopyMemory(((PUCHAR)errorLogEntry) + (sizeof(IO_ERROR_LOG_PACKET) +
+ NumberOfErrorValues * sizeof(ULONG)),
+ baseFileName,
+ StringSize);
+
+ }
+ else
+ {
+ errorLogEntry->NumberOfStrings = 0;
+ }
+
+ //
+ // write it out
+ //
+
+ IoWriteErrorLogEntry(errorLogEntry);
+ }
+
+}
+
+
+VOID
+NdisCompleteOpenAdapter(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS Status,
+ IN NDIS_STATUS OpenErrorStatus
+ )
+
+{
+ PNDIS_OPEN_BLOCK OpenP = (PNDIS_OPEN_BLOCK)NdisBindingContext;
+ PQUEUED_OPEN_CLOSE pQoC = NULL;
+ QUEUED_OPEN_CLOSE QoC;
+ KIRQL OldIrql;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("==>NdisCompleteOpenAdapter\n"));
+
+ IF_DBG(DBG_COMP_OPEN, DBG_LEVEL_ERR)
+ {
+ if (!DbgIsNonPaged(NdisBindingContext))
+ {
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_ERR,
+ ("NdisCompleteOpenAdapter: Handle not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_OPEN, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(NdisBindingContext))
+ {
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_ERR,
+ ("NdisCompleteOpenAdapter: Binding Context not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_OPEN, DBG_LEVEL_ERR);
+ }
+ }
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (!NdisFinishOpen(OpenP))
+ {
+ Status = NDIS_STATUS_CLOSING;
+ }
+ }
+
+ if (KeGetCurrentIrql() == DISPATCH_LEVEL)
+ {
+ pQoC = (PQUEUED_OPEN_CLOSE)ALLOC_FROM_POOL(sizeof(QUEUED_OPEN_CLOSE), NDIS_TAG_DEFAULT);
+ if (pQoC != NULL)
+ {
+ pQoC->FreeIt = TRUE;
+ }
+ }
+
+ if (pQoC == NULL)
+ {
+ pQoC = &QoC;
+ pQoC->FreeIt = FALSE;
+ }
+
+ pQoC->OpenP = OpenP;
+ pQoC->Status = Status;
+ pQoC->OpenErrorStatus = OpenErrorStatus;
+
+ if (pQoC->FreeIt)
+ {
+ INITIALIZE_WORK_ITEM(&pQoC->WorkItem,
+ ndisQueuedCompleteOpenAdapter,
+ pQoC);
+ QUEUE_WORK_ITEM(&pQoC->WorkItem, HyperCriticalWorkQueue);
+ }
+ else
+ {
+ ndisQueuedCompleteOpenAdapter(pQoC);
+ }
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("<==NdisCompleteOpenAdapter\n"));
+}
+
+
+VOID
+ndisQueuedCompleteOpenAdapter(
+ IN PQUEUED_OPEN_CLOSE pQoC
+ )
+{
+ PNDIS_OPEN_BLOCK *ppOpen;
+ KIRQL OldIrql;
+
+ (pQoC->OpenP->ProtocolHandle->ProtocolCharacteristics.OpenAdapterCompleteHandler)(
+ pQoC->OpenP->ProtocolBindingContext,
+ pQoC->Status,
+ pQoC->OpenErrorStatus);
+
+ if (pQoC->Status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Something went wrong, clean up and exit.
+ //
+
+ ACQUIRE_SPIN_LOCK(&ndisGlobalOpenListLock, &OldIrql);
+
+ for (ppOpen = &ndisGlobalOpenList;
+ *ppOpen != NULL;
+ ppOpen = &(*ppOpen)->NextGlobalOpen)
+ {
+ if (*ppOpen == pQoC->OpenP)
+ {
+ *ppOpen = pQoC->OpenP->NextGlobalOpen;
+ break;
+ }
+ }
+
+ RELEASE_SPIN_LOCK(&ndisGlobalOpenListLock, OldIrql);
+
+ ObDereferenceObject(pQoC->OpenP->FileObject);
+ ndisDereferenceAdapter(pQoC->OpenP->AdapterHandle);
+ ndisDereferenceProtocol(pQoC->OpenP->ProtocolHandle);
+ FREE_POOL(pQoC->OpenP);
+ }
+
+ if (pQoC->FreeIt)
+ {
+ FREE_POOL(pQoC);
+ }
+}
+
+VOID
+NdisCompleteCloseAdapter(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS Status
+ )
+
+{
+ PNDIS_OPEN_BLOCK Open = (PNDIS_OPEN_BLOCK) NdisBindingContext;
+ PQUEUED_OPEN_CLOSE pQoC = NULL;
+ QUEUED_OPEN_CLOSE QoC;
+ KIRQL OldIrql;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("==>NdisCompleteCloseAdapter\n"));
+
+ IF_DBG(DBG_COMP_OPEN, DBG_LEVEL_ERR)
+ {
+ if (!DbgIsNonPaged(NdisBindingContext))
+ {
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_ERR,
+ ("NdisCompleteCloseAdapter: Handle not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_OPEN, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(NdisBindingContext))
+ {
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_ERR,
+ ("NdisCompleteCloseAdapter: Binding Context not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_OPEN, DBG_LEVEL_ERR);
+ }
+ }
+
+ if (KeGetCurrentIrql() == DISPATCH_LEVEL)
+ {
+ pQoC = (PQUEUED_OPEN_CLOSE)ALLOC_FROM_POOL(sizeof(QUEUED_OPEN_CLOSE), NDIS_TAG_DEFAULT);
+ if (pQoC != NULL)
+ {
+ pQoC->FreeIt = TRUE;
+ }
+ }
+
+ if (pQoC == NULL)
+ {
+ pQoC = &QoC;
+ pQoC->FreeIt = FALSE;
+ }
+
+ pQoC->OpenP = Open;
+ pQoC->Status = Status;
+
+ if (pQoC->FreeIt)
+ {
+ INITIALIZE_WORK_ITEM(&pQoC->WorkItem,
+ ndisQueuedCompleteCloseAdapter,
+ pQoC);
+ QUEUE_WORK_ITEM(&pQoC->WorkItem, CriticalWorkQueue);
+ }
+ else
+ {
+ ndisQueuedCompleteCloseAdapter(pQoC);
+ }
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("<==NdisCompleteCloseAdapter\n"));
+}
+
+
+VOID
+ndisQueuedCompleteCloseAdapter(
+ IN PQUEUED_OPEN_CLOSE pQoC
+ )
+{
+ PNDIS_OPEN_BLOCK OpenP, *ppOpen;
+ KIRQL OldIrql;
+
+ OpenP = pQoC->OpenP;
+
+ (OpenP->ProtocolHandle->ProtocolCharacteristics.CloseAdapterCompleteHandler) (
+ OpenP->ProtocolBindingContext,
+ pQoC->Status);
+
+ ndisDeQueueOpenOnAdapter(OpenP, OpenP->AdapterHandle);
+ ndisDeQueueOpenOnProtocol(OpenP, OpenP->ProtocolHandle);
+
+ ndisDereferenceProtocol(OpenP->ProtocolHandle);
+ ndisDereferenceAdapter(OpenP->AdapterHandle);
+ NdisFreeSpinLock(&OpenP->SpinLock);
+
+ //
+ // This sends an IRP_MJ_CLOSE IRP.
+ //
+ ObDereferenceObject((OpenP->FileObject));
+
+ //
+ // Remove from global list
+ //
+ ACQUIRE_SPIN_LOCK(&ndisGlobalOpenListLock, &OldIrql);
+
+ for (ppOpen = &ndisGlobalOpenList;
+ *ppOpen != NULL;
+ ppOpen = &(*ppOpen)->NextGlobalOpen)
+ {
+ if (*ppOpen == pQoC->OpenP)
+ {
+ *ppOpen = pQoC->OpenP->NextGlobalOpen;
+ break;
+ }
+ }
+
+ RELEASE_SPIN_LOCK(&ndisGlobalOpenListLock, OldIrql);
+
+ FREE_POOL(pQoC->OpenP);
+
+ if (pQoC->FreeIt)
+ {
+ FREE_POOL(pQoC);
+ }
+}
+
+
+#undef NdisSend
+
+VOID
+NdisSend(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ )
+{
+ *Status = (((PNDIS_OPEN_BLOCK)NdisBindingHandle)->SendHandler)(
+ ((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacBindingHandle,
+ Packet);
+}
+
+#undef NdisSendPackets
+
+VOID
+NdisSendPackets(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ )
+{
+ (((PNDIS_OPEN_BLOCK)NdisBindingHandle)->SendPacketsHandler)(
+ ((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacBindingHandle,
+ PacketArray,
+ NumberOfPackets);
+}
+
+#undef NdisTransferData
+
+VOID
+NdisTransferData(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ )
+{
+ *Status = (((PNDIS_OPEN_BLOCK)NdisBindingHandle)->TransferDataHandler)(
+ ((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacBindingHandle,
+ MacReceiveContext,
+ ByteOffset,
+ BytesToTransfer,
+ Packet,
+ BytesTransferred);
+}
+
+#undef NdisReset
+
+VOID
+NdisReset(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisBindingHandle
+ )
+{
+ *Status = (((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacHandle->MacCharacteristics.ResetHandler)(
+ ((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacBindingHandle);
+
+}
+
+#undef NdisRequest
+
+VOID
+NdisRequest(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+{
+ *Status = (((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacHandle->MacCharacteristics.RequestHandler)(
+ ((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacBindingHandle,
+ NdisRequest);
+}
+
+BOOLEAN
+NdisReferenceRef(
+ IN PREFERENCE RefP
+ )
+
+/*++
+
+Routine Description:
+
+ Adds a reference to an object.
+
+Arguments:
+
+ RefP - A pointer to the REFERENCE portion of the object.
+
+Return Value:
+
+ TRUE if the reference was added.
+ FALSE if the object was closing.
+
+--*/
+
+{
+ BOOLEAN rc = TRUE;
+ KIRQL OldIrql;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisReferenceRef\n"));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(RefP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("NdisReferenceRef: NULL Reference address\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(RefP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("NdisReferenceRef: Reference not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ }
+ NDIS_ACQUIRE_SPIN_LOCK(&RefP->SpinLock, &OldIrql);
+
+ if (RefP->Closing)
+ {
+ rc = FALSE;
+ }
+ else
+ {
+ ++(RefP->ReferenceCount);
+ }
+
+ NDIS_RELEASE_SPIN_LOCK(&RefP->SpinLock, OldIrql);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisReferenceRef\n"));
+
+ return(rc);
+}
+
+
+BOOLEAN
+NdisDereferenceRef(
+ IN PREFERENCE RefP
+ )
+
+/*++
+
+Routine Description:
+
+ Removes a reference to an object.
+
+Arguments:
+
+ RefP - A pointer to the REFERENCE portion of the object.
+
+Return Value:
+
+ TRUE if the reference count is now 0.
+ FALSE otherwise.
+
+--*/
+
+{
+ BOOLEAN rc = FALSE;
+ KIRQL OldIrql;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisDereferenceRef\n"));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(RefP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("NdisDereferenceRef: NULL Reference address\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(RefP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("NdisDereferenceRef: Reference not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ }
+
+ NDIS_ACQUIRE_SPIN_LOCK(&RefP->SpinLock, &OldIrql);
+
+ --(RefP->ReferenceCount);
+
+ if (RefP->ReferenceCount == 0)
+ {
+ rc = TRUE;
+ }
+
+ NDIS_RELEASE_SPIN_LOCK(&RefP->SpinLock, OldIrql);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisDereferenceRef\n"));
+ return rc;
+}
+
+
+VOID
+NdisInitializeRef(
+ IN PREFERENCE RefP
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize a reference count structure.
+
+Arguments:
+
+ RefP - The structure to be initialized.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisInitializeRef\n"));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(RefP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("NdisInitializeRef: NULL Reference address\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(RefP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("NdisInitializeRef: Reference not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ }
+
+ RefP->Closing = FALSE;
+ RefP->ReferenceCount = 1;
+ NdisAllocateSpinLock(&RefP->SpinLock);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisInitializeRef\n"));
+}
+
+
+BOOLEAN
+NdisCloseRef(
+ IN PREFERENCE RefP
+ )
+
+/*++
+
+Routine Description:
+
+ Closes a reference count structure.
+
+Arguments:
+
+ RefP - The structure to be closed.
+
+Return Value:
+
+ FALSE if it was already closing.
+ TRUE otherwise.
+
+--*/
+
+{
+ KIRQL OldIrql;
+ BOOLEAN rc = TRUE;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisCloseRef\n"));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(RefP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("NdisCloseRef: NULL Reference address\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(RefP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("NdisCloseRef: Reference not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ }
+
+ NDIS_ACQUIRE_SPIN_LOCK(&RefP->SpinLock, &OldIrql);
+
+ if (RefP->Closing)
+ {
+ rc = FALSE;
+ }
+ else RefP->Closing = TRUE;
+
+ NDIS_RELEASE_SPIN_LOCK(&RefP->SpinLock, OldIrql);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisCloseRef\n"));
+ return rc;
+}
+
+
+BOOLEAN
+NdisFinishOpen(
+ IN PNDIS_OPEN_BLOCK OpenP
+ )
+
+/*++
+
+Routine Description:
+
+ Performs the final functions of NdisOpenAdapter. Called when
+ MacOpenAdapter is done.
+
+Arguments:
+
+ OpenP - The open block to finish up.
+
+Return Value:
+
+ FALSE if the adapter or the protocol is closing.
+ TRUE otherwise.
+
+--*/
+
+{
+ //
+ // Add us to the adapter's queue of opens.
+ //
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisFinishOpen\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ (" Protocol %wZ is being bound to Adapter %wZ\n",
+ &(OpenP->ProtocolHandle)->ProtocolCharacteristics.Name,
+ &OpenP->AdapterHandle->AdapterName));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(OpenP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("NdisFinishOpen: Null Open Block\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(OpenP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("NdisFinishOpen: Open Block not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ }
+
+ if (!ndisQueueOpenOnAdapter(OpenP, OpenP->AdapterHandle))
+ {
+ //
+ // The adapter is closing.
+ //
+ // Call MacCloseAdapter(), don't worry about it completing.
+ //
+
+ (OpenP->MacHandle->MacCharacteristics.CloseAdapterHandler) (
+ OpenP->MacBindingHandle);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisFinishOpen\n"));
+ return FALSE;
+ }
+
+
+ //
+ // Add us to the protocol's queue of opens.
+ //
+
+ if (!ndisQueueOpenOnProtocol(OpenP, OpenP->ProtocolHandle))
+ {
+ //
+ // The protocol is closing.
+ //
+ // Call MacCloseAdapter(), don't worry about it completing.
+ //
+
+ (OpenP->MacHandle->MacCharacteristics.CloseAdapterHandler) (
+ OpenP->MacBindingHandle);
+
+ //
+ // Undo the queueing we just did.
+ //
+
+ ndisDeQueueOpenOnAdapter(OpenP, OpenP->AdapterHandle);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisFinishOpen\n"));
+ return FALSE;
+ }
+
+
+ //
+ // Both queueings succeeded.
+ //
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisFinishOpen\n"));
+ return TRUE;
+}
+
+
+NTSTATUS
+ndisCreateIrpHandler(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ The handle for IRP_MJ_CREATE IRPs.
+
+Arguments:
+
+ DeviceObject - The adapter's device object.
+ Irp - The IRP.
+
+Return Value:
+
+ STATUS_SUCCESS if it should be.
+
+--*/
+
+{
+ PIO_STACK_LOCATION IrpSp;
+ PFILE_FULL_EA_INFORMATION IrpEaInfo;
+ PNDIS_USER_OPEN_CONTEXT OpenContext;
+ NTSTATUS Status = STATUS_SUCCESS;
+ PNDIS_ADAPTER_BLOCK AdapterBlock;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ BOOLEAN IsAMiniport;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>ndisCreateIrpHandler\n"));
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(Irp))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ (": Null Irp\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(Irp))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ (": Irp not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ }
+
+ AdapterBlock = (PNDIS_ADAPTER_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1);
+ Miniport = (PNDIS_MINIPORT_BLOCK)AdapterBlock;
+ IsAMiniport = (AdapterBlock->DeviceObject == NULL);
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+ IrpEaInfo = (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
+
+ if (IrpEaInfo == NULL)
+ {
+ //
+ // This is a user-mode open, do whatever.
+ //
+
+ OpenContext = (PNDIS_USER_OPEN_CONTEXT)ALLOC_FROM_POOL(sizeof(NDIS_USER_OPEN_CONTEXT),
+ NDIS_TAG_DEFAULT);
+
+ if (OpenContext == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ OpenContext->DeviceObject = DeviceObject;
+
+ OpenContext->AdapterBlock = AdapterBlock;
+ OpenContext->OidCount = 0;
+ OpenContext->FullOidCount = 0;
+ OpenContext->OidArray = NULL;
+ OpenContext->FullOidArray = NULL;
+
+ IrpSp->FileObject->FsContext = OpenContext;
+ IrpSp->FileObject->FsContext2 = (PVOID)NDIS_OPEN_QUERY_STATISTICS;
+
+ if (IsAMiniport && !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
+ {
+ Status = ndisMQueryOidList(OpenContext, Irp);
+ }
+ else
+ {
+ //
+ // Handle full-macs and 4.1 miniports here
+ //
+ Status = ndisQueryOidList(OpenContext, Irp);
+ }
+
+ if (Status != STATUS_SUCCESS)
+ {
+ FREE_POOL(OpenContext);
+ }
+ else
+ {
+ PnPReferencePackage();
+ }
+ }
+ }
+ else
+ {
+ //
+ // This is an internal open, verify the EA.
+ //
+
+ if ((IrpEaInfo->EaNameLength != sizeof(ndisInternalEaName)) ||
+ (!RtlEqualMemory(IrpEaInfo->EaName, ndisInternalEaName, sizeof(ndisInternalEaName))) ||
+ (IrpEaInfo->EaValueLength != sizeof(ndisInternalEaValue)) ||
+ (!RtlEqualMemory(&IrpEaInfo->EaName[IrpEaInfo->EaNameLength+1],
+ ndisInternalEaValue, sizeof(ndisInternalEaValue))))
+ {
+ //
+ // Something is wrong, reject it.
+ //
+
+ Status = STATUS_UNSUCCESSFUL;
+ }
+ else
+ {
+ //
+ // It checks out, just return success and everything
+ // else is done directly using the device object.
+ //
+
+ IrpSp->FileObject->FsContext = NULL;
+ IrpSp->FileObject->FsContext2 = (PVOID)NDIS_OPEN_INTERNAL;
+ }
+ }
+
+ Irp->IoStatus.Status = Status;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisCreateIrplHandler\n"));
+ return Status;
+}
+
+
+NTSTATUS
+ndisQueryOidList(
+ IN PNDIS_USER_OPEN_CONTEXT OpenContext,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will take care of querying the complete OID
+ list for the MAC and filling in OpenContext->OidArray
+ with the ones that are statistics. It blocks when the
+ MAC pends and so is synchronous.
+
+ NOTE: We also handle co-ndis miniports here.
+
+Arguments:
+
+ OpenContext - The open context.
+ Irp = The IRP that the open was done on (used at completion
+ to distinguish the request).
+
+Return Value:
+
+ STATUS_SUCCESS if it should be.
+
+--*/
+
+{
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PNDIS_COREQ_RESERVED ReqRsvd;
+ NDIS_QUERY_OPEN_REQUEST OpenRequest;
+ NDIS_STATUS NdisStatus;
+ PNDIS_OID TmpBuffer;
+ ULONG TmpBufferLength;
+
+ //
+ // First query the OID list with no buffer, to find out
+ // how big it should be.
+ //
+ INITIALIZE_EVENT(&OpenRequest.Event);
+
+ OpenRequest.Irp = Irp;
+
+ OpenRequest.Request.RequestType = NdisRequestQueryStatistics;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_SUPPORTED_LIST;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBuffer = NULL;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBufferLength = 0;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded = 0;
+ Miniport = (PNDIS_MINIPORT_BLOCK)OpenContext->AdapterBlock;
+
+ if (OpenContext->AdapterBlock->DeviceObject != NULL)
+ {
+ NdisStatus = (OpenContext->AdapterBlock->MacHandle->MacCharacteristics.QueryGlobalStatisticsHandler)(
+ OpenContext->AdapterBlock->MacAdapterContext,
+ &OpenRequest.Request);
+ }
+ else
+ {
+ OpenRequest.Request.RequestType = NdisRequestQueryInformation;
+ ReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(&OpenRequest.Request);
+
+ ReqRsvd->Open = NULL;
+ ReqRsvd->RequestCompleteHandler = NULL;
+ ReqRsvd->VcContext = NULL;
+ ReqRsvd->Flags = COREQ_QUERY_OIDS;
+ ReqRsvd->RealRequest = NULL;
+
+ //
+ // Call the miniport's CoRequest Handler
+ //
+ NdisStatus = (*Miniport->DriverHandle->MiniportCharacteristics.CoRequestHandler)(
+ Miniport->MiniportAdapterContext,
+ NULL,
+ &OpenRequest.Request);
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING)
+ {
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+ WAIT_FOR_OBJECT(&OpenRequest.Event, NULL);
+
+ NdisStatus = OpenRequest.NdisStatus;
+
+ }
+ else if ((NdisStatus != NDIS_STATUS_INVALID_LENGTH) &&
+ (NdisStatus != NDIS_STATUS_BUFFER_TOO_SHORT))
+ {
+ return NdisStatus;
+ }
+
+ //
+ // Now we know how much is needed, allocate temp storage...
+ //
+ TmpBufferLength = OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded;
+ TmpBuffer = ALLOC_FROM_POOL(TmpBufferLength, NDIS_TAG_DEFAULT);
+
+ if (TmpBuffer == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // ...and query the real list.
+ //
+ RESET_EVENT(&OpenRequest.Event);
+
+
+ OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBuffer = TmpBuffer;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBufferLength = TmpBufferLength;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded = 0;
+
+ if (OpenContext->AdapterBlock->DeviceObject != NULL)
+ {
+ NdisStatus = (OpenContext->AdapterBlock->MacHandle->MacCharacteristics.QueryGlobalStatisticsHandler)(
+ OpenContext->AdapterBlock->MacAdapterContext,
+ &OpenRequest.Request);
+ }
+ else
+ {
+ //
+ // Call the miniport's CoRequest Handler
+ //
+ NdisStatus = (*Miniport->DriverHandle->MiniportCharacteristics.CoRequestHandler)(
+ Miniport->MiniportAdapterContext,
+ NULL,
+ &OpenRequest.Request);
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING)
+ {
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+ WAIT_FOR_OBJECT(&OpenRequest.Event, NULL);
+
+ NdisStatus = OpenRequest.NdisStatus;
+ }
+
+ ASSERT (NdisStatus == NDIS_STATUS_SUCCESS);
+
+ NdisStatus = ndisSplitStatisticsOids(OpenContext,
+ TmpBuffer,
+ TmpBufferLength/sizeof(NDIS_OID));
+ FREE_POOL(TmpBuffer);
+
+ return NdisStatus;
+}
+
+
+NDIS_STATUS
+ndisSplitStatisticsOids(
+ IN PNDIS_USER_OPEN_CONTEXT OpenContext,
+ IN PNDIS_OID OidList,
+ IN ULONG NumOids
+ )
+{
+ ULONG i, j;
+
+ //
+ // Go through the buffer, counting the statistics OIDs.
+ //
+ OpenContext->FullOidCount = NumOids;
+ for (i = 0; i < NumOids; i++)
+ {
+ if ((OidList[i] & 0x00ff0000) == 0x00020000)
+ {
+ ++OpenContext->OidCount;
+ }
+ }
+
+ //
+ // Now allocate storage for the stat and non-stat OID arrays.
+ //
+ OpenContext->OidArray = ALLOC_FROM_POOL(OpenContext->OidCount*sizeof(NDIS_OID),
+ NDIS_TAG_DEFAULT);
+ if (OpenContext->OidArray == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ OpenContext->FullOidArray = ALLOC_FROM_POOL(OpenContext->FullOidCount*sizeof(NDIS_OID),
+ NDIS_TAG_DEFAULT);
+ if (OpenContext->FullOidArray == NULL)
+ {
+ FREE_POOL(OpenContext->OidArray);
+ OpenContext->OidArray = NULL;
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Now go through the buffer, copying the statistics and non-stat OIDs separately.
+ //
+ for (i = j = 0; i< NumOids; i++)
+ {
+ if ((OidList[i] & 0x00ff0000) == 0x00020000)
+ {
+ OpenContext->OidArray[j++] = OidList[i];
+ }
+ OpenContext->FullOidArray[i] = OidList[i];
+ }
+
+ ASSERT (j == OpenContext->OidCount);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+#define NDIS_STATISTICS_HEADER_SIZE FIELD_OFFSET(NDIS_STATISTICS_VALUE,Data[0])
+
+VOID
+ndisCancelLogIrp(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION IrpSp;
+ PNDIS_USER_OPEN_CONTEXT OpenContext;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PNDIS_LOG Log;
+ KIRQL OldIrql;
+
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+ OpenContext = IrpSp->FileObject->FsContext;
+ Miniport = (PNDIS_MINIPORT_BLOCK)(OpenContext->AdapterBlock);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ ASSERT (Miniport->Log != NULL);
+ ASSERT (Miniport->Log->Irp == Irp);
+
+ Miniport->Log->Irp = NULL;
+ Irp->IoStatus.Status = STATUS_REQUEST_ABORTED;
+ Irp->IoStatus.Information = 0;
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+}
+
+NTSTATUS
+ndisDeviceControlIrpHandler(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ The handle for IRP_MJ_DEVICE_CONTROL IRPs.
+
+Arguments:
+
+ DeviceObject - The adapter's device object.
+ Irp - The IRP.
+
+Return Value:
+
+ STATUS_SUCCESS if it should be.
+
+--*/
+
+{
+ PIO_STACK_LOCATION IrpSp;
+ PNDIS_USER_OPEN_CONTEXT OpenContext;
+ PNDIS_QUERY_GLOBAL_REQUEST GlobalRequest;
+ PNDIS_QUERY_ALL_REQUEST AllRequest;
+ NDIS_STATUS NdisStatus;
+ UINT CurrentOid;
+ ULONG BytesWritten, BytesWrittenThisOid;
+ PUCHAR Buffer;
+ ULONG BufferLength;
+ NTSTATUS Status = STATUS_SUCCESS;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ BOOLEAN LocalLock;
+ KIRQL OldIrql;
+ PSINGLE_LIST_ENTRY Link;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>ndisDeviceControlIrpHandler\n"));
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(Irp))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ (": Null Irp\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(Irp))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ (": Irp not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ }
+
+ IoMarkIrpPending (Irp);
+ Irp->IoStatus.Status = STATUS_PENDING;
+ Irp->IoStatus.Information = 0;
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ if (IrpSp->FileObject->FsContext2 != (PVOID)NDIS_OPEN_QUERY_STATISTICS)
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ PnPReferencePackage();
+
+ OpenContext = IrpSp->FileObject->FsContext;
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
+ {
+ case IOCTL_NDIS_GET_LOG_DATA:
+
+ //
+ // First verify that we have a miniport. This IOCTL is only
+ // valid for a miniport
+ //
+ if (OpenContext->AdapterBlock->DeviceObject != NULL)
+ {
+ Status = STATUS_UNSUCCESSFUL;
+ break;
+ }
+
+ Miniport = (PNDIS_MINIPORT_BLOCK)(OpenContext->AdapterBlock);
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ {
+ PNDIS_LOG Log;
+ UINT AmtToCopy;
+
+ if ((Log = Miniport->Log) != NULL)
+ {
+ ACQUIRE_SPIN_LOCK_DPC(&Log->LogLock);
+
+ if (Log->CurrentSize != 0)
+ {
+ //
+ // If the InPtr is lagging the OutPtr. then we can simply
+ // copy the data over in one shot.
+ //
+ AmtToCopy = MDL_SIZE(Irp->MdlAddress);
+ if (AmtToCopy > Log->CurrentSize)
+ AmtToCopy = Log->CurrentSize;
+ if ((Log->TotalSize - Log->OutPtr) >= AmtToCopy)
+ {
+ CopyMemory(MDL_ADDRESS(Irp->MdlAddress),
+ Log->LogBuf+Log->OutPtr,
+ AmtToCopy);
+ }
+ else
+ {
+ CopyMemory(MDL_ADDRESS(Irp->MdlAddress),
+ Log->LogBuf+Log->OutPtr,
+ Log->TotalSize-Log->OutPtr);
+ CopyMemory((PUCHAR)MDL_ADDRESS(Irp->MdlAddress)+Log->TotalSize-Log->OutPtr,
+ Log->LogBuf,
+ AmtToCopy - (Log->TotalSize-Log->OutPtr));
+ }
+ Log->CurrentSize -= AmtToCopy;
+ Log->OutPtr += AmtToCopy;
+ if (Log->OutPtr >= Log->TotalSize)
+ Log->OutPtr -= Log->TotalSize;
+ Irp->IoStatus.Information = AmtToCopy;
+ Status = STATUS_SUCCESS;
+ }
+ else if (Log->Irp != NULL)
+ {
+ Status = STATUS_UNSUCCESSFUL;
+ }
+ else
+ {
+ KIRQL OldIrql;
+
+ IoAcquireCancelSpinLock(&OldIrql);
+ IoSetCancelRoutine(Irp, ndisCancelLogIrp);
+ IoReleaseCancelSpinLock(OldIrql);
+ Log->Irp = Irp;
+ Status = STATUS_PENDING;
+ }
+
+ RELEASE_SPIN_LOCK_DPC(&Log->LogLock);
+ }
+ }
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+ break;
+
+ case IOCTL_NDIS_QUERY_GLOBAL_STATS:
+
+ if (!ndisValidOid(OpenContext,
+ *((PULONG)(Irp->AssociatedIrp.SystemBuffer))))
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+ //
+ // Allocate a request.
+ //
+ GlobalRequest = (PNDIS_QUERY_GLOBAL_REQUEST)ALLOC_FROM_POOL(sizeof(NDIS_QUERY_GLOBAL_REQUEST),
+ NDIS_TAG_DEFAULT);
+
+ if (GlobalRequest == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ GlobalRequest->Irp = Irp;
+
+ if (OpenContext->AdapterBlock->DeviceObject == NULL)
+ {
+ Miniport = (PNDIS_MINIPORT_BLOCK)(OpenContext->AdapterBlock);
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
+ {
+ //
+ // Do this for CL miniports only
+ //
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+ LOCK_MINIPORT(Miniport, LocalLock);
+ }
+ }
+ else
+ {
+ Miniport = NULL;
+ }
+
+ //
+ // Fill in the NDIS request.
+ //
+ GlobalRequest->Request.RequestType = NdisRequestQueryStatistics;
+ GlobalRequest->Request.DATA.QUERY_INFORMATION.Oid = *((PULONG)(Irp->AssociatedIrp.SystemBuffer));
+ GlobalRequest->Request.DATA.QUERY_INFORMATION.InformationBuffer = MDL_ADDRESS (Irp->MdlAddress);
+ GlobalRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength = MDL_SIZE (Irp->MdlAddress);
+ GlobalRequest->Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
+ GlobalRequest->Request.DATA.QUERY_INFORMATION.BytesNeeded = 0;
+
+
+ if (Miniport != NULL)
+ {
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
+ {
+ //
+ // Place the request on the queue.
+ //
+ ndisMQueueRequest(Miniport, &GlobalRequest->Request, NULL);
+
+ //
+ // Queue a work item if there is not one already queue'd.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+
+ //
+ // If we were able to grab the local lock then we can do some
+ // deferred processing now.
+ //
+
+ if (LocalLock)
+ {
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+ }
+ else
+ {
+ PNDIS_COREQ_RESERVED ReqRsvd;
+
+ ReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(&GlobalRequest->Request);
+
+ ReqRsvd->Open = NULL;
+ ReqRsvd->RequestCompleteHandler = NULL;
+ ReqRsvd->VcContext = NULL;
+ ReqRsvd->Flags = COREQ_GLOBAL_REQ;
+ ReqRsvd->RealRequest = NULL;
+
+ //
+ // Call the miniport's CoRequest Handler
+ //
+ Status = (*Miniport->DriverHandle->MiniportCharacteristics.CoRequestHandler)(
+ Miniport->MiniportAdapterContext,
+ NULL,
+ &GlobalRequest->Request);
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisMCoRequestComplete(Status,
+ Miniport,
+ &GlobalRequest->Request);
+ }
+ }
+ }
+ else
+ {
+ //
+ // Pass the request to the MAC.
+ //
+
+ NdisStatus = (OpenContext->AdapterBlock->MacHandle->MacCharacteristics.QueryGlobalStatisticsHandler)(
+ OpenContext->AdapterBlock->MacAdapterContext,
+ &GlobalRequest->Request);
+
+ //
+ // NdisCompleteQueryStatistics handles the completion.
+ //
+ if (NdisStatus != NDIS_STATUS_PENDING)
+ {
+ NdisCompleteQueryStatistics(OpenContext->AdapterBlock,
+ &GlobalRequest->Request,
+ NdisStatus);
+ }
+
+ }
+
+ Status = STATUS_PENDING;
+
+ break;
+
+ case IOCTL_NDIS_QUERY_ALL_STATS:
+
+
+ //
+ // Allocate a request.
+ //
+
+ AllRequest = (PNDIS_QUERY_ALL_REQUEST)ALLOC_FROM_POOL(sizeof(NDIS_QUERY_ALL_REQUEST),
+ NDIS_TAG_DEFAULT);
+
+ if (AllRequest == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ if (OpenContext->AdapterBlock->DeviceObject == NULL)
+ {
+ Miniport = (PNDIS_MINIPORT_BLOCK)(OpenContext->AdapterBlock);
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
+ {
+ //
+ // Do this for CL miniports only
+ //
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+ LOCK_MINIPORT(Miniport, LocalLock);
+ }
+ }
+ else
+ {
+ Miniport = NULL;
+ }
+
+ AllRequest->Irp = Irp;
+
+ Buffer = (PUCHAR)MDL_ADDRESS (Irp->MdlAddress);
+ BufferLength = MDL_SIZE (Irp->MdlAddress);
+ BytesWritten = 0;
+
+ INITIALIZE_EVENT(&AllRequest->Event);
+
+ NdisStatus = NDIS_STATUS_SUCCESS;
+
+ for (CurrentOid = 0; CurrentOid<OpenContext->OidCount; CurrentOid++)
+ {
+ //
+ // We need room for an NDIS_STATISTICS_VALUE (OID,
+ // Length, Data).
+ //
+
+ if (BufferLength < (ULONG)NDIS_STATISTICS_HEADER_SIZE)
+ {
+ NdisStatus = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ AllRequest->Request.RequestType = NdisRequestQueryStatistics;
+
+ AllRequest->Request.DATA.QUERY_INFORMATION.Oid = OpenContext->OidArray[CurrentOid];
+ AllRequest->Request.DATA.QUERY_INFORMATION.InformationBuffer = Buffer + NDIS_STATISTICS_HEADER_SIZE;
+ AllRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength = BufferLength - NDIS_STATISTICS_HEADER_SIZE;
+ AllRequest->Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
+ AllRequest->Request.DATA.QUERY_INFORMATION.BytesNeeded = 0;
+
+ if (Miniport != NULL)
+ {
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
+ {
+ //
+ // Queue the request.
+ //
+ ndisMQueueRequest(Miniport, &AllRequest->Request, NULL);
+
+ //
+ // Queue a work item if there is not one already queue'd.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+
+ //
+ // If we were able to grab the local lock then we can do some
+ // deferred processing now.
+ //
+ if (LocalLock)
+ {
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ NdisStatus = NDIS_STATUS_PENDING;
+ }
+ else
+ {
+ PNDIS_COREQ_RESERVED ReqRsvd;
+
+ ReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(&AllRequest->Request);
+
+ ReqRsvd->Open = NULL;
+ ReqRsvd->RequestCompleteHandler = NULL;
+ ReqRsvd->VcContext = NULL;
+ ReqRsvd->Flags = COREQ_QUERY_STATS;
+ ReqRsvd->RealRequest = NULL;
+
+ //
+ // Call the miniport's CoRequest Handler
+ //
+ NdisStatus = (*Miniport->DriverHandle->MiniportCharacteristics.CoRequestHandler)(
+ Miniport->MiniportAdapterContext,
+ NULL,
+ &AllRequest->Request);
+ if (NdisStatus == NDIS_STATUS_PENDING)
+ {
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+ WAIT_FOR_OBJECT(&AllRequest->Event, NULL);
+
+ NdisStatus = AllRequest->NdisStatus;
+ }
+ }
+ }
+ else
+ {
+ NdisStatus = (OpenContext->AdapterBlock->MacHandle->MacCharacteristics.QueryGlobalStatisticsHandler)(
+ OpenContext->AdapterBlock->MacAdapterContext,
+ &AllRequest->Request);
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING)
+ {
+ if ((Miniport != NULL) &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
+ {
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+ }
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+ WAIT_FOR_OBJECT(&AllRequest->Event, NULL);
+
+ NdisStatus = AllRequest->NdisStatus;
+
+ if (Miniport != NULL)
+ {
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+ LOCK_MINIPORT(Miniport, LocalLock);
+ }
+ }
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS)
+ {
+ PNDIS_STATISTICS_VALUE StatisticsValue = (PNDIS_STATISTICS_VALUE)Buffer;
+
+ //
+ // Create the equivalent of an NDIS_STATISTICS_VALUE
+ // element for this OID value (the data itself was
+ // already written in the right place.
+ //
+
+ StatisticsValue->Oid = OpenContext->OidArray[CurrentOid];
+ StatisticsValue->DataLength = AllRequest->Request.DATA.QUERY_INFORMATION.BytesWritten;
+
+ //
+ // Advance our pointers.
+ //
+
+ BytesWrittenThisOid = AllRequest->Request.DATA.QUERY_INFORMATION.BytesWritten +
+ NDIS_STATISTICS_HEADER_SIZE;
+ Buffer += BytesWrittenThisOid;
+ BufferLength -= BytesWrittenThisOid;
+ BytesWritten += BytesWrittenThisOid;
+
+ }
+ else
+ {
+ break;
+ }
+
+ RESET_EVENT(&AllRequest->Event);
+
+ }
+
+ if (Miniport != NULL)
+ {
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+ }
+
+ if (NdisStatus == NDIS_STATUS_INVALID_LENGTH)
+ {
+ Status = STATUS_BUFFER_OVERFLOW;
+ }
+ else if (NdisStatus != NDIS_STATUS_SUCCESS)
+ {
+ Status = STATUS_UNSUCCESSFUL;
+ }
+
+ Irp->IoStatus.Information = BytesWritten;
+ Irp->IoStatus.Status = Status;
+
+ break;
+
+ default:
+
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+
+ }
+
+ PnPDereferencePackage();
+ if (Status != STATUS_PENDING)
+ {
+ IrpSp->Control &= ~SL_PENDING_RETURNED;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ }
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==ndisDeviceControlIrpHandler\n"));
+
+ return Status;
+}
+
+
+BOOLEAN
+ndisValidOid(
+ IN PNDIS_USER_OPEN_CONTEXT OpenContext,
+ IN NDIS_OID Oid
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+ TRUE if OID is valid, FALSE otherwise
+
+--*/
+{
+ UINT i;
+
+ for (i = 0; i < OpenContext->FullOidCount; i++)
+ {
+ if (OpenContext->FullOidArray[i] == Oid)
+ {
+ break;
+ }
+ }
+
+ return (i < OpenContext->FullOidCount);
+}
+
+
+VOID
+NdisCompleteQueryStatistics(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by MACs when they have completed
+ processing of a MacQueryGlobalStatistics call.
+
+Arguments:
+
+ NdisAdapterHandle - The NDIS adapter context.
+ NdisRequest - The request that has been completed.
+ Status - The status of the request.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PNDIS_QUERY_GLOBAL_REQUEST GlobalRequest;
+ PNDIS_QUERY_ALL_REQUEST AllRequest;
+ PNDIS_QUERY_OPEN_REQUEST OpenRequest;
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+
+ //
+ // Rely on the fact that all our request structures start with
+ // the same fields: Irp followed by the NdisRequest.
+ //
+
+ GlobalRequest = CONTAINING_RECORD (NdisRequest, NDIS_QUERY_GLOBAL_REQUEST, Request);
+ Irp = GlobalRequest->Irp;
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ switch (IrpSp->MajorFunction)
+ {
+ case IRP_MJ_CREATE:
+ //
+ // This request is one of the ones made during an open,
+ // while we are trying to determine the OID list. We
+ // set the event we are waiting for, the open code
+ // takes care of the rest.
+ //
+
+ OpenRequest = (PNDIS_QUERY_OPEN_REQUEST)GlobalRequest;
+ OpenRequest->NdisStatus = Status;
+ SET_EVENT(&OpenRequest->Event);
+ break;
+
+ case IRP_MJ_DEVICE_CONTROL:
+ //
+ // This is a real user request, process it as such.
+ //
+
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
+ {
+ case IOCTL_NDIS_QUERY_GLOBAL_STATS:
+ //
+ // A single query, complete the IRP.
+ //
+
+ Irp->IoStatus.Information =
+ NdisRequest->DATA.QUERY_INFORMATION.BytesWritten;
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ }
+ else if (Status == NDIS_STATUS_INVALID_LENGTH)
+ {
+ Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
+ }
+ else
+ {
+ Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+ }
+
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ FREE_POOL(GlobalRequest);
+ break;
+
+ case IOCTL_NDIS_QUERY_ALL_STATS:
+
+ //
+ // An "all" query.
+ //
+
+ AllRequest = (PNDIS_QUERY_ALL_REQUEST)GlobalRequest;
+
+ AllRequest->NdisStatus = Status;
+ SET_EVENT(&AllRequest->Event);
+
+ break;
+ }
+
+ break;
+ }
+}
+
+
+NTSTATUS
+ndisCloseIrpHandler(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ The handle for IRP_MJ_CLOSE IRPs.
+
+Arguments:
+
+ DeviceObject - The adapter's device object.
+ Irp - The IRP.
+
+Return Value:
+
+ STATUS_SUCCESS if it should be.
+
+--*/
+
+{
+ PIO_STACK_LOCATION IrpSp;
+ PNDIS_USER_OPEN_CONTEXT OpenContext;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>ndisCloseIrpHandler\n"));
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(Irp))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ (": Null Irp\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(Irp))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ (": Irp not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ }
+
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ if (IrpSp->FileObject->FsContext2 == (PVOID)NDIS_OPEN_QUERY_STATISTICS)
+ {
+ //
+ // Free the query context.
+ //
+
+ ASSERT (IrpSp->FileObject->FsContext2 == (PVOID)NDIS_OPEN_QUERY_STATISTICS);
+
+ OpenContext = IrpSp->FileObject->FsContext;
+ if (OpenContext->OidArray != NULL)
+ {
+ FREE_POOL(OpenContext->OidArray);
+ }
+ if (OpenContext->FullOidArray != NULL)
+ {
+ FREE_POOL(OpenContext->FullOidArray);
+ }
+ FREE_POOL(OpenContext);
+ PnPDereferencePackage();
+ }
+
+ Irp->IoStatus.Status = Status;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisCloseIrpHandler\n"));
+ return Status;
+}
+
+
+NTSTATUS
+ndisSuccessIrpHandler(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ The "success handler" for any IRPs that we can ignore.
+
+Arguments:
+
+ DeviceObject - The adapter's device object.
+ Irp - The IRP.
+
+Return Value:
+
+ Always STATUS_SUCCESS.
+
+--*/
+
+{
+ DeviceObject; // to avoid "unused formal parameter" warning
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisSuccessIrpHandler\n"));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(Irp))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ (": Null Irp\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(Irp))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ (": Irp not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ }
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisSuccessIrpHandler\n"));
+ return STATUS_SUCCESS;
+}
+
+
+VOID
+ndisKillOpenAndNotifyProtocol(
+ IN PNDIS_OPEN_BLOCK OldOpenP
+ )
+
+/*++
+
+Routine Description:
+
+ Closes an open and notifies the protocol; used when the
+ close is internally generated by the NDIS wrapper (due to
+ a protocol or adapter deregistering with outstanding opens).
+
+Arguments:
+
+ OldOpenP - The open to be closed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Indicate the status to the protocol.
+ //
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>ndisKillOpenAndNotifyProtocol\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ (" Closing Adapter %wZ and notifying Protocol %wZ\n",
+ &OldOpenP->AdapterHandle->AdapterName,
+ &(OldOpenP->ProtocolHandle)->ProtocolCharacteristics.Name));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(OldOpenP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisKillOpenAndNotifyProtocol: Null Open Block\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(OldOpenP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisKillOpenAndNotifyProtocol: Open Block not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ }
+
+ (OldOpenP->ProtocolHandle->ProtocolCharacteristics.StatusHandler)(
+ OldOpenP->ProtocolBindingContext,
+ NDIS_STATUS_CLOSING,
+ NULL,
+ 0); // need real reason here
+
+
+ //
+ // Now KillOpen will do the real work.
+ //
+ if (OldOpenP->AdapterHandle->DeviceObject == NULL)
+ {
+ //
+ // Miniport
+ //
+ (void)ndisMKillOpen(OldOpenP);
+ }
+ else
+ {
+ //
+ // Mac
+ //
+ (void)ndisKillOpen(OldOpenP);
+ }
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==ndisKillOpenAndNotifyProtocol\n"));
+}
+
+
+BOOLEAN
+ndisKillOpen(
+ IN PNDIS_OPEN_BLOCK OldOpenP
+ )
+
+/*++
+
+Routine Description:
+
+ Closes an open. Used when NdisCloseAdapter is called, and also
+ for internally generated closes.
+
+Arguments:
+
+ OldOpenP - The open to be closed.
+
+Return Value:
+
+ TRUE if the open finished, FALSE if it pended.
+
+--*/
+
+{
+ KIRQL OldIrql;
+ PNDIS_OPEN_BLOCK *ppOpen;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>ndisKillOpen\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ (" Closing Adapter %wZ as requested by %wZ\n",
+ &OldOpenP->AdapterHandle->AdapterName,
+ &(OldOpenP->ProtocolHandle)->ProtocolCharacteristics.Name));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(OldOpenP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisKillOpen: Null Open Block\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(OldOpenP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisKillOpen: Open Block not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ }
+
+ ACQUIRE_SPIN_LOCK(&OldOpenP->SpinLock, &OldIrql);
+
+ //
+ // See if this open is already closing.
+ //
+
+ if (OldOpenP->Closing)
+ {
+ RELEASE_SPIN_LOCK(&OldOpenP->SpinLock, OldIrql);
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==ndisKillOpen\n"));
+ return TRUE;
+ }
+
+ //
+ // Indicate to others that this open is closing.
+ //
+
+ OldOpenP->Closing = TRUE;
+ RELEASE_SPIN_LOCK(&OldOpenP->SpinLock, OldIrql);
+
+ //
+ // Inform the MAC.
+ //
+
+ if ((OldOpenP->MacHandle->MacCharacteristics.CloseAdapterHandler)(
+ OldOpenP->MacBindingHandle) == NDIS_STATUS_PENDING)
+ {
+ //
+ // MacCloseAdapter pended, will complete later.
+ //
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==ndisKillOpen\n"));
+ return FALSE;
+ }
+
+ //
+ // Remove the reference for this open.
+ //
+ ObDereferenceObject(OldOpenP->FileObject);
+
+ //
+ // Remove us from the adapter and protocol open queues.
+ //
+
+ ndisDeQueueOpenOnAdapter(OldOpenP, OldOpenP->AdapterHandle);
+ ndisDeQueueOpenOnProtocol(OldOpenP, OldOpenP->ProtocolHandle);
+
+ //
+ // MacCloseAdapter did not pend; we ignore the return code.
+ //
+
+ ndisDereferenceProtocol(OldOpenP->ProtocolHandle);
+ ndisDereferenceAdapter(OldOpenP->AdapterHandle);
+
+ NdisFreeSpinLock(&OldOpenP->SpinLock);
+
+ //
+ // Remove from global open list
+ //
+ ACQUIRE_SPIN_LOCK(&ndisGlobalOpenListLock, &OldIrql);
+
+ for (ppOpen = &ndisGlobalOpenList;
+ *ppOpen != NULL;
+ ppOpen = &(*ppOpen)->NextGlobalOpen)
+ {
+ if (*ppOpen == OldOpenP)
+ {
+ *ppOpen = OldOpenP->NextGlobalOpen;
+ break;
+ }
+ }
+
+ ASSERT (*ppOpen == OldOpenP->NextGlobalOpen);
+
+ RELEASE_SPIN_LOCK(&ndisGlobalOpenListLock, OldIrql);
+
+ FREE_POOL(OldOpenP);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==ndisKillOpen\n"));
+ return TRUE;
+}
+
+
+BOOLEAN
+ndisQueueAdapterOnMac(
+ IN PNDIS_ADAPTER_BLOCK AdaptP,
+ IN PNDIS_MAC_BLOCK MacP
+ )
+
+/*++
+
+Routine Description:
+
+ Adds an adapter to a list of adapters for a MAC.
+
+Arguments:
+
+ AdaptP - The adapter block to queue.
+ MacP - The MAC block to queue it to.
+
+Return Value:
+
+ FALSE if the MAC is closing.
+ TRUE otherwise.
+
+--*/
+
+{
+ KIRQL OldIrql;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>ndisQueueAdapterOnMac\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ (" Adapter %wZ being added to MAC list\n",
+ &AdaptP->MacHandle->MacCharacteristics.Name));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ BOOLEAN f = FALSE;
+ if (DbgIsNull(AdaptP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisQueueAdapterOnMac: Null Adapter Block\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(AdaptP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisQueueAdapterOnMac: Adapter Block not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(MacP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisQueueAdapterOnMac: Null Mac Block\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(MacP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisQueueAdapterOnMac: Mac Block not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (f)
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ NDIS_ACQUIRE_SPIN_LOCK(&MacP->Ref.SpinLock, &OldIrql);
+
+ //
+ // Make sure the MAC is not closing.
+ //
+
+ if (MacP->Ref.Closing)
+ {
+ NDIS_RELEASE_SPIN_LOCK(&MacP->Ref.SpinLock, OldIrql);
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==ndisQueueAdapterOnMac\n"));
+ return FALSE;
+ }
+
+
+ //
+ // Add this adapter at the head of the queue
+ //
+
+ AdaptP->NextAdapter = MacP->AdapterQueue;
+ MacP->AdapterQueue = AdaptP;
+
+ NDIS_RELEASE_SPIN_LOCK(&MacP->Ref.SpinLock, OldIrql);
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==ndisQueueAdapterOnMac\n"));
+ return TRUE;
+}
+
+
+VOID
+ndisDeQueueAdapterOnMac(
+ IN PNDIS_ADAPTER_BLOCK AdaptP,
+ IN PNDIS_MAC_BLOCK MacP
+ )
+
+/*++
+
+Routine Description:
+
+ Removes an adapter from a list of adapters for a MAC.
+
+Arguments:
+
+ AdaptP - The adapter block to dequeue.
+ MacP - The MAC block to dequeue it from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ KIRQL OldIrql;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>ndisDeQueueAdapterOnMac\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ (" Adapter %wZ being removed from MAC list\n",
+ &AdaptP->MacHandle->MacCharacteristics.Name));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ BOOLEAN f = FALSE;
+
+ if (DbgIsNull(AdaptP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisDeQueueAdapterOnMac: Null Adapter Block\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(AdaptP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisDeQueueAdapterOnMac: Adapter Block not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(MacP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisDeQueueAdapterOnMac: Null Mac Block\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(MacP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisDeQueueAdapterOnMac: Mac Block not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (f)
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ NDIS_ACQUIRE_SPIN_LOCK(&MacP->Ref.SpinLock, &OldIrql);
+
+ //
+ // Find the MAC on the queue, and remove it.
+ //
+
+ if (MacP->AdapterQueue == AdaptP)
+ {
+ MacP->AdapterQueue = AdaptP->NextAdapter;
+ }
+ else
+ {
+ PNDIS_ADAPTER_BLOCK MP = MacP->AdapterQueue;
+
+ while (MP->NextAdapter != AdaptP)
+ {
+ MP = MP->NextAdapter;
+ }
+
+ MP->NextAdapter = MP->NextAdapter->NextAdapter;
+ }
+
+ NDIS_RELEASE_SPIN_LOCK(&MacP->Ref.SpinLock, OldIrql);
+
+ if (MacP->Unloading && (MacP->AdapterQueue == (PNDIS_ADAPTER_BLOCK)NULL))
+ {
+ SET_EVENT(&MacP->AdaptersRemovedEvent);
+
+ }
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==ndisDeQueueAdapterOnMac\n"));
+}
+
+
+VOID
+ndisKillAdapter(
+ IN PNDIS_ADAPTER_BLOCK OldAdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ Removes an adapter. Called by NdisDeregisterAdapter and also
+ for internally generated deregistrations.
+
+Arguments:
+
+ OldAdaptP - The adapter to be removed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // If the adapter is already closing, return.
+ //
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>ndisKillAdapter\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ (" Removing Adapter %s\n",OldAdaptP->AdapterName.Buffer));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(OldAdaptP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisKillAdapter: Null Adapter Block\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(OldAdaptP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisKillAdapter: Adapter Block not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ }
+ if (!NdisCloseRef(&OldAdaptP->Ref))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==ndisKillAdapter\n"));
+ return;
+ }
+
+
+ //
+ // Kill all the opens for this adapter.
+ //
+
+ while (OldAdaptP->OpenQueue != (PNDIS_OPEN_BLOCK)NULL)
+ {
+ //
+ // This removes it from the adapter's OpenQueue etc.
+ //
+
+ ndisKillOpenAndNotifyProtocol(OldAdaptP->OpenQueue);
+ }
+
+
+ //
+ // Remove the adapter from the MAC's list.
+ //
+
+ ndisDeQueueAdapterOnMac(OldAdaptP, OldAdaptP->MacHandle);
+
+ ndisDereferenceAdapter(OldAdaptP);
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==ndisKillAdapter\n"));
+}
+
+
+VOID
+ndisDereferenceAdapter(
+ IN PNDIS_ADAPTER_BLOCK AdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ Dereferences an adapter. If the reference count goes to zero,
+ it frees resources associated with the adapter.
+
+Arguments:
+
+ AdaptP - The adapter to be dereferenced.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if (NdisDereferenceRef(&AdaptP->Ref))
+ {
+ //
+ // Free resource memory
+ //
+
+ if (AdaptP->Resources != NULL)
+ {
+ NdisReleaseAdapterResources(AdaptP);
+ FREE_POOL(AdaptP->Resources);
+ }
+
+ FREE_POOL(AdaptP->AdapterName.Buffer);
+
+ if (AdaptP->Master)
+ {
+ UINT i;
+ ULONG MapRegistersPerChannel =
+ ((AdaptP->MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2;
+ KIRQL OldIrql;
+
+ RAISE_IRQL_TO_DISPATCH(&OldIrql);
+
+ for (i=0; i<AdaptP->PhysicalMapRegistersNeeded; i++)
+ {
+ IoFreeMapRegisters(
+ AdaptP->SystemAdapterObject,
+ AdaptP->MapRegisters[i].MapRegister,
+ MapRegistersPerChannel);
+ }
+
+ LOWER_IRQL(OldIrql);
+ }
+
+ if ((AdaptP->NumberOfPorts > 0) && AdaptP->InitialPortMapped)
+ {
+ MmUnmapIoSpace (AdaptP->InitialPortMapping, AdaptP->NumberOfPorts);
+ }
+
+ //
+ // Delete the global db entry
+ //
+ if (AdaptP->BusId != 0)
+ {
+ ndisDeleteGlobalDb(AdaptP->BusType,
+ AdaptP->BusId,
+ AdaptP->BusNumber,
+ AdaptP->SlotNumber);
+ }
+
+ ndisDereferenceMac(AdaptP->MacHandle);
+ IoDeleteDevice(AdaptP->DeviceObject);
+ }
+}
+
+
+BOOLEAN
+ndisQueueOpenOnAdapter(
+ IN PNDIS_OPEN_BLOCK OpenP,
+ IN PNDIS_ADAPTER_BLOCK AdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ Adds an open to a list of opens for an adapter.
+
+Arguments:
+
+ OpenP - The open block to queue.
+ AdaptP - The adapter block to queue it to.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ KIRQL OldIrql;
+
+ // attach ourselves to the adapter object linked list of opens
+ NDIS_ACQUIRE_SPIN_LOCK(&AdaptP->Ref.SpinLock, &OldIrql);
+
+ //
+ // Make sure the adapter is not closing.
+ //
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisQueueAdapterOnAdapter\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ (" Open being added to list for Adapter %s\n",AdaptP->AdapterName.Buffer));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ BOOLEAN f = FALSE;
+ if (DbgIsNull(OpenP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisQueueOpenOnAdapter: Null Open Block\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(OpenP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisQueueOpenOnAdapter: Open Block not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(AdaptP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisQueueOpenOnAdapter: Null Adapter Block\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(AdaptP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisQueueOpenOnAdapter: Adapter Block not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (f)
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ if (AdaptP->Ref.Closing)
+ {
+ NDIS_RELEASE_SPIN_LOCK(&AdaptP->Ref.SpinLock, OldIrql);
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisQueueAdapterOnAdapter\n"));
+ return FALSE;
+ }
+
+
+ //
+ // Attach this open at the head of the queue.
+ //
+
+ OpenP->AdapterNextOpen = AdaptP->OpenQueue;
+ AdaptP->OpenQueue = OpenP;
+
+
+ NDIS_RELEASE_SPIN_LOCK(&AdaptP->Ref.SpinLock, OldIrql);
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisQueueAdapterOnAdapter\n"));
+ return TRUE;
+}
+
+
+VOID
+ndisDeQueueOpenOnAdapter(
+ IN PNDIS_OPEN_BLOCK OpenP,
+ IN PNDIS_ADAPTER_BLOCK AdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ Removes an open from a list of opens for an adapter.
+
+Arguments:
+
+ OpenP - The open block to dequeue.
+ AdaptP - The adapter block to dequeue it from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ KIRQL OldIrql;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisDeQueueAdapterOnAdapter\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ (" Open being removed from list for Adapter %s\n",AdaptP->AdapterName.Buffer));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ BOOLEAN f = FALSE;
+ if (DbgIsNull(OpenP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisDeQueueOpenOnAdapter: Null Open Block\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(OpenP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisDeQueueOpenOnAdapter: Open Block not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(AdaptP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisDeQueueOpenOnAdapter: Null Adapter Block\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(AdaptP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisDeQueueOpenOnAdapter: Adapter Block not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (f)
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+
+ NDIS_ACQUIRE_SPIN_LOCK(&AdaptP->Ref.SpinLock, &OldIrql);
+ //
+ // Find the open on the queue, and remove it.
+ //
+
+ if (AdaptP->OpenQueue == OpenP)
+ {
+ AdaptP->OpenQueue = OpenP->AdapterNextOpen;
+ }
+ else
+ {
+ PNDIS_OPEN_BLOCK AP = AdaptP->OpenQueue;
+
+ while (AP->AdapterNextOpen != OpenP)
+ {
+ AP = AP->AdapterNextOpen;
+ }
+
+ AP->AdapterNextOpen = AP->AdapterNextOpen->AdapterNextOpen;
+ }
+
+ NDIS_RELEASE_SPIN_LOCK(&AdaptP->Ref.SpinLock, OldIrql);
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisDeQueueAdapterOnAdapter\n"));
+}
+
+
+VOID
+ndisDereferenceMac(
+ IN PNDIS_MAC_BLOCK MacP
+ )
+/*++
+
+Routine Description:
+
+ Removes a reference from the mac, deleting it if the count goes to 0.
+
+Arguments:
+
+ MacP - The Mac block to dereference.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ KIRQL OldIrql;
+
+ if (NdisDereferenceRef(&(MacP)->Ref))
+ {
+ //
+ // Remove it from the global list.
+ //
+
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+
+ if (ndisMacDriverList == MacP)
+ {
+ ndisMacDriverList = MacP->NextMac;
+ }
+ else
+ {
+ PNDIS_MAC_BLOCK TmpMacP = ndisMacDriverList;
+
+ while(TmpMacP->NextMac != MacP)
+ {
+ TmpMacP = TmpMacP->NextMac;
+ }
+
+ TmpMacP->NextMac = TmpMacP->NextMac->NextMac;
+ }
+
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ if (MacP->PciAssignedResources != NULL)
+ {
+ FREE_POOL(MacP->PciAssignedResources);
+ }
+
+ FREE_POOL(MacP);
+ }
+}
+
+
+//
+// Stubs to compile with Ndis 3.0 kernel.
+//
+
+NDIS_STATUS
+EthAddFilterAddress()
+{
+ return NDIS_STATUS_FAILURE;
+}
+
+NDIS_STATUS
+EthDeleteFilterAddress()
+{
+ return NDIS_STATUS_FAILURE;
+}
+
+NDIS_STATUS
+NdisInitializePacketPool()
+{
+ return NDIS_STATUS_FAILURE;
+}
+
+
+
+NDIS_STATUS
+ndisUnloadMac(
+ IN PNDIS_ADAPTER_BLOCK Mac
+ )
+/*++
+
+Routine Description:
+
+ Unbind all protocols from this mac and finally unload it.
+
+Arguments:
+
+ Mac - The Mac to unload.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ KIRQL OldIrql;
+ PNDIS_OPEN_BLOCK Open;
+ NDIS_BIND_CONTEXT UnbindContext;
+ NDIS_STATUS UnbindStatus;
+
+ //
+ // Walk the list of open bindings on this mac and ask the protocols to
+ // unbind from them. For down-level protocols, DEVICE A WAY TO HANDLE THEM.
+ //
+ NDIS_ACQUIRE_SPIN_LOCK(&Mac->Ref.SpinLock, &OldIrql);
+
+ next:
+ for (Open = Mac->OpenQueue;
+ Open != NULL;
+ Open = Open->NextGlobalOpen)
+ {
+ if (!Open->Closing && !Open->Unloading &&
+ (Open->ProtocolHandle->ProtocolCharacteristics.UnbindAdapterHandler != NULL))
+ {
+ Open->Unloading = TRUE;
+ break;
+ }
+ }
+
+ if (Open != NULL)
+ {
+ NDIS_RELEASE_SPIN_LOCK(&Mac->Ref.SpinLock, OldIrql);
+
+ INITIALIZE_EVENT(&UnbindContext.Event);
+
+ WAIT_FOR_OBJECT(&Open->ProtocolHandle->Mutex, NULL);
+
+ (*Open->ProtocolHandle->ProtocolCharacteristics.UnbindAdapterHandler)(
+ &UnbindStatus,
+ Open->ProtocolBindingContext,
+ &UnbindContext);
+
+ if (UnbindStatus == NDIS_STATUS_PENDING)
+ {
+ WAIT_FOR_OBJECT(&UnbindContext.Event, NULL);
+ }
+
+ RELEASE_MUTEX(&Open->ProtocolHandle->Mutex);
+
+ NDIS_ACQUIRE_SPIN_LOCK(&Mac->Ref.SpinLock, &OldIrql);
+
+ goto next;
+ }
+
+ NDIS_RELEASE_SPIN_LOCK(&Mac->Ref.SpinLock, OldIrql);
+
+ //
+ // The halt handler must be called when the last reference
+ // on the driver block goes away
+ //
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+NDIS_STATUS
+ndisTranslateMacName(
+ IN PNDIS_ADAPTER_BLOCK Mac,
+ IN PUCHAR Buffer,
+ IN UINT BufferLength,
+ OUT PUINT AmountCopied
+
+ )
+/*++
+
+Routine Description:
+
+ Calls the PnP protocols to enumerate PnP ids for the given miniport.
+
+Arguments:
+
+ Mac - The Mac in question.
+ Buffer, BufferLength - Buffer for a list of PnP Ids.
+ AmountCopied - How much buffer was used up.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ KIRQL OldIrql;
+ PNDIS_OPEN_BLOCK Open;
+ NDIS_STATUS Status;
+ UINT AmtCopied = 0, TotalAmtCopied = 0;
+
+ //
+ // Walk the list of open bindings on this mac and ask the protocols to
+ // unbind from them. For down-level protocols, DEVICE A WAY TO HANDLE THEM.
+ //
+ NDIS_ACQUIRE_SPIN_LOCK(&Mac->Ref.SpinLock, &OldIrql);
+
+ for (Open = Mac->OpenQueue;
+ Open != NULL;
+ Open = Open->NextGlobalOpen)
+ {
+ if (!Open->Closing && !Open->Unloading &&
+ (Open->ProtocolHandle->ProtocolCharacteristics.TranslateHandler != NULL))
+ {
+ break;
+ }
+ }
+
+ if (Open != NULL)
+ {
+ NDIS_RELEASE_SPIN_LOCK(&Mac->Ref.SpinLock, OldIrql);
+
+ (*Open->ProtocolHandle->ProtocolCharacteristics.TranslateHandler)(
+ &Status,
+ Open->ProtocolBindingContext,
+ (PNET_PNP_ID)(Buffer + TotalAmtCopied),
+ BufferLength - TotalAmtCopied,
+ &AmtCopied);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ TotalAmtCopied += AmtCopied;
+ }
+
+ NDIS_ACQUIRE_SPIN_LOCK(&Mac->Ref.SpinLock, &OldIrql);
+ }
+
+ NDIS_RELEASE_SPIN_LOCK(&Mac->Ref.SpinLock, OldIrql);
+
+ *AmountCopied = TotalAmtCopied;
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+#if defined(_ALPHA_)
+
+VOID
+NdisCreateLookaheadBufferFromSharedMemory(
+ IN PVOID pSharedMemory,
+ IN UINT LookaheadLength,
+ OUT PVOID * pLookaheadBuffer
+ )
+/*++
+
+Routine Description:
+
+ This routine creates a lookahead buffer from a pointer to shared
+ RAM because some architectures (like ALPHA) do not allow access
+ through a pointer to shared ram.
+
+Arguments:
+
+ pSharedMemory - Pointer to shared ram space.
+
+ LookaheadLength - Amount of Lookahead to copy.
+
+ pLookaheadBuffer - Pointer to host memory space with a copy of the
+ stuff in pSharedMemory.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ KIRQL OldIrql;
+ PNDIS_LOOKAHEAD_ELEMENT TmpElement;
+
+ ACQUIRE_SPIN_LOCK(&ndisLookaheadBufferLock, &OldIrql);
+
+ if (ndisLookaheadBufferLength < (LookaheadLength +
+ sizeof(NDIS_LOOKAHEAD_ELEMENT)))
+ {
+ //
+ // Free current list
+ //
+ while (ndisLookaheadBufferList != NULL)
+ {
+ TmpElement = ndisLookaheadBufferList;
+ ndisLookaheadBufferList = ndisLookaheadBufferList->Next;
+
+ FREE_POOL(TmpElement);
+ }
+
+ ndisLookaheadBufferLength = LookaheadLength +
+ sizeof(NDIS_LOOKAHEAD_ELEMENT);
+ }
+
+ if (ndisLookaheadBufferList == NULL)
+ {
+ ndisLookaheadBufferList = (PNDIS_LOOKAHEAD_ELEMENT)ALLOC_FROM_POOL(ndisLookaheadBufferLength,
+ NDIS_TAG_LA_BUF);
+
+ if (ndisLookaheadBufferList == NULL)
+ {
+ *pLookaheadBuffer = NULL;
+ RELEASE_SPIN_LOCK(&ndisLookaheadBufferLock, OldIrql);
+ return;
+ }
+
+ ndisLookaheadBufferList->Next = NULL;
+ ndisLookaheadBufferList->Length = ndisLookaheadBufferLength;
+ }
+
+
+ //
+ // Get the buffer
+ //
+
+ *pLookaheadBuffer = (ndisLookaheadBufferList + 1);
+ ndisLookaheadBufferList = ndisLookaheadBufferList->Next;
+
+ RELEASE_SPIN_LOCK(&ndisLookaheadBufferLock, OldIrql);
+
+ //
+ // Copy the stuff across
+ //
+
+ READ_REGISTER_BUFFER_UCHAR(pSharedMemory, *pLookaheadBuffer, LookaheadLength);
+}
+
+
+VOID
+NdisDestroyLookaheadBufferFromSharedMemory(
+ IN PVOID pLookaheadBuffer
+ )
+/*++
+
+Routine Description:
+
+ This routine returns resources associated with a lookahead buffer.
+
+Arguments:
+
+ pLookaheadBuffer - Lookahead buffer created by
+ CreateLookaheadBufferFromSharedMemory.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_LOOKAHEAD_ELEMENT Element = (PNDIS_LOOKAHEAD_ELEMENT)pLookaheadBuffer;
+ KIRQL OldIrql;
+
+ Element--;
+
+ if (Element->Length != ndisLookaheadBufferLength)
+ {
+ FREE_POOL(Element);
+ }
+ else
+ {
+ ACQUIRE_SPIN_LOCK(&ndisLookaheadBufferLock, &OldIrql);
+
+ Element->Next = ndisLookaheadBufferList;
+ ndisLookaheadBufferList = Element;
+
+ RELEASE_SPIN_LOCK(&ndisLookaheadBufferLock, OldIrql);
+ }
+}
+
+#endif // _ALPHA_
+
diff --git a/private/ntos/ndis/ndis40/mac.h b/private/ntos/ndis/ndis40/mac.h
new file mode 100644
index 000000000..a46096e23
--- /dev/null
+++ b/private/ntos/ndis/ndis40/mac.h
@@ -0,0 +1,48 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ mac.h
+
+Abstract:
+
+ NDIS wrapper definitions
+
+Author:
+
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ Jun-95 Jameel Hyder Split up from a monolithic file
+--*/
+
+//
+// The following are counters used for debugging
+//
+
+extern PNDIS_MAC_BLOCK ndisMacDriverList;
+extern const NDIS_PHYSICAL_ADDRESS HighestAcceptableMax;
+extern ULONG ndisDmaAlignment;
+
+//
+// For tracking memory allocated for shared memory
+//
+extern ERESOURCE SharedMemoryResource;
+
+//
+// For tracking on NT 3.1 protocols that do not use any of the filter packages.
+//
+extern PNDIS_OPEN_BLOCK ndisGlobalOpenList;
+extern KSPIN_LOCK ndisGlobalOpenListLock;
+extern KSPIN_LOCK ndisLookaheadBufferLock;
+extern ULONG ndisLookaheadBufferLength;
+#if defined(_ALPHA_)
+extern PNDIS_LOOKAHEAD_ELEMENT ndisLookaheadBufferList;
+#endif
+
diff --git a/private/ntos/ndis/ndis40/makefile b/private/ntos/ndis/ndis40/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/ndis40/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/ndis40/makefile.inc b/private/ntos/ndis/ndis40/makefile.inc
new file mode 100644
index 000000000..bc3f05082
--- /dev/null
+++ b/private/ntos/ndis/ndis40/makefile.inc
@@ -0,0 +1,11 @@
+obj\i386\ndis.def: ndis.src
+ cl386 /EP -Di386 $(C_DEFINES) $(386_DBG_DEFINES) ndis.src > obj\i386\ndis.def
+
+obj\mips\ndis.def: ndis.src
+ rcpp -P -f ndis.src -DMIPS=1 $(C_DEFINES) $(MIPS_DBG_DEFINES) -g obj\mips\ndis.def
+
+obj\ppc\ndis.def: ndis.src
+ rcpp -P -f ndis.src -DPPC=1 $(C_DEFINES) $(PPC_DBG_DEFINES) -g obj\ppc\ndis.def
+
+obj\alpha\ndis.def: ndis.src
+ rcpp -P -f ndis.src -DALPHA=1 $(C_DEFINES) $(ALPHA_DBG_DEFINES) -g obj\alpha\ndis.def
diff --git a/private/ntos/ndis/ndis40/mini.h b/private/ntos/ndis/ndis40/mini.h
new file mode 100644
index 000000000..e210962d5
--- /dev/null
+++ b/private/ntos/ndis/ndis40/mini.h
@@ -0,0 +1,251 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ mini.h
+
+Abstract:
+
+ NDIS miniport wrapper definitions
+
+Author:
+
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ Jun-95 Jameel Hyder Split up from a monolithic file
+--*/
+
+#ifndef __MINI_H
+#define __MINI_H
+
+//
+// Macros for setting, clearing, and testing bits in the Miniport Flags.
+//
+#define MINIPORT_SET_FLAG(m, f) ((m)->Flags |= (f))
+#define MINIPORT_CLEAR_FLAG(m, f) ((m)->Flags &= ~(f))
+#define MINIPORT_TEST_FLAG(m, f) (((m)->Flags & (f)) != 0)
+
+#define MINIPORT_SET_SEND_FLAG(m, f) ((m)->SendFlags |= (f))
+#define MINIPORT_CLEAR_SEND_FLAG(m, f) ((m)->SendFlags &= ~(f))
+#define MINIPORT_TEST_SEND_FLAG(m, f) (((m)->SendFlags & (f)) != 0)
+
+//
+// Flags for packet information.
+//
+#define MINIPORT_SET_PACKET_FLAG(p, f) ((p)->Private.NdisPacketFlags |= (f))
+#define MINIPORT_CLEAR_PACKET_FLAG(p, f) ((p)->Private.NdisPacketFlags &= ~(f))
+#define MINIPORT_TEST_PACKET_FLAG(p, f) (((p)->Private.NdisPacketFlags & (f)) != 0)
+
+#define fPACKET_HAS_BEEN_LOOPED_BACK 0x01
+#define fPACKET_HAS_TIMED_OUT 0x02
+#define fPACKET_IS_IN_NDIS 0x04
+
+
+#define NDIS_STATISTICS_HEADER_SIZE FIELD_OFFSET(NDIS_STATISTICS_VALUE,Data[0])
+
+//
+// Timeout values
+//
+#define NDIS_MINIPORT_WAKEUP_TIMEOUT 2000 // Wakeup DPC
+#define NDIS_MINIPORT_DEFERRED_TIMEOUT 15 // Deferred timer
+#define NDIS_MINIPORT_TR_RESET_TIMEOUT 15 // Number of WakeUps per reset attempt
+
+//
+// Internal definitions
+//
+typedef struct _NDIS_PACKET_RESERVED
+{
+ PNDIS_PACKET Next;
+ PNDIS_M_OPEN_BLOCK Open;
+} NDIS_PACKET_RESERVED, *PNDIS_PACKET_RESERVED;
+
+
+#define PNDIS_RESERVED_FROM_PNDIS_PACKET(_packet) \
+ ((PNDIS_PACKET_RESERVED)((_packet)->WrapperReserved))
+
+//
+// This structure is used by IndicatePacket/ReturnPacket code
+// to keep track of references.
+//
+typedef struct _NDIS_PACKET_REFERENCE
+{
+ PNDIS_MINIPORT_BLOCK Miniport;
+ union
+ {
+ UINT RefCount;
+ PNDIS_PACKET NextPacket;
+ };
+} NDIS_PACKET_REFERENCE, *PNDIS_PACKET_REFERENCE;
+
+#define PNDIS_REFERENCE_FROM_PNDIS_PACKET(_packet) \
+ ((PNDIS_PACKET_REFERENCE)((_packet)->WrapperReserved))
+
+//
+// Used by the NdisCoRequest api to keep context information in the Request->NdisReserved
+//
+typedef struct _NDIS_COREQ_RESERVED
+{
+ union
+ {
+ REQUEST_COMPLETE_HANDLER RequestCompleteHandler;
+ CO_REQUEST_COMPLETE_HANDLER CoRequestCompleteHandler;
+ };
+ NDIS_HANDLE VcContext;
+ union
+ {
+ NDIS_HANDLE AfContext;
+ PNDIS_M_OPEN_BLOCK Open;
+ };
+ NDIS_HANDLE PartyContext;
+ ULONG Flags;
+ PNDIS_REQUEST RealRequest;
+} NDIS_COREQ_RESERVED, *PNDIS_COREQ_RESERVED;
+
+#define COREQ_DOWNLEVEL 0x00000001
+#define COREQ_GLOBAL_REQ 0x00000002
+#define COREQ_QUERY_OIDS 0x00000004
+#define COREQ_QUERY_STATS 0x00000008
+#define COREQ_QUERY_SET 0x00000010
+
+#define PNDIS_COREQ_RESERVED_FROM_REQUEST(_request) \
+ (PNDIS_COREQ_RESERVED)((_request)->NdisReserved)
+
+#define MINIPORT_ENABLE_INTERRUPT(_M_) \
+{ \
+ if ((_M_)->EnableInterruptHandler != NULL) \
+ { \
+ ((_M_)->EnableInterruptHandler)((_M_)->MiniportAdapterContext); \
+ } \
+}
+
+#define MINIPORT_SYNC_ENABLE_INTERRUPT(_M_) \
+{ \
+ if ((_M_)->EnableInterruptHandler != NULL) \
+ { \
+ SYNC_WITH_ISR(((_M_))->Interrupt->InterruptObject, \
+ ((_M_)->EnableInterruptHandler), \
+ (_M_)->MiniportAdapterContext); \
+ } \
+}
+
+#define MINIPORT_DISABLE_INTERRUPT(_M_) \
+{ \
+ ASSERT((_M_)->DisableInterruptHandler != NULL); \
+ ((_M_)->DriverHandle->MiniportCharacteristics.DisableInterruptHandler)( \
+ (_M_)->MiniportAdapterContext); \
+}
+
+#define MINIPORT_SYNC_DISABLE_INTERRUPT(_M_) \
+{ \
+ if ((_M_)->DisableInterruptHandler != NULL) \
+ { \
+ SYNC_WITH_ISR(((_M_))->Interrupt->InterruptObject, \
+ ((_M_)->DisableInterruptHandler), \
+ (_M_)->MiniportAdapterContext); \
+ } \
+}
+
+#define CHECK_FOR_NORMAL_INTERRUPTS(_M_) \
+ if ((((_M_)->Flags & (fMINIPORT_HALTING | fMINIPORT_IN_INITIALIZE)) == 0)&& \
+ ((_M_)->Interrupt != NULL) && \
+ !(_M_)->Interrupt->IsrRequested && \
+ !(_M_)->Interrupt->SharedInterrupt) \
+ { \
+ (_M_)->Flags |= fMINIPORT_NORMAL_INTERRUPTS; \
+ } \
+ else \
+ { \
+ (_M_)->Flags &= ~fMINIPORT_NORMAL_INTERRUPTS; \
+ }
+
+
+#define EXPERIMENTAL_SIZE 4
+extern PNDIS_M_DRIVER_BLOCK ndisMiniDriverList;
+extern KSPIN_LOCK ndisDriverListLock;
+extern NDIS_MEDIUM * ndisMediumArray,
+ ndisMediumBuffer[NdisMediumMax + EXPERIMENTAL_SIZE];
+extern UINT ndisMediumArraySize, ndisMediumArrayMaxSize;
+
+//
+// Filter package callback handlers
+//
+#define PNDIS_M_OPEN_FROM_BINDING_HANDLE(_handle) ((PNDIS_M_OPEN_BLOCK)(_handle))
+
+typedef
+NDIS_STATUS
+(*WAN_RECEIVE_HANDLER) (
+ IN NDIS_HANDLE NdisLinkContext,
+ IN PUCHAR Packet,
+ IN ULONG PacketSize
+ );
+
+typedef
+NDIS_STATUS
+(*PNDIS_M_WAN_SEND)(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE NdisLinkHandle,
+ IN PVOID Packet
+ );
+
+VOID
+ndisLastCountRemovedFunction(
+ IN struct _KDPC *Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+
+typedef struct _AsyncWorkItem
+{
+ WORK_QUEUE_ITEM ExWorkItem;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ ULONG Length;
+ BOOLEAN Cached;
+ PVOID VAddr;
+ PVOID Context;
+ NDIS_PHYSICAL_ADDRESS PhyAddr;
+} ASYNC_WORKITEM, *PASYNC_WORKITEM;
+
+
+VOID
+ndisMQueuedAllocateSharedHandler(
+ IN PASYNC_WORKITEM pWorkItem
+ );
+
+VOID
+ndisMQueuedFreeSharedHandler(
+ IN PASYNC_WORKITEM pWorkItem
+ );
+
+//
+// Macro for the deferred send handler.
+//
+#define NDISM_START_SENDS(_M) (_M)->DeferredSendHandler((_M))
+
+#define NDISM_DEFER_PROCESS_DEFERRED(_M) NdisSetTimer((_M)->DeferredTimer, NDIS_MINIPORT_DEFERRED_TIMEOUT);
+
+//
+// A list of registered address families are maintained here.
+//
+typedef struct _NDIS_AF_LIST
+{
+ struct _NDIS_AF_LIST *NextGlobal; // Global. Head at ndisAfList;
+ struct _NDIS_AF_LIST *NextOpen; // For this miniport Head at NDIS_MINIPORT_BLOCK
+
+ PNDIS_M_OPEN_BLOCK Open; // Back pointer to the open-block
+
+ NDIS_AF AddressFamily;
+
+ NDIS_CALL_MANAGER_CHARACTERISTICS CmChars;
+} NDIS_AF_LIST, *PNDIS_AF_LIST;
+
+extern PNDIS_AF_LIST ndisAfList;
+
+#endif // __MINI_H
diff --git a/private/ntos/ndis/ndis40/minint.c b/private/ntos/ndis/ndis40/minint.c
new file mode 100644
index 000000000..ff87c1aca
--- /dev/null
+++ b/private/ntos/ndis/ndis40/minint.c
@@ -0,0 +1,1293 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ miniport.c
+
+Abstract:
+
+ NDIS miniport wrapper functions
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 05-Oct-93
+ Jameel Hyder (JameelH) Re-organization 01-Jun-95
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_MININT
+
+/////////////////////////////////////////////////////////////////////
+//
+// HALT / CLOSE CODE
+//
+/////////////////////////////////////////////////////////////////////
+
+BOOLEAN
+ndisMKillOpen(
+ PNDIS_OPEN_BLOCK OldOpenP
+ )
+
+/*++
+
+Routine Description:
+
+ Closes an open. Used when NdisCloseAdapter is called, and also
+ for internally generated closes.
+
+Arguments:
+
+ OldOpenP - The open to be closed.
+
+Return Value:
+
+ TRUE if the open finished, FALSE if it pended.
+
+--*/
+
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(OldOpenP->AdapterHandle);
+ PNDIS_M_OPEN_BLOCK MiniportOpen;
+ BOOLEAN LocalLock, rc = TRUE;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+
+ //
+ // Find the Miniport open block
+ //
+
+ for (MiniportOpen = Miniport->OpenQueue;
+ MiniportOpen != NULL;
+ MiniportOpen = MiniportOpen->MiniportNextOpen)
+ {
+ if (MiniportOpen->FakeOpen == OldOpenP)
+ {
+ break;
+ }
+ }
+
+ ASSERT(MiniportOpen != NULL);
+ RAISE_IRQL_TO_DISPATCH(&OldIrql);
+
+ do
+ {
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(&MiniportOpen->SpinLock);
+
+ if (MiniportOpen->Flags & fMINIPORT_OPEN_PMODE)
+ {
+ Miniport->PmodeOpens --;
+ }
+
+ //
+ // See if this open is already closing.
+ //
+ if (MINIPORT_TEST_FLAG(MiniportOpen, fMINIPORT_OPEN_CLOSING))
+ {
+ NDIS_RELEASE_SPIN_LOCK_DPC(&MiniportOpen->SpinLock);
+ break;
+ }
+
+ //
+ // Indicate to others that this open is closing.
+ //
+ MINIPORT_SET_FLAG(MiniportOpen, fMINIPORT_OPEN_CLOSING);
+ NDIS_RELEASE_SPIN_LOCK_DPC(&MiniportOpen->SpinLock);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Remove us from the filter package
+ //
+ switch (Miniport->MediaType)
+ {
+ case NdisMediumArcnet878_2:
+ if (!MINIPORT_TEST_FLAG(MiniportOpen,
+ fMINIPORT_OPEN_USING_ETH_ENCAPSULATION))
+ {
+ Status = ArcDeleteFilterOpenAdapter(Miniport->ArcDB,
+ MiniportOpen->FilterHandle,
+ NULL);
+ break;
+ }
+
+ //
+ // If we're using encapsulation then we
+ // didn't open an arcnet filter but rather
+ // an ethernet filter.
+ //
+
+ case NdisMedium802_3:
+ Status = EthDeleteFilterOpenAdapter(Miniport->EthDB,
+ MiniportOpen->FilterHandle,
+ NULL);
+ break;
+
+ case NdisMedium802_5:
+ Status = TrDeleteFilterOpenAdapter(Miniport->TrDB,
+ MiniportOpen->FilterHandle,
+ NULL);
+ break;
+
+ case NdisMediumFddi:
+ Status = FddiDeleteFilterOpenAdapter(Miniport->FddiDB,
+ MiniportOpen->FilterHandle,
+ NULL);
+ break;
+
+ case NdisMediumAtm:
+ //
+ // there is no filter database for ATM medium so we have to handle
+ // this differently. Specifically we do not need to know of there
+ // is an indication occuring now or not since the indication
+ // routine checks if the reference count goes to zero and it
+ // also checks the Closing flag. In addition if there is an active
+ // indication going on, then there must be an open connection
+ // which has the ref count above zero. Since a close on the
+ // connection will not run during a receive indication (because
+ // the miniport is locked), there should be no special code
+ // required for this case.
+ //
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+ }
+
+ if (Status != NDIS_STATUS_CLOSING_INDICATING)
+ {
+ //
+ // Otherwise the close action routine will fix this up.
+ //
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("- Open 0x%x Reference 0x%x\n", MiniportOpen, MiniportOpen->References));
+
+ MiniportOpen->References--;
+
+ //
+ // If the status that was returned from the filter library
+ // was NDIS_STATUS_PENDING then we need to do some set information
+ // calls to clean up the opens filter & address settings....
+ //
+ switch (Miniport->MediaType)
+ {
+ case NdisMedium802_3:
+ case NdisMedium802_5:
+ case NdisMediumFddi:
+ case NdisMediumArcnet878_2:
+ ndisMRestoreFilterSettings(Miniport, MiniportOpen);
+ break;
+ }
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("!=0 Open 0x%x References 0x%x\n", MiniportOpen, MiniportOpen->References));
+
+ if (MiniportOpen->References != 0)
+ {
+ //
+ // Wait for close to complete, reference count will drop to 0.
+ //
+ NDISM_DEFER_PROCESS_DEFERRED(Miniport);
+
+ rc = FALSE;
+ }
+ else
+ {
+ //
+ // Free Vc datastructures are queued to be reused, but when the
+ // Open closes we must clean up these free Vcs
+ //
+ ndisMCoFreeResources(MiniportOpen);
+
+ //
+ // This sends an IRP_MJ_CLOSE IRP.
+ //
+ ObDereferenceObject(OldOpenP->FileObject);
+
+ //
+ // Remove us from the adapter and protocol open queues.
+ //
+ ndisDeQueueOpenOnProtocol(OldOpenP, OldOpenP->ProtocolHandle);
+ ndisDeQueueOpenOnMiniport(MiniportOpen, MiniportOpen->MiniportHandle);
+
+ ndisDereferenceProtocol(OldOpenP->ProtocolHandle);
+ ndisDereferenceMiniport(MiniportOpen->MiniportHandle);
+
+ NdisFreeSpinLock(&MiniportOpen->SpinLock);
+ FREE_POOL(MiniportOpen);
+ FREE_POOL(OldOpenP);
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+ } while (FALSE);
+
+ LOWER_IRQL(OldIrql);
+ return rc;
+}
+
+
+VOID
+ndisMFinishClose(
+ PNDIS_MINIPORT_BLOCK Miniport,
+ PNDIS_M_OPEN_BLOCK Open
+ )
+
+/*++
+
+Routine Description:
+
+ Finishes off a close adapter call.
+
+ CALLED WITH LOCK HELD!!
+
+Arguments:
+
+ Miniport - The mini-port the open is queued on.
+
+ Open - The open to close
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ //
+ // free any memory allocated to Vcs
+ //
+ ndisMCoFreeResources(Open);
+
+ ASSERT(MINIPORT_TEST_FLAG(Open, fMINIPORT_OPEN_CLOSING));
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.CloseAdapterCompleteHandler) (
+ Open->ProtocolBindingContext,
+ NDIS_STATUS_SUCCESS);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ ndisDeQueueOpenOnProtocol(Open->FakeOpen, Open->ProtocolHandle);
+ ndisDeQueueOpenOnMiniport(Open, Open->MiniportHandle);
+ FREE_POOL(Open->FakeOpen);
+
+ ndisDereferenceMiniport(Open->MiniportHandle);
+ ndisDereferenceProtocol(Open->ProtocolHandle);
+
+ NdisFreeSpinLock(&Open->SpinLock);
+
+ //
+ // This sends an IRP_MJ_CLOSE IRP.
+ //
+
+ ObDereferenceObject(Open->FileObject);
+
+ FREE_POOL(Open);
+}
+
+
+VOID
+ndisDeQueueOpenOnMiniport(
+ IN PNDIS_M_OPEN_BLOCK OpenP,
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Detaches an open block from the list of opens for a Miniport.
+
+Arguments:
+
+ OpenP - The open block to be dequeued.
+ Miniport - The Miniport block to dequeue it from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ KIRQL OldIrql;
+
+ NDIS_ACQUIRE_SPIN_LOCK(&Miniport->Ref.SpinLock, &OldIrql);
+
+ //
+ // Find the open on the queue, and remove it.
+ //
+
+ if (Miniport->OpenQueue == OpenP)
+ {
+ Miniport->OpenQueue = OpenP->MiniportNextOpen;
+ }
+ else
+ {
+ PNDIS_M_OPEN_BLOCK PP = Miniport->OpenQueue;
+
+ while (PP->MiniportNextOpen != OpenP)
+ {
+ PP = PP->MiniportNextOpen;
+ }
+
+ PP->MiniportNextOpen = PP->MiniportNextOpen->MiniportNextOpen;
+ }
+
+ NDIS_RELEASE_SPIN_LOCK(&Miniport->Ref.SpinLock, OldIrql);
+}
+
+
+BOOLEAN
+ndisQueueMiniportOnDriver(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_M_DRIVER_BLOCK MiniBlock
+ )
+
+/*++
+
+Routine Description:
+
+ Adds an mini-port to a list of mini-port for a driver.
+
+Arguments:
+
+ Miniport - The mini-port block to queue.
+ MiniBlock - The driver block to queue it to.
+
+Return Value:
+
+ FALSE if the driver is closing.
+ TRUE otherwise.
+
+--*/
+
+{
+ KIRQL OldIrql;
+
+ NDIS_ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
+
+ DBGPRINT(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
+ ("Enter queue mini-port on driver\n"));
+ DBGPRINT(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
+ ("queue mini-port 0x%x\n", Miniport));
+ DBGPRINT(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
+ ("driver 0x%x\n", MiniBlock));
+
+ //
+ // Make sure the driver is not closing.
+ //
+
+ if (MiniBlock->Ref.Closing)
+ {
+ DBGPRINT(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
+ ("Exit queue mini-port on driver\n"));
+
+ NDIS_RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
+ return FALSE;
+ }
+
+ //
+ // Add this adapter at the head of the queue
+ //
+
+ Miniport->NextMiniport = MiniBlock->MiniportQueue;
+ MiniBlock->MiniportQueue = Miniport;
+
+ DBGPRINT(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
+ ("Exit queue mini-port on driver\n"));
+
+ NDIS_RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
+ return TRUE;
+}
+
+
+VOID
+ndisDequeueMiniportOnDriver(
+ PNDIS_MINIPORT_BLOCK Miniport,
+ PNDIS_M_DRIVER_BLOCK MiniBlock
+ )
+
+/*++
+
+Routine Description:
+
+ Removes an mini-port from a list of mini-port for a driver.
+
+Arguments:
+
+ Miniport - The mini-port block to dequeue.
+ MiniBlock - The driver block to dequeue it from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_MINIPORT_BLOCK *ppQ;
+ KIRQL OldIrql;
+
+ NDIS_ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
+
+ DBGPRINT(DBG_COMP_UNLOAD, DBG_LEVEL_INFO,
+ ("Dequeue on driver\n"));
+ DBGPRINT(DBG_COMP_UNLOAD, DBG_LEVEL_INFO,
+ ("dequeue mini-port 0x%x\n", Miniport));
+ DBGPRINT(DBG_COMP_UNLOAD, DBG_LEVEL_INFO,
+ ("driver 0x%x\n", MiniBlock));
+
+ //
+ // Find the driver on the queue, and remove it.
+ //
+ for (ppQ = &MiniBlock->MiniportQueue;
+ *ppQ != NULL;
+ ppQ = &(*ppQ)->NextMiniport)
+ {
+ if (*ppQ == Miniport)
+ {
+ *ppQ = Miniport->NextMiniport;
+ break;
+ }
+ }
+
+ ASSERT(*ppQ == Miniport->NextMiniport);
+
+ NDIS_RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
+
+ if (MiniBlock->Unloading && (MiniBlock->MiniportQueue == (PNDIS_MINIPORT_BLOCK)NULL))
+ {
+ SET_EVENT(&MiniBlock->MiniportsRemovedEvent);
+ }
+
+ DBGPRINT(DBG_COMP_UNLOAD, DBG_LEVEL_INFO,
+ ("Exit dequeue mini-port on driver\n"));
+}
+
+
+VOID
+ndisDereferenceDriver(
+ PNDIS_M_DRIVER_BLOCK MiniBlock
+ )
+/*++
+
+Routine Description:
+
+ Removes a reference from the mini-port driver, deleting it if the count goes to 0.
+
+Arguments:
+
+ Miniport - The mini-port block to dereference.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ KIRQL OldIrql;
+
+ if (NdisDereferenceRef(&(MiniBlock)->Ref))
+ {
+ //
+ // Remove it from the global list.
+ //
+
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+
+ if (ndisMiniDriverList == MiniBlock)
+ {
+ ndisMiniDriverList = MiniBlock->NextDriver;
+ }
+ else
+ {
+ PNDIS_M_DRIVER_BLOCK TmpDriver = ndisMiniDriverList;
+
+ while(TmpDriver->NextDriver != MiniBlock)
+ {
+ TmpDriver = TmpDriver->NextDriver;
+ }
+
+ TmpDriver->NextDriver = TmpDriver->NextDriver->NextDriver;
+ }
+
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ FREE_POOL(MiniBlock);
+ }
+}
+
+
+VOID
+ndisDereferenceMiniport(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+/*++
+
+Routine Description:
+
+ Removes a reference from the mini-port driver, deleting it if the count goes to 0.
+
+Arguments:
+
+ Miniport - The mini-port block to dereference.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PSINGLE_LIST_ENTRY Link;
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+ UINT c;
+ BOOLEAN TimerQueued;
+
+ if (NdisDereferenceRef(&(Miniport)->Ref))
+ {
+ if (Miniport->EthDB)
+ {
+ EthDeleteFilter(Miniport->EthDB);
+ }
+
+ if (Miniport->TrDB)
+ {
+ TrDeleteFilter(Miniport->TrDB);
+ }
+
+ if (Miniport->FddiDB)
+ {
+ FddiDeleteFilter(Miniport->FddiDB);
+ }
+
+ if (Miniport->ArcDB)
+ {
+ ArcDeleteFilter(Miniport->ArcDB);
+ }
+
+ if (Miniport->Resources)
+ {
+ ndisMReleaseResources(Miniport);
+ }
+
+ if (((PNDIS_WRAPPER_CONTEXT)Miniport->WrapperContext)->AssignedSlotResources != NULL)
+ {
+ FREE_POOL(((PNDIS_WRAPPER_CONTEXT)Miniport->WrapperContext)->AssignedSlotResources);
+ }
+
+ //
+ // Do we need to acquire the work queue lock?
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+ }
+
+ //
+ // Free work items
+ //
+ while (Miniport->WorkItemFreeQueue.Next != NULL)
+ {
+ Link = PopEntryList(&Miniport->WorkItemFreeQueue);
+ WorkItem = CONTAINING_RECORD(Link, NDIS_MINIPORT_WORK_ITEM, Link);
+ FREE_POOL(WorkItem);
+ }
+
+ //
+ // Free the work items that are currently on the work queue.
+ //
+ for (c = 0; c < NUMBER_OF_WORK_ITEM_TYPES; c++)
+ {
+ //
+ // Free all work items on the current queue.
+ //
+ while (Miniport->WorkQueue[c].Next != NULL)
+ {
+ Link = PopEntryList(&Miniport->WorkQueue[c]);
+ WorkItem = CONTAINING_RECORD(Link, NDIS_MINIPORT_WORK_ITEM, Link);
+ FREE_POOL(WorkItem);
+ }
+ }
+
+ //
+ // Free the single workitem list.
+ //
+ for (c = 0; c < NUMBER_OF_SINGLE_WORK_ITEMS; c++)
+ {
+ //
+ // Is there a work item here?
+ //
+ Link = PopEntryList(&Miniport->SingleWorkItems[c]);
+ if (Link != NULL)
+ {
+ WorkItem = CONTAINING_RECORD(Link, NDIS_MINIPORT_WORK_ITEM, Link);
+ FREE_POOL(WorkItem);
+ }
+ }
+
+ //
+ // Do we need to release the work queue lock?
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+ NdisFreeSpinLock(&Miniport->SendLock);
+ }
+
+ //
+ // Did we allocate an array of packets?
+ //
+ if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_PACKET_ARRAY))
+ {
+ FREE_POOL(Miniport->PacketArray);
+ }
+
+ //
+ // Cancel the timer from firing.
+ //
+ NdisCancelTimer(Miniport->DeferredTimer, &TimerQueued);
+ if (TimerQueued)
+ {
+ NdisStallExecution(NDIS_MINIPORT_DEFERRED_TIMEOUT);
+ }
+
+ //
+ // Free the memory allocated for the timer.
+ //
+ FREE_POOL(Miniport->DeferredTimer);
+
+ //
+ // Is there an arcnet lookahead buffer allocated?
+ //
+ if (Miniport->ArcnetLookaheadBuffer != NULL)
+ {
+ FREE_POOL(Miniport->ArcnetLookaheadBuffer);
+ }
+
+ //
+ // Delete the global db entry
+ //
+ if (Miniport->BusId != 0)
+ {
+ ndisDeleteGlobalDb(Miniport->BusType,
+ Miniport->BusId,
+ Miniport->BusNumber,
+ Miniport->SlotNumber);
+ }
+
+ if (Miniport->FakeMac != NULL)
+ {
+ FREE_POOL(Miniport->FakeMac);
+ }
+
+ MiniportDereferencePackage();
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
+ {
+ CoDereferencePackage();
+ }
+
+ ndisDequeueMiniportOnDriver(Miniport, Miniport->DriverHandle);
+ ndisDereferenceDriver(Miniport->DriverHandle);
+ NdisMDeregisterAdapterShutdownHandler(Miniport);
+ IoUnregisterShutdownNotification(Miniport->DeviceObject);
+ IoDeleteDevice(Miniport->DeviceObject);
+ }
+}
+
+
+VOID
+ndisMHaltMiniport(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Does all the clean up for a mini-port.
+
+Arguments:
+
+ Miniport - pointer to the mini-port to halt
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ BOOLEAN LocalLock;
+ KIRQL OldIrql;
+ BOOLEAN Canceled;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ LOCK_MINIPORT(Miniport, LocalLock);
+ while (!LocalLock)
+ {
+ //
+ // This can only happen on an MP system. We must now
+ // wait for the other processor to exit the mini-port.
+ //
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ NdisStallExecution(1000);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+ LOCK_MINIPORT(Miniport, LocalLock);
+ }
+
+ //
+ // We can now release safely
+ //
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ NdisCancelTimer(&Miniport->WakeUpDpcTimer, &Canceled);
+ if (!Canceled)
+ {
+ NdisStallExecution(500000);
+ }
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler)(
+ Miniport->MiniportAdapterContext);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ ndisMAbortPacketsAndRequests(Miniport);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ //
+ // If a shutdown handler was registered then deregister it.
+ //
+
+ NdisMDeregisterAdapterShutdownHandler(Miniport);
+
+ ndisDereferenceMiniport(Miniport);
+}
+
+VOID
+ndisMUnload(
+ IN PDRIVER_OBJECT DriverObject
+ )
+/*++
+
+Routine Description:
+
+ This routine is called when a driver is supposed to unload. Ndis
+ converts this into a set of calls to MiniportHalt() for each
+ adapter that the driver has open.
+
+Arguments:
+
+ DriverObject - the driver object for the mac that is to unload.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_M_DRIVER_BLOCK MiniBlock;
+ PNDIS_MINIPORT_BLOCK Miniport, NextMiniport;
+ KIRQL OldIrql;
+
+ DBGPRINT(DBG_COMP_UNLOAD, DBG_LEVEL_INFO,
+ ("Enter unload\n"));
+
+ //
+ // Search for the driver
+ //
+
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+
+ MiniBlock = ndisMiniDriverList;
+
+ while (MiniBlock != (PNDIS_M_DRIVER_BLOCK)NULL)
+ {
+ if (MiniBlock->NdisDriverInfo->NdisWrapperDriver == DriverObject)
+ {
+ break;
+ }
+
+ MiniBlock = MiniBlock->NextDriver;
+ }
+
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ if (MiniBlock == (PNDIS_M_DRIVER_BLOCK)NULL)
+ {
+ //
+ // It is already gone. Just return.
+ //
+
+ DBGPRINT(DBG_COMP_UNLOAD, DBG_LEVEL_INFO,
+ ("Exit unload\n"));
+
+ return;
+ }
+
+ MiniBlock->Unloading = TRUE;
+
+ DBGPRINT(DBG_COMP_UNLOAD, DBG_LEVEL_INFO,
+ ("Halting mini-port\n"));
+
+ //
+ // Now call MiniportHalt() for each Miniport.
+ //
+
+ Miniport = MiniBlock->MiniportQueue;
+
+ while (Miniport != (PNDIS_MINIPORT_BLOCK)NULL)
+ {
+ NextMiniport = Miniport->NextMiniport; // since queue may change
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ DBGPRINT(DBG_COMP_UNLOAD, DBG_LEVEL_INFO,
+ ("Enter shutdown\n"));
+
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_HALTING);
+ MINIPORT_SET_SEND_FLAG(Miniport, fMINIPORT_SEND_HALTING);
+
+ //
+ // Queue the halt work item.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemHalt, NULL, NULL);
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ ndisMHaltMiniport(Miniport);
+
+ Miniport = NextMiniport;
+ }
+
+ //
+ // Wait for all adapters to be gonzo.
+ //
+ WAIT_FOR_OBJECT(&MiniBlock->MiniportsRemovedEvent, NULL);
+
+ RESET_EVENT(&MiniBlock->MiniportsRemovedEvent);
+
+ //
+ // Now remove the last reference (this will remove it from the list)
+ //
+
+ ASSERT(MiniBlock->Ref.ReferenceCount == 1);
+
+ ndisDereferenceDriver(MiniBlock);
+
+ DBGPRINT(DBG_COMP_UNLOAD, DBG_LEVEL_INFO, ("Exit unload\n"));
+}
+
+
+NTSTATUS
+ndisMShutdown(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ The "shutdown handler" for the SHUTDOWN Irp. Will call the Ndis
+ shutdown routine, if one is registered.
+
+Arguments:
+
+ DeviceObject - The adapter's device object.
+ Irp - The IRP.
+
+Return Value:
+
+ Always STATUS_SUCCESS.
+
+--*/
+
+{
+ PNDIS_WRAPPER_CONTEXT WrapperContext = (PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(WrapperContext + 1);
+ KIRQL OldIrql;
+ BOOLEAN LocalLock;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>ndisMShutdown\n"));
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ //
+ // Mark the miniport as halting and NOT using normal interrupts.
+ //
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_HALTING);
+ MINIPORT_SET_SEND_FLAG(Miniport, fMINIPORT_SEND_HALTING);
+
+ //
+ // Queue a halt work item.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemHalt, NULL, NULL);
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS);
+
+ if (WrapperContext->ShutdownHandler != NULL)
+ {
+ LOCK_MINIPORT(Miniport, LocalLock);
+ while (!LocalLock)
+ {
+ //
+ // This can only happen on an MP system. We must now
+ // wait for the other processor to exit the mini-port.
+ //
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ NdisStallExecution(1000);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+ LOCK_MINIPORT(Miniport, LocalLock);
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ //
+ // Call the shutdown routine.
+ //
+
+ if (WrapperContext->ShutdownHandler != NULL)
+ {
+ WrapperContext->ShutdownHandler(WrapperContext->ShutdownContext);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ }
+ else
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+ }
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==ndisMShutdown\n"));
+
+ return STATUS_SUCCESS;
+}
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// PLUG-N-PLAY CODE
+//
+/////////////////////////////////////////////////////////////////////
+
+
+NDIS_STATUS
+ndisUnloadMiniport(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ )
+/*++
+
+Routine Description:
+
+ Unbind all protocols from this miniport and finally unload it.
+
+Arguments:
+
+ Miniport - The Miniport to unload.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ KIRQL OldIrql;
+ PNDIS_M_OPEN_BLOCK Open;
+ NDIS_BIND_CONTEXT UnbindContext;
+ NDIS_STATUS UnbindStatus;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ // Start off by stopping all activity on this miniport
+ // MINIPORT_SET_FLAG(Miniport, fMINIPORT_HALTING);
+
+ //
+ // Walk the list of open bindings on this miniport and ask the protocols to
+ // unbind from them. For down-level protocols, DEVICE A WAY TO HANDLE THEM.
+ //
+ next:
+ for (Open = Miniport->OpenQueue;
+ Open != NULL;
+ Open = Open->MiniportNextOpen)
+ {
+ if (!MINIPORT_TEST_FLAG(Open, (fMINIPORT_OPEN_CLOSING | fMINIPORT_UNLOADING)) &&
+ (Open->ProtocolHandle->ProtocolCharacteristics.UnbindAdapterHandler != NULL))
+ {
+ MINIPORT_SET_FLAG(Open, fMINIPORT_UNLOADING);
+ break;
+ }
+ }
+
+ if (Open != NULL)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ INITIALIZE_EVENT(&UnbindContext.Event);
+
+ WAIT_FOR_OBJECT(&Open->ProtocolHandle->Mutex, NULL);
+ (*Open->ProtocolHandle->ProtocolCharacteristics.UnbindAdapterHandler)(
+ &UnbindStatus,
+ Open->ProtocolBindingContext,
+ &UnbindContext);
+
+ if (UnbindStatus == NDIS_STATUS_PENDING)
+ {
+ WAIT_FOR_OBJECT(&UnbindContext.Event, NULL);
+ }
+
+ RELEASE_MUTEX(&Open->ProtocolHandle->Mutex);
+
+ if (UnbindStatus == NDIS_STATUS_PENDING)
+ {
+ WAIT_FOR_OBJECT(&UnbindContext.Event, NULL);
+ }
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ goto next;
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ //
+ // The halt handler must be called when the last reference
+ // on the driver block goes away
+ //
+ return NDIS_STATUS_SUCCESS;
+}
+
+NDIS_STATUS
+ndisTranslateMiniportName(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PUCHAR Buffer,
+ IN UINT BufferLength,
+ OUT PUINT AmountCopied
+ )
+/*++
+
+Routine Description:
+
+ Calls the PnP protocols to enumerate PnP ids for the given miniport.
+
+Arguments:
+
+ Miniport - The Miniport in question.
+ Buffer, BufferLength - Buffer for a list of PnP Ids.
+ AmountCopied - How much buffer was used up.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ KIRQL OldIrql;
+ PNDIS_M_OPEN_BLOCK Open, NextOpen;
+ NDIS_STATUS Status;
+ UINT AmtCopied = 0, TotalAmtCopied = 0;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ //
+ // Walk the list of open bindings on this miniport and ask the
+ // protocols to enumerate the PnP ids for that binding
+ //
+ for (Open = Miniport->OpenQueue;
+ Open != NULL;
+ Open = NextOpen)
+ {
+ NextOpen = Open->MiniportNextOpen;
+
+ if (!MINIPORT_TEST_FLAG(Open, (fMINIPORT_OPEN_CLOSING | fMINIPORT_UNLOADING)) &&
+ (Open->ProtocolHandle->ProtocolCharacteristics.TranslateHandler != NULL))
+ {
+ // Reference this open block
+ if (TotalAmtCopied < BufferLength)
+ {
+ Open->References ++;
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ (*Open->ProtocolHandle->ProtocolCharacteristics.TranslateHandler)(
+ &Status,
+ Open->ProtocolBindingContext,
+ (PNET_PNP_ID)(Buffer + TotalAmtCopied),
+ BufferLength - TotalAmtCopied,
+ &AmtCopied);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ TotalAmtCopied += AmtCopied;
+ }
+
+ Open->References --;
+ if (Open->References == 0)
+ {
+ NextOpen = Open->MiniportNextOpen;
+ ndisMFinishClose(Miniport, Open);
+ }
+ }
+ }
+ }
+
+ *AmountCopied = TotalAmtCopied;
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+VOID
+NdisMSetPeriodicTimer(
+ IN PNDIS_MINIPORT_TIMER Timer,
+ IN UINT MillisecondsPeriod
+ )
+/*++
+
+Routine Description:
+
+ Sets up a periodic timer.
+
+Arguments:
+
+ Timer - The timer to Set.
+
+ MillisecondsPeriod - The timer will fire once every so often.
+
+Return Value:
+
+--*/
+{
+ LARGE_INTEGER FireUpTime;
+
+ FireUpTime.QuadPart = Int32x32To64((LONG)MillisecondsPeriod, -10000);
+
+ //
+ // Set the timer
+ //
+ SET_PERIODIC_TIMER(&Timer->Timer, FireUpTime, MillisecondsPeriod, &Timer->Dpc);
+}
+
+
+VOID
+NdisMSleep(
+ IN ULONG MicrosecondsToSleep
+ )
+/*++
+
+ Routine Description:
+
+ Blocks the caller for specified duration of time. Callable at Irql < DISPATCH_LEVEL.
+
+ Arguments:
+
+ MicrosecondsToSleep - The caller will be blocked for this much time.
+
+ Return Value:
+
+ NONE
+
+--*/
+{
+ KTIMER SleepTimer;
+ LARGE_INTEGER TimerValue;
+
+ ASSERT (KeGetCurrentIrql() == LOW_LEVEL);
+
+ INITIALIZE_TIMER_EX(&SleepTimer, SynchronizationTimer);
+
+ TimerValue.QuadPart = Int32x32To64(MicrosecondsToSleep, -10);
+ SET_TIMER(&SleepTimer, TimerValue, NULL);
+
+ WAIT_FOR_OBJECT(&SleepTimer, NULL);
+}
+
+VOID
+ndisMReleaseResources(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PCM_RESOURCE_LIST Resources;
+ BOOLEAN Conflict;
+ NTSTATUS NtStatus;
+
+ Resources = (PCM_RESOURCE_LIST)ALLOC_FROM_POOL(
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ NDIS_TAG_RSRC_LIST);
+ if (NULL == Resources)
+ {
+ return;
+ }
+
+ MoveMemory(
+ Resources,
+ Miniport->Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
+
+ //
+ // Clear count
+ //
+ Resources->List->PartialResourceList.Count = 0;
+
+ //
+ // Make the call
+ //
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver,
+ NULL,
+ 0,
+ Miniport->DeviceObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ TRUE,
+ &Conflict);
+
+ FREE_POOL(Resources);
+ FREE_POOL(Miniport->Resources);
+ Miniport->Resources = NULL;
+}
diff --git a/private/ntos/ndis/ndis40/miniport.c b/private/ntos/ndis/ndis40/miniport.c
new file mode 100644
index 000000000..859c55be1
--- /dev/null
+++ b/private/ntos/ndis/ndis40/miniport.c
@@ -0,0 +1,3180 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ miniport.c
+
+Abstract:
+
+ NDIS miniport wrapper functions
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 05-Oct-93
+ Jameel Hyder (JameelH) Re-organization 01-Jun-95
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_MINIPORT
+
+/////////////////////////////////////////////////////////////////////
+//
+// WORK-ITEM CODE
+//
+/////////////////////////////////////////////////////////////////////
+
+
+BOOLEAN
+NdisIMSwitchToMiniport(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ OUT PNDIS_HANDLE SwitchHandle
+ )
+/*++
+
+Routine Description:
+
+ This routine will attempt to synchronously grab the miniport's (specified
+ by MiniportAdapterHandle) spin-lock and local lock. If it succeeds
+ it will return TRUE, otherwise it will return FALSE.
+
+Arguments:
+
+ MiniportAdapterHandle - Pointer to the NDIS_MINIPORT_BLOCK whose
+ context we should nail down.
+ SwitchHandle - Pointer to storage for the current irql.
+ This is returned to the caller as a handle,
+ need-to-know basis baby.
+
+Return Value:
+
+ TRUE if we obtain both locks, FALSE otherwise.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ BOOLEAN LocalLock;
+ LONG Thread;
+
+ //
+ // Did we already acuqire the lock with this thread?
+ //
+ Thread = InterlockedExchangeAdd(&Miniport->MiniportThread, 0);
+ if (CURRENT_THREAD == Thread)
+ {
+ //
+ // We've already acquired the lock...
+ //
+ ASSERT(Miniport->LockAcquired);
+
+ *SwitchHandle = (NDIS_HANDLE)-1;
+
+ return(TRUE);
+ }
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, (PKIRQL)SwitchHandle);
+
+ LOCK_MINIPORT(Miniport, LocalLock);
+ if (!LocalLock)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, (KIRQL)*SwitchHandle);
+
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+VOID
+NdisIMRevertBack(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE SwitchHandle
+ )
+/*++
+
+Routine Description:
+
+ This routine will undo what NdisMLockMiniport did. It will release the
+ local lock and free the spin lock.
+
+Arguments:
+
+ MiniportAdapterHandle - Pointer to the NDIS_MINIPORT_BLOCK whose
+ context we are releasing.
+ SwitchHandle - This is the original irql from the NdisMLockMiniport
+ call.
+
+Return Value:
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+
+ //
+ // Before we unlock the miniport's context we need to pick up any
+ // stray workitems for this miniport that may have been generated by
+ // the caller.
+ //
+
+#if _SEND_PRIORITY
+ //
+ // If we are not reseting and not halting then give priority to sends
+ // at this point.
+ //
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_REQUESTED) &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS) &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_HALTING))
+ {
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ ndisMProcessDeferredFullDuplexPrioritySends(Miniport);
+ }
+ else
+ {
+ ndisMProcessDeferredPrioritySends(Miniport);
+ }
+ }
+ else
+#endif
+ {
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ if ((NDIS_HANDLE)-1 == SwitchHandle)
+ {
+ return;
+ }
+
+ UNLOCK_MINIPORT(Miniport, TRUE);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, (KIRQL)SwitchHandle);
+}
+
+NDIS_STATUS
+NdisIMQueueMiniportCallback(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN W_MINIPORT_CALLBACK CallbackRoutine,
+ IN PVOID CallbackContext
+ )
+/*++
+
+Routine Description:
+
+ This routine will attempt to acquire the specified MiniportAdapterHandle's
+ miniport lock and local lock and call the callback routine with the context
+ information. If it cannot do so then it will queue a workitem to do it
+ later.
+
+Arguments:
+
+ MiniportAdapterHandle - PNDIS_MINIPORT_BLOCK of the miniport whose
+ context we are attempting to acquire.
+ CallbackRoutine - Pointer to the routine that we are to call.
+ CallbackContext - Context information for the callback routine.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS - If we were able to do this synchronously.
+ NDIS_STATUS_PENDING - If it will be called at a later time.
+ NDIS_STATUS_FAILURE - If the work item could not be queue'd.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ BOOLEAN LocalLock;
+ KIRQL OldIrql;
+ LONG Thread;
+ BOOLEAN LockAcquired;
+
+ //
+ // Did we already acuqire the lock with this thread?
+ //
+ Thread = InterlockedExchangeAdd(&Miniport->MiniportThread, 0);
+ if (CURRENT_THREAD == Thread)
+ {
+ //
+ // We've already acquired the lock...
+ //
+ ASSERT(Miniport->LockAcquired);
+ LockAcquired = FALSE;
+ LocalLock = TRUE;
+ }
+ else
+ {
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+ LOCK_MINIPORT(Miniport, LocalLock);
+ LockAcquired = TRUE;
+ }
+
+ if (!LocalLock)
+ {
+ NDIS_STATUS Status;
+
+ //
+ // Queue the work item to do this later.
+ //
+ Status = NDISM_QUEUE_NEW_WORK_ITEM(
+ Miniport,
+ NdisWorkItemMiniportCallback,
+ CallbackRoutine,
+ CallbackContext);
+
+ if (LockAcquired)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+ }
+
+ return((NDIS_STATUS_SUCCESS == Status) ? NDIS_STATUS_PENDING : NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // Call the callback routine.
+ //
+ (*CallbackRoutine)(Miniport->MiniportAdapterContext, CallbackContext);
+
+#if _SEND_PRIORITY
+ //
+ // If we are not reseting and not halting then give priority to sends
+ // at this point.
+ //
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_REQUESTED) &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS) &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_HALTING))
+ {
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ ndisMProcessDeferredFullDuplexPrioritySends(Miniport);
+ }
+ else
+ {
+ ndisMProcessDeferredPrioritySends(Miniport);
+ }
+ }
+ else
+#endif
+ {
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ if (LockAcquired)
+ {
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+/////////////////////////////////////////////////////////////////////
+//
+// WORKITEM CODE FOR INTERMEDIATE MINIPORTS
+//
+/////////////////////////////////////////////////////////////////////
+
+
+NDIS_STATUS
+FASTCALL
+ndisIMQueueWorkItem(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ IN PVOID WorkItemContext1,
+ IN PVOID WorkItemContext2
+ )
+/*++
+
+Routine Description:
+
+ Queue's the specific workitem on the work queue.
+
+ NOTE!!!!!
+
+ This routine assumes that you have the correct lock acquire to
+ touch the SingleWorkItem that you requested to be queued.
+
+ NdisWorkItemSend - SendLock
+ NdisWorkItemResetRequested - Miniport lock
+ NdisWorkItemRequest - Miniport lock
+ NdisWorkItemDpc - Miniport lock
+ NdisWorkItemHalt - Miniport lock
+
+Arguments:
+
+ Miniport - Pointer to the miniport block.
+ WorkItemType - Type of work item to queue.
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+#ifdef NDIS_NT
+
+ NDISM_QUEUE_WORK_ITEM_FULL_DUPLEX_MACRO(
+ Miniport,
+ WorkItemType,
+ WorkItemContext1,
+ WorkItemContext2,
+ &Status);
+
+ //
+ // If the status is not accepted then it means that there is already
+ // a workitem of this type queued and there should be a timer fired
+ // to process it.
+ //
+ if (Status != NDIS_STATUS_NOT_ACCEPTED)
+ {
+ NDISM_DEFER_PROCESS_DEFERRED(Miniport);
+ }
+
+#endif
+ return(Status);
+}
+
+
+NDIS_STATUS
+FASTCALL
+ndisIMQueueNewWorkItem(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ IN PVOID WorkItemContext1,
+ IN PVOID WorkItemContext2
+ )
+/*++
+
+Routine Description:
+
+ This routine will queue a workitem in the work queue even if there
+ are already work items queue for it.
+
+ THE WORK QUEUE LOCK MUST BE HELD WHEN CALLING THIS ROUTINE!!!!
+
+Arguments:
+
+ Miniport - Miniport block to queue the workitem to.
+ WorkItem - Workitem to place on the queue.
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+#ifdef NDIS_NT
+
+ NDISM_QUEUE_NEW_WORK_ITEM_FULL_DUPLEX_MACRO(
+ Miniport,
+ WorkItemType,
+ WorkItemContext1,
+ WorkItemContext2,
+ &Status);
+
+ //
+ // Since we can have any number of these work items queued we
+ // need to be sure that they all get processed.
+ //
+ NDISM_DEFER_PROCESS_DEFERRED(Miniport);
+
+#endif
+ return(Status);
+}
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// WORKITEM CODE FOR HARDWARE MINIPORTS
+//
+/////////////////////////////////////////////////////////////////////
+
+
+VOID
+FASTCALL
+ndisMDeQueueWorkItem(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ OUT PVOID *WorkItemContext1,
+ OUT PVOID *WorkItemContext2
+ )
+/*++
+
+Routine Description:
+
+ This routine will dequeue a workitem of the given type and return any context
+ information that is associated with it.
+
+ NOTE:
+
+ FOR FULL-DUPLEX USAGE THE WORK LOCK MUST BE ACQUIRED BEFORE THIS ROUTINE IS CALLED !!!!
+
+Arguments:
+
+ Miniport - Pointer to the miniport block.
+ WorkItemType - Type of workitem to dequeue.
+ WorkItemContext1 - Pointer to storage space for first piece of context information.
+ WorkItemContext2 - Pointer to storage space for second piece of context information.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PSINGLE_LIST_ENTRY Link;
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+
+ //
+ // Grab the first workitem of the given type.
+ //
+ Link = PopEntryList(&Miniport->WorkQueue[WorkItemType]);
+ if (Link != NULL)
+ {
+ //
+ // Get a pointer to the context information.
+ //
+ WorkItem = CONTAINING_RECORD(Link, NDIS_MINIPORT_WORK_ITEM, Link);
+
+ if (WorkItemContext1 != NULL)
+ {
+ *WorkItemContext1 = WorkItem->WorkItemContext1;
+ }
+
+ if (WorkItemContext2 != NULL)
+ {
+ *WorkItemContext2 = WorkItem->WorkItemContext2;
+ }
+
+ switch (WorkItemType)
+ {
+ case NdisWorkItemMiniportCallback:
+ case NdisWorkItemTimer:
+ case NdisWorkItemPendingOpen:
+
+ ASSERT(*WorkItemContext1 != NULL);
+ PushEntryList(&Miniport->WorkItemFreeQueue, Link);
+ break;
+
+ case NdisWorkItemResetInProgress:
+
+ PushEntryList(&Miniport->SingleWorkItems[NdisWorkItemResetRequested], Link);
+ break;
+
+ case NdisWorkItemResetRequested:
+
+ WorkItem->WorkItemType = NdisWorkItemResetInProgress;
+ PushEntryList(&Miniport->WorkQueue[NdisWorkItemResetInProgress], Link);
+ break;
+
+ default:
+ PushEntryList(&Miniport->SingleWorkItems[WorkItemType], Link);
+ break;
+ }
+ }
+}
+
+NDIS_STATUS
+FASTCALL
+ndisMQueueWorkItem(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ IN PVOID WorkItemContext1,
+ IN PVOID WorkItemContext2
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+
+ NDISM_QUEUE_WORK_ITEM_MACRO(
+ Miniport,
+ WorkItemType,
+ WorkItemContext1,
+ WorkItemContext2,
+ &Status);
+
+ return(Status);
+}
+
+NDIS_STATUS
+FASTCALL
+ndisMQueueWorkItemFullDuplex(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ IN PVOID WorkItemContext1,
+ IN PVOID WorkItemContext2
+ )
+/*++
+
+Routine Description:
+
+ Queue's the specific workitem on the work queue.
+
+ NOTE!!!!!
+
+ This routine assumes that you have the correct lock acquire to
+ touch the SingleWorkItem that you requested to be queued.
+
+ NdisWorkItemSend - SendLock
+ NdisWorkItemResetRequested - Miniport lock
+ NdisWorkItemRequest - Miniport lock
+ NdisWorkItemDpc - Miniport lock
+ NdisWorkItemHalt - Miniport lock
+
+Arguments:
+
+ Miniport - Pointer to the miniport block.
+ WorkItemType - Type of work item to queue.
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+#ifdef NDIS_NT
+
+ NDISM_QUEUE_WORK_ITEM_FULL_DUPLEX_MACRO(
+ Miniport,
+ WorkItemType,
+ WorkItemContext1,
+ WorkItemContext2,
+ &Status);
+
+#endif
+ return(Status);
+}
+
+
+NDIS_STATUS
+FASTCALL
+ndisMQueueNewWorkItem(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ IN PVOID WorkItemContext1,
+ IN PVOID WorkItemContext2
+ )
+/*++
+
+Routine Description:
+
+ This routine will queue a workitem in the work queue even if there
+ are already work items queue for it.
+
+ THE WORK QUEUE LOCK MUST BE HELD WHEN CALLING THIS ROUTINE!!!!
+
+Arguments:
+
+ Miniport - Miniport block to queue the workitem to.
+ WorkItem - Workitem to place on the queue.
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+
+ NDISM_QUEUE_NEW_WORK_ITEM_MACRO(
+ Miniport,
+ WorkItemType,
+ WorkItemContext1,
+ WorkItemContext2,
+ &Status);
+
+ return(Status);
+}
+
+NDIS_STATUS
+FASTCALL
+ndisMQueueNewWorkItemFullDuplex(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ IN PVOID WorkItemContext1,
+ IN PVOID WorkItemContext2
+ )
+/*++
+
+Routine Description:
+
+ This routine will queue a workitem in the work queue even if there
+ are already work items queue for it.
+
+ THE WORK QUEUE LOCK MUST BE HELD WHEN CALLING THIS ROUTINE!!!!
+
+Arguments:
+
+ Miniport - Miniport block to queue the workitem to.
+ WorkItem - Workitem to place on the queue.
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+#ifdef NDIS_NT
+
+ NDISM_QUEUE_NEW_WORK_ITEM_FULL_DUPLEX_MACRO(
+ Miniport,
+ WorkItemType,
+ WorkItemContext1,
+ WorkItemContext2,
+ &Status);
+
+#endif
+ return(Status);
+}
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// DEFERRED PROCESSING CODE
+//
+/////////////////////////////////////////////////////////////////////
+
+
+#if _SEND_PRIORITY
+
+VOID
+FASTCALL
+ndisMProcessDeferredFullDuplexPrioritySends(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Processes all outstanding operations.
+
+ CALLED WITH THE LOCK HELD!!
+
+Arguments:
+
+ Miniport - Miniport to send to.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+#ifdef NDIS_NT
+ NDIS_STATUS Status;
+ BOOLEAN ProcessWorkItems;
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+ PSINGLE_LIST_ENTRY Link;
+ NDIS_WORK_ITEM_TYPE WorkItemType;
+ BOOLEAN AddressingReset;
+ PKDPC Dpc;
+ PMINIPORT_PENDING_OPEN PendingOpen;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("==>ndisMProcessDeferredFullDuplexPrioritySends\n"));
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ //
+ // Are there any sends to process?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemSend].Next != NULL)
+ {
+ BOOLEAN fMoreSends;
+
+ //
+ // Process the sends.
+ //
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ NDISM_START_SENDS(Miniport);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+ }
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ //
+ // Are there any loopback packets to indicate?
+ //
+ if ((Miniport->WorkQueue[NdisWorkItemMiniportCallback].Next != NULL) ||
+ (Miniport->WorkQueue[NdisWorkItemSendLoopback].Next != NULL) ||
+ (Miniport->WorkQueue[NdisWorkItemDpc].Next != NULL) ||
+ (Miniport->WorkQueue[NdisWorkItemTimer].Next != NULL) ||
+ (Miniport->WorkQueue[NdisWorkItemPendingOpen].Next != NULL) ||
+ (Miniport->WorkQueue[NdisWorkItemRequest].Next != NULL))
+ {
+
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("<==ndisMProcessDeferredFullDuplexPrioritySends\n"));
+#endif
+}
+
+#endif
+
+VOID
+FASTCALL
+ndisMProcessDeferredFullDuplex(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Processes all outstanding operations.
+
+ CALLED WITH THE LOCK HELD!!
+
+Arguments:
+
+ Miniport - Miniport to send to.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+#ifdef NDIS_NT
+ NDIS_STATUS Status;
+ BOOLEAN ProcessWorkItems;
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+ PSINGLE_LIST_ENTRY Link;
+ NDIS_WORK_ITEM_TYPE WorkItemType;
+ BOOLEAN AddressingReset;
+ PKDPC Dpc;
+ PMINIPORT_PENDING_OPEN PendingOpen;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("==>ndisMProcessDeferredFullDuplex\n"));
+
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ //
+ // DO NOT CHANGE THE ORDER THAT THE WORKITEMS ARE PROCESSED!!!!!
+ //
+ do
+ {
+ ProcessWorkItems = FALSE;
+
+ //
+ // Is there a reset currently in progress?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemResetInProgress].Next != NULL)
+ {
+ //
+ // The only thing that can run during a reset in progress
+ // are the timers.
+ //
+ if (Miniport->WorkQueue[NdisWorkItemTimer].Next != NULL)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Queuing dpc timer\n"));
+
+ //
+ // Grab the timer workitem.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemTimer, &Dpc, NULL);
+
+ //
+ // Queue the timer's dpc to fire.
+ //
+ QUEUE_DPC(Dpc);
+ }
+ else if (Miniport->WorkQueue[NdisWorkItemRequest].Next != NULL)
+ {
+ //
+ // We have requests to process that set up the packet
+ // filters.
+ //
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+ ndisMDoRequests(Miniport);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+ }
+
+ break;
+ }
+
+ //
+ // If the adapter is halting then get out of here.
+ //
+ if (Miniport->WorkQueue[NdisWorkItemHalt].Next != NULL)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Miniport is halting\n"));
+
+ break;
+ }
+
+ //
+ // If an intermediate miniport wants a call back do it now...
+ //
+ if (Miniport->WorkQueue[NdisWorkItemMiniportCallback].Next != NULL)
+ {
+ W_MINIPORT_CALLBACK CallbackRoutine;
+ PVOID CallbackContext;
+
+ //
+ // Get the callback routine and the context information for it.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(
+ Miniport,
+ NdisWorkItemMiniportCallback,
+ (PVOID *)&CallbackRoutine,
+ &CallbackContext);
+
+ //
+ // Call the intermediate drivers callback routine.
+ //
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ (*CallbackRoutine)(Miniport->MiniportAdapterContext, CallbackContext);
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ ProcessWorkItems = TRUE;
+ }
+
+ //
+ // Does a deferred dpc need to run?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemDpc].Next != NULL)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Queuing DPC\n"));
+
+ //
+ // Queue the dpc to run.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemDpc, &Dpc, NULL);
+ QUEUE_DPC(Dpc);
+
+ break;
+ }
+
+ //
+ // Is there a timer to fire?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemTimer].Next != NULL)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Queuing dpc timer\n"));
+
+ //
+ // Queue the timer's dpc to fire.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemTimer, &Dpc, NULL);
+ QUEUE_DPC(Dpc);
+
+ break;
+ }
+
+ //
+ // Finish any pending opens?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemPendingOpen].Next != NULL)
+ {
+ //
+ // Grab the pending open block.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemPendingOpen, &PendingOpen, NULL);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ //
+ // Finish the pending open.
+ //
+ Status = ndisMFinishPendingOpen(PendingOpen);
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ //
+ // Did it pend again?
+ //
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ NDISM_QUEUE_NEW_WORK_ITEM(
+ Miniport,
+ NdisWorkItemPendingOpen,
+ PendingOpen,
+ NULL);
+ }
+
+
+ //
+ // Process more work items.
+ //
+ ProcessWorkItems = TRUE;
+ }
+
+ //
+ // Was there a reset requested?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemResetRequested].Next != NULL)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Reset requested\n"));
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ //
+ // We need to release the work item lock to
+ // indicate the status to the bindings
+ // and to call down to the miniport driver.
+ //
+ Status = ndisMProcessResetRequested(Miniport,
+ &AddressingReset);
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Reset is pending\n"));
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ //
+ // Do we need to run a dpc?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemDpc].Next != NULL)
+ {
+ //
+ // Queue the dpc to run.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemDpc, &Dpc, NULL);
+ QUEUE_DPC(Dpc);
+ }
+
+ //
+ // The reset is still in progress so we need to stop
+ // processing workitems and wait for the completion.
+ //
+ break;
+ }
+ else
+ {
+ //
+ // Do step1 of the reset complete.
+ //
+ ndisMResetCompleteCommonStep1(Miniport,
+ Status,
+ AddressingReset);
+ if (!AddressingReset || (Status != NDIS_STATUS_SUCCESS))
+ {
+ //
+ // If there is no addressing reset to be done or
+ // the reset failed in some way then we tell the
+ // bindings now.
+ //
+ ndisMResetCompleteCommonStep2(Miniport);
+ }
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ continue;
+ }
+ }
+
+ //
+ // Process any requests?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemRequest].Next != NULL)
+ {
+ //
+ // Process the requests.
+ //
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+ ndisMDoRequests(Miniport);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+
+ ProcessWorkItems = TRUE;
+ }
+
+ //
+ // Are there any loopback packets to indicate?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemSendLoopback].Next != NULL)
+ {
+ BOOLEAN fMoreLoopback;
+
+ //
+ // Process the loopback packets.
+ //
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+ fMoreLoopback = ndisMIndicateLoopback(Miniport);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ if (!fMoreLoopback)
+ {
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSendLoopback, NULL, NULL);
+ }
+
+ ProcessWorkItems = TRUE;
+ }
+
+ //
+ // Are there any sends to process?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemSend].Next != NULL)
+ {
+ BOOLEAN fMoreSends;
+
+ //
+ // Process the sends.
+ //
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ NDISM_START_SENDS(Miniport);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+
+ ProcessWorkItems = TRUE;
+ }
+ } while (ProcessWorkItems);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_PROCESS_DEFERRED);
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("<==ndisMProcessDeferredFullDuplex\n"));
+#endif
+}
+
+#if _SEND_PRIORITY
+
+VOID
+FASTCALL
+ndisMProcessDeferredPrioritySends(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Processes all outstanding operations.
+
+ CALLED WITH THE LOCK HELD!!
+
+Arguments:
+
+ Miniport - Miniport to send to.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("==>ndisMProcessDeferredPrioritySends\n"));
+
+ //
+ // Are there any sends to process?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemSend].Next != NULL)
+ {
+ //
+ // Process the sends.
+ //
+ NDISM_START_SENDS(Miniport);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+ }
+
+ //
+ // Are there any loopback packets to indicate?
+ //
+ if ((Miniport->WorkQueue[NdisWorkItemMiniportCallback].Next != NULL) ||
+ (Miniport->WorkQueue[NdisWorkItemSendLoopback].Next != NULL) ||
+ (Miniport->WorkQueue[NdisWorkItemDpc].Next != NULL) ||
+ (Miniport->WorkQueue[NdisWorkItemTimer].Next != NULL) ||
+ (Miniport->WorkQueue[NdisWorkItemPendingOpen].Next != NULL) ||
+ (Miniport->WorkQueue[NdisWorkItemRequest].Next != NULL))
+ {
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("<==ndisMProcessDeferredPrioritySends\n"));
+}
+
+#endif
+
+VOID
+FASTCALL
+ndisMProcessDeferred(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Processes all outstanding operations.
+
+ CALLED WITH THE LOCK HELD!!
+
+Arguments:
+
+ Miniport - Miniport to send to.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS Status;
+ BOOLEAN ProcessWorkItems;
+ PSINGLE_LIST_ENTRY Link;
+ NDIS_WORK_ITEM_TYPE WorkItemType;
+ BOOLEAN AddressingReset;
+ PKDPC Dpc;
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+ PMINIPORT_PENDING_OPEN PendingOpen;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("==>ndisMProcessDeferred\n"));
+
+ //
+ // DO NOT CHANGE THE ORDER THAT THE WORKITEMS ARE PROCESSED!!!!!
+ //
+ do
+ {
+ ProcessWorkItems = FALSE;
+
+ //
+ // Is there a reset currently in progress?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemResetInProgress].Next != NULL)
+ {
+ //
+ // The only thing that can run during a reset in progress
+ // are the timers.
+ //
+ if (Miniport->WorkQueue[NdisWorkItemTimer].Next != NULL)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Queuing dpc timer\n"));
+
+ //
+ // Grab the timer workitem.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemTimer, &Dpc, NULL);
+
+ //
+ // Queue the timer's dpc to fire.
+ //
+ QUEUE_DPC(Dpc);
+ }
+ else if (Miniport->WorkQueue[NdisWorkItemRequest].Next != NULL)
+ {
+ //
+ // We have requests to process that set up the packet
+ // filters.
+ //
+ ndisMDoRequests(Miniport);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+ }
+
+ break;
+ }
+
+ //
+ // If the adapter is halting then get out of here.
+ //
+ if (Miniport->WorkQueue[NdisWorkItemHalt].Next != NULL)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Miniport is halting\n"));
+
+ break;
+ }
+
+ //
+ // If an intermediate miniport wants a call back do it now...
+ //
+ if (Miniport->WorkQueue[NdisWorkItemMiniportCallback].Next != NULL)
+ {
+ W_MINIPORT_CALLBACK CallbackRoutine;
+ PVOID CallbackContext;
+
+ //
+ // Get the callback routine and the context information for it.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(
+ Miniport,
+ NdisWorkItemMiniportCallback,
+ (PVOID *)&CallbackRoutine,
+ &CallbackContext);
+
+ //
+ // Call the intermediate drivers callback routine.
+ //
+ (*CallbackRoutine)(Miniport->MiniportAdapterContext, CallbackContext);
+
+ ProcessWorkItems = TRUE;
+ }
+
+ //
+ // Does a deferred dpc need to run?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemDpc].Next != NULL)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Queuing DPC\n"));
+
+ //
+ // Queue the dpc to run.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemDpc, &Dpc, NULL);
+ QUEUE_DPC(Dpc);
+
+ break;
+ }
+
+ //
+ // Is there a timer to fire?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemTimer].Next != NULL)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Queuing dpc timer\n"));
+
+ //
+ // Queue the timer's dpc to fire.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemTimer, &Dpc, NULL);
+ QUEUE_DPC(Dpc);
+
+ break;
+ }
+
+ //
+ // Finish any pending opens?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemPendingOpen].Next != NULL)
+ {
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemPendingOpen, &PendingOpen, NULL);
+
+ //
+ // Finish the pending open.
+ //
+ Status = ndisMFinishPendingOpen(PendingOpen);
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ NDISM_QUEUE_NEW_WORK_ITEM(
+ Miniport,
+ NdisWorkItemPendingOpen,
+ PendingOpen,
+ NULL);
+ }
+
+ //
+ // Process more work items.
+ //
+ ProcessWorkItems = TRUE;
+ }
+
+ //
+ // Was there a reset requested?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemResetRequested].Next != NULL)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Reset requested\n"));
+ //
+ // We need to release the work item lock to
+ // indicate the status to the bindings
+ // and to call down to the miniport driver.
+ //
+ Status = ndisMProcessResetRequested(Miniport,
+ &AddressingReset);
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Reset is pending\n"));
+ //
+ // Do we need to run a dpc?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemDpc].Next != NULL)
+ {
+ //
+ // Dequeue the dpc.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemDpc, &Dpc, NULL);
+
+ //
+ // Queue the dpc to run.
+ //
+ QUEUE_DPC(Dpc);
+ }
+
+ //
+ // The reset is still in progress so we need to stop
+ // processing workitems and wait for the completion.
+ //
+ break;
+ }
+ else
+ {
+ //
+ // Do step1 of the reset complete.
+ //
+ ndisMResetCompleteCommonStep1(Miniport,
+ Status,
+ AddressingReset);
+ if (!AddressingReset || (Status != NDIS_STATUS_SUCCESS))
+ {
+ //
+ // If there is no addressing reset to be done or
+ // the reset failed in some way then we tell the
+ // bindings now.
+ //
+ ndisMResetCompleteCommonStep2(Miniport);
+ }
+ else
+ {
+ //
+ // We MUST complete the filter requests within
+ // the reset in progress workitem. Mainly because
+ // we don't want to do any sends at this time.
+ //
+ ProcessWorkItems = TRUE;
+
+ continue;
+ }
+ }
+ }
+
+ //
+ // Process any requests?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemRequest].Next != NULL)
+ {
+ //
+ // Process the requests.
+ //
+ ndisMDoRequests(Miniport);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+
+ ProcessWorkItems = TRUE;
+ }
+
+ //
+ // Are there any loopback packets to indicate?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemSendLoopback].Next != NULL)
+ {
+ BOOLEAN fMoreLoopback;
+
+ //
+ // Process the loopback packets.
+ //
+ fMoreLoopback = ndisMIndicateLoopback(Miniport);
+
+ if (!fMoreLoopback)
+ {
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSendLoopback, NULL, NULL);
+ }
+
+ ProcessWorkItems = TRUE;
+ }
+
+ //
+ // Are there any sends to process?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemSend].Next != NULL)
+ {
+ //
+ // Process the sends.
+ //
+ NDISM_START_SENDS(Miniport);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+
+ ProcessWorkItems = TRUE;
+ }
+ } while (ProcessWorkItems);
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_PROCESS_DEFERRED);
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("<==ndisMProcessDeferred\n"));
+}
+
+/////////////////////////////////////////////////////////////////////
+//
+// INDICATE CODE
+//
+/////////////////////////////////////////////////////////////////////
+
+VOID
+NdisMIndicateStatus(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ )
+/*++
+
+Routine Description:
+
+ This function indicates a new status of the media/mini-port.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+ GeneralStatus - The status to indicate.
+
+ StatusBuffer - Additional information.
+
+ StatusBufferSize - Length of the buffer.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+ NDIS_STATUS Status;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ if ((GeneralStatus == NDIS_STATUS_RING_STATUS) &&
+ (StatusBufferSize == sizeof(NDIS_STATUS)))
+ {
+
+ Status = *((PNDIS_STATUS)StatusBuffer);
+
+ if (Status & (NDIS_RING_LOBE_WIRE_FAULT |
+ NDIS_RING_HARD_ERROR |
+ NDIS_RING_SIGNAL_LOSS))
+ {
+ Miniport->TrResetRing = NDIS_MINIPORT_TR_RESET_TIMEOUT;
+ }
+ }
+
+ Open = Miniport->OpenQueue;
+
+ while (Open != NULL)
+ {
+ //
+ // Call Protocol to indicate status
+ //
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.StatusHandler) (
+ Open->ProtocolBindingContext,
+ GeneralStatus,
+ StatusBuffer,
+ StatusBufferSize
+ );
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ Open = Open->MiniportNextOpen;
+ }
+}
+
+VOID
+NdisMIndicateStatusComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ )
+/*++
+
+Routine Description:
+
+ This function indicates the status is complete.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ Open = Miniport->OpenQueue;
+
+ while (Open != NULL)
+ {
+ //
+ // Call Protocol to indicate status
+ //
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.StatusCompleteHandler) (
+ Open->ProtocolBindingContext);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ Open = Open->MiniportNextOpen;
+ }
+}
+
+
+VOID
+NdisMWanIndicateReceive(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE NdisLinkContext,
+ IN PUCHAR Packet,
+ IN ULONG PacketSize
+ )
+/*++
+
+Routine Description:
+
+ This function indicates the status is complete.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ Open = Miniport->OpenQueue;
+
+ while (Open != NULL)
+ {
+ //
+ // Call Protocol to indicate status
+ //
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ *Status = ((WAN_RECEIVE_HANDLER)(Open->ProtocolHandle->ProtocolCharacteristics.ReceiveHandler)) (
+ NdisLinkContext,
+ Packet,
+ PacketSize);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ Open = Open->MiniportNextOpen;
+ }
+}
+
+
+
+VOID
+NdisMWanIndicateReceiveComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE NdisLinkContext
+ )
+/*++
+
+Routine Description:
+
+ This function indicates the status is complete.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ Open = Miniport->OpenQueue;
+
+ while (Open != NULL)
+ {
+ //
+ // Call Protocol to indicate status
+ //
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.ReceiveCompleteHandler)(NdisLinkContext);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ Open = Open->MiniportNextOpen;
+ }
+}
+
+
+
+NDIS_STATUS
+NdisQueryReceiveInformation(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacContext,
+ OUT PLONGLONG TimeSent OPTIONAL,
+ OUT PLONGLONG TimeReceived OPTIONAL,
+ IN PUCHAR Buffer,
+ IN UINT BufferSize,
+ OUT PUINT SizeNeeded
+ )
+{
+ PNDIS_OPEN_BLOCK OpenBlock = ((PNDIS_OPEN_BLOCK)NdisBindingHandle);
+ PNDIS_M_OPEN_BLOCK MOpenBlock = (PNDIS_M_OPEN_BLOCK)(OpenBlock->MacBindingHandle);
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(MOpenBlock->MiniportHandle);
+ PNDIS_PACKET Packet = (PNDIS_PACKET)MacContext;
+ NDIS_STATUS Status = NDIS_STATUS_NOT_SUPPORTED;
+
+
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("NdisQueryReceiveInformation - Miniort %lx, Packet %lx\n",
+ Miniport, Packet));
+
+ //
+ // The following tests whether this is a mac or a miniport and also if we
+ // came here via a IndicatePacket or IndicateRecieve
+ //
+ if ((MOpenBlock->FakeOpen == OpenBlock) &&
+ (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID)))
+ {
+ PNDIS_PACKET_OOB_DATA pOob;
+
+ pOob = NDIS_OOB_DATA_FROM_PACKET(Packet);
+ *SizeNeeded = pOob->SizeMediaSpecificInfo;
+ if (BufferSize < *SizeNeeded)
+ {
+ Status = NDIS_STATUS_BUFFER_TOO_SHORT;
+ }
+ else
+ {
+ CopyMemory(Buffer, pOob->MediaSpecificInformation, *SizeNeeded);
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ if (ARGUMENT_PRESENT(TimeSent))
+ {
+ *TimeSent = pOob->TimeSent;
+ }
+ if (ARGUMENT_PRESENT(TimeReceived))
+ {
+ *TimeReceived = pOob->TimeReceived;
+ }
+ }
+
+ return Status;
+}
+
+
+VOID
+NdisReturnPackets(
+ IN PNDIS_PACKET *PacketsToReturn,
+ IN UINT NumberOfPackets
+ )
+/*++
+
+Routine Description:
+
+ Decrement the refcount for the packet and return back to the miniport if 0.
+ We take the Miniport lock here and hence are protected against other receives.
+
+Arguments:
+
+ NdisBindingHandle - Handle to the open binding
+ PacketsToReturn - Pointer to the set of packets to return to the miniport
+ NumberOfPackets - self descriptive
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UINT i;
+
+ for (i = 0; i < NumberOfPackets; i++)
+ {
+ KIRQL OldIrql;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ W_RETURN_PACKET_HANDLER Handler;
+ PNDIS_PACKET Packet;
+ BOOLEAN QueueWorkItem = FALSE;
+
+ Packet = PacketsToReturn[i];
+ ASSERT (Packet != NULL);
+
+ Miniport = PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->Miniport;
+ ASSERT (Miniport != NULL);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount --;
+ if (PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount == 0)
+ {
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID))
+ {
+ Handler = Miniport->DriverHandle->MiniportCharacteristics.ReturnPacketHandler;
+ (*Handler)(Miniport->MiniportAdapterContext, Packet);
+ }
+ else
+ {
+ ASSERT(NDIS_GET_PACKET_STATUS(Packet) != NDIS_STATUS_RESOURCES);
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->NextPacket =
+ Miniport->ReturnPacketsQueue;
+ Miniport->ReturnPacketsQueue = Packet;
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RP_WORK_ITEM_QUEUED))
+ {
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_RP_WORK_ITEM_QUEUED);
+ QueueWorkItem = TRUE;
+ }
+ }
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ if (QueueWorkItem)
+ {
+ ndisReferenceMiniport(Miniport);
+ QUEUE_WORK_ITEM(&Miniport->WorkItem, HyperCriticalWorkQueue);
+ }
+ }
+}
+
+
+VOID
+ndisMLazyReturnPackets(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ )
+{
+ KIRQL OldIrql;
+ PNDIS_PACKET Packet, NextPacket;
+ W_RETURN_PACKET_HANDLER Handler;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ ASSERT(MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RP_WORK_ITEM_QUEUED));
+
+ Packet = Miniport->ReturnPacketsQueue;
+ Miniport->ReturnPacketsQueue = NULL;
+
+ for (NOTHING;
+ Packet != NULL;
+ Packet = NextPacket)
+ {
+ NextPacket = PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->NextPacket;
+ Handler = Miniport->DriverHandle->MiniportCharacteristics.ReturnPacketHandler;
+ (*Handler)(Miniport->MiniportAdapterContext, Packet);
+ }
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_RP_WORK_ITEM_QUEUED);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ ndisDereferenceMiniport(Miniport);
+}
+
+
+VOID
+ndisMIndicatePacket(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by the Miniport to indicate packets to
+ all bindings. This is the code path for ndis 4.0 miniport drivers.
+
+Arguments:
+
+ Miniport - The Miniport block.
+
+ PacketArray - An array of Packets indicated by the miniport. Each packet consists of a
+ single buffer.
+
+ NumberOfPackets - Self-explanatory.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // The private structure to indicate up with
+ //
+ PPNDIS_PACKET pPktArray = PacketArray;
+
+ //
+ // Pointer to the buffer in the ndispacket
+ //
+ PNDIS_BUFFER Buffer;
+
+ //
+ // Pointer to the 1st segment of the buffer, points to dest address
+ //
+ PUCHAR Address;
+
+ //
+ // Total packet length
+ //
+ UINT i, LASize,PacketSize, NumIndicates = 0;
+
+ //
+ // Decides whether we use the protocol's revpkt handler or fall
+ // back to old rcvindicate handler
+ //
+ BOOLEAN fFallBack, FixRef;
+
+ //
+ // The current open block
+ //
+ PNDIS_M_OPEN_BLOCK pOpenBlock, NextOpen;
+
+ NDIS_STATUS StatusOfReceive;
+
+ //
+ // Define a NULL Fiter structure so that the IndicateToProtocol macro can be used.
+ //
+ struct _NullFilter
+ {
+ PNDIS_SPIN_LOCK Lock;
+ } Filter;
+
+ Filter.Lock = &Miniport->Lock;
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID);
+
+ // Walk all the packets
+ for (i = 0; i < NumberOfPackets; i++, pPktArray++)
+ {
+ PNDIS_PACKET Packet = *pPktArray;
+ PNDIS_PACKET_OOB_DATA pOob;
+
+ ASSERT(Packet != NULL);
+ pOob = NDIS_OOB_DATA_FROM_PACKET(Packet);
+
+ NdisGetFirstBufferFromPacket(Packet,
+ &Buffer,
+ &Address,
+ &LASize,
+ &PacketSize);
+ ASSERT(Buffer != NULL);
+
+ //
+ // Set the status here that nobody is holding the packet. This will get
+ // overwritten by the real status from the protocol. Pay heed to what
+ // the miniport is saying.
+ //
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount = 0;
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->Miniport = Miniport;
+
+ if (pOob->Status != NDIS_STATUS_RESOURCES)
+ {
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount --;
+ pOob->Status = NDIS_STATUS_SUCCESS;
+ fFallBack = FALSE;
+ FixRef = TRUE;
+ }
+ else
+ {
+ FixRef = FALSE;
+ fFallBack = TRUE;
+ }
+
+ //
+ // Ensure that we force re-calculation.
+ //
+ Packet->Private.ValidCounts = FALSE;
+
+ for (pOpenBlock = Miniport->OpenQueue;
+ pOpenBlock != NULL;
+ pOpenBlock = NextOpen)
+ {
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = pOpenBlock->MiniportNextOpen;
+ pOpenBlock->ReceivedAPacket = TRUE;
+ pOpenBlock->References++;
+ NumIndicates ++;
+
+ IndicateToProtocol(Miniport,
+ &Filter,
+ pOpenBlock->FakeOpen,
+ Packet,
+ Address,
+ PacketSize,
+ pOob->HeaderSize,
+ &fFallBack,
+ FALSE,
+ NdisMediumMax); // A dummy medium since it is unknown
+
+ pOpenBlock->References--;
+ if (pOpenBlock->References == 0)
+ {
+ // Anything to do here ?
+ }
+ }
+
+ if (FixRef)
+ {
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount++;
+ if (PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount != 0)
+ {
+ NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_PENDING);
+ }
+ }
+ }
+
+ if (NumIndicates > 0)
+ {
+ for (pOpenBlock = Miniport->OpenQueue;
+ pOpenBlock != NULL;
+ pOpenBlock = NextOpen)
+ {
+ if (pOpenBlock->ReceiveCompleteHandler)
+ {
+ pOpenBlock->References++;
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (*pOpenBlock->ReceiveCompleteHandler)(pOpenBlock->ProtocolBindingContext);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+ if ((--(pOpenBlock->References)) == 0)
+ {
+ // Anything to do here ?
+ }
+ }
+ }
+ }
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID);
+}
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// TRANSFER DATA CODE
+//
+/////////////////////////////////////////////////////////////////////
+
+VOID
+NdisMTransferDataComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ )
+/*++
+
+Routine Description:
+
+ This function indicates the completion of a transfer data request.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+ Packet - The packet the data was copied into.
+
+ Status - Status of the operation.
+
+ BytesTransferred - Total number of bytes transferred.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+ PNDIS_PACKET PrevPacket;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+ ASSERT(Miniport->FirstTDPacket != NULL);
+
+ //
+ // Find the packet
+ //
+
+ if (Packet == Miniport->FirstTDPacket)
+ {
+ Miniport->FirstTDPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next;
+ }
+ else
+ {
+ PrevPacket = Miniport->FirstTDPacket;
+
+ while (PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next != Packet)
+ {
+ PrevPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next;
+
+ ASSERT(PrevPacket != NULL);
+ }
+
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next =
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next;
+
+ if (Packet == Miniport->LastTDPacket)
+ {
+ Miniport->LastTDPacket = PrevPacket;
+ }
+ }
+
+ //
+ // Indicate to Protocol;
+ //
+
+ Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Open;
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.TransferDataCompleteHandler) (
+ Open->ProtocolBindingContext,
+ Packet,
+ Status,
+ BytesTransferred);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+}
+
+NDIS_STATUS
+ndisMTransferDataSync(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ PNDIS_PACKET_RESERVED Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ PNDIS_PACKET_OOB_DATA pOob;
+ NDIS_STATUS Status;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+ ASSERT((Miniport->MacOptions & NDIS_MAC_OPTION_TRANSFERS_NOT_PEND) != 0);
+
+ //
+ // Handle non-loopback as the default case.
+ //
+
+ if (Miniport->LoopbackPacket == NULL)
+ {
+ Reserved->Next = NULL;
+ Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+
+ //
+ // Call Miniport.
+ //
+
+ Status = (Reserved->Open->TransferDataHandler)(
+ Packet,
+ BytesTransferred,
+ Reserved->Open->MiniportAdapterContext,
+ MacReceiveContext,
+ ByteOffset,
+ BytesToTransfer);
+ //
+ // This miniport better not pend this send.
+ //
+
+ ASSERT(Status != NDIS_STATUS_PENDING);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ return Status;
+ }
+
+ //
+ // This packet is a loopback packet!
+ //
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ pOob = NDIS_OOB_DATA_FROM_PACKET((PNDIS_PACKET)MacReceiveContext);
+ NdisCopyFromPacketToPacket(Packet,
+ 0,
+ BytesToTransfer,
+ Miniport->LoopbackPacket,
+ ByteOffset + pOob->HeaderSize,
+ BytesTransferred);
+
+ if (*BytesTransferred == BytesToTransfer)
+ {
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ return NDIS_STATUS_FAILURE;
+}
+
+
+NDIS_STATUS
+ndisMTransferData(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ PNDIS_PACKET_RESERVED Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ PNDIS_PACKET_OOB_DATA pOob;
+ PNDIS_PACKET PrevLast;
+ NDIS_STATUS Status;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ //
+ // Handle non-loopback as the default case.
+ //
+
+ if (Miniport->LoopbackPacket == NULL)
+ {
+ Reserved->Next = NULL;
+ Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+
+ //
+ // Put this guy on the transfer data queue.
+ //
+
+ PrevLast = Miniport->LastTDPacket;
+
+ if (Miniport->FirstTDPacket == NULL)
+ {
+ Miniport->FirstTDPacket = Packet;
+ }
+ else
+ {
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastTDPacket)->Next = Packet;
+ }
+
+ Miniport->LastTDPacket = Packet;
+
+ //
+ // Call Miniport
+ //
+
+ Status = (Reserved->Open->TransferDataHandler)(
+ Packet,
+ BytesTransferred,
+ Reserved->Open->MiniportAdapterContext,
+ MacReceiveContext,
+ ByteOffset,
+ BytesToTransfer);
+
+ //
+ // If it didn't pend then we won't get a transfer data complte call
+ // so we need to remove this guy now.
+ //
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ //
+ // Remove from queue
+ //
+
+ if (Miniport->FirstTDPacket != Packet)
+ {
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevLast)->Next = NULL;
+ Miniport->LastTDPacket = PrevLast;
+ }
+ else
+ {
+ Miniport->FirstTDPacket = NULL;
+ Miniport->LastTDPacket = NULL;
+ }
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ return Status;
+ }
+
+ //
+ // This packet is a loopback packet!
+ //
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ pOob = NDIS_OOB_DATA_FROM_PACKET((PNDIS_PACKET)MacReceiveContext);
+ NdisCopyFromPacketToPacket(Packet,
+ 0,
+ BytesToTransfer,
+ Miniport->LoopbackPacket,
+ ByteOffset + pOob->HeaderSize,
+ BytesTransferred);
+
+ if (*BytesTransferred == BytesToTransfer)
+ {
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ return NDIS_STATUS_FAILURE;
+}
+
+NDIS_STATUS
+ndisMDummyTransferData(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ )
+{
+ PNDIS_PACKET_OOB_DATA pOob;
+
+ pOob = NDIS_OOB_DATA_FROM_PACKET((PNDIS_PACKET)MacReceiveContext);
+ NdisCopyFromPacketToPacket(Packet,
+ 0,
+ BytesToTransfer,
+ (PNDIS_PACKET)MacReceiveContext,
+ ByteOffset + pOob->HeaderSize,
+ BytesTransferred);
+
+ return ((*BytesTransferred == BytesToTransfer) ?
+ NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE);
+}
+
+
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// RESET CODE
+//
+/////////////////////////////////////////////////////////////////////
+
+VOID
+ndisMAbortPacketsAndRequests(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Aborts all outstanding requests on a mini-port.
+
+ CALLED WITH THE LOCK HELD!!
+
+Arguments:
+
+ Miniport - Miniport to abort.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_PACKET Packet;
+ PNDIS_PACKET NextPacket;
+ PNDIS_REQUEST MiniportRequest;
+ PNDIS_REQUEST PendingRequest;
+ PNDIS_REQUEST NextRequest;
+ PNDIS_M_OPEN_BLOCK Open;
+ PNDIS_PACKET ArcnetLimitPacket;
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+ BOOLEAN fRestoreDeferredState = FALSE;
+ PSINGLE_LIST_ENTRY Link;
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Enter abort packets and requests\n"));
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ //
+ // Dequeue any send workitems and acquire the send spin lock
+ // if we are full duplex..
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ //
+ // Since we are full duplex we need to wrap the dequeue operation
+ // with spin lock acquire and release.
+ //
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ //
+ // Acquire the spin lock.
+ //
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+ else
+ {
+ //
+ // non-full duplex miniports can just dequeue any send work items
+ // that are queued
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+ }
+
+ //
+ // Clear out the packet queues.
+ //
+ Packet = Miniport->FirstPacket;
+ ArcnetLimitPacket = Miniport->FirstPendingPacket;
+
+ Miniport->LastMiniportPacket = NULL;
+ Miniport->FirstPendingPacket = NULL;
+ Miniport->FirstPacket = NULL;
+ Miniport->LastPacket = NULL;
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'a');
+
+ //
+ // Go through the list of packets an return them to the
+ // bindings
+ //
+ while (Packet != NULL)
+ {
+ //
+ // Get a pointer to the next packet before we kill
+ // the current one.
+ //
+ NextPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next;
+
+ //
+ // Get the open that the packet came from.
+ //
+ Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Open;
+
+ //
+ // Set flag that we've reached the packets that are
+ // not on the mini-port.
+ //
+
+ if (Packet == ArcnetLimitPacket)
+ {
+ ArcnetLimitPacket = NULL;
+ }
+
+ //
+ // Now free the arcnet header.
+ //
+
+ if (Miniport->MediaType == NdisMediumArcnet878_2 && ArcnetLimitPacket)
+ {
+ ndisMFreeArcnetHeader(Miniport, Packet);
+ }
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'C');
+
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler) (
+ Open->ProtocolBindingContext,
+ Packet,
+ NDIS_STATUS_REQUEST_ABORTED);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ //
+ // Re-acquire the send lock if we are full duplex.
+ // Note that the wrapper does NOT keep track of open
+ // references with regard to sends for full duplex miniports.
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+ else
+ {
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("- Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ Open->References--;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("==0 Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ if (Open->References == 0)
+ {
+ ndisMFinishClose(Miniport,Open);
+ }
+ }
+
+ //
+ // Get the next packet.
+ //
+ Packet = NextPacket;
+ }
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'A');
+
+ Miniport->SendResourcesAvailable = 0x00ffffff;
+
+ //
+ // Dequeue any request workitems.
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ //
+ // Release the send lock.
+ //
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+
+ //
+ // Since we are full duplex we need to wrap the dequeue operation
+ // with spin lock acquire and release.
+ //
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+ }
+ else
+ {
+ //
+ // non-full duplex miniports can just dequeue any send work items
+ // that are queued
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+ }
+
+
+ //
+ // Clear the request timeout flag.
+ //
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_REQUEST_TIMEOUT);
+
+ //
+ // We need to clear out the pending request queue before the currently in
+ // progress one so that when we complete the in-progress request we
+ // won't think that we have to process more requests.
+ //
+ PendingRequest = Miniport->PendingRequest;
+ Miniport->PendingRequest = NULL;
+
+ MiniportRequest = Miniport->MiniportRequest;
+
+ //
+ // If there is one then abort it.
+ //
+ if (MiniportRequest != NULL)
+ {
+ //
+ // Get a pointer to the open that the request came from.
+ //
+ Open = PNDIS_RESERVED_FROM_PNDIS_REQUEST(MiniportRequest)->Open;
+
+ //
+ // Was this a statistics request?
+ //
+ if ((Open != NULL) &&
+ (MiniportRequest->RequestType == NdisRequestQueryStatistics))
+ {
+ ndisMAbortQueryStatisticsRequest(MiniportRequest,
+ NDIS_STATUS_REQUEST_ABORTED);
+
+ Miniport->MiniportRequest = NULL;
+ }
+ else
+ {
+ if (MiniportRequest->RequestType == NdisRequestSetInformation)
+ {
+ ndisMSyncSetInformationComplete((NDIS_HANDLE)Miniport,
+ NDIS_STATUS_REQUEST_ABORTED);
+ }
+ else
+ {
+ ndisMSyncQueryInformationComplete((NDIS_HANDLE)Miniport,
+ NDIS_STATUS_REQUEST_ABORTED);
+ }
+ }
+ }
+
+ //
+ // Go through the pending request queue and clear it out.
+ //
+ while (PendingRequest != NULL)
+ {
+ //
+ // Get a pointer to the next request before we kill the
+ // current one.
+ //
+ NextRequest = PNDIS_RESERVED_FROM_PNDIS_REQUEST(PendingRequest)->Next;
+
+ //
+ // Get a pointer to the open that the request belongs to.
+ //
+ Open = PNDIS_RESERVED_FROM_PNDIS_REQUEST(PendingRequest)->Open;
+
+ if (PendingRequest->RequestType == NdisRequestQueryStatistics)
+ {
+ ndisMAbortQueryStatisticsRequest(
+ PendingRequest,
+ NDIS_STATUS_REQUEST_ABORTED);
+ }
+ else
+ {
+ //
+ // Make this request the request in progress.
+ //
+ Miniport->MiniportRequest = PendingRequest;
+
+ if (PendingRequest->RequestType == NdisRequestSetInformation)
+ {
+ ndisMSyncSetInformationComplete(Miniport,
+ NDIS_STATUS_REQUEST_ABORTED);
+ }
+ else
+ {
+ ndisMSyncQueryInformationComplete(Miniport,
+ NDIS_STATUS_REQUEST_ABORTED);
+ }
+ }
+
+ //
+ // Get the next request.
+ //
+ PendingRequest = NextRequest;
+ }
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Exit abort packets and requests\n"));
+}
+
+VOID
+ndisMResetCompleteCommonStep2(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PSINGLE_LIST_ENTRY Link;
+ PNDIS_M_OPEN_BLOCK Open;
+ PNDIS_M_OPEN_BLOCK tmpOpen;
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+
+
+ //
+ // Dequeue the reset in progress work item.
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ //
+ // Acquire the work lock and dequeue the reset in progress work item.
+ //
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemResetInProgress, &Open, NULL);
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ //
+ // Grab the send lock so that we can clear the reset in progress flag.
+ //
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS);
+
+ for (tmpOpen = Miniport->OpenQueue;
+ tmpOpen != NULL;
+ tmpOpen = tmpOpen->MiniportNextOpen)
+ {
+ //
+ // Restore the send handler
+ //
+ tmpOpen->FakeOpen->SendHandler = Miniport->FakeMac->MacCharacteristics.SendHandler;
+
+ //
+ // Restore the send packets handler.
+ //
+ if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_PACKET_ARRAY))
+ {
+ tmpOpen->FakeOpen->SendPacketsHandler = ndisMSendPacketsFullDuplex;
+ }
+ else
+ {
+ tmpOpen->FakeOpen->SendPacketsHandler = ndisMSendPacketsFullDuplexToSend;
+ }
+ }
+
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+ else
+ {
+ //
+ // For non full duplex miniports we don't need to acquire the work lock.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemResetInProgress, &Open, NULL);
+
+ //
+ // Clear the reset in progress flag.
+ //
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS);
+
+ for (tmpOpen = Miniport->OpenQueue;
+ tmpOpen != NULL;
+ tmpOpen = tmpOpen->MiniportNextOpen)
+ {
+ //
+ // Restore the send handler
+ //
+ tmpOpen->FakeOpen->SendHandler = Miniport->FakeMac->MacCharacteristics.SendHandler;
+
+ //
+ // Restore the send packets handler.
+ //
+ if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_PACKET_ARRAY))
+ {
+ tmpOpen->FakeOpen->SendPacketsHandler = ndisMSendPackets;
+ }
+ else
+ {
+ tmpOpen->FakeOpen->SendPacketsHandler = ndisMSendPacketsToSend;
+ }
+ }
+ }
+
+ ASSERT(Open != NULL);
+
+ //
+ // Indicate to Protocols the reset is complete
+ //
+ NdisMIndicateStatus(Miniport,
+ NDIS_STATUS_RESET_END,
+ &Miniport->ResetStatus,
+ sizeof(Miniport->ResetStatus));
+
+ NdisMIndicateStatusComplete(Miniport);
+
+ //
+ // If a protocol initiated the reset then notify it of the
+ // completion.
+ //
+ if (Open != (PNDIS_M_OPEN_BLOCK)Miniport)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.ResetCompleteHandler)(
+ Open->ProtocolBindingContext,
+ Miniport->ResetStatus);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("- Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ Open->References--;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("==0 Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ if (Open->References == 0)
+ {
+ ndisMFinishClose(Miniport,Open);
+ }
+ }
+}
+
+VOID
+ndisMResetCompleteCommonStep1(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_STATUS Status,
+ IN BOOLEAN AddressingReset
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ //
+ // Destroy all outstanding packets and requests.
+ //
+ ndisMAbortPacketsAndRequests(Miniport);
+
+ //
+ // Check if we are going to have to reset the
+ // adapter again. This happens when we are doing
+ // the reset because of a ring failure.
+ //
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IGNORE_TOKEN_RING_ERRORS))
+ {
+ if (Miniport->TrResetRing == 1)
+ {
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ Miniport->TrResetRing = 0;
+ }
+ else
+ {
+ Miniport->TrResetRing = NDIS_MINIPORT_TR_RESET_TIMEOUT;
+ }
+ }
+ }
+
+ //
+ // If we need to reset the miniports filter settings then
+ // queue the necessary requests & work items.
+ //
+ if (AddressingReset &&
+ (Status == NDIS_STATUS_SUCCESS) &&
+ ((Miniport->EthDB != NULL) || (Miniport->TrDB != NULL) ||
+ (Miniport->FddiDB != NULL) || (Miniport->ArcDB != NULL)))
+ {
+ ndisMRestoreFilterSettings(Miniport, NULL);
+ }
+
+ //
+ // Save the reset status as it is now.
+ //
+ Miniport->ResetStatus = Status;
+}
+
+
+NDIS_STATUS
+ndisMProcessResetRequested(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ OUT PBOOLEAN pAddressingReset
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+ PNDIS_M_OPEN_BLOCK Open;
+
+ //
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ //
+ // We need to acquire the work lock to dequeue the reset requsted work item.
+ //
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemResetRequested, NULL, NULL);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ //
+ // We need to acquire the send lock to modify the reset requested and
+ // reset in progress flags.
+ //
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+
+ //
+ // Set the reset in progress bit so that the send path can see it.
+ //
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_RESET_REQUESTED);
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS);
+
+ //
+ // Replace the send handler for the open's
+ //
+ for (Open = Miniport->OpenQueue;
+ Open != NULL;
+ Open = Open->MiniportNextOpen)
+ {
+ if (NdisMediumWan == Miniport->MediaType)
+ {
+ Open->FakeOpen->SendHandler = (PVOID)ndisMResetWanSend;
+ }
+ else
+ {
+ Open->FakeOpen->SendHandler = ndisMResetSend;
+ }
+
+ Open->FakeOpen->SendPacketsHandler = ndisMResetSendPackets;
+ }
+
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+ else
+ {
+ //
+ // Dequeue the reset requested work item. this dequeuing will automatically
+ // queue the reset in progress work item.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemResetRequested, NULL, NULL);
+
+ //
+ // Set the reset in progress bit so that the send path can see it.
+ //
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_RESET_REQUESTED);
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS);
+
+ //
+ // Replace the send handler for the open's
+ //
+ for (Open = Miniport->OpenQueue;
+ Open != NULL;
+ Open = Open->MiniportNextOpen)
+ {
+ if (NdisMediumWan == Miniport->MediaType)
+ {
+ Open->FakeOpen->SendHandler = (PVOID)ndisMResetWanSend;
+ }
+ else
+ {
+ Open->FakeOpen->SendHandler = ndisMResetSend;
+ }
+
+ Open->FakeOpen->SendPacketsHandler = ndisMResetSendPackets;
+ }
+ }
+
+
+ //
+ // Indicate the reset status to the protocols.
+ //
+ NdisMIndicateStatus(Miniport, NDIS_STATUS_RESET_START, NULL, 0);
+ NdisMIndicateStatusComplete(Miniport);
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Calling miniport reset\n"));
+ //
+ // Call the miniport's reset handler.
+ //
+ Status = (Miniport->DriverHandle->MiniportCharacteristics.ResetHandler)(
+ pAddressingReset,
+ Miniport->MiniportAdapterContext);
+
+ return(Status);
+}
+
+
+VOID
+ndisMResetCompleteFullDuplex(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_STATUS Status,
+ IN BOOLEAN AddressingReset
+ )
+{
+#ifdef NDIS_NT
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("Enter reset complete\n"));
+
+ //
+ // Code that is common for synchronous and async resets.
+ //
+ ndisMResetCompleteCommonStep1(Miniport, Status, AddressingReset);
+ if (!AddressingReset || (Status != NDIS_STATUS_SUCCESS))
+ {
+ //
+ // If there is no addressing reset to be done or
+ // the reset failed in some way then we tell the
+ // bindings now.
+ //
+ ndisMResetCompleteCommonStep2(Miniport);
+ }
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("Exit reset complete\n"));
+#endif
+}
+
+VOID
+NdisMResetComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_STATUS Status,
+ IN BOOLEAN AddressingReset
+ )
+/*++
+
+Routine Description:
+
+ This function indicates the completion of a reset.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+ Status - Status of the reset.
+
+ AddressingReset - Do we have to submit a request to reload the address
+ information. This includes packet filter, and multicast/functional addresses.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("Enter reset complete\n"));
+
+ //
+ // Code that is common for synchronous and async resets.
+ //
+ ndisMResetCompleteCommonStep1(Miniport, Status, AddressingReset);
+ if (!AddressingReset || (Status != NDIS_STATUS_SUCCESS))
+ {
+ //
+ // If there is no addressing reset to be done or
+ // the reset failed in some way then we tell the
+ // bindings now.
+ //
+ ndisMResetCompleteCommonStep2(Miniport);
+ }
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("Exit reset complete\n"));
+}
+
+NDIS_STATUS
+ndisMResetFullDuplex(
+ IN NDIS_HANDLE NdisBindingHandle
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+#ifdef NDIS_NT
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ KIRQL OldIrql;
+ BOOLEAN LocalLock;
+ PSINGLE_LIST_ENTRY Link;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ //
+ // Is there already a reset in progress?
+ //
+ Status = NDISM_QUEUE_WORK_ITEM(Miniport,
+ NdisWorkItemResetRequested,
+ NdisBindingHandle,
+ NULL);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ return(NDIS_STATUS_RESET_IN_PROGRESS);
+ }
+
+ //
+ // Update the open's references.
+ //
+ ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("+ Open 0x%x Reference 0x%x\n", NdisBindingHandle,
+ ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References));
+
+ //
+ // The reset requested flag is used by both the send path and the
+ // dpc path.
+ //
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_RESET_REQUESTED);
+
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+
+ //
+ // Grab the local lock.
+ //
+ LOCK_MINIPORT(Miniport, LocalLock);
+ if (LocalLock)
+ {
+ //
+ // If we did not lock down the mini-port, then some other routine will
+ // do this processing for us. Otherwise we need to do this processing.
+ //
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+#endif
+ return(NDIS_STATUS_PENDING);
+}
+
+NDIS_STATUS
+ndisMReset(
+ IN NDIS_HANDLE NdisBindingHandle
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+ KIRQL OldIrql;
+ BOOLEAN LocalLock;
+ PSINGLE_LIST_ENTRY Link;
+ NDIS_STATUS Status;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ //
+ // Is there already a reset in progress?
+ //
+ Status = NDISM_QUEUE_WORK_ITEM(Miniport,
+ NdisWorkItemResetRequested,
+ NdisBindingHandle,
+ NULL);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+ return(NDIS_STATUS_RESET_IN_PROGRESS);
+ }
+
+ //
+ // Update the open's references.
+ //
+ ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("+ Open 0x%x Reference 0x%x\n", NdisBindingHandle, ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References));
+
+ //
+ // Set the reset requested flag.
+ //
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_RESET_REQUESTED);
+
+ //
+ // Grab the local lock.
+ //
+ LOCK_MINIPORT(Miniport, LocalLock);
+ if (LocalLock)
+ {
+ //
+ // If we did not lock down the mini-port, then some other routine will
+ // do this processing for us. Otherwise we need to do this processing.
+ //
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ return(NDIS_STATUS_PENDING);
+}
+
+
diff --git a/private/ntos/ndis/ndis40/minisub.c b/private/ntos/ndis/ndis40/minisub.c
new file mode 100644
index 000000000..1b7e52201
--- /dev/null
+++ b/private/ntos/ndis/ndis40/minisub.c
@@ -0,0 +1,569 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ miniport.c
+
+Abstract:
+
+ NDIS wrapper functions
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 05-Oct-93
+ Jameel Hyder (JameelH) Re-organization 01-Jun-95
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_MINISUB
+
+#undef NdisAllocateSpinLock
+#undef NdisFreeSpinLock
+#undef NdisAcquireSpinLock
+#undef NdisReleaseSpinLock
+#undef NdisDprAcquireSpinLock
+#undef NdisDprReleaseSpinLock
+#undef NdisFreeBuffer
+#undef NdisQueryBuffer
+#undef NdisQueryBufferOffset
+#undef NdisGetFirstBufferFromPacket
+#undef NDIS_BUFFER_TO_SPAN_PAGES
+#undef NdisGetBufferPhysicalArraySize
+#undef NdisEqualString
+#undef NdisInitAnsiString
+#undef NdisAnsiStringToUnicodeString
+#undef NdisInitUnicodeString
+#undef NdisUnicodeStringToAnsiString
+#undef NdisInterlockedIncrement
+#undef NdisInterlockedDecrement
+#undef NdisInterlockedAddUlong
+#undef NdisInterlockedInsertHeadList
+#undef NdisInterlockedInsertTailList
+#undef NdisInterlockedRemoveHeadList
+#undef NdisInterlockedPushEntryList
+#undef NdisInterlockedPopEntryList
+
+VOID
+NdisAllocateSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+ INITIALIZE_SPIN_LOCK(&SpinLock->SpinLock);
+}
+
+VOID
+NdisFreeSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+ UNREFERENCED_PARAMETER(SpinLock);
+}
+
+VOID
+NdisAcquireSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+ NDIS_ACQUIRE_SPIN_LOCK(SpinLock, &SpinLock->OldIrql);
+}
+
+VOID
+NdisReleaseSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+ NDIS_RELEASE_SPIN_LOCK(SpinLock, SpinLock->OldIrql);
+}
+
+VOID
+NdisDprAcquireSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(SpinLock);
+ SpinLock->OldIrql = DISPATCH_LEVEL;
+}
+
+VOID
+NdisDprReleaseSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+ NDIS_RELEASE_SPIN_LOCK_DPC(SpinLock);
+}
+
+VOID
+NdisFreeBuffer(
+ IN PNDIS_BUFFER Buffer
+ )
+{
+ IoFreeMdl(Buffer);
+}
+
+VOID
+NdisQueryBuffer(
+ IN PNDIS_BUFFER Buffer,
+ OUT PVOID * VirtualAddress OPTIONAL,
+ OUT PUINT Length
+ )
+{
+ if (ARGUMENT_PRESENT(VirtualAddress))
+ {
+ *VirtualAddress = MDL_ADDRESS(Buffer);
+ }
+ *Length = MDL_SIZE(Buffer);
+}
+
+VOID
+NdisQueryBufferOffset(
+ IN PNDIS_BUFFER Buffer,
+ OUT PUINT Offset,
+ OUT PUINT Length
+ )
+{
+ *Offset = MDL_OFFSET(Buffer);
+ *Length = MDL_SIZE(Buffer);
+}
+
+VOID
+NdisGetFirstBufferFromPacket(
+ IN PNDIS_PACKET Packet,
+ OUT PNDIS_BUFFER * FirstBuffer,
+ OUT PVOID * FirstBufferVA,
+ OUT PUINT FirstBufferLength,
+ OUT PUINT TotalBufferLength
+ )
+{
+ PNDIS_BUFFER pBuf;
+
+ pBuf = Packet->Private.Head;
+ *FirstBuffer = pBuf;
+ *FirstBufferVA = MmGetMdlVirtualAddress(pBuf);
+ *FirstBufferLength =
+ *TotalBufferLength = MmGetMdlByteCount(pBuf);
+ for (pBuf = pBuf->Next;
+ pBuf != NULL;
+ pBuf = pBuf->Next)
+ {
+ *TotalBufferLength += MmGetMdlByteCount(pBuf);
+ }
+}
+
+ULONG
+NDIS_BUFFER_TO_SPAN_PAGES(
+ IN PNDIS_BUFFER Buffer
+ )
+{
+ if (MDL_SIZE(Buffer) == 0)
+ {
+ return 1;
+ }
+ return COMPUTE_PAGES_SPANNED(MDL_VA(Buffer), MDL_SIZE(Buffer));
+}
+
+VOID
+NdisGetBufferPhysicalArraySize(
+ IN PNDIS_BUFFER Buffer,
+ OUT PUINT ArraySize
+ )
+{
+ if (MDL_SIZE(Buffer) == 0)
+ {
+ *ArraySize = 1;
+ }
+ else
+ {
+ *ArraySize = COMPUTE_PAGES_SPANNED(MDL_VA(Buffer), MDL_SIZE(Buffer));
+ }
+}
+
+BOOLEAN
+NdisEqualString(
+ IN PNDIS_STRING String1,
+ IN PNDIS_STRING String2,
+ IN BOOLEAN CaseInsensitive
+ )
+{
+ return RtlEqualUnicodeString(String1, String2, CaseInsensitive);
+}
+
+VOID
+NdisInitAnsiString(
+ IN OUT PANSI_STRING DestinationString,
+ IN PCSZ SourceString
+ )
+{
+ RtlInitAnsiString(DestinationString, SourceString);
+}
+
+VOID
+NdisInitUnicodeString(
+ IN OUT PUNICODE_STRING DestinationString,
+ IN PCWSTR SourceString
+ )
+{
+
+ RtlInitUnicodeString(DestinationString, SourceString);
+}
+
+NDIS_STATUS
+NdisAnsiStringToUnicodeString(
+ IN OUT PUNICODE_STRING DestinationString,
+ IN PANSI_STRING SourceString
+ )
+{
+ NDIS_STATUS Status;
+
+ Status = RtlAnsiStringToUnicodeString(DestinationString,
+ SourceString,
+ FALSE);
+ return Status;
+}
+
+NDIS_STATUS
+NdisUnicodeStringToAnsiString(
+ IN OUT PANSI_STRING DestinationString,
+ IN PUNICODE_STRING SourceString
+ )
+{
+ NDIS_STATUS Status;
+
+ Status = RtlUnicodeStringToAnsiString(DestinationString,
+ SourceString,
+ FALSE);
+ return Status;
+}
+
+VOID
+NdisMStartBufferPhysicalMapping(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG PhysicalMapRegister,
+ IN BOOLEAN WriteToDevice,
+ OUT PNDIS_PHYSICAL_ADDRESS_UNIT PhysicalAddressArray,
+ OUT PUINT ArraySize
+ )
+{
+ NdisMStartBufferPhysicalMappingMacro(MiniportAdapterHandle,
+ Buffer,
+ PhysicalMapRegister,
+ WriteToDevice,
+ PhysicalAddressArray,
+ ArraySize);
+}
+
+VOID
+NdisMCompleteBufferPhysicalMapping(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG PhysicalMapRegister
+ )
+{
+ NdisMCompleteBufferPhysicalMappingMacro(MiniportAdapterHandle,
+ Buffer,
+ PhysicalMapRegister);
+}
+
+
+ULONG
+NdisInterlockedIncrement(
+ IN PULONG Addend
+ )
+/*++
+
+ Return Value:
+
+ (eax) < 0 (but not necessarily -1) if result of add < 0
+ (eax) == 0 if result of add == 0
+ (eax) > 0 (but not necessarily +1) if result of add > 0
+
+--*/
+{
+ return(InterlockedIncrement(Addend));
+}
+
+ULONG
+NdisInterlockedDecrement(
+ IN PULONG Addend
+ )
+/*++
+
+ Return Value:
+
+ (eax) < 0 (but not necessarily -1) if result of add < 0
+ (eax) == 0 if result of add == 0
+ (eax) > 0 (but not necessarily +1) if result of add > 0
+
+--*/
+{
+ return(InterlockedDecrement(Addend));
+}
+
+ULONG
+NdisInterlockedAddUlong(
+ IN PULONG Addend,
+ IN ULONG Increment,
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+ return(ExInterlockedAddUlong(Addend,Increment, &SpinLock->SpinLock));
+
+}
+
+PLIST_ENTRY
+NdisInterlockedInsertHeadList(
+ IN PLIST_ENTRY ListHead,
+ IN PLIST_ENTRY ListEntry,
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+
+ return(ExInterlockedInsertHeadList(ListHead,ListEntry,&SpinLock->SpinLock));
+
+}
+
+PLIST_ENTRY
+NdisInterlockedInsertTailList(
+ IN PLIST_ENTRY ListHead,
+ IN PLIST_ENTRY ListEntry,
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+ return(ExInterlockedInsertTailList(ListHead,ListEntry,&SpinLock->SpinLock));
+}
+
+PLIST_ENTRY
+NdisInterlockedRemoveHeadList(
+ IN PLIST_ENTRY ListHead,
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+ return(ExInterlockedRemoveHeadList(ListHead, &SpinLock->SpinLock));
+}
+
+PSINGLE_LIST_ENTRY
+NdisInterlockedPushEntryList(
+ IN PSINGLE_LIST_ENTRY ListHead,
+ IN PSINGLE_LIST_ENTRY ListEntry,
+ IN PNDIS_SPIN_LOCK Lock
+ )
+{
+ return(ExInterlockedPushEntryList(ListHead, ListEntry, &Lock->SpinLock));
+}
+
+PSINGLE_LIST_ENTRY
+NdisInterlockedPopEntryList(
+ IN PSINGLE_LIST_ENTRY ListHead,
+ IN PNDIS_SPIN_LOCK Lock
+ )
+{
+ return(ExInterlockedPopEntryList(ListHead, &Lock->SpinLock));
+}
+
+//
+// Logging support for miniports
+//
+
+NDIS_STATUS
+NdisMCreateLog(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN UINT Size,
+ OUT PNDIS_HANDLE LogHandle
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_LOG Log = NULL;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ if (Miniport->Log != NULL)
+ {
+ Status = NDIS_STATUS_FAILURE;
+ }
+ else
+ {
+ Log = ALLOC_FROM_POOL(sizeof(NDIS_LOG) + Size, NDIS_TAG_DBG_LOG);
+ if (Log != NULL)
+ {
+ Status = NDIS_STATUS_SUCCESS;
+ Miniport->Log = Log;
+ INITIALIZE_SPIN_LOCK(&Log->LogLock);
+ Log->Miniport = Miniport;
+ Log->Irp = NULL;
+ Log->TotalSize = Size;
+ Log->CurrentSize = 0;
+ Log->InPtr = 0;
+ Log->OutPtr = 0;
+ }
+ else
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ }
+ }
+
+ *LogHandle = Log;
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ return Status;
+}
+
+
+VOID
+NdisMCloseLog(
+ IN NDIS_HANDLE LogHandle
+ )
+{
+ PNDIS_LOG Log = (PNDIS_LOG)LogHandle;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ KIRQL OldIrql;
+
+ Miniport = Log->Miniport;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+ Miniport->Log = NULL;
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ FREE_POOL(Log);
+}
+
+
+NDIS_STATUS
+NdisMWriteLogData(
+ IN NDIS_HANDLE LogHandle,
+ IN PVOID LogBuffer,
+ IN UINT LogBufferSize
+ )
+{
+ PNDIS_LOG Log = (PNDIS_LOG)LogHandle;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+ UINT AmtToCopy;
+
+ ACQUIRE_SPIN_LOCK(&Log->LogLock, &OldIrql);
+
+ if (LogBufferSize <= Log->TotalSize)
+ {
+ if (LogBufferSize <= (Log->TotalSize - Log->InPtr))
+ {
+ //
+ // Can copy the entire buffer
+ //
+ CopyMemory(Log->LogBuf+Log->InPtr, LogBuffer, LogBufferSize);
+ }
+ else
+ {
+ //
+ // We are going to wrap around. Copy it in two chunks.
+ //
+ AmtToCopy = Log->TotalSize - Log->InPtr;
+ CopyMemory(Log->LogBuf+Log->InPtr,
+ LogBuffer,
+ AmtToCopy);
+ CopyMemory(Log->LogBuf + 0,
+ (PUCHAR)LogBuffer+AmtToCopy,
+ LogBufferSize - AmtToCopy);
+ }
+
+ //
+ // Update the current size
+ //
+ Log->CurrentSize += LogBufferSize;
+ if (Log->CurrentSize > Log->TotalSize)
+ Log->CurrentSize = Log->TotalSize;
+
+ //
+ // Update the InPtr and possibly the outptr
+ //
+ Log->InPtr += LogBufferSize;
+ if (Log->InPtr >= Log->TotalSize)
+ {
+ Log->InPtr -= Log->TotalSize;
+ }
+
+ if (Log->CurrentSize == Log->TotalSize)
+ {
+ Log->OutPtr = Log->InPtr;
+ }
+
+ //
+ // Check if there is a pending Irp to complete
+ //
+ if (Log->Irp != NULL)
+ {
+ PIRP Irp = Log->Irp;
+
+ Log->Irp = NULL;
+
+ //
+ // If the InPtr is lagging the OutPtr. then we can simply
+ // copy the data over in one shot.
+ //
+ AmtToCopy = MDL_SIZE(Irp->MdlAddress);
+ if (AmtToCopy > Log->CurrentSize)
+ AmtToCopy = Log->CurrentSize;
+ if ((Log->TotalSize - Log->OutPtr) >= AmtToCopy)
+ {
+ CopyMemory(MDL_ADDRESS(Irp->MdlAddress),
+ Log->LogBuf+Log->OutPtr,
+ AmtToCopy);
+ }
+ else
+ {
+ CopyMemory(MDL_ADDRESS(Irp->MdlAddress),
+ Log->LogBuf+Log->OutPtr,
+ Log->TotalSize-Log->OutPtr);
+ CopyMemory((PUCHAR)MDL_ADDRESS(Irp->MdlAddress)+Log->TotalSize-Log->OutPtr,
+ Log->LogBuf,
+ AmtToCopy - (Log->TotalSize-Log->OutPtr));
+ }
+ Log->CurrentSize -= AmtToCopy;
+ Log->OutPtr += AmtToCopy;
+ if (Log->OutPtr >= Log->TotalSize)
+ Log->OutPtr -= Log->TotalSize;
+ Irp->IoStatus.Information = AmtToCopy;
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+ }
+ }
+ else
+ {
+ Status = NDIS_STATUS_BUFFER_OVERFLOW;
+ }
+
+ RELEASE_SPIN_LOCK(&Log->LogLock, OldIrql);
+
+ return Status;
+}
+
+VOID
+NdisMFlushLog(
+ IN NDIS_HANDLE LogHandle
+ )
+{
+ PNDIS_LOG Log = (PNDIS_LOG)LogHandle;
+ KIRQL OldIrql;
+
+ ACQUIRE_SPIN_LOCK(&Log->LogLock, &OldIrql);
+ Log->InPtr = 0;
+ Log->OutPtr = 0;
+ Log->CurrentSize = 0;
+ RELEASE_SPIN_LOCK(&Log->LogLock, OldIrql);
+}
+
diff --git a/private/ntos/ndis/ndis40/mp/makefile b/private/ntos/ndis/ndis40/mp/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/ndis40/mp/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/ndis40/mp/ndis.prf b/private/ntos/ndis/ndis40/mp/ndis.prf
new file mode 100644
index 000000000..7c294f08e
--- /dev/null
+++ b/private/ntos/ndis/ndis40/mp/ndis.prf
@@ -0,0 +1,136 @@
+_allmul
+NdisQueryBuffer@12
+@InterlockedDecrement@4
+NdisQueryBufferOffset@12
+@InterlockedIncrement@4
+@InterlockedExchange@8
+NDIS_BUFFER_TO_SPAN_PAGES@4
+NdisAllocateBuffer@20
+NdisSetTimer@8
+NdisUnchainBufferAtFront@8
+@ndisMSyncSend@8
+@ndisMProcessDeferredPrioritySends@4
+ndisMIsr@8
+@ndisMQueueWorkItem@16
+ndisMDpc@16
+@ndisMIsLoopbackPacket@8
+@ndisMStartSends@4
+@ndisMProcessDeferred@4
+ndisMWakeUpDpc@16
+NdisMSendComplete@12
+@ndisMDeQueueWorkItem@16
+NdisMSendResourcesAvailable@4
+NdisMStartBufferPhysicalMapping@24
+NdisMCompleteBufferPhysicalMapping@12
+ndisMDeferredTimerDpc@16
+@ndisMIndicateLoopback@4
+ndisMCopyFromPacketToBuffer@20
+ndisMTimerDpc@16
+ndisMSend@8
+EthFilterDprIndicateReceiveComplete@4
+EthFilterDprIndicateReceivePacket@12
+NdisReturnPackets@8
+NdisAllocateMemory@20
+NdisWritePciSlotInformation@20
+NdisCopyBuffer@24
+NdisUnchainBufferAtBack@8
+NdisDereferenceRef@4
+ndisAllocationExecutionRoutine@16
+ndisDereferencePackage@4
+ndisReportResources@20
+ndisAddResource@28
+NdisFreeMemory@12
+ndisMFinishPendingOpen@4
+NdisAllocateBufferPool@12
+ndisMFinishQueuedPendingOpen@4
+NdisAllocateSharedMemory@20
+NdisSystemProcessorCount@0
+NdisInitializeTimer@12
+NdisMSetPeriodicTimer@8
+NdisInitializeRef@4
+NdisFreeBufferPool@4
+NdisAllocatePacket@12
+NdisAllocatePacketPool@16
+NdisCopyFromPacketToPacket@24
+ndisReferencePackage@4
+NdisReadPciSlotInformation@20
+NdisReferenceRef@4
+ndisMRequestQueryInformationPost@12
+DriverEntry@8
+ndisReadParameters@24
+ndisReadRegistry@0
+ArcCreateFilter@24
+ArcDeleteFilter@4
+ndisMQueryMaximumTotalSize@8
+TrCreateFilter@28
+NdisMRegisterMiniport@12
+ethUpdateBroadcastBindingList@12
+EthCreateFilter@28
+EthNoteFilterOpenAdapter@16
+EthDeleteFilter@4
+ethUpdateDirectedBindingList@12
+ethUpdateSpecificBindingLists@8
+NdisOpenAdapter@44
+ndisDereferenceProtocol@4
+NdisRegisterProtocol@16
+NdisMRegisterAdapterShutdownHandler@12
+ndisMSetInformation@8
+ndisMSyncQueryInformationComplete@8
+NdisIMRegisterLayeredMiniport@16
+ndisMQueryMaximumFrameSize@8
+ndisDereferenceMiniport@4
+ndisMDoRequests@4
+TrDeleteFilter@4
+ndisMQueueRequest@12
+NdisMInitializeTimer@16
+NdisMRegisterInterrupt@28
+ndisDereferenceDriver@4
+ndisQueueMiniportOnDriver@8
+NdisMAllocateSharedMemory@20
+ndisMChangeClass@20
+NdisMRegisterIoPortRange@16
+ndisMRequest@8
+FddiCreateFilter@36
+ndisMSetCurrentLookahead@8
+FddiDeleteFilter@4
+ndisMQueryNetworkAddress@8
+@ndisMQueueNewWorkItem@16
+ndisMSetPacketFilter@8
+EthFilterAdjust@20
+ndisMRequestSetInformationPost@12
+ndisMSyncSetInformationComplete@8
+ndisSaveParameters@24
+ndisQueueOpenOnProtocol@8
+NdisInitializeInterrupt@40
+ndisUpdateDriverInstance@16
+ndisMDummyTransferData@24
+ndisCheckRoute@24
+NdisOpenConfiguration@12
+NdisInitializeWrapper@16
+ndisProtocolAlreadyBound@8
+NdisOverrideBusNumber@12
+ndisSaveLinkage@24
+ndisMInitializeAdapter@16
+ndisMOpenAdapter@48
+ndisMDoMiniportOp@24
+NdisMAllocateMapRegisters@20
+ndisCreateIrpHandler@8
+ndisSuccessIrpHandler@8
+ndisInitializePackage@8
+ndisDispatchRequest@8
+NdisRegisterTdiCallBack@4
+ndisQueuedProtocolNotification@4
+ndisHandlePnPRequest@4
+ndisHandleLegacyTransport@4
+ndisHandleProtocolNotification@4
+NdisReadNetworkAddress@16
+NdisCloseConfiguration@4
+ndisInitializeAdapter@8
+NdisReadConfiguration@20
+ndisInitializeBindings@12
+ndisCheckProtocolBinding@16
+NdisMSetAttributes@16
+ndisMUndoBogusFilters@4
+ndisInitializeAllAdapterInstances@8
+ndisMQueryInformation@8
+ndisMDpcTimer@16
diff --git a/private/ntos/ndis/ndis40/mp/sources b/private/ntos/ndis/ndis40/mp/sources
new file mode 100644
index 000000000..dc48d81bb
--- /dev/null
+++ b/private/ntos/ndis/ndis40/mp/sources
@@ -0,0 +1,29 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+NT_UP=0
+
+TARGETPATH=\nt\public\sdk\lib
+
+!include ..\sources.inc
diff --git a/private/ntos/ndis/ndis40/ndis.c b/private/ntos/ndis/ndis40/ndis.c
new file mode 100644
index 000000000..4b5a8a83b
--- /dev/null
+++ b/private/ntos/ndis/ndis40/ndis.c
@@ -0,0 +1,1349 @@
+/*++
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ndis.c
+
+Abstract:
+
+ NDIS wrapper functions
+
+Author:
+
+ Adam Barr (adamba) 11-Jul-1990
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ 10-Jul-1995 JameelH Make NDIS.SYS a device-driver and add PnP support
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_NDIS
+
+#define NDIS_DEVICE_NAME L"\\Device\\Ndis"
+#define NDIS_SYMBOLIC_NAME L"\\DosDevices\\NDIS"
+
+PDEVICE_OBJECT ndisDeviceObject = NULL;
+PDRIVER_OBJECT ndisDriverObject = NULL;
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+/*++
+
+Routine Description:
+
+ NDIS wrapper driver entry point.
+
+Arguments:
+
+ DriverObject - Pointer to the driver object created by the system.
+ RegistryPath - Pointer to the registry section where the parameters reside.
+
+Return Value:
+
+ Return value from IoCreateDevice
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ UNICODE_STRING DeviceName;
+ UINT i;
+
+ // Create the device object.
+ RtlInitUnicodeString(&DeviceName, NDIS_DEVICE_NAME);
+
+ ndisDriverObject = DriverObject;
+ Status = IoCreateDevice(DriverObject, // DriverObject
+ 0, // DeviceExtension
+ &DeviceName, // DeviceName
+ FILE_DEVICE_NETWORK,// DeviceType
+ 0, // DeviceCharacteristics
+ FALSE, // Exclusive
+ &ndisDeviceObject); // DeviceObject
+
+ if (NT_SUCCESS(Status))
+ {
+ UNICODE_STRING SymbolicLinkName;
+
+ // Create a symbolic link to this device
+ RtlInitUnicodeString(&SymbolicLinkName, NDIS_SYMBOLIC_NAME);
+ Status = IoCreateSymbolicLink(&SymbolicLinkName, &DeviceName);
+
+ // Initialize the driver object for this file system driver.
+ for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
+ {
+ DriverObject->MajorFunction[i] = ndisDispatchRequest;
+ }
+ // For now make this unloadable
+ DriverObject->DriverUnload = NULL;
+
+ INITIALIZE_SPIN_LOCK(&ndisDriverListLock);
+ INITIALIZE_SPIN_LOCK(&ndisGlobalDbLock);
+
+ ndisDmaAlignment = HalGetDmaAlignmentRequirement();
+ if (sizeof(ULONG) > ndisDmaAlignment)
+ {
+ ndisDmaAlignment = sizeof(ULONG);
+ }
+
+ ProtocolInitializePackage();
+ ArcInitializePackage();
+ EthInitializePackage();
+ FddiInitializePackage();
+ TrInitializePackage();
+ MiniportInitializePackage();
+ InitInitializePackage();
+ PnPInitializePackage();
+ MacInitializePackage();
+ CoInitializePackage();
+
+#if DBG
+ //
+ // set the offset to the debug information...
+ //
+ ndisDebugInformationOffset = FIELD_OFFSET(NDIS_MINIPORT_BLOCK, Reserved);
+#endif
+
+#if defined(_ALPHA_)
+ INITIALIZE_SPIN_LOCK(&ndisLookaheadBufferLock);
+#endif
+
+ ExInitializeResource(&SharedMemoryResource);
+
+ INITIALIZE_SPIN_LOCK(&ndisGlobalOpenListLock);
+
+ ndisReadRegistry();
+ Status = STATUS_SUCCESS;
+ }
+
+ return Status;
+}
+
+
+VOID
+ndisReadRegistry(
+ VOID
+ )
+{
+ NTSTATUS RegStatus;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[3];
+ UINT c;
+ ULONG DefaultZero = 0;
+
+ //
+ // First we need to initialize the processor information incase
+ // the registry is empty.
+ //
+ for (c = 0; c < **((PUCHAR *)&KeNumberProcessors); c++)
+ {
+ ndisValidProcessors[c] = c;
+ }
+
+ ndisCurrentProcessor = ndisMaximumProcessor = c - 1;
+
+ //
+ // 1) Switch to the MediaTypes key below the service (NDIS) key
+ //
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = L"MediaTypes";
+
+ //
+ // Setup to enumerate the values in the registry section (shown above).
+ // For each such value, we'll add it to the ndisMediumArray
+ //
+ QueryTable[1].QueryRoutine = ndisAddMediaTypeToArray;
+ QueryTable[1].DefaultType = REG_DWORD;
+ QueryTable[1].DefaultData = (PVOID)&DefaultZero;
+ QueryTable[1].DefaultLength = 0;
+ QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ QueryTable[1].Name = NULL;
+
+ //
+ // Query terminator
+ //
+ QueryTable[2].QueryRoutine = NULL;
+ QueryTable[2].Flags = 0;
+ QueryTable[2].Name = NULL;
+
+ //
+ // The rest of the work is done in the callback routine ndisAddMediaTypeToArray.
+ //
+ RegStatus = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
+ L"NDIS",
+ QueryTable,
+ (PVOID)NULL, // no context needed
+ NULL);
+ //
+ // Switch to the parameters key below the service (NDIS) key and
+ // read the processor affinity.
+ //
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = L"Parameters";
+
+ QueryTable[1].QueryRoutine = ndisReadParameters;
+ QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ QueryTable[1].DefaultData = (PVOID)&DefaultZero;
+ QueryTable[1].DefaultLength = 0;
+ QueryTable[1].DefaultType = REG_DWORD;
+ QueryTable[1].Name = L"ProcessorAffinityMask";
+
+ //
+ // Query terminator
+ //
+ QueryTable[2].QueryRoutine = NULL;
+ QueryTable[2].Flags = 0;
+ QueryTable[2].Name = NULL;
+
+ //
+ // The rest of the work is done in the callback routine ndisReadParameters
+ //
+ RegStatus = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
+ L"NDIS",
+ QueryTable,
+ (PVOID)NULL, // no context needed
+ NULL);
+}
+
+
+NTSTATUS
+ndisReadParameters(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ //
+ // If we have valid data then build our array of valid processors
+ // to use.... Treat the special case of 0 to signify no processor
+ // affinity - i.e. use defaults.
+ //
+ if ((REG_DWORD == ValueType) && (ValueData != NULL))
+ {
+ if (*(PULONG)ValueData == 0)
+ {
+ ndisSkipProcessorAffinity = TRUE;
+ }
+ else
+ {
+ ULONG ProcessorAffinity;
+ UINT c1, c2;
+
+ //
+ // Save the processor affinity.
+ //
+ ProcessorAffinity = *(PULONG)ValueData;
+
+ //
+ // Fill in the valid processor array.
+ //
+ for (c1 = c2 = 0;
+ (c1 <= ndisMaximumProcessor) && (ProcessorAffinity != 0);
+ c1++)
+ {
+ if (ProcessorAffinity & 1)
+ {
+ ndisValidProcessors[c2++] = c1;
+ }
+ ProcessorAffinity >>= 1;
+ }
+
+ ndisCurrentProcessor = ndisMaximumProcessor = c2 - 1;
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+ndisAddMediaTypeToArray(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+{
+#if DBG
+ NDIS_STRING Str;
+
+ RtlInitUnicodeString(&Str, ValueName);
+#endif
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("ExperimentalMediaType %Z - %x\n", &Str, *(PULONG)ValueData));
+
+ //
+ // Ignore all values that we already know about. These should not be in the
+ // registry anyway, but just in case somebody is messing with it.
+ //
+ if ((ValueType == REG_DWORD) && (ValueData != NULL) && (*(PULONG)ValueData > NdisMediumIrda))
+ {
+ NDIS_MEDIUM *pTemp;
+ ULONG size;
+
+ //
+ // See if we have enough space to add this value. If not allocate space for the
+ // new array, copy the old one into this (and free the old if not static).
+ //
+ ASSERT (ndisMediumArraySize <= ndisMediumArrayMaxSize);
+
+ //
+ // Check for duplicates. If so drop it
+ //
+ for (pTemp = ndisMediumArray, size = ndisMediumArraySize;
+ size > 0; pTemp ++, size -= sizeof(NDIS_MEDIUM))
+ {
+ if (*(NDIS_MEDIUM *)ValueData == *pTemp)
+ {
+ //
+ // Duplicate.
+ //
+ return STATUS_SUCCESS;
+ }
+ }
+
+ if (ndisMediumArraySize == ndisMediumArrayMaxSize)
+ {
+ //
+ // We do not have any space in the array. Need to re-alloc. Be generous.
+ //
+ pTemp = (NDIS_MEDIUM *)ALLOC_FROM_POOL(ndisMediumArraySize + EXPERIMENTAL_SIZE*sizeof(NDIS_MEDIUM),
+ NDIS_TAG_DEFAULT);
+ if (pTemp != NULL)
+ {
+ CopyMemory(pTemp, ndisMediumArray, ndisMediumArraySize);
+ if (ndisMediumArray != ndisMediumBuffer)
+ {
+ FREE_POOL(ndisMediumArray);
+ }
+ ndisMediumArray = pTemp;
+ }
+ }
+ if (ndisMediumArraySize < ndisMediumArrayMaxSize)
+ {
+ ndisMediumArray[ndisMediumArraySize/sizeof(NDIS_MEDIUM)] = *(NDIS_MEDIUM *)ValueData;
+ ndisMediumArraySize += sizeof(NDIS_MEDIUM);
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+ndisDispatchRequest(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description:
+
+ Dispatcher for Irps intended for the NDIS Device.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PIO_STACK_LOCATION pIrpSp;
+ static LONG OpenCount = 0;
+ static KSPIN_LOCK Lock = {0};
+
+ pDeviceObject; // prevent compiler warnings
+
+ PAGED_CODE( );
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pIrp->IoStatus.Status = STATUS_PENDING;
+ pIrp->IoStatus.Information = 0;
+
+ PnPReferencePackage();
+
+ switch (pIrpSp->MajorFunction)
+ {
+ case IRP_MJ_CREATE:
+ Increment(&OpenCount, &Lock);
+ break;
+
+ case IRP_MJ_CLEANUP:
+ Decrement(&OpenCount, &Lock);
+ break;
+
+ case IRP_MJ_CLOSE:
+ break;
+
+ case IRP_MJ_INTERNAL_DEVICE_CONTROL:
+ break;
+
+ case IRP_MJ_DEVICE_CONTROL:
+ Status = ndisHandlePnPRequest(pIrp);
+ break;
+
+ default:
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+ }
+
+ ASSERT (CURRENT_IRQL < DISPATCH_LEVEL);
+ ASSERT (Status != STATUS_PENDING);
+
+ pIrp->IoStatus.Status = Status;
+ IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
+
+ PnPDereferencePackage();
+
+ return Status;
+}
+
+
+NTSTATUS
+ndisHandlePnPRequest(
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description:
+
+ Handler for PnP ioctls.
+
+Arguments:
+
+ We get the following IOCTLS today.
+
+ - Load driver (and initiate bindings to transports)
+ - Unbind from all transports and unload driver
+ - Translate name
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PIO_STACK_LOCATION pIrpSp;
+ UNICODE_STRING Device;
+ ULONG Method;
+ PVOID pBuf;
+ UINT iBufLen, oBufLen;
+ UINT AmtCopied;
+
+ PAGED_CODE( );
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+
+ Method = pIrpSp->Parameters.DeviceIoControl.IoControlCode & 3;
+
+ // Ensure that the method is buffered - we always use that.
+ if (Method == METHOD_BUFFERED)
+ {
+ // Get the output buffer and its length. Input and Output buffers are
+ // both pointed to by the SystemBuffer
+ iBufLen = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
+ oBufLen = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+ pBuf = pIrp->AssociatedIrp.SystemBuffer;
+ }
+ else
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ RtlInitUnicodeString(&Device, pBuf);
+ }
+ except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return STATUS_ACCESS_VIOLATION;
+ }
+
+ switch (pIrpSp->Parameters.DeviceIoControl.IoControlCode)
+ {
+ case IOCTL_NDIS_ADD_DEVICE:
+ Status = ndisHandleLoadDriver(&Device);
+ break;
+
+ case IOCTL_NDIS_DELETE_DEVICE:
+ Status = ndisHandleUnloadDriver(&Device);
+ break;
+
+ case IOCTL_NDIS_ADD_TDI_DEVICE:
+ Status = ndisHandleLegacyTransport(&Device);
+ break;
+
+ case IOCTL_NDIS_NOTIFY_PROTOCOL:
+ Status = ndisHandleProtocolNotification(&Device);
+ break;
+
+ case IOCTL_NDIS_TRANSLATE_NAME:
+ Status = ndisHandleTranslateName(&Device,
+ pBuf,
+ oBufLen,
+ &AmtCopied);
+ pIrp->IoStatus.Information = AmtCopied;
+ break;
+
+ default:
+ break;
+ }
+
+ ASSERT (CURRENT_IRQL < DISPATCH_LEVEL);
+ return Status;
+}
+
+
+
+NTSTATUS
+ndisHandleLoadDriver(
+ IN PUNICODE_STRING pDevice
+ )
+/*++
+
+Routine Description:
+
+ Load the driver and initiate binding to all protocols bound to it.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ KIRQL OldIrql;
+ PNDIS_M_DRIVER_BLOCK MiniBlock;
+ PNDIS_MAC_BLOCK MacBlock;
+ UNICODE_STRING UpcaseDevice;
+ BOOLEAN fLoaded = FALSE;
+
+ //
+ // Map the device name to the driver. Search the miniport list first and then
+ // the mac list. The string passed to us is the name of the registry section
+ // of the specific driver to load. For e.g. if the driver being loaded is
+ // ELNK31, the string passed to us is: Elnk31. We first need to upper case the
+ // string before comparing since we cannot do case-insensitive comparisons at
+ // raised irql. The driver block has the registry path to the real driver -
+ // in this example Elnk3. The task is to correlate Elnk31 with Elnk3. We also
+ // cannot make an assumption about how many digits that follow. Also a prefix
+ // check itself is not enough since some drivers have a trailing digit at the
+ // end. Consider the case of two drivers in the system, IBMTOK and IBMTOK2.
+ // Single instances of these two in the machine could generate
+ // IBMTOK21 and IBMTOK2. So matching IBMTOK2 to IBMTOK2 is incorrect - IBMTOK2
+ // has to be matched with IBMTOK21. Oh, joy !!!
+ //
+ // Add to complicate matters further, the Service controller could call us
+ // to load a device that is already loaded. Ignore such requests.
+ //
+
+ Status = RtlUpcaseUnicodeString(&UpcaseDevice, pDevice, TRUE);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ do
+ {
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+
+ for (MiniBlock = ndisMiniDriverList;
+ MiniBlock != NULL;
+ MiniBlock = MiniBlock->NextDriver)
+ {
+ if ((UpcaseDevice.Length > MiniBlock->BaseName.Length) &&
+ RtlPrefixUnicodeString(&MiniBlock->BaseName, &UpcaseDevice, FALSE))
+ {
+ PNDIS_MINIPORT_BLOCK Miniport;
+
+ //
+ // Check if we already have this device
+ //
+
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(&MiniBlock->Ref.SpinLock);
+
+ for (Miniport = MiniBlock->MiniportQueue;
+ Miniport != NULL;
+ Miniport = Miniport->NextMiniport)
+ {
+ if (NDIS_EQUAL_UNICODE_STRING(&UpcaseDevice, &Miniport->BaseName))
+ {
+ fLoaded = TRUE;
+ break; // Found it.
+ }
+ }
+
+ NDIS_RELEASE_SPIN_LOCK_DPC(&MiniBlock->Ref.SpinLock);
+
+ if (fLoaded || !ndisReferenceDriver(MiniBlock))
+ {
+ MiniBlock = NULL;
+ }
+ break; // Found it.
+ }
+ }
+
+ if (MiniBlock != NULL)
+ break;
+
+ for (MacBlock = ndisMacDriverList;
+ MacBlock != NULL;
+ MacBlock = MacBlock->NextMac)
+ {
+ if ((UpcaseDevice.Length > MacBlock->BaseName.Length) &&
+ RtlPrefixUnicodeString(&MacBlock->BaseName, &UpcaseDevice, FALSE))
+ {
+ PNDIS_ADAPTER_BLOCK Mac;
+
+ //
+ // Check if we already have this device
+ //
+
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(&MacBlock->Ref.SpinLock);
+
+ for (Mac = MacBlock->AdapterQueue;
+ Mac != NULL;
+ Mac = Mac->NextAdapter)
+ {
+ if (NDIS_EQUAL_UNICODE_STRING(&UpcaseDevice, &Mac->BaseName))
+ {
+ fLoaded = TRUE;
+ break; // Found it.
+ }
+ }
+
+ NDIS_RELEASE_SPIN_LOCK_DPC(&MacBlock->Ref.SpinLock);
+
+ if (fLoaded || !ndisReferenceMac(MacBlock))
+ {
+ MacBlock = NULL;
+ }
+ break; // Found it.
+ }
+ }
+ } while (FALSE);
+
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ if (fLoaded)
+ {
+ return STATUS_SUCCESS;
+ }
+
+ if ((MiniBlock == NULL) && (MacBlock == NULL))
+ {
+ return STATUS_NO_SUCH_DEVICE;
+ }
+
+ Status = ndisInitializeAdapter((MiniBlock != NULL) ?
+ MiniBlock : (PNDIS_M_DRIVER_BLOCK)MacBlock,
+ &UpcaseDevice);
+
+ RtlFreeUnicodeString(&UpcaseDevice);
+
+ if (NT_SUCCESS(Status))
+ {
+ Status = ndisHandleProtocolNotification(pDevice);
+ }
+
+ if (MiniBlock != NULL)
+ {
+ ndisDereferenceDriver(MiniBlock);
+ }
+ else
+ {
+ ndisDereferenceMac(MacBlock);
+ }
+
+ return Status;
+}
+
+
+NTSTATUS
+ndisHandleUnloadDriver(
+ IN PUNICODE_STRING pDevice
+ )
+/*++
+
+Routine Description:
+
+ Unbind all transports from this adapter and unload the driver.
+
+Arguments:
+
+ pDevice - Base name (i.e. without the "\Device\") of the device being unloaded.
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PNDIS_ADAPTER_BLOCK Mac;
+
+ ndisReferenceAdapterOrMiniportByName(pDevice, &Miniport, &Mac);
+
+ if (Miniport != NULL)
+ {
+ Status = ndisUnloadMiniport(Miniport);
+ ndisDereferenceMiniport(Miniport);
+ }
+ else if (Mac != NULL)
+ {
+ Status = ndisUnloadMac(Mac);
+ ndisDereferenceAdapter(Mac);
+ }
+ else
+ {
+ Status = STATUS_NO_SUCH_DEVICE;
+ }
+
+ return Status;
+}
+
+
+NTSTATUS
+ndisHandleTranslateName(
+ IN PUNICODE_STRING pDevice,
+ IN PUCHAR Buffer,
+ IN UINT BufferLength,
+ OUT PUINT AmountCopied
+ )
+/*++
+
+Routine Description:
+
+ Calls the PnP protocols to enumerate PnP ids for the given adapter.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PNDIS_ADAPTER_BLOCK Mac;
+
+ ndisReferenceAdapterOrMiniportByName(pDevice, &Miniport, &Mac);
+
+ if (Miniport != NULL)
+ {
+ Status = ndisTranslateMiniportName(Miniport, Buffer, BufferLength, AmountCopied);
+ ndisDereferenceMiniport(Miniport);
+ }
+ else if (Mac != NULL)
+ {
+ Status = ndisTranslateMacName(Mac, Buffer, BufferLength, AmountCopied);
+ ndisDereferenceAdapter(Mac);
+ }
+ else
+ {
+ Status = STATUS_NO_SUCH_DEVICE;
+ }
+
+ return Status;
+}
+
+
+NTSTATUS
+ndisHandleProtocolNotification(
+ IN PUNICODE_STRING pDevice
+ )
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ KIRQL OldIrql;
+ PNDIS_M_DRIVER_BLOCK MiniBlock;
+ PNDIS_MAC_BLOCK MacBlock;
+ UNICODE_STRING UpcaseDevice;
+
+ Status = RtlUpcaseUnicodeString(&UpcaseDevice, pDevice, TRUE);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ //
+ // The device name passed to us is the 'base' name of the driver e.g. SONIC.
+ // First find the driver structure and walk thru its instances and notify
+ // the protocols bound to it
+ //
+ do
+ {
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+
+ //
+ // Try miniports first
+ //
+ for (MiniBlock = ndisMiniDriverList;
+ MiniBlock != NULL;
+ MiniBlock = MiniBlock->NextDriver)
+ {
+ if (NDIS_EQUAL_UNICODE_STRING(&UpcaseDevice, &MiniBlock->BaseName))
+ {
+ if (!ndisReferenceDriver(MiniBlock))
+ {
+ MiniBlock = NULL;
+ }
+ break;
+ }
+ }
+
+ if (MiniBlock != NULL)
+ {
+ PNDIS_MINIPORT_BLOCK Miniport, NextMiniport;
+
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ NDIS_ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
+
+ for (Miniport = MiniBlock->MiniportQueue;
+ Miniport != NULL;
+ Miniport = NextMiniport)
+ {
+ if (ndisReferenceMiniport(Miniport))
+ {
+ NDIS_RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
+
+ ndisInitializeBindings(&Miniport->MiniportName,
+ &Miniport->BaseName,
+ TRUE);
+
+ NDIS_ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
+ NextMiniport = Miniport->NextMiniport;
+ ndisDereferenceMiniport(Miniport);
+ }
+ else
+ {
+ NextMiniport = Miniport->NextMiniport;
+ }
+ }
+
+ NDIS_RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
+ ndisDereferenceDriver(MiniBlock);
+ break;
+ }
+
+ //
+ // Now try full nic drivers
+ //
+ for (MacBlock = ndisMacDriverList;
+ MacBlock != NULL;
+ MacBlock = MacBlock->NextMac)
+ {
+ if (NDIS_EQUAL_UNICODE_STRING(&UpcaseDevice, &MacBlock->BaseName))
+ {
+ if (!ndisReferenceMac(MacBlock))
+ {
+ MacBlock = NULL;
+ }
+ break;
+ }
+ }
+
+ if (MacBlock != NULL)
+ {
+ PNDIS_ADAPTER_BLOCK Mac, NextMac;
+
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ NDIS_ACQUIRE_SPIN_LOCK(&MacBlock->Ref.SpinLock, &OldIrql);
+
+ for (Mac = MacBlock->AdapterQueue;
+ Mac != NULL;
+ Mac = NextMac)
+ {
+ if (ndisReferenceAdapter(Mac))
+ {
+ NDIS_RELEASE_SPIN_LOCK(&MacBlock->Ref.SpinLock, OldIrql);
+
+ ndisInitializeBindings(&Mac->AdapterName,
+ &Mac->BaseName,
+ TRUE);
+
+ NextMac = Mac->NextAdapter;
+ NDIS_ACQUIRE_SPIN_LOCK(&MacBlock->Ref.SpinLock, &OldIrql);
+ ndisDereferenceAdapter(Mac);
+ }
+ else
+ {
+ NextMac = Mac->NextAdapter;
+ }
+ }
+
+ NDIS_RELEASE_SPIN_LOCK(&MacBlock->Ref.SpinLock, OldIrql);
+ ndisDereferenceMac(MacBlock);
+ break;
+ }
+ else
+ {
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+ }
+ Status = STATUS_NO_SUCH_DEVICE;
+
+ } while (FALSE);
+
+ RtlFreeUnicodeString(&UpcaseDevice);
+
+ return Status;
+}
+
+
+VOID
+ndisReferenceAdapterOrMiniportByName(
+ IN PUNICODE_STRING pDevice,
+ OUT PNDIS_MINIPORT_BLOCK * pMiniport,
+ OUT PNDIS_ADAPTER_BLOCK * pAdapter
+ )
+{
+ NTSTATUS Status;
+ KIRQL OldIrql;
+ PNDIS_M_DRIVER_BLOCK MiniBlock;
+ PNDIS_MINIPORT_BLOCK Miniport = NULL;
+ PNDIS_MAC_BLOCK MacBlock;
+ PNDIS_ADAPTER_BLOCK Mac = NULL;
+ UNICODE_STRING UpcaseDevice;
+
+ *pMiniport = NULL;
+ *pAdapter = NULL;
+
+ Status = RtlUpcaseUnicodeString(&UpcaseDevice, pDevice, TRUE);
+ if (!NT_SUCCESS(Status))
+ {
+ return;
+ }
+
+ do
+ {
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+
+ for (MiniBlock = ndisMiniDriverList;
+ MiniBlock != NULL;
+ MiniBlock = MiniBlock->NextDriver)
+ {
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(&MiniBlock->Ref.SpinLock);
+
+ for (Miniport = MiniBlock->MiniportQueue;
+ Miniport != NULL;
+ Miniport = Miniport->NextMiniport)
+ {
+ if (NDIS_EQUAL_UNICODE_STRING(&UpcaseDevice, &Miniport->BaseName))
+ {
+ if (!ndisReferenceMiniport(Miniport))
+ {
+ Miniport = NULL;
+ }
+ break; // Found it.
+ }
+ }
+
+ NDIS_RELEASE_SPIN_LOCK_DPC(&MiniBlock->Ref.SpinLock);
+
+ if (Miniport != NULL)
+ {
+ *pMiniport = Miniport;
+ break; // Found it.
+ }
+ }
+
+ for (MacBlock = ndisMacDriverList;
+ (Miniport == NULL) && (MacBlock != NULL);
+ MacBlock = MacBlock->NextMac)
+ {
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(&MacBlock->Ref.SpinLock);
+
+ for (Mac = MacBlock->AdapterQueue;
+ Mac != NULL;
+ Mac = Mac->NextAdapter)
+ {
+ if (NDIS_EQUAL_UNICODE_STRING(&UpcaseDevice, &Mac->BaseName))
+ {
+ if (!ndisReferenceMac(Mac))
+ {
+ Mac = NULL;
+ }
+ break; // Found it.
+ }
+ }
+
+ NDIS_RELEASE_SPIN_LOCK_DPC(&MacBlock->Ref.SpinLock);
+
+ if (Mac != NULL)
+ {
+ *pAdapter = Mac;
+ break; // Found it.
+ }
+ }
+ } while (FALSE);
+
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ RtlFreeUnicodeString(&UpcaseDevice);
+}
+
+NTSTATUS
+ndisHandleLegacyTransport(
+ IN PUNICODE_STRING pDevice
+ )
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ RTL_QUERY_REGISTRY_TABLE LinkQueryTable[3];
+ PWSTR Export = NULL;
+ HANDLE TdiHandle;
+
+ //
+ // Set up LinkQueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Linkage key below the xports registry key
+ //
+
+ LinkQueryTable[0].QueryRoutine = NULL;
+ LinkQueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ LinkQueryTable[0].Name = L"Linkage";
+
+ //
+ // 2) Call ndisSaveLinkage for "Export" (as a single multi-string),
+ // which will allocate storage and save the data in Export.
+ //
+
+ LinkQueryTable[1].QueryRoutine = ndisSaveLinkage;
+ LinkQueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ LinkQueryTable[1].Name = L"Export";
+ LinkQueryTable[1].EntryContext = (PVOID)&Export;
+ LinkQueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 3) Stop
+ //
+
+ LinkQueryTable[2].QueryRoutine = NULL;
+ LinkQueryTable[2].Flags = 0;
+ LinkQueryTable[2].Name = NULL;
+
+ do
+ {
+ UNICODE_STRING Us;
+ PWSTR CurExport;
+
+ Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
+ pDevice->Buffer,
+ LinkQueryTable,
+ (PVOID)NULL, // no context needed
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ Status = STATUS_SUCCESS; // Do not complain about TDI drivers which do not
+ break; // have any linkages
+ }
+
+ //
+ // Walk the list of exports and call TdiRegisterDevice for each
+ //
+ for (CurExport = Export;
+ *CurExport != 0;
+ CurExport = (PWCHAR)((PUCHAR)CurExport + Us.MaximumLength))
+ {
+ RtlInitUnicodeString (&Us, CurExport);
+
+ if (ndisTdiRegisterCallback != NULL)
+ {
+ Status = (*ndisTdiRegisterCallback)(&Us, &TdiHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ break;
+ }
+ }
+ }
+ } while (FALSE);
+
+ if (Export != NULL)
+ FREE_POOL(Export);
+
+ return(Status);
+}
+
+
+VOID
+ndisInitializeBindings(
+ IN PUNICODE_STRING ExportName,
+ IN PUNICODE_STRING ServiceName,
+ IN BOOLEAN Synchronous
+ )
+{
+ KIRQL OldIrql;
+ PNDIS_PROTOCOL_BLOCK Protocol, NextProt;
+ PNDIS_BIND_CONTEXT pBindContext, pBindContextHead = NULL;
+ UNICODE_STRING UpcasedName;
+ NTSTATUS Status;
+
+ Status = RtlUpcaseUnicodeString(&UpcasedName, ExportName, TRUE);
+ if (!NT_SUCCESS(Status))
+ {
+ return;
+ }
+
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+
+ for (Protocol = ndisProtocolList;
+ Protocol != NULL;
+ Protocol = NextProt)
+ {
+ NextProt = Protocol->NextProtocol;
+
+ //
+ // Can only do if the protocol has a bind handler
+ // and we can reference it.
+ //
+ if ((Protocol->ProtocolCharacteristics.BindAdapterHandler != NULL) &&
+ ndisReferenceProtocol(Protocol))
+ {
+ UNICODE_STRING ProtocolSection;
+ BOOLEAN Sync;
+
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ //
+ // Check if this protocol has the binding to this adapter and it
+ // is not already bound.
+ //
+ if (ndisCheckProtocolBinding(Protocol,
+ ExportName,
+ ServiceName,
+ &ProtocolSection) &&
+ !ndisProtocolAlreadyBound(Protocol, &UpcasedName))
+ {
+ NDIS_BIND_CONTEXT BindContext; // To handle allocation failures
+
+ //
+ // Attempt to queue this to get the protocols initialzation going
+ // parallel. Always serialize the call-managers since we must wait
+ // for the call-managers to complete their initializations before
+ // indicating to non-call-manager protocols.
+ //
+ Sync = TRUE;
+ if (!Synchronous &&
+ (Protocol->ProtocolCharacteristics.Flags & NDIS_PROTOCOL_CALL_MANAGER) == 0)
+ {
+ pBindContext = ALLOC_FROM_POOL(sizeof(NDIS_BIND_CONTEXT), NDIS_TAG_DEFAULT);
+ Sync = (pBindContext == NULL);
+ }
+
+ if (Sync)
+ {
+ //
+ // Use the local version and do it synchronously
+ //
+ pBindContext = &BindContext;
+ pBindContext->Next = NULL;
+ }
+ else
+ {
+ //
+ // Link it into the list and queue a worker thread to do it
+ //
+ pBindContext->Next = pBindContextHead;
+ pBindContextHead = pBindContext;
+ }
+
+ pBindContext->Protocol = Protocol;
+ pBindContext->ProtocolSection = ProtocolSection;
+ pBindContext->DeviceName = ExportName;
+ INITIALIZE_EVENT(&pBindContext->Event);
+ INITIALIZE_EVENT(&pBindContext->ThreadDoneEvent);
+
+ if (Sync)
+ {
+ //
+ // Initiate binding now
+ //
+ ndisQueuedProtocolNotification(pBindContext);
+ }
+ else
+ {
+ //
+ // Initiate binding in a worker thread
+ //
+ INITIALIZE_WORK_ITEM(&pBindContext->WorkItem,
+ ndisQueuedProtocolNotification,
+ pBindContext);
+ QUEUE_WORK_ITEM(&pBindContext->WorkItem, DelayedWorkQueue);
+ }
+ }
+ else
+ {
+ ndisDereferenceProtocol(Protocol);
+ }
+
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+ }
+ }
+
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ //
+ // Done with the upcased name
+ //
+ RtlFreeUnicodeString(&UpcasedName);
+
+ //
+ // Wait for the worker threads to finish
+ //
+ for (pBindContext = pBindContextHead;
+ pBindContext != NULL;
+ NOTHING)
+ {
+ PNDIS_BIND_CONTEXT pNext;
+
+ pNext = pBindContext->Next;
+
+ WAIT_FOR_OBJECT(&pBindContext->ThreadDoneEvent, NULL);
+ FREE_POOL(pBindContext);
+
+ pBindContext = pNext;
+ }
+}
+
+
+VOID
+ndisQueuedProtocolNotification(
+ IN PNDIS_BIND_CONTEXT pContext
+ )
+{
+ NDIS_STATUS BindStatus;
+
+ //
+ // Call the protocol to bind to the adapter
+ //
+ WAIT_FOR_OBJECT(&pContext->Protocol->Mutex, NULL);
+
+ if (!pContext->Protocol->Ref.Closing)
+ {
+ (*pContext->Protocol->ProtocolCharacteristics.BindAdapterHandler)(&BindStatus,
+ pContext,
+ pContext->DeviceName,
+ &pContext->ProtocolSection,
+ NULL);
+ if (BindStatus == NDIS_STATUS_PENDING)
+ {
+ WAIT_FOR_OBJECT(&pContext->Event, NULL);
+ }
+ }
+
+ RELEASE_MUTEX(&pContext->Protocol->Mutex);
+
+ ndisDereferenceProtocol(pContext->Protocol);
+
+ FREE_POOL(pContext->ProtocolSection.Buffer);
+
+ SET_EVENT(&pContext->ThreadDoneEvent);
+}
+
+VOID
+NdisCompleteBindAdapter(
+ IN NDIS_HANDLE BindAdapterContext,
+ IN NDIS_STATUS Status,
+ IN NDIS_STATUS OpenStatus
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_BIND_CONTEXT pContext = (PNDIS_BIND_CONTEXT)BindAdapterContext;
+
+ pContext->BindStatus = Status;
+ SET_EVENT(&pContext->Event);
+}
+
+VOID
+NdisCompleteUnbindAdapter(
+ IN NDIS_HANDLE UnbindAdapterContext,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_BIND_CONTEXT pContext = (PNDIS_BIND_CONTEXT)UnbindAdapterContext;
+
+ pContext->BindStatus = Status;
+ SET_EVENT(&pContext->Event);
+}
+
+VOID
+NdisRegisterTdiCallBack(
+ IN TDI_REGISTER_CALLBACK RegisterCallback
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ if (ndisTdiRegisterCallback == NULL)
+ {
+ ndisTdiRegisterCallback = RegisterCallback;
+ }
+}
diff --git a/private/ntos/ndis/ndis40/ndis.rc b/private/ntos/ndis/ndis40/ndis.rc
new file mode 100644
index 000000000..3d5b057d2
--- /dev/null
+++ b/private/ntos/ndis/ndis40/ndis.rc
@@ -0,0 +1,39 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "NDIS 3.0 wrapper driver"
+#define VER_INTERNALNAME_STR "NDIS.SYS"
+#define VER_ORIGINALFILENAME_STR "NDIS.SYS"
+
+#include "common.ver"
+
diff --git a/private/ntos/ndis/ndis40/ndis.src b/private/ntos/ndis/ndis40/ndis.src
new file mode 100644
index 000000000..0969e3cbb
--- /dev/null
+++ b/private/ntos/ndis/ndis40/ndis.src
@@ -0,0 +1,328 @@
+NAME NDIS.SYS
+
+DESCRIPTION 'NDIS.SYS'
+
+EXPORTS
+ ArcFilterDprIndicateReceive
+ ArcFilterDprIndicateReceiveComplete
+
+ EthChangeFilterAddresses
+ EthCreateFilter
+ EthDeleteFilter
+ EthDeleteFilterOpenAdapter
+ EthFilterAdjust
+ EthFilterDprIndicateReceive
+ EthFilterDprIndicateReceivePacket
+ EthFilterDprIndicateReceiveComplete
+ EthFilterIndicateReceive
+ EthFilterIndicateReceiveComplete
+ EthNoteFilterOpenAdapter
+ EthNumberOfOpenFilterAddresses
+ EthQueryGlobalFilterAddresses
+ EthQueryOpenFilterAddresses
+ EthShouldAddressLoopBack
+
+ FddiChangeFilterLongAddresses
+ FddiChangeFilterShortAddresses
+ FddiCreateFilter
+ FddiDeleteFilter
+ FddiDeleteFilterOpenAdapter
+ FddiFilterAdjust
+ FddiFilterDprIndicateReceive
+ FddiFilterDprIndicateReceivePacket
+ FddiFilterDprIndicateReceiveComplete
+ FddiFilterIndicateReceive
+ FddiFilterIndicateReceiveComplete
+ FddiNoteFilterOpenAdapter
+ FddiNumberOfOpenFilterLongAddresses
+ FddiNumberOfOpenFilterShortAddresses
+ FddiQueryGlobalFilterLongAddresses
+ FddiQueryGlobalFilterShortAddresses
+ FddiQueryOpenFilterLongAddresses
+ FddiQueryOpenFilterShortAddresses
+ FddiShouldAddressLoopBack
+
+ TrChangeFunctionalAddress
+ TrChangeGroupAddress
+ TrCreateFilter
+ TrDeleteFilter
+ TrDeleteFilterOpenAdapter
+ TrFilterAdjust
+ TrFilterDprIndicateReceive
+ TrFilterDprIndicateReceivePacket
+ TrFilterDprIndicateReceiveComplete
+ TrFilterIndicateReceive
+ TrFilterIndicateReceiveComplete
+ TrNoteFilterOpenAdapter
+ TrShouldAddressLoopBack
+
+ NdisAllocateBuffer
+ NdisAllocateBufferPool
+ NdisAdjustBufferLength
+ NdisAllocateDmaChannel
+ NdisAllocateMemory
+ NdisAllocateMemoryWithTag
+ NdisAllocatePacket
+ NdisDprAllocatePacket
+ NdisDprAllocatePacketNonInterlocked
+ NdisFreePacket
+ NdisDprFreePacket
+ NdisDprFreePacketNonInterlocked
+ NdisAllocatePacketPool
+ NdisQueryReceiveInformation
+ NdisAllocateSharedMemory
+ NdisCloseConfiguration
+ NdisCloseFile
+ NdisCloseRef
+ NdisCompleteCloseAdapter
+ NdisCompleteDmaTransfer
+ NdisCompleteOpenAdapter
+ NdisCompleteQueryStatistics
+ NdisCopyBuffer
+ NdisCopyFromPacketToPacket
+ NdisDereferenceRef
+#if ALPHA
+ NdisCreateLookaheadBufferFromSharedMemory
+ NdisDestroyLookaheadBufferFromSharedMemory
+#endif
+ NdisDeregisterAdapter
+ NdisDeregisterAdapterShutdownHandler
+ NdisDeregisterMac
+ NdisDeregisterProtocol
+ NdisGetDriverHandle
+ NdisRegisterTdiCallBack
+
+ NdisFinishOpen
+ NdisFreeBufferPool
+ NdisFreePacketPool
+ NdisFreeDmaChannel
+ NdisFreeMemory
+ NdisFreeSharedMemory
+ NdisImmediateReadPciSlotInformation
+ NdisImmediateReadPortUchar
+ NdisImmediateReadPortUshort
+ NdisImmediateReadPortUlong
+ NdisImmediateReadSharedMemory
+ NdisImmediateWritePciSlotInformation
+ NdisImmediateWritePortUchar
+ NdisImmediateWritePortUshort
+ NdisImmediateWritePortUlong
+ NdisImmediateWriteSharedMemory
+ NdisInitializeInterrupt
+ NdisInitializePacketPool
+ NdisInitializeRef
+ NdisInitializeTimer
+ NdisInitializeWrapper
+ NdisMapFile
+ NdisMapIoSpace
+ NdisOpenConfiguration
+ NdisOpenGlobalConfiguration
+ NdisOpenConfigurationKeyByName
+ NdisOpenConfigurationKeyByIndex
+ NdisOpenFile
+ NdisPciAssignResources
+ NdisReadConfiguration
+ NdisReadBindingInformation
+ NdisReadEisaSlotInformation
+ NdisReadEisaSlotInformationEx
+ NdisReadMcaPosInformation
+ NdisReadNetworkAddress
+ NdisConvertStringToAtmAddress
+ NdisReadPciSlotInformation
+ NdisReferenceRef
+ NdisRegisterAdapter
+ NdisRegisterAdapterShutdownHandler
+ NdisRegisterMac
+ NdisRegisterProtocol
+ NdisReleaseAdapterResources
+ NdisRemoveInterrupt
+ NdisCancelTimer
+ NdisSetTimer
+ NdisSetupDmaTransfer
+ NdisTerminateWrapper
+ NdisUnchainBufferAtFront
+ NdisUnchainBufferAtBack
+ NdisUnmapFile
+ NdisUpdateSharedMemory
+ NdisWriteErrorLogEntry
+ NdisWritePciSlotInformation
+
+ NdisOpenAdapter
+ NdisCloseAdapter
+ NdisCompleteBindAdapter
+ NdisCompleteUnbindAdapter
+ NdisOpenProtocolConfiguration
+ NdisSend
+ NdisSendPackets
+ NdisReturnPackets
+ NdisTransferData
+ NdisRequest
+ NdisReset
+ NdisWriteEventLogEntry
+
+ NdisMAllocateMapRegisters
+ NdisMCancelTimer
+ NdisMSetPeriodicTimer
+ NdisMDeregisterIoPortRange
+ NdisMFreeMapRegisters
+ NdisMIndicateStatus
+ NdisMIndicateStatusComplete
+ NdisMInitializeTimer
+ NdisMSleep
+ NdisMQueryInformationComplete
+ NdisMRegisterIoPortRange
+ NdisMRegisterMiniport
+ NdisIMRegisterLayeredMiniport
+ NdisIMInitializeDeviceInstance
+ NdisIMDeInitializeDeviceInstance
+ NdisMResetComplete
+ NdisMSendComplete
+ NdisMSendResourcesAvailable
+ NdisMSetAttributes
+ NdisMSetAttributesEx
+ NdisMSetInformationComplete
+ NdisMTransferDataComplete
+ NdisMMapIoSpace
+ NdisMUnmapIoSpace
+ NdisMRegisterInterrupt
+ NdisMDeregisterInterrupt
+ NdisMSynchronizeWithInterrupt
+ NdisMAllocateSharedMemory
+ NdisMAllocateSharedMemoryAsync
+ NdisMFreeSharedMemory
+ NdisMRegisterDmaChannel
+ NdisMDeregisterDmaChannel
+ NdisMReadDmaCounter
+ NdisMStartBufferPhysicalMapping
+ NdisMCompleteBufferPhysicalMapping
+ NdisMRegisterAdapterShutdownHandler
+ NdisMDeregisterAdapterShutdownHandler
+ NdisMPciAssignResources
+ NdisMQueryAdapterResources
+ NdisMCreateLog
+ NdisMCloseLog
+ NdisMFlushLog
+ NdisMWriteLogData
+
+ NdisMWanSendComplete
+ NdisMWanIndicateReceive
+ NdisMWanIndicateReceiveComplete
+
+ NdisAllocateSpinLock
+ NdisFreeSpinLock
+ NdisAcquireSpinLock
+ NdisReleaseSpinLock
+ NdisDprAcquireSpinLock
+ NdisDprReleaseSpinLock
+ NdisFreeBuffer
+ NdisQueryBuffer
+ NdisQueryBufferOffset
+ NdisGetFirstBufferFromPacket
+ NDIS_BUFFER_TO_SPAN_PAGES
+ NdisGetBufferPhysicalArraySize
+ NdisEqualString
+
+ NdisInterlockedIncrement
+ NdisInterlockedDecrement
+ NdisInterlockedAddUlong
+ NdisInterlockedInsertHeadList
+ NdisInterlockedInsertTailList
+ NdisInterlockedRemoveHeadList
+ NdisInterlockedPushEntryList
+ NdisInterlockedPopEntryList
+
+ NdisSystemProcessorCount
+ NdisWriteConfiguration
+
+ NdisOverrideBusNumber
+ NdisGetCurrentProcessorCpuUsage
+ NdisGetCurrentProcessorCounts
+ NdisGetCurrentSystemTime
+ NdisQueryMapRegisterCount
+ NdisGetSystemUpTime
+
+ NdisInitializeString
+ NdisInitAnsiString
+ NdisInitUnicodeString
+ NdisAnsiStringToUnicodeString
+ NdisUnicodeStringToAnsiString
+
+ NdisInitializeEvent
+ NdisSetEvent
+ NdisResetEvent
+ NdisWaitEvent
+
+ NdisSetProtocolFilter
+ NdisIMQueueMiniportCallback
+ NdisIMSwitchToMiniport
+ NdisIMRevertBack
+
+ //
+ // CoNdis entry points for clients as well as call-managers
+ //
+ NdisCoSendPackets
+ NdisCoRequest
+ NdisCoRequestComplete
+ NdisCoCreateVc
+ NdisCoDeleteVc
+
+ //
+ // CoNdis entry points for clients
+ //
+ NdisClOpenAddressFamily
+ NdisClCloseAddressFamily
+ NdisClRegisterSap
+ NdisClDeregisterSap
+ NdisClMakeCall
+ NdisClCloseCall
+ NdisClAddParty
+ NdisClDropParty
+ NdisClIncomingCallComplete
+ NdisClModifyCallQoS
+
+ //
+ // CoNdis entry points for call managers
+ //
+ NdisCmRegisterAddressFamily
+ NdisCmOpenAddressFamilyComplete
+ NdisCmCloseAddressFamilyComplete
+ NdisCmRegisterSapComplete
+ NdisCmDeregisterSapComplete
+ NdisCmMakeCallComplete
+ NdisCmCloseCallComplete
+ NdisCmAddPartyComplete
+ NdisCmDropPartyComplete
+ NdisCmDispatchIncomingCall
+ NdisCmDispatchCallConnected
+ NdisCmDispatchIncomingDropParty
+ NdisCmDispatchIncomingCloseCall
+ NdisCmDispatchIncomingDropParty
+ NdisCmActivateVc
+ NdisCmDeactivateVc
+ NdisCmModifyCallQoSComplete
+ NdisCmDispatchIncomingCallQoSChange
+
+ //
+ // CoNdis entry points for miniports
+ //
+ NdisMCoActivateVcComplete
+ NdisMCoDeactivateVcComplete
+ NdisMCoIndicateReceivePacket
+ NdisMCoReceiveComplete
+ NdisMCoIndicateStatus
+ NdisMCoSendComplete
+ NdisMCoRequestComplete
+
+ //
+ // CoNdis entry points for miniport-resident call-managers
+ //
+ NdisMCmRegisterAddressFamily
+ NdisMCmCreateVc
+ NdisMCmActivateVc
+ NdisMCmDeactivateVc
+
+#if _DBG && defined(_M_IX86) && defined(_NDIS_INTERNAL_DEBUG)
+ NdisMSetWriteBreakPoint
+ NdisMClearWriteBreakPoint
+#endif
+ \ No newline at end of file
diff --git a/private/ntos/ndis/ndis40/ndis_co.c b/private/ntos/ndis/ndis40/ndis_co.c
new file mode 100644
index 000000000..d3555de22
--- /dev/null
+++ b/private/ntos/ndis/ndis40/ndis_co.c
@@ -0,0 +1,3873 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ ndis_co.c
+
+Abstract:
+
+ CO-NDIS miniport wrapper functions
+
+Author:
+
+ Jameel Hyder (JameelH) 01-Feb-96
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+--*/
+
+#include <precomp.h>
+#include <atm.h>
+#pragma hdrstop
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_NDIS_CO
+
+/*
+ Connection-oriented section of NDIS exposes the following objects and apis to
+ manipulate these objects.
+
+ AF Address Family
+ SAP Service Access Point
+ VC Virtual Circuit
+ Party A node in a point-multipoint VC
+
+ There is a notion of a call-manager and a client on a per-binding basis. The
+ call manager acts as a helper dll for NDIS wrapper to manage the aforementioned
+ objects.
+
+ The concept of AF makes possible the existence of multiple call-managers. An
+ example of this is the UNI call-manager and a SPANS call-manager for the ATM
+ media.
+
+ SAPs provides a way for incoming calls to be routed to the right entity. A
+ protocol can register for more than one SAPs. Its upto the call-manager to
+ allow/dis-allow multiple protocol modules to register the same SAP.
+
+ VCs are created either by a protocol module requesting to make an outbound call
+ or by the call-manager dispatching an incoming call. VCs can either be point-point
+ or point-multi-point. Leaf nodes can be added to VCs at any time provided the first
+ leaf was created appropriately.
+
+ References:
+
+ An AF association results in the reference of file-object for the call-manager.
+
+ A SAP registration results in the reference of the AF.
+
+ A send or receive does not reference a VC. This is because miniports are required to
+ pend DeactivateVc calls till all I/O completes. So when it calls NdisMCoDeactivateVcComplete
+ no other packets will be indicated up and there are no sends outstanding.
+ */
+
+NDIS_STATUS
+NdisCmRegisterAddressFamily(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PCO_ADDRESS_FAMILY AddressFamily,
+ IN PNDIS_CALL_MANAGER_CHARACTERISTICS CmCharacteristics,
+ IN UINT SizeOfCmCharacteristics
+ )
+/*++
+
+Routine Description:
+ This is a call from the call-manager to register the address family
+ supported by this call-manager.
+
+Arguments:
+ NdisBindingHandle - Pointer to the call-managers NDIS_OPEN_BLOCK.
+ AddressFamily - The address family being registered.
+ CmCharacteristics - Call-Manager characteristics
+ SizeOfCmCharacteristics - Size of Call-Manager characteristics
+
+Return Value:
+ NDIS_STATUS_SUCCESS if the address family registration is successfully.
+ NDIS_STATUS_FAILURE if the caller is not a call-manager or this address
+ family is already registered for this miniport.
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ KIRQL OldIrql;
+ PNDIS_AF_LIST AfList;
+ PNDIS_PROTOCOL_BLOCK Protocol;
+ PNDIS_M_OPEN_BLOCK CallMgrOpen;
+ PNDIS_MINIPORT_BLOCK Miniport;
+
+ CallMgrOpen = (PNDIS_M_OPEN_BLOCK)(((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacBindingHandle);
+ Miniport = CallMgrOpen->MiniportHandle;
+ Protocol = CallMgrOpen->ProtocolHandle;
+
+ CoReferencePackage();
+
+ //
+ // Make sure that the miniport is a CoNdis miniport and
+ // there is no other module registering the same address family.
+ //
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ do
+ {
+ //
+ // Make sure the binding is not closing down
+ //
+ if (CallMgrOpen->Flags & fMINIPORT_OPEN_CLOSING)
+ {
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // Make sure that the miniport is a CoNdis miniport and
+ // protocol is also a NDIS 4.1 or later protocol.
+ //
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
+ {
+ //
+ // Not a NDIS 4.1 or later miniport
+ //
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ if ((Protocol->ProtocolCharacteristics.MajorNdisVersion < 4) ||
+ ((Protocol->ProtocolCharacteristics.MajorNdisVersion == 4) &&
+ (Protocol->ProtocolCharacteristics.MinorNdisVersion < 1)))
+ {
+ //
+ // Not a NDIS 4.1 or later protocol
+ //
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // Make sure that the call-manager characteristics are 4.1 or later
+ //
+ if ((CmCharacteristics->MajorVersion != 4) ||
+ (CmCharacteristics->MinorVersion != 1) ||
+ (SizeOfCmCharacteristics < sizeof(NDIS_CALL_MANAGER_CHARACTERISTICS)))
+ {
+ //
+ // Not a NDIS 4.1 or later protocol
+ //
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // Search registered call-managers for this miniport and make sure there is no
+ // clash. A call-manager can only register one address family per-open. This
+ // is due to the way we cache handlers. Can be over-come if the handlers are
+ // identical for each address-family - but decided not to since it is un-interesting.
+ //
+ for (AfList = Miniport->CallMgrAfList;
+ AfList != NULL;
+ AfList = AfList->NextOpen)
+ {
+ if ((AfList->AddressFamily == AddressFamily->AddressFamily) ||
+ (AfList->Open == CallMgrOpen))
+ {
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+ }
+
+ if (AfList == NULL)
+ {
+ //
+ // No other entity has claimed this address family.
+ //
+ AfList = (PNDIS_AF_LIST)ALLOC_FROM_POOL(sizeof(NDIS_AF_LIST), NDIS_TAG_CO);
+ if (AfList == NULL)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+ AfList->AddressFamily = AddressFamily->AddressFamily;
+ CopyMemory(&AfList->CmChars,
+ CmCharacteristics,
+ sizeof(NDIS_CALL_MANAGER_CHARACTERISTICS));
+
+ //
+ // link it in the miniport list
+ //
+ AfList->Open = CallMgrOpen;
+ AfList->NextOpen = Miniport->CallMgrAfList;
+ Miniport->CallMgrAfList = AfList;
+ //
+ // Now link it in the global list
+ //
+ ACQUIRE_SPIN_LOCK_DPC(&ndisGlobalOpenListLock);
+ AfList->NextGlobal = ndisAfList;
+ ndisAfList = AfList;
+ RELEASE_SPIN_LOCK_DPC(&ndisGlobalOpenListLock);
+
+ //
+ // Finally cache some handlers in the open-block
+ //
+ CallMgrOpen->CoCreateVcHandler = CmCharacteristics->CmCreateVcHandler;
+ CallMgrOpen->CoDeleteVcHandler = CmCharacteristics->CmDeleteVcHandler;
+ CallMgrOpen->CmActivateVcCompleteHandler = CmCharacteristics->CmActivateVcCompleteHandler;
+ CallMgrOpen->CmDeactivateVcCompleteHandler = CmCharacteristics->CmDeactivateVcCompleteHandler;
+
+ //
+ // Notify existing clients of this registration
+ //
+ ndisMNotifyAfRegistration(Miniport, AddressFamily);
+ }
+ } while (FALSE);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ if (!NT_SUCCESS(Status))
+ {
+ CoDereferencePackage();
+ }
+
+ return(Status);
+}
+
+
+NDIS_STATUS
+NdisMCmRegisterAddressFamily(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PCO_ADDRESS_FAMILY AddressFamily,
+ IN PNDIS_CALL_MANAGER_CHARACTERISTICS CmCharacteristics,
+ IN UINT SizeOfCmCharacteristics
+ )
+/*++
+
+Routine Description:
+ This is a call from the miniport supported call-manager to register the address family
+ supported by this call-manager.
+
+Arguments:
+ MiniportAdapterHandle - Pointer to the miniports NDIS_MINIPORT_BLOCK.
+ AddressFamily - The address family being registered.
+ CmCharacteristics - Call-Manager characteristics
+ SizeOfCmCharacteristics - Size of Call-Manager characteristics
+
+Return Value:
+ NDIS_STATUS_SUCCESS if the address family registration is successfully.
+ NDIS_STATUS_FAILURE if the caller is not a call-manager or this address
+ family is already registered for this miniport.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport;
+ NDIS_STATUS Status;
+ PNDIS_AF_LIST AfList;
+ KIRQL OldIrql;
+
+ CoReferencePackage();
+
+ Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+
+ //
+ // Make sure that the miniport is a CoNdis miniport and
+ // there is no other module registering the same address family.
+ //
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ do
+ {
+ //
+ // Make sure that the miniport is a CoNdis miniport
+ //
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
+ {
+ //
+ // Not a NDIS 4.1 or later miniport
+ //
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // Make sure that the call-manager characteristics are 4.1 or later
+ //
+ if ((CmCharacteristics->MajorVersion != 4) ||
+ (CmCharacteristics->MinorVersion != 1) ||
+ (SizeOfCmCharacteristics < sizeof(NDIS_CALL_MANAGER_CHARACTERISTICS)))
+ {
+ //
+ // Not a NDIS 4.1 or later protocol
+ //
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // Search registered call-managers for this miniport and make sure there is no
+ // clash. A call-manager can only register one address family per-open. This
+ // is due to the way we cache handlers. Can be over-come if the handlers are
+ // identical for each address-family - but decided not to since it is un-interesting.
+ //
+ for (AfList = Miniport->CallMgrAfList;
+ AfList != NULL;
+ AfList = AfList->NextOpen)
+ {
+ if ((AfList->AddressFamily == AddressFamily->AddressFamily) ||
+ (AfList->Open == NULL))
+ {
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+ }
+
+ if (AfList == NULL)
+ {
+ //
+ // No other entity has claimed this address family.
+ //
+ AfList = (PNDIS_AF_LIST)ALLOC_FROM_POOL(sizeof(NDIS_AF_LIST), NDIS_TAG_CO);
+ if (AfList == NULL)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+ AfList->AddressFamily = AddressFamily->AddressFamily;
+ CopyMemory(&AfList->CmChars,
+ CmCharacteristics,
+ sizeof(NDIS_CALL_MANAGER_CHARACTERISTICS));
+
+ //
+ // link it in the miniport list
+ //
+ AfList->Open = NULL;
+ AfList->NextOpen = Miniport->CallMgrAfList;
+ Miniport->CallMgrAfList = AfList;
+ //
+ // Now link it in the global list
+ //
+ ACQUIRE_SPIN_LOCK_DPC(&ndisGlobalOpenListLock);
+ AfList->NextGlobal = ndisAfList;
+ ndisAfList = AfList;
+ RELEASE_SPIN_LOCK_DPC(&ndisGlobalOpenListLock);
+ }
+ } while (FALSE);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ if (!NT_SUCCESS(Status))
+ {
+ CoDereferencePackage();
+ }
+
+ return Status;
+}
+
+VOID
+ndisMNotifyAfRegistration(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PCO_ADDRESS_FAMILY AddressFamily OPTIONAL
+ )
+/*++
+
+Routine Description:
+
+ If a protocol has a handler for it, notify it that a new address family has
+ been registered.
+
+Arguments:
+ NdisBindingHandle - Pointer to the protocol's NDIS_OPEN_BLOCK.
+ AddressFamily - Address family in question. If not specified all address
+ families for the miniport are reported
+
+Return Value:
+ None.
+
+--*/
+{
+}
+
+NDIS_STATUS
+NdisClOpenAddressFamily(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PCO_ADDRESS_FAMILY AddressFamily,
+ IN NDIS_HANDLE ClientAfContext,
+ IN PNDIS_CLIENT_CHARACTERISTICS ClCharacteristics,
+ IN UINT SizeOfClCharacteristics,
+ OUT PNDIS_HANDLE NdisAfHandle
+ )
+/*++
+
+Routine Description:
+ This is a call from a NDIS 4.1 or later protocol to open a particular
+ address familty - in essence getting a handle to the call-manager.
+
+Arguments:
+ NdisBindingHandle - Pointer to the protocol's NDIS_OPEN_BLOCK.
+ PCO_ADDRESS_FAMILY - The address family being registered.
+ ClientAfContext - Protocol context associated with this handle.
+ NdisAfHandle - Handle returned by NDIS for this address family.
+
+Return Value:
+ NDIS_STATUS_SUCCESS if the address family open is successfully.
+ NDIS_STATUS_PENDING if the call-manager pends this call. The caller will get
+ called at the completion handler when done.
+ NDIS_STATUS_FAILURE if the caller is not a NDIS 4.1 prototcol or this address
+ family is not registered for this miniport.
+
+--*/
+{
+ PNDIS_CO_AF_BLOCK pAf;
+ PNDIS_AF_LIST AfList;
+ PNDIS_M_OPEN_BLOCK CallMgrOpen, ClientOpen;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PNDIS_PROTOCOL_BLOCK Protocol;
+ KIRQL OldIrql;
+ NTSTATUS Status;
+
+ *NdisAfHandle = NULL;
+ ClientOpen = (PNDIS_M_OPEN_BLOCK)((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacBindingHandle;
+ Miniport = ClientOpen->MiniportHandle;
+ Protocol = ClientOpen->ProtocolHandle;
+
+ CoReferencePackage();
+
+ do
+ {
+ //
+ // Make sure the binding is not closing down
+ //
+ if (ClientOpen->Flags & fMINIPORT_OPEN_CLOSING)
+ {
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // Make sure that the miniport is a CoNdis miniport and
+ // protocol is also a NDIS 4.1 or later protocol.
+ //
+ if ((Miniport->DriverHandle->MiniportCharacteristics.MajorNdisVersion < 4) ||
+ ((Miniport->DriverHandle->MiniportCharacteristics.MajorNdisVersion == 4) &&
+ (Miniport->DriverHandle->MiniportCharacteristics.MinorNdisVersion < 1)) ||
+ (Miniport->DriverHandle->MiniportCharacteristics.CoCreateVcHandler == NULL))
+ {
+ //
+ // Not a NDIS 4.1 or later miniport
+ //
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ if ((Protocol->ProtocolCharacteristics.MajorNdisVersion < 4) ||
+ ((Protocol->ProtocolCharacteristics.MajorNdisVersion == 4) &&
+ (Protocol->ProtocolCharacteristics.MinorNdisVersion < 1)))
+ {
+ //
+ // Not a NDIS 4.1 or later protocol
+ //
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // Make sure that the client characteristics are 4.1 or later
+ //
+ if ((ClCharacteristics->MajorVersion != 4) ||
+ (ClCharacteristics->MinorVersion != 1) ||
+ (SizeOfClCharacteristics < sizeof(NDIS_CLIENT_CHARACTERISTICS)))
+ {
+ //
+ // Not a NDIS 4.1 or later protocol
+ //
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ //
+ // Search the miniport block for a registered call-manager for this address family
+ //
+ for (AfList = Miniport->CallMgrAfList;
+ AfList != NULL;
+ AfList = AfList->NextOpen)
+ {
+ if (AfList->AddressFamily == AddressFamily->AddressFamily)
+ {
+ CallMgrOpen = AfList->Open;
+ break;
+ }
+ }
+
+ //
+ // If we found a matching call manager, make sure that the callmgr
+ // is not currently closing.
+ //
+ if ((AfList == NULL) ||
+ ((AfList != NULL) && (AfList->Open->Flags & fMINIPORT_OPEN_CLOSING)) ||
+ (Miniport->Flags & (fMINIPORT_CLOSING | fMINIPORT_HALTING)))
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ //
+ // NOTE: We can possibly wait a little while here and retry
+ // before actually failing this call if (AfList == NULL).
+ //
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // Allocate memory for the AF block.
+ //
+ pAf = ALLOC_FROM_POOL(sizeof(NDIS_CO_AF_BLOCK), NDIS_TAG_CO);
+ if (pAf == NULL)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ pAf->References = 1;
+ pAf->Flags = 0;
+ pAf->Miniport = Miniport;
+
+ pAf->ClientOpen = ClientOpen;
+ pAf->CallMgrOpen = CallMgrOpen = AfList->Open;
+ pAf->ClientContext = ClientAfContext;
+
+ //
+ // Reference the call-manager's file object - we do not want to let it
+ // duck from under the client.
+ //
+ //
+ // Reference the client and the call-manager opens
+ //
+ ClientOpen->References++;
+ if (CallMgrOpen != NULL)
+ {
+ ObReferenceObject(CallMgrOpen->FileObject);
+ CallMgrOpen->References++;
+ }
+ else
+ {
+ ObReferenceObject(Miniport->DeviceObject);
+ Miniport->Ref.ReferenceCount ++;
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ INITIALIZE_SPIN_LOCK(&pAf->Lock);
+
+ //
+ // Cache in call-manager entry points
+ //
+ pAf->CallMgrEntries = &AfList->CmChars;
+
+ //
+ // And also Cache in client entry points
+ //
+ CopyMemory(&pAf->ClientEntries,
+ ClCharacteristics,
+ sizeof(NDIS_CLIENT_CHARACTERISTICS));
+
+
+ //
+ // Cache some handlers in the open-block
+ //
+ ClientOpen->CoCreateVcHandler = ClCharacteristics->ClCreateVcHandler;
+ ClientOpen->CoDeleteVcHandler = ClCharacteristics->ClDeleteVcHandler;
+
+ //
+ // Now call the CallMgr's OpenAfHandler
+ //
+ Status = (*AfList->CmChars.CmOpenAfHandler)((CallMgrOpen != NULL) ?
+ CallMgrOpen->ProtocolBindingContext :
+ Miniport->MiniportAdapterContext,
+ AddressFamily,
+ pAf,
+ &pAf->CallMgrContext);
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisCmOpenAddressFamilyComplete(Status,
+ pAf,
+ pAf->CallMgrContext);
+ Status = NDIS_STATUS_PENDING;
+ }
+
+ } while (FALSE);
+
+ if (!NT_SUCCESS(Status))
+ {
+ CoDereferencePackage();
+ }
+
+ return Status;
+}
+
+
+VOID
+NdisCmOpenAddressFamilyComplete(
+ IN NDIS_STATUS Status,
+ IN NDIS_HANDLE NdisAfHandle,
+ IN NDIS_HANDLE CallMgrAfContext
+ )
+/*++
+
+Routine Description:
+
+ Completion routine for the OpenAddressFamily call. The call manager had pended this
+ call earlier (or will pend). If the call succeeded there is a valid CallMgrContext
+ supplied here as well
+
+Arguments:
+ Status - Completion status
+ NdisAfHandle - Pointer to the AfBlock
+ CallMgrAfContext - Call manager's context used in other calls into the call manager.
+
+Return Value:
+ NONE. The client's completion handler is called.
+
+--*/
+{
+ PNDIS_CO_AF_BLOCK pAf;
+ PNDIS_M_OPEN_BLOCK ClientOpen;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ KIRQL OldIrql;
+
+ ASSERT (Status != NDIS_STATUS_PENDING);
+
+ pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
+ ClientOpen = pAf->ClientOpen;
+ Miniport = pAf->Miniport;
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ if (pAf->CallMgrOpen != NULL)
+ {
+ ObDereferenceObject(pAf->CallMgrOpen->FileObject);
+ }
+ else
+ {
+ ObDereferenceObject(Miniport->DeviceObject);
+ }
+ }
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ pAf->CallMgrContext = CallMgrAfContext;
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // OpenAfHandler failed
+ //
+ if (pAf->CallMgrOpen != NULL)
+ {
+ pAf->CallMgrOpen->References--;
+ if (pAf->CallMgrOpen->References == 0)
+ {
+ ndisMFinishClose(Miniport, pAf->CallMgrOpen);
+ }
+ }
+ else
+ {
+ ndisDereferenceMiniport(Miniport);
+ }
+
+ ClientOpen->References--;
+ if (ClientOpen->References == 0)
+ {
+ ndisMFinishClose(Miniport, ClientOpen);
+ }
+ FREE_POOL(pAf);
+
+ CoDereferencePackage();
+ }
+ else
+ {
+ //
+ // queue this CallMgr open onto the miniport open
+ //
+ pAf->NextAf = ClientOpen->NextAf;
+ ClientOpen->NextAf = pAf;
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ //
+ // Finally call the client's completion handler
+ //
+ (*pAf->ClientEntries.ClOpenAfCompleteHandler)(Status,
+ pAf->ClientContext,
+ (Status == NDIS_STATUS_SUCCESS) ? pAf : NULL);
+}
+
+
+NDIS_STATUS
+NdisClCloseAddressFamily(
+ IN NDIS_HANDLE NdisAfHandle
+ )
+/*++
+
+Routine Description:
+
+ This call closes the Af object which essentially tears down the client-callmanager
+ 'binding'. Causes all open Vcs to be closed and saps to be de-registered "by the call
+ manager".
+
+Arguments:
+
+ NdisAfHandle - Pointer to the Af.
+
+Return Value:
+
+ Status from Call Manager.
+
+--*/
+{
+ PNDIS_CO_AF_BLOCK pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ KIRQL OldIrql;
+
+ //
+ // Mark the address family as closing and call the call-manager to process.
+ //
+ ACQUIRE_SPIN_LOCK(&pAf->Lock, &OldIrql);
+ if (pAf->Flags & AF_CLOSING)
+ {
+ Status = NDIS_STATUS_FAILURE;
+ }
+ pAf->Flags |= AF_CLOSING;
+ RELEASE_SPIN_LOCK(&pAf->Lock, OldIrql);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ Status = (*pAf->CallMgrEntries->CmCloseAfHandler)(pAf->CallMgrContext);
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisCmCloseAddressFamilyComplete(Status, pAf);
+ Status = NDIS_STATUS_PENDING;
+ }
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ CoDereferencePackage();
+ }
+
+ return Status;
+}
+
+
+VOID
+NdisCmCloseAddressFamilyComplete(
+ IN NDIS_STATUS Status,
+ IN NDIS_HANDLE NdisAfHandle
+ )
+/*++
+
+Routine Description:
+
+ Completion routine for the CloseAddressFamily call. The call manager had pended this
+ call earlier (or will pend). If the call succeeded there is a valid CallMgrContext
+ supplied here as well
+
+Arguments:
+ Status - Completion status
+ NdisAfHandle - Pointer to the AfBlock
+
+Return Value:
+ NONE. The client's completion handler is called.
+
+--*/
+{
+ PNDIS_CO_AF_BLOCK pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ KIRQL OldIrql;
+
+ Miniport = pAf->Miniport;
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Dereference the file object for the call-manager
+ //
+ if (pAf->CallMgrOpen != NULL)
+ {
+ ObDereferenceObject(pAf->CallMgrOpen->FileObject);
+ }
+ else
+ {
+ ObDereferenceObject(Miniport->DeviceObject);
+ }
+
+ Miniport = pAf->Miniport;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ if (pAf->CallMgrOpen != NULL)
+ {
+ pAf->CallMgrOpen->References--;
+ if (pAf->CallMgrOpen->References == 0)
+ {
+ ndisMFinishClose(Miniport, pAf->CallMgrOpen);
+ }
+ }
+ else
+ {
+ ndisDereferenceMiniport(Miniport);
+ }
+
+ pAf->ClientOpen->References--;
+ if (pAf->ClientOpen->References == 0)
+ {
+ ndisMFinishClose(Miniport, pAf->ClientOpen);
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ CoDereferencePackage();
+ }
+
+ //
+ // Complete the call to the client
+ //
+ (*pAf->ClientEntries.ClCloseAfCompleteHandler)(Status,
+ pAf->ClientContext);
+
+ //
+ // Finally dereference the AF Block, if the call-manager successfully closed it.
+ //
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ ndisDereferenceAf(pAf);
+ }
+}
+
+
+BOOLEAN
+ndisReferenceAf(
+ IN PNDIS_CO_AF_BLOCK pAf
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ KIRQL OldIrql;
+ BOOLEAN rc = FALSE;
+
+ ACQUIRE_SPIN_LOCK(&pAf->Lock, &OldIrql);
+
+ if ((pAf->Flags & AF_CLOSING) == 0)
+ {
+ pAf->References ++;
+ rc = TRUE;
+ }
+
+ RELEASE_SPIN_LOCK(&pAf->Lock, OldIrql);
+
+ return rc;
+}
+
+
+VOID
+ndisDereferenceAf(
+ IN PNDIS_CO_AF_BLOCK pAf
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ KIRQL OldIrql;
+ BOOLEAN Done = FALSE;
+
+ ACQUIRE_SPIN_LOCK(&pAf->Lock, &OldIrql);
+
+ ASSERT (pAf->References > 0);
+ pAf->References --;
+ if (pAf->References == 0)
+ {
+ ASSERT (pAf->Flags & AF_CLOSING);
+ Done = TRUE;
+ }
+
+ RELEASE_SPIN_LOCK(&pAf->Lock, OldIrql);
+
+ if (Done)
+ FREE_POOL(pAf);
+}
+
+
+NDIS_STATUS
+NdisClRegisterSap(
+ IN NDIS_HANDLE NdisAfHandle,
+ IN NDIS_HANDLE ProtocolSapContext,
+ IN PCO_SAP Sap,
+ OUT PNDIS_HANDLE NdisSapHandle
+ )
+/*++
+
+Routine Description:
+ This is a call from a NDIS 4.1 or later protocol to register its SAP
+ with the call manager.
+
+Arguments:
+ NdisBindingHandle - Pointer to the protocol's NDIS_OPEN_BLOCK.
+ PCO_ADDRESS_FAMILY - The address family being registered.
+ ClientAfContext - Protocol context associated with this handle.
+ NdisAfHandle - Handle returned by NDIS for this address family.
+
+Return Value:
+ NDIS_STATUS_SUCCESS if the address family open is successfully.
+ NDIS_STATUS_PENDING if the call-manager pends this call. The caller will get
+ NDIS_STATUS_FAILURE if the caller is not a NDIS 4.1 prototcol or this address
+ family is not registered for this miniport.
+
+--*/
+{
+ NDIS_STATUS Status;
+ PNDIS_CO_AF_BLOCK pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
+ PNDIS_CO_SAP_BLOCK pSap;
+
+ *NdisSapHandle = NULL;
+ do
+ {
+ //
+ // Reference the Af for this SAP
+ //
+ if (!ndisReferenceAf(pAf))
+ {
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ pSap = (PNDIS_CO_SAP_BLOCK)ALLOC_FROM_POOL(sizeof(NDIS_CO_SAP_BLOCK), NDIS_TAG_CO);
+ if (pSap == NULL)
+ {
+ *NdisSapHandle = NULL;
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ pSap->Flags = 0;
+ pSap->References = 1;
+ INITIALIZE_SPIN_LOCK(&pSap->Lock);
+ pSap->AfBlock = pAf;
+ pSap->Sap = Sap;
+ pSap->ClientContext = ProtocolSapContext;
+ Status = (*pAf->CallMgrEntries->CmRegisterSapHandler)(pAf->CallMgrContext,
+ Sap,
+ pSap,
+ &pSap->CallMgrContext);
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisCmRegisterSapComplete(Status, pSap, pSap->CallMgrContext);
+ Status = NDIS_STATUS_PENDING;
+ }
+
+ } while (FALSE);
+
+ return Status;
+}
+
+
+VOID
+NdisCmRegisterSapComplete(
+ IN NDIS_STATUS Status,
+ IN NDIS_HANDLE NdisSapHandle,
+ IN NDIS_HANDLE CallMgrSapContext
+ )
+/*++
+
+Routine Description:
+ Completion routine for the registerSap call. The call manager had pended this
+ call earlier (or will pend). If the call succeeded there is a valid CallMgrContext
+ supplied here as well
+
+Arguments:
+ Status - Completion status
+ NdisAfHandle - Pointer to the AfBlock
+ CallMgrAfContext - Call manager's context used in other calls into the call manager.
+
+Return Value:
+ NONE. The client's completion handler is called.
+
+--*/
+{
+ PNDIS_CO_SAP_BLOCK pSap = (PNDIS_CO_SAP_BLOCK)NdisSapHandle;
+ PNDIS_CO_AF_BLOCK pAf;
+
+ ASSERT (Status != NDIS_STATUS_PENDING);
+
+ pAf = pSap->AfBlock;
+ pSap->CallMgrContext = CallMgrSapContext;
+
+ //
+ // Call the clients completion handler
+ //
+ (*pAf->ClientEntries.ClRegisterSapCompleteHandler)(Status,
+ pSap->ClientContext,
+ pSap->Sap,
+ pSap);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ ndisDereferenceAf(pSap->AfBlock);
+ FREE_POOL(pSap);
+ }
+}
+
+
+NDIS_STATUS
+NdisClDeregisterSap(
+ IN NDIS_HANDLE NdisSapHandle
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_CO_SAP_BLOCK pSap = (PNDIS_CO_SAP_BLOCK)NdisSapHandle;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+ BOOLEAN fAlreadyClosing;
+
+ ACQUIRE_SPIN_LOCK(&pSap->Lock, &OldIrql);
+
+ fAlreadyClosing = FALSE;
+ if (pSap->Flags & SAP_CLOSING)
+ {
+ fAlreadyClosing = TRUE;
+ }
+ pSap->Flags |= SAP_CLOSING;
+
+ RELEASE_SPIN_LOCK(&pSap->Lock, OldIrql);
+
+ if (fAlreadyClosing)
+ {
+ return NDIS_STATUS_FAILURE;
+ }
+
+ //
+ // Notify the call-manager that this sap is being de-registered
+ //
+ Status = (*pSap->AfBlock->CallMgrEntries->CmDeregisterSapHandler)(pSap->CallMgrContext);
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisCmDeregisterSapComplete(Status, pSap);
+ Status = NDIS_STATUS_PENDING;
+ }
+
+ return Status;
+}
+
+
+VOID
+NdisCmDeregisterSapComplete(
+ IN NDIS_STATUS Status,
+ IN NDIS_HANDLE NdisSapHandle
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_CO_SAP_BLOCK pSap = (PNDIS_CO_SAP_BLOCK)NdisSapHandle;
+
+ ASSERT (Status != NDIS_STATUS_PENDING);
+
+ //
+ // Complete the call to the client and deref the sap
+ //
+ (*pSap->AfBlock->ClientEntries.ClDeregisterSapCompleteHandler)(Status,
+ pSap->ClientContext);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ ndisDereferenceAf(pSap->AfBlock);
+ ndisDereferenceSap(pSap);
+ }
+}
+
+
+BOOLEAN
+ndisReferenceSap(
+ IN PNDIS_CO_SAP_BLOCK pSap
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ KIRQL OldIrql;
+ BOOLEAN rc = FALSE;
+
+ ACQUIRE_SPIN_LOCK(&pSap->Lock, &OldIrql);
+
+ if ((pSap->Flags & SAP_CLOSING) == 0)
+ {
+ pSap->References ++;
+ rc = TRUE;
+ }
+
+ RELEASE_SPIN_LOCK(&pSap->Lock, OldIrql);
+
+ return rc;
+}
+
+
+VOID
+ndisDereferenceSap(
+ IN PNDIS_CO_SAP_BLOCK pSap
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ KIRQL OldIrql;
+ BOOLEAN Done = FALSE;
+
+ ACQUIRE_SPIN_LOCK(&pSap->Lock, &OldIrql);
+
+ ASSERT (pSap->References > 0);
+ pSap->References --;
+ if (pSap->References == 0)
+ {
+ ASSERT (pSap->Flags & SAP_CLOSING);
+ Done = TRUE;
+ }
+
+ RELEASE_SPIN_LOCK(&pSap->Lock, OldIrql);
+
+ if (Done)
+ FREE_POOL(pSap);
+}
+
+
+NDIS_STATUS
+NdisCoCreateVc(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE NdisAfHandle OPTIONAL,
+ IN NDIS_HANDLE ProtocolVcContext,
+ IN OUT PNDIS_HANDLE NdisVcHandle
+ )
+/*++
+
+Routine Description:
+ This is a call from either the call-manager or from the client to create a vc.
+ The vc would then be owned by call-manager (signalling vc) or the client.
+ This is a synchronous call to all parties and simply creates an end-point over
+ which either incoming calls can be dispatched or out-going calls can be made.
+
+Arguments:
+ NdisBindingHandle - Pointer to the caller's NDIS_OPEN_BLOCK.
+ NdisAfHandle - Pointer to the AF Block. Not specified for call-manager's private vcs.
+ A miniport resident call-manager must never create call-manager vcs i.e.
+ the NdisAfHandle must always be present
+ NdisVcHandle - Where the handle to this Vc will be returned.
+
+Return Value:
+ NDIS_STATUS_SUCCESS if all the components succeed.
+ ErrorCode to signify why the call failed.
+
+--*/
+{
+ PNDIS_M_OPEN_BLOCK Open;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PNDIS_CO_VC_BLOCK Vc;
+ PNDIS_CO_AF_BLOCK pAf;
+ NDIS_STATUS Status;
+
+ Open = (PNDIS_M_OPEN_BLOCK)(((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->MacBindingHandle);
+ Miniport = Open->MiniportHandle;
+ *NdisVcHandle = NULL;
+
+ //
+ // Allocate the memory for NDIS_VC_BLOCK
+ //
+ Vc = ALLOC_FROM_POOL(sizeof(NDIS_CO_VC_BLOCK), NDIS_TAG_CO);
+ if (Vc == NULL)
+ return NDIS_STATUS_RESOURCES;
+
+ //
+ // Initialize the VC block
+ //
+ NdisZeroMemory(Vc, sizeof(NDIS_CO_VC_BLOCK));
+ INITIALIZE_SPIN_LOCK(&Vc->Lock);
+ InitializeListHead(&Vc->CallMgrLinkage);
+ InitializeListHead(&Vc->ClientLinkage);
+
+ //
+ // Cache some miniport handlers
+ //
+ Vc->Miniport = Miniport;
+ Vc->WCoSendPacketsHandler = Miniport->DriverHandle->MiniportCharacteristics.CoSendPacketsHandler;
+ Vc->WCoDeleteVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoDeleteVcHandler;
+ Vc->WCoActivateVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoActivateVcHandler;
+ Vc->WCoDeactivateVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoDeactivateVcHandler;
+
+ //
+ // We have only one reference for vc on creation.
+ //
+ pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
+ Vc->AfBlock = pAf;
+ Vc->References = 1;
+
+ //
+ // First call the miniport to get its context
+ //
+ Status = (*Open->MiniportCoCreateVcHandler)(Miniport->MiniportAdapterContext,
+ Vc,
+ &Vc->MiniportContext);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ FREE_POOL(Vc);
+ return Status;
+ }
+
+ if (ARGUMENT_PRESENT(NdisAfHandle))
+ {
+ Vc->ClientOpen = pAf->ClientOpen;
+ Vc->CallMgrOpen = pAf->CallMgrOpen;
+
+ Vc->CoSendCompleteHandler =
+ pAf->ClientOpen->ProtocolHandle->ProtocolCharacteristics.CoSendCompleteHandler;
+ Vc->CoReceivePacketHandler =
+ pAf->ClientOpen->ProtocolHandle->ProtocolCharacteristics.CoReceivePacketHandler;
+ Vc->ClModifyCallQoSCompleteHandler = pAf->ClientEntries.ClModifyCallQoSCompleteHandler;
+ Vc->ClIncomingCallQoSChangeHandler = pAf->ClientEntries.ClIncomingCallQoSChangeHandler;
+ Vc->ClCallConnectedHandler = pAf->ClientEntries.ClCallConnectedHandler;
+
+ Vc->CmActivateVcCompleteHandler = pAf->CallMgrEntries->CmActivateVcCompleteHandler;
+ Vc->CmDeactivateVcCompleteHandler = pAf->CallMgrEntries->CmDeactivateVcCompleteHandler;
+ Vc->CmModifyCallQoSHandler = pAf->CallMgrEntries->CmModifyCallQoSHandler;
+
+ //
+ // Determine who the caller is and initialize the other.
+ //
+ if (Open == pAf->ClientOpen)
+ {
+ Vc->ClientContext = ProtocolVcContext;
+
+ if (pAf->CallMgrOpen == NULL)
+ {
+ Vc->CallMgrContext = Vc->MiniportContext;
+ }
+ else
+ {
+ //
+ // Call-up to the call-manager now to get its context
+ //
+ Status = (*pAf->CallMgrOpen->CoCreateVcHandler)(pAf->CallMgrContext,
+ Vc,
+ &Vc->CallMgrContext);
+ }
+ }
+ else
+ {
+ ASSERT (pAf->CallMgrOpen == Open);
+
+ Vc->CallMgrContext = ProtocolVcContext;
+
+ //
+ // Call-up to the client now to get its context
+ //
+ Status = (*pAf->ClientOpen->CoCreateVcHandler)(pAf->ClientContext,
+ Vc,
+ &Vc->ClientContext);
+ }
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (Open == pAf->ClientOpen)
+ {
+ //
+ // Link this in the open_block
+ //
+ ExInterlockedInsertHeadList(&Open->InactiveVcHead,
+ &Vc->ClientLinkage,
+ &Open->SpinLock.SpinLock);
+ if (pAf->CallMgrOpen != NULL)
+ {
+ Vc->DeleteVcContext = Vc->CallMgrContext;
+ Vc->CoDeleteVcHandler = pAf->CallMgrOpen->CoDeleteVcHandler;
+ ExInterlockedInsertHeadList(&pAf->CallMgrOpen->InactiveVcHead,
+ &Vc->CallMgrLinkage,
+ &pAf->CallMgrOpen->SpinLock.SpinLock);
+ }
+ else
+ {
+ Vc->DeleteVcContext = NULL;
+ Vc->CoDeleteVcHandler = NULL;
+ }
+ }
+ else
+ {
+ //
+ // Link this in the open_block
+ //
+ Vc->DeleteVcContext = Vc->ClientContext;
+ Vc->CoDeleteVcHandler = pAf->ClientOpen->CoDeleteVcHandler;
+ ExInterlockedInsertHeadList(&Open->InactiveVcHead,
+ &Vc->CallMgrLinkage,
+ &Open->SpinLock.SpinLock);
+ ExInterlockedInsertHeadList(&pAf->ClientOpen->InactiveVcHead,
+ &Vc->ClientLinkage,
+ &pAf->ClientOpen->SpinLock.SpinLock);
+ }
+ }
+ else
+ {
+ Status = (*Vc->WCoDeleteVcHandler)(Vc->MiniportContext);
+
+ FREE_POOL(Vc);
+ Vc = NULL;
+ }
+ }
+ else
+ {
+ //
+ // This is a call-manager only VC and so the call-manager is the client and there
+ // is no call-manager associated with it. This VC cannot be used to CoMakeCall or
+ // CmDispatchIncomingCall. Set the client values to the call-manager
+ //
+ // Vc->CoDeleteVcContexr = NULL;
+ // Vc->CoDeleteVcHandler = NULL;
+ Vc->ClientOpen = Open;
+ Vc->ClientContext = ProtocolVcContext;
+ Vc->CoSendCompleteHandler =
+ Open->ProtocolHandle->ProtocolCharacteristics.CoSendCompleteHandler;
+ Vc->CoReceivePacketHandler =
+ Open->ProtocolHandle->ProtocolCharacteristics.CoReceivePacketHandler;
+
+ //
+ // Do set the following call-manager entries since this VC will need to be
+ // activated. Also set the call-managers context for the same reasons.
+ //
+ Vc->CmActivateVcCompleteHandler = Open->CmActivateVcCompleteHandler;
+ Vc->CmDeactivateVcCompleteHandler = Open->CmDeactivateVcCompleteHandler;
+ Vc->CallMgrContext = ProtocolVcContext;
+
+ //
+ // Link this in the open_block
+ //
+ ExInterlockedInsertHeadList(&Open->InactiveVcHead,
+ &Vc->ClientLinkage,
+ &Open->SpinLock.SpinLock);
+ }
+
+ *NdisVcHandle = Vc;
+ return Status;
+}
+
+
+NDIS_STATUS
+NdisCoDeleteVc(
+ IN PNDIS_HANDLE NdisVcHandle
+ )
+/*++
+
+Routine Description:
+
+ Synchronous call from either the call-manager or the client to delete a VC. Only inactive
+ VCs can be deleted. Active Vcs or partially active Vcs cannot be.
+
+Arguments:
+
+ NdisVcHandle The Vc to delete
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS If all goes well
+ NDIS_STATUS_NOT_ACCEPTED If Vc is active
+ NDIS_STATUS_CLOSING If Vc de-activation is pending
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+
+ ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
+
+ if (Vc->Flags & (VC_ACTIVE | VC_ACTIVATE_PENDING))
+ {
+ Status = NDIS_STATUS_NOT_ACCEPTED;
+ }
+ else if (Vc->Flags & VC_DEACTIVATE_PENDING)
+ {
+ Status = NDIS_STATUS_CLOSING;
+ }
+ else
+ {
+ Vc->Flags |= VC_CLOSING;
+
+ //
+ // Call the miniport to delete it first
+ //
+ Status = (*Vc->WCoDeleteVcHandler)(Vc->MiniportContext);
+ ASSERT (Status == NDIS_STATUS_SUCCESS);
+
+ //
+ // Next the non-creator, if any
+ //
+ if (Vc->CoDeleteVcHandler != NULL)
+ {
+ Status = (*Vc->CoDeleteVcHandler)(Vc->DeleteVcContext);
+ ASSERT (Status == NDIS_STATUS_SUCCESS);
+ }
+
+ //
+ // Now de-link the vc from the client and call-manager
+ //
+ ACQUIRE_SPIN_LOCK_DPC(&Vc->ClientOpen->SpinLock.SpinLock);
+ RemoveEntryList(&Vc->ClientLinkage);
+ RELEASE_SPIN_LOCK_DPC(&Vc->ClientOpen->SpinLock.SpinLock);
+
+ if (Vc->CallMgrOpen != NULL)
+ {
+ ACQUIRE_SPIN_LOCK_DPC(&Vc->CallMgrOpen->SpinLock.SpinLock);
+ RemoveEntryList(&Vc->CallMgrLinkage);
+ RELEASE_SPIN_LOCK_DPC(&Vc->CallMgrOpen->SpinLock.SpinLock);
+ }
+
+ Status = NDIS_STATUS_SUCCESS;
+ }
+
+ RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ ndisDereferenceVc(Vc);
+ }
+
+ return Status;
+}
+
+
+NDIS_STATUS
+NdisMCmCreateVc(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE NdisAfHandle,
+ IN NDIS_HANDLE MiniportVcContext,
+ OUT PNDIS_HANDLE NdisVcHandle
+ )
+/*++
+
+Routine Description:
+
+ This is a call by the miniport (with a resident CM) to create a Vc for an incoming call.
+
+Arguments:
+ MiniportAdapterHandle - Miniport's adapter context
+ NdisAfHandle - Pointer to the AF Block.
+ MiniportVcContext - Miniport's context to associate with this vc.
+ NdisVcHandle - Where the handle to this Vc will be returned.
+
+Return Value:
+ NDIS_STATUS_SUCCESS if all the components succeed.
+ ErrorCode to signify why the call failed.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_CO_VC_BLOCK Vc;
+ PNDIS_CO_AF_BLOCK pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
+ NDIS_STATUS Status;
+
+ *NdisVcHandle = NULL;
+
+ //
+ // Allocate the memory for NDIS_VC_BLOCK
+ //
+ Vc = ALLOC_FROM_POOL(sizeof(NDIS_CO_VC_BLOCK), NDIS_TAG_CO);
+ if (Vc == NULL)
+ return NDIS_STATUS_RESOURCES;
+
+ //
+ // Initialize the VC block
+ //
+ NdisZeroMemory(Vc, sizeof(NDIS_CO_VC_BLOCK));
+ INITIALIZE_SPIN_LOCK(&Vc->Lock);
+ InitializeListHead(&Vc->CallMgrLinkage);
+ InitializeListHead(&Vc->ClientLinkage);
+
+ //
+ // Cache some miniport handlers
+ //
+ Vc->Miniport = Miniport;
+ Vc->WCoSendPacketsHandler = Miniport->DriverHandle->MiniportCharacteristics.CoSendPacketsHandler;
+ Vc->WCoDeleteVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoDeleteVcHandler;
+ Vc->WCoActivateVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoActivateVcHandler;
+ Vc->WCoDeactivateVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoDeactivateVcHandler;
+ Vc->MiniportContext = MiniportVcContext;
+
+ //
+ // We have only one reference for vc on creation.
+ //
+ pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
+ Vc->AfBlock = pAf;
+ Vc->References = 1;
+
+ ASSERT (ARGUMENT_PRESENT(NdisAfHandle));
+
+ Vc->ClientOpen = pAf->ClientOpen;
+ Vc->CallMgrOpen = NULL;
+
+ Vc->CoSendCompleteHandler =
+ pAf->ClientOpen->ProtocolHandle->ProtocolCharacteristics.CoSendCompleteHandler;
+ Vc->CoReceivePacketHandler =
+ pAf->ClientOpen->ProtocolHandle->ProtocolCharacteristics.CoReceivePacketHandler;
+ Vc->ClModifyCallQoSCompleteHandler = pAf->ClientEntries.ClModifyCallQoSCompleteHandler;
+ Vc->ClIncomingCallQoSChangeHandler = pAf->ClientEntries.ClIncomingCallQoSChangeHandler;
+ Vc->ClCallConnectedHandler = pAf->ClientEntries.ClCallConnectedHandler;
+
+ Vc->CmActivateVcCompleteHandler = pAf->CallMgrEntries->CmActivateVcCompleteHandler;
+ Vc->CmDeactivateVcCompleteHandler = pAf->CallMgrEntries->CmDeactivateVcCompleteHandler;
+ Vc->CmModifyCallQoSHandler = pAf->CallMgrEntries->CmModifyCallQoSHandler;
+
+ Vc->CallMgrContext = MiniportVcContext;
+
+ //
+ // Call-up to the client now to get its context
+ //
+ Status = (*pAf->ClientOpen->CoCreateVcHandler)(pAf->ClientContext,
+ Vc,
+ &Vc->ClientContext);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Link this in the open_block
+ //
+ Vc->DeleteVcContext = Vc->ClientContext;
+ Vc->CoDeleteVcHandler = pAf->ClientOpen->CoDeleteVcHandler;
+ ExInterlockedInsertHeadList(&pAf->ClientOpen->InactiveVcHead,
+ &Vc->ClientLinkage,
+ &pAf->ClientOpen->SpinLock.SpinLock);
+ }
+ else
+ {
+ Status = (*Vc->WCoDeleteVcHandler)(Vc->MiniportContext);
+
+ FREE_POOL(Vc);
+ Vc = NULL;
+ }
+
+ *NdisVcHandle = Vc;
+ return Status;
+}
+
+
+NDIS_STATUS
+NdisMCmDeleteVc(
+ IN PNDIS_HANDLE NdisVcHandle
+ )
+/*++
+
+Routine Description:
+
+ This is a called by the miniport (with a resident CM) to delete a Vc created by it. Identical to
+ NdisMCoDeleteVc but a seperate api for completeness.
+
+Arguments:
+
+ NdisVcHandle The Vc to delete
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS If all goes well
+ NDIS_STATUS_NOT_ACCEPTED If Vc is active
+ NDIS_STATUS_CLOSING If Vc de-activation is pending
+
+--*/
+{
+ return(NdisMCmDeleteVc(NdisVcHandle));
+}
+
+
+NDIS_STATUS
+NdisCmActivateVc(
+ IN PNDIS_HANDLE NdisVcHandle,
+ IN OUT PCO_CALL_PARAMETERS CallParameters
+ )
+/*++
+
+Routine Description:
+
+ Called by the call-manager to set the Vc parameters on the Vc. The wrapper
+ saved the media id (e.g. Vpi/Vci for atm) in the Vc so that a p-mode protocol can
+ get this info as well on receives.
+
+Arguments:
+
+ NdisVcHandle The Vc to set parameters on.
+ MediaParameters The parameters to set.
+
+Return Value:
+
+ NDIS_STATUS_PENDING If the miniport pends the call.
+ NDIS_STATUS_CLOSING If Vc de-activation is pending
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+
+ ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
+
+ //
+ // Make sure the Vc does not have an activation/de-activation pending
+ // Not that it is ok for the Vc to be already active - then it is a re-activation.
+ //
+ if (Vc->Flags & VC_ACTIVATE_PENDING)
+ {
+ Status = NDIS_STATUS_NOT_ACCEPTED;
+ }
+ else if (Vc->Flags & VC_DEACTIVATE_PENDING)
+ {
+ Status = NDIS_STATUS_CLOSING;
+ }
+ else
+ {
+ Vc->Flags |= VC_ACTIVATE_PENDING;
+
+ //
+ // Save the media id for the Vc
+ //
+ Status = NDIS_STATUS_SUCCESS;
+ Vc->pVcId = &CallParameters->MediaParameters->MediaSpecific;
+ }
+
+ RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Now call down to the miniport to activate it
+ //
+ Status = (*Vc->WCoActivateVcHandler)(Vc->MiniportContext, CallParameters);
+ }
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisMCoActivateVcComplete(Status, Vc, CallParameters);
+ Status = NDIS_STATUS_PENDING;
+ }
+
+ return Status;
+}
+
+
+NDIS_STATUS
+NdisMCmActivateVc(
+ IN PNDIS_HANDLE NdisVcHandle,
+ IN PCO_CALL_PARAMETERS CallParameters
+ )
+/*++
+
+Routine Description:
+
+ Called by the miniport resident call-manager to set the Vc parameters on the Vc. This is a
+ synchronous call.
+
+Arguments:
+
+ NdisVcHandle The Vc to set parameters on.
+ MediaParameters The parameters to set.
+
+Return Value:
+
+ NDIS_STATUS_CLOSING If Vc de-activation is pending
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+
+ ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
+
+ //
+ // Make sure the Vc does not have an activation/de-activation pending
+ // Not that it is ok for the Vc to be already active - then it is a re-activation.
+ //
+ if (Vc->Flags & VC_ACTIVATE_PENDING)
+ {
+ Status = NDIS_STATUS_NOT_ACCEPTED;
+ }
+ else if (Vc->Flags & VC_DEACTIVATE_PENDING)
+ {
+ Status = NDIS_STATUS_CLOSING;
+ }
+ else
+ {
+ Vc->Flags |= VC_ACTIVE;
+ Status = NDIS_STATUS_SUCCESS;
+ Vc->pVcId = &CallParameters->MediaParameters->MediaSpecific;
+ }
+
+ RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
+
+ return Status;
+}
+
+
+VOID
+NdisMCoActivateVcComplete(
+ IN NDIS_STATUS Status,
+ IN PNDIS_HANDLE NdisVcHandle,
+ IN PCO_CALL_PARAMETERS CallParameters
+ )
+/*++
+
+Routine Description:
+
+ Called by the mini-port to complete a pending activation call.
+
+Arguments:
+
+ Status Status of activation.
+ NdisVcHandle The Vc in question.
+
+Return Value:
+
+ NONE
+ The call-manager's completion routine is called.
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ KIRQL OldIrql;
+
+ ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
+
+ ASSERT (Vc->Flags & VC_ACTIVATE_PENDING);
+
+ Vc->Flags &= ~VC_ACTIVATE_PENDING;
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ Vc->Flags |= VC_ACTIVE;
+ }
+
+ RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
+
+ //
+ // Complete the call to the call-manager
+ //
+ (*Vc->CmActivateVcCompleteHandler)(Status, Vc->CallMgrContext, CallParameters);
+}
+
+
+NDIS_STATUS
+NdisCmDeactivateVc(
+ IN PNDIS_HANDLE NdisVcHandle
+ )
+/*++
+
+Routine Description:
+
+ Called by the call-manager to de-activate a Vc.
+
+Arguments:
+
+ NdisVcHandle The Vc to de-activate the Vc.
+
+Return Value:
+
+ NDIS_STATUS_PENDING If the miniport pends the call.
+ NDIS_STATUS_SUCCESS If all goes well
+ NDIS_STATUS_CLOSING If Vc de-activation is pending
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+
+ ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
+
+ if ((Vc->Flags & (VC_ACTIVE | VC_ACTIVATE_PENDING)) == 0)
+ {
+ Status = NDIS_STATUS_NOT_ACCEPTED;
+ }
+ else if (Vc->Flags & VC_DEACTIVATE_PENDING)
+ {
+ Status = NDIS_STATUS_CLOSING;
+ }
+ else
+ {
+ Vc->Flags |= VC_DEACTIVATE_PENDING;
+ }
+
+ RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
+
+ //
+ // Now call down to the miniport to de-activate it
+ //
+ Status = (*Vc->WCoDeactivateVcHandler)(Vc->MiniportContext);
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisMCoDeactivateVcComplete(Status, Vc);
+ Status = NDIS_STATUS_PENDING;
+ }
+
+ return Status;
+}
+
+
+NDIS_STATUS
+NdisMCmDeactivateVc(
+ IN PNDIS_HANDLE NdisVcHandle
+ )
+/*++
+
+Routine Description:
+
+ Called by the miniport resident call-manager to de-activate the Vc. This is a
+ synchronous call.
+
+Arguments:
+
+ NdisVcHandle The Vc to set parameters on.
+
+Return Value:
+
+ NDIS_STATUS_CLOSING If Vc de-activation is pending
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+
+ ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
+
+ if ((Vc->Flags & (VC_ACTIVE | VC_ACTIVATE_PENDING)) == 0)
+ {
+ Status = NDIS_STATUS_NOT_ACCEPTED;
+ }
+ else if (Vc->Flags & VC_DEACTIVATE_PENDING)
+ {
+ Status = NDIS_STATUS_CLOSING;
+ }
+ else
+ {
+ Status = NDIS_STATUS_SUCCESS;
+ Vc->Flags &= ~VC_ACTIVE;
+ }
+
+ RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
+
+ return Status;
+}
+
+
+VOID
+NdisMCoDeactivateVcComplete(
+ IN NDIS_STATUS Status,
+ IN PNDIS_HANDLE NdisVcHandle
+ )
+/*++
+
+Routine Description:
+
+ Called by the mini-port to complete a pending de-activation of a Vc.
+
+Arguments:
+
+ NdisVcHandle The Vc in question.
+
+Return Value:
+
+ NONE
+ The call-manager's completion routine is called.
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ KIRQL OldIrql;
+
+ ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
+
+ ASSERT (Vc->Flags & VC_DEACTIVATE_PENDING);
+
+ Vc->Flags &= ~VC_DEACTIVATE_PENDING;
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ Vc->Flags &= ~VC_ACTIVE;
+ }
+
+ RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
+
+ //
+ // Complete the call to the call-manager
+ //
+ (*Vc->CmDeactivateVcCompleteHandler)(Status, Vc->CallMgrContext);
+}
+
+
+NDIS_STATUS
+NdisClMakeCall(
+ IN NDIS_HANDLE NdisVcHandle,
+ IN OUT PCO_CALL_PARAMETERS CallParameters,
+ IN NDIS_HANDLE ProtocolPartyContext OPTIONAL,
+ OUT PNDIS_HANDLE NdisPartyHandle OPTIONAL
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ PNDIS_CO_AF_BLOCK pAf;
+ PNDIS_CO_PARTY_BLOCK pParty = NULL;
+ PVOID CallMgrPartyContext = NULL;
+ NDIS_STATUS Status;
+
+ do
+ {
+ pAf = Vc->AfBlock;
+ ASSERT (pAf != NULL);
+ if (!ndisReferenceAf(pAf))
+ {
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ if (ARGUMENT_PRESENT(NdisPartyHandle))
+ {
+ *NdisPartyHandle = NULL;
+ pParty = (PNDIS_CO_PARTY_BLOCK)ALLOC_FROM_POOL(sizeof(NDIS_CO_PARTY_BLOCK),
+ NDIS_TAG_CO);
+ if (pParty == NULL)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+ pParty->Vc = Vc;
+ pParty->ClientContext = ProtocolPartyContext;
+ pParty->ClIncomingDropPartyHandler =
+ pAf->ClientEntries.ClIncomingDropPartyHandler;
+ pParty->ClDropPartyCompleteHandler =
+ pAf->ClientEntries.ClDropPartyCompleteHandler;
+ }
+
+ //
+ // Pass the request off to the call manager
+ //
+ Status = (*pAf->CallMgrEntries->CmMakeCallHandler)(Vc->CallMgrContext,
+ CallParameters,
+ pParty,
+ &CallMgrPartyContext);
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisCmMakeCallComplete(Status,
+ Vc,
+ pParty,
+ CallMgrPartyContext,
+ CallParameters);
+ Status = NDIS_STATUS_PENDING;
+ }
+ } while (FALSE);
+
+ if (!NT_SUCCESS(Status))
+ {
+ //
+ // These are resource failures and not a failure from call-manager
+ //
+ if (pParty != NULL)
+ {
+ FREE_POOL(pParty);
+ }
+ }
+
+ return Status;
+}
+
+
+VOID
+NdisCmMakeCallComplete(
+ IN NDIS_STATUS Status,
+ IN NDIS_HANDLE NdisVcHandle,
+ IN NDIS_HANDLE NdisPartyHandle OPTIONAL,
+ IN NDIS_HANDLE CallMgrPartyContext OPTIONAL,
+ IN PCO_CALL_PARAMETERS CallParameters
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_CO_AF_BLOCK pAf;
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
+ KIRQL OldIrql;
+
+ pAf = Vc->AfBlock;
+
+ ASSERT (Status != NDIS_STATUS_PENDING);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Call completed successfully. Complete it to the client.
+ //
+
+ //
+ // Reference the Vc for the client. This is dereferenced when
+ // the client calls NdisClCloseCall()
+ //
+ ndisReferenceVc(Vc);
+
+
+ if (ARGUMENT_PRESENT(NdisPartyHandle))
+ {
+ pParty->CallMgrContext = CallMgrPartyContext;
+ ndisReferenceVc(Vc);
+ }
+
+ ACQUIRE_SPIN_LOCK(&pAf->ClientOpen->SpinLock.SpinLock, &OldIrql);
+ RemoveEntryList(&Vc->ClientLinkage);
+ InsertHeadList(&pAf->ClientOpen->ActiveVcHead,
+ &Vc->ClientLinkage);
+ RELEASE_SPIN_LOCK(&pAf->ClientOpen->SpinLock.SpinLock, OldIrql);
+ }
+ else
+ {
+ ndisDereferenceAf(pAf);
+ }
+
+ (*pAf->ClientEntries.ClMakeCallCompleteHandler)(Status,
+ Vc->ClientContext,
+ pParty,
+ CallParameters);
+}
+
+
+NDIS_STATUS
+NdisCmDispatchIncomingCall(
+ IN NDIS_HANDLE NdisSapHandle,
+ IN NDIS_HANDLE NdisVcHandle,
+ IN OUT PCO_CALL_PARAMETERS CallParameters
+ )
+/*++
+
+Routine Description:
+
+ Call from the call-manager to dispatch an incoming vc to the client who registered the Sap.
+ The client is identified by the NdisSapHandle.
+
+Arguments:
+
+ NdisBindingHandle - Identifies the miniport on which the Vc is created
+ NdisSapHandle - Identifies the client
+ CallParameters - Self explanatory
+ NdisVcHandle - Pointer to the NDIS_CO_VC_BLOCK created via NdisCmCreateVc
+
+Return Value:
+
+ Return value from the client or an processing error.
+
+--*/
+{
+ PNDIS_CO_SAP_BLOCK Sap;
+ PNDIS_CO_VC_BLOCK Vc;
+ PNDIS_CO_AF_BLOCK pAf;
+ NDIS_STATUS Status;
+
+ Sap = (PNDIS_CO_SAP_BLOCK)NdisSapHandle;
+ Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ pAf = Sap->AfBlock;
+
+ ASSERT(pAf == Vc->AfBlock);
+
+ //
+ // Make sure the SAP's not closing
+ //
+ if (!ndisReferenceSap(Sap))
+ {
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // Make sure the AF is not closing
+ //
+ if (!ndisReferenceAf(pAf))
+ {
+ ndisDereferenceSap(Sap);
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // Notify the client of this call
+ //
+ Status = (*pAf->ClientEntries.ClIncomingCallHandler)(Sap->ClientContext,
+ Vc->ClientContext,
+ CallParameters);
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisClIncomingCallComplete(Status, Vc, CallParameters);
+ Status = NDIS_STATUS_PENDING;
+ }
+
+ ndisDereferenceSap(Sap);
+
+ return Status;
+}
+
+
+VOID
+NdisClIncomingCallComplete(
+ IN NDIS_STATUS Status,
+ IN NDIS_HANDLE NdisVcHandle,
+ IN PCO_CALL_PARAMETERS CallParameters
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ KIRQL OldIrql;
+
+ ASSERT (Status != NDIS_STATUS_PENDING);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ ACQUIRE_SPIN_LOCK(&Vc->ClientOpen->SpinLock.SpinLock, &OldIrql);
+ //
+ // Reference the Vc. This is dereferenced when NdisClCloseCall is called.
+ //
+ Vc->References ++;
+ RemoveEntryList(&Vc->ClientLinkage);
+ InsertHeadList(&Vc->ClientOpen->ActiveVcHead,
+ &Vc->ClientLinkage);
+
+ RELEASE_SPIN_LOCK(&Vc->ClientOpen->SpinLock.SpinLock, OldIrql);
+ }
+
+ //
+ // Call the call-manager handler to notify that client is done with this.
+ //
+ (*Vc->AfBlock->CallMgrEntries->CmIncomingCallCompleteHandler)(
+ Status,
+ Vc->CallMgrContext,
+ CallParameters);
+}
+
+
+VOID
+NdisCmDispatchCallConnected(
+ IN NDIS_HANDLE NdisVcHandle
+ )
+/*++
+
+Routine Description:
+
+ Called by the call-manager to complete the final hand-shake on an incoming call.
+
+Arguments:
+
+ NdisVcHandle - Pointer to the vc block
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+
+ (*Vc->ClCallConnectedHandler)(Vc->ClientContext);
+}
+
+
+NDIS_STATUS
+NdisClModifyCallQoS(
+ IN NDIS_HANDLE NdisVcHandle,
+ IN PCO_CALL_PARAMETERS CallParameters
+ )
+/*++
+
+Routine Description:
+
+ Initiated by the client to modify the QoS associated with the call.
+
+Arguments:
+
+ NdisVcHandle - Pointer to the vc block
+ CallParameters - New call QoS
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ NDIS_STATUS Status;
+
+ //
+ // Ask the call-manager to take care of this
+ //
+ Status = (*Vc->CmModifyCallQoSHandler)(Vc->CallMgrContext,
+ CallParameters);
+ return Status;
+}
+
+VOID
+NdisCmModifyCallQoSComplete(
+ IN NDIS_STATUS Status,
+ IN NDIS_HANDLE NdisVcHandle,
+ IN PCO_CALL_PARAMETERS CallParameters
+ )
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+
+ //
+ // Simply notify the client
+ //
+ (*Vc->ClModifyCallQoSCompleteHandler)(Status,
+ Vc->ClientContext,
+ CallParameters);
+}
+
+
+VOID
+NdisCmDispatchIncomingCallQoSChange(
+ IN NDIS_HANDLE NdisVcHandle,
+ IN PCO_CALL_PARAMETERS CallParameters
+ )
+/*++
+
+Routine Description:
+
+ Called by the call-manager to indicate a remote requested change in the call-qos. This is
+ simply an indication. A client must respond by either accepting it (do nothing) or reject
+ it (by either modifying the call qos or by tearing down the call).
+
+Arguments:
+
+ NdisVcHandle - Pointer to the vc block
+ CallParameters - New call qos
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+
+ //
+ // Simply notify the client
+ //
+ (*Vc->ClIncomingCallQoSChangeHandler)(Vc->ClientContext,
+ CallParameters);
+}
+
+
+NDIS_STATUS
+NdisClCloseCall(
+ IN NDIS_HANDLE NdisVcHandle,
+ IN NDIS_HANDLE NdisPartyHandle OPTIONAL,
+ IN PVOID Buffer OPTIONAL,
+ IN UINT Size OPTIONAL
+ )
+/*++
+
+Routine Description:
+
+ Called by the client to close down a connection established via either NdisClMakeCall
+ or accepting an incoming call via NdisClIncomingCallComplete. The optional buffer can
+ be specified by the client to send a disconnect message. Upto the call-manager to do
+ something reasonable with it.
+
+Arguments:
+
+ NdisVcHandle - Pointer to the vc block
+ Buffer - Optional disconnect message
+ Size - Size of the disconnect message
+
+Return Value:
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
+ NDIS_STATUS Status;
+
+ //
+ // Simply notify the call-manager
+ //
+ Status = (*Vc->AfBlock->CallMgrEntries->CmCloseCallHandler)(Vc->CallMgrContext,
+ (pParty != NULL) ?
+ pParty->CallMgrContext :
+ NULL,
+ Buffer,
+ Size);
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisCmCloseCallComplete(Status, Vc, pParty);
+ Status = NDIS_STATUS_PENDING;
+ }
+
+ return Status;
+}
+
+
+VOID
+NdisCmCloseCallComplete(
+ IN NDIS_STATUS Status,
+ IN NDIS_HANDLE NdisVcHandle,
+ IN NDIS_HANDLE NdisPartyHandle OPTIONAL
+ )
+/*++
+
+Routine Description:
+
+
+
+Arguments:
+
+ NdisVcHandle - Pointer to the vc block
+
+Return Value:
+
+ Nothing. Client handler called
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
+
+ //
+ // Notify the client and dereference the Vc
+ //
+ (*Vc->AfBlock->ClientEntries.ClCloseCallCompleteHandler)(Status,
+ Vc->ClientContext,
+ (pParty != NULL) ?
+ pParty->CallMgrContext :
+ NULL);
+
+ ndisDereferenceAf(Vc->AfBlock);
+ ndisDereferenceVc(Vc);
+ if (pParty != NULL)
+ {
+ ASSERT (Vc == pParty->Vc);
+ ndisDereferenceVc(pParty->Vc);
+ FREE_POOL(pParty);
+ }
+}
+
+
+VOID
+NdisCmDispatchIncomingCloseCall(
+ IN NDIS_STATUS CloseStatus,
+ IN NDIS_HANDLE NdisVcHandle,
+ IN PVOID Buffer,
+ IN UINT Size
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+
+ //
+ // Notify the client
+ //
+ (*Vc->AfBlock->ClientEntries.ClIncomingCloseCallHandler)(
+ CloseStatus,
+ Vc->ClientContext,
+ Buffer,
+ Size);
+}
+
+
+NDIS_STATUS
+NdisClAddParty(
+ IN NDIS_HANDLE NdisVcHandle,
+ IN NDIS_HANDLE ProtocolPartyContext,
+ IN OUT PCO_CALL_PARAMETERS CallParameters,
+ OUT PNDIS_HANDLE NdisPartyHandle
+ )
+/*++
+
+Routine Description:
+
+ Call from the client to the call-manager to add a party to a point-to-multi-point call.
+
+Arguments:
+
+ NdisVcHandle - The handle client obtained via NdisClMakeCall()
+ ProtocolPartyContext - Protocol's context for this leaf
+ Flags - Call flags
+ CallParameters - Call parameters
+ NdisPartyHandle - Place holder for the handle to identify the leaf
+
+Return Value:
+
+ NDIS_STATUS_PENDING The call has pended and will complete via CoAddPartyCompleteHandler.
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ PNDIS_CO_PARTY_BLOCK pParty;
+ NDIS_STATUS Status;
+
+ do
+ {
+ *NdisPartyHandle = NULL;
+ if (!ndisReferenceVc(Vc))
+ {
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ pParty = ALLOC_FROM_POOL(sizeof(NDIS_CO_PARTY_BLOCK), NDIS_TAG_CO);
+ if (pParty == NULL)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ pParty->ClientContext = ProtocolPartyContext;
+ pParty->Vc = Vc;
+ pParty->ClIncomingDropPartyHandler =
+ Vc->AfBlock->ClientEntries.ClIncomingDropPartyHandler;
+ pParty->ClDropPartyCompleteHandler =
+ Vc->AfBlock->ClientEntries.ClDropPartyCompleteHandler;
+
+ //
+ // Simply call the call-manager to do its stuff.
+ //
+ Status = (*Vc->AfBlock->CallMgrEntries->CmAddPartyHandler)(
+ Vc->CallMgrContext,
+ CallParameters,
+ pParty,
+ &pParty->CallMgrContext);
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisCmAddPartyComplete(Status,
+ pParty,
+ pParty->CallMgrContext,
+ CallParameters);
+ Status = NDIS_STATUS_PENDING;
+ }
+ } while (FALSE);
+
+ return Status;
+}
+
+
+VOID
+NdisCmAddPartyComplete(
+ IN NDIS_STATUS Status,
+ IN NDIS_HANDLE NdisPartyHandle,
+ IN NDIS_HANDLE CallMgrPartyContext OPTIONAL,
+ IN PCO_CALL_PARAMETERS CallParameters
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
+
+ ASSERT (Status != NDIS_STATUS_PENDING);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ pParty->CallMgrContext = CallMgrPartyContext;
+ }
+
+ //
+ // Complete the call to the client
+ //
+ (*pParty->Vc->AfBlock->ClientEntries.ClAddPartyCompleteHandler)(
+ Status,
+ pParty->ClientContext,
+ pParty,
+ CallParameters);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ ndisDereferenceVc(pParty->Vc);
+ FREE_POOL(pParty);
+ }
+}
+
+
+NDIS_STATUS
+NdisClDropParty(
+ IN NDIS_HANDLE NdisPartyHandle,
+ IN PVOID Buffer OPTIONAL,
+ IN UINT Size OPTIONAL
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
+ NDIS_STATUS Status;
+
+ //
+ // Pass it along to the call-manager to handle this
+ //
+ Status = (*pParty->Vc->AfBlock->CallMgrEntries->CmDropPartyHandler)(
+ pParty->CallMgrContext,
+ Buffer,
+ Size);
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisCmDropPartyComplete(Status, pParty);
+ Status = NDIS_STATUS_PENDING;
+ }
+
+ return Status;
+}
+
+
+VOID
+NdisCmDropPartyComplete(
+ IN NDIS_STATUS Status,
+ IN NDIS_HANDLE NdisPartyHandle
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
+
+ ASSERT (Status != NDIS_STATUS_PENDING);
+
+ //
+ // Complete the call to the client
+ //
+ (*pParty->ClDropPartyCompleteHandler)(Status,
+ pParty->ClientContext);
+ ndisDereferenceVc(pParty->Vc);
+ FREE_POOL(pParty);
+}
+
+
+VOID
+NdisCmDispatchIncomingDropParty(
+ IN NDIS_STATUS DropStatus,
+ IN NDIS_HANDLE NdisPartyHandle,
+ IN PVOID Buffer,
+ IN UINT Size
+ )
+/*++
+
+Routine Description:
+
+ Called by the call-manager to notify the client that this leaf of the multi-party
+ call is terminated. The client cannot use the NdisPartyHandle after completing this
+ call - synchronously or by calling NdisClIncomingDropPartyComplete.
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
+
+ //
+ // Notify the client
+ //
+ (*pParty->ClIncomingDropPartyHandler)(DropStatus,
+ pParty->ClientContext,
+ Buffer,
+ Size);
+}
+
+
+BOOLEAN
+ndisReferenceVc(
+ IN PNDIS_CO_VC_BLOCK Vc
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ KIRQL OldIrql;
+ BOOLEAN rc = FALSE;
+
+ ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
+
+ if ((Vc->Flags & VC_CLOSING) == 0)
+ {
+ Vc->References ++;
+ rc = TRUE;
+ }
+
+ RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
+
+ return rc;
+}
+
+
+VOID
+ndisDereferenceVc(
+ IN PNDIS_CO_VC_BLOCK Vc
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ KIRQL OldIrql;
+ BOOLEAN Done = FALSE;
+
+ ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
+
+ ASSERT (Vc->References > 0);
+ Vc->References --;
+ if (Vc->References == 0)
+ {
+ ASSERT (Vc->Flags & VC_CLOSING);
+ Done = TRUE;
+ }
+
+ RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
+
+ if (Done)
+ FREE_POOL(Vc);
+}
+
+
+VOID
+ndisMCoFreeResources(
+ PNDIS_M_OPEN_BLOCK Open
+ )
+/*++
+
+Routine Description:
+
+ Cleans-up address family list for call-managers etc.
+
+ CALLED WITH MINIPORT LOCK HELD.
+
+Arguments:
+
+ Open - Pointer to the Open block for miniports
+
+Return Value:
+
+ None
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PNDIS_AF_LIST *pAfList, pTmp;
+
+ Miniport = Open->MiniportHandle;
+
+ for (pAfList = &Miniport->CallMgrAfList;
+ (pTmp = *pAfList) != NULL;
+ NOTHING)
+ {
+ if (pTmp->Open == Open)
+ {
+ *pAfList = pTmp->NextOpen;
+ FREE_POOL(pTmp);
+ }
+ else
+ {
+ pAfList = &pTmp->NextOpen;
+ }
+ }
+
+ ASSERT (IsListEmpty(&Open->ActiveVcHead));
+ ASSERT (IsListEmpty(&Open->InactiveVcHead));
+}
+
+
+NDIS_STATUS
+NdisCoRequest(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE NdisAfHandle OPTIONAL,
+ IN NDIS_HANDLE NdisVcHandle OPTIONAL,
+ IN NDIS_HANDLE NdisPartyHandle OPTIONAL,
+ IN PNDIS_REQUEST NdisRequest
+ )
+/*++
+
+Routine Description:
+
+ This api is used for two separate paths.
+ 1. A symmetric call between the client and the call-manager. This mechanism is a
+ two-way mechanism for the call-manager and client to communicate with each other in an
+ asynchronous manner.
+ 2. A request down to the miniport.
+
+Arguments:
+
+ NdisBindingHandle - Specifies the binding and identifies the caller as call-manager/client
+ NdisAfHandle - Pointer to the AF Block and identifies the target. If absent, the
+ request is targeted to the miniport.
+ NdisVcHandle - Pointer to optional VC block. If present the request relates to the
+ VC
+ NdisPartyHandle - Pointer to the optional Party Block. If present the request relates
+ to the party.
+ NdisRequest - The request itself
+
+Return Value:
+ NDIS_STATUS_PENDING if the target pends the call.
+ NDIS_STATUS_FAILURE if the binding or af is closing.
+ Anything else return code from the other end.
+
+--*/
+{
+ PNDIS_M_OPEN_BLOCK Open;
+ PNDIS_CO_AF_BLOCK pAf;
+ NDIS_HANDLE VcContext;
+ PNDIS_COREQ_RESERVED ReqRsvd;
+ NDIS_STATUS Status;
+
+ ReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(NdisRequest);
+ Open = (PNDIS_M_OPEN_BLOCK)(((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacBindingHandle);
+
+ do
+ {
+ if (ARGUMENT_PRESENT(NdisAfHandle))
+ {
+ CO_REQUEST_HANDLER CoRequestHandler;
+ NDIS_HANDLE AfContext, PartyContext;
+
+ pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
+ //
+ // Attempt to reference the AF
+ //
+ if (!ndisReferenceAf(pAf))
+ {
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ VcContext = NULL;
+ PartyContext = NULL;
+ NdisZeroMemory(ReqRsvd, sizeof(NDIS_COREQ_RESERVED));
+
+ //
+ // Figure out who we are and call the peer
+ //
+ if (pAf->ClientOpen == Open)
+ {
+ //
+ // This is the client, so call the call-manager's CoRequestHandler
+ //
+ CoRequestHandler =
+ pAf->CallMgrOpen->ProtocolHandle->ProtocolCharacteristics.CoRequestHandler;
+ AfContext = pAf->CallMgrContext;
+ ReqRsvd->AfContext = pAf->ClientContext;
+ ReqRsvd->CoRequestCompleteHandler = Open->CoRequestCompleteHandler;
+ if (ARGUMENT_PRESENT(NdisVcHandle))
+ {
+ VcContext = ((PNDIS_CO_VC_BLOCK)NdisVcHandle)->CallMgrContext;
+ }
+ if (ARGUMENT_PRESENT(NdisPartyHandle))
+ {
+ PartyContext = ((PNDIS_CO_PARTY_BLOCK)NdisPartyHandle)->CallMgrContext;
+ }
+ }
+ else
+ {
+ ASSERT (pAf->CallMgrOpen == Open);
+ //
+ // This is the call-manager, so call the client's CoRequestHandler
+ //
+ CoRequestHandler =
+ pAf->ClientOpen->ProtocolHandle->ProtocolCharacteristics.CoRequestHandler;
+ AfContext = pAf->ClientContext;
+ ReqRsvd->AfContext = pAf->CallMgrContext;
+ ReqRsvd->CoRequestCompleteHandler = Open->CoRequestCompleteHandler;
+ if (ARGUMENT_PRESENT(NdisVcHandle))
+ {
+ ReqRsvd->VcContext = pAf->CallMgrContext;
+ VcContext = ((PNDIS_CO_VC_BLOCK)NdisVcHandle)->ClientContext;
+ }
+ if (ARGUMENT_PRESENT(NdisPartyHandle))
+ {
+ ReqRsvd->PartyContext = ((PNDIS_CO_PARTY_BLOCK)NdisPartyHandle)->CallMgrContext;
+ PartyContext = ((PNDIS_CO_PARTY_BLOCK)NdisPartyHandle)->ClientContext;
+ }
+ }
+
+ //
+ // Now call the handler
+ //
+ Status = (*CoRequestHandler)(AfContext, VcContext, PartyContext, NdisRequest);
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisCoRequestComplete(Status,
+ NdisAfHandle,
+ NdisVcHandle,
+ NdisPartyHandle,
+ NdisRequest);
+
+ Status = NDIS_STATUS_PENDING;
+ }
+ }
+ else
+ {
+ KIRQL OldIrql;
+ PNDIS_MINIPORT_BLOCK Miniport;
+
+ Miniport = Open->MiniportHandle;
+
+ //
+ // Start off by referencing the open.
+ //
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ if (Open->Flags & fMINIPORT_OPEN_CLOSING)
+ {
+ Status = NDIS_STATUS_CLOSING;
+ }
+ else if (Miniport->Flags & (fMINIPORT_RESET_IN_PROGRESS | fMINIPORT_RESET_REQUESTED))
+ {
+ Status = NDIS_STATUS_RESET_IN_PROGRESS;
+ }
+ else
+ {
+ Open->References ++;
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ ReqRsvd->Open = Open;
+ ReqRsvd->CoRequestCompleteHandler = Open->CoRequestCompleteHandler;
+ ReqRsvd->VcContext = NULL;
+ ReqRsvd->Flags = COREQ_DOWNLEVEL;
+ ReqRsvd->RealRequest = NdisRequest;
+ if (ARGUMENT_PRESENT(NdisVcHandle))
+ {
+ ReqRsvd->VcContext = ((PNDIS_CO_VC_BLOCK)NdisVcHandle)->ClientContext;
+ }
+
+ //
+ // Call the miniport's CoRequest Handler
+ //
+ Status = (*Open->MiniportCoRequestHandler)(Open->MiniportAdapterContext,
+ (NdisVcHandle != NULL) ?
+ ((PNDIS_CO_VC_BLOCK)NdisVcHandle)->MiniportContext :
+ NULL,
+ NdisRequest);
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisMCoRequestComplete(Status,
+ Open->MiniportHandle,
+ NdisRequest);
+ }
+ }
+
+ }
+ } while (FALSE);
+
+ return Status;
+}
+
+
+VOID
+NdisCoRequestComplete(
+ IN NDIS_STATUS Status,
+ IN NDIS_HANDLE NdisAfHandle,
+ IN NDIS_HANDLE NdisVcHandle OPTIONAL,
+ IN NDIS_HANDLE NdisPartyHandle OPTIONAL,
+ IN PNDIS_REQUEST NdisRequest
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_COREQ_RESERVED ReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(NdisRequest);
+
+ //
+ // Simply call the request completion handler and deref the Af block
+ //
+ (*ReqRsvd->CoRequestCompleteHandler)(Status,
+ ReqRsvd->AfContext,
+ ReqRsvd->VcContext,
+ ReqRsvd->PartyContext,
+ NdisRequest);
+ ndisDereferenceAf((PNDIS_CO_AF_BLOCK)NdisAfHandle);
+}
+
+
+VOID
+NdisMCoRequestComplete(
+ IN NDIS_STATUS Status,
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_COREQ_RESERVED ReqRsvd;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PNDIS_M_OPEN_BLOCK Open;
+
+ ReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(NdisRequest);
+ Miniport = (PNDIS_MINIPORT_BLOCK)NdisBindingHandle;
+ Open = ReqRsvd->Open;
+
+ if ((NdisRequest->RequestType == NdisRequestQueryInformation) &&
+ (NdisRequest->DATA.QUERY_INFORMATION.Oid == OID_GEN_CURRENT_PACKET_FILTER) &&
+ (NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength != 0))
+ {
+ if (Open->Flags & fMINIPORT_OPEN_PMODE)
+ {
+ *(PULONG)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer) |=
+ NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL;
+ }
+ }
+
+ if (Open != NULL)
+ {
+ PNDIS_REQUEST RealRequest;
+ KIRQL OldIrql;
+
+ RealRequest = NdisRequest;
+ if (ReqRsvd->RealRequest != NULL)
+ {
+ RealRequest = ReqRsvd->RealRequest;
+ RealRequest->DATA.QUERY_INFORMATION.BytesWritten = NdisRequest->DATA.QUERY_INFORMATION.BytesWritten;
+ RealRequest->DATA.QUERY_INFORMATION.BytesNeeded = NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded;
+ }
+
+ RealRequest = (ReqRsvd->RealRequest == NULL) ? NdisRequest : ReqRsvd->RealRequest;
+ ASSERT ((ReqRsvd->Flags & (COREQ_GLOBAL_REQ | COREQ_QUERY_OIDS)) == 0);
+
+ if (ReqRsvd->Flags == COREQ_DOWNLEVEL)
+ {
+ ASSERT(RealRequest != NdisRequest);
+
+ //
+ // Complete the request to the protocol and deref the open
+ //
+ (*ReqRsvd->RequestCompleteHandler)(ReqRsvd->Open->ProtocolBindingContext,
+ RealRequest,
+ Status);
+ FREE_POOL(NdisRequest);
+ }
+ else
+ {
+ ASSERT(RealRequest == NdisRequest);
+
+ //
+ // Complete the request to the protocol and deref the open
+ //
+ (*ReqRsvd->CoRequestCompleteHandler)(Status,
+ ReqRsvd->Open->ProtocolBindingContext,
+ ReqRsvd->VcContext,
+ NULL,
+ NdisRequest);
+ }
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ Open->References --;
+ if (Open->References == 0)
+ {
+ ndisMFinishClose(Miniport, Open);
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+ }
+ else if (ReqRsvd->Flags == COREQ_GLOBAL_REQ)
+ {
+ PIRP Irp;
+ PNDIS_QUERY_GLOBAL_REQUEST GlobalRequest;
+
+ GlobalRequest = CONTAINING_RECORD(NdisRequest,
+ NDIS_QUERY_GLOBAL_REQUEST,
+ Request);
+
+ ASSERT(ReqRsvd->RealRequest == NULL);
+ Irp = GlobalRequest->Irp;
+ Irp->IoStatus.Information = NdisRequest->DATA.QUERY_INFORMATION.BytesWritten;
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ }
+ else if (Status == NDIS_STATUS_INVALID_LENGTH)
+ {
+ Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
+ }
+ else
+ {
+ Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+ }
+
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ FREE_POOL (GlobalRequest);
+ }
+ else if (ReqRsvd->Flags == COREQ_QUERY_OIDS)
+ {
+ PNDIS_QUERY_OPEN_REQUEST OpenReq;
+
+ ASSERT(ReqRsvd->RealRequest == NULL);
+ OpenReq = CONTAINING_RECORD(NdisRequest,
+ NDIS_QUERY_OPEN_REQUEST,
+ Request);
+ OpenReq->NdisStatus = Status;
+ SET_EVENT(&OpenReq->Event);
+ }
+ else if (ReqRsvd->Flags == COREQ_QUERY_STATS)
+ {
+ PNDIS_QUERY_ALL_REQUEST AllReq;
+
+ ASSERT(ReqRsvd->RealRequest == NULL);
+ AllReq = CONTAINING_RECORD(NdisRequest,
+ NDIS_QUERY_ALL_REQUEST,
+ Request);
+ AllReq->NdisStatus = Status;
+ SET_EVENT(&AllReq->Event);
+ }
+ else if (ReqRsvd->Flags == COREQ_QUERY_SET)
+ {
+ PNDIS_QS_REQUEST QSReq;
+
+ ASSERT(ReqRsvd->RealRequest == NULL);
+ QSReq = CONTAINING_RECORD(NdisRequest,
+ NDIS_QS_REQUEST,
+ Request);
+ QSReq->NdisStatus = Status;
+ SET_EVENT(&QSReq->Event);
+ }
+ else
+ {
+ ASSERT(0);
+ }
+}
+
+
+VOID
+NdisMCoIndicateReceivePacket(
+ IN NDIS_HANDLE NdisVcHandle,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by the Miniport to indicate a set of packets to
+ a particular VC.
+
+Arguments:
+
+ NdisVcHandle - The handle suppplied by Ndis when the VC on which
+ data is received was first reserved.
+
+ PacketArray - Array of packets.
+
+ NumberOfPackets - Number of packets being indicated.
+
+Return Value:
+
+ None.
+--*/
+{
+ UINT i, Ref, NumPmodeOpens;
+ PPNDIS_PACKET pPktArray;
+ NDIS_STATUS Status;
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ PNDIS_MINIPORT_BLOCK Miniport;
+
+ Miniport = Vc->Miniport;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID);
+
+ //
+ // NOTE that checking Vc Flags for Closing should not be needed since the CallMgr
+ // holds onto the protocol's CloseCall request until the ref count goes to zero -
+ // which means the miniport has to have completed its RELEASE_VC, which will
+ // inturn mandate that we will NOT get any further indications from it.
+ // The miniport must not complete a RELEASE_VC until it is no longer indicating data.
+ //
+ for (i = 0, pPktArray = PacketArray;
+ i < NumberOfPackets;
+ i++, pPktArray++)
+ {
+ PNDIS_PACKET Packet;
+ NDIS_STATUS SavedStatus;
+
+ Packet = *pPktArray;
+ ASSERT(Packet != NULL);
+
+ //
+ // Set context in the packet so that NdisReturnPacket can do the right thing
+ //
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount = 0;
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->Miniport = Miniport;
+
+ //
+ // Ensure that we force re-calculation.
+ //
+ Packet->Private.ValidCounts = FALSE;
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ //
+ // Indicate the packet to the binding.
+ //
+ Ref = (*Vc->CoReceivePacketHandler)(Vc->ClientOpen->ProtocolBindingContext,
+ Vc->ClientContext,
+ Packet);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ if (Ref > 0)
+ {
+ ASSERT(NDIS_GET_PACKET_STATUS(Packet) != NDIS_STATUS_RESOURCES);
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount += Ref;
+ if (PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount != 0)
+ {
+ NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_PENDING);
+ }
+ }
+
+ //
+ // If there are promiscuous opens on this miniport, indicate it to them as well.
+ // The client context will identify the VC.
+ //
+ if (Miniport->PmodeOpens > 0)
+ {
+ PNDIS_M_OPEN_BLOCK pPmodeOpen;
+
+ NumPmodeOpens = Miniport->PmodeOpens;
+ for (pPmodeOpen = Miniport->OpenQueue;
+ (NumPmodeOpens > 0);
+ pPmodeOpen = pPmodeOpen->MiniportNextOpen)
+ {
+ if (pPmodeOpen->Flags & fMINIPORT_OPEN_PMODE)
+ {
+ pPmodeOpen->ReceivedAPacket = TRUE;
+ SavedStatus = NDIS_GET_PACKET_STATUS(Packet);
+ NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_RESOURCES);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ //
+ // For Pmode opens, we pass the VcId to the indication routine
+ // since the protocol does not really own the VC.
+ //
+ Ref = (*pPmodeOpen->ProtocolHandle->ProtocolCharacteristics.CoReceivePacketHandler)(
+ pPmodeOpen->ProtocolBindingContext,
+ Vc->pVcId,
+ Packet);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ ASSERT(Ref == 0);
+ NDIS_SET_PACKET_STATUS(Packet, SavedStatus);
+
+ NumPmodeOpens --;
+ }
+ }
+ }
+ }
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ //
+ // It should be impossible to assert here
+ // since the pVc will not lose all of its reference counts
+ // until the Miniport completes the RELEASE_VC which is should not
+ // do UNTIL there are no outstanding indications.
+ //
+ ASSERT(Vc->References);
+
+}
+
+
+VOID
+NdisMCoReceiveComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by the Miniport to indicate that the receive
+ process is complete to all bindings. Only those bindings which
+ have received packets will be notified. The Miniport lock is held
+ when this is called.
+
+Arguments:
+
+ MiniportAdapterHandle - The handle supplied by Ndis at initialization
+ time through miniport initialize.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ //
+ // check all of the bindings on this adapter
+ //
+ for (Open = Miniport->OpenQueue;
+ Open != NULL;
+ NOTHING)
+ {
+ if (((Open->Flags & fMINIPORT_OPEN_CLOSING) == 0) &&
+ Open->ReceivedAPacket)
+ {
+ //
+ // Indicate the binding.
+ //
+
+ Open->ReceivedAPacket = FALSE;
+
+ Open->References++;
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (*Open->ReceiveCompleteHandler)(Open->ProtocolBindingContext);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ //
+ // possibly the client closed the adapter in the time interval where
+ // the spin lock is released.
+ //
+ if ((--Open->References) == 0)
+ {
+ //
+ // This binding is shutting down. We have to kill it.
+ //
+ ndisMFinishClose(Miniport, Open);
+
+ //
+ // we have to start over in the loop through all of the
+ // Opens since the finishClose could have remove one or more
+ // opens from the list
+ //
+ Open = Miniport->OpenQueue;
+ }
+ else if (Open->Flags & fMINIPORT_OPEN_CLOSING)
+ {
+ //
+ // This Open has been dequeued from the miniport so start over
+ // at the beginning of the list
+ //
+ Open = Miniport->OpenQueue;
+ }
+ }
+ else
+ {
+ Open = Open->MiniportNextOpen;
+ }
+ }
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+}
+
+
+VOID
+NdisCoSendPackets(
+ IN NDIS_HANDLE NdisVcHandle,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PNDIS_PACKET Packet;
+ ULONG PacketCount;
+ NDIS_STATUS s;
+ ULONG NumPmodeOpens;
+
+ //
+ // If there are promiscuous opens on this miniport, this must be indicated to them.
+ // Do this before it is send down to the miniport to preserve packet ordering.
+ //
+ Miniport = Vc->Miniport;
+ if (Miniport->PmodeOpens > 0)
+ {
+ PNDIS_M_OPEN_BLOCK pPmodeOpen;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ NumPmodeOpens = Miniport->PmodeOpens;
+ for (pPmodeOpen = Miniport->OpenQueue;
+ (NumPmodeOpens > 0);
+ pPmodeOpen = pPmodeOpen->MiniportNextOpen)
+ {
+ if (pPmodeOpen->Flags & fMINIPORT_OPEN_PMODE)
+ {
+ ULONG Ref;
+
+ pPmodeOpen->ReceivedAPacket = TRUE;
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ PacketCount = NumberOfPackets;
+ Packet = *PacketArray;
+ while (PacketCount--)
+ {
+ //
+ // For Pmode opens, we pass the VcId to the indication routine
+ // since the protocol does not really own the VC. On lookback
+ // the packet cannot be held.
+ //
+ s = NDIS_GET_PACKET_STATUS(Packet);
+ NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_RESOURCES);
+ Ref = (*pPmodeOpen->ProtocolHandle->ProtocolCharacteristics.CoReceivePacketHandler)(
+ pPmodeOpen->ProtocolBindingContext,
+ Vc->pVcId,
+ Packet);
+
+ ASSERT (Ref == 0);
+ NDIS_SET_PACKET_STATUS(Packet, s);
+
+ Packet++;
+ }
+ NumPmodeOpens--;
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+ }
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+ }
+
+ //
+ // Simply call down to the miniport. The miniport must complete the sends for
+ // all cases. The send either succeeds/pends or fails. The miniport cannot
+ // ask the wrapper to queue it.
+ //
+ (*Vc->WCoSendPacketsHandler)(Vc->MiniportContext,
+ PacketArray,
+ NumberOfPackets);
+
+ PacketCount = NumberOfPackets;
+ Packet = *PacketArray;
+ while (PacketCount--)
+ {
+ NDIS_STATUS s;
+ s = NDIS_GET_PACKET_STATUS(Packet);
+ if (s != NDIS_STATUS_PENDING)
+ {
+ (Vc->CoSendCompleteHandler)(s,
+ Vc->ClientContext,
+ Packet);
+ }
+ }
+}
+
+
+VOID
+NdisMCoSendComplete(
+ IN NDIS_STATUS Status,
+ IN NDIS_HANDLE NdisVcHandle,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+ This function is called by the miniport when a send has completed. This
+ routine simply calls the protocol to pass along the indication.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+ NdisVcHandle - the handle supplied to the adapter on the OID_RESERVE_VC
+ PacketArray - a ptr to an array of NDIS_PACKETS
+ NumberOfPackets - the number of packets in PacketArray
+ Status - the send status that applies to all packets in the array
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PNDIS_M_OPEN_BLOCK Open;
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+
+ //
+ // There should not be any reason to grab the spin lock and increment the
+ // ref count on Open since the open cannot close until the Vc closes and
+ // the Vc cannot close in the middle of an indication because the miniport
+ // will not complete a RELEASE_VC until is it no longer indicating
+ //
+ //
+ // Indicate to Protocol;
+ //
+
+ Open = Vc->ClientOpen;
+ Miniport = Vc->Miniport;
+
+ (Vc->CoSendCompleteHandler)(Status,
+ Vc->ClientContext,
+ Packet);
+
+ //
+ // Technically this Vc should not close since there is a send outstanding
+ // on it, and the client should not close a Vc with an outstanding send.
+ //
+ ASSERT(Vc->References);
+ ASSERT(Open->References);
+}
+
+
+VOID
+NdisMCoIndicateStatus(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE NdisVcHandle,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN ULONG StatusBufferSize
+ )
+/*++
+
+Routine Description:
+
+ This routine handles passing CoStatus to the protocol. The miniport calls
+ this routine when it has status on a VC or a general status for all Vcs - in
+ this case the NdisVcHandle is null.
+
+Arguments:
+
+ MiniportAdapterHandle - pointer to the mini-port block;
+ NdisVcHandle - a pointer to the Vc block
+ GeneralStatus - the completion status of the request.
+ StatusBuffer - a buffer containing medium and status specific info
+ StatusBufferSize - the size of the buffer.
+
+Return Value:
+
+ none
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+
+ if (Vc != NULL)
+ {
+ Open = Vc->ClientOpen;
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.CoStatusHandler)(
+ Open->ProtocolBindingContext,
+ Vc->ClientContext,
+ GeneralStatus,
+ StatusBuffer,
+ StatusBufferSize);
+ }
+ else
+ {
+ //
+ // this must be a general status for all clients of this miniport
+ // since the Vc handle is null, so indicate this to all protocols.
+ //
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ for (Open = Miniport->OpenQueue;
+ Open != NULL;
+ NOTHING)
+ {
+ if ((Open->Flags & fMINIPORT_OPEN_CLOSING) == 0)
+ {
+ Open->References++;
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.CoStatusHandler)(
+ Open->ProtocolBindingContext,
+ NULL,
+ GeneralStatus,
+ StatusBuffer,
+ StatusBufferSize);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ //
+ // possibly the client closed the adapter in the time interval where
+ // the spin lock is released.
+ //
+ if ((--Open->References) == 0)
+ {
+ //
+ // This binding is shutting down. We have to kill it.
+ //
+ ndisMFinishClose(Miniport, Open);
+
+ //
+ // we have to start over in the loop through all of the
+ // Opens since the finishClose could have remove one or more
+ // opens from the list - this may result in status being indicated
+ // twice to a particular protocol....
+ //
+ Open = Miniport->OpenQueue;
+ continue;
+
+ }
+ else if (Open->Flags & fMINIPORT_OPEN_CLOSING)
+ {
+ //
+ // This Open has been dequeued from the miniport so start over
+ // at the beginning of the list
+ //
+ Open = Miniport->OpenQueue;
+ continue;
+ }
+ }
+ Open = Open->MiniportNextOpen;
+ }
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+ }
+}
+
+
+NDIS_STATUS
+ndisMRejectSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+ This routine handles any error cases where a protocol binds to an Atm
+ miniport and tries to use the normal NdisSend() call.
+
+Arguments:
+
+ NdisBindingHandle - Handle returned by NdisOpenAdapter.
+
+ Packet - the Ndis packet to send
+
+
+Return Value:
+
+ NDIS_STATUS - always fails
+
+--*/
+{
+ return(NDIS_STATUS_NOT_SUPPORTED);
+}
+
+
+VOID
+ndisMRejectSendPackets(
+ IN PNDIS_OPEN_BLOCK OpenBlock,
+ IN PPNDIS_PACKET Packet,
+ IN UINT NumberOfPackets
+ )
+/*++
+
+Routine Description:
+
+ This routine handles any error cases where a protocol binds to an Atm
+ miniport and tries to use the normal NdisSend() call.
+
+Arguments:
+
+ OpenBlock - Pointer to the NdisOpenBlock
+
+ Packet - Pointer to the array of packets to send
+
+ NumberOfPackets - self-explanatory
+
+
+Return Value:
+
+ None - SendCompleteHandler is called for the protocol calling this.
+
+--*/
+{
+ PNDIS_M_OPEN_BLOCK MiniportOpen = (PNDIS_M_OPEN_BLOCK)(OpenBlock->MacBindingHandle);
+ UINT i;
+
+ for (i = 0; i < NumberOfPackets; i++)
+ {
+ (*MiniportOpen->SendCompleteHandler)(MiniportOpen->ProtocolBindingContext,
+ Packet[i],
+ NDIS_STATUS_NOT_SUPPORTED);
+ }
+}
+
+
+NDIS_STATUS
+ndisMWrappedRequest(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+/*++
+
+Routine Description:
+
+ This routine handles wrapping an NdisRequest to NdisCoRequest since a NDIS 4.1
+ miniport does not support QueryInformation and SetInformation handlers.
+
+Arguments:
+
+ NdisBindingHandle - Points to the NDIS_OPEN_BLOCK
+
+ NdisRequest - The request
+
+
+Return Value:
+
+ NDIS_STATUS_PENDING If the request pends or an appropriate code if it succeeds/fails
+
+--*/
+{
+ PNDIS_M_OPEN_BLOCK Open;
+ KIRQL OldIrql;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PNDIS_COREQ_RESERVED ReqRsvd;
+ PNDIS_REQUEST NewReq;
+ NDIS_STATUS Status;
+ PULONG Filter;
+
+
+ Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+ Miniport = Open->MiniportHandle;
+
+ //
+ // Start off by allocating a request. We do this since the original request is not
+ // big enough to accomodate the ReqRsvd block
+ //
+ NewReq = ALLOC_FROM_POOL(sizeof(NDIS_REQUEST), NDIS_TAG_CO);
+ if (NewReq == NULL)
+ {
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ //
+ // Copy the original request to the new structure
+ //
+ NewReq->RequestType = NdisRequest->RequestType;
+ NewReq->DATA.SET_INFORMATION.Oid = NdisRequest->DATA.SET_INFORMATION.Oid;
+ NewReq->DATA.SET_INFORMATION.InformationBuffer = NdisRequest->DATA.SET_INFORMATION.InformationBuffer;
+ NewReq->DATA.SET_INFORMATION.InformationBufferLength = NdisRequest->DATA.SET_INFORMATION.InformationBufferLength;
+
+ ReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(NewReq);
+ ReqRsvd->RealRequest = NdisRequest;
+
+ //
+ // Start off by referencing the open.
+ //
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ if (Open->Flags & fMINIPORT_OPEN_CLOSING)
+ {
+ Status = NDIS_STATUS_CLOSING;
+ }
+ else if (Miniport->Flags & (fMINIPORT_RESET_IN_PROGRESS | fMINIPORT_RESET_REQUESTED))
+ {
+ Status = NDIS_STATUS_RESET_IN_PROGRESS;
+ }
+ else
+ {
+ Open->References ++;
+ Status = NDIS_STATUS_SUCCESS;
+
+ Filter = (PULONG)(NdisRequest->DATA.SET_INFORMATION.InformationBuffer);
+
+ //
+ // If this was a request to turn p-mode/l-only on/off then mark things appropriately
+ //
+ if ((NdisRequest->RequestType == NdisRequestSetInformation) &&
+ (NdisRequest->DATA.SET_INFORMATION.Oid == OID_GEN_CURRENT_PACKET_FILTER))
+ {
+ if (*Filter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL))
+ {
+ if ((Open->Flags & fMINIPORT_OPEN_PMODE) == 0)
+ {
+ Open->Flags |= fMINIPORT_OPEN_PMODE;
+ Miniport->PmodeOpens ++;
+ }
+ *Filter &= ~(NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL);
+ }
+ else
+ {
+ if (Open->Flags & fMINIPORT_OPEN_PMODE)
+ {
+ Open->Flags &= ~fMINIPORT_OPEN_PMODE;
+ Miniport->PmodeOpens --;
+ }
+ }
+ }
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ ReqRsvd->Open = Open;
+ ReqRsvd->RequestCompleteHandler = Open->ProtocolHandle->ProtocolCharacteristics.RequestCompleteHandler;
+ ReqRsvd->VcContext = NULL;
+ ReqRsvd->Flags = COREQ_DOWNLEVEL;
+
+ if ((NdisRequest->RequestType == NdisRequestSetInformation) &&
+ (NdisRequest->DATA.SET_INFORMATION.Oid == OID_GEN_CURRENT_PACKET_FILTER) &&
+ (*Filter == 0))
+ {
+ NewReq->DATA.SET_INFORMATION.BytesRead = 4;
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ else
+ {
+ //
+ // Call the miniport's CoRequest Handler
+ //
+ Status = (*Open->MiniportCoRequestHandler)(Open->MiniportAdapterContext,
+ NULL,
+ NewReq);
+ }
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisMCoRequestComplete(Status,
+ Open->MiniportHandle,
+ NewReq);
+ Status = NDIS_STATUS_PENDING;
+ }
+ }
+
+ return Status;
+}
+
+
diff --git a/private/ntos/ndis/ndis40/ndisdbg.h b/private/ntos/ndis/ndis40/ndisdbg.h
new file mode 100644
index 000000000..eadfefcc3
--- /dev/null
+++ b/private/ntos/ndis/ndis40/ndisdbg.h
@@ -0,0 +1,270 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ ndisdbg.h
+
+Abstract:
+
+ NDIS wrapper definitions
+
+Author:
+
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ Jul-14 Kyle Brandon Added debug supported for conditional breaks.
+--*/
+#ifndef __DEBUG_H
+#define __DEBUG_H
+
+//
+// Define module numbers.
+//
+#define MODULE_NDIS 0x00010000
+#define MODULE_DATA 0x00020000
+#define MODULE_INIT 0x00030000
+#define MODULE_INITPNP 0x00040000
+#define MODULE_COMMON 0x00050000
+#define MODULE_CONFIG 0x00060000
+#define MODULE_CONFIGM 0x00070000
+#define MODULE_BUS 0x00080000
+#define MODULE_TIMER 0x00090000
+#define MODULE_TIMERM 0x000A0000
+#define MODULE_MINIPORT 0x000B0000
+#define MODULE_REQUESTM 0x000C0000
+#define MODULE_MINISUB 0x000D0000
+#define MODULE_MAC 0x000E0000
+#define MODULE_PROTOCOL 0x000F0000
+#define MODULE_EFILTER 0x00100000
+#define MODULE_TFILTER 0x00110000
+#define MODULE_FFILTER 0x00120000
+#define MODULE_AFILTER 0x00130000
+#define MODULE_DEBUG 0x00140000
+#define MODULE_MININT 0x00150000
+#define MODULE_SENDM 0x00160000
+#define MODULE_NDIS_CO 0x00170000
+
+
+#define DBG_LEVEL_INFO 0x00000000
+#define DBG_LEVEL_LOG 0x00000800
+#define DBG_LEVEL_WARN 0x00001000
+#define DBG_LEVEL_ERR 0x00002000
+#define DBG_LEVEL_FATAL 0x00003000
+
+#define DBG_COMP_INIT 0x00000001
+#define DBG_COMP_CONFIG 0x00000002
+#define DBG_COMP_SEND 0x00000004
+#define DBG_COMP_RECV 0x00000008
+#define DBG_COMP_MEMORY 0x00000010
+#define DBG_COMP_FILTER 0x00000020
+#define DBG_COMP_PROTOCOL 0x00000040
+#define DBG_COMP_REQUEST 0x00000080
+#define DBG_COMP_UNLOAD 0x00000100
+#define DBG_COMP_WORK_ITEM 0x00000200
+#define DBG_COMP_OPEN 0x00000400
+#define DBG_COMP_LOCKS 0x00000800
+#define DBG_COMP_ALL 0xFFFFFFFF
+
+#if DBG
+
+#if defined(MEMPRINT)
+#include "memprint.h" // DavidTr's memprint program at ntos\srv
+#endif // MEMPRINT
+
+extern ULONG ndisDebugSystems;
+extern LONG ndisDebugLevel;
+extern ULONG ndisDebugInformationOffset;
+
+#ifdef NDIS_NT
+#define MINIPORT_AT_DPC_LEVEL (CURRENT_IRQL == DISPATCH_LEVEL)
+#else
+#define MINIPORT_AT_DPC_LEVEL 1
+#endif
+
+#define DBGPRINT(Component, Level, Fmt) \
+ { \
+ if ((Level >= ndisDebugLevel) && \
+ ((ndisDebugSystems & Component) == Component)) \
+ { \
+ DbgPrint("***NDIS*** (%x, %d) ", \
+ MODULE_NUMBER >> 16, __LINE__); \
+ DbgPrint Fmt; \
+ } \
+ }
+
+#define DBGBREAK(Component, Level) \
+{ \
+ if ((Level >= ndisDebugLevel) && (ndisDebugSystems & Component)) \
+ { \
+ DbgPrint("***NDIS*** DbgBreak @ %x, %d\n", MODULE_NUMBER, __LINE__); \
+ DbgBreakPoint(); \
+ } \
+}
+
+#define IF_DBG(Component, Level) if ((Level >= ndisDebugLevel) && (ndisDebugSystems & Component))
+
+extern UINT AfilterDebugFlag;
+
+#ifdef NDIS_NT
+#define DbgIsNonPaged(_Address) (MmIsNonPagedSystemAddressValid((PVOID)(_Address)))
+#else
+#define DbgIsNonPaged(_Address) TRUE
+#endif
+
+#define DbgIsPacket(_Packet) \
+ ( ((_Packet)->Private.Pool->PacketLength) > sizeof(_Packet) )
+
+#define DbgIsNull(_Ptr) ( ((PVOID)(_Ptr)) == NULL )
+
+//
+// The following structures are used to hold debugging information
+//
+//
+#if _DBG
+VOID
+ndisMInitializeDebugInformation(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+VOID
+NDISM_LOG_RECV_PACKET(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PVOID Context1,
+ IN PVOID Context2,
+ IN ULONG Ident
+ );
+
+VOID
+NDISM_LOG_PACKET(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PVOID Context1,
+ IN PVOID Context2,
+ IN ULONG Ident
+ );
+
+typedef struct _PACKET_LOG_ENTRY
+{
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PVOID Context1;
+ PVOID Context2;
+ ULONG Ident;
+} PACKET_LOG_ENTRY, *PPACKET_LOG_ENTRY;
+
+typedef struct _SPIN_LOCK_LOG_ENTRY
+{
+ ULONG Ident; // Module & line number.
+ ULONG Function; // Acquire or release.
+ ULONG SpinLock; // Pointer to the spinlock.
+ ULONG filler2;
+} SPIN_LOCK_LOG_ENTRY, *PSPIN_LOCK_LOG_ENTRY;
+
+typedef struct _LOCAL_LOCK_LOG_ENTRY
+{
+ ULONG Ident;
+ ULONG Function;
+ ULONG Status;
+ ULONG filler1;
+} LOCAL_LOCK_LOG_ENTRY, *PLOCAL_LOCK_LOG_ENTRY;
+
+#define LOG_SIZE 1024
+
+typedef struct _PACKET_LOG
+{
+ UINT CurrentEntry;
+ PPACKET_LOG_ENTRY Head;
+ KSPIN_LOCK Lock;
+ PPACKET_LOG_ENTRY Buffer;
+} PACKET_LOG, *PPACKET_LOG;
+
+typedef struct _SPIN_LOCK_LOG
+{
+ UINT CurrentEntry;
+ PSPIN_LOCK_LOG_ENTRY Head;
+ KSPIN_LOCK Lock;
+ PSPIN_LOCK_LOG_ENTRY Buffer;
+} SPIN_LOCK_LOG, *PSPIN_LOCK_LOG;
+
+typedef struct _LOCAL_LOCK_LOG
+{
+ UINT CurrentEntry;
+ PLOCAL_LOCK_LOG_ENTRY Head;
+ KSPIN_LOCK Lock;
+ PLOCAL_LOCK_LOG_ENTRY Buffer;
+} LOCAL_LOCK_LOG, *PLOCAL_LOCK_LOG;
+
+
+typedef struct _NDIS_MOJO
+{
+ PSPIN_LOCK_LOG SpinLockLog;
+ PLOCAL_LOCK_LOG LocalLockLog;
+ PPACKET_LOG SendPacketLog;
+ PPACKET_LOG RecvPacketLog;
+} NDIS_MOJO, *PNDIS_MOJO;
+
+#define NUMBER_OF_LOGS 4
+
+//
+// Macros for referencing the logs.
+//
+#define SPIN_LOCK_LOG(_M) ((PNDIS_MOJO)(_M)->Reserved)->SpinLockLog
+
+#define SL_CURRENT_ENTRY(_M) SPIN_LOCK_LOG((_M))->CurrentEntry
+#define SL_HEAD(_M) SPIN_LOCK_LOG((_M))->Head
+#define SL_LOCK(_M) SPIN_LOCK_LOG((_M))->Lock
+#define SL_LOG(_M) SPIN_LOCK_LOG((_M))->Buffer
+
+#define LOCAL_LOCK_LOG(_M) ((PNDIS_MOJO)(_M)->Reserved)->LocalLockLog
+
+#define LL_CURRENT_ENTRY(_M) LOCAL_LOCK_LOG((_M))->CurrentEntry
+#define LL_HEAD(_M) LOCAL_LOCK_LOG((_M))->Head
+#define LL_LOCK(_M) LOCAL_LOCK_LOG((_M))->Lock
+#define LL_LOG(_M) LOCAL_LOCK_LOG((_M))->Buffer
+
+#define SEND_PACKET_LOG(_M) ((PNDIS_MOJO)(_M)->Reserved)->SendPacketLog
+
+#define SPL_CURRENT_ENTRY(_M) SEND_PACKET_LOG((_M))->CurrentEntry
+#define SPL_HEAD(_M) SEND_PACKET_LOG((_M))->Head
+#define SPL_LOCK(_M) SEND_PACKET_LOG((_M))->Lock
+#define SPL_LOG(_M) SEND_PACKET_LOG((_M))->Buffer
+
+#define RECV_PACKET_LOG(_M) ((PNDIS_MOJO)(_M)->Reserved)->RecvPacketLog
+
+#define RPL_CURRENT_ENTRY(_M) RECV_PACKET_LOG((_M))->CurrentEntry
+#define RPL_HEAD(_M) RECV_PACKET_LOG((_M))->Head
+#define RPL_LOCK(_M) RECV_PACKET_LOG((_M))->Lock
+#define RPL_LOG(_M) RECV_PACKET_LOG((_M))->Buffer
+
+#else
+
+#define ndisMInitializeDebugInformation(_Miniport)
+#define NDISM_LOG_RECV_PACKET(Miniport, Context1, Context2, Ident)
+#define NDISM_LOG_PACKET(Miniport, Context1, Context2, Ident)
+
+#endif // _DBG
+
+#else
+
+#define ndisMInitializeDebugInformation(_Miniport)
+#define NDISM_LOG_RECV_PACKET(Miniport, Context1, Context2, Ident)
+#define NDISM_LOG_PACKET(Miniport, Context1, Context2, Ident)
+
+#define MINIPORT_AT_DPC_LEVEL 1
+#define DBGPRINT(Component, Level, Fmt)
+#define DBGBREAK(Component, Level)
+
+#define DbgIsNonPaged(_Address) TRUE
+#define DbgIsPacket(_Packet) TRUE
+#define DbgIsNull(_Ptr) FALSE
+
+#define IF_DBG(Component, Level) if (FALSE)
+
+#endif
+
+#endif // __DEBUG_H
diff --git a/private/ntos/ndis/ndis40/ndisnt.h b/private/ntos/ndis/ndis40/ndisnt.h
new file mode 100644
index 000000000..978aa33e9
--- /dev/null
+++ b/private/ntos/ndis/ndis40/ndisnt.h
@@ -0,0 +1,325 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ ndisnt.h
+
+Abstract:
+
+ Windows NT Specific macros
+
+Author:
+
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ Nov-95 Jameel Hyder Split up from a monolithic file
+--*/
+
+#define Increment(a,b) InterlockedIncrement(a)
+#define Decrement(a,b) InterlockedDecrement(a)
+
+#define CURRENT_THREAD ((LONG)PsGetCurrentThread())
+
+#define CopyMemory(Destination,Source,Length) RtlCopyMemory(Destination,Source,Length)
+#define MoveMemory(Destination,Source,Length) RtlMoveMemory(Destination,Source,Length)
+#define ZeroMemory(Destination,Length) RtlZeroMemory(Destination,Length)
+
+#define INITIALIZE_SPIN_LOCK(_L_) KeInitializeSpinLock(_L_)
+#define ACQUIRE_SPIN_LOCK(_SpinLock, _pOldIrql) ExAcquireSpinLock(_SpinLock, _pOldIrql)
+#define RELEASE_SPIN_LOCK(_SpinLock, _OldIrql) ExReleaseSpinLock(_SpinLock, _OldIrql)
+
+#define ACQUIRE_SPIN_LOCK_DPC(_SpinLock) \
+ { \
+ ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); \
+ ExAcquireSpinLockAtDpcLevel(_SpinLock); \
+ }
+
+#define RELEASE_SPIN_LOCK_DPC(_SpinLock) \
+ { \
+ ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); \
+ ExReleaseSpinLockFromDpcLevel(_SpinLock); \
+ }
+
+
+#define NDIS_ACQUIRE_SPIN_LOCK(_SpinLock, _pOldIrql) ExAcquireSpinLock(&(_SpinLock)->SpinLock, _pOldIrql)
+#define NDIS_RELEASE_SPIN_LOCK(_SpinLock, _OldIrql) ExReleaseSpinLock(&(_SpinLock)->SpinLock, _OldIrql)
+
+
+#define NDIS_ACQUIRE_SPIN_LOCK_DPC(_SpinLock) \
+ { \
+ ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); \
+ ExAcquireSpinLockAtDpcLevel(&(_SpinLock)->SpinLock); \
+ }
+
+#define NDIS_RELEASE_SPIN_LOCK_DPC(_SpinLock) \
+ { \
+ ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); \
+ ExReleaseSpinLockFromDpcLevel(&(_SpinLock)->SpinLock); \
+ }
+
+//
+// Debug versions for the miniport locks.
+//
+#if DBG && _DBG
+
+//
+// LOG macro for use at unknown IRQL.
+//
+#define DBG_LOG_LOCK(_M, _SpinLock, _Ident) \
+{ \
+ KIRQL _OldIrql; \
+ IF_DBG(DBG_COMP_LOCKS, DBG_LEVEL_LOG) \
+ { \
+ ACQUIRE_SPIN_LOCK(&SL_LOCK(_M), &_OldIrql); \
+ SL_HEAD(_M) = &SL_LOG(_M)[SL_CURRENT_ENTRY(_M)]; \
+ SL_HEAD(_M)->Ident = (ULONG)(MODULE_NUMBER | __LINE__); \
+ SL_HEAD(_M)->Function = (ULONG)(_Ident); \
+ SL_HEAD(_M)->SpinLock = (ULONG)_SpinLock; \
+ if (SL_CURRENT_ENTRY(_M)-- == 0) \
+ SL_CURRENT_ENTRY(_M) = (LOG_SIZE - 1); \
+ RELEASE_SPIN_LOCK(&SL_LOCK(_M), _OldIrql); \
+ } \
+}
+
+//
+// LOG macro for use at DPC level.
+//
+#define DBG_LOG_LOCK_DPC(_M, _SpinLock, _Ident) \
+{ \
+ IF_DBG(DBG_COMP_LOCKS, DBG_LEVEL_LOG) \
+ { \
+ ACQUIRE_SPIN_LOCK_DPC(&SL_LOCK(_M)); \
+ SL_HEAD(_M) = &SL_LOG(_M)[SL_CURRENT_ENTRY(_M)]; \
+ SL_HEAD(_M)->Ident = (ULONG)(MODULE_NUMBER | __LINE__); \
+ SL_HEAD(_M)->Function = (ULONG)(_Ident); \
+ SL_HEAD(_M)->SpinLock = (ULONG)_SpinLock; \
+ if (SL_CURRENT_ENTRY(_M)-- == 0) \
+ SL_CURRENT_ENTRY(_M) = (LOG_SIZE - 1); \
+ RELEASE_SPIN_LOCK_DPC(&SL_LOCK(_M)); \
+ } \
+}
+
+
+
+// Miniport Lock macros
+//
+// Debug versions of these macros will log where
+// and by whom they were called.
+//
+#define DBG_LOG_LOCAL_LOCK(_M, _L, _Ident) \
+{ \
+ IF_DBG(DBG_COMP_LOCKS, DBG_LEVEL_LOG) \
+ { \
+ KIRQL lockOldIrql; \
+ ACQUIRE_SPIN_LOCK(&LL_LOCK(_M), &lockOldIrql); \
+ LL_HEAD(_M) = &LL_LOG(_M)[LL_CURRENT_ENTRY(_M)]; \
+ LL_HEAD(_M)->Ident = (ULONG)(MODULE_NUMBER | __LINE__); \
+ LL_HEAD(_M)->Function = (ULONG)(_Ident); \
+ LL_HEAD(_M)->Status = (_L) ? 's' : 'f'; \
+ if (LL_CURRENT_ENTRY(_M)-- == 0) \
+ LL_CURRENT_ENTRY(_M) = (LOG_SIZE - 1); \
+ RELEASE_SPIN_LOCK(&LL_LOCK(_M), lockOldIrql); \
+ } \
+}
+
+#else
+
+#define DBG_LOG_LOCK(_M, _SpinLock, _Ident)
+#define DBG_LOG_LOCK_DPC(_M, _SpinLock, _Ident)
+#define DBG_LOG_LOCAL_LOCK(_M, _L, _Ident)
+
+#endif
+
+#define NDIS_ACQUIRE_COMMON_SPIN_LOCK(_M, _pS, _pIrql, _pT) \
+{ \
+ LONG _original; \
+ \
+ DBG_LOG_LOCK((_M), (_pS), 'a'); \
+ \
+ ExAcquireSpinLock(&(_pS)->SpinLock, _pIrql); \
+ _original = InterlockedExchange((_pT), CURRENT_THREAD); \
+ ASSERT(0 == _original); \
+}
+
+#define NDIS_RELEASE_COMMON_SPIN_LOCK(_M, _pS, _Irql, _pT) \
+{ \
+ DBG_LOG_LOCK((_M), (_pS), 'r'); \
+ \
+ InterlockedExchange((_pT), 0); \
+ ExReleaseSpinLock(&(_pS)->SpinLock, _Irql); \
+}
+
+#define NDIS_ACQUIRE_COMMON_SPIN_LOCK_DPC(_M, _pS, _pT) \
+{ \
+ LONG _original; \
+ ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); \
+ \
+ DBG_LOG_LOCK_DPC((_M), (_pS), 'a'); \
+ \
+ ExAcquireSpinLockAtDpcLevel(&(_pS)->SpinLock); \
+ _original = InterlockedExchange((_pT), CURRENT_THREAD); \
+ ASSERT(0 == _original); \
+}
+
+#define NDIS_RELEASE_COMMON_SPIN_LOCK_DPC(_M, _pS, _pT) \
+{ \
+ ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); \
+ \
+ DBG_LOG_LOCK_DPC((_M), (_pS), 'r'); \
+ \
+ InterlockedExchange((_pT), 0); \
+ ExReleaseSpinLockFromDpcLevel(&(_pS)->SpinLock); \
+}
+
+
+#define NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(_M, _pIrql) \
+ NDIS_ACQUIRE_COMMON_SPIN_LOCK((_M), &(_M)->Lock, (_pIrql), &(_M)->MiniportThread)
+
+#define NDIS_ACQUIRE_SEND_SPIN_LOCK(_M, _pIrql) \
+ NDIS_ACQUIRE_COMMON_SPIN_LOCK((_M), &(_M)->SendLock, (_pIrql), &(_M)->SendThread)
+
+#define NDIS_RELEASE_MINIPORT_SPIN_LOCK(_M, _Irql) \
+ NDIS_RELEASE_COMMON_SPIN_LOCK((_M), &(_M)->Lock, (_Irql), &(_M)->MiniportThread)
+
+#define NDIS_RELEASE_SEND_SPIN_LOCK(_M, _Irql) \
+ NDIS_RELEASE_COMMON_SPIN_LOCK((_M), &(_M)->SendLock, (_Irql), &(_M)->SendThread)
+
+#define NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(_M) \
+ NDIS_ACQUIRE_COMMON_SPIN_LOCK_DPC((_M), &(_M)->Lock, &(_M)->MiniportThread)
+
+#define NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(_M) \
+ NDIS_ACQUIRE_COMMON_SPIN_LOCK_DPC((_M), &(_M)->SendLock, &(_M)->SendThread)
+
+#define NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(_M) \
+ NDIS_RELEASE_COMMON_SPIN_LOCK_DPC(_M, &(_M)->Lock, &(_M)->MiniportThread)
+
+#define NDIS_RELEASE_SEND_SPIN_LOCK_DPC(_M) \
+ NDIS_RELEASE_COMMON_SPIN_LOCK_DPC(_M, &(_M)->SendLock, &(_M)->SendThread)
+
+#define LOCK_MINIPORT(_M, _L) \
+{ \
+ if ((_M)->LockAcquired) \
+ { \
+ (_L) = FALSE; \
+ } \
+ else \
+ { \
+ (_M)->LockAcquired = TRUE; \
+ (_L) = TRUE; \
+ } \
+ \
+ DBG_LOG_LOCAL_LOCK((_M), (_L), 'l'); \
+}
+
+
+#define UNLOCK_MINIPORT(_M, _L) \
+{ \
+ if (_L) \
+ { \
+ (_M)->LockAcquired = FALSE; \
+ } \
+ \
+ DBG_LOG_LOCAL_LOCK((_M), (_L), 'u'); \
+}
+
+
+#define BLOCK_LOCK_MINIPORT(_M, _L) \
+ { \
+ KIRQL OldIrql; \
+ \
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(_M, &OldIrql); \
+ LOCK_MINIPORT(_M, _L); \
+ while (!_L) { \
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(_M, OldIrql); \
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(_M, &OldIrql); \
+ LOCK_MINIPORT(_M, _L); \
+ } \
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(_M, OldIrql); \
+ }
+
+#define BLOCK_LOCK_MINIPORT_DPC(_M, _L) \
+ { \
+ KIRQL OldIrql; \
+ \
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(_M); \
+ LOCK_MINIPORT(_M, _L); \
+ while (!_L) { \
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(_M); \
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(_M); \
+ LOCK_MINIPORT(_M, _L); \
+ } \
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(_M); \
+ }
+
+//
+// Some macros for platform independence
+//
+
+#if TRACK_MEMORY
+
+#define ALLOC_FROM_POOL(_Size_, _Tag_) AllocateM(_Size_, \
+ MODULE_NUMBER | __LINE__, \
+ _Tag_)
+#define FREE_POOL(_P_) FreeM(_P_)
+
+#else
+
+#define ALLOC_FROM_POOL(_Size_, _Tag_) ExAllocatePoolWithTag(NonPagedPool, \
+ _Size_, \
+ _Tag_)
+#define FREE_POOL(_P_) ExFreePool(_P_)
+
+#endif
+
+#define INITIALIZE_WORK_ITEM(_W, _R, _C) ExInitializeWorkItem(_W, _R, _C)
+#define QUEUE_WORK_ITEM(_W, _Q) ExQueueWorkItem(_W, _Q)
+
+#define CURRENT_IRQL KeGetCurrentIrql()
+#define RAISE_IRQL_TO_DISPATCH(_pIrql_) KeRaiseIrql(DISPATCH_LEVEL, _pIrql_)
+#define LOWER_IRQL(_Irql_) KeLowerIrql(_Irql_)
+
+#define INITIALIZE_TIMER(_Timer_) KeInitializeTimer(_Timer_)
+#define INITIALIZE_TIMER_EX(_Timer_,_Type_) KeInitializeTimerEx(_Timer_, _Type_)
+#define CANCEL_TIMER(_Timer_) KeCancelTimer(_Timer_)
+#define SET_TIMER(_Timer_, _Time_, _Dpc_) KeSetTimer(_Timer_, _Time_, _Dpc_)
+#define SET_PERIODIC_TIMER(_Timer_, _DueTime_, _PeriodicTime_, _Dpc_) \
+ KeSetTimerEx(_Timer_, _DueTime_, _PeriodicTime_, _Dpc_)
+
+#define INITIALIZE_EVENT(_pEvent_) KeInitializeEvent(_pEvent_, NotificationEvent, FALSE)
+#define SET_EVENT(_pEvent_) KeSetEvent(_pEvent_, 0, FALSE)
+#define RESET_EVENT(_pEvent_) KeResetEvent(_pEvent_)
+
+#define INITIALIZE_MUTEX(_M_) KeInitializeMutex(_M_, 0xFFFF)
+#define RELEASE_MUTEX(_M_) KeReleaseMutex(_M_, FALSE)
+
+#define WAIT_FOR_OBJECT(_O_, _TO_) KeWaitForSingleObject(_O_, \
+ Executive, \
+ KernelMode, \
+ TRUE, \
+ _TO_) \
+
+#define QUEUE_DPC(_pDpc_) KeInsertQueueDpc(_pDpc_, NULL, NULL)
+#define INITIALIZE_DPC(_pDpc_, _R_, _C_) KeInitializeDpc(_pDpc_, _R_, _C_)
+#define SET_DPC_IMPORTANCE(_pDpc_) KeSetImportanceDpc(_pDpc_, LowImportance)
+#define SET_PROCESSOR_DPC(_pDpc_, _R_) if (!ndisSkipProcessorAffinity) \
+ KeSetTargetProcessorDpc(_pDpc_, _R_)
+#define SYNC_WITH_ISR(_O_, _F_, _C_) KeSynchronizeExecution(_O_, \
+ (PKSYNCHRONIZE_ROUTINE)(_F_), \
+ _C_)
+
+#define MDL_ADDRESS(_MDL_) MmGetSystemAddressForMdl(_MDL_)
+#define MDL_SIZE(_MDL_) MmGetMdlByteCount(_MDL_)
+#define MDL_OFFSET(_MDL_) MmGetMdlByteOffset(_MDL_)
+#define MDL_VA(_MDL_) MmGetMdlVirtualAddress(_MDL_)
+
+#define NDIS_EQUAL_UNICODE_STRING(s1, s2) (((s1)->Length == (s2)->Length) && \
+ RtlEqualMemory((s1)->Buffer, (s2)->Buffer, (s1)->Length))
+#define CHAR_TO_INT(_s, _b, _p) RtlCharToInteger(_s, _b, _p)
+
diff --git a/private/ntos/ndis/ndis40/ndistags.h b/private/ntos/ndis/ndis40/ndistags.h
new file mode 100644
index 000000000..55b1a8cec
--- /dev/null
+++ b/private/ntos/ndis/ndis40/ndistags.h
@@ -0,0 +1,53 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ ndistags.h
+
+Abstract:
+
+ List of pool tags used by the NDIS Wraper.
+
+Author:
+
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ Mar-96 Jameel Hyder Initial version
+--*/
+
+#ifndef _NDISTAGS_
+#define _NDISTAGS_
+
+#define NDIS_TAG_DEFAULT ' DN'
+#define NDIS_TAG_WORK_ITEM 'iwDN'
+#define NDIS_TAG_NAME_BUF 'naDN'
+#define NDIS_TAG_CO 'ocDN'
+#define NDIS_TAG_DMA 'bdDN'
+#define NDIS_TAG_ALLOC_MEM 'maDN'
+#define NDIS_TAG_SLOT_INFO 'isDN'
+#define NDIS_TAG_PKT_POOL 'ppDN'
+#define NDIS_TAG_RSRC_LIST 'lrDN'
+#define NDIS_TAG_LOOP_PKT 'plDN'
+#define NDIS_TAG_Q_REQ 'qrDN'
+#define NDIS_TAG_PROT_BLK 'bpDN'
+#define NDIS_TAG_OPEN_BLK 'boDN'
+#define NDIS_TAG_DFRD_TMR 'tdDN'
+#define NDIS_TAG_LA_BUF 'blDN'
+#define NDIS_TAG_MAC_BLOCK 'bMDN'
+#define NDIS_TAG_MAP_REG 'rmDN'
+#define NDIS_TAG_MINI_BLOCK 'bmDN'
+#define NDIS_TAG_DBG ' dDN'
+#define NDIS_TAG_DBG_S 'sdDN'
+#define NDIS_TAG_DBG_L 'ldDN'
+#define NDIS_TAG_DBG_P 'pdDN'
+#define NDIS_TAG_DBG_LOG 'lDDN'
+#define NDIS_TAG_FILTER 'fpDN'
+#define NDIS_TAG_STRING 'tsDN'
+#endif // _NDISTAGS_
diff --git a/private/ntos/ndis/ndis40/pragma.h b/private/ntos/ndis/ndis40/pragma.h
new file mode 100644
index 000000000..ec73aeebb
--- /dev/null
+++ b/private/ntos/ndis/ndis40/pragma.h
@@ -0,0 +1,733 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ pragma.h
+
+Abstract:
+
+ Pragma definitions for pageable/init/section-pageable NDIS Wrapper routines.
+
+Author:
+
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ Feb-96 Jameel Hyder Moved from individual source files
+--*/
+
+#ifndef _PRAGMA_
+#define _PRAGMA_
+
+#ifdef ALLOC_PRAGMA
+#ifdef NDIS_NT
+
+#pragma alloc_text(INIT, DriverEntry)
+#pragma alloc_text(INIT, ndisReadRegistry)
+#pragma alloc_text(INIT, ndisAddMediaTypeToArray)
+#pragma alloc_text(INIT, ndisReadParameters)
+
+#pragma alloc_text(PAGENPNP, ndisDispatchRequest)
+#pragma alloc_text(PAGENPNP, ndisHandlePnPRequest)
+#pragma alloc_text(PAGENPNP, ndisHandleLoadDriver)
+#pragma alloc_text(PAGENPNP, ndisHandleUnloadDriver)
+#pragma alloc_text(PAGENPNP, ndisHandleTranslateName)
+#pragma alloc_text(PAGENPNP, ndisHandleProtocolNotification)
+#pragma alloc_text(PAGENPNP, ndisReferenceAdapterOrMiniportByName)
+#pragma alloc_text(PAGENPNP, ndisHandleLegacyTransport)
+#pragma alloc_text(PAGENPNP, ndisInitializeBindings)
+#pragma alloc_text(PAGENPNP, NdisCompleteBindAdapter)
+#pragma alloc_text(PAGENPNP, ndisQueuedProtocolNotification)
+#pragma alloc_text(PAGENPNP, NdisCompleteUnbindAdapter)
+#pragma alloc_text(PAGENPNP, NdisRegisterTdiCallBack)
+#pragma alloc_text(PAGENPNP, ndisInitializePackage)
+#pragma alloc_text(PAGENPNP, NdisOpenFile)
+#pragma alloc_text(PAGENPNP, NdisCloseFile)
+#pragma alloc_text(PAGENPNP, NdisQueryMapRegisterCount)
+#pragma alloc_text(PAGENPNP, ndisUnloadMiniport)
+#pragma alloc_text(PAGENPNP, ndisTranslateMiniportName)
+#pragma alloc_text(PAGENPNP, ndisUnloadMac)
+#pragma alloc_text(PAGENPNP, ndisTranslateMacName)
+#pragma alloc_text(PAGENPNP, ndisCreateIrpHandler)
+#pragma alloc_text(PAGENPNP, ndisDeviceControlIrpHandler)
+#pragma alloc_text(PAGENPNP, ndisSuccessIrpHandler)
+
+#pragma alloc_text(PAGENDSI, ndisInitializeAllAdapterInstances)
+#pragma alloc_text(PAGENDSI, ndisInitializeAdapter)
+#pragma alloc_text(PAGENDSI, ndisMInitializeAdapter)
+#pragma alloc_text(PAGENDSI, ndisQueuedBindNotification)
+#pragma alloc_text(PAGENDSI, NdisIMInitializeDeviceInstance)
+#pragma alloc_text(PAGENDSI, NdisIMDeInitializeDeviceInstance)
+#pragma alloc_text(PAGENDSI, ndisValidatePcmciaDriver)
+#pragma alloc_text(PAGENDSI, ndisCheckIfPcmciaCardPresent)
+#pragma alloc_text(PAGENDSI, ndisFixBusInformation)
+#pragma alloc_text(PAGENDSI, ndisAddBusInformation)
+#pragma alloc_text(PAGENDSI, ndisSearchGlobalDb)
+#pragma alloc_text(PAGENDSI, ndisAddGlobalDb)
+#pragma alloc_text(PAGENDSI, ndisDeleteGlobalDb)
+#pragma alloc_text(PAGENDSI, ndisCheckProtocolBinding)
+#pragma alloc_text(PAGENDSI, ndisProtocolAlreadyBound)
+#pragma alloc_text(PAGENDSI, ndisUpdateDriverInstance)
+#pragma alloc_text(PAGENDSI, NdisOpenConfiguration)
+#pragma alloc_text(PAGENDSI, NdisOpenGlobalConfiguration)
+#pragma alloc_text(PAGENDSI, NdisOpenConfigurationKeyByName)
+#pragma alloc_text(PAGENDSI, NdisOpenConfigurationKeyByIndex)
+#pragma alloc_text(PAGENDSI, NdisReadConfiguration)
+#pragma alloc_text(PAGENDSI, NdisWriteConfiguration)
+#pragma alloc_text(PAGENDSI, NdisCloseConfiguration)
+#pragma alloc_text(PAGENDSI, NdisReadBindingInformation)
+#pragma alloc_text(PAGENDSI, NdisReadNetworkAddress)
+#pragma alloc_text(PAGENDSI, NdisConvertStringToAtmAddress)
+#pragma alloc_text(PAGENDSI, ndisSaveLinkage)
+#pragma alloc_text(PAGENDSI, ndisSaveParameters)
+#pragma alloc_text(PAGENDSI, ndisCheckRoute)
+#pragma alloc_text(PAGENDSI, ndisCheckPortUsage)
+#pragma alloc_text(PAGENDSI, ndisStartMapping)
+#pragma alloc_text(PAGENDSI, ndisEndMapping)
+#pragma alloc_text(PAGENDSI, NdisImmediateReadPortUchar)
+#pragma alloc_text(PAGENDSI, NdisImmediateReadPortUshort)
+#pragma alloc_text(PAGENDSI, NdisImmediateReadPortUlong)
+#pragma alloc_text(PAGENDSI, NdisImmediateWritePortUchar)
+#pragma alloc_text(PAGENDSI, NdisImmediateWritePortUshort)
+#pragma alloc_text(PAGENDSI, NdisImmediateWritePortUlong)
+#pragma alloc_text(PAGENDSI, ndisCheckMemoryUsage)
+#pragma alloc_text(PAGENDSI, NdisImmediateReadSharedMemory)
+#pragma alloc_text(PAGENDSI, NdisImmediateWriteSharedMemory)
+#pragma alloc_text(PAGENDSI, NdisInitializeWrapper)
+#pragma alloc_text(PAGENDSI, NdisRegisterAdapterShutdownHandler)
+#pragma alloc_text(PAGENDSI, NdisRegisterMac)
+#pragma alloc_text(PAGENDSI, NdisRegisterAdapter)
+#pragma alloc_text(PAGENDSI, NdisMapIoSpace)
+#pragma alloc_text(PAGENDSI, NdisPciAssignResources)
+#pragma alloc_text(PAGENDSI, NdisAllocateDmaChannel)
+#pragma alloc_text(PAGENDSI, NdisMAllocateMapRegisters)
+#pragma alloc_text(PAGENDSI, NdisMSetAttributes)
+#pragma alloc_text(PAGENDSI, NdisMSetAttributesEx)
+#pragma alloc_text(PAGENDSI, NdisReadEisaSlotInformationEx)
+#pragma alloc_text(PAGENDSI, NdisReadEisaSlotInformation)
+#pragma alloc_text(PAGENDSI, NdisReadMcaPosInformation)
+#pragma alloc_text(PAGENDSI, NdisImmediateReadPciSlotInformation)
+#pragma alloc_text(PAGENDSI, NdisImmediateWritePciSlotInformation)
+#pragma alloc_text(PAGENDSI, NdisOverrideBusNumber)
+#pragma alloc_text(PAGENDSI, NdisInitializeInterrupt)
+
+#pragma alloc_text(PAGENDSM, NdisMRegisterMiniport)
+#pragma alloc_text(PAGENDSM, NdisIMRegisterLayeredMiniport)
+#pragma alloc_text(PAGENDSM, NdisMDeregisterIoPortRange)
+#pragma alloc_text(PAGENDSM, NdisMRegisterIoPortRange)
+#pragma alloc_text(PAGENDSM, NdisMMapIoSpace)
+#pragma alloc_text(PAGENDSM, NdisMUnmapIoSpace)
+#pragma alloc_text(PAGENDSM, NdisMRegisterDmaChannel)
+#pragma alloc_text(PAGENDSM, NdisMDeregisterDmaChannel)
+#pragma alloc_text(PAGENDSM, NdisMAllocateSharedMemory)
+#pragma alloc_text(PAGENDSM, NdisMFreeSharedMemory)
+#pragma alloc_text(PAGENDSM, NdisMReadDmaCounter)
+#pragma alloc_text(PAGENDSM, NdisMFreeMapRegisters)
+#pragma alloc_text(PAGENDSM, NdisMRegisterAdapterShutdownHandler)
+#pragma alloc_text(PAGENDSM, NdisMDeregisterAdapterShutdownHandler)
+#pragma alloc_text(PAGENDSM, NdisMPciAssignResources)
+#pragma alloc_text(PAGENDSM, NdisMInitializeTimer)
+#pragma alloc_text(PAGENDSM, NdisMCancelTimer)
+#pragma alloc_text(PAGENDSM, NdisMDeregisterInterrupt)
+#pragma alloc_text(PAGENDSM, NdisMRegisterInterrupt)
+#pragma alloc_text(PAGENDSM, NdisMSynchronizeWithInterrupt)
+#pragma alloc_text(PAGENDSM, ndisMIsr)
+#pragma alloc_text(PAGENDSM, ndisMDpc)
+#pragma alloc_text(PAGENDSM, ndisMWakeUpDpc)
+#pragma alloc_text(PAGENDSM, ndisMDpcTimer)
+#pragma alloc_text(PAGENDSM, ndisMTimerDpc)
+#pragma alloc_text(PAGENDSM, ndisMDeferredTimerDpc)
+#pragma alloc_text(PAGENDSM, ndisMDeQueueWorkItem)
+#pragma alloc_text(PAGENDSM, ndisMDeQueueWorkItemFullDuplex)
+#pragma alloc_text(PAGENDSM, ndisMQueueWorkItem)
+#pragma alloc_text(PAGENDSM, ndisMQueueWorkItemFullDuplex)
+#pragma alloc_text(PAGENDSM, ndisMQueueNewWorkItem)
+#pragma alloc_text(PAGENDSM, ndisMQueueNewWorkItemFullDuplex)
+#pragma alloc_text(PAGENDSM, ndisMProcessDeferredFullDuplex)
+#pragma alloc_text(PAGENDSM, ndisMProcessDeferred)
+#if _SEND_PRIORITY
+#pragma alloc_text(PAGENDSM, ndisMProcessDeferredFullDuplexPrioritySends)
+#pragma alloc_text(PAGENDSM, ndisMProcessDeferredPrioritySends)
+#endif
+#pragma alloc_text(PAGENDSM, ndisMProcessResetRequested)
+#pragma alloc_text(PAGENDSM, NdisMIndicateStatus)
+#pragma alloc_text(PAGENDSM, NdisMIndicateStatusComplete)
+#pragma alloc_text(PAGENDSM, NdisMWanIndicateReceive)
+#pragma alloc_text(PAGENDSM, NdisMWanIndicateReceiveComplete)
+#pragma alloc_text(PAGENDSM, NdisQueryReceiveInformation)
+#pragma alloc_text(PAGENDSM, NdisReturnPackets)
+#pragma alloc_text(PAGENDSM, ndisMIndicatePacket)
+#pragma alloc_text(PAGENDSM, ndisMLazyReturnPackets)
+#pragma alloc_text(PAGENDSM, NdisMTransferDataComplete)
+#pragma alloc_text(PAGENDSM, ndisMTransferDataSync)
+#pragma alloc_text(PAGENDSM, ndisMTransferData)
+#pragma alloc_text(PAGENDSM, ndisMDummyTransferData)
+#pragma alloc_text(PAGENDSM, ndisMAbortPacketsAndRequests)
+#pragma alloc_text(PAGENDSM, ndisMResetCompleteCommonStep2)
+#pragma alloc_text(PAGENDSM, ndisMResetCompleteCommonStep1)
+#pragma alloc_text(PAGENDSM, ndisMProcessResetRequested)
+#pragma alloc_text(PAGENDSM, ndisMResetCompleteFullDuplex)
+#pragma alloc_text(PAGENDSM, NdisMResetComplete)
+#pragma alloc_text(PAGENDSM, ndisMResetFullDuplex)
+#pragma alloc_text(PAGENDSM, ndisMReset)
+#pragma alloc_text(PAGENDSM, ndisMResetSend)
+#pragma alloc_text(PAGENDSM, ndisMResetSendPackets)
+#pragma alloc_text(PAGENDSM, ndisMFinishClose)
+#pragma alloc_text(PAGENDSM, ndisMKillOpen)
+#pragma alloc_text(PAGENDSM, ndisDeQueueOpenOnMiniport)
+#pragma alloc_text(PAGENDSM, ndisDequeueMiniportOnDriver)
+#pragma alloc_text(PAGENDSM, ndisQueueMiniportOnDriver)
+#pragma alloc_text(PAGENDSM, ndisDereferenceMiniport)
+#pragma alloc_text(PAGENDSM, ndisDereferenceDriver)
+#pragma alloc_text(PAGENDSM, ndisMHaltMiniport)
+#pragma alloc_text(PAGENDSM, ndisMUnload)
+#pragma alloc_text(PAGENDSM, ndisMShutdown)
+#pragma alloc_text(PAGENDSM, ndisMRequest)
+#pragma alloc_text(PAGENDSI, ndisMUndoBogusFilters)
+#pragma alloc_text(PAGENDSI, ndisMDoMiniportOp)
+#pragma alloc_text(PAGENDSM, ndisMRequestQueryInformationPost)
+#pragma alloc_text(PAGENDSM, ndisMSyncQueryInformationComplete)
+#pragma alloc_text(PAGENDSM, NdisMQueryInformationComplete)
+#pragma alloc_text(PAGENDSM, ndisMRequestSetInformationPost)
+#pragma alloc_text(PAGENDSM, ndisMSyncSetInformationComplete)
+#pragma alloc_text(PAGENDSM, NdisMSetInformationComplete)
+#pragma alloc_text(PAGENDSM, ndisMAbortQueryStatisticsRequest)
+#pragma alloc_text(PAGENDSM, ndisMSetPacketFilter)
+#pragma alloc_text(PAGENDSM, ndisMSetCurrentLookahead)
+#pragma alloc_text(PAGENDSM, ndisMSetMulticastList)
+#pragma alloc_text(PAGENDSM, ndisMSetFunctionalAddress)
+#pragma alloc_text(PAGENDSM, ndisMSetGroupAddress)
+#pragma alloc_text(PAGENDSM, ndisMSetFddiMulticastList)
+#pragma alloc_text(PAGENDSM, ndisMSetInformation)
+#pragma alloc_text(PAGENDSM, ndisMQueryCurrentPacketFilter)
+#pragma alloc_text(PAGENDSM, ndisMQueryMediaSupported)
+#pragma alloc_text(PAGENDSM, ndisMQueryEthernetMulticastList)
+#pragma alloc_text(PAGENDSM, ndisMQueryLongMulticastList)
+#pragma alloc_text(PAGENDSM, ndisMQueryShortMulticastList)
+#pragma alloc_text(PAGENDSM, ndisMQueryMaximumFrameSize)
+#pragma alloc_text(PAGENDSM, ndisMQueryMaximumTotalSize)
+#pragma alloc_text(PAGENDSM, ndisMQueryNetworkAddress)
+#pragma alloc_text(PAGENDSM, ndisMQueryInformation)
+#pragma alloc_text(PAGENDSM, ndisMDoRequests)
+#pragma alloc_text(PAGENDSM, ndisMAllocateRequest)
+#pragma alloc_text(PAGENDSM, ndisMQueueRequest)
+#pragma alloc_text(PAGENDSM, ndisMRestoreFilterSettings)
+#pragma alloc_text(PAGENDSM, ndisMFilterOutStatisticsOids)
+#pragma alloc_text(PAGENDSM, ndisMQueryOidList)
+#pragma alloc_text(PAGENDSM, ndisMChangeFddiAddresses)
+#pragma alloc_text(PAGENDSM, ndisMChangeFunctionalAddress)
+#pragma alloc_text(PAGENDSM, ndisMChangeGroupAddress)
+#pragma alloc_text(PAGENDSM, ndisMCloseAction)
+#pragma alloc_text(PAGENDSM, ndisMChangeClass)
+#pragma alloc_text(PAGENDSM, ndisMChangeEthAddresses)
+#pragma alloc_text(PAGENDSM, ndisMCopyFromPacketToBuffer)
+#pragma alloc_text(PAGENDSM, ndisMIndicateLoopback)
+#pragma alloc_text(PAGENDSM, ndisMIsLoopbackPacket)
+#pragma alloc_text(PAGENDSM, ndisMStartSendPacketsFullDuplex)
+#pragma alloc_text(PAGENDSM, ndisMStartSendsFullDuplex)
+#pragma alloc_text(PAGENDSM, ndisMStartSendPackets)
+#pragma alloc_text(PAGENDSM, ndisMStartSends)
+#pragma alloc_text(PAGENDSM, ndisMSyncSend)
+#pragma alloc_text(PAGENDSM, ndisMWanSend)
+#pragma alloc_text(PAGENDSM, NdisMSendComplete)
+#pragma alloc_text(PAGENDSM, ndisMSendCompleteFullDuplex)
+#pragma alloc_text(PAGENDSM, NdisMWanSendComplete)
+#pragma alloc_text(PAGENDSM, ndisMSendResourcesAvailableFullDuplex)
+#pragma alloc_text(PAGENDSM, NdisMSendResourcesAvailable)
+#pragma alloc_text(PAGENDSM, ndisMSendFullDuplex)
+#pragma alloc_text(PAGENDSM, ndisMSend)
+#pragma alloc_text(PAGENDSM, NdisMStartBufferPhysicalMapping)
+#pragma alloc_text(PAGENDSM, NdisMCompleteBufferPhysicalMapping)
+
+#pragma alloc_text(PAGENDSP, ndisMOpenAdapter)
+#pragma alloc_text(PAGENDSP, ndisMSendFullDuplexToSendPackets)
+#pragma alloc_text(PAGENDSP, ndisMSendPacketsFullDuplex)
+#pragma alloc_text(PAGENDSP, ndisMSendToSendPackets)
+#pragma alloc_text(PAGENDSP, ndisMSendPackets)
+#pragma alloc_text(PAGENDSP, ndisMSendPacketsFullDuplexToSend)
+#pragma alloc_text(PAGENDSP, ndisMSendPacketsToSend)
+#pragma alloc_text(PAGENDSP, NdisRegisterProtocol)
+#pragma alloc_text(PAGENDSP, NdisDeregisterProtocol)
+#pragma alloc_text(PAGENDSP, NdisOpenAdapter)
+#pragma alloc_text(PAGENDSP, NdisCloseAdapter)
+#pragma alloc_text(PAGENDSP, NdisSetProtocolFilter)
+#pragma alloc_text(PAGENDSP, NdisGetDriverHandle)
+#pragma alloc_text(PAGENDSP, ndisDereferenceProtocol)
+#pragma alloc_text(PAGENDSP, NdisOpenProtocolConfiguration)
+#pragma alloc_text(PAGENDSP, ndisQueueOpenOnProtocol)
+#pragma alloc_text(PAGENDSP, ndisDeQueueOpenOnProtocol)
+#pragma alloc_text(PAGENDSP, NdisWriteEventLogEntry)
+
+#pragma alloc_text(PAGENDSW, NdisDeregisterMac)
+#pragma alloc_text(PAGENDSW, ndisDpc)
+#pragma alloc_text(PAGENDSW, ndisIsr)
+#pragma alloc_text(PAGENDSW, ndisDereferenceMac)
+#pragma alloc_text(PAGENDSW, ndisDereferenceAdapter)
+#pragma alloc_text(PAGENDSW, ndisKillAdapter)
+#pragma alloc_text(PAGENDSW, ndisQueueOpenOnAdapter)
+#pragma alloc_text(PAGENDSW, ndisDeQueueOpenOnAdapter)
+#pragma alloc_text(PAGENDSW, ndisDeQueueAdapterOnMac)
+#pragma alloc_text(PAGENDSW, ndisQueueAdapterOnMac)
+#pragma alloc_text(PAGENDSW, ndisKillOpen)
+#pragma alloc_text(PAGENDSW, ndisKillOpenAndNotifyProtocol)
+#pragma alloc_text(PAGENDSW, ndisCloseIrpHandler)
+#pragma alloc_text(PAGENDSW, NdisCompleteQueryStatistics)
+#pragma alloc_text(PAGENDSW, ndisQueryOidList)
+#pragma alloc_text(PAGENDSW, NdisFinishOpen)
+#pragma alloc_text(PAGENDSW, NdisCompleteOpenAdapter)
+#pragma alloc_text(PAGENDSW, ndisQueuedCompleteOpenAdapter)
+#pragma alloc_text(PAGENDSW, NdisCompleteCloseAdapter)
+#pragma alloc_text(PAGENDSW, ndisQueuedCompleteCloseAdapter)
+#pragma alloc_text(PAGENDSW, ndisMacReceiveCompleteHandler)
+#pragma alloc_text(PAGENDSW, ndisMacReceiveHandler)
+#pragma alloc_text(PAGENDSW, ndisGetOpenBlockFromProtocolBindingContext)
+#pragma alloc_text(PAGENDSW, ndisShutdown)
+#pragma alloc_text(PAGENDSW, ndisUnload)
+
+#pragma alloc_text(PAGENDSE, ethRemoveBindingFromLists)
+#pragma alloc_text(PAGENDSE, ethRemoveAndFreeBinding)
+#pragma alloc_text(PAGENDSE, EthCreateFilter)
+#pragma alloc_text(PAGENDSE, EthDeleteFilter)
+#pragma alloc_text(PAGENDSE, EthNoteFilterOpenAdapter)
+#pragma alloc_text(PAGENDSE, EthDeleteFilterOpenAdapter)
+#pragma alloc_text(PAGENDSE, ethUndoChangeFilterAddresses)
+#pragma alloc_text(PAGENDSE, EthChangeFilterAddresses)
+#pragma alloc_text(PAGENDSE, ethUpdateDirectedBindingList)
+#pragma alloc_text(PAGENDSE, ethUpdateBroadcastBindingList)
+#pragma alloc_text(PAGENDSE, ethUpdateSpecificBindingLists)
+#pragma alloc_text(PAGENDSE, ethUndoFilterAdjust)
+#pragma alloc_text(PAGENDSE, EthFilterAdjust)
+#pragma alloc_text(PAGENDSE, EthNumberOfOpenFilterAddresses)
+#pragma alloc_text(PAGENDSE, EthQueryOpenFilterAddresses)
+#pragma alloc_text(PAGENDSE, EthQueryGlobalFilterAddresses)
+#pragma alloc_text(PAGENDSE, EthFilterIndicateReceiveComplete)
+#pragma alloc_text(PAGENDSE, EthFilterDprIndicateReceiveComplete)
+#pragma alloc_text(PAGENDSE, EthFilterDprIndicateReceiveCompleteFullMac)
+#pragma alloc_text(PAGENDSE, EthFilterIndicateReceive)
+#pragma alloc_text(PAGENDSE, EthFilterDprIndicateReceive)
+#pragma alloc_text(PAGENDSE, EthFilterDprIndicateReceiveFullMac)
+#pragma alloc_text(PAGENDSE, EthFilterDprIndicateReceivePacket)
+#pragma alloc_text(PAGENDSE, EthFindMulticast)
+#pragma alloc_text(PAGENDSE, EthShouldAddressLoopBack)
+
+#pragma alloc_text(PAGENDST, trRemoveBindingFromLists)
+#pragma alloc_text(PAGENDST, trRemoveAndFreeBinding)
+#pragma alloc_text(PAGENDST, TrCreateFilter)
+#pragma alloc_text(PAGENDST, TrDeleteFilter)
+#pragma alloc_text(PAGENDST, TrNoteFilterOpenAdapter)
+#pragma alloc_text(PAGENDST, TrDeleteFilterOpenAdapter)
+#pragma alloc_text(PAGENDST, trUndoChangeFunctionalAddress)
+#pragma alloc_text(PAGENDST, TrChangeFunctionalAddress)
+#pragma alloc_text(PAGENDST, trUndoChangeGroupAddress)
+#pragma alloc_text(PAGENDST, trCompleteChangeGroupAddress)
+#pragma alloc_text(PAGENDST, TrChangeGroupAddress)
+#pragma alloc_text(PAGENDST, trUpdateDirectedBindingList)
+#pragma alloc_text(PAGENDST, trUpdateBroadcastBindingList)
+#pragma alloc_text(PAGENDST, trUpdateSpecificBindingLists)
+#pragma alloc_text(PAGENDST, trUndoFilterAdjust)
+#pragma alloc_text(PAGENDST, TrFilterAdjust)
+#pragma alloc_text(PAGENDST, TrFilterIndicateReceive)
+#pragma alloc_text(PAGENDST, TrFilterDprIndicateReceive)
+#pragma alloc_text(PAGENDST, TrFilterDprIndicateReceiveFullMac)
+#pragma alloc_text(PAGENDST, TrFilterDprIndicateReceivePacket)
+#pragma alloc_text(PAGENDST, TrFilterIndicateReceiveComplete)
+#pragma alloc_text(PAGENDST, TrFilterDprIndicateReceiveComplete)
+#pragma alloc_text(PAGENDST, TrFilterDprIndicateReceiveCompleteFullMac)
+#pragma alloc_text(PAGENDST, TrShouldAddressLoopBack)
+
+#pragma alloc_text(PAGENDSF, fddiRemoveBindingFromLists)
+#pragma alloc_text(PAGENDSF, fddiRemoveAndFreeBinding)
+#pragma alloc_text(PAGENDSF, FddiCreateFilter)
+#pragma alloc_text(PAGENDSF, FddiDeleteFilter)
+#pragma alloc_text(PAGENDSF, FddiNoteFilterOpenAdapter)
+#pragma alloc_text(PAGENDSF, FddiDeleteFilterOpenAdapter)
+#pragma alloc_text(PAGENDSF, fddiUndoChangeFilterLongAddresses)
+#pragma alloc_text(PAGENDSF, FddiChangeFilterLongAddresses)
+#pragma alloc_text(PAGENDSF, fddiUndoChangeFilterShortAddresses)
+#pragma alloc_text(PAGENDSF, FddiChangeFilterShortAddresses)
+#pragma alloc_text(PAGENDSF, fddiUpdateDirectedBindingList)
+#pragma alloc_text(PAGENDSF, fddiUpdateBroadcastBindingList)
+#pragma alloc_text(PAGENDSF, fddiUpdateSpecificBindingLists)
+#pragma alloc_text(PAGENDSF, fddiUndoFilterAdjust)
+#pragma alloc_text(PAGENDSF, FddiFilterAdjust)
+#pragma alloc_text(PAGENDSF, FddiNumberOfOpenFilterLongAddresses)
+#pragma alloc_text(PAGENDSF, FddiNumberOfOpenFilterShortAddresses)
+#pragma alloc_text(PAGENDSF, FddiQueryOpenFilterLongAddresses)
+#pragma alloc_text(PAGENDSF, FddiQueryOpenFilterShortAddresses)
+#pragma alloc_text(PAGENDSF, FddiQueryGlobalFilterLongAddresses)
+#pragma alloc_text(PAGENDSF, FddiQueryGlobalFilterShortAddresses)
+#pragma alloc_text(PAGENDSF, FddiFilterIndicateReceive)
+#pragma alloc_text(PAGENDSF, FddiFilterDprIndicateReceive)
+#pragma alloc_text(PAGENDSF, FddiFilterDprIndicateReceiveFullMac)
+#pragma alloc_text(PAGENDSF, FddiFilterDprIndicateReceivePacket)
+#pragma alloc_text(PAGENDSF, FddiFilterIndicateReceiveComplete)
+#pragma alloc_text(PAGENDSF, FddiFilterDprIndicateReceiveComplete)
+#pragma alloc_text(PAGENDSF, FddiFilterDprIndicateReceiveCompleteFullMac)
+#pragma alloc_text(PAGENDSF, FddiFindMulticastLongAddress)
+#pragma alloc_text(PAGENDSF, FddiFindMulticastShortAddress)
+#pragma alloc_text(PAGENDSF, FddiShouldAddressLoopBack)
+
+#pragma alloc_text(PAGENDSA, ArcAllocateBuffers)
+#pragma alloc_text(PAGENDSA, ArcAllocatePackets)
+#pragma alloc_text(PAGENDSA, ArcDiscardPacketBuffers)
+#pragma alloc_text(PAGENDSA, ArcFreeNdisPacket)
+#pragma alloc_text(PAGENDSA, ArcDestroyPacket)
+#pragma alloc_text(PAGENDSA, ArcConvertToNdisPacket)
+#pragma alloc_text(PAGENDSA, ArcFilterDprIndicateReceive)
+#pragma alloc_text(PAGENDSA, ArcCreateFilter)
+#pragma alloc_text(PAGENDSA, ArcDeleteFilter)
+#pragma alloc_text(PAGENDSA, ArcNoteFilterOpenAdapter)
+#pragma alloc_text(PAGENDSA, ArcDeleteFilterOpenAdapter)
+#pragma alloc_text(PAGENDSA, ArcFilterAdjust)
+#pragma alloc_text(PAGENDSA, ArcFilterDoIndication)
+#pragma alloc_text(PAGENDSA, ArcFilterDprIndicateReceiveComplete)
+#pragma alloc_text(PAGENDSA, ArcConvertOidListToEthernet)
+#pragma alloc_text(PAGENDSA, ndisMArcCopyFromBufferToPacket)
+#pragma alloc_text(PAGENDSA, ndisMArcnetSend)
+#pragma alloc_text(PAGENDSA, ndisMArcTransferData)
+#pragma alloc_text(PAGENDSA, ndisMArcIndicateEthEncapsulatedReceive)
+#pragma alloc_text(PAGENDSA, ndisMBuildArcnetHeader)
+#pragma alloc_text(PAGENDSA, ndisMFreeArcnetHeader)
+#pragma alloc_text(PAGENDSA, ndisMArcnetSendLoopback)
+
+#pragma alloc_text(PAGENDCO, NdisCmRegisterAddressFamily)
+#pragma alloc_text(PAGENDCO, NdisClOpenAddressFamily)
+#pragma alloc_text(PAGENDCO, NdisCmOpenAddressFamilyComplete)
+#pragma alloc_text(PAGENDCO, NdisClCloseAddressFamily)
+#pragma alloc_text(PAGENDCO, NdisCmCloseAddressFamilyComplete)
+#pragma alloc_text(PAGENDCO, NdisClRegisterSap)
+#pragma alloc_text(PAGENDCO, NdisCmRegisterSapComplete)
+#pragma alloc_text(PAGENDCO, NdisClDeregisterSap)
+#pragma alloc_text(PAGENDCO, NdisCmDeregisterSapComplete)
+#pragma alloc_text(PAGENDCO, NdisClMakeCall)
+#pragma alloc_text(PAGENDCO, NdisCmMakeCallComplete)
+#pragma alloc_text(PAGENDCO, NdisCmDispatchIncomingCall)
+#pragma alloc_text(PAGENDCO, NdisClIncomingCallComplete)
+#pragma alloc_text(PAGENDCO, NdisCmDispatchCallConnected)
+#pragma alloc_text(PAGENDCO, NdisClModifyCallQoS)
+#pragma alloc_text(PAGENDCO, NdisCmModifyCallQoSComplete)
+#pragma alloc_text(PAGENDCO, NdisCmDispatchIncomingCallQoSChange)
+#pragma alloc_text(PAGENDCO, NdisClCloseCall)
+#pragma alloc_text(PAGENDCO, NdisCmCloseCallComplete)
+#pragma alloc_text(PAGENDCO, NdisCmDispatchIncomingCloseCall)
+#pragma alloc_text(PAGENDCO, NdisClAddParty)
+#pragma alloc_text(PAGENDCO, NdisCmAddPartyComplete)
+#pragma alloc_text(PAGENDCO, NdisClDropParty)
+#pragma alloc_text(PAGENDCO, NdisCmDropPartyComplete)
+#pragma alloc_text(PAGENDCO, NdisCmDispatchIncomingDropParty)
+#pragma alloc_text(PAGENDCO, NdisCoCreateVc)
+#pragma alloc_text(PAGENDCO, NdisCoDeleteVc)
+#pragma alloc_text(PAGENDCO, NdisCmActivateVc)
+#pragma alloc_text(PAGENDCO, NdisMCoActivateVcComplete)
+#pragma alloc_text(PAGENDCO, NdisCmDeactivateVc)
+#pragma alloc_text(PAGENDCO, NdisMCoDeactivateVcComplete)
+#pragma alloc_text(PAGENDCO, NdisCoRequest)
+#pragma alloc_text(PAGENDCO, NdisCoRequestComplete)
+#pragma alloc_text(PAGENDCO, NdisMCoIndicateReceivePacket)
+#pragma alloc_text(PAGENDCO, NdisMCoReceiveComplete)
+#pragma alloc_text(PAGENDCO, NdisCoSendPackets)
+#pragma alloc_text(PAGENDCO, NdisMCoSendComplete)
+#pragma alloc_text(PAGENDCO, NdisMCoIndicateStatus)
+#pragma alloc_text(PAGENDCO, NdisMCmRegisterAddressFamily)
+#pragma alloc_text(PAGENDCO, NdisMCmCreateVc)
+// #pragma alloc_text(PAGENDCO, NdisMCmDeleteVc)
+#pragma alloc_text(PAGENDCO, NdisMCmActivateVc)
+#pragma alloc_text(PAGENDCO, NdisMCmDeactivateVc)
+#pragma alloc_text(PAGENDCO, ndisMNotifyAfRegistration)
+#pragma alloc_text(PAGENDCO, ndisReferenceAf)
+#pragma alloc_text(PAGENDCO, ndisDereferenceAf)
+#pragma alloc_text(PAGENDCO, ndisReferenceSap)
+#pragma alloc_text(PAGENDCO, ndisDereferenceSap)
+#pragma alloc_text(PAGENDSM, ndisMCoFreeResources)
+#pragma alloc_text(PAGENDCO, ndisReferenceVc)
+#pragma alloc_text(PAGENDCO, ndisDereferenceVc)
+#pragma alloc_text(PAGENDCO, ndisMRejectSend)
+#pragma alloc_text(PAGENDCO, ndisMRejectSendPackets)
+#pragma alloc_text(PAGENDCO, ndisMCoDpc)
+#pragma alloc_text(PAGENDCO, ndisMCoDpcTimer)
+
+#else // NDIS_WIN
+
+#pragma NDIS_PAGEABLE_FUNCTION(NdisMInitializeTimer)
+#pragma NDIS_LOCKED_FUNCTION(NdisMCancelTimer)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisMDeregisterInterrupt)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisMRegisterInterrupt)
+#pragma NDIS_LOCKED_FUNCTION(NdisMSynchronizeWithInterrupt)
+#pragma NDIS_LOCKED_FUNCTION(ndisMIsr)
+#pragma NDIS_LOCKED_FUNCTION(ndisMDpc)
+#pragma NDIS_LOCKED_FUNCTION(ndisMWakeUpDpc)
+#pragma NDIS_LOCKED_FUNCTION(ndisMDpcTimer)
+#pragma NDIS_LOCKED_FUNCTION(ndisMTimerDpc)
+#pragma NDIS_LOCKED_FUNCTION(ndisMDeferredTimerDpc)
+#pragma NDIS_LOCKED_FUNCTION(ndisMDeQueueWorkItem)
+#pragma NDIS_LOCKED_FUNCTION(ndisMDeQueueWorkItemFullDuplex)
+#pragma NDIS_LOCKED_FUNCTION(ndisMQueueWorkItem)
+#pragma NDIS_LOCKED_FUNCTION(ndisMQueueWorkItemFullDuplex)
+#pragma NDIS_LOCKED_FUNCTION(ndisMQueueNewWorkItem)
+#pragma NDIS_LOCKED_FUNCTION(ndisMQueueNewWorkItemFullDuplex)
+#pragma NDIS_LOCKED_FUNCTION(ndisMProcessDeferredFullDuplex)
+#pragma NDIS_LOCKED_FUNCTION(ndisMProcessDeferred)
+#if _SEND_PRIORITY
+#pragma NDIS_LOCKED_FUNCTION(PAGENDSM, ndisMProcessDeferredFullDuplexPrioritySends)
+#pragma NDIS_LOCKED_FUNCTION(PAGENDSM, ndisMProcessDeferredPrioritySends)
+#endif
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMProcessResetRequested)
+#pragma NDIS_LOCKED_FUNCTION(NdisMIndicateStatus)
+#pragma NDIS_LOCKED_FUNCTION(NdisMIndicateStatusComplete)
+#pragma NDIS_LOCKED_FUNCTION(NdisMWanIndicateReceive)
+#pragma NDIS_LOCKED_FUNCTION(NdisMWanIndicateReceiveComplete)
+#pragma NDIS_LOCKED_FUNCTION(NdisQueryReceiveInformation)
+#pragma NDIS_LOCKED_FUNCTION(NdisReturnPackets)
+#pragma NDIS_LOCKED_FUNCTION(ndisMIndicatePacket)
+#pragma NDIS_LOCKED_FUNCTION(ndisMLazyReturnPackets)
+#pragma NDIS_LOCKED_FUNCTION(NdisMTransferDataComplete)
+#pragma NDIS_LOCKED_FUNCTION(ndisMTransferDataSync)
+#pragma NDIS_LOCKED_FUNCTION(ndisMTransferData)
+#pragma NDIS_LOCKED_FUNCTION(ndisMDummyTransferData)
+#pragma NDIS_LOCKED_FUNCTION(ndisMAbortPacketsAndRequests)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMResetCompleteCommonStep2)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMResetCompleteCommonStep1)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMProcessResetRequested)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMResetCompleteFullDuplex)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisMResetComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMResetFullDuplex)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMReset)
+#pragma NDIS_LOCKED_FUNCTION(ndisMResetSend)
+#pragma NDIS_LOCKED_FUNCTION(ndisMResetSendPackets)
+#pragma NDIS_LOCKED_FUNCTION(NdisIMSwitchToMiniport)
+#pragma NDIS_LOCKED_FUNCTION(NdisIMRevertBack)
+#pragma NDIS_LOCKED_FUNCTION(NdisIMQueueMiniportCallback)
+#pragma NDIS_LOCKED_FUNCTION(ndisIMQueueWorkItem)
+#pragma NDIS_LOCKED_FUNCTION(ndisIMQueueWorkItemFullDuplex)
+#pragma NDIS_LOCKED_FUNCTION(ndisIMQueueNewWorkItem)
+#pragma NDIS_LOCKED_FUNCTION(ndisIMQueueNewWorkItemFullDuplex)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMRequest)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMUndoBogusFilters)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMDoMiniportOp)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMRequestQueryInformationPost)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMSyncQueryInformationComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisMQueryInformationComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMRequestSetInformationPost)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMSyncSetInformationComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisMSetInformationComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMAbortQueryStatisticsRequest)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMSetPacketFilter)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMSetCurrentLookahead)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMSetMulticastList)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMSetFunctionalAddress)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMSetGroupAddress)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMSetFddiMulticastList)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMSetInformation)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMQueryCurrentPacketFilter)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMQueryMediaSupported)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMQueryEthernetMulticastList)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMQueryLongMulticastList)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMQueryShortMulticastList)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMQueryMaximumFrameSize)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMQueryMaximumTotalSize)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMQueryNetworkAddress)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMQueryInformation)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMDoRequests)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMAllocateRequest)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMQueueRequest)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMRestoreFilterSettings)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMFilterOutStatisticsOids)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMQueryOidList)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMChangeFddiAddresses)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMChangeFunctionalAddress)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMChangeGroupAddress)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMCloseAction)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMChangeClass)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMChangeEthAddresses)
+#pragma NDIS_LOCKED_FUNCTION(ndisMCopyFromPacketToBuffer)
+#pragma NDIS_LOCKED_FUNCTION(ndisMIndicateLoopback)
+#pragma NDIS_LOCKED_FUNCTION(ndisMIsLoopbackPacket)
+#pragma NDIS_LOCKED_FUNCTION(ndisMStartSendPacketsFullDuplex)
+#pragma NDIS_LOCKED_FUNCTION(ndisMStartSendsFullDuplex)
+#pragma NDIS_LOCKED_FUNCTION(ndisMStartSendPackets)
+#pragma NDIS_LOCKED_FUNCTION(ndisMStartSends)
+#pragma NDIS_LOCKED_FUNCTION(ndisMSyncSend)
+#pragma NDIS_LOCKED_FUNCTION(ndisMWanSend)
+#pragma NDIS_LOCKED_FUNCTION(NdisMSendComplete)
+#pragma NDIS_LOCKED_FUNCTION(ndisMSendCompleteFullDuplex)
+#pragma NDIS_LOCKED_FUNCTION(NdisMWanSendComplete)
+#pragma NDIS_LOCKED_FUNCTION(ndisMSendResourcesAvailableFullDuplex)
+#pragma NDIS_LOCKED_FUNCTION(NdisMSendResourcesAvailable)
+#pragma NDIS_LOCKED_FUNCTION(ndisMSendFullDuplexToSendPackets)
+#pragma NDIS_LOCKED_FUNCTION(ndisMSendPacketsFullDuplex)
+#pragma NDIS_LOCKED_FUNCTION(ndisMSendToSendPackets)
+#pragma NDIS_LOCKED_FUNCTION(ndisMSendPackets)
+#pragma NDIS_LOCKED_FUNCTION(ndisMSendPacketsFullDuplexToSend)
+#pragma NDIS_LOCKED_FUNCTION(ndisMSendFullDuplex)
+#pragma NDIS_LOCKED_FUNCTION(ndisMSendPacketsToSend)
+#pragma NDIS_LOCKED_FUNCTION(ndisMSend)
+
+#pragma NDIS_PAGEABLE_FUNCTION(ethRemoveBindingFromLists)
+#pragma NDIS_PAGEABLE_FUNCTION(ethRemoveAndFreeBinding)
+#pragma NDIS_PAGEABLE_FUNCTION(EthCreateFilter)
+#pragma NDIS_PAGEABLE_FUNCTION(EthDeleteFilter)
+#pragma NDIS_PAGEABLE_FUNCTION(EthNoteFilterOpenAdapter)
+#pragma NDIS_PAGEABLE_FUNCTION(EthDeleteFilterOpenAdapter)
+#pragma NDIS_PAGEABLE_FUNCTION(ethUndoChangeFilterAddresses)
+#pragma NDIS_PAGEABLE_FUNCTION(EthChangeFilterAddresses)
+#pragma NDIS_PAGEABLE_FUNCTION(ethUpdateDirectedBindingList)
+#pragma NDIS_PAGEABLE_FUNCTION(ethUpdateBroadcastBindingList)
+#pragma NDIS_PAGEABLE_FUNCTION(ethUpdateSpecificBindingLists)
+#pragma NDIS_PAGEABLE_FUNCTION(ethUndoFilterAdjust)
+#pragma NDIS_PAGEABLE_FUNCTION(EthFilterAdjust)
+#pragma NDIS_PAGEABLE_FUNCTION(EthNumberOfOpenFilterAddresses)
+#pragma NDIS_PAGEABLE_FUNCTION(EthQueryOpenFilterAddresses)
+#pragma NDIS_PAGEABLE_FUNCTION(EthQueryGlobalFilterAddresses)
+#pragma NDIS_LOCKED_FUNCTION(EthFilterIndicateReceiveComplete)
+#pragma NDIS_LOCKED_FUNCTION(EthFilterDprIndicateReceiveComplete)
+#pragma NDIS_LOCKED_FUNCTION(EthFilterDprIndicateReceiveCompleteFullMac)
+#pragma NDIS_LOCKED_FUNCTION(EthFilterIndicateReceive)
+#pragma NDIS_LOCKED_FUNCTION(EthFilterDprIndicateReceive)
+#pragma NDIS_LOCKED_FUNCTION(EthFilterDprIndicateReceiveFullMac)
+#pragma NDIS_LOCKED_FUNCTION(EthFilterDprIndicateReceivePacket)
+#pragma NDIS_LOCKED_FUNCTION(EthFindMulticast)
+#pragma NDIS_LOCKED_FUNCTION(EthShouldAddressLoopBack)
+
+#pragma NDIS_PAGEABLE_FUNCTION(trRemoveBindingFromLists)
+#pragma NDIS_PAGEABLE_FUNCTION(trRemoveAndFreeBinding)
+#pragma NDIS_PAGEABLE_FUNCTION(TrCreateFilter)
+#pragma NDIS_PAGEABLE_FUNCTION(TrDeleteFilter)
+#pragma NDIS_PAGEABLE_FUNCTION(TrNoteFilterOpenAdapter)
+#pragma NDIS_PAGEABLE_FUNCTION(TrDeleteFilterOpenAdapter)
+#pragma NDIS_PAGEABLE_FUNCTION(trUndoChangeFunctionalAddress)
+#pragma NDIS_PAGEABLE_FUNCTION(TrChangeFunctionalAddress)
+#pragma NDIS_PAGEABLE_FUNCTION(trUndoChangeGroupAddress)
+#pragma NDIS_PAGEABLE_FUNCTION(trCompleteChangeGroupAddress)
+#pragma NDIS_PAGEABLE_FUNCTION(TrChangeGroupAddress)
+#pragma NDIS_PAGEABLE_FUNCTION(trUpdateDirectedBindingList)
+#pragma NDIS_PAGEABLE_FUNCTION(trUpdateBroadcastBindingList)
+#pragma NDIS_PAGEABLE_FUNCTION(trUpdateSpecificBindingLists)
+#pragma NDIS_PAGEABLE_FUNCTION(trUndoFilterAdjust)
+#pragma NDIS_PAGEABLE_FUNCTION(TrFilterAdjust)
+#pragma NDIS_LOCKED_FUNCTION(TrFilterIndicateReceive)
+#pragma NDIS_LOCKED_FUNCTION(TrFilterDprIndicateReceive)
+#pragma NDIS_LOCKED_FUNCTION(TrFilterDprIndicateReceiveFullMac)
+#pragma NDIS_LOCKED_FUNCTION(TrFilterDprIndicateReceivePacket)
+#pragma NDIS_LOCKED_FUNCTION(TrFilterIndicateReceiveComplete)
+#pragma NDIS_LOCKED_FUNCTION(TrFilterDprIndicateReceiveComplete)
+#pragma NDIS_LOCKED_FUNCTION(TrFilterDprIndicateReceiveCompleteFullMac)
+#pragma NDIS_LOCKED_FUNCTION(TrShouldAddressLoopBack)
+
+#pragma NDIS_PAGEABLE_FUNCTION(fddiRemoveBindingFromLists)
+#pragma NDIS_PAGEABLE_FUNCTION(fddiRemoveAndFreeBinding)
+#pragma NDIS_PAGEABLE_FUNCTION(FddiCreateFilter)
+#pragma NDIS_PAGEABLE_FUNCTION(FddiDeleteFilter)
+#pragma NDIS_PAGEABLE_FUNCTION(FddiNoteFilterOpenAdapter)
+#pragma NDIS_PAGEABLE_FUNCTION(FddiDeleteFilterOpenAdapter)
+#pragma NDIS_PAGEABLE_FUNCTION(fddiUndoChangeFilterLongAddresses)
+#pragma NDIS_PAGEABLE_FUNCTION(FddiChangeFilterLongAddresses)
+#pragma NDIS_PAGEABLE_FUNCTION(fddiUndoChangeFilterShortAddresses)
+#pragma NDIS_PAGEABLE_FUNCTION(FddiChangeFilterShortAddresses)
+#pragma NDIS_PAGEABLE_FUNCTION(fddiUpdateDirectedBindingList)
+#pragma NDIS_PAGEABLE_FUNCTION(fddiUpdateBroadcastBindingList)
+#pragma NDIS_PAGEABLE_FUNCTION(fddiUpdateSpecificBindingLists)
+#pragma NDIS_PAGEABLE_FUNCTION(fddiUndoFilterAdjust)
+#pragma NDIS_PAGEABLE_FUNCTION(FddiFilterAdjust)
+#pragma NDIS_PAGEABLE_FUNCTION(FddiNumberOfOpenFilterLongAddresses)
+#pragma NDIS_PAGEABLE_FUNCTION(FddiNumberOfOpenFilterShortAddresses)
+#pragma NDIS_PAGEABLE_FUNCTION(FddiQueryOpenFilterLongAddresses)
+#pragma NDIS_PAGEABLE_FUNCTION(FddiQueryOpenFilterShortAddresses)
+#pragma NDIS_PAGEABLE_FUNCTION(FddiQueryGlobalFilterLongAddresses)
+#pragma NDIS_PAGEABLE_FUNCTION(FddiQueryGlobalFilterShortAddresses)
+#pragma NDIS_LOCKED_FUNCTION(FddiFilterIndicateReceive)
+#pragma NDIS_LOCKED_FUNCTION(FddiFilterDprIndicateReceive)
+#pragma NDIS_LOCKED_FUNCTION(FddiFilterDprIndicateReceiveFullMac)
+#pragma NDIS_LOCKED_FUNCTION(FddiFilterDprIndicateReceivePacket)
+#pragma NDIS_LOCKED_FUNCTION(FddiFilterIndicateReceiveComplete)
+#pragma NDIS_LOCKED_FUNCTION(FddiFilterDprIndicateReceiveComplete)
+#pragma NDIS_LOCKED_FUNCTION(FddiFilterDprIndicateReceiveCompleteFullMac)
+#pragma NDIS_LOCKED_FUNCTION(FddiFindMulticastLongAddress)
+#pragma NDIS_LOCKED_FUNCTION(FddiFindMulticastShortAddress)
+#pragma NDIS_LOCKED_FUNCTION(FddiShouldAddressLoopBack)
+
+#pragma NDIS_LOCKED_FUNCTION(ArcAllocateBuffers)
+#pragma NDIS_LOCKED_FUNCTION(ArcAllocatePackets)
+#pragma NDIS_LOCKED_FUNCTION(ArcDiscardPacketBuffers)
+#pragma NDIS_LOCKED_FUNCTION(ArcFreeNdisPacket)
+#pragma NDIS_LOCKED_FUNCTION(ArcDestroyPacket)
+#pragma NDIS_LOCKED_FUNCTION(ArcConvertToNdisPacket)
+#pragma NDIS_LOCKED_FUNCTION(ArcFilterDprIndicateReceive)
+#pragma NDIS_PAGEABLE_FUNCTION(ArcCreateFilter)
+#pragma NDIS_PAGEABLE_FUNCTION(ArcDeleteFilter)
+#pragma NDIS_PAGEABLE_FUNCTION(ArcNoteFilterOpenAdapter)
+#pragma NDIS_PAGEABLE_FUNCTION(ArcDeleteFilterOpenAdapter)
+#pragma NDIS_PAGEABLE_FUNCTION(ArcFilterAdjust)
+#pragma NDIS_LOCKED_FUNCTION(ArcFilterDoIndication)
+#pragma NDIS_LOCKED_FUNCTION(ArcFilterDprIndicateReceiveComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(ArcConvertOidListToEthernet)
+#pragma NDIS_LOCKED_FUNCTION(ndisMArcCopyFromBufferToPacket)
+#pragma NDIS_LOCKED_FUNCTION(ndisMArcnetSend)
+#pragma NDIS_LOCKED_FUNCTION(ndisMArcTransferData)
+#pragma NDIS_LOCKED_FUNCTION(ndisMArcIndicateEthEncapsulatedReceive)
+#pragma NDIS_LOCKED_FUNCTION(ndisMBuildArcnetHeader)
+#pragma NDIS_LOCKED_FUNCTION(ndisMFreeArcnetHeader)
+#pragma NDIS_LOCKED_FUNCTION(ndisMArcnetSendLoopback)
+
+
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmRegisterAddressFamily)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisClOpenAddressFamily)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmOpenAddressFamilyComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMNotifyAfRegistration)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisClCloseAddressFamily)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmCloseAddressFamilyComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisClRegisterSap)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmRegisterSapComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisClDeregisterSap)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmDeregisterSapComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisClMakeCall)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmMakeCallComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmDispatchIncomingCall)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisClIncomingCallComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmDispatchCallConnected)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisClModifyCallQoS)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmModifyCallQoSComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmDispatchIncomingCallQoSChange)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisClCloseCall)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmCloseCallComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmDispatchIncomingCloseCall)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisClAddParty)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmAddPartyComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisClDropParty)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmDropPartyComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmDispatchIncomingDropParty)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCoCreateVc)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCoDeleteVc)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmActivateVc)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisMCoActivateVcComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmDeactivateVc)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisMCoDeactivateVcComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCoRequest)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCoRequestComplete)
+#pragma NDIS_LOCKED_FUNCTION(NdisMCoIndicateReceivePacket)
+#pragma NDIS_LOCKED_FUNCTION(NdisMCoReceiveComplete)
+#pragma NDIS_LOCKED_FUNCTION(NdisCoSendPackets)
+#pragma NDIS_LOCKED_FUNCTION(NdisMCoSendComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisMCoIndicateStatus)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisMCmRegisterAddressFamily)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisMCoRequestComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisReferenceAf)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisDereferenceAf)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisReferenceSap)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisDereferenceSap)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMCoFreeResources)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisReferenceVc)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisDereferenceVc)
+#pragma NDIS_LOCKED_FUNCTION(ndisMRejectSend)
+#pragma NDIS_LOCKED_FUNCTION(ndisMRejectSendPackets)
+#pragma NDIS_LOCKED_FUNCTION(ndisMCoDpc)
+#pragma NDIS_LOCKED_FUNCTION(ndisMCoDpcTimer)
+#endif // NDIS_NT
+#endif // ALLOC_PRAGMA
+
+#endif // _PRAGMA_
diff --git a/private/ntos/ndis/ndis40/precomp.h b/private/ntos/ndis/ndis40/precomp.h
new file mode 100644
index 000000000..07c0aa762
--- /dev/null
+++ b/private/ntos/ndis/ndis40/precomp.h
@@ -0,0 +1,17 @@
+#include "ndisnt.h"
+#include "wrapper.h"
+#include "protos.h"
+#include "mac.h"
+#include "mini.h"
+#include "filter.h"
+
+#include <afilter.h>
+#include <efilter.h>
+#include <ffilter.h>
+#include <tfilter.h>
+
+#include "pragma.h"
+
+#include <tdikrnl.h>
+#include <ndisprv.h>
+
diff --git a/private/ntos/ndis/ndis40/protocol.c b/private/ntos/ndis/ndis40/protocol.c
new file mode 100644
index 000000000..f021a0ced
--- /dev/null
+++ b/private/ntos/ndis/ndis40/protocol.c
@@ -0,0 +1,1757 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ protocol.c
+
+Abstract:
+
+ NDIS wrapper functions used by protocol modules
+
+Author:
+
+ Adam Barr (adamba) 11-Jul-1990
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ 26-Feb-1991 JohnsonA Added Debugging Code
+ 10-Jul-1991 JohnsonA Implement revised Ndis Specs
+ 01-Jun-1995 JameelH Re-organization/optimization
+
+--*/
+
+#define GLOBALS
+#include <precomp.h>
+#pragma hdrstop
+
+#include <stdarg.h>
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_PROTOCOL
+
+//
+// Requests used by protocol modules
+//
+//
+
+VOID
+NdisRegisterProtocol(
+ OUT PNDIS_STATUS pStatus,
+ OUT PNDIS_HANDLE NdisProtocolHandle,
+ IN PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics,
+ IN UINT CharacteristicsLength
+ )
+/*++
+
+Routine Description:
+
+ Register an NDIS protocol.
+
+Arguments:
+
+ Status - Returns the final status.
+ NdisProtocolHandle - Returns a handle referring to this protocol.
+ ProtocolCharacteritics - The NDIS_PROTOCOL_CHARACTERISTICS table.
+ CharacteristicsLength - The length of ProtocolCharacteristics.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_PROTOCOL_BLOCK pProtocol;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+ USHORT size;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisRegisterProtocol\n"));
+
+ ProtocolReferencePackage();
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ BOOLEAN f = FALSE;
+ if (DbgIsNull(ProtocolCharacteristics->OpenAdapterCompleteHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterProtocol: OpenAdapterCompleteHandler Null\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(ProtocolCharacteristics->CloseAdapterCompleteHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterProtocol: CloseAdapterCompleteHandler Null\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(ProtocolCharacteristics->SendCompleteHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterProtocol: SendCompleteHandler Null\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(ProtocolCharacteristics->TransferDataCompleteHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterProtocol: TransferDataCompleteHandler Null\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(ProtocolCharacteristics->ResetCompleteHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterProtocol: ResetCompleteHandler Null\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(ProtocolCharacteristics->RequestCompleteHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterProtocol: RequestCompleteHandler Null\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(ProtocolCharacteristics->ReceiveHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterProtocol: ReceiveHandler Null\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(ProtocolCharacteristics->ReceiveCompleteHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterProtocol: ReceiveCompleteHandler Null\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(ProtocolCharacteristics->StatusHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterProtocol: StatusHandler Null\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(ProtocolCharacteristics->StatusCompleteHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterProtocol: StatusCompleteHandler Null\n"));
+ f = TRUE;
+ }
+ if (f)
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+
+ do
+ {
+ //
+ // Check version numbers and CharacteristicsLength.
+ //
+ size = 0; // Used to indicate bad version below
+ if (ProtocolCharacteristics->MajorNdisVersion == 3)
+ {
+ if (ProtocolCharacteristics->MinorNdisVersion == 0)
+ {
+ size = sizeof(NDIS30_PROTOCOL_CHARACTERISTICS);
+ }
+ }
+ else if (ProtocolCharacteristics->MajorNdisVersion == 4)
+ {
+ if (ProtocolCharacteristics->MinorNdisVersion == 0)
+ {
+ size = sizeof(NDIS40_PROTOCOL_CHARACTERISTICS);
+ }
+ else if (ProtocolCharacteristics->MinorNdisVersion == 1)
+ {
+ size = sizeof(NDIS41_PROTOCOL_CHARACTERISTICS);
+ }
+ }
+
+ //
+ // Check that this is an NDIS 3.0/4.0/4.1 protocol.
+ //
+ if (size == 0)
+ {
+ Status = NDIS_STATUS_BAD_VERSION;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisRegisterProtocol\n"));
+ break;
+ }
+
+ //
+ // Check that CharacteristicsLength is enough.
+ //
+ if (CharacteristicsLength < size)
+ {
+ Status = NDIS_STATUS_BAD_CHARACTERISTICS;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisRegisterProtocol\n"));
+ break;
+ }
+
+ //
+ // Allocate memory for the NDIS protocol block.
+ //
+ pProtocol = (PNDIS_PROTOCOL_BLOCK)ALLOC_FROM_POOL(sizeof(NDIS_PROTOCOL_BLOCK) +
+ ProtocolCharacteristics->Name.Length + sizeof(WCHAR),
+ NDIS_TAG_PROT_BLK);
+ if (pProtocol == (PNDIS_PROTOCOL_BLOCK)NULL)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisRegisterProtocol\n"));
+ break;
+ }
+ ZeroMemory(pProtocol, sizeof(NDIS_PROTOCOL_BLOCK) + sizeof(WCHAR) + ProtocolCharacteristics->Name.Length);
+ pProtocol->Length = sizeof(NDIS_PROTOCOL_BLOCK);
+ INITIALIZE_MUTEX(&pProtocol->Mutex);
+
+ //
+ // Copy over the characteristics table.
+ //
+ CopyMemory(&pProtocol->ProtocolCharacteristics,
+ ProtocolCharacteristics,
+ size);
+
+ // Upcase the name in the characteristics table before saving it.
+ pProtocol->ProtocolCharacteristics.Name.Buffer = (PWCHAR)((PUCHAR)pProtocol +
+ sizeof(NDIS_PROTOCOL_BLOCK));
+ pProtocol->ProtocolCharacteristics.Name.Length = ProtocolCharacteristics->Name.Length;
+ pProtocol->ProtocolCharacteristics.Name.MaximumLength = ProtocolCharacteristics->Name.Length;
+ RtlCopyUnicodeString(&pProtocol->ProtocolCharacteristics.Name,
+ &ProtocolCharacteristics->Name);
+
+ //
+ // No opens for this protocol yet.
+ //
+ pProtocol->OpenQueue = (PNDIS_OPEN_BLOCK)NULL;
+
+ NdisInitializeRef(&pProtocol->Ref);
+ *NdisProtocolHandle = (NDIS_HANDLE)pProtocol;
+ Status = NDIS_STATUS_SUCCESS;
+
+ //
+ // Link the protocol into the list.
+ //
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+
+ if (ProtocolCharacteristics->Flags & NDIS_PROTOCOL_CALL_MANAGER)
+ {
+ //
+ // If this protocol is a call-manager, then it must bind to the
+ // adapters below ahead of others. So link it at the head of the list.
+ //
+ pProtocol->NextProtocol = ndisProtocolList;
+ ndisProtocolList = pProtocol;
+ }
+ else
+ {
+ PNDIS_PROTOCOL_BLOCK *pTemp;
+
+ for (pTemp = & ndisProtocolList;
+ *pTemp != NULL;
+ pTemp = &(*pTemp)->NextProtocol)
+ {
+ if (((*pTemp)->ProtocolCharacteristics.Flags & NDIS_PROTOCOL_CALL_MANAGER) == 0)
+ break;
+ }
+ pProtocol->NextProtocol = *pTemp;
+ *pTemp = pProtocol;
+ }
+
+ if ((pProtocol->ProtocolCharacteristics.BindAdapterHandler != NULL) &&
+ ((ndisMiniDriverList != NULL) || (ndisMacDriverList != NULL)) &&
+ ndisReferenceProtocol(pProtocol))
+ {
+ // Start a worker thread to notify the protocol of any existing drivers
+ INITIALIZE_WORK_ITEM(&pProtocol->WorkItem, ndisNotifyProtocols, pProtocol);
+ QUEUE_WORK_ITEM(&pProtocol->WorkItem, DelayedWorkQueue);
+ }
+
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisRegisterProtocol\n"));
+
+ } while (FALSE);
+
+ *pStatus = Status;
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ ProtocolDereferencePackage();
+ }
+}
+
+
+VOID
+NdisDeregisterProtocol(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisProtocolHandle
+ )
+/*++
+
+Routine Description:
+
+ Deregisters an NDIS protocol.
+
+Arguments:
+
+ Status - Returns the final status.
+ NdisProtocolHandle - The handle returned by NdisRegisterProtocol.
+
+Return Value:
+
+ None.
+
+Note:
+
+ This will kill all the opens for this protocol.
+
+--*/
+{
+ PNDIS_PROTOCOL_BLOCK ProtP = (PNDIS_PROTOCOL_BLOCK)NdisProtocolHandle;
+ UINT i;
+ KEVENT DeregEvent;
+
+ //
+ // If the protocol is already closing, return.
+ //
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisDeregisterProtocol\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("Protocol: %wZ\n",&ProtP->ProtocolCharacteristics.Name));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(NdisProtocolHandle))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("DeregisterProtocol: Null Handle\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(NdisProtocolHandle))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("DeregisterProtocol: Handle not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ }
+ if (!NdisCloseRef(&ProtP->Ref))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisDeregisterProtocol\n"));
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+ //
+ // Kill all the opens for this protocol.
+ //
+ INITIALIZE_EVENT(&DeregEvent);
+ ProtP->DeregEvent = &DeregEvent;
+ while (ProtP->OpenQueue != (PNDIS_OPEN_BLOCK)NULL)
+ {
+ //
+ // This removes it from the protocol's OpenQueue etc.
+ //
+
+ ndisKillOpenAndNotifyProtocol(ProtP->OpenQueue);
+ }
+
+ //
+ // Kill all the protocol filters for this protocol.
+ //
+ for (i = 0; i < NdisMediumMax; i++)
+ {
+ while (ProtP->ProtocolFilter[i] != NULL)
+ {
+ PNDIS_PROTOCOL_FILTER pF;
+
+ pF = ProtP->ProtocolFilter[i];
+ ProtP->ProtocolFilter[i] = pF->Next;
+ FREE_POOL(pF);
+ ndisDereferenceProtocol(ProtP);
+ }
+ }
+
+ ndisDereferenceProtocol(ProtP);
+
+ WAIT_FOR_OBJECT(&DeregEvent, NULL);
+ *Status = NDIS_STATUS_SUCCESS;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisDeregisterProtocol\n"));
+}
+
+
+VOID
+NdisOpenAdapter(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PNDIS_HANDLE NdisBindingHandle,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE NdisProtocolHandle,
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_STRING AdapterName,
+ IN UINT OpenOptions,
+ IN PSTRING AddressingInformation OPTIONAL
+ )
+/*++
+
+Routine Description:
+
+ Opens a connection between a protocol and an adapter (MAC).
+
+Arguments:
+
+ Status - Returns the final status.
+ NdisBindingHandle - Returns a handle referring to this open.
+ SelectedMediumIndex - Index in MediumArray of the medium type that
+ the MAC wishes to be viewed as.
+ MediumArray - Array of medium types which a protocol supports.
+ MediumArraySize - Number of elements in MediumArray.
+ NdisProtocolHandle - The handle returned by NdisRegisterProtocol.
+ ProtocolBindingContext - A context for indications.
+ AdapterName - The name of the adapter to open.
+ OpenOptions - bit mask.
+ AddressingInformation - Information passed to MacOpenAdapter.
+
+Return Value:
+
+ None.
+
+Note:
+
+ This function opens the adapter which will cause an IRP_MJ_CREATE
+ to be sent to the adapter, which is ignored. However, after that we
+ can access the file object for the open, and fill it in as
+ appropriate. The work is done here rather than in the IRP_MJ_CREATE
+ handler because this avoids having to pass the parameters to
+ NdisOpenAdapter through to the adapter.
+
+--*/
+{
+ HANDLE FileHandle;
+ OBJECT_ATTRIBUTES ObjectAttr;
+ PFILE_OBJECT FileObject;
+ PDEVICE_OBJECT DeviceObject;
+ PNDIS_OPEN_BLOCK NewOpenP;
+ PNDIS_PROTOCOL_BLOCK TmpProtP;
+ PNDIS_ADAPTER_BLOCK TmpAdaptP;
+ NDIS_STATUS OpenStatus;
+ NTSTATUS NtOpenStatus;
+ IO_STATUS_BLOCK IoStatus;
+ PFILE_FULL_EA_INFORMATION OpenEa;
+ ULONG OpenEaLength;
+ BOOLEAN UsingEncapsulation;
+ KIRQL OldIrql;
+ BOOLEAN LocalLock;
+
+ //
+ // Allocate memory for the NDIS open block.
+ //
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisOpenAdapter\n"));
+
+ IF_DBG(DBG_COMP_CONFIG, DBG_LEVEL_ERR)
+ {
+ BOOLEAN f = FALSE;
+ if (DbgIsNull(NdisProtocolHandle))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("OpenAdapter: Null ProtocolHandle\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(NdisProtocolHandle))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("OpenAdapter: ProtocolHandle not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(ProtocolBindingContext))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("OpenAdapter: Null Context\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(ProtocolBindingContext))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("OpenAdapter: Context not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (f)
+ DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR);
+
+ }
+
+ NewOpenP = (PNDIS_OPEN_BLOCK)
+ ALLOC_FROM_POOL(sizeof(NDIS_OPEN_BLOCK) + AdapterName->MaximumLength,
+ NDIS_TAG_OPEN_BLK);
+ if (NewOpenP == (PNDIS_OPEN_BLOCK)NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisOpenAdapter\n"));
+ return;
+ }
+
+ ZeroMemory(NewOpenP, sizeof(NDIS_OPEN_BLOCK));
+ NewOpenP->AdapterName.Buffer = (PWCHAR)((PUCHAR)NewOpenP + sizeof(NDIS_OPEN_BLOCK));
+ NewOpenP->AdapterName.Length = AdapterName->Length;
+ NewOpenP->AdapterName.MaximumLength = AdapterName->MaximumLength;
+ RtlUpcaseUnicodeString(&NewOpenP->AdapterName,
+ AdapterName,
+ FALSE);
+
+ OpenEaLength = sizeof(FILE_FULL_EA_INFORMATION) +
+ sizeof(ndisInternalEaName) +
+ sizeof(ndisInternalEaValue);
+
+ OpenEa = ALLOC_FROM_POOL(OpenEaLength, NDIS_TAG_DEFAULT);
+
+ if (OpenEa == NULL)
+ {
+ FREE_POOL(NewOpenP);
+ *Status = NDIS_STATUS_RESOURCES;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisOpenAdapter\n"));
+ return;
+ }
+
+ OpenEa->NextEntryOffset = 0;
+ OpenEa->Flags = 0;
+ OpenEa->EaNameLength = sizeof(ndisInternalEaName);
+ OpenEa->EaValueLength = sizeof(ndisInternalEaValue);
+
+ CopyMemory(OpenEa->EaName,
+ ndisInternalEaName,
+ sizeof(ndisInternalEaName));
+
+ CopyMemory(&OpenEa->EaName[OpenEa->EaNameLength+1],
+ ndisInternalEaValue,
+ sizeof(ndisInternalEaValue));
+
+ //
+ // Obtain a handle to the driver's file object.
+ //
+ InitializeObjectAttributes(&ObjectAttr,
+ AdapterName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ NtOpenStatus = ZwCreateFile(&FileHandle,
+ FILE_READ_DATA | FILE_WRITE_DATA,
+ &ObjectAttr,
+ &IoStatus,
+ (PLARGE_INTEGER) NULL, // allocation size
+ 0L, // file attributes
+ FILE_SHARE_READ | FILE_SHARE_WRITE, // share access
+ FILE_OPEN, // create disposition
+ 0, // create options
+ OpenEa,
+ OpenEaLength);
+ FREE_POOL(OpenEa);
+
+ if (NtOpenStatus != STATUS_SUCCESS)
+ {
+ FREE_POOL(NewOpenP);
+
+ *Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisOpenAdapter\n"));
+ return;
+ }
+ //
+ // Convert the file handle into a pointer to the adapter's file object.
+ //
+ ObReferenceObjectByHandle(FileHandle,
+ 0,
+ NULL,
+ KernelMode,
+ (PVOID *) &FileObject,
+ NULL);
+
+ //
+ // Close the file handle, now that we have the object reference.
+ //
+ ZwClose(FileHandle);
+
+ //
+ // From the file object, obtain the device object.
+ //
+ DeviceObject = IoGetRelatedDeviceObject(FileObject);
+
+ //
+ // Get the adapter (or miniport) block from the device object.
+ //
+
+ TmpAdaptP = (PNDIS_ADAPTER_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1);
+
+ //
+ // Check if this is a Miniport or mac
+ //
+
+ if (TmpAdaptP->DeviceObject != DeviceObject)
+ {
+ //
+ // It is a Miniport
+ //
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)TmpAdaptP;
+ PMINIPORT_PENDING_OPEN MiniportPendingOpen;
+ ULONG i;
+
+ UsingEncapsulation = FALSE;
+
+ //
+ // Is this the ndiswan miniport wrapper?
+ //
+ if ((Miniport->MacOptions & (NDIS_MAC_OPTION_RESERVED | NDIS_MAC_OPTION_NDISWAN)) ==
+ (NDIS_MAC_OPTION_RESERVED | NDIS_MAC_OPTION_NDISWAN))
+ {
+ //
+ // Yup. We want the binding to think that this is an
+ // ndiswan link.
+ //
+ for (i = 0; i < MediumArraySize; i++)
+ {
+ if (MediumArray[i] == NdisMediumWan)
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ //
+ // Select the medium to use
+ //
+ for (i = 0; i < MediumArraySize; i++)
+ {
+ if (MediumArray[i] == Miniport->MediaType)
+ {
+ break;
+ }
+ }
+ }
+
+ if (i == MediumArraySize)
+ {
+ //
+ // Check for ethernet encapsulation on Arcnet as
+ // a possible combination.
+ //
+ if (Miniport->MediaType == NdisMediumArcnet878_2)
+ {
+ for (i = 0; i < MediumArraySize; i++)
+ {
+ if (MediumArray[i] == NdisMedium802_3)
+ {
+ break;
+ }
+ }
+
+ if (i == MediumArraySize)
+ {
+ *Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
+ ObDereferenceObject( FileObject);
+ return;
+ }
+
+ UsingEncapsulation = TRUE;
+ }
+ else
+ {
+ *Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
+ ObDereferenceObject( FileObject);
+ return;
+ }
+ }
+
+ *SelectedMediumIndex = i;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ //
+ // Allocate some space for this pending structure.
+ // We free in after we call NdisOpenComplete.
+ //
+ *Status = NdisAllocateMemory((PVOID *) &MiniportPendingOpen,
+ sizeof(MINIPORT_PENDING_OPEN),
+ 0,
+ HighestAcceptableMax);
+ if (*Status == NDIS_STATUS_SUCCESS)
+ {
+ NdisZeroMemory(MiniportPendingOpen, sizeof(MINIPORT_PENDING_OPEN));
+
+ //
+ // Save off the parameters for this open so we can
+ // do the actual NdisOpenAdapter() later on.
+ //
+ MiniportPendingOpen->NdisBindingHandle = NdisBindingHandle;
+ MiniportPendingOpen->NdisProtocolHandle = NdisProtocolHandle;
+ MiniportPendingOpen->ProtocolBindingContext = ProtocolBindingContext;
+ MiniportPendingOpen->AdapterName = AdapterName;
+ MiniportPendingOpen->OpenOptions = OpenOptions;
+ MiniportPendingOpen->AddressingInformation = AddressingInformation;
+ MiniportPendingOpen->Miniport = Miniport;
+ MiniportPendingOpen->NewOpenP = NewOpenP;
+ MiniportPendingOpen->FileObject = FileObject;
+
+ if (UsingEncapsulation)
+ {
+ MINIPORT_SET_FLAG(MiniportPendingOpen, fPENDING_OPEN_USING_ENCAPSULATION);
+ }
+
+ //
+ // Queue a work item to process the pending open adapter.
+ //
+ NDISM_QUEUE_NEW_WORK_ITEM(Miniport, NdisWorkItemPendingOpen, MiniportPendingOpen, NULL);
+
+ //
+ // Make sure ndisMProcessDeferred() completes the open.
+ //
+ *Status = NDIS_STATUS_PENDING;
+
+ //
+ // Lock the miniport. If the lock fails, then
+ // we must pend this open and try it later.
+ //
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // If we can grab the local lock then we can
+ // process this open now.
+ //
+ if (LocalLock)
+ {
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ //
+ // Unlock the miniport.
+ //
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ }
+ else
+ {
+ ObDereferenceObject( FileObject);
+ FREE_POOL( NewOpenP);
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ return;
+ }
+
+ //
+ // It is a mac
+ //
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("openadapter: adaptername=%s\n",TmpAdaptP->AdapterName.Buffer));
+ if (!ndisReferenceAdapter(TmpAdaptP))
+ {
+ //
+ // The adapter is closing.
+ //
+ ObDereferenceObject(FileObject);
+ FREE_POOL(NewOpenP);
+ *Status = NDIS_STATUS_CLOSING;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisOpenAdapter\n"));
+ return;
+ }
+
+ //
+ // Increment the protocol's reference count.
+ //
+ TmpProtP = (PNDIS_PROTOCOL_BLOCK)NdisProtocolHandle;
+ if (!ndisReferenceProtocol(TmpProtP))
+ {
+ //
+ // The protocol is closing.
+ //
+ ndisDereferenceAdapter(TmpAdaptP);
+ ObDereferenceObject(FileObject);
+ FREE_POOL(NewOpenP);
+ *Status = NDIS_STATUS_CLOSING;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisOpenAdapter\n"));
+ return;
+ }
+
+
+ //
+ // Set up the elements of the open structure.
+ //
+ INITIALIZE_SPIN_LOCK(&NewOpenP->SpinLock);
+ NewOpenP->Closing = FALSE;
+
+ NewOpenP->AdapterHandle = TmpAdaptP;
+ NewOpenP->ProtocolHandle = TmpProtP;
+
+ //
+ // for speed, instead of having to use AdapterHandle->MacHandle
+ //
+ NewOpenP->MacHandle = TmpAdaptP->MacHandle;
+
+ //
+ // for even more speed....
+ //
+ NewOpenP->SendHandler = TmpAdaptP->MacHandle->MacCharacteristics.SendHandler;
+ NewOpenP->TransferDataHandler = TmpAdaptP->MacHandle->MacCharacteristics.TransferDataHandler;
+ NewOpenP->ResetHandler = TmpAdaptP->MacHandle->MacCharacteristics.ResetHandler;
+ NewOpenP->RequestHandler = TmpAdaptP->MacHandle->MacCharacteristics.RequestHandler;
+
+ NewOpenP->SendCompleteHandler = TmpProtP->ProtocolCharacteristics.SendCompleteHandler;
+ NewOpenP->TransferDataCompleteHandler = TmpProtP->ProtocolCharacteristics.TransferDataCompleteHandler;
+ NewOpenP->SendPacketsHandler = ndisMSendPacketsToFullMac;
+
+ //
+ // Now we have to fake some stuff to get all indications to happen
+ // at DPC_LEVEL. What we do is start the pointer at an NDIS function
+ // which will guarantee that it occurs.
+ //
+ // Then, by extending the OPEN structure and adding the real handlers
+ // at the end we can use these for drivers compiled with this header.
+ //
+ NewOpenP->ProtocolBindingContext = ProtocolBindingContext;
+ NewOpenP->PostNt31ReceiveHandler = TmpProtP->ProtocolCharacteristics.ReceiveHandler;
+ NewOpenP->PostNt31ReceiveCompleteHandler = TmpProtP->ProtocolCharacteristics.ReceiveCompleteHandler;
+ NewOpenP->ReceiveHandler = ndisMacReceiveHandler;
+ NewOpenP->ReceiveCompleteHandler = ndisMacReceiveCompleteHandler;
+ NewOpenP->ReceivePacketHandler = NULL;
+
+ //
+ // Patch the open into the global list of macs
+ //
+ ACQUIRE_SPIN_LOCK(&ndisGlobalOpenListLock, &OldIrql);
+
+ NewOpenP->NextGlobalOpen = ndisGlobalOpenList;
+ ndisGlobalOpenList = NewOpenP;
+
+ RELEASE_SPIN_LOCK(&ndisGlobalOpenListLock, OldIrql);
+
+
+ //
+ // Save a pointer to the file object in the open...
+ //
+ NewOpenP->FileObject = FileObject;
+
+ //
+ // ...and a pointer to the open in the file object.
+ //
+ FileObject->FsContext = NewOpenP;
+
+
+ *NdisBindingHandle = (NDIS_HANDLE)NewOpenP;
+
+
+ //
+ // Call MacOpenAdapter, see what we shall see...
+ //
+ OpenStatus = (TmpAdaptP->MacHandle->MacCharacteristics.OpenAdapterHandler)(OpenErrorStatus,
+ &NewOpenP->MacBindingHandle,
+ SelectedMediumIndex,
+ MediumArray,
+ MediumArraySize,
+ (NDIS_HANDLE)NewOpenP,
+ TmpAdaptP->MacAdapterContext,
+ OpenOptions,
+ AddressingInformation);
+ if ((OpenStatus == NDIS_STATUS_SUCCESS) && NdisFinishOpen(NewOpenP))
+ {
+ *Status = NDIS_STATUS_SUCCESS;
+ }
+ else if (OpenStatus == NDIS_STATUS_PENDING)
+ {
+ *Status = NDIS_STATUS_PENDING;
+ }
+ else
+ {
+ PNDIS_OPEN_BLOCK *ppOpen;
+
+ //
+ // Something went wrong, clean up and exit.
+ //
+ ACQUIRE_SPIN_LOCK(&ndisGlobalOpenListLock, &OldIrql);
+
+ for (ppOpen = &ndisGlobalOpenList;
+ *ppOpen != NULL;
+ ppOpen = &(*ppOpen)->NextGlobalOpen)
+ {
+ if (*ppOpen == NewOpenP)
+ {
+ *ppOpen = NewOpenP->NextGlobalOpen;
+ break;
+ }
+ }
+
+ RELEASE_SPIN_LOCK(&ndisGlobalOpenListLock, OldIrql);
+
+ ObDereferenceObject(FileObject);
+ ndisDereferenceAdapter(TmpAdaptP);
+ ndisDereferenceProtocol(TmpProtP);
+ FREE_POOL(NewOpenP);
+ *Status = NDIS_STATUS_OPEN_FAILED;
+ }
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisOpenAdapter\n"));
+}
+
+VOID
+NdisCloseAdapter(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisBindingHandle
+ )
+/*++
+
+Routine Description:
+
+ Closes a connection between a protocol and an adapter (MAC).
+
+Arguments:
+
+ Status - Returns the final status.
+ NdisBindingHandle - The handle returned by NdisOpenAdapter.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_OPEN_BLOCK OpenP = ((PNDIS_OPEN_BLOCK)NdisBindingHandle);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisCloseAdapter\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("Protocol %wZ is closing Adapter %wZ\n",
+ &(OpenP->ProtocolHandle)->ProtocolCharacteristics.Name,
+ &(OpenP->AdapterHandle)->AdapterName));
+
+ IF_DBG(DBG_COMP_CONFIG, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(NdisBindingHandle))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("OpenAdapter: Null BindingHandle\n"));
+ DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(NdisBindingHandle))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("OpenAdapter: BindingHandle not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR);
+ }
+ }
+
+ //
+ // Is this a miniport?
+ //
+ if (OpenP->AdapterHandle->DeviceObject == NULL)
+ {
+ //
+ // This is a Miniport
+ // This returns TRUE if it finished synchronously.
+ //
+ if (ndisMKillOpen(OpenP))
+ {
+ *Status = NDIS_STATUS_SUCCESS;
+ }
+ else
+ {
+ *Status = NDIS_STATUS_PENDING; // will complete later
+ }
+
+ return;
+ }
+
+ //
+ // This returns TRUE if it finished synchronously.
+ //
+ if (ndisKillOpen(OpenP))
+ {
+ *Status = NDIS_STATUS_SUCCESS;
+ }
+ else
+ {
+ *Status = NDIS_STATUS_PENDING; // will complete later
+ }
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisCloseAdapter\n"));
+#undef OpenP
+}
+
+
+VOID
+NdisSetProtocolFilter(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN RECEIVE_HANDLER ReceiveHandler,
+ IN RECEIVE_PACKET_HANDLER ReceivePacketHandler,
+ IN NDIS_MEDIUM Medium,
+ IN UINT Offset,
+ IN UINT Size,
+ IN PUCHAR Pattern
+ )
+/*++
+
+Routine Description:
+
+ Sets a protocol filter.
+
+Arguments:
+
+ Status Returns the final status.
+ NdisProtocolHandle The handle returned by NdisRegisterProtocol.
+ ReceiveHandler This will be invoked instead of the default receivehandler
+ when the pattern match happens.
+ ReceivePacketHandler This will be invoked instead of the default receivepackethandler
+ when the pattern match happens.
+ Size Size of pattern
+ Pattern This must match
+
+Return Value:
+
+ None.
+
+Note:
+
+--*/
+{
+ PNDIS_PROTOCOL_BLOCK ProtP = ((PNDIS_OPEN_BLOCK)NdisBindingHandle)->ProtocolHandle;
+ PNDIS_PROTOCOL_FILTER PFilter;
+ KIRQL OldIrql;
+
+ PFilter = ALLOC_FROM_POOL(sizeof(NDIS_PROTOCOL_FILTER) + Size, NDIS_TAG_FILTER);
+ if (PFilter == NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ PFilter->ReceiveHandler = ReceiveHandler;
+ PFilter->ReceivePacketHandler = ReceivePacketHandler;
+ PFilter->Size = Size;
+ PFilter->Offset = Offset;
+ CopyMemory((PUCHAR)PFilter + sizeof(NDIS_PROTOCOL_FILTER),
+ Pattern,
+ Size);
+
+ if ((Medium < NdisMediumMax) && ndisReferenceProtocol(ProtP))
+ {
+ NDIS_ACQUIRE_SPIN_LOCK(&ProtP->Ref.SpinLock, &OldIrql);
+ PFilter->Next = ProtP->ProtocolFilter[Medium];
+ ProtP->ProtocolFilter[Medium] = PFilter;
+ if ((PFilter->Offset + PFilter->Size) > (USHORT)(ProtP->MaxPatternSize))
+ ProtP->MaxPatternSize = PFilter->Size;
+ NDIS_RELEASE_SPIN_LOCK(&ProtP->Ref.SpinLock, OldIrql);
+ *Status = NDIS_STATUS_SUCCESS;
+ }
+ else
+ {
+ *Status = NDIS_STATUS_CLOSING;
+ FREE_POOL(PFilter);
+ }
+}
+
+
+VOID
+NdisGetDriverHandle(
+ IN NDIS_HANDLE NdisBindingHandle,
+ OUT PNDIS_HANDLE NdisDriverHandle
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+ None.
+
+Note:
+
+--*/
+{
+ PNDIS_OPEN_BLOCK OpenBlock = (PNDIS_OPEN_BLOCK)NdisBindingHandle;
+
+ //
+ // Figure out if it is a miniport or a mac and return the ptr to the
+ // NDIS_M_DRIVER_BLOCK/NDIS_ADAPTER_BLOCK
+ //
+ if (OpenBlock->AdapterHandle->DeviceObject == NULL)
+ {
+ *NdisDriverHandle = ((PNDIS_M_OPEN_BLOCK)(OpenBlock->MacBindingHandle))->DriverHandle;
+ }
+ else
+ {
+ *NdisDriverHandle = OpenBlock->MacHandle;
+ }
+}
+
+
+VOID
+ndisDereferenceProtocol(
+ IN PNDIS_PROTOCOL_BLOCK ProtP
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+ None.
+
+Note:
+
+--*/
+{
+ if (NdisDereferenceRef(&(ProtP)->Ref))
+ {
+ KIRQL OldIrql;
+ PNDIS_PROTOCOL_BLOCK *ppProt;
+
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+
+ for (ppProt = &ndisProtocolList;
+ *ppProt != NULL;
+ ppProt = &(*ppProt)->NextProtocol)
+ {
+ if (*ppProt == ProtP)
+ {
+ *ppProt = ProtP->NextProtocol;
+ break;
+ }
+ }
+
+ ASSERT (*ppProt == ProtP->NextProtocol);
+
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ if (ProtP->DeregEvent != NULL)
+ SET_EVENT(ProtP->DeregEvent);
+ FREE_POOL(ProtP);
+
+ ProtocolDereferencePackage();
+ }
+}
+
+
+VOID
+ndisNotifyProtocols(
+ IN PNDIS_PROTOCOL_BLOCK pProt
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+ None.
+
+Note:
+
+--*/
+{
+ KIRQL OldIrql;
+ PNDIS_M_DRIVER_BLOCK MiniBlock, NextMiniBlock;
+ PNDIS_MAC_BLOCK MacBlock, NextMacBlock;
+
+ //
+ // Check again if reference is allowed i.e. if the protocol called NdisDeregisterProtocol
+ // before this thread had a chance to run.
+ //
+ if (!ndisReferenceProtocol(pProt))
+ {
+ return;
+ }
+
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+
+ // First walk the list of miniports
+ for (MiniBlock = ndisMiniDriverList;
+ MiniBlock != NULL;
+ MiniBlock = NextMiniBlock)
+ {
+ PNDIS_MINIPORT_BLOCK Miniport, NextMiniport;
+
+ NextMiniBlock = MiniBlock->NextDriver;
+ if (ndisReferenceDriver(MiniBlock))
+ {
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ NDIS_ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
+
+ for (Miniport = MiniBlock->MiniportQueue;
+ Miniport != NULL;
+ Miniport = NextMiniport)
+ {
+ NextMiniport = Miniport->NextMiniport;
+ if (ndisReferenceMiniport(Miniport))
+ {
+ NDIS_BIND_CONTEXT BindContext;
+ NDIS_STATUS BindStatus;
+
+ NDIS_RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
+
+ if (ndisCheckProtocolBinding(pProt,
+ &Miniport->MiniportName,
+ &Miniport->BaseName,
+ &BindContext.ProtocolSection))
+ {
+ ASSERT(CURRENT_IRQL < DISPATCH_LEVEL);
+ INITIALIZE_EVENT(&BindContext.Event);
+
+ WAIT_FOR_OBJECT(&pProt->Mutex, NULL);
+
+ if (!pProt->Ref.Closing)
+ {
+ (*pProt->ProtocolCharacteristics.BindAdapterHandler)(&BindStatus,
+ &BindContext,
+ &Miniport->MiniportName,
+ &BindContext.ProtocolSection,
+ NULL);
+ if (BindStatus == NDIS_STATUS_PENDING)
+ {
+ WAIT_FOR_OBJECT(&BindContext.Event, NULL);
+ }
+ }
+
+ RELEASE_MUTEX(&pProt->Mutex);
+
+ FREE_POOL(BindContext.ProtocolSection.Buffer);
+ }
+
+ NDIS_ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
+ NextMiniport = Miniport->NextMiniport;
+ ndisDereferenceMiniport(Miniport);
+ }
+ }
+
+ NDIS_RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
+
+ NextMiniBlock = MiniBlock->NextDriver;
+ ndisDereferenceDriver(MiniBlock);
+
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+ }
+ }
+
+ // And now the list of macs
+ for (MacBlock = ndisMacDriverList;
+ MacBlock != NULL;
+ MacBlock = NextMacBlock)
+ {
+ PNDIS_ADAPTER_BLOCK Adapter, NextAdapter;
+
+ NextMacBlock = MacBlock->NextMac;
+ if (ndisReferenceMac(MacBlock))
+ {
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ NDIS_ACQUIRE_SPIN_LOCK(&MacBlock->Ref.SpinLock, &OldIrql);
+
+ for (Adapter = MacBlock->AdapterQueue;
+ Adapter != NULL;
+ Adapter = NextAdapter)
+ {
+ NextAdapter = Adapter->NextAdapter;
+ if (ndisReferenceAdapter(Adapter))
+ {
+ NDIS_BIND_CONTEXT BindContext;
+ NDIS_STATUS BindStatus;
+
+ NDIS_RELEASE_SPIN_LOCK(&MacBlock->Ref.SpinLock, OldIrql);
+
+ if (ndisCheckProtocolBinding(pProt,
+ &Adapter->AdapterName,
+ &Adapter->BaseName,
+ &BindContext.ProtocolSection))
+ {
+ ASSERT(CURRENT_IRQL < DISPATCH_LEVEL);
+ INITIALIZE_EVENT(&BindContext.Event);
+ WAIT_FOR_OBJECT(&pProt->Mutex, NULL);
+
+ if (!pProt->Ref.Closing)
+ {
+ (*pProt->ProtocolCharacteristics.BindAdapterHandler)(&BindStatus,
+ &BindContext,
+ &Adapter->AdapterName,
+ &BindContext.ProtocolSection,
+ NULL);
+ if (BindStatus == NDIS_STATUS_PENDING)
+ {
+ WAIT_FOR_OBJECT(&BindContext.Event, NULL);
+ }
+ }
+
+ RELEASE_MUTEX(&pProt->Mutex);
+
+ FREE_POOL(BindContext.ProtocolSection.Buffer);
+ }
+
+ NDIS_ACQUIRE_SPIN_LOCK(&MacBlock->Ref.SpinLock, &OldIrql);
+ NextAdapter = Adapter->NextAdapter;
+ ndisDereferenceAdapter(Adapter);
+ }
+ }
+
+ NDIS_RELEASE_SPIN_LOCK(&MacBlock->Ref.SpinLock, OldIrql);
+
+ NextMacBlock = MacBlock->NextMac;
+ ndisDereferenceMac(MacBlock);
+
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+ }
+ }
+
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ //
+ // Dereference twice - one for reference by caller and one for reference at the beginning
+ // of this routine.
+ //
+ ndisDereferenceProtocol(pProt);
+ ndisDereferenceProtocol(pProt);
+}
+
+
+VOID
+NdisOpenProtocolConfiguration(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING ProtocolSection
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+ None.
+
+Note:
+
+--*/
+{
+ PNDIS_CONFIGURATION_HANDLE HandleToReturn;
+ PNDIS_WRAPPER_CONFIGURATION_HANDLE ConfigHandle;
+#define PQueryTable ConfigHandle->ParametersQueryTable
+
+ //
+ // Allocate the space for configuration handle
+ //
+
+ *Status = NdisAllocateMemory((PVOID*)&HandleToReturn,
+ sizeof(NDIS_CONFIGURATION_HANDLE) + sizeof(NDIS_WRAPPER_CONFIGURATION_HANDLE),
+ 0,
+ HighestAcceptableMax);
+
+ if (*Status != NDIS_STATUS_SUCCESS)
+ {
+ *ConfigurationHandle = (NDIS_HANDLE)NULL;
+ return;
+ }
+
+ ZeroMemory(HandleToReturn, sizeof(NDIS_CONFIGURATION_HANDLE) + sizeof(NDIS_WRAPPER_CONFIGURATION_HANDLE));
+
+ ConfigHandle = (PNDIS_WRAPPER_CONFIGURATION_HANDLE)((PUCHAR)HandleToReturn + sizeof(NDIS_CONFIGURATION_HANDLE));
+
+ HandleToReturn->KeyQueryTable = ConfigHandle->ParametersQueryTable;
+ HandleToReturn->ParameterList = NULL;
+
+ //
+ // 1.
+ // Call ndisSaveParameter for a parameter, which will allocate storage for it.
+ //
+ PQueryTable[0].QueryRoutine = ndisSaveParameters;
+ PQueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ PQueryTable[0].DefaultType = REG_NONE;
+ //
+ // PQueryTable[0].Name and PQueryTable[0].EntryContext
+ // are filled in inside ReadConfiguration, in preparation
+ // for the callback.
+ //
+ // PQueryTable[0].Name = KeywordBuffer;
+ // PQueryTable[0].EntryContext = ParameterValue;
+
+ //
+ // 2.
+ // Stop
+ //
+
+ PQueryTable[1].QueryRoutine = NULL;
+ PQueryTable[1].Flags = 0;
+ PQueryTable[1].Name = NULL;
+
+ //
+ // NOTE: Some fields in ParametersQueryTable[3] are used to store information for later retrieval.
+ //
+ PQueryTable[3].QueryRoutine = NULL;
+ PQueryTable[3].Name = ProtocolSection->Buffer;
+ PQueryTable[3].EntryContext = NULL;
+ PQueryTable[3].DefaultData = NULL;
+
+ *ConfigurationHandle = (NDIS_HANDLE)HandleToReturn;
+ *Status = NDIS_STATUS_SUCCESS;
+}
+
+BOOLEAN
+ndisQueueOpenOnProtocol(
+ IN PNDIS_OPEN_BLOCK OpenP,
+ IN PNDIS_PROTOCOL_BLOCK ProtP
+ )
+/*++
+
+Routine Description:
+
+ Attaches an open block to the list of opens for a protocol.
+
+Arguments:
+
+ OpenP - The open block to be queued.
+ ProtP - The protocol block to queue it to.
+
+Return Value:
+
+ TRUE if the operation is successful.
+ FALSE if the protocol is closing.
+
+--*/
+{
+ KIRQL OldIrql;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>ndisQueueOpenOnProtocol\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("Protocol: %wZ\n",&ProtP->ProtocolCharacteristics.Name));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ BOOLEAN f = FALSE;
+ if (DbgIsNull(OpenP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisQueueOpenOnProtocol: Null Open Block\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(OpenP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisQueueOpenOnProtocol: Open Block not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(ProtP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisQueueOpenOnProtocol: Null Protocol Block\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(ProtP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisQueueOpenOnProtocol: Protocol Block not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (f)
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ NDIS_ACQUIRE_SPIN_LOCK(&ProtP->Ref.SpinLock, &OldIrql);
+
+ //
+ // Make sure the protocol is not closing.
+ //
+
+ if (ProtP->Ref.Closing)
+ {
+ NDIS_RELEASE_SPIN_LOCK(&ProtP->Ref.SpinLock, OldIrql);
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==ndisQueueOpenOnProtocol\n"));
+ return FALSE;
+ }
+
+
+ //
+ // Attach this open at the head of the queue.
+ //
+
+ OpenP->ProtocolNextOpen = ProtP->OpenQueue;
+ ProtP->OpenQueue = OpenP;
+
+
+ NDIS_RELEASE_SPIN_LOCK(&ProtP->Ref.SpinLock, OldIrql);
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==ndisQueueOpenOnProtocol\n"));
+ return TRUE;
+}
+
+
+VOID
+ndisDeQueueOpenOnProtocol(
+ IN PNDIS_OPEN_BLOCK OpenP,
+ IN PNDIS_PROTOCOL_BLOCK ProtP
+ )
+/*++
+
+Routine Description:
+
+ Detaches an open block from the list of opens for a protocol.
+
+Arguments:
+
+ OpenP - The open block to be dequeued.
+ ProtP - The protocol block to dequeue it from.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ KIRQL OldIrql;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>ndisDeQueueOpenOnProtocol\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("Protocol: %wZ\n",&ProtP->ProtocolCharacteristics.Name));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ BOOLEAN f = FALSE;
+ if (DbgIsNull(OpenP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisDeQueueOpenOnProtocol: Null Open Block\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(OpenP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisDeQueueOpenOnProtocol: Open Block not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(ProtP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisDeQueueOpenOnProtocol: Null Protocol Block\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(ProtP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisDeQueueOpenOnProtocol: Protocol Block not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (f)
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+
+ NDIS_ACQUIRE_SPIN_LOCK(&ProtP->Ref.SpinLock, &OldIrql);
+
+ //
+ // Find the open on the queue, and remove it.
+ //
+
+ if (ProtP->OpenQueue == OpenP)
+ {
+ ProtP->OpenQueue = OpenP->ProtocolNextOpen;
+ }
+ else
+ {
+ PNDIS_OPEN_BLOCK PP = ProtP->OpenQueue;
+
+ while (PP->ProtocolNextOpen != OpenP)
+ {
+ PP = PP->ProtocolNextOpen;
+ }
+
+ PP->ProtocolNextOpen = PP->ProtocolNextOpen->ProtocolNextOpen;
+ }
+
+ NDIS_RELEASE_SPIN_LOCK(&ProtP->Ref.SpinLock, OldIrql);
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==ndisDeQueueOpenOnProtocol\n"));
+}
+
+
+#define MAX_EVENT_LOG_DATA_SIZE ((ERROR_LOG_MAXIMUM_SIZE - sizeof(IO_ERROR_LOG_PACKET) + sizeof(ULONG)) & ~3)
+
+NDIS_STATUS
+NdisWriteEventLogEntry(
+ IN PVOID LogHandle,
+ IN ULONG EventCode,
+ IN ULONG UniqueEventValue,
+ IN USHORT NumStrings,
+ IN PVOID StringsList OPTIONAL,
+ IN ULONG DataSize,
+ IN PVOID Data OPTIONAL
+ )
+/*++
+
+Routine Description:
+
+ This function allocates an I/O error log record, fills it in and writes it
+ to the I/O error log on behalf of a NDIS Protocol.
+
+
+Arguments:
+
+ LogHandle - Pointer to the driver object logging this event.
+
+ EventCode - Identifies the error message.
+
+ UniqueEventValue - Identifies this instance of a given error message.
+
+ NumStrings - Number of unicode strings in strings list.
+
+ DataSize - Number of bytes of data.
+
+ Strings - Array of pointers to unicode strings (PWCHAR).
+
+ Data - Binary dump data for this message, each piece being
+ aligned on word boundaries.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS - The error was successfully logged.
+ NDIS_STATUS_BUFFER_TOO_SHORT - The error data was too large to be logged.
+ NDIS_STATUS_RESOURCES - Unable to allocate memory.
+
+Notes:
+
+ This code is paged and may not be called at raised IRQL.
+
+--*/
+{
+ PIO_ERROR_LOG_PACKET ErrorLogEntry;
+ ULONG PaddedDataSize;
+ ULONG PacketSize;
+ ULONG TotalStringsSize = 0;
+ USHORT i;
+ PWCHAR *Strings;
+ PWCHAR Tmp;
+
+ Strings = (PWCHAR *)StringsList;
+
+ //
+ // Sum up the length of the strings
+ //
+ for (i = 0; i < NumStrings; i++)
+ {
+ PWCHAR currentString;
+ ULONG stringSize;
+
+ stringSize = sizeof(UNICODE_NULL);
+ currentString = Strings[i];
+
+ while (*currentString++ != UNICODE_NULL)
+ {
+ stringSize += sizeof(WCHAR);
+ }
+
+ TotalStringsSize += stringSize;
+ }
+
+ if (DataSize % sizeof(ULONG))
+ {
+ PaddedDataSize = DataSize + (sizeof(ULONG) - (DataSize % sizeof(ULONG)));
+ }
+ else
+ {
+ PaddedDataSize = DataSize;
+ }
+
+ PacketSize = TotalStringsSize + PaddedDataSize;
+
+ if (PacketSize > MAX_EVENT_LOG_DATA_SIZE)
+ {
+ return (NDIS_STATUS_BUFFER_TOO_SHORT); // Too much error data
+ }
+
+ //
+ // Now add in the size of the log packet, but subtract 4 from the data
+ // since the packet struct contains a ULONG for data.
+ //
+ if (PacketSize > sizeof(ULONG))
+ {
+ PacketSize += sizeof(IO_ERROR_LOG_PACKET) - sizeof(ULONG);
+ }
+ else
+ {
+ PacketSize += sizeof(IO_ERROR_LOG_PACKET);
+ }
+
+ ASSERT(PacketSize <= ERROR_LOG_MAXIMUM_SIZE);
+
+ ErrorLogEntry = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry((PDRIVER_OBJECT)LogHandle,
+ (UCHAR) PacketSize);
+
+ if (ErrorLogEntry == NULL)
+ {
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ //
+ // Fill in the necessary log packet fields.
+ //
+ ErrorLogEntry->UniqueErrorValue = UniqueEventValue;
+ ErrorLogEntry->ErrorCode = EventCode;
+ ErrorLogEntry->NumberOfStrings = NumStrings;
+ ErrorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET) +
+ PaddedDataSize - sizeof(ULONG);
+ ErrorLogEntry->DumpDataSize = (USHORT) PaddedDataSize;
+
+ //
+ // Copy the Dump Data to the packet
+ //
+ if (DataSize > 0)
+ {
+ RtlMoveMemory((PVOID) ErrorLogEntry->DumpData,
+ Data,
+ DataSize);
+ }
+
+ //
+ // Copy the strings to the packet.
+ //
+ Tmp = (PWCHAR)((PUCHAR)ErrorLogEntry + ErrorLogEntry->StringOffset + PaddedDataSize);
+
+ for (i = 0; i < NumStrings; i++)
+ {
+ PWCHAR wchPtr = Strings[i];
+
+ while( (*Tmp++ = *wchPtr++) != UNICODE_NULL)
+ NOTHING;
+ }
+
+ IoWriteErrorLogEntry(ErrorLogEntry);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
diff --git a/private/ntos/ndis/ndis40/protos.h b/private/ntos/ndis/ndis40/protos.h
new file mode 100644
index 000000000..dd8f0623c
--- /dev/null
+++ b/private/ntos/ndis/ndis40/protos.h
@@ -0,0 +1,1991 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ protos.h
+
+Abstract:
+
+ NDIS wrapper function prototypes
+
+Author:
+
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ Jun-95 Jameel Hyder Split up from a monolithic file
+--*/
+
+NTSTATUS
+ndisDispatchRequest(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ );
+
+NTSTATUS
+ndisHandlePnPRequest(
+ IN PIRP pIrp
+ );
+
+NTSTATUS
+ndisHandleLoadDriver(
+ IN PUNICODE_STRING pDevice
+ );
+
+NTSTATUS
+ndisHandleUnloadDriver(
+ IN PUNICODE_STRING pDevice
+ );
+
+NTSTATUS
+ndisHandleTranslateName(
+ IN PUNICODE_STRING pDevice,
+ IN PUCHAR Buffer,
+ IN UINT BufferLength,
+ OUT PUINT AmountCopied
+
+ );
+
+NTSTATUS
+ndisHandleLegacyTransport(
+ IN PUNICODE_STRING pDevice
+ );
+
+NTSTATUS
+ndisHandleProtocolNotification(
+ IN PUNICODE_STRING pDevice
+ );
+
+VOID
+ndisReferenceAdapterOrMiniportByName(
+ IN PUNICODE_STRING pDevice,
+ OUT PNDIS_MINIPORT_BLOCK * pMiniport,
+ OUT PNDIS_ADAPTER_BLOCK * pAdapter
+ );
+
+BOOLEAN
+ndisMIsr(
+ IN PKINTERRUPT KInterrupt,
+ IN PVOID Context
+ );
+
+VOID
+ndisMDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+VOID
+ndisMDpcTimer(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+VOID
+ndisMCoDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+VOID
+ndisMCoDpcTimer(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+VOID
+ndisMCoTimerDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+VOID
+ndisMWakeUpDpc(
+ IN PKDPC Dpc,
+ IN PVOID Context,
+ IN PVOID SystemContext1,
+ IN PVOID SystemContext2
+ );
+
+VOID
+ndisMDeferredTimerDpc(
+ IN PKDPC Dpc,
+ IN PVOID Context,
+ IN PVOID SystemContext1,
+ IN PVOID SystemContext2
+ );
+
+NDIS_STATUS
+ndisMChangeEthAddresses(
+ IN UINT OldAddressCount,
+ IN CHAR OldAddresses[][6],
+ IN UINT NewAddressCount,
+ IN CHAR NewAddresses[][6],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+NDIS_STATUS
+ndisMChangeClass(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+VOID
+ndisMCloseAction(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+NDIS_STATUS
+ndisMResetFullDuplex(
+ IN NDIS_HANDLE NdisBindingHandle
+ );
+
+NDIS_STATUS
+ndisMReset(
+ IN NDIS_HANDLE NdisBindingHandle
+ );
+
+NDIS_STATUS
+ndisMRequest(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+#if _SEND_PRIORITY
+
+VOID
+FASTCALL
+ndisMProcessDeferredFullDuplexPrioritySends(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+VOID
+FASTCALL
+ndisMProcessDeferredPrioritySends(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+#endif
+
+VOID
+FASTCALL
+ndisMProcessDeferredFullDuplex(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+VOID
+FASTCALL
+ndisMProcessDeferred(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+NDIS_STATUS
+ndisMTransferData(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+NDIS_STATUS
+ndisMTransferDataSync(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+NDIS_STATUS
+ndisMDummyTransferData(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+VOID
+ndisMLazyReturnPackets(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+VOID
+ndisMIndicatePacket(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ );
+
+//
+// general reference/dereference functions
+//
+
+BOOLEAN
+NdisReferenceRef(
+ IN PREFERENCE RefP
+ );
+
+
+BOOLEAN
+NdisDereferenceRef(
+ IN PREFERENCE RefP
+ );
+
+
+VOID
+NdisInitializeRef(
+ IN PREFERENCE RefP
+ );
+
+
+BOOLEAN
+NdisCloseRef(
+ IN PREFERENCE RefP
+ );
+
+
+/*++
+BOOLEAN
+ndisReferenceProtocol(
+ IN PNDIS_PROTOCOL_BLOCK ProtP
+ );
+--*/
+
+#define ndisReferenceProtocol(ProtP) NdisReferenceRef(&(ProtP)->Ref)
+
+
+VOID
+ndisDereferenceProtocol(
+ IN PNDIS_PROTOCOL_BLOCK ProtP
+ );
+
+
+VOID
+ndisDeQueueOpenOnProtocol(
+ IN PNDIS_OPEN_BLOCK OpenP,
+ IN PNDIS_PROTOCOL_BLOCK ProtP
+ );
+
+
+BOOLEAN
+NdisFinishOpen(
+ IN PNDIS_OPEN_BLOCK OpenP
+ );
+
+
+VOID
+ndisKillOpenAndNotifyProtocol(
+ IN PNDIS_OPEN_BLOCK OldOpenP
+ );
+
+
+BOOLEAN
+ndisKillOpen(
+ IN PNDIS_OPEN_BLOCK OldOpenP
+ );
+
+/*++
+BOOLEAN
+ndisReferenceMac(
+ IN PNDIS_MAC_BLOCK MacP
+ );
+--*/
+#define ndisReferenceMac(MacP) NdisReferenceRef(&(MacP)->Ref)
+
+VOID
+ndisDereferenceMac(
+ IN PNDIS_MAC_BLOCK MacP
+ );
+
+BOOLEAN
+ndisQueueAdapterOnMac(
+ IN PNDIS_ADAPTER_BLOCK AdaptP,
+ IN PNDIS_MAC_BLOCK MacP
+ );
+
+VOID
+ndisDeQueueAdapterOnMac(
+ IN PNDIS_ADAPTER_BLOCK AdaptP,
+ IN PNDIS_MAC_BLOCK MacP
+ );
+
+/*++
+BOOLEAN
+ndisReferenceAdapter(
+ IN PNDIS_ADAPTER_BLOCK AdaptP
+ );
+--*/
+#define ndisReferenceAdapter(AdaptP) NdisReferenceRef(&(AdaptP)->Ref)
+
+
+BOOLEAN
+ndisQueueOpenOnAdapter(
+ IN PNDIS_OPEN_BLOCK OpenP,
+ IN PNDIS_ADAPTER_BLOCK AdaptP
+ );
+
+VOID
+ndisKillAdapter(
+ IN PNDIS_ADAPTER_BLOCK OldAdaptP
+ );
+
+VOID
+ndisDereferenceAdapter(
+ IN PNDIS_ADAPTER_BLOCK AdaptP
+ );
+
+VOID
+ndisDeQueueOpenOnAdapter(
+ IN PNDIS_OPEN_BLOCK OpenP,
+ IN PNDIS_ADAPTER_BLOCK AdaptP
+ );
+
+BOOLEAN
+ndisCheckPortUsage(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG PortNumber,
+ IN ULONG Length,
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+BOOLEAN
+ndisCheckMemoryUsage(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG Address,
+ IN ULONG Length,
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+NTSTATUS
+ndisStartMapping(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG InitialAddress,
+ IN ULONG Length,
+ OUT PVOID * InitialMapping,
+ OUT PBOOLEAN Mapped
+ );
+
+NTSTATUS
+ndisEndMapping(
+ IN PVOID InitialMapping,
+ IN ULONG Length,
+ IN BOOLEAN Mapped
+ );
+
+NDIS_STATUS
+ndisInitializeAdapter(
+ IN PNDIS_M_DRIVER_BLOCK pMiniBlock,
+ IN PUNICODE_STRING RegServiceName // Relative to Services key
+ );
+
+NDIS_STATUS
+ndisCheckIfPcmciaCardPresent(
+ IN PNDIS_M_DRIVER_BLOCK pMiniBlock
+ );
+
+NDIS_STATUS
+ndisFixBusInformation(
+ IN PNDIS_CONFIGURATION_HANDLE ConfigHandle,
+ IN PBUS_SLOT_DB pDb
+ );
+
+VOID
+ndisAddBusInformation(
+ IN PNDIS_CONFIGURATION_HANDLE ConfigHandle,
+ IN PBUS_SLOT_DB pDb
+ );
+
+BOOLEAN
+ndisSearchGlobalDb(
+ IN NDIS_INTERFACE_TYPE BusType,
+ IN ULONG BusId,
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber
+ );
+
+BOOLEAN
+ndisAddGlobalDb(
+ IN NDIS_INTERFACE_TYPE BusType,
+ IN ULONG BusId,
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber
+ );
+
+BOOLEAN
+ndisDeleteGlobalDb(
+ IN NDIS_INTERFACE_TYPE BusType,
+ IN ULONG BusId,
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber
+ );
+
+NTSTATUS
+ndisValidatePcmciaDriver(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+VOID
+ndisQueuedBindNotification(
+ IN PQUEUED_PROTOCOL_NOTIFICATION pQPN
+ );
+
+NDIS_STATUS
+NdisIMInitializeDeviceInstance(
+ IN NDIS_HANDLE DriverHandle,
+ IN PNDIS_STRING DeviceInstance
+ );
+
+NDIS_STATUS
+NdisIMRegisterLayeredMiniport(
+ IN NDIS_HANDLE NdisWrapperHandle,
+ IN PNDIS_MINIPORT_CHARACTERISTICS MiniportCharacteristics,
+ IN UINT CharacteristicsLength,
+ OUT PNDIS_HANDLE DriverHandle
+ );
+
+NDIS_STATUS
+ndisMInitializeAdapter(
+ IN PNDIS_M_DRIVER_BLOCK pMiniDriver,
+ IN PNDIS_WRAPPER_CONFIGURATION_HANDLE pConfigurationHandle,
+ IN PUNICODE_STRING pExportName,
+ IN PBUS_SLOT_DB pDb
+ );
+
+VOID
+ndisInitializeBindings(
+ IN PUNICODE_STRING ExportName,
+ IN PUNICODE_STRING ServiceName,
+ IN BOOLEAN Synchronous
+ );
+
+VOID
+ndisQueuedProtocolNotification(
+ IN PNDIS_BIND_CONTEXT pContext
+ );
+
+NDIS_STATUS
+ndisUpdateDriverInstance(
+ IN PUNICODE_STRING BaseString,
+ IN PUNICODE_STRING BindString,
+ IN PUNICODE_STRING ExportString,
+ IN PUNICODE_STRING RouteString
+ );
+
+BOOLEAN
+ndisCheckProtocolBinding(
+ IN PNDIS_PROTOCOL_BLOCK Protocol,
+ IN PUNICODE_STRING DeviceName,
+ IN PUNICODE_STRING BaseName,
+ OUT PUNICODE_STRING ProtocolSection
+ );
+
+BOOLEAN
+ndisProtocolAlreadyBound(
+ IN PNDIS_PROTOCOL_BLOCK Protocol,
+ IN PUNICODE_STRING AdapterName
+ );
+
+NDIS_STATUS
+ndisUnloadMiniport(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+NDIS_STATUS
+ndisTranslateMiniportName(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PUCHAR Buffer,
+ IN UINT BufferLength,
+ OUT PUINT AmountCopied
+ );
+
+NDIS_STATUS
+ndisUnloadMac(
+ IN PNDIS_ADAPTER_BLOCK Mac
+ );
+
+NDIS_STATUS
+ndisTranslateMacName(
+ IN PNDIS_ADAPTER_BLOCK Mac,
+ IN PUCHAR Buffer,
+ IN UINT BufferLength,
+ OUT PUINT AmountCopied
+ );
+
+VOID
+ndisNotifyProtocols(
+ IN PNDIS_PROTOCOL_BLOCK pProt
+ );
+
+NDIS_STATUS
+ndisInitializeAllAdapterInstances(
+ IN PNDIS_MAC_BLOCK MacBlock,
+ IN PNDIS_STRING DeviceInstance OPTIONAL
+ );
+
+/*++
+BOOLEAN
+ndisReferenceDriver(
+ IN PNDIS_M_DRIVER_BLOCK DriverP
+ );
+--*/
+#define ndisReferenceDriver(DriverP) NdisReferenceRef(&(DriverP)->Ref)
+
+
+VOID
+ndisDereferenceDriver(
+ IN PNDIS_M_DRIVER_BLOCK DriverP
+ );
+
+BOOLEAN
+ndisQueueMiniportOnDriver(
+ IN PNDIS_MINIPORT_BLOCK MiniportP,
+ IN PNDIS_M_DRIVER_BLOCK DriverP
+ );
+
+VOID
+ndisDequeueMiniportOnDriver(
+ IN PNDIS_MINIPORT_BLOCK MiniportP,
+ IN PNDIS_M_DRIVER_BLOCK DriverP
+ );
+
+/*++
+BOOLEAN
+ndisReferenceMiniport(
+ IN PNDIS_MINIPORT_BLOCK MiniportP
+ );
+--*/
+#define ndisReferenceMiniport(MiniportP) NdisReferenceRef(&(MiniportP)->Ref)
+
+VOID
+ndisDereferenceMiniport(
+ IN PNDIS_MINIPORT_BLOCK MiniportP
+ );
+
+VOID
+ndisDeQueueOpenOnMiniport(
+ IN PNDIS_M_OPEN_BLOCK OpenP,
+ IN PNDIS_MINIPORT_BLOCK MiniportP
+ );
+
+VOID
+ndisInitializePackage(
+ IN PPKG_REF pPkg,
+ IN PVOID RoutineName
+ );
+
+VOID
+ndisReferencePackage(
+ IN PPKG_REF pPkg
+ );
+
+VOID
+ndisDereferencePackage(
+ IN PPKG_REF pPkg
+ );
+
+#define ProtocolInitializePackage() ndisInitializePackage(&ProtocolPkg, NdisRegisterProtocol)
+#define MiniportInitializePackage() ndisInitializePackage(&MiniportPkg, ndisMReset)
+#define InitInitializePackage() ndisInitializePackage(&InitPkg, NdisReadConfiguration)
+#define PnPInitializePackage() ndisInitializePackage(&PnPPkg, ndisDispatchRequest)
+#define MacInitializePackage() ndisInitializePackage(&MacPkg, ndisIsr)
+#define CoInitializePackage() ndisInitializePackage(&CoPkg, NdisCmRegisterAddressFamily)
+#define EthInitializePackage() ndisInitializePackage(&EthPkg, EthCreateFilter)
+#define FddiInitializePackage() ndisInitializePackage(&FddiPkg, FddiCreateFilter)
+#define TrInitializePackage() ndisInitializePackage(&TrPkg, TrCreateFilter)
+#define ArcInitializePackage() ndisInitializePackage(&ArcPkg, ArcCreateFilter)
+
+#define ProtocolReferencePackage() ndisReferencePackage(&ProtocolPkg)
+#define MiniportReferencePackage() ndisReferencePackage(&MiniportPkg)
+#define InitReferencePackage() ndisReferencePackage(&InitPkg)
+#define PnPReferencePackage() ndisReferencePackage(&PnPPkg)
+#define MacReferencePackage() ndisReferencePackage(&MacPkg)
+#define CoReferencePackage() ndisReferencePackage(&CoPkg)
+#define EthReferencePackage() ndisReferencePackage(&EthPkg)
+#define FddiReferencePackage() ndisReferencePackage(&FddiPkg)
+#define TrReferencePackage() ndisReferencePackage(&TrPkg)
+#define ArcReferencePackage() ndisReferencePackage(&ArcPkg)
+
+#define ProtocolDereferencePackage() ndisDereferencePackage(&ProtocolPkg)
+#define MiniportDereferencePackage() ndisDereferencePackage(&MiniportPkg)
+#define InitDereferencePackage() ndisDereferencePackage(&InitPkg)
+#define PnPDereferencePackage() ndisDereferencePackage(&PnPPkg)
+#define MacDereferencePackage() ndisDereferencePackage(&MacPkg)
+#define CoDereferencePackage() ndisDereferencePackage(&CoPkg)
+#define EthDereferencePackage() ndisDereferencePackage(&EthPkg)
+#define FddiDereferencePackage() ndisDereferencePackage(&FddiPkg)
+#define TrDereferencePackage() ndisDereferencePackage(&TrPkg)
+#define ArcDereferencePackage() ndisDereferencePackage(&ArcPkg)
+
+//
+// IRP handlers established on behalf of NDIS devices by
+// the wrapper.
+//
+
+NTSTATUS
+ndisCreateIrpHandler(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+ndisDeviceControlIrpHandler(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+ndisCloseIrpHandler(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+ndisSuccessIrpHandler(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+ndisLastCountRemovedFunction(
+ IN struct _KDPC * Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+
+BOOLEAN
+ndisQueueOpenOnProtocol(
+ IN PNDIS_OPEN_BLOCK OpenP,
+ IN PNDIS_PROTOCOL_BLOCK ProtP
+ );
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+VOID
+ndisReadRegistry(
+ VOID
+ );
+
+NTSTATUS
+ndisReadParameters(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+ndisAddMediaTypeToArray(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NDIS_STATUS
+ndisMacReceiveHandler(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+VOID
+ndisMacReceiveCompleteHandler(
+ IN NDIS_HANDLE NdisBindingContext
+ );
+
+PNDIS_OPEN_BLOCK
+ndisGetOpenBlockFromProtocolBindingContext(
+ IN NDIS_HANDLE ProtocolBindingContext
+ );
+
+NTSTATUS
+ndisShutdown(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+ndisUnload(
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+BOOLEAN
+ndisIsr(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID Context
+ );
+
+VOID
+ndisDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+//
+// Dma operations
+//
+
+extern
+IO_ALLOCATION_ACTION
+ndisDmaExecutionRoutine(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ );
+
+
+//
+// Map Registers
+//
+
+extern
+IO_ALLOCATION_ACTION
+ndisAllocationExecutionRoutine(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ );
+
+NDIS_STATUS
+ndisMProcessResetRequested(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ OUT PBOOLEAN pAddressingReset
+ );
+
+
+#undef NdisMResetComplete
+
+EXPORT
+VOID
+NdisMResetComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_STATUS Status,
+ IN BOOLEAN AddressingReset
+ );
+
+VOID
+ndisMResetCompleteFullDuplex(
+ IN NDIS_HANDLE Miniport,
+ IN NDIS_STATUS Status,
+ IN BOOLEAN AddressingReset
+ );
+
+VOID
+ndisMResetCompleteCommonStep1(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_STATUS Status,
+ IN BOOLEAN AddressingReset
+ );
+
+VOID
+ndisMResetCompleteCommonStep2(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+
+
+NDIS_STATUS
+ndisMWanSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE NdisLinkHandle,
+ IN PVOID Packet
+ );
+
+VOID
+NdisMWanSendComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ );
+
+extern
+NTSTATUS
+ndisSaveParameters(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+extern
+NTSTATUS
+ndisSaveLinkage(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+extern
+NTSTATUS
+ndisCheckRoute(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+VOID
+ndisMHaltMiniport(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+NDIS_STATUS
+ndisMAllocateRequest(
+ OUT PNDIS_REQUEST * pRequest,
+ IN NDIS_REQUEST_TYPE RequestType,
+ IN NDIS_OID Oid,
+ IN PVOID Buffer,
+ IN ULONG BufferLength
+ );
+
+NDIS_STATUS
+ndisMFilterOutStatisticsOids(
+ PNDIS_MINIPORT_BLOCK Miniport,
+ PNDIS_REQUEST Request
+ );
+
+// VOID
+// ndisMFreeInternalRequest(
+// PVOID PRequest
+// )
+#define ndisMFreeInternalRequest(_pRequest) FREE_POOL(_pRequest)
+
+//
+// Some Wan functions that crept in because
+// the send/receive paths for WAN drivers is different
+//
+
+VOID
+NdisMWanIndicateReceive(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE NdisLinkContext,
+ IN PUCHAR Packet,
+ IN ULONG PacketSize
+ );
+
+VOID
+NdisMWanIndicateReceiveComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE NdisLinkContext
+ );
+
+VOID
+ndisMTimerDpc(
+ IN PKDPC Dpc,
+ IN PVOID Context,
+ IN PVOID SystemContext1,
+ IN PVOID SystemContext2
+ );
+
+VOID
+ndisMAbortPacketsAndRequests(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+VOID
+ndisMAbortQueryStatisticsRequest(
+ IN PNDIS_REQUEST Request,
+ IN NDIS_STATUS Status
+ );
+
+BOOLEAN
+FASTCALL
+ndisMIndicateLoopback(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+BOOLEAN
+FASTCALL
+ndisMIsLoopbackPacket(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_PACKET Packet
+ );
+
+VOID
+ndisMDoRequests(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+VOID
+ndisMCopyFromPacketToBuffer(
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ IN UINT BytesToCopy,
+ OUT PCHAR Buffer,
+ OUT PUINT BytesCopied
+ );
+
+NTSTATUS
+ndisMShutdown(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+ndisMUnload(
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+NTSTATUS
+ndisMQueryOidList(
+ IN PNDIS_USER_OPEN_CONTEXT OpenContext,
+ IN PIRP Irp
+ );
+
+NDIS_STATUS
+ndisSplitStatisticsOids(
+ IN PNDIS_USER_OPEN_CONTEXT OpenContext,
+ IN PNDIS_OID OidList,
+ IN ULONG NumOids
+ );
+
+BOOLEAN
+ndisValidOid(
+ IN PNDIS_USER_OPEN_CONTEXT OpenContext,
+ IN NDIS_OID Oid
+ );
+
+VOID
+ndisQueuedCompleteOpenAdapter(
+ IN PQUEUED_OPEN_CLOSE pQoC
+ );
+
+VOID
+ndisQueuedCompleteCloseAdapter(
+ IN PQUEUED_OPEN_CLOSE pQoC
+ );
+
+VOID
+ndisMFinishClose(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_M_OPEN_BLOCK Open
+ );
+
+BOOLEAN
+ndisMKillOpen(
+ IN PNDIS_OPEN_BLOCK OldOpenP
+ );
+
+NTSTATUS
+ndisQueryOidList(
+ IN PNDIS_USER_OPEN_CONTEXT OpenContext,
+ IN PIRP Irp
+ );
+
+VOID
+ndisBugcheckHandler(
+ IN PNDIS_WRAPPER_CONTEXT WrapperContext,
+ IN ULONG Size
+ );
+
+
+VOID
+ndisMUndoBogusFilters(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+LONG
+ndisMDoMiniportOp(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN BOOLEAN Query,
+ IN ULONG Oid,
+ IN PVOID Buf,
+ IN LONG BufSize,
+ IN LONG ErrorCodesToReturn
+ );
+
+VOID
+ndisMOpenAdapter(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PNDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE NdisProtocolHandle,
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_STRING AdapterName,
+ IN UINT OpenOptions,
+ IN PSTRING AddressingInformation,
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_OPEN_BLOCK NewOpenP,
+ IN PFILE_OBJECT FileObject,
+ IN BOOLEAN UsingEncapsulation
+ );
+
+NDIS_STATUS
+ndisMFinishPendingOpen(
+ PMINIPORT_PENDING_OPEN MiniportPendingOpen
+ );
+
+VOID
+ndisMFinishQueuedPendingOpen(
+ IN PMINIPORT_PENDING_OPEN MiniportPendingOpen
+ );
+
+VOID
+ndisMResetCleanup(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN BOOLEAN Synchronous
+ );
+
+VOID
+ndisMSyncQueryInformationComplete(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+ndisMSyncSetInformationComplete(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+ndisMRequestQueryInformationPost(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+ndisMRequestSetInformationPost(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request,
+ IN NDIS_STATUS Status
+ );
+
+
+VOID
+ndisMQueueRequest(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request,
+ IN PNDIS_M_OPEN_BLOCK Open
+ );
+
+VOID
+ndisMRestoreFilterSettings(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_M_OPEN_BLOCK Open
+ );
+
+NDIS_STATUS
+ndisMSetPacketFilter(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ );
+
+NDIS_STATUS
+ndisMSetCurrentLookahead(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ );
+
+NDIS_STATUS
+ndisMSetMulticastList(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ );
+
+//
+// EthFilterxxx
+//
+BOOLEAN
+EthFindMulticast(
+ IN UINT NumberOfAddresses,
+ IN CHAR AddressArray[][ETH_LENGTH_OF_ADDRESS],
+ IN CHAR MulticastAddress[ETH_LENGTH_OF_ADDRESS],
+ OUT PUINT ArrayIndex
+ );
+
+VOID
+ethUndoFilterAdjust(
+ IN PETH_FILTER Filter,
+ IN PETH_BINDING_INFO Binding
+ );
+
+VOID
+ethUndoChangeFilterAddresses(
+ IN PETH_FILTER Filter
+ );
+
+VOID
+ethRemoveBindingFromLists(
+ IN PETH_FILTER Filter,
+ IN PETH_BINDING_INFO Binding
+ );
+
+VOID
+ethRemoveAndFreeBinding(
+ IN PETH_FILTER Filter,
+ IN PETH_BINDING_INFO Binding,
+ IN BOOLEAN fCallCloseAction
+ );
+
+VOID
+ethUpdateDirectedBindingList(
+ IN OUT PETH_FILTER Filter,
+ IN PETH_BINDING_INFO Binding,
+ IN BOOLEAN fAddBindingToList
+ );
+
+VOID
+ethUpdateBroadcastBindingList(
+ IN OUT PETH_FILTER Filter,
+ IN PETH_BINDING_INFO Binding,
+ IN BOOLEAN fAddToList
+ );
+
+VOID
+ethUpdateSpecificBindingLists(
+ IN OUT PETH_FILTER Filter,
+ IN PETH_BINDING_INFO Binding
+ );
+
+VOID
+EthFilterDprIndicateReceiveFullMac(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PCHAR Address,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+);
+
+VOID
+EthFilterDprIndicateReceiveCompleteFullMac(
+ IN PETH_FILTER Filter
+ );
+
+//
+// FddiFilterxxxx
+//
+
+VOID
+fddiRemoveBindingFromLists(
+ IN PFDDI_FILTER Filter,
+ IN PFDDI_BINDING_INFO Binding
+ );
+
+VOID
+fddiRemoveAndFreeBinding(
+ IN PFDDI_FILTER Filter,
+ IN PFDDI_BINDING_INFO Binding,
+ IN BOOLEAN fCallCloseAction
+ );
+
+BOOLEAN
+FddiFindMulticastLongAddress(
+ IN UINT NumberOfAddresses,
+ IN CHAR AddressArray[][FDDI_LENGTH_OF_LONG_ADDRESS],
+ IN CHAR MulticastAddress[FDDI_LENGTH_OF_LONG_ADDRESS],
+ OUT PUINT ArrayIndex
+ );
+
+BOOLEAN
+FddiFindMulticastShortAddress(
+ IN UINT NumberOfAddresses,
+ IN CHAR AddressArray[][FDDI_LENGTH_OF_SHORT_ADDRESS],
+ IN CHAR MulticastAddress[FDDI_LENGTH_OF_SHORT_ADDRESS],
+ OUT PUINT ArrayIndex
+ );
+
+NDIS_STATUS
+ndisMChangeFddiAddresses(
+ IN UINT oldLongAddressCount,
+ IN CHAR oldLongAddresses[][6],
+ IN UINT newLongAddressCount,
+ IN CHAR newLongAddresses[][6],
+ IN UINT oldShortAddressCount,
+ IN CHAR oldShortAddresses[][2],
+ IN UINT newShortAddressCount,
+ IN CHAR newShortAddresses[][2],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+VOID
+fddiUpdateSpecificBindingLists(
+ IN OUT PFDDI_FILTER Filter,
+ IN PFDDI_BINDING_INFO Binding
+ );
+
+VOID
+fddiUpdateDirectedBindingList(
+ IN OUT PFDDI_FILTER Filter,
+ IN PFDDI_BINDING_INFO Binding,
+ IN BOOLEAN fAddToList
+ );
+
+VOID
+fddiUpdateBroadcastBindingList(
+ IN OUT PFDDI_FILTER Filter,
+ IN PFDDI_BINDING_INFO Binding,
+ IN BOOLEAN fAddToList
+ );
+
+VOID
+fddiUndoFilterAdjust(
+ IN OUT PFDDI_FILTER Filter,
+ IN PFDDI_BINDING_INFO Binding
+ );
+
+VOID
+fddiUndoChangeFilterLongAddresses(
+ IN PFDDI_FILTER Filter
+ );
+
+VOID
+fddiUndoChangeFilterShortAddresses(
+ IN PFDDI_FILTER Filter
+ );
+
+VOID
+FddiFilterDprIndicateReceiveFullMac(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PCHAR Address,
+ IN UINT AddressLength,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+VOID
+FddiFilterDprIndicateReceiveCompleteFullMac(
+ IN PFDDI_FILTER Filter
+ );
+
+//
+// TrFilterxxx
+//
+VOID
+trRemoveBindingFromLists(
+ IN PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding
+ );
+
+VOID
+trRemoveAndFreeBinding(
+ IN PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding,
+ IN BOOLEAN fCallCloseAction
+ );
+
+VOID
+trUpdateDirectedBindingList(
+ IN OUT PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding,
+ IN BOOLEAN fAddBindingToList
+ );
+
+VOID
+trUpdateBroadcastBindingList(
+ IN OUT PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding,
+ IN BOOLEAN fAddBindingToList
+ );
+
+NDIS_STATUS
+ndisMChangeFunctionalAddress(
+ IN TR_FUNCTIONAL_ADDRESS OldFunctionalAddress,
+ IN TR_FUNCTIONAL_ADDRESS NewFunctionalAddress,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+NDIS_STATUS
+ndisMChangeGroupAddress(
+ IN TR_FUNCTIONAL_ADDRESS OldGroupAddress,
+ IN TR_FUNCTIONAL_ADDRESS NewGroupAddress,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+VOID
+trUpdateSpecificBindingLists(
+ IN OUT PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding
+ );
+
+VOID
+trUndoFilterAdjust(
+ IN OUT PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding
+ );
+
+VOID
+trUndoChangeFunctionalAddress(
+ IN OUT PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding
+ );
+
+VOID
+trUndoChangeGroupAddress(
+ IN OUT PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding
+ );
+
+VOID
+trCompleteChangeGroupAddress(
+ IN OUT PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding
+ );
+
+VOID
+TrFilterDprIndicateReceiveFullMac(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+VOID
+TrFilterDprIndicateReceiveCompleteFullMac(
+ IN PTR_FILTER Filter
+ );
+
+//
+// ArcFilterxxx
+//
+VOID
+ndisMArcCopyFromBufferToPacket(
+ IN PCHAR Buffer,
+ IN UINT BytesToCopy,
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ OUT PUINT BytesCopied
+ );
+
+
+BOOLEAN
+FASTCALL
+ndisMArcnetSendLoopback(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_PACKET Packet
+ );
+
+NDIS_STATUS
+ndisMArcnetSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ );
+
+NDIS_STATUS
+ndisMBuildArcnetHeader(
+ PNDIS_MINIPORT_BLOCK Miniport,
+ PNDIS_M_OPEN_BLOCK Open,
+ PNDIS_PACKET Packet
+ );
+
+VOID
+ndisMFreeArcnetHeader(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_PACKET Packet
+ );
+
+VOID
+ArcDeleteFilter(
+ IN PARC_FILTER Filter
+ );
+
+
+NDIS_STATUS
+ndisMArcTransferData(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+VOID
+ndisMArcIndicateEthEncapsulatedReceive(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PVOID HeaderBuffer,
+ IN PVOID DataBuffer,
+ IN UINT Length
+ );
+
+VOID
+arcUndoFilterAdjust(
+ IN PARC_FILTER Filter,
+ IN PARC_BINDING_INFO Binding
+ );
+
+NDIS_STATUS
+ArcConvertOidListToEthernet(
+ IN PNDIS_OID OidList,
+ IN PULONG NumberOfOids
+ );
+
+NDIS_STATUS
+ArcAllocateBuffers(
+ IN PARC_FILTER Filter
+ );
+
+NDIS_STATUS
+ArcAllocatePackets(
+ IN PARC_FILTER Filter
+ );
+
+VOID
+ArcDiscardPacketBuffers(
+ IN PARC_FILTER Filter,
+ IN PARC_PACKET Packet
+ );
+
+VOID
+ArcDestroyPacket(
+ IN PARC_FILTER Filter,
+ IN PARC_PACKET Packet
+ );
+
+BOOLEAN
+ArcConvertToNdisPacket(
+ IN PARC_FILTER Filter,
+ IN PARC_PACKET Packet,
+ IN BOOLEAN ConvertWholePacket
+ );
+
+NDIS_STATUS
+ndisMSetFunctionalAddress(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ );
+
+NDIS_STATUS
+ndisMSetGroupAddress(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ );
+
+NDIS_STATUS
+ndisMSetFddiMulticastList(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request,
+ IN BOOLEAN fShort
+ );
+
+NDIS_STATUS
+ndisMSetInformation(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ );
+
+NDIS_STATUS
+ndisMQueryCurrentPacketFilter(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ );
+
+NDIS_STATUS
+ndisMQueryMediaSupported(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ );
+
+NDIS_STATUS
+ndisMQueryEthernetMulticastList(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ );
+
+NDIS_STATUS
+ndisMQueryLongMulticastList(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ );
+
+NDIS_STATUS
+ndisMQueryShortMulticastList(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ );
+
+NDIS_STATUS
+ndisMQueryMaximumFrameSize(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ );
+
+NDIS_STATUS
+ndisMQueryMaximumTotalSize(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ );
+
+NDIS_STATUS
+ndisMQueryNetworkAddress(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ );
+
+NDIS_STATUS
+ndisMQueryInformation(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ );
+
+//
+// WORK ITEM ROUTINES.
+//
+VOID
+FASTCALL
+ndisMDeQueueWorkItem(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ OUT PVOID * WorkItemContext1,
+ OUT PVOID * WorkItemContext2
+ );
+
+VOID
+FASTCALL
+ndisMDeQueueWorkItemFullDuplex(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ OUT PVOID WorkItemContext1,
+ OUT PVOID WorkItemContext2
+ );
+
+NDIS_STATUS
+FASTCALL
+ndisMQueueWorkItem(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ OUT PVOID WorkItemContext1,
+ OUT PVOID WorkItemContext2
+ );
+
+NDIS_STATUS
+FASTCALL
+ndisMQueueWorkItemFullDuplex(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ OUT PVOID WorkItemContext1,
+ OUT PVOID WorkItemContext2
+ );
+
+NDIS_STATUS
+FASTCALL
+ndisMQueueNewWorkItem(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ OUT PVOID WorkItemContext1,
+ OUT PVOID WorkItemContext2
+ );
+
+NDIS_STATUS
+FASTCALL
+ndisMQueueNewWorkItemFullDuplex(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ OUT PVOID WorkItemContext1,
+ OUT PVOID WorkItemContext2
+ );
+
+
+VOID
+FASTCALL
+ndisIMDeQueueWorkItem(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ OUT PVOID WorkItemContext1,
+ OUT PVOID WorkItemContext2
+ );
+
+VOID
+FASTCALL
+ndisIMDeQueueWorkItemFullDuplex(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ OUT PVOID WorkItemContext1,
+ OUT PVOID WorkItemContext2
+ );
+
+NDIS_STATUS
+FASTCALL
+ndisIMQueueWorkItem(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ OUT PVOID WorkItemContext1,
+ OUT PVOID WorkItemContext2
+ );
+
+NDIS_STATUS
+FASTCALL
+ndisIMQueueNewWorkItem(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ OUT PVOID WorkItemContext1,
+ OUT PVOID WorkItemContext2
+ );
+
+//
+// SEND HANDLERS
+//
+//
+
+NDIS_STATUS FASTCALL
+ndisMSyncSend(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_PACKET Packet
+ );
+
+#undef NdisMSendResourcesAvailable
+
+VOID
+NdisMSendResourcesAvailable(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ );
+
+VOID
+ndisMSendResourcesAvailableFullDuplex(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ );
+
+#undef NdisMSendComplete
+
+VOID
+NdisMSendComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+ndisMSendCompleteFullDuplex(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ );
+
+BOOLEAN
+FASTCALL
+ndisMStartSendPacketsFullDuplex(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+BOOLEAN
+FASTCALL
+ndisMStartSendsFullDuplex(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+BOOLEAN
+FASTCALL
+ndisMStartSendPackets(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+BOOLEAN
+FASTCALL
+ndisMStartSends(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+NDIS_STATUS
+ndisMSendFullDuplexToSendPackets(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ );
+
+VOID
+ndisMSendPacketsFullDuplex(
+ IN PNDIS_OPEN_BLOCK NdisOpenBlock,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ );
+
+NDIS_STATUS
+ndisMSendToSendPackets(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ );
+
+VOID
+ndisMSendPackets(
+ IN PNDIS_OPEN_BLOCK NdisOpenBlock,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ );
+
+VOID
+ndisMSendPacketsFullDuplexToSend(
+ IN PNDIS_OPEN_BLOCK NdisOpenBlock,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ );
+
+NDIS_STATUS
+ndisMSendFullDuplex(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ );
+
+VOID
+ndisMSendPacketsToSend(
+ IN PNDIS_OPEN_BLOCK NdisOpenBlock,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ );
+
+NDIS_STATUS
+ndisMSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ );
+
+VOID
+ndisMSendPacketsToFullMac(
+ IN PNDIS_OPEN_BLOCK NdisOpenBlock,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ );
+
+VOID
+ndisMResetSendPackets(
+ IN PNDIS_OPEN_BLOCK NdisOpenBlock,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ );
+
+NDIS_STATUS
+ndisMResetSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ );
+
+NDIS_STATUS
+ndisMResetWanSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE NdisLinkHandle,
+ IN PVOID Packet
+ );
+
+
+NDIS_STATUS
+ndisMCoSendPackets(
+ IN NDIS_HANDLE NdisVcHandle,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ );
+
+NDIS_STATUS
+ndisMRejectSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ );
+
+VOID
+ndisMRejectSendPackets(
+ IN PNDIS_OPEN_BLOCK OpenBlock,
+ IN PPNDIS_PACKET Packets,
+ IN UINT NumberOfPackets
+ );
+
+NDIS_STATUS
+ndisMWrappedRequest(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+#undef NdisMStartBufferPhysicalMapping
+#undef NdisMCompleteBufferPhysicalMapping
+
+VOID
+NdisMStartBufferPhysicalMapping(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG PhysicalMapRegister,
+ IN BOOLEAN WriteToDevice,
+ OUT PNDIS_PHYSICAL_ADDRESS_UNIT PhysicalAddressArray,
+ OUT PUINT ArraySize
+ );
+
+VOID
+NdisMCompleteBufferPhysicalMapping(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG PhysicalMapRegister
+ );
+
+NDIS_STATUS
+ndisAddResource(
+ OUT PCM_RESOURCE_LIST *pResources,
+ IN PCM_PARTIAL_RESOURCE_DESCRIPTOR NewResource,
+ IN NDIS_INTERFACE_TYPE AdapterType,
+ IN ULONG BusNumber,
+ IN PDRIVER_OBJECT DriverObject,
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PNDIS_STRING AdapterName
+ );
+
+NDIS_STATUS
+ndisRemoveResource(
+ OUT PCM_RESOURCE_LIST *pResources,
+ IN PCM_PARTIAL_RESOURCE_DESCRIPTOR DeadResource,
+ IN PDRIVER_OBJECT DriverObject,
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PNDIS_STRING AdapterName
+ );
+
+VOID
+ndisMReleaseResources(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+
+//
+// Co-Ndis prototypes
+//
+VOID
+ndisMNotifyAfRegistration(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PCO_ADDRESS_FAMILY AddressFamily OPTIONAL
+ );
+
+BOOLEAN
+ndisReferenceAf(
+ IN PNDIS_CO_AF_BLOCK AfBlock
+ );
+
+VOID
+ndisDereferenceAf(
+ IN PNDIS_CO_AF_BLOCK AfBlock
+ );
+
+BOOLEAN
+ndisReferenceSap(
+ IN PNDIS_CO_SAP_BLOCK SapBlock
+ );
+
+VOID
+ndisDereferenceSap(
+ IN PNDIS_CO_SAP_BLOCK SapBlock
+ );
+
+BOOLEAN
+ndisReferenceVc(
+ IN PNDIS_CO_VC_BLOCK AfBlock
+ );
+
+VOID
+ndisDereferenceVc(
+ IN PNDIS_CO_VC_BLOCK AfBlock
+ );
+
+VOID
+ndisMCoFreeResources(
+ PNDIS_M_OPEN_BLOCK Open
+ );
+
+//
+// If we are on an x86 box and internal debugging is enabled
+// then we prototype the following.
+//
+#if _DBG && defined(_M_IX86) && defined(_NDIS_INTERNAL_DEBUG)
+
+EXPORT
+VOID
+NdisMSetWriteBreakPoint(
+ IN PVOID LinearAddress
+ );
+
+EXPORT
+VOID
+NdisMClearWriteBreakPoint(
+ IN PVOID LinearAddress
+ );
+
+#else
+
+#define NdisMSetWriteBreakPoint(LinearAddress)
+#define NdisMClearWriteBreakPoint(LinearAddress)
+
+#endif
+
+#if TRACK_MEMORY
+
+extern
+PVOID
+AllocateM(
+ IN UINT Size,
+ IN ULONG ModLine,
+ IN ULONG Tag
+ );
+
+extern
+VOID
+FreeM(
+ IN PVOID MemPtr
+ );
+
+#endif
diff --git a/private/ntos/ndis/ndis40/requestm.c b/private/ntos/ndis/ndis40/requestm.c
new file mode 100644
index 000000000..1a3a5578d
--- /dev/null
+++ b/private/ntos/ndis/ndis40/requestm.c
@@ -0,0 +1,3994 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ requestm.c
+
+Abstract:
+
+ NDIS miniport request routines.
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 05-Oct-93
+ Jameel Hyder (JameelH) Re-organization 01-Jun-95
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_REQUESTM
+
+//
+// This macro verifies the query information buffer length.
+//
+#define VERIFY_QUERY_PARAMETERS(_Request, _SizeNeeded, _Status) \
+{ \
+ if ((_Request)->DATA.QUERY_INFORMATION.InformationBufferLength < (_SizeNeeded)) \
+ { \
+ (_Request)->DATA.QUERY_INFORMATION.BytesNeeded = (_SizeNeeded); \
+ \
+ Status = NDIS_STATUS_INVALID_LENGTH; \
+ } \
+ else \
+ { \
+ Status = NDIS_STATUS_SUCCESS; \
+ } \
+}
+
+//
+// This macro verifies the set information buffer length.
+//
+#define VERIFY_SET_PARAMETERS(_Request, _SizeNeeded, _Status) \
+{ \
+ if ((_Request)->DATA.SET_INFORMATION.InformationBufferLength < (_SizeNeeded)) \
+ { \
+ (_Request)->DATA.SET_INFORMATION.BytesNeeded = (_SizeNeeded); \
+ \
+ Status = NDIS_STATUS_INVALID_LENGTH; \
+ } \
+ else \
+ { \
+ Status = NDIS_STATUS_SUCCESS; \
+ } \
+}
+
+VOID
+ndisMQueueRequest(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request,
+ IN PNDIS_M_OPEN_BLOCK Open
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_REQUEST *ppReq;
+
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Next = NULL;
+ if (Open != NULL)
+ {
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open = Open;
+ Open->References++;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("+ Open 0x%x Reference 0x%x\n", Open, Open->References));
+ }
+
+ for (ppReq = &Miniport->PendingRequest;
+ *ppReq != NULL;
+ NOTHING)
+ {
+ ppReq = &(PNDIS_RESERVED_FROM_PNDIS_REQUEST(*ppReq))->Next;
+ }
+ *ppReq = Request;
+}
+
+NDIS_STATUS
+ndisMAllocateRequest(
+ OUT PNDIS_REQUEST * pRequest,
+ IN NDIS_REQUEST_TYPE RequestType,
+ IN NDIS_OID Oid,
+ IN PVOID Buffer,
+ IN ULONG BufferLength
+ )
+/*++
+
+Routine Description:
+
+ This routine will allocate a request to be used as an internal request.
+
+Arguments:
+
+ Request - Will contain a pointer to the new request on exit.
+ RequestType - Type of ndis request.
+ Oid - Request identifier.
+ Buffer - Pointer to the buffer for the request.
+ BufferLength- Length of the buffer.
+ Context1 - This is the type of request.
+ Context2 - Information that will be needed when the internal request
+ completes.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if the request allocation succeeded.
+ NDIS_STATUS_FAILURE otherwise.
+
+--*/
+{
+ PNDIS_REQUEST Request;
+ ULONG SizeNeeded;
+ PVOID Data;
+
+ //
+ // Allocate the request structure.
+ //
+ SizeNeeded = sizeof(NDIS_REQUEST) + BufferLength;
+ Data = ALLOC_FROM_POOL(SizeNeeded, NDIS_TAG_Q_REQ);
+ if (NULL == Data)
+ {
+ *pRequest = NULL;
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ //
+ // Zero out the request.
+ //
+ ZeroMemory(Data, SizeNeeded);
+
+ //
+ // Get a pointer to the request.
+ //
+ Request = Data;
+
+ //
+ // Set the request type.
+ //
+ Request->RequestType = RequestType;
+
+ //
+ // Copy the buffer that was passed to us into
+ // the new buffer.
+ //
+ if ((BufferLength > 0) &&
+ (Buffer != NULL) &&
+ (RequestType != NdisRequestQueryInformation) &&
+ (RequestType != NdisRequestQueryStatistics))
+ {
+ MoveMemory(Request + 1, Buffer, BufferLength);
+ }
+
+ //
+ // Initialize depending upon request type.
+ //
+ switch (RequestType)
+ {
+ case NdisRequestQueryStatistics:
+ case NdisRequestQueryInformation:
+ Request->DATA.QUERY_INFORMATION.Oid = Oid;
+ if ((BufferLength > 0) && (Buffer != NULL))
+ {
+ Request->DATA.QUERY_INFORMATION.InformationBuffer = Request + 1;
+ Request->DATA.QUERY_INFORMATION.InformationBufferLength = BufferLength;
+ }
+
+ break;
+
+ case NdisRequestSetInformation:
+ Request->DATA.SET_INFORMATION.Oid = Oid;
+ if ((BufferLength > 0) && (Buffer != NULL))
+ {
+ Request->DATA.SET_INFORMATION.InformationBuffer = Request + 1;
+ Request->DATA.SET_INFORMATION.InformationBufferLength = BufferLength;
+ }
+
+ break;
+
+ default:
+
+ break;
+ }
+
+ //
+ // Give it back to the caller.
+ //
+ *pRequest = Request;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+VOID
+ndisMRestoreFilterSettings(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_M_OPEN_BLOCK Open
+ )
+/*++
+
+Routine Description:
+
+ This routine will build request's to send down to the driver to
+ restore the filter settings. we have free run of the request queue
+ since we just reset it.
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_REQUEST Request;
+ NDIS_STATUS Status;
+ ULONG PacketFilter;
+ UINT NumberOfAddresses;
+ UINT FunctionalAddress;
+ UINT GroupAddress;
+ PSINGLE_LIST_ENTRY Link;
+
+ //
+ // Get the packet filter for the media type.
+ //
+ switch (Miniport->MediaType)
+ {
+ case NdisMedium802_3:
+ PacketFilter = ETH_QUERY_FILTER_CLASSES(Miniport->EthDB);
+
+ break;
+
+ case NdisMedium802_5:
+ PacketFilter = TR_QUERY_FILTER_CLASSES(Miniport->TrDB);
+
+ break;
+
+ case NdisMediumFddi:
+ PacketFilter = FDDI_QUERY_FILTER_CLASSES(Miniport->FddiDB);
+
+ break;
+
+ case NdisMediumArcnet878_2:
+ PacketFilter = ARC_QUERY_FILTER_CLASSES(Miniport->ArcDB);
+ PacketFilter |= ETH_QUERY_FILTER_CLASSES(Miniport->EthDB);
+
+ if (MINIPORT_TEST_FLAG(
+ Miniport,
+ fMINIPORT_ARCNET_BROADCAST_SET) ||
+ (PacketFilter & NDIS_PACKET_TYPE_MULTICAST))
+ {
+ PacketFilter &= ~NDIS_PACKET_TYPE_MULTICAST;
+ PacketFilter |= NDIS_PACKET_TYPE_BROADCAST;
+ }
+
+ break;
+ }
+
+ //
+ // Allocate a request to restore the packet filter.
+ //
+ Status = ndisMAllocateRequest(&Request,
+ NdisRequestSetInformation,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ &PacketFilter,
+ sizeof(PacketFilter));
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Should do something here!!
+ //
+ }
+
+ ndisMQueueRequest(Miniport, Request, Open);
+
+ //
+ // Now build media dependant requests.
+ //
+ switch (Miniport->MediaType)
+ {
+ case NdisMedium802_3:
+
+ ///
+ // For ethernet we need to restore the multicast address list.
+ ///
+
+ //
+ // Get a list of all the multicast address that need
+ // to be set.
+ //
+ EthQueryGlobalFilterAddresses(&Status,
+ Miniport->EthDB,
+ NDIS_M_MAX_MULTI_LIST * ETH_LENGTH_OF_ADDRESS,
+ &NumberOfAddresses,
+ (PVOID)Miniport->MulticastBuffer);
+
+ //
+ // Allocate a request to restore the multicast address list.
+ //
+ Status = ndisMAllocateRequest(&Request,
+ NdisRequestSetInformation,
+ OID_802_3_MULTICAST_LIST,
+ Miniport->MulticastBuffer,
+ NumberOfAddresses * ETH_LENGTH_OF_ADDRESS);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Should do something here!!
+ //
+ }
+
+ ndisMQueueRequest(Miniport, Request, Open);
+ break;
+
+ case NdisMedium802_5:
+
+ ///
+ // For token ring we need to restore the functional address
+ // and the group address.
+ ///
+
+ //
+ // Get the current functional address from the filter
+ // library.
+ //
+ FunctionalAddress = TR_QUERY_FILTER_ADDRESSES(Miniport->TrDB);
+ FunctionalAddress = BYTE_SWAP_ULONG(FunctionalAddress);
+
+ //
+ // Allocate a request to restore the functional address.
+ //
+ Status = ndisMAllocateRequest(&Request,
+ NdisRequestSetInformation,
+ OID_802_5_CURRENT_FUNCTIONAL,
+ &FunctionalAddress,
+ sizeof(FunctionalAddress));
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Should do something here!!
+ //
+ }
+
+ ndisMQueueRequest(Miniport, Request, Open);
+
+ //
+ // Get the current group address from the filter library.
+ //
+ GroupAddress = TR_QUERY_FILTER_GROUP(Miniport->TrDB);
+ GroupAddress = BYTE_SWAP_ULONG(GroupAddress);
+
+ //
+ // Allocate a request to restore the group address.
+ //
+ Status = ndisMAllocateRequest(&Request,
+ NdisRequestSetInformation,
+ OID_802_5_CURRENT_GROUP,
+ &GroupAddress,
+ sizeof(GroupAddress));
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Should do something here!!
+ //
+ }
+
+ ndisMQueueRequest(Miniport, Request, Open);
+
+ break;
+
+ case NdisMediumFddi:
+
+ ///
+ // For FDDI we need to restore the long multicast address
+ // list and the short multicast address list.
+ ///
+
+ //
+ // Get the number of multicast addresses and the list
+ // of multicast addresses to send to the miniport driver.
+ //
+ FddiQueryGlobalFilterLongAddresses(&Status,
+ Miniport->FddiDB,
+ NDIS_M_MAX_MULTI_LIST * FDDI_LENGTH_OF_LONG_ADDRESS,
+ &NumberOfAddresses,
+ (PVOID)Miniport->MulticastBuffer);
+
+ //
+ // Allocate a request to restore the long multicast address list.
+ //
+ Status = ndisMAllocateRequest(&Request,
+ NdisRequestSetInformation,
+ OID_FDDI_LONG_MULTICAST_LIST,
+ Miniport->MulticastBuffer,
+ NumberOfAddresses * FDDI_LENGTH_OF_LONG_ADDRESS);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Should do something here!!
+ //
+ }
+
+ ndisMQueueRequest(Miniport, Request, Open);
+
+ //
+ // Get the number of multicast addresses and the list
+ // of multicast addresses to send to the miniport driver.
+ //
+ FddiQueryGlobalFilterShortAddresses(&Status,
+ Miniport->FddiDB,
+ NDIS_M_MAX_MULTI_LIST * FDDI_LENGTH_OF_SHORT_ADDRESS,
+ &NumberOfAddresses,
+ (PVOID)Miniport->MulticastBuffer);
+
+ //
+ // Allocate a request to restore the short multicast address list.
+ //
+ Status = ndisMAllocateRequest(&Request,
+ NdisRequestSetInformation,
+ OID_FDDI_SHORT_MULTICAST_LIST,
+ Miniport->MulticastBuffer,
+ NumberOfAddresses * FDDI_LENGTH_OF_SHORT_ADDRESS);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Should do something here!!
+ //
+ }
+
+ ndisMQueueRequest(Miniport, Request, Open);
+
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ //
+ // Only the packet filter is restored for arcnet and
+ // that was done above.
+ //
+
+ break;
+ }
+
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+}
+
+
+NDIS_STATUS
+ndisMRequest(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_M_OPEN_BLOCK Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = Open->MiniportHandle;
+ PNDIS_REQUEST_RESERVED Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(NdisRequest);
+ BOOLEAN LocalLock;
+ KIRQL OldIrql;
+ NDIS_STATUS Status;
+ PSINGLE_LIST_ENTRY Link;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ //
+ // Get protocol-options
+ //
+ if ((NdisRequest->RequestType == NdisRequestSetInformation) &&
+ (NdisRequest->DATA.SET_INFORMATION.Oid == OID_GEN_PROTOCOL_OPTIONS) &&
+ (NdisRequest->DATA.SET_INFORMATION.InformationBuffer != NULL))
+ {
+ PULONG ProtocolOptions;
+
+ ProtocolOptions = (PULONG)(NdisRequest->DATA.SET_INFORMATION.InformationBuffer);
+ if (*ProtocolOptions & NDIS_PROT_OPTION_NO_RSVD_ON_RCVPKT)
+ {
+ *ProtocolOptions &= ~NDIS_PROT_OPTION_NO_RSVD_ON_RCVPKT;
+ Open->Flags |= fMINIPORT_OPEN_NO_PROT_RSVD;
+ Open->FakeOpen->NoProtRsvdOnRcvPkt = TRUE;
+ }
+ if ((*ProtocolOptions & NDIS_PROT_OPTION_NO_LOOPBACK) &&
+ (Miniport->MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK))
+ {
+ *ProtocolOptions &= ~fMINIPORT_OPEN_NO_LOOPBACK;
+ Open->Flags |= NDIS_PROT_OPTION_NO_LOOPBACK;
+ }
+ }
+
+ //
+ // Is there a reset in progress?
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS))
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ return(NDIS_STATUS_RESET_IN_PROGRESS);
+ }
+
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Got request 0x%x\n", NdisRequest));
+
+ //
+ // Place the new request on the pending queue.
+ //
+ ndisMQueueRequest(
+ Miniport,
+ NdisRequest,
+ (PNDIS_M_OPEN_BLOCK)NdisBindingHandle);
+
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+
+ if (LocalLock)
+ {
+ //
+ // If we did not lock down the mini-port, then some other routine will
+ // do this processing for us. Otherwise we need to do this processing.
+ //
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ return(NDIS_STATUS_PENDING);
+}
+
+
+VOID
+ndisMUndoBogusFilters(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+)
+
+/*++
+
+Routine Description:
+
+ Deletes the bogus filter packages created in NdisCallDriverAddAdapter.
+
+Arguments:
+
+ Miniport - Pointer to the Miniport.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ EthDeleteFilter(Miniport->EthDB);
+ Miniport->EthDB = NULL;
+ TrDeleteFilter(Miniport->TrDB);
+ Miniport->TrDB = NULL;
+ FddiDeleteFilter(Miniport->FddiDB);
+ Miniport->FddiDB = NULL;
+ ArcDeleteFilter(Miniport->ArcDB);
+ Miniport->ArcDB = NULL;
+}
+
+LONG
+ndisMDoMiniportOp(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN BOOLEAN Query,
+ IN ULONG Oid,
+ IN PVOID Buf,
+ IN LONG BufSize,
+ IN LONG ErrorCodesToReturn
+ )
+
+{
+ KIRQL OldIrql;
+ NTSTATUS NtStatus;
+ NDIS_STATUS NdisStatus;
+ LONG ErrorCode = 0;
+ UINT BytesWritten;
+ UINT BytesNeeded;
+ BOOLEAN LocalLock;
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+
+ RAISE_IRQL_TO_DISPATCH(&OldIrql);
+ BLOCK_LOCK_MINIPORT_DPC(Miniport, LocalLock);
+
+ //
+ // Save a pointer to the miniport block as the
+ // current request. This will tell us that this request
+ // needs to be completed by setting the event.
+ //
+ Miniport->MiniportRequest = (PNDIS_REQUEST)Miniport;
+
+ //
+ // Do the appropriate operation.
+ //
+ if (Query)
+ {
+ NdisStatus = (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ Oid,
+ Buf,
+ BufSize,
+ &BytesWritten,
+ &BytesNeeded);
+ }
+ else
+ {
+ NdisStatus = (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ Oid,
+ Buf,
+ BufSize,
+ &BytesWritten,
+ &BytesNeeded);
+ }
+
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS))
+ {
+ //
+ // Queue a dpc to fire.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemDpc, &Miniport->Dpc, NULL);
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ LOWER_IRQL(OldIrql);
+
+ if (NdisStatus == NDIS_STATUS_PENDING)
+ {
+ LARGE_INTEGER TimeoutValue;
+
+ TimeoutValue.QuadPart = Int32x32To64(1000, -10000); // Make it 1 second
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+ NtStatus = WAIT_FOR_OBJECT(&Miniport->RequestEvent, &TimeoutValue);
+
+ NdisStatus = Miniport->RequestStatus;
+
+ if ((NtStatus != STATUS_SUCCESS) ||
+ (NdisStatus != NDIS_STATUS_SUCCESS))
+ {
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler)(Miniport->MiniportAdapterContext);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ ErrorCode = (NtStatus != STATUS_SUCCESS) ? ErrorCodesToReturn : ErrorCodesToReturn + 1;
+ }
+
+ RESET_EVENT(&Miniport->RequestEvent);
+ }
+
+ return(ErrorCode);
+}
+
+NDIS_STATUS
+ndisMFilterOutStatisticsOids(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+ This routine will filter out any statistics OIDs.
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ ULONG c;
+ PNDIS_OID OidList;
+ ULONG TotalOids;
+ ULONG CurrentDestOid;
+
+ //
+ // Initialize some temp variables.
+ //
+ OidList = Request->DATA.QUERY_INFORMATION.InformationBuffer;
+ TotalOids = Request->DATA.QUERY_INFORMATION.BytesWritten / sizeof(NDIS_OID);
+
+ //
+ // Copy the information OIDs to the buffer that
+ // was passed with the original request.
+ //
+ for (c = 0, CurrentDestOid = 0;
+ c < TotalOids;
+ c++
+ )
+ {
+ //
+ // Is this a statistic Oid?
+ //
+ if ((OidList[c] & 0x00FF0000) != 0x00020000)
+ {
+ OidList[CurrentDestOid++] = OidList[c];
+ }
+ }
+
+ //
+ // If ARCnet then do the filtering.
+ //
+ if ((Miniport->MediaType == NdisMediumArcnet878_2) &&
+ MINIPORT_TEST_FLAG(
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open,
+ fMINIPORT_OPEN_USING_ETH_ENCAPSULATION)
+ )
+ {
+ ArcConvertOidListToEthernet(OidList, &CurrentDestOid);
+ }
+
+ //
+ // Save the amount of data that was kept.
+ //
+ Request->DATA.QUERY_INFORMATION.BytesWritten =
+ CurrentDestOid * sizeof(NDIS_OID);
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+VOID
+ndisMRequestQueryInformationPost(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ switch (Request->DATA.QUERY_INFORMATION.Oid)
+ {
+ case OID_GEN_SUPPORTED_LIST:
+
+ //
+ // Was this a query for the size of the list?
+ //
+ if ((NULL == Request->DATA.QUERY_INFORMATION.InformationBuffer) ||
+ (0 == Request->DATA.QUERY_INFORMATION.InformationBufferLength) ||
+ (Status != NDIS_STATUS_SUCCESS))
+ {
+ //
+ // If this is ARCnet running encapsulated ethernet then
+ // we need to add a couple of OIDs to be safe.
+ //
+ if ((Miniport->MediaType == NdisMediumArcnet878_2) &&
+ MINIPORT_TEST_FLAG(
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open,
+ fMINIPORT_OPEN_USING_ETH_ENCAPSULATION))
+ {
+ Request->DATA.QUERY_INFORMATION.BytesNeeded +=
+ (ARC_NUMBER_OF_EXTRA_OIDS * sizeof(NDIS_OID));
+ }
+
+ Request->DATA.QUERY_INFORMATION.BytesWritten = 0;
+ }
+ else
+ {
+ //
+ // Filter out the statistics oids.
+ //
+ ndisMFilterOutStatisticsOids(Miniport, Request);
+ }
+ break;
+ }
+}
+
+VOID
+ndisMSyncQueryInformationComplete(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ This routine will process a query information complete. This is only
+ called from the wrapper. The difference is that this routine will not
+ call ndisMProcessDeferred() after processing the completion of the query.
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_REQUEST Request;
+ PNDIS_M_OPEN_BLOCK Open;
+ PNDIS_REQUEST_RESERVED Reserved;
+
+ //
+ // Check for global statistics request
+ //
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_REQUEST_TIMEOUT);
+
+ //
+ // If the current request is a pointer to the miniport block
+ // then this is an initialization request that pended.
+ // We complete this by setting the request event.
+ //
+ if (Miniport->MiniportRequest == (PNDIS_REQUEST)Miniport)
+ {
+ Miniport->MiniportRequest = NULL;
+ Miniport->RequestStatus = Status;
+ SET_EVENT(&Miniport->RequestEvent);
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Exit query information complete\n"));
+ return;
+ }
+
+ //
+ // Remove the request.
+ //
+ Request = Miniport->MiniportRequest;
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request);
+ Miniport->MiniportRequest = NULL;
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Request 0x%x\n", Request));
+
+ //
+ // Separate processing for query statistics information complete.
+ //
+ if (Request->RequestType == NdisRequestQueryStatistics)
+ {
+ PNDIS_QUERY_GLOBAL_REQUEST GlobalRequest;
+ PNDIS_QUERY_ALL_REQUEST AllRequest;
+ PNDIS_QUERY_OPEN_REQUEST OpenRequest;
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Enter Query Statistics Information Complete\n"));
+
+ GlobalRequest = CONTAINING_RECORD(Request,
+ NDIS_QUERY_GLOBAL_REQUEST,
+ Request);
+ Irp = GlobalRequest->Irp;
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ switch (IrpSp->MajorFunction)
+ {
+ case IRP_MJ_CREATE:
+
+ //
+ // This request is one of the ones made during an open,
+ // while we are trying to determine the OID list. We
+ // set the event we are waiting for, the open code
+ // takes care of the rest.
+ //
+
+ OpenRequest = (PNDIS_QUERY_OPEN_REQUEST)GlobalRequest;
+
+ OpenRequest->NdisStatus = Status;
+ SET_EVENT(&OpenRequest->Event);
+
+ break;
+
+ case IRP_MJ_DEVICE_CONTROL:
+
+ //
+ // This is a real user request, process it as such.
+ //
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
+ {
+ case IOCTL_NDIS_QUERY_GLOBAL_STATS:
+
+ //
+ // A single query, complete the IRP.
+ //
+ Irp->IoStatus.Information =
+ Request->DATA.QUERY_INFORMATION.BytesWritten;
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ }
+ else if (Status == NDIS_STATUS_INVALID_LENGTH)
+ {
+ Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
+ }
+ else
+ {
+ Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+ }
+
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ FREE_POOL (GlobalRequest);
+
+ break;
+
+ case IOCTL_NDIS_QUERY_ALL_STATS:
+
+ //
+ // An "all" query.
+ //
+
+ AllRequest = (PNDIS_QUERY_ALL_REQUEST)GlobalRequest;
+
+ AllRequest->NdisStatus = Status;
+ SET_EVENT(&AllRequest->Event);
+
+ break;
+ }
+
+ break;
+ }
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Exit Query Statistics Information Complete\n"));
+
+ return;
+ }
+
+ //
+ // Do any necessary post-processing on the query.
+ //
+ ndisMRequestQueryInformationPost(Miniport, Request, Status);
+
+ //
+ // Was this an internal request?
+ //
+ if (Reserved->Open != NULL)
+ {
+ //
+ // Indicate to Protocol;
+ //
+ Open = Reserved->Open;
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Open 0x%x\n", Open));
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.RequestCompleteHandler)(
+ Open->ProtocolBindingContext,
+ Request,
+ Status);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("- Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ Open->References--;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("==0 Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ if (Open->References == 0)
+ {
+ ndisMFinishClose(Miniport,Open);
+ }
+ }
+ else
+ {
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Completing Internal Request\n"));
+
+ ndisMFreeInternalRequest(Request);
+ }
+}
+
+VOID
+NdisMQueryInformationComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ This function indicates the completion of a query information operation.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+ Status - Status of the operation
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PSINGLE_LIST_ENTRY Link;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ //
+ // If there is no request then we assume this is a complete that was
+ // aborted due to the heart-beat.
+ //
+ if (Miniport->MiniportRequest == NULL)
+ {
+ return;
+ }
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Enter query information complete\n"));
+
+ //
+ // Do the actual processing of the query information complete.
+ //
+ ndisMSyncQueryInformationComplete(Miniport, Status);
+
+ //
+ // Are there more requests pending?
+ //
+ if (Miniport->PendingRequest != NULL)
+ {
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+ }
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Exit query information complete\n"));
+}
+
+
+VOID
+ndisMRequestSetInformationPost(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request,
+ IN NDIS_STATUS Status
+)
+/*++
+
+Routine Description:
+
+ This routine will do any necessary post processing for ndis requests
+ of the set information type.
+
+Arguments:
+
+ Miniport - Pointer to the miniport block.
+
+ Request - Pointer to the request to process.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_REQUEST_RESERVED Reserved;
+ ULONG GroupAddress;
+
+ //
+ // Get the reserved information for the request.
+ //
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request);
+
+ switch (Request->DATA.SET_INFORMATION.Oid)
+ {
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ //
+ // The request was completed with something besides
+ // NDIS_STATUS_SUCCESS (and of course NDIS_STATUS_PENDING).
+ // Return the packete filter to the original state.
+ //
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request);
+
+ switch (Miniport->MediaType)
+ {
+ case NdisMedium802_3:
+ ethUndoFilterAdjust(Miniport->EthDB, Reserved->Open->FilterHandle);
+ break;
+
+ case NdisMedium802_5:
+ trUndoFilterAdjust(Miniport->TrDB, Reserved->Open->FilterHandle);
+ break;
+
+ case NdisMediumFddi:
+ fddiUndoFilterAdjust(Miniport->FddiDB, Reserved->Open->FilterHandle);
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ if (MINIPORT_TEST_FLAG(Reserved->Open,
+ fMINIPORT_OPEN_USING_ETH_ENCAPSULATION))
+ {
+ ethUndoFilterAdjust(Miniport->EthDB, Reserved->Open->FilterHandle);
+ }
+ else
+ {
+ arcUndoFilterAdjust(Miniport->ArcDB, Reserved->Open->FilterHandle);
+ }
+
+ break;
+ }
+ }
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ //
+ // If we succeeded then update the binding information.
+ //
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ NdisMoveMemory(&Reserved->Open->CurrentLookahead,
+ Request->DATA.SET_INFORMATION.InformationBuffer,
+ 4);
+
+ Miniport->CurrentLookahead = Reserved->Open->CurrentLookahead;
+
+ Request->DATA.SET_INFORMATION.BytesRead = 4;
+ }
+
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+
+ //
+ // We only need to do cleanup if it did not
+ // return NDIS_STATUS_SUCCESS.
+ //
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ ethUndoChangeFilterAddresses(Miniport->EthDB);
+ }
+ else
+ {
+ Request->DATA.SET_INFORMATION.BytesRead =
+ Request->DATA.SET_INFORMATION.InformationBufferLength;
+ }
+
+ break;
+
+ case OID_802_5_CURRENT_FUNCTIONAL:
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ trUndoChangeFunctionalAddress(Miniport->TrDB, Reserved->Open->FilterHandle);
+ }
+ break;
+
+ case OID_802_5_CURRENT_GROUP:
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ trUndoChangeGroupAddress(Miniport->TrDB, Reserved->Open->FilterHandle);
+ }
+
+ break;
+
+ case OID_FDDI_LONG_MULTICAST_LIST:
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ fddiUndoChangeFilterLongAddresses(Miniport->FddiDB);
+ }
+ else
+ {
+ Request->DATA.SET_INFORMATION.BytesRead =
+ Request->DATA.SET_INFORMATION.InformationBufferLength;
+ }
+ break;
+
+ case OID_FDDI_SHORT_MULTICAST_LIST:
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ fddiUndoChangeFilterShortAddresses(Miniport->FddiDB);
+ }
+ else
+ {
+ Request->DATA.SET_INFORMATION.BytesRead =
+ Request->DATA.SET_INFORMATION.InformationBufferLength;
+ }
+ break;
+ }
+}
+
+VOID
+ndisMSyncSetInformationComplete(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ This routine will process a set information complete. This is only
+ called from the wrapper. The difference is that this routine will not
+ call ndisMProcessDeferred() after processing the completion of the set.
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_REQUEST Request;
+ PNDIS_M_OPEN_BLOCK Open;
+
+ //
+ // Clear the timeout flag.
+ //
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_REQUEST_TIMEOUT);
+
+ //
+ // Get a pointer to the request that we are completeing.
+ // And clear out the request in-progress pointer.
+ //
+ Request = Miniport->MiniportRequest;
+ Miniport->MiniportRequest = NULL;
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Completing Set Information Request 0x%x\n", Request));
+
+ //
+ // Get a pointer to the open that made the request.
+ // for internal requests this will be NULL.
+ //
+ Open = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open;
+
+ //
+ // Do we need to indicate this request to the protocol?
+ // We do if it's not an internal request.
+ //
+ if (Open != NULL)
+ {
+ //
+ // If the open is not closing then notify it of
+ // the request completion.
+ //
+ if (!MINIPORT_TEST_FLAG(Open, fMINIPORT_OPEN_CLOSING))
+ {
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Open 0x%x\n", Open));
+
+ //
+ // Do any necessary post processing for the request.
+ //
+ ndisMRequestSetInformationPost(Miniport, Request, Status);
+
+ //
+ // Indicate to Protocol;
+ //
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.RequestCompleteHandler) (
+ Open->ProtocolBindingContext,
+ Request,
+ Status
+ );
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+ }
+
+ //
+ // Dereference the open.
+ //
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("- Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ Open->References--;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("==0 Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ if (Open->References == 0)
+ {
+ ndisMFinishClose(Miniport,Open);
+ }
+ }
+ else
+ {
+ //
+ // Internal requests are only used for restoring filter settings
+ // in the set information path. this means that no post processing
+ // needs to be done.
+ //
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Completeing internal request\n"));
+
+ //
+ // BUGBUG
+ //
+ // What if one of these requests fails???? We should probably halt
+ // the driver sine this is a fatal error as far as the bindings
+ // are concerned.
+ //
+ ASSERT(NDIS_STATUS_SUCCESS == Status);
+
+ //
+ // Is this the last internal request?
+ //
+ if (NULL == Miniport->PendingRequest)
+ {
+ //
+ // Now clear out the reset in progress stuff.
+ //
+ ndisMResetCompleteCommonStep2(Miniport);
+ }
+
+ //
+ // Free the request.
+ //
+ ndisMFreeInternalRequest(Request);
+ }
+}
+
+VOID
+NdisMSetInformationComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ This function indicates the completion of a set information operation.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+ Status - Status of the operation
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PSINGLE_LIST_ENTRY Link;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ //
+ // If we don't have a request to complete assume it was
+ // aborted via the reset handler.
+ //
+ if ((Miniport->MiniportRequest == NULL) ||
+ (Miniport->MiniportRequest == (PNDIS_REQUEST)Miniport))
+ {
+ return;
+ }
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Enter set information complete\n"));
+
+ //
+ // Process the actual set information complete.
+ //
+ ndisMSyncSetInformationComplete(Miniport, Status);
+
+ //
+ // Are there more requests pending?
+ //
+ if (Miniport->PendingRequest != NULL)
+ {
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+ }
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Exit set information complete\n"));
+}
+
+VOID
+ndisMAbortQueryStatisticsRequest(
+ IN PNDIS_REQUEST Request,
+ IN NDIS_STATUS Status
+ )
+{
+ PNDIS_QUERY_GLOBAL_REQUEST GlobalRequest;
+ PNDIS_QUERY_ALL_REQUEST AllRequest;
+ PNDIS_QUERY_OPEN_REQUEST OpenRequest;
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+
+ GlobalRequest = CONTAINING_RECORD(Request,
+ NDIS_QUERY_GLOBAL_REQUEST,
+ Request);
+ Irp = GlobalRequest->Irp;
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ switch (IrpSp->MajorFunction)
+ {
+ case IRP_MJ_CREATE:
+
+ //
+ // This request is one of the ones made during an open,
+ // while we are trying to determine the OID list. We
+ // set the event we are waiting for, the open code
+ // takes care of the rest.
+ //
+
+ OpenRequest = (PNDIS_QUERY_OPEN_REQUEST)GlobalRequest;
+
+ OpenRequest->NdisStatus = Status;
+ SET_EVENT(&OpenRequest->Event);
+ break;
+
+ case IRP_MJ_DEVICE_CONTROL:
+
+ //
+ // This is a real user request, process it as such.
+ //
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
+ {
+ case IOCTL_NDIS_QUERY_GLOBAL_STATS:
+ //
+ // A single query, complete the IRP.
+ //
+ Irp->IoStatus.Information =
+ Request->DATA.QUERY_INFORMATION.BytesWritten;
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ }
+ else if (Status == NDIS_STATUS_INVALID_LENGTH)
+ {
+ Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
+ }
+ else
+ {
+ Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+ }
+
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ FREE_POOL (GlobalRequest);
+ break;
+
+ case IOCTL_NDIS_QUERY_ALL_STATS:
+
+ //
+ // An "all" query.
+ //
+ AllRequest = (PNDIS_QUERY_ALL_REQUEST)GlobalRequest;
+
+ AllRequest->NdisStatus = Status;
+ SET_EVENT(&AllRequest->Event);
+
+ break;
+ }
+
+ break;
+ }
+
+} // ndisMAbortQueryStatisticsRequest
+
+NDIS_STATUS
+ndisMSetPacketFilter(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+ This routine will process two types of set packet filter requests.
+ The first one is for when a reset happens. We simply take the
+ packet filter setting that is in the request and send it to the adapter.
+ The second is when a protocol sets the packet filter, for this we need
+ to update the filter library and then send it down to the adapter.
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+ ULONG PacketFilter;
+ PNDIS_REQUEST_RESERVED Reserved;
+
+ //
+ // Verify the information buffer length that was sent in.
+ //
+ VERIFY_SET_PARAMETERS(Request, sizeof(PacketFilter), Status);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ return(Status);
+ }
+
+ //
+ // Now call the filter package to set the
+ // packet filter.
+ //
+ MoveMemory((PVOID)&PacketFilter,
+ Request->DATA.SET_INFORMATION.InformationBuffer,
+ sizeof(ULONG));
+
+ //
+ // Get a pointer to the reserved information of the request.
+ //
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request);
+
+ //
+ // If this request is because of an open that is closing then we
+ // have already adjusted the filter settings and we just need to
+ // make sure that the adapter has the new settings.
+ //
+ if (MINIPORT_TEST_FLAG(Reserved->Open, fMINIPORT_OPEN_CLOSING))
+ {
+ //
+ // By setting the Status to NDIS_STATUS_PENDING we will call
+ // down to the miniport's SetInformationHandler below.
+ //
+ Status = NDIS_STATUS_PENDING;
+ }
+ else
+ {
+ switch (Miniport->MediaType)
+ {
+ case NdisMedium802_3:
+ Status = EthFilterAdjust(Miniport->EthDB,
+ Reserved->Open->FilterHandle,
+ Request,
+ PacketFilter,
+ TRUE);
+
+ //
+ // Do this here in anticipation that we
+ // need to call down to the miniport
+ // driver.
+ //
+ PacketFilter = ETH_QUERY_FILTER_CLASSES(Miniport->EthDB);
+
+ break;
+
+ case NdisMedium802_5:
+ Status = TrFilterAdjust(Miniport->TrDB,
+ Reserved->Open->FilterHandle,
+ Request,
+ PacketFilter,
+ TRUE);
+
+ //
+ // Do this here in anticipation that we
+ // need to call down to the miniport
+ // driver.
+ //
+ PacketFilter = TR_QUERY_FILTER_CLASSES(Miniport->TrDB);
+
+ break;
+
+ case NdisMediumFddi:
+ Status = FddiFilterAdjust(Miniport->FddiDB,
+ Reserved->Open->FilterHandle,
+ Request,
+ PacketFilter,
+ TRUE);
+
+ //
+ // Do this here in anticipation that we
+ // need to call down to the miniport
+ // driver.
+ //
+ PacketFilter = FDDI_QUERY_FILTER_CLASSES(Miniport->FddiDB);
+
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ if (MINIPORT_TEST_FLAG(Reserved->Open, fMINIPORT_OPEN_USING_ETH_ENCAPSULATION))
+ {
+ Status = EthFilterAdjust(Miniport->EthDB,
+ Reserved->Open->FilterHandle,
+ Request,
+ PacketFilter,
+ TRUE);
+ }
+ else
+ {
+ Status = ArcFilterAdjust(Miniport->ArcDB,
+ Reserved->Open->FilterHandle,
+ Request,
+ PacketFilter,
+ TRUE);
+ }
+
+ //
+ // Do this here in anticipation that we
+ // need to call down to the miniport
+ // driver.
+ //
+ PacketFilter = ARC_QUERY_FILTER_CLASSES(Miniport->ArcDB);
+ PacketFilter |= ETH_QUERY_FILTER_CLASSES(Miniport->EthDB);
+
+ if (MINIPORT_TEST_FLAG(Miniport,
+ fMINIPORT_ARCNET_BROADCAST_SET) ||
+ (PacketFilter & NDIS_PACKET_TYPE_MULTICAST))
+ {
+ PacketFilter &= ~NDIS_PACKET_TYPE_MULTICAST;
+ PacketFilter |= NDIS_PACKET_TYPE_BROADCAST;
+ }
+
+ break;
+ }
+ }
+
+ //
+ // If the filter library returns NDIS_STATUS_PENDING from
+ // the XxxFitlerAdjust() then we need to call down to the
+ // miniport driver. Other wise this will have succeeded.
+ //
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ //
+ // Save the current global packet filter in a buffer that will stick around.
+ // Remove the ALL_LOCAL bit since miniport does not understand this (and does
+ // not need to).
+ //
+ *(UNALIGNED ULONG *)(Miniport->MulticastBuffer) = PacketFilter & ~NDIS_PACKET_TYPE_ALL_LOCAL;
+
+ //
+ // If the local-only bit is set and the miniport is doing it's own
+ // loop back then we need to make sure that we loop back non-self
+ // directed packets that are sent out on the pipe.
+ //
+ if ((PacketFilter & NDIS_PACKET_TYPE_ALL_LOCAL) &&
+ (Miniport->MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK) == 0)
+ {
+ MINIPORT_SET_SEND_FLAG(Miniport, fMINIPORT_SEND_LOOPBACK_DIRECTED);
+ }
+ else
+ {
+ MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_LOOPBACK_DIRECTED);
+ }
+
+ //
+ // Call the miniport driver.
+ //
+ Status = (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ Miniport->MulticastBuffer,
+ sizeof(PacketFilter),
+ &Request->DATA.SET_INFORMATION.BytesRead,
+ &Request->DATA.SET_INFORMATION.BytesNeeded);
+ }
+
+ //
+ // If we have success then set the Bytes read in the original request.
+ //
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ Request->DATA.SET_INFORMATION.BytesRead = 4;
+ }
+ else if (Status != NDIS_STATUS_PENDING)
+ {
+ Request->DATA.SET_INFORMATION.BytesRead = 0;
+ Request->DATA.SET_INFORMATION.BytesNeeded = 0;
+ }
+
+ return(Status);
+}
+
+NDIS_STATUS
+ndisMSetCurrentLookahead(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ UINT Lookahead;
+ ULONG CurrentMax;
+ PNDIS_M_OPEN_BLOCK CurrentOpen;
+ NDIS_STATUS Status;
+
+ //
+ // Verify length of the information buffer.
+ //
+ VERIFY_SET_PARAMETERS(Request, sizeof(Lookahead), Status);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ return(Status);
+ }
+
+ //
+ // Put the lookahead that the binding requests into a
+ // buffer we can use...
+ //
+ MoveMemory(&Lookahead,
+ Request->DATA.SET_INFORMATION.InformationBuffer,
+ sizeof(Lookahead));
+
+ //
+ // Verify that the lookahead is within boundaries...
+ //
+ if (Lookahead > Miniport->MaximumLookahead)
+ {
+ Request->DATA.SET_INFORMATION.BytesRead = 0;
+ Request->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ return(NDIS_STATUS_INVALID_LENGTH);
+ }
+
+ //
+ // Find the maximum lookahead between all opens that
+ // are bound to the miniport driver.
+ //
+ for (CurrentOpen = Miniport->OpenQueue, CurrentMax = 0;
+ CurrentOpen != NULL;
+ CurrentOpen = CurrentOpen->MiniportNextOpen)
+ {
+ if (CurrentOpen->CurrentLookahead > CurrentMax)
+ {
+ CurrentMax = CurrentOpen->CurrentLookahead;
+ }
+ }
+
+ //
+ // Figure in the new lookahead.
+ //
+ if (Lookahead > CurrentMax)
+ {
+ CurrentMax = Lookahead;
+ }
+
+ //
+ // Adjust the current max lookahead if needed.
+ //
+ if (CurrentMax == 0)
+ {
+ CurrentMax = Miniport->MaximumLookahead;
+ }
+
+ //
+ // Set the default status.
+ //
+ Status = NDIS_STATUS_SUCCESS;
+
+ //
+ // Do we need to call the miniport driver with the
+ // new max lookahead?
+ //
+ if (Miniport->CurrentLookahead != CurrentMax)
+ {
+ //
+ // Save the new lookahead value in a buffer
+ // that will stick around.
+ //
+ MoveMemory(Miniport->MulticastBuffer,
+ &CurrentMax,
+ sizeof(CurrentMax));
+
+ //
+ // Send it to the driver.
+ //
+ Status = (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ Miniport->MulticastBuffer,
+ sizeof(CurrentMax),
+ &Request->DATA.SET_INFORMATION.BytesRead,
+ &Request->DATA.SET_INFORMATION.BytesNeeded);
+ }
+
+ //
+ // If we succeeded then update the binding information.
+ //
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open->CurrentLookahead = Lookahead;
+ Request->DATA.SET_INFORMATION.BytesRead = sizeof(Lookahead);
+ Miniport->CurrentLookahead = CurrentMax;
+ }
+ else if (Status != NDIS_STATUS_PENDING)
+ {
+ Request->DATA.SET_INFORMATION.BytesRead = 0;
+ Request->DATA.SET_INFORMATION.BytesNeeded = 0;
+ }
+
+ return(Status);
+}
+
+NDIS_STATUS
+ndisMSetMulticastList(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ UINT NumberOfAddresses;
+ NDIS_STATUS Status;
+ PNDIS_REQUEST_RESERVED Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request);
+
+ //
+ // If the media type is not Ethernet or Ethernet encapsulated ARCnet
+ // then bail.
+ //
+ if ((Miniport->MediaType != NdisMedium802_3) &&
+ !((Miniport->MediaType == NdisMediumArcnet878_2) &&
+ MINIPORT_TEST_FLAG(Reserved->Open,
+ fMINIPORT_OPEN_USING_ETH_ENCAPSULATION)))
+ {
+ Request->DATA.SET_INFORMATION.BytesRead = 0;
+ Request->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ return(NDIS_STATUS_NOT_SUPPORTED);
+ }
+
+ //
+ // Verify the information buffer length that was passed in.
+ //
+ if ((Request->DATA.SET_INFORMATION.InformationBufferLength % ETH_LENGTH_OF_ADDRESS) != 0)
+ {
+ //
+ // The data must be a multiple of the Ethernet
+ // address size.
+ //
+ Request->DATA.SET_INFORMATION.BytesRead = 0;
+ Request->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ return(NDIS_STATUS_INVALID_DATA);
+ }
+
+ //
+ // If this request is because of an open that is closing then we
+ // have already adjusted the settings and we just need to
+ // make sure that the adapter has the new settings.
+ //
+ if (MINIPORT_TEST_FLAG(Reserved->Open, fMINIPORT_OPEN_CLOSING))
+ {
+ //
+ // By setting the Status to NDIS_STATUS_PENDING we will call
+ // down to the miniport's SetInformationHandler below.
+ //
+ Status = NDIS_STATUS_PENDING;
+ }
+ else
+ {
+ //
+ // Call the filter library for a normal set operation.
+ //
+ Status = EthChangeFilterAddresses(
+ Miniport->EthDB,
+ Reserved->Open->FilterHandle,
+ Request,
+ Request->DATA.SET_INFORMATION.InformationBufferLength / ETH_LENGTH_OF_ADDRESS,
+ Request->DATA.SET_INFORMATION.InformationBuffer,
+ TRUE);
+ }
+
+ //
+ // If the filter library returned pending then we need to
+ // call the miniport driver.
+ //
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ //
+ // Get a list of all the multicast address that need
+ // to be set.
+ //
+ EthQueryGlobalFilterAddresses(
+ &Status,
+ Miniport->EthDB,
+ NDIS_M_MAX_MULTI_LIST * ETH_LENGTH_OF_ADDRESS,
+ &NumberOfAddresses,
+ (PVOID)Miniport->MulticastBuffer);
+
+ //
+ // Call the driver with the new multicast list.
+ //
+ Status = (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ OID_802_3_MULTICAST_LIST,
+ Miniport->MulticastBuffer,
+ NumberOfAddresses * ETH_LENGTH_OF_ADDRESS,
+ &Request->DATA.SET_INFORMATION.BytesRead,
+ &Request->DATA.SET_INFORMATION.BytesNeeded);
+ }
+
+ //
+ // If we succeeded then update the request.
+ //
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ Request->DATA.SET_INFORMATION.BytesRead =
+ Request->DATA.SET_INFORMATION.InformationBufferLength;
+ }
+ else if (Status != NDIS_STATUS_PENDING)
+ {
+ Request->DATA.SET_INFORMATION.BytesRead = 0;
+ Request->DATA.SET_INFORMATION.BytesNeeded = 0;
+ }
+
+ return(Status);
+}
+
+NDIS_STATUS
+ndisMSetFunctionalAddress(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+ UINT FunctionalAddress;
+
+ //
+ // Verify the media type.
+ //
+ if (Miniport->MediaType != NdisMedium802_5)
+ {
+ Request->DATA.SET_INFORMATION.BytesRead = 0;
+ Request->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ return(NDIS_STATUS_NOT_SUPPORTED);
+ }
+
+ //
+ // Verify the buffer length that was passed in.
+ //
+ VERIFY_SET_PARAMETERS(Request, sizeof(FunctionalAddress), Status);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ return(Status);
+ }
+
+ //
+ // If this request is because of an open that is closing then we
+ // have already adjusted the settings and we just need to
+ // make sure that the adapter has the new settings.
+ //
+ if (MINIPORT_TEST_FLAG(
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open, fMINIPORT_OPEN_CLOSING))
+ {
+ //
+ // By setting the Status to NDIS_STATUS_PENDING we will call
+ // down to the miniport's SetInformationHandler below.
+ //
+ Status = NDIS_STATUS_PENDING;
+ }
+ else
+ {
+ //
+ // Call the filter library to set the functional address.
+ //
+ Status = TrChangeFunctionalAddress(
+ Miniport->TrDB,
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open->FilterHandle,
+ Request,
+ (PUCHAR)(Request->DATA.SET_INFORMATION.InformationBuffer),
+ TRUE);
+ }
+
+ //
+ // If the filter library returned NDIS_STATUS_PENDING then we
+ // need to call down to the miniport driver.
+ //
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ //
+ // Get the new combined functional address from the filter library
+ // and save it in a buffer that will stick around.
+ //
+ FunctionalAddress = TR_QUERY_FILTER_ADDRESSES(Miniport->TrDB);
+ FunctionalAddress = BYTE_SWAP_ULONG(FunctionalAddress);
+ MoveMemory(Miniport->MulticastBuffer,
+ &FunctionalAddress,
+ sizeof(FunctionalAddress));
+
+ //
+ // Call the miniport driver.
+ //
+ Status = (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ OID_802_5_CURRENT_FUNCTIONAL,
+ Miniport->MulticastBuffer,
+ sizeof(FunctionalAddress),
+ &Request->DATA.SET_INFORMATION.BytesRead,
+ &Request->DATA.SET_INFORMATION.BytesNeeded);
+ }
+
+ //
+ // If we succeeded then update the request.
+ //
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ Request->DATA.SET_INFORMATION.BytesRead =
+ Request->DATA.SET_INFORMATION.InformationBufferLength;
+ }
+ else if (Status != NDIS_STATUS_PENDING)
+ {
+ Request->DATA.SET_INFORMATION.BytesRead = 0;
+ Request->DATA.SET_INFORMATION.BytesNeeded = 0;
+ }
+
+ return(Status);
+}
+
+NDIS_STATUS
+ndisMSetGroupAddress(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+ UINT GroupAddress;
+
+ //
+ // Verify the media type.
+ //
+ if (Miniport->MediaType != NdisMedium802_5)
+ {
+ Request->DATA.SET_INFORMATION.BytesRead = 0;
+ Request->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ return(NDIS_STATUS_NOT_SUPPORTED);
+ }
+
+ //
+ // Verify the information buffer length.
+ //
+ VERIFY_SET_PARAMETERS(Request, sizeof(GroupAddress), Status);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ return(Status);
+ }
+
+ //
+ // If this request is because of an open that is closing then we
+ // have already adjusted the settings and we just need to
+ // make sure that the adapter has the new settings.
+ //
+ if (MINIPORT_TEST_FLAG(
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open, fMINIPORT_OPEN_CLOSING))
+ {
+ //
+ // By setting the Status to NDIS_STATUS_PENDING we will call
+ // down to the miniport's SetInformationHandler below.
+ //
+ Status = NDIS_STATUS_PENDING;
+ }
+ else
+ {
+ //
+ // Call the filter library to set the new group address.
+ //
+ Status = TrChangeGroupAddress(
+ Miniport->TrDB,
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open->FilterHandle,
+ Request,
+ (PUCHAR)(Request->DATA.SET_INFORMATION.InformationBuffer),
+ TRUE);
+ }
+
+ //
+ // If the filter library returned NDIS_STATUS_PENDING then we
+ // need to call down to the miniport driver.
+ //
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ //
+ // Get the new group address from the filter library
+ // and save it in a buffer that will stick around.
+ //
+ GroupAddress = TR_QUERY_FILTER_GROUP(Miniport->TrDB);
+ GroupAddress = BYTE_SWAP_ULONG(GroupAddress);
+ MoveMemory(Miniport->MulticastBuffer,
+ &GroupAddress,
+ sizeof(GroupAddress));
+
+ //
+ // Call the miniport driver with the new group address.
+ //
+ Status = (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ OID_802_5_CURRENT_GROUP,
+ Miniport->MulticastBuffer,
+ sizeof(GroupAddress),
+ &Request->DATA.SET_INFORMATION.BytesRead,
+ &Request->DATA.SET_INFORMATION.BytesNeeded);
+ }
+
+ //
+ // If we succeeded then update the request.
+ //
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ Request->DATA.SET_INFORMATION.BytesRead =
+ Request->DATA.SET_INFORMATION.InformationBufferLength;
+ }
+ else if (Status != NDIS_STATUS_PENDING)
+ {
+ Request->DATA.SET_INFORMATION.BytesRead = 0;
+ Request->DATA.SET_INFORMATION.BytesNeeded = 0;
+ }
+
+ return(Status);
+}
+
+NDIS_STATUS
+ndisMSetFddiMulticastList(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request,
+ IN BOOLEAN fShort
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+ UINT NumberOfAddresses, AddrLen;
+
+ AddrLen = FDDI_LENGTH_OF_LONG_ADDRESS;
+ if (fShort)
+ {
+ AddrLen = FDDI_LENGTH_OF_SHORT_ADDRESS;
+ }
+ //
+ // Verify the media type.
+ //
+ if (Miniport->MediaType != NdisMediumFddi)
+ {
+ Request->DATA.SET_INFORMATION.BytesRead = 0;
+ Request->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ return(NDIS_STATUS_NOT_SUPPORTED);
+ }
+
+ //
+ // Verify the information buffer length.
+ //
+ if ((Request->DATA.SET_INFORMATION.InformationBufferLength % AddrLen) != 0)
+ {
+ //
+ // The data must be a multiple of the Ethernet
+ // address size.
+ //
+ Request->DATA.SET_INFORMATION.BytesRead = 0;
+ Request->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ return(NDIS_STATUS_INVALID_DATA);
+ }
+
+ //
+ // If this request is because of an open that is closing then we
+ // have already adjusted the settings and we just need to
+ // make sure that the adapter has the new settings.
+ //
+ if (MINIPORT_TEST_FLAG(
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open, fMINIPORT_OPEN_CLOSING))
+ {
+ //
+ // By setting the Status to NDIS_STATUS_PENDING we will call
+ // down to the miniport's SetInformationHandler below.
+ //
+ Status = NDIS_STATUS_PENDING;
+ }
+ else
+ {
+ //
+ // Now call the filter package to set up the addresses.
+ //
+ Status = fShort ?
+ FddiChangeFilterShortAddresses(
+ Miniport->FddiDB,
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open->FilterHandle,
+ Request,
+ Request->DATA.SET_INFORMATION.InformationBufferLength / AddrLen,
+ Request->DATA.SET_INFORMATION.InformationBuffer,
+ TRUE) :
+ FddiChangeFilterLongAddresses(
+ Miniport->FddiDB,
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open->FilterHandle,
+ Request,
+ Request->DATA.SET_INFORMATION.InformationBufferLength / AddrLen,
+ Request->DATA.SET_INFORMATION.InformationBuffer,
+ TRUE);
+ }
+
+ //
+ // If the filter library returned NDIS_STATUS_PENDING then we
+ // need to call down to the miniport driver.
+ //
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ //
+ // Get the number of multicast addresses and the list
+ // of multicast addresses to send to the miniport driver.
+ //
+ fShort ?
+ FddiQueryGlobalFilterShortAddresses(&Status,
+ Miniport->FddiDB,
+ NDIS_M_MAX_MULTI_LIST * AddrLen,
+ &NumberOfAddresses,
+ (PVOID)Miniport->MulticastBuffer) :
+ FddiQueryGlobalFilterLongAddresses( &Status,
+ Miniport->FddiDB,
+ NDIS_M_MAX_MULTI_LIST * AddrLen,
+ &NumberOfAddresses,
+ (PVOID)Miniport->MulticastBuffer);
+
+ //
+ // Call the miniport driver.
+ //
+ Status = (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ fShort ? OID_FDDI_SHORT_MULTICAST_LIST : OID_FDDI_LONG_MULTICAST_LIST,
+ Miniport->MulticastBuffer,
+ NumberOfAddresses * AddrLen,
+ &Request->DATA.SET_INFORMATION.BytesRead,
+ &Request->DATA.SET_INFORMATION.BytesNeeded);
+ }
+
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ Request->DATA.SET_INFORMATION.BytesRead =
+ Request->DATA.SET_INFORMATION.InformationBufferLength;
+ }
+ else if (Status != NDIS_STATUS_PENDING)
+ {
+ Request->DATA.SET_INFORMATION.BytesRead = 0;
+ Request->DATA.SET_INFORMATION.BytesNeeded = 0;
+ }
+
+ return(Status);
+}
+
+NDIS_STATUS
+ndisMSetInformation(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+
+ //
+ // If there is no open associated with the request
+ // then it is an internal request and we just send it down
+ // to the adapter.
+ //
+ if (PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open == NULL)
+ {
+ Status = (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ Request->DATA.SET_INFORMATION.Oid,
+ Request->DATA.SET_INFORMATION.InformationBuffer,
+ Request->DATA.SET_INFORMATION.InformationBufferLength,
+ &Request->DATA.SET_INFORMATION.BytesRead,
+ &Request->DATA.SET_INFORMATION.BytesNeeded);
+
+ return(Status);
+ }
+
+ //
+ // Process the binding's request.
+ //
+ switch (Request->DATA.SET_INFORMATION.Oid)
+ {
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ //
+ // Set the packet filter.
+ //
+ Status = ndisMSetPacketFilter(Miniport, Request);
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ //
+ // Set the current look ahead for the miniport.
+ //
+ Status = ndisMSetCurrentLookahead(Miniport, Request);
+
+ break;
+
+ case OID_GEN_PROTOCOL_OPTIONS:
+
+ VERIFY_SET_PARAMETERS(Request, sizeof(ULONG), Status);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ //
+ // Copy the protocol options into the open block.
+ //
+ MoveMemory(&PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open->ProtocolOptions,
+ Request->DATA.SET_INFORMATION.InformationBuffer,
+ sizeof(ULONG));
+
+ Request->DATA.SET_INFORMATION.BytesRead = sizeof(ULONG);
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+
+ //
+ // Set the ethernet multicast list.
+ //
+ Status = ndisMSetMulticastList(Miniport, Request);
+ break;
+
+ case OID_802_5_CURRENT_FUNCTIONAL:
+
+ //
+ // Set the token ring functional address.
+ //
+ Status = ndisMSetFunctionalAddress(Miniport, Request);
+ break;
+
+ case OID_802_5_CURRENT_GROUP:
+
+ //
+ // Set the token ring group address.
+ //
+ Status = ndisMSetGroupAddress(Miniport, Request);
+
+ break;
+
+ case OID_FDDI_LONG_MULTICAST_LIST:
+
+ //
+ // Set the FDDI long multicast list.
+ //
+ Status = ndisMSetFddiMulticastList(Miniport, Request, FALSE);
+
+ break;
+
+ case OID_FDDI_SHORT_MULTICAST_LIST:
+
+ //
+ // Set the FDDI short multicast list.
+ //
+ Status = ndisMSetFddiMulticastList(Miniport, Request, TRUE);
+
+ break;
+
+ default:
+ Status =
+ (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ Request->DATA.SET_INFORMATION.Oid,
+ Request->DATA.SET_INFORMATION.InformationBuffer,
+ Request->DATA.SET_INFORMATION.InformationBufferLength,
+ &Request->DATA.SET_INFORMATION.BytesRead,
+ &Request->DATA.SET_INFORMATION.BytesNeeded);
+ break;
+ }
+
+ return(Status);
+}
+
+NDIS_STATUS
+ndisMQueryCurrentPacketFilter(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ ULONG PacketFilter;
+ NDIS_HANDLE FilterHandle;
+ NDIS_STATUS Status;
+
+ //
+ // Verify the buffer that was passed to us.
+ //
+ VERIFY_QUERY_PARAMETERS(Request, sizeof(PacketFilter), Status);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ return(Status);
+ }
+
+ //
+ // Get the filter handle from the open block.
+ //
+ FilterHandle = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open->FilterHandle;
+
+ //
+ // Get the packet filter from the filter library.
+ //
+ switch (Miniport->MediaType)
+ {
+ case NdisMedium802_3:
+ PacketFilter = ETH_QUERY_PACKET_FILTER(Miniport->EthDB, FilterHandle);
+
+ break;
+
+ case NdisMedium802_5:
+ PacketFilter = TR_QUERY_PACKET_FILTER(Miniport->TrDB, FilterHandle);
+ break;
+
+ case NdisMediumFddi:
+ PacketFilter = FDDI_QUERY_PACKET_FILTER(Miniport->FddiDB, FilterHandle);
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ if (MINIPORT_TEST_FLAG(
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open,
+ fMINIPORT_OPEN_USING_ETH_ENCAPSULATION))
+ {
+ PacketFilter = ETH_QUERY_PACKET_FILTER(Miniport->EthDB, FilterHandle);
+ }
+ else
+ {
+ PacketFilter = ARC_QUERY_PACKET_FILTER(Miniport->ArcDB, FilterHandle);
+ }
+ break;
+ }
+
+ //
+ // Place the packet filter in the buffer that was passed in.
+ //
+ MoveMemory(Request->DATA.QUERY_INFORMATION.InformationBuffer,
+ &PacketFilter,
+ sizeof(PacketFilter));
+
+ Request->DATA.QUERY_INFORMATION.BytesWritten = sizeof(PacketFilter);
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+ndisMQueryMediaSupported(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ ULONG MediaType;
+ NDIS_STATUS Status;
+
+ //
+ // Verify the size of the buffer that was passed in by the binding.
+ //
+ VERIFY_QUERY_PARAMETERS(Request, sizeof(MediaType), Status);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ return(Status);
+ }
+
+ //
+ // Default the media type to what the miniport knows it is.
+ //
+ MediaType = (ULONG)Miniport->MediaType;
+
+ //
+ // If we are doing ethernet encapsulation then lie.
+ //
+ if ((NdisMediumArcnet878_2 == Miniport->MediaType) &&
+ MINIPORT_TEST_FLAG(PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open,
+ fMINIPORT_OPEN_USING_ETH_ENCAPSULATION))
+ {
+ //
+ // Tell the binding that we are ethernet.
+ //
+ MediaType = (ULONG)NdisMedium802_3;
+ }
+
+ //
+ // Save it in the request.
+ //
+ MoveMemory(Request->DATA.QUERY_INFORMATION.InformationBuffer,
+ &MediaType,
+ sizeof(MediaType));
+
+ Request->DATA.QUERY_INFORMATION.BytesWritten = sizeof(MediaType);
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+ndisMQueryEthernetMulticastList(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+ UINT NumberOfAddresses;
+
+ //
+ // call the filter library to get the list of multicast
+ // addresses for this open
+ //
+ EthQueryOpenFilterAddresses(&Status,
+ Miniport->EthDB,
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open->FilterHandle,
+ Request->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &NumberOfAddresses,
+ Request->DATA.QUERY_INFORMATION.InformationBuffer);
+
+ //
+ // If the library returned NDIS_STATUS_FAILURE then the buffer
+ // was not big enough. So call back down to determine how
+ // much buffer space we need.
+ //
+ if (NDIS_STATUS_FAILURE == Status)
+ {
+ Request->DATA.QUERY_INFORMATION.BytesNeeded =
+ ETH_LENGTH_OF_ADDRESS *
+ EthNumberOfOpenFilterAddresses(
+ Miniport->EthDB,
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open->FilterHandle);
+
+ Request->DATA.QUERY_INFORMATION.BytesWritten = 0;
+
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ }
+ else
+ {
+ Request->DATA.QUERY_INFORMATION.BytesNeeded = 0;
+ Request->DATA.QUERY_INFORMATION.BytesWritten =
+ NumberOfAddresses * ETH_LENGTH_OF_ADDRESS;
+ }
+
+ return(Status);
+}
+
+NDIS_STATUS
+ndisMQueryLongMulticastList(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+ UINT NumberOfAddresses;
+
+ //
+ // Call the filter library to get the list of long
+ // multicast address for this open.
+ //
+ FddiQueryOpenFilterLongAddresses(
+ &Status,
+ Miniport->FddiDB,
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open->FilterHandle,
+ Request->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &NumberOfAddresses,
+ Request->DATA.QUERY_INFORMATION.InformationBuffer);
+
+
+ //
+ // If the library returned NDIS_STATUS_FAILURE then the buffer
+ // was not big enough. So call back down to determine how
+ // much buffer space we need.
+ //
+ if (NDIS_STATUS_FAILURE == Status)
+ {
+ Request->DATA.QUERY_INFORMATION.BytesNeeded =
+ FDDI_LENGTH_OF_LONG_ADDRESS *
+ FddiNumberOfOpenFilterLongAddresses(
+ Miniport->FddiDB,
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open->FilterHandle);
+
+
+ Request->DATA.QUERY_INFORMATION.BytesWritten = 0;
+
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ }
+ else
+ {
+ Request->DATA.QUERY_INFORMATION.BytesNeeded = 0;
+ Request->DATA.QUERY_INFORMATION.BytesWritten =
+ NumberOfAddresses * FDDI_LENGTH_OF_LONG_ADDRESS;
+ }
+
+ return(Status);
+}
+
+NDIS_STATUS
+ndisMQueryShortMulticastList(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+ UINT NumberOfAddresses;
+
+ //
+ // Call the filter library to get the list of long
+ // multicast address for this open.
+ //
+ FddiQueryOpenFilterShortAddresses(
+ &Status,
+ Miniport->FddiDB,
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open->FilterHandle,
+ Request->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &NumberOfAddresses,
+ Request->DATA.QUERY_INFORMATION.InformationBuffer);
+
+
+ //
+ // If the library returned NDIS_STATUS_FAILURE then the buffer
+ // was not big enough. So call back down to determine how
+ // much buffer space we need.
+ //
+ if (NDIS_STATUS_FAILURE == Status)
+ {
+ Request->DATA.QUERY_INFORMATION.BytesNeeded =
+ FDDI_LENGTH_OF_SHORT_ADDRESS *
+ FddiNumberOfOpenFilterShortAddresses(
+ Miniport->FddiDB,
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open->FilterHandle);
+
+ Request->DATA.QUERY_INFORMATION.BytesWritten = 0;
+
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ }
+ else
+ {
+ Request->DATA.QUERY_INFORMATION.BytesNeeded = 0;
+ Request->DATA.QUERY_INFORMATION.BytesWritten =
+ NumberOfAddresses * FDDI_LENGTH_OF_SHORT_ADDRESS;
+ }
+
+ return(Status);
+}
+
+NDIS_STATUS
+ndisMQueryMaximumFrameSize(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+ PULONG pulBuffer = Request->DATA.QUERY_INFORMATION.InformationBuffer;
+
+ VERIFY_QUERY_PARAMETERS(Request, sizeof(*pulBuffer), Status);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ return(Status);
+ }
+
+ //
+ // Is this ARCnet using encapsulated ethernet?
+ //
+ if (Miniport->MediaType == NdisMediumArcnet878_2)
+ {
+ if (MINIPORT_TEST_FLAG(
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open,
+ fMINIPORT_OPEN_USING_ETH_ENCAPSULATION))
+ {
+ //
+ // 504 - 14 (ethernet header) == 490.
+ //
+ *pulBuffer = ARC_MAX_FRAME_SIZE - 14;
+ Request->DATA.QUERY_INFORMATION.BytesWritten = sizeof(*pulBuffer);
+
+ return(NDIS_STATUS_SUCCESS);
+ }
+ }
+
+ //
+ // Call the miniport for the information.
+ //
+ Status = (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ Request->DATA.QUERY_INFORMATION.Oid,
+ Request->DATA.QUERY_INFORMATION.InformationBuffer,
+ Request->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &(Request->DATA.QUERY_INFORMATION.BytesWritten),
+ &(Request->DATA.QUERY_INFORMATION.BytesNeeded));
+
+ return(Status);
+}
+
+NDIS_STATUS
+ndisMQueryMaximumTotalSize(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+ PULONG pulBuffer = Request->DATA.QUERY_INFORMATION.InformationBuffer;
+
+ VERIFY_QUERY_PARAMETERS(Request, sizeof(*pulBuffer), Status);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ return(Status);
+ }
+
+ //
+ // Is this ARCnet using encapsulated ethernet?
+ //
+ if (Miniport->MediaType == NdisMediumArcnet878_2)
+ {
+ if (MINIPORT_TEST_FLAG(
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open,
+ fMINIPORT_OPEN_USING_ETH_ENCAPSULATION))
+ {
+ *pulBuffer = ARC_MAX_FRAME_SIZE;
+ Request->DATA.QUERY_INFORMATION.BytesWritten = sizeof(*pulBuffer);
+
+ return(NDIS_STATUS_SUCCESS);
+ }
+ }
+
+ //
+ // Call the miniport for the information.
+ //
+ Status = (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ Request->DATA.QUERY_INFORMATION.Oid,
+ Request->DATA.QUERY_INFORMATION.InformationBuffer,
+ Request->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &(Request->DATA.QUERY_INFORMATION.BytesWritten),
+ &(Request->DATA.QUERY_INFORMATION.BytesNeeded));
+
+ return(Status);
+}
+
+NDIS_STATUS
+ndisMQueryNetworkAddress(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+ UCHAR Address[ETH_LENGTH_OF_ADDRESS];
+
+ VERIFY_QUERY_PARAMETERS(Request, ETH_LENGTH_OF_ADDRESS, Status);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ return(Status);
+ }
+
+ //
+ // Is this ARCnet using encapsulated ethernet?
+ //
+ if (Miniport->MediaType == NdisMediumArcnet878_2)
+ {
+ if (MINIPORT_TEST_FLAG(
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open,
+ fMINIPORT_OPEN_USING_ETH_ENCAPSULATION))
+ {
+ //
+ // Arcnet-to-ethernet conversion.
+ //
+ ZeroMemory(Address, ETH_LENGTH_OF_ADDRESS);
+
+ Address[5] = Miniport->ArcnetAddress;
+
+ MoveMemory(Request->DATA.QUERY_INFORMATION.InformationBuffer,
+ Address,
+ ETH_LENGTH_OF_ADDRESS);
+
+ Request->DATA.QUERY_INFORMATION.BytesWritten = ETH_LENGTH_OF_ADDRESS;
+
+ return(NDIS_STATUS_SUCCESS);
+ }
+ }
+
+ //
+ // Call the miniport for the information.
+ //
+ Status = (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ Request->DATA.QUERY_INFORMATION.Oid,
+ Request->DATA.QUERY_INFORMATION.InformationBuffer,
+ Request->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &(Request->DATA.QUERY_INFORMATION.BytesWritten),
+ &(Request->DATA.QUERY_INFORMATION.BytesNeeded)
+ );
+
+ return(Status);
+}
+
+NDIS_STATUS
+ndisMQueryInformation(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+ PVOID Buffer;
+ PULONG pulBuffer;
+ ULONG BufferLength;
+ PNDIS_M_OPEN_BLOCK Open;
+ ULONG Generic;
+
+ //
+ // Copy the request information into temporary storage.
+ //
+ Buffer = Request->DATA.QUERY_INFORMATION.InformationBuffer;
+ pulBuffer = Buffer;
+ BufferLength = Request->DATA.QUERY_INFORMATION.InformationBufferLength;
+
+ Open = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open;
+
+ //
+ // We intercept some calls.
+ //
+ switch (Request->DATA.QUERY_INFORMATION.Oid)
+ {
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ Status = ndisMQueryCurrentPacketFilter(Miniport, Request);
+
+ break;
+
+ case OID_GEN_MEDIA_IN_USE:
+ case OID_GEN_MEDIA_SUPPORTED:
+
+ Status = ndisMQueryMediaSupported(Miniport, Request);
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ VERIFY_QUERY_PARAMETERS(
+ Request,
+ sizeof(Open->CurrentLookahead),
+ Status);
+
+ //
+ // Save the lookahead in the binding's buffer.
+ //
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ *pulBuffer = Open->CurrentLookahead;
+ Request->DATA.QUERY_INFORMATION.BytesWritten =
+ sizeof(Open->CurrentLookahead);
+ }
+
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+
+ VERIFY_QUERY_PARAMETERS(
+ Request,
+ sizeof(Miniport->MaximumLookahead),
+ Status);
+
+ //
+ // Save the lookahead in the binding's buffer.
+ //
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ *pulBuffer = Miniport->MaximumLookahead;
+ Request->DATA.QUERY_INFORMATION.BytesWritten =
+ sizeof(Miniport->MaximumLookahead);
+ }
+
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+
+ Status = ndisMQueryEthernetMulticastList(Miniport, Request);
+
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+
+ VERIFY_QUERY_PARAMETERS(
+ Request,
+ sizeof(Miniport->MaximumLongAddresses),
+ Status);
+
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ *pulBuffer = Miniport->MaximumLongAddresses;
+ Request->DATA.QUERY_INFORMATION.BytesWritten =
+ sizeof(Miniport->MaximumLongAddresses);
+ }
+
+ break;
+
+ case OID_802_5_CURRENT_FUNCTIONAL:
+
+ VERIFY_QUERY_PARAMETERS(
+ Request,
+ sizeof(*pulBuffer),
+ Status);
+
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ Generic = TR_QUERY_FILTER_BINDING_ADDRESS(
+ Miniport->TrDB,
+ Open->FilterHandle
+ );
+
+ *pulBuffer = BYTE_SWAP_ULONG(Generic);
+ Request->DATA.QUERY_INFORMATION.BytesWritten =
+ sizeof(*pulBuffer);
+ }
+
+ break;
+
+ case OID_802_5_CURRENT_GROUP:
+
+ VERIFY_QUERY_PARAMETERS(
+ Request,
+ sizeof(*pulBuffer),
+ Status);
+
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ *pulBuffer = TR_QUERY_FILTER_GROUP(Miniport->TrDB);
+ *pulBuffer = BYTE_SWAP_ULONG(*pulBuffer);
+ Request->DATA.QUERY_INFORMATION.BytesWritten =
+ sizeof(*pulBuffer);
+ }
+
+ break;
+
+ case OID_FDDI_LONG_MULTICAST_LIST:
+
+ Status = ndisMQueryLongMulticastList(Miniport, Request);
+
+ break;
+
+ case OID_FDDI_LONG_MAX_LIST_SIZE:
+
+ VERIFY_QUERY_PARAMETERS(
+ Request,
+ sizeof(*pulBuffer),
+ Status);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ *pulBuffer = Miniport->MaximumLongAddresses;
+ Request->DATA.QUERY_INFORMATION.BytesWritten =
+ sizeof(*pulBuffer);
+ }
+
+ break;
+
+ case OID_FDDI_SHORT_MULTICAST_LIST:
+
+ Status = ndisMQueryShortMulticastList(Miniport, Request);
+
+ break;
+
+ case OID_FDDI_SHORT_MAX_LIST_SIZE:
+
+ VERIFY_QUERY_PARAMETERS(
+ Request,
+ sizeof(Miniport->MaximumShortAddresses),
+ Status);
+
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ *pulBuffer = Miniport->MaximumShortAddresses;
+ Request->DATA.QUERY_INFORMATION.BytesWritten =
+ sizeof(Miniport->MaximumShortAddresses);
+ }
+
+ break;
+
+ //
+ // Start interceptions for running an ethernet
+ // protocol on top of an arcnet mini-port.
+ //
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+
+ Status = ndisMQueryMaximumFrameSize(Miniport, Request);
+
+ break;
+
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+
+ Status = ndisMQueryMaximumTotalSize(Miniport, Request);
+
+ break;
+
+ case OID_802_3_PERMANENT_ADDRESS:
+ case OID_802_3_CURRENT_ADDRESS:
+
+ Status = ndisMQueryNetworkAddress(Miniport, Request);
+
+ break;
+
+ default:
+
+ //
+ // We don't filter this request, just pass it down
+ // to the driver.
+ //
+ Status = (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ Request->DATA.QUERY_INFORMATION.Oid,
+ Request->DATA.QUERY_INFORMATION.InformationBuffer,
+ Request->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &Request->DATA.QUERY_INFORMATION.BytesWritten,
+ &Request->DATA.QUERY_INFORMATION.BytesNeeded);
+
+ break;
+ }
+
+ return(Status);
+}
+
+
+VOID
+ndisMDoRequests(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Submits a request to the mini-port.
+
+Arguments:
+
+ Miniport - Miniport to send to.
+
+Return Value:
+
+ TRUE if we need to place the work item back on the queue to process later.
+ FALSE if we are done with the work item.
+
+--*/
+
+{
+ NDIS_STATUS Status;
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Enter do requests\n"));
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ //
+ // Do we have a request in progress?
+ //
+ while ((Miniport->MiniportRequest == NULL) && (Miniport->PendingRequest != NULL))
+ {
+ PNDIS_REQUEST_RESERVED Reserved;
+ PNDIS_REQUEST NdisRequest;
+ UINT MulticastAddresses;
+ ULONG PacketFilter;
+ BOOLEAN DoMove;
+ PVOID MoveSource;
+ UINT MoveBytes;
+ ULONG GenericULong;
+
+ //
+ // Set defaults.
+ //
+ DoMove = TRUE;
+ Status = NDIS_STATUS_SUCCESS;
+
+ //
+ // Remove first request
+ //
+ NdisRequest = Miniport->PendingRequest;
+ Miniport->PendingRequest = PNDIS_RESERVED_FROM_PNDIS_REQUEST(NdisRequest)->Next;
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Starting protocol request 0x%x\n", NdisRequest));
+
+ //
+ // Clear the timeout flag.
+ //
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_REQUEST_TIMEOUT);
+
+ //
+ // Put it on mini-port queue
+ //
+ Miniport->MiniportRequest = NdisRequest;
+
+ //
+ // Submit to mini-port
+ //
+ switch (NdisRequest->RequestType)
+ {
+ case NdisRequestQueryInformation:
+
+ //
+ // Process the query information.
+ //
+ Status = ndisMQueryInformation(Miniport, NdisRequest);
+
+ break;
+
+ case NdisRequestQueryStatistics:
+
+ //
+ // Query GLOBAL statistics
+ //
+ MoveSource = &GenericULong;
+ MoveBytes = sizeof(GenericULong);
+
+ //
+ // We intercept some calls
+ //
+
+ switch (NdisRequest->DATA.QUERY_INFORMATION.Oid)
+ {
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ switch (Miniport->MediaType)
+ {
+ case NdisMedium802_3:
+ PacketFilter = ETH_QUERY_FILTER_CLASSES(Miniport->EthDB);
+ break;
+
+ case NdisMedium802_5:
+ PacketFilter = TR_QUERY_FILTER_CLASSES(Miniport->TrDB);
+ break;
+
+ case NdisMediumFddi:
+ PacketFilter = FDDI_QUERY_FILTER_CLASSES(Miniport->FddiDB);
+ break;
+
+ case NdisMediumArcnet878_2:
+ PacketFilter = ARC_QUERY_FILTER_CLASSES(Miniport->ArcDB);
+ PacketFilter |= ETH_QUERY_FILTER_CLASSES(Miniport->EthDB);
+ break;
+ }
+
+ GenericULong = (ULONG)(PacketFilter);
+ break;
+
+ case OID_GEN_MEDIA_IN_USE:
+ case OID_GEN_MEDIA_SUPPORTED:
+ MoveSource = (PVOID) (&Miniport->MediaType);
+ MoveBytes = sizeof(NDIS_MEDIUM);
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ GenericULong = (ULONG)(Miniport->CurrentLookahead);
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+ GenericULong = (ULONG)(Miniport->MaximumLookahead);
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+
+ EthQueryGlobalFilterAddresses(
+ &Status,
+ Miniport->EthDB,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &MulticastAddresses,
+ (PVOID)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer));
+
+ MoveSource = (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
+ MoveBytes = MulticastAddresses * ETH_LENGTH_OF_ADDRESS;
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+ GenericULong = Miniport->MaximumLongAddresses;
+ break;
+
+ case OID_802_5_CURRENT_FUNCTIONAL:
+ GenericULong = TR_QUERY_FILTER_ADDRESSES(Miniport->TrDB);
+ GenericULong = BYTE_SWAP_ULONG(GenericULong);
+ break;
+
+ case OID_802_5_CURRENT_GROUP:
+ GenericULong = TR_QUERY_FILTER_GROUP(Miniport->TrDB);
+ GenericULong = BYTE_SWAP_ULONG(GenericULong);
+ break;
+
+ case OID_FDDI_LONG_MULTICAST_LIST:
+ FddiQueryGlobalFilterLongAddresses(
+ &Status,
+ Miniport->FddiDB,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &MulticastAddresses,
+ (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+
+ MoveSource = (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
+ MoveBytes = FDDI_LENGTH_OF_LONG_ADDRESS * MulticastAddresses;
+ break;
+
+ case OID_FDDI_LONG_MAX_LIST_SIZE:
+ GenericULong = Miniport->MaximumLongAddresses;
+ break;
+
+ case OID_FDDI_SHORT_MULTICAST_LIST:
+ FddiQueryGlobalFilterShortAddresses(
+ &Status,
+ Miniport->FddiDB,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &MulticastAddresses,
+ (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+
+ MoveSource = (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
+ MoveBytes = FDDI_LENGTH_OF_SHORT_ADDRESS * MulticastAddresses;
+ break;
+
+ case OID_FDDI_SHORT_MAX_LIST_SIZE:
+ GenericULong = Miniport->MaximumShortAddresses;
+ break;
+
+ default:
+ DoMove = FALSE;
+
+ Status =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ NdisRequest->DATA.QUERY_INFORMATION.Oid,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &NdisRequest->DATA.QUERY_INFORMATION.BytesWritten,
+ &NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded);
+ break;
+ }
+
+ if (DoMove)
+ {
+ //
+ // This was an intercepted request. Finish it off
+ //
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (MoveBytes >
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength)
+ {
+ //
+ // Not enough room in InformationBuffer. Punt
+ //
+ NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = MoveBytes;
+
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ }
+ else
+ {
+ //
+ // Copy result into InformationBuffer
+ //
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesWritten = MoveBytes;
+
+ if ((MoveBytes > 0) &&
+ (MoveSource != NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer))
+ {
+ MoveMemory(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
+ MoveSource,
+ MoveBytes);
+ }
+ }
+ }
+ else
+ {
+ NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = MoveBytes;
+ }
+ }
+ break;
+
+ case NdisRequestSetInformation:
+
+ //
+ // Process the set infromation.
+ //
+ Status = ndisMSetInformation(Miniport, NdisRequest);
+
+ break;
+ }
+
+ //
+ // Did the request pend? If so then there is nothing more to do.
+ //
+ if ((Status == NDIS_STATUS_PENDING) &&
+ (Miniport->MiniportRequest != NULL))
+ {
+ //
+ // Still outstanding
+ //
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Request pending, exit do requests\n"));
+
+ break;
+ }
+
+ //
+ // Complete request
+ //
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ switch (NdisRequest->RequestType)
+ {
+ case NdisRequestQueryStatistics:
+ case NdisRequestQueryInformation:
+
+ ndisMSyncQueryInformationComplete(Miniport, Status);
+ break;
+
+ case NdisRequestSetInformation:
+
+ ndisMSyncSetInformationComplete(Miniport, Status);
+ break;
+ }
+ }
+ }
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Exit do requests\n"));
+}
+
+//
+// IRP handlers established on behalf of NDIS devices by
+// the wrapper.
+//
+
+NTSTATUS
+ndisMQueryOidList(
+ IN PNDIS_USER_OPEN_CONTEXT OpenContext,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will take care of querying the complete OID
+ list for the driver and filling in OpenContext->OidArray
+ with the ones that are statistics. It blocks when the
+ driver pends and so is synchronous.
+
+Arguments:
+
+ OpenContext - The open context.
+ Irp = The IRP that the open was done on (used at completion
+ to distinguish the request).
+
+Return Value:
+
+ STATUS_SUCCESS if it should be.
+
+--*/
+
+{
+ NDIS_QUERY_OPEN_REQUEST OpenRequest;
+ NDIS_STATUS NdisStatus;
+ PNDIS_OID TmpBuffer;
+ ULONG TmpBufferLength;
+ PNDIS_REQUEST_RESERVED Reserved;
+ BOOLEAN LocalLock;
+ PNDIS_MINIPORT_BLOCK Miniport = OpenContext->MiniportBlock;
+ KIRQL OldIrql;
+ PSINGLE_LIST_ENTRY Link;
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Enter query oid list\n"));
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ do
+ {
+ //
+ // First query the OID list with no buffer, to find out
+ // how big it should be.
+ //
+
+ INITIALIZE_EVENT(&OpenRequest.Event);
+
+ OpenRequest.Irp = Irp;
+
+ //
+ // Build fake request
+ //
+
+ OpenRequest.Request.RequestType = NdisRequestQueryStatistics;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_SUPPORTED_LIST;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBuffer = NULL;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBufferLength = 0;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded = 0;
+
+ //
+ // Put request on queue
+ //
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(&OpenRequest.Request);
+ ndisMQueueRequest(Miniport, &OpenRequest.Request, NULL);
+
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+
+ if (LocalLock)
+ {
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+ WAIT_FOR_OBJECT(&OpenRequest.Event, NULL);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisStatus = OpenRequest.NdisStatus;
+
+ if ((NdisStatus != NDIS_STATUS_INVALID_LENGTH) &&
+ (NdisStatus != NDIS_STATUS_BUFFER_TOO_SHORT))
+ {
+ break;
+ }
+
+ //
+ // Now we know how much is needed, allocate temp storage...
+ //
+ TmpBufferLength = OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded;
+ TmpBuffer = ALLOC_FROM_POOL(TmpBufferLength, NDIS_TAG_DEFAULT);
+
+ if (TmpBuffer == NULL)
+ {
+ NdisStatus = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ //
+ // ...and query the real list.
+ //
+
+ RESET_EVENT(&OpenRequest.Event);
+
+ OpenRequest.Request.RequestType = NdisRequestQueryStatistics;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_SUPPORTED_LIST;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBuffer = TmpBuffer;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBufferLength = TmpBufferLength;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded = 0;
+
+ //
+ // Put request on queue
+ //
+
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(&OpenRequest.Request);
+ ndisMQueueRequest(Miniport, &OpenRequest.Request, NULL);
+
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+
+ if (LocalLock)
+ {
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ WAIT_FOR_OBJECT(&OpenRequest.Event, NULL);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisStatus = OpenRequest.NdisStatus;
+
+ ASSERT(NdisStatus == NDIS_STATUS_SUCCESS);
+
+ NdisStatus = ndisSplitStatisticsOids(OpenContext,
+ TmpBuffer,
+ TmpBufferLength/sizeof(NDIS_OID));
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Exit query oid list\n"));
+
+ FREE_POOL(TmpBuffer);
+ } while (FALSE);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ return(NdisStatus);
+}
+
+
+VOID
+ndisMCloseAction(
+ IN NDIS_HANDLE MacBindingHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when a particular binding
+ was closed while it was indicating through NdisIndicateReceive
+
+ All this routine needs to do is to decrement the reference count
+ of the binding.
+
+ NOTE: This routine assumes that it is called with the lock acquired.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the driver when the
+ adapter was opened. In reality, it is a pointer to W_OPEN_BLOCK.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ PNDIS_M_OPEN_BLOCK Open = PNDIS_M_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+ PNDIS_MINIPORT_BLOCK Miniport = Open->MiniportHandle;
+
+ DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_INFO,
+ ("ndisMCloseAction()\n"));
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("- Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ Open->References--;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("==0 Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ if (Open->References == 0)
+ {
+ ndisMFinishClose(Miniport,Open);
+ }
+}
+
+
+NDIS_STATUS
+ndisMChangeFunctionalAddress(
+ IN TR_FUNCTIONAL_ADDRESS OldFunctionalAddress,
+ IN TR_FUNCTIONAL_ADDRESS NewFunctionalAddress,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when an address is added to
+ the filter that wasn't referenced by any other open binding.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ OldFunctionalAddress - The previous functional address.
+
+ NewFunctionalAddress - The new functional address.
+
+ MacBindingHandle - The context value returned by the driver when the
+ adapter was opened. In reality, it is a pointer to W_OPEN_BLOCK.
+
+ NdisRequest - A pointer to the Request that submitted the set command.
+
+ Set - If true the change resulted from a set, otherwise the
+ change resulted from a open closing.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_INFO,
+ ("ndisMChangeFunctionalAddress()\n"));
+
+ return(NDIS_STATUS_PENDING);
+}
+
+
+NDIS_STATUS
+ndisMChangeGroupAddress(
+ IN TR_FUNCTIONAL_ADDRESS OldGroupAddress,
+ IN TR_FUNCTIONAL_ADDRESS NewGroupAddress,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when a group address is to
+ be changed.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ OldGroupAddress - The previous group address.
+
+ NewGroupAddress - The new group address.
+
+ MacBindingHandle - The context value returned by the driver when the
+ adapter was opened. In reality, it is a pointer to W_OPEN_BLOCK.
+
+ NdisRequest - A pointer to the Request that submitted the set command.
+
+ Set - If true the change resulted from a set, otherwise the
+ change resulted from a open closing.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_INFO,
+ ("ndisMChangeGroupAddress()\n"));
+
+ return(NDIS_STATUS_PENDING);
+}
+
+
+NDIS_STATUS
+ndisMChangeFddiAddresses(
+ IN UINT oldLongAddressCount,
+ IN CHAR oldLongAddresses[][FDDI_LENGTH_OF_LONG_ADDRESS],
+ IN UINT newLongAddressCount,
+ IN CHAR newLongAddresses[][FDDI_LENGTH_OF_LONG_ADDRESS],
+ IN UINT oldShortAddressCount,
+ IN CHAR oldShortAddresses[][FDDI_LENGTH_OF_SHORT_ADDRESS],
+ IN UINT newShortAddressCount,
+ IN CHAR newShortAddresses[][FDDI_LENGTH_OF_SHORT_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when the multicast address
+ list has changed.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ oldAddressCount - The number of addresses in oldAddresses.
+
+ oldAddresses - The old multicast address list.
+
+ newAddressCount - The number of addresses in newAddresses.
+
+ newAddresses - The new multicast address list.
+
+ macBindingHandle - The context value returned by the driver when the
+ adapter was opened. In reality, it is a pointer to W_OPEN_BLOCK.
+
+ requestHandle - A value supplied by the NDIS interface that the driver
+ must use when completing this request.
+
+ Set - If true the change resulted from a set, otherwise the
+ change resulted from a open closing.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_INFO,
+ ("ndisMChangeFddiAddresses()\n"));
+
+ return(NDIS_STATUS_PENDING);
+}
+
+
+NDIS_STATUS
+ndisMChangeEthAddresses(
+ IN UINT OldAddressCount,
+ IN CHAR OldAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN UINT NewAddressCount,
+ IN CHAR NewAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when the multicast address
+ list has changed.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ OldAddressCount - The number of addresses in OldAddresses.
+
+ OldAddresses - The old multicast address list.
+
+ NewAddressCount - The number of addresses in NewAddresses.
+
+ NewAddresses - The new multicast address list.
+
+ MacBindingHandle - The context value returned by the driver when the
+ adapter was opened. In reality, it is a pointer to W_OPEN_BLOCK.
+
+ RequestHandle - A value supplied by the NDIS interface that the driver
+ must use when completing this request.
+
+ Set - If true the change resulted from a set, otherwise the
+ change resulted from a open closing.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ PNDIS_M_OPEN_BLOCK Open = PNDIS_M_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+ PNDIS_MINIPORT_BLOCK Miniport = Open->MiniportHandle;
+
+ DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_INFO,
+ ("Enter ChangeEthAddresses\n"));
+
+ if ((Miniport->MediaType == NdisMediumArcnet878_2) &&
+ MINIPORT_TEST_FLAG(Open, fMINIPORT_OPEN_USING_ETH_ENCAPSULATION))
+ {
+ if (NewAddressCount > 0)
+ {
+ //
+ // Turn on broadcast acceptance.
+ //
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_ARCNET_BROADCAST_SET);
+ }
+ else
+ {
+ //
+ // Unset the broadcast filter.
+ //
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_ARCNET_BROADCAST_SET);
+ }
+
+ //
+ // Need to return success here so that we don't call down to the
+ // ARCnet miniport with an invalid OID, i.e. an ethernet one....
+ //
+ return(NDIS_STATUS_SUCCESS);
+ }
+
+ DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_INFO,
+ ("ndisMChangeEthAddresses()\n"));
+
+ return(NDIS_STATUS_PENDING);
+}
+
+
+NDIS_STATUS
+ndisMChangeClass(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when a particular filter
+ class is first used or last cleared.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ OldFilterClasses - The values of the class filter before it
+ was changed.
+
+ NewFilterClasses - The current value of the class filter
+
+ MacBindingHandle - The context value returned by the driver when the
+ adapter was opened. In reality, it is a pointer to W_OPEN_BLOCK.
+
+ RequestHandle - A value supplied by the NDIS interface that the driver
+ must use when completing this request.
+
+ Set - If true the change resulted from a set, otherwise the
+ change resulted from a open closing.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_INFO,
+ ("ndisMChangeClass()\n"));
+
+ return(NDIS_STATUS_PENDING);
+}
+
diff --git a/private/ntos/ndis/ndis40/sendm.c b/private/ntos/ndis/ndis40/sendm.c
new file mode 100644
index 000000000..8e3dfc7c4
--- /dev/null
+++ b/private/ntos/ndis/ndis40/sendm.c
@@ -0,0 +1,3212 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ sendm.c
+
+Abstract:
+
+Author:
+
+ Kyle Brandon (KyleB)
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+#include "sendm.h"
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_SENDM
+
+VOID
+ndisMCopyFromPacketToBuffer(
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ IN UINT BytesToCopy,
+ OUT PCHAR Buffer,
+ OUT PUINT BytesCopied
+ )
+
+/*++
+
+Routine Description:
+
+ Copy from an ndis packet into a buffer.
+
+Arguments:
+
+ Packet - The packet to copy from.
+
+ Offset - The offset from which to start the copy.
+
+ BytesToCopy - The number of bytes to copy from the packet.
+
+ Buffer - The destination of the copy.
+
+ BytesCopied - The number of bytes actually copied. Can be less then
+ BytesToCopy if the packet is shorter than BytesToCopy.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ //
+ // Holds the number of ndis buffers comprising the packet.
+ //
+ UINT NdisBufferCount;
+
+ //
+ // Points to the buffer from which we are extracting data.
+ //
+ PNDIS_BUFFER CurrentBuffer;
+
+ //
+ // Holds the virtual address of the current buffer.
+ //
+ PVOID VirtualAddress;
+
+ //
+ // Holds the length of the current buffer of the packet.
+ //
+ UINT CurrentLength;
+
+ //
+ // Keep a local variable of BytesCopied so we aren't referencing
+ // through a pointer.
+ //
+ UINT LocalBytesCopied = 0;
+
+ //
+ // Take care of boundary condition of zero length copy.
+ //
+
+ *BytesCopied = 0;
+ if (!BytesToCopy)
+ return;
+
+ //
+ // Get the first buffer.
+ //
+
+ NdisQueryPacket(Packet,
+ NULL,
+ &NdisBufferCount,
+ &CurrentBuffer,
+ NULL);
+
+ //
+ // Could have a null packet.
+ //
+
+ if (!NdisBufferCount)
+ return;
+
+ NdisQueryBuffer(CurrentBuffer, &VirtualAddress, &CurrentLength);
+
+ while (LocalBytesCopied < BytesToCopy)
+ {
+ if (CurrentLength == 0)
+ {
+ NdisGetNextBuffer(CurrentBuffer, &CurrentBuffer);
+
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.
+ //
+
+ if (!CurrentBuffer)
+ break;
+
+ NdisQueryBuffer(CurrentBuffer, &VirtualAddress, &CurrentLength);
+ continue;
+ }
+
+ //
+ // Try to get us up to the point to start the copy.
+ //
+
+ if (Offset)
+ {
+ if (Offset > CurrentLength)
+ {
+ //
+ // What we want isn't in this buffer.
+ //
+
+ Offset -= CurrentLength;
+ CurrentLength = 0;
+ continue;
+ }
+ else
+ {
+ VirtualAddress = (PCHAR)VirtualAddress + Offset;
+ CurrentLength -= Offset;
+ Offset = 0;
+ }
+ }
+
+ //
+ // Copy the data.
+ //
+ {
+ //
+ // Holds the amount of data to move.
+ //
+ UINT AmountToMove;
+
+ AmountToMove = ((CurrentLength <= (BytesToCopy - LocalBytesCopied)) ?
+ (CurrentLength):
+ (BytesToCopy - LocalBytesCopied));
+
+ MoveMemory(Buffer, VirtualAddress, AmountToMove);
+
+ Buffer = (PCHAR)Buffer + AmountToMove;
+ VirtualAddress = (PCHAR)VirtualAddress + AmountToMove;
+
+ LocalBytesCopied += AmountToMove;
+ CurrentLength -= AmountToMove;
+ }
+ }
+
+ *BytesCopied = LocalBytesCopied;
+}
+
+BOOLEAN
+FASTCALL
+ndisMIsLoopbackPacket(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+ This routine will determine if a packet needs to be looped back in
+ software. if the packet is any kind of loopback packet then it
+ will get placed on the loopback queue and a workitem will be queued
+ to process it later.
+
+Arguments:
+
+ Miniport- Pointer to the miniport block to send the packet on.
+ Packet - Packet to check for loopback.
+
+Return Value:
+
+ Returns TRUE if the packet is self-directed.
+
+--*/
+{
+ PNDIS_BUFFER FirstBuffer;
+ UINT Length;
+ UINT Offset;
+ PUCHAR BufferAddress;
+ BOOLEAN Loopback;
+ BOOLEAN SelfDirected;
+ PNDIS_PACKET pNewPacket;
+ PUCHAR Buffer;
+ NDIS_STATUS Status;
+ PNDIS_BUFFER pNdisBuffer;
+ UINT HdrLength;
+ BOOLEAN ArcEncap = TRUE;
+
+ //
+ // We should not be here if the driver handles loopback.
+ //
+ ASSERT(Miniport->MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK);
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ FirstBuffer = Packet->Private.Head;
+ BufferAddress = MDL_ADDRESS(FirstBuffer);
+
+ //
+ // If the card does not do loopback, then we check if
+ // we need to send it to ourselves, then if that is the
+ // case we also check for it being self-directed.
+ //
+ switch (Miniport->MediaType)
+ {
+ case NdisMedium802_3:
+
+ if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_LOOPBACK_DIRECTED))
+ {
+ if (ETH_IS_MULTICAST(BufferAddress))
+ {
+ Loopback = FALSE;
+ SelfDirected = FALSE;
+ break;
+ }
+
+ //
+ // Packet is of type directed, now make sure that it
+ // is not self-directed.
+ //
+ ETH_COMPARE_NETWORK_ADDRESSES_EQ(
+ BufferAddress,
+ Miniport->EthDB->AdapterAddress,
+ &Loopback);
+
+ SelfDirected = FALSE;
+
+ break;
+ }
+
+ //
+ // Check for the miniports that don't do loopback.
+ //
+ EthShouldAddressLoopBackMacro(Miniport->EthDB,
+ BufferAddress,
+ &Loopback,
+ &SelfDirected);
+ break;
+
+ case NdisMedium802_5:
+
+ if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_LOOPBACK_DIRECTED))
+ {
+ BOOLEAN IsNotDirected;
+ TR_IS_NOT_DIRECTED(BufferAddress + 2, &IsNotDirected);
+ if (IsNotDirected)
+ {
+ Loopback = FALSE;
+ SelfDirected = FALSE;
+ break;
+ }
+
+ //
+ // Packet is of type directed, now make sure that it
+ // is not self-directed.
+ //
+ TR_COMPARE_NETWORK_ADDRESSES_EQ(
+ BufferAddress + 2,
+ Miniport->TrDB->AdapterAddress,
+ &Loopback);
+
+ SelfDirected = FALSE;
+
+ break;
+ }
+
+ TrShouldAddressLoopBackMacro(Miniport->TrDB,
+ BufferAddress +2,
+ BufferAddress +8,
+ &Loopback,
+ &SelfDirected);
+
+ break;
+
+ case NdisMediumFddi:
+
+ if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_LOOPBACK_DIRECTED))
+ {
+ BOOLEAN IsMulticast;
+
+ FDDI_IS_MULTICAST(
+ BufferAddress + 1,
+ (BufferAddress[0] & 0x40) ?
+ FDDI_LENGTH_OF_LONG_ADDRESS :
+ FDDI_LENGTH_OF_SHORT_ADDRESS,
+ &IsMulticast);
+ if (IsMulticast)
+ {
+ Loopback = FALSE;
+ SelfDirected = FALSE;
+ break;
+ }
+
+ //
+ // Packet is of type directed, now make sure that it
+ // is not self-directed.
+ //
+ FDDI_COMPARE_NETWORK_ADDRESSES_EQ(
+ BufferAddress + 1,
+ (BufferAddress[0] & 0x40) ?
+ Miniport->FddiDB->AdapterLongAddress :
+ Miniport->FddiDB->AdapterShortAddress,
+ (BufferAddress[0] & 0x40) ?
+ FDDI_LENGTH_OF_LONG_ADDRESS :
+ FDDI_LENGTH_OF_SHORT_ADDRESS,
+ &Loopback);
+
+ SelfDirected = FALSE;
+
+ break;
+ }
+
+ FddiShouldAddressLoopBackMacro(Miniport->FddiDB,
+ BufferAddress + 1, // Skip FC byte to dest address.
+ (BufferAddress[0] & 0x40) ?
+ FDDI_LENGTH_OF_LONG_ADDRESS :
+ FDDI_LENGTH_OF_SHORT_ADDRESS,
+ &Loopback,
+ &SelfDirected);
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ //
+ // We just handle arcnet packets (encapsulated or not) in
+ // a totally different manner...
+ //
+ SelfDirected = ndisMArcnetSendLoopback(Miniport, Packet);
+
+ //
+ // Mark the packet as having been looped back.
+ //
+ MINIPORT_SET_PACKET_FLAG(Packet, fPACKET_HAS_BEEN_LOOPED_BACK);
+
+ return(SelfDirected);
+
+ break;
+ }
+
+ //
+ // If it is not a loopback packet then get out of here.
+ //
+ if (!Loopback)
+ {
+ ASSERT(!SelfDirected);
+ return FALSE;
+ }
+
+ //
+ // Get the buffer length.
+ //
+ NdisQueryPacket(Packet, NULL, NULL, NULL, &Length);
+ Offset = 0;
+
+ //
+ // Allocate a buffer for the packet.
+ //
+ pNewPacket = (PNDIS_PACKET)ALLOC_FROM_POOL(Length +
+ sizeof(NDIS_PACKET) +
+ sizeof(NDIS_PACKET_OOB_DATA) +
+ sizeof(NDIS_PACKET_PRIVATE_EXTENSION) +
+ PROTOCOL_RESERVED_SIZE_IN_PACKET,
+ NDIS_TAG_LOOP_PKT);
+ if (pNewPacket != NULL)
+ {
+ //
+ // Get a pointer to the destination buffer.
+ //
+ Buffer = (PUCHAR)pNewPacket +
+ sizeof(NDIS_PACKET) +
+ sizeof(NDIS_PACKET_OOB_DATA) +
+ sizeof(NDIS_PACKET_PRIVATE_EXTENSION) +
+ PROTOCOL_RESERVED_SIZE_IN_PACKET;
+
+ ZeroMemory(pNewPacket,
+ sizeof(NDIS_PACKET) +
+ sizeof(NDIS_PACKET_OOB_DATA) +
+ sizeof(NDIS_PACKET_PRIVATE_EXTENSION) +
+ PROTOCOL_RESERVED_SIZE_IN_PACKET);
+
+ //
+ // Allocate an MDL for the packet.
+ //
+ NdisAllocateBuffer(&Status,
+ &pNdisBuffer,
+ NULL,
+ Buffer,
+ Length);
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ //
+ // NdisChainBufferAtFront()
+ //
+ pNewPacket->Private.Head = pNdisBuffer;
+ pNewPacket->Private.Tail = pNdisBuffer;
+
+ pNewPacket->Private.NdisPacketOobOffset = (USHORT)sizeof(NDIS_PACKET) + PROTOCOL_RESERVED_SIZE_IN_PACKET;
+
+ ndisMCopyFromPacketToBuffer(Packet, // Packet to copy from.
+ Offset, // Offset from beginning of packet.
+ Length, // Number of bytes to copy.
+ Buffer, // The destination buffer.
+ &HdrLength);// The number of bytes copied.
+ }
+ else
+ {
+ //
+ // Clean up the memory allocated for the packet.
+ //
+ FREE_POOL(pNewPacket);
+ pNewPacket = NULL;
+ }
+ }
+
+ //
+ // Do we have a packet built ?
+ //
+ if (NULL != pNewPacket)
+ {
+ //
+ // Mark the packet as having been looped back.
+ //
+ MINIPORT_SET_PACKET_FLAG(Packet, fPACKET_HAS_BEEN_LOOPED_BACK);
+
+ NDISM_LOG_PACKET(Miniport, Packet, pNewPacket, 'pool');
+
+ //
+ // Place the packet on the loopback queue.
+ //
+ if (NULL == Miniport->LoopbackHead)
+ {
+ Miniport->LoopbackHead = pNewPacket;
+
+ //
+ // If this is the first one on the loopback queue then we need
+ // to make sure that we pick it up later.
+ //
+ NDISM_DEFER_PROCESS_DEFERRED(Miniport);
+ }
+ else
+ {
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LoopbackTail)->Next = pNewPacket;
+ }
+
+ Miniport->LoopbackTail = pNewPacket;
+
+ //
+ // Packet needs to have a workitem queued.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSendLoopback, NULL, NULL);
+ }
+
+ return(SelfDirected);
+}
+
+
+BOOLEAN
+FASTCALL
+ndisMIndicateLoopback(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Checks if a packet needs to be loopbacked and does so if necessary.
+
+ NOTE: Must be called at DPC_LEVEL with lock HELD!
+
+Arguments:
+
+ Miniport - Miniport to send to.
+
+ Packet - Packet to loopback.
+
+Return Value:
+
+ FALSE if the packet should be sent on the net, TRUE if it is
+ a self-directed packet.
+
+--*/
+
+{
+ UINT Length;
+ PUCHAR BufferAddress;
+ PNDIS_PACKET Packet, QueueHead;
+ PNDIS_PACKET_OOB_DATA pOob;
+ NDIS_STATUS Status;
+ BOOLEAN fReturnStatus = FALSE;
+
+ // We should not be here if the driver handles loopback
+ ASSERT(Miniport->MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK);
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+
+ //
+ // Get a local copy of the loopback queue.
+ //
+ QueueHead = Miniport->LoopbackHead;
+ Miniport->LoopbackHead = NULL;
+ Miniport->LoopbackTail = NULL;
+
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+
+ //
+ // Loop through any loopback packets that are queue'd.
+ //
+
+ while (QueueHead != NULL)
+ {
+ //
+ // Grab the first loopback packet to indicate up.
+ //
+ Packet = QueueHead;
+ pOob = NDIS_OOB_DATA_FROM_PACKET(Packet);
+ pOob->Status = NDIS_STATUS_RESOURCES;
+ QueueHead = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next;
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'i');
+
+ //
+ // Setup the packet references and packet array.
+ //
+ Miniport->LoopbackPacket = Packet;
+ BufferAddress = (PUCHAR)Packet +
+ sizeof(NDIS_PACKET) +
+ sizeof(NDIS_PACKET_OOB_DATA) +
+ sizeof(NDIS_PACKET_PRIVATE_EXTENSION) +
+ PROTOCOL_RESERVED_SIZE_IN_PACKET;
+
+ //
+ // For ethernet/token-ring/fddi/encapsulated arc-net, we want to
+ // indicate the packet using the receivepacket way.
+ //
+ switch (Miniport->MediaType)
+ {
+ case NdisMedium802_3:
+ pOob->HeaderSize = 14;
+ EthFilterDprIndicateReceivePacket(Miniport, &Packet, 1);
+ break;
+
+ case NdisMedium802_5:
+ pOob->HeaderSize = 14;
+ if (BufferAddress[8] & 0x80)
+ {
+ pOob->HeaderSize += (BufferAddress[14] & 0x1F);
+ }
+ TrFilterDprIndicateReceivePacket(Miniport, &Packet, 1);
+ break;
+
+ case NdisMediumFddi:
+ pOob->HeaderSize = (*BufferAddress & 0x40) ?
+ 2 * FDDI_LENGTH_OF_LONG_ADDRESS + 1:
+ 2 * FDDI_LENGTH_OF_SHORT_ADDRESS + 1;
+
+ FddiFilterDprIndicateReceivePacket(Miniport, &Packet, 1);
+ break;
+ }
+
+ ASSERT(NDIS_GET_PACKET_STATUS(Packet) != NDIS_STATUS_PENDING);
+ NdisFreeBuffer(Packet->Private.Head);
+ FREE_POOL(Packet);
+ }
+
+ Miniport->LoopbackPacket = NULL;
+
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+
+ //
+ // If there are more loopback packets on the loopback
+ // queue then we need to let process deferred know not to
+ // dequeue the loopback workitem.
+ //
+ if (Miniport->LoopbackHead != NULL)
+ {
+ fReturnStatus = TRUE;
+ }
+
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+
+ return(fReturnStatus);
+}
+
+BOOLEAN
+FASTCALL
+ndisMStartSendPacketsFullDuplex(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+{
+ BOOLEAN fReturn = FALSE;
+#ifdef NDIS_NT
+ PNDIS_PACKET Packet;
+ PNDIS_PACKET PrevPacket;
+ NDIS_STATUS Status;
+ PNDIS_PACKET_RESERVED Reserved;
+ PNDIS_M_OPEN_BLOCK Open;
+ UINT Flags;
+ PPNDIS_PACKET pPktArray;
+
+ //
+ // Acquire the send lock.
+ //
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'rfed');
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMStartSendPacketsFullDuplex\n"));
+
+ MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED);
+
+ //
+ // Loop and process sends.
+ //
+ while ((Miniport->SendResourcesAvailable != 0) &&
+ (Miniport->FirstPendingPacket != NULL))
+ {
+ UINT Count;
+ UINT ResourcesCount;
+ UINT NumberOfPackets;
+
+ //
+ // Initialize the packet array.
+ //
+ pPktArray = Miniport->PacketArray;
+
+ //
+ // Place as many packets as we can in the packet array to send
+ // to the miniport.
+ //
+ for (NumberOfPackets = 0;
+ (NumberOfPackets < Miniport->MaximumSendPackets) &&
+ (Miniport->FirstPendingPacket != NULL); )
+ {
+ //
+ // Grab the packet off of the pending queue.
+ //
+ Packet = Miniport->FirstPendingPacket;
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+
+ //
+ // Remove from pending queue
+ //
+ Miniport->FirstPendingPacket = Reserved->Next;
+
+ //
+ // Put on finish queue
+ //
+ PrevPacket = Miniport->LastMiniportPacket;
+ Miniport->LastMiniportPacket = Packet;
+
+ //
+ // Indicate the packet loopback if necessary.
+ //
+ if (((Miniport->MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK) ||
+ MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_LOOPBACK_DIRECTED)) &&
+ !MINIPORT_TEST_PACKET_FLAG(Packet, fPACKET_HAS_BEEN_LOOPED_BACK) &&
+ ndisMIsLoopbackPacket(Miniport, Packet))
+ {
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Packet 0x%x is self-directed.\n", Packet));
+
+ //
+ // Get a pointer to the open block.
+ // DO NOT USE "Reserved->Open" TO CALL INTO THE MACRO!!!!!
+ //
+ Open = Reserved->Open;
+
+ //
+ // Complete the packet back to the binding.
+ //
+ NDISM_COMPLETE_SEND_FULL_DUPLEX(
+ Miniport,
+ Open,
+ Packet,
+ PrevPacket,
+ NDIS_STATUS_SUCCESS);
+
+ //
+ // No, we don't want to increment the counter for the
+ // miniport's packet array.
+ //
+ }
+ else
+ {
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'inim');
+
+ //
+ // We have to re-initialize this.
+ //
+ *pPktArray = Packet;
+ NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_SUCCESS);
+
+ //
+ // Increment the counter for the packet array index.
+ //
+ NumberOfPackets++;
+ pPktArray++;
+ }
+ }
+
+ //
+ // Are there any packets to send?
+ //
+ if (NumberOfPackets != 0)
+ {
+ //
+ // Get a temp pointer to our packet array.
+ //
+ pPktArray = Miniport->PacketArray;
+ Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Open;
+
+ //
+ // Pass the packet array down to the miniport.
+ //
+ (Open->SendPacketsHandler)(
+ Miniport->MiniportAdapterContext,
+ Miniport->PacketArray,
+ NumberOfPackets);
+
+ //
+ // First check to see if the LastMiniportPacket is NULL.
+ // If it is then the miniport called NdisMSendComplete()
+ // in our send context and we don't need to do anything more.
+ //
+ if (NULL == Miniport->LastMiniportPacket)
+ {
+ //
+ // We may still have packets pending to be sent down....
+ //
+ continue;
+ }
+
+ //
+ // Process the packet completion.
+ //
+ for (Count = 0; Count < NumberOfPackets; Count++, pPktArray++)
+ {
+ BOOLEAN fFoundPacket = FALSE;
+
+ //
+ // Try and find the packet on our miniport's packet queue.
+ //
+ Packet = Miniport->FirstPacket;
+ PrevPacket = NULL;
+
+ ASSERT(Packet != NULL);
+
+ //
+ // We are only going to travers the packet queue from the
+ // FirstPacket to the LastMiniportPacket.
+ // Why you ask? Well we need to make sure that the miniport
+ // didn't complete the packet we are now trying to complete
+ // with a call to NdisMSendComplete().
+ //
+ while (Packet != PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastMiniportPacket)->Next)
+ {
+ if (Packet == *pPktArray)
+ {
+ fFoundPacket = TRUE;
+ break;
+ }
+
+ PrevPacket = Packet;
+ Packet = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next;
+ }
+
+ //
+ // If we didn't find the packet on our queue then we need to
+ // go on to the next one since it MUST have been completed
+ // via NdisMSendComplete....
+ //
+ if (!fFoundPacket)
+ {
+ continue;
+ }
+
+ Status = NDIS_GET_PACKET_STATUS(*pPktArray);
+
+ //
+ // Process the packet based on it's return status.
+ //
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'dnep');
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Complete is pending\n"));
+ }
+ else if (NDIS_STATUS_RESOURCES != Status)
+ {
+#if DBG
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'liaf');
+ }
+ else
+ {
+ NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'ccus');
+ }
+#endif
+
+ ADD_RESOURCE(Miniport, 'F');
+
+ //
+ // Remove from the finish queue.
+ //
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Completed packet 0x%x with status 0x%x\n",
+ *pPktArray,
+ Status));
+
+ //
+ // Fix up the packet queues.
+ //
+ if (Miniport->FirstPacket == *pPktArray)
+ {
+ Miniport->FirstPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Next;
+
+ if (Miniport->LastMiniportPacket == *pPktArray)
+ {
+ Miniport->LastMiniportPacket = NULL;
+ }
+ }
+ else
+ {
+ //
+ // If we just completed the last packet then
+ // we need to update our last packet pointer.
+ //
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Next;
+ if (*pPktArray == Miniport->LastPacket)
+ {
+ Miniport->LastPacket = PrevPacket;
+ }
+
+ //
+ // If we just complete the last miniport packet then
+ // the last miniport packet is the previous packet.
+ //
+ if (Miniport->LastMiniportPacket == *pPktArray)
+ {
+ Miniport->LastMiniportPacket = PrevPacket;
+ }
+ }
+
+ //
+ // We need to save a pointer to the open so that we
+ // can dereference it after the completion.
+ //
+ Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Open;
+
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)(
+ Open->ProtocolBindingContext,
+ *pPktArray,
+ Status);
+
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+ else
+ {
+ //
+ // Once we hit a return code of NDIS_STATUS_RESOURCES
+ // for a packet then we must break out and re-queue.
+ //
+ CLEAR_RESOURCE(Miniport, 'S');
+ MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED);
+
+ break;
+ }
+ }
+
+ //
+ // if there are any packets that returned NDIS_STATUS_RESOURCES
+ // then re-queue them.
+ //
+ if (Count != NumberOfPackets)
+ {
+ PNDIS_PACKET FinalPrevPacket = PrevPacket;
+
+ for (ResourcesCount = NumberOfPackets - 1, pPktArray = &Miniport->PacketArray[ResourcesCount];
+ ResourcesCount > Count;
+ ResourcesCount--, pPktArray--)
+ {
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Packet 0x%x returned resources\n", *pPktArray));
+
+ NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'oser');
+
+ //
+ // Float the pointers.
+ //
+ Miniport->LastMiniportPacket = *(pPktArray - 1);
+ Miniport->FirstPendingPacket = *pPktArray;
+ }
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Packet 0x%x returned resources\n", *pPktArray));
+
+ NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'oser');
+
+ //
+ // If this is the last packet on the miniport queue
+ // then NULL the last miniport packet out so we know there
+ // are no more.
+ //
+ if (Miniport->FirstPacket == *pPktArray)
+ {
+ Miniport->LastMiniportPacket = NULL;
+ Miniport->FirstPendingPacket = *pPktArray;
+ }
+ else
+ {
+ //
+ // There are other packets that are pending on
+ // the miniport queue.
+ //
+ Miniport->LastMiniportPacket = PrevPacket;
+ Miniport->FirstPendingPacket = *pPktArray;
+ }
+ }
+ }
+ }
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMStartSendPacketsFullDuplex\n"));
+
+ //
+ // If there are no more resources available but
+ // there are still packets to send then we need to
+ // keep the workitem queue'd.
+ //
+ if ((0 == Miniport->SendResourcesAvailable) &&
+ (Miniport->FirstPendingPacket != NULL))
+ {
+ fReturn = TRUE;
+ }
+ else
+ {
+ fReturn = FALSE;
+ }
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'RFED');
+
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+#endif
+ return(fReturn);
+}
+
+BOOLEAN
+FASTCALL
+ndisMStartSendsFullDuplex(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+/*++
+
+Routine Description:
+
+ This routine will process any pending sends for full-duplex miniports.
+
+
+ !!!!!!!NOTE!!!!!!!!
+ This routine MUST be called with the Miniport Lock NOT held!!!!
+
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ BOOLEAN fReturn = FALSE;
+#ifdef NDIS_NT
+ PNDIS_PACKET Packet;
+ PNDIS_PACKET PrevPacket;
+ NDIS_STATUS Status;
+ PNDIS_PACKET_RESERVED Reserved;
+ PNDIS_M_OPEN_BLOCK Open;
+ UINT Flags;
+ KIRQL OldIrql;
+
+ //
+ // Acquire the send lock.
+ //
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'rfed');
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMStartSendsFullDuplex\n"));
+
+ MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED);
+
+ //
+ // Loop and process sends.
+ //
+ while ((Miniport->SendResourcesAvailable != 0) &&
+ (Miniport->FirstPendingPacket != NULL))
+ {
+ //
+ // Grab the packet off of the pending queue.
+ //
+ Packet = Miniport->FirstPendingPacket;
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ Open = Reserved->Open;
+
+ //
+ // Remove from pending queue
+ //
+ Miniport->FirstPendingPacket = Reserved->Next;
+
+ //
+ // Put on finish queue
+ //
+ PrevPacket = Miniport->LastMiniportPacket;
+ Miniport->LastMiniportPacket = Packet;
+
+ //
+ // Send the packet
+ //
+ NDISM_SEND_PACKET(Miniport, Open, Packet, &Status);
+
+ //
+ // Process the completion status of the packet.
+ //
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnep');
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Complete is pending\n"));
+ }
+ else if (Status != NDIS_STATUS_RESOURCES)
+ {
+ NDISM_COMPLETE_SEND_FULL_DUPLEX(
+ Miniport,
+ Open,
+ Packet,
+ PrevPacket,
+ Status);
+ }
+ else
+ {
+ NDISM_COMPLETE_SEND_RESOURCES(Miniport, Packet, PrevPacket);
+ }
+ }
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("<==ndisMStartSendsFullDuplex\n"));
+
+ //
+ // If there are no more resources available but
+ // there are still packets to send then we need to
+ // keep the workitem queue'd.
+ //
+ if ((0 == Miniport->SendResourcesAvailable) &&
+ (Miniport->FirstPendingPacket != NULL))
+ {
+ fReturn = TRUE;
+ }
+ else
+ {
+ fReturn = FALSE;
+ }
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'RFED');
+
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+#endif
+ return(fReturn);
+}
+
+BOOLEAN
+FASTCALL
+ndisMStartSendPackets(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+{
+ PNDIS_PACKET Packet;
+ PNDIS_PACKET PrevPacket;
+ NDIS_STATUS Status;
+ PNDIS_PACKET_RESERVED Reserved;
+ PNDIS_M_OPEN_BLOCK Open;
+ UINT Flags;
+ BOOLEAN fReturn;
+ PPNDIS_PACKET pPktArray;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("==>ndisMStartSendPackets\n"));
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'rfed');
+
+ MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED);
+
+ //
+ // Loop and process sends.
+ //
+ while ((Miniport->SendResourcesAvailable != 0) &&
+ (Miniport->FirstPendingPacket != NULL))
+ {
+ UINT Count;
+ UINT ResourcesCount;
+ UINT NumberOfPackets;
+ PNDIS_PACKET FirstPrevPacket = NULL;
+
+ //
+ // Initialize the packet array.
+ //
+ pPktArray = Miniport->PacketArray;
+
+ //
+ // Place as many packets as we can in the packet array to send
+ // to the miniport.
+ //
+ for (NumberOfPackets = 0;
+ (NumberOfPackets < Miniport->MaximumSendPackets) &&
+ (Miniport->FirstPendingPacket != NULL); )
+ {
+ //
+ // Grab the packet off of the pending queue.
+ //
+ Packet = Miniport->FirstPendingPacket;
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+
+ //
+ // Remove from pending queue
+ //
+ Miniport->FirstPendingPacket = Reserved->Next;
+
+ //
+ // Put on finish queue
+ //
+ PrevPacket = Miniport->LastMiniportPacket;
+ Miniport->LastMiniportPacket = Packet;
+
+ //
+ // Indicate the packet loopback if necessary.
+ //
+ if (((Miniport->MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK) ||
+ MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_LOOPBACK_DIRECTED)) &&
+ !MINIPORT_TEST_PACKET_FLAG(Packet, fPACKET_HAS_BEEN_LOOPED_BACK) &&
+ ndisMIsLoopbackPacket(Miniport, Packet))
+ {
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Packet 0x%x is self-directed.\n", Packet));
+
+ //
+ // Get a pointer to our open block.
+ // DO NOT USE "Reserved->Open" TO CALL INTO THE MACRO SINCE IT
+ // WILL NOT BE VALID FOR THE LIFE OF THE MACRO!!!!!
+ //
+ Open = Reserved->Open;
+
+ //
+ // Complete the packet back to the binding.
+ //
+ NDISM_COMPLETE_SEND(
+ Miniport,
+ Open,
+ Packet,
+ PrevPacket,
+ NDIS_STATUS_SUCCESS);
+
+ //
+ // No, we don't want to increment the counter for the
+ // miniport's packet array.
+ //
+ }
+ else
+ {
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'inim');
+
+ //
+ // We have to re-initialize this.
+ //
+ *pPktArray = Packet;
+ NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_SUCCESS);
+
+ //
+ // Increment the counter for the packet array index.
+ //
+ NumberOfPackets++;
+ pPktArray++;
+ }
+ }
+
+ //
+ // Are there any packets to send?
+ //
+ if (NumberOfPackets != 0)
+ {
+ //
+ // Get a temp pointer to our packet array.
+ //
+ pPktArray = Miniport->PacketArray;
+ Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Open;
+
+ //
+ // Pass the packet array down to the miniport.
+ //
+ (Open->SendPacketsHandler)(
+ Miniport->MiniportAdapterContext,
+ Miniport->PacketArray,
+ NumberOfPackets);
+
+ //
+ // First check to see if the LastMiniportPacket is NULL.
+ // If it is then the miniport called NdisMSendComplete()
+ // in our send context and we don't need to do anything more.
+ //
+ if (NULL == Miniport->LastMiniportPacket)
+ {
+ //
+ // We may still have packets pending to be sent down....
+ //
+ continue;
+ }
+
+ //
+ // Process the packet completion.
+ //
+ for (Count = 0; Count < NumberOfPackets; Count++, pPktArray++)
+ {
+ BOOLEAN fFoundPacket = FALSE;
+
+ //
+ // Try and find the packet on our miniport's packet queue.
+ //
+ Packet = Miniport->FirstPacket;
+ PrevPacket = NULL;
+
+ ASSERT(Packet != NULL);
+
+ //
+ // We are only going to travers the packet queue from the
+ // FirstPacket to the LastMiniportPacket.
+ // Why you ask? Well we need to make sure that the miniport
+ // didn't complete the packet we are now trying to complete
+ // with a call to NdisMSendComplete().
+ //
+ while (Packet != PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastMiniportPacket)->Next)
+ {
+ if (Packet == *pPktArray)
+ {
+ fFoundPacket = TRUE;
+ break;
+ }
+
+ PrevPacket = Packet;
+ Packet = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next;
+ }
+
+ //
+ // If we didn't find the packet on our queue then we need to
+ // go on to the next one since it MUST have been completed
+ // via NdisMSendComplete....
+ //
+ if (!fFoundPacket)
+ {
+ continue;
+ }
+
+ Status = NDIS_GET_PACKET_STATUS(*pPktArray);
+
+ //
+ // Process the packet based on it's return status.
+ //
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'dnep');
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Complete is pending\n"));
+ }
+ else if (Status != NDIS_STATUS_RESOURCES)
+ {
+#if DBG
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'liaf');
+ }
+ else
+ {
+ NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'ccus');
+ }
+#endif
+
+ ADD_RESOURCE(Miniport, 'F');
+
+ //
+ // Remove from the finish queue.
+ //
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Completed packet 0x%x with status 0x%x\n",
+ *pPktArray,
+ Status));
+
+ //
+ // Fix up the packet queues.
+ //
+ if (Miniport->FirstPacket == *pPktArray)
+ {
+ Miniport->FirstPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Next;
+
+ if (Miniport->LastMiniportPacket == *pPktArray)
+ {
+ Miniport->LastMiniportPacket = NULL;
+ }
+ }
+ else
+ {
+ //
+ // If we just completed the last packet then
+ // we need to update our last packet pointer.
+ //
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Next;
+ if (*pPktArray == Miniport->LastPacket)
+ {
+ Miniport->LastPacket = PrevPacket;
+ }
+
+ //
+ // If we just complete the last miniport packet then
+ // the last miniport packet is the previous packet.
+ //
+ if (Miniport->LastMiniportPacket == *pPktArray)
+ {
+ Miniport->LastMiniportPacket = PrevPacket;
+ }
+ }
+
+ //
+ // We need to save a pointer to the open so that we
+ // can dereference it after the completion.
+ //
+ Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Open;
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)(
+ Open->ProtocolBindingContext,
+ *pPktArray,
+ Status);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("- Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ Open->References--;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("==0 Open 0x%x Reference 0x%x\n",
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Open,
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Open->References));
+
+ if (Open->References == 0)
+ {
+ ndisMFinishClose(Miniport, Open);
+ }
+ }
+ else
+ {
+ //
+ // Once we hit a return code of NDIS_STATUS_RESOURCES
+ // for a packet then we must break out and re-queue.
+ //
+ CLEAR_RESOURCE(Miniport, 'S');
+ MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED);
+
+ break;
+ }
+ }
+
+ //
+ // if there are any packets that returned NDIS_STATUS_RESOURCES
+ // then re-queue them.
+ //
+ if (Count != NumberOfPackets)
+ {
+ PNDIS_PACKET FinalPrevPacket = PrevPacket;
+
+ for (ResourcesCount = NumberOfPackets - 1, pPktArray = &Miniport->PacketArray[ResourcesCount];
+ ResourcesCount > Count;
+ ResourcesCount--, pPktArray--)
+ {
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Packet 0x%x returned resources\n", *pPktArray));
+
+ NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'oser');
+
+ //
+ // Float the pointers.
+ //
+ Miniport->LastMiniportPacket = *(pPktArray - 1);
+ Miniport->FirstPendingPacket = *pPktArray;
+ }
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Packet 0x%x returned resources\n", *pPktArray));
+
+ NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'oser');
+
+ //
+ // If this is the last packet on the miniport queue
+ // then NULL the last miniport packet out so we know there
+ // are no more.
+ //
+ if (Miniport->FirstPacket == *pPktArray)
+ {
+ Miniport->LastMiniportPacket = NULL;
+ Miniport->FirstPendingPacket = *pPktArray;
+ }
+ else
+ {
+ //
+ // There are other packets that are pending on
+ // the miniport queue.
+ //
+ Miniport->LastMiniportPacket = PrevPacket;
+ Miniport->FirstPendingPacket = *pPktArray;
+ }
+ }
+ }
+ }
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'RFED');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("<==ndisMStartSendPackets\n"));
+
+ return(FALSE);
+}
+
+BOOLEAN
+FASTCALL
+ndisMStartSends(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Submits as many sends as possible to the mini-port.
+
+Arguments:
+
+ Miniport - Miniport to send to.
+
+Return Value:
+
+ If there are more packets to send but no resources to do it with
+ the this is TRUE to keep a workitem queue'd.
+
+--*/
+
+{
+ PNDIS_PACKET Packet;
+ PNDIS_PACKET PrevPacket;
+ NDIS_STATUS Status;
+ PNDIS_PACKET_RESERVED Reserved;
+ PNDIS_M_OPEN_BLOCK Open;
+ UINT Flags;
+ BOOLEAN fReturn;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("==>ndisMStartSends\n"));
+
+ MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED);
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'rfed');
+
+ //
+ // Loop and process sends.
+ //
+ while ((Miniport->SendResourcesAvailable != 0) &&
+ (Miniport->FirstPendingPacket != NULL))
+ {
+ //
+ // Grab the packet off of the pending queue.
+ //
+ Packet = Miniport->FirstPendingPacket;
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ Open = Reserved->Open;
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 's');
+
+ //
+ // Is this arcnet using ethernet encapsulation?
+ //
+ if (Miniport->MediaType == NdisMediumArcnet878_2)
+ {
+ //
+ // Build the header for arcnet.
+ //
+ Status = ndisMBuildArcnetHeader(Miniport, Open, Packet);
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ return(TRUE);
+ }
+ }
+
+ //
+ // Remove from pending queue
+ //
+ Miniport->FirstPendingPacket = Reserved->Next;
+
+ //
+ // Put on finish queue
+ //
+ PrevPacket = Miniport->LastMiniportPacket;
+ Miniport->LastMiniportPacket = Packet;
+
+ //
+ // Send the packet.
+ //
+ NDISM_SEND_PACKET(Miniport, Open, Packet, &Status);
+
+ //
+ // Process the packet pending completion status.
+ //
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnep');
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Complete is pending\n"));
+ }
+ else
+ {
+ //
+ // Clean-up arcnet's extra buffers.
+ //
+ if (Miniport->MediaType == NdisMediumArcnet878_2)
+ {
+ ndisMFreeArcnetHeader(Miniport, Packet);
+ }
+
+ //
+ // Handle the completion and resources cases.
+ //
+ if (Status != NDIS_STATUS_RESOURCES)
+ {
+ NDISM_COMPLETE_SEND(
+ Miniport,
+ Open,
+ Packet,
+ PrevPacket,
+ Status);
+ }
+ else
+ {
+ NDISM_COMPLETE_SEND_RESOURCES(Miniport, Packet, PrevPacket);
+ }
+ }
+
+ }
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("<==ndisMStartSends\n"));
+
+ //
+ // If there are no more resources available but
+ // there are still packets to send then we need to
+ // keep the workitem queue'd.
+ //
+ if ((0 == Miniport->SendResourcesAvailable) &&
+ (Miniport->FirstPendingPacket != NULL))
+ {
+ fReturn = TRUE;
+ }
+ else
+ {
+ fReturn = FALSE;
+ }
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'RFED');
+
+ return(fReturn);
+}
+
+NDIS_STATUS FASTCALL
+ndisMSyncSend(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+ Submits an immediate send to a miniport. The miniport has
+ the send on the pending queue, and it is the only element on the send
+ queue. This routine is also called with the lock held.
+
+Arguments:
+
+ Miniport - Miniport to send to.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_PACKET PrevPacket;
+ NDIS_STATUS Status;
+ PNDIS_PACKET_RESERVED Reserved;
+ PNDIS_M_OPEN_BLOCK Open;
+ UINT Flags;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Enter Sync send.\n"));
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'cnys');
+
+ //
+ // Get the Open block that the send is for from the packet.
+ //
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ Open = Reserved->Open;
+
+ //
+ // Remove from Queue
+ //
+ Miniport->FirstPendingPacket = Reserved->Next;
+
+ //
+ // Put on finish queue
+ //
+ PrevPacket = Miniport->LastMiniportPacket;
+ Miniport->LastMiniportPacket = Packet;
+ MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED);
+
+ //
+ // Send the packet.
+ //
+ NDISM_SEND_PACKET(Miniport, Open, Packet, &Status);
+
+ //
+ // Process the status of the send.
+ //
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnep');
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Complete sync send is pending\n"));
+
+ return(NDIS_STATUS_PENDING);
+ }
+
+ //
+ // If send complete was called from the miniport's send handler
+ // then our local PrevPacket pointer may no longer be valid....
+ //
+ if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED))
+ {
+ MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED);
+ MiniportFindPacket(Miniport, Packet, &PrevPacket);
+ }
+
+ Miniport->LastMiniportPacket = PrevPacket;
+
+ if (Status != NDIS_STATUS_RESOURCES)
+ {
+#if DBG
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'liaf');
+ }
+ else
+ {
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'ccus');
+ }
+#endif
+
+ ADD_RESOURCE(Miniport, 'F');
+
+ //
+ // Remove from finish queue
+ //
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Completed 0x%x\n", Status));
+
+ if (PrevPacket == NULL)
+ {
+ //
+ // Set up the next packet to send.
+ //
+ Miniport->FirstPacket = Reserved->Next;
+ }
+ else
+ {
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next = Reserved->Next;
+
+ if (Packet == Miniport->LastPacket)
+ {
+ Miniport->LastPacket = PrevPacket;
+ }
+ }
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("- Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ Open->References--;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("==0 Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ if (Open->References == 0)
+ ndisMFinishClose(Miniport, Open);
+ }
+ else
+ {
+ //
+ // Status == NDIS_STATUS_RESOURCES!!!!
+ //
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Deferring send\n"));
+
+ //
+ // Put on pending queue
+ //
+ Miniport->FirstPendingPacket = Packet;
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'oser');
+
+ //
+ // Set flag
+ //
+ CLEAR_RESOURCE(Miniport, 'S');
+
+ Status = NDIS_STATUS_PENDING;
+ }
+
+ return(Status);
+}
+
+
+NDIS_STATUS
+ndisMWanSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE NdisLinkHandle,
+ IN PVOID Packet
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ BOOLEAN LocalLock;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Call MAC to send WAN packet
+ //
+ Status = ((PNDIS_M_WAN_SEND)(Miniport->DriverHandle->MiniportCharacteristics.SendHandler))(
+ Miniport->MiniportAdapterContext,
+ NdisLinkHandle,
+ Packet);
+
+ if (LocalLock)
+ {
+ //
+ // Process any changes that may have occured.
+ //
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ return Status;
+}
+
+VOID
+ndisMSendCompleteFullDuplex(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ )
+{
+#ifdef NDIS_NT
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+ PNDIS_PACKET_RESERVED Reserved;
+ LONG Thread;
+ BOOLEAN fAcquireMiniportLock = FALSE;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMSendCompleteFullDuplex\n"));
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("packet 0x%x\n", Packet));
+
+ //
+ // Acquire the send lock, unless it has alrady been acquired earlier
+ // by this thread....
+ //
+ Thread = InterlockedExchangeAdd(&Miniport->SendThread, 0);
+ if (CURRENT_THREAD != Thread)
+ {
+ //
+ // We need to try and grab the lock...
+ //
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+
+ MINIPORT_SET_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED);
+
+ //
+ // If the packet is not equal to the first packet then we have to find
+ // it because it may have completed out of order.
+ //
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+
+ if (Miniport->FirstPacket == Packet)
+ {
+ Miniport->FirstPacket = Reserved->Next;
+
+ if (Miniport->LastMiniportPacket == Packet)
+ {
+ Miniport->LastMiniportPacket = NULL;
+ }
+ }
+ else
+ {
+ PNDIS_PACKET PrevPacket;
+
+ //
+ // Search for the packet.
+ //
+ MiniportFindPacket(Miniport, Packet, &PrevPacket);
+
+ ASSERT(PrevPacket != NULL);
+
+ //
+ // If we just completed the last packet then
+ // we need to update our last packet pointer.
+ //
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next = Reserved->Next;
+ if (Packet == Miniport->LastPacket)
+ {
+ Miniport->LastPacket = PrevPacket;
+ }
+
+ //
+ // If we just completed the last miniport packet then
+ // last miniport packet is the previous packet.
+ //
+ if (Miniport->LastMiniportPacket == Packet)
+ {
+ Miniport->LastMiniportPacket = PrevPacket;
+ }
+ }
+
+ //
+ // Indicate to Protocol;
+ //
+ Open = Reserved->Open;
+
+ //
+ // Do we need to queue another workitem to process more sends?
+ //
+ if (Miniport->FirstPendingPacket != NULL)
+ {
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+ }
+
+
+#if DBG
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'pmoc');
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'liaf');
+ }
+ else
+ {
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'ccus');
+ }
+#endif
+
+ ADD_RESOURCE(Miniport, 'P');
+
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+
+ //
+ // If the current thread has the miniport lock then we need to
+ // release it....
+ //
+ if (CURRENT_THREAD == Miniport->MiniportThread)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+ fAcquireMiniportLock = TRUE;
+ }
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)(
+ Open->ProtocolBindingContext,
+ Packet,
+ Status);
+
+ if (fAcquireMiniportLock)
+ {
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+ }
+
+ //
+ // If the SendLock was acquired on entry then we need to make sure
+ // that it's acquired on exit...
+ //
+ if (CURRENT_THREAD == Thread)
+ {
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMSendCompleteFullDuplex\n"));
+#endif
+}
+
+VOID
+NdisMSendComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ This function indicates the completion of a send.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+ PNDIS_PACKET_RESERVED Reserved;
+ PSINGLE_LIST_ENTRY Link;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMSendComplete\n"));
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("packet 0x%x\n", Packet));
+
+ MINIPORT_SET_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED);
+
+ //
+ // If the packet is not equal to the first packet then we have to find
+ // it because it may have completed out of order.
+ //
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+
+ if (Miniport->FirstPacket == Packet)
+ {
+ Miniport->FirstPacket = Reserved->Next;
+
+ if (Miniport->LastMiniportPacket == Packet)
+ {
+ Miniport->LastMiniportPacket = NULL;
+ }
+ }
+ else
+ {
+ PNDIS_PACKET PrevPacket;
+
+ //
+ // Search for the packet.
+ //
+ MiniportFindPacket(Miniport, Packet, &PrevPacket);
+
+ ASSERT(PrevPacket != NULL);
+
+ //
+ // If we just completed the last packet then
+ // we need to update our last packet pointer.
+ //
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next = Reserved->Next;
+ if (Packet == Miniport->LastPacket)
+ {
+ Miniport->LastPacket = PrevPacket;
+ }
+
+ //
+ // If we just completed the last miniport packet then
+ // last miniport packet is the previous packet.
+ //
+
+ if (Miniport->LastMiniportPacket == Packet)
+ {
+ Miniport->LastMiniportPacket = PrevPacket;
+ }
+ }
+
+ //
+ // Indicate to Protocol;
+ //
+ Open = Reserved->Open;
+
+ //
+ // If this is arcnet, then free the appended header.
+ //
+ if (Miniport->MediaType == NdisMediumArcnet878_2)
+ {
+ ndisMFreeArcnetHeader(Miniport, Packet);
+ }
+
+#if DBG
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'pmoc');
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'liaf');
+ }
+ else
+ {
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'ccus');
+ }
+#endif
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)(
+ Open->ProtocolBindingContext,
+ Packet,
+ Status);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ ADD_RESOURCE(Miniport, 'P');
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("- Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ Open->References--;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("==0 Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ if (Open->References == 0)
+ {
+ ndisMFinishClose(Miniport,Open);
+ }
+
+ //
+ // Do we need to queue another workitem to process more sends?
+ //
+ if (Miniport->FirstPendingPacket != NULL)
+ {
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+ }
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMSendComplete\n"));
+}
+
+
+VOID
+NdisMWanSendComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ )
+
+/*++
+
+Routine Description:
+
+ This function indicates the status is complete.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ Open = Miniport->OpenQueue;
+
+ while (Open != NULL)
+ {
+ //
+ // Call Protocol to indicate status
+ //
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'C');
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler) (
+ Open->ProtocolBindingContext,
+ Packet,
+ Status);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ Open = Open->MiniportNextOpen;
+ }
+}
+
+VOID
+ndisMSendResourcesAvailableFullDuplex(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ )
+{
+#ifdef NDIS_NT
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ LONG Thread;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ Thread = InterlockedExchangeAdd(&Miniport->SendThread, 0);
+ if (CURRENT_THREAD != Thread)
+ {
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMSendResourcesAvailableFullDuplex\n"));
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'aser');
+ ADD_RESOURCE(Miniport, 'V');
+
+ //
+ // Are there more sends to process?
+ //
+ if (Miniport->FirstPendingPacket != NULL)
+ {
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+ }
+
+ if (CURRENT_THREAD != Thread)
+ {
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMSendResourcesAvailableFullDuplex\n"));
+#endif
+}
+
+VOID
+NdisMSendResourcesAvailable(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ )
+/*++
+
+Routine Description:
+
+ This function indicates that some send resources are available and are free for
+ processing more sends.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMSendResourcesAvailable\n"));
+
+ ADD_RESOURCE(Miniport, 'V');
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'aser');
+
+ //
+ // Are there more sends to process?
+ //
+ if (Miniport->FirstPendingPacket != NULL)
+ {
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+ }
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMSendResourcesAvailable\n"));
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////
+//
+// UPPER-EDGE SEND HANDLERS
+//
+///////////////////////////////////////////////////////////////////////////////////////
+
+
+NDIS_STATUS
+ndisMSendFullDuplexToSendPackets(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ )
+{
+ NDIS_STATUS Status = NDIS_STATUS_PENDING;
+#ifdef NDIS_NT
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ PNDIS_PACKET_RESERVED Reserved;
+ KIRQL OldIrql;
+ BOOLEAN fQueueWorkItem = FALSE;
+ BOOLEAN fDeferredSend = FALSE;
+ BOOLEAN LocalLock;
+ UINT Flags;
+
+ NDIS_ACQUIRE_SEND_SPIN_LOCK(Miniport, &OldIrql);
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnes');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMSendFullDuplexToSendPackets\n"));
+
+ //
+ // Initialize the packet info.
+ //
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ Reserved->Next = NULL;
+ Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+
+ //
+ // Place the packet on the packet queue.
+ //
+ if (Miniport->FirstPacket == NULL)
+ {
+ //
+ // Place the packet at the head of the queue.
+ //
+ Miniport->FirstPacket = Packet;
+ }
+ else
+ {
+ CHECK_FOR_DUPLICATE_PACKET(Miniport, Packet);
+
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = Packet;
+ }
+
+ Miniport->LastPacket = Packet;
+
+ //
+ // This packet has not been looped back yet!
+ //
+ MINIPORT_CLEAR_PACKET_FLAG(Packet, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT));
+
+ //
+ // Check to see if a sync send is possible.
+ //
+ if (Miniport->FirstPendingPacket == NULL)
+ {
+ Miniport->FirstPendingPacket = Packet;
+ }
+
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'DNES');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMSendFullDuplexToSendPackets\n"));
+
+ NDIS_RELEASE_SEND_SPIN_LOCK(Miniport, OldIrql);
+#endif
+ return(Status);
+}
+
+VOID
+ndisMSendPacketsFullDuplex(
+ IN PNDIS_OPEN_BLOCK NdisOpenBlock,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ )
+{
+#ifdef NDIS_NT
+ PNDIS_M_OPEN_BLOCK NdisBindingHandle = (PNDIS_M_OPEN_BLOCK)NdisOpenBlock->MacBindingHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = NdisBindingHandle->MiniportHandle;
+ PPNDIS_PACKET pPktArray;
+ PNDIS_PACKET_RESERVED Reserved;
+ BOOLEAN LocalLock;
+ KIRQL OldIrql;
+ UINT c;
+
+ NDIS_ACQUIRE_SEND_SPIN_LOCK(Miniport, &OldIrql);
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'KPES');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMSendPacketsFullDuplex\n"));
+
+ //
+ // Place the packets on the miniport queue.
+ //
+ for (c = 0, pPktArray = PacketArray;
+ c < NumberOfPackets;
+ c++, pPktArray++)
+ {
+ //
+ // Get the first packet....
+ //
+ NDIS_SET_PACKET_STATUS(*pPktArray, NDIS_STATUS_PENDING);
+
+ //
+ // Initialize the packet info.
+ //
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray);
+ Reserved->Next = NULL;
+ Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+
+ //
+ // Place the packet on the packet queue.
+ //
+ if (Miniport->FirstPacket == NULL)
+ {
+ //
+ // Place the packet at the head of the queue.
+ //
+ Miniport->FirstPacket = *pPktArray;
+ }
+ else
+ {
+ CHECK_FOR_DUPLICATE_PACKET(Miniport, *pPktArray);
+
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = *pPktArray;
+ }
+
+ Miniport->LastPacket = *pPktArray;
+
+ //
+ // This packet has not been looped back yet!
+ //
+ MINIPORT_CLEAR_PACKET_FLAG(*pPktArray, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT));
+
+ //
+ // Check to see if a sync send is possible.
+ //
+ if (Miniport->FirstPendingPacket == NULL)
+ {
+ Miniport->FirstPendingPacket = *pPktArray;
+ }
+ }
+
+ //
+ // Queue a workitem for the new sends.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'KPES');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMSendPacketsFullDuplex\n"));
+
+ NDIS_RELEASE_SEND_SPIN_LOCK(Miniport, OldIrql);
+
+#endif
+}
+
+
+NDIS_STATUS
+ndisMSendToSendPackets(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ PNDIS_PACKET_RESERVED Reserved;
+ BOOLEAN LocalLock;
+ NDIS_STATUS Status = NDIS_STATUS_PENDING;
+ KIRQL OldIrql;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnes');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMSendToSendPackets\n"));
+
+ //
+ // Increment the references on this open.
+ //
+ ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("+ Open 0x%x Reference 0x%x\n", NdisBindingHandle, ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References));
+
+ //
+ // Initialize the packet info.
+ //
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ Reserved->Next = NULL;
+ Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+
+ //
+ // Place the packet on the packet queue.
+ //
+ if (Miniport->FirstPacket == NULL)
+ {
+ //
+ // Place the packet at the head of the queue.
+ //
+ Miniport->FirstPacket = Packet;
+ }
+ else
+ {
+ CHECK_FOR_DUPLICATE_PACKET(Miniport, Packet);
+
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = Packet;
+ }
+
+ Miniport->LastPacket = Packet;
+
+ //
+ // This packet has not been looped back yet!
+ //
+ MINIPORT_CLEAR_PACKET_FLAG(Packet, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT));
+
+ //
+ // Check to see if a sync send is possible.
+ //
+ if (Miniport->FirstPendingPacket == NULL)
+ {
+ Miniport->FirstPendingPacket = Packet;
+ }
+
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+
+ //
+ // Try to grab the local lock on the miniport block.
+ //
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // If we have the local lock and there is not
+ // a reset in progress then fire off the send.
+ //
+ if (LocalLock)
+ {
+ //
+ // Process deferred.
+ //
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMSendToSendPackets\n"));
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'DNES');
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ return(NDIS_STATUS_PENDING);
+}
+
+
+VOID
+ndisMSendPackets(
+ IN PNDIS_OPEN_BLOCK NdisOpenBlock,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ )
+{
+ PNDIS_M_OPEN_BLOCK NdisBindingHandle = (PNDIS_M_OPEN_BLOCK)NdisOpenBlock->MacBindingHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = NdisBindingHandle->MiniportHandle;
+ BOOLEAN LocalLock;
+ KIRQL OldIrql;
+ UINT c;
+ PNDIS_PACKET_RESERVED Reserved;
+ PPNDIS_PACKET pPktArray;;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'KPES');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMSendPackets\n"));
+
+ //
+ // Place the packets on the miniport queue.
+ //
+ for (c = 0, pPktArray = PacketArray;
+ c < NumberOfPackets;
+ c++, pPktArray++)
+ {
+ //
+ // Get the first packet....
+ //
+ NDIS_SET_PACKET_STATUS(*pPktArray, NDIS_STATUS_PENDING);
+
+ //
+ // Initialize the packet info.
+ //
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray);
+ Reserved->Next = NULL;
+ Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+
+ //
+ // Increment the references on this open.
+ //
+ ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("+ Open 0x%x Reference 0x%x\n", NdisBindingHandle, ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References));
+
+ //
+ // Place the packet on the packet queue.
+ //
+ if (Miniport->FirstPacket == NULL)
+ {
+ //
+ // Place the packet at the head of the queue.
+ //
+ Miniport->FirstPacket = *pPktArray;
+ }
+ else
+ {
+ CHECK_FOR_DUPLICATE_PACKET(Miniport, *pPktArray);
+
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = *pPktArray;
+ }
+
+ Miniport->LastPacket = *pPktArray;
+
+ //
+ // This packet has not been looped back yet!
+ //
+ MINIPORT_CLEAR_PACKET_FLAG(*pPktArray, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT));
+
+ //
+ // Check to see if a sync send is possible.
+ //
+ if (Miniport->FirstPendingPacket == NULL)
+ {
+ Miniport->FirstPendingPacket = *pPktArray;
+ }
+ }
+
+ //
+ // Queue a workitem for the new sends.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+
+ //
+ // Try to grab the local lock on the miniport block.
+ //
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // If we have the local lock and there is not
+ // a reset in progress then fire off the send.
+ //
+ if (LocalLock)
+ {
+ //
+ // Process deferred.
+ //
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'KPES');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMSendPackets\n"));
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+}
+
+VOID
+ndisMSendPacketsFullDuplexToSend(
+ IN PNDIS_OPEN_BLOCK NdisOpenBlock,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ )
+{
+#ifdef NDIS_NT
+ PNDIS_M_OPEN_BLOCK NdisBindingHandle = (PNDIS_M_OPEN_BLOCK)NdisOpenBlock->MacBindingHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = NdisBindingHandle->MiniportHandle;
+ PNDIS_PACKET_RESERVED Reserved;
+ PPNDIS_PACKET pPktArray;
+ BOOLEAN LocalLock;
+ KIRQL OldIrql;
+ UINT c;
+
+ NDIS_ACQUIRE_SEND_SPIN_LOCK(Miniport, &OldIrql);
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'kpes');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMSendPacketsFullDuplexToSend\n"));
+
+ //
+ // Place the packets on the miniport queue.
+ //
+ for (c = 0, pPktArray = PacketArray;
+ c < NumberOfPackets;
+ c++, pPktArray++)
+ {
+ //
+ // Initialize the packet info.
+ //
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray);
+ Reserved->Next = NULL;
+ Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+
+ //
+ // Place the packet on the packet queue.
+ //
+ if (Miniport->FirstPacket == NULL)
+ {
+ //
+ // Place the packet at the head of the queue.
+ //
+ Miniport->FirstPacket = *pPktArray;
+ }
+ else
+ {
+ CHECK_FOR_DUPLICATE_PACKET(Miniport, *pPktArray);
+
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = *pPktArray;
+ }
+
+ Miniport->LastPacket = *pPktArray;
+
+ //
+ // This packet has not been looped back yet.
+ //
+ MINIPORT_CLEAR_PACKET_FLAG(*pPktArray, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT));
+
+ //
+ // Check to see if a sync send is possible.
+ //
+ if (Miniport->FirstPendingPacket == NULL)
+ {
+ Miniport->FirstPendingPacket = *pPktArray;
+ }
+ }
+
+ //
+ // Queue a workitem for the new sends.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'KPES');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMSendPacketsFullDuplexToSend\n"));
+
+ NDIS_RELEASE_SEND_SPIN_LOCK(Miniport, OldIrql);
+#endif
+}
+
+NDIS_STATUS
+ndisMSendFullDuplex(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_PENDING;
+#ifdef NDIS_NT
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ PNDIS_PACKET_RESERVED Reserved;
+ KIRQL OldIrql;
+ BOOLEAN fQueueWorkItem = FALSE;
+ BOOLEAN fDeferredSend = FALSE;
+ BOOLEAN LocalLock;
+ UINT Flags;
+
+ NDIS_ACQUIRE_SEND_SPIN_LOCK(Miniport, &OldIrql);
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnes');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMSendFullDuplex\n"));
+
+ //
+ // Initialize the packet info.
+ //
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ Reserved->Next = NULL;
+ Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+
+ //
+ // Place the packet on the packet queue.
+ //
+ if (Miniport->FirstPacket == NULL)
+ {
+ //
+ // Place the packet at the head of the queue.
+ //
+ Miniport->FirstPacket = Packet;
+ }
+ else
+ {
+ CHECK_FOR_DUPLICATE_PACKET(Miniport, Packet);
+
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = Packet;
+ }
+
+ Miniport->LastPacket = Packet;
+
+ //
+ // This packet has not been looped back yet and it does not
+ // contain any media specific information.
+ //
+ MINIPORT_CLEAR_PACKET_FLAG(Packet, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT));
+
+ if (NULL == Miniport->FirstPendingPacket)
+ {
+ Miniport->FirstPendingPacket = Packet;
+ }
+
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'DNES');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMSendFullDuplex\n"));
+
+ NDIS_RELEASE_SEND_SPIN_LOCK(Miniport, OldIrql);
+#endif
+ return(Status);
+}
+
+VOID
+ndisMSendPacketsToSend(
+ IN PNDIS_OPEN_BLOCK NdisOpenBlock,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ )
+/*++
+
+Routine Description:
+
+ This routine will take a packet array and "thunk" it down for a
+ driver that does not support a send packet handler.
+ This involves queueing the packet array onto the miniport's packet queue
+ and sending them one at a time.
+
+Arguments:
+
+ NdisBindingHandle - Pointer to the NDIS_OPEN_BLOCK.
+ PacketArray - Array of PNDIS_PACKET structures that are
+ to be sent to the miniport as NDIS_PACKETs.
+ NumberOfPackets - Number of elements in the PacketArray.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_M_OPEN_BLOCK NdisBindingHandle = (PNDIS_M_OPEN_BLOCK)NdisOpenBlock->MacBindingHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = NdisBindingHandle->MiniportHandle;
+ PNDIS_PACKET Packet;
+ PNDIS_PACKET_RESERVED Reserved;
+ PPNDIS_PACKET pPktArray;
+ BOOLEAN LocalLock;
+ KIRQL OldIrql;
+ UINT c;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'kpes');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMSendPacketsToSend\n"));
+
+ //
+ // Try to grab the local lock on the miniport block.
+ //
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Place the packets on the miniport queue.
+ //
+ for (c = 0, pPktArray = PacketArray;
+ c < NumberOfPackets;
+ c++, pPktArray++)
+ {
+ //
+ // Initialize the packet info.
+ //
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray);
+ Reserved->Next = NULL;
+ Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+
+ //
+ // Increment the references on this open.
+ //
+ ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("+ Open 0x%x Reference 0x%x\n", NdisBindingHandle, ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References));
+
+ //
+ // Place the packet on the packet queue.
+ //
+ if (Miniport->FirstPacket == NULL)
+ {
+ //
+ // Place the packet at the head of the queue.
+ //
+ Miniport->FirstPacket = *pPktArray;
+ }
+ else
+ {
+ CHECK_FOR_DUPLICATE_PACKET(Miniport, *pPktArray);
+
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = *pPktArray;
+ }
+
+ Miniport->LastPacket = *pPktArray;
+
+ //
+ // This packet has not been looped back yet.
+ //
+ MINIPORT_CLEAR_PACKET_FLAG(*pPktArray, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT));
+
+ //
+ // Check to see if a sync send is possible.
+ //
+ if (Miniport->FirstPendingPacket == NULL)
+ {
+ Miniport->FirstPendingPacket = *pPktArray;
+ }
+ }
+
+ //
+ // Queue a workitem for the new sends.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+
+ //
+ // If we have the local lock and there is not
+ // a reset in progress then fire off the send.
+ //
+ if (LocalLock)
+ {
+ //
+ // Process deferred.
+ //
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'KPES');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMSendPacketsToSend\n"));
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+}
+
+NDIS_STATUS
+ndisMSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ PNDIS_PACKET_RESERVED Reserved;
+ BOOLEAN LocalLock;
+ BOOLEAN SyncSend = FALSE;
+ NDIS_STATUS Status = NDIS_STATUS_PENDING;
+ KIRQL OldIrql;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnes');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMSend\n"));
+
+ //
+ // Try to grab the local lock on the miniport block.
+ //
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Increment the references on this open.
+ //
+ ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("+ Open 0x%x Reference 0x%x\n", NdisBindingHandle, ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References));
+
+ //
+ // Initialize the packet info.
+ //
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ Reserved->Next = NULL;
+ Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+
+ //
+ // Place the packet on the packet queue.
+ //
+ if (Miniport->FirstPacket == NULL)
+ {
+ //
+ // Place the packet at the head of the queue.
+ //
+ Miniport->FirstPacket = Packet;
+ }
+ else
+ {
+ CHECK_FOR_DUPLICATE_PACKET(Miniport, Packet);
+
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = Packet;
+ }
+
+ Miniport->LastPacket = Packet;
+
+ //
+ // Mark the packet as not having been looped back yet.
+ //
+ MINIPORT_CLEAR_PACKET_FLAG(Packet, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT));
+
+ if (NULL == Miniport->FirstPendingPacket)
+ {
+ Miniport->FirstPendingPacket = Packet;
+
+ SyncSend = TRUE;
+ }
+
+ //
+ // If we have the local lock and there is not
+ // a reset in progress then fire off the send.
+ //
+ if (LocalLock)
+ {
+ //
+ // Can we do a sync send?
+ //
+ if (SyncSend && (Miniport->WorkQueue[NdisWorkItemHalt].Next == NULL))
+ {
+ //
+ // TODO: Make the call to sync send inline!!!
+ //
+ // Synchronous send.
+ //
+ Status = ndisMSyncSend(Miniport, Packet);
+ }
+ else
+ {
+ //
+ // Process deferred.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+ }
+ else
+ {
+ //
+ // We can't get the local lock so queue a workitem
+ // to process the send later.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMSend\n"));
+
+ NDISM_LOG_PACKET(Miniport, Packet, (PVOID)Status, 'DNES');
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ return(Status);
+}
+
+
+VOID
+ndisMSendPacketsToFullMac(
+ IN PNDIS_OPEN_BLOCK NdisOpenBlock,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ UINT c;
+ UINT Flags;
+ PPNDIS_PACKET pPktArray;
+ NDIS_STATUS Status;
+
+ //
+ // Send the packets to the mac one at a time.
+ //
+ for (c = 0, pPktArray = PacketArray;
+ c < NumberOfPackets;
+ c++, pPktArray++)
+ {
+ //
+ // Send the packet to the mac driver.
+ //
+ Status = NdisOpenBlock->SendHandler(
+ NdisOpenBlock->MacBindingHandle,
+ *pPktArray);
+
+ //
+ // If the packet is not pending then complete it back to the protocol.
+ //
+ if (NDIS_STATUS_PENDING != Status)
+ {
+ //
+ // Call the protocol's complete handler....
+ //
+ (NdisOpenBlock->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)(
+ NdisOpenBlock->ProtocolBindingContext,
+ *pPktArray,
+ Status);
+ }
+ }
+}
+
+
+NDIS_STATUS
+ndisMResetWanSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE NdisLinkHandle,
+ IN PVOID Packet
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMResetWanSend\n"));
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnes');
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, ' PIR');
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'DNES');
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("ndisMResetWanSend: Reset in progress or Reset Requested\n"));
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMResetWanSend\n"));
+
+ return(NDIS_STATUS_RESET_IN_PROGRESS);
+}
+
+NDIS_STATUS
+ndisMResetSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMResetSend\n"));
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnes');
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, ' PIR');
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'DNES');
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("ndisMResetSend: Reset in progress or Reset Requested\n"));
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMResetSend\n"));
+
+ return(NDIS_STATUS_RESET_IN_PROGRESS);
+}
+
+VOID
+ndisMResetSendPackets(
+ IN PNDIS_OPEN_BLOCK NdisOpenBlock,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_M_OPEN_BLOCK NdisBindingHandle = (PNDIS_M_OPEN_BLOCK)NdisOpenBlock->MacBindingHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = NdisBindingHandle->MiniportHandle;
+ UINT c;
+
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMResetSendPackets\n"));
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'kpes');
+
+ for (c = 0; c < NumberOfPackets; c++)
+ {
+ NDISM_LOG_PACKET(Miniport, PacketArray[c], NULL, ' PIR');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("ndisMResetSendPackets: Reset in progress or Reset Requested\n"));
+
+ //
+ // For send packets we need to call the completion handler....
+ //
+ (NdisBindingHandle->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)(
+ NdisBindingHandle->ProtocolBindingContext,
+ PacketArray[c],
+ NDIS_STATUS_RESET_IN_PROGRESS);
+ }
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'KPES');
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMResetSendPackets\n"));
+
+}
+
+
diff --git a/private/ntos/ndis/ndis40/sendm.h b/private/ntos/ndis/ndis40/sendm.h
new file mode 100644
index 000000000..b201fdb56
--- /dev/null
+++ b/private/ntos/ndis/ndis40/sendm.h
@@ -0,0 +1,334 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ D:\nt\private\ntos\ndis\wrapper\sendm.h
+
+Abstract:
+
+Author:
+
+ Kyle Brandon (KyleB)
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#ifndef __SENDM_H
+#define __SENDM_H
+
+#if DBG
+
+extern UCHAR ndisMSendRescBuffer[512];
+extern ULONG ndisMSendRescIndex;
+
+#define REMOVE_RESOURCE(W, C) \
+{ \
+ W->SendResourcesAvailable--; \
+ ndisMSendRescBuffer[ndisMSendRescIndex++] = (UCHAR)C; \
+ ndisMSendRescBuffer[ndisMSendRescIndex++] = (UCHAR)'R'; \
+ ndisMSendRescBuffer[ndisMSendRescIndex++] = (UCHAR)W->SendResourcesAvailable;\
+ ndisMSendRescBuffer[ndisMSendRescIndex] = (UCHAR)'X'; \
+ if (ndisMSendRescIndex >= 500) \
+ { \
+ ndisMSendRescIndex = 0; \
+ } \
+}
+
+#define ADD_RESOURCE(W, C) \
+{ \
+ W->SendResourcesAvailable=0xffffff; \
+ ndisMSendRescBuffer[ndisMSendRescIndex++] = (UCHAR)C; \
+ ndisMSendRescBuffer[ndisMSendRescIndex++] = (UCHAR)'A'; \
+ ndisMSendRescBuffer[ndisMSendRescIndex++] = (UCHAR)W->SendResourcesAvailable;\
+ ndisMSendRescBuffer[ndisMSendRescIndex] = (UCHAR)'X'; \
+ if (ndisMSendRescIndex >= 500) \
+ { \
+ ndisMSendRescIndex = 0; \
+ } \
+}
+
+#define CLEAR_RESOURCE(W, C) \
+{ \
+ W->SendResourcesAvailable = 0; \
+ ndisMSendRescBuffer[ndisMSendRescIndex++] = (UCHAR)C; \
+ ndisMSendRescBuffer[ndisMSendRescIndex++] = (UCHAR)'C'; \
+ ndisMSendRescBuffer[ndisMSendRescIndex++] = (UCHAR)W->SendResourcesAvailable;\
+ if (ndisMSendRescIndex >= 500) \
+ { \
+ ndisMSendRescIndex = 0; \
+ } \
+}
+
+#define CHECK_FOR_DUPLICATE_PACKET(_M, _P) \
+{ \
+ PNDIS_PACKET pTmpPacket; \
+ \
+ IF_DBG(DBG_COMP_SEND, DBG_LEVEL_FATAL) \
+ { \
+ for (pTmpPacket = (_M)->FirstPacket; \
+ pTmpPacket != NULL; \
+ pTmpPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(pTmpPacket)->Next) \
+ { \
+ if (_P == pTmpPacket) \
+ { \
+ DBGBREAK(DBG_COMP_SEND, DBG_LEVEL_FATAL); \
+ } \
+ } \
+ } \
+}
+
+#else
+
+#define REMOVE_RESOURCE(W, C) W->SendResourcesAvailable--
+#define ADD_RESOURCE(W, C) W->SendResourcesAvailable = 0x00ffffff
+#define CLEAR_RESOURCE(W, C) W->SendResourcesAvailable = 0
+
+#define CHECK_FOR_DUPLICATE_PACKET(_M, _P)
+
+#endif
+
+
+//
+// Macros used for getting to OOB data and packet extension.
+//
+#define PNDIS_PACKET_OOB_DATA_FROM_PNDIS_PACKET(p) (PNDIS_PACKET_OOB_DATA)((PUCHAR)Packet + Packet->Private.NdisPacketOobOffset)
+#define PNDIS_PACKET_PRIVATE_EXTENSION_FROM_PNDIS_PACKET(p) (PNDIS_PACKET_PRIVATE_EXTENSION)((PUCHAR)Packet + Packet->Private.NdisPacketOobOffset + sizeof(NDIS_PACKET_OOB_DATA))
+
+/*++
+
+VOID
+MiniportFindPacket(
+ PNDIS_MINIPORT_BLOCK Miniport,
+ PNDIS_PACKET Packet,
+ PNDIS_PACKET *PrevPacket
+ )
+
+Routine Description:
+
+ Searchs the miniport send queue for a packet.
+
+Arguments:
+
+ Miniport - Miniport to send to.
+ Packet - Packet to find.
+
+Return Value:
+
+ Pointer to packet which immediately preceeds the packet to search for or
+ NULL if the packet is not found.
+
+--*/
+
+#define MiniportFindPacket(_Miniport, _Packet, _PrevPacket) \
+{ \
+ PNDIS_PACKET CurrPacket = ((PNDIS_MINIPORT_BLOCK)(_Miniport))->FirstPacket; \
+ PNDIS_PACKET TempPacket = NULL; \
+ \
+ ASSERT(CurrPacket != NULL); \
+ \
+ do \
+ { \
+ if (CurrPacket == ((PNDIS_PACKET)(_Packet))) \
+ { \
+ break; \
+ } \
+ \
+ TempPacket = CurrPacket; \
+ CurrPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(CurrPacket)->Next; \
+ } while(CurrPacket != NULL); \
+ \
+ *((PNDIS_PACKET *)(_PrevPacket)) = TempPacket; \
+ \
+ ASSERT(CurrPacket != NULL); \
+}
+
+#define NDISM_COMPLETE_SEND_COMMON(_M, _O, _P, _PrevP, _S) \
+{ \
+ if ((_S) != NDIS_STATUS_SUCCESS) \
+ { \
+ NDISM_LOG_PACKET((_M), (_P), NULL, 'liaf'); \
+ } \
+ else \
+ { \
+ NDISM_LOG_PACKET((_M), (_P), NULL, 'ccus'); \
+ } \
+ \
+ ADD_RESOURCE((_M), 'F'); \
+ \
+ /* \
+ Remove from finish queue \
+ */ \
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, \
+ ("Completed 0x%x\n", (_S))); \
+ \
+ /* \
+ If send complete was called from the miniport's send handler \
+ then our local PrevPacket pointer may no longer be valid. \
+ */ \
+ if (MINIPORT_TEST_SEND_FLAG((_M), fMINIPORT_SEND_COMPLETE_CALLED)) \
+ { \
+ MINIPORT_CLEAR_SEND_FLAG((_M), fMINIPORT_SEND_COMPLETE_CALLED); \
+ MiniportFindPacket((_M), (_P), &(_PrevP)); \
+ } \
+ \
+ /* \
+ Set up the next packet to send. \
+ */ \
+ (_M)->LastMiniportPacket = (_PrevP); \
+ if ((_PrevP) == NULL) \
+ { \
+ /* \
+ Place the packet at the head of the queue. \
+ */ \
+ (_M)->FirstPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(_P)->Next; \
+ } \
+ else \
+ { \
+ PNDIS_RESERVED_FROM_PNDIS_PACKET((_PrevP))->Next = \
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(_P)->Next; \
+ \
+ /* \
+ If we just unlinked the last packet then we need to update \
+ our last packet pointer. \
+ */ \
+ if ((_P) == (_M)->LastPacket) \
+ { \
+ (_M)->LastPacket = (_PrevP); \
+ } \
+ } \
+}
+
+#define NDISM_COMPLETE_SEND_FULL_DUPLEX(_M, _O, _P, _PrevP, _S) \
+{ \
+ /* \
+ The full-duplex completion will take care of everything but the \
+ open references. \
+ */ \
+ NDISM_COMPLETE_SEND_COMMON((_M), (_O), (_P), (_PrevP), (_S)); \
+ \
+ /* \
+ Indicate the completion to the protocol. \
+ */ \
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC((_M)); \
+ \
+ ((_O)->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)( \
+ (_O)->ProtocolBindingContext, \
+ (_P), \
+ (_S)); \
+ \
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC((_M)); \
+}
+
+#define NDISM_COMPLETE_SEND(_M, _O, _P, _PrevP, _S) \
+{ \
+ /* \
+ The full-duplex completion will take care of everything but the \
+ open references. \
+ */ \
+ NDISM_COMPLETE_SEND_COMMON((_M), (_O), (_P), (_PrevP), (_S)); \
+ \
+ /* \
+ Indicate the completion to the protocol. \
+ */ \
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC((_M)); \
+ \
+ ((_O)->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)( \
+ (_O)->ProtocolBindingContext, \
+ (_P), \
+ (_S)); \
+ \
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC((_M)); \
+ \
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO, \
+ ("- Open 0x%x Reference 0x%x\n", (_O), (_O)->References)); \
+ \
+ (_O)->References--; \
+ \
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO, \
+ ("==0 Open 0x%x Reference 0x%x\n", (_O), (_O)->References)); \
+ \
+ if ((_O)->References == 0) \
+ { \
+ ndisMFinishClose((_M), (_O)); \
+ } \
+}
+
+#define NDISM_COMPLETE_SEND_RESOURCES(_M, _P, _PrevP) \
+{ \
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, \
+ ("Deferring send\n")); \
+ \
+ NDISM_LOG_PACKET((_M), (_P), NULL, 'oser'); \
+ \
+ /* \
+ If send complete was called from the miniport's send handler \
+ then our local PrevPacket pointer may no longer be valid. \
+ */ \
+ if (MINIPORT_TEST_SEND_FLAG((_M), fMINIPORT_SEND_COMPLETE_CALLED)) \
+ { \
+ MINIPORT_CLEAR_SEND_FLAG((_M), fMINIPORT_SEND_COMPLETE_CALLED); \
+ MiniportFindPacket((_M), (_P), &(_PrevP)); \
+ } \
+ \
+ /* \
+ Remove from finish queue \
+ */ \
+ (_M)->LastMiniportPacket = (_PrevP); \
+ \
+ /* \
+ Put on pending queue \
+ */ \
+ (_M)->FirstPendingPacket = (_P); \
+ \
+ /* \
+ Mark the miniport as out of send resources. \
+ */ \
+ CLEAR_RESOURCE((_M), 'S'); \
+}
+
+#define NDISM_SEND_PACKET(_M, _O, _P, _pS) \
+{ \
+ UINT _Flags; \
+ \
+ /* \
+ Indicate the packet loopback if necessary. \
+ */ \
+ if ((((_M)->MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK) || \
+ MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_LOOPBACK_DIRECTED)) && \
+ !MINIPORT_TEST_PACKET_FLAG((_P), fPACKET_HAS_BEEN_LOOPED_BACK) && \
+ ndisMIsLoopbackPacket((_M), (_P))) \
+ { \
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, \
+ ("Packet is self-directed.\n")); \
+ \
+ /* \
+ Self-directed loopback always succeeds. \
+ */ \
+ *(_pS) = NDIS_STATUS_SUCCESS; \
+ } \
+ else \
+ { \
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, \
+ ("Sending packet 0x%x\n", Packet)); \
+ \
+ REMOVE_RESOURCE((_M), 'S'); \
+ \
+ NdisQuerySendFlags((_P), &_Flags); \
+ \
+ NDISM_LOG_PACKET((_M), (_P), NULL, 'inim'); \
+ \
+ /* \
+ Call down to the driver. \
+ */ \
+ *(_pS) = ((_O)->SendHandler)((_O)->MiniportAdapterContext, (_P), _Flags); \
+ } \
+}
+
+#endif // __SENDM_H
diff --git a/private/ntos/ndis/ndis40/sources.inc b/private/ntos/ndis/ndis40/sources.inc
new file mode 100644
index 000000000..a7812d04e
--- /dev/null
+++ b/private/ntos/ndis/ndis40/sources.inc
@@ -0,0 +1,77 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=ndis
+TARGETTYPE=EXPORT_DRIVER
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+INCLUDES=..;..\..\..\inc;..\..\..\..\inc;..\..\inc
+C_DEFINES= $(C_DEFINES) -DNDIS_WRAPPER -D_NTDRIVER_ -D_NTIFS_
+C_DEFINES= $(C_DEFINES) -DNDIS41_MINIPORT -D_SEND_PRIORITY=1
+C_DEFINES= $(C_DEFINES) -DNDIS41
+#C_DEFINES= $(C_DEFINES) -D_DBG=1
+
+NTPROFILEINPUT=yes
+
+
+SOURCES= \
+ ..\ndis.rc \
+ ..\ndis.c \
+ ..\data.c \
+ ..\init.c \
+ ..\initpnp.c \
+ ..\common.c \
+ ..\config.c \
+ ..\configm.c \
+ ..\bus.c \
+ ..\timer.c \
+ ..\timerm.c \
+ ..\miniport.c \
+ ..\minint.c \
+ ..\ndis_co.c \
+ ..\requestm.c \
+ ..\sendm.c \
+ ..\minisub.c \
+ ..\mac.c \
+ ..\protocol.c \
+ ..\efilter.c \
+ ..\ffilter.c \
+ ..\tfilter.c \
+ ..\afilter.c \
+ ..\debug.c
+
+PRECOMPILED_INCLUDE=..\precomp.h
+PRECOMPILED_PCH=precomp.pch
+PRECOMPILED_OBJ=precomp.obj
+
+DLLDEF=obj\*\ndis.def
+
+SOURCES_USED=..\sources.inc
+
+
+ \ No newline at end of file
diff --git a/private/ntos/ndis/ndis40/tfilter.c b/private/ntos/ndis/ndis40/tfilter.c
new file mode 100644
index 000000000..bb0754b3a
--- /dev/null
+++ b/private/ntos/ndis/ndis40/tfilter.c
@@ -0,0 +1,2813 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ tfilter.c
+
+Abstract:
+
+ This module implements a set of library routines to handle packet
+ filtering for NDIS MAC drivers.
+
+Author:
+
+ Anthony V. Ercolano (Tonye) 03-Aug-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+ Adam Barr (adamba) 19-Mar-1991
+
+ - Modified for Token-Ring
+ Jameel Hyder (JameelH) Re-organization 01-Jun-95
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_TFILTER
+
+//
+// Used in case we have to call TrChangeFunctionalAddress or
+// TrChangeGroupAddress with a NULL address.
+//
+static CHAR NullFunctionalAddress[4] = { 0x00 };
+
+
+//
+// Maximum number of supported opens
+//
+#define TR_FILTER_MAX_OPENS 32
+
+
+//
+// VOID
+// TR_FILTER_ALLOC_OPEN(
+// IN PTR_FILTER Filter,
+// OUT PUINT FilterIndex
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Allocates an open block. This only allocate the index, not memory for
+// the open block.
+//
+//Arguments:
+//
+// Filter - DB from which to allocate the space
+//
+// FilterIndex - pointer to place to store the index.
+//
+//Return Value:
+//
+// FilterIndex of the new open
+//
+//--*/
+#define TR_FILTER_ALLOC_OPEN(Filter, FilterIndex) \
+{ \
+ UINT i; \
+ for (i = 0; i < TR_FILTER_MAX_OPENS; i++) \
+ { \
+ if (IS_BIT_SET_IN_MASK(i, (Filter)->FreeBindingMask)) \
+ { \
+ *(FilterIndex) = i; \
+ CLEAR_BIT_IN_MASK(i, &((Filter)->FreeBindingMask)); \
+ break; \
+ } \
+ } \
+}
+
+//
+// VOID
+// TR_FILTER_FREE_OPEN(
+// IN PTR_FILTER Filter,
+// IN PTR_BINDING_INFO LocalOpen
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Frees an open block. Also frees the memory associated with the open.
+//
+//Arguments:
+//
+// Filter - DB from which to allocate the space
+//
+// FilterIndex - Index to free
+//
+//Return Value:
+//
+// None
+//
+//--*/
+#define TR_FILTER_FREE_OPEN(Filter, LocalOpen)\
+{\
+ SET_BIT_IN_MASK(((LocalOpen)->FilterIndex), &((Filter)->FreeBindingMask)); \
+ FreePhys((LocalOpen), sizeof(TR_BINDING_INFO));\
+}
+
+#define TR_CHECK_FOR_INVALID_BROADCAST_INDICATION(_F) \
+IF_DBG(DBG_COMP_FILTER, DBG_LEVEL_WARN) \
+{ \
+ if (!((_F)->CombinedPacketFilter & NDIS_PACKET_TYPE_BROADCAST)) \
+ { \
+ /* \
+ We should never receive broadcast packets \
+ to someone else unless in p-mode. \
+ */ \
+ DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_ERR, \
+ ("Bad driver, indicating broadcast packets when not set to.\n"));\
+ DBGBREAK(DBG_COMP_FILTER, DBG_LEVEL_ERR); \
+ } \
+}
+
+
+#define TR_CHECK_FOR_INVALID_DIRECTED_INDICATION(_F, _A) \
+IF_DBG(DBG_COMP_FILTER, DBG_LEVEL_WARN) \
+{ \
+ /* \
+ The result of comparing an element of the address \
+ array and the functional address. \
+ \
+ Result < 0 Implies the adapter address is greater. \
+ Result > 0 Implies the address is greater. \
+ Result = 0 Implies that the they are equal. \
+ */ \
+ INT Result; \
+ \
+ TR_COMPARE_NETWORK_ADDRESSES_EQ( \
+ (_F)->AdapterAddress, \
+ (_A), \
+ &Result); \
+ if (Result != 0) \
+ { \
+ /* \
+ We should never receive directed packets \
+ to someone else unless in p-mode. \
+ */ \
+ DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_ERR, \
+ ("Bad driver, indicating packets to another station when not in promiscuous mode.\n"));\
+ DBGBREAK(DBG_COMP_FILTER, DBG_LEVEL_ERR); \
+ } \
+}
+
+
+VOID
+trRemoveBindingFromLists(
+ IN PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding
+ )
+/*++
+
+ This routine will remove a binding from all of the list in a
+ filter database. These lists include the list of bindings,
+ the directed filter list and the broadcast filter list.
+
+Arguments:
+
+ Filter - Pointer to the filter database to remove the binding from.
+ Binding - Pointer to the binding to remove.
+
+--*/
+{
+ PTR_BINDING_INFO *ppBI;
+
+ //
+ // Remove the binding from the filters list
+ // of all bindings.
+ //
+ for (ppBI = &Filter->OpenList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextOpen)
+ {
+ if (*ppBI == Binding)
+ {
+ *ppBI = Binding->NextOpen;
+ break;
+ }
+ }
+ ASSERT(*ppBI == Binding->NextOpen);
+
+ //
+ // Remove it from the directed binding list - conditionally
+ //
+ for (ppBI = &Filter->DirectedList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextDirected)
+ {
+ if (*ppBI == Binding)
+ {
+ *ppBI = Binding->NextDirected;
+ break;
+ }
+ }
+
+ //
+ // Remove it from the broadcast/functional/group binding list - conditionally
+ //
+ for (ppBI = &Filter->BFGList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextBFG)
+ {
+ if (*ppBI == Binding)
+ {
+ *ppBI = Binding->NextBFG;
+ break;
+ }
+ }
+
+ Binding->NextDirected = NULL;
+ Binding->NextBFG = NULL;
+ Binding->NextOpen = NULL;
+}
+
+VOID
+trRemoveAndFreeBinding(
+ IN PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding,
+ IN BOOLEAN fCallCloseAction
+ )
+/*++
+
+Routine Description:
+
+ This routine will remove a binding from the filter database and
+ indicate a receive complete if necessary. This was made a function
+ to remove code redundancey in following routines. Its not time
+ critical so it's cool.
+
+Arguments:
+
+ Filter - Pointer to the filter database to remove the binding from.
+ Binding - Pointer to the binding to remove.
+ fCallCloseAction - TRUE if we should call the filter's close
+ action routine. FALSE if not.
+
+--*/
+{
+ //
+ // Remove the binding.
+ //
+ trRemoveBindingFromLists(Filter, Binding);
+
+ //
+ // If we have received and packet indications then
+ // notify the binding of the indication completion.
+ //
+ if (Binding->ReceivedAPacket)
+ {
+ if (NULL != Filter->Miniport)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+ }
+ else
+ {
+ NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ }
+
+ FilterIndicateReceiveComplete(Binding->NdisBindingContext);
+
+ if (NULL != Filter->Miniport)
+ {
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+ }
+ else
+ {
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ }
+ }
+
+ //
+ // Do we need to call the close action?
+ //
+ if (fCallCloseAction)
+ {
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+ Filter->CloseAction(Binding->MacBindingHandle);
+ }
+
+ //
+ // Free the open.
+ //
+ TR_FILTER_FREE_OPEN(Filter, Binding);
+}
+
+
+
+BOOLEAN
+TrCreateFilter(
+ IN TR_ADDRESS_CHANGE AddressChangeAction,
+ IN TR_GROUP_CHANGE GroupChangeAction,
+ IN TR_FILTER_CHANGE FilterChangeAction,
+ IN TR_DEFERRED_CLOSE CloseAction,
+ IN PUCHAR AdapterAddress,
+ IN PNDIS_SPIN_LOCK Lock,
+ OUT PTR_FILTER *Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to create and initialize the filter database.
+
+Arguments:
+
+ AddressChangeAction - Action routine to call when the ORing together
+ of the functional address desired by all the bindings had changed.
+
+ GroupChangeAction - Action routine to call when the group address
+ desired by all the bindings had changed.
+
+ FilterChangeAction - Action routine to call when a binding sets or clears
+ a particular filter class and it is the first or only binding using
+ the filter class.
+
+ CloseAction - This routine is called if a binding closes while
+ it is being indicated to via NdisIndicateReceive. It will be
+ called upon return from NdisIndicateReceive.
+
+ AdapterAddress - the address of the adapter associated with this filter
+ database.
+
+ Lock - Pointer to the lock that should be held when mutual exclusion
+ is required.
+
+ Filter - A pointer to a TR_FILTER. This is what is allocated and
+ created by this routine.
+
+Return Value:
+
+ If the function returns false then one of the parameters exceeded
+ what the filter was willing to support.
+
+--*/
+
+{
+ PTR_FILTER LocalFilter;
+ NDIS_STATUS AllocStatus;
+
+
+ //
+ // Allocate the database and it's associated arrays.
+ //
+
+ AllocStatus = AllocPhys(&LocalFilter, sizeof(TR_FILTER));
+ *Filter = LocalFilter;
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ return(FALSE);
+
+ TrReferencePackage();
+
+ ZeroMemory(LocalFilter, sizeof(TR_FILTER));
+
+ LocalFilter->FreeBindingMask = (ULONG)-1;
+
+ LocalFilter->Lock = Lock;
+
+ TR_COPY_NETWORK_ADDRESS(LocalFilter->AdapterAddress, AdapterAddress);
+ LocalFilter->AddressChangeAction = AddressChangeAction;
+ LocalFilter->GroupChangeAction = GroupChangeAction;
+ LocalFilter->FilterChangeAction = FilterChangeAction;
+ LocalFilter->CloseAction = CloseAction;
+
+ return(TRUE);
+}
+
+//
+// NOTE : THIS ROUTINE CANNOT BE PAGEABLE
+//
+
+VOID
+TrDeleteFilter(
+ IN PTR_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to delete the memory associated with a filter
+ database. Note that this routines *ASSUMES* that the database
+ has been cleared of any active filters.
+
+Arguments:
+
+ Filter - A pointer to a TR_FILTER to be deleted.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ASSERT(Filter->OpenList == NULL);
+
+ FreePhys(Filter, sizeof(TR_FILTER));
+
+ TrDereferencePackage();
+}
+
+
+BOOLEAN
+TrNoteFilterOpenAdapter(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE NdisBindingContext,
+ OUT PNDIS_HANDLE NdisFilterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to add a new binding to the filter database.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE DATABASE IS LOCKED WHEN
+ IT IS CALLED.
+
+Arguments:
+
+ Filter - A pointer to the previously created and initialized filter
+ database.
+
+ MacBindingHandle - The MAC supplied value to the protocol in response
+ to a call to MacOpenAdapter.
+
+ NdisBindingContext - An NDIS supplied value to the call to MacOpenAdapter.
+
+ NdisFilterHandle - A pointer to the open block.
+
+Return Value:
+
+ Will return false if creating a new filter index will cause the maximum
+ number of filter indexes to be exceeded.
+
+--*/
+
+{
+ NDIS_STATUS AllocStatus;
+
+ //
+ // Will hold the value of the filter index so that we
+ // need not indirectly address through pointer parameter.
+ //
+ UINT LocalIndex;
+
+ //
+ // This new open
+ //
+ PTR_BINDING_INFO LocalOpen;
+
+ PNDIS_OPEN_BLOCK NdisOpen = (PNDIS_OPEN_BLOCK)NdisBindingContext;
+
+ if (Filter->FreeBindingMask == 0)
+ return(FALSE);
+
+ AllocStatus = AllocPhys(&LocalOpen, sizeof(TR_BINDING_INFO));
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ return(FALSE);
+
+ //
+ // Zero the memory
+ //
+ ZeroMemory(LocalOpen, sizeof(TR_BINDING_INFO));
+
+ //
+ // Get place for the open and insert it.
+ //
+ TR_FILTER_ALLOC_OPEN(Filter, &LocalIndex);
+
+ LocalOpen->NextOpen = Filter->OpenList;
+ Filter->OpenList = LocalOpen;
+
+ LocalOpen->References = 1;
+ LocalOpen->FilterIndex = (UCHAR)LocalIndex;
+ LocalOpen->MacBindingHandle = MacBindingHandle;
+ LocalOpen->NdisBindingContext = NdisBindingContext;
+
+ *NdisFilterHandle = (PTR_BINDING_INFO)LocalOpen;
+
+ return(TRUE);
+}
+
+
+NDIS_STATUS
+TrDeleteFilterOpenAdapter(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ When an adapter is being closed this routine should
+ be called to delete knowledge of the adapter from
+ the filter database. This routine is likely to call
+ action routines associated with clearing filter classes
+ and addresses.
+
+ NOTE: THIS ROUTINE SHOULD ****NOT**** BE CALLED IF THE ACTION
+ ROUTINES FOR DELETING THE FILTER CLASSES OR THE FUNCTIONAL ADDRESSES
+ HAVE ANY POSSIBILITY OF RETURNING A STATUS OTHER THAN NDIS_STATUS_PENDING
+ OR NDIS_STATUS_SUCCESS. WHILE THESE ROUTINES WILL NOT BUGCHECK IF
+ SUCH A THING IS DONE, THE CALLER WILL PROBABLY FIND IT DIFFICULT
+ TO CODE A CLOSE ROUTINE!
+
+ NOTE: THIS ROUTINE ASSUMES THAT IT IS CALLED WITH THE LOCK HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - A pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routines,
+ this will be passed to it.
+
+Return Value:
+
+ If action routines are called by the various address and filtering
+ routines the this routine will likely return the status returned
+ by those routines. The exception to this rule is noted below.
+
+ Given that the filter and address deletion routines return a status
+ NDIS_STATUS_PENDING or NDIS_STATUS_SUCCESS this routine will then
+ try to return the filter index to the freelist. If the routine
+ detects that this binding is currently being indicated to via
+ NdisIndicateReceive, this routine will return a status of
+ NDIS_STATUS_CLOSING_INDICATING.
+
+--*/
+
+{
+ //
+ // Holds the status returned from the packet filter and address
+ // deletion routines. Will be used to return the status to
+ // the caller of this routine.
+ //
+ NDIS_STATUS StatusToReturn;
+
+ PTR_BINDING_INFO LocalOpen = (PTR_BINDING_INFO)NdisFilterHandle;
+
+ //
+ // Set the packet filter to NONE.
+ //
+ StatusToReturn = TrFilterAdjust(Filter,
+ NdisFilterHandle,
+ NdisRequest,
+ (UINT)0,
+ FALSE);
+ if ((NDIS_STATUS_SUCCESS == StatusToReturn) ||
+ (NDIS_STATUS_PENDING == StatusToReturn))
+ {
+ NDIS_STATUS StatusToReturn2;
+
+ //
+ // Clear the functional address.
+ //
+ StatusToReturn2 = TrChangeFunctionalAddress(
+ Filter,
+ NdisFilterHandle,
+ NdisRequest,
+ NullFunctionalAddress,
+ FALSE);
+ if (StatusToReturn2 != NDIS_STATUS_SUCCESS)
+ {
+ StatusToReturn = StatusToReturn2;
+ }
+ }
+
+ if (((StatusToReturn == NDIS_STATUS_SUCCESS) ||
+ (StatusToReturn == NDIS_STATUS_PENDING)) &&
+ (LocalOpen->UsingGroupAddress))
+ {
+ Filter->GroupReferences--;
+
+ LocalOpen->UsingGroupAddress = FALSE;
+
+ if (Filter->GroupReferences == 0)
+ {
+ NDIS_STATUS StatusToReturn2;
+
+ //
+ // Clear the group address if no other bindings are using it.
+ //
+ StatusToReturn2 = TrChangeGroupAddress(
+ Filter,
+ NdisFilterHandle,
+ NdisRequest,
+ NullFunctionalAddress,
+ FALSE);
+ if (StatusToReturn2 != NDIS_STATUS_SUCCESS)
+ {
+ StatusToReturn = StatusToReturn2;
+ }
+ }
+ }
+
+ if ((StatusToReturn == NDIS_STATUS_SUCCESS) ||
+ (StatusToReturn == NDIS_STATUS_PENDING))
+ {
+ //
+ // If this is the last reference to the open - remove it.
+ //
+ if ((--(LocalOpen->References)) == 0)
+ {
+ //
+ // Remove the binding and indicate a receive complete
+ // if necessary.
+ //
+ trRemoveAndFreeBinding(Filter, LocalOpen, FALSE);
+ }
+ else
+ {
+ //
+ // Let the caller know that this "reference" to the open
+ // is still "active". The close action routine will be
+ // called upon return from NdisIndicateReceive.
+ //
+ StatusToReturn = NDIS_STATUS_CLOSING_INDICATING;
+ }
+ }
+
+ return(StatusToReturn);
+}
+
+VOID
+trUndoChangeFunctionalAddress(
+ IN PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding
+)
+{
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+ Binding->FunctionalAddress = Binding->OldFunctionalAddress;
+ Filter->CombinedFunctionalAddress = Filter->OldCombinedFunctionalAddress;
+}
+
+
+
+NDIS_STATUS
+TrChangeFunctionalAddress(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN CHAR FunctionalAddressArray[TR_LENGTH_OF_FUNCTIONAL],
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ The ChangeFunctionalAddress routine will call an action
+ routine when the overall functional address for the adapter
+ has changed.
+
+ If the action routine returns a value other than pending or
+ success then this routine has no effect on the functional address
+ for the open or for the adapter as a whole.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - A pointer to the open
+
+ NdisRequest - If it is necessary to call the action routine,
+ this will be passed to it.
+
+ FunctionalAddress - The new functional address for this binding.
+
+ Set - A boolean that determines whether the filter classes
+ are being adjusted due to a set or because of a close. (The filtering
+ routines don't care, the MAC might.)
+
+Return Value:
+
+ If it calls the action routine then it will return the
+ status returned by the action routine. If the status
+ returned by the action routine is anything other than
+ NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
+ will be returned to the state it was in upon entrance to this
+ routine.
+
+ If the action routine is not called this routine will return
+ the following statum:
+
+ NDIS_STATUS_SUCCESS - If the new packet filters doesn't change
+ the combined mask of all bindings packet filters.
+
+--*/
+
+{
+ //
+ // Holds the functional address as a longword.
+ //
+ TR_FUNCTIONAL_ADDRESS FunctionalAddress;
+
+ //
+ // Pointer to the open.
+ //
+ PTR_BINDING_INFO LocalOpen = (PTR_BINDING_INFO)NdisFilterHandle;
+
+ //
+ // Holds the status returned to the user of this routine, if the
+ // action routine is not called then the status will be success,
+ // otherwise, it is whatever the action routine returns.
+ //
+ NDIS_STATUS StatusOfAdjust;
+
+ //
+ // Simple iteration variable.
+ //
+ PTR_BINDING_INFO OpenList;
+
+
+ //
+ // Convert the 32 bits of the address to a longword.
+ //
+ RetrieveUlong(&FunctionalAddress, FunctionalAddressArray);
+
+ //
+ // Set the new filter information for the open.
+ //
+ LocalOpen->OldFunctionalAddress = LocalOpen->FunctionalAddress;
+ LocalOpen->FunctionalAddress = FunctionalAddress;
+
+ //
+ // Contains the value of the combined functional address before
+ // it is adjusted.
+ //
+ Filter->OldCombinedFunctionalAddress = Filter->CombinedFunctionalAddress;
+
+ //
+ // We always have to reform the compbined filter since
+ // this filter index may have been the only filter index
+ // to use a particular bit.
+ //
+
+ for (OpenList = Filter->OpenList, Filter->CombinedFunctionalAddress = 0;
+ OpenList != NULL;
+ OpenList = OpenList->NextOpen)
+ {
+ Filter->CombinedFunctionalAddress |= OpenList->FunctionalAddress;
+ }
+
+ if (Filter->OldCombinedFunctionalAddress != Filter->CombinedFunctionalAddress)
+ {
+ StatusOfAdjust = Filter->AddressChangeAction(
+ Filter->OldCombinedFunctionalAddress,
+ Filter->CombinedFunctionalAddress,
+ LocalOpen->MacBindingHandle,
+ NdisRequest,
+ Set);
+
+ if ((StatusOfAdjust != NDIS_STATUS_SUCCESS) &&
+ (StatusOfAdjust != NDIS_STATUS_PENDING))
+ {
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+ trUndoChangeFunctionalAddress(Filter, LocalOpen);
+ }
+ }
+ else
+ {
+ StatusOfAdjust = NDIS_STATUS_SUCCESS;
+ }
+
+ return(StatusOfAdjust);
+}
+
+VOID
+trUndoChangeGroupAddress(
+ IN PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding
+ )
+{
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+ Filter->GroupAddress = Filter->OldGroupAddress;
+ Filter->GroupReferences = Filter->OldGroupReferences;
+
+ Binding->UsingGroupAddress = Binding->OldUsingGroupAddress;
+}
+
+
+NDIS_STATUS
+TrChangeGroupAddress(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN CHAR GroupAddressArray[TR_LENGTH_OF_FUNCTIONAL],
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ The ChangeGroupAddress routine will call an action
+ routine when the overall group address for the adapter
+ has changed.
+
+ If the action routine returns a value other than pending or
+ success then this routine has no effect on the group address
+ for the open or for the adapter as a whole.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - A pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routine,
+ this will be passed to it.
+
+ GroupAddressArray - The new group address for this binding.
+
+ Set - A boolean that determines whether the filter classes
+ are being adjusted due to a set or because of a close. (The filtering
+ routines don't care, the MAC might.)
+
+Return Value:
+
+ If it calls the action routine then it will return the
+ status returned by the action routine. If the status
+ returned by the action routine is anything other than
+ NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
+ will be returned to the state it was in upon entrance to this
+ routine.
+
+ If the action routine is not called this routine will return
+ the following statum:
+
+ NDIS_STATUS_SUCCESS - If the new packet filters doesn't change
+ the combined mask of all bindings packet filters.
+
+--*/
+
+{
+ //
+ // Holds the Group address as a longword.
+ //
+ TR_FUNCTIONAL_ADDRESS GroupAddress;
+
+ PTR_BINDING_INFO LocalOpen = (PTR_BINDING_INFO)NdisFilterHandle;
+
+ //
+ // Holds the status returned to the user of this routine, if the
+ // action routine is not called then the status will be success,
+ // otherwise, it is whatever the action routine returns.
+ //
+ NDIS_STATUS StatusOfAdjust = NDIS_STATUS_PENDING;
+
+ //
+ // Convert the 32 bits of the address to a longword.
+ //
+ RetrieveUlong(&GroupAddress, GroupAddressArray);
+
+ Filter->OldGroupAddress = Filter->GroupAddress;
+ Filter->OldGroupReferences = Filter->GroupReferences;
+ LocalOpen->OldUsingGroupAddress = LocalOpen->UsingGroupAddress;
+
+ //
+ // If the new group address is 0 then a binding is
+ // attempting to delete the current group address.
+ //
+ if (0 == GroupAddress)
+ {
+ //
+ // Is the binding using the group address?
+ //
+ if (LocalOpen->UsingGroupAddress)
+ {
+ //
+ // Remove the bindings reference.
+ //
+ Filter->GroupReferences--;
+ LocalOpen->UsingGroupAddress = FALSE;
+
+ //
+ // Are any other bindings using the group address?
+ //
+ if (Filter->GroupReferences != 0)
+ {
+ //
+ // Since other bindings are using the group address
+ // we cannot tell the driver to remove it.
+ //
+ return(NDIS_STATUS_SUCCESS);
+ }
+
+ //
+ // We are the only binding using the group address
+ // so we fall through and call the driver to delete it.
+ //
+ }
+ else
+ {
+ //
+ // This binding is not using the group address but
+ // it is trying to clear it.
+ //
+ if (Filter->GroupReferences != 0)
+ {
+ //
+ // There are other bindings using the group address
+ // so we cannot delete it.
+ //
+ return(NDIS_STATUS_GROUP_ADDRESS_IN_USE);
+ }
+ else
+ {
+ //
+ // There are no bindings using the group address.
+ //
+ return(NDIS_STATUS_SUCCESS);
+ }
+ }
+ }
+ else
+ {
+ //
+ // See if this address is already the current address.
+ //
+ if (GroupAddress == Filter->GroupAddress)
+ {
+ //
+ // If the current binding is already using the
+ // group address then do nothing.
+ //
+ if (LocalOpen->UsingGroupAddress)
+ {
+ return(NDIS_STATUS_SUCCESS);
+ }
+
+ //
+ // If there are already bindings that are using the group
+ // address then we just need to update the bindings
+ // information.
+ //
+ if (Filter->GroupReferences != 0)
+ {
+ //
+ // We can take care of everything here...
+ //
+ Filter->GroupReferences++;
+ LocalOpen->UsingGroupAddress = TRUE;
+
+ return(NDIS_STATUS_SUCCESS);
+ }
+ }
+ else
+ {
+ //
+ // If there are other bindings using the address then
+ // we can't change it.
+ //
+ if (Filter->GroupReferences > 1)
+ {
+ return(NDIS_STATUS_GROUP_ADDRESS_IN_USE);
+ }
+
+ //
+ // Is there only one binding using the address?
+ // If is it some other binding?
+ //
+ if ((Filter->GroupReferences == 1) &&
+ (!LocalOpen->UsingGroupAddress))
+ {
+ //
+ // Some other binding is using the group address.
+ //
+ return(NDIS_STATUS_GROUP_ADDRESS_IN_USE);
+ }
+
+ //
+ // Is this the only binding using the address.
+ //
+ if ((Filter->GroupReferences == 1) &&
+ (LocalOpen->UsingGroupAddress))
+ {
+ //
+ // Remove the reference.
+ //
+ Filter->GroupReferences = 0;
+ LocalOpen->UsingGroupAddress = FALSE;
+ }
+ }
+ }
+
+ //
+ // Set the new filter information for the open.
+ //
+ Filter->GroupAddress = GroupAddress;
+ StatusOfAdjust = Filter->GroupChangeAction(
+ Filter->OldGroupAddress,
+ Filter->GroupAddress,
+ LocalOpen->MacBindingHandle,
+ NdisRequest,
+ Set);
+
+ if ((StatusOfAdjust != NDIS_STATUS_SUCCESS) &&
+ (StatusOfAdjust != NDIS_STATUS_PENDING))
+ {
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+ trUndoChangeGroupAddress(Filter, LocalOpen);
+ }
+ else if (GroupAddress == 0)
+ {
+ LocalOpen->UsingGroupAddress = FALSE;
+ Filter->GroupReferences = 0;
+ }
+ else
+ {
+ LocalOpen->UsingGroupAddress = TRUE;
+ Filter->GroupReferences = 1;
+ }
+
+ return(StatusOfAdjust);
+}
+
+
+VOID
+trUpdateDirectedBindingList(
+ IN OUT PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding,
+ IN BOOLEAN fAddBindingToList
+ )
+{
+ PTR_BINDING_INFO CurrentBinding;
+ BOOLEAN AlreadyOnList;
+
+ //
+ // Do we need to add it to the directed list?
+ //
+ if (fAddBindingToList)
+ {
+ //
+ // First we need to see if it is already on the
+ // directed list.
+ //
+ for (CurrentBinding = Filter->DirectedList, AlreadyOnList = FALSE;
+ CurrentBinding != NULL;
+ CurrentBinding = CurrentBinding->NextDirected
+ )
+ {
+ if (CurrentBinding == Binding)
+ {
+ AlreadyOnList = TRUE;
+ }
+ }
+
+ if (!AlreadyOnList)
+ {
+ Binding->NextDirected = Filter->DirectedList;
+ Filter->DirectedList = Binding;
+ }
+ }
+ else
+ {
+ PTR_BINDING_INFO *ppBI;
+
+ for (ppBI = &Filter->DirectedList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextDirected)
+ {
+ if (*ppBI == Binding)
+ {
+ *ppBI = Binding->NextDirected;
+ break;
+ }
+ }
+ Binding->NextDirected = NULL;
+ }
+}
+
+
+VOID
+trUpdateBroadcastBindingList(
+ IN OUT PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding,
+ IN BOOLEAN fAddToList
+ )
+{
+ PTR_BINDING_INFO CurrentBinding;
+ BOOLEAN AlreadyOnList;
+
+ //
+ // Do we need to add it to the directed list?
+ //
+ if (fAddToList)
+ {
+ //
+ // First we need to see if it is already on the
+ // directed list.
+ //
+ for (CurrentBinding = Filter->BFGList, AlreadyOnList = FALSE;
+ CurrentBinding != NULL;
+ CurrentBinding = CurrentBinding->NextBFG)
+ {
+ if (CurrentBinding == Binding)
+ {
+ AlreadyOnList = TRUE;
+ }
+ }
+
+ if (!AlreadyOnList)
+ {
+ Binding->NextBFG = Filter->BFGList;
+ Filter->BFGList = Binding;
+ }
+ }
+ else
+ {
+ PTR_BINDING_INFO *ppBI;
+
+ for (ppBI = &Filter->BFGList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextBFG)
+ {
+ if (*ppBI == Binding)
+ {
+ *ppBI = Binding->NextBFG;
+ break;
+ }
+ }
+
+ Binding->NextBFG = NULL;
+ }
+}
+
+
+VOID
+trUpdateSpecificBindingLists(
+ IN OUT PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding
+)
+{
+ BOOLEAN fOnDirectedList = FALSE;
+ BOOLEAN fOnBFGList = FALSE;
+ BOOLEAN fAddToDirectedList = FALSE;
+ BOOLEAN fAddToBFGList = FALSE;
+
+ //
+ // If the old filter is promsicuous then it is currently on
+ // both lists.
+ //
+ if (Binding->OldPacketFilters & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL))
+ {
+ fOnDirectedList = TRUE;
+ fOnBFGList = TRUE;
+ }
+ else
+ {
+ //
+ // If the binding had the directed bit set then it is on
+ // the directed list.
+ //
+ if (Binding->OldPacketFilters & NDIS_PACKET_TYPE_DIRECTED)
+ {
+ fOnDirectedList = TRUE;
+ }
+
+ //
+ // If the binding had the broadcast/functional/group bit set then it is on
+ // the broadcast/functional list.
+ //
+ if (Binding->OldPacketFilters & (NDIS_PACKET_TYPE_BROADCAST |
+ NDIS_PACKET_TYPE_GROUP |
+ NDIS_PACKET_TYPE_FUNCTIONAL|
+ NDIS_PACKET_TYPE_ALL_FUNCTIONAL))
+ {
+ fOnBFGList = TRUE;
+ }
+ }
+
+ //
+ // If the current filter has the promsicuous bit set then we
+ // need to add it to both lists.
+ //
+ if (Binding->PacketFilters & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL))
+ {
+ fAddToDirectedList = TRUE;
+ fAddToBFGList = TRUE;
+ }
+ else
+ {
+ //
+ // Was the directed bit set?
+ //
+ if (Binding->PacketFilters & NDIS_PACKET_TYPE_DIRECTED)
+ {
+ fAddToDirectedList = TRUE;
+ }
+
+ //
+ // Was the broadcast bit set?
+ //
+ if (Binding->PacketFilters & (NDIS_PACKET_TYPE_BROADCAST |
+ NDIS_PACKET_TYPE_GROUP |
+ NDIS_PACKET_TYPE_FUNCTIONAL |
+ NDIS_PACKET_TYPE_ALL_FUNCTIONAL))
+ {
+ fAddToBFGList = TRUE;
+ }
+ }
+
+ //
+ // Determine if the binding should be added or removed from
+ // the directed list.
+ //
+ if (!fOnDirectedList && fAddToDirectedList)
+ {
+ //
+ // Add the binding to the directed list.
+ //
+ trUpdateDirectedBindingList(Filter, Binding, TRUE);
+ }
+ else if (fOnDirectedList && !fAddToDirectedList)
+ {
+ //
+ // Remove it from the directed list.
+ //
+ trUpdateDirectedBindingList(Filter, Binding, FALSE);
+ }
+
+ //
+ // Determine if the binding should be added or removed from
+ // the broadcast list.
+ //
+ if (!fOnBFGList && fAddToBFGList)
+ {
+ //
+ // Add the binding to the broadcast list.
+ //
+ trUpdateBroadcastBindingList(Filter, Binding, TRUE);
+ }
+ else if (fOnBFGList && !fAddToBFGList)
+ {
+ //
+ // Remove the binding from the broadcast list.
+ //
+ trUpdateBroadcastBindingList(Filter, Binding, FALSE);
+ }
+
+}
+
+VOID
+trUndoFilterAdjust(
+ IN PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding
+)
+{
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+ Binding->PacketFilters = Binding->OldPacketFilters;
+ Filter->CombinedPacketFilter = Filter->OldCombinedPacketFilter;
+
+ //
+ // Remove the binding from the filter lists.
+ //
+ trUpdateSpecificBindingLists(Filter, Binding);
+}
+
+
+NDIS_STATUS
+TrFilterAdjust(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT FilterClasses,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ The FilterAdjust routine will call an action routine when a
+ particular filter class is changes from not being used by any
+ binding to being used by at least one binding or vice versa.
+
+ If the action routine returns a value other than pending or
+ success then this routine has no effect on the packet filters
+ for the open or for the adapter as a whole.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - A pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routine,
+ this will be passed to it.
+
+ FilterClasses - The filter classes that are to be added or
+ deleted.
+
+ Set - A boolean that determines whether the filter classes
+ are being adjusted due to a set or because of a close. (The filtering
+ routines don't care, the MAC might.)
+
+Return Value:
+
+ If it calls the action routine then it will return the
+ status returned by the action routine. If the status
+ returned by the action routine is anything other than
+ NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
+ will be returned to the state it was in upon entrance to this
+ routine.
+
+ If the action routine is not called this routine will return
+ the following statum:
+
+ NDIS_STATUS_SUCCESS - If the new packet filters doesn't change
+ the combined mask of all bindings packet filters.
+
+--*/
+
+{
+ //
+ // Pointer to the open
+ //
+ PTR_BINDING_INFO LocalOpen = (PTR_BINDING_INFO)NdisFilterHandle;
+
+ //
+ // Holds the status returned to the user of this routine, if the
+ // action routine is not called then the status will be success,
+ // otherwise, it is whatever the action routine returns.
+ //
+ NDIS_STATUS StatusOfAdjust;
+
+ //
+ // Simple iteration variable.
+ //
+ PTR_BINDING_INFO OpenList;
+
+ //
+ // Set the new filter information for the open.
+ //
+ LocalOpen->OldPacketFilters = LocalOpen->PacketFilters;
+ LocalOpen->PacketFilters = FilterClasses;
+ Filter->OldCombinedPacketFilter = Filter->CombinedPacketFilter;
+
+ //
+ // We always have to reform the compbined filter since
+ // this filter index may have been the only filter index
+ // to use a particular bit.
+ //
+ for (OpenList = Filter->OpenList, Filter->CombinedPacketFilter = 0;
+ OpenList != NULL;
+ OpenList = OpenList->NextOpen)
+ {
+ Filter->CombinedPacketFilter |= OpenList->PacketFilters;
+ }
+
+ //
+ // Update the specific binding lists with the new information.
+ //
+ trUpdateSpecificBindingLists(Filter, LocalOpen);
+
+ //
+ // If the packet filter has changed then we need to call down to
+ // the change action handler.
+ //
+ if ((Filter->OldCombinedPacketFilter & ~NDIS_PACKET_TYPE_ALL_LOCAL) !=
+ (Filter->CombinedPacketFilter & ~NDIS_PACKET_TYPE_ALL_LOCAL))
+ {
+ StatusOfAdjust = Filter->FilterChangeAction(
+ Filter->OldCombinedPacketFilter & ~NDIS_PACKET_TYPE_ALL_LOCAL,
+ Filter->CombinedPacketFilter & ~NDIS_PACKET_TYPE_ALL_LOCAL,
+ LocalOpen->MacBindingHandle,
+ NdisRequest,
+ Set);
+ if ((StatusOfAdjust != NDIS_STATUS_SUCCESS) &&
+ (StatusOfAdjust != NDIS_STATUS_PENDING))
+ {
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+ trUndoFilterAdjust(Filter, LocalOpen);
+ }
+ }
+ else
+ {
+ StatusOfAdjust = NDIS_STATUS_SUCCESS;
+ }
+
+ return(StatusOfAdjust);
+}
+
+
+
+VOID
+TrFilterDprIndicateReceiveFullMac(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate a packet to
+ all bindings. The packet will be filtered so that only the
+ appropriate bindings will receive the packet.
+
+ Called at DPC_LEVEL.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ MacReceiveContext - A MAC supplied context value that must be
+ returned by the protocol if it calls MacTransferData.
+
+ HeaderBuffer - A virtual address of the virtually contiguous
+ buffer containing the MAC header of the packet.
+
+ HeaderBufferSize - An unsigned integer indicating the size of
+ the header buffer, in bytes.
+
+ LookaheadBuffer - A virtual address of the virtually contiguous
+ buffer containing the first LookaheadBufferSize bytes of data
+ of the packet. The packet buffer is valid only within the current
+ call to the receive event handler.
+
+ LookaheadBufferSize - An unsigned integer indicating the size of
+ the lookahead buffer, in bytes.
+
+ PacketSize - An unsigned integer indicating the size of the received
+ packet, in bytes. This number has nothing to do with the lookahead
+ buffer, but indicates how large the arrived packet is so that a
+ subsequent MacTransferData request can be made to transfer the entire
+ packet as necessary.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // The destination address in the lookahead buffer.
+ //
+ PCHAR DestinationAddress = (PCHAR)HeaderBuffer + 2;
+
+ //
+ // The source address in the lookahead buffer.
+ //
+ PCHAR SourceAddress = (PCHAR)HeaderBuffer + 8;
+
+ //
+ // Will hold the type of address that we know we've got.
+ //
+ UINT AddressType;
+
+ //
+ // TRUE if the packet is source routing packet.
+ //
+ BOOLEAN IsSourceRouting;
+
+ //
+ // TRUE if the packet is a MAC frame packet.
+ //
+ BOOLEAN IsMacFrame;
+
+ //
+ // The functional address as a longword, if the packet
+ // is addressed to one.
+ //
+ TR_FUNCTIONAL_ADDRESS FunctionalAddress;
+
+ //
+ // Will hold the status of indicating the receive packet.
+ // ZZZ For now this isn't used.
+ //
+ NDIS_STATUS StatusOfReceive;
+
+ //
+ // Will hold the open being indicated.
+ //
+ PTR_BINDING_INFO LocalOpen, NextOpen;
+
+ //
+ // Will hold the filter classes of the binding being indicated.
+ //
+ UINT BindingFilters;
+
+ //
+ // Holds intersection of open filters and this packet's type
+ //
+ UINT IntersectionOfFilters;
+
+ //
+ // If the packet is a runt packet, then only indicate to PROMISCUOUS
+ //
+
+ if ((HeaderBufferSize >= 14) && (PacketSize != 0))
+ {
+ UINT ResultOfAddressCheck;
+
+ TR_IS_NOT_DIRECTED(DestinationAddress, &ResultOfAddressCheck);
+
+ //
+ // Handle the directed packet case first
+ //
+ if (!ResultOfAddressCheck)
+ {
+ UINT IsNotOurs;
+
+ //
+ // If it is a directed packet, then check if the combined packet
+ // filter is PROMISCUOUS, if it is check if it is directed towards
+ // us
+ //
+ IsNotOurs = FALSE; // Assume it is
+ if (Filter->CombinedPacketFilter & (NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_ALL_LOCAL |
+ NDIS_PACKET_TYPE_ALL_FUNCTIONAL))
+ {
+ TR_COMPARE_NETWORK_ADDRESSES_EQ(Filter->AdapterAddress,
+ DestinationAddress,
+ &IsNotOurs);
+ }
+
+ //
+ // Walk the directed list and indicate up the packets.
+ //
+ for (LocalOpen = Filter->DirectedList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextDirected;
+
+ //
+ // Ignore if not directed to us and if the binding is not promiscuous
+ //
+ if (((LocalOpen->PacketFilters & NDIS_PACKET_TYPE_PROMISCUOUS) == 0) &&
+ IsNotOurs)
+ {
+ continue;
+ }
+
+ LocalOpen->References++;
+
+ NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ //
+ // Indicate the packet to the binding.
+ //
+ ProtocolFilterIndicateReceive(&StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize,
+ NdisMedium802_5);
+
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ --LocalOpen->References;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+ trRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+
+ return;
+ }
+
+ TR_IS_SOURCE_ROUTING(SourceAddress, &IsSourceRouting);
+ IsMacFrame = TR_IS_MAC_FRAME(HeaderBuffer);
+
+ //
+ // First check if it *at least* has the functional address bit.
+ //
+ TR_IS_NOT_DIRECTED(DestinationAddress, &ResultOfAddressCheck);
+ if (ResultOfAddressCheck)
+ {
+ //
+ // It is at least a functional address. Check to see if
+ // it is a broadcast address.
+ //
+ TR_IS_BROADCAST(DestinationAddress, &ResultOfAddressCheck);
+ if (ResultOfAddressCheck)
+ {
+ TR_CHECK_FOR_INVALID_BROADCAST_INDICATION(Filter);
+
+ AddressType = NDIS_PACKET_TYPE_BROADCAST;
+ }
+ else
+ {
+ TR_IS_GROUP(DestinationAddress, &ResultOfAddressCheck);
+ if (ResultOfAddressCheck)
+ {
+ AddressType = NDIS_PACKET_TYPE_GROUP;
+ }
+ else
+ {
+ AddressType = NDIS_PACKET_TYPE_FUNCTIONAL;
+ }
+
+ RetrieveUlong(&FunctionalAddress, (DestinationAddress + 2));
+ }
+ }
+ }
+ else
+ {
+ // Runt Packet
+ AddressType = NDIS_PACKET_TYPE_PROMISCUOUS;
+ IsSourceRouting = FALSE;
+ }
+
+
+ //
+ // At this point we know that the packet is either:
+ // - Runt packet - indicated by AddressType = NDIS_PACKET_TYPE_PROMISCUOUS (OR)
+ // - Broadcast packet - indicated by AddressType = NDIS_PACKET_TYPE_BROADCAST (OR)
+ // - Functional packet - indicated by AddressType = NDIS_PACKET_TYPE_FUNCTIONAL
+ //
+ // Walk the broadcast/functional list and indicate up the packets.
+ //
+ // The packet is indicated if it meets the following criteria:
+ //
+ // if ((Binding is promiscuous) OR
+ // ((Packet is broadcast) AND (Binding is Broadcast)) OR
+ // ((Packet is functional) AND
+ // ((Binding is all-functional) OR
+ // ((Binding is functional) AND (binding using functional address)))) OR
+ // ((Packet is a group packet) AND (Intersection of filters uses group addresses)) OR
+ // ((Packet is a macframe) AND (Binding wants mac frames)) OR
+ // ((Packet is a source routing packet) AND (Binding wants source routing packetss)))
+ //
+ for (LocalOpen = Filter->BFGList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ UINT LocalFilter = LocalOpen->PacketFilters;
+ UINT IntersectionOfFilters = LocalFilter & AddressType;
+ UINT IndexOfAddress;
+
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextBFG;
+
+ if ((LocalFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_BROADCAST) &&
+ (LocalFilter & NDIS_PACKET_TYPE_BROADCAST)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_FUNCTIONAL) &&
+ ((LocalFilter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL) ||
+ ((LocalFilter & NDIS_PACKET_TYPE_FUNCTIONAL) &&
+ (FunctionalAddress & LocalOpen->FunctionalAddress)))) ||
+
+ ((IntersectionOfFilters & NDIS_PACKET_TYPE_GROUP) &&
+ (LocalOpen->UsingGroupAddress) &&
+ (FunctionalAddress == Filter->GroupAddress)) ||
+
+ ((LocalFilter & NDIS_PACKET_TYPE_SOURCE_ROUTING) &&
+ IsSourceRouting) ||
+
+ ((LocalFilter & NDIS_PACKET_TYPE_MAC_FRAME) &&
+ IsMacFrame))
+ {
+ LocalOpen->References++;
+
+ NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ //
+ // Indicate the packet to the binding.
+ //
+ ProtocolFilterIndicateReceive(&StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize,
+ NdisMedium802_5);
+
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ if ((--(LocalOpen->References)) == 0)
+ {
+ //
+ // This binding is shutting down.
+ //
+ trRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+ }
+}
+
+
+
+VOID
+TrFilterIndicateReceive(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate a packet to
+ all bindings. The packet will be filtered so that only the
+ appropriate bindings will receive the packet.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ MacReceiveContext - A MAC supplied context value that must be
+ returned by the protocol if it calls MacTransferData.
+
+ HeaderBuffer - A virtual address of the virtually contiguous
+ buffer containing the MAC header of the packet.
+
+ HeaderBufferSize - An unsigned integer indicating the size of
+ the header buffer, in bytes.
+
+ LookaheadBuffer - A virtual address of the virtually contiguous
+ buffer containing the first LookaheadBufferSize bytes of data
+ of the packet. The packet buffer is valid only within the current
+ call to the receive event handler.
+
+ LookaheadBufferSize - An unsigned integer indicating the size of
+ the lookahead buffer, in bytes.
+
+ PacketSize - An unsigned integer indicating the size of the received
+ packet, in bytes. This number has nothing to do with the lookahead
+ buffer, but indicates how large the arrived packet is so that a
+ subsequent MacTransferData request can be made to transfer the entire
+ packet as necessary.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ KIRQL OldIrql;
+
+ NDIS_ACQUIRE_SPIN_LOCK(Filter->Lock, &OldIrql);
+
+ TrFilterDprIndicateReceiveFullMac(Filter,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize);
+
+ NDIS_RELEASE_SPIN_LOCK(Filter->Lock, OldIrql);
+}
+
+
+VOID
+TrFilterDprIndicateReceive(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate a packet to
+ all bindings. The packet will be filtered so that only the
+ appropriate bindings will receive the packet.
+
+ Called at DPC_LEVEL.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ MacReceiveContext - A MAC supplied context value that must be
+ returned by the protocol if it calls MacTransferData.
+
+ HeaderBuffer - A virtual address of the virtually contiguous
+ buffer containing the MAC header of the packet.
+
+ HeaderBufferSize - An unsigned integer indicating the size of
+ the header buffer, in bytes.
+
+ LookaheadBuffer - A virtual address of the virtually contiguous
+ buffer containing the first LookaheadBufferSize bytes of data
+ of the packet. The packet buffer is valid only within the current
+ call to the receive event handler.
+
+ LookaheadBufferSize - An unsigned integer indicating the size of
+ the lookahead buffer, in bytes.
+
+ PacketSize - An unsigned integer indicating the size of the received
+ packet, in bytes. This number has nothing to do with the lookahead
+ buffer, but indicates how large the arrived packet is so that a
+ subsequent MacTransferData request can be made to transfer the entire
+ packet as necessary.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // The destination address in the lookahead buffer.
+ //
+ PCHAR DestinationAddress = (PCHAR)HeaderBuffer + 2;
+
+ //
+ // The source address in the lookahead buffer.
+ //
+ PCHAR SourceAddress = (PCHAR)HeaderBuffer + 8;
+
+ //
+ // Will hold the type of address that we know we've got.
+ //
+ UINT AddressType;
+
+ //
+ // TRUE if the packet is source routing packet.
+ //
+ BOOLEAN IsSourceRouting;
+
+ //
+ // TRUE if the packet is a MAC frame packet.
+ //
+ BOOLEAN IsMacFrame;
+
+ //
+ // The functional address as a longword, if the packet
+ // is addressed to one.
+ //
+ TR_FUNCTIONAL_ADDRESS FunctionalAddress;
+
+ //
+ // Will hold the status of indicating the receive packet.
+ // ZZZ For now this isn't used.
+ //
+ NDIS_STATUS StatusOfReceive;
+
+ //
+ // Will hold the open being indicated.
+ //
+ PTR_BINDING_INFO LocalOpen, NextOpen;
+
+ //
+ // Will hold the filter classes of the binding being indicated.
+ //
+ UINT BindingFilters;
+
+ //
+ // Holds intersection of open filters and this packet's type
+ //
+ UINT IntersectionOfFilters;
+
+ //
+ // If the packet is a runt packet, then only indicate to PROMISCUOUS
+ //
+
+ if ((HeaderBufferSize >= 14) && (PacketSize != 0))
+ {
+ UINT ResultOfAddressCheck;
+
+ TR_IS_NOT_DIRECTED(DestinationAddress, &ResultOfAddressCheck);
+
+ //
+ // Handle the directed packet case first
+ //
+ if (!ResultOfAddressCheck)
+ {
+ UINT IsNotOurs;
+
+ //
+ // If it is a directed packet, then check if the combined packet
+ // filter is PROMISCUOUS, if it is check if it is directed towards
+ // us
+ //
+ IsNotOurs = FALSE; // Assume it is
+ if (Filter->CombinedPacketFilter & (NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_ALL_LOCAL |
+ NDIS_PACKET_TYPE_ALL_FUNCTIONAL))
+ {
+ TR_COMPARE_NETWORK_ADDRESSES_EQ(Filter->AdapterAddress,
+ DestinationAddress,
+ &IsNotOurs);
+ }
+
+ //
+ // Walk the directed list and indicate up the packets.
+ //
+ for (LocalOpen = Filter->DirectedList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextDirected;
+
+ //
+ // Ignore if not directed to us and if the binding is not promiscuous
+ //
+ if (((LocalOpen->PacketFilters & NDIS_PACKET_TYPE_PROMISCUOUS) == 0) &&
+ IsNotOurs)
+ {
+ continue;
+ }
+
+ LocalOpen->References++;
+
+// NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ //
+ // Indicate the packet to the binding.
+ //
+ ProtocolFilterIndicateReceive(&StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize,
+ NdisMedium802_5);
+
+// NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ --LocalOpen->References;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+ trRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+
+ return;
+ }
+
+ TR_IS_SOURCE_ROUTING(SourceAddress, &IsSourceRouting);
+ IsMacFrame = TR_IS_MAC_FRAME(HeaderBuffer);
+
+ //
+ // First check if it *at least* has the functional address bit.
+ //
+ TR_IS_NOT_DIRECTED(DestinationAddress, &ResultOfAddressCheck);
+ if (ResultOfAddressCheck)
+ {
+ //
+ // It is at least a functional address. Check to see if
+ // it is a broadcast address.
+ //
+ TR_IS_BROADCAST(DestinationAddress, &ResultOfAddressCheck);
+ if (ResultOfAddressCheck)
+ {
+ TR_CHECK_FOR_INVALID_BROADCAST_INDICATION(Filter);
+
+ AddressType = NDIS_PACKET_TYPE_BROADCAST;
+ }
+ else
+ {
+ TR_IS_GROUP(DestinationAddress, &ResultOfAddressCheck);
+ if (ResultOfAddressCheck)
+ {
+ AddressType = NDIS_PACKET_TYPE_GROUP;
+ }
+ else
+ {
+ AddressType = NDIS_PACKET_TYPE_FUNCTIONAL;
+ }
+
+ RetrieveUlong(&FunctionalAddress, (DestinationAddress + 2));
+ }
+ }
+ }
+ else
+ {
+ // Runt Packet
+ AddressType = NDIS_PACKET_TYPE_PROMISCUOUS;
+ IsSourceRouting = FALSE;
+ }
+
+
+ //
+ // At this point we know that the packet is either:
+ // - Runt packet - indicated by AddressType = NDIS_PACKET_TYPE_PROMISCUOUS (OR)
+ // - Broadcast packet - indicated by AddressType = NDIS_PACKET_TYPE_BROADCAST (OR)
+ // - Functional packet - indicated by AddressType = NDIS_PACKET_TYPE_FUNCTIONAL
+ //
+ // Walk the broadcast/functional list and indicate up the packets.
+ //
+ // The packet is indicated if it meets the following criteria:
+ //
+ // if ((Binding is promiscuous) OR
+ // ((Packet is broadcast) AND (Binding is Broadcast)) OR
+ // ((Packet is functional) AND
+ // ((Binding is all-functional) OR
+ // ((Binding is functional) AND (binding using functional address)))) OR
+ // ((Packet is a group packet) AND (Intersection of filters uses group addresses)) OR
+ // ((Packet is a macframe) AND (Binding wants mac frames)) OR
+ // ((Packet is a source routing packet) AND (Binding wants source routing packetss)))
+ //
+ for (LocalOpen = Filter->BFGList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ UINT LocalFilter = LocalOpen->PacketFilters;
+ UINT IntersectionOfFilters = LocalFilter & AddressType;
+ UINT IndexOfAddress;
+
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextBFG;
+
+ if ((LocalFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_BROADCAST) &&
+ (LocalFilter & NDIS_PACKET_TYPE_BROADCAST)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_FUNCTIONAL) &&
+ ((LocalFilter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL) ||
+ ((LocalFilter & NDIS_PACKET_TYPE_FUNCTIONAL) &&
+ (FunctionalAddress & LocalOpen->FunctionalAddress)))) ||
+
+ ((IntersectionOfFilters & NDIS_PACKET_TYPE_GROUP) &&
+ (LocalOpen->UsingGroupAddress) &&
+ (FunctionalAddress == Filter->GroupAddress)) ||
+
+ ((LocalFilter & NDIS_PACKET_TYPE_SOURCE_ROUTING) &&
+ IsSourceRouting) ||
+
+ ((LocalFilter & NDIS_PACKET_TYPE_MAC_FRAME) &&
+ IsMacFrame))
+ {
+ LocalOpen->References++;
+
+// NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ //
+ // Indicate the packet to the binding.
+ //
+ ProtocolFilterIndicateReceive(&StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize,
+ NdisMedium802_5);
+
+// NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ if ((--(LocalOpen->References)) == 0)
+ {
+ //
+ // This binding is shutting down.
+ //
+ trRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+ }
+}
+
+
+VOID
+TrFilterDprIndicateReceivePacket(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+)
+
+/*++
+
+Routine Description:
+
+ This routine is called by the Miniport to indicate packets to
+ all bindings. The packets will be filtered so that only the
+ appropriate bindings will receive the individual packets.
+ This is the code path for ndis 4.0 miniport drivers.
+
+Arguments:
+
+ Miniport - The Miniport block.
+
+ PacketArray - An array of Packets indicated by the miniport.
+
+ NumberOfPackets - Self-explanatory.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // The Filter of interest
+ //
+ PTR_FILTER Filter = Miniport->TrDB;
+
+ //
+ // Current packet being processed
+ //
+ PPNDIS_PACKET pPktArray = PacketArray;
+
+ //
+ // Pointer to the buffer in the ndispacket
+ //
+ PNDIS_BUFFER Buffer;
+
+ //
+ // Pointer to the 1st segment of the buffer, points to dest address
+ //
+ PUCHAR Address;
+
+ //
+ // Total packet length
+ //
+ UINT i, LASize, PacketSize, NumIndicates = 0;
+
+ //
+ // The destination address in the lookahead buffer.
+ //
+ PCHAR DestinationAddress;
+
+ //
+ // The source address in the lookahead buffer.
+ //
+ PCHAR SourceAddress;
+
+ //
+ // Will hold the type of address that we know we've got.
+ //
+ UINT AddressType;
+
+ //
+ // TRUE if the packet is source routing packet.
+ //
+ BOOLEAN IsSourceRouting;
+
+ //
+ // TRUE if the packet is a MAC frame packet.
+ //
+ BOOLEAN IsMacFrame;
+
+ //
+ // The functional address as a longword, if the packet
+ // is addressed to one.
+ //
+ TR_FUNCTIONAL_ADDRESS FunctionalAddress;
+
+ //
+ // Will hold the status of indicating the receive packet.
+ // ZZZ For now this isn't used.
+ //
+ NDIS_STATUS StatusOfReceive;
+
+ //
+ // Will hold the filter classes of the binding being indicated.
+ //
+ UINT BindingFilters;
+
+ //
+ // Decides whether we use the protocol's revpkt handler or fall
+ // back to old rcvindicate handler
+ //
+ BOOLEAN fFallBack, fPmode, FixRef;
+
+ //
+ // Will hold the open being indicated.
+ //
+ PTR_BINDING_INFO LocalOpen, NextOpen;
+ PNDIS_OPEN_BLOCK pOpenBlock; \
+
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID);
+
+ // Walk all the packets
+ for (i = 0; i < NumberOfPackets; i++, pPktArray++)
+ {
+ PNDIS_PACKET Packet = *pPktArray;
+ PNDIS_PACKET_OOB_DATA pOob;
+
+ ASSERT(Packet != NULL);
+
+ pOob = NDIS_OOB_DATA_FROM_PACKET(Packet);
+
+ NdisGetFirstBufferFromPacket(Packet,
+ &Buffer,
+ &Address,
+ &LASize,
+ &PacketSize);
+ ASSERT(Buffer != NULL);
+
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount = 0;
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->Miniport = Miniport;
+
+ //
+ // Set the status here that nobody is holding the packet. This will get
+ // overwritten by the real status from the protocol. Pay heed to what
+ // the miniport is saying.
+ //
+ if (pOob->Status != NDIS_STATUS_RESOURCES)
+ {
+ pOob->Status = NDIS_STATUS_SUCCESS;
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount --;
+ fFallBack = FALSE;
+ FixRef = TRUE;
+ }
+ else
+ {
+ fFallBack = TRUE;
+ FixRef = FALSE;
+ }
+
+ //
+ // Ensure that we force re-calculation.
+ //
+ Packet->Private.ValidCounts = FALSE;
+
+ //
+ // The destination address in the lookahead buffer.
+ //
+ DestinationAddress = (PCHAR)Address + 2;
+
+ //
+ // The source address in the lookahead buffer.
+ //
+ SourceAddress = (PCHAR)Address + 8;
+
+ // Determine if there is source routing info and compute hdr len
+#if DBG
+ {
+ UINT HdrSize;
+
+ HdrSize = 14;
+ if (Address[8] & 0x80)
+ {
+ HdrSize += (Address[14] & 0x1F);
+ }
+ ASSERT(HdrSize == pOob->HeaderSize);
+ }
+#endif
+ //
+ // A quick check for Runt packets. These are only indicated to Promiscuous bindings
+ //
+ if (PacketSize >= pOob->HeaderSize)
+ {
+ UINT ResultOfAddressCheck;
+
+ //
+ // If it is a directed packet, then check if the combined packet
+ // filter is PROMISCUOUS, if it is check if it is directed towards us
+ //
+ TR_IS_NOT_DIRECTED(DestinationAddress, &ResultOfAddressCheck);
+
+ //
+ // Handle the directed packet case first
+ //
+ if (!ResultOfAddressCheck)
+ {
+ UINT IsNotOurs;
+
+ //
+ // If it is a directed packet, then check if the combined packet
+ // filter is PROMISCUOUS, if it is check if it is directed towards
+ // us
+ //
+ IsNotOurs = FALSE; // Assume it is
+ if (Filter->CombinedPacketFilter & (NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_ALL_LOCAL |
+ NDIS_PACKET_TYPE_ALL_FUNCTIONAL))
+ {
+ TR_COMPARE_NETWORK_ADDRESSES_EQ(Filter->AdapterAddress,
+ DestinationAddress,
+ &IsNotOurs);
+ }
+
+ //
+ // We definitely have a directed packet so lets indicate it now.
+ //
+ // Walk the directed list and indicate up the packets.
+ //
+ for (LocalOpen = Filter->DirectedList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextDirected;
+
+ //
+ // Ignore if not directed to us and if the binding is not promiscuous
+ //
+ if (((LocalOpen->PacketFilters & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) == 0) &&
+ IsNotOurs)
+ {
+ continue;
+ }
+
+ pOpenBlock = (PNDIS_OPEN_BLOCK)(LocalOpen->NdisBindingContext);
+ LocalOpen->ReceivedAPacket = TRUE;
+ LocalOpen->References++;
+ NumIndicates ++;
+
+ fPmode = (LocalOpen->PacketFilters & (NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_ALL_LOCAL)) ?
+ TRUE : FALSE;
+ IndicateToProtocol(Miniport,
+ Filter,
+ pOpenBlock,
+ Packet,
+ Address,
+ PacketSize,
+ pOob->HeaderSize,
+ &fFallBack,
+ fPmode,
+ NdisMedium802_5);
+
+ LocalOpen->References--;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+ trRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+
+ if (FixRef)
+ {
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount++;
+ if (PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount != 0)
+ {
+ NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_PENDING);
+ }
+ }
+ continue; // Done with this packet
+ }
+
+ TR_IS_SOURCE_ROUTING(SourceAddress, &IsSourceRouting);
+ IsMacFrame = TR_IS_MAC_FRAME(Address);
+
+ //
+ // First check if it *at least* has the functional address bit.
+ //
+ TR_IS_NOT_DIRECTED(DestinationAddress, &ResultOfAddressCheck);
+ if (ResultOfAddressCheck)
+ {
+ //
+ // It is at least a functional address. Check to see if
+ // it is a broadcast address.
+ //
+ TR_IS_BROADCAST(DestinationAddress, &ResultOfAddressCheck);
+ if (ResultOfAddressCheck)
+ {
+ TR_CHECK_FOR_INVALID_BROADCAST_INDICATION(Filter);
+
+ AddressType = NDIS_PACKET_TYPE_BROADCAST;
+ }
+ else
+ {
+ TR_IS_GROUP(DestinationAddress, &ResultOfAddressCheck);
+ if (ResultOfAddressCheck)
+ {
+ AddressType = NDIS_PACKET_TYPE_GROUP;
+ }
+ else
+ {
+ AddressType = NDIS_PACKET_TYPE_FUNCTIONAL;
+ }
+
+ RetrieveUlong(&FunctionalAddress, (DestinationAddress + 2));
+ }
+ }
+ }
+ else
+ {
+ // Runt Packet
+ AddressType = NDIS_PACKET_TYPE_PROMISCUOUS;
+ IsSourceRouting = FALSE;
+ }
+
+ //
+ // At this point we know that the packet is either:
+ // - Runt packet - indicated by AddressType = NDIS_PACKET_TYPE_PROMISCUOUS (OR)
+ // - Broadcast packet - indicated by AddressType = NDIS_PACKET_TYPE_BROADCAST (OR)
+ // - Functional packet - indicated by AddressType = NDIS_PACKET_TYPE_FUNCTIONAL
+ //
+ // Walk the broadcast/functional list and indicate up the packets.
+ //
+ // The packet is indicated if it meets the following criteria:
+ //
+ // if ((Binding is promiscuous) OR
+ // ((Packet is broadcast) AND (Binding is Broadcast)) OR
+ // ((Packet is functional) AND
+ // ((Binding is all-functional) OR
+ // ((Binding is functional) AND (binding using functional address)))) OR
+ // ((Packet is a group packet) AND (Intersection of filters uses group addresses)) OR
+ // ((Packet is a macframe) AND (Binding wants mac frames)) OR
+ // ((Packet is a source routing packet) AND (Binding wants source routing packetss)))
+ //
+ for (LocalOpen = Filter->BFGList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ UINT LocalFilter = LocalOpen->PacketFilters;
+ UINT IntersectionOfFilters = LocalFilter & AddressType;
+ UINT IndexOfAddress;
+
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextBFG;
+
+ if ((LocalFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_BROADCAST) &&
+ (LocalFilter & NDIS_PACKET_TYPE_BROADCAST)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_FUNCTIONAL) &&
+ ((LocalFilter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL) ||
+ ((LocalFilter & NDIS_PACKET_TYPE_FUNCTIONAL) &&
+ (FunctionalAddress & LocalOpen->FunctionalAddress)))) ||
+
+ ((IntersectionOfFilters & NDIS_PACKET_TYPE_GROUP) &&
+ (LocalOpen->UsingGroupAddress)) ||
+
+ ((LocalFilter & NDIS_PACKET_TYPE_SOURCE_ROUTING) &&
+ IsSourceRouting) ||
+
+ ((LocalFilter & NDIS_PACKET_TYPE_MAC_FRAME) &&
+ IsMacFrame))
+ {
+ pOpenBlock = (PNDIS_OPEN_BLOCK)(LocalOpen->NdisBindingContext);
+ LocalOpen->ReceivedAPacket = TRUE;
+ LocalOpen->References++;
+ NumIndicates ++;
+
+ fPmode = (LocalFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) ?
+ TRUE : FALSE;
+ IndicateToProtocol(Miniport,
+ Filter,
+ pOpenBlock,
+ Packet,
+ Address,
+ PacketSize,
+ pOob->HeaderSize,
+ &fFallBack,
+ fPmode,
+ NdisMedium802_5);
+
+ LocalOpen->References--;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down.
+ //
+ trRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+ }
+
+ if (FixRef)
+ {
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount++;
+ if (PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount != 0)
+ {
+ NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_PENDING);
+ }
+ }
+ }
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID);
+
+ if (NumIndicates > 0)
+ {
+ TrFilterDprIndicateReceiveComplete(Filter);
+ }
+}
+
+
+
+VOID
+TrFilterDprIndicateReceiveCompleteFullMac(
+ IN PTR_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate that the receive
+ process is done and to indicate to all protocols which received
+ a packet that receive is complete.
+
+ Called at DPC_LEVEL.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Pointer to currently indicated binding.
+ //
+ PTR_BINDING_INFO LocalOpen, NextOpen;
+
+ //
+ // We need to aquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+ for (LocalOpen = Filter->OpenList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ LocalOpen->References++;
+ NextOpen = LocalOpen->NextOpen;
+
+ if (LocalOpen->ReceivedAPacket)
+ {
+ //
+ // Indicate the binding.
+ //
+
+ LocalOpen->ReceivedAPacket = FALSE;
+
+ NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ }
+
+ if ((--(LocalOpen->References)) == 0)
+ {
+ //
+ // This binding is shutting down.
+ //
+ trRemoveBindingFromLists(Filter, LocalOpen);
+
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+ Filter->CloseAction(LocalOpen->MacBindingHandle);
+
+ TR_FILTER_FREE_OPEN(Filter, LocalOpen);
+ }
+ }
+}
+
+
+
+VOID
+TrFilterIndicateReceiveComplete(
+ IN PTR_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate that the receive
+ process is done and to indicate to all protocols which received
+ a packet that receive is complete.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ KIRQL OldIrql;
+
+ NDIS_ACQUIRE_SPIN_LOCK(Filter->Lock, &OldIrql);
+ TrFilterDprIndicateReceiveCompleteFullMac(Filter);
+ NDIS_RELEASE_SPIN_LOCK(Filter->Lock, OldIrql);
+}
+
+
+VOID
+TrFilterDprIndicateReceiveComplete(
+ IN PTR_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate that the receive
+ process is done and to indicate to all protocols which received
+ a packet that receive is complete.
+
+ Called at DPC_LEVEL.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Pointer to currently indicated binding.
+ //
+ PTR_BINDING_INFO LocalOpen, NextOpen;
+
+ //
+ // We need to aquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+ for (LocalOpen = Filter->OpenList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ LocalOpen->References++;
+ NextOpen = LocalOpen->NextOpen;
+
+ if (LocalOpen->ReceivedAPacket)
+ {
+ //
+ // Indicate the binding.
+ //
+
+ LocalOpen->ReceivedAPacket = FALSE;
+
+// NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+// NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+ }
+
+ if ((--(LocalOpen->References)) == 0)
+ {
+ //
+ // This binding is shutting down.
+ //
+ trRemoveBindingFromLists(Filter, LocalOpen);
+
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+ Filter->CloseAction(LocalOpen->MacBindingHandle);
+
+ TR_FILTER_FREE_OPEN(Filter, LocalOpen);
+ }
+ }
+}
+
+
+BOOLEAN
+TrShouldAddressLoopBack(
+ IN PTR_FILTER Filter,
+ IN CHAR DestinationAddress[TR_LENGTH_OF_ADDRESS],
+ IN CHAR SourceAddress[TR_LENGTH_OF_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ Do a quick check to see whether the input address should
+ loopback.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+ NOTE: THIS ROUTINE DOES NOT CHECK THE SPECIAL CASE OF SOURCE
+ EQUALS DESTINATION.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ Address - A network address to check for loopback.
+
+
+Return Value:
+
+ Returns TRUE if the address is *likely* to need loopback. It
+ will return FALSE if there is *no* chance that the address would
+ require loopback.
+
+--*/
+{
+ BOOLEAN fLoopback, fSelfDirected;
+
+ TrShouldAddressLoopBackMacro(Filter,
+ DestinationAddress,
+ SourceAddress,
+ &fLoopback,
+ &fSelfDirected);
+
+ return(fLoopback);
+}
+
+
diff --git a/private/ntos/ndis/ndis40/timer.c b/private/ntos/ndis/ndis40/timer.c
new file mode 100644
index 000000000..821d62b2e
--- /dev/null
+++ b/private/ntos/ndis/ndis40/timer.c
@@ -0,0 +1,794 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ timer.c
+
+Abstract:
+
+ NDIS wrapper functions for full mac drivers isr/timer
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 05-Oct-93
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+ Jameel Hyder (JameelH) Re-organization 01-Jun-95
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+#include <stdarg.h>
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_TIMER
+
+VOID
+NdisInitializeTimer(
+ IN OUT PNDIS_TIMER NdisTimer,
+ IN PNDIS_TIMER_FUNCTION TimerFunction,
+ IN PVOID FunctionContext
+ )
+/*++
+
+Routine Description:
+
+ Sets up an NdisTimer object, initializing the DPC in the timer to
+ the function and context.
+
+Arguments:
+
+ NdisTimer - the timer object.
+ TimerFunction - Routine to start.
+ FunctionContext - Context of TimerFunction.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ INITIALIZE_TIMER(&(NdisTimer)->Timer);
+
+ //
+ // Initialize our dpc. If Dpc was previously initialized, this will
+ // reinitialize it.
+ //
+
+ INITIALIZE_DPC(&NdisTimer->Dpc,
+ (PKDEFERRED_ROUTINE)TimerFunction,
+ FunctionContext);
+
+ SET_PROCESSOR_DPC(&NdisTimer->Dpc,
+ ndisValidProcessors[ndisCurrentProcessor]);
+
+ SET_DPC_IMPORTANCE(&NdisTimer->Dpc);
+}
+
+
+VOID
+NdisSetTimer(
+ IN PNDIS_TIMER NdisTimer,
+ IN UINT MillisecondsToDelay
+ )
+/*++
+
+Routine Description:
+
+ Sets up TimerFunction to fire after MillisecondsToDelay.
+
+Arguments:
+
+ NdisTimer - the timer object.
+ MillisecondsToDelay - Amount of time before TimerFunction is started.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ LARGE_INTEGER FireUpTime;
+
+ FireUpTime.QuadPart = Int32x32To64((LONG)MillisecondsToDelay, -10000);
+
+ //
+ // Set the timer
+ //
+ SET_TIMER(&NdisTimer->Timer, FireUpTime, &NdisTimer->Dpc);
+}
+
+
+#undef NdisCancelTimer
+
+VOID
+NdisCancelTimer(
+ IN PNDIS_TIMER Timer,
+ OUT PBOOLEAN TimerCancelled
+ )
+{
+ *TimerCancelled = KeCancelTimer(&Timer->Timer);
+}
+
+BOOLEAN
+ndisIsr(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ Handles ALL Mac interrupts, calling the appropriate Mac ISR and DPC
+ depending on the context.
+
+Arguments:
+
+ Interrupt - Interrupt object for the Mac.
+
+ Context - Really a pointer to the interrupt.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Get adapter from context.
+ //
+
+ PNDIS_INTERRUPT NdisInterrupt = (PNDIS_INTERRUPT)(Context);
+
+ BOOLEAN (*InterruptIsr)(PVOID) = (BOOLEAN (*) (PVOID))(NdisInterrupt->MacIsr);
+
+ UNREFERENCED_PARAMETER(Interrupt);
+
+ //
+ // Call MacIsr
+ //
+
+ if((*InterruptIsr)(NdisInterrupt->InterruptContext) != FALSE)
+ {
+ //
+ // Queue MacDpc if needed
+ //
+
+ Increment((PLONG)&NdisInterrupt->DpcCount, &Interrupt->DpcCountLock);
+
+ if (!(QUEUE_DPC(&NdisInterrupt->InterruptDpc)))
+ {
+ //
+ // If the DPC was already queued, then we have an extra
+ // reference (we do it this way to ensure that the reference
+ // is added *before* the DPC is queued).
+ //
+
+ Decrement((PLONG)&NdisInterrupt->DpcCount, &Interrupt->DpcCountLock);
+
+ if (NdisInterrupt->Removing && (NdisInterrupt->DpcCount==0))
+ {
+ //
+ // We need to queue a DPC to set the event because we
+ // can't do it from the ISR. We know that the interrupt
+ // DPC won't fire because the refcount is 0, so we reuse it.
+ //
+
+ INITIALIZE_DPC(&NdisInterrupt->InterruptDpc,
+ ndisLastCountRemovedFunction,
+ (PVOID)(&NdisInterrupt->DpcsCompletedEvent));
+
+ //
+ // When ndisLastCountRemovedFunction runs it will set
+ // the event.
+ //
+
+ QUEUE_DPC (&NdisInterrupt->InterruptDpc);
+ }
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+VOID
+ndisDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+/*++
+
+Routine Description:
+
+ Handles ALL Mac interrupt DPCs, calling the appropriate Mac DPC
+ depending on the context.
+
+Arguments:
+
+ Interrupt - Interrupt object for the Mac.
+
+ Context - Really a pointer to the Interrupt.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Get adapter from context.
+ //
+
+ PNDIS_INTERRUPT NdisInterrupt = (PNDIS_INTERRUPT)(InterruptContext);
+
+ VOID (*MacDpc)(PVOID) = (VOID (*) (PVOID))(NdisInterrupt->MacDpc);
+
+ //
+ // Call MacDpc
+ //
+
+ (*((PNDIS_DEFERRED_PROCESSING)MacDpc))(SystemSpecific1,
+ NdisInterrupt->InterruptContext,
+ SystemSpecific2,
+ SystemSpecific3);
+
+ Decrement((PLONG)&NdisInterrupt->DpcCount, &Interrupt->DpcCountLock);
+
+ if (NdisInterrupt->Removing && (NdisInterrupt->DpcCount==0))
+ {
+ SET_EVENT(&NdisInterrupt->DpcsCompletedEvent);
+ }
+}
+
+
+VOID
+NdisInitializeInterrupt(
+ OUT PNDIS_STATUS Status,
+ IN OUT PNDIS_INTERRUPT NdisInterrupt,
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN PNDIS_INTERRUPT_SERVICE InterruptServiceRoutine,
+ IN PVOID InterruptContext,
+ IN PNDIS_DEFERRED_PROCESSING DeferredProcessingRoutine,
+ IN UINT InterruptVector,
+ IN UINT InterruptLevel,
+ IN BOOLEAN SharedInterrupt,
+ IN NDIS_INTERRUPT_MODE InterruptMode
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes the interrupt and sets up the Dpc.
+
+Arguments:
+
+ Status - Status of this request.
+ InterruptDpc - The Dpc object corresponding to DeferredProcessingRoutine.
+ Interrupt - Points to driver allocated memory that the wrapper fills in
+ with information about the interrupt handler.
+ InterruptServiceRoutine - The ISR that is called for this interrupt.
+ InterruptContext - Value passed to the ISR.
+ DeferredProcessingRoutine - The DPC queued by the ISR.
+ InterruptVector - Interrupt number used by the ISR.
+ InterruptMode - Type of interrupt the adapter generates.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ NTSTATUS NtStatus;
+ PNDIS_ADAPTER_BLOCK AdptrP = (PNDIS_ADAPTER_BLOCK)(NdisAdapterHandle);
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(NdisAdapterHandle);
+ ULONG Vector;
+ ULONG NumberOfElements;
+ KIRQL Irql;
+ KAFFINITY InterruptAffinity;
+ PCM_RESOURCE_LIST Resources;
+ BOOLEAN Conflict;
+ BOOLEAN IsAMiniport;
+ PNDIS_MINIPORT_INTERRUPT MiniportInterrupt = (PNDIS_MINIPORT_INTERRUPT)(NdisInterrupt);
+
+ IsAMiniport = (AdptrP->DeviceObject == NULL);
+
+ //
+ // First check if any bus access is allowed
+ //
+
+ if (((IsAMiniport ?
+ Miniport->BusType:
+ AdptrP->BusType) == (NDIS_INTERFACE_TYPE)-1) ||
+ ((IsAMiniport ?
+ Miniport->BusNumber:
+ AdptrP->BusNumber) == (ULONG)-1))
+ {
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ //
+ // First check for resource conflict by expanding current resource list,
+ // adding in the interrupt, and then re-submitting the resource list.
+ //
+
+ if ((IsAMiniport ?
+ Miniport->Resources:
+ AdptrP->Resources) != NULL)
+ {
+ NumberOfElements = (IsAMiniport ?
+ Miniport->Resources->List[0].PartialResourceList.Count + 1 :
+ AdptrP->Resources->List[0].PartialResourceList.Count + 1);
+ }
+ else
+ {
+ NumberOfElements = 1;
+ }
+
+ Resources = (PCM_RESOURCE_LIST)ALLOC_FROM_POOL(sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ NumberOfElements,
+ NDIS_TAG_RSRC_LIST);
+
+ if (Resources == NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ if ((IsAMiniport ?
+ Miniport->Resources :
+ AdptrP->Resources) != NULL)
+ {
+ CopyMemory(Resources,
+ (IsAMiniport ? Miniport->Resources :AdptrP->Resources),
+ sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * (NumberOfElements - 1));
+ }
+ else
+ {
+ //
+ // Setup initial resource info
+ //
+ ASSERT(IsAMiniport);
+ Resources->Count = 1;
+ Resources->List[0].InterfaceType = Miniport->AdapterType;
+ Resources->List[0].BusNumber = Miniport->BusNumber;
+ Resources->List[0].PartialResourceList.Version = 0;
+ Resources->List[0].PartialResourceList.Revision = 0;
+ Resources->List[0].PartialResourceList.Count = 0;
+ }
+
+ //
+ // Setup interrupt
+ //
+
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Type =
+ CmResourceTypeInterrupt;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].ShareDisposition =
+ SharedInterrupt ? CmResourceShareShared : CmResourceShareDeviceExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Flags =
+ (InterruptMode == NdisInterruptLatched) ?
+ CM_RESOURCE_INTERRUPT_LATCHED :
+ CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Interrupt.Level =
+ InterruptLevel;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Interrupt.Vector =
+ InterruptVector;
+ Resources->List[0].PartialResourceList.Count++;
+
+ //
+ // Make the call
+ //
+
+ NtStatus = IoReportResourceUsage(NULL,
+ (IsAMiniport ?
+ Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver :
+ AdptrP->MacHandle->NdisMacInfo->NdisWrapperDriver),
+ NULL,
+ 0,
+ IsAMiniport ?
+ Miniport->DeviceObject :
+ AdptrP->DeviceObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * Resources->List[0].PartialResourceList.Count,
+ TRUE,
+ &Conflict);
+
+ //
+ // Check for conflict.
+ //
+
+ if ((IsAMiniport ?
+ Miniport->Resources:
+ AdptrP->Resources) != NULL)
+ {
+ FREE_POOL((IsAMiniport ?
+ Miniport->Resources:
+ AdptrP->Resources));
+ }
+
+ if (IsAMiniport)
+ {
+ Miniport->Resources = Resources;
+ }
+ else
+ {
+ AdptrP->Resources = Resources;
+ }
+
+ if (Conflict || (NtStatus != STATUS_SUCCESS))
+ {
+ if (Conflict)
+ {
+ //
+ // Log an error
+ //
+
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ ULONG i;
+ ULONG StringSize;
+ PUCHAR Place;
+ PWCH baseFileName;
+ WCHAR Character;
+ ULONG Value;
+
+ baseFileName = ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.Buffer :
+ Miniport->MiniportName.Buffer);
+
+ //
+ // Parse out the path name, leaving only the device name.
+ //
+
+ for (i = 0;
+ i < ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.Length :
+ Miniport->MiniportName.Length) / sizeof(WCHAR);
+ i++)
+ {
+ //
+ // If s points to a directory separator, set baseFileName to
+ // the character after the separator.
+ //
+
+ if (((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.Buffer[i] :
+ Miniport->MiniportName.Buffer[i]) == OBJ_NAME_PATH_SEPARATOR)
+ {
+ baseFileName = ((AdptrP->DeviceObject != NULL) ?
+ &(AdptrP->AdapterName.Buffer[++i]):
+ &(Miniport->MiniportName.Buffer[++i]));
+ }
+ }
+
+ StringSize = ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.MaximumLength :
+ Miniport->MiniportName.MaximumLength) -
+ (((ULONG)baseFileName) -
+ ((AdptrP->DeviceObject != NULL) ?
+ ((ULONG)AdptrP->AdapterName.Buffer) :
+ ((ULONG)Miniport->MiniportName.Buffer)));
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (IsAMiniport ?
+ Miniport->DeviceObject :
+ AdptrP->DeviceObject),
+ (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize +
+ 6)); // wstrlen("99") * sizeof(WHCAR) + sizeof(UNICODE_NULL)
+
+ if (errorLogEntry != NULL)
+ {
+ errorLogEntry->ErrorCode = EVENT_NDIS_INTERRUPT_CONFLICT;
+
+ //
+ // store the time
+ //
+
+ errorLogEntry->MajorFunctionCode = 0;
+ errorLogEntry->RetryCount = 0;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = 0;
+ errorLogEntry->SequenceNumber = 0;
+ errorLogEntry->IoControlCode = 0;
+
+ //
+ // Set string information
+ //
+
+ if (StringSize != 0)
+ {
+ errorLogEntry->NumberOfStrings = 1;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+
+ CopyMemory(((PUCHAR)errorLogEntry) + sizeof(IO_ERROR_LOG_PACKET),
+ baseFileName,
+ StringSize);
+
+ Place = ((PUCHAR)errorLogEntry) + sizeof(IO_ERROR_LOG_PACKET) + StringSize;
+
+ }
+ else
+ {
+ Place = ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET);
+
+ errorLogEntry->NumberOfStrings = 0;
+
+ }
+
+ errorLogEntry->NumberOfStrings++;
+
+ //
+ // Put in interrupt level
+ //
+
+ Value = InterruptLevel;
+
+ //
+ // Convert value
+ //
+ // I couldn't think of a better way to do this (with some
+ // loop). If you find one, plz put it in.
+ //
+
+ if (Value > 9)
+ {
+ Character = L'0' + (WCHAR)(Value / 10);
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ Place += sizeof(WCHAR);
+
+ Value -= 10;
+ }
+
+ Character = L'0' + (WCHAR)Value;
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ Place += sizeof(WCHAR);
+
+ Character = UNICODE_NULL;
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ //
+ // write it out
+ //
+
+ IoWriteErrorLogEntry(errorLogEntry);
+ }
+
+ *Status = NDIS_STATUS_RESOURCE_CONFLICT;
+ return;
+ }
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+ //
+ // We must do this stuff first because if we connect the
+ // interrupt first then an interrupt could occur before
+ // the MacISR is recorded in the Ndis interrupt structure.
+ //
+
+ if (IsAMiniport)
+ {
+ INITIALIZE_SPIN_LOCK(&MiniportInterrupt->DpcCountLock);
+ Miniport->Interrupt = MiniportInterrupt;
+ MiniportInterrupt->DpcCount = 0;
+ MiniportInterrupt->MiniportIdField = NULL;
+ MiniportInterrupt->Miniport = Miniport;
+ MiniportInterrupt->MiniportIsr = Miniport->DriverHandle->MiniportCharacteristics.ISRHandler;
+ MiniportInterrupt->MiniportDpc = Miniport->HandleInterruptHandler;
+ MiniportInterrupt->SharedInterrupt = SharedInterrupt;
+ MiniportInterrupt->IsrRequested = (BOOLEAN)DeferredProcessingRoutine;
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+ }
+ else
+ {
+ NdisInterrupt->MacIsr = InterruptServiceRoutine;
+ NdisInterrupt->MacDpc = DeferredProcessingRoutine;
+ NdisInterrupt->InterruptContext = InterruptContext;
+ INITIALIZE_SPIN_LOCK(&NdisInterrupt->DpcCountLock);
+ NdisInterrupt->DpcCount = 0;
+ NdisInterrupt->Removing = FALSE;
+ }
+
+ //
+ // This is used to tell when all Dpcs are completed after the
+ // interrupt has been removed.
+ //
+
+ INITIALIZE_EVENT(IsAMiniport ?
+ &MiniportInterrupt->DpcsCompletedEvent :
+ &NdisInterrupt->DpcsCompletedEvent);
+
+ //
+ // Initialize our dpc.
+ //
+
+ if (IsAMiniport)
+ {
+ INITIALIZE_DPC(&MiniportInterrupt->InterruptDpc,
+ (Miniport->Flags & fMINIPORT_IS_CO) ?
+ ndisMCoDpc : ndisMDpc,
+ MiniportInterrupt);
+
+ SET_DPC_IMPORTANCE(&MiniportInterrupt->InterruptDpc);
+
+ SET_PROCESSOR_DPC(&MiniportInterrupt->InterruptDpc,
+ ndisValidProcessors[ndisCurrentProcessor]);
+ }
+ else
+ {
+ INITIALIZE_DPC(&NdisInterrupt->InterruptDpc,
+ (PKDEFERRED_ROUTINE) ndisDpc,
+ NdisInterrupt);
+
+ SET_DPC_IMPORTANCE(&NdisInterrupt->InterruptDpc);
+
+ SET_PROCESSOR_DPC(&NdisInterrupt->InterruptDpc,
+ ndisValidProcessors[ndisCurrentProcessor]);
+ }
+
+ //
+ // Get the system interrupt vector and IRQL.
+ //
+
+ Vector = HalGetInterruptVector((IsAMiniport ?
+ Miniport->BusType :
+ AdptrP->BusType), // InterfaceType
+ (IsAMiniport ?
+ Miniport->BusNumber :
+ AdptrP->BusNumber), // BusNumber
+ (ULONG)InterruptLevel, // BusInterruptLevel
+ (ULONG)InterruptVector, // BusInterruptVector
+ &Irql, // Irql
+ &InterruptAffinity);
+
+ if (IsAMiniport)
+ {
+ NtStatus = IoConnectInterrupt(
+ &MiniportInterrupt->InterruptObject,
+ (PKSERVICE_ROUTINE)ndisMIsr,
+ MiniportInterrupt,
+ NULL,
+ Vector,
+ Irql,
+ Irql,
+ (KINTERRUPT_MODE)InterruptMode,
+ SharedInterrupt,
+ InterruptAffinity,
+ FALSE);
+ }
+ else
+ {
+ NtStatus = IoConnectInterrupt(
+ &NdisInterrupt->InterruptObject,
+ (PKSERVICE_ROUTINE)ndisIsr,
+ NdisInterrupt,
+ NULL,
+ Vector,
+ Irql,
+ Irql,
+ (KINTERRUPT_MODE)InterruptMode,
+ SharedInterrupt,
+ InterruptAffinity,
+ FALSE);
+ }
+
+
+ if (!NT_SUCCESS(NtStatus))
+ {
+ *Status = NDIS_STATUS_FAILURE;
+ }
+}
+
+
+VOID
+NdisRemoveInterrupt(
+ IN PNDIS_INTERRUPT Interrupt
+ )
+/*++
+
+Routine Description:
+
+ Removes the interrupt, will not return until all interrupts and
+ interrupt dpcs are completed.
+
+Arguments:
+
+ Interrupt - Points to driver allocated memory that the wrapper filled
+ with information about the interrupt handler.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MINIPORT_INTERRUPT MiniportInterrupt = (PNDIS_MINIPORT_INTERRUPT)Interrupt;
+ BOOLEAN fIsMiniport;
+
+ //
+ // Determine if this is a miniport's interrupt.
+ //
+ fIsMiniport = (BOOLEAN)(MiniportInterrupt->MiniportIdField == NULL);
+
+ //
+ // Mark the interrupt as being removed.
+ //
+ if (fIsMiniport)
+ {
+ MINIPORT_SET_FLAG(
+ MiniportInterrupt->Miniport,
+ fMINIPORT_BEING_REMOVED);
+ }
+ else
+ {
+ Interrupt->Removing = TRUE;
+ }
+
+ //
+ // Now we disconnect the interrupt.
+ // NOTE: they are aligned in both structures
+ //
+ IoDisconnectInterrupt(Interrupt->InterruptObject);
+
+ //
+ // Right now we know that any Dpcs that may fire are counted.
+ // We don't have to guard this with a spin lock because the
+ // Dpc will set the event it completes first, or we may
+ // wait for a little while for it to complete.
+ //
+ if (fIsMiniport)
+ {
+ if (MiniportInterrupt->DpcCount > 0)
+ {
+ //
+ // Now we wait for all dpcs to complete.
+ //
+ WAIT_FOR_OBJECT(&MiniportInterrupt->DpcsCompletedEvent, NULL);
+
+ RESET_EVENT(&MiniportInterrupt->DpcsCompletedEvent);
+ }
+ }
+ else
+ {
+ if (Interrupt->DpcCount > 0)
+ {
+ //
+ // Now we wait for all dpcs to complete.
+ //
+ WAIT_FOR_OBJECT(&Interrupt->DpcsCompletedEvent, NULL);
+
+ RESET_EVENT(&Interrupt->DpcsCompletedEvent);
+ }
+ }
+}
+
+
+
+
diff --git a/private/ntos/ndis/ndis40/timerm.c b/private/ntos/ndis/ndis40/timerm.c
new file mode 100644
index 000000000..20ff1b7e6
--- /dev/null
+++ b/private/ntos/ndis/ndis40/timerm.c
@@ -0,0 +1,1080 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ timerm.c
+
+Abstract:
+
+ NDIS wrapper functions for miniport isr/timer
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 05-Oct-93
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ Jameel Hyder (JameelH) Re-organization 01-Jun-95
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_TIMERM
+
+//
+// Timers
+//
+VOID
+ndisMTimerDpc(
+ IN PKDPC Dpc,
+ IN PVOID Context,
+ IN PVOID SystemContext1,
+ IN PVOID SystemContext2
+ )
+/*++
+
+Routine Description:
+
+ This function services all mini-port timer interrupts. It then calls the
+ appropriate function that mini-port consumers have registered in the
+ call to NdisMInitializeTimer.
+
+Arguments:
+
+ Dpc - Not used.
+
+ Context - A pointer to the NDIS_MINIPORT_TIMER which is bound to this DPC.
+
+ SystemContext1,2 - not used.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MINIPORT_TIMER MiniportTimer = (PNDIS_MINIPORT_TIMER)(Context);
+ PNDIS_TIMER_FUNCTION TimerFunction;
+ PNDIS_MINIPORT_BLOCK Miniport = MiniportTimer->Miniport;
+ BOOLEAN LocalLock;
+
+ UNREFERENCED_PARAMETER(Dpc);
+ UNREFERENCED_PARAMETER(SystemContext1);
+ UNREFERENCED_PARAMETER(SystemContext2);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ do
+ {
+ //
+ // Attempt to acquire the local lock.
+ //
+ LOCK_MINIPORT(Miniport, LocalLock);
+ if (!LocalLock || MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IN_INITIALIZE))
+ {
+ //
+ // Unlock the miniport in the case of the in-initialize flag.
+ //
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Queue a work item for the timer.
+ //
+ NDISM_QUEUE_NEW_WORK_ITEM(Miniport,
+ NdisWorkItemTimer,
+ &MiniportTimer->Dpc,
+ NULL);
+
+ break;
+ }
+
+ //
+ // Call Miniport timer function
+ //
+ TimerFunction = MiniportTimer->MiniportTimerFunction;
+
+ (*TimerFunction)(NULL, MiniportTimer->MiniportTimerContext, NULL, NULL);
+
+#if _SEND_PRIORITY
+ //
+ // If we are not reseting and not halting then give priority to sends
+ // at this point.
+ //
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_REQUESTED) &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS) &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_HALTING))
+ {
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ ndisMProcessDeferredFullDuplexPrioritySends(Miniport);
+ }
+ else
+ {
+ ndisMProcessDeferredPrioritySends(Miniport);
+ }
+ }
+ else
+#endif
+ {
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ } while (FALSE);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+}
+
+
+VOID
+NdisMInitializeTimer(
+ IN OUT PNDIS_MINIPORT_TIMER MiniportTimer,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_TIMER_FUNCTION TimerFunction,
+ IN PVOID FunctionContext
+ )
+/*++
+
+Routine Description:
+
+ Sets up an Miniport Timer object, initializing the DPC in the timer to
+ the function and context.
+
+Arguments:
+
+ MiniportTimer - the timer object.
+ MiniportAdapterHandle - pointer to the mini-port block;
+ TimerFunction - Routine to start.
+ FunctionContext - Context of TimerFunction.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ INITIALIZE_TIMER(&(MiniportTimer->Timer));
+
+ MiniportTimer->Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ MiniportTimer->MiniportTimerFunction = TimerFunction;
+ MiniportTimer->MiniportTimerContext = FunctionContext;
+
+ //
+ // Initialize our dpc. If Dpc was previously initialized, this will
+ // reinitialize it.
+ //
+ INITIALIZE_DPC(&MiniportTimer->Dpc,
+ (MiniportTimer->Miniport->Flags & fMINIPORT_IS_CO) ?
+ (PKDEFERRED_ROUTINE)ndisMCoTimerDpc :
+ (PKDEFERRED_ROUTINE)ndisMTimerDpc,
+ (PVOID)MiniportTimer);
+
+ SET_PROCESSOR_DPC(&MiniportTimer->Dpc,
+ ndisValidProcessors[ndisCurrentProcessor]);
+}
+
+
+VOID
+NdisMCancelTimer(
+ IN PNDIS_MINIPORT_TIMER Timer,
+ OUT PBOOLEAN TimerCancelled
+ )
+/*++
+
+Routine Description:
+
+ Cancels a timer.
+
+Arguments:
+
+ Timer - The timer to cancel.
+
+ TimerCancelled - TRUE if the timer was canceled, else FALSE.
+
+Return Value:
+
+ None
+
+--*/
+{
+ *TimerCancelled = CANCEL_TIMER(&((((PNDIS_TIMER)(Timer))->Timer)));
+}
+
+
+NDIS_STATUS
+NdisMRegisterInterrupt(
+ OUT PNDIS_MINIPORT_INTERRUPT Interrupt,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN UINT InterruptVector,
+ IN UINT InterruptLevel,
+ IN BOOLEAN RequestIsr,
+ IN BOOLEAN SharedInterrupt,
+ IN NDIS_INTERRUPT_MODE InterruptMode
+ )
+{
+ NDIS_STATUS Status;
+
+ NdisInitializeInterrupt(&Status,
+ (PNDIS_INTERRUPT)Interrupt,
+ MiniportAdapterHandle,
+ NULL,
+ NULL,
+ (PNDIS_DEFERRED_PROCESSING)RequestIsr,
+ InterruptVector,
+ InterruptLevel,
+ SharedInterrupt,
+ InterruptMode);
+ return Status;
+}
+
+
+VOID
+NdisMDeregisterInterrupt(
+ IN PNDIS_MINIPORT_INTERRUPT Interrupt
+ )
+{
+ NdisRemoveInterrupt((PNDIS_INTERRUPT)Interrupt);
+}
+
+
+BOOLEAN
+NdisMSynchronizeWithInterrupt(
+ IN PNDIS_MINIPORT_INTERRUPT Interrupt,
+ IN PVOID SynchronizeFunction,
+ IN PVOID SynchronizeContext
+ )
+{
+ return (SYNC_WITH_ISR((Interrupt)->InterruptObject,
+ SynchronizeFunction,
+ SynchronizeContext));
+}
+
+
+
+VOID
+ndisMWakeUpDpc(
+ IN PKDPC Dpc,
+ IN PVOID Context,
+ IN PVOID SystemContext1,
+ IN PVOID SystemContext2
+ )
+/*++
+
+Routine Description:
+
+ This function services all mini-port. It checks to see if a mini-port is
+ ever stalled.
+
+Arguments:
+
+ Dpc - Not used.
+
+ Context - A pointer to the NDIS_TIMER which is bound to this DPC.
+
+ SystemContext1,2 - not used.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(Context);
+ BOOLEAN Hung = FALSE;
+ BOOLEAN LocalLock;
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+ PSINGLE_LIST_ENTRY Link;
+
+ UNREFERENCED_PARAMETER(Dpc);
+ UNREFERENCED_PARAMETER(SystemContext1);
+ UNREFERENCED_PARAMETER(SystemContext2);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ do
+ {
+ //
+ // If the miniport is halting then do nothing.
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_HALTING))
+ {
+ break;
+ }
+
+ //
+ // Does some other DPC have the miniport lock?
+ //
+ LOCK_MINIPORT(Miniport, LocalLock);
+ if (!LocalLock ||
+ MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS) ||
+ MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_REQUESTED))
+ {
+ //
+ // Release the local lock in case we are here due to
+ // a reset in progress.
+ //
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // A DPC or timer is already running, assume that
+ // means things are fine.
+ //
+ break;
+ }
+
+ //
+ // Call Miniport stall checker.
+ //
+ if (Miniport->DriverHandle->MiniportCharacteristics.CheckForHangHandler != NULL)
+ {
+ Hung = (Miniport->DriverHandle->MiniportCharacteristics.CheckForHangHandler)(
+ Miniport->MiniportAdapterContext);
+ }
+
+ //
+ // Check the internal wrapper states for the miniport and
+ // see if we think the miniport should be reset.
+ //
+ if (!Hung) do
+ {
+ //
+ // Should we check the request queue?
+ //
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IGNORE_REQUEST_QUEUE))
+ {
+ //
+ // Did a request pend to long?
+ //
+ if (Miniport->MiniportRequest != NULL)
+ {
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_REQUEST_TIMEOUT))
+ {
+ Hung = TRUE;
+ break;
+ }
+ else
+ {
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_REQUEST_TIMEOUT);
+ }
+ }
+ }
+
+ //
+ // Should we ignore the packet queue's?
+ //
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IGNORE_PACKET_QUEUE))
+ {
+ //
+ // Grab the send lock.
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+
+ //
+ // Does the miniport have possession of any packets?
+ //
+ if (Miniport->FirstPacket != NULL)
+ {
+ //
+ // Has the packet timed out?
+ //
+ if (MINIPORT_TEST_PACKET_FLAG(Miniport->FirstPacket, fPACKET_HAS_TIMED_OUT))
+ {
+ //
+ // Reset the miniport.
+ //
+ Hung = TRUE;
+ }
+ else
+ {
+ //
+ // Set the packet flag and wait to see if it is still
+ // there next time in.
+ //
+ MINIPORT_SET_PACKET_FLAG(Miniport->FirstPacket, fPACKET_HAS_TIMED_OUT);
+ }
+ }
+
+ //
+ // Release the send lock.
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+
+ //
+ // If we are hung then we don't need to check for token ring
+ // errors.
+ //
+ if (Hung)
+ {
+ break;
+ }
+ }
+
+ //
+ // Are we ignoring token ring errors?
+ //
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IGNORE_TOKEN_RING_ERRORS))
+ {
+ //
+ // Token Ring reset...
+ //
+ if (Miniport->TrResetRing == 1)
+ {
+ Hung = TRUE;
+ break;
+ }
+ else if (Miniport->TrResetRing > 1)
+ {
+ Miniport->TrResetRing--;
+ }
+ }
+ } while (FALSE);
+
+ //
+ // If the miniport is hung then queue a workitem to reset it.
+ //
+ if (Hung)
+ {
+ //
+ // Queue a reset requested workitem.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemResetRequested, Miniport, NULL);
+ }
+
+ //
+ // Process any changes that have occurred.
+ //
+ NDISM_PROCESS_DEFERRED(Miniport);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ } while (FALSE);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+}
+
+
+//
+// Interrupt stuff
+//
+
+
+BOOLEAN
+ndisMIsr(
+ IN PKINTERRUPT KInterrupt,
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ Handles ALL Miniport interrupts, calling the appropriate Miniport ISR and DPC
+ depending on the context.
+
+Arguments:
+
+ Interrupt - Interrupt object for the Mac.
+
+ Context - Really a pointer to the interrupt.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Get adapter from context.
+ //
+
+ PNDIS_MINIPORT_INTERRUPT Interrupt = (PNDIS_MINIPORT_INTERRUPT)Context;
+ PNDIS_MINIPORT_BLOCK Miniport = Interrupt->Miniport;
+
+ BOOLEAN InterruptRecognized;
+ BOOLEAN QueueDpc;
+
+ do
+ {
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS))
+ {
+ //
+ // Call to disable the interrupt
+ //
+ MINIPORT_DISABLE_INTERRUPT(Miniport);
+
+ InterruptRecognized = TRUE;
+
+ goto queue_dpc;
+
+ break;
+ }
+
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_HALTING))
+ {
+ //
+ // Call MiniportIsr
+ //
+
+ Interrupt->MiniportIsr(
+ &InterruptRecognized,
+ &QueueDpc,
+ Miniport->MiniportAdapterContext);
+
+ if (QueueDpc)
+ {
+queue_dpc:
+ Increment((PLONG)&Interrupt->DpcCount, &Interrupt->DpcCountLock);
+
+ if (QUEUE_DPC(&Interrupt->InterruptDpc))
+ {
+ break;
+ }
+
+ //
+ // The DPC was already queued, so we have an extra reference (we
+ // do it this way to ensure that the reference is added *before*
+ // the DPC is queued).
+ //
+
+ Decrement((PLONG)&Interrupt->DpcCount, &Interrupt->DpcCountLock);
+
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_HALTING) &&
+ (Interrupt->DpcCount == 0))
+ {
+ //
+ // We need to queue a DPC to set the event because we
+ // can't do it from the ISR. We know that the interrupt
+ // DPC won't fire because the refcount is 0, so we reuse it.
+ //
+
+ INITIALIZE_DPC(&Interrupt->InterruptDpc,
+ ndisLastCountRemovedFunction,
+ (PVOID)&Interrupt->DpcsCompletedEvent);
+
+ //
+ // When ndisLastCountRemovedFunction runs it will set
+ // the event.
+ //
+
+ QUEUE_DPC(&Interrupt->InterruptDpc);
+ }
+ }
+
+ break;
+ }
+
+ if (!Interrupt->SharedInterrupt &&
+ !Interrupt->IsrRequested &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IN_INITIALIZE))
+ {
+ //
+ // Call to disable the interrupt
+ //
+ ASSERT(Miniport->DisableInterruptHandler != NULL);
+
+ MINIPORT_DISABLE_INTERRUPT(Miniport);
+ InterruptRecognized = TRUE;
+
+ break;
+ }
+
+ //
+ // Call MiniportIsr, but don't queue a DPC.
+ //
+ Interrupt->MiniportIsr(
+ &InterruptRecognized,
+ &QueueDpc,
+ Miniport->MiniportAdapterContext);
+
+ } while (FALSE);
+
+ return(InterruptRecognized);
+}
+
+
+VOID
+ndisMDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+/*++
+
+Routine Description:
+
+ Handles ALL Miniport interrupt DPCs, calling the appropriate Miniport DPC
+ depending on the context.
+
+Arguments:
+
+ Interrupt - Interrupt object for the Mac.
+
+ Context - Really a pointer to the Interrupt.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Get adapter from context.
+ //
+
+ PNDIS_MINIPORT_INTERRUPT Interrupt = (PNDIS_MINIPORT_INTERRUPT)(InterruptContext);
+ PNDIS_MINIPORT_BLOCK Miniport = Interrupt->Miniport;
+ BOOLEAN LocalLock;
+
+ W_HANDLE_INTERRUPT_HANDLER MiniportDpc = Interrupt->MiniportDpc;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ do
+ {
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_HALTING))
+ {
+ Decrement((PLONG)&Interrupt->DpcCount, &Interrupt->DpcCountLock);
+
+ if (Interrupt->DpcCount==0)
+ {
+ SET_EVENT(&Interrupt->DpcsCompletedEvent);
+ }
+
+ break;
+ }
+
+ LOCK_MINIPORT(Miniport, LocalLock);
+ if (!LocalLock)
+ {
+ //
+ // A DPC is already running, queue this for later.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemDpc, &Miniport->Dpc, NULL);
+ Decrement((PLONG)&Interrupt->DpcCount, &Interrupt->DpcCountLock);
+
+ break;
+ }
+
+ //
+ // Call MiniportDpc
+ //
+ (*MiniportDpc)(Miniport->MiniportAdapterContext);
+
+ Decrement((PLONG)&Interrupt->DpcCount, &Interrupt->DpcCountLock);
+
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_HALTING))
+ {
+ //
+ // Enable interrupts
+ //
+
+ MINIPORT_SYNC_ENABLE_INTERRUPT(Miniport);
+
+#if _SEND_PRIORITY
+ //
+ // If we are not reseting and not halting then give priority to sends
+ // at this point.
+ //
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_REQUESTED) &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS) &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_HALTING))
+ {
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ ndisMProcessDeferredFullDuplexPrioritySends(Miniport);
+ }
+ else
+ {
+ ndisMProcessDeferredPrioritySends(Miniport);
+ }
+ }
+ else
+#endif
+ {
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+ }
+ else
+ {
+ if (Interrupt->DpcCount == 0)
+ {
+ SET_EVENT(&Interrupt->DpcsCompletedEvent);
+ }
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ } while (FALSE);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+}
+
+
+VOID
+ndisMDpcTimer(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+/*++
+
+Routine Description:
+
+ Handles a deferred interrupt dpc.
+
+Arguments:
+
+ Context - Really a pointer to the Miniport block.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Get adapter from context.
+ //
+
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(InterruptContext);
+ BOOLEAN LocalLock;
+
+ W_HANDLE_INTERRUPT_HANDLER MiniportDpc = Miniport->HandleInterruptHandler;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ do
+ {
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IN_INITIALIZE))
+ {
+ break;
+ }
+
+ LOCK_MINIPORT(Miniport, LocalLock);
+ if (!LocalLock)
+ {
+ //
+ // A DPC is already running, queue this for later.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemDpc, &Miniport->Dpc, NULL);
+ break;
+ }
+
+ //
+ // Disable the interrupts.
+ //
+ MINIPORT_SYNC_DISABLE_INTERRUPT(Miniport);
+
+ //
+ // Call MiniportDpc
+ //
+ if (MiniportDpc != NULL)
+ {
+ (*MiniportDpc)(Miniport->MiniportAdapterContext);
+ }
+
+ //
+ // Enable interrupts
+ //
+ MINIPORT_SYNC_ENABLE_INTERRUPT(Miniport);
+
+#if _SEND_PRIORITY
+ //
+ // If we are not reseting and not halting then give priority to sends
+ // at this point.
+ //
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_REQUESTED) &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS) &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_HALTING))
+ {
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ ndisMProcessDeferredFullDuplexPrioritySends(Miniport);
+ }
+ else
+ {
+ ndisMProcessDeferredPrioritySends(Miniport);
+ }
+ }
+ else
+#endif
+ {
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ } while (FALSE);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+}
+
+
+VOID
+ndisMDeferredTimerDpc(
+ IN PKDPC Dpc,
+ IN PVOID Context,
+ IN PVOID SystemContext1,
+ IN PVOID SystemContext2
+ )
+
+/*++
+
+Routine Description:
+
+ This is a DPC routine that is queue'd by some of the [full-duplex] routines
+ in order to get ndisMProcessDeferred[FullDuplex] to run outside of their
+ context.
+
+Arguments:
+
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = Context;
+ BOOLEAN LocalLock;
+
+ UNREFERENCED_PARAMETER(Dpc);
+ UNREFERENCED_PARAMETER(SystemContext1);
+ UNREFERENCED_PARAMETER(SystemContext2);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ LOCK_MINIPORT(Miniport, LocalLock);
+ if (!LocalLock)
+ {
+ //
+ // Queue this to run later.
+ //
+ NDISM_DEFER_PROCESS_DEFERRED(Miniport);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ return;
+ }
+
+#if _SEND_PRIORITY
+ //
+ // If we are not reseting and not halting then give priority to sends
+ // at this point.
+ //
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_REQUESTED) &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS) &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_HALTING))
+ {
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ ndisMProcessDeferredFullDuplexPrioritySends(Miniport);
+ }
+ else
+ {
+ ndisMProcessDeferredPrioritySends(Miniport);
+ }
+ }
+ else
+#endif
+ {
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+}
+
+
+VOID
+ndisMCoDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+/*++
+
+Routine Description:
+
+ Handles ALL Miniport interrupt DPCs, calling the appropriate Miniport DPC
+ depending on the context.
+
+Arguments:
+
+ Interrupt - Interrupt object for the Mac.
+
+ Context - Really a pointer to the Interrupt.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Get adapter from context.
+ //
+
+ PNDIS_MINIPORT_INTERRUPT Interrupt = (PNDIS_MINIPORT_INTERRUPT)(InterruptContext);
+ PNDIS_MINIPORT_BLOCK Miniport = Interrupt->Miniport;
+ BOOLEAN LocalLock;
+
+ W_HANDLE_INTERRUPT_HANDLER MiniportDpc = Interrupt->MiniportDpc;
+
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_HALTING))
+ {
+ Decrement((PLONG)&Interrupt->DpcCount, &Interrupt->DpcCountLock);
+
+ if (Interrupt->DpcCount==0)
+ {
+ SET_EVENT(&Interrupt->DpcsCompletedEvent);
+ }
+ }
+ else
+ {
+ //
+ // Call MiniportDpc
+ //
+ (*MiniportDpc)(Miniport->MiniportAdapterContext);
+
+ Decrement((PLONG)&Interrupt->DpcCount, &Interrupt->DpcCountLock);
+
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_HALTING))
+ {
+ //
+ // Enable interrupts
+ //
+
+ MINIPORT_SYNC_ENABLE_INTERRUPT(Miniport);
+ }
+ else
+ {
+ if (Interrupt->DpcCount == 0)
+ {
+ SET_EVENT(&Interrupt->DpcsCompletedEvent);
+ }
+ }
+
+ }
+}
+
+
+VOID
+ndisMCoDpcTimer(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+/*++
+
+Routine Description:
+
+ Handles a deferred interrupt dpc.
+
+Arguments:
+
+ Context - Really a pointer to the Miniport block.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Get adapter from context.
+ //
+
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(InterruptContext);
+ BOOLEAN LocalLock;
+
+ W_HANDLE_INTERRUPT_HANDLER MiniportDpc = Miniport->HandleInterruptHandler;
+
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IN_INITIALIZE))
+ {
+ //
+ // Disable the interrupts.
+ //
+ MINIPORT_SYNC_DISABLE_INTERRUPT(Miniport);
+
+ //
+ // Call MiniportDpc
+ //
+ if (MiniportDpc != NULL)
+ {
+ (*MiniportDpc)(Miniport->MiniportAdapterContext);
+ }
+
+ //
+ // Enable interrupts
+ //
+ MINIPORT_SYNC_ENABLE_INTERRUPT(Miniport);
+
+ }
+}
+
+VOID
+ndisMCoTimerDpc(
+ IN PKDPC Dpc,
+ IN PVOID Context,
+ IN PVOID SystemContext1,
+ IN PVOID SystemContext2
+ )
+/*++
+
+Routine Description:
+
+ This function services all mini-port timer interrupts. It then calls the
+ appropriate function that mini-port consumers have registered in the
+ call to NdisMInitializeTimer.
+
+Arguments:
+
+ Dpc - Not used.
+
+ Context - A pointer to the NDIS_MINIPORT_TIMER which is bound to this DPC.
+
+ SystemContext1,2 - not used.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MINIPORT_TIMER MiniportTimer = (PNDIS_MINIPORT_TIMER)(Context);
+ PNDIS_MINIPORT_BLOCK Miniport = MiniportTimer->Miniport;
+ BOOLEAN LocalLock;
+
+ UNREFERENCED_PARAMETER(Dpc);
+ UNREFERENCED_PARAMETER(SystemContext1);
+ UNREFERENCED_PARAMETER(SystemContext2);
+
+ //
+ // Call Miniport timer function
+ //
+ (*MiniportTimer->MiniportTimerFunction)(NULL, MiniportTimer->MiniportTimerContext, NULL, NULL);
+}
+
+
+
diff --git a/private/ntos/ndis/ndis40/up/makefile b/private/ntos/ndis/ndis40/up/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/ndis40/up/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/ndis40/up/ndis.prf b/private/ntos/ndis/ndis40/up/ndis.prf
new file mode 100644
index 000000000..7c294f08e
--- /dev/null
+++ b/private/ntos/ndis/ndis40/up/ndis.prf
@@ -0,0 +1,136 @@
+_allmul
+NdisQueryBuffer@12
+@InterlockedDecrement@4
+NdisQueryBufferOffset@12
+@InterlockedIncrement@4
+@InterlockedExchange@8
+NDIS_BUFFER_TO_SPAN_PAGES@4
+NdisAllocateBuffer@20
+NdisSetTimer@8
+NdisUnchainBufferAtFront@8
+@ndisMSyncSend@8
+@ndisMProcessDeferredPrioritySends@4
+ndisMIsr@8
+@ndisMQueueWorkItem@16
+ndisMDpc@16
+@ndisMIsLoopbackPacket@8
+@ndisMStartSends@4
+@ndisMProcessDeferred@4
+ndisMWakeUpDpc@16
+NdisMSendComplete@12
+@ndisMDeQueueWorkItem@16
+NdisMSendResourcesAvailable@4
+NdisMStartBufferPhysicalMapping@24
+NdisMCompleteBufferPhysicalMapping@12
+ndisMDeferredTimerDpc@16
+@ndisMIndicateLoopback@4
+ndisMCopyFromPacketToBuffer@20
+ndisMTimerDpc@16
+ndisMSend@8
+EthFilterDprIndicateReceiveComplete@4
+EthFilterDprIndicateReceivePacket@12
+NdisReturnPackets@8
+NdisAllocateMemory@20
+NdisWritePciSlotInformation@20
+NdisCopyBuffer@24
+NdisUnchainBufferAtBack@8
+NdisDereferenceRef@4
+ndisAllocationExecutionRoutine@16
+ndisDereferencePackage@4
+ndisReportResources@20
+ndisAddResource@28
+NdisFreeMemory@12
+ndisMFinishPendingOpen@4
+NdisAllocateBufferPool@12
+ndisMFinishQueuedPendingOpen@4
+NdisAllocateSharedMemory@20
+NdisSystemProcessorCount@0
+NdisInitializeTimer@12
+NdisMSetPeriodicTimer@8
+NdisInitializeRef@4
+NdisFreeBufferPool@4
+NdisAllocatePacket@12
+NdisAllocatePacketPool@16
+NdisCopyFromPacketToPacket@24
+ndisReferencePackage@4
+NdisReadPciSlotInformation@20
+NdisReferenceRef@4
+ndisMRequestQueryInformationPost@12
+DriverEntry@8
+ndisReadParameters@24
+ndisReadRegistry@0
+ArcCreateFilter@24
+ArcDeleteFilter@4
+ndisMQueryMaximumTotalSize@8
+TrCreateFilter@28
+NdisMRegisterMiniport@12
+ethUpdateBroadcastBindingList@12
+EthCreateFilter@28
+EthNoteFilterOpenAdapter@16
+EthDeleteFilter@4
+ethUpdateDirectedBindingList@12
+ethUpdateSpecificBindingLists@8
+NdisOpenAdapter@44
+ndisDereferenceProtocol@4
+NdisRegisterProtocol@16
+NdisMRegisterAdapterShutdownHandler@12
+ndisMSetInformation@8
+ndisMSyncQueryInformationComplete@8
+NdisIMRegisterLayeredMiniport@16
+ndisMQueryMaximumFrameSize@8
+ndisDereferenceMiniport@4
+ndisMDoRequests@4
+TrDeleteFilter@4
+ndisMQueueRequest@12
+NdisMInitializeTimer@16
+NdisMRegisterInterrupt@28
+ndisDereferenceDriver@4
+ndisQueueMiniportOnDriver@8
+NdisMAllocateSharedMemory@20
+ndisMChangeClass@20
+NdisMRegisterIoPortRange@16
+ndisMRequest@8
+FddiCreateFilter@36
+ndisMSetCurrentLookahead@8
+FddiDeleteFilter@4
+ndisMQueryNetworkAddress@8
+@ndisMQueueNewWorkItem@16
+ndisMSetPacketFilter@8
+EthFilterAdjust@20
+ndisMRequestSetInformationPost@12
+ndisMSyncSetInformationComplete@8
+ndisSaveParameters@24
+ndisQueueOpenOnProtocol@8
+NdisInitializeInterrupt@40
+ndisUpdateDriverInstance@16
+ndisMDummyTransferData@24
+ndisCheckRoute@24
+NdisOpenConfiguration@12
+NdisInitializeWrapper@16
+ndisProtocolAlreadyBound@8
+NdisOverrideBusNumber@12
+ndisSaveLinkage@24
+ndisMInitializeAdapter@16
+ndisMOpenAdapter@48
+ndisMDoMiniportOp@24
+NdisMAllocateMapRegisters@20
+ndisCreateIrpHandler@8
+ndisSuccessIrpHandler@8
+ndisInitializePackage@8
+ndisDispatchRequest@8
+NdisRegisterTdiCallBack@4
+ndisQueuedProtocolNotification@4
+ndisHandlePnPRequest@4
+ndisHandleLegacyTransport@4
+ndisHandleProtocolNotification@4
+NdisReadNetworkAddress@16
+NdisCloseConfiguration@4
+ndisInitializeAdapter@8
+NdisReadConfiguration@20
+ndisInitializeBindings@12
+ndisCheckProtocolBinding@16
+NdisMSetAttributes@16
+ndisMUndoBogusFilters@4
+ndisInitializeAllAdapterInstances@8
+ndisMQueryInformation@8
+ndisMDpcTimer@16
diff --git a/private/ntos/ndis/ndis40/up/sources b/private/ntos/ndis/ndis40/up/sources
new file mode 100644
index 000000000..85cdb3764
--- /dev/null
+++ b/private/ntos/ndis/ndis40/up/sources
@@ -0,0 +1,29 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+UP_DRIVER=yes
+
+TARGETPATH=obj
+
+!include ..\sources.inc
diff --git a/private/ntos/ndis/ndis40/wrapper.h b/private/ntos/ndis/ndis40/wrapper.h
new file mode 100644
index 000000000..e53e3e0ce
--- /dev/null
+++ b/private/ntos/ndis/ndis40/wrapper.h
@@ -0,0 +1,681 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ wrapper.h
+
+Abstract:
+
+ NDIS wrapper definitions
+
+Author:
+
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ Jun-95 Jameel Hyder Split up from a monolithic file
+--*/
+
+#ifndef _WRAPPPER_
+#define _WRAPPPER_
+
+#include <ntos.h>
+#include <ndismain.h>
+#include <ndisprot.h>
+#include <ndismac.h>
+#include <ndismini.h>
+#include <ndisco.h>
+#include <zwapi.h>
+#include <ndisdbg.h>
+#include <ndistags.h>
+
+extern UCHAR ndisValidProcessors[];
+extern ULONG ndisMaximumProcessor;
+extern ULONG ndisCurrentProcessor;
+extern UCHAR ndisInternalEaName[4];
+extern UCHAR ndisInternalEaValue[8];
+extern TDI_REGISTER_CALLBACK ndisTdiRegisterCallback;
+extern BOOLEAN ndisSkipProcessorAffinity;
+extern BOOLEAN ndisMediaTypeCl[NdisMediumMax];
+
+#define BYTE_SWAP(_word) ((USHORT) (((_word) >> 8) | ((_word) << 8)))
+
+#define LOW_WORD(_dword) ((USHORT) ((_dword) & 0x0000FFFF))
+
+#define HIGH_WORD(_dword) ((USHORT) (((_dword) >> 16) & 0x0000FFFF))
+
+#define BYTE_SWAP_ULONG(_ulong) ((ULONG)((ULONG)(BYTE_SWAP(LOW_WORD(_ulong)) << 16) + \
+ BYTE_SWAP(HIGH_WORD(_ulong))))
+
+//
+// A set of macros to manipulate bitmasks.
+//
+
+//VOID
+//CLEAR_BIT_IN_MASK(
+// IN UINT Offset,
+// IN OUT PMASK MaskToClear
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Clear a bit in the bitmask pointed to by the parameter.
+//
+//Arguments:
+//
+// Offset - The offset (from 0) of the bit to altered.
+//
+// MaskToClear - Pointer to the mask to be adjusted.
+//
+//Return Value:
+//
+// None.
+//
+//--*/
+//
+#define CLEAR_BIT_IN_MASK(Offset, MaskToClear) *(MaskToClear) &= (~(1 << Offset))
+
+//VOID
+//SET_BIT_IN_MASK(
+// IN UINT Offset,
+// IN OUT PMASK MaskToSet
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Set a bit in the bitmask pointed to by the parameter.
+//
+//Arguments:
+//
+// Offset - The offset (from 0) of the bit to altered.
+//
+// MaskToSet - Pointer to the mask to be adjusted.
+//
+//Return Value:
+//
+// None.
+//
+//--*/
+#define SET_BIT_IN_MASK(Offset, MaskToSet) *(MaskToSet) |= (1 << Offset)
+
+//BOOLEAN
+//IS_BIT_SET_IN_MASK(
+// IN UINT Offset,
+// IN MASK MaskToTest
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Tests if a particular bit in the bitmask pointed to by the parameter is
+// set.
+//
+//Arguments:
+//
+// Offset - The offset (from 0) of the bit to test.
+//
+// MaskToTest - The mask to be tested.
+//
+//Return Value:
+//
+// Returns TRUE if the bit is set.
+//
+//--*/
+#define IS_BIT_SET_IN_MASK(Offset, MaskToTest) ((MaskToTest & (1 << Offset)) ? TRUE : FALSE)
+
+//BOOLEAN
+//IS_MASK_CLEAR(
+// IN MASK MaskToTest
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Tests whether there are *any* bits enabled in the mask.
+//
+//Arguments:
+//
+// MaskToTest - The bit mask to test for all clear.
+//
+//Return Value:
+//
+// Will return TRUE if no bits are set in the mask.
+//
+//--*/
+#define IS_MASK_CLEAR(MaskToTest) ((MaskToTest) ? FALSE : TRUE)
+
+//VOID
+//CLEAR_MASK(
+// IN OUT PMASK MaskToClear
+// );
+//
+///*++
+//
+//Routine Description:
+//
+// Clears a mask.
+//
+//Arguments:
+//
+// MaskToClear - The bit mask to adjust.
+//
+//Return Value:
+//
+// None.
+//
+//--*/
+#define CLEAR_MASK(MaskToClear) *(MaskToClear) = 0
+
+//
+// This constant is used for places where NdisAllocateMemory
+// needs to be called and the HighestAcceptableAddress does
+// not matter.
+//
+#define RetrieveUlong(Destination, Source) \
+{ \
+ PUCHAR _S = (Source); \
+ *(Destination) = ((ULONG)(*_S) << 24) | \
+ ((ULONG)(*(_S+1)) << 16) | \
+ ((ULONG)(*(_S+2)) << 8) | \
+ ((ULONG)(*(_S+3))); \
+}
+
+
+//
+// This is the number of extra OIDs that ARCnet with Ethernet encapsulation
+// supports.
+//
+#define ARC_NUMBER_OF_EXTRA_OIDS 2
+
+//
+// ZZZ NonPortable definitions.
+//
+#define AllocPhys(s, l) NdisAllocateMemory((PVOID *)(s), (l), 0, HighestAcceptableMax)
+#define FreePhys(s, l) NdisFreeMemory((PVOID)(s), (l), 0)
+
+//
+// Internal wrapper data structures.
+//
+
+//
+// NDIS_WRAPPER_CONTEXT
+//
+// This data structure contains internal data items for use by the wrapper.
+//
+typedef struct _NDIS_WRAPPER_CONTEXT
+{
+ //
+ // Mac/miniport defined shutdown context.
+ //
+
+ PVOID ShutdownContext;
+
+ //
+ // Mac/miniport registered shutdown handler.
+ //
+
+ ADAPTER_SHUTDOWN_HANDLER ShutdownHandler;
+
+ //
+ // Kernel bugcheck record for bugcheck handling.
+ //
+
+ KBUGCHECK_CALLBACK_RECORD BugcheckCallbackRecord;
+
+ //
+ // Miniport assigned resources for PCI, PCMCIA, EISA, etc.
+ //
+
+ PCM_RESOURCE_LIST AssignedSlotResources;
+
+ //
+ // HAL common buffer cache.
+ //
+
+ PVOID SharedMemoryPage[2];
+ ULONG SharedMemoryLeft[2];
+ NDIS_PHYSICAL_ADDRESS SharedMemoryAddress[2];
+
+} NDIS_WRAPPER_CONTEXT, *PNDIS_WRAPPER_CONTEXT;
+
+//
+// Arcnet specific stuff
+//
+#define WRAPPER_ARC_BUFFERS 8
+#define WRAPPER_ARC_HEADER_SIZE 4
+
+//
+// Define constants used internally to identify regular opens from
+// query global statistics ones.
+//
+
+#define NDIS_OPEN_INTERNAL 1
+#define NDIS_OPEN_QUERY_STATISTICS 2
+
+//
+// This is the structure pointed to by the FsContext of an
+// open used for query statistics.
+//
+typedef struct _NDIS_USER_OPEN_CONTEXT
+{
+ PDEVICE_OBJECT DeviceObject;
+ union
+ {
+ PNDIS_MINIPORT_BLOCK MiniportBlock;
+ PNDIS_ADAPTER_BLOCK AdapterBlock;
+ };
+ ULONG OidCount;
+ PNDIS_OID OidArray;
+ ULONG FullOidCount;
+ PNDIS_OID FullOidArray;
+} NDIS_USER_OPEN_CONTEXT, *PNDIS_USER_OPEN_CONTEXT;
+
+//
+// An active query single statistic request.
+//
+typedef struct _NDIS_QUERY_GLOBAL_REQUEST
+{
+ PIRP Irp;
+ NDIS_REQUEST Request;
+} NDIS_QUERY_GLOBAL_REQUEST, *PNDIS_QUERY_GLOBAL_REQUEST;
+
+
+//
+// An active query all statistics request.
+//
+typedef struct _NDIS_QUERY_ALL_REQUEST
+{
+ PIRP Irp;
+ NDIS_REQUEST Request;
+ NDIS_STATUS NdisStatus;
+ KEVENT Event;
+} NDIS_QUERY_ALL_REQUEST, *PNDIS_QUERY_ALL_REQUEST;
+
+//
+// An temporary request used during an open.
+//
+typedef struct _NDIS_QUERY_OPEN_REQUEST
+{
+ PIRP Irp;
+ NDIS_REQUEST Request;
+ NDIS_STATUS NdisStatus;
+ KEVENT Event;
+} NDIS_QUERY_OPEN_REQUEST, *PNDIS_QUERY_OPEN_REQUEST;
+
+//
+// An temporary request used during init
+//
+typedef struct _NDIS_QS_REQUEST
+{
+ NDIS_REQUEST Request;
+ NDIS_STATUS NdisStatus;
+ KEVENT Event;
+} NDIS_QS_REQUEST, *PNDIS_QS_REQUEST;
+
+//
+// Used to queue configuration parameters
+//
+typedef struct _NDIS_CONFIGURATION_PARAMETER_QUEUE
+{
+ struct _NDIS_CONFIGURATION_PARAMETER_QUEUE* Next;
+ NDIS_CONFIGURATION_PARAMETER Parameter;
+} NDIS_CONFIGURATION_PARAMETER_QUEUE, *PNDIS_CONFIGURATION_PARAMETER_QUEUE;
+
+//
+// Configuration Handle
+//
+typedef struct _NDIS_CONFIGURATION_HANDLE
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable;
+ PNDIS_CONFIGURATION_PARAMETER_QUEUE ParameterList;
+} NDIS_CONFIGURATION_HANDLE, *PNDIS_CONFIGURATION_HANDLE;
+
+typedef struct _NDIS_REQUEST_RESERVED
+{
+ PNDIS_REQUEST Next;
+ struct _NDIS_M_OPEN_BLOCK * Open;
+} NDIS_REQUEST_RESERVED, *PNDIS_REQUEST_RESERVED;
+
+#define PNDIS_RESERVED_FROM_PNDIS_REQUEST(_request) ((PNDIS_REQUEST_RESERVED)((_request)->MacReserved))
+
+//
+// This is used to keep track of pci/eisa/mca cards in the system so that
+// if they move, then the bus#/slot# can be fixed up appropriately.
+//
+typedef struct _BUS_SLOT_DB
+{
+ struct _BUS_SLOT_DB *Next;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ ULONG SlotNumber;
+ ULONG BusId;
+} BUS_SLOT_DB, *PBUS_SLOT_DB;
+
+extern PBUS_SLOT_DB ndisGlobalDb;
+extern KSPIN_LOCK ndisGlobalDbLock;
+
+//
+// This is used during addadapter/miniportinitialize so that when the
+// driver calls any NdisImmediatexxx routines we can access its driverobj.
+//
+typedef struct _NDIS_WRAPPER_CONFIGURATION_HANDLE
+{
+ RTL_QUERY_REGISTRY_TABLE ParametersQueryTable[5];
+ PDRIVER_OBJECT DriverObject;
+ PUNICODE_STRING DriverBaseName;
+ BUS_SLOT_DB Db;
+} NDIS_WRAPPER_CONFIGURATION_HANDLE, *PNDIS_WRAPPER_CONFIGURATION_HANDLE;
+
+//
+// Describes an open NDIS file
+//
+
+//
+// Context for Bind Adapter.
+//
+typedef struct _NDIS_BIND_CONTEXT
+{
+ struct _NDIS_BIND_CONTEXT * Next;
+ PNDIS_PROTOCOL_BLOCK Protocol;
+ NDIS_STRING ProtocolSection;
+ PNDIS_STRING DeviceName;
+ WORK_QUEUE_ITEM WorkItem;
+ NDIS_STATUS BindStatus;
+ KEVENT Event;
+ KEVENT ThreadDoneEvent;
+} NDIS_BIND_CONTEXT, *PNDIS_BIND_CONTEXT;
+
+typedef struct _NDIS_FILE_DESCRIPTOR
+{
+ PVOID Data;
+ KSPIN_LOCK Lock;
+ BOOLEAN Mapped;
+} NDIS_FILE_DESCRIPTOR, *PNDIS_FILE_DESCRIPTOR;
+
+//
+// The following structure is used to queue openadapter/closeadapter calls to
+// worker threads so that they can complete at LOW_LEVEL.
+//
+typedef struct _QUEUED_OPEN_CLOSE
+{
+ PNDIS_OPEN_BLOCK OpenP;
+ NDIS_STATUS Status;
+ NDIS_STATUS OpenErrorStatus;
+ WORK_QUEUE_ITEM WorkItem;
+ BOOLEAN FreeIt;
+} QUEUED_OPEN_CLOSE, *PQUEUED_OPEN_CLOSE;
+
+
+typedef struct _QueuedProtocolNotification
+{
+ WORK_QUEUE_ITEM WorkItem;
+ PNDIS_M_DRIVER_BLOCK MiniBlock;
+ UNICODE_STRING UpCaseDeviceInstance;
+ WCHAR Buffer[1];
+} QUEUED_PROTOCOL_NOTIFICATION, *PQUEUED_PROTOCOL_NOTIFICATION;
+
+#if defined(_ALPHA_)
+
+typedef struct _NDIS_LOOKAHEAD_ELEMENT
+{
+ ULONG Length;
+ struct _NDIS_LOOKAHEAD_ELEMENT *Next;
+
+} NDIS_LOOKAHEAD_ELEMENT, *PNDIS_LOOKAHEAD_ELEMENT;
+
+#endif
+
+
+typedef struct _PKG_REF
+{
+ KSPIN_LOCK ReferenceLock;
+ ULONG ReferenceCount;
+ PVOID ImageHandle;
+ KEVENT PagedInEvent;
+} PKG_REF, *PPKG_REF;
+
+//
+// Structures for dealing with making the module specific routines pagable
+//
+
+extern PKG_REF ProtocolPkg;
+extern PKG_REF MacPkg;
+extern PKG_REF CoPkg;
+extern PKG_REF InitPkg;
+extern PKG_REF PnPPkg;
+extern PKG_REF MiniportPkg;
+extern PKG_REF ArcPkg;
+extern PKG_REF EthPkg;
+extern PKG_REF TrPkg;
+extern PKG_REF FddiPkg;
+
+extern PNDIS_PROTOCOL_BLOCK ndisProtocolList;
+
+//
+// Work item structure
+//
+typedef struct _NDIS_MINIPORT_WORK_ITEM
+{
+ //
+ // Link for the list of work items of this type.
+ //
+ SINGLE_LIST_ENTRY Link;
+
+ //
+ // type of work item and context information.
+ //
+ NDIS_WORK_ITEM_TYPE WorkItemType;
+ PVOID WorkItemContext1;
+ PVOID WorkItemContext2;
+} NDIS_MINIPORT_WORK_ITEM, *PNDIS_MINIPORT_WORK_ITEM;
+
+//
+// This does most of the work of dequeueing a workitem.
+//
+#define NDISM_DEQUEUE_WORK_ITEM_MACRO(_M, _WT, _pWC1, _pWC2) \
+{ \
+}
+
+#define NDISM_QUEUE_WORK_ITEM_MACRO(_M, _WT, _WC1, _WC2, _pS) \
+{ \
+ PSINGLE_LIST_ENTRY _Link; \
+ PNDIS_MINIPORT_WORK_ITEM _WorkItem; \
+ \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("==>ndisMQueueWorkItem()\n")); \
+ \
+ _Link = PopEntryList(&(_M)->SingleWorkItems[(_WT)]); \
+ if (NULL != _Link) \
+ { \
+ _WorkItem = CONTAINING_RECORD(_Link, NDIS_MINIPORT_WORK_ITEM, Link); \
+ _WorkItem->WorkItemType = (_WT); \
+ _WorkItem->WorkItemContext1 = (_WC1); \
+ _WorkItem->WorkItemContext2 = (_WC2); \
+ PushEntryList(&(_M)->WorkQueue[(_WT)], _Link); \
+ *(_pS) = NDIS_STATUS_SUCCESS; \
+ } \
+ else \
+ { \
+ *(_pS) = NDIS_STATUS_NOT_ACCEPTED; \
+ } \
+ \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("<==ndisMQueueWorkItem()\n")); \
+}
+
+#define NDISM_QUEUE_WORK_ITEM_FULL_DUPLEX_MACRO(_M, _WT, _WC1, _WC2, _pS) \
+{ \
+ PSINGLE_LIST_ENTRY _Link; \
+ PNDIS_MINIPORT_WORK_ITEM _WorkItem; \
+ \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("==>ndisMQueueWorkItemFullDuplex()\n")); \
+ \
+ ACQUIRE_SPIN_LOCK_DPC(&(_M)->WorkLock); \
+ \
+ _Link = PopEntryList(&(_M)->SingleWorkItems[(_WT)]); \
+ if (NULL != _Link) \
+ { \
+ _WorkItem = CONTAINING_RECORD(_Link, NDIS_MINIPORT_WORK_ITEM, Link); \
+ _WorkItem->WorkItemType = (_WT); \
+ _WorkItem->WorkItemContext1 = (_WC1); \
+ _WorkItem->WorkItemContext2 = (_WC2); \
+ PushEntryList(&(_M)->WorkQueue[(_WT)], \
+ _Link); \
+ \
+ *(_pS) = NDIS_STATUS_SUCCESS; \
+ } \
+ else \
+ { \
+ *(_pS) = NDIS_STATUS_NOT_ACCEPTED; \
+ } \
+ \
+ RELEASE_SPIN_LOCK_DPC(&(_M)->WorkLock); \
+ \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("<==ndisMQueueWorkItemFullDuplex()\n")); \
+}
+
+#define NDISM_QUEUE_NEW_WORK_ITEM_MACRO(_M, _WT, _WC1, _WC2, _pS) \
+{ \
+ PSINGLE_LIST_ENTRY _Link; \
+ PNDIS_MINIPORT_WORK_ITEM _WorkItem; \
+ \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("==>ndisMQueueNewWorkItem()\n")); \
+ \
+ ASSERT(((_WT) < NUMBER_OF_WORK_ITEM_TYPES) && ((_WT) > NUMBER_OF_SINGLE_WORK_ITEMS)); \
+ \
+ do \
+ { \
+ _Link = PopEntryList(&(_M)->WorkItemFreeQueue); \
+ if (NULL == _Link) \
+ { \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("Allocate a workitem from the pool.\n")); \
+ \
+ _WorkItem = ALLOC_FROM_POOL(sizeof(NDIS_MINIPORT_WORK_ITEM), NDIS_TAG_WORK_ITEM);\
+ if (NULL == _WorkItem) \
+ { \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_FATAL, \
+ ("Failed to allocate a workitem from the pool!\n")); \
+ DBGBREAK(DBG_COMP_WORK_ITEM, DBG_LEVEL_FATAL); \
+ \
+ *(_pS) = NDIS_STATUS_FAILURE; \
+ \
+ break; \
+ } \
+ (_M)->NumberOfAllocatedWorkItems++; \
+ } \
+ else \
+ { \
+ _WorkItem = CONTAINING_RECORD(_Link, NDIS_MINIPORT_WORK_ITEM, Link); \
+ } \
+ \
+ ZeroMemory(_WorkItem, sizeof(NDIS_MINIPORT_WORK_ITEM)); \
+ _WorkItem->WorkItemType = (_WT); \
+ _WorkItem->WorkItemContext1 = (_WC1); \
+ _WorkItem->WorkItemContext2 = (_WC2); \
+ \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("WorkItem 0x%x\n", _WorkItem)); \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("WorkItem Type 0x%x\n", (_WT))); \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("WorkItem Context2 0x%x\n", (_WC1))); \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("WorkItem Context1 0x%x\n", (_WC2))); \
+ \
+ PushEntryList(&(_M)->WorkQueue[(_WT)], &_WorkItem->Link); \
+ \
+ *(_pS) = NDIS_STATUS_SUCCESS; \
+ \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("<==ndisMQueueNewWorkItem()\n")); \
+ } while (FALSE); \
+}
+
+#define NDISM_QUEUE_NEW_WORK_ITEM_FULL_DUPLEX_MACRO(_M, _WT, _WC1, _WC2, _pS) \
+{ \
+ PSINGLE_LIST_ENTRY _Link; \
+ PNDIS_MINIPORT_WORK_ITEM _WorkItem; \
+ \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("==>ndisMQueueNewWorkItemFullDuplex()\n")); \
+ \
+ ASSERT(((_WT) < NUMBER_OF_WORK_ITEM_TYPES) && ((_WT) > NUMBER_OF_SINGLE_WORK_ITEMS)); \
+ \
+ ACQUIRE_SPIN_LOCK_DPC(&(_M)->WorkLock); \
+ \
+ do \
+ { \
+ _Link = PopEntryList(&(_M)->WorkItemFreeQueue); \
+ if (NULL == _Link) \
+ { \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("Allocate a workitem from the pool.\n")); \
+ \
+ _WorkItem = ALLOC_FROM_POOL(sizeof(NDIS_MINIPORT_WORK_ITEM), NDIS_TAG_WORK_ITEM);\
+ if (NULL == _WorkItem) \
+ { \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_FATAL, \
+ ("Failed to allocate a workitem from the pool!\n")); \
+ DBGBREAK(DBG_COMP_WORK_ITEM, DBG_LEVEL_FATAL); \
+ \
+ *(_pS) = NDIS_STATUS_FAILURE; \
+ \
+ break; \
+ } \
+ \
+ (_M)->NumberOfAllocatedWorkItems++; \
+ } \
+ else \
+ { \
+ _WorkItem = CONTAINING_RECORD(_Link, NDIS_MINIPORT_WORK_ITEM, Link); \
+ } \
+ \
+ ZeroMemory(_WorkItem, sizeof(NDIS_MINIPORT_WORK_ITEM)); \
+ _WorkItem->WorkItemType = (_WT); \
+ _WorkItem->WorkItemContext1 = (_WC1); \
+ _WorkItem->WorkItemContext2 = (_WC2); \
+ \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("WorkItem 0x%x\n", _WorkItem)); \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("WorkItem Type 0x%x\n", (_WT))); \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("WorkItem Context2 0x%x\n", (_WC1))); \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("WorkItem Context1 0x%x\n", (_WC2))); \
+ \
+ PushEntryList(&(_M)->WorkQueue[(_WT)], &_WorkItem->Link); \
+ \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("<==ndisMQueueNewWorkItemFullDuplex()\n")); \
+ } while (FALSE); \
+ \
+ RELEASE_SPIN_LOCK_DPC(&(_M)->WorkLock); \
+}
+
+#define NDISM_QUEUE_WORK_ITEM(_M, _WT, _WC1, _WC2) (_M)->QueueWorkItemHandler(_M, _WT, _WC1, _WC2)
+
+#define NDISM_QUEUE_NEW_WORK_ITEM(_M, _WT, _WC1, _WC2) (_M)->QueueNewWorkItemHandler(_M, _WT, _WC1, _WC2)
+
+#define NDISM_DEQUEUE_WORK_ITEM(_M, _WT, _pWC1, _pWC2) (_M)->DeQueueWorkItemHandler(_M, _WT, _pWC1, _pWC2)
+
+#define NDISM_PROCESS_DEFERRED(_M) (_M)->ProcessDeferredHandler((_M))
+
+#endif // _WRAPPPER_
+
diff --git a/private/ntos/ndis/ndis40/wrapper.txt b/private/ntos/ndis/ndis40/wrapper.txt
new file mode 100644
index 000000000..2e52189f0
--- /dev/null
+++ b/private/ntos/ndis/ndis40/wrapper.txt
@@ -0,0 +1,120 @@
+Debug Wrapper
+
+Johnson Apacible (johnsona)
+3-11-91
+
+
+
+The debug version of the wrapper allows developers to
+1. turn on/off error checking
+2. control level of tracing. There are currently 2 levels of tracing:
+Level 2 tracing turns on tracing on all wrapper functions; while level
+1 tracing turns on tracing only on the more interesting functions.
+Level 1 and 2 functions are enumerated below:
+
+
+Level 1 Tracing enables tracing on the following functions:
+
+ NdisInitializePacketPool
+ NdisTerminatePacketPool
+
+ NdisRegisterProtocol
+ NdisDeregisterProtocol
+
+ NdisOpenAdapter
+ NdisCloseAdapter
+ FinishOpen
+
+ KillOpenAndNotifyProtocol
+ KillOpen
+
+ NdisInitializeWrapper
+ NdisTerminateWrapper
+
+ NdisRegisterMac
+ NdisDeregisterMac
+ DeQueueAdapterOnMac
+ QueueAdapterOnMac
+
+ QueueOpenOnProtocol
+ DeQueueOpenOnProtocol
+ NdisRegisterAdapter
+ NdisDeregisterAdapter
+ KillAdapter
+ QueueAdapterOnAdapter
+ DeQueueAdapterOnAdapter
+ NdisSetPacketFilter
+ NdisAddMulticastAddress
+ NdisDeleteMulticastAddress
+ NdisSend
+ NdisTransferData
+ NdisQueryInformation
+ NdisSetInformation
+ NdisReset
+ NdisTest
+ NdisCompleteRequest
+ NdisCompleteSend
+ NdisCompleteTransferData
+ NdisIndicateStatus
+ NdisIndicateStatusComplete
+
+
+Level 2 tracing enables tracing the functions listedbelow in addition
+to all Level 1 functions:
+
+ NdisQueryBuffer
+ NdisAllocatePacket
+ NdisDeallocatePacket
+ NdisReinitializePacket
+ NdisChainBufferAtFront
+ NdisChainBufferAtBack
+ NdisUnchainBufferAtFront
+ NdisUnchainBufferAtBack
+ NdisQueryPacket
+ NdisGetNextBuffer
+ ReferenceRef
+ DereferenceRef
+ InitializeRef
+ CloseRef
+ ReferenceProtocol
+ DereferenceProtocol
+ NdisSuccessIrplHandler
+ ReferencMac
+ ReferenceAdapter
+ DereferenceAdapter
+
+ NdisIndicateReceive
+ NdisIndicateReceiveComplete
+
+
+
+Turning on/off error checking
+
+Error checking may be turned on/off during run-time by changing the
+value of the flag NdisChkErrorFlag. A zero value turns off error
+checking and a non-zero value turn it on. This flag is turned on
+by default.
+
+
+Controlling level of messages
+
+Message level may by specified by changing the NdisMsgLevel variable.
+
+ Value of NdisMsgLevel Meaning
+ 0x000 Turn off all messages
+ 0x001 Turn on tracing on Level 1 functions
+ 0x002 Turn on all tracing
+
+NdisMsgLevel is set to 0 by default
+
+
+
+The debug code will be included only if the NDISDBG flag is turned on (== 1).
+
+If you do change this flag, be sure to delete (1) all nbf .obj files,
+(2) ntos\dd\init\obj\i386\ddinit.obj, (3) ntos\init\obj\i386\init.obj, and
+(4) recompile everything under ndis, since this flag will change a lot
+of goings on inside ndis.h
+
+
+ \ No newline at end of file
diff --git a/private/ntos/ndis/ndistapi/intrface.h b/private/ntos/ndis/ndistapi/intrface.h
new file mode 100644
index 000000000..6babe2fb5
--- /dev/null
+++ b/private/ntos/ndis/ndistapi/intrface.h
@@ -0,0 +1,138 @@
+/*++ BUILD Version: 0000 // Increment this if a change has global effects
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ intrface.h
+
+Abstract:
+
+ Definition for user-mode/kernel-mode tapi/connection wrapper interface.
+
+Author:
+
+ Dan Knudson (DanKn) 20-Feb-1994
+
+Revision History:
+
+--*/
+
+
+
+#define NDISTAPIERR_UNINITIALIZED 0x00001001
+#define NDISTAPIERR_BADDEVICEID 0x00001002
+#define NDISTAPIERR_DEVICEOFFLINE 0x00001003
+
+
+
+//
+// Define the various device type values. Note that values used by Microsoft
+// Corporation are in the range 0-32767, and 32768-65535 are reserved for use
+// by customers.
+//
+
+#define FILE_DEVICE_NDISTAPI 0x00008fff
+
+
+
+//
+// Macro definition for defining IOCTL and FSCTL function control codes. Note
+// that function codes 0-2047 are reserved for Microsoft Corporation, and
+// 2048-4095 are reserved for customers.
+//
+
+#define NDISTAPI_IOCTL_INDEX 0x8f0
+
+
+
+//
+// The NDISTAPI device driver IOCTLs
+//
+
+#define IOCTL_NDISTAPI_CONNECT CTL_CODE(FILE_DEVICE_NDISTAPI, \
+ NDISTAPI_IOCTL_INDEX, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_NDISTAPI_DISCONNECT CTL_CODE(FILE_DEVICE_NDISTAPI, \
+ NDISTAPI_IOCTL_INDEX + 1, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_NDISTAPI_QUERY_INFO CTL_CODE(FILE_DEVICE_NDISTAPI, \
+ NDISTAPI_IOCTL_INDEX + 2, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_NDISTAPI_SET_INFO CTL_CODE(FILE_DEVICE_NDISTAPI, \
+ NDISTAPI_IOCTL_INDEX + 3, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_NDISTAPI_GET_LINE_EVENTS CTL_CODE(FILE_DEVICE_NDISTAPI, \
+ NDISTAPI_IOCTL_INDEX + 4, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+
+//
+// Type definitions
+//
+
+typedef struct _NDISTAPI_REQUEST
+{
+ //
+ // Return value
+ //
+
+ OUT ULONG ulReturnValue;
+
+ //
+ // Operation idenfifier
+ //
+
+ IN ULONG Oid;
+
+ //
+ // Target line device ID
+ //
+
+ IN ULONG ulDeviceID;
+
+ //
+ // Total size of request data in buffer
+ //
+
+ IN ULONG ulDataSize;
+
+ //
+ // Buffer for request data
+ //
+
+ IN OUT UCHAR Data[1];
+
+} NDISTAPI_REQUEST, *PNDISTAPI_REQUEST;
+
+
+typedef struct _NDISTAPI_EVENT_DATA
+{
+ //
+ // Total size of the event data buffer
+ //
+
+ IN ULONG ulTotalSize;
+
+ //
+ // Size of the returned event data
+ //
+
+ OUT ULONG ulUsedSize;
+
+ //
+ // Event data buffer
+ //
+
+ OUT UCHAR Data[1];
+
+} NDISTAPI_EVENT_DATA, *PNDISTAPI_EVENT_DATA;
diff --git a/private/ntos/ndis/ndistapi/makefile b/private/ntos/ndis/ndistapi/makefile
new file mode 100644
index 000000000..58189757d
--- /dev/null
+++ b/private/ntos/ndis/ndistapi/makefile
@@ -0,0 +1,7 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the driver components of the Windows NT DDK
+#
+
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/ndistapi/ndistapi.c b/private/ntos/ndis/ndistapi/ndistapi.c
new file mode 100644
index 000000000..ea37cd6b3
--- /dev/null
+++ b/private/ntos/ndis/ndistapi/ndistapi.c
@@ -0,0 +1,2873 @@
+/*++ BUILD Version: 0000 // Increment this if a change has global effects
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ ndistapi.c
+
+Abstract:
+
+ This module contains the NdisTapi.sys implementation
+
+Author:
+
+ Dan Knudson (DanKn) 20-Feb-1994
+
+Notes:
+
+ (Future/outstanding issues)
+
+ - stuff marked with "PnP" needs to be rev'd for plug 'n play support
+
+Revision History:
+
+--*/
+
+
+
+#include "ntos.h"
+#include "ndis.h"
+#include "stdarg.h"
+#include "stdio.h"
+#include "ntddndis.h"
+#include "ndistapi.h"
+#include "private.h"
+#include "intrface.h"
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+VOID
+NdisTapiCancel(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NdisTapiCleanup(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NdisTapiDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+NdisTapiUnload(
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+
+#if DBG
+VOID
+DbgPrt(
+ IN ULONG DbgLevel,
+ IN PUCHAR DbgMessage,
+ IN ...
+ );
+#endif
+
+VOID
+DoProviderInitComplete(
+ PPROVIDER_REQUEST ProviderRequest
+ );
+
+ULONG
+GetLineEvents(
+ PVOID EventBuffer,
+ ULONG BufferSize
+ );
+
+VOID
+GetRegistryParameters(
+ IN PUNICODE_STRING RegistryPath
+);
+
+BOOLEAN
+SyncInitAllProviders(
+ void
+ );
+
+NDIS_STATUS
+SendProviderInitRequest(
+ PPROVIDER_INFO Provider
+ );
+
+NDIS_STATUS
+SendProviderShutdown(
+ PPROVIDER_INFO Provider
+ );
+
+
+//
+// Use the alloc_text pragma to specify the driver initialization routines
+// (they can be paged out).
+//
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,DriverEntry)
+#pragma alloc_text(INIT,GetRegistryParameters)
+#endif
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ Installable driver initialization entry point.
+ This entry point is called directly by the I/O system.
+
+Arguments:
+
+ DriverObject - pointer to the driver object
+
+ RegistryPath - pointer to a unicode string representing the path
+ to driver-specific key in the registry
+
+Return Value:
+
+ STATUS_SUCCESS if successful,
+ STATUS_UNSUCCESSFUL otherwise
+
+--*/
+
+{
+
+ PDEVICE_OBJECT deviceObject = NULL;
+ NTSTATUS ntStatus;
+ WCHAR deviceNameBuffer[] = L"\\Device\\NdisTapi";
+ UNICODE_STRING deviceNameUnicodeString;
+ UNICODE_STRING registryPath;
+
+
+ DBGOUT ((2, "DriverEntry: enter"));
+
+
+ //
+ // Create a NON-EXCLUSIVE device, i.e. multiple threads at a time
+ // can send i/o requests.
+ //
+
+ RtlInitUnicodeString (&deviceNameUnicodeString, deviceNameBuffer);
+
+ ntStatus = IoCreateDevice(
+ DriverObject,
+ sizeof (DEVICE_EXTENSION),
+ &deviceNameUnicodeString,
+ FILE_DEVICE_NDISTAPI,
+ 0,
+ FALSE,
+ &deviceObject
+ );
+
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ //
+ // Init the global & sero the extension
+ //
+
+ DeviceExtension =
+ (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
+
+ RtlZeroMemory(
+ DeviceExtension,
+ sizeof (DEVICE_EXTENSION)
+ );
+
+
+ //
+ // Create a NULL-terminated registry path & retrieve the registry
+ // params (EventDataQueueLength)
+ //
+
+ registryPath.Buffer = ExAllocatePoolWithTag(
+ PagedPool,
+ RegistryPath->Length + sizeof(UNICODE_NULL),
+ 'TAPI'
+ );
+
+ if (!registryPath.Buffer)
+ {
+ DBGOUT((1, "DriverEntry: ExAllocPool for szRegistryPath failed"));
+
+ ntStatus = STATUS_UNSUCCESSFUL;
+
+ goto DriverEntry_err;
+ }
+ else
+ {
+ registryPath.Length = RegistryPath->Length;
+ registryPath.MaximumLength =
+ registryPath.Length + sizeof(UNICODE_NULL);
+
+ RtlZeroMemory(
+ registryPath.Buffer,
+ registryPath.MaximumLength
+ );
+
+ RtlMoveMemory(
+ registryPath.Buffer,
+ RegistryPath->Buffer,
+ RegistryPath->Length
+ );
+ }
+
+ GetRegistryParameters (&registryPath);
+
+ ExFreePool (registryPath.Buffer);
+
+
+ //
+ // Init event data buf, state vars, spin lock, device queue, & event
+ //
+
+ DeviceExtension->EventData =
+ DeviceExtension->DataIn =
+ DeviceExtension->DataOut = ExAllocatePoolWithTag(
+ NonPagedPool,
+ DeviceExtension->EventDataQueueLength,
+ 'TAPI'
+ );
+
+ if (!DeviceExtension->DataOut)
+ {
+ DBGOUT((1, "DriverEntry: ExAllocPool for event data buf failed"));
+
+ ntStatus = STATUS_UNSUCCESSFUL;
+
+ goto DriverEntry_err;
+ }
+
+ DeviceExtension->DeviceObject = deviceObject;
+ DeviceExtension->Status = NDISTAPI_STATUS_DISCONNECTED;
+ DeviceExtension->NdisTapiNumDevices = 0;
+ DeviceExtension->htCall = 0x80000000;
+
+ KeInitializeSpinLock (&DeviceExtension->SpinLock);
+ KeInitializeSpinLock (&DeviceExtension->EventSpinLock);
+
+ KeInitializeDeviceQueue (&DeviceExtension->DeviceQueue);
+
+ KeInitializeEvent(
+ &DeviceExtension->SyncEvent,
+ SynchronizationEvent,
+ FALSE
+ );
+
+
+ //
+ // Create dispatch points for device control, create, close.
+ //
+
+ DriverObject->MajorFunction[IRP_MJ_CREATE] =
+ DriverObject->MajorFunction[IRP_MJ_CLOSE] =
+ DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = NdisTapiDispatch;
+ DriverObject->MajorFunction[IRP_MJ_CLEANUP] = NdisTapiCleanup;
+ DriverObject->DriverUnload = NdisTapiUnload;
+ }
+
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+
+DriverEntry_err:
+
+ //
+ // Something went wrong, so clean up
+ //
+
+ DBGOUT((0, "init failed"));
+
+ if (deviceObject)
+ {
+ if (DeviceExtension->EventData)
+ {
+ ExFreePool (DeviceExtension->EventData);
+ }
+
+ IoDeleteDevice (deviceObject);
+ }
+ }
+
+
+ DBGOUT ((2, "DriverEntry: exit"));
+
+ return ntStatus;
+}
+
+
+
+VOID
+NdisTapiCancel(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+{
+ KIRQL oldIrql;
+// KIRQL cancelIrql;
+
+
+ DBGOUT((2,"NdisTapiCancel: enter"));
+
+
+ //
+ // Release the cancel spinlock
+ //
+
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+
+ //
+ // Acquire the EventSpinLock & check to see if we're canceling a
+ // pending get-events Irp
+ //
+
+ KeAcquireSpinLock (&DeviceExtension->EventSpinLock, &oldIrql);
+
+ if (Irp == DeviceExtension->EventsRequestIrp)
+ {
+ DeviceExtension->EventsRequestIrp = NULL;
+
+ KeReleaseSpinLock (&DeviceExtension->EventSpinLock, oldIrql);
+
+ goto NdisTapiCancel_done;
+ }
+
+ KeReleaseSpinLock (&DeviceExtension->EventSpinLock, oldIrql);
+
+
+ //
+ // Acquire the SpinLock & try to remove request from our special
+ // user-mode requests dev queue
+ //
+
+ KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
+
+ if (TRUE != KeRemoveEntryDeviceQueue(
+ &DeviceExtension->DeviceQueue,
+ &Irp->Tail.Overlay.DeviceQueueEntry
+ ))
+ {
+ //
+ // If we couldn't find the Irp in the device queue then it's
+ // "unknown", i.e. perhaps it was completed before we got here,
+ // so set it to NULL
+ //
+
+ Irp = NULL;
+
+ DBGOUT((1,"NdisTapiCancel: Irp 0x%x not in device queue?!?\n", Irp));
+ }
+
+ KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
+
+
+NdisTapiCancel_done:
+
+ if (Irp)
+ {
+ //
+ // Complete the request with STATUS_CANCELLED.
+ //
+
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest (Irp, IO_NO_INCREMENT);
+
+ DBGOUT((2,"NdisTapiCancel: completing irp=x%x", Irp));
+ }
+ else
+ {
+ DBGOUT((2,"NdisTapiCancel: irp=x%x not found, not completing!", Irp));
+ }
+
+ DBGOUT((2,"NdisTapiCancel: exit"));
+
+ return;
+}
+
+
+
+NTSTATUS
+NdisTapiCleanup(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the dispatch routine for cleanup requests.
+ All requests queued are completed with STATUS_CANCELLED.
+
+Arguments:
+
+ DeviceObject - Pointer to device object.
+
+ Irp - Pointer to the request packet.
+
+Return Value:
+
+ Status is returned.
+
+--*/
+
+{
+ PIRP irp;
+ KIRQL oldIrql;
+ KIRQL cancelIrql;
+ BOOLEAN completeRequest;
+ PNDISTAPI_REQUEST ndisTapiRequest;
+ PKDEVICE_QUEUE_ENTRY packet;
+
+
+ DBGOUT((2,"NdisTapiCleanup: enter"));
+
+
+ //
+ // If this cleanup originated from the NCPA then don't bother
+ // completing stuff (we don't want to possibly hose tapisrv & by
+ // canceling it's requests)
+ //
+
+ if (DeviceExtension->NCPAFileObject &&
+ (Irp->Tail.Overlay.OriginalFileObject ==
+ DeviceExtension->NCPAFileObject))
+ {
+ goto NdisTapiCleanup_CompleteRequest;
+ }
+
+
+ //
+ // Sync access to EventsRequestIrp by acquiring EventSpinLock
+ //
+
+ KeAcquireSpinLock (&DeviceExtension->EventSpinLock, &oldIrql);
+
+
+ //
+ // Check to see if there's a get-events request pending that needs
+ // completing
+ //
+
+ completeRequest = FALSE;
+
+ if (DeviceExtension->EventsRequestIrp)
+ {
+ //
+ // Acquire the cancel spinlock, remove the request from the
+ // cancellable state, and free the cancel spinlock.
+ //
+
+ IoAcquireCancelSpinLock (&cancelIrql);
+ irp = DeviceExtension->EventsRequestIrp;
+ IoSetCancelRoutine (irp, NULL);
+ DeviceExtension->EventsRequestIrp = NULL;
+ IoReleaseCancelSpinLock (cancelIrql);
+
+ irp->IoStatus.Status = STATUS_CANCELLED;
+ irp->IoStatus.Information = 0;
+
+ completeRequest = TRUE;
+ }
+
+ KeReleaseSpinLock (&DeviceExtension->EventSpinLock, oldIrql);
+
+ if (completeRequest)
+ {
+ IoCompleteRequest (irp, IO_NO_INCREMENT);
+
+ DBGOUT((2,"NdisTapiCleanup: completing GET_EVENTS request x%x", irp));
+ }
+
+
+ //
+ // Sync access to our request device queue by acquiring SpinLock
+ //
+
+ KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
+
+
+ //
+ // Cancel all outstanding QUERY/SET_INFO requests
+ //
+
+ if (DeviceExtension->DeviceQueue.Busy == TRUE)
+ {
+ IoAcquireCancelSpinLock (&cancelIrql);
+
+ while ((packet = KeRemoveDeviceQueue (&DeviceExtension->DeviceQueue))
+ != NULL)
+ {
+ irp = CONTAINING_RECORD(
+ packet,
+ IRP,
+ Tail.Overlay.DeviceQueueEntry
+ );
+
+ //
+ // Remove the IRP from the cancelable state
+ //
+
+ IoSetCancelRoutine (irp, NULL);
+ IoReleaseCancelSpinLock (cancelIrql);
+
+
+ //
+ // Release the SpinLock since IoCompleteRequest() must be
+ // called at <= DISPATCH_LEVEL
+ //
+
+ KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
+
+
+ //
+ // Set the status & info size values appropriately, & complete
+ // the request
+ //
+
+ ndisTapiRequest = irp->AssociatedIrp.SystemBuffer;
+ ndisTapiRequest->ulReturnValue = (ULONG) NDIS_STATUS_FAILURE;
+
+ irp->IoStatus.Status = STATUS_CANCELLED;
+ irp->IoStatus.Information = 0;
+
+ IoCompleteRequest (irp, IO_NO_INCREMENT);
+
+ DBGOUT((2,"NdisTapiCleanup: completing QRY/SET request x%x", irp));
+
+
+ //
+ // Reacquire the SpinLock protecting the device queue
+ // & the cancel spinlock
+ //
+
+ KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
+ IoAcquireCancelSpinLock (&cancelIrql);
+ }
+
+ IoReleaseCancelSpinLock (cancelIrql);
+ }
+
+ KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
+
+
+
+ //
+ // Complete the cleanup request with STATUS_SUCCESS.
+ //
+
+NdisTapiCleanup_CompleteRequest:
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest (Irp, IO_NO_INCREMENT);
+
+
+ DBGOUT((2,"NdisTapiCleanup: exit\n"));
+
+ return(STATUS_SUCCESS);
+}
+
+
+
+
+NTSTATUS
+NdisTapiDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ Process the IRPs sent to this device.
+
+Arguments:
+
+ DeviceObject - pointer to a device object
+
+ Irp - pointer to an I/O Request Packet
+
+Return Value:
+
+
+--*/
+
+{
+ KIRQL oldIrql;
+ PVOID ioBuffer;
+ ULONG inputBufferLength;
+ ULONG outputBufferLength;
+ ULONG ioControlCode;
+ NTSTATUS ntStatus;
+ PIO_STACK_LOCATION irpStack;
+
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+
+
+ //
+ // Get a pointer to the current location in the Irp. This is where
+ // the function codes and parameters are located.
+ //
+
+ irpStack = IoGetCurrentIrpStackLocation (Irp);
+
+
+
+ //
+ // Get the pointer to the input/output buffer and it's length
+ //
+
+ ioBuffer = Irp->AssociatedIrp.SystemBuffer;
+ inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
+ outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
+
+
+ switch (irpStack->MajorFunction)
+ {
+ case IRP_MJ_CREATE:
+
+ DBGOUT ((2, "IRP_MJ_CREATE, Irp=x%x", Irp));
+
+ break;
+
+ case IRP_MJ_CLOSE:
+
+ DBGOUT ((2, "IRP_MJ_CLOSE, Irp=x%x", Irp));
+
+ KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
+
+ if (DeviceExtension->NCPAFileObject &&
+ DeviceExtension->TapiSrvFileObject)
+ {
+ //
+ // Both TapiSrv & NCPA are currently running, so we
+ // don't want to shutdown the providers/chg state because
+ // one is closing
+ //
+ }
+ else if ((Irp->Tail.Overlay.OriginalFileObject ==
+ DeviceExtension->NCPAFileObject) ||
+
+ (Irp->Tail.Overlay.OriginalFileObject ==
+ DeviceExtension->TapiSrvFileObject))
+ {
+ //
+ // Either the NCPA or TapiSrv (but no both) was running,
+ // but is now shutting down, so send shutdown msg to providers
+ // & chg state
+ //
+
+ if (DeviceExtension->Status == NDISTAPI_STATUS_CONNECTED)
+ {
+ PPROVIDER_INFO provider;
+
+
+ //
+ // State change
+ //
+
+ DeviceExtension->Status =
+ NDISTAPI_STATUS_DISCONNECTING;
+
+
+ //
+ // Send the providers a shutdown request
+ //
+
+ provider = DeviceExtension->Providers;
+
+ while (provider != NULL)
+ {
+ switch (provider->Status)
+ {
+ case PROVIDER_STATUS_ONLINE:
+ case PROVIDER_STATUS_PENDING_INIT:
+
+ //
+ // Reset provider status
+ //
+
+ provider->Status = PROVIDER_STATUS_PENDING_INIT;
+
+ SendProviderShutdown (provider);
+
+ break;
+
+ case PROVIDER_STATUS_OFFLINE:
+
+ //
+ // If provider is currently offline just remove it
+ // since it's not wanting to talk to us right now
+ //
+
+ // PnP provider = DoRemoveProvider (provider);
+
+ break;
+
+ }
+
+ provider = provider->Next;
+ }
+
+
+ //
+ // State change
+ //
+
+ DeviceExtension->Status = NDISTAPI_STATUS_DISCONNECTED;
+ }
+ }
+
+
+ //
+ // Zero the DeviceExtension->XxxFileObject as appropriate
+ // (Note that we actually get two close requests from each
+ // client, since the each open both a sync & an async driver
+ // handle)
+ //
+
+ if (Irp->Tail.Overlay.OriginalFileObject ==
+ DeviceExtension->NCPAFileObject)
+ {
+ DeviceExtension->NCPAFileObject = NULL;
+ }
+ else if (Irp->Tail.Overlay.OriginalFileObject ==
+ DeviceExtension->TapiSrvFileObject)
+ {
+ DeviceExtension->TapiSrvFileObject = NULL;
+ }
+
+ KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
+
+ break;
+
+ case IRP_MJ_DEVICE_CONTROL:
+
+ ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
+
+ switch (ioControlCode)
+ {
+ case IOCTL_NDISTAPI_CONNECT:
+ {
+ DBGOUT ((2, "IOCTL_NDISTAPI_CONNECT, Irp=x%x", Irp));
+
+
+ //
+ // Someone's connecting. Make sure they passed us a valid
+ // info buffer
+ //
+
+ if ((inputBufferLength < 2*sizeof(ULONG)) ||
+ (outputBufferLength < sizeof(ULONG))
+ )
+ {
+ DBGOUT ((3, "IOCTL_NDISTAPI_CONNECT: buffer too small"));
+
+ Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+
+ break;
+ }
+
+
+ if (DeviceExtension->Status == NDISTAPI_STATUS_DISCONNECTED)
+ {
+ DeviceExtension->Status = NDISTAPI_STATUS_CONNECTING;
+
+
+ //
+ // Reset the async event buf count & pointers
+ //
+
+ DeviceExtension->EventCount = 0;
+ DeviceExtension->DataIn =
+ DeviceExtension->DataOut = DeviceExtension->EventData;
+
+
+ //
+ // Synchronously init all providers
+ //
+
+ SyncInitAllProviders();
+ }
+
+
+ //
+ // Check to see if this is the NCPA
+ //
+
+ if (*(((ULONG *) ioBuffer) + 1) == 0)
+ {
+ DeviceExtension->NCPAFileObject =
+ Irp->Tail.Overlay.OriginalFileObject;
+ }
+ else
+ {
+ DeviceExtension->TapiSrvFileObject =
+ Irp->Tail.Overlay.OriginalFileObject;
+ }
+
+
+ //
+ // Return the number of line devs
+ //
+
+ *((ULONG *) ioBuffer)=
+ DeviceExtension->NdisTapiNumDevices;
+
+ DeviceExtension->Status = NDISTAPI_STATUS_CONNECTED;
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = sizeof(ULONG);
+
+ break;
+ }
+
+ case IOCTL_NDISTAPI_QUERY_INFO:
+ case IOCTL_NDISTAPI_SET_INFO:
+ {
+ ULONG targetDeviceID;
+ NDIS_STATUS ndisStatus;
+ NDIS_HANDLE providerHandle = NULL;
+ REQUEST_PROC requestProc;
+ PPROVIDER_INFO provider;
+ PNDISTAPI_REQUEST ndisTapiRequest;
+ PPROVIDER_REQUEST providerRequest;
+ KIRQL oldIrql;
+ KIRQL cancelIrql;
+
+
+ DBGOUT ((2, "IOCTL_NDISTAPI_QUERY/SET_INFO, Irp=x%x", Irp));
+
+
+ //
+ // Verify we're connected, then check the device ID of the
+ // incoming request against our list of online devices
+ //
+
+ ndisTapiRequest = ioBuffer;
+
+ targetDeviceID = ndisTapiRequest->ulDeviceID;
+
+ DBGOUT((
+ 3,
+ "\tOid=0x%x, retVal=0x%x, devID=%d, dataSize=%d, reqID=%d, parm1=0x%x",
+ ndisTapiRequest->Oid,
+ ndisTapiRequest->ulReturnValue,
+ ndisTapiRequest->ulDeviceID,
+ ndisTapiRequest->ulDataSize,
+ *((ULONG *)ndisTapiRequest->Data),
+ *(((ULONG *)ndisTapiRequest->Data) + 1)
+ ));
+
+ KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
+
+ if (DeviceExtension->Status != NDISTAPI_STATUS_CONNECTED)
+ {
+ DBGOUT((3, "\tunconnected, returning err"));
+
+ ndisTapiRequest->ulReturnValue = NDISTAPIERR_UNINITIALIZED;
+ }
+
+ else if ((targetDeviceID <
+ DeviceExtension->NdisTapiDeviceIDBase) ||
+ (targetDeviceID >=
+ DeviceExtension->NdisTapiDeviceIDBase +
+ DeviceExtension->NdisTapiNumDevices))
+ {
+ DBGOUT((3, "\tdev ID out of range, returning err"));
+
+ ndisTapiRequest->ulReturnValue = NDISTAPIERR_BADDEVICEID;
+ }
+
+ else
+ {
+ provider = DeviceExtension->Providers;
+
+ while (provider != NULL)
+ {
+ if ((provider->Status == PROVIDER_STATUS_ONLINE) &&
+ (targetDeviceID >= provider->DeviceIDBase) &&
+ (targetDeviceID <
+ provider->DeviceIDBase + provider->NumDevices)
+ )
+ {
+ providerHandle = provider->ProviderHandle;
+ requestProc = provider->RequestProc;
+
+ break;
+ }
+
+ provider = provider->Next;
+ }
+
+ if (provider == NULL)
+ {
+ DBGOUT((3, "dev offline, returning err"));
+
+ ndisTapiRequest->ulReturnValue = NDISTAPIERR_DEVICEOFFLINE;
+ }
+ }
+
+ KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
+
+ if (providerHandle == NULL)
+ {
+ //
+ // Set Irp->IoStatus.Information large enough that err code
+ // gets copied back to user buffer
+ //
+
+ Irp->IoStatus.Information = sizeof(ULONG);
+
+ break;
+ }
+
+
+ //
+ // Create the providerRequest & submit it
+ //
+
+ providerRequest = ExAllocatePoolWithTag(
+ NonPagedPoolCacheAligned,
+ sizeof(PROVIDER_REQUEST) + ndisTapiRequest->ulDataSize -
+ sizeof(ULONG), // to acct for ULONG in PROVIDER_REQUEST
+ 'TAPI'
+ );
+
+ if (!providerRequest)
+ {
+ DBGOUT((1, "NdisTapiDispatch: unable to alloc request buf"));
+
+ Irp->IoStatus.Information = sizeof (ULONG);
+
+ ndisTapiRequest->ulReturnValue = (ULONG) NDIS_STATUS_RESOURCES;
+
+ break;
+ }
+
+ providerRequest->NdisRequest.RequestType =
+ (ioControlCode == IOCTL_NDISTAPI_QUERY_INFO ?
+ NdisRequestQueryInformation : NdisRequestSetInformation);
+
+ providerRequest->NdisRequest.DATA.SET_INFORMATION.Oid =
+ ndisTapiRequest->Oid;
+
+ providerRequest->NdisRequest.DATA.SET_INFORMATION.InformationBuffer =
+ providerRequest->Data;
+
+ providerRequest->NdisRequest.DATA.SET_INFORMATION.InformationBufferLength =
+ ndisTapiRequest->ulDataSize;
+
+ providerRequest->Provider = provider;
+
+ RtlMoveMemory(
+ providerRequest->Data,
+ ndisTapiRequest->Data,
+ ndisTapiRequest->ulDataSize
+ );
+
+
+ //
+ // Queue up this TAPI request in our special device queue
+ // prior to submitting the provider request.
+ //
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldIrql);
+
+ if (!KeInsertByKeyDeviceQueue(
+ &DeviceExtension->DeviceQueue,
+ &Irp->Tail.Overlay.DeviceQueueEntry,
+ *((ULONG *) ndisTapiRequest->Data) // sort key = req ID
+ ))
+ {
+ //
+ // If here the queue was not busy, but KeInsertXxx marked
+ // it busy, so try again. We want to toss this in the
+ // queue regardless- it's just going to sit there until
+ // the corresponding provider request is completed, or the
+ // TAPI request is canceled.
+ //
+
+ KeInsertByKeyDeviceQueue(
+ &DeviceExtension->DeviceQueue,
+ &Irp->Tail.Overlay.DeviceQueueEntry,
+ *((ULONG *) ndisTapiRequest->Data) // sort key = req ID
+ );
+ }
+
+ KeLowerIrql (oldIrql);
+
+
+ //
+ // Mark the TAPI request pending
+ //
+
+ Irp->IoStatus.Status = STATUS_PENDING;
+
+
+ //
+ // Set the cancel routine for the TAPI request
+ //
+
+ IoAcquireCancelSpinLock (&cancelIrql);
+ IoSetCancelRoutine (Irp, NdisTapiCancel);
+ IoReleaseCancelSpinLock (cancelIrql);
+
+
+ //
+ // Call the provider's request proc
+ //
+
+ ndisStatus = (*requestProc)(
+ providerHandle,
+ (PNDIS_REQUEST) providerRequest
+ );
+
+
+ //
+ // If PENDING was returned then just exit & let the completion
+ // routine handle the request completion
+ //
+ // NOTE: If pending was returned then the request may have
+ // already been completed, so DO NOT touch anything
+ // in the Irp (don't reference the pointer, etc.)
+ //
+
+ if (ndisStatus == NDIS_STATUS_PENDING)
+ {
+ return STATUS_PENDING;
+ }
+ else
+ {
+ DBGOUT((
+ 1,
+ "IOCTL_TAPI_SET/QUERY_INFO: reqProc return !pending"
+ ));
+
+ //
+ // The provider request completed synchronously, so remove
+ // the TAPI request from the device queue. We need to
+ // synchronize access to this queue with the
+ // SpinLock since the NdisTapiCompleteRequest
+ // func might have removed this request temporarily.
+ //
+
+ KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
+
+ KeRemoveByKeyDeviceQueue(
+ &DeviceExtension->DeviceQueue,
+ *((ULONG *) ndisTapiRequest->Data) // sort key = req ID
+ );
+
+ KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
+
+
+ //
+ // Mark request as successfully completed
+ //
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+
+ //
+ // If this was a succesful QUERY_INFO request copy all the
+ // data back to the tapi request buf & set
+ // Irp->IoStatus.Information appropriately. Otherwise, we
+ // just need to pass back the return value.
+ //
+
+ if ((ioControlCode == IOCTL_NDISTAPI_QUERY_INFO) &&
+ (ndisStatus == NDIS_STATUS_SUCCESS))
+ {
+ RtlMoveMemory(
+ ndisTapiRequest->Data,
+ providerRequest->Data,
+ ndisTapiRequest->ulDataSize
+ );
+
+ Irp->IoStatus.Information =
+ irpStack->Parameters.DeviceIoControl.OutputBufferLength;
+ }
+ else
+ {
+ Irp->IoStatus.Information = sizeof (ULONG);
+ }
+
+ ndisTapiRequest->ulReturnValue = ndisStatus;
+
+
+ //
+ // Free the providerRequest
+ //
+
+ ExFreePool (providerRequest);
+ }
+
+ break;
+ }
+
+ case IOCTL_NDISTAPI_GET_LINE_EVENTS:
+ {
+ KIRQL oldIrql;
+ KIRQL cancelIrql;
+ BOOLEAN satisfiedRequest = FALSE;
+
+
+ DBGOUT ((2, "IOCTL_NDISTAPI_GET_LINE_EVENTS, Irp=x%x", Irp));
+
+
+ //
+ // Sync event buf access by acquiring EventSpinLock
+ //
+
+ KeAcquireSpinLock (&DeviceExtension->EventSpinLock, &oldIrql);
+
+
+ //
+ // Inspect DeviceExtension to see if there's any data available
+ //
+
+ if (DeviceExtension->EventCount != 0)
+ {
+ //
+ // There's line event data queued in our ring buffer. Grab as
+ // much as we can & complete the request.
+ //
+
+ PNDISTAPI_EVENT_DATA ndisTapiEventData = ioBuffer;
+
+
+ ndisTapiEventData->ulUsedSize = GetLineEvents(
+ ndisTapiEventData->Data,
+ ndisTapiEventData->ulTotalSize
+ );
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = ndisTapiEventData->ulUsedSize +
+ sizeof(NDISTAPI_EVENT_DATA) - 1;
+
+ satisfiedRequest = TRUE;
+ }
+ else
+ {
+ //
+ // Hold the request pending. It remains in the cancelable
+ // state. When new line event input is received
+ // (NdisTapiIndicateStatus) or generated (i.e.
+ // LINEDEVSTATE_REINIT) the data will get copied & the
+ // request completed.
+ //
+
+ DeviceExtension->EventsRequestIrp = Irp;
+
+ Irp->IoStatus.Status = STATUS_PENDING;
+
+ IoAcquireCancelSpinLock (&cancelIrql);
+ IoSetCancelRoutine (Irp, NdisTapiCancel);
+ IoReleaseCancelSpinLock (cancelIrql);
+ }
+
+ KeReleaseSpinLock (&DeviceExtension->EventSpinLock, oldIrql);
+
+
+ //
+ // If request not satisfied just return pending
+ //
+
+ if (!satisfiedRequest)
+ {
+ return STATUS_PENDING;
+ }
+
+ break;
+ }
+
+ default:
+
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+
+ DBGOUT ((2, "unknown IRP_MJ_DEVICE_CONTROL"));
+
+ break;
+
+ } // switch
+
+ break;
+ }
+
+
+ //
+ // DON'T try to use the status field of the irp in the return
+ // status. That IRP IS GONE as soon as you call IoCompleteRequest.
+ //
+
+ if ((ntStatus = Irp->IoStatus.Status) != STATUS_PENDING)
+ {
+ IoCompleteRequest (Irp, IO_NO_INCREMENT);
+
+ DBGOUT((3, "NdisTapiDispatch: completed Irp=x%x", Irp));
+ }
+ else
+ {
+ DBGOUT((3, "NdisTapiDispatch: pending Irp=x%x", Irp));
+ }
+
+ return ntStatus;
+}
+
+
+
+
+VOID
+NdisTapiUnload(
+ IN PDRIVER_OBJECT DriverObject
+ )
+
+/*++
+
+Routine Description:
+
+ Free all the allocated resources, etc.
+
+Arguments:
+
+ DriverObject - pointer to a driver object
+
+Return Value:
+
+
+--*/
+
+{
+ PPROVIDER_INFO provider, nextProvider;
+
+
+ DBGOUT ((2, "NdisTapiUnload: enter"));
+
+
+ //
+ // Delete the device object & sundry resources
+ //
+
+ ExFreePool (DeviceExtension->EventData);
+
+ provider = DeviceExtension->Providers, nextProvider;
+
+ while (provider != NULL)
+ {
+ nextProvider = provider->Next;
+
+ ExFreePool (provider);
+
+ provider = nextProvider;
+ }
+
+ IoDeleteDevice (DriverObject->DeviceObject);
+
+ DBGOUT ((2, "NdisTapiUnload: exit"));
+
+ return;
+}
+
+
+
+VOID
+NdisTapiRegisterProvider(
+ IN NDIS_HANDLE ProviderHandle,
+ IN REQUEST_PROC RequestProc
+ )
+
+/*++
+
+Routine Description:
+
+ This func gets called by Ndis as a result of a Mac driver
+ registering for Connection Wrapper services.
+
+Arguments:
+
+
+
+Return Value:
+
+
+--*/
+
+{
+// KIRQL oldIrql;
+ BOOLEAN sendRequest = FALSE;
+ NDIS_STATUS ndisStatus;
+ PPROVIDER_INFO provider, newProvider;
+
+
+ DBGOUT ((2, "NdisTapiRegisterProvider: enter"));
+
+
+ //
+ // Create a new provider instance
+ //
+
+ newProvider = ExAllocatePoolWithTag(
+ NonPagedPoolCacheAligned,
+ sizeof(PROVIDER_INFO),
+ 'TAPI'
+ );
+
+ newProvider->Status = PROVIDER_STATUS_PENDING_INIT;
+ newProvider->ProviderHandle = ProviderHandle;
+ newProvider->RequestProc = RequestProc;
+ newProvider->Next = NULL;
+
+
+
+ //
+ // Grab the spin lock & add the new provider, and see whether to
+ // send the provider an init request
+ //
+
+// KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
+
+ if ((provider = DeviceExtension->Providers) == NULL)
+ {
+ DeviceExtension->Providers = newProvider;
+ }
+ else
+ {
+ while (provider->Next != NULL)
+ {
+ provider = provider->Next;
+ }
+
+ provider->Next = newProvider;
+ }
+
+ //
+ // The only case where we want to send off an init request to the
+ // provider directly is when we are currently connected to TAPI,
+ // and even then only when there are no other inits pending (since
+ // we must synchronize inits due to calculation of DeviceIDBase)
+ //
+
+ if ((DeviceExtension->Status == NDISTAPI_STATUS_CONNECTED) &&
+ (DeviceExtension->ProviderInitPending == FALSE)
+ )
+ {
+ ndisStatus = SendProviderInitRequest (newProvider);
+
+ if (ndisStatus == NDIS_STATUS_PENDING)
+ {
+ DeviceExtension->ProviderInitPending == TRUE;
+ }
+ }
+
+// KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
+
+ // Pnp: we should keep track of the current # of providers
+ // registered, so that we can bump up NdisTapiNumDevices
+ // appropriately
+
+ return;
+}
+
+
+
+VOID
+NdisTapiDeregisterProvider(
+ IN NDIS_HANDLE ProviderHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This func...
+
+ Note that this func does not send the provider a shutdown message,
+ as an implicit shutdown is assumed when the provider deegisters.
+
+Arguments:
+
+
+
+Return Value:
+
+
+--*/
+
+{
+// KIRQL oldIrql;
+ BOOLEAN sendShutdownMsg = FALSE;
+ PPROVIDER_INFO provider, previousProvider;
+
+
+ DBGOUT ((2, "NdisTapiDeregisterProvider: enter"));
+
+
+ //
+ // Grab the spin lock protecting the device extension
+ //
+
+// KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
+
+
+
+ //
+ // Find the provider instance corresponding to ProviderHandle
+ //
+
+ provider = DeviceExtension->Providers;
+
+ if (provider == NULL)
+ {
+ goto NdisTapiDeregisterProvider_err;
+ }
+
+ while (provider->ProviderHandle != ProviderHandle)
+ {
+ previousProvider = provider;
+
+ provider = provider->Next;
+
+ if (provider == NULL)
+ {
+ goto NdisTapiDeregisterProvider_err;
+ }
+ }
+
+
+ //
+ // Do the right thing according to the current NdisTapi state
+ //
+
+ switch (DeviceExtension->Status)
+ {
+ case NDISTAPI_STATUS_CONNECTED:
+
+ //
+ // Mark provider as offline
+ //
+
+ provider->Status = PROVIDER_STATUS_OFFLINE;
+
+
+ // PnP: what if providerInfo->State == PROVIDER_INIT_PENDING
+ // PnP: what if providerInfo->State == PROVIDER_OFFLINE
+
+ break;
+
+ case NDISTAPI_STATUS_DISCONNECTING:
+ case NDISTAPI_STATUS_DISCONNECTED:
+
+ //
+ // Fix up pointers, remove provider from list
+ //
+
+ if (provider == DeviceExtension->Providers)
+ {
+ DeviceExtension->Providers = provider->Next;
+ }
+ else
+ {
+ previousProvider->Next = provider->Next;
+ }
+
+ ExFreePool (provider);
+
+ break;
+
+ case NDISTAPI_STATUS_CONNECTING:
+
+ // PnP: implement
+
+ break;
+
+ } // switch
+
+ goto NdisTapiDeregisterProvider_ReleaseSpinLock;
+
+
+NdisTapiDeregisterProvider_err:
+
+ DBGOUT((0, "NdisTapiDeregisterProvider: bad provider handle"));
+
+
+NdisTapiDeregisterProvider_ReleaseSpinLock:
+
+// KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
+
+ DBGOUT((2, "NdisTapiDeregisterProvider: exit"));
+
+ return;
+}
+
+
+
+VOID
+NdisTapiIndicateStatus(
+ IN ULONG DriverHandle,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ )
+
+/*++
+
+Routine Description:
+
+ This func gets called by Ndis when a miniport driver calls
+ NdisIndicateStatus to notify us of an async event
+ (i.e. new call, call state chg, dev state chg, etc.)
+
+Arguments:
+
+
+
+Return Value:
+
+
+--*/
+
+{
+ PIRP irp;
+ KIRQL oldIrql;
+ KIRQL cancelIrql;
+ ULONG bytesInQueue;
+ ULONG bytesToMove;
+ ULONG moveSize;
+ BOOLEAN satisfiedPendingEventsRequest = FALSE;
+ PNDIS_TAPI_EVENT ndisTapiEvent;
+ PNDISTAPI_EVENT_DATA ndisTapiEventData;
+
+
+ DBGOUT((2,"NdisTapiIndicateStatus: enter"));
+
+
+ bytesInQueue = StatusBufferSize;
+
+ moveSize = 0;
+
+
+ //
+ // Sync event buf access by acquiring EventSpinLock
+ //
+
+ KeAcquireSpinLock (&DeviceExtension->EventSpinLock, &oldIrql);
+
+
+ //
+ // The very first thing to do is check if this is a LINE_NEWCALL
+ // indication. If so, we need to generate a unique tapi call
+ // handle, which will be both returned to the calling miniport
+ // (for use in subsequent status indications) and passed up to
+ // the tapi server. Note that valid htCall values as generated by
+ // this driver range between 0x80000000 and 0xfffffffe (the
+ // user-mode tapi server reserves the range 0x1-0x7fffffff).
+ //
+
+ ndisTapiEvent = StatusBuffer;
+
+ if (ndisTapiEvent->ulMsg == LINE_NEWCALL)
+ {
+ ndisTapiEvent->ulParam2 = DeviceExtension->htCall;
+
+ DeviceExtension->htCall++;
+
+ if (DeviceExtension->htCall > 0xfffffffe)
+ {
+ DeviceExtension->htCall = 0x80000000;
+ }
+ }
+
+
+ //
+ // Check of there is an outstanding request to satisfy
+ //
+
+ if (DeviceExtension->EventsRequestIrp)
+ {
+ //
+ // Acquire the cancel spinlock, remove the request from the
+ // cancellable state, and free the cancel spinlock.
+ //
+
+ IoAcquireCancelSpinLock (&cancelIrql);
+ irp = DeviceExtension->EventsRequestIrp;
+ IoSetCancelRoutine (irp, NULL);
+ DeviceExtension->EventsRequestIrp = NULL;
+ IoReleaseCancelSpinLock (cancelIrql);
+
+
+ //
+ // Copy as much of the input data possible from the input data
+ // queue to the SystemBuffer to satisfy the read.
+ //
+
+ ndisTapiEventData = irp->AssociatedIrp.SystemBuffer;
+
+ bytesToMove = ndisTapiEventData->ulTotalSize;
+
+ moveSize = (bytesInQueue < bytesToMove) ? bytesInQueue : bytesToMove;
+
+ RtlMoveMemory (
+ ndisTapiEventData->Data,
+ (PCHAR) StatusBuffer,
+ moveSize
+ );
+
+
+ //
+ // Set the flag so that we start the next packet and complete
+ // this read request (with STATUS_SUCCESS) prior to return.
+ //
+
+ ndisTapiEventData->ulUsedSize = moveSize;
+
+ irp->IoStatus.Status = STATUS_SUCCESS;
+
+ irp->IoStatus.Information = sizeof(NDISTAPI_EVENT_DATA) + moveSize - 1;
+
+ satisfiedPendingEventsRequest = TRUE;
+ }
+
+
+ //
+ // If there is still data in the input data queue, move it
+ // to the event data queue
+ //
+
+ StatusBuffer = ((PCHAR) StatusBuffer) + moveSize;
+
+ moveSize = bytesInQueue - moveSize;
+
+ if (moveSize > 0)
+ {
+ //
+ // Move the remaining data from the status data queue to the
+ // event data queue. The move will happen in two parts in
+ // the case where the event data buffer wraps.
+ //
+
+ bytesInQueue =
+ DeviceExtension->EventDataQueueLength -
+ (DeviceExtension->EventCount * sizeof(NDIS_TAPI_EVENT));
+
+ bytesToMove = moveSize;
+
+ if (bytesInQueue == 0)
+ {
+ //
+ // Refuse to move any bytes that would cause an event data
+ // queue overflow. Just drop the bytes on the floor, and
+ // log an overrun error.
+ //
+
+ DBGOUT((1,"NdisTapiIndicateStatus: event queue overflow"));
+ }
+ else
+ {
+ //
+ // There is room in the event data queue, so move the
+ // remaining status data to it.
+ //
+ // bytesToMove <- MIN(Number of unused bytes in event data queue,
+ // Number of bytes remaining in status buffer)
+ //
+ // This is the total number of bytes that actually will move from
+ // the status data buffer to the event data queue.
+ //
+
+ bytesToMove = (bytesInQueue < bytesToMove) ?
+ bytesInQueue : bytesToMove;
+
+
+ //
+ // bytesInQueue <- Number of unused bytes from insertion pointer
+ // to the end of the event data queue (i.e., until the buffer
+ // wraps)
+ //
+
+ bytesInQueue =
+ ((PCHAR) DeviceExtension->EventData +
+ DeviceExtension->EventDataQueueLength) -
+ (PCHAR) DeviceExtension->DataIn;
+
+
+ //
+ // moveSize <- Number of bytes to handle in the first move.
+ //
+
+ moveSize = (bytesToMove < bytesInQueue) ?
+ bytesToMove : bytesInQueue;
+
+
+ //
+ // Do the move from the status data buffer to the event data queue
+ //
+
+ RtlMoveMemory(
+ (PCHAR) DeviceExtension->DataIn,
+ (PCHAR) StatusBuffer,
+ moveSize
+ );
+
+ //
+ // Increment the event data queue pointer and the status data
+ // buffer insertion pointer. Wrap the insertion pointer,
+ // if necessary.
+ //
+
+ StatusBuffer = ((PCHAR) StatusBuffer) + moveSize;
+
+ DeviceExtension->DataIn =
+ ((PCHAR) DeviceExtension->DataIn) + moveSize;
+
+ if ((PCHAR) DeviceExtension->DataIn >=
+ ((PCHAR) DeviceExtension->EventData +
+ DeviceExtension->EventDataQueueLength))
+ {
+ DeviceExtension->DataIn = DeviceExtension->EventData;
+ }
+
+ if ((bytesToMove - moveSize) > 0)
+ {
+ //
+ // Special case. The data must wrap in the event data
+ // buffer. Copy the rest of the status data into the
+ // beginning of the event data queue.
+ //
+
+ //
+ // moveSize <- Number of bytes to handle in the second move.
+ //
+
+ moveSize = bytesToMove - moveSize;
+
+
+ //
+ // Do the move from the status data buffer to the event data
+ // queue
+ //
+
+ RtlMoveMemory(
+ (PCHAR) DeviceExtension->DataIn,
+ (PCHAR) StatusBuffer,
+ moveSize
+ );
+
+ //
+ // Update the event data queue insertion pointer
+ //
+
+ DeviceExtension->DataIn =
+ ((PCHAR) DeviceExtension->DataIn) + moveSize;
+ }
+
+ //
+ // Update the event data queue counter
+ //
+
+ DeviceExtension->EventCount +=
+ (bytesToMove / sizeof(NDIS_TAPI_EVENT));
+ }
+ }
+
+
+ //
+ // Release the spinlock
+ //
+
+ KeReleaseSpinLock (&DeviceExtension->EventSpinLock, oldIrql);
+
+
+ //
+ // If we satisfied an outstanding get events request then complete it
+ //
+
+ if (satisfiedPendingEventsRequest)
+ {
+ IoCompleteRequest (irp, IO_NO_INCREMENT);
+
+ DBGOUT((2, "NdisTapiIndicateStatus: completion req 0x%x", irp));
+ }
+
+
+ DBGOUT((2,"NdisTapiIndicateStatus: exit"));
+
+ return;
+}
+
+
+
+VOID
+NdisTapiCompleteRequest(
+ IN NDIS_HANDLE NdisHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This func gets called by Ndis as a result of a Mac driver
+ calling NdisCompleteRequest of one of our requests.
+
+Arguments:
+
+
+
+Return Value:
+
+
+--*/
+
+{
+ PIRP irp;
+ KIRQL oldIrql;
+ KIRQL cancelIrql;
+ ULONG requestID;
+// PPROVIDER_INFO provider;
+ PNDISTAPI_REQUEST ndisTapiRequest;
+ PPROVIDER_REQUEST providerRequest = (PPROVIDER_REQUEST) NdisRequest;
+ PIO_STACK_LOCATION irpStack;
+ PKDEVICE_QUEUE_ENTRY packet;
+
+
+ DBGOUT ((2, "NdisTapiCompleteRequest: enter"));
+
+
+ requestID = providerRequest->Data[0];
+
+
+ //
+ // Determine the type of request
+ //
+
+ if (requestID == 0)
+ {
+ //
+ // This request originated from NdisTapi.sys
+ //
+
+ switch (providerRequest->NdisRequest.DATA.SET_INFORMATION.Oid)
+ {
+ case OID_TAPI_PROVIDER_INITIALIZE:
+
+ KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
+
+ switch (DeviceExtension->Status)
+ {
+ case NDISTAPI_STATUS_CONNECTED:
+
+ // PnP: what if NdisStatus != NDIS_STATUS_SUCCESS?
+
+ DoProviderInitComplete (providerRequest);
+
+ if (SyncInitAllProviders() == TRUE)
+ {
+ DeviceExtension->ProviderInitPending = FALSE;
+ }
+
+ break;
+
+ case NDISTAPI_STATUS_DISCONNECTED:
+
+ break;
+
+ case NDISTAPI_STATUS_CONNECTING:
+
+ // PnP: what if NdisStatus != NDIS_STATUS_SUCCESS?
+
+ //
+ // Mark provider as online, etc.
+ //
+
+ DoProviderInitComplete (providerRequest);
+
+
+ //
+ // Set the event which sync's miniport inits
+ //
+
+ KeSetEvent(
+ &DeviceExtension->SyncEvent,
+ 0,
+ FALSE
+ );
+
+ break;
+
+ case NDISTAPI_STATUS_DISCONNECTING:
+
+ break;
+
+ } // switch
+
+ KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
+
+ break;
+
+ case OID_TAPI_PROVIDER_SHUTDOWN:
+
+ break;
+
+ default:
+
+ DBGOUT((1, "NdisTapiCompleteRequest: unrecognized Oid"));
+
+ break;
+ }
+ }
+ else
+ {
+ //
+ // This is a request originating from TAPI
+ //
+
+ //
+ // Acquire the SpinLock since we're going to be removing a
+ // TAPI request from the queue, and it might not be the request
+ // we're looking for. The primary concern is that we could (if
+ // the request we're really looking for has been removed) remove
+ // a synchrously-completed request that is about to be removed &
+ // completed in NdisTapiDispatch, in which case we want to stick
+ // the request back in the queue before NdisTapiDispatch tries
+ // to remove it.
+ //
+
+ KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
+
+
+
+ //
+ // Grab the cancel spin lock & get the IRP out of our queue.
+ //
+
+ IoAcquireCancelSpinLock (&cancelIrql);
+
+ packet = KeRemoveByKeyDeviceQueue(
+ &DeviceExtension->DeviceQueue,
+ requestID
+ );
+
+ if (packet != NULL)
+ {
+ //
+ // Get the ptrs
+ //
+
+ irp = CONTAINING_RECORD(
+ packet,
+ IRP,
+ Tail.Overlay.DeviceQueueEntry
+ );
+
+ ndisTapiRequest = irp->AssociatedIrp.SystemBuffer;
+
+
+ //
+ // Verify the IRP we got back was the one we wanted to remove
+ //
+
+ if (requestID == *((ULONG *)ndisTapiRequest->Data))
+ {
+ //
+ // Remove the IRP from the cancelable state
+ //
+
+ IoSetCancelRoutine (irp, NULL);
+ IoReleaseCancelSpinLock (cancelIrql);
+
+
+ //
+ // Release the SpinLock
+ //
+
+ KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
+
+
+ //
+ // Copy the relevant info back to the IRP
+ //
+
+ irpStack = IoGetCurrentIrpStackLocation (irp);
+
+
+ //
+ // If this was a succesful QUERY_INFO request copy all the
+ // data back to the tapi request buf & set
+ // Irp->IoStatus.Information appropriately. Otherwise, we
+ // just need to pass back the return value. Also mark irp
+ // as successfully completed (regardless of actual op result)
+ //
+
+ if ((NdisRequest->RequestType == NdisRequestQueryInformation)&&
+ (NdisStatus == 0))
+ {
+ RtlMoveMemory(
+ ndisTapiRequest->Data,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
+ ndisTapiRequest->ulDataSize
+ );
+
+ irp->IoStatus.Information =
+ irpStack->Parameters.DeviceIoControl.OutputBufferLength;
+ }
+ else
+ {
+ irp->IoStatus.Information = sizeof (ULONG);
+ }
+
+ irp->IoStatus.Status = STATUS_SUCCESS;
+
+ ndisTapiRequest->ulReturnValue = NdisStatus;
+
+
+ //
+ // Finally, complete the TAPI request
+ //
+
+ DBGOUT ((3, "completing request 0x%lx", requestID));
+
+ IoCompleteRequest (irp, IO_NO_INCREMENT);
+ }
+ else
+ {
+ DBGOUT ((1, "Wrong IRP removed from queue- requeueing"));
+
+
+ //
+ // We got the wrong IRP out, the one we wanted probably
+ // has been canceled. Stick this IRP back in the queue.
+ //
+
+ if (!KeInsertByKeyDeviceQueue(
+ &DeviceExtension->DeviceQueue,
+ &irp->Tail.Overlay.DeviceQueueEntry,
+ *((ULONG *) ndisTapiRequest->Data) // sortkey=reqID
+ ))
+ {
+ //
+ // If here the queue was not busy, but KeInsertXxx marked
+ // it busy, so try again. We want to toss this in the
+ // queue regardless- it's just going to sit there until
+ // the corresponding provider request is completed, or the
+ // TAPI request is canceled.
+ //
+
+ KeInsertByKeyDeviceQueue(
+ &DeviceExtension->DeviceQueue,
+ &irp->Tail.Overlay.DeviceQueueEntry,
+ *((ULONG *) ndisTapiRequest->Data) // sortkey=reqID
+ );
+ }
+
+
+ //
+ // Release the cancel spin lock
+ //
+
+ IoReleaseCancelSpinLock (cancelIrql);
+
+
+ //
+ // Release the SpinLock.
+ //
+
+ KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
+ }
+ }
+ else
+ {
+ //
+ // No packets in the queue, release the cancel spin lock
+ //
+
+ IoReleaseCancelSpinLock (cancelIrql);
+
+
+ //
+ // Release the SpinLock.
+ //
+
+ KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
+ }
+ }
+
+ ExFreePool (NdisRequest);
+
+ DBGOUT ((2, "NdisTapiCompleteRequest: exit"));
+
+ return;
+}
+
+
+#if DBG
+VOID
+DbgPrt(
+ IN ULONG DbgLevel,
+ IN PUCHAR DbgMessage,
+ IN ...
+ )
+
+/*++
+
+Routine Description:
+
+ Formats the incoming debug message & calls DbgPrint
+
+Arguments:
+
+ DbgLevel - level of message verboseness
+
+ DbgMessage - printf-style format string, followed by appropriate
+ list of arguments
+
+Return Value:
+
+
+--*/
+
+{
+ if (DbgLevel <= NdisTapiDebugLevel)
+ {
+ char buf[256] = "NDISTAPI.SYS: ";
+ va_list ap;
+
+ va_start (ap, DbgMessage);
+
+ vsprintf (&buf[14], DbgMessage, ap);
+
+ strcat (buf, "\n");
+
+ DbgPrint (buf);
+
+ va_end(ap);
+ }
+
+ return;
+}
+#endif // DBG
+
+
+VOID
+DoProviderInitComplete(
+ PPROVIDER_REQUEST ProviderRequest
+ )
+
+/*++
+
+Routine Description:
+
+
+
+Arguments:
+
+ ProviderInitRequest - pointer successfully completed init request
+
+Return Value:
+
+
+
+Note:
+
+ Assumes DeviceExtension->SpinLock held by caller.
+
+--*/
+
+{
+ PPROVIDER_INFO provider = ProviderRequest->Provider;
+ PNDIS_TAPI_PROVIDER_INITIALIZE providerInitData =
+ (PNDIS_TAPI_PROVIDER_INITIALIZE) ProviderRequest->Data;
+
+
+ DBGOUT ((2, "DoProviderInitComplete: enter"));
+
+
+ //
+ // Wrap this in an exception handler in case the provider was
+ // removed during an async completion
+ //
+
+ try
+ {
+ provider->Status = PROVIDER_STATUS_ONLINE;
+ provider->ProviderID = providerInitData->ulProviderID;
+ provider->NumDevices = providerInitData->ulNumLineDevs;
+
+ DBGOUT((
+ 3,
+ "providerID = 0x%lx, numDevices = 0x%lx",
+ provider->ProviderID,
+ provider->NumDevices
+ ));
+ }
+ except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ DBGOUT((1, "DoProviderInitComplete: provider invalid"));
+ }
+
+ //
+ // PnP: Check to see if this is a provider that registered &
+ // deregistered earlier (look at ProviderID's).
+ //
+
+ DBGOUT ((2, "DoProviderInitComplete: exit"));
+}
+
+
+ULONG
+GetLineEvents(
+ PCHAR EventBuffer,
+ ULONG BufferSize
+ )
+
+/*++
+
+Routine Description:
+
+
+
+Arguments:
+
+
+
+Return Value:
+
+
+
+Note:
+
+ Assumes DeviceExtension->EventSpinLock held by caller.
+
+--*/
+
+{
+ ULONG bytesInQueue;
+ ULONG bytesToMove;
+ ULONG moveSize;
+
+
+ bytesInQueue = DeviceExtension->EventCount * sizeof(NDIS_TAPI_EVENT);
+
+ bytesToMove = BufferSize;
+
+ bytesToMove = (bytesInQueue < bytesToMove) ? bytesInQueue : bytesToMove;
+
+
+ //
+ // moveSize <- MIN(Number of bytes to be moved from the event data queue,
+ // Number of bytes to end of event data queue).
+ //
+
+ bytesInQueue =
+ ((PCHAR) DeviceExtension->EventData +
+ DeviceExtension->EventDataQueueLength) -
+ (PCHAR) DeviceExtension->DataOut;
+
+ moveSize = (bytesToMove < bytesInQueue) ? bytesToMove : bytesInQueue;
+
+
+ //
+ // Move bytes from the class input data queue to SystemBuffer, until
+ // the request is satisfied or we wrap the class input data buffer.
+ //
+
+ RtlMoveMemory(
+ EventBuffer,
+ (PCHAR) DeviceExtension->DataOut,
+ moveSize
+ );
+
+ EventBuffer += moveSize;
+
+
+ //
+ // If the data wraps in the event data buffer, copy the rest
+ // of the data from the start of the input data queue
+ // buffer through the end of the queued data.
+ //
+
+ if ((bytesToMove - moveSize) > 0)
+ {
+ //
+ // moveSize <- Remaining number bytes to move.
+ //
+
+ moveSize = bytesToMove - moveSize;
+
+ //
+ // Move the bytes from the
+ //
+
+ RtlMoveMemory(
+ EventBuffer,
+ (PCHAR) DeviceExtension->EventData,
+ moveSize
+ );
+
+ //
+ // Update the class input data queue removal pointer.
+ //
+
+ DeviceExtension->DataOut =
+ ((PCHAR) DeviceExtension->EventData) + moveSize;
+ }
+ else
+ {
+ //
+ // Update the input data queue removal pointer.
+ //
+
+ DeviceExtension->DataOut =
+ ((PCHAR) DeviceExtension->DataOut) + moveSize;
+ }
+
+
+ //
+ // Update the event data queue EventCount.
+ //
+
+ DeviceExtension->EventCount -=
+ (bytesToMove / sizeof(NDIS_TAPI_EVENT));
+
+ return bytesToMove;
+}
+
+
+VOID
+GetRegistryParameters(
+ IN PUNICODE_STRING RegistryPath
+)
+
+/*++
+
+Routine Description:
+
+ This routine stores the configuration information for this device.
+
+Arguments:
+
+ RegistryPath - Pointer to the null-terminated Unicode name of the
+ registry path for this driver.
+
+Return Value:
+
+ None. As a side-effect, sets DeviceExtension->EventDataQueuLength field
+
+--*/
+
+{
+ ULONG defaultDataQueueSize = 32 * sizeof(NDIS_TAPI_EVENT);
+ PWSTR path = NULL;
+ USHORT queriesPlusOne = 2;
+ NTSTATUS status = STATUS_SUCCESS;
+ UNICODE_STRING parametersPath;
+ PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
+
+
+ parametersPath.Buffer = NULL;
+
+
+ //
+ // Registry path is already null-terminated, so just use it.
+ //
+
+ path = RegistryPath->Buffer;
+
+ if (NT_SUCCESS(status))
+ {
+ //
+ // Allocate the Rtl query table.
+ //
+
+ parameters = ExAllocatePool(
+ PagedPool,
+ sizeof(RTL_QUERY_REGISTRY_TABLE) * queriesPlusOne
+ );
+
+ if (!parameters)
+ {
+ DBGOUT((1, "NdisTapiConfiguration: ExAllocPool failed"));
+
+ status = STATUS_UNSUCCESSFUL;
+ }
+ else
+ {
+ RtlZeroMemory(
+ parameters,
+ sizeof(RTL_QUERY_REGISTRY_TABLE) * queriesPlusOne
+ );
+
+ //
+ // Form a path to this driver's Parameters subkey.
+ //
+
+ RtlInitUnicodeString(
+ &parametersPath,
+ NULL
+ );
+
+ parametersPath.MaximumLength = RegistryPath->Length +
+ sizeof(L"\\Parameters");
+
+ parametersPath.Buffer = ExAllocatePool(
+ PagedPool,
+ parametersPath.MaximumLength
+ );
+
+ if (!parametersPath.Buffer)
+ {
+ DBGOUT((1, "NdisTapiConfiguration: ExAllocPool failed"));
+
+ status = STATUS_UNSUCCESSFUL;
+ }
+ }
+ }
+
+ if (NT_SUCCESS(status))
+ {
+ //
+ // Form the parameters path.
+ //
+
+ RtlZeroMemory(
+ parametersPath.Buffer,
+ parametersPath.MaximumLength
+ );
+
+ RtlAppendUnicodeToString(
+ &parametersPath,
+ path
+ );
+
+ RtlAppendUnicodeToString(
+ &parametersPath,
+ L"\\Parameters"
+ );
+
+ DBGOUT((
+ 1,
+ "NdisTapiConfiguration: parameters path is %ws\n",
+ parametersPath.Buffer
+ ));
+
+
+ //
+ // Gather all of the "user specified" information from
+ // the registry.
+ //
+
+ parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ parameters[0].Name = L"AsyncEventQueueSize";
+ parameters[0].EntryContext =
+ &DeviceExtension->EventDataQueueLength;
+ parameters[0].DefaultType = REG_DWORD;
+ parameters[0].DefaultData = &defaultDataQueueSize;
+ parameters[0].DefaultLength = sizeof(ULONG);
+
+ status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
+ parametersPath.Buffer,
+ parameters,
+ NULL,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ DBGOUT((
+ 1,
+ "NdisTapiConfiguration: RtlQueryRegistryVals failed, err=x%x",
+ status
+ ));
+ }
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ //
+ // Go ahead and assign driver defaults.
+ //
+
+ DeviceExtension->EventDataQueueLength = defaultDataQueueSize;
+ }
+
+
+ //
+ // Data queue ought be a least the size of the default
+ //
+
+ if (DeviceExtension->EventDataQueueLength < defaultDataQueueSize)
+ {
+ DeviceExtension->EventDataQueueLength = defaultDataQueueSize;
+ }
+
+
+ //
+ // Make sure the queue length is an integral # of (sizeof) events
+ //
+
+ DeviceExtension->EventDataQueueLength -=
+ DeviceExtension->EventDataQueueLength % sizeof(NDIS_TAPI_EVENT);
+
+
+ //
+ // Dump value
+ //
+
+ DBGOUT ((
+ 1,
+ "NdisTapiConfiguration: EventDataQueueLength = x%x",
+ DeviceExtension->EventDataQueueLength
+ ));
+
+
+ //
+ // Free the allocated memory before returning.
+ //
+
+ if (parametersPath.Buffer)
+ {
+ ExFreePool(parametersPath.Buffer);
+ }
+
+ if (parameters)
+ {
+ ExFreePool(parameters);
+ }
+}
+
+
+NDIS_STATUS
+SendProviderInitRequest(
+ PPROVIDER_INFO Provider
+ )
+
+/*++
+
+Routine Description:
+
+
+
+Arguments:
+
+ Provider - pointer to a PROVIDER_INFO representing provider to initialize
+
+Return Value:
+
+
+
+Note:
+
+ Assumes DeviceExtension->SpinLock held by caller
+
+--*/
+
+{
+ NDIS_STATUS ndisStatus;
+ PPROVIDER_INFO tmpProvider;
+ PPROVIDER_REQUEST providerRequest;
+ PNDIS_TAPI_PROVIDER_INITIALIZE providerInitData;
+
+
+ DBGOUT ((2, "SendProviderInitRequest: enter"));
+
+
+ //
+ // Determine the DeviceIDBase to be used for this provider
+ //
+
+ Provider->DeviceIDBase = DeviceExtension->NdisTapiDeviceIDBase;
+
+ tmpProvider = DeviceExtension->Providers;
+
+ while (tmpProvider != NULL)
+ {
+ if (tmpProvider->Status != PROVIDER_STATUS_PENDING_INIT)
+ {
+ Provider->DeviceIDBase += tmpProvider->NumDevices;
+ }
+ tmpProvider = tmpProvider->Next;
+ }
+
+
+
+ //
+ // Create a provider init request
+ //
+
+ providerRequest = ExAllocatePoolWithTag(
+ NonPagedPoolCacheAligned,
+ sizeof(PROVIDER_REQUEST) + sizeof(NDIS_TAPI_PROVIDER_INITIALIZE) -
+ sizeof(ULONG),
+ 'TAPI'
+ );
+
+
+ providerRequest->NdisRequest.RequestType = NdisRequestQueryInformation;
+
+ providerRequest->NdisRequest.DATA.SET_INFORMATION.Oid =
+ OID_TAPI_PROVIDER_INITIALIZE;
+
+ providerRequest->NdisRequest.DATA.SET_INFORMATION.InformationBuffer =
+ providerRequest->Data;
+
+ providerRequest->NdisRequest.DATA.SET_INFORMATION.InformationBufferLength =
+ sizeof(NDIS_TAPI_PROVIDER_INITIALIZE);
+
+
+ providerRequest->Provider = Provider;
+
+
+ providerInitData =
+ (PNDIS_TAPI_PROVIDER_INITIALIZE) providerRequest->Data;
+
+ providerInitData->ulRequestID = 0;
+ providerInitData->ulDeviceIDBase = Provider->DeviceIDBase;
+
+
+ //
+ // Send the request
+ //
+
+ ndisStatus=
+ (*Provider->RequestProc)(
+ Provider->ProviderHandle,
+ (PNDIS_REQUEST) providerRequest
+ );
+
+ if (ndisStatus == NDIS_STATUS_SUCCESS)
+ {
+ DoProviderInitComplete (providerRequest);
+
+ ExFreePool (providerRequest);
+ }
+ else if (ndisStatus == NDIS_STATUS_PENDING)
+ {
+ //
+ // Do nothing
+ //
+ }
+ else
+ {
+ // PnP: an error occured, clean up & act like this never happened
+ }
+
+ DBGOUT ((2, "SendProviderInitRequest: exit"));
+
+ return ndisStatus;
+}
+
+
+NDIS_STATUS
+SendProviderShutdown(
+ PPROVIDER_INFO Provider
+ )
+
+/*++
+
+Routine Description:
+
+
+
+Arguments:
+
+
+
+Return Value:
+
+ A pointer to the next provider in the global providers list
+
+Note:
+
+ Assumes DeviceExtension->SpinLock held by caller.
+
+--*/
+
+{
+ NDIS_STATUS ndisStatus;
+ PPROVIDER_REQUEST providerRequest;
+
+
+ DBGOUT ((2, "SendProviderShutdown: enter"));
+
+
+
+ //
+ // Create a provider init request
+ //
+
+ providerRequest = ExAllocatePoolWithTag(
+ NonPagedPoolCacheAligned,
+ sizeof(PROVIDER_REQUEST) + sizeof(NDIS_TAPI_PROVIDER_SHUTDOWN) -
+ sizeof(ULONG),
+ 'TAPI'
+ );
+
+
+ providerRequest->NdisRequest.RequestType = NdisRequestSetInformation;
+
+ providerRequest->NdisRequest.DATA.SET_INFORMATION.Oid =
+ OID_TAPI_PROVIDER_SHUTDOWN;
+
+ providerRequest->NdisRequest.DATA.SET_INFORMATION.InformationBuffer =
+ providerRequest->Data;
+
+ providerRequest->NdisRequest.DATA.SET_INFORMATION.InformationBufferLength =
+ sizeof(NDIS_TAPI_PROVIDER_SHUTDOWN);
+
+
+ providerRequest->Provider = Provider;
+
+ providerRequest->Data[0] = 0; // request ID, 0 = driver-initiated req
+
+
+ //
+ // Send the request
+ //
+
+ ndisStatus = (*Provider->RequestProc)(
+ Provider->ProviderHandle,
+ (PNDIS_REQUEST) providerRequest
+ );
+
+
+ //
+ // If request was completed synchronously then free the request
+ // (otherwise it will get freed when the completion proc is called)
+ //
+
+ if (ndisStatus != NDIS_STATUS_PENDING)
+ {
+ ExFreePool (providerRequest);
+ }
+
+
+ DBGOUT ((2, "SendProviderShutdown: exit"));
+
+ return ndisStatus;
+}
+
+
+BOOLEAN
+SyncInitAllProviders(
+ void
+ )
+
+/*++
+
+Routine Description:
+
+ This functions walks the list of registered providers and sends
+ init requests to the providers in the PENDING_INIT state
+
+Arguments:
+
+ (none)
+
+Return Value:
+
+ TRUE if all registered providers initialized, or
+ FALSE if there are more providers to initialze
+
+Note:
+
+ Assumes DeviceExtension->SpinLock held by caller
+
+--*/
+
+{
+ ULONG numDevices = 0;
+ NDIS_STATUS ndisStatus;
+ PPROVIDER_INFO provider = DeviceExtension->Providers;
+
+
+ DBGOUT((2, "SyncInitAllProviders: enter"));
+
+
+ while (provider != NULL)
+ {
+ if (provider->Status == PROVIDER_STATUS_PENDING_INIT)
+ {
+ ndisStatus = SendProviderInitRequest (provider);
+
+ if (ndisStatus == NDIS_STATUS_PENDING)
+ {
+ //
+ // Wait for completion routine to get called
+ //
+
+ KeWaitForSingleObject (&DeviceExtension->SyncEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ (PTIME) NULL
+ );
+ }
+ else if (ndisStatus == NDIS_STATUS_SUCCESS)
+ {
+ provider->Status == PROVIDER_STATUS_ONLINE;
+ }
+ else
+ {
+ provider->Status == PROVIDER_STATUS_OFFLINE;
+ }
+ }
+
+ provider = provider->Next;
+ }
+
+
+ //
+ // If here all providers (>= 1) initialized, so determine the total
+ // # of line devices currently in the list
+ //
+
+ provider = DeviceExtension->Providers;
+
+ while (provider != NULL)
+ {
+ numDevices += provider->NumDevices;
+
+ provider = provider->Next;
+ }
+
+ if (DeviceExtension->Status == NDISTAPI_STATUS_CONNECTING)
+ {
+ DeviceExtension->NdisTapiNumDevices = numDevices;
+ }
+ else if ((DeviceExtension->Status == NDISTAPI_STATUS_CONNECTED) &&
+ (numDevices > DeviceExtension->NdisTapiNumDevices))
+ {
+ // PnP: need to send TAPI a reinit msg (or LINE_CREATE?)
+
+ DBGOUT((1, "SyncInitAllProviders: exceeded numDevs, must reinit"));
+ }
+
+
+ DBGOUT((2, "SyncInitAllProviders: exit"));
+
+ return TRUE;
+}
diff --git a/private/ntos/ndis/ndistapi/ndistapi.rc b/private/ntos/ndis/ndistapi/ndistapi.rc
new file mode 100644
index 000000000..a0f75325a
--- /dev/null
+++ b/private/ntos/ndis/ndistapi/ndistapi.rc
@@ -0,0 +1,38 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "NDIS 3.0 connection wrapper driver"
+#define VER_INTERNALNAME_STR "NDISTAPI.SYS"
+#define VER_ORIGINALFILENAME_STR "NDISTAPI.SYS"
+
+#include "common.ver"
diff --git a/private/ntos/ndis/ndistapi/ndistapi.src b/private/ntos/ndis/ndistapi/ndistapi.src
new file mode 100644
index 000000000..3a071870e
--- /dev/null
+++ b/private/ntos/ndis/ndistapi/ndistapi.src
@@ -0,0 +1,7 @@
+NAME NDISTAPI.SYS
+DESCRIPTION 'NDISTAPI.SYS'
+EXPORTS
+ NdisTapiRegisterProvider
+ NdisTapiCompleteRequest
+ NdisTapiIndicateStatus
+ NdisTapiDeregisterProvider
diff --git a/private/ntos/ndis/ndistapi/private.h b/private/ntos/ndis/ndistapi/private.h
new file mode 100644
index 000000000..5129f0ac5
--- /dev/null
+++ b/private/ntos/ndis/ndistapi/private.h
@@ -0,0 +1,251 @@
+/*++ BUILD Version: 0000 // Increment this if a change has global effects
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ private.h
+
+Abstract:
+
+ Private definitions for NdisTapi.sys
+
+Author:
+
+ Dan Knudson (DanKn) 20-Feb-1994
+
+Revision History:
+
+--*/
+
+
+//
+// Various definitions
+//
+
+typedef enum _PROVIDER_STATUS
+{
+ PROVIDER_STATUS_ONLINE,
+ PROVIDER_STATUS_OFFLINE,
+ PROVIDER_STATUS_PENDING_INIT
+
+} PROVIDER_STATUS, *PPROVIDER_STATUS;
+
+
+typedef NDIS_STATUS (*REQUEST_PROC)(NDIS_HANDLE, PNDIS_REQUEST);
+
+
+typedef struct _PROVIDER_INFO
+{
+ PROVIDER_STATUS Status;
+
+ NDIS_HANDLE ProviderHandle;
+
+ REQUEST_PROC RequestProc;
+
+ ULONG ProviderID;
+
+ ULONG NumDevices;
+
+ ULONG DeviceIDBase;
+
+ struct _PROVIDER_INFO *Next;
+
+} PROVIDER_INFO, *PPROVIDER_INFO;
+
+
+typedef enum _NDISTAPI_STATUS
+{
+ NDISTAPI_STATUS_CONNECTED,
+ NDISTAPI_STATUS_DISCONNECTED,
+ NDISTAPI_STATUS_CONNECTING,
+ NDISTAPI_STATUS_DISCONNECTING
+
+} NDISTAPI_STATUS, *PNDISTAPI_STATUS;
+
+
+typedef struct _DEVICE_EXTENSION
+{
+ //
+ // The following are set only in DriverEntry and are not
+ // modified elsewhere
+ //
+
+ //
+ // Pointer to the NdisTapi device object
+ //
+
+ PDEVICE_OBJECT DeviceObject;
+
+ //
+ // Length in bytes of the event data buf
+ //
+
+ ULONG EventDataQueueLength;
+
+ //
+ // Pointer to a circular event data buf
+ //
+
+ PCHAR EventData;
+
+
+
+ //
+ // Synchronizes access to the device extension following fields
+ //
+
+ KSPIN_LOCK SpinLock;
+
+ //
+ // Whether TAPI has the the connection wrapper open
+ //
+
+ NDISTAPI_STATUS Status;
+
+ //
+ // Event we use for synchronizing provider inits
+ //
+
+ KEVENT SyncEvent;
+
+ //
+ // The connection wrapper's device ID base as passed down by TAPI
+ // when it connected.
+ //
+
+ ULONG NdisTapiDeviceIDBase;
+
+ //
+ // The number of line devices we told told TAPI we supported when
+ // it opened us (some of which may not actually be online at any
+ // given time)
+ //
+
+ ULONG NdisTapiNumDevices;
+
+ //
+ // Whether we have an outstanding provider init request
+ //
+
+ BOOLEAN ProviderInitPending;
+
+ //
+ // Pointer to a list of registered providers. (Some may actually
+ // not be currently registered, but they were at one point so we've
+ // saved a placeholder for them should they come back online at some
+ // point.)
+ //
+
+ PPROVIDER_INFO Providers;
+
+ //
+ //
+ //
+
+ BOOLEAN CleanupWasInitiated;
+
+ //
+ // A special queue for QUERY/SET_INFO requests
+ //
+
+ KDEVICE_QUEUE DeviceQueue;
+
+
+
+ //
+ // Synchronizes access to the events buffer & related fields
+ //
+
+ KSPIN_LOCK EventSpinLock;
+
+ //
+ // Value return to provider for next NEWCALL msg
+ //
+
+ ULONG htCall;
+
+ //
+ // Outstanding get-events request
+ //
+
+ PIRP EventsRequestIrp;
+
+ //
+ // Pointer to next place to PUT event data (from provider)
+ //
+
+ PCHAR DataIn;
+
+ //
+ // Pointer to next place to GET event data (for user-mode request)
+ //
+
+ PCHAR DataOut;
+
+ //
+ // Number of valid events in queue
+ //
+
+ ULONG EventCount;
+
+
+ //
+ //
+ //
+
+ PFILE_OBJECT TapiSrvFileObject;
+
+ //
+ //
+ //
+
+ PFILE_OBJECT NCPAFileObject;
+
+} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
+
+
+typedef struct _PROVIDER_REQUEST
+{
+ NDIS_REQUEST NdisRequest;
+
+ PPROVIDER_INFO Provider;
+
+ //
+ // This field is a placeholder for an NDIS_TAPI_XXX structure, the
+ // first ULONG of which is always a request ID.
+ //
+
+ ULONG Data[1];
+
+} PROVIDER_REQUEST, *PPROVIDER_REQUEST;
+
+
+//
+// Our global device extension
+//
+
+PDEVICE_EXTENSION DeviceExtension;
+
+
+
+#if DBG
+
+//
+// A var which determines the verboseness of the msgs printed by DBGOUT()
+//
+//
+
+ULONG NdisTapiDebugLevel = 0;
+
+//
+// DbgPrint wrapper
+//
+
+#define DBGOUT(arg) DbgPrt arg
+
+#else
+
+#define DBGOUT(arg)
+
+#endif
diff --git a/private/ntos/ndis/ndistapi/sources b/private/ntos/ndis/ndistapi/sources
new file mode 100644
index 000000000..7d876fe2c
--- /dev/null
+++ b/private/ntos/ndis/ndistapi/sources
@@ -0,0 +1,40 @@
+!IF 0
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ John Rogers (JohnRo) 25-Oct-1991
+
+NOTE: Commented description of this file is in \nt\public\oak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=ndistapi
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=EXPORT_DRIVER
+
+INCLUDES=..\..\inc
+C_DEFINES= $(C_DEFINES)
+
+SOURCES=ndistapi.c \
+ ndistapi.rc
+
+DLLDEF=obj\*\ndistapi.def
+
+MSC_WARNING_LEVEL=/W3 /WX
diff --git a/private/ntos/ndis/ndiswan/adapter.h b/private/ntos/ndis/ndiswan/adapter.h
new file mode 100644
index 000000000..17d0cc1ab
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/adapter.h
@@ -0,0 +1,132 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ Adapter.h
+
+Abstract:
+
+ This file contains major data structures used by the NdisWan driver
+
+Author:
+
+ Tony Bell (TonyBe) June 06, 1995
+
+Environment:
+
+ Kernel Mode
+
+Revision History:
+
+ TonyBe 06/06/95 Created
+
+--*/
+
+#ifndef _NDISWAN_ADAPTER_
+#define _NDISWAN_ADAPTER_
+
+//
+// This is the control block for the NdisWan adapter that is created by the NDIS Wrapper
+// making a call to NdisWanInitialize. There should only be one call to initialize and
+// therefore only one adapter created.
+//
+typedef struct _ADAPTERCB {
+ LIST_ENTRY Linkage; // Used to link adapter into global list
+ ULONG ulAllocationSize; // Size of memory allocated
+ NDIS_SPIN_LOCK Lock; // Structure access lock
+ ULONG ulReferenceCount; // Adapter reference count
+ NDIS_HANDLE hMiniportHandle; // Assigned in MiniportInitialize
+#define RESET_IN_PROGRESS 0x00000001
+#define ASK_FOR_RESET 0x00000002
+#define MINIPORT_LOCK_OWNER 0x00000004
+
+#ifdef USE_NDIS_MINIPORT_CALLBACK
+#define DEFERRED_CALLBACK_SET 0x00000008
+#else // end of USE_NDIS_MINIPORT_CALLBACK
+#define DEFERRED_TIMER_SET 0x00000008
+#endif // end of !USE_NDIS_MINIPORT_CALLBACK
+
+#define RECEIVE_COMPLETE 0x00000010
+ ULONG Flags;
+
+#ifdef USE_NDIS_MINIPORT_LOCKING
+ NDIS_HANDLE SwitchHandle;
+#else // end of USE_NDIS_MINIPORT_LOCKING
+ WAN_IRQL MiniportLockIrql;
+ WAN_IRQL SavedIrql;
+#endif // end of !USE_NDIS_MINIPORT_LOCKING
+
+ DEFERRED_QUEUE FreeDeferredQueue;
+ DEFERRED_QUEUE DeferredQueue[MAX_DEFERRED_QUEUE_TYPES];
+
+#ifndef USE_NDIS_MINIPORT_CALLBACK
+ NDIS_MINIPORT_TIMER DeferredTimer;
+#endif // end of !USE_NDIS_MINIPORT_CALLBACK
+
+ NDIS_MEDIUM MediumType; // Medium type that we are emulating
+ NDIS_HARDWARE_STATUS HardwareStatus; // Hardware status (????)
+ NDIS_STRING AdapterName; // Adapter Name (????)
+ UCHAR NetworkAddress[ETH_LENGTH_OF_ADDRESS]; // Ethernet address for this adapter
+ ULONG ulNumberofProtocols;
+ USHORT ProtocolType;
+ struct _BUNDLECB *NbfBundleCB;
+ NDIS_HANDLE NbfProtocolHandle;
+#if DBG
+ LIST_ENTRY DbgNdisPacketList;
+#endif
+} ADAPTERCB, *PADAPTERCB;
+
+//
+// This is the control block for each WAN Miniport adapter that NdisWan binds to through
+// the NDIS Wrapper as a "protocol".
+//
+typedef struct _WAN_ADAPTERCB {
+ LIST_ENTRY Linkage; // Used to link adapter into global list
+ ULONG ulAllocationSize; // Size of memory allocated
+ NDIS_SPIN_LOCK Lock; // Structure access lock
+ LIST_ENTRY FreeLinkCBList; // Free pool of link control blocks for this WAN Miniport
+ NDIS_HANDLE hNdisBindingHandle; // Binding handle
+ NDIS_STRING MiniportName; // WAN Miniport name
+ NDIS_MEDIUM MediumType; // WAN Miniport medium type
+ NDIS_WAN_MEDIUM_SUBTYPE MediumSubType; // WAN Miniport medium subtype
+ NDIS_WAN_HEADER_FORMAT WanHeaderFormat; // WAN Miniport header type
+ WAN_EVENT NotificationEvent; // Async notification event for adapter operations (open, close, ...)
+ NDIS_STATUS NotificationStatus; // Notification status for async adapter events
+ PWAN_REQUEST pWanRequest; // 1st entry on WanRequest queue
+ PWAN_REQUEST pLastWanRequest; // Last entry on WanRequest queue
+ NDIS_WAN_INFO WanInfo; // WanInfo structure
+#if DBG
+ LIST_ENTRY DbgWanPacketList;
+#endif
+} WAN_ADAPTERCB, *PWAN_ADAPTERCB;
+
+//
+// Main control block for all global data
+//
+typedef struct _NDISWANCB {
+ NDIS_SPIN_LOCK Lock; // Structure access lock
+ NDIS_HANDLE hNdisWrapperHandle; // NDIS Wrapper handle
+ NDIS_HANDLE hProtocolHandle; // Our protocol handle
+ ULONG ulNumberOfProtocols; // Total number of protocols that we are bound to
+ ULONG ulNumberOfLinks; // Total number of links for all WAN Miniport Adapters
+ ULONG ulMinFragmentSize; // Minimum fragment size
+ ULONG ulTraceLevel; // Trace Level values 0 - 10 (10 verbose)
+ ULONG ulTraceMask; // Trace bit mask
+ PVOID pDriverObject; // Pointer to the NT Driver Object
+ PVOID pDeviceObject; // Pointer to the device object
+ ULONG SendCount;
+ ULONG SendCompleteCount;
+ ULONG IORecvError1;
+ ULONG IORecvError2;
+ PADAPTERCB PromiscuousAdapter;
+ NDIS_MINIPORT_TIMER RecvFlushTimer;
+
+#ifdef NT
+ PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION+1]; // Device dispatch functions
+#endif
+
+}NDISWANCB, *PNDISWANCB;
+
+#endif // _NDISWAN_ADAPTER_
diff --git a/private/ntos/ndis/ndiswan/ccp.c b/private/ntos/ndis/ndiswan/ccp.c
new file mode 100644
index 000000000..645e01884
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/ccp.c
@@ -0,0 +1,456 @@
+/*++
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ ccp.c
+
+Abstract:
+
+
+Author:
+
+ Thomas J. Dimitri (TommyD) 29-March-1994
+
+Environment:
+
+Revision History:
+
+
+--*/
+
+#include "wan.h"
+
+#include <rc4.h>
+#include "compress.h"
+#include "tcpip.h"
+#include "vjslip.h"
+
+//
+// Assumes the endpoint lock is held
+//
+VOID
+WanDeallocateCCP(
+ PBUNDLECB BundleCB
+ )
+{
+ ULONG CompressSend;
+ ULONG CompressRecv;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_CCP, ("WanDeallocateCCP: Enter"));
+
+ //
+ // Deallocate encryption keys.
+ //
+ if (BundleCB->SendRC4Key) {
+ NdisWanFreeMemory(BundleCB->SendRC4Key);
+
+ //
+ // Clear so we know it is deallocated
+ //
+ BundleCB->SendRC4Key= NULL;
+ }
+ if (BundleCB->SendEncryptInfo.Context) {
+ NdisWanFreeMemory(BundleCB->SendEncryptInfo.Context);
+
+ BundleCB->SendEncryptInfo.Context = NULL;
+ }
+
+ if (BundleCB->RecvRC4Key) {
+ NdisWanFreeMemory(BundleCB->RecvRC4Key);
+
+ //
+ // Clear it so we know it is deallocated
+ //
+ BundleCB->RecvRC4Key= NULL;
+ }
+ if (BundleCB->RecvEncryptInfo.Context) {
+ NdisWanFreeMemory(BundleCB->RecvEncryptInfo.Context);
+
+ BundleCB->RecvEncryptInfo.Context = NULL;
+ }
+
+
+ //
+ // Get compression context sizes
+ //
+ getcontextsizes (&CompressSend, &CompressRecv);
+
+ //
+ // Deallocate compression send/recv buffers
+ //
+ if (BundleCB->SendCompressContext) {
+ NdisWanFreeMemory(BundleCB->SendCompressContext);
+
+ BundleCB->SendCompressContext= NULL;
+ }
+
+ if (BundleCB->RecvCompressContext) {
+ NdisWanFreeMemory(BundleCB->RecvCompressContext);
+
+ BundleCB->RecvCompressContext= NULL;
+ }
+
+ //
+ // Any VJ header compression
+ //
+ if (BundleCB->VJCompress) {
+ NdisWanFreeMemory(BundleCB->VJCompress);
+
+ BundleCB->VJCompress = NULL;
+ }
+
+ //
+ // Turn off any compression/encryption
+ //
+ BundleCB->SendCompInfo.MSCompType =
+ BundleCB->RecvCompInfo.MSCompType = 0;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_CCP, ("WanDeallocateCCP: Exit"));
+}
+
+
+//
+// Assumes the endpoint lock is held
+//
+NTSTATUS
+WanAllocateCCP(
+ PBUNDLECB BundleCB
+ )
+{
+ ULONG CompressSend;
+ ULONG CompressRecv;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_CCP, ("WanAllocateCCP: Enter"));
+
+ //
+ // Reset all counters regardless
+ //
+ BundleCB->SCoherencyCounter =
+ BundleCB->RCoherencyCounter =
+ BundleCB->LastRC4Reset=
+ BundleCB->CCPIdentifier = 0;
+
+ //
+ // Is encryption enabled?
+ //
+#ifdef ENCRYPT_128BIT
+ if ((BundleCB->SendCompInfo.MSCompType &
+ (NDISWAN_ENCRYPTION | NDISWAN_40_ENCRYPTION | NDISWAN_128_ENCRYPTION))) {
+#else
+ if ((BundleCB->SendCompInfo.MSCompType &
+ (NDISWAN_ENCRYPTION | NDISWAN_40_ENCRYPTION))) {
+#endif
+
+ if (BundleCB->SendRC4Key == NULL) {
+ NdisWanAllocateMemory(&BundleCB->SendRC4Key, sizeof(struct RC4_KEYSTRUCT));
+
+ //
+ // If we can't allocate memory the machine is toast.
+ // Forget about freeing anything up.
+ //
+
+ if (BundleCB->SendRC4Key == NULL) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_CCP, ("Can't allocate encryption key!"));
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+ }
+
+ if (BundleCB->SendCompInfo.MSCompType & NDISWAN_ENCRYPTION) {
+
+ //
+ // For legacy encryption we use the 8 byte LMSessionKey
+ // for initiali encryption session key. The first 256
+ // packets will be sent using this without any salt
+ // (the first 256 packets are using 64 bit encryption).
+ // After the first 256 we will always salt the first 3
+ // bytes of the encryption key so that we are doing 40
+ // bit encryption.
+ //
+ BundleCB->SendEncryptInfo.SessionKeyLength = MAX_SESSIONKEY_SIZE;
+
+ NdisMoveMemory(BundleCB->SendEncryptInfo.StartKey,
+ BundleCB->SendCompInfo.LMSessionKey,
+ BundleCB->SendEncryptInfo.SessionKeyLength);
+
+ NdisMoveMemory(BundleCB->SendEncryptInfo.SessionKey,
+ BundleCB->SendEncryptInfo.StartKey,
+ BundleCB->SendEncryptInfo.SessionKeyLength);
+
+#if DBG
+ DbgPrint("NDISWAN: Send using legacy 40 bit encryption\n");
+#endif
+
+ } else if (BundleCB->SendCompInfo.MSCompType & NDISWAN_40_ENCRYPTION) {
+
+ if (NDIS_STATUS_SUCCESS != InitSHAContext(&BundleCB->SendEncryptInfo)) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_CCP, ("Can't allocate sha encryption key!"));
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ //
+ // For our new 40 bit encryption we will use SHA on the
+ // 8 byte LMSessionKey to derive our intial 8 byte
+ // encryption session key. We will always salt the first
+ // 3 bytes so that we are doing 40 bit encryption.
+ //
+ BundleCB->SendEncryptInfo.SessionKeyLength = MAX_SESSIONKEY_SIZE;
+
+ NdisMoveMemory(BundleCB->SendEncryptInfo.StartKey,
+ BundleCB->SendCompInfo.LMSessionKey,
+ BundleCB->SendEncryptInfo.SessionKeyLength);
+
+ NdisMoveMemory(BundleCB->SendEncryptInfo.SessionKey,
+ BundleCB->SendEncryptInfo.StartKey,
+ BundleCB->SendEncryptInfo.SessionKeyLength);
+
+ GetNewKeyFromSHA(&BundleCB->SendEncryptInfo);
+
+ //
+ // Salt the first 3 bytes
+ //
+ BundleCB->SendEncryptInfo.SessionKey[0] = 0xD1;
+ BundleCB->SendEncryptInfo.SessionKey[1] = 0x26;
+ BundleCB->SendEncryptInfo.SessionKey[2] = 0x9E;
+
+#if DBG
+ DbgPrint("NDISWAN: Send using new 40 bit encryption\n");
+#endif
+ }
+
+#ifdef ENCRYPT_128BIT
+ else if (BundleCB->SendCompInfo.MSCompType & NDISWAN_128_ENCRYPTION) {
+
+ if (NDIS_STATUS_SUCCESS != InitSHAContext(&BundleCB->SendEncryptInfo)) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_CCP, ("Can't allocate sha encryption key!"));
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ //
+ // For our new 128 bit encryption we will use SHA on the
+ // 16 byte NTUserSessionKey and the 8 byte Challenge to
+ // derive our the intial 128 bit encryption session key.
+ //
+ BundleCB->SendEncryptInfo.SessionKeyLength = MAX_USERSESSIONKEY_SIZE;
+ NdisMoveMemory(BundleCB->SendEncryptInfo.StartKey,
+ BundleCB->SendCompInfo.UserSessionKey,
+ BundleCB->SendEncryptInfo.SessionKeyLength);
+
+
+ GetStartKeyFromSHA(&BundleCB->SendEncryptInfo,
+ BundleCB->SendCompInfo.Challenge);
+
+ GetNewKeyFromSHA(&BundleCB->SendEncryptInfo);
+
+#if DBG
+ DbgPrint("NDISWAN: Send using 128 bit encryption\n");
+#endif
+ }
+#endif
+
+ //
+ // Initialize the rc4 send table
+ //
+ NdisWanDbgOut(DBG_TRACE, DBG_CCP,
+ ("RC4 encryption KeyLength %d", BundleCB->SendEncryptInfo.SessionKeyLength));
+ NdisWanDbgOut(DBG_TRACE, DBG_CCP,
+ ("RC4 encryption Key %.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x %.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x",
+ BundleCB->SendEncryptInfo.SessionKey[0],
+ BundleCB->SendEncryptInfo.SessionKey[1],
+ BundleCB->SendEncryptInfo.SessionKey[2],
+ BundleCB->SendEncryptInfo.SessionKey[3],
+ BundleCB->SendEncryptInfo.SessionKey[4],
+ BundleCB->SendEncryptInfo.SessionKey[5],
+ BundleCB->SendEncryptInfo.SessionKey[6],
+ BundleCB->SendEncryptInfo.SessionKey[7],
+ BundleCB->SendEncryptInfo.SessionKey[8],
+ BundleCB->SendEncryptInfo.SessionKey[9],
+ BundleCB->SendEncryptInfo.SessionKey[10],
+ BundleCB->SendEncryptInfo.SessionKey[11],
+ BundleCB->SendEncryptInfo.SessionKey[12],
+ BundleCB->SendEncryptInfo.SessionKey[13],
+ BundleCB->SendEncryptInfo.SessionKey[14],
+ BundleCB->SendEncryptInfo.SessionKey[15]));
+
+ rc4_key(
+ BundleCB->SendRC4Key,
+ BundleCB->SendEncryptInfo.SessionKeyLength,
+ BundleCB->SendEncryptInfo.SessionKey);
+ }
+
+
+#ifdef ENCRYPT_128BIT
+ if ((BundleCB->RecvCompInfo.MSCompType &
+ (NDISWAN_ENCRYPTION | NDISWAN_40_ENCRYPTION | NDISWAN_128_ENCRYPTION))) {
+#else
+ if ((BundleCB->RecvCompInfo.MSCompType &
+ (NDISWAN_ENCRYPTION | NDISWAN_40_ENCRYPTION))) {
+#endif
+
+ if (BundleCB->RecvRC4Key == NULL) {
+ NdisWanAllocateMemory(&BundleCB->RecvRC4Key, sizeof(struct RC4_KEYSTRUCT));
+
+ //
+ // If we can't allocate memory the machine is toast.
+ // Forget about freeing anything up.
+ //
+ if (BundleCB->RecvRC4Key == NULL) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_CCP, ("Can't allocate encryption key!"));
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+ }
+
+ if (BundleCB->RecvCompInfo.MSCompType & NDISWAN_ENCRYPTION) {
+ BundleCB->RecvEncryptInfo.SessionKeyLength = MAX_SESSIONKEY_SIZE;
+
+ NdisMoveMemory(BundleCB->RecvEncryptInfo.StartKey,
+ BundleCB->RecvCompInfo.LMSessionKey,
+ BundleCB->RecvEncryptInfo.SessionKeyLength);
+
+ NdisMoveMemory(BundleCB->RecvEncryptInfo.SessionKey,
+ BundleCB->RecvEncryptInfo.StartKey,
+ BundleCB->RecvEncryptInfo.SessionKeyLength);
+
+#if DBG
+ DbgPrint("NDISWAN: Recv using legacy 40 bit encryption\n");
+#endif
+ } else if (BundleCB->RecvCompInfo.MSCompType & (NDISWAN_40_ENCRYPTION)) {
+
+ if (NDIS_STATUS_SUCCESS != InitSHAContext(&BundleCB->RecvEncryptInfo)) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_CCP, ("Can't allocate sha encryption key!"));
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ BundleCB->RecvEncryptInfo.SessionKeyLength = MAX_SESSIONKEY_SIZE;
+
+ NdisMoveMemory(BundleCB->RecvEncryptInfo.StartKey,
+ BundleCB->RecvCompInfo.LMSessionKey,
+ BundleCB->RecvEncryptInfo.SessionKeyLength);
+
+ NdisMoveMemory(BundleCB->RecvEncryptInfo.SessionKey,
+ BundleCB->RecvEncryptInfo.StartKey,
+ BundleCB->RecvEncryptInfo.SessionKeyLength);
+
+ GetNewKeyFromSHA(&BundleCB->RecvEncryptInfo);
+
+ //
+ // Salt the first 3 bytes
+ //
+ BundleCB->RecvEncryptInfo.SessionKey[0] = 0xD1;
+ BundleCB->RecvEncryptInfo.SessionKey[1] = 0x26;
+ BundleCB->RecvEncryptInfo.SessionKey[2] = 0x9E;
+
+#if DBG
+ DbgPrint("NDISWAN: Recv using new 40 bit encryption\n");
+#endif
+ }
+#ifdef ENCRYPT_128BIT
+ else if (BundleCB->RecvCompInfo.MSCompType & NDISWAN_128_ENCRYPTION) {
+
+ if (NDIS_STATUS_SUCCESS != InitSHAContext(&BundleCB->RecvEncryptInfo)) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_CCP, ("Can't allocate sha encryption key!"));
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ BundleCB->RecvEncryptInfo.SessionKeyLength = MAX_USERSESSIONKEY_SIZE;
+ NdisMoveMemory(BundleCB->RecvEncryptInfo.StartKey,
+ BundleCB->RecvCompInfo.UserSessionKey,
+ BundleCB->RecvEncryptInfo.SessionKeyLength);
+
+ GetStartKeyFromSHA(&BundleCB->RecvEncryptInfo,
+ BundleCB->RecvCompInfo.Challenge);
+
+ GetNewKeyFromSHA(&BundleCB->RecvEncryptInfo);
+
+#if DBG
+ DbgPrint("NDISWAN: Recv using 128 bit encryption\n");
+#endif
+ }
+#endif
+
+ //
+ // Initialize the rc4 receive table
+ //
+ NdisWanDbgOut(DBG_TRACE, DBG_CCP,
+ ("RC4 encryption KeyLength %d", BundleCB->RecvEncryptInfo.SessionKeyLength));
+ NdisWanDbgOut(DBG_TRACE, DBG_CCP,
+ ("RC4 encryption Key %.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x",
+ BundleCB->RecvEncryptInfo.SessionKey[0],
+ BundleCB->RecvEncryptInfo.SessionKey[1],
+ BundleCB->RecvEncryptInfo.SessionKey[2],
+ BundleCB->RecvEncryptInfo.SessionKey[3],
+ BundleCB->RecvEncryptInfo.SessionKey[4],
+ BundleCB->RecvEncryptInfo.SessionKey[5],
+ BundleCB->RecvEncryptInfo.SessionKey[6],
+ BundleCB->RecvEncryptInfo.SessionKey[7],
+ BundleCB->RecvEncryptInfo.SessionKey[8],
+ BundleCB->RecvEncryptInfo.SessionKey[9],
+ BundleCB->RecvEncryptInfo.SessionKey[10],
+ BundleCB->RecvEncryptInfo.SessionKey[11],
+ BundleCB->RecvEncryptInfo.SessionKey[12],
+ BundleCB->RecvEncryptInfo.SessionKey[13],
+ BundleCB->RecvEncryptInfo.SessionKey[14],
+ BundleCB->RecvEncryptInfo.SessionKey[15]));
+
+ rc4_key(
+ BundleCB->RecvRC4Key,
+ BundleCB->RecvEncryptInfo.SessionKeyLength,
+ BundleCB->RecvEncryptInfo.SessionKey);
+ }
+
+ //
+ // Get compression context sizes
+ //
+ getcontextsizes (&CompressSend, &CompressRecv);
+
+ if (BundleCB->SendCompInfo.MSCompType & NDISWAN_COMPRESSION) {
+
+ if (BundleCB->SendCompressContext == NULL) {
+ NdisWanAllocateMemory(&BundleCB->SendCompressContext, CompressSend);
+ //
+ // If we can't allocate memory the machine is toast.
+ // Forget about freeing anything up.
+ //
+ if (BundleCB->SendCompressContext == NULL) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_CCP, ("Can't allocate compression!"));
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ }
+
+ //
+ // Initialize the compression history table and tree
+ //
+ initsendcontext (BundleCB->SendCompressContext);
+ }
+
+ if (BundleCB->RecvCompInfo.MSCompType & NDISWAN_COMPRESSION) {
+
+ if (BundleCB->RecvCompressContext == NULL) {
+ NdisWanAllocateMemory(&BundleCB->RecvCompressContext, CompressRecv);
+
+ //
+ // If we can't allocate memory the machine is toast.
+ // Forget about freeing anything up.
+ //
+ if (BundleCB->RecvCompressContext == NULL) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_CCP, ("Can't allocate decompression"));
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+ }
+
+ //
+ // Initialize the decompression history table
+ //
+ initrecvcontext (BundleCB->RecvCompressContext);
+ }
+
+ //
+ // Next packet out is flushed
+ //
+ BundleCB->Flags |= RECV_PACKET_FLUSH;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_CCP, ("WanAllocateCCP: Exit"));
+ return(STATUS_SUCCESS);
+}
diff --git a/private/ntos/ndis/ndiswan/compress.c b/private/ntos/ndis/ndiswan/compress.c
new file mode 100644
index 000000000..141da0929
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/compress.c
@@ -0,0 +1,1689 @@
+//************************************************************************
+// Microsoft Corporation
+// Copyright(c) Microsoft Corp., 1990-1992
+//
+//
+// Revision history:
+// 5/5/94 Created gurdeep
+//
+//************************************************************************
+
+//#define COMP_12K
+
+#include "wan.h"
+#include "compress.h"
+
+
+//#define DEBUG
+
+unsigned long lookup_array1[256] = {
+ 0, 10276755, 20553510, 30830265,
+ 41107020, 51383775, 61660530, 71937285,
+ 82214040, 92490795, 102767550, 113044305,
+ 123321060, 133597815, 143874570, 154151325,
+ 164428080, 174704835, 184981590, 195258345,
+ 205535100, 215811855, 226088610, 236365365,
+ 246642120, 256918875, 267195630, 277472385,
+ 287749140, 298025895, 308302650, 318579405,
+ 328856160, 339132915, 349409670, 359686425,
+ 369963180, 380239935, 390516690, 400793445,
+ 411070200, 421346955, 431623710, 441900465,
+ 452177220, 462453975, 472730730, 483007485,
+ 493284240, 503560995, 513837750, 524114505,
+ 534391260, 544668015, 554944770, 565221525,
+ 575498280, 585775035, 596051790, 606328545,
+ 616605300, 626882055, 637158810, 647435565,
+ 657712320, 667989075, 678265830, 688542585,
+ 698819340, 709096095, 719372850, 729649605,
+ 739926360, 750203115, 760479870, 770756625,
+ 781033380, 791310135, 801586890, 811863645,
+ 822140400, 832417155, 842693910, 852970665,
+ 863247420, 873524175, 883800930, 894077685,
+ 904354440, 914631195, 924907950, 935184705,
+ 945461460, 955738215, 966014970, 976291725,
+ 986568480, 996845235, 1007121990, 1017398745,
+ 1027675500, 1037952255, 1048229010, 1058505765,
+ 1068782520, 1079059275, 1089336030, 1099612785,
+ 1109889540, 1120166295, 1130443050, 1140719805,
+ 1150996560, 1161273315, 1171550070, 1181826825,
+ 1192103580, 1202380335, 1212657090, 1222933845,
+ 1233210600, 1243487355, 1253764110, 1264040865,
+ 1274317620, 1284594375, 1294871130, 1305147885,
+ 1315424640, 1325701395, 1335978150, 1346254905,
+ 1356531660, 1366808415, 1377085170, 1387361925,
+ 1397638680, 1407915435, 1418192190, 1428468945,
+ 1438745700, 1449022455, 1459299210, 1469575965,
+ 1479852720, 1490129475, 1500406230, 1510682985,
+ 1520959740, 1531236495, 1541513250, 1551790005,
+ 1562066760, 1572343515, 1582620270, 1592897025,
+ 1603173780, 1613450535, 1623727290, 1634004045,
+ 1644280800, 1654557555, 1664834310, 1675111065,
+ 1685387820, 1695664575, 1705941330, 1716218085,
+ 1726494840, 1736771595, 1747048350, 1757325105,
+ 1767601860, 1777878615, 1788155370, 1798432125,
+ 1808708880, 1818985635, 1829262390, 1839539145,
+ 1849815900, 1860092655, 1870369410, 1880646165,
+ 1890922920, 1901199675, 1911476430, 1921753185,
+ 1932029940, 1942306695, 1952583450, 1962860205,
+ 1973136960, 1983413715, 1993690470, 2003967225,
+ 2014243980, 2024520735, 2034797490, 2045074245,
+ 2055351000, 2065627755, 2075904510, 2086181265,
+ 2096458020, 2106734775, 2117011530, 2127288285,
+ 2137565040, 2147841795, 2158118550, 2168395305,
+ 2178672060, 2188948815, 2199225570, 2209502325,
+ 2219779080, 2230055835, 2240332590, 2250609345,
+ 2260886100, 2271162855, 2281439610, 2291716365,
+ 2301993120, 2312269875, 2322546630, 2332823385,
+ 2343100140, 2353376895, 2363653650, 2373930405,
+ 2384207160, 2394483915, 2404760670, 2415037425,
+ 2425314180, 2435590935, 2445867690, 2456144445,
+ 2466421200, 2476697955, 2486974710, 2497251465,
+ 2507528220, 2517804975, 2528081730, 2538358485,
+ 2548635240, 2558911995, 2569188750, 2579465505,
+ 2589742260, 2600019015, 2610295770, 2620572525
+};
+
+/*
+ for i = 0 to 255,
+ lookup_array2[i] = lookup_array1[i] << 8;
+*/
+unsigned long lookup_array2[256] = {
+ 0, 2630849280, 966731264, 3597580544,
+ 1933462528, 269344512, 2900193792, 1236075776,
+ 3866925056, 2202807040, 538689024, 3169538304,
+ 1505420288, 4136269568, 2472151552, 808033536,
+ 3438882816, 1774764800, 110646784, 2741496064,
+ 1077378048, 3708227328, 2044109312, 379991296,
+ 3010840576, 1346722560, 3977571840, 2313453824,
+ 649335808, 3280185088, 1616067072, 4246916352,
+ 2582798336, 918680320, 3549529600, 1885411584,
+ 221293568, 2852142848, 1188024832, 3818874112,
+ 2154756096, 490638080, 3121487360, 1457369344,
+ 4088218624, 2424100608, 759982592, 3390831872,
+ 1726713856, 62595840, 2693445120, 1029327104,
+ 3660176384, 1996058368, 331940352, 2962789632,
+ 1298671616, 3929520896, 2265402880, 601284864,
+ 3232134144, 1568016128, 4198865408, 2534747392,
+ 870629376, 3501478656, 1837360640, 173242624,
+ 2804091904, 1139973888, 3770823168, 2106705152,
+ 442587136, 3073436416, 1409318400, 4040167680,
+ 2376049664, 711931648, 3342780928, 1678662912,
+ 14544896, 2645394176, 981276160, 3612125440,
+ 1948007424, 283889408, 2914738688, 1250620672,
+ 3881469952, 2217351936, 553233920, 3184083200,
+ 1519965184, 4150814464, 2486696448, 822578432,
+ 3453427712, 1789309696, 125191680, 2756040960,
+ 1091922944, 3722772224, 2058654208, 394536192,
+ 3025385472, 1361267456, 3992116736, 2327998720,
+ 663880704, 3294729984, 1630611968, 4261461248,
+ 2597343232, 933225216, 3564074496, 1899956480,
+ 235838464, 2866687744, 1202569728, 3833419008,
+ 2169300992, 505182976, 3136032256, 1471914240,
+ 4102763520, 2438645504, 774527488, 3405376768,
+ 1741258752, 77140736, 2707990016, 1043872000,
+ 3674721280, 2010603264, 346485248, 2977334528,
+ 1313216512, 3944065792, 2279947776, 615829760,
+ 3246679040, 1582561024, 4213410304, 2549292288,
+ 885174272, 3516023552, 1851905536, 187787520,
+ 2818636800, 1154518784, 3785368064, 2121250048,
+ 457132032, 3087981312, 1423863296, 4054712576,
+ 2390594560, 726476544, 3357325824, 1693207808,
+ 29089792, 2659939072, 995821056, 3626670336,
+ 1962552320, 298434304, 2929283584, 1265165568,
+ 3896014848, 2231896832, 567778816, 3198628096,
+ 1534510080, 4165359360, 2501241344, 837123328,
+ 3467972608, 1803854592, 139736576, 2770585856,
+ 1106467840, 3737317120, 2073199104, 409081088,
+ 3039930368, 1375812352, 4006661632, 2342543616,
+ 678425600, 3309274880, 1645156864, 4276006144,
+ 2611888128, 947770112, 3578619392, 1914501376,
+ 250383360, 2881232640, 1217114624, 3847963904,
+ 2183845888, 519727872, 3150577152, 1486459136,
+ 4117308416, 2453190400, 789072384, 3419921664,
+ 1755803648, 91685632, 2722534912, 1058416896,
+ 3689266176, 2025148160, 361030144, 2991879424,
+ 1327761408, 3958610688, 2294492672, 630374656,
+ 3261223936, 1597105920, 4227955200, 2563837184,
+ 899719168, 3530568448, 1866450432, 202332416,
+ 2833181696, 1169063680, 3799912960, 2135794944,
+ 471676928, 3102526208, 1438408192, 4069257472,
+ 2405139456, 741021440, 3371870720, 1707752704,
+ 43634688, 2674483968, 1010365952, 3641215232,
+ 1977097216, 312979200, 2943828480, 1279710464,
+ 3910559744, 2246441728, 582323712, 3213172992,
+ 1549054976, 4179904256, 2515786240, 851668224
+};
+
+/*
+ for i = 0 to 255,
+ lookup_array3[i] = lookup_array1[i] << 16;
+*/
+unsigned long lookup_array3[256] = {
+ 0, 3482517504, 2670067712, 1857617920,
+ 1045168128, 232718336, 3715235840, 2902786048,
+ 2090336256, 1277886464, 465436672, 3947954176,
+ 3135504384, 2323054592, 1510604800, 698155008,
+ 4180672512, 3368222720, 2555772928, 1743323136,
+ 930873344, 118423552, 3600941056, 2788491264,
+ 1976041472, 1163591680, 351141888, 3833659392,
+ 3021209600, 2208759808, 1396310016, 583860224,
+ 4066377728, 3253927936, 2441478144, 1629028352,
+ 816578560, 4128768, 3486646272, 2674196480,
+ 1861746688, 1049296896, 236847104, 3719364608,
+ 2906914816, 2094465024, 1282015232, 469565440,
+ 3952082944, 3139633152, 2327183360, 1514733568,
+ 702283776, 4184801280, 3372351488, 2559901696,
+ 1747451904, 935002112, 122552320, 3605069824,
+ 2792620032, 1980170240, 1167720448, 355270656,
+ 3837788160, 3025338368, 2212888576, 1400438784,
+ 587988992, 4070506496, 3258056704, 2445606912,
+ 1633157120, 820707328, 8257536, 3490775040,
+ 2678325248, 1865875456, 1053425664, 240975872,
+ 3723493376, 2911043584, 2098593792, 1286144000,
+ 473694208, 3956211712, 3143761920, 2331312128,
+ 1518862336, 706412544, 4188930048, 3376480256,
+ 2564030464, 1751580672, 939130880, 126681088,
+ 3609198592, 2796748800, 1984299008, 1171849216,
+ 359399424, 3841916928, 3029467136, 2217017344,
+ 1404567552, 592117760, 4074635264, 3262185472,
+ 2449735680, 1637285888, 824836096, 12386304,
+ 3494903808, 2682454016, 1870004224, 1057554432,
+ 245104640, 3727622144, 2915172352, 2102722560,
+ 1290272768, 477822976, 3960340480, 3147890688,
+ 2335440896, 1522991104, 710541312, 4193058816,
+ 3380609024, 2568159232, 1755709440, 943259648,
+ 130809856, 3613327360, 2800877568, 1988427776,
+ 1175977984, 363528192, 3846045696, 3033595904,
+ 2221146112, 1408696320, 596246528, 4078764032,
+ 3266314240, 2453864448, 1641414656, 828964864,
+ 16515072, 3499032576, 2686582784, 1874132992,
+ 1061683200, 249233408, 3731750912, 2919301120,
+ 2106851328, 1294401536, 481951744, 3964469248,
+ 3152019456, 2339569664, 1527119872, 714670080,
+ 4197187584, 3384737792, 2572288000, 1759838208,
+ 947388416, 134938624, 3617456128, 2805006336,
+ 1992556544, 1180106752, 367656960, 3850174464,
+ 3037724672, 2225274880, 1412825088, 600375296,
+ 4082892800, 3270443008, 2457993216, 1645543424,
+ 833093632, 20643840, 3503161344, 2690711552,
+ 1878261760, 1065811968, 253362176, 3735879680,
+ 2923429888, 2110980096, 1298530304, 486080512,
+ 3968598016, 3156148224, 2343698432, 1531248640,
+ 718798848, 4201316352, 3388866560, 2576416768,
+ 1763966976, 951517184, 139067392, 3621584896,
+ 2809135104, 1996685312, 1184235520, 371785728,
+ 3854303232, 3041853440, 2229403648, 1416953856,
+ 604504064, 4087021568, 3274571776, 2462121984,
+ 1649672192, 837222400, 24772608, 3507290112,
+ 2694840320, 1882390528, 1069940736, 257490944,
+ 3740008448, 2927558656, 2115108864, 1302659072,
+ 490209280, 3972726784, 3160276992, 2347827200,
+ 1535377408, 722927616, 4205445120, 3392995328,
+ 2580545536, 1768095744, 955645952, 143196160,
+ 3625713664, 2813263872, 2000814080, 1188364288,
+ 375914496, 3858432000, 3045982208, 2233532416,
+ 1421082624, 608632832, 4091150336, 3278700544
+};
+
+/*
+ The key for the multiplicative hash function consists of 3 unsigned
+ characters. They are composed (logically) by concatenating them i.e.
+ the composed key = 2^16*c2 + 2^8*c2 + c3 and fits in 24 bits. The
+ composed key is not actually computed here as we use the components
+ to directly compute the hash function.
+
+ The multiplicative hash function consists of taking the higher order
+ 12 bits (2^12 = 4096) of the lower order 24 bits of the product
+ key * Multiplier where
+ Multiplier = floor(A * pow(2.0, (double) w));
+ double A = 0.6125423371; (chosen according to Knuth)
+ w = 24 (the key's width in bits)
+ The algorithm for this is in Cormen/Leiserson/Rivest.
+
+ To do the multplication efficiently, the product c*Multiplier is
+ precomputed and stored in lookup_array1 (for all 256 possible c's).
+ lookup_array2 and lookup_array3 contain the same data as lookup_array1
+ but shifted left 8 and 16 bits respectively.
+
+ MultHash1 is the mult hashing function. MultHash0 contains an older
+ (slower but less space-efficient) version of the same function.
+*/
+
+
+#define MULTHASH1(c1,c2,c3) \
+ ((lookup_array1[c1]+ \
+ lookup_array2[c2]+ \
+ lookup_array3[c3] ) & 0x00fff000) >> 12
+
+
+/*
+USHORT xorlookup1 [256] = {
+ 0x110, 0x120, 0x130, 0x140, 0x150, 0x160, 0x170, 0x180, // 0-7
+ 0x190, 0x1a0, 0x1b0, 0x1c0, 0x1d0, 0x1e0, 0x1f0, 0x100, // 8-15
+ 0x210, 0x220, 0x230, 0x240, 0x250, 0x260, 0x270, 0x280, // 16-23
+ 0x290, 0x2a0, 0x2b0, 0x2c0, 0x2d0, 0x2e0, 0x2f0, 0x200, // 24-31
+ 0x310, 0x320, 0x330, 0x340, 0x350, 0x360, 0x370, 0x380, // 32-39
+ 0x390, 0x3a0, 0x3b0, 0x3c0, 0x3d0, 0x3e0, 0x3f0, 0x300, // 40-47
+ 0x410, 0x420, 0x430, 0x440, 0x450, 0x460, 0x470, 0x480, // 48-55
+ 0x490, 0x4a0, 0x4b0, 0x4c0, 0x4d0, 0x4e0, 0x4f0, 0x400, // 56-63
+ 0x510, 0x520, 0x530, 0x540, 0x550, 0x560, 0x570, 0x580, // 64-71
+ 0x590, 0x5a0, 0x5b0, 0x5c0, 0x5d0, 0x5e0, 0x5f0, 0x500, // 72-79
+ 0x610, 0x620, 0x630, 0x640, 0x650, 0x660, 0x670, 0x680, // 80-87
+ 0x690, 0x6a0, 0x6b0, 0x6c0, 0x6d0, 0x6e0, 0x6f0, 0x600, // 88-95
+ 0x710, 0x720, 0x730, 0x740, 0x750, 0x760, 0x770, 0x780, // 96-103
+ 0x790, 0x7a0, 0x7b0, 0x7c0, 0x7d0, 0x7e0, 0x7f0, 0x700, // 104-111
+ 0x810, 0x820, 0x830, 0x840, 0x850, 0x860, 0x870, 0x880, // 112-119
+ 0x890, 0x8a0, 0x8b0, 0x8c0, 0x8d0, 0x8e0, 0x8f0, 0x800, // 120-127
+ 0x910, 0x920, 0x930, 0x940, 0x950, 0x960, 0x970, 0x980, // 128-135
+ 0x990, 0x9a0, 0x9b0, 0x9c0, 0x9d0, 0x9e0, 0x9f0, 0x900, // 136-143
+ 0xa10, 0xa20, 0xa30, 0xa40, 0xa50, 0xa60, 0xa70, 0xa80, // 144-151
+ 0xa90, 0xaa0, 0xab0, 0xac0, 0xad0, 0xae0, 0xaf0, 0xa00, // 152-159
+ 0xb10, 0xb20, 0xb30, 0xb40, 0xb50, 0xb60, 0xb70, 0xb80, // 160-167
+ 0xb90, 0xba0, 0xbb0, 0xbc0, 0xbd0, 0xbe0, 0xbf0, 0xb00, // 168-175
+ 0xc10, 0xc20, 0xc30, 0xc40, 0xc50, 0xc60, 0xc70, 0xc80, // 176-183
+ 0xc90, 0xca0, 0xcb0, 0xcc0, 0xcd0, 0xce0, 0xcf0, 0xc00, // 184-191
+ 0xd10, 0xd20, 0xd30, 0xd40, 0xd50, 0xd60, 0xd70, 0xd80, // 192-199
+ 0xd90, 0xda0, 0xdb0, 0xdc0, 0xdd0, 0xde0, 0xdf0, 0xd00, // 200-207
+ 0xe10, 0xe20, 0xe30, 0xe40, 0xe50, 0xe60, 0xe70, 0xe80, // 208-215
+ 0xe90, 0xea0, 0xeb0, 0xec0, 0xed0, 0xee0, 0xef0, 0xe00, // 216-223
+ 0xf10, 0xf20, 0xf30, 0xf40, 0xf50, 0xf60, 0xf70, 0xf80, // 224-231
+ 0xf90, 0xfa0, 0xfb0, 0xfc0, 0xfd0, 0xfe0, 0xff0, 0xf00, // 232-239
+ 0x010, 0x020, 0x030, 0x040, 0x050, 0x060, 0x070, 0x080, // 240-247
+ 0x090, 0x0a0, 0x0b0, 0x0c0, 0x0d0, 0x0e0, 0x0f0, 0x000 }; // 248-255
+
+
+USHORT xorlookup2 [256] = {
+ 0x101, 0x201, 0x301, 0x401, 0x501, 0x601, 0x701, 0x801, // 0-7
+ 0x901, 0xa01, 0xb01, 0xc01, 0xd01, 0xe01, 0xf01, 0x001, // 8-15
+ 0x102, 0x202, 0x302, 0x402, 0x502, 0x602, 0x702, 0x802, // 16-23
+ 0x902, 0xa02, 0xb02, 0xc02, 0xd02, 0xe02, 0xf02, 0x002, // 24-31
+ 0x103, 0x203, 0x303, 0x403, 0x503, 0x603, 0x703, 0x803, // 32-39
+ 0x903, 0xa03, 0xb03, 0xc03, 0xd03, 0xe03, 0xf03, 0x003, // 40-47
+ 0x104, 0x204, 0x304, 0x404, 0x504, 0x604, 0x704, 0x804, // 48-55
+ 0x904, 0xa04, 0xb04, 0xc04, 0xd04, 0xe04, 0xf04, 0x004, // 56-63
+ 0x105, 0x205, 0x305, 0x405, 0x505, 0x605, 0x705, 0x805, // 64-71
+ 0x905, 0xa05, 0xb05, 0xc05, 0xd05, 0xe05, 0xf05, 0x005, // 72-79
+ 0x106, 0x206, 0x306, 0x406, 0x506, 0x606, 0x706, 0x806, // 80-87
+ 0x906, 0xa06, 0xb06, 0xc06, 0xd06, 0xe06, 0xf06, 0x006, // 88-95
+ 0x107, 0x207, 0x307, 0x407, 0x507, 0x607, 0x707, 0x807, // 96-103
+ 0x907, 0xa07, 0xb07, 0xc07, 0xd07, 0xe07, 0xf07, 0x007, // 104-111
+ 0x108, 0x208, 0x308, 0x408, 0x508, 0x608, 0x708, 0x808, // 112-119
+ 0x908, 0xa08, 0xb08, 0xc08, 0xd08, 0xe08, 0xf08, 0x008, // 120-127
+ 0x109, 0x209, 0x309, 0x409, 0x509, 0x609, 0x709, 0x809, // 128-135
+ 0x909, 0xa09, 0xb09, 0xc09, 0xd09, 0xe09, 0xf09, 0x009, // 136-143
+ 0x10a, 0x20a, 0x30a, 0x40a, 0x50a, 0x60a, 0x70a, 0x80a, // 144-151
+ 0x90a, 0xa0a, 0xb0a, 0xc0a, 0xd0a, 0xe0a, 0xf0a, 0x00a, // 152-159
+ 0x10b, 0x20b, 0x30b, 0x40b, 0x50b, 0x60b, 0x70b, 0x80b, // 160-167
+ 0x90b, 0xa0b, 0xb0b, 0xc0b, 0xd0b, 0xe0b, 0xf0b, 0x00b, // 168-175
+ 0x10c, 0x20c, 0x30c, 0x40c, 0x50c, 0x60c, 0x70c, 0x80c, // 176-183
+ 0x90c, 0xa0c, 0xb0c, 0xc0c, 0xd0c, 0xe0c, 0xf0c, 0x00c, // 184-191
+ 0x10d, 0x20d, 0x30d, 0x40d, 0x50d, 0x60d, 0x70d, 0x80d, // 192-199
+ 0x90d, 0xa0d, 0xb0d, 0xc0d, 0xd0d, 0xe0d, 0xf0d, 0x00d, // 200-207
+ 0x10e, 0x20e, 0x30e, 0x40e, 0x50e, 0x60e, 0x70e, 0x80e, // 208-215
+ 0x90e, 0xa0e, 0xb0e, 0xc0e, 0xd0e, 0xe0e, 0xf0e, 0x00e, // 216-223
+ 0x10f, 0x20f, 0x30f, 0x40f, 0x50f, 0x60f, 0x70f, 0x80f, // 224-231
+ 0x90f, 0xa0f, 0xb0f, 0xc0f, 0xd0f, 0xe0f, 0xf0f, 0x00f, // 232-239
+ 0x000, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x800, // 240-247
+ 0x900, 0xa00, 0xb00, 0xc00, 0xd00, 0xe00, 0xf00, 0x100 }; // 248-255
+
+*/
+
+/* Bitptrs point to the current byte. The current bit (i.e. next bit to be
+ * stored) is masked off by the bit entry. When this reaches zero, it is
+ * reset to 0x80 and the next byte is set up. The bytes are filled MSBit
+ * first. */
+
+/* Starts and sets the first byte to zero for the bitptr. */
+#define bitptr_init(s) pbyte = s; byte=0; bit = 16;
+
+/* Sets up the byte part of the bitptr so that it is pointing to the byte after
+ * the byte which had the last bit put into it. */
+#define bitptr_end() if (bit != 16) *pbyte++=(UCHAR)(byte >> 8);
+
+/* Goes to the next bit, and byte if necessary. */
+#define bitptr_next() \
+ if (bit < 10) { \
+ *pbyte++=(UCHAR)(byte >> 8); \
+ byte <<= 8; \
+ bit = 16; \
+ } else \
+ bit-- ;
+
+/*
+#define bitptr_next() \
+ bit--; \
+ if (bit < 9) { \
+ *pbyte++=(UCHAR)(byte >> 8); \
+ byte <<= 8; \
+ bit = 16; \
+ }
+*/
+
+
+/* Advances to the next bit, and byte if necessary, readjusting the bit. */
+#define bitptr_advance() \
+ if (bit < 9) { \
+ *pbyte++=(UCHAR)(byte >> 8); \
+ bit+=8; \
+ byte <<= 8; \
+ }
+
+
+/* BIT I/O FUNCTIONS *********************************************************/
+
+/* These routines output most-significant-bit-first and the input will return
+ * them MSB first, too. */
+
+/* Outputs a one bit in the bit stream. */
+#define out_bit_1() bit--; byte |= (1 << bit); bitptr_advance();
+#define out_bit_0() bitptr_next();
+
+/* TestBit; output 1 if that bit is set */
+//#define tb(b,w,n) if ((w) & (n)) *pbyte |= bit; bitptr_next(b);
+
+#define out_bits_2(w) bit-=2; byte|=(w << bit); bitptr_advance();
+#define out_bits_3(w) bit-=3; byte|=(w << bit); bitptr_advance();
+#define out_bits_4(w) bit-=4; byte|=(w << bit); bitptr_advance();
+#define out_bits_5(w) bit-=5; byte|=(w << bit); bitptr_advance();
+#define out_bits_6(w) bit-=6; byte|=(w << bit); bitptr_advance();
+#define out_bits_7(w) bit-=7; byte|=(w << bit); bitptr_advance();
+
+// #define out_bits_8(w) bit-=8; byte|=(w << bit); bit+=8; *pbyte++=(UCHAR)(byte >> 8); byte <<= 8;
+#define out_bits_8(w) byte|=(w << (bit-8)); *pbyte++=(UCHAR)(byte >> 8); byte <<= 8;
+
+
+/*
+#define out_bits_9(w) \
+ if (bit > 9) { \
+ bit-=9; byte|=(w << bit); \
+ *pbyte++=(UCHAR)(byte >> 8);\
+ bit+=8; \
+ byte <<= 8; \
+ } else { \
+ bit=16; byte |= w; \
+ *pbyte++=(UCHAR)(byte >> 8); *pbyte++=(UCHAR)(byte); byte=0; \
+ }
+*/
+
+#define out_bits_9(w) \
+ if (bit > 9) { \
+ byte|=(w << (bit-9)); \
+ *pbyte++=(UCHAR)(byte >> 8);\
+ bit--; \
+ byte <<= 8; \
+ } else { \
+ bit=16; byte |= w; \
+ *pbyte++=(UCHAR)(byte >> 8); *pbyte++=(UCHAR)(byte); byte=0; \
+ }
+
+
+#define out_bits_10(w) \
+ if (bit > 10) { \
+ bit-=10; byte |= (w << bit); *pbyte++ = (UCHAR)(byte >> 8); bit+=8; byte <<=8; \
+ } else { \
+ out_bits_2((w >> 8)); \
+ out_bits_8((w & 0xFF)); \
+ }
+
+//
+// Weird effect - if out_bits_9 used instead of out_bits_8,
+// it's faster! if (bit == 11) is faster than if (bit != 11).
+//
+
+#define out_bits_11(w) \
+ if (bit > 11) { \
+ bit-=11; byte |= (w << bit); *pbyte++ = (UCHAR)(byte >> 8); bit+=8; byte <<=8; \
+ } else { \
+ if (bit == 11) { \
+ bit=16; byte |= w; \
+ *pbyte++=(UCHAR)(byte >> 8); *pbyte++=(UCHAR)(byte); byte=0; \
+ } else { \
+ bit=11-bit; \
+ byte|=(w >> bit); \
+ *pbyte++=(UCHAR)(byte >> 8); *pbyte++=(UCHAR)(byte); \
+ bit=16-bit; \
+ byte=(w << bit); \
+ } \
+ }
+
+
+#define out_bits_12(w) \
+ if (bit > 12) { \
+ bit-=12; byte |= (w << bit); *pbyte++ = (UCHAR)(byte >> 8); bit+=8; byte <<=8; \
+ } else { \
+ out_bits_4((w >> 8)); \
+ out_bits_8((w & 0xFF)); \
+ }
+
+#define out_bits_13(w) \
+ if (bit > 13) { \
+ bit-=13; byte |= (w << bit); *pbyte++ = (UCHAR)(byte >> 8); bit+=8; byte <<=8; \
+ } else { \
+ out_bits_5((w >> 8)); \
+ out_bits_8((w & 0xFF)); \
+ }
+
+#define out_bits_14(w) \
+ if (bit > 14) { \
+ bit-=14; byte |= (w << bit); *pbyte++ = (UCHAR)(byte >> 8); bit+=8; byte <<=8; \
+ } else { \
+ out_bits_6((w >> 8)); \
+ out_bits_8((w & 0xFF)); \
+ }
+
+
+#define out_reserve_4() \
+ bit-=4; bitptr_advance();
+
+
+/* Starts the given bit pointer */
+#define inbit_start(s) pbyte = s; bit = 16; byte=(*pbyte << 8) + *(pbyte+1); pbyte++;
+#define inbit_end() if (bit != 16) pbyte++;
+
+#define in_bit_next() if (bit < 9) { \
+ bit=16; \
+ byte <<=8; \
+ byte |= *(++pbyte); \
+ }
+
+
+#define in_bit_advance() if (bit < 9) { \
+ bit+=8; \
+ byte <<=8; \
+ byte |= *(++pbyte); \
+ }
+
+/* Returns non-zero in bitset if the next bit in the stream is a 1. */
+#define in_bit() bit--; bitset = (byte >> bit) & 1; in_bit_next()
+
+
+#define in_bits_2(w) bit-=2; w = (byte >> bit) & 0x03;\
+ in_bit_advance();
+
+#define in_bits_3(w) bit-=3; w = (byte >> bit) & 0x07;\
+ in_bit_advance();
+
+#define in_bits_4(w) bit-=4; w = (byte >> bit) & 0x0F;\
+ in_bit_advance();
+
+#define in_bits_5(w) bit-=5; w = (byte >> bit) & 0x1F;\
+ in_bit_advance();
+
+#define in_bits_6(w) bit-=6; w = (byte >> bit) & 0x3F;\
+ in_bit_advance();
+
+#define in_bits_7(w) bit-=7; w = (byte >> bit) & 0x7F;\
+ in_bit_advance();
+
+#define in_bits_8(w) bit-=8; w = (byte >> bit) & 0xFF;\
+ bit+=8; byte <<=8; byte |= *(++pbyte);
+
+
+#define in_bits_9(w) bit-=9; w = (byte >> bit) & 0x1FF; \
+ bit+=8; byte <<=8; byte |= *(++pbyte); \
+ in_bit_advance();
+
+#define in_bits_10(w) if (bit > 10) { \
+ bit-=10; w = (byte >> bit) & 0x3FF; \
+ bit+=8; byte <<=8; byte |= *(++pbyte); \
+ } else { \
+ in_bits_2(bitset); \
+ in_bits_8(w); \
+ w= w + (bitset << 8); \
+ }
+
+#define in_bits_11(w) if (bit > 11) { \
+ bit-=11; w = (byte >> bit) & 0x7FF; \
+ bit+=8; byte <<=8; byte |= *(++pbyte); \
+ } else { \
+ in_bits_3(bitset); \
+ in_bits_8(w); \
+ w= w + (bitset << 8); \
+ }
+
+
+#define in_bits_12(w) if (bit > 12) { \
+ bit-=12; w = (byte >> bit) & 0xFFF; \
+ bit+=8; byte <<=8; byte |= *(++pbyte); \
+ } else { \
+ in_bits_4(bitset); \
+ in_bits_8(w); \
+ w= w + (bitset << 8); \
+ }
+
+
+
+#define in_bits_13(w)\
+ if (bit > 13) { \
+ bit-=13; w = (byte >> bit) & 0x1FFF; \
+ bit+=8; byte <<=8; byte |= *(++pbyte); \
+ } else { \
+ in_bits_5(bitset); \
+ in_bits_8(w); \
+ w=w + (bitset << 8); \
+ }
+
+
+#define in_bits_14(w)\
+ if (bit > 14) { \
+ bit-=14; w = (byte >> bit) & 0x3FFF; \
+ bit+=8; byte <<=8; byte |= *(++pbyte); \
+ } else { \
+ in_bits_6(bitset); \
+ in_bits_8(w); \
+ w=w + (bitset << 8); \
+ }
+
+
+
+UCHAR SHApad1[40] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+UCHAR SHApad2[40] = {0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
+ 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
+ 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
+ 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2};
+
+#ifdef DEBUG
+char
+ChPrint(UCHAR b)
+{
+ if (isprint(b))
+ return (char)b;
+ else
+ return '.';
+}
+#endif
+
+
+//* compress()
+//
+// Function: Main compression function.
+//
+// Parameters:
+// IN CurrentBuffer -> points to NDIS_WAN_PACKET with data to compress
+// OUT CompOutBuffer -> points to NDIS_WAN_PACKET to compress data to
+// IN CurrentLength -> points to Length of data to compress
+// IN context -> connection compress context
+//
+// Returns: Nothing
+//
+// WARNING: CODE IS HIGHLY OPTIMIZED FOR TIME.
+//
+//
+UCHAR
+compress (UCHAR *CurrentBuffer, UCHAR *CompOutBuffer, ULONG *CurrentLength, SendContext *context)
+{
+ int copylen ;
+ int bit;
+ int byte;
+ int backptr ;
+ int cbMatch;
+ int hashvalue ;
+ int lookup1 ;
+ UCHAR *matchptr ;
+ UCHAR *pbyte;
+ UCHAR *historyptr ;
+ UCHAR *currentptr ;
+ UCHAR *endptr ;
+ UCHAR hashchar1;
+ UCHAR hashchar2;
+ UCHAR hashchar3;
+ int literal ;
+ UCHAR status=0; // return flags
+ PUCHAR currentbuf ;
+
+
+ // Will this packet fit at the end of the history buffer?
+ //
+ if (((context->CurrentIndex + *CurrentLength) >= (HISTORY_MAX - 1 )) ||
+ (context->CurrentIndex == 0)) {
+ context->CurrentIndex = 0; // Index into the history
+ status |= PACKET_AT_FRONT;
+ }
+
+ //
+ // we no longer need to save the non compressed data - tonybe 01-12-95
+ //
+// RtlMoveMemory(context->CompressBuffer, CurrentBuffer, *CurrentLength) ;
+
+ // Start out the bit pointing output
+ //
+ bitptr_init(CompOutBuffer);
+
+ //
+ // We are now compressing into an output buffer - tonybe 01-12-95
+ //
+// bitptr_init(CurrentBuffer);
+
+ historyptr = context->History + context->CurrentIndex ;
+
+ currentptr = CurrentBuffer;
+
+ //
+ // we are now compressing from the currentbuffer - tonybe 01-12-95
+ //
+// currentptr = context->CompressBuffer ;
+
+ endptr = currentptr + *CurrentLength - 1;
+
+ while (currentptr < (endptr-2)) {
+
+ *historyptr++ = hashchar1 = *currentptr++ ;
+ hashchar2 = *currentptr ;
+ hashchar3 = *(currentptr+1) ;
+
+ // "fast" hash function
+ // hashvalue = (int)hashchar1 ^ xorlookup1[hashchar2] ^ xorlookup2[hashchar3];
+ hashvalue = MULTHASH1(hashchar1, hashchar2, hashchar3) ;
+
+ matchptr = context->History + context->HashTable[hashvalue] ;
+
+ if (matchptr != (historyptr - 1))
+ context->HashTable[hashvalue] = historyptr - context->History ;
+
+ if (context->ValidHistory < historyptr)
+ context->ValidHistory = historyptr ;
+
+ if (matchptr != context->History &&
+ *(matchptr-1) == hashchar1 && *matchptr == hashchar2 &&
+ *(matchptr+1) == hashchar3 && matchptr != (historyptr - 1) &&
+ matchptr != historyptr && (matchptr+1) <= context->ValidHistory) {
+
+ backptr = (historyptr - matchptr) & (HISTORY_SIZE - 1) ;
+
+ *historyptr++ = hashchar2 ; // copy the other 2 chars
+ *historyptr++ = hashchar3 ; // copy the other 2 chars
+ currentptr +=2 ;
+ cbMatch = 3 ; // length of match
+ matchptr +=2 ; // we have already matched 3
+
+ while ((*matchptr == *currentptr) && (currentptr < endptr) && (matchptr <= context->ValidHistory)) {
+ matchptr++ ;
+ *historyptr++ = *currentptr++ ;
+ cbMatch++ ;
+ }
+
+#ifdef DEBUG
+ DbgPrint("\tCOMP: Location:%d Char %c, matched length %d, backindex %d\n", (currentptr - context->CompressBuffer), ChPrint(*currentptr), cbMatch, backptr) ;
+#endif
+
+ // First output the backpointer
+ //
+ if (backptr >= 320) {
+ backptr -= 320 ;
+ out_bits_8((0xc000 + backptr) >> 8) ; // 110 + 13 bits
+ out_bits_8((backptr)) ;
+ } else if (backptr < 64) { // 1111 + 6 bits
+ backptr += 0x3c0 ;
+ out_bits_10(backptr);
+ } else {
+ backptr += (0xE00 - 64); // 1110 + 8 bits
+ out_bits_12(backptr);
+ }
+
+ // output the length of the match encoding
+ //
+ switch (cbMatch) {
+
+ case 3:
+ out_bit_0(); // length of 3 - most common
+ break;
+
+ case 4:
+ out_bits_4(8);
+ break;
+
+ case 5:
+ out_bits_4(9);
+ break;
+
+ case 6:
+ out_bits_4(10);
+ break;
+
+ case 7:
+ out_bits_4(11);
+ break;
+
+ case 8:
+ out_bits_6(48);
+ break;
+
+ case 9:
+ out_bits_6(49);
+ break;
+
+ case 10:
+ out_bits_6(50);
+ break;
+
+ case 11:
+ out_bits_6(51);
+ break;
+
+ case 12:
+ out_bits_6(52);
+ break;
+
+ case 13:
+ out_bits_6(53);
+ break;
+
+ case 14:
+ out_bits_6(54);
+ break;
+
+ case 15:
+ out_bits_6(55);
+ break;
+
+ case 16:
+ out_bits_8(0xe0);
+ break;
+
+ case 17:
+ out_bits_8(0xe1);
+ break;
+
+ case 18:
+ out_bits_8(0xe2);
+ break;
+
+ case 19:
+ out_bits_8(0xe3);
+ break;
+
+ case 20:
+ out_bits_8(0xe4);
+ break;
+
+ case 21:
+ out_bits_8(0xe5);
+ break;
+
+ case 22:
+ out_bits_8(0xe6);
+ break;
+
+ case 23:
+ out_bits_8(0xe7);
+ break;
+
+ case 24:
+ out_bits_8(0xe8);
+ break;
+
+ case 25:
+ out_bits_8(0xe9);
+ break;
+
+ case 26:
+ out_bits_8(0xea);
+ break;
+
+ case 27:
+ out_bits_8(0xeb);
+ break;
+
+ case 28:
+ out_bits_8(0xec);
+ break;
+
+ case 29:
+ out_bits_8(0xed);
+ break;
+
+ case 30:
+ out_bits_8(0xee);
+ break;
+
+ case 31:
+ out_bits_8(0xef);
+ break;
+
+ default:
+ if (cbMatch < 64) {
+ out_bits_4(0xF) ;
+ cbMatch -= 32 ;
+ out_bits_6(cbMatch) ;
+ }
+ else if (cbMatch < 128) {
+ out_bits_5(0x1F) ;
+ cbMatch -= 64 ;
+ out_bits_7(cbMatch) ;
+ }
+ else if (cbMatch < 256) {
+ out_bits_6(0x3F) ;
+ cbMatch -= 128 ;
+ out_bits_8(cbMatch) ;
+ }
+ else if (cbMatch < 512) {
+ out_bits_7(0x7F) ;
+ cbMatch -= 256 ;
+ out_bits_9(cbMatch) ;
+ }
+ else if (cbMatch < 1024) {
+ out_bits_8(0xFF) ;
+ cbMatch -= 512 ;
+ out_bits_10(cbMatch) ;
+ }
+ else if (cbMatch < 2048) {
+ out_bits_9(0x1FF) ;
+ cbMatch -= 1024 ;
+ out_bits_11(cbMatch) ;
+ }
+ else if (cbMatch < 4096) {
+ out_bits_10(0x3FF) ;
+ cbMatch -= 2048 ;
+ out_bits_12(cbMatch) ;
+ }
+ else if (cbMatch < 8192) {
+ out_bits_11(0x7FF) ;
+ cbMatch -= 4096 ;
+ out_bits_13(cbMatch) ;
+ }
+ else { // 8192 and greater
+ out_bits_12(0xFFF) ;
+ cbMatch -= 8192 ;
+ out_bits_14(cbMatch) ;
+ }
+ break ;
+ }
+
+ } else { // encode a literal
+
+#ifdef DEBUG
+ DbgPrint("\t COMP:Location %d, <No Match>: '%c'\n", (currentptr - context->CompressBuffer),*currentptr) ;
+#endif
+ // temp=literallookup[context->History[i-1]] ;
+ literal= hashchar1 ;
+
+ if (literal & 0x80) {
+ literal += 0x80;
+ out_bits_9(literal) ;
+ } else {
+ out_bits_8(literal) ;
+ }
+
+ }
+
+ } // while
+
+
+ // get any remaining chars as literals
+ while (currentptr <= endptr) {
+
+#ifdef DEBUG
+ DbgPrint("\t COMP:Location %d, <No Match>: '%c'\n", (currentptr - context->CompressBuffer),*currentptr) ;
+#endif
+
+ // temp=literallookup[context->History[i-1]] ;
+ literal=*currentptr ;
+
+
+ if (literal & 0x80) {
+ literal += 0x80;
+ out_bits_9(literal) ;
+ } else {
+ out_bits_8(literal) ;
+ }
+
+ *historyptr++ = *currentptr++ ;
+ }
+
+
+ bitptr_end() ;
+
+
+ // Check if we had expansion instead of compression
+ //
+ if ((ULONG)(pbyte - CompOutBuffer) > *CurrentLength) { // expansion.
+
+ //
+ // We don't need to do this copy since we can just signal the outside world
+ // that compression did not take place and the valid data is still in the
+ // current buffer
+ //
+ // RtlMoveMemory(CompOutBuffer, CurrentBuffer, *CurrentLength) ;
+
+ memset (context->History, 0, sizeof(context->History)) ;
+ memset (context->HashTable, 0, sizeof(context->HashTable)) ;
+#ifdef COMP_12K
+ status = 0 ;
+#else
+ status = PACKET_FLUSHED;
+#endif
+ context->CurrentIndex = HISTORY_SIZE+1 ; // this forces a start over next time
+
+ } else { // compression successful
+
+ *CurrentLength = pbyte - CompOutBuffer;
+
+ //
+ // the compressed data is now in CompOutBuffer - tonybe 01-12-95
+ //
+ // *CurrentLength = pbyte - CurrentBuffer ;
+
+ status |= PACKET_COMPRESSED ;
+ context->CurrentIndex = historyptr - context->History ;
+ }
+
+ return(status);
+}
+
+
+
+//* getcontextsizes()
+//
+// Function: Returns size of send and receive context blocks
+//
+// Parameters: OUT send -> sizeof(SendContext)
+// OUT recv -> sizeof(RecvContext)
+//
+// Returns: Nothing
+//
+//*
+void
+getcontextsizes (long *send, long *recv)
+{
+ *send = sizeof(SendContext) ;
+ *recv = sizeof(RecvContext) ;
+}
+
+
+//* initsendcontext()
+//
+// Function: Initialize SendContext block
+//
+// Parameters: IN context -> connection compress context
+//
+// Returns: Nothing
+//
+//*
+void
+initsendcontext (SendContext *context)
+{
+ context->CurrentIndex = 0; // Index into the history
+ context->ValidHistory = 0 ; // reset valid history
+ memset (context->HashTable, 0, sizeof(context->HashTable)) ;
+ memset (context->History, 0, sizeof(context->HashTable)) ;
+}
+
+
+
+//* initrecvcontext()
+//
+// Function: Initialize RecvContext block
+//
+// Parameters: IN context -> connection decompress context
+//
+// Returns: Nothing
+//
+//*
+void
+initrecvcontext (RecvContext *context)
+{
+ context->CurrentPtr = context->History ;
+
+#if DBG
+ context->DebugFence = DEBUG_FENCE_VALUE;
+#endif
+
+ memset (context->History, 0, sizeof(context->History)) ;
+}
+
+
+
+//* decompress()
+//
+// Function: de-compression function.
+//
+// Parameters: IN inbuf -> points to data to be uncompressed
+// IN inlen -> length of data
+// IN start -> flag indicating whether to start with a clean history buffer
+// OUT output-> decompressed data
+// OUT outlen-> lenght of decompressed data
+// IN context -> connection decompress context
+//
+// Returns: TRUE if decompress was successful
+// FALSE if it wasnt
+//
+// WARNING: CODE IS HIGHLY OPTIMIZED FOR TIME.
+//
+//*
+int
+decompress(
+ UCHAR *inbuf,
+ int inlen,
+ int start,
+ UCHAR **output,
+ int *outlen,
+ RecvContext *context)
+{
+ UCHAR *inend; // When we know we're done decompressing
+ UCHAR *outstart; // Remember where in dbuf we started
+
+ UCHAR *current;
+
+ int backptr; // Back pointer for copy items
+ int length; // Where to copy from in dbuf
+
+ UCHAR *s1, *s2;
+
+ int bitset;
+ int bit;
+ int byte;
+ UCHAR *pbyte;
+ UCHAR *historyend = context->History + HISTORY_SIZE ;
+
+ inend = inbuf + inlen ;
+
+ //
+ // Start out looking at the first bit
+ //
+ inbit_start(inbuf);
+
+ if (start) // start over clean?
+ context->CurrentPtr = current = context->History ;
+ else
+ current = context->CurrentPtr ;
+
+ //
+ // Save our starting position
+ //
+ outstart = current;
+
+ //
+ // Decompress until we run out of input
+ //
+ while (pbyte < inend) {
+
+ //
+ // Jump on what to do with these three bits.
+ //
+ in_bits_3(length);
+
+ switch (length) {
+
+ case 0:
+ in_bits_5(length) ;
+ goto LITERAL ;
+
+ case 1:
+ in_bits_5(length) ;
+ length += 32 ;
+ goto LITERAL ;
+
+ case 2:
+ in_bits_5(length) ;
+ length += 64 ;
+ goto LITERAL ;
+
+ case 3:
+ in_bits_5(length) ;
+ length += 96 ;
+ goto LITERAL ;
+
+ case 4:
+ in_bits_6(length) ;
+ length +=128 ;
+ goto LITERAL ;
+
+ case 5:
+ in_bits_6(length) ;
+ length +=192 ;
+ goto LITERAL ;
+
+ case 6:
+ in_bits_13 (backptr) ; // 110 - 14 bit offset
+ backptr+=320 ;
+ break ;
+
+ case 7:
+ in_bit() ;
+ if (bitset) {
+ in_bits_6(backptr) ;
+ } else {
+ in_bits_8(backptr) ;
+ backptr+=64 ;
+ }
+ break ;
+ }
+
+ //
+ // If we reach here, it's a copy item
+ //
+
+ //
+ // Now get the length
+ //
+
+ in_bit() ; // 1st length bit
+ if (!bitset) {
+ length = 3 ;
+ goto DONE ;
+ }
+
+ in_bit() ; // 2nd length bit
+ if (!bitset) {
+ in_bits_2 (length) ;
+ length += 4 ;
+ goto DONE ;
+ }
+
+ in_bit() ; // 3rd length bit
+ if (!bitset) {
+ in_bits_3 (length) ;
+ length += 8 ;
+ goto DONE ;
+ }
+
+ in_bit() ; // 4th length bit
+ if (!bitset) {
+ in_bits_4 (length) ;
+ length += 16 ;
+ goto DONE ;
+ }
+
+ in_bit() ; // 5th length bit
+ if (!bitset) {
+ in_bits_5 (length) ;
+ length += 32 ;
+ goto DONE ;
+ }
+
+ in_bit() ; // 6th length bit
+ if (!bitset) {
+ in_bits_6 (length) ;
+ length += 64 ;
+ goto DONE ;
+ }
+
+ in_bit() ; // 7th length bit
+ if (!bitset) {
+ in_bits_7 (length) ;
+ length += 128 ;
+ goto DONE ;
+ }
+
+ in_bit() ; // 8th length bit
+ if (!bitset) {
+ in_bits_8 (length) ;
+ length += 256 ;
+ goto DONE ;
+ }
+
+ in_bit() ; // 9th length bit
+ if (!bitset) {
+ in_bits_9 (length) ;
+ length += 512 ;
+ goto DONE ;
+ }
+
+ in_bit() ; // 10th length bit
+ if (!bitset) {
+ in_bits_10 (length) ;
+ length += 1024 ;
+ goto DONE ;
+ }
+
+ //
+ // length cannot be greater than max packets size which is 1500
+ //
+ DbgPrint("NDISWAN: RAS Decompressor problem: Possible data corruption\n");
+
+ return FALSE ;
+
+
+ DONE:
+ //
+ // Turn the backptr into an index location
+ //
+#ifdef COMP_12K
+ s2 = current - backptr ;
+#else
+ s2 = context->History + (((current - context->History) - backptr) & (HISTORY_SIZE -1)) ;
+#endif
+
+ s1 = current;
+
+#ifdef DEBUG
+ DbgPrint("\tdecomp: location: %d, bp %.4d length %.4d\n", (current-context->CurrentPtr), backptr, length);
+#endif
+ current += length;
+
+ // if we are past the end of the history this is a bad sign: abort decompression
+ //
+ if (current >= historyend) {
+ DbgPrint("NDISWAN: RAS Decompressor problem: Possible data corruption\n");
+ return FALSE ;
+ }
+
+ // loop unrolled to handle lenght>backptr case
+ //
+ *s1=*s2;
+ *(s1+1)=*(s2+1);
+ s1+=2;
+ s2+=2;
+ length-=2;
+
+ //
+ // copy all the bytes
+ //
+ while (length) {
+ *s1++=*s2++;
+ length--;
+ }
+
+ //
+ // We have another copy item, and no literals
+ //
+ continue;
+
+
+ LITERAL:
+
+#ifdef DEBUG
+ DbgPrint("\tdecomp: Location %d, literal '%c'\n",(current-context->CurrentPtr), length);
+#endif
+
+ //
+ // We have a literal
+ //
+ //*current++ = literallookup[length];
+ *current++ = length;
+
+ } // while loop
+
+
+ // End case:
+ //
+ if ((bit == 16) && (pbyte == inend)) {
+ *current++ = *(pbyte -1) ;
+ }
+
+#if DBG
+ if (context->DebugFence != DEBUG_FENCE_VALUE) {
+ DbgPrint("Decompression Error!\n");
+ DbgPrint("context 0x%8.8x, current 0x%8.8x, outstart 0x%8.8x\n", context, current, outstart);
+ DbgPrint("inbuf 0x%8.8x, inlength %d, start 0x%8.8x\n", inbuf, inlen, start);
+ DbgBreakPoint();
+ }
+#endif
+
+ *outlen = current - outstart ; // the length of decompressed data
+
+ *output = context->CurrentPtr ;
+
+ context->CurrentPtr = current ;
+
+ return TRUE ;
+}
+
+NDIS_STATUS
+InitSHAContext(
+ PENCRYPTION_INFO EncryptInfo
+ )
+{
+ if (EncryptInfo->Context == NULL) {
+ NdisWanAllocateMemory(&EncryptInfo->Context, sizeof(A_SHA_CTX));
+
+ if (EncryptInfo->Context == NULL) {
+ return (NDIS_STATUS_RESOURCES);
+ }
+ }
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+//
+// This function uses the 16 byte user session key and the 8 byte
+// challenge to create an intial 16 byte encryption session key.
+//
+VOID
+GetStartKeyFromSHA(
+ PENCRYPTION_INFO EncryptInfo,
+ PUCHAR Challenge
+ )
+{
+ UCHAR Digest[A_SHA_DIGEST_LEN];
+ UCHAR SessionKeyChallenge[MAX_USERSESSIONKEY_SIZE + MAX_CHALLENGE_SIZE];
+
+ NdisZeroMemory(Digest, A_SHA_DIGEST_LEN);
+
+ //
+ // Copy the start session key
+ //
+ NdisMoveMemory(SessionKeyChallenge,
+ EncryptInfo->StartKey,
+ EncryptInfo->SessionKeyLength);
+
+ //
+ // Append the challenge
+ //
+ NdisMoveMemory((PUCHAR)(SessionKeyChallenge + EncryptInfo->SessionKeyLength),
+ Challenge,
+ MAX_CHALLENGE_SIZE);
+
+//
+// SHAInit(context)
+// SHAUpdate(context, sessionkey, sessionkeylength)
+// SHAUpdate(context, sessionkeychallenge, sessionkeylength + challengelength)
+// SHAFinal(context, digest)
+//
+// Start key is the first 16 bytes of the digest.
+//
+ A_SHAInit(EncryptInfo->Context);
+
+ A_SHAUpdate(EncryptInfo->Context,
+ EncryptInfo->StartKey,
+ EncryptInfo->SessionKeyLength);
+
+ A_SHAUpdate(EncryptInfo->Context,
+ SessionKeyChallenge,
+ EncryptInfo->SessionKeyLength + MAX_CHALLENGE_SIZE);
+
+ A_SHAFinal(EncryptInfo->Context,
+ Digest);
+
+ NdisMoveMemory(EncryptInfo->StartKey,
+ Digest,
+ EncryptInfo->SessionKeyLength);
+
+ NdisMoveMemory(EncryptInfo->SessionKey,
+ Digest,
+ EncryptInfo->SessionKeyLength);
+}
+
+VOID
+GetNewKeyFromSHA(
+ PENCRYPTION_INFO EncryptInfo
+ )
+{
+ UCHAR Digest[A_SHA_DIGEST_LEN];
+
+ NdisZeroMemory(Digest, A_SHA_DIGEST_LEN);
+
+ A_SHAInit(EncryptInfo->Context);
+ A_SHAUpdate(EncryptInfo->Context,
+ EncryptInfo->StartKey,
+ EncryptInfo->SessionKeyLength);
+ A_SHAUpdate(EncryptInfo->Context,
+ SHApad1,
+ 40);
+ A_SHAUpdate(EncryptInfo->Context,
+ EncryptInfo->SessionKey,
+ EncryptInfo->SessionKeyLength);
+ A_SHAUpdate(EncryptInfo->Context,
+ SHApad2,
+ 40);
+ A_SHAFinal(EncryptInfo->Context,
+ Digest);
+
+ NdisMoveMemory(EncryptInfo->SessionKey,
+ Digest,
+ EncryptInfo->SessionKeyLength);
+}
+
+/* Copyright (C) RSA Data Security, Inc. created 1993. This is an
+ unpublished work protected as such under copyright law. This work
+ contains proprietary, confidential, and trade secret information of
+ RSA Data Security, Inc. Use, disclosure or reproduction without the
+ express written authorization of RSA Data Security, Inc. is
+ prohibited.
+ */
+
+/* SHA initialization. Begins an SHA operation, writing a new context.
+ */
+void A_SHAInitCommon (context)
+A_SHA_COMM_CTX *context;
+{
+ context->count[0] = context->count[1] = 0;
+
+ /* Load magic initialization constants.
+ */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xc3d2e1f0;
+}
+
+/* SHA block update operation. Continues an SHA message-digest
+ operation, processing another message block, and updating the
+ context.
+ */
+void A_SHAUpdateCommon (context, partIn, partInLen, Transform)
+A_SHA_COMM_CTX *context;
+unsigned char *partIn;
+ULONG partInLen;
+A_SHA_TRANSFORM *Transform;
+{
+ unsigned int bufferLen;
+
+ /* Compute length of buffer */
+ bufferLen = (unsigned int)(context->count[1] & 0x3f);
+
+ /* Update number of bytes */
+ if ((context->count[1] += partInLen) < partInLen)
+ context->count[0]++;
+
+ /* If previous input in buffer, buffer new input and transform if
+ possible.
+ */
+ if (bufferLen > 0 && bufferLen + partInLen >= 64) {
+ NdisMoveMemory(context->buffer+bufferLen, partIn, 64-bufferLen);
+ partIn += (64-bufferLen);
+ partInLen -= (64-bufferLen);
+ (*Transform) (context->state, context->buffer);
+ bufferLen = 0;
+ }
+
+ /* Transform directly from input.
+ */
+ while (partInLen >= 64) {
+ (*Transform) (context->state, partIn);
+ partIn += 64;
+ partInLen -= 64;
+ }
+
+ /* Buffer remaining input */
+ NdisMoveMemory((context->buffer+bufferLen), partIn, partInLen);
+}
+
+/* SHA finalization. Ends an SHA message-digest operation, writing
+ the message digest and zeroizing the context.
+ */
+void A_SHAFinalCommon (context, digest, Transform)
+A_SHA_COMM_CTX *context;
+unsigned char digest[A_SHA_DIGEST_LEN];
+A_SHA_TRANSFORM *Transform;
+{
+ ULONG bitCount[2];
+ unsigned char pad[72];
+ unsigned int padLen;
+
+ /* Compute padding: 80 00 00 ... 00 00 <bit count>
+ */
+ padLen = 64 - (unsigned int)(context->count[1] & 0x3f);
+ if (padLen <= 8)
+ padLen += 64;
+ pad[0] = 0x80;
+ NdisZeroMemory(pad+1, padLen-7);
+ bitCount[0] = (context->count[0] << 3) | (context->count[1] >> 29);
+ bitCount[1] = context->count[1] << 3;
+ ByteReverse ((ULONG*)(pad+padLen-8), bitCount, 2);
+
+ /* Digest padding */
+ A_SHAUpdateCommon (context, pad, padLen, Transform);
+
+ /* Store digest */
+ ByteReverse ((ULONG*)digest, context->state, 5);
+
+ /* Restart the context */
+ A_SHAInitCommon (context);
+}
+
+void A_SHAInit (A_SHA_CTX *context)
+{
+ A_SHAInitCommon (&context->commonContext);
+}
+
+void A_SHAUpdate (context, partIn, partInLen)
+A_SHA_CTX *context;
+unsigned char *partIn;
+unsigned int partInLen;
+{
+ A_SHAUpdateCommon (&context->commonContext, partIn, partInLen, SHATransform);
+}
+
+void A_SHAFinal (context, digest)
+A_SHA_CTX *context;
+unsigned char digest[A_SHA_DIGEST_LEN];
+{
+ A_SHAFinalCommon (&context->commonContext, digest, SHATransform);
+}
+
+void SHATransform (state, block)
+ULONG state[5];
+unsigned char block[64];
+{
+ ULONG a = state[0], b = state[1], c = state[2], d = state[3],
+ e = state[4], x[80];
+
+ ByteReverse (x, (ULONG*)block, 16);
+ SHAExpand (x);
+
+ /* Round 1 */
+ FF (a, b, c, d, e, x[ 0]);
+ FF (e, a, b, c, d, x[ 1]);
+ FF (d, e, a, b, c, x[ 2]);
+ FF (c, d, e, a, b, x[ 3]);
+ FF (b, c, d, e, a, x[ 4]);
+ FF (a, b, c, d, e, x[ 5]);
+ FF (e, a, b, c, d, x[ 6]);
+ FF (d, e, a, b, c, x[ 7]);
+ FF (c, d, e, a, b, x[ 8]);
+ FF (b, c, d, e, a, x[ 9]);
+ FF (a, b, c, d, e, x[10]);
+ FF (e, a, b, c, d, x[11]);
+ FF (d, e, a, b, c, x[12]);
+ FF (c, d, e, a, b, x[13]);
+ FF (b, c, d, e, a, x[14]);
+ FF (a, b, c, d, e, x[15]);
+ FF (e, a, b, c, d, x[16]);
+ FF (d, e, a, b, c, x[17]);
+ FF (c, d, e, a, b, x[18]);
+ FF (b, c, d, e, a, x[19]);
+
+ /* Round 2 */
+ GG (a, b, c, d, e, x[20]);
+ GG (e, a, b, c, d, x[21]);
+ GG (d, e, a, b, c, x[22]);
+ GG (c, d, e, a, b, x[23]);
+ GG (b, c, d, e, a, x[24]);
+ GG (a, b, c, d, e, x[25]);
+ GG (e, a, b, c, d, x[26]);
+ GG (d, e, a, b, c, x[27]);
+ GG (c, d, e, a, b, x[28]);
+ GG (b, c, d, e, a, x[29]);
+ GG (a, b, c, d, e, x[30]);
+ GG (e, a, b, c, d, x[31]);
+ GG (d, e, a, b, c, x[32]);
+ GG (c, d, e, a, b, x[33]);
+ GG (b, c, d, e, a, x[34]);
+ GG (a, b, c, d, e, x[35]);
+ GG (e, a, b, c, d, x[36]);
+ GG (d, e, a, b, c, x[37]);
+ GG (c, d, e, a, b, x[38]);
+ GG (b, c, d, e, a, x[39]);
+
+ /* Round 3 */
+ HH (a, b, c, d, e, x[40]);
+ HH (e, a, b, c, d, x[41]);
+ HH (d, e, a, b, c, x[42]);
+ HH (c, d, e, a, b, x[43]);
+ HH (b, c, d, e, a, x[44]);
+ HH (a, b, c, d, e, x[45]);
+ HH (e, a, b, c, d, x[46]);
+ HH (d, e, a, b, c, x[47]);
+ HH (c, d, e, a, b, x[48]);
+ HH (b, c, d, e, a, x[49]);
+ HH (a, b, c, d, e, x[50]);
+ HH (e, a, b, c, d, x[51]);
+ HH (d, e, a, b, c, x[52]);
+ HH (c, d, e, a, b, x[53]);
+ HH (b, c, d, e, a, x[54]);
+ HH (a, b, c, d, e, x[55]);
+ HH (e, a, b, c, d, x[56]);
+ HH (d, e, a, b, c, x[57]);
+ HH (c, d, e, a, b, x[58]);
+ HH (b, c, d, e, a, x[59]);
+
+ /* Round 4 */
+ II (a, b, c, d, e, x[60]);
+ II (e, a, b, c, d, x[61]);
+ II (d, e, a, b, c, x[62]);
+ II (c, d, e, a, b, x[63]);
+ II (b, c, d, e, a, x[64]);
+ II (a, b, c, d, e, x[65]);
+ II (e, a, b, c, d, x[66]);
+ II (d, e, a, b, c, x[67]);
+ II (c, d, e, a, b, x[68]);
+ II (b, c, d, e, a, x[69]);
+ II (a, b, c, d, e, x[70]);
+ II (e, a, b, c, d, x[71]);
+ II (d, e, a, b, c, x[72]);
+ II (c, d, e, a, b, x[73]);
+ II (b, c, d, e, a, x[74]);
+ II (a, b, c, d, e, x[75]);
+ II (e, a, b, c, d, x[76]);
+ II (d, e, a, b, c, x[77]);
+ II (c, d, e, a, b, x[78]);
+ II (b, c, d, e, a, x[79]);
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+
+ /* Zeroize potentially sensitive information.
+ */
+ NdisZeroMemory((void *)x, sizeof (x));
+}
+
+/* Expands x[0..15] into x[16..79], according to the recurrence
+ x[i] = x[i-3] ^ x[i-8] ^ x[i-14] ^ x[i-16].
+ */
+void SHAExpand (x)
+ULONG x[80];
+{
+ unsigned int i;
+ ULONG tmp;
+
+ for (i = 16; i < 80; i++)
+ {
+ tmp = x[i-3] ^ x[i-8] ^ x[i-14] ^ x[i-16];
+ x[i] = (tmp << 1) | (tmp >> 31);
+ }
+}
+
+VOID
+ByteReverse(
+ ULONG *Out,
+ ULONG *In,
+ ULONG Count
+ )
+{
+ ULONG i;
+ ULONG Value;
+
+ for (i = 0; i < Count; i++) {
+ Value = (ULONG)(In[i] << 16) | (In[i] >> 16);
+ Out[i] = ((Value & 0xFF00FF00L) >> 8) | ((Value & 0x00FF00FFL) << 8);
+ }
+}
+
diff --git a/private/ntos/ndis/ndiswan/compress.h b/private/ntos/ndis/ndiswan/compress.h
new file mode 100644
index 000000000..a5bd31c29
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/compress.h
@@ -0,0 +1,187 @@
+//************************************************************************
+// Microsoft Corporation
+// Copyright(c) Microsoft Corp., 1994
+//
+//
+// Revision history:
+// 5/5/94 Created gurdeep
+//
+// This file uses 4 space tabs
+//************************************************************************
+
+#ifdef COMP_12K
+#define HISTORY_SIZE 16000
+#else
+#define HISTORY_SIZE (8192U) // Maximum back-pointer value, also used
+#endif
+
+#define HISTORY_MAX (HISTORY_SIZE -1) // Maximum back-pointer value, also used
+
+#define HASH_TABLE_SIZE 4096
+
+#define MAX_BACK_PTR 8511
+
+#define MAX_COMPRESSFRAME_SIZE 1600
+
+struct SendContext {
+
+ UCHAR History [HISTORY_SIZE+1] ;
+
+ int CurrentIndex ; // how far into the history buffer we are
+
+ PUCHAR ValidHistory ; // how much of history is valid
+
+ UCHAR CompressBuffer[MAX_COMPRESSFRAME_SIZE] ;
+
+ USHORT HashTable[HASH_TABLE_SIZE];
+
+} ;
+
+typedef struct SendContext SendContext ;
+
+
+struct RecvContext {
+
+ UCHAR History [HISTORY_SIZE+1] ;
+
+#if DBG
+
+#define DEBUG_FENCE_VALUE 0xABABABAB
+ ULONG DebugFence;
+
+#endif
+
+ UCHAR *CurrentPtr ; // how far into the history buffer we are
+} ;
+
+typedef struct RecvContext RecvContext ;
+
+
+// Prototypes
+//
+UCHAR
+compress (
+ UCHAR *CurrentBuffer,
+ UCHAR *CompOutBuffer,
+ ULONG *CurrentLength,
+ SendContext *context);
+
+//UCHAR
+//compress (
+// UCHAR *CurrentBuffer,
+// ULONG *CurrentLength,
+// SendContext *context);
+
+int
+decompress (
+ UCHAR *inbuf,
+ int inlen,
+ int start,
+ UCHAR **output,
+ int *outlen,
+ RecvContext *context) ;
+
+void getcontextsizes (long *, long *) ;
+
+void initsendcontext (SendContext *) ;
+
+void initrecvcontext (RecvContext *) ;
+
+NDIS_STATUS
+InitSHAContext(
+ PENCRYPTION_INFO EncryptInfo
+ );
+
+VOID
+GetStartKeyFromSHA(
+ PENCRYPTION_INFO EncryptInfo,
+ PUCHAR Challenge
+ );
+
+VOID
+GetNewKeyFromSHA(
+ PENCRYPTION_INFO EncryptInfo
+ );
+
+
+//
+// Other defines
+//
+
+#define COMPRESSION_PADDING 4
+
+#define PACKET_FLUSHED 0x80
+#define PACKET_AT_FRONT 0x40
+#define PACKET_COMPRESSED 0x20
+#define PACKET_ENCRYPTED 0x10
+
+
+/* Copyright (C) RSA Data Security, Inc. created 1993. This is an
+ unpublished work protected as such under copyright law. This work
+ contains proprietary, confidential, and trade secret information of
+ RSA Data Security, Inc. Use, disclosure or reproduction without the
+ express written authorization of RSA Data Security, Inc. is
+ prohibited.
+ */
+
+#define A_SHA_DIGEST_LEN 20
+
+typedef struct {
+ ULONG state[5]; /* state (ABCDE) */
+ ULONG count[2]; /* number of UCHARs, msb first */
+ unsigned char buffer[64]; /* input buffer */
+} A_SHA_COMM_CTX;
+
+typedef void (A_SHA_TRANSFORM) (ULONG [5], unsigned char [64]);
+
+void A_SHAInitCommon (A_SHA_COMM_CTX *);
+void A_SHAUpdateCommon(A_SHA_COMM_CTX *, UCHAR *, ULONG, A_SHA_TRANSFORM *);
+void A_SHAFinalCommon(A_SHA_COMM_CTX *, UCHAR[A_SHA_DIGEST_LEN],
+ A_SHA_TRANSFORM *);
+
+VOID ByteReverse(ULONG* Out, ULONG* In, ULONG Count);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ ULONG FinishFlag;
+ UCHAR HashVal[A_SHA_DIGEST_LEN];
+ A_SHA_COMM_CTX commonContext;
+} A_SHA_CTX;
+
+void A_SHAInit(A_SHA_CTX *);
+void A_SHAUpdate(A_SHA_CTX *, unsigned char *, unsigned int);
+void A_SHAFinal(A_SHA_CTX *, unsigned char [A_SHA_DIGEST_LEN]);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/* F, G, H and I are basic SHA functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) ((x) ^ (y) ^ (z))
+#define H(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
+#define I(x, y, z) ((x) ^ (y) ^ (z))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+ */
+#define ROUND(a, b, c, d, e, x, F, k) { \
+ (e) += ROTATE_LEFT ((a), 5) + F ((b), (c), (d)) + (x) + k; \
+ (b) = ROTATE_LEFT ((b), 30); \
+ }
+#define FF(a, b, c, d, e, x) ROUND (a, b, c, d, e, x, F, 0x5a827999);
+#define GG(a, b, c, d, e, x) ROUND (a, b, c, d, e, x, G, 0x6ed9eba1);
+#define HH(a, b, c, d, e, x) ROUND (a, b, c, d, e, x, H, 0x8f1bbcdc);
+#define II(a, b, c, d, e, x) ROUND (a, b, c, d, e, x, I, 0xca62c1d6);
+
+void SHATransform(ULONG [5], unsigned char [64]);
+void SHAExpand(ULONG [80]);
+
diff --git a/private/ntos/ndis/ndiswan/dirs b/private/ntos/ndis/ndiswan/dirs
new file mode 100644
index 000000000..8a1ff70d8
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/dirs
@@ -0,0 +1,26 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=domestic \
+ export
+
+OPTIONAL_DIRS=kdexts
diff --git a/private/ntos/ndis/ndiswan/export/makefile b/private/ntos/ndis/ndiswan/export/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/export/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/ndiswan/export/sources b/private/ntos/ndis/ndiswan/export/sources
new file mode 100644
index 000000000..2bc2f0dec
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/export/sources
@@ -0,0 +1,59 @@
+!IF 0
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=ndiswan
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib \
+ $(BASEDIR)\public\sdk\lib\*\ndistapi.lib \
+ ..\..\..\..\lsa\crypt\engine\obj\*\rc4c.obj
+
+INCLUDES=..\..\inc;..\..\..\inc;..\..\..\..\inc;..\..\..\..\lsa\crypt\engine;..\..\..\tdi\nbf;..\..\..\tdi\isnp\ipx
+
+#C_DEFINES=-DNT -DNDIS_MINIPORT_DRIVER -DBINARY_COMPATIBLE=0 -DNDIS_WRAPPER
+C_DEFINES=-DNT -DNDIS_WRAPPER
+
+SOURCES=..\ndiswan.c \
+ ..\send.c \
+ ..\compress.c \
+ ..\receive.c \
+ ..\io.c \
+ ..\miniport.c \
+ ..\protocol.c \
+ ..\util.c \
+ ..\request.c \
+ ..\memory.c \
+ ..\indicate.c \
+ ..\vjslip.c \
+ ..\tapi.c \
+ ..\ccp.c \
+ ..\loopback.c \
+ ..\ndiswan.rc
+
+MSC_WARNING_LEVEL=/W3 /WX
+
diff --git a/private/ntos/ndis/ndiswan/global.h b/private/ntos/ndis/ndiswan/global.h
new file mode 100644
index 000000000..4f60ef906
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/global.h
@@ -0,0 +1,52 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ Global.h
+
+Abstract:
+
+ This file contains global structures for the NdisWan driver.
+
+Author:
+
+ Tony Bell (TonyBe) June 06, 1995
+
+Environment:
+
+ Kernel Mode
+
+Revision History:
+
+ TonyBe 06/06/95 Created
+
+--*/
+
+#ifndef _NDISWAN_GLOBAL_
+#define _NDISWAN_GLOBAL_
+
+extern NDISWANCB NdisWanCB; // Global ndiswan control block
+
+extern WAN_GLOBAL_LIST ThresholdEventQueue; // Queue to hold threshold events
+
+extern WAN_GLOBAL_LIST RecvPacketQueue; // Queue to hold ppp receive packets
+
+extern WAN_GLOBAL_LIST FreeBundleCBList; // List of free BundleCB's
+
+extern WAN_GLOBAL_LIST FreeProtocolCBList; // List of free ProtocolCB's
+
+extern WAN_GLOBAL_LIST AdapterCBList; // List of NdisWan AdapterCB's
+
+extern WAN_GLOBAL_LIST WanAdapterCBList; // List of WAN Miniport structures
+
+extern WAN_GLOBAL_LIST GlobalRecvDescPool; // Global pool of free recvdesc's
+
+extern PCONNECTION_TABLE ConnectionTable; // Pointer to connection table
+
+extern PPPP_PROTOCOL_TABLE PPP_ProtocolTable; // Pointer to the PPP/Protocol value lookup table
+
+extern NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress;
+
+#endif // _NDISWAN_GLOBAL_
diff --git a/private/ntos/ndis/ndiswan/indicate.c b/private/ntos/ndis/ndiswan/indicate.c
new file mode 100644
index 000000000..40e0d61ae
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/indicate.c
@@ -0,0 +1,611 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ Indicate.c
+
+Abstract:
+
+ This file contains procedures to handle indications from the
+ WAN Miniport drivers.
+
+
+Author:
+
+ Tony Bell (TonyBe) June 06, 1995
+
+Environment:
+
+ Kernel Mode
+
+Revision History:
+
+ TonyBe 06/06/95 Created
+
+--*/
+
+#include "wan.h"
+
+
+VOID
+NdisWanLineUpIndication(
+ PWAN_ADAPTERCB WanAdapterCB,
+ PUCHAR Buffer,
+ ULONG BufferSize
+ )
+/*++
+
+Routine Name:
+
+ NdisWanLineupIndication
+
+Routine Description:
+
+ This routine is called when a WAN Miniport driver has a new connetion
+ become active or when the status of an active connection changes. If
+ this is a new connection the routine creates a LinkCB, and a BundleCB
+ for the new connection. If this is for an already active connetion the
+ connection info is updated.
+
+Arguments:
+
+Return Values:
+
+ None
+
+--*/
+{
+ PLINKCB LinkCB;
+ PBUNDLECB BundleCB;
+ PPROTOCOLCB ProtocolCB;
+ NDIS_STATUS Status;
+ PNDIS_MAC_LINE_UP LineUpInfo = (PNDIS_MAC_LINE_UP)Buffer;
+ PNDIS_MAC_LINE_UP LinkLineUpInfo;
+ BOOLEAN EmptyList;
+
+ if (BufferSize >= sizeof(NDIS_MAC_LINE_UP)) {
+
+ //
+ // Is this for a new connetion?
+ //
+ if (LineUpInfo->NdisLinkContext == NULL) {
+
+ //
+ // This is a new connection!
+ //
+
+ //
+ // Get a linkcb
+ //
+ NdisWanGetLinkCB(&LinkCB,
+ WanAdapterCB,
+ LineUpInfo->SendWindow);
+
+ if (LinkCB == NULL) {
+
+ //
+ // Error getting LinkCB!
+ //
+
+ return;
+
+ }
+
+ LinkCB->NdisLinkHandle = LineUpInfo->NdisLinkHandle;
+
+ //
+ // Get a bundlecb
+ //
+ NdisWanGetBundleCB(&BundleCB);
+
+ if (BundleCB == NULL) {
+
+ //
+ // Error getting BundleCB!
+ //
+
+ NdisWanReturnLinkCB(LinkCB);
+
+ return;
+ }
+
+ //
+ // Copy LineUpInfo to Link LineUpInfo
+ //
+ NdisMoveMemory((PUCHAR)&LinkCB->LineUpInfo,
+ (PUCHAR)LineUpInfo,
+ sizeof(NDIS_MAC_LINE_UP));
+
+ //
+ // Add LinkCB to BundleCB
+ //
+ AddLinkToBundle(BundleCB, LinkCB);
+
+ //
+ // Place BundleCB in active connection table
+ //
+ InsertBundleInConnectionTable(BundleCB);
+
+ //
+ // Place LinkCB in active connection table
+ //
+ InsertLinkInConnectionTable(LinkCB);
+
+ LineUpInfo->NdisLinkContext = (NDIS_HANDLE)LinkCB->hLinkHandle;
+
+
+ } else {
+
+ //
+ // This is an already existing connetion
+ //
+ LINKCB_FROM_LINKH(LinkCB, LineUpInfo->NdisLinkContext);
+
+ if (LinkCB == NULL) {
+#if DBG
+ DbgPrint("NDISWAN.SYS: Invalid LinkContext (0x%8.8x) in LineUp!",
+ LineUpInfo->NdisLinkContext);
+#endif
+ return;
+ }
+
+ BundleCB = BUNDLECB_FROM_LINKCB(LinkCB);
+
+ if (BundleCB == NULL) {
+#if DBG
+ DbgPrint("NDISWAN.SYS: Invalid BundleCB in LineUp, BundleCB: 0x%8.8x, LinkCB: 0x%8.8x\n",
+ LinkCB, BundleCB);
+#endif
+ return;
+ }
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ LinkLineUpInfo = &LinkCB->LineUpInfo;
+
+ LinkLineUpInfo->LinkSpeed = LineUpInfo->LinkSpeed;
+ LinkLineUpInfo->Quality = LineUpInfo->Quality;
+ LinkLineUpInfo->SendWindow = LineUpInfo->SendWindow;
+
+ //
+ // Update BundleCB info
+ //
+ UpdateBundleInfo(BundleCB);
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+ }
+ }
+}
+
+
+VOID
+NdisWanLineDownIndication(
+ PWAN_ADAPTERCB WanAdapterCB,
+ PUCHAR Buffer,
+ ULONG BufferSize
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PNDIS_MAC_LINE_DOWN LineDownInfo = (PNDIS_MAC_LINE_DOWN)Buffer;
+ PLINKCB LinkCB;
+ PBUNDLECB BundleCB;
+ PPROTOCOLCB ProtocolCB;
+ BOOLEAN FreeBundle = FALSE;
+ BOOLEAN FreeLink = FALSE;
+
+ LINKCB_FROM_LINKH(LinkCB, (ULONG)LineDownInfo->NdisLinkContext);
+
+ if (LinkCB == NULL) {
+ return;
+ }
+
+ BundleCB = LinkCB->BundleCB;
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ //
+ // Link is now going down
+ //
+ LinkCB->State = LINK_GOING_DOWN;
+
+ //
+ // If there are not any frames pending on this
+ // link we will go ahead and free it's resources.
+ // If there are frames pending the resources will
+ // be freed in the sendcomplete routine.
+ //
+ if (LinkCB->OutstandingFrames == 0) {
+
+ //
+ // Mark this link as being down
+ //
+ LinkCB->State = LINK_DOWN;
+ FreeLink = TRUE;
+
+ //
+ // Remove the link from the bundle
+ //
+ RemoveLinkFromBundle(BundleCB, LinkCB);
+
+ }
+
+ //
+ // If this bundle's link count has gone to
+ // zero and it is not been routed yet no
+ // user-mode component will be freeing the
+ // resources so we may need to free the
+ // resources.
+ //
+ if (BundleCB->ulLinkCBCount == 0) {
+
+ BundleCB->State = BUNDLE_GOING_DOWN;
+
+ //
+ // If there are not any frames pending on this
+ // bundle so we need to free it's resources now.
+ // If there are frames pending the resources will
+ // be freed in the sendcomplete routine.
+ //
+ if ((BundleCB->OutstandingFrames == 0) &&
+ !(BundleCB->Flags & BUNDLE_ROUTED)) {
+
+ BundleCB->State = BUNDLE_DOWN;
+
+ FreeBundle = TRUE;
+ }
+ }
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ if (FreeLink) {
+ //
+ // Remove this link from the connection table
+ //
+ RemoveLinkFromConnectionTable(LinkCB);
+ NdisWanReturnLinkCB(LinkCB);
+ }
+
+ if (FreeBundle) {
+ //
+ // Remove this bundle from the connection table
+ //
+ RemoveBundleFromConnectionTable(BundleCB);
+ NdisWanReturnBundleCB(BundleCB);
+ }
+
+}
+
+
+VOID
+NdisWanFragmentIndication(
+ PWAN_ADAPTERCB WanAdapterCB,
+ PUCHAR Buffer,
+ ULONG BufferSize
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PNDIS_MAC_FRAGMENT FragmentInfo = (PNDIS_MAC_FRAGMENT)Buffer;
+ PLINKCB LinkCB;
+ PBUNDLECB BundleCB;
+
+ LINKCB_FROM_LINKH(LinkCB, (ULONG)FragmentInfo->NdisLinkContext);
+
+ if (LinkCB == NULL) {
+ return;
+ }
+
+ BundleCB = LinkCB->BundleCB;
+
+ if (BundleCB == NULL) {
+ return;
+ }
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ if (FragmentInfo->Errors & WAN_ERROR_CRC) {
+ LinkCB->LinkStats.CRCErrors++;
+ BundleCB->BundleStats.CRCErrors++;
+ }
+
+ if (FragmentInfo->Errors & WAN_ERROR_FRAMING) {
+ LinkCB->LinkStats.FramingErrors++;
+ BundleCB->BundleStats.FramingErrors++;
+ }
+
+ if (FragmentInfo->Errors & WAN_ERROR_HARDWAREOVERRUN) {
+ LinkCB->LinkStats.SerialOverrunErrors++;
+ BundleCB->BundleStats.SerialOverrunErrors++;
+ }
+
+ if (FragmentInfo->Errors & WAN_ERROR_BUFFEROVERRUN) {
+ LinkCB->LinkStats.BufferOverrunErrors++;
+ BundleCB->BundleStats.BufferOverrunErrors++;
+ }
+
+ if (FragmentInfo->Errors & WAN_ERROR_TIMEOUT) {
+ LinkCB->LinkStats.TimeoutErrors++;
+ BundleCB->BundleStats.TimeoutErrors++;
+ }
+
+ if (FragmentInfo->Errors & WAN_ERROR_ALIGNMENT) {
+ LinkCB->LinkStats.AlignmentErrors++;
+ BundleCB->BundleStats.AlignmentErrors++;
+ }
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+}
+
+VOID
+UpdateBundleInfo(
+ PBUNDLECB BundleCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+ Expects the BundleCB->Lock to be held!
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PLINKCB LinkCB;
+ ULONG SlowestLink;
+ PPROTOCOLCB ProtocolCB, IoProtocolCB;
+#ifdef BANDWIDTH_ON_DEMAND
+ ULONG SecondsInSamplePeriod;
+ ULONG BytesPerSecond;
+ ULONG BytesInSamplePeriod;
+#endif // end of BANDWIDTH_ON_DEMAND
+
+ //
+ // If there are any links attached to this bundlecb we will
+ // update the bundlecb's info
+ //
+ if (BundleCB->ulLinkCBCount != 0) {
+ PBUNDLE_LINE_UP BundleLineUpInfo = &BundleCB->LineUpInfo;
+
+ SlowestLink =
+ BundleLineUpInfo->BundleSpeed = 0;
+ BundleLineUpInfo->usSendWindow = 0;
+ BundleLineUpInfo->Quality = NdisWanReliable;
+
+ //
+ // Walk the LinkCBList and update the bundle's info
+ //
+ for (LinkCB = (PLINKCB)BundleCB->LinkCBList.Flink;
+ (PVOID)LinkCB != (PVOID)&BundleCB->LinkCBList;
+ LinkCB = (PLINKCB)LinkCB->Linkage.Flink) {
+
+ PWAN_ADAPTERCB WanAdapterCB = LinkCB->WanAdapterCB;
+ PNDIS_MAC_LINE_UP LinkLineUpInfo = &LinkCB->LineUpInfo;
+
+ //
+ // Bundle link speed is total of all links. Keep track
+ // of slowest link for multilink recv desc's time to live.
+ //
+ BundleLineUpInfo->BundleSpeed += LinkLineUpInfo->LinkSpeed;
+ if ((LinkLineUpInfo->LinkSpeed < SlowestLink) || (SlowestLink == 0)) {
+ SlowestLink = LinkLineUpInfo->LinkSpeed;
+ }
+
+ //
+ // Bundle send windows is the total of all links
+ //
+ BundleLineUpInfo->usSendWindow += LinkLineUpInfo->SendWindow;
+
+ //
+ // Bundle line quality is the worst of all links
+ //
+ if (BundleLineUpInfo->Quality < LinkLineUpInfo->Quality) {
+ BundleLineUpInfo->Quality = LinkLineUpInfo->Quality;
+ }
+
+ }
+
+#if 0
+ //
+ // Update the time to live for multilink recv desc's. This is in ms and
+ // is the time it would take to receive a complete frame of size MRRU
+ // across the slowest link in the bundle. Value must be a multiple of
+ // 100ms with a minimum value of 1sec. If the slowest link in the bundle is
+ // slower than a 28.8K modem we will increase the timeout value by 2
+ //
+ if (SlowestLink == 0) {
+ SlowestLink = 288;
+ }
+
+ BundleCB->TimeToLive =
+ (BundleCB->FramingInfo.MaxRRecvFrameSize * 1000) /
+ ((SlowestLink * 100) / 8);
+
+ if (SlowestLink < 64) {
+ BundleCB->TimeToLive *= 2;
+ }
+
+ BundleCB->TimeToLive |= 0x3E8;
+ BundleCB->TimeToLive /= 0x64;
+ BundleCB->TimeToLive *= 0x64;
+#endif
+
+ //
+ // Now calculate the % bandwidth that each links contributes to the
+ // bundle.
+ //
+ BundleCB->NextLinkToXmit = (PLINKCB)BundleCB->LinkCBList.Flink;
+
+ for (LinkCB = (PLINKCB)BundleCB->LinkCBList.Flink;
+ (PVOID)LinkCB != (PVOID)&BundleCB->LinkCBList;
+ LinkCB = (PLINKCB)LinkCB->Linkage.Flink) {
+
+ if (LinkCB->LineUpInfo.LinkSpeed != 0) {
+ ULONG n, d, temp;
+
+ d = BundleCB->LineUpInfo.BundleSpeed;
+ n = LinkCB->LineUpInfo.LinkSpeed * 100;
+
+ LinkCB->ulBandwidth = (temp = (n / d)) ? temp : 1;
+ } else {
+ LinkCB->ulBandwidth = 1;
+ }
+
+ if (LinkCB->ulBandwidth > ((PLINKCB)(BundleCB->NextLinkToXmit))->ulBandwidth) {
+ BundleCB->NextLinkToXmit = LinkCB;
+ }
+ }
+
+
+#ifdef BANDWIDTH_ON_DEMAND
+
+ //
+ // Update the BandwidthOnDemand information
+ //
+ SecondsInSamplePeriod = BundleCB->UpperBonDInfo.ulSecondsInSamplePeriod;
+
+ BytesPerSecond = BundleCB->LineUpInfo.BundleSpeed * 100 / 8;
+
+ BytesInSamplePeriod = BytesPerSecond * SecondsInSamplePeriod;
+
+ BundleCB->UpperBonDInfo.ulBytesThreshold = BytesInSamplePeriod *
+ BundleCB->UpperBonDInfo.usPercentBandwidth / 100;
+
+ SecondsInSamplePeriod = BundleCB->LowerBonDInfo.ulSecondsInSamplePeriod;
+
+ BytesPerSecond = BundleCB->LineUpInfo.BundleSpeed * 100 / 8;
+
+ BytesInSamplePeriod = BytesPerSecond * SecondsInSamplePeriod;
+
+ BundleCB->LowerBonDInfo.ulBytesThreshold = BytesInSamplePeriod *
+ BundleCB->LowerBonDInfo.usPercentBandwidth / 100;
+
+#endif // end of BANDWIDTH_ON_DEMAND
+
+ //
+ // We need to do a new lineup to all routed protocols skipping
+ // the IoProtocolCB!
+ //
+ IoProtocolCB = (PPROTOCOLCB)BundleCB->ProtocolCBList.Flink;
+
+ for (ProtocolCB = (PPROTOCOLCB)IoProtocolCB->Linkage.Flink;
+ (PVOID)ProtocolCB != (PVOID)&BundleCB->ProtocolCBList;
+ ProtocolCB = (PPROTOCOLCB)ProtocolCB->Linkage.Flink) {
+
+#ifdef BANDWIDTH_ON_DEMAND
+
+ ProtocolCB->ulByteQuota =
+ (BytesPerSecond * ProtocolCB->usPriority) / 100;
+
+#endif // end of BANDWIDTH_ON_DEMAND
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ DoLineUpToProtocol(ProtocolCB);
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+ }
+
+ }
+}
+
+
+VOID
+AddLinkToBundle(
+ IN PBUNDLECB BundleCB,
+ IN PLINKCB LinkCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NdisAcquireSpinLock(&(BundleCB->Lock));
+
+ InsertTailList(&(BundleCB->LinkCBList), &(LinkCB->Linkage));
+
+ BundleCB->ulLinkCBCount++;
+
+ BundleCB->SendingLinks++;
+
+ LinkCB->BundleCB = BundleCB;
+
+ LinkCB->LastRecvSeqNumber = BundleCB->MinReceivedSeqNumber;
+
+ //
+ // Update BundleCB Info
+ //
+ UpdateBundleInfo(BundleCB);
+
+ NdisReleaseSpinLock(&(BundleCB->Lock));
+}
+
+VOID
+RemoveLinkFromBundle(
+ IN PBUNDLECB BundleCB,
+ IN PLINKCB LinkCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+ Expects the BundleCB->Lock to be held!
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+
+ //
+ // Remove link from the bundle
+ //
+ RemoveEntryList(&LinkCB->Linkage);
+
+ LinkCB->BundleCB = NULL;
+
+ BundleCB->ulLinkCBCount--;
+
+ BundleCB->SendingLinks--;
+
+ //
+ // Update BundleCB LineUp Info
+ //
+ UpdateBundleInfo(BundleCB);
+
+}
diff --git a/private/ntos/ndis/ndiswan/io.c b/private/ntos/ndis/ndiswan/io.c
new file mode 100644
index 000000000..ec757be38
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/io.c
@@ -0,0 +1,4608 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ io.c
+
+Abstract:
+
+ This file contains the procedures to process I/O requests from
+ a User Mode entity. All OS dependent I/O interface functions
+ will be conditionally coded, and will be responsible for translating
+ the I/O functions from the OS format to buffers that are useable by
+ the main I/O handling routine.
+
+
+Author:
+
+ Tony Bell (TonyBe) June 06, 1995
+
+Environment:
+
+ Kernel Mode
+
+Revision History:
+
+ TonyBe 06/06/95 Created
+
+
+--*/
+
+#include "wan.h"
+#include "tcpip.h"
+#include "vjslip.h"
+
+//
+// Local function prototypes
+//
+
+NTSTATUS
+ExecuteIo(
+ IN ULONG ulFuncCode,
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ );
+
+NTSTATUS
+MapConnectionId(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+
+NTSTATUS
+GetBundleHandle(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+
+NTSTATUS
+SetFriendlyName(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+
+NTSTATUS
+ActivateRoute(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+
+NTSTATUS
+BundleLink(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+
+NTSTATUS
+EnumLinksInBundle(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+
+NTSTATUS
+SetProtocolPriority(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+
+NTSTATUS
+SetBandwidthOnDemand(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+
+NTSTATUS
+SetThresholdEvent(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+
+NTSTATUS
+IoSendPacket(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+
+NTSTATUS
+IoReceivePacket(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+
+NTSTATUS
+FlushReceivePacket(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+
+NTSTATUS
+GetStatistics(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+
+NTSTATUS
+SetLinkInfo(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+
+NTSTATUS
+GetLinkInfo(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+
+NTSTATUS
+SetCompressionInfo(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+
+NTSTATUS
+GetCompressionInfo(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+
+NTSTATUS
+SetBridgeInfo(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+
+NTSTATUS
+GetBridgeInfo(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+
+NTSTATUS
+SetVJInfo(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+
+NTSTATUS
+GetVJInfo(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+
+NTSTATUS
+SetCIPXInfo(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+
+NTSTATUS
+GetCIPXInfo(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+
+NTSTATUS
+SetEncryptionInfo(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+
+NTSTATUS
+GetEncryptionInfo(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+NTSTATUS
+GetIdleTime(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+NTSTATUS
+SetDebugInfo(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+NTSTATUS
+EnumActiveBundles(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+NTSTATUS
+GetNdisWanCB(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+NTSTATUS
+EnumAdapterCB(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+NTSTATUS
+GetAdapterCB(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+NTSTATUS
+EnumWanAdapterCB(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+NTSTATUS
+GetWanAdapterCB(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+NTSTATUS
+GetBandwidthUtilization(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+NTSTATUS
+EnumProtocolUtilization(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+NTSTATUS
+FlushThresholdEvents(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+NTSTATUS
+GetWanInfo(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ );
+
+NTSTATUS
+DeactivateRoute(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+);
+
+VOID
+CancelThresholdEvents(
+ VOID
+ );
+
+VOID
+CancelIoReceivePackets(
+ VOID
+ );
+
+VOID
+AddProtocolCBToBundle(
+ PPROTOCOLCB ProtocolCB,
+ PBUNDLECB BundleCB
+ );
+
+VOID
+RemoveProtocolCBFromBundle(
+ PPROTOCOLCB ProtocolCB,
+ PBUNDLECB BundleCB
+ );
+
+#ifdef BANDWIDTH_ON_DEMAND
+VOID
+SortProtocolListByPriority(
+ IN PBUNDLECB BundleCB
+ );
+#endif
+
+VOID
+FlushProtocolPacketQueue(
+ PPROTOCOLCB ProtocolCB
+ );
+
+VOID
+AssignProtocolCBHandle(
+ PBUNDLECB BundleCB,
+ PPROTOCOLCB ProtocolCB
+ );
+
+VOID
+FreeProtocolCBHandle(
+ PBUNDLECB BundleCB,
+ PPROTOCOLCB ProtocolCB
+ );
+
+//
+// End of local function prototypes
+//
+
+IO_DISPATCH_TABLE IoDispatchTable[] =
+{
+ {FUNC_MAP_CONNECTION_ID , MapConnectionId},
+ {FUNC_GET_BUNDLE_HANDLE , GetBundleHandle},
+ {FUNC_SET_FRIENDLY_NAME , SetFriendlyName},
+ {FUNC_ROUTE , ActivateRoute},
+ {FUNC_ADD_LINK_TO_BUNDLE , BundleLink},
+ {FUNC_ENUM_LINKS_IN_BUNDLE , EnumLinksInBundle},
+ {FUNC_SET_PROTOCOL_PRIORITY , SetProtocolPriority},
+ {FUNC_SET_BANDWIDTH_ON_DEMAND, SetBandwidthOnDemand},
+ {FUNC_SET_THRESHOLD_EVENT , SetThresholdEvent},
+ {FUNC_FLUSH_THRESHOLD_EVENTS, FlushThresholdEvents},
+ {FUNC_SEND_PACKET , IoSendPacket},
+ {FUNC_RECEIVE_PACKET , IoReceivePacket},
+ {FUNC_FLUSH_RECEIVE_PACKETS , FlushReceivePacket},
+ {FUNC_GET_STATS , GetStatistics},
+ {FUNC_SET_LINK_INFO , SetLinkInfo},
+ {FUNC_GET_LINK_INFO , GetLinkInfo},
+ {FUNC_SET_COMPRESSION_INFO , SetCompressionInfo},
+ {FUNC_GET_COMPRESSION_INFO , GetCompressionInfo},
+ {FUNC_SET_BRIDGE_INFO , SetBridgeInfo},
+ {FUNC_GET_BRIDGE_INFO , GetBridgeInfo},
+ {FUNC_SET_VJ_INFO , SetVJInfo},
+ {FUNC_GET_VJ_INFO , GetVJInfo},
+ {FUNC_SET_CIPX_INFO , SetCIPXInfo},
+ {FUNC_GET_CIPX_INFO , GetCIPXInfo},
+ {FUNC_SET_ENCRYPTION_INFO , SetEncryptionInfo},
+ {FUNC_GET_ENCRYPTION_INFO , GetEncryptionInfo},
+ {FUNC_SET_DEBUG_INFO , SetDebugInfo},
+ {FUNC_ENUM_ACTIVE_BUNDLES , EnumActiveBundles},
+ {FUNC_GET_NDISWANCB , GetNdisWanCB},
+ {FUNC_GET_ADAPTERCB , GetAdapterCB},
+ {FUNC_GET_WAN_ADAPTERCB , GetWanAdapterCB},
+ {FUNC_GET_BANDWIDTH_UTILIZATION, GetBandwidthUtilization},
+ {FUNC_ENUM_PROTOCOL_UTILIZATION, EnumProtocolUtilization},
+ {FUNC_ENUM_ADAPTERCB , EnumAdapterCB},
+ {FUNC_ENUM_WAN_ADAPTERCB , EnumWanAdapterCB},
+ {FUNC_GET_WAN_INFO , GetWanInfo},
+ {FUNC_GET_IDLE_TIME , GetIdleTime},
+ {FUNC_UNROUTE , DeactivateRoute}
+};
+
+#define MAX_FUNC_CODES sizeof(IoDispatchTable)/sizeof(IO_DISPATCH_TABLE)
+
+#ifdef NT
+
+NTSTATUS
+NdisWanIoctl(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status, ReturnStatus;
+ ULONG ulBytesWritten = 0;
+
+ //
+ // Get current Irp stack location
+ //
+ PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+
+ //
+ // Ioctl Function Code
+ //
+ ULONG ulFuncCode = (pIrpSp->Parameters.DeviceIoControl.IoControlCode >> 2) & 0x00000FFF ;
+ ULONG ulDeviceType = (pIrpSp->Parameters.DeviceIoControl.IoControlCode >> 16) & 0x0000FFFF;
+
+ //
+ // Input buffer, Output buffer, and lengths
+ //
+ PUCHAR pInputBuffer = pIrp->AssociatedIrp.SystemBuffer;
+ PUCHAR pOutputBuffer = pInputBuffer;
+ ULONG ulInputBufferLength = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
+ ULONG ulOutputBufferLength = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("NdisWanIoctl: FunctionCode: 0x%8.8x, MajorFunction: 0x%8.8x, DeviceType: 0x%8.8x",
+ ulFuncCode, pIrpSp->MajorFunction, ulDeviceType));
+ //
+ // Make sure that this is for us
+ //
+ if ((pIrpSp->MajorFunction != IRP_MJ_DEVICE_CONTROL) ||
+ (ulDeviceType != FILE_DEVICE_NDISWAN) ||
+ (pDeviceObject != NdisWanCB.pDeviceObject)) {
+
+ return(NdisWanCB.MajorFunction[pIrpSp->MajorFunction](pDeviceObject, pIrp));
+ }
+
+ //
+ // If this is a function code that requires an irp to be pended and completed
+ // later, we need to queue the irp up somewhere. In order for this to be somewhat
+ // portable we will pass the irp in as the input buffer and store it in a
+ // a structure that it has it's own linkage for queueing.
+ //
+ if ((ulFuncCode == FUNC_SET_THRESHOLD_EVENT) ||
+ (ulFuncCode == FUNC_RECEIVE_PACKET)) {
+
+ pInputBuffer = (PUCHAR)pIrp;
+ }
+
+ Status = ExecuteIo(ulFuncCode,
+ pInputBuffer,
+ ulInputBufferLength,
+ pOutputBuffer,
+ ulOutputBufferLength,
+ &ulBytesWritten);
+
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("NdisWanIoctl: Status: 0x%8.8x, BytesWritten: %d",
+ Status, ulBytesWritten));
+
+ switch (Status) {
+ case STATUS_SUCCESS:
+ ReturnStatus = Status;
+ break;
+
+ case STATUS_PENDING:
+ return(Status);
+
+ case STATUS_INFO_LENGTH_MISMATCH:
+ //
+ // See if this was a request to get size needed for
+ // ioctl.
+ //
+ if (ulOutputBufferLength >= sizeof(ULONG)) {
+
+ *(PULONG)pOutputBuffer = ulBytesWritten;
+ ulBytesWritten = sizeof(ULONG);
+ ReturnStatus =
+ Status = STATUS_SUCCESS;
+ }
+ break;
+
+ default:
+ if (Status < 0xC0000000) {
+ Status += 0xC0100000;
+ }
+ ReturnStatus = STATUS_UNSUCCESSFUL;
+ break;
+ }
+
+ pIrp->IoStatus.Information = ulBytesWritten;
+ pIrp->IoStatus.Status = Status;
+
+ IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
+
+ return(ReturnStatus);
+}
+
+NTSTATUS
+NdisWanIrpStub(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ //
+ // Get current Irp stack location
+ //
+ PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+
+ NdisWanDbgOut(DBG_VERBOSE, DBG_IO, ("NdisWanIrpStub: Entry"));
+
+ //
+ // Make sure that this is for us
+ //
+ if (pDeviceObject != NdisWanCB.pDeviceObject) {
+
+ NdisWanDbgOut(DBG_VERBOSE, DBG_IO, ("NdisWanIrpStub: Exit1"));
+
+ return(NdisWanCB.MajorFunction[pIrpSp->MajorFunction](pDeviceObject, pIrp));
+ }
+
+ pIrp->IoStatus.Information = 0;
+ pIrp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+
+ NdisWanDbgOut(DBG_VERBOSE, DBG_IO, ("NdisWanIrpStub: Exit2"));
+
+ return (STATUS_SUCCESS);
+}
+
+VOID
+NdisWanCancelRoutine(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ BOOLEAN Found = FALSE;
+ WAN_IRQL OldIrql;
+
+ //
+ // Get the pointer to the AsyncEvent from the Irp.
+ //
+ PWAN_ASYNC_EVENT pAsyncEvent;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("NdisWanCancelRoutine: Irp 0x%8.8x", pIrp));
+
+// NdisWanRaiseIrql(&OldIrql);
+
+ //
+ // We need to walk the async event queue looking for
+ // the async event that this irp is associated with
+ //
+ NdisAcquireSpinLock(&RecvPacketQueue.Lock);
+
+ for (pAsyncEvent = (PWAN_ASYNC_EVENT)RecvPacketQueue.List.Flink;
+ (PVOID)pAsyncEvent != (PVOID)&RecvPacketQueue.List;
+ pAsyncEvent = (PWAN_ASYNC_EVENT)pAsyncEvent->Linkage.Flink) {
+
+ if (pAsyncEvent->Context == (PVOID)pIrp) {
+
+ RecvPacketQueue.ulCount--;
+ //
+ // Remove from the list
+ //
+ RemoveEntryList(&pAsyncEvent->Linkage);
+
+ Found = TRUE;
+ ((PNDISWAN_IO_PACKET)(pIrp->AssociatedIrp.SystemBuffer))->usHandleType = CANCELEDHANDLE;
+ break;
+ }
+ }
+
+ NdisReleaseSpinLock(&RecvPacketQueue.Lock);
+
+ if (!Found) {
+
+ NdisAcquireSpinLock(&ThresholdEventQueue.Lock);
+
+ for (pAsyncEvent = (PWAN_ASYNC_EVENT)ThresholdEventQueue.List.Flink;
+ (PVOID)pAsyncEvent != (PVOID)&ThresholdEventQueue.List;
+ pAsyncEvent = (PWAN_ASYNC_EVENT)pAsyncEvent->Linkage.Flink) {
+
+ if (pAsyncEvent->Context == (PVOID)pIrp) {
+
+ ThresholdEventQueue.ulCount--;
+
+ //
+ // Remove from the list
+ //
+ RemoveEntryList(&pAsyncEvent->Linkage);
+
+ Found = TRUE;
+ break;
+ }
+ }
+
+ NdisReleaseSpinLock(&ThresholdEventQueue.Lock);
+ }
+
+ ASSERT(Found);
+
+ //
+ // Free the wan_async_event structure
+ //
+ NdisWanFreeMemory(pAsyncEvent);
+
+// NdisWanLowerIrql(DISPATCH_LEVEL, &OldIrql);
+
+ //
+ // Complete the irp
+ //
+ IoSetCancelRoutine(pIrp, NULL);
+ pIrp->Cancel = TRUE;
+ pIrp->IoStatus.Status = STATUS_CANCELLED;
+ pIrp->IoStatus.Information = 0;
+
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+
+ IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
+
+}
+
+#endif
+
+NTSTATUS
+ExecuteIo(
+ IN ULONG ulFuncCode,
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("ExecuteIo: FuncCode 0x%8.8x", ulFuncCode));
+
+ if (ulFuncCode < MAX_FUNC_CODES) {
+
+ Status = (*IoDispatchTable[ulFuncCode].Function)(pInputBuffer,
+ ulInputBufferLength,
+ pOutputBuffer,
+ ulOutputBufferLength,
+ pulBytesWritten);
+ }
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("ExecuteIo: Status 0x%8.8x", Status));
+
+ return (Status);
+}
+
+NTSTATUS
+MapConnectionId(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+ MapConnectionId
+
+Routine Description:
+
+ This functions takes a WAN Wrapper connection id, finds the corresponding
+ LinkCB and BundleCB, and returns handles to these CB's.
+
+Arguments:
+
+ pInputBuffer - Pointer to the input structure that should be NDISWAN_MAP_CONNECTION_ID
+
+ ulInputBufferLength - Length of input buffer should be sizeof(NDISWAN_MAP_CONNECTION_ID)
+
+ pOutputBuffer - Pointer to the output structure that should be NDISWAN_MAP_CONNNECTION_ID
+
+ ulOutputBufferLength - Length of output buffer should be sizeof(NDISWAN_MAP_CONNECTION_ID)
+
+ pulBytesWritten - Then number of bytes written to the output buffer is returned here
+
+Return Values:
+
+ NDISWAN_ERROR_INVALID_HANDLE
+ STATUS_INFO_LENGTH_MISMATCH
+ STATUS_SUCCESS
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PNDISWAN_MAP_CONNECTION_ID In = (PNDISWAN_MAP_CONNECTION_ID)pInputBuffer;
+ PNDISWAN_MAP_CONNECTION_ID Out = (PNDISWAN_MAP_CONNECTION_ID)pOutputBuffer;
+ ULONG SizeNeeded = sizeof(NDISWAN_MAP_CONNECTION_ID);
+ ULONG i;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("MapConnectionId:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if ((ulInputBufferLength >= SizeNeeded) &&
+ (ulOutputBufferLength >= SizeNeeded)) {
+
+ NdisAcquireSpinLock(&ConnectionTable->Lock);
+
+ //
+ // Find the linkcb that has this connection id and return
+ // both the linkcb index and the bundlecb index
+ //
+ for (i = 0; i < ConnectionTable->ulArraySize; i++) {
+ PLINKCB pLinkCB = *(ConnectionTable->LinkArray + i);
+
+ if ((pLinkCB != NULL) &&
+ (pLinkCB->State == LINK_UP) &&
+ ((pLinkCB->LineUpInfo.ConnectionWrapperID == In->hConnectionID) ||
+ (pLinkCB->hLinkHandle == In->hConnectionID))) {
+ PBUNDLECB BundleCB = pLinkCB->BundleCB;
+
+ //
+ // We have found the right link, return the link and bundle handles
+ //
+ Out->hLinkHandle = pLinkCB->hLinkHandle;
+ Out->hBundleHandle = BUNDLEH_FROM_BUNDLECB(BundleCB);
+ pLinkCB->hLinkContext = In->hLinkContext;
+ BundleCB->hBundleContext = In->hBundleContext;
+
+ //
+ // Copy the friendly name to the link
+ //
+ NdisMoveMemory(pLinkCB->Name,
+ In->szName,
+ (In->ulNameLength > MAX_NAME_LENGTH) ? MAX_NAME_LENGTH : In->ulNameLength);
+ break;
+ }
+ }
+
+ if (i >= ConnectionTable->ulArraySize) {
+ //
+ // We did not find a match to the connection id
+ //
+ Status = NDISWAN_ERROR_INVALID_HANDLE;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("MapConnectionId: ConnectionId not found! ConnectionId: 0x%8.8x",
+ In->hConnectionID));
+ }
+
+ NdisReleaseSpinLock(&ConnectionTable->Lock);
+
+ } else {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("MapConnectionId: Buffer to small: Size: %d, SizeNeeded %d",
+ ulOutputBufferLength, SizeNeeded));
+ }
+
+ return (Status);
+}
+
+
+NTSTATUS
+GetBundleHandle(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+ GetBundleHandle
+
+Routine Description:
+
+ This function takes a handle to a linkcb and returns the handle to the bundlecb
+ that the linkcb belongs to
+
+Arguments:
+
+ pInputBuffer - Pointer to the input structure that should be NDISWAN_GET_BUNDLE_HANDLE
+
+ ulInputBufferLength - Length of the input buffer should be sizeof(NDISWAN_GET_BUNDLE_HANDLE)
+
+ pOutputBuffer - Pointer to the output structure that should be NDISWAN_GET_BUNDLE_HANDLE
+
+ ulOutputBufferLength - Length of the output buffer should be sizeof(NDISWAN_GET_BUNDLE_HANDLE)
+
+Return Values:
+
+ NDISWAN_ERROR_INVALID_HANDLE
+ STATUS_INFO_LENGTH_MISMATCH
+ STATUS_SUCCESS
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PNDISWAN_GET_BUNDLE_HANDLE In = (PNDISWAN_GET_BUNDLE_HANDLE)pInputBuffer;
+ PNDISWAN_GET_BUNDLE_HANDLE Out = (PNDISWAN_GET_BUNDLE_HANDLE)pOutputBuffer;
+ ULONG SizeNeeded = sizeof(NDISWAN_GET_BUNDLE_HANDLE);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("GetBundleHandle:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ NdisAcquireSpinLock(&ConnectionTable->Lock);
+
+ if ((ulInputBufferLength >= SizeNeeded) &&
+ (ulOutputBufferLength >= SizeNeeded)) {
+
+ PLINKCB LinkCB;
+ PBUNDLECB BundleCB;
+
+ LINKCB_FROM_LINKH(LinkCB, In->hLinkHandle);
+
+ //
+ // Get the bundle handle that this link belongs to
+ //
+ if (LinkCB && LinkCB->State == LINK_UP &&
+ (BundleCB = LinkCB->BundleCB) != NULL) {
+ Out->hBundleHandle = BundleCB->hBundleHandle;
+ } else {
+ Status = NDISWAN_ERROR_INVALID_HANDLE;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("GetBundleHandle: Invalid LinkHandle: 0x%8.8x",
+ In->hLinkHandle));
+ }
+
+ } else {
+
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("GetBundleHandle: Buffer to small: Size: %d, SizeNeeded %d",
+ ulOutputBufferLength, SizeNeeded));
+ }
+
+ NdisReleaseSpinLock(&ConnectionTable->Lock);
+
+ return (Status);
+}
+
+
+NTSTATUS
+SetFriendlyName(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+ SetFriendlyName
+
+Routine Description:
+
+ Sets the friendly name of either a bundlecb or a linkcb
+
+Arguments:
+
+ pInputBuffer - Pointer to the input structure that should be NDISWAN_SET_FRIENDLY_NAME
+
+ ulInputBufferLength - Length of the input buffer should be sizeof(NDISWAN_SET_FRIENDLY_NAME)
+
+ pOutputBuffer - Pointer to the output structure that should be NDISWAN_SET_FRIENDLY_NAME
+
+ ulOutputBufferLength - Length of the output buffer should be sizeof(NDISWAN_SET_FRIENDLY_NAME)
+
+Return Values:
+
+ NDISWAN_ERROR_INVALID_HANDLE_TYPE
+ NDISWAN_ERROR_INVALID_HANDLE
+ STATUS_INFO_LENGTH_MISMATCH
+ STATUS_SUCCESS
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PNDISWAN_SET_FRIENDLY_NAME In = (PNDISWAN_SET_FRIENDLY_NAME)pInputBuffer;
+ ULONG SizeNeeded = sizeof(NDISWAN_SET_FRIENDLY_NAME);
+ PLINKCB LinkCB;
+ PBUNDLECB BundleCB;
+ PUCHAR Dest;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("SetFriendlyName:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ NdisAcquireSpinLock(&ConnectionTable->Lock);
+
+ if (ulInputBufferLength >= SizeNeeded) {
+
+ if (In->usHandleType == LINKHANDLE) {
+ //
+ // Is this a link handle
+ //
+ LINKCB_FROM_LINKH(LinkCB, In->hHandle);
+
+ if (LinkCB != NULL && LinkCB->State == LINK_UP) {
+ Dest = LinkCB->Name;
+
+ } else {
+ Status = NDISWAN_ERROR_INVALID_HANDLE;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("SetFriendlyName: Invalid LinkHandle: 0x%8.8x",
+ In->hHandle));
+ }
+
+ } else if (In->usHandleType == BUNDLEHANDLE) {
+ //
+ // Or a bundle handle
+ //
+ BUNDLECB_FROM_BUNDLEH(BundleCB, In->hHandle);
+
+ if (BundleCB != NULL) {
+ Dest = BundleCB->Name;
+
+ } else {
+ Status = NDISWAN_ERROR_INVALID_HANDLE;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("SetFriendlyName: Invalid BundleHandle: 0x%8.8x",
+ In->hHandle));
+ }
+ } else {
+ Status = NDISWAN_ERROR_INVALID_HANDLE_TYPE;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("SetFriendlyName: Invalid HandleType: 0x%4.4x",
+ In->usHandleType));
+ }
+
+ if (Status == STATUS_SUCCESS) {
+
+ //
+ // Copy the friendly name to the link
+ //
+ NdisMoveMemory(Dest,
+ In->szName,
+ (In->ulNameLength > MAX_NAME_LENGTH) ? MAX_NAME_LENGTH : In->ulNameLength);
+ }
+
+ } else {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("SetFriendlyName: Buffer to small: Size: %d, SizeNeeded %d",
+ ulInputBufferLength, SizeNeeded));
+ }
+
+ NdisReleaseSpinLock(&ConnectionTable->Lock);
+
+ return (Status);
+}
+
+
+NTSTATUS
+ActivateRoute(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+ ActivateRoute
+
+Routine Description:
+
+ This function routes the bundle given by hbundlehandle to
+ the protocol give by usprotocoltype.
+
+Arguments:
+
+ pInputBuffer - Pointer to the input structure that should be NDISWAN_ACTIVATE_ROUTE
+
+ ulInputBufferLength - Length of input buffer should be sizeof(NDISWAN_ACTIVATE_ROUTE)
+
+ pOutputBuffer - Pointer to the output structure that should be NDISWAN_ACTIVATE_ROUTE
+
+ ulOutputBufferLength - Length of output buffer should be sizeof(NDISWAN_ACTIVATE_ROUTE)
+
+ pulBytesWritten - Then number of bytes written to the output buffer is returned here
+
+Return Values:
+
+ NDISWAN_ERROR_ALREADY_ROUTED
+ NDISWAN_ERROR_INVALID_HANDLE
+ STATUS_INSUFFICIENT_RESOURCES
+ STATUS_INFO_LENGTH_MISMATCH
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PNDISWAN_ROUTE In = (PNDISWAN_ROUTE)pInputBuffer;
+ PNDISWAN_ROUTE Out = (PNDISWAN_ROUTE)pOutputBuffer;
+ ULONG SizeNeeded = sizeof(NDISWAN_ROUTE);
+ ULONG AllocationSize, i;
+ PBUNDLECB BundleCB;
+ BOOLEAN RouteExists = FALSE;
+ PPROTOCOLCB ProtocolCB;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("ActivateRoute:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulInputBufferLength < SizeNeeded) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("ActivateRoute: Buffer to small: Size: %d, SizeNeeded %d",
+ ulInputBufferLength, SizeNeeded));
+ return (STATUS_INFO_LENGTH_MISMATCH);
+ }
+
+ //
+ // If this is a valid bundle
+ //
+ BUNDLECB_FROM_BUNDLEH(BundleCB, In->hBundleHandle);
+
+ if (BundleCB == NULL) {
+
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("ActivateRoute: Invalid BundleHandle: 0x%8.8x, ProtocolType: 0x%4.4x",
+ In->hBundleHandle, In->usProtocolType));
+
+ return (NDISWAN_ERROR_INVALID_HANDLE);
+ }
+
+ //
+ // Is this a route or unroute call?
+ //
+ if (In->usProtocolType == PROTOCOL_UNROUTE) {
+
+ //
+ // This is a call to unroute
+ //
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ if (!(BundleCB->Flags & BUNDLE_ROUTED)) {
+
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("ActivateRoute: BundleCB 0x%8.8x not routed!",
+ BundleCB));
+ NdisReleaseSpinLock(&BundleCB->Lock);
+ return(NDISWAN_ERROR_INVALID_HANDLE);
+ }
+
+ //
+ // Don't accept anymore sends on this bundle
+ //
+ BundleCB->Flags &= ~BUNDLE_ROUTED;
+
+ //
+ // Flush the protocol packet queues. This could cause us
+ // to complete frames to ndis out of order. Ndis should
+ // handle this.
+ //
+ for (ProtocolCB = (PPROTOCOLCB)BundleCB->ProtocolCBList.Flink;
+ (PVOID)ProtocolCB != (PVOID)&BundleCB->ProtocolCBList;
+ ProtocolCB = (PPROTOCOLCB)ProtocolCB->Linkage.Flink) {
+
+ FlushProtocolPacketQueue(ProtocolCB);
+ }
+
+ //
+ // Do we need to wait for any outstanding frames on the bundle?
+ //
+ if (BundleCB->OutstandingFrames != 0) {
+
+ NdisWanClearSyncEvent(&BundleCB->OutstandingFramesEvent);
+
+ BundleCB->Flags |= FRAMES_PENDING;
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ NdisWanWaitForSyncEvent(&BundleCB->OutstandingFramesEvent);
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ BundleCB->Flags &= ~FRAMES_PENDING;
+ }
+
+ //
+ // For each protocolcb in the bundle's protocolcb table
+ // (except for the i/o protocolcb)
+ //
+ for (i = 1; i < MAX_PROTOCOLS; i++) {
+
+ if (ProtocolCB = BundleCB->ProtocolCBTable[i]) {
+
+ //
+ // Remove the protocolcb from the bundlecb, both the table and
+ // the list.
+ //
+ RemoveProtocolCBFromBundle(ProtocolCB, BundleCB);
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ //
+ // Do a linedown to the protocol
+ //
+ NdisWanClearSyncEvent(&BundleCB->IndicationEvent);
+
+ Status = DoLineDownToProtocol(ProtocolCB);
+
+ if (Status == NDIS_STATUS_PENDING) {
+
+ //
+ // This has been queued because we could not
+ // get the miniport lock. Wait for notification
+ // and pick up the route status.
+ //
+ NdisWanWaitForSyncEvent(&BundleCB->IndicationEvent);
+
+ Status = BundleCB->IndicationStatus;
+ }
+
+ //
+ // Return the protocolcb
+ //
+ NdisWanReturnProtocolCB(ProtocolCB);
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+ }
+ }
+
+ if (BundleCB->State == BUNDLE_GOING_DOWN) {
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ //
+ // Clean up the connection table
+ //
+ RemoveBundleFromConnectionTable(BundleCB);
+
+ //
+ // Return the bundlecb
+ //
+ NdisWanReturnBundleCB(BundleCB);
+
+ } else {
+ NdisReleaseSpinLock(&BundleCB->Lock);
+ }
+
+ } else {
+
+ //
+ // This is a call to route
+ //
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ if (BundleCB->State != BUNDLE_UP) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("ActivateRoute: Invalid BundleState: 0x%8.8x, BundleHandle: 0x%8.8x ProtocolType: 0x%4.4x",
+ BundleCB->State, In->hBundleHandle, In->usProtocolType));
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ return (NDISWAN_ERROR_INVALID_HANDLE);
+ }
+
+ //
+ // First make sure that we don't already have a route to this
+ // protocol type
+ //
+ for (ProtocolCB = (PPROTOCOLCB)BundleCB->ProtocolCBList.Flink;
+ (PVOID)ProtocolCB != (PVOID)&BundleCB->ProtocolCBList;
+ ProtocolCB = (PPROTOCOLCB)ProtocolCB->Linkage.Flink) {
+
+ //
+ // If we already have a route to this protocol type
+ // flag it as already existing
+ //
+ if (ProtocolCB->usProtocolType == In->usProtocolType) {
+ RouteExists = TRUE;
+ break;
+ }
+
+ }
+
+ if (RouteExists) {
+ //
+ // A route already exists for this protocoltype
+ //
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("ActivateRoute: Route already exists: ProtocolType: 0x%2.2x",
+ ProtocolCB->usProtocolType));
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ return (NDISWAN_ERROR_ALREADY_ROUTED);
+ }
+
+ //
+ // Create and initialize a ProtocolCB for this new route
+ //
+ NdisWanGetProtocolCB(&ProtocolCB,
+ In->usProtocolType,
+ In->usBindingNameLength,
+ In->BindingName,
+ In->ulBufferLength,
+ In->Buffer);
+
+ if (ProtocolCB == NULL) {
+ //
+ // Memory allocation failed
+ //
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ return (STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ //
+ // Assign a handle for this protocolcb
+ //
+ AssignProtocolCBHandle(BundleCB, ProtocolCB);
+
+ //
+ // Do a new lineup to protocol
+ //
+ NdisWanClearSyncEvent(&BundleCB->IndicationEvent);
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ Status = DoNewLineUpToProtocol(ProtocolCB);
+
+ if (Status == NDIS_STATUS_PENDING) {
+
+ //
+ // This has been queued because we could not
+ // get the miniport lock. Wait for notification
+ // and pick up the route status.
+ //
+ NdisWanWaitForSyncEvent(&BundleCB->IndicationEvent);
+
+ Status = BundleCB->IndicationStatus;
+
+ }
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ Out->usDeviceNameLength =
+ (ProtocolCB->DeviceName.Length > MAX_NAME_LENGTH) ?
+ MAX_NAME_LENGTH : ProtocolCB->DeviceName.Length;
+
+ NdisMoveMemory(&Out->DeviceName[0],
+ ProtocolCB->DeviceName.Buffer,
+ Out->usDeviceNameLength);
+
+ //
+ // Insert the protocolcb in the bundle's protocolcb table
+ // and list.
+ //
+ AddProtocolCBToBundle(ProtocolCB, BundleCB);
+
+ } else {
+
+ //
+ // Assign a handle for this protocolcb
+ //
+ FreeProtocolCBHandle(BundleCB, ProtocolCB);
+
+ NdisWanReturnProtocolCB(ProtocolCB);
+
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("ActivateRoute: Error during LineUp to ProtocolType: 0x%4.4x",
+ ProtocolCB->usProtocolType));
+
+ }
+ }
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+NTSTATUS
+BundleLink(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+ BundleLink
+
+Routine Description:
+
+ This function bundles the link given by hLinkHandle to the bundle given
+ by hBundlehandle. The resources used by the bundle that the link used
+ to belong to are freed.
+
+Arguments:
+
+ pInputBuffer - Pointer to the input structure that should be NDISWAN_ADD_LINK_TO_BUNDLE
+
+ ulInputBufferLength - Length of input buffer should be sizeof(NDISWAN_ADD_LINK_TO_BUNDLE)
+
+ pOutputBuffer - Pointer to the output structure that should be NDISWAN_ADD_LINK_TO_BUNDLE
+
+ ulOutputBufferLength - Length of output buffer should be sizeof(NDISWAN_ADD_LINK_TO_BUNDLE)
+
+ pulBytesWritten - Then number of bytes written to the output buffer is returned here
+
+Return Values:
+
+ NDISWAN_ERROR_INVALID_HANDLE
+ STATUS_INFO_LENGTH_MISMATCH
+
+--*/
+{
+ ULONG SizeNeeded = sizeof(NDISWAN_ADD_LINK_TO_BUNDLE);
+ PBUNDLECB OldBundleCB, NewBundleCB;
+ PNDISWAN_ADD_LINK_TO_BUNDLE In = (PNDISWAN_ADD_LINK_TO_BUNDLE)pInputBuffer;
+ PLINKCB LinkCB;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("BundleLink:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulInputBufferLength < SizeNeeded) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("BundleLink: Buffer to small: Size: %d, SizeNeeded %d",
+ ulInputBufferLength, SizeNeeded));
+
+ return (STATUS_INFO_LENGTH_MISMATCH);
+ }
+
+ LINKCB_FROM_LINKH(LinkCB, In->hLinkHandle);
+
+ if (LinkCB == NULL || LinkCB->State != LINK_UP) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("BundleLink: Invalid LinkHandle: 0x%8.8x",
+ In->hLinkHandle));
+ return (NDISWAN_ERROR_INVALID_HANDLE);
+ }
+
+ BUNDLECB_FROM_BUNDLEH(NewBundleCB, In->hBundleHandle);
+
+ if (NewBundleCB == NULL) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("BundleLink: Invalid BundleHandle: 0x%8.8x",
+ In->hBundleHandle));
+ return (NDISWAN_ERROR_INVALID_HANDLE);
+ }
+
+ //
+ // Get the Bundle that this link currently belongs to
+ //
+ OldBundleCB = LinkCB->BundleCB;
+
+ if (OldBundleCB == NULL) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("BundleLink: OldBundleCB == NULL! LinkHandle: 0x%8.8x",
+ In->hLinkHandle));
+ return (NDISWAN_ERROR_INVALID_HANDLE);
+
+ }
+
+ if (OldBundleCB == NewBundleCB) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO,
+ ("BundleLink: OldBundle == NewBundle! LinkHandle 0x%8.8x BundleHandle 0x%8.8x",
+ In->hLinkHandle, In->hBundleHandle));
+ return (NDISWAN_ERROR_INVALID_HANDLE);
+
+ }
+
+ NdisAcquireSpinLock(&OldBundleCB->Lock);
+
+ if (OldBundleCB->State != BUNDLE_UP) {
+ NdisReleaseSpinLock(&OldBundleCB->Lock);
+
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("BundleLink: Invalid BundleState: 0x%8.8x",
+ OldBundleCB->State));
+ return (NDISWAN_ERROR_INVALID_HANDLE);
+ }
+
+ NdisReleaseSpinLock(&OldBundleCB->Lock);
+
+ NdisAcquireSpinLock(&NewBundleCB->Lock);
+
+ if (NewBundleCB->State != BUNDLE_UP) {
+ NdisReleaseSpinLock(&NewBundleCB->Lock);
+
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("BundleLink: Invalid BundleState: 0x%8.8x",
+ NewBundleCB->State));
+ return (NDISWAN_ERROR_INVALID_HANDLE);
+ }
+
+ NdisReleaseSpinLock(&NewBundleCB->Lock);
+
+ NdisAcquireSpinLock(&OldBundleCB->Lock);
+
+ if (OldBundleCB->OutstandingFrames != 0) {
+
+ OldBundleCB->State = BUNDLE_GOING_DOWN;
+
+ NdisWanClearSyncEvent(&OldBundleCB->OutstandingFramesEvent);
+
+ OldBundleCB->Flags |= FRAMES_PENDING;
+
+ NdisReleaseSpinLock(&OldBundleCB->Lock);
+
+ NdisWanWaitForSyncEvent(&OldBundleCB->OutstandingFramesEvent);
+
+ NdisAcquireSpinLock(&OldBundleCB->Lock);
+
+ }
+
+ OldBundleCB->State = BUNDLE_DOWN;
+
+ //
+ // Remove the link from the old bundle
+ //
+ RemoveLinkFromBundle(OldBundleCB, LinkCB);
+
+ NdisReleaseSpinLock(&OldBundleCB->Lock);
+
+ RemoveBundleFromConnectionTable(OldBundleCB);
+
+ NdisWanReturnBundleCB(OldBundleCB);
+
+ //
+ // Add the link to the new bundle
+ //
+ AddLinkToBundle(NewBundleCB, LinkCB);
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+NTSTATUS
+EnumLinksInBundle(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PNDISWAN_ENUM_LINKS_IN_BUNDLE In = (PNDISWAN_ENUM_LINKS_IN_BUNDLE)pInputBuffer;
+ PNDISWAN_ENUM_LINKS_IN_BUNDLE Out = (PNDISWAN_ENUM_LINKS_IN_BUNDLE)pOutputBuffer;
+ ULONG SizeNeeded, i;
+ PBUNDLECB BundleCB;
+ PLINKCB LinkCB;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("EnumLinksInBundle:"));
+
+
+ BUNDLECB_FROM_BUNDLEH(BundleCB, In->hBundleHandle);
+
+ if (BundleCB != NULL) {
+
+ SizeNeeded = sizeof(NDISWAN_ENUM_LINKS_IN_BUNDLE) +
+ (sizeof(NDIS_HANDLE) * BundleCB->ulLinkCBCount);
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulOutputBufferLength >= SizeNeeded) {
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ Out->ulNumberOfLinks = BundleCB->ulLinkCBCount;
+
+ //
+ // Walk the list of linkcb's and put the handle for each
+ // cb in the output handle array
+ //
+ i = 0;
+ for (LinkCB = (PLINKCB)BundleCB->LinkCBList.Flink;
+ (PVOID)LinkCB != (PVOID)&BundleCB->LinkCBList;
+ LinkCB = (PLINKCB)LinkCB->Linkage.Flink) {
+
+ Out->hLinkHandleArray[i++] = LinkCB->hLinkHandle;
+ }
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ } else {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("EnumLinksInBundle: Buffer to small: Size: %d, SizeNeeded %d",
+ ulOutputBufferLength, SizeNeeded));
+ }
+
+ } else {
+
+ Status = NDISWAN_ERROR_INVALID_HANDLE;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("EnumLinksInBundle: Invalid BundleHandle: 0x%8.8x",
+ In->hBundleHandle));
+ }
+
+ return (Status);
+}
+
+
+NTSTATUS
+SetProtocolPriority(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+ SetProtocolPriority
+
+Routine Description:
+
+ This function sets the the priority, given by uspriority, for the
+ protocol given by usprotocoltype on the bundle given by hbundlehandle.
+
+Arguments:
+
+ pInputBuffer - Pointer to the input structure that should be NDISWAN_SET_PROTOCOL_PRIORITY
+
+ ulInputBufferLength - Length of input buffer should be sizeof(NDISWAN_SET_PROTOCOL_PRIORITY)
+
+ pOutputBuffer - Pointer to the output structure that should be NDISWAN_SET_PROTOCOL_PRIORITY
+
+ ulOutputBufferLength - Length of output buffer should be sizeof(NDISWAN_SET_PROTOCOL_PRIORITY)
+
+ pulBytesWritten - Then number of bytes written to the output buffer is returned here
+
+Return Values:
+
+ NDISWAN_ERROR_INVALID_HANDLE
+ STATUS_INFO_LENGTH_MISMATCH
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG SizeNeeded = sizeof(NDISWAN_SET_PROTOCOL_PRIORITY);
+ PNDISWAN_SET_PROTOCOL_PRIORITY In = (PNDISWAN_SET_PROTOCOL_PRIORITY)pInputBuffer;
+ PBUNDLECB BundleCB;
+ PPROTOCOLCB ProtocolCB;
+
+#ifdef BANDWIDTH_ON_DEMAND
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("SetProtocolPriority:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulInputBufferLength >= SizeNeeded) {
+ //
+ // If this is a valid bundle handle
+ //
+ BUNDLECB_FROM_BUNDLEH(BundleCB, In->hBundleHandle);
+
+ if (BundleCB != NULL) {
+ ULONG BytesPerSecond;
+
+ //
+ // Walk the protocolcb list looking for this protocol type
+ // and set it's priority level
+ //
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ BundleCB->Flags |= PROTOCOL_PRIORITY;
+
+ BytesPerSecond = (BundleCB->LineUpInfo.BundleSpeed * 100) / 8;
+
+ for (ProtocolCB = (PPROTOCOLCB)BundleCB->ProtocolCBList.Flink;
+ (PVOID)ProtocolCB != (PVOID)&BundleCB->ProtocolCBList;
+ ProtocolCB = (PPROTOCOLCB)ProtocolCB->Linkage.Flink) {
+
+ if (ProtocolCB->usProtocolType == In->usProtocolType) {
+
+ ProtocolCB->usPriority = In->usPriority;
+
+ ProtocolCB->ulByteQuota =
+ (BytesPerSecond * ProtocolCB->usPriority) / 100;
+ break;
+ }
+ }
+
+ //
+ // Sort the list so that highest priorty protcol is at the head
+ //
+ SortProtocolListByPriority(BundleCB);
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ } else {
+ Status = NDISWAN_ERROR_INVALID_HANDLE;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("SetProtocolPriority: Invalid BundleHandle: 0x%8.8x",
+ In->hBundleHandle));
+ }
+
+ } else {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("SetProtocolPriority: Buffer to small: Size: %d, SizeNeeded %d",
+ ulInputBufferLength, SizeNeeded));
+ }
+
+#endif // end of BANDWIDTH_ON_DEMAND
+
+ return (Status);
+}
+
+
+NTSTATUS
+SetBandwidthOnDemand(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+ SetBandwidthOnDemand
+
+Routine Description:
+
+ This function sets the bandwidth on demand parameters for the bundle given by
+ hbundlehandle.
+
+Arguments:
+
+ pInputBuffer - Pointer to the input structure that should be NDISWAN_SET_BANDWIDTH_ON_DEMAND
+
+ ulInputBufferLength - Length of input buffer should be sizeof(NDISWAN_SET_BANDWIDTH_ON_DEMAND)
+
+ pOutputBuffer - Pointer to the output structure that should be NDISWAN_SET_BANDWIDTH_ON_DEMAND
+
+ ulOutputBufferLength - Length of output buffer should be sizeof(NDISWAN_SET_BANDWIDTH_ON_DEMAND)
+
+ pulBytesWritten - Then number of bytes written to the output buffer is returned here
+
+Return Values:
+
+ NDISWAN_ERROR_INVALID_HANDLE
+ STATUS_INFO_LENGTH_MISMATCH
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PBUNDLECB BundleCB;
+ ULONG SizeNeeded = sizeof(NDISWAN_SET_BANDWIDTH_ON_DEMAND);
+ PNDISWAN_SET_BANDWIDTH_ON_DEMAND In = (PNDISWAN_SET_BANDWIDTH_ON_DEMAND)pInputBuffer;
+
+#ifdef BANDWIDTH_ON_DEMAND
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("SetBandwidthOnDemand:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulInputBufferLength >= SizeNeeded) {
+ //
+ // If this is a valid bundle handle
+ //
+ BUNDLECB_FROM_BUNDLEH(BundleCB, In->hBundleHandle);
+
+ if (BundleCB != NULL) {
+
+ WAN_TIME Temp1, Temp2;
+ ULONG SecondsInSamplePeriod;
+ ULONG BytesPerSecond;
+ ULONG BytesInSamplePeriod;
+ PSAMPLE_TABLE UpperSampleTable = &BundleCB->UpperBonDInfo.SampleTable;
+ PSAMPLE_TABLE LowerSampleTable = &BundleCB->LowerBonDInfo.SampleTable;
+
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ //
+ // We need to init the sample period in 100 nanoseconds
+ //
+ NdisWanInitWanTime(&Temp1, MILS_TO_100NANOS);
+ NdisWanInitWanTime(&Temp2, In->ulUpperSamplePeriod);
+ NdisWanMultiplyWanTime(&UpperSampleTable->SamplePeriod,
+ &Temp1,
+ &Temp2);
+
+ NdisWanInitWanTime(&Temp2, In->ulLowerSamplePeriod);
+ NdisWanMultiplyWanTime(&LowerSampleTable->SamplePeriod,
+ &Temp1,
+ &Temp2);
+
+ //
+ // The sample rate is the sample period divided by the number of
+ // samples in the sample array
+ //
+ NdisWanInitWanTime(&Temp1, UpperSampleTable->ulSampleArraySize);
+ NdisWanDivideWanTime(&UpperSampleTable->SampleRate,
+ &UpperSampleTable->SamplePeriod,
+ &Temp1);
+
+ //
+ // The sample rate is the sample period divided by the number of
+ // samples in the sample array
+ //
+ NdisWanInitWanTime(&Temp2, LowerSampleTable->ulSampleArraySize);
+ NdisWanDivideWanTime(&LowerSampleTable->SampleRate,
+ &LowerSampleTable->SamplePeriod,
+ &Temp2);
+
+ //
+ // Convert %bandwidth to Bytes/SamplePeriod
+ // 100bsp * 100 / 8 = BytesPerSecond
+ // BytesPerSecond * SecondsInSamplePeriod = BytesInSamplePeriod
+ // BytesInSamplePeriod * %Bandwidth / 100 = BytesInSamplePeriod
+ //
+ BundleCB->UpperBonDInfo.ulSecondsInSamplePeriod =
+ SecondsInSamplePeriod = In->ulUpperSamplePeriod / 1000;
+
+ BytesPerSecond = BundleCB->LineUpInfo.BundleSpeed * 100 / 8;
+
+ BytesInSamplePeriod = BytesPerSecond * SecondsInSamplePeriod;
+
+ BundleCB->UpperBonDInfo.ulBytesThreshold = BytesInSamplePeriod *
+ In->usUpperThreshold / 100;
+
+ BundleCB->UpperBonDInfo.usPercentBandwidth =
+ In->usUpperThreshold;
+
+ BundleCB->LowerBonDInfo.ulSecondsInSamplePeriod =
+ SecondsInSamplePeriod = In->ulLowerSamplePeriod / 1000;
+
+ BytesInSamplePeriod = BytesPerSecond * SecondsInSamplePeriod;
+
+ BundleCB->LowerBonDInfo.ulBytesThreshold = BytesInSamplePeriod *
+ In->usLowerThreshold / 100;
+
+ BundleCB->LowerBonDInfo.usPercentBandwidth =
+ In->usLowerThreshold;
+
+ BundleCB->UpperBonDInfo.State = BonDIdle;
+ BundleCB->LowerBonDInfo.State = BonDIdle;
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ } else {
+ Status = NDISWAN_ERROR_INVALID_HANDLE;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("SetBandwidthOnDemand: Invalid BundleHandle: 0x%8.8x",
+ In->hBundleHandle));
+ }
+
+ } else {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("SetBandwidthOnDemand: Buffer to small: Size: %d, SizeNeeded %d",
+ ulInputBufferLength, SizeNeeded));
+ }
+
+#endif // end of BANDWIDTH_ON_DEMAND
+
+ return (Status);
+}
+
+
+#ifdef NT
+NTSTATUS
+SetThresholdEvent(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+ SetThresholdEvent
+
+Routine Description:
+
+ This function queues up an asyncevent for bandwidth on demand
+ events.
+
+Arguments:
+
+ pInputBuffer - Pointer to the input structure that should be WAN_ASYNC_EVENT
+
+ ulInputBufferLength - Length of input buffer should be sizeof(WAN_ASYNC_EVENT)
+
+ pOutputBuffer - Pointer to the output structure that should be WAN_ASYNC_EVENT
+
+ ulOutputBufferLength - Length of output buffer should be sizeof(WAN_ASYNC_EVENT)
+
+ pulBytesWritten - Then number of bytes written to the output buffer is returned here
+
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_PENDING;
+ ULONG SizeNeeded = sizeof(NDISWAN_SET_THRESHOLD_EVENT);
+ PWAN_ASYNC_EVENT pAsyncEvent;
+ PIRP pIrp = (PIRP)pInputBuffer;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("SetThresholdEvent:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulInputBufferLength >= SizeNeeded) {
+
+ NdisWanAllocateMemory(&pAsyncEvent, sizeof(WAN_ASYNC_EVENT));
+
+ if (pAsyncEvent != NULL) {
+ KIRQL Irql;
+
+ //
+ // The IRP was pended so setup a cancel routine and let the
+ // i/o subsystem know about the pend.
+ //
+ IoAcquireCancelSpinLock(&Irql);
+
+ IoMarkIrpPending(pIrp);
+
+ //
+ // Setup the structure
+ //
+ pAsyncEvent->Context = (PVOID)pIrp;
+
+ InsertTailGlobalList(ThresholdEventQueue, &(pAsyncEvent->Linkage));
+
+ IoSetCancelRoutine(pIrp, NdisWanCancelRoutine);
+
+ IoReleaseCancelSpinLock(Irql);
+
+ } else {
+
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("SetThresholdEvent: Failed to allocate asyncevent storage"));
+ }
+
+ } else {
+
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("SetThresholdEvent: Buffer to small: Size: %d, SizeNeeded %d",
+ ulInputBufferLength, SizeNeeded));
+ }
+
+ return (Status);
+}
+#endif
+
+NTSTATUS
+FlushThresholdEvents(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("FlushThresholdEvents:"));
+
+ CancelThresholdEvents();
+
+ return (Status);
+}
+
+NTSTATUS
+IoSendPacket(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG SizeNeeded = sizeof(NDISWAN_IO_PACKET);
+ PNDISWAN_IO_PACKET In = (PNDISWAN_IO_PACKET)pInputBuffer;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("IoSendPacket:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulInputBufferLength >= SizeNeeded) {
+
+ //
+ // Verify the handle is a valid link or bundle handle
+ //
+ if (IsHandleValid(In->usHandleType, In->hHandle)) {
+ //
+ // Queue an Ndis Packet for this send
+ //
+ Status = BuildIoPacket(In, FALSE);
+
+ } else {
+ Status = NDISWAN_ERROR_INVALID_HANDLE;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("IoSendPacket: Invalid Handle: 0x%8.8x, HandleType: 0x%4.4x",
+ In->hHandle, In->usHandleType));
+ }
+
+ } else {
+
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("IoSendPacket: Buffer to small: Size: %d, SizeNeeded %d",
+ ulInputBufferLength, SizeNeeded));
+ }
+
+ return (Status);
+}
+
+
+#ifdef NT
+NTSTATUS
+IoReceivePacket(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_PENDING;
+ ULONG SizeNeeded = sizeof(NDISWAN_IO_PACKET);
+ PWAN_ASYNC_EVENT pAsyncEvent;
+ PIRP pIrp = (PIRP)pInputBuffer;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("IoReceivePacket:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulInputBufferLength >= SizeNeeded) {
+
+ NdisWanAllocateMemory(&pAsyncEvent, sizeof(WAN_ASYNC_EVENT));
+
+ if (pAsyncEvent != NULL) {
+ KIRQL Irql;
+
+ //
+ // The IRP was pended so setup a cancel routine and let the
+ // i/o subsystem know about the pend.
+ //
+ IoAcquireCancelSpinLock(&Irql);
+
+ IoMarkIrpPending(pIrp);
+
+ //
+ // Setup the structure
+ //
+ pAsyncEvent->Context = (PVOID)pIrp;
+
+ InsertTailGlobalList(RecvPacketQueue, &(pAsyncEvent->Linkage));
+
+ IoSetCancelRoutine(pIrp, NdisWanCancelRoutine);
+
+ IoReleaseCancelSpinLock(Irql);
+
+ } else {
+
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("IoReceivePacket: Failed to allocate asyncevent storage"));
+ }
+
+ } else {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("IoReceivePacket: Buffer to small: Size: %d, SizeNeeded %d",
+ ulInputBufferLength, SizeNeeded));
+ }
+
+ return (Status);
+}
+#endif
+
+
+NTSTATUS
+FlushReceivePacket(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("FlushReceivePacket:"));
+
+ CancelIoReceivePackets();
+
+ return (Status);
+}
+
+
+NTSTATUS
+GetStatistics(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG SizeNeeded = sizeof(NDISWAN_GET_STATS);
+ PNDISWAN_GET_STATS In = (PNDISWAN_GET_STATS)pInputBuffer;
+ PNDISWAN_GET_STATS Out = (PNDISWAN_GET_STATS)pOutputBuffer;
+ PBUNDLECB BundleCB;
+ PLINKCB LinkCB;
+ NDIS_REQUEST NdisRequest;
+ NDIS_WAN_GET_STATS_INFO WanMiniportStats;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("GetStatistics:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulOutputBufferLength < SizeNeeded) {
+
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("GetStatistics: Buffer to small: Size: %d, SizeNeeded %d",
+ ulOutputBufferLength, SizeNeeded));
+
+ return (STATUS_INFO_LENGTH_MISMATCH);
+ }
+
+ NdisZeroMemory(&Out->Stats, sizeof(Out->Stats));
+
+ if (In->usHandleType == LINKHANDLE) {
+
+ //
+ // Looking for link stats
+ //
+ LINKCB_FROM_LINKH(LinkCB, In->hHandle);
+
+ if (LinkCB == NULL || LinkCB->State != LINK_UP) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("GetStatistics: Invalid LinkHandle: 0x%8.8x",
+ In->hHandle));
+
+ return (NDISWAN_ERROR_INVALID_HANDLE);
+ }
+
+ BundleCB = BUNDLECB_FROM_LINKCB(LinkCB);
+
+ if (BundleCB == NULL) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("GetStatistics: Invalid BundleHandle: 0x%8.8x",
+ In->hHandle));
+
+ return (NDISWAN_ERROR_INVALID_HANDLE);
+ }
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ //
+ // Copy the stats over
+ //
+ NdisMoveMemory((PUCHAR)&Out->Stats.LinkStats,
+ (PUCHAR)&LinkCB->LinkStats,
+ sizeof(WAN_STATS));
+
+ //
+ // Copy the stats over
+ //
+ NdisMoveMemory((PUCHAR)&Out->Stats.BundleStats,
+ (PUCHAR)&BundleCB->BundleStats,
+ sizeof(WAN_STATS));
+
+ //
+ // If the wan miniport is doing framing or compression we
+ // need to get stats from it.
+ //
+ if ((BundleCB->FramingInfo.SendFramingBits & PASS_THROUGH_MODE) ||
+ ((BundleCB->SendCompInfo.MSCompType == 0 &&
+ BundleCB->RecvCompInfo.MSCompType == 0) &&
+ (BundleCB->SendCompInfo.CompType != COMPTYPE_NONE ||
+ BundleCB->RecvCompInfo.CompType != COMPTYPE_NONE))) {
+ PWAN_ADAPTERCB WanAdapterCB = LinkCB->WanAdapterCB;
+
+ NdisZeroMemory(&WanMiniportStats, sizeof(NDIS_WAN_GET_STATS_INFO));
+
+ WanMiniportStats.NdisLinkHandle = LinkCB->LineUpInfo.NdisLinkHandle;
+
+ //
+ // Submit this to the WAN Miniport
+ //
+ NdisRequest.RequestType = NdisRequestQueryInformation;
+ NdisRequest.DATA.QUERY_INFORMATION.Oid = OID_WAN_GET_STATS_INFO;
+ NdisRequest.DATA.QUERY_INFORMATION.InformationBuffer = &WanMiniportStats;
+ NdisRequest.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(NDIS_WAN_GET_STATS_INFO);
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ if (NdisWanSubmitNdisRequest(WanAdapterCB,
+ &NdisRequest,
+ SYNC,
+ NDISWAN) == NDIS_STATUS_SUCCESS){
+
+ //
+ // Copy the stats over
+ //
+ NdisMoveMemory((PUCHAR)&Out->Stats.LinkStats,
+ (PUCHAR)&WanMiniportStats.BytesSent,
+ sizeof(WAN_STATS));
+
+ //
+ // Copy the stats over
+ //
+ NdisMoveMemory((PUCHAR)&Out->Stats.BundleStats,
+ (PUCHAR)&WanMiniportStats.BytesSent,
+ sizeof(WAN_STATS));
+
+ }
+ } else {
+ NdisReleaseSpinLock(&BundleCB->Lock);
+ }
+
+ } else if (In->usHandleType == BUNDLEHANDLE) {
+
+ //
+ // Looking for bundle stats
+ //
+ BUNDLECB_FROM_BUNDLEH(BundleCB, In->hHandle);
+
+ if (BundleCB == NULL) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("GetStatistics: Invalid BundleHandle: 0x%8.8x",
+ In->hHandle));
+
+ return (NDISWAN_ERROR_INVALID_HANDLE);
+ }
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ //
+ // Copy the stats over
+ //
+ NdisMoveMemory((PUCHAR)&Out->Stats.BundleStats,
+ (PUCHAR)&BundleCB->BundleStats,
+ sizeof(WAN_STATS));
+
+ //
+ // If the wan miniport is doing framing or compression we
+ // need to get stats from it.
+ //
+ if ((BundleCB->LinkCBList.Flink != &BundleCB->LinkCBList) &&
+ ((BundleCB->FramingInfo.SendFramingBits & PASS_THROUGH_MODE) ||
+ ((BundleCB->SendCompInfo.MSCompType == 0 &&
+ BundleCB->RecvCompInfo.MSCompType == 0) &&
+ (BundleCB->SendCompInfo.CompType != COMPTYPE_NONE ||
+ BundleCB->RecvCompInfo.CompType != COMPTYPE_NONE)))) {
+ PWAN_ADAPTERCB WanAdapterCB;
+
+ LinkCB = (PLINKCB)BundleCB->LinkCBList.Flink;
+
+ NdisZeroMemory(&WanMiniportStats, sizeof(NDIS_WAN_GET_STATS_INFO));
+
+ //
+ // If a miniport is doing it's own compression for this release we will
+ // expect that multilink is not allowed on the connection so the bundle
+ // will only have one link.
+ //
+
+ WanMiniportStats.NdisLinkHandle = LinkCB->LineUpInfo.NdisLinkHandle;
+ WanAdapterCB = LinkCB->WanAdapterCB;
+
+ //
+ // Submit this to the WAN Miniport
+ //
+ NdisRequest.RequestType = NdisRequestQueryInformation;
+ NdisRequest.DATA.QUERY_INFORMATION.Oid = OID_WAN_GET_STATS_INFO;
+ NdisRequest.DATA.QUERY_INFORMATION.InformationBuffer = &WanMiniportStats;
+ NdisRequest.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(NDIS_WAN_GET_STATS_INFO);
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ if (NdisWanSubmitNdisRequest(WanAdapterCB,
+ &NdisRequest,
+ SYNC,
+ NDISWAN) == NDIS_STATUS_SUCCESS){
+
+ //
+ // Copy the stats over
+ //
+ NdisMoveMemory((PUCHAR)&Out->Stats.BundleStats,
+ (PUCHAR)&WanMiniportStats.BytesSent,
+ sizeof(WAN_STATS));
+
+ }
+ } else {
+ NdisReleaseSpinLock(&BundleCB->Lock);
+ }
+
+ } else {
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("GetStatistics: Invalid handle type: 0x%4.4x",
+ In->usHandleType));
+
+ return (NDISWAN_ERROR_INVALID_HANDLE_TYPE);
+ }
+
+ return (STATUS_SUCCESS);
+}
+
+
+NTSTATUS
+SetLinkInfo(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG SizeNeeded = sizeof(NDISWAN_SET_LINK_INFO);
+ PLINKCB LinkCB;
+ PBUNDLECB BundleCB;
+ NDIS_REQUEST NdisRequest;
+ PNDISWAN_SET_LINK_INFO In = (PNDISWAN_SET_LINK_INFO)pInputBuffer;
+ NDIS_WAN_SET_LINK_INFO WanMiniportLinkInfo;
+ PWAN_LINK_INFO LinkInfo;
+ PWAN_ADAPTERCB WanAdapterCB;
+ PLINKCB TempLinkCB;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("SetLinkInfo:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulInputBufferLength >= SizeNeeded) {
+
+ LINKCB_FROM_LINKH(LinkCB, In->hLinkHandle);
+
+ if (LinkCB == NULL || LinkCB->State != LINK_UP) {
+ return (NDISWAN_ERROR_INVALID_HANDLE);
+ }
+
+ LinkInfo = &LinkCB->LinkInfo;
+ WanAdapterCB = LinkCB->WanAdapterCB;
+
+ NdisZeroMemory(&WanMiniportLinkInfo, sizeof (NDIS_WAN_SET_LINK_INFO));
+
+ //
+ // Copy into buffer to be sent to WAN Miniport this
+ // skips over the LinkHandle in the NDIS_WAN_SET_LINK_INFO
+ // structure.
+ //
+ WanMiniportLinkInfo.NdisLinkHandle = LinkCB->LineUpInfo.NdisLinkHandle;
+ WanMiniportLinkInfo.MaxSendFrameSize = In->LinkInfo.MaxSendFrameSize;
+ WanMiniportLinkInfo.MaxRecvFrameSize = In->LinkInfo.MaxRecvFrameSize;
+ WanMiniportLinkInfo.SendFramingBits = In->LinkInfo.SendFramingBits;
+ WanMiniportLinkInfo.RecvFramingBits = In->LinkInfo.RecvFramingBits;
+ WanMiniportLinkInfo.SendCompressionBits = In->LinkInfo.SendCompressionBits;
+ WanMiniportLinkInfo.RecvCompressionBits = In->LinkInfo.RecvCompressionBits;
+ WanMiniportLinkInfo.SendACCM = In->LinkInfo.SendACCM;
+ WanMiniportLinkInfo.RecvACCM = In->LinkInfo.RecvACCM;
+
+ //
+ // Submit this to the WAN Miniport
+ //
+ NdisRequest.RequestType = NdisRequestSetInformation;
+ NdisRequest.DATA.QUERY_INFORMATION.Oid = OID_WAN_SET_LINK_INFO;
+ NdisRequest.DATA.QUERY_INFORMATION.InformationBuffer = &WanMiniportLinkInfo;
+ NdisRequest.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(NDIS_WAN_SET_LINK_INFO);
+
+ Status = NdisWanSubmitNdisRequest(LinkCB->WanAdapterCB,
+ &NdisRequest,
+ SYNC,
+ NDISWAN);
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ BundleCB = BUNDLECB_FROM_LINKCB(LinkCB);
+
+ if (BundleCB == NULL) {
+ return (NDISWAN_ERROR_INVALID_HANDLE);
+ }
+
+ //
+ // Copy info into our linkcb
+ //
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ LinkInfo->MaxSendFrameSize = In->LinkInfo.MaxSendFrameSize;
+ LinkInfo->MaxRecvFrameSize = In->LinkInfo.MaxRecvFrameSize;
+ LinkInfo->SendFramingBits = In->LinkInfo.SendFramingBits;
+ LinkInfo->RecvFramingBits = In->LinkInfo.RecvFramingBits;
+ LinkInfo->SendCompressionBits = In->LinkInfo.SendCompressionBits;
+ LinkInfo->RecvCompressionBits = In->LinkInfo.RecvCompressionBits;
+ LinkInfo->SendACCM = In->LinkInfo.SendACCM;
+ LinkInfo->RecvACCM = In->LinkInfo.RecvACCM;
+ LinkInfo->MaxRRecvFrameSize = In->LinkInfo.MaxRRecvFrameSize;
+ LinkInfo->MaxRSendFrameSize = In->LinkInfo.MaxRSendFrameSize;
+
+ //
+ // We need to set our bundle framing based on the framing for
+ // each link in the bundle so we will walk the linkcb list
+ // and | in each link's framing bits into the bundle.
+ //
+ //
+ BundleCB->FramingInfo.SendFramingBits = 0;
+ BundleCB->FramingInfo.RecvFramingBits = 0;
+
+ for (TempLinkCB = (PLINKCB)BundleCB->LinkCBList.Flink;
+ (PVOID)TempLinkCB != (PVOID)&BundleCB->LinkCBList;
+ TempLinkCB = (PLINKCB)TempLinkCB->Linkage.Flink) {
+
+ BundleCB->FramingInfo.SendFramingBits |= TempLinkCB->LinkInfo.SendFramingBits;
+ BundleCB->FramingInfo.RecvFramingBits |= TempLinkCB->LinkInfo.RecvFramingBits;
+ }
+
+ BundleCB->FramingInfo.MaxRSendFrameSize = LinkInfo->MaxRSendFrameSize;
+
+ //
+ // Since I use the receive frame size for memory allocation.
+ //
+ BundleCB->FramingInfo.MaxRRecvFrameSize = (LinkInfo->MaxRRecvFrameSize) ?
+ LinkInfo->MaxRRecvFrameSize : DEFAULT_MAX_MRRU;
+
+ //
+ // If VJ header compression has been negotiated allocate
+ // and initialize resources.
+ //
+ if (BundleCB->FramingInfo.SendFramingBits & SLIP_VJ_COMPRESSION ||
+ BundleCB->FramingInfo.SendFramingBits & SLIP_VJ_AUTODETECT ||
+ BundleCB->FramingInfo.RecvFramingBits & SLIP_VJ_COMPRESSION ||
+ BundleCB->FramingInfo.RecvFramingBits & SLIP_VJ_AUTODETECT) {
+
+ Status = sl_compress_init(&BundleCB->VJCompress, MAX_VJ_STATES);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("Error allocating VJ Info!"));
+ }
+ }
+
+ //
+ // Configure multilink variables if needed
+ //
+ if (BundleCB->FramingInfo.SendFramingBits & PPP_MULTILINK_FRAMING) {
+ if (BundleCB->FramingInfo.SendFramingBits & PPP_SHORT_SEQUENCE_HDR_FORMAT) {
+ BundleCB->SendSeqMask = SHORT_SEQ_MASK;
+ BundleCB->SendSeqTest = TEST_SHORT_SEQ;
+ } else {
+ BundleCB->SendSeqMask = LONG_SEQ_MASK;
+ BundleCB->SendSeqTest = TEST_LONG_SEQ;
+ }
+ }
+
+ if (BundleCB->FramingInfo.RecvFramingBits & PPP_MULTILINK_FRAMING) {
+ if (BundleCB->FramingInfo.RecvFramingBits & PPP_SHORT_SEQUENCE_HDR_FORMAT) {
+ BundleCB->RecvSeqMask = SHORT_SEQ_MASK;
+ BundleCB->RecvSeqTest = TEST_SHORT_SEQ;
+ } else {
+ BundleCB->RecvSeqMask = LONG_SEQ_MASK;
+ BundleCB->RecvSeqTest = TEST_LONG_SEQ;
+ }
+ }
+
+ BundleCB->RecvDescMax = ((((BundleCB->LineUpInfo.BundleSpeed * 100) / 8) * 3) /
+ BundleCB->FramingInfo.MaxRRecvFrameSize) +
+ BundleCB->ulLinkCBCount;
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ } else {
+ Status = STATUS_UNSUCCESSFUL;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("SetLinkInfo: Error submitting request to Wan Miniport!"));
+ }
+
+ } else {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("SetLinkInfo: Buffer to small: Size: %d, SizeNeeded %d",
+ ulInputBufferLength, SizeNeeded));
+ }
+
+ return (Status);
+}
+
+
+NTSTATUS
+GetLinkInfo(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG SizeNeeded = sizeof(NDISWAN_GET_LINK_INFO);
+ PNDISWAN_GET_LINK_INFO In = (PNDISWAN_GET_LINK_INFO)pInputBuffer;
+ PNDISWAN_GET_LINK_INFO Out = (PNDISWAN_GET_LINK_INFO)pOutputBuffer;
+ PLINKCB LinkCB;
+ NDIS_REQUEST NdisRequest;
+ NDIS_WAN_GET_LINK_INFO WanMiniportLinkInfo;
+ PWAN_LINK_INFO LinkInfo;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("GetLinkInfo:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulOutputBufferLength >= SizeNeeded) {
+
+ LINKCB_FROM_LINKH(LinkCB, In->hLinkHandle);
+
+ if (LinkCB == NULL || LinkCB->State != LINK_UP) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("GetLinkInfo: Invalid LinkHandle: 0x%8.8x",
+ In->hLinkHandle));
+ return (NDISWAN_ERROR_INVALID_HANDLE);
+ }
+
+ LinkInfo = &LinkCB->LinkInfo;
+
+ NdisZeroMemory(&WanMiniportLinkInfo, sizeof (NDIS_WAN_GET_LINK_INFO));
+
+ //
+ // Setup the link context for this request
+ //
+ WanMiniportLinkInfo.NdisLinkHandle = LinkCB->LineUpInfo.NdisLinkHandle;
+
+ //
+ // Submit this to the WAN Miniport
+ //
+ NdisRequest.RequestType = NdisRequestQueryInformation;
+ NdisRequest.DATA.QUERY_INFORMATION.Oid = OID_WAN_GET_LINK_INFO;
+ NdisRequest.DATA.QUERY_INFORMATION.InformationBuffer = &WanMiniportLinkInfo;
+ NdisRequest.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(NDIS_WAN_GET_LINK_INFO);
+
+ Status = NdisWanSubmitNdisRequest(LinkCB->WanAdapterCB,
+ &NdisRequest,
+ SYNC,
+ NDISWAN);
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ LinkInfo->MaxSendFrameSize = WanMiniportLinkInfo.MaxSendFrameSize;
+ LinkInfo->MaxRecvFrameSize = WanMiniportLinkInfo.MaxRecvFrameSize;
+ LinkInfo->SendFramingBits = WanMiniportLinkInfo.SendFramingBits;
+ LinkInfo->RecvFramingBits = WanMiniportLinkInfo.RecvFramingBits;
+ LinkInfo->SendCompressionBits = WanMiniportLinkInfo.SendCompressionBits;
+ LinkInfo->RecvCompressionBits = WanMiniportLinkInfo.RecvCompressionBits;
+ LinkInfo->SendACCM = WanMiniportLinkInfo.SendACCM;
+ LinkInfo->RecvACCM = WanMiniportLinkInfo.RecvACCM;
+
+ //
+ // Fill Recv and Send MRRU
+ //
+ LinkInfo->MaxRSendFrameSize = MIN_SEND;
+
+ LinkInfo->MaxRRecvFrameSize = MAX_MRRU;
+
+ NdisMoveMemory(&Out->LinkInfo,
+ LinkInfo,
+ sizeof(WAN_LINK_INFO));
+
+ Out->hLinkHandle = LinkCB->hLinkHandle;
+
+ } else {
+ Status = STATUS_UNSUCCESSFUL;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("GetLinkInfo: Error submitting request to Wan Miniport!"));
+ }
+
+ } else {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("GetLinkInfo: Buffer to small: Size: %d, SizeNeeded %d",
+ ulOutputBufferLength, SizeNeeded));
+ }
+
+ return (Status);
+}
+
+
+NTSTATUS
+SetCompressionInfo(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG SizeNeeded = sizeof(NDISWAN_SET_COMPRESSION_INFO);
+ PNDISWAN_SET_COMPRESSION_INFO In = (PNDISWAN_SET_COMPRESSION_INFO)pInputBuffer;
+ NDIS_REQUEST NdisRequest;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("SetCompressionInfo:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulInputBufferLength >= SizeNeeded) {
+ PLINKCB LinkCB;
+ PBUNDLECB BundleCB;
+ NDIS_WAN_SET_COMP_INFO WanCompressionInfo;
+
+ LINKCB_FROM_LINKH(LinkCB, In->hLinkHandle);
+
+ if (LinkCB == NULL || LinkCB->State != LINK_UP) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("SetCompressionInfo: Invalid LinkHandle: 0x%8.8x",
+ In->hLinkHandle));
+ return (NDISWAN_ERROR_INVALID_HANDLE);
+ }
+
+ NdisZeroMemory(&WanCompressionInfo, sizeof(NDIS_WAN_SET_COMP_INFO));
+
+ WanCompressionInfo.NdisLinkHandle =
+ LinkCB->LineUpInfo.NdisLinkHandle;
+
+ WanCompressionInfo.SendCapabilities.MSCompType =
+ In->SendCapabilities.MSCompType;
+
+ WanCompressionInfo.SendCapabilities.CompType =
+ In->SendCapabilities.CompType;
+
+ WanCompressionInfo.SendCapabilities.CompLength =
+ In->SendCapabilities.CompLength;
+
+ if (In->SendCapabilities.CompType == 0) {
+ NdisMoveMemory(&WanCompressionInfo.SendCapabilities.Proprietary,
+ &In->SendCapabilities.Proprietary,
+ sizeof(In->SendCapabilities.Proprietary));
+ } else {
+ NdisMoveMemory(&WanCompressionInfo.SendCapabilities.Public,
+ &In->SendCapabilities.Public,
+ sizeof(In->SendCapabilities.Public));
+ }
+
+ WanCompressionInfo.RecvCapabilities.MSCompType =
+ In->RecvCapabilities.MSCompType;
+
+ WanCompressionInfo.RecvCapabilities.CompType =
+ In->RecvCapabilities.CompType;
+
+ WanCompressionInfo.RecvCapabilities.CompLength =
+ In->RecvCapabilities.CompLength;
+
+ if (In->RecvCapabilities.CompType == 0) {
+ NdisMoveMemory(&WanCompressionInfo.RecvCapabilities.Proprietary,
+ &In->RecvCapabilities.Proprietary,
+ sizeof(In->RecvCapabilities.Proprietary));
+ } else {
+ NdisMoveMemory(&WanCompressionInfo.RecvCapabilities.Public,
+ &In->RecvCapabilities.Public,
+ sizeof(In->RecvCapabilities.Public));
+ }
+
+ //
+ // Submit this to the WAN Miniport
+ //
+ NdisRequest.RequestType = NdisRequestSetInformation;
+ NdisRequest.DATA.QUERY_INFORMATION.Oid = OID_WAN_SET_COMP_INFO;
+ NdisRequest.DATA.QUERY_INFORMATION.InformationBuffer = &WanCompressionInfo;
+ NdisRequest.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(NDIS_WAN_SET_COMP_INFO);
+
+ NdisWanSubmitNdisRequest(LinkCB->WanAdapterCB,
+ &NdisRequest,
+ SYNC,
+ NDISWAN);
+
+ BundleCB = BUNDLECB_FROM_LINKCB(LinkCB);
+
+ if (BundleCB == NULL) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("SetCompressionInfo: Invalid LinkHandle: 0x%8.8x",
+ In->hLinkHandle));
+ return (NDISWAN_ERROR_INVALID_HANDLE);
+
+ }
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ //
+ // Store the compression info in our bundlecb
+ //
+ NdisMoveMemory(&BundleCB->SendCompInfo,
+ &In->SendCapabilities,
+ sizeof(COMPRESS_INFO));
+
+ NdisMoveMemory(&BundleCB->RecvCompInfo,
+ &In->RecvCapabilities,
+ sizeof(COMPRESS_INFO));
+
+ WanAllocateCCP(BundleCB);
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ } else {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("SetCompressionInfo: Buffer to small: Size: %d, SizeNeeded %d",
+ ulInputBufferLength, SizeNeeded));
+ }
+
+ return (Status);
+}
+
+
+NTSTATUS
+GetCompressionInfo(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG SizeNeeded = sizeof(NDISWAN_GET_COMPRESSION_INFO);
+ PNDISWAN_GET_COMPRESSION_INFO In = (PNDISWAN_GET_COMPRESSION_INFO)pInputBuffer;
+ PNDISWAN_GET_COMPRESSION_INFO Out = (PNDISWAN_GET_COMPRESSION_INFO)pOutputBuffer;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("GetCompressionInfo:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulOutputBufferLength >= SizeNeeded) {
+ PLINKCB LinkCB;
+ NDIS_REQUEST NdisRequest;
+ PBUNDLECB BundleCB;
+ NDIS_WAN_GET_COMP_INFO WanCompressionInfo;
+ ULONG i;
+
+ LINKCB_FROM_LINKH(LinkCB, In->hLinkHandle);
+
+ if (LinkCB == NULL || LinkCB->State != LINK_UP) {
+ return (NDISWAN_ERROR_INVALID_HANDLE);
+ }
+
+ NdisZeroMemory(&WanCompressionInfo, sizeof(NDIS_WAN_GET_COMP_INFO));
+
+ WanCompressionInfo.NdisLinkHandle = LinkCB->LineUpInfo.NdisLinkHandle;
+
+ //
+ // Submit this to the WAN Miniport
+ //
+ NdisRequest.RequestType = NdisRequestQueryInformation;
+ NdisRequest.DATA.QUERY_INFORMATION.Oid = OID_WAN_GET_COMP_INFO;
+ NdisRequest.DATA.QUERY_INFORMATION.InformationBuffer = &WanCompressionInfo;
+ NdisRequest.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(NDIS_WAN_SET_COMP_INFO);
+
+ Status = NdisWanSubmitNdisRequest(LinkCB->WanAdapterCB,
+ &NdisRequest,
+ SYNC,
+ NDISWAN);
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ //
+ // This miniport is doing some kind of compression!
+ // Fill in the miniport specific stuff
+ //
+ Out->SendCapabilities.MSCompType =
+ WanCompressionInfo.SendCapabilities.MSCompType;
+ Out->SendCapabilities.CompType =
+ WanCompressionInfo.SendCapabilities.CompType;
+ Out->SendCapabilities.CompLength =
+ WanCompressionInfo.SendCapabilities.CompLength;
+
+ if (Out->SendCapabilities.CompType == 0) {
+ NdisMoveMemory((PUCHAR)&Out->SendCapabilities.Proprietary,
+ (PUCHAR)&WanCompressionInfo.SendCapabilities.Proprietary,
+ sizeof(In->SendCapabilities.Proprietary));
+ } else {
+ NdisMoveMemory((PUCHAR)&Out->SendCapabilities.Public,
+ (PUCHAR)&WanCompressionInfo.SendCapabilities.Public,
+ sizeof(In->SendCapabilities.Public));
+ }
+
+ Out->RecvCapabilities.MSCompType =
+ WanCompressionInfo.RecvCapabilities.MSCompType;
+ Out->RecvCapabilities.CompType =
+ WanCompressionInfo.RecvCapabilities.CompType;
+ Out->RecvCapabilities.CompLength =
+ WanCompressionInfo.RecvCapabilities.CompLength;
+
+ if (Out->RecvCapabilities.CompType == 0) {
+ NdisMoveMemory((PUCHAR)&Out->RecvCapabilities.Proprietary,
+ (PUCHAR)&WanCompressionInfo.RecvCapabilities.Proprietary,
+ sizeof(In->SendCapabilities.Proprietary));
+ } else {
+ NdisMoveMemory((PUCHAR)&Out->RecvCapabilities.Public,
+ (PUCHAR)&WanCompressionInfo.RecvCapabilities.Public,
+ sizeof(In->SendCapabilities.Public));
+ }
+
+ } else {
+ Status = STATUS_SUCCESS;
+ Out->SendCapabilities.CompType = COMPTYPE_NONE;
+ Out->SendCapabilities.CompLength = 0;
+ Out->RecvCapabilities.CompType = COMPTYPE_NONE;
+ Out->RecvCapabilities.CompLength = 0;
+ }
+
+ BundleCB = BUNDLECB_FROM_LINKCB(LinkCB);
+
+ if (BundleCB == NULL) {
+ return (NDISWAN_ERROR_INVALID_HANDLE);
+ }
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ //
+ // Fill in the ndiswan specific stuff
+ //
+ NdisMoveMemory(Out->SendCapabilities.LMSessionKey,
+ BundleCB->SendCompInfo.LMSessionKey,
+ sizeof(Out->SendCapabilities.LMSessionKey));
+
+ NdisMoveMemory(Out->SendCapabilities.UserSessionKey,
+ BundleCB->SendCompInfo.UserSessionKey,
+ sizeof(Out->SendCapabilities.UserSessionKey));
+
+ NdisMoveMemory(Out->SendCapabilities.Challenge,
+ BundleCB->SendCompInfo.Challenge,
+ sizeof(Out->SendCapabilities.Challenge));
+
+ NdisMoveMemory(Out->RecvCapabilities.LMSessionKey,
+ BundleCB->RecvCompInfo.LMSessionKey,
+ sizeof(Out->RecvCapabilities.LMSessionKey));
+
+ NdisMoveMemory(Out->RecvCapabilities.UserSessionKey,
+ BundleCB->RecvCompInfo.UserSessionKey,
+ sizeof(Out->RecvCapabilities.UserSessionKey));
+
+ NdisMoveMemory(Out->RecvCapabilities.Challenge,
+ BundleCB->RecvCompInfo.Challenge,
+ sizeof(Out->RecvCapabilities.Challenge));
+
+ //
+ // We will set encryption capabilities based on session key
+ // availability. If the LMSessionKey is all zero's we will not
+ // offer 40bit encryption. If the UserSessionKey is all zero's
+ // we will not offer 128bit encryption.
+ //
+ Out->SendCapabilities.MSCompType = NDISWAN_COMPRESSION;
+
+ for (i = 0; i < sizeof(Out->SendCapabilities.LMSessionKey); i++) {
+ if (Out->SendCapabilities.LMSessionKey[i] != 0) {
+ Out->SendCapabilities.MSCompType |= (NDISWAN_ENCRYPTION | NDISWAN_40_ENCRYPTION);
+ break;
+ }
+ }
+
+#ifdef ENCRYPT_128BIT
+ for (i = 0; i < sizeof(Out->SendCapabilities.UserSessionKey); i++) {
+ if (Out->SendCapabilities.UserSessionKey[i] != 0) {
+ Out->SendCapabilities.MSCompType |= NDISWAN_128_ENCRYPTION;
+ break;
+ }
+ }
+#endif
+
+ Out->RecvCapabilities.MSCompType = NDISWAN_COMPRESSION;
+
+ for (i = 0; i < sizeof(Out->RecvCapabilities.LMSessionKey); i++) {
+ if (Out->RecvCapabilities.LMSessionKey[i] != 0) {
+ Out->RecvCapabilities.MSCompType |= (NDISWAN_ENCRYPTION | NDISWAN_40_ENCRYPTION);
+ break;
+ }
+ }
+
+#ifdef ENCRYPT_128BIT
+ for (i = 0; i < sizeof(Out->RecvCapabilities.UserSessionKey); i++) {
+ if (Out->RecvCapabilities.UserSessionKey[i] != 0) {
+ Out->RecvCapabilities.MSCompType |= NDISWAN_128_ENCRYPTION;
+ break;
+ }
+ }
+#endif
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ } else {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("GetCompressionInfo: Buffer to small: Size: %d, SizeNeeded %d",
+ ulOutputBufferLength, SizeNeeded));
+ }
+
+ return (Status);
+}
+
+
+NTSTATUS
+SetVJInfo(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PNDISWAN_SET_VJ_INFO In = (PNDISWAN_SET_VJ_INFO)pInputBuffer;
+ PLINKCB LinkCB;
+ PBUNDLECB BundleCB;
+ ULONG SizeNeeded = sizeof(NDISWAN_SET_VJ_INFO);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("SetVJInfo:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulInputBufferLength >= SizeNeeded) {
+
+ LINKCB_FROM_LINKH(LinkCB, In->hLinkHandle);
+
+ if (LinkCB == NULL || LinkCB->State != LINK_UP) {
+ return (NDISWAN_ERROR_INVALID_HANDLE);
+ }
+
+ BundleCB = BUNDLECB_FROM_LINKCB(LinkCB);
+
+ if (BundleCB == NULL) {
+ return (NDISWAN_ERROR_INVALID_HANDLE);
+ }
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ NdisMoveMemory(&BundleCB->RecvVJInfo,
+ &In->RecvCapabilities,
+ sizeof(VJ_INFO));
+
+ if (In->RecvCapabilities.IPCompressionProtocol == 0x2D) {
+
+ if (In->RecvCapabilities.MaxSlotID < MAX_VJ_STATES) {
+
+ Status = sl_compress_init(&BundleCB->VJCompress,
+ (UCHAR)(In->RecvCapabilities.MaxSlotID + 1));
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("Error allocating VJ Info!"));
+ }
+ }
+ }
+
+ NdisMoveMemory(&BundleCB->SendVJInfo,
+ &In->SendCapabilities,
+ sizeof(VJ_INFO));
+
+ if (In->SendCapabilities.IPCompressionProtocol == 0x2D) {
+
+ if (In->SendCapabilities.MaxSlotID < MAX_VJ_STATES) {
+
+ Status = sl_compress_init(&BundleCB->VJCompress,
+ (UCHAR)(In->SendCapabilities.MaxSlotID + 1));
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("Error allocating VJ Info!"));
+ }
+ }
+
+ }
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ } else {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("SetVJInfo: Buffer to small: Size: %d, SizeNeeded %d",
+ ulInputBufferLength, SizeNeeded));
+ }
+
+ return (Status);
+}
+
+
+NTSTATUS
+GetVJInfo(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PNDISWAN_GET_VJ_INFO In = (PNDISWAN_GET_VJ_INFO)pInputBuffer;
+ PNDISWAN_GET_VJ_INFO Out = (PNDISWAN_GET_VJ_INFO)pOutputBuffer;
+ ULONG SizeNeeded = sizeof(NDISWAN_GET_VJ_INFO);
+ PLINKCB LinkCB;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("GetVJInfo:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulOutputBufferLength >= SizeNeeded) {
+
+ LINKCB_FROM_LINKH(LinkCB, In->hLinkHandle);
+
+ if (LinkCB == NULL || LinkCB->State != LINK_UP) {
+ return (NDISWAN_ERROR_INVALID_HANDLE);
+ }
+
+ Out->SendCapabilities.IPCompressionProtocol =
+ Out->RecvCapabilities.IPCompressionProtocol = 0x2D;
+
+ Out->SendCapabilities.MaxSlotID =
+ Out->RecvCapabilities.MaxSlotID = MAX_VJ_STATES - 1;
+
+ Out->SendCapabilities.CompSlotID =
+ Out->RecvCapabilities.CompSlotID = 1;
+
+ } else {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("GetVJInfo: Buffer to small: Size: %d, SizeNeeded %d",
+ ulOutputBufferLength, SizeNeeded));
+ }
+
+ return (Status);
+}
+
+NTSTATUS
+GetBandwidthUtilization(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG SizeNeeded = sizeof(NDISWAN_GET_BANDWIDTH_UTILIZATION);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("GetBandwidthUtilization:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulOutputBufferLength >= SizeNeeded) {
+
+ } else {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("GetBandwidthUtilization: Buffer to small: Size: %d, SizeNeeded %d",
+ ulOutputBufferLength, SizeNeeded));
+ }
+
+ return (Status);
+}
+
+NTSTATUS
+EnumProtocolUtilization(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG SizeNeeded = sizeof(NDISWAN_ENUM_PROTOCOL_UTILIZATION);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("EnumProtocolUtilization:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulOutputBufferLength >= SizeNeeded) {
+
+ } else {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("EnumProtocolUtilization: Buffer to small: Size: %d, SizeNeeded %d",
+ ulOutputBufferLength, SizeNeeded));
+ }
+
+ return (Status);
+}
+
+NTSTATUS
+EnumActiveBundles(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG SizeNeeded = sizeof(NDISWAN_ENUM_ACTIVE_BUNDLES);
+ PNDISWAN_ENUM_ACTIVE_BUNDLES Out = (PNDISWAN_ENUM_ACTIVE_BUNDLES)pOutputBuffer;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("GetNumActiveBundles:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulOutputBufferLength >= SizeNeeded) {
+
+ //
+ // Does this information need to be protected by the lock?
+ // I would hate to have things get slowed for this call!
+ //
+ Out->ulNumberOfActiveBundles = ConnectionTable->ulNumActiveBundles;
+
+ } else {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("GetNumActiveBundles: Buffer to small: Size: %d, SizeNeeded %d",
+ ulOutputBufferLength, SizeNeeded));
+ }
+
+ return (Status);
+}
+
+NTSTATUS
+GetWanInfo(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG SizeNeeded = sizeof(NDISWAN_GET_WAN_INFO);
+ PNDISWAN_GET_WAN_INFO In = (PNDISWAN_GET_WAN_INFO)pInputBuffer;
+ PNDISWAN_GET_WAN_INFO Out = (PNDISWAN_GET_WAN_INFO)pOutputBuffer;
+ PLINKCB LinkCB;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("GetWanInfo:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulOutputBufferLength >= SizeNeeded) {
+ LINKCB_FROM_LINKH(LinkCB, In->hLinkHandle);
+
+ if (LinkCB != NULL) {
+ PWAN_ADAPTERCB WanAdapterCB = LinkCB->WanAdapterCB;
+
+ Out->WanInfo.MaxFrameSize = WanAdapterCB->WanInfo.MaxFrameSize;
+ Out->WanInfo.MaxTransmit = WanAdapterCB->WanInfo.MaxTransmit;
+ Out->WanInfo.FramingBits = WanAdapterCB->WanInfo.FramingBits;
+ Out->WanInfo.DesiredACCM = WanAdapterCB->WanInfo.DesiredACCM;
+ Out->WanInfo.MaxReconstructedFrameSize = MAX_MRRU;
+ Out->WanInfo.LinkSpeed = LinkCB->LineUpInfo.LinkSpeed * 100;
+
+ } else {
+ Status = NDISWAN_ERROR_INVALID_HANDLE;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("GetWanInfo: Invalid LinkHandle: 0x%8.8x",
+ In->hLinkHandle));
+ }
+
+ } else {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("GetWanInfo: Buffer to small: Size: %d, SizeNeeded %d",
+ ulOutputBufferLength, SizeNeeded));
+ }
+
+ return (Status);
+}
+
+NTSTATUS
+SetDebugInfo(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PNDISWAN_SET_DEBUG_INFO pDebugInfo = (PNDISWAN_SET_DEBUG_INFO)pInputBuffer;
+ ULONG SizeNeeded = sizeof(NDISWAN_SET_DEBUG_INFO);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("SetDebugInfo: OldLevel: 0x%8.8x OldMask: 0x%8.8x",
+ NdisWanCB.ulTraceLevel, NdisWanCB.ulTraceMask));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulInputBufferLength >= SizeNeeded) {
+ NdisWanCB.ulTraceLevel = pDebugInfo->ulTraceLevel;
+ NdisWanCB.ulTraceMask = pDebugInfo->ulTraceMask;
+ } else {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("Buffer to small: Size: %d, SizeNeeded %d",
+ ulInputBufferLength, SizeNeeded));
+ }
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("SetDebugInfo: NewLevel: 0x%8.8x NewMask: 0x%8.8x",
+ NdisWanCB.ulTraceLevel, NdisWanCB.ulTraceMask));
+
+ return (Status);
+}
+
+NTSTATUS
+SetBridgeInfo(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG SizeNeeded = sizeof(NDISWAN_SET_BRIDGE_INFO);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("SetBridgeInfo:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulInputBufferLength >= SizeNeeded) {
+
+ } else {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+
+ Status = STATUS_NOT_IMPLEMENTED;
+
+ return (Status);
+}
+
+
+NTSTATUS
+GetBridgeInfo(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG SizeNeeded = sizeof(NDISWAN_GET_BRIDGE_INFO);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("GetBridgeInfo:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulOutputBufferLength >= SizeNeeded) {
+
+ } else {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+
+ Status = STATUS_NOT_IMPLEMENTED;
+
+ return (Status);
+}
+
+NTSTATUS
+SetCIPXInfo(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG SizeNeeded = sizeof(NDISWAN_SET_CIPX_INFO);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("SetCIPXInfo:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulInputBufferLength >= SizeNeeded) {
+
+ } else {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+
+ Status = STATUS_NOT_IMPLEMENTED;
+
+ return (Status);
+}
+
+
+NTSTATUS
+GetCIPXInfo(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG SizeNeeded = sizeof(NDISWAN_GET_CIPX_INFO);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("GetCIPXInfo:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulOutputBufferLength >= SizeNeeded) {
+
+ } else {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+
+ Status = STATUS_NOT_IMPLEMENTED;
+
+ return (Status);
+}
+
+
+NTSTATUS
+SetEncryptionInfo(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG SizeNeeded = sizeof(NDISWAN_SET_ENCRYPTION_INFO);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("SetEncryptionInfo:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulInputBufferLength >= SizeNeeded) {
+
+ } else {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+
+ Status = STATUS_NOT_IMPLEMENTED;
+
+ return (Status);
+}
+
+
+NTSTATUS
+GetEncryptionInfo(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG SizeNeeded = sizeof(NDISWAN_GET_ENCRYPTION_INFO);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("GetEncryptionInfo:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulOutputBufferLength >= SizeNeeded) {
+
+ } else {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+
+ Status = STATUS_NOT_IMPLEMENTED;
+
+ return (Status);
+}
+
+NTSTATUS
+GetIdleTime(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+)
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ ULONG SizeNeeded = sizeof(NDISWAN_GET_IDLE_TIME);
+ PNDISWAN_GET_IDLE_TIME In = (PNDISWAN_GET_IDLE_TIME)pInputBuffer;
+ PNDISWAN_GET_IDLE_TIME Out = (PNDISWAN_GET_IDLE_TIME)pOutputBuffer;
+ PBUNDLECB BundleCB = NULL;
+ PPROTOCOLCB ProtocolCB = NULL;
+ WAN_TIME CurrentTime, Diff, OneSecond;
+ WAN_TIME LastNonIdleData;
+ BOOLEAN Found = FALSE;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("GetIdleTime:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulOutputBufferLength < SizeNeeded) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("GetIdleTime: Buffer to small: Size: %d, SizeNeeded %d",
+ ulInputBufferLength, SizeNeeded));
+ return (STATUS_INFO_LENGTH_MISMATCH);
+ }
+
+ BUNDLECB_FROM_BUNDLEH(BundleCB, In->hBundleHandle);
+
+ if (BundleCB == NULL) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("GetIdleTime: Invalid BundleHandle: 0x%8.8x",
+ In->hBundleHandle));
+ return (NDISWAN_ERROR_INVALID_HANDLE);
+
+ }
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+
+ //
+ // If this is for the bundle
+ //
+ if (In->usProtocolType == BUNDLE_IDLE_TIME) {
+ LastNonIdleData = BundleCB->LastRecvNonIdleData;
+ } else {
+
+ //
+ // Find the protocol type
+ //
+ for (ProtocolCB = (PPROTOCOLCB)BundleCB->ProtocolCBList.Flink;
+ (PVOID)ProtocolCB != (PVOID)&BundleCB->ProtocolCBList;
+ ProtocolCB = (PPROTOCOLCB)ProtocolCB->Linkage.Flink) {
+
+ if (ProtocolCB->usProtocolType == In->usProtocolType) {
+ Found = TRUE;
+ break;
+ }
+ }
+
+ if (!Found) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("GetIdleTime: Invalid ProtocolType: 0x%4.4x",
+ In->usProtocolType));
+ NdisReleaseSpinLock(&BundleCB->Lock);
+ return (NDISWAN_ERROR_NO_ROUTE);
+ }
+
+ LastNonIdleData = ProtocolCB->LastRecvNonIdleData;
+ }
+
+
+ NdisWanGetSystemTime(&CurrentTime);
+ NdisWanCalcTimeDiff(&Diff, &CurrentTime, &LastNonIdleData);
+ NdisWanInitWanTime(&OneSecond, ONE_SECOND);
+ NdisWanDivideWanTime(&CurrentTime, &Diff, &OneSecond);
+
+ Out->ulSeconds = CurrentTime.LowPart;
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ return (STATUS_SUCCESS);
+}
+
+NTSTATUS
+DeactivateRoute(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+ DeactivateRoute
+
+Routine Description:
+
+ This function unroutes the protocol given by usprotocoltype
+ from the bundle given by hbundlehandle.
+
+Arguments:
+
+ pInputBuffer - Pointer to the input structure that should be NDISWAN_UNROUTE
+
+ ulInputBufferLength - Length of input buffer should be sizeof(NDISWAN_UNROUTE)
+
+ pOutputBuffer - Pointer to the output structure that should be NDISWAN_UNROUTE
+
+ ulOutputBufferLength - Length of output buffer should be sizeof(NDISWAN_UNROUTE)
+
+ pulBytesWritten - Then number of bytes written to the output buffer is returned here
+
+Return Values:
+
+ NDISWAN_ERROR_ALREADY_ROUTED
+ NDISWAN_ERROR_INVALID_HANDLE
+ STATUS_INSUFFICIENT_RESOURCES
+ STATUS_INFO_LENGTH_MISMATCH
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PNDISWAN_UNROUTE In = (PNDISWAN_UNROUTE)pInputBuffer;
+ PNDISWAN_UNROUTE Out = (PNDISWAN_UNROUTE)pOutputBuffer;
+ ULONG SizeNeeded = sizeof(NDISWAN_UNROUTE);
+ ULONG AllocationSize, i;
+ PBUNDLECB BundleCB;
+ BOOLEAN RouteExists = FALSE;
+ PPROTOCOLCB ProtocolCB;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("ActivateRoute:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulInputBufferLength < SizeNeeded) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("DeactivateRoute: Buffer to small: Size: %d, SizeNeeded %d",
+ ulInputBufferLength, SizeNeeded));
+ return (STATUS_INFO_LENGTH_MISMATCH);
+ }
+
+ //
+ // If this is a valid bundle
+ //
+ BUNDLECB_FROM_BUNDLEH(BundleCB, In->hBundleHandle);
+
+ if (BundleCB == NULL) {
+
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("DeactivateRoute: Invalid BundleHandle: 0x%8.8x, ProtocolType: 0x%4.4x",
+ In->hBundleHandle, In->usProtocolType));
+
+ return (NDISWAN_ERROR_INVALID_HANDLE);
+ }
+
+ //
+ // If the ProtocolType is PROTOCOL_UNROUTE we will unroute all protocols
+ // from the bundle, otherwise we will only unroute the protocol = ProtocolType.
+ // If this is the only protocol on the bundle we will mark the bundle as
+ // being unrouted.
+ //
+ //
+
+ if (In->usProtocolType == PROTOCOL_UNROUTE) {
+
+ //
+ // This is a call to unroute
+ //
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ if (!(BundleCB->Flags & BUNDLE_ROUTED)) {
+
+ NdisWanDbgOut(DBG_FAILURE, DBG_IO, ("DeactivateRoute: BundleCB 0x%8.8x not routed!",
+ BundleCB));
+ NdisReleaseSpinLock(&BundleCB->Lock);
+ return(NDISWAN_ERROR_INVALID_HANDLE);
+ }
+
+ //
+ // Don't accept anymore sends on this bundle
+ //
+ BundleCB->Flags &= ~BUNDLE_ROUTED;
+
+ //
+ // Flush the protocol packet queues. This could cause us
+ // to complete frames to ndis out of order. Ndis should
+ // handle this.
+ //
+ for (ProtocolCB = (PPROTOCOLCB)BundleCB->ProtocolCBList.Flink;
+ (PVOID)ProtocolCB != (PVOID)&BundleCB->ProtocolCBList;
+ ProtocolCB = (PPROTOCOLCB)ProtocolCB->Linkage.Flink) {
+
+ FlushProtocolPacketQueue(ProtocolCB);
+ }
+
+ //
+ // Do we need to wait for any outstanding frames on the bundle?
+ //
+ if (BundleCB->OutstandingFrames != 0) {
+
+ NdisWanClearSyncEvent(&BundleCB->OutstandingFramesEvent);
+
+ BundleCB->Flags |= FRAMES_PENDING;
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ NdisWanWaitForSyncEvent(&BundleCB->OutstandingFramesEvent);
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ BundleCB->Flags &= ~FRAMES_PENDING;
+ }
+
+ //
+ // For each protocolcb in the bundle's protocolcb table
+ // (except for the i/o protocolcb)
+ //
+ for (i = 1; i < MAX_PROTOCOLS; i++) {
+
+ if (ProtocolCB = BundleCB->ProtocolCBTable[i]) {
+
+ //
+ // Remove the protocolcb from the bundlecb, both the table and
+ // the list.
+ //
+ RemoveProtocolCBFromBundle(ProtocolCB, BundleCB);
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ //
+ // Do a linedown to the protocol
+ //
+ NdisWanClearSyncEvent(&BundleCB->IndicationEvent);
+
+ Status = DoLineDownToProtocol(ProtocolCB);
+
+ if (Status == NDIS_STATUS_PENDING) {
+
+ //
+ // This has been queued because we could not
+ // get the miniport lock. Wait for notification
+ // and pick up the route status.
+ //
+ NdisWanWaitForSyncEvent(&BundleCB->IndicationEvent);
+
+ Status = BundleCB->IndicationStatus;
+ }
+
+ //
+ // Return the protocolcb
+ //
+ NdisWanReturnProtocolCB(ProtocolCB);
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+ }
+ }
+
+ if (BundleCB->State == BUNDLE_GOING_DOWN) {
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ //
+ // Clean up the connection table
+ //
+ RemoveBundleFromConnectionTable(BundleCB);
+
+ //
+ // Return the bundlecb
+ //
+ NdisWanReturnBundleCB(BundleCB);
+
+ } else {
+ NdisReleaseSpinLock(&BundleCB->Lock);
+ }
+
+ }
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+NTSTATUS
+GetNdisWanCB(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PNDISWAN_DUMPCB Out = (PNDISWAN_DUMPCB)pOutputBuffer;
+ ULONG SizeNeeded = sizeof(NDISWAN_DUMPCB) + sizeof(NDISWANCB);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("GetNdisWanCB:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulOutputBufferLength >= SizeNeeded) {
+ Out->Address = (PVOID)&NdisWanCB;
+ NdisMoveMemory(&Out->Buffer[0],
+ &NdisWanCB,
+ sizeof(NDISWANCB));
+
+ } else {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+
+ return (Status);
+}
+
+
+NTSTATUS
+EnumAdapterCB(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PNDISWAN_ENUMCB Out = (PNDISWAN_ENUMCB)pOutputBuffer;
+ ULONG SizeNeeded = sizeof(NDISWAN_ENUMCB) + (sizeof(PADAPTERCB) * AdapterCBList.ulCount);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("GetAdapterCB:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulOutputBufferLength >= SizeNeeded) {
+ PADAPTERCB AdapterCB;
+ ULONG i = 0;
+
+ Out->ulNumberOfCBs = AdapterCBList.ulCount;
+
+ for (AdapterCB = (PADAPTERCB)AdapterCBList.List.Flink;
+ (PVOID)AdapterCB != (PVOID)&AdapterCBList.List;
+ AdapterCB = (PADAPTERCB)AdapterCB->Linkage.Flink) {
+
+ Out->Address[i++] = (PVOID)AdapterCB;
+ }
+
+ } else {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+
+ return (Status);
+}
+
+NTSTATUS
+GetAdapterCB(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PNDISWAN_DUMPCB Out = (PNDISWAN_DUMPCB)pOutputBuffer;
+ ULONG SizeNeeded = sizeof(NDISWAN_DUMPCB) + sizeof(ADAPTERCB);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("GetAdapterCB:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulOutputBufferLength >= SizeNeeded) {
+ PADAPTERCB AdapterCB;
+
+ for (AdapterCB = (PADAPTERCB)AdapterCBList.List.Flink;
+ (PVOID)AdapterCB != (PVOID)&AdapterCBList.List;
+ AdapterCB = (PADAPTERCB)AdapterCB->Linkage.Flink) {
+
+ if (AdapterCB == (PADAPTERCB)Out->Address) {
+ break;
+ }
+ }
+
+ if ((PVOID)AdapterCB != (PVOID)&AdapterCBList.List) {
+
+ NdisMoveMemory(&Out->Buffer[0],
+ AdapterCB,
+ sizeof(ADAPTERCB));
+ } else {
+
+ Status = NDISWAN_ERROR_INVALID_ADDRESS;
+ }
+
+ } else {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+
+ return (Status);
+}
+
+NTSTATUS
+EnumWanAdapterCB(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PNDISWAN_ENUMCB Out = (PNDISWAN_ENUMCB)pOutputBuffer;
+ ULONG SizeNeeded = sizeof(NDISWAN_ENUMCB) +
+ sizeof(PWAN_ADAPTERCB) * WanAdapterCBList.ulCount;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("GetAdapterCB:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulOutputBufferLength >= SizeNeeded) {
+ PWAN_ADAPTERCB WanAdapterCB;
+ ULONG i = 0;
+
+ Out->ulNumberOfCBs = WanAdapterCBList.ulCount;
+
+ for (WanAdapterCB = (PWAN_ADAPTERCB)WanAdapterCBList.List.Flink;
+ (PVOID)WanAdapterCB != (PVOID)&WanAdapterCBList.List;
+ WanAdapterCB = (PWAN_ADAPTERCB)WanAdapterCB->Linkage.Flink) {
+
+ Out->Address[i] = (PVOID)WanAdapterCB;
+ }
+
+ } else {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+
+ return (Status);
+}
+
+NTSTATUS
+GetWanAdapterCB(
+ IN PUCHAR pInputBuffer,
+ IN ULONG ulInputBufferLength,
+ IN PUCHAR pOutputBuffer,
+ IN ULONG ulOutputBufferLength,
+ OUT PULONG pulBytesWritten
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG SizeNeeded = sizeof(NDISWAN_DUMPCB) + sizeof(WAN_ADAPTERCB);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_IO, ("GetWanAdapterCB:"));
+
+ *pulBytesWritten = SizeNeeded;
+
+ if (ulOutputBufferLength >= SizeNeeded) {
+
+ } else {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+
+ return (Status);
+}
+
+VOID
+CancelThresholdEvents(
+ VOID
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+#ifdef NT
+ PWAN_ASYNC_EVENT pAsyncEvent = NULL;
+ KIRQL Irql;
+ PIRP pIrp;
+
+
+ for (; ;) {
+
+ NdisAcquireSpinLock(&ThresholdEventQueue.Lock);
+
+ if (!IsListEmpty(&ThresholdEventQueue.List)) {
+
+ pAsyncEvent = (PWAN_ASYNC_EVENT)RemoveHeadList(&ThresholdEventQueue.List);
+ ThresholdEventQueue.ulCount--;
+ }
+
+ NdisReleaseSpinLock(&ThresholdEventQueue.Lock);
+
+ if (pAsyncEvent != NULL) {
+
+ IoAcquireCancelSpinLock(&Irql);
+
+ pIrp = (PIRP)pAsyncEvent->Context;
+
+ pIrp->Cancel = TRUE;
+ pIrp->IoStatus.Status = STATUS_CANCELLED;
+ pIrp->IoStatus.Information = 0;
+
+ IoReleaseCancelSpinLock(Irql);
+
+ IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
+
+ //
+ // Free the wan_async_event structure
+ //
+ NdisWanFreeMemory(pAsyncEvent);
+
+ pAsyncEvent = NULL;
+ } else
+ break;
+ }
+
+#endif // End #ifdef NT
+
+}
+
+VOID
+CancelIoReceivePackets(
+ VOID
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+#ifdef NT
+ PWAN_ASYNC_EVENT pAsyncEvent = NULL;
+ KIRQL Irql;
+ PIRP pIrp;
+
+
+ for (; ;) {
+
+ NdisAcquireSpinLock(&RecvPacketQueue.Lock);
+
+ if (!IsListEmpty(&RecvPacketQueue.List)) {
+
+ pAsyncEvent = (PWAN_ASYNC_EVENT)RemoveHeadList(&RecvPacketQueue.List);
+ RecvPacketQueue.ulCount--;
+ }
+
+ NdisReleaseSpinLock(&RecvPacketQueue.Lock);
+
+ if (pAsyncEvent != NULL) {
+
+ IoAcquireCancelSpinLock(&Irql);
+
+ pIrp = (PIRP)pAsyncEvent->Context;
+
+ pIrp->Cancel = TRUE;
+ pIrp->IoStatus.Status = STATUS_CANCELLED;
+ pIrp->IoStatus.Information = 0;
+ ((PNDISWAN_IO_PACKET)(pIrp->AssociatedIrp.SystemBuffer))->usHandleType = CANCELEDHANDLE;
+
+ IoReleaseCancelSpinLock(Irql);
+
+ IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
+
+ //
+ // Free the wan_async_event structure
+ //
+ NdisWanFreeMemory(pAsyncEvent);
+
+ pAsyncEvent = NULL;
+ } else
+ break;
+ }
+
+#endif // End #ifdef NT
+
+}
+
+VOID
+AddProtocolCBToBundle(
+ PPROTOCOLCB ProtocolCB,
+ PBUNDLECB BundleCB
+ )
+/*++
+
+Routine Name:
+
+ AddProtocolCBToBundle
+
+Routine Description:
+
+ This routine adds the protocolcb to the bundlecb protocollist and
+ protocoltable. It also assigns the protocolcb's handle (index into
+ the table) and set's the initial priority of all of the protocols
+ on the list.
+
+Arguments:
+
+ ProtocolCB - Pointer to the protocol control block
+ BundleCB - Pointer to the bundle control block
+
+Return Values:
+
+ None
+
+--*/
+{
+ ULONG i, InitialByteQuota;
+ ULONG InitialPriority;
+
+ //
+ // Add to list
+ //
+ InsertTailList(&BundleCB->ProtocolCBList, &ProtocolCB->Linkage);
+
+ //
+ // Insert in table
+ //
+ ASSERT(BundleCB->ProtocolCBTable[(ULONG)ProtocolCB->hProtocolHandle] ==
+ (PPROTOCOLCB)RESERVED_PROTOCOLCB);
+
+ BundleCB->ProtocolCBTable[(ULONG)ProtocolCB->hProtocolHandle] = ProtocolCB;
+
+ BundleCB->ulNumberOfRoutes++;
+
+ //
+ // Setup the send mask for this protocolcb
+ //
+ ProtocolCB->SendMaskBit = BundleCB->SendMask + 0x00000001;
+ BundleCB->SendMask = (BundleCB->SendMask << 1) | 0x00000001;
+
+ BundleCB->Flags |= BUNDLE_ROUTED;
+ ProtocolCB->Flags |= PROTOCOL_ROUTED;
+
+ //
+ // We want to walk the protocolcblist and assign the intial
+ // value for each protocol priority and byte quota. The
+ // initial value for the priority is just 100 divided by the
+ // number of protocols that we have routed. The initial value
+ // for the byte quota is the bundle speed in Bps * InitialPriority (%)
+ // divided by 100.
+ //
+ InitialPriority = (BundleCB->ulNumberOfRoutes - 1) ?
+ 100 / (BundleCB->ulNumberOfRoutes - 1) : 100;
+
+ InitialByteQuota = (((BundleCB->LineUpInfo.BundleSpeed * 100) / 8) *
+ InitialPriority) / 100;
+
+ //
+ // Skip the first one on the list since it is the PrivateIo
+ // protocolcb and always has a priority of 100.
+ //
+ ProtocolCB = (PPROTOCOLCB)BundleCB->ProtocolCBList.Flink;
+
+ for (ProtocolCB = (PPROTOCOLCB)ProtocolCB->Linkage.Flink;
+ (PVOID)ProtocolCB != (PVOID)&BundleCB->ProtocolCBList;
+ ProtocolCB = (PPROTOCOLCB)ProtocolCB->Linkage.Flink) {
+
+#ifdef BANDWIDTH_ON_DEMAND
+ ProtocolCB->usPriority = (USHORT)InitialPriority;
+ ProtocolCB->ulByteQuota = InitialByteQuota;
+#endif // end of BANDWIDTH_ON_DEMAND
+
+ }
+
+}
+
+VOID
+RemoveProtocolCBFromBundle(
+ PPROTOCOLCB ProtocolCB,
+ PBUNDLECB BundleCB
+ )
+{
+ ProtocolCB->Flags &= ~PROTOCOL_ROUTED;
+ RemoveEntryList(&ProtocolCB->Linkage);
+ BundleCB->ProtocolCBTable[(ULONG)ProtocolCB->hProtocolHandle] = NULL;
+ BundleCB->ulNumberOfRoutes--;
+ BundleCB->SendMask &= ~ProtocolCB->SendMaskBit;
+}
+
+#ifdef BANDWIDTH_ON_DEMAND
+
+VOID
+SortProtocolListByPriority(
+ IN PBUNDLECB BundleCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PPROTOCOLCB ProtocolCB, NextProtocolCB, IoProtocolCB;
+
+ //
+ // First save the I/O ProtocolCB
+ //
+ IoProtocolCB = (PPROTOCOLCB)RemoveHeadList(&BundleCB->ProtocolCBList);
+
+ //
+ // Initial starting conditions
+ //
+ ProtocolCB = (PPROTOCOLCB)BundleCB->ProtocolCBList.Flink;
+ NextProtocolCB = (PPROTOCOLCB)ProtocolCB->Linkage.Flink;
+
+ //
+ // This is a lousy sorting algorith but it is simple and not called
+ // very often so we will leave it as is for now.
+ //
+ while ((PVOID)ProtocolCB != (PVOID)&BundleCB->ProtocolCBList) {
+
+ while ((PVOID)NextProtocolCB != (PVOID)&BundleCB->ProtocolCBList) {
+
+ if (NextProtocolCB->usPriority > ProtocolCB->usPriority) {
+ PLIST_ENTRY Prev, Next;
+
+ RemoveEntryList(&NextProtocolCB->Linkage);
+
+ Prev = (PLIST_ENTRY)ProtocolCB->Linkage.Blink;
+ Next = (PLIST_ENTRY)ProtocolCB->Linkage.Flink;
+
+ //
+ // Fix up the previous flink
+ //
+ Prev->Flink = (PLIST_ENTRY)NextProtocolCB;
+
+ //
+ // Fixup the new insertions flink and blink
+ //
+ NextProtocolCB->Linkage.Blink = Prev;
+ NextProtocolCB->Linkage.Flink = (PLIST_ENTRY)ProtocolCB;
+
+ //
+ // Fixup the next blink
+ //
+ ProtocolCB->Linkage.Blink = (PLIST_ENTRY)NextProtocolCB;
+
+ //
+ // Get the new starting point
+ //
+ ProtocolCB = NextProtocolCB;
+
+ //
+ // Get the next compare
+ //
+ NextProtocolCB = (PPROTOCOLCB)Next;
+
+ } else {
+ NextProtocolCB = (PPROTOCOLCB)NextProtocolCB->Linkage.Flink;
+ }
+ }
+
+ ProtocolCB = (PPROTOCOLCB)ProtocolCB->Linkage.Flink;
+ }
+
+ //
+ // Restore I/O ProtocolCB
+ //
+ InsertHeadList(&BundleCB->ProtocolCBList, &IoProtocolCB->Linkage);
+
+}
+
+#endif // end of BANDWIDTH_ON_DEMAND
+
+VOID
+CompleteThresholdEvent(
+ PBUNDLECB BundleCB,
+ ULONG ThresholdType
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+#ifdef NT
+ KIRQL Irql;
+ PIRP pIrp;
+ PWAN_ASYNC_EVENT pAsyncEvent = NULL;
+ PNDISWAN_SET_THRESHOLD_EVENT ThresholdEvent;
+
+ NdisAcquireSpinLock(&ThresholdEventQueue.Lock);
+
+ if (!IsListEmpty(&ThresholdEventQueue.List)) {
+
+ pAsyncEvent = (PWAN_ASYNC_EVENT)RemoveHeadList(&ThresholdEventQueue.List);
+ ThresholdEventQueue.ulCount--;
+ }
+
+ NdisReleaseSpinLock(&ThresholdEventQueue.Lock);
+
+ if (pAsyncEvent != NULL) {
+
+ IoAcquireCancelSpinLock(&Irql);
+
+ pIrp = (PIRP)pAsyncEvent->Context;
+
+ pIrp->IoStatus.Status = STATUS_SUCCESS;
+ pIrp->IoStatus.Information = sizeof(NDISWAN_SET_THRESHOLD_EVENT);
+
+ ThresholdEvent = (PNDISWAN_SET_THRESHOLD_EVENT)pIrp->AssociatedIrp.SystemBuffer;
+ ThresholdEvent->hBundleHandle = BundleCB->hBundleHandle;
+ ThresholdEvent->ulThreshold = ThresholdType;
+
+ IoSetCancelRoutine(pIrp, NULL);
+
+ IoReleaseCancelSpinLock(Irql);
+
+ IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
+
+ //
+ // Free the wan_async_event structure
+ //
+ NdisWanFreeMemory(pAsyncEvent);
+
+ }
+
+#endif // End #ifdef NT
+}
+
+VOID
+FlushProtocolPacketQueue(
+ PPROTOCOLCB ProtocolCB
+ )
+{
+ ULONG MagicNumber = 0;
+ PADAPTERCB AdapterCB = ProtocolCB->AdapterCB;
+ PBUNDLECB BundleCB = ProtocolCB->BundleCB;
+
+ if (ProtocolCB->usProtocolType == PROTOCOL_PRIVATE_IO) {
+ MagicNumber = NDISWAN_MAGIC_NUMBER;
+ }
+
+ while (!IsNdisPacketQueueEmpty(ProtocolCB)) {
+ PNDIS_PACKET NdisPacket;
+
+ NdisPacket = RemoveHeadNdisPacketQueue(ProtocolCB);
+
+ //
+ // Assign the magic number
+ //
+ PMINIPORT_RESERVED_FROM_NDIS(NdisPacket)->MagicNumber = MagicNumber;
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ //
+ // Complete the NdisPacket
+ //
+ TryToCompleteNdisPacket(AdapterCB, NdisPacket);
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+ }
+}
+
+VOID
+AssignProtocolCBHandle(
+ PBUNDLECB BundleCB,
+ PPROTOCOLCB ProtocolCB
+ )
+{
+ ULONG i;
+
+ //
+ // Find the first unused slot in the table
+ //
+ for (i = 1; i < MAX_PROTOCOLS; i++) {
+ if (BundleCB->ProtocolCBTable[i] == NULL) {
+ ProtocolCB->hProtocolHandle = (NDIS_HANDLE)i;
+ ProtocolCB->BundleCB = BundleCB;
+ BundleCB->ProtocolCBTable[i] = (PPROTOCOLCB)RESERVED_PROTOCOLCB;
+ break;
+ }
+ }
+
+ ASSERT(i < MAX_PROTOCOLS);
+}
+
+VOID
+FreeProtocolCBHandle(
+ PBUNDLECB BundleCB,
+ PPROTOCOLCB ProtocolCB
+ )
+{
+
+ ASSERT(BundleCB->ProtocolCBTable[(ULONG)ProtocolCB->hProtocolHandle] ==
+ (PPROTOCOLCB)RESERVED_PROTOCOLCB);
+
+ ASSERT((ULONG)ProtocolCB->hProtocolHandle < MAX_PROTOCOLS);
+
+ BundleCB->ProtocolCBTable[(ULONG)ProtocolCB->hProtocolHandle] = NULL;
+}
+
diff --git a/private/ntos/ndis/ndiswan/kdexts/api.c b/private/ntos/ndis/ndiswan/kdexts/api.c
new file mode 100644
index 000000000..d46296696
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/kdexts/api.c
@@ -0,0 +1,385 @@
+#include <wanhelp.h>
+
+DECLARE_API(ndiswancb)
+{
+ DWORD Address, BytesRead;
+ NDISWANCB NdisWanCB;
+
+ Address = GetExpression("ndiswan!ndiswancb");
+
+ if (!ReadMemory(Address, &NdisWanCB, sizeof(NDISWANCB), &BytesRead)) {
+ return;
+ }
+
+ if (BytesRead >= sizeof(NDISWANCB)) {
+
+ DisplayNdisWanCB(Address, &NdisWanCB);
+
+ } else {
+ dprintf("Only read %d bytes, expected %d bytes\n", BytesRead, sizeof(NdisWanCB));
+ }
+
+ return;
+}
+
+DECLARE_API(enumwanadaptercb)
+{
+ DWORD Address, BytesRead;
+ WAN_GLOBAL_LIST AdapterList;
+ PWAN_GLOBAL_LIST Address1;
+
+ Address = GetExpression("ndiswan!wanadaptercblist");
+ Address1 = (PWAN_GLOBAL_LIST)Address;
+
+ if (!ReadMemory(Address, &AdapterList, sizeof(WAN_GLOBAL_LIST), &BytesRead)) {
+ return;
+ }
+
+ if (BytesRead >= sizeof(WAN_GLOBAL_LIST)) {
+ dprintf("WanAdapterCBList: 0x%8.8x\n",Address);
+ dprintf(" Lock: 0x%8.8x Irql: 0x%8.8x\n",
+ AdapterList.Lock.SpinLock, AdapterList.Lock.OldIrql);
+ dprintf(" Count: %ld MaxCount: %ld\n",
+ AdapterList.ulCount, AdapterList.ulMaxCount);
+
+ Address = AdapterList.List.Flink;
+
+ while ((PVOID)Address != (PVOID)&Address1->List) {
+ WAN_ADAPTERCB WanAdapterCB;
+
+ if (ReadMemory(Address, &WanAdapterCB, sizeof(WAN_ADAPTERCB), &BytesRead)) {
+ DisplayWanAdapterCB(Address, &WanAdapterCB);
+ }
+
+ Address = (DWORD)WanAdapterCB.Linkage.Flink;
+ }
+
+ } else {
+
+ dprintf("Only read %d bytes, expected %d bytes\n", BytesRead, sizeof(WAN_GLOBAL_LIST));
+ }
+}
+
+DECLARE_API(wanadaptercb)
+{
+ DWORD Address, BytesRead;
+ WAN_ADAPTERCB WanAdapterCB;
+ PUCHAR s = (PSTR)args;
+ BOOLEAN Verbose = FALSE;
+
+ //
+ // Did they forget something...
+ //
+ if (0 == args[0])
+ {
+Usage:
+ dprintf("wanadapter <PWANADAPTERCB>\n");
+ return;
+ }
+
+ sscanf(args, "%lx", &Address);
+
+ if (!ReadMemory(Address, &WanAdapterCB, sizeof(WAN_ADAPTERCB), &BytesRead)) {
+ return;
+ }
+
+ if (BytesRead >= sizeof(WAN_ADAPTERCB)) {
+
+ DisplayWanAdapterCB(Address, &WanAdapterCB);
+
+ } else {
+ dprintf("Only read %d bytes, expected %d bytes\n", BytesRead, sizeof(WanAdapterCB));
+ }
+}
+
+DECLARE_API(enumadaptercb)
+{
+ DWORD Address, BytesRead;
+ WAN_GLOBAL_LIST AdapterList;
+ PWAN_GLOBAL_LIST Address1;
+
+
+ Address = GetExpression("ndiswan!adaptercblist");
+ Address1 = (PWAN_GLOBAL_LIST)Address;
+
+ if (!ReadMemory(Address, &AdapterList, sizeof(WAN_GLOBAL_LIST), &BytesRead)) {
+ return;
+ }
+
+ if (BytesRead >= sizeof(WAN_GLOBAL_LIST)) {
+
+ dprintf("AdapterCBList: 0x%8.8x\n",Address);
+ dprintf(" Lock: 0x%8.8x Irql: 0x%8.8x\n",
+ AdapterList.Lock.SpinLock, AdapterList.Lock.OldIrql);
+ dprintf(" Count: %ld MaxCount: %ld\n",
+ AdapterList.ulCount, AdapterList.ulMaxCount);
+
+ Address = AdapterList.List.Flink;
+
+ while ((PVOID)Address != (PVOID)&Address1->List) {
+ ADAPTERCB AdapterCB;
+
+ if (ReadMemory(Address, &AdapterCB, sizeof(ADAPTERCB), &BytesRead)) {
+ DisplayAdapterCB(Address, &AdapterCB);
+ }
+
+ Address = (DWORD)AdapterCB.Linkage.Flink;
+ }
+ } else {
+
+ dprintf("Only read %d bytes, expected %d bytes\n", BytesRead, sizeof(WAN_GLOBAL_LIST));
+ }
+}
+
+DECLARE_API(adaptercb)
+{
+ DWORD Address, BytesRead;
+ ADAPTERCB AdapterCB;
+ PUCHAR s = (PSTR)args;
+ BOOLEAN Verbose = FALSE;
+
+ //
+ // Did they forget something...
+ //
+ if (0 == args[0])
+ {
+Usage:
+ dprintf("adapter <PADAPTERCB>\n");
+ return;
+ }
+
+ sscanf(args, "%lx", &Address);
+
+ if (!ReadMemory(Address, &AdapterCB, sizeof(ADAPTERCB), &BytesRead)) {
+ return;
+ }
+
+ if (BytesRead >= sizeof(ADAPTERCB)) {
+
+ DisplayAdapterCB(Address, &AdapterCB);
+
+ } else {
+ dprintf("Only read %d bytes, expected %d bytes\n", BytesRead, sizeof(AdapterCB));
+ }
+}
+
+DECLARE_API(connectiontable)
+{
+ DWORD Address, Address1, BytesRead, i, j;
+ CONNECTION_TABLE ConnectionTable;
+
+ Address = GetExpression("ndiswan!connectiontable");
+
+ if (!ReadMemory(Address, &Address1, sizeof(DWORD), &BytesRead)) {
+ return;
+ }
+
+ if (!ReadMemory(Address1, &ConnectionTable, sizeof(CONNECTION_TABLE), &BytesRead)) {
+ return;
+ }
+
+ if (BytesRead >= sizeof(CONNECTION_TABLE)) {
+ DisplayConnectionTable(Address, &ConnectionTable);
+
+ for (i = 0, j = 0; j < ConnectionTable.ulNumActiveLinks; i++) {
+ LINKCB LinkCB;
+
+ //
+ // Get pointer to location in Linktable
+ //
+ Address = ConnectionTable.LinkArray + i;
+
+ if (!ReadMemory(Address, &Address1, sizeof(DWORD), &BytesRead)) {
+ continue;
+ }
+
+ if (Address1 != NULL) {
+
+ if (ReadMemory(Address1, &LinkCB, sizeof(LINKCB), &BytesRead)) {
+ DisplayLinkCB(Address1, &LinkCB);
+ j++;
+ }
+
+ }
+
+ }
+
+ for (i = 0, j = 0; j < ConnectionTable.ulNumActiveBundles; i++) {
+ BUNDLECB BundleCB;
+
+ //
+ // Get pointer to location in bundletable
+ //
+ Address = ConnectionTable.BundleArray + i;
+
+
+ if (!ReadMemory(Address, &Address1, sizeof(DWORD), &BytesRead)) {
+ continue;
+ }
+
+ if (Address1 != NULL) {
+
+ if (ReadMemory(Address1, &BundleCB, sizeof(BUNDLECB), &BytesRead)) {
+ DisplayBundleCB(Address1, &BundleCB);
+ j++;
+ }
+ }
+
+ }
+
+ } else {
+ dprintf("Only read %d bytes, expected %d bytes\n", BytesRead, sizeof(CONNECTION_TABLE));
+ }
+}
+
+DECLARE_API(bundlecb)
+{
+ DWORD Address, BytesRead;
+ BUNDLECB BundleCB;
+
+ //
+ // Did they forget something...
+ //
+ if (0 == args[0])
+ {
+Usage:
+ dprintf("bundlecb <PBUNDLECB>\n");
+ return;
+ }
+
+ sscanf(args, "%lx", &Address);
+
+ if (!ReadMemory(Address, &BundleCB, sizeof(BUNDLECB), &BytesRead)) {
+ return;
+ }
+
+ if (BytesRead >= sizeof(BUNDLECB)) {
+
+ DisplayBundleCB(Address, &BundleCB);
+
+ } else {
+ dprintf("Only read %d bytes, expected %d bytes\n", BytesRead, sizeof(BUNDLECB));
+ }
+}
+
+DECLARE_API(linkcb)
+{
+ DWORD Address, BytesRead;
+ LINKCB LinkCB;
+
+ //
+ // Did they forget something...
+ //
+ if (0 == args[0])
+ {
+Usage:
+ dprintf("linkcb <PLINKCB>\n");
+ return;
+ }
+
+ sscanf(args, "%lx", &Address);
+
+ if (!ReadMemory(Address, &LinkCB, sizeof(LINKCB), &BytesRead)) {
+ return;
+ }
+
+ if (BytesRead >= sizeof(LINKCB)) {
+
+ DisplayLinkCB(Address, &LinkCB);
+
+ } else {
+ dprintf("Only read %d bytes, expected %d bytes\n", BytesRead, sizeof(LINKCB));
+ }
+}
+
+DECLARE_API(protocolcb)
+{
+ DWORD Address, BytesRead;
+ PROTOCOLCB ProtocolCB;
+
+ //
+ // Did they forget something...
+ //
+ if (0 == args[0])
+ {
+Usage:
+ dprintf("protocolcb <PPROTOCOLCB>\n");
+ return;
+ }
+
+ sscanf(args, "%lx", &Address);
+
+ if (!ReadMemory(Address, &ProtocolCB, sizeof(PROTOCOLCB), &BytesRead)) {
+ return;
+ }
+
+ if (BytesRead >= sizeof(PROTOCOLCB)) {
+
+ DisplayProtocolCB(Address, &ProtocolCB);
+
+ } else {
+ dprintf("Only read %d bytes, expected %d bytes\n", BytesRead, sizeof(PROTOCOLCB));
+ }
+}
+
+DECLARE_API(wanpacket)
+{
+ DWORD Address, BytesRead;
+ NDIS_WAN_PACKET Packet;
+
+ //
+ // Did they forget something...
+ //
+ if (0 == args[0])
+ {
+Usage:
+ dprintf("wanpacket <PNDIS_WAN_PACKET>\n");
+ return;
+ }
+
+ sscanf(args, "%lx", &Address);
+
+ if (!ReadMemory(Address, &Packet, sizeof(NDIS_WAN_PACKET), &BytesRead)) {
+ return;
+ }
+
+ if (BytesRead >= sizeof(NDIS_WAN_PACKET)) {
+
+ DisplayWanPacket(Address, &Packet);
+
+ } else {
+ dprintf("Only read %d bytes, expected %d bytes\n", BytesRead, sizeof(NDIS_WAN_PACKET));
+ }
+}
+
+DECLARE_API(ndispacket)
+{
+ DWORD Address, BytesRead;
+ NDIS_PACKET Packet;
+
+ //
+ // Did they forget something...
+ //
+ if (0 == args[0])
+ {
+Usage:
+ dprintf("ndispacket <PNDIS_PACKET>\n");
+ return;
+ }
+
+ sscanf(args, "%lx", &Address);
+
+ if (!ReadMemory(Address, &Packet, sizeof(NDIS_PACKET), &BytesRead)) {
+ return;
+ }
+
+ if (BytesRead >= sizeof(NDIS_PACKET)) {
+
+ DisplayNdisPacket(Address, &Packet);
+
+ } else {
+ dprintf("Only read %d bytes, expected %d bytes\n", BytesRead, sizeof(NDIS_PACKET));
+ }
+}
+
+
diff --git a/private/ntos/ndis/ndiswan/kdexts/display.c b/private/ntos/ndis/ndiswan/kdexts/display.c
new file mode 100644
index 000000000..cf412c0e9
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/kdexts/display.c
@@ -0,0 +1,543 @@
+#include <wanhelp.h>
+
+PSTR MediumType[] =
+{
+ "NdisMedium802_3",
+ "NdisMedium802_5",
+ "NdisMediumFddi",
+ "NdisMediumWan",
+ "NdisMediumLocalTalk",
+ "NdisMediumDix",
+ "NdisMediumArcnetRaw",
+ "NdisMediumArcnet878_2",
+ "NdisMediumAtm",
+ "NdisMediumWirelessWan",
+ "NdisMediumIrda"
+};
+
+PSTR WanMediumSubtype[] =
+{
+ "NdisWanMediumHub",
+ "NdisWanMediumX_25",
+ "NdisWanMediumIsdn",
+ "NdisWanMediumSerial",
+ "NdisWanMediumFrameRelay",
+ "NdisWanMediumAtm",
+ "NdisWanMediumSonet",
+ "NdisWanMediumSW56K"
+};
+
+PSTR WanHeaderFormat[] =
+{
+ "NdisWanHeaderNative", // src/dest based on subtype, followed by NLPID
+ "NdisWanHeaderEthernet" // emulation of ethernet header
+};
+
+PSTR HardwareStatus[] =
+{
+ "NdisHardwareStatusReady",
+ "NdisHardwareStatusInitializing",
+ "NdisHardwareStatusReset",
+ "NdisHardwareStatusClosing",
+ "NdisHardwareStatusNotReady"
+};
+
+PSTR LinkCBStates[] =
+{
+ "LinkDown",
+ "LinkGoingDown",
+ "LinkUp"
+};
+
+PSTR BundleCBStates[] =
+{
+ "BundleDown",
+ "BundleGowingDown",
+ "BundleUp",
+ "BundleRouted",
+ "BundleUnrouting"
+};
+
+PSTR WanQuality[] =
+{
+ "NdisWanRaw",
+ "NdisWanErrorControl",
+ "NdisWanReliable"
+};
+
+PSTR DeferredQueueDesc[] =
+{
+ "ReceiveIndication",
+ "SendComplete",
+ "StatusIndication",
+ "Loopback"
+};
+
+VOID
+DisplayNdisWanCB(
+ DWORD Address,
+ PNDISWANCB NdisWanCB
+ )
+{
+ dprintf("NdisWanCB: 0x%8.8x\n\n", Address);
+ dprintf(" Lock: 0x%8.8x Irql: 0x%8.8x\n", NdisWanCB->Lock.SpinLock, NdisWanCB->Lock.OldIrql);
+ dprintf(" NdisWrapperHandle: 0x%8.8x\n", NdisWanCB->hNdisWrapperHandle);
+ dprintf(" ProtocolHandle: 0x%8.8x\n", NdisWanCB->hProtocolHandle);
+ dprintf(" NumberOfProtocols: %ld\n", NdisWanCB->ulNumberOfProtocols);
+ dprintf(" NumberOfLinks: %ld\n", NdisWanCB->ulNumberOfLinks);
+ dprintf(" MiniumFragmentSize: 0x%8.8x\n", NdisWanCB->ulMinFragmentSize);
+ dprintf(" TraceLevel: 0x%8.8x\n", NdisWanCB->ulTraceLevel);
+ dprintf(" TraceMask: 0x%8.8x\n", NdisWanCB->ulTraceMask);
+ dprintf(" DriverObject: 0x%8.8x\n", NdisWanCB->pDriverObject);
+ dprintf(" DeviceObject: 0x%8.8x\n", NdisWanCB->pDeviceObject);
+ dprintf(" PacketsSent: %ld\n", NdisWanCB->SendCount);
+ dprintf(" PacketsCompleted: %ld\n", NdisWanCB->SendCompleteCount);
+ dprintf(" IORecvQueueEmpty: %ld\n", NdisWanCB->IORecvError1);
+ dprintf(" IORecvBeforMap: %ld\n", NdisWanCB->IORecvError2);
+ dprintf(" PromiscuousAdapter: 0x%8.8x\n",NdisWanCB->PromiscuousAdapter);
+}
+
+VOID
+DisplayWanAdapterCB(
+ DWORD Address,
+ PWAN_ADAPTERCB WanAdapterCB
+ )
+{
+ dprintf("\n\nWanAdapterCB: 0x%8.8x\n", Address);
+
+ dprintf(" Linkage:\n");
+ dprintf(" Flink: 0x%8.8x Blink: 0x%8.8x\n",
+ WanAdapterCB->Linkage.Flink, WanAdapterCB->Linkage.Blink);
+
+ dprintf(" Lock: 0x%8.8x Irql: 0x%8.8x\n",
+ WanAdapterCB->Lock.SpinLock, WanAdapterCB->Lock.OldIrql);
+
+ dprintf(" FreeLinkCBList:\n");
+ dprintf(" Flink: 0x%8.8x Blink: 0x%8.8x\n",
+ WanAdapterCB->FreeLinkCBList.Flink, WanAdapterCB->FreeLinkCBList.Blink);
+
+ dprintf(" NdisBindingHandle: 0x%8.8x\n", WanAdapterCB->hNdisBindingHandle);
+
+ dprintf(" WanRequest: 0x%8.8x\n", WanAdapterCB->pWanRequest);
+ dprintf(" LastRequest: 0x%8.8x\n", WanAdapterCB->pLastWanRequest);
+
+ dprintf(" MiniportName: Buffer: 0x%8.8x Length: %ld\n",
+ WanAdapterCB->MiniportName.Buffer, WanAdapterCB->MiniportName.Length);
+
+ dprintf(" MediumType: %s\n", MediumType[WanAdapterCB->MediumType]);
+
+ dprintf(" MediumSubType: %s\n", WanMediumSubtype[WanAdapterCB->MediumSubType]);
+
+ dprintf(" WanHeaderFormat: %s\n", WanHeaderFormat[WanAdapterCB->WanHeaderFormat]);
+
+ dprintf(" MaxFrameSize: %ld\n", WanAdapterCB->WanInfo.MaxFrameSize);
+
+ dprintf(" MaxTransmit: %ld\n", WanAdapterCB->WanInfo.MaxTransmit);
+
+ dprintf(" HeaderPadding: %ld\n",WanAdapterCB->WanInfo.HeaderPadding);
+
+ dprintf(" TailPadding: %ld\n",WanAdapterCB->WanInfo.TailPadding);
+
+ dprintf(" Endpoints: %ld\n",WanAdapterCB->WanInfo.Endpoints);
+
+ dprintf(" MemoryFlags: 0x%8.8x\n",WanAdapterCB->WanInfo.MemoryFlags);
+
+ dprintf(" HighestAddress: 0x%8.8x 0x%8.8x\n",
+ WanAdapterCB->WanInfo.HighestAcceptableAddress.HighPart,
+ WanAdapterCB->WanInfo.HighestAcceptableAddress.LowPart);
+
+ dprintf(" FramingBits: 0x%8.8x\n",WanAdapterCB->WanInfo.FramingBits);
+
+ dprintf(" DesiredACCM: 0x%8.8x\n",WanAdapterCB->WanInfo.DesiredACCM);
+}
+
+VOID
+DisplayAdapterCB(
+ DWORD Address,
+ PADAPTERCB AdapterCB
+ )
+{
+ DWORD i;
+
+ dprintf("\n\nAdapterCB: 0x%8.8x\n", Address);
+
+ dprintf(" Linkage:\n");
+ dprintf(" Flink: 0x%8.8x Blink: 0x%8.8x\n",
+ AdapterCB->Linkage.Flink, AdapterCB->Linkage.Blink);
+
+ dprintf(" Lock: 0x%8.8x Irql: 0x%8.8x\n",
+ AdapterCB->Lock.SpinLock, AdapterCB->Lock.OldIrql);
+
+ dprintf(" ReferenceCount: %ld\n", AdapterCB->ulReferenceCount);
+
+ dprintf(" MiniportAdapterHandle: 0x%8.8x\n", AdapterCB->hMiniportHandle);
+
+ dprintf(" Flags: 0x%8.8x\n", AdapterCB->Flags);
+
+ dprintf(" FreeDeferredQueue:\n");
+ dprintf(" Head: 0x%8.8x\n", AdapterCB->FreeDeferredQueue.Head);
+ dprintf(" Tail: 0x%8.8x\n", AdapterCB->FreeDeferredQueue.Tail);
+ dprintf(" Count: %ld\n", AdapterCB->FreeDeferredQueue.Count);
+ dprintf(" MaxCount: %ld\n", AdapterCB->FreeDeferredQueue.MaxCount);
+ for (i = 0; i < MAX_DEFERRED_QUEUE_TYPES; i++) {
+ dprintf(" DeferredQueue: %s\n", DeferredQueueDesc[i]);
+ dprintf(" Head: 0x%8.8x\n", AdapterCB->DeferredQueue[i].Head);
+ dprintf(" Tail: 0x%8.8x\n", AdapterCB->DeferredQueue[i].Tail);
+ dprintf(" Count: %ld\n", AdapterCB->DeferredQueue[i].Count);
+ dprintf(" MaxCount: %ld\n", AdapterCB->DeferredQueue[i].MaxCount);
+ }
+
+ dprintf(" MediumType: %s\n", MediumType[AdapterCB->MediumType]);
+
+ dprintf(" HardwareStatus: %s\n", HardwareStatus[AdapterCB->HardwareStatus]);
+
+ dprintf(" AdapterName: Buffer: 0x%8.8x Length: %d\n",
+ AdapterCB->AdapterName.Buffer, AdapterCB->AdapterName.Length);
+
+ dprintf(" NetworkAddress: 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n",
+ AdapterCB->NetworkAddress[0], AdapterCB->NetworkAddress[1], AdapterCB->NetworkAddress[2],
+ AdapterCB->NetworkAddress[3], AdapterCB->NetworkAddress[4], AdapterCB->NetworkAddress[5]);
+
+ dprintf(" NumberOfProtocols: %ld\n", AdapterCB->ulNumberofProtocols);
+
+ dprintf(" ProtocolType: 0x%4.4x\n", AdapterCB->ProtocolType);
+
+ dprintf(" NbfBundleCB: 0x%8.8x\n", AdapterCB->NbfBundleCB);
+ dprintf(" NbfProtocolHandle: 0x%8.8x\n", AdapterCB->NbfProtocolHandle);
+
+}
+
+VOID
+DisplayConnectionTable(
+ DWORD Address,
+ PCONNECTION_TABLE ConnectionTable
+ )
+{
+ dprintf("\n\nConnectionTable: 0x%8.8x\n", Address);
+ dprintf(" Lock: 0x%8.8x Irql: 0x%8.8x\n",
+ ConnectionTable->Lock.SpinLock, ConnectionTable->Lock.OldIrql);
+ dprintf(" AllocationSize: %ld\n", ConnectionTable->ulAllocationSize);
+ dprintf(" ArraySize: %ld\n", ConnectionTable->ulArraySize);
+ dprintf(" Number Of Active Links: %ld\n", ConnectionTable->ulNumActiveLinks);
+ dprintf(" Number Of Active Bundles: %ld\n", ConnectionTable->ulNumActiveBundles);
+ dprintf(" LinkArray: 0x%8.8x\n", ConnectionTable->LinkArray);
+ dprintf(" BundleArray: 0x%8.8x\n", ConnectionTable->BundleArray);
+}
+
+VOID
+DisplayLinkCB(
+ DWORD Address,
+ PLINKCB LinkCB
+ )
+{
+ dprintf("\n\nLinkCB: 0x%8.8x\n", Address);
+ dprintf(" Linkage:\n");
+ dprintf(" Flink: 0x%8.8x Blink: 0x%8.8x\n",
+ LinkCB->Linkage.Flink, LinkCB->Linkage.Blink);
+ dprintf(" Handle: 0x%8.8x\n", LinkCB->hLinkHandle);
+ dprintf(" User Context: 0x%8.8x\n", LinkCB->hLinkContext);
+ dprintf(" ReferenceCount: %ld\n", LinkCB->ulReferenceCount);
+ dprintf(" State: %s\n", LinkCBStates[LinkCB->State]);
+ dprintf(" WanAdapterCB: 0x%8.8x\n", LinkCB->WanAdapterCB);
+ dprintf(" BundleCB: 0x%8.8x\n", LinkCB->BundleCB);
+ dprintf(" WanMiniport Lineup Context: 0x%8.8x\n", LinkCB->NdisLinkHandle);
+ dprintf(" WanPacketPool:\n");
+ dprintf(" Flink: 0x%8.8x Blink: 0x%8.8x\n",
+ LinkCB->WanPacketPool.Flink, LinkCB->WanPacketPool.Blink);
+ dprintf(" WanPacketCount: %ld\n", LinkCB->ulWanPacketCount);
+ dprintf(" OutstandingFrames: %ld\n", LinkCB->OutstandingFrames);
+ dprintf(" LinkBandwidth: %ld\n", LinkCB->ulBandwidth);
+ dprintf(" LinkInfo:\n");
+ dprintf(" MaxSendFrameSize: %ld\n", LinkCB->LinkInfo.MaxSendFrameSize);
+ dprintf(" MaxRecvFrameSize: %ld\n", LinkCB->LinkInfo.MaxRecvFrameSize);
+ dprintf(" HeaderPadding: %ld\n", LinkCB->LinkInfo.HeaderPadding);
+ dprintf(" TailPadding: %ld\n", LinkCB->LinkInfo.TailPadding);
+ dprintf(" SendFramingBits: 0x%8.8x\n", LinkCB->LinkInfo.SendFramingBits);
+ dprintf(" RecvFramingBits: 0x%8.8x\n", LinkCB->LinkInfo.RecvFramingBits);
+ dprintf(" SendCompressionBits: 0x%8.8x\n", LinkCB->LinkInfo.SendCompressionBits);
+ dprintf(" RecvCompressionBits: 0x%8.8x\n", LinkCB->LinkInfo.RecvCompressionBits);
+ dprintf(" SendACCM: 0x%8.8x\n", LinkCB->LinkInfo.SendACCM);
+ dprintf(" RecvACCM: 0x%8.8x\n", LinkCB->LinkInfo.RecvACCM);
+ dprintf(" MaxRSendFrameSize: %ld\n", LinkCB->LinkInfo.MaxRSendFrameSize);
+ dprintf(" MaxRRecvFrameSize: %ld\n", LinkCB->LinkInfo.MaxRRecvFrameSize);
+ dprintf(" LineUpInfo:\n");
+ dprintf(" LinkSpeed: %ld\n", LinkCB->LineUpInfo.LinkSpeed);
+ dprintf(" Quality: 0x%8.8x\n", LinkCB->LineUpInfo.Quality);
+ dprintf(" SendWindow: %d\n", LinkCB->LineUpInfo.SendWindow);
+ dprintf(" ConnectionWrapperID: 0x%8.8x\n", LinkCB->LineUpInfo.ConnectionWrapperID);
+ dprintf(" NdisLinkHandle: 0x%8.8x\n", LinkCB->LineUpInfo.NdisLinkHandle);
+ dprintf(" NdisLinkContext: 0x%8.8x\n", LinkCB->LineUpInfo.NdisLinkContext);
+ dprintf(" FriendlyName: %s\n", LinkCB->Name);
+ dprintf(" LinkStats:\n");
+ dprintf(" BytesTransmitted: %ld\n", LinkCB->LinkStats.BytesTransmitted);
+ dprintf(" BytesReceived: %ld\n", LinkCB->LinkStats.BytesReceived);
+ dprintf(" FramesTransmitted: %ld\n", LinkCB->LinkStats.FramesTransmitted);
+ dprintf(" FramesReceived: %ld\n", LinkCB->LinkStats.FramesReceived);
+
+ dprintf(" CRCErrors: %ld\n", LinkCB->LinkStats.CRCErrors);
+ dprintf(" TimeoutErrors: %ld\n", LinkCB->LinkStats.TimeoutErrors);
+ dprintf(" AlignmentErrors: %ld\n", LinkCB->LinkStats.AlignmentErrors);
+ dprintf(" SerialOverrunErrors: %ld\n", LinkCB->LinkStats.SerialOverrunErrors);
+ dprintf(" FramingErrors: %ld\n", LinkCB->LinkStats.FramingErrors);
+ dprintf(" BufferOverrunErrors: %ld\n", LinkCB->LinkStats.BufferOverrunErrors);
+ dprintf(" ByteTransmittedUncompressed: %ld\n", LinkCB->LinkStats.BytesTransmittedUncompressed);
+ dprintf(" BytesReceivedUncompressed: %ld\n", LinkCB->LinkStats.BytesReceivedUncompressed);
+ dprintf(" BytesTransmittedCompressed: %ld\n", LinkCB->LinkStats.BytesTransmittedCompressed);
+ dprintf(" BytesReceivedCompressed: %ld\n", LinkCB->LinkStats.BytesReceivedCompressed);
+}
+
+VOID
+DisplayBundleCB(
+ DWORD Address,
+ PBUNDLECB BundleCB
+ )
+{
+ DWORD i;
+
+ dprintf("\n\nBundleCB: 0x%8.8x\n", Address);
+ dprintf(" Handle: 0x%8.8x\n",BundleCB->hBundleHandle);
+ dprintf(" ReferenceCount: %ld\n",BundleCB->ulReferenceCount);
+ dprintf(" State: %s\n",BundleCBStates[BundleCB->State]);
+ dprintf(" LinkCBList:\n");
+ dprintf(" Flink: 0x%8.8x Blink: 0x%8.8x\n",
+ BundleCB->LinkCBList.Flink, BundleCB->LinkCBList.Blink);
+ dprintf(" LinkCBCount: %ld\n",BundleCB->ulLinkCBCount);
+ dprintf(" FramingInfo:\n");
+ dprintf(" SendFramingBits: 0x%8.8x\n", BundleCB->FramingInfo.SendFramingBits);
+ dprintf(" RecvFramingBits: 0x%8.8x\n", BundleCB->FramingInfo.RecvFramingBits);
+ dprintf(" MaxRSendFrameSize: %ld\n", BundleCB->FramingInfo.MaxRSendFrameSize);
+ dprintf(" MaxRRecvFrameSize: %ld\n", BundleCB->FramingInfo.MaxRRecvFrameSize);
+ dprintf(" NextLinkToXmit: 0x%8.8x\n",BundleCB->NextLinkToXmit);
+ dprintf(" SendingLinks: %d\n", BundleCB->SendingLinks);
+ dprintf(" SendPacketQueue:\n");
+ dprintf(" Flink: 0x%8.8x Blink: 0x%8.8x\n",
+ BundleCB->SendPacketQueue.Flink, BundleCB->SendPacketQueue.Blink);
+ dprintf(" SendSequenceNumber: 0x%8.8x\n", BundleCB->SendSeqNumber);
+ dprintf(" MaxSendSequenceNumber: 0x%8.8x\n", BundleCB->MaxSendSeqNumber);
+ dprintf(" SendSequenceMask: 0x%8.8x\n", BundleCB->SendSeqMask);
+ dprintf(" Flags: 0x%8.8x\n",BundleCB->Flags);
+ dprintf(" OutstandingFrames: %ld\n",BundleCB->OutstandingFrames);
+ dprintf(" RecvDescPool:\n");
+ dprintf(" Flink: 0x%8.8x Blink: 0x%8.8x\n",
+ BundleCB->RecvDescPool.Flink, BundleCB->RecvDescPool.Blink);
+ dprintf(" RecvDesc Count: %ld\n", BundleCB->RecvDescCount);
+ dprintf(" RecvDesc Max Count: %ld\n", BundleCB->RecvDescMax);
+ dprintf(" RecvDescAssemblyList:\n");
+ dprintf(" Flink: 0x%8.8x Blink: 0x%8.8x\n",
+ BundleCB->RecvDescAssemblyList.Flink, BundleCB->RecvDescAssemblyList.Blink);
+ dprintf(" RecvDescHole: 0x%8.8x\n", BundleCB->RecvDescHole);
+ dprintf(" MaxRecvSeqNumber: 0x%8.8x\n", BundleCB->MaxRecvSeqNumber);
+ dprintf(" RecvSeqMask: 0x%8.8x\n", BundleCB->RecvSeqMask);
+ dprintf(" TimeToLive: %ld\n", BundleCB->TimeToLive);
+ dprintf(" RecvFragmentsLost: %ld\n", BundleCB->RecvFragmentsLost);
+ dprintf(" ProtocolCBTable: 0x%8.8x\n",BundleCB->ProtocolCBTable);
+ dprintf(" Number Of Routes: %ld\n",BundleCB->ulNumberOfRoutes);
+ dprintf(" ProtocolCBList:\n");
+ dprintf(" Flink: 0x%8.8x Blink: 0x%8.8x\n",
+ BundleCB->ProtocolCBList.Flink, BundleCB->ProtocolCBList.Blink);
+ dprintf(" SendMask: 0x%8.8x\n",BundleCB->SendMask);
+ dprintf(" LineUpInfo:\n");
+ dprintf(" BundleSpeed: %ld\n", BundleCB->LineUpInfo.BundleSpeed);
+ dprintf(" MaxSendSize: %ld\n", BundleCB->LineUpInfo.ulMaximumTotalSize);
+ dprintf(" LinkQuality: %s\n", WanQuality[BundleCB->LineUpInfo.Quality]);
+ dprintf(" SendWindow: %d\n", BundleCB->LineUpInfo.usSendWindow);
+ dprintf(" SendVJInfo:\n");
+ dprintf(" IPCompressionProtocol: 0x%4.4x\n", BundleCB->SendVJInfo.IPCompressionProtocol);
+ dprintf(" MaxSlotID: %d\n", BundleCB->SendVJInfo.MaxSlotID);
+ dprintf(" CompSlotID: %d\n", BundleCB->SendVJInfo.CompSlotID);
+ dprintf(" VJCompress: 0x%8.8x\n", BundleCB->SendVJCompress);
+ dprintf(" RecvVJInfo:\n");
+ dprintf(" IPCompressionProtocol: 0x%4.4x\n", BundleCB->RecvVJInfo.IPCompressionProtocol);
+ dprintf(" MaxSlotID: %d\n", BundleCB->RecvVJInfo.MaxSlotID);
+ dprintf(" CompSlotID: %d\n", BundleCB->RecvVJInfo.CompSlotID);
+ dprintf(" VJCompress: 0x%8.8x\n", BundleCB->RecvVJCompress);
+ dprintf(" SendCompInfo:\n");
+ dprintf(" SessionKey: 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n",
+ BundleCB->SendCompInfo.SessionKey[0],BundleCB->SendCompInfo.SessionKey[1],
+ BundleCB->SendCompInfo.SessionKey[2],BundleCB->SendCompInfo.SessionKey[3],
+ BundleCB->SendCompInfo.SessionKey[4],BundleCB->SendCompInfo.SessionKey[5],
+ BundleCB->SendCompInfo.SessionKey[6],BundleCB->SendCompInfo.SessionKey[7]);
+ dprintf(" MSCompType: 0x%8.8x\n", BundleCB->SendCompInfo.MSCompType);
+ dprintf(" SendCompressContext: 0x%8.8x\n", BundleCB->SendCompressContext);
+ dprintf(" RecvCompInfo:\n");
+ dprintf(" SessionKey: 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n",
+ BundleCB->RecvCompInfo.SessionKey[0],BundleCB->RecvCompInfo.SessionKey[1],
+ BundleCB->RecvCompInfo.SessionKey[2],BundleCB->RecvCompInfo.SessionKey[3],
+ BundleCB->RecvCompInfo.SessionKey[4],BundleCB->RecvCompInfo.SessionKey[5],
+ BundleCB->RecvCompInfo.SessionKey[6],BundleCB->RecvCompInfo.SessionKey[7]);
+ dprintf(" MSCompType: 0x%8.8x\n", BundleCB->RecvCompInfo.MSCompType);
+ dprintf(" RecvCompressContext: 0x%8.8x\n", BundleCB->RecvCompressContext);
+ dprintf(" SendRC4Key: 0x%8.8x\n", BundleCB->SendRC4Key);
+ dprintf(" RecvRC4Key: 0x%8.8x\n", BundleCB->RecvRC4Key);
+ dprintf(" SCoherencyCounter: 0x%4.4x\n", BundleCB->SCoherencyCounter);
+ dprintf(" RCoherencyCounter: 0x%4.4x\n", BundleCB->RCoherencyCounter);
+ dprintf(" LastRC4Reset: 0x%4.4x\n", BundleCB->LastRC4Reset);
+ dprintf(" CCPIdentifier: 0x%4.4x\n", BundleCB->CCPIdentifier);
+ dprintf(" UpperBonDInfo:\n");
+ dprintf(" BytesThreshold: %ld\n", BundleCB->UpperBonDInfo.ulBytesThreshold);
+ dprintf(" PercentBandwidth: %d\n", BundleCB->UpperBonDInfo.usPercentBandwidth);
+ dprintf(" SecondsInSamplePeriod: %ld\n", BundleCB->UpperBonDInfo.ulSecondsInSamplePeriod);
+ dprintf(" State: 0x%8.8x\n", BundleCB->UpperBonDInfo.State);
+ dprintf(" StartTime: 0x%8.8x%8.8x\n",
+ BundleCB->UpperBonDInfo.StartTime.HighPart, BundleCB->UpperBonDInfo.StartTime.LowPart);
+ dprintf(" SampleTable:\n");
+ dprintf(" FirstIndex: %ld\n", BundleCB->UpperBonDInfo.SampleTable.ulFirstIndex);
+ dprintf(" CurrentIndex: %ld\n", BundleCB->UpperBonDInfo.SampleTable.ulCurrentIndex);
+ dprintf(" CurrentSampleByteCount: %ld\n", BundleCB->UpperBonDInfo.SampleTable.ulCurrentSampleByteCount);
+ dprintf(" SampleArraySize: %ld\n", BundleCB->UpperBonDInfo.SampleTable.ulSampleArraySize);
+ dprintf(" SampleRate: 0x%8.8x%8.8x\n",
+ BundleCB->UpperBonDInfo.SampleTable.SampleRate.HighPart, BundleCB->UpperBonDInfo.SampleTable.SampleRate.LowPart);
+ dprintf(" SamplePeriod: 0x%8.8x%8.8x\n",
+ BundleCB->UpperBonDInfo.SampleTable.SamplePeriod.HighPart, BundleCB->UpperBonDInfo.SampleTable.SamplePeriod.LowPart);
+ dprintf(" SampleTable:\n");
+ for (i = 0; i < SAMPLE_ARRAY_SIZE; i++) {
+ dprintf(" Sample %d:\n", i);
+ dprintf(" BytesThisSend: %ld\n",BundleCB->UpperBonDInfo.SampleTable.SampleArray[i].ulBytesThisSend);
+ dprintf(" ReferenceCount: %ld\n",BundleCB->UpperBonDInfo.SampleTable.SampleArray[i].ulReferenceCount);
+ dprintf(" TimeStample: 0x%8.8x%8.8x\n",
+ BundleCB->UpperBonDInfo.SampleTable.SampleArray[i].TimeStamp.HighPart, BundleCB->UpperBonDInfo.SampleTable.SampleArray[i].TimeStamp.LowPart);
+ }
+ dprintf(" LowerBonDInfo:\n");
+ dprintf(" BytesThreshold: %ld\n", BundleCB->LowerBonDInfo.ulBytesThreshold);
+ dprintf(" PercentBandwidth: %d\n", BundleCB->LowerBonDInfo.usPercentBandwidth);
+ dprintf(" SecondsInSamplePeriod: %ld\n", BundleCB->LowerBonDInfo.ulSecondsInSamplePeriod);
+ dprintf(" State: 0x%8.8x\n", BundleCB->LowerBonDInfo.State);
+ dprintf(" StartTime: 0x%8.8x%8.8x\n",
+ BundleCB->LowerBonDInfo.StartTime.HighPart, BundleCB->LowerBonDInfo.StartTime.LowPart);
+ dprintf(" SampleTable:\n");
+ dprintf(" FirstIndex: %ld\n", BundleCB->LowerBonDInfo.SampleTable.ulFirstIndex);
+ dprintf(" CurrentIndex: %ld\n", BundleCB->LowerBonDInfo.SampleTable.ulCurrentIndex);
+ dprintf(" CurrentSampleByteCount: %ld\n", BundleCB->LowerBonDInfo.SampleTable.ulCurrentSampleByteCount);
+ dprintf(" SampleArraySize: %ld\n", BundleCB->LowerBonDInfo.SampleTable.ulSampleArraySize);
+ dprintf(" SampleRate: 0x%8.8x%8.8x\n",
+ BundleCB->LowerBonDInfo.SampleTable.SampleRate.HighPart, BundleCB->LowerBonDInfo.SampleTable.SampleRate.LowPart);
+ dprintf(" SamplePeriod: 0x%8.8x%8.8x\n",
+ BundleCB->LowerBonDInfo.SampleTable.SamplePeriod.HighPart, BundleCB->LowerBonDInfo.SampleTable.SamplePeriod.LowPart);
+ dprintf(" SampleArray:\n");
+ for (i = 0; i < SAMPLE_ARRAY_SIZE; i++) {
+ dprintf(" Sample %d:\n", i);
+ dprintf(" BytesThisSend: %ld\n",BundleCB->LowerBonDInfo.SampleTable.SampleArray[i].ulBytesThisSend);
+ dprintf(" ReferenceCount: %ld\n",BundleCB->LowerBonDInfo.SampleTable.SampleArray[i].ulReferenceCount);
+ dprintf(" TimeStample: 0x%8.8x%8.8x\n",
+ BundleCB->LowerBonDInfo.SampleTable.SampleArray[i].TimeStamp.HighPart, BundleCB->LowerBonDInfo.SampleTable.SampleArray[i].TimeStamp.LowPart);
+ }
+ dprintf(" FriendlyName: %s\n", BundleCB->Name);
+ dprintf(" BundleStats:\n");
+ dprintf(" BytesTransmitted: %ld\n", BundleCB->BundleStats.BytesTransmitted);
+ dprintf(" BytesReceived: %ld\n", BundleCB->BundleStats.BytesReceived);
+ dprintf(" FramesTransmitted: %ld\n", BundleCB->BundleStats.FramesTransmitted);
+ dprintf(" FramesReceived: %ld\n", BundleCB->BundleStats.FramesReceived);
+
+ dprintf(" CRCErrors: %ld\n", BundleCB->BundleStats.CRCErrors);
+ dprintf(" TimeoutErrors: %ld\n", BundleCB->BundleStats.TimeoutErrors);
+ dprintf(" AlignmentErrors: %ld\n", BundleCB->BundleStats.AlignmentErrors);
+ dprintf(" SerialOverrunErrors: %ld\n", BundleCB->BundleStats.SerialOverrunErrors);
+ dprintf(" FramingErrors: %ld\n", BundleCB->BundleStats.FramingErrors);
+ dprintf(" BufferOverrunErrors: %ld\n", BundleCB->BundleStats.BufferOverrunErrors);
+ dprintf(" ByteTransmittedUncompressed: %ld\n", BundleCB->BundleStats.BytesTransmittedUncompressed);
+ dprintf(" BytesReceivedUncompressed: %ld\n", BundleCB->BundleStats.BytesReceivedUncompressed);
+ dprintf(" BytesTransmittedCompressed: %ld\n", BundleCB->BundleStats.BytesTransmittedCompressed);
+ dprintf(" BytesReceivedCompressed: %ld\n", BundleCB->BundleStats.BytesReceivedCompressed);
+}
+
+VOID
+DisplayProtocolCB(
+ DWORD Address,
+ PPROTOCOLCB ProtocolCB
+ )
+{
+ DWORD i;
+
+ dprintf("\n\nProtocolCB: 0x%8.8x\n", Address);
+ dprintf(" Linkage:\n");
+ dprintf(" Flink: 0x%8.8x Blink: 0x%8.8x\n",
+ ProtocolCB->Linkage.Flink, ProtocolCB->Linkage.Blink);
+ dprintf(" ProtocolHandle: 0x%8.8x\n", ProtocolCB->hProtocolHandle);
+ dprintf(" ReferenceCount: %ld\n", ProtocolCB->ulReferenceCount);
+ dprintf(" HeadNdisPacketQueue: 0x%8.8x\n", ProtocolCB->HeadNdisPacketQueue);
+ dprintf(" TailNdisPacketQueue: 0x%8.8x\n", ProtocolCB->TailNdisPacketQueue);
+ dprintf(" SendMaskBit: 0x%8.8x\n", ProtocolCB->SendMaskBit);
+ dprintf(" AdapterCB: 0x%8.8x\n", ProtocolCB->AdapterCB);
+ dprintf(" BundleCB: 0x%8.8x\n", ProtocolCB->BundleCB);
+ dprintf(" Flags: 0x%8.8x\n", ProtocolCB->Flags);
+ dprintf(" ProtocolType: 0x%4.4x\n", ProtocolCB->usProtocolType);
+ dprintf(" PPP ProtocolID: 0x%4.4x\n", ProtocolCB->usPPPProtocolID);
+ dprintf(" Priority: %ld\n", ProtocolCB->usPriority);
+ dprintf(" Bytes Quota: %ld\n", ProtocolCB->ulByteQuota);
+ dprintf(" SampleTable:\n");
+ dprintf(" FirstIndex: %ld\n", ProtocolCB->SampleTable.ulFirstIndex);
+ dprintf(" CurrentIndex: %ld\n", ProtocolCB->SampleTable.ulCurrentIndex);
+ dprintf(" CurrentSampleByteCount: %ld\n", ProtocolCB->SampleTable.ulCurrentSampleByteCount);
+ dprintf(" SampleArraySize: %ld\n", ProtocolCB->SampleTable.ulSampleArraySize);
+ dprintf(" SampleRate: 0x%8.8x%8.8x\n",
+ ProtocolCB->SampleTable.SampleRate.HighPart, ProtocolCB->SampleTable.SampleRate.LowPart);
+ dprintf(" SamplePeriod: 0x%8.8x%8.8x\n",
+ ProtocolCB->SampleTable.SamplePeriod.HighPart, ProtocolCB->SampleTable.SamplePeriod.LowPart);
+ dprintf(" SampleArray:\n");
+ for (i = 0; i < SAMPLE_ARRAY_SIZE; i++) {
+ dprintf(" Sample %d:\n", i);
+ dprintf(" BytesThisSend: %ld\n",ProtocolCB->SampleTable.SampleArray[i].ulBytesThisSend);
+ dprintf(" ReferenceCount: %ld\n",ProtocolCB->SampleTable.SampleArray[i].ulReferenceCount);
+ dprintf(" TimeStample: 0x%8.8x%8.8x\n",
+ ProtocolCB->SampleTable.SampleArray[i].TimeStamp.HighPart, ProtocolCB->SampleTable.SampleArray[i].TimeStamp.LowPart);
+ }
+ dprintf(" TransportHandle: 0x%8.8x\n", ProtocolCB->hTransportHandle);
+ dprintf(" NdisWanAddress: 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n",
+ ProtocolCB->NdisWanAddress[0], ProtocolCB->NdisWanAddress[1], ProtocolCB->NdisWanAddress[2],
+ ProtocolCB->NdisWanAddress[3], ProtocolCB->NdisWanAddress[4], ProtocolCB->NdisWanAddress[5]);
+ dprintf(" TransportAddress: 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n",
+ ProtocolCB->TransportAddress[0], ProtocolCB->TransportAddress[1], ProtocolCB->TransportAddress[2],
+ ProtocolCB->TransportAddress[3], ProtocolCB->TransportAddress[4], ProtocolCB->TransportAddress[5]);
+ dprintf(" DeviceName: Buffer: 0x%8.8x Length: %ld\n",
+ ProtocolCB->DeviceName.Buffer, ProtocolCB->DeviceName.Length);
+}
+
+VOID
+DisplayWanPacket(
+ DWORD Address,
+ PNDIS_WAN_PACKET Packet
+ )
+{
+
+ dprintf("\n\nWanPacket: 0x%8.8x\n", Address);
+ dprintf(" WanPacketQueue:\n");
+ dprintf(" Flink: 0x%8.8x Blink: 0x%8.8x\n",
+ Packet->WanPacketQueue.Flink, Packet->WanPacketQueue.Blink);
+ dprintf(" CurrentBuffer: 0x%8.8x\n", Packet->CurrentBuffer);
+ dprintf(" CurrentLength: %ld\n", Packet->CurrentLength);
+ dprintf(" StartBuffer: 0x%8.8x\n", Packet->StartBuffer);
+ dprintf(" EndBuffer: 0x%8.8x\n", Packet->EndBuffer);
+ dprintf(" PR1 (LinkCB): 0x%8.8x\n", Packet->ProtocolReserved1);
+ dprintf(" PR2 (NdisPacket): 0x%8.8x\n", Packet->ProtocolReserved2);
+ dprintf(" PR3 (ProtocolCB): 0x%8.8x\n", Packet->ProtocolReserved3);
+ dprintf(" PR4 (BytesSent): %ld\n", Packet->ProtocolReserved4);
+ dprintf(" MR1: 0x%8.8x\n", Packet->MacReserved1);
+ dprintf(" MR2: 0x%8.8x\n", Packet->MacReserved2);
+ dprintf(" MR3: 0x%8.8x\n", Packet->MacReserved3);
+ dprintf(" MR4: 0x%8.8x\n", Packet->MacReserved4);
+}
+
+VOID
+DisplayNdisPacket(
+ DWORD Address,
+ PNDIS_PACKET Packet
+ )
+{
+
+ dprintf("\n\nNdisPacket: 0x%8.8x\n", Address);
+ dprintf(" Private:\n");
+ dprintf(" PhysicalCount: 0x%8.8x\n", Packet->Private.PhysicalCount);
+ dprintf(" TotalLength: %ld\n", Packet->Private.TotalLength);
+ dprintf(" BufferHead: 0x%8.8x\n", Packet->Private.Head);
+ dprintf(" BufferTail: 0x%8.8x\n", Packet->Private.Tail);
+ dprintf(" Pool: 0x%8.8x\n", Packet->Private.Pool);
+ dprintf(" Count: 0x%8.8x\n", Packet->Private.Count);
+ dprintf(" Flags: 0x%8.8x\n", Packet->Private.Flags);
+ dprintf(" ValidCounts: %d\n", Packet->Private.ValidCounts);
+ dprintf(" MR1 (Next/MagicNumber): 0x%8.8x\n", *((PDWORD)&Packet->MiniportReserved[0]));
+ dprintf(" MR2 (ReferenceCount): 0x%4.4x (Flags): 0x%4.4x\n",
+ *((PWORD)&Packet->MiniportReserved[4]),*((PWORD)&Packet->MiniportReserved[6]));
+ dprintf(" WR1: 0x%8.8x\n", *((PDWORD)&Packet->WrapperReserved[0]));
+ dprintf(" WR2: 0x%8.8x\n", *((PDWORD)&Packet->WrapperReserved[4]));
+}
+
diff --git a/private/ntos/ndis/ndiswan/kdexts/display.h b/private/ntos/ndis/ndiswan/kdexts/display.h
new file mode 100644
index 000000000..58795a3b9
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/kdexts/display.h
@@ -0,0 +1,54 @@
+VOID
+DisplayNdisWanCB(
+ DWORD Address,
+ PNDISWANCB NdisWanCB
+ );
+
+VOID
+DisplayWanAdapterCB(
+ ULONG Address,
+ PWAN_ADAPTERCB WanAdapterCB
+ );
+
+VOID
+DisplayAdapterCB(
+ ULONG Address,
+ PADAPTERCB AdapterCB
+ );
+
+VOID
+DisplayConnectionTable(
+ DWORD Address,
+ PCONNECTION_TABLE ConnectionTable
+ );
+
+VOID
+DisplayBundleCB(
+ DWORD Address,
+ PBUNDLECB BundleCB
+ );
+
+VOID
+DisplayProtocolCB(
+ DWORD Address,
+ PPROTOCOLCB ProtocolCB
+ );
+
+VOID
+DisplayLinkCB(
+ DWORD Address,
+ PLINKCB LinkCB
+ );
+
+VOID
+DisplayWanPacket(
+ DWORD Address,
+ PNDIS_WAN_PACKET Packet
+ );
+
+VOID
+DisplayNdisPacket(
+ DWORD Address,
+ PNDIS_PACKET Packet
+ );
+
diff --git a/private/ntos/ndis/ndiswan/kdexts/makefile b/private/ntos/ndis/ndiswan/kdexts/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/kdexts/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/ndiswan/kdexts/sources b/private/ntos/ndis/ndiswan/kdexts/sources
new file mode 100644
index 000000000..32e7d2812
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/kdexts/sources
@@ -0,0 +1,49 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Tony Bell (tonybe)
+
+!ENDIF
+
+TARGETNAME=wanhelp
+DLLBASE=0x58400000
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+
+INCLUDES=..\;..\..\inc;..\..\..\inc;..\..\..\..\inc;..\..\..\..\..\public\sdk\inc
+
+C_DEFINES=-DNT -DNDIS_WRAPPER
+
+DLLENTRY=_DllMainCRTStartup
+
+SOURCES=wanhelp.c \
+ display.c \
+ api.c \
+ wanhelp.rc
+
+UMTYPE=console
+USE_CRTDLL=1
+DLLBASE=0x1000000
+
+MSC_WARNING_LEVEL=/W3
+
+LINKLIBS=\
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib
+# $(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+# $(BASEDIR)\public\sdk\lib\*\libcmt.lib
+
diff --git a/private/ntos/ndis/ndiswan/kdexts/wanhelp.c b/private/ntos/ndis/ndiswan/kdexts/wanhelp.c
new file mode 100644
index 000000000..e2c8b0c0c
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/kdexts/wanhelp.c
@@ -0,0 +1,183 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ kdexts.c
+
+Abstract:
+
+ This file contains the generic routines and initialization code
+ for the kernel debugger extensions dll.
+
+Author:
+
+
+Environment:
+
+ User Mode
+
+--*/
+
+#include <wanhelp.h>
+
+//
+// globals
+//
+EXT_API_VERSION ApiVersion = { 3, 5, EXT_API_VERSION_NUMBER, 0 };
+WINDBG_EXTENSION_APIS ExtensionApis;
+ULONG STeip;
+ULONG STebp;
+ULONG STesp;
+USHORT SavedMajorVersion;
+USHORT SavedMinorVersion;
+VOID UnicodeToAnsi(PWSTR pws,PSTR ps, ULONG cbLength);
+CHAR Name[1024];
+
+PSTR gApiDescriptions[] =
+{
+ "help - What do you think your reading?\n",
+ "ndiswancb - Dump the contents of the main NdisWan control structure\n",
+ "enumwanadaptercb - Dump the head of the WanAdapterCB list\n",
+ "wanadaptercb - Dump the contents of a Wan Miniport Adapter structure\n",
+ "enumadaptercb - Dump the head of the AdapterCB list\n",
+ "adaptercb - Dump the contents of a NdisWan Adapter structure\n",
+ "connectiontable - Dump the connetion table\n",
+ "bundlecb - Dump the bundlecb\n",
+ "linkcb - Dump the linkcb\n",
+ "protocolcb - Dump the protocolcb\n",
+ "wanpacket - Dump the wanpacket\n",
+ "ndispacket - Dump the ndispacket\n",
+};
+
+#define MAX_APIS 12
+
+//
+// THESE ARE NEEDED FOR THE KDEXT DLLs
+//
+BOOLEAN
+DllInit(
+ HANDLE hModule,
+ DWORD dwReason,
+ DWORD dwReserved
+ )
+{
+ switch (dwReason) {
+ case DLL_THREAD_ATTACH:
+ DbgBreakPoint();
+ break;
+
+ case DLL_THREAD_DETACH:
+ break;
+
+ case DLL_PROCESS_DETACH:
+ break;
+
+ case DLL_PROCESS_ATTACH:
+ break;
+ }
+
+ return TRUE;
+}
+
+
+//
+// THESE ARE NEEDED FOR THE KDEXT DLLs
+//
+VOID
+WinDbgExtensionDllInit(
+ PWINDBG_EXTENSION_APIS lpExtensionApis,
+ USHORT MajorVersion,
+ USHORT MinorVersion
+ )
+{
+ ExtensionApis = *lpExtensionApis;
+
+ SavedMajorVersion = MajorVersion;
+ SavedMinorVersion = MinorVersion;
+
+ return;
+}
+
+//
+// THESE ARE NEEDED FOR THE KDEXT DLLs
+//
+DECLARE_API( version )
+{
+#if DBG
+ PCHAR DebuggerType = "Checked";
+#else
+ PCHAR DebuggerType = "Free";
+#endif
+
+ dprintf( "%s Extension dll for Build %d debugging %s kernel for Build %d\n",
+ DebuggerType,
+ VER_PRODUCTBUILD,
+ SavedMajorVersion == 0x0c ? "Checked" : "Free",
+ SavedMinorVersion
+ );
+}
+
+//
+// THESE ARE NEEDED FOR THE KDEXT DLLs
+//
+VOID
+CheckVersion(
+ VOID
+ )
+{
+#if DBG
+ if ((SavedMajorVersion != 0x0c) || (SavedMinorVersion != VER_PRODUCTBUILD)) {
+ dprintf("\r\n*** Extension DLL(%d Checked) does not match target system(%d %s)\r\n\r\n",
+ VER_PRODUCTBUILD, SavedMinorVersion, (SavedMajorVersion==0x0f) ? "Free" : "Checked" );
+ }
+#else
+ if ((SavedMajorVersion != 0x0f) || (SavedMinorVersion != VER_PRODUCTBUILD)) {
+ dprintf("\r\n*** Extension DLL(%d Free) does not match target system(%d %s)\r\n\r\n",
+ VER_PRODUCTBUILD, SavedMinorVersion, (SavedMajorVersion==0x0f) ? "Free" : "Checked" );
+ }
+#endif
+}
+
+LPEXT_API_VERSION
+ExtensionApiVersion(
+ VOID
+ )
+{
+ return &ApiVersion;
+}
+
+/*++
+ Try and keep an accurate list of commands.
+--*/
+DECLARE_API(help)
+{
+ UINT c;
+
+ if (0 == args[0]) {
+ for (c = 0; c < MAX_APIS; c++)
+ dprintf(gApiDescriptions[c]);
+ return;
+ }
+}
+
+VOID
+UnicodeToAnsi(
+ PWSTR pws,
+ PSTR ps,
+ ULONG cbLength
+ )
+{
+ PSTR Dest = ps;
+ PWSTR Src = pws;
+ ULONG Length = cbLength;
+
+ dprintf("Enter UnicodeToAnsi\n");
+
+ while (Length--) {
+ *Dest++ = (CHAR)*Src++;
+ }
+
+ dprintf("Exit UnicodeToAnsi\n");
+}
diff --git a/private/ntos/ndis/ndiswan/kdexts/wanhelp.def b/private/ntos/ndis/ndiswan/kdexts/wanhelp.def
new file mode 100644
index 000000000..8acaae7a4
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/kdexts/wanhelp.def
@@ -0,0 +1,48 @@
+;--------------------------------------------------------------------
+;
+; when modifying this file please be aware that the common portions
+; are stored in ..\kdextdef.src. Put your extension in the correct
+; alphabetical order. all extension names must be in lower case!
+;
+;--------------------------------------------------------------------
+
+LIBRARY wanhelp
+
+DESCRIPTION 'Kernel Debugger Extensions Api Library - NdisWan'
+
+EXPORTS
+
+;--------------------------------------------------------------------
+;
+; these are the common exports that all dlls contain
+;
+;--------------------------------------------------------------------
+ help
+ ndiswancb
+ enumwanadaptercb
+ wanadaptercb
+ enumadaptercb
+ adaptercb
+ connectiontable
+ bundlecb
+ linkcb
+ protocolcb
+ wanpacket
+ ndispacket
+
+;--------------------------------------------------------------------
+;
+; these are the i386 specific exports
+;
+;--------------------------------------------------------------------
+
+
+;--------------------------------------------------------------------
+;
+; these are the extension service functions provided for the debugger
+;
+;--------------------------------------------------------------------
+
+ CheckVersion
+ WinDbgExtensionDllInit
+ ExtensionApiVersion
diff --git a/private/ntos/ndis/ndiswan/kdexts/wanhelp.h b/private/ntos/ndis/ndiswan/kdexts/wanhelp.h
new file mode 100644
index 000000000..00016d3c6
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/kdexts/wanhelp.h
@@ -0,0 +1,99 @@
+/*++
+
+ Copyright (c) 1993 Microsoft Corporation
+
+ Module Name:
+
+ wanhelp
+
+ Abstract:
+
+
+ Author:
+
+ Thanks - Kyle Brandon
+
+ History:
+
+--*/
+
+#ifndef __WANHELP_H
+#define __WANHELP_H
+
+//
+// Get rid of as much of Windows as possible
+//
+
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOICONS
+#define NOKEYSTATES
+#define NOSYSCOMMANDS
+#define NORASTEROPS
+#define NOSHOWWINDOW
+#define OEMRESOURCE
+#define NOATOM
+#define NOCLIPBOARD
+#define NOCOLOR
+#define NOCTLMGR
+#define NODRAWTEXT
+#define NOGDI
+#define NOKERNEL
+#define NOUSER
+#define NONLS
+#define NOMB
+#define NOMEMMGR
+#define NOMETAFILE
+#define NOMINMAX
+#define NOMSG
+#define NOOPENFILE
+#define NOSCROLL
+#define NOSERVICE
+#define NOSOUND
+#define NOTEXTMETRIC
+#define NOWH
+#define NOWINOFFSETS
+#define NOCOMM
+#define NOKANJI
+#define NOHELP
+#define NOPROFILER
+#define NODEFERWINDOWPOS
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <ntos.h>
+#include <srb.h>
+#include <io.h>
+#include <windows.h>
+#include <imagehlp.h>
+#include <wdbgexts.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ntverp.h>
+//#include <ndismain.h>
+//#include <ndismac.h>
+//#include <ndismini.h>
+//#include <ndiswan.h>
+#include "wan.h"
+#include "display.h"
+
+//
+// support routines.
+//
+VOID UnicodeToAnsi(PWSTR pws, PSTR ps, ULONG cbLength);
+
+
+//
+// Internal definitions
+//
+
+#define NOT_IMPLEMENTED 0xFACEFEED
+
+
+#endif // __WANHELP_H
+
diff --git a/private/ntos/ndis/ndiswan/kdexts/wanhelp.rc b/private/ntos/ndis/ndiswan/kdexts/wanhelp.rc
new file mode 100644
index 000000000..937dbf7b9
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/kdexts/wanhelp.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Microsoft\256 Kernel Debugger Extensions"
+
+#define VER_INTERNALNAME_STR "KDEXTxxx.DLL"
+#define VER_ORIGINALFILENAME_STR "KDEXTxxx.DLL"
+
+#include <common.ver>
+
diff --git a/private/ntos/ndis/ndiswan/loopback.c b/private/ntos/ndis/ndiswan/loopback.c
new file mode 100644
index 000000000..a7702da3b
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/loopback.c
@@ -0,0 +1,148 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ Loopback.c
+
+Abstract:
+
+ This file contains the procedures for doing loopback of send
+ packets for ndiswan. Loopback is being done in NdisWan because
+ the NDIS wrapper could not meet all of the needs of NdisWan.
+
+Author:
+
+ Tony Bell (TonyBe) January 25, 1996
+
+Environment:
+
+ Kernel Mode
+
+Revision History:
+
+ TonyBe 01/25/96 Created
+
+--*/
+
+#include "wan.h"
+
+VOID
+NdisWanQueueLoopbackPacket(
+ PADAPTERCB AdapterCB,
+ PNDIS_PACKET NdisPacket
+ )
+{
+ PLOOPBACK_DESC LoopbackDesc;
+ ULONG AllocationSize, BufferLength;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_LOOPBACK, ("NdisWanQueueLoopbackPacket: Enter"));
+ NdisWanDbgOut(DBG_INFO, DBG_LOOPBACK, ("AdapterCB: 0x%8.8x, NdisPacket: 0x%8.8x",
+ AdapterCB, NdisPacket));
+
+ //
+ // Create a loopback descriptor
+ //
+ NdisQueryPacket(NdisPacket,
+ NULL,
+ NULL,
+ NULL,
+ &BufferLength);
+
+ AllocationSize = BufferLength + sizeof(LOOPBACK_DESC);
+
+ NdisWanAllocateMemory(&LoopbackDesc, AllocationSize);
+
+ if (LoopbackDesc != NULL) {
+ ULONG BytesCopied;
+ PDEFERRED_DESC DeferredDesc;
+
+ //
+ // For loopback we do not care about the bundlecb/protocolcb
+ // states so they will remain NULL.
+ //
+ LoopbackDesc->AllocationSize = (USHORT)AllocationSize;
+ LoopbackDesc->BufferLength = (USHORT)BufferLength;
+ LoopbackDesc->Buffer = (PUCHAR)LoopbackDesc + sizeof(LOOPBACK_DESC);
+
+ //
+ // Copy the current packet
+ //
+ NdisWanCopyFromPacketToBuffer(NdisPacket,
+ 0,
+ 0xFFFFFFFF,
+ LoopbackDesc->Buffer,
+ &BytesCopied);
+
+ ASSERT(BytesCopied == BufferLength);
+
+ NdisAcquireSpinLock(&AdapterCB->Lock);
+
+ NdisWanGetDeferredDesc(AdapterCB, &DeferredDesc);
+
+ ASSERT(DeferredDesc != NULL);
+
+ DeferredDesc->Context = (PVOID)LoopbackDesc;
+
+ InsertTailDeferredQueue(&AdapterCB->DeferredQueue[Loopback], DeferredDesc);
+
+ NdisWanSetDeferred(AdapterCB);
+
+ NdisReleaseSpinLock(&AdapterCB->Lock);
+
+ } else {
+ NdisWanDbgOut(DBG_FAILURE, DBG_LOOPBACK, ("NdisWanQueueLoopbackPacket: Memory allocation failure!"));
+ }
+}
+
+VOID
+NdisWanProcessLoopbacks(
+ PADAPTERCB AdapterCB
+ )
+{
+ RECV_DESC RecvDesc;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_LOOPBACK, ("NdisWanIndicateLoopback: Enter"));
+ NdisWanDbgOut(DBG_TRACE, DBG_LOOPBACK, ("NdisWanIndicateLoopback: AdapterCB 0x%8.8x", AdapterCB));
+
+ while (!IsDeferredQueueEmpty(&AdapterCB->DeferredQueue[Loopback])) {
+
+ PDEFERRED_DESC ReturnDesc;
+ PLOOPBACK_DESC LoopbackDesc;
+
+ ReturnDesc = RemoveHeadDeferredQueue(&AdapterCB->DeferredQueue[Loopback]);
+
+ NdisReleaseSpinLock(&AdapterCB->Lock);
+
+ LoopbackDesc = ReturnDesc->Context;
+
+ NdisWanDbgOut(DBG_INFO, DBG_LOOPBACK, ("NdisWanIndicateLoopback: Desc 0x%8.8x", LoopbackDesc));
+
+ RecvDesc.Flags = 0x4c4F4F50;
+ RecvDesc.WanHeader = LoopbackDesc->Buffer;
+ RecvDesc.WanHeaderLength = 14;
+ RecvDesc.LookAhead = NULL;
+ RecvDesc.LookAheadLength = 0;
+ RecvDesc.CurrentBuffer = LoopbackDesc->Buffer + 14;
+ RecvDesc.CurrentBufferLength = LoopbackDesc->BufferLength - 14;
+
+ ASSERT((LONG)RecvDesc.CurrentBufferLength > 0);
+
+ NdisMEthIndicateReceive(AdapterCB->hMiniportHandle,
+ &RecvDesc,
+ LoopbackDesc->Buffer,
+ 14,
+ LoopbackDesc->Buffer + 14,
+ LoopbackDesc->BufferLength - 14,
+ LoopbackDesc->BufferLength - 14);
+
+ NdisWanFreeMemory(LoopbackDesc);
+
+ NdisAcquireSpinLock(&AdapterCB->Lock);
+
+ AdapterCB->Flags |= RECEIVE_COMPLETE;
+
+ InsertHeadDeferredQueue(&AdapterCB->FreeDeferredQueue, ReturnDesc);
+ }
+}
diff --git a/private/ntos/ndis/ndiswan/memory.c b/private/ntos/ndis/ndiswan/memory.c
new file mode 100644
index 000000000..740a74e41
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/memory.c
@@ -0,0 +1,1624 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ Ndiswan.c
+
+Abstract:
+
+ This is the initialization file for the NdisWan driver. This driver
+ is a shim between the protocols, where it conforms to the NDIS 3.1
+ Miniport interface spec, and the WAN Miniport drivers, where it exports
+ the WAN Extensions for Miniports (it looks like a protocol to the WAN
+ Miniport drivers).
+
+Author:
+
+ Tony Bell (TonyBe) June 06, 1995
+
+Environment:
+
+ Kernel Mode
+
+Revision History:
+
+ TonyBe 06/06/95 Created
+
+--*/
+
+#include "wan.h"
+#include "tcpip.h"
+#include "vjslip.h"
+
+
+//
+// Local function prototypes
+//
+
+NDIS_STATUS
+NdisWanCreateLinkCB(
+ OUT PLINKCB *LinkCB
+ );
+
+VOID
+NdisWanInitLinkCB(
+ IN PLINKCB *LinkCB,
+ IN PWAN_ADAPTERCB WanAdapterCB,
+ IN ULONG SendWindow
+ );
+
+VOID
+NdisWanDestroyLinkCB(
+ IN PLINKCB LinkCB
+ );
+
+NDIS_STATUS
+NdisWanCreateBundleCB(
+ OUT PBUNDLECB *BundleCB
+ );
+
+VOID
+NdisWanInitBundleCB(
+ IN PBUNDLECB BundleCB
+ );
+
+VOID
+NdisWanDestroyBundleCB(
+ IN PBUNDLECB BundleCB
+ );
+
+NDIS_STATUS
+NdisWanCreateProtocolCB(
+ OUT PPROTOCOLCB *ProtocolCB,
+ IN USHORT usProtocolType,
+ IN USHORT usBindingNameLength,
+ IN PWSTR BindingName,
+ IN ULONG ulBufferLength,
+ IN PUCHAR Buffer
+ );
+
+//VOID
+//NdisWanInitProtocolCB(
+// IN PPROTOCOLCB ProtocolCB,
+// IN ULONG ulBufferLength,
+// IN PUCHAR Buffer,
+// IN USHORT usProtocolType
+// );
+
+VOID
+NdisWanDestroyProtocolCB(
+ IN PPROTOCOLCB ProtocolCB
+ );
+
+
+NDIS_STATUS
+NdisWanAllocateSendResources(
+ IN PLINKCB LinkCB,
+ IN ULONG SendWindow
+ );
+
+VOID
+NdisWanFreeSendResources(
+ IN PLINKCB LinkCB
+ );
+
+//
+// End local function prototypes
+//
+
+
+NDIS_STATUS
+NdisWanCreateAdapterCB(
+ OUT PADAPTERCB *pAdapterCB,
+ IN PNDIS_STRING AdapterName
+ )
+/*++
+
+Routine Name:
+
+ NdisWanCreateAdapterCB
+
+Routine Description:
+
+ This routine creates and initializes an AdapterCB
+
+Arguments:
+
+ pAdapterCB - Pointer to a pointer to the AdapterCB that was created
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_RESOURCES
+
+--*/
+{
+ PADAPTERCB LocalAdapterCB;
+ ULONG ulAllocationSize, i;
+ PDEFERRED_DESC FreeDesc;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_MEMORY, ("NdisWanCreateAdapterCB: Enter"));
+
+ //
+ // Allocate and zero out the memory block
+ //
+ ulAllocationSize = sizeof(ADAPTERCB) + 20*sizeof(DEFERRED_DESC);
+ NdisWanAllocateMemory(&LocalAdapterCB, ulAllocationSize);
+
+ if (LocalAdapterCB == NULL) {
+
+ return (NDIS_STATUS_RESOURCES);
+ }
+
+ //
+ // setup the new control block
+ //
+ LocalAdapterCB->ulAllocationSize = ulAllocationSize;
+
+ NdisAllocateSpinLock(&LocalAdapterCB->Lock);
+
+#ifdef MINIPORT_NAME
+// NdisWanStringToNdisString(&LocalAdapterCB->AdapterName, AdapterName->Buffer);
+ NdisWanAllocateAdapterName(&LocalAdapterCB->AdapterName, AdapterName);
+#endif
+
+ //
+ // Setup free deferred desc list
+ //
+ FreeDesc = (PDEFERRED_DESC)((PUCHAR)LocalAdapterCB + sizeof(ADAPTERCB));
+
+ for (i = 0; i < 20; i++) {
+ InsertHeadDeferredQueue(&LocalAdapterCB->FreeDeferredQueue, FreeDesc);
+ (PUCHAR)FreeDesc += sizeof(DEFERRED_DESC);
+ }
+
+#if DBG
+ InitializeListHead(&LocalAdapterCB->DbgNdisPacketList);
+#endif
+
+ //
+ // Add to global list
+ //
+ InsertTailGlobalList(AdapterCBList, &(LocalAdapterCB->Linkage));
+
+ *pAdapterCB = LocalAdapterCB;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_MEMORY, ("%ls AdapterCB: 0x%x, Number: %d",
+ LocalAdapterCB->AdapterName.Buffer, *pAdapterCB, AdapterCBList.ulCount));
+
+ NdisWanDbgOut(DBG_TRACE, DBG_MEMORY, ("NdisWanCreateAdapterCB: Exit"));
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+VOID
+NdisWanDestroyAdapterCB(
+ IN PADAPTERCB pAdapterCB
+ )
+/*++
+
+Routine Name:
+
+ NdisWanDestroyAdapterCB
+
+Routine Description:
+
+ This destroys an AdapterCB
+
+Arguments:
+
+ pAdapterCB - Pointer to to the AdapterCB that is being destroyed
+
+Return Values:
+
+ None
+
+--*/
+{
+ NdisWanDbgOut(DBG_TRACE, DBG_MEMORY, ("NdisWanDestroyAdapterCB: Enter"));
+ NdisWanDbgOut(DBG_TRACE, DBG_MEMORY, ("AdapterCB: 0x%x", pAdapterCB));
+
+#ifdef MINIPORT_NAME
+ NdisWanFreeNdisString(&pAdapterCB->AdapterName);
+#endif
+
+ NdisFreeSpinLock(&pAdapterCB->Lock);
+
+ NdisWanFreeMemory(pAdapterCB);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_MEMORY, ("NdisWanDestroyAdapterCB: Exit"));
+}
+
+NDIS_STATUS
+NdisWanCreateWanAdapterCB(
+ IN PWSTR BindName
+ )
+/*++
+
+Routine Name:
+
+ NdisWanCreateWanAdapterCB
+
+Routine Description:
+
+ This routine creates and initializes a WanAdapterCB
+
+Arguments:
+
+ BindName - Pointer to an NDIS_STRING that has the name of the WAN Miniport
+ that will be used in the NdisOpenAdapter call when we bind to
+ the WAN Miniport.
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_RESOURCES
+
+--*/
+{
+ PWAN_ADAPTERCB pWanAdapterCB;
+ ULONG ulAllocationSize;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_MEMORY, ("NdisWanCreateWanAdapterCB: Enter"));
+ NdisWanDbgOut(DBG_TRACE, DBG_MEMORY, ("BindName: %ls", BindName));
+
+ //
+ // Allocate memory for WanAdapterCB
+ //
+ ulAllocationSize = sizeof(WAN_ADAPTERCB);
+
+ NdisWanAllocateMemory(&pWanAdapterCB, ulAllocationSize);
+
+ if (pWanAdapterCB == NULL) {
+
+ return (NDIS_STATUS_RESOURCES);
+ }
+
+ //
+ // Init WanAdapterCB
+ //
+
+ //
+ // Setup new control block
+ //
+ pWanAdapterCB->ulAllocationSize = ulAllocationSize;
+
+ NdisWanStringToNdisString(&(pWanAdapterCB->MiniportName), BindName);
+
+ NdisAllocateSpinLock(&pWanAdapterCB->Lock);
+ InitializeListHead(&pWanAdapterCB->FreeLinkCBList);
+
+#if DBG
+ InitializeListHead(&pWanAdapterCB->DbgWanPacketList);
+#endif
+
+ //
+ // Put WanAdapterCB on global list
+ //
+ InsertTailGlobalList(WanAdapterCBList, &(pWanAdapterCB->Linkage));
+
+ NdisWanDbgOut(DBG_TRACE, DBG_MEMORY, ("WanMiniport %ls WanAdapterCB: 0x%x",
+ pWanAdapterCB->MiniportName.Buffer, pWanAdapterCB));
+ NdisWanDbgOut(DBG_TRACE, DBG_MEMORY, ("NdisWanCreateWanAdapterCB: Exit"));
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+VOID
+NdisWanDestroyWanAdapterCB(
+ IN PWAN_ADAPTERCB pWanAdapterCB
+ )
+/*++
+
+Routine Name:
+
+ NdisWanDestroyWanAdapterCB
+
+Routine Description:
+
+ This routine destroys a WanAdapterCB
+
+Arguments:
+
+ pWanAdapterCB - Pointer to the WanAdapterCB that is being destroyed
+
+Return Values:
+
+ None
+
+--*/
+{
+ NdisWanDbgOut(DBG_TRACE, DBG_MEMORY, ("NdisWanDestroyWanAdapterCB: Enter - WanAdapterCB: 0x%4.4x", pWanAdapterCB));
+
+ //
+ // Free the memory allocated for the NDIS_STRING
+ //
+ NdisWanFreeNdisString(&pWanAdapterCB->MiniportName);
+
+ NdisFreeSpinLock(&pWanAdapter->Lock);
+
+ //
+ // Free the memory allocated for the control block
+ //
+ NdisWanFreeMemory(pWanAdapterCB);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_MEMORY, ("NdisWanDestroyWanAdapterCB: Exit"));
+}
+
+VOID
+NdisWanGetProtocolCB(
+ OUT PPROTOCOLCB *ProtocolCB,
+ IN USHORT usProtocolType,
+ IN USHORT usBindingNameLength,
+ IN PWSTR BindingName,
+ IN ULONG ulBufferLength,
+ IN PUCHAR Buffer
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ *ProtocolCB = NULL;
+
+// NdisAcquireSpinLock(&(FreeProtocolCBList.Lock));
+
+ //
+ // See if there are any ProtocolCB's available on the free list.
+ // If there are not we will need to allocate one.
+ //
+// if (FreeProtocolCBList.ulCount == 0) {
+
+ //
+ // Create ProtocolCB
+ //
+ NdisWanCreateProtocolCB(ProtocolCB,
+ usProtocolType,
+ usBindingNameLength,
+ BindingName,
+ ulBufferLength,
+ Buffer);
+
+// } else {
+
+ //
+ // Get the ProtocolCB from the free list
+ //
+// *ProtocolCB = (PPROTOCOLCB)RemoveHeadList(&(FreeProtocolCBList.List));
+
+// FreeProtocolCBList.ulCount--;
+
+// }
+
+// NdisReleaseSpinLock(&(FreeProtocolCBList.Lock));
+
+// if (*ProtocolCB != NULL) {
+// NdisWanInitProtocolCB(*ProtocolCB,
+// ulBufferLength,
+// Buffer,
+// usProtocolType);
+// }
+
+}
+
+NDIS_STATUS
+NdisWanCreateProtocolCB(
+ OUT PPROTOCOLCB *ProtocolCB,
+ IN USHORT usProtocolType,
+ IN USHORT usBindingNameLength,
+ IN PWSTR BindingName,
+ IN ULONG ulBufferLength,
+ IN PUCHAR Buffer
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS - ProtocolCB was allocated and initialized
+ NDIS_STATUS_RESOURCES - Error allocating memory for ProtocolCB
+
+--*/
+{
+ PPROTOCOLCB LocalProtocolCB = NULL;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ ULONG ulAllocationSize = sizeof(PROTOCOLCB) + ulBufferLength;
+ PUCHAR AllocatedMemory;
+ ULONG i;
+
+ NdisWanAllocateMemory(&AllocatedMemory, ulAllocationSize);
+
+ if (AllocatedMemory != NULL) {
+
+ LocalProtocolCB = (PPROTOCOLCB)AllocatedMemory;
+ LocalProtocolCB->ulAllocationSize = ulAllocationSize;
+ AllocatedMemory += sizeof(PROTOCOLCB);
+ LocalProtocolCB->LineUpInfo = AllocatedMemory;
+
+#ifdef BANDWIDTH_ON_DEMAND
+ //
+ // Initialize the sample table
+ //
+ LocalProtocolCB->SampleTable.ulSampleArraySize = SAMPLE_ARRAY_SIZE;
+ NdisWanInitWanTime(&LocalProtocolCB->SampleTable.SampleRate, ONE_HUNDRED_MILS);
+ NdisWanInitWanTime(&LocalProtocolCB->SampleTable.SamplePeriod, ONE_SECOND);
+#endif
+
+ //
+ // Copy the bindingname
+ //
+ NdisWanStringToNdisString(&LocalProtocolCB->BindingName, BindingName);
+
+ //
+ // Copy over the protocol info
+ //
+ LocalProtocolCB->ulLineUpInfoLength = ulBufferLength;
+ NdisMoveMemory(LocalProtocolCB->LineUpInfo,
+ Buffer,
+ ulBufferLength);
+
+ //
+ // Setup the protocol type
+ //
+ LocalProtocolCB->usProtocolType = usProtocolType;
+
+ //
+ // Get the PPP protocol value for this protocol type
+ //
+ LocalProtocolCB->usPPPProtocolID = GetPPP_ProtocolID(usProtocolType, PROTOCOL_TYPE);
+
+ switch (usProtocolType) {
+ case PROTOCOL_IP:
+ LocalProtocolCB->NonIdleDetectFunc = IpIsDataFrame;
+ break;
+ case PROTOCOL_IPX:
+ LocalProtocolCB->NonIdleDetectFunc = IpxIsDataFrame;
+ break;
+ case PROTOCOL_NBF:
+ LocalProtocolCB->NonIdleDetectFunc = NbfIsDataFrame;
+ break;
+ default:
+ LocalProtocolCB->NonIdleDetectFunc = NULL;
+ break;
+ }
+
+ NdisWanGetSystemTime(&LocalProtocolCB->LastRecvNonIdleData);
+
+#ifdef BANDWIDTH_ON_DEMAND
+
+ LocalProtocolCB->SampleTable.ulFirstIndex =
+ LocalProtocolCB->SampleTable.ulCurrentIndex = 0;
+ NdisZeroMemory(&LocalProtocolCB->SampleTable.SampleArray[0],
+ sizeof(SEND_SAMPLE) * SAMPLE_ARRAY_SIZE);
+
+#endif // end BANDWIDTH_ON_DEMAND
+
+ } else {
+
+ Status = NDIS_STATUS_RESOURCES;
+ NdisWanDbgOut(DBG_CRITICAL_ERROR, DBG_MEMORY, ("Error allocating memory for ProtocolCB, ulAllocationSize: %d",
+ ulAllocationSize));
+ }
+
+ *ProtocolCB = LocalProtocolCB;
+
+ return (Status);
+}
+
+//VOID
+//NdisWanInitProtocolCB(
+// IN PPROTOCOLCB ProtocolCB,
+// IN ULONG ulBufferLength,
+// IN PUCHAR Buffer,
+// IN USHORT usProtocolType
+// )
+///*++
+//
+//Routine Name:
+//
+//Routine Description:
+//
+//Arguments:
+//
+//Return Values:
+//
+//--*/
+//{
+// //
+// // Copy over the protocol info
+// //
+// ProtocolCB->ulLineUpInfoLength = ulBufferLength;
+// NdisMoveMemory(ProtocolCB->LineUpInfo,
+// Buffer,
+// ulBufferLength);
+//
+// //
+// // Setup the protocol type
+// //
+// ProtocolCB->usProtocolType = usProtocolType;
+//
+// //
+// // Get the PPP protocol value for this protocol type
+// //
+// ProtocolCB->usPPPProtocolID = GetPPP_ProtocolID(usProtocolType, PROTOCOL_TYPE);
+//
+// ProtocolCB->SampleTable.ulFirstIndex =
+// ProtocolCB->SampleTable.ulCurrentIndex = 0;
+// NdisZeroMemory(&ProtocolCB->SampleTable.SampleArray[0],
+// sizeof(SEND_SAMPLE) * SAMPLE_ARRAY_SIZE);
+//
+//}
+
+VOID
+NdisWanReturnProtocolCB(
+ IN PPROTOCOLCB ProtocolCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+// NdisAcquireSpinLock(&(FreeProtocolCBList.Lock));
+//
+// if (FreeProtocolCBList.ulCount > FreeProtocolCBList.ulMaxCount) {
+
+ NdisWanDestroyProtocolCB(ProtocolCB);
+
+// } else {
+//
+// InsertTailGlobalList(FreeProtocolCBList, &(ProtocolCB->Linkage));
+//
+// FreeProtocolCBList.ulCount++;
+//
+// }
+//
+// NdisReleaseSpinLock(&(FreeProtocolCBList.Lock));
+}
+
+VOID
+NdisWanDestroyProtocolCB(
+ IN PPROTOCOLCB ProtocolCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ ASSERT(ProtocolCB->HeadNdisPacketQueue == NULL);
+ ASSERT(ProtocolCB->TailNdisPacketQueue == NULL);
+
+ if (ProtocolCB->DeviceName.Length != 0) {
+ NdisWanFreeNdisString(&ProtocolCB->DeviceName);
+ }
+
+ if (ProtocolCB->BindingName.Length != 0) {
+ NdisWanFreeNdisString(&ProtocolCB->BindingName);
+ }
+
+ NdisWanFreeMemory(ProtocolCB);
+}
+
+VOID
+NdisWanGetLinkCB(
+ OUT PLINKCB *LinkCB,
+ IN PWAN_ADAPTERCB WanAdapterCB,
+ IN ULONG SendWindow
+ )
+/*++
+
+Routine Name:
+
+ NdisWanGetLinkCB
+
+Routine Description:
+
+ This function returns a pointer to a LinkCB. The LinkCB is either retrieved
+ from the WanAdapters free list or, if this list is empty, it is allocated.
+
+Arguments:
+
+ *LinkCB - Pointer to the location to store the pointer to the LinkCB
+
+ WanAdapterCB - Pointer to the WanAdapter control block that this Link is
+ associated with
+
+Return Values:
+
+ None
+
+--*/
+{
+ //
+ // See if we have any free LinkCB's hanging around
+ // if not we will allocate one
+ //
+ NdisAcquireSpinLock(&(WanAdapterCB->Lock));
+
+ if (IsListEmpty(&(WanAdapterCB->FreeLinkCBList))) {
+
+ //
+ // Create LinkCB
+ //
+ NdisWanCreateLinkCB(LinkCB);
+
+ } else {
+
+ //
+ // Get the LinkCB from the free list
+ //
+ *LinkCB = (PLINKCB)RemoveHeadList(&(WanAdapterCB->FreeLinkCBList));
+ }
+
+ NdisReleaseSpinLock(&(WanAdapterCB->Lock));
+
+ //
+ // Set the new link state
+ //
+ NdisWanInitLinkCB(LinkCB, WanAdapterCB, SendWindow);
+}
+
+NDIS_STATUS
+NdisWanCreateLinkCB(
+ OUT PLINKCB *LinkCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PLINKCB LocalLinkCB = NULL;
+ ULONG ulAllocationSize, n;
+ PUCHAR AllocatedMemory = NULL;
+
+ //
+ // Figure out how much we need to allocate
+ //
+ ulAllocationSize = sizeof(LINKCB);
+
+ //
+ // Allocate the memory for the LinkCB and it's WAN PACKETS
+ //
+ NdisWanAllocateMemory(&AllocatedMemory, ulAllocationSize);
+
+
+ if (AllocatedMemory != NULL) {
+
+ //
+ // Initialize the control block
+ //
+ LocalLinkCB = (PLINKCB)AllocatedMemory;
+ LocalLinkCB->ulAllocationSize = ulAllocationSize;
+
+ InitializeListHead(&LocalLinkCB->WanPacketPool);
+ NdisWanInitializeSyncEvent(&LocalLinkCB->OutstandingFramesEvent);
+
+ } else {
+ Status = NDIS_STATUS_RESOURCES;
+
+ NdisWanDbgOut(DBG_CRITICAL_ERROR, DBG_MEMORY, ("Error allocating memory for LinkCB, AllocationSize: %d",
+ ulAllocationSize));
+ }
+
+ *LinkCB = LocalLinkCB;
+
+ return (Status);
+}
+
+VOID
+NdisWanInitLinkCB(
+ IN PLINKCB *LinkCB,
+ IN PWAN_ADAPTERCB WanAdapterCB,
+ IN ULONG SendWindow
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PLINKCB LocalLinkCB = *LinkCB;
+
+ if (LocalLinkCB == NULL) {
+ return;
+ }
+
+ LocalLinkCB->hLinkContext = NULL;
+ LocalLinkCB->ulReferenceCount = 0;
+ LocalLinkCB->State = LINK_UP;
+ LocalLinkCB->WanAdapterCB = WanAdapterCB;
+ LocalLinkCB->OutstandingFrames = 0;
+ LocalLinkCB->LastRecvSeqNumber = 0;
+ LocalLinkCB->ulBandwidth = 100;
+ LocalLinkCB->PacketMemory = NULL;
+ LocalLinkCB->PacketMemorySize = 0;
+ LocalLinkCB->RecvFragmentsLost = 0;
+
+ NdisZeroMemory(&LocalLinkCB->LinkInfo, sizeof(WAN_LINK_INFO));
+
+ LocalLinkCB->LinkInfo.HeaderPadding = WanAdapterCB->WanInfo.HeaderPadding;
+ LocalLinkCB->LinkInfo.TailPadding = WanAdapterCB->WanInfo.TailPadding;
+ LocalLinkCB->LinkInfo.SendACCM =
+ LocalLinkCB->LinkInfo.RecvACCM = WanAdapterCB->WanInfo.DesiredACCM;
+
+ NdisZeroMemory(&LocalLinkCB->LinkStats, sizeof(WAN_STATS));
+
+ if (NdisWanAllocateSendResources(LocalLinkCB, SendWindow) != NDIS_STATUS_SUCCESS) {
+ //
+ // return the linkcb
+ //
+ NdisWanReturnLinkCB(LocalLinkCB);
+ *LinkCB = NULL;
+ }
+}
+
+VOID
+NdisWanReturnLinkCB(
+ PLINKCB LinkCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PWAN_ADAPTERCB WanAdapterCB = LinkCB->WanAdapterCB;
+
+ NdisAcquireSpinLock(&(WanAdapterCB->Lock));
+
+ //
+ // Free the wanpacket pool
+ //
+ NdisWanFreeSendResources(LinkCB);
+
+ InsertTailList(&WanAdapterCB->FreeLinkCBList, &LinkCB->Linkage);
+
+ NdisReleaseSpinLock(&(WanAdapterCB->Lock));
+}
+
+VOID
+NdisWanDestroyLinkCB(
+ IN PLINKCB LinkCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PWAN_ADAPTERCB WanAdapterCB = LinkCB->WanAdapterCB;
+
+ //
+ // Free the memory allocated for the control block
+ //
+ NdisWanFreeMemory(LinkCB);
+}
+
+NDIS_STATUS
+NdisWanAllocateSendResources(
+ IN PLINKCB LinkCB,
+ IN ULONG SendWindow
+ )
+/*++
+
+Routine Name:
+
+ NdisWanAllocateSendResources
+
+Routine Description:
+
+ Allocates all resources (SendDescriptors, WanPackets, ...)
+ required for sending data. Should be called at line up time.
+
+Arguments:
+
+ LinkCB - Pointer to the linkcb that the send resources will be attached to.
+ SendWindow - Maximum number of sends that this link can handle
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_RESOURCES
+
+--*/
+{
+ PWAN_ADAPTERCB WanAdapterCB = LinkCB->WanAdapterCB;
+ ULONG BufferSize, PacketMemorySize, NumberOfPackets, n;
+ PUCHAR PacketMemory = NULL;
+ PNDIS_WAN_PACKET WanPacket;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ SendWindow = (SendWindow == 0) ?
+ WanAdapterCB->WanInfo.MaxTransmit : SendWindow;
+
+ SendWindow = (SendWindow == 0) ? 1 : SendWindow;
+
+ //
+ // The number of packets that we will create is the send
+ // window of this WAN Miniport + 1
+ //
+ NumberOfPackets = SendWindow + 1;
+
+ //
+ // The size of the buffer that we create is
+ //
+ BufferSize = WanAdapterCB->WanInfo.MaxFrameSize +
+ WanAdapterCB->WanInfo.HeaderPadding +
+ WanAdapterCB->WanInfo.TailPadding +
+ 40 + sizeof(PVOID);
+
+ //
+ // We assume compression is always on so we pad out 12%
+ // incase the compressor expands. I don't know where the
+ // 12% figure comes from.
+ //
+ BufferSize += (WanAdapterCB->WanInfo.MaxFrameSize + 7) / 8;
+
+ //
+ // Make sure that the buffer is dword aligned.
+ //
+ BufferSize &= ~(sizeof(PVOID) - 1);
+
+ PacketMemorySize = (BufferSize + sizeof(NDIS_WAN_PACKET)) * NumberOfPackets;
+
+ //
+ // Allocate the memory for the wan packet buffer pool
+ //
+ NdisAllocateMemory(&PacketMemory,
+ PacketMemorySize,
+ WanAdapterCB->WanInfo.MemoryFlags,
+ WanAdapterCB->WanInfo.HighestAcceptableAddress);
+
+ if (PacketMemory != NULL) {
+
+ LinkCB->PacketMemory = PacketMemory;
+ LinkCB->PacketMemorySize = PacketMemorySize;
+ LinkCB->BufferSize = BufferSize;
+
+ for (n = 0; n < NumberOfPackets; n++) {
+
+ WanPacket = (PNDIS_WAN_PACKET)PacketMemory;
+ PacketMemory += sizeof(NDIS_WAN_PACKET);
+
+ InsertTailList(&LinkCB->WanPacketPool, &WanPacket->WanPacketQueue);
+ LinkCB->ulWanPacketCount++;
+ }
+
+ //
+ // Walk the list of newly created packets and fix up startbuffer and
+ // endbuffer pointers.
+ //
+ for (WanPacket = (PNDIS_WAN_PACKET)LinkCB->WanPacketPool.Flink;
+ (PVOID)WanPacket != (PVOID)&LinkCB->WanPacketPool;
+ WanPacket = (PNDIS_WAN_PACKET)WanPacket->WanPacketQueue.Flink) {
+
+ //
+ // Point to the begining of the data.
+ //
+ WanPacket->StartBuffer = PacketMemory;
+ PacketMemory += BufferSize;
+
+ //
+ // The 5 bytes give us a short buffer at the end and will
+ // keep a WAN Miniport from alignment checking if it uses
+ // this pointer to 'back copy'
+ //
+ WanPacket->EndBuffer = PacketMemory - 5;
+ }
+
+ } else {
+ Status = NDIS_STATUS_RESOURCES;
+
+ NdisWanDbgOut(DBG_CRITICAL_ERROR, DBG_MEMORY, ("Error allocating memory for BufferPool, AllocationSize: %d",
+ PacketMemorySize));
+ }
+
+ return (Status);
+}
+
+VOID
+NdisWanFreeSendResources(
+ IN PLINKCB LinkCB
+ )
+/*++
+
+Routine Name:
+
+ NdisWanFreeSendResources
+
+Routine Description:
+
+ This routine removes the WanPackets from this linkcb's send list
+ and free's the memory allocated for these packets. Should be called
+ at linedown time after all outstanding sends have been accounted for.
+
+Arguments:
+
+ LinkCB - Pointer to the linkcb that the resources are being freed from.
+
+Return Values:
+
+ None
+
+--*/
+{
+ PNDIS_WAN_PACKET WanPacket;
+ PUCHAR PacketMemory;
+ ULONG PacketMemorySize, Flags;
+
+ PacketMemory = LinkCB->PacketMemory;
+ PacketMemorySize = LinkCB->PacketMemorySize;
+ Flags = LinkCB->WanAdapterCB->WanInfo.MemoryFlags;
+
+ //
+ // Remove the packets from the wan packet pool
+ //
+ while (!IsListEmpty(&LinkCB->WanPacketPool)) {
+ RemoveHeadList(&LinkCB->WanPacketPool);
+ LinkCB->ulWanPacketCount--;
+ }
+
+ //
+ // Free the block of memory allocated for this send
+ //
+ if (PacketMemory != NULL) {
+ NdisFreeMemory(PacketMemory, PacketMemorySize, Flags);
+ }
+}
+
+VOID
+NdisWanGetBundleCB(
+ OUT PBUNDLECB *BundleCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NdisAcquireSpinLock(&(FreeBundleCBList.Lock));
+
+ //
+ // See if there are any BundleCB's available on the free list.
+ // If there are not we will need to allocate one.
+ //
+ if (FreeBundleCBList.ulCount == 0) {
+
+ //
+ // Create BundleCB
+ //
+ NdisWanCreateBundleCB(BundleCB);
+
+ } else {
+
+ //
+ // Get the BundleCB from the free list
+ //
+ *BundleCB = (PBUNDLECB)RemoveHeadList(&(FreeBundleCBList.List));
+
+ FreeBundleCBList.ulCount--;
+
+ }
+
+ NdisReleaseSpinLock(&(FreeBundleCBList.Lock));
+
+ if (*BundleCB != NULL) {
+ NdisWanInitBundleCB(*BundleCB);
+ }
+}
+
+NDIS_STATUS
+NdisWanCreateBundleCB(
+ OUT PBUNDLECB *BundleCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PBUNDLECB LocalBundleCB = NULL;
+ ULONG ulAllocationSize;
+ PUCHAR AllocatedMemory = NULL;
+
+ //
+ // Allocation size is the size of the control block plus the size
+ // of a table of pointers to protocolcb's that might be routed to
+ // this bundle.
+ //
+ ulAllocationSize = sizeof(BUNDLECB) +
+ sizeof(PROTOCOLCB) +
+ (sizeof(PPROTOCOLCB) * MAX_PROTOCOLS);
+
+ NdisWanAllocateMemory(&AllocatedMemory, ulAllocationSize);
+
+ if (AllocatedMemory != NULL) {
+ PWSTR IOName = L"I/O ProtocolCB";
+ PPROTOCOLCB ProtocolCB;
+
+ //
+ // This is the bundlecb
+ //
+ LocalBundleCB = (PBUNDLECB)AllocatedMemory;
+ LocalBundleCB->ulAllocationSize = ulAllocationSize;
+ AllocatedMemory += sizeof(BUNDLECB);
+
+ //
+ // This is the memory used for the I/O protocolcb
+ //
+ ProtocolCB = (PPROTOCOLCB)AllocatedMemory;
+ AllocatedMemory += sizeof(PROTOCOLCB);
+
+ //
+ // This is the protocolcb table
+ //
+ (PUCHAR)LocalBundleCB->ProtocolCBTable = (PUCHAR)AllocatedMemory;
+
+ //
+ // Initialize the BundleCB
+ //
+
+ NdisAllocateSpinLock(&LocalBundleCB->Lock);
+ InitializeListHead(&LocalBundleCB->LinkCBList);
+ InitializeListHead(&LocalBundleCB->SendPacketQueue);
+ InitializeListHead(&LocalBundleCB->RecvDescPool);
+ InitializeListHead(&LocalBundleCB->RecvDescAssemblyList);
+ InitializeListHead(&LocalBundleCB->ProtocolCBList);
+ NdisWanInitializeSyncEvent(&LocalBundleCB->OutstandingFramesEvent);
+ NdisWanInitializeSyncEvent(&LocalBundleCB->IndicationEvent);
+
+#ifdef BANDWIDTH_ON_DEMAND
+ LocalBundleCB->UpperBonDInfo.SampleTable.ulSampleArraySize = SAMPLE_ARRAY_SIZE;
+ LocalBundleCB->LowerBonDInfo.SampleTable.ulSampleArraySize = SAMPLE_ARRAY_SIZE;
+#endif // end of BANDWIDTH_ON_DEMAND
+
+ //
+ // Add the protocolcb to the bundle's table and list
+ //
+ ProtocolCB->hProtocolHandle = 0;
+ ProtocolCB->BundleCB = LocalBundleCB;
+ ProtocolCB->HeadNdisPacketQueue =
+ ProtocolCB->TailNdisPacketQueue = NULL;
+ NdisWanStringToNdisString(&ProtocolCB->DeviceName, IOName);
+
+#ifdef BANDWIDTH_ON_DEMAND
+ ProtocolCB->SampleTable.ulSampleArraySize = SAMPLE_ARRAY_SIZE;
+ NdisWanInitWanTime(&ProtocolCB->SampleTable.SampleRate, ONE_HUNDRED_MILS);
+ NdisWanInitWanTime(&ProtocolCB->SampleTable.SamplePeriod, ONE_SECOND);
+#endif
+
+ LocalBundleCB->ProtocolCBTable[0] = ProtocolCB;
+ InsertHeadList(&LocalBundleCB->ProtocolCBList, &ProtocolCB->Linkage);
+ LocalBundleCB->ulNumberOfRoutes = 1;
+
+ } else {
+
+ Status = NDIS_STATUS_RESOURCES;
+ NdisWanDbgOut(DBG_CRITICAL_ERROR, DBG_MEMORY, ("Error allocating memory for BundleCB, AllocationSize: %d",
+ ulAllocationSize));
+ }
+
+ *BundleCB = LocalBundleCB;
+
+ return (Status);
+}
+
+VOID
+NdisWanInitBundleCB(
+ PBUNDLECB BundleCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PPROTOCOLCB ProtocolCB = BundleCB->ProtocolCBTable[0];
+ PRECV_DESC RecvDescHole;
+
+#ifdef BANDWIDTH_ON_DEMAND
+ PSAMPLE_TABLE SampleTable;
+ PBOND_INFO BonDInfo;
+#endif // end of BANDWIDTH_ON_DEMAND
+
+ BundleCB->State = BUNDLE_UP;
+ NdisZeroMemory(&BundleCB->FramingInfo, sizeof(BUNDLE_FRAME_INFO));
+ BundleCB->NextLinkToXmit = NULL;
+ BundleCB->SendingLinks = 0;
+ BundleCB->SendSeqNumber = 0;
+ BundleCB->SendSeqMask = 0;
+ BundleCB->SendSeqTest = 0;
+ BundleCB->Flags = 0;
+ NdisZeroMemory(&BundleCB->LineUpInfo, sizeof(BUNDLE_LINE_UP));
+ BundleCB->LineUpInfo.ulMaximumTotalSize = MAX_TOTAL_SIZE;
+
+ //
+ // Init the recv hole desc
+ //
+ BundleCB->RecvSeqMask = 0;
+ BundleCB->RecvSeqTest = 0;
+ BundleCB->RecvFragmentsLost = 0;
+ BundleCB->MinReceivedSeqNumber = 0;
+ ASSERT(BundleCB->RecvDescAssemblyList.Flink == BundleCB->RecvDescAssemblyList.Blink);
+ NdisWanGetRecvDesc(BundleCB, &RecvDescHole);
+ RecvDescHole->SequenceNumber = 0;
+ RecvDescHole->Flags = 1;
+ BundleCB->RecvDescHole = RecvDescHole;
+ InsertHeadList(&BundleCB->RecvDescAssemblyList, &RecvDescHole->Linkage);
+ NdisWanGetSystemTime(&BundleCB->LastRecvNonIdleData);
+
+ ProtocolCB->SendMaskBit = IO_SEND_MASK_BIT;
+
+ NdisZeroMemory(&BundleCB->SendVJInfo, sizeof(VJ_INFO));
+ NdisZeroMemory(&BundleCB->RecvVJInfo, sizeof(VJ_INFO));
+ NdisZeroMemory(&BundleCB->SendCompInfo, sizeof(COMPRESS_INFO));
+ NdisZeroMemory(&BundleCB->RecvCompInfo, sizeof(COMPRESS_INFO));
+ NdisZeroMemory(&BundleCB->SendEncryptInfo,sizeof(ENCRYPTION_INFO));
+ NdisZeroMemory(&BundleCB->RecvEncryptInfo,sizeof(ENCRYPTION_INFO));
+
+/*
+#ifdef ENCRYPT_128BIT
+ BundleCB->SendEncryptInfo.SessionKeyLength =
+ BundleCB->RecvEncryptInfo.SessionKeyLength = 16;
+ BundleCB->SendCompInfo.MSCompType =
+ BundleCB->RecvCompInfo.MSCompType = NDISWAN_ENCRYPTION |
+ NDISWAN_40_ENCRYPTION |
+ NDISWAN_128_ENCRYPTION |
+ NDISWAN_COMPRESSION;
+#else
+ BundleCB->SendEncryptInfo.SessionKeyLength =
+ BundleCB->RecvEncryptInfo.SessionKeyLength = 8;
+ BundleCB->SendCompInfo.MSCompType =
+ BundleCB->RecvCompInfo.MSCompType = NDISWAN_ENCRYPTION |
+ NDISWAN_40_ENCRYPTION |
+ NDISWAN_COMPRESSION;
+#endif
+*/
+ BundleCB->SendCompInfo.CompType =
+ BundleCB->RecvCompInfo.CompType = COMPTYPE_NONE;
+
+ ProtocolCB->usProtocolType = PROTOCOL_PRIVATE_IO;
+ ProtocolCB->usPPPProtocolID = PPP_PROTOCOL_PRIVATE_IO;
+
+ BundleCB->SendMask = IO_SEND_MASK_BIT;
+
+#ifdef BANDWIDTH_ON_DEMAND
+
+ ProtocolCB->usPriority = 100;
+ ProtocolCB->ulByteQuota = 0xFFFFFFFF;
+ ProtocolCB->SampleTable.ulFirstIndex =
+ ProtocolCB->SampleTable.ulCurrentIndex = 0;
+ NdisZeroMemory(&ProtocolCB->SampleTable.SampleArray[0],
+ sizeof(SEND_SAMPLE) * SAMPLE_ARRAY_SIZE);
+
+
+ BonDInfo = &BundleCB->UpperBonDInfo;
+ BonDInfo->ulBytesThreshold = 0;
+ BonDInfo->State = BonDIdle;
+ BonDInfo->usPercentBandwidth = 0xFFFF;
+ BonDInfo->ulSecondsInSamplePeriod = 0;
+ NdisWanInitWanTime(&BonDInfo->StartTime, 0);
+
+ SampleTable = &BonDInfo->SampleTable;
+ NdisWanInitWanTime(&SampleTable->SampleRate, 0);
+ NdisWanInitWanTime(&SampleTable->SamplePeriod, 0);
+ SampleTable->ulFirstIndex =
+ SampleTable->ulCurrentIndex =
+ SampleTable->ulCurrentSampleByteCount = 0;
+
+ NdisZeroMemory(&SampleTable->SampleArray[0],
+ sizeof(SEND_SAMPLE) * SAMPLE_ARRAY_SIZE);
+
+ BonDInfo = &BundleCB->LowerBonDInfo;
+ BonDInfo->ulBytesThreshold = 0;
+ BonDInfo->State = BonDIdle;
+ BonDInfo->usPercentBandwidth = 0xFFFF;
+ BonDInfo->ulSecondsInSamplePeriod = 0;
+ NdisWanInitWanTime(&BonDInfo->StartTime, 0);
+ SampleTable = &BonDInfo->SampleTable;
+ NdisWanInitWanTime(&SampleTable->SampleRate, 0);
+ NdisWanInitWanTime(&SampleTable->SamplePeriod, 0);
+ SampleTable->ulFirstIndex =
+ SampleTable->ulCurrentIndex =
+ SampleTable->ulCurrentSampleByteCount = 0;
+
+ NdisZeroMemory(&SampleTable->SampleArray[0],
+ sizeof(SEND_SAMPLE) * SAMPLE_ARRAY_SIZE);
+
+#endif // end of BANDWIDTH_ON_DEMAND
+
+ BundleCB->ulNameLength = 0;
+ NdisZeroMemory(&BundleCB->Name, MAX_NAME_LENGTH);
+
+ NdisZeroMemory(&BundleCB->BundleStats, sizeof(WAN_STATS));
+}
+
+VOID
+NdisWanReturnBundleCB(
+ IN PBUNDLECB BundleCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+
+ sl_compress_terminate(&BundleCB->VJCompress);
+
+ WanDeallocateCCP(BundleCB);
+
+ FlushRecvDescAssemblyList(BundleCB);
+
+ FreeRecvDescFreeList(BundleCB);
+
+ NdisAcquireSpinLock(&(FreeBundleCBList.Lock));
+
+ if (FreeBundleCBList.ulCount >= FreeBundleCBList.ulMaxCount) {
+
+ NdisWanDestroyBundleCB(BundleCB);
+
+ } else {
+ InsertTailList(&FreeBundleCBList.List, &(BundleCB->Linkage));
+
+ FreeBundleCBList.ulCount++;
+ }
+
+ NdisReleaseSpinLock(&(FreeBundleCBList.Lock));
+}
+
+VOID
+NdisWanDestroyBundleCB(
+ IN PBUNDLECB BundleCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PPROTOCOLCB ProtocolCB = BundleCB->ProtocolCBTable[0];
+
+ NdisFreeSpinLock(&BundleCB->Lock);
+
+ NdisWanFreeNdisString(&ProtocolCB->DeviceName);
+
+ NdisWanFreeMemory(BundleCB);
+}
+
+
+NDIS_STATUS
+NdisWanCreatePPPProtocolTable(
+ VOID
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ ULONG ulAllocationSize = 0;
+ PUCHAR AllocatedMemory;
+
+
+ //
+ // Allocate ProtocolLookupTable. This table is used to match protocol values
+ // with their corresponding PPP Protocol values. The table size is set to
+ // MAX_PROTOCOLS.
+ //
+ ulAllocationSize = sizeof(PPP_PROTOCOL_TABLE) +
+ (sizeof(USHORT) * MAX_PROTOCOLS) +
+ (sizeof(USHORT) * MAX_PROTOCOLS);
+
+ NdisWanAllocateMemory(&AllocatedMemory, ulAllocationSize);
+
+ if (AllocatedMemory == NULL) {
+ NdisWanDbgOut(DBG_CRITICAL_ERROR, DBG_MEMORY,
+ ("Failed allocating memory for ProtocolLookupTable! TableSize: %d",
+ ulAllocationSize));
+
+ return (NDIS_STATUS_RESOURCES);
+ }
+
+ PPP_ProtocolTable = (PPPP_PROTOCOL_TABLE)AllocatedMemory;
+
+ //
+ // Save the allocation size
+ //
+ PPP_ProtocolTable->ulAllocationSize = ulAllocationSize;
+
+ //
+ // Store the array size. This should be read from the registry
+ //
+ PPP_ProtocolTable->ulArraySize = MAX_PROTOCOLS;
+
+ NdisAllocateSpinLock(&PPP_ProtocolTable->Lock);
+
+ //
+ // Setup the pointer to the ProtocolValue array
+ //
+ AllocatedMemory += sizeof(PPP_PROTOCOL_TABLE);
+ PPP_ProtocolTable->ProtocolID = (PUSHORT)(AllocatedMemory);
+
+ //
+ // Setup the pointer to the PPPProtocolValue array
+ //
+ AllocatedMemory += (sizeof(USHORT) * MAX_PROTOCOLS);
+ PPP_ProtocolTable->PPPProtocolID = (PUSHORT)(AllocatedMemory);
+
+ //
+ // Insert default values for Netbuei, IP, IPX
+ //
+ InsertPPP_ProtocolID(PROTOCOL_PRIVATE_IO, PROTOCOL_TYPE);
+ InsertPPP_ProtocolID(PPP_PROTOCOL_PRIVATE_IO, PPP_TYPE);
+
+ InsertPPP_ProtocolID(PROTOCOL_IP, PROTOCOL_TYPE);
+ InsertPPP_ProtocolID(PPP_PROTOCOL_IP, PPP_TYPE);
+
+ InsertPPP_ProtocolID(PROTOCOL_IPX, PROTOCOL_TYPE);
+ InsertPPP_ProtocolID(PPP_PROTOCOL_IPX, PPP_TYPE);
+
+ InsertPPP_ProtocolID(PROTOCOL_NBF, PROTOCOL_TYPE);
+ InsertPPP_ProtocolID(PPP_PROTOCOL_NBF, PPP_TYPE);
+
+ return (Status);
+
+}
+
+VOID
+NdisWanDestroyPPPProtocolTable(
+ VOID
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NdisFreeSpinLock(&PPP_ProtocolTable->Lock);
+
+ NdisWanFreeMemory(PPP_ProtocolTable);
+}
+
+NDIS_STATUS
+NdisWanCreateConnectionTable(
+ ULONG TableSize
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ ULONG ulAllocationSize = 0;
+ PUCHAR AllocatedMemory;
+ PCONNECTION_TABLE NewTable;
+
+ //
+ // Since we skip the first place in the tables we increase the
+ // size by one.
+ //
+ TableSize += 1;
+
+ //
+ // Allocate the Bundle and Link Arrays based on the number of possible connections
+ // that we have in the system. This should be grown if we get called
+ // to reinitialize and gain new ports.
+ //
+ ulAllocationSize = sizeof(CONNECTION_TABLE) +
+ (sizeof(PBUNDLECB) * TableSize) +
+ (sizeof(PLINKCB) * TableSize);
+
+ NdisWanAllocateMemory(&AllocatedMemory, ulAllocationSize);
+
+ if (AllocatedMemory == NULL) {
+
+ NdisWanDbgOut(DBG_CRITICAL_ERROR, DBG_MEMORY,
+ ("Failed allocating memory for ConnectionTable! Size: %d, Links: %d",
+ ulAllocationSize, TableSize));
+
+ return (NDIS_STATUS_RESOURCES);
+ }
+
+ NewTable = (PCONNECTION_TABLE)AllocatedMemory;
+
+ NdisAllocateSpinLock(&NewTable->Lock);
+
+ //
+ // This is the amount of memory we allocated
+ //
+ NewTable->ulAllocationSize = ulAllocationSize;
+ NewTable->ulArraySize = TableSize;
+ InitializeListHead(&NewTable->BundleList);
+
+ //
+ // Setup pointer to the linkcb array
+ //
+ AllocatedMemory += sizeof(CONNECTION_TABLE);
+ NewTable->LinkArray = (PLINKCB*)(AllocatedMemory);
+
+ //
+ // Setup the pointer to the bundlecb array
+ //
+ AllocatedMemory += (sizeof(PLINKCB) * TableSize);
+ NewTable->BundleArray = (PBUNDLECB*)(AllocatedMemory);
+
+ if (ConnectionTable != NULL) {
+ //
+ // We must be growing the table
+ //
+ NewTable->ulNumActiveLinks = ConnectionTable->ulNumActiveLinks;
+ NewTable->ulNumActiveBundles = ConnectionTable->ulNumActiveBundles;
+
+ NdisMoveMemory((PUCHAR)NewTable->LinkArray,
+ (PUCHAR)ConnectionTable->LinkArray,
+ ConnectionTable->ulArraySize * sizeof(PLINKCB));
+
+ NdisMoveMemory((PUCHAR)NewTable->BundleArray,
+ (PUCHAR)ConnectionTable->BundleArray,
+ ConnectionTable->ulArraySize * sizeof(PBUNDLECB));
+
+ while (!IsListEmpty(&ConnectionTable->BundleList)) {
+ PBUNDLECB BundleCB;
+
+ BundleCB = (PBUNDLECB)RemoveHeadList(&ConnectionTable->BundleList);
+ InsertTailList(&NewTable->BundleList, &BundleCB->Linkage);
+ }
+
+ NdisWanDestroyConnectionTable();
+ }
+
+ ConnectionTable = NewTable;
+
+ return (Status);
+}
+
+VOID
+NdisWanDestroyConnectionTable(
+ VOID
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NdisFreeSpinLock(&ConnectionTable->Lock);
+
+ NdisWanFreeMemory(ConnectionTable);
+}
+
+VOID
+NdisWanGetDeferredDesc(
+ PADAPTERCB AdapterCB,
+ PDEFERRED_DESC *RetDesc
+ )
+{
+ ULONG i;
+
+ if (IsDeferredQueueEmpty(&AdapterCB->FreeDeferredQueue)) {
+ PDEFERRED_DESC DeferredDesc;
+ NdisWanAllocateMemory(&DeferredDesc, sizeof(DEFERRED_DESC) * 20);
+
+ if (DeferredDesc != NULL) {
+ for (i = 0; i < 20; i++) {
+ InsertHeadDeferredQueue(&AdapterCB->FreeDeferredQueue, DeferredDesc);
+ (PUCHAR)DeferredDesc += sizeof(DEFERRED_DESC);
+ }
+ }
+ }
+
+ *RetDesc = RemoveHeadDeferredQueue(&AdapterCB->FreeDeferredQueue);
+
+ ASSERT(*RetDesc != NULL);
+}
diff --git a/private/ntos/ndis/ndiswan/miniport.c b/private/ntos/ndis/ndiswan/miniport.c
new file mode 100644
index 000000000..ed5213a25
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/miniport.c
@@ -0,0 +1,576 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ Miniport.c
+
+Abstract:
+
+ This file contains the procedures that makeup most of the NDIS 3.1
+ Miniport interface.
+
+
+Author:
+
+ Tony Bell (TonyBe) June 06, 1995
+
+Environment:
+
+ Kernel Mode
+
+Revision History:
+
+ TonyBe 06/06/95 Created
+
+--*/
+
+#include "wan.h"
+
+//
+// Local function prototypes
+//
+#ifndef USE_NDIS_MINIPORT_CALLBACK
+VOID
+DeferredTimerFunction(
+ PVOID System1,
+ PADAPTERCB AdapterCB,
+ PVOID System2,
+ PVOID System3
+ );
+#endif // end of !USE_NDIS_MINIPORT_CALLBACK
+
+//
+// End local function prototypes
+//
+
+BOOLEAN
+NdisWanCheckForHang(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+/*++
+
+Routine Name:
+
+ NdisWanCheckForHang
+
+Routine Description:
+
+ This routine checks to see is this adapter needs to be reset, and if it
+ does the return value is set to TRUE. I can't think of any reason that
+ we might use this right now, but I'm sure that there will be.
+
+Arguments:
+
+ MiniportAdapterContext - AdapterContext that is given to the wrapper in
+ NdisMSetAttributes call. Is our AdapterCB.
+
+Return Values:
+
+ TRUE - Reset Adapter
+ FALSE - Don't reset adapter
+
+--*/
+{
+ PADAPTERCB AdapterCB = (PADAPTERCB)MiniportAdapterContext;
+ BOOLEAN Status = FALSE;
+
+ NdisWanInterlockedInc(&AdapterCB->ulReferenceCount);
+
+ //
+ // Does this adapter need to be reset?
+ //
+ if (AdapterCB->Flags & ASK_FOR_RESET) {
+ Status = TRUE;
+ }
+
+ NdisWanInterlockedDec(&AdapterCB->ulReferenceCount);
+ return (Status);
+}
+
+VOID
+NdisWanHalt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+/*++
+
+Routine Name:
+
+ NdisWanHalt
+
+Routine Description:
+
+ This routine free's all resources for the adapter.
+
+Arguments:
+
+ MiniportAdapterContext - AdapterContext that is given to the wrapper in
+ NdisMSetAttributes call. Is our AdapterCB.
+
+Return Values:
+
+ None
+
+--*/
+{
+ PADAPTERCB AdapterCB = (PADAPTERCB)MiniportAdapterContext;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_MINIPORT, ("NdisWanHalt: Enter"));
+ NdisWanDbgOut(DBG_TRACE, DBG_MINIPORT, ("AdapterCB: 0x%x", AdapterCB));
+
+ NdisWanDbgOut(DBG_TRACE, DBG_MINIPORT, ("NdisWanHalt: Exit"));
+}
+
+NDIS_STATUS
+NdisWanInitialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ )
+/*++
+
+Routine Name:
+
+ NdisWanInitialize
+
+Routine Description:
+
+ This routine is called after NdisWan registers itself as a Miniport driver.
+ It is responsible for installing NdisWan as a Miniport driver, creating
+ adapter control blocks for each adapter NdisWan exposes (should only be 1),
+ and initializing all adapter specific variables
+
+
+Arguments:
+
+ OpenErrorStatus - Returns information about the error if this function
+ returns NDIS_STATUS_OPEN_ERROR. Used for TokenRing.
+
+ SelectedMediumIndex - An index into the MediumArray that specifies the
+ medium type of this driver. Should be WAN or 802.3
+
+ MediumArray - An array of medium types supported by the NDIS library
+
+ MediumArraySize - Size of the medium array
+
+ MiniportAdapterHandle - Handle assigned by the NDIS library that defines
+ this miniport driver. Used as handle in subsequent
+ calls to the NDIS library.
+
+ WrapperConfigurationContext - Handle used to read configuration information
+ from the registry
+
+Return Values:
+
+ NDIS_STATUS_ADAPTER_NOT_FOUND
+ NDIS_STATUS_FAILURE
+ NDIS_STATUS_NOT_ACCEPTED
+ NDIS_STATUS_OPEN_ERROR
+ NDIS_STATUS_RESOURCES
+ NDIS_STATUS_UNSUPPORTED_MEDIA
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PADAPTERCB AdapterCB;
+ UINT Index;
+ NDIS_HANDLE ConfigHandle;
+ ULONG NetworkAddressLength;
+#ifdef NT
+ LARGE_INTEGER TickCount, SystemTime;
+#endif
+
+ NdisWanDbgOut(DBG_TRACE, DBG_MINIPORT, ("NdisWanInitialize: Enter"));
+
+
+ //
+ // We have to be type 802.3 to the ndis wrapper, but the
+ // wrapper will expose us to the transports as type wan.
+ //
+ for (Index = 0; Index < MediumArraySize; Index++) {
+
+ if (MediumArray[Index] == NdisMedium802_3) {
+ break;
+ }
+ }
+
+ //
+ // We don't have a match so we are screwed
+ //
+ if (Index == MediumArraySize) {
+ return (NDIS_STATUS_UNSUPPORTED_MEDIA);
+ }
+
+ *SelectedMediumIndex = Index;
+
+ //
+ // Allocate and initialize miniport adapter structure
+ //
+#ifdef MINIPORT_NAME
+ Status = NdisWanCreateAdapterCB(&AdapterCB, &((PNDIS_MINIPORT_BLOCK)(MiniportAdapterHandle))->MiniportName);
+#else
+ Status = NdisWanCreateAdapterCB(&AdapterCB, NULL);
+#endif
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ NdisWanDbgOut(DBG_CRITICAL_ERROR, DBG_MINIPORT,
+ ("Error Creating AdapterCB! Status: 0x%x - %s",
+ Status, NdisWanGetNdisStatus(Status)));
+ return (NDIS_STATUS_FAILURE);
+ }
+
+ NdisMSetAttributesEx(MiniportAdapterHandle,
+ AdapterCB,
+ (UINT)-1,
+ NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT |
+ NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT,
+ NdisInterfaceInternal);
+
+ AdapterCB->MediumType = MediumArray[Index];
+ AdapterCB->ulReferenceCount = 0;
+ AdapterCB->hMiniportHandle = MiniportAdapterHandle;
+
+ NdisOpenConfiguration(&Status,
+ &ConfigHandle,
+ WrapperConfigurationContext);
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ NdisReadNetworkAddress(&Status,
+ (PVOID*)&(AdapterCB->NetworkAddress),
+ &NetworkAddressLength,
+ ConfigHandle);
+
+ NdisCloseConfiguration(ConfigHandle);
+
+ if (Status != NDIS_STATUS_SUCCESS ||
+ NetworkAddressLength != ETH_LENGTH_OF_ADDRESS) {
+
+ goto BuildAddress;
+
+ }
+
+
+ } else {
+
+BuildAddress:
+
+#ifdef NT
+
+ KeQueryTickCount(&TickCount);
+ KeQuerySystemTime(&SystemTime);
+
+ AdapterCB->NetworkAddress[0] = (UCHAR)((TickCount.LowPart >> 16) ^
+ (SystemTime.LowPart >> 16)) &
+ 0xFE;
+
+ AdapterCB->NetworkAddress[1] = (UCHAR)((TickCount.LowPart >> 8) ^
+ (SystemTime.LowPart >> 8));
+
+ AdapterCB->NetworkAddress[2] = (UCHAR)(TickCount.LowPart ^
+ SystemTime.LowPart);
+
+ //
+ // The following three bytes will be filled in at lineup time
+ //
+ AdapterCB->NetworkAddress[3] = 0x00;
+ AdapterCB->NetworkAddress[4] = 0x00;
+ AdapterCB->NetworkAddress[5] = 0x00;
+#endif
+
+ }
+
+#ifndef USE_NDIS_MINIPORT_CALLBACK
+ NdisMInitializeTimer(&AdapterCB->DeferredTimer,
+ AdapterCB->hMiniportHandle,
+ DeferredTimerFunction,
+ AdapterCB);
+#endif // end of !USE_NDIS_MINIPORT_CALLBACK
+
+ NdisWanDbgOut(DBG_TRACE, DBG_MINIPORT, ("NdisWanInitialize: Exit"));
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+NdisWanQueryInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PADAPTERCB AdapterCB = (PADAPTERCB)MiniportAdapterContext;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_MINIPORT, ("NdisWanQueryInformation: Enter Oid: 0x%4.4x", Oid));
+
+ NdisWanInterlockedInc(&AdapterCB->ulReferenceCount);
+
+ Status = NdisWanOidProc(AdapterCB,
+ Oid,
+ QUERY_OID,
+ InformationBuffer,
+ InformationBufferLength,
+ BytesWritten,
+ BytesNeeded);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_MINIPORT, ("NdisWanQueryInformation: Exit"));
+
+ NdisWanInterlockedDec(&AdapterCB->ulReferenceCount);
+
+ return (Status);
+}
+
+NDIS_STATUS
+NdisWanReconfigure(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PADAPTERCB AdapterCB = (PADAPTERCB)MiniportAdapterContext;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_MINIPORT, ("NdisWanReconfigure: Enter"));
+
+ NdisWanInterlockedInc(&AdapterCB->ulReferenceCount);
+
+ NdisWanInterlockedDec(&AdapterCB->ulReferenceCount);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_MINIPORT, ("NdisWanReconfigure: Exit"));
+ return (Status);
+}
+
+NDIS_STATUS
+NdisWanReset(
+ OUT PBOOLEAN AddressingReset,
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PADAPTERCB AdapterCB = (PADAPTERCB)MiniportAdapterContext;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_MINIPORT, ("NdisWanReset: Enter"));
+ DbgPrint("NDISWAN: Resest for Adapter: 0x%8.8x\n", AdapterCB);
+
+ NdisWanInterlockedInc(&AdapterCB->ulReferenceCount);
+
+ AdapterCB->Flags &= ~ASK_FOR_RESET;
+
+ NdisWanInterlockedDec(&AdapterCB->ulReferenceCount);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_MINIPORT, ("NdisWanReset: Exit"));
+
+ return (Status);
+}
+
+
+NDIS_STATUS
+NdisWanSetInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PADAPTERCB AdapterCB = (PADAPTERCB)MiniportAdapterContext;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_MINIPORT, ("NdisWanSetInformation: Enter Oid: 0x%4.4x", Oid));
+
+ NdisWanInterlockedInc(&AdapterCB->ulReferenceCount);
+
+ Status = NdisWanOidProc(AdapterCB,
+ Oid,
+ SET_OID,
+ InformationBuffer,
+ InformationBufferLength,
+ BytesWritten,
+ BytesNeeded);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_MINIPORT, ("NdisWanSetInformation: Exit"));
+
+ NdisWanInterlockedDec(&AdapterCB->ulReferenceCount);
+
+ return (Status);
+}
+
+#ifdef USE_NDIS_MINIPORT_CALLBACK
+VOID
+DeferredCallback(
+ PADAPTERCB AdapterCB,
+ PVOID Context
+ )
+{
+ BOOLEAN Again;
+ ULONG Type = (ULONG)Context;
+
+ NdisAcquireSpinLock(&AdapterCB->Lock);
+
+ NdisWanInterlockedInc(&AdapterCB->ulReferenceCount);
+
+ do {
+ Again = FALSE;
+
+ //
+ // Chec the receive indication queue first
+ //
+ if (!IsDeferredQueueEmpty(&AdapterCB->DeferredQueue[ReceiveIndication])) {
+ NdisWanProcessReceiveIndications(AdapterCB);
+ Again = TRUE;
+ }
+
+ //
+ // Check the send complete queue
+ //
+ if (!IsDeferredQueueEmpty(&AdapterCB->DeferredQueue[SendComplete])) {
+ NdisWanProcessSendCompletes(AdapterCB);
+ Again = TRUE;
+ }
+
+ //
+ // Check the loopback queue
+ //
+ if (!IsDeferredQueueEmpty(&AdapterCB->DeferredQueue[Loopback])) {
+ NdisWanProcessLoopbacks(AdapterCB);
+ Again = TRUE;
+ }
+
+ //
+ // Check the indications queue
+ //
+ if (!IsDeferredQueueEmpty(&AdapterCB->DeferredQueue[StatusIndication])) {
+ NdisWanProcessStatusIndications(AdapterCB);
+ Again = TRUE;
+ }
+
+ } while (Again);
+
+ if (AdapterCB->Flags & RECEIVE_COMPLETE) {
+ NdisWanDoReceiveComplete(AdapterCB);
+ AdapterCB->Flags &= ~RECEIVE_COMPLETE;
+ }
+
+ AdapterCB->Flags &= ~DEFERRED_CALLBACK_SET;
+
+ NdisReleaseSpinLock(&AdapterCB->Lock);
+
+ NdisWanInterlockedDec(&AdapterCB->ulReferenceCount);
+}
+#else // end of USE_NDIS_MINIPORT_CALLBACK
+VOID
+DeferredTimerFunction(
+ PVOID System1,
+ PADAPTERCB AdapterCB,
+ PVOID System2,
+ PVOID System3
+ )
+{
+ BOOLEAN Again;
+
+ NdisAcquireSpinLock(&AdapterCB->Lock);
+
+ NdisWanInterlockedInc(&AdapterCB->ulReferenceCount);
+
+ do {
+ Again = FALSE;
+
+ //
+ // Chec the receive indication queue first
+ //
+ if (!IsDeferredQueueEmpty(&AdapterCB->DeferredQueue[ReceiveIndication])) {
+ NdisWanProcessReceiveIndications(AdapterCB);
+ Again = TRUE;
+ }
+
+ //
+ // Check the send complete queue
+ //
+ if (!IsDeferredQueueEmpty(&AdapterCB->DeferredQueue[SendComplete])) {
+ NdisWanProcessSendCompletes(AdapterCB);
+ Again = TRUE;
+ }
+
+ //
+ // Check the loopback queue
+ //
+ if (!IsDeferredQueueEmpty(&AdapterCB->DeferredQueue[Loopback])) {
+ NdisWanProcessLoopbacks(AdapterCB);
+ Again = TRUE;
+ }
+
+ //
+ // Check the indications queue
+ //
+ if (!IsDeferredQueueEmpty(&AdapterCB->DeferredQueue[StatusIndication])) {
+ NdisWanProcessStatusIndications(AdapterCB);
+ Again = TRUE;
+ }
+
+ } while (Again);
+
+ if (AdapterCB->Flags & RECEIVE_COMPLETE) {
+ NdisWanDoReceiveComplete(AdapterCB);
+ AdapterCB->Flags &= ~RECEIVE_COMPLETE;
+ }
+
+ AdapterCB->Flags &= ~DEFERRED_TIMER_SET;
+
+ NdisReleaseSpinLock(&AdapterCB->Lock);
+
+ NdisWanInterlockedDec(&AdapterCB->ulReferenceCount);
+}
+#endif // end of !USE_NDIS_MINIPORT_CALLBACK
diff --git a/private/ntos/ndis/ndiswan/ndiswan.c b/private/ntos/ndis/ndiswan/ndiswan.c
new file mode 100644
index 000000000..da5771b79
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/ndiswan.c
@@ -0,0 +1,1346 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ Ndiswan.c
+
+Abstract:
+
+ This is the initialization file for the NdisWan driver. This driver
+ is a shim between the protocols, where it conforms to the NDIS 3.1
+ Miniport interface spec, and the WAN Miniport drivers, where it exports
+ the WAN Extensions for Miniports (it looks like a protocol to the WAN
+ Miniport drivers).
+
+Author:
+
+ Tony Bell (TonyBe) June 06, 1995
+
+Environment:
+
+ Kernel Mode
+
+Revision History:
+
+ TonyBe 06/06/95 Created
+
+--*/
+
+
+//
+// We want to initialize all of the global variables now!
+//
+#include "wan.h"
+
+EXPORT
+VOID
+NdisTapiRegisterProvider(
+ IN NDIS_HANDLE DriverHandle,
+ IN PVOID RequestProc
+ );
+
+//
+// Globals
+//
+NDISWANCB NdisWanCB; // Global control block for NdisWan
+
+WAN_GLOBAL_LIST ThresholdEventQueue; // Global thresholdevent queue
+
+WAN_GLOBAL_LIST RecvPacketQueue; // Global receive packet queue
+
+WAN_GLOBAL_LIST FreeBundleCBList; // List of free BundleCB's
+
+WAN_GLOBAL_LIST AdapterCBList; // List of NdisWan AdapterCB's
+
+WAN_GLOBAL_LIST WanAdapterCBList; // List of WAN Miniport structures
+
+WAN_GLOBAL_LIST GlobalRecvDescPool; // Global pool of free recvdesc's
+
+PCONNECTION_TABLE ConnectionTable = NULL; // Pointer to connection table
+
+PPPP_PROTOCOL_TABLE PPP_ProtocolTable = NULL; // Pointer to the PPP/Protocol lookup table
+
+NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
+
+#ifdef NT
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+/*++
+Routine Name:
+
+ DriverEntry
+
+Routine Description:
+
+ This is the NT OS specific driver entry point. It kicks off initialization
+ for the driver. We return from this routine only after NdisWan has installed
+ itself as: a Miniport driver, a "transport" to the WAN Miniport drivers, and
+ has been bound to the WAN Miniport drivers.
+
+Arguments:
+
+ DriverObject - NT OS specific Object
+ RegistryPath - NT OS specific pointer to registry location for NdisWan
+
+Return Values:
+
+ STATUS_SUCCESS
+ STATUS_FAILURE
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ NDIS_STRING SymbolicName = NDIS_STRING_CONST("\\DosDevices\\NdisWan");
+ NDIS_STRING Name = NDIS_STRING_CONST("\\Device\\NdisWan");
+ ULONG i;
+
+ NdisZeroMemory(&NdisWanCB, sizeof(NdisWanCB));
+
+ NdisWanCB.ulTraceLevel = DBG_CRITICAL_ERROR;
+ NdisWanCB.ulTraceMask = DBG_ALL;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_INIT, ("DriverEntry: Enter"));
+
+ //
+ // Initialize as a Miniport MAC driver first
+ //
+ NdisMInitializeWrapper(&(NdisWanCB.hNdisWrapperHandle),
+ DriverObject,
+ RegistryPath,
+ NULL);
+
+ //
+ // Initialize globals
+ //
+ NdisAllocateSpinLock(&NdisWanCB.Lock);
+
+ NdisWanCB.pDriverObject = DriverObject;
+
+ NdisZeroMemory(&AdapterCBList, sizeof(WAN_GLOBAL_LIST));
+ InitializeListHead(&(AdapterCBList.List));
+ NdisAllocateSpinLock(&AdapterCBList.Lock);
+
+ NdisZeroMemory(&WanAdapterCBList, sizeof(WAN_GLOBAL_LIST));
+ InitializeListHead(&(WanAdapterCBList.List));
+ NdisAllocateSpinLock(&WanAdapterCBList.Lock);
+
+ NdisZeroMemory(&ThresholdEventQueue, sizeof(WAN_GLOBAL_LIST));
+ InitializeListHead(&(ThresholdEventQueue.List));
+ NdisAllocateSpinLock(&ThresholdEventQueue.Lock);
+
+ NdisZeroMemory(&RecvPacketQueue, sizeof(WAN_GLOBAL_LIST));
+ InitializeListHead(&(RecvPacketQueue.List));
+ NdisAllocateSpinLock(&RecvPacketQueue.Lock);
+
+ NdisZeroMemory(&FreeBundleCBList, sizeof(WAN_GLOBAL_LIST));
+ InitializeListHead(&(FreeBundleCBList.List));
+ NdisAllocateSpinLock(&FreeBundleCBList.Lock);
+
+ NdisZeroMemory(&GlobalRecvDescPool, sizeof(WAN_GLOBAL_LIST));
+ InitializeListHead(&GlobalRecvDescPool.List);
+ NdisAllocateSpinLock(&GlobalRecvDescPool.Lock);
+
+ Status = NdisWanCreatePPPProtocolTable();
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NdisWanDbgOut(DBG_CRITICAL_ERROR, DBG_INIT,
+ ("NdisWanInitProtocolLookupTable Failed! Status: 0x%x - %s",
+ Status, NdisWanGetNdisStatus(Status)));
+
+ goto DriverEntryError;
+ }
+
+ //
+ // Initialize as a Miniport driver to the transports
+ //
+ Status = DoMiniportInit();
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NdisWanDbgOut(DBG_CRITICAL_ERROR, DBG_INIT,
+ ("DoMiniportInit Failed! Status: 0x%x - %s",
+ Status, NdisWanGetNdisStatus(Status)));
+
+ goto DriverEntryError;
+ }
+
+ //
+ // Now initialzie as a "Protocol" to the WAN Miniport drivers
+ //
+ Status = DoProtocolInit(RegistryPath);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NdisWanDbgOut(DBG_CRITICAL_ERROR, DBG_INIT,
+ ("DoProtocolInit Failed! Status: 0x%x - %s",
+ Status, NdisWanGetNdisStatus(Status)));
+
+ goto DriverEntryError;
+ }
+
+ NdisWanReadRegistry(RegistryPath);
+
+ //
+ // Bind NdisWan to the WAN Miniport drivers
+ //
+ Status = DoWanMiniportInit();
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NdisWanDbgOut(DBG_CRITICAL_ERROR, DBG_INIT,
+ ("DoWanMiniportInit Failed! Status: 0x%x - %s",
+ Status, NdisWanGetNdisStatus(Status)));
+
+ goto DriverEntryError;
+
+ }
+
+//
+// Code commented out for PNP. We may go through DriverEntry and not have
+// any miniports bound to us yet. We will get called to bind to a WanMiniport
+// at a later time by the ProtocolBindHandler call (?).
+//
+/*
+ NdisAcquireSpinLock(&WanAdapterCBList.Lock);
+
+ if (WanAdapterCBList.ulCount == 0) {
+ NdisWanDbgOut(DBG_CRITICAL_ERROR, DBG_INIT, ("No WanAdapters installed!"));
+
+ NdisReleaseSpinLock(&WanAdapterCBList.Lock);
+
+ goto DriverEntryError;
+ }
+
+ NdisReleaseSpinLock(&WanAdapterCBList.Lock);
+*/
+
+ //
+ // Allocate and initialize the ConnectionTable
+ //
+ Status = NdisWanCreateConnectionTable(NdisWanCB.ulNumberOfLinks + 10);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NdisWanDbgOut(DBG_CRITICAL_ERROR, DBG_INIT,
+ ("NdisWanInitConnectionTable Failed! Status: 0x%x - %s",
+ Status, NdisWanGetNdisStatus(Status)));
+
+ goto DriverEntryError;
+
+ }
+
+ //
+ // Initialize the Ioctl interface
+ //
+ for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
+
+ NdisWanCB.MajorFunction[i] = (PVOID)DriverObject->MajorFunction[i];
+ DriverObject->MajorFunction[i] = NdisWanIrpStub;
+ }
+
+ DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = NdisWanIoctl;
+
+ IoCreateDevice(DriverObject,
+ sizeof(LIST_ENTRY),
+ &Name,
+ FILE_DEVICE_NDISWAN,
+ 0,
+ FALSE,
+ (PDEVICE_OBJECT*)&NdisWanCB.pDeviceObject);
+
+ NdisWanDbgOut(DBG_INFO, DBG_INIT,
+ ("IoCreateSymbolicLink: %ls -> %ls",
+ SymbolicName.Buffer, Name.Buffer));
+
+ ((PDEVICE_OBJECT)NdisWanCB.pDeviceObject)->Flags |= DO_BUFFERED_IO;
+
+ IoCreateSymbolicLink(&SymbolicName,
+ &Name);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_INIT, ("DriverEntry: Exit"));
+
+ return (STATUS_SUCCESS);
+
+ //
+ // An error occured so we need to cleanup things
+ //
+DriverEntryError:
+ NdisWanGlobalCleanup();
+
+// NdisTerminateWrapper(NdisWanCB.hNdisWrapperHandle,
+// NdisWanCB.pDriverObject);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_INIT, ("DriverEntry: Exit Error!"));
+
+ return (STATUS_UNSUCCESSFUL);
+
+}
+
+
+VOID
+NdisWanReadRegistry(
+ IN PUNICODE_STRING RegistryPath
+ )
+/*++
+
+Routine Name:
+
+ NdisWanReadRegistry
+
+Routine Description:
+
+ This routine will read the registry values for NdisWan. These values only
+ need to be read once for all adapters as their information is global.
+
+Arguments:
+
+ WrapperConfigurationContext - Handle to registry key where NdisWan information
+ is stored.
+
+Return Values:
+
+ None
+
+--*/
+{
+ NDIS_STATUS Status;
+ PWSTR ParameterKey = L"NdisWan\\Parameters";
+ PWSTR BindKeyWord = L"Bind";
+ PWSTR ProtocolKeyWord = L"ProtocolType";
+ PWSTR PPPKeyWord = L"PPPProtocolType";
+ PWSTR FragmentSizeKeyWord = L"MinimumFragmentSize";
+ PWSTR DebugLevelKeyWord = L"DebugLevel";
+ PWSTR DebugIDKeyWord = L"DebugIdentifier";
+ RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+ ULONG GenericULong;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_INIT, ("NdisWanReadRegistry: Enter"));
+
+ //
+ // Read the Bind Parameter MULTI_SZ
+ //
+ NdisZeroMemory(&QueryTable, sizeof(QueryTable));
+ QueryTable[0].QueryRoutine = BindQueryRoutine;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[0].Name = BindKeyWord;
+ QueryTable[0].EntryContext = NULL;
+ QueryTable[0].DefaultType = 0;
+ Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
+ ParameterKey,
+ &QueryTable[0],
+ NULL,
+ NULL);
+
+
+ NdisWanDbgOut(DBG_INFO, DBG_INIT,
+ ("RtlQueryRegistry - 'Bind' Status: 0x%x",
+ Status));
+
+ //
+ // Read the ProtocolType parameter MULTI_SZ
+ //
+ NdisZeroMemory(&QueryTable, sizeof(QueryTable));
+ QueryTable[0].QueryRoutine = ProtocolTypeQueryRoutine;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[0].Name = ProtocolKeyWord;
+ QueryTable[0].EntryContext = (PVOID)PROTOCOL_TYPE;
+ QueryTable[0].DefaultType = 0;
+ Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
+ ParameterKey,
+ &QueryTable[0],
+ NULL,
+ NULL);
+
+ NdisWanDbgOut(DBG_INFO, DBG_INIT,
+ ("RtlQueryRegistry - 'ProtocolType' Status: 0x%x",
+ Status));
+ //
+ // Read the PPPProtocolType parameter MULTI_SZ
+ //
+ NdisZeroMemory(&QueryTable, sizeof(QueryTable));
+ QueryTable[0].QueryRoutine = ProtocolTypeQueryRoutine;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[0].Name = PPPKeyWord;
+ QueryTable[0].EntryContext = (PVOID)PPP_TYPE;
+ QueryTable[0].DefaultType = 0;
+ Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
+ ParameterKey,
+ &QueryTable[0],
+ NULL,
+ NULL);
+
+ NdisWanDbgOut(DBG_INFO, DBG_INIT,
+ ("RtlQueryRegistry - 'PPPProtocolType' Status: 0x%x",
+ Status));
+
+ //
+ // Read the MinFragmentSize parameter DWORD
+ //
+ NdisWanCB.ulMinFragmentSize = 100;
+ NdisZeroMemory(&QueryTable, sizeof(QueryTable));
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[0].Name = FragmentSizeKeyWord;
+ QueryTable[0].EntryContext = (PVOID)&GenericULong;
+ QueryTable[0].DefaultType = 0;
+ Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
+ ParameterKey,
+ &QueryTable[0],
+ NULL,
+ NULL);
+
+ NdisWanDbgOut(DBG_INFO, DBG_INIT,
+ ("RtlQueryRegistry - 'MinimumFragmentSize' Status: 0x%x",
+ Status));
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+ NdisWanCB.ulMinFragmentSize = GenericULong;
+ }
+
+
+ //
+ // Read the DebugLevel parameter DWORD
+ //
+ NdisZeroMemory(&QueryTable, sizeof(QueryTable));
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[0].Name = DebugLevelKeyWord;
+ QueryTable[0].EntryContext = (PVOID)&GenericULong;
+ QueryTable[0].DefaultType = 0;
+ Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
+ ParameterKey,
+ &QueryTable[0],
+ NULL,
+ NULL);
+
+ NdisWanDbgOut(DBG_INFO, DBG_INIT,
+ ("RtlQueryRegistry - 'DebugLevel' Status: 0x%x",
+ Status));
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+ NdisWanCB.ulTraceLevel = GenericULong;
+ }
+
+ //
+ // Read the DebugIdentifier parameter DWORD
+ //
+ NdisZeroMemory(&QueryTable, sizeof(QueryTable));
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[0].Name = DebugIDKeyWord;
+ QueryTable[0].EntryContext = (PVOID)&GenericULong;
+ QueryTable[0].DefaultType = 0;
+ Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
+ ParameterKey,
+ &QueryTable[0],
+ NULL,
+ NULL);
+
+ NdisWanDbgOut(DBG_INFO, DBG_INIT,
+ ("RtlQueryRegistry - 'DebugID' Status: 0x%x",
+ Status));
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+ NdisWanCB.ulTraceMask = GenericULong;
+ }
+
+ NdisWanDbgOut(DBG_TRACE, DBG_INIT, ("NdisWanReadRegistry: Exit"));
+}
+
+NTSTATUS
+BindQueryRoutine(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_INIT, ("BindQueryRoutine: Enter"));
+ NdisWanDbgOut(DBG_TRACE, DBG_INIT, ("MiniportName %ls", ValueData));
+
+ //
+ // Create the WanAdapterCB
+ //
+ Status = NdisWanCreateWanAdapterCB(ValueData);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ NdisWanDbgOut(DBG_CRITICAL_ERROR, DBG_INIT,
+ ("NdisWanCreateWanAdapterCB Failed! Status: 0x%x - %s",
+ Status, NdisWanGetNdisStatus(Status)));
+
+ }
+
+ NdisWanDbgOut(DBG_TRACE, DBG_INIT, ("BindQueryRoutine: Exit Status: 0x%x", Status));
+
+ return (Status);
+}
+
+NTSTATUS
+ProtocolTypeQueryRoutine(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NDIS_STRING String;
+ ULONG Value;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_INIT, ("ProtocolTypeQueryRoutine: Enter"));
+
+ //
+ // Convert to an NDIS_STRING
+ //
+ NdisWanStringToNdisString(&String, ValueData);
+
+ //
+ // Convert to an integer
+ //
+ NdisWanNdisStringToInteger(&String, &Value);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_INIT, ("ProtocolID 0x%x", Value));
+
+ NdisWanFreeNdisString(&String);
+
+ //
+ // Place in table
+ //
+ InsertPPP_ProtocolID(Value, (ULONG)EntryContext);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_INIT, ("ProtocolTypeQueryRoutine: Exit"));
+
+ return (Status);
+}
+
+
+#endif // NT specific code
+
+
+
+NDIS_STATUS
+DoMiniportInit(
+ VOID
+ )
+/*++
+
+Routine Name:
+
+ DoMiniportInit
+
+Routine Description:
+
+ This routines registers NdisWan as a Miniport driver with the NDIS wrapper.
+ The wrapper will now call NdisWanInitialize once for each adapter instance
+ of NdisWan that is in the registry.
+
+Arguments:
+
+ None
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_BAD_VERSION
+ NDIS_STATUS_FAILURE
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ NDIS_MINIPORT_CHARACTERISTICS MiniportChars;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_INIT, ("DoMiniportInit: Enter"));
+
+ NdisZeroMemory(&MiniportChars, sizeof(MiniportChars));
+
+ MiniportChars.MajorNdisVersion = 3;
+ MiniportChars.MinorNdisVersion = 0;
+ MiniportChars.HaltHandler = NdisWanHalt;
+ MiniportChars.InitializeHandler = NdisWanInitialize;
+ MiniportChars.QueryInformationHandler = NdisWanQueryInformation;
+ MiniportChars.ReconfigureHandler = NdisWanReconfigure;
+ MiniportChars.ResetHandler = NdisWanReset;
+ MiniportChars.SendHandler = NdisWanSend;
+ MiniportChars.SetInformationHandler = NdisWanSetInformation;
+ MiniportChars.TransferDataHandler = NdisWanTransferData;
+
+ //
+ // Since we don't have any hardware to worry about we will
+ // not handle any of the interrupt stuff!
+ //
+ MiniportChars.DisableInterruptHandler = NULL;
+ MiniportChars.EnableInterruptHandler = NULL;
+ MiniportChars.HandleInterruptHandler = NULL;
+ MiniportChars.ISRHandler = NULL;
+
+ //
+ // We will disable the check for hang timeout so we do not
+ // need a check for hang handler!
+ //
+// MiniportChars.CheckForHangHandler = NdisWanCheckForHang;
+ MiniportChars.CheckForHangHandler = NULL;
+
+ Status = NdisMRegisterMiniport(NdisWanCB.hNdisWrapperHandle,
+ &MiniportChars,
+ sizeof(MiniportChars));
+
+ NdisWanDbgOut(DBG_TRACE, DBG_INIT, ("DoMiniportInit: Exit"));
+
+ return (Status);
+}
+
+
+
+NDIS_STATUS
+DoProtocolInit(
+ IN PUNICODE_STRING RegistryPath
+ )
+/*++
+
+Routine Name:
+
+ DoProtocolInit
+
+Routine Description:
+
+ This function registers NdisWan as a protocol with the NDIS wrapper.
+
+Arguments:
+
+ None
+
+Return Values:
+
+ NDIS_STATUS_BAD_CHARACTERISTICS
+ NDIS_STATUS_BAD_VERSION
+ NDIS_STATUS_RESOURCES
+ NDIS_STATUS_SUCCESS
+
+--*/
+{
+//
+// The name of the "transport" side of NdisWan
+//
+ NDIS_PROTOCOL_CHARACTERISTICS ProtocolChars;
+ NDIS_STATUS Status;
+ NDIS_STRING NdisWanName = NDIS_STRING_CONST("\\Device\\NdisWan");
+
+
+ NdisWanDbgOut(DBG_TRACE, DBG_INIT, ("DoProtocolInit: Enter"));
+
+ NdisZeroMemory(&ProtocolChars, sizeof(ProtocolChars));
+
+
+ ProtocolChars.Name.Length = NdisWanName.Length;
+ ProtocolChars.Name.Buffer = (PVOID)NdisWanName.Buffer;
+
+ ProtocolChars.MajorNdisVersion = 3;
+ ProtocolChars.MinorNdisVersion = 0;
+ ProtocolChars.CloseAdapterCompleteHandler = NdisWanCloseAdapterComplete;
+ ProtocolChars.StatusHandler = NdisWanIndicateStatus;
+ ProtocolChars.StatusCompleteHandler = NdisWanIndicateStatusComplete;
+ ProtocolChars.OpenAdapterCompleteHandler = NdisWanOpenAdapterComplete;
+ ProtocolChars.RequestCompleteHandler = NdisWanRequestComplete;
+ ProtocolChars.ResetCompleteHandler = NdisWanResetComplete;
+ ProtocolChars.WanSendCompleteHandler = NdisWanSendCompleteHandler;
+ ProtocolChars.TransferDataCompleteHandler = NdisWanTransferDataComplete;
+ ProtocolChars.WanReceiveHandler = NdisWanReceiveIndication;
+ ProtocolChars.ReceiveCompleteHandler = NdisWanReceiveComplete;
+
+ NdisRegisterProtocol(&Status,
+ &NdisWanCB.hProtocolHandle,
+ (PNDIS_PROTOCOL_CHARACTERISTICS)&ProtocolChars,
+ sizeof(NDIS_PROTOCOL_CHARACTERISTICS) + ProtocolChars.Name.Length);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_INIT, ("DoProtocolInit: Exit"));
+
+ return (Status);
+}
+
+NDIS_STATUS
+DoWanMiniportInit(
+ VOID
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PWAN_ADAPTERCB pWanAdapterCB;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ NDIS_MEDIUM WanMediumSubType;
+ NDIS_WAN_INFO WanInfo;
+ NDIS_REQUEST NdisRequest;
+
+ //
+ // For each WAN Miniport that we have a WANAdapterCB for we will
+ // open the WAN Miniport thus binding to it. We will also query
+ // each WAN Miniport adapter to get information about it.
+ //
+ NdisWanDbgOut(DBG_TRACE, DBG_INIT, ("DoWanMiniportInit: Enter"));
+
+ NdisAcquireSpinLock(&WanAdapterCBList.Lock);
+
+ for (pWanAdapterCB = (PWAN_ADAPTERCB)WanAdapterCBList.List.Flink;
+ (PVOID)pWanAdapterCB != (PVOID)&(WanAdapterCBList.List);
+ pWanAdapterCB = (PWAN_ADAPTERCB)pWanAdapterCB->Linkage.Flink) {
+
+ NdisReleaseSpinLock(&WanAdapterCBList.Lock);
+
+ Status = NdisWanOpenWanAdapter(pWanAdapterCB);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ PWAN_ADAPTERCB pPrevWanAdapterCB = (PWAN_ADAPTERCB)pWanAdapterCB->Linkage.Blink;
+
+ RemoveEntryList(&pWanAdapterCB->Linkage);
+ WanAdapterCBList.ulCount--;
+
+ NdisWanDbgOut(DBG_CRITICAL_ERROR, DBG_INIT, ("Failed to bind to %ls! Error 0x%x - %s",
+ pWanAdapterCB->MiniportName.Buffer, Status, NdisWanGetNdisStatus(Status)));
+
+ NdisWanDestroyWanAdapterCB(pWanAdapterCB);
+
+ pWanAdapterCB = pPrevWanAdapterCB;
+
+ NdisAcquireSpinLock(&WanAdapterCBList.Lock);
+ continue;
+ }
+
+ NdisWanDbgOut(DBG_TRACE, DBG_INIT, ("Successful Binding to %ls!",
+ pWanAdapterCB->MiniportName.Buffer));
+
+ //
+ // Get the medium subtype. We don't use this info right now but
+ // maybe someday...
+ //
+ NdisRequest.RequestType = NdisRequestQueryInformation;
+ NdisRequest.DATA.QUERY_INFORMATION.Oid = OID_WAN_MEDIUM_SUBTYPE;
+ NdisRequest.DATA.QUERY_INFORMATION.InformationBuffer = &WanMediumSubType;
+ NdisRequest.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(WanMediumSubType);
+
+ Status = NdisWanSubmitNdisRequest(pWanAdapterCB,
+ &NdisRequest,
+ SYNC,
+ NDISWAN);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_INIT, ("Error returned from OID_WAN_MEDIUM_SUBTYPE! Error 0x%x - %s",
+ Status, NdisWanGetNdisStatus(Status)));
+
+ NdisAcquireSpinLock(&WanAdapterCBList.Lock);
+ continue;
+ }
+
+ pWanAdapterCB->MediumSubType = WanMediumSubType;
+
+ //
+ // Get more information about the WAN Miniport that we are bound to!
+ //
+ NdisZeroMemory(&WanInfo, sizeof(WanInfo));
+ NdisRequest.RequestType = NdisRequestQueryInformation;
+ NdisRequest.DATA.QUERY_INFORMATION.Oid = OID_WAN_GET_INFO;
+ NdisRequest.DATA.QUERY_INFORMATION.InformationBuffer = &WanInfo;
+ NdisRequest.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(WanInfo);
+
+ Status = NdisWanSubmitNdisRequest(pWanAdapterCB,
+ &NdisRequest,
+ SYNC,
+ NDISWAN);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_INIT, ("Error returned from OID_WAN_GET_INFO! Error 0x%x - %s",
+ Status, NdisWanGetNdisStatus(Status)));
+
+ NdisAcquireSpinLock(&WanAdapterCBList.Lock);
+ continue;
+ }
+
+ NdisMoveMemory(&pWanAdapterCB->WanInfo, &WanInfo, sizeof(NDIS_WAN_INFO));
+
+ NdisWanCB.ulNumberOfLinks += pWanAdapterCB->WanInfo.Endpoints;
+
+ NdisAcquireSpinLock(&FreeBundleCBList.Lock);
+ FreeBundleCBList.ulMaxCount = NdisWanCB.ulNumberOfLinks;
+ NdisReleaseSpinLock(&FreeBundleCBList.Lock);
+
+ if (pWanAdapterCB->WanInfo.FramingBits & TAPI_PROVIDER) {
+
+ //
+ // Tell tapi about this device
+ //
+ NdisTapiRegisterProvider(pWanAdapterCB, NdisWanTapiRequestProc);
+
+ }
+
+ NdisAcquireSpinLock(&WanAdapterCBList.Lock);
+ }
+
+//
+// The following lines are commented out to take into account pnp.
+// We may not have any miniports to bind to initially but get called
+// to bind to them later!
+//
+// if (WanAdapterCBList.ulCount == 0)
+// Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+// else
+ Status = NDIS_STATUS_SUCCESS;
+
+ NdisReleaseSpinLock(&WanAdapterCBList.Lock);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_INIT, ("DoWanMiniportInit: Exit"));
+
+ return (Status);
+}
+
+VOID
+InsertPPP_ProtocolID(
+ IN ULONG Value,
+ IN ULONG ValueType
+ )
+/*++
+
+Routine Name:
+
+ InsertPPP_ProtocolID
+
+Routine Description:
+
+ This routine takes a protocol value or a PPP protocol value and inserts it
+ into the appropriate lookup table.
+
+Arguments:
+
+ Value - Either a ProtocolID or PPP ProtocolID
+
+ ValueType - Either PROTOCOL_TYPE or PPP_TYPE
+
+Return Values:
+
+--*/
+{
+ ULONG i;
+ ULONG ArraySize = PPP_ProtocolTable->ulArraySize;
+ PUSHORT ValueArray;
+
+ //
+ // Figure out which array we should be looking at for
+ // this value type
+ //
+ if (ValueType == PROTOCOL_TYPE) {
+ ValueArray = PPP_ProtocolTable->ProtocolID;
+ } else {
+ ValueArray = PPP_ProtocolTable->PPPProtocolID;
+ }
+
+ NdisAcquireSpinLock(&PPP_ProtocolTable->Lock);
+
+ //
+ // First check to see if this value is already in the array
+ //
+ for (i = 0; i < ArraySize; i++) {
+
+ if (ValueArray[i] == (USHORT)Value) {
+
+ //
+ // If it is then we just update the value
+ //
+ ValueArray[i] = (USHORT)Value;
+ break;
+
+ }
+ }
+
+ //
+ // We did not find the value in the array so
+ // we will add it at the 1st available spot
+ //
+ if (i >= ArraySize) {
+
+ for (i = 0; i < ArraySize; i++) {
+
+ //
+ // We are looking for an empty slot to add
+ // the new value to
+ //
+ if (ValueArray[i] == 0) {
+
+ ValueArray[i] = (USHORT)Value;
+
+ if (ValueType == PROTOCOL_TYPE) {
+ NdisWanCB.ulNumberOfProtocols++;
+ }
+
+ break;
+ }
+ }
+ }
+
+ NdisReleaseSpinLock(&PPP_ProtocolTable->Lock);
+}
+
+USHORT
+GetPPP_ProtocolID(
+ IN USHORT Value,
+ IN ULONG ValueType
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ ULONG i;
+ ULONG ArraySize = PPP_ProtocolTable->ulArraySize;
+ PUSHORT ValueArray, ReturnValueArray;
+ USHORT ReturnValue = INVALID_PROTOCOL;
+
+ //
+ // Figure out which array we should be looking at for
+ // this value type
+ //
+ if (ValueType == PROTOCOL_TYPE) {
+ ValueArray = PPP_ProtocolTable->ProtocolID;
+ ReturnValueArray = PPP_ProtocolTable->PPPProtocolID;
+ } else {
+ ValueArray = PPP_ProtocolTable->PPPProtocolID;
+ ReturnValueArray = PPP_ProtocolTable->ProtocolID;
+ }
+
+ NdisAcquireSpinLock(&PPP_ProtocolTable->Lock);
+
+ for (i = 0; i < ArraySize; i++) {
+ if (ValueArray[i] == Value) {
+ ReturnValue = ReturnValueArray[i];
+ break;
+ }
+ }
+
+ NdisReleaseSpinLock(&PPP_ProtocolTable->Lock);
+
+ return (ReturnValue);
+}
+
+NDIS_HANDLE
+InsertLinkInConnectionTable(
+ IN PLINKCB LinkCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ ULONG Index;
+ PLINKCB *LinkArray = ConnectionTable->LinkArray;
+
+ NdisAcquireSpinLock(&ConnectionTable->Lock);
+
+ //
+ // We are doing a linear search for an empty spot in
+ // the link array
+ //
+ for (Index = 1; Index < ConnectionTable->ulArraySize; Index++) {
+ if (LinkArray[Index] == NULL) {
+ LinkArray[Index] = LinkCB;
+ ConnectionTable->ulNumActiveLinks++;
+ LinkCB->hLinkHandle = (NDIS_HANDLE)Index;
+ break;
+ }
+ }
+
+ ASSERT(Index < ConnectionTable->ulArraySize);
+
+ NdisReleaseSpinLock(&ConnectionTable->Lock);
+
+ return ((NDIS_HANDLE)Index);
+}
+
+VOID
+RemoveLinkFromConnectionTable(
+ IN PLINKCB LinkCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ ULONG Index = (ULONG)LinkCB->hLinkHandle;
+ PLINKCB *LinkArray = ConnectionTable->LinkArray;
+
+ NdisAcquireSpinLock(&ConnectionTable->Lock);
+
+ if (LinkArray[Index] != NULL) {
+
+ ASSERT(LinkCB == LinkArray[Index]);
+
+ LinkArray[Index] = NULL;
+
+ ConnectionTable->ulNumActiveLinks--;
+ } else {
+ NdisWanDbgOut(DBG_CRITICAL_ERROR, DBG_INIT, ("LinkCB not in connection table! LinkCB: 0x%8.8x", LinkCB));
+ ASSERT(0);
+ }
+
+ NdisReleaseSpinLock(&ConnectionTable->Lock);
+}
+
+NDIS_HANDLE
+InsertBundleInConnectionTable(
+ IN PBUNDLECB BundleCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ ULONG Index;
+ PBUNDLECB *BundleArray = ConnectionTable->BundleArray;
+
+ NdisAcquireSpinLock(&ConnectionTable->Lock);
+
+ //
+ // We are doing a linear search for an empty spot in
+ // the link array
+ //
+ for (Index = 1; Index < ConnectionTable->ulArraySize; Index++) {
+ if (BundleArray[Index] == NULL) {
+ BundleArray[Index] = BundleCB;
+ ConnectionTable->ulNumActiveBundles++;
+ BundleCB->hBundleHandle = (NDIS_HANDLE)Index;
+ break;
+ }
+ }
+
+ InsertTailList(&ConnectionTable->BundleList, &BundleCB->Linkage);
+
+ ASSERT(Index != ConnectionTable->ulArraySize);
+
+ NdisReleaseSpinLock(&ConnectionTable->Lock);
+
+ return ((NDIS_HANDLE)Index);
+}
+
+VOID
+RemoveBundleFromConnectionTable(
+ IN PBUNDLECB BundleCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ ULONG Index = (ULONG)BundleCB->hBundleHandle;
+ PBUNDLECB *BundleArray = ConnectionTable->BundleArray;
+
+ NdisAcquireSpinLock(&ConnectionTable->Lock);
+
+ if (BundleArray[Index] != NULL) {
+
+ ASSERT(BundleCB == BundleArray[Index]);
+
+ RemoveEntryList(&BundleCB->Linkage);
+
+ BundleArray[Index] = NULL;
+
+ ConnectionTable->ulNumActiveBundles--;
+ } else {
+ NdisWanDbgOut(DBG_CRITICAL_ERROR, DBG_INIT, ("BundleCB not in connection table! BundleCB: 0x%8.8x", BundleCB));
+ ASSERT(0);
+ }
+
+ NdisReleaseSpinLock(&ConnectionTable->Lock);
+}
+
+VOID
+NdisWanGlobalCleanup(
+ VOID
+ )
+/*++
+
+Routine Name:
+
+ NdisWanGlobalCleanup
+
+Routine Description:
+ This routine is responsible for cleaning up all allocated resources.
+
+Arguments:
+
+ None
+
+Return Values:
+
+ None
+
+--*/
+{
+ //
+ // Stop all timers
+ //
+
+ //
+ // Complete all outstanding requests
+ //
+
+ //
+ // Free all of the AdapterCB's
+ //
+ NdisAcquireSpinLock(&AdapterCBList.Lock);
+ while (!IsListEmpty(&AdapterCBList.List)) {
+ PADAPTERCB AdapterCB;
+
+ AdapterCB = (PADAPTERCB)RemoveHeadList(&AdapterCBList.List);
+ NdisWanFreeMemory(AdapterCB);
+ }
+ NdisReleaseSpinLock(&AdapterCBList.Lock);
+
+ //
+ // Free all of the WanAdapterCB's
+ //
+ NdisAcquireSpinLock(&WanAdapterCBList.Lock);
+ while (!IsListEmpty(&WanAdapterCBList.List)) {
+ PWAN_ADAPTERCB WanAdapterCB;
+
+ WanAdapterCB = (PWAN_ADAPTERCB)RemoveHeadList(&WanAdapterCBList.List);
+ NdisWanFreeMemory(WanAdapterCB);
+ }
+ NdisReleaseSpinLock(&WanAdapterCBList.Lock);
+
+ //
+ // Free all of the BundleCB's
+ //
+
+ //
+ // Free all of the LinkCB's
+ //
+
+ //
+ // Free globals
+ //
+ if (ConnectionTable != NULL) {
+ NdisWanFreeMemory(ConnectionTable);
+ }
+
+ if (PPP_ProtocolTable != NULL) {
+ NdisWanFreeMemory(PPP_ProtocolTable);
+ }
+
+ //
+ // Terminate the wrapper
+ //
+ NdisTerminateWrapper(NdisWanCB.hNdisWrapperHandle,
+ NdisWanCB.pDriverObject);
+}
+
+BOOLEAN
+IsHandleValid(
+ USHORT usHandleType,
+ NDIS_HANDLE hHandle
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ BOOLEAN RetValue = FALSE;
+ PVOID Cb;
+
+ if (usHandleType == LINKHANDLE) {
+
+ LINKCB_FROM_LINKH((PLINKCB)Cb, hHandle);
+
+ } else if (usHandleType == BUNDLEHANDLE) {
+
+ BUNDLECB_FROM_BUNDLEH((PBUNDLECB)Cb, hHandle);
+
+ }
+
+ if (Cb != NULL) {
+ RetValue = TRUE;
+ }
+
+ return (RetValue);
+}
+
+
+#if DBG // Debug
+
+PUCHAR
+NdisWanGetNdisStatus(
+ NDIS_STATUS GeneralStatus
+ )
+/*++
+
+Routine Name:
+
+ NdisWanGetNdisStatus
+
+Routine Description:
+
+ This routine returns a pointer to the string describing the NDIS error
+ denoted by GeneralStatus
+
+Arguments:
+
+ GeneralStatus - The NDIS status you wish to make readable
+
+Return Values:
+
+ Returns a pointer to a string describing GeneralStatus
+
+--*/
+{
+ static NDIS_STATUS Status[] = {
+ NDIS_STATUS_SUCCESS,
+ NDIS_STATUS_PENDING,
+
+ NDIS_STATUS_ADAPTER_NOT_FOUND,
+ NDIS_STATUS_ADAPTER_NOT_OPEN,
+ NDIS_STATUS_ADAPTER_NOT_READY,
+ NDIS_STATUS_ADAPTER_REMOVED,
+ NDIS_STATUS_BAD_CHARACTERISTICS,
+ NDIS_STATUS_BAD_VERSION,
+ NDIS_STATUS_CLOSING,
+ NDIS_STATUS_DEVICE_FAILED,
+ NDIS_STATUS_FAILURE,
+ NDIS_STATUS_INVALID_DATA,
+ NDIS_STATUS_INVALID_LENGTH,
+ NDIS_STATUS_INVALID_OID,
+ NDIS_STATUS_INVALID_PACKET,
+ NDIS_STATUS_MULTICAST_FULL,
+ NDIS_STATUS_NOT_INDICATING,
+ NDIS_STATUS_NOT_RECOGNIZED,
+ NDIS_STATUS_NOT_RESETTABLE,
+ NDIS_STATUS_NOT_SUPPORTED,
+ NDIS_STATUS_OPEN_FAILED,
+ NDIS_STATUS_OPEN_LIST_FULL,
+ NDIS_STATUS_REQUEST_ABORTED,
+ NDIS_STATUS_RESET_IN_PROGRESS,
+ NDIS_STATUS_RESOURCES,
+ NDIS_STATUS_UNSUPPORTED_MEDIA
+ };
+ static PUCHAR String[] = {
+ "SUCCESS",
+ "PENDING",
+
+ "ADAPTER_NOT_FOUND",
+ "ADAPTER_NOT_OPEN",
+ "ADAPTER_NOT_READY",
+ "ADAPTER_REMOVED",
+ "BAD_CHARACTERISTICS",
+ "BAD_VERSION",
+ "CLOSING",
+ "DEVICE_FAILED",
+ "FAILURE",
+ "INVALID_DATA",
+ "INVALID_LENGTH",
+ "INVALID_OID",
+ "INVALID_PACKET",
+ "MULTICAST_FULL",
+ "NOT_INDICATING",
+ "NOT_RECOGNIZED",
+ "NOT_RESETTABLE",
+ "NOT_SUPPORTED",
+ "OPEN_FAILED",
+ "OPEN_LIST_FULL",
+ "REQUEST_ABORTED",
+ "RESET_IN_PROGRESS",
+ "RESOURCES",
+ "UNSUPPORTED_MEDIA"
+ };
+
+ static UCHAR BadStatus[] = "UNDEFINED";
+#define StatusCount (sizeof(Status)/sizeof(NDIS_STATUS))
+ INT i;
+
+ for (i=0; i<StatusCount; i++)
+ if (GeneralStatus == Status[i])
+ return String[i];
+ return BadStatus;
+#undef StatusCount
+}
+#endif // End Debug
+
+
diff --git a/private/ntos/ndis/ndiswan/ndiswan.rc b/private/ntos/ndis/ndiswan/ndiswan.rc
new file mode 100644
index 000000000..902eca593
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/ndiswan.rc
@@ -0,0 +1,43 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "MS WAN Wrapper Network Driver"
+#define VER_INTERNALNAME_STR "NDISWAN.SYS"
+
+#define EXPORT_CONTROLLED
+
+#ifndef ENCRYPT_128BIT
+#define EXPORT
+#endif
+
+#include "common.ver"
diff --git a/private/ntos/ndis/ndiswan/protocol.c b/private/ntos/ndis/ndiswan/protocol.c
new file mode 100644
index 000000000..c67bad125
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/protocol.c
@@ -0,0 +1,723 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ Protocol.c
+
+Abstract:
+
+ This file contains the procedures that makeup most of the NDIS 3.1
+ Protocol interface. This interface is what NdisWan exposes to the
+ WAN Miniports below. NdisWan is not really a protocol and does not
+ do TDI, but is a shim that sits between the protocols and the
+ WAN Miniport drivers.
+
+
+Author:
+
+ Tony Bell (TonyBe) June 06, 1995
+
+Environment:
+
+ Kernel Mode
+
+Revision History:
+
+ TonyBe 06/06/95 Created
+
+--*/
+
+#include "wan.h"
+
+EXPORT
+VOID
+NdisTapiIndicateStatus(
+ IN NDIS_HANDLE BindingContext,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferLength
+);
+
+NDIS_STATUS
+DoLineUpWork(
+ IN PPROTOCOLCB ProtocolCB
+ );
+
+NDIS_STATUS
+DoLineDownWork(
+ PPROTOCOLCB ProtocolCB
+ );
+
+NDIS_STATUS
+NdisWanOpenWanAdapter(
+ IN PWAN_ADAPTERCB pWanAdapterCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NDIS_STATUS Status, OpenErrorStatus;
+ ULONG SelectedMediumIndex;
+ NDIS_MEDIUM MediumArray[] = {NdisMediumWan};
+
+ NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanOpenAdapter: Enter - AdapterName %ls", pWanAdapterCB->MiniportName.Buffer));
+
+ //
+ // This is the only initialization of this event
+ //
+ NdisWanInitializeNotificationEvent(&pWanAdapterCB->NotificationEvent);
+
+ NdisOpenAdapter(&Status,
+ &OpenErrorStatus,
+ &(pWanAdapterCB->hNdisBindingHandle),
+ &SelectedMediumIndex,
+ MediumArray,
+ sizeof(MediumArray) / sizeof(NDIS_MEDIUM),
+ NdisWanCB.hProtocolHandle,
+ (NDIS_HANDLE)pWanAdapterCB,
+ &(pWanAdapterCB->MiniportName),
+ 0,
+ NULL);
+
+ if (Status == NDIS_STATUS_PENDING) {
+
+ NdisWanWaitForNotificationEvent(&pWanAdapterCB->NotificationEvent);
+
+ Status = pWanAdapterCB->NotificationStatus;
+
+ NdisWanClearNotificationEvent(&pWanAdapterCB->NotificationEvent);
+ }
+
+ //
+ // Medium type must be WAN!
+ //
+ pWanAdapterCB->MediumType = NdisMediumWan;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanOpenAdapter: Exit"));
+
+ return (Status);
+}
+
+VOID
+NdisWanOpenAdapterComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status,
+ IN NDIS_STATUS OpenErrorStatus
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PWAN_ADAPTERCB pWanAdapterCB = (PWAN_ADAPTERCB)ProtocolBindingContext;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanOpenAdapterComplete: Enter - WanAdapterCB 0x%4.4x", pWanAdapterCB));
+
+ pWanAdapterCB->NotificationStatus = Status;
+
+ NdisWanSetNotificationEvent(&pWanAdapterCB->NotificationEvent);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanOpenAdapterComplete: Exit"));
+}
+
+VOID
+NdisWanCloseAdapterComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PWAN_ADAPTERCB pWanAdapterCB = (PWAN_ADAPTERCB)ProtocolBindingContext;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanCloseAdapterComplete: Enter"));
+ NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("WanAdapterCB 0x%4.4x", pWanAdapterCB));
+
+ pWanAdapterCB->NotificationStatus = Status;
+
+ NdisWanSetNotificationEvent(&pWanAdapterCB->NotificationEvent);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanCloseAdapterComplete: Exit"));
+}
+
+VOID
+NdisWanResetComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanResetComplete: Enter"));
+
+ NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanResetComplete: Exit"));
+}
+
+
+
+VOID
+NdisWanTransferDataComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET pNdisPacket,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanTransferDataComplete: Enter"));
+
+ NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanTransferDataComplete: Exit"));
+}
+
+VOID
+NdisWanRequestComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PWAN_ADAPTERCB pWanAdapterCB = (PWAN_ADAPTERCB)ProtocolBindingContext;
+ PWAN_REQUEST pWanRequest = GetWanRequest(pWanAdapterCB, NdisRequest);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanRequestComplete: Enter - pWanRequest: 0x%8.8x", pWanRequest));
+
+ pWanRequest->NotificationStatus = Status;
+
+ switch (pWanRequest->Origin) {
+ case NDISTAPI:
+ NdisWanTapiRequestComplete(pWanAdapterCB, pWanRequest);
+ break;
+
+ default:
+ NdisWanSetNotificationEvent(&pWanRequest->NotificationEvent);
+ break;
+
+ }
+
+ NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanRequestComplete: Exit"));
+}
+
+VOID
+NdisWanIndicateStatus(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PWAN_ADAPTERCB pWanAdapterCB = (PWAN_ADAPTERCB)ProtocolBindingContext;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanIndicateStatus: Enter"));
+
+ switch (GeneralStatus) {
+ case NDIS_STATUS_WAN_LINE_UP:
+ NdisWanLineUpIndication(pWanAdapterCB,
+ StatusBuffer,
+ StatusBufferSize);
+ break;
+
+ case NDIS_STATUS_WAN_LINE_DOWN:
+ NdisWanLineDownIndication(pWanAdapterCB,
+ StatusBuffer,
+ StatusBufferSize);
+ break;
+
+ case NDIS_STATUS_WAN_FRAGMENT:
+ NdisWanFragmentIndication(pWanAdapterCB,
+ StatusBuffer,
+ StatusBufferSize);
+ break;
+
+ case NDIS_STATUS_TAPI_INDICATION:
+ NdisWanTapiIndication(pWanAdapterCB,
+ StatusBuffer,
+ StatusBufferSize);
+
+ break;
+
+ default:
+ NdisWanDbgOut(DBG_INFO, DBG_PROTOCOL, ("Unknown Status Indication: 0x%8.8x", GeneralStatus));
+ break;
+ }
+
+ NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanIndicateStatus: Exit"));
+}
+
+VOID
+NdisWanIndicateStatusComplete(
+ IN NDIS_HANDLE BindingContext
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanIndicateStatusComplete: Enter"));
+
+ NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanIndicateStatusComplete: Exit"));
+}
+
+NDIS_STATUS
+DoNewLineUpToProtocol(
+ PPROTOCOLCB ProtocolCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PADAPTERCB AdapterCB;
+ NDIS_STATUS Status = STATUS_SUCCESS;
+ PBUNDLECB BundleCB = ProtocolCB->BundleCB;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("DoNewLineupToProtocol: Enter"));
+
+ //
+ // Find the adapter that this lineup is for
+ //
+ NdisAcquireSpinLock(&AdapterCBList.Lock);
+
+ for (AdapterCB = (PADAPTERCB)AdapterCBList.List.Flink;
+ (PVOID)AdapterCB != (PVOID)&AdapterCBList.List;
+ AdapterCB = (PADAPTERCB)AdapterCB->Linkage.Flink) {
+
+ if (NdisWanCompareNdisString(&AdapterCB->AdapterName,
+ &ProtocolCB->BindingName)) {
+ break;
+
+ }
+ }
+
+ NdisReleaseSpinLock(&AdapterCBList.Lock);
+
+ if ((PVOID)AdapterCB != (PVOID)&AdapterCBList.List) {
+
+ ASSERT(AdapterCB->ProtocolType == ProtocolCB->usProtocolType);
+
+ ETH_COPY_NETWORK_ADDRESS(ProtocolCB->NdisWanAddress, AdapterCB->NetworkAddress);
+
+ //
+ // Put the protocol index in place
+ //
+ FillNdisWanProtocolIndex(ProtocolCB->NdisWanAddress, ProtocolCB->hProtocolHandle);
+
+ //
+ // Put the bundle index in place
+ //
+ FillNdisWanBundleIndex(ProtocolCB->NdisWanAddress, BundleCB->hBundleHandle);
+
+ NdisZeroMemory(ProtocolCB->TransportAddress, 6);
+ FillTransportBundleIndex(ProtocolCB->TransportAddress, BundleCB->hBundleHandle);
+
+ ProtocolCB->AdapterCB = AdapterCB;
+
+ Status = DoLineUpToProtocol(ProtocolCB);
+
+ } else {
+ Status = NDISWAN_ERROR_NO_ROUTE;
+ NdisWanDbgOut(DBG_FAILURE, DBG_PROTOCOL, ("Adapter not found!"));
+ }
+
+ NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("DoNewLineupToProtocols: Exit"));
+
+ return (Status);
+}
+
+NDIS_STATUS
+DoLineUpToProtocol(
+ IN PPROTOCOLCB ProtocolCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NDIS_STATUS Status;
+ PDEFERRED_DESC DeferredDesc;
+ PADAPTERCB AdapterCB = ProtocolCB->AdapterCB;
+
+#if TRY_IMMEDIATE_LINEUP
+ if (NdisWanAcquireMiniportLock(AdapterCB)) {
+
+ NdisAcquireSpinLock(&AdapterCB->Lock);
+
+ if (IsDeferredQueueEmpty(&AdapterCB->DeferredQueue[StatusIndication])) {
+
+ NdisReleaseSpinLock(&AdapterCB->Lock);
+
+ Status = DoLineUpWork(ProtocolCB);
+
+ NdisWanReleaseMiniportLock(AdapterCB);
+
+ return (Status);
+ }
+
+ NdisReleaseSpinLock(&AdapterCB->Lock);
+
+ NdisWanReleaseMiniportLock(AdapterCB);
+ }
+#endif
+
+ NdisAcquireSpinLock(&AdapterCB->Lock);
+
+ //
+ // Queue up a deferred work item
+ //
+ NdisWanGetDeferredDesc(AdapterCB, &DeferredDesc);
+
+ DeferredDesc->Context = ProtocolCB;
+ DeferredDesc->Type = LineUp;
+
+ InsertTailDeferredQueue(&AdapterCB->DeferredQueue[StatusIndication],
+ DeferredDesc);
+
+ NdisWanSetDeferred(AdapterCB);
+
+ NdisReleaseSpinLock(&AdapterCB->Lock);
+
+ Status = NDIS_STATUS_PENDING;
+
+ return (Status);
+}
+
+NDIS_STATUS
+DoLineUpWork(
+ PPROTOCOLCB ProtocolCB
+ )
+{
+ ULONG i, AllocationSize;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PNDIS_WAN_LINE_UP LineUpInfo;
+ PADAPTERCB AdapterCB = ProtocolCB->AdapterCB;
+ PBUNDLECB BundleCB = ProtocolCB->BundleCB;
+ PBUNDLE_LINE_UP BundleLineUpInfo = &BundleCB->LineUpInfo;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("DoLineupToProtocol: Enter"));
+
+ ASSERT(AdapterCB != NULL);
+
+ AllocationSize = sizeof(NDIS_WAN_LINE_UP) +
+ ProtocolCB->ulLineUpInfoLength +
+ (sizeof(WCHAR) * (MAX_NAME_LENGTH + 1) +
+ (2 * sizeof(PVOID)));
+
+ NdisWanAllocateMemory(&LineUpInfo, AllocationSize);
+
+ if (LineUpInfo != NULL) {
+ NDIS_HANDLE LineUpHandle = ProtocolCB->hTransportHandle;
+
+ //
+ // Fill values that are common to all protocols on this bundle
+ //
+ LineUpInfo->LinkSpeed = BundleLineUpInfo->BundleSpeed;
+ LineUpInfo->MaximumTotalSize = BundleLineUpInfo->ulMaximumTotalSize;
+ LineUpInfo->Quality = BundleLineUpInfo->Quality;
+ LineUpInfo->SendWindow = BundleLineUpInfo->usSendWindow;
+ LineUpInfo->ProtocolType = ProtocolCB->usProtocolType;
+ LineUpInfo->DeviceName.Length = 0;
+ LineUpInfo->DeviceName.MaximumLength = MAX_NAME_LENGTH + 1;
+ LineUpInfo->DeviceName.Buffer = (PWCHAR)((PUCHAR)LineUpInfo +
+ sizeof(NDIS_WAN_LINE_UP));
+ (ULONG)LineUpInfo->DeviceName.Buffer &= (ULONG)~(sizeof(PVOID) - 1);
+
+ LineUpInfo->ProtocolBuffer = (PUCHAR)LineUpInfo +
+ sizeof(NDIS_WAN_LINE_UP) +
+ (sizeof(WCHAR) * (MAX_NAME_LENGTH + 1) +
+ sizeof(PVOID));
+ (ULONG)LineUpInfo->ProtocolBuffer &= (ULONG)~(sizeof(PVOID) - 1);
+
+ //
+ // The Local address(SRC address in a send), is used
+ // to figure out what bundle to send across if the
+ // DEST address is a multicast. We use the two high
+ // order bytes of the address. The transport uses the
+ // other four bytes for a context on receive.
+ //
+ //
+ // The Remote address (DEST address in a send) is what we use to
+ // mutilplex sends across our single adapter/binding context.
+ // The address has the following format:
+ //
+ // XX XX XX YY YY ZZ
+ //
+ // XX = Randomly generated OUI
+ // YY = Index into the active bundle connection table to get bundlecb
+ // ZZ = Index into the protocol table of a bundle to get protocolcb
+ //
+ ETH_COPY_NETWORK_ADDRESS(LineUpInfo->RemoteAddress,ProtocolCB->NdisWanAddress);
+ ETH_COPY_NETWORK_ADDRESS(LineUpInfo->LocalAddress,ProtocolCB->TransportAddress);
+
+ //
+ // Fill in the protocol specific information
+ //
+ LineUpInfo->ProtocolBufferLength = ProtocolCB->ulLineUpInfoLength;
+ NdisMoveMemory(LineUpInfo->ProtocolBuffer,
+ ProtocolCB->LineUpInfo,
+ ProtocolCB->ulLineUpInfoLength);
+
+ //
+ // Do the line up indication
+ //
+ NdisMIndicateStatus(AdapterCB->hMiniportHandle,
+ NDIS_STATUS_WAN_LINE_UP,
+ LineUpInfo,
+ AllocationSize);
+
+ *((ULONG UNALIGNED *)(&LineUpHandle)) = *((ULONG UNALIGNED *)(&LineUpInfo->LocalAddress[2]));
+
+ //
+ // If this was the first line up for this protocolcb and
+ // this lineup was answered we need to collect some info
+ //
+ if (ProtocolCB->hTransportHandle == NULL) {
+
+ if (LineUpHandle != NULL) {
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ ETH_COPY_NETWORK_ADDRESS(ProtocolCB->TransportAddress, LineUpInfo->LocalAddress);
+
+ ProtocolCB->hTransportHandle = LineUpHandle;
+
+ if (LineUpInfo->DeviceName.Length != 0) {
+ NdisWanStringToNdisString(&ProtocolCB->DeviceName,
+ LineUpInfo->DeviceName.Buffer);
+ }
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ //
+ // If this is an nbf adapter
+ //
+ if (ProtocolCB->usProtocolType == PROTOCOL_NBF) {
+
+ ASSERT(AdapterCB->ProtocolType == PROTOCOL_NBF);
+
+ AdapterCB->NbfBundleCB = BundleCB;
+ AdapterCB->NbfProtocolHandle = ProtocolCB->hProtocolHandle;
+ }
+
+ } else {
+ Status = NDISWAN_ERROR_NO_ROUTE;
+ }
+ }
+
+ NdisWanFreeMemory(LineUpInfo);
+
+ } else {
+
+ Status = NDIS_STATUS_RESOURCES;
+ }
+
+ NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("DoLineupToProtocol: Exit"));
+
+ return (Status);
+}
+
+NDIS_STATUS
+DoLineDownToProtocol(
+ PPROTOCOLCB ProtocolCB
+ )
+{
+ PADAPTERCB AdapterCB = ProtocolCB->AdapterCB;
+ PDEFERRED_DESC DeferredDesc;
+
+//
+// We are always going to defer the line down. This will
+// allow us to complete all sends and process all loopbacks
+// before doing the linedown.
+//
+ NdisAcquireSpinLock(&AdapterCB->Lock);
+
+ //
+ // Queue up a deferred work item
+ //
+ NdisWanGetDeferredDesc(AdapterCB, &DeferredDesc);
+
+ DeferredDesc->Context = ProtocolCB;
+ DeferredDesc->Type = LineDown;
+
+ InsertTailDeferredQueue(&AdapterCB->DeferredQueue[StatusIndication],
+ DeferredDesc);
+
+ NdisWanSetDeferred(AdapterCB);
+
+ NdisReleaseSpinLock(&AdapterCB->Lock);
+
+ return (NDIS_STATUS_PENDING);
+}
+
+NDIS_STATUS
+DoLineDownWork(
+ PPROTOCOLCB ProtocolCB
+ )
+{
+ NDIS_WAN_LINE_DOWN WanLineDown;
+ PNDIS_WAN_LINE_DOWN LineDownInfo = &WanLineDown;
+ PADAPTERCB AdapterCB = ProtocolCB->AdapterCB;
+
+ //
+ // The Remote address (DEST address) is what we use to mutilplex
+ // sends across our single adapter/binding context. The address
+ // has the following format:
+ //
+ // XX XX XX YY YY ZZ
+ //
+ // XX = Randomly generated OUI
+ // YY = Index into the active bundle connection table to get bundlecb
+ // ZZ = Index into the protocol table of a bundle to get protocolcb
+ //
+ ETH_COPY_NETWORK_ADDRESS(LineDownInfo->RemoteAddress, ProtocolCB->NdisWanAddress);
+ ETH_COPY_NETWORK_ADDRESS(LineDownInfo->LocalAddress, ProtocolCB->TransportAddress);
+
+ //
+ // If this is an nbf adapter
+ //
+ if (ProtocolCB->usProtocolType == PROTOCOL_NBF) {
+
+ ASSERT(AdapterCB->ProtocolType == PROTOCOL_NBF);
+
+ AdapterCB->NbfBundleCB = NULL;
+
+ (ULONG)AdapterCB->NbfProtocolHandle = MAX_PROTOCOLS + 1;
+ }
+
+ ProtocolCB->hTransportHandle = NULL;
+
+ NdisMIndicateStatus(AdapterCB->hMiniportHandle,
+ NDIS_STATUS_WAN_LINE_DOWN,
+ LineDownInfo,
+ sizeof(NDIS_WAN_LINE_DOWN));
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+VOID
+NdisWanProcessStatusIndications(
+ PADAPTERCB AdapterCB
+ )
+{
+ NDIS_STATUS Status;
+
+ while (!IsDeferredQueueEmpty(&AdapterCB->DeferredQueue[StatusIndication])) {
+ PPROTOCOLCB ProtocolCB;
+ PBUNDLECB BundleCB;
+ ULONG DescType;
+ PDEFERRED_DESC ReturnDesc;
+
+ ReturnDesc = RemoveHeadDeferredQueue(&AdapterCB->DeferredQueue[StatusIndication]);
+
+ NdisReleaseSpinLock(&AdapterCB->Lock);
+
+ ProtocolCB = ReturnDesc->Context;
+ BundleCB= ProtocolCB->BundleCB;
+ DescType = ReturnDesc->Type;
+
+ ASSERT((DescType == LineUp) || (DescType == LineDown));
+
+ if (DescType == LineUp) {
+ Status = DoLineUpWork(ProtocolCB);
+ }else {
+ Status = DoLineDownWork(ProtocolCB);
+ }
+
+ NdisAcquireSpinLock(&AdapterCB->Lock);
+
+ InsertHeadDeferredQueue(&AdapterCB->FreeDeferredQueue, ReturnDesc);
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ BundleCB->IndicationStatus = Status;
+
+ NdisWanSetSyncEvent(&BundleCB->IndicationEvent);
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+ }
+}
diff --git a/private/ntos/ndis/ndiswan/receive.c b/private/ntos/ndis/ndiswan/receive.c
new file mode 100644
index 000000000..35652e39c
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/receive.c
@@ -0,0 +1,2865 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ Receive.c
+
+Abstract:
+
+ This file contains the procedures for handling a receive indication from
+ a Wan Miniport link, bound to the lower interface of NdisWan, and passing
+ the data on to a protocol, bound to the upper interface of NdisWan. The
+ upper interface of NdisWan conforms to the NDIS 3.1 Miniport specification.
+ The lower interface of NdisWan conforms to the NDIS 3.1 Extentions for
+ Wan Miniport drivers.
+
+Author:
+
+ Tony Bell (TonyBe) June 06, 1995
+
+Environment:
+
+ Kernel Mode
+
+Revision History:
+
+ TonyBe 06/06/95 Created
+
+--*/
+
+#include "wan.h"
+#include "tcpip.h"
+#include "vjslip.h"
+#include "compress.h"
+#include "isnipx.h"
+#include "nbfconst.h"
+#include "nbfhdrs.h"
+#include <rc4.h>
+
+VOID
+DoMultilinkProcessing(
+ PBUNDLECB BundleCB,
+ PRECV_DESC RecvDesc
+ );
+
+VOID
+UpdateMinRecvSeqNumber(
+ PBUNDLECB BundleCB
+ );
+
+VOID
+TryToAssembleFrame(
+ PBUNDLECB BundleCB
+ );
+
+VOID
+ProcessFrame(
+ PBUNDLECB BundleCB,
+ PRECV_DESC RecvDesc
+ );
+
+VOID
+QueueDeferredReceive(
+ PADAPTERCB AdapterCB,
+ PRECV_DESC RecvDesc
+ );
+
+BOOLEAN
+DoVJDecompression(
+ PBUNDLECB BundleCB,
+ USHORT ProtocolID,
+ PUCHAR *DataPointer,
+ PULONG DataLength,
+ PUCHAR Header,
+ PULONG HeaderLength
+ );
+
+BOOLEAN
+DoDecompDecryptProcessing(
+ PBUNDLECB BundleCB,
+ PLINKCB LinkCB,
+ PUCHAR *DataPointer,
+ PULONG DataLength
+ );
+
+VOID
+DoCompressionReset(
+ PBUNDLECB BundleCB
+ );
+
+VOID
+FlushRecvDescWindow(
+ PBUNDLECB BundleCB
+ );
+
+VOID
+NdisWanReturnRecvDesc(
+ PBUNDLECB BundleCB,
+ PRECV_DESC RecvDesc
+ );
+
+VOID
+FindHoleInRecvList(
+ PBUNDLECB BundleCB,
+ PRECV_DESC RecvDesc
+ );
+
+VOID
+NdisWanCopyFromBufferToPacket(
+ PUCHAR Buffer,
+ ULONG BytesToCopy,
+ PNDIS_PACKET NdisPacket,
+ ULONG PacketOffset,
+ PULONG BytesCopied
+ );
+
+#if 0
+ULONG
+CalculatePPPHeaderLength(
+ PLINKCB LinkCB
+ );
+#endif
+
+VOID
+QueuePromiscuousReceive(
+ PRECV_DESC RecvDesc
+ );
+
+#ifdef NT
+
+VOID
+CompleteIoRecvPacket(
+ PBUNDLECB BundleCB,
+ PLINKCB LinkCB,
+ USHORT PPPProtocolID,
+ PRECV_DESC RecvDesc
+ );
+
+#endif
+
+NDIS_STATUS
+NdisWanReceiveIndication(
+ NDIS_HANDLE NdisLinkContext,
+ PUCHAR Packet,
+ ULONG PacketSize
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PLINKCB LinkCB;
+ PBUNDLECB BundleCB;
+ PRECV_DESC RecvDesc;
+ PUCHAR FramePointer;
+ ULONG FrameLength;
+ ULONG LinkFraming;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("NdisWanReceiveIndication: Enter"));
+
+ LINKCB_FROM_LINKH(LinkCB, NdisLinkContext);
+
+ if (LinkCB == NULL) {
+ return (NDIS_STATUS_SUCCESS);
+ }
+
+ BundleCB = LinkCB->BundleCB;
+
+ if (BundleCB == NULL) {
+ return (NDIS_STATUS_SUCCESS);
+ }
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ if (LinkCB->State != LINK_UP ||
+ BundleCB->State != BUNDLE_UP) {
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+ return (NDIS_STATUS_SUCCESS);
+ }
+
+ //
+ // We need to get a descriptor to copy data into
+ //
+ NdisWanGetRecvDesc(BundleCB, &RecvDesc);
+
+ if (RecvDesc == NULL) {
+ NdisReleaseSpinLock(&BundleCB->Lock);
+ return (NDIS_STATUS_SUCCESS);
+ }
+
+ //
+ // Copy the data
+ //
+ NdisMoveMemory(RecvDesc->StartBuffer, Packet, PacketSize);
+ FramePointer = RecvDesc->CurrentBuffer = RecvDesc->StartBuffer;
+ FrameLength = RecvDesc->CurrentBufferLength = PacketSize;
+ RecvDesc->LinkCB = LinkCB;
+
+ //
+ // Add up the statistics
+ //
+ LinkCB->LinkStats.BytesReceived += PacketSize;
+ LinkCB->LinkStats.FramesReceived++;
+ BundleCB->BundleStats.BytesReceived += PacketSize;
+
+ //
+ // If we are in framing detect mode figure it out
+ //
+ if ((LinkFraming = LinkCB->LinkInfo.RecvFramingBits) == 0x00) {
+
+ if (*FramePointer == 0xFF && *(FramePointer + 1) == 0x03) {
+ LinkFraming =
+ LinkCB->LinkInfo.RecvFramingBits =
+ LinkCB->LinkInfo.SendFramingBits = PPP_FRAMING;
+ } else {
+ LinkFraming =
+ LinkCB->LinkInfo.RecvFramingBits =
+ LinkCB->LinkInfo.SendFramingBits = RAS_FRAMING;
+ }
+ }
+
+ if (BundleCB->FramingInfo.RecvFramingBits == 0x00) {
+ if (*FramePointer == 0xFF && *(FramePointer + 1) == 0x03) {
+ BundleCB->FramingInfo.RecvFramingBits =
+ BundleCB->FramingInfo.SendFramingBits = PPP_FRAMING;
+ } else {
+ BundleCB->FramingInfo.RecvFramingBits =
+ BundleCB->FramingInfo.SendFramingBits = RAS_FRAMING;
+ }
+ }
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+#if 0
+ if (FrameLength < CalculatePPPHeaderLength(LinkCB)) {
+
+ NdisWanDbgOut(DBG_FAILURE, DBG_RECEIVE, ("Receive buffer to small! %d", PacketSize));
+
+ return (NDIS_STATUS_SUCCESS);
+ }
+#endif
+
+ //
+ // If this is a PPP frame we will remove the link specific
+ // header information and check for multilink.
+ //
+ if (LinkFraming & PPP_FRAMING) {
+
+ //
+ // Remove the address/control part of the PPP header
+ //
+ if (*FramePointer == 0xFF) {
+ FramePointer += 2;
+ FrameLength -= 2;
+ }
+
+ //
+ // If multilink framing is set and this is a multilink frame
+ // send to the multilink processor!
+ //
+ if ((LinkFraming & PPP_MULTILINK_FRAMING) &&
+ ((*FramePointer == 0x3D) ||
+ (*FramePointer == 0x00) && (*(FramePointer + 1) == 0x3D)) ) {
+
+ //
+ // Remove multilink protocol id
+ //
+ if (*FramePointer & 1) {
+ FramePointer++;
+ FrameLength--;
+ } else {
+ FramePointer += 2;
+ FrameLength -= 2;
+ }
+
+ RecvDesc->CurrentBufferLength = FrameLength;
+ RecvDesc->CurrentBuffer = FramePointer;
+
+ DoMultilinkProcessing(BundleCB, RecvDesc);
+
+ return (NDIS_STATUS_SUCCESS);
+
+ } // end of PPP_MULTILINK_FRAMING
+
+ } // end of PPP_FRAMING
+
+ //
+ // Send the frame on for further processing!
+ //
+ RecvDesc->CurrentBufferLength = FrameLength;
+ RecvDesc->CurrentBuffer = FramePointer;
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+ ASSERT(!(BundleCB->Flags & IN_RECEIVE));
+ BundleCB->Flags |= IN_RECEIVE;
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ ProcessFrame(BundleCB, RecvDesc);
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+ BundleCB->Flags &= ~IN_RECEIVE;
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("NdisWanReceiveIndication: Exit"));
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+VOID
+DoMultilinkProcessing(
+ PBUNDLECB BundleCB,
+ PRECV_DESC RecvDesc
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+ *DataPointer - Points to a pointer that points to a data block that
+ should have one of the following formats:
+
+ 0 1 2 3 4 5 6 7 8 9 1 1 1 1 1 1
+ 0 1 2 3 4 5
+ +-+-+-+-+------------------------+
+ Short Sequence Number |B|E|0|0| Sequence Number |
+ +-+-+-+-+------------------------+
+ | Data |
+ +--------------------------------+
+
+ +-+-+-+-+-+-+-+-+----------------+
+ Long Sequence Number |B|E|0|0|0|0|0|0|Sequence Number |
+ +-+-+-+-+-+-+-+-+----------------+
+ | Sequence Number |
+ +--------------------------------+
+ | Data |
+ +--------------------------------+
+
+Return Values:
+
+--*/
+{
+ BOOLEAN Inserted = FALSE;
+ ULONG BundleFraming;
+ PUCHAR FramePointer = RecvDesc->CurrentBuffer;
+ ULONG FrameLength = RecvDesc->CurrentBufferLength;
+ ULONG SequenceNumber, Flags;
+ PRECV_DESC RecvDescHole;
+ PLINKCB LinkCB = RecvDesc->LinkCB;
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ BundleFraming = BundleCB->FramingInfo.RecvFramingBits;
+ RecvDescHole = BundleCB->RecvDescHole;
+
+ //
+ // Get the flags
+ //
+ Flags = *FramePointer & MULTILINK_FLAG_MASK;
+
+ //
+ // Get the sequence number
+ //
+ if (BundleFraming & PPP_SHORT_SEQUENCE_HDR_FORMAT) {
+ //
+ // Short sequence format
+ //
+ SequenceNumber = ((*FramePointer & 0x0F) << 8) | *(FramePointer + 1);
+
+ FramePointer += 2;
+ FrameLength -= 2;
+
+ } else {
+ //
+ // Long sequence format
+ //
+ SequenceNumber = (*(FramePointer + 1) << 16) |
+ (*(FramePointer + 2) << 8) |
+ *(FramePointer + 3);
+
+ FramePointer += 4;
+ FrameLength -= 4;
+ }
+
+ NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV,
+ ("r %8.8x %8.8x h: %8.8x l: %d",SequenceNumber, Flags, RecvDescHole->SequenceNumber, LinkCB->hLinkHandle));
+
+ //
+ // Is the new recveive sequence number smaller that the last
+ // sequence number received on this link? If so the increasing seq
+ // number rule has been violated and we need to toss this one.
+ //
+ if (SEQ_LT(SequenceNumber,
+ LinkCB->LastRecvSeqNumber,
+ BundleCB->RecvSeqTest)) {
+
+ ASSERT(RecvDesc->RefCount == 1);
+
+ LinkCB->RecvFragmentsLost++;
+ BundleCB->RecvFragmentsLost++;
+
+ NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
+ ("dl s: %8.8x %8.8x lr: %8.8x", SequenceNumber, Flags,
+ LinkCB->LastRecvSeqNumber));
+
+ NdisWanReturnRecvDesc(BundleCB, RecvDesc);
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ return;
+
+ }
+
+ //
+ // Initialize the recv desc
+ //
+ RecvDesc->Flags = Flags;
+ RecvDesc->SequenceNumber =
+ LinkCB->LastRecvSeqNumber = SequenceNumber;
+ RecvDesc->CurrentBufferLength = FrameLength;
+ RecvDesc->CurrentBuffer = FramePointer;
+
+ //
+ // Is the new receive sequence number smaller than the hole? If so
+ // we received a fragment across a slow link after it has been flushed
+ //
+ if (SEQ_LT(SequenceNumber,
+ RecvDescHole->SequenceNumber,
+ BundleCB->RecvSeqTest)) {
+ ASSERT(RecvDesc->RefCount == 1);
+
+ LinkCB->RecvFragmentsLost++;
+ BundleCB->RecvFragmentsLost++;
+
+ NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
+ ("db s: %8.8x %8.8x h: %8.8x", SequenceNumber, Flags,
+ RecvDescHole->SequenceNumber));
+
+ NdisWanReturnRecvDesc(BundleCB, RecvDesc);
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ return;
+ }
+
+ //
+ // If this fills the hole
+ //
+ if (SEQ_EQ(SequenceNumber, RecvDescHole->SequenceNumber)) {
+
+ //
+ // Insert the hole filler in the current holes spot
+ //
+ RecvDesc->Linkage.Blink = (PLIST_ENTRY)RecvDescHole->Linkage.Blink;
+ RecvDesc->Linkage.Flink = (PLIST_ENTRY)RecvDescHole->Linkage.Flink;
+
+ RecvDesc->Linkage.Blink->Flink =
+ RecvDesc->Linkage.Flink->Blink = (PLIST_ENTRY)RecvDesc;
+
+ //
+ // Find the next hole
+ //
+ FindHoleInRecvList(BundleCB, RecvDesc);
+
+ NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV, ("r1"));
+
+ } else {
+
+ PRECV_DESC BeginDesc, EndDesc;
+
+ //
+ // This does not fill a hole so we need to insert it into
+ // the list at the right spot. This spot will be someplace
+ // between the hole and the end of the list.
+ //
+ BeginDesc = RecvDescHole;
+ EndDesc = (PRECV_DESC)BeginDesc->Linkage.Flink;
+
+ while ((PVOID)EndDesc != (PVOID)&BundleCB->RecvDescAssemblyList) {
+
+ //
+ // Calculate the absolute delta between the begining sequence
+ // number and the sequence number we are looking to insert.
+ //
+ ULONG DeltaBegin =
+ ((RecvDesc->SequenceNumber - BeginDesc->SequenceNumber) &
+ BundleCB->RecvSeqMask);
+
+ //
+ // Calculate the absolute delta between the begining sequence
+ // number and the end sequence number.
+ //
+ ULONG DeltaEnd =
+ ((EndDesc->SequenceNumber - BeginDesc->SequenceNumber) &
+ BundleCB->RecvSeqMask);
+
+ //
+ // If the delta from the begin to current is less than
+ // the delta from the end to current it is time to insert
+ //
+ if (DeltaBegin < DeltaEnd) {
+ PLIST_ENTRY Flink, Blink;
+
+ //
+ // Insert the desc
+ //
+ RecvDesc->Linkage.Flink = (PLIST_ENTRY)EndDesc;
+ RecvDesc->Linkage.Blink = (PLIST_ENTRY)BeginDesc;
+ BeginDesc->Linkage.Flink =
+ EndDesc->Linkage.Blink = (PLIST_ENTRY)RecvDesc;
+
+ Inserted = TRUE;
+
+ NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV, ("r2"));
+
+ break;
+
+ } else {
+
+ //
+ // Get next pair of descriptors
+ //
+ BeginDesc = EndDesc;
+ EndDesc = (PRECV_DESC)EndDesc->Linkage.Flink;
+ }
+ }
+
+ if (!Inserted) {
+
+ //
+ // If we are here we have fallen through and we need to
+ // add this at the end of the list
+ //
+ InsertTailList(&BundleCB->RecvDescAssemblyList, &RecvDesc->Linkage);
+
+ NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV, ("r3"));
+ }
+ }
+
+ //
+ // Update the bundles minimum recv sequence number. This is
+ // used to detect lost fragments.
+ //
+ UpdateMinRecvSeqNumber(BundleCB);
+
+ //
+ // Check for lost fragments. If the minimum recv sequence number
+ // over the bundle is greater than the hole sequence number we have
+ // lost a fragment and need to flush the assembly list until we find
+ // the first begin fragment after the hole.
+ //
+ if (SEQ_GT(BundleCB->MinReceivedSeqNumber,
+ RecvDescHole->SequenceNumber,
+ BundleCB->RecvSeqTest)) {
+
+ NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
+ ("min %8.8x > h %8.8x b %8.8x", BundleCB->MinReceivedSeqNumber,
+ RecvDescHole->SequenceNumber, BundleCB));
+
+ //
+ // Flush the recv desc assembly window.
+ //
+ FlushRecvDescWindow(BundleCB);
+
+ }
+
+ //
+ // See if we can complete some frames!!!!
+ //
+ TryToAssembleFrame(BundleCB);
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+}
+
+VOID
+UpdateMinRecvSeqNumber(
+ PBUNDLECB BundleCB
+ )
+{
+ PLINKCB LinkCB = (PLINKCB)BundleCB->LinkCBList.Flink;
+
+ NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV,
+ ("MinReceived c %8.8x", BundleCB->MinReceivedSeqNumber));
+
+ BundleCB->MinReceivedSeqNumber = LinkCB->LastRecvSeqNumber;
+
+ for (LinkCB = (PLINKCB)LinkCB->Linkage.Flink;
+ (PVOID)LinkCB != (PVOID)&BundleCB->LinkCBList;
+ LinkCB = (PLINKCB)LinkCB->Linkage.Flink) {
+
+ if (SEQ_LT(LinkCB->LastRecvSeqNumber,
+ BundleCB->MinReceivedSeqNumber,
+ BundleCB->RecvSeqTest)) {
+ BundleCB->MinReceivedSeqNumber = LinkCB->LastRecvSeqNumber;
+ }
+ }
+
+ NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV,
+ ("MinReceived n %8.8x", BundleCB->MinReceivedSeqNumber));
+}
+
+VOID
+FindHoleInRecvList(
+ PBUNDLECB BundleCB,
+ PRECV_DESC RecvDesc
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+ We want to start at the spot where the current hole was removed
+ from and look for adjoining recv desc's in the list who have
+ sequence numbers that differ by more than 1.
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PRECV_DESC NextRecvDesc, RecvDescHole;
+ ULONG SequenceNumber;
+ PLIST_ENTRY RecvList;
+
+ RecvDescHole = BundleCB->RecvDescHole;
+
+ RecvList = &BundleCB->RecvDescAssemblyList;
+
+ NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV,
+ ("h: %8.8x", RecvDescHole->SequenceNumber));
+
+ if (IsListEmpty(RecvList)) {
+ //
+ // Set the new sequence number
+ //
+ RecvDescHole->SequenceNumber += 1;
+ RecvDescHole->SequenceNumber &= BundleCB->RecvSeqMask;
+
+ //
+ // Put the hole back on the list
+ //
+ InsertHeadList(RecvList, &RecvDescHole->Linkage);
+
+ } else {
+
+ //
+ // Walk the list looking for two descriptors that have
+ // sequence numbers differing by more than 1 or until we
+ // get to the end of the list
+ //
+ NextRecvDesc = (PRECV_DESC)RecvDesc->Linkage.Flink;
+ SequenceNumber = RecvDesc->SequenceNumber;
+
+ while (((PVOID)NextRecvDesc != (PVOID)RecvList) &&
+ (((NextRecvDesc->SequenceNumber - RecvDesc->SequenceNumber) &
+ BundleCB->RecvSeqMask) == 1)) {
+
+ RecvDesc = NextRecvDesc;
+ NextRecvDesc = (PRECV_DESC)RecvDesc->Linkage.Flink;
+ SequenceNumber = RecvDesc->SequenceNumber;
+ }
+
+ RecvDescHole->SequenceNumber = SequenceNumber + 1;
+ RecvDescHole->SequenceNumber &= BundleCB->RecvSeqMask;
+
+ RecvDescHole->Linkage.Flink = (PLIST_ENTRY)NextRecvDesc;
+ RecvDescHole->Linkage.Blink = (PLIST_ENTRY)RecvDesc;
+
+ RecvDesc->Linkage.Flink =
+ NextRecvDesc->Linkage.Blink =
+ (PLIST_ENTRY)RecvDescHole;
+ }
+
+ NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV, ("nh: %8.8x", RecvDescHole->SequenceNumber));
+}
+
+VOID
+NdisWanGetRecvDesc(
+ PBUNDLECB BundleCB,
+ PRECV_DESC *ReturnRecvDesc
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PRECV_DESC RecvDesc = NULL;
+ ULONG i;
+
+ //
+ // Try the local pool first
+ //
+ if (BundleCB != NULL
+ && !IsListEmpty(&BundleCB->RecvDescPool)) {
+
+ RecvDesc = (PRECV_DESC)RemoveHeadList(&BundleCB->RecvDescPool);
+ BundleCB->RecvDescCount--;
+
+ } else {
+
+ //
+ // Since the local pool is empty we will
+ // try to get a desc from the global pool
+ //
+ // MAX_MRRU -> Data packet
+ // 14 -> Ethernet Header
+ // 128 -> Used for VJ header compression
+ // 3 * sizeof(PVOID) -> DWORD alignment
+
+ if (IsListEmpty(&GlobalRecvDescPool.List)) {
+
+ ULONG AllocationSize = sizeof(RECV_DESC) +
+ MAX_MRRU + 14 + 128 + 3 * sizeof(PVOID);
+
+ for (i = 0; i < 10; i++) {
+
+ //
+ // The global list is empty so we need to allocate
+ // some more
+ //
+ NdisWanAllocateMemory(&RecvDesc, AllocationSize);
+
+ if (RecvDesc != NULL) {
+
+ RecvDesc->AllocationSize = AllocationSize;
+
+ RecvDesc->WanHeader = (PUCHAR)RecvDesc + sizeof(RECV_DESC) + sizeof(PVOID);
+ (ULONG)RecvDesc->WanHeader &= (ULONG)~(sizeof(PVOID) - 1);
+
+ RecvDesc->LookAhead = RecvDesc->WanHeader + 14 + sizeof(PVOID);
+ (ULONG)RecvDesc->LookAhead &= (ULONG)~(sizeof(PVOID) - 1);
+
+ RecvDesc->StartBuffer = RecvDesc->LookAhead + 128 + sizeof(PVOID);
+ (ULONG)RecvDesc->StartBuffer &= (ULONG)~(sizeof(PVOID) - 1);
+
+ RecvDesc->CurrentBuffer = RecvDesc->StartBuffer;
+
+ NdisWanInterlockedInsertTailList(&GlobalRecvDescPool.List,
+ &RecvDesc->Linkage,
+ &GlobalRecvDescPool.Lock.SpinLock);
+
+ NdisWanInterlockedInc(&GlobalRecvDescPool.ulCount);
+
+ } else {
+
+ //
+ // Memory allocation failed!
+ //
+ break;
+ }
+ }
+
+ }
+
+ if (!IsListEmpty(&GlobalRecvDescPool.List)) {
+
+ RecvDesc =
+ (PRECV_DESC)NdisWanInterlockedRemoveHeadList(&GlobalRecvDescPool.List,
+ &GlobalRecvDescPool.Lock.SpinLock);
+
+ NdisWanInterlockedDec(&GlobalRecvDescPool.ulCount);
+
+ RecvDesc->BundleCB = BundleCB;
+ }
+
+ }
+
+ if (RecvDesc) {
+ ASSERT(RecvDesc->RefCount == 0);
+ NdisWanInterlockedInc(&RecvDesc->RefCount);
+ }
+
+ *ReturnRecvDesc = RecvDesc;
+}
+
+VOID
+NdisWanReturnRecvDesc(
+ PBUNDLECB BundleCB,
+ PRECV_DESC RecvDesc
+ )
+{
+ if (NdisWanInterlockedDec(&RecvDesc->RefCount) == 0) {
+
+ if (BundleCB->State == BUNDLE_UP &&
+ BundleCB->RecvDescCount < BundleCB->RecvDescMax) {
+ //
+ // Return receive descriptor to bundle list
+ //
+ InsertTailList(&BundleCB->RecvDescPool, &RecvDesc->Linkage);
+ BundleCB->RecvDescCount++;
+
+ } else {
+ //
+ // Return receive descriptor to global list
+ //
+ NdisWanInterlockedInsertTailList(&GlobalRecvDescPool.List,
+ &RecvDesc->Linkage,
+ &GlobalRecvDescPool.Lock.SpinLock);
+ NdisWanInterlockedInc(&GlobalRecvDescPool.ulCount);
+
+ }
+ }
+}
+
+
+VOID
+FlushRecvDescWindow(
+ IN PBUNDLECB BundleCB
+ )
+/*++
+
+Routine Name:
+
+ FlushRecvDescWindow
+
+Routine Description:
+
+ This routine is called to flush recv desc's from the assembly list when
+ a fragment loss is detected. The idea is to flush fragments until we find
+ a begin fragment that has a sequence number >= the minimum received fragment
+ on the bundle.
+
+Arguments:
+
+--*/
+{
+ PRECV_DESC RecvDescHole = BundleCB->RecvDescHole;
+ PRECV_DESC TempDesc;
+ ULONG Flags;
+
+ //
+ // Remove all recvdesc's until we find the hole
+ //
+ while (!IsListEmpty(&BundleCB->RecvDescAssemblyList)) {
+
+ TempDesc = (PRECV_DESC)RemoveHeadList(&BundleCB->RecvDescAssemblyList);
+
+ if (TempDesc == RecvDescHole) {
+ break;
+ }
+
+ BundleCB->RecvFragmentsLost++;
+ TempDesc->LinkCB->RecvFragmentsLost++;
+
+ NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
+ ("flw %8.8x %8.8x h: %8.8x", TempDesc->SequenceNumber,
+ TempDesc->Flags, RecvDescHole->SequenceNumber));
+
+ NdisWanReturnRecvDesc(BundleCB, TempDesc);
+ }
+
+ //
+ // Now flush all recvdesc's until we find a begin fragment that has a
+ // sequence number >= M or the list is empty.
+ //
+ while (!IsListEmpty(&BundleCB->RecvDescAssemblyList)) {
+
+ TempDesc = (PRECV_DESC)BundleCB->RecvDescAssemblyList.Flink;
+ Flags = TempDesc->Flags;
+
+ if (TempDesc->Flags & MULTILINK_BEGIN_FRAME) {
+ break;
+ }
+
+ BundleCB->RecvFragmentsLost++;
+ TempDesc->LinkCB->RecvFragmentsLost++;
+
+ NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
+ ("flw %8.8x %8.8x h: %8.8x", TempDesc->SequenceNumber,
+ TempDesc->Flags, RecvDescHole->SequenceNumber));
+
+ RecvDescHole->SequenceNumber = TempDesc->SequenceNumber;
+
+ RemoveEntryList(&TempDesc->Linkage);
+ NdisWanReturnRecvDesc(BundleCB, TempDesc);
+ TempDesc == NULL;
+ }
+
+ //
+ // Now reinsert the hole desc.
+ //
+ NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
+ ("h: %8.8x", RecvDescHole->SequenceNumber));
+
+ FindHoleInRecvList(BundleCB, TempDesc);
+
+ NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
+ ("nh: %8.8x", RecvDescHole->SequenceNumber));
+}
+
+VOID
+FlushRecvDescAssemblyList(
+ IN PBUNDLECB BundleCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PRECV_DESC RecvDesc;
+
+ while (!IsListEmpty(&BundleCB->RecvDescAssemblyList)) {
+
+ RecvDesc = (PRECV_DESC)RemoveHeadList(&BundleCB->RecvDescAssemblyList);
+
+ NdisWanReturnRecvDesc(BundleCB, RecvDesc);
+ }
+}
+
+VOID
+FreeRecvDescFreeList(
+ IN PBUNDLECB BundleCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PRECV_DESC RecvDesc;
+
+ while (!IsListEmpty(&BundleCB->RecvDescPool)) {
+
+ RecvDesc = (PRECV_DESC)RemoveHeadList(&BundleCB->RecvDescPool);
+
+ NdisWanInterlockedInsertTailList(&GlobalRecvDescPool.List,
+ &RecvDesc->Linkage,
+ &GlobalRecvDescPool.Lock.SpinLock);
+
+ NdisWanInterlockedInc(&GlobalRecvDescPool.ulCount);
+
+ }
+}
+
+VOID
+TryToAssembleFrame(
+ PBUNDLECB BundleCB
+ )
+/*++
+
+Routine Name:
+
+ TryToAssembleFrame
+
+Routine Description:
+
+ The goal here is to walk the recv list looking for a full frame
+ (BeginFlag, EndFlag, no holes in between). If we do not have a
+ full frame we return FALSE.
+
+ If we have a full frame we remove each desc from the assembly list
+ copying the data into the first desc and returning all of the desc's
+ except the first one to the free pool. Once all of the data had been
+ collected we process the frame. After the frame has been processed
+ we return the first desc to the free pool.
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PRECV_DESC RecvDesc, RecvDescHole;
+ ULONG MaxRRecvFrameSize;
+ PUCHAR DataPointer;
+
+ RecvDesc = (PRECV_DESC)BundleCB->RecvDescAssemblyList.Flink;
+ RecvDescHole = BundleCB->RecvDescHole;
+
+ //
+ // If we are already doing some receive processing get out.
+ //
+ if (BundleCB->Flags & IN_RECEIVE) {
+ return;
+ }
+
+TryToAssembleAgain:
+
+ while ((RecvDesc != RecvDescHole) &&
+ (RecvDesc->Flags & MULTILINK_BEGIN_FRAME)) {
+
+ PRECV_DESC NextRecvDesc = (PRECV_DESC)RecvDesc->Linkage.Flink;
+
+ MaxRRecvFrameSize = BundleCB->FramingInfo.MaxRRecvFrameSize;
+
+ DataPointer = RecvDesc->CurrentBuffer + RecvDesc->CurrentBufferLength;
+
+ while ((NextRecvDesc != RecvDescHole) &&
+ !(RecvDesc->Flags & MULTILINK_END_FRAME)) {
+
+ RemoveEntryList(&NextRecvDesc->Linkage);
+
+ ASSERT(NextRecvDesc != RecvDescHole);
+ ASSERT(RecvDesc != RecvDescHole);
+
+ NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV, ("c 0x%8.8x -> 0x%8.8x",
+ NextRecvDesc->SequenceNumber, RecvDesc->SequenceNumber));
+
+ NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV, ("fl 0x%8.8x -> 0x%8.8x",
+ NextRecvDesc->Flags, RecvDesc->Flags));
+
+ NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV, ("l %d -> %d",
+ NextRecvDesc->CurrentBufferLength, RecvDesc->CurrentBufferLength));
+
+ //
+ // Update recvdesc info
+ //
+ RecvDesc->Flags |= NextRecvDesc->Flags;
+ RecvDesc->SequenceNumber = NextRecvDesc->SequenceNumber;
+ RecvDesc->CurrentBufferLength += NextRecvDesc->CurrentBufferLength;
+
+ //
+ // Make sure we don't assemble something too big!
+ //
+ if (RecvDesc->CurrentBufferLength > MaxRRecvFrameSize) {
+
+ NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
+ ("Max receive size exceeded!"));
+
+ //
+ // Return the recv desc's
+ //
+ RemoveEntryList(&RecvDesc->Linkage);
+
+ BundleCB->RecvFragmentsLost += 2;
+ RecvDesc->LinkCB->RecvFragmentsLost += 2;
+
+ NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
+ ("dumping %8.8x %8.8x h: %8.8x", RecvDesc->SequenceNumber,
+ RecvDesc->Flags, RecvDescHole->SequenceNumber));
+
+ NdisWanReturnRecvDesc(BundleCB, RecvDesc);
+
+ NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
+ ("dumping %8.8x %8.8x h: %8.8x", NextRecvDesc->SequenceNumber,
+ NextRecvDesc->Flags, RecvDescHole->SequenceNumber));
+
+ NdisWanReturnRecvDesc(BundleCB, NextRecvDesc);
+
+ //
+ // Start at the list head and flush until we find either the hole
+ // or a new begin fragment.
+ //
+ RecvDesc = (PRECV_DESC)BundleCB->RecvDescAssemblyList.Flink;
+
+ while (RecvDesc != RecvDescHole &&
+ !(RecvDesc->Flags & MULTILINK_BEGIN_FRAME)) {
+
+ RemoveHeadList(&BundleCB->RecvDescAssemblyList);
+
+ BundleCB->RecvFragmentsLost += 1;
+ RecvDesc->LinkCB->RecvFragmentsLost += 1;
+
+ NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
+ ("dumping %8.8x %8.8x h: %8.8x", RecvDesc->SequenceNumber,
+ RecvDesc->Flags, RecvDescHole->SequenceNumber));
+
+ NdisWanReturnRecvDesc(BundleCB, RecvDesc);
+ }
+
+ goto TryToAssembleAgain;
+ }
+
+ NdisMoveMemory(DataPointer,
+ NextRecvDesc->CurrentBuffer,
+ NextRecvDesc->CurrentBufferLength);
+
+ DataPointer += NextRecvDesc->CurrentBufferLength;
+
+ NdisWanReturnRecvDesc(BundleCB, NextRecvDesc);
+
+ NextRecvDesc = (PRECV_DESC)RecvDesc->Linkage.Flink;
+ }
+
+ //
+ // We hit a hole before completion of the frame.
+ // Get out.
+ //
+ if (!IsCompleteFrame(RecvDesc->Flags)) {
+ return;
+ }
+
+ //
+ // If we made it here we must have a begin flag, end flag, and
+ // no hole in between. Let's build a frame.
+ //
+ RecvDesc = (PRECV_DESC)RemoveHeadList(&BundleCB->RecvDescAssemblyList);
+
+ NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV, ("a %8.8x %8.8x", RecvDesc->SequenceNumber, RecvDesc->Flags));
+
+ RecvDesc->LinkCB = NULL;
+
+ BundleCB->Flags |= IN_RECEIVE;
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ ProcessFrame(BundleCB, RecvDesc);
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ BundleCB->Flags &= ~IN_RECEIVE;
+
+ RecvDesc = (PRECV_DESC)BundleCB->RecvDescAssemblyList.Flink;
+
+ } // end of while MULTILINK_BEGIN_FRAME
+}
+
+VOID
+ProcessFrame(
+ PBUNDLECB BundleCB,
+ PRECV_DESC RecvDesc
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PPROTOCOLCB ProtocolCB = NULL;
+ PADAPTERCB AdapterCB;
+ PLINKCB LinkCB;
+ PUCHAR FramePointer;
+ ULONG BundleFraming, FrameLength;
+ PWAN_STATS BundleStats;
+ USHORT PPPProtocolID = 0;
+ ULONG i, LookAheadLength = 0;
+ ULONG TotalLength;
+ PUCHAR WanHeader;
+ PUCHAR LookAhead;
+ NDISWAN_RECV_CONTEXT ReceiveContext;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("ProcessFrame: Enter"));
+
+ //
+ // We do not have an active link or we have a zero
+ // length packet, so drop the receive.
+ //
+ if (BundleCB->State != BUNDLE_UP ||
+ RecvDesc->CurrentBufferLength == 0) {
+ goto PROCESS_FRAME_EXIT;
+ }
+
+ LinkCB = (RecvDesc->LinkCB == NULL) ?
+ (PLINKCB)BundleCB->LinkCBList.Flink : RecvDesc->LinkCB;
+
+ FramePointer = RecvDesc->CurrentBuffer;
+ FrameLength = RecvDesc->CurrentBufferLength;
+ WanHeader = RecvDesc->WanHeader;
+ LookAhead = RecvDesc->LookAhead;
+
+ BundleFraming = BundleCB->FramingInfo.RecvFramingBits;
+ BundleStats = &BundleCB->BundleStats;
+
+ BundleStats->FramesReceived++;
+
+ if (BundleFraming & PPP_FRAMING) {
+
+ //
+ // Get the PPP Protocol id
+ // 0xC1 is SPAP - Shiva hack!
+ //
+ if ((*FramePointer & 1) &&
+ (*FramePointer != 0xC1) &&
+ (*FramePointer != 0xCF)) {
+
+ //
+ // Field is compressed
+ //
+ PPPProtocolID = *FramePointer;
+ FramePointer++;
+ FrameLength--;
+
+ } else {
+
+ //
+ // Field is not compressed
+ //
+ PPPProtocolID = (*FramePointer << 8) | *(FramePointer + 1);
+ FramePointer += 2;
+ FrameLength -= 2;
+
+ }
+
+ //
+ // Is this a compressed frame?
+ //
+ if (PPPProtocolID == PPP_PROTOCOL_COMPRESSION) {
+
+ if (!DoDecompDecryptProcessing(BundleCB,
+ LinkCB,
+ &FramePointer,
+ &FrameLength)){
+
+ goto PROCESS_FRAME_EXIT;
+ }
+
+ //
+ // Get the new PPPProtocolID
+ //
+ if (*FramePointer & 1) {
+
+ //
+ // Field is compressed
+ //
+ PPPProtocolID = *FramePointer;
+ FramePointer++;
+ FrameLength--;
+
+ } else {
+ PPPProtocolID = (*FramePointer << 8) | *(FramePointer + 1);
+ FramePointer += 2;
+ FrameLength -= 2;
+
+ }
+
+ //end of PPP_PROTOCOL_COMPRESSED
+ } else if ((PPPProtocolID == PPP_PROTOCOL_COMP_RESET) &&
+ (*FramePointer == 14)) {
+
+ if (NdisWanCB.PromiscuousAdapter != NULL) {
+ RecvDesc->LookAheadLength = 0;
+ RecvDesc->WanHeader[0] =
+ RecvDesc->WanHeader[6] = ' ';
+ RecvDesc->WanHeader[1] =
+ RecvDesc->WanHeader[7] = 'R';
+ RecvDesc->WanHeader[2] =
+ RecvDesc->WanHeader[8] = 'E';
+ RecvDesc->WanHeader[3] =
+ RecvDesc->WanHeader[9] = 'C';
+ RecvDesc->WanHeader[4] =
+ RecvDesc->WanHeader[10] = 'V';
+ RecvDesc->WanHeader[5] =
+ RecvDesc->WanHeader[11] = (UCHAR)LinkCB->hLinkHandle;
+ RecvDesc->WanHeader[12] = (UCHAR)(PPPProtocolID >> 8);
+ RecvDesc->WanHeader[13] = (UCHAR)PPPProtocolID;
+ RecvDesc->WanHeaderLength = 14;
+ RecvDesc->CurrentBuffer = FramePointer;
+ RecvDesc->CurrentBufferLength = FrameLength;
+
+ //
+ // Queue the packet on the promiscous adapter
+ //
+ QueuePromiscuousReceive(RecvDesc);
+ }
+
+ //
+ // Compression reset!
+ //
+ DoCompressionReset(BundleCB);
+
+ goto PROCESS_FRAME_EXIT;
+
+ } // end of compression reset
+
+ // end of PPP_FRAMING
+ } else {
+
+ if (BundleFraming & RAS_FRAMING) {
+
+ //
+ // Must be RAS framing
+ //
+
+ // For normal NBF frames, first byte is always the DSAP
+ // i.e 0xF0 followed by SSAP 0xF0 or 0xF1
+ //
+ //
+ if (*FramePointer == 14) {
+
+ //
+ // Compression reset!
+ //
+ DoCompressionReset(BundleCB);
+
+ goto PROCESS_FRAME_EXIT;
+ }
+
+ if (*FramePointer == 0xFD) {
+
+ //
+ // Skip over 0xFD
+ //
+ FramePointer++;
+ FrameLength--;
+
+ //
+ // Decompress as if an NBF PPP Packet
+ //
+ if (!DoDecompDecryptProcessing(BundleCB,
+ LinkCB,
+ &FramePointer,
+ &FrameLength)){
+ //
+ // There was an error get out!
+ //
+ goto PROCESS_FRAME_EXIT;
+ }
+ }
+
+ //
+ // Make frame look like an NBF PPP packet
+ //
+ PPPProtocolID = PPP_PROTOCOL_NBF;
+
+ } // end of RAS framing
+
+ } // end of non-ppp framing
+
+ //
+ // If this is slip or if the ProtocolID == PPP_PROTOCOL_COMPRESSED_TCP ||
+ // ProtocolID == PPP_PROTOCOL_UNCOMPRESSED_TCP
+ //
+ if ((BundleFraming & SLIP_FRAMING) ||
+ ((PPPProtocolID == PPP_PROTOCOL_COMPRESSED_TCP) ||
+ (PPPProtocolID == PPP_PROTOCOL_UNCOMPRESSED_TCP))) {
+
+ if (!DoVJDecompression(BundleCB, // Bundle
+ PPPProtocolID, // ProtocolID
+ &FramePointer, // Input buffer
+ &FrameLength, // Input length
+ LookAhead, // Output buffer
+ &LookAheadLength)) {
+
+ goto PROCESS_FRAME_EXIT;
+
+ }
+
+
+ PPPProtocolID = PPP_PROTOCOL_IP;
+
+
+ // end of check for VJ header compression
+ }
+
+ if ((PPPProtocolID >= 0x8000) ||
+ (BundleCB->ulNumberOfRoutes == 1)) {
+
+ RecvDesc->CurrentBufferLength = FrameLength;
+ RecvDesc->CurrentBuffer = FramePointer;
+
+ //
+ // Either this frame is an LCP, NCP or we have no routes yet.
+ // Indicate to PPP engine.
+ //
+ CompleteIoRecvPacket(BundleCB,
+ LinkCB,
+ PPPProtocolID,
+ RecvDesc);
+
+ goto PROCESS_FRAME_EXIT;
+ }
+
+ //
+ // We need to find a protocol to indicate this frame to.
+ //
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ if (BundleCB->State != BUNDLE_UP) {
+ NdisReleaseSpinLock(&BundleCB->Lock);
+ goto PROCESS_FRAME_EXIT;
+ }
+
+ for (i = 1; i < BundleCB->ulNumberOfRoutes; i++) {
+
+ ProtocolCB = BundleCB->ProtocolCBTable[i];
+
+ if (IsValidProtocolCB(ProtocolCB) &&
+ (PPPProtocolID == ProtocolCB->usPPPProtocolID)) {
+ break;
+ }
+ }
+
+ if (!IsValidProtocolCB(ProtocolCB) ||
+ !(ProtocolCB->Flags & PROTOCOL_ROUTED)) {
+ NdisReleaseSpinLock(&BundleCB->Lock);
+ goto PROCESS_FRAME_EXIT;
+ }
+
+ AdapterCB = ProtocolCB->AdapterCB;
+
+ //
+ // We found a valid protocol to indicate this frame to!
+ //
+
+ //
+ // Fill the WanHeader dest address with the transports context
+ //
+ ETH_COPY_NETWORK_ADDRESS(WanHeader, ProtocolCB->TransportAddress);
+
+ if (PPPProtocolID == PPP_PROTOCOL_NBF) {
+
+ //
+ // For nbf fill the length field
+ //
+ WanHeader[12] = (UCHAR)(FrameLength >> 8);
+ WanHeader[13] = (UCHAR)FrameLength;
+
+ if (!(BundleFraming & NBF_PRESERVE_MAC_ADDRESS)) {
+ goto USE_OUR_ADDRESS;
+ }
+
+ //
+ // For nbf and preserve mac address option (SHIVA_FRAMING)
+ // we keep the source address.
+ //
+ ETH_COPY_NETWORK_ADDRESS(&WanHeader[6], FramePointer + 6);
+
+ FramePointer += 12;
+ FrameLength -= 12;
+
+ //
+ // For nbf fill the length field
+ //
+ WanHeader[12] = (UCHAR)(FrameLength >> 8);
+ WanHeader[13] = (UCHAR)FrameLength;
+
+ } else {
+
+ //
+ // For other protocols fill the protocol type
+ //
+ WanHeader[12] = (UCHAR)(ProtocolCB->usProtocolType >> 8);
+ WanHeader[13] = (UCHAR)ProtocolCB->usProtocolType;
+
+ //
+ // Use our address for the src address
+ //
+USE_OUR_ADDRESS:
+ ETH_COPY_NETWORK_ADDRESS(&WanHeader[6], ProtocolCB->NdisWanAddress);
+ }
+
+ ASSERT(WanHeader == RecvDesc->WanHeader);
+ RecvDesc->WanHeaderLength = 14;
+
+ RecvDesc->LookAheadLength = LookAheadLength;
+
+ RecvDesc->CurrentBufferLength = FrameLength;
+ RecvDesc->CurrentBuffer = FramePointer;
+
+ //
+ // Check for non-idle data
+ //
+ if (ProtocolCB->NonIdleDetectFunc != NULL) {
+ PUCHAR HeaderBuffer;
+ ULONG HeaderLength, TotalLength;
+
+ HeaderBuffer = (LookAheadLength != 0) ? LookAhead : FramePointer;
+ HeaderLength = (LookAheadLength != 0) ? LookAheadLength : FrameLength;
+ TotalLength = LookAheadLength + FrameLength;
+
+ if (TRUE == ProtocolCB->NonIdleDetectFunc(HeaderBuffer, HeaderLength, TotalLength)) {
+ NdisWanGetSystemTime(&ProtocolCB->LastRecvNonIdleData);
+ BundleCB->LastRecvNonIdleData = ProtocolCB->LastRecvNonIdleData;
+ }
+ }
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ if ((AdapterCB->ulReferenceCount == 0) &&
+ NdisWanAcquireMiniportLock(AdapterCB)) {
+
+ NdisAcquireSpinLock(&AdapterCB->Lock);
+
+ if (IsDeferredQueueEmpty(&AdapterCB->DeferredQueue[ReceiveIndication])) {
+ AdapterCB->Flags |= RECEIVE_COMPLETE;
+
+ NdisWanSetDeferred(AdapterCB);
+
+ NdisReleaseSpinLock(&AdapterCB->Lock);
+
+ TotalLength = FrameLength + LookAheadLength;
+
+ if (LookAheadLength == 0) {
+ LookAhead = FramePointer;
+ LookAheadLength = FrameLength;
+ }
+
+ ASSERT((LONG)TotalLength > 0);
+
+ if (NdisWanCB.PromiscuousAdapter != NULL) {
+
+ //
+ // Queue the packet on the promiscous adapter
+ //
+ QueuePromiscuousReceive(RecvDesc);
+ }
+
+ //
+ // We got the lock and there are no pending receive
+ // indications so go ahead and indicate the frame to the protocol
+ //
+ NdisMEthIndicateReceive(AdapterCB->hMiniportHandle,
+ RecvDesc,
+ WanHeader,
+ 14,
+ LookAhead,
+ LookAheadLength,
+ TotalLength);
+
+ NdisWanReleaseMiniportLock(AdapterCB);
+
+ goto PROCESS_FRAME_EXIT;
+ }
+
+ NdisReleaseSpinLock(&AdapterCB->Lock);
+
+ NdisWanReleaseMiniportLock(AdapterCB);
+ }
+
+ QueueDeferredReceive(AdapterCB, RecvDesc);
+
+
+PROCESS_FRAME_EXIT:
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ NdisWanReturnRecvDesc(BundleCB, RecvDesc);
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("ProcessFrame: Exit"));
+ return;
+}
+
+VOID
+QueueDeferredReceive(
+ PADAPTERCB AdapterCB,
+ PRECV_DESC RecvDesc
+ )
+{
+ PDEFERRED_DESC DeferredDesc;
+
+ //
+ // The current buffer pointer may point to the decompressor's context
+ // We cannot leave the data in the decompressor so we need to copy it
+ // back to the receive descriptor so we check to see if the current
+ // buffer pointer is already pointing to somewhere in the receive descriptor
+ // If it is we do not need to do the copy.
+ //
+
+ if (RecvDesc->CurrentBuffer < RecvDesc->StartBuffer ||
+ RecvDesc->CurrentBuffer > RecvDesc->StartBuffer + MAX_MRRU) {
+ PUCHAR FramePointer;
+ ULONG FrameLength;
+
+ FramePointer = RecvDesc->CurrentBuffer;
+ FrameLength = RecvDesc->CurrentBufferLength;
+ RecvDesc->CurrentBuffer = RecvDesc->StartBuffer;
+ NdisMoveMemory(RecvDesc->CurrentBuffer,
+ FramePointer,
+ FrameLength);
+ }
+
+ NdisAcquireSpinLock(&AdapterCB->Lock);
+
+ NdisWanGetDeferredDesc(AdapterCB, &DeferredDesc);
+
+ NdisWanInterlockedInc(&RecvDesc->RefCount);
+
+ DeferredDesc->Context = RecvDesc;
+
+ InsertTailDeferredQueue(&AdapterCB->DeferredQueue[ReceiveIndication],
+ DeferredDesc);
+
+ NdisWanSetDeferred(AdapterCB);
+
+ NdisReleaseSpinLock(&AdapterCB->Lock);
+}
+
+BOOLEAN
+DoVJDecompression(
+ PBUNDLECB BundleCB,
+ USHORT ProtocolID,
+ PUCHAR *DataPointer,
+ PULONG DataLength,
+ PUCHAR Header,
+ PULONG HeaderLength
+ )
+{
+ ULONG BundleFraming;
+ PUCHAR FramePointer = *DataPointer;
+ ULONG FrameLength = *DataLength;
+ UCHAR VJCompType = 0;
+ BOOLEAN DoDecomp = FALSE;
+ BOOLEAN VJDetect = FALSE;
+
+ *HeaderLength = 0;
+
+
+ BundleFraming = BundleCB->FramingInfo.RecvFramingBits;
+
+ if (BundleFraming & SLIP_FRAMING) {
+
+ VJCompType = *FramePointer & 0xF0;
+
+ //
+ // If the packet is compressed the header has to be atleast 3 bytes long.
+ // If this is a regular IP packet we do not decompress it.
+ //
+ if ((FrameLength > 2) && (VJCompType != TYPE_IP)) {
+
+ if (VJCompType & 0x80) {
+
+ VJCompType = TYPE_COMPRESSED_TCP;
+
+ } else if (VJCompType == TYPE_UNCOMPRESSED_TCP) {
+
+ *FramePointer &= 0x4F;
+ }
+
+ //
+ // If framing is set for detection, in order for this to be a good
+ // frame for detection we need a type of UNCOMPRESSED_TCP and a
+ // frame that is atleast 40 bytes long.
+ //
+ VJDetect = ((BundleFraming & SLIP_VJ_AUTODETECT) &&
+ (VJCompType == TYPE_UNCOMPRESSED_TCP) &&
+ (FrameLength > 39));
+
+ if ((BundleCB->VJCompress != NULL) &&
+ ((BundleFraming & SLIP_VJ_COMPRESSION) || VJDetect)) {
+
+ //
+ // If VJ compression is set or if we are in
+ // autodetect and this looks like a reasonable
+ // frame
+ //
+ DoDecomp = TRUE;
+
+ }
+ }
+
+ // end of SLIP_FRAMING
+ } else {
+
+ //
+ // Must be PPP framing
+ //
+ if (ProtocolID == PPP_PROTOCOL_COMPRESSED_TCP) {
+ VJCompType = TYPE_COMPRESSED_TCP;
+ } else {
+ VJCompType = TYPE_UNCOMPRESSED_TCP;
+ }
+
+ DoDecomp = TRUE;
+ }
+
+ if (DoDecomp) {
+ ULONG PreCompSize = *DataLength;
+ ULONG PostCompSize;
+
+ if (BundleCB->VJCompress == NULL) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_RECEIVE, ("RecvVJCompress == NULL!"));
+ return(FALSE);
+ }
+
+ NdisWanDbgOut(DBG_INFO, DBG_RECV_VJ,
+ ("rvj %2.2x %d", VJCompType, PreCompSize));
+
+ if ((PostCompSize = sl_uncompress_tcp(DataPointer,
+ DataLength,
+ Header,
+ HeaderLength,
+ VJCompType,
+ BundleCB->VJCompress)) == 0) {
+
+ NdisWanDbgOut(DBG_INFO, DBG_RECV_VJ,
+ ("rvj decomp error!"));
+
+ NdisWanDbgOut(DBG_FAILURE, DBG_RECEIVE, ("Error in sl_uncompress_tcp!"));
+ return(FALSE);
+ }
+
+ if (VJDetect) {
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ BundleCB->FramingInfo.RecvFramingBits |= SLIP_VJ_COMPRESSION;
+ BundleCB->FramingInfo.SendFramingBits |= SLIP_VJ_COMPRESSION;
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+ }
+
+ PostCompSize = *DataLength + *HeaderLength;
+
+ //
+ // Calculate how much expansion we had
+ //
+ BundleCB->BundleStats.BytesReceivedCompressed +=
+ (40 - (PostCompSize - PreCompSize));
+
+ BundleCB->BundleStats.BytesReceivedUncompressed += 40;
+
+ NdisWanDbgOut(DBG_INFO, DBG_RECV_VJ,
+ ("rvj %d", PostCompSize));
+ }
+
+ return(TRUE);
+}
+
+BOOLEAN
+DoDecompDecryptProcessing(
+ PBUNDLECB BundleCB,
+ PLINKCB LinkCB,
+ PUCHAR *DataPointer,
+ PULONG DataLength
+ )
+{
+ USHORT Coherency;
+ PNDISWAN_IO_PACKET IoPacket;
+ ULONG Flags;
+ PWAN_STATS BundleStats;
+ PUCHAR FramePointer = *DataPointer;
+ ULONG FrameLength = *DataLength;
+
+
+ Flags = ((BundleCB->RecvCompInfo.MSCompType & NDISWAN_COMPRESSION) &&
+ (BundleCB->RecvCompressContext != NULL)) ? DO_COMPRESSION : 0;
+
+ if (BundleCB->RecvRC4Key != NULL) {
+ if (BundleCB->RecvCompInfo.MSCompType & NDISWAN_ENCRYPTION) {
+ Flags |= (DO_ENCRYPTION | DO_LEGACY_ENCRYPTION);
+ } else if (BundleCB->RecvCompInfo.MSCompType & NDISWAN_40_ENCRYPTION) {
+ Flags |= (DO_ENCRYPTION | DO_40_ENCRYPTION);
+ }
+#ifdef ENCRYPT_128BIT
+ else if (BundleCB->RecvCompInfo.MSCompType & NDISWAN_128_ENCRYPTION) {
+ Flags |= (DO_ENCRYPTION | DO_128_ENCRYPTION);
+ }
+#endif
+ }
+
+ BundleStats = &BundleCB->BundleStats;
+
+ if (Flags & (DO_COMPRESSION | DO_ENCRYPTION)) {
+ PUCHAR SessionKey = BundleCB->RecvEncryptInfo.SessionKey;
+ ULONG SessionKeyLength = BundleCB->RecvEncryptInfo.SessionKeyLength;
+ PVOID RecvRC4Key = BundleCB->RecvRC4Key;
+ PVOID RecvCompressContext = BundleCB->RecvCompressContext;
+
+ //
+ // Get the coherency counter
+ //
+ Coherency = (*FramePointer << 8) | *(FramePointer + 1);
+ FramePointer += 2;
+ FrameLength -= 2;
+
+
+ if (SEQ_LT(Coherency & 0x0FFF,
+ BundleCB->RCoherencyCounter & 0x0FFF,
+ 0x0800)) {
+ //
+ // We received a sequence number that is less then the
+ // expected sequence number so we must be way out of sync
+ //
+#if DBG
+ DbgPrint("NDISWAN: !!!!rc %4.4x < ec %4.4x!!!!\n", Coherency & 0x0FFF,
+ BundleCB->RCoherencyCounter & 0x0FFF);
+#endif
+ goto RESYNC;
+ }
+
+ //
+ // See if this is a flush packet
+ //
+ if (Coherency & (PACKET_FLUSHED << 8)) {
+
+ NdisWanDbgOut(DBG_INFO, DBG_RECEIVE,
+ ("Recv Packet Flushed 0x%4.4x\n", (Coherency & 0x0FFF)));
+
+ if ((BundleCB->RCoherencyCounter & 0x0FFF) >
+ (Coherency & 0x0FFF)) {
+ BundleCB->RCoherencyCounter += 0x1000;
+ }
+
+ BundleCB->RCoherencyCounter &= 0xF000;
+ BundleCB->RCoherencyCounter |= (Coherency & 0x0FFF);
+
+ if (Flags & DO_ENCRYPTION) {
+
+ //
+ // Re-Init the rc4 receive table
+ //
+ rc4_key(RecvRC4Key,
+ SessionKeyLength,
+ SessionKey);
+
+ }
+
+ if (Flags & DO_COMPRESSION) {
+
+ //
+ // Initialize the decompression history table
+ //
+ initrecvcontext(RecvCompressContext);
+
+ }
+
+ } // end of packet flushed
+
+ if ((Coherency & 0x0FFF) == (BundleCB->RCoherencyCounter & 0x0FFF)) {
+
+ //
+ // We are still in sync
+ //
+
+ BundleCB->RCoherencyCounter++;
+
+ if (Coherency & (PACKET_ENCRYPTED << 8)) {
+
+ //
+ // This packet is encrypted
+ //
+
+ if (!(Flags & DO_ENCRYPTION)) {
+ //
+ // We are not configured to decrypt
+ //
+ return (FALSE);
+ }
+
+ if ((BundleCB->RCoherencyCounter - BundleCB->LastRC4Reset)
+ >= 0x100) {
+
+ //
+ // It is time to change encryption keys
+ //
+
+ //
+ // Always align last reset on 0x100 boundary so as not to
+ // propagate error!
+ //
+ BundleCB->LastRC4Reset = BundleCB->RCoherencyCounter & 0xFF00;
+
+ //
+ // Prevent ushort rollover
+ //
+ if ((BundleCB->LastRC4Reset & 0xF000) == 0xF000) {
+ BundleCB->LastRC4Reset &= 0x0FFF;
+ BundleCB->RCoherencyCounter &= 0x0FFF;
+ }
+
+ if (Flags & DO_LEGACY_ENCRYPTION) {
+
+ //
+ // Change the session key
+ //
+ SessionKey[3] += 1;
+ SessionKey[4] += 3;
+ SessionKey[5] += 13;
+ SessionKey[6] += 57;
+ SessionKey[7] += 19;
+
+ } else {
+
+ //
+ // Change the session key
+ //
+ GetNewKeyFromSHA(&BundleCB->RecvEncryptInfo);
+ }
+
+
+ //
+ // We use rc4 to scramble and recover a new key
+ //
+
+ //
+ // Re-initialize the rc4 receive table to the
+ // intermediate value
+ //
+ rc4_key(RecvRC4Key, SessionKeyLength, SessionKey);
+
+ //
+ // Scramble the existing session key
+ //
+ rc4(RecvRC4Key, SessionKeyLength, SessionKey);
+
+ //
+ // If this is 40 bit encryption we need to fix
+ // the first 3 bytes of the key.
+ //
+
+#ifdef ENCRYPT_128BIT
+ if (!(Flags & DO_128_ENCRYPTION)) {
+#endif
+
+ //
+ // Re-Salt the first 3 bytes
+ //
+ SessionKey[0] = 0xD1;
+ SessionKey[1] = 0x26;
+ SessionKey[2] = 0x9E;
+
+#ifdef ENCRYPT_128BIT
+ }
+#endif
+ NdisWanDbgOut(DBG_TRACE, DBG_CCP,
+ ("RC4 Recv encryption KeyLength %d", BundleCB->RecvEncryptInfo.SessionKeyLength));
+ NdisWanDbgOut(DBG_TRACE, DBG_CCP,
+ ("RC4 Recv encryption Key %.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x",
+ BundleCB->RecvEncryptInfo.SessionKey[0],
+ BundleCB->RecvEncryptInfo.SessionKey[1],
+ BundleCB->RecvEncryptInfo.SessionKey[2],
+ BundleCB->RecvEncryptInfo.SessionKey[3],
+ BundleCB->RecvEncryptInfo.SessionKey[4],
+ BundleCB->RecvEncryptInfo.SessionKey[5],
+ BundleCB->RecvEncryptInfo.SessionKey[6],
+ BundleCB->RecvEncryptInfo.SessionKey[7],
+ BundleCB->RecvEncryptInfo.SessionKey[8],
+ BundleCB->RecvEncryptInfo.SessionKey[9],
+ BundleCB->RecvEncryptInfo.SessionKey[10],
+ BundleCB->RecvEncryptInfo.SessionKey[11],
+ BundleCB->RecvEncryptInfo.SessionKey[12],
+ BundleCB->RecvEncryptInfo.SessionKey[13],
+ BundleCB->RecvEncryptInfo.SessionKey[14],
+ BundleCB->RecvEncryptInfo.SessionKey[15]));
+
+ // Re-initialize the rc4 receive table to the
+ // scrambled session key
+ //
+ rc4_key(RecvRC4Key, SessionKeyLength, SessionKey);
+
+
+ } // end of reset encryption key
+
+ //
+ // Decrypt the data!
+ //
+ rc4(RecvRC4Key,
+ FrameLength,
+ FramePointer);
+
+ } // end of encryption
+
+ if (Coherency & (PACKET_COMPRESSED << 8)) {
+
+ //
+ // This packet is compressed!
+ //
+ if (!(Flags & DO_COMPRESSION)) {
+ //
+ // We are not configured to decompress
+ //
+ return (FALSE);
+ }
+
+ //
+ // Add up bundle stats
+ //
+ BundleStats->BytesReceivedCompressed += FrameLength;
+
+ if (decompress(FramePointer,
+ FrameLength,
+ ((Coherency & (PACKET_AT_FRONT << 8)) >> 8),
+ &FramePointer,
+ &FrameLength,
+ RecvCompressContext) == FALSE) {
+
+#if DBG
+ DbgPrint("dce %4.4x\n", Coherency);
+#endif
+ //
+ // Error decompressing!
+ //
+ BundleCB->RCoherencyCounter--;
+ goto RESYNC;
+
+ }
+
+ BundleStats->BytesReceivedUncompressed += FrameLength;
+
+ } // end of compression
+
+ } else { // end of insync
+RESYNC:
+
+
+ NdisWanDbgOut(DBG_FAILURE, DBG_RECEIVE, ("oos r %4.4x, e %4.4x\n", (Coherency & 0x0FFF),
+ (BundleCB->RCoherencyCounter & 0x0FFF)));
+
+ //
+ // We are out of sync!
+ //
+ NdisWanAllocateMemory(&IoPacket, sizeof(NDISWAN_IO_PACKET) + 100);
+
+ if (IoPacket != NULL) {
+ NDIS_STATUS IoStatus;
+
+ IoPacket->hHandle = LinkCB->hLinkHandle;
+ IoPacket->usHandleType = LINKHANDLE;
+ IoPacket->usHeaderSize = 0;
+ IoPacket->usPacketSize = 6;
+ IoPacket->usPacketFlags = 0;
+ IoPacket->PacketData[0] = 0x80;
+ IoPacket->PacketData[1] = 0xFD;
+ IoPacket->PacketData[2] = 14;
+ IoPacket->PacketData[3] = BundleCB->CCPIdentifier++;
+ IoPacket->PacketData[4] = 0x00;
+ IoPacket->PacketData[5] = 0x04;
+
+ IoStatus = BuildIoPacket(IoPacket, FALSE);
+
+ NdisWanFreeMemory(IoPacket);
+ }
+
+
+ return (FALSE);
+
+ } // end of out of sync
+
+ } else { // end of DoCompEncrypt
+
+ //
+ // For some reason we were not able to
+ // decrypt/decompress!
+ //
+ return (FALSE);
+ }
+
+ *DataPointer = FramePointer;
+ *DataLength = FrameLength;
+
+ return (TRUE);
+}
+
+VOID
+DoCompressionReset(
+ PBUNDLECB BundleCB
+ )
+{
+ if (BundleCB->RecvCompInfo.MSCompType != 0) {
+
+ //
+ // The next outgoing packet will flush
+ //
+ NdisAcquireSpinLock(&BundleCB->Lock);
+ BundleCB->Flags |= RECV_PACKET_FLUSH;
+ NdisReleaseSpinLock(&BundleCB->Lock);
+ }
+}
+
+VOID
+NdisWanReceiveComplete(
+ IN NDIS_HANDLE NdisLinkContext
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("NdisWanReceiveComplete: Enter"));
+
+ NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("NdisWanReceiveComplete: Exit"));
+}
+
+NDIS_STATUS
+NdisWanTransferData(
+ OUT PNDIS_PACKET NdisPacket,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PRECV_DESC RecvDesc;
+ PUCHAR LookAhead, FramePointer;
+ ULONG LookAheadLength, FrameLength;
+ ULONG BytesToCopy, BytesCopied, PacketOffset = 0;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("NdisWanTransferData: Enter"));
+
+ RecvDesc = (PRECV_DESC)MiniportReceiveContext;
+ LookAhead = RecvDesc->LookAhead;
+ LookAheadLength = RecvDesc->LookAheadLength;
+ FramePointer = RecvDesc->CurrentBuffer;
+ FrameLength = RecvDesc->CurrentBufferLength;
+
+ *BytesTransferred = 0;
+
+ if (BytesToTransfer == 0) {
+ return (NDIS_STATUS_SUCCESS);
+ }
+
+ ASSERT(BytesToTransfer <= (FrameLength + LookAheadLength));
+
+ if ((ByteOffset < LookAheadLength) && (LookAheadLength != 0)) {
+
+ //
+ // First we will copy the lookahead bytes
+ //
+ BytesToCopy = LookAheadLength - ByteOffset;
+
+ BytesToCopy = (BytesToTransfer < BytesToCopy) ?
+ BytesToTransfer : BytesToCopy;
+
+ NdisWanCopyFromBufferToPacket(LookAhead + ByteOffset,
+ BytesToCopy,
+ NdisPacket,
+ PacketOffset,
+ &BytesCopied);
+
+ *BytesTransferred += BytesCopied;
+
+ PacketOffset += BytesCopied;
+ BytesToTransfer -= BytesCopied;
+ ByteOffset = 0;
+ }
+
+ if (FrameLength != 0) {
+
+ //
+ // Now we copy the rest of the frame
+ //
+
+ BytesToCopy = (BytesToTransfer < FrameLength) ?
+ BytesToTransfer : FrameLength;
+
+ NdisWanCopyFromBufferToPacket(FramePointer + ByteOffset,
+ BytesToCopy,
+ NdisPacket,
+ PacketOffset,
+ &BytesCopied);
+
+ *BytesTransferred += BytesCopied;
+ }
+
+ NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("NdisWanTransferData: Exit"));
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+VOID
+NdisWanCopyFromBufferToPacket(
+ PUCHAR Buffer,
+ ULONG BytesToCopy,
+ PNDIS_PACKET NdisPacket,
+ ULONG PacketOffset,
+ PULONG BytesCopied
+ )
+{
+ PNDIS_BUFFER NdisBuffer;
+ ULONG NdisBufferCount, NdisBufferLength;
+ PVOID VirtualAddress;
+ ULONG LocalBytesCopied = 0;
+
+ *BytesCopied = 0;
+
+ //
+ // Make sure we actually want to do something
+ //
+ if (BytesToCopy == 0) {
+ return;
+ }
+
+ //
+ // Get the buffercount of the packet
+ //
+ NdisQueryPacket(NdisPacket,
+ NULL,
+ &NdisBufferCount,
+ &NdisBuffer,
+ NULL);
+
+ //
+ // Make sure this is not a null packet
+ //
+ if (NdisBufferCount == 0) {
+ return;
+ }
+
+ //
+ // Get first buffer and buffer length
+ //
+ NdisQueryBuffer(NdisBuffer,
+ &VirtualAddress,
+ &NdisBufferLength);
+
+ while (LocalBytesCopied < BytesToCopy) {
+
+ if (NdisBufferLength == 0) {
+
+ NdisGetNextBuffer(NdisBuffer,
+ &NdisBuffer);
+
+ if (NdisBuffer == NULL) {
+ break;
+ }
+
+ NdisQueryBuffer(NdisBuffer,
+ &VirtualAddress,
+ &NdisBufferLength);
+
+ continue;
+ }
+
+ if (PacketOffset != 0) {
+
+ if (PacketOffset > NdisBufferLength) {
+
+ PacketOffset -= NdisBufferLength;
+
+ NdisBufferLength = 0;
+
+ continue;
+
+ } else {
+ VirtualAddress = (PUCHAR)VirtualAddress + PacketOffset;
+ NdisBufferLength -= PacketOffset;
+ PacketOffset = 0;
+ }
+ }
+
+ //
+ // Copy the data
+ //
+ {
+ ULONG AmountToMove;
+ ULONG AmountRemaining;
+
+ AmountRemaining = BytesToCopy - LocalBytesCopied;
+
+ AmountToMove = (NdisBufferLength < AmountRemaining) ?
+ NdisBufferLength : AmountRemaining;
+
+ NdisMoveMemory((PUCHAR)VirtualAddress,
+ Buffer,
+ AmountToMove);
+
+ Buffer += AmountToMove;
+ LocalBytesCopied += AmountToMove;
+ NdisBufferLength -= AmountToMove;
+ }
+ }
+
+ *BytesCopied = LocalBytesCopied;
+}
+
+
+#if 0
+ULONG
+CalculatePPPHeaderLength(
+ PLINKCB LinkCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ ULONG PPPHeaderLength = 0;
+ ULONG LinkFraming = LinkCB->LinkInfo.RecvFramingBits;
+
+ if (LinkFraming & PPP_FRAMING) {
+
+ PPPHeaderLength += (LinkFraming & PPP_COMPRESS_ADDRESS_CONTROL) ? 0 : 2;
+
+ if (LinkFraming & PPP_MULTILINK_FRAMING) {
+
+ PPPHeaderLength += (LinkFraming & PPP_COMPRESS_PROTOCOL_FIELD) ? 1 : 2;
+
+ PPPHeaderLength += (LinkFraming & PPP_SHORT_SEQUENCE_HDR_FORMAT) ? 2 : 4;
+ }
+
+ PPPHeaderLength += (LinkFraming & PPP_COMPRESS_PROTOCOL_FIELD) ? 1 : 2;
+
+ }
+
+ return (PPPHeaderLength);
+}
+#endif
+
+VOID
+NdisWanProcessReceiveIndications(
+ PADAPTERCB AdapterCB
+ )
+{
+
+ while (!IsDeferredQueueEmpty(&AdapterCB->DeferredQueue[ReceiveIndication])) {
+ PRECV_DESC RecvDesc;
+ PBUNDLECB BundleCB;
+ PDEFERRED_DESC ReturnDesc;
+
+ ReturnDesc = RemoveHeadDeferredQueue(&AdapterCB->DeferredQueue[ReceiveIndication]);
+ RecvDesc = ReturnDesc->Context;
+ BundleCB = RecvDesc->BundleCB;
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ if ((BundleCB->State == BUNDLE_UP) &&
+ (BundleCB->Flags & BUNDLE_ROUTED)) {
+ PUCHAR LookAhead;
+ ULONG LookAheadLength;
+ ULONG TotalLength = RecvDesc->LookAheadLength +
+ RecvDesc->CurrentBufferLength;
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ if (RecvDesc->LookAheadLength == 0) {
+ LookAhead = RecvDesc->CurrentBuffer;
+ LookAheadLength = RecvDesc->CurrentBufferLength;
+ } else {
+ LookAhead = RecvDesc->LookAhead;
+ LookAheadLength = RecvDesc->LookAheadLength;
+ }
+
+ ASSERT((LONG)TotalLength > 0);
+
+ NdisReleaseSpinLock(&AdapterCB->Lock);
+
+ if (NdisWanCB.PromiscuousAdapter != NULL) {
+
+ //
+ // Queue the packet on the promiscous adapter
+ //
+ QueuePromiscuousReceive(RecvDesc);
+ }
+
+ NdisMEthIndicateReceive(AdapterCB->hMiniportHandle,
+ RecvDesc,
+ RecvDesc->WanHeader,
+ 14,
+ LookAhead,
+ LookAheadLength,
+ TotalLength);
+
+ NdisAcquireSpinLock(&AdapterCB->Lock);
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+ }
+
+ NdisWanReturnRecvDesc(BundleCB, RecvDesc);
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ InsertHeadDeferredQueue(&AdapterCB->FreeDeferredQueue, ReturnDesc);
+ }
+}
+
+VOID
+QueuePromiscuousReceive(
+ PRECV_DESC RecvDesc
+ )
+{
+ PADAPTERCB AdapterCB = NdisWanCB.PromiscuousAdapter;
+ PLOOPBACK_DESC LoopbackDesc;
+ ULONG AllocationSize, BufferLength;
+ PDEFERRED_DESC DeferredDesc;
+ PUCHAR DataOffset;
+
+ BufferLength = RecvDesc->WanHeaderLength +
+ RecvDesc->LookAheadLength +
+ RecvDesc->CurrentBufferLength;
+
+ AllocationSize = sizeof(LOOPBACK_DESC) + BufferLength;
+
+ NdisWanAllocateMemory(&LoopbackDesc, AllocationSize);
+
+ if (LoopbackDesc == NULL) {
+ return;
+ }
+
+ LoopbackDesc->AllocationSize = (USHORT)AllocationSize;
+ LoopbackDesc->BufferLength = (USHORT)BufferLength;
+
+ LoopbackDesc->Buffer = (PUCHAR)LoopbackDesc + sizeof(LOOPBACK_DESC);
+
+ //
+ // Copy all of the data
+ //
+ DataOffset = LoopbackDesc->Buffer;
+ NdisMoveMemory(DataOffset,
+ RecvDesc->WanHeader,
+ RecvDesc->WanHeaderLength);
+ DataOffset += RecvDesc->WanHeaderLength;
+
+ if (RecvDesc->LookAheadLength != 0) {
+ NdisMoveMemory(DataOffset,
+ RecvDesc->LookAhead,
+ RecvDesc->LookAheadLength);
+ DataOffset += RecvDesc->LookAheadLength;
+ }
+
+ NdisMoveMemory(DataOffset,
+ RecvDesc->CurrentBuffer,
+ RecvDesc->CurrentBufferLength);
+
+ NdisAcquireSpinLock(&AdapterCB->Lock);
+
+ NdisWanGetDeferredDesc(AdapterCB, &DeferredDesc);
+
+ if (DeferredDesc == NULL) {
+
+ NdisWanFreeMemory(LoopbackDesc);
+ return;
+ }
+
+ DeferredDesc->Context = (PVOID)LoopbackDesc;
+
+ InsertTailDeferredQueue(&AdapterCB->DeferredQueue[Loopback], DeferredDesc);
+
+ NdisWanSetDeferred(AdapterCB);
+
+ NdisReleaseSpinLock(&AdapterCB->Lock);
+}
+
+BOOLEAN
+IpIsDataFrame(
+ PUCHAR HeaderBuffer,
+ ULONG HeaderBufferLength,
+ ULONG TotalLength
+ )
+{
+ UINT tcpheaderlength ;
+ UINT ipheaderlength ;
+ UCHAR *tcppacket;
+ UCHAR *ippacket = HeaderBuffer;
+ IPHeader UNALIGNED *ipheader = (IPHeader UNALIGNED *) HeaderBuffer;
+
+
+#define TYPE_UDP 17
+#define UDPPACKET_SRC_PORT_137(x) ((UCHAR) *(x + ((*x & 0x0f)*4) + 1) == 137)
+
+ if (ipheader->ip_p == TYPE_UDP) {
+
+ if (!UDPPACKET_SRC_PORT_137(ippacket))
+
+ return TRUE ;
+
+ else {
+
+ //
+ // UDP port 137 - is wins traffic. we count this as idle traffic.
+ //
+ return FALSE ;
+ }
+
+ }
+
+#define TYPE_TCP 6
+#define TCPPACKET_SRC_OR_DEST_PORT_139(x,y) (((UCHAR) *(x + y + 1) == 139) || ((UCHAR) *(x + y + 3) == 139))
+
+ //
+ // TCP packets with SRC | DEST == 139 which are ACKs (0 data) or Session Alives
+ // are considered as idle
+ //
+ if (ipheader->ip_p == TYPE_TCP) {
+
+ ipheaderlength = ((UCHAR)*ippacket & 0x0f)*4 ;
+ tcppacket = ippacket + ipheaderlength ;
+ tcpheaderlength = (*(tcppacket + 10) >> 4)*4 ;
+
+ if (!TCPPACKET_SRC_OR_DEST_PORT_139(ippacket,ipheaderlength))
+ return TRUE ;
+
+ //
+ // NetBT traffic
+ //
+
+ //
+ // if zero length tcp packet - this is an ACK on 139 - filter this.
+ //
+ if (TotalLength == (ipheaderlength + tcpheaderlength))
+ return FALSE ;
+
+ //
+ // Session alives are also filtered.
+ //
+ if ((UCHAR) *(tcppacket+tcpheaderlength) == 0x85)
+ return FALSE ;
+ }
+
+ //
+ // all other ip traffic is valid traffic
+ //
+ return TRUE ;
+}
+
+BOOLEAN
+IpxIsDataFrame(
+ PUCHAR HeaderBuffer,
+ ULONG HeaderBufferLength,
+ ULONG TotalLength
+ )
+{
+
+/*++
+
+Routine Description:
+
+ This routine is called when a frame is received on a WAN
+ line. It returns TRUE unless:
+
+ - The frame is from the RIP socket
+ - The frame is from the SAP socket
+ - The frame is a netbios keep alive
+ - The frame is an NCP keep alive
+
+Arguments:
+
+ HeaderBuffer - points to a contiguous buffer starting at the IPX header.
+
+ HeaderBufferLength - Length of the header buffer (could be same as totallength)
+
+ TotalLength - the total length of the frame
+
+Return Value:
+
+ TRUE - if this is a connection-based packet.
+
+ FALSE - otherwise.
+
+--*/
+
+ IPX_HEADER UNALIGNED * IpxHeader = (IPX_HEADER UNALIGNED *)HeaderBuffer;
+ USHORT SourceSocket;
+
+ //
+ // First get the source socket.
+ //
+ SourceSocket = IpxHeader->SourceSocket;
+
+ //
+ // Not connection-based
+ //
+ if ((SourceSocket == RIP_SOCKET) ||
+ (SourceSocket == SAP_SOCKET)) {
+
+ return FALSE;
+
+ }
+
+ //
+ // See if there are at least two more bytes to look at.
+ //
+ if (TotalLength >= sizeof(IPX_HEADER) + 2) {
+
+ if (SourceSocket == NB_SOCKET) {
+
+ UCHAR ConnectionControlFlag;
+ UCHAR DataStreamType;
+ USHORT TotalDataLength;
+
+ //
+ // ConnectionControlFlag and DataStreamType will always follow
+ // IpxHeader
+ //
+ ConnectionControlFlag = ((PUCHAR)(IpxHeader+1))[0];
+ DataStreamType = ((PUCHAR)(IpxHeader+1))[1];
+
+ //
+ // If this is a SYS packet with or without a request for ACK and
+ // has session data in it.
+ //
+ if (((ConnectionControlFlag == 0x80) || (ConnectionControlFlag == 0xc0)) &&
+ (DataStreamType == 0x06)) {
+
+ //
+ // TotalDataLength is in the same buffer.
+ //
+ TotalDataLength = ((USHORT UNALIGNED *)(IpxHeader+1))[4];
+
+ //
+ // KeepAlive - return FALSE
+ //
+ if (TotalDataLength == 0) {
+ return FALSE;
+ }
+ }
+
+ } else {
+
+ //
+ // Now see if it is an NCP keep alive. It can be from rip or from
+ // NCP on this machine
+ //
+ if (TotalLength == sizeof(IPX_HEADER) + 2) {
+
+ UCHAR KeepAliveSignature = ((PUCHAR)(IpxHeader+1))[1];
+
+ if ((KeepAliveSignature == '?') ||
+ (KeepAliveSignature == 'Y')) {
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ //
+ // This was a normal packet, so return TRUE
+ //
+
+ return TRUE;
+}
+
+BOOLEAN
+NbfIsDataFrame(
+ PUCHAR HeaderBuffer,
+ ULONG HeaderBufferLength,
+ ULONG TotalLength
+ )
+{
+/*++
+
+Routine Description:
+
+ This routine looks at a data packet from the net to deterimine if there is
+ any data flowing on the connection.
+
+Arguments:
+
+ HeaderBuffer - Pointer to the dlc header for this packet.
+
+ HeaderBufferLength - Length of the header buffer (could be same as totallength)
+
+ TotalLength - the total length of the frame
+
+Return Value:
+
+ True if this is a frame that indicates data traffic on the connection.
+ False otherwise.
+
+--*/
+
+ PDLC_FRAME DlcHeader = (PDLC_FRAME)HeaderBuffer;
+ BOOLEAN Command = (BOOLEAN)!(DlcHeader->Ssap & DLC_SSAP_RESPONSE);
+ PNBF_HDR_CONNECTION nbfHeader;
+
+ if (TotalLength < sizeof(PDLC_FRAME)) {
+ return(FALSE);
+ }
+
+ if (!(DlcHeader->Byte1 & DLC_I_INDICATOR)) {
+
+ //
+ // We have an I frame.
+ //
+
+ if (TotalLength < 4 + sizeof(NBF_HDR_CONNECTION)) {
+
+ //
+ // It's a runt I-frame.
+ //
+
+ return(FALSE);
+ }
+
+ nbfHeader = (PNBF_HDR_CONNECTION) ((PUCHAR)DlcHeader + 4);
+
+ switch (nbfHeader->Command) {
+ case NBF_CMD_DATA_FIRST_MIDDLE:
+ case NBF_CMD_DATA_ONLY_LAST:
+ case NBF_CMD_DATA_ACK:
+ case NBF_CMD_SESSION_CONFIRM:
+ case NBF_CMD_SESSION_INITIALIZE:
+ case NBF_CMD_NO_RECEIVE:
+ case NBF_CMD_RECEIVE_OUTSTANDING:
+ case NBF_CMD_RECEIVE_CONTINUE:
+ return(TRUE);
+ break;
+
+ default:
+ return(FALSE);
+ break;
+ }
+ }
+ return(FALSE);
+
+}
+
+#ifdef NT
+
+VOID
+CompleteIoRecvPacket(
+ PBUNDLECB BundleCB,
+ PLINKCB LinkCB,
+ USHORT PPPProtocolID,
+ PRECV_DESC RecvDesc
+ )
+{
+ PWAN_ASYNC_EVENT AsyncEvent;
+ PUCHAR FramePointer = RecvDesc->CurrentBuffer;
+ ULONG FrameLength = RecvDesc->CurrentBufferLength;
+ KIRQL Irql;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("CompleteIoRecvPacket: Enter"));
+
+ IoAcquireCancelSpinLock(&Irql);
+
+ if (!IsListEmpty(&RecvPacketQueue.List)) {
+ PNDISWAN_IO_PACKET IoPacket;
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+ ULONG SizeNeeded, BufferLength;
+
+ AsyncEvent =
+ (PWAN_ASYNC_EVENT)NdisWanInterlockedRemoveHeadList(&RecvPacketQueue.List,
+ &RecvPacketQueue.Lock.SpinLock);
+
+ NdisWanInterlockedDec(&RecvPacketQueue.ulCount);
+
+ Irp = (PIRP)AsyncEvent->Context;
+
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+ BufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+
+ SizeNeeded = sizeof(NDISWAN_IO_PACKET) + 14 + FrameLength;
+
+ if ((BufferLength >= SizeNeeded) && (LinkCB->hLinkContext != NULL)) {
+ PUCHAR Data;
+
+ IoPacket = Irp->AssociatedIrp.SystemBuffer;
+
+ IoPacket->hHandle = LinkCB->hLinkContext;
+ IoPacket->usHandleType = LINKHANDLE;
+ IoPacket->usHeaderSize = 14;
+ IoPacket->usPacketSize = (USHORT)FrameLength + 14;
+ IoPacket->usPacketFlags = 0;
+
+ Data = IoPacket->PacketData;
+
+ //
+ // First build the header
+ //
+ Data[0] =
+ Data[6] = ' ';
+
+ Data[1] =
+ Data[7] = 'R';
+
+ Data[2] =
+ Data[8] = 'E';
+
+ Data[3] =
+ Data[9] = 'C';
+
+ Data[4] =
+ Data[10] = 'V';
+
+ Data[5] =
+ Data[11] = (UCHAR)LinkCB->hLinkHandle;
+
+ Data[12] = (UCHAR)(PPPProtocolID >> 8);
+ Data[13] = (UCHAR)PPPProtocolID;
+
+ NdisMoveMemory(RecvDesc->WanHeader, Data, 14);
+ RecvDesc->WanHeaderLength = 14;
+
+ //
+ // Now copy the data
+ //
+ NdisMoveMemory(Data + 14,
+ FramePointer,
+ FrameLength);
+
+ IoSetCancelRoutine(Irp, NULL);
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = SizeNeeded;
+
+ IoReleaseCancelSpinLock(Irql);
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ //
+ // Free the wan_async_event structure
+ //
+ NdisWanFreeMemory(AsyncEvent);
+
+ if (NdisWanCB.PromiscuousAdapter != NULL) {
+ RecvDesc->LookAheadLength = 0;
+
+ //
+ // Queue the packet on the promiscous adapter
+ //
+ QueuePromiscuousReceive(RecvDesc);
+ }
+
+ } else {
+
+#if DBG
+ DbgPrint("NDISWAN: Error I/O recv: bufferlength %d, linkcontext: 0x%8.8x\n",
+ BufferLength, LinkCB->hLinkContext);
+#endif
+ InsertHeadList(&RecvPacketQueue.List, &AsyncEvent->Linkage);
+ NdisWanInterlockedInc(&NdisWanCB.IORecvError2);
+ IoReleaseCancelSpinLock(Irql);
+ }
+
+ } else {
+#if DBG
+ DbgPrint("NDISWAN: No I/O recv packets available!\n");
+#endif
+ NdisWanInterlockedInc(&NdisWanCB.IORecvError1);
+ IoReleaseCancelSpinLock(Irql);
+ }
+
+ NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("CompleteIoRecvPacket: Exit"));
+}
+
+
+#endif // end ifdef NT
diff --git a/private/ntos/ndis/ndiswan/request.c b/private/ntos/ndis/ndiswan/request.c
new file mode 100644
index 000000000..238dbed53
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/request.c
@@ -0,0 +1,541 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ Request.c
+
+Abstract:
+
+
+Author:
+
+ Tony Bell (TonyBe) June 06, 1995
+
+Environment:
+
+ Kernel Mode
+
+Revision History:
+
+ TonyBe 06/06/95 Created
+
+--*/
+
+#include "wan.h"
+
+
+static UINT SupportedOids[] =
+{
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ OID_WAN_PERMANENT_ADDRESS,
+ OID_WAN_CURRENT_ADDRESS,
+ OID_WAN_QUALITY_OF_SERVICE,
+ OID_WAN_MEDIUM_SUBTYPE,
+ OID_WAN_PROTOCOL_TYPE,
+ OID_WAN_HEADER_FORMAT,
+ OID_WAN_LINE_COUNT
+};
+
+
+NDIS_STATUS
+NdisWanOidProc(
+ IN PADAPTERCB pAdapterCB,
+ IN NDIS_OID Oid,
+ IN ULONG SetQueryFlag,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ ULONG OidType = Oid & 0xFF000000;
+ NDIS_MEDIUM MediumType;
+ ULONG GenericULong = 0, i;
+ USHORT GenericUShort = 0;
+ UCHAR GenericArray[6];
+ PVOID MoveSource = (PVOID)&GenericULong;
+ ULONG MoveBytes = sizeof(ULONG);
+ NDIS_HARDWARE_STATUS HardwareStatus;
+ ULONG Filter = 0;
+
+ NdisAcquireSpinLock(&pAdapterCB->Lock);
+
+ //
+ // We will break the OID's down into smaller categories
+ //
+ switch (OidType) {
+
+ //
+ // Swith on General Oid's
+ //
+ case OID_GEN:
+ switch (Oid) {
+ case OID_GEN_SUPPORTED_LIST:
+ MoveSource = (PVOID)SupportedOids;
+ MoveBytes = sizeof(SupportedOids);
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+ HardwareStatus = pAdapterCB->HardwareStatus;
+ MoveSource = (PVOID)&HardwareStatus;
+ MoveBytes = sizeof(HardwareStatus);
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+ MediumType = pAdapterCB->MediumType;
+ MoveSource = (PVOID)&MediumType;
+ MoveBytes = sizeof(MediumType);
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+ GenericULong = (ULONG)MAX_FRAME_SIZE;
+ break;
+
+ case OID_GEN_LINK_SPEED:
+ //
+ // Who knows what the initial link speed is?
+ // This should not be called, right?
+ //
+ GenericULong = (ULONG)288;
+ break;
+
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+ GenericULong = (ULONG)(MAX_FRAME_SIZE * MAX_OUTSTANDING_PACKETS);
+ break;
+
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+ GenericULong = (ULONG)(MAX_TOTAL_SIZE);
+ break;
+
+ case OID_GEN_VENDOR_ID:
+ GenericULong = 0xFFFFFFFF;
+ MoveBytes = 3;
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+ MoveSource = (PVOID)"NdisWan Adapter";
+ MoveBytes = 16;
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ if (SetQueryFlag == SET_OID) {
+ if (InformationBufferLength > 3) {
+ NdisMoveMemory(&Filter, InformationBuffer, 4);
+
+ if (Filter & NDIS_PACKET_TYPE_PROMISCUOUS) {
+ NdisWanCB.PromiscuousAdapter = pAdapterCB;
+ } else if (NdisWanCB.PromiscuousAdapter == pAdapterCB) {
+ NdisWanCB.PromiscuousAdapter = NULL;
+ }
+
+ } else {
+ Status = NDIS_STATUS_BUFFER_TOO_SHORT;
+ *BytesWritten = 0;
+ *BytesNeeded = 4;
+ }
+ }
+ break;
+
+
+ case OID_GEN_DRIVER_VERSION:
+ GenericUShort = 0x0301;
+ MoveSource = (PVOID)&GenericUShort;
+ MoveBytes = sizeof(USHORT);
+ break;
+
+ case OID_GEN_MAC_OPTIONS:
+ GenericULong = (ULONG)(NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
+ NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
+// NDIS_MAC_OPTION_NO_LOOPBACK |
+ NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
+// NDIS_MAC_OPTION_FULL_DUPLEX |
+ NDIS_MAC_OPTION_RESERVED |
+ NDIS_MAC_OPTION_NDISWAN);
+ break;
+
+ case OID_GEN_XMIT_OK:
+ break;
+
+ case OID_GEN_RCV_OK:
+ break;
+
+ case OID_GEN_XMIT_ERROR:
+ break;
+
+ case OID_GEN_RCV_ERROR:
+ break;
+
+ case OID_GEN_RCV_NO_BUFFER:
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ //
+ // Switch on ethernet media specific Oid's
+ //
+ case OID_802_3:
+ switch (Oid) {
+ case OID_802_3_PERMANENT_ADDRESS:
+ case OID_802_3_CURRENT_ADDRESS:
+ ETH_COPY_NETWORK_ADDRESS(GenericArray, pAdapterCB->NetworkAddress);
+ MoveSource = (PVOID)GenericArray;
+ MoveBytes = ETH_LENGTH_OF_ADDRESS;
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+ MoveBytes = 0;
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+ GenericULong = 1;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ //
+ // Switch on WAN specific Oid's
+ //
+ case OID_WAN:
+ switch (Oid) {
+ case OID_WAN_PERMANENT_ADDRESS:
+ case OID_WAN_CURRENT_ADDRESS:
+ ETH_COPY_NETWORK_ADDRESS(GenericArray, pAdapterCB->NetworkAddress);
+ MoveSource = (PVOID)GenericArray;
+ MoveBytes = ETH_LENGTH_OF_ADDRESS;
+ break;
+
+ case OID_WAN_QUALITY_OF_SERVICE:
+ GenericULong = NdisWanReliable;
+ break;
+
+ case OID_WAN_MEDIUM_SUBTYPE:
+ GenericULong = NdisWanMediumHub;
+ break;
+
+ case OID_WAN_PROTOCOL_TYPE:
+ if (InformationBufferLength > 5) {
+
+ pAdapterCB->ProtocolType =
+ (((PUCHAR)InformationBuffer)[4] << 8) |
+ ((PUCHAR)InformationBuffer)[5];
+
+ pAdapterCB->ulNumberofProtocols++;
+
+ } else {
+ Status = NDIS_STATUS_BUFFER_TOO_SHORT;
+ *BytesWritten = 0;
+ *BytesNeeded = 6;
+ }
+ break;
+
+ case OID_WAN_HEADER_FORMAT:
+ GenericULong = NdisWanHeaderEthernet;
+ break;
+
+ case OID_WAN_LINE_COUNT:
+ GenericULong = NdisWanCB.ulNumberOfLinks;
+ break;
+
+ default:
+ break;
+ }
+ break;
+ }
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ if ((MoveBytes > InformationBufferLength) &&
+ (SetQueryFlag == QUERY_OID)) {
+
+ //
+ // Not enough room in the information buffer
+ //
+ *BytesNeeded = MoveBytes;
+
+ Status = NDIS_STATUS_INVALID_LENGTH;
+
+ } else {
+
+ *BytesWritten = MoveBytes;
+
+ NdisMoveMemory(InformationBuffer,
+ MoveSource,
+ MoveBytes);
+ }
+
+ }
+
+ NdisReleaseSpinLock(&pAdapterCB->Lock);
+
+ return (Status);
+}
+
+NDIS_STATUS
+NdisWanSubmitNdisRequest(
+ IN PWAN_ADAPTERCB pWanAdapterCB,
+ IN PNDIS_REQUEST pNdisRequest,
+ IN WanRequestType Type,
+ IN WanRequestOrigin Origin
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NDIS_STATUS Status;
+ PWAN_REQUEST WanRequest;
+
+ NdisWanAllocateMemory(&WanRequest, sizeof(WAN_REQUEST));
+
+ if (WanRequest == NULL) {
+ return (NDIS_STATUS_RESOURCES);
+ }
+
+ WanRequest->pNdisRequest = pNdisRequest;
+ WanRequest->Type = Type;
+ WanRequest->Origin = Origin;
+
+ NdisWanInitializeNotificationEvent(&WanRequest->NotificationEvent);
+
+ AddRequestToList(pWanAdapterCB, WanRequest);
+
+ NdisRequest(&Status,
+ pWanAdapterCB->hNdisBindingHandle,
+ pNdisRequest);
+
+ //
+ // We will only wait for request that are to complete
+ // synchronously with respect to this function. We will
+ // wait here for completion.
+ //
+ if (Type == SYNC) {
+
+ if (Status == NDIS_STATUS_PENDING) {
+
+ NdisWanWaitForNotificationEvent(&WanRequest->NotificationEvent);
+
+ Status = WanRequest->NotificationStatus;
+
+ NdisWanClearNotificationEvent(&WanRequest->NotificationEvent);
+ }
+
+ RemoveRequestFromList(pWanAdapterCB, WanRequest);
+
+ NdisWanFreeMemory(WanRequest);
+ }
+
+ return (Status);
+}
+
+VOID
+AddRequestToList(
+ IN PWAN_ADAPTERCB pWanAdapterCB,
+ IN PWAN_REQUEST pWanRequest
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NdisAcquireSpinLock(&pWanAdapterCB->Lock);
+
+ pWanRequest->pNext = NULL;
+
+ //
+ // Is the list empty?
+ //
+ if (pWanAdapterCB->pWanRequest == NULL) {
+
+ ASSERT(pWanAdapterCB->pLastWanRequest == NULL);
+
+ pWanAdapterCB->pWanRequest = pWanRequest;
+ } else {
+ pWanAdapterCB->pLastWanRequest->pNext = pWanRequest;
+ }
+
+ //
+ // update the last request
+ //
+ pWanAdapterCB->pLastWanRequest = pWanRequest;
+
+ NdisReleaseSpinLock(&pWanAdapterCB->Lock);
+}
+
+
+VOID
+RemoveRequestFromList(
+ IN PWAN_ADAPTERCB pWanAdapterCB,
+ IN PWAN_REQUEST pWanRequest
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PWAN_REQUEST CRequest, PRequest;
+
+ NdisAcquireSpinLock(&pWanAdapterCB->Lock);
+
+ //
+ // Make sure that there is something on the list
+ //
+ ASSERT(pWanAdapterCB->pWanRequest != NULL);
+
+ //
+ // Is this request on the head of the list?
+ //
+ if (pWanRequest == pWanAdapterCB->pWanRequest) {
+ pWanAdapterCB->pWanRequest = pWanRequest->pNext;
+
+ //
+ // If this is also the last request update tail
+ //
+ if (pWanRequest == pWanAdapterCB->pLastWanRequest) {
+ pWanAdapterCB->pLastWanRequest = NULL;
+ }
+
+ } else {
+ CRequest =
+ PRequest = pWanAdapterCB->pWanRequest;
+
+ do {
+
+ if (CRequest == pWanRequest) {
+ //
+ // We found it so remove it from the list
+ //
+ PRequest->pNext = CRequest->pNext;
+ break;
+ }
+
+ PRequest = CRequest;
+
+ CRequest = CRequest->pNext;
+
+ } while (CRequest != NULL);
+
+ //
+ // Did we not find the bugger?
+ //
+ ASSERT (CRequest != NULL);
+
+ //
+ // If this is on the tail of the list remove and update tail
+ //
+ if (CRequest == pWanAdapterCB->pLastWanRequest) {
+ pWanAdapterCB->pLastWanRequest = PRequest;
+ }
+ }
+
+ NdisReleaseSpinLock(&pWanAdapterCB->Lock);
+}
+
+PWAN_REQUEST
+GetWanRequest(
+ IN PWAN_ADAPTERCB pWanAdapterCB,
+ IN PNDIS_REQUEST pNdisRequest
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PWAN_REQUEST pReturnRequest;
+
+ NdisAcquireSpinLock(&pWanAdapterCB->Lock);
+
+ pReturnRequest = pWanAdapterCB->pWanRequest;
+
+ while (pReturnRequest != NULL) {
+ if (pReturnRequest->pNdisRequest == pNdisRequest) {
+ break;
+ }
+ pReturnRequest = pReturnRequest->pNext;
+ }
+
+ ASSERT (pReturnRequest != NULL);
+
+ NdisReleaseSpinLock(&pWanAdapterCB->Lock);
+
+ return (pReturnRequest);
+}
diff --git a/private/ntos/ndis/ndiswan/send.c b/private/ntos/ndis/ndiswan/send.c
new file mode 100644
index 000000000..1cf740be1
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/send.c
@@ -0,0 +1,3080 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ Send.c
+
+Abstract:
+
+ This file contains the procedures for doing a send from a protocol, bound
+ to the upper interface of NdisWan, to a Wan Miniport link, bound to the
+ lower interfaceof NdisWan. The upper interface of NdisWan conforms to the
+ NDIS 3.1 Miniport specification. The lower interface of NdisWan conforms
+ to the NDIS 3.1 Extentions for Wan Miniport drivers.
+
+Author:
+
+ Tony Bell (TonyBe) June 06, 1995
+
+Environment:
+
+ Kernel Mode
+
+Revision History:
+
+ TonyBe 06/06/95 Created
+
+--*/
+
+#include "wan.h"
+#include "tcpip.h"
+#include "vjslip.h"
+#include "compress.h"
+#include <rc4.h>
+
+#define EXTRA_COPY 1
+
+//
+// Local function prototypes
+//
+NDIS_STATUS
+FrameAndSend(
+ PBUNDLECB BundleCB,
+ PPROTOCOLCB ProtocolCB,
+ PNDIS_PACKET NdisPacket,
+ BOOLEAN DoMultilink,
+ PULONG BytesSent
+ );
+
+NDIS_STATUS
+SendPacketOnBundle(
+ PBUNDLECB BundleCB
+ );
+
+#ifdef BANDWIDTH_ON_DEMAND
+BOOLEAN
+IsProtocolQuotaFilled(
+ PPROTOCOLCB ProtocolCB
+ );
+
+VOID
+AgeSampleTable(
+ PSAMPLE_TABLE SampleTable
+ );
+
+VOID
+UpdateSampleTable(
+ PSAMPLE_TABLE SampleTable,
+ ULONG BytesSent
+ );
+
+BOOLEAN
+IsSampleTableFull(
+ PSAMPLE_TABLE SampleTable
+ );
+
+VOID
+UpdateBandwidthOnDemand(
+ PBUNDLECB BundleCB,
+ ULONG BytesSent
+ );
+VOID
+CheckUpperThreshold(
+ PBUNDLECB BundleCB
+ );
+
+VOID
+CheckLowerThreshold(
+ PBUNDLECB BundleCB
+ );
+
+#endif // end of BANDWIDTH_ON_DEMAND
+
+ULONG
+GetNumSendingLinks(
+ PBUNDLECB BundleCB
+ );
+
+PLINKCB
+GetNextLinkToXmitOn(
+ PBUNDLECB BundleCB
+ );
+
+VOID
+BuildLinkHeader(
+ PHEADER_FRAMING_INFO FramingInfo,
+ PUCHAR StartBuffer
+ );
+
+//VOID
+//AddPPPProtocolID(
+// PHEADER_FRAMING_INFO FramingInfo,
+// USHORT ProtocolID
+// );
+
+//VOID
+//AddMultilinkInfo(
+// PHEADER_FRAMING_INFO FramingInfo,
+// UCHAR Flags,
+// ULONG SequenceNumber,
+// ULONG SequenceMask
+// );
+
+//VOID
+//AddCompressionInfo(
+// PHEADER_FRAMING_INFO FramingInfo,
+// USHORT CoherencyCounter
+// );
+
+
+PNDIS_WAN_PACKET
+GetWanPacketFromLink(
+ PLINKCB LinkCB
+ );
+
+VOID
+ReturnWanPacketToLink(
+ PLINKCB LinkCB,
+ PNDIS_WAN_PACKET WanPacket
+ );
+
+VOID
+DestroyIoPacket(
+ PNDIS_PACKET NdisPacket
+ );
+
+#if DBG
+VOID
+InsertDbgPacket(
+ PDBG_SEND_CONTEXT DbgContext
+ );
+
+BOOLEAN
+RemoveDbgPacket(
+ PDBG_SEND_CONTEXT DbgContext
+ );
+#endif
+
+//
+// end of local function prototypes
+//
+
+NDIS_STATUS
+NdisWanSend(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN UINT Flags
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PADAPTERCB AdapterCB = (PADAPTERCB)MiniportAdapterContext;
+ ULONG BundleIndex = 0, ProtocolIndex = 0, BytesCopied = 0;
+ BOOLEAN SendOnWire;
+ PBUNDLECB BundleCB;
+ PPROTOCOLCB ProtocolCB;
+ PETH_HEADER EthernetHeader;
+ PUCHAR DestAddr, SrcAddr;
+ USHORT ProtocolType = AdapterCB->ProtocolType;
+ PNDIS_BUFFER FirstBuffer;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("NdisWanSend: Enter"));
+ NdisWanDbgOut(DBG_INFO, DBG_SEND, ("s-0x%8.8x, 0x%8.8x, 0x%8.8x", NdisPacket,
+ *((PULONG)&NdisPacket->WrapperReserved[0]), *((PULONG)&NdisPacket->WrapperReserved[4])));
+
+ NdisWanInterlockedInc(&AdapterCB->ulReferenceCount);
+
+ //
+ // Get the ethernet address. This is stolen from the
+ // NDIS wrapper code. This may be a Win95 portability issue.
+ //
+ FirstBuffer = NdisPacket->Private.Head;
+ EthernetHeader = (PETH_HEADER)MDL_ADDRESS(FirstBuffer);
+
+// NdisWanCopyFromPacketToBuffer(NdisPacket,
+// 0,
+// sizeof(ETH_HEADER),
+// (PUCHAR)&EthernetHeader,
+// &BytesCopied);
+
+// if (BytesCopied < ETH_LENGTH_OF_ADDRESS) {
+//
+// goto NdisWanSendExit;
+// }
+
+ DestAddr = EthernetHeader->DestAddr;
+ SrcAddr = EthernetHeader->SrcAddr;
+
+ //
+ // Is this destined for the wire or is it self directed?
+ // If SendOnWire is FALSE this is a self directed packet.
+ //
+ ETH_COMPARE_NETWORK_ADDRESSES_EQ(DestAddr, SrcAddr, &SendOnWire);
+
+ //
+ // Do we need to do loopback? We can check for both multicast
+ // and broadcast with one check because we don't differentiate
+ // between the two.
+ //
+ if (!SendOnWire || (DestAddr[0] & 1)) {
+
+ //
+ // Put on loopback queue
+ //
+ NdisWanQueueLoopbackPacket(AdapterCB, NdisPacket);
+
+ }
+
+ if (!SendOnWire || AdapterCB == NdisWanCB.PromiscuousAdapter) {
+
+ goto NdisWanSendExit;
+ }
+
+ //
+ // We play special tricks with NBF because NBF is
+ // guaranteed to have a one-to-one mapping between
+ // an adapter and a bundle.
+ //
+ if (AdapterCB->ProtocolType == PROTOCOL_NBF) {
+
+ BundleCB = AdapterCB->NbfBundleCB;
+
+ if (BundleCB == NULL) {
+ //
+ // This should just fall through and complete successfully.
+ //
+ NdisWanDbgOut(DBG_INFO, DBG_SEND,
+ ("NdisWanSend: BundleCB is NULL!, BundleHandle: 0x%8.8x", BundleIndex));
+ NdisWanDbgOut(DBG_INFO, DBG_SEND,
+ ("NdisWanSend: AdapterCB: 0x%8.8x, ProtocolType: 0x%4.4x!", AdapterCB, ProtocolType));
+
+ goto NdisWanSendExit;
+ }
+
+ ProtocolIndex = (ULONG)AdapterCB->NbfProtocolHandle;
+
+ } else {
+
+ //
+ // If this a multicast or broadcast our destination
+ // address context has been compromised. We have to
+ // lift the bundle information out of the SRC address.
+ //
+ //
+ if (DestAddr[0] & 1) {
+
+ //
+ // Get the stashed BundleIndex
+ //
+ GetTransportBundleIndex(SrcAddr, BundleIndex);
+
+ BUNDLECB_FROM_BUNDLEH(BundleCB, BundleIndex);
+
+ if (BundleCB == NULL) {
+ //
+ // This should just fall through and complete successfully.
+ //
+ NdisWanDbgOut(DBG_INFO, DBG_SEND,
+ ("NdisWanSend: BundleCB is NULL!, BundleHandle: 0x%8.8x", BundleIndex));
+ NdisWanDbgOut(DBG_INFO, DBG_SEND,
+ ("NdisWanSend: AdapterCB: 0x%8.8x, ProtocolType: 0x%4.4x!", AdapterCB, ProtocolType));
+
+ goto NdisWanSendExit;
+ }
+
+ //
+ // Get the ProtocolIndex from the BundleCB's
+ // list of protocols.
+ //
+ GetProtocolIndexFromProtocolList(&BundleCB->ProtocolCBList,
+ ProtocolType,
+ ProtocolIndex);
+
+ } else {
+
+ //
+ // Get the Bundle Index and BundleCB
+ //
+ GetNdisWanBundleIndex(DestAddr, BundleIndex);
+
+ BUNDLECB_FROM_BUNDLEH(BundleCB, BundleIndex);
+
+ if (BundleCB == NULL) {
+ //
+ // This should just fall through and complete successfully.
+ //
+ NdisWanDbgOut(DBG_INFO, DBG_SEND,
+ ("NdisWanSend: BundleCB is NULL!, BundleHandle: 0x%8.8x", BundleIndex));
+ NdisWanDbgOut(DBG_INFO, DBG_SEND,
+ ("NdisWanSend: AdapterCB: 0x%8.8x, ProtocolType: 0x%4.4x!", AdapterCB, ProtocolType));
+
+ goto NdisWanSendExit;
+ }
+
+ //
+ // Get the Protocol Index
+ //
+ GetNdisWanProtocolIndex(DestAddr, ProtocolIndex);
+ }
+ }
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ //
+ // Get the ProtocolCB from the BundleCB->ProtocolCBTable
+ //
+ ProtocolCBFromProtocolH(BundleCB, ProtocolIndex, ProtocolCB);
+
+ if ((BundleCB->State != BUNDLE_UP) || !(BundleCB->Flags & BUNDLE_ROUTED) ||
+ !IsValidProtocolCB(ProtocolCB) || !(ProtocolCB->Flags & PROTOCOL_ROUTED) ||
+ ProtocolCB->hProtocolHandle == 0) {
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+ NdisWanDbgOut(DBG_INFO, DBG_SEND,("NdisWanSend: Problem with route!"));
+
+ NdisWanDbgOut(DBG_INFO, DBG_SEND,
+ ("NdisWanSend: BundleCB: 0x%8.8x State: 0x%8.8x, Flags: 0x%8.8x",
+ BundleCB, BundleCB->State, BundleCB->Flags));
+
+ NdisWanDbgOut(DBG_INFO, DBG_SEND,
+ ("NdisWanSend: ProtocolCB: 0x%8.8x, ProtocolHandle: 0x%8.8x, Flags: 0x%8.8x",
+ ProtocolCB, ProtocolIndex, ProtocolCB->Flags));
+
+ goto NdisWanSendExit;
+ }
+
+ NdisWanInterlockedInc(&NdisWanCB.SendCount);
+
+#if DBG
+ {
+ DBG_SEND_CONTEXT DbgContext;
+ DbgContext.Packet = NdisPacket;
+ DbgContext.PacketType = PACKET_TYPE_NDIS;
+ DbgContext.BundleCB = BundleCB;
+ DbgContext.ProtocolCB = ProtocolCB;
+ DbgContext.LinkCB = NULL;
+ DbgContext.ListHead = &ProtocolCB->AdapterCB->DbgNdisPacketList;
+ DbgContext.ListLock = &ProtocolCB->AdapterCB->Lock;
+
+ InsertDbgPacket(&DbgContext);
+ }
+#endif
+
+ //
+ // Queue the packet on the ProtocolCB NdisPacketQueue
+ //
+ InsertTailNdisPacketQueue(ProtocolCB, NdisPacket);
+
+ //
+ // Try to send a packet on the BundleCB. Called
+ // with bundle lock held but returns with lock
+ // free.
+ //
+ Status = SendPacketOnBundle(BundleCB);
+
+ ASSERT (Status == NDIS_STATUS_PENDING);
+
+NdisWanSendExit:
+
+ NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("NdisWanSend: Exit, Status: 0x%8.8x", Status));
+
+ NdisWanInterlockedDec(&AdapterCB->ulReferenceCount);
+
+ return (Status);
+}
+
+VOID
+NdisWanSendCompleteHandler(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_WAN_PACKET WanPacket,
+ IN NDIS_STATUS Status
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+)
+{
+ PLINKCB LinkCB;
+ PBUNDLECB BundleCB;
+ PPROTOCOLCB ProtocolCB;
+ PWAN_IO_PROTOCOL_RESERVED ProtocolReserved;
+ PNDIS_PACKET NdisPacket;
+ BOOLEAN FreeLink = FALSE;
+ BOOLEAN FreeBundle = FALSE;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("NdisWanSendComplete: Enter"));
+ NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("WanPacket: 0x%8.8x", WanPacket));
+
+ //
+ // Get info from the WanPacket
+ //
+ LinkCB = (PLINKCB)WanPacket->ProtocolReserved1;
+ NdisPacket = (PNDIS_PACKET)WanPacket->ProtocolReserved2;
+ ProtocolCB = (PPROTOCOLCB)WanPacket->ProtocolReserved3;
+
+ NdisWanDbgOut(DBG_INFO, DBG_SEND, ("sc-0x%8.8x, 0x%8.8x, 0x%8.8x", NdisPacket,
+ *((PULONG)&NdisPacket->WrapperReserved[0]), *((PULONG)&NdisPacket->WrapperReserved[4])));
+
+ //
+ // Bundle that this link is on
+ //
+ BundleCB = LinkCB->BundleCB;
+
+#if DBG
+{
+ DBG_SEND_CONTEXT DbgContext;
+
+ DbgContext.Packet = WanPacket;
+ DbgContext.PacketType = PACKET_TYPE_WAN;
+ DbgContext.BundleCB = BundleCB;
+ DbgContext.ProtocolCB = ProtocolCB;
+ DbgContext.LinkCB = LinkCB;
+ DbgContext.ListHead = &LinkCB->WanAdapterCB->DbgWanPacketList;
+ DbgContext.ListLock = &LinkCB->WanAdapterCB->Lock;
+ RemoveDbgPacket(&DbgContext);
+}
+#endif
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ //
+ // Return the WanPacket to the link
+ //
+ ReturnWanPacketToLink(LinkCB, WanPacket);
+
+ //
+ // Update link stats
+ //
+
+ if ((--LinkCB->OutstandingFrames == 0) &&
+ (LinkCB->State == LINK_GOING_DOWN)) {
+
+ LinkCB->State = LINK_DOWN;
+
+ FreeLink = TRUE;
+
+ RemoveLinkFromBundle(BundleCB, LinkCB);
+
+ if (BundleCB->ulLinkCBCount == 0) {
+ BundleCB->State = BUNDLE_GOING_DOWN;
+ }
+ }
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ ASSERT((SHORT)PMINIPORT_RESERVED_FROM_NDIS(NdisPacket)->ReferenceCount > 0);
+
+ //
+ // See if the reference count is zero
+ //
+ if (--(PMINIPORT_RESERVED_FROM_NDIS(NdisPacket)->ReferenceCount)) {
+
+ //
+ // The reference count is not yet zero
+ //
+ return;
+ }
+
+ TryToCompleteNdisPacket(ProtocolCB->AdapterCB, NdisPacket);
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ //
+ // If this bundle is going away but is waiting on all outstanding frames
+ // we need to do cleanup.
+ //
+ if (--BundleCB->OutstandingFrames == 0) {
+
+ //
+ // If this bundle is going away but unroute is waiting on
+ // all outstanding frames we need to signal the waiting thread.
+ //
+ if (BundleCB->Flags & FRAMES_PENDING) {
+
+ NdisWanSetSyncEvent(&BundleCB->OutstandingFramesEvent);
+
+ } else if ((BundleCB->State == BUNDLE_GOING_DOWN) &&
+ !(BundleCB->Flags & BUNDLE_ROUTED)){
+
+ BundleCB->State = BUNDLE_DOWN;
+ FreeBundle = TRUE;
+ }
+ }
+
+ //
+ // Called with bundle lock help but returns with lock released
+ //
+ SendPacketOnBundle(BundleCB);
+
+ if (FreeLink) {
+ //
+ // Remove this link from the connection table
+ //
+ RemoveLinkFromConnectionTable(LinkCB);
+ NdisWanReturnLinkCB(LinkCB);
+ }
+
+ if (FreeBundle) {
+ //
+ // Remove this bundle from the connection table
+ //
+ RemoveBundleFromConnectionTable(BundleCB);
+ NdisWanReturnBundleCB(BundleCB);
+ }
+
+ NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("NdisWanSendComplete: Exit"));
+}
+
+VOID
+TryToCompleteNdisPacket(
+ PADAPTERCB AdapterCB,
+ PNDIS_PACKET NdisPacket
+ )
+{
+ //
+ // If this is a packet that we created we need to free the resources
+ //
+ if (PMINIPORT_RESERVED_FROM_NDIS(NdisPacket)->MagicNumber == NDISWAN_MAGIC_NUMBER) {
+
+ DestroyIoPacket(NdisPacket);
+
+ } else {
+ PDEFERRED_DESC DeferredDesc;
+
+ if ((AdapterCB->ulReferenceCount == 0) &&
+ NdisWanAcquireMiniportLock(AdapterCB)) {
+
+ NdisAcquireSpinLock(&AdapterCB->Lock);
+
+ if (IsDeferredQueueEmpty(&AdapterCB->DeferredQueue[SendComplete])) {
+
+ NdisReleaseSpinLock(&AdapterCB->Lock);
+
+#if DBG
+{
+ DBG_SEND_CONTEXT DbgContext;
+ DbgContext.Packet = NdisPacket;
+ DbgContext.PacketType = PACKET_TYPE_NDIS;
+ DbgContext.BundleCB = NULL;
+ DbgContext.ProtocolCB = NULL;
+ DbgContext.LinkCB = NULL;
+ DbgContext.ListHead = &AdapterCB->DbgNdisPacketList;
+ DbgContext.ListLock = &AdapterCB->Lock;
+ RemoveDbgPacket(&DbgContext);
+}
+#endif
+ //
+ // We got the lock and there are no pending send completes
+ // so go ahead and complete this one!
+ //
+ NdisMSendComplete(AdapterCB->hMiniportHandle,
+ NdisPacket,
+ NDIS_STATUS_SUCCESS);
+
+ //
+ // Increment global count
+ //
+ NdisWanInterlockedInc(&NdisWanCB.SendCompleteCount);
+
+ NdisWanReleaseMiniportLock(AdapterCB);
+
+ return;
+ }
+
+ NdisReleaseSpinLock(&AdapterCB->Lock);
+
+ NdisWanReleaseMiniportLock(AdapterCB);
+ }
+
+ NdisAcquireSpinLock(&AdapterCB->Lock);
+
+ NdisWanGetDeferredDesc(AdapterCB, &DeferredDesc);
+
+ DeferredDesc->Context = NdisPacket;
+
+ InsertTailDeferredQueue(&AdapterCB->DeferredQueue[SendComplete], DeferredDesc);
+
+ NdisWanSetDeferred(AdapterCB);
+
+ NdisReleaseSpinLock(&AdapterCB->Lock);
+ }
+}
+
+VOID
+NdisWanProcessSendCompletes(
+ PADAPTERCB AdapterCB
+ )
+{
+
+ while (!IsDeferredQueueEmpty(&AdapterCB->DeferredQueue[SendComplete])) {
+
+ PNDIS_PACKET NdisPacket;
+ PDEFERRED_DESC ReturnDesc;
+
+ ReturnDesc = RemoveHeadDeferredQueue(&AdapterCB->DeferredQueue[SendComplete]);
+
+ NdisReleaseSpinLock(&AdapterCB->Lock);
+
+ NdisPacket = ReturnDesc->Context;
+
+#if DBG
+{
+ DBG_SEND_CONTEXT DbgContext;
+ DbgContext.Packet = NdisPacket;
+ DbgContext.PacketType = PACKET_TYPE_NDIS;
+ DbgContext.BundleCB = NULL;
+ DbgContext.ProtocolCB = NULL;
+ DbgContext.LinkCB = NULL;
+ DbgContext.ListHead = &AdapterCB->DbgNdisPacketList;
+ DbgContext.ListLock = &AdapterCB->Lock;
+ RemoveDbgPacket(&DbgContext);
+}
+#endif
+ NdisMSendComplete(AdapterCB->hMiniportHandle,
+ NdisPacket,
+ NDIS_STATUS_SUCCESS);
+
+ //
+ // Increment global count
+ //
+ NdisWanInterlockedInc(&NdisWanCB.SendCompleteCount);
+
+ NdisAcquireSpinLock(&AdapterCB->Lock);
+
+ InsertHeadDeferredQueue(&AdapterCB->FreeDeferredQueue, ReturnDesc);
+ }
+}
+
+NDIS_STATUS
+SendPacketOnBundle(
+ PBUNDLECB BundleCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+ Called with bundle lock held but returns with lock released!!!
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_PENDING;
+ ULONG ulProtocolSending, BytesSent;
+ PLIST_ENTRY ProtocolCBList;
+ PPROTOCOLCB IOProtocolCB;
+ PPROTOCOLCB ProtocolCB;
+ BOOLEAN DoMultilink = TRUE;
+ PLINKCB LinkCB;
+#ifdef BANDWIDTH_ON_DEMAND
+ ULONG ulFirstTime;
+#endif
+
+ NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("SendPacketOnBundle: Enter"));
+
+ //
+ // Are we already involved in a send on this bundlecb?
+ //
+ if (BundleCB->Flags & IN_SEND) {
+
+ //
+ // If so flag that we should try back later
+ // and get the hell out.
+ //
+ BundleCB->Flags |= TRY_SEND_AGAIN;
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ return (NDIS_STATUS_PENDING);
+ }
+
+ BundleCB->Flags |= IN_SEND;
+
+ ProtocolCBList = &BundleCB->ProtocolCBList;
+ IOProtocolCB = (PPROTOCOLCB)ProtocolCBList->Flink;
+
+SendPacketOnBundleTryAgain:
+
+ //
+ // This contains a bit mask with a bit set for each possible send queue.
+ // To start off we will set all of the bits so each send queue will have
+ // a chance to send. If a send queue can send it just sets the bit in
+ // the mask so sends will continue to happen. If the send queue does not
+ // have anything to send the bit for that send queue is turned off. When
+ // all bits are turned off we will fall through the send loop.
+ //
+ ulProtocolSending = BundleCB->SendMask;
+
+#ifdef BANDWIDTH_ON_DEMAND
+ ulFirstTime = (ulProtocolSending & ~IOProtocolCB->SendMaskBit);
+#endif
+
+ if ((PVOID)(ProtocolCB = (PPROTOCOLCB)IOProtocolCB->Linkage.Flink) ==
+ (PVOID)ProtocolCBList) {
+ ProtocolCB = NULL;
+ }
+
+ //
+ // Stay in loop as long as we have protocols sending and endpoints
+ // accepting sends.
+ //
+
+ while (ulProtocolSending && (BundleCB->SendingLinks != 0)) {
+ PNDIS_PACKET NdisPacket;
+ PPROTOCOLCB SendingProtocolCB = NULL;
+ ULONG MagicNumber = 0;
+
+ //
+ // Always check to see if there is an I/O (PPP) packet to
+ // be sent!
+ //
+ if (!IsNdisPacketQueueEmpty(IOProtocolCB)) {
+ PWAN_IO_PROTOCOL_RESERVED pProtocolReserved;
+ PLINKCB LinkCB;
+
+ MagicNumber = NDISWAN_MAGIC_NUMBER;
+
+ NdisPacket = IOProtocolCB->HeadNdisPacketQueue;
+
+ pProtocolReserved = (PWAN_IO_PROTOCOL_RESERVED)NdisPacket->ProtocolReserved;
+
+ //
+ // Is this a directed PPP packet
+ //
+ if (((LinkCB = pProtocolReserved->LinkCB) == NULL) ||
+ (LinkCB->State != LINK_UP)) {
+
+ //
+ // The link has gone down since this send was
+ // queued so destroy the packet
+ //
+ RemoveHeadNdisPacketQueue(IOProtocolCB);
+ DestroyIoPacket(NdisPacket);
+ BundleCB->Flags |= TRY_SEND_AGAIN;
+ break;
+
+ }
+
+ if (!IsLinkSendWindowOpen(LinkCB)) {
+ //
+ // We can not send from the I/O queue because the send
+ // window for this link is closed. We will not send
+ // any data until the link has resources!
+ //
+ break;
+
+ }
+
+ BundleCB->NextLinkToXmit = LinkCB;
+ DoMultilink = FALSE;
+
+ //
+ // We are sending this packet so take it off of the list
+ //
+ RemoveHeadNdisPacketQueue(IOProtocolCB);
+
+ ulProtocolSending |= IOProtocolCB->SendMaskBit;
+
+ SendingProtocolCB = IOProtocolCB;
+
+ //
+ // End of I/O send check
+ //
+ } else {
+
+ ulProtocolSending &= ~IOProtocolCB->SendMaskBit;
+
+ //
+ // If there is not another protocol to check get out
+ //
+ if (ProtocolCB == NULL)
+ break;
+
+ if (!IsNdisPacketQueueEmpty(ProtocolCB)) {
+#ifdef BANDWIDTH_ON_DEMAND
+ BOOLEAN FirstPass;
+
+ FirstPass = (ulFirstTime != 0);
+
+ //
+ // Clear the first time bit. The entire mask will only be
+ // cleared when all of the protocols have had a chance to
+ // send at least once.
+ //
+ ulFirstTime &= ~ProtocolCB->SendMaskBit;
+
+ if (IsSampleTableFull(&ProtocolCB->SampleTable)) {
+
+ //
+ // We don't want this protocol to send again
+ // until its sampletable has an open entry so clear
+ // the protocols send bit.
+ //
+ ulProtocolSending &= ~ProtocolCB->SendMaskBit;
+ goto GetNextProtocolCB;
+ }
+
+ //
+ // We will send a packet from this protocol if it's bandwidth
+ // quota has not been met or if it's quota has been met we
+ // can still send if this is not the first time through the
+ // send loop (all other protocols have had a change to send).
+ //
+ if (IsProtocolQuotaFilled(ProtocolCB) && FirstPass) {
+
+ goto GetNextProtocolCB;
+ }
+#endif // end of BANDWIDTH_ON_DEMAND
+
+ ulProtocolSending |= ProtocolCB->SendMaskBit;
+
+ NdisPacket = RemoveHeadNdisPacketQueue(ProtocolCB);
+
+ SendingProtocolCB = ProtocolCB;
+
+ } else {
+
+ //
+ // Protocol does not have anything to send so mark it
+ // and get the next protocol.
+ //
+ ulProtocolSending &= ~ProtocolCB->SendMaskBit;
+
+#ifdef BANDWIDTH_ON_DEMAND
+ ulFirstTime &= ~ProtocolCB->SendMaskBit;
+#endif
+ goto GetNextProtocolCB;
+
+ }
+ }
+
+ ASSERT(NdisPacket != NULL);
+ ASSERT(SendingProtocolCB != NULL);
+
+ //
+ // We we get here we should have a valid NdisPacket with at least one link
+ // that is accepting sends
+ //
+
+ //
+ // The magic number is only set to a non-zero value if this is a send
+ // through our I/O interface.
+ //
+ PMINIPORT_RESERVED_FROM_NDIS(NdisPacket)->MagicNumber = MagicNumber;
+
+ //
+ // We will get the packet into a contiguous buffer, and do framing,
+ // compression and encryption. This is called with the bundle lock
+ // held and returns with it released.
+ //
+ Status = FrameAndSend(BundleCB,
+ SendingProtocolCB,
+ NdisPacket,
+ DoMultilink,
+ &BytesSent);
+
+#ifdef BANDWIDTH_ON_DEMAND
+ //
+ // Update this protocols sample array with the latest send.
+ //
+ UpdateProtocolQuota(SendingProtocolCB, BytesSent);
+
+ //
+ // Update the bandwidth on demand sample array with the latest send.
+ // If we need to notify someone of a bandwidth event do it.
+ //
+ UpdateBandwidthOnDemand(BundleCB, BytesSent);
+#endif
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ //
+ // This will force round-robin sends if no protocol
+ // prioritization has been set.
+ //
+#ifdef BANDWIDTH_ON_DEMAND
+
+ if (!(BundleCB->Flags & PROTOCOL_PRIORITY) &&
+ (ProtocolCB != NULL)) {
+
+#else // end of BANDWIDTH_ON_DEMAND
+
+ if (ProtocolCB != NULL) {
+
+#endif // end of !BANDWIDTH_ON_DEMAND
+
+GetNextProtocolCB:
+
+ if ((PVOID)(ProtocolCB = (PPROTOCOLCB)ProtocolCB->Linkage.Flink) ==
+ (PVOID)ProtocolCBList) {
+ ProtocolCB = (PPROTOCOLCB)IOProtocolCB->Linkage.Flink;
+ }
+ }
+
+ } // end of the send while loop
+
+ //
+ // Did someone try to do a send while we were already
+ // sending on this bundle?
+ //
+ if (BundleCB->Flags & TRY_SEND_AGAIN) {
+
+ //
+ // If so clear the flag and try another send.
+ //
+ BundleCB->Flags &= ~TRY_SEND_AGAIN;
+ goto SendPacketOnBundleTryAgain;
+ }
+
+ //
+ // Clear the in send flag.
+ //
+ BundleCB->Flags &= ~IN_SEND;
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("SendPacketOnBundle: Exit"));
+
+ return (Status);
+}
+
+NDIS_STATUS
+FrameAndSend(
+ PBUNDLECB BundleCB,
+ PPROTOCOLCB ProtocolCB,
+ PNDIS_PACKET NdisPacket,
+ BOOLEAN DoMultilink,
+ PULONG BytesSent
+ )
+/*++
+
+Routine Name:
+
+ FrameAndSend
+
+Routine Description:
+
+ This routine does all of the data manipulation required to take the
+ NdisPacket and make it into the appropriate number of WanPackets. These
+ WanPackets will be queued on a list on their linkcbs. The manipulation
+ that occurs includes getting the data from the ndispacket into a contiguous
+ buffer, protocol header compression, data compression, data encryption,
+ PPP framing, multilink fragmentation and framing.
+
+ Called with bundle lock held but returns with lock released!!!
+
+ A finished frame will look like
+
+ PPPHeader
+ ProtocolHeader
+ Data
+
+Arguments:
+
+ BundleCB - Pointer to the BundleCB that we are sending over
+ ProtocolCB - Pointer to the ProtocolCB that this send is for
+ NdisPacket - Pointer to the NdisPacket that is being sent
+
+Return Values:
+
+ NDIS_STATUS_SUCCESS
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ ULONG BytesCopied, PacketDataOffset;
+ ULONG FragmentsLeft, FragmentsSent, DataLeft;
+ PWAN_STATS BundleStats = &BundleCB->BundleStats;
+ USHORT PPPProtocolID = ProtocolCB->usPPPProtocolID;
+
+ //
+ // Framing information flags
+ //
+ ULONG BundleFraming = BundleCB->FramingInfo.SendFramingBits;
+ ULONG LinkFraming;
+
+ //
+ // This is the next link to be transmitted over
+ //
+ PLINKCB LinkCB;
+
+ //
+ // These are pointers to the active WanPacket and
+ // data buffer.
+ //
+ // WanPacket points to the active WanPacket
+ // StartBuffer points to the begining of the frame
+ // DataBuffer points to where the data begins in the frame
+ // FrameLength is the length of the frame
+ // DataLength is the length of the data
+ //
+ PNDIS_WAN_PACKET WanPacket;
+ PUCHAR StartBuffer, CurrentBuffer, DataBuffer;
+ ULONG DataLength = 0;
+
+ //
+ // These are points to the second WanPacket and
+ // data buffer. These are used to compress into
+ // if compression is on.
+ //
+ // WanPacket2 points to the WanPacket used if compression occurs
+ // PacketNotUsed points to the WanPacket that is to be returned
+ // StartBuffer2 points to the begining of the data buffer in WanPacket2
+ //
+ PNDIS_WAN_PACKET WanPacket2, PacketNotUsed;
+ PUCHAR StartBuffer2, CurrentBuffer2, DataBuffer2;
+
+ //
+ // Flags set to make decisions on whether to compress and/or encrypt the data
+ //
+ ULONG Flags;
+
+ BOOLEAN FirstFragment = TRUE;
+
+ //
+ // Used to gather information about the link header
+ //
+ HEADER_FRAMING_INFO FramingInfo1, FramingInfo2;
+ PHEADER_FRAMING_INFO FramingInfo = &FramingInfo1;
+
+ ULONG ProtocolHeaderLength;
+ UCHAR ProtocolBuffer[40];
+ PUCHAR ProtocolHeader = ProtocolBuffer;
+
+ ULONG EthernetHeaderLength;
+#ifdef EXTRA_COPY
+ PUCHAR EthernetHeader;
+#else
+ UCHAR EthernetHeader[12];
+#endif
+
+ NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("FrameAndSend: Enter"));
+
+ //
+ // Clear out the bytes sent count
+ //
+ *BytesSent = 0;
+
+ //
+ // Get the next link to xmit on.
+ //
+ LinkCB = GetNextLinkToXmitOn(BundleCB);
+
+ ASSERT(LinkCB != NULL);
+
+ ASSERT(IsLinkSendWindowOpen(LinkCB));
+
+ //
+ // Set flags for compression, encryption and multilink
+ //
+ Flags = ((BundleCB->SendCompInfo.MSCompType & NDISWAN_COMPRESSION) &&
+ (BundleCB->SendCompressContext != NULL)) ? DO_COMPRESSION : 0;
+
+ if (BundleCB->SendRC4Key != NULL) {
+ if (BundleCB->SendCompInfo.MSCompType & NDISWAN_ENCRYPTION) {
+ Flags |= (DO_ENCRYPTION | DO_LEGACY_ENCRYPTION);
+ } else if (BundleCB->SendCompInfo.MSCompType & NDISWAN_40_ENCRYPTION) {
+ Flags |= (DO_ENCRYPTION | DO_40_ENCRYPTION);
+ }
+#ifdef ENCRYPT_128BIT
+ else if (BundleCB->SendCompInfo.MSCompType & NDISWAN_128_ENCRYPTION) {
+ Flags |= (DO_ENCRYPTION | DO_128_ENCRYPTION);
+ }
+#endif
+ }
+
+ Flags |= (DoMultilink && (BundleFraming & PPP_FRAMING) &&
+ (BundleFraming & PPP_MULTILINK_FRAMING)) ? DO_MULTILINK : 0;
+
+ if (PPPProtocolID == PPP_PROTOCOL_PRIVATE_IO) {
+ Flags |= IO_PROTOCOLID;
+ Flags &= ~(DO_COMPRESSION | DO_ENCRYPTION);
+ }
+
+ Flags |= FIRST_FRAGMENT;
+
+ //
+ // Did the last receive cause us to flush?
+ //
+ if (BundleCB->Flags & RECV_PACKET_FLUSH) {
+ BundleCB->Flags &= ~RECV_PACKET_FLUSH;
+ Flags |= DO_FLUSH;
+ }
+
+ FramingInfo->FramingBits =
+ LinkFraming = LinkCB->LinkInfo.SendFramingBits;
+ FramingInfo->Flags = Flags;
+
+ //
+ // Bump the outstanding frames on the bundle
+ //
+ BundleCB->OutstandingFrames++;
+
+ //
+ // If we are in promiscuous mode we should indicate this
+ // baby back up.
+ //
+ if (NdisWanCB.PromiscuousAdapter != NULL) {
+ NdisWanQueueLoopbackPacket(NdisWanCB.PromiscuousAdapter, NdisPacket);
+ }
+
+ //
+ // See if we are in pass through mode
+ //
+ if (!(BundleFraming & PASS_THROUGH_MODE) &&
+ !(BundleFraming & RAW_PASS_THROUGH_MODE)) {
+
+ //
+ // Get two wanpackets from the next to send link.
+ //
+ WanPacket = GetWanPacketFromLink(LinkCB);
+ PacketNotUsed =
+ WanPacket2 = GetWanPacketFromLink(LinkCB);
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ //
+ // This is where we will build the frame. This needs to be
+ // on a 8 byte boundary.
+ //
+ StartBuffer = WanPacket->StartBuffer +
+ LinkCB->LinkInfo.HeaderPadding +
+ sizeof(PVOID);
+
+ (ULONG)StartBuffer &= (ULONG)~(sizeof(PVOID) - 1);
+
+ //
+ // This is where we will build the frame. This needs to be
+ // on a 8 byte boundary.
+ //
+ StartBuffer2 = WanPacket2->StartBuffer +
+ LinkCB->LinkInfo.HeaderPadding +
+ sizeof(PVOID);
+
+ (ULONG)StartBuffer2 &= (ULONG)~(sizeof(PVOID) - 1);
+
+ BuildLinkHeader(FramingInfo, StartBuffer);
+
+ FramingInfo2.FramingBits = FramingInfo->FramingBits;
+ FramingInfo2.Flags = FramingInfo->Flags;
+
+ BuildLinkHeader(&FramingInfo2, StartBuffer2);
+
+ DataBuffer =
+ CurrentBuffer = StartBuffer + FramingInfo->HeaderLength;
+
+ DataBuffer2 =
+ CurrentBuffer2 = StartBuffer2 + FramingInfo->HeaderLength;
+
+ //
+ // If this is a netbios frame and we have to ship the mac header
+ //
+ if ((BundleFraming & NBF_PRESERVE_MAC_ADDRESS) &&
+ (PPPProtocolID == PPP_PROTOCOL_NBF)) {
+
+#ifdef EXTRA_COPY
+
+ EthernetHeader = CurrentBuffer;
+
+#endif
+
+ //
+ // Copy Ethernet header to temp buffer
+ //
+ NdisWanCopyFromPacketToBuffer(NdisPacket,
+ 0,
+ 12,
+ EthernetHeader,
+ &BytesCopied);
+ ASSERT(BytesCopied == 12);
+
+ CurrentBuffer += BytesCopied;
+ DataLength += BytesCopied;
+
+ EthernetHeaderLength = BytesCopied;
+ }
+
+ //
+ // We are beyond the mac header (also skip the length/protocoltype field)
+ //
+ if (PPPProtocolID == PPP_PROTOCOL_PRIVATE_IO) {
+ PacketDataOffset = 12;
+ } else {
+ PacketDataOffset = 14;
+ }
+
+ //
+ // Do protocol header compression - IP only!
+ //
+ if ((PPPProtocolID == PPP_PROTOCOL_IP) &&
+ (BundleCB->VJCompress != NULL) &&
+ ((BundleFraming & SLIP_VJ_COMPRESSION) || (BundleFraming & PPP_FRAMING))) {
+ UCHAR CompType = TYPE_IP;
+
+ BundleStats->BytesTransmittedUncompressed += 40;
+
+ //
+ // Get the protocol header
+ //
+ NdisWanCopyFromPacketToBuffer(NdisPacket,
+ PacketDataOffset,
+ 40,
+ ProtocolHeader,
+ &ProtocolHeaderLength);
+
+
+ PacketDataOffset += ProtocolHeaderLength;
+
+ NdisWanDbgOut(DBG_INFO, DBG_SEND_VJ,
+ ("svj %d", ProtocolHeaderLength));
+
+ //
+ // Are we compressing TCP/IP headers? There is a nasty
+ // hack in VJs implementation for attempting to detect
+ // interactive TCP/IP sessions. That is, telnet, login,
+ // klogin, eklogin, and ftp sessions. If detected,
+ // the traffic gets put on a higher TypeOfService (TOS). We do
+ // no such hack for RAS. Also, connection ID compression
+ // is negotiated, but we always don't compress it.
+ //
+ CompType = sl_compress_tcp(&ProtocolHeader,
+ &ProtocolHeaderLength,
+ BundleCB->VJCompress,
+ 0);
+
+
+ if (BundleFraming & SLIP_VJ_COMPRESSION) {
+
+ //
+ // For SLIP, the upper bits of the first byte
+ // are for VJ header compression control bits
+ //
+ ProtocolHeader[0] |= CompType;
+ }
+
+
+#ifdef EXTRA_COPY
+
+ NdisMoveMemory(CurrentBuffer, ProtocolHeader, ProtocolHeaderLength);
+
+ CurrentBuffer += ProtocolHeaderLength;
+ DataLength += ProtocolHeaderLength;
+#else
+
+#endif
+ NdisWanDbgOut(DBG_INFO, DBG_SEND_VJ,
+ ("svj %2.2x %d",CompType, ProtocolHeaderLength));
+
+ BundleStats->BytesTransmittedCompressed += ProtocolHeaderLength;
+
+
+ switch (CompType) {
+ case TYPE_IP:
+ PPPProtocolID = PPP_PROTOCOL_IP;
+ break;
+
+ case TYPE_UNCOMPRESSED_TCP:
+ PPPProtocolID = PPP_PROTOCOL_UNCOMPRESSED_TCP;
+ break;
+
+ case TYPE_COMPRESSED_TCP:
+ PPPProtocolID = PPP_PROTOCOL_COMPRESSED_TCP;
+ break;
+
+ default:
+ DbgBreakPoint();
+ break;
+ }
+
+ }
+
+#ifdef EXTRA_COPY
+ //
+ // Copy the rest of the data from the ndis packet to
+ // a contiguous buffer
+ //
+ NdisWanCopyFromPacketToBuffer(NdisPacket,
+ PacketDataOffset,
+ 0xFFFFFFFF,
+ CurrentBuffer,
+ &BytesCopied);
+
+ DataLength += BytesCopied;
+#endif
+
+ //
+ // Add the PPP Protocol ID to the PPP header
+ //
+ AddPPPProtocolID(FramingInfo, PPPProtocolID);
+
+ //
+ // At this point we have our framinginfo structure created
+ // StartBuffer points to the begining of the frame, DataBuffer
+ // points to the place where the data starts in the frame,
+ // DataLength is the length of the data in the frame.
+ //
+
+ //
+ // If compression and/or encryption is on and this is not a PPP CP frame do
+ // data compression.
+ //
+ if (Flags & (DO_COMPRESSION | DO_ENCRYPTION)) {
+ union {
+ USHORT uShort;
+ UCHAR uChar[2];
+ }CoherencyCounter;
+
+ //
+ // If we are compressing/encrypting, the ProtocolID
+ // is part of the compressed data so fix the pointer
+ // and the length;
+ //
+ DataBuffer -= FramingInfo->ProtocolID.Length;
+ DataBuffer2 -= FramingInfo->ProtocolID.Length;
+
+ DataLength += FramingInfo->ProtocolID.Length;
+ FramingInfo->HeaderLength -= FramingInfo->ProtocolID.Length;
+
+ //
+ // Get the coherency counter
+ //
+ CoherencyCounter.uShort = BundleCB->SCoherencyCounter;
+ CoherencyCounter.uChar[1] &= 0x0F;
+
+ //
+ // Bump the coherency count
+ //
+ BundleCB->SCoherencyCounter++;
+
+ if (Flags & DO_COMPRESSION) {
+
+ BundleStats->BytesTransmittedUncompressed += DataLength;
+
+ if (Flags & DO_FLUSH) {
+ //
+ // Init the compression history table and tree
+ //
+ initsendcontext(BundleCB->SendCompressContext);
+ }
+
+#ifdef EXTRA_COPY
+
+ //
+ // We are doing the copy to get things into a contiguous buffer before
+ // compression occurs
+ //
+ CoherencyCounter.uChar[1] |= compress(DataBuffer,
+ DataBuffer2,
+ &DataLength,
+ BundleCB->SendCompressContext);
+
+#else
+
+ //
+ // Compression will occur on fragments. We are not doing a copy
+ // to get things into a contiguous buffer before compressing
+ //
+
+ //
+ // If we need to include the ethernet header, compress it
+ //
+
+ //
+ // If we have a compressed protocol header, compress it again
+ //
+
+ //
+ // Now we need to walk the NdisBuffer chain compressing each
+ // buffer as we go. We need to get to the buffer where our
+ // current DataOffset is. Once we get to this buffer we will
+ // compress what is left of the buffer. We then go into a loop
+ // that walks the rest of the buffers in the buffer chain.
+ //
+#endif
+
+ if (CoherencyCounter.uChar[1] & PACKET_FLUSHED) {
+
+ //
+ // If encryption is enabled this will force a
+ // reinit of the table
+ //
+ Flags |= DO_FLUSH;
+
+ } else {
+ //
+ // We compressed the packet so now the active WanPacket will be
+ // WanPacket2. We need to copy the PPP header from WanPacket to
+ // WanPacket2. The header includes everything except for the
+ // protocolid field.
+ //
+
+ NdisMoveMemory(StartBuffer2,
+ StartBuffer,
+ FramingInfo->HeaderLength - FramingInfo->ProtocolID.Length);
+
+ //
+ // Now WanPacket2 and all of it's relevant pointers
+ // and structures are active.
+ //
+ PacketNotUsed = WanPacket;
+ WanPacket = WanPacket2;
+ DataBuffer = DataBuffer2;
+ StartBuffer = StartBuffer2;
+ FramingInfo = &FramingInfo2;
+ FramingInfo->HeaderLength -= FramingInfo->ProtocolID.Length;
+ }
+
+ BundleStats->BytesTransmittedCompressed += DataLength;
+ }
+
+ //
+ // Do data encryption
+ //
+ if (Flags & DO_ENCRYPTION) {
+ PUCHAR SessionKey = BundleCB->SendEncryptInfo.SessionKey;
+ ULONG SessionKeyLength = BundleCB->SendEncryptInfo.SessionKeyLength;
+ PVOID SendRC4Key = BundleCB->SendRC4Key;
+
+ //
+ // We may need to reinit the rc4 table
+ //
+ if (Flags & DO_FLUSH) {
+ rc4_key(SendRC4Key, SessionKeyLength, SessionKey);
+ }
+
+ //
+ // Mark this as being encrypted
+ //
+ CoherencyCounter.uChar[1] |= PACKET_ENCRYPTED;
+
+ //
+ // Every 256 frames change the RC4 session key
+ //
+ if ((BundleCB->SCoherencyCounter & 0xFF) == 0) {
+
+ if (Flags & DO_LEGACY_ENCRYPTION) {
+ //
+ // Simple munge for legacy encryption
+ //
+ SessionKey[3] += 1;
+ SessionKey[4] += 3;
+ SessionKey[5] += 13;
+ SessionKey[6] += 57;
+ SessionKey[7] += 19;
+
+ } else {
+
+ //
+ // Use SHA to get new sessionkey
+ //
+ GetNewKeyFromSHA(&BundleCB->SendEncryptInfo);
+
+ }
+
+ //
+ // We use rc4 to scramble and recover a new key
+ //
+
+ //
+ // Re-initialize the rc4 receive table to the
+ // intermediate value
+ //
+ rc4_key(SendRC4Key, SessionKeyLength, SessionKey);
+
+ //
+ // Scramble the existing session key
+ //
+ rc4(SendRC4Key, SessionKeyLength, SessionKey);
+
+ //
+ // If this is 40 bit encryption we need to fix
+ // the first 3 bytes of the key.
+ //
+#ifdef ENCRYPT_128BIT
+ if (!(Flags & DO_128_ENCRYPTION)) {
+
+#endif
+ //
+ // Re-Salt the first 3 bytes
+ //
+ SessionKey[0] = 0xD1;
+ SessionKey[1] = 0x26;
+ SessionKey[2] = 0x9E;
+
+#ifdef ENCRYPT_128BIT
+ }
+
+#endif
+ NdisWanDbgOut(DBG_TRACE, DBG_CCP,
+ ("RC4 Send encryption KeyLength %d", BundleCB->SendEncryptInfo.SessionKeyLength));
+ NdisWanDbgOut(DBG_TRACE, DBG_CCP,
+ ("RC4 Send encryption Key %.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x",
+ BundleCB->SendEncryptInfo.SessionKey[0],
+ BundleCB->SendEncryptInfo.SessionKey[1],
+ BundleCB->SendEncryptInfo.SessionKey[2],
+ BundleCB->SendEncryptInfo.SessionKey[3],
+ BundleCB->SendEncryptInfo.SessionKey[4],
+ BundleCB->SendEncryptInfo.SessionKey[5],
+ BundleCB->SendEncryptInfo.SessionKey[6],
+ BundleCB->SendEncryptInfo.SessionKey[7],
+ BundleCB->SendEncryptInfo.SessionKey[8],
+ BundleCB->SendEncryptInfo.SessionKey[9],
+ BundleCB->SendEncryptInfo.SessionKey[10],
+ BundleCB->SendEncryptInfo.SessionKey[11],
+ BundleCB->SendEncryptInfo.SessionKey[12],
+ BundleCB->SendEncryptInfo.SessionKey[13],
+ BundleCB->SendEncryptInfo.SessionKey[14],
+ BundleCB->SendEncryptInfo.SessionKey[15]));
+
+ //
+ // Re-initialize the rc4 receive table to the
+ // scrambled session key
+ //
+ rc4_key(SendRC4Key, SessionKeyLength, SessionKey);
+
+ }
+
+ //
+ // Encrypt the data
+ //
+ rc4(SendRC4Key, DataLength, DataBuffer);
+
+ }
+
+
+ //
+ // Did the last receive cause us to flush?
+ //
+ if (Flags & DO_FLUSH) {
+ CoherencyCounter.uChar[1] |= PACKET_FLUSHED;
+ }
+
+ //
+ // Add the coherency bytes to the frame
+ //
+ AddCompressionInfo(FramingInfo, CoherencyCounter.uShort);
+
+ ASSERT(((CoherencyCounter.uShort + 1) & 0x0FFF) ==
+ (BundleCB->SCoherencyCounter & 0x0FFF));
+ }
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ //
+ // Return the unused wanpacket to the pool
+ //
+ ReturnWanPacketToLink(LinkCB, PacketNotUsed);
+
+ //
+ // At this point we have our framinginfo structure initialized,
+ // StartBuffer pointing to the begining of the frame, DataBuffer
+ // pointing to the begining of the data, DataLength is the
+ // length of the data.
+ //
+ FragmentsLeft = BundleCB->SendingLinks;
+ DataLeft = DataLength;
+ FragmentsSent = 0;
+ FirstFragment = TRUE;
+
+ //
+ // For all fragments we loop fixing up the multilink header
+ // if multilink is on, fixing up pointers in the wanpacket,
+ // and queuing the wanpackets for further processing.
+ //
+ while (DataLeft) {
+ ULONG FragDataLength;
+ ULONG LinkBandwidth;
+
+ if (!FirstFragment) {
+
+ //
+ // We had more than one fragment, get the next
+ // link to send over and a wanpacket from the
+ // link.
+ //
+
+ LinkCB = GetNextLinkToXmitOn(BundleCB);
+
+ ASSERT(IsLinkSendWindowOpen(LinkCB));
+
+ WanPacket = GetWanPacketFromLink(LinkCB);
+
+ //
+ // This is where we will build the frame. This needs to be
+ // on a 8 byte boundary.
+ //
+ StartBuffer = WanPacket->StartBuffer +
+ LinkCB->LinkInfo.HeaderPadding +
+ sizeof(PVOID);
+
+ (ULONG)StartBuffer &= (ULONG)~(sizeof(PVOID) - 1);
+
+ //
+ // Get new framing information and build a new
+ // header for the new link.
+ //
+ FramingInfo->FramingBits =
+ LinkFraming = LinkCB->LinkInfo.SendFramingBits;
+
+ FramingInfo->Flags = (DoMultilink) ? DO_MULTILINK : 0;
+
+ BuildLinkHeader(FramingInfo, StartBuffer);
+ }
+
+ LinkBandwidth = LinkCB->ulBandwidth;
+
+ if ((Flags & DO_MULTILINK) && (FragmentsLeft > 1) &&
+ (LinkBandwidth < 85)) {
+
+ //
+ // Calculate the length of this fragment
+ //
+ FragDataLength = (DataLength * LinkBandwidth / 100);
+
+ FragDataLength = (FragDataLength < NdisWanCB.ulMinFragmentSize) ?
+ NdisWanCB.ulMinFragmentSize : FragDataLength;
+
+ if ((FragDataLength > DataLeft) ||
+ ((LONG)DataLeft - FragDataLength < NdisWanCB.ulMinFragmentSize)) {
+ //
+ // This will leave a fragment of less than min frag size
+ // so send all of the data
+ //
+ FragDataLength = DataLeft;
+ FragmentsLeft = 1;
+ }
+
+
+ } else {
+ //
+ // We either have one fragment left or this link has
+ // more than 85 percent of the bundle so send what
+ // data is left
+ //
+ FragDataLength = DataLeft;
+ FragmentsLeft = 1;
+ }
+
+ if (!FirstFragment) {
+ //
+ // Copy the data to the new buffer from the old buffer.
+ //
+ NdisMoveMemory(StartBuffer + FramingInfo->HeaderLength,
+ DataBuffer,
+ FragDataLength);
+
+ }
+
+ //
+ // Update the data pointer and the length left to send
+ //
+ DataBuffer += FragDataLength;
+ DataLeft -= FragDataLength;
+
+ if (Flags & DO_MULTILINK) {
+ UCHAR MultilinkFlags = 0;
+
+
+ //
+ // Multlink is on so create flags for this
+ // fragment.
+ //
+ if (FirstFragment) {
+ MultilinkFlags = MULTILINK_BEGIN_FRAME;
+ FirstFragment = FALSE;
+ }
+
+ if (FragmentsLeft == 1) {
+ MultilinkFlags |= MULTILINK_END_FRAME;
+ }
+
+ //
+ // Add the multilink header information and
+ // take care of the sequence number.
+ //
+ AddMultilinkInfo(FramingInfo,
+ MultilinkFlags,
+ BundleCB->SendSeqNumber,
+ BundleCB->SendSeqMask);
+
+ NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_SEND, ("sf %8.8x %8.8x %d",
+ BundleCB->SendSeqNumber, MultilinkFlags, FragDataLength));
+
+ BundleCB->SendSeqNumber++;
+
+ }
+
+ //
+ // Initialize the WanPacket
+ //
+ WanPacket->CurrentBuffer = StartBuffer;
+ WanPacket->CurrentLength = FragDataLength + FramingInfo->HeaderLength;
+
+ WanPacket->ProtocolReserved1 = (PVOID)LinkCB;
+ WanPacket->ProtocolReserved2 = (PVOID)NdisPacket;
+ WanPacket->ProtocolReserved3 = (PVOID)ProtocolCB;
+
+ NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_SEND,
+ ("l %8.8x %8.8x", LinkCB->hLinkHandle));
+ //
+ // Add up the bytes that we are sending over all
+ // links in this bundle.
+ //
+ *BytesSent += WanPacket->CurrentLength;
+
+ //
+ // Queue for further processing.
+ //
+ InsertTailList(&BundleCB->SendPacketQueue, &WanPacket->WanPacketQueue);
+
+ FragmentsSent++;
+ FragmentsLeft--;
+
+ } // end of the fragment loop
+
+ ASSERT(FragmentsLeft == 0);
+
+ //
+ // Get the mac reserved structure from the ndispacket. This
+ // is where we will keep the reference count on the packet.
+ //
+ ASSERT((LONG)FragmentsSent > 0 && FragmentsSent <= BundleCB->ulLinkCBCount);
+ PMINIPORT_RESERVED_FROM_NDIS(NdisPacket)->ReferenceCount = (USHORT)FragmentsSent;
+
+ BundleCB->BundleStats.FramesTransmitted++;
+
+ //
+ // At this point we have a list of wanpackets that need to be sent,
+ // update the total bytes associated with this send, and send
+ // the packets over their links.
+ //
+ while (!IsListEmpty(&BundleCB->SendPacketQueue)) {
+ Status = NDIS_STATUS_SUCCESS;
+
+ //
+ // Get the wanpacket off of the list
+ //
+ WanPacket = (PNDIS_WAN_PACKET)RemoveHeadList(&BundleCB->SendPacketQueue);
+
+ //
+ // Get the link to send over
+ //
+ LinkCB = WanPacket->ProtocolReserved1;
+
+ //
+ // Update the outstanding frames on the link
+ //
+ LinkCB->LinkStats.FramesTransmitted++;
+ LinkCB->LinkStats.BytesTransmitted += WanPacket->CurrentLength;
+ BundleCB->BundleStats.BytesTransmitted += WanPacket->CurrentLength;
+
+#if DBG
+ {
+ DBG_SEND_CONTEXT DbgContext;
+ DbgContext.Packet = WanPacket;
+ DbgContext.PacketType = PACKET_TYPE_WAN;
+ DbgContext.BundleCB = BundleCB;
+ DbgContext.ProtocolCB = ProtocolCB;
+ DbgContext.LinkCB = LinkCB;
+ DbgContext.ListHead = &LinkCB->WanAdapterCB->DbgWanPacketList;
+ DbgContext.ListLock = &LinkCB->WanAdapterCB->Lock;
+
+ InsertDbgPacket(&DbgContext);
+ }
+#endif
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ //
+ // If the link is up send the packet
+ //
+ if (LinkCB->State == LINK_UP) {
+
+
+ NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("FrameAndSend: LinkCB: 0x%8.8x, WanPacket: 0x%8.8x", LinkCB, WanPacket));
+
+ WanMiniportSend(&Status,
+ LinkCB->WanAdapterCB->hNdisBindingHandle,
+ LinkCB->LineUpInfo.NdisLinkHandle,
+ WanPacket);
+
+ NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("FrameAndSend: Status: 0x%8.8x", Status));
+ }
+
+ //
+ // If we get something other than pending back we need to
+ // do the send complete.
+ //
+ if (Status != NDIS_STATUS_PENDING) {
+
+ NdisWanSendCompleteHandler(NULL,
+ WanPacket,
+ NDIS_STATUS_SUCCESS);
+
+ Status = NDIS_STATUS_PENDING;
+ }
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+ }
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ } else {
+ //
+ // We need to get a WanPacket
+ //
+ WanPacket = GetWanPacketFromLink(LinkCB);
+
+ NdisReleaseSpinLock(&BundleCB->Lock);
+
+ //
+ // Copy the data into the WanPacket
+ //
+ //
+ // This is where we will build the frame. This needs to be
+ // on a 8 byte boundary.
+ //
+ StartBuffer = WanPacket->StartBuffer +
+ LinkCB->LinkInfo.HeaderPadding +
+ sizeof(PVOID);
+
+ (ULONG)StartBuffer &= (ULONG)~(sizeof(PVOID) - 1);
+
+ NdisWanCopyFromPacketToBuffer(NdisPacket,
+ 0,
+ 0xFFFFFFFF,
+ StartBuffer,
+ &BytesCopied);
+
+ //
+ // If we are in pass through mode set the protocol type
+ //
+ if (BundleFraming & PASS_THROUGH_MODE) {
+ StartBuffer[12] = (UCHAR)(ProtocolCB->usProtocolType << 8);
+ StartBuffer[13] = (UCHAR)ProtocolCB->usProtocolType;
+ }
+
+ WanPacket->CurrentBuffer = StartBuffer;
+ WanPacket->CurrentLength = BytesCopied;
+ WanPacket->ProtocolReserved1 = (PVOID)LinkCB;
+ WanPacket->ProtocolReserved2 = (PVOID)NdisPacket;
+ WanPacket->ProtocolReserved3 = (PVOID)ProtocolCB;
+
+ if (LinkCB->State == LINK_UP) {
+
+ NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("FrameAndSend: LinkCB: 0x%8.8x, WanPacket: 0x%8.8x", LinkCB, WanPacket));
+
+ WanMiniportSend(&Status,
+ LinkCB->WanAdapterCB->hNdisBindingHandle,
+ LinkCB->LineUpInfo.NdisLinkHandle,
+ WanPacket);
+ }
+
+ //
+ // If we get something other than pending back we need to
+ // do the send complete.
+ //
+ if (Status != NDIS_STATUS_PENDING) {
+
+ NdisWanSendCompleteHandler(NULL,
+ WanPacket,
+ NDIS_STATUS_SUCCESS);
+
+ Status = NDIS_STATUS_PENDING;
+ }
+ }
+
+ NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("FrameAndSend: Exit"));
+
+ return (Status);
+}
+
+#ifdef BANDWIDTH_ON_DEMAND
+
+BOOLEAN
+IsProtocolQuotaFilled(
+ PPROTOCOLCB ProtocolCB
+ )
+/*++
+
+Routine Name:
+
+ IsProtocolQuotaFilled
+
+Routine Description:
+
+ This routine checks to see if the protocol has filled it's
+ bandwidth quota.
+
+Arguments:
+
+ ProtocolCB - Pointer to the protocolcb that is sending.
+
+Return Values:
+
+ TRUE Quota filled
+ FALSE Quota not filled
+
+--*/
+{
+ BOOLEAN QuotaMet = FALSE;
+ PSAMPLE_TABLE SampleTable = &ProtocolCB->SampleTable;
+ PSEND_SAMPLE FirstSample, CurrentSample;
+
+ AgeSampleTable(SampleTable);
+ if (ProtocolCB->ulByteQuota < SampleTable->ulCurrentSampleByteCount) {
+ QuotaMet = TRUE;
+ }
+
+ return (QuotaMet);
+}
+
+VOID
+AgeSampleTable(
+ PSAMPLE_TABLE SampleTable
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ WAN_TIME CurrentTime, TimeDiff;
+ ULONG FirstIndex = SampleTable->ulFirstIndex;
+ ULONG CurrentIndex = SampleTable->ulCurrentIndex;
+ PSEND_SAMPLE FirstSample = &SampleTable->SampleArray[FirstIndex];
+
+ //
+ // Should return CurrentTime in 100ns units
+ //
+ NdisWanGetSystemTime(&CurrentTime);
+
+ //
+ // We will search through the sample indexing over samples that are more than
+ // one second older than the current time.
+ //
+ NdisWanCalcTimeDiff(&TimeDiff, &CurrentTime, &FirstSample->TimeStamp);
+
+ while ( !NdisWanIsTimeDiffLess(&TimeDiff, &SampleTable->SamplePeriod) &&
+ (FirstIndex != CurrentIndex) ) {
+
+ SampleTable->ulCurrentSampleByteCount -= FirstSample->ulBytesThisSend;
+
+ ASSERT((LONG)SampleTable->ulCurrentSampleByteCount >= 0);
+
+ FirstSample->ulReferenceCount = 0;
+
+ if (++FirstIndex == SampleTable->ulSampleArraySize) {
+ FirstIndex = 0;
+ }
+
+ SampleTable->ulFirstIndex = FirstIndex ;
+
+ FirstSample = &SampleTable->SampleArray[FirstIndex];
+
+ NdisWanCalcTimeDiff(&TimeDiff, &CurrentTime, &FirstSample->TimeStamp);
+ }
+
+}
+
+BOOLEAN
+IsSampleTableFull(
+ PSAMPLE_TABLE SampleTable
+ )
+{
+ LONG Diff;
+
+// AgeSampleTable(SampleTable);
+ Diff = (LONG)(SampleTable->ulCurrentIndex - SampleTable->ulFirstIndex);
+ return((Diff == (LONG)(SampleTable->ulSampleArraySize - 1)) || (Diff == -1));
+}
+
+VOID
+UpdateSampleTable(
+ PSAMPLE_TABLE SampleTable,
+ ULONG BytesSent
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ WAN_TIME CurrentTime, TimeDiff;
+ ULONG CurrentIndex = SampleTable->ulCurrentIndex;
+ PSEND_SAMPLE CurrentSample = &SampleTable->SampleArray[CurrentIndex];
+
+ NdisWanGetSystemTime(&CurrentTime);
+
+ NdisWanCalcTimeDiff(&TimeDiff, &CurrentTime, &CurrentSample->TimeStamp);
+
+ if ( NdisWanIsTimeDiffLess(&TimeDiff, &SampleTable->SampleRate) ||
+ IsSampleTableFull(SampleTable)) {
+ //
+ // Add this send on the previous sample
+ //
+ CurrentSample->ulBytesThisSend += BytesSent;
+ CurrentSample->ulReferenceCount++;
+ } else {
+ //
+ // We need a new sample
+ //
+ if (++CurrentIndex == SampleTable->ulSampleArraySize) {
+ CurrentIndex = 0;
+ }
+
+ SampleTable->ulCurrentIndex = CurrentIndex;
+ CurrentSample = &SampleTable->SampleArray[CurrentIndex];
+ CurrentSample->TimeStamp = CurrentTime;
+ CurrentSample->ulBytesThisSend = BytesSent;
+ CurrentSample->ulReferenceCount = 1;
+ }
+
+ SampleTable->ulCurrentSampleByteCount += BytesSent;
+
+}
+
+VOID
+UpdateBandwidthOnDemand(
+ PBUNDLECB BundleCB,
+ ULONG BytesSent
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ ULONG EventCount;
+ PSAMPLE_TABLE UpperSampleTable = &BundleCB->UpperBonDInfo.SampleTable;
+ PSAMPLE_TABLE LowerSampleTable = &BundleCB->LowerBonDInfo.SampleTable;
+
+ //
+ // Age and update the sample table
+ //
+ AgeSampleTable(UpperSampleTable);
+ UpdateSampleTable(UpperSampleTable, BytesSent);
+ AgeSampleTable(LowerSampleTable);
+ UpdateSampleTable(LowerSampleTable, BytesSent);
+
+ GetGlobalListCount(ThresholdEventQueue, EventCount);
+
+ if (EventCount != 0) {
+
+ CheckUpperThreshold(BundleCB);
+ CheckLowerThreshold(BundleCB);
+
+ }
+
+}
+
+VOID
+CheckUpperThreshold(
+ PBUNDLECB BundleCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ WAN_TIME CurrentTime, TimeDiff;
+ PBOND_INFO BonDInfo = &BundleCB->UpperBonDInfo;
+ PSAMPLE_TABLE SampleTable = &BonDInfo->SampleTable;
+ ULONG Bps = SampleTable->ulCurrentSampleByteCount;
+ //
+ // Switch on the current state
+ //
+ switch (BonDInfo->State) {
+ case BonDIdle:
+ //
+ // We are currently below the upper threshold. If we
+ // go over the upperthreshold we will set the time and
+ // transition to the monitor state.
+ //
+ if (Bps >= BonDInfo->ulBytesThreshold) {
+ NdisWanGetSystemTime(&BonDInfo->StartTime);
+ BonDInfo->State = BonDMonitor;
+ }
+ break;
+
+ case BonDMonitor:
+
+ //
+ // We are currently in the monitor state which means that
+ // we have gone above the upper threshold. If we fall below
+ // the upper threshold we will go back to the idle state.
+ //
+ if (Bps < BonDInfo->ulBytesThreshold) {
+ BonDInfo->State = BonDIdle;
+
+ } else {
+
+ NdisWanGetSystemTime(&CurrentTime);
+
+ NdisWanCalcTimeDiff(&TimeDiff, &CurrentTime, &BonDInfo->StartTime);
+
+ if (!NdisWanIsTimeDiffLess(&TimeDiff, &SampleTable->SamplePeriod)) {
+ //
+ // We have been above the threshold for time greater than the
+ // threshold sample period so we need to notify someone of this
+ // historic event!
+ //
+ CompleteThresholdEvent(BundleCB, UPPER_THRESHOLD);
+
+ //
+ // I'm not sure what state we should be in now!
+ //
+ BonDInfo->State = BonDSignaled;
+ }
+ }
+ break;
+
+ case BonDSignaled:
+ break;
+
+ }
+}
+
+VOID
+CheckLowerThreshold(
+ PBUNDLECB BundleCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ WAN_TIME CurrentTime, TimeDiff;
+ PBOND_INFO BonDInfo = &BundleCB->LowerBonDInfo;
+ PSAMPLE_TABLE SampleTable = &BonDInfo->SampleTable;
+ ULONG Bps = SampleTable->ulCurrentSampleByteCount;
+
+ //
+ // Switch on the current state
+ //
+ switch (BonDInfo->State) {
+ case BonDIdle:
+ //
+ // We are currently above the lower threshold. If we
+ // go below the lowerthreshold we will set the time and
+ // transition to the monitor state.
+ //
+ if (Bps <= BonDInfo->ulBytesThreshold) {
+ NdisWanGetSystemTime(&BonDInfo->StartTime);
+ BonDInfo->State = BonDMonitor;
+ }
+ break;
+
+ case BonDMonitor:
+
+ //
+ // We are currently in the monitor state which means that
+ // we have gone below the lower threshold. If we rise above
+ // the lower threshold we will go back to the idle state.
+ //
+ if (Bps > BonDInfo->ulBytesThreshold) {
+ BonDInfo->State = BonDIdle;
+
+ } else {
+
+ NdisWanGetSystemTime(&CurrentTime);
+
+ NdisWanCalcTimeDiff(&TimeDiff, &CurrentTime, &BonDInfo->StartTime);
+
+ if (!NdisWanIsTimeDiffLess(&TimeDiff, &SampleTable->SamplePeriod)) {
+ //
+ // We have been below the lower threshold for time greater than the
+ // threshold sample period so we need to notify someone of this
+ // historic event!
+ //
+ CompleteThresholdEvent(BundleCB, LOWER_THRESHOLD);
+
+ //
+ // I'm not sure what state we should be in now!
+ //
+ BonDInfo->State = BonDSignaled;
+ }
+ }
+ break;
+
+ case BonDSignaled:
+ break;
+
+ }
+}
+
+#endif // end of BANDWIDTH_ON_DEMAND
+
+PLINKCB
+GetNextLinkToXmitOn(
+ PBUNDLECB BundleCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PLINKCB LinkCB = BundleCB->NextLinkToXmit;
+ PLIST_ENTRY LinkCBList = &BundleCB->LinkCBList;
+
+ //
+ // We need to find the first link that has an open send window
+ //
+ while (LinkCB->ulWanPacketCount < 2) {
+ LinkCB = (PLINKCB)LinkCB->Linkage.Flink;
+
+ if ((PVOID)LinkCB == (PVOID)LinkCBList) {
+ LinkCB = (PLINKCB)LinkCBList->Flink;
+ }
+ }
+
+ BundleCB->NextLinkToXmit =
+ ((PVOID)LinkCB->Linkage.Flink == (PVOID)LinkCBList) ?
+ (PLINKCB)LinkCBList->Flink : (PLINKCB)LinkCB->Linkage.Flink;
+
+ LinkCB->OutstandingFrames++;
+
+ return(LinkCB);
+}
+
+NDIS_STATUS
+BuildIoPacket(
+ IN PNDISWAN_IO_PACKET pWanIoPacket,
+ IN BOOLEAN SendImmediate
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_RESOURCES;
+ PWAN_IO_PROTOCOL_RESERVED pProtocolReserved;
+ PPROTOCOLCB ProtocolCB;
+ ULONG Stage = 0, ulAllocationSize = 0;
+ PUCHAR pAllocatedMemory = NULL, pSrcAddr, pDestAddr;
+ NDIS_HANDLE hPacketPool, hBufferPool, hBundle, hLink;
+ PNDIS_PACKET pNdisPacket;
+ PNDIS_BUFFER pNdisBuffer;
+ PBUNDLECB BundleCB;
+ PLINKCB LinkCB = NULL;
+ UCHAR SendHeader[] = {' ', 'S', 'E', 'N', 'D', 0xFF};
+
+ NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("BuildIoPacket: Enter!"));
+ //
+ // Some time in the future this should be redone so that
+ // there is a pool of packets and buffers attached to a
+ // BundleCB. This pool could be grown and shrunk as needed
+ // but some minimum number would live for the lifetime of
+ // the BundleCB.
+
+ if (pWanIoPacket->usHandleType == LINKHANDLE) {
+
+ hLink = pWanIoPacket->hHandle;
+ LINKCB_FROM_LINKH(LinkCB, hLink);
+
+ if (LinkCB == NULL) {
+ return (NDIS_STATUS_SUCCESS);
+ }
+
+ BundleCB = LinkCB->BundleCB;
+
+ if (BundleCB == NULL) {
+ return (NDIS_STATUS_SUCCESS);
+ }
+
+ } else {
+ hBundle = pWanIoPacket->hHandle;
+ BUNDLECB_FROM_BUNDLEH(BundleCB, hBundle);
+
+ if (BundleCB == NULL) {
+ return (NDIS_STATUS_SUCCESS);
+ }
+
+ LinkCB = (PLINKCB)BundleCB->LinkCBList.Flink;
+
+ if (LinkCB == NULL) {
+ return (NDIS_STATUS_SUCCESS);
+ }
+ }
+
+ NdisAcquireSpinLock(&BundleCB->Lock);
+
+ if ((LinkCB->State != LINK_UP) ||
+ (BundleCB->State != BUNDLE_UP)) {
+ NdisReleaseSpinLock(&BundleCB->Lock);
+ return (NDIS_STATUS_SUCCESS);
+ }
+
+ //
+ // We only support ethernet headers right now so the supplied header
+ // either has to be ethernet or none at all!
+ //
+
+ //
+ //
+ // Get an NdisPacket for this send
+ //
+ NdisAllocatePacketPool(&Status,
+ &hPacketPool,
+ 1,
+ sizeof(WAN_IO_PROTOCOL_RESERVED));
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_SEND, ("BuildIoPacket: Error Allocating PacketPool!"));
+ NdisReleaseSpinLock(&BundleCB->Lock);
+ goto RESOURCE_ERROR;
+ }
+
+ Stage++;
+
+ NdisAllocatePacket(&Status,
+ &pNdisPacket,
+ hPacketPool);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_SEND, ("BuildIoPacket: Error Allocating Packet!"));
+ NdisReleaseSpinLock(&BundleCB->Lock);
+ goto RESOURCE_ERROR;
+ }
+
+ Stage++;
+
+ //
+ // Get an NdisBuffer for this send
+ //
+ NdisAllocateBufferPool(&Status,
+ &hBufferPool,
+ 2);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_SEND, ("BuildIoPacket: Error Allocating BufferPool!"));
+ NdisReleaseSpinLock(&BundleCB->Lock);
+ goto RESOURCE_ERROR;
+ }
+
+ Stage++;
+
+ if (pWanIoPacket->usHeaderSize == 0) {
+ ulAllocationSize = 12;
+ }
+
+ ulAllocationSize += pWanIoPacket->usPacketSize;
+
+ NdisWanAllocateMemory(&pAllocatedMemory, ulAllocationSize);
+
+ if (pAllocatedMemory == NULL) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_SEND, ("BuildIoPacket: Error Allocating Memory! Size: %d", ulAllocationSize));
+ NdisReleaseSpinLock(&BundleCB->Lock);
+ goto RESOURCE_ERROR;
+ }
+
+ Stage++;
+
+ NdisAllocateBuffer(&Status,
+ &pNdisBuffer,
+ hBufferPool,
+ pAllocatedMemory,
+ ulAllocationSize);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_SEND, ("BuildIoPacket: Error Allocating Buffer!"));
+ NdisReleaseSpinLock(&BundleCB->Lock);
+ goto RESOURCE_ERROR;
+ }
+
+ Stage++;
+
+ pProtocolReserved = (PWAN_IO_PROTOCOL_RESERVED)pNdisPacket->ProtocolReserved;
+ pProtocolReserved->LinkCB = LinkCB;
+ pProtocolReserved->hPacketPool = hPacketPool;
+ pProtocolReserved->pNdisPacket = pNdisPacket;
+ pProtocolReserved->hBufferPool = hBufferPool;
+ pProtocolReserved->pNdisBuffer = pNdisBuffer;
+ pProtocolReserved->pAllocatedMemory = pAllocatedMemory;
+ pProtocolReserved->ulAllocationSize = ulAllocationSize;
+
+ pDestAddr = &pAllocatedMemory[0];
+ pSrcAddr = &pAllocatedMemory[6];
+
+ //
+ // If no header build a header
+ //
+ if (pWanIoPacket->usHeaderSize == 0) {
+
+ //
+ // Header will look like " S XXYYYY" where
+ // XX is the ProtocolCB index and YYYY is the
+ // BundleCB index. Both the Src and Dst addresses
+ // look the same.
+ //
+ NdisMoveMemory(pDestAddr,
+ SendHeader,
+ sizeof(SendHeader));
+
+ NdisMoveMemory(pSrcAddr,
+ SendHeader,
+ sizeof(SendHeader));
+
+ } else {
+ //
+ // Header supplied so go ahead and move it.
+ //
+ NdisMoveMemory(pDestAddr,
+ pWanIoPacket->PacketData,
+ pWanIoPacket->usHeaderSize);
+ }
+
+ //
+ // Fill the BundleCB Index for the Src and Dest Address
+ //
+ FillNdisWanProtocolIndex(pDestAddr, hLink);
+ FillNdisWanProtocolIndex(pSrcAddr, hLink);
+
+ //
+ // Copy the data to the buffer
+ //
+ NdisMoveMemory(&pAllocatedMemory[12],
+ &pWanIoPacket->PacketData[pWanIoPacket->usHeaderSize],
+ pWanIoPacket->usPacketSize);
+
+ //
+ // Chain buffer to ndis packet
+ //
+ NdisChainBufferAtFront(pNdisPacket, pNdisBuffer);
+
+ //
+ // Queue the packet on the bundlecb
+ //
+ ProtocolCB = BundleCB->ProtocolCBTable[0];
+
+ ASSERT(ProtocolCB != NULL);
+
+ if (SendImmediate) {
+ InsertHeadNdisPacketQueue(ProtocolCB, pNdisPacket);
+ } else {
+ InsertTailNdisPacketQueue(ProtocolCB, pNdisPacket);
+ }
+
+ //
+ // Try to send
+ //
+ // Called with lock held and returns with
+ // lock released
+ //
+ Status = SendPacketOnBundle(BundleCB);
+
+ //
+ // We don't pend I/O packets so complete
+ // as if it succeeded
+ //
+ if (Status == NDIS_STATUS_PENDING) {
+ Status = NDIS_STATUS_SUCCESS;
+ }
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+RESOURCE_ERROR:
+
+ //
+ // Free all of the allocated resources
+ //
+ switch (Stage) {
+ case 5:
+ NdisFreeBuffer(pNdisBuffer);
+
+ case 4:
+ NdisWanFreeMemory(pAllocatedMemory);
+
+ case 3:
+ NdisFreeBufferPool(hBufferPool);
+
+ case 2:
+ NdisFreePacket(pNdisPacket);
+
+ case 1:
+ NdisFreePacketPool(hPacketPool);
+
+ }
+ }
+
+ NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("BuildIoPacket: Exit-Status: 0x%8.8x\n", Status));
+
+ return (Status);
+}
+
+//ULONG
+//GetNumSendingLinks(
+// PBUNDLECB BundleCB
+// )
+///*++
+//
+//Routine Name:
+//
+//Routine Description:
+//
+//Arguments:
+//
+//Return Values:
+//
+//--*/
+//{
+// ULONG LinkCount = 0;
+// PLINKCB LinkCB;
+//
+// //
+// // We need to walk through the list of links on this bundle and
+// // count how many have an open send window.
+// //
+// for (LinkCB = (PLINKCB)BundleCB->LinkCBList.Flink;
+// (PVOID)LinkCB != (PVOID)&BundleCB->LinkCBList;
+// LinkCB = (PLINKCB)LinkCB->Linkage.Flink) {
+//
+// //
+// // Since we create enough sendwindow + 1 wanpackets
+// // for each link, if the send window is open we will
+// // have atleast 2 wanpackets available.
+// //
+// if (LinkCB->ulWanPacketCount > 1) {
+// LinkCount++;
+// }
+// }
+//
+// return (LinkCount);
+//}
+
+VOID
+BuildLinkHeader(
+ PHEADER_FRAMING_INFO FramingInfo,
+ PUCHAR StartBuffer
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ ULONG LinkFraming = FramingInfo->FramingBits;
+ ULONG Flags = FramingInfo->Flags;
+ PUCHAR CurrentPointer = StartBuffer;
+
+ FramingInfo->HeaderLength =
+ FramingInfo->AddressControl.Length =
+ FramingInfo->Multilink.Length =
+ FramingInfo->Compression.Length =
+ FramingInfo->ProtocolID.Length = 0;
+
+ if (LinkFraming & PPP_FRAMING) {
+
+ if (!(LinkFraming & PPP_COMPRESS_ADDRESS_CONTROL)) {
+ //
+ // If there is no address/control compression
+ // we need a pointer and a length
+ //
+ FramingInfo->AddressControl.Pointer = CurrentPointer;
+ *CurrentPointer++ = 0xFF;
+ *CurrentPointer++ = 0x03;
+ FramingInfo->AddressControl.Length = 2;
+ FramingInfo->HeaderLength += FramingInfo->AddressControl.Length;
+
+ }
+
+ if (!(Flags & IO_PROTOCOLID)) {
+
+ //
+ // If this is not from our private I/O interface we will
+ // build the rest of the header.
+ //
+ if ((Flags & DO_MULTILINK) && (LinkFraming & PPP_MULTILINK_FRAMING)) {
+
+ //
+ // We are doing multilink so we need a pointer
+ // and a length
+ //
+ FramingInfo->Multilink.Pointer = CurrentPointer;
+
+ if (!(LinkFraming & PPP_COMPRESS_PROTOCOL_FIELD)) {
+ //
+ // No protocol compression
+ //
+ *CurrentPointer++ = 0x00;
+ FramingInfo->Multilink.Length++;
+ }
+
+ *CurrentPointer++ = 0x3D;
+ FramingInfo->Multilink.Length++;
+
+ if (!(LinkFraming & PPP_SHORT_SEQUENCE_HDR_FORMAT)) {
+ //
+ // We are using long sequence number
+ //
+ FramingInfo->Multilink.Length += 2;
+ CurrentPointer += 2;
+
+ }
+
+ FramingInfo->Multilink.Length += 2;
+ CurrentPointer += 2;
+
+ FramingInfo->HeaderLength += FramingInfo->Multilink.Length;
+
+ }
+
+ if (Flags & (DO_COMPRESSION | DO_ENCRYPTION)) {
+ //
+ // We are doing compression/encryption so we need
+ // a pointer and a length
+ //
+ FramingInfo->Compression.Pointer = CurrentPointer;
+
+ //
+ // It appears that legacy ras (< NT 4.0) requires that
+ // the PPP protocol field in a compressed packet not
+ // be compressed, ie has to have the leading 0x00
+ //
+ if (!(LinkFraming & PPP_COMPRESS_PROTOCOL_FIELD)) {
+ //
+ // No protocol compression
+ //
+ *CurrentPointer++ = 0x00;
+ FramingInfo->Compression.Length++;
+ }
+
+ *CurrentPointer++ = 0xFD;
+ FramingInfo->Compression.Length++;
+
+ //
+ // Add coherency bytes
+ //
+ FramingInfo->Compression.Length += 2;
+ CurrentPointer += 2;
+
+ FramingInfo->HeaderLength += FramingInfo->Compression.Length;
+ }
+
+ if (Flags & FIRST_FRAGMENT) {
+
+ FramingInfo->ProtocolID.Pointer = CurrentPointer;
+
+ if (!(LinkFraming & PPP_COMPRESS_PROTOCOL_FIELD) ||
+ (Flags & (DO_COMPRESSION | DO_ENCRYPTION))) {
+ FramingInfo->ProtocolID.Length++;
+ CurrentPointer++;
+ }
+
+ FramingInfo->ProtocolID.Length++;
+ FramingInfo->HeaderLength += FramingInfo->ProtocolID.Length;
+
+ }
+ }
+
+ } else if ((LinkFraming & RAS_FRAMING)) {
+ //
+ // If this is old ras framing:
+ //
+ // Alter the framing so that 0xFF 0x03 is not added
+ // and that the first byte is 0xFD not 0x00 0xFD
+ //
+ // So basically, a RAS compression looks like
+ // <0xFD> <2 BYTE COHERENCY> <NBF DATA FIELD>
+ //
+ // Whereas uncompressed looks like
+ // <NBF DATA FIELD> which always starts with 0xF0
+ //
+ // If this is ppp framing:
+ //
+ // A compressed frame will look like (before address/control
+ // - multilink is added)
+ // <0x00> <0xFD> <2 Byte Coherency> <Compressed Data>
+ //
+ if (Flags & (DO_COMPRESSION | DO_ENCRYPTION)) {
+ FramingInfo->Compression.Pointer = CurrentPointer;
+
+ *CurrentPointer++ = 0xFD;
+ FramingInfo->Compression.Length++;
+
+ //
+ // Coherency bytes
+ //
+ FramingInfo->Compression.Length += 2;
+ CurrentPointer += 2;
+
+ FramingInfo->HeaderLength += FramingInfo->Compression.Length;
+ }
+ }
+}
+
+VOID
+NdisWanCopyFromPacketToBuffer(
+ IN PNDIS_PACKET pNdisPacket,
+ IN ULONG Offset,
+ IN ULONG BytesToCopy,
+ OUT PUCHAR Buffer,
+ OUT PULONG BytesCopied
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ ULONG NdisBufferCount;
+ PNDIS_BUFFER CurrentBuffer;
+ PVOID VirtualAddress;
+ ULONG CurrentLength, AmountToMove;
+ ULONG LocalBytesCopied = 0;
+
+ *BytesCopied = 0;
+
+ //
+ // Take care of zero byte copy
+ //
+ if (!BytesToCopy) {
+ return;
+ }
+
+ //
+ // Get the buffer count
+ //
+ NdisQueryPacket(pNdisPacket,
+ NULL,
+ &NdisBufferCount,
+ &CurrentBuffer,
+ NULL);
+
+ //
+ // Could be a null packet
+ //
+ if (!NdisBufferCount) {
+ return;
+ }
+
+
+ NdisQueryBuffer(CurrentBuffer,
+ &VirtualAddress,
+ &CurrentLength);
+
+ while (LocalBytesCopied < BytesToCopy) {
+
+ //
+ // No more bytes left in this buffer
+ //
+ if (!CurrentLength) {
+
+ //
+ // Get the next buffer
+ //
+ NdisGetNextBuffer(CurrentBuffer,
+ &CurrentBuffer);
+
+ //
+ // End of the packet, copy what we can
+ //
+ if (CurrentBuffer == NULL) {
+ break;
+ }
+
+ //
+ //
+ //
+ NdisQueryBuffer(CurrentBuffer,
+ &VirtualAddress,
+ &CurrentLength);
+
+ continue;
+ }
+
+ //
+ // Get to the point where we can start copying
+ //
+ if (Offset) {
+
+ if (Offset > CurrentLength) {
+
+ //
+ // Not in this buffer, go to the next one
+ //
+ Offset -= CurrentLength;
+ CurrentLength = 0;
+ continue;
+
+ } else {
+
+ //
+ // At least some in this buffer
+ //
+ VirtualAddress = (PUCHAR)VirtualAddress + Offset;
+ CurrentLength -= Offset;
+ Offset = 0;
+ }
+
+ }
+
+ //
+ // We can copy some data. If we need more data than is available
+ // in this buffer we can copy what we need and go back for more.
+ //
+ AmountToMove = (CurrentLength > (BytesToCopy - LocalBytesCopied)) ?
+ (BytesToCopy - LocalBytesCopied) : CurrentLength;
+
+ NdisMoveMemory(Buffer, VirtualAddress, AmountToMove);
+
+ Buffer = (PUCHAR)Buffer + AmountToMove;
+
+ VirtualAddress = (PUCHAR)VirtualAddress + AmountToMove;
+
+ LocalBytesCopied += AmountToMove;
+
+ CurrentLength -= AmountToMove;
+
+ }
+
+ *BytesCopied = LocalBytesCopied;
+}
+
+PNDIS_WAN_PACKET
+GetWanPacketFromLink(
+ PLINKCB LinkCB
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PNDIS_WAN_PACKET WanPacket;
+ ULONG PrevCount = LinkCB->ulWanPacketCount;
+
+ ASSERT(LinkCB->ulWanPacketCount);
+
+ //
+ // If the current count is greater than threshold and the
+ // new count falls below we need to decrement the sending
+ // link count.
+ //
+ if ((--LinkCB->ulWanPacketCount < 2) && (PrevCount > 1)) {
+ ((PBUNDLECB)LinkCB->BundleCB)->SendingLinks--;
+ }
+
+ WanPacket = (PNDIS_WAN_PACKET)RemoveHeadList(&LinkCB->WanPacketPool);
+
+ return (WanPacket);
+}
+
+VOID
+ReturnWanPacketToLink(
+ PLINKCB LinkCB,
+ PNDIS_WAN_PACKET WanPacket
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ ULONG PrevCount = LinkCB->ulWanPacketCount;
+
+ //
+ // If the current count is below the threshold and the
+ // new count puts us over we need to increment the sending
+ // link count.
+ //
+ if ((++LinkCB->ulWanPacketCount > 1) && (PrevCount < 2)) {
+ ((PBUNDLECB)LinkCB->BundleCB)->SendingLinks++;
+ }
+
+ InsertTailList(&LinkCB->WanPacketPool, &WanPacket->WanPacketQueue);
+}
+
+VOID
+DestroyIoPacket(
+ PNDIS_PACKET NdisPacket
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PWAN_IO_PROTOCOL_RESERVED ProtocolReserved =
+ (PWAN_IO_PROTOCOL_RESERVED)NdisPacket->ProtocolReserved;
+
+ NDIS_HANDLE PacketPool = ProtocolReserved->hPacketPool;
+
+ NdisWanFreeMemory(ProtocolReserved->pAllocatedMemory);
+ NdisFreeBuffer(ProtocolReserved->pNdisBuffer);
+ NdisFreeBufferPool(ProtocolReserved->hBufferPool);
+ NdisFreePacket(NdisPacket);
+ NdisFreePacketPool(PacketPool);
+}
+
+#if DBG
+VOID
+InsertDbgPacket(
+ PDBG_SEND_CONTEXT DbgContext
+ )
+{
+ PDBG_SEND_PACKET DbgPacket;
+ PBUNDLECB BundleCB = DbgContext->BundleCB;
+ PPROTOCOLCB ProtocolCB = DbgContext->ProtocolCB;
+ PLINKCB LinkCB = DbgContext->LinkCB;
+
+ NdisWanAllocateMemory(&DbgPacket, sizeof(DBG_SEND_PACKET));
+
+ if (DbgPacket == NULL) {
+ return;
+ }
+
+ DbgPacket->Packet = DbgContext->Packet;
+ DbgPacket->PacketType = DbgContext->PacketType;
+ DbgPacket->BundleCB = BundleCB;
+ if (BundleCB) {
+ DbgPacket->BundleState = BundleCB->State;
+ DbgPacket->BundleFlags = BundleCB->Flags;
+ }
+
+ DbgPacket->ProtocolCB = ProtocolCB;
+ if (ProtocolCB) {
+ DbgPacket->ProtocolFlags = ProtocolCB->Flags;
+ }
+
+ DbgPacket->LinkCB = LinkCB;
+ if (LinkCB) {
+ DbgPacket->LinkState = LinkCB->State;
+ }
+
+ NdisAcquireSpinLock(DbgContext->ListLock);
+ InsertTailList(DbgContext->ListHead, &DbgPacket->Linkage);
+ NdisReleaseSpinLock(DbgContext->ListLock);
+}
+
+BOOLEAN
+RemoveDbgPacket(
+ PDBG_SEND_CONTEXT DbgContext
+ )
+{
+ PDBG_SEND_PACKET DbgPacket = NULL;
+ BOOLEAN Found = FALSE;
+
+ NdisAcquireSpinLock(DbgContext->ListLock);
+
+ if (!IsListEmpty(DbgContext->ListHead)) {
+ for (DbgPacket = (PDBG_SEND_PACKET)DbgContext->ListHead->Flink;
+ (PVOID)DbgPacket != (PVOID)DbgContext->ListHead;
+ DbgPacket = (PDBG_SEND_PACKET)DbgPacket->Linkage.Flink) {
+
+ if (DbgPacket->Packet == DbgContext->Packet) {
+ RemoveEntryList(&DbgPacket->Linkage);
+ NdisWanFreeMemory(DbgPacket);
+ Found = TRUE;
+ break;
+ }
+
+ }
+ }
+
+ ASSERT(Found == TRUE);
+
+ NdisReleaseSpinLock(DbgContext->ListLock);
+
+ return (Found);
+}
+
+#endif
diff --git a/private/ntos/ndis/ndiswan/tapi.c b/private/ntos/ndis/ndiswan/tapi.c
new file mode 100644
index 000000000..bc1c4cb6e
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/tapi.c
@@ -0,0 +1,144 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ Tapi.c
+
+Abstract:
+
+
+Author:
+
+ Tony Bell (TonyBe) June 06, 1995
+
+Environment:
+
+ Kernel Mode
+
+Revision History:
+
+ TonyBe 06/06/95 Created
+
+--*/
+
+
+//
+// We want to initialize all of the global variables now!
+//
+#include "wan.h"
+
+EXPORT
+VOID
+NdisTapiCompleteRequest(
+ IN NDIS_HANDLE Handle,
+ IN PVOID NdisRequest,
+ IN NDIS_STATUS Status
+ );
+
+EXPORT
+VOID
+NdisTapiIndicateStatus(
+ IN NDIS_HANDLE Handle,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ );
+
+
+NDIS_STATUS
+NdisWanTapiRequestProc(
+ PWAN_ADAPTERCB WanAdapterCB,
+ PNDIS_REQUEST NdisRequest
+ )
+/*++
+
+Routine Name:
+
+ NdisWanTapiRequestProc
+
+Routine Description:
+
+ Procedure is called by the NdisTapi.sys driver to send
+ requests to the WanMiniport driver. We intercept this
+ just to moderate. NdisTapi could call the miniport directly
+ if we wanted but we don't.
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NDIS_STATUS Status;
+
+ NdisWanDbgOut(DBG_TRACE, DBG_TAPI, ("NdisWanTapiRequestProc - Enter"));
+ NdisWanDbgOut(DBG_INFO, DBG_TAPI, ("NdisRequest: Type: 0x%8.8x OID: 0x%8.8x",
+ NdisRequest->RequestType,NdisRequest->DATA.QUERY_INFORMATION.Oid));
+
+ Status = NdisWanSubmitNdisRequest(WanAdapterCB,
+ NdisRequest,
+ ASYNC,
+ NDISTAPI);
+
+ NdisWanDbgOut(DBG_INFO, DBG_TAPI, ("Status: 0x%8.8x", Status));
+ NdisWanDbgOut(DBG_TRACE, DBG_TAPI, ("NdisWanTapiRequestProc - Exit"));
+
+ return (Status);
+}
+
+VOID
+NdisWanTapiRequestComplete(
+ PWAN_ADAPTERCB WanAdapterCB,
+ PWAN_REQUEST WanRequest
+ )
+{
+ NdisWanDbgOut(DBG_TRACE, DBG_TAPI, ("NdisWanTapiRequestComplete - Enter"));
+ NdisWanDbgOut(DBG_INFO, DBG_TAPI, ("NdisRequest: Type: 0x%8.8x OID: 0x%8.8x",
+ WanRequest->pNdisRequest->RequestType,
+ WanRequest->pNdisRequest->DATA.QUERY_INFORMATION.Oid));
+ NdisWanDbgOut(DBG_INFO, DBG_TAPI, ("Status: 0x%8.8x",
+ WanRequest->NotificationStatus));
+
+ RemoveRequestFromList(WanAdapterCB, WanRequest);
+
+ NdisTapiCompleteRequest(WanAdapterCB,
+ WanRequest->pNdisRequest,
+ WanRequest->NotificationStatus);
+
+ NdisWanFreeMemory(WanRequest);
+}
+
+VOID
+NdisWanTapiIndication(
+ PWAN_ADAPTERCB WanAdapterCB,
+ PUCHAR StatusBuffer,
+ ULONG StatusBufferSize
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ NdisWanDbgOut(DBG_TRACE, DBG_TAPI, ("NdisWanTapiIndication - Enter"));
+
+ //
+ // If tapi is present and this miniport has registered for
+ // connectionwrapper services give this to tapi
+ //
+ if (WanAdapterCB->WanInfo.FramingBits & TAPI_PROVIDER) {
+
+ NdisTapiIndicateStatus(WanAdapterCB,
+ StatusBuffer,
+ StatusBufferSize);
+ }
+
+ NdisWanDbgOut(DBG_TRACE, DBG_TAPI, ("NdisWanTapiIndication - Exit"));
+}
diff --git a/private/ntos/ndis/ndiswan/tcpip.h b/private/ntos/ndis/ndiswan/tcpip.h
new file mode 100644
index 000000000..de5abe474
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/tcpip.h
@@ -0,0 +1,52 @@
+// TCP control bits
+
+#ifndef _TCPIP_
+#define _TCPIP_
+
+#define TH_SYN 0x02 // Synchronize sequence numbers
+#define TH_FIN 0x01 // Sender has reached end of his stream
+#define TH_RST 0x04 // Reset the connection
+#define TH_PUSH 0x08 // Push data to above level
+#define TH_ACK 0x10 // Acknowledgement field is valid
+#define TH_URG 0x20 // Urgent pointer is valid
+
+struct tcphdr {
+ USHORT th_sport;
+ USHORT th_dport;
+ ULONG th_seq;
+ ULONG th_ack;
+ UCHAR th_off;
+ UCHAR th_flags;
+ USHORT th_win;
+ UCHAR th_sumhi;
+ UCHAR th_sumlo;
+ USHORT th_urp;
+ UCHAR th_data[1];
+};
+
+#define IP_ALEN 4
+
+typedef struct IPaddr {
+ ULONG s_addr;
+} IPaddr;
+
+#define IPPROTO_TCP 6
+
+struct ip {
+
+ UCHAR ip_hl;
+ UCHAR ip_tos;
+ USHORT ip_len;
+ USHORT ip_id;
+ USHORT ip_off;
+ UCHAR ip_ttl;
+ UCHAR ip_p;
+ USHORT ip_sum;
+ IPaddr ip_src;
+ IPaddr ip_dst;
+ UCHAR ip_data[1];
+};
+
+typedef struct ip IPHeader, *PIPHeader;
+
+#endif // _TCPIP_
diff --git a/private/ntos/ndis/ndiswan/util.c b/private/ntos/ndis/ndiswan/util.c
new file mode 100644
index 000000000..a44cb40ea
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/util.c
@@ -0,0 +1,323 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ Util.c
+
+Abstract:
+
+This file contains utility functions used by NdisWan.
+
+Author:
+
+ Tony Bell (TonyBe) June 06, 1995
+
+Environment:
+
+ Kernel Mode
+
+Revision History:
+
+ TonyBe 06/06/95 Created
+
+--*/
+
+#include "wan.h"
+
+#ifdef NT
+
+
+VOID
+NdisWanStringToNdisString(
+ PNDIS_STRING pDestString,
+ PWSTR pSrcBuffer
+ )
+{
+ PWSTR Dest, Src = pSrcBuffer;
+ NDIS_STRING SrcString;
+
+ RtlInitUnicodeString(&SrcString, pSrcBuffer);
+ NdisWanAllocateMemory(&pDestString->Buffer, SrcString.MaximumLength);
+ pDestString->MaximumLength = SrcString.MaximumLength;
+ pDestString->Length = SrcString.Length;
+ RtlCopyUnicodeString(pDestString, &SrcString);
+}
+
+//VOID
+//NdisWanInitNdisString(
+// PNDIS_STRING pDestString,
+// PWSTR pSrcBuffer,
+// USHORT ulSrcLength
+// )
+//{
+// PWSTR Dest, Src = pSrcBuffer;
+//
+// pDestString->Length = ulSrcLength;
+// pDestString->MaximumLength = pDestString->Length + 1;
+//
+// NdisAllocateMemory((PVOID)&(pDestString->Buffer),
+// (pDestString->MaximumLength * sizeof(WCHAR)),
+// 0,
+// HighestAcceptableAddress);
+//
+// Dest = pDestString->Buffer;
+// Src = pSrcBuffer;
+//
+// while (ulSrcLength--) {
+// *Dest = *Src;
+// Dest++;
+// Src++;
+// }
+//
+// *Dest = UNICODE_NULL;
+//}
+
+VOID
+NdisWanFreeNdisString(
+ PNDIS_STRING NdisString
+ )
+{
+ NdisWanFreeMemory(NdisString->Buffer);
+}
+
+VOID
+NdisWanAllocateAdapterName(
+ PNDIS_STRING Dest,
+ PNDIS_STRING Src
+ )
+{
+ NdisWanAllocateMemory(&Dest->Buffer, Src->MaximumLength);
+ Dest->MaximumLength = Src->MaximumLength;
+ Dest->Length = Src->Length;
+ RtlUpcaseUnicodeString(Dest, Src, FALSE);
+}
+
+BOOLEAN
+NdisWanCompareNdisString(
+ PNDIS_STRING NdisString1,
+ PNDIS_STRING NdisString2
+ )
+{
+ USHORT l1 = NdisString1->Length;
+ USHORT l2 = NdisString2->Length;
+ PWSTR s1 = NdisString1->Buffer;
+ PWSTR s2 = NdisString2->Buffer;
+ PWSTR EndCompare;
+
+ ASSERT(l1 != 0);
+ ASSERT(l2 != 0);
+
+ if (l1 == l2) {
+
+ EndCompare = (PWSTR)((PUCHAR)s1 + l1);
+
+ while (s1 < EndCompare) {
+
+ if (*s1++ != *s2++) {
+ return (FALSE);
+
+ }
+ }
+
+ return (TRUE);
+ }
+
+ return(FALSE);
+}
+
+
+//VOID
+//NdisWanFreeNdisString(
+// PNDIS_STRING NdisString
+// )
+//{
+// NdisFreeMemory(NdisString->Buffer,
+// NdisString->MaximumLength * sizeof(WCHAR),
+// 0);
+//}
+
+VOID
+NdisWanNdisStringToInteger(
+ PNDIS_STRING Source,
+ PULONG Value
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PWSTR s = Source->Buffer;
+ ULONG Digit;
+
+ *Value = 0;
+
+ while (*s != UNICODE_NULL) {
+
+ if (*s >= L'0' && *s < L'9') {
+ Digit = *s - L'0';
+ } else if (*s >= L'A' && *s <= L'F') {
+ Digit = *s - L'A' + 10;
+ } else if (*s >= L'a' && *s <= L'f') {
+ Digit = *s - L'a' + 10;
+ }
+
+ *Value = (*Value << 4) | Digit;
+
+ s++;
+ }
+}
+
+VOID
+NdisWanCopyNdisString(
+ PNDIS_STRING Dest,
+ PNDIS_STRING Src
+ )
+/*++
+
+Routine Name:
+
+Routine Description:
+
+Arguments:
+
+Return Values:
+
+--*/
+{
+ PWSTR SrcBuffer = Src->Buffer;
+ PWSTR DestBuffer = Dest->Buffer;
+
+ while (*SrcBuffer != UNICODE_NULL) {
+
+ *DestBuffer = *SrcBuffer;
+
+ SrcBuffer++;
+ DestBuffer++;
+ }
+
+ *DestBuffer = UNICODE_NULL;
+
+ Dest->Length = Src->Length;
+
+}
+
+#ifndef USE_NDIS_MINIPORT_LOCKING
+
+#define CURRENT_THREAD ((LONG)PsGetCurrentThread())
+BOOLEAN
+NdisWanAcquireMiniportLock(
+ PADAPTERCB AdapterCB
+ )
+/*++
+
+Routine Name:
+
+ NdisWanAcquireMiniportLock
+
+Routine Description:
+
+ This routine does the work that the ndis wrapper would normally do
+ to get a miniport's spinlock and local lock. Called when ndiswan gets
+ an indication from a lower miniport or user mode.
+
+Arguments:
+
+ PADAPTERCB AdapterCB - Miniport context (ndiswan space)
+
+Return Values:
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK MiniportBlock;
+ BOOLEAN LockAcquired = FALSE;
+ LONG original;
+ KIRQL SavedIrql, MiniportLockIrql;
+
+ MiniportBlock = (PNDIS_MINIPORT_BLOCK)AdapterCB->hMiniportHandle;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &SavedIrql);
+
+ ExAcquireSpinLock(&MiniportBlock->Lock.SpinLock, &MiniportLockIrql);
+
+ //
+ // If the lock is already acquired we may be in a deadlock situation.
+ //
+ if (!MiniportBlock->LockAcquired) {
+ MiniportBlock->LockAcquired =
+ LockAcquired = TRUE;
+
+ AdapterCB->Flags |= MINIPORT_LOCK_OWNER;
+
+ AdapterCB->SavedIrql = SavedIrql;
+ AdapterCB->MiniportLockIrql = MiniportLockIrql;
+
+ original = InterlockedExchange(&MiniportBlock->MiniportThread, CURRENT_THREAD);
+ ASSERT((LONG)NULL == original);
+
+ } else {
+ ExReleaseSpinLock(&MiniportBlock->Lock.SpinLock, MiniportLockIrql);
+ KeLowerIrql(SavedIrql);
+ }
+
+ return (LockAcquired);
+}
+
+VOID
+NdisWanReleaseMiniportLock(
+ PADAPTERCB AdapterCB
+ )
+/*++
+
+Routine Name:
+
+ NdisWanReleaseMiniportLock
+
+Routine Description:
+
+ This routine does the work that the ndis wrapper would normally do
+ to free a miniport's spinlock and local lock.
+
+Arguments:
+
+ PADAPTERCB AdapterCB -
+
+Return Values:
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK MiniportBlock;
+ KIRQL SavedIrql, MiniportLockIrql;
+
+ MiniportBlock = (PNDIS_MINIPORT_BLOCK)AdapterCB->hMiniportHandle;
+
+ NDISM_PROCESS_DEFERRED(MiniportBlock);
+
+ MiniportBlock->LockAcquired = FALSE;
+
+ ASSERT(AdapterCB->Flags & MINIPORT_LOCK_OWNER);
+
+ AdapterCB->Flags &= ~MINIPORT_LOCK_OWNER;
+
+ InterlockedExchange(&MiniportBlock->MiniportThread, 0);
+
+ SavedIrql = AdapterCB->SavedIrql;
+ MiniportLockIrql = AdapterCB->MiniportLockIrql;
+
+ ExReleaseSpinLock(&MiniportBlock->Lock.SpinLock, MiniportLockIrql);
+
+ KeLowerIrql(SavedIrql);
+}
+
+#endif // end of !USE_NDIS_MINIPORT_LOCKING
+
+#endif
+
diff --git a/private/ntos/ndis/ndiswan/vjslip.c b/private/ntos/ndis/ndiswan/vjslip.c
new file mode 100644
index 000000000..6e2288200
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/vjslip.c
@@ -0,0 +1,885 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ vjslip.c
+
+Abstract:
+
+Author:
+
+ Thomas J. Dimitri (TommyD)
+
+Environment:
+
+Revision History:
+
+--*/
+#include "wan.h"
+#include "tcpip.h"
+#include "vjslip.h"
+
+#define INCR(counter) ++comp->counter;
+
+// A.2 Compression
+//
+// This routine looks daunting but isn't really. The code splits into four
+// approximately equal sized sections: The first quarter manages a
+// circularly linked, least-recently-used list of `active' TCP
+// connections./47/ The second figures out the sequence/ack/window/urg
+// changes and builds the bulk of the compressed packet. The third handles
+// the special-case encodings. The last quarter does packet ID and
+// connection ID encoding and replaces the original packet header with the
+// compressed header.
+//
+// The arguments to this routine are a pointer to a packet to be
+// compressed, a pointer to the compression state data for the serial line,
+// and a flag which enables or disables connection id (C bit) compression.
+//
+// Compression is done `in-place' so, if a compressed packet is created,
+// both the start address and length of the incoming packet (the off and
+// len fields of m) will be updated to reflect the removal of the original
+// header and its replacement by the compressed header. If either a
+// compressed or uncompressed packet is created, the compression state is
+// updated. This routines returns the packet type for the transmit framer
+// (TYPE_IP, TYPE_UNCOMPRESSED_TCP or TYPE_COMPRESSED_TCP).
+//
+// Because 16 and 32 bit arithmetic is done on various header fields, the
+// incoming IP packet must be aligned appropriately (e.g., on a SPARC, the
+// IP header is aligned on a 32-bit boundary). Substantial changes would
+// have to be made to the code below if this were not true (and it would
+// probably be cheaper to byte copy the incoming header to somewhere
+// correctly aligned than to make those changes).
+//
+// Note that the outgoing packet will be aligned arbitrarily (e.g., it
+// could easily start on an odd-byte boundary).
+//
+
+UCHAR
+sl_compress_tcp(
+ PUUCHAR UNALIGNED *m_off, // Frame start (points to IP header)
+ ULONG *m_len, // Length of entire frame
+ struct slcompress *comp, // Compression struct for this link
+ ULONG compress_cid) { // Compress connection id boolean
+
+ struct cstate *cs = comp->last_cs->cs_next;
+ struct ip UNALIGNED *ip = (struct ip UNALIGNED *)*m_off;
+ ULONG hlen = ip->ip_hl & 0x0F; // last 4 bits are the length
+ struct tcphdr UNALIGNED *oth; /* last TCP header */
+ struct tcphdr UNALIGNED *th; /* current TCP header */
+
+// ----------------------------
+// 47. The two most common operations on the connection list are a `find'
+// that terminates at the first entry (a new packet for the most recently
+// used connection) and moving the last entry on the list to the head of
+// the list (the first packet from a new connection). A circular list
+// efficiently handles these two operations.
+
+ ULONG deltaS, deltaA; /* general purpose temporaries */
+ ULONG changes = 0; /* change mask */
+ UCHAR new_seq[16]; /* changes from last to current */
+ UCHAR UNALIGNED *cp = new_seq;
+ USHORT ip_len;
+
+ /*
+ * Bail if this is an IP fragment or if the TCP packet isn't
+ * `compressible' (i.e., ACK isn't set or some other control bit is
+ * set). Or if it does not contain the TCP protocol.
+ */
+ if ((ip->ip_off & 0xff3f) || *m_len < 40 || ip->ip_p != IPPROTO_TCP)
+ return (TYPE_IP);
+
+ th = (struct tcphdr UNALIGNED *) & ((PULONG) ip)[hlen];
+ if ((th->th_flags & (TH_SYN | TH_FIN | TH_RST | TH_ACK)) != TH_ACK)
+ return (TYPE_IP);
+
+ /*
+ * Packet is compressible -- we're going to send either a
+ * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way we need to
+ * locate (or create) the connection state. Special case the most
+ * recently used connection since it's most likely to be used again &
+ * we don't have to do any reordering if it's used.
+ */
+
+ //
+ // Keep stats here
+ //
+ INCR(OutPackets);
+
+ if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr ||
+ ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr ||
+ *(ULONG UNALIGNED *) th != ((ULONG UNALIGNED *) &cs->cs_ip)[cs->cs_ip.ip_hl & 0x0F]) {
+
+ /*
+ * Wasn't the first -- search for it.
+ *
+ * States are kept in a circularly linked list with last_cs
+ * pointing to the end of the list. The list is kept in lru
+ * order by moving a state to the head of the list whenever
+ * it is referenced. Since the list is short and,
+ * empirically, the connection we want is almost always near
+ * the front, we locate states via linear search. If we
+ * don't find a state for the datagram, the oldest state is
+ * (re-)used.
+ */
+ struct cstate *lcs;
+ struct cstate *lastcs = comp->last_cs;
+
+ do {
+ lcs = cs;
+ cs = cs->cs_next;
+ INCR(OutSearches);
+
+ if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr &&
+ ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr &&
+ *(ULONG UNALIGNED *) th == ((ULONG UNALIGNED *) &cs->cs_ip)[cs->cs_ip.ip_hl & 0x0F])
+
+ goto found;
+
+ } while (cs != lastcs);
+
+ /*
+ * Didn't find it -- re-use oldest cstate. Send an
+ * uncompressed packet that tells the other side what
+ * connection number we're using for this conversation. Note
+ * that since the state list is circular, the oldest state
+ * points to the newest and we only need to set last_cs to
+ * update the lru linkage.
+ */
+
+ INCR(OutMisses);
+
+ //
+ // A miss!
+ //
+ comp->last_cs = lcs;
+ hlen += (th->th_off >> 4);
+ hlen <<= 2;
+
+ if (hlen > *m_len) {
+ return(TYPE_IP);
+ }
+
+ goto uncompressed;
+
+found:
+ /* Found it -- move to the front on the connection list. */
+ if (cs == lastcs)
+ comp->last_cs = lcs;
+ else {
+ lcs->cs_next = cs->cs_next;
+ cs->cs_next = lastcs->cs_next;
+ lastcs->cs_next = cs;
+ }
+ }
+
+ /*
+ * Make sure that only what we expect to change changed. The first
+ * line of the `if' checks the IP protocol version, header length &
+ * type of service. The 2nd line checks the "Don't fragment" bit.
+ * The 3rd line checks the time-to-live and protocol (the protocol
+ * check is unnecessary but costless). The 4th line checks the TCP
+ * header length. The 5th line checks IP options, if any. The 6th
+ * line checks TCP options, if any. If any of these things are
+ * different between the previous & current datagram, we send the
+ * current datagram `uncompressed'.
+ */
+ oth = (struct tcphdr UNALIGNED *) & ((ULONG UNALIGNED *) &cs->cs_ip)[hlen];
+ deltaS = hlen;
+ hlen += (th->th_off >> 4);
+ hlen <<= 2;
+
+ //
+ // Bug fix? It's in cslip.tar.Z
+ //
+ if (hlen > *m_len) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_VJ,("Bad TCP packet length\n"));
+ return(TYPE_IP);
+ }
+
+ if (((PUSHORT) ip)[0] != ((PUSHORT) &cs->cs_ip)[0] ||
+ ((PUSHORT) ip)[3] != ((PUSHORT) &cs->cs_ip)[3] ||
+ ((PUSHORT) ip)[4] != ((PUSHORT) &cs->cs_ip)[4] ||
+ (th->th_off >> 4) != (oth->th_off >> 4) ||
+ (deltaS > 5 &&
+ memcmp((PUCHAR)(ip + 1), (PUCHAR)(&cs->cs_ip + 1), (deltaS - 5) << 2)) ||
+ ((th->th_off >> 4) > 5 &&
+ memcmp((PUCHAR)(th + 1), (PUCHAR)(oth + 1), ((th->th_off >> 4) - 5) << 2))) {
+
+ goto uncompressed;
+ }
+
+ /*
+ * Figure out which of the changing fields changed. The receiver
+ * expects changes in the order: urgent, window, ack, seq.
+ */
+ if (th->th_flags & TH_URG) {
+ deltaS = ntohs(th->th_urp);
+ ENCODEZ(deltaS);
+ changes |= NEW_U;
+ } else if (th->th_urp != oth->th_urp) {
+
+ /*
+ * argh! URG not set but urp changed -- a sensible
+ * implementation should never do this but RFC793 doesn't
+ * prohibit the change so we have to deal with it.
+ */
+ goto uncompressed;
+ }
+
+ if (deltaS = (USHORT) (ntohs(th->th_win) - ntohs(oth->th_win))) {
+ ENCODE(deltaS);
+ changes |= NEW_W;
+ }
+ if (deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack)) {
+ if (deltaA > 0xffff) {
+ goto uncompressed;
+ }
+
+ ENCODE(deltaA);
+ changes |= NEW_A;
+ }
+ if (deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq)) {
+ if (deltaS > 0xffff) {
+ goto uncompressed;
+ }
+
+ ENCODE(deltaS);
+ changes |= NEW_S;
+ }
+
+ ip_len = ntohs(cs->cs_ip.ip_len);
+
+ /*
+ * Look for the special-case encodings.
+ */
+ switch (changes) {
+
+ case 0:
+ /*
+ * Nothing changed. If this packet contains data and the last
+ * one didn't, this is probably a data packet following an
+ * ack (normal on an interactive connection) and we send it
+ * compressed. Otherwise it's probably a retransmit,
+ * retransmitted ack or window probe. Send it uncompressed
+ * in case the other side missed the compressed version.
+ */
+ if (ip->ip_len != cs->cs_ip.ip_len &&
+ ip_len == hlen)
+
+ break;
+
+ /* (fall through) */
+
+ case SPECIAL_I:
+ case SPECIAL_D:
+ /*
+ * Actual changes match one of our special case encodings --
+ * send packet uncompressed.
+ */
+ goto uncompressed;
+
+ case NEW_S | NEW_A:
+ if (deltaS == deltaA &&
+ deltaS == ip_len - hlen) {
+ /* special case for echoed terminal traffic */
+ changes = SPECIAL_I;
+ cp = new_seq;
+ }
+ break;
+
+ case NEW_S:
+ if (deltaS == ip_len - hlen) {
+ /* special case for data xfer */
+ changes = SPECIAL_D;
+ cp = new_seq;
+ }
+ break;
+ }
+
+ deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id);
+
+ if (deltaS != 1) {
+ ENCODEZ(deltaS);
+ changes |= NEW_I;
+ }
+
+ if (th->th_flags & TH_PUSH)
+ changes |= TCP_PUSH_BIT;
+ /*
+ * Grab the cksum before we overwrite it below. Then update our
+ * state with this packet's header.
+ */
+ deltaA = (th->th_sumhi << 8) + th->th_sumlo;
+
+ NdisMoveMemory((PUCHAR)&cs->cs_ip,
+ (PUCHAR)ip,
+ hlen);
+
+ /*
+ * We want to use the original packet as our compressed packet. (cp -
+ * new_seq) is the number of bytes we need for compressed sequence
+ * numbers. In addition we need one byte for the change mask, one
+ * for the connection id and two for the tcp checksum. So, (cp -
+ * new_seq) + 4 bytes of header are needed. hlen is how many bytes
+ * of the original packet to toss so subtract the two to get the new
+ * packet size.
+ */
+ deltaS = cp - new_seq;
+ cp = (UCHAR UNALIGNED *) ip;
+
+ if (compress_cid == 0 || comp->last_xmit != cs->cs_id) {
+ comp->last_xmit = cs->cs_id;
+ hlen -= deltaS + 4;
+ cp += hlen;
+ *cp++ = (UCHAR)(changes | NEW_C);
+ *cp++ = cs->cs_id;
+ } else {
+ hlen -= deltaS + 3;
+ cp += hlen;
+ *cp++ = (UCHAR)changes;
+ }
+
+ *m_len -= hlen;
+ *m_off += hlen;
+ *cp++ = (UCHAR)(deltaA >> 8);
+ *cp++ = (UCHAR)(deltaA);
+
+ NdisMoveMemory((PUCHAR)cp,
+ (PUCHAR)new_seq,
+ deltaS);
+
+ INCR(OutCompressed);
+ return (TYPE_COMPRESSED_TCP);
+
+uncompressed:
+ /*
+ * Update connection state cs & send uncompressed packet
+ * ('uncompressed' means a regular ip/tcp packet but with the
+ * 'conversation id' we hope to use on future compressed packets in
+ * the protocol field).
+ */
+
+ NdisMoveMemory((PUCHAR)&cs->cs_ip,
+ (PUCHAR)ip,
+ hlen);
+
+ ip->ip_p = cs->cs_id;
+ comp->last_xmit = cs->cs_id;
+ return (TYPE_UNCOMPRESSED_TCP);
+}
+
+
+
+
+
+// A.3 Decompression
+//
+// This routine decompresses a received packet. It is called with a
+// pointer to the packet, the packet length and type, and a pointer to the
+// compression state structure for the incoming serial line. It returns a
+// pointer to the resulting packet or zero if there were errors in the
+// incoming packet. If the packet is COMPRESSED_TCP or UNCOMPRESSED_TCP,
+// the compression state will be updated.
+//
+// The new packet will be constructed in-place. That means that there must
+// be 128 bytes of free space in front of bufp to allow room for the
+// reconstructed IP and TCP headers. The reconstructed packet will be
+// aligned on a 32-bit boundary.
+//
+
+//LONG
+//sl_uncompress_tcp(
+// PUUCHAR UNALIGNED *bufp,
+// LONG len,
+// UCHAR type,
+// struct slcompress *comp) {
+LONG
+sl_uncompress_tcp(
+ PUUCHAR UNALIGNED *InBuffer,
+ PULONG InLength,
+ UCHAR UNALIGNED *OutBuffer,
+ PULONG OutLength,
+ UCHAR type,
+ struct slcompress *comp
+ )
+{
+ UCHAR UNALIGNED *cp;
+ ULONG inlen;
+ ULONG hlen, changes;
+ struct tcphdr UNALIGNED *th;
+ struct cstate *cs;
+ struct ip UNALIGNED *ip;
+
+ inlen = *InLength;
+
+ switch (type) {
+
+ case TYPE_ERROR:
+ default:
+ NdisWanDbgOut(DBG_FAILURE, DBG_VJ, ("Packet transmission error type 0x%.2x\n",type));
+ goto bad;
+
+ case TYPE_IP:
+ break;
+
+ case TYPE_UNCOMPRESSED_TCP:
+ /*
+ * Locate the saved state for this connection. If the state
+ * index is legal, clear the 'discard' flag.
+ */
+ ip = (struct ip UNALIGNED *) *InBuffer;
+ if (ip->ip_p >= comp->MaxStates) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_VJ, ("Max state exceeded %u\n", ip->ip_p));
+ goto bad;
+ }
+
+ cs = &comp->rstate[comp->last_recv = ip->ip_p];
+ comp->flags &= ~SLF_TOSS;
+
+ /*
+ * Restore the IP protocol field then save a copy of this
+ * packet header. (The checksum is zeroed in the copy so we
+ * don't have to zero it each time we process a compressed
+ * packet.
+ */
+ hlen = ip->ip_hl & 0x0F;
+ hlen += ((struct tcphdr UNALIGNED *) & ((ULONG UNALIGNED *) ip)[hlen])->th_off >> 4;
+ hlen <<= 2;
+
+ NdisMoveMemory((PUCHAR)&cs->cs_ip,
+ (PUCHAR)ip,
+ hlen);
+
+ cs->cs_ip.ip_p = IPPROTO_TCP;
+
+ NdisMoveMemory((PUCHAR)OutBuffer,
+ (PUCHAR)&cs->cs_ip,
+ hlen);
+
+ cs->cs_ip.ip_sum = 0;
+ cs->cs_hlen = (USHORT)hlen;
+
+ *InBuffer = (PUCHAR)ip + hlen;
+ *InLength = inlen - hlen;
+ *OutLength = hlen;
+
+ INCR(InUncompressed);
+ return (inlen);
+
+ case TYPE_COMPRESSED_TCP:
+ break;
+ }
+
+ /* We've got a compressed packet. */
+ INCR(InCompressed);
+ cp = *InBuffer;
+ changes = *cp++;
+
+ if (changes & NEW_C) {
+ /*
+ * Make sure the state index is in range, then grab the
+ * state. If we have a good state index, clear the 'discard'
+ * flag.
+ */
+ if (*cp >= comp->MaxStates) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_VJ, ("MaxState of %u too big\n", *cp));
+ goto bad;
+ }
+
+ comp->flags &= ~SLF_TOSS;
+ comp->last_recv = *cp++;
+ } else {
+ /*
+ * This packet has an implicit state index. If we've had a
+ * line error since the last time we got an explicit state
+ * index, we have to toss the packet.
+ */
+ if (comp->flags & SLF_TOSS) {
+ NdisWanDbgOut(DBG_FAILURE, DBG_VJ,("Packet has state index, have to toss it\n"));
+ INCR(InTossed);
+ return (0);
+ }
+ }
+
+ /*
+ * Find the state then fill in the TCP checksum and PUSH bit.
+ */
+
+ cs = &comp->rstate[comp->last_recv];
+ hlen = (cs->cs_ip.ip_hl & 0x0F) << 2;
+ th = (struct tcphdr UNALIGNED *) & ((UCHAR UNALIGNED *) &cs->cs_ip)[hlen];
+
+ th->th_sumhi = cp[0];
+ th->th_sumlo = cp[1];
+
+ cp += 2;
+ if (changes & TCP_PUSH_BIT)
+ th->th_flags |= TH_PUSH;
+ else
+ th->th_flags &= ~TH_PUSH;
+
+ /*
+ * Fix up the state's ack, seq, urg and win fields based on the
+ * changemask.
+ */
+ switch (changes & SPECIALS_MASK) {
+ case SPECIAL_I:
+ {
+ UCHAR UNALIGNED * piplen=(UCHAR UNALIGNED *)&(cs->cs_ip.ip_len);
+ UCHAR UNALIGNED * ptcplen;
+ ULONG tcplen;
+ ULONG i;
+
+ i = ((piplen[0] << 8) + piplen[1]) - cs->cs_hlen;
+
+// th->th_ack = htonl(ntohl(th->th_ack) + i);
+
+ ptcplen=(UCHAR UNALIGNED *)&(th->th_ack);
+ tcplen=(ptcplen[0] << 24) + (ptcplen[1] << 16) +
+ (ptcplen[2] << 8) + ptcplen[3] + i;
+ ptcplen[3]=(UCHAR)(tcplen);
+ ptcplen[2]=(UCHAR)(tcplen >> 8);
+ ptcplen[1]=(UCHAR)(tcplen >> 16);
+ ptcplen[0]=(UCHAR)(tcplen >> 24);
+
+
+// th->th_seq = htonl(ntohl(th->th_seq) + i);
+
+ ptcplen=(UCHAR UNALIGNED *)&(th->th_seq);
+ tcplen=(ptcplen[0] << 24) + (ptcplen[1] << 16) +
+ (ptcplen[2] << 8) + ptcplen[3] + i;
+ ptcplen[3]=(UCHAR)(tcplen);
+ ptcplen[2]=(UCHAR)(tcplen >> 8);
+ ptcplen[1]=(UCHAR)(tcplen >> 16);
+ ptcplen[0]=(UCHAR)(tcplen >> 24);
+
+ }
+ break;
+
+ case SPECIAL_D:
+ {
+// th->th_seq = htonl(ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len)
+// - cs->cs_hlen);
+
+ UCHAR UNALIGNED *piplen=(UCHAR UNALIGNED *)&(cs->cs_ip.ip_len);
+ UCHAR UNALIGNED *ptcplen;
+ ULONG tcplen;
+ ULONG i;
+
+ i = ((piplen[0] << 8) + piplen[1]) - cs->cs_hlen;
+
+ ptcplen=(UCHAR UNALIGNED *)&(th->th_seq);
+ tcplen=(ptcplen[0] << 24) + (ptcplen[1] << 16) +
+ (ptcplen[2] << 8) + ptcplen[3] + i;
+
+ ptcplen[3]=(UCHAR)(tcplen);
+ ptcplen[2]=(UCHAR)(tcplen >> 8);
+ ptcplen[1]=(UCHAR)(tcplen >> 16);
+ ptcplen[0]=(UCHAR)(tcplen >> 24);
+
+
+ }
+
+ break;
+
+ default:
+ if (changes & NEW_U) {
+ th->th_flags |= TH_URG;
+ DECODEU(th->th_urp)
+ } else
+ th->th_flags &= ~TH_URG;
+
+ if (changes & NEW_W)
+ DECODES(th->th_win);
+ if (changes & NEW_A)
+ DECODEL(th->th_ack)
+ if (changes & NEW_S)
+ DECODEL(th->th_seq)
+
+ break;
+ }
+ /* Update the IP ID */
+ if (changes & NEW_I) {
+
+ DECODES(cs->cs_ip.ip_id)
+
+ } else {
+
+ USHORT id;
+ UCHAR UNALIGNED *pid = (UCHAR UNALIGNED *)&(cs->cs_ip.ip_id);
+
+// cs->cs_ip.ip_id = htons(ntohs(cs->cs_ip.ip_id) + 1);
+ id=(pid[0] << 8) + pid[1] + 1;
+ pid[0]=(UCHAR)(id >> 8);
+ pid[1]=(UCHAR)(id);
+ }
+
+
+ /*
+ * At this point, cp points to the first byte of data in the packet.
+ * If we're not aligned on a 4-byte boundary, copy the data down so
+ * the IP & TCP headers will be aligned. Then back up cp by the
+ * TCP/IP header length to make room for the reconstructed header (we
+ * assume the packet we were handed has enough space to prepend 128
+ * bytes of header). Adjust the lenth to account for the new header
+ * & fill in the IP total length.
+ */
+// len -= (cp - *bufp);
+ inlen -= (cp - *InBuffer);
+
+ if (inlen < 0) {
+
+ /*
+ * we must have dropped some characters (crc should detect
+ * this but the old slip framing won't)
+ */
+ NdisWanDbgOut(DBG_FAILURE, DBG_VJ,("len has dropped below 0!\n"));
+ goto bad;
+ }
+//
+// SCREW 4 byte alignement! It's just a useless big copy!
+//
+// if ((ULONG) cp & 3) {
+// if (len > 0)
+// //
+// // BUG BUG we want OVBCOPY..
+// //
+// NdisMoveMemory(
+// (PUCHAR)((ULONG) cp & ~3),
+// cp,
+// len);
+// cp = (PUCHAR) ((ULONG) cp & ~3);
+// }
+
+// cp -= cs->cs_hlen;
+// len += cs->cs_hlen;
+
+// cs->cs_ip.ip_len = htons(len);
+ cs->cs_ip.ip_len = htons(inlen + cs->cs_hlen);
+
+// NdisMoveMemory(
+// (PUCHAR)cp,
+// (PUCHAR)&cs->cs_ip,
+// cs->cs_hlen);
+
+ NdisMoveMemory((PUCHAR)OutBuffer,
+ (PUCHAR)&cs->cs_ip,
+ cs->cs_hlen);
+
+// *bufp = cp;
+ *InBuffer = cp;
+ *InLength = inlen;
+ *OutLength = cs->cs_hlen;
+
+ /* recompute the ip header checksum */
+ {
+// USHORT UNALIGNED * bp = (USHORT UNALIGNED *) cp;
+ USHORT UNALIGNED * bp = (USHORT UNALIGNED *) OutBuffer;
+
+ for (changes = 0; hlen > 0; hlen -= 2)
+ changes += *bp++;
+
+ changes = (changes & 0xffff) + (changes >> 16);
+ changes = (changes & 0xffff) + (changes >> 16);
+// ((struct ip UNALIGNED *) cp)->ip_sum = (USHORT)~changes;
+ ((struct ip UNALIGNED *) OutBuffer)->ip_sum = (USHORT)~changes;
+ }
+
+ return (inlen + cs->cs_hlen);
+
+bad:
+ comp->flags |= SLF_TOSS;
+ INCR(InErrors);
+ return (0);
+}
+
+
+
+
+// A.4 Initialization
+//
+// This routine initializes the state structure for both the transmit and
+// receive halves of some serial line. It must be called each time the
+// line is brought up.
+//
+
+NDIS_STATUS
+sl_compress_init(
+ struct slcompress **retcomp,
+ UCHAR MaxStates
+ )
+{
+ ULONG i;
+ struct cstate *tstate; // = comp->tstate;
+ struct slcompress *comp;
+
+ comp = *retcomp;
+
+ //
+ // Do we need to allocate memory for this bundle
+ //
+
+ if (comp != NULL) {
+ return (NDIS_STATUS_SUCCESS);
+ }
+
+
+ NdisWanAllocateMemory(&comp, sizeof(slcompress));
+
+ //
+ // If there was no memory to allocate
+ //
+ if (comp == NULL) {
+
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ tstate = comp->tstate;
+
+ /*
+ * Clean out any junk left from the last time line was used.
+ */
+ NdisZeroMemory(
+ (PUCHAR) comp,
+ sizeof(*comp));
+
+ /*
+ * Link the transmit states into a circular list.
+ */
+ for (i = MaxStates - 1; i > 0; --i) {
+ tstate[i].cs_id = (UCHAR)i;
+ tstate[i].cs_next = &tstate[i - 1];
+ }
+
+ tstate[0].cs_next = &tstate[MaxStates - 1];
+ tstate[0].cs_id = 0;
+ comp->last_cs = &tstate[0];
+
+ /*
+ * Make sure we don't accidentally do CID compression
+ * (assumes MAX_VJ_STATES < 255).
+ */
+ comp->last_recv = 255;
+ comp->last_xmit = 255;
+ comp->flags = SLF_TOSS;
+ comp->MaxStates=MaxStates;
+
+ *retcomp = comp;
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+VOID
+sl_compress_terminate(
+ struct slcompress **comp
+ )
+{
+ if (*comp != NULL) {
+ NdisWanFreeMemory(*comp);
+ *comp = NULL;
+ }
+}
+
+// A.5 Berkeley Unix dependencies
+//
+// Note: The following is of interest only if you are trying to bring the
+// sample code up on a system that is not derived from 4BSD (Berkeley
+// Unix).
+//
+// The code uses the normal Berkeley Unix header files (from
+// /usr/include/netinet) for definitions of the structure of IP and TCP
+// headers. The structure tags tend to follow the protocol RFCs closely
+// and should be obvious even if you do not have access to a 4BSD
+// system./48/
+//
+// ----------------------------
+// 48. In the event they are not obvious, the header files (and all the
+// Berkeley networking code) can be anonymous ftp'd from host
+//
+//
+// The macro BCOPY(src, dst, amt) is invoked to copy amt bytes from src to
+// dst. In BSD, it translates into a call to BCOPY. If you have the
+// misfortune to be running System-V Unix, it can be translated into a call
+// to memcpy. The macro OVBCOPY(src, dst, amt) is used to copy when src
+// and dst overlap (i.e., when doing the 4-byte alignment copy). In the
+// BSD kernel, it translates into a call to ovbcopy. Since AT&T botched
+// the definition of memcpy, this should probably translate into a copy
+// loop under System-V.
+//
+// The macro BCMP(src, dst, amt) is invoked to compare amt bytes of src and
+// dst for equality. In BSD, it translates into a call to bcmp. In
+// System-V, it can be translated into a call to memcmp or you can write a
+// routine to do the compare. The routine should return zero if all bytes
+// of src and dst are equal and non-zero otherwise.
+//
+// The routine ntohl(dat) converts (4 byte) long dat from network byte
+// order to host byte order. On a reasonable cpu this can be the no-op
+// macro:
+// #define ntohl(dat) (dat)
+//
+// On a Vax or IBM PC (or anything with Intel byte order), you will have to
+// define a macro or routine to rearrange bytes.
+//
+// The routine ntohs(dat) is like ntohl but converts (2 byte) shorts
+// instead of longs. The routines htonl(dat) and htons(dat) do the inverse
+// transform (host to network byte order) for longs and shorts.
+//
+// A struct mbuf is used in the call to sl_compress_tcp because that
+// routine needs to modify both the start address and length if the
+// incoming packet is compressed. In BSD, an mbuf is the kernel's buffer
+// management structure. If other systems, the following definition should
+// be sufficient:
+//
+// struct mbuf {
+// UCHAR *m_off; /* pointer to start of data */
+// int m_len; /* length of data */
+// };
+//
+// #define mtod(m, t) ((t)(m->m_off))
+//
+//
+// B Compatibility with past mistakes
+//
+//
+// When combined with the modern PPP serial line protocol[9], the use of
+// header compression is automatic and invisible to the user.
+// Unfortunately, many sites have existing users of the SLIP described in
+// [12] which doesn't allow for different protocol types to distinguish
+// header compressed packets from IP packets or for version numbers or an
+// option exchange that could be used to automatically negotiate header
+// compression.
+//
+// The author has used the following tricks to allow header compressed SLIP
+// to interoperate with the existing servers and clients. Note that these
+// are hacks for compatibility with past mistakes and should be offensive
+// to any right thinking person. They are offered solely to ease the pain
+// of running SLIP while users wait patiently for vendors to release PPP.
+//
+//
+// B.1 Living without a framing `type' byte
+//
+// The bizarre packet type numbers in sec. A.1 were chosen to allow a
+// `packet type' to be sent on lines where it is undesirable or impossible
+// to add an explicit type byte. Note that the first byte of an IP packet
+// always contains `4' (the IP protocol version) in the top four bits. And
+// that the most significant bit of the first byte of the compressed header
+// is ignored. Using the packet types in sec. A.1, the type can be encoded
+// in the most significant bits of the outgoing packet using the code
+//
+// p->dat[0] |= sl_compress_tcp(p, comp);
+//
+// and decoded on the receive side by
+//
+// if (p->dat[0] & 0x80)
+// type = TYPE_COMPRESSED_TCP;
+// else if (p->dat[0] >= 0x70) {
+// type = TYPE_UNCOMPRESSED_TCP;
+// p->dat[0] &=~ 0x30;
+// } else
+// type = TYPE_IP;
+// status = sl_uncompress_tcp(p, type, comp);
+
+
diff --git a/private/ntos/ndis/ndiswan/vjslip.h b/private/ntos/ndis/ndiswan/vjslip.h
new file mode 100644
index 000000000..e171125ea
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/vjslip.h
@@ -0,0 +1,249 @@
+#ifndef _VJSLIP_
+#define _VJSLIP_
+
+/*
+ * Copyright (c) 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are
+ * permitted provided that the above copyright notice and this
+ * paragraph are duplicated in all such forms and that any
+ * documentation, advertising materials, and other materials
+ * related to such distribution and use acknowledge that the
+ * software was developed by the University of California,
+ * Berkeley. The name of the University may not be used to
+ * endorse or promote products derived from this software
+ * without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE
+ * IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE.
+ */
+
+
+// A.1 Definitions and State Data
+
+#define MAX_VJ_STATES 16 /* must be >2 and <255 */
+#define MAX_HDR 128 /* max TCP+IP hdr length (by protocol def) */
+
+
+//
+// NT is little endian, so we follow these rules
+//
+#define ntohs(x) (USHORT)( ((x) >> 8) + (((x) & 0xFF) << 8) )
+
+#define ntohl(x) (ULONG) ( ((x) >> 24) + (((x) & 0xFF0000) >> 8) +\
+ (((x) & 0xFF00) << 8) + (((x) & 0xFF) << 24) )
+
+#define htons(x) ntohs(x)
+#define htonl(x) ntohl(x)
+
+
+/* packet types */
+#define TYPE_IP 0x40
+#define TYPE_UNCOMPRESSED_TCP 0x70
+#define TYPE_COMPRESSED_TCP 0x80
+#define TYPE_ERROR 0x00
+ /* this is not a type that ever appears on
+ * the wire. The receive framer uses it to
+ * tell the decompressor there was a packet
+ * transmission error. */
+/*
+ * Bits in first octet of compressed packet
+ */
+
+/* flag bits for what changed in a packet */
+
+#define NEW_C 0x40
+#define NEW_I 0x20
+#define TCP_PUSH_BIT 0x10
+
+#define NEW_S 0x08
+#define NEW_A 0x04
+#define NEW_W 0x02
+#define NEW_U 0x01
+
+
+/* reserved, special-case values of above */
+#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */
+#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */
+#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U)
+
+
+/*
+ * "state" data for each active tcp conversation on the wire. This is
+ * basically a copy of the entire IP/TCP header from the last packet together
+ * with a small identifier the transmit & receive ends of the line use to
+ * locate saved header.
+ */
+
+struct cstate {
+ struct cstate *cs_next; /* next most recently used cstate (xmit only) */
+ USHORT cs_hlen; /* size of hdr (receive only) */
+ UCHAR cs_id; /* connection # associated with this state */
+ UCHAR cs_filler;
+ union {
+ UCHAR hdr[MAX_HDR];
+ struct ip UNALIGNED csu_ip; /* ip/tcp hdr from most recent packet */
+ } slcs_u;
+};
+
+#define cs_ip slcs_u.csu_ip
+
+#define cs_hdr slcs_u.csu_hdr
+
+/*
+ * all the state data for one serial line (we need one of these per line).
+ */
+typedef struct slcompress slcompress;
+
+struct slcompress {
+ struct cstate *last_cs; /* most recently used tstate */
+ UCHAR last_recv; /* last rcvd conn. id */
+ UCHAR last_xmit; /* last sent conn. id */
+ USHORT flags;
+ UCHAR MaxStates;
+//
+// Some Statistics
+//
+ ULONG OutPackets;
+ ULONG OutCompressed;
+ ULONG OutSearches;
+ ULONG OutMisses;
+ ULONG InUncompressed;
+ ULONG InCompressed;
+ ULONG InErrors;
+ ULONG InTossed;
+
+ struct cstate tstate[MAX_VJ_STATES]; /* xmit connection states */
+ struct cstate rstate[MAX_VJ_STATES]; /* receive connection states */
+};
+
+struct mbuf {
+ PUCHAR m_off; // pointer to start of data
+ UINT m_len; // length of data
+};
+
+#define mtod(m,t) ((t)(m->m_off))
+
+/* flag values */
+#define SLF_TOSS 1 /* tossing rcvd frames because of input err */
+
+/*
+ * The following macros are used to encode and decode numbers. They all
+ * assume that `cp' points to a buffer where the next byte encoded (decoded)
+ * is to be stored (retrieved). Since the decode routines do arithmetic,
+ * they have to convert from and to network byte order.
+ */
+
+/*
+ * ENCODE encodes a number that is known to be non-zero. ENCODEZ checks for
+ * zero (zero has to be encoded in the long, 3 byte form).
+ */
+#define ENCODE(n) { \
+ if ((USHORT)(n) >= 256) { \
+ *cp++ = 0; \
+ cp[1] = (UCHAR)(n); \
+ cp[0] = (UCHAR)((n) >> 8); \
+ cp += 2; \
+ } else { \
+ *cp++ = (UCHAR)(n); \
+ } \
+}
+
+#define ENCODEZ(n) { \
+ if ((USHORT)(n) >= 256 || (USHORT)(n) == 0) { \
+ *cp++ = 0; \
+ cp[1] = (UCHAR)(n); \
+ cp[0] = (UCHAR)((n) >> 8); \
+ cp += 2; \
+ } else { \
+ *cp++ = (UCHAR)(n); \
+ } \
+}
+
+/*
+ * DECODEL takes the (compressed) change at byte cp and adds it to the
+ * current value of packet field 'f' (which must be a 4-byte (long) integer
+ * in network byte order). DECODES does the same for a 2-byte (short) field.
+ * DECODEU takes the change at cp and stuffs it into the (short) field f.
+ * 'cp' is updated to point to the next field in the compressed header.
+ */
+
+#define DECODEL(f) { \
+ ULONG _x_ = ntohl(f); \
+ if (*cp == 0) {\
+ _x_ += ((cp[1] << 8) + cp[2]); \
+ (f) = htonl(_x_); \
+ cp += 3; \
+ } else { \
+ _x_ += *cp; \
+ (f) = htonl(_x_); \
+ cp++; \
+ } \
+}
+
+#define DECODES(f) { \
+ USHORT _x_= ntohs(f); \
+ if (*cp == 0) {\
+ _x_ += ((cp[1] << 8) + cp[2]); \
+ (f) = htons(_x_); \
+ cp += 3; \
+ } else { \
+ _x_ += *cp; \
+ (f) = htons(_x_); \
+ cp++; \
+ } \
+}
+
+#define DECODEU(f) { \
+ USHORT _x_; \
+ if (*cp == 0) {\
+ _x_=(cp[1] << 8) + cp[2]; \
+ (f) = htons(_x_); \
+ cp += 3; \
+ } else { \
+ _x_=*cp; \
+ (f) = htons(_x_); \
+ cp++; \
+ } \
+}
+
+typedef UCHAR UNALIGNED * PUUCHAR;
+
+
+UCHAR
+sl_compress_tcp(
+ PUUCHAR UNALIGNED *m_off, // Frame start (points to IP header)
+ PULONG m_len, // Length of entire frame
+ struct slcompress *comp, // Compression struct for this link
+ ULONG compress_cid); // Compress connection id boolean
+
+//LONG
+//sl_uncompress_tcp(
+// PUUCHAR UNALIGNED *bufp,
+// LONG len,
+// UCHAR type,
+// struct slcompress *comp);
+LONG
+sl_uncompress_tcp(
+ PUUCHAR UNALIGNED *InBuffer,
+ PULONG InLength,
+ UCHAR UNALIGNED *OutBuffer,
+ PULONG OutLength,
+ UCHAR type,
+ struct slcompress *comp
+ );
+
+NDIS_STATUS
+sl_compress_init(
+ struct slcompress **comp,
+ UCHAR MaxStates);
+
+VOID
+sl_compress_terminate(
+ struct slcompress **comp
+ );
+
+#endif // _VJSLIP_
+
diff --git a/private/ntos/ndis/ndiswan/wan.h b/private/ntos/ndis/ndiswan/wan.h
new file mode 100644
index 000000000..6137d7a18
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/wan.h
@@ -0,0 +1,42 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ Wan.h
+
+Abstract:
+
+ This file contains all include files for the NdisWan driver.
+
+
+
+Author:
+
+ Tony Bell (TonyBe) June 06, 1995
+
+Environment:
+
+ Kernel Mode
+
+Revision History:
+
+ TonyBe 06/06/95 Created
+
+--*/
+
+#include <ndis.h>
+#include <ndiswan.h>
+#include <ndistapi.h>
+#include <efilter.h>
+#include <ntddk.h>
+#include <ndisprv.h>
+
+#include "wandefs.h"
+#include "wanpub.h"
+#include "wantypes.h"
+#include "adapter.h"
+#include "global.h"
+#include "wanproto.h"
+
diff --git a/private/ntos/ndis/ndiswan/wandefs.h b/private/ntos/ndis/ndiswan/wandefs.h
new file mode 100644
index 000000000..18fd45d7b
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/wandefs.h
@@ -0,0 +1,649 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ Wandefs.h
+
+Abstract:
+
+ This file contains defines for the NdisWan driver.
+
+Author:
+
+ Tony Bell (TonyBe) June 06, 1995
+
+Environment:
+
+ Kernel Mode
+
+Revision History:
+
+ TonyBe 06/06/95 Created
+
+--*/
+
+#ifndef _NDISWAN_DEFS_
+#define _NDISWAN_DEFS_
+
+//
+// Define if we are going to pull the miniport name out of
+// an ndis wrapper control structure!!!!!! (kinda dirty)
+//
+#define MINIPORT_NAME 1
+
+//
+// Maximum number of protocols we can support
+//
+#define MAX_PROTOCOLS 32
+
+//
+// Identifiers for protocol type being added to the
+// protocol lookup table
+//
+#define PROTOCOL_TYPE 0
+#define PPP_TYPE 1
+
+//
+// Flags for Send packet properties
+//
+#define SEND_ON_WIRE 0x00000001
+#define SELF_DIRECTED 0x00000002
+
+//
+// Known protocol ID's
+//
+#define PROTOCOL_PRIVATE_IO 0xAB00
+#define PROTOCOL_IP 0x0800
+#define PROTOCOL_IPX 0x8137
+#define PROTOCOL_NBF 0x80D5
+
+//
+// Known PPP protocol ID's
+//
+#define PPP_PROTOCOL_PRIVATE_IO 0x00AB
+#define PPP_PROTOCOL_IP 0x0021
+#define PPP_PROTOCOL_UNCOMPRESSED_TCP 0x002F
+#define PPP_PROTOCOL_COMPRESSED_TCP 0x002D
+#define PPP_PROTOCOL_IPX 0x002B
+#define PPP_PROTOCOL_NBF 0x003F
+#define PPP_PROTOCOL_COMPRESSION 0x00FD
+#define PPP_PROTOCOL_COMP_RESET 0x80FD
+
+//
+// Returned from protocol table lookup if value is
+// not found
+//
+#define INVALID_PROTOCOL 0xFFFF
+
+#define RESERVED_PROTOCOLCB 0xFFFFFFFF
+
+//
+// OID Masks
+//
+#define OID_GEN 0x00000000
+#define OID_802_3 0x01000000
+#define OID_WAN 0x04000000
+#define SET_OID 0x00000001
+#define QUERY_OID 0x00000002
+
+#define MAX_FRAME_SIZE 1500
+#define MAX_TOTAL_SIZE 1500
+#define MAX_OUTSTANDING_PACKETS 10
+#define DEFAULT_MAX_MRRU 1600
+#define IO_SEND_MASK_BIT 0x00000001
+#define ONE_HUNDRED_MILS 1000000
+#define ONE_SECOND 10000000
+#define TEN_SECONDS 100000000
+#define MILS_TO_100NANOS 10000
+#define SAMPLE_ARRAY_SIZE 10
+
+//
+// Multilink defines
+//
+#define MULTILINK_BEGIN_FRAME 0x80
+#define MULTILINK_END_FRAME 0x40
+#define MULTILINK_COMPLETE_FRAME 0xC0
+#define MULTILINK_FLAG_MASK 0xC0
+#define SHORT_SEQ_MASK 0x0FFF
+#define TEST_SHORT_SEQ 0x0800
+#define LONG_SEQ_MASK 0x0FFFFFF
+#define TEST_LONG_SEQ 0x00800000
+#define MAX_MRRU 1614
+#define MIN_SEND 1500
+
+#define SEQ_EQ(_a, _b) ((int)((_a) - (_b)) == 0)
+#define SEQ_LT(_a, _b, _t) (!SEQ_EQ(_a, _b) && ((int)((_a) - (_b)) & _t))
+#define SEQ_LTE(_a, _b, _t) (SEQ_EQ(_a, _b) || ((int)((_a) - (_b)) & _t))
+#define SEQ_GT(_a, _b, _t) (!SEQ_EQ(_a, _b) && !((int)((_a) - (_b)) & _t))
+#define SEQ_GTE(_a, _b, _t) (SEQ_EQ(_a, _b) || !((int)((_a) - (_b)) & _t))
+
+//
+// Debugging
+//
+#define DBG_DEATH 1
+#define DBG_CRITICAL_ERROR 2
+#define DBG_FAILURE 4
+#define DBG_INFO 6
+#define DBG_TRACE 8
+#define DBG_VERBOSE 10
+
+#define DBG_INIT 0x00000001
+#define DBG_MINIPORT 0x00000002
+#define DBG_PROTOCOL 0x00000004
+#define DBG_SEND 0x00000008
+#define DBG_RECEIVE 0x00000010
+#define DBG_IO 0x00000020
+#define DBG_MEMORY 0x00000040
+#define DBG_VJ 0x00000080
+#define DBG_TAPI 0x00000100
+#define DBG_CCP 0x00000200
+#define DBG_LOOPBACK 0x00000400
+#define DBG_MULTILINK_RECV 0x00000800
+#define DBG_MULTILINK_SEND 0x00001000
+#define DBG_SEND_VJ 0x00002000
+#define DBG_RECV_VJ 0x00004000
+#define DBG_ALL 0xFFFFFFFF
+
+//
+// Link State's
+//
+typedef enum _LinkState {
+ LINK_DOWN,
+ LINK_GOING_DOWN,
+ LINK_UP
+} LinkState;
+
+//
+// Bundle State's
+//
+typedef enum _BundleState {
+ BUNDLE_DOWN,
+ BUNDLE_GOING_DOWN,
+ BUNDLE_UP
+} BundleState;
+
+//
+// Wan request types
+//
+typedef enum _WanRequestType {
+ ASYNC,
+ SYNC
+} WanRequestType;
+
+typedef enum _WanRequestOrigin {
+ NDISWAN,
+ NDISTAPI
+} WanRequestOrigin;
+
+typedef enum _BandwidthOnDemandState {
+ BonDIdle,
+ BonDMonitor,
+ BonDSignaled
+} BandwithOnDemandState;
+
+typedef enum _DeferredQueueType {
+ ReceiveIndication,
+ SendComplete,
+ StatusIndication,
+ Loopback
+} DeferredQueueType;
+
+#define MAX_DEFERRED_QUEUE_TYPES 4
+
+typedef enum _DeferredType {
+ LineUp = MAX_DEFERRED_QUEUE_TYPES,
+ LineDown
+} DeferredType;
+
+#define BUNDLEH_FROM_BUNDLECB(_pbcb) _pbcb->hBundleHandle
+#define BUNDLECB_FROM_LINKCB(_plcb) (PBUNDLECB)_plcb->BundleCB
+#define BUNDLECB_FROM_BUNDLEH(_pbcb, _bh) \
+{ \
+ NdisAcquireSpinLock(&ConnectionTable->Lock); \
+ if ((ULONG)_bh <= ConnectionTable->ulArraySize) { \
+ _pbcb = *(ConnectionTable->BundleArray + (ULONG)_bh); \
+ } else { \
+ _pbcb = NULL; \
+ } \
+ NdisReleaseSpinLock(&ConnectionTable->Lock); \
+}
+
+#define LINKH_FROM_LINKCB(_plcb) _plcb->hLinkHandle
+#define LINKCB_FROM_LINKH(_plcb, _lh) \
+{ \
+ NdisAcquireSpinLock(&ConnectionTable->Lock); \
+ if ((ULONG)_lh <= ConnectionTable->ulArraySize) { \
+ _plcb = *(ConnectionTable->LinkArray + (ULONG)_lh); \
+ } else { \
+ _plcb = NULL; \
+ } \
+ NdisReleaseSpinLock(&ConnectionTable->Lock); \
+}
+
+#define GetGlobalListCount(_gl, _ul) \
+{ \
+ NdisAcquireSpinLock(&(_gl.Lock)); \
+ _ul = _gl.ulCount; \
+ NdisReleaseSpinLock(&(_gl.Lock)); \
+}
+
+#define InsertTailGlobalList(_gl, _ple) \
+{ \
+ NdisAcquireSpinLock(&(_gl.Lock)); \
+ InsertTailList(&(_gl.List), _ple); \
+ _gl.ulCount++; \
+ NdisReleaseSpinLock(&(_gl.Lock)); \
+}
+
+#define InsertHeadGlobalList(_gl, _ple) \
+{ \
+ NdisAcquireSpinLock(&(_gl.Lock)); \
+ InsertHeadList(&(_gl.List), _ple); \
+ _gl.ulCount++; \
+ NdisReleaseSpinLock(&(_gl.Lock)); \
+}
+
+#define RemoveHeadGlobalList(_gl, _ple) \
+{ \
+ NdisAcquireSpinLock(&(_gl.Lock)); \
+ _ple = RemoveHeadList(&(_gl.List)); \
+ _gl.ulCount--; \
+ NdisReleaseSpinLock(&(_gl.Lock)); \
+}
+
+//
+// The Remote address (DEST address) is what we use to mutilplex
+// sends across our single adapter/binding context. The address
+// has the following format:
+//
+// XX XX XX YY YY ZZ
+//
+// XX = Randomly generated OUI
+// YY = Index into the active bundle connection table to get bundlecb
+// ZZ = Index into the protocol table of a bundle to get protocolcb
+//
+#define FillNdisWanBundleIndex(_pAddr, _Index) \
+{ \
+ _pAddr[3] = (UCHAR)((USHORT)_Index >> 8); \
+ _pAddr[4] = (UCHAR)_Index; \
+}
+
+#define GetNdisWanBundleIndex(_pAddr, _Index) \
+{ \
+ _Index = ((USHORT)_pAddr[3] << 8) | _pAddr[4]; \
+}
+
+#define FillNdisWanProtocolIndex(_pAddr, _Index) _pAddr[5] = (UCHAR)_Index
+
+#define GetNdisWanProtocolIndex(_pAddr, _Index) \
+{ \
+ _Index = _pAddr[5]; \
+ ASSERT(_Index != 0); \
+ if (_Index == 0) { \
+ _Index = MAX_PROTOCOLS + 1; \
+ } \
+}
+
+//
+// In the Src address (from a NdisSend) the bundle index
+// is stashed in the two high order bytes as shown below
+// with the mask of valid bits given by the x's. The
+// high byte is shifted to the left one bit so the number
+// of possible bundles is now 0x7FFF
+//
+// 0 1
+// 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+// x x x x x x x 0 x x x x x x x x
+//
+#define FillTransportBundleIndex(_pAddr, _Index) \
+{ \
+ _pAddr[0] = (UCHAR)((USHORT)_Index >> 7) & 0xFE; \
+ _pAddr[1] = (UCHAR)_Index; \
+}
+
+#define GetTransportBundleIndex(_pAddr, _Index) \
+{ \
+ _Index = (((USHORT)_pAddr[0] << 7) & 0x7F) | _pAddr[1]; \
+} \
+
+#define GetProtocolIndexFromProtocolList(_pl, _pt, _Index) \
+{ \
+ PPROTOCOLCB _pP; \
+ \
+ _Index = MAX_PROTOCOLS + 1; \
+ \
+ for (_pP = (PPROTOCOLCB)(_pl)->Flink; \
+ (PLIST_ENTRY)_pP != _pl; \
+ _pP = (PPROTOCOLCB)(_pP)->Linkage.Flink) { \
+ \
+ if (_pP->usProtocolType == _pt) { \
+ _Index = (ULONG)_pP->hProtocolHandle; \
+ break; \
+ } \
+ } \
+}
+
+#define ProtocolCBFromProtocolH(_pBCB, _hP, _pPCB) \
+{ \
+ ASSERT(_hP != 0); \
+ if (_hP < MAX_PROTOCOLS) { \
+ _pPCB = _pBCB->ProtocolCBTable[_hP]; \
+ } \
+}
+
+#define IsValidProtocolCB(_pPCB) \
+ (_pPCB != NULL && _pPCB != (PPROTOCOLCB)RESERVED_PROTOCOLCB)
+
+#define NetToHostShort(_ns) ( ((_ns & 0x00FF) << 8) | ((_ns & 0xFF00) >> 8) )
+#define HostToNetShort(_hs) ( ((_hs & 0x00FF) << 8) | ((_hs & 0xFF00) >> 8) )
+
+#define IsLinkSendWindowOpen(_plcb) ((_plcb)->ulWanPacketCount > 1)
+
+#define UpdateProtocolQuota(_pPCB, _ulBytes) UpdateSampleTable(&(_pPCB->SampleTable), _ulBytes)
+
+#define PMINIPORT_RESERVED_FROM_NDIS(_packet) \
+ ((PNDISWAN_MINIPORT_RESERVED)((_packet)->MiniportReserved))
+
+#define IsCompleteFrame(_fl) \
+ ((_fl & MULTILINK_BEGIN_FRAME) && (_fl & MULTILINK_END_FRAME))
+
+#define AddPPPProtocolID(_finf, _usID) \
+{ \
+ PUCHAR _cp = _finf->ProtocolID.Pointer; \
+ if (_finf->ProtocolID.Length != 0) { \
+ ASSERT(_cp); \
+ if (!(_finf->FramingBits & PPP_COMPRESS_PROTOCOL_FIELD) || \
+ (_finf->Flags & (DO_COMPRESSION | DO_ENCRYPTION))) { \
+ *_cp++ = (UCHAR)(_usID >> 8); \
+ } \
+ *_cp = (UCHAR)_usID; \
+ } \
+}
+
+#define AddMultilinkInfo(_finf, _f, _seq, _mask) \
+{ \
+ PUCHAR _cp = _finf->Multilink.Pointer; \
+ if (_finf->Multilink.Length != 0) { \
+ ASSERT(_cp); \
+ if (!(_finf->FramingBits & PPP_COMPRESS_PROTOCOL_FIELD)) { \
+ _cp++; \
+ } \
+ _cp++; \
+ _seq &= _mask; \
+ if (_finf->FramingBits & PPP_SHORT_SEQUENCE_HDR_FORMAT) { \
+ *_cp++ = _f | (UCHAR)((_seq >> 8) & SHORT_SEQ_MASK); \
+ *_cp++ = (UCHAR)_seq; \
+ } else { \
+ *_cp++ = _f; \
+ *_cp++ = (UCHAR)(_seq >> 16); \
+ *_cp++ = (UCHAR)(_seq >> 8); \
+ *_cp = (UCHAR)_seq; \
+ } \
+ } \
+}
+
+#define AddCompressionInfo(_finf, _usCC) \
+{ \
+ PUCHAR _cp = _finf->Compression.Pointer; \
+ if (_finf->Compression.Length != 0) { \
+ ASSERT(_cp); \
+ if (!(_finf->FramingBits & PPP_COMPRESS_PROTOCOL_FIELD)) { \
+ _cp++; \
+ } \
+ _cp++; \
+ *_cp++ = (UCHAR)(_usCC >> 8); \
+ *_cp = (UCHAR)_usCC; \
+ } \
+}
+
+#ifdef USE_NDIS_MINIPORT_LOCKING
+
+#define NdisWanAcquireMiniportLock(_a) \
+ NdisIMSwitchToMiniport((_a)->hMiniportHandle, &((_a)->SwitchHandle))
+
+#define NdisWanReleaseMiniportLock(_a) \
+ NdisIMRevertBack((_a)->hMiniportHandle, (_a)->SwitchHandle)
+
+#endif // end of use_ndis_miniport_locking
+
+
+#ifdef USE_NDIS_MINIPORT_CALLBACK
+
+#define NdisWanSetDeferred(_a) \
+{ \
+ if (!((_a)->Flags & DEFERRED_CALLBACK_SET)) { \
+ (_a)->Flags |= DEFERRED_CALLBACK_SET; \
+ NdisIMQueueMiniportCallback((_a)->hMiniportHandle, DeferredCallback, (_a)); \
+ } \
+}
+
+#else // end of USE_NDIS_MINIPORT_CALLBACK
+
+#define NdisWanSetDeferred(_a) \
+{ \
+ if (!((_a)->Flags & DEFERRED_TIMER_SET)) { \
+ (_a)->Flags |= DEFERRED_TIMER_SET; \
+ NdisMSetTimer(&((_a)->DeferredTimer), 15); \
+ } \
+}
+#endif // end of !USE_NDIS_MINIPORT_CALLBACK
+
+#define NdisWanChangeMiniportAddress(_a, _addr) \
+{ \
+ PNDIS_MINIPORT_BLOCK Miniport; \
+ \
+ Miniport = (PNDIS_MINIPORT_BLOCK)((_a)->hMiniportHandle); \
+ ETH_COPY_NETWORK_ADDRESS(Miniport->EthDB->AdapterAddress, _addr); \
+}
+
+//
+// Queue routines for the deferred work queues
+//
+#define IsDeferredQueueEmpty(_pq) ((_pq)->Head == NULL)
+
+#define InsertHeadDeferredQueue(_pq, _pe) \
+{ \
+ if (((_pe)->Next = (_pq)->Head) == NULL) { \
+ (_pq)->Tail = (_pe); \
+ } \
+ (_pq)->Head = (_pe); \
+ if (++(_pq)->Count > (_pq)->MaxCount) { \
+ (_pq)->MaxCount++; \
+ } \
+}
+
+#define InsertTailDeferredQueue(_pq, _pe) \
+{ \
+ (_pe)->Next = NULL; \
+ if ((_pq)->Head == NULL) { \
+ (_pq)->Head = (_pe); \
+ } else { \
+ (_pq)->Tail->Next = (_pe); \
+ } \
+ (_pq)->Tail = (_pe); \
+ if (++(_pq)->Count > (_pq)->MaxCount) { \
+ (_pq)->MaxCount++; \
+ } \
+}
+
+#define RemoveHeadDeferredQueue(_pq) \
+ (_pq)->Head; \
+ { \
+ if ((_pq)->Head->Next == NULL) { \
+ (_pq)->Tail = NULL; \
+ } \
+ (_pq)->Head = (_pq)->Head->Next; \
+ (_pq)->Count--; \
+ }
+
+
+//
+// Queue routines for the ProtocolCB's NdisPacket queues
+//
+#define InsertHeadNdisPacketQueue(_ppcb, _pnp) \
+{ \
+ PMINIPORT_RESERVED_FROM_NDIS(_pnp)->Next = \
+ (_ppcb)->HeadNdisPacketQueue; \
+ \
+ if ((_ppcb)->HeadNdisPacketQueue == NULL) { \
+ (_ppcb)->TailNdisPacketQueue = _pnp; \
+ } \
+ \
+ (_ppcb)->HeadNdisPacketQueue = _pnp; \
+}
+
+#define InsertTailNdisPacketQueue(_ppcb, _pnp) \
+{ \
+ PMINIPORT_RESERVED_FROM_NDIS(_pnp)->Next = NULL; \
+ \
+ if ((_ppcb)->HeadNdisPacketQueue == NULL) { \
+ (_ppcb)->HeadNdisPacketQueue = _pnp; \
+ } else { \
+ PMINIPORT_RESERVED_FROM_NDIS((_ppcb)->TailNdisPacketQueue)->Next = _pnp; \
+ } \
+ \
+ (_ppcb)->TailNdisPacketQueue = _pnp; \
+}
+
+#define RemoveHeadNdisPacketQueue(_ppcb) \
+ (_ppcb)->HeadNdisPacketQueue; \
+ { \
+ PNDIS_PACKET _FirstPacket = \
+ PMINIPORT_RESERVED_FROM_NDIS((_ppcb)->HeadNdisPacketQueue)->Next; \
+ \
+ if (_FirstPacket == NULL) { \
+ (_ppcb)->TailNdisPacketQueue = NULL; \
+ } \
+ \
+ (_ppcb)->HeadNdisPacketQueue = _FirstPacket; \
+ }
+
+#define IsNdisPacketQueueEmpty(_ppcb) ((_ppcb)->HeadNdisPacketQueue == NULL)
+
+#define NdisWanDoReceiveComplete(_pa) \
+{ \
+ NdisReleaseSpinLock(&(_pa)->Lock); \
+ NdisMEthIndicateReceiveComplete((_pa)->hMiniportHandle); \
+ NdisAcquireSpinLock(&(_pa)->Lock); \
+}
+
+#define NDISM_PROCESS_DEFERRED(_M) (_M)->ProcessDeferredHandler((_M))
+
+//
+// OS specific code
+//
+#ifdef NT
+
+//
+// NT stuff
+//
+#define NdisWanInitializeNotificationEvent(_pEvent) KeInitializeEvent(_pEvent, NotificationEvent, FALSE)
+#define NdisWanSetNotificationEvent(_pEvent) KeSetEvent(_pEvent, 0, FALSE)
+#define NdisWanClearNotificationEvent(_pEvent) KeClearEvent(_pEvent)
+#define NdisWanWaitForNotificationEvent(_pEvent) KeWaitForSingleObject(_pEvent, Executive, KernelMode, TRUE, NULL)
+
+#define NdisWanInitializeSyncEvent(_pEvent) KeInitializeEvent(_pEvent, SynchronizationEvent, FALSE)
+#define NdisWanSetSyncEvent(_pEvent) KeSetEvent(_pEvent, 1, FALSE)
+#define NdisWanClearSyncEvent(_pEvent) KeClearEvent(_pEvent)
+#define NdisWanWaitForSyncEvent(_pEvent) KeWaitForSingleObject(_pEvent, UserRequest, KernelMode, FALSE, NULL)
+
+#define NdisWanAllocateMemory(_AllocatedMemory, _Size) \
+{ \
+ (PVOID)*(_AllocatedMemory) = (PVOID)ExAllocatePoolWithTag(NonPagedPool, _Size, ' naW'); \
+ ASSERT((PVOID)*(_AllocatedMemory) != NULL); \
+ if ((PVOID)*(_AllocatedMemory) != NULL) { \
+ NdisZeroMemory((PUCHAR)*(_AllocatedMemory), _Size); \
+ } \
+}
+
+#define NdisWanFreeMemory(_AllocatedMemory) ExFreePool(_AllocatedMemory)
+#define NdisWanMoveMemory(_Dest, _Src, _Length) RtlMoveMemory(_Dest, _Src, _Length)
+
+#define NdisWanGetSystemTime(_pTime) KeQuerySystemTime(_pTime)
+
+#define NdisWanCalcTimeDiff(_pDest, _pEnd, _pBegin) \
+ (_pDest)->QuadPart = (_pEnd)->QuadPart - (_pBegin)->QuadPart
+
+#define NdisWanInitWanTime(_pTime, _Val) (_pTime)->QuadPart = _Val
+
+#define NdisWanMultiplyWanTime(_pDest, _pMulti1, _pMulti2) \
+ (_pDest)->QuadPart = (_pMulti1)->QuadPart * (_pMulti2)->QuadPart
+
+#define NdisWanDivideWanTime(_pDest, _pDivi1, _pDivi2) \
+ (_pDest)->QuadPart = (_pDivi1)->QuadPart / (_pDivi2)->QuadPart
+
+#define NdisWanIsTimeDiffLess(_pTime1, _pTime2) ((_pTime1)->QuadPart < (_pTime2)->QuadPart)
+#define NdisWanIsTimeDiffGreater(_pTime1, _pTime2) ((_pTime1)->QuadPart > (_pTime2)->QuadPart)
+#define NdisWanIsTimeEqual(_pTime1, _pTime2) ((_pTime1)->QuadPart == (_pTime2)->QuadPart)
+
+#define NdisWanUppercaseNdisString(_pns1, _pns2, _b) RtlUpcaseUnicodeString(_pns1, _pns2, _b)
+#define MDL_ADDRESS(_MDL_) MmGetSystemAddressForMdl(_MDL_)
+
+#define NdisWanInterlockedInc(_pul) InterlockedIncrement(_pul)
+#define NdisWanInterlockedDec(_pul) InterlockedDecrement(_pul)
+#define NdisWanInterlockedExchange(_pul, ul) InterlockedExchange(_pul, ul)
+#define NdisWanExInterlockedExchange(_pul, ul, _plock) ExInterlockedExchangeUlong(_pul, ul, _plock)
+
+#define NdisWanInterlockedInsertTailList(_phead, _pentry, _plock) \
+ ExInterlockedInsertTailList(_phead, _pentry, _plock)
+
+#define NdisWanInterlockedInsertHeadList(_phead, _pentry, _plock) \
+ ExInterlockedInsertHeadList(_phead, _pentry, _plock)
+
+#define NdisWanInterlockedRemoveHeadList(_phead, _plock) \
+ ExInterlockedRemoveHeadList(_phead, _plock)
+
+#define NdisWanRaiseIrql(_pirql) KeRaiseIrql(DISPATCH_LEVEL, _pirql)
+#define NdisWanLowerIrql(_irql) KeLowerIrql(_irql)
+//
+// Wait for event structure. Used for async completion notification.
+//
+typedef KEVENT WAN_EVENT;
+typedef WAN_EVENT *PWAN_EVENT;
+
+typedef LARGE_INTEGER WAN_TIME;
+typedef WAN_TIME *PWAN_TIME;
+
+typedef KIRQL WAN_IRQL;
+typedef WAN_IRQL *PWAN_IRQL;
+
+#if DBG // If built with debug
+
+#define NdisWanDbgOut(_DebugLevel, _DebugMask, _Out) { \
+ if ((NdisWanCB.ulTraceLevel >= _DebugLevel) && \
+ (_DebugMask & NdisWanCB.ulTraceMask)) { \
+ DbgPrint("NDISWAN: "); \
+ DbgPrint _Out; \
+ DbgPrint("\n"); \
+ } \
+}
+
+#undef ASSERT
+#define ASSERT(exp) \
+{ \
+ if (!(exp)) { \
+ DbgPrint("NDISWAN: ASSERTION FAILED! %s\n", #exp); \
+ DbgPrint("NDISWAN: File: %s, Line: %d\n", __FILE__, __LINE__); \
+ DbgBreakPoint(); \
+ } \
+}
+
+#else // If not built with debug
+
+#define NdisWanDbgOut(_DebugLevel, _DebugMask, _Out)
+
+#endif // end DBG
+
+#else // end NT stuff
+//
+// Win95 stuff
+//
+
+typedef ULONG WAN_TIME;
+typedef WAN_TIME *PWAN_TIME;
+
+#endif
+
+#endif
diff --git a/private/ntos/ndis/ndiswan/wanproto.h b/private/ntos/ndis/ndiswan/wanproto.h
new file mode 100644
index 000000000..e8e515aa5
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/wanproto.h
@@ -0,0 +1,696 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ Wanproto.h
+
+Abstract:
+
+ This file contains the prototypes for functions that NdisWan uses.
+
+Author:
+
+ Tony Bell (TonyBe) June 06, 1995
+
+Environment:
+
+ Kernel Mode
+
+Revision History:
+
+ TonyBe 06/06/95 Created
+
+--*/
+
+#ifndef _NDISWAN_PROTO
+#define _NDISWAN_PROTO
+
+//
+// Functions from ccp.c
+//
+VOID
+WanDeallocateCCP(
+ PBUNDLECB BundleCB
+ );
+
+NTSTATUS
+WanAllocateCCP(
+ PBUNDLECB BundleCB
+ );
+
+//
+// Functions from indicate.c
+//
+VOID
+NdisWanLineUpIndication(
+ IN PWAN_ADAPTERCB WanAdapterCB,
+ IN PUCHAR Buffer,
+ IN ULONG BufferSize
+ );
+
+VOID
+NdisWanLineDownIndication(
+ IN PWAN_ADAPTERCB WanAdapterCB,
+ IN PUCHAR Buffer,
+ IN ULONG BufferSize
+ );
+
+VOID
+NdisWanFragmentIndication(
+ IN PWAN_ADAPTERCB WanAdapterCB,
+ IN PUCHAR Buffer,
+ IN ULONG BufferSize
+ );
+
+VOID
+UpdateBundleInfo(
+ IN PBUNDLECB BundleCB
+ );
+
+VOID
+AddLinkToBundle(
+ IN PBUNDLECB BundleCB,
+ IN PLINKCB LinkCB
+ );
+
+VOID
+RemoveLinkFromBundle(
+ IN PBUNDLECB BundleCB,
+ IN PLINKCB LinkCB
+ );
+
+VOID
+FreeBundleResources(
+ PBUNDLECB BundleCB
+ );
+
+//
+// Functions from io.c
+//
+#ifdef NT
+
+NTSTATUS
+NdisWanIoctl(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ );
+
+VOID
+NdisWanCancelRoutine(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ );
+
+NTSTATUS
+NdisWanIrpStub(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ );
+
+#endif // NT
+
+//
+// Functions from loopback.c
+//
+
+VOID
+NdisWanQueueLoopbackPacket(
+ PADAPTERCB AdapterCB,
+ PNDIS_PACKET NdisPacket
+ );
+
+VOID
+NdisWanProcessLoopbacks(
+ PADAPTERCB AdapterCB
+ );
+
+//
+// Functions from memory.c
+//
+NDIS_STATUS
+NdisWanCreateAdapterCB(
+ OUT PADAPTERCB *pAdapterCB,
+ IN PNDIS_STRING AdapterName
+ );
+
+VOID
+NdisWanDestroyAdapterCB(
+ IN PADAPTERCB pAdapterCB
+ );
+
+NDIS_STATUS
+NdisWanCreateWanAdapterCB(
+ IN PWSTR BindName
+ );
+
+VOID
+NdisWanDestroyWanAdapterCB(
+ IN PWAN_ADAPTERCB pWanAdapterCB
+ );
+
+VOID
+NdisWanGetProtocolCB(
+ OUT PPROTOCOLCB *ProtocolCB,
+ IN USHORT usProtocolType,
+ IN USHORT usDeviceNameLength,
+ IN PWSTR DeviceName,
+ IN ULONG ulBufferLength,
+ IN PUCHAR Buffer
+ );
+
+VOID
+NdisWanReturnProtocolCB(
+ IN PPROTOCOLCB ProtocolCB
+ );
+
+VOID
+NdisWanGetLinkCB(
+ OUT PLINKCB *LinkCB,
+ IN PWAN_ADAPTERCB WanAdapterCB,
+ IN ULONG SendWindow
+ );
+
+VOID
+NdisWanReturnLinkCB(
+ PLINKCB LinkCB
+ );
+
+
+VOID
+NdisWanGetBundleCB(
+ OUT PBUNDLECB *BundleCB
+ );
+
+VOID
+NdisWanReturnBundleCB(
+ IN PBUNDLECB BundleCB
+ );
+
+NDIS_STATUS
+NdisWanCreatePPPProtocolTable(
+ VOID
+ );
+
+VOID
+NdisWanDestroyPPPProtocolTable(
+ VOID
+ );
+
+NDIS_STATUS
+NdisWanCreateConnectionTable(
+ ULONG TableSize
+ );
+
+VOID
+NdisWanDestroyConnectionTable(
+ VOID
+ );
+
+VOID
+CompleteThresholdEvent(
+ PBUNDLECB BundleCB,
+ ULONG ThresholdType
+ );
+
+VOID
+NdisWanGetDeferredDesc(
+ PADAPTERCB AdapterCB,
+ PDEFERRED_DESC *RetDesc
+ );
+
+//
+// Functions from ndiswan.c
+//
+NDIS_STATUS
+DoMiniportInit(
+ VOID
+ );
+
+NDIS_STATUS
+DoProtocolInit(
+ IN PUNICODE_STRING RegistryPath
+ );
+
+NDIS_STATUS
+DoWanMiniportInit(
+ VOID
+ );
+
+VOID
+NdisWanReadRegistry(
+ IN PUNICODE_STRING RegistryPath
+ );
+
+VOID
+NdisWanGlobalCleanup(
+ VOID
+ );
+
+VOID
+InsertPPP_ProtocolID(
+ IN ULONG Value,
+ IN ULONG ValueType
+ );
+
+USHORT
+GetPPP_ProtocolID(
+ IN USHORT Value,
+ IN ULONG ValueType
+ );
+
+NDIS_HANDLE
+InsertLinkInConnectionTable(
+ IN PLINKCB LinkCB
+ );
+
+VOID
+RemoveLinkFromConnectionTable(
+ IN PLINKCB LinkCB
+ );
+
+NDIS_HANDLE
+InsertBundleInConnectionTable(
+ IN PBUNDLECB BundleCB
+ );
+
+VOID
+RemoveBundleFromConnectionTable(
+ IN PBUNDLECB BundleCB
+ );
+
+NTSTATUS
+BindQueryRoutine(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+ProtocolTypeQueryRoutine(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+BOOLEAN
+IsHandleValid(
+ USHORT usHandleType,
+ NDIS_HANDLE hHandle
+ );
+
+#if DBG
+
+PUCHAR
+NdisWanGetNdisStatus(
+ IN NDIS_STATUS GeneralStatus
+ );
+
+#endif
+
+
+//
+// Functions from miniport.c
+//
+
+BOOLEAN
+NdisWanCheckForHang(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+NDIS_STATUS
+NdisWanQueryInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+ );
+
+NDIS_STATUS
+NdisWanSetInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+ );
+
+VOID
+NdisWanHalt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+NDIS_STATUS
+NdisWanInitialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ );
+
+NDIS_STATUS
+NdisWanReconfigure(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ );
+
+NDIS_STATUS
+NdisWanReset(
+ OUT PBOOLEAN AddressingReset,
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+#ifdef USE_NDIS_MINIPORT_CALLBACK
+VOID
+DeferredCallback(
+ PADAPTERCB AdapterCB,
+ PVOID Context
+ );
+#endif // end of USE_NDIS_MINIPORT_CALLBACK
+
+//
+// Functions from protocol.c
+//
+
+NDIS_STATUS
+NdisWanOpenWanAdapter(
+ PWAN_ADAPTERCB pWanAdapterCB
+ );
+
+VOID
+NdisWanOpenAdapterComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status,
+ IN NDIS_STATUS OpenErrorStatus
+ );
+
+VOID
+NdisWanCloseAdapterComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+NdisWanResetComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+NdisWanTransferDataComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET pNdisPacket,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ );
+
+VOID
+NdisWanRequestComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+NdisWanIndicateStatusComplete(
+ IN NDIS_HANDLE BindingContext
+ );
+
+VOID
+NdisWanIndicateStatus(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ );
+
+NDIS_STATUS
+DoNewLineUpToProtocol(
+ IN PPROTOCOLCB ProtocolCB
+ );
+
+NDIS_STATUS
+DoLineUpToProtocol(
+ IN PPROTOCOLCB ProtocolCB
+ );
+
+NDIS_STATUS
+DoLineDownToProtocol(
+ PPROTOCOLCB ProtocolCB
+ );
+
+VOID
+NdisWanProcessStatusIndications(
+ PADAPTERCB AdapterCB
+ );
+
+//
+// Functions from receive.c
+//
+NDIS_STATUS
+NdisWanReceiveIndication(
+ IN NDIS_HANDLE NdisLinkContext,
+ IN PUCHAR Packet,
+ IN ULONG PacketSize
+ );
+
+VOID
+NdisWanReceiveComplete(
+ IN NDIS_HANDLE NdisLinkContext
+ );
+
+NDIS_STATUS
+NdisWanTransferData(
+ OUT PNDIS_PACKET NdisPacket,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+ );
+
+VOID
+FlushRecvDescAssemblyList(
+ IN PBUNDLECB BundleCB
+ );
+
+VOID
+FreeRecvDescFreeList(
+ IN PBUNDLECB BundleCB
+ );
+
+VOID
+NdisWanGetRecvDesc(
+ PBUNDLECB BundleCB,
+ PRECV_DESC *ReturnRecvDesc
+ );
+
+VOID
+RecvFlushFunction(
+ PVOID System1,
+ PVOID Context,
+ PVOID System2,
+ PVOID System3
+ );
+
+VOID
+NdisWanProcessReceiveIndications(
+ PADAPTERCB AdapterCB
+ );
+
+BOOLEAN
+IpIsDataFrame(
+ PUCHAR HeaderBuffer,
+ ULONG HeaderBufferLength,
+ ULONG TotalLength
+ );
+
+BOOLEAN
+IpxIsDataFrame(
+ PUCHAR HeaderBuffer,
+ ULONG HeaderBufferLength,
+ ULONG TotalLength
+ );
+
+BOOLEAN
+NbfIsDataFrame(
+ PUCHAR HeaderBuffer,
+ ULONG HeaderBufferLength,
+ ULONG TotalLength
+ );
+
+
+//
+// Functions from request.c
+//
+
+NDIS_STATUS
+NdisWanSubmitNdisRequest(
+ IN PWAN_ADAPTERCB pWanAdapterCB,
+ IN PNDIS_REQUEST pNdisRequest,
+ IN WanRequestType Type,
+ IN WanRequestOrigin Origin
+ );
+
+NDIS_STATUS
+NdisWanOidProc(
+ IN PADAPTERCB pAdapterCB,
+ IN NDIS_OID Oid,
+ IN ULONG SetQueryFlag,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+ );
+
+PWAN_REQUEST
+GetWanRequest(
+ IN PWAN_ADAPTERCB pWanAdapterCB,
+ IN PNDIS_REQUEST pNdisRequest
+ );
+
+VOID
+AddRequestToList(
+ IN PWAN_ADAPTERCB pWanAdapterCB,
+ IN PWAN_REQUEST pWanRequest
+ );
+
+VOID
+RemoveRequestFromList(
+ IN PWAN_ADAPTERCB pWanAdapterCB,
+ IN PWAN_REQUEST pWanRequest
+ );
+
+//
+// Functions from send.c
+//
+NDIS_STATUS
+NdisWanSend(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET pNdisPacket,
+ IN UINT Flags
+ );
+
+VOID
+NdisWanSendCompleteHandler(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_WAN_PACKET pNdisWanPacket,
+ IN NDIS_STATUS NdisStatus
+);
+
+VOID
+NdisWanProcessSendCompletes(
+ PADAPTERCB AdapterCB
+ );
+
+NDIS_STATUS
+BuildIoPacket(
+ IN PNDISWAN_IO_PACKET pWanIoPacket,
+ IN BOOLEAN SendImmediate
+ );
+
+VOID
+NdisWanCopyFromPacketToBuffer(
+ IN PNDIS_PACKET NdisPacket,
+ IN ULONG Offset,
+ IN ULONG BytesToCopy,
+ OUT PUCHAR Buffer,
+ OUT PULONG BytesCopied
+ );
+
+VOID
+TryToCompleteNdisPacket(
+ PADAPTERCB AdapterCB,
+ PNDIS_PACKET NdisPacket
+ );
+//
+// Functions from tapi.c
+//
+
+NDIS_STATUS
+NdisWanTapiRequestProc(
+ PWAN_ADAPTERCB WanAdapterCB,
+ PNDIS_REQUEST NdisRequest
+ );
+
+VOID
+NdisWanTapiRequestComplete(
+ PWAN_ADAPTERCB WanAdapterCB,
+ PWAN_REQUEST WanRequest
+ );
+
+VOID
+NdisWanTapiIndication(
+ PWAN_ADAPTERCB WanAdapterCB,
+ PUCHAR StatusBuffer,
+ ULONG StatusBufferSize
+ );
+
+//
+// Function from util.c
+//
+
+VOID
+NdisWanStringToNdisString(
+ IN PNDIS_STRING pDestString,
+ IN PWSTR pSrcBuffer
+ );
+
+VOID
+NdisWanAllocateAdapterName(
+ PNDIS_STRING Dest,
+ PNDIS_STRING Src
+ );
+
+VOID
+NdisWanFreeNdisString(
+ IN PNDIS_STRING NdisString
+ );
+
+BOOLEAN
+NdisWanCompareNdisString(
+ PNDIS_STRING NdisString1,
+ PNDIS_STRING NdisString2
+ );
+
+VOID
+NdisWanNdisStringToInteger(
+ IN PNDIS_STRING Source,
+ IN PULONG Value
+ );
+
+VOID
+NdisWanCopyNdisString(
+ OUT PNDIS_STRING Dest,
+ IN PNDIS_STRING Src
+ );
+
+#ifndef USE_NDIS_MINIPORT_LOCKING
+
+BOOLEAN
+NdisWanAcquireMiniportLock(
+ PADAPTERCB AdapterCB
+ );
+
+VOID
+NdisWanReleaseMiniportLock(
+ PADAPTERCB AdapterCB
+ );
+
+#endif // end of !USE_NDIS_MINIPORT_LOCKING
+
+#endif
+
diff --git a/private/ntos/ndis/ndiswan/wantypes.h b/private/ntos/ndis/ndiswan/wantypes.h
new file mode 100644
index 000000000..ff6750797
--- /dev/null
+++ b/private/ntos/ndis/ndiswan/wantypes.h
@@ -0,0 +1,505 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ Wantypes.h
+
+Abstract:
+
+ This file contains data structures used by the NdisWan driver
+
+
+
+Author:
+
+ Tony Bell (TonyBe) June 06, 1995
+
+Environment:
+
+ Kernel Mode
+
+Revision History:
+
+ TonyBe 06/06/95 Created
+
+--*/
+
+#ifndef _NDISWAN_TYPES_
+#define _NDISWAN_TYPES_
+
+//
+// OS specific structures
+//
+#ifdef NT
+
+#endif
+//
+// end of OS specific structures
+//
+
+#if DBG
+typedef struct _DBG_SEND_PACKET {
+ LIST_ENTRY Linkage;
+ PVOID Packet;
+ ULONG PacketType;
+ struct _BUNDLECB *BundleCB;
+ ULONG BundleState;
+ ULONG BundleFlags;
+ struct _PROTOCOLCB *ProtocolCB;
+ ULONG ProtocolFlags;
+ struct _LINKCB *LinkCB;
+ ULONG LinkState;
+} DBG_SEND_PACKET, *PDBG_SEND_PACKET;
+
+typedef struct _DBG_SEND_CONTEXT {
+ struct _BUNDLECB *BundleCB;
+ struct _PROTOCOLCB *ProtocolCB;
+ struct _LINKCB *LinkCB;
+ PVOID Packet;
+#define PACKET_TYPE_WAN 1
+#define PACKET_TYPE_NDIS 2
+ ULONG PacketType;
+ PLIST_ENTRY ListHead;
+ PNDIS_SPIN_LOCK ListLock;
+} DBG_SEND_CONTEXT, *PDBG_SEND_CONTEXT;
+
+#endif
+
+typedef struct _WAN_ASYNC_EVENT {
+ LIST_ENTRY Linkage;
+ PVOID Context;
+} WAN_ASYNC_EVENT, *PWAN_ASYNC_EVENT;
+
+//
+// WanRequest structure used to queue requests to the WAN Miniports
+//
+typedef struct _WAN_REQUEST {
+ struct _WAN_REQUEST *pNext; // Next Request on the queue
+ WanRequestType Type; // Sync or Async
+ WanRequestOrigin Origin; // Is this tapi
+ PNDIS_REQUEST pNdisRequest; // Ndis Request type
+ NDIS_STATUS NotificationStatus; // Request status
+ WAN_EVENT NotificationEvent; // Request pending event
+} WAN_REQUEST, *PWAN_REQUEST;
+
+//
+// Used for
+//
+typedef struct _WAN_GLOBAL_LIST {
+ NDIS_SPIN_LOCK Lock; // Access lock
+ ULONG ulCount; // Count of nodes on list
+ ULONG ulMaxCount; // Max allowed on list
+ LIST_ENTRY List; // Doubly-Linked list of nodes
+} WAN_GLOBAL_LIST, *PWAN_GLOBAL_LIST;
+
+//
+// Ethernet Header
+//
+typedef struct _ETH_HEADER {
+ UCHAR DestAddr[6];
+ UCHAR SrcAddr[6];
+ USHORT Type;
+} ETH_HEADER, *PETH_HEADER;
+
+//
+// Receive context for transfer data
+//
+typedef struct _NDISWAN_RECV_CONTEXT {
+ struct _BUNDLECB *BundleCB;
+ struct _PROTOCOLCB *ProtocolCB;
+ PUCHAR WanHeader;
+ ULONG WanHeaderLength;
+ PUCHAR LookAhead;
+ ULONG LookAheadLength;
+ PUCHAR FramePointer;
+ ULONG FrameLength;
+} NDISWAN_RECV_CONTEXT, *PNDISWAN_RECV_CONTEXT;
+
+//
+// The ProtocolType to PPPProtocolID Lookup Table
+//
+typedef struct _PPP_PROTOCOL_TABLE {
+ NDIS_SPIN_LOCK Lock; // Table access lock
+ ULONG ulAllocationSize; // Size of memory allocated
+ ULONG ulArraySize; // MAX size of the two arrays
+ PUSHORT ProtocolID; // Pointer to the ProtocolID array
+ PUSHORT PPPProtocolID; // Pointer to the PPPProtocolID array
+} PPP_PROTOCOL_TABLE, *PPPP_PROTOCOL_TABLE;
+
+//
+// Active connections Table
+//
+typedef struct _CONNECTION_TABLE {
+ NDIS_SPIN_LOCK Lock; // Table access lock
+ ULONG ulAllocationSize; // Size of memory allocated
+ ULONG ulArraySize; // Number of possible connections in table
+ ULONG ulNumActiveLinks; // Number of links in link array
+ ULONG ulNumActiveBundles; // Number of bundles in bundle array
+ LIST_ENTRY BundleList; // List of bundles in table
+ struct _LINKCB **LinkArray; // Pointer to the LinkArray
+ struct _BUNDLECB **BundleArray; // Pointer to the BundleArray
+} CONNECTION_TABLE, *PCONNECTION_TABLE;
+
+typedef struct _IO_DISPATCH_TABLE {
+ ULONG ulFunctionCode;
+ NTSTATUS (*Function)();
+}IO_DISPATCH_TABLE, *PIO_DISPATCH_TABLE;
+
+#ifdef BANDWIDTH_ON_DEMAND
+typedef struct _SEND_SAMPLE {
+ ULONG ulBytesThisSend;
+ ULONG ulReferenceCount;
+ WAN_TIME TimeStamp;
+} SEND_SAMPLE, *PSEND_SAMPLE;
+
+typedef struct _SAMPLE_TABLE {
+ ULONG ulFirstIndex; // Index to first sample in current 1sec period
+ ULONG ulCurrentIndex; // Index to current sample in current 1sec period
+ ULONG ulCurrentSampleByteCount; // Count of bytes sent in this sample period
+ ULONG ulSampleArraySize; // Sample array size
+ WAN_TIME SampleRate; // Time between each sample
+ WAN_TIME SamplePeriod; // Time between 1st sample and last sample
+ SEND_SAMPLE SampleArray[SAMPLE_ARRAY_SIZE]; // SampleArray
+} SAMPLE_TABLE, *PSAMPLE_TABLE;
+#endif
+
+typedef struct _DEFERRED_DESC {
+ struct _DEFERRED_DESC *Next;
+ DeferredType Type;
+ PVOID Context;
+} DEFERRED_DESC, *PDEFERRED_DESC;
+
+typedef struct _DEFERRED_QUEUE {
+ PDEFERRED_DESC Head;
+ PDEFERRED_DESC Tail;
+ ULONG Count;
+ ULONG MaxCount;
+} DEFERRED_QUEUE, *PDEFERRED_QUEUE;
+
+typedef struct _LOOPBACK_DESC {
+ USHORT AllocationSize;
+ USHORT BufferLength;
+ PUCHAR Buffer;
+} LOOPBACK_DESC, *PLOOPBACK_DESC;
+
+typedef struct _RECV_DESC {
+ LIST_ENTRY Linkage;
+ ULONG AllocationSize;
+ ULONG RefCount;
+ struct _BUNDLECB *BundleCB;
+ struct _LINKCB *LinkCB;
+ ULONG SequenceNumber;
+ ULONG Flags;
+ ULONG WanHeaderLength;
+ PUCHAR WanHeader;
+ ULONG LookAheadLength;
+ PUCHAR LookAhead;
+ ULONG CurrentBufferLength;
+ PUCHAR CurrentBuffer;
+ PUCHAR StartBuffer;
+} RECV_DESC, *PRECV_DESC;
+
+typedef struct _HEADER_FIELD_INFO {
+ ULONG Length;
+ PUCHAR Pointer;
+}HEADER_FIELD_INFO, *PHEADER_FIELD_INFO;
+
+typedef struct _HEADER_FRAMING_INFO {
+ ULONG FramingBits; // Framing bits
+ ULONG HeaderLength; // Total length of the header
+#define DO_MULTILINK 0x00000001
+#define DO_COMPRESSION 0x00000002
+#define DO_ENCRYPTION 0x00000004
+#define IO_PROTOCOLID 0x00000008
+#define FIRST_FRAGMENT 0x00000010
+#define DO_FLUSH 0x00000020
+#define DO_LEGACY_ENCRYPTION 0x00000040 // Legacy encryption NT 3.0/3.5/3.51
+#define DO_40_ENCRYPTION 0x00000080 // Pseudo fixed 40 bit encryption NT 4.0
+#define DO_128_ENCRYPTION 0x00000100 // 128 bit encryption NT 4.0 encryption update
+ ULONG Flags; // Framing flags
+ HEADER_FIELD_INFO AddressControl; // Info about the address/control field
+ HEADER_FIELD_INFO Multilink; // Info about the multlink field
+ HEADER_FIELD_INFO Compression; // Info about the compression field
+ HEADER_FIELD_INFO ProtocolID; // Info about the protocol id field
+}HEADER_FRAMING_INFO, *PHEADER_FRAMING_INFO;
+
+//
+// Used in NdisWan for NT 3.5 and NT 3.51 and seemed to work.
+// Made up and tried to not make it a valid memory address.
+//
+#define NDISWAN_MAGIC_NUMBER (ULONG)0xC1207435
+
+typedef struct _WAN_IO_PROTOCOL_RESERVED {
+ ULONG ulMagicNumber;
+ struct _LINKCB *LinkCB;
+ NDIS_HANDLE hPacketPool;
+ PNDIS_PACKET pNdisPacket;
+ NDIS_HANDLE hBufferPool;
+ PNDIS_BUFFER pNdisBuffer;
+ PUCHAR pAllocatedMemory;
+ ULONG ulAllocationSize;
+} WAN_IO_PROTOCOL_RESERVED, *PWAN_IO_PROTOCOL_RESERVED;
+
+typedef struct _NDISWAN_MINIPORT_RESERVED {
+ union {
+
+ struct {
+ PNDIS_PACKET Next; // Pointer to next packet in queue
+ USHORT Reserved; //
+ };
+
+ struct {
+ ULONG MagicNumber; // Used to identify this ndispacket as belonging to ndiswan
+ USHORT ReferenceCount; // Used to count number of fragments this ndispacket
+ };
+ };
+
+ USHORT Flags; // Packet properties
+
+} NDISWAN_MINIPORT_RESERVED, *PNDISWAN_MINIPORT_RESERVED;
+
+//
+// LineUp information that is common to all protocol's
+// routed to the BundleCB
+//
+typedef struct _BUNDLE_LINE_UP {
+ ULONG BundleSpeed; // 100 bps units
+ ULONG ulMaximumTotalSize; // suggested max for send packets
+ NDIS_WAN_QUALITY Quality; //
+ USHORT usSendWindow; // suggested by the MAC
+} BUNDLE_LINE_UP, *PBUNDLE_LINE_UP;
+
+//
+// BundleInfo is information needed by the bundle for framing decisions.
+// This information is the combined information of all links that are part
+// of this bundle.
+//
+typedef struct _BUNDLE_FRAME_INFO {
+ ULONG SendFramingBits; // Send framing bits
+ ULONG RecvFramingBits; // Receive framing bits
+ ULONG MaxRSendFrameSize; // Max size of send frame
+ ULONG MaxRRecvFrameSize; // Max size of receive frame
+} BUNDLE_FRAME_INFO, *PBUNDLE_FRAME_INFO;
+
+#ifdef BANDWIDTH_ON_DEMAND
+typedef struct _BOND_INFO {
+ ULONG ulBytesThreshold; // Threshold in BytesPerSamplePeriod
+ USHORT usPercentBandwidth; // Threshold as % of total bandwidth
+ ULONG ulSecondsInSamplePeriod; // # of seconds in a sample period
+ ULONG State; // Current state
+ WAN_TIME StartTime; // Start time for threshold event
+ SAMPLE_TABLE SampleTable;
+} BOND_INFO, *PBOND_INFO;
+#endif
+
+//
+// This information is used to describe the encryption that is being
+// done on the bundle. At some point this should be moved into
+// wanpub.h and ndiswan.h.
+//
+typedef struct _ENCRYPTION_INFO{
+ UCHAR StartKey[16]; // Start key
+ UCHAR SessionKey[16]; // Session key used for encrypting
+ ULONG SessionKeyLength; // Session key length
+ PVOID Context; // Key encryption context
+} ENCRYPTION_INFO, *PENCRYPTION_INFO;
+
+//
+// This is the control block that defines a bundle (connection). This block is created when
+// a WAN Miniport driver gives a lineup indicating a new connection has been established.
+// This control block will live as long as the connection is up (until a linedown is received) or
+// until the link associated with the bundle is added to a different bundle. BundleCB's live in
+// the global bundle array with their hBundleHandle as their index into the array.
+//
+typedef struct _BUNDLECB {
+ LIST_ENTRY Linkage; // Linkage for the global free list
+ NDIS_HANDLE hBundleHandle; // Index of this bundle in bundle array
+ NDIS_HANDLE hBundleContext; // Context passed down by usermode
+ ULONG ulAllocationSize; // Size of memory allocated
+ ULONG ulReferenceCount; // Reference count for this structure
+ BundleState State;
+ NDIS_SPIN_LOCK Lock; // Structure access lock
+
+ LIST_ENTRY LinkCBList; // List head for links in this bundle
+ ULONG ulLinkCBCount; // Count of links in the bundle
+
+ BUNDLE_FRAME_INFO FramingInfo; // Framing information for this bundle
+
+ //
+ // Send section
+ //
+ struct _LINKCB *NextLinkToXmit; // Next link to send data over
+ ULONG SendingLinks; // Number of links with wanpacket count > 1
+ LIST_ENTRY SendPacketQueue; // List head of wanpackets waiting to be sent
+ ULONG SendSeqNumber; // Current send sequence number (multilink)
+ ULONG SendSeqMask; // Mask for send sequence numbers
+ ULONG SendSeqTest; // Test for sequence number diff
+
+#define IN_SEND 0x00000001
+#define IN_RECEIVE 0x00000002
+#define TRY_SEND_AGAIN 0x00000004
+#define RECV_PACKET_FLUSH 0x00000008
+#define PROTOCOL_PRIORITY 0x00000010
+#define FRAMES_PENDING 0x00000020
+#define BUNDLE_ROUTED 0x00000040
+#define INDICATION_EVENT 0x00000080
+ ULONG Flags; // Flags
+
+ ULONG OutstandingFrames; // Number of outstanding sends on this bundle
+ WAN_EVENT OutstandingFramesEvent; // Async notification event for pending sends
+ NDIS_STATUS IndicationStatus;
+ WAN_EVENT IndicationEvent;
+
+ //
+ // Receive section
+ //
+ LIST_ENTRY RecvDescPool; // List of available recv desc's
+ ULONG RecvDescCount; // Count of available recv desc's
+ ULONG RecvDescMax; // Max number recv desc's needed
+ LIST_ENTRY RecvDescAssemblyList; // List head for assembly of recv descriptors
+ PRECV_DESC RecvDescHole; // Pointer to 1st hole in recv desc list
+ ULONG HoleSeqNumber; // Sequence number of the hole
+ ULONG MinReceivedSeqNumber; // Minimum recv sequence number on the bundle
+ ULONG RecvSeqMask; // Mask for receive sequence number
+ ULONG RecvSeqTest; // Test for sequence number diff
+ ULONG RecvFragmentsLost; // Count of recv fragments flushed
+ WAN_TIME LastRecvNonIdleData;
+
+ //
+ // Protocol information
+ //
+ struct _PROTOCOLCB **ProtocolCBTable; // Pointer to table of pointers to protocolcb's
+ ULONG ulNumberOfRoutes; // Number of protocolcb's in protocol table
+ LIST_ENTRY ProtocolCBList; // List head for protocols routed to this bundle
+ ULONG SendMask; // Send Mask for all send queues
+ BUNDLE_LINE_UP LineUpInfo; // Lineup info common to all protocols
+
+ //
+ // VJ information
+ //
+ VJ_INFO SendVJInfo; // Send VJ compression options
+ VJ_INFO RecvVJInfo; // Recv VJ compression options
+ struct slcompress *VJCompress; // Pointer to VJ compression table
+
+ //
+ // MS Compression
+ //
+ COMPRESS_INFO SendCompInfo; // Send compression options
+ PVOID SendCompressContext; // Pointer to send compressor context
+
+ COMPRESS_INFO RecvCompInfo; // Recv compression options
+ PVOID RecvCompressContext; // Pointer to receive decompressor context
+
+ //
+ // MS Encryption
+ //
+ ENCRYPTION_INFO SendEncryptInfo;
+ PVOID SendRC4Key; // Pointer to send encryption context
+
+ ENCRYPTION_INFO RecvEncryptInfo;
+ PVOID RecvRC4Key; // Pointer to receive encryption context
+
+ USHORT SCoherencyCounter; // Coherency counters
+ USHORT RCoherencyCounter; //
+ USHORT LastRC4Reset; // Encryption key reset
+ UCHAR CCPIdentifier; //
+
+#ifdef BANDWIDTH_ON_DEMAND
+ //
+ // Bandwidth on Demand
+ //
+ BOND_INFO UpperBonDInfo;
+ BOND_INFO LowerBonDInfo;
+#endif
+
+ //
+ // Bundle Name
+ //
+ ULONG ulNameLength; // Bundle name length
+ UCHAR Name[MAX_NAME_LENGTH]; // Bundle name
+
+ //
+ // Bundle statistics
+ //
+ WAN_STATS BundleStats; // Bundle statistics
+
+} BUNDLECB, *PBUNDLECB;
+
+
+//
+// This control blocks defines an active link that is part of a bundle (connection). This block
+// is created when a WAN Miniport driver gives a lineup indicating that a new connection has been
+// established. The control block lives until a linedown indication is received for the link.
+// The control block lives linked into a bundle control block.
+//
+typedef struct _LINKCB {
+ LIST_ENTRY Linkage; // Used to link the link into a bundle
+ NDIS_HANDLE hLinkHandle; // Index of this link in the active link array
+ NDIS_HANDLE hLinkContext; // Context passed down by usermode
+ ULONG ulAllocationSize; // Size of memory allocated
+ ULONG ulReferenceCount; // Reference count
+ LinkState State;
+ struct _WAN_ADAPTERCB *WanAdapterCB; // WanAdapter Context for this link
+ struct _BUNDLECB *BundleCB; // Pointer to owning bundle control block
+ NDIS_HANDLE NdisLinkHandle; // Handle given at lineup by the miniport
+
+ PUCHAR PacketMemory; // Pointer to packet memory allocation
+ ULONG PacketMemorySize; // Size of packet memory allocation
+ ULONG BufferSize; // Size of buffer in each packet
+ LIST_ENTRY WanPacketPool; // Pool of NDIS_WAN_PACKETS
+ ULONG ulWanPacketCount; // Count of available packets
+ ULONG PPPHeaderLength; // Length of the PPP header for this link
+ ULONG LastRecvSeqNumber; // Last recv sequence number on this link
+ ULONG RecvFragmentsLost; // Number of lost fragments on this link
+
+ ULONG OutstandingFrames; // Number of outstanding frames on the link
+ WAN_EVENT OutstandingFramesEvent; // Async notification event for pending sends
+ ULONG ulBandwidth; // % of the bundle bandwidth that this link has
+
+ WAN_LINK_INFO LinkInfo; // Framing information for this link
+ NDIS_MAC_LINE_UP LineUpInfo; // Link specific lineup information
+
+
+ ULONG ulNameLength; // Name length
+ UCHAR Name[MAX_NAME_LENGTH]; // Name of the link
+
+ WAN_STATS LinkStats; // Link statistics
+} LINKCB, *PLINKCB;
+
+//
+// The protocol control block defines a protocol that is routed to a bundle
+//
+typedef struct _PROTOCOLCB {
+ LIST_ENTRY Linkage; // Used to link the protocolcb onto the bundle
+ NDIS_HANDLE hProtocolHandle; // Index of this protocol in the bundle protocol array
+ ULONG ulAllocationSize; // Size of memory allocated
+ ULONG ulReferenceCount; // References to this structure
+#define PROTOCOL_ROUTED 0x00000001
+ ULONG Flags;
+ PNDIS_PACKET HeadNdisPacketQueue; // Queue of NdisPackets waiting to be sent
+ PNDIS_PACKET TailNdisPacketQueue; // Last packet on the queue
+ ULONG SendMaskBit; // Send mask bit for this protocol send queue
+ struct _ADAPTERCB *AdapterCB; // Pointer to the adaptercb
+ struct _BUNDLECB *BundleCB; // Pointer to the bundlecb
+ USHORT usProtocolType; // EtherType of this protocol
+ USHORT usPPPProtocolID; // PPP Protocol ID
+ WAN_TIME LastRecvNonIdleData; // Time at which last non-idle packet was recv'd
+ BOOLEAN (*NonIdleDetectFunc)(); // Function to sniff for non-idle data
+#ifdef BANDWIDTH_ON_DEMAND
+ USHORT usPriority; // Protocol's priority setting
+ ULONG ulByteQuota; // Number of bytes allowed to be sent in 1sec
+ SAMPLE_TABLE SampleTable; // Sample table
+#endif
+ NDIS_HANDLE hTransportHandle; // Transport's connection identifier
+ UCHAR NdisWanAddress[6]; // MAC address used for this protocol
+ UCHAR TransportAddress[6]; // MAC address used for indications to transport
+ NDIS_STRING BindingName;
+ NDIS_STRING DeviceName;
+ ULONG ulLineUpInfoLength; // Length of protocol specific lineup info
+ PUCHAR LineUpInfo; // Pointer to protocol specific lineup info
+} PROTOCOLCB, *PPROTOCOLCB;
+
+#endif // WAN_TYPES
+
diff --git a/private/ntos/ndis/ne1000/makefile b/private/ntos/ndis/ne1000/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/ne1000/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/ne1000/ne1000.c b/private/ntos/ndis/ne1000/ne1000.c
new file mode 100644
index 000000000..8512af997
--- /dev/null
+++ b/private/ntos/ndis/ne1000/ne1000.c
@@ -0,0 +1,30 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ne1000.c
+
+Abstract:
+
+ This is the main file for the NE1000 Ethernet adapter.
+ This driver conforms to the NDIS 3.0 interface.
+
+Author:
+
+ Sean Selitrennikoff
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+
+--*/
+
+#include "..\ne2000\card.c"
+#include "..\ne2000\interrup.c"
+#include "..\ne2000\ne2000.c"
+
diff --git a/private/ntos/ndis/ne1000/ne1000.rc b/private/ntos/ndis/ne1000/ne1000.rc
new file mode 100644
index 000000000..9c87643e8
--- /dev/null
+++ b/private/ntos/ndis/ne1000/ne1000.rc
@@ -0,0 +1,39 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "Novell NE1000 network driver"
+#define VER_INTERNALNAME_STR "NE1000.SYS"
+#define VER_ORIGINALFILENAME_STR "NE1000.SYS"
+
+#include "common.ver"
+
diff --git a/private/ntos/ndis/ne1000/sources b/private/ntos/ndis/ne1000/sources
new file mode 100644
index 000000000..76b443d42
--- /dev/null
+++ b/private/ntos/ndis/ne1000/sources
@@ -0,0 +1,43 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=ne1000
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER -DNE1000
+
+INCLUDES=..\ne2000;..\..\inc
+
+SOURCES=ne1000.c\
+ ne1000.rc
+
+RELATIVE_DEPTH=..\..
+
+MSC_WARNING_LEVEL=/W3 /WX
+
diff --git a/private/ntos/ndis/ne2000/card.c b/private/ntos/ndis/ne2000/card.c
new file mode 100644
index 000000000..19244a224
--- /dev/null
+++ b/private/ntos/ndis/ne2000/card.c
@@ -0,0 +1,3212 @@
+
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ card.c
+
+Abstract:
+
+ Card-specific functions for the NDIS 3.0 Novell 2000 driver.
+
+Author:
+
+ Sean Selitrennikoff
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+--*/
+
+#include <ndis.h>
+#include "ne2000hw.h"
+#include "ne2000sw.h"
+
+
+BOOLEAN
+CardSlotTest(
+ IN PNE2000_ADAPTER Adapter
+ );
+
+BOOLEAN
+CardRamTest(
+ IN PNE2000_ADAPTER Adapter
+ );
+
+
+#pragma NDIS_INIT_FUNCTION(CardCheckParameters)
+
+BOOLEAN CardCheckParameters(
+ IN PNE2000_ADAPTER Adapter
+)
+
+/*++
+
+Routine Description:
+
+ Checks that the I/O base address is correct.
+
+Arguments:
+
+ Adapter - pointer to the adapter block.
+
+Return Value:
+
+ TRUE, if IoBaseAddress appears correct.
+
+--*/
+
+{
+ UCHAR Tmp;
+
+ //
+ // If adapter responds to a stop command correctly -- assume it is there.
+ //
+
+ //
+ // Turn off interrupts first.
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_INTR_MASK, 0);
+
+ //
+ // Stop the card.
+ //
+ SyncCardStop(Adapter);
+
+ //
+ // Pause
+ //
+ NdisStallExecution(2000);
+
+ //
+ // Read response
+ //
+ NdisRawReadPortUchar(Adapter->IoPAddr + NIC_COMMAND, &Tmp);
+
+ if ((Tmp == (CR_NO_DMA | CR_STOP)) ||
+ (Tmp == (CR_NO_DMA | CR_STOP | CR_START))
+ )
+ {
+ return(TRUE);
+ }
+ else
+ {
+ return(FALSE);
+ }
+}
+#ifdef NE2000
+
+#pragma NDIS_INIT_FUNCTION(CardSlotTest)
+
+
+BOOLEAN CardSlotTest(
+ IN PNE2000_ADAPTER Adapter
+)
+
+/*++
+
+Routine Description:
+
+ Checks if the card is in an 8 or 16 bit slot and sets a flag in the
+ adapter structure.
+
+Arguments:
+
+ Adapter - pointer to the adapter block.
+
+Return Value:
+
+ TRUE, if all goes well, else FALSE.
+
+--*/
+
+{
+ UCHAR Tmp;
+ UCHAR RomCopy[32];
+ UCHAR i;
+ BOOLEAN found;
+
+ //
+ // Reset the chip
+ //
+ NdisRawReadPortUchar(Adapter->IoPAddr + NIC_RESET, &Tmp);
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RESET, 0xFF);
+
+ //
+ // Go to page 0 and stop
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_COMMAND, CR_STOP | CR_NO_DMA);
+
+ //
+ // Pause
+ //
+ NdisStallExecution(2000);
+
+ //
+ // Check that it is stopped
+ //
+ NdisRawReadPortUchar(Adapter->IoPAddr + NIC_COMMAND, &Tmp);
+ if (Tmp != (CR_NO_DMA | CR_STOP))
+ {
+ IF_LOUD(DbgPrint("Could not stop the card\n");)
+
+ return(FALSE);
+ }
+
+ //
+ // Setup to read from ROM
+ //
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_DATA_CONFIG,
+ DCR_BYTE_WIDE | DCR_FIFO_8_BYTE | DCR_NORMAL
+ );
+
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_INTR_MASK, 0x0);
+
+ //
+ // Ack any interrupts that may be hanging around
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_INTR_STATUS, 0xFF);
+
+ //
+ // Setup to read in the ROM, the address and byte count.
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_ADDR_LSB, 0x0);
+
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_ADDR_MSB, 0x0);
+
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 32);
+
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0x0);
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_COMMAND,
+ CR_DMA_READ | CR_START
+ );
+
+ //
+ // Read first 32 bytes in 16 bit mode
+ //
+ for (i = 0; i < 32; i++)
+ {
+ NdisRawReadPortUchar(Adapter->IoPAddr + NIC_RACK_NIC, RomCopy + i);
+ }
+
+ IF_VERY_LOUD( DbgPrint("Resetting the chip\n"); )
+
+ //
+ // Reset the chip
+ //
+ NdisRawReadPortUchar(Adapter->IoPAddr + NIC_RESET, &Tmp);
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RESET, 0xFF);
+
+ //
+ // Check ROM for 'B' (byte) or 'W' (word)
+ // NOTE: If the buffer has bot BB and WW then use WW instead of BB
+ IF_VERY_LOUD( DbgPrint("Checking slot type\n"); )
+
+ found = FALSE;
+ for (i = 16; i < 31; i++)
+ {
+ if (((RomCopy[i] == 'B') && (RomCopy[i+1] == 'B')) ||
+ ((RomCopy[i] == 'W') && (RomCopy[i+1] == 'W'))
+ )
+ {
+ if (RomCopy[i] == 'B')
+ {
+ Adapter->EightBitSlot = TRUE;
+ found = TRUE;
+ }
+ else
+ {
+ Adapter->EightBitSlot = FALSE;
+ found = TRUE;
+ break; // Go no farther
+ }
+ }
+ }
+
+ if (found)
+ {
+ IF_VERY_LOUD( (Adapter->EightBitSlot?DbgPrint("8 bit slot\n"):
+ DbgPrint("16 bit slot\n")); )
+ }
+ else
+ {
+ //
+ // If neither found -- then not an NE2000
+ //
+ IF_VERY_LOUD( DbgPrint("Failed slot type\n"); )
+ }
+
+ return(found);
+}
+
+#endif // NE2000
+
+
+
+
+#pragma NDIS_INIT_FUNCTION(CardRamTest)
+
+BOOLEAN
+CardRamTest(
+ IN PNE2000_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Finds out how much RAM the adapter has. It starts at 1K and checks thru
+ 60K. It will set Adapter->RamSize to the appropriate value iff this
+ function returns TRUE.
+
+Arguments:
+
+ Adapter - pointer to the adapter block.
+
+Return Value:
+
+ TRUE, if all goes well, else FALSE.
+
+--*/
+
+{
+ PUCHAR RamBase, RamPointer;
+ PUCHAR RamEnd;
+
+ UCHAR TestPattern[]={ 0xAA, 0x55, 0xFF, 0x00 };
+ PULONG pTestPattern = (PULONG)TestPattern;
+ UCHAR ReadPattern[4];
+ PULONG pReadPattern = (PULONG)ReadPattern;
+
+ for (RamBase = (PUCHAR)0x400; RamBase < (PUCHAR)0x10000; RamBase += 0x400) {
+
+ //
+ // Write Test pattern
+ //
+
+ if (!CardCopyDown(Adapter, RamBase, TestPattern, 4)) {
+
+ continue;
+
+ }
+
+ //
+ // Read pattern
+ //
+
+ if (!CardCopyUp(Adapter, ReadPattern, RamBase, 4)) {
+
+ continue;
+
+ }
+
+ IF_VERY_LOUD( DbgPrint("Addr 0x%x: 0x%x, 0x%x, 0x%x, 0x%x\n",
+ RamBase,
+ ReadPattern[0],
+ ReadPattern[1],
+ ReadPattern[2],
+ ReadPattern[3]
+ );
+ )
+
+
+ //
+ // If they are the same, find the end
+ //
+
+ if (*pReadPattern == *pTestPattern) {
+
+ for (RamEnd = RamBase; !((ULONG)RamEnd & 0xFFFF0000); RamEnd += 0x400) {
+
+ //
+ // Write test pattern
+ //
+
+ if (!CardCopyDown(Adapter, RamEnd, TestPattern, 4)) {
+
+ break;
+
+ }
+
+ //
+ // Read pattern
+ //
+
+ if (!CardCopyUp(Adapter, ReadPattern, RamEnd, 4)) {
+
+ break;
+
+ }
+
+ if (*pReadPattern != *pTestPattern) {
+
+ break;
+
+ }
+
+ }
+
+ break;
+
+ }
+
+ }
+
+ IF_LOUD( DbgPrint("RamBase 0x%x, RamEnd 0x%x\n", RamBase, RamEnd); )
+
+ //
+ // If not found, error out
+ //
+
+ if ((RamBase >= (PUCHAR)0x10000) || (RamBase == RamEnd)) {
+
+ return(FALSE);
+
+ }
+
+ //
+ // Watch for boundary case when RamEnd is maximum value
+ //
+
+ if ((ULONG)RamEnd & 0xFFFF0000) {
+
+ RamEnd -= 0x100;
+
+ }
+
+ //
+ // Check all of ram
+ //
+
+ for (RamPointer = RamBase; RamPointer < RamEnd; RamPointer += 4) {
+
+ //
+ // Write test pattern
+ //
+
+ if (!CardCopyDown(Adapter, RamPointer, TestPattern, 4)) {
+
+ return(FALSE);
+
+ }
+
+ //
+ // Read pattern
+ //
+
+ if (!CardCopyUp(Adapter, ReadPattern, RamBase, 4)) {
+
+ return(FALSE);
+
+ }
+
+ if (*pReadPattern != *pTestPattern) {
+
+ return(FALSE);
+
+ }
+
+ }
+
+ //
+ // Store Results
+ //
+
+ Adapter->RamBase = RamBase;
+ Adapter->RamSize = (ULONG)(RamEnd - RamBase);
+
+ return(TRUE);
+
+}
+
+#pragma NDIS_INIT_FUNCTION(CardInitialize)
+
+BOOLEAN
+CardInitialize(
+ IN PNE2000_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes the card into a running state.
+
+Arguments:
+
+ Adapter - pointer to the adapter block.
+
+Return Value:
+
+ TRUE, if all goes well, else FALSE.
+
+--*/
+
+{
+ UCHAR Tmp;
+ USHORT i;
+
+ //
+ // Stop the card.
+ //
+ SyncCardStop(Adapter);
+
+ //
+ // Initialize the Data Configuration register.
+ //
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_DATA_CONFIG,
+ DCR_AUTO_INIT | DCR_FIFO_8_BYTE
+ );
+
+ //
+ // Set Xmit start location
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_XMIT_START, 0xA0);
+
+ //
+ // Set Xmit configuration
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_XMIT_CONFIG, 0x0);
+
+ //
+ // Set Receive configuration
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RCV_CONFIG, RCR_MONITOR);
+
+ //
+ // Set Receive start
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_PAGE_START, 0x4);
+
+ //
+ // Set Receive end
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_PAGE_STOP, 0xFF);
+
+ //
+ // Set Receive boundary
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_BOUNDARY, 0x4);
+
+ //
+ // Set Xmit bytes
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_XMIT_COUNT_LSB, 0x3C);
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_XMIT_COUNT_MSB, 0x0);
+
+ //
+ // Pause
+ //
+ NdisStallExecution(2000);
+
+ //
+ // Ack all interrupts that we might have produced
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_INTR_STATUS, 0xFF);
+
+ //
+ // Change to page 1
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_COMMAND, CR_PAGE1 | CR_STOP);
+
+ //
+ // Set current
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_CURRENT, 0x4);
+
+ //
+ // Back to page 0
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_COMMAND, CR_PAGE0 | CR_STOP);
+
+ //
+ // Pause
+ //
+ NdisStallExecution(2000);
+
+ //
+ // Check that Command register reflects this last command
+ //
+ NdisRawReadPortUchar(Adapter->IoPAddr + NIC_COMMAND, &Tmp);
+ if (!(Tmp & CR_STOP))
+ {
+ IF_LOUD(DbgPrint("Invalid command register\n");)
+
+ return(FALSE);
+ }
+
+ //
+ // Do initialization errata
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 55);
+
+ //
+ // Setup for a read
+ //
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_COMMAND,
+ CR_DMA_READ | CR_START
+ );
+
+#ifdef NE2000
+
+ //
+ // Check if the slot is 8 or 16 bit (affects data transfer rate).
+ //
+
+ if ((Adapter->BusType == NdisInterfaceMca) ||
+ (NE2000_PCMCIA == Adapter->CardType))
+ {
+ Adapter->EightBitSlot = FALSE;
+ }
+ else
+ {
+ IF_VERY_LOUD(DbgPrint("CardSlotTest\n");)
+
+ if (CardSlotTest(Adapter) == FALSE)
+ {
+ //
+ // Stop chip
+ //
+ SyncCardStop(Adapter);
+
+ IF_LOUD(DbgPrint(" -- Failed\n");)
+ return(FALSE);
+ }
+
+ }
+
+#else // NE2000
+
+ Adapter->EightBitSlot = TRUE;
+
+#endif // NE2000
+
+ //
+ // Mask Interrupts
+ //
+
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_INTR_MASK, 0x0);
+
+ //
+ // Setup the Adapter for reading ram
+ //
+
+// NdisRawWritePortUchar(Adapter->IoPAddr + NIC_COMMAND, CR_PAGE0); // robin
+
+ if (Adapter->EightBitSlot)
+ {
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_DATA_CONFIG,
+ DCR_FIFO_8_BYTE | DCR_NORMAL | DCR_BYTE_WIDE
+ );
+ }
+ else
+ {
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_DATA_CONFIG,
+ DCR_FIFO_8_BYTE | DCR_NORMAL | DCR_WORD_WIDE
+ );
+ }
+
+ //
+ // Clear transmit configuration.
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_XMIT_CONFIG, 0);
+
+ //
+ // Clear receive configuration.
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RCV_CONFIG, 0);
+
+ //
+ // Clear any interrupts
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_INTR_STATUS, 0xFF);
+
+ //
+ // Stop the chip
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_COMMAND, CR_NO_DMA | CR_STOP);
+
+ //
+ // Clear any DMA values
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0);
+
+ //
+ // Clear any DMA values
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0);
+
+ //
+ // Wait for the reset to complete.
+ //
+ i = 0x3FFF;
+
+ while (--i)
+ {
+ NdisRawReadPortUchar(Adapter->IoPAddr + NIC_INTR_STATUS, &Tmp);
+
+ if (Tmp & ISR_RESET)
+ break;
+
+ NdisStallExecution(4);
+ }
+
+ //
+ // Put card in loopback mode
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_XMIT_CONFIG, TCR_LOOPBACK);
+
+ //
+ // Start the chip.
+ //
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_COMMAND,
+ CR_NO_DMA | CR_START
+ );
+
+ //
+ // Test for the amount of RAM
+ //
+ if (NE2000_ISA == Adapter->CardType)
+ {
+ if (CardRamTest(Adapter) == FALSE)
+ {
+ //
+ // Stop the chip
+ //
+ SyncCardStop(Adapter);
+
+ return(FALSE);
+ }
+ }
+ else
+ {
+ //
+ // We know what it is for the pcmcia adapters,
+ // so don't waste time on detecting it.
+ //
+ Adapter->RamBase = (PUCHAR)0x4000;
+ Adapter->RamSize = 0x4000;
+ }
+
+ //
+ // Stop the chip
+ //
+ SyncCardStop(Adapter);
+
+ return(TRUE);
+}
+
+
+#pragma NDIS_INIT_FUNCTION(CardReadEthernetAddress)
+
+BOOLEAN CardReadEthernetAddress(
+ IN PNE2000_ADAPTER Adapter
+)
+
+/*++
+
+Routine Description:
+
+ Reads in the Ethernet address from the Novell 2000.
+
+Arguments:
+
+ Adapter - pointer to the adapter block.
+
+Return Value:
+
+ The address is stored in Adapter->PermanentAddress, and StationAddress if it
+ is currently zero.
+
+--*/
+
+{
+ UINT c;
+
+ //
+ // Things are done a little differently for PCMCIA adapters.
+ //
+ if (NE2000_PCMCIA == Adapter->CardType)
+ {
+ NDIS_STATUS Status;
+ PUCHAR pAttributeWindow;
+ NDIS_PHYSICAL_ADDRESS AttributePhysicalAddress;
+
+ //
+ // Setup the physical address for the attribute window.
+ //
+ NdisSetPhysicalAddressHigh(AttributePhysicalAddress, 0);
+ NdisSetPhysicalAddressLow(
+ AttributePhysicalAddress,
+ Adapter->AttributeMemoryAddress
+ );
+
+ //
+ // We need to get the pcmcia information from the tuple.
+ //
+ Status = NdisMMapIoSpace(
+ (PVOID *)&pAttributeWindow,
+ Adapter->MiniportAdapterHandle,
+ AttributePhysicalAddress,
+ Adapter->AttributeMemorySize
+ );
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ //
+ // Failed to setup the attribute window.
+ //
+ return(FALSE);
+ }
+
+ //
+ // Read the ethernet address from the card.
+ //
+ for (c = 0; c < ETH_LENGTH_OF_ADDRESS; c++)
+ {
+ NdisReadRegisterUchar(
+ (PUCHAR)(pAttributeWindow + CIS_NET_ADDR_OFFSET + c * 2),
+ &Adapter->PermanentAddress[c]);
+ }
+ }
+ else
+ {
+ //
+ // Setup to read the ethernet address
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 12);
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0);
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_ADDR_LSB, 0);
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_ADDR_MSB, 0);
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_COMMAND,
+ CR_START | CR_DMA_READ
+ );
+
+ //
+ // Read in the station address. (We have to read words -- 2 * 6 -- bytes)
+ //
+ for (c = 0; c < NE2000_LENGTH_OF_ADDRESS; c++)
+ {
+ NdisRawReadPortUchar(
+ Adapter->IoPAddr + NIC_RACK_NIC,
+ &Adapter->PermanentAddress[c]
+ );
+ }
+ }
+
+ IF_LOUD(
+ DbgPrint(
+ "Ne2000: PermanentAddress [ %02x-%02x-%02x-%02x-%02x-%02x ]\n",
+ Adapter->PermanentAddress[0],
+ Adapter->PermanentAddress[1],
+ Adapter->PermanentAddress[2],
+ Adapter->PermanentAddress[3],
+ Adapter->PermanentAddress[4],
+ Adapter->PermanentAddress[5]
+ );
+ )
+
+ //
+ // Use the burned in address as the station address, unless the
+ // registry specified an override value.
+ //
+ if ((Adapter->StationAddress[0] == 0x00) &&
+ (Adapter->StationAddress[1] == 0x00) &&
+ (Adapter->StationAddress[2] == 0x00) &&
+ (Adapter->StationAddress[3] == 0x00) &&
+ (Adapter->StationAddress[4] == 0x00) &&
+ (Adapter->StationAddress[5] == 0x00)
+ )
+ {
+ Adapter->StationAddress[0] = Adapter->PermanentAddress[0];
+ Adapter->StationAddress[1] = Adapter->PermanentAddress[1];
+ Adapter->StationAddress[2] = Adapter->PermanentAddress[2];
+ Adapter->StationAddress[3] = Adapter->PermanentAddress[3];
+ Adapter->StationAddress[4] = Adapter->PermanentAddress[4];
+ Adapter->StationAddress[5] = Adapter->PermanentAddress[5];
+ }
+
+ return(TRUE);
+}
+
+
+BOOLEAN
+CardSetup(
+ IN PNE2000_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Sets up the card.
+
+Arguments:
+
+ Adapter - pointer to the adapter block, which must be initialized.
+
+Return Value:
+
+ TRUE if successful.
+
+--*/
+
+{
+ UINT i;
+ UINT Filter;
+ UCHAR Tmp;
+
+
+ //
+ // Write to and read from CR to make sure it is there.
+ //
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_COMMAND,
+ CR_STOP | CR_NO_DMA | CR_PAGE0
+ );
+
+ NdisRawReadPortUchar(
+ Adapter->IoPAddr + NIC_COMMAND,
+ &Tmp
+ );
+ if ((Tmp & (CR_STOP | CR_NO_DMA | CR_PAGE0)) !=
+ (CR_STOP | CR_NO_DMA | CR_PAGE0)
+ )
+ {
+ return(FALSE);
+ }
+
+ //
+ // Set up the registers in the correct sequence, as defined by
+ // the 8390 specification.
+ //
+ if (Adapter->EightBitSlot)
+ {
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_DATA_CONFIG,
+ DCR_BYTE_WIDE | DCR_NORMAL | DCR_FIFO_8_BYTE
+ );
+ }
+ else
+ {
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_DATA_CONFIG,
+ DCR_WORD_WIDE | DCR_NORMAL | DCR_FIFO_8_BYTE
+ );
+ }
+
+
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0);
+
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0);
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_RCV_CONFIG,
+ Adapter->NicReceiveConfig
+ );
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_XMIT_CONFIG,
+ TCR_LOOPBACK
+ );
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_BOUNDARY,
+ Adapter->NicPageStart
+ );
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_PAGE_START,
+ Adapter->NicPageStart
+ );
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_PAGE_STOP,
+ Adapter->NicPageStop
+ );
+
+ Adapter->Current = Adapter->NicPageStart + (UCHAR)1;
+ Adapter->NicNextPacket = Adapter->NicPageStart + (UCHAR)1;
+ Adapter->BufferOverflow = FALSE;
+
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_INTR_STATUS, 0xff);
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_INTR_MASK,
+ Adapter->NicInterruptMask
+ );
+
+
+ //
+ // Move to page 1 to write the station address
+ //
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_COMMAND,
+ CR_STOP | CR_NO_DMA | CR_PAGE1
+ );
+
+ for (i = 0; i < NE2000_LENGTH_OF_ADDRESS; i++)
+ {
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + (NIC_PHYS_ADDR + i),
+ Adapter->StationAddress[i]
+ );
+ }
+
+ Filter = Adapter->PacketFilter;
+
+ //
+ // Write out the multicast addresses
+ //
+ for (i = 0; i < 8; i++)
+ {
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + (NIC_MC_ADDR + i),
+ (UCHAR)((Filter & NDIS_PACKET_TYPE_ALL_MULTICAST) ?
+ 0xff : Adapter->NicMulticastRegs[i])
+ );
+ }
+
+ //
+ // Write out the current receive buffer to receive into
+ //
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_CURRENT,
+ Adapter->Current
+ );
+
+
+ //
+ // move back to page 0 and start the card...
+ //
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_COMMAND,
+ CR_STOP | CR_NO_DMA | CR_PAGE0
+ );
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE0
+ );
+
+ //
+ // ... but it is still in loopback mode.
+ //
+ return(TRUE);
+}
+
+VOID CardStop(
+ IN PNE2000_ADAPTER Adapter
+)
+
+/*++
+
+Routine Description:
+
+ Stops the card.
+
+Arguments:
+
+ Adapter - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UINT i;
+ UCHAR Tmp;
+
+ //
+ // Turn on the STOP bit in the Command register.
+ //
+ SyncCardStop(Adapter);
+
+ //
+ // Clear the Remote Byte Count register so that ISR_RESET
+ // will come on.
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0);
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0);
+
+
+ //
+ // Wait for ISR_RESET, but only for 1.6 milliseconds (as
+ // described in the March 1991 8390 addendum), since that
+ // is the maximum time for a software reset to occur.
+ //
+ //
+ for (i = 0; i < 4; i++)
+ {
+ NdisRawReadPortUchar(Adapter->IoPAddr+NIC_INTR_STATUS, &Tmp);
+ if (Tmp & ISR_RESET)
+ break;
+
+ NdisStallExecution(500);
+ }
+
+ if (i == 4)
+ {
+ IF_LOUD( DbgPrint("RESET\n");)
+ IF_LOG( Ne2000Log('R');)
+ }
+
+ //
+ // Put the card in loopback mode, then start it.
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_XMIT_CONFIG, TCR_LOOPBACK);
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_COMMAND, CR_START | CR_NO_DMA);
+
+ //
+ // At this point the card is still in loopback mode.
+ //
+}
+
+BOOLEAN CardReset(
+ IN PNE2000_ADAPTER Adapter
+)
+
+/*++
+
+Routine Description:
+
+ Resets the card.
+
+Arguments:
+
+ Adapter - pointer to the adapter block
+
+Return Value:
+
+ TRUE if everything is OK.
+
+--*/
+
+{
+ //
+ // Stop the chip
+ //
+ CardStop(Adapter);
+
+ //
+ // Wait for the card to finish any receives or transmits
+ //
+ NdisStallExecution(2000);
+
+ //
+ // CardSetup() does a software reset.
+ //
+ if (!CardSetup(Adapter))
+ {
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 2,
+ cardReset,
+ NE2000_ERRMSG_CARD_SETUP
+ );
+
+ return(FALSE);
+ }
+
+ //
+ // Restart the chip
+ //
+ CardStart(Adapter);
+
+ return TRUE;
+}
+
+
+
+BOOLEAN CardCopyDownPacket(
+ IN PNE2000_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet,
+ OUT PUINT Length
+)
+
+/*++
+
+Routine Description:
+
+ Copies the packet Packet down starting at the beginning of
+ transmit buffer XmitBufferNum, fills in Length to be the
+ length of the packet.
+
+Arguments:
+
+ Adapter - pointer to the adapter block
+ Packet - the packet to copy down
+
+Return Value:
+
+ Length - the length of the data in the packet in bytes.
+ TRUE if the transfer completed with no problems.
+
+--*/
+
+{
+ //
+ // Addresses of the Buffers to copy from and to.
+ //
+ PUCHAR CurBufAddress;
+ PUCHAR OddBufAddress;
+ PUCHAR XmitBufAddress;
+
+ //
+ // Length of each of the above buffers
+ //
+ UINT CurBufLen;
+ UINT PacketLength;
+
+ //
+ // Was the last transfer of an odd length?
+ //
+ BOOLEAN OddBufLen = FALSE;
+
+ //
+ // Current NDIS_BUFFER that is being copied from
+ //
+ PNDIS_BUFFER CurBuffer;
+
+ //
+ // Programmed I/O, have to transfer the data.
+ //
+ NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, &PacketLength);
+
+ //
+ // Skip 0 length copies
+ //
+ if (PacketLength == 0) {
+ return(TRUE);
+ }
+
+ //
+ // Get the starting buffer address
+ //
+ XmitBufAddress = (PUCHAR)Adapter->XmitStart +
+ Adapter->NextBufToFill*TX_BUF_SIZE;
+
+ //
+ // Get address and length of the first buffer in the packet
+ //
+ NdisQueryBuffer(CurBuffer, (PVOID *)&CurBufAddress, &CurBufLen);
+
+ while (CurBuffer && (CurBufLen == 0)) {
+
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+
+ NdisQueryBuffer(CurBuffer, (PVOID *)&CurBufAddress, &CurBufLen);
+
+ }
+
+ //
+ // set up the card
+ //
+ {
+
+ //
+ // Temporary places for holding values for transferring to
+ // an odd aligned address on 16-bit slots.
+ //
+ UCHAR Tmp;
+ UCHAR Tmp1;
+ USHORT TmpShort;
+
+ //
+ // Values for waiting for noticing when a DMA completes.
+ //
+ USHORT OldAddr, NewAddr;
+
+ //
+ // Count of transfers to do
+ //
+ USHORT Count;
+
+ //
+ // Buffer to read from for odd aligned transfers
+ //
+ PUCHAR ReadBuffer;
+
+ if (!Adapter->EightBitSlot && ((ULONG)XmitBufAddress & 0x1)) {
+
+ //
+ // Avoid transfers to odd addresses in word mode.
+ //
+ // For odd addresses we need to read first to get the previous
+ // byte and then merge it with our first byte.
+ //
+
+ //
+ // Set Count and Source address
+ //
+
+// NdisRawWritePortUchar(Adapter->IoPAddr + NIC_COMMAND, CR_PAGE0); // robin
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_RMT_ADDR_LSB,
+ LSB((XmitBufAddress - 1))
+ );
+
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_ADDR_MSB,
+ MSB((XmitBufAddress - 1))
+ );
+
+// NE2000 PCMCIA CHANGE START
+
+ //
+ // NE2000 PCMCIA CHANGE!!!
+ //
+ //NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0x1 );
+ //NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0x0 );
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0x2 );
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0x0 );
+
+ //
+ // Set direction (Read)
+ //
+
+ NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND,
+ CR_START | CR_PAGE0 | CR_DMA_READ );
+
+ //
+ // NE2000 PCMCIA CHANGE!!!
+ //
+ //NdisRawReadPortUchar( Adapter->IoPAddr + NIC_RACK_NIC, &Tmp1 );
+ NdisRawReadPortUshort( Adapter->IoPAddr + NIC_RACK_NIC, &TmpShort );
+ Tmp1 = LSB(TmpShort);
+
+// NE2000 PCMCIA CHANGE END
+
+ //
+ // Do Write errata as described on pages 1-143 and
+ // 1-144 of the 1992 LAN databook
+ //
+
+ //
+ // Set Count and destination address
+ //
+ ReadBuffer = XmitBufAddress + ((ULONG)XmitBufAddress & 1);
+
+ OldAddr = NewAddr = (USHORT)(ReadBuffer);
+
+// NdisRawWritePortUchar(Adapter->IoPAddr + NIC_COMMAND, // robin
+// CR_PAGE0 // robin
+// ); // robin
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_ADDR_LSB,
+ LSB(ReadBuffer)
+ );
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_ADDR_MSB,
+ MSB(ReadBuffer)
+ );
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0x2 );
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0x0 );
+
+ //
+ // Set direction (Read)
+ //
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_COMMAND,
+ CR_START | CR_PAGE0 | CR_DMA_READ
+ );
+
+ //
+ // Read from port
+ //
+ NdisRawReadPortUshort( Adapter->IoPAddr + NIC_RACK_NIC, &TmpShort );
+
+ //
+ // Wait for addr to change
+ //
+ TmpShort = 0xFFFF;
+
+ while (TmpShort != 0) {
+
+ NdisRawReadPortUchar( Adapter->IoPAddr + NIC_CRDA_LSB, &Tmp );
+ NewAddr = Tmp;
+ NdisRawReadPortUchar( Adapter->IoPAddr + NIC_CRDA_MSB, &Tmp );
+ NewAddr |= (Tmp << 8);
+
+ if (NewAddr != OldAddr) {
+
+ break;
+
+ }
+
+ NdisStallExecution(1);
+
+ TmpShort--;
+ }
+
+ if (NewAddr == OldAddr) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 2,
+ cardCopyDownPacket,
+ (ULONG)XmitBufAddress
+ );
+
+ return(FALSE);
+
+ }
+
+ //
+ // Set Count and destination address
+ //
+ NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_ADDR_LSB,
+ LSB((XmitBufAddress - 1)) );
+
+ NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_ADDR_MSB,
+ MSB((XmitBufAddress - 1)) );
+
+ NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0x2 );
+
+ NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0x0 );
+
+ //
+ // Set direction (Write)
+ //
+ NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND,
+ CR_START | CR_PAGE0 | CR_DMA_WRITE );
+
+ //
+ // It seems that the card stores words in LOW:HIGH order
+ //
+ NdisRawWritePortUshort( Adapter->IoPAddr + NIC_RACK_NIC,
+ (USHORT)(Tmp1 | ((*CurBufAddress) << 8)) );
+
+ //
+ // Wait for DMA to complete
+ //
+ Count = 0xFFFF;
+
+ while (Count) {
+
+ NdisRawReadPortUchar( Adapter->IoPAddr + NIC_INTR_STATUS, &Tmp1 );
+
+ if (Tmp1 & ISR_DMA_DONE) {
+
+ break;
+
+ } else {
+
+ Count--;
+ NdisStallExecution(4);
+
+ }
+
+ }
+
+ CurBufAddress++;
+ XmitBufAddress++;
+ PacketLength--;
+ CurBufLen--;
+
+ }
+
+ //
+ // Do Write errata as described on pages 1-143 and 1-144 of
+ // the 1992 LAN databook
+ //
+
+ //
+ // Set Count and destination address
+ //
+ ReadBuffer = XmitBufAddress + ((ULONG)XmitBufAddress & 1);
+
+ OldAddr = NewAddr = (USHORT)(ReadBuffer);
+
+// NdisRawWritePortUchar(Adapter->IoPAddr + NIC_COMMAND, // robin
+// CR_PAGE0 // robin
+// ); // robin
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_ADDR_LSB,
+ LSB(ReadBuffer)
+ );
+
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_ADDR_MSB,
+ MSB(ReadBuffer)
+ );
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB,
+ 0x2
+ );
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB,
+ 0x0
+ );
+
+ //
+ // Set direction (Read)
+ //
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_COMMAND,
+ CR_START | CR_PAGE0 | CR_DMA_READ
+ );
+
+ if (Adapter->EightBitSlot) {
+
+ //
+ // Read from port
+ //
+ NdisRawReadPortUchar( Adapter->IoPAddr + NIC_RACK_NIC, &Tmp );
+ NdisRawReadPortUchar( Adapter->IoPAddr + NIC_RACK_NIC, &Tmp );
+
+ } else {
+
+ //
+ // Read from port
+ //
+ NdisRawReadPortUshort( Adapter->IoPAddr + NIC_RACK_NIC, &TmpShort );
+
+ }
+
+ //
+ // Wait for addr to change
+ //
+ TmpShort = 0xFFFF;
+
+ while (TmpShort != 0) {
+
+ NdisRawReadPortUchar( Adapter->IoPAddr + NIC_CRDA_LSB, &Tmp );
+ NewAddr = Tmp;
+ NdisRawReadPortUchar( Adapter->IoPAddr + NIC_CRDA_MSB, &Tmp );
+ NewAddr |= (Tmp << 8);
+
+ if (NewAddr != OldAddr) {
+
+ break;
+
+ }
+
+ NdisStallExecution(1);
+
+ TmpShort--;
+ }
+
+ if (NewAddr == OldAddr) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 2,
+ cardCopyDownPacket,
+ (ULONG)XmitBufAddress
+ );
+
+ return(FALSE);
+
+ }
+
+ //
+ // Set Count and destination address
+ //
+
+// NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND, CR_PAGE0 ); // robin
+
+ NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_ADDR_LSB,
+ LSB(XmitBufAddress) );
+
+ NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_ADDR_MSB,
+ MSB(XmitBufAddress) );
+
+ NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_COUNT_LSB,
+ LSB(PacketLength) );
+
+ NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_COUNT_MSB,
+ MSB(PacketLength) );
+ //
+ // Set direction (Write)
+ //
+ NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND,
+ CR_START | CR_PAGE0 | CR_DMA_WRITE );
+
+ } // setup
+
+ //
+ // Copy the data now
+ //
+
+ do {
+
+ UINT Count;
+ UCHAR Tmp;
+
+ //
+ // Write the previous byte with this one
+ //
+ if (OddBufLen) {
+
+ //
+ // It seems that the card stores words in LOW:HIGH order
+ //
+ NdisRawWritePortUshort( Adapter->IoPAddr + NIC_RACK_NIC,
+ (USHORT)(*OddBufAddress | ((*CurBufAddress) << 8)) );
+
+ OddBufLen = FALSE;
+ CurBufAddress++;
+ CurBufLen--;
+
+ }
+
+ if (Adapter->EightBitSlot) { // byte mode
+
+ NdisRawWritePortBufferUchar(
+ Adapter->IoPAddr + NIC_RACK_NIC,
+ CurBufAddress,
+ CurBufLen
+ );
+
+ } else { // word mode
+
+ NdisRawWritePortBufferUshort(
+ Adapter->IoPAddr + NIC_RACK_NIC,
+ (PUSHORT)CurBufAddress,
+ (CurBufLen >> 1));
+
+ //
+ // Save trailing byte (if an odd lengthed transfer)
+ //
+ if (CurBufLen & 0x1) {
+ OddBufAddress = CurBufAddress + (CurBufLen - 1);
+ OddBufLen = TRUE;
+ }
+
+ }
+
+ //
+ // Wait for DMA to complete
+ //
+ Count = 0xFFFF;
+ while (Count) {
+
+ NdisRawReadPortUchar(
+ Adapter->IoPAddr + NIC_INTR_STATUS,
+ &Tmp );
+
+ if (Tmp & ISR_DMA_DONE) {
+
+ break;
+
+ } else {
+
+ Count--;
+ NdisStallExecution(4);
+
+ }
+
+ }
+
+ //
+ // Move to the next buffer
+ //
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+
+ if (CurBuffer){
+ NdisQueryBuffer(CurBuffer, (PVOID *)&CurBufAddress, &CurBufLen);
+ }
+
+ //
+ // Get address and length of the next buffer
+ //
+ while (CurBuffer && (CurBufLen == 0)) {
+
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+
+ if (CurBuffer){
+ NdisQueryBuffer(CurBuffer, (PVOID *)&CurBufAddress, &CurBufLen);
+ }
+
+ }
+
+ } while (CurBuffer);
+
+ //
+ // Write trailing byte (if necessary)
+ //
+ if (OddBufLen)
+ {
+ UINT Count;
+ UCHAR Tmp;
+ USHORT TmpShort;
+
+ if (NE2000_PCMCIA == Adapter->CardType) {
+// NE2000 PCMCIA CHANGE!!! start
+ TmpShort = (USHORT)*OddBufAddress;
+ NdisRawWritePortUshort(Adapter->IoPAddr + NIC_RACK_NIC, TmpShort);
+// NE2000 PCMCIA CHANGE!!! end
+ }
+ else {
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RACK_NIC, *OddBufAddress);
+ }
+
+ //
+ // Wait for DMA to complete robin-2
+ //
+ Count = 0xFFFF;
+ while (Count) {
+
+ NdisRawReadPortUchar(
+ Adapter->IoPAddr + NIC_INTR_STATUS,
+ &Tmp );
+
+ if (Tmp & ISR_DMA_DONE) {
+ break;
+ } else {
+ Count--;
+ NdisStallExecution(4);
+ }
+ }
+ }
+
+ //
+ // Return length written
+ //
+ *Length = PacketLength;
+
+ return TRUE;
+}
+
+BOOLEAN
+CardCopyDown(
+ IN PNE2000_ADAPTER Adapter,
+ IN PUCHAR TargetBuffer,
+ IN PUCHAR SourceBuffer,
+ IN UINT Length
+ )
+
+/*++
+
+Routine Description:
+
+ Copies Length bytes from the SourceBuffer to the card buffer space
+ at card address TargetBuffer.
+
+Arguments:
+
+ Adapter - pointer to the adapter block
+
+ SourceBuffer - Buffer in virtual address space
+
+ TargetBuffer - Buffer in card address space
+
+ Length - number of bytes to transfer to card
+
+Return Value:
+
+ TRUE if the transfer completed with no problems.
+
+--*/
+
+{
+ //
+ // Temporary place holders for odd alignment transfers
+ //
+ UCHAR Tmp, TmpSave;
+ USHORT TmpShort;
+
+ //
+ // Values for waiting for noticing when a DMA completes.
+ //
+ USHORT OldAddr, NewAddr;
+
+ //
+ // Count of transfers to do
+ //
+ USHORT Count;
+
+ //
+ // Address the copy if coming from
+ //
+ PUCHAR ReadBuffer;
+
+
+ //
+ // Skip 0 length copies
+ //
+
+ if (Length == 0) {
+
+ return(TRUE);
+
+ }
+
+
+ if (!Adapter->EightBitSlot && ((ULONG)TargetBuffer & 0x1)) {
+
+ //
+ // For odd addresses we need to read first to get the previous
+ // byte and then merge it with our first byte.
+ //
+
+ //
+ // Set Count and Source address
+ //
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_RMT_ADDR_LSB,
+ LSB((TargetBuffer - 1))
+ );
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_RMT_ADDR_MSB,
+ MSB((TargetBuffer - 1))
+ );
+
+// NE2000 PCMCIA CHANGE!!! start
+ //NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0x1);
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0x2);
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0x0);
+// NE2000 PCMCIA CHANGE!!! end
+
+ //
+ // Set direction (Read)
+ //
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_COMMAND,
+ CR_START | CR_PAGE0 | CR_DMA_READ
+ );
+
+// NE2000 PCMCIA CHANGE!!! start
+ //NdisRawReadPortUchar(Adapter->IoPAddr + NIC_RACK_NIC, &TmpSave);
+ NdisRawReadPortUshort(Adapter->IoPAddr + NIC_RACK_NIC, &TmpShort);
+ TmpSave = LSB(TmpShort);
+// NE2000 PCMCIA CHANGE!!! end
+
+ //
+ // Do Write errata as described on pages 1-143 and 1-144 of the 1992
+ // LAN databook
+ //
+
+ //
+ // Set Count and destination address
+ //
+
+ ReadBuffer = TargetBuffer + ((ULONG)TargetBuffer & 1);
+
+ OldAddr = NewAddr = (USHORT)(ReadBuffer);
+
+// NdisRawWritePortUchar(Adapter->IoPAddr + NIC_COMMAND, CR_PAGE0); // robin
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_RMT_ADDR_LSB,
+ LSB(ReadBuffer)
+ );
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_RMT_ADDR_MSB,
+ MSB(ReadBuffer)
+ );
+
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0x2);
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0x0);
+
+ //
+ // Set direction (Read)
+ //
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_COMMAND,
+ CR_START | CR_PAGE0 | CR_DMA_READ
+ );
+
+ //
+ // Read from port
+ //
+
+ NdisRawReadPortUshort(Adapter->IoPAddr + NIC_RACK_NIC, &TmpShort);
+
+ //
+ // Wait for addr to change
+ //
+
+ TmpShort = 0xFFFF;
+
+ while (TmpShort != 0) {
+
+ NdisRawReadPortUchar(
+ Adapter->IoPAddr + NIC_CRDA_LSB,
+ &Tmp
+ );
+
+ NewAddr = Tmp;
+
+ NdisRawReadPortUchar(
+ Adapter->IoPAddr + NIC_CRDA_MSB,
+ &Tmp
+ );
+
+ NewAddr |= (Tmp << 8);
+
+ if (NewAddr != OldAddr) {
+
+ break;
+ }
+
+ NdisStallExecution(1);
+
+ TmpShort--;
+
+ }
+
+ if (NewAddr == OldAddr) {
+
+ return(FALSE);
+
+ }
+
+ //
+ // Set Count and destination address
+ //
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_RMT_ADDR_LSB,
+ LSB((TargetBuffer - 1))
+ );
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_RMT_ADDR_MSB,
+ MSB((TargetBuffer - 1))
+ );
+
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0x2);
+ NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0x0);
+
+ //
+ // Set direction (Write)
+ //
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_COMMAND,
+ CR_START | CR_PAGE0 | CR_DMA_WRITE
+ );
+
+ //
+ // It seems that the card stores words in LOW:HIGH order
+ //
+
+ NdisRawWritePortUshort(
+ Adapter->IoPAddr + NIC_RACK_NIC,
+ (USHORT)(TmpSave | ((*SourceBuffer) << 8))
+ );
+
+ //
+ // Wait for DMA to complete
+ //
+
+ Count = 0xFFFF;
+
+ while (Count) {
+
+ NdisRawReadPortUchar(
+ Adapter->IoPAddr + NIC_INTR_STATUS,
+ &Tmp
+ );
+
+ if (Tmp & ISR_DMA_DONE) {
+
+ break;
+
+ } else {
+
+ Count--;
+
+ NdisStallExecution(4);
+
+ }
+
+ }
+
+ SourceBuffer++;
+ TargetBuffer++;
+ Length--;
+
+ }
+
+ //
+ // Do Write errata as described on pages 1-143 and 1-144 of the 1992
+ // LAN databook
+ //
+
+ //
+ // Set Count and destination address
+ //
+
+ ReadBuffer = TargetBuffer + ((ULONG)TargetBuffer & 1);
+
+ OldAddr = NewAddr = (USHORT)(ReadBuffer);
+
+// NdisRawWritePortUchar( // robin
+// Adapter->IoPAddr + NIC_COMMAND, // robin
+// CR_PAGE0 // robin
+// ); // robin
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_RMT_ADDR_LSB,
+ LSB(ReadBuffer)
+ );
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_RMT_ADDR_MSB,
+ MSB(ReadBuffer)
+ );
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_RMT_COUNT_LSB,
+ 0x2
+ );
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_RMT_COUNT_MSB,
+ 0x0
+ );
+
+ //
+ // Set direction (Read)
+ //
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_COMMAND,
+ CR_START | CR_PAGE0 | CR_DMA_READ
+ );
+
+ if (Adapter->EightBitSlot) {
+
+ //
+ // Read from port
+ //
+
+ NdisRawReadPortUchar(
+ Adapter->IoPAddr + NIC_RACK_NIC,
+ &Tmp
+ );
+
+
+ NdisRawReadPortUchar(
+ Adapter->IoPAddr + NIC_RACK_NIC,
+ &Tmp
+ );
+
+ } else {
+
+ //
+ // Read from port
+ //
+
+ NdisRawReadPortUshort(
+ Adapter->IoPAddr + NIC_RACK_NIC,
+ &TmpShort
+ );
+
+ }
+
+ //
+ // Wait for addr to change
+ //
+
+ TmpShort = 0xFFFF;
+
+ while (TmpShort != 0) {
+
+ NdisRawReadPortUchar(
+ Adapter->IoPAddr + NIC_CRDA_LSB,
+ &Tmp
+ );
+
+ NewAddr = Tmp;
+
+ NdisRawReadPortUchar(
+ Adapter->IoPAddr + NIC_CRDA_MSB,
+ &Tmp
+ );
+
+ NewAddr |= (Tmp << 8);
+
+ if (NewAddr != OldAddr) {
+
+ break;
+ }
+
+ NdisStallExecution(1);
+
+ TmpShort--;
+
+ }
+
+ if (NewAddr == OldAddr) {
+
+ return(FALSE);
+
+ }
+
+ //
+ // Set Count and destination address
+ //
+
+// NdisRawWritePortUchar( // robin
+// Adapter->IoPAddr + NIC_COMMAND, // robin
+// CR_PAGE0 // robin
+// ); // robin
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_RMT_ADDR_LSB,
+ LSB(TargetBuffer)
+ );
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_RMT_ADDR_MSB,
+ MSB(TargetBuffer)
+ );
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_RMT_COUNT_LSB,
+ LSB(Length)
+ );
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_RMT_COUNT_MSB,
+ MSB(Length)
+ );
+
+ //
+ // Set direction (Write)
+ //
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_COMMAND,
+ CR_START | CR_PAGE0 | CR_DMA_WRITE
+ );
+
+ if (Adapter->EightBitSlot) {
+
+ //
+ // Repeatedly write to out port
+ //
+
+ NdisRawWritePortBufferUchar(
+ Adapter->IoPAddr + NIC_RACK_NIC,
+ SourceBuffer,
+ Length);
+
+ } else {
+
+ //
+ // Write words to out ports
+ //
+
+ NdisRawWritePortBufferUshort(
+ Adapter->IoPAddr + NIC_RACK_NIC,
+ (PUSHORT)SourceBuffer,
+ (Length >> 1));
+
+ //
+ // Write trailing byte (if necessary)
+ //
+ if (Length & 0x1)
+ {
+ SourceBuffer += (Length - 1);
+
+// NE2000 PCMCIA CHANGE!!! start
+
+ //NdisRawWritePortUchar(
+ // Adapter->IoPAddr + NIC_RACK_NIC,
+ // *SourceBuffer
+ //);
+
+ TmpShort = (USHORT)(*SourceBuffer);
+ NdisRawWritePortUshort(
+ Adapter->IoPAddr + NIC_RACK_NIC,
+ TmpShort
+ );
+// NE2000 PCMCIA CHANGE!!! end
+
+
+ }
+
+ }
+
+ //
+ // Wait for DMA to complete
+ //
+
+ Count = 0xFFFF;
+
+ while (Count) {
+
+ NdisRawReadPortUchar(
+ Adapter->IoPAddr + NIC_INTR_STATUS,
+ &Tmp
+ );
+
+ if (Tmp & ISR_DMA_DONE) {
+
+ break;
+
+ } else {
+
+ Count--;
+
+ NdisStallExecution(4);
+
+ }
+
+#if DBG
+ if (!(Tmp & ISR_DMA_DONE)) {
+
+ DbgPrint("CopyDownDMA didn't finish!");
+
+ }
+#endif // DBG
+
+ }
+
+ IF_LOG(Ne2000Log('>');)
+
+ return TRUE;
+}
+
+
+BOOLEAN
+CardCopyUp(
+ IN PNE2000_ADAPTER Adapter,
+ IN PUCHAR TargetBuffer,
+ IN PUCHAR SourceBuffer,
+ IN UINT BufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ Copies data from the card to memory.
+
+Arguments:
+
+ Adapter - pointer to the adapter block
+
+ Target - the target address
+
+ Source - the source address (on the card)
+
+ BufferLength - the number of bytes to copy
+
+Return Value:
+
+ TRUE if the transfer completed with no problems.
+
+--*/
+
+{
+
+ //
+ // Used to check when the dma is done
+ //
+ UCHAR IsrValue;
+
+ //
+ // Count of the number of transfers to do
+ //
+ USHORT Count;
+
+ //
+ // Place holder for port values
+ //
+ UCHAR Temp;
+
+ if (BufferLength == 0) {
+
+ return TRUE;
+
+ }
+
+ //
+ // Read the Command Register, to make sure it is ready for a write
+ //
+ NdisRawReadPortUchar(Adapter->IoPAddr+NIC_COMMAND, &Temp);
+
+ if (Adapter->EightBitSlot) {
+
+ //
+ // If byte mode
+ //
+
+ //
+ // Set Count and destination address
+ //
+
+// NdisRawWritePortUchar( // robin
+// Adapter->IoPAddr + NIC_COMMAND, // robin
+// CR_PAGE0 // robin
+// ); // robin
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_RMT_ADDR_LSB,
+ LSB(SourceBuffer)
+ );
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_RMT_ADDR_MSB,
+ MSB(SourceBuffer)
+ );
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_RMT_COUNT_LSB,
+ LSB(BufferLength)
+ );
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_RMT_COUNT_MSB,
+ MSB(BufferLength)
+ );
+
+ //
+ // Set direction (Read)
+ //
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_COMMAND,
+ CR_START | CR_PAGE0 | CR_DMA_READ
+ );
+ //
+ // Repeatedly read from port
+ //
+
+ NdisRawReadPortBufferUchar(
+ Adapter->IoPAddr + NIC_RACK_NIC,
+ TargetBuffer,
+ BufferLength
+ );
+
+ } else {
+
+ //
+ // Else word mode
+ //
+
+ USHORT Tmp;
+
+// NdisRawWritePortUchar( // robin
+// Adapter->IoPAddr + NIC_COMMAND, // robin
+// CR_PAGE0 // robin
+// ); // robin
+
+ //
+ // Avoid transfers to odd addresses
+ //
+
+ if ((ULONG)SourceBuffer & 0x1) {
+
+ //
+ // For odd addresses we need to read previous word and store the
+ // second byte
+ //
+
+ //
+ // Set Count and Source address
+ //
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_RMT_ADDR_LSB,
+ LSB((SourceBuffer - 1))
+ );
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_RMT_ADDR_MSB,
+ MSB((SourceBuffer - 1))
+ );
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_RMT_COUNT_LSB,
+ 0x2
+ );
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_RMT_COUNT_MSB,
+ 0x0
+ );
+
+ //
+ // Set direction (Read)
+ //
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_COMMAND,
+ CR_START | CR_PAGE0 | CR_DMA_READ
+ );
+
+ NdisRawReadPortUshort(
+ Adapter->IoPAddr + NIC_RACK_NIC,
+ &Tmp
+ );
+
+ *TargetBuffer = MSB(Tmp);
+
+ //
+ // Wait for DMA to complete
+ //
+
+ Count = 0xFFFF;
+
+ while (Count) {
+
+ NdisRawReadPortUchar(
+ Adapter->IoPAddr + NIC_INTR_STATUS,
+ &IsrValue
+ );
+
+ if (IsrValue & ISR_DMA_DONE) {
+
+ break;
+
+ } else {
+
+ Count--;
+
+ NdisStallExecution(4);
+
+ }
+
+#if DBG
+ if (!(IsrValue & ISR_DMA_DONE)) {
+
+ DbgPrint("CopyUpDMA didn't finish!");
+
+ }
+#endif // DBG
+
+ }
+
+ SourceBuffer++;
+ TargetBuffer++;
+ BufferLength--;
+ }
+
+ //
+ // Set Count and destination address
+ //
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_RMT_ADDR_LSB,
+ LSB(SourceBuffer)
+ );
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_RMT_ADDR_MSB,
+ MSB(SourceBuffer)
+ );
+
+// NE2000 PCMCIA CHANGE!!! start
+
+// NdisRawWritePortUchar(
+// Adapter->IoPAddr + NIC_RMT_COUNT_LSB,
+// LSB(BufferLength)
+// );
+//
+// NdisRawWritePortUchar(
+// Adapter->IoPAddr + NIC_RMT_COUNT_MSB,
+// MSB(BufferLength)
+// );
+
+ if (BufferLength & 1)
+ {
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_RMT_COUNT_LSB,
+ LSB(BufferLength + 1)
+ );
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_RMT_COUNT_MSB,
+ MSB(BufferLength + 1)
+ );
+ }
+ else
+ {
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_RMT_COUNT_LSB,
+ LSB(BufferLength)
+ );
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_RMT_COUNT_MSB,
+ MSB(BufferLength)
+ );
+ }
+
+// NE2000 PCMCIA CHANGE!!! end
+
+
+ //
+ // Set direction (Read)
+ //
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_COMMAND,
+ CR_START | CR_PAGE0 | CR_DMA_READ
+ );
+
+ //
+ // Read words from port
+ //
+
+ NdisRawReadPortBufferUshort(
+ Adapter->IoPAddr + NIC_RACK_NIC,
+ (PUSHORT)TargetBuffer,
+ (BufferLength >> 1));
+
+ //
+ // Read trailing byte (if necessary)
+ //
+
+ if (BufferLength & 1) {
+
+ TargetBuffer += (BufferLength - 1);
+
+// NE2000 PCMCIA CHANGE!!! start
+
+ //NdisRawReadPortUchar(
+ // Adapter->IoPAddr + NIC_RACK_NIC,
+ // TargetBuffer
+ //);
+
+ NdisRawReadPortUshort(
+ Adapter->IoPAddr + NIC_RACK_NIC,
+ &Tmp
+ );
+
+ *TargetBuffer = LSB(Tmp);
+
+// NE2000 PCMCIA CHANGE!!! end
+ }
+
+ }
+
+ //
+ // Wait for DMA to complete
+ //
+
+ Count = 0xFFFF;
+
+ while (Count) {
+
+ NdisRawReadPortUchar(
+ Adapter->IoPAddr + NIC_INTR_STATUS,
+ &IsrValue
+ );
+
+ if (IsrValue & ISR_DMA_DONE) {
+
+ break;
+
+ } else {
+
+ Count--;
+
+ NdisStallExecution(4);
+
+ }
+
+ }
+
+#if DBG
+ if (!(IsrValue & ISR_DMA_DONE)) {
+
+ DbgPrint("CopyUpDMA didn't finish!\n");
+
+ }
+
+ IF_LOG(Ne2000Log('<');)
+
+#endif // DBG
+
+ return TRUE;
+
+}
+
+ULONG
+CardComputeCrc(
+ IN PUCHAR Buffer,
+ IN UINT Length
+ )
+
+/*++
+
+Routine Description:
+
+ Runs the AUTODIN II CRC algorithm on buffer Buffer of
+ length Length.
+
+Arguments:
+
+ Buffer - the input buffer
+
+ Length - the length of Buffer
+
+Return Value:
+
+ The 32-bit CRC value.
+
+Note:
+
+ This is adapted from the comments in the assembly language
+ version in _GENREQ.ASM of the DWB NE1000/2000 driver.
+
+--*/
+
+{
+ ULONG Crc, Carry;
+ UINT i, j;
+ UCHAR CurByte;
+
+ Crc = 0xffffffff;
+
+ for (i = 0; i < Length; i++) {
+
+ CurByte = Buffer[i];
+
+ for (j = 0; j < 8; j++) {
+
+ Carry = ((Crc & 0x80000000) ? 1 : 0) ^ (CurByte & 0x01);
+
+ Crc <<= 1;
+
+ CurByte >>= 1;
+
+ if (Carry) {
+
+ Crc = (Crc ^ 0x04c11db6) | Carry;
+
+ }
+
+ }
+
+ }
+
+ return Crc;
+
+}
+
+
+VOID
+CardGetMulticastBit(
+ IN UCHAR Address[NE2000_LENGTH_OF_ADDRESS],
+ OUT UCHAR * Byte,
+ OUT UCHAR * Value
+ )
+
+/*++
+
+Routine Description:
+
+ For a given multicast address, returns the byte and bit in
+ the card multicast registers that it hashes to. Calls
+ CardComputeCrc() to determine the CRC value.
+
+Arguments:
+
+ Address - the address
+
+ Byte - the byte that it hashes to
+
+ Value - will have a 1 in the relevant bit
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Crc;
+ UINT BitNumber;
+
+ //
+ // First compute the CRC.
+ //
+
+ Crc = CardComputeCrc(Address, NE2000_LENGTH_OF_ADDRESS);
+
+
+ //
+ // The bit number is now in the 6 most significant bits of CRC.
+ //
+
+ BitNumber = (UINT)((Crc >> 26) & 0x3f);
+
+ *Byte = (UCHAR)(BitNumber / 8);
+ *Value = (UCHAR)((UCHAR)1 << (BitNumber % 8));
+}
+
+VOID
+CardFillMulticastRegs(
+ IN PNE2000_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Erases and refills the card multicast registers. Used when
+ an address has been deleted and all bits must be recomputed.
+
+Arguments:
+
+ Adapter - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UINT i;
+ UCHAR Byte, Bit;
+
+ //
+ // First turn all bits off.
+ //
+
+ for (i=0; i<8; i++) {
+
+ Adapter->NicMulticastRegs[i] = 0;
+
+ }
+
+ //
+ // Now turn on the bit for each address in the multicast list.
+ //
+
+ for ( ; i > 0; ) {
+
+ i--;
+
+ CardGetMulticastBit(Adapter->Addresses[i], &Byte, &Bit);
+
+ Adapter->NicMulticastRegs[Byte] |= Bit;
+
+ }
+
+}
+
+
+
+
+
+
+
+
+BOOLEAN SyncCardStop(
+ IN PVOID SynchronizeContext
+)
+
+/*++
+
+Routine Description:
+
+ Sets the NIC_COMMAND register to stop the card.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ TRUE if the power has failed.
+
+--*/
+
+{
+ PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)SynchronizeContext);
+
+ NdisRawWritePortUchar(
+ Adapter->IoPAddr + NIC_COMMAND,
+ CR_STOP | CR_NO_DMA
+ );
+
+ return(FALSE);
+}
+
+VOID
+CardStartXmit(
+ IN PNE2000_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the NIC_COMMAND register to start a transmission.
+ The transmit buffer number is taken from Adapter->CurBufXmitting
+ and the length from Adapter->PacketLens[Adapter->CurBufXmitting].
+
+Arguments:
+
+ Adapter - pointer to the adapter block
+
+Return Value:
+
+ TRUE if the power has failed.
+
+--*/
+
+{
+ UINT Length = Adapter->PacketLens[Adapter->CurBufXmitting];
+ UCHAR Tmp;
+
+ //
+ // Prepare the NIC registers for transmission.
+ //
+
+ NdisRawWritePortUchar(Adapter->IoPAddr+NIC_XMIT_START,
+ (UCHAR)(Adapter->NicXmitStart + (UCHAR)(Adapter->CurBufXmitting*BUFS_PER_TX)));
+
+ //
+ // Pad the length to 60 (plus CRC will be 64) if needed.
+ //
+
+ if (Length < 60) {
+
+ Length = 60;
+
+ }
+
+ NdisRawWritePortUchar(Adapter->IoPAddr+NIC_XMIT_COUNT_MSB, MSB(Length));
+ NdisRawWritePortUchar(Adapter->IoPAddr+NIC_XMIT_COUNT_LSB, LSB(Length));
+
+ //
+ // Start transmission, check for power failure first.
+ //
+
+ NdisRawReadPortUchar(Adapter->IoPAddr+NIC_COMMAND, &Tmp);
+ NdisRawWritePortUchar(Adapter->IoPAddr+NIC_COMMAND,
+ CR_START | CR_XMIT | CR_NO_DMA);
+
+ IF_LOG( Ne2000Log('x');)
+
+}
+
+BOOLEAN
+SyncCardGetCurrent(
+ IN PVOID SynchronizeContext
+ )
+
+/*++
+
+Routine Description:
+
+ Gets the value of the CURRENT NIC register and stores it in Adapter->Current
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)SynchronizeContext);
+
+ //
+ // Have to go to page 1 to read this register
+ //
+
+ NdisRawWritePortUchar(Adapter->IoPAddr+NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE1);
+
+ NdisRawReadPortUchar(Adapter->IoPAddr+NIC_CURRENT,
+ &Adapter->Current);
+
+ NdisRawWritePortUchar(Adapter->IoPAddr+NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE0);
+
+ return FALSE;
+
+}
+
+BOOLEAN
+SyncCardGetXmitStatus(
+ IN PVOID SynchronizeContext
+ )
+
+/*++
+
+Routine Description:
+
+ Gets the value of the "transmit status" NIC register and stores
+ it in Adapter->XmitStatus.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)SynchronizeContext);
+
+ NdisRawReadPortUchar( Adapter->IoPAddr+NIC_XMIT_STATUS, &Adapter->XmitStatus);
+
+ return FALSE;
+
+}
+
+VOID
+CardSetBoundary(
+ IN PNE2000_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the value of the "boundary" NIC register to one behind
+ Adapter->NicNextPacket, to prevent packets from being received
+ on top of un-indicated ones.
+
+Arguments:
+
+ Adapter - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Have to be careful with "one behind NicNextPacket" when
+ // NicNextPacket is the first buffer in receive area.
+ //
+
+ if (Adapter->NicNextPacket == Adapter->NicPageStart) {
+
+ NdisRawWritePortUchar( Adapter->IoPAddr+NIC_BOUNDARY,
+ (UCHAR)(Adapter->NicPageStop-(UCHAR)1));
+
+ } else {
+
+ NdisRawWritePortUchar( Adapter->IoPAddr+NIC_BOUNDARY,
+ (UCHAR)(Adapter->NicNextPacket-(UCHAR)1));
+
+ }
+
+}
+
+BOOLEAN
+SyncCardSetReceiveConfig(
+ IN PVOID SynchronizeContext
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the value of the "receive configuration" NIC register to
+ the value of Adapter->NicReceiveConfig.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)SynchronizeContext);
+
+ NdisRawWritePortUchar( Adapter->IoPAddr+NIC_RCV_CONFIG, Adapter->NicReceiveConfig);
+
+ return FALSE;
+
+}
+
+BOOLEAN
+SyncCardSetAllMulticast(
+ IN PVOID SynchronizeContext
+ )
+
+/*++
+
+Routine Description:
+
+ Turns on all the bits in the multicast register. Used when
+ the card must receive all multicast packets.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)SynchronizeContext);
+ UINT i;
+
+ //
+ // Have to move to page 1 to set these registers.
+ //
+
+ NdisRawWritePortUchar( Adapter->IoPAddr+NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE1);
+
+ for (i=0; i<8; i++) {
+
+ NdisRawWritePortUchar( Adapter->IoPAddr+(NIC_MC_ADDR+i), 0xff);
+
+ }
+
+ NdisRawWritePortUchar( Adapter->IoPAddr+NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE0);
+
+ return FALSE;
+
+}
+
+BOOLEAN
+SyncCardCopyMulticastRegs(
+ IN PVOID SynchronizeContext
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the eight bytes in the card multicast registers.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)SynchronizeContext);
+ UINT i;
+
+ //
+ // Have to move to page 1 to set these registers.
+ //
+
+ NdisRawWritePortUchar( Adapter->IoPAddr+NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE1);
+
+ for (i=0; i<8; i++) {
+
+ NdisRawWritePortUchar( Adapter->IoPAddr+(NIC_MC_ADDR+i),
+ Adapter->NicMulticastRegs[i]);
+
+ }
+
+ NdisRawWritePortUchar( Adapter->IoPAddr+NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE0);
+
+ return FALSE;
+
+}
+
+BOOLEAN
+SyncCardAcknowledgeOverflow(
+ IN PVOID SynchronizeContext
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the "buffer overflow" bit in the NIC interrupt status register,
+ which re-enables interrupts of that type.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)SynchronizeContext);
+ UCHAR AcknowledgeMask = 0;
+
+ if (Adapter->InterruptStatus & ISR_RCV_ERR) {
+
+ SyncCardUpdateCounters(Adapter);
+
+ }
+
+ return FALSE;
+
+}
+
+BOOLEAN
+SyncCardUpdateCounters(
+ IN PVOID SynchronizeContext
+ )
+
+/*++
+
+Routine Description:
+
+ Updates the values of the three counters (frame alignment errors,
+ CRC errors, and missed packets).
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)SynchronizeContext);
+ UCHAR Tmp;
+
+ NdisRawReadPortUchar( Adapter->IoPAddr+NIC_FAE_ERR_CNTR, &Tmp);
+ Adapter->FrameAlignmentErrors += Tmp;
+
+ NdisRawReadPortUchar( Adapter->IoPAddr+NIC_CRC_ERR_CNTR, &Tmp);
+ Adapter->CrcErrors += Tmp;
+
+ NdisRawReadPortUchar( Adapter->IoPAddr+NIC_MISSED_CNTR, &Tmp);
+ Adapter->MissedPackets += Tmp;
+
+ return FALSE;
+
+}
+
+BOOLEAN
+SyncCardHandleOverflow(
+ IN PVOID SynchronizeContext
+ )
+
+/*++<
+
+Routine Description:
+
+ Sets all the flags for dealing with a receive overflow, stops the card
+ and acknowledges all outstanding interrupts.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)SynchronizeContext);
+ UCHAR Status;
+
+ IF_LOG( Ne2000Log('F');)
+
+ //
+ // Turn on the STOP bit in the Command register.
+ //
+
+ SyncCardStop(Adapter);
+
+ //
+ // Wait for ISR_RESET, but only for 1.6 milliseconds (as
+ // described in the March 1991 8390 addendum), since that
+ // is the maximum time for a software reset to occur.
+ //
+ //
+
+ NdisStallExecution(2000);
+
+ //
+ // Save whether we were transmitting to avoid a timing problem
+ // where an indication resulted in a send.
+ //
+
+ if (!(Adapter->InterruptStatus & (ISR_XMIT | ISR_XMIT_ERR))) {
+
+ CardGetInterruptStatus(Adapter,&Status);
+ if (!(Status & (ISR_XMIT | ISR_XMIT_ERR))) {
+
+ Adapter->OverflowRestartXmitDpc = Adapter->TransmitInterruptPending;
+
+ IF_LOUD( DbgPrint("ORXD=%x\n",Adapter->OverflowRestartXmitDpc); )
+ }
+
+ }
+
+ Adapter->TransmitInterruptPending = FALSE;
+
+ //
+ // Clear the Remote Byte Count register so that ISR_RESET
+ // will come on.
+ //
+
+ NdisRawWritePortUchar( Adapter->IoPAddr+NIC_RMT_COUNT_MSB, 0);
+ NdisRawWritePortUchar( Adapter->IoPAddr+NIC_RMT_COUNT_LSB, 0);
+
+ //
+ // According to National Semiconductor, the next check is necessary
+ // See Step 5. of the overflow process
+ //
+ // NOTE: The setting of variables to check if the transmit has completed
+ // cannot be done here because anything in the ISR has already been ack'ed
+ // inside the main DPC. Thus, the setting of the variables, described in
+ // the Handbook was moved to the main DPC.
+ //
+ // Continued: If you did the check here, you will doubly transmit most
+ // packets that happened to be on the card when the overflow occurred.
+ //
+
+ //
+ // Put the card in loopback mode, then start it.
+ //
+
+ NdisRawWritePortUchar( Adapter->IoPAddr+NIC_XMIT_CONFIG, TCR_LOOPBACK);
+
+ //
+ // Start the card. This does not Undo the loopback mode.
+ //
+
+ NdisRawWritePortUchar( Adapter->IoPAddr+NIC_COMMAND, CR_START | CR_NO_DMA);
+
+ return FALSE;
+
+}
+
diff --git a/private/ntos/ndis/ne2000/interrup.c b/private/ntos/ndis/ne2000/interrup.c
new file mode 100644
index 000000000..25f10cd3f
--- /dev/null
+++ b/private/ntos/ndis/ne2000/interrup.c
@@ -0,0 +1,2126 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ interrup.c
+
+Abstract:
+
+ This is a part of the driver for the National Semiconductor Novell 2000
+ Ethernet controller. It contains the interrupt-handling routines.
+ This driver conforms to the NDIS 3.0 interface.
+
+ The overall structure and much of the code is taken from
+ the Lance NDIS driver by Tony Ercolano.
+
+Author:
+
+ Sean Selitrennikoff (seanse) Dec-1991
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+ Bob Noradki - Apr 93 - added piggyback interrupt code.
+ Jameel Hyder- Dec 94 - Fixed initialization - part of the fixes from JimMcn
+
+--*/
+
+#include <ndis.h>
+#include "ne2000hw.h"
+#include "ne2000sw.h"
+
+//
+// On debug builds tell the compiler to keep the symbols for
+// internal functions, otw throw them out.
+//
+#if DBG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+
+
+INDICATE_STATUS
+Ne2000IndicatePacket(
+ IN PNE2000_ADAPTER Adapter
+ );
+
+VOID
+Ne2000DoNextSend(
+ PNE2000_ADAPTER Adapter
+ );
+
+
+
+//
+// This is used to pad short packets.
+//
+static UCHAR BlankBuffer[60] = " ";
+
+
+
+VOID
+Ne2000EnableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to turn on the interrupt mask.
+
+Arguments:
+
+ Context - The adapter for the NE2000 to start.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNE2000_ADAPTER Adapter = (PNE2000_ADAPTER)(MiniportAdapterContext);
+
+ IF_LOG( Ne2000Log('P'); )
+
+ CardUnblockInterrupts(Adapter);
+
+}
+
+VOID
+Ne2000DisableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to turn off the interrupt mask.
+
+Arguments:
+
+ Context - The adapter for the NE2000 to start.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNE2000_ADAPTER Adapter = (PNE2000_ADAPTER)(MiniportAdapterContext);
+
+ IF_LOG( Ne2000Log('p'); )
+
+ CardBlockInterrupts(Adapter);
+
+}
+
+VOID
+Ne2000Isr(
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueDpc,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This is the interrupt handler which is registered with the operating
+ system. If several are pending (i.e. transmit complete and receive),
+ handle them all. Block new interrupts until all pending interrupts
+ are handled.
+
+Arguments:
+
+ InterruptRecognized - Boolean value which returns TRUE if the
+ ISR recognizes the interrupt as coming from this adapter.
+
+ QueueDpc - TRUE if a DPC should be queued.
+
+ Context - pointer to the adapter object
+
+Return Value:
+
+ None.
+--*/
+
+{
+ PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)Context);
+
+ IF_LOUD( DbgPrint("In Ne2000ISR\n");)
+
+ IF_LOG( Ne2000Log('i'); )
+
+ IF_VERY_LOUD( DbgPrint( "Ne2000InterruptHandler entered\n" );)
+
+ //
+ // Force the INT signal from the chip low. When all
+ // interrupts are acknowledged interrupts will be unblocked,
+ //
+ CardBlockInterrupts(Adapter);
+
+ IF_LOG( Ne2000Log('I'); )
+
+ *InterruptRecognized = TRUE;
+ *QueueDpc = TRUE;
+
+ return;
+}
+
+
+VOID
+Ne2000HandleInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+/*++
+
+Routine Description:
+
+ This is the defered processing routine for interrupts. It
+ reads from the Interrupt Status Register any outstanding
+ interrupts and handles them.
+
+Arguments:
+
+ MiniportAdapterContext - a handle to the adapter block.
+
+Return Value:
+
+ NONE.
+
+--*/
+{
+ //
+ // The adapter to process
+ //
+ PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)MiniportAdapterContext);
+
+ //
+ // The most recent port value read.
+ //
+ UCHAR InterruptStatus;
+
+ //
+ // The interrupt type currently being processed.
+ //
+ INTERRUPT_TYPE InterruptType;
+
+ IF_LOUD( DbgPrint("==>IntDpc\n");)
+ IF_LOG( Ne2000Log('d'); )
+
+ //
+ // Get the interrupt bits and save them.
+ //
+ CardGetInterruptStatus(Adapter, &InterruptStatus);
+ Adapter->InterruptStatus |= InterruptStatus;
+
+ if (InterruptStatus != ISR_EMPTY) {
+
+ //
+ // Acknowledge the interrupts
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr+NIC_INTR_STATUS,
+ InterruptStatus
+ );
+
+ }
+
+ //
+ // Return the type of the most important interrupt waiting on the card.
+ // Order of importance is COUNTER, OVERFLOW, TRANSMIT,and RECEIVE.
+ //
+ InterruptType = CARD_GET_INTERRUPT_TYPE(Adapter, Adapter->InterruptStatus);
+
+ //
+ // InterruptType is used to dispatch to correct DPC and are then cleared
+ //
+ while (InterruptType != UNKNOWN) {
+
+ //
+ // Handle the interrupts
+ //
+
+ switch (InterruptType) {
+
+ case COUNTER:
+
+ //
+ // One of the counters' MSB has been set, read in all
+ // the values just to be sure (and then exit below).
+ //
+
+ IF_LOUD( DbgPrint("DPC got COUNTER\n");)
+
+ SyncCardUpdateCounters((PVOID)Adapter);
+
+ //
+ // Clear the COUNTER interrupt bit
+ //
+ Adapter->InterruptStatus &= ~ISR_COUNTER;
+
+ break;
+
+ case OVERFLOW:
+
+ //
+ // Overflow interrupts are handled as part of a receive interrupt,
+ // so set a flag and then pretend to be a receive, in case there
+ // is no receive already being handled.
+ //
+ Adapter->BufferOverflow = TRUE;
+
+ IF_LOUD( DbgPrint("Overflow Int\n"); )
+ IF_VERY_LOUD( DbgPrint(" overflow interrupt\n"); )
+
+ //
+ // Clear the OVERFLOW interrupt bit
+ //
+ Adapter->InterruptStatus &= ~ISR_OVERFLOW;
+
+ case RECEIVE:
+
+ IF_LOG( Ne2000Log('R'); )
+ IF_LOUD( DbgPrint("DPC got RCV\n"); )
+
+ //
+ // For receives, call this to handle the receive
+ //
+ if (Ne2000RcvDpc(Adapter)) {
+
+ //
+ // Clear the RECEIVE interrupt bits
+ //
+ Adapter->InterruptStatus &= ~(ISR_RCV | ISR_RCV_ERR);
+
+ }
+
+ IF_LOG( Ne2000Log('r'); )
+
+ if (!(Adapter->InterruptStatus & (ISR_XMIT | ISR_XMIT_ERR)))
+ break;
+
+ case TRANSMIT:
+
+ IF_LOG( Ne2000Log('X'); )
+
+ ASSERT(!Adapter->OverflowRestartXmitDpc);
+
+ //
+ // Get the status of the transmit
+ //
+ SyncCardGetXmitStatus((PVOID)Adapter);
+
+ //
+ // We are no longer expecting an interrupts, as
+ // we just got it.
+ //
+ Adapter->TransmitInterruptPending = FALSE;
+
+ IF_LOUD( DbgPrint( "DPC got XMIT\n"); )
+
+ //
+ // Handle transmit errors
+ //
+ if (Adapter->InterruptStatus & ISR_XMIT_ERR) {
+
+ OctogmetusceratorRevisited(Adapter);
+
+ }
+
+ //
+ // Handle the transmit
+ //
+ if (Adapter->InterruptStatus & ISR_XMIT) {
+
+ Ne2000XmitDpc(Adapter);
+
+ }
+
+ //
+ // Clear the TRANSMIT interrupt bits
+ //
+ Adapter->InterruptStatus &= ~(ISR_XMIT | ISR_XMIT_ERR);
+
+ break;
+
+ default:
+
+ IF_LOUD( DbgPrint("unhandled interrupt type: %x\n", InterruptType); )
+
+ break;
+
+ }
+
+ //
+ // Get any new interrupts
+ //
+ CardGetInterruptStatus(Adapter, &InterruptStatus);
+
+ if (InterruptStatus != ISR_EMPTY) {
+
+ //
+ // Acknowledge the interrupt
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr+NIC_INTR_STATUS,
+ InterruptStatus
+ );
+ }
+
+ //
+ // Save the interrupt reasons
+ //
+ Adapter->InterruptStatus |= InterruptStatus;
+
+ //
+ // Get next interrupt to process
+ //
+ InterruptType = CARD_GET_INTERRUPT_TYPE(Adapter, Adapter->InterruptStatus);
+
+ }
+
+ IF_LOG( Ne2000Log('D'); )
+
+ IF_LOUD( DbgPrint("<==IntDpc\n"); )
+
+}
+
+
+BOOLEAN
+Ne2000RcvDpc(
+ IN PNE2000_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This is the real interrupt handler for receive/overflow interrupt.
+
+ Called when a receive interrupt is received. It first indicates
+ all packets on the card and finally indicates ReceiveComplete().
+
+Arguments:
+
+ Adapter - Pointer to the adapter block.
+
+Return Value:
+
+ TRUE if done with all receives, else FALSE.
+
+--*/
+
+{
+ //
+ // Use to restart a transmit if a buffer overflow occured
+ // during a transmission
+ //
+ BOOLEAN TransmitInterruptWasPending = FALSE;
+
+ //
+ // Status of a received packet.
+ //
+ INDICATE_STATUS IndicateStatus = INDICATE_OK;
+
+ //
+ // Flag to tell when the receive process is complete
+ //
+ BOOLEAN Done = TRUE;
+
+ IF_LOUD( DbgPrint( "Ne2000RcvDpc entered\n" );)
+
+ //
+ // Default to not indicating NdisMEthIndicateReceiveComplete
+ //
+ Adapter->IndicateReceiveDone = FALSE;
+
+ //
+ // At this point, receive interrupts are disabled.
+ //
+ SyncCardGetCurrent((PVOID)Adapter);
+
+ //
+ // Handle a buffer overflow
+ //
+ if (Adapter->BufferOverflow) {
+
+ SyncCardHandleOverflow(Adapter);
+
+#if DBG
+ if (Adapter->OverflowRestartXmitDpc) {
+
+ IF_LOG( Ne2000Log('O');)
+ IF_LOUD( DbgPrint ("Adapter->OverflowRestartXmitDpc set:RcvDpc\n"); )
+
+ }
+#endif // DBG
+
+ }
+
+ //
+ // Loop
+ //
+ while (TRUE)
+ {
+ if ((Adapter->InterruptStatus & ISR_RCV_ERR) &&
+ !Adapter->BufferOverflow
+ )
+ {
+ IF_LOUD( DbgPrint ("RCV_ERR, IR=%x\n",Adapter->InterruptStatus); )
+
+ //
+ // Skip this packet
+ //
+
+ SyncCardGetCurrent((PVOID)Adapter);
+
+ Adapter->NicNextPacket = Adapter->Current;
+
+ CardSetBoundary(Adapter);
+
+ break;
+
+ }
+
+ if (Adapter->Current == Adapter->NicNextPacket) {
+
+ //
+ // Acknowledge previous packet before the check for new ones,
+ // then read in the Current register.
+ // The card register Current used to point to
+ // the end of the packet just received; read
+ // the new value off the card and see if it
+ // still does.
+ //
+ // This will store the value in Adapter->Current and acknowledge
+ // the receive interrupt.
+ //
+ //
+
+ SyncCardGetCurrent((PVOID)Adapter);
+
+ if (Adapter->Current == Adapter->NicNextPacket) {
+
+ //
+ // End of Loop -- no more packets
+ //
+
+ break;
+ }
+
+ }
+
+ //
+ // A packet was found on the card, indicate it.
+ //
+
+ Adapter->ReceivePacketCount++;
+
+ //
+ // Verify packet is not corrupt
+ //
+ if (Ne2000PacketOK(Adapter)) {
+
+ ULONG PacketLen;
+
+ PacketLen = (Adapter->PacketHeader[2]) + ((Adapter->PacketHeader[3])*256) - 4;
+
+ PacketLen = (PacketLen < Adapter->MaxLookAhead)?
+ PacketLen :
+ Adapter->MaxLookAhead;
+
+ //
+ // Copy up the lookahead data
+ //
+ if (!CardCopyUp(Adapter,
+ Adapter->Lookahead,
+ Adapter->PacketHeaderLoc,
+ PacketLen + NE2000_HEADER_SIZE
+ )) {
+
+ //
+ // Failed! Skip this packet
+ //
+ IndicateStatus = SKIPPED;
+
+ } else {
+
+ //
+ // Indicate the packet to the wrapper
+ //
+ IndicateStatus = Ne2000IndicatePacket(Adapter);
+
+ if (IndicateStatus != CARD_BAD) {
+
+ Adapter->FramesRcvGood++;
+
+ }
+
+ }
+
+ } else {
+
+ //
+ // Packet is corrupt, skip it.
+ //
+ IF_LOUD( DbgPrint("Packet did not pass OK check\n"); )
+
+ IndicateStatus = SKIPPED;
+
+ }
+
+ //
+ // Handle when the card is unable to indicate good packets
+ //
+ if (IndicateStatus == CARD_BAD) {
+
+#if DBG
+
+ IF_NE2000DEBUG( NE2000_DEBUG_CARD_BAD ) {
+
+ DbgPrint("R: <%x %x %x %x> C %x N %x\n",
+ Adapter->PacketHeader[0],
+ Adapter->PacketHeader[1],
+ Adapter->PacketHeader[2],
+ Adapter->PacketHeader[3],
+ Adapter->Current,
+ Adapter->NicNextPacket);
+
+ }
+#endif
+
+ IF_LOG( Ne2000Log('W');)
+
+ //
+ // Start off with receive interrupts disabled.
+ //
+
+ Adapter->NicInterruptMask = IMR_XMIT | IMR_XMIT_ERR | IMR_OVERFLOW;
+
+ //
+ // Reset the adapter
+ //
+ CardReset(Adapter);
+
+ //
+ // Since the adapter was just reset, stop indicating packets.
+ //
+
+ break;
+
+ }
+
+ //
+ // (IndicateStatus == SKIPPED) is OK, just move to next packet.
+ //
+ if (IndicateStatus == SKIPPED) {
+
+ SyncCardGetCurrent((PVOID)Adapter);
+
+ Adapter->NicNextPacket = Adapter->Current;
+
+ } else {
+
+ //
+ // Free the space used by packet on card.
+ //
+
+ Adapter->NicNextPacket = Adapter->PacketHeader[1];
+
+ }
+
+ //
+ // This will set BOUNDARY to one behind NicNextPacket.
+ //
+ CardSetBoundary(Adapter);
+
+ if (Adapter->ReceivePacketCount > 10) {
+
+ //
+ // Give transmit interrupts a chance
+ //
+ Done = FALSE;
+ Adapter->ReceivePacketCount = 0;
+ break;
+
+ }
+
+ }
+
+ //
+ // See if a buffer overflow occured previously.
+ //
+ if (Adapter->BufferOverflow) {
+
+ //
+ // ... and set a flag to restart the card after receiving
+ // a packet.
+ //
+ Adapter->BufferOverflow = FALSE;
+
+ SyncCardAcknowledgeOverflow(Adapter);
+
+ //
+ // Undo loopback mode
+ //
+ CardStart(Adapter);
+
+ IF_LOG( Ne2000Log('f'); )
+
+ //
+ // Check if transmission needs to be queued or not
+ //
+ if (Adapter->OverflowRestartXmitDpc && Adapter->CurBufXmitting != -1) {
+
+ IF_LOUD( DbgPrint("queueing xmit in RcvDpc\n"); )
+
+ Adapter->OverflowRestartXmitDpc = FALSE;
+
+ Adapter->TransmitInterruptPending = TRUE;
+
+ IF_LOG( Ne2000Log('5'); )
+
+ CardStartXmit(Adapter);
+
+ }
+ }
+
+ //
+ // Finally, indicate ReceiveComplete to all protocols which received packets
+ //
+ if (Adapter->IndicateReceiveDone) {
+
+ NdisMEthIndicateReceiveComplete(Adapter->MiniportAdapterHandle);
+
+ Adapter->IndicateReceiveDone = FALSE;
+
+ }
+
+ IF_LOUD( DbgPrint( "Ne2000RcvDpc exiting\n" );)
+
+ return (Done);
+
+}
+
+
+VOID
+Ne2000XmitDpc(
+ IN PNE2000_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This is the real interrupt handler for a transmit complete interrupt.
+ Ne2000Dpc queues a call to it.
+
+ Called after a transmit complete interrupt. It checks the
+ status of the transmission, completes the send if needed,
+ and sees if any more packets are ready to be sent.
+
+Arguments:
+
+ Adapter - Pointer to the adapter block.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Packet that was transmitted
+ //
+ PNDIS_PACKET Packet;
+
+ //
+ // Status of the send
+ //
+ NDIS_STATUS Status;
+
+ //
+ // Length of the packet sent
+ //
+ ULONG Len;
+
+ //
+ // Temporary loopnig variable
+ //
+ UINT i;
+
+ IF_VERY_LOUD( DbgPrint( "Ne2000XmitDpc entered\n" );)
+
+ //
+ // Verify that we are transmitting a packet
+ //
+ if ( Adapter->CurBufXmitting == -1 ) {
+
+#if DBG
+ DbgPrint( "Ne2000HandleXmitComplete called with nothing transmitting!\n" );
+#endif
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 1,
+ NE2000_ERRMSG_HANDLE_XMIT_COMPLETE
+ );
+
+ return;
+ }
+
+ IF_LOG( Ne2000Log('C');)
+
+ //
+ // Get the status of the transmit
+ //
+ SyncCardGetXmitStatus((PVOID)Adapter);
+
+ //
+ // Statistics
+ //
+ if (Adapter->XmitStatus & TSR_XMIT_OK) {
+
+ Adapter->FramesXmitGood++;
+ Status = NDIS_STATUS_SUCCESS;
+
+ } else {
+
+ Adapter->FramesXmitBad++;
+ Status = NDIS_STATUS_FAILURE;
+
+ }
+
+ //
+ // Mark the current transmit as done.
+ //
+ Len = (Adapter->PacketLens[Adapter->CurBufXmitting] + 255) >> 8;
+
+ ASSERT (Len != 0);
+
+ //
+ // Free the transmit buffers
+ //
+ for (i = Adapter->CurBufXmitting; i < Adapter->CurBufXmitting + Len; i++) {
+
+ Adapter->BufferStatus[i] = EMPTY;
+
+ }
+
+ //
+ // Set the next buffer to start transmitting.
+ //
+ Adapter->NextBufToXmit += Len;
+
+ if (Adapter->NextBufToXmit == MAX_XMIT_BUFS) {
+
+ Adapter->NextBufToXmit = 0;
+
+ }
+
+ if (Adapter->BufferStatus[Adapter->NextBufToXmit] == EMPTY &&
+ Adapter->NextBufToFill != Adapter->NextBufToXmit) {
+
+ Adapter->NextBufToXmit = 0;
+
+ }
+
+ //
+ // Remove the packet from the outstanding packet list.
+ //
+ Packet = Adapter->Packets[Adapter->CurBufXmitting];
+ Adapter->Packets[Adapter->CurBufXmitting] = (PNDIS_PACKET)NULL;
+
+ //
+ // See what to do next.
+ //
+
+ switch (Adapter->BufferStatus[Adapter->NextBufToXmit]) {
+
+
+ case FULL:
+
+ //
+ // The next packet is ready to go -- only happens with
+ // more than one transmit buffer.
+ //
+
+ IF_LOUD( DbgPrint( " next packet ready to go\n" );)
+
+ //
+ // Start the transmission and check for more.
+ //
+
+ Adapter->CurBufXmitting = Adapter->NextBufToXmit;
+
+ IF_LOG( Ne2000Log('2');)
+
+ //
+ // This is used to check if stopping the chip prevented
+ // a transmit complete interrupt from coming through (it
+ // is cleared in the ISR if a transmit DPC is queued).
+ //
+
+ Adapter->TransmitInterruptPending = TRUE;
+
+ IF_LOG( Ne2000Log('6'); )
+ CardStartXmit(Adapter);
+
+ break;
+
+ case EMPTY:
+
+ //
+ // No packet is ready to transmit.
+ //
+
+ IF_LOUD( DbgPrint( " next packet empty\n" );)
+
+ Adapter->CurBufXmitting = (XMIT_BUF)-1;
+
+ break;
+
+ }
+
+ //
+ // Start next send
+ //
+
+ Ne2000DoNextSend(Adapter);
+
+ IF_VERY_LOUD( DbgPrint( "Ne2000XmitDpc exiting\n" );)
+
+}
+
+
+BOOLEAN
+Ne2000PacketOK(
+ IN PNE2000_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Reads a packet off the card -- checking if the CRC is good. This is
+ a workaround for a bug where bytes in the data portion of the packet
+ are shifted either left or right by two in some weird 8390 cases.
+
+ This routine is a combination of Ne2000TransferData (to copy up data
+ from the card), CardCalculateCrc and CardCalculatePacketCrc.
+
+Arguments:
+
+ Adapter - pointer to the adapter block.
+
+Return Value:
+
+ TRUE if the packet seems ok, else false.
+
+--*/
+
+{
+
+ //
+ // Length of the packet
+ //
+ UINT PacketLen;
+
+ //
+ // Guess at where the packet is located
+ //
+ PUCHAR PacketLoc;
+
+ //
+ // Header Validation Variables
+ //
+ BOOLEAN FrameAlign;
+ PUCHAR PacketRcvStatus;
+ PUCHAR NextPacket;
+ PUCHAR PacketLenLo;
+ PUCHAR PacketLenHi;
+ PUCHAR ReceiveDestAddrLo;
+ UINT FrameAlignCount;
+ UCHAR OldPacketLenHi;
+ UCHAR TempPacketHeader[6];
+ PUCHAR BeginPacketHeader;
+
+ //
+ // First copy up the four-byte header the card attaches
+ // plus first two bytes of the data packet (which contain
+ // the destination address of the packet). We use the extra
+ // two bytes in case the packet was shifted right 1 or 2 bytes
+ //
+ PacketLoc = Adapter->PageStart +
+ 256*(Adapter->NicNextPacket-Adapter->NicPageStart);
+
+ if (!CardCopyUp(Adapter, TempPacketHeader, PacketLoc, 6)) {
+
+ return FALSE;
+
+ }
+ PacketLoc += 4;
+
+ //
+ // Validate the header
+ //
+ FrameAlignCount = 0;
+ BeginPacketHeader = TempPacketHeader;
+
+ //
+ // Sometimes the Ne2000 will misplace a packet and shift the
+ // entire packet and header by a byte, either up by 1 or 2 bytes.
+ // This loop will look for the packet in the expected place,
+ // and then shift up in an effort to find the packet.
+ //
+ do {
+
+ //
+ // Set where we think the packet is
+ //
+ PacketRcvStatus = BeginPacketHeader;
+ NextPacket = BeginPacketHeader + 1;
+ PacketLenLo = BeginPacketHeader + 2;
+ PacketLenHi = BeginPacketHeader + 3;
+ OldPacketLenHi = *PacketLenHi;
+ ReceiveDestAddrLo = BeginPacketHeader + 4;
+ FrameAlign = FALSE;
+
+ //
+ // Check if the status makes sense as is.
+ //
+ if (*PacketRcvStatus & 0x05E){
+
+ FrameAlign = TRUE;
+
+ } else if ((*PacketRcvStatus & RSR_MULTICAST) // If a multicast packet
+ && (!FrameAlignCount) // and hasn't been aligned
+ && !(*ReceiveDestAddrLo & 1) // and lsb is set on dest addr
+ ){
+
+ FrameAlign = TRUE;
+
+ } else {
+
+ //
+ // Compare high and low address bytes. If the same, the low
+ // byte may have been copied into the high byte.
+ //
+
+ if (*PacketLenLo == *PacketLenHi){
+
+ //
+ // Save the old packetlenhi
+ //
+ OldPacketLenHi = *PacketLenHi;
+
+ //
+ // Compute new packet length
+ //
+ *PacketLenHi = *NextPacket - Adapter->NicNextPacket - 1;
+
+ if (*PacketLenHi < 0) {
+
+ *PacketLenHi = (Adapter->NicPageStop - Adapter->NicNextPacket) +
+ (*NextPacket - Adapter->NicPageStart) - 1;
+
+ }
+
+ if (*PacketLenLo > 0xFC) {
+
+ *PacketLenHi++;
+ }
+
+ }
+
+ PacketLen = (*PacketLenLo) + ((*PacketLenHi)*256) - 4;
+
+ //
+ // Does it make sense?
+ //
+ if ((PacketLen > 1514) || (PacketLen < 60)){
+
+ //
+ // Bad length. Restore the old packetlenhi
+ //
+ *PacketLenHi = OldPacketLenHi;
+
+ FrameAlign = TRUE;
+
+ }
+
+ //
+ // Did we recover the frame?
+ //
+ if (!FrameAlign && ((*NextPacket < Adapter->NicPageStart) ||
+ (*NextPacket > Adapter->NicPageStop))) {
+
+ IF_LOUD( DbgPrint ("Packet address invalid in HeaderValidation\n"); )
+
+ FrameAlign = TRUE;
+
+ }
+
+ }
+
+ //
+ // FrameAlignment - if first time through, shift packetheader right 1 or 2 bytes.
+ // If second time through, shift it back to where it was and let it through.
+ // This compensates for a known bug in the 8390D chip.
+ //
+ if (FrameAlign){
+
+ switch (FrameAlignCount){
+
+ case 0:
+
+ BeginPacketHeader++;
+ PacketLoc++;
+ if (!Adapter->EightBitSlot){
+
+ BeginPacketHeader++;
+ PacketLoc++;
+
+ }
+ break;
+
+ case 1:
+
+ BeginPacketHeader--;
+ PacketLoc--;
+ if (!Adapter->EightBitSlot){
+ BeginPacketHeader--;
+ PacketLoc--;
+ }
+ break;
+
+ }
+
+ FrameAlignCount++;
+
+ }
+
+ } while ( (FrameAlignCount < 2) && FrameAlign );
+
+ //
+ // Now grab the packet header information
+ //
+ Adapter->PacketHeader[0] = *BeginPacketHeader;
+ BeginPacketHeader++;
+ Adapter->PacketHeader[1] = *BeginPacketHeader;
+ BeginPacketHeader++;
+ Adapter->PacketHeader[2] = *BeginPacketHeader;
+ BeginPacketHeader++;
+ Adapter->PacketHeader[3] = *BeginPacketHeader;
+
+ //
+ // Packet length is in bytes 3 and 4 of the header.
+ //
+ Adapter->PacketHeaderLoc = PacketLoc;
+ PacketLen = (Adapter->PacketHeader[2]) + ((Adapter->PacketHeader[3])*256) - 4;
+
+ //
+ // Sanity check the packet
+ //
+ if ((PacketLen > 1514) || (PacketLen < 60)){
+
+ if ((Adapter->PacketHeader[1] < Adapter->NicPageStart) ||
+ (Adapter->PacketHeader[1] > Adapter->NicPageStop)) {
+
+ //
+ // Return TRUE here since IndicatePacket will notice the error
+ // and handle it correctly.
+ //
+ return(TRUE);
+
+ }
+
+ return(FALSE);
+
+ }
+
+ return(TRUE);
+}
+
+
+INDICATE_STATUS
+Ne2000IndicatePacket(
+ IN PNE2000_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Indicates the first packet on the card to the protocols.
+
+ NOTE: For MP, non-x86 architectures, this assumes that the packet has been
+ read from the card and into Adapter->PacketHeader and Adapter->Lookahead.
+
+ NOTE: For UP x86 systems this assumes that the packet header has been
+ read into Adapter->PacketHeader and the minimal lookahead stored in
+ Adapter->Lookahead
+
+Arguments:
+
+ Adapter - pointer to the adapter block.
+
+Return Value:
+
+ CARD_BAD if the card should be reset;
+ INDICATE_OK otherwise.
+
+--*/
+
+{
+ //
+ // Length of the packet
+ //
+ UINT PacketLen;
+
+ //
+ // Length of the lookahead buffer
+ //
+ UINT IndicateLen;
+
+ //
+ // Variables for checking if the packet header looks valid
+ //
+ UCHAR PossibleNextPacket1, PossibleNextPacket2;
+
+ //
+ // Check if the next packet byte agress with the length, as
+ // described on p. A-3 of the Etherlink II Technical Reference.
+ // The start of the packet plus the MSB of the length must
+ // be equal to the start of the next packet minus one or two.
+ // Otherwise the header is considered corrupted, and the
+ // card must be reset.
+ //
+
+ PossibleNextPacket1 =
+ Adapter->NicNextPacket + Adapter->PacketHeader[3] + (UCHAR)1;
+
+ if (PossibleNextPacket1 >= Adapter->NicPageStop) {
+
+ PossibleNextPacket1 -= (Adapter->NicPageStop - Adapter->NicPageStart);
+
+ }
+
+ if (PossibleNextPacket1 != Adapter->PacketHeader[1]) {
+
+ PossibleNextPacket2 = PossibleNextPacket1+(UCHAR)1;
+
+ if (PossibleNextPacket2 == Adapter->NicPageStop) {
+
+ PossibleNextPacket2 = Adapter->NicPageStart;
+
+ }
+
+ if (PossibleNextPacket2 != Adapter->PacketHeader[1]) {
+
+ IF_LOUD( DbgPrint("First CARD_BAD check failed\n"); )
+ return SKIPPED;
+ }
+
+ }
+
+ //
+ // Check that the Next is valid
+ //
+ if ((Adapter->PacketHeader[1] < Adapter->NicPageStart) ||
+ (Adapter->PacketHeader[1] > Adapter->NicPageStop)) {
+
+ IF_LOUD( DbgPrint("Second CARD_BAD check failed\n"); )
+ return(SKIPPED);
+
+ }
+
+ //
+ // Sanity check the length
+ //
+ PacketLen = Adapter->PacketHeader[2] + Adapter->PacketHeader[3]*256 - 4;
+
+ if (PacketLen > 1514) {
+ IF_LOUD( DbgPrint("Third CARD_BAD check failed\n"); )
+ return(SKIPPED);
+
+ }
+
+#if DBG
+
+ IF_NE2000DEBUG( NE2000_DEBUG_WORKAROUND1 ) {
+ //
+ // Now check for the high order 2 bits being set, as described
+ // on page A-2 of the Etherlink II Technical Reference. If either
+ // of the two high order bits is set in the receive status byte
+ // in the packet header, the packet should be skipped (but
+ // the adapter does not need to be reset).
+ //
+
+ if (Adapter->PacketHeader[0] & (RSR_DISABLED|RSR_DEFERRING)) {
+
+ IF_LOUD (DbgPrint("H");)
+
+ return SKIPPED;
+
+ }
+
+ }
+
+#endif
+
+ //
+ // Lookahead amount to indicate
+ //
+ IndicateLen = (PacketLen > (Adapter->MaxLookAhead + NE2000_HEADER_SIZE)) ?
+ (Adapter->MaxLookAhead + NE2000_HEADER_SIZE) :
+ PacketLen;
+
+ //
+ // Indicate packet
+ //
+
+ Adapter->PacketLen = PacketLen;
+
+ if (IndicateLen < NE2000_HEADER_SIZE) {
+
+ //
+ // Runt Packet
+ //
+
+ NdisMEthIndicateReceive(
+ Adapter->MiniportAdapterHandle,
+ (NDIS_HANDLE)Adapter,
+ (PCHAR)(Adapter->Lookahead),
+ IndicateLen,
+ NULL,
+ 0,
+ 0
+ );
+
+ } else {
+
+ NdisMEthIndicateReceive(
+ Adapter->MiniportAdapterHandle,
+ (NDIS_HANDLE)Adapter,
+ (PCHAR)(Adapter->Lookahead),
+ NE2000_HEADER_SIZE,
+ (PCHAR)(Adapter->Lookahead) + NE2000_HEADER_SIZE,
+ IndicateLen - NE2000_HEADER_SIZE,
+ PacketLen - NE2000_HEADER_SIZE
+ );
+
+ }
+
+ Adapter->IndicateReceiveDone = TRUE;
+
+ return INDICATE_OK;
+}
+
+
+NDIS_STATUS
+Ne2000TransferData(
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+ )
+
+/*++
+
+Routine Description:
+
+ A protocol calls the Ne2000TransferData request (indirectly via
+ NdisTransferData) from within its Receive event handler
+ to instruct the driver to copy the contents of the received packet
+ a specified packet buffer.
+
+Arguments:
+
+ MiniportAdapterContext - Context registered with the wrapper, really
+ a pointer to the adapter.
+
+ MiniportReceiveContext - The context value passed by the driver on its call
+ to NdisMEthIndicateReceive. The driver can use this value to determine
+ which packet, on which adapter, is being received.
+
+ ByteOffset - An unsigned integer specifying the offset within the
+ received packet at which the copy is to begin. If the entire packet
+ is to be copied, ByteOffset must be zero.
+
+ BytesToTransfer - An unsigned integer specifying the number of bytes
+ to copy. It is legal to transfer zero bytes; this has no effect. If
+ the sum of ByteOffset and BytesToTransfer is greater than the size
+ of the received packet, then the remainder of the packet (starting from
+ ByteOffset) is transferred, and the trailing portion of the receive
+ buffer is not modified.
+
+ Packet - A pointer to a descriptor for the packet storage into which
+ the MAC is to copy the received packet.
+
+ BytesTransfered - A pointer to an unsigned integer. The MAC writes
+ the actual number of bytes transferred into this location. This value
+ is not valid if the return status is STATUS_PENDING.
+
+Notes:
+
+ - The MacReceiveContext will be a pointer to the open block for
+ the packet.
+
+--*/
+
+{
+ //
+ // Variables for the number of bytes to copy, how much can be
+ // copied at this moment, and the total number of bytes to copy.
+ //
+ UINT BytesLeft, BytesNow, BytesWanted;
+
+ //
+ // Current NDIS_BUFFER to copy into
+ //
+ PNDIS_BUFFER CurBuffer;
+
+ //
+ // Virtual address of the buffer.
+ //
+ XMIT_BUF NextBufToXmit;
+ PUCHAR BufStart;
+
+ //
+ // Length and offset into the buffer.
+ //
+ UINT BufLen, BufOff;
+
+ //
+ // The adapter to transfer from.
+ //
+ PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)MiniportReceiveContext);
+
+ IF_LOG( Ne2000Log('t');)
+
+ //
+ // Add the packet header onto the offset.
+ //
+ ByteOffset += NE2000_HEADER_SIZE;
+
+ //
+ // See how much data there is to transfer.
+ //
+ if (ByteOffset+BytesToTransfer > Adapter->PacketLen) {
+
+ if (Adapter->PacketLen < ByteOffset) {
+
+ *BytesTransferred = 0;
+ IF_LOG( Ne2000Log('T');)
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ BytesWanted = Adapter->PacketLen - ByteOffset;
+
+ } else {
+
+ BytesWanted = BytesToTransfer;
+
+ }
+
+ //
+ // Set the number of bytes left to transfer
+ //
+ BytesLeft = BytesWanted;
+
+ {
+
+ //
+ // Address on the adapter to copy from
+ //
+ PUCHAR CurCardLoc;
+
+ //
+ // Copy data from the card -- it is not completely stored in the
+ // adapter structure.
+ //
+ // Determine where the copying should start.
+ //
+ CurCardLoc = Adapter->PacketHeaderLoc + ByteOffset;
+
+ if (CurCardLoc > Adapter->PageStop) {
+
+ CurCardLoc = CurCardLoc - (Adapter->PageStop - Adapter->PageStart);
+
+ }
+
+ //
+ // Get location to copy into
+ //
+ NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, NULL);
+
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufStart, &BufLen);
+
+ BufOff = 0;
+
+ //
+ // Loop, filling each buffer in the packet until there
+ // are no more buffers or the data has all been copied.
+ //
+ while (BytesLeft > 0) {
+
+ //
+ // See how much data to read into this buffer.
+ //
+
+ if ((BufLen-BufOff) > BytesLeft) {
+
+ BytesNow = BytesLeft;
+
+ } else {
+
+ BytesNow = (BufLen - BufOff);
+
+ }
+
+ //
+ // See if the data for this buffer wraps around the end
+ // of the receive buffers (if so filling this buffer
+ // will use two iterations of the loop).
+ //
+
+ if (CurCardLoc + BytesNow > Adapter->PageStop) {
+
+ BytesNow = Adapter->PageStop - CurCardLoc;
+
+ }
+
+ //
+ // Copy up the data.
+ //
+
+ if (!CardCopyUp(Adapter, BufStart+BufOff, CurCardLoc, BytesNow)) {
+
+ *BytesTransferred = BytesWanted - BytesLeft;
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 1,
+ 0x2
+ );
+
+ return(NDIS_STATUS_FAILURE);
+
+ }
+
+ //
+ // Update offsets and counts
+ //
+ CurCardLoc += BytesNow;
+ BytesLeft -= BytesNow;
+
+ //
+ // Is the transfer done now?
+ //
+ if (BytesLeft == 0) {
+
+ break;
+
+ }
+
+ //
+ // Wrap around the end of the receive buffers?
+ //
+ if (CurCardLoc == Adapter->PageStop) {
+
+ CurCardLoc = Adapter->PageStart;
+
+ }
+
+ //
+ // Was the end of this packet buffer reached?
+ //
+ BufOff += BytesNow;
+
+ if (BufOff == BufLen) {
+
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+
+ if (CurBuffer == (PNDIS_BUFFER)NULL) {
+
+ break;
+
+ }
+
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufStart, &BufLen);
+
+ BufOff = 0;
+
+ }
+
+ }
+
+ *BytesTransferred = BytesWanted - BytesLeft;
+
+ //
+ // Did a transmit complete while we were doing what we were doing?
+ //
+ if (!Adapter->BufferOverflow && Adapter->CurBufXmitting != -1) {
+
+ ULONG Len;
+ UINT i;
+ UCHAR Status;
+ PNDIS_PACKET Packet;
+ NDIS_STATUS NdisStatus;
+
+ //
+ // Check if it completed
+ //
+ CardGetInterruptStatus(Adapter, &Status);
+
+ if (Status & ISR_XMIT_ERR) {
+ OctogmetusceratorRevisited(Adapter);
+ Adapter->InterruptStatus &= ~ISR_XMIT_ERR;
+ NdisRawWritePortUchar(Adapter->IoPAddr+NIC_INTR_STATUS, (ISR_XMIT_ERR));
+ Status &= ~ISR_XMIT_ERR;
+
+ }
+
+ if (Status & (ISR_XMIT)) {
+
+
+ IF_LOG( Ne2000Log('*'); )
+
+
+ //
+ // Update NextBufToXmit
+ //
+ Len = (Adapter->PacketLens[Adapter->CurBufXmitting] + 255) >> 8;
+ NextBufToXmit = Adapter->NextBufToXmit + Len;
+
+// Adapter->NextBufToXmit += Len;
+
+ if (NextBufToXmit == MAX_XMIT_BUFS) {
+ NextBufToXmit = 0;
+ }
+
+ if (Adapter->BufferStatus[NextBufToXmit] == EMPTY &&
+ Adapter->NextBufToFill != NextBufToXmit) {
+ NextBufToXmit = 0;
+ }
+
+
+ //
+ // If the next packet is ready to go, start it.
+ //
+ if (Adapter->BufferStatus[NextBufToXmit] == FULL) {
+
+ //
+ // Ack the transmit
+ //
+
+ //
+ // Remove the packet from the packet list.
+ //
+ Adapter->NextBufToXmit = NextBufToXmit;
+ Packet = Adapter->Packets[Adapter->CurBufXmitting];
+ Adapter->Packets[Adapter->CurBufXmitting] = (PNDIS_PACKET)NULL;
+ SyncCardGetXmitStatus((PVOID)Adapter);
+
+
+ //
+ // Statistics
+ //
+ if (Adapter->XmitStatus & TSR_XMIT_OK) {
+
+ Adapter->FramesXmitGood++;
+ NdisStatus = NDIS_STATUS_SUCCESS;
+
+ } else {
+
+ Adapter->FramesXmitBad++;
+ NdisStatus = NDIS_STATUS_FAILURE;
+
+ }
+
+ for (i = Adapter->CurBufXmitting; i < Adapter->CurBufXmitting + Len; i++) {
+ Adapter->BufferStatus[i] = EMPTY;
+ }
+ Adapter->TransmitInterruptPending = FALSE;
+ NdisRawWritePortUchar(Adapter->IoPAddr+NIC_INTR_STATUS, (ISR_XMIT));
+ Adapter->CurBufXmitting = Adapter->NextBufToXmit;
+ Adapter->TransmitInterruptPending = TRUE;
+
+ IF_LOG( Ne2000Log('8'); )
+ Adapter->InterruptStatus &= ~(ISR_XMIT);
+ CardStartXmit(Adapter);
+
+ } else {
+ NdisRawWritePortUchar(Adapter->IoPAddr+NIC_INTR_STATUS, (ISR_XMIT));
+ Adapter->InterruptStatus |= (Status);
+
+ }
+
+ }
+
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+}
+
+
+NDIS_STATUS
+Ne2000Send(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET Packet,
+ IN UINT Flags
+ )
+
+/*++
+
+Routine Description:
+
+
+ The Ne2000Send request instructs a driver to transmit a packet through
+ the adapter onto the medium.
+
+Arguments:
+
+ MiniportAdapterContext - Context registered with the wrapper, really
+ a pointer to the adapter.
+
+ Packet - A pointer to a descriptor for the packet that is to be
+ transmitted.
+
+ SendFlags - Optional send flags
+
+Notes:
+
+ This miniport driver will always accept a send. This is because
+ the Ne2000 has limited send resources and the driver needs packets
+ to copy to the adapter immediately after a transmit completes in
+ order to keep the adapter as busy as possible.
+
+ This is not required for other adapters, as they have enough
+ resources to keep the transmitter busy until the wrapper submits
+ the next packet.
+
+--*/
+
+{
+ PNE2000_ADAPTER Adapter = (PNE2000_ADAPTER)(MiniportAdapterContext);
+
+ //
+ // Put the packet on the send queue.
+ //
+ if (Adapter->FirstPacket == NULL) {
+ Adapter->FirstPacket = Packet;
+ } else {
+ RESERVED(Adapter->LastPacket)->Next = Packet;
+ }
+
+ RESERVED(Packet)->Next = NULL;
+
+ Adapter->LastPacket = Packet;
+
+ //
+ // Process the next send
+ //
+ Ne2000DoNextSend(Adapter);
+ return(NDIS_STATUS_PENDING);
+
+}
+
+VOID
+Ne2000DoNextSend(
+ PNE2000_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine examines if the packet at the head of the packet
+ list can be copied to the adapter, and does so.
+
+Arguments:
+
+ Adapter - Pointer to the adapter block.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ //
+ // The packet to process.
+ //
+ PNDIS_PACKET Packet;
+
+ //
+ // The current destination transmit buffer.
+ //
+ XMIT_BUF TmpBuf1;
+
+ //
+ // Length of the packet
+ //
+ ULONG Len;
+
+ //
+ // Temporary looping variable
+ //
+ ULONG i;
+
+ IF_LOG( Ne2000Log('s'); )
+
+ //
+ // Check if we have enough resources and a packet to process
+ //
+ while((Adapter->FirstPacket != NULL) &&
+ (Adapter->BufferStatus[Adapter->NextBufToFill] == EMPTY)) {
+
+ //
+ // Get the length of the packet.
+ //
+ NdisQueryPacket(
+ Adapter->FirstPacket,
+ NULL,
+ NULL,
+ NULL,
+ &Len
+ );
+
+ //
+ // Convert length to the number of transmit buffers needed.
+ //
+ Len = (Len + 255) >> 8;
+
+ //
+ // If not transmitting
+ //
+ if (Adapter->CurBufXmitting == -1) {
+
+ //
+ // Then check from the next free buffer if the packet will
+ // fit.
+ //
+ if (Adapter->BufferStatus[Adapter->NextBufToXmit] == EMPTY) {
+
+ //
+ // It won't fit at the end, so put it at the first buffer
+ //
+ if (Adapter->NextBufToFill + Len > MAX_XMIT_BUFS) {
+
+ Adapter->NextBufToFill = 0;
+
+ }
+
+ } else {
+
+ //
+ // Check if this packet will fit before the packet on the
+ // adapter.
+ //
+ if (Adapter->NextBufToXmit > Adapter->NextBufToFill) {
+
+ if (Adapter->NextBufToFill + Len > Adapter->NextBufToXmit) {
+
+ IF_LOG( Ne2000Log('^'); )
+ IF_LOG( Ne2000Log('S'); )
+
+ break;
+
+ }
+
+ } else {
+
+ //
+ // Check if it will fit after the packet already on the
+ // adapter.
+ //
+ if (Adapter->NextBufToFill + Len > MAX_XMIT_BUFS) {
+
+ Adapter->NextBufToFill = 0;
+
+ if (Adapter->NextBufToFill + Len > Adapter->NextBufToXmit){
+
+ IF_LOG( Ne2000Log('%'); )
+ IF_LOG( Ne2000Log('S'); )
+
+ break;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ } else {
+
+ //
+ // Check if the packet will fit before the packet currently
+ // transmitting
+ //
+
+ if (Adapter->CurBufXmitting > Adapter->NextBufToFill) {
+
+ if (Adapter->NextBufToFill + Len > Adapter->CurBufXmitting) {
+
+ IF_LOG( Ne2000Log('$'); )
+ IF_LOG( Ne2000Log('S'); )
+
+ break;
+ }
+
+ } else {
+
+ //
+ // Check if it will fit after the packet currently transmitting
+ //
+ if (Adapter->NextBufToFill + Len > MAX_XMIT_BUFS) {
+
+ Adapter->NextBufToFill = 0;
+
+ if (Adapter->NextBufToFill + Len > Adapter->CurBufXmitting){
+
+ IF_LOG( Ne2000Log('!'); )
+ IF_LOG( Ne2000Log('S'); )
+ break;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ //
+ // Set starting location
+ //
+ TmpBuf1 = Adapter->NextBufToFill;
+
+ //
+ // Remove the packet from the queue.
+ //
+ Packet = Adapter->FirstPacket;
+ Adapter->FirstPacket = RESERVED(Packet)->Next;
+
+ if (Packet == Adapter->LastPacket) {
+ Adapter->LastPacket = NULL;
+ }
+
+ //
+ // Store the packet in the list
+ //
+ Adapter->Packets[TmpBuf1] = Packet;
+
+ //
+ // Copy down the packet.
+ //
+ if (CardCopyDownPacket(Adapter, Packet,
+ &Adapter->PacketLens[TmpBuf1]) == FALSE) {
+
+ for (i = TmpBuf1; i < TmpBuf1 + Len; i++) {
+ Adapter->BufferStatus[i] = EMPTY;
+ }
+ Adapter->Packets[TmpBuf1] = NULL;
+ IF_LOG( Ne2000Log('F'); )
+ IF_LOG( Ne2000Log('S'); )
+
+ NdisMSendComplete(
+ Adapter->MiniportAdapterHandle,
+ Packet,
+ NDIS_STATUS_FAILURE
+ );
+
+ continue;
+
+ }
+
+ //
+ // Pad short packets with blanks.
+ //
+ if (Adapter->PacketLens[TmpBuf1] < 60) {
+
+ (VOID)CardCopyDown(
+ Adapter,
+ ((PUCHAR)Adapter->XmitStart +
+ TmpBuf1*TX_BUF_SIZE +
+ Adapter->PacketLens[TmpBuf1]),
+ BlankBuffer,
+ 60-Adapter->PacketLens[TmpBuf1]
+ );
+
+ }
+
+ //
+ // Set the buffer status
+ //
+ for (i = TmpBuf1; i < (TmpBuf1 + Len); i++) {
+ Adapter->BufferStatus[i] = FULL;
+ }
+
+ //
+ // Update next free buffer
+ //
+ Adapter->NextBufToFill += Len;
+
+ if (Adapter->NextBufToFill == MAX_XMIT_BUFS) {
+ Adapter->NextBufToFill = 0;
+ }
+
+ //
+ // See whether to start the transmission.
+ //
+ if (Adapter->CurBufXmitting == -1) {
+
+ //
+ // OK to start transmission.
+ //
+ if (Adapter->BufferStatus[Adapter->NextBufToXmit] == EMPTY &&
+ Adapter->NextBufToFill != Adapter->NextBufToXmit) {
+
+ Adapter->NextBufToXmit = 0;
+
+ }
+
+ Adapter->CurBufXmitting = Adapter->NextBufToXmit;
+
+
+ IF_LOG( Ne2000Log('4');)
+
+ //
+ // If we are currently handling an overflow, then we need to let
+ // the overflow handler send this packet...
+ //
+
+ if (Adapter->BufferOverflow) {
+
+ Adapter->OverflowRestartXmitDpc = TRUE;
+
+ IF_LOG( Ne2000Log('O');)
+ IF_LOUD( DbgPrint ("Adapter->OverflowRestartXmitDpc set:copy and send");)
+
+ } else {
+
+ //
+ // This is used to check if stopping the chip prevented
+ // a transmit complete interrupt from coming through (it
+ // is cleared in the ISR if a transmit DPC is queued).
+ //
+
+ Adapter->TransmitInterruptPending = TRUE;
+
+ IF_LOG( Ne2000Log('9'); )
+ CardStartXmit(Adapter);
+
+ }
+
+ }
+
+ //
+ // Ack the send immediately. If for some reason it
+ // should fail, the protocol should be able to handle
+ // the retransmit.
+ //
+
+ IF_LOG( Ne2000Log('S'); )
+
+ NdisMSendComplete(
+ Adapter->MiniportAdapterHandle,
+ Packet,
+ NDIS_STATUS_SUCCESS
+ );
+ }
+
+}
+
+VOID
+OctogmetusceratorRevisited(
+ IN PNE2000_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Recovers the card from a transmit error.
+
+Arguments:
+
+ Adapter - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ IF_LOUD( DbgPrint("Octogmetuscerator called!"); )
+
+ IF_LOG( Ne2000Log('y'); )
+
+ //
+ // Ack the interrupt, if needed
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr+NIC_INTR_STATUS, ISR_XMIT_ERR);
+
+ //
+ // Stop the card
+ //
+ SyncCardStop(Adapter);
+
+ //
+ // Wait up to 1.6 milliseconds for any receives to finish
+ //
+ NdisStallExecution(2000);
+
+ //
+ // Place the card in Loopback
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr+NIC_XMIT_CONFIG, TCR_LOOPBACK);
+
+ //
+ // Start the card in Loopback
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr+NIC_COMMAND, CR_START | CR_NO_DMA);
+
+ //
+ // Get out of loopback and start the card
+ //
+ CardStart(Adapter);
+
+ //
+ // If there was a packet waiting to get sent, send it.
+ //
+ if (Adapter->CurBufXmitting != -1) {
+
+ Adapter->TransmitInterruptPending = TRUE;
+ CardStartXmit(Adapter);
+
+ }
+ IF_LOG( Ne2000Log('Y'); )
+}
+
diff --git a/private/ntos/ndis/ne2000/keywords.h b/private/ntos/ndis/ne2000/keywords.h
new file mode 100644
index 000000000..e2df0f275
--- /dev/null
+++ b/private/ntos/ndis/ne2000/keywords.h
@@ -0,0 +1,54 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ keywords.h
+
+Abstract:
+
+ Contains all Ndis2 and Ndis3 mac-specific keywords.
+
+Author:
+
+ Bob Noradki
+
+Environment:
+
+ This driver is expected to work in DOS, OS2 and NT at the equivalent
+ of kernal mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+
+
+--*/
+#ifndef NDIS2
+#define NDIS2 0
+#endif
+
+#if NDIS2
+
+#define IOADDRESS NDIS_STRING_CONST("IOBASE")
+#define INTERRUPT NDIS_STRING_CONST("INTERRUPT")
+#define MAX_MULTICAST_LIST NDIS_STRING_CONST("MAXMULTICAST")
+#define NETWORK_ADDRESS NDIS_STRING_CONST("NETADDRESS")
+#define BUS_TYPE NDIS_STRING_CONST("BusType")
+
+#else // NDIS3
+
+#define IOADDRESS NDIS_STRING_CONST("IoBaseAddress")
+#define INTERRUPT NDIS_STRING_CONST("InterruptNumber")
+#define MAX_MULTICAST_LIST NDIS_STRING_CONST("MaximumMulticastList")
+#define NETWORK_ADDRESS NDIS_STRING_CONST("NetworkAddress")
+#define BUS_TYPE NDIS_STRING_CONST("BusType")
+
+#endif
diff --git a/private/ntos/ndis/ne2000/makefile b/private/ntos/ndis/ne2000/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/ne2000/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/ne2000/ne2000.c b/private/ntos/ndis/ne2000/ne2000.c
new file mode 100644
index 000000000..07cd6f05e
--- /dev/null
+++ b/private/ntos/ndis/ne2000/ne2000.c
@@ -0,0 +1,2054 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ne2000.c
+
+Abstract:
+
+ This is the main file for the Novel 2000 Ethernet controller.
+ This driver conforms to the NDIS 3.0 miniport interface.
+
+Author:
+
+ Sean Selitrennikoff (Dec 1993)
+
+Environment:
+
+Revision History:
+
+--*/
+
+#include <ndis.h>
+#include "ne2000hw.h"
+#include "ne2000sw.h"
+#include "keywords.h"
+
+
+
+//
+// On debug builds tell the compiler to keep the symbols for
+// internal functions, otw throw them out.
+//
+#if DBG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+//
+// Debugging definitions
+//
+#if DBG
+
+//
+// Default debug mode
+//
+ULONG Ne2000DebugFlag = NE2000_DEBUG_LOG;
+
+//
+// Debug tracing defintions
+//
+#define NE2000_LOG_SIZE 256
+UCHAR Ne2000LogBuffer[NE2000_LOG_SIZE]={0};
+UINT Ne2000LogLoc = 0;
+
+extern
+VOID
+Ne2000Log(UCHAR c) {
+
+ Ne2000LogBuffer[Ne2000LogLoc++] = c;
+
+ Ne2000LogBuffer[(Ne2000LogLoc + 4) % NE2000_LOG_SIZE] = '\0';
+
+ if (Ne2000LogLoc >= NE2000_LOG_SIZE)
+ Ne2000LogLoc = 0;
+}
+
+#endif
+
+
+
+//
+// This constant is used for places where NdisAllocateMemory
+// needs to be called and the HighestAcceptableAddress does
+// not matter.
+//
+NDIS_PHYSICAL_ADDRESS HighestAcceptableMax =
+ NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
+
+//
+// The global Miniport driver block.
+//
+
+DRIVER_BLOCK Ne2000MiniportBlock={0};
+
+//
+// List of supported OID for this driver.
+//
+STATIC UINT Ne2000SupportedOids[] = {
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ OID_802_3_RCV_ERROR_ALIGNMENT,
+ OID_802_3_XMIT_ONE_COLLISION,
+ OID_802_3_XMIT_MORE_COLLISIONS
+ };
+
+//
+// Determines whether failing the initial card test will prevent
+// the adapter from being registered.
+//
+#ifdef CARD_TEST
+
+BOOLEAN InitialCardTest = TRUE;
+
+#else // CARD_TEST
+
+BOOLEAN InitialCardTest = FALSE;
+
+#endif // CARD_TEST
+
+
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This is the primary initialization routine for the NE2000 driver.
+ It is simply responsible for the intializing the wrapper and registering
+ the Miniport driver. It then calls a system and architecture specific
+ routine that will initialize and register each adapter.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+ RegistryPath - Path to the parameters for this driver in the registry.
+
+Return Value:
+
+ The status of the operation.
+
+--*/
+
+{
+
+
+ //
+ // Receives the status of the NdisMRegisterMiniport operation.
+ //
+ NDIS_STATUS Status;
+
+ //
+ // Characteristics table for this driver.
+ //
+ NDIS_MINIPORT_CHARACTERISTICS NE2000Char;
+
+ //
+ // Pointer to the global information for this driver
+ //
+ PDRIVER_BLOCK NewDriver = &Ne2000MiniportBlock;
+
+ //
+ // Handle for referring to the wrapper about this driver.
+ //
+ NDIS_HANDLE NdisWrapperHandle;
+
+#if NDIS_WIN
+ UCHAR pIds[sizeof (EISA_MCA_ADAPTER_IDS) + 3 * sizeof (USHORT)];
+ ((PEISA_MCA_ADAPTER_IDS)pIds)->nEisaAdapters=0;
+ ((PEISA_MCA_ADAPTER_IDS)pIds)->nMcaAdapters=3;
+ *((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 0)=AE2_ADAPTER_ID;
+ *((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 1)=UB_ADAPTER_ID;
+ *((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 2)=NE2_ADAPTER_ID;
+ (PVOID) DriverObject = (PVOID) pIds;
+
+#endif
+
+ //
+ // Initialize the wrapper.
+ //
+ NdisMInitializeWrapper(
+ &NdisWrapperHandle,
+ DriverObject,
+ RegistryPath,
+ NULL
+ );
+
+ //
+ // Save the global information about this driver.
+ //
+ NewDriver->NdisWrapperHandle = NdisWrapperHandle;
+ NewDriver->AdapterQueue = (PNE2000_ADAPTER)NULL;
+
+ //
+ // Initialize the Miniport characteristics for the call to
+ // NdisMRegisterMiniport.
+ //
+ NE2000Char.MajorNdisVersion = NE2000_NDIS_MAJOR_VERSION;
+ NE2000Char.MinorNdisVersion = NE2000_NDIS_MINOR_VERSION;
+ NE2000Char.CheckForHangHandler = NULL;
+ NE2000Char.DisableInterruptHandler = Ne2000DisableInterrupt;
+ NE2000Char.EnableInterruptHandler = Ne2000EnableInterrupt;
+ NE2000Char.HaltHandler = Ne2000Halt;
+ NE2000Char.HandleInterruptHandler = Ne2000HandleInterrupt;
+ NE2000Char.InitializeHandler = Ne2000Initialize;
+ NE2000Char.ISRHandler = Ne2000Isr;
+ NE2000Char.QueryInformationHandler = Ne2000QueryInformation;
+ NE2000Char.ReconfigureHandler = NULL;
+ NE2000Char.ResetHandler = Ne2000Reset;
+ NE2000Char.SendHandler = Ne2000Send;
+ NE2000Char.SetInformationHandler = Ne2000SetInformation;
+ NE2000Char.TransferDataHandler = Ne2000TransferData;
+
+ Status = NdisMRegisterMiniport(
+ NdisWrapperHandle,
+ &NE2000Char,
+ sizeof(NE2000Char)
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ return STATUS_SUCCESS;
+
+ }
+
+ return STATUS_UNSUCCESSFUL;
+
+}
+
+extern
+NDIS_STATUS
+Ne2000Initialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Ne2000Initialize starts an adapter and registers resources with the
+ wrapper.
+
+Arguments:
+
+ OpenErrorStatus - Extra status bytes for opening token ring adapters.
+
+ SelectedMediumIndex - Index of the media type chosen by the driver.
+
+ MediumArray - Array of media types for the driver to chose from.
+
+ MediumArraySize - Number of entries in the array.
+
+ MiniportAdapterHandle - Handle for passing to the wrapper when
+ referring to this adapter.
+
+ ConfigurationHandle - A handle to pass to NdisOpenConfiguration.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_PENDING
+
+--*/
+
+{
+ //
+ // Pointer to our newly allocated adapter.
+ //
+ PNE2000_ADAPTER Adapter;
+
+ //
+ // The handle for reading from the registry.
+ //
+ NDIS_HANDLE ConfigHandle;
+
+ //
+ // The value read from the registry.
+ //
+ PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
+
+ //
+ // String names of all the parameters that will be read.
+ //
+ NDIS_STRING IOAddressStr = IOADDRESS;
+ NDIS_STRING InterruptStr = INTERRUPT;
+ NDIS_STRING MaxMulticastListStr = MAX_MULTICAST_LIST;
+ NDIS_STRING NetworkAddressStr = NETWORK_ADDRESS;
+ NDIS_STRING BusTypeStr = NDIS_STRING_CONST("BusType");
+ NDIS_STRING CardTypeStr = NDIS_STRING_CONST("CardType");
+
+ //
+ // TRUE if there is a configuration error.
+ //
+ BOOLEAN ConfigError = FALSE;
+
+ //
+ // A special value to log concerning the error.
+ //
+ ULONG ConfigErrorValue = 0;
+
+ //
+ // The slot number the adapter is located in, used for
+ // Microchannel adapters.
+ //
+ UINT SlotNumber = 0;
+
+ //
+ // TRUE if it is unnecessary to read the Io Base Address
+ // and Interrupt from the registry. Used for Microchannel
+ // adapters, which get this information from the slot
+ // information.
+ //
+ BOOLEAN SkipIobaseAndInterrupt = FALSE;
+
+ //
+ // The network address the adapter should use instead of the
+ // the default burned in address.
+ //
+ PVOID NetAddress;
+
+ //
+ // The number of bytes in the address. It should be
+ // NE2000_LENGTH_OF_ADDRESS
+ //
+ ULONG Length;
+
+ //
+ // These are used when calling Ne2000RegisterAdapter.
+ //
+
+ //
+ // The physical address of the base I/O port.
+ //
+ PVOID IoBaseAddr;
+
+ //
+ // The interrupt number to use.
+ //
+ CCHAR InterruptNumber;
+
+ //
+ // The number of multicast address to be supported.
+ //
+ UINT MaxMulticastList;
+
+ //
+ // Temporary looping variable.
+ //
+ ULONG i;
+
+ //
+ // Status of Ndis calls.
+ //
+ NDIS_STATUS Status;
+
+ NDIS_MCA_POS_DATA McaData;
+
+ //
+ // Search for the medium type (802.3) in the given array.
+ //
+ for (i = 0; i < MediumArraySize; i++){
+
+ if (MediumArray[i] == NdisMedium802_3){
+
+ break;
+
+ }
+
+ }
+
+ if (i == MediumArraySize){
+
+ return( NDIS_STATUS_UNSUPPORTED_MEDIA );
+
+ }
+
+ *SelectedMediumIndex = i;
+
+
+ //
+ // Set default values.
+ //
+ IoBaseAddr = DEFAULT_IOBASEADDR;
+ InterruptNumber = DEFAULT_INTERRUPTNUMBER;
+ MaxMulticastList = DEFAULT_MULTICASTLISTMAX;
+
+ //
+ // Allocate memory for the adapter block now.
+ //
+ Status = NdisAllocateMemory( (PVOID *)&Adapter,
+ sizeof(NE2000_ADAPTER),
+ 0,
+ HighestAcceptableMax
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ return Status;
+
+ }
+
+ //
+ // Clear out the adapter block, which sets all default values to FALSE,
+ // or NULL.
+ //
+ NdisZeroMemory (Adapter, sizeof(NE2000_ADAPTER));
+
+ //
+ // Open the configuration space.
+ //
+ NdisOpenConfiguration(
+ &Status,
+ &ConfigHandle,
+ ConfigurationHandle
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NdisFreeMemory(Adapter, sizeof(NE2000_ADAPTER), 0);
+
+ return Status;
+
+ }
+
+ //
+ // Read in the card type.
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &CardTypeStr,
+ NdisParameterHexInteger
+ );
+ if (Status == NDIS_STATUS_SUCCESS)
+ Adapter->CardType = (UINT)ReturnedValue->ParameterData.IntegerData;
+
+ //
+ // Read net address
+ //
+ NdisReadNetworkAddress(
+ &Status,
+ &NetAddress,
+ &Length,
+ ConfigHandle
+ );
+
+ if ((Length == NE2000_LENGTH_OF_ADDRESS) && (Status == NDIS_STATUS_SUCCESS)) {
+
+ //
+ // Save the address that should be used.
+ //
+ NdisMoveMemory(
+ Adapter->StationAddress,
+ NetAddress,
+ NE2000_LENGTH_OF_ADDRESS
+ );
+
+ }
+
+#if NDIS_NT
+ //
+ // Disallow multiple adapters in the same MP machine because of hardware
+ // problems this results in random packet corruption.
+ //
+ if ((NdisSystemProcessorCount() > 1) && (Ne2000MiniportBlock.AdapterQueue != NULL)) {
+
+ ConfigError = TRUE;
+ ConfigErrorValue = (ULONG)NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION;
+ goto RegisterAdapter;
+
+ return NDIS_STATUS_FAILURE;
+
+ }
+#endif
+
+
+ //
+ // Read Bus Type (for NE2/AE2 support)
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &BusTypeStr,
+ NdisParameterHexInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ Adapter->BusType = (UCHAR)ReturnedValue->ParameterData.IntegerData;
+
+ }
+
+ if (Adapter->BusType == NdisInterfaceMca) {
+
+ NdisReadMcaPosInformation(
+ &Status,
+ ConfigurationHandle,
+ &SlotNumber,
+ &McaData
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ ConfigError = TRUE;
+ ConfigErrorValue = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION;
+ goto RegisterAdapter;
+
+ }
+
+ //
+ // Interpret POS data
+ //
+ if (McaData.AdapterId == AE2_ADAPTER_ID ){
+ SkipIobaseAndInterrupt = TRUE;
+ switch ((McaData.PosData1 & MC_IO_BASE_MASK)>>1) {
+ case 0x01:
+ IoBaseAddr = (PVOID)0x1000;
+ break;
+ case 0x02:
+ IoBaseAddr = (PVOID)0x2020;
+ break;
+ case 0x03:
+ IoBaseAddr = (PVOID)0x8020;
+ break;
+ case 0x04:
+ IoBaseAddr = (PVOID)0x0300;
+ break;
+ case 0x05:
+ IoBaseAddr = (PVOID)0x0320;
+ break;
+ case 0x06:
+ IoBaseAddr = (PVOID)0x0340;
+ break;
+ case 0x07:
+ IoBaseAddr = (PVOID)0x0360;
+ break;
+ }
+ switch ((McaData.PosData1 & MC_IRQ_MASK)>>5) {
+ case 0x00:
+ InterruptNumber = 3;
+ break;
+ case 0x01:
+ InterruptNumber = 4;
+ break;
+ case 0x02:
+ InterruptNumber = 5;
+ break;
+ case 0x03:
+ InterruptNumber = 9;
+ break;
+ }
+
+ } else if (McaData.AdapterId == NE2_ADAPTER_ID ){
+ SkipIobaseAndInterrupt = TRUE;
+ switch ((McaData.PosData1 & MC_IO_BASE_MASK)>>1) {
+ case 0x01:
+ IoBaseAddr = (PVOID)0x1000;
+ break;
+ case 0x02:
+ IoBaseAddr = (PVOID)0x2020;
+ break;
+ case 0x03:
+ IoBaseAddr = (PVOID)0x8020;
+ break;
+ case 0x04:
+ IoBaseAddr = (PVOID)0xa0a0;
+ break;
+ case 0x05:
+ IoBaseAddr = (PVOID)0xb0b0;
+ break;
+ case 0x06:
+ IoBaseAddr = (PVOID)0xc0c0;
+ break;
+ case 0x07:
+ IoBaseAddr = (PVOID)0xc3d0;
+ break;
+ }
+ switch ((McaData.PosData1 & MC_IRQ_MASK)>>5) {
+ case 0x00:
+ InterruptNumber = 3;
+ break;
+ case 0x01:
+ InterruptNumber = 4;
+ break;
+ case 0x02:
+ InterruptNumber = 5;
+ break;
+ case 0x03:
+ InterruptNumber = 9;
+ break;
+ case 0x04:
+ InterruptNumber = 10;
+ break;
+ case 0x05:
+ InterruptNumber = 11;
+ break;
+ case 0x06:
+ InterruptNumber = 12;
+ break;
+ case 0x07:
+ InterruptNumber = 15;
+ break;
+ }
+ }
+
+ //
+ // You cannot read the POS information for a UBEtherNext.
+ //
+ }
+
+ if (!SkipIobaseAndInterrupt) {
+
+ //
+ // Read I/O Address
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &IOAddressStr,
+ NdisParameterHexInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ IoBaseAddr = (PVOID)(ReturnedValue->ParameterData.IntegerData);
+
+ }
+
+ //
+ // Check that the value is valid.
+ //
+ if ((IoBaseAddr < (PVOID)MIN_IOBASEADDR) ||
+ (IoBaseAddr > (PVOID)MAX_IOBASEADDR)) {
+
+ ConfigError = TRUE;
+ ConfigErrorValue = (ULONG)IoBaseAddr;
+ goto RegisterAdapter;
+
+ }
+
+ //
+ // Read interrupt number
+ //
+#if NDIS_NT
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &InterruptStr,
+ NdisParameterHexInteger
+ );
+#endif
+
+#if NDIS_WIN
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &InterruptStr,
+ NdisParameterInteger
+ );
+#endif
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ InterruptNumber = (CCHAR)(ReturnedValue->ParameterData.IntegerData);
+
+ }
+
+ //
+ // Verify that the value is valid.
+ //
+ if ((InterruptNumber < MIN_IRQ) ||
+ (InterruptNumber > MAX_IRQ)) {
+
+ ConfigError = TRUE;
+ ConfigErrorValue = (ULONG)InterruptNumber;
+ goto RegisterAdapter;
+
+ }
+
+ //
+ // If the adapter is a pcmcia card then get the memory window
+ // address for later use.
+ //
+ if (NE2000_PCMCIA == Adapter->CardType)
+ {
+ NDIS_STRING AttributeMemoryAddrStr =
+ NDIS_STRING_CONST("PCCARDAttributeMemoryAddress");
+ NDIS_STRING AttributeMemorySizeStr =
+ NDIS_STRING_CONST("PCCARDAttributeMemorySize");
+
+ //
+ // Read the attribute memory address.
+ //
+ Adapter->AttributeMemoryAddress = 0xd4000;
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &AttributeMemoryAddrStr,
+ NdisParameterHexInteger
+ );
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ Adapter->AttributeMemoryAddress =
+ (ULONG)ReturnedValue->ParameterData.IntegerData;
+ }
+
+ //
+ // Read the size of the attribute memory range.
+ //
+ Adapter->AttributeMemorySize = 0x1000;
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &AttributeMemorySizeStr,
+ NdisParameterHexInteger
+ );
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ Adapter->AttributeMemorySize =
+ (ULONG)ReturnedValue->ParameterData.IntegerData;
+ }
+ }
+ }
+
+ //
+ // Read MaxMulticastList
+ //
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &MaxMulticastListStr,
+ NdisParameterInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ MaxMulticastList = ReturnedValue->ParameterData.IntegerData;
+ if (ReturnedValue->ParameterData.IntegerData <= DEFAULT_MULTICASTLISTMAX)
+ MaxMulticastList = ReturnedValue->ParameterData.IntegerData;
+ }
+
+
+RegisterAdapter:
+
+ //
+ // Now to use this information and register with the wrapper
+ // and initialize the adapter.
+ //
+
+ //
+ // First close the configuration space.
+ //
+ NdisCloseConfiguration(ConfigHandle);
+
+ IF_LOUD( DbgPrint(
+ "Registering adapter # buffers %ld\n"
+ "Card type: 0x%x\n"
+ "I/O base addr 0x%lx\n"
+ "interrupt number %ld\n"
+ "max multicast %ld\nattribute memory address 0x%X\n"
+ "attribute memory size 0x%X\n"
+ "CardType: %d\n",
+ DEFAULT_NUMBUFFERS,
+ Adapter->CardType,
+ IoBaseAddr,
+ InterruptNumber,
+ DEFAULT_MULTICASTLISTMAX,
+ Adapter->AttributeMemoryAddress,
+ Adapter->AttributeMemorySize,
+ Adapter->CardType );)
+
+
+
+ //
+ // Set up the parameters.
+ //
+ Adapter->NumBuffers = DEFAULT_NUMBUFFERS;
+ Adapter->IoBaseAddr = IoBaseAddr;
+
+ Adapter->InterruptNumber = InterruptNumber;
+
+ Adapter->MulticastListMax = MaxMulticastList;
+ Adapter->MiniportAdapterHandle = MiniportAdapterHandle;
+
+ Adapter->MaxLookAhead = NE2000_MAX_LOOKAHEAD;
+
+ //
+ // Now do the work.
+ //
+ if (Ne2000RegisterAdapter(Adapter,
+ ConfigurationHandle,
+ ConfigError,
+ ConfigErrorValue
+ ) != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Ne2000RegisterAdapter failed.
+ //
+ NdisFreeMemory(Adapter, sizeof(NE2000_ADAPTER), 0);
+
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+
+ IF_LOUD( DbgPrint( "Ne2000RegisterAdapter succeeded\n" );)
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+NDIS_STATUS
+Ne2000RegisterAdapter(
+ IN PNE2000_ADAPTER Adapter,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN BOOLEAN ConfigError,
+ IN ULONG ConfigErrorValue
+ )
+
+/*++
+
+Routine Description:
+
+ Called when a new adapter should be registered. It allocates space for
+ the adapter, initializes the adapter's block, registers resources
+ with the wrapper and initializes the physical adapter.
+
+Arguments:
+
+ Adapter - The adapter structure.
+
+ ConfigurationHandle - Handle passed to Ne2000Initialize.
+
+ ConfigError - Was there an error during configuration reading.
+
+ ConfigErrorValue - Value to log if there is an error.
+
+Return Value:
+
+ Indicates the success or failure of the registration.
+
+--*/
+
+{
+
+ //
+ // Temporary looping variable.
+ //
+ UINT i;
+
+ //
+ // General purpose return from NDIS calls
+ //
+ NDIS_STATUS status;
+
+ //
+ // check that NumBuffers <= MAX_XMIT_BUFS
+ //
+
+ if (Adapter->NumBuffers > MAX_XMIT_BUFS)
+ return(NDIS_STATUS_RESOURCES);
+
+ //
+ // Check for a configuration error
+ //
+ if (ConfigError)
+ {
+ //
+ // Log Error and exit.
+ //
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
+ 1,
+ ConfigErrorValue
+ );
+
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // Inform the wrapper of the physical attributes of this adapter.
+ //
+ NdisMSetAttributes(
+ Adapter->MiniportAdapterHandle,
+ (NDIS_HANDLE)Adapter,
+ FALSE,
+ Adapter->BusType
+ );
+
+ //
+ // Register the port addresses.
+ //
+ status = NdisMRegisterIoPortRange(
+ (PVOID *)(&(Adapter->IoPAddr)),
+ Adapter->MiniportAdapterHandle,
+ (ULONG)Adapter->IoBaseAddr,
+ 0x20
+ );
+
+ if (status != NDIS_STATUS_SUCCESS)
+ return(status);
+
+ if (NE2000_ISA == Adapter->CardType)
+ {
+ //
+ // Check that the IoBaseAddress seems to be correct.
+ //
+ IF_VERY_LOUD( DbgPrint("Checking Parameters\n"); )
+
+ if (!CardCheckParameters(Adapter))
+ {
+ //
+ // The card does not seem to be there, fail silently.
+ //
+ IF_VERY_LOUD( DbgPrint(" -- Failed\n"); )
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
+ 0
+ );
+
+ status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+
+ goto fail2;
+ }
+
+ IF_VERY_LOUD( DbgPrint(" -- Success\n"); )
+ }
+
+ //
+ // Initialize the card.
+ //
+ IF_VERY_LOUD( DbgPrint("CardInitialize\n"); )
+
+ if (!CardInitialize(Adapter))
+ {
+ //
+ // Card seems to have failed.
+ //
+
+ IF_VERY_LOUD( DbgPrint(" -- Failed\n"); )
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
+ 0
+ );
+
+ status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+
+ goto fail2;
+ }
+
+ IF_VERY_LOUD( DbgPrint(" -- Success\n"); )
+
+ //
+ //
+ // For programmed I/O, we will refer to transmit/receive memory in
+ // terms of offsets in the card's 64K address space.
+ //
+ Adapter->XmitStart = Adapter->RamBase;
+
+ //
+ // For the NicXXX fields, always use the addressing system
+ // containing the MSB only).
+ //
+ Adapter->NicXmitStart = (UCHAR)(((ULONG)Adapter->XmitStart) >> 8);
+
+ //
+ // The start of the receive space.
+ //
+ Adapter->PageStart = Adapter->XmitStart +
+ (Adapter->NumBuffers * TX_BUF_SIZE);
+
+ Adapter->NicPageStart = Adapter->NicXmitStart +
+ (UCHAR)(Adapter->NumBuffers * BUFS_PER_TX);
+
+ ASSERT(Adapter->PageStart < (Adapter->RamBase + Adapter->RamSize));
+
+ //
+ // The end of the receive space.
+ //
+ Adapter->PageStop = Adapter->XmitStart + Adapter->RamSize;
+ Adapter->NicPageStop = Adapter->NicXmitStart + (UCHAR)(Adapter->RamSize >> 8);
+
+ ASSERT(Adapter->PageStop <= (Adapter->RamBase + Adapter->RamSize));
+
+ IF_LOUD( DbgPrint("Xmit Start (0x%x, 0x%x) : Rcv Start (0x%x, 0x%x) : Rcv End (0x%x, 0x%x)\n",
+ Adapter->XmitStart,
+ Adapter->NicXmitStart,
+ Adapter->PageStart,
+ Adapter->NicPageStart,
+ (ULONG)Adapter->PageStop,
+ Adapter->NicPageStop
+ );
+ )
+
+
+ //
+ // Initialize the receive variables.
+ //
+ Adapter->NicReceiveConfig = RCR_REJECT_ERR;
+
+ //
+ // Initialize the transmit buffer control.
+ //
+ Adapter->CurBufXmitting = (XMIT_BUF)-1;
+
+ //
+ // Initialize the transmit buffer states.
+ //
+ for (i = 0; i < Adapter->NumBuffers; i++)
+ Adapter->BufferStatus[i] = EMPTY;
+
+ //
+ // Read the Ethernet address off of the PROM.
+ //
+ if (!CardReadEthernetAddress(Adapter))
+ {
+ IF_LOUD(DbgPrint("Could not read the ethernet address\n");)
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
+ 0
+ );
+
+ status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+
+ goto fail2;
+ }
+
+ //
+ // Now initialize the NIC and Gate Array registers.
+ //
+ Adapter->NicInterruptMask = IMR_RCV | IMR_XMIT | IMR_XMIT_ERR | IMR_OVERFLOW;
+
+ //
+ // Link us on to the chain of adapters for this driver.
+ //
+ Adapter->NextAdapter = Ne2000MiniportBlock.AdapterQueue;
+ Ne2000MiniportBlock.AdapterQueue = Adapter;
+
+
+ //
+ // Setup the card based on the initialization information
+ //
+
+ IF_VERY_LOUD( DbgPrint("Setup\n"); )
+
+ if (!CardSetup(Adapter))
+ {
+ //
+ // The NIC could not be written to.
+ //
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
+ 0
+ );
+
+ IF_VERY_LOUD( DbgPrint(" -- Failed\n"); )
+
+ status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+
+ goto fail3;
+ }
+
+ IF_VERY_LOUD( DbgPrint(" -- Success\n"); )
+
+ //
+ // Initialize the interrupt.
+ //
+ status = NdisMRegisterInterrupt(
+ &Adapter->Interrupt,
+ Adapter->MiniportAdapterHandle,
+ Adapter->InterruptNumber,
+ Adapter->InterruptNumber,
+ FALSE,
+ FALSE,
+ NdisInterruptLatched
+ );
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_INTERRUPT_CONNECT,
+ 0
+ );
+
+ goto fail3;
+ }
+
+ IF_LOUD( DbgPrint("Interrupt Connected\n");)
+
+ //
+ // Start up the adapter.
+ //
+ CardStart(Adapter);
+
+ //
+ // Initialization completed successfully.
+ //
+ IF_LOUD( DbgPrint(" [ Ne2000 ] : OK\n");)
+
+ return(NDIS_STATUS_SUCCESS);
+
+ //
+ // Code to unwind what has already been set up when a part of
+ // initialization fails, which is jumped into at various
+ // points based on where the failure occured. Jumping to
+ // a higher-numbered failure point will execute the code
+ // for that block and all lower-numbered ones.
+ //
+
+fail3:
+
+ //
+ // Take us out of the AdapterQueue.
+ //
+
+ if (Ne2000MiniportBlock.AdapterQueue == Adapter)
+ {
+ Ne2000MiniportBlock.AdapterQueue = Adapter->NextAdapter;
+ }
+ else
+ {
+ PNE2000_ADAPTER TmpAdapter = Ne2000MiniportBlock.AdapterQueue;
+
+ while (TmpAdapter->NextAdapter != Adapter)
+ {
+ TmpAdapter = TmpAdapter->NextAdapter;
+ }
+
+ TmpAdapter->NextAdapter = TmpAdapter->NextAdapter->NextAdapter;
+ }
+
+ //
+ // We already enabled the interrupt on the card, so
+ // turn it off.
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr+NIC_COMMAND, CR_STOP);
+
+fail2:
+
+ NdisMDeregisterIoPortRange(
+ Adapter->MiniportAdapterHandle,
+ (ULONG)Adapter->IoBaseAddr,
+ 0x20,
+ (PVOID)Adapter->IoPAddr
+ );
+
+ return(status);
+}
+
+
+extern
+VOID
+Ne2000Halt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ NE2000Halt removes an adapter that was previously initialized.
+
+Arguments:
+
+ MiniportAdapterContext - The context value that the Miniport returned
+ from Ne2000Initialize; actually as pointer to an NE2000_ADAPTER.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNE2000_ADAPTER Adapter;
+
+ Adapter = PNE2000_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ //
+ // Shut down the chip.
+ //
+ CardStop(Adapter);
+
+ //
+ // Disconnect the interrupt line.
+ //
+ NdisMDeregisterInterrupt(&Adapter->Interrupt);
+
+ //
+ // Pause, waiting for any DPC stuff to clear.
+ //
+ NdisStallExecution(250000);
+
+ NdisMDeregisterIoPortRange(Adapter->MiniportAdapterHandle,
+ (ULONG)Adapter->IoBaseAddr,
+ 0x20,
+ (PVOID)Adapter->IoPAddr
+ );
+
+ //
+ // Remove the adapter from the global queue of adapters.
+ //
+ if (Ne2000MiniportBlock.AdapterQueue == Adapter) {
+
+ Ne2000MiniportBlock.AdapterQueue = Adapter->NextAdapter;
+
+ } else {
+
+ PNE2000_ADAPTER TmpAdapter = Ne2000MiniportBlock.AdapterQueue;
+
+ while (TmpAdapter->NextAdapter != Adapter) {
+
+ TmpAdapter = TmpAdapter->NextAdapter;
+
+ }
+
+ TmpAdapter->NextAdapter = TmpAdapter->NextAdapter->NextAdapter;
+ }
+
+ //
+ // Free up the memory
+ //
+ NdisFreeMemory(Adapter, sizeof(NE2000_ADAPTER), 0);
+
+ return;
+
+}
+
+
+
+
+NDIS_STATUS
+Ne2000Reset(
+ OUT PBOOLEAN AddressingReset,
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+/*++
+
+Routine Description:
+
+ The NE2000Reset request instructs the Miniport to issue a hardware reset
+ to the network adapter. The driver also resets its software state. See
+ the description of NdisMReset for a detailed description of this request.
+
+Arguments:
+
+ AddressingReset - Does the adapter need the addressing information reloaded.
+
+ MiniportAdapterContext - Pointer to the adapter structure.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+ //
+ // Pointer to the adapter structure.
+ //
+ PNE2000_ADAPTER Adapter = (PNE2000_ADAPTER)MiniportAdapterContext;
+
+ //
+ // Temporary looping variable
+ //
+ UINT i;
+
+ //
+ // Clear the values for transmits, they will be reset these for after
+ // the reset is completed.
+ //
+ Adapter->NextBufToFill = 0;
+ Adapter->NextBufToXmit = 0;
+ Adapter->CurBufXmitting = (XMIT_BUF)-1;
+
+ Adapter->FirstPacket = NULL;
+ Adapter->LastPacket = NULL;
+
+ for (i=0; i<Adapter->NumBuffers; i++) {
+ Adapter->BufferStatus[i] = EMPTY;
+ }
+
+ //
+ // Physically reset the card.
+ //
+ Adapter->NicInterruptMask = IMR_RCV | IMR_XMIT | IMR_XMIT_ERR | IMR_OVERFLOW;
+
+ return (CardReset(Adapter) ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE);
+}
+
+NDIS_STATUS
+Ne2000QueryInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+)
+
+/*++
+
+Routine Description:
+
+ The NE2000QueryInformation process a Query request for
+ NDIS_OIDs that are specific about the Driver.
+
+Arguments:
+
+ MiniportAdapterContext - a pointer to the adapter.
+
+ Oid - the NDIS_OID to process.
+
+ InformationBuffer - a pointer into the
+ NdisRequest->InformationBuffer into which store the result of the query.
+
+ InformationBufferLength - a pointer to the number of bytes left in the
+ InformationBuffer.
+
+ BytesWritten - a pointer to the number of bytes written into the
+ InformationBuffer.
+
+ BytesNeeded - If there is not enough room in the information buffer
+ then this will contain the number of bytes needed to complete the
+ request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+
+ //
+ // Pointer to the adapter structure.
+ //
+ PNE2000_ADAPTER Adapter = (PNE2000_ADAPTER)MiniportAdapterContext;
+
+ //
+ // General Algorithm:
+ //
+ // Switch(Request)
+ // Get requested information
+ // Store results in a common variable.
+ // default:
+ // Try protocol query information
+ // If that fails, fail query.
+ //
+ // Copy result in common variable to result buffer.
+ // Finish processing
+
+ UINT BytesLeft = InformationBufferLength;
+ PUCHAR InfoBuffer = (PUCHAR)(InformationBuffer);
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+ NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady;
+ NDIS_MEDIUM Medium = NdisMedium802_3;
+
+ //
+ // This variable holds result of query
+ //
+ ULONG GenericULong;
+ USHORT GenericUShort;
+ UCHAR GenericArray[6];
+ UINT MoveBytes = sizeof(ULONG);
+ PVOID MoveSource = (PVOID)(&GenericULong);
+
+ //
+ // Make sure that int is 4 bytes. Else GenericULong must change
+ // to something of size 4.
+ //
+ ASSERT(sizeof(ULONG) == 4);
+
+ //
+ // Switch on request type
+ //
+
+ switch (Oid) {
+
+ case OID_GEN_MAC_OPTIONS:
+
+ GenericULong = (ULONG)(NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
+ NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
+ NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
+ NDIS_MAC_OPTION_NO_LOOPBACK
+ );
+
+ break;
+
+ case OID_GEN_SUPPORTED_LIST:
+
+ MoveSource = (PVOID)(Ne2000SupportedOids);
+ MoveBytes = sizeof(Ne2000SupportedOids);
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+
+ HardwareStatus = NdisHardwareStatusReady;
+ MoveSource = (PVOID)(&HardwareStatus);
+ MoveBytes = sizeof(NDIS_HARDWARE_STATUS);
+
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+
+ MoveSource = (PVOID) (&Medium);
+ MoveBytes = sizeof(NDIS_MEDIUM);
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+
+ GenericULong = NE2000_MAX_LOOKAHEAD;
+
+ break;
+
+
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+
+ GenericULong = (ULONG)(1514 - NE2000_HEADER_SIZE);
+
+ break;
+
+
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+
+ GenericULong = (ULONG)(1514);
+
+ break;
+
+
+ case OID_GEN_LINK_SPEED:
+
+ GenericULong = (ULONG)(100000);
+
+ break;
+
+
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+
+ GenericULong = (ULONG)(Adapter->NumBuffers * TX_BUF_SIZE);
+
+ break;
+
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+
+ GenericULong = (ULONG)(0x2000 - (Adapter->NumBuffers * TX_BUF_SIZE));
+
+ break;
+
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+
+ GenericULong = (ULONG)(TX_BUF_SIZE);
+
+ break;
+
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+
+ GenericULong = (ULONG)(256);
+
+ break;
+
+#ifdef NE2000
+
+ case OID_GEN_VENDOR_ID:
+
+ NdisMoveMemory(
+ (PVOID)&GenericULong,
+ Adapter->PermanentAddress,
+ 3
+ );
+ GenericULong &= 0xFFFFFF00;
+ MoveSource = (PVOID)(&GenericULong);
+ MoveBytes = sizeof(GenericULong);
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+
+ MoveSource = (PVOID)"Novell 2000 Adapter.";
+ MoveBytes = 21;
+
+ break;
+
+#else
+
+ case OID_GEN_VENDOR_ID:
+
+ NdisMoveMemory(
+ (PVOID)&GenericULong,
+ Adapter->PermanentAddress,
+ 3
+ );
+ GenericULong &= 0xFFFFFF00;
+ GenericULong |= 0x01;
+ MoveSource = (PVOID)(&GenericULong);
+ MoveBytes = sizeof(GenericULong);
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+
+ MoveSource = (PVOID)"Novell 1000 Adapter.";
+ MoveBytes = 21;
+
+ break;
+
+#endif
+
+ case OID_GEN_DRIVER_VERSION:
+
+ GenericUShort = ((USHORT)NE2000_NDIS_MAJOR_VERSION << 8) |
+ NE2000_NDIS_MINOR_VERSION;
+
+ MoveSource = (PVOID)(&GenericUShort);
+ MoveBytes = sizeof(GenericUShort);
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ GenericULong = (ULONG)(Adapter->MaxLookAhead);
+ break;
+
+ case OID_802_3_PERMANENT_ADDRESS:
+
+ NE2000_MOVE_MEM((PCHAR)GenericArray,
+ Adapter->PermanentAddress,
+ NE2000_LENGTH_OF_ADDRESS);
+
+ MoveSource = (PVOID)(GenericArray);
+ MoveBytes = sizeof(Adapter->PermanentAddress);
+
+ break;
+
+ case OID_802_3_CURRENT_ADDRESS:
+
+ NE2000_MOVE_MEM((PCHAR)GenericArray,
+ Adapter->StationAddress,
+ NE2000_LENGTH_OF_ADDRESS);
+
+ MoveSource = (PVOID)(GenericArray);
+ MoveBytes = sizeof(Adapter->StationAddress);
+
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+
+ GenericULong = (ULONG) (Adapter->MulticastListMax);
+ break;
+
+ case OID_GEN_XMIT_OK:
+
+ GenericULong = (UINT)(Adapter->FramesXmitGood);
+ break;
+
+ case OID_GEN_RCV_OK:
+
+ GenericULong = (UINT)(Adapter->FramesRcvGood);
+ break;
+
+ case OID_GEN_XMIT_ERROR:
+
+ GenericULong = (UINT)(Adapter->FramesXmitBad);
+ break;
+
+ case OID_GEN_RCV_ERROR:
+
+ GenericULong = (UINT)(Adapter->CrcErrors);
+ break;
+
+ case OID_GEN_RCV_NO_BUFFER:
+
+ GenericULong = (UINT)(Adapter->MissedPackets);
+ break;
+
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+
+ GenericULong = (UINT)(Adapter->FrameAlignmentErrors);
+ break;
+
+ case OID_802_3_XMIT_ONE_COLLISION:
+
+ GenericULong = (UINT)(Adapter->FramesXmitOneCollision);
+ break;
+
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+
+ GenericULong = (UINT)(Adapter->FramesXmitManyCollisions);
+ break;
+
+ default:
+
+ StatusToReturn = NDIS_STATUS_INVALID_OID;
+ break;
+
+ }
+
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS) {
+
+ if (MoveBytes > BytesLeft) {
+
+ //
+ // Not enough room in InformationBuffer. Punt
+ //
+
+ *BytesNeeded = MoveBytes;
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ } else {
+
+ //
+ // Store result.
+ //
+
+ NE2000_MOVE_MEM(InfoBuffer, MoveSource, MoveBytes);
+
+ (*BytesWritten) += MoveBytes;
+
+ }
+ }
+
+ return StatusToReturn;
+}
+
+extern
+NDIS_STATUS
+Ne2000SetInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ )
+
+/*++
+
+Routine Description:
+
+ NE2000SetInformation handles a set operation for a
+ single OID.
+
+Arguments:
+
+ MiniportAdapterContext - Context registered with the wrapper, really
+ a pointer to the adapter.
+
+ Oid - The OID of the set.
+
+ InformationBuffer - Holds the data to be set.
+
+ InformationBufferLength - The length of InformationBuffer.
+
+ BytesRead - If the call is successful, returns the number
+ of bytes read from InformationBuffer.
+
+ BytesNeeded - If there is not enough data in InformationBuffer
+ to satisfy the OID, returns the amount of storage needed.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_PENDING
+ NDIS_STATUS_INVALID_LENGTH
+ NDIS_STATUS_INVALID_OID
+
+--*/
+{
+ //
+ // Pointer to the adapter structure.
+ //
+ PNE2000_ADAPTER Adapter = (PNE2000_ADAPTER)MiniportAdapterContext;
+
+ //
+ // General Algorithm:
+ //
+ // Verify length
+ // Switch(Request)
+ // Process Request
+ //
+
+ UINT BytesLeft = InformationBufferLength;
+ PUCHAR InfoBuffer = (PUCHAR)(InformationBuffer);
+
+ //
+ // Variables for a particular request
+ //
+ UINT OidLength;
+
+ //
+ // Variables for holding the new values to be used.
+ //
+ ULONG LookAhead;
+ ULONG Filter;
+
+ //
+ // Status of the operation.
+ //
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+
+ IF_LOUD( DbgPrint("In SetInfo\n");)
+
+ //
+ // Get Oid and Length of request
+ //
+ OidLength = BytesLeft;
+
+ switch (Oid) {
+
+ case OID_802_3_MULTICAST_LIST:
+
+ //
+ // Verify length
+ //
+ if ((OidLength % NE2000_LENGTH_OF_ADDRESS) != 0){
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ *BytesRead = 0;
+ *BytesNeeded = 0;
+
+ break;
+
+ }
+
+ //
+ // Set the new list on the adapter.
+ //
+ NdisMoveMemory(Adapter->Addresses, InfoBuffer, OidLength);
+
+ //
+ // If we are currently receiving all multicast or
+ // we are promsicuous then we DO NOT call this, or
+ // it will reset thoes settings.
+ //
+ if
+ (
+ !(Adapter->PacketFilter & (NDIS_PACKET_TYPE_ALL_MULTICAST |
+ NDIS_PACKET_TYPE_PROMISCUOUS))
+ )
+ {
+ StatusToReturn = DispatchSetMulticastAddressList(Adapter);
+ }
+ else
+ {
+ //
+ // Our list of multicast addresses is kept by the
+ // wrapper.
+ //
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+ }
+
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ //
+ // Verify length
+ //
+
+ if (OidLength != 4 ) {
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ *BytesRead = 0;
+ *BytesNeeded = 0;
+
+ break;
+
+ }
+
+ NE2000_MOVE_MEM(&Filter, InfoBuffer, 4);
+
+ //
+ // Verify bits
+ //
+
+ if (Filter & (NDIS_PACKET_TYPE_SOURCE_ROUTING |
+ NDIS_PACKET_TYPE_SMT |
+ NDIS_PACKET_TYPE_MAC_FRAME |
+ NDIS_PACKET_TYPE_FUNCTIONAL |
+ NDIS_PACKET_TYPE_ALL_FUNCTIONAL |
+ NDIS_PACKET_TYPE_GROUP
+ )) {
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+
+ *BytesRead = 4;
+ *BytesNeeded = 0;
+
+ break;
+
+ }
+
+ //
+ // Set the new value on the adapter.
+ //
+ Adapter->PacketFilter = Filter;
+ StatusToReturn = DispatchSetPacketFilter(Adapter);
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ //
+ // Verify length
+ //
+
+ if (OidLength != 4) {
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ *BytesRead = 0;
+ *BytesNeeded = 0;
+
+ break;
+
+ }
+
+ //
+ // Store the new value.
+ //
+
+ NE2000_MOVE_MEM(&LookAhead, InfoBuffer, 4);
+
+ if (LookAhead <= NE2000_MAX_LOOKAHEAD) {
+ Adapter->MaxLookAhead = LookAhead;
+ } else {
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+ }
+
+ break;
+
+ default:
+
+ StatusToReturn = NDIS_STATUS_INVALID_OID;
+
+ *BytesRead = 0;
+ *BytesNeeded = 0;
+
+ break;
+
+ }
+
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS) {
+
+ *BytesRead = BytesLeft;
+ *BytesNeeded = 0;
+
+ }
+
+ return(StatusToReturn);
+}
+
+NDIS_STATUS
+DispatchSetPacketFilter(
+ IN PNE2000_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the appropriate bits in the adapter filters
+ and modifies the card Receive Configuration Register if needed.
+
+Arguments:
+
+ Adapter - Pointer to the adapter block
+
+Return Value:
+
+ The final status (always NDIS_STATUS_SUCCESS).
+
+Notes:
+
+ - Note that to receive all multicast packets the multicast
+ registers on the card must be filled with 1's. To be
+ promiscuous that must be done as well as setting the
+ promiscuous physical flag in the RCR. This must be done
+ as long as ANY protocol bound to this adapter has their
+ filter set accordingly.
+
+--*/
+
+
+{
+ //
+ // See what has to be put on the card.
+ //
+
+ if
+ (
+ Adapter->PacketFilter & (NDIS_PACKET_TYPE_ALL_MULTICAST |
+ NDIS_PACKET_TYPE_PROMISCUOUS)
+ )
+ {
+ //
+ // need "all multicast" now.
+ //
+ CardSetAllMulticast(Adapter); // fills it with 1's
+ }
+ else
+ {
+ //
+ // No longer need "all multicast".
+ //
+ DispatchSetMulticastAddressList(Adapter);
+ }
+
+ //
+ // The multicast bit in the RCR should be on if ANY protocol wants
+ // multicast/all multicast packets (or is promiscuous).
+ //
+ if
+ (
+ Adapter->PacketFilter & (NDIS_PACKET_TYPE_ALL_MULTICAST |
+ NDIS_PACKET_TYPE_MULTICAST |
+ NDIS_PACKET_TYPE_PROMISCUOUS)
+ )
+ {
+ Adapter->NicReceiveConfig |= RCR_MULTICAST;
+ }
+ else
+ {
+ Adapter->NicReceiveConfig &= ~RCR_MULTICAST;
+ }
+
+ //
+ // The promiscuous physical bit in the RCR should be on if ANY
+ // protocol wants to be promiscuous.
+ //
+ if (Adapter->PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS)
+ {
+ Adapter->NicReceiveConfig |= RCR_ALL_PHYS;
+ }
+ else
+ {
+ Adapter->NicReceiveConfig &= ~RCR_ALL_PHYS;
+ }
+
+ //
+ // The broadcast bit in the RCR should be on if ANY protocol wants
+ // broadcast packets (or is promiscuous).
+ //
+ if
+ (
+ Adapter->PacketFilter & (NDIS_PACKET_TYPE_BROADCAST |
+ NDIS_PACKET_TYPE_PROMISCUOUS)
+ )
+ {
+ Adapter->NicReceiveConfig |= RCR_BROADCAST;
+ }
+ else
+ {
+ Adapter->NicReceiveConfig &= ~RCR_BROADCAST;
+ }
+
+ CardSetReceiveConfig(Adapter);
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+
+NDIS_STATUS
+DispatchSetMulticastAddressList(
+ IN PNE2000_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the multicast list for this open
+
+Arguments:
+
+ Adapter - Pointer to the adapter block
+
+Return Value:
+
+ NDIS_STATUS_SUCESS
+
+Implementation Note:
+
+ When invoked, we are to make it so that the multicast list in the filter
+ package becomes the multicast list for the adapter. To do this, we
+ determine the required contents of the NIC multicast registers and
+ update them.
+
+
+--*/
+{
+ //
+ // Update the local copy of the NIC multicast regs and copy them to the NIC
+ //
+ CardFillMulticastRegs(Adapter);
+ CardCopyMulticastRegs(Adapter);
+
+ return NDIS_STATUS_SUCCESS;
+}
diff --git a/private/ntos/ndis/ne2000/ne2000.rc b/private/ntos/ndis/ne2000/ne2000.rc
new file mode 100644
index 000000000..03d7d099d
--- /dev/null
+++ b/private/ntos/ndis/ne2000/ne2000.rc
@@ -0,0 +1,39 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "Novell NE2000 network driver"
+#define VER_INTERNALNAME_STR "NE2000.SYS"
+#define VER_ORIGINALFILENAME_STR "NE2000.SYS"
+
+#include "common.ver"
+
diff --git a/private/ntos/ndis/ne2000/ne2000hw.h b/private/ntos/ndis/ne2000/ne2000hw.h
new file mode 100644
index 000000000..bab8e30dc
--- /dev/null
+++ b/private/ntos/ndis/ne2000/ne2000hw.h
@@ -0,0 +1,557 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ne2000hw.h
+
+Abstract:
+
+ The main program for an Ne2000 miniport driver.
+
+Author:
+
+ Sean Selitrennikoff
+
+Environment:
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+--*/
+
+#ifndef _NE2000HARDWARE_
+#define _NE2000HARDWARE_
+
+
+//
+// Definitions for supporting clone adapters.
+//
+
+//
+// Valid value ranges for the IoBaseAddress.
+//
+#ifdef NE1000
+#define MIN_IOBASEADDR 0x0200
+#else
+#define MIN_IOBASEADDR 0x0120
+#endif
+
+#define MAX_IOBASEADDR 0xc3d0
+
+
+
+//
+// Valid value ranges for the InterruptNumber.
+//
+#define MIN_IRQ 2
+
+#ifdef NE1000
+#define MAX_IRQ 9
+#else
+#define MAX_IRQ 15
+#endif
+
+
+//
+// Types of Ne2000 cards.
+//
+#define NE2000_ISA 0
+#define NE2000_PCMCIA 1
+
+//
+// ID for MCA Ne2000 clone cards
+//
+#define AE2_ADAPTER_ID 0x67b0
+#define UB_ADAPTER_ID 0x611f
+#define NE2_ADAPTER_ID 0x7154
+
+//
+// Microchannel IRQ POS register mask and shift count
+//
+#define MC_IRQ_MASK 0x60
+#define MC_IRQ_MASK_UB 0x0E
+
+
+//
+// Microchannel I/O base address mask and shift count
+//
+#define MC_IO_BASE_MASK 0x0E
+#define MC_IO_BASE_MASK_UB 0xE0
+
+//
+// Default value for Adapter->IoBaseAddr
+//
+#define DEFAULT_IOBASEADDR (PVOID)0x300
+
+#define CIS_NET_ADDR_OFFSET 0xff0
+
+//
+// Default value for Adapter->InterruptNumber
+//
+#define DEFAULT_INTERRUPTNUMBER 3
+
+
+//
+// Default value for Adapter->MulticastListMax
+//
+#define DEFAULT_MULTICASTLISTMAX 8
+
+
+//
+// Offsets from Adapter->IoPAddr of the ports used to access
+// the 8390 NIC registers.
+//
+// The names in parenthesis are the abbreviations by which
+// the registers are referred to in the 8390 data sheet.
+//
+// Some of the offsets appear more than once
+// because they have have relevant page 0 and page 1 values,
+// or they are different registers when read than they are
+// when written. The notation MSB indicates that only the
+// MSB can be set for this register, the LSB is assumed 0.
+//
+
+#define NIC_COMMAND 0x0 // (CR)
+#define NIC_PAGE_START 0x1 // (PSTART) MSB, write-only
+#define NIC_PHYS_ADDR 0x1 // (PAR0) page 1
+#define NIC_PAGE_STOP 0x2 // (PSTOP) MSB, write-only
+#define NIC_BOUNDARY 0x3 // (BNRY) MSB
+#define NIC_XMIT_START 0x4 // (TPSR) MSB, write-only
+#define NIC_XMIT_STATUS 0x4 // (TSR) read-only
+#define NIC_XMIT_COUNT_LSB 0x5 // (TBCR0) write-only
+#define NIC_XMIT_COUNT_MSB 0x6 // (TBCR1) write-only
+#define NIC_FIFO 0x6 // (FIFO) read-only
+#define NIC_INTR_STATUS 0x7 // (ISR)
+#define NIC_CURRENT 0x7 // (CURR) page 1
+#define NIC_MC_ADDR 0x8 // (MAR0) page 1
+#define NIC_CRDA_LSB 0x8 // (CRDA0)
+#define NIC_RMT_ADDR_LSB 0x8 // (RSAR0)
+#define NIC_CRDA_MSB 0x9 // (CRDA1)
+#define NIC_RMT_ADDR_MSB 0x9 // (RSAR1)
+#define NIC_RMT_COUNT_LSB 0xa // (RBCR0) write-only
+#define NIC_RMT_COUNT_MSB 0xb // (RBCR1) write-only
+#define NIC_RCV_CONFIG 0xc // (RCR) write-only
+#define NIC_RCV_STATUS 0xc // (RSR) read-only
+#define NIC_XMIT_CONFIG 0xd // (TCR) write-only
+#define NIC_FAE_ERR_CNTR 0xd // (CNTR0) read-only
+#define NIC_DATA_CONFIG 0xe // (DCR) write-only
+#define NIC_CRC_ERR_CNTR 0xe // (CNTR1) read-only
+#define NIC_INTR_MASK 0xf // (IMR) write-only
+#define NIC_MISSED_CNTR 0xf // (CNTR2) read-only
+#define NIC_RACK_NIC 0x10 // Byte to read or write
+#define NIC_RESET 0x1f // (RESET)
+
+
+//
+// Constants for the NIC_COMMAND register.
+//
+// Start/stop the card, start transmissions, and select
+// which page of registers was seen through the ports.
+//
+
+#define CR_STOP (UCHAR)0x01 // reset the card
+#define CR_START (UCHAR)0x02 // start the card
+#define CR_XMIT (UCHAR)0x04 // begin transmission
+#define CR_NO_DMA (UCHAR)0x20 // stop remote DMA
+
+#define CR_PS0 (UCHAR)0x40 // low bit of page number
+#define CR_PS1 (UCHAR)0x80 // high bit of page number
+#define CR_PAGE0 (UCHAR)0x00 // select page 0
+#define CR_PAGE1 CR_PS0 // select page 1
+#define CR_PAGE2 CR_PS1 // select page 2
+
+#define CR_DMA_WRITE (UCHAR)0x10 // Write
+#define CR_DMA_READ (UCHAR)0x08 // Read
+#define CR_SEND (UCHAR)0x18 // send
+
+
+//
+// Constants for the NIC_XMIT_STATUS register.
+//
+// Indicate the result of a packet transmission.
+//
+
+#define TSR_XMIT_OK (UCHAR)0x01 // transmit with no errors
+#define TSR_COLLISION (UCHAR)0x04 // collided at least once
+#define TSR_ABORTED (UCHAR)0x08 // too many collisions
+#define TSR_NO_CARRIER (UCHAR)0x10 // carrier lost
+#define TSR_NO_CDH (UCHAR)0x40 // no collision detect heartbeat
+
+
+//
+// Constants for the NIC_INTR_STATUS register.
+//
+// Indicate the cause of an interrupt.
+//
+
+#define ISR_EMPTY (UCHAR)0x00 // no bits set in ISR
+#define ISR_RCV (UCHAR)0x01 // packet received with no errors
+#define ISR_XMIT (UCHAR)0x02 // packet transmitted with no errors
+#define ISR_RCV_ERR (UCHAR)0x04 // error on packet reception
+#define ISR_XMIT_ERR (UCHAR)0x08 // error on packet transmission
+#define ISR_OVERFLOW (UCHAR)0x10 // receive buffer overflow
+#define ISR_COUNTER (UCHAR)0x20 // MSB set on tally counter
+#define ISR_DMA_DONE (UCHAR)0x40 // RDC
+#define ISR_RESET (UCHAR)0x80 // (not an interrupt) card is reset
+
+
+//
+// Constants for the NIC_RCV_CONFIG register.
+//
+// Configure what type of packets are received.
+//
+
+#define RCR_REJECT_ERR (UCHAR)0x00 // reject error packets
+#define RCR_BROADCAST (UCHAR)0x04 // receive broadcast packets
+#define RCR_MULTICAST (UCHAR)0x08 // receive multicast packets
+#define RCR_ALL_PHYS (UCHAR)0x10 // receive ALL directed packets
+#define RCR_MONITOR (UCHAR)0x20 // don't collect packets
+
+
+//
+// Constants for the NIC_RCV_STATUS register.
+//
+// Indicate the status of a received packet.
+//
+// These are also used to interpret the status byte in the
+// packet header of a received packet.
+//
+
+#define RSR_PACKET_OK (UCHAR)0x01 // packet received with no errors
+#define RSR_CRC_ERROR (UCHAR)0x02 // packet received with CRC error
+#define RSR_MULTICAST (UCHAR)0x20 // packet received was multicast
+#define RSR_DISABLED (UCHAR)0x40 // received is disabled
+#define RSR_DEFERRING (UCHAR)0x80 // receiver is deferring
+
+
+//
+// Constants for the NIC_XMIT_CONFIG register.
+//
+// Configures how packets are transmitted.
+//
+
+#define TCR_NO_LOOPBACK (UCHAR)0x00 // normal operation
+#define TCR_LOOPBACK (UCHAR)0x02 // loopback (set when NIC is stopped)
+
+#define TCR_INHIBIT_CRC (UCHAR)0x01 // inhibit appending of CRC
+
+#define TCR_NIC_LBK (UCHAR)0x02 // loopback through the NIC
+#define TCR_SNI_LBK (UCHAR)0x04 // loopback through the SNI
+#define TCR_COAX_LBK (UCHAR)0x06 // loopback to the coax
+
+
+//
+// Constants for the NIC_DATA_CONFIG register.
+//
+// Set data transfer sizes.
+//
+
+#define DCR_BYTE_WIDE (UCHAR)0x00 // byte-wide DMA transfers
+#define DCR_WORD_WIDE (UCHAR)0x01 // word-wide DMA transfers
+
+#define DCR_LOOPBACK (UCHAR)0x00 // loopback mode (TCR must be set)
+#define DCR_NORMAL (UCHAR)0x08 // normal operation
+
+#define DCR_FIFO_2_BYTE (UCHAR)0x00 // 2-byte FIFO threshhold
+#define DCR_FIFO_4_BYTE (UCHAR)0x20 // 4-byte FIFO threshhold
+#define DCR_FIFO_8_BYTE (UCHAR)0x40 // 8-byte FIFO threshhold
+#define DCR_FIFO_12_BYTE (UCHAR)0x60 // 12-byte FIFO threshhold
+#define DCR_AUTO_INIT (UCHAR)0x10 // Auto-init to remove packets from ring
+
+
+//
+// Constants for the NIC_INTR_MASK register.
+//
+// Configure which ISR settings actually cause interrupts.
+//
+
+#define IMR_RCV (UCHAR)0x01 // packet received with no errors
+#define IMR_XMIT (UCHAR)0x02 // packet transmitted with no errors
+#define IMR_RCV_ERR (UCHAR)0x04 // error on packet reception
+#define IMR_XMIT_ERR (UCHAR)0x08 // error on packet transmission
+#define IMR_OVERFLOW (UCHAR)0x10 // receive buffer overflow
+#define IMR_COUNTER (UCHAR)0x20 // MSB set on tally counter
+
+
+//++
+//
+// VOID
+// CardStart(
+// IN PNE2000_ADAPTER Adapter
+// )
+//
+//
+// Routine Description:
+//
+// Starts the card.
+//
+// Arguments:
+//
+// Adapter - pointer to the adapter block
+//
+// Return Value:
+//
+// None.
+//
+//--
+ //
+ // Assume that the card has been stopped as in CardStop.
+ //
+
+#define CardStart(Adapter) \
+ NdisRawWritePortUchar(((Adapter->IoPAddr)+NIC_XMIT_CONFIG), TCR_NO_LOOPBACK)
+
+
+
+//++
+//
+// VOID
+// CardSetAllMulticast(
+// IN PNE2000_ADAPTER Adapter
+// )
+//
+// Routine Description:
+//
+// Enables every bit in the card multicast bit mask.
+// Calls SyncCardSetAllMulticast.
+//
+// Arguments:
+//
+// Adapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardSetAllMulticast(Adapter) \
+ NdisMSynchronizeWithInterrupt(&(Adapter)->Interrupt, \
+ SyncCardSetAllMulticast, (PVOID)(Adapter))
+
+
+//++
+//
+// VOID
+// CardCopyMulticastRegs(
+// IN PNE2000_ADAPTER Adapter
+// )
+//
+// Routine Description:
+//
+// Writes out the entire multicast bit mask to the card from
+// Adapter->NicMulticastRegs. Calls SyncCardCopyMulticastRegs.
+//
+// Arguments:
+//
+// Adapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardCopyMulticastRegs(Adapter) \
+ NdisMSynchronizeWithInterrupt(&(Adapter)->Interrupt, \
+ SyncCardCopyMulticastRegs, (PVOID)(Adapter))
+
+
+
+//++
+//
+// VOID
+// CardGetInterruptStatus(
+// IN PNE2000_ADAPTER Adapter,
+// OUT PUCHAR InterrupStatus
+// )
+//
+// Routine Description:
+//
+// Reads the interrupt status (ISR) register from the card. Only
+// called at IRQL INTERRUPT_LEVEL.
+//
+// Arguments:
+//
+// Adapter - The adapter block.
+//
+// InterruptStatus - Returns the value of ISR.
+//
+// Return Value:
+//
+//--
+
+#define CardGetInterruptStatus(_Adapter,_InterruptStatus) \
+ NdisRawReadPortUchar(((_Adapter)->IoPAddr+NIC_INTR_STATUS), (_InterruptStatus))
+
+
+//++
+//
+// VOID
+// CardSetReceiveConfig(
+// IN PNE2000_ADAPTER Adapter
+// )
+//
+// Routine Description:
+//
+// Sets the receive configuration (RCR) register on the card.
+// The value used is Adapter->NicReceiveConfig. Calls
+// SyncCardSetReceiveConfig.
+//
+// Arguments:
+//
+// Adapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardSetReceiveConfig(Adapter) \
+ NdisMSynchronizeWithInterrupt(&(Adapter)->Interrupt, \
+ SyncCardSetReceiveConfig, (PVOID)(Adapter))
+
+
+//++
+//
+// VOID
+// CardBlockInterrupts(
+// IN PNE2000_ADAPTER Adapter
+// )
+//
+// Routine Description:
+//
+// Blocks all interrupts from the card by clearing the
+// interrupt mask (IMR) register. Only called from
+// IRQL INTERRUPT_LEVEL.
+//
+// Arguments:
+//
+// Adapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardBlockInterrupts(Adapter) \
+ NdisRawWritePortUchar(((Adapter)->IoPAddr+NIC_INTR_MASK), 0)
+
+
+//++
+//
+// VOID
+// CardUnblockInterrupts(
+// IN PNE2000_ADAPTER Adapter
+// )
+//
+// Routine Description:
+//
+// Unblocks all interrupts from the card by setting the
+// interrupt mask (IMR) register. Only called from IRQL
+// INTERRUPT_LEVEL.
+//
+// Arguments:
+//
+// Adapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardUnblockInterrupts(Adapter) \
+ NdisRawWritePortUchar(\
+ ((Adapter)->IoPAddr+NIC_INTR_MASK), \
+ (Adapter)->NicInterruptMask)
+
+//++
+//
+// VOID
+// CardAcknowledgeOverflowInterrupt(
+// IN PNE2000_ADAPTER Adapter
+// )
+//
+// Routine Description:
+//
+// Acknowledges an overflow interrupt by setting the bit in
+// the interrupt status (ISR) register. Calls
+// SyncCardAcknowledgeOverflow.
+//
+// Arguments:
+//
+// Adapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardAcknowledgeOverflowInterrupt(Adapter) \
+ SyncCardAcknowledgeOverflow(Adapter)
+
+
+//++
+//
+// VOID
+// CardAcknowledgeCounterInterrupt(
+// IN PNE2000_ADAPTER Adapter
+// )
+//
+// Routine Description:
+//
+// Acknowledges a counter interrupt by setting the bit in
+// the interrupt status (ISR) register.
+//
+// Arguments:
+//
+// Adapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardAcknowledgeCounterInterrupt(Adapter) \
+ NdisRawWritePortUchar(((Adapter)->IoPAddr+NIC_INTR_STATUS), ISR_COUNTER)
+
+//++
+//
+// VOID
+// CardUpdateCounters(
+// IN PNE2000_ADAPTER Adapter
+// )
+//
+// Routine Description:
+//
+// Updates the values of the three counters (frame alignment
+// errors, CRC errors, and missed packets) by reading in their
+// current values from the card and adding them to the ones
+// stored in the Adapter structure. Calls SyncCardUpdateCounters.
+//
+// Arguments:
+//
+// Adapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardUpdateCounters(Adapter) \
+ NdisMSynchronizeWithInterrupt(&(Adapter)->Interrupt, \
+ SyncCardUpdateCounters, (PVOID)(Adapter))
+
+
+#endif // _NE2000HARDWARE_
diff --git a/private/ntos/ndis/ne2000/ne2000sw.h b/private/ntos/ndis/ne2000/ne2000sw.h
new file mode 100644
index 000000000..02e982136
--- /dev/null
+++ b/private/ntos/ndis/ne2000/ne2000sw.h
@@ -0,0 +1,877 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ne2000sw.h
+
+Abstract:
+
+ The main header for an Novell 2000 Miniport driver.
+
+Author:
+
+ Sean Selitrennikoff
+
+Environment:
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+--*/
+
+#ifndef _NE2000SFT_
+#define _NE2000SFT_
+
+#define NE2000_NDIS_MAJOR_VERSION 3
+#define NE2000_NDIS_MINOR_VERSION 0
+
+//
+// This macro is used along with the flags to selectively
+// turn on debugging.
+//
+
+#if DBG
+
+#define IF_NE2000DEBUG(f) if (Ne2000DebugFlag & (f))
+extern ULONG Ne2000DebugFlag;
+
+#define NE2000_DEBUG_LOUD 0x00000001 // debugging info
+#define NE2000_DEBUG_VERY_LOUD 0x00000002 // excessive debugging info
+#define NE2000_DEBUG_LOG 0x00000004 // enable Ne2000Log
+#define NE2000_DEBUG_CHECK_DUP_SENDS 0x00000008 // check for duplicate sends
+#define NE2000_DEBUG_TRACK_PACKET_LENS 0x00000010 // track directed packet lens
+#define NE2000_DEBUG_WORKAROUND1 0x00000020 // drop DFR/DIS packets
+#define NE2000_DEBUG_CARD_BAD 0x00000040 // dump data if CARD_BAD
+#define NE2000_DEBUG_CARD_TESTS 0x00000080 // print reason for failing
+
+//
+// Macro for deciding whether to print a lot of debugging information.
+//
+
+#define IF_LOUD(A) IF_NE2000DEBUG( NE2000_DEBUG_LOUD ) { A }
+#define IF_VERY_LOUD(A) IF_NE2000DEBUG( NE2000_DEBUG_VERY_LOUD ) { A }
+
+//
+// Whether to use the Ne2000Log buffer to record a trace of the driver.
+//
+#define IF_LOG(A) IF_NE2000DEBUG( NE2000_DEBUG_LOG ) { A }
+extern VOID Ne2000Log(UCHAR);
+
+//
+// Whether to do loud init failure
+//
+#define IF_INIT(A) A
+
+//
+// Whether to do loud card test failures
+//
+#define IF_TEST(A) IF_NE2000DEBUG( NE2000_DEBUG_CARD_TESTS ) { A }
+
+#else
+
+//
+// This is not a debug build, so make everything quiet.
+//
+#define IF_LOUD(A)
+#define IF_VERY_LOUD(A)
+#define IF_LOG(A)
+#define IF_INIT(A)
+#define IF_TEST(A)
+
+#endif
+
+
+
+
+//
+// Adapter->NumBuffers
+//
+// controls the number of transmit buffers on the packet.
+// Choices are 1 through 12.
+//
+
+#define DEFAULT_NUMBUFFERS 12
+
+
+//
+// Create a macro for moving memory from place to place. Makes
+// the code more readable and portable in case we ever support
+// a shared memory Ne2000 adapter.
+//
+#define NE2000_MOVE_MEM(dest,src,size) NdisMoveMemory(dest,src,size)
+
+//
+// The status of transmit buffers.
+//
+
+typedef enum {
+ EMPTY = 0x00,
+ FULL = 0x02
+} BUFFER_STATUS;
+
+//
+// Type of an interrupt.
+//
+
+typedef enum {
+ RECEIVE = 0x01,
+ TRANSMIT = 0x02,
+ OVERFLOW = 0x04,
+ COUNTER = 0x08,
+ UNKNOWN = 0x10
+} INTERRUPT_TYPE;
+
+//
+// Result of Ne2000IndicatePacket().
+//
+typedef enum {
+ INDICATE_OK,
+ SKIPPED,
+ ABORT,
+ CARD_BAD
+} INDICATE_STATUS;
+
+
+
+//
+// Size of the ethernet header
+//
+#define NE2000_HEADER_SIZE 14
+
+//
+// Size of the ethernet address
+//
+#define NE2000_LENGTH_OF_ADDRESS 6
+
+//
+// Number of bytes allowed in a lookahead (max)
+//
+#define NE2000_MAX_LOOKAHEAD (252 - NE2000_HEADER_SIZE)
+
+//
+// Maximum number of transmit buffers on the card.
+//
+#define MAX_XMIT_BUFS 12
+
+//
+// Definition of a transmit buffer.
+//
+typedef UINT XMIT_BUF;
+
+//
+// Number of 256-byte buffers in a transmit buffer.
+//
+#define BUFS_PER_TX 1
+
+//
+// Size of a single transmit buffer.
+//
+#define TX_BUF_SIZE (BUFS_PER_TX*256)
+
+
+
+
+//
+// This structure contains information about the driver
+// itself. There is only have one of these structures.
+//
+typedef struct _DRIVER_BLOCK {
+
+ //
+ // NDIS wrapper information.
+ //
+ NDIS_HANDLE NdisMacHandle; // returned from NdisRegisterMac
+ NDIS_HANDLE NdisWrapperHandle; // returned from NdisInitializeWrapper
+
+ //
+ // Adapters registered for this Miniport driver.
+ //
+ struct _NE2000_ADAPTER * AdapterQueue;
+
+} DRIVER_BLOCK, * PDRIVER_BLOCK;
+
+
+
+//
+// This structure contains all the information about a single
+// adapter that this driver is controlling.
+//
+typedef struct _NE2000_ADAPTER {
+
+ //
+ // This is the handle given by the wrapper for calling ndis
+ // functions.
+ //
+ NDIS_HANDLE MiniportAdapterHandle;
+
+ //
+ // Interrupt object.
+ //
+ NDIS_MINIPORT_INTERRUPT Interrupt;
+
+ //
+ // used by DriverBlock->AdapterQueue
+ //
+ struct _NE2000_ADAPTER * NextAdapter;
+
+ //
+ // This is a count of the number of receives that have been
+ // indicated in a row. This is used to limit the number
+ // of sequential receives so that one can periodically check
+ // for transmit complete interrupts.
+ //
+ ULONG ReceivePacketCount;
+
+ //
+ // Configuration information
+ //
+
+ //
+ // Number of buffer in this adapter.
+ //
+ UINT NumBuffers;
+
+ //
+ // Physical address of the IoBaseAddress
+ //
+ PVOID IoBaseAddr;
+
+ //
+ // Interrupt number this adapter is using.
+ //
+ CHAR InterruptNumber;
+
+ //
+ // Number of multicast addresses that this adapter is to support.
+ //
+ UINT MulticastListMax;
+
+ //
+ // The type of bus that this adapter is running on. Either ISA or
+ // MCA.
+ //
+ UCHAR BusType;
+
+ //
+ // InterruptType is the next interrupt that should be serviced.
+ //
+ UCHAR InterruptType;
+
+
+ //
+ // Type of ne2000 card.
+ //
+ UINT CardType;
+
+ //
+ // Address of the memory window.
+ //
+ ULONG AttributeMemoryAddress;
+ ULONG AttributeMemorySize;
+
+ //
+ // Transmit information.
+ //
+
+ //
+ // The next available empty transmit buffer.
+ //
+ XMIT_BUF NextBufToFill;
+
+ //
+ // The next full transmit buffer waiting to transmitted. This
+ // is valid only if CurBufXmitting is -1
+ //
+ XMIT_BUF NextBufToXmit;
+
+ //
+ // This transmit buffer that is currently transmitting. If none,
+ // then the value is -1.
+ //
+ XMIT_BUF CurBufXmitting;
+
+ //
+ // TRUE if a transmit has been started, and have not received the
+ // corresponding transmit complete interrupt.
+ //
+ BOOLEAN TransmitInterruptPending;
+
+ //
+ // TRUE if a receive buffer overflow occurs while a
+ // transmit complete interrupt was pending.
+ //
+ BOOLEAN OverflowRestartXmitDpc;
+
+ //
+ // The current status of each transmit buffer.
+ //
+ BUFFER_STATUS BufferStatus[MAX_XMIT_BUFS];
+
+ //
+ // Used to map packets to transmit buffers and visa-versa.
+ //
+ PNDIS_PACKET Packets[MAX_XMIT_BUFS];
+
+ //
+ // The length of each packet in the Packets list.
+ //
+ UINT PacketLens[MAX_XMIT_BUFS];
+
+ //
+ // The first packet we have pending.
+ //
+ PNDIS_PACKET FirstPacket;
+
+ //
+ // The tail of the pending queue.
+ //
+ PNDIS_PACKET LastPacket;
+
+ //
+ // The address of the start of the transmit buffer space.
+ //
+ PUCHAR XmitStart;
+
+ //
+ // The address of the start of the receive buffer space.
+ PUCHAR PageStart;
+
+ //
+ // The address of the end of the receive buffer space.
+ //
+ PUCHAR PageStop;
+
+ //
+ // Status of the last transmit.
+ //
+ UCHAR XmitStatus;
+
+ //
+ // The value to write to the adapter for the start of
+ // the transmit buffer space.
+ //
+ UCHAR NicXmitStart;
+
+ //
+ // The value to write to the adapter for the start of
+ // the receive buffer space.
+ //
+ UCHAR NicPageStart;
+
+ //
+ // The value to write to the adapter for the end of
+ // the receive buffer space.
+ //
+ UCHAR NicPageStop;
+
+
+
+
+ //
+ // Receive information
+ //
+
+ //
+ // The value to write to the adapter for the next receive
+ // buffer that is free.
+ //
+ UCHAR NicNextPacket;
+
+ //
+ // The next receive buffer that will be filled.
+ //
+ UCHAR Current;
+
+ //
+ // Total length of a received packet.
+ //
+ UINT PacketLen;
+
+
+
+
+ //
+ // Operational information.
+ //
+
+ //
+ // Mapped address of the base io port.
+ //
+ ULONG IoPAddr;
+
+ //
+ // InterruptStatus tracks interrupt sources that still need to be serviced,
+ // it is the logical OR of all card interrupts that have been received and not
+ // processed and cleared. (see also INTERRUPT_TYPE definition in ne2000.h)
+ //
+ UCHAR InterruptStatus;
+
+ //
+ // The ethernet address currently in use.
+ //
+ UCHAR StationAddress[NE2000_LENGTH_OF_ADDRESS];
+
+ //
+ // The ethernet address that is burned into the adapter.
+ //
+ UCHAR PermanentAddress[NE2000_LENGTH_OF_ADDRESS];
+
+ //
+ // The adapter space address of the start of on board memory.
+ //
+ PUCHAR RamBase;
+
+ //
+ // The number of K on the adapter.
+ //
+ ULONG RamSize;
+
+ //
+ // The current packet filter in use.
+ //
+ ULONG PacketFilter;
+
+ //
+ // TRUE if a receive buffer overflow occured.
+ //
+ BOOLEAN BufferOverflow;
+
+ //
+ // TRUE if the driver needs to call NdisMEthIndicateReceiveComplete
+ //
+ BOOLEAN IndicateReceiveDone;
+
+ //
+ // TRUE if this is an NE2000 in an eight bit slot.
+ //
+ BOOLEAN EightBitSlot;
+
+
+ //
+ // Statistics used by Set/QueryInformation.
+ //
+
+ ULONG FramesXmitGood; // Good Frames Transmitted
+ ULONG FramesRcvGood; // Good Frames Received
+ ULONG FramesXmitBad; // Bad Frames Transmitted
+ ULONG FramesXmitOneCollision; // Frames Transmitted with one collision
+ ULONG FramesXmitManyCollisions; // Frames Transmitted with > 1 collision
+ ULONG FrameAlignmentErrors; // FAE errors counted
+ ULONG CrcErrors; // CRC errors counted
+ ULONG MissedPackets; // missed packet counted
+
+ //
+ // Reset information.
+ //
+
+ UCHAR NicMulticastRegs[8]; // contents of card multicast registers
+ UCHAR NicReceiveConfig; // contents of NIC RCR
+ UCHAR NicInterruptMask; // contents of NIC IMR
+
+ //
+ // The lookahead buffer size in use.
+ //
+ ULONG MaxLookAhead;
+
+ //
+ // These are for the current packet being indicated.
+ //
+
+ //
+ // The NIC appended header. Used to find corrupted receive packets.
+ //
+ UCHAR PacketHeader[4];
+
+ //
+ // Ne2000 address of the beginning of the packet.
+ //
+ PUCHAR PacketHeaderLoc;
+
+ //
+ // Lookahead buffer
+ //
+ UCHAR Lookahead[NE2000_MAX_LOOKAHEAD + NE2000_HEADER_SIZE];
+
+ //
+ // List of multicast addresses in use.
+ //
+ CHAR Addresses[DEFAULT_MULTICASTLISTMAX][NE2000_LENGTH_OF_ADDRESS];
+
+} NE2000_ADAPTER, * PNE2000_ADAPTER;
+
+
+
+//
+// Given a MiniportContextHandle return the PNE2000_ADAPTER
+// it represents.
+//
+#define PNE2000_ADAPTER_FROM_CONTEXT_HANDLE(Handle) \
+ ((PNE2000_ADAPTER)(Handle))
+
+//
+// Given a pointer to a NE2000_ADAPTER return the
+// proper MiniportContextHandle.
+//
+#define CONTEXT_HANDLE_FROM_PNE2000_ADAPTER(Ptr) \
+ ((NDIS_HANDLE)(Ptr))
+
+//
+// Macros to extract high and low bytes of a word.
+//
+#define MSB(Value) ((UCHAR)((((ULONG)Value) >> 8) & 0xff))
+#define LSB(Value) ((UCHAR)(((ULONG)Value) & 0xff))
+
+//
+// What we map into the reserved section of a packet.
+// Cannot be more than 8 bytes (see ASSERT in ne2000.c).
+//
+typedef struct _MINIPORT_RESERVED {
+ PNDIS_PACKET Next; // used to link in the queues (4 bytes)
+} MINIPORT_RESERVED, * PMINIPORT_RESERVED;
+
+
+//
+// Retrieve the MINIPORT_RESERVED structure from a packet.
+//
+#define RESERVED(Packet) ((PMINIPORT_RESERVED)((Packet)->MiniportReserved))
+
+//
+// Procedures which log errors.
+//
+
+typedef enum _NE2000_PROC_ID {
+ cardReset,
+ cardCopyDownPacket,
+ cardCopyDownBuffer,
+ cardCopyUp
+} NE2000_PROC_ID;
+
+
+//
+// Special error log codes.
+//
+#define NE2000_ERRMSG_CARD_SETUP (ULONG)0x01
+#define NE2000_ERRMSG_DATA_PORT_READY (ULONG)0x02
+#define NE2000_ERRMSG_HANDLE_XMIT_COMPLETE (ULONG)0x04
+
+//
+// Declarations for functions in ne2000.c.
+//
+NDIS_STATUS
+Ne2000SetInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ );
+
+VOID
+Ne2000Halt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+NDIS_STATUS
+Ne2000RegisterAdapter(
+ IN PNE2000_ADAPTER Adapter,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN BOOLEAN ConfigError,
+ IN ULONG ConfigErrorValue
+ );
+
+NDIS_STATUS
+Ne2000Initialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE ConfigurationHandle
+ );
+
+NDIS_STATUS
+Ne2000TransferData(
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+ );
+
+NDIS_STATUS
+Ne2000Send(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET Packet,
+ IN UINT Flags
+ );
+
+NDIS_STATUS
+Ne2000Reset(
+ OUT PBOOLEAN AddressingReset,
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+NDIS_STATUS
+Ne2000QueryInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+ );
+
+VOID
+Ne2000Halt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+VOID
+OctogmetusceratorRevisited(
+ IN PNE2000_ADAPTER Adapter
+ );
+
+NDIS_STATUS
+DispatchSetPacketFilter(
+ IN PNE2000_ADAPTER Adapter
+ );
+
+NDIS_STATUS
+DispatchSetMulticastAddressList(
+ IN PNE2000_ADAPTER Adapter
+ );
+
+
+//
+// Interrup.c
+//
+
+VOID
+Ne2000EnableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+VOID
+Ne2000DisableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+VOID
+Ne2000Isr(
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueDpc,
+ IN PVOID Context
+ );
+
+VOID
+Ne2000HandleInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+BOOLEAN
+Ne2000PacketOK(
+ IN PNE2000_ADAPTER Adapter
+ );
+
+VOID
+Ne2000XmitDpc(
+ IN PNE2000_ADAPTER Adapter
+ );
+
+BOOLEAN
+Ne2000RcvDpc(
+ IN PNE2000_ADAPTER Adapter
+ );
+
+
+//
+// Declarations of functions in card.c.
+//
+
+BOOLEAN
+CardCheckParameters(
+ IN PNE2000_ADAPTER Adapter
+ );
+
+BOOLEAN
+CardInitialize(
+ IN PNE2000_ADAPTER Adapter
+ );
+
+BOOLEAN
+CardReadEthernetAddress(
+ IN PNE2000_ADAPTER Adapter
+ );
+
+BOOLEAN
+CardSetup(
+ IN PNE2000_ADAPTER Adapter
+ );
+
+VOID
+CardStop(
+ IN PNE2000_ADAPTER Adapter
+ );
+
+BOOLEAN
+CardTest(
+ IN PNE2000_ADAPTER Adapter
+ );
+
+BOOLEAN
+CardReset(
+ IN PNE2000_ADAPTER Adapter
+ );
+
+BOOLEAN
+CardCopyDownPacket(
+ IN PNE2000_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet,
+ OUT UINT * Length
+ );
+
+BOOLEAN
+CardCopyDown(
+ IN PNE2000_ADAPTER Adapter,
+ IN PUCHAR TargetBuffer,
+ IN PUCHAR SourceBuffer,
+ IN UINT Length
+ );
+
+BOOLEAN
+CardCopyUp(
+ IN PNE2000_ADAPTER Adapter,
+ IN PUCHAR Target,
+ IN PUCHAR Source,
+ IN UINT Length
+ );
+
+ULONG
+CardComputeCrc(
+ IN PUCHAR Buffer,
+ IN UINT Length
+ );
+
+VOID
+CardGetPacketCrc(
+ IN PUCHAR Buffer,
+ IN UINT Length,
+ OUT UCHAR Crc[4]
+ );
+
+VOID
+CardGetMulticastBit(
+ IN UCHAR Address[NE2000_LENGTH_OF_ADDRESS],
+ OUT UCHAR * Byte,
+ OUT UCHAR * Value
+ );
+
+VOID
+CardFillMulticastRegs(
+ IN PNE2000_ADAPTER Adapter
+ );
+
+VOID
+CardSetBoundary(
+ IN PNE2000_ADAPTER Adapter
+ );
+
+VOID
+CardStartXmit(
+ IN PNE2000_ADAPTER Adapter
+ );
+
+BOOLEAN
+SyncCardStop(
+ IN PVOID SynchronizeContext
+ );
+
+BOOLEAN
+SyncCardGetXmitStatus(
+ IN PVOID SynchronizeContext
+ );
+
+BOOLEAN
+SyncCardGetCurrent(
+ IN PVOID SynchronizeContext
+ );
+
+BOOLEAN
+SyncCardSetReceiveConfig(
+ IN PVOID SynchronizeContext
+ );
+
+BOOLEAN
+SyncCardSetAllMulticast(
+ IN PVOID SynchronizeContext
+ );
+
+BOOLEAN
+SyncCardCopyMulticastRegs(
+ IN PVOID SynchronizeContext
+ );
+
+BOOLEAN
+SyncCardSetInterruptMask(
+ IN PVOID SynchronizeContext
+ );
+
+BOOLEAN
+SyncCardAcknowledgeOverflow(
+ IN PVOID SynchronizeContext
+ );
+
+BOOLEAN
+SyncCardUpdateCounters(
+ IN PVOID SynchronizeContext
+ );
+
+BOOLEAN
+SyncCardHandleOverflow(
+ IN PVOID SynchronizeContext
+ );
+
+/*++
+
+Routine Description:
+
+ Determines the type of the interrupt on the card. The order of
+ importance is overflow, then transmit complete, then receive.
+ Counter MSB is handled first since it is simple.
+
+Arguments:
+
+ Adapter - pointer to the adapter block
+
+ InterruptStatus - Current Interrupt Status.
+
+Return Value:
+
+ The type of the interrupt
+
+--*/
+#define CARD_GET_INTERRUPT_TYPE(_A, _I) \
+ (_I & ISR_COUNTER) ? \
+ COUNTER : \
+ (_I & ISR_OVERFLOW ) ? \
+ SyncCardUpdateCounters(_A), OVERFLOW : \
+ (_I & (ISR_XMIT|ISR_XMIT_ERR)) ? \
+ TRANSMIT : \
+ (_I & ISR_RCV) ? \
+ RECEIVE : \
+ (_I & ISR_RCV_ERR) ? \
+ SyncCardUpdateCounters(_A), RECEIVE : \
+ UNKNOWN
+
+#endif // NE2000SFT
+
diff --git a/private/ntos/ndis/ne2000/sources b/private/ntos/ndis/ne2000/sources
new file mode 100644
index 000000000..2e59e695d
--- /dev/null
+++ b/private/ntos/ndis/ne2000/sources
@@ -0,0 +1,45 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=ne2000
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER -DNE2000
+
+INCLUDES=..\..\inc
+
+SOURCES=interrup.c \
+ ne2000.c \
+ card.c \
+ ne2000.rc
+
+RELATIVE_DEPTH=..\..
+
+MSC_WARNING_LEVEL=/W3 /WX
diff --git a/private/ntos/ndis/ne3200/command.c b/private/ntos/ndis/ne3200/command.c
new file mode 100644
index 000000000..1e3bee680
--- /dev/null
+++ b/private/ntos/ndis/ne3200/command.c
@@ -0,0 +1,272 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ command.c
+
+Abstract:
+
+ This file contains the code for managing Command Blocks on the
+ NE3200's Command Queue.
+
+Author:
+
+ Keith Moore (KeithMo) 07-Feb-1991
+
+Environment:
+
+Revision History:
+
+
+--*/
+
+#include <ne3200sw.h>
+
+
+VOID
+FASTCALL
+Ne3200Stall(
+ PULONG Dummy
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to cause the processor to spin momentarily,
+ without actually having to stall for a full microsecond, as in
+ NdisStallExecution.
+
+Arguments:
+
+ Dummy - A variable to increment.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ (*Dummy)++;
+}
+
+
+VOID
+NE3200AcquirePublicCommandBlock(
+ IN PNE3200_ADAPTER Adapter,
+ OUT PNE3200_SUPER_COMMAND_BLOCK * CommandBlock
+ )
+
+/*++
+
+Routine Description:
+
+ Gets a public command block.
+
+Arguments:
+
+ Adapter - The adapter that points to the ring entry structures.
+
+ CommandBlock - Will receive a pointer to a Command Block.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // This is a pointer to the "public" Command Block.
+ //
+ PNE3200_SUPER_COMMAND_BLOCK PublicCommandBlock =
+ Adapter->PublicCommandQueue + Adapter->NextPublicCommandBlock;
+
+
+ ASSERT(Adapter->NumberOfPublicCommandBlocks > 0);
+
+ //
+ // Remove a command block count.
+ //
+ Adapter->NumberOfPublicCommandBlocks--;
+
+ //
+ // Initialize the Command Block.
+ //
+ NdisZeroMemory(
+ PublicCommandBlock,
+ sizeof(NE3200_SUPER_COMMAND_BLOCK)
+ );
+
+ PublicCommandBlock->Hardware.NextPending = NE3200_NULL;
+ PublicCommandBlock->AvailableCommandBlockCounter =
+ &Adapter->NumberOfPublicCommandBlocks;
+ NdisSetPhysicalAddressLow(
+ PublicCommandBlock->Self,
+ NdisGetPhysicalAddressLow(Adapter->PublicCommandQueuePhysical) +
+ Adapter->NextPublicCommandBlock * sizeof(NE3200_SUPER_COMMAND_BLOCK));
+
+ //
+ // Increment to next command block
+ //
+ Adapter->NextPublicCommandBlock++;
+ if (Adapter->NextPublicCommandBlock == NE3200_NUMBER_OF_PUBLIC_CMD_BLOCKS) {
+ Adapter->NextPublicCommandBlock = 0;
+ }
+
+ IF_LOG('q');
+
+ //
+ // Return the Command Block pointer.
+ //
+ *CommandBlock = PublicCommandBlock;
+
+ IF_NE3200DBG(ACQUIRE) {
+
+ DPrint2(
+ "Acquired public command block @ %08lX\n",
+ (ULONG)PublicCommandBlock
+ );
+
+ }
+
+}
+
+
+VOID
+FASTCALL
+NE3200RelinquishCommandBlock(
+ IN PNE3200_ADAPTER Adapter,
+ IN PNE3200_SUPER_COMMAND_BLOCK CommandBlock
+ )
+
+/*++
+
+Routine Description:
+
+ Relinquish the Command Block resource. If this is a "public"
+ Command Block, then update the CommandQueue. If this is a
+ "private" Command Block, then free to the private command queue.
+
+Arguments:
+
+ Adapter - The adapter that owns the Command Block.
+
+ CommandBlock - The Command Block to relinquish.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IF_NE3200DBG(SUBMIT) {
+
+ DPrint2(
+ "Relinquishing command @ %08lX\n",
+ (ULONG)NdisGetPhysicalAddressLow(CommandBlock->Self)
+ );
+
+ }
+
+ //
+ // If this is the last pending command block, then we
+ // can remove the adapter's last pending command pointer.
+ //
+ if (CommandBlock == Adapter->LastCommandOnCard) {
+
+ //
+ // If there is another waiting chain of commands -- submit those
+ //
+ if (Adapter->FirstWaitingCommand != NULL) {
+
+ //
+ // Move the chain to the on card queue.
+ //
+ Adapter->FirstCommandOnCard = Adapter->FirstWaitingCommand;
+ Adapter->LastCommandOnCard = Adapter->LastWaitingCommand;
+ Adapter->FirstWaitingCommand = NULL;
+
+ IF_NE3200DBG(SUBMIT) {
+
+ DPrint2(
+ "Starting command @ %08lX\n",
+ (ULONG)NdisGetPhysicalAddressLow(Adapter->FirstCommandOnCard->Self)
+ );
+
+ }
+
+ //
+ // Submit this command chain to the card.
+ //
+ NE3200_WRITE_COMMAND_POINTER(
+ Adapter,
+ NdisGetPhysicalAddressLow(Adapter->FirstCommandOnCard->Self)
+ );
+
+ //
+ // Stall momentarily for the adapter to get the command.
+ //
+ {
+ ULONG i;
+ Ne3200Stall(&i);
+ }
+
+ //
+ // Inform the card of the command
+ //
+ NE3200_WRITE_LOCAL_DOORBELL_INTERRUPT(
+ Adapter,
+ NE3200_LOCAL_DOORBELL_NEW_COMMAND
+ );
+
+ } else {
+
+ //
+ // No commands are pending, clear the on card queue
+ //
+ Adapter->FirstCommandOnCard = NULL;
+
+ }
+
+ } else {
+
+ //
+ // Point the adapter's first pending command to the
+ // next command on the command queue.
+ //
+ Adapter->FirstCommandOnCard = CommandBlock->NextCommand;
+
+ }
+
+ //
+ // Free this command block
+ //
+ CommandBlock->Hardware.NextPending = NE3200_NULL;
+ CommandBlock->Hardware.State = NE3200_STATE_FREE;
+
+ //
+ // Update the correct queue.
+ //
+ (*CommandBlock->AvailableCommandBlockCounter)++;
+
+#if DBG
+ if (CommandBlock->AvailableCommandBlockCounter == &Adapter->NumberOfAvailableCommandBlocks) {
+ //
+ // This is a "private" Command Block.
+ //
+ IF_LOG('A');
+ } else {
+ //
+ // This is a "public" Command Block.
+ //
+ IF_LOG('Q');
+ }
+#endif
+
+}
+
diff --git a/private/ntos/ndis/ne3200/interrup.c b/private/ntos/ndis/ne3200/interrup.c
new file mode 100644
index 000000000..d1fef19b0
--- /dev/null
+++ b/private/ntos/ndis/ne3200/interrup.c
@@ -0,0 +1,835 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ interrup.c
+
+Abstract:
+
+ This module contains the interrupt-processing code for the Novell
+ NE3200 NDIS 3.0 miniport driver.
+
+Author:
+
+ Keith Moore (KeithMo) 04-Feb-1991
+
+Environment:
+
+Revision History:
+
+--*/
+
+#include <ne3200sw.h>
+
+//
+// Forward declarations of functions in this file
+//
+STATIC
+BOOLEAN
+FASTCALL
+NE3200ProcessReceiveInterrupts(
+ IN PNE3200_ADAPTER Adapter
+ );
+
+STATIC
+BOOLEAN
+FASTCALL
+NE3200ProcessCommandInterrupts(
+ IN PNE3200_ADAPTER Adapter
+ );
+
+VOID
+NE3200Isr(
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueDpc,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ Interrupt service routine for the NE3200. It's main job is
+ to get the value of the System Doorbell Register and record the
+ changes in the adapters own list of interrupt reasons.
+
+Arguments:
+
+ Interrupt - Interrupt object for the NE3200.
+
+ Context - Really a pointer to the adapter.
+
+Return Value:
+
+ Returns true if the interrupt really was from our NE3200.
+
+--*/
+
+{
+
+ //
+ // Will hold the value from the System Doorbell Register.
+ //
+ UCHAR SystemDoorbell;
+
+ //
+ // Holds the pointer to the adapter.
+ //
+ PNE3200_ADAPTER Adapter = Context;
+
+ IF_LOG('i');
+
+ //
+ // Get the interrupt status
+ //
+ NE3200_READ_SYSTEM_DOORBELL_INTERRUPT(Adapter, &SystemDoorbell);
+
+ //
+ // Are any of the bits expected?
+ //
+ if (SystemDoorbell & NE3200_SYSTEM_DOORBELL_MASK) {
+
+ IF_LOG(SystemDoorbell);
+
+ //
+ // It's our interrupt. Disable further interrupts.
+ //
+ NE3200_WRITE_SYSTEM_DOORBELL_MASK(
+ Adapter,
+ 0
+ );
+
+ IF_LOG('I');
+
+ //
+ // Return that we recognize it
+ //
+ *InterruptRecognized = TRUE;
+
+ } else {
+
+ IF_LOG('I');
+
+ //
+ // Return that we don't recognize it
+ //
+ *InterruptRecognized = FALSE;
+
+ }
+
+ //
+ // No Dpc call is needed for initialization
+ //
+ *QueueDpc = FALSE;
+
+}
+
+
+STATIC
+VOID
+NE3200HandleInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ Main routine for processing interrupts.
+
+Arguments:
+
+ Adapter - The Adapter to process interrupts for.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // The adapter for which to handle interrupts.
+ //
+ PNE3200_ADAPTER Adapter = ((PNE3200_ADAPTER)MiniportAdapterContext);
+
+ //
+ // Holds a value of SystemDoorbellInterrupt.
+ //
+ USHORT SystemDoorbell = 0;
+
+ //
+ // Should NdisMEthIndicateReceiveComplete() be called?
+ //
+ BOOLEAN IndicateReceiveComplete = FALSE;
+
+ IF_LOG('p');
+
+ //
+ // Get the current reason for interrupts
+ //
+ NE3200_READ_SYSTEM_DOORBELL_INTERRUPT(Adapter, &SystemDoorbell);
+
+ //
+ // Acknowledge those interrupts.
+ //
+ NE3200_WRITE_SYSTEM_DOORBELL_INTERRUPT(
+ Adapter,
+ SystemDoorbell
+ );
+
+ //
+ // Get just the important ones.
+ //
+ SystemDoorbell &= NE3200_SYSTEM_DOORBELL_MASK;
+
+ while (TRUE) {
+
+ //
+ // If we have a reset in progress then start the reset.
+ //
+
+ if (Adapter->ResetInProgress) goto check_reset;
+
+not_reset:
+
+ //
+ // Check the interrupt source and other reasons
+ // for processing. If there are no reasons to
+ // process then exit this loop.
+ //
+
+ //
+ // Check the interrupt vector and see if there are any
+ // more receives to process. After we process any
+ // other interrupt source we always come back to the top
+ // of the loop to check if any more receive packets have
+ // come in. This is to lessen the probability that we
+ // drop a receive.
+ //
+ if (SystemDoorbell & NE3200_SYSTEM_DOORBELL_PACKET_RECEIVED) {
+
+ IF_LOG('r');
+
+ //
+ // Process receive interrupts.
+ //
+ if (NE3200ProcessReceiveInterrupts(Adapter)) {
+
+ //
+ // If done with all receives, then clear the interrupt
+ // from our status.
+ //
+ SystemDoorbell &= ~NE3200_SYSTEM_DOORBELL_PACKET_RECEIVED;
+
+ }
+
+ //
+ // Note that we got a receive.
+ //
+ Adapter->ReceiveInterrupt = TRUE;
+ IndicateReceiveComplete = TRUE;
+
+ IF_LOG('R');
+
+ } else if ((SystemDoorbell &
+ NE3200_SYSTEM_DOORBELL_COMMAND_COMPLETE) == 0 ) {
+
+ //
+ // If the command is not completed, and no receives, then
+ // exit the loop.
+ //
+ break;
+ }
+
+ //
+ // First we check that this is a packet that was transmitted
+ // but not already processed. Recall that this routine
+ // will be called repeatedly until this tests false, Or we
+ // hit a packet that we don't completely own.
+ //
+ if ((Adapter->FirstCommandOnCard == NULL) ||
+ (Adapter->FirstCommandOnCard->Hardware.State != NE3200_STATE_EXECUTION_COMPLETE)) {
+
+ //
+ // No more work to do, clear the interrupt status bit.
+ //
+ IF_LOG('V');
+ SystemDoorbell &= ~NE3200_SYSTEM_DOORBELL_COMMAND_COMPLETE;
+
+ } else {
+
+ IF_LOG('c');
+
+ //
+ // Complete this transmit.
+ //
+ if ( NE3200ProcessCommandInterrupts(Adapter) ) {
+ SystemDoorbell &= ~NE3200_SYSTEM_DOORBELL_COMMAND_COMPLETE;
+ }
+
+ IF_LOG('C');
+
+ }
+
+ //
+ // Get more interrupt bits for processing
+ //
+ if (SystemDoorbell == 0) {
+
+ //
+ // Get the current reason for interrupts
+ //
+ NE3200_READ_SYSTEM_DOORBELL_INTERRUPT(Adapter, &SystemDoorbell);
+
+ //
+ // Acknowledge those interrupts.
+ //
+ NE3200_WRITE_SYSTEM_DOORBELL_INTERRUPT(
+ Adapter,
+ SystemDoorbell
+ );
+
+ //
+ // Get just the important ones.
+ //
+ SystemDoorbell &= NE3200_SYSTEM_DOORBELL_MASK;
+
+ }
+
+ }
+
+done:
+
+ IF_LOG('P');
+
+ if (IndicateReceiveComplete) {
+
+ NdisMEthIndicateReceiveComplete(Adapter->MiniportAdapterHandle);
+
+ }
+
+ return;
+
+check_reset:
+
+ if (Adapter->ResetState != NE3200ResetStateComplete) {
+
+ //
+ // The adapter is not in a state where it can process a reset.
+ //
+ goto not_reset;
+
+ }
+
+ //
+ // Start the reset
+ //
+ NE3200DoAdapterReset(Adapter);
+
+ goto done;
+
+}
+
+STATIC
+BOOLEAN
+FASTCALL
+NE3200ProcessReceiveInterrupts(
+ IN PNE3200_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Process the packets that have the adapter has finished receiving.
+
+Arguments:
+
+ Adapter - The adapter to indicate to.
+
+Return Value:
+
+ Whether to clear interrupt bit or not.
+
+--*/
+
+{
+
+ //
+ // We don't get here unless there was a receive. Loop through
+ // the receive blocks starting at the last known block owned by
+ // the hardware.
+ //
+ // Examine each receive block for errors.
+ //
+ // We keep an array whose elements are indexed by the block
+ // index of the receive blocks. The arrays elements are the
+ // virtual addresses of the buffers pointed to by each block.
+ //
+ // After we find a packet we give the routine that process the
+ // packet through the filter, the buffers virtual address (which
+ // is always the lookahead size) and as the MAC Context the
+ // index to the receive block.
+ //
+
+ //
+ // Pointer to the receive block being examined.
+ //
+ PNE3200_SUPER_RECEIVE_ENTRY CurrentEntry = Adapter->ReceiveQueueHead;
+
+ //
+ // Pointer to last receive block in the queue.
+ //
+ PNE3200_SUPER_RECEIVE_ENTRY LastEntry;
+
+ //
+ // Limit the number of consecutive receives we will do. This way
+ // we do not starve transmit interrupts when processing many, many
+ // receives
+ //
+#define MAX_RECEIVES_PROCESSED 10
+ ULONG ReceivePacketCount = 0;
+
+
+ //
+ // Loop forever
+ //
+ while (TRUE) {
+
+ //
+ // Ensure that our Receive Entry is on an even boundary.
+ //
+ ASSERT(!(NdisGetPhysicalAddressLow(CurrentEntry->Self) & 1));
+
+ //
+ // Check to see whether we own the packet. If
+ // we don't then simply return to the caller.
+ //
+ if (CurrentEntry->Hardware.State != NE3200_STATE_FREE) {
+
+ //
+ // We've found a packet. Prepare the parameters
+ // for indication, then indicate.
+ //
+ if (ReceivePacketCount < MAX_RECEIVES_PROCESSED) {
+
+ //
+ // Increment the limit.
+ //
+ ReceivePacketCount++;
+
+ //
+ // Flush the receive buffer
+ //
+ NdisFlushBuffer(CurrentEntry->FlushBuffer, FALSE);
+
+ //
+ // Check the packet for a runt
+ //
+ if ((UINT)(CurrentEntry->Hardware.FrameSize) <
+ NE3200_HEADER_SIZE) {
+
+ if ((UINT)(CurrentEntry->Hardware.FrameSize) >=
+ NE3200_LENGTH_OF_ADDRESS) {
+
+ //
+ // Runt Packet, indicate it.
+ //
+ NdisMEthIndicateReceive(
+ Adapter->MiniportAdapterHandle,
+ (NDIS_HANDLE)(CurrentEntry->ReceiveBuffer),
+ CurrentEntry->ReceiveBuffer,
+ (UINT)CurrentEntry->Hardware.FrameSize,
+ NULL,
+ 0,
+ 0
+ );
+
+ }
+
+ } else {
+
+ //
+ // Good frame, indicate it
+ //
+ NdisMEthIndicateReceive(
+ Adapter->MiniportAdapterHandle,
+ (NDIS_HANDLE)(CurrentEntry->ReceiveBuffer),
+ CurrentEntry->ReceiveBuffer,
+ NE3200_HEADER_SIZE,
+ ((PUCHAR)CurrentEntry->ReceiveBuffer) + NE3200_HEADER_SIZE,
+ (UINT)CurrentEntry->Hardware.FrameSize - NE3200_HEADER_SIZE,
+ (UINT)CurrentEntry->Hardware.FrameSize - NE3200_HEADER_SIZE
+ );
+
+ }
+
+ //
+ // Give the packet back to the hardware.
+ //
+ // Chain the current block onto the tail of the Receive Queue.
+ //
+ CurrentEntry->Hardware.NextPending = NE3200_NULL;
+ CurrentEntry->Hardware.State = NE3200_STATE_FREE;
+
+ //
+ // Update receive ring
+ //
+ LastEntry = Adapter->ReceiveQueueTail;
+ LastEntry->Hardware.NextPending =
+ NdisGetPhysicalAddressLow(CurrentEntry->Self);
+
+ //
+ // Update the queue tail.
+ //
+ Adapter->ReceiveQueueTail = LastEntry->NextEntry;
+
+ //
+ // Advance to the next block.
+ //
+ CurrentEntry = CurrentEntry->NextEntry;
+
+ //
+ // See if the adapter needs to be restarted. The NE3200
+ // stops if it runs out receive buffers. Since we just
+ // released one, we restart the adapter.
+ //
+ if (LastEntry->Hardware.State != NE3200_STATE_FREE) {
+
+ //
+ // We've exhausted all Receive Blocks. Now we
+ // must restart the adapter.
+ //
+ IF_LOG('O');
+ NE3200StartChipAndDisableInterrupts(Adapter, Adapter->ReceiveQueueTail);
+
+ }
+
+ } else {
+
+ //
+ // Update statistics, we are exiting to check for
+ // transmit interrupts.
+ //
+ Adapter->ReceiveQueueHead = CurrentEntry;
+ Adapter->GoodReceives += MAX_RECEIVES_PROCESSED+1;
+
+ IF_LOG('o');
+
+ return FALSE;
+
+ }
+
+ } else {
+
+ //
+ // All done, update statistics and exit.
+ //
+ Adapter->ReceiveQueueHead = CurrentEntry;
+ Adapter->GoodReceives += ReceivePacketCount;
+ return TRUE;
+
+ }
+
+ }
+
+}
+
+
+STATIC
+BOOLEAN
+FASTCALL
+NE3200ProcessCommandInterrupts(
+ IN PNE3200_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Process the Command Complete interrupts.
+
+Arguments:
+
+ Adapter - The adapter that was sent from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Pointer to command block being processed.
+ //
+ PNE3200_SUPER_COMMAND_BLOCK CurrentCommandBlock = Adapter->FirstCommandOnCard;
+
+ //
+ // Holds whether the packet successfully transmitted or not.
+ //
+ NDIS_STATUS StatusToReturn;
+
+ //
+ // Pointer to the packet that started this transmission.
+ //
+ PNDIS_PACKET OwningPacket;
+
+ //
+ // Points to the reserved part of the OwningPacket.
+ //
+ PNE3200_RESERVED Reserved;
+
+ //
+ // Ensure that the Command Block is on an even boundary.
+ //
+ ASSERT(!(NdisGetPhysicalAddressLow(CurrentCommandBlock->Self) & 1));
+
+ IF_LOG('t');
+
+ if (CurrentCommandBlock->Hardware.CommandCode == NE3200_COMMAND_TRANSMIT) {
+
+ //
+ // The current command block is from a transmit.
+ //
+ Adapter->SendInterrupt = TRUE;
+
+ //
+ // Get a pointer to the owning packet and the reserved part of
+ // the packet.
+ //
+ OwningPacket = CurrentCommandBlock->OwningPacket;
+ Reserved = PNE3200_RESERVED_FROM_PACKET(OwningPacket);
+
+ if (CurrentCommandBlock->UsedNE3200Buffer) {
+
+ //
+ // This packet used adapter buffers. We can
+ // now return these buffers to the adapter.
+ //
+
+ //
+ // The adapter buffer descriptor that was allocated to this packet.
+ //
+ PNE3200_BUFFER_DESCRIPTOR BufferDescriptor = Adapter->NE3200Buffers +
+ CurrentCommandBlock->NE3200BuffersIndex;
+
+ //
+ // Put the adapter buffer back on the free list.
+ //
+ BufferDescriptor->Next = Adapter->NE3200BufferListHead;
+ Adapter->NE3200BufferListHead = CurrentCommandBlock->NE3200BuffersIndex;
+
+ } else {
+
+ //
+ // Ndis buffer mapped
+ //
+ PNDIS_BUFFER CurrentBuffer;
+
+ //
+ // Map register that was used
+ //
+ UINT CurMapRegister;
+
+ //
+ // The transmit is finished, so we can release
+ // the physical mapping used for it.
+ //
+ NdisQueryPacket(
+ OwningPacket,
+ NULL,
+ NULL,
+ &CurrentBuffer,
+ NULL
+ );
+
+ //
+ // Get starting map register
+ //
+ CurMapRegister = CurrentCommandBlock->CommandBlockIndex *
+ NE3200_MAXIMUM_BLOCKS_PER_PACKET;
+
+ //
+ // For each buffer
+ //
+ while (CurrentBuffer) {
+
+ //
+ // Finish the mapping
+ //
+ NdisMCompleteBufferPhysicalMapping(
+ Adapter->MiniportAdapterHandle,
+ CurrentBuffer,
+ CurMapRegister
+ );
+
+ ++CurMapRegister;
+
+ NdisGetNextBuffer(
+ CurrentBuffer,
+ &CurrentBuffer
+ );
+
+ }
+
+ }
+
+ //
+ // If there was an error transmitting this
+ // packet, update our error counters.
+ //
+ if (CurrentCommandBlock->Hardware.Status & NE3200_STATUS_FATALERROR_MASK) {
+
+ if (CurrentCommandBlock->Hardware.Status &
+ NE3200_STATUS_MAXIMUM_COLLISIONS) {
+
+ Adapter->RetryFailure++;
+
+ } else if (CurrentCommandBlock->Hardware.Status &
+ NE3200_STATUS_NO_CARRIER) {
+
+ Adapter->LostCarrier++;
+
+ } else if (CurrentCommandBlock->Hardware.Status &
+ NE3200_STATUS_HEART_BEAT) {
+
+ Adapter->NoClearToSend++;
+
+ } else if (CurrentCommandBlock->Hardware.Status &
+ NE3200_STATUS_DMA_UNDERRUN) {
+
+ Adapter->UnderFlow++;
+
+ }
+
+ StatusToReturn = NDIS_STATUS_FAILURE;
+
+ } else {
+
+ //
+ // Update good transmit counter
+ //
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+ Adapter->GoodTransmits++;
+ }
+
+ ASSERT(sizeof(UINT) == sizeof(PNDIS_PACKET));
+
+ //
+ // Release the command block.
+ //
+ NE3200RelinquishCommandBlock(Adapter, CurrentCommandBlock);
+
+ //
+ // The transmit is now complete
+ //
+ NdisMSendComplete(
+ Adapter->MiniportAdapterHandle,
+ OwningPacket,
+ StatusToReturn
+ );
+
+ } else if (CurrentCommandBlock->Hardware.CommandCode ==
+ NE3200_COMMAND_READ_ADAPTER_STATISTICS) {
+
+ //
+ // Release the command block.
+ //
+ Adapter->OutOfResources =
+ CurrentCommandBlock->Hardware.PARAMETERS.STATISTICS.ResourceErrors;
+
+ Adapter->CrcErrors =
+ CurrentCommandBlock->Hardware.PARAMETERS.STATISTICS.CrcErrors;
+
+ Adapter->AlignmentErrors =
+ CurrentCommandBlock->Hardware.PARAMETERS.STATISTICS.AlignmentErrors;
+
+ Adapter->DmaOverruns =
+ CurrentCommandBlock->Hardware.PARAMETERS.STATISTICS.OverrunErrors;
+
+
+ //
+ // If this was from a request, complete it
+ //
+ if (Adapter->RequestInProgress) {
+
+ NE3200FinishQueryInformation(Adapter);
+
+ }
+
+ //
+ // Release the command block
+ //
+ NE3200RelinquishCommandBlock(Adapter, CurrentCommandBlock);
+
+ } else if (CurrentCommandBlock->Hardware.CommandCode ==
+ NE3200_COMMAND_CLEAR_ADAPTER_STATISTICS) {
+
+ //
+ // Release the command block.
+ //
+ NE3200RelinquishCommandBlock(Adapter, CurrentCommandBlock);
+
+ } else if (CurrentCommandBlock->Hardware.CommandCode ==
+ NE3200_COMMAND_SET_STATION_ADDRESS) {
+
+ //
+ // Ignore
+ //
+
+ } else {
+
+ //
+ // The current command block is not from a transmit.
+ //
+ // Complete the request.
+ //
+ // if the CurrentCommandBlock->Set is FALSE,
+ // it means this multicast operation was not caused by
+ // a SetInformation request.
+ //
+
+ if (CurrentCommandBlock->Set) {
+
+ //
+ // Release the command block.
+ //
+ NE3200RelinquishCommandBlock(Adapter, CurrentCommandBlock);
+
+ if (!Adapter->RequestInProgress) {
+
+ //
+ // Bogus interrupt. Ignore it
+ //
+
+ } else {
+
+ IF_LOG(']');
+
+ Adapter->RequestInProgress = FALSE;
+
+ //
+ // Complete the request
+ //
+ NdisMSetInformationComplete(
+ Adapter->MiniportAdapterHandle,
+ NDIS_STATUS_SUCCESS);
+
+ }
+
+ } else {
+ IF_LOG('T');
+ return TRUE;
+ }
+
+ }
+
+ return FALSE;
+
+}
+
diff --git a/private/ntos/ndis/ne3200/keywords.h b/private/ntos/ndis/ne3200/keywords.h
new file mode 100644
index 000000000..30b52656f
--- /dev/null
+++ b/private/ntos/ndis/ne3200/keywords.h
@@ -0,0 +1,43 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ keywords.h
+
+Abstract:
+
+ Contains all Ndis2 and Ndis3 mac-specific keywords.
+
+Author:
+
+ Bob Noradki
+
+Environment:
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+
+
+--*/
+#ifndef NDIS2
+#define NDIS2 0
+#endif
+
+#if NDIS2
+
+#define NETWORK_ADDRESS NDIS_STRING_CONST("NETADDRESS")
+
+#else // NDIS3
+
+#define NETWORK_ADDRESS NDIS_STRING_CONST("NetworkAddress")
+
+#endif
diff --git a/private/ntos/ndis/ne3200/mac2hex/mac.bin b/private/ntos/ndis/ne3200/mac2hex/mac.bin
new file mode 100644
index 000000000..259f85a8e
--- /dev/null
+++ b/private/ntos/ndis/ne3200/mac2hex/mac.bin
Binary files differ
diff --git a/private/ntos/ndis/ne3200/mac2hex/mac2hex.c b/private/ntos/ndis/ne3200/mac2hex/mac2hex.c
new file mode 100644
index 000000000..661e768c1
--- /dev/null
+++ b/private/ntos/ndis/ne3200/mac2hex/mac2hex.c
@@ -0,0 +1,309 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ mac2hex.c
+
+Abstract:
+
+ This program will read in MAC.BIN and produce MACBIN.H. MACBIN.H
+ will consist of a character array representation (MacBinImage[])
+ of MAC.BIN.
+
+Author:
+
+ Keith Moore (KeithMo) 23-Jan-1991
+
+Environment:
+
+ OS/2 1.x/2.x Protected Mode
+
+Revision History:
+
+
+--*/
+
+#define INCL_BASE
+#include <os2.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+//
+// Macros
+//
+#define CHECK_RETURN(code) \
+{ \
+ if ((code) != NO_ERROR) { \
+ printf( \
+ "Error %d, File %s, Line %ld\n", \
+ (code), \
+ __FILE__, \
+ (long)__LINE__ \
+ ); \
+ exit(1); \
+ } \
+}
+
+
+//
+// Prototypes
+//
+int
+main(
+ int nArgc,
+ char *pArgv[]
+ );
+
+VOID
+CreateHeaderFile(
+ PUCHAR pBuffer,
+ USHORT usLength
+ );
+
+
+//
+// main
+//
+int
+main(
+ int nArgc,
+ char *pArgv[]
+ )
+
+/*++
+
+Routine Description:
+
+ Usual C entry point.
+
+Arguments:
+
+ nArgc - Count of command line arguments.
+ pArgv - Array of pointers to the command line arguments.
+
+Return Value:
+
+ 0 if everything went OK.
+ 1 if something horrible happened.
+
+--*/
+
+{
+
+ FILESTATUS FileStatus;
+ HFILE hFile;
+ PCHAR pFileName;
+ PVOID pBuffer;
+ SEL Selector;
+ USHORT usAction;
+ USHORT usFileSize;
+ USHORT usNumRead;
+ USHORT usResult;
+
+ //
+ // If no command line arguments are given, then
+ // use "MAC.BIN" for the input file. Otherwise,
+ // assume that the first (only?) argument is the
+ // name of the download file.
+ //
+
+ pFileName = (nArgc > 1) ? (PCHAR)pArgv[1] : (PCHAR)"MAC.BIN";
+
+ //
+ // Open MAC.BIN.
+ //
+
+ usResult = DosOpen(
+ pFileName,
+ &hFile,
+ &usAction,
+ 0L,
+ FILE_NORMAL,
+ FILE_OPEN,
+ OPEN_ACCESS_READONLY
+ | OPEN_SHARE_DENYNONE,
+ 0L
+ );
+ CHECK_RETURN(usResult);
+
+ //
+ // Query the file so we can retrive its length.
+ //
+
+ usResult = DosQFileInfo(
+ hFile,
+ FIL_STANDARD,
+ (PBYTE)&FileStatus,
+ sizeof(FILESTATUS)
+ );
+ CHECK_RETURN(usResult);
+
+ usFileSize = (USHORT)FileStatus.cbFile;
+
+ //
+ // Allocate a chunk of memory to use.
+ //
+
+ usResult = DosAllocSeg(
+ usFileSize,
+ &Selector,
+ SEG_NONSHARED
+ );
+ CHECK_RETURN(usResult);
+
+ //
+ // Build our pointer from the selector we just allocated.
+ //
+
+ pBuffer = MAKEP(Selector, 0);
+
+ //
+ // Read MAC.BIN into our buffer.
+ //
+
+ usResult = DosRead(
+ hFile,
+ pBuffer,
+ usFileSize,
+ &usNumRead
+ );
+ CHECK_RETURN(usResult);
+
+ //
+ // Close MAC.BIN.
+ //
+
+ usResult = DosClose(
+ hFile
+ );
+ CHECK_RETURN(usResult);
+
+ //
+ // Write the new file.
+ //
+ CreateHeaderFile(pBuffer, usFileSize);
+
+ //
+ // Free the allocated memory.
+ //
+ usResult = DosFreeSeg(
+ Selector
+ );
+ CHECK_RETURN(usResult);
+
+ return 0;
+
+}
+
+
+//
+// CreateHeaderFile
+//
+VOID
+CreateHeaderFile(
+ PUCHAR pBuffer,
+ USHORT usLength
+ )
+
+/*++
+
+Routine Description:
+
+ Create a C header file containing a character
+ array representation of the specified buffer.
+
+Arguments:
+
+ pBuffer - Pointer to the buffer to convert.
+
+ usLength - The length (in bytes) of the buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // TRUE if we're starting a new line.
+ //
+ BOOL fNewLine;
+
+ //
+ // Number of bytes on current line.
+ //
+ USHORT usNumBytes;
+
+ //
+ // Create the prologue
+ //
+
+ printf("/*++\n");
+ printf("\n");
+ printf("Copyright (c) 1990 Microsoft Corporation\n");
+ printf("\n");
+ printf("Module Name:\n");
+ printf("\n");
+ printf(" macbin.h\n");
+ printf("\n");
+ printf("Abstract:\n");
+ printf("\n");
+ printf(" This module is generated by MAC2HEX.EXE. MAC2HEX reads in the\n");
+ printf(" NE3200's MAC.BIN module and produces this C character array\n");
+ printf(" representation. This is an unfortunate artifact of having\n");
+ printf(" all device drivers linked into the kernel. Once we have real\n");
+ printf(" installable device drivers, this will be unnecessary (the\n");
+ printf(" NE3200 driver will just open MAC.BIN and read it). But for now,\n");
+ printf(" all device drivers get initialized *before* the filesystem.\n");
+ printf(" Ergo, device drivers cannot open files at initialization time.\n");
+ printf("\n");
+ printf("Author:\n");
+ printf("\n");
+ printf(" Keith Moore (KeithMo) 24-Jan-1991\n");
+ printf("\n");
+ printf("Environment:\n");
+ printf("\n");
+ printf(" Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.\n");
+ printf("\n");
+ printf("Revision History:\n");
+ printf("\n");
+ printf("\n");
+ printf("--*/\n");
+ printf("\n");
+ printf("#define NE3200_MACBIN_LENGTH %u\n", usLength);
+ printf("\n");
+ printf("UCHAR NE3200MacBinImage[] = {");
+
+ fNewLine = TRUE;
+
+ while(usLength--) {
+
+ if (fNewLine) {
+
+ printf("\n");
+ printf(" ");
+ fNewLine = FALSE;
+ usNumBytes = 0;
+
+ }
+
+ printf("0x%02X", (UINT)(*pBuffer++));
+
+ if (usLength > 0)
+ printf(",");
+
+ if (++usNumBytes >= 13)
+ fNewLine = TRUE;
+
+ }
+
+ printf("\n");
+ printf(" };\n");
+
+}
diff --git a/private/ntos/ndis/ne3200/mac2hex/mac2hex.def b/private/ntos/ndis/ne3200/mac2hex/mac2hex.def
new file mode 100644
index 000000000..d879f7eb3
--- /dev/null
+++ b/private/ntos/ndis/ne3200/mac2hex/mac2hex.def
@@ -0,0 +1,5 @@
+NAME MAC2HEX WINDOWCOMPAT
+
+DESCRIPTION 'Convert MAC.BIN to C Header File'
+
+STACKSIZE 8192
diff --git a/private/ntos/ndis/ne3200/mac2hex/makefile b/private/ntos/ndis/ne3200/mac2hex/makefile
new file mode 100644
index 000000000..ac264b66c
--- /dev/null
+++ b/private/ntos/ndis/ne3200/mac2hex/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\maketool.def
diff --git a/private/ntos/ndis/ne3200/mac2hex/sources b/private/ntos/ndis/ne3200/mac2hex/sources
new file mode 100644
index 000000000..055ce7ff7
--- /dev/null
+++ b/private/ntos/ndis/ne3200/mac2hex/sources
@@ -0,0 +1,19 @@
+MAJORCOMP=ne3200
+MINORCOMP=mac2hex
+
+TARGETNAME=mac2hex
+TARGETPATH=obj
+TARGETTYPE=PROGRAM
+
+INCLUDES=\nt\private\tools\inc
+
+SOURCES=mac2hex.c
+
+BUILDTOOL=1
+TOOL_MODEL=/AS /G2s
+TOOL_LIBS=\nt\private\tools\lib\slibcep /NOD/NOE
+TOOL_TYPE=WINDOWCOMPAT
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+
diff --git a/private/ntos/ndis/ne3200/makefile b/private/ntos/ndis/ne3200/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/ne3200/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/ne3200/makefile.inc b/private/ntos/ndis/ne3200/makefile.inc
new file mode 100644
index 000000000..439bc1088
--- /dev/null
+++ b/private/ntos/ndis/ne3200/makefile.inc
@@ -0,0 +1,5 @@
+ne3200.bin: $(TARGETEXEFILES)
+ chmode -r ne3200.bin
+ binplace ne3200.bin
+ touch ne3200.bin
+ chmode +r ne3200.bin
diff --git a/private/ntos/ndis/ne3200/ne3200.bin b/private/ntos/ndis/ne3200/ne3200.bin
new file mode 100644
index 000000000..91b9b0dec
--- /dev/null
+++ b/private/ntos/ndis/ne3200/ne3200.bin
Binary files differ
diff --git a/private/ntos/ndis/ne3200/ne3200.c b/private/ntos/ndis/ne3200/ne3200.c
new file mode 100644
index 000000000..f4bd1dbab
--- /dev/null
+++ b/private/ntos/ndis/ne3200/ne3200.c
@@ -0,0 +1,2497 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ne3200.c
+
+Abstract:
+
+ This is the main file for the Novell NE3200 EISA Ethernet adapter.
+ This driver conforms to the NDIS 3.0 miniport interface.
+
+Author:
+
+ Keith Moore (KeithMo) 08-Jan-1991
+
+Environment:
+
+Revision History:
+
+--*/
+
+#include <ne3200sw.h>
+#include "keywords.h"
+
+//
+// Global data block for holding MAC.BIN infomormation.
+//
+NE3200_GLOBAL_DATA NE3200Globals = {0};
+BOOLEAN FirstAdd = TRUE;
+
+//
+// Global for the largest acceptable piece of memory
+//
+NDIS_PHYSICAL_ADDRESS MinusOne = NDIS_PHYSICAL_ADDRESS_CONST (-1, -1);
+
+#if DBG
+
+//
+// Debugging flags for various debugging modes.
+//
+ULONG NE3200Debug = 0 ; // NE3200_DEBUG_LOUD |
+ // NE3200_DEBUG_ACQUIRE |
+ // NE3200_DEBUG_SUBMIT |
+ // NE3200_DEBUG_DUMP_COMMAND
+ // ;
+#endif
+
+
+//
+// Forward declarations for functions in this file
+//
+STATIC
+BOOLEAN
+NE3200AllocateAdapterMemory(
+ IN PNE3200_ADAPTER Adapter
+ );
+
+STATIC
+VOID
+NE3200DeleteAdapterMemory(
+ IN PNE3200_ADAPTER Adapter
+ );
+
+STATIC
+BOOLEAN
+NE3200InitialInit(
+ IN PNE3200_ADAPTER Adapter,
+ IN UINT NE3200InterruptVector,
+ IN NDIS_INTERRUPT_MODE NE3200InterruptMode
+ );
+
+STATIC
+BOOLEAN
+NE3200InitializeGlobals(
+ OUT PNE3200_GLOBAL_DATA Globals,
+ IN NDIS_HANDLE MiniportAdapterHandle
+ );
+
+STATIC
+VOID
+NE3200DestroyGlobals(
+ IN PNE3200_GLOBAL_DATA Globals
+ );
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+
+VOID
+NE3200Shutdown(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+#pragma NDIS_INIT_FUNCTION(DriverEntry)
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This is the primary initialization routine for the NE3200 driver.
+ It is simply responsible for the intializing the wrapper and registering
+ the Miniport driver. It then calls a system and architecture specific
+ routine that will initialize and register each adapter.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+Return Value:
+
+ The status of the operation.
+
+--*/
+
+{
+ //
+ // Receives the status of the NdisRegisterMiniport operation.
+ //
+ NDIS_STATUS Status;
+
+ //
+ // The characteristics table
+ //
+ NDIS_MINIPORT_CHARACTERISTICS NE3200Char;
+
+ //
+ // The handle returned by NdisMInitializeWrapper
+ //
+ NDIS_HANDLE NdisWrapperHandle;
+
+#if NDIS_WIN
+ UCHAR pIds[sizeof (EISA_MCA_ADAPTER_IDS) + sizeof (ULONG)];
+#endif
+
+#if NDIS_WIN
+ ((PEISA_MCA_ADAPTER_IDS)pIds)->nEisaAdapters=1;
+ ((PEISA_MCA_ADAPTER_IDS)pIds)->nMcaAdapters=0;
+ *(PULONG)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray)=EISA_NE3200_IDENTIFICATION;
+ (PVOID)DriverObject=(PVOID)pIds;
+#endif
+
+ //
+ // Initialize the wrapper.
+ //
+ NdisMInitializeWrapper(
+ &NdisWrapperHandle,
+ DriverObject,
+ RegistryPath,
+ NULL
+ );
+
+ //
+ // Initialize the Miniport characteristics for the call to
+ // NdisMRegisterMiniport.
+ //
+ NE3200Globals.NE3200NdisWrapperHandle = NdisWrapperHandle;
+
+ NE3200Char.MajorNdisVersion = NE3200_NDIS_MAJOR_VERSION;
+ NE3200Char.MinorNdisVersion = NE3200_NDIS_MINOR_VERSION;
+ NE3200Char.CheckForHangHandler = NE3200CheckForHang;
+ NE3200Char.DisableInterruptHandler = NE3200DisableInterrupt;
+ NE3200Char.EnableInterruptHandler = NE3200EnableInterrupt;
+ NE3200Char.HaltHandler = NE3200Halt;
+ NE3200Char.HandleInterruptHandler = NE3200HandleInterrupt;
+ NE3200Char.InitializeHandler = NE3200Initialize;
+ NE3200Char.ISRHandler = NE3200Isr;
+ NE3200Char.QueryInformationHandler = NE3200QueryInformation;
+ NE3200Char.ReconfigureHandler = NULL;
+ NE3200Char.ResetHandler = NE3200Reset;
+ NE3200Char.SendHandler = NE3200Send;
+ NE3200Char.SetInformationHandler = NE3200SetInformation;
+ NE3200Char.TransferDataHandler = NE3200TransferData;
+
+ //
+ // Register this driver with NDIS
+ //
+ Status = NdisMRegisterMiniport(
+ NdisWrapperHandle,
+ &NE3200Char,
+ sizeof(NE3200Char)
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ return STATUS_SUCCESS;
+
+ }
+
+ //
+ // We can only get here if something went wrong with registering
+ // the driver or *all* of the adapters.
+ //
+ NE3200DestroyGlobals(&NE3200Globals);
+ NdisTerminateWrapper(NdisWrapperHandle, NULL);
+
+ return STATUS_UNSUCCESSFUL;
+
+}
+
+
+#pragma NDIS_INIT_FUNCTION(NE3200RegisterAdapter)
+
+BOOLEAN
+NE3200RegisterAdapter(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN UINT EisaSlot,
+ IN UINT InterruptVector,
+ IN NDIS_INTERRUPT_MODE InterruptMode,
+ IN PUCHAR CurrentAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is responsible for the allocation of the datastructures
+ for the driver as well as any hardware specific details necessary
+ to talk with the device.
+
+Arguments:
+
+ MiniportAdapterHandle - The handle given by ndis identifying this mini-port.
+
+ EisaSlot - The EISA Slot Number for this NE3200 adapter.
+
+ InterruptVector - The interrupt vector to used for the adapter.
+
+ InterruptMode - The interrupt mode (Latched or LevelSensitive)
+ used for this adapter.
+
+ CurrentAddress - The address the card will assume. If this is NULL,
+ then the card will use the BIA.
+
+Return Value:
+
+ Returns false if anything occurred that prevents the initialization
+ of the adapter.
+
+--*/
+
+{
+ //
+ // Status of nt calls
+ //
+ NDIS_STATUS Status;
+
+ //
+ // Pointer for the adapter root.
+ //
+ PNE3200_ADAPTER Adapter;
+
+ //
+ // All of the code that manipulates physical addresses depends
+ // on the fact that physical addresses are 4 byte quantities.
+ //
+ ASSERT(sizeof(NE3200_PHYSICAL_ADDRESS) == 4);
+
+ //
+ // Allocate the Adapter block.
+ //
+ NE3200_ALLOC_PHYS(&Status, &Adapter, sizeof(NE3200_ADAPTER));
+
+ if ( Status == NDIS_STATUS_SUCCESS ) {
+
+ //
+ // The IoBase Address for this adapter
+ //
+ ULONG AdapterIoBase;
+
+ //
+ // The resulting mapped base address
+ //
+ PUCHAR MappedIoBase;
+
+ //
+ // Initialize the adapter structure to all zeros
+ //
+ NdisZeroMemory(
+ Adapter,
+ sizeof(NE3200_ADAPTER)
+ );
+
+#if DBG
+ Adapter->LogAddress = Adapter->Log;
+#endif
+
+ //
+ // Save the adapter handle
+ //
+ Adapter->MiniportAdapterHandle = MiniportAdapterHandle;
+
+ //
+ // Compute the base address
+ //
+ AdapterIoBase = (ULONG)(EisaSlot << 12);
+
+ //
+ // Save the base address
+ //
+ Adapter->AdapterIoBase = AdapterIoBase;
+
+ //
+ // Set the attributes for this adapter
+ //
+ NdisMSetAttributes(
+ MiniportAdapterHandle,
+ (NDIS_HANDLE)Adapter,
+ TRUE,
+ NdisInterfaceEisa
+ );
+
+ //
+ // Register the reset port addresses.
+ //
+ Status = NdisMRegisterIoPortRange(
+ (PVOID *)(&(Adapter->ResetPort)),
+ MiniportAdapterHandle,
+ AdapterIoBase,
+ 0x4
+ );
+
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NE3200_FREE_PHYS(Adapter);
+ return FALSE;
+ }
+
+ //
+ // Register the command ports
+ //
+ Status = NdisMRegisterIoPortRange(
+ (PVOID *)(&(MappedIoBase)),
+ MiniportAdapterHandle,
+ AdapterIoBase + NE3200_ID_PORT,
+ 0x20
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NE3200_FREE_PHYS(Adapter);
+ NdisMDeregisterIoPortRange(MiniportAdapterHandle,
+ AdapterIoBase,
+ 4,
+ (PVOID)Adapter->ResetPort
+ );
+ return FALSE;
+ }
+
+ //
+ // Allocate the map registers
+ //
+ Status = NdisMAllocateMapRegisters(
+ MiniportAdapterHandle,
+ 0,
+ FALSE,
+ NE3200_NUMBER_OF_COMMAND_BLOCKS * NE3200_MAXIMUM_BLOCKS_PER_PACKET,
+ MAXIMUM_ETHERNET_PACKET_SIZE
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NE3200_FREE_PHYS(Adapter);
+ NdisMDeregisterIoPortRange(MiniportAdapterHandle,
+ AdapterIoBase,
+ 4,
+ (PVOID)Adapter->ResetPort
+ );
+ NdisMDeregisterIoPortRange(MiniportAdapterHandle,
+ AdapterIoBase + NE3200_ID_PORT,
+ 0x20,
+ (PVOID)MappedIoBase
+ );
+ return FALSE;
+ }
+
+ //
+ // Should an alternative ethernet address be used?
+ //
+ if (CurrentAddress != NULL) {
+
+ Adapter->AddressChanged = TRUE;
+
+ NdisMoveMemory(
+ Adapter->CurrentAddress,
+ CurrentAddress,
+ NE3200_LENGTH_OF_ADDRESS
+ );
+ } else {
+
+ Adapter->AddressChanged = FALSE;
+ }
+
+ //
+ // Save the eisa slot number
+ //
+ Adapter->EisaSlot = EisaSlot;
+ //DbgPrint( "NE3200: Adapter %x is slot %d\n", Adapter, EisaSlot );
+
+ //
+ // ResetPort is set by NdisRegisterAdapter.
+ // MappedIoBase is set in NdisRegisterAdapter to be the mapped
+ // of NE3200_ID_PORT. Now we set the other ports based on
+ // this offset.
+ //
+ Adapter->SystemInterruptPort = MappedIoBase + NE3200_SYSTEM_INTERRUPT_PORT - NE3200_ID_PORT;
+ Adapter->LocalDoorbellInterruptPort = MappedIoBase + NE3200_LOCAL_DOORBELL_INTERRUPT_PORT - NE3200_ID_PORT;
+ Adapter->SystemDoorbellMaskPort = MappedIoBase + NE3200_SYSTEM_DOORBELL_MASK_PORT - NE3200_ID_PORT;
+ Adapter->SystemDoorbellInterruptPort = MappedIoBase + NE3200_SYSTEM_DOORBELL_INTERRUPT_PORT - NE3200_ID_PORT;
+ Adapter->BaseMailboxPort = MappedIoBase + NE3200_BASE_MAILBOX_PORT - NE3200_ID_PORT;
+
+ //
+ // Allocate the global resources if needed.
+ //
+ if (FirstAdd) {
+
+ if (!NE3200InitializeGlobals(&NE3200Globals, Adapter->MiniportAdapterHandle)) {
+
+ NdisMFreeMapRegisters(MiniportAdapterHandle);
+ NdisMDeregisterIoPortRange(MiniportAdapterHandle,
+ AdapterIoBase,
+ 4,
+ (PVOID)Adapter->ResetPort
+ );
+ NdisMDeregisterIoPortRange(MiniportAdapterHandle,
+ AdapterIoBase + NE3200_ID_PORT,
+ 0x20,
+ (PVOID)MappedIoBase
+ );
+ NE3200_FREE_PHYS(Adapter);
+ return FALSE;
+
+ }
+
+ FirstAdd = FALSE;
+ }
+
+ //
+ // Setup default numbers for resources
+ //
+ Adapter->NumberOfTransmitBuffers = NE3200_NUMBER_OF_TRANSMIT_BUFFERS;
+ Adapter->NumberOfReceiveBuffers = NE3200_NUMBER_OF_RECEIVE_BUFFERS;
+ Adapter->NumberOfCommandBlocks = NE3200_NUMBER_OF_COMMAND_BLOCKS;
+ Adapter->NumberOfPublicCommandBlocks = NE3200_NUMBER_OF_PUBLIC_CMD_BLOCKS;
+
+ //
+ // Allocate memory for all of the adapter structures.
+ //
+ if (NE3200AllocateAdapterMemory(Adapter)) {
+
+ //
+ // Set the initial internal state
+ //
+ NE3200ResetVariables(Adapter);
+
+ //
+ // Initialize the timer for doing asynchronous resets
+ //
+ NdisMInitializeTimer(
+ &Adapter->ResetTimer,
+ MiniportAdapterHandle,
+ (PVOID) NE3200ResetHandler,
+ (PVOID) Adapter
+ );
+
+ //
+ // Now start the adapter
+ //
+ if (!NE3200InitialInit(
+ Adapter,
+ InterruptVector,
+ InterruptMode
+ )) {
+
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
+ 0
+ );
+
+ NE3200DeleteAdapterMemory(Adapter);
+ NdisMFreeMapRegisters(MiniportAdapterHandle);
+ NdisMDeregisterIoPortRange(MiniportAdapterHandle,
+ AdapterIoBase,
+ 4,
+ (PVOID)Adapter->ResetPort
+ );
+ NdisMDeregisterIoPortRange(MiniportAdapterHandle,
+ AdapterIoBase + NE3200_ID_PORT,
+ 0x20,
+ (PVOID)MappedIoBase
+ );
+ NE3200_FREE_PHYS(Adapter);
+ return FALSE;
+ }
+
+ //
+ // Enable further interrupts.
+ //
+ NE3200_WRITE_SYSTEM_DOORBELL_MASK(
+ Adapter,
+ NE3200_SYSTEM_DOORBELL_MASK
+ );
+
+ //
+ // Record it in the global adapter list.
+ //
+
+ InsertTailList(&NE3200Globals.AdapterList,
+ &Adapter->AdapterList,
+ );
+
+ //
+ // Register our shutdown handler.
+ //
+
+ NdisMRegisterAdapterShutdownHandler(
+ Adapter->MiniportAdapterHandle, // miniport handle.
+ Adapter, // shutdown context.
+ NE3200Shutdown // shutdown handler.
+ );
+
+ return(TRUE);
+
+ } else {
+
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 3,
+ registerAdapter,
+ NE3200_ERRMSG_ALLOC_MEM,
+ 0
+ );
+
+ NdisMFreeMapRegisters(MiniportAdapterHandle);
+ NdisMDeregisterIoPortRange(MiniportAdapterHandle,
+ AdapterIoBase,
+ 4,
+ (PVOID)Adapter->ResetPort
+ );
+ NdisMDeregisterIoPortRange(MiniportAdapterHandle,
+ AdapterIoBase + NE3200_ID_PORT,
+ 0x20,
+ (PVOID)MappedIoBase
+ );
+ return(FALSE);
+
+ }
+
+ } else {
+
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 3,
+ registerAdapter,
+ NE3200_ERRMSG_ALLOC_MEM,
+ 1
+ );
+
+ return FALSE;
+ }
+}
+
+
+#pragma NDIS_INIT_FUNCTION(NE3200AllocateAdapterMemory)
+
+STATIC
+BOOLEAN
+NE3200AllocateAdapterMemory(
+ IN PNE3200_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates memory for:
+
+ - Configuration Block
+
+ - Command Queue
+
+ - Receive Queue
+
+ - Receive Buffers
+
+ - Transmit Buffers for use if user transmit buffers don't meet hardware
+ contraints
+
+ - Structures to map Command Queue entries back to the packets.
+
+Arguments:
+
+ Adapter - The adapter to allocate memory for.
+
+Return Value:
+
+ Returns FALSE if some memory needed for the adapter could not
+ be allocated.
+
+--*/
+
+{
+ //
+ // Pointer to a Receive Entry. Used while initializing
+ // the Receive Queue.
+ //
+ PNE3200_SUPER_RECEIVE_ENTRY CurrentReceiveEntry;
+
+ //
+ // Pointer to a Command Block. Used while initializing
+ // the Command Queue.
+ //
+ PNE3200_SUPER_COMMAND_BLOCK CurrentCommandBlock;
+
+ //
+ // Simple iteration variable.
+ //
+ UINT i;
+
+ //
+ // Status of allocation
+ //
+ NDIS_STATUS Status;
+
+ //
+ // Allocate the public command block
+ //
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(NE3200_SUPER_COMMAND_BLOCK) * NE3200_NUMBER_OF_PUBLIC_CMD_BLOCKS,
+ FALSE,
+ (PVOID *) &Adapter->PublicCommandQueue,
+ &Adapter->PublicCommandQueuePhysical
+ );
+
+ if (Adapter->PublicCommandQueue == NULL) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 3,
+ allocateAdapterMemory,
+ NE3200_ERRMSG_ALLOC_MEM,
+ 1
+ );
+
+ NE3200DeleteAdapterMemory(Adapter);
+ return FALSE;
+
+ }
+
+ //
+ // Allocate the card multicast table
+ //
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ NE3200_SIZE_OF_MULTICAST_TABLE_ENTRY *
+ NE3200_MAXIMUM_MULTICAST,
+ FALSE, // noncached
+ (PVOID*)&Adapter->CardMulticastTable,
+ &Adapter->CardMulticastTablePhysical
+ );
+
+ if (Adapter->CardMulticastTable == NULL) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 3,
+ allocateAdapterMemory,
+ NE3200_ERRMSG_ALLOC_MEM,
+ 2
+ );
+
+ NE3200DeleteAdapterMemory(Adapter);
+ return FALSE;
+
+ }
+
+ //
+ // Allocate the Configuration Block.
+ //
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(NE3200_CONFIGURATION_BLOCK),
+ FALSE, // noncached
+ (PVOID*)&Adapter->ConfigurationBlock,
+ &Adapter->ConfigurationBlockPhysical
+ );
+
+ if (Adapter->ConfigurationBlock == NULL) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 3,
+ allocateAdapterMemory,
+ NE3200_ERRMSG_ALLOC_MEM,
+ 3
+ );
+
+ NE3200DeleteAdapterMemory(Adapter);
+ return FALSE;
+ }
+
+ //
+ // Allocate the Padding Buffer used to pad very short
+ // packets to the minimum Ethernet packet size (60 bytes).
+ //
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ MINIMUM_ETHERNET_PACKET_SIZE,
+ FALSE,
+ (PVOID*)&Adapter->PaddingVirtualAddress,
+ &Adapter->PaddingPhysicalAddress
+ );
+
+ if (Adapter->PaddingVirtualAddress == NULL) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 3,
+ allocateAdapterMemory,
+ NE3200_ERRMSG_ALLOC_MEM,
+ 4
+ );
+
+ NE3200DeleteAdapterMemory(Adapter);
+ return FALSE;
+
+ }
+
+ //
+ // Zero the Padding Buffer so we don't pad with garbage.
+ //
+ NdisZeroMemory(
+ Adapter->PaddingVirtualAddress,
+ MINIMUM_ETHERNET_PACKET_SIZE
+ );
+
+
+ //
+ // Allocate the Command Queue.
+ //
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(NE3200_SUPER_COMMAND_BLOCK) *
+ Adapter->NumberOfCommandBlocks,
+ FALSE,
+ (PVOID*)&Adapter->CommandQueue,
+ &Adapter->CommandQueuePhysical
+ );
+
+
+ if (!Adapter->CommandQueue) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 3,
+ allocateAdapterMemory,
+ NE3200_ERRMSG_ALLOC_MEM,
+ 5
+ );
+
+ NE3200DeleteAdapterMemory(Adapter);
+ return FALSE;
+ }
+
+ //
+ // Set the tail pointer
+ //
+ Adapter->LastCommandBlockAllocated =
+ Adapter->CommandQueue + Adapter->NumberOfCommandBlocks;
+
+ //
+ // Clear the command list
+ //
+ NdisZeroMemory(
+ Adapter->CommandQueue,
+ sizeof(NE3200_SUPER_COMMAND_BLOCK) * Adapter->NumberOfCommandBlocks
+ );
+
+ //
+ // Put the Command Blocks into a known state.
+ //
+ for(
+ i = 0, CurrentCommandBlock = Adapter->CommandQueue;
+ i < Adapter->NumberOfCommandBlocks;
+ i++, CurrentCommandBlock++
+ ) {
+
+ CurrentCommandBlock->Hardware.State = NE3200_STATE_FREE;
+ CurrentCommandBlock->Hardware.NextPending = NE3200_NULL;
+
+ CurrentCommandBlock->NextCommand = NULL;
+
+ NdisSetPhysicalAddressHigh (CurrentCommandBlock->Self, 0);
+ NdisSetPhysicalAddressLow(
+ CurrentCommandBlock->Self,
+ NdisGetPhysicalAddressLow(Adapter->CommandQueuePhysical) +
+ i * sizeof(NE3200_SUPER_COMMAND_BLOCK));
+
+ CurrentCommandBlock->AvailableCommandBlockCounter =
+ &Adapter->NumberOfAvailableCommandBlocks;
+ CurrentCommandBlock->CommandBlockIndex = (USHORT)i;
+ CurrentCommandBlock->Timeout = FALSE;
+ }
+
+ //
+ // Now do the same for the public command queue.
+ //
+ for(
+ i = 0, CurrentCommandBlock = Adapter->PublicCommandQueue;
+ i < NE3200_NUMBER_OF_PUBLIC_CMD_BLOCKS;
+ i++, CurrentCommandBlock++
+ ) {
+
+ CurrentCommandBlock->Hardware.State = NE3200_STATE_FREE;
+ CurrentCommandBlock->Hardware.NextPending = NE3200_NULL;
+
+ CurrentCommandBlock->NextCommand = NULL;
+
+ NdisSetPhysicalAddressHigh (CurrentCommandBlock->Self, 0);
+ NdisSetPhysicalAddressLow(
+ CurrentCommandBlock->Self,
+ NdisGetPhysicalAddressLow(Adapter->PublicCommandQueuePhysical) +
+ i * sizeof(NE3200_SUPER_COMMAND_BLOCK));
+
+ CurrentCommandBlock->AvailableCommandBlockCounter =
+ &Adapter->NumberOfPublicCommandBlocks;
+ CurrentCommandBlock->CommandBlockIndex = (USHORT)i;
+ CurrentCommandBlock->Timeout = FALSE;
+ }
+
+
+ //
+ // Allocate Flush Buffer Pool
+ //
+ NdisAllocateBufferPool(
+ &Status,
+ (PVOID*)&Adapter->FlushBufferPoolHandle,
+ NE3200_NUMBER_OF_TRANSMIT_BUFFERS +
+ Adapter->NumberOfReceiveBuffers
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 3,
+ allocateAdapterMemory,
+ NE3200_ERRMSG_ALLOC_MEM,
+ 6
+ );
+
+ NE3200DeleteAdapterMemory(Adapter);
+ return FALSE;
+ }
+
+ //
+ // Allocate the Receive Queue.
+ //
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(NE3200_SUPER_RECEIVE_ENTRY) *
+ Adapter->NumberOfReceiveBuffers,
+ FALSE,
+ (PVOID*)&Adapter->ReceiveQueue,
+ &Adapter->ReceiveQueuePhysical
+ );
+
+ if (!Adapter->ReceiveQueue) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 3,
+ allocateAdapterMemory,
+ NE3200_ERRMSG_ALLOC_MEM,
+ 7
+ );
+
+ NE3200DeleteAdapterMemory(Adapter);
+ return FALSE;
+
+ }
+
+ //
+ // Clear the receive ring
+ //
+ NdisZeroMemory(
+ Adapter->ReceiveQueue,
+ sizeof(NE3200_SUPER_RECEIVE_ENTRY) * Adapter->NumberOfReceiveBuffers
+ );
+
+
+ //
+ // Allocate the receive buffers and attach them to the Receive
+ // Queue entries.
+ //
+ for(
+ i = 0, CurrentReceiveEntry = Adapter->ReceiveQueue;
+ i < Adapter->NumberOfReceiveBuffers;
+ i++, CurrentReceiveEntry++
+ ) {
+
+ //
+ // Allocate the actual receive buffers
+ //
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ NE3200_SIZE_OF_RECEIVE_BUFFERS,
+ TRUE,
+ &CurrentReceiveEntry->ReceiveBuffer,
+ &CurrentReceiveEntry->ReceiveBufferPhysical
+ );
+
+ if (!CurrentReceiveEntry->ReceiveBuffer) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 3,
+ allocateAdapterMemory,
+ NE3200_ERRMSG_ALLOC_MEM,
+ 8
+ );
+
+ NE3200DeleteAdapterMemory(Adapter);
+ return FALSE;
+
+ }
+
+ //
+ // Build flush buffers
+ //
+ NdisAllocateBuffer(
+ &Status,
+ &CurrentReceiveEntry->FlushBuffer,
+ Adapter->FlushBufferPoolHandle,
+ CurrentReceiveEntry->ReceiveBuffer,
+ NE3200_SIZE_OF_RECEIVE_BUFFERS
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 3,
+ allocateAdapterMemory,
+ NE3200_ERRMSG_ALLOC_MEM,
+ 9
+ );
+
+ NE3200DeleteAdapterMemory(Adapter);
+ return FALSE;
+ }
+
+ //
+ // Initialize receive buffers
+ //
+ NdisFlushBuffer(CurrentReceiveEntry->FlushBuffer, FALSE);
+
+ CurrentReceiveEntry->Hardware.State = NE3200_STATE_FREE;
+ CurrentReceiveEntry->Hardware.FrameSize = NE3200_SIZE_OF_RECEIVE_BUFFERS;
+ CurrentReceiveEntry->Hardware.NextPending =
+ NdisGetPhysicalAddressLow(Adapter->ReceiveQueuePhysical) +
+ (i + 1) * sizeof(NE3200_SUPER_RECEIVE_ENTRY);
+
+ CurrentReceiveEntry->Hardware.BufferDescriptor.BlockLength =
+ NE3200_SIZE_OF_RECEIVE_BUFFERS;
+ CurrentReceiveEntry->Hardware.BufferDescriptor.PhysicalAddress =
+ NdisGetPhysicalAddressLow(CurrentReceiveEntry->ReceiveBufferPhysical);
+
+ NdisSetPhysicalAddressHigh (CurrentReceiveEntry->Self, 0);
+ NdisSetPhysicalAddressLow(
+ CurrentReceiveEntry->Self,
+ NdisGetPhysicalAddressLow(Adapter->ReceiveQueuePhysical) +
+ i * sizeof(NE3200_SUPER_RECEIVE_ENTRY));
+
+ CurrentReceiveEntry->NextEntry = CurrentReceiveEntry + 1;
+
+ }
+
+ //
+ // Make sure the last entry is properly terminated.
+ //
+ (CurrentReceiveEntry - 1)->Hardware.NextPending = NE3200_NULL;
+ (CurrentReceiveEntry - 1)->NextEntry = Adapter->ReceiveQueue;
+
+ //
+ // Allocate the array of buffer descriptors.
+ //
+ NE3200_ALLOC_PHYS(
+ &Status,
+ &Adapter->NE3200Buffers,
+ sizeof(NE3200_BUFFER_DESCRIPTOR)*
+ (NE3200_NUMBER_OF_TRANSMIT_BUFFERS)
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 3,
+ allocateAdapterMemory,
+ NE3200_ERRMSG_ALLOC_MEM,
+ 0xA
+ );
+
+ NE3200DeleteAdapterMemory(Adapter);
+ return FALSE;
+ }
+
+ //
+ // Zero the memory of all the descriptors so that we can
+ // know which buffers weren't allocated incase we can't allocate
+ // them all.
+ //
+ NdisZeroMemory(
+ Adapter->NE3200Buffers,
+ sizeof(NE3200_BUFFER_DESCRIPTOR)*
+ (NE3200_NUMBER_OF_TRANSMIT_BUFFERS)
+ );
+
+
+ //
+ // Allocate each of the buffers and fill in the
+ // buffer descriptor.
+ //
+ Adapter->NE3200BufferListHead = 0;
+
+ for (
+ i = 0;
+ i < NE3200_NUMBER_OF_TRANSMIT_BUFFERS;
+ i++
+ ) {
+
+ //
+ // Allocate a buffer
+ //
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ NE3200_SIZE_OF_TRANSMIT_BUFFERS,
+ TRUE,
+ &Adapter->NE3200Buffers[i].VirtualNE3200Buffer,
+ &Adapter->NE3200Buffers[i].PhysicalNE3200Buffer
+ );
+
+ if (!Adapter->NE3200Buffers[i].VirtualNE3200Buffer) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 3,
+ allocateAdapterMemory,
+ NE3200_ERRMSG_ALLOC_MEM,
+ 0xB
+ );
+
+ NE3200DeleteAdapterMemory(Adapter);
+ return FALSE;
+
+ }
+
+ //
+ // Build flush buffers
+ //
+ NdisAllocateBuffer(
+ &Status,
+ &Adapter->NE3200Buffers[i].FlushBuffer,
+ Adapter->FlushBufferPoolHandle,
+ Adapter->NE3200Buffers[i].VirtualNE3200Buffer,
+ NE3200_SIZE_OF_TRANSMIT_BUFFERS
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 3,
+ allocateAdapterMemory,
+ NE3200_ERRMSG_ALLOC_MEM,
+ 0xC
+ );
+
+ NE3200DeleteAdapterMemory(Adapter);
+ return FALSE;
+ }
+
+ //
+ // Insert this buffer into the queue
+ //
+ Adapter->NE3200Buffers[i].Next = i+1;
+ Adapter->NE3200Buffers[i].BufferSize = NE3200_SIZE_OF_TRANSMIT_BUFFERS;
+
+ }
+
+ //
+ // Make sure that the last buffer correctly terminates the free list.
+ //
+ Adapter->NE3200Buffers[i-1].Next = -1;
+
+ return TRUE;
+
+}
+
+
+STATIC
+VOID
+NE3200DeleteAdapterMemory(
+ IN PNE3200_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deallocates memory for:
+
+ - Command Queue.
+
+ - Receive Queue.
+
+ - Receive buffers
+
+ - Transmit Buffers for use if user transmit buffers don't meet hardware
+ contraints
+
+ - Structures to map transmit ring entries back to the packets.
+
+Arguments:
+
+ Adapter - The adapter to deallocate memory for.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Do the public command queue
+ //
+ if (Adapter->PublicCommandQueue) {
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(NE3200_SUPER_COMMAND_BLOCK) * NE3200_NUMBER_OF_PUBLIC_CMD_BLOCKS,
+ FALSE,
+ Adapter->PublicCommandQueue,
+ Adapter->PublicCommandQueuePhysical
+ );
+ }
+
+ //
+ // The table for downloading multicast addresses
+ //
+ if (Adapter->CardMulticastTable) {
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ NE3200_SIZE_OF_MULTICAST_TABLE_ENTRY *
+ NE3200_MAXIMUM_MULTICAST,
+ FALSE,
+ Adapter->CardMulticastTable,
+ Adapter->CardMulticastTablePhysical
+ );
+
+ }
+
+ //
+ // The configuration block
+ //
+ if (Adapter->ConfigurationBlock) {
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(NE3200_CONFIGURATION_BLOCK),
+ FALSE,
+ Adapter->ConfigurationBlock,
+ Adapter->ConfigurationBlockPhysical
+ );
+
+ }
+
+ //
+ // The pad buffer for short packets
+ //
+ if (Adapter->PaddingVirtualAddress) {
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ MINIMUM_ETHERNET_PACKET_SIZE,
+ FALSE,
+ Adapter->PaddingVirtualAddress,
+ Adapter->PaddingPhysicalAddress
+ );
+
+ }
+
+ //
+ // The private command blocks
+ //
+ if (Adapter->CommandQueue) {
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(NE3200_SUPER_COMMAND_BLOCK) *
+ Adapter->NumberOfCommandBlocks,
+ FALSE,
+ Adapter->CommandQueue,
+ Adapter->CommandQueuePhysical
+ );
+
+ }
+
+
+ //
+ // The receive buffers
+ //
+ if (Adapter->ReceiveQueue) {
+
+ //
+ // Pointer to current Receive Entry being deallocated.
+ //
+ PNE3200_SUPER_RECEIVE_ENTRY CurrentReceiveEntry;
+
+ //
+ // Simple iteration counter.
+ //
+ UINT i;
+
+
+ for(
+ i = 0, CurrentReceiveEntry = Adapter->ReceiveQueue;
+ i < Adapter->NumberOfReceiveBuffers;
+ i++, CurrentReceiveEntry++
+ ) {
+
+
+ if (CurrentReceiveEntry->ReceiveBuffer) {
+
+ //
+ // Free the memory
+ //
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ NE3200_SIZE_OF_RECEIVE_BUFFERS,
+ TRUE,
+ CurrentReceiveEntry->ReceiveBuffer,
+ CurrentReceiveEntry->ReceiveBufferPhysical
+ );
+
+
+ if (CurrentReceiveEntry->FlushBuffer) {
+
+ //
+ // Free the flush buffer
+ //
+ NdisFreeBuffer(
+ CurrentReceiveEntry->FlushBuffer
+ );
+ }
+
+ }
+
+ }
+
+ //
+ // Free the receive ring
+ //
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(NE3200_SUPER_RECEIVE_ENTRY) *
+ Adapter->NumberOfReceiveBuffers,
+ FALSE,
+ Adapter->ReceiveQueue,
+ Adapter->ReceiveQueuePhysical
+ );
+
+ }
+
+ //
+ // Free the merge buffers
+ //
+ if (Adapter->NE3200Buffers) {
+
+ //
+ // Loop counter
+ //
+ UINT i;
+
+ for (
+ i = 0;
+ i < NE3200_NUMBER_OF_TRANSMIT_BUFFERS;
+ i++
+ ) {
+
+
+ if (Adapter->NE3200Buffers[i].VirtualNE3200Buffer) {
+
+ //
+ // Free the memory
+ //
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ NE3200_SIZE_OF_TRANSMIT_BUFFERS,
+ TRUE,
+ Adapter->NE3200Buffers[i].VirtualNE3200Buffer,
+ Adapter->NE3200Buffers[i].PhysicalNE3200Buffer
+ );
+
+ if (Adapter->NE3200Buffers[i].FlushBuffer) {
+
+ //
+ // Free the flush buffer
+ //
+ NdisFreeBuffer(
+ Adapter->NE3200Buffers[i].FlushBuffer
+ );
+
+ }
+
+ }
+
+ }
+
+ //
+ // Free the buffer ring
+ //
+ NE3200_FREE_PHYS(Adapter->NE3200Buffers);
+
+ }
+
+ if (Adapter->FlushBufferPoolHandle) {
+
+ //
+ // Free the buffer pool
+ //
+ NdisFreeBufferPool(
+ Adapter->FlushBufferPoolHandle
+ );
+
+ }
+
+}
+
+#pragma NDIS_INIT_FUNCTION(NE3200InitializeGlobals)
+
+STATIC
+BOOLEAN
+NE3200InitializeGlobals(
+ OUT PNE3200_GLOBAL_DATA Globals,
+ IN NDIS_HANDLE MiniportAdapterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will initialize the global data structure used
+ by all adapters managed by this driver. This routine is only
+ called once, when the driver is initializing the first
+ adapter.
+
+Arguments:
+
+ Globals - Pointer to the global data structure to initialize.
+
+ AdapterHandle - The handle to be used to allocate shared memory.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // File with the download code.
+ //
+ NDIS_STRING FileName=NDIS_STRING_CONST("ne3200.bin");
+
+ //
+ // Handle for the file.
+ //
+ NDIS_HANDLE FileHandle;
+
+ //
+ // Length of the file.
+ //
+ UINT FileLength;
+
+ //
+ // Status of NDIS calls
+ //
+ NDIS_STATUS Status;
+
+ //
+ // Virtual address of the download software in the file.
+ //
+ PVOID ImageBuffer;
+
+ //
+ // The value to return
+ //
+ BOOLEAN ReturnValue = TRUE;
+
+ //
+ // Save the adpater handle that did the allocations
+ //
+ Globals->MacBinAdapterHandle = MiniportAdapterHandle;
+
+ //
+ // Allocate the buffer.
+ //
+ NdisMAllocateSharedMemory(
+ MiniportAdapterHandle,
+ NE3200_MACBIN_LENGTH,
+ FALSE,
+ &Globals->MacBinVirtualAddress,
+ &Globals->MacBinPhysicalAddress
+ );
+
+ if (Globals->MacBinVirtualAddress == NULL) {
+ NE3200DestroyGlobals(Globals);
+ return FALSE;
+ }
+
+ //
+ // Store the length
+ //
+ Globals->MacBinLength = NE3200_MACBIN_LENGTH;
+
+
+ //
+ // Open the file with the download code
+ //
+ NdisOpenFile(
+ &Status,
+ &FileHandle,
+ &FileLength,
+ &FileName,
+ MinusOne
+ );
+
+ if (Status==NDIS_STATUS_SUCCESS) {
+
+ //
+ // Map the file into virtual memory
+ //
+ NdisMapFile(
+ &Status,
+ &ImageBuffer,
+ FileHandle
+ );
+
+ if (Status==NDIS_STATUS_SUCCESS) {
+
+ //
+ // Copy the download code into the shared memory space
+ //
+ NdisMoveMemory(Globals->MacBinVirtualAddress,ImageBuffer,FileLength);
+
+ //
+ // Done with the file
+ //
+ NdisUnmapFile(FileHandle);
+
+ } else {
+
+ ReturnValue = FALSE;
+
+ }
+
+ //
+ // Close the file
+ //
+ NdisCloseFile(FileHandle);
+
+ } else {
+
+ ReturnValue = FALSE;
+
+ }
+
+ //
+ // AdapterListHead is initially empty
+ //
+ InitializeListHead(&Globals->AdapterList);
+
+ //
+ // All done.
+ //
+ return ReturnValue;
+
+}
+
+
+STATIC
+VOID
+NE3200DestroyGlobals(
+ IN PNE3200_GLOBAL_DATA Globals
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees all global data allocated with
+ NE3200InitializeGlobals. This routine is called just before
+ the driver is unloaded.
+
+Arguments:
+
+ Globals - Pointer to the global data structure to destroy.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Free the memory with the download software in it.
+ //
+ if (Globals->MacBinVirtualAddress != NULL) {
+
+ NdisMFreeSharedMemory(
+ Globals->MacBinAdapterHandle,
+ NE3200_MACBIN_LENGTH,
+ FALSE,
+ Globals->MacBinVirtualAddress,
+ Globals->MacBinPhysicalAddress
+ );
+
+ }
+
+}
+
+#pragma NDIS_INIT_FUNCTION(NE3200Initialize)
+
+NDIS_STATUS
+NE3200Initialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+
+/*++
+
+Routine Description:
+
+ NE3200Initialize starts an adapter.
+
+Arguments:
+
+ See NDIS 3.0 Miniport spec.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_PENDING
+
+--*/
+
+{
+ //
+ // Handle returned by NdisOpenConfiguration
+ //
+ NDIS_HANDLE ConfigHandle;
+
+ //
+ // For changing the network address of this adapter.
+ //
+ NDIS_STRING NetAddrStr = NETWORK_ADDRESS;
+ UCHAR NetworkAddress[NE3200_LENGTH_OF_ADDRESS];
+ PUCHAR CurrentAddress;
+ PVOID NetAddress;
+ ULONG Length;
+
+ //
+ // The type of interrupt the adapter is set to use, level
+ // sensitive, or edged.
+ //
+ NDIS_INTERRUPT_MODE InterruptType;
+
+ //
+ // The interrupt number to use.
+ //
+ UINT InterruptVector;
+
+ //
+ // The slot number the adapter is located in
+ //
+ UINT EisaSlot;
+
+ //
+ // The port to look for in the EISA slot information
+ //
+ USHORT Portz800;
+
+ //
+ // The default value to use.
+ //
+ UCHAR z800Value;
+
+ //
+ // The mast to apply to the default values
+ //
+ UCHAR Mask;
+
+ //
+ // The type of initialization described in the EISA slot information.
+ //
+ UCHAR InitType;
+
+ //
+ // The port value for this iteration
+ //
+ UCHAR PortValue;
+
+ //
+ // The current port address to initialize
+ //
+ USHORT PortAddress;
+
+ //
+ // The location in the EISA slot information buffer
+ //
+ PUCHAR CurrentChar;
+
+ //
+ // Set to TRUE when done processing EISA slot information
+ //
+ BOOLEAN LastEntry;
+
+ //
+ // The EISA data
+ //
+ NDIS_EISA_FUNCTION_INFORMATION EisaData;
+
+ //
+ // Temporary looping variable
+ //
+ ULONG i;
+
+ //
+ // For signalling a configuration error
+ //
+ BOOLEAN ConfigError = FALSE;
+ NDIS_STATUS ConfigErrorCode;
+
+ //
+ // Status of NDIS calls
+ //
+ NDIS_STATUS Status;
+
+ //
+ // Search for the medium type (802.3)
+ //
+ for (i = 0; i < MediumArraySize; i++){
+
+ if (MediumArray[i] == NdisMedium802_3){
+
+ break;
+
+ }
+
+ }
+
+ //
+ // Ethernet was not found. Return an error.
+ //
+ if (i == MediumArraySize){
+
+ return NDIS_STATUS_UNSUPPORTED_MEDIA;
+
+ }
+
+ //
+ // Select ethernet
+ //
+ *SelectedMediumIndex = i;
+
+ //
+ // Open the configuration handle
+ //
+ NdisOpenConfiguration(
+ &Status,
+ &ConfigHandle,
+ ConfigurationHandle
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ return Status;
+ }
+
+ //
+ // Set address to default, using the burned in adapter address
+ //
+ CurrentAddress = NULL;
+
+ //
+ // Read an overriding net address
+ //
+ NdisReadNetworkAddress(
+ &Status,
+ &NetAddress,
+ &Length,
+ ConfigHandle
+ );
+
+ if ((Length == NE3200_LENGTH_OF_ADDRESS) && (Status == NDIS_STATUS_SUCCESS)) {
+
+ //
+ // Save overriding net address
+ //
+ NdisMoveMemory(
+ NetworkAddress,
+ NetAddress,
+ NE3200_LENGTH_OF_ADDRESS
+ );
+
+ CurrentAddress = NetworkAddress;
+
+ }
+
+ //
+ // Read the EISA configuration information
+ //
+ NdisReadEisaSlotInformation(
+ &Status,
+ ConfigurationHandle,
+ &EisaSlot,
+ &EisaData
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ ConfigError = TRUE;
+ ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION;
+
+ goto RegisterAdapter;
+
+ }
+
+ //
+ // Start at the beginning of the buffer
+ //
+ CurrentChar = EisaData.InitializationData;
+
+ //
+ // This is the port to look for
+ //
+ Portz800 = (EisaSlot << 12) + 0x800;
+
+ LastEntry = FALSE;
+
+ while (!LastEntry) {
+
+
+ InitType = *(CurrentChar++);
+ PortAddress = *((USHORT UNALIGNED *) CurrentChar++);
+ CurrentChar++;
+
+ //
+ // Check for last entry in EISA information
+ //
+ if ((InitType & 0x80) == 0) {
+ LastEntry = TRUE;
+ }
+
+ //
+ // Is this the port we are interested in?
+ //
+ if (PortAddress != Portz800) {
+ continue;
+ }
+
+ //
+ // Yes, get the port value to use
+ //
+ PortValue = *(CurrentChar++);
+
+ //
+ // Get the mask to use.
+ //
+ if (InitType & 0x40) {
+ Mask = *(CurrentChar++);
+ } else {
+ Mask = 0;
+ }
+
+ //
+ // Mask old value and or on new value.
+ //
+ z800Value &= Mask;
+ z800Value |= PortValue;
+ }
+
+ //
+ // Now, interpret the port data
+ //
+ // Get interrupt
+ //
+
+ switch (z800Value & 0x07) {
+ case 0x00:
+
+ ConfigError = TRUE;
+ ConfigErrorCode = NDIS_ERROR_CODE_HARDWARE_FAILURE;
+
+ goto RegisterAdapter;
+
+ case 0x01:
+ InterruptVector = 5;
+ break;
+ case 0x02:
+ InterruptVector = 9;
+ break;
+ case 0x03:
+ InterruptVector = 10;
+ break;
+ case 0x04:
+ InterruptVector = 11;
+ break;
+ case 0x05:
+ InterruptVector = 15;
+ break;
+ default:
+
+ ConfigError = TRUE;
+ ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION;
+
+ goto RegisterAdapter;
+
+ }
+
+ //
+ // Get interrupt mode
+ //
+
+ if (z800Value & 0x20) {
+ InterruptType = NdisInterruptLatched;
+ } else {
+ InterruptType = NdisInterruptLevelSensitive;
+ }
+
+RegisterAdapter:
+
+ //
+ // Were there any errors?
+ //
+ if (ConfigError) {
+
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ ConfigErrorCode,
+ 0
+ );
+
+ Status = NDIS_STATUS_FAILURE;
+
+ } else if (NE3200RegisterAdapter(
+ MiniportAdapterHandle,
+ EisaSlot,
+ InterruptVector,
+ InterruptType,
+ CurrentAddress
+ )) {
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ } else {
+
+ Status = NDIS_STATUS_FAILURE;
+
+ }
+
+ //
+ // All done
+ //
+ NdisCloseConfiguration(ConfigHandle);
+
+ return Status;
+}
+
+
+VOID
+NE3200Halt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ NE3200Halts removes an adapter previously initialized.
+
+Arguments:
+
+ MacAdapterContext - The context value that the Miniport returned
+ from Ne3200Initialize; actually as pointer to an NE3200_ADAPTER.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // The adapter to halt
+ //
+ PNE3200_ADAPTER Adapter;
+
+ Adapter = PNE3200_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ //
+ // Shut down the h/w
+ //
+ NE3200Shutdown(Adapter);
+
+ //
+ // Disconnect the interrupt
+ //
+ NdisMDeregisterInterrupt(&Adapter->Interrupt);
+
+ //
+ // Delete all resources
+ //
+ NE3200DeleteAdapterMemory(Adapter);
+
+ //
+ // Free map registers
+ //
+ NdisMFreeMapRegisters(Adapter->MiniportAdapterHandle);
+
+ //
+ // Remove ports
+ //
+ NdisMDeregisterIoPortRange(Adapter->MiniportAdapterHandle,
+ Adapter->AdapterIoBase,
+ 4,
+ (PVOID)Adapter->ResetPort
+ );
+
+ //
+ // Remove ports
+ //
+ NdisMDeregisterIoPortRange(Adapter->MiniportAdapterHandle,
+ Adapter->AdapterIoBase + NE3200_ID_PORT,
+ 0x20,
+ (PVOID)(Adapter->SystemInterruptPort -
+ NE3200_SYSTEM_INTERRUPT_PORT + NE3200_ID_PORT)
+ );
+
+ //
+ // Remove from global adapter list
+ //
+ RemoveEntryList(&Adapter->AdapterList);
+
+ //
+ // Free the adapter structure
+ //
+ NE3200_FREE_PHYS(Adapter);
+
+ return;
+}
+
+
+VOID
+NE3200Shutdown(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ NE3200Shutdown shuts down the h/w.
+
+Arguments:
+
+ MacAdapterContext - The context value that the Miniport returned
+ from Ne3200Initialize; actually as pointer to an NE3200_ADAPTER.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // The adapter to halt
+ //
+ PNE3200_ADAPTER Adapter;
+
+ //
+ // Temporary looping variable
+ //
+ ULONG i;
+
+ Adapter = PNE3200_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ //
+ // Shut down the chip.
+ //
+ NE3200StopChip(Adapter);
+
+ //
+ // Pause, waiting for the chip to stop.
+ //
+ NdisStallExecution(500000);
+
+ //
+ // Unfortunately, a hardware reset to the NE3200 does *not*
+ // reset the BMIC chip. To ensure that we read a proper status,
+ // we'll clear all of the BMIC's registers.
+ //
+ NE3200_WRITE_SYSTEM_INTERRUPT(
+ Adapter,
+ 0
+ );
+
+ //
+ // I changed this to ff since the original 0 didn't work for
+ // some cases. since we don't have the specs....
+ //
+ NE3200_WRITE_LOCAL_DOORBELL_INTERRUPT(
+ Adapter,
+ 0xff
+ );
+
+ NE3200_WRITE_SYSTEM_DOORBELL_MASK(
+ Adapter,
+ 0
+ );
+
+ SyncNE3200ClearDoorbellInterrupt(Adapter);
+
+ for (i = 0 ; i < 16 ; i += 4 ) {
+
+ NE3200_WRITE_MAILBOX_ULONG(
+ Adapter,
+ i,
+ 0L
+ );
+ }
+
+ //
+ // Toggle the NE3200's reset line.
+ //
+ NE3200_WRITE_RESET(
+ Adapter,
+ NE3200_RESET_BIT_ON
+ );
+}
+
+
+NDIS_STATUS
+NE3200TransferData(
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+ )
+
+/*++
+
+Routine Description:
+
+ A protocol calls the NE3200TransferData request (indirectly via
+ NdisTransferData) from within its Receive event handler
+ to instruct the Miniport to copy the contents of the received packet
+ a specified paqcket buffer.
+
+Arguments:
+
+ MiniportAdapterContext - The context value returned by the driver when the
+ adapter was initialized. In reality this is a pointer to NE3200_ADAPTER.
+
+ MiniportReceiveContext - The context value passed by the driver on its call
+ to NdisMIndicateReceive. The driver can use this value to determine
+ which packet, on which adapter, is being received.
+
+ ByteOffset - An unsigned integer specifying the offset within the
+ received packet at which the copy is to begin. If the entire packet
+ is to be copied, ByteOffset must be zero.
+
+ BytesToTransfer - An unsigned integer specifying the number of bytes
+ to copy. It is legal to transfer zero bytes; this has no effect. If
+ the sum of ByteOffset and BytesToTransfer is greater than the size
+ of the received packet, then the remainder of the packet (starting from
+ ByteOffset) is transferred, and the trailing portion of the receive
+ buffer is not modified.
+
+ Packet - A pointer to a descriptor for the packet storage into which
+ the MAC is to copy the received packet.
+
+ BytesTransfered - A pointer to an unsigned integer. The MAC writes
+ the actual number of bytes transferred into this location. This value
+ is not valid if the return status is STATUS_PENDING.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+
+{
+ //
+ // The adapter to transfer from
+ //
+ PNE3200_ADAPTER Adapter;
+
+ //
+ // Holds the count of the number of ndis buffers comprising the
+ // destination packet.
+ //
+ UINT DestinationBufferCount;
+
+ //
+ // Points to the buffer into which we are putting data.
+ //
+ PNDIS_BUFFER DestinationCurrentBuffer;
+
+ //
+ // Points to the location in Buffer from which we are extracting data.
+ //
+ PUCHAR SourceCurrentAddress;
+
+ //
+ // Holds the virtual address of the current destination buffer.
+ //
+ PVOID DestinationVirtualAddress;
+
+ //
+ // Holds the length of the current destination buffer.
+ //
+ UINT DestinationCurrentLength;
+
+ //
+ // Keep track of the bytes transferred so far.
+ //
+ UINT LocalBytesCopied = 0;
+
+ //
+ // Get the adapter structure
+ //
+ Adapter = PNE3200_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ *BytesTransferred = 0;
+
+ //
+ // Take care of boundary condition of zero length copy.
+ //
+ if (!BytesToTransfer) {
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ //
+ // Get the first buffer of the destination.
+ //
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ &DestinationBufferCount,
+ &DestinationCurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet.
+ //
+ if (!DestinationBufferCount) {
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ //
+ // Get first buffer information
+ //
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+
+ //
+ // Set up the source address.
+ //
+ SourceCurrentAddress = (PUCHAR)(MiniportReceiveContext) + ByteOffset + NE3200_HEADER_SIZE;
+
+ //
+ // While there is still data to copy
+ //
+ while (LocalBytesCopied < BytesToTransfer) {
+
+ //
+ // Check to see whether we've exhausted the current destination
+ // buffer. If so, move onto the next one.
+ //
+ if (!DestinationCurrentLength) {
+
+ //
+ // Get the next buffer
+ //
+ NdisGetNextBuffer(
+ DestinationCurrentBuffer,
+ &DestinationCurrentBuffer
+ );
+
+ if (!DestinationCurrentBuffer) {
+
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.)
+ //
+ break;
+
+ }
+
+ //
+ // Get this buffers information
+ //
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+
+ continue;
+
+ }
+
+ //
+ // Copy the data.
+ //
+ {
+
+ //
+ // Holds the amount of data to move.
+ //
+ UINT AmountToMove;
+
+ //
+ // Holds the amount desired remaining.
+ //
+ UINT Remaining = BytesToTransfer - LocalBytesCopied;
+
+
+ AmountToMove = DestinationCurrentLength;
+
+ AmountToMove = ((Remaining < AmountToMove)?
+ (Remaining):(AmountToMove));
+
+ NE3200_MOVE_MEMORY(
+ DestinationVirtualAddress,
+ SourceCurrentAddress,
+ AmountToMove
+ );
+
+ SourceCurrentAddress += AmountToMove;
+ LocalBytesCopied += AmountToMove;
+ DestinationCurrentLength -= AmountToMove;
+
+ }
+
+ }
+
+ *BytesTransferred = LocalBytesCopied;
+
+ return NDIS_STATUS_SUCCESS;
+
+}
+
+STATIC
+NDIS_STATUS
+NE3200Reset(
+ OUT PBOOLEAN AddressingReset,
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+/*++
+
+Routine Description:
+
+ The NE3200Reset request instructs the Miniport to issue a hardware reset
+ to the network adapter. The driver also resets its software state. See
+ the description of NdisMReset for a detailed description of this request.
+
+Arguments:
+
+ MiniportAdapterContext - Pointer to the adapter structure.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+
+{
+ //
+ // The adapter to reset
+ //
+ PNE3200_ADAPTER Adapter = PNE3200_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ IF_LOG('w');
+
+ //
+ // Start the reset process
+ //
+ NE3200SetupForReset(
+ Adapter
+ );
+
+ //
+ // Call Handle interrupt to continue the reset process
+ //
+ NE3200HandleInterrupt(
+ (NDIS_HANDLE)Adapter
+ );
+
+ IF_LOG('W');
+
+ return NDIS_STATUS_PENDING;
+}
+
+BOOLEAN
+NE3200CheckForHang(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to check on the head of the command
+ block queue. It will fire off the queue if the head has
+ been sleeping on the job.
+
+ It also detects when the ne3200 adapter has failed, where the
+ symptoms are that the adapter will transmit packets, but will
+ not receive them.
+
+Arguments:
+
+ Context - Really a pointer to the adapter.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // The adapter to check over
+ //
+ PNE3200_ADAPTER Adapter = PNE3200_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ //
+ // The first command that is outstanding
+ //
+ PNE3200_SUPER_COMMAND_BLOCK FirstPending = Adapter->FirstCommandOnCard;
+
+ //
+ // Check if the command is stalled
+ //
+ if( (FirstPending != NULL) &&
+ (FirstPending->Hardware.State == NE3200_STATE_WAIT_FOR_ADAPTER) ) {
+
+ //
+ // See if the command block has timed-out.
+ //
+
+ if ( FirstPending->Timeout ) {
+
+ if ( FirstPending->TimeoutCount >= 2) {
+
+ //
+ // Give up, the card appears dead.
+ //
+ Adapter->ResetAsynchronous = TRUE;
+ Adapter->SendInterrupt = FALSE;
+ Adapter->NoReceiveInterruptCount = 0;
+
+ return TRUE;
+
+ } else {
+
+ //
+ // Re-sumbit the block.
+ //
+ NE3200_WRITE_COMMAND_POINTER(
+ Adapter,
+ NdisGetPhysicalAddressLow(FirstPending->Self)
+ );
+
+ NE3200_WRITE_LOCAL_DOORBELL_INTERRUPT(
+ Adapter,
+ NE3200_LOCAL_DOORBELL_NEW_COMMAND
+ );
+
+ IF_LOG('+');
+
+ FirstPending->TimeoutCount++;
+
+ }
+
+ } else {
+
+ IF_LOG('0');
+
+ //
+ // Let the next call find the stall
+ //
+ FirstPending->Timeout = TRUE;
+ FirstPending->TimeoutCount = 0;
+
+ }
+
+ }
+
+ //
+ // Check if the receive side has died.
+ //
+ if ((!Adapter->ReceiveInterrupt) && (Adapter->SendInterrupt)) {
+
+ //
+ // If we go five times with no receives, but we are sending then
+ // we will reset the adapter.
+ //
+ if ((Adapter->NoReceiveInterruptCount == 5) && !Adapter->ResetInProgress) {
+
+ //
+ // We've waited long enough
+ //
+ Adapter->ResetAsynchronous = TRUE;
+ Adapter->SendInterrupt = FALSE;
+ Adapter->NoReceiveInterruptCount = 0;
+
+ return(TRUE);
+
+ } else {
+
+ Adapter->NoReceiveInterruptCount++;
+
+ }
+
+ } else {
+
+ //
+ // If we got a receive or there are no sends, doesn't matter. Reset
+ // the state.
+ //
+ Adapter->SendInterrupt = FALSE;
+ Adapter->ReceiveInterrupt = FALSE;
+ Adapter->NoReceiveInterruptCount = 0;
+
+ }
+
+ return(FALSE);
+
+}
diff --git a/private/ntos/ndis/ne3200/ne3200.ini b/private/ntos/ndis/ne3200/ne3200.ini
new file mode 100644
index 000000000..356d754e9
--- /dev/null
+++ b/private/ntos/ndis/ne3200/ne3200.ini
@@ -0,0 +1,18 @@
+//
+// This section is used to configure the Novell NE3200 Ethernet adapter for
+// non-Compaq machines. This section will be removed when the registry
+// becomes available. These values must matched the ones configured using
+// the EISA configuration utility.
+//
+// Defaults are shown below.
+//
+
+
+[NE3200Sys]
+ Bind1=\Device\NE32001
+
+[NE32001]
+ InterruptNumber = 9
+ InterruptType = EdgeTriggered
+ SlotNumber = 3
+
diff --git a/private/ntos/ndis/ne3200/ne3200.prf b/private/ntos/ndis/ne3200/ne3200.prf
new file mode 100644
index 000000000..814c0d1ff
--- /dev/null
+++ b/private/ntos/ndis/ne3200/ne3200.prf
@@ -0,0 +1,40 @@
+NE3200ChangeClass@8
+@NE3200RelinquishCommandBlock@8
+NE3200CheckForHang@4
+NE3200DisableInterrupt@4
+NE3200HandleInterrupt@4
+NE3200TransmitPacket@20
+@NE3200ProcessCommandInterrupts@4
+@Ne3200Stall@4
+NE3200EnableInterrupt@4
+NE3200Send@12
+@NE3200ProcessReceiveInterrupts@4
+NE3200UpdateMulticastTable@12
+NE3200EnableAdapter@4
+NE3200ChangeCurrentAddress@4
+NE3200FinishQueryInformation@4
+NE3200QueryInformation@24
+NE3200SetConfigurationBlock@4
+NE3200DoAdapterReset@4
+NE3200ConstrainPacket@8
+NE3200SetupForReset@4
+NE3200ResetHandler@16
+NE3200Reset@8
+NE3200TransmitMergedPacket@8
+NE3200GetStationAddress@4
+NE3200SetInformation@24
+NE3200ResetCommandBlocks@4
+SyncNE3200ClearDoorbellInterrupt@4
+NE3200StartChipAndDisableInterrupts@8
+NE3200DoResetIndications@8
+NE3200AcquirePublicCommandBlock@8
+NE3200Isr@12
+NE3200SetConfigurationBlockAndInit@4
+NE3200ResetVariables@4
+NE3200Initialize@24
+NE3200StopChip@4
+NE3200AllocateAdapterMemory@4
+NE3200InitialInit@12
+NE3200RegisterAdapter@20
+NE3200InitializeGlobals@8
+DriverEntry@8
diff --git a/private/ntos/ndis/ne3200/ne3200.rc b/private/ntos/ndis/ne3200/ne3200.rc
new file mode 100644
index 000000000..14c68c9ad
--- /dev/null
+++ b/private/ntos/ndis/ne3200/ne3200.rc
@@ -0,0 +1,39 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "Novell NE3200 network driver"
+#define VER_INTERNALNAME_STR "NE3200.SYS"
+#define VER_ORIGINALFILENAME_STR "NE3200.SYS"
+
+#include "common.ver"
+
diff --git a/private/ntos/ndis/ne3200/ne3200hw.h b/private/ntos/ndis/ne3200/ne3200hw.h
new file mode 100644
index 000000000..ab640b819
--- /dev/null
+++ b/private/ntos/ndis/ne3200/ne3200hw.h
@@ -0,0 +1,964 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ne3200hw.h
+
+Abstract:
+
+ Hardware specific values for the Novell NE3200 NDIS 3.0 driver.
+
+Author:
+
+ Keith Moore (KeithMo) 08-Jan-1991
+
+Environment:
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+
+--*/
+
+#ifndef _NE3200HARDWARE_
+#define _NE3200HARDWARE_
+
+//
+// Defines for the packet and media specific information
+//
+#define MINIMUM_ETHERNET_PACKET_SIZE ((UINT)60)
+#define MAXIMUM_ETHERNET_PACKET_SIZE ((UINT)1514)
+#define NE3200_LENGTH_OF_ADDRESS 6
+
+//
+// The default interrupt number.
+//
+#define NE3200_DEFAULT_INTERRUPT_VECTOR ((CCHAR)11)
+
+//
+// The following parameters *MUST* each be a greater than one!
+//
+// The number of receive buffers to allocate.
+// The number of transmit buffers to allocate.
+// The number of command blocks for transmits that the driver has available.
+// The number of command blocks for requests the driver has availabale.
+//
+#define NE3200_NUMBER_OF_RECEIVE_BUFFERS ((UINT)16)
+#define NE3200_NUMBER_OF_TRANSMIT_BUFFERS ((UINT)4)
+#define NE3200_NUMBER_OF_COMMAND_BLOCKS ((UINT)8)
+#define NE3200_NUMBER_OF_PUBLIC_CMD_BLOCKS ((UINT)3)
+
+
+//
+// MAC.BIN info.
+//
+#define NE3200_MAXIMUM_MACBIN_SIZE ((ULONG)16384)
+#define NE3200_MACBIN_LENGTH 4096
+
+
+//
+// This is the number of bytes per entry in the multicast table
+// as presented to the NE3200. Note that this is *not* the number
+// of bytes in a multicast address, just the number of bytes per
+// table entry. For some goofy reason, MAC.BIN requires the table
+// used in the NE3200_COMMAND_SET_MULTICAST_ADDRESS command to have
+// 16 bytes per entry.
+//
+#define NE3200_SIZE_OF_MULTICAST_TABLE_ENTRY ((UINT)16)
+#define NE3200_MAXIMUM_MULTICAST ((UINT)50)
+
+
+//
+// Our buffer sizes.
+//
+// These are *not* configurable. Portions of the code assumes
+// that these buffers can contain *any* legal Ethernet packet.
+//
+#define NE3200_SIZE_OF_TRANSMIT_BUFFERS (MAXIMUM_ETHERNET_PACKET_SIZE)
+#define NE3200_SIZE_OF_RECEIVE_BUFFERS (MAXIMUM_ETHERNET_PACKET_SIZE)
+
+
+//
+// I/O Port Address.
+//
+// Note that the NE3200 uses EISA Slot-Specific Addressing. In
+// this method, each slot has its own I/O address space. This space
+// begins at the slot number shifted left 12 bits. For example,
+// the I/O space for slot number 6 begins at I/O address 6000h.
+//
+// Each of the following addresses are offset from the start of
+// slot-specific I/O space.
+//
+#define NE3200_RESET_PORT ((USHORT)0x0000)
+#define NE3200_ID_PORT ((USHORT)0x0C80)
+#define NE3200_GLOBAL_CONFIGURATION_PORT ((USHORT)0x0C88)
+#define NE3200_SYSTEM_INTERRUPT_PORT ((USHORT)0x0C89)
+#define NE3200_LOCAL_DOORBELL_MASK_PORT ((USHORT)0x0C8C)
+#define NE3200_LOCAL_DOORBELL_INTERRUPT_PORT ((USHORT)0x0C8D)
+#define NE3200_SYSTEM_DOORBELL_MASK_PORT ((USHORT)0x0C8E)
+#define NE3200_SYSTEM_DOORBELL_INTERRUPT_PORT ((USHORT)0x0C8F)
+#define NE3200_BASE_MAILBOX_PORT ((USHORT)0x0C90)
+
+
+//
+// Definitions for NE3200_RESET_PORT.
+//
+#define NE3200_RESET_BIT_ON ((UCHAR)1)
+#define NE3200_RESET_BIT_OFF ((UCHAR)0)
+
+
+//
+// Mailbox Registers
+//
+#define NE3200_MAILBOX_RESET_STATUS ((USHORT)0x0000)
+#define NE3200_MAILBOX_COMMAND_POINTER ((USHORT)0x0000)
+#define NE3200_MAILBOX_MACBIN_LENGTH ((USHORT)0x0001)
+#define NE3200_MAILBOX_MACBIN_DOWNLOAD_MODE ((USHORT)0x0003)
+#define NE3200_MAILBOX_RECEIVE_POINTER ((USHORT)0x0004)
+#define NE3200_MAILBOX_MACBIN_POINTER ((USHORT)0x0004)
+#define NE3200_MAILBOX_STATUS ((USHORT)0x0008)
+#define NE3200_MAILBOX_MACBIN_TARGET ((USHORT)0x0008)
+#define NE3200_MAILBOX_STATION_ID ((USHORT)0x000A)
+
+
+//
+// Values for MAC.BIN download
+//
+#define NE3200_MACBIN_DIRECT ((UCHAR)0x80)
+#define NE3200_MACBIN_TARGET_ADDRESS ((USHORT)0x0400)
+
+
+//
+// Status read from NE3200_MAILBOX_RESET_STATUS after hardware reset
+//
+#define NE3200_RESET_FAILED ((UCHAR)0x40)
+#define NE3200_RESET_PASSED ((UCHAR)0x80)
+
+
+//
+// Status read from NE3200_MAILBOX_STATUS after initialization
+//
+#define NE3200_INITIALIZATION_FAILED ((UCHAR)0x20)
+#define NE3200_INITIALIZATION_PASSED ((UCHAR)0x60)
+
+
+//
+// Local DoorBell bits
+//
+#define NE3200_LOCAL_DOORBELL_NEW_COMMAND ((UCHAR)0x01)
+#define NE3200_LOCAL_DOORBELL_RESET ((UCHAR)0x04)
+#define NE3200_LOCAL_DOORBELL_INITIALIZE ((UCHAR)0x10)
+#define NE3200_LOCAL_DOORBELL_NEW_RECEIVE ((UCHAR)0x20)
+
+#define NE3200_LOCAL_DOORBELL_MASK \
+ ( NE3200_LOCAL_DOORBELL_NEW_COMMAND \
+ | NE3200_LOCAL_DOORBELL_RESET \
+ | NE3200_LOCAL_DOORBELL_INITIALIZE \
+ | NE3200_LOCAL_DOORBELL_NEW_RECEIVE )
+
+
+//
+// System DoorBell bits
+//
+#define NE3200_SYSTEM_DOORBELL_PACKET_RECEIVED ((UCHAR)0x01)
+#define NE3200_SYSTEM_DOORBELL_COMMAND_COMPLETE ((UCHAR)0x02)
+#define NE3200_SYSTEM_DOORBELL_RESET_COMPLETE ((UCHAR)0x04)
+#define NE3200_SYSTEM_DOORBELL_INIT_COMPLETE ((UCHAR)0x08)
+#define NE3200_SYSTEM_DOORBELL_SELF_RESET ((UCHAR)0x10)
+
+#define NE3200_SYSTEM_DOORBELL_MASK \
+ ( NE3200_SYSTEM_DOORBELL_PACKET_RECEIVED \
+ | NE3200_SYSTEM_DOORBELL_COMMAND_COMPLETE)
+
+
+//
+// System Interrupt Mask/Control bits
+//
+#define NE3200_SYSTEM_INTERRUPT_ENABLE ((UCHAR)0x01)
+#define NE3200_SYSTEM_INTERRUPT_PENDING ((UCHAR)0x02)
+
+
+//
+// NE3200 Command Codes
+//
+#define NE3200_COMMAND_NOP ((UCHAR)0x00)
+#define NE3200_COMMAND_SET_STATION_ADDRESS ((UCHAR)0x01)
+#define NE3200_COMMAND_CONFIGURE_82586 ((UCHAR)0x02)
+#define NE3200_COMMAND_SET_MULTICAST_ADDRESS ((UCHAR)0x03)
+#define NE3200_COMMAND_TRANSMIT ((UCHAR)0x04)
+#define NE3200_COMMAND_READ_ADAPTER_STATISTICS ((UCHAR)0x08)
+#define NE3200_COMMAND_INITIALIZE_ADAPTER ((UCHAR)0x09)
+#define NE3200_COMMAND_CLEAR_ADAPTER_STATISTICS ((UCHAR)0x0A)
+
+
+//
+// NE3200 Receive/Command Block States
+//
+#define NE3200_STATE_FREE ((USHORT)0x0000)
+#define NE3200_STATE_EXECUTION_COMPLETE ((USHORT)0x0001)
+#define NE3200_STATE_WAIT_FOR_ADAPTER ((USHORT)0x0002)
+
+
+//
+// NE3200 Command Block Status
+//
+
+//
+// These apply to all commands.
+//
+#define NE3200_STATUS_COMPLETE ((USHORT)0x8000)
+#define NE3200_STATUS_BUSY ((USHORT)0x4000)
+#define NE3200_STATUS_SUCCESS ((USHORT)0x2000)
+#define NE3200_STATUS_ABORTED ((USHORT)0x1000)
+#define NE3200_STATUS_GENERIC_MASK ((USHORT)0xF000)
+
+//
+// These apply to transmit only.
+//
+#define NE3200_STATUS_NO_CARRIER ((USHORT)0x0400)
+#define NE3200_STATUS_NO_CLEAR_TO_SEND ((USHORT)0x0200)
+#define NE3200_STATUS_DMA_UNDERRUN ((USHORT)0x0100)
+#define NE3200_STATUS_TRANSMIT_DEFERRED ((USHORT)0x0080)
+#define NE3200_STATUS_HEART_BEAT ((USHORT)0x0040)
+#define NE3200_STATUS_MAXIMUM_COLLISIONS ((USHORT)0x0020)
+#define NE3200_STATUS_COLLISION_MASK ((USHORT)0x000F)
+#define NE3200_STATUS_FATALERROR_MASK (NE3200_STATUS_NO_CARRIER | \
+ NE3200_STATUS_NO_CLEAR_TO_SEND | \
+ NE3200_STATUS_DMA_UNDERRUN | \
+ NE3200_STATUS_HEART_BEAT | \
+ NE3200_STATUS_MAXIMUM_COLLISIONS)
+
+//
+// This defines a "proper" command complete status.
+//
+#define NE3200_STATUS_COMMAND_COMPLETE (NE3200_STATUS_COMPLETE | \
+ NE3200_STATUS_SUCCESS)
+
+
+//
+// Timeout constants
+//
+// Each of these timeout constants represents the time to wait
+// for a particular event to occur. For example, NE3200_TIMEOUT_RESET
+// represents the amount of time to wait for an adapter reset to
+// complete. Each of these values is in units of 1/100 of a second.
+// Therefore, a value of 200 would be approximately 2 seconds.
+//
+#define NE3200_TIMEOUT_RESET 200
+#define NE3200_TIMEOUT_DOWNLOAD 100
+
+//
+// This timeout represents the maximum amount of time we'll wait
+// for an NE3200 command to complete. This value is in units of
+// 1/1000 of a second. Therefore, a value of 2000 would be approximately
+// 2 seconds.
+//
+#define NE3200_TIMEOUT_COMMAND 2000
+
+
+//
+// This type defines the physical addresses used by the NE3200
+// card itself. This should always be four bytes.
+//
+typedef ULONG NE3200_PHYSICAL_ADDRESS, *PNE3200_PHYSICAL_ADDRESS;
+
+
+//
+// Miscellaneous Constants
+//
+#define NE3200_NULL ((NE3200_PHYSICAL_ADDRESS)(-1L))
+#define NE3200_MAXIMUM_BLOCKS_PER_PACKET ((UINT)4)
+#define NE3200_IMMEDIATE_DATA_LENGTH ((UINT)64)
+
+
+
+//
+// Force misalignment of the following structures
+//
+#include <pshpack1.h>
+
+
+//
+// NE3200 Data Block Descriptor
+//
+typedef struct _NE3200_DATA_BLOCK {
+
+ //
+ // This is the length (in bytes) of this block.
+ //
+ USHORT BlockLength;
+
+ //
+ // This is the physical address of this block.
+ //
+ NE3200_PHYSICAL_ADDRESS PhysicalAddress;
+
+} NE3200_DATA_BLOCK, *PNE3200_DATA_BLOCK;
+
+
+//
+// NE3200 Receive Ring Entry
+//
+typedef struct _NE3200_RECEIVE_ENTRY {
+
+ //
+ // This 4-byte field is unused by MAC.BIN and is
+ // available for use by the driver. We'll use
+ // this field as . . .
+ //
+ UCHAR Available1[4];
+
+ //
+ // This is the state of this Receive Ring entry.
+ //
+ USHORT State;
+
+ //
+ // This is the total size of the received frame.
+ //
+ USHORT FrameSize;
+
+ //
+ // This is the physical address of the next entry
+ // in the Receive Ring.
+ //
+ NE3200_PHYSICAL_ADDRESS NextPending;
+
+ //
+ // This 6-byte field is unused by MAC.BIN and is
+ // available for use by the driver. We'll use
+ // this field as . . .
+ //
+ UCHAR Available2[6];
+
+ //
+ // This is the descriptor which specifies the
+ // receive buffer used by this entry.
+ //
+ NE3200_DATA_BLOCK BufferDescriptor;
+
+} NE3200_RECEIVE_ENTRY, *PNE3200_RECEIVE_ENTRY;
+
+
+//
+// NE3200 Command Block
+//
+typedef struct _NE3200_COMMAND_BLOCK {
+
+ //
+ // This 4-byte field is unused by MAC.BIN and is
+ // available for use by the driver. We'll use
+ // this field as . . .
+ //
+ UCHAR Available1[4];
+
+ //
+ // This is the state of this Command Block.
+ //
+ USHORT State;
+
+ //
+ // This is the status of this Command Block.
+ //
+ USHORT Status;
+
+ //
+ // This is the physical address of the next Command Block
+ // to be executed. If this address == -1, then there are
+ // no more commands to be executed.
+ //
+ NE3200_PHYSICAL_ADDRESS NextPending;
+
+ //
+ // This 1-byte field is unused by MAC.BIN and is
+ // available for use by the driver. We'll use
+ // this field as . . .
+ //
+ UCHAR Available2[1];
+
+ //
+ // This is the NE3200 Command Code.
+ //
+ UCHAR CommandCode;
+
+ //
+ // This 1-byte field is unused by MAC.BIN and is
+ // available for use by the driver. We'll use
+ // this field as . . .
+ //
+ UCHAR Available3[1];
+
+ //
+ // The following eight bytes are used as parameters
+ // by various NE3200 commands.
+ //
+ union _PARAMETERS {
+
+ //
+ // Parameters for NE3200_COMMAND_SET_STATION_ADDRESS.
+ //
+ struct _SET_ADDRESS {
+
+ //
+ // This field contains the new station address.
+ //
+ IN UCHAR NewStationAddress[NE3200_LENGTH_OF_ADDRESS];
+
+ } SET_ADDRESS;
+
+ //
+ // Parameters for NE3200_COMMAND_CONFIGURE_82586.
+ //
+ struct _CONFIGURE {
+
+ //
+ // This field holds the physical address of
+ // the configuration block.
+ //
+ IN NE3200_PHYSICAL_ADDRESS ConfigurationBlock;
+
+ } CONFIGURE;
+
+ //
+ // Parameters for NE3200_COMMAND_SET_MULTICAST_ADDRESS.
+ //
+ struct _MULTICAST {
+
+ //
+ // This field holds the physical address of
+ // the multicast address table.
+ //
+ IN NE3200_PHYSICAL_ADDRESS MulticastAddressTable;
+
+ //
+ // This field holds the number of multicast
+ // address in the multicast address table.
+ //
+ IN USHORT NumberOfMulticastAddresses;
+
+ } MULTICAST;
+
+ //
+ // Parameters for NE3200_COMMAND_TRANSMIT.
+ //
+ struct _TRANSMIT {
+
+ //
+ // This field holds the length of "immediate data"
+ // to be transmitted.
+ //
+ IN USHORT ImmediateDataLength;
+
+ } TRANSMIT;
+
+ //
+ // Parameters for NE3200_READ_ADAPTER_STATISTICS.
+ //
+ struct _STATISTICS {
+
+ //
+ // The following fields are filled in by the adapter
+ // when it executes the NE3200_READ_ADAPTER_STATISTICS
+ // command.
+ //
+
+ //
+ // This field holds the number of properly aligned
+ // frames received with a CRC error.
+ //
+ OUT USHORT CrcErrors;
+
+ //
+ // This field holds the number of misaligned frames
+ // received.
+ //
+ OUT USHORT AlignmentErrors;
+
+ //
+ // This field holds the number of resource errors
+ // (the number of frames which were discarded due
+ // to lack of memory resources such as buffer space
+ // or receive frame descriptors).
+ //
+ OUT USHORT ResourceErrors;
+
+ //
+ // This field holds the number of received frame
+ // sequeneces lost because the memory bus was
+ // not available in time for the transfer.
+ //
+ OUT USHORT OverrunErrors;
+
+ } STATISTICS;
+
+ //
+ // This field holds the raw data.
+ //
+ IN OUT USHORT RawParameters[4];
+
+ } PARAMETERS;
+
+ //
+ // This is the total size of the frame to be transmitted.
+ //
+ USHORT TransmitFrameSize;
+
+ //
+ // This is the number of data blocks in the frame to be
+ // transmitted.
+ //
+ UCHAR NumberOfDataBlocks;
+
+ //
+ // These are the descriptors describing the transmit packet.
+ //
+ NE3200_DATA_BLOCK TransmitDataBlocks[NE3200_MAXIMUM_BLOCKS_PER_PACKET];
+
+ //
+ // This is the immediate data to be used by all commands
+ // other than transmit.
+ //
+ UCHAR ImmediateData[NE3200_IMMEDIATE_DATA_LENGTH];
+
+} NE3200_COMMAND_BLOCK, *PNE3200_COMMAND_BLOCK;
+
+
+//
+// NE3200 Configuration Block
+//
+// This structure contains configuration data for the NE3200's
+// on-board 82586 Lan Coprocessor. The majority of this data
+// will not change during operation of the driver.
+//
+typedef struct _NE3200_CONFIGURATION_BLOCK {
+
+ //
+ // This field contains the number of bytes in the
+ // Configuration Block.
+ //
+ // In this implementation, this will always be 12.
+ //
+ USHORT ByteCount:4;
+
+ //
+ // This field is undefined by the 82586.
+ //
+ USHORT Undefined1:4;
+
+ //
+ // This field contains the FIFO threshold.
+ //
+ // In this implementation, this will always be 8.
+ //
+ USHORT FifoThreshold:4;
+
+ //
+ // This field is undefined by the 82586.
+ //
+ USHORT Undefined2:4;
+
+ //
+ // This field is undefined by the 82586.
+ //
+ USHORT Undefined3:6;
+
+ //
+ // If this field is set to 0, the 82586 operates with
+ // internal synchronization. If set to 1, the 82586
+ // uses external synchronization.
+ //
+ // This will always be set to 0 in this implementation
+ // (internal synchronization).
+ //
+ USHORT Synchronization:1;
+
+ //
+ // If this field is set to 0, the 82586 will not save
+ // bad frames in memory. If set to 1, the 82856 will
+ // save bad frames.
+ //
+ // In this implementation, this will always be 0
+ // (don't save bad frames).
+ //
+ USHORT SaveBadFrames:1;
+
+ //
+ // This field contains the number of bytes in a
+ // network address.
+ //
+ // In this implementation, this will always be 6.
+ //
+ USHORT AddressLength:3;
+
+ //
+ // If this field is set to 0, then the Destination
+ // Network Address is part of the Transmit Command Block
+ // and the Source Address is inserted by the 82586. If
+ // set to 1, then the Destination and Source Addresses
+ // are part of the Transmit/Receive data buffers.
+ //
+ // In this implementation, this is always set to 1
+ // (Addresses are part of the data buffers).
+ //
+ USHORT SeparateAddressAndLength:1;
+
+ //
+ // These two bits determine the length of the packet
+ // preamble according to the following table:
+ //
+ // Bits Preamble Length
+ // ---- ---------------
+ // 00 2 bytes
+ // 01 4 bytes
+ // 10 8 bytes
+ // 11 16 bytes
+ //
+ // In this implementation, these bits will always be
+ // set to 10 (8 byte preamble).
+ //
+ USHORT PreambleLength:2;
+
+ //
+ // These two field control internal/external loopback on
+ // the 82586.
+ //
+ // In this implementation, these two fields should be set to 0.
+ //
+ USHORT InternalLoopback:1;
+ USHORT ExternalLoopback:1;
+
+ //
+ // This field contains the linear backoff priority.
+ //
+ // In this implementation, this field will always be 0.
+ //
+ USHORT LinearPriority:3;
+
+ //
+ // This field is undefined by the 82586.
+ //
+ USHORT Undefined4:1;
+
+ //
+ // This field contains the exponential backoff priority.
+ //
+ // In this implementation, this field will always be 0.
+ //
+ USHORT ExponentialPriority:3;
+
+ //
+ // If this field is set to 0, the 82586 will use the
+ // IEEE 802.3/Ethernet exponential backoff method. If
+ // set to 1, the 82586 will use an alternate backoff
+ // method.
+ //
+ // In this implementation, this field will always be 0
+ // (use the IEEE 802.3/Ethernet backoff method).
+ //
+ USHORT ExponentialBackoffMethod:1;
+
+ //
+ // This field contains the Interframe Spacing in TxC units.
+ //
+ // In this implementation, this field will always be 96.
+ //
+ USHORT InterframeSpacing:8;
+
+ //
+ // This field contains the Slot Time Number.
+ //
+ // In this implementation, this field will always be 512.
+ //
+ USHORT SlotTime:11;
+
+ //
+ // This field is undefined by the 82586.
+ //
+ USHORT Undefined5:1;
+
+ //
+ // This field contains the maximum number of transmission
+ // retries on collisions.
+ //
+ // In this implementation, this field will always be 15.
+ //
+ USHORT MaximumRetries:4;
+
+ //
+ // If this field is set to 0, Promiscuous Mode will be disabled.
+ // If set to 1, then Promiscuous Mode will be enabled and the
+ // 82586 will receive *all* packets.
+ //
+ // This field will initially be set to 0 (disable Promiscuous
+ // Mode) but may be changed when a protocol requests a change
+ // to the packet filter.
+ //
+ USHORT PromiscuousMode:1;
+
+ //
+ // If this field is set to 0, then all Broadcast Packets will be
+ // received. If set to 1, then Broadcast reception is disabled.
+ //
+ // This field will initially be set to 1 (disable Broadcast
+ // reception) but may be changed when a protocol requests a change
+ // to the packet filter.
+ //
+ USHORT DisableBroadcast:1;
+
+ //
+ // If this field is set to 0, then the 82586 will use NRZ encoding
+ // and decoding. If set to 1, the 82586 will use Manchester
+ // encoding and decoding.
+ //
+ // In this implementation, this field will always be set to 0
+ // (use NRZ encoding).
+ //
+ USHORT EncodingMethod:1;
+
+ //
+ // If this field is set to 0, then the 82586 will cease transmission
+ // if CRS goes inactive during frame transmission. If set to 1,
+ // the 82586 will continue transmission even if there is no carrier
+ // sense.
+ //
+ // In this implementation, this field will always be set to 0
+ // (cease transmission if carrier lost).
+ //
+ USHORT TransmitOnNoCarrier:1;
+
+ //
+ // If this field is set to 0, then the 82586 will insert a CRC
+ // field into the packet. If set to 1, then no CRC will be
+ // inserted
+ //
+ // In this implementation, this field will always be set to 0
+ // (insert CRC field).
+ //
+ USHORT DisableCrcInsertion:1;
+
+ //
+ // If this field is set to 0, then the 82856 will use the
+ // 32-bit Autodin II CRC polynomial. If set to 1 then the
+ // 16-bit CCITT CRC polynomial will be used.
+ //
+ // In this implementation, this field will always be set to 0
+ // (use the 32-bit Autodin II CRC polynomial).
+ //
+ USHORT CrcType:1;
+
+ //
+ // If this field is set to 0, then the 82586 will use the
+ // Ethernet bitstuffing method. If set to 1 then the 82586 will
+ // use an HDLC-like bitstuffing method.
+ //
+ // In this implementation, this field will always be set to 0
+ // (use the Ethernet bitstuffing method).
+ //
+ USHORT BitStuffingMethod:1;
+
+ //
+ // If this field is set to 0, then the 82586 will perform no
+ // padding. If set to 1 then the 82586 will pad transmits
+ // out to the full slot time.
+ //
+ // In this implementation, this field will always be set to 0
+ // (no padding).
+ //
+ USHORT EnablePadding:1;
+
+ //
+ // This field contains the Carrier Sense Filter (in bit times).
+ //
+ // In this implementation, this field will always be set to 0.
+ //
+ USHORT CarrierSenseFilter:2;
+
+ //
+ // If this field is set to 0, then the 82586 will use an external
+ // carrier sense source. If set to 1 than an internal carrier
+ // sense source is used.
+ //
+ // In this implementation, this field will always be set to 0
+ // (external carrier sense source).
+ //
+ USHORT CarrierSenseSource:1;
+
+ //
+ // This field contains the Collision Detect Filter (in bit times).
+ //
+ // In this implementation, this field will always be set to 0.
+ //
+ USHORT CollisionDetectFilter:2;
+
+ //
+ // If this field is set to 0, then the 82586 will use an external
+ // collision detect source. If set to 1 then an internal
+ // collision detect source is used.
+ //
+ // In this implementation, this field will always be set to 0
+ // (external collision detect source).
+ //
+ USHORT CollisionDetectSource:1;
+
+ //
+ // Padding bits to align MinimumFrameLength
+ //
+ USHORT TempPadding:2;
+
+ //
+ // This field contains the minimum number of bytes in a frame.
+ //
+ // In this implementation, this field will always be 64.
+ //
+ USHORT MinimumFrameLength:8;
+
+ //
+ // The following three bits are technically undefined by the
+ // 82586, but are used by MAC.BIN.
+ //
+
+ //
+ // This bit must be set to 1 to enable packet reception. If
+ // this bit is not set, then no packets will be received.
+ //
+ USHORT MacBinEnablePacketReception:1;
+
+ //
+ // This bit is unused.
+ //
+ USHORT MacBinUnused:1;
+
+ //
+ // If promiscuous mode is enabled, then this but must also
+ // be set. This short-circuits MAC.BIN's multicast filtering.
+ //
+ USHORT MacBinPromiscuous:1;
+
+ //
+ // This field is (honest!) unused.
+ //
+ USHORT Undefined6:5;
+
+} NE3200_CONFIGURATION_BLOCK, *PNE3200_CONFIGURATION_BLOCK;
+
+#include <poppack.h>
+
+
+
+//
+// Macros to read/write BMIC registers
+//
+#define NE3200_READ_MAILBOX_UCHAR(_Adapter, _MailboxIndex, _pValue) \
+ NdisRawReadPortUchar( \
+ (ULONG)(_Adapter)->BaseMailboxPort+(_MailboxIndex), \
+ (PUCHAR)(_pValue) \
+ )
+
+#define NE3200_READ_MAILBOX_USHORT(_Adapter, _MailboxIndex, _pValue) \
+ NdisRawReadPortUshort( \
+ (ULONG)(_Adapter)->BaseMailboxPort+(_MailboxIndex), \
+ (PUSHORT)(_pValue) \
+ )
+
+#define NE3200_READ_MAILBOX_ULONG(_Adapter, _MailboxIndex, _pValue) \
+ NdisRawReadPortUlong( \
+ (ULONG)(_Adapter)->BaseMailboxPort+(_MailboxIndex), \
+ (PULONG)(_pValue) \
+ )
+
+#define NE3200_WRITE_MAILBOX_UCHAR(_Adapter, _MailboxIndex, _Value) \
+ NdisRawWritePortUchar( \
+ (ULONG)(_Adapter)->BaseMailboxPort+(_MailboxIndex), \
+ (UCHAR)(_Value) \
+ )
+
+#define NE3200_WRITE_MAILBOX_USHORT(_Adapter, _MailboxIndex, _Value) \
+ NdisRawWritePortUshort( \
+ (ULONG)(_Adapter)->BaseMailboxPort+(_MailboxIndex), \
+ (USHORT)(_Value) \
+ )
+
+#define NE3200_WRITE_MAILBOX_ULONG(_Adapter, _MailboxIndex, _Value) \
+ NdisRawWritePortUlong( \
+ (ULONG)(_Adapter)->BaseMailboxPort+(_MailboxIndex), \
+ (ULONG)(_Value) \
+ )
+
+#define NE3200_WRITE_COMMAND_POINTER(_Adapter, _Address) \
+ NE3200_WRITE_MAILBOX_ULONG( \
+ _Adapter, \
+ NE3200_MAILBOX_COMMAND_POINTER, \
+ (_Address) \
+ )
+
+#define NE3200_WRITE_RECEIVE_POINTER(_Adapter, _Address) \
+ NE3200_WRITE_MAILBOX_ULONG( \
+ _Adapter, \
+ NE3200_MAILBOX_RECEIVE_POINTER, \
+ (_Address) \
+ )
+
+#define NE3200_READ_LOCAL_DOORBELL_INTERRUPT(_Adapter, _pValue) \
+ NdisRawReadPortUchar( \
+ (ULONG)(_Adapter)->LocalDoorbellInterruptPort, \
+ (PUCHAR)(_pValue) \
+ )
+
+#define NE3200_WRITE_LOCAL_DOORBELL_INTERRUPT(_Adapter, _Value) \
+ NdisRawWritePortUchar( \
+ (ULONG)(_Adapter)->LocalDoorbellInterruptPort, \
+ (UCHAR)(_Value) \
+ )
+
+#define NE3200_READ_SYSTEM_DOORBELL_INTERRUPT(_Adapter, _pValue) \
+ NdisRawReadPortUchar( \
+ (ULONG)(_Adapter)->SystemDoorbellInterruptPort, \
+ (PUCHAR)(_pValue) \
+ )
+
+#define NE3200_SYNC_CLEAR_SYSTEM_DOORBELL_INTERRUPT(_Adapter) \
+ NdisMSynchronizeWithInterrupt(\
+ &(_Adapter)->Interrupt,\
+ SyncNE3200ClearDoorbellInterrupt,\
+ (PVOID)(_Adapter)\
+ )
+
+#define NE3200_WRITE_SYSTEM_DOORBELL_INTERRUPT(_Adapter, _Value) \
+ NdisRawWritePortUchar( \
+ (ULONG)(_Adapter)->SystemDoorbellInterruptPort, \
+ (UCHAR)(_Value) \
+ )
+
+#define NE3200_READ_SYSTEM_DOORBELL_MASK(_Adapter, _pValue) \
+ NdisRawReadPortUchar( \
+ (ULONG)(_Adapter)->SystemDoorbellMaskPort, \
+ (PUCHAR)(_pValue) \
+ )
+
+#define NE3200_WRITE_SYSTEM_DOORBELL_MASK(_Adapter, _Value) \
+ NdisRawWritePortUchar( \
+ (ULONG)(_Adapter)->SystemDoorbellMaskPort, \
+ (UCHAR)(_Value) \
+ )
+
+#define NE3200_WRITE_SYSTEM_INTERRUPT(_Adapter, _Value) \
+ NdisRawWritePortUchar( \
+ (ULONG)(_Adapter)->SystemInterruptPort, \
+ (UCHAR)(_Value) \
+ )
+
+#define NE3200_WRITE_RESET(_Adapter, _Value) \
+ NdisRawWritePortUchar( \
+ (ULONG)(_Adapter)->ResetPort, \
+ (UCHAR)(_Value) \
+ )
+
+#endif // _NE3200HARDWARE_
diff --git a/private/ntos/ndis/ne3200/ne3200pr.h b/private/ntos/ndis/ne3200/ne3200pr.h
new file mode 100644
index 000000000..68485cf0e
--- /dev/null
+++ b/private/ntos/ndis/ne3200/ne3200pr.h
@@ -0,0 +1,273 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ne3200proc.h
+
+Abstract:
+
+ Procedure declarations for the Novell NE3200 NDIS 3.0 driver.
+ Moved most of these from ne3200sw.h
+
+Author:
+
+ Johnson R. Apacible (johnsona) 21-Aug-1991
+
+Environment:
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+
+--*/
+
+#ifndef _NE3200PROC_
+#define _NE3200PROC_
+
+//
+// We define the external interfaces to the NE3200 driver.
+// These routines are only external to permit separate
+// compilation. Given a truely fast compiler they could
+// all reside in a single file and be static.
+//
+extern
+BOOLEAN
+NE3200CheckForHang(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+extern
+VOID
+NE3200DisableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+extern
+VOID
+NE3200EnableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+extern
+VOID
+NE3200Halt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+extern
+VOID
+NE3200HandleInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+extern
+NDIS_STATUS
+NE3200Initialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ );
+
+extern
+VOID
+NE3200Isr(
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueDpc,
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+extern
+NDIS_STATUS
+NE3200QueryInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+ );
+
+extern
+NDIS_STATUS
+NE3200Reset(
+ OUT PBOOLEAN AddressingReset,
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+extern
+NDIS_STATUS
+NE3200Send(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET Packet,
+ IN UINT Flags
+ );
+
+extern
+NDIS_STATUS
+NE3200SetInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ );
+
+extern
+NDIS_STATUS
+NE3200TransferData(
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+ );
+
+VOID
+NE3200StartChipAndDisableInterrupts(
+ IN PNE3200_ADAPTER Adapter,
+ IN PNE3200_SUPER_RECEIVE_ENTRY FirstReceiveEntry
+ );
+
+VOID
+NE3200FinishQueryInformation(
+ IN PNE3200_ADAPTER Adapter
+ );
+
+
+VOID
+NE3200GetStationAddress(
+ IN PNE3200_ADAPTER Adapter
+ );
+
+VOID
+NE3200StopChip(
+ IN PNE3200_ADAPTER Adapter
+ );
+
+BOOLEAN
+NE3200RegisterAdapter(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN UINT EisaSlot,
+ IN UINT InterruptVector,
+ IN NDIS_INTERRUPT_MODE InterruptMode,
+ IN PUCHAR CurrentAddress
+ );
+
+VOID
+NE3200AcquirePublicCommandBlock(
+ IN PNE3200_ADAPTER Adapter,
+ OUT PNE3200_SUPER_COMMAND_BLOCK * CommandBlock
+ );
+
+VOID
+FASTCALL
+NE3200RelinquishCommandBlock(
+ IN PNE3200_ADAPTER Adapter,
+ IN PNE3200_SUPER_COMMAND_BLOCK CommandBlock
+ );
+
+VOID
+NE3200DoAdapterReset(
+ IN PNE3200_ADAPTER Adapter
+ );
+
+VOID
+NE3200SetupForReset(
+ IN PNE3200_ADAPTER Adapter
+ );
+
+NDIS_STATUS
+NE3200UpdateMulticastTable(
+ IN PNE3200_ADAPTER Adapter,
+ IN UINT CurrentAddressCount,
+ IN CHAR CurrentAddresses[][NE3200_LENGTH_OF_ADDRESS]
+ );
+
+VOID
+NE3200ResetVariables(
+ IN PNE3200_ADAPTER Adapter
+ );
+
+BOOLEAN
+SyncNE3200ClearDoorbellInterrupt(
+ IN PVOID SyncContext
+ );
+
+VOID
+NE3200ResetHandler(
+ IN PVOID SystemSpecific1,
+ IN PNE3200_ADAPTER Adapter,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+VOID
+NE3200DeferredTimer(
+ IN PVOID SystemSpecific1,
+ IN PNE3200_ADAPTER Adapter,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+VOID
+FASTCALL
+Ne3200Stall(
+ PULONG Dummy
+ );
+
+#define NE3200SubmitCommandBlock( _Adapter, _CommandBlock ) \
+{ \
+ ASSERT(!(NdisGetPhysicalAddressLow(_CommandBlock->Self) & 1)); \
+ _CommandBlock->Timeout = FALSE; \
+ if (_Adapter->FirstCommandOnCard != NULL) { \
+ if (_Adapter->FirstWaitingCommand == NULL) { \
+ _Adapter->FirstWaitingCommand = _CommandBlock; \
+ } else { \
+ PNE3200_SUPER_COMMAND_BLOCK PreviousCommandBlock; \
+ PreviousCommandBlock = _Adapter->LastWaitingCommand; \
+ PreviousCommandBlock->Hardware.NextPending = \
+ NdisGetPhysicalAddressLow(_CommandBlock->Self); \
+ PreviousCommandBlock->NextCommand = _CommandBlock; \
+ } \
+ _Adapter->LastWaitingCommand = _CommandBlock; \
+ IF_LOG('2'); \
+ } else { \
+ ASSERT(_Adapter->FirstWaitingCommand == NULL); \
+ IF_LOG('1'); \
+ _Adapter->FirstCommandOnCard = _CommandBlock; \
+ _Adapter->LastCommandOnCard = _CommandBlock; \
+ NE3200_WRITE_COMMAND_POINTER(_Adapter,NdisGetPhysicalAddressLow(_CommandBlock->Self)); \
+ { ULONG i; Ne3200Stall(&i); } \
+ NE3200_WRITE_LOCAL_DOORBELL_INTERRUPT(_Adapter,NE3200_LOCAL_DOORBELL_NEW_COMMAND); \
+ } \
+}
+
+#define NE3200AcquireCommandBlock( _Adapter, _CommandBlock ) \
+{ \
+ if (_Adapter->NumberOfAvailableCommandBlocks) { \
+ IF_LOG('a'); \
+ _Adapter->NumberOfAvailableCommandBlocks--; \
+ *(_CommandBlock) = _Adapter->NextCommandBlock; \
+ _Adapter->NextCommandBlock++; \
+ if (_Adapter->NextCommandBlock >= _Adapter->LastCommandBlockAllocated ) {\
+ Adapter->NextCommandBlock = Adapter->CommandQueue; \
+ } \
+ } else { \
+ *(_CommandBlock) = NULL; \
+ } \
+}
+
+#endif //_NE3200PROC_
diff --git a/private/ntos/ndis/ne3200/ne3200sw.h b/private/ntos/ndis/ne3200/ne3200sw.h
new file mode 100644
index 000000000..28300334f
--- /dev/null
+++ b/private/ntos/ndis/ne3200/ne3200sw.h
@@ -0,0 +1,805 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ne3200sw.h
+
+Abstract:
+
+ Software specific values for the Novell NE3200 NDIS 3.0 driver.
+
+Author:
+
+ Keith Moore (KeithMo) 08-Jan-1991
+
+Environment:
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+
+--*/
+
+#ifndef _NE3200SOFTWARE_
+#define _NE3200SOFTWARE_
+
+#include <ndis.h>
+#include <ne3200hw.h>
+
+//
+// Debugging flags. This buffer is used to record whenever the driver
+// does something important. If there is a bug, then this buffer
+// can be viewed from the debugger and an effective trace of events
+// can be found.
+//
+
+#if DBG
+
+#define IF_NE3200DBG(flag) if (NE3200Debug & (NE3200_DEBUG_ ## flag))
+
+//
+// Macro for putting a character in the buffer.
+//
+#define IF_LOG(ch) { \
+ UCHAR lp = Adapter->LogPlace; \
+ Adapter->LogPlace++; \
+ Adapter->Log[(UCHAR)(lp+3)] = (UCHAR)'\0'; \
+ Adapter->Log[lp] = (ch); \
+ }
+
+//
+// Debug flag, determines what debug information is kept around
+//
+extern ULONG NE3200Debug;
+
+//
+// Possible values for the above flag
+//
+#define NE3200_DEBUG_DUMP_LOOKAHEAD 0x00000001 // dump lookahead buffer
+#define NE3200_DEBUG_DUMP_TRANSFER 0x00000002 // dump transfer buffer
+#define NE3200_DEBUG_DUMP_SEND 0x00000004 // dump send packet
+#define NE3200_DEBUG_DUMP_COMMAND 0x00000008 // dump command block & buffer
+
+#define NE3200_DEBUG_ACQUIRE 0x00000010 // NE3200AcquireCommandBlock activity
+#define NE3200_DEBUG_SUBMIT 0x00000020 // NE3200SubmitCommandBlock activity
+#define NE3200_DEBUG_ASSIGN 0x00000040 // NE3200AssignPacketToCommandBlock activity
+#define NE3200_DEBUG_RECEIVE 0x00000080 // ProcessReceiveInterrupts activity
+
+#define NE3200_DEBUG_LOUD 0x00000100 // print things
+#define NE3200_DEBUG_VERY_LOUD 0x00000200 // print lots of things
+
+#define DPrint1(fmt) DbgPrint(fmt)
+#define DPrint2(fmt,v1) DbgPrint(fmt,v1)
+#define DPrint3(fmt,v1,v2) DbgPrint(fmt,v1,v2)
+#define DPrint4(fmt,v1,v2,v3) DbgPrint(fmt,v1,v2,v3)
+
+#else // DBG
+
+#define IF_LOG(ch)
+
+#define IF_NE3200DBG(flag) if (0)
+#define DPrint1(fmt)
+#define DPrint2(fmt,v1)
+#define DPrint3(fmt,v1,v2)
+#define DPrint4(fmt,v1,v2,v3)
+
+#endif // DBG
+
+//
+// Keep symbols for internal functions
+//
+#define STATIC
+
+//
+// NDIS version of this driver
+//
+#define NE3200_NDIS_MAJOR_VERSION 3
+#define NE3200_NDIS_MINOR_VERSION 0
+
+
+extern NDIS_PHYSICAL_ADDRESS MinusOne;
+
+//
+// Macro for allocating memory
+//
+#define NE3200_ALLOC_PHYS(_Status, _pBuffer, _Length) \
+{ \
+ *(_Status) = NdisAllocateMemory( \
+ (PVOID*)(_pBuffer), \
+ (_Length), \
+ 0, \
+ MinusOne); \
+}
+
+//
+// Macro for freeing memory
+//
+#define NE3200_FREE_PHYS(_Buffer) NdisFreeMemory((_Buffer), 0, 0)
+
+
+//
+// Macro for moving memory around
+//
+#define NE3200_MOVE_MEMORY(Destination,Source,Length) NdisMoveMemory(Destination,Source,Length)
+
+//
+// Size of ethernet header
+//
+#define NE3200_HEADER_SIZE 14
+
+//
+// Size of lookahead buffer for loopback packets
+//
+#define NE3200_SIZE_OF_LOOPBACK 256
+
+
+//
+// The implementation of RESET.
+//
+// The NE3200 must be "held by the hand" during the reset & download
+// operations. Typically, the reset (or download) is initiated and
+// the status ports are POLLED, waiting for pass/fail status. This
+// is unacceptable in NT.
+//
+// To handle this cleanly in NT, the reset & download operations will
+// be controlled by a state machine. This state machine will be
+// contained by a flag and driven by a Timer Object.
+//
+// This ENUM represents the current state of the reset operation.
+//
+typedef enum _NE3200_RESET_STATE {
+
+ NE3200ResetStateStarting,
+ NE3200ResetStateResetting,
+ NE3200ResetStateDownloading,
+ NE3200ResetStateReloadAddress,
+ NE3200ResetStateComplete
+
+} NE3200_RESET_STATE, *PNE3200_RESET_STATE;
+
+//
+// This ENUM represents the result of the reset operation.
+//
+typedef enum _NE3200_RESET_RESULT {
+
+ NE3200ResetResultSuccessful,
+ NE3200ResetResultResetFailure,
+ NE3200ResetResultResetTimeout,
+ NE3200ResetResultInitializationFailure,
+ NE3200ResetResultInitializationTimeout,
+ NE3200ResetResultInvalidState,
+ NE3200ResetResultResources
+
+} NE3200_RESET_RESULT, *PNE3200_RESET_RESULT;
+
+
+struct _NE3200_ADAPTER;
+
+//
+// This structure defines the global data needed by the driver.
+//
+typedef struct _NE3200_GLOBAL_DATA {
+
+ //
+ // We need to allocate a buffer to contain the MAC.BIN code to be
+ // downloaded to the NE3200 adapter(s). This field will contain
+ // the virtual address of this buffer.
+ //
+ PVOID MacBinVirtualAddress;
+ NDIS_PHYSICAL_ADDRESS MacBinPhysicalAddress;
+
+ //
+ // Chain of Adapters
+ //
+ LIST_ENTRY AdapterList;
+
+ //
+ // The handle of the adapter used for the allocaton of
+ // the MAC.BIN buffer (the first one added for this MAC).
+ //
+ NDIS_HANDLE MacBinAdapterHandle;
+
+ //
+ // Handle to our driver
+ //
+ NDIS_HANDLE NE3200DriverHandle;
+
+ //
+ // Handle for NdisTerminateWrapper
+ //
+ NDIS_HANDLE NE3200NdisWrapperHandle;
+
+ //
+ // This field contains the actual length (in bytes) of MAC.BIN.
+ //
+ USHORT MacBinLength;
+
+} NE3200_GLOBAL_DATA, *PNE3200_GLOBAL_DATA;
+
+//
+// In addition to the Command Block fields which the NE3200
+// defines, we need some additional fields for our own purposes.
+// To ensure that these fields are properly aligned (and to
+// ensure that the actual Command Block is properly aligned)
+// we'll defined a Super Command Block. This structure will
+// contain a "normal" NE3200 Command Block plus some additional
+// fields.
+//
+typedef struct _NE3200_SUPER_COMMAND_BLOCK {
+
+ //
+ // The actual NE3200 Command Block.
+ //
+ NE3200_COMMAND_BLOCK Hardware;
+
+ //
+ // This contains the physical address of the above Command Block.
+ //
+ NDIS_PHYSICAL_ADDRESS Self;
+
+ //
+ // Points to the packet from which data is being transmitted
+ // through this Command Block.
+ //
+ PNDIS_PACKET OwningPacket;
+
+ //
+ // This tells if the command block is a public or private command block.
+ //
+ PUINT AvailableCommandBlockCounter;
+
+ //
+ // This contains the virtual address of the next pending command.
+ //
+ struct _NE3200_SUPER_COMMAND_BLOCK *NextCommand;
+
+ //
+ // Is this from a set
+ //
+ BOOLEAN Set;
+
+ //
+ // This field is used to timestamp the command blocks
+ // as they are placed into the command queue. If a
+ // block fails to execute, the adapter will get a kick in the ass to
+ // start it up again.
+ //
+ BOOLEAN Timeout;
+
+ //
+ // If this is a public (adapter-wide) command block, then
+ // this will contain this block's index into the adapter's
+ // command queue.
+ //
+ USHORT CommandBlockIndex;
+
+ //
+ // Count of the number of times we have retried a command.
+ //
+ UCHAR TimeoutCount;
+
+ //
+ // When a packet is submitted to the hardware we record
+ // here whether it used adapter buffers and if so, the buffer
+ // index.
+ //
+ BOOLEAN UsedNE3200Buffer;
+ UINT NE3200BuffersIndex;
+
+} NE3200_SUPER_COMMAND_BLOCK, *PNE3200_SUPER_COMMAND_BLOCK;
+
+//
+// In addition to the Receive Entry fields which the NE3200
+// defines, we need some additional fields for our own purposes.
+// To ensure that these fields are properly aligned (and to
+// ensure that the actual Receive Entry is properly aligned)
+// we'll defined a Super Receive Entry. This structure will
+// contain a "normal" NE3200 Receive Entry plus some additional
+// fields.
+//
+typedef struct _NE3200_SUPER_RECEIVE_ENTRY {
+
+ //
+ // The actual NE3200 Receive Entry.
+ //
+ NE3200_RECEIVE_ENTRY Hardware;
+
+ //
+ // This contains the physical address of the above Receive Entry.
+ //
+ NDIS_PHYSICAL_ADDRESS Self;
+
+ //
+ // This contains the virtual address of the next
+ // Receive Entry in the Receive Queue.
+ //
+ struct _NE3200_SUPER_RECEIVE_ENTRY *NextEntry;
+
+ //
+ // This contains the virtual address of this Receive Entry's
+ // frame buffer.
+ //
+ PVOID ReceiveBuffer;
+ NDIS_PHYSICAL_ADDRESS ReceiveBufferPhysical;
+
+ //
+ // Points to an NDIS buffer which describes this buffer
+ //
+ PNDIS_BUFFER FlushBuffer;
+
+} NE3200_SUPER_RECEIVE_ENTRY, *PNE3200_SUPER_RECEIVE_ENTRY;
+
+
+
+//
+// This record type is inserted into the MiniportReserved portion
+// of the packet header when the packet is going through the
+// staged allocation of buffer space prior to the actual send.
+//
+typedef struct _NE3200_RESERVED {
+
+ //
+ // Points to the next packet in the chain of queued packets
+ // being allocated or waiting for the finish of transmission.
+ //
+ PNDIS_PACKET Next;
+
+ //
+ // If TRUE then the packet caused an adapter buffer to
+ // be allocated.
+ //
+ BOOLEAN UsedNE3200Buffer;
+
+ //
+ // If the previous field was TRUE then this gives the
+ // index into the array of adapter buffer descriptors that
+ // contains the old packet information.
+ //
+ UCHAR NE3200BuffersIndex;
+
+ //
+ // Gives the index of the Command Block as well as the
+ // command block to packet structure.
+ //
+ USHORT CommandBlockIndex;
+
+} NE3200_RESERVED,*PNE3200_RESERVED;
+
+//
+// This macro will return a pointer to the NE3200 reserved portion
+// of a packet given a pointer to a packet.
+//
+#define PNE3200_RESERVED_FROM_PACKET(Packet) \
+ ((PNE3200_RESERVED)((Packet)->MiniportReserved))
+
+//
+// If an ndis packet does not meet the hardware contraints then
+// an adapter buffer will be allocated. Enough data will be copied
+// out of the ndis packet so that by using a combination of the
+// adapter buffer and remaining ndis buffers the hardware
+// constraints are satisfied.
+//
+// In the NE3200_ADAPTER structure three threaded lists are kept in
+// one array. One points to a list of NE3200_BUFFER_DESCRIPTORS
+// that point to small adapter buffers. Another is for medium sized
+// buffers and the last for full sized (large) buffers.
+//
+// The allocation is controlled via a free list head and
+// the free lists are "threaded" by a field in the adapter buffer
+// descriptor.
+//
+typedef struct _NE3200_BUFFER_DESCRIPTOR {
+
+ //
+ // A physical pointer to a small, medium, or large buffer.
+ //
+ NDIS_PHYSICAL_ADDRESS PhysicalNE3200Buffer;
+
+ //
+ // A virtual pointer to a small, medium, or large buffer.
+ //
+ PVOID VirtualNE3200Buffer;
+
+ //
+ // Flush buffer
+ //
+ PNDIS_BUFFER FlushBuffer;
+
+ //
+ // Threads the elements of an array of these descriptors into
+ // a free list. -1 implies no more entries in the list.
+ //
+ INT Next;
+
+ //
+ // Holds the amount of space (in bytes) available in the buffer
+ //
+ UINT BufferSize;
+
+ //
+ // Holds the length of data placed into the buffer. This
+ // can (and likely will) be less that the actual buffers
+ // length.
+ //
+ UINT DataLength;
+
+} NE3200_BUFFER_DESCRIPTOR,*PNE3200_BUFFER_DESCRIPTOR;
+
+//
+// This is the main structure for each adapter.
+//
+typedef struct _NE3200_ADAPTER {
+
+#if DBG
+ PUCHAR LogAddress;
+#endif
+
+ PUCHAR SystemDoorbellInterruptPort;
+ PUCHAR SystemDoorbellMaskPort;
+
+ //
+ // Flag that when enabled lets routines know that a reset
+ // is in progress.
+ //
+ BOOLEAN ResetInProgress;
+
+ //
+ // TRUE when a receive interrupt is received
+ //
+ BOOLEAN ReceiveInterrupt;
+
+ BOOLEAN InterruptsDisabled;
+
+ //
+ // Handle given by NDIS when the widget was initialized.
+ //
+ NDIS_HANDLE MiniportAdapterHandle;
+
+ //
+ // Pointer to the head of the Receive Queue.
+ //
+ PNE3200_SUPER_RECEIVE_ENTRY ReceiveQueueHead;
+
+ //
+ // Pointer to the tail of the Receive Queue.
+ //
+ PNE3200_SUPER_RECEIVE_ENTRY ReceiveQueueTail;
+
+ //
+ // Packet counts
+ //
+ UINT GoodReceives;
+
+ //
+ // Pointer to the next command to complete execution.
+ //
+ PNE3200_SUPER_COMMAND_BLOCK FirstCommandOnCard;
+
+ //
+ // Pointers to an array of adapter buffer descriptors.
+ // The array will actually be threaded together by
+ // three free lists. The lists will be for small,
+ // medium and full sized packets.
+ //
+ PNE3200_BUFFER_DESCRIPTOR NE3200Buffers;
+
+ //
+ // List head for the adapters buffers. If the list
+ // head is equal to -1 then there are no free elements
+ // on the list.
+ //
+ INT NE3200BufferListHead;
+
+ UINT GoodTransmits;
+
+ //
+ // Is there an outstanding request
+ //
+ BOOLEAN RequestInProgress;
+
+ //
+ // Is this a packet resubmission?
+ //
+ BOOLEAN PacketResubmission;
+
+ //
+ // Pointer to the most recently submitted command.
+ //
+ PNE3200_SUPER_COMMAND_BLOCK LastCommandOnCard;
+
+ //
+ // Pointer to the first command waiting to be put on the list to the card.
+ //
+ PNE3200_SUPER_COMMAND_BLOCK FirstWaitingCommand;
+
+ //
+ // Pointer to the last command waiting to be put on the list to the card.
+ //
+ PNE3200_SUPER_COMMAND_BLOCK LastWaitingCommand;
+
+ PUCHAR BaseMailboxPort;
+
+ //
+ // Total number of Command Blocks in the PublicCommandQueue.
+ //
+ UINT NumberOfPublicCommandBlocks;
+
+ //
+ // Number of available Command Blocks in the Command Queue.
+ //
+ UINT NumberOfAvailableCommandBlocks;
+
+ //
+ // Pointer to the next available Command Block.
+ //
+ PNE3200_SUPER_COMMAND_BLOCK NextCommandBlock;
+
+ PNE3200_SUPER_COMMAND_BLOCK LastCommandBlockAllocated;
+//----
+ //
+ // Used for filter and statistics operations
+ //
+ PNE3200_SUPER_COMMAND_BLOCK PublicCommandQueue;
+ NDIS_PHYSICAL_ADDRESS PublicCommandQueuePhysical;
+
+ //
+ // Used for padding short packets
+ //
+ PUCHAR PaddingVirtualAddress;
+ NDIS_PHYSICAL_ADDRESS PaddingPhysicalAddress;
+
+ //
+ // Points to the card multicast entry table
+ //
+ PUCHAR CardMulticastTable;
+ NDIS_PHYSICAL_ADDRESS CardMulticastTablePhysical;
+
+ //
+ // Holds the interrupt object for this adapter.
+ //
+ NDIS_MINIPORT_INTERRUPT Interrupt;
+
+ //
+ // Current packet filter on adapter
+ //
+ UINT CurrentPacketFilter;
+
+ //
+ // Is this the initial initialization reset?
+ //
+ BOOLEAN InitialInit;
+
+ //
+ // These variables hold information about a pending request.
+ //
+ PUINT BytesWritten;
+ PUINT BytesNeeded;
+ NDIS_OID Oid;
+ PVOID InformationBuffer;
+ UINT InformationBufferLength;
+
+ //
+ // The EISA Slot Number for this adapter.
+ //
+ USHORT EisaSlot;
+
+ //
+ // The I/O Base address of the adapter.
+ //
+ ULONG AdapterIoBase;
+
+ //
+ // Various mapped I/O Port Addresses for this adapter.
+ //
+ PUCHAR ResetPort;
+ PUCHAR SystemInterruptPort;
+ PUCHAR LocalDoorbellInterruptPort;
+
+ //
+ // Count of CheckForHang calls that have occurred without
+ // a receive interrupt.
+ //
+ UCHAR NoReceiveInterruptCount;
+
+ //
+ // TRUE when a send interrupt is received
+ //
+ BOOLEAN SendInterrupt;
+
+ //
+ // Should we use an alternative address
+ //
+ BOOLEAN AddressChanged;
+
+ //
+ // The network address from the hardware.
+ //
+ CHAR NetworkAddress[NE3200_LENGTH_OF_ADDRESS];
+ CHAR CurrentAddress[NE3200_LENGTH_OF_ADDRESS];
+
+ //
+ // Pointer to the Receive Queue.
+ //
+ PNE3200_SUPER_RECEIVE_ENTRY ReceiveQueue;
+ NDIS_PHYSICAL_ADDRESS ReceiveQueuePhysical;
+
+ //
+ // Pointer to the Command Queue.
+ //
+ PNE3200_SUPER_COMMAND_BLOCK CommandQueue;
+ NDIS_PHYSICAL_ADDRESS CommandQueuePhysical;
+
+ //
+ // Next free public command block
+ //
+ UINT NextPublicCommandBlock;
+
+ //
+ // Total number of Command Blocks in the Command Queue.
+ //
+ UINT NumberOfCommandBlocks;
+
+ //
+ // Total number of Receive Buffers.
+ //
+ UINT NumberOfReceiveBuffers;
+
+ //
+ // Total number of Transmit Buffers.
+ //
+ UINT NumberOfTransmitBuffers;
+
+ //
+ // The Flush buffer pool
+ //
+ PNDIS_HANDLE FlushBufferPoolHandle;
+
+ //
+ // Is the reset to be done asynchronously?
+ //
+ BOOLEAN ResetAsynchronous;
+
+ //
+ // Used to store the command block for asynchronous resetting.
+ //
+ PNE3200_SUPER_COMMAND_BLOCK ResetHandlerCommandBlock;
+
+ //
+ // Index of the receive ring descriptor that started the
+ // last packet not completely received by the hardware.
+ //
+ UINT CurrentReceiveIndex;
+
+ //
+ // Counters to hold the various number of errors/statistics for both
+ // reception and transmission.
+ //
+
+ //
+ // Packet counts
+ //
+ UINT TransmitsQueued;
+
+ //
+ // Count of transmit errors
+ //
+ UINT RetryFailure;
+ UINT LostCarrier;
+ UINT UnderFlow;
+ UINT NoClearToSend;
+ UINT Deferred;
+ UINT OneRetry;
+ UINT MoreThanOneRetry;
+
+ //
+ // Count of receive errors
+ //
+ UINT CrcErrors;
+ UINT AlignmentErrors;
+ UINT OutOfResources;
+ UINT DmaOverruns;
+
+ //
+ // This holds the current state of the reset operation.
+ //
+ NE3200_RESET_STATE ResetState;
+
+ //
+ // This hold the result of the reset operation.
+ //
+ NE3200_RESET_RESULT ResetResult;
+
+ //
+ // This is a timeout counter. Before a timed operation is
+ // started, a positive value is placed in this field. Every
+ // time the particular state is entered in the ResetDpc, this
+ // value is decremented. If this value becomes zero, then
+ // the operation has timed-out and the adapter is toast.
+ //
+ UINT ResetTimeoutCounter;
+
+ //
+ // This timer object will be used to queue the deferred processing routine
+ //
+ NDIS_MINIPORT_TIMER DeferredTimer;
+
+ //
+ // This timer is for handling resets from when the card is dead.
+ //
+ NDIS_MINIPORT_TIMER ResetTimer;
+
+ //
+ // Place for holding command block for pending commands during
+ // reset processing.
+ //
+ PNE3200_SUPER_COMMAND_BLOCK ResetCommandBlock;
+
+ //
+ // This is a pointer to the Configuration Block for this
+ // adapter. The Configuration Block will be modified during
+ // changes to the packet filter.
+ //
+ PNE3200_CONFIGURATION_BLOCK ConfigurationBlock;
+ NDIS_PHYSICAL_ADDRESS ConfigurationBlockPhysical;
+
+ //
+ // This points to the next adapter registered for the same Mac
+ //
+ LIST_ENTRY AdapterList;
+
+#if DBG
+ UCHAR Log[256];
+ UCHAR LogPlace;
+#endif
+
+} NE3200_ADAPTER,*PNE3200_ADAPTER;
+
+//
+// Given a MiniportContextHandle return the PNE3200_ADAPTER
+// it represents.
+//
+#define PNE3200_ADAPTER_FROM_CONTEXT_HANDLE(Handle) \
+ ((PNE3200_ADAPTER)(Handle))
+
+//
+// Procedures which do error logging
+//
+
+typedef enum _NE3200_PROC_ID{
+ allocateAdapterMemory,
+ initialInit,
+ setConfigurationBlockAndInit,
+ registerAdapter,
+ openAdapter,
+ wakeUpDpc,
+ resetDpc
+}NE3200_PROC_ID;
+
+//
+// Error log codes.
+//
+#define NE3200_ERRMSG_ALLOC_MEM (ULONG)0x01
+#define NE3200_ERRMSG_INIT_INTERRUPT (ULONG)0x02
+#define NE3200_ERRMSG_NO_DELAY (ULONG)0x03
+#define NE3200_ERRMSG_INIT_DB (ULONG)0x04
+#define NE3200_ERRMSG_OPEN_DB (ULONG)0x05
+#define NE3200_ERRMSG_BAD_STATE (ULONG)0x06
+#define NE3200_ERRMSG_ (ULONG)0x06
+
+
+//
+// Define our block of global data. The actual data resides in NE3200.C.
+//
+extern NE3200_GLOBAL_DATA NE3200Globals;
+
+#include <ne3200pr.h>
+
+#endif // _NE3200SOFTWARE_
diff --git a/private/ntos/ndis/ne3200/request.c b/private/ntos/ndis/ne3200/request.c
new file mode 100644
index 000000000..5c294ce9d
--- /dev/null
+++ b/private/ntos/ndis/ne3200/request.c
@@ -0,0 +1,954 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ request.c
+
+Abstract:
+
+ This file contains code to implement request processing.
+ This driver conforms to the NDIS 3.0 miniport interface.
+
+Author:
+
+ Johnson R. Apacible (JohnsonA) 10-June-1991
+
+Environment:
+
+Revision History:
+
+--*/
+
+#include <ne3200sw.h>
+
+extern
+NDIS_STATUS
+NE3200ChangeClass(
+ PNE3200_ADAPTER Adapter,
+ IN UINT NewFilterClasses
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when a particular filter
+ class is first used or last cleared.
+
+Arguments:
+
+ NewFilterClasses - The current value of the class filter
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ //
+ // Holds the change that should be returned to the filtering package.
+ //
+ NDIS_STATUS StatusOfChange;
+
+ //
+ // Holds the list of changes;
+ //
+ UINT PacketChanges;
+
+ //
+ // This points to the public Command Block.
+ //
+ PNE3200_SUPER_COMMAND_BLOCK CommandBlock;
+
+ //
+ // This points to the adapter's configuration block.
+ //
+ PNE3200_CONFIGURATION_BLOCK ConfigurationBlock =
+ Adapter->ConfigurationBlock;
+
+ //
+ // The NE3200 has no method for easily disabling multicast
+ // packets. Therefore, we'll only reconfigure the 82586
+ // when there is a change in either directed, broadcast, or
+ // promiscuous filtering.
+ //
+ PacketChanges = (Adapter->CurrentPacketFilter ^ NewFilterClasses) &
+ (NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_BROADCAST |
+ NDIS_PACKET_TYPE_DIRECTED);
+
+ if (!PacketChanges) {
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+ //
+ // Use the generic command block
+ //
+ IF_LOG('F');
+
+ NE3200AcquirePublicCommandBlock(
+ Adapter,
+ &CommandBlock
+ );
+
+ //
+ // This from a set.
+ //
+ CommandBlock->Set = TRUE;
+
+ //
+ // Setup the command block.
+ //
+ CommandBlock->NextCommand = NULL;
+
+ CommandBlock->Hardware.State = NE3200_STATE_WAIT_FOR_ADAPTER;
+ CommandBlock->Hardware.Status = 0;
+ CommandBlock->Hardware.NextPending = NE3200_NULL;
+ CommandBlock->Hardware.CommandCode =
+ NE3200_COMMAND_CONFIGURE_82586;
+ CommandBlock->Hardware.PARAMETERS.CONFIGURE.ConfigurationBlock =
+ NdisGetPhysicalAddressLow(Adapter->ConfigurationBlockPhysical);
+
+ //
+ // Update the configuration block to reflect the new
+ // packet filtering.
+ //
+ if (NewFilterClasses == 0) {
+
+ ConfigurationBlock->PromiscuousMode = 0;
+ ConfigurationBlock->MacBinPromiscuous = 0;
+ ConfigurationBlock->DisableBroadcast = 1;
+
+ } else {
+
+ ConfigurationBlock->MacBinEnablePacketReception = 1;
+
+ if (PacketChanges & NDIS_PACKET_TYPE_PROMISCUOUS) {
+
+ ConfigurationBlock->PromiscuousMode = 1;
+ ConfigurationBlock->MacBinPromiscuous = 1;
+
+ } else {
+
+ ConfigurationBlock->PromiscuousMode = 0;
+ ConfigurationBlock->MacBinPromiscuous = 0;
+
+ }
+
+ if (PacketChanges & NDIS_PACKET_TYPE_BROADCAST) {
+
+ ConfigurationBlock->DisableBroadcast = 0;
+
+ } else {
+
+ ConfigurationBlock->DisableBroadcast = 1;
+
+ }
+
+ }
+
+ //
+ // Now that we've got the command block built,
+ // let's do it!
+ //
+ NE3200SubmitCommandBlock(Adapter, CommandBlock);
+
+ StatusOfChange = NDIS_STATUS_PENDING;
+
+ return StatusOfChange;
+}
+
+
+STATIC
+NDIS_STATUS
+NE3200UpdateMulticastTable(
+ IN PNE3200_ADAPTER Adapter,
+ IN UINT CurrentAddressCount,
+ IN CHAR CurrentAddresses[][NE3200_LENGTH_OF_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to update the list of multicast addreses
+ on the adapter.
+
+Arguments:
+
+ Adapter - The adapter where the multicast is to be changed.
+
+ CurrentAddressCount - The number of addresses in the address array.
+
+ CurrentAddresses - An array of multicast addresses. Note that this
+ array already contains the new address.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+
+ //
+ // This points to the public Command Block.
+ //
+ PNE3200_SUPER_COMMAND_BLOCK CommandBlock;
+
+ //
+ // Holds the status that should be returned to the filtering package.
+ //
+ NDIS_STATUS StatusOfUpdate;
+
+ //
+ // Multicast address table
+ //
+ PUCHAR MulticastAddressTable;
+
+ IF_LOG('f');
+
+ //
+ // See if we can acquire a private command block.
+ //
+ NE3200AcquirePublicCommandBlock(Adapter, &CommandBlock);
+
+ //
+ // Store the request that uses this command block.
+ //
+ CommandBlock->Set = TRUE;
+
+ //
+ // Get the multicast address table.
+ //
+ MulticastAddressTable = Adapter->CardMulticastTable;
+
+ //
+ // Clear out the old address
+ //
+ NdisZeroMemory(
+ MulticastAddressTable,
+ CurrentAddressCount * NE3200_SIZE_OF_MULTICAST_TABLE_ENTRY
+ );
+
+ {
+
+ //
+ // Simple iteration counter.
+ //
+ UINT i;
+
+ //
+ // Pointer into the multicast address table.
+ //
+ PCHAR OriginalAddress;
+
+ //
+ // Pointer into our temporary buffer.
+ //
+ PCHAR MungedAddress;
+
+ //
+ // Munge the address to 16 bytes per entry.
+ //
+ OriginalAddress = &CurrentAddresses[0][0];
+ MungedAddress = MulticastAddressTable;
+
+ for ( i = CurrentAddressCount ; i > 0 ; i-- ) {
+
+ NdisMoveMemory(
+ MungedAddress,
+ OriginalAddress,
+ NE3200_LENGTH_OF_ADDRESS
+ );
+
+ OriginalAddress += NE3200_LENGTH_OF_ADDRESS;
+ MungedAddress += NE3200_SIZE_OF_MULTICAST_TABLE_ENTRY;
+
+ }
+
+
+ //
+ // Setup the command block.
+ //
+ CommandBlock->NextCommand = NULL;
+
+ CommandBlock->Hardware.State = NE3200_STATE_WAIT_FOR_ADAPTER;
+ CommandBlock->Hardware.Status = 0;
+ CommandBlock->Hardware.NextPending = NE3200_NULL;
+ CommandBlock->Hardware.CommandCode = NE3200_COMMAND_SET_MULTICAST_ADDRESS;
+ CommandBlock->Hardware.PARAMETERS.MULTICAST.NumberOfMulticastAddresses =
+ (USHORT)CurrentAddressCount;
+
+ if (CurrentAddressCount == 0) {
+
+ CommandBlock->Hardware.PARAMETERS.MULTICAST.MulticastAddressTable =
+ (NE3200_PHYSICAL_ADDRESS)NULL;
+
+ } else {
+
+ CommandBlock->Hardware.PARAMETERS.MULTICAST.MulticastAddressTable =
+ NdisGetPhysicalAddressLow(Adapter->CardMulticastTablePhysical);
+
+ }
+
+ //
+ // Now that we've got the command block built,
+ // let's do it!
+ //
+ NE3200SubmitCommandBlock(Adapter, CommandBlock);
+
+ StatusOfUpdate = NDIS_STATUS_PENDING;
+
+ }
+
+ return StatusOfUpdate;
+
+}
+
+extern
+NDIS_STATUS
+NE3200SetInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ )
+
+/*++
+
+Routine Description:
+
+ NE3200SetInformation handles a set operation for a
+ single OID.
+
+Arguments:
+
+ MiniportAdapterContext - The adapter that the set is for.
+
+ Oid - The OID of the set.
+
+ InformationBuffer - Holds the data to be set.
+
+ InformationBufferLength - The length of InformationBuffer.
+
+ BytesRead - If the call is successful, returns the number
+ of bytes read from InformationBuffer.
+
+ BytesNeeded - If there is not enough data in OvbBuffer
+ to satisfy the OID, returns the amount of storage needed.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_PENDING
+ NDIS_STATUS_INVALID_LENGTH
+ NDIS_STATUS_INVALID_OID
+
+--*/
+
+{
+ //
+ // Variable to hold the new packet filter
+ //
+ ULONG PacketFilter;
+
+ //
+ // The adapter to process the request for.
+ //
+ PNE3200_ADAPTER Adapter = PNE3200_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ //
+ // Status of NDIS operation
+ //
+ NDIS_STATUS Status;
+
+ IF_LOG('w');
+
+ //
+ // Now check for the most common OIDs
+ //
+ switch (Oid) {
+
+ case OID_802_3_MULTICAST_LIST:
+
+ if (InformationBufferLength % NE3200_LENGTH_OF_ADDRESS != 0) {
+
+ //
+ // The data must be a multiple of the Ethernet
+ // address size.
+ //
+ return(NDIS_STATUS_INVALID_DATA);
+
+ }
+
+ //
+ // Now call the routine that does this.
+ //
+ Status = NE3200UpdateMulticastTable(
+ Adapter,
+ InformationBufferLength /
+ NE3200_LENGTH_OF_ADDRESS,
+ InformationBuffer
+ );
+
+ *BytesRead = InformationBufferLength;
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ if (InformationBufferLength != 4) {
+
+ return NDIS_STATUS_INVALID_DATA;
+
+ }
+
+ //
+ // Now call the filter package to set the packet filter.
+ //
+ NdisMoveMemory ((PVOID)&PacketFilter, InformationBuffer, sizeof(ULONG));
+
+ //
+ // Verify bits
+ //
+ if (PacketFilter & (NDIS_PACKET_TYPE_SOURCE_ROUTING |
+ NDIS_PACKET_TYPE_SMT |
+ NDIS_PACKET_TYPE_MAC_FRAME |
+ NDIS_PACKET_TYPE_FUNCTIONAL |
+ NDIS_PACKET_TYPE_ALL_FUNCTIONAL |
+ NDIS_PACKET_TYPE_ALL_MULTICAST |
+ NDIS_PACKET_TYPE_GROUP
+ )) {
+
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+
+ *BytesRead = 4;
+ *BytesNeeded = 0;
+
+ break;
+
+ }
+
+ //
+ // Submit the change
+ //
+ Status = NE3200ChangeClass(
+ Adapter,
+ PacketFilter
+ );
+
+ *BytesRead = InformationBufferLength;
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ *BytesRead = 4;
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+
+ default:
+
+ Status = NDIS_STATUS_INVALID_OID;
+ break;
+
+ }
+
+ if (Status == NDIS_STATUS_PENDING) {
+
+ Adapter->RequestInProgress = TRUE;
+
+ }
+
+ IF_LOG('W');
+ return Status;
+}
+
+STATIC
+NDIS_STATUS
+NE3200QueryInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+)
+
+/*++
+
+Routine Description:
+
+ The NE3200QueryInformation process a Query request for
+ NDIS_OIDs that are specific about the Driver.
+
+Arguments:
+
+ MiniportAdapterContext - a pointer to the adapter.
+
+ Oid - the NDIS_OID to process.
+
+ InformationBuffer - a pointer into the
+ NdisRequest->InformationBuffer into which store the result of the query.
+
+ InformationBufferLength - a pointer to the number of bytes left in the
+ InformationBuffer.
+
+ BytesWritten - a pointer to the number of bytes written into the
+ InformationBuffer.
+
+ BytesNeeded - If there is not enough room in the information buffer
+ then this will contain the number of bytes needed to complete the
+ request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ //
+ // The command block for getting the statistics from the adapter.
+ //
+ PNE3200_SUPER_COMMAND_BLOCK CommandBlock;
+
+ //
+ // The adapter to process the request for.
+ //
+ PNE3200_ADAPTER Adapter = PNE3200_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ //
+ // Save the information about the request
+ //
+ Adapter->BytesWritten = BytesWritten;
+ Adapter->BytesNeeded = BytesNeeded;
+ Adapter->Oid = Oid;
+ Adapter->InformationBuffer = InformationBuffer;
+ Adapter->InformationBufferLength = InformationBufferLength;
+
+ IF_LOG('?');
+
+ //
+ // Get a public command block. This will succeed since
+ // the wrapper will only give one request at a time, and
+ // there are more than 1 public command block.
+ //
+ NE3200AcquirePublicCommandBlock(Adapter,
+ &CommandBlock
+ );
+
+ //
+ // Store the request that uses this CB
+ //
+ CommandBlock->Set = TRUE;
+
+ //
+ // Setup the command block.
+ //
+ CommandBlock->NextCommand = NULL;
+
+ CommandBlock->Hardware.State = NE3200_STATE_WAIT_FOR_ADAPTER;
+ CommandBlock->Hardware.Status = 0;
+ CommandBlock->Hardware.NextPending = NE3200_NULL;
+ CommandBlock->Hardware.CommandCode = NE3200_COMMAND_READ_ADAPTER_STATISTICS;
+
+ //
+ // Now that we're set up, let's do it!
+ //
+ Adapter->RequestInProgress = TRUE;
+ NE3200SubmitCommandBlock(Adapter, CommandBlock);
+
+ //
+ // Catch the ball at the interrupt handler
+ //
+
+ IF_LOG('/');
+ return NDIS_STATUS_PENDING;
+}
+
+STATIC
+VOID
+NE3200FinishQueryInformation(
+ IN PNE3200_ADAPTER Adapter
+)
+
+/*++
+
+Routine Description:
+
+ The NE3200FinishQueryInformation finish processing a Query request for
+ NDIS_OIDs that are specific about the Driver.
+
+Arguments:
+
+ Adapter - a pointer to the adapter.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+static
+NDIS_OID NE3200GlobalSupportedOids[] = {
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+ OID_GEN_RCV_CRC_ERROR,
+ OID_GEN_TRANSMIT_QUEUE_LENGTH,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ OID_802_3_RCV_ERROR_ALIGNMENT,
+ OID_802_3_XMIT_ONE_COLLISION,
+ OID_802_3_XMIT_MORE_COLLISIONS,
+ OID_802_3_XMIT_DEFERRED,
+ OID_802_3_XMIT_MAX_COLLISIONS,
+ OID_802_3_RCV_OVERRUN,
+ OID_802_3_XMIT_UNDERRUN,
+ OID_802_3_XMIT_HEARTBEAT_FAILURE,
+ OID_802_3_XMIT_TIMES_CRS_LOST,
+ OID_802_3_XMIT_LATE_COLLISIONS
+ };
+
+ //
+ // Get the saved information about the request.
+ //
+ PUINT BytesWritten = Adapter->BytesWritten;
+ PUINT BytesNeeded = Adapter->BytesNeeded;
+ NDIS_OID Oid = Adapter->Oid;
+ PVOID InformationBuffer = Adapter->InformationBuffer;
+ UINT InformationBufferLength = Adapter->InformationBufferLength;
+
+
+ //
+ // Variables for holding the data that satisfies the request.
+ //
+ NDIS_MEDIUM Medium = NdisMedium802_3;
+ UINT GenericUlong;
+ USHORT GenericUShort;
+ UCHAR GenericArray[6];
+ NDIS_HARDWARE_STATUS HardwareStatus;
+
+ //
+ // Common variables for pointing to result of query
+ //
+ PVOID MoveSource = (PVOID)(&GenericUlong);
+ ULONG MoveBytes = sizeof(ULONG);
+
+ //
+ // The status of the request.
+ //
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ //
+ // Initialize the result
+ //
+ *BytesWritten = 0;
+ *BytesNeeded = 0;
+
+ IF_LOG('!');
+
+ //
+ // Switch on request type
+ //
+ switch(Oid){
+
+ case OID_GEN_MAC_OPTIONS:
+
+ GenericUlong = (ULONG)(NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
+ NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
+ NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
+ NDIS_MAC_OPTION_NO_LOOPBACK
+ );
+
+ break;
+
+ case OID_GEN_SUPPORTED_LIST:
+
+ MoveSource = (PVOID)(NE3200GlobalSupportedOids);
+ MoveBytes = sizeof(NE3200GlobalSupportedOids);
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+
+ if (Adapter->ResetInProgress){
+
+ HardwareStatus = NdisHardwareStatusReset;
+
+ } else {
+
+ HardwareStatus = NdisHardwareStatusReady;
+
+ }
+
+
+ MoveSource = (PVOID)(&HardwareStatus);
+ MoveBytes = sizeof(NDIS_HARDWARE_STATUS);
+
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+
+ MoveSource = (PVOID) (&Medium);
+ MoveBytes = sizeof(NDIS_MEDIUM);
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+
+ GenericUlong = (ULONG) (MAXIMUM_ETHERNET_PACKET_SIZE - NE3200_HEADER_SIZE);
+
+ break;
+
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+
+ GenericUlong = (ULONG) (MAXIMUM_ETHERNET_PACKET_SIZE);
+
+ break;
+
+
+ case OID_GEN_LINK_SPEED:
+
+ //
+ // 10 Mbps
+ //
+ GenericUlong = (ULONG)100000;
+
+ break;
+
+
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+
+ GenericUlong = (ULONG) MAXIMUM_ETHERNET_PACKET_SIZE *
+ NE3200_NUMBER_OF_TRANSMIT_BUFFERS;
+
+ break;
+
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+
+ GenericUlong = (ULONG) MAXIMUM_ETHERNET_PACKET_SIZE *
+ NE3200_NUMBER_OF_RECEIVE_BUFFERS;
+
+ break;
+
+
+ case OID_GEN_VENDOR_ID:
+
+ NdisMoveMemory(
+ (PVOID)&GenericUlong,
+ Adapter->NetworkAddress,
+ 3
+ );
+ GenericUlong &= 0xFFFFFF00;
+ MoveSource = (PVOID)(&GenericUlong);
+ MoveBytes = sizeof(GenericUlong);
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+
+ MoveSource = (PVOID)"NE3200 Adapter";
+ MoveBytes = 15;
+ break;
+
+ case OID_GEN_DRIVER_VERSION:
+
+ GenericUShort = (USHORT)0x0300;
+
+ MoveSource = (PVOID)(&GenericUShort);
+ MoveBytes = sizeof(GenericUShort);
+ break;
+
+ case OID_802_3_PERMANENT_ADDRESS:
+
+ NdisMoveMemory(
+ (PCHAR)GenericArray,
+ Adapter->NetworkAddress,
+ NE3200_LENGTH_OF_ADDRESS
+ );
+
+ MoveSource = (PVOID)(GenericArray);
+ MoveBytes = NE3200_LENGTH_OF_ADDRESS;
+ break;
+
+ case OID_802_3_CURRENT_ADDRESS:
+ NdisMoveMemory(
+ (PCHAR)GenericArray,
+ Adapter->CurrentAddress,
+ NE3200_LENGTH_OF_ADDRESS
+ );
+
+ MoveSource = (PVOID)(GenericArray);
+ MoveBytes = NE3200_LENGTH_OF_ADDRESS;
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+
+ GenericUlong = (ULONG) NE3200_MAXIMUM_MULTICAST;
+
+ break;
+
+ default:
+
+ switch(Oid){
+
+ case OID_GEN_XMIT_OK:
+ GenericUlong = (ULONG) Adapter->GoodTransmits;
+ break;
+
+ case OID_GEN_RCV_OK:
+ GenericUlong = (ULONG) Adapter->GoodReceives;
+ break;
+
+ case OID_GEN_XMIT_ERROR:
+ GenericUlong = (ULONG) (Adapter->RetryFailure +
+ Adapter->LostCarrier +
+ Adapter->UnderFlow +
+ Adapter->NoClearToSend);
+ break;
+
+ case OID_GEN_RCV_ERROR:
+ GenericUlong = (ULONG) (Adapter->CrcErrors +
+ Adapter->AlignmentErrors +
+ Adapter->OutOfResources +
+ Adapter->DmaOverruns);
+ break;
+
+ case OID_GEN_RCV_NO_BUFFER:
+ GenericUlong = (ULONG) Adapter->OutOfResources;
+ break;
+
+ case OID_GEN_RCV_CRC_ERROR:
+ GenericUlong = (ULONG) Adapter->CrcErrors;
+ break;
+
+ case OID_GEN_TRANSMIT_QUEUE_LENGTH:
+ GenericUlong = (ULONG) Adapter->TransmitsQueued;
+ break;
+
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+ GenericUlong = (ULONG) Adapter->AlignmentErrors;
+ break;
+
+ case OID_802_3_XMIT_ONE_COLLISION:
+ GenericUlong = (ULONG) Adapter->OneRetry;
+ break;
+
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+ GenericUlong = (ULONG) Adapter->MoreThanOneRetry;
+ break;
+
+ case OID_802_3_XMIT_DEFERRED:
+ GenericUlong = (ULONG) Adapter->Deferred;
+ break;
+
+ case OID_802_3_XMIT_MAX_COLLISIONS:
+ GenericUlong = (ULONG) Adapter->RetryFailure;
+ break;
+
+ case OID_802_3_RCV_OVERRUN:
+ GenericUlong = (ULONG) Adapter->DmaOverruns;
+ break;
+
+ case OID_802_3_XMIT_UNDERRUN:
+ GenericUlong = (ULONG) Adapter->UnderFlow;
+ break;
+
+ case OID_802_3_XMIT_HEARTBEAT_FAILURE:
+ GenericUlong = (ULONG) Adapter->NoClearToSend;
+ break;
+
+ case OID_802_3_XMIT_TIMES_CRS_LOST:
+ GenericUlong = (ULONG) Adapter->LostCarrier;
+ break;
+
+ default:
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+
+ }
+
+ }
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ if (MoveBytes > InformationBufferLength) {
+
+ //
+ // Not enough room in InformationBuffer. Punt
+ //
+ *BytesNeeded = MoveBytes;
+
+ Status = NDIS_STATUS_INVALID_LENGTH;
+
+ } else {
+
+ //
+ // Copy result into InformationBuffer
+ //
+ *BytesWritten = MoveBytes;
+
+ if (MoveBytes > 0) {
+
+ NE3200_MOVE_MEMORY(
+ InformationBuffer,
+ MoveSource,
+ MoveBytes
+ );
+ }
+ }
+ }
+
+ Adapter->RequestInProgress = FALSE;
+
+ //
+ // Complete the request
+ //
+ NdisMQueryInformationComplete(
+ Adapter->MiniportAdapterHandle,
+ Status
+ );
+
+ IF_LOG('@');
+
+ return;
+}
+
diff --git a/private/ntos/ndis/ne3200/reset.c b/private/ntos/ndis/ne3200/reset.c
new file mode 100644
index 000000000..1da22a03e
--- /dev/null
+++ b/private/ntos/ndis/ne3200/reset.c
@@ -0,0 +1,1805 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ reset.c
+
+Abstract:
+
+ This is the file containing the reset code for the Novell NE3200 EISA
+ Ethernet adapter. This driver conforms to the NDIS 3.0 miniport
+ interface.
+
+Author:
+
+ Keith Moore (KeithMo) 08-Jan-1991
+
+Environment:
+
+Revision History:
+
+--*/
+
+#include <ne3200sw.h>
+
+//
+// Global information stored in ne3200.c. This is used for
+// getting at the download software
+//
+extern NE3200_GLOBAL_DATA NE3200Globals;
+
+//
+// Forward declarations of functions in this file
+//
+extern
+VOID
+NE3200ProcessRequestQueue(
+ IN PNE3200_ADAPTER Adapter,
+ IN BOOLEAN StatisticsUpdated
+ );
+
+STATIC
+VOID
+NE3200SetConfigurationBlock(
+ IN PNE3200_ADAPTER Adapter
+ );
+
+STATIC
+BOOLEAN
+NE3200SetConfigurationBlockAndInit(
+ IN PNE3200_ADAPTER Adapter
+ );
+
+NDIS_STATUS
+NE3200ChangeCurrentAddress(
+ IN PNE3200_ADAPTER Adapter
+ );
+
+VOID
+NE3200ResetCommandBlocks(
+ IN PNE3200_ADAPTER Adapter
+ );
+
+extern
+VOID
+NE3200GetStationAddress(
+ IN PNE3200_ADAPTER Adapter
+ );
+
+extern
+VOID
+NE3200SetupForReset(
+ IN PNE3200_ADAPTER Adapter
+ );
+
+STATIC
+VOID
+NE3200DoResetIndications(
+ IN PNE3200_ADAPTER Adapter,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+NE3200ResetHandler(
+ IN PVOID SystemSpecific1,
+ IN PNE3200_ADAPTER Adapter,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+BOOLEAN
+NE3200InitialInit(
+ IN PNE3200_ADAPTER Adapter,
+ IN UINT NE3200InterruptVector,
+ IN NDIS_INTERRUPT_MODE NE3200InterruptMode
+ );
+
+
+#pragma NDIS_INIT_FUNCTION(NE3200InitialInit)
+
+BOOLEAN
+NE3200InitialInit(
+ IN PNE3200_ADAPTER Adapter,
+ IN UINT NE3200InterruptVector,
+ IN NDIS_INTERRUPT_MODE NE3200InterruptMode
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets up the initial init of the driver, by
+ stopping the adapter, connecting the interrupt and initializing
+ the adapter.
+
+Arguments:
+
+ Adapter - The adapter for the hardware.
+
+Return Value:
+
+ TRUE if the initialization succeeds, else FALSE.
+
+--*/
+
+{
+ //
+ // Status of NDIS calls
+ //
+ NDIS_STATUS Status;
+
+ //
+ // First we make sure that the device is stopped.
+ //
+ NE3200StopChip(Adapter);
+
+ //
+ // The ISR will set this to FALSE if we get an interrupt
+ //
+ Adapter->InitialInit = TRUE;
+
+ //
+ // Initialize the interrupt.
+ //
+ Status = NdisMRegisterInterrupt(
+ &Adapter->Interrupt,
+ Adapter->MiniportAdapterHandle,
+ NE3200InterruptVector,
+ NE3200InterruptVector,
+ FALSE,
+ FALSE,
+ NE3200InterruptMode
+ );
+
+ //
+ // So far so good
+ //
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ //
+ // Now try to initialize the adapter
+ //
+ if (!NE3200SetConfigurationBlockAndInit(Adapter)) {
+
+ //
+ // Failed. Write out an error log entry.
+ //
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_TIMEOUT,
+ 2,
+ initialInit,
+ NE3200_ERRMSG_NO_DELAY
+ );
+
+ //
+ // Unhook the interrupt
+ //
+ NdisMDeregisterInterrupt(&Adapter->Interrupt);
+
+ Adapter->InitialInit = FALSE;
+
+ return FALSE;
+
+ }
+
+ //
+ // Get hardware assigned network address.
+ //
+ NE3200GetStationAddress(
+ Adapter
+ );
+
+ //
+ // We can start the chip. We may not
+ // have any bindings to indicate to but this
+ // is unimportant.
+ //
+ Status = NE3200ChangeCurrentAddress(Adapter);
+
+ Adapter->InitialInit = FALSE;
+
+ return(Status == NDIS_STATUS_SUCCESS);
+
+ } else {
+
+ //
+ // Interrupt line appears to be taken. Notify user.
+ //
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_INTERRUPT_CONNECT,
+ 2,
+ initialInit,
+ NE3200_ERRMSG_INIT_INTERRUPT
+ );
+
+ Adapter->InitialInit = FALSE;
+
+ return(FALSE);
+ }
+
+}
+
+VOID
+NE3200StartChipAndDisableInterrupts(
+ IN PNE3200_ADAPTER Adapter,
+ IN PNE3200_SUPER_RECEIVE_ENTRY FirstReceiveEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to start an already initialized NE3200,
+ but to keep the interrupt line masked.
+
+Arguments:
+
+ Adapter - The adapter for the NE3200 to start.
+
+ FirstReceiveEntry - Pointer to the first receive entry to be
+ used by the adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ IF_LOG('%');
+
+ //
+ // Write the new receive pointer.
+ //
+ NE3200_WRITE_RECEIVE_POINTER(
+ Adapter,
+ NdisGetPhysicalAddressLow(FirstReceiveEntry->Self)
+ );
+
+ NE3200_WRITE_LOCAL_DOORBELL_INTERRUPT(
+ Adapter,
+ NE3200_LOCAL_DOORBELL_NEW_RECEIVE
+ );
+
+ //
+ // Initialize the doorbell & system interrupt masks
+ //
+ NE3200_WRITE_SYSTEM_DOORBELL_MASK(
+ Adapter,
+ 0
+ );
+
+ NE3200_WRITE_SYSTEM_INTERRUPT(
+ Adapter,
+ NE3200_SYSTEM_INTERRUPT_ENABLE
+ );
+
+ NE3200_WRITE_MAILBOX_UCHAR(
+ Adapter,
+ NE3200_MAILBOX_STATUS,
+ 0
+ );
+
+}
+
+VOID
+NE3200EnableAdapter(
+ IN NDIS_HANDLE Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to start an already initialized NE3200.
+
+Arguments:
+
+ Context - The adapter for the NE3200 to start.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNE3200_ADAPTER Adapter = (PNE3200_ADAPTER)Context;
+
+ IF_LOG('#');
+
+ //
+ // Initialize the doorbell & system interrupt masks
+ //
+ NE3200_WRITE_SYSTEM_INTERRUPT(
+ Adapter,
+ NE3200_SYSTEM_INTERRUPT_ENABLE
+ );
+
+ if (!Adapter->InterruptsDisabled) {
+ NE3200_WRITE_SYSTEM_DOORBELL_MASK(
+ Adapter,
+ NE3200_SYSTEM_DOORBELL_MASK
+ );
+ }
+
+ NE3200_WRITE_SYSTEM_DOORBELL_INTERRUPT(
+ Adapter,
+ NE3200_SYSTEM_DOORBELL_MASK
+ );
+
+ NE3200_WRITE_MAILBOX_UCHAR(
+ Adapter,
+ NE3200_MAILBOX_STATUS,
+ 0
+ );
+
+}
+
+VOID
+NE3200EnableInterrupt(
+ IN NDIS_HANDLE Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to turn on the interrupt mask.
+
+Arguments:
+
+ Context - The adapter for the NE3200 to start.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNE3200_ADAPTER Adapter = (PNE3200_ADAPTER)Context;
+
+ IF_LOG('E');
+
+ //
+ // Enable further interrupts.
+ //
+ Adapter->InterruptsDisabled = FALSE;
+ NE3200_WRITE_SYSTEM_DOORBELL_MASK(
+ Adapter,
+ NE3200_SYSTEM_DOORBELL_MASK
+ );
+
+}
+
+VOID
+NE3200DisableInterrupt(
+ IN NDIS_HANDLE Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to turn off the interrupt mask.
+
+Arguments:
+
+ Context - The adapter for the NE3200 to start.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNE3200_ADAPTER Adapter = (PNE3200_ADAPTER)Context;
+
+ //
+ // Initialize the doorbell mask
+ //
+ Adapter->InterruptsDisabled = TRUE;
+ NE3200_WRITE_SYSTEM_DOORBELL_MASK(
+ Adapter,
+ 0
+ );
+
+ IF_LOG('D');
+}
+
+VOID
+NE3200StopChip(
+ IN PNE3200_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to stop the NE3200.
+
+Arguments:
+
+ Adapter - The NE3200 adapter to stop.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ IF_LOG('h');
+
+ //
+ // Packet reception can be stopped by writing a
+ // (ULONG)-1 to the Receive Packet Mailbox port.
+ // Also, commands can be stopped by writing a -1
+ // to the Command Pointer Mailbox port.
+ //
+ NE3200_WRITE_RECEIVE_POINTER(
+ Adapter,
+ NE3200_NULL
+ );
+
+ NE3200_WRITE_COMMAND_POINTER(
+ Adapter,
+ NE3200_NULL
+ );
+
+ //
+ // Ack any outstanding interrupts
+ //
+ NE3200_WRITE_LOCAL_DOORBELL_INTERRUPT(
+ Adapter,
+ NE3200_LOCAL_DOORBELL_NEW_RECEIVE | NE3200_LOCAL_DOORBELL_NEW_COMMAND
+ );
+
+ //
+ // Disable the doorbell & system interrupt masks.
+ //
+ NE3200_WRITE_SYSTEM_INTERRUPT(
+ Adapter,
+ 0
+ );
+
+ NE3200_WRITE_SYSTEM_DOORBELL_MASK(
+ Adapter,
+ 0
+ );
+
+ NE3200_WRITE_SYSTEM_DOORBELL_INTERRUPT(
+ Adapter,
+ 0
+ );
+
+}
+
+STATIC
+VOID
+NE3200SetConfigurationBlock(
+ IN PNE3200_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine simply fills the configuration block
+ with the information necessary for initialization.
+
+Arguments:
+
+ Adapter - The adapter which holds the initialization block
+ to initialize.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+
+ PNE3200_CONFIGURATION_BLOCK Configuration;
+
+ //
+ // Get the configuration block
+ //
+ Configuration = Adapter->ConfigurationBlock;
+
+ //
+ // Initialize it to zero
+ //
+ NdisZeroMemory(
+ Configuration,
+ sizeof(NE3200_CONFIGURATION_BLOCK)
+ );
+
+ //
+ // Set up default values
+ //
+ Configuration->ByteCount = 12;
+ Configuration->FifoThreshold = 8;
+ Configuration->AddressLength = 6;
+ Configuration->SeparateAddressAndLength = 1;
+ Configuration->PreambleLength = 2;
+ Configuration->InterframeSpacing = 96;
+ Configuration->SlotTime = 512;
+ Configuration->MaximumRetries = 15;
+ Configuration->DisableBroadcast = 1;
+ Configuration->MinimumFrameLength = 64;
+
+}
+
+VOID
+NE3200DoAdapterReset(
+ IN PNE3200_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This is the resetting the adapter hardware.
+
+ It makes the following assumptions:
+
+ 1) That the hardware has been stopped.
+
+ 2) That no other adapter activity can occur.
+
+ When this routine is finished all of the adapter information
+ will be as if the driver was just initialized.
+
+Arguments:
+
+ Adapter - The adapter whose hardware is to be reset.
+
+Return Value:
+
+ not.
+
+--*/
+{
+
+ //
+ // Recover all of the adapter transmit merge buffers.
+ //
+ {
+
+ UINT i;
+
+ for (
+ i = 0;
+ i < NE3200_NUMBER_OF_TRANSMIT_BUFFERS;
+ i++
+ ) {
+
+ Adapter->NE3200Buffers[i].Next = i+1;
+
+ }
+
+ Adapter->NE3200BufferListHead = 0;
+ Adapter->NE3200Buffers[NE3200_NUMBER_OF_TRANSMIT_BUFFERS-1].Next = -1;
+
+ }
+
+ //
+ // Reset all state variables
+ //
+ NE3200ResetVariables(Adapter);
+
+ //
+ // Recover all command blocks
+ //
+ NE3200ResetCommandBlocks(Adapter);
+
+ //
+ // Initialize the adapter
+ //
+ NE3200SetConfigurationBlockAndInit(Adapter);
+
+
+}
+
+STATIC
+BOOLEAN
+NE3200SetConfigurationBlockAndInit(
+ IN PNE3200_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ It is this routine's responsibility to make sure that the
+ Configuration block is filled and the adapter is initialized
+ *but not* started.
+
+Arguments:
+
+ Adapter - The adapter whose hardware is to be initialized.
+
+Return Value:
+
+ If ResetAsynchoronous is FALSE, then returns TRUE if reset successful,
+ FALSE if reset unsuccessful.
+
+ If ResetAsynchoronous is TRUE, then always returns TRUE.
+
+--*/
+{
+
+ //
+ // Fill in the adapter's initialization block.
+ //
+ NE3200SetConfigurationBlock(Adapter);
+
+ //
+ // Set the initial state for the ResetDpc state machine.
+ //
+ Adapter->ResetState = NE3200ResetStateStarting;
+
+ //
+ // Go through the reset
+ //
+ NE3200ResetHandler(NULL, Adapter, NULL, NULL);
+
+ //
+ // Is Synchronous resets, then check the final result
+ //
+ if (!Adapter->ResetAsynchronous) {
+
+ return((Adapter->ResetResult == NE3200ResetResultSuccessful));
+
+ } else {
+
+ return(TRUE);
+
+ }
+
+}
+
+VOID
+NE3200ResetHandler(
+ IN PVOID SystemSpecific1,
+ IN PNE3200_ADAPTER Adapter,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+
+/*++
+
+Routine Description:
+
+ This manages the reset/download process. It is
+ responsible for resetting the adapter, waiting for proper
+ status, downloading MAC.BIN, waiting for MAC.BIN initialization,
+ and optionally sending indications to the appropriate protocol.
+
+ Since the NE3200's status registers must be polled during the
+ reset/download process, this is implemented as a state machine.
+
+Arguments:
+
+ Adapter - The adapter whose hardware is to be initialized.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ //
+ // Physical address of the MAC.BIN buffer.
+ //
+ NDIS_PHYSICAL_ADDRESS MacBinPhysicalAddress;
+
+ //
+ // Status from the adapter.
+ //
+ UCHAR Status;
+
+ //
+ // Simple iteration counter.
+ //
+ UINT i;
+
+ //
+ // Loop until the reset has completed.
+ //
+ while (Adapter->ResetState != NE3200ResetStateComplete) {
+
+ switch (Adapter->ResetState) {
+
+ //
+ // The first stage of resetting an NE3200
+ //
+ case NE3200ResetStateStarting :
+
+ //
+ // Unfortunately, a hardware reset to the NE3200 does *not*
+ // reset the BMIC chip. To ensure that we read a proper status,
+ // we'll clear all of the BMIC's registers.
+ //
+ NE3200_WRITE_SYSTEM_INTERRUPT(
+ Adapter,
+ 0
+ );
+
+ //
+ // I changed this to ff since the original 0 didn't work for
+ // some cases. since we don't have the specs....
+ //
+ NE3200_WRITE_LOCAL_DOORBELL_INTERRUPT(
+ Adapter,
+ 0xff
+ );
+
+ NE3200_WRITE_SYSTEM_DOORBELL_MASK(
+ Adapter,
+ 0
+ );
+
+ NE3200_SYNC_CLEAR_SYSTEM_DOORBELL_INTERRUPT(
+ Adapter
+ );
+
+ for (i = 0 ; i < 16 ; i += 4 ) {
+
+ NE3200_WRITE_MAILBOX_ULONG(
+ Adapter,
+ i,
+ 0L
+ );
+
+ }
+
+ //
+ // Toggle the NE3200's reset line.
+ //
+ NE3200_WRITE_RESET(
+ Adapter,
+ NE3200_RESET_BIT_ON
+ );
+
+ NE3200_WRITE_RESET(
+ Adapter,
+ NE3200_RESET_BIT_OFF
+ );
+
+ //
+ // Switch to the next state.
+ //
+ Adapter->ResetState = NE3200ResetStateResetting;
+ Adapter->ResetTimeoutCounter = NE3200_TIMEOUT_RESET;
+
+ //
+ // Loop to the next processing
+ //
+ break;
+
+ //
+ // Part Deux. The actual downloading of the software.
+ //
+ case NE3200ResetStateResetting :
+
+ //
+ // Read the status mailbox.
+ //
+ NE3200_READ_MAILBOX_UCHAR(Adapter, NE3200_MAILBOX_RESET_STATUS, &Status);
+
+ if (Status == NE3200_RESET_PASSED) {
+
+ //
+ // We have good reset. Initiate the MAC.BIN download.
+ //
+
+ //
+ // The station address for this adapter can be forced to
+ // a specific value at initialization time. When MAC.BIN
+ // first gets control, it reads mailbox 10. If this mailbox
+ // contains a 0xFF, then the burned-in PROM station address
+ // is used. If this mailbox contains any value other than
+ // 0xFF, then mailboxes 10-15 are read. The six bytes
+ // stored in these mailboxes then become the station address.
+ //
+ // Since we have no need for this feature, we will always
+ // initialize mailbox 10 with a 0xFF.
+ //
+ NE3200_WRITE_MAILBOX_UCHAR(
+ Adapter,
+ NE3200_MAILBOX_STATION_ID,
+ 0xFF
+ );
+
+
+ //
+ // Get the MAC.BIN buffer.
+ //
+ MacBinPhysicalAddress = NE3200Globals.MacBinPhysicalAddress;
+
+ //
+ // Download MAC.BIN to the card.
+ //
+ NE3200_WRITE_MAILBOX_USHORT(
+ Adapter,
+ NE3200_MAILBOX_MACBIN_LENGTH,
+ NE3200Globals.MacBinLength
+ );
+
+ NE3200_WRITE_MAILBOX_UCHAR(
+ Adapter,
+ NE3200_MAILBOX_MACBIN_DOWNLOAD_MODE,
+ NE3200_MACBIN_DIRECT
+ );
+
+ NE3200_WRITE_MAILBOX_ULONG(
+ Adapter,
+ NE3200_MAILBOX_MACBIN_POINTER,
+ NdisGetPhysicalAddressLow(MacBinPhysicalAddress)
+ );
+
+ NE3200_WRITE_MAILBOX_USHORT(
+ Adapter,
+ NE3200_MAILBOX_MACBIN_TARGET,
+ NE3200_MACBIN_TARGET_ADDRESS >> 1
+ );
+
+ //
+ // This next OUT "kicks" the loader into action.
+ //
+ NE3200_WRITE_MAILBOX_UCHAR(
+ Adapter,
+ NE3200_MAILBOX_RESET_STATUS,
+ 0
+ );
+
+ //
+ // Switch to the next state.
+ //
+ Adapter->ResetState = NE3200ResetStateDownloading;
+ Adapter->ResetTimeoutCounter = NE3200_TIMEOUT_DOWNLOAD;
+
+ //
+ // Loop to the next state.
+ //
+
+ } else if (Status == NE3200_RESET_FAILED) {
+
+ //
+ // Reset failure. Notify the authorities and
+ // next of kin.
+ //
+ Adapter->ResetResult = NE3200ResetResultResetFailure;
+ Adapter->ResetState = NE3200ResetStateComplete;
+
+ NE3200DoResetIndications(Adapter, NDIS_STATUS_HARD_ERRORS);
+
+ } else {
+
+ //
+ // Still waiting for results, check if we have
+ // timed out waiting.
+ //
+ Adapter->ResetTimeoutCounter--;
+
+ if (Adapter->ResetTimeoutCounter == 0) {
+
+ //
+ // We've timed-out. Bad news. Notify the death.
+ //
+ Adapter->ResetResult = NE3200ResetResultResetTimeout;
+ Adapter->ResetState = NE3200ResetStateComplete;
+
+ NE3200DoResetIndications(Adapter, NDIS_STATUS_HARD_ERRORS);
+
+ } else {
+
+ //
+ // For Synchronous resets, we stall. For async,
+ // we set a timer to check later.
+ //
+ if (!Adapter->ResetAsynchronous) {
+
+ //
+ // Otherwise, wait and try again.
+ //
+ NdisStallExecution(10000);
+
+ } else{
+
+ //
+ // Try again later.
+ //
+ NdisMSetTimer(&Adapter->ResetTimer, 100);
+
+ return;
+
+ }
+
+ }
+
+ }
+
+ break;
+
+ //
+ // Part Three: The download was started. Check for completion,
+ // and reload the current station address.
+ //
+ case NE3200ResetStateDownloading :
+
+ //
+ // Read the download status.
+ //
+ NE3200_READ_MAILBOX_UCHAR(Adapter, NE3200_MAILBOX_STATUS, &Status);
+
+ if (Status == NE3200_INITIALIZATION_PASSED) {
+
+ //
+ // According to documentation from Compaq, this next port
+ // write will (in a future MAC.BIN) tell MAC.BIN whether or
+ // not to handle loopback internally. This value is currently
+ // not used, but must still be written to the port.
+ //
+ NE3200_WRITE_MAILBOX_UCHAR(
+ Adapter,
+ NE3200_MAILBOX_STATUS,
+ 1
+ );
+
+ //
+ // Initialization is good, the card is ready.
+ //
+ NE3200StartChipAndDisableInterrupts(Adapter,
+ Adapter->ReceiveQueueHead
+ );
+
+ {
+
+ //
+ // Do the work for updating the current address
+ //
+
+ //
+ // This points to the public Command Block.
+ //
+ PNE3200_SUPER_COMMAND_BLOCK CommandBlock;
+
+ //
+ // This points to the adapter's configuration block.
+ //
+ PNE3200_CONFIGURATION_BLOCK ConfigurationBlock =
+ Adapter->ConfigurationBlock;
+
+ //
+ // Get a public command block.
+ //
+ NE3200AcquirePublicCommandBlock(Adapter,
+ &CommandBlock
+ );
+
+ Adapter->ResetHandlerCommandBlock = CommandBlock;
+
+ //
+ // Setup the command block.
+ //
+
+ CommandBlock->NextCommand = NULL;
+
+ CommandBlock->Hardware.State = NE3200_STATE_WAIT_FOR_ADAPTER;
+ CommandBlock->Hardware.Status = 0;
+ CommandBlock->Hardware.NextPending = NE3200_NULL;
+ CommandBlock->Hardware.CommandCode =
+ NE3200_COMMAND_CONFIGURE_82586;
+ CommandBlock->Hardware.PARAMETERS.CONFIGURE.ConfigurationBlock =
+ NdisGetPhysicalAddressLow(Adapter->ConfigurationBlockPhysical);
+
+ //
+ // Now that we've got the command block built,
+ // let's do it!
+ //
+ NE3200SubmitCommandBlock(Adapter, CommandBlock);
+
+ Adapter->ResetState = NE3200ResetStateReloadAddress;
+ Adapter->ResetTimeoutCounter = NE3200_TIMEOUT_DOWNLOAD;
+
+ }
+
+ } else if (Status == NE3200_INITIALIZATION_FAILED) {
+
+ //
+ // Initialization failed. Notify the wrapper.
+ //
+ Adapter->ResetResult = NE3200ResetResultInitializationFailure;
+ Adapter->ResetState = NE3200ResetStateComplete;
+
+ NE3200DoResetIndications(Adapter, NDIS_STATUS_HARD_ERRORS);
+
+ } else {
+
+ //
+ // See if we've timed-out waiting for the download to
+ // complete.
+ //
+ Adapter->ResetTimeoutCounter--;
+
+ if (Adapter->ResetTimeoutCounter == 0) {
+
+ //
+ // We've timed-out. Bad news.
+ //
+ Adapter->ResetResult = NE3200ResetResultInitializationTimeout;
+ Adapter->ResetState = NE3200ResetStateComplete;
+
+ NE3200DoResetIndications(Adapter, NDIS_STATUS_HARD_ERRORS);
+
+ } else {
+
+ //
+ // For Synchronous resets, we stall. For async,
+ // we set a timer to check later.
+ //
+ if (!Adapter->ResetAsynchronous) {
+
+ //
+ // Otherwise, wait and try again.
+ //
+ NdisStallExecution(10000);
+
+ } else{
+
+ //
+ // Try again later.
+ //
+ NdisMSetTimer(&Adapter->ResetTimer, 100);
+ return;
+
+ }
+
+ }
+
+ }
+
+ break;
+
+ //
+ // Part Last: Waiting for the configuring of the adapter
+ // to complete
+ //
+ case NE3200ResetStateReloadAddress :
+
+ //
+ // Read the command block status.
+ //
+ if (Adapter->ResetHandlerCommandBlock->Hardware.State ==
+ NE3200_STATE_EXECUTION_COMPLETE) {
+
+ //
+ // return this command block
+ //
+ NE3200RelinquishCommandBlock(Adapter,
+ Adapter->ResetHandlerCommandBlock
+ );
+
+ //
+ // Reset is complete. Do those indications.
+ //
+ Adapter->ResetResult = NE3200ResetResultSuccessful;
+ Adapter->ResetState = NE3200ResetStateComplete;
+
+ NE3200DoResetIndications(Adapter, NDIS_STATUS_SUCCESS);
+
+ } else {
+
+ //
+ // See if we've timed-out.
+ //
+ Adapter->ResetTimeoutCounter--;
+
+ if (Adapter->ResetTimeoutCounter == 0) {
+
+ //
+ // We've timed-out. Bad news.
+ //
+
+ //
+ // return this command block
+ //
+ NE3200RelinquishCommandBlock(Adapter,
+ Adapter->ResetHandlerCommandBlock
+ );
+
+ Adapter->ResetResult = NE3200ResetResultInitializationTimeout;
+ Adapter->ResetState = NE3200ResetStateComplete;
+
+ NE3200DoResetIndications(Adapter, NDIS_STATUS_HARD_ERRORS);
+
+ } else {
+
+ if ( Adapter->ResetTimeoutCounter ==
+ (NE3200_TIMEOUT_DOWNLOAD/2) ) {
+
+ //
+ // The command may have stalled, try again.
+ //
+ NE3200_WRITE_LOCAL_DOORBELL_INTERRUPT(
+ Adapter,
+ NE3200_LOCAL_DOORBELL_NEW_COMMAND
+ );
+
+ }
+
+ //
+ // For Synchronous resets, we stall. For async,
+ // we set a timer to check later.
+ //
+ if (!Adapter->ResetAsynchronous) {
+
+ //
+ // Otherwise, wait and try again.
+ //
+ NdisStallExecution(10000);
+
+ } else{
+
+ //
+ // Check again later
+ //
+ NdisMSetTimer(&Adapter->ResetTimer, 100);
+ return;
+
+ }
+
+ }
+
+ }
+
+ break;
+
+ default :
+
+ //
+ // Somehow, we reached an invalid state.
+ //
+
+ //
+ // We'll try to salvage our way out of this.
+ //
+ Adapter->ResetResult = NE3200ResetResultInvalidState;
+ Adapter->ResetState = NE3200ResetStateComplete;
+
+ NE3200DoResetIndications(Adapter, NDIS_STATUS_HARD_ERRORS);
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 3,
+ resetDpc,
+ NE3200_ERRMSG_BAD_STATE,
+ (ULONG)(Adapter->ResetState)
+ );
+
+ break;
+ }
+
+ }
+
+}
+
+STATIC
+VOID
+NE3200DoResetIndications(
+ IN PNE3200_ADAPTER Adapter,
+ IN NDIS_STATUS Status
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NE3200ResetHandler to perform any
+ indications which need to be done after a reset. Note that
+ this routine will be called after either a successful reset
+ or a failed reset.
+
+Arguments:
+
+ Adapter - The adapter whose hardware has been initialized.
+
+ Status - The status of the reset to send to the protocol(s).
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Re-start the card if the reset was successful, else stop it.
+ //
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ NdisMSynchronizeWithInterrupt(
+ &(Adapter->Interrupt),
+ NE3200EnableAdapter,
+ (PVOID)(Adapter)
+ );
+
+ } else {
+
+ //
+ // Reset has failed.
+ //
+
+ NE3200StopChip(Adapter);
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 0
+ );
+ }
+
+ //
+ // Setup the network address.
+ //
+ NE3200ChangeCurrentAddress(Adapter);
+
+ Adapter->ResetInProgress = FALSE;
+
+ //
+ // Reset default reset method
+ //
+ Adapter->ResetAsynchronous = FALSE;
+
+ if (!Adapter->InitialInit) {
+
+ //
+ // Signal the end of the reset
+ //
+ NdisMResetComplete(
+ Adapter->MiniportAdapterHandle,
+ Status,
+ TRUE
+ );
+
+ }
+
+}
+
+extern
+VOID
+NE3200SetupForReset(
+ IN PNE3200_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to fill in the who and why a reset is
+ being set up as well as setting the appropriate fields in the
+ adapter.
+
+ NOTE: This routine must be called with the lock acquired.
+
+Arguments:
+
+ Adapter - The adapter whose hardware is to be initialized.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Ndis buffer mapped
+ //
+ PNDIS_BUFFER CurrentBuffer;
+
+ //
+ // Map register that was used
+ //
+ UINT CurMapRegister;
+
+ //
+ // Packet to abort
+ //
+ PNDIS_PACKET Packet;
+
+ //
+ // Reserved portion of the packet.
+ //
+ PNE3200_RESERVED Reserved;
+
+ //
+ // Pointer to command block being processed.
+ //
+ PNE3200_SUPER_COMMAND_BLOCK CurrentCommandBlock = Adapter->FirstCommandOnCard;
+
+
+
+ Adapter->ResetInProgress = TRUE;
+
+ //
+ // Shut down the chip. We won't be doing any more work until
+ // the reset is complete.
+ //
+ NE3200StopChip(Adapter);
+
+ //
+ // Un-map all outstanding transmits
+ //
+ while (CurrentCommandBlock != NULL) {
+
+ if (CurrentCommandBlock->Hardware.CommandCode == NE3200_COMMAND_TRANSMIT) {
+
+ //
+ // Remove first packet from the queue
+ //
+ Packet = CurrentCommandBlock->OwningPacket;
+ Reserved = PNE3200_RESERVED_FROM_PACKET(Packet);
+
+ if (Reserved->UsedNE3200Buffer) {
+ goto GetNextCommandBlock;
+ }
+
+ //
+ // The transmit is finished, so we can release
+ // the physical mapping used for it.
+ //
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ NULL,
+ &CurrentBuffer,
+ NULL
+ );
+
+ //
+ // Get starting map register
+ //
+ CurMapRegister = Reserved->CommandBlockIndex *
+ NE3200_MAXIMUM_BLOCKS_PER_PACKET;
+
+ //
+ // For each buffer
+ //
+ while (CurrentBuffer) {
+
+ //
+ // Finish the mapping
+ //
+ NdisMCompleteBufferPhysicalMapping(
+ Adapter->MiniportAdapterHandle,
+ CurrentBuffer,
+ CurMapRegister
+ );
+
+ ++CurMapRegister;
+
+ NdisGetNextBuffer(
+ CurrentBuffer,
+ &CurrentBuffer
+ );
+
+ }
+
+ }
+
+GetNextCommandBlock:
+
+ CurrentCommandBlock = CurrentCommandBlock->NextCommand;
+
+ //
+ // Now do the pending queue
+ //
+ if (CurrentCommandBlock == NULL) {
+
+ if (Adapter->FirstWaitingCommand != NULL) {
+
+ CurrentCommandBlock = Adapter->FirstWaitingCommand;
+ Adapter->FirstWaitingCommand = NULL;
+
+ }
+
+ }
+
+ }
+
+}
+
+
+#pragma NDIS_INIT_FUNCTION(NE3200GetStationAddress)
+
+VOID
+NE3200GetStationAddress(
+ IN PNE3200_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine gets the network address from the hardware.
+
+ NOTE: This routine assumes that it is called *immediately*
+ after MAC.BIN has been downloaded. It should only be called
+ immediately after SetConfigurationBlockAndInit() has completed.
+
+Arguments:
+
+ Adapter - Where to store the network address.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Read the station address from the ports
+ //
+ NE3200_READ_MAILBOX_UCHAR(
+ Adapter,
+ NE3200_MAILBOX_STATION_ID,
+ &Adapter->NetworkAddress[0]
+ );
+
+ NE3200_READ_MAILBOX_UCHAR(
+ Adapter,
+ NE3200_MAILBOX_STATION_ID + 1,
+ &Adapter->NetworkAddress[1]
+ );
+ NE3200_READ_MAILBOX_UCHAR(
+ Adapter,
+ NE3200_MAILBOX_STATION_ID + 2,
+ &Adapter->NetworkAddress[2]
+ );
+ NE3200_READ_MAILBOX_UCHAR(
+ Adapter,
+ NE3200_MAILBOX_STATION_ID + 3,
+ &Adapter->NetworkAddress[3]
+ );
+ NE3200_READ_MAILBOX_UCHAR(
+ Adapter,
+ NE3200_MAILBOX_STATION_ID + 4,
+ &Adapter->NetworkAddress[4]
+ );
+ NE3200_READ_MAILBOX_UCHAR(
+ Adapter,
+ NE3200_MAILBOX_STATION_ID +5,
+ &Adapter->NetworkAddress[5]
+ );
+
+ if (!Adapter->AddressChanged) {
+
+ //
+ // Copy the real address to be used as the current address.
+ //
+ NdisMoveMemory(
+ Adapter->CurrentAddress,
+ Adapter->NetworkAddress,
+ NE3200_LENGTH_OF_ADDRESS
+ );
+
+ }
+
+}
+
+
+VOID
+NE3200ResetVariables(
+ IN PNE3200_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets variables to their proper value after a reset.
+
+Arguments:
+
+ Adapter - Adapter we are resetting.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Clear the command queues
+ //
+ Adapter->FirstCommandOnCard = NULL;
+ Adapter->FirstWaitingCommand = NULL;
+
+ //
+ // Reset the receive buffer ring
+ //
+ Adapter->ReceiveQueueHead = Adapter->ReceiveQueue;
+ Adapter->ReceiveQueueTail =
+ Adapter->ReceiveQueue + Adapter->NumberOfReceiveBuffers - 1;
+
+ //
+ // Reset count of available command blocks
+ //
+ Adapter->NumberOfAvailableCommandBlocks = Adapter->NumberOfCommandBlocks;
+ Adapter->NumberOfPublicCommandBlocks = NE3200_NUMBER_OF_PUBLIC_CMD_BLOCKS;
+ Adapter->NextPublicCommandBlock = 0;
+ Adapter->NextCommandBlock = Adapter->CommandQueue;
+
+ //
+ // Reset transmitting and receiving states
+ //
+ Adapter->PacketResubmission = FALSE;
+ Adapter->TransmitsQueued = 0;
+ Adapter->CurrentReceiveIndex = 0;
+
+}
+
+VOID
+NE3200ResetCommandBlocks(
+ IN PNE3200_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets command block elementsto their proper value after a reset.
+
+Arguments:
+
+ Adapter - Adapter we are resetting.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Pointer to a Receive Entry. Used while initializing
+ // the Receive Queue.
+ //
+ PNE3200_SUPER_RECEIVE_ENTRY CurrentReceiveEntry;
+
+ //
+ // Pointer to a Command Block. Used while initializing
+ // the Command Queue.
+ //
+ PNE3200_SUPER_COMMAND_BLOCK CurrentCommandBlock;
+
+ //
+ // Simple iteration variable.
+ //
+ UINT i;
+
+ //
+ // Put the Command Blocks into a known state.
+ //
+ for(
+ i = 0, CurrentCommandBlock = Adapter->CommandQueue;
+ i < Adapter->NumberOfCommandBlocks;
+ i++, CurrentCommandBlock++
+ ) {
+
+ CurrentCommandBlock->Hardware.State = NE3200_STATE_FREE;
+ CurrentCommandBlock->Hardware.NextPending = NE3200_NULL;
+
+ CurrentCommandBlock->NextCommand = NULL;
+ CurrentCommandBlock->AvailableCommandBlockCounter =
+ &Adapter->NumberOfAvailableCommandBlocks;
+ CurrentCommandBlock->Timeout = FALSE;
+ }
+
+ //
+ // Now do the same for the public command queue.
+ //
+ for(
+ i = 0, CurrentCommandBlock = Adapter->PublicCommandQueue;
+ i < NE3200_NUMBER_OF_PUBLIC_CMD_BLOCKS;
+ i++, CurrentCommandBlock++
+ ) {
+
+ CurrentCommandBlock->Hardware.State = NE3200_STATE_FREE;
+ CurrentCommandBlock->Hardware.NextPending = NE3200_NULL;
+ CurrentCommandBlock->NextCommand = NULL;
+ CurrentCommandBlock->AvailableCommandBlockCounter =
+ &Adapter->NumberOfPublicCommandBlocks;
+ CurrentCommandBlock->CommandBlockIndex = (USHORT)i;
+ CurrentCommandBlock->Timeout = FALSE;
+ }
+
+ //
+ // Reset the receive buffers.
+ //
+ for(
+ i = 0, CurrentReceiveEntry = Adapter->ReceiveQueue;
+ i < Adapter->NumberOfReceiveBuffers;
+ i++, CurrentReceiveEntry++
+ ) {
+
+
+ //
+ // Initialize receive buffers
+ //
+ CurrentReceiveEntry->Hardware.State = NE3200_STATE_FREE;
+ CurrentReceiveEntry->Hardware.NextPending =
+ NdisGetPhysicalAddressLow(Adapter->ReceiveQueuePhysical) +
+ (i + 1) * sizeof(NE3200_SUPER_RECEIVE_ENTRY);
+ CurrentReceiveEntry->NextEntry = CurrentReceiveEntry + 1;
+
+ }
+
+ //
+ // Make sure the last entry is properly terminated.
+ //
+ (CurrentReceiveEntry - 1)->Hardware.NextPending = NE3200_NULL;
+ (CurrentReceiveEntry - 1)->NextEntry = Adapter->ReceiveQueue;
+
+}
+
+
+NDIS_STATUS
+NE3200ChangeCurrentAddress(
+ IN PNE3200_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to modify the card address.
+
+Arguments:
+
+ Adapter - The adapter for the NE3200 to change address.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS, if everything went ok
+ NDIS_STATUS_FAILURE, otherwise
+
+--*/
+{
+
+ //
+ // Modify the card address if needed
+ //
+
+ if (Adapter->AddressChanged) {
+
+ //
+ // The command block for submitting the change
+ //
+ PNE3200_SUPER_COMMAND_BLOCK CommandBlock;
+
+ //
+ // Temporary looping variable
+ //
+ UINT i;
+
+ //
+ // Get a public command block for the request
+ //
+ NE3200AcquirePublicCommandBlock(Adapter,
+ &CommandBlock
+ );
+
+ //
+ // Setup the command block.
+ //
+ CommandBlock->NextCommand = NULL;
+
+ CommandBlock->Hardware.State = NE3200_STATE_WAIT_FOR_ADAPTER;
+ CommandBlock->Hardware.Status = 0;
+ CommandBlock->Hardware.NextPending = NE3200_NULL;
+ CommandBlock->Hardware.CommandCode = NE3200_COMMAND_SET_STATION_ADDRESS;
+
+ //
+ // Copy in the address
+ //
+ NdisMoveMemory(
+ CommandBlock->Hardware.PARAMETERS.SET_ADDRESS.NewStationAddress,
+ Adapter->CurrentAddress,
+ NE3200_LENGTH_OF_ADDRESS
+ );
+
+ //
+ // Now that we've got the command block built,
+ // let's do it!
+ //
+ NE3200SubmitCommandBlock(Adapter, CommandBlock);
+
+ //
+ // Wait for the command block to finish
+ //
+ for (i = 0; i < 100000; i++) {
+ NdisStallExecution(100);
+ if (CommandBlock->Hardware.State == NE3200_STATE_EXECUTION_COMPLETE) {
+ break;
+ }
+ }
+
+ //
+ // Check the status of the command.
+ //
+ if (CommandBlock->Hardware.State != NE3200_STATE_EXECUTION_COMPLETE) {
+
+ //
+ // Failed
+ //
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 0
+ );
+
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ //
+ // return this command block
+ //
+ NE3200RelinquishCommandBlock(Adapter, CommandBlock);
+
+ }
+ return NDIS_STATUS_SUCCESS;
+}
+
+BOOLEAN
+SyncNE3200ClearDoorbellInterrupt(
+ IN PVOID SyncContext
+ )
+/*++
+
+Routine Description:
+
+ Clears the Doorbell Interrupt Port.
+
+Arguments:
+
+ SyncContext - pointer to the adapter block
+
+Return Value:
+
+ Always TRUE
+
+--*/
+
+{
+
+ PNE3200_ADAPTER Adapter = (PNE3200_ADAPTER)SyncContext;
+
+ //
+ // Clear the value
+ //
+ NdisRawWritePortUchar(
+ (ULONG)(Adapter->SystemDoorbellInterruptPort),
+ (UCHAR)0
+ );
+
+ return(FALSE);
+}
+
diff --git a/private/ntos/ndis/ne3200/send.c b/private/ntos/ndis/ne3200/send.c
new file mode 100644
index 000000000..e2eee44bb
--- /dev/null
+++ b/private/ntos/ndis/ne3200/send.c
@@ -0,0 +1,816 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ send.c
+
+Abstract:
+
+ This file contains the code for putting a packet through the
+ staged allocation for transmission.
+
+ This is a process of
+
+ 1) Calculating the what would need to be done to the
+ packet so that the packet can be transmitted on the hardware.
+
+ 2) Potentially allocating adapter buffers and copying user data
+ to those buffers so that the packet data is transmitted under
+ the hardware constraints.
+
+ 3) Allocating enough hardware ring entries so that the packet
+ can be transmitted.
+
+ 4) Relinquish those ring entries to the hardware.
+
+Author:
+
+ Anthony V. Ercolano (Tonye) 12-Sept-1990
+ Keith Moore (KeithMo) 08-Jan-1991
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+
+--*/
+
+#include <ne3200sw.h>
+
+//
+// Forward declarations of functions in this file.
+//
+VOID
+NE3200ConstrainPacket(
+ IN PNE3200_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet
+ );
+
+NDIS_STATUS
+NE3200TransmitPacket(
+ IN PNE3200_ADAPTER Adapter,
+ PNDIS_PACKET FirstPacket,
+ UINT TotalDataLength,
+ UINT NdisBufferCount,
+ PNDIS_BUFFER CurrentBuffer
+ );
+
+NDIS_STATUS
+NE3200TransmitMergedPacket(
+ IN PNE3200_ADAPTER Adapter,
+ PNDIS_PACKET FirstPacket
+ );
+
+
+NDIS_STATUS
+NE3200Send(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET Packet,
+ IN UINT Flags
+ )
+
+/*++
+
+Routine Description:
+
+ The NE3200Send request instructs a Miniport to transmit a packet through
+ the adapter onto the medium.
+
+Arguments:
+
+ MiniportAdapterContext - The context value returned by the Miniport when the
+ adapter was initialized. In reality, it is a pointer to NE3200_ADAPTER.
+
+ Packet - A pointer to a descriptor for the packet that is to be
+ transmitted.
+
+ Flags - The send options to use.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ //
+ // Pointer to the adapter.
+ //
+ PNE3200_ADAPTER Adapter;
+
+ //
+ // The number of physical buffers in the entire packet.
+ //
+ UINT PhysicalBufferCount;
+
+ //
+ // The total amount of data in the ndis packet.
+ //
+ UINT TotalDataLength;
+
+ //
+ // The number of ndis buffers in the packet.
+ //
+ UINT NdisBufferCount;
+
+ //
+ // Points to the current ndis buffer being walked.
+ //
+ PNDIS_BUFFER CurrentBuffer;
+
+ //
+ // Points to the miniport reserved portion of this packet. This
+ // interpretation of the reserved section is only valid during
+ // the allocation phase of the packet.
+ //
+ PNE3200_RESERVED Reserved = PNE3200_RESERVED_FROM_PACKET(Packet);
+
+ //
+ // Status of the transmit.
+ //
+ NDIS_STATUS Status;
+
+ //
+ // The adapter upon which to transmit the packet.
+ //
+ Adapter = PNE3200_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ IF_LOG('s');
+
+ //
+ // Check if this is a packet we rejected earlier due to a lack
+ // of resources. If so, we don't have to recalculate all the
+ // constraints.
+ //
+ if (!Adapter->PacketResubmission) {
+
+ ASSERT(sizeof(NE3200_RESERVED) <= sizeof(Packet->MiniportReserved));
+
+ //
+ // Determine if and how much adapter space would need to be allocated
+ // to meet hardware constraints.
+ //
+ NdisQueryPacket(
+ Packet,
+ &PhysicalBufferCount,
+ &NdisBufferCount,
+ &CurrentBuffer,
+ &TotalDataLength
+ );
+
+
+ //
+ // See if the packet exceeds NE3200_MAXIMUM_BLOCKS_PER_PACKET.
+ // Keep in mind that if the total virtual packet length is less than
+ // MINIMUM_ETHERNET_PACKET_SIZE then we'll have to chain on an
+ // additional buffer to pad the packet out to the minimum size.
+ //
+ if ( PhysicalBufferCount < NE3200_MAXIMUM_BLOCKS_PER_PACKET ) {
+
+ //
+ // This packet will not need a merge buffer
+ //
+ Reserved->UsedNE3200Buffer = FALSE;
+
+ //
+ // See if we can send it now.
+ //
+ Status = NE3200TransmitPacket(
+ Adapter,
+ Packet,
+ TotalDataLength,
+ NdisBufferCount,
+ CurrentBuffer
+ );
+
+ Adapter->PacketResubmission =
+ (BOOLEAN)(Status == NDIS_STATUS_RESOURCES);
+
+ IF_LOG('S');
+
+ return(Status);
+
+ } else {
+
+ //
+ // We will have to use a merge buffer. Let the processing
+ // below handle this.
+ //
+ if ( (PhysicalBufferCount > NE3200_MAXIMUM_BLOCKS_PER_PACKET) ||
+ (TotalDataLength < MINIMUM_ETHERNET_PACKET_SIZE) ) {
+
+ Reserved->UsedNE3200Buffer = TRUE;
+
+ } else {
+
+ Reserved->UsedNE3200Buffer = FALSE;
+
+ }
+
+ }
+
+ }
+
+ //
+ // Check if we have to merge this packet.
+ //
+ if ( Reserved->UsedNE3200Buffer ) {
+
+ //
+ // Try and send it now.
+ //
+ Status = NE3200TransmitMergedPacket(Adapter, Packet);
+
+ } else {
+
+ //
+ // Determine if and how much adapter space would need to be allocated
+ // to meet hardware constraints.
+ //
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ &NdisBufferCount,
+ &CurrentBuffer,
+ &TotalDataLength
+ );
+
+
+ Status = NE3200TransmitPacket(
+ Adapter,
+ Packet,
+ TotalDataLength,
+ NdisBufferCount,
+ CurrentBuffer);
+
+ }
+
+ //
+ // Save if this packet was rejected due to lack of resources.
+ //
+ Adapter->PacketResubmission = (BOOLEAN)(Status == NDIS_STATUS_RESOURCES);
+
+ IF_LOG('S');
+
+ return(Status);
+}
+
+
+//
+// Put this code inline to save the overhead of the function call.
+//
+#ifdef _X86_
+__inline
+#endif
+
+NDIS_STATUS
+NE3200TransmitPacket(
+ IN PNE3200_ADAPTER Adapter,
+ PNDIS_PACKET FirstPacket,
+ UINT TotalDataLength,
+ UINT NdisBufferCount,
+ PNDIS_BUFFER CurrentBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine attempts to take a packet through a stage of allocation
+ and transmit it.
+
+Arguments:
+
+ Adapter - The adapter that the packets are coming through.
+
+Return Value:
+
+ NDIS_STATUS_RESOURCES - if there are not enough resources
+ NDIS_STATUS_PENDING - if sending.
+
+--*/
+
+{
+ //
+ // If we successfully acquire a command block, this
+ // is a pointer to it.
+ //
+ PNE3200_SUPER_COMMAND_BLOCK CommandBlock;
+
+ //
+ // Pointer to the NE3200 data block descriptor being filled.
+ //
+ PNE3200_DATA_BLOCK DataBlock;
+
+ //
+ // Array to hold the physical segments
+ //
+ NDIS_PHYSICAL_ADDRESS_UNIT PhysicalSegmentArray[NE3200_MAXIMUM_BLOCKS_PER_PACKET];
+
+ //
+ // Number of physical segments in the buffer
+ //
+ UINT BufferPhysicalSegments;
+
+ //
+ // map register to use for this buffer
+ //
+ UINT CurMapRegister;
+
+ //
+ // Iteration variable
+ //
+ UINT i;
+
+ //
+ // We look to see if there is an available Command Block.
+ // If there isn't then stage 3 will close.
+ //
+
+ NE3200AcquireCommandBlock(
+ Adapter,
+ &CommandBlock
+ );
+
+ if (CommandBlock != NULL) {
+
+ //
+ // We have a command block. Assign all packet
+ // buffers to the command block.
+ //
+
+ //
+ // Get a pointer to the the first data block descriptor
+ // in the Command Block.
+ //
+ DataBlock = &CommandBlock->Hardware.TransmitDataBlocks[0];
+
+ //
+ // We record the owning packet information in the ring packet packet
+ // structure.
+ //
+ CommandBlock->OwningPacket = FirstPacket;
+ CommandBlock->UsedNE3200Buffer = FALSE;
+ CommandBlock->NextCommand = NULL;
+
+ //
+ // Initialize the various fields of the Command Block.
+ //
+ CommandBlock->Hardware.State = NE3200_STATE_WAIT_FOR_ADAPTER;
+ CommandBlock->Hardware.Status = 0;
+ CommandBlock->Hardware.NextPending = NE3200_NULL;
+ CommandBlock->Hardware.CommandCode = NE3200_COMMAND_TRANSMIT;
+ CommandBlock->Hardware.PARAMETERS.TRANSMIT.ImmediateDataLength = 0;
+
+ CommandBlock->Hardware.NumberOfDataBlocks = 0;
+ CommandBlock->Hardware.TransmitFrameSize = (USHORT)TotalDataLength;
+
+ //
+ // Set the map registers to use
+ //
+ CurMapRegister = CommandBlock->CommandBlockIndex *
+ NE3200_MAXIMUM_BLOCKS_PER_PACKET;
+
+ //
+ // Go through all of the buffers in the packet getting
+ // the actual physical buffers from each NDIS_BUFFER.
+ //
+ do {
+
+ NdisMStartBufferPhysicalMapping(
+ Adapter->MiniportAdapterHandle,
+ CurrentBuffer,
+ CurMapRegister,
+ TRUE,
+ PhysicalSegmentArray,
+ &BufferPhysicalSegments
+ );
+
+ //
+ // Go to the next map register
+ //
+ CurMapRegister++;
+
+ //
+ // Store segments into command block
+ //
+ for (i = 0; i < BufferPhysicalSegments ; i++, DataBlock++ ) {
+
+ DataBlock->BlockLength = (USHORT)PhysicalSegmentArray[i].Length;
+ DataBlock->PhysicalAddress = NdisGetPhysicalAddressLow(PhysicalSegmentArray[i].PhysicalAddress);
+
+ }
+
+ //
+ // Update the number of fragments.
+ //
+ CommandBlock->Hardware.NumberOfDataBlocks += BufferPhysicalSegments;
+
+ NdisFlushBuffer(CurrentBuffer, TRUE);
+
+ //
+ // Go to the next buffer.
+ //
+ NdisGetNextBuffer(
+ CurrentBuffer,
+ &CurrentBuffer
+ );
+
+ } while (CurrentBuffer != NULL);
+
+ //
+ // If the total packet length is less than MINIMUM_ETHERNET_PACKET_SIZE
+ // then we must chain the Padding buffer onto the end and update
+ // the transfer size.
+ //
+ if (TotalDataLength >= MINIMUM_ETHERNET_PACKET_SIZE) {
+
+ PNE3200_RESERVED_FROM_PACKET(FirstPacket)->CommandBlockIndex =
+ CommandBlock->CommandBlockIndex;
+
+ IF_LOG('x');
+
+ NE3200SubmitCommandBlock(
+ Adapter,
+ CommandBlock
+ );
+
+ return(NDIS_STATUS_PENDING);
+ }
+
+ //
+ // Must do padding
+ //
+ DataBlock->BlockLength =
+ (USHORT)(MINIMUM_ETHERNET_PACKET_SIZE - TotalDataLength);
+
+ DataBlock->PhysicalAddress = NdisGetPhysicalAddressLow(Adapter->PaddingPhysicalAddress);
+
+ DataBlock++;
+ CommandBlock->Hardware.NumberOfDataBlocks++;
+
+ CommandBlock->Hardware.TransmitFrameSize = MINIMUM_ETHERNET_PACKET_SIZE;
+
+ PNE3200_RESERVED_FROM_PACKET(FirstPacket)->CommandBlockIndex =
+ CommandBlock->CommandBlockIndex;
+
+ IF_LOG('x');
+
+ NE3200SubmitCommandBlock(
+ Adapter,
+ CommandBlock
+ );
+
+ return(NDIS_STATUS_PENDING);
+
+ } else {
+
+ //
+ // Not enough resources
+ //
+ return(NDIS_STATUS_RESOURCES);
+
+ }
+
+}
+
+
+NDIS_STATUS
+NE3200TransmitMergedPacket(
+ IN PNE3200_ADAPTER Adapter,
+ PNDIS_PACKET FirstPacket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine attempts to take a packet through a stage of allocation
+ and tranmit it. The packet needs to be merged into a single
+ before transmitting because it contains more fragments than the
+ adapter can handle.
+
+Arguments:
+
+ Adapter - The adapter that the packets are coming through.
+
+Return Value:
+
+ NDIS_STATUS_RESOURCES - if there are not enough resources
+ NDIS_STATUS_PENDING - if sending.
+
+--*/
+
+{
+ //
+ // If we successfully acquire a command block, this
+ // is a pointer to it.
+ //
+ PNE3200_SUPER_COMMAND_BLOCK CommandBlock;
+
+ //
+ // Points to the reserved portion of the packet.
+ //
+ PNE3200_RESERVED Reserved;
+
+ //
+ // Pointer to the NE3200 data block descriptor being filled.
+ //
+ PNE3200_DATA_BLOCK DataBlock;
+
+ //
+ // Points to the adapter buffer descriptor allocated
+ // for this packet.
+ //
+ PNE3200_BUFFER_DESCRIPTOR BufferDescriptor;
+
+ //
+ // Check that we have a merge buffer if one will be necessary.
+ //
+ if ( Adapter->NE3200BufferListHead == -1 ) {
+
+ //
+ // Not enough space for the packet -- save state
+ //
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ //
+ // We look to see if there is an available Command Block.
+ // If there isn't then stage 3 will close.
+ //
+ NE3200AcquireCommandBlock(
+ Adapter,
+ &CommandBlock
+ );
+
+ if (CommandBlock != NULL) {
+
+ //
+ // We have a command block. Assign all packet
+ // buffers to the command block.
+ //
+ Reserved = PNE3200_RESERVED_FROM_PACKET(FirstPacket);
+
+ //
+ // Get a pointer to the the first data block descriptor
+ // in the Command Block.
+ //
+ DataBlock = &CommandBlock->Hardware.TransmitDataBlocks[0];
+
+ //
+ // Now we merge the packet into a buffer
+ //
+ NE3200ConstrainPacket(Adapter, FirstPacket);
+
+ //
+ // We record the owning packet information in the ring packet packet
+ // structure.
+ //
+ CommandBlock->OwningPacket = FirstPacket;
+ CommandBlock->UsedNE3200Buffer = TRUE;
+ CommandBlock->NE3200BuffersIndex = Reserved->NE3200BuffersIndex;
+ CommandBlock->NextCommand = NULL;
+
+ //
+ // Initialize the various fields of the Command Block.
+ //
+ CommandBlock->Hardware.State = NE3200_STATE_WAIT_FOR_ADAPTER;
+ CommandBlock->Hardware.Status = 0;
+ CommandBlock->Hardware.NextPending = NE3200_NULL;
+ CommandBlock->Hardware.CommandCode = NE3200_COMMAND_TRANSMIT;
+ CommandBlock->Hardware.PARAMETERS.TRANSMIT.ImmediateDataLength = 0;
+
+ //
+ // Get the buffer descriptor
+ //
+ BufferDescriptor = Adapter->NE3200Buffers + Reserved->NE3200BuffersIndex;
+
+ //
+ // Since this packet used one of the adapter buffers, the
+ // following is known:
+ //
+ // o There is exactly one physical buffer for this packet.
+ // o The buffer's length is the transmit frame size.
+ //
+
+ //
+ // Set the number of data blocks and the transmit frame size.
+ //
+ NdisFlushBuffer(BufferDescriptor->FlushBuffer, TRUE);
+ CommandBlock->Hardware.NumberOfDataBlocks = 1;
+ CommandBlock->Hardware.TransmitFrameSize =
+ (USHORT)BufferDescriptor->DataLength;
+
+ //
+ // Initialize the (one) data block for this transmit.
+ //
+ DataBlock->BlockLength = (USHORT)BufferDescriptor->DataLength;
+ DataBlock->PhysicalAddress = NdisGetPhysicalAddressLow(BufferDescriptor->PhysicalNE3200Buffer);
+
+ Adapter->TransmitsQueued++;
+
+ Reserved->CommandBlockIndex = CommandBlock->CommandBlockIndex;
+
+ IF_LOG('x');
+
+ //
+ // Start the transmit.
+ //
+ NE3200SubmitCommandBlock(
+ Adapter,
+ CommandBlock
+ );
+
+ return(NDIS_STATUS_PENDING);
+ }
+
+ return(NDIS_STATUS_RESOURCES);
+
+}
+
+STATIC
+VOID
+NE3200ConstrainPacket(
+ IN PNE3200_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ Given a packet and if necessary attempt to acquire adapter
+ buffer resources so that the packet meets NE3200 hardware/MAC.BIN
+ contraints.
+
+ NOTE : MUST BE CALLED WITH NE3200BufferListHead != -1!!
+
+Arguments:
+
+ Adapter - The adapter the packet is coming through.
+
+ Packet - The packet whose buffers are to be constrained.
+ The packet reserved section is filled with information
+ detailing how the packet needs to be adjusted.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Holds the adapter buffer index available for allocation.
+ //
+ INT NE3200BuffersIndex;
+
+ //
+ // Points to a successfully allocated adapter buffer descriptor.
+ //
+ PNE3200_BUFFER_DESCRIPTOR BufferDescriptor;
+
+ //
+ // Will point into the virtual address space addressed
+ // by the adapter buffer if one was successfully allocated.
+ //
+ PCHAR CurrentDestination;
+
+ //
+ // Will hold the total amount of data copied to the
+ // adapter buffer.
+ //
+ UINT TotalDataMoved = 0;
+
+ //
+ // Will point to the current source buffer.
+ //
+ PNDIS_BUFFER SourceBuffer;
+
+ //
+ // Points to the virtual address of the source buffers data.
+ //
+ PVOID SourceData;
+
+ //
+ // The number of ndis buffers in the packet.
+ //
+ UINT NdisBufferCount;
+
+ //
+ // Will point to the number of bytes of data in the source
+ // buffer.
+ //
+ UINT SourceLength;
+
+ //
+ // The total amount of data contained within the ndis packet.
+ //
+ UINT TotalVirtualLength;
+
+ //
+ // Simple iteration variable.
+ //
+ INT i;
+
+ NE3200BuffersIndex = Adapter->NE3200BufferListHead;
+
+ BufferDescriptor = Adapter->NE3200Buffers + NE3200BuffersIndex;
+ Adapter->NE3200BufferListHead = BufferDescriptor->Next;
+
+ //
+ // Fill in the adapter buffer with the data from the users
+ // buffers.
+ //
+ CurrentDestination = BufferDescriptor->VirtualNE3200Buffer;
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ &NdisBufferCount,
+ &SourceBuffer,
+ &TotalVirtualLength
+ );
+
+ NdisQueryBuffer(
+ SourceBuffer,
+ &SourceData,
+ &SourceLength
+ );
+
+ BufferDescriptor->DataLength = TotalVirtualLength;
+
+ for (
+ i = NdisBufferCount;
+ i;
+ i--
+ ) {
+
+ //
+ // Copy this buffer
+ //
+ NE3200_MOVE_MEMORY(
+ CurrentDestination,
+ SourceData,
+ SourceLength
+ );
+
+ //
+ // Update destination address
+ //
+ CurrentDestination = (PCHAR)CurrentDestination + SourceLength;
+
+ //
+ // Update count of packet length.
+ //
+ TotalDataMoved += SourceLength;
+
+ if (i > 1) {
+
+ //
+ // Get the next buffers information
+ //
+ NdisGetNextBuffer(
+ SourceBuffer,
+ &SourceBuffer
+ );
+
+ NdisQueryBuffer(
+ SourceBuffer,
+ &SourceData,
+ &SourceLength
+ );
+
+ }
+
+ }
+
+ //
+ // If the packet is less than the minimum Ethernet
+ // packet size, then clear the remaining part of
+ // the buffer up to the minimum packet size.
+ //
+ if (TotalVirtualLength < MINIMUM_ETHERNET_PACKET_SIZE) {
+
+ NdisZeroMemory(
+ CurrentDestination,
+ MINIMUM_ETHERNET_PACKET_SIZE - TotalVirtualLength
+ );
+
+ }
+
+ //
+ // We need to save in the packet which adapter buffer descriptor
+ // it is using so that we can deallocate it later.
+ //
+ PNE3200_RESERVED_FROM_PACKET(Packet)->NE3200BuffersIndex = NE3200BuffersIndex;
+}
+
diff --git a/private/ntos/ndis/ne3200/sources b/private/ntos/ndis/ne3200/sources
new file mode 100644
index 000000000..a10b25497
--- /dev/null
+++ b/private/ntos/ndis/ne3200/sources
@@ -0,0 +1,51 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=ne3200
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER
+
+NTPROFILEINPUT=yes
+
+INCLUDES=..\..\inc;..\..\..\inc
+
+SOURCES=command.c \
+ interrup.c \
+ ne3200.c \
+ request.c \
+ reset.c \
+ send.c \
+ ne3200.rc
+
+RELATIVE_DEPTH=..\..
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+NTTARGETFILES=ne3200.bin
diff --git a/private/ntos/ndis/netflex.bc/init.c b/private/ntos/ndis/netflex.bc/init.c
new file mode 100644
index 000000000..49527f812
--- /dev/null
+++ b/private/ntos/ndis/netflex.bc/init.c
@@ -0,0 +1 @@
+#include <..\netflex\init.c>
diff --git a/private/ntos/ndis/netflex.bc/initd.c b/private/ntos/ndis/netflex.bc/initd.c
new file mode 100644
index 000000000..269d5b0b2
--- /dev/null
+++ b/private/ntos/ndis/netflex.bc/initd.c
@@ -0,0 +1 @@
+#include <..\netflex\initd.c>
diff --git a/private/ntos/ndis/netflex.bc/int.c b/private/ntos/ndis/netflex.bc/int.c
new file mode 100644
index 000000000..e3ae56d06
--- /dev/null
+++ b/private/ntos/ndis/netflex.bc/int.c
@@ -0,0 +1 @@
+#include <..\netflex\int.c>
diff --git a/private/ntos/ndis/netflex.bc/makefile b/private/ntos/ndis/netflex.bc/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/netflex.bc/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/netflex.bc/netflex.rc b/private/ntos/ndis/netflex.bc/netflex.rc
new file mode 100644
index 000000000..0574267ee
--- /dev/null
+++ b/private/ntos/ndis/netflex.bc/netflex.rc
@@ -0,0 +1 @@
+#include <..\netflex\netflex.rc>
diff --git a/private/ntos/ndis/netflex.bc/netflxbc.prf b/private/ntos/ndis/netflex.bc/netflxbc.prf
new file mode 100644
index 000000000..8ad30ddbb
--- /dev/null
+++ b/private/ntos/ndis/netflex.bc/netflxbc.prf
@@ -0,0 +1,27 @@
+NetFlexDisableInterrupt@4
+NetFlexHandleInterrupt@4
+NetFlexSend@12
+@NetFlexProcessXmit@4
+@NetFlexProcessEthRcv@4
+NetFlexDeferredTimer@16
+NetFlexEnableInterrupt@4
+NetFlexConstrainPacket@24
+NetFlexCheckForHang@4
+NetFlexTransferData@24
+NetFlexInitialize@24
+NetFlexSetupNetType@4
+NetFlexAdapterReset@8
+NetFlexSetInformation@24
+NetFlexQueryInformation@24
+NetFlexDownload@4
+NetFlexOpenAdapter@4
+NetFlexBudWait@4
+NetFlexInitializeAdapter@4
+NetFlexSendNextSCB@4
+NetFlexBoardInitandReg@8
+DriverEntry@8
+NetFlexInitializeAcb@4
+NetFlexInitGlobals@0
+NetFlexGetBIA@4
+NetFlexReadConfigurationParameters@8
+NetFlexRegisterAdapter@20
diff --git a/private/ntos/ndis/netflex.bc/receive.c b/private/ntos/ndis/netflex.bc/receive.c
new file mode 100644
index 000000000..05bb6366b
--- /dev/null
+++ b/private/ntos/ndis/netflex.bc/receive.c
@@ -0,0 +1 @@
+#include <..\netflex\receive.c>
diff --git a/private/ntos/ndis/netflex.bc/request.c b/private/ntos/ndis/netflex.bc/request.c
new file mode 100644
index 000000000..2e01f6d72
--- /dev/null
+++ b/private/ntos/ndis/netflex.bc/request.c
@@ -0,0 +1 @@
+#include <..\netflex\request.c>
diff --git a/private/ntos/ndis/netflex.bc/reset.c b/private/ntos/ndis/netflex.bc/reset.c
new file mode 100644
index 000000000..12b124679
--- /dev/null
+++ b/private/ntos/ndis/netflex.bc/reset.c
@@ -0,0 +1 @@
+#include <..\netflex\reset.c>
diff --git a/private/ntos/ndis/netflex.bc/sources b/private/ntos/ndis/netflex.bc/sources
new file mode 100644
index 000000000..62a9b1dae
--- /dev/null
+++ b/private/ntos/ndis/netflex.bc/sources
@@ -0,0 +1,83 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+ Carol Fuss 13-July-1992 - Converted for the Netflx driver.
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=netflxbc
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+#
+# Standard Dynamic Ratio w/o Xmit Ints
+#
+C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER -DDBGPRINT=0
+
+#
+# Add Xmit Ints
+#
+C_DEFINES=$(C_DEFINES) -DXMIT_INTS
+
+#
+# Add Newer Dynamic Ratio
+#
+C_DEFINES=$(C_DEFINES) -DNEW_DYNAMIC_RATIO
+
+#
+# Add dynamic ratio history.
+#
+#C_DEFINES=$(C_DEFINES) -DDYNAMIC_RATIO_HISTORY
+
+#
+# Turn on dynamic ratio stuff.
+#
+C_DEFINES=$(C_DEFINES) -DALLOW_DISABLE_DYNAMIC_RATIO
+
+#
+# Make it a ndis 40 miniport
+#
+C_DEFINES=$(C_DEFINES) -DNDIS40_MINIPORT
+
+INCLUDES=..\..\inc;..\..\..\inc;..\netflex
+
+LINKER_FLAGS=$(LINKER_FLAGS) /map
+NTPROFILEINPUT=yes
+
+
+SOURCES= init.c \
+ initd.c \
+ int.c \
+ request.c \
+ receive.c \
+ reset.c \
+ support.c \
+ netflex.rc \
+ transmit.c
+
+RELATIVE_DEPTH=..\..
+
+MSC_WARNING_LEVEL=/W3 /WX
diff --git a/private/ntos/ndis/netflex.bc/support.c b/private/ntos/ndis/netflex.bc/support.c
new file mode 100644
index 000000000..206fea2bf
--- /dev/null
+++ b/private/ntos/ndis/netflex.bc/support.c
@@ -0,0 +1 @@
+#include <..\netflex\support.c>
diff --git a/private/ntos/ndis/netflex.bc/transmit.c b/private/ntos/ndis/netflex.bc/transmit.c
new file mode 100644
index 000000000..ca78eab9e
--- /dev/null
+++ b/private/ntos/ndis/netflex.bc/transmit.c
@@ -0,0 +1 @@
+#include <..\netflex\transmit.c>
diff --git a/private/ntos/ndis/netflex/adapter.h b/private/ntos/ndis/netflex/adapter.h
new file mode 100644
index 000000000..956082620
--- /dev/null
+++ b/private/ntos/ndis/netflex/adapter.h
@@ -0,0 +1,137 @@
+/***********************************************************************/
+/***********************************************************************/
+/* */
+/* File Name: ADAPTER.H */
+/* */
+/* Program Name: NetFlex NDIS 3.0 Driver */
+/* */
+/* Companion Files: None */
+/* */
+/* Function: This module contains all the adapter specific data */
+/* structure definitions that are specific to the */
+/* CPQTOK board. */
+/* */
+/* (c) Compaq Computer Corporation, 1992,1993 */
+/* */
+/* This file is licensed by Compaq Computer Corporation to Microsoft */
+/* Corporation pursuant to the letter of August 20, 1992 from */
+/* Gary Stimac to Mark Baber. */
+/* */
+/* History: */
+/* */
+/* 02/24/92 Carol Fuss - Reworked from NDIS driver */
+/* 06/14/93 Cat Abueg - Modified for MAPLE */
+/* 08/09/93 Cat Abueg - Modified for BONSAI */
+/* */
+/***********************************************************************/
+/***********************************************************************/
+
+/*
+ * COMPAQ Token Ring Configuration Register definitions -
+ * These equates define the bit settings in the CPQTOK
+ * adapter's configuration registers.
+ */
+#define CFG_INTS 0xe000 /* Interrupt Level 5, 9 10, 11, 15 */
+#define CFG_INTRIG 0x1000 /* Interrupt Level Trigger */
+#define CFG_MEDIA 0x0800 /* Type 3 Media (else type 1) */
+#define CFG_16MBS 0x0400 /* 16Mbs select (else 4Mbs) */
+#define CFG_RSVD1 0x0300 /* Reserved */
+
+#define CFG_RSVD2 0x00f8 /* Reserved */
+#define CFG_ZERO 0x0006 /* Always zero */
+#define CFG_ENABLE 0x0001 /* Adapter Enable */
+
+/*
+ * The following configuration registers are read as long words during
+ * init time - i.e. 0xc84 and 0xc85, and 0x01b and 0x01c
+ */
+//define CFG_REGISTER 0xc84 /* Configuration register */
+#define CFG_REGISTER 0x4 /* Configuration register */
+ /* Actual value = 0xc85 */
+#define CFG_REGRODAN 0x01b /* Cfg reg for 2nd port of Rodan */
+ /* Actual value = 0x01c */
+
+#define CFG_REG2_OFF 0x01c /* ext cfg reg for 2nd port of Rodan */
+ /* Actual value = 0x01c */
+
+#define COMPAQ_ID 0x110e /* Product Register ID */
+#define CPQTOK_ID 0x0060 /* Cpqtok's board ID */
+#define DURANGO_ID 0x0260 /* Durango's board ID */
+#define NETFLEX_ID 0x0061 /* NETFLEX's board ID */
+#define MAPLE_ID 0x0161 /* Manitu's board ID */
+#define BONSAI_ID 0x0062 /* Bonsai board ID */
+#define RODAN_ID 0x0063 /* Rodan board ID */
+#define NETFLEX_REVMASK 0xf0ff /* Board ID revision mask - MAJ */
+#define NETFLEX_MINMASK 0xff00 /* Board ID revision mask - MIN */
+#define PAGE3_MASK 0xc0000000 /* PCI mask - for < TRIC 5 */
+
+#define CFG_DUALPT_ADP1 0x0800 /* Type of connection for adp 1 */
+#define CFG_DUALPT_ADP2 0x0400 /* Type of connection for adp 2 */
+
+#define CFG_FULL_DUPLEX 0x04 /* Mask For Full Duplex */
+#define CFG_FULL_DUPLEX_HEAD2 0x08 /* Mask For Full Duplex Bonsai H2 */
+
+#define DUALHEAD_CFG_PORT_OFFSET 0x20 /* base port range for dual head z020 - z02e */
+#define CFG_PORT_OFFSET 0xc80 /* adapter configuration ports */
+#define EXTCFG_PORT_OFFSET 0xc63 /* extra adapter configuration ports */
+
+#define NUM_BASE_PORTS 0x20 /* z0000 - z001f */
+#define NUM_CFG_PORTS 0x8 /* z0c80 - z0c87 */
+#define NUM_EXTCFG_PORTS 0x5 /* z0c63 - z0c67 */
+
+#define NUM_DUALHEAD_CFG_PORTS 0x30 /* z000 - z02F */
+
+#define COLL_DETECT_ENABLED 0x8 /* bit 7 = 1 if collision enabled */
+
+#define LOOP_BACK_ENABLE_OFF 0x2 /* added to 0zc63 = 0Zc65 */
+#define LOOP_BACK_STATUS_OFF 0x1 /* added to 0zc63 = 0Zc64 */
+
+#define LOOP_BACK_ENABLE_HEAD1_OFF 0x3 /* added to 0zc63 = 0Zc66 */
+#define LOOP_BACK_STATUS_HEAD1_OFF 0x3 /* added to 0zc63 = 0Zc66 */
+#define LOOP_BACK_ENABLE_HEAD2_OFF 0x4 /* added to 0zc63 = 0Zc67 */
+#define LOOP_BACK_STATUS_HEAD2_OFF 0x4 /* added to 0zc63 = 0Zc67 */
+
+
+#define SWAPL(x) (((ULONG)(x) << 24) | \
+ (((ULONG)(x) >> 24) & 0x000000ff) | \
+ (((ULONG)(x) << 8) & 0x00ff0000) | \
+ (((ULONG)(x) >> 8) & 0x0000ff00))
+
+#define SWAPS(x) (((USHORT)(x) << 8) | (((USHORT)(x) >> 8) & 0x00ff))
+
+#define CTRL_ADDR(x) ((x) | 0x80000000)
+
+#define MAKE_ODD(x) (x |= 0x1000000)
+#define MAKE_EVEN(x) (x &= ~0x1000000)
+
+#define TOKENMTU 4096 /* Token-Ring maximum packet size */
+#define MIN_TPKT 14 /* Minimunm packet size */
+
+#define CMD_ASYNCH 0
+#define CMD_SYNCH 1
+
+#define HARD_RESET 0
+#define SOFT_RESET 1
+
+#define DBM_NOT_SET 0
+#define DBM_RECV_ONLY 1
+#define DBM_XMIT_ONLY 2
+#define DBM_RECV_XMIT 3
+
+#define NETFLEX_INIT_ERROR_CODE ((ULONG) 0x1111)
+#define NETFLEX_RESET_FAILURE_ERROR_CODE ((ULONG) 0x2222)
+#define NETFLEX_ADAPTERCHECK_ERROR_CODE ((ULONG) 0x3333)
+#define NETFLEX_RINGSTATUS_ERROR_CODE ((ULONG) 0x4444)
+
+//
+// Structure Name: Download Structure Definition
+//
+// Description: The Download Structure Definition defines the structure
+// of the code/data to download to the TMS380 chipset.
+//
+typedef struct dl_struct
+ {
+ USHORT dl_chap; /* Section hi address */
+ USHORT dl_addr; /* Section lo address */
+ USHORT dl_bytes; /* Section length in bytes */
+ } DL_STRUCT, *PDL_STRUCT;
diff --git a/private/ntos/ndis/netflex/cpqntssd.ver b/private/ntos/ndis/netflex/cpqntssd.ver
new file mode 100644
index 000000000..efbd41516
--- /dev/null
+++ b/private/ntos/ndis/netflex/cpqntssd.ver
@@ -0,0 +1,68 @@
+/*++
+
+Copyright (c) 1993-1994 Compaq Computer Corporation
+
+
+Module Name:
+
+ CPQNTSSD.VER
+
+
+Abstract:
+
+ This file contains common version information for all device drivers
+ that are modified and released by Compaq. This file should be included
+ in the resource file of all device drivers modified by Compaq and released
+ on the Windows NT SSD or through a SoftPaq. It should be included after
+ the file NTVERP.H but before COMMON.VER.
+
+
+Author:
+
+ Michael E. McGowen
+
+
+Environment:
+
+ Resource Compiler Only
+
+
+Notes:
+
+ This file should only be modified after the initial release by the official
+ NT SSD builder and should be modified with each build.
+
+
+Revision History:
+
+ 1.00 MEM 01/11/94 Initial release.
+ 1.01 AMB 01/12/94 Modified for 1.03.01.001 release
+ 1.02 AMB 01/12/94 Modified for 1.03.01.004 release (P940217)
+ 1.03 AMB 02/22/94 Modified for 1.03.01.005 release (P940222)
+ 1.04 AMB 03/14/94 Modified for 1.04.01.001 release (P940315)
+ 1.05 MDG 03/30/94 Modified for 1.04.01.002 release <P940330>
+ 1.06 MDG 04/07/94 Modified for 1.04.01.003 release <P940407>
+ 1.07 MDG 04/12/94 Modified for 1.04.01.004 release <P940412>
+ 1.08 MDG 04/14/94 Modified for 1.04.01.004 release <P940414>
+
+Datona History:
+
+ 1.10 Beta MDG 04/20/94 Modified for 1.10.01.001 Datona Beta <P940420>
+ 1.10 Beta MDG 04/21/94 Modified for 1.10.01.002 Datona Beta <P940422>
+
+--*/
+
+
+#undef VER_COMPANYNAME_STR
+#define VER_COMPANYNAME_STR "Compaq Computer Corp."
+
+#undef VER_LEGALCOPYRIGHT_YEARS
+#define VER_LEGALCOPYRIGHT_YEARS "1993-1994"
+
+#undef VER_LEGALCOPYRIGHT_STR
+#define VER_LEGALCOPYRIGHT_STR VER_COMPANYNAME_STR " " VER_LEGALCOPYRIGHT_YEARS
+
+#undef VER_PRODUCTNAME_STR
+#define VER_PRODUCTNAME_STR "Compaq Support Software for Microsoft\256 Windows NT(TM)"
+
+ \ No newline at end of file
diff --git a/private/ntos/ndis/netflex/init.c b/private/ntos/ndis/netflex/init.c
new file mode 100644
index 000000000..c5826a1e1
--- /dev/null
+++ b/private/ntos/ndis/netflex/init.c
@@ -0,0 +1,1605 @@
+//**********************************************************************
+//**********************************************************************
+//
+// File Name: INIT.C
+//
+// Program Name: NetFlex NDIS 3.0 Miniport Driver
+//
+// Companion Files: None
+//
+// Function: This module contains the NetFlex Miniport Driver
+// interface routines called by the Wrapper and the
+// configuration manager.
+//
+// (c) Compaq Computer Corporation, 1992,1993,1994
+//
+// This file is licensed by Compaq Computer Corporation to Microsoft
+// Corporation pursuant to the letter of August 20, 1992 from
+// Gary Stimac to Mark Baber.
+//
+// History:
+//
+// 04/15/94 Robert Van Cleve - Converted from NDIS Mac Driver
+//
+//**********************************************************************
+//**********************************************************************
+
+
+//-------------------------------------
+// Include all general companion files
+//-------------------------------------
+
+#include <ndis.h>
+#include "tmsstrct.h"
+#include "macstrct.h"
+#include "adapter.h"
+#include "protos.h"
+
+//-----------------
+// Variables
+//-----------------
+
+MAC macgbls = {0};
+USHORT gbl_addingdualport = 0;
+USHORT gbl_portnumbertoadd = 0;
+
+USHORT RxIntRatio = 1;
+#ifdef XMIT_INTS
+USHORT TxIntRatio = 1;
+#endif
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: DriverEntry
+//
+// Description: This routine is the initialization entry
+// point into the driver. In this routine,
+// the driver registers itself with the wrapper
+// and initializes the global variables for the
+// driver.
+//
+// Input: DriverObject Pointer to the driver object
+// assigned to the MAC driver.
+//
+// Output: Returns NDIS_STATUS_SUCCESS for a successful
+// completion and returns an error code if an
+// error is encountered.
+//
+// Called_By: OS
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+#pragma NDIS_INIT_FUNCTION(DriverEntry)
+NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath)
+
+{
+ NDIS_STATUS Status;
+
+ //
+ // The characteristics table
+ //
+ NDIS_MINIPORT_CHARACTERISTICS NetFlexChar;
+
+ DebugPrint(1,("NetFlex: Dynamic Ratio Version\n"));
+
+#ifdef XMIT_INTS
+ DebugPrint(1,("NetFlex: with Transmit Interrupts\n"));
+#endif
+
+ //
+ // Indicate that we are in initialization mode.
+ //
+ macgbls.Initializing = TRUE;
+
+ //
+ // Initialize the Wrapper
+ //
+ NdisMInitializeWrapper(
+ &macgbls.mac_wrapper,
+ DriverObject,
+ RegistryPath,
+ NULL);
+
+ //
+ // Store the driver object. We will need this for Unloading
+ // the driver.
+
+ macgbls.mac_object = DriverObject;
+
+ //
+ // Initialize the Miniport characteristics for the call to
+ // NdisMRegisterMiniport.
+ //
+ NetFlexChar.MajorNdisVersion = NETFLEX_MAJ_VER;
+ NetFlexChar.MinorNdisVersion = NETFLEX_MIN_VER;
+ NetFlexChar.CheckForHangHandler = NetFlexCheckForHang;
+ NetFlexChar.DisableInterruptHandler = NetFlexDisableInterrupt;
+ NetFlexChar.EnableInterruptHandler = NetFlexEnableInterrupt;
+ NetFlexChar.HaltHandler = NetFlexHalt;
+ NetFlexChar.HandleInterruptHandler = NetFlexHandleInterrupt;
+ NetFlexChar.InitializeHandler = NetFlexInitialize;
+ NetFlexChar.ISRHandler = NetFlexISR;
+ NetFlexChar.QueryInformationHandler = NetFlexQueryInformation;
+ NetFlexChar.ReconfigureHandler = NULL;
+ NetFlexChar.ResetHandler = NetFlexResetDispatch;
+ NetFlexChar.SendHandler = NetFlexSend;
+ NetFlexChar.SetInformationHandler = NetFlexSetInformation;
+ NetFlexChar.TransferDataHandler = NetFlexTransferData;
+ NetFlexChar.ReturnPacketHandler = NULL;
+ NetFlexChar.SendPacketsHandler = NULL;
+ NetFlexChar.AllocateCompleteHandler = NULL;
+
+ //
+ // Register this driver with NDIS
+ //
+ Status = NdisMRegisterMiniport( macgbls.mac_wrapper,
+ &NetFlexChar,
+ sizeof(NetFlexChar) );
+
+ //
+ // Set to non-initializing mode
+ //
+ macgbls.Initializing = FALSE;
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // We can only get here if something went wrong with registering
+ // the driver or *ALL* of the adapters.
+ //
+ if ((macgbls.mac_adapters == NULL) &&
+ (macgbls.mac_wrapper != NULL))
+ {
+ NdisTerminateWrapper(macgbls.mac_wrapper, NULL);
+ }
+ return STATUS_UNSUCCESSFUL;
+}
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexInitialize
+//
+// Description: See NDIS 3.0 Miniport spec.
+// Called to initialize each adapter
+//
+// Input: See NDIS 3.0 Miniport spec.
+//
+// Output: NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING
+//
+// Called_By: NDIS Miniport Wrapper
+//
+//----------------------------------------------------------------
+NDIS_STATUS
+NetFlexInitialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+
+{
+ NDIS_STATUS status;
+ PACB acb = NULL;
+ PACB FirstHeadsAcb = NULL;
+ USHORT baseaddr;
+ UINT slot,i;
+ NDIS_STRING portnumber = NDIS_STRING_CONST("PortNumber");
+ NDIS_HANDLE ConfigHandle = NULL;
+
+ NDIS_EISA_FUNCTION_INFORMATION EisaData;
+ PNDIS_CONFIGURATION_PARAMETER cfgp;
+
+ DebugPrint(2,("NetFlex: NetFlexInitialize\n"));
+
+ //
+ // Make sure we still have the wrapper, this is needed if an adapter
+ // fails to open and there isn't any already opened, the halt routine
+ // will remove the wrapper, and thus all adapters fail. I don't know
+ // if this means that I should remove the code from the halt routine
+ // or if I need to come up with aditional logic...
+ //
+ if (macgbls.mac_wrapper == NULL)
+ {
+ DebugPrint(0,("NetFlex: Don't have a handle to the Wrapper!\n"));
+ status = NDIS_STATUS_FAILURE;
+ goto ConfigError;
+ }
+
+ //
+ // Check if we have a configuration handle before proceeding.
+ //
+ if (ConfigurationHandle == NULL)
+ {
+ DebugPrint(0,("NetFlex: Adapter not set up properly - no config handle\n"));
+ status = NDIS_STATUS_FAILURE;
+ goto ConfigError;
+ }
+
+ //
+ // Open the configuration handle
+ //
+ NdisOpenConfiguration( &status,
+ &ConfigHandle,
+ ConfigurationHandle );
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ DebugPrint(0,("NetFlex: Adapter not set up properly - couldn't open config\n"));
+ status = NDIS_STATUS_FAILURE;
+ ConfigHandle = NULL;
+ goto ConfigError;
+ }
+
+ //
+ // Find out what slot number the adapter associated with
+ // this name is in.
+ //
+ NdisReadEisaSlotInformation( &status,
+ ConfigurationHandle,
+ &slot,
+ &EisaData );
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ DebugPrint(0,("NetFlex: Slot number not set up\n"));
+ status = NDIS_ERROR_CODE_ADAPTER_NOT_FOUND;
+ goto ConfigError;
+ }
+
+ baseaddr = slot * 0x1000;
+
+ NdisReadConfiguration( &status,
+ &cfgp,
+ ConfigHandle,
+ &portnumber,
+ NdisParameterInteger);
+
+ //
+ // If we didn't read a portnumber, that means we're adding a
+ // non-dual port card - NETFLX, MAPLE, CPQTOK
+ //
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ gbl_portnumbertoadd = 0;
+ gbl_addingdualport = FALSE;
+ }
+ else
+ {
+ gbl_portnumbertoadd = (USHORT)cfgp->ParameterData.IntegerData;
+ if (gbl_portnumbertoadd == PORT0)
+ gbl_addingdualport = FALSE;
+ else
+ gbl_addingdualport = TRUE;
+ }
+
+ //
+ // See if this adapter has been added. If so return an error.
+ // The very first time we are called, acb should be NULL.
+ //
+
+ if (macgbls.DownloadCode == NULL)
+ {
+ // On Initial Init, We need to get the global stuff...
+ //
+ status = NetFlexInitGlobals();
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ goto ConfigError;
+ }
+ }
+ else
+ {
+ acb = macgbls.mac_adapters;
+
+ while (acb)
+ {
+ if ( acb->acb_baseaddr == baseaddr)
+ {
+ //
+ // If the card has the same slot and we're adding a dual port
+ // then go to the next acb, otherwise it is an error.
+ //
+ if ( gbl_addingdualport )
+ {
+ FirstHeadsAcb = acb;
+ acb = acb->acb_next;
+ }
+ else
+ {
+ DebugPrint(0,("NetFlex: Adapter already added\n"));
+ status = NDIS_STATUS_FAILURE;
+ goto ConfigError;
+ }
+ }
+ else
+ {
+ acb = acb->acb_next;
+ }
+ }
+ }
+
+ //
+ // Allocate adapter control block and register adapter.
+ //
+
+ status = NetFlexRegisterAdapter( &acb,
+ FirstHeadsAcb,
+ ConfigHandle,
+ baseaddr,
+ MiniportAdapterHandle
+ );
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ goto ConfigError;
+ }
+
+
+ //
+ // Search for the medium type supported matches adapter configuration
+ //
+
+ for (i = 0; i < MediumArraySize; i++)
+ {
+ if (MediumArray[i] == acb->acb_gen_objs.media_type_in_use)
+ {
+ *SelectedMediumIndex = i;
+ break;
+ }
+ }
+
+ //
+ // If supported medium not found. Return an error.
+ //
+ if (i == MediumArraySize)
+ {
+ DebugPrint(0,("NetFlex: No supported media found!\n"));
+ status = NDIS_STATUS_UNSUPPORTED_MEDIA;
+ goto ConfigError;
+ }
+
+ //
+ // Now, initialize the board and the data structures.
+ // glb_ErrorCode will be set if there was an error.
+ //
+ status = NetFlexBoardInitandReg(acb,&EisaData);
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ DebugPrint(0,("NF(%d): Board Init and Reg Failed\n",acb->anum));
+ goto ConfigError;
+ }
+
+ConfigError:
+
+ //
+ // Were there any errors?
+ //
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // if we allocated an acb, we need to get rid of it...
+ //
+ if (acb != NULL)
+ {
+ //
+ // Since there was an acb, the error data and section code will be in
+ // the acb instead of the globals.
+ //
+ NetFlexDeregisterAdapter(acb);
+ }
+
+ DebugPrint(0, ("NF: NetFlexInitialize Failed!\n"));
+ }
+
+ if (ConfigHandle != NULL)
+ {
+ NdisCloseConfiguration(ConfigHandle);
+ }
+ return status;
+}
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexRegisterAdapter
+//
+// Description: This routine allocates memory for the adapter
+// control block and registers with the wrapper.
+//
+// Input: acbp - pointer to adapter control block
+//
+//
+// Output: Returns NDIS_STATUS_SUCCESS for a successful
+// completion. Otherwise, an error code is
+// returned.
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+NDIS_STATUS
+NetFlexRegisterAdapter(
+ PACB *acbp,
+ PACB FirstHeadsAcb,
+ NDIS_HANDLE ConfigHandle,
+ USHORT baseaddr,
+ NDIS_HANDLE MiniportAdapterHandle
+ )
+{
+ PACB acb;
+ USHORT cpqid, boardid, reg_value;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ //
+ // Allocate the Memory for the adapter's acb.
+ //
+ NdisAllocateMemory( (PVOID *)&acb,
+ (UINT) (sizeof (ACB)),
+ (UINT) 0,
+ NetFlexHighestAddress );
+ //
+ // If we did not get the memory, flag any error.
+ //
+ if (acb == NULL)
+ {
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ //
+ // Zero out the memory. Save configuration handle.
+ //
+ NdisZeroMemory(acb, sizeof (ACB));
+ acb->acb_state = AS_REGISTERING;
+ acb->acb_baseaddr = baseaddr;
+
+ //
+ // Indicate that we are initializing the adapter.
+ //
+ acb->AdapterInitializing = TRUE;
+
+ //
+ // link in this acb
+ //
+ *acbp = acb;
+ macgbls.mac_numadpts++;
+#if (DBG || DBGPRINT)
+ acb->anum = macgbls.mac_numadpts;
+#endif
+
+ //
+ // save reference to our Miniport Handle
+ //
+ acb->acb_handle = MiniportAdapterHandle;
+
+ //
+ // Initialize reset timer
+ //
+ NdisMInitializeTimer(
+ &acb->ResetTimer,
+ acb->acb_handle,
+ (PVOID) NetFlexResetHandler,
+ (PVOID) acb );
+
+ //
+ // Initialize DPC timer
+ //
+ NdisMInitializeTimer(
+ &acb->DpcTimer,
+ acb->acb_handle,
+ (PVOID) NetFlexDeferredTimer,
+ (PVOID) acb );
+
+ //
+ // Set the attributes for this adapter
+ //
+ NdisMSetAttributes( MiniportAdapterHandle,
+ (NDIS_HANDLE) acb,
+ TRUE,
+ NdisInterfaceEisa );
+
+ //
+ // Register our shutdown handler.
+ //
+
+ NdisMRegisterAdapterShutdownHandler(
+ MiniportAdapterHandle, // wrapper miniport handle.
+ acb, // shutdown context.
+ NetFlexShutdown // shutdown handler.
+ );
+
+ //
+ // Reserve this adapters IO ports, if they haven't allready been added by the first
+ // head...
+ //
+
+ if (gbl_addingdualport)
+ {
+ if (FirstHeadsAcb == NULL)
+ {
+ // This is the first instance of a head on a dual port board,
+ // so register all the io ports for both heads.
+
+ acb->FirstHeadsAcb = acb;
+
+ //
+ // grab ports z000 - z02f
+ //
+ Status = NdisMRegisterIoPortRange( (PVOID *)&acb->BasePorts,
+ MiniportAdapterHandle,
+ baseaddr,
+ NUM_DUALHEAD_CFG_PORTS );
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ // Save the master base port addresses
+ //
+ acb->MasterBasePorts = acb->BasePorts;
+
+ // grab zc80 - zc85
+ //
+ Status = NdisMRegisterIoPortRange( (PVOID *)&acb->ConfigPorts,
+ MiniportAdapterHandle,
+ baseaddr + CFG_PORT_OFFSET,
+ NUM_CFG_PORTS );
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ // grab zc63 - zc67
+ //
+ Status = NdisMRegisterIoPortRange( (PVOID *)&acb->ExtConfigPorts,
+ MiniportAdapterHandle,
+ baseaddr + EXTCFG_PORT_OFFSET,
+ NUM_EXTCFG_PORTS );
+ }
+ }
+ }
+ else
+ {
+ // Get the pointers to the other head's ports, which are already mapped.
+ //
+ acb->FirstHeadsAcb = FirstHeadsAcb;
+ acb->BasePorts = FirstHeadsAcb->MasterBasePorts;
+ acb->ConfigPorts = FirstHeadsAcb->ConfigPorts;
+ acb->ExtConfigPorts = FirstHeadsAcb->ExtConfigPorts;
+ acb->MasterBasePorts= FirstHeadsAcb->MasterBasePorts;
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ }
+ else
+ {
+ // grab ports z000 - z01f
+ //
+ Status = NdisMRegisterIoPortRange( (PVOID *)&acb->BasePorts,
+ MiniportAdapterHandle,
+ baseaddr,
+ NUM_BASE_PORTS );
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ // grab zc80 - zc85
+ //
+ Status = NdisMRegisterIoPortRange( (PVOID *)&acb->ConfigPorts,
+ MiniportAdapterHandle,
+ baseaddr + CFG_PORT_OFFSET,
+ NUM_CFG_PORTS );
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ // grab zc63 - zc67
+ //
+ Status = NdisMRegisterIoPortRange( (PVOID *)&acb->ExtConfigPorts,
+ MiniportAdapterHandle,
+ baseaddr + EXTCFG_PORT_OFFSET,
+ NUM_EXTCFG_PORTS );
+ }
+ }
+ }
+
+ //
+ // If the registration fails, free up the memory we allocated
+ // for the acb.
+ //
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DebugPrint(0,("NF: Registration FAILED for slot#%d\n",(baseaddr / 1000)));
+ goto HandleRegisterError;
+ }
+
+ //
+ // Read in the company product id.
+ //
+ NdisRawReadPortUshort( acb->ConfigPorts, (PUSHORT) &cpqid);
+ //
+ // Read in the board product id.
+ //
+ NdisRawReadPortUshort( acb->ConfigPorts + 2, (PUSHORT) &boardid);
+ //
+ // Does it have a Compaq id?
+ //
+ // NETFLEX_ID covers NetFlex and NetFlex-2
+ // CPQTOK_ID covers DualSpeed and 16/4 Token-Ring
+
+ if ( !( (cpqid == COMPAQ_ID) &&
+ ( ((boardid & NETFLEX_REVMASK) == NETFLEX_ID) ||
+ ((boardid & NETFLEX_REVMASK) == CPQTOK_ID) ||
+ ((boardid & NETFLEX_REVMASK) == RODAN_ID) ||
+ ((boardid & NETFLEX_REVMASK) == BONSAI_ID)
+ ) ) )
+ {
+ //
+ // Not a Compaq id.
+ //
+ DebugPrint(0,("NF(%d): No Compaq adapter found\n",acb->anum));
+ Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+ goto HandleRegisterError;
+ }
+
+ //
+ // Make sure this is our board.
+ //
+ NdisRawReadPortUshort( acb->ConfigPorts + CFG_REGISTER, &reg_value);
+
+ if (!(reg_value & CFG_ENABLE))
+ {
+ DebugPrint(0,("NF(%d): Adapter is not enabled\n",acb->anum));
+ DebugPrint(0,("NF(%d): Board Test Failed\n",acb->anum));
+ Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+ goto HandleRegisterError;
+ }
+
+ //
+ // Check to see if it's a card with FPA or a dual port adapter
+ //
+
+ if ( (boardid == MAPLE_ID) ||
+ (boardid == DURANGO_ID) )
+ {
+ DebugPrint(1,("NF(%d): We're adding a card using FPA ! \n",acb->anum));
+ acb->acb_usefpa = TRUE;
+ }
+ else if ( ((boardid & NETFLEX_REVMASK) == BONSAI_ID) ||
+ ((boardid & NETFLEX_REVMASK) == RODAN_ID ) )
+ {
+ acb->acb_usefpa = TRUE;
+ acb->acb_dualport = TRUE;
+ acb->acb_portnumber = gbl_portnumbertoadd;
+ DebugPrint(1,("NF(%d): We're adding BONSAI or RODAN port #%d\n",acb->anum,acb->acb_portnumber));
+ }
+
+ //
+ // Set up the Config register location and the extended sif address
+ // register location.
+ //
+ acb->AdapterConfigPort = acb->ConfigPorts + CFG_REGISTER;
+
+ if (acb->acb_dualport && (acb->acb_portnumber == PORT2) )
+ {
+ //
+ // Align the ports right for the head #2's ports
+ //
+ acb->BasePorts = acb->FirstHeadsAcb->BasePorts + DUALHEAD_CFG_PORT_OFFSET;
+
+ if ((boardid & NETFLEX_REVMASK) == RODAN_ID)
+ {
+ acb->AdapterConfigPort = acb->MasterBasePorts + CFG_REGRODAN;
+ }
+ }
+
+ acb->SifDataPort = acb->BasePorts + SIF_DATA_OFF; /* SIF data register */
+ acb->SifDIncPort = acb->BasePorts + SIF_DINC_OFF; /* SIF data autoincrment reg */
+ acb->SifAddrPort = acb->BasePorts + SIF_ADDR_OFF; /* SIF address register */
+ acb->SifIntPort = acb->BasePorts + SIF_INT_OFF; /* SIF interrupt register */
+ acb->SifActlPort = acb->BasePorts + SIF_ACTL_OFF; /* SIF ACTL register */
+ acb->SifAddrxPort = acb->BasePorts + SIF_ACTL_EXT_OFF;/* SIF SIF extended address reg */
+
+ //
+ // Save the Board ID
+ //
+ acb->acb_boardid = boardid;
+
+ //
+ // Do a reset to the adapter
+ //
+ NdisRawWritePortUshort(acb->SifActlPort, 0xEE);
+
+ //
+ // Wait 15 milliseconds to let the reset take place.
+ //
+ NdisStallExecution((UINT)15000); // Wait 15 milliseconds
+
+ //
+ // Get the Network type and speed from the eisa config info.
+ //
+ NetFlexSetupNetType(acb);
+
+ //
+ // Read configuration parameters from the registry if there are any
+ //
+
+ Status = NetFlexReadConfigurationParameters(acb,ConfigHandle);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DebugPrint(0,("NF(%d): NetFlexReadConfigurationParameters Failed\n",acb->anum));
+ Status = NDIS_STATUS_RESOURCES;
+ goto HandleRegisterError;
+ }
+
+HandleRegisterError:
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ if (acb!=NULL)
+ {
+ if (acb->acb_parms != NULL)
+ {
+ NdisFreeMemory( (PVOID) acb->acb_parms, (UINT) sizeof(PNETFLEX_PARMS), (UINT) 0);
+ }
+ *acbp = NULL;
+ NdisFreeMemory( (PVOID) acb, (UINT) sizeof(ACB), (UINT) 0);
+ }
+ }
+
+ return(Status);
+}
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexReadConfigurationParameters
+//
+// Description: This routine reads configuration parameters
+// set by the user in the registry if exist.
+//
+// Input: acb - Adapter Context
+// ConfigHandle
+//
+// Output: Returns NDIS_STATUS_SUCCESS for a successful
+// completion. Otherwise, an error code is
+// returned.
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+NDIS_STATUS
+NetFlexReadConfigurationParameters(
+ PACB acb,
+ NDIS_HANDLE ConfigHandle
+ )
+
+{
+ NDIS_STATUS status;
+ PNETFLEX_PARMS pParms = NULL;
+ ULONG length;
+ PVOID NetworkAddress;
+ BOOLEAN WriteError;
+ PNDIS_CONFIGURATION_PARAMETER cfgp;
+
+ ULONG netspeed = acb->acb_gen_objs.link_speed;
+
+ NDIS_STRING maxreceives = NDIS_STRING_CONST("MAXRECEIVES");
+ NDIS_STRING productid = NDIS_STRING_CONST("PRODUCTID");
+ NDIS_STRING earlyrelease = NDIS_STRING_CONST("EARLYRELEASE");
+ NDIS_STRING maxtransmits = NDIS_STRING_CONST("MAXTRANSMITS");
+ NDIS_STRING maxframesz = NDIS_STRING_CONST("MAXFRAMESIZE");
+ NDIS_STRING maxmulticast = NDIS_STRING_CONST("MAXMULTICAST");
+ NDIS_STRING maxinternalreqs = NDIS_STRING_CONST("MAXINTERNALREQS");
+ NDIS_STRING maxinternalbufs = NDIS_STRING_CONST("MAXINTERNALBUFS");
+ NDIS_STRING maxtxbuf = NDIS_STRING_CONST("MAXTXBUF");
+ NDIS_STRING mintxbuf = NDIS_STRING_CONST("MINTXBUF");
+ NDIS_STRING extremecheckforhang = NDIS_STRING_CONST("ExtremeCheckForHang");
+
+#ifdef XMIT_INTS
+ NDIS_STRING xmitintratio = NDIS_STRING_CONST("TXINTRATIO");
+#endif
+ NDIS_STRING rcvintratio = NDIS_STRING_CONST("RXINTRATIO");
+
+ //
+ // Allocate the Memory for the adapter's parms structure.
+ //
+ NdisAllocateMemory( (PVOID *)&pParms,
+ (UINT) (sizeof (NETFLEX_PARMS)),
+ (UINT) 0,
+ NetFlexHighestAddress );
+ //
+ // If we did not get the memory, flag any error.
+ //
+ if (pParms == NULL)
+ {
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ NdisMoveMemory(pParms, &NetFlex_Defaults, sizeof(NETFLEX_PARMS));
+
+
+ //
+ // See if the user has specified the maximum number of internal
+ // transmit buffers
+ //
+ NdisReadConfiguration( &status,
+ &cfgp,
+ ConfigHandle,
+ &maxinternalbufs,
+ NdisParameterInteger);
+
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ if ( (cfgp->ParameterData.IntegerData <= MAX_INTERNALBUFS) &&
+ (cfgp->ParameterData.IntegerData >= MIN_INTERNALBUFS) )
+ {
+ pParms->utd_maxinternalbufs = (USHORT)cfgp->ParameterData.IntegerData;
+ }
+ else
+ {
+ // The parameter is out of range.
+ DebugPrint(0,("NF(%d): MAXINTERNALBUFS parameter is out of range, using default\n",acb->anum));
+ NdisWriteErrorLogEntry( acb->acb_handle,
+ EVENT_NDIS_MAXINTERNALBUFS_ERROR,
+ 2,
+ (ULONG)cfgp->ParameterData.IntegerData,
+ (ULONG)pParms->utd_maxinternalbufs);
+ }
+ }
+
+ //
+ // Read the network specific information from the registry
+ //
+ if (acb->acb_gen_objs.media_type_in_use == NdisMedium802_5)
+ {
+ // TokenRing
+ //
+ //
+ // See if early token release has been selected.
+ //
+ if (netspeed == 16)
+ {
+ // Default to early token release.
+ //
+ pParms->utd_open.OPEN_Options |= SWAPS(OOPTS_ETR);
+
+ NdisReadConfiguration( &status,
+ &cfgp,
+ ConfigHandle,
+ &earlyrelease,
+ NdisParameterInteger );
+
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ if ( cfgp->ParameterData.IntegerData == 0)
+ {
+ // The user does not want early token release.
+ //
+ pParms->utd_open.OPEN_Options &= SWAPS((~OOPTS_ETR));
+ }
+ }
+ }
+
+ //
+ // Set the framehold bit so that we can allow promiscuous mode
+ // to be set later on. We don't necessarily have to set
+ // promiscuous mode but if we do, this is a requirement.
+ //
+ pParms->utd_open.OPEN_Options |= SWAPS(OOPTS_FHOLD);
+
+ //
+ // Set MaxTransmits
+ //
+ pParms->utd_numsmallbufs = pParms->utd_maxtrans = DF_XMITS_TR;
+ //
+ // See if the user has specified the maximum number of transmit
+ // lists supported.
+ //
+
+ NdisReadConfiguration( &status,
+ &cfgp,
+ ConfigHandle,
+ &maxtransmits,
+ NdisParameterInteger);
+
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ if ( (cfgp->ParameterData.IntegerData <= MAX_XMITS_TR) &&
+ (cfgp->ParameterData.IntegerData >= MIN_XMITS) )
+ {
+ pParms->utd_numsmallbufs = pParms->utd_maxtrans = (USHORT)cfgp->ParameterData.IntegerData;
+ }
+ else
+ {
+ // The parameter is out of range.
+ DebugPrint(0,("NF(%d): MAXTRANSMITS parameter is out of range, using default\n",acb->anum));
+ NdisWriteErrorLogEntry( acb->acb_handle,
+ EVENT_NDIS_MAXTRANSMITS_ERROR,
+ 2,
+ (ULONG)cfgp->ParameterData.IntegerData,
+ (ULONG)pParms->utd_maxtrans);
+ }
+ }
+
+ //
+ // See if the user has specified the maximum frame size.
+ //
+ pParms->utd_maxframesz = DF_FRAMESIZE_TR;
+ WriteError = FALSE;
+ NdisReadConfiguration( &status,
+ &cfgp,
+ ConfigHandle,
+ &maxframesz,
+ NdisParameterInteger);
+
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ if (cfgp->ParameterData.IntegerData < MIN_FRAMESIZE)
+ {
+ pParms->utd_maxframesz = MIN_FRAMESIZE;
+ WriteError = TRUE;
+ }
+ else if (netspeed == 16)
+ {
+ // 16 Mb
+ //
+ if (cfgp->ParameterData.IntegerData > MAX_FRAMESIZE_TR16)
+ {
+ pParms->utd_maxframesz = MAX_FRAMESIZE_TR16;
+ WriteError = TRUE;
+ }
+ else
+ {
+ pParms->utd_maxframesz = (USHORT)cfgp->ParameterData.IntegerData;
+ }
+ }
+ //
+ // 4Mb
+ //
+ else if (cfgp->ParameterData.IntegerData > MAX_FRAMESIZE_TR4)
+ {
+ pParms->utd_maxframesz = MAX_FRAMESIZE_TR4;
+ WriteError = TRUE;
+ }
+ else
+ {
+ pParms->utd_maxframesz = (USHORT)cfgp->ParameterData.IntegerData;
+ }
+
+ if (WriteError)
+ {
+ // The parameter is out of range.
+ NdisWriteErrorLogEntry( acb->acb_handle,
+ EVENT_NDIS_MAXFRAMESIZE_ERROR,
+ 2,
+ (ULONG)cfgp->ParameterData.IntegerData,
+ (ULONG)pParms->utd_maxframesz);
+
+ DebugPrint(0,("NF(%d): MaxFrameSize parameter is out of range, using default\n",acb->anum));
+ }
+ }
+
+ //
+ // See if the user has specified the maximum number of Receive
+ // lists supported.
+ //
+ pParms->utd_maxrcvs = DF_RCVS_TR;
+
+ NdisReadConfiguration( &status,
+ &cfgp,
+ ConfigHandle,
+ &maxreceives,
+ NdisParameterInteger);
+
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ if ( (cfgp->ParameterData.IntegerData <= MAX_RCVS_TR) &&
+ (cfgp->ParameterData.IntegerData >= MIN_RCVS) )
+ {
+ pParms->utd_maxrcvs = (USHORT)cfgp->ParameterData.IntegerData;
+ }
+ else
+ {
+ // The parameter is out of range.
+ NdisWriteErrorLogEntry( acb->acb_handle,
+ EVENT_NDIS_MAXRECEIVES_ERROR,
+ 2,
+ (ULONG)cfgp->ParameterData.IntegerData,
+ (ULONG)pParms->utd_maxrcvs);
+
+ DebugPrint(0,("NF(%d): MAXReceives parameter is out of range, using default\n",acb->anum));
+ }
+ }
+
+ //
+ // Adjust Number of Lists based on size of Max TR Frame Size
+ //
+ //
+ // For every frame size which is greater than a multiple of 4096,
+ // decrease number of transmits, Receives, and internal buffers.
+ //
+ if (pParms->utd_maxframesz > DF_FRAMESIZE_TR)
+ {
+ if (pParms->utd_maxframesz < ( (DF_FRAMESIZE_TR*2)+2) )
+ {
+ pParms->utd_maxtrans = MAX_XMITS_TR-2; /* 6 xmits, 30 mapregs */
+ pParms->utd_maxrcvs = MAX_XMITS_TR-2;
+ pParms->utd_maxinternalbufs = pParms->utd_maxtrans / 2;
+ }
+ else
+ {
+ pParms->utd_maxtrans = MAX_XMITS_TR-4; /* 4 xmits, 25 mapregs */
+ pParms->utd_maxrcvs = MAX_XMITS_TR-4;
+ pParms->utd_maxinternalbufs = pParms->utd_maxtrans / 2;
+ }
+ }
+
+ }
+ else
+ {
+ // Ethernet
+ //
+ //
+ // Set the framehold bit so that we can allow promiscuous mode
+ // to be set later on. We don't necessarily have to set
+ // promiscuous mode but if we do, this is a requirement.
+ //
+ pParms->utd_open.OPEN_Options |= SWAPS(OOPTS_REQ + OOPTS_FHOLD);
+ pParms->utd_maxframesz = DF_FRAMESIZE_ETH;
+
+ //
+ // See if the user has specified the maximum number of multicast
+ // addresses supported.
+ //
+
+ pParms->utd_maxmulticast = DF_MULTICASTS;
+
+ NdisReadConfiguration( &status,
+ &cfgp,
+ ConfigHandle,
+ &maxmulticast,
+ NdisParameterInteger);
+
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ if ( (cfgp->ParameterData.IntegerData <= MAX_MULTICASTS) &&
+ (cfgp->ParameterData.IntegerData >= MIN_MULTICASTS) )
+ {
+ pParms->utd_maxmulticast = (USHORT)cfgp->ParameterData.IntegerData;
+ }
+ else
+ {
+ // The parameter is out of range.
+ DebugPrint(0,("NF(%d): MAXMULTICAST Parameter is out of range, using default\n",acb->anum));
+ NdisWriteErrorLogEntry( acb->acb_handle,
+ EVENT_NDIS_MAXMULTICAST_ERROR,
+ 2,
+ (ULONG)cfgp->ParameterData.IntegerData,
+ (ULONG)pParms->utd_maxmulticast);
+ }
+ }
+
+ //
+ // See if the user has specified the maximum number of transmit lists.
+ //
+
+ pParms->utd_numsmallbufs = pParms->utd_maxtrans = DF_XMITS_ETH;
+
+ NdisReadConfiguration( &status,
+ &cfgp,
+ ConfigHandle,
+ &maxtransmits,
+ NdisParameterInteger);
+
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ if ( (cfgp->ParameterData.IntegerData <= MAX_XMITS_ETH) &&
+ (cfgp->ParameterData.IntegerData >= MIN_XMITS) )
+ {
+ pParms->utd_numsmallbufs = pParms->utd_maxtrans = (USHORT)cfgp->ParameterData.IntegerData;
+ }
+ else
+ {
+ // The parameter is out of range.
+ DebugPrint(0,("NF(%d): MAXTRANSMITS parameter is out of range, using default\n",acb->anum));
+ NdisWriteErrorLogEntry( acb->acb_handle,
+ EVENT_NDIS_MAXTRANSMITS_ERROR,
+ 2,
+ (ULONG)cfgp->ParameterData.IntegerData,
+ (ULONG)pParms->utd_maxtrans);
+ }
+ }
+
+ //
+ // See if the user has specified the maximum frame size.
+ //
+ WriteError = FALSE;
+ pParms->utd_maxframesz = MAX_FRAMESIZE_ETH;
+
+ NdisReadConfiguration( &status,
+ &cfgp,
+ ConfigHandle,
+ &maxframesz,
+ NdisParameterInteger);
+
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ if (cfgp->ParameterData.IntegerData < MIN_FRAMESIZE)
+ {
+ pParms->utd_maxframesz = MIN_FRAMESIZE;
+ WriteError = TRUE;
+ }
+ else if (cfgp->ParameterData.IntegerData > MAX_FRAMESIZE_ETH)
+ {
+ pParms->utd_maxframesz = MAX_FRAMESIZE_ETH;
+ WriteError = TRUE;
+ }
+ else
+ {
+ pParms->utd_maxframesz = (USHORT)cfgp->ParameterData.IntegerData;
+ }
+
+ if (WriteError)
+ {
+ // The parameter is out of range.
+ NdisWriteErrorLogEntry( acb->acb_handle,
+ EVENT_NDIS_MAXFRAMESIZE_ERROR,
+ 2,
+ (ULONG)cfgp->ParameterData.IntegerData,
+ (ULONG)pParms->utd_maxframesz);
+
+ DebugPrint(0,("NF(%d): MaxFrameSize parameter is out of range, using default\n",acb->anum));
+ }
+ }
+
+ //
+ // See if the user has specified the maximum number of Receive
+ // lists supported.
+ //
+
+ pParms->utd_maxrcvs = DF_RCVS_ETH;
+
+ NdisReadConfiguration( &status,
+ &cfgp,
+ ConfigHandle,
+ &maxreceives,
+ NdisParameterInteger);
+
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ if ( (cfgp->ParameterData.IntegerData <= MAX_RCVS_ETH) &&
+ (cfgp->ParameterData.IntegerData >= MIN_RCVS) )
+ {
+ pParms->utd_maxrcvs = (USHORT)cfgp->ParameterData.IntegerData;
+ }
+ else
+ {
+ // The parameter is out of range.
+ NdisWriteErrorLogEntry( acb->acb_handle,
+ EVENT_NDIS_MAXRECEIVES_ERROR,
+ (ULONG)cfgp->ParameterData.IntegerData,
+ (ULONG)pParms->utd_maxrcvs);
+ DebugPrint(0,("NF(%d): MAXReceives parameter is out of range, using default\n",acb->anum));
+ }
+ }
+ }
+
+ DebugPrint(1,("NF(%d): MaxFrameSize = %d\n",acb->anum,pParms->utd_maxframesz));
+ DebugPrint(1,("NF(%d): MaxTransmits = %d\n",acb->anum,pParms->utd_maxtrans));
+ DebugPrint(1,("NF(%d): MaxReceives = %d\n",acb->anum,pParms->utd_maxrcvs));
+
+ //
+ // Common Configuration settings for both Ethernet and TokenRing
+ //
+
+ //
+ // See if the user has specified extreme checking for adapter hang.
+ //
+ NdisReadConfiguration(&status,
+ &cfgp,
+ ConfigHandle,
+ &extremecheckforhang,
+ NdisParameterInteger);
+ if ((NDIS_STATUS_SUCCESS == status) &&
+ (cfgp->ParameterData.IntegerData != 0))
+ {
+ //
+ // They want the extreme checking to see if this adapter is
+ // hung.
+ //
+ pParms->utd_extremecheckforhang = TRUE;
+ }
+
+ //
+ // See if the user has specified the maximum number of adapter transmit buffers.
+ //
+ NdisReadConfiguration( &status,
+ &cfgp,
+ ConfigHandle,
+ &maxtxbuf,
+ NdisParameterInteger);
+
+ //
+ // Set default Transmist_Buffer_Maximum_Count based on the max frame size * 2 tx lists
+ //
+
+ pParms->utd_open.OPEN_Xbufmax = ((pParms->utd_maxframesz / 1024) + 1 ) * 2;
+
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ // Make Sure the value doesn't preclude us from transmiting a max frame size
+ //
+ if (cfgp->ParameterData.IntegerData > (UINT) (pParms->utd_maxframesz / 1024))
+ {
+ pParms->utd_open.OPEN_Xbufmax = (UCHAR)cfgp->ParameterData.IntegerData;
+ }
+ else
+ {
+ // The parameter is out of range.
+ DebugPrint(0,("NF(%d): MaxTXBuf parameter is out of range, using default\n",acb->anum));
+ }
+ }
+
+ DebugPrint(1,("NF(%d): MaxTXBuf = 0x%x\n",acb->anum,pParms->utd_open.OPEN_Xbufmax));
+
+ //
+ // See if the user has specified the minimum number of adapter transmit buffers.
+ //
+ NdisReadConfiguration( &status,
+ &cfgp,
+ ConfigHandle,
+ &mintxbuf,
+ NdisParameterInteger);
+
+ //
+ // Set default Transmist_Buffer_Minimum_Count based on the max
+ //
+ pParms->utd_open.OPEN_Xbufmin = pParms->utd_open.OPEN_Xbufmax;
+
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+
+ if ((cfgp->ParameterData.IntegerData >= 0) &&
+ (cfgp->ParameterData.IntegerData <= pParms->utd_open.OPEN_Xbufmax) )
+ {
+ pParms->utd_open.OPEN_Xbufmin = (UCHAR)cfgp->ParameterData.IntegerData;
+ }
+ else
+ {
+ // The parameter is out of range.
+ DebugPrint(0,("NF(%d): MinTXBuf parameter is out of range, using default\n",acb->anum));
+ }
+ }
+
+ DebugPrint(1,("NF(%d): MinTXBuf = 0x%x\n",acb->anum,pParms->utd_open.OPEN_Xbufmin));
+
+
+ //
+ // See if the user has specified the maximum number of internal
+ // requests supported.
+ //
+ NdisReadConfiguration( &status,
+ &cfgp,
+ ConfigHandle,
+ &maxinternalreqs,
+ NdisParameterInteger);
+
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ if ( (cfgp->ParameterData.IntegerData <= MAX_INTERNALREQS) &&
+ (cfgp->ParameterData.IntegerData >= MIN_INTERNALREQS) )
+ {
+ pParms->utd_maxinternalreqs = (USHORT)cfgp->ParameterData.IntegerData;
+ }
+ else
+ {
+ // The parameter is out of range.
+ DebugPrint(0,("NF(%d): MAXINTERNALREQS parameter is out of range, using default\n",acb->anum));
+ }
+ }
+
+ //
+ // See if the user has specified the node address
+ //
+ NdisReadNetworkAddress( &status,
+ &NetworkAddress,
+ &length,
+ ConfigHandle );
+
+ if ((length == NET_ADDR_SIZE) && (status == NDIS_STATUS_SUCCESS))
+ {
+ NdisMoveMemory((PUCHAR)pParms->utd_open.OPEN_NodeAddr,
+ (PUCHAR)NetworkAddress,
+ NET_ADDR_SIZE);
+ }
+ else
+ {
+ DebugPrint(1,("NF(%d): Error in NdisReadNetworkAddress or none specified\n",acb->anum));
+ }
+
+ //
+ // See if the user has specified the product id
+ //
+ NdisReadConfiguration( &status,
+ &cfgp,
+ ConfigHandle,
+ &productid,NdisParameterString );
+
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ status = NetFlexAsciiToHex( &(cfgp->ParameterData.StringData),
+ (PUCHAR)pParms->utd_open.OPEN_ProdID,
+ (USHORT)(18) );
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ // The parameter is out of range.
+ DebugPrint(1,("NF(%d): PRODUCTID parameter is invalid, using default\n",acb->anum));
+ NdisWriteErrorLogEntry( acb->acb_handle,
+ EVENT_NDIS_PRODUCTID_ERROR,
+ 0);
+ }
+ }
+
+ //
+ // See if we need to open in Full Duplex
+ //
+ if (acb->FullDuplexEnabled)
+ {
+ //
+ // Allocate the xmit spin lock.
+ //
+ NdisAllocateSpinLock(&acb->XmitLock);
+
+ pParms->utd_open.OPEN_Options |= SWAPS(OOPTS_FULLDUP);
+ }
+
+ acb->acb_parms = pParms;
+
+#ifdef XMIT_INTS
+ //
+ // See if the user has specified the xmit_int_ratio
+ //
+
+ acb->XmitIntRatio = TxIntRatio;
+
+ NdisReadConfiguration( &status,
+ &cfgp,
+ ConfigHandle,
+ &xmitintratio,
+ NdisParameterInteger);
+
+ if (status == NDIS_STATUS_SUCCESS) {
+ acb->XmitIntRatio = (USHORT)cfgp->ParameterData.IntegerData;
+ }
+ DebugPrint(1,("NF(%d): TxIntRatio = 1:%d\n",acb->anum,acb->XmitIntRatio));
+#endif
+
+ //
+ // See if the user has specified the rcv_int_ratio
+ //
+
+ acb->RcvIntRatio = RxIntRatio;
+
+ NdisReadConfiguration( &status,
+ &cfgp,
+ ConfigHandle,
+ &rcvintratio,
+ NdisParameterInteger);
+
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ acb->RcvIntRatio = (USHORT)cfgp->ParameterData.IntegerData;
+ }
+ DebugPrint(1,("NF(%d): Rx Int Ratio = 1:%d\n",acb->anum,acb->RcvIntRatio));
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexBoardInitandReg
+//
+// Description: This routine initiailizes the board, downloads
+// the mac code, and registers the adapter with
+// the wrapper.
+//
+// Input: acbp - Pointer to an acb ptr.
+// pParms - Settable parameters
+//
+// Output: acbp - Pointer to allocated acb
+// Returns NDIS_STATUS_SUCCESS for a successful
+// completion. Otherwise, an error code is
+// returned.
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+NDIS_STATUS
+NetFlexBoardInitandReg(
+ PACB acb,
+ PNDIS_EISA_FUNCTION_INFORMATION EisaData
+ )
+{
+ UINT int_vector;
+ NDIS_INTERRUPT_MODE int_mode;
+ NDIS_STATUS status;
+ UINT i=0;
+
+ //
+ // Initialize the fields of the acb.
+ //
+ if ((status = NetFlexInitializeAcb(acb)) != NDIS_STATUS_SUCCESS)
+ {
+ // Failed, get out now...
+ //
+ return status;
+ }
+
+ //
+ // Get EISA Config Data so we can set the interrupt data
+ //
+ int_vector = EisaData->EisaIrq[0].ConfigurationByte.Interrupt;
+
+ if (!int_vector)
+ {
+ return NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION;
+ }
+
+ if (gbl_addingdualport)
+ {
+ // Dualport boards share the same interupt between heads
+ //
+ acb->InterruptsShared = TRUE;
+ }
+ else
+ {
+ acb->InterruptsShared = EisaData->EisaIrq[0].ConfigurationByte.Shared;
+ }
+
+ int_mode = EisaData->EisaIrq[0].ConfigurationByte.LevelTriggered ? NdisInterruptLevelSensitive : NdisInterruptLatched;
+
+ //
+ // Add this acb to the global list
+ //
+ acb->acb_next = macgbls.mac_adapters;
+ macgbls.mac_adapters = acb;
+
+ //
+ // Initialize the interrupt.
+ //
+ status = NdisMRegisterInterrupt( &acb->acb_interrupt,
+ acb->acb_handle,
+ int_vector,
+ int_vector,
+ FALSE, // TRUE,
+ acb->InterruptsShared,
+ int_mode );
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ DebugPrint(0,("NF(%d): Initialization of the Interrupt FAILED\n",acb->anum));
+
+ NetFlexDequeue_OnePtrQ( (PVOID *)&macgbls.mac_adapters,
+ (PVOID)acb);
+
+ return status;
+ }
+
+ //
+ // Ok, we're set, so reset the adapter and open'er up!
+ // Try three times...
+ //
+ do
+ {
+ status = NetFlexAdapterReset(acb,HARD_RESET);
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Send the Open Command
+ //
+ status = NetFlexOpenAdapter(acb);
+ }
+
+ } while ((++i < 3) && (status != NDIS_STATUS_SUCCESS));
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ // Something failed, so get out.
+ //
+ return status;
+ }
+
+ //
+ // Get the Burned In Address
+ //
+
+ NetFlexGetBIA(acb);
+
+ //
+ // Set the Default DPC timer
+ //
+
+ NdisMSetTimer(&acb->DpcTimer, 10);
+
+ //
+ // Indidicate that we're done with initializing this adapter.
+ //
+ acb->AdapterInitializing = FALSE;
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexInitGlobals
+//
+// Description: This routine initializes the global
+// variables and downloads the mac download
+// code into our map buffer area.
+//
+// Input: None.
+//
+// Output: Status = SUCCESS .
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+NDIS_STATUS
+NetFlexInitGlobals(
+ )
+{
+ NDIS_STRING maccode = NDIS_STRING_CONST("NETFLX.BIN");
+ UINT length;
+ NDIS_STATUS status;
+ PUSHORT MappedBuffer;
+ NDIS_HANDLE mac_filehandle;
+
+ //
+ // Open the file containing the MAC download code.
+ //
+ NdisOpenFile( &status,
+ &mac_filehandle,
+ &length,
+ &maccode,
+ NetFlexHighestAddress);
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ DebugPrint(0,("NF: Download file could not be opened\n"));
+ return status;
+ }
+
+ //
+ // Allocate the buffer.
+ //
+ NdisAllocateMemory( (PVOID *)&macgbls.DownloadCode,
+ length,
+ FALSE,
+ NetFlexHighestAddress);
+
+ if (macgbls.DownloadCode == NULL)
+ {
+ status = NDIS_STATUS_FAILURE;
+ }
+ else
+ {
+ // Store the length
+ //
+ macgbls.DownloadLength = length;
+ //
+ // Get a mapping to the opened download file.
+ //
+ NdisMapFile( &status,
+ (PVOID *)&MappedBuffer,
+ mac_filehandle);
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ DebugPrint(0,("NF: Download file could not be mapped\n"));
+ }
+ else
+ {
+ // Copy the download code into the shared memory space
+ //
+ NdisMoveMemory(macgbls.DownloadCode,MappedBuffer,length);
+ NdisUnmapFile(mac_filehandle);
+ }
+
+ //
+ // Done with the file
+ NdisCloseFile(mac_filehandle);
+ }
+
+ return status;
+}
diff --git a/private/ntos/ndis/netflex/initd.c b/private/ntos/ndis/netflex/initd.c
new file mode 100644
index 000000000..f05ebb41f
--- /dev/null
+++ b/private/ntos/ndis/netflex/initd.c
@@ -0,0 +1,230 @@
+//**********************************************************************
+//**********************************************************************
+//
+// File Name: INITD.C
+//
+// Program Name: NetFlex NDIS 3.0 Miniport Driver
+//
+// Companion Files: None
+//
+// Function: This module contains the NetFlex Miniport Driver
+// interface routines called by the Wrapper and the
+// configuration manager.
+//
+// (c) Compaq Computer Corporation, 1992,1993,1994
+//
+// This file is licensed by Compaq Computer Corporation to Microsoft
+// Corporation pursuant to the letter of August 20, 1992 from
+// Gary Stimac to Mark Baber.
+//
+// History:
+//
+// 04/15/94 Robert Van Cleve - Converted from NDIS Mac Driver
+//
+//**********************************************************************
+//**********************************************************************
+
+//-------------------------------------
+// Include all general companion files
+//-------------------------------------
+
+#include <ndis.h>
+#include "tmsstrct.h"
+#include "macstrct.h"
+#include "adapter.h"
+#include "protos.h"
+
+
+INIT init_mask =
+{
+ 0x9f00,
+ { 0, 0, 0, 0, 0, 0 },
+ 0,
+ 0,
+ 0x0505
+};
+
+
+NETFLEX_PARMS NetFlex_Defaults =
+{
+ { 0, // Options
+ { 0, 0, 0, 0, 0, 0 }, // Node Address
+ { 0, 0, 0, 0}, // Group Address
+ { 0, 0, 0, 0}, // Functional Address
+ 0x0e00, // Receive list size
+ SWAPS(SIZE_XMIT_LIST), // Transmit list size w/ NUM_BUFS_PER_LIST frags
+ 0x0004, // Buffer size 1 k
+ 0x0000, // Ram start
+ 0xffff, // Ram end
+ 0xc, // Xmit buf min (4k/1k)*2
+ 0xc, // Xmit buf max
+ (char *) NetFlex_Defaults.utd_open.OPEN_ProdID,
+ { 0x09, 0x10,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0 }
+ },
+ DF_XMITS_TR,
+ DF_RCVS_TR,
+ DF_FRAMESIZE_TR,
+ DF_MULTICASTS,
+ DF_INTERNALREQS,
+ DF_INTERNALBUFS,
+ DF_XMITS_TR,
+ 256,
+ 0
+};
+// USHORT utd_numsmallbufs;
+// USHORT utd_smallbufsz;
+
+
+NDIS_OID NetFlexGlobalOIDs_Eth[] =
+{
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+ OID_GEN_RCV_CRC_ERROR,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ OID_802_3_RCV_ERROR_ALIGNMENT,
+ OID_802_3_XMIT_ONE_COLLISION,
+ OID_802_3_XMIT_MORE_COLLISIONS,
+ OID_802_3_XMIT_DEFERRED,
+ OID_802_3_XMIT_LATE_COLLISIONS,
+ OID_802_3_XMIT_MAX_COLLISIONS,
+ OID_802_3_XMIT_TIMES_CRS_LOST,
+ OID_NF_INTERRUPT_COUNT,
+ OID_NF_INTERRUPT_RATIO,
+ OID_NF_INTERRUPT_RATIO_CHANGES
+};
+SHORT NetFlexGlobalOIDs_Eth_size = sizeof (NetFlexGlobalOIDs_Eth);
+
+
+NDIS_OID NetFlexNetworkOIDs_Eth[] =
+{
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_MAC_OPTIONS,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE
+};
+SHORT NetFlexNetworkOIDs_Eth_size = sizeof(NetFlexNetworkOIDs_Eth);
+
+NDIS_OID NetFlexGlobalOIDs_Tr[] =
+{
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+ OID_802_5_PERMANENT_ADDRESS,
+ OID_802_5_CURRENT_ADDRESS,
+ OID_802_5_UPSTREAM_ADDRESS,
+ OID_802_5_CURRENT_FUNCTIONAL,
+ OID_802_5_CURRENT_GROUP,
+ OID_802_5_LAST_OPEN_STATUS,
+ OID_802_5_CURRENT_RING_STATUS,
+ OID_802_5_CURRENT_RING_STATE,
+ OID_802_5_LINE_ERRORS,
+ OID_802_5_LOST_FRAMES,
+ OID_802_5_BURST_ERRORS,
+ OID_802_5_AC_ERRORS,
+ OID_802_5_CONGESTION_ERRORS,
+ OID_802_5_FRAME_COPIED_ERRORS,
+ OID_802_5_TOKEN_ERRORS
+};
+SHORT NetFlexGlobalOIDs_Tr_size = sizeof(NetFlexGlobalOIDs_Tr);
+
+NDIS_OID NetFlexNetworkOIDs_Tr[] =
+{
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_MAC_OPTIONS,
+ OID_802_5_PERMANENT_ADDRESS,
+ OID_802_5_CURRENT_ADDRESS,
+ OID_802_5_UPSTREAM_ADDRESS,
+ OID_802_5_CURRENT_FUNCTIONAL,
+ OID_802_5_CURRENT_GROUP
+};
+SHORT NetFlexNetworkOIDs_Tr_size = sizeof(NetFlexNetworkOIDs_Tr);
+
+//
+// Make a 64-bit Ndis_Physical_Address value for the highest acceptable
+// Physical address allowable. The -1 means that it does not matter.
+//
+NDIS_PHYSICAL_ADDRESS NetFlexHighestAddress = NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
diff --git a/private/ntos/ndis/netflex/int.c b/private/ntos/ndis/netflex/int.c
new file mode 100644
index 000000000..64571a328
--- /dev/null
+++ b/private/ntos/ndis/netflex/int.c
@@ -0,0 +1,977 @@
+
+//**********************************************************************
+//**********************************************************************
+//
+// File Name: INT.C
+//
+// Program Name: NetFlex NDIS 3.0 Miniport Driver
+//
+// Companion Files: None
+//
+// Function: This module contains the NetFlex Miniport Driver
+// interface routines called by the Wrapper and the
+// configuration manager.
+//
+// (c) Compaq Computer Corporation, 1992,1993,1994
+//
+// This file is licensed by Compaq Computer Corporation to Microsoft
+// Corporation pursuant to the letter of August 20, 1992 from
+// Gary Stimac to Mark Baber.
+//
+// History:
+//
+// 04/15/94 Robert Van Cleve - Converted from NDIS Mac Driver
+//
+//
+//
+//***********************************************************************
+
+
+/*-------------------------------------*/
+/* Include all general companion files */
+/*-------------------------------------*/
+
+#include <ndis.h>
+#include "tmsstrct.h"
+#include "macstrct.h"
+#include "adapter.h"
+#include "protos.h"
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexISR
+//
+// Description:
+// This routine is the ISR for this Netflx mac driver.
+// This routine determines if the interrupt is for it
+// and if so, it clears the system interrupt bit of
+// the sifint register.
+//
+// Input:
+// Context - Our Driver Context for this adapter or head.
+//
+// Output:
+// Returns TRUE if the interrupt belongs to the
+// adapter and returns FALSE if it does not
+// belong to the adapter.
+//
+// Called By:
+// Miniport Wrapper
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+VOID NetFlexISR(
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueDpc,
+ IN PVOID Context )
+{
+ PACB acb;
+ USHORT sifint_reg;
+ USHORT actl_reg;
+
+ acb = (PACB) Context;
+
+ //
+ // Read the Sifint register.
+ //
+ NdisRawReadPortUshort( acb->SifIntPort, &sifint_reg);
+
+ //
+ // See if the System Interrupt bit is set. If it is, this is an
+ // interrupt for us.
+ //
+ if (sifint_reg & SIFINT_SYSINT)
+ {
+ //
+ // Acknowledge and Clear Int
+ //
+ if (!acb->InterruptsDisabled)
+ {
+ actl_reg = acb->actl_reg & ~ACTL_SINTEN;
+ NdisRawWritePortUshort(acb->SifActlPort, actl_reg);
+ DebugPrint(3,("NF(%d)(D)\n",acb->anum));
+ acb->InterruptsDisabled = TRUE;
+
+ //
+ // Return that we recognize it
+ //
+ *InterruptRecognized = TRUE;
+ *QueueDpc = TRUE;
+ }
+ else
+ {
+ //
+ // It appears that a second head is generating
+ // the interrupt, and we have a DPC queued to
+ // process our int, return that we don't recognize it
+ // so that the oterh head's isr gets called...
+ //
+ *InterruptRecognized = FALSE;
+ *QueueDpc = FALSE;
+ }
+ }
+ else
+ {
+ // Return that we don't recognize it
+ //
+ *InterruptRecognized = FALSE;
+ *QueueDpc = FALSE;
+ }
+}
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexDeferredTimer
+//
+// Description:
+// This routine is called every 10ms to check to see
+// if there is any receives or transmits which need
+// to be cleaned up since we don't require an interrupt
+// for each frame.
+//
+// Input:
+// acb - Our Driver Context for this adapter or head.
+//
+// Output:
+// None.
+//
+// Called By:
+// Miniport Wrapper via acb->DpcTimer
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+
+#ifdef NEW_DYNAMIC_RATIO
+UINT MaxIntRatio = 4;
+
+//
+// New Threshold for xmit disabled case.
+//
+UINT RaiseIntThreshold = 26;
+
+//
+// Run threshold of 1.5 seconds instead of 200msecs.
+//
+UINT RunThreshold = 15;
+UINT RatioCheckCount = 10;
+#else
+
+UINT sw24 = 220;
+UINT sw21 = 40;
+#endif
+
+#ifdef ALLOW_DISABLE_DYNAMIC_RATIO
+BOOLEAN EnableDynamicRatio = TRUE;
+UINT ratio = 1;
+#endif
+
+VOID NetFlexDeferredTimer(
+ IN PVOID SystemSpecific1,
+ IN PACB acb,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+)
+{
+ USHORT ReceivesProcessed = 0;
+ USHORT sifint_reg;
+ UINT IntAve;
+
+ //
+ // Indicate that a timer has expired.
+ //
+ DebugPrint(3,("NF(%d) - Defered Timer Expired!\n",acb->anum));
+
+ //
+ // If we are resetting, get out...
+ //
+ if (acb->acb_state == AS_RESETTING)
+ {
+ return;
+ }
+
+ //
+ // See if there are any recieves to do...
+ //
+
+ if (acb->acb_rcv_head->RCV_CSTAT & RCSTAT_COMPLETE)
+ {
+ //
+ // Increment the interrupt count.
+ //
+ acb->acb_int_count++;
+
+ // yes, do them...
+ //
+ ReceivesProcessed = acb->ProcessReceiveHandler(acb);
+ }
+
+ //
+ // See if there are any transmits to do...
+ //
+ NetFlexProcessXmit(acb);
+
+ //
+ // Processed any receives which need IndicateReceiveComplete?
+ //
+ if (ReceivesProcessed)
+ {
+ if (acb->acb_gen_objs.media_type_in_use == NdisMedium802_5)
+ {
+ // Token Ring
+ //
+ NdisMTrIndicateReceiveComplete(acb->acb_handle);
+ }
+ else
+ {
+ // Ethernet
+ //
+ NdisMEthIndicateReceiveComplete(acb->acb_handle);
+ }
+ }
+
+
+ if ( ++acb->timer_run_count >= RatioCheckCount )
+ {
+ acb->timer_run_count = 0;
+
+#ifdef ALLOW_DISABLE_DYNAMIC_RATIO
+ if ( EnableDynamicRatio )
+ {
+#endif
+
+#ifdef NEW_DYNAMIC_RATIO
+
+ //
+ // Should we increase the ratio?
+ //
+ if ( acb->handled_interrupts > RaiseIntThreshold)
+ {
+ acb->current_run_down = 0;
+ if (acb->XmitIntRatio == 1)
+ {
+ if ( ++acb->current_run_up > RunThreshold )
+ {
+#ifdef XMIT_INTS
+ acb->XmitIntRatio = acb->acb_maxtrans;
+#endif
+ acb->acb_gen_objs.interrupt_ratio_changes++;
+ acb->current_run_up = 0;
+ DebugPrint(1,("NF(%d) - RcvIntRatio = %d\n",acb->anum,acb->RcvIntRatio));
+ }
+ }
+ }
+ //
+ // Or, should we decrease it?
+ //
+ else //if ( acb->handled_interrupts < LowerIntThreshold )
+ {
+ acb->current_run_up = 0;
+ if (acb->XmitIntRatio != 1)
+
+ {
+ if ( ++acb->current_run_down > RunThreshold )
+ {
+
+#ifdef XMIT_INTS
+ acb->XmitIntRatio = 1;
+#endif
+ acb->acb_gen_objs.interrupt_ratio_changes++;
+ acb->current_run_down = 0;
+ DebugPrint(1,("NF(%d) - RcvIntRatio = %d\n",acb->anum,acb->RcvIntRatio));
+ }
+ }
+ }
+
+#else // !defined(NEW_DYNAMIC_RATIO)
+
+ if ( acb->XmitIntRatio != 1 )
+ {
+ if ( acb->handled_interrupts < sw21 )
+ {
+ if ( ++acb->current_run > RunThreshold )
+ {
+
+#ifdef XMIT_INTS
+ acb->XmitIntRatio = 1;
+#endif
+ acb->RcvIntRatio = 1;
+ acb->acb_gen_objs.interrupt_ratio_changes++;
+ acb->current_run = 0;
+ acb->sw24 += 3;
+
+ acb->cleartime = 0;
+ }
+ }
+ else
+ {
+ acb->current_run = 0;
+ }
+ }
+ else
+ {
+ if ( acb->handled_interrupts > sw24 )
+ {
+ if ( ++acb->current_run > RunThreshold )
+ {
+
+#ifdef XMIT_INTS
+ acb->XmitIntRatio = ratio;
+#endif
+ acb->RcvIntRatio = ratio;
+ acb->acb_gen_objs.interrupt_ratio_changes++;
+ acb->current_run = 0;
+ }
+ }
+ else
+ {
+ acb->current_run = 0;
+ }
+ }
+
+#ifdef DYNAMIC_RATIO_HISTORY
+ acb->IntHistory[acb->Hndx] = acb->handled_interrupts;
+ acb->RatioHistory[acb->Hndx] = (UCHAR)acb->RcvIntRatio;
+
+ if ( ++acb->Hndx >= 1024 )
+ {
+ acb->Hndx = 0;
+ }
+#endif
+ //
+ // The switchover value to turbo gets incremented each time
+ // we drop to normal mode. We reset this value every x seconds.
+ // This will prevent the driver from toggling rapidly between
+ // turbo <-> normal mode.
+ //
+ if ( ++acb->cleartime > 50 )
+ {
+ acb->sw24 = sw24;
+ acb->cleartime = 0;
+ }
+
+#endif // !NEW_DYNAMIC_RATIO
+
+#ifdef ALLOW_DISABLE_DYNAMIC_RATIO
+ }
+ else
+ {
+
+#ifdef XMIT_INTS
+ acb->XmitIntRatio = ratio;
+#endif
+ acb->RcvIntRatio = ratio;
+ }
+#endif // ALLOW_DISABLE_DYNAMIC_RATIO
+
+ acb->acb_gen_objs.interrupt_count = acb->handled_interrupts;
+ acb->handled_interrupts = 0;
+ }
+
+ //
+ // Set the timer...
+ //
+ NdisMSetTimer(&acb->DpcTimer, 10);
+
+} // NetFlexDeferredTimer
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexHandleInterrupt
+//
+// Description:
+// This routine is the deferred processing
+// routine for all adapter interrupts.
+//
+// Input:
+// acb - Our Driver Context for this adapter or head.
+//
+// Output:
+// None
+//
+// Called By:
+// Miniport Wrapper
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+VOID
+NetFlexHandleInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+{
+ USHORT sifint_reg;
+ USHORT tmp_reg;
+ USHORT ReceivesProcessed = 0;
+
+ PACB acb = (PACB) MiniportAdapterContext;
+
+ //
+ // Read the SifInt
+ //
+ NdisRawReadPortUshort( acb->SifIntPort, &sifint_reg);
+
+ while (sifint_reg & SIFINT_SYSINT)
+ {
+ //
+ // Ack the interrupt
+ //
+ sifint_reg &= ~SIFINT_SYSINT;
+ NdisRawWritePortUshort( acb->SifIntPort, sifint_reg);
+
+ //
+ // mask off the int code
+ //
+ sifint_reg &= INT_CODES;
+
+ //
+ // See if there are any recieves to do...
+ //
+ if (acb->acb_rcv_head->RCV_CSTAT & RCSTAT_COMPLETE)
+ {
+ //
+ // Increment the interrupt count.
+ //
+ acb->acb_int_count++;
+
+ //
+ // yes, do them...
+ //
+ acb->handled_interrupts++;
+ ReceivesProcessed += acb->ProcessReceiveHandler(acb);
+ }
+
+ //
+ // See if there are any transmits to do...
+ //
+ NetFlexProcessXmit(acb);
+
+ switch (sifint_reg)
+ {
+ case INT_SCBCLEAR:
+ acb->acb_scbclearout = FALSE;
+ //
+ // Is the SCB really clear?
+ //
+ // If the SCB is clear, send a SCB command off now.
+ // Otherwise, if we are not currently waiting for an SCB clear
+ // interrupt, signal the adapter to send us a SCB clear interrupt
+ // when it is done with the SCB.
+ //
+ if (acb->acb_scb_virtptr->SCB_Cmd == 0)
+ {
+ NetFlexSendNextSCB(acb);
+ }
+ else if ((acb->acb_xmit_whead) ||
+ (acb->acb_rcv_whead) ||
+ (acb->acb_scbreq_next))
+ {
+ acb->acb_scbclearout = TRUE;
+ NdisRawWritePortUshort(
+ acb->SifIntPort,
+ (USHORT)SIFINT_SCBREQST);
+ }
+ break;
+
+ case INT_COMMAND:
+ NetFlexCommand(acb);
+
+ //
+ // Do we have any commands to complete?
+ //
+ if (acb->acb_confirm_qhead != NULL)
+ {
+ NetFlexProcessMacReq(acb);
+ }
+ break;
+
+ case INT_ADPCHECK:
+ //
+ // Read the Adapter Check Status @ 1.05e0
+ //
+ NdisRawWritePortUshort(acb->SifAddrxPort, (USHORT) 1);
+ NdisRawWritePortUshort(acb->SifAddrPort, (USHORT) 0x5e0);
+ NdisRawReadPortUshort( acb->SifDIncPort, &tmp_reg);
+
+ DebugPrint(1,("NF(%d): Adapter Check - 0x%x\n",acb->anum,tmp_reg));
+
+ //
+ // Reset has failed, errorlog an entry.
+ //
+
+ NdisWriteErrorLogEntry( acb->acb_handle,
+ EVENT_NDIS_ADAPTER_CHECK_ERROR,
+ 2,
+ NETFLEX_ADAPTERCHECK_ERROR_CODE,
+ tmp_reg );
+
+ //
+ // Set the variables up showing that the hardware has an unrecoverable
+ // error.
+ //
+ acb->acb_state = AS_HARDERROR;
+ break;
+
+ case INT_RINGSTAT:
+ NetFlexRingStatus(acb);
+ break;
+
+ case INT_RECEIVE:
+ break;
+
+ case INT_TRANSMIT:
+ //
+ // If we reached the end of the xmit lists,
+ // then the xmit status will indicate COMMAND_COMPLETE.
+ // The transmiter will be stalled until another transmit
+ // command is issued with a valid list.
+ //
+ if (acb->acb_ssb_virtptr->SSB_Status & XSTAT_LERROR)
+ {
+ //
+ // We have a list error...
+ //
+ NetFlexTransmitStatus(acb);
+ }
+
+ default:
+ break;
+ }
+
+ //
+ // Issue a ssb clear. After this we may see SIFCMD interrupts.
+ //
+ NdisRawWritePortUshort(acb->SifIntPort, SIFINT_SSBCLEAR);
+
+ //
+ // Read the SifInt
+ //
+ NdisRawReadPortUshort(acb->SifIntPort, &sifint_reg);
+ }
+
+ //
+ // Processed any receives which need IndicateReceiveComplete?
+ //
+ if (ReceivesProcessed)
+ {
+ if (acb->acb_gen_objs.media_type_in_use == NdisMedium802_5)
+ {
+ // Token Ring
+ //
+ NdisMTrIndicateReceiveComplete(acb->acb_handle);
+ }
+ else
+ {
+ // Ethernet
+ //
+ NdisMEthIndicateReceiveComplete(acb->acb_handle);
+ }
+ }
+}
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexRingStatus
+//
+// Description:
+// This routine does the clean up work necessary
+// when a ring status occurs.
+//
+// Input:
+// acb - Our Driver Context for this adapter or head.
+//
+// Output:
+// None
+//
+// Called By:
+// NetFlexHandleInterrupt
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+VOID
+NetFlexRingStatus(
+ PACB acb
+ )
+{
+ USHORT value;
+ ULONG RingStatus = 0;
+
+ value = acb->acb_ssb_virtptr->SSB_Status;
+
+ DebugPrint(1,("NF(%d): RingStatus value = %x\n",acb->anum, value));
+
+ //
+ // Determine the reason for the ring interrupt.
+ //
+ if (value & RING_STATUS_SIGNAL_LOSS)
+ {
+ RingStatus |= NDIS_RING_SIGNAL_LOSS;
+ DebugPrint(1,("NF(%d): RING_STATUS_SIGNAL_LOSS\n",acb->anum));
+
+ //
+ // Have we already reported the error?
+ //
+ if (!acb->SentRingStatusLog &&
+ ((acb->acb_lastringstatus & RING_STATUS_SIGNAL_LOSS) == 0))
+ {
+ // no, so send one.
+ NdisWriteErrorLogEntry( acb->acb_handle,
+ EVENT_NDIS_SIGNAL_LOSS_ERROR,
+ 3,
+ NETFLEX_RINGSTATUS_ERROR_CODE,
+ (ULONG) acb->acb_baseaddr,
+ (ULONG) value
+ );
+ acb->SentRingStatusLog = TRUE;
+ }
+ }
+
+ if (value & RING_STATUS_HARD_ERROR)
+ {
+ RingStatus |= NDIS_RING_HARD_ERROR;
+ DebugPrint(1,("NF(%d): RING_STATUS_HARD_ERROR\n",acb->anum));
+ }
+ if (value & RING_STATUS_SOFT_ERROR)
+ {
+ RingStatus |= NDIS_RING_SOFT_ERROR;
+ DebugPrint(1,("NF(%d): RING_STATUS_SOFT_ERROR\n",acb->anum));
+ }
+ if (value & RING_STATUS_XMIT_BEACON)
+ {
+ RingStatus |= NDIS_RING_TRANSMIT_BEACON;
+ DebugPrint(1,("NF(%d): RING_STATUS_XMIT_BEACON\n",acb->anum));
+ }
+ if (value & RING_STATUS_LOBE_WIRE_FAULT)
+ {
+ RingStatus |= NDIS_RING_LOBE_WIRE_FAULT;
+ DebugPrint(1,("NF(%d): RING_STATUS_LOBE_WIRE_FAULT\n",acb->anum));
+ //
+ // Have we already reported the error?
+ //
+ if (!acb->SentRingStatusLog &&
+ ((acb->acb_lastringstatus & NDIS_RING_LOBE_WIRE_FAULT) == 0))
+ {
+ // no, so send one.
+ NdisWriteErrorLogEntry( acb->acb_handle,
+ EVENT_NDIS_LOBE_FAILUE_ERROR,
+ 3,
+ NETFLEX_RINGSTATUS_ERROR_CODE,
+ (ULONG) acb->acb_baseaddr,
+ (ULONG) value
+ );
+
+ acb->SentRingStatusLog = TRUE;
+ }
+ }
+
+ if (value & (RING_STATUS_AUTO_REMOVE_1 | RING_STATUS_REMOVE_RECEIVED))
+ {
+ if (value & RING_STATUS_AUTO_REMOVE_1)
+ {
+ RingStatus |= NDIS_RING_AUTO_REMOVAL_ERROR;
+ DebugPrint(1,("NF(%d): RING_STATUS_AUTO_REMOVE_1\n",acb->anum));
+ }
+ if (value & RING_STATUS_REMOVE_RECEIVED)
+ {
+ RingStatus |= NDIS_RING_REMOVE_RECEIVED;
+ DebugPrint(1,("NF(%d): RING_STATUS_REMOVE_RECEIVED\n",acb->anum));
+ }
+ //
+ // Have we already reported the error?
+ //
+ if ((acb->acb_lastringstatus &
+ (RING_STATUS_AUTO_REMOVE_1 | RING_STATUS_REMOVE_RECEIVED )) == 0)
+ {
+ // no, so send one.
+ NdisWriteErrorLogEntry( acb->acb_handle,
+ EVENT_NDIS_REMOVE_RECEIVED_ERROR,
+ 3,
+ NETFLEX_RINGSTATUS_ERROR_CODE,
+ (ULONG) acb->acb_baseaddr,
+ (ULONG) value
+ );
+ }
+ }
+
+ if (value & RING_STATUS_OVERFLOW)
+ {
+ RingStatus |= NDIS_RING_COUNTER_OVERFLOW;
+ DebugPrint(1,("NF(%d): RING_STATUS_OVERFLOW\n",acb->anum));
+ }
+
+ if (value & RING_STATUS_SINGLESTATION)
+ {
+ RingStatus |= NDIS_RING_SINGLE_STATION;
+ DebugPrint(1,("NF(%d): RING_STATUS_SINGLESTATION\n",acb->anum));
+ }
+
+ if (value & RING_STATUS_RINGRECOVERY)
+ {
+ RingStatus |= NDIS_RING_RING_RECOVERY;
+ DebugPrint(1,("NF(%d): RING_STATUS_RINGRECOVERY\n",acb->anum));
+ }
+
+ //
+ // Save the Ring Status
+ //
+ acb->acb_lastringstatus = RingStatus;
+
+
+ //
+ // Indicate to the filter the ring status.
+ //
+ NdisMIndicateStatus(
+ acb->acb_handle,
+ NDIS_STATUS_RING_STATUS,
+ &RingStatus,
+ sizeof(ULONG)
+ );
+
+ //
+ // Tell the filter that we have completed the ring status.
+ //
+ NdisMIndicateStatusComplete(acb->acb_handle);
+}
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexCommand
+//
+// Description:
+// This routine looks at the current SSB struct
+// and places the corresponding request on the
+// Request Confirm Queue. If the command that
+// has completed is an open, a receive and
+// transmit command are issued.
+//
+// Input:
+// acb - Our Driver Context for this adapter or head.
+//
+// Output:
+// None
+//
+// Called By:
+// NetFlexHandleInterrupt
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+VOID
+NetFlexCommand(
+ PACB acb
+ )
+{
+ PSCBREQ scbreq;
+ PMACREQ macreq;
+ PTR_OBJS trobjs;
+ PETH_OBJS ethobjs;
+ SHORT value,i;
+ PUSHORT tempptr;
+ NDIS_STATUS Status;
+
+#if (DBG || DBGPRINT)
+ //
+ // I wanted to know if I'm getting bad commands
+ //
+ if (acb->acb_ssb_virtptr->SSB_Cmd == TMS_CMDREJECT)
+ {
+ DebugPrint(0,("NF(%d): Command rejected\n",acb->anum));
+ DebugPrint(0,("NF(%d): SSB Status %x\n",acb->anum,SWAPS(acb->acb_ssb_virtptr->SSB_Status)));
+ DebugPrint(0,("NF(%d): SSB Ptr %x\n",acb->anum,SWAPL(acb->acb_ssb_virtptr->SSB_Ptr)));
+ }
+ else if (acb->acb_ssb_virtptr->SSB_Status != SSB_GOOD)
+ {
+ DebugPrint(0,("NF(%d): Bad status %x\n",acb->anum,acb->acb_ssb_virtptr->SSB_Status));
+ DebugPrint(0,("NF(%d): cmd is %x\n",acb->anum,acb->acb_ssb_virtptr->SSB_Cmd));
+ }
+#endif
+
+ //
+ // Get the scb request associated with the completed request.
+ //
+ Status = NetFlexDequeue_TwoPtrQ_Head(
+ (PVOID *)&(acb->acb_scbreq_head),
+ (PVOID *)&(acb->acb_scbreq_tail),
+ (PVOID *)&scbreq
+ );
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DebugPrint(0,("NF(%d) NetFlexCommand - dequeue scbreq failed!\n",acb->anum));
+ return;
+ }
+
+ //
+ // If we have a Macreq to place on the confirm q. Do this now.
+ //
+ macreq = scbreq->req_macreq;
+
+ if (macreq)
+ {
+ //
+ // If the command had a problem, save the failure reason and
+ // exit out of the routine. Otherwise, save the success code
+ // and see if the completed command is an open or a read error log.
+ //
+ if (acb->acb_ssb_virtptr->SSB_Cmd == TMS_CMDREJECT)
+ {
+ DebugPrint(0,("NF(%d): Command rejected\n",acb->anum));
+ DebugPrint(0,("NF(%d): SSB Status %x\n",acb->anum,SWAPS(acb->acb_ssb_virtptr->SSB_Status)));
+ DebugPrint(0,("NF(%d): SSB Ptr %x\n",acb->anum,SWAPL(acb->acb_ssb_virtptr->SSB_Ptr)));
+ macreq->req_status = NDIS_STATUS_FAILURE;
+ }
+ else if (acb->acb_ssb_virtptr->SSB_Status != SSB_GOOD)
+ {
+ DebugPrint(0,("NF(%d): Bad status %x\n",acb->anum,acb->acb_ssb_virtptr->SSB_Status));
+ DebugPrint(0,("NF(%d): cmd is %x\n",acb->anum,acb->acb_ssb_virtptr->SSB_Cmd));
+
+ if ((acb->acb_ssb_virtptr->SSB_Cmd == TMS_OPEN) &&
+ (acb->acb_ssb_virtptr->SSB_Status & SSB_OPENERR)
+ )
+ {
+ macreq->req_status = NDIS_STATUS_TOKEN_RING_OPEN_ERROR;
+ macreq->req_info = (PVOID)(acb->acb_ssb_virtptr->SSB_Status >> 8);
+ }
+ else
+ {
+ macreq->req_status = NDIS_STATUS_FAILURE;
+ }
+ }
+ else if (acb->acb_ssb_virtptr->SSB_Cmd == TMS_READLOG)
+ {
+ acb->acb_logbuf_valid = TRUE;
+ //
+ // Fill in the appropriate fields with the information
+ // given by the log buffer.
+ //
+ if (acb->acb_gen_objs.media_type_in_use == NdisMedium802_5)
+ {
+ // TOKEN RING
+ trobjs = (PTR_OBJS)(acb->acb_spec_objs);
+ trobjs->REL_Congestion += ((PREL)(acb->acb_logbuf_virtptr))->REL_Congestion;
+ trobjs->REL_LineError += ((PREL)(acb->acb_logbuf_virtptr))->REL_LineError;
+ trobjs->REL_LostError += ((PREL)(acb->acb_logbuf_virtptr))->REL_LostError;
+ trobjs->REL_BurstError += ((PREL)(acb->acb_logbuf_virtptr))->REL_BurstError;
+ trobjs->REL_ARIFCIError += ((PREL)(acb->acb_logbuf_virtptr))->REL_ARIFCIError;
+ trobjs->REL_Congestion += ((PREL)(acb->acb_logbuf_virtptr))->REL_Congestion;
+ trobjs->REL_CopiedError += ((PREL)(acb->acb_logbuf_virtptr))->REL_CopiedError;
+ trobjs->REL_TokenError += ((PREL)(acb->acb_logbuf_virtptr))->REL_TokenError;
+ }
+ else
+ {
+ // ETHERNET
+ ethobjs = (PETH_OBJS)(acb->acb_spec_objs);
+ ethobjs->RSL_AlignmentErr = (USHORT)SWAPS(((PRSL)(acb->acb_logbuf_virtptr))->RSL_AlignmentErr);
+ ethobjs->RSL_1_Collision = (USHORT)SWAPS(((PRSL)(acb->acb_logbuf_virtptr))->RSL_1_Collision);
+ ethobjs->RSL_FrameCheckSeq = (USHORT)SWAPS(((PRSL)(acb->acb_logbuf_virtptr))->RSL_FrameCheckSeq);
+ ethobjs->RSL_DeferredXmit = (USHORT)SWAPS(((PRSL)(acb->acb_logbuf_virtptr))->RSL_DeferredXmit);
+ ethobjs->RSL_LateCollision = (USHORT)SWAPS(((PRSL)(acb->acb_logbuf_virtptr))->RSL_LateCollision);
+ ethobjs->RSL_Excessive = (USHORT)SWAPS(((PRSL)(acb->acb_logbuf_virtptr))->RSL_Excessive);
+ ethobjs->RSL_CarrierErr = (USHORT)SWAPS(((PRSL)(acb->acb_logbuf_virtptr))->RSL_CarrierErr);
+ tempptr = (PUSHORT)&(((PRSL)(acb->acb_logbuf_virtptr))->RSL_2_Collision);
+ value = 0;
+ for (i = 0; i < 14; i++)
+ {
+ value += SWAPS( *(tempptr+i) );
+ }
+ ethobjs->RSL_More_Collision = value;
+ }
+ }
+
+ //
+ // Take the Mac request off the macreq queue and place it on
+ // the confirm queue so that the command can be completed.
+ //
+ NetFlexDequeue_TwoPtrQ(
+ (PVOID *)&(acb->acb_macreq_head),
+ (PVOID *)&(acb->acb_macreq_tail),
+ (PVOID)macreq
+ );
+
+ NetFlexEnqueue_TwoPtrQ_Tail(
+ (PVOID *)&(acb->acb_confirm_qhead),
+ (PVOID *)&(acb->acb_confirm_qtail),
+ (PVOID)macreq
+ );
+ } // if (macreq)
+
+ //
+ // Free up the SCB request associated with this command.
+ //
+ scbreq->req_macreq = NULL;
+
+ NetFlexEnqueue_OnePtrQ_Head(
+ (PVOID *)&(acb->acb_scbreq_free),
+ (PVOID)scbreq
+ );
+}
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexEnableInterrupt
+//
+// Description:
+// This routine is used to enable the adapter to
+// interrupt the system.
+//
+// Input:
+// Context - Our Driver Context for this adapter or head.
+//
+// Output:
+// None
+//
+// Called By:
+// Miniport Wrapper
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+VOID
+NetFlexEnableInterrupt(
+ IN NDIS_HANDLE Context
+ )
+{
+ USHORT actl_reg;
+ PACB acb = (PACB) Context;
+
+ DebugPrint(3,("NF(%d)(E)\n",acb->anum));
+ //
+ // Enable System Interrupts
+ //
+ actl_reg = acb->actl_reg | ACTL_SINTEN;
+
+ NdisRawWritePortUshort(acb->SifActlPort, actl_reg);
+
+ acb->InterruptsDisabled = FALSE;
+}
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexDisableInterrupt
+//
+// Description:
+// This routine is used to disable the adapter from being
+// able to interrupt the system.
+//
+// Input:
+// Context - Our Driver Context for this adapter or head.
+//
+// Output:
+// None
+//
+// Called By:
+// Miniport Wrapper
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+VOID
+NetFlexDisableInterrupt(
+ IN NDIS_HANDLE Context
+ )
+{
+ USHORT actl_reg;
+ PACB acb = (PACB) Context;
+
+ //
+ // Disable System Interrupts
+ //
+ actl_reg = acb->actl_reg & ~ACTL_SINTEN;
+
+ NdisRawWritePortUshort(acb->SifActlPort, actl_reg);
+
+ acb->InterruptsDisabled = TRUE;
+
+ DebugPrint(3,("NF(%d)(D)\n",acb->anum));
+}
diff --git a/private/ntos/ndis/netflex/macstrct.h b/private/ntos/ndis/netflex/macstrct.h
new file mode 100644
index 000000000..e6d9184d1
--- /dev/null
+++ b/private/ntos/ndis/netflex/macstrct.h
@@ -0,0 +1,581 @@
+//************************************************************************
+//************************************************************************
+//
+// File Name: MACSTRCT.H
+//
+// Program Name: NetFlex NDIS 3.0 Miniport Driver
+//
+// Companion Files: None
+//
+// Function: This module contains the NetFlex Miniport Driver
+// interface routines called by the Wrapper and the
+// configuration manager.
+//
+// (c) Compaq Computer Corporation, 1992,1993,1994
+//
+// This file is licensed by Compaq Computer Corporation to Microsoft
+// Corporation pursuant to the letter of August 20, 1992 from
+// Gary Stimac to Mark Baber.
+//
+// History:
+//
+// 04/15/94 Robert Van Cleve - Converted from NDIS Mac Driver
+//***********************************************************************
+//***********************************************************************
+
+#ifndef _MACSTRCT_
+#define _MACSTRCT_
+
+#if DBG
+#define BreakPoint() DbgBreakPoint()
+#endif
+
+typedef
+USHORT
+(FASTCALL *W_PROCESS_RECEIVE_HANDLER) (
+ struct acb_block *acb
+ );
+
+typedef struct netflx_parameters {
+ OPEN utd_open;
+ USHORT utd_maxtrans;
+ USHORT utd_maxrcvs;
+ USHORT utd_maxframesz;
+ USHORT utd_maxmulticast;
+ USHORT utd_maxinternalreqs;
+ USHORT utd_maxinternalbufs;
+ USHORT utd_numsmallbufs;
+ USHORT utd_smallbufsz;
+ BOOLEAN utd_extremecheckforhang;
+} NETFLEX_PARMS, *PNETFLEX_PARMS;
+
+/* Netflx parms defaults */
+
+#define MIN_MULTICASTS 10
+#define MAX_MULTICASTS 40
+#define DF_MULTICASTS 20
+
+#define MIN_INTERNALREQS 10
+#define MAX_INTERNALREQS 80
+#define DF_INTERNALREQS 40
+
+#define MIN_INTERNALBUFS 2 /* Transmit buffers */
+#define MAX_INTERNALBUFS 8
+#define DF_INTERNALBUFS 8
+
+//
+// Number of xmit packets
+// Number of lists is this number * MAX_LISTS_PER_XMIT
+//
+#define MAX_XMITS_TR 10
+#define MIN_XMITS 3
+#define DF_XMITS_TR 8
+
+//
+// Number of rcv packets.
+// Because a packet requires only one list, this is the number of Receive
+// list as well.
+//
+
+#define MAX_RCVS_ETH 40
+#define MAX_RCVS_TR 20
+#define MIN_RCVS 3
+#define DF_RCVS_ETH 20
+#define DF_RCVS_TR 10
+
+#define MAX_XMITS_ETH 20
+#define DF_XMITS_ETH 16
+
+#define MAX_FRAMESIZE_ETH 1514
+#define DF_FRAMESIZE_ETH 1514
+#define MAX_FRAMESIZE_TR4 4096
+#define MAX_FRAMESIZE_TR16 17952
+#define DF_FRAMESIZE_TR 4500 // Was 4096.
+#define MIN_FRAMESIZE 256
+
+//
+// Additional Statistics supported by Netflex but not by MS
+//
+
+#define OID_802_5_UPSTREAM_ADDRESS 0xff020201
+#define OID_802_5_CONGESTION_ERRORS 0xff020202
+#define OID_NF_INTERRUPT_COUNT 0xff020203
+#define OID_NF_INTERRUPT_RATIO 0xff020204
+#define OID_NF_INTERRUPT_RATIO_CHANGES 0xff020205
+
+/*----------------------------------------------------------------------*/
+/* Structure Name: Netflx Global MAC structure (MAC) */
+/* */
+/* Description: The adapter binding block contain the internal variables*/
+/* for the binding between a protocol and an adpater. */
+/*----------------------------------------------------------------------*/
+typedef struct mac
+{
+ struct acb_block *mac_adapters;/* Ptr to registered adapters */
+ PDRIVER_OBJECT mac_object; /* Value passed by DriverEntry */
+ NDIS_HANDLE mac_wrapper; /* global handle to miniport wrapper*/
+ USHORT mac_numadpts; /* number of adpaters on list */
+ PVOID DownloadCode; /* Virtual address of Download code */
+ USHORT DownloadLength; /* length of download image */
+ BOOLEAN Initializing; /* is the system still in intitialization mode */
+} MAC, *PMAC;
+
+/*----------------------------------------------------------------------*/
+/* Structure Name: Multicast Table */
+/* */
+/* Description: The multicast table contains a list of the enabled */
+/* multicast or group address on the adapter. */
+/*----------------------------------------------------------------------*/
+
+typedef struct multi_table {
+ struct multi_table *mt_next;
+ UCHAR mt_addr[NET_ADDR_SIZE]; /* Multicast address */
+} MULTI_TABLE, *PMULTI_TABLE;
+
+/*----------------------------------------------------------------------*/
+/* Structure Name: Mac Request Block */
+/* */
+/* Description: The mac request block contains the variables necessary */
+/* to complete a pending command. */
+/*----------------------------------------------------------------------*/
+typedef struct macreq_blk
+{
+ struct macreq_blk *req_next; /* Pointer to the next request */
+ ULONG req_type; /* Type of request and completion */
+ NDIS_STATUS req_status; /* Status of command */
+ PVOID req_info; /* Extra info needed to complete the req */
+ BOOLEAN req_timeout; /* This field is used to timestamp the command blocks */
+ UCHAR req_timeoutcount; /* Count of the number of times we have retried a command. */
+} MACREQ, *PMACREQ;
+
+#define MACREQSIZE sizeof(MACREQ)
+
+#define NO_CMP_NEEDED 0
+#define OPENADAPTER_CMP 1
+#define OPENADAPTER_DUMCMP 2
+#define CLOSEADAPTER_CMP 3
+#define CLOSEADAPTER_DUMCMP 4
+#define SEND_CMP 5
+#define TRANSFERDATA_CMP 6
+#define RESET_CMP 7
+#define REQUEST_CMP 8
+#define INDICATERCV_CMP 9
+#define INDICATESTATUS_CMP 10
+#define QUERY_CMP 11
+
+#define RESET_STAGE_1 1
+#define RESET_STAGE_2 2
+#define RESET_STAGE_3 3
+#define RESET_STAGE_4 4
+#define RESET_HALTED 5
+/*----------------------------------------------------------------------*/
+/* Structure Name: SCB Request Block */
+/* */
+/* Description: The SCB Request block contains the variables necessary */
+/* to send a command to the adapter, wait for the response */
+/* and find the mac request block in order to complete the */
+/* request if necessary. */
+/*----------------------------------------------------------------------*/
+typedef struct scbreq_blk
+{
+ struct scbreq_blk *req_next; /* Pointer to the next request */
+ SCB req_scb; /* Copy of the SCB to send */
+ MULTI_BLOCK req_multi;
+ PMACREQ req_macreq; /* Ptr to the corresponding macreq */
+} SCBREQ, *PSCBREQ;
+
+#define SCBREQSIZE sizeof(SCBREQ)
+
+
+
+/*----------------------------------------------------------------------*/
+/* Structure Name: General Objects structure */
+/* */
+/* Description: The General Objects strucuture contains the variables */
+/* necessary to hold the gerneral operational */
+/* characteristics and statistics. */
+/*----------------------------------------------------------------------*/
+typedef struct general_objs
+{
+ NDIS_MEDIUM media_type_in_use;
+ ULONG max_frame_size;
+ ULONG min_frame_size;
+ ULONG link_speed;
+ ULONG cur_filter;
+ ULONG frames_xmitd_ok;
+ ULONG frames_rcvd_ok;
+ ULONG frames_xmitd_err;
+ ULONG frames_rcvd_err;
+ ULONG interrupt_count;
+ ULONG interrupt_ratio_changes;
+ UCHAR perm_staddr[NET_ADDR_SIZE];
+ UCHAR current_staddr[NET_ADDR_SIZE];
+} GENERAL_OBJS, *PGENERAL_OBJS;
+
+typedef struct eth_objs
+{
+ USHORT MaxMulticast;
+ UCHAR *MulticastEntries;
+ USHORT NumberOfEntries;
+ USHORT RSL_AlignmentErr;
+ USHORT RSL_1_Collision;
+ USHORT RSL_More_Collision;
+ USHORT RSL_FrameCheckSeq;
+ USHORT RSL_DeferredXmit;
+ USHORT RSL_Excessive;
+ USHORT RSL_LateCollision;
+ USHORT RSL_CarrierErr;
+} ETH_OBJS, *PETH_OBJS;
+
+typedef struct tr_objs
+{
+ UCHAR cur_func_addr[NET_GROUP_SIZE];
+ UCHAR cur_grp_addr[NET_GROUP_SIZE];
+ UCHAR upstream_addr[NET_GROUP_SIZE];
+ USHORT grp_users_count;
+ ULONG frames_xmtd_no_return;
+ UCHAR REL_LineError;
+ UCHAR REL_Congestion;
+ UCHAR REL_LostError;
+ UCHAR REL_BurstError;
+ UCHAR REL_ARIFCIError;
+ UCHAR REL_CopiedError;
+ UCHAR REL_TokenError;
+} TR_OBJS, *PTR_OBJS;
+
+/*----------------------------------------------------------------------*/
+/* Structure Name: MAC Internal Adapter Control Block (ACB) */
+/* */
+/* Description: The Mac internal adapter control block contains all */
+/* internal variables for ONE SINGLE adapter. The Global */
+/* variables structure for this driver contains a pointer */
+/* to a linked list of ACBs. (One ACB for each adapter */
+/* registered by this driver). The variables in the ACB */
+/* are used by the NDI driver to maintain internal */
+/* statistics, driver states, and resources. */
+/*----------------------------------------------------------------------*/
+typedef struct acb_block {
+ struct acb_block *acb_next; /* Next ACB */
+ NDIS_HANDLE acb_handle; /* Our Miniport Handle */
+
+ USHORT actl_reg; // Saved value of our ACTL_REG
+ USHORT InterruptsDisabled;
+
+ PUCHAR SifIntPort; // SIF interrupt register
+ PUCHAR SifActlPort; // SIF ACTL register
+ PRCV acb_rcv_head; /* Head of our Receive Lists */
+
+#ifdef ODD_POINTER
+ BOOLEAN XmitStalled; /* state of the transmiter */
+#endif
+
+ NDIS_SPIN_LOCK XmitLock;
+ PXMIT acb_xmit_head; /* */
+ PXMIT acb_xmit_ahead; /* */
+ PXMIT acb_xmit_atail; /* */
+
+ USHORT acb_maxrcvs;
+ USHORT acb_avail_xmit;
+
+ USHORT acb_curmap;
+ USHORT acb_maxmaps;
+
+ W_PROCESS_RECEIVE_HANDLER ProcessReceiveHandler;
+
+ PSCB acb_scb_virtptr; /* Virt ptr to the SCB */
+ PSSB acb_ssb_virtptr; /* Virt ptr to the SSB */
+
+ USHORT RcvIntRatio;
+
+#ifdef XMIT_INTS
+ USHORT XmitIntRatio;
+#endif
+
+#ifdef ODD_POINTER
+ BOOLEAN XmitStalled; /* state of the transmiter */
+ BOOLEAN HandlingInterrupt;
+#endif
+
+ PBUFFER_DESCRIPTOR OurBuffersListHead;
+ PBUFFER_DESCRIPTOR SmallBuffersListHead;
+
+ //
+ // Dynamic ratio stuff
+ //
+ UINT timer_run_count;
+ UINT handled_interrupts;
+#ifdef NEW_DYNAMIC_RATIO
+ union {
+ struct {
+ USHORT current_run_up;
+ USHORT current_run_down;
+ } ;
+ ULONG current_run_both;
+ } ;
+#else
+ UINT current_run;
+#endif
+
+ //
+ // Dynamic ratio
+ //
+
+#ifdef DYNAMIC_RATIO_HISTORY
+ UCHAR IntHistory[1024];
+ UCHAR RatioHistory[1024];
+ UINT Hndx;
+#endif
+
+#ifndef NEW_DYNAMIC_RATIO
+ UINT cleartime;
+ UINT sw24;
+#endif
+
+ GENERAL_OBJS acb_gen_objs; // General chars and stats
+
+ NDIS_MINIPORT_TIMER DpcTimer;
+
+ NDIS_MINIPORT_INTERRUPT acb_interrupt;
+
+ PNDIS_HANDLE FlushBufferPoolHandle; // The Flush buffer pool
+
+ USHORT acb_scbclearout;
+ USHORT acb_maxtrans;
+ USHORT acb_smallbufsz;
+ USHORT acb_padJim;
+ USHORT acb_maxreqs;
+ USHORT acb_openoptions;
+ NDIS_STATUS acb_lastopenstat;
+ ULONG acb_lastringstate;
+ ULONG acb_lastringstatus;
+
+ NDIS_PHYSICAL_ADDRESS acb_rcv_physptr;
+ PRCV acb_rcv_virtptr;
+
+ NDIS_PHYSICAL_ADDRESS acb_xmit_physptr; /* Ptr to Xmit memory */
+ PXMIT acb_xmit_virtptr;
+
+
+ PMULTI_BLOCK acb_multiblk_virtptr; /* Virt ptr to Multicast blk */
+ NDIS_PHYSICAL_ADDRESS acb_multiblk_physptr; /* Phys ptr to Multicast blk */
+ USHORT acb_multi_index; /* index to Multicast blks */
+
+ PRCV acb_rcv_tail; /* Tail, has the odd fwdptr */
+ PRCV acb_rcv_whead; /* */
+ PXMIT acb_xmit_whead; /* */
+ PXMIT acb_xmit_wtail; /* */
+ PXMIT acb_xmit_chead; /* */
+ PXMIT acb_xmit_ctail; /* */
+
+ USHORT acb_state; /* Adapter Primary State */
+ ULONG acb_int_timeout; // Interrupt timeout.
+ ULONG acb_int_count; // Count of interrupts.
+
+ //
+ // Various mapped I/O Port Addresses for this adapter.
+ //
+ PUCHAR SifDataPort; // SIF data register
+ PUCHAR SifDIncPort; // SIF data autoincrment reg
+ PUCHAR SifAddrPort; // SIF address register
+ PUCHAR SifAddrxPort; // SIF SIF extended address reg
+
+ PUCHAR BasePorts;
+ PUCHAR MasterBasePorts;
+ PUCHAR ConfigPorts;
+ PUCHAR ExtConfigPorts;
+
+ PUCHAR AdapterConfigPort; // Adapter configuration reg
+
+ PVOID acb_xmitbuf_virtptr; /* Virt ptr to our xmit bufs */
+ NDIS_PHYSICAL_ADDRESS acb_xmitbuf_physptr; /* Phys ptr to our xmit bufs */
+
+ PVOID OurBuffersVirtPtr; /* Virt ptr to our internal bufs */
+
+ PVOID SmallBuffersVirtPtr; /* Virt ptr to our internal bufs */
+ NDIS_PHYSICAL_ADDRESS acb_scb_physptr; /* Phys ptr to the SCB */
+ NDIS_PHYSICAL_ADDRESS acb_ssb_physptr; /* Phys ptr to the SSB */
+
+ USHORT acb_logbuf_valid; /* Validity of the log contents */
+ PVOID acb_logbuf_virtptr; /* Virt ptr to READ ERROR LOG */
+ NDIS_PHYSICAL_ADDRESS acb_logbuf_physptr; /* Phys ptr to READ ERROR LOG */
+
+ POPEN acb_opnblk_virtptr; /* Virt ptr to OPEN block */
+ NDIS_PHYSICAL_ADDRESS acb_opnblk_physptr; /* Phys ptr to OPEN block */
+
+ INIT acb_initblk; /* Virt ptr to INIT block */
+
+ PSCBREQ acb_scbreq_ptr; /* Ptr to SCB Request memory */
+ PSCBREQ acb_scbreq_head; /* Ptr to next SCB */
+ PSCBREQ acb_scbreq_tail; /* Ptr to last SCB */
+ PSCBREQ acb_scbreq_free; /* Ptr to free SCB Requests */
+ PSCBREQ acb_scbreq_next; /* Ptr to next SCB to execute */
+
+ PMACREQ acb_macreq_ptr; /* Ptr to MAC Request memory */
+ PMACREQ acb_macreq_head; /* Ptr to front of pending reqs */
+ PMACREQ acb_macreq_tail; /* Ptr to end of pending reqs */
+ PMACREQ acb_macreq_free; /* Ptr to free MAC Requests */
+ PMACREQ acb_confirm_qhead; /* Ptr to pending MAC Reqs to complete */
+ PMACREQ acb_confirm_qtail; /* Ptr to pending MAC Reqs to complete */
+
+
+ PNDIS_OID acb_gbl_oid_list;
+ PNDIS_OID acb_spec_oid_list;
+ SHORT acb_gbl_oid_list_size;
+ SHORT acb_spec_oid_list_size;
+ PVOID acb_spec_objs; /* Network specific chars and stats */
+
+
+ USHORT acb_promiscuousmode; /* Board accepts all pkts */
+ USHORT acb_boardid; /* Board id */
+ USHORT acb_baseaddr; /* Base address of board */
+ PNETFLEX_PARMS acb_parms; /* Pointer to adp's param's */
+
+ USHORT acb_usefpa; /* are using fast pkt accel */
+ USHORT acb_dualport; /* is this a dual port card */
+ USHORT acb_portnumber; /* which head of dual card */
+
+ struct acb_block *FirstHeadsAcb; /* Pointer to first Head's ACB */
+
+ USHORT acb_upstreamaddrptr; /* buffer for read adapter */
+ USHORT acb_maxinternalbufs; /* maximum internal xmit bufs */
+
+ USHORT acb_numsmallbufs; /* maximum small xmit bufs */
+ BOOLEAN RequestInProgress; // Is there an outstanding request
+ BOOLEAN AdapterInitializing; // Are we initialing?
+
+
+ //
+ // These variables hold information about a pending request.
+ //
+
+ PUINT BytesWritten;
+ PUINT BytesRead;
+ PUINT BytesNeeded;
+ NDIS_OID Oid;
+ PVOID InformationBuffer;
+ UINT InformationBufferLength;
+
+ BOOLEAN InterruptsShared;
+ BOOLEAN FullDuplexEnabled;
+ BOOLEAN SmallBuffersAreContiguous;
+ BOOLEAN MergeBuffersAreContiguous;
+ BOOLEAN RecvBuffersAreContiguous;
+
+ BOOLEAN nfpad1;
+ USHORT nfpad2;
+
+ //
+ // Stuff Needed for a reset.
+ //
+ NDIS_MINIPORT_TIMER ResetTimer;
+ USHORT ResetState;
+ USHORT ResetRetries;
+ USHORT InitRetries;
+ BOOLEAN SentRingStatusLog;
+ BOOLEAN ResetErrorLogged;
+
+ //
+ // Memory pools.
+ //
+
+ PVOID ReceiveBufferPoolVirt;
+ NDIS_PHYSICAL_ADDRESS ReceiveBufferPoolPhys;
+
+ PVOID MergeBufferPoolVirt;
+ NDIS_PHYSICAL_ADDRESS MergeBufferPoolPhys;
+
+ PVOID SmallBufferPoolVirt;
+ NDIS_PHYSICAL_ADDRESS SmallBufferPoolPhys;
+#if (DBG || DBGPRINT)
+ USHORT anum;
+ USHORT max_int_buffs_used;
+ USHORT num_int_buffs_used;
+ ULONG XmitSent;
+ ULONG LastXmitSent;
+#endif
+
+} ACB, *PACB;
+
+/*----------------------------------------------------------------------*/
+/* Structure Name: ACB Adpter States (AS) */
+/* */
+/* Description: These equates define the primary states that an */
+/* adapter may take on. */
+/*----------------------------------------------------------------------*/
+#define AS_NOTINSTALLED 0 // Adapter not installed
+#define AS_REGISTERING 1 // Adapter is registering
+#define AS_REGISTERED 2 // Adapter has been
+ // registered - but not initialized
+#define AS_INITIALIZING 3 // Adapter is initializing
+#define AS_INITIALIZED 4 // Adapter initialized
+#define AS_OPENING 5 // Adapter is opening
+#define AS_OPENED 6 // Adapter opened
+#define AS_CLOSING 7 // Adapter is closing
+#define AS_RESET_HOLDING 8 // Adapter reset
+#define AS_RESETTING 9 // Adapter is resetting
+#define AS_UNLOADING 10
+#define AS_REMOVING 11
+
+#define AS_HARDERROR 100 // Adapter suffered hardware error
+#define AS_CARDERROR 101 // Adapter reset error
+#define AS_INITERROR 102 // Adapter initialization error
+#define AS_INSTALLED 103 // Adapter installed (not reset)
+#define AS_IRQERROR 104 // Adapter IRQ error
+#define AS_DMAERROR 105 // Adapter DMA error
+#define AS_DOWNFILERR 106 // Adapter download no file error
+#define AS_DOWNMEMERR 107 // Adapter download no mem error
+#define AS_MEDIAERROR 108 // Adapter media error
+#define AS_SPEEDERROR 109 // Adapter ring speed error
+
+
+typedef struct netflx_reqrsvd {
+ PNDIS_REQUEST rsvd_nextreq;
+ USHORT rsvd_req_type;
+} NETFLEX_REQRSVD, *PNETFLEX_REQRSVD;
+
+typedef struct netflx_sendpkt_reqrsvd {
+ PNDIS_PACKET next;
+} NETFLEX_SENDPKT_RESERVED, *PNETFLEX_SENDPKT_RESERVED;
+
+#define RESERVED_FROM_PACKET(Packet)\
+ ((PNETFLEX_SENDPKT_RESERVED)((Packet)->MiniportReserved))
+
+typedef struct netflx_entry {
+ PVOID next;
+} NETFLEX_ENTRY, *PNETFLEX_ENTRY;
+
+
+//------------------
+// Definitions
+//------------------
+
+
+#define NETFLEX_MAJ_VER 4
+#define NETFLEX_MIN_VER 0
+
+//-------------------------------------
+// External Data Variable References
+//-------------------------------------
+
+extern MAC macgbls;
+extern USHORT gbl_addingdualport;
+extern USHORT gbl_portnumbertoadd;
+extern NDIS_HANDLE gbl_confighandle;
+
+extern NDIS_OID NetFlexGlobalOIDs_Eth[];
+extern NDIS_OID NetFlexNetworkOIDs_Eth[];
+extern NDIS_OID NetFlexGlobalOIDs_Tr[];
+extern NDIS_OID NetFlexNetworkOIDs_Tr[];
+extern SHORT NetFlexGlobalOIDs_Eth_size;
+extern SHORT NetFlexNetworkOIDs_Eth_size;
+extern SHORT NetFlexGlobalOIDs_Tr_size;
+extern SHORT NetFlexNetworkOIDs_Tr_size;
+
+extern OPEN open_mask;
+extern INIT init_mask;
+
+extern NDIS_PHYSICAL_ADDRESS NetFlexHighestAddress;
+extern NETFLEX_PARMS NetFlex_Defaults;
+
+#endif
+
diff --git a/private/ntos/ndis/netflex/makefile b/private/ntos/ndis/netflex/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/netflex/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/netflex/makefile.inc b/private/ntos/ndis/netflex/makefile.inc
new file mode 100644
index 000000000..e2934cb73
--- /dev/null
+++ b/private/ntos/ndis/netflex/makefile.inc
@@ -0,0 +1,5 @@
+netflx.bin: $(TARGETEXEFILES)
+ chmode -r netflx.bin
+ binplace netflx.bin
+ touch netflx.bin
+ chmode +r netflx.bin
diff --git a/private/ntos/ndis/netflex/netflex.rc b/private/ntos/ndis/netflex/netflex.rc
new file mode 100644
index 000000000..8282cdf15
--- /dev/null
+++ b/private/ntos/ndis/netflex/netflex.rc
@@ -0,0 +1,40 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "Compaq NetFlex network driver"
+#define VER_INTERNALNAME_STR "NETFLX.SYS"
+#define VER_ORIGINALFILENAME_STR "NETFLX.SYS"
+
+#include "cpqntssd.ver"
+
+#include "common.ver"
diff --git a/private/ntos/ndis/netflex/netflx.bin b/private/ntos/ndis/netflex/netflx.bin
new file mode 100644
index 000000000..50d5106e5
--- /dev/null
+++ b/private/ntos/ndis/netflex/netflx.bin
Binary files differ
diff --git a/private/ntos/ndis/netflex/netflx.prf b/private/ntos/ndis/netflex/netflx.prf
new file mode 100644
index 000000000..8ad30ddbb
--- /dev/null
+++ b/private/ntos/ndis/netflex/netflx.prf
@@ -0,0 +1,27 @@
+NetFlexDisableInterrupt@4
+NetFlexHandleInterrupt@4
+NetFlexSend@12
+@NetFlexProcessXmit@4
+@NetFlexProcessEthRcv@4
+NetFlexDeferredTimer@16
+NetFlexEnableInterrupt@4
+NetFlexConstrainPacket@24
+NetFlexCheckForHang@4
+NetFlexTransferData@24
+NetFlexInitialize@24
+NetFlexSetupNetType@4
+NetFlexAdapterReset@8
+NetFlexSetInformation@24
+NetFlexQueryInformation@24
+NetFlexDownload@4
+NetFlexOpenAdapter@4
+NetFlexBudWait@4
+NetFlexInitializeAdapter@4
+NetFlexSendNextSCB@4
+NetFlexBoardInitandReg@8
+DriverEntry@8
+NetFlexInitializeAcb@4
+NetFlexInitGlobals@0
+NetFlexGetBIA@4
+NetFlexReadConfigurationParameters@8
+NetFlexRegisterAdapter@20
diff --git a/private/ntos/ndis/netflex/protos.h b/private/ntos/ndis/netflex/protos.h
new file mode 100644
index 000000000..47204461d
--- /dev/null
+++ b/private/ntos/ndis/netflex/protos.h
@@ -0,0 +1,450 @@
+//************************************************************************
+//************************************************************************
+//
+// File Name: PROTOS.H
+//
+// Program Name: NetFlex NDIS 3.0 Miniport Driver
+//
+// Companion Files: All
+//
+// Function: This module contains the NetFlex Miniport Driver
+// routine prototypes references.
+//
+// (c) Compaq Computer Corporation, 1992,1993,1994
+//
+// This file is licensed by Compaq Computer Corporation to Microsoft
+// Corporation pursuant to the letter of August 20, 1992 from
+// Gary Stimac to Mark Baber.
+//
+// History:
+//
+// 04/15/94 Robert Van Cleve - Converted from NDIS Mac Driver
+//***********************************************************************
+//***********************************************************************
+
+
+#ifndef _PROTOS_
+#define _PROTOS_
+
+
+NDIS_STATUS
+NetFlexBoardTest(
+ PACB acb,
+ NDIS_HANDLE NdisAdapterHandle
+ );
+
+NDIS_STATUS
+NetFlexBoardInitandReg(
+ PACB acb,
+ PNDIS_EISA_FUNCTION_INFORMATION EisaData
+ );
+
+
+VOID
+NetFlexSetupNetType(
+ PACB acb
+ );
+
+VOID
+NetFlexGetBIA(
+ PACB acb
+ );
+
+NDIS_STATUS
+NetFlexDownload(
+ PACB acb
+ );
+
+NDIS_STATUS
+NetFlexReadConfigurationParameters(
+ PACB acb,
+ NDIS_HANDLE ConfigHandle
+ );
+
+VOID
+NetFlexGetUpstreamAddrPtr(
+ PACB acb
+ );
+
+//++
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+BOOLEAN
+NetFlexCheckForHang(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+VOID
+NetFlexISR(
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueDpc,
+ IN PVOID Context
+ );
+
+VOID
+NetFlexHandleInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+VOID
+NetFlexDeferredTimer(
+ IN PVOID SystemSpecific1,
+ IN PACB acb,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+VOID
+NetFlexEnableInterrupt(
+ IN NDIS_HANDLE Context
+ );
+
+VOID
+NetFlexDisableInterrupt(
+ IN NDIS_HANDLE Context
+ );
+
+VOID
+NetFlexHalt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+VOID
+NetFlexShutdown(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+NDIS_STATUS
+NetFlexInitialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE ConfigurationHandle
+ );
+
+NDIS_STATUS
+NetFlexSetInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ );
+
+NDIS_STATUS
+NetFlexQueryInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+ );
+
+VOID
+NetFlexFinishQueryInformation(
+ PACB acb,
+ NDIS_STATUS Status
+ );
+
+NDIS_STATUS
+NetFlexResetDispatch(
+ OUT PBOOLEAN AddressingReset,
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+VOID
+NetFlexResetHandler(
+ IN PVOID SystemSpecific1,
+ IN PACB acb,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+NDIS_STATUS NetFlexSend(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET Packet,
+ IN UINT Flags
+ );
+
+NDIS_STATUS NetFlexTransferData(
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+ );
+
+NDIS_STATUS
+NetFlexRegisterAdapter(
+ PACB *acbp,
+ PACB FirstHeadsAcb,
+ NDIS_HANDLE ConfigurationHandle,
+ USHORT baseaddr,
+ NDIS_HANDLE MiniportAdapterHandle
+ );
+
+NDIS_STATUS
+NetFlexInitializeAcb(
+ PACB acb
+ );
+VOID
+NetFlexDeallocateAcb(
+ PACB acb);
+
+
+VOID
+NetFlexSendNextSCB(
+ PACB acb
+ );
+
+VOID
+NetFlexRemoveRequests(
+ PACB acb
+ );
+
+VOID
+NetFlexDoResetIndications(
+ IN PACB acb,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+NetFlexQueueSCB(
+ PACB acb,
+ PSCBREQ scbreq
+ );
+
+NDIS_STATUS
+NetFlexAdapterReset(
+ PACB acb,
+ INT mode
+ );
+
+NDIS_STATUS
+NetFlexBudWait(
+ PACB acb
+ );
+
+NDIS_STATUS
+NetFlexInitializeAdapter(
+ PACB acb
+ );
+
+NDIS_STATUS
+NetFlexProcessRequest(
+ PACB acb
+ );
+
+VOID
+NetFlexFinishUnloading(
+ VOID
+ );
+
+VOID
+NetFlexDeregisterAdapter(
+ PACB acb
+ );
+
+NDIS_STATUS
+NetFlexAsciiToHex(
+ PNDIS_STRING src,
+ PUCHAR dst,
+ USHORT dst_length
+ );
+
+VOID
+FASTCALL
+NetFlexProcessXmit(
+ PACB acb
+ );
+
+USHORT
+FASTCALL
+NetFlexProcessTrRcv(
+ PACB acb
+ );
+
+USHORT
+FASTCALL
+NetFlexProcessEthRcv(
+ PACB acb
+ );
+
+NDIS_STATUS
+NetFlexProcessSendQueue(
+ PACB acb
+ );
+
+NDIS_STATUS
+NetFlexProcessSend(
+ PACB acb,
+ PNDIS_PACKET Packet,
+ UINT PhysicalBufferCount,
+ UINT BufferCount,
+ PNDIS_BUFFER curbuf,
+ UINT TotalPacketLength
+ );
+
+VOID
+NetFlexGetUpstreamAddress(
+ PACB acb
+ );
+
+VOID
+NetFlexRingStatus(
+ PACB acb
+ );
+
+VOID
+NetFlexCommand(
+ PACB acb
+ );
+
+VOID
+NetFlexTransmitStatus(
+ PACB acb
+ );
+
+BOOLEAN
+NetFlexReset_Test(
+ PACB acb,
+ PMACREQ *resetreq
+ );
+
+VOID
+NetFlexProcessMacReq(
+ PACB acb
+ );
+
+NDIS_STATUS
+NetFlexValidateMulticasts(
+ PUCHAR multiaddrs,
+ USHORT multinumber
+ );
+
+NDIS_STATUS
+NetFlexOpenAdapter(
+ PACB acb
+ );
+
+
+BOOLEAN
+NetFlexCloseAdapter(
+ PACB acb
+ );
+
+NDIS_STATUS
+NetFlexInitGlobals(
+ );
+
+NDIS_STATUS
+NetFlexConstrainPacket(
+ PACB acb,
+ PXMIT xmitptr,
+ PNDIS_PACKET Packet,
+ UINT PhysicalBufferCount,
+ PNDIS_BUFFER curbuf,
+ UINT TotalPacketLength
+ );
+
+BOOLEAN
+NetFlexFindEntry(
+ PVOID head,
+ PVOID *back,
+ PVOID entry
+ );
+VOID
+NetFlexDequeue_OnePtrQ(
+ PVOID *head,
+ PVOID entry
+ );
+
+VOID
+NetFlexEnqueue_OnePtrQ_Head(
+ PVOID *head,
+ PVOID entry
+ );
+
+NDIS_STATUS
+NetFlexDequeue_OnePtrQ_Head(
+ PVOID *head,
+ PVOID *entry
+ );
+
+NDIS_STATUS
+NetFlexEnqueue_TwoPtrQ_Tail(
+ PVOID *head,
+ PVOID *tail,
+ PVOID entry
+ );
+
+VOID
+NetFlexDequeue_TwoPtrQ(
+ PVOID *head,
+ PVOID *tail,
+ PVOID entry
+ );
+
+NDIS_STATUS
+NetFlexDequeue_TwoPtrQ_Head(
+ PVOID *head,
+ PVOID *tail,
+ PVOID *entry
+ );
+
+//
+// Debug macros
+//
+
+#if (DBG || DBGPRINT)
+extern ULONG DebugLevel;
+
+
+VOID
+_DebugPrint(
+ PCCHAR DebugMessage,
+ ...
+ );
+
+#define DebugPrint(level, msg) \
+ if ((ULONG) level <= DebugLevel) \
+ _DebugPrint msg
+
+extern USHORT DisplayLists;
+VOID
+_DisplayXmitList(
+ PACB acb
+ );
+
+VOID
+_DisplayRcvList(
+ PACB acb
+ );
+
+#define DisplayXmitList(_acb) \
+ if (DisplayLists) \
+ _DisplayXmitList(_acb)
+
+#define DisplayRcvList(_acb) \
+ if (DisplayLists) \
+ _DisplayRcvList(_acb)
+
+#else
+
+#define DebugPrint(level, x)
+#define DisplayXmitList(x)
+#define DisplayRcvList(x)
+#endif // DBG
+
+
+#endif
diff --git a/private/ntos/ndis/netflex/receive.c b/private/ntos/ndis/netflex/receive.c
new file mode 100644
index 000000000..1219cb033
--- /dev/null
+++ b/private/ntos/ndis/netflex/receive.c
@@ -0,0 +1,633 @@
+//**********************************************************************
+//**********************************************************************
+//
+// File Name: RECEIVE.C
+//
+// Program Name: NetFlex NDIS 3.0 Miniport Driver
+//
+// Companion Files: None
+//
+// Function: This module contains the NetFlex Miniport Driver
+// interface routines called by the Wrapper and the
+// configuration manager.
+//
+// (c) Compaq Computer Corporation, 1992,1993,1994
+//
+// This file is licensed by Compaq Computer Corporation to Microsoft
+// Corporation pursuant to the letter of August 20, 1992 from
+// Gary Stimac to Mark Baber.
+//
+// History:
+//
+// 04/15/94 Robert Van Cleve - Converted from NDIS Mac Driver
+//
+//**********************************************************************
+//**********************************************************************
+
+
+//-------------------------------------
+// Include all general companion files
+//-------------------------------------
+
+#include <ndis.h>
+#include "tmsstrct.h"
+#include "macstrct.h"
+#include "adapter.h"
+#include "protos.h"
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexProcessRcv
+//
+// Description: This routine looks through the receive lists
+// looking for received packets. A receive
+// indication is given for each packet received
+//
+// Input: acb - Pointer to the Adapter's acb
+//
+// Output: true if we should indicaterecievecomplete
+//
+// Calls: NdisIndicateReceive
+//
+// Called_By: NetflxHandleInterrupt
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+USHORT
+FASTCALL
+NetFlexProcessEthRcv(
+ PACB acb
+ )
+{
+ PRCV rcvptr;
+ USHORT FrameSize;
+ USHORT ReceiveCount = 0;
+ PUCHAR Temp;
+
+#if (DBG || DBGPRINT)
+ BOOLEAN IsBroadcast;
+ PUCHAR SourceAddress;
+#endif
+
+ //
+ // While there is recieves to process...
+ //
+ rcvptr = acb->acb_rcv_head;
+
+ //
+ // Ensure that our Receive Entry is on an even boundary.
+ //
+ ASSERT(!(NdisGetPhysicalAddressLow(rcvptr->RCV_Phys) & 1));
+
+ do
+ {
+ //
+ // See if the recieve is on one list...
+ //
+ if ((rcvptr->RCV_CSTAT & (RCSTAT_EOF | RCSTAT_SOF)) == (RCSTAT_EOF | RCSTAT_SOF))
+ {
+ // Frame is on one list.
+ //
+ FrameSize = (USHORT)(SWAPS(rcvptr->RCV_Fsize));
+ rcvptr->RCV_HeaderLen = HDR_SIZE;
+
+ //
+ // Flush the receive buffer
+ //
+ NdisFlushBuffer(rcvptr->RCV_FlushBuffer, FALSE);
+
+#if (DBG || DBGPRINT)
+ SourceAddress = (PVOID)((PUCHAR)&(rcvptr->RCV_Buf) + 2);
+ IsBroadcast = ETH_IS_BROADCAST(SourceAddress); // works for eth & tr
+ if (IsBroadcast)
+ {
+ DebugPrint(3,("NF(%d): Recieved broadcast!\n",acb->anum));
+ }
+ else if (ETH_IS_MULTICAST(SourceAddress))
+ {
+ DebugPrint(3,("NF(%d): Recieved multicast!\n",acb->anum));
+ }
+#endif
+ //
+ // For speed...
+ //
+ Temp = (PUCHAR) rcvptr->RCV_Buf;
+
+ //
+ // Check for Runt or Normal Packet
+ //
+ if (FrameSize >= HDR_SIZE)
+ {
+ // Normal Packet
+ //
+ ReceiveCount++;
+ NdisMEthIndicateReceive(acb->acb_handle,
+ (NDIS_HANDLE)(((PUCHAR) Temp) + HDR_SIZE),
+ Temp,
+ (UINT)HDR_SIZE,
+ (((PUCHAR) Temp) + HDR_SIZE),
+ (UINT)(FrameSize - HDR_SIZE),
+ (UINT)(FrameSize - HDR_SIZE));
+
+ }
+ else if (FrameSize >= NET_ADDR_SIZE)
+ {
+ ReceiveCount++;
+ // Runt Packet
+ //
+ DebugPrint(1,("NF(%d) - Got Runt! len = %d\n",acb->anum,FrameSize));
+ NdisMEthIndicateReceive(acb->acb_handle,
+ (NDIS_HANDLE)(((PUCHAR) Temp) + HDR_SIZE),
+ Temp,
+ (UINT)FrameSize,
+ NULL,
+ 0,
+ 0);
+ }
+#if DBG
+ else
+ {
+ DebugPrint(1,("NF(%d) - Rec - Packetlen = %d",acb->anum,FrameSize));
+ }
+#endif
+
+ rcvptr->RCV_CSTAT =
+ ((rcvptr->RCV_Number % acb->RcvIntRatio) == 0) ? RCSTAT_GO_INT : RCSTAT_GO;
+ //
+ // Get next receive list
+ //
+ rcvptr = rcvptr->RCV_Next;
+ }
+ else
+ {
+ //
+ // Frame is too large. Release the frame.
+ //
+ acb->acb_gen_objs.frames_rcvd_err++;
+
+ DebugPrint(0,("Netflx: Receive Not on one list.\n"));
+
+ //
+ // Clean up the list making up this packet.
+ //
+ while (((rcvptr->RCV_CSTAT & (RCSTAT_EOF | RCSTAT_SOF)) != (RCSTAT_EOF | RCSTAT_SOF)) &&
+ ((rcvptr->RCV_CSTAT & RCSTAT_COMPLETE) != 0)
+ )
+ {
+ //
+ // Clean the list and set the FINT based on ratio.
+ //
+
+ rcvptr->RCV_CSTAT =
+ ((rcvptr->RCV_Number % acb->RcvIntRatio) == 0) ? RCSTAT_GO_INT : RCSTAT_GO;
+
+ rcvptr = rcvptr->RCV_Next;
+ }
+ }
+
+ //
+ // If we're processing too many, get out
+ //
+ if (ReceiveCount >= acb->acb_maxrcvs)
+ break;
+
+ } while (rcvptr->RCV_CSTAT & RCSTAT_COMPLETE);
+
+ //
+ // Update head pointer
+ //
+ acb->acb_rcv_head = rcvptr;
+
+ //
+ // Tell Adapter that there are more receives available
+ //
+ NdisRawWritePortUshort( acb->SifIntPort, (USHORT) SIFINT_RCVVALID);
+
+ //
+ // Update number of received frames
+ //
+ acb->acb_gen_objs.frames_rcvd_ok += ReceiveCount;
+
+ return(ReceiveCount);
+}
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexProcessTrRcv
+//
+// Description: This routine looks through the receive lists
+// looking for received packets. A receive
+// indication is given for each packet received.
+//
+// Input: acb - Pointer to the Adapter's acb
+//
+// Output: true if we should indicaterecievecomplete
+//
+// Calls: NdisIndicateReceive
+//
+// Called_By: NetflxHandleInterrupt
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+USHORT
+FASTCALL
+NetFlexProcessTrRcv(
+ PACB acb
+ )
+{
+ PRCV rcvptr;
+ USHORT FrameSize;
+ USHORT HeaderSize;
+ USHORT ReceiveCount = 0;
+ PUCHAR Temp;
+
+#if (DBG || DBGPRINT)
+ BOOLEAN IsBroadcast;
+ PUCHAR SourceAddress;
+#endif
+
+ //
+ // While there is recieves to process...
+ //
+ rcvptr = acb->acb_rcv_head;
+
+ //
+ // Ensure that our Receive Entry is on an even boundary.
+ //
+ ASSERT(!(NdisGetPhysicalAddressLow(rcvptr->RCV_Phys) & 1));
+
+ do
+ {
+ // See if the recieve is on one list...
+ //
+ if ((rcvptr->RCV_CSTAT & (RCSTAT_EOF | RCSTAT_SOF)) == (RCSTAT_EOF | RCSTAT_SOF))
+ {
+ // Frame is on one list.
+ //
+ FrameSize = (USHORT)(SWAPS(rcvptr->RCV_Fsize));
+
+ HeaderSize = HDR_SIZE;
+
+ //
+ // Flush the receive buffer
+ //
+ NdisFlushBuffer(rcvptr->RCV_FlushBuffer, FALSE);
+
+#if (DBG || DBGPRINT)
+ SourceAddress = (PVOID)((PUCHAR)&(rcvptr->RCV_Buf) + 2);
+
+ IsBroadcast = ETH_IS_BROADCAST(SourceAddress); // works for eth & tr
+ if (IsBroadcast)
+ {
+ DebugPrint(3,("NF(%d): Recieved broadcast!\n",acb->anum));
+ }
+ else
+ {
+ TR_IS_GROUP(SourceAddress,&IsBroadcast);
+ if (IsBroadcast)
+ {
+ DebugPrint(3,("NF(%d): Recieved TR Group!\n",acb->anum));
+ }
+ }
+
+ TR_IS_FUNCTIONAL(SourceAddress,&IsBroadcast);
+ if (IsBroadcast)
+ DebugPrint(2,("NF(%d): Recieved TR Fuctional!\n",acb->anum));
+#endif
+ //
+ // For speed...
+ //
+ Temp = (PUCHAR) rcvptr->RCV_Buf;
+
+ //
+ // Make sure we have at least the AC, FS, SRC & DST fields before
+ // looking at the source routing info.
+ //
+ if (FrameSize >= HeaderSize)
+ {
+ // Is the source routing bit is on?
+ //
+ if (Temp[8] & 0x80)
+ {
+ // Yes, figure out the size of the MAC Frame Header.
+ //
+ HeaderSize = (Temp[HDR_SIZE] & 0x1f) + HDR_SIZE;
+ rcvptr->RCV_HeaderLen = HeaderSize;
+ //
+ // Check for Runt or Normal Packet again...
+ //
+ if (FrameSize >= HeaderSize)
+ {
+ // Normal Packet
+ //
+ ReceiveCount++;
+
+ NdisMTrIndicateReceive(
+ acb->acb_handle,
+ (NDIS_HANDLE)(((PUCHAR) Temp) + HeaderSize),
+ Temp,
+ (UINT)HeaderSize,
+ (((PUCHAR) Temp) + HeaderSize),
+ (UINT)(FrameSize - HeaderSize),
+ (UINT)(FrameSize - HeaderSize));
+ }
+ else if (FrameSize >= NET_ADDR_SIZE)
+ {
+ // Runt Packet
+ //
+ ReceiveCount++;
+
+ DebugPrint(1,("NF(%d) - Got Runt - len = %d!\n",acb->anum,FrameSize));
+
+ NdisMTrIndicateReceive(
+ acb->acb_handle,
+ (NDIS_HANDLE)(((PUCHAR) Temp) + HeaderSize),
+ Temp,
+ (UINT)FrameSize,
+ NULL,
+ 0,
+ 0);
+ }
+ }
+ else
+ {
+ // No Source Routing info, but has Normal Packet Length
+ //
+ rcvptr->RCV_HeaderLen = HeaderSize;
+
+ ReceiveCount++;
+
+ NdisMTrIndicateReceive(
+ acb->acb_handle,
+ (NDIS_HANDLE)(((PUCHAR) Temp) + HeaderSize),
+ Temp,
+ (UINT)HeaderSize,
+ (((PUCHAR) Temp) + HeaderSize),
+ (UINT)(FrameSize - HeaderSize),
+ (UINT)(FrameSize - HeaderSize));
+ }
+ }
+ else
+ {
+ // No, Frame doesn't have AC, FC, SRC & DST.
+ // Is it bigger than net_addr_size?
+ //
+ if (FrameSize >= NET_ADDR_SIZE)
+ {
+ // Yes, so indicate Runt Packet
+ //
+ ReceiveCount++;
+
+ DebugPrint(1,("NF(%d) - Got Runt - len = %d!\n",acb->anum,FrameSize));
+
+ NdisMTrIndicateReceive(
+ acb->acb_handle,
+ (NDIS_HANDLE)(((PUCHAR) Temp) + HeaderSize),
+ Temp,
+ (UINT)FrameSize,
+ NULL,
+ 0,
+ 0);
+ }
+ }
+
+ rcvptr->RCV_CSTAT =
+ ((rcvptr->RCV_Number % acb->RcvIntRatio) == 0) ? RCSTAT_GO_INT : RCSTAT_GO;
+
+ //
+ // Get next receive list
+ //
+ rcvptr = rcvptr->RCV_Next;
+
+ }
+ else
+ {
+ // Frame is too large. Release the frame.
+ //
+ acb->acb_gen_objs.frames_rcvd_err++;
+ DebugPrint(0,("Netflx: Receive Not on one list.\n"));
+ //
+ // Clean up the list making up this packet.
+ //
+ while (((rcvptr->RCV_CSTAT & (RCSTAT_EOF | RCSTAT_SOF)) != (RCSTAT_EOF | RCSTAT_SOF)) &&
+ ((rcvptr->RCV_CSTAT & RCSTAT_COMPLETE) != 0))
+ {
+ // Clean the list and set the FINT based on ratio.
+ //
+ rcvptr->RCV_CSTAT =
+ ((rcvptr->RCV_Number % acb->RcvIntRatio) == 0) ? RCSTAT_GO_INT : RCSTAT_GO;
+
+ rcvptr = rcvptr->RCV_Next;
+ }
+ }
+
+ //
+ // If we're processing too many, get out
+ //
+ if (ReceiveCount >= acb->acb_maxrcvs)
+ break;
+
+ } while (rcvptr->RCV_CSTAT & RCSTAT_COMPLETE);
+
+ //
+ // Update head pointer
+ //
+ acb->acb_rcv_head = rcvptr;
+
+ //
+ // Tell Adapter that there are more receives available
+ //
+ NdisRawWritePortUshort( acb->SifIntPort, (USHORT) SIFINT_RCVVALID);
+
+ //
+ // Update number of recieved frames
+ //
+ acb->acb_gen_objs.frames_rcvd_ok += ReceiveCount;
+
+ return ReceiveCount;
+}
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexTransferData
+//
+// Description: This routine copies the received data into
+// a packet structure provided by the caller.
+//
+// Input:
+//
+// MiniportAdapterContext - The context value returned by the driver when the
+// adapter was initialized. In reality this is a pointer to NE3200_ADAPTER.
+//
+// MiniportReceiveContext - The context value passed by the driver on its call
+// to NdisMIndicateReceive. The driver can use this value to determine
+// which packet, on which adapter, is being received.
+//
+// ByteOffset - An unsigned integer specifying the offset within the
+// received packet at which the copy is to begin. If the entire packet
+// is to be copied, ByteOffset must be zero.
+//
+// BytesToTransfer - An unsigned integer specifying the number of bytes
+// to copy. It is legal to transfer zero bytes; this has no effect. If
+// the sum of ByteOffset and BytesToTransfer is greater than the size
+// of the received packet, then the remainder of the packet (starting from
+// ByteOffset) is transferred, and the trailing portion of the receive
+// buffer is not modified.
+//
+// Packet - A pointer to a descriptor for the packet storage into which
+// the MAC is to copy the received packet.
+//
+// BytesTransfered - A pointer to an unsigned integer. The MAC writes
+// the actual number of bytes transferred into this location. This value
+// is not valid if the return Status is STATUS_PENDING.
+//
+// Output:
+// Packet - Place to copy data.
+// BytesTransferred - Number of bytes copied.
+// Returns NDIS_STATUS_SUCCESS for a successful
+// completion. Otherwise, an error code is returned.
+//
+// Called By:
+// Miniport Wrapper
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+NDIS_STATUS
+NetFlexTransferData(
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+ )
+{
+ PACB acb = (PACB) MiniportAdapterContext;
+ PNDIS_BUFFER DestinationCurrentBuffer;
+ UINT DestinationBufferCount;
+ PUCHAR SourceCurrentAddress;
+ PVOID DestinationVirtualAddress;
+ UINT DestinationCurrentLength;
+ UINT LocalBytesTransferred = 0;
+ UINT AmountToMove;
+ UINT Remaining;
+
+ //
+ // Display number of bytes to transfer on the debugger
+ //
+ DebugPrint(2,("NF(%d) - Copying %u bytes\n",acb->anum,BytesToTransfer));
+
+ //
+ // Initialize the number of bytes transferred to 0
+ //
+ *BytesTransferred = 0;
+
+ //
+ // If we don't have any more to transfer, we're done
+ //
+ if (BytesToTransfer == 0)
+ {
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ //
+ // Get the first buffer of the destination.
+ //
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ &DestinationBufferCount,
+ &DestinationCurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet. If so, we are done.
+ //
+ if (DestinationBufferCount == 0)
+ {
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ //
+ // Get information on the buffer.
+ //
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+
+ //
+ // Set up the source address.
+ //
+ SourceCurrentAddress = (PCHAR)(MiniportReceiveContext) + ByteOffset;
+
+ //
+ // Do the actual transfer from source to destination
+ //
+ while (LocalBytesTransferred < BytesToTransfer)
+ {
+ // Check to see whether we've exhausted the current destination
+ // buffer. If so, move onto the next one.
+ //
+ if (DestinationCurrentLength == 0)
+ {
+ NdisGetNextBuffer(
+ DestinationCurrentBuffer,
+ &DestinationCurrentBuffer
+ );
+
+ if (DestinationCurrentBuffer == NULL)
+ {
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.)
+ //
+ break;
+ }
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+
+ continue;
+ }
+
+ //
+ // Copy the data.
+ //
+
+ Remaining = BytesToTransfer - LocalBytesTransferred;
+
+ AmountToMove = DestinationCurrentLength;
+
+ AmountToMove = ((Remaining < AmountToMove)?
+ (Remaining):(AmountToMove));
+
+ NdisMoveMemory(
+ DestinationVirtualAddress,
+ SourceCurrentAddress,
+ AmountToMove
+ );
+
+ //
+ // Update pointers and counters
+ //
+ SourceCurrentAddress += AmountToMove;
+ LocalBytesTransferred += AmountToMove;
+ DestinationCurrentLength -= AmountToMove;
+ }
+
+ //
+ // Indicate how many bytes were transferred
+ //
+ *BytesTransferred = LocalBytesTransferred;
+
+ //
+ // Display total bytes transferred on debugger
+ //
+ DebugPrint(2,("NF(%d) - Total bytes transferred = %x\n",acb->anum,*BytesTransferred));
+
+ return NDIS_STATUS_SUCCESS;
+}
diff --git a/private/ntos/ndis/netflex/request.c b/private/ntos/ndis/netflex/request.c
new file mode 100644
index 000000000..7188d17dd
--- /dev/null
+++ b/private/ntos/ndis/netflex/request.c
@@ -0,0 +1,2148 @@
+//**********************************************************************
+//**********************************************************************
+//
+// File Name: REQUEST.C
+//
+// Program Name: NetFlex NDIS 3.0 Miniport Driver
+//
+// Companion Files: None
+//
+// Function: This module contains the NetFlex Miniport Driver
+// interface routines called by the Wrapper and the
+// configuration manager.
+//
+// (c) Compaq Computer Corporation, 1992,1993,1994
+//
+// This file is licensed by Compaq Computer Corporation to Microsoft
+// Corporation pursuant to the letter of August 20, 1992 from
+// Gary Stimac to Mark Baber.
+//
+// History:
+//
+// 04/15/94 Robert Van Cleve - Converted from NDIS Mac Driver
+//
+//**********************************************************************
+//**********************************************************************
+
+
+//-------------------------------------
+// Include all general companion files
+//-------------------------------------
+#include <ndis.h>
+#include "tmsstrct.h"
+#include "macstrct.h"
+#include "adapter.h"
+#include "protos.h"
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexAddMulticasts
+//
+// Description:
+// This routine adds a Multicast address to
+// the adapter if it has not already been added.
+//
+// Input:
+// acb - Our Driver Context for this adapter or head.
+//
+// Output:
+//
+// Called By: NetFlexSetInformation
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+NDIS_STATUS NetFlexAddMulticasts(
+ PACB acb,
+ PSCBREQ *ScbHead,
+ PSCBREQ *ScbTail
+)
+{
+ NDIS_STATUS Status;
+ PETH_OBJS ethobjs;
+ PSCBREQ scbreq;
+ USHORT j;
+ PUCHAR addr;
+
+ //
+ // Set ethobjs to the special objects...
+ //
+ ethobjs = (PETH_OBJS)acb->acb_spec_objs;
+
+ //
+ // Loop through the multicast table, and send them to the card
+ //
+ for (j = 0; j < ethobjs->NumberOfEntries; j++)
+ {
+ //
+ // Get an SCB.
+ //
+ Status = NetFlexDequeue_OnePtrQ_Head(
+ (PVOID *)(&acb->acb_scbreq_free),
+ (PVOID *)&scbreq
+ );
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DebugPrint(
+ 0,
+ ("NF(%d): Add Multicast, Ran out of SCB's!\n",
+ acb->anum)
+ );
+
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // Add Multicast entry to card
+ //
+ addr = ethobjs->MulticastEntries + (j * NET_ADDR_SIZE);
+
+ DebugPrint(
+ 1, ("NF(%d): Adding %02x-%02x-%02x-%02x-%02x-%02x to Multicast Table\n",
+ acb->anum, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]));
+
+ scbreq->req_scb.SCB_Cmd = TMS_MULTICAST;
+ scbreq->req_macreq = NULL;
+ scbreq->req_multi.MB_Option = MPB_ADD_ADDRESS;
+ scbreq->req_multi.MB_Addr_Hi = *((PUSHORT) addr);
+ scbreq->req_multi.MB_Addr_Med = *((PUSHORT)(addr + 2));
+ scbreq->req_multi.MB_Addr_Lo = *((PUSHORT)(addr + 4));
+
+ //
+ // Queue the scb.
+ //
+ NetFlexEnqueue_TwoPtrQ_Tail(ScbHead, ScbTail, scbreq);
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexDeleteMulticast
+//
+// Description:
+// This routine removes the multicast address from the
+// enabled multicast lists.
+//
+// Input:
+// acb - Our Driver Context for this adapter or head.
+//
+// Output:
+// Status - SUCCESS | FAILURE
+//
+// Called By:
+// NetFlexSetInformation
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+NDIS_STATUS NetFlexDeleteMulticast(
+ PACB acb,
+ PSCBREQ *ScbHead,
+ PSCBREQ *ScbTail
+)
+{
+ NDIS_STATUS Status;
+ PSCBREQ scbreq;
+
+ DebugPrint(1, ("NF(%d): Delete Multicast Table\n", acb->anum));
+
+ //
+ // Get a free SCBReq block.
+ //
+ Status = NetFlexDequeue_OnePtrQ_Head(
+ (PVOID *)&(acb->acb_scbreq_free),
+ (PVOID *)&scbreq
+ );
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ // Queue SCB to process request
+ //
+ scbreq->req_scb.SCB_Cmd = TMS_MULTICAST;
+ scbreq->req_macreq = NULL;
+ scbreq->req_multi.MB_Option = MPB_CLEAR_ALL;
+
+ NetFlexEnqueue_TwoPtrQ_Tail(ScbHead, ScbTail, scbreq);
+ }
+ else
+ {
+ DebugPrint(0,("NF(%d): Delete Multicast Table, Ran out of SCB's!\n",acb->anum));
+ }
+
+ return(Status);
+}
+
+
+NDIS_STATUS PromiscuousFilterChanged(
+ PACB acb,
+ ULONG Filter,
+ PSCBREQ *ScbHead,
+ PSCBREQ *ScbTail
+)
+{
+ NDIS_STATUS Status;
+ PSCBREQ scbreq;
+ ULONG open_options;
+
+ // Modify the open options to set COPY ALL FRAMES (promiscuous)
+ //
+ Status = NetFlexDequeue_OnePtrQ_Head(
+ (PVOID *)&(acb->acb_scbreq_free),
+ (PVOID *)&scbreq
+ );
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Queue SCB to process request
+ //
+ scbreq->req_scb.SCB_Cmd = TMS_MODIFYOPEN;
+ scbreq->req_macreq = NULL;
+
+ //
+ // Set the open options for ethernet and token ring.
+ //
+ open_options = OOPTS_CNMAC;
+ if (acb->acb_gen_objs.media_type_in_use == NdisMedium802_5)
+ open_options |= OOPTS_CMAC;
+
+ //
+ // If we are turning it on, set the copy all frame bit
+ // bit, else turn it off.
+ //
+ if (Filter & NDIS_PACKET_TYPE_PROMISCUOUS)
+ {
+ //
+ // Turn on promiscuous mode.
+ //
+ acb->acb_opnblk_virtptr->OPEN_Options |= SWAPS((USHORT)open_options);
+ scbreq->req_scb.SCB_Ptr = acb->acb_opnblk_virtptr->OPEN_Options;
+
+ DebugPrint(1,("NF(%d): FilterChanged: Turn Promiscous Mode ON...\n",acb->anum));
+ acb->acb_promiscuousmode++;
+ }
+ else
+ {
+ //
+ // Turn off promiscuous mode.
+ //
+ acb->acb_opnblk_virtptr->OPEN_Options &= SWAPS((USHORT)~open_options);
+ scbreq->req_scb.SCB_Ptr = acb->acb_opnblk_virtptr->OPEN_Options;
+
+ DebugPrint(1,("NF(%d): FilterChanged: Turn Promiscous Mode OFF...\n",acb->anum));
+ acb->acb_promiscuousmode--;
+ }
+
+ //
+ // Queue the scb to be sent.
+ //
+ NetFlexEnqueue_TwoPtrQ_Tail(ScbHead, ScbTail, scbreq);
+ }
+ else
+ {
+ DebugPrint(0, ("NF(%d): Change Promiscuous mode, ran out of SCB's\n", acb->anum));
+ }
+
+ return(Status);
+}
+
+
+NDIS_STATUS AllMulticastFilterChanged(
+ PACB acb,
+ ULONG Filter,
+ PSCBREQ *ScbHead,
+ PSCBREQ *ScbTail
+)
+{
+ NDIS_STATUS Status;
+ PSCBREQ scbreq;
+ PETH_OBJS ethobjs = acb->acb_spec_objs;
+
+ //
+ // Get a free SCBReq block.
+ //
+ Status = NetFlexDequeue_OnePtrQ_Head(
+ (PVOID *)&(acb->acb_scbreq_free),
+ (PVOID *)&scbreq
+ );
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DebugPrint(0, ("NF(%d): AllMulticastFilterChanged(), Ran out of SCB's!\n",acb->anum));
+ return(Status);
+ }
+
+ //
+ // Turning All_Multicast On?
+ //
+ if (Filter & NDIS_PACKET_TYPE_ALL_MULTICAST)
+ {
+ DebugPrint(1,("NF(%d): FilterChanged: Turn ALL_Multicast ON...\n",acb->anum));
+
+ // Queue SCB to process request
+ //
+ scbreq->req_scb.SCB_Cmd = TMS_MULTICAST;
+ scbreq->req_macreq = NULL;
+ scbreq->req_multi.MB_Option = MPB_SET_ALL;
+
+ //
+ // Queue the scb to be sent.
+ //
+ NetFlexEnqueue_TwoPtrQ_Tail(ScbHead, ScbTail, scbreq);
+ }
+ else
+ {
+ // Turn All_Multicast Off.
+ //
+ DebugPrint(1,("NF(%d): FilterChanged: Turn ALL_Multicast OFF, delete all\n",acb->anum));
+
+ //
+ // Set up the scb to turn off ALL_MULTICAST.
+ //
+ scbreq->req_scb.SCB_Cmd = TMS_MULTICAST;
+ scbreq->req_macreq = NULL;
+ scbreq->req_multi.MB_Option = MPB_CLEAR_ALL;
+
+ //
+ // Queue the scb to be sent.
+ //
+ NetFlexEnqueue_TwoPtrQ_Tail(ScbHead, ScbTail, scbreq);
+
+ //
+ // Is Multicast on?
+ //
+ if (Filter & NDIS_PACKET_TYPE_MULTICAST)
+ {
+ //
+ // Yes, we need to re-enable all of the entries...
+ // The call to delete the multicast address above
+ // will determine if a completion is queued.
+ //
+ if (ethobjs->NumberOfEntries > 0)
+ NetFlexAddMulticasts(acb, ScbHead, ScbTail);
+ }
+ else
+ {
+ //
+ // Multicast isn't enabled, and we deleted them, so indicate
+ // that we also removed the multicast entries.
+ //
+ ethobjs->NumberOfEntries = 0;
+ }
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS MulticastFilterChanged(
+ PACB acb,
+ ULONG Filter,
+ PSCBREQ *ScbHead,
+ PSCBREQ *ScbTail
+)
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PSCBREQ scbreq;
+ PETH_OBJS ethobjs;
+
+ //
+ // If the ALL_MULTICAST filter bit is set then we don't need to
+ // turn on/off the MULTICAST crap. We will save the current filter
+ // options with the ACB in the calling routine so that we know
+ // to turn on the MULTICAST addresses when the ALL_MULTICAST bit
+ // is cleared.
+ //
+ if (Filter & NDIS_PACKET_TYPE_ALL_MULTICAST)
+ return(NDIS_STATUS_SUCCESS);
+
+ //
+ // Get a pointer to the ethernet objecst.
+ //
+ ethobjs = acb->acb_spec_objs;
+
+ //
+ // Are we turning the MULTICAST bit on or off?
+ //
+ if (Filter & NDIS_PACKET_TYPE_MULTICAST)
+ {
+ DebugPrint(1,("NF(%d): FilterChanged: Turn multicast ON...\n",acb->anum));
+
+ //
+ // Do we have any entries to enable?
+ //
+ if (ethobjs->NumberOfEntries > 0)
+ Status = NetFlexAddMulticasts(acb, ScbHead, ScbTail);
+ }
+ else
+ {
+ DebugPrint(1,("NF(%d): FilterChanged: Turn multicast OFF, delete all\n", acb->anum));
+
+ //
+ // Have any to delete?
+ //
+ if (ethobjs->NumberOfEntries > 0)
+ Status = NetFlexDeleteMulticast(acb, ScbHead, ScbTail);
+ }
+
+ return(Status);
+}
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexSetInformation
+//
+// Description:
+// NetFlexSetInformation handles a set operation for a
+// single OID.
+//
+// Input:
+// MiniportAdapterContext - Our Driver Context for
+// this adapter or head.
+//
+// Oid - The OID of the set.
+//
+// InformationBuffer - Holds the data to be set.
+//
+// InformationBufferLength - The length of InformationBuffer.
+//
+// Output:
+//
+// BytesRead - If the call is successful, returns the number
+// of bytes read from InformationBuffer.
+//
+// BytesNeeded - If there is not enough data in OvbBuffer
+// to satisfy the OID, returns the amount of
+// storage needed.
+// Status
+//
+// Called By:
+// Miniport Wrapper
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+NDIS_STATUS NetFlexSetInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+)
+{
+ ULONG value;
+ PMACREQ macreq;
+ PETH_OBJS ethobjs;
+ PTR_OBJS trobjs;
+ PSCBREQ scbreq;
+ PSCBREQ ScbHead = NULL;
+ PSCBREQ ScbTail = NULL;
+ ULONG Filter;
+ ULONG BadFilter;
+ BOOLEAN QueueCompletion = FALSE;
+ BOOLEAN QueueCleanup = FALSE;
+
+ PACB acb = (PACB) MiniportAdapterContext;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ *BytesRead = 0;
+ *BytesNeeded = 0;
+
+ if (acb->acb_state == AS_RESETTING)
+ {
+ return(NDIS_STATUS_RESET_IN_PROGRESS);
+ }
+
+ if (acb->RequestInProgress)
+ {
+ DebugPrint(0,("NF(%d): SetOID: Aready have RequestInProcess!\n",acb->anum));
+ return NDIS_STATUS_FAILURE;
+ }
+
+ acb->RequestInProgress = TRUE;
+
+ //
+ // Save the information about the request
+ //
+ acb->BytesRead = BytesRead;
+ acb->BytesNeeded = BytesNeeded;
+ acb->Oid = Oid;
+ acb->InformationBuffer = InformationBuffer;
+ acb->InformationBufferLength = InformationBufferLength;
+
+ switch (Oid)
+ {
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ if (InformationBufferLength != sizeof(ULONG))
+ {
+ DebugPrint(0,("NF(%d): Bad Packet Filter\n",acb->anum));
+ acb->RequestInProgress = FALSE;
+
+ return(NDIS_STATUS_INVALID_DATA);
+ }
+
+ Filter = *(PULONG)(InformationBuffer);
+ DebugPrint(1,("NF(%d): OidSet: GEN_CURRENT_PACKET_FILTER = %x\n",acb->anum,Filter));
+
+ //-------------------------------------------
+ // Filters Common to TokenRing and Ethernet
+ //-------------------------------------------
+
+#if (DBG || DBGPRINT)
+ if (Filter & NDIS_PACKET_TYPE_DIRECTED)
+ DebugPrint(1,("NF(%d): FilterChangeAction: Directed\n",acb->anum));
+#endif
+ //
+ // Verify Filter
+ //
+ if ( acb->acb_gen_objs.media_type_in_use == NdisMedium802_3)
+ {
+ //--------------------------------
+ // Ethernet Specific Filters...
+ //--------------------------------
+ //
+ // accept only the following:
+ //
+ BadFilter = (ULONG)~(NDIS_PACKET_TYPE_DIRECTED |
+ NDIS_PACKET_TYPE_MULTICAST |
+ NDIS_PACKET_TYPE_ALL_MULTICAST |
+ NDIS_PACKET_TYPE_BROADCAST |
+ (acb->FullDuplexEnabled ?
+ 0 : NDIS_PACKET_TYPE_PROMISCUOUS)
+ );
+ if (Filter & BadFilter)
+ {
+ DebugPrint(1,("NF(%d): PacketFilter Not Supported\n",acb->anum));
+
+ *BytesRead = sizeof(ULONG);
+ acb->RequestInProgress = FALSE;
+
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+
+ break;
+ }
+
+ //
+ // Did the state of the ALL_MULTICAST bit change?
+ //
+ if ((acb->acb_gen_objs.cur_filter & NDIS_PACKET_TYPE_ALL_MULTICAST) ^
+ (Filter & NDIS_PACKET_TYPE_ALL_MULTICAST)
+ )
+ {
+ Status = AllMulticastFilterChanged(
+ acb,
+ Filter,
+ &ScbHead,
+ &ScbTail
+ );
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ //
+ // We might need to cleanup the local
+ // queue of SCBs.
+ //
+ QueueCleanup = TRUE;
+ break;
+ }
+
+ //
+ // We successfully changed the ALL_MULTICAST bit.
+ //
+ QueueCompletion = TRUE;
+ }
+
+ //
+ // Did the state of the MULTICAST bit change?
+ //
+ if ((acb->acb_gen_objs.cur_filter & NDIS_PACKET_TYPE_MULTICAST) ^
+ (Filter & NDIS_PACKET_TYPE_MULTICAST)
+ )
+ {
+ Status = MulticastFilterChanged(
+ acb,
+ Filter,
+ &ScbHead,
+ &ScbTail
+ );
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ //
+ // We might need to cleanup the local
+ // queue of SCBs.
+ //
+ QueueCleanup = TRUE;
+ break;
+ }
+
+ //
+ // We successfully changed the MULTICAST bit.
+ //
+ QueueCompletion = TRUE;
+ }
+ }
+ else
+ {
+ //-------------------------------
+ // Token Ring Specific Filters...
+ //-------------------------------
+ //
+ // accept all of the following:
+ //
+ BadFilter = (ULONG)~(NDIS_PACKET_TYPE_FUNCTIONAL |
+ NDIS_PACKET_TYPE_ALL_FUNCTIONAL |
+ NDIS_PACKET_TYPE_GROUP |
+ NDIS_PACKET_TYPE_DIRECTED |
+ NDIS_PACKET_TYPE_BROADCAST |
+ NDIS_PACKET_TYPE_PROMISCUOUS
+ );
+ if (Filter & BadFilter)
+ {
+ DebugPrint(1,("NF(%d): PacketFilter Not Supported\n",acb->anum));
+
+ *BytesRead = sizeof(ULONG);
+
+ acb->RequestInProgress = FALSE;
+
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+
+ break;
+ }
+
+ //
+ // Are we turning the All Functional address filter on or off?
+ //
+ if (((acb->acb_gen_objs.cur_filter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL) ^
+ (Filter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL)) ||
+ ((acb->acb_gen_objs.cur_filter & NDIS_PACKET_TYPE_FUNCTIONAL) ^
+ (Filter & NDIS_PACKET_TYPE_FUNCTIONAL))
+ )
+ {
+ //
+ // We are changing it. Are we turning it on?
+ // Set functional address to all functional address
+ //
+ // Get a free SCBReq block.
+ //
+ Status = NetFlexDequeue_OnePtrQ_Head(
+ (PVOID *)&(acb->acb_scbreq_free),
+ (PVOID *)&scbreq
+ );
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // We failed to get an scb. We don't need
+ // to cleanup the scb queue since this is the
+ // first one.
+ //
+ break;
+ }
+
+ //
+ // Queue SCB to process request
+ //
+ scbreq->req_scb.SCB_Cmd = TMS_SETFUNCT;
+ scbreq->req_macreq = NULL;
+
+ //
+ // If we are turning it on, set the functional address
+ // to all ones, else set it to the acb's functional
+ // address.
+ //
+ if (Filter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL)
+ {
+ scbreq->req_scb.SCB_Ptr = SWAPL(0x7fffffff);
+ }
+ else
+ {
+ if (Filter & NDIS_PACKET_TYPE_FUNCTIONAL)
+ {
+ scbreq->req_scb.SCB_Ptr =
+ *((PLONG)(((PTR_OBJS)(acb->acb_spec_objs))->cur_func_addr));
+ }
+ else
+ {
+ //
+ // clear it
+ //
+ scbreq->req_scb.SCB_Ptr = 0;
+ }
+ }
+
+ DebugPrint(1,("NF(%d): FilterChanged: Setting Functional Address =0x%x\n",acb->anum,scbreq->req_scb.SCB_Ptr));
+
+ //
+ // Queue the scb.
+ //
+ NetFlexEnqueue_TwoPtrQ_Tail(&ScbHead, &ScbTail, scbreq);
+
+ //
+ // Indicate we need to QueueCompletion MacReq
+ //
+ QueueCompletion = TRUE;
+ }
+
+ //
+ // Changing Group?
+ //
+ if ((acb->acb_gen_objs.cur_filter & NDIS_PACKET_TYPE_GROUP) ^
+ (Filter & NDIS_PACKET_TYPE_GROUP)
+ )
+ {
+ // Get a free SCBReq block.
+ //
+ Status = NetFlexDequeue_OnePtrQ_Head(
+ (PVOID *)&(acb->acb_scbreq_free),
+ (PVOID *)&scbreq
+ );
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // We might need to cleanup the local
+ // queue of SCBs.
+ //
+ QueueCleanup = TRUE;
+
+ break;
+ }
+
+ //
+ // Queue SCB to process request
+ //
+ scbreq->req_scb.SCB_Cmd = TMS_SETGROUP;
+ scbreq->req_macreq = NULL;
+
+ //
+ // Set or Clear the Group Address?
+ //
+ if (Filter & NDIS_PACKET_TYPE_GROUP)
+ {
+ scbreq->req_scb.SCB_Ptr =
+ *((PLONG)(((PTR_OBJS)(acb->acb_spec_objs))->cur_grp_addr));
+ }
+ else
+ {
+ scbreq->req_scb.SCB_Ptr = 0;
+ }
+
+ DebugPrint(1,("NF(%d): FilterChanged: Setting Group Address =0x%x\n",acb->anum,scbreq->req_scb.SCB_Ptr));
+
+ //
+ // Queue the scb.
+ //
+ NetFlexEnqueue_TwoPtrQ_Tail(&ScbHead, &ScbTail, scbreq);
+
+ //
+ // Indicate we need to QueueCompletion MacReq
+ //
+ QueueCompletion = TRUE;
+ }
+ }
+
+ //
+ // Did the state of the PROMISCUOUS flag change?
+ //
+ if ((acb->acb_gen_objs.cur_filter & NDIS_PACKET_TYPE_PROMISCUOUS) ^
+ (Filter & NDIS_PACKET_TYPE_PROMISCUOUS)
+ )
+ {
+ Status = PromiscuousFilterChanged(
+ acb,
+ Filter,
+ &ScbHead,
+ &ScbTail
+ );
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ //
+ // We might need to cleanup the local
+ // queue of SCBs.
+ //
+ QueueCleanup = TRUE;
+ break;
+ }
+
+ //
+ // We successfully changed the PROMISCUOUS bit.
+ //
+ QueueCompletion = TRUE;
+ }
+
+ acb->acb_gen_objs.cur_filter = Filter;
+ *BytesRead = InformationBufferLength;
+
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+
+ //
+ // Is the adapter setup for token ring?
+ //
+ if (acb->acb_gen_objs.media_type_in_use == NdisMedium802_5 )
+ {
+ //
+ // Token ring does not support multicast.
+ //
+ DebugPrint(0,("NF(%d): MULTICAST LIST INVALID OID\n",acb->anum));
+ *BytesRead = 0;
+ acb->RequestInProgress = FALSE;
+
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+
+ break;
+ }
+
+ if (InformationBufferLength % NET_ADDR_SIZE != 0)
+ {
+ //
+ // The data must be a multiple of the Ethernet address size.
+ //
+ DebugPrint(0,("NF(%d): MULTICAST LIST INVALID LENGTH\n",acb->anum));
+
+ *BytesNeeded = InformationBufferLength + (NET_ADDR_SIZE - (InformationBufferLength % NET_ADDR_SIZE));
+ acb->RequestInProgress = FALSE;
+
+ Status = NDIS_STATUS_INVALID_DATA;
+
+ break;
+ }
+
+ //
+ // Get a pointer to the ethernet objects.
+ //
+ ethobjs = (PETH_OBJS)(acb->acb_spec_objs);
+ scbreq = NULL;
+
+ value = (InformationBufferLength / NET_ADDR_SIZE );
+
+ if (value > ethobjs->MaxMulticast)
+ {
+ DebugPrint(0,("NF(%d): TOO MANY MULTICAST ADDRESSES\n",acb->anum));
+
+ //
+ // There are too many, but add as many as we can.
+ //
+ acb->RequestInProgress = FALSE;
+
+ Status = NDIS_STATUS_MULTICAST_FULL;
+
+ break;
+ }
+
+ DebugPrint(1, ("NF(%d): Saving multicast address\n", acb->anum));
+
+ //
+ // Save entries in the table.
+ //
+ NdisMoveMemory(
+ ethobjs->MulticastEntries,
+ InformationBuffer,
+ value * NET_ADDR_SIZE
+ );
+
+ //
+ // If we have any entries enabled, delete them,
+ // unless NDIS_PACKET_TYPE_ALL_MULTICAST is set.
+ //
+ if (!(acb->acb_gen_objs.cur_filter & NDIS_PACKET_TYPE_ALL_MULTICAST) &&
+ (ethobjs->NumberOfEntries > 0)
+ )
+ {
+ //
+ // Get a free SCBReq block.
+ //
+ Status = NetFlexDequeue_OnePtrQ_Head(
+ (PVOID *)&(acb->acb_scbreq_free),
+ (PVOID *)&scbreq
+ );
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DebugPrint(0,("NF(%d): MULTICAST_LIST: out of SCBs\n", acb->anum));
+
+ //
+ // Since this is the first SCB, and it failed,
+ // we don't need to clean up.
+ //
+ break;
+ }
+
+ DebugPrint(1,("NF(%d): MULTICAST_LIST: clearing current list\n", acb->anum));
+
+ // Queue SCB to process request
+ //
+ scbreq->req_scb.SCB_Cmd = TMS_MULTICAST;
+ scbreq->req_macreq = NULL;
+ scbreq->req_multi.MB_Option = MPB_CLEAR_ALL;
+
+ //
+ // Queue the scb.
+ //
+ NetFlexEnqueue_TwoPtrQ_Tail(&ScbHead, &ScbTail, scbreq);
+
+ //
+ // Indicate we need to a Queue MacReq Completion
+ //
+ QueueCompletion = TRUE;
+ }
+
+ //
+ // Save number of entrys
+ //
+ ethobjs->NumberOfEntries = (SHORT)value;
+
+ //
+ // If filter has NDIS_PACKET_TYPE_MULTICAST, but NOT
+ // NDIS_PACKET_TYPE_ALL_MULTICAST, then enable these entries now.
+ //
+ if ((acb->acb_gen_objs.cur_filter & NDIS_PACKET_TYPE_MULTICAST) &&
+ !(acb->acb_gen_objs.cur_filter & NDIS_PACKET_TYPE_ALL_MULTICAST)
+ )
+ {
+ if (ethobjs->NumberOfEntries > 0)
+ {
+ Status = NetFlexAddMulticasts(acb, &ScbHead, &ScbTail);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Cleanup the local SCB queue.
+ //
+ QueueCleanup = TRUE;
+ break;
+ }
+
+ //
+ // Indicate we need to a Queue MacReq Completion
+ //
+ QueueCompletion = TRUE;
+ }
+ }
+
+ *BytesRead = InformationBufferLength;
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ //
+ // We don't set anything, just return ok. - RVC true?
+ //
+ *BytesRead = 4;
+ Status = NDIS_STATUS_SUCCESS;
+ DebugPrint(1,("NF(%d): OID_GEN_CURRENT_LOOKAHEAD...\n",acb->anum));
+
+ break;
+
+
+ case OID_802_5_CURRENT_FUNCTIONAL:
+ if (acb->acb_gen_objs.media_type_in_use == NdisMedium802_3)
+ {
+ //
+ // If we are running Ethernet, a call for this oid is an error.
+ //
+ acb->RequestInProgress = FALSE;
+
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+
+ break;
+ }
+
+ if (InformationBufferLength != TR_LENGTH_OF_FUNCTIONAL )
+ {
+ DebugPrint(0,("NF(%d): Oid_Set Functional Address bad\n",acb->anum));
+ *BytesNeeded = TR_LENGTH_OF_FUNCTIONAL - InformationBufferLength;
+
+ acb->RequestInProgress = FALSE;
+
+ Status = NDIS_STATUS_INVALID_LENGTH;
+
+ break;
+ }
+
+ //
+ // Get the oid info.
+ //
+ NdisMoveMemory(
+ (PVOID)&value,
+ InformationBuffer,
+ TR_LENGTH_OF_FUNCTIONAL
+ );
+
+ //
+ // Get a pointer to the token ring objects.
+ //
+ trobjs = (PTR_OBJS)(acb->acb_spec_objs);
+
+ *((PULONG)(trobjs->cur_func_addr)) = value;
+
+ DebugPrint(1,("NF(%d): OidSet Functional Address = %08x\n",acb->anum,value));
+
+ //
+ // Update filter if the funcational address has been set in
+ // the packet filter.
+ //
+ if (!(acb->acb_gen_objs.cur_filter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL) &&
+ (acb->acb_gen_objs.cur_filter & NDIS_PACKET_TYPE_FUNCTIONAL)
+ )
+ {
+ //
+ // Get an scb.
+ //
+ Status = NetFlexDequeue_OnePtrQ_Head(
+ (PVOID *)&(acb->acb_scbreq_free),
+ (PVOID *)&scbreq
+ );
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ scbreq->req_scb.SCB_Cmd = TMS_SETFUNCT;
+ scbreq->req_macreq = NULL;
+ scbreq->req_scb.SCB_Ptr = value;
+
+ //
+ // Queue the scb.
+ //
+ NetFlexEnqueue_TwoPtrQ_Tail(&ScbHead, &ScbTail, scbreq);
+
+ QueueCompletion = TRUE;
+ }
+ }
+
+ *BytesRead = TR_LENGTH_OF_FUNCTIONAL;
+ break;
+
+ case OID_802_5_CURRENT_GROUP:
+ if (acb->acb_gen_objs.media_type_in_use == NdisMedium802_3 )
+ {
+ // If we are running Ethernet, a call for this oid is an error.
+ //
+ acb->RequestInProgress = FALSE;
+
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+
+ break;
+ }
+
+ if (InformationBufferLength != TR_LENGTH_OF_FUNCTIONAL)
+ {
+ DebugPrint(0,("NF(%d): OidSet Group Address BAD\n",acb->anum));
+ *BytesNeeded = TR_LENGTH_OF_FUNCTIONAL - InformationBufferLength;
+
+ acb->RequestInProgress = FALSE;
+ Status = NDIS_STATUS_INVALID_LENGTH;
+
+ break;
+ }
+
+ NdisMoveMemory(
+ (PVOID)&value,
+ InformationBuffer,
+ TR_LENGTH_OF_FUNCTIONAL
+ );
+
+ trobjs = (PTR_OBJS)(acb->acb_spec_objs);
+
+ *((PULONG)(trobjs->cur_grp_addr)) = value;
+
+ DebugPrint(1,("NF(%d): OidSet Group Address = %08x\n",acb->anum,value));
+
+ //
+ // Update filter if the group address has been set in
+ // the packet filter.
+ //
+ if ((acb->acb_gen_objs.cur_filter & NDIS_PACKET_TYPE_GROUP) != 0)
+ {
+ Status = NetFlexDequeue_OnePtrQ_Head(
+ (PVOID *)&(acb->acb_scbreq_free),
+ (PVOID *)&scbreq
+ );
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ scbreq->req_scb.SCB_Cmd = TMS_SETGROUP;
+ scbreq->req_macreq = NULL;
+ scbreq->req_scb.SCB_Ptr = value;
+
+ //
+ // Queue the scb.
+ //
+ NetFlexEnqueue_TwoPtrQ_Tail(&ScbHead, &ScbTail, scbreq);
+
+ QueueCompletion = TRUE;
+ }
+ }
+
+ *BytesRead = TR_LENGTH_OF_FUNCTIONAL;
+ break;
+
+ default:
+
+ Status = NDIS_STATUS_INVALID_OID;
+ break;
+
+ }
+
+ if (QueueCleanup)
+ {
+ DebugPrint(1,("NF(%d): Error Setting OID (0x%x)\n",acb->anum, Oid));
+
+ //
+ // There was an error trying to get sufficent SCBs to
+ // complete the request.
+ //
+ while (ScbHead != NULL)
+ {
+ NetFlexDequeue_OnePtrQ_Head(&ScbHead, &scbreq);
+
+ NetFlexEnqueue_OnePtrQ_Head(
+ (PVOID *)&acb->acb_scbreq_free,
+ scbreq
+ );
+ }
+
+ QueueCompletion = FALSE;
+ }
+
+ if (QueueCompletion)
+ {
+ //
+ // Was there actually an scb queued?
+ //
+ if (NULL != ScbHead)
+ {
+ //
+ // We should have a local list of scb's to send.
+ //
+ do
+ {
+ //
+ // Get a pointer to the next scb to process.
+ //
+ scbreq = ScbHead->req_next;
+
+ //
+ // Are we on the last scb?
+ //
+ if (NULL == scbreq)
+ {
+ //
+ // Get a mac request in case we need the completeion
+ //
+ NetFlexDequeue_OnePtrQ_Head(
+ (PVOID *)&(acb->acb_macreq_free),
+ (PVOID *)&macreq
+ );
+
+ //
+ // Initialize the completion request.
+ //
+ macreq->req_next = NULL;
+ macreq->req_type = REQUEST_CMP;
+ macreq->req_status = NDIS_STATUS_SUCCESS;
+
+ //
+ // Setup the last scb to be sent to the card.
+ //
+ ScbHead->req_macreq = macreq;
+
+ //
+ // put the macreq on the macreq queue
+ //
+ NetFlexEnqueue_TwoPtrQ_Tail(
+ (PVOID *)&(acb->acb_macreq_head),
+ (PVOID *)&(acb->acb_macreq_tail),
+ (PVOID)macreq
+ );
+ }
+
+ //
+ // Send the scb down to the card
+ //
+ NetFlexQueueSCB(acb, ScbHead);
+
+ ScbHead = scbreq;
+
+ } while (NULL != scbreq);
+
+ return(NDIS_STATUS_PENDING);
+ }
+ }
+
+ //
+ // Request was aborted due to error.
+ //
+ acb->RequestInProgress = FALSE;
+
+ return(Status);
+}
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexQueryInformation
+//
+// Description:
+// The NetFlexQueryInformation process a Query request for
+// NDIS_OIDs that are specific about the Driver.
+//
+// Input:
+// MiniportAdapterContext - Our Driver Context for this
+// adapter or head.
+//
+// Oid - the NDIS_OID to process.
+//
+// InformationBuffer - a pointer into the NdisRequest->InformationBuffer
+// into which store the result of the query.
+//
+// InformationBufferLength - a pointer to the number of bytes left in the
+// InformationBuffer.
+//
+// Output:
+// BytesWritten - a pointer to the number of bytes written into the
+// InformationBuffer.
+//
+// BytesNeeded - If there is not enough room in the information buffer
+// then this will contain the number of bytes needed to complete the
+// request.
+//
+// Status - The function value is the Status of the operation.
+//
+// Called By:
+// Miniport Wrapper
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+NDIS_STATUS
+NetFlexQueryInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+)
+{
+ PACB acb = (PACB) MiniportAdapterContext;
+ PMACREQ macreq;
+ ULONG lvalue;
+ USHORT svalue;
+ PTR_OBJS trobjs;
+ PETH_OBJS ethobjs;
+ PUCHAR srcptr;
+ PUCHAR copyptr = NULL;
+ PSCBREQ scbreq;
+ UCHAR vendorid[4];
+ SHORT copylen = (SHORT)sizeof(ULONG); // Most common length
+
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ BOOLEAN needcopy = TRUE;
+
+ if (acb->acb_state == AS_RESETTING)
+ {
+ return(NDIS_STATUS_RESET_IN_PROGRESS);
+ }
+
+ //
+ // Initialize the result
+ //
+ *BytesWritten = 0;
+ *BytesNeeded = 0;
+
+ //
+ // General Objects Characteristics
+ //
+
+ switch (Oid)
+ {
+ case OID_GEN_SUPPORTED_LIST:
+ copyptr = (PUCHAR)acb->acb_gbl_oid_list;
+ copylen = (SHORT)acb->acb_gbl_oid_list_size;
+ DebugPrint(2,("NF: Query OID_GEN_SUPPORTED_LIST...\n",acb->anum));
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+ lvalue = NdisHardwareStatusNotReady;
+ switch (acb->acb_state)
+ {
+ case AS_OPENED:
+ lvalue = NdisHardwareStatusReady;
+ DebugPrint(1,("NF(%d):Query HW Status - AS_OPENED\n",acb->anum));
+ break;
+ case AS_CLOSING:
+ lvalue = NdisHardwareStatusClosing;
+ DebugPrint(1,("NF(%d):Query HW Status - AS_CLOSING\n",acb->anum));
+ break;
+ case AS_RESETTING:
+ case AS_RESET_HOLDING:
+ DebugPrint(1,("NF(%d):Query HW Status - AS_RESETTING\n",acb->anum));
+ lvalue = NdisHardwareStatusReset;
+ break;
+ case AS_INITIALIZING:
+ DebugPrint(1,("NF(%d):Query HW Status - AS_INITIALIZING\n",acb->anum));
+ lvalue = NdisHardwareStatusInitializing;
+ break;
+ default:
+ DebugPrint(1,("NF(%d):NetFlexQueryInformation: Undefinded State - 0x%x",acb->anum,acb->acb_state));
+ break;
+ }
+ copyptr = (PUCHAR)&lvalue;
+ DebugPrint(2,("NF(%d): Query OID_GEN_HARDWARE_STATUS 0x%x...\n",acb->anum,lvalue));
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+ copyptr = (PUCHAR)&acb->acb_gen_objs.media_type_in_use;
+ DebugPrint(2,("NF(%d): Query OID_GEN_MEDIA_IN_USE 0x%x...\n",acb->anum,
+ acb->acb_gen_objs.media_type_in_use));
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+ copyptr = (PUCHAR)&acb->acb_gen_objs.max_frame_size;
+ break;
+
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+ // Frame size is the max frame size minus the minimum header size.
+ //
+ lvalue = acb->acb_gen_objs.max_frame_size - 14;
+ copyptr = (PUCHAR)&lvalue;
+ break;
+
+ case OID_GEN_LINK_SPEED:
+ lvalue = acb->acb_gen_objs.link_speed * 10000;
+ copyptr = (PUCHAR)&lvalue;
+ break;
+
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+ lvalue = acb->acb_gen_objs.max_frame_size * acb->acb_maxtrans;
+ copyptr = (PUCHAR)&lvalue;
+ break;
+
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+ lvalue = acb->acb_gen_objs.max_frame_size * acb->acb_maxrcvs;
+ copyptr = (PUCHAR)&lvalue;
+ break;
+
+ case OID_GEN_VENDOR_ID:
+ NdisMoveMemory(vendorid,acb->acb_gen_objs.perm_staddr,3);
+ vendorid[3] = 0x0;
+ copyptr = (PUCHAR)vendorid;
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+ copyptr = (PUCHAR)"Compaq NetFlex Driver, Version 1.10"; // RVC: move to string...
+ copylen = (USHORT)36;
+ break;
+
+ case OID_GEN_DRIVER_VERSION:
+ svalue = 0x0300;
+ copyptr = (PUCHAR)&svalue;
+ copylen = (SHORT)sizeof(USHORT);
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ lvalue = acb->acb_gen_objs.cur_filter;
+ copyptr = (PUCHAR)&lvalue;
+ DebugPrint(2,("NF(%d): Query OID_GEN_CURRENT_PACKET_FILTER = 0x%x\n",acb->anum,lvalue));
+ break;
+
+ case OID_GEN_MAC_OPTIONS:
+ lvalue = NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
+ NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
+ NDIS_MAC_OPTION_RECEIVE_SERIALIZED;
+
+ //
+ // Indicate we need loop back if running Full Duplex
+ //
+ if (acb->FullDuplexEnabled)
+ {
+ lvalue |= NDIS_MAC_OPTION_NO_LOOPBACK |
+ NDIS_MAC_OPTION_FULL_DUPLEX;
+ }
+ copyptr = (PUCHAR)&lvalue;
+ break;
+
+ //
+ // GENERAL STATISTICS (Mandatory)
+ //
+
+ case OID_GEN_XMIT_OK:
+ copyptr = (PUCHAR)&acb->acb_gen_objs.frames_xmitd_ok;
+ break;
+
+ case OID_GEN_RCV_OK:
+ copyptr = (PUCHAR)&acb->acb_gen_objs.frames_rcvd_ok;
+ break;
+
+ case OID_GEN_XMIT_ERROR:
+ copyptr = (PUCHAR)&acb->acb_gen_objs.frames_xmitd_err;
+ break;
+
+ case OID_GEN_RCV_ERROR:
+ copyptr = (PUCHAR)&acb->acb_gen_objs.frames_rcvd_err;
+ break;
+
+ case OID_NF_INTERRUPT_COUNT:
+ copyptr = (PUCHAR)&acb->acb_gen_objs.interrupt_count;
+ break;
+
+ case OID_NF_INTERRUPT_RATIO:
+ copyptr = (PUCHAR)&acb->RcvIntRatio;
+ break;
+
+ case OID_NF_INTERRUPT_RATIO_CHANGES:
+ copyptr = (PUCHAR)&acb->acb_gen_objs.interrupt_ratio_changes;
+ break;
+
+ } // end of general
+
+ if (copyptr == NULL)
+ {
+ if (acb->acb_gen_objs.media_type_in_use == NdisMedium802_3 )
+ {
+ //---------------------------------------
+ // Ethernet Specific Oid's
+ //---------------------------------------
+ //
+
+ switch (Oid)
+ {
+ //-------------------------------------
+ // 802.3 OPERATIONAL CHARACTERISTICS
+ //-------------------------------------
+
+ case OID_802_3_PERMANENT_ADDRESS:
+ srcptr = acb->acb_gen_objs.perm_staddr;
+ copyptr = (PUCHAR)srcptr;
+ copylen = (SHORT)NET_ADDR_SIZE;
+
+ case OID_802_3_CURRENT_ADDRESS:
+ srcptr = acb->acb_gen_objs.current_staddr;
+ copyptr = (PUCHAR)srcptr;
+ copylen = (SHORT)NET_ADDR_SIZE;
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+ DebugPrint(2,("NF(%d): Query OID_802_3_MULTICAST_LIST\n",acb->anum));
+ ethobjs = (PETH_OBJS)(acb->acb_spec_objs);
+
+ needcopy = TRUE;
+ copylen = ethobjs->NumberOfEntries * NET_ADDR_SIZE;
+ copyptr = (PVOID) &ethobjs->NumberOfEntries;
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+ ethobjs = (PETH_OBJS)(acb->acb_spec_objs);
+ lvalue = ethobjs->MaxMulticast;
+ copyptr = (PUCHAR)&lvalue;
+ DebugPrint(2,("NF(%d): Query OID_802_3_MAXIMUM_LIST_SIZE = 0x%x\n",acb->anum,lvalue));
+ break;
+
+ //-------------------------------
+ // 802.3 STATISTICS (Mandatory)
+ //-------------------------------
+
+ case OID_GEN_RCV_NO_BUFFER:
+ lvalue = 0;
+ copyptr = (PUCHAR)&lvalue;
+ break;
+
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+ case OID_802_3_XMIT_ONE_COLLISION:
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+ case OID_802_3_XMIT_DEFERRED:
+ case OID_802_3_XMIT_LATE_COLLISIONS:
+ case OID_802_3_XMIT_MAX_COLLISIONS:
+ case OID_802_3_XMIT_TIMES_CRS_LOST:
+ case OID_GEN_RCV_CRC_ERROR:
+ if (acb->acb_logbuf_valid)
+ {
+ ethobjs = (PETH_OBJS)(acb->acb_spec_objs);
+
+ switch (Oid)
+ {
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+ lvalue = ethobjs->RSL_AlignmentErr;
+ break;
+ case OID_802_3_XMIT_ONE_COLLISION:
+ lvalue = ethobjs->RSL_1_Collision;
+ break;
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+ lvalue = ethobjs->RSL_More_Collision;
+ break;
+ case OID_802_3_XMIT_DEFERRED:
+ lvalue = ethobjs->RSL_DeferredXmit;
+ break;
+ case OID_802_3_XMIT_LATE_COLLISIONS:
+ lvalue = ethobjs->RSL_LateCollision;
+ break;
+ case OID_802_3_XMIT_MAX_COLLISIONS:
+ case OID_802_3_XMIT_TIMES_CRS_LOST:
+ lvalue = ethobjs->RSL_Excessive;
+ break;
+ default:
+ lvalue = ethobjs->RSL_FrameCheckSeq;
+ break;
+ }
+ copyptr = (PUCHAR)&lvalue;
+ }
+ else
+ {
+ needcopy = FALSE;
+ Status = NetFlexDequeue_OnePtrQ_Head(
+ (PVOID *)&(acb->acb_scbreq_free),
+ (PVOID *)&scbreq);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ // Save the information about the request
+ //
+ if (acb->RequestInProgress)
+ {
+ DebugPrint(0,("NF(%d): Query OID: Aready have RequestInProcess!\n",acb->anum));
+ // return NDIS_STATUS_FAILURE;
+ }
+
+ acb->RequestInProgress = TRUE;
+
+ acb->BytesWritten = BytesWritten;
+ acb->BytesNeeded = BytesNeeded;
+ acb->Oid = Oid;
+ acb->InformationBuffer = InformationBuffer;
+ acb->InformationBufferLength = InformationBufferLength;
+
+ DebugPrint(2,("NF(%d): Queue Up Request to get OID (0x%x) info\n",acb->anum,Oid));
+
+ NetFlexDequeue_OnePtrQ_Head( (PVOID *)&(acb->acb_macreq_free),
+ (PVOID *)&macreq);
+ macreq->req_next = NULL;
+ macreq->req_type = QUERY_CMP;
+ macreq->req_status = NDIS_STATUS_SUCCESS;
+
+ scbreq->req_scb.SCB_Cmd = TMS_READLOG;
+ scbreq->req_macreq = macreq;
+ scbreq->req_scb.SCB_Ptr = SWAPL(CTRL_ADDR(NdisGetPhysicalAddressLow(acb->acb_logbuf_physptr)));
+
+ //
+ // put the macreq on the macreq queue
+ //
+ NetFlexEnqueue_TwoPtrQ_Tail( (PVOID *)&(acb->acb_macreq_head),
+ (PVOID *)&(acb->acb_macreq_tail),
+ (PVOID)macreq);
+
+ NetFlexQueueSCB(acb, scbreq);
+ Status = NDIS_STATUS_PENDING;
+ }
+ }
+ break;
+
+ default:
+ DebugPrint(1,("NF(%d): (ETH) Invalid Query or Unsupported OID, %x\n",acb->anum,Oid));
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ needcopy = FALSE;
+ break;
+ }
+ }
+ else
+ {
+ //---------------------------------------
+ // Token Ring Specific Oid's
+ //---------------------------------------
+ //
+ switch (Oid)
+ {
+ // We added the 802.5 stats here as well because of the
+ // read error log buffer.
+ //
+ case OID_802_5_LINE_ERRORS:
+ case OID_802_5_LOST_FRAMES:
+ case OID_802_5_BURST_ERRORS:
+ case OID_802_5_AC_ERRORS:
+ case OID_802_5_CONGESTION_ERRORS:
+ case OID_802_5_FRAME_COPIED_ERRORS:
+ case OID_802_5_TOKEN_ERRORS:
+ case OID_GEN_RCV_NO_BUFFER:
+ if (acb->acb_logbuf_valid)
+ {
+ trobjs = (PTR_OBJS)(acb->acb_spec_objs);
+ switch (Oid)
+ {
+ case OID_GEN_RCV_NO_BUFFER:
+ lvalue = trobjs->REL_Congestion;
+ break;
+ case OID_802_5_LINE_ERRORS:
+ lvalue = trobjs->REL_LineError;
+ break;
+ case OID_802_5_LOST_FRAMES:
+ lvalue = trobjs->REL_LostError;
+ break;
+ case OID_802_5_BURST_ERRORS:
+ lvalue = trobjs->REL_BurstError;
+ break;
+ case OID_802_5_AC_ERRORS:
+ lvalue = trobjs->REL_ARIFCIError;
+ break;
+ case OID_802_5_CONGESTION_ERRORS:
+ lvalue = trobjs->REL_Congestion;
+ break;
+ case OID_802_5_FRAME_COPIED_ERRORS:
+ lvalue = trobjs->REL_CopiedError;
+ break;
+ case OID_802_5_TOKEN_ERRORS:
+ lvalue = trobjs->REL_TokenError;
+ break;
+ default:
+ DebugPrint(0,("NetFlexQueryInformation: Undefinded OID - 0x%x",Oid));
+ break;
+ }
+ copyptr = (PUCHAR)&lvalue;
+ }
+ else
+ {
+ needcopy = FALSE;
+ Status = NetFlexDequeue_OnePtrQ_Head((PVOID *)&(acb->acb_scbreq_free),
+ (PVOID *)&scbreq);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ //
+ // Save the information about the request
+ //
+ if (acb->RequestInProgress)
+ {
+ DebugPrint(0,("NF(%d): Query OID: Aready have RequestInProcess!\n",acb->anum));
+ //return NDIS_STATUS_FAILURE;
+ }
+
+ acb->RequestInProgress = TRUE;
+
+ acb->BytesWritten = BytesWritten;
+ acb->BytesNeeded = BytesNeeded;
+ acb->Oid = Oid;
+ acb->InformationBuffer = InformationBuffer;
+ acb->InformationBufferLength = InformationBufferLength;
+
+ DebugPrint(2,("NF(%d): Queue Up Request to get OID (0x%x) info\n",acb->anum,Oid));
+
+ NetFlexDequeue_OnePtrQ_Head( (PVOID *)&(acb->acb_macreq_free),
+ (PVOID *)&macreq);
+ macreq->req_next = NULL;
+ macreq->req_type = QUERY_CMP;
+ macreq->req_status = NDIS_STATUS_SUCCESS;
+
+ scbreq->req_scb.SCB_Cmd = TMS_READLOG;
+ scbreq->req_macreq = macreq;
+ scbreq->req_scb.SCB_Ptr = SWAPL(CTRL_ADDR(NdisGetPhysicalAddressLow(acb->acb_logbuf_physptr)));
+ //
+ // put the macreq on the macreq queue
+ //
+ NetFlexEnqueue_TwoPtrQ_Tail( (PVOID *)&(acb->acb_macreq_head),
+ (PVOID *)&(acb->acb_macreq_tail),
+ (PVOID)macreq);
+
+ NetFlexQueueSCB(acb, scbreq);
+ Status = NDIS_STATUS_PENDING;
+ }
+ }
+ break;
+
+ //------------------------------------
+ // 802.5 OPERATIONAL CHARACTERISTICS
+ //------------------------------------
+
+ case OID_802_5_PERMANENT_ADDRESS:
+ srcptr = acb->acb_gen_objs.perm_staddr;
+ copyptr = (PUCHAR)srcptr;
+ copylen = (SHORT)NET_ADDR_SIZE;
+ break;
+
+ case OID_802_5_CURRENT_ADDRESS:
+ srcptr = acb->acb_gen_objs.current_staddr;
+ copyptr = (PUCHAR)srcptr;
+ copylen = (SHORT)NET_ADDR_SIZE;
+ break;
+
+ case OID_802_5_UPSTREAM_ADDRESS:
+ NetFlexGetUpstreamAddress(acb);
+ srcptr = ((PTR_OBJS)acb->acb_spec_objs)->upstream_addr;
+ copyptr = (PUCHAR)srcptr;
+ copylen = (SHORT)NET_ADDR_SIZE;
+ break;
+
+ case OID_802_5_CURRENT_FUNCTIONAL:
+ lvalue = *( (PULONG)(((PTR_OBJS)(acb->acb_spec_objs))->cur_func_addr));
+ copyptr = (PUCHAR)&lvalue;
+ copylen = (SHORT)NET_GROUP_SIZE;
+ break;
+
+ case OID_802_5_CURRENT_GROUP:
+ lvalue = *( (PULONG)(((PTR_OBJS)(acb->acb_spec_objs))->cur_grp_addr));
+ copylen = (lvalue == 0) ? 0 : NET_GROUP_SIZE;
+ copyptr = (PUCHAR)&lvalue;
+ break;
+
+ case OID_802_5_LAST_OPEN_STATUS:
+ lvalue = acb->acb_lastopenstat;
+ copyptr = (PUCHAR)&lvalue;
+ break;
+
+ case OID_802_5_CURRENT_RING_STATUS:
+ lvalue = acb->acb_lastringstatus;
+ copyptr = (PUCHAR)&lvalue;
+ break;
+
+ case OID_802_5_CURRENT_RING_STATE:
+ lvalue = acb->acb_lastringstate;
+ copyptr = (PUCHAR)&lvalue;
+ break;
+
+ default:
+ DebugPrint(1,("NF(%d): (TR) Invalid Query or Unsupported OID, %x\n",acb->anum,Oid));
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ needcopy = FALSE;
+ break;
+ }
+ }
+ }
+
+ if (needcopy)
+ {
+ // Do we have enough space for the list + the oid value + the length?
+ //
+ if (InformationBufferLength < (USHORT) copylen)
+ {
+ DebugPrint(1,("NF(%d): Tell the user of the bytes needed\n",acb->anum));
+ *BytesNeeded = copylen - InformationBufferLength;
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ }
+ else
+ {
+ // Copy the data bytes
+ //
+ NdisMoveMemory( InformationBuffer,
+ copyptr,
+ copylen);
+ //
+ // Update the information pointer and size.
+ //
+ *BytesWritten += copylen;
+ }
+ }
+
+ acb->RequestInProgress = Status == NDIS_STATUS_PENDING;
+
+ return Status;
+}
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexFinishQueryInformation
+//
+// Description:
+// The NetFlexFinishQueryInformation finish processing a Query request for
+// NDIS_OIDs that are specific about the Driver which we had to update
+// before returning.
+//
+// Input:
+// acb - Our Driver Context for this adapter or head.
+//
+// Output:
+// The function value is the Status of the operation.
+//
+// Called By:
+//
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+VOID
+NetFlexFinishQueryInformation(
+ PACB acb,
+ NDIS_STATUS Status
+ )
+{
+ ULONG lvalue;
+ PTR_OBJS trobjs;
+ PETH_OBJS ethobjs;
+ BOOLEAN needcopy = TRUE;
+ PUCHAR copyptr;
+ SHORT copylen = (SHORT)sizeof(ULONG); // Most common length
+
+ //
+ // Get the saved information about the request.
+ //
+
+ PUINT BytesWritten = acb->BytesWritten;
+ PUINT BytesNeeded = acb->BytesNeeded;
+ NDIS_OID Oid = acb->Oid;
+ PVOID InformationBuffer = acb->InformationBuffer;
+ UINT InformationBufferLength = acb->InformationBufferLength;
+
+ DebugPrint(2,("NF(%d): NetFlexFinishQueryInformation\n",acb->anum));
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ *BytesNeeded = 0;
+
+ switch (Oid)
+ {
+
+ case OID_GEN_RCV_NO_BUFFER:
+ case OID_802_5_LINE_ERRORS:
+ case OID_802_5_LOST_FRAMES:
+ case OID_802_5_BURST_ERRORS:
+ case OID_802_5_AC_ERRORS:
+ case OID_802_5_CONGESTION_ERRORS:
+ case OID_802_5_FRAME_COPIED_ERRORS:
+ case OID_802_5_TOKEN_ERRORS:
+ trobjs = (PTR_OBJS)(acb->acb_spec_objs);
+ switch (Oid)
+ {
+ case OID_GEN_RCV_NO_BUFFER:
+ lvalue = trobjs->REL_Congestion;
+ break;
+ case OID_802_5_LINE_ERRORS:
+ lvalue = trobjs->REL_LineError;
+ break;
+ case OID_802_5_LOST_FRAMES:
+ lvalue = trobjs->REL_LostError;
+ break;
+ case OID_802_5_BURST_ERRORS:
+ lvalue = trobjs->REL_BurstError;
+ break;
+ case OID_802_5_AC_ERRORS:
+ lvalue = trobjs->REL_ARIFCIError;
+ break;
+ case OID_802_5_CONGESTION_ERRORS:
+ lvalue = trobjs->REL_Congestion;
+ break;
+ case OID_802_5_FRAME_COPIED_ERRORS:
+ lvalue = trobjs->REL_CopiedError;
+ break;
+ case OID_802_5_TOKEN_ERRORS:
+ lvalue = trobjs->REL_TokenError;
+ break;
+ default:
+ DebugPrint(0,("NetFlexFinishQueryInformation: Undefinded OID - 0x%x",Oid));
+ break;
+ }
+ copyptr = (PUCHAR)&lvalue;
+ break;
+
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+ case OID_802_3_XMIT_ONE_COLLISION:
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+ case OID_802_3_XMIT_DEFERRED:
+ case OID_802_3_XMIT_LATE_COLLISIONS:
+ case OID_802_3_XMIT_MAX_COLLISIONS:
+ case OID_802_3_XMIT_TIMES_CRS_LOST:
+ case OID_GEN_RCV_CRC_ERROR:
+ ethobjs = (PETH_OBJS)(acb->acb_spec_objs);
+
+ switch (Oid)
+ {
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+ lvalue = ethobjs->RSL_AlignmentErr;
+ break;
+ case OID_802_3_XMIT_ONE_COLLISION:
+ lvalue = ethobjs->RSL_1_Collision;
+ break;
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+ lvalue = ethobjs->RSL_More_Collision;
+ break;
+ case OID_802_3_XMIT_DEFERRED:
+ lvalue = ethobjs->RSL_DeferredXmit;
+ break;
+ case OID_802_3_XMIT_LATE_COLLISIONS:
+ lvalue = ethobjs->RSL_LateCollision;
+ break;
+ case OID_802_3_XMIT_MAX_COLLISIONS:
+ case OID_802_3_XMIT_TIMES_CRS_LOST:
+ lvalue = ethobjs->RSL_Excessive;
+ break;
+ default:
+ lvalue = ethobjs->RSL_FrameCheckSeq;
+ break;
+ }
+ copyptr = (PUCHAR)&lvalue;
+ break;
+
+ default:
+ DebugPrint(1,("NF(%d): Invalid Query or Unsupported OID, %x\n",acb->anum,Oid));
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ needcopy = FALSE;
+ break;
+ }
+
+ if (needcopy)
+ {
+ // Do we have enough space for the list + the oid value + the length?
+ //
+ if (InformationBufferLength < (USHORT) copylen)
+ {
+ DebugPrint(1,("NF(%d): Tell the user of the bytes needed\n",acb->anum));
+ *BytesNeeded = copylen - InformationBufferLength;
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ }
+ else
+ {
+ // Copy the data bytes
+ //
+ NdisMoveMemory( InformationBuffer,
+ copyptr,
+ copylen);
+ //
+ // Update the information pointer and size.
+ //
+ *BytesWritten += copylen;
+ }
+ }
+ }
+
+ //
+ // Complete the request
+ //
+ NdisMQueryInformationComplete( acb->acb_handle,
+ Status );
+ acb->RequestInProgress = FALSE;
+
+}
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexGetUpstreamAddress
+//
+// Description:
+// This routine gets the upstream neighbor of
+// the adapter in Token-Ring.
+//
+// Input:
+// acb - Our Driver Context for this adapter or head.
+//
+// Output:
+// Returns NDIS_STATUS_SUCCESS for a successful
+// completion. Otherwise, an error code is returned.
+//
+// Called By:
+// NetFlexBoardInitandReg
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+VOID
+NetFlexGetUpstreamAddress(
+ PACB acb
+ )
+{
+ USHORT value;
+ SHORT i;
+
+ NdisRawWritePortUshort(acb->SifAddrPort, acb->acb_upstreamaddrptr+4 );
+
+ for (i = 0; i < 3; i++)
+ {
+ NdisRawReadPortUshort(acb->SifDIncPort,(PUSHORT) &value);
+
+ ((PTR_OBJS)(acb->acb_spec_objs))->upstream_addr[i*2] =
+ (UCHAR)(SWAPS(value));
+ ((PTR_OBJS)(acb->acb_spec_objs))->upstream_addr[(i*2)+1] =
+ (UCHAR)value;
+ }
+}
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexProcessMacReq
+//
+// Description:
+// This routine completes a request which had to wait
+// for a adapter command to complete.
+//
+// Input:
+// acb - Our Driver Context for this adapter or head.
+//
+// Output:
+// None
+//
+// Called By:
+// NetFlexHandleInterrupt
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+VOID
+NetFlexProcessMacReq(
+ PACB acb
+ )
+{
+
+ NDIS_STATUS status;
+ PMACREQ macreq;
+ BOOLEAN ReceiveResult;
+
+ DebugPrint(1,("NF(%d): NetFlexProcessMacReq entered.\n", acb->anum));
+
+ while (acb->acb_confirm_qhead != NULL)
+ {
+ // We have command to complete.
+ //
+ macreq = acb->acb_confirm_qhead;
+ if ((acb->acb_confirm_qhead = macreq->req_next) == NULL)
+ {
+ acb->acb_confirm_qtail = NULL;
+ }
+ //
+ // what was the status...
+ //
+ status = macreq->req_status;
+
+ switch (macreq->req_type)
+ {
+ case OPENADAPTER_CMP:
+
+ //
+ // Cancel the Reset Timer, since the hardware seems to be working correctly
+ //
+ NdisMCancelTimer(&acb->ResetTimer,&ReceiveResult);
+
+ //
+ // Did the open complete successfully?
+ //
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ // Yes, mark as opened.
+ //
+ acb->acb_lastopenstat = 0;
+ acb->acb_lastringstate = NdisRingStateOpened;
+
+ //
+ // If the open completed successfully, we need to
+ // issue the transmit and receive commands. Also,
+ // we need to set the state according to the status.
+ //
+ if (acb->acb_state == AS_OPENING)
+ {
+ acb->acb_state = AS_OPENED;
+ }
+
+ //
+ // Now lets finish the open by sending a receive command to the adapter.
+ //
+ acb->acb_rcv_whead = acb->acb_rcv_head;
+
+ //
+ // Now lets finish the open by sending a
+ // transmit and receive command to the adapter.
+ //
+ acb->acb_xmit_whead = acb->acb_xmit_wtail = acb->acb_xmit_head;
+
+ //
+ // If the adapter is ready for a command, call a
+ // routine that will kick off the transmit command.
+ //
+ if (acb->acb_scb_virtptr->SCB_Cmd == 0)
+ {
+ NetFlexSendNextSCB(acb);
+ }
+ else if (!acb->acb_scbclearout)
+ {
+ //
+ // Make sure we are interrupted when the SCB is
+ // available so that we can send the transmit command.
+ //
+ acb->acb_scbclearout = TRUE;
+ NdisRawWritePortUshort(
+ acb->SifIntPort,
+ (USHORT)SIFINT_SCBREQST);
+ }
+ }
+ else
+ {
+ // Open failed.
+ // If we had an open error that is specific to TOKEN RING,
+ // set the last open status to the correct error code. Otherwise,
+ // just send the status as normal.
+ //
+ if (macreq->req_status == NDIS_STATUS_TOKEN_RING_OPEN_ERROR)
+ {
+ acb->acb_lastopenstat = (NDIS_STATUS)(macreq->req_info) |
+ NDIS_STATUS_TOKEN_RING_OPEN_ERROR;
+ }
+ else
+ {
+ acb->acb_lastopenstat = 0;
+ }
+ acb->acb_lastringstate = NdisRingStateOpenFailure;
+
+ if (acb->acb_state == AS_OPENING)
+ {
+ acb->acb_state = AS_INITIALIZED;
+ }
+ //
+ // Force a reset.
+ //
+ acb->ResetState = RESET_STAGE_4;
+ }
+
+ //
+ // Put Macreq back on free queue
+ //
+ NetFlexEnqueue_OnePtrQ_Head((PVOID *)&(acb->acb_macreq_free),
+ (PVOID)macreq);
+
+
+ //
+ //
+ // processed the open command.
+ //
+
+ if (acb->ResetState == RESET_STAGE_4)
+ {
+ //
+ // If this is the completion of a Reset, set the reset timer
+ // so it can be completed.
+ //
+ NdisMSetTimer(&acb->ResetTimer,10);
+ }
+ break;
+
+ case CLOSEADAPTER_CMP:
+ acb->acb_state = AS_CLOSING;
+ break;
+
+ case QUERY_CMP:
+ case REQUEST_CMP:
+
+ if (acb->RequestInProgress)
+ {
+ //
+ // Go process the request
+ // Is it a Query or a Set?
+ //
+ if (macreq->req_type == QUERY_CMP)
+ {
+ NetFlexFinishQueryInformation(acb,status);
+ }
+ else
+ {
+ DebugPrint(1,("NF(%d): NetFlexProcessMacReq: Completing request.\n", acb->anum));
+
+ acb->RequestInProgress = FALSE;
+ NdisMSetInformationComplete(acb->acb_handle, status);
+ }
+ }
+ else
+ {
+ DebugPrint(0,("NF(%d): Have macreq QUERY_CMP or REQUEST_CMP without RequestInProgress!\n",acb->anum));
+ }
+
+ NdisZeroMemory(macreq, sizeof(MACREQ));
+ NetFlexEnqueue_OnePtrQ_Head(
+ (PVOID *)&(acb->acb_macreq_free),
+ (PVOID)macreq
+ );
+
+ break;
+
+ default: // We should NEVER be here
+ DebugPrint(0,("NF(%d): ProcessMaqReq - No command - ERROR!\n",acb->anum));
+ break;
+ } // End of switch
+ } // End of while confirm q
+}
diff --git a/private/ntos/ndis/netflex/reset.c b/private/ntos/ndis/netflex/reset.c
new file mode 100644
index 000000000..f907de47e
--- /dev/null
+++ b/private/ntos/ndis/netflex/reset.c
@@ -0,0 +1,1924 @@
+//**********************************************************************
+//**********************************************************************
+//
+// File Name: RESET.C
+//
+// Program Name: NetFlex NDIS 3.0 Miniport Driver
+//
+// Companion Files: None
+//
+// Function: This module contains the NetFlex Miniport Driver
+// interface routines called by the Wrapper and the
+// configuration manager.
+//
+// (c) Compaq Computer Corporation, 1992,1993,1994
+//
+// This file is licensed by Compaq Computer Corporation to Microsoft
+// Corporation pursuant to the letter of August 20, 1992 from
+// Gary Stimac to Mark Baber.
+//
+// History:
+//
+// 04/15/94 Robert Van Cleve - Converted from NDIS Mac Driver
+//
+//**********************************************************************
+//**********************************************************************
+
+
+//-------------------------------------
+// Include all general companion files
+//-------------------------------------
+
+#include <ndis.h>
+#include "tmsstrct.h"
+#include "macstrct.h"
+#include "adapter.h"
+#include "protos.h"
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexResetDispatch
+//
+// Description:
+// Kick off a reset!
+//
+// Input:
+// MiniportAdapterContext - really our acb.
+//
+// Output:
+// Returns NDIS_STATUS_PENDING unless we are already handling a reset,
+// in which case we return NDIS_STATUS_RESET_IN_PROGRESS.
+//
+// Called By:
+// Miniport Wrapper
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+NDIS_STATUS
+NetFlexResetDispatch(
+ OUT PBOOLEAN AddressingReset,
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+{
+ PACB acb = (PACB) MiniportAdapterContext;
+ BOOLEAN ReceiveResult = FALSE;
+
+ DebugPrint(1,("NF(%d): Reset Called!\n",acb->anum));
+
+ if ( acb->ResetState && (acb->ResetState != RESET_HALTED))
+ {
+ return NDIS_STATUS_RESET_IN_PROGRESS;
+ }
+
+ acb->acb_lastringstate = NdisRingStateClosed;
+ acb->acb_state = AS_RESETTING;
+ acb->ResetState = RESET_STAGE_1;
+
+ //
+ // Cancel the DPC Timer!
+ //
+
+ NdisMCancelTimer(&acb->DpcTimer,&ReceiveResult);
+
+ //
+ // Set the timer for the NetFlexResetHandler DPC.
+ //
+ NdisMSetTimer(&acb->ResetTimer,500 );
+
+ return NDIS_STATUS_PENDING;
+}
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexResetHandler
+//
+// Description:
+// Performs that operations to put the adatper
+// through a reset and back into operation.
+//
+//
+// Input:
+//
+// SystemSpecific1 - Not used.
+// acb - The Adapter whose hardware is being reset.
+// SystemSpecific2 - Not used.
+// SystemSpecific3 - Not used.
+//
+// Output:
+// None.
+//
+// Called By:
+// via acb->ResetTimer
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+VOID
+NetFlexResetHandler(
+ IN PVOID SystemSpecific1,
+ IN PACB acb,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+{
+ NDIS_STATUS Status;
+ BOOLEAN ReceiveResult;
+ BOOLEAN DoneWReset;
+
+ //
+ // Cancel the reset timer
+ //
+ NdisMCancelTimer(&acb->ResetTimer,&ReceiveResult);
+
+ do
+ {
+ DoneWReset = TRUE; // default to true...
+
+ //
+ // Based on the current acb->ResetState, proceed with the reset.
+ //
+ switch(acb->ResetState)
+ {
+
+ case RESET_STAGE_1:
+
+ acb->ResetRetries = 0;
+ acb->InitRetries = 0;
+
+ //
+ // Issue Close
+ //
+ NetFlexCloseAdapter(acb);
+
+ //
+ // Remove all xmit mappings, and clean up queues
+ //
+ NetFlexRemoveRequests(acb);
+ acb->ResetState = RESET_STAGE_2;
+
+ case RESET_STAGE_2:
+
+ //
+ // Try soft resetting adapter
+ //
+ Status = NetFlexAdapterReset(acb,SOFT_RESET);
+ //
+ // Was the reset successful?
+ //
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ // No!
+ // Increment the retry count
+ //
+ acb->ResetRetries++;
+ //
+ // have we tried 3 times?
+ //
+ if (acb->ResetRetries < 3 )
+ {
+ // no, try it again in 10 sec
+ //
+ NdisMSetTimer(&acb->ResetTimer,10000 );
+ }
+ else
+ {
+ // yes, try a hard reset
+ //
+ acb->ResetState = RESET_STAGE_3;
+ acb->ResetRetries = 0;
+ DoneWReset = FALSE;
+ }
+ break;
+ }
+
+ //
+ // Yes, soft reset was successful, send open request...
+ // Note: When the Open request completes/fails
+ // we wind up in Reset_Stage_4.
+ //
+ acb->ResetState = RESET_STAGE_4;
+ acb->InitRetries++;
+
+ NetFlexOpenAdapter(acb);
+
+ //
+ // Give the Open 20 seconds to Complete
+ //
+ NdisMSetTimer(&acb->ResetTimer,20000);
+ break;
+
+ case RESET_STAGE_3:
+ //
+ // Perform Hard Reset!
+ //
+ Status = NetFlexAdapterReset(acb,HARD_RESET);
+ //
+ // Was the reset successful?
+ //
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ // No!
+ // Increment the retry count
+ //
+ acb->ResetRetries++;
+ //
+ // have we tried Hard Reset 3 times?
+ //
+ if (acb->ResetRetries < 3 )
+ {
+ // no, try it again in 10 sec
+ //
+ acb->ResetState = RESET_STAGE_3;
+ NdisMSetTimer(&acb->ResetTimer,10000 );
+ }
+ else
+ {
+ // Hard Reset timed out, do the reset indications.
+ //
+ DebugPrint(0,("NF(%d): Reset - Exceeded Hard Reset Retries\n",acb->anum));
+ NetFlexDoResetIndications(acb,NDIS_STATUS_FAILURE);
+ }
+ break;
+ }
+
+ //
+ // Yes, hard reset was successful, go do init stuff...
+ //
+ acb->ResetState = RESET_STAGE_4;
+ //
+ // Send Open Comand, when complete, we end up in Reset_Stage_4
+ //
+ NetFlexOpenAdapter(acb);
+ //
+ // Give the Open 20 seconds to Complete
+ //
+ NdisMSetTimer(&acb->ResetTimer,20000);
+ break;
+
+ case RESET_STAGE_4:
+
+ //
+ // Increment the retry count
+ //
+ acb->InitRetries++;
+
+ if (acb->acb_state != AS_OPENED)
+ {
+ // Have we expired the retry count, do the indications
+ //
+ if (acb->InitRetries > 4)
+ {
+ DebugPrint(0,("NF(%d): Reset - Exceeded Open Retries\n",acb->anum));
+
+ NetFlexDoResetIndications(acb,NDIS_STATUS_FAILURE);
+ }
+ else
+ {
+ // Perform a Soft Reset again!
+ //
+ acb->ResetState = RESET_STAGE_2;
+ DoneWReset = FALSE;
+ }
+ }
+ else
+ {
+ // We were successful!
+ //
+ NetFlexDoResetIndications(acb,NDIS_STATUS_SUCCESS);
+ }
+ break;
+ }
+ } while (!DoneWReset);
+}
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexDoResetIndications
+//
+// Description:
+// This routine is called by NetFlexResetHandler to perform any
+// indications which need to be done after a reset. Note that
+// this routine will be called after either a successful reset
+// or a failed reset.
+//
+// Input:
+// acb - Our Driver Context.
+//
+// Output:
+// Status - The status of the reset to send to the protocol(s).
+//
+// Called By:
+// NetFlexResetHandler
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+VOID
+NetFlexDoResetIndications(
+ IN PACB acb,
+ IN NDIS_STATUS Status
+ )
+{
+ USHORT actl_reg;
+ //
+ // If we have a bad result, we stop the chip and do the indication
+ // back to the protocol(s).
+ //
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DebugPrint(0,("NF(%d): Reset failed!\n",acb->anum));
+
+ //
+ // Stop the chip
+ //
+ NdisRawReadPortUshort( acb->SifActlPort, (PUSHORT) (&actl_reg));
+ actl_reg |= ACTL_ARESET;
+ NdisRawWritePortUshort( acb->SifActlPort, (USHORT) actl_reg);
+
+ //
+ // Reset has failed, errorlog an entry if
+ // did not already send out a message.
+ //
+ if (!acb->ResetErrorLogged)
+ {
+ NdisWriteErrorLogEntry( acb->acb_handle,
+ EVENT_NDIS_RESET_FAILURE_ERROR,
+ 1,
+ NETFLEX_RESET_FAILURE_ERROR_CODE
+ );
+ acb->ResetErrorLogged = TRUE;
+ }
+
+ acb->ResetState = RESET_HALTED;
+ acb->acb_state = AS_CARDERROR;
+ Status = NDIS_STATUS_HARD_ERRORS;
+
+ }
+
+ //
+ // Verify that the dpc timer is set.
+ //
+ NdisMSetTimer(&acb->DpcTimer,10);
+
+ NdisMResetComplete( acb->acb_handle,
+ Status,
+ TRUE );
+
+ //
+ // We are no longer resetting the Adapter.
+ //
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ acb->ResetState = 0;
+
+ //
+ // Did we send out a message that a reset failed before?
+ //
+ if (acb->ResetErrorLogged)
+ {
+ //
+ // Log the fact that everything is ok now...
+ //
+ NdisWriteErrorLogEntry( acb->acb_handle,
+ EVENT_NDIS_RESET_FAILURE_CORRECTION,
+ 0);
+
+ acb->ResetErrorLogged = FALSE;
+ }
+ else
+ {
+ if (acb->acb_lastringstatus &
+ ( NDIS_RING_SIGNAL_LOSS |
+ NDIS_RING_LOBE_WIRE_FAULT |
+ NDIS_RING_AUTO_REMOVAL_ERROR |
+ NDIS_RING_REMOVE_RECEIVED
+ ))
+ {
+ //
+ // Log the fact that we have reinserted in a TR MAU...
+ //
+ acb->SentRingStatusLog = FALSE;
+ acb->acb_lastringstatus = 0;
+ NdisWriteErrorLogEntry( acb->acb_handle,
+ EVENT_NDIS_TOKEN_RING_CORRECTION,
+ 0);
+
+ }
+ }
+ }
+
+ DebugPrint(1,("NF(%d): Reset Complete.\n",acb->anum));
+}
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexCheckForHang
+//
+// Description:
+// This function simply gets call once every two seconds to
+// check on the head of the command block queue.
+// It will fire off the queue if the head has been sleeping on
+// the job.
+//
+// It also detects when the NetFlex adapter has failed, where the
+// symptoms are that the adapter will transmit packets, but will
+// not receive them.
+//
+// Input: acb - Our Driver Context.
+//
+// Output: True if we think the adapter is hung..
+//
+// Called By: Miniport Wrapper
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+BOOLEAN
+NetFlexCheckForHang(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+{
+ PXMIT xmitptr;
+ PMACREQ macreq;
+ PSCBREQ scbreq;
+
+ PACB acb = (PACB) MiniportAdapterContext;
+
+ //
+ // If we're run into a hard error, return true
+ //
+
+ if (acb->acb_state == AS_HARDERROR)
+ {
+ return TRUE;
+ }
+
+ //
+ // If we're not open return false
+ //
+ else if (acb->acb_state != AS_OPENED)
+ {
+ return FALSE;
+ }
+
+ //
+ // Is there a command outstanding?
+ //
+ if (acb->acb_scbreq_head != NULL)
+ {
+ scbreq = acb->acb_scbreq_head;
+ macreq = scbreq->req_macreq;
+
+ if (macreq != NULL)
+ {
+ // See if the command block has timed-out.
+ //
+ if (macreq->req_timeout)
+ {
+ // See if we have given it enough time
+ //
+ if ( macreq->req_timeoutcount >= 40)
+ {
+ DebugPrint(1,("NF(%d): CheckHang - Command Timed Out!\n",acb->anum));
+ return TRUE;
+ }
+ else
+ {
+ macreq->req_timeoutcount++;
+ }
+ }
+ else
+ {
+ // Start testing this command to check timeout
+ //
+ macreq->req_timeout = TRUE;
+ macreq->req_timeoutcount = 0;
+ }
+ }
+ }
+
+ if (acb->FullDuplexEnabled)
+ {
+ NdisAcquireSpinLock(&acb->XmitLock);
+ }
+
+ //
+ // See if there is any xmits which have not been processed
+ //
+ if (acb->acb_xmit_ahead != NULL)
+ {
+ xmitptr = acb->acb_xmit_ahead;
+
+ if (xmitptr->XMIT_Timeout)
+ {
+#if DBG
+ if (xmitptr->XMIT_CSTAT & XCSTAT_COMPLETE)
+ {
+ DebugPrint(0,("NF(%d): CheckHang - Xmit Complete but Xmit Timed Out!\n",acb->anum));
+ }
+ else
+ {
+ DebugPrint(0,("NF(%d): CheckHang - Xmit Timed Out!\n",acb->anum));
+ }
+#endif
+
+ if (acb->FullDuplexEnabled)
+ {
+ NdisReleaseSpinLock(&acb->XmitLock);
+ }
+
+ return TRUE;
+ }
+ xmitptr->XMIT_Timeout++;
+ }
+
+ //
+ // If we are in full-duplex mode then that is the extent of our
+ // checking to see if we are hung. If we are in half-duplex mode
+ // then we might want to send a dummy packet to see if our receiver
+ // is working correctly....
+ //
+ if (acb->FullDuplexEnabled)
+ {
+ NdisReleaseSpinLock(&acb->XmitLock);
+ }
+
+ //
+ // Should we do extreme checking?
+ //
+ if (!acb->acb_parms->utd_extremecheckforhang)
+ {
+ return(FALSE);
+ }
+
+ //
+ // Have we been getting interrupts?
+ //
+ if (acb->acb_int_count != 0)
+ {
+ //
+ // We got some, initialize the counts.
+ //
+ acb->acb_int_count = 0;
+ acb->acb_int_timeout = 0;
+ }
+ else
+ {
+ //
+ // Increment the timeout count.
+ //
+ acb->acb_int_timeout++;
+
+ //
+ // We will do this 5 times before we reset.
+ //
+ if (5 == acb->acb_int_timeout)
+ {
+ //
+ // Clear our counts and request a reset.
+ //
+ acb->acb_int_timeout = 0;
+ acb->acb_int_count = 0;
+
+ return(TRUE);
+ }
+ }
+
+ //
+ // Not certain we're hung yet...
+ //
+ return FALSE;
+}
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexOpenAdapter
+//
+// Description:
+// This routine is called to queue up and issue
+// an open command to the adapter.
+//
+// If the system is still in initialization, then
+// the routine polls for the open command to complete,
+// otherwise, the interrupt hander processes the complete
+// and then returns to the reset handler for completion.
+//
+// Input:
+// acb - Our Driver Context.
+//
+// Output:
+// Success or Failure.
+//
+// Called By:
+// NetFlexResetHandler, NetFlexBoardInitandReg
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+NDIS_STATUS
+NetFlexOpenAdapter(
+ PACB acb
+ )
+{
+ NDIS_STATUS Status;
+ PMACREQ macreq;
+ PSCBREQ scbreq;
+ ULONG Counter=0;
+
+ //
+ // Open Adapter
+ //
+ acb->acb_state = AS_OPENING;
+ acb->acb_lastringstate = NdisRingStateOpening;
+
+ //
+ // Are we doing an open for reset or during initialization?
+ //
+ if (!acb->AdapterInitializing)
+ {
+ //
+ // Get a free block.
+ //
+ Status = NetFlexDequeue_OnePtrQ_Head( (PVOID *)&(acb->acb_scbreq_free),
+ (PVOID *)&scbreq);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DebugPrint(0,("NF(%d): Could not get an SCBREQ for the Open Command\n",acb->anum));
+ return Status;
+ }
+
+ acb->acb_opnblk_virtptr->OPEN_Options = acb->acb_openoptions;
+ scbreq->req_scb.SCB_Cmd = TMS_OPEN;
+ scbreq->req_scb.SCB_Ptr = SWAPL(CTRL_ADDR(NdisGetPhysicalAddressLow(acb->acb_opnblk_physptr)));
+
+ Status = NetFlexDequeue_OnePtrQ_Head( (PVOID *)&(acb->acb_macreq_free),
+ (PVOID *)&macreq);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ // We have no more room for another request currently
+ //
+ DebugPrint(0,("NF(%d): No macreq for the Open Command\n",acb->anum));
+ //
+ // Put the SCBREQ back...
+ //
+ NetFlexEnqueue_OnePtrQ_Head((PVOID *)&acb->acb_scbreq_free,(PVOID)scbreq);
+ return Status;
+ }
+
+ macreq->req_info = 0;
+ macreq->req_type = OPENADAPTER_CMP;
+ macreq->req_status = NDIS_STATUS_SUCCESS;
+ scbreq->req_macreq = macreq;
+
+ NetFlexEnqueue_TwoPtrQ_Tail((PVOID *)&(acb->acb_macreq_head),
+ (PVOID *)&(acb->acb_macreq_tail),
+ (PVOID)macreq);
+ //
+ // Verify that interrupts are enabled!
+ //
+ NetFlexEnableInterrupt(acb);
+
+ //
+ // Send the command out...
+ //
+ NetFlexQueueSCB(acb, scbreq);
+
+ //
+ // Note: acb->ErrorCode will be set while processing the
+ // open command complete if there is an error.
+ //
+ }
+ else
+ {
+ //
+ // Open for Initialization
+ //
+ ULONG Counter = 0;
+ ULONG CounterTimeOut = 2000; // 2 seconds in miliseconds
+ USHORT sifint_reg;
+
+ Status = NDIS_STATUS_FAILURE;
+
+ //
+ // Make sure the command is clear, try for 2 seconds
+ //
+ while ((acb->acb_scb_virtptr->SCB_Cmd != 0) && (Counter++ < CounterTimeOut))
+ NdisStallExecution((UINT)1000);
+
+ if (Counter < CounterTimeOut)
+ {
+ // Get the command together...
+ //
+ acb->acb_opnblk_virtptr->OPEN_Options = acb->acb_openoptions;
+ acb->acb_scb_virtptr->SCB_Cmd = TMS_OPEN;
+ acb->acb_scb_virtptr->SCB_Ptr = SWAPL(CTRL_ADDR(NdisGetPhysicalAddressLow(acb->acb_opnblk_physptr)));
+
+ //
+ // Make sure interrupts are disabled!
+ //
+ NetFlexDisableInterrupt(acb);
+
+ //
+ // Send the SCB to the adapter.
+ //
+ NdisRawWritePortUshort(acb->SifIntPort, SIFINT_CMD);
+
+ Counter = 0;
+ CounterTimeOut = 20000; // 20 seconds in miliseconds
+
+ do
+ {
+ Counter++;
+ NdisStallExecution((UINT)1000); // 1 milisecond in microseconds
+ //
+ // Read the Sifint register.
+ //
+ NdisRawReadPortUshort( acb->SifIntPort, &sifint_reg);
+
+ //
+ // Is there an interrupt pending?
+ //
+ if ((sifint_reg & SIFINT_SYSINT) && ((sifint_reg & INT_CODES) == INT_COMMAND))
+ {
+
+ // Ack the interrupt
+ //
+ sifint_reg &= ~SIFINT_SYSINT;
+ NdisRawWritePortUshort( acb->SifIntPort, sifint_reg);
+
+ if (acb->acb_ssb_virtptr->SSB_Status == SSB_GOOD)
+ {
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ else
+ {
+ DebugPrint(0,("NF(%d): Bad status %x\n",acb->anum,acb->acb_ssb_virtptr->SSB_Status));
+
+ if (acb->acb_ssb_virtptr->SSB_Status & SSB_OPENERR) // only Token Ring
+ {
+ Status = NDIS_STATUS_TOKEN_RING_OPEN_ERROR;
+ acb->acb_lastopenstat = NDIS_STATUS_TOKEN_RING_OPEN_ERROR;
+ }
+ else
+ {
+ acb->acb_lastopenstat = 0;
+ }
+ acb->acb_lastringstate = NdisRingStateOpenFailure;
+ }
+ //
+ // Issue a ssb clear.
+ //
+ NdisRawWritePortUshort( acb->SifIntPort, SIFINT_SSBCLEAR);
+
+ break;
+ }
+ } while (Counter < CounterTimeOut);
+ }
+
+ //
+ // Did it work?
+ //
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ // Set State to Opened
+ //
+ acb->acb_state = AS_OPENED;
+ //
+ // Now lets finish the open by sending a receive command to the adapter.
+ //
+ acb->acb_rcv_whead = acb->acb_rcv_head;
+
+ //
+ // Now lets finish the open by sending a
+ // transmit command to the adapter.
+ //
+
+ acb->acb_xmit_whead = acb->acb_xmit_wtail = acb->acb_xmit_head;
+
+ //
+ // Verify that interrupts are enabled!
+ //
+ NetFlexEnableInterrupt(acb);
+
+ //
+ // If the adapter is ready for a command, call a
+ // routine that will kick off the transmit command.
+ //
+ if (acb->acb_scb_virtptr->SCB_Cmd == 0)
+ {
+ NetFlexSendNextSCB(acb);
+ }
+ else if (!acb->acb_scbclearout)
+ {
+ // Make sure we are interrupted when the SCB is
+ // available so that we can send the transmit command.
+ //
+ acb->acb_scbclearout = TRUE;
+ NdisRawWritePortUshort( acb->SifIntPort, (USHORT) SIFINT_SCBREQST);
+ }
+ }
+ else
+ {
+ // Set State back to Initialized since the open failed.
+ //
+ acb->acb_state = AS_INITIALIZED;
+ }
+ }
+
+ return Status;
+}
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexCloseAdapter
+//
+// Description:
+// This routine is called to queue up and issue an close
+// command to the adapter.
+//
+// Input:
+// acb - Our Driver Context.
+//
+// Output:
+// Success or Failure.
+//
+// Called By:
+// NetFlexResetHandler
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+BOOLEAN
+NetFlexCloseAdapter(
+ PACB acb)
+
+{
+ USHORT Counter = 0;
+ USHORT CounterTimeOut = 500;
+
+ if ((acb->acb_state == AS_OPENED) ||
+ (acb->acb_state == AS_RESETTING))
+ {
+ //
+ // Make sure the command is clear, try for 5 seconds
+ //
+ while ((acb->acb_scb_virtptr->SCB_Cmd != 0) && (Counter++ < CounterTimeOut)) {
+
+ NdisStallExecution((UINT)1000);
+ }
+
+ if (acb->acb_scb_virtptr->SCB_Cmd == 0)
+ {
+ //
+ // Send Close,
+ //
+
+ acb->acb_scb_virtptr->SCB_Cmd = TMS_CLOSE;
+ NdisRawWritePortUshort(acb->SifIntPort, (USHORT) SIFINT_CMD);
+
+ acb->acb_state = AS_CLOSING;
+ //
+ // Give it a little time...
+ //
+ NdisStallExecution((UINT)10000);
+ }
+
+ return (Counter >= CounterTimeOut);
+ }
+ return TRUE;
+}
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexHalt
+//
+// Description:
+// Removes an adapter previously initialized.
+//
+// Input:
+// MacAdapterContext - Actually as pointer to an PACB.
+//
+// Output:
+// None.
+//
+// Called By:
+// Miniport Wrapper.
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+VOID
+NetFlexHalt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+{
+ USHORT actl_reg;
+ BOOLEAN ReceiveResult1;
+ BOOLEAN ReceiveResult2;
+
+ //
+ // The adapter to halt
+ //
+ PACB acb = (PACB) MiniportAdapterContext;
+
+ DebugPrint(1,("NF(%d): Halt Called!\n", acb->anum));
+
+ //
+ // Cancel all of our timers.
+ //
+ NdisMCancelTimer(&acb->DpcTimer, &ReceiveResult1);
+ NdisMCancelTimer(&acb->ResetTimer, &ReceiveResult2);
+
+ //
+ // Is one of the timer dpc's going to fire?
+ //
+ if (!ReceiveResult1 || !ReceiveResult2)
+ {
+ NdisStallExecution(500000);
+ }
+
+ //
+ // Send Close
+ //
+ NetFlexCloseAdapter(acb);
+
+ //
+ // Stop Adapter
+ //
+ NdisRawReadPortUshort( acb->SifActlPort, (PUSHORT) (&actl_reg));
+ actl_reg |= ACTL_ARESET;
+ NdisRawWritePortUshort( acb->SifActlPort, (USHORT) actl_reg);
+
+ //
+ // Complete mappings
+ //
+ NetFlexRemoveRequests(acb);
+
+ //
+ // Free adapter resources
+ //
+ NetFlexDeregisterAdapter(acb);
+}
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexShutdown
+//
+// Description:
+// Removes an adapter previously initialized.
+//
+// Input:
+// MacAdapterContext - Actually as pointer to an PACB.
+//
+// Output:
+// None.
+//
+// Called By:
+// Miniport Wrapper.
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+VOID
+NetFlexShutdown(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+{
+ PACB acb = (PACB) MiniportAdapterContext;
+ USHORT actl_reg;
+
+ //
+ // Send Close.
+ //
+
+ NetFlexCloseAdapter(acb);
+
+ //
+ // Stop Adapter
+ //
+
+ NdisRawReadPortUshort( acb->SifActlPort, (PUSHORT) (&actl_reg));
+ actl_reg |= ACTL_ARESET;
+ NdisRawWritePortUshort( acb->SifActlPort, (USHORT) actl_reg);
+}
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexRemoveRequests
+//
+// Description:
+// Clean up queues during a Reset and Halt
+//
+// Input:
+// acb - Pointer to acb
+//
+// Output:
+// None
+//
+// Called By:
+// NetFlexResetHandler,
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+VOID
+NetFlexRemoveRequests(
+ PACB acb
+ )
+{
+ PXMIT xmitptr;
+ PRCV rcvptr;
+ UINT curmap;
+ PNDIS_PACKET packet;
+ PNDIS_BUFFER curbuf;
+ PMULTI_TABLE mt;
+ PETH_OBJS ethobjs;
+ USHORT i;
+ PSCBREQ scbreq;
+ PMACREQ macreq;
+
+ //
+ // Terminate all the transmits on the active queue.
+ //
+ xmitptr = acb->acb_xmit_ahead;
+
+ while (xmitptr != NULL)
+ {
+ // Did we use an internal buffer?
+ //
+ if (xmitptr->XMIT_OurBufferPtr != NULL)
+ {
+ // We've used one of our adapter buffers, so put the adapter
+ // buffer back on the free list.
+ //
+ if (xmitptr->XMIT_OurBufferPtr->BufferSize != acb->acb_smallbufsz) {
+ xmitptr->XMIT_OurBufferPtr->Next = acb->OurBuffersListHead;
+ acb->OurBuffersListHead = xmitptr->XMIT_OurBufferPtr;
+ }
+ else { // small buffer
+ xmitptr->XMIT_OurBufferPtr->Next = acb->SmallBuffersListHead;
+ acb->SmallBuffersListHead = xmitptr->XMIT_OurBufferPtr;
+ }
+ xmitptr->XMIT_OurBufferPtr = NULL;
+ }
+ else
+ {
+ packet = xmitptr->XMIT_Packet;
+
+ if ( packet != NULL ) {
+
+ curmap = xmitptr->XMIT_MapReg;
+
+ // Complete mappings, but don't complete the sends...
+ //
+
+ NdisQueryPacket(
+ packet,
+ NULL,
+ NULL,
+ (PNDIS_BUFFER *) &curbuf,
+ NULL
+ );
+
+ while (curbuf)
+ {
+ NdisMCompleteBufferPhysicalMapping(
+ acb->acb_handle,
+ (PNDIS_BUFFER) curbuf,
+ curmap
+ );
+
+ curmap++;
+ if (curmap == acb->acb_maxmaps)
+ {
+ curmap = 0;
+ }
+
+ NdisGetNextBuffer(curbuf, &curbuf);
+ }
+ }
+ }
+
+ xmitptr->XMIT_CSTAT = 0;
+ xmitptr->XMIT_Packet = NULL;
+
+ //
+ // If we've reached the active queue tail, we are done.
+ //
+ if (xmitptr == acb->acb_xmit_atail)
+ xmitptr = NULL;
+ else
+ xmitptr = xmitptr->XMIT_Next;
+ }
+
+ acb->acb_xmit_ahead = acb->acb_xmit_atail = NULL;
+ acb->acb_avail_xmit = acb->acb_parms->utd_maxtrans;
+
+ //
+ // Clean up the Receive Lists
+ //
+
+ rcvptr = acb->acb_rcv_head;
+
+ do {
+
+ //
+ // Mark receive list available
+ //
+ rcvptr->RCV_CSTAT =
+ ((rcvptr->RCV_Number % acb->RcvIntRatio) == 0) ? RCSTAT_GO_INT : RCSTAT_GO;
+
+ //
+ // Get next receive list
+ //
+ rcvptr = rcvptr->RCV_Next;
+
+ } while (rcvptr != acb->acb_rcv_head);
+
+ //
+ // Clean up multicast if ethernet.
+ //
+ if (acb->acb_gen_objs.media_type_in_use == NdisMedium802_3)
+ {
+ ethobjs = (PETH_OBJS)acb->acb_spec_objs;
+
+ NdisZeroMemory(
+ ethobjs->MulticastEntries,
+ ethobjs->MaxMulticast * NET_ADDR_SIZE
+ );
+
+ ethobjs->NumberOfEntries = 0;
+ }
+
+ //
+ // Clean up SCB Requests
+ //
+ while (acb->acb_scbreq_head)
+ {
+ NetFlexDequeue_TwoPtrQ_Head((PVOID *)&acb->acb_scbreq_head,
+ (PVOID *)&acb->acb_scbreq_tail,
+ (PVOID *)&scbreq);
+
+ NdisZeroMemory(scbreq, sizeof(SCBREQ));
+
+ NetFlexEnqueue_OnePtrQ_Head((PVOID *)&acb->acb_scbreq_free,(PVOID)scbreq);
+
+ }
+
+ //
+ // Clean up MacReq Requests
+ //
+ while (acb->acb_macreq_head)
+ {
+ NetFlexDequeue_TwoPtrQ_Head((PVOID *)&acb->acb_macreq_head,
+ (PVOID *)&acb->acb_macreq_tail,
+ (PVOID *)&macreq);
+
+ NdisZeroMemory(macreq, sizeof(MACREQ));
+
+ NetFlexEnqueue_OnePtrQ_Head( (PVOID *)&acb->acb_macreq_free,
+ (PVOID)macreq);
+
+ }
+
+ //
+ // Clean Up some more State stuff...
+ //
+ acb->RequestInProgress = FALSE;
+ acb->acb_scbclearout = FALSE;
+ acb->acb_scbreq_next = NULL;
+ acb->acb_gen_objs.cur_filter = 0;
+}
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexAdapterReset
+//
+// Description:
+// This routine resets the Super Eagle or Eagle
+//
+// Input:
+// mode - 0 = Hard Reset, ~0 = Soft Reset
+//
+// Output:
+// status - NDIS_STATUS_SUCCESS if Success
+//
+// Called By:
+// NetFlexResetHandler
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+NDIS_STATUS
+NetFlexAdapterReset(
+ PACB acb,
+ INT mode)
+{
+ NDIS_STATUS status;
+
+ //
+ // Which Reset?
+ //
+ if (mode == HARD_RESET)
+ {
+
+ // Do the reset
+ //
+ NdisRawWritePortUshort(acb->SifActlPort, ACTL_HARD_RESET);
+
+ //
+ // Wait 15 milliseconds to let the reset take place.
+ //
+ NdisStallExecution((UINT)15000); // Wait 15 milliseconds
+
+ //
+ // Call NetFlexSetupNetType to verify everything gets set correctly.
+ //
+ NetFlexSetupNetType(acb);
+
+ //
+ // Make sure that promiscuous mode is turned off
+ //
+ acb->acb_opnblk_virtptr->OPEN_Options &= SWAPS((USHORT) ~(OOPTS_CNMAC | OOPTS_CMAC));
+
+ //
+ // Download and initialize the adapter
+ //
+ if ((status = NetFlexDownload(acb)) == NDIS_STATUS_SUCCESS)
+ {
+ // Verify Bring Up Diagnostics
+ //
+ if ((status = NetFlexBudWait(acb))== NDIS_STATUS_SUCCESS)
+ {
+ // Initialize the adapter
+ //
+ if ((status = NetFlexInitializeAdapter(acb)) == NDIS_STATUS_SUCCESS)
+ {
+ // Yes, do we need to save the address that will give up our upstream address?
+ //
+ if (acb->acb_gen_objs.media_type_in_use == NdisMedium802_5)
+ {
+ // Yes, get it...
+ //
+ NetFlexGetUpstreamAddrPtr(acb);
+ }
+ }
+ }
+ }
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ DebugPrint(0,("NF(%d): Hard Reset Failed!\n",acb->anum));
+ }
+ }
+ else
+ {
+ // A Soft Reset was requested. Write the reset code into the
+ // SIF interrupt register.
+ //
+ NdisRawWritePortUshort(acb->SifIntPort, SIF_SOFT_RESET);
+
+ //
+ // Write the saved ACTL Settings.
+ //
+ NdisRawWritePortUshort( acb->SifActlPort, acb->actl_reg);
+
+ //
+ // Go check to see if the bring up diagnostics worked...
+ //
+ if ((status = NetFlexBudWait(acb)) == NDIS_STATUS_SUCCESS)
+ {
+ status = NetFlexInitializeAdapter(acb);
+ }
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ DebugPrint(0,("NF(%d): Soft Reset Failed!\n",acb->anum));
+ }
+ }
+
+ return status;
+}
+
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexBudWait
+//
+// Description:
+// This routine waits for the Bring Up Diags
+// (BUD) code to finish on the Super Eagle or Eagle
+//
+// Input:
+// acb - Our Driver Context.
+//
+// Output:
+// status - 0 = SUCCESS, ~0 = failure
+//
+// Called By:
+// NetFlexAdapterReset, NetFlexDownload
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+NDIS_STATUS
+NetFlexBudWait(
+ PACB acb
+ )
+{
+ int i;
+ USHORT value;
+
+ //
+ // Wait for Bring Up Diagnotics to start.
+ //
+ for (i = 0; i < 3000; i++)
+ {
+ NdisStallExecution((UINT)1000); /* Wait 1 millisecond */
+ NdisRawReadPortUshort(acb->SifIntPort, (PUSHORT) &value);
+ if ((value & 0x00f0) >= 0x0020)
+ break;
+ }
+
+ if (i >= 3000)
+ {
+ // Diags never got started!!
+ //
+ DebugPrint(0,("NF(%d): Diags never got started\n",acb->anum));
+ DebugPrint(0,("NF(%d): Sif int is 0x%x\n",acb->anum,value));
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // Wait for either success or failure.
+ //
+ for (i = 0; i < 3000; i++)
+ {
+ NdisStallExecution((UINT)1000); /* Wait 1 millisecond */
+ NdisRawReadPortUshort(acb->SifIntPort, (PUSHORT) (&value));
+ if ((value & 0x00f0) >= 0x0030)
+ break;
+ }
+
+ if (i >= 3000)
+ {
+ // Diags never finished!!
+ //
+ DebugPrint(0,("NetFlex: Diags never finished\n"));
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ if ((value & 0x00f0) != 0x0040)
+ {
+ // Diags failed!!
+ //
+ DebugPrint(0,("NF(%d): Diags Failed!\n",acb->anum));
+ return(NDIS_STATUS_FAILURE);
+ }
+ else
+ {
+ // The Diags passed OK!
+ //
+ DebugPrint(0,("NF(%d): Diags Passed OK\n",acb->anum));
+ return(NDIS_STATUS_SUCCESS);
+ }
+}
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexInitializeAdapter
+//
+// Description:
+// This routine initializes the adapter for open.
+//
+// Input:
+// acb - Our Driver Context
+//
+// Output:
+// Returns a NDIS_STATUS_SUCCESS if the adapter
+// initialized properly. Otherwise, an error code is returned,
+// showing that an initialization error has occurred.
+//
+// Called By:
+// NetFlexProcess_Open_Request
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+NDIS_STATUS
+NetFlexInitializeAdapter(
+ PACB acb
+ )
+{
+ ULONG temp;
+ INT i;
+ SHORT *ps;
+
+ //
+ // Set the SIF address register to point to the INIT block location
+ // and copy the INIT block info into the data inc register.
+ // make sure we are at chapter 1.
+ //
+ NdisRawWritePortUshort(acb->SifAddrxPort, (USHORT) 1);
+ NdisRawWritePortUshort(acb->SifAddrPort, (USHORT) ADDR_INIT);
+
+ for (i = 0, ps = (SHORT *) &acb->acb_initblk;
+ i < (SIZE_INIT / 2); i++, ps++)
+ {
+ NdisRawWritePortUshort(acb->SifDIncPort, (USHORT) *ps);
+ }
+
+ //
+ // Now write the SCB and SSB addresses into the
+ // data inc register.
+ //
+ temp = CTRL_ADDR(NdisGetPhysicalAddressLow(acb->acb_scb_physptr) + sizeof(USHORT));
+ NdisRawWritePortUshort(acb->SifDIncPort, (USHORT) (temp >> 16));
+ NdisRawWritePortUshort(acb->SifDIncPort, (USHORT) temp);
+
+ temp = CTRL_ADDR(NdisGetPhysicalAddressLow(acb->acb_ssb_physptr));
+ NdisRawWritePortUshort(acb->SifDIncPort, (USHORT) (temp >> 16));
+ NdisRawWritePortUshort(acb->SifDIncPort, (USHORT) temp);
+
+ //
+ // Now write the execute command out to the SIF.
+ //
+ NdisRawWritePortUshort(acb->SifIntPort, (USHORT) SIFINT_CMD);
+
+ //
+ // Wait for the intialization to complete.
+ //
+ for (i = 0; i < 3000; i++)
+ {
+ NdisStallExecution((UINT)1000); /* Wait 1 millisecond */
+ NdisRawReadPortUshort(acb->SifIntPort, (PUSHORT) (&temp));
+ if ((temp & 0x00ff) != 0x0040)
+ break;
+ }
+
+ if ( (i >= 3000) || ((temp & 0x00ff) != 0x0000) )
+ {
+ //
+ // Initialization never finished!! OR Initialization failed!!
+ //
+ return(NDIS_STATUS_FAILURE);
+
+ }
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexDownload
+//
+// Description:
+// This routine downloads the TMS380 MAC code to the
+// Super Eagle or Eagle.
+//
+// Input:
+// acb - Our Driver Context.
+//
+// Output:
+// status - 0 = SUCCESS, ~0 = failure
+//
+// Called By:
+// NetFlexAdapterReset
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+NDIS_STATUS
+NetFlexDownload(
+ PACB acb
+ )
+{
+ LONG j;
+ USHORT temp_value;
+ LONG totalbytes;
+ PUSHORT MappedBuffer;
+ PDL_STRUCT ds;
+ PUCHAR dataptr;
+
+ if (macgbls.DownloadCode == NULL)
+ {
+ DebugPrint(0,("NF(%d) - No Download code!\n",acb->anum));
+ return NDIS_STATUS_FAILURE;
+ }
+
+ //
+ // Get our pointers ready. Currently the MappedBuffer is pointing
+ // to the length of the header. The data begins after the header.
+ // Also the section headers are contained within the header just
+ // past the length field which is 2 bytes long.
+ //
+
+ MappedBuffer = macgbls.DownloadCode;
+
+ dataptr = (PUCHAR)(*MappedBuffer + (PUCHAR)(MappedBuffer) );
+
+ ds = (PDL_STRUCT)( (PUCHAR)(MappedBuffer) + 2);
+
+ //
+ // If we're using FPA skip to the second set of mac code. The
+ // order of the mac code is TOK, ETH, TOKFPA and ETHFPA.
+ //
+ if (acb->acb_usefpa)
+ {
+ for (j=0; j<2; j++)
+ {
+ totalbytes = 0;
+ while (ds->dl_chap != 0x7ffe)
+ {
+ totalbytes += ds->dl_bytes;
+ ds++;
+ }
+
+ MappedBuffer = (PUSHORT)(dataptr + totalbytes);
+
+ dataptr = (PUCHAR)(*MappedBuffer + (PUCHAR)(MappedBuffer) );
+ ds = (PDL_STRUCT)( (PUCHAR)(MappedBuffer) + 2);
+ }
+ }
+
+ //
+ // No need to perform a hard reset of the Super Eagle or Eagle
+ // since we have already done.
+ //
+ if (acb->acb_gen_objs.media_type_in_use == NdisMedium802_3)
+ {
+ //
+ // We need to skip around the download code for Token Ring.
+ // Therefore, find the end of the token ring download code.
+ //
+ totalbytes = 0;
+ while (ds->dl_chap != 0x7ffe)
+ {
+ totalbytes += ds->dl_bytes;
+ ds++;
+ }
+
+ MappedBuffer = (PUSHORT)(dataptr + totalbytes);
+
+ dataptr = (PUCHAR)(*MappedBuffer + (PUCHAR)(MappedBuffer) );
+ ds = (PDL_STRUCT)( (PUCHAR)(MappedBuffer) + 2);
+ }
+
+ //
+ // Download each section of data
+ //
+ while (ds->dl_chap != 0x7ffe)
+ {
+ NdisRawWritePortUshort( acb->SifAddrxPort, (USHORT) ds->dl_chap);
+ NdisRawWritePortUshort( acb->SifAddrPort, (USHORT) ds->dl_addr);
+
+ for (j = 0; j < (ds->dl_bytes / 2); j++)
+ {
+ NdisRawWritePortUshort( acb->SifDIncPort,
+ (USHORT)(SWAPS(*( (PUSHORT)(dataptr)))) );
+ dataptr += 2;
+ }
+ ds++;
+ }
+
+ //
+ // Now turn off the CP halt bit in the ACTL register to let the
+ // TMS380 chipset startup. Wait for the BUD to finish and report
+ // the appropriate status code.
+ //
+ NdisRawReadPortUshort( acb->SifActlPort, (PUSHORT) (&temp_value));
+
+ temp_value &= ~ACTL_CPHALT;
+
+ NdisRawWritePortUshort( acb->SifActlPort, (USHORT) temp_value);
+
+ //
+ // Save the Current Actl value
+ //
+ acb->actl_reg = temp_value;
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexSetupNetType
+//
+// Description:
+// This routine sets up the Super Eagle to run the type of
+// network and network speed requested by config. It assumes
+// that the adapter is in a halted state after reset.
+//
+// Input:
+// acb - Our Driver Context.
+//
+// Output:
+// Returns NDIS_STATUS_SUCCESS for a successful
+// completion. Otherwise, an error code is returned.
+//
+// Called By:
+// NetFlexResetHandler, NetFlexBoardInitandReg
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+VOID
+NetFlexSetupNetType(
+ PACB acb
+ )
+{
+ USHORT cfg_reg, actl_reg;
+ USHORT cfg_reg2, tmp_reg;
+ UCHAR cfg_regl, cfg_regh;
+ NDIS_MEDIUM nettype;
+ ULONG netspeed;
+ USHORT board_id = acb->acb_boardid;
+
+ //
+ // Get the network type and speed the user set up in EISA config.
+ // The port address for the cfg port is odd which will cause an
+ // alignment fault on RISC.
+ //
+ // NdisRawReadPortUshort(acb->AdapterConfigPort, &cfg_reg);
+ NdisRawReadPortUchar(acb->AdapterConfigPort, &cfg_regl);
+ NdisRawReadPortUchar(acb->AdapterConfigPort+1, &cfg_regh);
+ cfg_reg = (cfg_regh << 8) + cfg_regl;
+
+ //
+ // Read the actl register and turn off the reset bit.
+ //
+ NdisRawReadPortUshort( acb->SifActlPort, &actl_reg);
+
+ actl_reg &= ~ACTL_ARESET;
+
+ //
+ // If we're using FPA turn on ROM reserved bit 11
+ //
+ if (acb->acb_usefpa)
+ {
+ actl_reg |= ACTL_ROM;
+ }
+
+ //
+ // If the board is a Cpqtok board, just fill in the parameters,
+ // reset the board, and get out. If the board is a Netflx board,
+ // fill in the parameters, reset the board specifying the type and
+ // speed of the network, make sure we get what we asked for, and
+ // then get out.
+
+ if ( (board_id & NETFLEX_REVMASK) == CPQTOK_ID &&
+ (board_id != DURANGO_ID))
+ {
+ // This is a JUPITER board
+ //
+ DebugPrint(1,("NF(%d): Setting up Jupiter\n",acb->anum));
+
+ if (acb->AdapterInitializing)
+ {
+ nettype = NdisMedium802_5;
+ if (cfg_reg & CFG_16MBS)
+ netspeed = 4;
+ else
+ netspeed = 16;
+ //
+ // Setup the ProcessReceiveHandler
+ //
+ acb->ProcessReceiveHandler = &NetFlexProcessTrRcv;
+ }
+ }
+ else if ( ((board_id & NETFLEX_REVMASK) == NETFLEX_ID) ||
+ ((board_id & NETFLEX_REVMASK) == RODAN_ID) ||
+ (board_id == DURANGO_ID) )
+ {
+ //
+ // This is a NETFLEX, MAPLE, DURANGO or RODAN board
+ //
+ // The Nselout1 bit has been redefined as the media bit. If this
+ // bit is set to a 1, AUI/DB-9 has been selected. Otherwise,
+ // unshielded has been selected.
+ // If the CFG_MEDIA bit is set, Unshielded has been selected.
+
+ DebugPrint(1,("NF(%d): Setting up Netflx, Durango, or Rodan\n",acb->anum));
+
+ if (cfg_reg & CFG_MEDIA)
+ {
+ actl_reg &= (~ACTL_NSELOUT1);
+ }
+ else
+ {
+ actl_reg |= ACTL_NSELOUT1;
+ }
+
+ if (cfg_reg & CFG_16MBS)
+ {
+ actl_reg |= ACTL_NSELOUT0;
+ }
+ else
+ {
+ actl_reg &= (~ACTL_NSELOUT0);
+ }
+ }
+ else
+ {
+ // This is a BONSAI board
+ //
+ // Bits 3 and 2 represent net type for head 1 and 2, respectively.
+ DebugPrint(1,("NF(%d): Setting up Bonsai head %d\n",acb->anum,acb->acb_portnumber));
+
+ if (acb->acb_portnumber == PORT1)
+ {
+ if (cfg_reg & CFG_DUALPT_ADP1)
+ {
+ actl_reg &= (~ACTL_NSELOUT1);
+ }
+ else
+ {
+ actl_reg |= ACTL_NSELOUT1;
+ }
+ }
+ else
+ {
+ if (cfg_reg & CFG_DUALPT_ADP2)
+ {
+ actl_reg &= (~ACTL_NSELOUT1);
+ }
+ else
+ {
+ actl_reg |= ACTL_NSELOUT1;
+ }
+ }
+ }
+
+ NdisRawWritePortUshort(acb->SifActlPort, actl_reg);
+
+ //
+ // If this is during an initial initialization
+ //
+ if (acb->AdapterInitializing)
+ {
+ //
+ // If this is a NETFLEX type board, make sure we got what
+ // we were asking for
+ //
+ if ( ( (board_id & NETFLEX_REVMASK) == NETFLEX_ID ) ||
+ ( (board_id & NETFLEX_REVMASK) == BONSAI_ID ) ||
+ ( (board_id & NETFLEX_REVMASK) == RODAN_ID ) ||
+ (board_id == DURANGO_ID) )
+ {
+ NdisRawReadPortUshort( acb->SifActlPort, &actl_reg);
+ //
+ // Now, find out our network type and speed.
+ //
+ if (actl_reg & ACTL_TEST1)
+ {
+ //
+ // We are token ring. Are we 16 mbps or 4 mbps.
+ //
+ nettype = NdisMedium802_5;
+ if (actl_reg & ACTL_TEST0)
+ netspeed = 4;
+ else
+ netspeed = 16;
+
+ //
+ // Setup the ProcessReceiveHandler
+ //
+ acb->ProcessReceiveHandler = &NetFlexProcessTrRcv;
+
+ }
+ else
+ {
+ // Ethernet is selected
+ nettype = NdisMedium802_3;
+ netspeed = 10;
+ //
+ // Setup the ProcessReceiveHandler
+ //
+ acb->ProcessReceiveHandler = &NetFlexProcessEthRcv;
+ }
+ }
+ //
+ // Initialize some of acb fields as well as adapter information.
+ //
+ acb->acb_gen_objs.media_type_in_use = nettype;
+ acb->acb_gen_objs.link_speed = netspeed;
+ }
+ else
+ {
+ nettype = acb->acb_gen_objs.media_type_in_use;
+ netspeed = acb->acb_gen_objs.link_speed;
+ }
+
+ //
+ // Check Full Duplex Support... Ethernet Only!
+ //
+ if (nettype == NdisMedium802_3)
+ {
+ // Do we want Full Duplex?
+ //
+
+ if (acb->acb_portnumber != PORT2)
+ {
+ NdisRawReadPortUchar( acb->BasePorts + CFG_REG2_OFF , &cfg_reg2);
+ if (cfg_reg2 & CFG_FULL_DUPLEX)
+ {
+ acb->FullDuplexEnabled = TRUE;
+ }
+ }
+ else
+ {
+ NdisRawReadPortUchar( acb->BasePorts + CFG_REG2_OFF - DUALHEAD_CFG_PORT_OFFSET, &cfg_reg2);
+ if (cfg_reg2 & CFG_FULL_DUPLEX_HEAD2)
+ {
+ acb->FullDuplexEnabled = TRUE;
+ }
+ }
+
+ if (acb->FullDuplexEnabled)
+ {
+ DebugPrint(1,("NF(%d): Enabling FullDuplex Support!\n",acb->anum));
+ if ( (board_id & NETFLEX_REVMASK) == BONSAI_ID )
+ {
+ // On Bansai, disable colision detect by writing to 0xZc67 for H2 0xZc66 for H1
+ //
+ if (acb->acb_portnumber == PORT2)
+ {
+ NdisRawWritePortUchar( acb->ExtConfigPorts + LOOP_BACK_ENABLE_HEAD2_OFF , 0xff);
+ }
+ else
+ {
+ NdisRawWritePortUchar( acb->ExtConfigPorts + LOOP_BACK_ENABLE_HEAD1_OFF , 0xff);
+ }
+ }
+ else
+ {
+ // On NetFlex/NetFlex-2, disable colision detect by writing to 0xZc65
+ // until status indicates that it is ok, per Ray...
+ //
+ do
+ {
+ NdisRawWritePortUchar( acb->ExtConfigPorts + LOOP_BACK_ENABLE_OFF , 0xff);
+ NdisStallExecution((UINT)1000); // Wait 1 milliseconds
+ NdisRawReadPortUchar( acb->ExtConfigPorts + LOOP_BACK_STATUS_OFF , &tmp_reg);
+ } while (tmp_reg & COLL_DETECT_ENABLED);
+ }
+ }
+ }
+}
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexFinishUnloading
+//
+// Description: This routine finishes the unloading process
+//
+// Input: None.
+//
+// Output: None.
+//
+// Calls: NdisDeregisterMac,NdisTerminateWrapper,
+//
+// Called By: NetFlexUnload, NetFlexDeregisterAdapter
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+VOID NetFlexFinishUnloading(VOID)
+{
+ //
+ //
+ // Free the memory with the download software in it.
+ //
+ if (macgbls.DownloadCode != NULL) {
+
+ NdisFreeMemory( macgbls.DownloadCode,
+ macgbls.DownloadLength,
+ 0);
+
+ }
+
+ NdisTerminateWrapper(macgbls.mac_wrapper,(PVOID)NULL);
+ macgbls.mac_wrapper = NULL;
+ macgbls.DownloadCode= NULL;
+ macgbls.DownloadLength = 0;
+}
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexDeregisterAdapter
+//
+// Description:
+// This routine finishes the removal of an adapter.
+//
+// Input:
+// acb - Our Driver Context.
+//
+// Output:
+// None.
+//
+// Called By:
+// NetFlexHalt, NetFlexInitialize
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+VOID NetFlexDeregisterAdapter(PACB acb)
+{
+ //
+ // Remove the acb from the mac's acb list
+ //
+ NetFlexDequeue_OnePtrQ((PVOID *) &macgbls.mac_adapters,(PVOID)acb);
+
+ if (acb->acb_interrupt.InterruptObject != NULL)
+ NdisMDeregisterInterrupt(&acb->acb_interrupt);
+
+ //
+ // Deallocate the memory for the acb.
+ //
+ NetFlexDeallocateAcb(acb);
+
+ if ((macgbls.mac_adapters == NULL) && !macgbls.Initializing)
+ {
+ NetFlexFinishUnloading();
+ }
+}
+
diff --git a/private/ntos/ndis/netflex/sources b/private/ntos/ndis/netflex/sources
new file mode 100644
index 000000000..22fd6def5
--- /dev/null
+++ b/private/ntos/ndis/netflex/sources
@@ -0,0 +1,84 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+ Carol Fuss 13-July-1992 - Converted for the Netflx driver.
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=netflx
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+#
+# Standard Dynamic Ratio w/o Xmit Ints
+#
+C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER -DDBGPRINT=0
+
+#
+# Add Xmit Ints
+#
+C_DEFINES=$(C_DEFINES) -DXMIT_INTS
+
+#
+# Add Newer Dynamic Ratio
+#
+C_DEFINES=$(C_DEFINES) -DNEW_DYNAMIC_RATIO
+
+#
+# Add dynamic ratio history.
+#
+#C_DEFINES=$(C_DEFINES) -DDYNAMIC_RATIO_HISTORY
+
+#
+# Turn on dynamic ratio stuff.
+#
+C_DEFINES=$(C_DEFINES) -DALLOW_DISABLE_DYNAMIC_RATIO
+
+#
+# Turn off binary compatibility. Comment out the line below to enable it.
+#
+C_DEFINES=$(C_DEFINES) -DBINARY_COMPATIBLE=0 -DNDIS40_MINIPORT
+
+INCLUDES=..\..\inc;..\..\..\inc
+
+NTPROFILEINPUT=yes
+
+
+SOURCES= init.c \
+ initd.c \
+ int.c \
+ request.c \
+ receive.c \
+ reset.c \
+ support.c \
+ netflex.rc \
+ transmit.c
+
+RELATIVE_DEPTH=..\..
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+NTTARGETFILES=netflx.bin
diff --git a/private/ntos/ndis/netflex/support.c b/private/ntos/ndis/netflex/support.c
new file mode 100644
index 000000000..73a0dc74b
--- /dev/null
+++ b/private/ntos/ndis/netflex/support.c
@@ -0,0 +1,1986 @@
+//**********************************************************************
+//**********************************************************************
+//
+// File Name: SUPPORT.C
+//
+// Program Name: NetFlex NDIS 3.0 Miniport Driver
+//
+// Companion Files: None
+//
+// Function: This module contains the NetFlex Miniport Driver
+// interface routines called by the Wrapper and the
+// configuration manager.
+//
+// (c) Compaq Computer Corporation, 1992,1993,1994
+//
+// This file is licensed by Compaq Computer Corporation to Microsoft
+// Corporation pursuant to the letter of August 20, 1992 from
+// Gary Stimac to Mark Baber.
+//
+// History:
+//
+// 04/15/94 Robert Van Cleve - Converted from NDIS Mac Driver
+//
+//**********************************************************************
+//**********************************************************************
+
+
+//-------------------------------------
+// Include all general companion files
+//-------------------------------------
+
+#if (DBG || DBGPRINT)
+#include <stdarg.h>
+#include <stdio.h>
+
+#endif
+
+#include <ndis.h>
+#include "tmsstrct.h"
+#include "macstrct.h"
+#include "adapter.h"
+#include "protos.h"
+
+
+#if (DBG || DBGPRINT)
+ULONG DebugLevel=1;
+#endif
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexInitializeAcb
+//
+// Description: This routine initializes the given ACB. This
+// routine allocates memory for certain fields
+// pointed to by the ACB.
+//
+// Input: acb - Pointer to acb to fill in.
+// parms - Settable mac driver parms.
+//
+// Output: Returns NDIS_STATUS_SUCCESS for a successful
+// completion. Otherwise, an error code is
+// returned.
+//
+// Calls: NdisAllocateMemory,NdisZeroMemory,NdisMoveMemory
+// NdisMAllocateSharedMemory,SWAPL,CTRL_ADDR
+//
+// Called By: NetFlexInitialize
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+NDIS_STATUS
+NetFlexInitializeAcb(PACB acb)
+{
+ USHORT i;
+
+ PRCV CurrentReceiveEntry;
+ PXMIT CurrentXmitEntry;
+ PVOID start, next, current;
+ ULONG next_phys, current_phys, temp;
+ PETH_OBJS ethobjs;
+ NDIS_STATUS Status;
+ PBUFFER_DESCRIPTOR OurBuf;
+ ULONG LowPart;
+ PUCHAR CurrentReceiveBuffer;
+ PUCHAR CurrentMergeBuffer;
+ PNETFLEX_PARMS parms = acb->acb_parms;
+ ULONG Alignment, FrameSizeCacheAligned;
+
+ DebugPrint(1,("NF(%d): NetFlexInitializeAcb entered.\n",acb->anum));
+
+ //
+ // Initialize pointers and counters
+ //
+ acb->InterruptsDisabled = FALSE; // interrupts are enabled after a reset.
+ acb->ResetState = 0;
+
+ //
+ // Set up rest of general oid variables.
+ //
+ acb->acb_smallbufsz = parms->utd_smallbufsz;
+ acb->acb_maxmaps = parms->utd_maxtrans * MAX_BUFS_PER_XMIT;
+ acb->acb_gen_objs.max_frame_size = parms->utd_maxframesz;
+ acb->acb_lastringstate = NdisRingStateClosed;
+ acb->acb_curmap = 0;
+
+ //
+ // Get the max frame size, cache align it and a save it for later.
+ //
+
+ Alignment = NdisGetCacheFillSize();
+
+ if ( Alignment < sizeof(ULONG) ) {
+
+ Alignment = sizeof(ULONG);
+ }
+
+ FrameSizeCacheAligned = (parms->utd_maxframesz + Alignment - 1) & ~(Alignment - 1);
+
+ //
+ // Allocate the map registers
+ //
+
+ if (NdisMAllocateMapRegisters(
+ acb->acb_handle,
+ 0,
+ TRUE,
+ acb->acb_maxmaps,
+ acb->acb_gen_objs.max_frame_size
+ ) != NDIS_STATUS_SUCCESS)
+ {
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ //
+ // Get the OID structures set up. The list of oids is determined
+ // by the network type of the adapter. Also set up any network type
+ // specific information.
+ //
+ if (acb->acb_gen_objs.media_type_in_use == NdisMedium802_3)
+ {
+ // ETHERNET
+
+ //
+ // Load up the oid pointers and lengths
+ //
+ acb->acb_gbl_oid_list = (PNDIS_OID)NetFlexGlobalOIDs_Eth;
+ acb->acb_gbl_oid_list_size = NetFlexGlobalOIDs_Eth_size;
+ acb->acb_spec_oid_list = (PNDIS_OID)NetFlexNetworkOIDs_Eth;
+ acb->acb_spec_oid_list_size = NetFlexNetworkOIDs_Eth_size;
+
+ //
+ // Allocate and Zero out the Memory for Ethernet specific objects
+ //
+ NdisAllocateMemory( (PVOID *)&(acb->acb_spec_objs),
+ (UINT) (sizeof (ETH_OBJS)),
+ (UINT) 0,
+ NetFlexHighestAddress);
+
+ if (acb->acb_spec_objs == NULL)
+ {
+ return(NDIS_STATUS_RESOURCES);
+ }
+ NdisZeroMemory( acb->acb_spec_objs, sizeof (ETH_OBJS) );
+
+ //
+ // Allocate and Zero out Memory for the Multicast table.
+ //
+ ethobjs = (PETH_OBJS)(acb->acb_spec_objs);
+ ethobjs->MaxMulticast = parms->utd_maxmulticast;
+
+ NdisAllocateMemory( (PVOID *)&ethobjs->MulticastEntries,
+ (UINT) (ethobjs->MaxMulticast * NET_ADDR_SIZE),
+ (UINT) 0,
+ NetFlexHighestAddress);
+ if (ethobjs->MulticastEntries == NULL)
+ {
+ return(NDIS_STATUS_RESOURCES);
+ }
+ NdisZeroMemory(ethobjs->MulticastEntries, ethobjs->MaxMulticast * NET_ADDR_SIZE);
+ ethobjs->NumberOfEntries = 0;
+
+ //
+ // Allocate Memory for sending multicast requests to the adapter.
+ //
+ NdisMAllocateSharedMemory( acb->acb_handle,
+ (ULONG)(sizeof(MULTI_BLOCK) * 2),
+ FALSE,
+ (PVOID *)(&(acb->acb_multiblk_virtptr)),
+ &acb->acb_multiblk_physptr);
+
+ if (acb->acb_multiblk_virtptr == NULL)
+ {
+ return(NDIS_STATUS_RESOURCES);
+ }
+ }
+ else
+ {
+ // TOKEN RING
+
+ //
+ // Load up the oid pointers and lengths
+ //
+ acb->acb_gbl_oid_list = (PNDIS_OID)NetFlexGlobalOIDs_Tr;
+ acb->acb_gbl_oid_list_size = NetFlexGlobalOIDs_Tr_size;
+ acb->acb_spec_oid_list = (PNDIS_OID)NetFlexNetworkOIDs_Tr;
+ acb->acb_spec_oid_list_size = NetFlexNetworkOIDs_Tr_size;
+
+ //
+ // Allocate and Zero out Memory for Token Ring specific objects
+ //
+ NdisAllocateMemory( (PVOID *)&(acb->acb_spec_objs),
+ (UINT) (sizeof (TR_OBJS)),
+ (UINT) 0,
+ NetFlexHighestAddress);
+
+ if (acb->acb_spec_objs == NULL)
+ {
+ return(NDIS_STATUS_RESOURCES);
+ }
+ NdisZeroMemory( acb->acb_spec_objs, sizeof (TR_OBJS) );
+ }
+
+ //
+ // Allocate the SCB for this adapter.
+ //
+ NdisMAllocateSharedMemory( acb->acb_handle,
+ (ULONG)SIZE_SCB,
+ FALSE,
+ (PVOID *)(&(acb->acb_scb_virtptr)),
+ &acb->acb_scb_physptr);
+
+ if (acb->acb_scb_virtptr == NULL)
+ {
+ DebugPrint(1,("NF(%d): NetFlexInitializeAcb: Allocating SCB failed.\n",acb->anum));
+
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ //
+ // Allocate the SSB for this adapter.
+ //
+ NdisMAllocateSharedMemory( acb->acb_handle,
+ (ULONG)SIZE_SSB,
+ FALSE,
+ (PVOID *)(&(acb->acb_ssb_virtptr)),
+ &acb->acb_ssb_physptr);
+
+ if (acb->acb_ssb_virtptr == NULL)
+ {
+ DebugPrint(1,("NF(%d): NetFlexInitializeAcb: Allocating SSB failed.\n",acb->anum));
+
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ acb->acb_maxinternalbufs = parms->utd_maxinternalbufs;
+ acb->acb_numsmallbufs = parms->utd_numsmallbufs;
+
+ //
+ // Allocate Flush Buffer Pool for our InteralBuffers and the ReceiveBuffers
+ //
+ NdisAllocateBufferPool(
+ &Status,
+ (PVOID*)&acb->FlushBufferPoolHandle,
+ acb->acb_gen_objs.max_frame_size * ( parms->utd_maxinternalbufs + acb->acb_maxrcvs + acb->acb_maxinternalbufs));
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DebugPrint(1,("NF(%d): NetFlexInitializeAcb: Allocating flush buffer pool failed.\n",acb->anum));
+
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ //
+ // Now allocate our internal buffers, and their flush buffers...
+ //
+ NdisAllocateMemory(
+ (PVOID *) &acb->OurBuffersVirtPtr,
+ sizeof(BUFFER_DESCRIPTOR) * acb->acb_maxinternalbufs,
+ (UINT) 0,
+ NetFlexHighestAddress);
+
+ //
+ // Zero the memory of all the descriptors so that we can
+ // know which buffers weren't allocated incase we can't allocate
+ // them all.
+ //
+ NdisZeroMemory(
+ acb->OurBuffersVirtPtr,
+ sizeof(BUFFER_DESCRIPTOR) * acb->acb_maxinternalbufs );
+
+
+ //
+ // Allocate each of the buffers and fill in the
+ // buffer descriptor.
+ //
+ OurBuf = acb->OurBuffersVirtPtr;
+
+ NdisMAllocateSharedMemory(
+ acb->acb_handle,
+ FrameSizeCacheAligned * acb->acb_maxinternalbufs,
+ TRUE,
+ &acb->MergeBufferPoolVirt,
+ &acb->MergeBufferPoolPhys);
+
+ if ( acb->MergeBufferPoolVirt != NULL )
+ {
+ acb->MergeBuffersAreContiguous = TRUE;
+
+ CurrentMergeBuffer = acb->MergeBufferPoolVirt;
+
+ LowPart = NdisGetPhysicalAddressLow(acb->MergeBufferPoolPhys);
+
+ //
+ // If the high part is non-zero then this adapter is hosed anyway since
+ // its a 32-bit busmaster device.
+ //
+ ASSERT( NdisGetPhysicalAddressHigh(acb->MergeBufferPoolPhys) == 0 );
+ }
+ else
+ {
+ acb->MergeBuffersAreContiguous = FALSE;
+
+ acb->MergeBufferPoolVirt = NULL;
+
+ CurrentMergeBuffer = NULL;
+ }
+
+ for (i = 0; i < acb->acb_maxinternalbufs; i++ )
+ {
+ //
+ // Allocate a buffer
+ //
+ if ( acb->MergeBuffersAreContiguous )
+ {
+ OurBuf->VirtualBuffer = CurrentMergeBuffer;
+
+ NdisSetPhysicalAddressLow(OurBuf->PhysicalBuffer, LowPart);
+ NdisSetPhysicalAddressHigh(OurBuf->PhysicalBuffer, 0);
+
+ CurrentMergeBuffer += FrameSizeCacheAligned;
+
+ LowPart += FrameSizeCacheAligned;
+ }
+ else
+ {
+ NdisMAllocateSharedMemory(
+ acb->acb_handle,
+ parms->utd_maxframesz,
+ TRUE,
+ &OurBuf->VirtualBuffer,
+ &OurBuf->PhysicalBuffer);
+
+ if ( OurBuf->VirtualBuffer == NULL )
+ {
+ DebugPrint(1,("NF(%d): NetFlexInitializeAcb: Allocating individual merge buffer failed.\n",acb->anum));
+
+ return NDIS_STATUS_RESOURCES;
+ }
+ }
+
+ //
+ // Build flush buffers
+ //
+ NdisAllocateBuffer(
+ &Status,
+ &OurBuf->FlushBuffer,
+ acb->FlushBufferPoolHandle,
+ OurBuf->VirtualBuffer,
+ acb->acb_gen_objs.max_frame_size );
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DebugPrint(1,("NF(%d): NetFlexInitializeAcb: Allocating FLUSH buffer failed.\n",acb->anum));
+
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ //
+ // Insert this buffer into the queue
+ //
+ OurBuf->Next = (OurBuf + 1);
+ OurBuf->BufferSize = acb->acb_gen_objs.max_frame_size;
+ OurBuf = OurBuf->Next;
+ }
+
+ //
+ // Make sure that the last buffer correctly terminates the free list.
+ //
+ (OurBuf - 1)->Next = NULL;
+ acb->OurBuffersListHead = acb->OurBuffersVirtPtr;
+
+ //
+ // Now allocate our internal buffers, and their flush buffers...
+ //
+ NdisAllocateMemory(
+ (PVOID *) &acb->SmallBuffersVirtPtr,
+ sizeof(BUFFER_DESCRIPTOR) * parms->utd_numsmallbufs,
+ (UINT) 0,
+ NetFlexHighestAddress);
+
+ //
+ // Zero the memory of all the descriptors so that we can
+ // know which buffers weren't allocated incase we can't allocate
+ // them all.
+ //
+ NdisZeroMemory(
+ acb->SmallBuffersVirtPtr,
+ sizeof(BUFFER_DESCRIPTOR) * parms->utd_numsmallbufs);
+
+ //
+ // Allocate each of the buffers and fill in the
+ // buffer descriptor.
+ //
+ OurBuf = acb->SmallBuffersVirtPtr;
+
+ NdisMAllocateSharedMemory(
+ acb->acb_handle,
+ acb->acb_smallbufsz * parms->utd_numsmallbufs,
+ TRUE,
+ &acb->SmallBufferPoolVirt,
+ &acb->SmallBufferPoolPhys);
+
+ if ( acb->SmallBufferPoolVirt != NULL )
+ {
+ acb->SmallBuffersAreContiguous = TRUE;
+
+ CurrentMergeBuffer = acb->SmallBufferPoolVirt;
+
+ LowPart = NdisGetPhysicalAddressLow(acb->SmallBufferPoolPhys);
+
+ //
+ // If the high part is non-zero then this adapter is hosed anyway since
+ // its a 32-bit busmaster device.
+ //
+
+ ASSERT( NdisGetPhysicalAddressHigh(acb->SmallBufferPoolPhys) == 0 );
+
+ }
+ else
+ {
+ acb->SmallBuffersAreContiguous = FALSE;
+
+ acb->SmallBufferPoolVirt = NULL;
+
+ CurrentMergeBuffer = NULL;
+ }
+
+ for (i = 0; i < parms->utd_numsmallbufs; i++ )
+ {
+ //
+ // Allocate a small buffer
+ //
+
+ if ( acb->SmallBuffersAreContiguous ) {
+
+ OurBuf->VirtualBuffer = CurrentMergeBuffer;
+
+ NdisSetPhysicalAddressLow(OurBuf->PhysicalBuffer, LowPart);
+ NdisSetPhysicalAddressHigh(OurBuf->PhysicalBuffer, 0);
+
+ CurrentMergeBuffer += acb->acb_smallbufsz;
+
+ LowPart += acb->acb_smallbufsz;
+
+ } else {
+
+ NdisMAllocateSharedMemory(
+ acb->acb_handle,
+ acb->acb_smallbufsz,
+ TRUE,
+ &OurBuf->VirtualBuffer,
+ &OurBuf->PhysicalBuffer
+ );
+
+ if ( OurBuf->VirtualBuffer == NULL ) {
+
+ DebugPrint(1,("NF(%d): NetFlexInitializeAcb: Allocating individual merge buffer failed.\n",acb->anum));
+
+ return NDIS_STATUS_RESOURCES;
+ }
+ }
+
+ //
+ // Build flush buffers
+ //
+
+ NdisAllocateBuffer( &Status,
+ &OurBuf->FlushBuffer,
+ acb->FlushBufferPoolHandle,
+ OurBuf->VirtualBuffer,
+ acb->acb_smallbufsz );
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DebugPrint(1,("NF(%d): NetFlexInitializeAcb: Allocating FLUSH buffer failed.\n",acb->anum));
+
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ //
+ // Insert this buffer into the queue
+ //
+ OurBuf->Next = (OurBuf + 1);
+ OurBuf->BufferSize = acb->acb_smallbufsz;
+ OurBuf = OurBuf->Next;
+ }
+
+ //
+ // Make sure that the last buffer correctly terminates the free list.
+ //
+ (OurBuf - 1)->Next = NULL;
+ acb->SmallBuffersListHead = acb->SmallBuffersVirtPtr;
+
+ //
+ // Now, Allocate the transmit lists
+ //
+ acb->acb_maxtrans = parms->utd_maxtrans * (USHORT)MAX_LISTS_PER_XMIT;
+ NdisMAllocateSharedMemory( acb->acb_handle,
+ (ULONG)(SIZE_XMIT * acb->acb_maxtrans),
+ FALSE,
+ (PVOID *)&acb->acb_xmit_virtptr,
+ &acb->acb_xmit_physptr);
+
+ if (acb->acb_xmit_virtptr == NULL)
+ {
+ DebugPrint(1,("NF(%d): NetFlexInitializeAcb: Allocating transmit list failed.\n",acb->anum));
+
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ //
+ // Initialize the transmit lists and link them together.
+ //
+
+ acb->acb_xmit_head = acb->acb_xmit_virtptr;
+
+ current_phys = NdisGetPhysicalAddressLow(acb->acb_xmit_physptr);
+
+ for (i = 0, CurrentXmitEntry = acb->acb_xmit_virtptr;
+ i < acb->acb_maxtrans;
+ i++, CurrentXmitEntry++ )
+ {
+ NdisSetPhysicalAddressHigh(CurrentXmitEntry->XMIT_Phys, 0);
+ NdisSetPhysicalAddressLow( CurrentXmitEntry->XMIT_Phys,
+ current_phys);
+
+ CurrentXmitEntry->XMIT_MyMoto = SWAPL(CTRL_ADDR((LONG)current_phys));
+
+ CurrentXmitEntry->XMIT_CSTAT = 0;
+
+#ifdef XMIT_INTS
+ CurrentXmitEntry->XMIT_Number = i;
+#endif
+ next_phys = current_phys + SIZE_XMIT;
+
+ //
+ // Make the forward pointer odd.
+ //
+ CurrentXmitEntry->XMIT_FwdPtr = SWAPL(CTRL_ADDR((LONG)next_phys));
+
+ CurrentXmitEntry->XMIT_Next = (CurrentXmitEntry + 1);
+ CurrentXmitEntry->XMIT_OurBufferPtr = NULL;
+ current_phys = next_phys;
+ }
+
+ //
+ // Make sure the last entry is properly set to the begining...
+ //
+ (CurrentXmitEntry - 1)->XMIT_Next = acb->acb_xmit_virtptr;
+ (CurrentXmitEntry - 1)->XMIT_FwdPtr =
+ SWAPL(CTRL_ADDR(NdisGetPhysicalAddressLow(acb->acb_xmit_physptr)));
+
+ acb->acb_avail_xmit = parms->utd_maxtrans;
+
+ //
+ // Now, Allocate the Receive lists.
+ //
+ NdisMAllocateSharedMemory( acb->acb_handle,
+ (ULONG)(sizeof(RCV) * parms->utd_maxrcvs),
+ FALSE,
+ (PVOID *) &acb->acb_rcv_virtptr,
+ &acb->acb_rcv_physptr);
+
+ if (acb->acb_rcv_virtptr == NULL)
+ {
+ DebugPrint(1,("NF(%d): NetFlexInitializeAcb: Allocating receive list failed.\n",acb->anum));
+
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ //
+ // Point the head to the first one...
+ //
+ acb->acb_rcv_head = acb->acb_rcv_virtptr;
+ //
+ // Clear the receive lists
+ //
+ NdisZeroMemory( acb->acb_rcv_virtptr,
+ sizeof(RCV) * parms->utd_maxrcvs );
+
+ //
+ // Initialize the receive lists and link them together.
+ //
+
+ acb->acb_maxrcvs = parms->utd_maxrcvs;
+ current_phys = NdisGetPhysicalAddressLow(acb->acb_rcv_physptr);
+
+ CurrentReceiveEntry = acb->acb_rcv_virtptr;
+
+ //
+ // Create the receive buffer pool.
+ //
+
+ NdisMAllocateSharedMemory(
+ acb->acb_handle,
+ FrameSizeCacheAligned * parms->utd_maxrcvs,
+ TRUE,
+ &acb->ReceiveBufferPoolVirt,
+ &acb->ReceiveBufferPoolPhys
+ );
+
+ if ( acb->ReceiveBufferPoolVirt != NULL ) {
+
+ acb->RecvBuffersAreContiguous = TRUE;
+
+ CurrentReceiveBuffer = acb->ReceiveBufferPoolVirt;
+
+ LowPart = NdisGetPhysicalAddressLow(acb->ReceiveBufferPoolPhys);
+
+ //
+ // If the high part is non-zero then this adapter is hosed anyway since
+ // its a 32-bit busmaster device.
+ //
+
+ ASSERT( NdisGetPhysicalAddressHigh(acb->ReceiveBufferPoolPhys) == 0 );
+
+ } else {
+
+ acb->RecvBuffersAreContiguous = FALSE;
+
+ acb->ReceiveBufferPoolVirt = NULL;
+
+ CurrentReceiveBuffer = NULL;
+ }
+
+ for ( i = 0; i < parms->utd_maxrcvs; ++i, ++CurrentReceiveEntry )
+ {
+ //
+ // Allocate the actual receive frame buffers.
+ //
+
+ if ( acb->RecvBuffersAreContiguous ) {
+
+ CurrentReceiveEntry->RCV_Buf = CurrentReceiveBuffer;
+
+ NdisSetPhysicalAddressLow(CurrentReceiveEntry->RCV_BufPhys, LowPart);
+ NdisSetPhysicalAddressHigh(CurrentReceiveEntry->RCV_BufPhys, 0);
+
+ CurrentReceiveBuffer += FrameSizeCacheAligned;
+
+ LowPart += FrameSizeCacheAligned;
+
+ } else {
+
+ NdisMAllocateSharedMemory(
+ acb->acb_handle,
+ parms->utd_maxframesz,
+ TRUE,
+ &CurrentReceiveEntry->RCV_Buf,
+ &CurrentReceiveEntry->RCV_BufPhys
+ );
+
+ if ( CurrentReceiveEntry->RCV_Buf == NULL ) {
+
+ DebugPrint(1,("NF(%d): NetFlexInitializeAcb: Allocating individual receive buffer failed.\n",acb->anum));
+
+ return NDIS_STATUS_RESOURCES;
+ }
+ }
+
+ //
+ // Build flush buffers
+ //
+
+ NdisAllocateBuffer(
+ &Status,
+ &CurrentReceiveEntry->RCV_FlushBuffer,
+ acb->FlushBufferPoolHandle,
+ CurrentReceiveEntry->RCV_Buf,
+ acb->acb_gen_objs.max_frame_size);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DebugPrint(1,("NF(%d): NetFlexInitializeAcb: Allocating FLUSH receive buffer failed.\n",acb->anum));
+
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ //
+ // Initialize receive buffers
+ //
+ NdisFlushBuffer(CurrentReceiveEntry->RCV_FlushBuffer, FALSE);
+
+ CurrentReceiveEntry->RCV_Number = i;
+ CurrentReceiveEntry->RCV_CSTAT = ((i % acb->RcvIntRatio) == 0) ? RCSTAT_GO_INT : RCSTAT_GO;
+
+ CurrentReceiveEntry->RCV_Dsize = (SHORT) SWAPS((USHORT)(acb->acb_gen_objs.max_frame_size));
+ CurrentReceiveEntry->RCV_Dsize &= DATA_LAST;
+
+ temp = NdisGetPhysicalAddressLow(CurrentReceiveEntry->RCV_BufPhys);
+ temp = SWAPL(temp);
+
+ CurrentReceiveEntry->RCV_DptrHi = (USHORT)temp;
+ CurrentReceiveEntry->RCV_DptrLo = (USHORT)(temp >> 16);
+
+ NdisSetPhysicalAddressHigh(CurrentReceiveEntry->RCV_Phys, 0);
+ NdisSetPhysicalAddressLow( CurrentReceiveEntry->RCV_Phys,
+ current_phys);
+
+ next_phys = current_phys + SIZE_RCV;
+
+ CurrentReceiveEntry->RCV_FwdPtr = SWAPL(CTRL_ADDR(next_phys));
+ CurrentReceiveEntry->RCV_MyMoto = SWAPL(CTRL_ADDR(current_phys));
+
+ CurrentReceiveEntry->RCV_Next = (CurrentReceiveEntry + 1);
+ current_phys = next_phys;
+ }
+
+ //
+ // Make sure the last entry is properly set to the begining...
+ //
+ (CurrentReceiveEntry - 1)->RCV_Next = acb->acb_rcv_virtptr;
+ (CurrentReceiveEntry - 1)->RCV_FwdPtr =
+ SWAPL(CTRL_ADDR(NdisGetPhysicalAddressLow(acb->acb_rcv_physptr)));
+
+ //
+ // Allocate and initialize the OPEN parameter block.
+ //
+ NdisMAllocateSharedMemory( acb->acb_handle,
+ (ULONG)SIZE_OPEN,
+ FALSE,
+ (PVOID *)(&(acb->acb_opnblk_virtptr)),
+ &acb->acb_opnblk_physptr );
+
+ if (acb->acb_opnblk_virtptr == NULL)
+ {
+ DebugPrint(1,("NF(%d): NetFlexInitializeAcb: Allocating OPEN block failed.\n",acb->anum));
+
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ NdisMoveMemory(acb->acb_opnblk_virtptr, &(parms->utd_open), SIZE_OPEN);
+
+ //
+ // Convert the product ID pointer in the Open parameter block
+ // into a big endian type address.
+ //
+ acb->acb_opnblk_virtptr->OPEN_ProdIdPtr =
+ (CHAR *) (SWAPL((LONG) acb->acb_opnblk_virtptr->OPEN_ProdIdPtr));
+
+ acb->acb_openoptions = parms->utd_open.OPEN_Options;
+
+ //
+ // Initialize the intialization block.
+ //
+ NdisMoveMemory(&acb->acb_initblk, &init_mask, SIZE_INIT);
+
+ //
+ // Allocate Memory to hold the Read Statistics Log information.
+ //
+ NdisMAllocateSharedMemory( acb->acb_handle,
+ (ULONG)(sizeof(RSL)),
+ FALSE,
+ (PVOID *)(&(acb->acb_logbuf_virtptr)),
+ &acb->acb_logbuf_physptr );
+
+ if (acb->acb_logbuf_virtptr == NULL)
+ {
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ //
+ // Allocate Memory for internal SCB requests.
+ //
+ NdisAllocateMemory( (PVOID *)&(start),
+ (UINT) (SCBREQSIZE * parms->utd_maxinternalreqs),
+ (UINT) NDIS_MEMORY_CONTIGUOUS,
+ NetFlexHighestAddress);
+ if (start == NULL)
+ {
+ DebugPrint(1,("NF(%d): NetFlexInitializeAcb: Allocating internal SCB request failed.\n",acb->anum));
+
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ //
+ // Initialize the SCB requests and place them on the free queue.
+ //
+ acb->acb_maxreqs = parms->utd_maxinternalreqs;
+ current = start;
+ for (i = 0; i < parms->utd_maxinternalreqs; i++)
+ {
+ next = (PVOID)( ((PUCHAR)(current)) + SCBREQSIZE);
+ ((PSCBREQ) current)->req_next = next;
+ if (i < (USHORT)(parms->utd_maxinternalreqs-1))
+ {
+ current = next;
+ }
+ }
+ ((PSCBREQ)current)->req_next = (PSCBREQ) NULL;
+ acb->acb_scbreq_ptr = (PSCBREQ)start;
+ acb->acb_scbreq_free = (PSCBREQ)start;
+
+ //
+ // Allocate Memory for the internal MAC requests.
+ //
+ NdisAllocateMemory( (PVOID *)&(start),
+ (UINT) (MACREQSIZE * parms->utd_maxinternalreqs),
+ (UINT) NDIS_MEMORY_CONTIGUOUS,
+ NetFlexHighestAddress);
+ if (start == NULL)
+ {
+ DebugPrint(1,("NF(%d): NetFlexInitializeAcb: Allocating internal MAC request failed.\n",acb->anum));
+
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ //
+ // Initialize the internal MAC requests and place them
+ // on the free queue.
+ //
+ current = start;
+ for (i = 0; i < parms->utd_maxinternalreqs; i++)
+ {
+ next = (PVOID)( ((PUCHAR)(current)) + MACREQSIZE);
+ ((PMACREQ) current)->req_next = next;
+ if (i < (USHORT)(parms->utd_maxinternalreqs-1))
+ {
+ current = next;
+ }
+ }
+ ((PMACREQ)current)->req_next = (PMACREQ) NULL;
+ acb->acb_macreq_ptr = (PMACREQ)start;
+ acb->acb_macreq_free = (PMACREQ)start;
+
+ DebugPrint(1,("NF(%d): NetFlexInitializeAcb completed successfully!\n",acb->anum));
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexDeallocateAcb
+//
+// Description: This routine deallocates the acb resources.
+//
+// Input: acb - Our Driver Context for this adapter or head.
+//
+// Output: None.
+//
+// Called By: NetFlexInitialize,
+// NetFlexDeregisterAdapter
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+VOID
+NetFlexDeallocateAcb(
+ PACB acb
+ )
+{
+ PETH_OBJS ethobjs;
+ PRCV CurrentReceiveEntry;
+ PNETFLEX_PARMS parms = acb->acb_parms;
+ USHORT i;
+ PBUFFER_DESCRIPTOR OurBuf;
+ ULONG Alignment, FrameSizeCacheAligned;
+
+ //
+ // Get the max frame size, cache align it and a save it for later.
+ //
+
+ Alignment = NdisGetCacheFillSize();
+
+ if ( Alignment < sizeof(ULONG) ) {
+
+ Alignment = sizeof(ULONG);
+ }
+
+ FrameSizeCacheAligned = (parms->utd_maxframesz + Alignment - 1) & ~(Alignment - 1);
+
+ //
+ // If we have allocated memory for the network specific information,
+ // release this memory now.
+ //
+
+ if (acb->acb_spec_objs)
+ {
+ if (acb->acb_gen_objs.media_type_in_use == NdisMedium802_3)
+ {
+ // ETHERNET
+
+ ethobjs = (PETH_OBJS)(acb->acb_spec_objs);
+ //
+ // If we have allocated the multicast table entries, free
+ // the memory.
+ //
+ if (ethobjs->MulticastEntries)
+ {
+ NdisFreeMemory( (PVOID)(ethobjs->MulticastEntries),
+ (UINT) (ethobjs->MaxMulticast * NET_ADDR_SIZE),
+ (UINT) 0);
+ }
+ //
+ // Deallocate Memory for Ethernet specific objects
+ //
+ NdisFreeMemory((PVOID)(acb->acb_spec_objs),
+ (UINT) (sizeof (ETH_OBJS)),
+ (UINT) 0);
+ }
+ else
+ {
+ // Token Ring
+ //
+ // Deallocate Memory for Token Ring specific objects
+ //
+ NdisFreeMemory( (PVOID)(acb->acb_spec_objs),
+ (UINT) (sizeof (TR_OBJS)),
+ (UINT) 0);
+
+ }
+ }
+
+ //
+ // If we have allocated memory for the multicast request to the
+ // adapter, free the memory.
+ //
+ if (acb->acb_multiblk_virtptr)
+ {
+ NdisMFreeSharedMemory( acb->acb_handle,
+ (ULONG)(sizeof(MULTI_BLOCK) * 2),
+ FALSE,
+ (PVOID)(acb->acb_multiblk_virtptr),
+ acb->acb_multiblk_physptr);
+ }
+
+ //
+ // If we have allocated memory for the scb, free the memory.
+ //
+ if (acb->acb_scb_virtptr)
+ {
+ NdisMFreeSharedMemory( acb->acb_handle,
+ (ULONG)SIZE_SCB,
+ FALSE,
+ (PVOID)(acb->acb_scb_virtptr),
+ acb->acb_scb_physptr);
+ }
+
+ //
+ // If we have allocated memory for the ssb, free the memory.
+ //
+ if (acb->acb_ssb_virtptr)
+ {
+ NdisMFreeSharedMemory( acb->acb_handle,
+ (ULONG)SIZE_SSB,
+ FALSE,
+ (PVOID)(acb->acb_ssb_virtptr),
+ acb->acb_ssb_physptr);
+ }
+
+ //
+ // Free merge buffer pool.
+ //
+
+ if (acb->MergeBufferPoolVirt) {
+
+ OurBuf = acb->OurBuffersVirtPtr;
+
+ //
+ // Free flush buffers
+ //
+
+ for (i = 0; i < acb->acb_maxinternalbufs; ++i, ++OurBuf) {
+
+ if (OurBuf->FlushBuffer)
+ {
+ NdisFreeBuffer(OurBuf->FlushBuffer);
+
+ if ( !acb->MergeBuffersAreContiguous ) {
+
+ NdisMFreeSharedMemory(
+ acb->acb_handle,
+ parms->utd_maxframesz,
+ TRUE,
+ OurBuf->VirtualBuffer,
+ OurBuf->PhysicalBuffer
+ );
+ }
+ }
+ }
+
+ //
+ // Free the pool itself.
+ //
+
+ if ( acb->MergeBuffersAreContiguous ) {
+
+ NdisMFreeSharedMemory(
+ acb->acb_handle,
+ FrameSizeCacheAligned * acb->acb_maxinternalbufs,
+ TRUE,
+ acb->MergeBufferPoolVirt,
+ acb->MergeBufferPoolPhys
+ );
+ }
+ }
+ //
+ // Free our own transmit buffers.
+ //
+
+ if (acb->OurBuffersVirtPtr)
+ {
+ //
+ // Free OurBuffers
+ //
+
+ NdisFreeMemory(
+ acb->OurBuffersVirtPtr,
+ sizeof(BUFFER_DESCRIPTOR) * acb->acb_maxinternalbufs,
+ 0
+ );
+ }
+
+ //
+ // Free Small Merge buffer pool.
+ //
+ if (acb->SmallBufferPoolVirt)
+ {
+ OurBuf = acb->SmallBuffersVirtPtr;
+
+ //
+ // Free flush buffers
+ //
+ for (i = 0; i < acb->acb_numsmallbufs; ++i, ++OurBuf)
+ {
+ if (OurBuf->FlushBuffer)
+ {
+ NdisFreeBuffer(OurBuf->FlushBuffer);
+
+ if ( !acb->SmallBuffersAreContiguous ) {
+
+ NdisMFreeSharedMemory(
+ acb->acb_handle,
+ acb->acb_smallbufsz,
+ TRUE,
+ OurBuf->VirtualBuffer,
+ OurBuf->PhysicalBuffer);
+ }
+ }
+ }
+
+ //
+ // Free the pool itself.
+ //
+ if ( acb->SmallBuffersAreContiguous )
+ {
+ NdisMFreeSharedMemory(
+ acb->acb_handle,
+ acb->acb_smallbufsz * acb->acb_numsmallbufs,
+ TRUE,
+ acb->SmallBufferPoolVirt,
+ acb->SmallBufferPoolPhys);
+ }
+ }
+
+ //
+ // Free our Small transmit buffers.
+ //
+ if (acb->SmallBuffersVirtPtr)
+ {
+ //
+ // Free Small Buffers
+ //
+
+ NdisFreeMemory(
+ acb->SmallBuffersVirtPtr,
+ sizeof(BUFFER_DESCRIPTOR) * acb->acb_numsmallbufs,
+ 0
+ );
+ }
+ //
+ // If we have allocated memory for the transmit lists, free it.
+ //
+ if (acb->acb_xmit_virtptr)
+ {
+ NdisMFreeSharedMemory( acb->acb_handle,
+ (ULONG)(SIZE_XMIT * acb->acb_maxtrans),
+ FALSE,
+ (PVOID)(acb->acb_xmit_virtptr),
+ acb->acb_xmit_physptr );
+ }
+
+ //
+ // If we have allocated memory for the receive lists, free it.
+ //
+
+ if ( acb->acb_rcv_virtptr ) {
+
+ //
+ // If we allocated the receive buffer pool, free it.
+ //
+ CurrentReceiveEntry = acb->acb_rcv_virtptr;
+
+ for (i = 0; i < parms->utd_maxrcvs; ++i, ++CurrentReceiveEntry) {
+ //
+ // Free flush buffers
+ //
+
+ if ( CurrentReceiveEntry->RCV_FlushBuffer )
+ {
+ NdisFreeBuffer(CurrentReceiveEntry->RCV_FlushBuffer);
+
+ }
+
+ //
+ // Free individual buffer, if allocated.
+ //
+ if ((!acb->RecvBuffersAreContiguous) &&
+ (CurrentReceiveEntry->RCV_Buf))
+ {
+ NdisMFreeSharedMemory(
+ acb->acb_handle,
+ parms->utd_maxframesz,
+ TRUE,
+ CurrentReceiveEntry->RCV_Buf,
+ CurrentReceiveEntry->RCV_BufPhys
+ );
+ }
+ }
+
+ //
+ // Free the pool itself, if it was allocated contiguously.
+ //
+ if ( acb->RecvBuffersAreContiguous && acb->ReceiveBufferPoolVirt)
+ {
+ NdisMFreeSharedMemory(
+ acb->acb_handle,
+ FrameSizeCacheAligned * parms->utd_maxrcvs,
+ TRUE,
+ acb->ReceiveBufferPoolVirt,
+ acb->ReceiveBufferPoolPhys
+ );
+ }
+
+ //
+ // Now Free the RCV Lists
+ //
+
+ NdisMFreeSharedMemory( acb->acb_handle,
+ (ULONG)(SIZE_RCV * parms->utd_maxrcvs),
+ FALSE,
+ (PVOID)acb->acb_rcv_virtptr,
+ acb->acb_rcv_physptr);
+ }
+
+ //
+ // Free the Flush Pool
+ //
+ if (acb->FlushBufferPoolHandle)
+ {
+ // Free the buffer pool
+ //
+ NdisFreeBufferPool(acb->FlushBufferPoolHandle);
+ }
+
+
+ //
+ // If we have allocated memory for the open block, free it.
+ //
+ if (acb->acb_opnblk_virtptr)
+ {
+ NdisMFreeSharedMemory( acb->acb_handle,
+ (ULONG)SIZE_OPEN,
+ FALSE,
+ (PVOID)(acb->acb_opnblk_virtptr),
+ acb->acb_opnblk_physptr);
+ }
+
+ //
+ // If we have allocated memory for the Read Statistics Log, free it.
+ //
+ if (acb->acb_logbuf_virtptr)
+ {
+ NdisMFreeSharedMemory( acb->acb_handle,
+ (ULONG)(sizeof(RSL)),
+ FALSE,
+ (PVOID)(acb->acb_logbuf_virtptr),
+ acb->acb_logbuf_physptr);
+ }
+
+ //
+ // If we have allocated memory for the internal SCB requests,
+ // free it.
+ //
+ if (acb->acb_scbreq_ptr)
+ {
+ NdisFreeMemory( (PVOID)acb->acb_scbreq_ptr,
+ (UINT) (SCBREQSIZE * acb->acb_maxreqs),
+ (UINT) NDIS_MEMORY_CONTIGUOUS);
+ }
+ //
+ // If we have allocated memory for the internal MAC requests,
+ // free it.
+ //
+ if (acb->acb_macreq_ptr)
+ {
+ NdisFreeMemory( (PVOID)acb->acb_macreq_ptr,
+ (UINT) (MACREQSIZE * acb->acb_maxreqs),
+ (UINT) NDIS_MEMORY_CONTIGUOUS);
+ }
+
+ //
+ // Free map registers
+ //
+ NdisMFreeMapRegisters(acb->acb_handle);
+
+ //
+ // Deregister IO mappings
+ //
+
+ if (acb->acb_dualport)
+ {
+ BOOLEAN OtherHeadStillActive = FALSE;
+ PACB tmp_acb = macgbls.mac_adapters;
+ while (tmp_acb)
+ {
+ if ((tmp_acb->acb_baseaddr == acb->acb_baseaddr) &&
+ (tmp_acb->acb_portnumber != acb->acb_portnumber))
+ {
+ OtherHeadStillActive = TRUE;
+ break;
+ }
+ else
+ {
+ tmp_acb = tmp_acb->acb_next;
+ }
+ }
+
+ if (!OtherHeadStillActive)
+ {
+ // Remove ports for both heads
+ //
+
+ // free ports z000 - -z02f
+ //
+ NdisMDeregisterIoPortRange( acb->acb_handle,
+ acb->acb_baseaddr,
+ NUM_DUALHEAD_CFG_PORTS,
+ (PVOID) acb->MasterBasePorts );
+
+ // free ports zc80 - zc87
+ //
+ NdisMDeregisterIoPortRange( acb->acb_handle,
+ acb->acb_baseaddr + CFG_PORT_OFFSET,
+ NUM_CFG_PORTS,
+ (PVOID)acb->ConfigPorts );
+
+ // free ports zc63 - zc67
+ //
+ NdisMDeregisterIoPortRange( acb->acb_handle,
+ acb->acb_baseaddr + EXTCFG_PORT_OFFSET,
+ NUM_EXTCFG_PORTS,
+ (PVOID)acb->ExtConfigPorts );
+ }
+ }
+ else
+ {
+ // free ports z000 - z01f
+ //
+ NdisMDeregisterIoPortRange( acb->acb_handle,
+ acb->acb_baseaddr,
+ NUM_BASE_PORTS,
+ (PVOID) acb->BasePorts );
+
+ // free ports zc80 - zc87
+ //
+ NdisMDeregisterIoPortRange( acb->acb_handle,
+ acb->acb_baseaddr + CFG_PORT_OFFSET,
+ NUM_CFG_PORTS,
+ (PVOID)acb->ConfigPorts );
+
+ // free ports zc63 - zc67
+ //
+ NdisMDeregisterIoPortRange( acb->acb_handle,
+ acb->acb_baseaddr + EXTCFG_PORT_OFFSET,
+ NUM_EXTCFG_PORTS,
+ (PVOID)acb->ExtConfigPorts );
+ }
+
+ //
+ // Free the Memory for the adapter's acb.
+ //
+ if (acb->acb_parms != NULL)
+ {
+ NdisFreeMemory( (PVOID) acb->acb_parms, (UINT) sizeof(PNETFLEX_PARMS), (UINT) 0);
+ }
+ if (acb != NULL)
+ {
+ NdisFreeMemory( (PVOID)acb, (UINT) (sizeof (ACB)),(UINT) 0);
+ }
+ //
+ // Indicate New Number of Adapters
+ //
+ macgbls.mac_numadpts--;
+}
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexSendNextSCB
+//
+// Description:
+// This routine either sends a TMS_TRANSMIT SCB
+// command to the adapter or sends a command on
+// the SCBReq active queue.
+//
+// Input:
+// acb - Our Driver Context for this adapter or head.
+//
+// Output:
+// None
+//
+// Called By:
+// NetFlexSCBClear,
+// NetFlexQueueSCB,
+// NetFlexTransmitStatus
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+VOID
+NetFlexSendNextSCB(
+ PACB acb
+ )
+{
+ USHORT sifint_reg;
+ PSCBREQ req;
+ PMACREQ macreq;
+ PMULTI_BLOCK tempmulti;
+
+ //
+ // If there is a Transmit command waiting, issue it. Otherwise,
+ // issue the first SCBReq on the SCBReq active queue.
+ //
+ if (acb->acb_xmit_whead)
+ {
+ // Load up the real SCB with a Transmit command
+ //
+ DebugPrint(2,("!S!"));
+ acb->acb_scb_virtptr->SCB_Cmd = TMS_TRANSMIT;
+ acb->acb_scb_virtptr->SCB_Ptr = acb->acb_xmit_whead->XMIT_MyMoto;
+
+ //
+ // If the transmit lists on the waiting queue are ready to
+ // transmit, put them on the active queue.
+ //
+ if ((acb->acb_xmit_whead->XMIT_CSTAT & XCSTAT_GO) != 0)
+ {
+ acb->acb_xmit_ahead = acb->acb_xmit_whead;
+ acb->acb_xmit_atail = acb->acb_xmit_wtail;
+ }
+
+ acb->acb_xmit_whead = 0;
+ acb->acb_xmit_wtail = 0;
+ }
+ //
+ // If there is a Receive command waiting, issue it.
+ //
+ else if (acb->acb_rcv_whead)
+ {
+
+ // Load up the real SCB with a receive command
+ //
+ acb->acb_scb_virtptr->SCB_Cmd = TMS_RECEIVE;
+ acb->acb_scb_virtptr->SCB_Ptr = acb->acb_rcv_whead->RCV_MyMoto;
+
+ acb->acb_rcv_head = acb->acb_rcv_whead;
+ acb->acb_rcv_whead = 0;
+ }
+ //
+ // Otherwise, if there is a SCB request waiting, issue it.
+ //
+ else if (acb->acb_scbreq_next)
+ {
+ // First, let's skip over any dummy SCB commands
+ //
+ req = acb->acb_scbreq_next;
+
+ //
+ // Fill in the real SCB with the first SCBReq on the SCBReq active
+ // queue.
+ //
+ acb->acb_scbreq_next = acb->acb_scbreq_next->req_next;
+ acb->acb_scb_virtptr->SCB_Cmd = req->req_scb.SCB_Cmd;
+
+ //
+ // If this is a Multicast request, we have to fill in a Multicast
+ // buffer.
+ //
+ if (req->req_scb.SCB_Cmd == TMS_MULTICAST)
+ {
+ acb->acb_scb_virtptr->SCB_Ptr = SWAPL(CTRL_ADDR((ULONG)(NdisGetPhysicalAddressLow(acb->acb_multiblk_physptr) +
+ (acb->acb_multi_index * sizeof(MULTI_BLOCK)))) );
+
+ tempmulti = (PMULTI_BLOCK)((ULONG)(acb->acb_multiblk_virtptr) +
+ (acb->acb_multi_index * sizeof(MULTI_BLOCK)));
+
+ acb->acb_multi_index = acb->acb_multi_index ^ (SHORT)1;
+
+ tempmulti->MB_Option = req->req_multi.MB_Option;
+ tempmulti->MB_Addr_Hi = req->req_multi.MB_Addr_Hi;
+ tempmulti->MB_Addr_Med = req->req_multi.MB_Addr_Med;
+ tempmulti->MB_Addr_Lo = req->req_multi.MB_Addr_Lo;
+ }
+ else
+ {
+ acb->acb_scb_virtptr->SCB_Ptr = req->req_scb.SCB_Ptr;
+ }
+ }
+ else
+ {
+ // Nothing to do
+ //
+ return;
+ }
+
+ sifint_reg = SIFINT_CMD;
+
+ //
+ // If there are other requests to send and we are not waiting for
+ // an SCB clear interrupt, tell the adapter we want an SCB clear int.
+ //
+ if ((!acb->acb_scbclearout) &&
+ ((acb->acb_scbreq_next) || (acb->acb_rcv_whead))
+ )
+ {
+ sifint_reg |= SIFINT_SCBREQST;
+ acb->acb_scbclearout = TRUE;
+ }
+
+ //
+ // Send the SCB to the adapter.
+ //
+ NdisRawWritePortUshort(acb->SifIntPort, (USHORT) sifint_reg);
+}
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexQueueSCB
+//
+// Description:
+// This routine places the given SCBReq onto the
+// active SCBreq queue.
+//
+// Input:
+// acb - Our Driver Context for this adapter or head.
+// scbreq - Ptr to the SCBReq to execute
+//
+// Output:
+// None
+//
+// Called By:
+// NetFlexQueryInformation
+// NetFlexSetInformation,
+// NetFlexDeleteMulticast,
+// NetFlexAddMulticast
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+VOID NetFlexQueueSCB(
+ PACB acb,
+ PSCBREQ scbreq
+)
+{
+ //
+ // Place the scbreq on the SCBReq active queue.
+ //
+ NetFlexEnqueue_TwoPtrQ_Tail(
+ (PVOID *)&(acb->acb_scbreq_head),
+ (PVOID *)&(acb->acb_scbreq_tail),
+ (PVOID)scbreq
+ );
+
+ //
+ // If there are no requests waiting for the SCB to clear,
+ // point the request waiting queue to this SCBReq.
+ //
+ if (!acb->acb_scbreq_next)
+ acb->acb_scbreq_next = scbreq;
+
+ //
+ // If the SCB is clear, send a SCB command off now.
+ // Otherwise, if we are not currently waiting for an SCB clear
+ // interrupt, signal the adapter to send us a SCB clear interrupt
+ // when it is done with the SCB.
+ //
+ if (acb->acb_scb_virtptr->SCB_Cmd == 0)
+ {
+ NetFlexSendNextSCB(acb);
+ }
+ else if (!acb->acb_scbclearout)
+ {
+ acb->acb_scbclearout = TRUE;
+ NdisRawWritePortUshort(acb->SifIntPort, (USHORT)SIFINT_SCBREQST);
+ }
+}
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexGetBIA
+//
+// Description:
+// This routine gets the Burned In Address of the adapter.
+//
+// Input:
+// acb - Acb pointer
+//
+// Output:
+// NDIS_STATUS_SUCCESS if successful
+//
+// Called By:
+// NetFlexBoardInitandReg
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+VOID
+NetFlexGetBIA(
+ PACB acb
+ )
+{
+ USHORT value;
+ SHORT i;
+
+ NdisRawWritePortUshort( acb->SifAddrPort, (USHORT) 0x0a00);
+ NdisRawReadPortUshort( acb->SifDataPort, (PUSHORT) &value);
+ NdisRawWritePortUshort( acb->SifAddrPort, (USHORT) value);
+
+ for (i = 0; i < 3; i++)
+ {
+ NdisRawReadPortUshort( acb->SifDIncPort, (PUSHORT) &value);
+ //
+ // Copy the value into the permanent and current station addresses
+ //
+ acb->acb_gen_objs.perm_staddr[i*2] = (UCHAR)(SWAPS(value));
+ acb->acb_gen_objs.perm_staddr[(i*2)+1] = (UCHAR)(value);
+ }
+
+ //
+ // Figure out whether the current station address will be the bia or
+ // an address set up in the configuration file.
+ //
+ if ( (acb->acb_opnblk_virtptr->OPEN_NodeAddr[0] == 0) &&
+ (acb->acb_opnblk_virtptr->OPEN_NodeAddr[1] == 0) &&
+ (acb->acb_opnblk_virtptr->OPEN_NodeAddr[2] == 0) &&
+ (acb->acb_opnblk_virtptr->OPEN_NodeAddr[3] == 0) &&
+ (acb->acb_opnblk_virtptr->OPEN_NodeAddr[4] == 0) &&
+ (acb->acb_opnblk_virtptr->OPEN_NodeAddr[5] == 0) )
+ {
+ NdisMoveMemory(acb->acb_gen_objs.current_staddr,
+ acb->acb_gen_objs.perm_staddr,
+ NET_ADDR_SIZE);
+ }
+ else
+ {
+ NdisMoveMemory(acb->acb_gen_objs.current_staddr,
+ acb->acb_opnblk_virtptr->OPEN_NodeAddr,
+ NET_ADDR_SIZE);
+ }
+}
+
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexGetUpstreamAddrPtr
+//
+// Description: This routine saves the address of where to
+// get the upstream address after opening.
+//
+// Input:
+// acb - Our Driver Context for this adapter or head.
+//
+// Output:
+// NDIS_STATUS_SUCCESS if successful
+//
+// Called By:
+// NetFlexAdapterReset
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+VOID
+NetFlexGetUpstreamAddrPtr(
+ PACB acb
+ )
+{
+ USHORT value;
+
+ NdisRawWritePortUshort( acb->SifAddrPort, (USHORT) 0x0a06); // RVC: what is this value for?
+
+ NdisRawReadPortUshort( acb->SifDataPort, (PUSHORT) &value);
+
+ //
+ // Save the address of where to get the UNA for later requests
+ //
+ acb->acb_upstreamaddrptr = value;
+}
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexAsciiToHex
+//
+// Description:
+// This routine takes an ascii string an converts
+// it into hex digits storing them in an array provided.
+//
+// Input:
+// src - source string.
+// dst - destiniation string
+// dst_length - length of dst
+//
+// Output:
+// NDIS_STATUS_SUCCESS if the string was converted successfully.
+//
+// Called By:
+// NetFlexReadConfigurationParameters
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+NDIS_STATUS NetFlexAsciiToHex(
+ PNDIS_STRING src,
+ PUCHAR dst,
+ USHORT dst_length
+ )
+{
+ ULONG i;
+ UCHAR num;
+
+ //
+ // If the string is too short, return an error.
+ //
+ if (src->Length < (USHORT)(dst_length*2))
+ return(NDIS_STATUS_FAILURE);
+
+ //
+ // Begin to convert.
+ //
+ for (i = 0; i < dst_length; i++)
+ {
+ //
+ // Get first digit of the byte
+ //
+ num = (UCHAR)(src->Buffer[i*2]);
+ if ( (num >= '0') && (num <= '9') )
+ *dst = (UCHAR)(num - '0') * 0x10;
+ else if ( (num >= 'a') && (num <= 'f') )
+ *dst = (UCHAR)(num - 'a' + 10) * 0x10;
+ else if ( (num >= 'A') && (num <= 'F') )
+ *dst = (UCHAR)(num - 'A' + 10) * 0x10;
+ else
+ return(NDIS_STATUS_FAILURE);
+
+ //
+ // Get second digit of the byte
+ //
+ num = (UCHAR)(src->Buffer[(i*2)+1]);
+ if ( (num >= '0') && (num <= '9') )
+ *dst += (UCHAR)(num - '0');
+ else if ( (num >= 'a') && (num <= 'f') )
+ *dst += (UCHAR)(num - 'a' + 10);
+ else if ( (num >= 'A') && (num <= 'F') )
+ *dst += (UCHAR)(num - 'A' + 10);
+ else
+ return(NDIS_STATUS_FAILURE);
+
+ dst++;
+ }
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexFindEntry
+//
+// Description:
+// This routine finds the given entry in a queue given to it.
+//
+// Input:
+// head - Ptr to the head of the queue.
+// entry - Ptr to the entry to find.
+//
+// Output:
+// back - Ptr to the address of the entry in front of the
+// entry given.
+// Returns TRUE if found and FALSE if not.
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+BOOLEAN
+NetFlexFindEntry(
+ PVOID head,
+ PVOID *back,
+ PVOID entry
+ )
+{
+ PVOID current;
+
+ current = *back = head;
+ while (current)
+ {
+ if (current == entry)
+ return(TRUE);
+ *back = current;
+ current = (PVOID)( ( (PNETFLEX_ENTRY)(current) )->next );
+ }
+
+ return FALSE;
+}
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexDequeue_OnePtrQ
+//
+// Description: This routine finds the given entry and removes
+// it from the queueu given.
+//
+// Input: head - Ptr to the head of the queue.
+// entry - Ptr to the entry to remove.
+//
+// Output: None.
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+VOID
+NetFlexDequeue_OnePtrQ(
+ PVOID *head,
+ PVOID entry
+ )
+{
+ PNETFLEX_ENTRY back;
+
+ if (NetFlexFindEntry(*head, (PVOID *) &back, entry))
+ {
+ if (entry == *head)
+ *head = (PVOID)( ( (PNETFLEX_ENTRY)(entry) )->next );
+ else
+ back->next = ( (PNETFLEX_ENTRY)(entry) )->next;
+ }
+}
+
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexEnqueue_OnePtrQ_Head
+//
+// Description:
+// This routine places the entry given on the front of the
+// queue given.
+//
+// Input:
+// head - Ptr to the ptr of the head of the queue.
+// entry - Pointer to the entry to add
+//
+// Output: None
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+VOID
+NetFlexEnqueue_OnePtrQ_Head(
+ PVOID *head,
+ PVOID entry
+ )
+{
+ ((PNETFLEX_ENTRY)(entry))->next = *head;
+ *head = entry;
+}
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexDequeue_OnePtrQ_Head
+//
+// Description:
+// This routine dequeues a the first entry of the given queue
+//
+// Input:
+// head - Ptr to the ptr of the head of the queue.
+//
+// Output:
+// entry - Ptr to the ptr of the dequeued entry.
+//
+// Returns NDIS_STATUS_SUCCESS if an entry is freed.
+// Otherwise, NDIS_STATUS_RESOURCES.
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+NDIS_STATUS
+NetFlexDequeue_OnePtrQ_Head(
+ PVOID *head,
+ PVOID *entry
+ )
+{
+ //
+ // Is there a free entry? If not, return an error.
+ //
+ if (!(*head))
+ {
+ *entry = NULL;
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ //
+ // Dequeue the free entry from the queue.
+ //
+ *entry = *head;
+ *head = ( (PNETFLEX_ENTRY)(*head))->next;
+ ((PNETFLEX_ENTRY)(*entry))->next = NULL;
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexEnqueue_TwoPtrQ_Tail
+//
+// Description:
+// This routine places an entry on the tail of
+// a queue with a head and tail pointer.
+//
+// Input:
+// head - Ptr to address of the head of the queue.
+// tail - Ptr to the address of the tail of the queue.
+// entry - Ptr to the entry to enqueue
+//
+// Output:
+// Status.
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+NDIS_STATUS
+NetFlexEnqueue_TwoPtrQ_Tail(
+ PVOID *head,
+ PVOID *tail,
+ PVOID entry)
+{
+ //
+ // Place the entry on tail of the queue.
+ //
+ ((PNETFLEX_ENTRY)(entry))->next = NULL;
+ if (*tail)
+ ((PNETFLEX_ENTRY)(*tail))->next = entry;
+ else
+ *head = entry;
+ *tail = entry;
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexDequeue_TwoPtrQ
+//
+// Description:
+// This routine finds the given entry and removes it from
+// the queue. Queue has a head and tail pointer.
+//
+// Input:
+// head - Ptr to address of the head of the queue.
+// tail - Ptr to the address of the tail of the queue.
+// entry - Ptr to the entry to enqueue
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+VOID
+NetFlexDequeue_TwoPtrQ(
+ PVOID *head,
+ PVOID *tail,
+ PVOID entry
+ )
+{
+ PVOID back;
+
+ if (NetFlexFindEntry(*head, &back, entry))
+ {
+ if (entry == *head)
+ {
+ if ( (*head = ((PNETFLEX_ENTRY)entry)->next) == NULL)
+ *tail = NULL;
+ }
+ else
+ {
+ ((PNETFLEX_ENTRY)back)->next = ((PNETFLEX_ENTRY)entry)->next;
+ if (*tail == entry)
+ *tail = back;
+ }
+ }
+}
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexDequeue_TwoPtrQ_Head
+//
+// Description:
+// This routine dequeues a the first entry of the given queue
+//
+// Input:
+// head - Ptr to the ptr of the head of the queue.
+// tail - Ptr to the address of the tail of the queue.
+//
+// Output:
+// entry - Ptr to the ptr of the dequeued entry.
+//
+// Status - NDIS_STATUS_SUCCESS if an entry is freed.
+// Otherwise, NDIS_STATUS_RESOURCES.
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+NDIS_STATUS
+NetFlexDequeue_TwoPtrQ_Head(
+ PVOID *head,
+ PVOID *tail,
+ PVOID *entry
+ )
+{
+ //
+ // Is there a free entry? If not, return an error.
+ //
+ if (!(*head))
+ {
+ *entry = NULL;
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ //
+ // Dequeue the free entry from the queue.
+ //
+ *entry = *head;
+ *head = ((PNETFLEX_ENTRY)(*head))->next;
+ if (*head == NULL)
+ *tail = NULL;
+ ((PNETFLEX_ENTRY)(*entry))->next = NULL;
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+#if (DBG || DBGPRINT)
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: _DebugPrint
+//
+// Description:
+// Level sensitive debug print. It is called through
+// a the DebugPrint macro which compares the current
+// DebugLevel to that specified. If the level indicated
+// is less than or equal, the message is displayed.
+//
+// Input:
+// Variable PrintF style Message to display
+//
+// Output:
+// Displays Message on Debug Screen
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+VOID
+_DebugPrint(PCHAR DebugMessage,
+ ...
+ )
+{
+ char buffer[256];
+ va_list ap;
+
+ va_start(ap, DebugMessage);
+ vsprintf(buffer, DebugMessage, ap);
+ DbgPrint(buffer);
+ va_end(ap);
+
+} // end _DebugPrint()
+
+#endif /* DBG */
diff --git a/private/ntos/ndis/netflex/tmsstrct.h b/private/ntos/ndis/netflex/tmsstrct.h
new file mode 100644
index 000000000..f091a2124
--- /dev/null
+++ b/private/ntos/ndis/netflex/tmsstrct.h
@@ -0,0 +1,606 @@
+/***********************************************************************/
+/***********************************************************************/
+/* */
+/* File Name: TMSSTRCT.H */
+/* */
+/* Program Name: NetFlex NDIS 3.0 Driver */
+/* */
+/* Companion Files: None */
+/* */
+/* Function: This module contains all the data strcuture defini- */
+/* tions that are specific to the TMS380 software */
+/* interface specification. The data structures */
+/* defined are as follows: */
+/* */
+/* - TMS380 Adapter Command Definitions */
+/* - TMS380 SIF Register Offset Definitions */
+/* - Adapter Interrupt Register Bit Definition */
+/* - Adapter Configuration Register Bit Definition */
+/* - TMS380 Adapter Command Definitions */
+/* - System Command Block (SCB) */
+/* - System Status Block (SSB) */
+/* - Adapter Initialization Parameter Block */
+/* - Adapter Open Parameter Block */
+/* - Adapter Transmit Parameter List */
+/* - Transmit CSTAT Bit Definitions */
+/* - Transmit Status Bit Definitions */
+/* - Adapter Receive Parameter List */
+/* - Receive CSTAT Bit Definitions */
+/* - Receive Status Bit Definitions */
+/* - Read Error Log Buffer Definition */
+/* */
+/* (c) Compaq Computer Corporation, 1992,1993,1994 */
+/* */
+/* This file is licensed by Compaq Computer Corporation to Microsoft */
+/* Corporation pursuant to the letter of August 20, 1992 from */
+/* Gary Stimac to Mark Baber. */
+/* */
+/* History: */
+/* */
+/* 05/24/94 Robert Van Cleve - Reworked from NDIS 3.0 Driver */
+/* */
+/***********************************************************************/
+/***********************************************************************/
+
+#define NET_ADDR_SIZE 6
+#define NET_GROUP_SIZE 4
+#define HDR_SIZE 14
+
+
+
+/*
+ * Structure Name: TMS380 Adapter Command Definitions
+ *
+ * Description: The TMS380 Adapter Commands Definitions define the
+ * reversed byte ordering of the TMS380 adapter command
+ * word values.
+ */
+#define TMS_RESET 0x0000 /* Reset Adapter (doesn't exist) */
+#define TMS_CMDREJECT 0x0200 /* Command Reject */
+#define TMS_OPEN 0x0300 /* Open Adapter */
+#define TMS_TRANSMIT 0x0400 /* Transmit Frame */
+#define TMS_XMITHALT 0x0500 /* Transmit Halt */
+#define TMS_RECEIVE 0x0600 /* Receive */
+#define TMS_CLOSE 0x0700 /* Close Adapter */
+#define TMS_SETGROUP 0x0800 /* Set Group Address */
+#define TMS_SETFUNCT 0x0900 /* Set Functional Address */
+#define TMS_READLOG 0x0a00 /* Read Error Log */
+#define TMS_READADP 0x0b00 /* Read Adapter Buffer */
+#define TMS_MODIFYOPEN 0x0d00 /* Modify Open Parameters */
+#define TMS_MULTICAST 0x1200 /* Set/Clr Multicast Address */
+#define TMS_DUMMYCMD 0x1111 /* Dummy SCB */
+
+
+/*
+ * Structure Name: TMS380 SIF Register Offset Definitions
+ *
+ * Description: The TMS380 Register Offset Definitions describe the
+ * offsets to and number of TMS380 SIF registers.
+ */
+#define NUMREGS 4
+
+#define SIF_DATA_OFF 0x0 /* SIF data register */
+#define SIF_DINC_OFF 0x2 /* SIF data autoincrment reg */
+#define SIF_ADDR_OFF 0x4 /* SIF address register */
+#define SIF_INT_OFF 0x6 /* SIF interrupt register */
+#define SIF_ACTL_OFF 0x8 /* SIF ACTL register */
+#define SIF_ACTL_EXT_OFF 0xc /* SIF Address Extended reg */
+
+
+#define PORT0 0 /* Regular single port adapter */
+#define PORT1 1 /* Port 1 of dual port adapter */
+#define PORT2 2 /* Port 2 of dual port adapter */
+
+/*
+ * Structure Name: Adapter Control Register Bit Definitions
+ *
+ * Description: The Adapter Control Register Bit Definitions define
+ * functions of the individual bits in the Adapter Con-
+ * trol register of the EAGLE chip. Bit combinations are
+ * also defined here.
+ */
+#define ACTL_TEST0 0x8000 /* Test0, set - 4mbps, clr - 16 */
+#define ACTL_TEST1 0x4000 /* Test1, set - TR, clr - Eth */
+#define ACTL_SWHLDA 0x0800 /* Software Hold Acknowledge */
+#define ACTL_SWDDIR 0x0400 /* Current SDDIR signal level */
+#define ACTL_SWHRQ 0x0200 /* Software Hold Request */
+#define ACTL_PSDMALEN 0x0100 /* Psuedo System DMA Length */
+#define ACTL_ARESET 0x0080 /* Adapter Reset */
+#define ACTL_CPHALT 0x0040 /* Comm Processor Halt */
+#define ACTL_BOOT 0x0020 /* Bootstrapped CP Code */
+#define ACTL_ROM 0x0010 /* Reserved */
+#define ACTL_SINTEN 0x0008 /* System Interrupt Enable */
+#define ACTL_PEN 0x0004 /* Adapter Parity Enable */
+#define ACTL_NSELOUT0 0x0002 /* Net Select, set - 4, clr -16 */
+#define ACTL_NSELOUT1 0x0001 /* Net Select,set - tr, clr -eth*/
+
+#define ACTL_TESTPINS ACTL_TEST1 + ACTL_TEST0
+
+#define ACTL_HARD_RESET 0xEE /* Force Hard Reset */
+#define SIF_SOFT_RESET 0xff00 /* Soft Reset */
+/*
+ * Structure Name: Adapter Interrupt Register Bit Definitions
+ *
+ * Description: The Adapter Interrupt Register Bit Definitions define
+ * functions of the individual bits in the System Inter-
+ * rupt register of the TMS380 chipset. Bit combinations
+ * are also defined here.
+ */
+#define SIFINT_ADPINT 0x8000 /* Adapter Interrupt */
+#define SIFINT_RESET 0x4000 /* Reset request */
+#define SIFINT_SSBCLR 0x2000 /* SSB Clear */
+#define SIFINT_EXECUTE 0x1000 /* Execute Command */
+#define SIFINT_SCBREQ 0x0800 /* SCB Clear request */
+#define SIFINT_RCVCON 0x0400 /* Receive Continue */
+#define SIFINT_RCVVLD 0x0200 /* Receive Valid */
+#define SIFINT_XMTVLD 0x0100 /* Transmit Valid */
+#define SIFINT_SYSINT 0x0080 /* System Interrupt */
+
+#define SIFINT_CMD (SIFINT_ADPINT | SIFINT_EXECUTE | SIFINT_SYSINT)
+#define SIFINT_SSBCLEAR (SIFINT_ADPINT | SIFINT_SSBCLR)
+#define SIFINT_SCBREQST (SIFINT_ADPINT | SIFINT_SCBREQ | SIFINT_SYSINT)
+#define SIFINT_RCVVALID (SIFINT_ADPINT | SIFINT_RCVVLD | SIFINT_SYSINT)
+#define SIFINT_XMTVALID (SIFINT_ADPINT | SIFINT_XMTVLD | SIFINT_SYSINT)
+#define SIFINT_RCVCONT (SIFINT_ADPINT | SIFINT_RCVCON | SIFINT_SYSINT)
+
+#define INT_ADPCHECK 0x0000 /* Adapter Check Interrupt */
+#define INT_RINGSTAT 0x0004 /* Ring Status Interrupt */
+#define INT_SCBCLEAR 0x0006 /* SCB Clear Interrupt */
+#define INT_COMMAND 0x0008 /* Command Interrupt */
+#define INT_TRANSMIT 0x000c /* Transmit Interrupt */
+#define INT_RECEIVE 0x000a /* Receive Interrupt */
+
+#define INT_CODES 0x000f /* Mask for interrupt codes */
+
+
+/*
+ * Structure Name: Address Register INIT Block Location Definition
+ *
+ * Description: The Address Register INIT Block Loaction Definition defines
+ * the value that must be placed into the SIF address reg
+ * when the TMS380 is being initialized.
+ */
+#define ADDR_INIT 0x0a00 /* Start at address 0x0a00 */
+
+
+/*
+ * Structure Name: System Command Block (SCB) Structure Definition
+ *
+ * Description: The System Command Block Structure Definition defines
+ * the structure of the TMS380 based SCB block.
+ */
+typedef struct SCB_Block
+{
+ USHORT SCB_Dummy; /* Force SCB.Ptr to word boundry */
+ USHORT SCB_Cmd; /* SCB Command field */
+ ULONG SCB_Ptr; /* SCB Pointer field */
+} SCB, *PSCB;
+
+#define SIZE_SCB sizeof(SCB)
+
+
+/*
+ * Structure Name: System Status Block (SSB) Structure Definition
+ *
+ * Description: The System Status Block Structure Definition defines
+ * the structure of the TMS380 based SSB block. Also in-
+ * cluded are the SSB status field bit definitions.
+ */
+typedef struct SSB_Block
+{
+ USHORT SSB_Cmd; /* SSB Command field */
+ USHORT SSB_Status; /* SSB Status field */
+ ULONG SSB_Ptr; /* SSB Pointer field */
+} SSB, *PSSB;
+
+#define SIZE_SSB sizeof(SSB)
+
+#define SSB_GOOD 0x0080 /* SSB Command successful status */
+#define SSB_OPENERR 0x0002 /* Open Error Completion */
+
+
+/*
+ * Structure Name: Adapter Initialization Parameter Block Definition
+ *
+ * Description: The Adapter Initialization Parameter Block Definition
+ * defines the structure of the TMS380 based initiali-
+ * zation block.
+ */
+
+typedef struct INIT_Block
+{
+ USHORT INIT_Options; /* Initialization Options */
+ UCHAR INIT_Vectors[6]; /* Interrupt vector codes */
+ USHORT INIT_Rburst; /* Receive DMA burst size */
+ USHORT INIT_Xburst; /* Transmit DMA burst size */
+ USHORT INIT_DMARetry; /* DMA retry counts */
+} INIT, *PINIT;
+
+#define SIZE_INIT sizeof(INIT)
+
+
+//
+// Structure Name: Open Adapter Parameter Block Structure Definition
+//
+// Description: The Open Adapter Parameter Block Structure Definition
+// defines the structure of the TMS380 based parameter
+// block passed to the adapter on an Open Adapter request.
+// All parameter defaults listed here are already byte
+// swapped for DMA into the adapter. Open options are
+// also defined here.
+//
+
+typedef struct OPEN_Block
+{
+ USHORT OPEN_Options; /* Open options */
+ UCHAR OPEN_NodeAddr[NET_ADDR_SIZE]; /* Adapter node addr */
+ UCHAR OPEN_GroupAddr[NET_GROUP_SIZE]; /* Adapter grp addr */
+ UCHAR OPEN_FunctAddr[NET_GROUP_SIZE]; /* Adapter fnc addr */
+ USHORT OPEN_RLSize; /* Receive list size */
+ USHORT OPEN_XLSize; /* Transmit list size */
+ USHORT OPEN_BufSize; /* Adapter buffer size (1K) */
+ USHORT OPEN_RAMStart; /* Adapter RAM start addr */
+ USHORT OPEN_RAMEnd; /* Adapter RAM end address */
+ UCHAR OPEN_Xbufmin; /* Adapter xmit min buf cnt */
+ UCHAR OPEN_Xbufmax; /* Adapter xmit max buf cnt */
+ UCHAR *OPEN_ProdIdPtr; /* Product ID pointer */
+ UCHAR OPEN_ProdID[18]; /* Product ID */
+} OPEN, *POPEN;
+
+#define SIZE_OPEN sizeof(OPEN)
+
+
+#define OOPTS_WRAP 0x8000 /* Open Wrap Mode BOTH */
+#define OOPTS_DHARD 0x4000 /* Disable Hard Errors TR */
+#define OOPTS_DSOFT 0x2000 /* Disable Soft Errors TR */
+#define OOPTS_PADPM 0x1000 /* Pass Adapter MAC Frames TR */
+#define OOPTS_PATTM 0x0800 /* Pass Attention MAC Frames TR */
+#define OOPTS_PADR 0x0400 /* Pad Routing Field TR */
+#define OOPTS_FHOLD 0x0200 /* Frame Hold BOTH */
+#define OOPTS_CONT 0x0100 /* Contender TR */
+#define OOPTS_SHFR 0x0100 /* Pad Short Frames ETH */
+#define OOPTS_PBCNM 0x0080 /* Pass Beacon MAC Frames TR */
+#define OOPTS_REQ 0x0040 /* Required bit. ETH */
+#define OOPTS_FULLDUP 0x0020 /* Full duplex enable ETH */
+#define OOPTS_ETR 0x0010 /* Early Token Release TR */
+#define OOPTS_CMAC 0x0004 /* Copy All MAC Frames TR */
+#define OOPTS_CNMAC 0x0002 /* Copy All Non-MAC Frames BOTH */
+#define OOPTS_FONLY 0x0001 /* Pass First Buffer Only */
+
+#define OOPTS_TR_CFG 0xff87 /* Token ring configurable bits */
+#define OOPTS_ETH_CFG 0x8263 /* Ethernet configurable bits */
+
+//
+// Structure Name: Transmit List Data Pointer Structure Definition
+//
+// Description: The Transmit List Data Pointer Structure Definition
+// defines the structure of the data pointers contained
+// in the TMS380 based Transmit Parameter List.
+//
+
+typedef struct _XMIT_DATA
+{
+ USHORT DataCount;
+ USHORT DataHi;
+ USHORT DataLo;
+} XMIT_DATA, *PXMIT_DATA;
+
+
+#define DATA_NOT_LAST 0x0080 /* "Not last" mask for len field*/
+#define DATA_LAST 0xff7f /* "Last" mask for len field */
+
+
+//
+// Structure Name: Transmit List Structure Definition
+//
+// Description: The Transmit List Structure Definition defines the
+// structure of the TMS380 based Transmit Parameter List.
+// Also included are the definitions of the TRNDD parti-
+// cular fields that have been added to the end of the
+// list structure to allow easy management of the trans-
+// mit process.
+//
+
+
+#define MAX_LISTS_PER_XMIT 1
+#define NUM_BUFS_PER_LIST 6 // MAC Can Handle max of 9 fragments
+#define MAX_BUFS_PER_XMIT (MAX_LISTS_PER_XMIT * NUM_BUFS_PER_LIST)
+#define SIZE_XMIT_DATA (NUM_BUFS_PER_LIST * 6) // 3 words per
+#define SIZE_XMIT_LIST (SIZE_XMIT_DATA + 8) // data + fwrdptr + size + count
+
+//
+// Definition of the buffer structures we need for recieve lists,
+// and our own transmit buffers.
+//
+typedef struct _BUFFER_DESCRIPTOR {
+
+ NDIS_PHYSICAL_ADDRESS PhysicalBuffer;
+ PVOID VirtualBuffer;
+ PNDIS_BUFFER FlushBuffer;
+ struct _BUFFER_DESCRIPTOR *Next; // NULL implies no more entries in the list.
+ UINT BufferSize; // bytes available in the buffer
+ UINT DataLength; // actual bytes placed into buffer.
+
+} BUFFER_DESCRIPTOR, *PBUFFER_DESCRIPTOR;
+
+
+typedef struct XMIT_List
+{
+ // Hardware List Fields
+ //
+ ULONG XMIT_FwdPtr; // Motorola pointer to next list
+ USHORT XMIT_CSTAT; // Command/Status field
+ SHORT XMIT_Fsize; // Frame size
+ XMIT_DATA XMIT_Data[MAX_BUFS_PER_XMIT]; // Data
+ struct XMIT_List *XMIT_Next; // Intel pointer to next list
+ //
+ // Our extra List Fields...
+ //
+ ULONG XMIT_MyMoto; // My motorola address
+
+#ifndef COPALL
+ ULONG XMIT_MapReg; // Index to mapping register
+ PNDIS_PACKET XMIT_Packet; //
+#endif
+
+ NDIS_PHYSICAL_ADDRESS XMIT_Phys; // Physical Pointer to this XMIT
+ ULONG XMIT_Timeout; // > 0 if checking for timeout
+
+#ifdef XMIT_INTS
+ ULONG XMIT_Number; // index of this list
+#endif
+
+ PBUFFER_DESCRIPTOR XMIT_OurBufferPtr; // which buffer we used...
+
+} XMIT, *PXMIT;
+
+#define SIZE_XMIT sizeof(XMIT) /* Size of transmit list */
+
+// Structure Name: Transmit List CSTAT Bit Definitions
+//
+// Description: The Transmit List CSTAT Bit Definitions defines the
+// meaning of the bits in the CSTAT field of the transmit
+// list.
+//
+#define XCSTAT_VALID 0x0080 /* Transmit Valid */
+#define XCSTAT_COMPLETE 0x0040 /* Transmit Frame Complete */
+#define XCSTAT_SOF 0x0020 /* Transmit Start of Frame */
+#define XCSTAT_EOF 0x0010 /* Transmit End of Frame */
+#define XCSTAT_FINT 0x0008 /* Transmit Frame Interrupt */
+#define XCSTAT_ERROR 0x0004 /* Transmit Error */
+#define XCSTAT_GOODFS 0x8800 /* Good Transmit FS btye */
+
+#define XCSTAT_LSOF 0x00a8 /* Transmit Start of Frame */
+#define XCSTAT_GO_INT 0x00b8 /* Transmit VALID/SOF/EOF/FINT */
+#define XCSTAT_GO 0x00b0 /* Transmit VALID/SOF/EOF */
+
+
+//
+// Structure Name: Transmit SSB Status Codes Definitions
+//
+// Description: The Transmit SSB Status Codes Definitions defines the
+// meaning of the bits in the Status field of the trans-
+// mit completion SSB.
+//
+#define XSTAT_CMDCMPLT 0x0080 /* Command Complete */
+#define XSTAT_FRMCMPLT 0x0040 /* Frame Complete */
+#define XSTAT_LERROR 0x0020 /* List Error */
+
+#define XSTAT_FRAME_SIZE_ERROR 0x8000
+#define XSTAT_XMIT_THRESHOLD 0x4000
+#define XSTAT_ODD_ADDRESS 0x2000
+#define XSTAT_FRAME_ERROR 0x1000
+#define XSTAT_ACCESS_PRIORITY_ERR 0x0800
+#define XSTAT_UNENABLE_MAC_FRAME 0x0400
+#define XSTAT_ILLEGAL_FRAME_FORMAT 0x0200
+
+
+//
+// Structure Name: Receive List Structure Definition
+//
+// Description: The Receive List Structure Definition defines the
+// structure of the TMS380 based Receive Parameter List.
+// Also included are the definitions of the TRNDD parti-
+// cular fields that have been added to the end of the
+// list structure to allow easy management of the receive
+// process.
+//
+typedef struct RCV_List
+{
+ // Physical Hardware List Fields
+ //
+ ULONG RCV_FwdPtr; /* Motorola pointer to next list*/
+ USHORT RCV_CSTAT; /* Command/Status field */
+ SHORT RCV_Fsize; /* Frame size */
+ USHORT RCV_Dsize; /* Receive list data size */
+ USHORT RCV_DptrHi; /* Receive list date pointer hi word*/
+ USHORT RCV_DptrLo; /* Receive list data pointer lo word*/
+ //
+ // Our Extra Receive List Fields
+ //
+ struct RCV_List *RCV_Next; // Intel pointer to next list
+#ifdef ODD_POINTER
+ struct RCV_List *RCV_Prev; // Intel pointer to previous list
+#endif
+ ULONG RCV_Number; // index
+
+ ULONG RCV_MyMoto; // Motorola Physical Address
+ ULONG RCV_HeaderLen; // Len of the rcvd packet's hdr
+ NDIS_PHYSICAL_ADDRESS RCV_Phys; // Physical Pointer to this RCV
+ PVOID RCV_Buf; // pointer to our recieve buffer
+ NDIS_PHYSICAL_ADDRESS RCV_BufPhys; // Physical Pointer to our Frame Buffer
+ PNDIS_BUFFER RCV_FlushBuffer; // Points to an NDIS buffer which describes thisbuffer
+} RCV, *PRCV;
+
+#define SIZE_RCV sizeof(RCV) // Size of receive list
+
+//
+// Structure Name: Receive List CSTAT Bit Definitions
+//
+// Description: The Receive List CSTAT Bit Definitions defines the
+// meaning of the bits in the CSTAT field of the receive
+// list.
+//
+#define RCSTAT_VALID 0x0080 /* Receive Valid */
+#define RCSTAT_COMPLETE 0x0040 /* Receive Frame Complete */
+#define RCSTAT_SOF 0x0020 /* Receive Start of Frame */
+#define RCSTAT_EOF 0x0010 /* Receive End of Frame */
+#define RCSTAT_FINT 0x0008 /* Receive Frame Interrupt */
+
+#define RCSTAT_GO_INT 0x0088 /* Receive Valid and frame int */
+#define RCSTAT_GO 0x0080 /* Receive Valid and frame int */
+
+//
+// Receive_Status Field Defines
+//
+#define RSTAT_FRAME_COMPLETE 0x0080 /* Frame Complete */
+#define RSTAT_RX_SUSPENDED 0x0040 /* Receive Suspended */
+//
+// Structure Name: Token-Ring Frame Format
+//
+// Description: The Token-Ring Frame Format structure defines the
+// fields of a valid Token-Ring frame.
+//
+typedef struct TR_Format
+{
+ UCHAR FF_Ac; /* AC Field */
+ UCHAR FF_Fc; /* FC Field */
+ UCHAR FF_Dest[6]; /* Destination Address */
+ UCHAR FF_Src[6]; /* Source Address */
+} TRF, *PTRF;
+
+//
+// Structure Name: Source Routing Format
+//
+// Description: The Source Routing Format structure defines the fields
+// of Source Routing information contained within a frame
+//
+typedef struct routing_control
+{
+ UCHAR rc_L:5, /* Length of RI including rc */
+ rc_B:3; /* Broadcast Bits */
+ UCHAR rc_r:3, /* Reserved */
+ rc_LF:4, /* Largest Frame */
+ rc_D:1; /* Direction bits */
+} ROUTING_CONTROL, *PROUTING_CONTROL;
+
+
+//
+// Structure Name: Ethernet Frame Format
+//
+// Description: The Ethernet Frame Format structure defines the
+// fields of a valid Ethernet frame.
+//
+typedef struct Eth_Format
+{
+ UCHAR FF_Dest[6]; /* Destination Address */
+ UCHAR FF_Src[6]; /* Source Address */
+} ETHF, *PETHF;
+
+
+//
+// MAC Header Size. This is the same header size for both network types.
+//
+#define NETFLEX_MACHEADER_SIZE 14
+
+
+//
+// Structure Name: Read Error Log Buffer Structure Definition
+// (Token Ring Only)
+//
+// Description: The Read Error Log Buffer Structure Definition defines
+// the structure of the TMS380 based Read Error Log.
+//
+typedef struct REL_Block
+{
+ UCHAR REL_LineError;
+ UCHAR REL_Rsvd1;
+ UCHAR REL_BurstError;
+ UCHAR REL_ARIFCIError;
+ UCHAR REL_Rsvd2;
+ UCHAR REL_Rsvd3;
+ UCHAR REL_LostError;
+ UCHAR REL_Congestion;
+ UCHAR REL_CopiedError;
+ UCHAR REL_Rsvd4;
+ UCHAR REL_TokenError;
+ UCHAR REL_Rsvd5;
+ UCHAR REL_DMABUSError;
+ UCHAR REL_DMAPARError;
+} REL, *PREL;
+
+#define SIZE_REL sizeof(REL)
+
+//
+// Structure Name: Read Statistics Log Buffer Structure Definition
+// (Ethernet Only)
+//
+// Description: The Read Statistics Log Buffer Structure Definition defines
+// the structure of the TMS380 based Read Statistics Log.
+//
+typedef struct RSL_Block
+{
+ USHORT RSL_ReceviedOK;
+ USHORT RSL_Rsvd1;
+ USHORT RSL_FrameCheckSeq;
+ USHORT RSL_AlignmentErr;
+ USHORT RSL_DeferredXmit;
+ USHORT RSL_Excessive;
+ USHORT RSL_LateCollision;
+ USHORT RSL_CarrierErr;
+ USHORT RSL_XmitdOK;
+ USHORT RSL_1_Collision;
+ USHORT RSL_2_Collision;
+ USHORT RSL_3_Collision;
+ USHORT RSL_4_Collision;
+ USHORT RSL_5_Collision;
+ USHORT RSL_6_Collision;
+ USHORT RSL_7_Collision;
+ USHORT RSL_8_Collision;
+ USHORT RSL_9_Collision;
+ USHORT RSL_10_Collision;
+ USHORT RSL_11_Collision;
+ USHORT RSL_12_Collision;
+ USHORT RSL_13_Collision;
+ USHORT RSL_14_Collision;
+ USHORT RSL_15_Collision;
+} RSL, *PRSL;
+
+#define SIZE_RSL sizeof(RSL)
+
+
+
+struct read_adapter_buf
+{
+ SHORT count;
+ SHORT addr;
+ UCHAR data[100];
+};
+
+
+typedef struct multi_block
+{
+ USHORT MB_Option;
+ USHORT MB_Addr_Hi;
+ USHORT MB_Addr_Med;
+ USHORT MB_Addr_Lo;
+} MULTI_BLOCK, *PMULTI_BLOCK;
+
+#define MPB_DELETE_ADDRESS 0x0000
+#define MPB_ADD_ADDRESS 0x0100
+#define MPB_CLEAR_ALL 0x0200
+#define MPB_SET_ALL 0x0300
+
+
+#define RING_STATUS_OVERFLOW 0x8000
+#define RING_STATUS_SINGLESTATION 0x4000
+#define RING_STATUS_RINGRECOVERY 0x2000
+#define RING_STATUS_SIGNAL_LOSS 0x0080
+#define RING_STATUS_HARD_ERROR 0x0040
+#define RING_STATUS_SOFT_ERROR 0x0020
+#define RING_STATUS_XMIT_BEACON 0x0010
+#define RING_STATUS_LOBE_WIRE_FAULT 0x0008
+#define RING_STATUS_AUTO_REMOVE_1 0x0004
+#define RING_STATUS_REMOVE_RECEIVED 0x0001
+
+
diff --git a/private/ntos/ndis/netflex/transmit.c b/private/ntos/ndis/netflex/transmit.c
new file mode 100644
index 000000000..37373c5f8
--- /dev/null
+++ b/private/ntos/ndis/netflex/transmit.c
@@ -0,0 +1,802 @@
+//**********************************************************************
+//**********************************************************************
+//
+// File Name: TRANSMIT.C
+//
+// Program Name: NetFlex NDIS 3.0 Miniport Driver
+//
+// Companion Files: None
+//
+// Function: This module contains the NetFlex Miniport Driver
+// interface routines called by the Wrapper and the
+// configuration manager.
+//
+// (c) Compaq Computer Corporation, 1992,1993,1994
+//
+// This file is licensed by Compaq Computer Corporation to Microsoft
+// Corporation pursuant to the letter of August 20, 1992 from
+// Gary Stimac to Mark Baber.
+//
+// History:
+//
+// 04/15/94 Robert Van Cleve - Converted from NDIS Mac Driver
+//
+//**********************************************************************
+//**********************************************************************
+
+//-------------------------------------
+// Include all general companion files
+//-------------------------------------
+
+#include <ndis.h>
+#include "tmsstrct.h"
+#include "macstrct.h"
+#include "adapter.h"
+#include "protos.h"
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexProcessXmit
+//
+// Description: This routine looks through the tranmit lists
+// and calls the send complete routines of the
+// bindings whose sends have completed.
+//
+// Input: acb - Pointer to the Adapter's acb
+//
+// Output: None
+//
+// Calls: NetFlexDequeue_TwoPtrQ,
+// NetFlexEnqueue_TwoPtrQ_Tail
+//
+// Called_By: NetFlexDPR
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+VOID
+FASTCALL
+NetFlexProcessXmit(
+ PACB acb
+ )
+{
+ PXMIT xmitptr;
+ UINT curmap;
+ PNDIS_PACKET packet;
+ NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+ PNDIS_BUFFER SourceBuffer;
+ ULONG XmitedOk = 0;
+
+ if (acb->FullDuplexEnabled)
+ {
+ NdisAcquireSpinLock(&acb->XmitLock);
+ }
+
+ xmitptr = acb->acb_xmit_ahead;
+
+ if ((xmitptr == NULL) ||
+ !(xmitptr->XMIT_CSTAT & XCSTAT_COMPLETE))
+ {
+ if (acb->FullDuplexEnabled)
+ {
+ NdisReleaseSpinLock(&acb->XmitLock);
+ }
+
+ return;
+ }
+
+ //
+ // Increment the interrupt count.
+ //
+ acb->acb_int_count++;
+
+ //
+ // For each completed frame issue a NdisMSendComplete.
+ // Before completing the send, release the mapping of
+ // the phyical buffers if we are using the protocol's buffers.
+ //
+ while (xmitptr->XMIT_CSTAT & XCSTAT_COMPLETE)
+ {
+ XmitedOk++;
+
+ //
+ // Check the status of the transmit and update the
+ // counter accordingly.
+ //
+ if (xmitptr->XMIT_CSTAT & XCSTAT_ERROR)
+ {
+ // Transmit error
+ //
+ DebugPrint(1,("NF(%d): Xmit Error CSTAT = 0x%x\n",acb->anum,xmitptr->XMIT_CSTAT));
+ acb->acb_gen_objs.frames_xmitd_err++;
+ XmitedOk--;
+ status = NDIS_STATUS_FAILURE;
+ }
+ else if (( xmitptr->XMIT_CSTAT & 0xff00) &&
+ ((xmitptr->XMIT_CSTAT & 0xff00) != 0xcc00))
+ {
+ // FS indicates something happened
+ //
+ DebugPrint(1,("NF(%d): Xmit: FS = 0x%x\n",acb->anum,xmitptr->XMIT_CSTAT));
+ status = ((xmitptr->XMIT_CSTAT & XCSTAT_GOODFS) != XCSTAT_GOODFS)
+ ? NDIS_STATUS_NOT_RECOGNIZED : NDIS_STATUS_NOT_COPIED;
+ }
+
+ //
+ // Get the info we need from the sof.
+ //
+ curmap = xmitptr->XMIT_MapReg;
+ packet = xmitptr->XMIT_Packet;
+
+ //
+ // Clean up the transmit lists and the transmit queues.
+ //
+ xmitptr->XMIT_CSTAT = 0;
+ xmitptr->XMIT_Packet = NULL;
+
+ if (xmitptr->XMIT_OurBufferPtr == NULL)
+ {
+ // Normal Xmit Packet
+ //
+ NdisQueryPacket(
+ packet,
+ NULL,
+ NULL,
+ (PNDIS_BUFFER *)&SourceBuffer,
+ NULL);
+ while (SourceBuffer)
+ {
+ NdisMCompleteBufferPhysicalMapping(
+ acb->acb_handle,
+ (PNDIS_BUFFER)SourceBuffer,
+ curmap);
+ curmap++;
+ if (curmap == acb->acb_maxmaps)
+ {
+ curmap = 0;
+ }
+
+ NdisGetNextBuffer(SourceBuffer, &SourceBuffer);
+ }
+ }
+ else
+ {
+ // We've used one of our adapter buffers, so put the adapter
+ // buffer back on the free list.
+ //
+ if (xmitptr->XMIT_OurBufferPtr->BufferSize != acb->acb_smallbufsz)
+ {
+ xmitptr->XMIT_OurBufferPtr->Next = acb->OurBuffersListHead;
+ acb->OurBuffersListHead = xmitptr->XMIT_OurBufferPtr;
+ }
+ else
+ {
+ //
+ // small buffer
+ //
+ xmitptr->XMIT_OurBufferPtr->Next = acb->SmallBuffersListHead;
+ acb->SmallBuffersListHead = xmitptr->XMIT_OurBufferPtr;
+ }
+ xmitptr->XMIT_OurBufferPtr = NULL;
+ }
+
+ //
+ // Point to next xmit
+ //
+ if (xmitptr == acb->acb_xmit_atail)
+ {
+ // Set the list to null, also have to
+ // the ahead pointer, since if we had run
+ // out of xmit buffers, the wrapper can call
+ // our sendhandler during the completion.
+ //
+ xmitptr = acb->acb_xmit_ahead = acb->acb_xmit_atail = NULL;
+ }
+ else
+ {
+ // Point to the next xmit list
+ //
+ xmitptr = xmitptr->XMIT_Next;
+ }
+
+ //
+ // Increase the number of available xmit lists
+ //
+ acb->acb_avail_xmit++;
+
+ //
+ // Complete the request
+ //
+ if (acb->FullDuplexEnabled)
+ {
+ NdisReleaseSpinLock(&acb->XmitLock);
+ }
+
+ if (packet != NULL)
+ {
+ NdisMSendComplete(acb->acb_handle, packet, status);
+ }
+ else
+ {
+ NdisMSendResourcesAvailable(acb->acb_handle);
+ }
+
+ if (acb->FullDuplexEnabled)
+ {
+ NdisAcquireSpinLock(&acb->XmitLock);
+ }
+
+ if (xmitptr == NULL)
+ break;
+ }
+
+ //
+ // Update the head of the active lists if we ran into a non-completed
+ // list.
+ //
+ if (xmitptr)
+ {
+ acb->acb_xmit_ahead = xmitptr;
+ }
+
+ if (acb->acb_xmit_ahead)
+ {
+ //
+ // Issue a xmit valid adapter interrupt
+ //
+ NdisRawWritePortUshort(acb->SifIntPort, (USHORT) SIFINT_XMTVALID);
+ }
+
+ acb->acb_gen_objs.frames_xmitd_ok += XmitedOk;
+
+ if (acb->FullDuplexEnabled)
+ {
+ NdisReleaseSpinLock(&acb->XmitLock);
+ }
+}
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexTransmitStatus
+//
+// Description: This routine detemined the action to take
+// depending on the reason for the xmit interrupt
+//
+// Input: acb - Pointer to the Adapter's acb
+//
+// Output: None
+//
+// Calls: NdisRawWritePortUshort,
+// NetFlexDequeue_TwoPtrQ,
+// NetFlexSendNextSCB,
+// NetFlexEnqueue_TwoPtrQ_Tail
+//
+// Called_By: NetFlexDPR
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+VOID
+NetFlexTransmitStatus(
+ PACB acb
+ )
+{
+ PXMIT xmitptr;
+ UINT curmap;
+ PNDIS_PACKET packet;
+ NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+ PNDIS_BUFFER SourceBuffer;
+
+ if (acb->FullDuplexEnabled)
+ {
+ NdisAcquireSpinLock(&acb->XmitLock);
+ }
+
+ if (acb->acb_xmit_ahead == NULL)
+ {
+ if (acb->FullDuplexEnabled)
+ {
+ NdisReleaseSpinLock(&acb->XmitLock);
+ }
+
+ return;
+ }
+
+ //
+ // We have received a list error. Determine the type of list error
+ // in order to tell the protocol what happened.
+ //
+ acb->acb_gen_objs.frames_xmitd_err++;
+ xmitptr = acb->acb_xmit_ahead;
+
+ DebugPrint(1,("NF(%d): xmitptr = %x, Cstat = %x\n",acb->anum,xmitptr,xmitptr->XMIT_CSTAT));
+
+ switch (acb->acb_ssb_virtptr->SSB_Status & 0xff00)
+ {
+ case XSTAT_FRAME_SIZE_ERROR:
+ case XSTAT_ILLEGAL_FRAME_FORMAT:
+ case XSTAT_ACCESS_PRIORITY_ERR:
+ DebugPrint(1,("NF(%d): Frame sz err, illegal format or access priority\n",acb->anum));
+ status = NDIS_STATUS_INVALID_PACKET;
+ break;
+ case XSTAT_XMIT_THRESHOLD:
+ case XSTAT_ODD_ADDRESS:
+ case XSTAT_FRAME_ERROR:
+ case XSTAT_UNENABLE_MAC_FRAME:
+ acb->acb_gen_objs.frames_xmitd_err++;
+ DebugPrint(1,("NF(%d): threshold, frame error or unenable\n",acb->anum));
+ status = NDIS_STATUS_FAILURE;
+ break;
+ default:
+ acb->acb_gen_objs.frames_xmitd_err++;
+ DebugPrint(1,("NF(%d): Unknown error\n",acb->anum));
+ status = NDIS_STATUS_SUCCESS;
+ break;
+ }
+
+
+ //
+ // Get the info we need from the sof.
+ //
+ curmap = xmitptr->XMIT_MapReg;
+ packet = xmitptr->XMIT_Packet;
+
+ //
+ // Clean up the transmit lists and the transmit queues.
+ //
+ xmitptr->XMIT_CSTAT = 0;
+ xmitptr->XMIT_Packet = NULL;
+
+ //
+ // Take the error list off the active list. Set up the waiting list
+ // to either point to the next list of the active queue or the next
+ // available list from transmission.
+ //
+ if (acb->acb_state == AS_OPENED)
+ {
+ if (acb->acb_xmit_atail == xmitptr)
+ {
+ acb->acb_xmit_whead = acb->acb_xmit_wtail = xmitptr->XMIT_Next;
+ }
+ else
+ {
+ acb->acb_xmit_whead = xmitptr->XMIT_Next;
+ acb->acb_xmit_wtail = acb->acb_xmit_atail;
+ }
+ acb->acb_xmit_atail = acb->acb_xmit_ahead = NULL;
+
+ //
+ // Send off the transmit command to the adapter since the transmit
+ // command completes when a list error is encountered.
+ //
+ if (acb->acb_scb_virtptr->SCB_Cmd == 0)
+ {
+ NetFlexSendNextSCB(acb);
+ }
+ else if (!acb->acb_scbclearout)
+ {
+ acb->acb_scbclearout = TRUE;
+ NdisRawWritePortUshort(acb->SifIntPort, (USHORT) SIFINT_SCBREQST);
+ }
+ }
+ else
+ {
+ acb->acb_xmit_atail = acb->acb_xmit_ahead = NULL;
+ }
+ acb->acb_avail_xmit++;
+
+ if (xmitptr->XMIT_OurBufferPtr != NULL)
+ {
+ // We've used one of our adapter buffers, so put the adapter
+ // buffer back on the free list.
+ //
+ if (xmitptr->XMIT_OurBufferPtr->BufferSize != acb->acb_smallbufsz)
+ {
+ xmitptr->XMIT_OurBufferPtr->Next = acb->OurBuffersListHead;
+ acb->OurBuffersListHead = xmitptr->XMIT_OurBufferPtr;
+ }
+ else
+ {
+ //
+ // small buffer
+ //
+ xmitptr->XMIT_OurBufferPtr->Next = acb->SmallBuffersListHead;
+ acb->SmallBuffersListHead = xmitptr->XMIT_OurBufferPtr;
+ }
+ xmitptr->XMIT_OurBufferPtr = NULL;
+ }
+ else
+ {
+ NdisQueryPacket(
+ packet,
+ NULL,
+ NULL,
+ (PNDIS_BUFFER *)&SourceBuffer,
+ NULL);
+
+ while (SourceBuffer)
+ {
+ NdisMCompleteBufferPhysicalMapping(
+ acb->acb_handle,
+ (PNDIS_BUFFER)SourceBuffer,
+ curmap);
+
+ curmap++;
+ if (curmap == acb->acb_maxmaps)
+ {
+ curmap = 0;
+ }
+
+ NdisGetNextBuffer(SourceBuffer, &SourceBuffer);
+ }
+ }
+ //
+ // Complete the request
+ //
+ if (acb->FullDuplexEnabled)
+ {
+ NdisReleaseSpinLock(&acb->XmitLock);
+ }
+
+ if (packet)
+ {
+ NdisMSendComplete(acb->acb_handle, packet, status);
+ }
+ else
+ {
+ NdisMSendResourcesAvailable(acb->acb_handle);
+ }
+}
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexSend
+//
+// Description: This routine places the given packet on the
+// adapter's transmit list.
+//
+// Input:
+// MiniportAdapterContext - The context value
+// returned by the Miniport when the adapter was
+// initialized. In reality, it is a pointer to ACB
+//
+// Packet - A pointer to a descriptor for the packet
+// that is to be transmitted.
+//
+// Flags - The send options to use.
+//
+// Output: Returns NDIS_STATUS_SUCCESS for a successful
+// completion. Otherwise, an error code is
+// returned.
+//
+// Calls: NdisQueryPacket,NdisQueryBuffer,NdisMoveMemory
+// NdisGetNextBuffer,NdisGetBufferPhysicalAddress
+// NdisWritePortUshort,NetFlexEnqueue_TwoPtrQ_Tail
+// NetFlexDequeue_OnePtrQ_Head,SWAPL,SWAPS
+//
+// Called_By: Wrapper
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+NDIS_STATUS NetFlexSend(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET Packet,
+ IN UINT Flags
+ )
+{
+ PACB acb = (PACB) MiniportAdapterContext;
+ PXMIT xmitptr;
+
+ UINT PhysicalBufferCount, BufferCount;
+ UINT TotalPacketLength;
+ PNDIS_BUFFER SourceBuffer;
+ PUSHORT avail_xmits;
+
+
+ UINT curmap,j,i;
+ UINT arraysize;
+ ULONG physbufptr;
+ NDIS_STATUS status = NDIS_STATUS_PENDING;
+
+ NDIS_PHYSICAL_ADDRESS_UNIT physaddrarray[MAX_BUFS_PER_XMIT];
+
+ //
+ // if we are in full duplex mode then acquire the xmit spin lock.
+ //
+ if (acb->FullDuplexEnabled)
+ {
+ NdisAcquireSpinLock(&acb->XmitLock);
+ }
+
+ avail_xmits = &acb->acb_avail_xmit;
+
+ //
+ // Do we have at least one available xmit list?
+ //
+ if (*avail_xmits)
+ {
+ // Yes, See if we can process this send request
+ //
+ NdisQueryPacket(
+ Packet,
+ (PUINT)&PhysicalBufferCount,
+ (PUINT)&BufferCount,
+ (PNDIS_BUFFER *)(&SourceBuffer),
+ (PUINT)(&TotalPacketLength));
+
+ //
+ // Point to the head of the xmit list
+ //
+ xmitptr = acb->acb_xmit_head;
+
+ //
+ // Do we need to use our own buffer?
+ //
+ if ((PhysicalBufferCount <= MAX_BUFS_PER_XMIT) &&
+ (TotalPacketLength > acb->acb_smallbufsz ||
+ acb->SmallBuffersListHead == NULL))
+ {
+ // Clean the Data fields
+ //
+ NdisZeroMemory(xmitptr->XMIT_Data, SIZE_XMIT_DATA);
+
+ // With the new fpa mac code we can only use 1
+ // xmit list per xmit. Point the head pointer to the next
+ // available list. At this point we are guaranteed less than
+ // MAX_BUFS_PER_XMIT buffers per xmit = 1 xmit list.
+ //
+
+ curmap = acb->acb_curmap;
+ acb->acb_curmap += BufferCount;
+ if (acb->acb_curmap >= acb->acb_maxmaps)
+ {
+ acb->acb_curmap -= acb->acb_maxmaps;
+ }
+
+ xmitptr->XMIT_MapReg = curmap;
+
+ i=0;
+ while (SourceBuffer != NULL)
+ {
+ NdisMStartBufferPhysicalMapping(
+ acb->acb_handle,
+ SourceBuffer,
+ curmap,
+ TRUE,
+ physaddrarray,
+ &arraysize);
+
+ curmap++;
+ if (curmap == acb->acb_maxmaps)
+ {
+ curmap = 0;
+ }
+
+ for (j=0; j < arraysize; j++)
+ {
+ physbufptr = SWAPL(NdisGetPhysicalAddressLow(physaddrarray[j].PhysicalAddress));
+ xmitptr->XMIT_Data[i].DataCount = (USHORT)(SWAPS(physaddrarray[j].Length)) | DATA_NOT_LAST;
+ xmitptr->XMIT_Data[i].DataHi = (USHORT)physbufptr;
+ xmitptr->XMIT_Data[i].DataLo = (USHORT)(physbufptr >> 16);
+ PhysicalBufferCount--;
+ i++;
+ }
+ NdisFlushBuffer(SourceBuffer, TRUE);
+ NdisGetNextBuffer(SourceBuffer, &SourceBuffer);
+ }
+
+ xmitptr->XMIT_Data[i-1].DataCount &= DATA_LAST;
+ xmitptr->XMIT_Fsize = (SHORT)(SWAPS((USHORT)TotalPacketLength));
+ xmitptr->XMIT_Packet = Packet;
+ xmitptr->XMIT_OurBufferPtr = NULL;
+ }
+ else
+ {
+ // We need to constrain the packet into our own buffer
+ //
+ if (((PhysicalBufferCount > MAX_BUFS_PER_XMIT) &&
+ (acb->OurBuffersListHead != NULL)) ||
+ ((acb->SmallBuffersListHead != NULL) &&
+ (TotalPacketLength <= acb->acb_smallbufsz)))
+ {
+ status = NetFlexConstrainPacket(
+ acb,
+ xmitptr,
+ Packet,
+ PhysicalBufferCount,
+ SourceBuffer,
+ TotalPacketLength);
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ if (acb->FullDuplexEnabled)
+ {
+ NdisReleaseSpinLock(&acb->XmitLock);
+ }
+
+ return(status);
+ }
+ }
+ else
+ {
+ // we don't have any buffers at this time...
+ // See if we can process any transmits, freeing up any that are completed...
+ //
+ DebugPrint(1,("NF(%d): No empty Xmit Buffers to transfer into\n",acb->anum));
+
+ if (acb->FullDuplexEnabled)
+ {
+ NdisReleaseSpinLock(&acb->XmitLock);
+ }
+
+ return(NDIS_STATUS_RESOURCES);
+ }
+ }
+
+ //
+ // Update all the pointers...
+ //
+ acb->acb_xmit_head = xmitptr->XMIT_Next;
+
+ xmitptr->XMIT_Timeout = 0;
+
+#ifdef XMIT_INTS
+
+ //
+ // Leave the original FInt setting
+ //
+ xmitptr->XMIT_CSTAT =
+ ((xmitptr->XMIT_Number % acb->XmitIntRatio) == 0) ? XCSTAT_GO_INT : XCSTAT_GO;
+#else
+ xmitptr->XMIT_CSTAT = XCSTAT_GO;
+#endif
+
+ //
+ // Update Tail Pointer
+ //
+ acb->acb_xmit_atail = xmitptr;
+
+ //
+ // Update the head if this is the first one...
+ //
+ if (acb->acb_xmit_ahead == NULL)
+ {
+ acb->acb_xmit_ahead = xmitptr;
+ }
+
+ //
+ // If the transmitter had stalled because it ran out of
+ // valid lists, issue an adapter int to pickup this new valid one.
+ //
+ NdisRawWritePortUshort(acb->SifIntPort, (USHORT) SIFINT_XMTVALID);
+
+ //
+ // Indicate we've taken one of the ints
+ //
+ (*avail_xmits)--;
+
+ if (acb->FullDuplexEnabled)
+ {
+ NdisReleaseSpinLock(&acb->XmitLock);
+ }
+
+ return(status);
+ }
+
+ // No, We don't have any transmits at this time...
+ //
+ DebugPrint(2,("NF(%d): Send, Out of Xmit Lists...\n",acb->anum));
+
+ if (acb->FullDuplexEnabled)
+ {
+ NdisReleaseSpinLock(&acb->XmitLock);
+ }
+
+ return(NDIS_STATUS_RESOURCES);
+}
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Routine Name: NetFlexConstrainPacket
+//
+// Description: This routine combines the packet fragments
+// into our own buffer for transmition.
+//
+// Called_By: NetFlexSend
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+NDIS_STATUS
+NetFlexConstrainPacket(
+ PACB acb,
+ PXMIT xmitptr,
+ PNDIS_PACKET Packet,
+ UINT PhysicalBufferCount,
+ PNDIS_BUFFER SourceBuffer,
+ UINT TotalPacketLength
+ )
+{
+ PVOID SourceData; // Points to the virtual address of the source buffers data.
+ UINT SourceLength; // Number of bytes of data in the source buffer.
+ PCHAR CurrentDestination; // Pointer to virtual address for the adapter buffer
+ UINT TotalDataMoved = 0;
+ ULONG AdapterPhysicalBufferPtr;
+
+ PBUFFER_DESCRIPTOR BufferDescriptor;
+
+ if (TotalPacketLength > acb->acb_smallbufsz)
+ {
+ BufferDescriptor = acb->OurBuffersListHead;
+
+ if (!BufferDescriptor)
+ {
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ acb->OurBuffersListHead = BufferDescriptor->Next;
+ BufferDescriptor->Next = NULL;
+ }
+ else
+ {
+ BufferDescriptor = acb->SmallBuffersListHead;
+
+ if (!BufferDescriptor)
+ {
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ acb->SmallBuffersListHead = BufferDescriptor->Next;
+ BufferDescriptor->Next = NULL;
+ }
+
+ //
+ // Clear out the data fields in the xmit list
+ //
+ NdisZeroMemory(xmitptr->XMIT_Data, SIZE_XMIT_DATA);
+
+ //
+ // Copy the packet's buffers into our buffer
+ //
+ CurrentDestination = BufferDescriptor->VirtualBuffer;
+ BufferDescriptor->DataLength = TotalPacketLength;
+
+ do
+ {
+ // Get Buffer info
+ //
+ NdisQueryBuffer(SourceBuffer, &SourceData, &SourceLength);
+
+ // Copy this buffer
+ //
+ NdisMoveMemory(CurrentDestination, SourceData, SourceLength);
+
+ //
+ // Update destination address
+ //
+ CurrentDestination = (PCHAR)CurrentDestination + SourceLength;
+
+ //
+ // Update count of packet length.
+ //
+ TotalDataMoved += SourceLength;
+
+ //
+ // Get the next buffers information
+ //
+ NdisGetNextBuffer(SourceBuffer, &SourceBuffer);
+
+ } while (SourceBuffer != NULL);
+
+
+ NdisFlushBuffer(BufferDescriptor->FlushBuffer, TRUE);
+
+ AdapterPhysicalBufferPtr =
+ SWAPL(NdisGetPhysicalAddressLow(BufferDescriptor->PhysicalBuffer));
+
+ xmitptr->XMIT_OurBufferPtr = BufferDescriptor;
+ xmitptr->XMIT_Data[0].DataCount = (USHORT)(SWAPS((USHORT)TotalPacketLength)) & DATA_LAST;
+ xmitptr->XMIT_Data[0].DataHi = (USHORT) AdapterPhysicalBufferPtr;
+ xmitptr->XMIT_Data[0].DataLo = (USHORT)(AdapterPhysicalBufferPtr >> 16);
+ xmitptr->XMIT_Fsize = (SHORT)(SWAPS((USHORT)TotalPacketLength));
+ xmitptr->XMIT_Packet = NULL;
+
+
+ DebugPrint(2,("NF(%d): Using internal buffer\n",acb->anum));
+
+ return NDIS_STATUS_SUCCESS;
+}
diff --git a/private/ntos/ndis/odimac/keywords.h b/private/ntos/ndis/odimac/keywords.h
new file mode 100644
index 000000000..35896713e
--- /dev/null
+++ b/private/ntos/ndis/odimac/keywords.h
@@ -0,0 +1,54 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ keywords.h
+
+Abstract:
+
+ Contains all Ndis2 and Ndis3 mac-specific keywords.
+
+Author:
+
+ Bob Noradki
+
+Environment:
+
+ This driver is expected to work in DOS, OS2 and NT at the equivalent
+ of kernal mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+
+
+--*/
+#ifndef NDIS2
+#define NDIS2 0
+#endif
+
+#if NDIS2
+
+#define IOBASE NDIS_STRING_CONST("IOBASE")
+#define MAXMULTICASTLIST NDIS_STRING_CONST("MAXMULTICAST")
+#define NETADDRESS NDIS_STRING_CONST("NETADDRESS")
+#define INTERRUPT NDIS_STRING_CONST("IRQ")
+#define MEMMAPPEDBASEADDRESS NDIS_STRING_CONST("RAMADDRESS")
+
+#else // NDIS3
+
+#define IOBASE NDIS_STRING_CONST("IoBaseAddress")
+#define MAXMULTICASTLIST NDIS_STRING_CONST("MaximumMulticastList")
+#define NETADDRESS NDIS_STRING_CONST("NetworkAddress")
+#define INTERRUPT NDIS_STRING_CONST("InterruptNumber")
+#define MEMMAPPEDBASEADDRESS NDIS_STRING_CONST("MemoryMappedBaseAddress")
+
+#endif
diff --git a/private/ntos/ndis/odimac/mlid.c b/private/ntos/ndis/odimac/mlid.c
new file mode 100644
index 000000000..67826a8f1
--- /dev/null
+++ b/private/ntos/ndis/odimac/mlid.c
@@ -0,0 +1,4413 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ Mlid.c
+
+Abstract:
+
+ This is the main file for the Western Digital
+ Ethernet controller. This driver conforms to the NDIS 3.1 interface.
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 15-Jan-1992
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+#include <efilter.h>
+#include <odihsm.h>
+#include <mlidsft.h>
+#include "keywords.h"
+
+#if DBG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+#if DBG
+
+
+#define LOGSIZE 512
+
+extern UCHAR MlidDebugLog[LOGSIZE] = {0};
+extern UINT MlidDebugLogPlace = 0;
+
+
+extern
+VOID
+LOG (UCHAR A) {
+ MlidDebugLog[MlidDebugLogPlace++] = A;
+ MlidDebugLog[(MlidDebugLogPlace + 4) % LOGSIZE] = '\0';
+ if (MlidDebugLogPlace >= LOGSIZE) MlidDebugLogPlace = 0;
+}
+
+
+ULONG MlidDebugFlag= MLID_DEBUG_LOG; // MLID_DEBUG_LOG | MLID_DEBUG_LOUD | MLID_DEBUG_VERY_LOUD;
+
+#define IF_LOG(A) A
+
+#else
+
+#define IF_LOG(A)
+
+#endif
+
+
+//
+// This constant is used for places where NdisAllocateMemory
+// needs to be called and the HighestAcceptableAddress does
+// not matter.
+//
+
+NDIS_PHYSICAL_ADDRESS HighestAcceptableMax =
+ NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
+
+
+
+//
+// The global MAC block.
+//
+
+extern MAC_BLOCK MlidMacBlock={0};
+
+
+
+//
+// If you add to this, make sure to add the
+// a case in MlidFillInGlobalData() and in
+// MlidQueryGlobalStatistics() if global
+// information only or
+// MlidQueryProtocolStatistics() if it is
+// protocol queriable information.
+//
+UINT MlidGlobalSupportedOids[] = {
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+
+/*++
+ These are not available
+
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+
+--*/
+
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ OID_802_3_RCV_ERROR_ALIGNMENT,
+ OID_802_3_XMIT_ONE_COLLISION,
+ OID_802_3_XMIT_MORE_COLLISIONS,
+
+ OID_802_5_PERMANENT_ADDRESS,
+ OID_802_5_CURRENT_ADDRESS,
+ OID_802_5_CURRENT_FUNCTIONAL,
+ OID_802_5_CURRENT_GROUP,
+ OID_802_5_LAST_OPEN_STATUS,
+ OID_802_5_CURRENT_RING_STATUS,
+ OID_802_5_CURRENT_RING_STATE,
+ OID_802_5_LINE_ERRORS,
+ OID_802_5_LOST_FRAMES
+ };
+
+//
+// If you add to this, make sure to add the
+// a case in MlidQueryGlobalStatistics() and in
+// MlidQueryProtocolInformation()
+//
+UINT MlidProtocolSupportedOids[] = {
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+
+/*++
+ Not available
+
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+--*/
+
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+
+ OID_802_5_PERMANENT_ADDRESS,
+ OID_802_5_CURRENT_ADDRESS,
+ OID_802_5_CURRENT_FUNCTIONAL,
+ OID_802_5_CURRENT_GROUP,
+ OID_802_5_LAST_OPEN_STATUS,
+ OID_802_5_CURRENT_RING_STATUS,
+ OID_802_5_CURRENT_RING_STATE,
+ OID_802_5_LINE_ERRORS,
+ OID_802_5_LOST_FRAMES
+ };
+
+
+
+
+
+
+
+UINT
+MlidCopyOver(
+ OUT PUCHAR Buf, // destination
+ IN PNDIS_PACKET Packet, // source packet
+ IN UINT Offset, // offset in packet
+ IN UINT Length // number of bytes to copy
+ );
+
+
+
+
+#ifdef NDIS_WIN
+ #ifndef DEBUG
+ #pragma code_seg ("_ITEXT","ICODE")
+ #endif
+#endif
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+/*++
+
+Routine Description:
+
+ This is the transfer address of the driver. It initializes
+ MlidMacBlock and calls NdisInitializeWrapper() and
+ NdisRegisterMac().
+
+Arguments:
+
+Return Value:
+
+ Indicates the success or failure of the initialization.
+
+--*/
+
+{
+ PMAC_BLOCK NewMacP = &MlidMacBlock;
+ NDIS_STATUS Status;
+ NDIS_HANDLE NdisWrapperHandle;
+
+#ifdef NDIS_NT
+ NDIS_STRING MacName = NDIS_STRING_CONST("Smc8000n");
+#endif
+
+#ifdef NDIS_WIN
+ NDIS_STRING MacName = NDIS_STRING_CONST("SMC8000W");
+#endif
+
+ //
+ // Ensure that the MAC_RESERVED structure will fit in the
+ // MacReserved section of a packet.
+ //
+
+ ASSERT(sizeof(MAC_RESERVED) <= sizeof(((PNDIS_PACKET)NULL)->MacReserved));
+
+
+ //
+ // Pass the wrapper a pointer to the device object.
+ //
+
+ NdisInitializeWrapper(&NdisWrapperHandle,
+ DriverObject,
+ RegistryPath,
+ NULL
+ );
+
+ //
+ // Set up the driver object.
+ //
+
+ NewMacP->DriverObject = DriverObject;
+
+ NdisAllocateSpinLock(&NewMacP->SpinLock);
+
+ NewMacP->NdisWrapperHandle = NdisWrapperHandle;
+ NewMacP->Unloading = FALSE;
+ NewMacP->NumAdapters = 0;
+ NewMacP->AdapterQueue = (PMLID_ADAPTER)NULL;
+
+
+ //
+ // Prepare to call NdisRegisterMac.
+ //
+
+ NewMacP->MacCharacteristics.MajorNdisVersion = MLID_NDIS_MAJOR_VERSION;
+ NewMacP->MacCharacteristics.MinorNdisVersion = MLID_NDIS_MINOR_VERSION;
+ NewMacP->MacCharacteristics.Reserved = 0;
+ NewMacP->MacCharacteristics.OpenAdapterHandler = MlidOpenAdapter;
+ NewMacP->MacCharacteristics.CloseAdapterHandler = MlidCloseAdapter;
+ NewMacP->MacCharacteristics.SendHandler = MlidSend;
+ NewMacP->MacCharacteristics.TransferDataHandler = MlidTransferData;
+ NewMacP->MacCharacteristics.ResetHandler = MlidReset;
+ NewMacP->MacCharacteristics.RequestHandler = MlidRequest;
+ NewMacP->MacCharacteristics.QueryGlobalStatisticsHandler =
+ MlidQueryGlobalStatistics;
+ NewMacP->MacCharacteristics.UnloadMacHandler = MlidUnload;
+ NewMacP->MacCharacteristics.AddAdapterHandler = MlidAddAdapter;
+ NewMacP->MacCharacteristics.RemoveAdapterHandler = MlidRemoveAdapter;
+
+ NewMacP->MacCharacteristics.Name = MacName;
+
+ NdisRegisterMac(&Status,
+ &NewMacP->NdisMacHandle,
+ NdisWrapperHandle,
+ (NDIS_HANDLE)&MlidMacBlock,
+ &NewMacP->MacCharacteristics,
+ sizeof(NewMacP->MacCharacteristics));
+
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ //
+ // NdisRegisterMac failed.
+ //
+
+ NdisFreeSpinLock(&NewMacP->SpinLock);
+ NdisTerminateWrapper(NdisWrapperHandle, NULL);
+ IF_LOUD( DbgPrint( "NdisRegisterMac failed with code 0x%x\n", Status );)
+ return Status;
+ }
+
+
+ IF_LOUD( DbgPrint( "NdisRegisterMac succeeded\n" );)
+
+ IF_LOUD( DbgPrint("Adapter Initialization Complete\n");)
+
+ return Status;
+
+}
+
+#ifdef NDIS_WIN
+ #ifndef DEBUG
+ #pragma code_seg ()
+ #endif
+#endif
+
+
+#ifdef NDIS_WIN
+ #ifndef DEBUG
+ #pragma code_seg ("_ITEXT","ICODE")
+ #endif
+#endif
+
+NDIS_STATUS
+MlidAddAdapter(
+ IN NDIS_HANDLE MacMacContext,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING AdapterName
+ )
+/*++
+Routine Description:
+
+ This is the Mlid MacAddAdapter routine. The system calls this routine
+ to add support for a particular Mlid adapter. This routine extracts
+ configuration information from the configuration data base and registers
+ the adapter with NDIS.
+
+Arguments:
+
+ see NDIS 3.0 spec...
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS - Adapter was successfully added.
+ NDIS_STATUS_FAILURE - Adapter was not added, also MAC deregistered.
+
+--*/
+{
+
+ LM_STATUS LmStatus;
+ NDIS_HANDLE ConfigHandle;
+ PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
+ NDIS_STRING MlidDriverNameStr = NDIS_STRING_CONST("MlidDriverName");
+
+ ULONG ConfigErrorValue = 0;
+ BOOLEAN ConfigError = FALSE;
+
+ PMAC_BLOCK NewMacP = &MlidMacBlock;
+ NDIS_STATUS Status;
+ PMLID_ADAPTER Adapter;
+ NDIS_ADAPTER_INFORMATION AdapterInformation; // needed to register adapter
+
+
+ UNREFERENCED_PARAMETER(MacMacContext);
+
+ NdisOpenConfiguration(
+ &Status,
+ &ConfigHandle,
+ ConfigurationHandle
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+#if i386
+#else
+ ASSERT(0);
+#endif
+
+ //
+ // Read MlidDriverName
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &MlidDriverNameStr,
+ NdisParameterString
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NdisCloseConfiguration(ConfigHandle);
+
+ return(NDIS_STATUS_FAILURE);
+
+ }
+
+ //
+ // Here we load the image for the MLID, get the configuration and make the
+ // appropriate setup calls
+ //*\\ HERE!
+
+ //
+ // Allocate memory for the adapter block now.
+ //
+
+ Status = NdisAllocateMemory( (PVOID *)&Adapter, sizeof(MLID_ADAPTER), 0, HighestAcceptableMax);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ ConfigError = TRUE;
+ ConfigErrorValue = NDIS_ERROR_CODE_OUT_OF_RESOURCES;
+
+ }
+
+ NdisZeroMemory(Adapter,sizeof(MLID_ADAPTER));
+
+ //
+ // The adapter is initialized, register it with NDIS.
+ // This must occur before interrupts are enabled since the
+ // InitializeInterrupt routine requires the NdisAdapterHandle
+ //
+
+ //
+ // Set up the AdapterInformation structure; zero it
+ // first in case it is extended later.
+ //
+
+ NdisZeroMemory (&AdapterInformation, sizeof(NDIS_ADAPTER_INFORMATION));
+ AdapterInformation.NumberOfPortDescriptors = 0;
+
+ Status = NdisRegisterAdapter(&Adapter->NdisAdapterHandle,
+ MlidMacBlock.NdisMacHandle,
+ (NDIS_HANDLE)Adapter,
+ ConfigurationHandle,
+ AdapterName,
+ &AdapterInformation
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ //
+ // NdisRegisterAdapter failed.
+ //
+
+ NdisCloseConfiguration(ConfigHandle);
+
+ NdisFreeMemory(Adapter, sizeof(MLID_ADAPTER), 0);
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+
+ if (ConfigError) {
+
+ //
+ // Log Error and exit.
+ //
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ ConfigErrorValue,
+ 1
+ );
+
+ NdisCloseConfiguration(ConfigHandle);
+
+ NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
+
+ NdisFreeMemory(Adapter, sizeof(MLID_ADAPTER), 0);
+
+ return(NDIS_STATUS_FAILURE);
+
+ }
+
+ NdisCloseConfiguration(ConfigHandle);
+
+
+ if (MlidRegisterAdapter(Adapter) != NDIS_STATUS_SUCCESS) {
+
+ //
+ // MlidRegisterAdapter failed.
+ //
+
+ NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
+ NdisFreeMemory(Adapter, sizeof(MLID_ADAPTER), 0);
+ return NDIS_STATUS_FAILURE;
+ }
+
+ IF_LOUD( DbgPrint( "MlidRegisterAdapter succeeded\n" );)
+
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+#ifdef NDIS_WIN
+ #ifndef DEBUG
+ #pragma code_seg ()
+ #endif
+#endif
+
+#ifdef NDIS_WIN
+ #ifndef DEBUG
+ #pragma code_seg ("_ITEXT","ICODE")
+ #endif
+#endif
+
+NDIS_STATUS
+MlidRegisterAdapter(
+ IN PMLID_ADAPTER Adapter
+ )
+
+/*++
+
+
+Routine Description:
+
+ Called when a new adapter should be registered. It allocates space for
+ the adapter and open blocks, initializes the adapters block, and
+ calls NdisRegisterAdapter().
+
+Arguments:
+
+ Adapter - A pointer to the adapter structure.
+
+Return Value:
+
+ Indicates the success or failure of the registration.
+
+--*/
+
+{
+ UINT i;
+ NDIS_PHYSICAL_ADDRESS PhysicalAddress;
+
+ NDIS_STATUS status; //general purpose return from NDIS calls
+
+ Adapter->OpenQueue = (PMLID_OPEN)NULL;
+
+ //
+ // Allocate the Spin lock.
+ //
+ NdisAllocateSpinLock(&Adapter->Lock);
+
+ Adapter->DeferredDpc = (PVOID)MlidReceiveEvents;
+
+ NdisInitializeTimer(&(Adapter->DeferredTimer),
+ Adapter->DeferredDpc,
+ Adapter);
+
+ //
+ // Link us on to the chain of adapters for this MAC.
+ //
+
+ Adapter->MacBlock = &MlidMacBlock;
+ NdisAcquireSpinLock(&MlidMacBlock.SpinLock);
+ Adapter->NextAdapter = MlidMacBlock.AdapterQueue;
+ MlidMacBlock.AdapterQueue = Adapter;
+ NdisReleaseSpinLock(&MlidMacBlock.SpinLock);
+
+ //
+ // Set up the interrupt handlers.
+ //*\\ HERE!
+
+ KernelInterrupt = (CCHAR)(Adapter->irq_value);
+
+ NdisInitializeInterrupt(&status, // status of call
+ &(Adapter->NdisInterrupt), // interrupt info str
+ Adapter->NdisAdapterHandle,
+ (PNDIS_INTERRUPT_SERVICE) MlidInterruptHandler,
+ Adapter, // context for ISR, DPC
+ (PNDIS_DEFERRED_PROCESSING) MlidInterruptDpc,
+ KernelInterrupt, // int #
+ KernelInterrupt, // IRQL
+ FALSE, // NOT shared
+ (Adapter->bus_type == 0) ?
+ NdisInterruptLatched : // ATBus
+ NdisInterruptLevelSensitive // MCA
+ );
+
+
+ if (status != NDIS_STATUS_SUCCESS) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_INTERRUPT_CONNECT,
+ 0
+ );
+
+ goto fail3;
+ }
+
+ IF_LOUD( DbgPrint("Interrupt Connected\n");)
+
+ //
+ // Map the memory mapped portion of the card.
+ //
+ //
+
+ NdisSetPhysicalAddressHigh(PhysicalAddress, 0);
+ NdisSetPhysicalAddressLow(PhysicalAddress, (ULONG)(Adapter->ram_base));
+
+ //
+ // Now Initialize the card.
+ //*\\ HERE!
+
+ Adapter->FilterDB = NULL;
+
+ //
+ // Initialize Filter Database
+ //*\\ HERE!
+
+ if (Adapter->TokenRing) {
+
+ //
+ // token ring
+ //*\\ HERE!
+
+ goto fail6;
+
+ } else {
+
+ if (!EthCreateFilter(MulticastListMax,
+ MlidChangeMulticastAddresses,
+ MlidChangeFilterClasses,
+ MlidCloseAction,
+ Adapter->node_address,
+ &Adapter->Lock,
+ &Adapter->FilterDB
+ )) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+
+ status = NDIS_STATUS_FAILURE;
+
+ goto fail6;
+
+ }
+
+ }
+
+ //
+ // Initialize the wake up timer to catch interrupts that
+ // don't complete. It fires continuously
+ // every 5 seconds, and we check if there are any
+ // uncompleted operations from the previous two-second
+ // period.
+ //
+
+ Adapter->WakeUpDpc = (PVOID)MlidWakeUpDpc;
+
+ NdisInitializeTimer(&Adapter->WakeUpTimer,
+ (PVOID)(Adapter->WakeUpDpc),
+ Adapter );
+
+ NdisSetTimer(
+ &Adapter->WakeUpTimer,
+ 5000
+ );
+
+ //
+ // Initialization completed successfully.
+ //
+
+ IF_LOUD( { DbgPrint(" MlidLan: [OK]\n");})
+
+ return NDIS_STATUS_SUCCESS;
+
+
+ //
+ // Code to unwind what has already been set up when a part of
+ // initialization fails, which is jumped into at various
+ // points based on where the failure occured. Jumping to
+ // a higher-numbered failure point will execute the code
+ // for that block and all lower-numbered ones.
+ //
+
+fail6:
+
+ NdisUnmapIoSpace(
+ Adapter->NdisAdapterHandle,
+ Adapter->ram_access,
+ Adapter->ram_size * 1024);
+
+failmap:
+
+ NdisRemoveInterrupt(&(Adapter->NdisInterrupt));
+
+ NdisAcquireSpinLock(&MlidMacBlock.SpinLock);
+
+ //
+ // Take us out of the AdapterQueue.
+ //
+
+ if (MlidMacBlock.AdapterQueue == Adapter) {
+
+ MlidMacBlock.AdapterQueue = Adapter->NextAdapter;
+
+ } else {
+
+ PMLID_ADAPTER TmpAdapter = MlidMacBlock.AdapterQueue;
+
+ while (TmpAdapter->NextAdapter != Adapter) {
+
+ TmpAdapter = TmpAdapter->NextAdapter;
+
+ }
+
+ TmpAdapter->NextAdapter = TmpAdapter->NextAdapter->NextAdapter;
+ }
+
+ NdisReleaseSpinLock(&MlidMacBlock.SpinLock);
+
+fail3:
+ NdisFreeSpinLock(&Adapter->Lock);
+
+fail1:
+
+ return status;
+}
+
+#ifdef NDIS_WIN
+ #ifndef DEBUG
+ #pragma code_seg ()
+ #endif
+#endif
+
+#ifdef NDIS_WIN
+ #ifndef DEBUG
+ #pragma code_seg ("_ITEXT","ICODE")
+ #endif
+#endif
+
+NDIS_STATUS
+MlidOpenAdapter(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT NDIS_HANDLE * MacBindingHandle,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_HANDLE MacAdapterContext,
+ IN UINT OpenOptions,
+ IN PSTRING AddressingInformation OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ NDIS function. It initializes the open block and links it in
+ the appropriate lists.
+
+Arguments:
+
+ See NDIS 3.0 spec.
+
+--*/
+
+{
+ PMLID_ADAPTER Adapter = ((PMLID_ADAPTER)MacAdapterContext);
+ PMLID_OPEN NewOpen;
+ NDIS_STATUS Status;
+
+ //
+ // Don't use extended error or OpenOptions for Mlid
+ //
+
+ UNREFERENCED_PARAMETER(OpenOptions);
+
+ *OpenErrorStatus=NDIS_STATUS_SUCCESS;
+
+ IF_LOUD( DbgPrint("In Open Adapter\n");)
+
+ //
+ // Scan the media list for our media type (802.3)
+ //
+
+ *SelectedMediumIndex = (UINT)(-1);
+
+ while (MediumArraySize > 0) {
+
+ if (MediumArray[--MediumArraySize] == NdisMedium802_3 ) {
+
+ *SelectedMediumIndex = MediumArraySize;
+
+ break;
+ }
+ }
+
+
+ if (*SelectedMediumIndex == -1) {
+
+ return NDIS_STATUS_UNSUPPORTED_MEDIA;
+
+ }
+
+ //
+ // Link this open to the appropriate lists.
+ //
+
+ if (Adapter->HardwareFailure) {
+
+ return(NDIS_STATUS_FAILURE);
+
+ }
+
+ //
+ // Allocate memory for the open.
+ //
+
+
+ Status = NdisAllocateMemory((PVOID *)&NewOpen, sizeof(MLID_OPEN), 0, HighestAcceptableMax);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+
+ return(NDIS_STATUS_RESOURCES);
+
+ }
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ Adapter->References++;
+
+ //
+ // Link this open to the appropriate lists.
+ //
+
+ if (Adapter->OpenQueue == NULL) {
+
+ //
+ // The first open on this adapter.
+ //
+
+ if (LM_Open_Adapter(&(Adapter->LMAdapter)) != SUCCESS) {
+
+ IF_LOUD( DbgPrint("OpenFailed!\n");)
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 0
+ );
+
+ return(NDIS_STATUS_FAILURE);
+
+ }
+
+ IF_LOUD( DbgPrint("OpenSuccess!\n");)
+
+ }
+
+ NewOpen->NextOpen = Adapter->OpenQueue;
+ Adapter->OpenQueue = NewOpen;
+
+ if (Adapter->TokenRing) {
+
+ //*\\ token ring
+
+ } else {
+
+ if (!EthNoteFilterOpenAdapter(
+ Adapter->FilterDB,
+ NewOpen,
+ NdisBindingContext,
+ &NewOpen->NdisFilterHandle
+ )) {
+
+ Adapter->References--;
+
+ Adapter->OpenQueue = NewOpen->NextOpen;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+
+ return NDIS_STATUS_FAILURE;
+
+
+ }
+
+ }
+
+ //
+ // Set up the open block.
+ //
+
+ NewOpen->Adapter = Adapter;
+ NewOpen->MacBlock = Adapter->MacBlock;
+ NewOpen->NdisBindingContext = NdisBindingContext;
+ NewOpen->AddressingInformation = AddressingInformation;
+ NewOpen->Closing = FALSE;
+ NewOpen->LookAhead = MLID_MAX_LOOKAHEAD;
+ NewOpen->ProtOptionFlags = 0;
+
+ Adapter->MaxLookAhead = MLID_MAX_LOOKAHEAD;
+
+ NewOpen->ReferenceCount = 1;
+
+ *MacBindingHandle = (NDIS_HANDLE)NewOpen;
+
+ MLID_DO_DEFERRED(Adapter);
+
+ IF_LOUD( DbgPrint("Out Open Adapter\n");)
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+#ifdef NDIS_WIN
+ #ifndef DEBUG
+ #pragma code_seg ()
+ #endif
+#endif
+
+
+VOID
+MlidAdjustMaxLookAhead(
+ IN PMLID_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine finds the open with the maximum lookahead value and
+ stores that in the adapter block.
+
+ NOTE: THIS ROUTINE MUST BE CALLED WITH THE SPINLOCK HELD.
+
+Arguments:
+
+ Adapter - A pointer to the adapter block.
+
+Returns:
+
+ None.
+
+--*/
+{
+ ULONG CurrentMax = 0;
+ PMLID_OPEN CurrentOpen;
+
+ CurrentOpen = Adapter->OpenQueue;
+
+ while (CurrentOpen != NULL) {
+
+ if (CurrentOpen->LookAhead > CurrentMax) {
+
+ CurrentMax = CurrentOpen->LookAhead;
+
+ }
+
+ CurrentOpen = CurrentOpen->NextOpen;
+ }
+
+ if (CurrentMax == 0) {
+
+ CurrentMax = MLID_MAX_LOOKAHEAD;
+
+ }
+
+ Adapter->MaxLookAhead = CurrentMax;
+
+}
+
+NDIS_STATUS
+MlidCloseAdapter(
+ IN NDIS_HANDLE MacBindingHandle
+ )
+
+/*++
+
+Routine Description:
+
+ NDIS function. Unlinks the open block and frees it.
+
+Arguments:
+
+ See NDIS 3.0 spec.
+
+--*/
+
+{
+ PMLID_OPEN Open = ((PMLID_OPEN)MacBindingHandle);
+ PMLID_ADAPTER Adapter = Open->Adapter;
+ PMLID_OPEN TmpOpen;
+ NDIS_STATUS StatusToReturn;
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ if (Open->Closing) {
+
+ //
+ // The open is already being closed.
+ //
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ return NDIS_STATUS_CLOSING;
+ }
+
+ Adapter->References++;
+
+ Open->ReferenceCount++;
+
+ //
+ // Remove this open from the list for this adapter.
+ //
+
+ if (Open == Adapter->OpenQueue) {
+
+ Adapter->OpenQueue = Open->NextOpen;
+
+ } else {
+
+ TmpOpen = Adapter->OpenQueue;
+
+ while (TmpOpen->NextOpen != Open) {
+
+ TmpOpen = TmpOpen->NextOpen;
+
+ }
+
+ TmpOpen->NextOpen = Open->NextOpen;
+ }
+
+
+
+ //
+ // Remove from Filter package to block all receives.
+ //
+
+ if (Adapter->TokenRing) {
+
+ //*\\ token ring
+
+ } else {
+
+ StatusToReturn = EthDeleteFilterOpenAdapter(
+ Adapter->FilterDB,
+ Open->NdisFilterHandle,
+ NULL
+ );
+
+ }
+
+
+ //
+ // If the status is successful that merely implies that
+ // we were able to delete the reference to the open binding
+ // from the filtering code. If we have a successful status
+ // at this point we still need to check whether the reference
+ // count to determine whether we can close.
+ //
+ //
+ // The delete filter routine can return a "special" status
+ // that indicates that there is a current NdisIndicateReceive
+ // on this binding. See below.
+ //
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS) {
+
+ //
+ // Check whether the reference count is two. If
+ // it is then we can get rid of the memory for
+ // this open.
+ //
+ // A count of two indicates one for this routine
+ // and one for the filter which we *know* we can
+ // get rid of.
+ //
+
+ if (Open->ReferenceCount != 2) {
+
+ //
+ // We are not the only reference to the open. Remove
+ // it from the open list and delete the memory.
+ //
+
+
+ Open->Closing = TRUE;
+
+ //
+ // Account for this routines reference to the open
+ // as well as reference because of the original open.
+ //
+
+ Open->ReferenceCount -= 2;
+
+ //
+ // Change the status to indicate that we will
+ // be closing this later.
+ //
+
+ StatusToReturn = NDIS_STATUS_PENDING;
+
+ } else {
+
+ Open->ReferenceCount -= 2;
+
+ }
+
+ } else if (StatusToReturn == NDIS_STATUS_PENDING) {
+
+ Open->Closing = TRUE;
+
+ //
+ // Account for this routines reference to the open
+ // as well as reference because of the original open.
+ //
+
+ Open->ReferenceCount -= 2;
+
+ } else if (StatusToReturn == NDIS_STATUS_CLOSING_INDICATING) {
+
+ //
+ // When we have this status it indicates that the filtering
+ // code was currently doing an NdisIndicateReceive. It
+ // would not be wise to delete the memory for the open at
+ // this point. The filtering code will call our close action
+ // routine upon return from NdisIndicateReceive and that
+ // action routine will decrement the reference count for
+ // the open.
+ //
+
+ Open->Closing = TRUE;
+
+ //
+ // This status is private to the filtering routine. Just
+ // tell the caller the the close is pending.
+ //
+
+ StatusToReturn = NDIS_STATUS_PENDING;
+
+ //
+ // Account for this routines reference to the open.
+ //
+
+ Open->ReferenceCount--;
+
+ } else {
+
+ //
+ // Account for this routines reference to the open.
+ //
+
+ Open->ReferenceCount--;
+
+ }
+
+ //
+ // See if this is the last reference to this open.
+ //
+
+ if (Open->ReferenceCount == 0) {
+
+ //
+ // Check if the MaxLookAhead needs adjustment.
+ //
+
+ if (Open->LookAhead == Adapter->MaxLookAhead) {
+
+ MlidAdjustMaxLookAhead(Adapter);
+
+ }
+
+
+ if (Adapter->OpenQueue == NULL) {
+
+ //
+ // We can disable the card.
+ //
+
+ if (NdisSynchronizeWithInterrupt(
+ &(Adapter->NdisInterrupt),
+ (PVOID)MlidSyncCloseAdapter,
+ (PVOID)(&(Adapter->LMAdapter))
+ ) == FALSE) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 0
+ );
+
+ IF_LOUD( DbgPrint("CloseAdapter FAILED!\n");)
+
+ } else {
+
+
+ IF_LOUD( DbgPrint("CloseAdapter Success!\n");)
+
+ }
+
+ }
+
+ } else {
+
+ //
+ // Will get removed when count drops to zero.
+ //
+
+ StatusToReturn = NDIS_STATUS_PENDING;
+
+ }
+
+
+ MLID_DO_DEFERRED(Adapter);
+
+ return(StatusToReturn);
+
+}
+
+NDIS_STATUS
+MlidRequest(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allows a protocol to query and set information
+ about the MAC.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to PMLID_OPEN.
+
+ NdisRequest - A structure which contains the request type (Set or
+ Query), an array of operations to perform, and an array for holding
+ the results of the operations.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ PMLID_OPEN Open = (PMLID_OPEN)(MacBindingHandle);
+ PMLID_ADAPTER Adapter = (Open->Adapter);
+
+
+ IF_LOUD( DbgPrint("In Request\n");)
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ //
+ // Ensure that the open does not close while in this function.
+ //
+
+ Open->ReferenceCount++;
+
+ Adapter->References++;
+
+ //
+ // Process request
+ //
+
+ if (Open->Closing) {
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ StatusToReturn = NDIS_STATUS_CLOSING;
+
+ } else if (NdisRequest->RequestType == NdisRequestQueryInformation) {
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ StatusToReturn = MlidQueryInformation(Adapter, Open, NdisRequest);
+
+ } else if (NdisRequest->RequestType == NdisRequestSetInformation) {
+
+ if (Adapter->HardwareFailure) {
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ StatusToReturn = NDIS_STATUS_FAILURE;
+
+ } else {
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ StatusToReturn = MlidSetInformation(Adapter,Open,NdisRequest);
+
+ }
+
+ } else {
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ StatusToReturn = NDIS_STATUS_NOT_RECOGNIZED;
+
+ }
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ MlidRemoveReference(Open);
+
+ MLID_DO_DEFERRED(Adapter);
+
+ IF_LOUD( DbgPrint("Out Request\n");)
+
+ return(StatusToReturn);
+
+}
+
+NDIS_STATUS
+MlidQueryProtocolInformation(
+ IN PMLID_ADAPTER Adapter,
+ IN PMLID_OPEN Open,
+ IN NDIS_OID Oid,
+ IN BOOLEAN GlobalMode,
+ IN PVOID InfoBuffer,
+ IN UINT BytesLeft,
+ OUT PUINT BytesNeeded,
+ OUT PUINT BytesWritten
+)
+
+/*++
+
+Routine Description:
+
+ The MlidQueryProtocolInformation process a Query request for
+ NDIS_OIDs that are specific to a binding about the MAC. Note that
+ some of the OIDs that are specific to bindings are also queryable
+ on a global basis. Rather than recreate this code to handle the
+ global queries, I use a flag to indicate if this is a query for the
+ global data or the binding specific data.
+
+Arguments:
+
+ Adapter - a pointer to the adapter.
+
+ Open - a pointer to the open instance.
+
+ Oid - the NDIS_OID to process.
+
+ GlobalMode - Some of the binding specific information is also used
+ when querying global statistics. This is a flag to specify whether
+ to return the global value, or the binding specific value.
+
+ PlaceInInfoBuffer - a pointer into the NdisRequest->InformationBuffer
+ into which store the result of the query.
+
+ BytesLeft - the number of bytes left in the InformationBuffer.
+
+ BytesNeeded - If there is not enough room in the information buffer
+ then this will contain the number of bytes needed to complete the
+ request.
+
+ BytesWritten - a pointer to the number of bytes written into the
+ InformationBuffer.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NDIS_MEDIUM Medium = NdisMedium802_3;
+ ULONG GenericULong;
+ USHORT GenericUShort;
+ UCHAR GenericArray[6];
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ //
+ // Common variables for pointing to result of query
+ //
+
+ PVOID MoveSource = (PVOID)(&GenericULong);
+ ULONG MoveBytes = sizeof(ULONG);
+
+ NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady;
+
+ //
+ // General Algorithm:
+ //
+ // Switch(Request)
+ // Get requested information
+ // Store results in a common variable.
+ // Copy result in common variable to result buffer.
+ //
+
+ //
+ // Make sure that ulong is 4 bytes. Else GenericULong must change
+ // to something of size 4.
+ //
+ ASSERT(sizeof(ULONG) == 4);
+
+
+ IF_LOUD( DbgPrint("In QueryProtocol\n");)
+
+ //
+ // Make sure no changes occur while processing.
+ //
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ //
+ // Switch on request type
+ //
+
+ switch (Oid) {
+
+ case OID_GEN_MAC_OPTIONS:
+
+ GenericULong = (ULONG)(NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
+ NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
+ NDIS_MAC_OPTION_NO_LOOPBACK
+ );
+
+ break;
+
+ case OID_GEN_SUPPORTED_LIST:
+
+ if (Adapter->TokenRing) {
+
+ //*\\ token ring
+
+ break;
+ }
+
+ if (!GlobalMode) {
+
+ MoveSource = (PVOID)(MlidProtocolSupportedOids);
+ MoveBytes = sizeof(MlidProtocolSupportedOids);
+
+ } else {
+
+ MoveSource = (PVOID)(MlidGlobalSupportedOids);
+ MoveBytes = sizeof(MlidGlobalSupportedOids);
+
+ }
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+
+ if (Adapter->HardwareFailure) {
+
+ HardwareStatus = NdisHardwareStatusNotReady;
+
+ } else {
+
+ HardwareStatus = NdisHardwareStatusReady;
+
+ }
+
+ MoveSource = (PVOID)(&HardwareStatus);
+ MoveBytes = sizeof(NDIS_HARDWARE_STATUS);
+
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+
+ if (Adapter->TokenRing) {
+
+ Medium = NdisMedium802_5;
+
+ }
+
+ MoveSource = (PVOID) (&Medium);
+ MoveBytes = sizeof(NDIS_MEDIUM);
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+
+ GenericULong = MLID_MAX_LOOKAHEAD;
+
+ break;
+
+
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+
+ if (Adapter->TokenRing) {
+
+ GenericULong = Adapter->xmit_buf_size - MLID_HEADER_SIZE;
+
+ } else {
+
+ GenericULong = (ULONG)(MLID_MAX_PACKET_SIZE - MLID_HEADER_SIZE);
+
+ }
+
+ break;
+
+
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+
+ if (Adapter->TokenRing) {
+
+ GenericULong = Adapter->xmit_buf_size;
+
+ } else {
+
+ GenericULong = (ULONG)(MLID_MAX_PACKET_SIZE);
+
+ }
+
+ break;
+
+
+ case OID_GEN_LINK_SPEED:
+
+ if (Adapter->TokenRing) {
+
+ if ((Adapter->media_type & MEDIA_UTP_16) ||
+ (Adapter->media_type & MEDIA_STP_16)) {
+
+ GenericULong = 160000;
+
+ } else {
+
+ GenericULong = 40000;
+
+ }
+
+ } else {
+
+ GenericULong = (ULONG)(100000);
+
+ }
+
+ break;
+
+
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+
+ GenericULong = (ULONG)(Adapter->num_of_tx_buffs
+ * Adapter->xmit_buf_size);
+
+ break;
+
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+
+ GenericULong = (ULONG)((Adapter->ram_size * 1024) -
+ (Adapter->num_of_tx_buffs
+ * Adapter->xmit_buf_size));
+
+ break;
+
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+
+ GenericULong = (ULONG)(Adapter->buffer_page_size);
+
+ break;
+
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+
+ GenericULong = (ULONG)(Adapter->buffer_page_size);
+
+ break;
+
+ case OID_GEN_VENDOR_ID:
+
+ NdisMoveMemory(
+ (PVOID)&GenericULong,
+ Adapter->permanent_node_address,
+ 3
+ );
+ GenericULong &= 0xFFFFFF00;
+ MoveSource = (PVOID)(&GenericULong);
+ MoveBytes = sizeof(GenericULong);
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+
+ MoveSource = (PVOID)"SMC Adapter.";
+ MoveBytes = 13;
+
+ break;
+
+ case OID_GEN_DRIVER_VERSION:
+
+ GenericUShort = ((USHORT)MLID_NDIS_MAJOR_VERSION << 8) |
+ MLID_NDIS_MINOR_VERSION;
+
+ MoveSource = (PVOID)(&GenericUShort);
+ MoveBytes = sizeof(GenericUShort);
+ break;
+
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ if (Adapter->TokenRing) {
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+
+ //*\\ token ring
+
+ break;
+ }
+
+ if (GlobalMode) {
+
+ UINT Filter;
+
+ Filter = ETH_QUERY_FILTER_CLASSES(Adapter->FilterDB);
+
+ GenericULong = (ULONG)(Filter);
+
+ } else {
+
+ UINT Filter = 0;
+
+ Filter = ETH_QUERY_PACKET_FILTER(Adapter->FilterDB,
+ Open->NdisFilterHandle);
+
+ GenericULong = (ULONG)(Filter);
+
+ }
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ if ( GlobalMode ) {
+
+ GenericULong = (ULONG)(Adapter->MaxLookAhead);
+
+ } else {
+
+ GenericULong = Open->LookAhead;
+
+ }
+
+ break;
+
+ case OID_802_3_PERMANENT_ADDRESS:
+
+ if (Adapter->TokenRing) {
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ MLID_MOVE_MEM((PCHAR)GenericArray,
+ Adapter->permanent_node_address,
+ ETH_LENGTH_OF_ADDRESS);
+
+ MoveSource = (PVOID)(GenericArray);
+ MoveBytes = sizeof(Adapter->permanent_node_address);
+ break;
+
+ case OID_802_3_CURRENT_ADDRESS:
+
+ if (Adapter->TokenRing) {
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ MLID_MOVE_MEM((PCHAR)GenericArray,
+ Adapter->node_address,
+ ETH_LENGTH_OF_ADDRESS);
+
+ MoveSource = (PVOID)(GenericArray);
+ MoveBytes = sizeof(Adapter->node_address);
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+
+ if (Adapter->TokenRing) {
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+
+ break;
+ }
+
+ {
+ UINT NumAddresses;
+
+
+ if (GlobalMode) {
+
+ NumAddresses = ETH_NUMBER_OF_GLOBAL_FILTER_ADDRESSES(Adapter->FilterDB);
+
+ if ((NumAddresses * ETH_LENGTH_OF_ADDRESS) > BytesLeft) {
+
+ *BytesNeeded = (NumAddresses * ETH_LENGTH_OF_ADDRESS);
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ break;
+
+ }
+
+ EthQueryGlobalFilterAddresses(
+ &StatusToReturn,
+ Adapter->FilterDB,
+ BytesLeft,
+ &NumAddresses,
+ InfoBuffer
+ );
+
+ *BytesWritten = NumAddresses * ETH_LENGTH_OF_ADDRESS;
+
+ //
+ // Should not be an error since we held the spinlock
+ // nothing should have changed.
+ //
+
+ ASSERT(StatusToReturn == NDIS_STATUS_SUCCESS);
+
+ } else {
+
+ NumAddresses = EthNumberOfOpenFilterAddresses(
+ Adapter->FilterDB,
+ Open->NdisFilterHandle
+ );
+
+ if ((NumAddresses * ETH_LENGTH_OF_ADDRESS) > BytesLeft) {
+
+ *BytesNeeded = (NumAddresses * ETH_LENGTH_OF_ADDRESS);
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ break;
+
+ }
+
+ EthQueryOpenFilterAddresses(
+ &StatusToReturn,
+ Adapter->FilterDB,
+ Open->NdisFilterHandle,
+ BytesLeft,
+ &NumAddresses,
+ InfoBuffer
+ );
+
+ //
+ // Should not be an error since we held the spinlock
+ // nothing should have changed.
+ //
+
+ ASSERT(StatusToReturn == NDIS_STATUS_SUCCESS);
+
+ *BytesWritten = NumAddresses * ETH_LENGTH_OF_ADDRESS;
+
+ }
+
+ }
+
+
+
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+
+ if (Adapter->TokenRing) {
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ GenericULong = (ULONG) (Adapter->MulticastListMax);
+
+ break;
+
+
+
+ default:
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if ((StatusToReturn == NDIS_STATUS_SUCCESS) &&
+ (Oid != OID_802_3_MULTICAST_LIST)) {
+
+ if (MoveBytes > BytesLeft) {
+
+ //
+ // Not enough room in InformationBuffer. Punt
+ //
+
+ *BytesNeeded = MoveBytes - BytesLeft;
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ } else {
+
+ //
+ // Store result.
+ //
+
+ MLID_MOVE_MEM(InfoBuffer, MoveSource, MoveBytes);
+
+ (*BytesWritten) += MoveBytes;
+
+ }
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ IF_LOUD( DbgPrint("Out QueryProtocol\n");)
+
+ return(StatusToReturn);
+}
+
+NDIS_STATUS
+MlidQueryInformation(
+ IN PMLID_ADAPTER Adapter,
+ IN PMLID_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest
+ )
+/*++
+
+Routine Description:
+
+ The MlidQueryInformation is used by MlidRequest to query information
+ about the MAC.
+
+Arguments:
+
+ Adapter - A pointer to the adapter.
+
+ Open - A pointer to a particular open instance.
+
+ NdisRequest - A structure which contains the request type (Query),
+ an array of operations to perform, and an array for holding
+ the results of the operations.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+ UINT BytesWritten = 0;
+ UINT BytesNeeded = 0;
+ UINT BytesLeft = NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength;
+ PUCHAR InfoBuffer = (PUCHAR)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+
+ IF_LOUD( DbgPrint("In QueryInfor\n");)
+
+ StatusToReturn = MlidQueryProtocolInformation(
+ Adapter,
+ Open,
+ NdisRequest->DATA.QUERY_INFORMATION.Oid,
+ FALSE,
+ InfoBuffer,
+ BytesLeft,
+ &BytesNeeded,
+ &BytesWritten
+ );
+
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesWritten = BytesWritten;
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = BytesNeeded;
+
+ IF_LOUD( DbgPrint("Out QueryInfor\n");)
+
+ return(StatusToReturn);
+}
+
+NDIS_STATUS
+MlidSetInformation(
+ IN PMLID_ADAPTER Adapter,
+ IN PMLID_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest
+ )
+/*++
+
+Routine Description:
+
+ The MlidSetInformation is used by MlidRequest to set information
+ about the MAC.
+
+Arguments:
+
+ Adapter - A pointer to the adapter.
+
+ Open - A pointer to an open instance.
+
+ NdisRequest - A structure which contains the request type (Set),
+ an array of operations to perform, and an array for holding
+ the results of the operations.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+ //
+ // General Algorithm:
+ //
+ // Verify length
+ // Switch(Request)
+ // Process Request
+ //
+
+ UINT BytesRead = 0;
+ UINT BytesNeeded = 0;
+ UINT BytesLeft = NdisRequest->DATA.SET_INFORMATION.InformationBufferLength;
+ PUCHAR InfoBuffer = (PUCHAR)(NdisRequest->DATA.SET_INFORMATION.InformationBuffer);
+
+ //
+ // Variables for a particular request
+ //
+
+ NDIS_OID Oid;
+ UINT OidLength;
+
+ //
+ // Variables for holding the new values to be used.
+ //
+
+ ULONG LookAhead;
+ ULONG Filter;
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+
+ IF_LOUD( DbgPrint("In SetInfo\n");)
+
+
+
+ //
+ // Get Oid and Length of request
+ //
+
+ Oid = NdisRequest->DATA.SET_INFORMATION.Oid;
+
+ OidLength = BytesLeft;
+
+ switch (Oid) {
+
+
+ case OID_802_3_MULTICAST_LIST:
+
+ if (Adapter->TokenRing) {
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ //
+ // Verify length
+ //
+
+ if ((OidLength % ETH_LENGTH_OF_ADDRESS) != 0){
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ break;
+
+ }
+
+ StatusToReturn = MlidSetMulticastAddresses(
+ Adapter,
+ Open,
+ NdisRequest,
+ (UINT)(OidLength / ETH_LENGTH_OF_ADDRESS),
+ (PVOID)InfoBuffer
+ );
+ break;
+
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ if (Adapter->TokenRing) {
+
+ //*\\ token ring
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+
+ //
+ // Verify length
+ //
+
+ if (OidLength != 4 ) {
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ break;
+
+ }
+
+
+ MLID_MOVE_MEM(&Filter, InfoBuffer, 4);
+
+ //
+ // Verify bits
+ //
+
+ if (Filter & (NDIS_PACKET_TYPE_SOURCE_ROUTING |
+ NDIS_PACKET_TYPE_SMT |
+ NDIS_PACKET_TYPE_MAC_FRAME |
+ NDIS_PACKET_TYPE_FUNCTIONAL |
+ NDIS_PACKET_TYPE_ALL_FUNCTIONAL |
+ NDIS_PACKET_TYPE_GROUP
+ )) {
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 4;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ break;
+
+ }
+
+ StatusToReturn = MlidSetPacketFilter(Adapter,
+ Open,
+ NdisRequest,
+ Filter
+ );
+
+
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ //
+ // Verify length
+ //
+
+ if (OidLength != 4) {
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ break;
+
+ }
+
+ MLID_MOVE_MEM(&LookAhead, InfoBuffer, 4);
+
+ if (LookAhead <= (MLID_MAX_LOOKAHEAD)) {
+
+ if (LookAhead > Adapter->MaxLookAhead) {
+
+ Adapter->MaxLookAhead = LookAhead;
+
+ Open->LookAhead = LookAhead;
+
+ } else {
+
+ if ((Open->LookAhead == Adapter->MaxLookAhead) &&
+ (LookAhead < Open->LookAhead)) {
+
+ Open->LookAhead = LookAhead;
+
+ MlidAdjustMaxLookAhead(Adapter);
+
+ } else {
+
+ Open->LookAhead = LookAhead;
+
+ }
+
+ }
+
+
+ } else {
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ }
+
+ break;
+
+ case OID_GEN_PROTOCOL_OPTIONS:
+
+ //
+ // Verify length
+ //
+
+ if (OidLength != 4) {
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ break;
+
+ }
+
+ MLID_MOVE_MEM(&Open->ProtOptionFlags, InfoBuffer, 4);
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ break;
+
+ default:
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ break;
+
+ }
+
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS) {
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = BytesLeft;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ }
+
+
+ IF_LOUD( DbgPrint("Out SetInfo\n");)
+
+ return(StatusToReturn);
+}
+
+
+STATIC
+NDIS_STATUS
+MlidSetPacketFilter(
+ IN PMLID_ADAPTER Adapter,
+ IN PMLID_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT PacketFilter
+ )
+
+/*++
+
+Routine Description:
+
+ The MlidSetPacketFilter request allows a protocol to control the types
+ of packets that it receives from the MAC.
+
+Arguments:
+
+ Adapter - A pointer to the adapter structure.
+
+ Open - A pointer to the open block giving the request.
+
+ NdisRequest - The NDIS_REQUEST with the set packet filter command in it.
+
+ PacketFilter - A bit mask that contains flags that correspond to specific
+ classes of received packets. If a particular bit is set in the mask,
+ then packet reception for that class of packet is enabled. If the
+ bit is clear, then packets that fall into that class are not received
+ by the client. A single exception to this rule is that if the promiscuous
+ bit is set, then the client receives all packets on the network, regardless
+ of the state of the other flags.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ //
+ // Keeps track of the *MAC's* status. The status will only be
+ // reset if the filter change action routine is called.
+ //
+ NDIS_STATUS StatusOfFilterChange = NDIS_STATUS_SUCCESS;
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ IF_LOUD( DbgPrint("In SetFilter\n");)
+
+ if (!Open->Closing) {
+
+ //
+ // Increment the open while it is going through the filtering
+ // routines.
+ //
+
+ Open->ReferenceCount++;
+
+ StatusOfFilterChange = EthFilterAdjust(
+ Adapter->FilterDB,
+ Open->NdisFilterHandle,
+ NdisRequest,
+ PacketFilter,
+ TRUE
+ );
+
+ Open->ReferenceCount--;
+
+ } else {
+
+ StatusOfFilterChange = NDIS_STATUS_CLOSING;
+
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ IF_LOUD( DbgPrint("Out SetFilter\n");)
+
+ return StatusOfFilterChange;
+}
+
+
+
+
+STATIC
+NDIS_STATUS
+MlidSetMulticastAddresses(
+ IN PMLID_ADAPTER Adapter,
+ IN PMLID_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT NumAddresses,
+ IN CHAR AddressList[][ETH_LENGTH_OF_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ This function calls into the filter package in order to set the
+ multicast address list for the card to the specified list.
+
+Arguments:
+
+ Adapter - A pointer to the adapter block.
+
+ Open - A pointer to the open block submitting the request.
+
+ NdisRequest - The NDIS_REQUEST with the set multicast address list command
+ in it.
+
+ NumAddresses - A count of the number of addresses in the addressList.
+
+ AddressList - An array of multicast addresses that this open instance
+ wishes to accept.
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+ //
+ // Keeps track of the *MAC's* status. The status will only be
+ // reset if the filter change action routine is called.
+ //
+ NDIS_STATUS StatusOfFilterChange = NDIS_STATUS_SUCCESS;
+
+ IF_LOUD( DbgPrint("In SetMulticast\n");)
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ if (!Open->Closing) {
+
+ //
+ // Increment the open while it is going through the filtering
+ // routines.
+ //
+
+ Open->ReferenceCount++;
+
+ StatusOfFilterChange = EthChangeFilterAddresses(
+ Adapter->FilterDB,
+ Open->NdisFilterHandle,
+ NdisRequest,
+ NumAddresses,
+ AddressList,
+ TRUE
+ );
+ Open->ReferenceCount--;
+
+ } else {
+
+ StatusOfFilterChange = NDIS_STATUS_CLOSING;
+
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ IF_LOUD( DbgPrint("Out SetMulticast\n");)
+
+ return StatusOfFilterChange;
+}
+
+
+
+NDIS_STATUS
+MlidFillInGlobalData(
+ IN PMLID_ADAPTER Adapter,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ This routine completes a GlobalStatistics request. It is critical that
+ if information is needed from the Adapter->* fields, they have been
+ updated before this routine is called.
+
+Arguments:
+
+ Adapter - A pointer to the Adapter.
+
+ NdisRequest - A structure which contains the request type (Global
+ Query), an array of operations to perform, and an array for holding
+ the results of the operations.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ //
+ // General Algorithm:
+ //
+ // Switch(Request)
+ // Get requested information
+ // Store results in a common variable.
+ // default:
+ // Try protocol query information
+ // If that fails, fail query.
+ //
+ // Copy result in common variable to result buffer.
+ // Finish processing
+
+ UINT BytesWritten = 0;
+ UINT BytesNeeded = 0;
+ UINT BytesLeft = NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength;
+ PUCHAR InfoBuffer = (PUCHAR)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ //
+ // This variable holds result of query
+ //
+
+ ULONG GenericULong;
+
+ //
+ // Make sure that long is 4 bytes. Else GenericULong must change
+ // to something of size 4.
+ //
+ ASSERT(sizeof(ULONG) == 4);
+
+
+ StatusToReturn = MlidQueryProtocolInformation(
+ Adapter,
+ NULL,
+ NdisRequest->DATA.QUERY_INFORMATION.Oid,
+ TRUE,
+ InfoBuffer,
+ BytesLeft,
+ &BytesNeeded,
+ &BytesWritten
+ );
+
+
+ if (StatusToReturn == NDIS_STATUS_NOT_SUPPORTED) {
+
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ //
+ // Switch on request type
+ //
+
+ switch (NdisRequest->DATA.QUERY_INFORMATION.Oid) {
+
+ case OID_GEN_XMIT_OK:
+
+ GenericULong = (ULONG)(Adapter->FramesXmitGood);
+
+ break;
+
+ case OID_GEN_RCV_OK:
+
+ GenericULong = (ULONG)(Adapter->FramesRcvGood);
+
+ break;
+
+ case OID_GEN_XMIT_ERROR:
+
+ GenericULong = (ULONG)(Adapter->FramesXmitBad);
+
+ break;
+
+ case OID_GEN_RCV_ERROR:
+
+ if (Adapter->TokenRing) {
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ GenericULong = (ULONG)(Adapter->CrcErrors);
+
+ break;
+
+ case OID_GEN_RCV_NO_BUFFER:
+
+ if (Adapter->TokenRing) {
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ GenericULong = (ULONG)(Adapter->MissedPackets);
+
+ break;
+
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+
+ if (Adapter->TokenRing) {
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ GenericULong = (ULONG)(Adapter->FrameAlignmentErrors);
+
+ break;
+
+ case OID_802_3_XMIT_ONE_COLLISION:
+
+ if (Adapter->TokenRing) {
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ GenericULong = (ULONG)(Adapter->FramesXmitOneCollision);
+
+ break;
+
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+
+ if (Adapter->TokenRing) {
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ GenericULong = (ULONG)(Adapter->FramesXmitManyCollisions);
+
+ break;
+
+
+ default:
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+
+ break;
+
+ }
+
+
+ //
+ // Check to make sure there is enough room in the
+ // buffer to store the result.
+ //
+
+ if (BytesLeft >= sizeof(ULONG)) {
+
+ //
+ // Store the result.
+ //
+
+ MLID_MOVE_MEM(
+ (PVOID)InfoBuffer,
+ (PVOID)(&GenericULong),
+ sizeof(ULONG)
+ );
+
+ BytesWritten += sizeof(ULONG);
+
+ }
+
+ }
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesWritten = BytesWritten;
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = BytesNeeded;
+
+ return(StatusToReturn);
+}
+
+NDIS_STATUS
+MlidQueryGlobalStatistics(
+ IN NDIS_HANDLE MacAdapterContext,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ The MlidQueryGlobalStatistics is used by the protocol to query
+ global information about the MAC.
+
+Arguments:
+
+ MacAdapterContext - The value associated with the adapter that is being
+ opened when the MAC registered the adapter with NdisRegisterAdapter.
+
+ NdisRequest - A structure which contains the request type (Query),
+ an array of operations to perform, and an array for holding
+ the results of the operations.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+ //
+ // General Algorithm:
+ //
+ //
+ // Check if a request is going to pend...
+ // If so, pend the entire operation.
+ //
+ // Else
+ // Fill in the request block.
+ //
+ //
+
+ PMLID_ADAPTER Adapter = (PMLID_ADAPTER)(MacAdapterContext);
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ //
+ // Check if a request is valid and going to pend...
+ // If so, pend the entire operation.
+ //
+
+
+ //
+ // Switch on request type
+ //
+
+ switch (NdisRequest->DATA.QUERY_INFORMATION.Oid) {
+ case OID_GEN_SUPPORTED_LIST:
+ case OID_GEN_HARDWARE_STATUS:
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+ case OID_GEN_MAC_OPTIONS:
+ case OID_GEN_LINK_SPEED:
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+ case OID_GEN_VENDOR_ID:
+ case OID_GEN_VENDOR_DESCRIPTION:
+ case OID_GEN_DRIVER_VERSION:
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ case OID_GEN_XMIT_OK:
+ case OID_GEN_RCV_OK:
+ case OID_GEN_XMIT_ERROR:
+ case OID_GEN_RCV_ERROR:
+
+ break;
+
+ case OID_802_3_PERMANENT_ADDRESS:
+ case OID_802_3_CURRENT_ADDRESS:
+ case OID_GEN_RCV_NO_BUFFER:
+ case OID_802_3_MULTICAST_LIST:
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+ case OID_802_3_XMIT_ONE_COLLISION:
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+
+ if (Adapter->TokenRing) {
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+
+ }
+ break;
+
+ default:
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+
+ break;
+ }
+
+ NdisInterlockedAddUlong(&Adapter->References, 1, &Adapter->Lock);
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS) {
+
+ StatusToReturn = MlidFillInGlobalData(Adapter, NdisRequest);
+
+ }
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ MLID_DO_DEFERRED(Adapter);
+
+ return(StatusToReturn);
+}
+
+
+VOID
+MlidRemoveAdapter(
+ IN PVOID MacAdapterContext
+ )
+/*++
+
+Routine Description:
+
+ MlidRemoveAdapter removes an adapter previously registered
+ with NdisRegisterAdapter.
+
+Arguments:
+
+ MacAdapterContext - The context value that the MAC passed
+ to NdisRegisterAdapter; actually as pointer to an
+ MLID_ADAPTER.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PMLID_ADAPTER Adapter;
+ BOOLEAN Canceled;
+
+ Adapter = PMLID_ADAPTER_FROM_CONTEXT_HANDLE(MacAdapterContext);
+
+ LM_Free_Resources(&Adapter->LMAdapter);
+
+ ASSERT(Adapter->OpenQueue == (PMLID_OPEN)NULL);
+
+ //
+ // There are no opens left, so remove ourselves.
+ //
+
+ NdisCancelTimer(&Adapter->WakeUpTimer, &Canceled);
+
+ if ( !Canceled ) {
+ NdisStallExecution(500000);
+ }
+
+ //
+ // Take us out of the AdapterQueue.
+ //
+
+ NdisAcquireSpinLock(&MlidMacBlock.SpinLock);
+
+ Adapter->Removed = TRUE;
+
+ if (MlidMacBlock.AdapterQueue == Adapter) {
+
+ MlidMacBlock.AdapterQueue = Adapter->NextAdapter;
+
+ } else {
+
+ PMLID_ADAPTER TmpAdaptP = MlidMacBlock.AdapterQueue;
+
+ while (TmpAdaptP->NextAdapter != Adapter) {
+
+ TmpAdaptP = TmpAdaptP->NextAdapter;
+
+ }
+
+ TmpAdaptP->NextAdapter = TmpAdaptP->NextAdapter->NextAdapter;
+ }
+
+ NdisReleaseSpinLock(&MlidMacBlock.SpinLock);
+
+ NdisRemoveInterrupt(&(Adapter->NdisInterrupt));
+
+ NdisUnmapIoSpace(
+ Adapter->NdisAdapterHandle,
+ Adapter->ram_access,
+ Adapter->ram_size * 1024);
+
+ if (Adapter->TokenRing) {
+
+ //*\\ token ring
+
+ } else {
+
+ EthDeleteFilter(Adapter->FilterDB);
+
+ }
+
+ NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
+
+ NdisFreeSpinLock(&Adapter->Lock);
+
+ NdisFreeMemory(Adapter, sizeof(MLID_ADAPTER), 0);
+
+ return;
+}
+
+VOID
+MlidUnload(
+ IN NDIS_HANDLE MacMacContext
+ )
+
+/*++
+
+Routine Description:
+
+ MlidUnload is called when the MAC is to unload itself.
+
+Arguments:
+
+ MacMacContext - actually a pointer to MlidMacBlock.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS InitStatus;
+
+ UNREFERENCED_PARAMETER(MacMacContext);
+
+ NdisDeregisterMac(
+ &InitStatus,
+ MlidMacBlock.NdisMacHandle
+ );
+
+ NdisFreeSpinLock(&MlidMacBlock.SpinLock);
+
+ NdisTerminateWrapper(
+ MlidMacBlock.NdisWrapperHandle,
+ NULL
+ );
+
+ return;
+}
+
+NDIS_STATUS
+MlidSend(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+ NDIS function. Sends a packet on the wire
+
+Arguments:
+
+ See NDIS 3.0 spec.
+
+--*/
+
+{
+ PMLID_OPEN Open = PMLID_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+ PMLID_ADAPTER Adapter = Open->Adapter;
+ PMAC_RESERVED Reserved = RESERVED(Packet);
+ UINT PacketLength;
+ NDIS_STATUS Status;
+
+
+ //
+ // Check that the packet is not too short or too long.
+ //
+
+ NdisQueryPacket(Packet, NULL, NULL, NULL, &PacketLength);
+
+ if (PacketLength < (ETH_LENGTH_OF_ADDRESS*2) || PacketLength > 1514) {
+
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+
+
+
+ if (Adapter->HardwareFailure) {
+
+ return(NDIS_STATUS_FAILURE);
+
+ }
+
+ if (Adapter->ResetInProgress) {
+
+ return(NDIS_STATUS_RESET_IN_PROGRESS);
+
+ }
+
+ //
+ // Ensure that the open won't close during this function.
+ //
+
+ if (Open->Closing) {
+
+ return NDIS_STATUS_CLOSING;
+
+ }
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ IF_LOG(LOG('s'));
+
+ Open->ReferenceCount++;
+
+ Adapter->References++;
+
+ //
+ // Set up the MacReserved section of the packet.
+ //
+
+ Reserved->Open = Open;
+
+ Reserved->NextPacket = (PNDIS_PACKET)NULL;
+
+
+
+
+ //
+ // Set Reserved->Loopback
+ //
+
+ MlidSetLoopbackFlag(Adapter, Open, Packet);
+
+
+
+
+ IF_LOUD( DbgPrint("Sending a packet for Open 0x%lx\n", Reserved->Open);)
+
+
+ //
+ // We do not Open->ReferenceCount-- because that will be done when
+ // then send completes.
+ //
+
+
+ if (Reserved->Directed) {
+
+ //
+ // Put it directly on loopback queue.
+ //
+
+ IF_VERY_LOUD( DbgPrint("Putting Packet 0x%lx on Loopback queue\n",Packet);)
+
+ IF_LOG(LOG('l'));
+
+ if (Adapter->LoopbackQueue == NULL) {
+
+ Adapter->LoopbackQueue = Adapter->LoopbackQTail = Packet;
+
+ } else {
+
+ RESERVED(Adapter->LoopbackQTail)->NextPacket = Packet;
+
+ Adapter->LoopbackQTail = Packet;
+
+ }
+
+ Status = NDIS_STATUS_PENDING;
+
+ } else {
+
+ //
+ // Put Packet on queue to hit the wire.
+ //
+
+ if (Adapter->XmitQueue != NULL) {
+
+ IF_LOG(LOG('q'));
+
+ RESERVED(Adapter->XmitQTail)->NextPacket = Packet;
+
+ Adapter->XmitQTail = Packet;
+
+ } else {
+
+ PNDIS_PACKET PreviousTail;
+
+ //
+ // We have to assume it will be sent. In case the send completes
+ // before we have time to add it.
+ //
+
+ if (Adapter->PacketsOnCard == NULL) {
+
+ PreviousTail = NULL;
+
+ Adapter->PacketsOnCard = Adapter->PacketsOnCardTail = Packet;
+
+ } else {
+
+ PreviousTail = Adapter->PacketsOnCardTail;
+
+ RESERVED(Adapter->PacketsOnCardTail)->NextPacket = Packet;
+
+ Adapter->PacketsOnCardTail = Packet;
+
+ }
+
+ IF_LOG(LOG('t'));
+
+ if (LM_Send(Packet, &Adapter->LMAdapter) == OUT_OF_RESOURCES) {
+
+ IF_LOG(LOG('Q'));
+
+ //
+ // Remove it from list of packets on card and add it to xmit
+ // queue.
+ //
+
+ if (PreviousTail == NULL) {
+
+ Adapter->PacketsOnCard = Adapter->PacketsOnCardTail = NULL;
+
+ } else {
+
+ Adapter->PacketsOnCardTail = PreviousTail;
+
+ RESERVED(Adapter->PacketsOnCardTail)->NextPacket = NULL;
+
+ }
+
+ Adapter->XmitQueue = Packet;
+
+ Adapter->XmitQTail = Packet;
+
+ }
+
+ }
+
+ Status = NDIS_STATUS_PENDING;
+
+ }
+
+
+ MLID_DO_DEFERRED(Adapter);
+
+ IF_LOG(LOG('S'));
+
+ return Status;
+
+}
+
+UINT
+MlidCompareMemory(
+ IN PUCHAR String1,
+ IN PUCHAR String2,
+ IN UINT Length
+ )
+/*++
+
+Routine Description:
+
+ Determines if two arrays of bytes are equal.
+
+Arguments:
+
+ String1, String2 - the two arrays to check.
+
+ Length - the first length bytes to compare.
+
+Return Value:
+
+ 0 if equal, -1 if not.
+
+--*/
+{
+ UINT i;
+
+ for (i=0; i<Length; i++) {
+ if (String1[i] != String2[i]) {
+ return (UINT)(-1);
+ }
+ }
+ return 0;
+}
+
+
+NDIS_STATUS
+MlidReset(
+ IN NDIS_HANDLE MacBindingHandle
+ )
+
+/*++
+
+Routine Description:
+
+ NDIS function.
+
+Arguments:
+
+ See NDIS 3.0 spec.
+
+--*/
+
+{
+ PMLID_OPEN Open = ((PMLID_OPEN)MacBindingHandle);
+ PMLID_ADAPTER Adapter = Open->Adapter;
+
+
+ if (Open->Closing) {
+
+ return(NDIS_STATUS_CLOSING);
+
+ }
+
+ if (Adapter->ResetRequested) {
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ IF_LOUD( DbgPrint("In MlidReset\n");)
+
+ IF_LOG(LOG('r'));
+
+ //
+ // Ensure that the open does not close while in this function.
+ //
+
+ Open->ReferenceCount++;
+
+ Adapter->References++;
+
+
+ Adapter->ResetRequested = TRUE;
+
+ //
+ // Needed in case the reset pends somewhere along the line.
+ //
+
+ Adapter->ResetOpen = Open;
+
+ MLID_DO_DEFERRED(Adapter);
+
+ IF_LOUD( DbgPrint("Out MlidReset\n");)
+
+ return(NDIS_STATUS_PENDING);
+
+}
+
+STATIC
+NDIS_STATUS
+MlidChangeMulticastAddresses(
+ IN UINT OldFilterCount,
+ IN CHAR OldAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN UINT NewFilterCount,
+ IN CHAR NewAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when a particular filter
+ class is first used or last cleared.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+
+ OldFilterCount - The number of addresses that used to be on the card.
+
+ OldAddresses - A list of all the addresses that used to be on the card.
+
+ NewFilterCount - The number of addresses that should now be on the card.
+
+ NewAddresses - A list of addresses that should be put on the card.
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to MLID_OPEN.
+
+ NdisRequest - The request which submitted the filter change.
+ Must use when completing this request with the NdisCompleteRequest
+ service, if the MAC completes this request asynchronously.
+
+ Set - If true the change resulted from a set, otherwise the
+ change resulted from a open closing.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+
+
+ PMLID_ADAPTER Adapter = PMLID_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ UNREFERENCED_PARAMETER(Set);
+ UNREFERENCED_PARAMETER(NdisRequest);
+ UNREFERENCED_PARAMETER(OldAddresses);
+ UNREFERENCED_PARAMETER(OldFilterCount);
+
+ if (LM_Set_Multi_Address(NewAddresses, NewFilterCount, &Adapter->LMAdapter)
+ != SUCCESS) {
+
+ return(NDIS_STATUS_FAILURE);
+
+ } else {
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+}
+
+STATIC
+NDIS_STATUS
+MlidChangeFilterClasses(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when an address is added to
+ the filter that wasn't referenced by any other open binding.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ OldFilterClasses - A bit mask that is currently on the card telling
+ which packet types to accept.
+
+ NewFilterClasses - A bit mask that should be put on the card telling
+ which packet types to accept.
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to MLID_OPEN.
+
+ NdisRequest - The NDIS_REQUEST which submitted the filter change command.
+
+ Set - A flag telling if the command is a result of a close or not.
+
+Return Value:
+
+ Status of the change (successful or pending).
+
+
+--*/
+
+{
+
+ PMLID_ADAPTER Adapter = PMLID_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ UNREFERENCED_PARAMETER(Set);
+ UNREFERENCED_PARAMETER(OldFilterClasses);
+ UNREFERENCED_PARAMETER(NewFilterClasses);
+ UNREFERENCED_PARAMETER(NdisRequest);
+
+
+ if (LM_Set_Receive_Mask(&(Adapter->LMAdapter)) != SUCCESS) {
+
+ return(NDIS_STATUS_FAILURE);
+
+ } else {
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+}
+
+STATIC
+VOID
+MlidCloseAction(
+ IN NDIS_HANDLE MacBindingHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when a particular binding
+ was closed while it was indicating through NdisIndicateReceive
+
+ All this routine needs to do is to decrement the reference count
+ of the binding.
+
+ NOTE: This routine assumes that it is called with the lock acquired.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to MLID_OPEN.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+
+ PMLID_OPEN_FROM_BINDING_HANDLE(MacBindingHandle)->ReferenceCount--;
+
+}
+
+BOOLEAN
+MlidInterruptHandler(
+ IN PVOID ServiceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This is the interrupt handler which is registered with the operating
+ system. Only one interrupt is handled at one time, even if several
+ are pending (i.e. transmit complete and receive).
+
+Arguments:
+
+ ServiceContext - pointer to the adapter object
+
+Return Value:
+
+ TRUE, if the DPC is to be executed, otherwise FALSE.
+
+--*/
+
+{
+ PMLID_ADAPTER Adapter = ((PMLID_ADAPTER)ServiceContext);
+
+ IF_LOUD( DbgPrint("In MlidISR\n");)
+
+ IF_LOG(LOG('i'));
+
+ //
+ // Force the INT signal from the chip low. When the
+ // interrupt is acknowledged interrupts will be unblocked,
+ // which will cause a rising edge on the interrupt line
+ // if there is another interrupt pending on the card.
+ //
+
+ IF_LOUD( DbgPrint( " blocking interrupts\n" );)
+
+ LM_Disable_Adapter(&Adapter->LMAdapter);
+
+ IF_LOG(LOG('I'));
+
+ return(TRUE);
+
+}
+
+VOID
+MlidInterruptDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+/*++
+
+Routine Description:
+
+ This is the deffered processing routine for interrupts, it examines the
+ global 'InterruptReg' to determine what deffered processing is necessary
+ and dispatches control to the Rcv and Xmt handlers.
+
+Arguments:
+ SystemSpecific1, SystemSpecific2, SystemSpecific3 - not used
+ InterruptContext - a handle to the adapter block.
+
+Return Value:
+
+ NONE.
+
+--*/
+{
+ PMLID_ADAPTER Adapter = ((PMLID_ADAPTER)InterruptContext);
+ BOOLEAN RequeueRcv = FALSE;
+
+ UNREFERENCED_PARAMETER(SystemSpecific1);
+ UNREFERENCED_PARAMETER(SystemSpecific2);
+ UNREFERENCED_PARAMETER(SystemSpecific3);
+
+ IF_LOG(LOG('d'));
+
+
+ IF_LOUD( DbgPrint("==>IntDpc\n");)
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ if ( Adapter->ProcessingDpc ) {
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+ return;
+ }
+
+ Adapter->ProcessingDpc = TRUE;
+ Adapter->References++;
+
+ do {
+
+ Adapter->WakeUpTimeout = FALSE;
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ RequeueRcv = MlidReceiveEvents(NULL, (PVOID)Adapter, NULL, NULL);
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ MlidTransmitEvents(Adapter);
+
+ //
+ // This causes any transmit that may have caused a tranmitted packet
+ // to loopback and indicate the packet.
+ //
+
+ } while ( (Adapter->LoopbackQueue != (PNDIS_PACKET)NULL) || RequeueRcv);
+
+ Adapter->ProcessingDpc = FALSE;
+
+ //
+ // Reenable interrupts
+ //
+
+ Adapter->InterruptMask = PACKET_RECEIVE_ENABLE |
+ PACKET_TRANSMIT_ENABLE |
+ RECEIVE_ERROR_ENABLE |
+ TRANSMIT_ERROR_ENABLE |
+ OVERWRITE_WARNING_ENABLE |
+ COUNTER_OVERFLOW_ENABLE;
+
+ NdisSynchronizeWithInterrupt(
+ &(Adapter->NdisInterrupt),
+ LM_Enable_Adapter,
+ &Adapter->LMAdapter
+ );
+
+ MLID_DO_DEFERRED(Adapter);
+
+ IF_LOUD( DbgPrint("<==IntDpc\n");)
+
+ IF_LOG(LOG('D'));
+
+}
+
+VOID
+MlidIndicateLoopbackPacket(
+ IN PMLID_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+ This routine indicates a packet to the current host.
+
+ NOTE: THIS ROUTINE MUST BE CALLED WITH THE SPINLOCK HELD.
+
+Arguments:
+
+ Adapter - Pointer to the adapter structure.
+
+ Packet - Pointer to the packet to indicate.
+
+Return Value:
+
+ NONE.
+
+--*/
+{
+ UINT IndicateLen;
+ UINT PacketLen;
+
+ //
+ // Store that we are indicating a loopback packet
+ //
+
+ Adapter->IndicatingPacket = Packet;
+ Adapter->IndicatedAPacket = TRUE;
+
+ //
+ // Indicate packet.
+ //
+
+ IF_LOUD( DbgPrint("Indicating loopback packet\n");)
+
+ //
+ // Indicate up to 252 bytes.
+ //
+
+ NdisQueryPacket(Packet, NULL, NULL, NULL, &PacketLen);
+
+ if (PacketLen >= ETH_LENGTH_OF_ADDRESS) {
+
+ IndicateLen = (PacketLen > (Adapter->MaxLookAhead + MLID_HEADER_SIZE) ?
+ (Adapter->MaxLookAhead + MLID_HEADER_SIZE) :
+ PacketLen
+ );
+
+ //
+ // Copy the lookahead data into a contiguous buffer.
+ //
+
+ MlidCopyOver(Adapter->LookAhead,
+ Packet,
+ 0,
+ IndicateLen
+ );
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+
+ //
+ // Indicate packet
+ //
+
+ if (Adapter->TokenRing) {
+
+ //*\\ token ring
+
+ } else {
+
+ if (PacketLen < MLID_HEADER_SIZE) {
+
+ //
+ // Runt packet
+ //
+
+ EthFilterIndicateReceive(
+ Adapter->FilterDB,
+ (NDIS_HANDLE)Adapter,
+ (PCHAR)Adapter->LookAhead,
+ Adapter->LookAhead,
+ PacketLen,
+ NULL,
+ 0,
+ 0
+ );
+
+ } else {
+
+ EthFilterIndicateReceive(
+ Adapter->FilterDB,
+ (NDIS_HANDLE)Adapter,
+ (PCHAR)Adapter->LookAhead,
+ Adapter->LookAhead,
+ MLID_HEADER_SIZE,
+ Adapter->LookAhead + MLID_HEADER_SIZE,
+ IndicateLen - MLID_HEADER_SIZE,
+ PacketLen - MLID_HEADER_SIZE
+ );
+
+ }
+
+ }
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ }
+
+}
+
+BOOLEAN
+MlidReceiveEvents(
+ IN PVOID SystemSpecific1,
+ IN PVOID Context,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+/*++
+
+Routine Description:
+
+ This routine handles all Receive deferred processing, this includes any
+ packets that never went through the XmitQueue and need to be indicated
+ (Loopbacked), and all card events.
+
+Arguments:
+
+ Context - a handle to the adapter block.
+
+Return Value:
+
+ Do we need to requeue this Rcv.
+
+--*/
+{
+
+ PMLID_ADAPTER Adapter = (PMLID_ADAPTER)(Context);
+ PNDIS_PACKET Packet;
+ PMLID_OPEN TmpOpen;
+ NDIS_STATUS Status;
+ BOOLEAN RequeueRcv;
+
+ IF_LOG(LOG('e'));
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ Adapter->References++;
+
+ RequeueRcv = (BOOLEAN)(LM_Service_Receive_Events(&Adapter->LMAdapter) ==
+ REQUEUE_LATER);
+
+ while (Adapter->LoopbackQueue != NULL) {
+
+ //
+ // Take packet off queue.
+ //
+
+ Packet = Adapter->LoopbackQueue;
+
+ if (Packet == Adapter->LoopbackQTail) {
+
+ Adapter->LoopbackQTail = NULL;
+
+ }
+
+ Adapter->LoopbackQueue = RESERVED(Packet)->NextPacket;
+
+ //
+ // Indicate the packet
+ //
+
+ MlidIndicateLoopbackPacket(Adapter,Packet);
+
+
+ //
+ // Complete the packet send.
+ //
+
+ Adapter->FramesXmitGood++;
+
+ //
+ // Save this, since once we complete the send
+ // Reserved is no longer valid.
+ //
+
+ TmpOpen = RESERVED(Packet)->Open;
+
+ IF_VERY_LOUD( DbgPrint("Completing send for packet 0x%x\n",Packet);)
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteSend(TmpOpen->NdisBindingContext,
+ Packet,
+ NDIS_STATUS_SUCCESS
+ );
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ MlidRemoveReference(TmpOpen);
+
+ }
+
+ //
+ // If any indications done, then
+ //
+ // CompleteIndications();
+ //
+
+ if (Adapter->IndicatedAPacket) {
+
+ Adapter->IndicatedAPacket = FALSE;
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ if (Adapter->TokenRing) {
+
+ //*\\ token ring
+
+ } else {
+
+ EthFilterIndicateReceiveComplete(Adapter->FilterDB);
+
+ }
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ }
+
+
+
+ if ((Adapter->ResetRequested) && (Adapter->References == 1)) {
+
+ PNDIS_PACKET Packet;
+ PMLID_OPEN TmpOpen;
+
+ IF_LOG(LOG('R'));
+
+ IF_VERY_LOUD( DbgPrint("Starting Reset\n");)
+
+ Adapter->ResetInProgress = TRUE;
+
+ NdisSynchronizeWithInterrupt(
+ &(Adapter->NdisInterrupt),
+ LM_Disable_Adapter,
+ &Adapter->LMAdapter
+ );
+
+ //
+ // Indicate Status to all opens
+ //
+
+ IF_VERY_LOUD( DbgPrint("Indicating status\n");)
+
+ TmpOpen = Adapter->OpenQueue;
+
+ while (TmpOpen != (PMLID_OPEN)NULL) {
+
+ AddRefWhileHoldingSpinLock(Adapter, TmpOpen);
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ NdisIndicateStatus(TmpOpen->NdisBindingContext,
+ NDIS_STATUS_RESET_START,
+ NULL,
+ 0
+ );
+
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ MlidRemoveReference(TmpOpen);
+
+ TmpOpen = TmpOpen->NextOpen;
+
+ }
+
+ //
+ // Reset the Card.
+ //
+
+ IF_VERY_LOUD( DbgPrint("Resetting the card\n");)
+
+ if (LM_Initialize_Adapter(&Adapter->LMAdapter) != SUCCESS) {
+
+ Adapter->HardwareFailure = TRUE;
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 0
+ );
+
+ } else {
+
+ Adapter->HardwareFailure = FALSE;
+
+ }
+
+
+
+ //
+ // Put packets that were on the card on to the front of the xmit
+ // queue.
+ //
+
+ if (Adapter->PacketsOnCard != NULL) {
+
+ IF_VERY_LOUD( DbgPrint("Moving Packets On card\n");)
+
+ RESERVED(Adapter->PacketsOnCardTail)->NextPacket = Adapter->XmitQueue;
+
+ Adapter->XmitQueue = Adapter->PacketsOnCard;
+
+ Adapter->PacketsOnCard = Adapter->PacketsOnCardTail = NULL;
+
+ }
+
+
+ //
+ // Put packets on loopback queue on xmit queue
+ //
+
+ if (Adapter->LoopbackQueue != NULL) {
+
+ RESERVED(Adapter->LoopbackQTail)->NextPacket = Adapter->XmitQueue;
+
+ Adapter->XmitQueue = Adapter->LoopbackQueue;
+
+ }
+
+
+ //
+ // Wipe out loopback queue.
+ //
+
+ Adapter->LoopbackQueue = Adapter->LoopbackQTail = (PNDIS_PACKET)NULL;
+
+
+ //
+ // Abort all xmits
+ //
+
+ IF_VERY_LOUD( DbgPrint("Killing Xmits\n");)
+
+ while (Adapter->XmitQueue != NULL) {
+
+ Packet = Adapter->XmitQueue;
+
+ Adapter->XmitQueue = RESERVED(Packet)->NextPacket;
+
+ TmpOpen = RESERVED(Packet)->Open;
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteSend(TmpOpen->NdisBindingContext,
+ Packet,
+ NDIS_STATUS_REQUEST_ABORTED
+ );
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ MlidRemoveReference(TmpOpen);
+
+ }
+
+ Adapter->XmitQTail = NULL;
+
+ if (!Adapter->HardwareFailure) {
+
+ LM_Open_Adapter(&Adapter->LMAdapter);
+
+ }
+
+ Adapter->ResetInProgress = FALSE;
+
+ IF_VERY_LOUD( DbgPrint("Indicating Done\n");)
+
+ //
+ // Indicate Reset is done
+ //
+
+ //
+ // Indicate Status to all opens
+ //
+
+ IF_VERY_LOUD( DbgPrint("Indicating status\n");)
+
+ TmpOpen = Adapter->OpenQueue;
+
+ while (TmpOpen != (PMLID_OPEN)NULL) {
+
+ AddRefWhileHoldingSpinLock(Adapter, TmpOpen);
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ if (Adapter->HardwareFailure) {
+
+ NdisIndicateStatus(TmpOpen->NdisBindingContext,
+ NDIS_STATUS_CLOSED,
+ NULL,
+ 0
+ );
+
+ }
+
+ Status = (Adapter->HardwareFailure) ?
+ NDIS_STATUS_FAILURE :
+ NDIS_STATUS_SUCCESS;
+
+
+ NdisIndicateStatus(TmpOpen->NdisBindingContext,
+ NDIS_STATUS_RESET_END,
+ &Status,
+ sizeof(Status)
+ );
+
+ NdisIndicateStatusComplete(TmpOpen->NdisBindingContext);
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ MlidRemoveReference(TmpOpen);
+
+ TmpOpen = TmpOpen->NextOpen;
+
+ }
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteReset(Adapter->ResetOpen->NdisBindingContext,
+ (Adapter->HardwareFailure) ?
+ NDIS_STATUS_FAILURE :
+ NDIS_STATUS_SUCCESS
+ );
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ MlidRemoveReference(Adapter->ResetOpen);
+
+ //
+ // Reset the flag
+ //
+
+
+ IF_VERY_LOUD( DbgPrint("Restarting Adapter\n");)
+
+ Adapter->ResetRequested = FALSE;
+
+ LM_Open_Adapter(&Adapter->LMAdapter);
+
+ }
+
+#if DBG
+
+ else if (Adapter->ResetRequested) {
+
+ IF_LOUD( DbgPrint("No reset because count is... 0x%x\n", Adapter->References);)
+
+ }
+
+#endif
+
+ Adapter->References--;
+
+ IF_LOG(LOG('E'));
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ return(RequeueRcv);
+
+}
+
+
+VOID
+MlidTransmitEvents(
+ IN PMLID_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine handles all transmit deferred processing.
+
+ NOTE : Called with lock held!!
+
+Arguments:
+
+ Adapter - pointer to the adapter structure.
+
+Return Value:
+
+ NONE.
+
+--*/
+{
+
+ if (Adapter->ResetInProgress) {
+
+ return;
+
+ }
+
+ IF_LOG(LOG('w'));
+
+ LM_Service_Transmit_Events(&Adapter->LMAdapter);
+
+ IF_LOG(LOG('W'));
+
+}
+
+UINT
+MlidCopyOver(
+ OUT PUCHAR Buf, // destination
+ IN PNDIS_PACKET Packet, // source packet
+ IN UINT Offset, // offset in packet
+ IN UINT Length // number of bytes to copy
+ )
+
+/*++
+
+Routine Description:
+
+ Copies bytes from a packet into a buffer. Used to copy data
+ out of a packet during loopback indications.
+
+Arguments:
+
+ Buf - the destination buffer
+ Packet - the source packet
+ Offset - the offset in the packet to start copying at
+ Length - the number of bytes to copy
+
+Return Value:
+
+ The actual number of bytes copied; will be less than Length if
+ the packet length is less than Offset+Length.
+
+--*/
+
+{
+ PNDIS_BUFFER CurBuffer;
+ UINT BytesCopied;
+ PUCHAR BufVA;
+ UINT BufLen;
+ UINT ToCopy;
+ UINT CurOffset;
+
+
+ BytesCopied = 0;
+
+ //
+ // First find a spot Offset bytes into the packet.
+ //
+
+ CurOffset = 0;
+
+ NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, NULL);
+
+ while (CurBuffer != (PNDIS_BUFFER)NULL) {
+
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufVA, &BufLen);
+
+ if (CurOffset + BufLen > Offset) {
+
+ break;
+
+ }
+
+ CurOffset += BufLen;
+
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+
+ }
+
+
+ //
+ // See if the end of the packet has already been passed.
+ //
+
+ if (CurBuffer == (PNDIS_BUFFER)NULL) {
+
+ return 0;
+
+ }
+
+
+ //
+ // Now copy over Length bytes.
+ //
+
+ BufVA += (Offset - CurOffset);
+
+ BufLen -= (Offset - CurOffset);
+
+ for (;;) {
+
+ ToCopy = (BytesCopied+BufLen > Length) ? Length - BytesCopied : BufLen;
+
+ MLID_MOVE_MEM(Buf+BytesCopied, BufVA, ToCopy);
+
+ BytesCopied += ToCopy;
+
+
+ if (BytesCopied == Length) {
+
+ return BytesCopied;
+
+ }
+
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+
+ if (CurBuffer == (PNDIS_BUFFER)NULL) {
+
+ break;
+
+ }
+
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufVA, &BufLen);
+
+ }
+
+ return BytesCopied;
+
+}
+
+
+
+NDIS_STATUS
+MlidTransferData(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ )
+
+/*++
+
+Routine Description:
+
+ NDIS function.
+
+Arguments:
+
+ see NDIS 3.0 spec.
+
+Notes:
+
+ - The MacReceiveContext will be a pointer to the open block for
+ the packet.
+ - The LoopbackPacket field in the adapter block will be NULL if this
+ is a call for a normal packet, otherwise it will be set to point
+ to the loopback packet.
+
+--*/
+{
+ PMLID_OPEN Open = PMLID_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+ PMLID_ADAPTER Adapter = Open->Adapter;
+ PNDIS_BUFFER CurrentBuffer;
+ PUCHAR BufferVA;
+ UINT BufferLength, Copied;
+ UINT CurrentOffset;
+
+ UNREFERENCED_PARAMETER(MacReceiveContext);
+
+ ByteOffset += MLID_HEADER_SIZE;
+
+ if (Adapter->IndicatingPacket != NULL) {
+
+ IF_LOUD( DbgPrint("Transferring data for loopback packet\n");)
+
+ //
+ // It is a loopback packet
+ //
+
+ NdisQueryPacket(Packet, NULL, NULL, &CurrentBuffer, NULL);
+
+ CurrentOffset = ByteOffset;
+
+ while (CurrentBuffer != (PNDIS_BUFFER)NULL) {
+
+ NdisQueryBuffer(CurrentBuffer, (PVOID *)&BufferVA, &BufferLength);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ Copied =
+ MlidCopyOver(BufferVA,
+ Adapter->IndicatingPacket,
+ CurrentOffset,
+ BufferLength
+ );
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ CurrentOffset += Copied;
+
+ if (Copied < BufferLength) {
+
+ break;
+
+ }
+
+ NdisGetNextBuffer(CurrentBuffer, &CurrentBuffer);
+
+ }
+
+ //
+ // We are done, return.
+ //
+
+
+ *BytesTransferred = CurrentOffset - ByteOffset;
+
+ return(NDIS_STATUS_SUCCESS);
+
+ } else if (Adapter->IndicatedAPacket) {
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ IF_LOUD( DbgPrint("Transferring data for card packet\n");)
+
+ if (LM_Receive_Copy(
+ BytesTransferred,
+ BytesToTransfer,
+ ByteOffset,
+ Packet,
+ &(Adapter->LMAdapter)) != SUCCESS) {
+
+ //
+ // Copy failed.
+ //
+
+ *BytesTransferred = 0;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ return(NDIS_STATUS_FAILURE);
+
+ } else {
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+ } else {
+
+ return(NDIS_STATUS_NOT_INDICATING);
+
+ }
+
+}
+
+BOOLEAN
+MlidSyncCloseAdapter(
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ This function is used to synchronize with the lower MAC layer close
+ calls that may access the same areas of the LM that are accessed in
+ the ISR.
+
+Arguments:
+
+ see NDIS 3.0 spec.
+
+Notes:
+
+ returns TRUE on success, else FALSE.
+
+--*/
+{
+
+ if (LM_Close_Adapter((Ptr_Adapter_Struc)Context) == SUCCESS) {
+
+ return(TRUE);
+
+ } else {
+
+ return(FALSE);
+
+ }
+
+}
+
+
+VOID
+MlidWakeUpDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID Context,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+
+/*++
+
+Routine Description:
+
+ This DPC routine is queued every 5 seconds to check on the
+ queues. If an interrupt was not received
+ in the last 5 seconds and there should have been one,
+ then we abort all operations.
+
+Arguments:
+
+ Context - Really a pointer to the adapter.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PMLID_ADAPTER Adapter = (PMLID_ADAPTER)Context;
+ PMLID_OPEN TmpOpen;
+ PNDIS_PACKET TransmitPacket;
+ PMAC_RESERVED Reserved;
+
+ UNREFERENCED_PARAMETER(SystemSpecific1);
+ UNREFERENCED_PARAMETER(SystemSpecific2);
+ UNREFERENCED_PARAMETER(SystemSpecific3);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ if ((Adapter->WakeUpTimeout) &&
+ ((Adapter->PacketsOnCard != NULL) ||
+ (Adapter->XmitQueue != NULL))) {
+
+ //
+ // We had a pending operation the last time we ran,
+ // and it has not been completed...we need to complete
+ // it now.
+
+ Adapter->WakeUpTimeout = FALSE;
+
+ Adapter->HardwareFailure = TRUE;
+
+ if (Adapter->WakeUpErrorCount < 10) {
+
+ Adapter->WakeUpErrorCount++;
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 0
+ );
+
+ }
+
+ while (Adapter->PacketsOnCard != NULL) {
+
+ TransmitPacket = Adapter->PacketsOnCard;
+
+ Reserved = RESERVED(TransmitPacket);
+
+ Adapter->PacketsOnCard = Reserved->NextPacket;
+
+ if (Adapter->PacketsOnCard == NULL) {
+
+ Adapter->PacketsOnCardTail = NULL;
+
+ }
+
+ TmpOpen = Reserved->Open;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteSend(
+ TmpOpen->NdisBindingContext,
+ TransmitPacket,
+ NDIS_STATUS_SUCCESS
+ );
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ TmpOpen->ReferenceCount--;
+
+ }
+
+ while (Adapter->XmitQueue != NULL) {
+
+ TransmitPacket = Adapter->XmitQueue;
+
+ Reserved = RESERVED(TransmitPacket);
+
+ //
+ // Remove the packet from the queue.
+ //
+
+ Adapter->XmitQueue = Reserved->NextPacket;
+
+ if (Adapter->XmitQueue == NULL) {
+
+ Adapter->XmitQTail = NULL;
+
+ }
+
+ TmpOpen = Reserved->Open;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteSend(
+ TmpOpen->NdisBindingContext,
+ TransmitPacket,
+ NDIS_STATUS_SUCCESS
+ );
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ TmpOpen->ReferenceCount--;
+
+ }
+
+ Adapter->WakeUpTimeout = FALSE;
+
+ //
+ // reinitialize the card
+ //
+
+ if (LM_Initialize_Adapter(&Adapter->LMAdapter) != SUCCESS) {
+
+ Adapter->HardwareFailure = TRUE;
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 0
+ );
+
+ } else {
+
+ Adapter->HardwareFailure = FALSE;
+
+ }
+
+ //
+ // reenable interrupts
+ //
+
+ LM_Enable_Adapter(&Adapter->LMAdapter);
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ } else {
+
+ if ((Adapter->PacketsOnCard != NULL) ||
+ (Adapter->XmitQueue != NULL)) {
+
+ Adapter->WakeUpTimeout = TRUE;
+
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+
+ }
+
+ //
+ // Fire off another Dpc to execute after 5 seconds
+ //
+
+ NdisSetTimer(
+ &Adapter->WakeUpTimer,
+ 5000
+ );
+
+}
+
+
+
diff --git a/private/ntos/ndis/odimac/mlidsft.h b/private/ntos/ndis/odimac/mlidsft.h
new file mode 100644
index 000000000..f705b1357
--- /dev/null
+++ b/private/ntos/ndis/odimac/mlidsft.h
@@ -0,0 +1,814 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ MLIDsft.h
+
+Abstract:
+
+ The main header for an Western Digital MAC driver.
+
+Author:
+
+ Anthony V. Ercolano (tonye) creation-date 19-Jun-1990 (Driver Model)
+
+ Sean Selitrennikoff (seanse) original MLID code.
+
+Environment:
+
+ This driver is expected to work in DOS, OS2 and NT at the equivalent
+ of kernal mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+
+--*/
+
+#ifndef _MLIDSFT_
+#define _MLIDSFT_
+
+#define MLID_NDIS_MAJOR_VERSION 3
+#define MLID_NDIS_MINOR_VERSION 0
+
+//
+// This macro is used along with the flags to selectively
+// turn on debugging.
+//
+
+#if DBG
+
+#define IF_MLIDDEBUG(f) if (MlidDebugFlag & (f))
+
+extern ULONG MlidDebugFlag;
+
+#define MLID_DEBUG_LOUD 0x00000001 // debugging info
+#define MLID_DEBUG_VERY_LOUD 0x00000002 // excessive debugging info
+#define MLID_DEBUG_LOG 0x00000004 // enable MLIDLog
+#define MLID_DEBUG_CHECK_DUP_SENDS 0x00000008 // check for duplicate sends
+#define MLID_DEBUG_TRACK_PACKET_LENS 0x00000010 // track directed packet lens
+#define MLID_DEBUG_WORKAROUND1 0x00000020 // drop DFR/DIS packets
+#define MLID_DEBUG_CARD_BAD 0x00000040 // dump data if CARD_BAD
+#define MLID_DEBUG_CARD_TESTS 0x00000080 // print reason for failing
+
+
+
+//
+// Macro for deciding whether to dump lots of debugging information.
+//
+
+#define IF_LOUD(A) IF_MLIDDEBUG( MLID_DEBUG_LOUD ) { A }
+#define IF_VERY_LOUD(A) IF_MLIDDEBUG( MLID_DEBUG_VERY_LOUD ) { A }
+
+#else
+
+#define IF_LOUD(A)
+#define IF_VERY_LOUD(A)
+
+#endif
+
+
+//
+// Macros for services that differ between DOS and NT, we may consider adding these
+// into the NDIS spec.
+//
+
+
+//
+// controls the number of transmit buffers on the packet.
+// Choices are 1 or 2.
+//
+
+#define DEFAULT_NUMBUFFERS 2
+
+
+//
+// Macros for moving memory around
+//
+
+#define MLID_MOVE_MEM(dest,src,size) NdisMoveMemory(dest,src,size)
+#define MLID_MOVE_MEM_TO_SHARED_RAM(dest,src,size) NdisMoveToMappedMemory(dest,src,size)
+#define MLID_MOVE_SHARED_RAM_TO_MEM(dest,src,size) NdisMoveFromMappedMemory(dest,src,size)
+
+#define MLID_MOVE_DWORD_TO_SHARED_RAM(dest,src) NdisWriteRegisterUlong((PULONG)(dest),(ULONG)(src))
+#define MLID_MOVE_SHARED_RAM_TO_DWORD(dest,src) NdisReadRegisterUlong((PULONG)(src),(PULONG)(dest))
+
+#define MLID_MOVE_UCHAR_TO_SHARED_RAM(dest,src) NdisWriteRegisterUchar((PUCHAR)(dest),(UCHAR)(src))
+#define MLID_MOVE_SHARED_RAM_TO_UCHAR(dest,src) NdisReadRegisterUchar((PUCHAR)(src),(PUCHAR)(dest))
+
+#define MLID_MOVE_USHORT_TO_SHARED_RAM(dest,src) NdisWriteRegisterUshort((PUSHORT)(dest),(USHORT)(src))
+#define MLID_MOVE_SHARED_RAM_TO_USHORT(dest,src) NdisReadRegisterUshort((PUSHORT)(src),(PUSHORT)(dest))
+
+
+//
+// Only have one of these structures.
+//
+
+typedef struct _MAC_BLOCK {
+
+ //
+ // NDIS wrapper information.
+ //
+
+ NDIS_HANDLE NdisMacHandle; // returned from NdisRegisterMac
+ NDIS_HANDLE NdisWrapperHandle; // returned from NdisInitializeWrapper
+ NDIS_MAC_CHARACTERISTICS MacCharacteristics;
+
+ //
+ // Adapters registered for this MAC.
+ //
+
+ UINT NumAdapters;
+ struct _MLID_ADAPTER * AdapterQueue;
+ NDIS_SPIN_LOCK SpinLock; // guards NumAdapter and AdapterQueue
+
+ //
+ // driver object.
+ //
+
+ PDRIVER_OBJECT DriverObject;
+
+ BOOLEAN Unloading;
+
+} MAC_BLOCK, * PMAC_BLOCK;
+
+
+
+
+
+
+//
+// One of these structures per adapter registered.
+//
+
+typedef struct _MLID_ADAPTER {
+
+ //
+ // Adapter structure for LMI.
+ // This must occur first in the adapter structure.
+ //
+
+ Adapter_Struc LMAdapter;
+
+ //
+ // Spin lock for adapter structure
+ //
+ NDIS_SPIN_LOCK Lock;
+
+
+ //
+ // Links with our MAC.
+ //
+
+ PMAC_BLOCK MacBlock;
+ struct _MLID_ADAPTER * NextAdapter; // used by MacBlock->OpenQueue
+
+ //
+ // Opens for this adapter.
+ //
+
+ struct _MLID_OPEN * OpenQueue;
+
+
+ //
+ // Number of references to the adapter.
+ //
+ ULONG References;
+
+ UINT MulticastListMax;
+
+ //
+ // Transmit queue.
+ //
+
+ PNDIS_PACKET XmitQueue; // packets waiting to be transmitted
+ PNDIS_PACKET XmitQTail;
+
+ PNDIS_PACKET PacketsOnCard; // List of packets that the card is
+ // is currently transmitting
+ PNDIS_PACKET PacketsOnCardTail;
+
+ //
+ // Loopback queue;
+ //
+
+ PNDIS_PACKET LoopbackQueue; // directed packets waiting to be received
+ PNDIS_PACKET LoopbackQTail;
+ PNDIS_PACKET IndicatingPacket;
+ BOOLEAN IndicatedAPacket;
+
+ //
+ // These are for the current packet being indicated.
+ //
+
+ UCHAR PacketHeader[4]; // the NIC appended header
+ UINT PacketLen; // the overall length of the packet
+
+
+
+ //
+ // Statistics used by Set/QueryInformation.
+ //
+
+ ULONG FramesXmitGood; // Good Frames Transmitted
+ ULONG FramesRcvGood; // Good Frames Received
+
+ ULONG FramesXmitBad; // Bad Frames Transmitted
+ ULONG FramesXmitOneCollision; // Frames Transmitted with one collision
+ ULONG FramesXmitManyCollisions; // Frames Transmitted with > 1 collision
+ ULONG FramesXmitDeferred; // Frames where xmit was deferred
+ ULONG FramesXmitOverWrite; // Frames where xmit was overwritten
+ ULONG FramesXmitHeartbeat; // Frames lost heartbeat
+ ULONG FramesXmitUnderruns; // Frames where FIFO underran
+
+ ULONG FrameAlignmentErrors; // FAE errors counted
+ ULONG CrcErrors; // CRC errors counted
+ ULONG MissedPackets; // missed packet counted
+ ULONG TooBig; // received packets too large counted
+ ULONG Overruns; // received packets with FIFO overrun
+
+ ULONG CongestionCount;
+ ULONG FCSErrors;
+ ULONG BurstErrors;
+ ULONG ACErrors;
+ ULONG AbortDelimiters;
+ ULONG FailedReturns;
+ ULONG FramesCopied;
+ ULONG FrequencyErrors;
+ ULONG MonitorCount;
+ ULONG DMAUnderruns;
+
+ //
+ // Reset information.
+ //
+
+ BOOLEAN HardwareFailure; // Did the hardware fail in some way
+ BOOLEAN ResetRequested; // TRUE if a reset is needed
+ BOOLEAN ResetInProgress; // TRUE if a reset is in progress
+ struct _MLID_OPEN * ResetOpen; // who called MLIDReset
+
+ UINT ByteToWrite; // temp storage
+
+
+ //
+ // Look Ahead information.
+ //
+
+ ULONG MaxLookAhead;
+
+
+ //
+ // Handling deferred events
+ //
+
+ NDIS_TIMER DeferredTimer;
+ PVOID DeferredDpc;
+
+ BOOLEAN ReceiveEventsQueued;
+ BOOLEAN TransmitEventsQueued;
+
+ BOOLEAN Removed;
+
+ //
+ // For handling missing interrupts (caused by user mis-configs)
+ //
+
+ PVOID WakeUpDpc;
+ NDIS_TIMER WakeUpTimer;
+ BOOLEAN WakeUpTimeout;
+ UCHAR WakeUpErrorCount;
+ BOOLEAN ProcessingDpc;
+
+} MLID_ADAPTER, * PMLID_ADAPTER;
+
+
+
+
+//
+// Given a MacBindingHandle this macro returns a pointer to the
+// MLID_ADAPTER.
+//
+#define PMLID_ADAPTER_FROM_BINDING_HANDLE(Handle) \
+ (((PMLID_OPEN)(Handle))->Adapter)
+
+//
+// Given a MacContextHandle return the PMLID_ADAPTER
+// it represents.
+//
+#define PMLID_ADAPTER_FROM_CONTEXT_HANDLE(Handle) \
+ ((PMLID_ADAPTER)(Handle))
+
+//
+// Given a pointer to a MLID_ADAPTER return the
+// proper MacContextHandle.
+//
+#define CONTEXT_HANDLE_FROM_PMLID_ADAPTER(Ptr) \
+ ((NDIS_HANDLE)(Ptr))
+
+
+//
+// Given a pointer to a MLID_ADAPTER, return the
+// pointer to the LMAdapter.
+//
+#define Ptr_Adapter_Struc_FROM_PMLID_ADAPTER(P)\
+ (&((P)->LMAdapter))
+
+//
+// Given a pointer to a LMAdapter, return the
+// pointer to the MLID_ADAPTER.
+//
+#define PMLID_ADAPTER_FROM_Ptr_Adapter_Struc(P)\
+ ((PMLID_ADAPTER)(P))
+
+
+
+
+//
+// Macros to extract high and low bytes of a word.
+//
+
+#define MSB(Value) ((UCHAR)(((Value) >> 8) & 0xff))
+#define LSB(Value) ((UCHAR)((Value) & 0xff))
+
+
+//
+// One of these per open on an adapter.
+//
+
+typedef struct _MLID_OPEN {
+
+ //
+ // NDIS wrapper information.
+ //
+
+ NDIS_HANDLE NdisBindingContext; // passed to MacOpenAdapter
+ PSTRING AddressingInformation; // not used currently
+
+ //
+ // Links to our adapter.
+ //
+
+ PMLID_ADAPTER Adapter;
+ struct _MLID_OPEN * NextOpen;
+
+ //
+ // Links to our MAC.
+ //
+
+ PMAC_BLOCK MacBlock; // faster than using AdapterBlock->MacBlock
+
+
+ //
+ // Handle of this adapter in the filter database.
+ //
+ NDIS_HANDLE NdisFilterHandle;
+
+ //
+ // Indication information
+ //
+
+ UINT LookAhead;
+
+ //
+ // Reset/Close information.
+ //
+
+ UINT ReferenceCount; // number of reasons this open can't close
+ BOOLEAN Closing; // is a close pending
+
+ NDIS_REQUEST CloseFilterRequest; // Holds Requests for pending close op
+ NDIS_REQUEST CloseAddressRequest;// Holds Requests for pending close op
+
+ UINT ProtOptionFlags;
+
+} MLID_OPEN, * PMLID_OPEN;
+
+
+//
+// This macro returns a pointer to a PMLID_OPEN given a MacBindingHandle.
+//
+#define PMLID_OPEN_FROM_BINDING_HANDLE(Handle) \
+ ((PMLID_OPEN)(Handle))
+
+//
+// This macro returns a NDIS_HANDLE from a PMLID_OPEN
+//
+#define BINDING_HANDLE_FROM_PMLID_OPEN(Open) \
+ ((NDIS_HANDLE)(Open))
+
+
+
+
+
+//
+// What we map into the reserved section of a packet.
+// Cannot be more than 16 bytes (see ASSERT in MLID.c).
+//
+
+typedef struct _MAC_RESERVED {
+ PNDIS_PACKET NextPacket; // used to link in the queues (4 bytes)
+ PMLID_OPEN Open; // open that called MLIDSend (4 bytes)
+ BOOLEAN Loopback; // is this a loopback packet (1 byte)
+ BOOLEAN Directed; // is this a directed packet (1 byte)
+} MAC_RESERVED, * PMAC_RESERVED;
+
+
+//
+// These appear in the status field of MAC_RESERVED; they are
+// used because there is not enough room for a full NDIS_HANDLE.
+//
+
+#define RESERVED_SUCCESS ((USHORT)0)
+#define RESERVED_FAILURE ((USHORT)1)
+
+
+//
+// Retrieve the MAC_RESERVED structure from a packet.
+//
+
+#define RESERVED(Packet) ((PMAC_RESERVED)((Packet)->MacReserved))
+
+
+//
+// This macro will act a "epilogue" to every routine in the
+// *interface*. It will check whether any requests need
+// to defer their processing. It will also decrement the reference
+// count on the adapter. If the reference count is zero and there
+// is deferred work to do it will insert the interrupt processing
+// routine in the DPC queue.
+//
+// Note that we don't need to include checking for blocked receives
+// since blocked receives imply that there will eventually be an
+// interrupt.
+//
+// NOTE: This macro assumes that it is called with the lock acquired.
+//
+//
+#define MLID_DO_DEFERRED(Adapter) \
+{ \
+ PMLID_ADAPTER _A = (Adapter); \
+ _A->References--; \
+ if ((!_A->References) && \
+ ((_A->ResetRequested && (!_A->ReceiveEventsQueued)) || \
+ ((_A->LoopbackQueue != NULL) && (!_A->ReceiveEventsQueued)))) \
+ {\
+ _A->ReceiveEventsQueued = TRUE; \
+ NdisReleaseSpinLock(&_A->Lock); \
+ NdisSetTimer(&_A->DeferredTimer, 0);\
+ } else { \
+ NdisReleaseSpinLock(&_A->Lock); \
+ } \
+}
+
+
+
+
+//
+// Declarations for functions in MLID.c.
+//
+
+NDIS_STATUS
+MlidRegisterAdapter(
+ IN PMLID_ADAPTER Adapter,
+ IN UINT NumBuffers,
+ IN UINT MulticastListMax,
+ IN UCHAR NodeAddress[ETH_LENGTH_OF_ADDRESS]
+ );
+
+
+BOOLEAN
+MlidInterruptHandler(
+ IN PVOID ServiceContext // will be a pointer to the adapter block
+ );
+
+VOID
+MlidInterruptDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+NDIS_STATUS
+MlidOpenAdapter(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT NDIS_HANDLE * MacBindingHandle,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_HANDLE MacAdapterContext,
+ IN UINT OpenOptions,
+ IN PSTRING AddressingInformation OPTIONAL
+ );
+
+
+NDIS_STATUS
+MlidCloseAdapter(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+
+BOOLEAN
+MlidAddReference(
+ IN PMLID_OPEN OpenP
+ );
+
+
+#define MlidRemoveReference(_Open) \
+{ \
+ PMLID_ADAPTER _Adapter = _Open->Adapter; \
+ PMLID_OPEN _TmpOpen = _Open; \
+ --_TmpOpen->ReferenceCount; \
+ if (_TmpOpen->ReferenceCount == 0) { \
+ if (_TmpOpen == _Adapter->OpenQueue) { \
+ _Adapter->OpenQueue = _TmpOpen->NextOpen; \
+ } else { \
+ _TmpOpen = _Adapter->OpenQueue; \
+ while (_TmpOpen->NextOpen != _Open) { \
+ _TmpOpen = _TmpOpen->NextOpen; \
+ } \
+ _TmpOpen->NextOpen = _Open->NextOpen; \
+ _TmpOpen = _Open; \
+ } \
+ if (_TmpOpen->LookAhead == _Adapter->MaxLookAhead) {\
+ MlidAdjustMaxLookAhead(_Adapter); \
+ } \
+ NdisReleaseSpinLock(&_Adapter->Lock); \
+ NdisCompleteCloseAdapter (_TmpOpen->NdisBindingContext, NDIS_STATUS_SUCCESS); \
+ NdisFreeMemory(_TmpOpen, sizeof(MLID_OPEN), 0); \
+ NdisAcquireSpinLock(&_Adapter->Lock); \
+ if (_Adapter->OpenQueue == NULL) { \
+ NdisSynchronizeWithInterrupt( \
+ &(_Adapter->LMAdapter.NdisInterrupt), \
+ (PVOID)MlidSyncCloseAdapter, \
+ (PVOID)(&(_Adapter->LMAdapter)) \
+ ); \
+ } \
+ } \
+}
+
+VOID
+MlidAdjustMaxLookAhead(
+ IN PMLID_ADAPTER Adapter
+ );
+
+NDIS_STATUS
+MlidReset(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+NDIS_STATUS
+MlidRequest(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+NDIS_STATUS
+MlidQueryInformation(
+ IN PMLID_ADAPTER Adapter,
+ IN PMLID_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+NDIS_STATUS
+MlidSetInformation(
+ IN PMLID_ADAPTER Adapter,
+ IN PMLID_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+NDIS_STATUS
+MlidSetMulticastAddresses(
+ IN PMLID_ADAPTER Adapter,
+ IN PMLID_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT NumAddresses,
+ IN CHAR AddressList[][ETH_LENGTH_OF_ADDRESS]
+ );
+
+NDIS_STATUS
+MlidSetPacketFilter(
+ IN PMLID_ADAPTER Adapter,
+ IN PMLID_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT PacketFilter
+ );
+
+NDIS_STATUS
+MlidQueryGlobalStatistics(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+VOID
+MlidUnload(
+ IN NDIS_HANDLE MacMacContext
+ );
+
+NDIS_STATUS
+MlidAddAdapter(
+ IN NDIS_HANDLE NdisMacContext,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING AdaptName
+ );
+
+VOID
+MlidRemoveAdapter(
+ IN PVOID MacAdapterContext
+ );
+
+VOID
+MlidInterruptDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+NDIS_STATUS
+MlidChangeMulticastAddresses(
+ IN UINT OldFilterCount,
+ IN CHAR OldAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN UINT NewFilterCount,
+ IN CHAR NewAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+NDIS_STATUS
+MlidChangeFilterClasses(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+
+VOID
+MlidCloseAction(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+
+UINT
+MlidPacketSize(
+ IN PNDIS_PACKET Packet
+ );
+
+
+INDICATE_STATUS
+MlidIndicatePacket(
+ IN PMLID_ADAPTER Adapter
+ );
+
+
+NDIS_STATUS
+MlidTransferData(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+BOOLEAN
+MlidReceiveEvents(
+ IN PVOID SystemSpecific1,
+ IN PVOID Context,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+VOID
+MlidTransmitEvents(
+ IN PMLID_ADAPTER Adapter
+ );
+
+NDIS_STATUS
+MlidSend(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_PACKET Packet
+ );
+
+UINT
+MlidCompareMemory(
+ IN PUCHAR String1,
+ IN PUCHAR String2,
+ IN UINT Length
+ );
+
+VOID
+MlidSetLoopbackFlag(
+ IN PMLID_ADAPTER Adapter,
+ IN PMLID_OPEN Open,
+ IN OUT PNDIS_PACKET Packet
+ );
+
+VOID
+MlidIndicateLoopbackPacket(
+ IN PMLID_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet
+ );
+
+BOOLEAN
+MlidSyncCloseAdapter(
+ IN PVOID Context
+ );
+
+BOOLEAN
+MlidSyncSend(
+ IN PVOID Context
+ );
+
+BOOLEAN
+MlidSyncSetMulticastAddress(
+ IN PVOID Context
+ );
+
+VOID
+MlidWakeUpDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID Context,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+//++
+//
+// VOID
+// AddRefWhileHoldingSpinLock(
+// IN PMLID_ADAPTER Adapter,
+// IN PMLID_OPEN OpenP
+// )
+//
+// Routine Description:
+//
+// Adds a reference to an open. Similar to AddReference, but
+// called with Adapter->Lock held.
+//
+// Arguments:
+//
+// Adapter - The adapter block of OpenP.
+// OpenP - The open block that is being referenced.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define AddRefWhileHoldingSpinLock(Adapter, OpenP) { \
+ ++((OpenP)->ReferenceCount); \
+}
+
+
+
+//++
+//
+// BOOLEAN
+// MlidAddressEqual(
+// IN UCHAR Address1[ETH_LENGTH_OF_ADDRESS],
+// IN UCHAR Address2[ETH_LENGTH_OF_ADDRESS]
+// )
+//
+// Routine Description:
+//
+// Compares two Ethernet addresses.
+//
+// Arguments:
+//
+// Address1 - The first address.
+// Address2 - The second address.
+//
+// Return Value:
+//
+// TRUE if the addresses are equal.
+// FALSE if they are not.
+//
+//--
+
+#define MlidAddressEqual(Address1, Address2) \
+ ((Address1)[4] == (Address2)[4] && \
+ MlidCompareMemory((Address1), (Address2), ETH_LENGTH_OF_ADDRESS) == 0)
+
+
+#endif // MLIDSFT
+
+
+
+
+
+
+
diff --git a/private/ntos/ndis/odimac/odihsm.h b/private/ntos/ndis/odimac/odihsm.h
new file mode 100644
index 000000000..0d17f1c0c
--- /dev/null
+++ b/private/ntos/ndis/odimac/odihsm.h
@@ -0,0 +1,418 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ odihsm.h
+
+Abstract:
+
+ This contains all the definitions for the ODI HSM structures.
+
+Author:
+
+ Sean Selitrennikoff (seanse) 15-Jan-92
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+
+--*/
+
+
+typedef struct _ADAPTER_STRUC{
+
+ UCHAR bus_type; // 0 = ISA, 1 = MCA
+
+ UCHAR mc_slot_num; // MCA bus only
+
+ USHORT pos_id; // Adapter POS ID (Mca only)
+
+ USHORT io_base; // Adapter I/O Base
+
+ PUCHAR adapter_text_ptr; // See LM_Get_Config
+
+ USHORT irq_value; // IRQ line used by hardware
+
+ USHORT rom_size; // num of 1K blocks
+
+ ULONG rom_base; // physical address of ROM
+
+ PVOID rom_access; // Pointer into VM of rom_base
+
+ USHORT ram_size; // num of 1K blocks
+
+ ULONG ram_base; // physical address of RAM
+
+ PVOID ram_access; // Pointer into VM of ram_base
+
+ USHORT ram_usable; // num of 1K blocks that can be accessed at once
+
+ USHORT io_base_new; // new i/o base addr for LM_Put_Config
+
+ UCHAR node_address[6]; // network address
+
+ UCHAR permanent_node_address[6]; // network address burned into card.
+
+ UCHAR multi_address[6]; // multicase address
+
+ USHORT max_packet_size; // for this MAC driver
+
+ USHORT buffer_page_size; // size of adapters RAM TX/RX buffer pages.
+
+ USHORT num_of_tx_buffs; // TX bufss in adapter RAM
+
+ USHORT receive_lookahead_size;
+
+ USHORT receive_mask;
+
+ USHORT adapter_status;
+
+ USHORT media_type;
+
+ USHORT bic_type;
+
+ USHORT nic_type;
+
+ USHORT adapter_type;
+
+ NDIS_HANDLE NdisAdapterHandle;
+
+ NDIS_MCA_POS_DATA PosData;
+
+ BOOLEAN TokenRing;
+
+ //
+ // Token Ring Specific stuff
+ //
+
+
+ USHORT ring_status;
+
+ UCHAR funct_address[4];
+
+ UCHAR group_address[6];
+
+ //
+ // These counters must be initialized by the upper layer.
+ //
+
+
+ //
+ // Common counters...
+ //
+
+ PULONG ptr_rx_CRC_errors;
+
+ PULONG ptr_rx_lost_pkts;
+
+
+ //
+ // Token Ring counters
+ //
+
+ PULONG ptr_rx_congestion;
+
+ PULONG ptr_FCS_error;
+
+ PULONG ptr_burst_error;
+
+ PULONG ptr_AC_error;
+
+ PULONG ptr_tx_abort_delimiter;
+
+ PULONG ptr_tx_failed_return;
+
+ PULONG ptr_frames_copied;
+
+ PULONG ptr_frequency_error;
+
+ PULONG ptr_monitor_gen_count;
+
+ PULONG ptr_DMA_underruns;
+
+ //
+ // Ethernet specific counters. Must be initialized by upper layer.
+ //
+
+ PULONG ptr_rx_too_big;
+
+ PULONG ptr_rx_align_errors;
+
+ PULONG ptr_rx_overruns;
+
+ PULONG ptr_tx_deferred;
+
+ PULONG ptr_tx_max_collisions;
+
+ PULONG ptr_tx_one_collision;
+
+ PULONG ptr_tx_mult_collisions;
+
+ PULONG ptr_tx_ow_collision;
+
+ PULONG ptr_tx_CD_heartbeat;
+
+ PULONG ptr_tx_carrier_lost;
+
+ PULONG ptr_tx_underruns;
+
+
+
+
+ ULONG board_id;
+
+ USHORT mode_bits;
+
+ USHORT status_bits;
+
+ USHORT xmit_buf_size;
+
+ USHORT config_mode; // 1 == Store config in EEROM
+
+
+
+
+ UCHAR State;
+
+ BOOLEAN BufferOverflow; // does an overflow need to be handled
+
+ UCHAR InterruptMask;
+
+ BOOLEAN UMRequestedInterrupt; // Has LM_Interrupt() been called.
+
+
+
+ NDIS_INTERRUPT NdisInterrupt; // interrupt info used by wrapper
+
+ UCHAR Current;
+
+ //
+ // Transmit information.
+ //
+
+ XMIT_BUF NextBufToFill; // where to copy next packet to
+ XMIT_BUF NextBufToXmit; // valid if CurBufXmitting is -1
+ XMIT_BUF CurBufXmitting; // -1 if none is
+ BOOLEAN TransmitInterruptPending; // transmit interrupt and overwrite error?
+ UINT PacketLens[MAX_XMIT_BUFS];
+ BUFFER_STATUS BufferStatus[MAX_XMIT_BUFS];
+
+ PUCHAR ReceiveStart; // start of card receive area
+ PUCHAR ReceiveStop; // end of card receive area
+
+
+ //
+ // Loopback information
+ //
+
+ PNDIS_PACKET LoopbackQueue; // queue of packets to loop back
+ PNDIS_PACKET LoopbackQTail;
+ PNDIS_PACKET LoopbackPacket; // current one we are looping back
+
+ //
+ // Receive information
+ //
+
+ PUCHAR IndicatingPacket;
+ BOOLEAN OverWriteHandling; // Currently handling an overwrite
+ BOOLEAN OverWriteStartTransmit;
+ UCHAR StartBuffer; // Start buffer number to receive into
+ UCHAR LastBuffer; // Last buffer number + 1
+ UINT PacketLen;
+
+ //
+ // Interrupt Information
+ //
+
+ UCHAR LaarHold;
+
+ //
+ // Pointer to the filter database for the MAC.
+ //
+ PETH_FILTER FilterDB;
+
+}Adapter_Struc, *Ptr_Adapter_Struc;
+
+
+
+
+//
+// LMI Status and Return codes
+//
+
+typedef USHORT LM_STATUS;
+
+#define SUCCESS 0x0
+#define ADAPTER_AND_CONFIG 0x1 // Adapter found and config info gotten
+#define ADAPTER_NO_CONFIG 0x2 // Adapter found, no config info found
+#define NOT_MY_INTERRUPT 0x3 // No interrupt found in LM_Service_Events
+#define FRAME_REJECTED 0x4
+#define EVENTS_DISABLED 0x5 // Disables LM_Service_Events from reporting
+ // any further interrupts.
+#define OUT_OF_RESOURCES 0x6
+#define OPEN_FAILED 0x7
+#define HARDWARE_FAILED 0x8
+#define INITIALIZE_FAILED 0x9
+#define CLOSE_FAILED 0xA
+#define MAX_COLLISIONS 0xB
+#define FIFO_UNDERRUN 0xC
+#define BUFFER_TOO_SMALL 0xD
+#define ADAPTER_CLOSED 0xE
+#define FAILURE 0xF
+
+#define REQUEUE_LATER 0x12
+
+#define INVALID_FUNCTION 0x80
+#define INVALID_PARAMETER 0x81
+
+#define ADAPTER_NOT_FOUND 0xFFFF
+
+
+
+//
+// Function Definitions.
+//
+
+
+extern
+LM_STATUS
+LM_Send(
+ PNDIS_PACKET Packet,
+ Ptr_Adapter_Struc Adapter
+ );
+
+
+
+extern
+LM_STATUS
+LM_Interrupt_req(
+ Ptr_Adapter_Struc Adapter
+ );
+
+
+extern
+LM_STATUS
+LM_Service_Receive_Events(
+ Ptr_Adapter_Struc Adapter
+ );
+
+extern
+LM_STATUS
+LM_Service_Transmit_Events(
+ Ptr_Adapter_Struc Adapter
+ );
+
+
+extern
+LM_STATUS
+LM_Receive_Copy(
+ PULONG Bytes_Transferred,
+ ULONG Byte_Count,
+ ULONG Offset,
+ PNDIS_PACKET Packet,
+ Ptr_Adapter_Struc Adapter
+ );
+
+
+extern
+LM_STATUS
+LM_Receive_Lookahead(
+ ULONG Byte_Count,
+ ULONG Offset,
+ PUCHAR Buffer,
+ Ptr_Adapter_Struc Adapter
+ );
+
+extern
+LM_STATUS
+LM_Get_Mca_Io_Base_Address(
+ IN Ptr_Adapter_Struc Adapt,
+ IN NDIS_HANDLE ConfigurationHandle,
+ OUT USHORT *IoBaseAddress
+ );
+
+extern
+LM_STATUS
+LM_Get_Config(
+ Ptr_Adapter_Struc Adapter
+ );
+
+extern
+LM_STATUS
+LM_Free_Resources(
+ Ptr_Adapter_Struc Adapt
+ );
+
+extern
+LM_STATUS
+LM_Initialize_Adapter(
+ Ptr_Adapter_Struc Adapter
+ );
+
+
+extern
+LM_STATUS
+LM_Open_Adapter(
+ Ptr_Adapter_Struc Adapter
+ );
+
+
+extern
+LM_STATUS
+LM_Close_Adapter(
+ Ptr_Adapter_Struc Adapter
+ );
+
+
+extern
+LM_STATUS
+LM_Disable_Adapter(
+ Ptr_Adapter_Struc Adapter
+ );
+
+extern
+LM_STATUS
+LM_Disable_Adapter_Receives(
+ Ptr_Adapter_Struc Adapt
+ );
+
+extern
+LM_STATUS
+LM_Disable_Adapter_Transmits(
+ Ptr_Adapter_Struc Adapt
+ );
+
+extern
+LM_STATUS
+LM_Enable_Adapter(
+ Ptr_Adapter_Struc Adapter
+ );
+
+
+extern
+LM_STATUS
+LM_Enable_Adapter_Receives(
+ Ptr_Adapter_Struc Adapt
+ );
+
+extern
+LM_STATUS
+LM_Enable_Adapter_Transmits(
+ Ptr_Adapter_Struc Adapt
+ );
+
+#define LM_Set_Multi_Address(Addresses, Count, Adapter) (SUCCESS)
+
+
+extern
+LM_STATUS
+LM_Set_Receive_Mask(
+ Ptr_Adapter_Struc Adapter
+ );
+
+
diff --git a/private/ntos/ndis/odimac/umi.c b/private/ntos/ndis/odimac/umi.c
new file mode 100644
index 000000000..d007f8af8
--- /dev/null
+++ b/private/ntos/ndis/odimac/umi.c
@@ -0,0 +1,336 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ umi.c
+
+Abstract:
+
+ Upper MAC Interface functions for the NDIS 3.0 Western Digital driver.
+
+Author:
+
+ Sean Selitrennikoff (seanse) 15-Jan-92
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+#include <efilter.h>
+#include "wdlmi.h"
+#include "wdhrd.h"
+#include "wdsft.h"
+#include "wdumi.h"
+
+
+
+#if DBG
+
+extern UCHAR WdDebugLog[];
+extern UCHAR WdDebugLogPlace;
+
+#define IF_LOG(A) A
+
+#else
+
+#define IF_LOG(A)
+
+#endif
+
+
+LM_STATUS
+UM_Send_Complete(
+ LM_STATUS Status,
+ Ptr_Adapter_Struc Adapt
+ )
+/*++
+
+Routine Description:
+
+ This routine is called back when the packet on the front of
+ PacketsOnCard has been fully transmitted by the Lower MAC.
+
+
+ NOTE: The lock is held before the LM_ routines are called and
+ therefore held at the beginning of this call.
+
+Arguments:
+
+ Status - Status of the send.
+
+ Adapt - A pointer to an LMI adapter structure.
+
+Return:
+
+ SUCCESS
+ EVENTS_DISABLED
+
+--*/
+{
+
+ PWD_ADAPTER Adapter = PWD_ADAPTER_FROM_Ptr_Adapter_Struc(Adapt);
+ PWD_OPEN Open;
+ PNDIS_PACKET Packet;
+
+
+
+ ASSERT(Adapter->PacketsOnCard != NULL);
+
+ IF_LOG(LOG('c'));
+
+ //
+ // Remove Packet from list.
+ //
+
+ Packet = Adapter->PacketsOnCard;
+
+ Adapter->PacketsOnCard = RESERVED(Packet)->NextPacket;
+
+ if (Adapter->PacketsOnCard == NULL) {
+
+ Adapter->PacketsOnCardTail = NULL;
+
+ }
+
+ Open = RESERVED(Packet)->Open;
+
+
+ IF_LOUD( DbgPrint("Completing send for open 0x%lx\n",Open);)
+
+
+ if (RESERVED(Packet)->Loopback) {
+
+ //
+ // Put packet on loopback
+ //
+
+ if (Adapter->LoopbackQueue == NULL) {
+
+ Adapter->LoopbackQueue = Adapter->LoopbackQTail = Packet;
+
+ } else {
+
+ RESERVED(Adapter->LoopbackQTail)->NextPacket = Packet;
+
+ Adapter->LoopbackQTail = Packet;
+
+ }
+
+ RESERVED(Packet)->NextPacket = NULL;
+
+ } else {
+
+ IF_LOUD( DbgPrint("Not a loopback packet\n");)
+
+ //
+ // Complete send
+ //
+
+ if (Status == SUCCESS) {
+ Adapter->FramesXmitGood++;
+ } else {
+ Adapter->FramesXmitBad++;
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteSend(Open->NdisBindingContext,
+ Packet,
+ (Status == SUCCESS ? NDIS_STATUS_SUCCESS :
+ NDIS_STATUS_FAILURE)
+ );
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ WdRemoveReference(Open);
+
+ }
+
+ //
+ // If there are any sends waiting and there is not a reset to be
+ // done, queue them up
+ //
+
+ if ((Adapter->XmitQueue != NULL) && !(Adapter->ResetRequested)) {
+
+ //
+ // Remove packet from front.
+ //
+
+ Packet = Adapter->XmitQueue;
+
+ Adapter->XmitQueue = RESERVED(Packet)->NextPacket;
+
+ if (Adapter->XmitQueue == NULL) {
+
+ Adapter->XmitQTail = NULL;
+
+ }
+
+ //
+ // Start packet send.
+ //
+
+ IF_LOG(LOG('t'));
+
+ Status = LM_Send(Packet, Adapt);
+
+ if (Status == OUT_OF_RESOURCES) {
+
+ IF_LOG(LOG('2'));
+
+ //
+ // Put packet back on xmit queue.
+ //
+
+ if (Adapter->XmitQueue != NULL) {
+
+ RESERVED(Packet)->NextPacket = Adapter->XmitQueue;
+
+ Adapter->XmitQueue = Packet;
+
+ } else {
+
+ Adapter->XmitQueue = Packet;
+
+ Adapter->XmitQTail = Packet;
+
+ }
+
+ } else if (Status == SUCCESS) {
+
+ //
+ // Put packet at end of card list.
+ //
+
+ if (Adapter->PacketsOnCard == NULL) {
+
+ Adapter->PacketsOnCard = Adapter->PacketsOnCardTail = Packet;
+
+ } else {
+
+ RESERVED(Adapter->PacketsOnCardTail)->NextPacket = Packet;
+
+ Adapter->PacketsOnCardTail = Packet;
+
+ }
+
+ RESERVED(Packet)->NextPacket = NULL;
+
+ }
+
+ }
+
+ IF_LOG(LOG('C'));
+
+ return(SUCCESS);
+
+}
+
+
+LM_STATUS
+UM_Receive_Packet(
+ ULONG PacketSize,
+ Ptr_Adapter_Struc Adapt
+ )
+/*++
+
+Routine Description:
+
+ This routine is called whenever the lower MAC receives a packet.
+
+
+Arguments:
+
+ PacketSize - Total size of the packet
+
+ Adapt - A pointer to an LMI adapter structure.
+
+Return:
+
+ SUCCESS
+ EVENTS_DISABLED
+
+--*/
+{
+ PWD_ADAPTER Adapter = PWD_ADAPTER_FROM_Ptr_Adapter_Struc(Adapt);
+ ULONG IndicateLen;
+
+ //
+ // Setup for indication
+ //
+
+ Adapter->IndicatedAPacket = TRUE;
+
+ Adapter->IndicatingPacket = (PNDIS_PACKET)NULL;
+
+ IndicateLen = ((Adapter->MaxLookAhead + WD_HEADER_SIZE) > PacketSize ?
+ PacketSize :
+ Adapter->MaxLookAhead + WD_HEADER_SIZE
+ );
+
+ if (LM_Receive_Lookahead(
+ IndicateLen,
+ 0,
+ Adapter->LookAhead,
+ &(Adapter->LMAdapter)) != SUCCESS) {
+
+ return(SUCCESS);
+
+ }
+
+ //
+ // Indicate packet
+ //
+
+ Adapter->FramesRcvGood++;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ if (PacketSize < WD_HEADER_SIZE) {
+
+ if (PacketSize >= ETH_LENGTH_OF_ADDRESS) {
+
+ //
+ // Runt packet
+ //
+
+ EthFilterIndicateReceive(
+ Adapt->FilterDB,
+ (NDIS_HANDLE)Adapter,
+ (PCHAR)Adapter->LookAhead,
+ Adapter->LookAhead,
+ PacketSize,
+ NULL,
+ 0,
+ 0
+ );
+
+ }
+
+ } else {
+
+ EthFilterIndicateReceive(
+ Adapt->FilterDB,
+ (NDIS_HANDLE)Adapter,
+ (PCHAR)Adapter->LookAhead,
+ Adapter->LookAhead,
+ WD_HEADER_SIZE,
+ Adapter->LookAhead + WD_HEADER_SIZE,
+ IndicateLen - WD_HEADER_SIZE,
+ PacketSize - WD_HEADER_SIZE
+ );
+ }
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ return(SUCCESS);
+}
diff --git a/private/ntos/ndis/pc586e/filter.c b/private/ntos/ndis/pc586e/filter.c
new file mode 100644
index 000000000..fe2445595
--- /dev/null
+++ b/private/ntos/ndis/pc586e/filter.c
@@ -0,0 +1,1824 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ filter.c
+
+Abstract:
+
+ This module implements a set of library routines to handle packet
+ filtering for NDIS MAC drivers.
+
+Author:
+
+ Anthony V. Ercolano (Tonye) 03-Aug-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+
+--*/
+
+#include <ntos.h>
+#include <ndis.h>
+#include <filter.h>
+
+//
+// ZZZ NonPortable definitions.
+//
+#define AllocPhys(s) ExAllocatePool(NonPagedPool,(s))
+#define FreePhys(s) ExFreePool((s))
+#define MoveMemory(Destination,Source,Length) RtlMoveMemory(Destination,Source,Length)
+#define ZeroMemory(Destination,Length) RtlZeroMemory(Destination,Length)
+
+//
+// A set of macros to manipulate bitmasks.
+//
+
+//VOID
+//CLEAR_BIT_IN_MASK(
+// IN UINT Offset,
+// IN OUT PMASK MaskToClear
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Clear a bit in the bitmask pointed to by the parameter.
+//
+//Arguments:
+//
+// Offset - The offset (from 0) of the bit to altered.
+//
+// MaskToClear - Pointer to the mask to be adjusted.
+//
+//Return Value:
+//
+// None.
+//
+//--*/
+//
+#define CLEAR_BIT_IN_MASK(Offset,MaskToClear) *MaskToClear &= (~(1 << Offset))
+
+//VOID
+//SET_BIT_IN_MASK(
+// IN UINT Offset,
+// IN OUT PMASK MaskToSet
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Set a bit in the bitmask pointed to by the parameter.
+//
+//Arguments:
+//
+// Offset - The offset (from 0) of the bit to altered.
+//
+// MaskToSet - Pointer to the mask to be adjusted.
+//
+//Return Value:
+//
+// None.
+//
+//--*/
+#define SET_BIT_IN_MASK(Offset,MaskToSet) *MaskToSet |= (1 << Offset)
+
+//BOOLEAN
+//IS_BIT_SET_IN_MASK(
+// IN UINT Offset,
+// IN MASK MaskToTest
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Tests if a particular bit in the bitmask pointed to by the parameter is
+// set.
+//
+//Arguments:
+//
+// Offset - The offset (from 0) of the bit to test.
+//
+// MaskToTest - The mask to be tested.
+//
+//Return Value:
+//
+// Returns TRUE if the bit is set.
+//
+//--*/
+#define IS_BIT_SET_IN_MASK(Offset,MaskToTest) \
+((MaskToTest & (1 << Offset))?(TRUE):(FALSE))
+
+//BOOLEAN
+//IS_MASK_CLEAR(
+// IN MASK MaskToTest
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Tests whether there are *any* bits enabled in the mask.
+//
+//Arguments:
+//
+// MaskToTest - The bit mask to test for all clear.
+//
+//Return Value:
+//
+// Will return TRUE if no bits are set in the mask.
+//
+//--*/
+#define IS_MASK_CLEAR(MaskToTest) ((!MaskToTest)?(TRUE):(FALSE))
+
+//VOID
+//CLEAR_MASK(
+// IN OUT PMASK MaskToClear
+// );
+//
+///*++
+//
+//Routine Description:
+//
+// Clears a mask.
+//
+//Arguments:
+//
+// MaskToClear - The bit mask to adjust.
+//
+//Return Value:
+//
+// None.
+//
+//--*/
+#define CLEAR_MASK(MaskToClear) *MaskToClear = 0
+
+static
+BOOLEAN
+FindMulticast(
+ IN UINT NumberOfAddresses,
+ IN CHAR AddressArray[][MAC_LENGTH_OF_ADDRESS],
+ IN CHAR MulticastAddress[MAC_LENGTH_OF_ADDRESS],
+ OUT PUINT ArrayIndex
+ );
+
+
+BOOLEAN
+MacCreateFilter(
+ IN UINT MaximumMulticastAddresses,
+ IN UINT MaximumOpenAdapters,
+ IN MAC_ADDRESS_DELETE DeleteAction,
+ IN MAC_ADDRESS_ADD AddAction,
+ IN MAC_FILTER_CHANGE ChangeAction,
+ IN MAC_DEFERRED_CLOSE CloseAction,
+ IN PNDIS_SPIN_LOCK Lock,
+ OUT PMAC_FILTER *Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to create and initialize the filter database.
+
+Arguments:
+
+ MaximumMulticastAddresses - The maximum number of multicast addresses
+ that the MAC will support.
+
+ MaximumOpenAdapters - The maximum number of bindings that will be
+ open at any one time.
+
+ DeleteAction - Action routine to call when a binding deletes a
+ multicast address from the filter and it is the last binding to
+ desire the address.
+
+ AddAction - Action routine to call when a binding adds a multicast
+ address and it is the first binding to request the address.
+
+ ChangeAction - Action routine to call when a binding sets or clears
+ a particular filter class and it is the first or only binding using
+ the filter class.
+
+ CloseAction - This routine is called if a binding closes while
+ it is being indicated to via NdisIndicateReceive. It will be
+ called upon return from NdisIndicateReceive.
+
+ Lock - Pointer to the lock that should be held when mutual exclusion
+ is required.
+
+ Filter - A pointer to a MAC_FILTER. This is what is allocated and
+ created by this routine.
+
+Return Value:
+
+ If the function returns false then one of the parameters exceeded
+ what the filter was willing to support.
+
+--*/
+
+{
+
+ PMAC_FILTER LocalFilter;
+
+ //
+ // Make sure that the mask is 32 bits
+ //
+ // Make sure that the number of bindings don't
+ // exceed what we're prepared to support.
+ //
+
+ if (MaximumOpenAdapters > (sizeof(MASK)*8)) {
+ return FALSE;
+ }
+
+ //
+ // Allocate the database and it's associated arrays.
+ //
+
+ LocalFilter = AllocPhys(sizeof(MAC_FILTER));
+ *Filter = LocalFilter;
+
+ if (!LocalFilter) {
+ return FALSE;
+ }
+
+ ZeroMemory(
+ LocalFilter,
+ sizeof(MAC_FILTER)
+ );
+
+ LocalFilter->MulticastAddresses = AllocPhys(MAC_LENGTH_OF_ADDRESS*
+ MaximumMulticastAddresses);
+
+ if (!LocalFilter->MulticastAddresses) {
+
+ MacDeleteFilter(LocalFilter);
+ return FALSE;
+
+ }
+
+ LocalFilter->BindingsUsingAddress = AllocPhys(sizeof(MASK)*
+ MaximumMulticastAddresses
+ );
+
+ if (!LocalFilter->BindingsUsingAddress) {
+
+ MacDeleteFilter(LocalFilter);
+ return FALSE;
+
+ }
+
+ LocalFilter->BindingInfo = AllocPhys(sizeof(BINDING_INFO)*
+ MaximumOpenAdapters);
+
+ if (!LocalFilter->BindingInfo) {
+
+ MacDeleteFilter(LocalFilter);
+ return FALSE;
+
+ }
+
+ //
+ // Now link all of the binding info's together on a free list.
+ //
+
+ {
+
+ UINT i;
+
+ for (
+ i = 0,LocalFilter->FirstFreeBinding = 0;
+ i < MaximumOpenAdapters;
+ i++
+ ) {
+
+ LocalFilter->BindingInfo[i].FreeNext = i+1;
+
+ }
+
+ LocalFilter->BindingInfo[i].FreeNext = -1;
+ }
+
+ LocalFilter->IndicatingBinding = -1;
+ LocalFilter->CurrentBindingShuttingDown = FALSE;
+ LocalFilter->OpenStart = -1;
+ LocalFilter->OpenEnd = -1;
+
+ LocalFilter->Lock = Lock;
+
+ LocalFilter->DeleteAction = DeleteAction;
+ LocalFilter->AddAction = AddAction;
+ LocalFilter->ChangeAction = ChangeAction;
+ LocalFilter->CloseAction = CloseAction;
+
+ LocalFilter->NumberOfAddresses = 0;
+
+ LocalFilter->MaximumMulticastAddresses = MaximumMulticastAddresses;
+
+ return TRUE;
+}
+
+VOID
+MacDeleteFilter(
+ IN PMAC_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to delete the memory associated with a filter
+ database. Note that this routines *ASSUMES* that the database
+ has been cleared of any active filters.
+
+Arguments:
+
+ Filter - A pointer to a MAC_FILTER to be deleted.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ASSERT(Filter->OpenStart == -1);
+
+ if (Filter->MulticastAddresses) {
+
+ FreePhys(Filter->MulticastAddresses);
+
+ }
+
+ if (Filter->BindingsUsingAddress) {
+
+ FreePhys(Filter->BindingsUsingAddress);
+
+ }
+
+ if (Filter->BindingInfo) {
+
+ FreePhys(Filter->BindingInfo);
+
+ }
+
+ FreePhys(Filter);
+
+
+
+}
+
+BOOLEAN
+MacNoteFilterOpenAdapter(
+ IN PMAC_FILTER Filter,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE NdisBindingContext,
+ OUT PUINT FilterIndex
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to add a new binding to the filter database.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE DATABASE IS LOCKED WHEN
+ IT IS CALLED.
+
+Arguments:
+
+ Filter - A pointer to the previously created and initialized filter
+ database.
+
+ MacBindingHandle - The MAC supplied value to the protocol in response
+ to a call to MacOpenAdapter.
+
+ NdisBindingContext - An NDIS supplied value to the call to MacOpenAdapter.
+
+ FilterIndex - A pointer to a UINT which will receive the value of the
+ filter index.
+
+Return Value:
+
+ Will return false if creating a new filter index will cause the maximum
+ number of filter indexes to be exceeded.
+
+--*/
+
+{
+
+ //
+ // Will hold the value of the filter index so that we
+ // need not indirectly address through pointer parameter.
+ //
+ UINT LocalIndex;
+
+
+ //
+ // Get the first free binding slot and remove that slot from
+ // the free list. We check to see if the list is empty.
+ //
+
+ LocalIndex = Filter->FirstFreeBinding;
+
+ if (LocalIndex == -1) {
+
+ return FALSE;
+
+ }
+
+ Filter->FirstFreeBinding = Filter->BindingInfo[LocalIndex].FreeNext;
+
+ //
+ // We put this new binding at the end of the open list.
+ //
+
+ Filter->BindingInfo[LocalIndex].OpenNext = -1;
+ Filter->BindingInfo[LocalIndex].OpenPrev = Filter->OpenEnd;
+
+ if (Filter->OpenEnd != -1) {
+
+ //
+ // The open list was *not* empty. Update the previous end
+ // to point to this new element.
+ //
+
+ Filter->BindingInfo[Filter->OpenEnd].OpenNext = LocalIndex;
+
+ } else {
+
+ //
+ // The list was empty. We make sure that the start now points
+ // to this element.
+ //
+
+ Filter->OpenStart = LocalIndex;
+
+ }
+
+ //
+ // This is the new end of the list.
+ //
+
+ Filter->OpenEnd = LocalIndex;
+
+
+ //
+ // If we have a currently indicating binding that is shutting
+ // down and it was the end of the list. we want to make sure that
+ // it knows about us, so that when it is finished indicating, we
+ // will also be indicated next. This check is special since
+ // a problem occurs if the binding was shutting down. When
+ // a binding is shutting down (and indicating) it is removed from
+ // the list of open bindings.
+ //
+
+ if ((Filter->IndicatingBinding != -1) &&
+ (Filter->CurrentBindingShuttingDown) &&
+ (Filter->BindingInfo[Filter->IndicatingBinding].OpenNext == -1)) {
+
+ Filter->BindingInfo[Filter->IndicatingBinding].OpenNext = LocalIndex;
+
+ }
+
+ Filter->BindingInfo[LocalIndex].MacBindingHandle = MacBindingHandle;
+ Filter->BindingInfo[LocalIndex].NdisBindingContext = NdisBindingContext;
+ Filter->BindingInfo[LocalIndex].PacketFilters = 0;
+
+ *FilterIndex = LocalIndex;
+
+ return TRUE;
+
+}
+
+NDIS_STATUS
+MacDeleteFilterOpenAdapter(
+ IN PMAC_FILTER Filter,
+ IN UINT FilterIndex,
+ IN NDIS_HANDLE RequestHandle
+ )
+
+/*++
+
+Routine Description:
+
+ When an adapter is being closed this routine should
+ be called to delete knowledge of the adapter from
+ the filter database. This routine is likely to call
+ action routines associated with clearing filter classes
+ and addresses.
+
+ NOTE: THIS ROUTINE SHOULD ****NOT**** BE CALLED IF THE ACTION
+ ROUTINES FOR DELETING THE FILTER CLASSES OR THE MULTICAST ADDRESSES
+ HAVE ANY POSSIBILITY OF RETURNING A STATUS OTHER THAN NDIS_STATUS_PENDING
+ OR NDIS_STATUS_SUCCESS. WHILE THESE ROUTINES WILL NOT BUGCHECK IF
+ SUCH A THING IS DONE, THE CALLER WILL PROBABLY FIND IT DIFFICULT
+ TO CODE A CLOSE ROUTINE!
+
+ NOTE: THIS ROUTINE ASSUMES THAT IT IS CALLED WITH THE LOCK HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ FilterIndex - A value returned by a previous call to NoteFilterOpenAdapter.
+
+ RequestHandle - If it is necessary to call the action routines,
+ this will be passed to it.
+
+Return Value:
+
+ If action routines are called by the various address and filtering
+ routines the this routine will likely return the status returned
+ by those routines. The exception to this rule is noted below.
+
+ Given that the filter and address deletion routines return a status
+ NDIS_STATUS_PENDING or NDIS_STATUS_SUCCESS this routine will then
+ try to return the filter index to the freelist. If the routine
+ detects that this binding is currently being indicated to via
+ NdisIndicateReceive, this routine will return a status of
+ NDIS_STATUS_CLOSING_INDICATING.
+
+--*/
+
+{
+
+ //
+ // Used to index into the array of address filters.
+ //
+ UINT CurrentAddress;
+
+ //
+ // Holds the status returned from the packet filter and address
+ // deletion routines. Will be used to return the status to
+ // the caller of this routine.
+ //
+ NDIS_STATUS StatusToReturn;
+
+ StatusToReturn = MacFilterAdjust(
+ Filter,
+ FilterIndex,
+ RequestHandle,
+ (UINT)0,
+ FALSE
+ );
+
+ //
+ // Loop through all of the filter addresses. If the bit is present
+ // then call the delete address routine.
+ //
+
+ CurrentAddress = 0;
+ while ((CurrentAddress < Filter->NumberOfAddresses) &&
+ ((StatusToReturn == NDIS_STATUS_SUCCESS) ||
+ (StatusToReturn == NDIS_STATUS_PENDING))) {
+
+ if (IS_BIT_SET_IN_MASK(
+ FilterIndex,
+ Filter->BindingsUsingAddress[CurrentAddress]
+ )) {
+
+ StatusToReturn = MacDeleteFilterAddress(
+ Filter,
+ FilterIndex,
+ RequestHandle,
+ Filter->MulticastAddresses[CurrentAddress]
+ );
+
+ } else {
+
+ //
+ // We don't increment the current address in the found
+ // case since all the addresses have been moved "down".
+ //
+
+ CurrentAddress++;
+
+ }
+
+ }
+
+ if ((StatusToReturn == NDIS_STATUS_SUCCESS) ||
+ (StatusToReturn == NDIS_STATUS_PENDING)) {
+
+ //
+ // Update the binding previous to us to point to the binding
+ // next to us.
+ //
+
+ if (Filter->BindingInfo[FilterIndex].OpenPrev != -1) {
+
+ Filter->BindingInfo[
+ Filter->BindingInfo[FilterIndex].OpenPrev].OpenNext =
+ Filter->BindingInfo[FilterIndex].OpenNext;
+
+ } else {
+
+ //
+ // This is the first binding on the list. Make sure
+ // that the list head is correct.
+ //
+
+ Filter->OpenStart = Filter->BindingInfo[FilterIndex].OpenNext;
+
+ }
+
+ //
+ // Update the binding next to us to point to the binding previous
+ // to us.
+ //
+
+ if (Filter->BindingInfo[FilterIndex].OpenNext != -1) {
+
+ Filter->BindingInfo[
+ Filter->BindingInfo[FilterIndex].OpenNext].OpenPrev =
+ Filter->BindingInfo[FilterIndex].OpenPrev;
+
+ } else {
+
+ //
+ // This was the last open binding on the list. Update
+ // the end pointer.
+ //
+
+ Filter->OpenEnd = -1;
+
+ }
+
+ //
+ // If this is not the currently indicated binding then
+ // put it back on the free list. Note that it won't
+ // be able to be reallocated until we're done here.
+ //
+
+ if (FilterIndex != Filter->IndicatingBinding) {
+
+ //
+ // This was not the currently indicating binding.
+ //
+ // We check to see if there is a currently indicating
+ // binding. If there is one, and it is shutting down
+ // AND this binding used to be next after the indicating
+ // binding, we need to point the indicating binding to
+ // the binding after this one.
+ //
+
+ if ((Filter->IndicatingBinding != -1) &&
+ (Filter->CurrentBindingShuttingDown) &&
+ (Filter->BindingInfo[Filter->IndicatingBinding].OpenNext ==
+ FilterIndex)) {
+
+ Filter->BindingInfo[Filter->IndicatingBinding].OpenNext =
+ Filter->BindingInfo[FilterIndex].OpenNext;
+
+ }
+
+ //
+ // Put the binding back on the free list.
+ //
+
+ Filter->BindingInfo[FilterIndex].FreeNext =
+ Filter->FirstFreeBinding;
+ Filter->FirstFreeBinding = FilterIndex;
+
+ } else {
+
+ //
+ // Note that this filter index is shutting down.
+ //
+
+ Filter->CurrentBindingShuttingDown = TRUE;
+
+ //
+ // Let the caller know that this "reference" to the open
+ // is still "active". The close action routine will be
+ // called upon return from NdisIndicateReceive.
+ //
+
+ StatusToReturn = NDIS_STATUS_CLOSING_INDICATING;
+
+ }
+
+ }
+
+ return StatusToReturn;
+
+}
+
+NDIS_STATUS
+MacAddFilterAddress(
+ IN PMAC_FILTER Filter,
+ IN UINT FilterIndex,
+ IN NDIS_HANDLE RequestHandle,
+ IN CHAR MulticastAddress[MAC_LENGTH_OF_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a binding has a multicast
+ address to add to the filter. An action routine will
+ be called when this routine determines that no other
+ binding has asked for this multicast address.
+
+ If the action routine returns a value other than pending or
+ success then this routine has no effect on the multicast addresses
+ for the open or for the adapter as a whole.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ FilterIndex - An index returned by a previous call to
+ NoteFilterOpenAdapter.
+
+ RequestHandle - If it is necessary to call the action routine,
+ this will be passed to it.
+
+ MulticastAddress - The multicast address to add to the filter.
+
+Return Value:
+
+ If it calls the action routine then it will return the
+ status returned by the action routine. If the status
+ returned by the action routine is anything other than
+ NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
+ will be returned to the state it was in upon entrance to this
+ routine.
+
+ If the action routine is not called this routine will return
+ the following statum:
+
+ NDIS_MULTICAST_EXISTS - If the address was already being used
+ by this filter index.
+
+ NDIS_STATUS_SUCCESS - If the address was already in the
+ base and this filter index was not already referencing it.
+
+ NDIS_MULTICAST_LIST_FULL - returned if the maximum number of addresses
+ were already in the multicast address list.
+
+--*/
+
+{
+
+ //
+ // Given to the find multicast routine. It will either point
+ // to the location of the multicast address in the array of
+ // multicast addresses or it will point to the place it should
+ // be.
+ //
+ UINT ArrayIndex;
+
+ NDIS_STATUS StatusOfAdd;
+
+ //
+ // Call the Search routine. If it finds it it will
+ // return TRUE and it will set the index parameter to
+ // indicate where it found it. If it couldn't find
+ // it will return FALSE and set the index parameter to
+ // indicate where it should go.
+ //
+
+ if (FindMulticast(
+ Filter->NumberOfAddresses,
+ Filter->MulticastAddresses,
+ MulticastAddress,
+ &ArrayIndex
+ )) {
+
+ //
+ // We can be sure that at least one other open was using this
+ // address.
+ //
+
+ ASSERT(!IS_MASK_CLEAR(Filter->BindingsUsingAddress[ArrayIndex]));
+
+ //
+ // Make sure that the address wasn't already being used by this
+ // open.
+ //
+
+ if (IS_BIT_SET_IN_MASK(
+ FilterIndex,
+ Filter->BindingsUsingAddress[ArrayIndex]
+ )) {
+
+ StatusOfAdd = NDIS_MULTICAST_EXISTS;
+
+ } else {
+
+ //
+ // Mark that this binding wishes to receive it.
+ //
+
+ SET_BIT_IN_MASK(
+ FilterIndex,
+ &Filter->BindingsUsingAddress[ArrayIndex]
+ );
+
+ StatusOfAdd = NDIS_STATUS_SUCCESS;
+
+ }
+
+ } else {
+
+ //
+ // Nobody using this address. First we check to make sure that
+ // there is available space in the filter. If there isn't then
+ // we return FALSE to the MAC. If there is space for the address,
+ // add the address and call the action routine so that the MAC can
+ // do something appropriate.
+ //
+
+ if (Filter->NumberOfAddresses < Filter->MaximumMulticastAddresses) {
+
+ MoveMemory(
+ Filter->MulticastAddresses[ArrayIndex+1],
+ Filter->MulticastAddresses[ArrayIndex],
+ (Filter->NumberOfAddresses-ArrayIndex)*MAC_LENGTH_OF_ADDRESS
+ );
+
+ MAC_COPY_NETWORK_ADDRESS(
+ Filter->MulticastAddresses[ArrayIndex],
+ MulticastAddress
+ );
+
+ MoveMemory(
+ &Filter->BindingsUsingAddress[ArrayIndex+1],
+ &Filter->BindingsUsingAddress[ArrayIndex],
+ (Filter->NumberOfAddresses-ArrayIndex)*(sizeof(MASK))
+ );
+
+ CLEAR_MASK(&Filter->BindingsUsingAddress[ArrayIndex]);
+
+ SET_BIT_IN_MASK(
+ FilterIndex,
+ &Filter->BindingsUsingAddress[ArrayIndex]
+ );
+
+ Filter->NumberOfAddresses++;
+ StatusOfAdd = Filter->AddAction(
+ Filter->NumberOfAddresses,
+ Filter->MulticastAddresses,
+ ArrayIndex,
+ Filter->BindingInfo[
+ FilterIndex
+ ].MacBindingHandle,
+ RequestHandle
+ );
+
+ if ((StatusOfAdd != NDIS_STATUS_SUCCESS) &&
+ (StatusOfAdd != NDIS_STATUS_PENDING)) {
+
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+
+ MoveMemory(
+ Filter->MulticastAddresses[ArrayIndex],
+ Filter->MulticastAddresses[ArrayIndex+1],
+ (Filter->NumberOfAddresses-(ArrayIndex+1))
+ *MAC_LENGTH_OF_ADDRESS
+ );
+
+ MoveMemory(
+ &Filter->BindingsUsingAddress[ArrayIndex],
+ &Filter->BindingsUsingAddress[ArrayIndex+1],
+ (Filter->NumberOfAddresses-(ArrayIndex+1))*(sizeof(MASK))
+ );
+
+ Filter->NumberOfAddresses--;
+
+ }
+
+ } else {
+
+ StatusOfAdd = NDIS_MULTICAST_LIST_FULL;
+
+ }
+
+ }
+
+ return StatusOfAdd;
+
+}
+
+NDIS_STATUS
+MacDeleteFilterAddress(
+ IN PMAC_FILTER Filter,
+ IN UINT FilterIndex,
+ IN NDIS_HANDLE RequestHandle,
+ IN CHAR MulticastAddress[MAC_LENGTH_OF_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a binding no longer desires
+ to receive packets destined for this multicast address.
+ An action routine will be called when this routine determines
+ that this is the only binding that wanted such packets.
+
+ If the action routine returns a value other than pending or
+ success then this routine has no effect on the multicast addresses
+ for the open or for the adapter as a whole.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ FilterIndex - An index returned by a previous call to
+ NoteFilterOpenAdapter.
+
+ RequestHandle - If it is necessary to call the action routine,
+ this will be passed to it.
+
+ MulticastAddress - The multicast address to delete the filter.
+
+Return Value:
+
+ If it calls the action routine then it will return the
+ status returned by the action routine. If the status
+ returned by the action routine is anything other than
+ NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
+ will be returned to the state it was in upon entrance to this
+ routine.
+
+ If the action routine is not called this routine will return
+ the following statum:
+
+ NDIS_MULTICAST_NOT_FOUND - The address itself wasn't in the database
+ or the address was in the database but this filter index wasn't
+ referencing it.
+
+ NDIS_MULTICAST_EXISTS - If the address was already being used
+ by this filter index.
+
+ NDIS_STATUS_SUCCESS - If the address was in the database and
+ this filter index was referencing it.
+
+--*/
+
+{
+
+ //
+ // Given to the find multicast routine. It will either point
+ // to the location of the multicast address in the array of
+ // multicast addresses or it will point to the place it should
+ // be.
+ //
+ UINT ArrayIndex;
+
+ //
+ // Holds the status returned to the user of this routine, if the
+ // action routine is not called then the status will be success
+ // or NDIS_MULTICAST_NOT_FOUND, otherwise, it is whatever the action
+ // routine returns.
+ //
+ NDIS_STATUS StatusOfDelete;
+
+ //
+ // Call the Search routine. If it finds it it will
+ // return TRUE and it will set the index parameter to
+ // indicate where it found it. If it couldn't find
+ // it will return FALSE and set the index parameter to
+ // indicate where it should go.
+ //
+
+ if (FindMulticast(
+ Filter->NumberOfAddresses,
+ Filter->MulticastAddresses,
+ MulticastAddress,
+ &ArrayIndex
+ )) {
+
+ //
+ // We know that no address in the array can be in there
+ // with a clear filter mask.
+ //
+
+ ASSERT(!IS_MASK_CLEAR(Filter->BindingsUsingAddress[ArrayIndex]));
+
+ //
+ // Make sure that the user is actually using this address. If
+ // the user isn't using the address tell them that it wasn't found.
+ //
+
+ if (IS_BIT_SET_IN_MASK(
+ FilterIndex,
+ Filter->BindingsUsingAddress[ArrayIndex]
+ )) {
+
+ //
+ // Clear the bit in the request filters part. If the
+ // requested filters is then zero we delete the address
+ // and call the action routine to notify the MAC.
+ //
+
+ CLEAR_BIT_IN_MASK(
+ FilterIndex,
+ &Filter->BindingsUsingAddress[ArrayIndex]
+ );
+ if (IS_MASK_CLEAR(Filter->BindingsUsingAddress[ArrayIndex])) {
+
+ MoveMemory(
+ Filter->MulticastAddresses[ArrayIndex],
+ Filter->MulticastAddresses[ArrayIndex+1],
+ (Filter->NumberOfAddresses-(ArrayIndex+1))
+ *MAC_LENGTH_OF_ADDRESS
+ );
+
+ MoveMemory(
+ &Filter->BindingsUsingAddress[ArrayIndex],
+ &Filter->BindingsUsingAddress[ArrayIndex+1],
+ (Filter->NumberOfAddresses-(ArrayIndex+1))*(sizeof(MASK))
+ );
+
+ Filter->NumberOfAddresses--;
+ StatusOfDelete = Filter->DeleteAction(
+ Filter->NumberOfAddresses,
+ Filter->MulticastAddresses,
+ MulticastAddress,
+ Filter->BindingInfo[
+ FilterIndex
+ ].MacBindingHandle,
+ RequestHandle
+ );
+
+ if ((StatusOfDelete != NDIS_STATUS_SUCCESS) &&
+ (StatusOfDelete != NDIS_STATUS_PENDING)) {
+
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+
+ MoveMemory(
+ Filter->MulticastAddresses[ArrayIndex+1],
+ Filter->MulticastAddresses[ArrayIndex],
+ (Filter->NumberOfAddresses-ArrayIndex)
+ *MAC_LENGTH_OF_ADDRESS
+ );
+
+ MAC_COPY_NETWORK_ADDRESS(
+ Filter->MulticastAddresses[ArrayIndex],
+ MulticastAddress
+ );
+
+ MoveMemory(
+ &Filter->BindingsUsingAddress[ArrayIndex+1],
+ &Filter->BindingsUsingAddress[ArrayIndex],
+ (Filter->NumberOfAddresses-ArrayIndex)*(sizeof(MASK))
+ );
+
+ Filter->NumberOfAddresses++;
+
+ CLEAR_MASK(&Filter->BindingsUsingAddress[ArrayIndex]);
+
+ SET_BIT_IN_MASK(
+ FilterIndex,
+ &Filter->BindingsUsingAddress[ArrayIndex]
+ );
+
+ }
+
+ } else {
+
+ StatusOfDelete = NDIS_STATUS_SUCCESS;
+
+ }
+
+ } else {
+
+ StatusOfDelete = NDIS_MULTICAST_NOT_FOUND;
+
+ }
+
+ } else {
+
+ StatusOfDelete = NDIS_MULTICAST_NOT_FOUND;
+
+ }
+
+ return StatusOfDelete;
+}
+
+NDIS_STATUS
+MacFilterAdjust(
+ IN PMAC_FILTER Filter,
+ IN UINT FilterIndex,
+ IN NDIS_HANDLE RequestHandle,
+ IN UINT FilterClasses,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ The FilterAdjust routine will call an action routine when a
+ particular filter class is changes from not being used by any
+ binding to being used by at least one binding or vice versa.
+
+ If the action routine returns a value other than pending or
+ success then this routine has no effect on the packet filters
+ for the open or for the adapter as a whole.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ FilterIndex - An index returned by a previous call to
+ NoteFilterOpenAdapter.
+
+ RequestHandle - If it is necessary to call the action routine,
+ this will be passed to it.
+
+ FilterClasses - The filter classes that are to be added or
+ deleted.
+
+ Set - A boolean that determines whether the filter classes
+ are being adjusted due to a set or because of a close. (The filtering
+ routines don't care, the MAC might.)
+
+Return Value:
+
+ If it calls the action routine then it will return the
+ status returned by the action routine. If the status
+ returned by the action routine is anything other than
+ NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
+ will be returned to the state it was in upon entrance to this
+ routine.
+
+ If the action routine is not called this routine will return
+ the following statum:
+
+ NDIS_STATUS_SUCCESS - If the new packet filters doesn't change
+ the combined mask of all bindings packet filters.
+
+--*/
+
+{
+ //
+ // Contains the value of the combined filter classes before
+ // it is adjusted.
+ //
+ UINT OldCombined = Filter->CombinedPacketFilter;
+
+ //
+ // Contains the value of the particlar opens packet filters
+ // prior to the change. We save this incase the action
+ // routine (if called) returns an "error" status.
+ //
+ UINT OldOpenFilters = Filter->BindingInfo[FilterIndex].PacketFilters;
+
+ //
+ // Holds the status returned to the user of this routine, if the
+ // action routine is not called then the status will be success,
+ // otherwise, it is whatever the action routine returns.
+ //
+ NDIS_STATUS StatusOfAdjust;
+
+ //
+ // Simple iteration variable.
+ //
+ INT i;
+
+ //
+ // Set the new filter information for the open.
+ //
+
+ Filter->BindingInfo[FilterIndex].PacketFilters = FilterClasses;
+
+ //
+ // We always have to reform the compbined filter since
+ // this filter index may have been the only filter index
+ // to use a particular bit.
+ //
+
+ for (
+ i = Filter->OpenStart,Filter->CombinedPacketFilter = 0;
+ i != -1;
+ i = Filter->BindingInfo[i].OpenNext
+ ) {
+
+ Filter->CombinedPacketFilter |=
+ Filter->BindingInfo[i].PacketFilters;
+
+ }
+
+ if (OldCombined != Filter->CombinedPacketFilter) {
+
+ StatusOfAdjust = Filter->ChangeAction(
+ OldCombined,
+ Filter->CombinedPacketFilter,
+ Filter->BindingInfo[FilterIndex].MacBindingHandle,
+ RequestHandle,
+ Set
+ );
+
+ if ((StatusOfAdjust != NDIS_STATUS_SUCCESS) &&
+ (StatusOfAdjust != NDIS_STATUS_PENDING)) {
+
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+
+ Filter->BindingInfo[FilterIndex].PacketFilters = OldOpenFilters;
+ Filter->CombinedPacketFilter = OldCombined;
+
+ }
+
+ } else {
+
+ StatusOfAdjust = NDIS_STATUS_SUCCESS;
+
+ }
+
+ return StatusOfAdjust;
+
+}
+
+VOID
+MacQueryFilterAddresses(
+ IN PMAC_FILTER Filter,
+ OUT PUINT NumberOfAddresses,
+ IN OUT CHAR AddressArray[][MAC_LENGTH_OF_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ The routine should be used by the MAC before
+ it actually alters the hardware registers to effect a
+ filtering hardware. This is usefull if another binding
+ has altered the address list since the action routine
+ is called.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NumberOfAddresses - Will receive the number of addresses currently in the
+ multicast address list.
+
+ AddressArray - Will be filled with the addresses currently in the
+ multicast address list.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ MoveMemory(
+ AddressArray[0],
+ Filter->MulticastAddresses[0],
+ Filter->NumberOfAddresses*MAC_LENGTH_OF_ADDRESS
+ );
+
+ *NumberOfAddresses = Filter->NumberOfAddresses;
+
+}
+
+VOID
+MacFilterIndicateReceive(
+ IN PMAC_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PCHAR Address,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate a packet to
+ all bindings. The packet will be filtered so that only the
+ appropriate bindings will receive the packet.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ MacReceiveContext - A MAC supplied context value that must be
+ returned by the protocol if it calls MacTransferData.
+
+ Address - The destination address from the received packet.
+
+ LookaheadBuffer - A virtual address of the virtually contiguous
+ buffer containing the first LookaheadBufferSize bytes of data
+ of the packet. The packet buffer is valid only within the current
+ call to the receive event handler.
+
+ LookaheadBufferSize - An unsigned integer indicating the size of
+ the lookahead buffer, in bytes.
+
+ PacketSize - An unsigned integer indicating the size of the received
+ packet, in bytes. This number has nothing to do with the lookahead
+ buffer, but indicates how large the arrived packet is so that a
+ subsequent MacTransferData request can be made to transfer the entire
+ packet as necessary.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Will hold the type of address that we know we've got.
+ //
+ UINT AddressType;
+
+ //
+ // Will hold the status of indicating the receive packet.
+ // ZZZ For now this isn't used.
+ //
+ NDIS_STATUS StatusOfReceive;
+
+ //
+ // Will hold the filter index of the binding being indicated.
+ //
+ UINT BindingToIndicate;
+
+ //
+ // Will hold the filter classes of the binding being indicated.
+ //
+ UINT BindingFilters;
+
+ //
+ //
+ // Determine whether the input address is a simple direct,
+ // a broadcast, or a multicast address.
+ //
+
+ {
+
+ //
+ // Holds the result of address determinations.
+ //
+ INT ResultOfAddressCheck;
+
+ //
+ // First check if it *at least* has the multicast address bit.
+ //
+
+ MAC_IS_MULTICAST(
+ Address,
+ &ResultOfAddressCheck
+ );
+
+ if (ResultOfAddressCheck) {
+
+ //
+ // It is at least a multicast address. Check to see if
+ // it is a broadcast address.
+ //
+
+ MAC_IS_BROADCAST(
+ Address,
+ &ResultOfAddressCheck
+ );
+
+ if (ResultOfAddressCheck) {
+
+ AddressType = NDIS_PACKET_TYPE_BROADCAST;
+
+ } else {
+
+ AddressType = NDIS_PACKET_TYPE_MULTICAST;
+
+ }
+
+ } else {
+
+ AddressType = NDIS_PACKET_TYPE_DIRECTED;
+
+ }
+
+ }
+
+ //
+ // We need to aquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+
+ NdisAcquireSpinLock(Filter->Lock);
+
+ BindingToIndicate = Filter->OpenStart;
+ Filter->IndicatingBinding = BindingToIndicate;
+
+ if (BindingToIndicate != -1) {
+
+ do {
+
+ BindingFilters =
+ Filter->BindingInfo[BindingToIndicate].PacketFilters;
+ NdisReleaseSpinLock(Filter->Lock);
+
+ //
+ // Do a quick check to make sure that this binding wants
+ // anything.
+ //
+
+ if (!BindingFilters) {
+
+ goto GetNextBinding;
+
+ }
+
+ //
+ // if the binding is promiscuous then it will get the packet
+ //
+
+ if (BindingFilters & NDIS_PACKET_TYPE_PROMISCUOUS) {
+
+ goto IndicatePacket;
+
+ }
+
+ //
+ // if the binding wants direct packets and this is a directly
+ // addressed packet then the binding gets the packet.
+ //
+
+ if (AddressType & (BindingFilters & NDIS_PACKET_TYPE_DIRECTED)) {
+
+ goto IndicatePacket;
+
+ }
+
+ //
+ // if the binding wants broadcast packets and the packet
+ // is a broadcast packet it will get the packet.
+ //
+
+ if (AddressType & (BindingFilters & NDIS_PACKET_TYPE_BROADCAST)) {
+
+ goto IndicatePacket;
+
+ }
+
+ //
+ // if the binding wants all multicast packets and the packet
+ // has a multicast address it will get the packet
+ //
+
+ if ((AddressType & NDIS_PACKET_TYPE_MULTICAST) &&
+ (BindingFilters & NDIS_PACKET_TYPE_ALL_MULTICAST)) {
+
+ goto IndicatePacket;
+
+ }
+
+ //
+ // if the binding wants multicast packets and the packet
+ // is a multicast packet and it's in the list of addresses
+ // it will get the packet.
+ //
+
+ if (AddressType & (BindingFilters & NDIS_PACKET_TYPE_MULTICAST)) {
+
+ //
+ // Will hold the index of the multicast
+ // address if it finds it.
+ //
+ UINT IndexOfAddress;
+
+ NdisAcquireSpinLock(Filter->Lock);
+
+ if (FindMulticast(
+ Filter->NumberOfAddresses,
+ Filter->MulticastAddresses,
+ Address,
+ &IndexOfAddress
+ )) {
+
+ if (IS_BIT_SET_IN_MASK(
+ BindingToIndicate,
+ Filter->BindingsUsingAddress[IndexOfAddress]
+ )) {
+
+ NdisReleaseSpinLock(Filter->Lock);
+ goto IndicatePacket;
+
+ }
+
+ } else {
+
+ NdisReleaseSpinLock(Filter->Lock);
+
+ }
+
+ }
+
+ goto GetNextBinding;
+
+IndicatePacket:;
+
+ //
+ // Indicate the packet to the binding.
+ //
+
+ NdisIndicateReceive(
+ &StatusOfReceive,
+ Filter->BindingInfo[BindingToIndicate].NdisBindingContext,
+ MacReceiveContext,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize
+ );
+
+GetNextBinding:;
+
+ NdisAcquireSpinLock(Filter->Lock);
+
+ if (Filter->CurrentBindingShuttingDown) {
+
+ //
+ // This binding is shutting down. We have to put
+ // it on the free list.
+ //
+
+ UINT CurrentBinding = BindingToIndicate;
+
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+
+ Filter->CloseAction(
+ Filter->BindingInfo[CurrentBinding].MacBindingHandle
+ );
+
+ BindingToIndicate =
+ Filter->BindingInfo[CurrentBinding].OpenNext;
+
+ Filter->BindingInfo[CurrentBinding].FreeNext =
+ Filter->FirstFreeBinding;
+ Filter->FirstFreeBinding = CurrentBinding;
+
+ Filter->CurrentBindingShuttingDown = FALSE;
+
+ } else {
+
+ BindingToIndicate =
+ Filter->BindingInfo[BindingToIndicate].OpenNext;
+
+ }
+
+ Filter->IndicatingBinding = BindingToIndicate;
+
+ } while (BindingToIndicate != -1);
+
+ }
+
+ NdisReleaseSpinLock(Filter->Lock);
+}
+
+static
+BOOLEAN
+FindMulticast(
+ IN UINT NumberOfAddresses,
+ IN CHAR AddressArray[][MAC_LENGTH_OF_ADDRESS],
+ IN CHAR MulticastAddress[MAC_LENGTH_OF_ADDRESS],
+ OUT PUINT ArrayIndex
+ )
+
+/*++
+
+Routine Description:
+
+ Given an array of multicast addresses search the array for
+ a particular multicast address. It is assumed that the
+ address array is already sorted.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+ NOTE: This ordering is arbitrary but consistant.
+
+Arguments:
+
+ NumberOfAddresses - The number of addresses currently in the
+ address array.
+
+ AddressArray - An array of multicast addresses.
+
+ MulticastAddress - The address to search for in the address array.
+
+ ArrayIndex - Will point to where the MulticastAddress is in
+ the AddressArray, or if it isn't in the array, where it should
+ be in the array.
+
+Return Value:
+
+ If the address is in the sorted list this routine will return
+ TRUE, otherwise FALSE.
+
+--*/
+
+{
+
+ //
+ // Indices into the address array so that we may do a binary
+ // search.
+ //
+ UINT Bottom = 0;
+ UINT Middle = NumberOfAddresses / 2;
+ UINT Top;
+ BOOLEAN FinalStatus = FALSE;
+
+ if (NumberOfAddresses) {
+
+ Top = NumberOfAddresses - 1;
+
+ while ((Middle <= Top) && (Middle >= Bottom)) {
+
+ //
+ // The result of comparing an element of the address
+ // array and the multicast address.
+ //
+ // Result < 0 Implies the multicast address is greater.
+ // Result > 0 Implies the address array element is greater.
+ // Result = 0 Implies that the array element and the address
+ // are equal.
+ //
+ INT Result;
+
+ MAC_COMPARE_NETWORK_ADDRESSES(
+ AddressArray[Middle],
+ MulticastAddress,
+ &Result
+ );
+
+ if (Result < 0) {
+
+ Bottom = Middle+1;
+
+ } else if (Result > 0) {
+
+ if (Middle == 0) break;
+ Top = Middle - 1;
+
+
+ } else {
+
+ FinalStatus = TRUE;
+ break;
+
+ }
+ Middle = Bottom + (((Top+1) - Bottom)/2);
+ }
+ }
+
+ *ArrayIndex = Middle;
+ return FinalStatus;
+
+}
+
+BOOLEAN
+MacShouldAddressLoopBack(
+ IN PMAC_FILTER Filter,
+ IN CHAR Address[MAC_LENGTH_OF_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ Do a quick check to see whether the input address should
+ loopback.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+ NOTE: THIS ROUTINE DOES NOT CHECK THE SPECIAL CASE OF SOURCE
+ EQUALS DESTINATION.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ Address - A network address to check for loopback.
+
+
+Return Value:
+
+ Returns TRUE if the address is *likely* to need loopback. It
+ will return FALSE if there is *no* chance that the address would
+ require loopback.
+
+--*/
+{
+
+ //
+ // Holds the result of address determinations.
+ //
+ INT ResultOfAddressCheck;
+
+ UINT CombinedFilters;
+
+ CombinedFilters = MAC_QUERY_FILTER_CLASSES(Filter);
+
+ if (!CombinedFilters) {
+
+ return FALSE;
+
+ }
+
+ if (CombinedFilters & NDIS_PACKET_TYPE_PROMISCUOUS) {
+
+ return TRUE;
+
+ }
+
+ //
+ // First check if it *at least* has the multicast address bit.
+ //
+
+ MAC_IS_MULTICAST(
+ Address,
+ &ResultOfAddressCheck
+ );
+
+ if (ResultOfAddressCheck) {
+
+ //
+ // It is at least a multicast address. Check to see if
+ // it is a broadcast address.
+ //
+
+ MAC_IS_BROADCAST(
+ Address,
+ &ResultOfAddressCheck
+ );
+
+ if (ResultOfAddressCheck) {
+
+ if (CombinedFilters & NDIS_PACKET_TYPE_BROADCAST) {
+
+ return TRUE;
+
+ } else {
+
+ return FALSE;
+
+ }
+
+ } else {
+
+ if ((CombinedFilters & NDIS_PACKET_TYPE_ALL_MULTICAST) ||
+ (CombinedFilters & NDIS_PACKET_TYPE_MULTICAST)) {
+
+ return TRUE;
+
+ } else {
+
+ return FALSE;
+
+ }
+
+ }
+
+ } else {
+
+ //
+ // Direct address never loop back.
+ //
+
+ return FALSE;
+
+ }
+
+}
diff --git a/private/ntos/ndis/pc586e/filter.h b/private/ntos/ndis/pc586e/filter.h
new file mode 100644
index 000000000..54d01a9de
--- /dev/null
+++ b/private/ntos/ndis/pc586e/filter.h
@@ -0,0 +1,402 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ filter.h
+
+Abstract:
+
+ Header file for the address filtering library for NDIS MAC's.
+
+Author:
+
+ Anthony V. Ercolano (tonye) creation-date 3-Aug-1990
+
+Environment:
+
+ Runs in the context of a single MAC driver.
+
+Notes:
+
+ None.
+
+Revision History:
+
+
+--*/
+
+#ifndef _MAC_FILTER_DEFS_
+#define _MAC_FILTER_DEFS_
+
+#define MAC_LENGTH_OF_ADDRESS 6
+
+
+//
+// ZZZ This is a little indian specific check.
+//
+#define MAC_IS_MULTICAST(Address,Result) \
+{ \
+ PUCHAR _A = Address; \
+ *Result = ((_A[0] & ((UCHAR)0x01))?(TRUE):(FALSE)); \
+}
+
+
+//
+// Check whether an address is broadcast.
+//
+#define MAC_IS_BROADCAST(Address,Result) \
+{ \
+ PUCHAR _A = Address; \
+ *Result = (((_A[0] == ((UCHAR)0xff)) && \
+ (_A[1] == ((UCHAR)0xff)) && \
+ (_A[2] == ((UCHAR)0xff)) && \
+ (_A[3] == ((UCHAR)0xff)) && \
+ (_A[4] == ((UCHAR)0xff)) && \
+ (_A[5] == ((UCHAR)0xff)))?(TRUE):(FALSE)); \
+}
+
+
+//
+// This macro will compare network addresses.
+//
+// A - Is a network address.
+//
+// B - Is a network address.
+//
+// Result - The result of comparing two network address.
+//
+// Result < 0 Implies the B address is greater.
+// Result > 0 Implies the A element is greater.
+// Result = 0 Implies equality.
+//
+// Note that this is an arbitrary ordering. There is not
+// defined relation on network addresses. This is ad-hoc!
+//
+//
+#define MAC_COMPARE_NETWORK_ADDRESSES(A,B,Result) \
+{ \
+ PCHAR _A = A; \
+ PCHAR _B = B; \
+ INT _LocalResult = 0; \
+ UINT _i; \
+ for ( \
+ _i = 0; \
+ _i <= 5 && !_LocalResult; \
+ _i++ \
+ ) { \
+ _LocalResult = _A[_i] - _B[_i]; \
+ } \
+ *Result = _LocalResult; \
+}
+
+
+//
+// This macro is used to copy from one network address to
+// another.
+//
+#define MAC_COPY_NETWORK_ADDRESS(D,S) \
+{ \
+ PCHAR _D = (D); \
+ PCHAR _S = (S); \
+ _D[0] = _S[0]; \
+ _D[1] = _S[1]; \
+ _D[2] = _S[2]; \
+ _D[3] = _S[3]; \
+ _D[4] = _S[4]; \
+ _D[5] = _S[5]; \
+}
+
+
+//
+//UINT
+//MAC_QUERY_FILTER_CLASSES(
+// IN PMAC_FILTER Filter
+// )
+//
+// This macro returns the currently enabled filter classes.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define MAC_QUERY_FILTER_CLASSES(Filter) ((Filter)->CombinedPacketFilter)
+
+
+//
+//UINT
+//MAC_NUMBER_OF_FILTER_ADDRESSES(
+// IN PMAC_FILTER Filter
+// )
+//
+// This macro returns the number of multicast addresses in the
+// multicast address list.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define MAC_NUMBER_OF_FILTER_ADDRESSES(Filter) ((Filter)->NumberOfAddresses)
+
+
+//
+// An action routine type. The routines are called
+// when a filter type is set for the first time or
+// no more bindings require a particular type of filter.
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+NDIS_STATUS
+(*MAC_FILTER_CHANGE)(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN BOOLEAN Set
+ );
+
+//
+// This action routine is called when a unique multicast address
+// is added to the filter. The action routine is passed an array
+// filled with all of the addresses that are being filtered, as
+// well as the index into this array of the unique address just
+// added.
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+NDIS_STATUS
+(*MAC_ADDRESS_ADD)(
+ IN UINT CurrentAddressCount,
+ IN CHAR CurrentAddresses[][MAC_LENGTH_OF_ADDRESS],
+ IN UINT NewAddress,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle
+ );
+
+//
+// This action routine is called when a unique multicast address
+// is no longer requested for filtering by any binding. The
+// action routine is passed an array filled with the all of the
+// addresses that are *still* being used for multicast filtering.
+// The routine is also passed the address of the address being deleted.
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+NDIS_STATUS
+(*MAC_ADDRESS_DELETE)(
+ IN UINT CurrentAddressCount,
+ IN CHAR CurrentAddresses[][MAC_LENGTH_OF_ADDRESS],
+ IN CHAR OldAddress[MAC_LENGTH_OF_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle
+ );
+
+//
+// This action routine is called when the mac requests a close for
+// a particular binding *WHILE THE BINDING IS BEING INDICATED TO
+// THE PROTOCOL*. The filtering package can't get rid of the open
+// right away. So this routine will be called as soon as the
+// NdisIndicateReceive returns.
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+VOID
+(*MAC_DEFERRED_CLOSE)(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+typedef ULONG MASK,*PMASK;
+
+//
+// The binding info is threaded on two lists. When
+// the binding is free it is on a single freelist.
+//
+// When the binding is being used it is on a doubly linked
+// index list.
+//
+typedef struct _BINDING_INFO {
+ NDIS_HANDLE MacBindingHandle;
+ NDIS_HANDLE NdisBindingContext;
+ UINT PacketFilters;
+ INT FreeNext;
+ INT OpenNext;
+ INT OpenPrev;
+} BINDING_INFO,*PBINDING_INFO;
+
+//
+// An opaque type that contains a filter database.
+// The MAC need not know how it is structured.
+//
+typedef struct _MAC_FILTER {
+
+ //
+ // Spin lock used to protect the filter from multiple accesses.
+ //
+ PNDIS_SPIN_LOCK Lock;
+
+ //
+ // Pointer to an array of 6 character arrays holding the
+ // multicast addresses requested for filtering.
+ //
+ CHAR (*MulticastAddresses)[MAC_LENGTH_OF_ADDRESS];
+
+ //
+ // Pointer to an array of MASKS that work in conjuction with
+ // the MulticastAddress array. In the masks, a bit being enabled
+ // indicates that the binding with the given FilterIndex is using
+ // the corresponding address.
+ //
+ MASK *BindingsUsingAddress;
+
+ //
+ // Combination of all the filters of all the open bindings.
+ //
+ UINT CombinedPacketFilter;
+
+ //
+ // Array indexed by FilterIndex giving the Handle and context
+ // for a particular binding.
+ //
+ PBINDING_INFO BindingInfo;
+
+ //
+ // Action routines to be invoked on notable changes in the filter.
+ //
+ MAC_ADDRESS_DELETE DeleteAction;
+ MAC_ADDRESS_ADD AddAction;
+ MAC_FILTER_CHANGE ChangeAction;
+ MAC_DEFERRED_CLOSE CloseAction;
+
+ //
+ // The maximum number of addresses used for filtering.
+ //
+ UINT MaximumMulticastAddresses;
+
+ //
+ // The current number of addresses in the address filter.
+ //
+ UINT NumberOfAddresses;
+
+ //
+ // Listhead of the free list of bindings that are available.
+ //
+ // Can only be accessed when the lock is held.
+ //
+ INT FirstFreeBinding;
+
+ //
+ // Index of the first element of the open binding list.
+ //
+ // Can only be accessed when the lock is held.
+ //
+ INT OpenStart;
+
+ //
+ // Index of the last element of the open binding list.
+ //
+ // Can only be accessed when the lock is held.
+ //
+ INT OpenEnd;
+
+ //
+ // Holds the value of the open binding that is currently
+ // being indicated.
+ //
+ // If this value is -1 then no bindings are currently being
+ // indicated.
+ //
+ // This value can only be accessed when the lock is held.
+ //
+ INT IndicatingBinding;
+
+ //
+ // This is set to true when the DeleteFilterOpenAdapter routine
+ // notices that the FilterIndex being shut down is the same one
+ // that is being indicated.
+ //
+ BOOLEAN CurrentBindingShuttingDown;
+
+} MAC_FILTER,*PMAC_FILTER;
+
+BOOLEAN
+MacCreateFilter(
+ IN UINT MaximumMulticastAddresses,
+ IN UINT MaximumOpenAdapters,
+ IN MAC_ADDRESS_DELETE DeleteAction,
+ IN MAC_ADDRESS_ADD AddAction,
+ IN MAC_FILTER_CHANGE ChangeAction,
+ IN MAC_DEFERRED_CLOSE CloseAction,
+ IN PNDIS_SPIN_LOCK Lock,
+ OUT PMAC_FILTER *Filter
+ );
+
+VOID
+MacDeleteFilter(
+ IN PMAC_FILTER Filter
+ );
+
+BOOLEAN
+MacNoteFilterOpenAdapter(
+ IN PMAC_FILTER Filter,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE NdisBindingContext,
+ OUT PUINT FilterIndex
+ );
+
+NDIS_STATUS
+MacDeleteFilterOpenAdapter(
+ IN PMAC_FILTER Filter,
+ IN UINT FilterIndex,
+ IN NDIS_HANDLE RequestHandle
+ );
+
+NDIS_STATUS
+MacAddFilterAddress(
+ IN PMAC_FILTER Filter,
+ IN UINT FilterIndex,
+ IN NDIS_HANDLE RequestHandle,
+ IN CHAR MulticastAddress[MAC_LENGTH_OF_ADDRESS]
+ );
+
+NDIS_STATUS
+MacDeleteFilterAddress(
+ IN PMAC_FILTER Filter,
+ IN UINT FilterIndex,
+ IN NDIS_HANDLE RequestHandle,
+ IN CHAR MulticastAddress[MAC_LENGTH_OF_ADDRESS]
+ );
+
+BOOLEAN
+MacShouldAddressLoopBack(
+ IN PMAC_FILTER Filter,
+ IN CHAR Address[MAC_LENGTH_OF_ADDRESS]
+ );
+
+NDIS_STATUS
+MacFilterAdjust(
+ IN PMAC_FILTER Filter,
+ IN UINT FilterIndex,
+ IN NDIS_HANDLE RequestHandle,
+ IN UINT FilterClasses,
+ IN BOOLEAN Set
+ );
+
+VOID
+MacQueryFilterAddresses(
+ IN PMAC_FILTER Filter,
+ OUT PUINT NumberOfAddresses,
+ IN OUT CHAR AddressArray[][MAC_LENGTH_OF_ADDRESS]
+ );
+
+VOID
+MacFilterIndicateReceive(
+ IN PMAC_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PCHAR Address,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+#endif // _MAC_FILTER_DEFS_
diff --git a/private/ntos/ndis/pc586e/loopback.c b/private/ntos/ndis/pc586e/loopback.c
new file mode 100644
index 000000000..dcee0afef
--- /dev/null
+++ b/private/ntos/ndis/pc586e/loopback.c
@@ -0,0 +1,523 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ loopback.c
+
+Abstract:
+
+ The routines here indicate packets on the loopback queue and are
+ responsible for inserting and removing packets from the loopback
+ queue and the send finishing queue.
+
+Author:
+
+ Anthony V. Ercolano (Tonye) 12-Sept-1990
+
+Environment:
+
+ Operates at dpc level - or the equivalent on os2 and dos.
+
+Revision History:
+
+
+--*/
+
+#include <ntos.h>
+#include <ndis.h>
+#include <filter.h>
+#include <pc586hrd.h>
+#include <pc586sft.h>
+
+
+extern
+VOID
+Pc586ProcessLoopback(
+ IN PPC586_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is responsible for indicating *one* packet on
+ the loopback queue either completing it or moving on to the
+ finish send queue.
+
+Arguments:
+
+ Adapter - The adapter whose loopback queue we are processing.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ if (Adapter->FirstLoopBack) {
+
+ //
+ // Packet at the head of the loopback list.
+ //
+ PNDIS_PACKET PacketToMove;
+
+ //
+ // The reserved portion of the above packet.
+ //
+ PPC586_RESERVED Reserved;
+
+ //
+ // Buffer for loopback.
+ //
+ CHAR Loopback[PC586_SIZE_OF_RECEIVE_BUFFERS];
+
+ //
+ // The first buffer in the ndis packet to be loopbacked.
+ //
+ PNDIS_BUFFER FirstBuffer;
+
+ //
+ // The total amount of user data in the packet to be
+ // loopbacked.
+ //
+ UINT TotalPacketLength;
+
+ //
+ // Eventually the address of the data to be indicated
+ // to the transport.
+ //
+ PVOID BufferAddress;
+
+ //
+ // Eventually the length of the data to be indicated
+ // to the transport.
+ //
+ UINT BufferLength;
+
+ PacketToMove = Adapter->FirstLoopBack;
+ Pc586RemovePacketFromLoopBack(Adapter);
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ Reserved = PPC586_RESERVED_FROM_PACKET(PacketToMove);
+
+ //
+ // See if we need to copy the data from the packet
+ // into the loopback buffer.
+ //
+ // We need to copy to the local loopback buffer if
+ // the first buffer of the packet is less than the
+ // minimum loopback size AND the first buffer isn't
+ // the total packet.
+ //
+
+ NdisQueryPacket(
+ PacketToMove,
+ NULL,
+ NULL,
+ &FirstBuffer,
+ &TotalPacketLength
+ );
+
+ NdisQueryBuffer(
+ FirstBuffer,
+ NULL,
+ &BufferAddress,
+ &BufferLength
+ );
+
+ if ((BufferLength < PC586_SIZE_OF_RECEIVE_BUFFERS) &&
+ (BufferLength != TotalPacketLength)) {
+
+ Pc586CopyFromPacketToBuffer(
+ PacketToMove,
+ 0,
+ PC586_SIZE_OF_RECEIVE_BUFFERS,
+ Loopback,
+ &BufferLength
+ );
+
+ BufferAddress = Loopback;
+
+ }
+
+ //
+ // Indicate the packet to every open binding
+ // that could want it.
+ //
+
+ MacFilterIndicateReceive(
+ Adapter->FilterDB,
+ PacketToMove,
+ ((PCHAR)BufferAddress),
+ BufferAddress,
+ BufferLength,
+ TotalPacketLength
+ );
+
+ //
+ // Remove the packet from the loopback queue and
+ // either indicate that it is finished or put
+ // it on the finishing up queue for the real transmits.
+ //
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ if (!Reserved->STAGE.STAGE4.ReadyToComplete) {
+
+ //
+ // We can decrement the reference count on the open by one since
+ // it is no longer being "referenced" by the packet on the
+ // loopback queue.
+ //
+
+ PPC586_OPEN_FROM_BINDING_HANDLE(
+ Reserved->MacBindingHandle
+ )->References--;
+ Pc586PutPacketOnFinishTrans(
+ Adapter,
+ PacketToMove
+ );
+
+ } else {
+
+ PPC586_OPEN Open;
+ //
+ // Increment the reference count on the open so that
+ // it will not be deleted out from under us while
+ // where indicating it.
+ //
+
+ Open = PPC586_OPEN_FROM_BINDING_HANDLE(Reserved->MacBindingHandle);
+ Open->References++;
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteSend(
+ Open->NdisBindingContext,
+ Reserved->RequestHandle,
+ ((Reserved->STAGE.STAGE4.SuccessfulTransmit)?
+ (NDIS_STATUS_SUCCESS):(NDIS_STATUS_FAILURE))
+ );
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ //
+ // We can decrement the reference count by two since it is
+ // no longer being referenced to indicate and it is no longer
+ // being "referenced" by the packet on the loopback queue.
+ //
+
+ Open->References -= 2;
+
+ }
+
+ //
+ // If there is nothing else on the loopback queue
+ // then indicate that reception is "done".
+ //
+
+ if (!Adapter->FirstLoopBack) {
+
+ //
+ // We need to signal every open binding that the
+ // "receives" are complete. We increment the reference
+ // count on the open binding while we're doing indications
+ // so that the open can't be deleted out from under
+ // us while we're indicating (recall that we can't own
+ // the lock during the indication).
+ //
+
+ PPC586_OPEN Open;
+ PLIST_ENTRY CurrentLink;
+
+ CurrentLink = Adapter->OpenBindings.Flink;
+
+ while (CurrentLink != &Adapter->OpenBindings) {
+
+ Open = CONTAINING_RECORD(
+ CurrentLink,
+ PC586_OPEN,
+ OpenList
+ );
+
+ Open->References++;
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisIndicateReceiveComplete(Open->NdisBindingContext);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Open->References--;
+
+ CurrentLink = CurrentLink->Flink;
+
+ }
+
+ }
+
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+}
+
+extern
+VOID
+Pc586PutPacketOnFinishTrans(
+ IN PPC586_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ Put the packet on the adapter wide queue for packets that
+ are transmitting.
+
+ NOTE: This routine assumes that the lock is held.
+
+ NOTE: By definition any packet given to this routine is ready
+ to complete.
+
+Arguments:
+
+ Adapter - The adapter that contains the queue.
+
+ Packet - The packet to be put on the queue.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PPC586_RESERVED Reserved, LastReserved;
+
+ Reserved = PPC586_RESERVED_FROM_PACKET(Packet);
+
+ Reserved->STAGE.ClearStage = 0;
+
+ if (Adapter->LastFinishTransmit) {
+
+ LastReserved =
+ PPC586_RESERVED_FROM_PACKET(Adapter->LastFinishTransmit);
+
+ LastReserved->Next = Packet;
+ Reserved->STAGE.BackPointer = Adapter->LastFinishTransmit;
+
+ } else {
+
+ Reserved->STAGE.BackPointer = NULL;
+
+ }
+
+ Reserved->STAGE.STAGE4.ReadyToComplete = TRUE;
+ Reserved->Next = NULL;
+
+ Adapter->LastFinishTransmit = Packet;
+
+ if (!Adapter->FirstFinishTransmit) {
+
+ Adapter->FirstFinishTransmit = Packet;
+
+ }
+
+}
+
+extern
+VOID
+Pc586RemovePacketOnFinishTrans(
+ IN PPC586_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ Remove a packet on the adapter wide queue for packets that
+ are transmitting.
+
+ NOTE: This routine assumes that the lock is held.
+
+Arguments:
+
+ Adapter - The adapter that contains the queue.
+
+ Packet - The packet to be removed from the queue.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PPC586_RESERVED Reserved, RBack, RForward;
+ PNDIS_PACKET Forward, Back;
+
+ Reserved = PPC586_RESERVED_FROM_PACKET(Packet);
+ //
+ // Get rid of the low bits that is set in the backpointer by
+ // the routine that inserted this packet on the finish
+ // transmission list.
+ //
+ Reserved->STAGE.STAGE4.ReadyToComplete = 0;
+ Reserved->STAGE.STAGE4.SuccessfulTransmit = 0;
+
+ Forward = Reserved->Next;
+
+ ASSERT(sizeof(UINT) == sizeof(PNDIS_PACKET));
+
+ Back = Reserved->STAGE.BackPointer;
+
+ if (!Back) {
+
+ Adapter->FirstFinishTransmit = Forward;
+
+ } else {
+
+ RBack = PPC586_RESERVED_FROM_PACKET(Back);
+
+ RBack->Next = Forward;
+
+ }
+
+ if (!Forward) {
+
+ Adapter->LastFinishTransmit = Back;
+
+ } else {
+
+ RForward = PPC586_RESERVED_FROM_PACKET(Forward);
+
+ RForward->STAGE.BackPointer = Back;
+ RForward->STAGE.STAGE4.ReadyToComplete = TRUE;
+
+ }
+
+}
+
+extern
+VOID
+Pc586PutPacketOnLoopBack(
+ IN PPC586_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet,
+ IN BOOLEAN ReadyToComplete
+ )
+
+/*++
+
+Routine Description:
+
+ Put the packet on the adapter wide loop back list.
+
+ NOTE: This routine assumes that the lock is held.
+
+ NOTE: This routine absolutely must be called before the packet
+ is relinquished to the hardware.
+
+ NOTE: This routine also increments the reference count on the
+ open binding.
+
+Arguments:
+
+ Adapter - The adapter that contains the loop back list.
+
+ Packet - The packet to be put on loop back.
+
+ ReadyToComplete - This value should be placed in the
+ reserved section.
+
+ NOTE: If ReadyToComplete == TRUE then the packets completion status
+ field will also be set TRUE.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PPC586_RESERVED Reserved = PPC586_RESERVED_FROM_PACKET(Packet);
+
+ if (!Adapter->FirstLoopBack) {
+
+ Adapter->FirstLoopBack = Packet;
+
+ } else {
+
+ PPC586_RESERVED_FROM_PACKET(Adapter->LastLoopBack)->Next = Packet;
+
+ }
+
+ Reserved->STAGE.ClearStage = 0;
+ Reserved->STAGE.STAGE4.ReadyToComplete = ReadyToComplete;
+
+ if (ReadyToComplete) {
+
+ Reserved->STAGE.STAGE4.SuccessfulTransmit = TRUE;
+
+ }
+
+ Reserved->Next = NULL;
+ Adapter->LastLoopBack = Packet;
+
+ //
+ // Increment the reference count on the open since it will be
+ // leaving a packet on the loopback queue.
+ //
+
+ PPC586_OPEN_FROM_BINDING_HANDLE(Reserved->MacBindingHandle)->References++;
+
+}
+
+extern
+VOID
+Pc586RemovePacketFromLoopBack(
+ IN PPC586_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Remove the first packet on the adapter wide loop back list.
+
+ NOTE: This routine assumes that the lock is held.
+
+Arguments:
+
+ Adapter - The adapter that contains the loop back list.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PPC586_RESERVED Reserved =
+ PPC586_RESERVED_FROM_PACKET(Adapter->FirstLoopBack);
+
+ if (!Reserved->Next) {
+
+ Adapter->LastLoopBack = NULL;
+
+ }
+
+ Adapter->FirstLoopBack = Reserved->Next;
+
+}
diff --git a/private/ntos/ndis/pc586e/makefile b/private/ntos/ndis/pc586e/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/pc586e/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/pc586e/packet.c b/private/ntos/ndis/pc586e/packet.c
new file mode 100644
index 000000000..ace8bb7d8
--- /dev/null
+++ b/private/ntos/ndis/pc586e/packet.c
@@ -0,0 +1,535 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ packet.c
+
+Abstract:
+
+ This module contains code to copy from ndis packets to ndis packets,
+ and also to copy from ndis packets to a buffer.
+
+Author:
+
+ Anthony V. Ercolano (Tonye) 12-Sept-1990
+
+Environment:
+
+ Works in kernal mode, but is not important that it does.
+
+Revision History:
+
+
+--*/
+
+#include <ntos.h>
+#include <ndis.h>
+#include <filter.h>
+#include <pc586hrd.h>
+#include <pc586sft.h>
+
+
+extern
+VOID
+Pc586CopyFromPacketToBuffer(
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ IN UINT BytesToCopy,
+ OUT PCHAR Buffer,
+ OUT PUINT BytesCopied
+ )
+
+/*++
+
+Routine Description:
+
+ Copy from an ndis packet into a buffer.
+
+Arguments:
+
+ Packet - The packet to copy from.
+
+ Offset - The offset from which to start the copy.
+
+ BytesToCopy - The number of bytes to copy from the packet.
+
+ Buffer - The destination of the copy.
+
+ BytesCopied - The number of bytes actually copied. Can be less then
+ BytesToCopy if the packet is shorter than BytesToCopy.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ //
+ // Holds the number of ndis buffers comprising the packet.
+ //
+ UINT NdisBufferCount;
+
+ //
+ // Points to the buffer from which we are extracting data.
+ //
+ PNDIS_BUFFER CurrentBuffer;
+
+ //
+ // Holds the virtual address of the current buffer.
+ //
+ PVOID VirtualAddress;
+
+ //
+ // Holds the length of the current buffer of the packet.
+ //
+ UINT CurrentLength;
+
+ //
+ // Keep a local variable of BytesCopied so we aren't referencing
+ // through a pointer.
+ //
+ UINT LocalBytesCopied = 0;
+
+ //
+ // Take care of boundary condition of zero length copy.
+ //
+
+ *BytesCopied = 0;
+ if (!BytesToCopy) return;
+
+ //
+ // Get the first buffer.
+ //
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ &NdisBufferCount,
+ &CurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet.
+ //
+
+ if (!NdisBufferCount) return;
+
+ NdisQueryBuffer(
+ CurrentBuffer,
+ NULL,
+ &VirtualAddress,
+ &CurrentLength
+ );
+
+ while (LocalBytesCopied < BytesToCopy) {
+
+ if (!CurrentLength) {
+
+ NdisGetNextBuffer(
+ CurrentBuffer,
+ &CurrentBuffer
+ );
+
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.
+ //
+
+ if (!CurrentBuffer) break;
+
+ NdisQueryBuffer(
+ CurrentBuffer,
+ NULL,
+ &VirtualAddress,
+ &CurrentLength
+ );
+ continue;
+
+ }
+
+ //
+ // Try to get us up to the point to start the copy.
+ //
+
+ if (Offset) {
+
+ if (Offset > CurrentLength) {
+
+ //
+ // What we want isn't in this buffer.
+ //
+
+ Offset -= CurrentLength;
+ CurrentLength = 0;
+ continue;
+
+ } else {
+
+ VirtualAddress = (PCHAR)VirtualAddress + Offset;
+ CurrentLength -= Offset;
+ Offset = 0;
+
+ }
+
+ }
+
+ //
+ // Copy the data.
+ //
+
+
+ {
+
+ //
+ // Holds the amount of data to move.
+ //
+ UINT AmountToMove;
+
+ AmountToMove =
+ ((CurrentLength <= (BytesToCopy - LocalBytesCopied))?
+ (CurrentLength):(BytesToCopy - LocalBytesCopied));
+
+ PC586_MOVE_MEMORY(
+ Buffer,
+ VirtualAddress,
+ AmountToMove
+ );
+
+ Buffer = (PCHAR)Buffer + AmountToMove;
+ VirtualAddress = (PCHAR)VirtualAddress + AmountToMove;
+
+ LocalBytesCopied += AmountToMove;
+ CurrentLength -= AmountToMove;
+
+ }
+
+ }
+
+ *BytesCopied = LocalBytesCopied;
+
+}
+
+extern
+VOID
+Pc586CopyFromPacketToPacket(
+ IN PNDIS_PACKET Destination,
+ IN UINT DestinationOffset,
+ IN UINT BytesToCopy,
+ IN PNDIS_PACKET Source,
+ IN UINT SourceOffset,
+ OUT PUINT BytesCopied
+ )
+
+/*++
+
+Routine Description:
+
+ Copy from an ndis packet to an ndis packet.
+
+Arguments:
+
+ Destination - The packet should be copied in to.
+
+ DestinationOffset - The offset from the beginning of the packet
+ into which the data should start being placed.
+
+ BytesToCopy - The number of bytes to copy from the source packet.
+
+ Source - The ndis packet from which to copy data.
+
+ SourceOffset - The offset from the start of the packet from which
+ to start copying data.
+
+ BytesCopied - The number of bytes actually copied from the source
+ packet. This can be less than BytesToCopy if the source or destination
+ packet is too short.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ //
+ // Holds the count of the number of ndis buffers comprising the
+ // destination packet.
+ //
+ UINT DestinationBufferCount;
+
+ //
+ // Holds the count of the number of ndis buffers comprising the
+ // source packet.
+ //
+ UINT SourceBufferCount;
+
+ //
+ // Points to the buffer into which we are putting data.
+ //
+ PNDIS_BUFFER DestinationCurrentBuffer;
+
+ //
+ // Points to the buffer from which we are extracting data.
+ //
+ PNDIS_BUFFER SourceCurrentBuffer;
+
+ //
+ // Holds the virtual address of the current destination buffer.
+ //
+ PVOID DestinationVirtualAddress;
+
+ //
+ // Holds the virtual address of the current source buffer.
+ //
+ PVOID SourceVirtualAddress;
+
+ //
+ // Holds the length of the current destination buffer.
+ //
+ UINT DestinationCurrentLength;
+
+ //
+ // Holds the length of the current source buffer.
+ //
+ UINT SourceCurrentLength;
+
+ //
+ // Keep a local variable of BytesCopied so we aren't referencing
+ // through a pointer.
+ //
+ UINT LocalBytesCopied = 0;
+
+ //
+ // Take care of boundary condition of zero length copy.
+ //
+
+ *BytesCopied = 0;
+ if (!BytesToCopy) return;
+
+ //
+ // Get the first buffer of the destination.
+ //
+
+ NdisQueryPacket(
+ Destination,
+ NULL,
+ &DestinationBufferCount,
+ &DestinationCurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet.
+ //
+
+ if (!DestinationBufferCount) return;
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ NULL,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+
+ //
+ // Get the first buffer of the source.
+ //
+
+ NdisQueryPacket(
+ Source,
+ NULL,
+ &SourceBufferCount,
+ &SourceCurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet.
+ //
+
+ if (!SourceBufferCount) return;
+
+ NdisQueryBuffer(
+ SourceCurrentBuffer,
+ NULL,
+ &SourceVirtualAddress,
+ &SourceCurrentLength
+ );
+
+ while (LocalBytesCopied < BytesToCopy) {
+
+ //
+ // Check to see whether we've exhausted the current destination
+ // buffer. If so, move onto the next one.
+ //
+
+ if (!DestinationCurrentLength) {
+
+ NdisGetNextBuffer(
+ DestinationCurrentBuffer,
+ &DestinationCurrentBuffer
+ );
+
+ if (!DestinationCurrentBuffer) {
+
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.)
+ //
+
+ break;
+
+ }
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ NULL,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+ continue;
+
+ }
+
+
+ //
+ // Check to see whether we've exhausted the current source
+ // buffer. If so, move onto the next one.
+ //
+
+ if (!SourceCurrentLength) {
+
+ NdisGetNextBuffer(
+ SourceCurrentBuffer,
+ &SourceCurrentBuffer
+ );
+
+ if (!SourceCurrentBuffer) {
+
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.)
+ //
+
+ break;
+
+ }
+
+ NdisQueryBuffer(
+ SourceCurrentBuffer,
+ NULL,
+ &SourceVirtualAddress,
+ &SourceCurrentLength
+ );
+ continue;
+
+ }
+
+ //
+ // Try to get us up to the point to start the copy.
+ //
+
+ if (DestinationOffset) {
+
+ if (DestinationOffset > DestinationCurrentLength) {
+
+ //
+ // What we want isn't in this buffer.
+ //
+
+ DestinationOffset -= DestinationCurrentLength;
+ DestinationCurrentLength = 0;
+ continue;
+
+ } else {
+
+ DestinationVirtualAddress = (PCHAR)DestinationVirtualAddress
+ + DestinationOffset;
+ DestinationCurrentLength -= DestinationOffset;
+ DestinationOffset = 0;
+
+ }
+
+ }
+
+ //
+ // Try to get us up to the point to start the copy.
+ //
+
+ if (SourceOffset) {
+
+ if (SourceOffset > SourceCurrentLength) {
+
+ //
+ // What we want isn't in this buffer.
+ //
+
+ SourceOffset -= SourceCurrentLength;
+ SourceCurrentLength = 0;
+ continue;
+
+ } else {
+
+ SourceVirtualAddress = (PCHAR)SourceVirtualAddress
+ + SourceOffset;
+ SourceCurrentLength -= SourceOffset;
+ SourceOffset = 0;
+
+ }
+
+ }
+
+ //
+ // Copy the data.
+ //
+
+ {
+
+ //
+ // Holds the amount of data to move.
+ //
+ UINT AmountToMove;
+
+ //
+ // Holds the amount desired remaining.
+ //
+ UINT Remaining = BytesToCopy - LocalBytesCopied;
+
+ AmountToMove =
+ ((SourceCurrentLength <= DestinationCurrentLength)?
+ (SourceCurrentLength):(DestinationCurrentLength));
+
+ AmountToMove = ((Remaining < AmountToMove)?
+ (Remaining):(AmountToMove));
+
+ PC586_MOVE_MEMORY(
+ DestinationVirtualAddress,
+ SourceVirtualAddress,
+ AmountToMove
+ );
+
+ DestinationVirtualAddress =
+ (PCHAR)DestinationVirtualAddress + AmountToMove;
+ SourceVirtualAddress =
+ (PCHAR)SourceVirtualAddress + AmountToMove;
+
+ LocalBytesCopied += AmountToMove;
+ SourceCurrentLength -= AmountToMove;
+ DestinationCurrentLength -= AmountToMove;
+
+ }
+
+ }
+
+ *BytesCopied = LocalBytesCopied;
+
+}
diff --git a/private/ntos/ndis/pc586e/pc586.c b/private/ntos/ndis/pc586e/pc586.c
new file mode 100644
index 000000000..fee06b179
--- /dev/null
+++ b/private/ntos/ndis/pc586e/pc586.c
@@ -0,0 +1,4269 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ pc586.c
+
+Abstract:
+
+ This is the main file for the Intel PC586
+ Ethernet controller. This driver conforms to the NDIS 3.0 interface.
+
+ The idea for handling loopback and sends simultaneously is largely
+ adapted from the EtherLink II NDIS driver by Adam Barr.
+
+Author:
+ Weldon Washburn (o-weldo, Intel) 30-OCT-1990 adapted from ...
+
+ Anthony V. Ercolano (Tonye) 20-Jul-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+
+--*/
+
+#include <ntos.h>
+#include <ndis.h>
+#include <filter.h>
+#include <pc586hrd.h>
+#include <pc586sft.h>
+
+
+
+ULONG ResetCount, SpuriousIntCount, BadRcvCount,
+ RcvRestartCount, RcvSuspendCount;
+
+static
+NDIS_STATUS
+Pc586OpenAdapter(
+ OUT NDIS_HANDLE *MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_HANDLE MacAdapterContext,
+ IN PSTRING AddressingInformation OPTIONAL
+ );
+
+static
+NDIS_STATUS
+Pc586CloseAdapter(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle
+ );
+
+static
+NDIS_STATUS
+Pc586SetPacketFilter(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN UINT PacketFilter
+ );
+
+static
+NDIS_STATUS
+Pc586AddMulticastAddress(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequstHandle,
+ IN PSTRING MulticastAddress
+ );
+
+static
+NDIS_STATUS
+Pc586DeleteMulticastAddress(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN PSTRING MulticastAddress
+ );
+
+static
+NDIS_STATUS
+Pc586QueryInformation(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN NDIS_INFORMATION_CLASS InformationClass,
+ OUT PVOID Buffer,
+ IN UINT BufferLength
+ );
+
+static
+NDIS_STATUS
+Pc586SetInformation(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN NDIS_INFORMATION_CLASS InformationClass,
+ IN PVOID Buffer,
+ IN UINT BufferLength
+ );
+
+static
+NDIS_STATUS
+Pc586Reset(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle
+ );
+
+static
+NDIS_STATUS
+Pc586Test(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle
+ );
+
+static
+NDIS_STATUS
+Pc586ChangeClass(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_HANDLE RequestHandle,
+ IN BOOLEAN Set
+ );
+
+static
+NDIS_STATUS
+Pc586AddMulticast(
+ IN UINT CurrentAddressCount,
+ IN CHAR CurrentAddresses[][MAC_LENGTH_OF_ADDRESS],
+ IN UINT NewAddress,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_HANDLE RequestHandle
+ );
+
+static
+NDIS_STATUS
+Pc586DeleteMulticast(
+ IN UINT CurrentAddressCount,
+ IN CHAR CurrentAddresses[][MAC_LENGTH_OF_ADDRESS],
+ IN CHAR OldAddress[MAC_LENGTH_OF_ADDRESS],
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_HANDLE RequestHandle
+ );
+
+static
+VOID
+Pc586CloseAction(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+static
+VOID
+ReturnAdapterResources(
+ IN PPC586_ADAPTER Adapter
+
+ );
+
+static
+VOID
+ProcessReceiveInterrupts(
+ IN PPC586_ADAPTER Adapter
+ );
+
+static
+BOOLEAN
+ProcessTransmitInterrupts(
+ IN PPC586_ADAPTER Adapter
+ );
+
+static
+VOID
+Pc586StandardInterruptDPC(
+ IN PKDPC Dpc,
+ IN PVOID Context,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+
+extern
+BOOLEAN
+Pc586ISR(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID Context
+ );
+
+static
+VOID
+ProcessInterrupt(
+ IN PPC586_ADAPTER Adapter
+ );
+
+static
+VOID
+SetInitBlockAndInit(
+ IN PPC586_ADAPTER Adapter
+ );
+
+static
+VOID
+StartAdapterReset(
+ IN PPC586_ADAPTER Adapter
+ );
+
+static
+VOID
+SetupForReset(
+ IN PPC586_ADAPTER Adapter,
+ IN PPC586_OPEN Open,
+ IN NDIS_HANDLE RequestHandle,
+ IN NDIS_REQUEST_TYPE RequestType
+ );
+
+static
+BOOLEAN
+Pc586InitialInit(
+ IN PPC586_ADAPTER Adapter
+ );
+
+static
+VOID
+LoadMCAddress(
+ IN PPC586_ADAPTER Adapter
+ );
+
+//
+// ZZZ Non portable interface.
+//
+
+UINT ww_put = 0xff; // debug, set != 0 for 4 byte xfer in PutPacket();
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject
+ )
+
+/*++
+
+Routine Description:
+
+ This is the primary initialization routine for the pc586 driver.
+ It is simply responsible for the intializing the wrapper and registering
+ the MAC. It then calls a system and architecture specific routine that
+ will initialize and register each adapter.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+Return Value:
+
+ The status of the operation.
+
+--*/
+
+{
+
+
+ //
+ // Receives the status of the NdisRegisterMac operation.
+ //
+ NDIS_STATUS InitStatus;
+
+ NDIS_HANDLE NdisMacHandle;
+
+ NDIS_HANDLE NdisWrapperHandle;
+
+ char MacName[] = "PC586";
+ char Tmp[sizeof(NDIS_MAC_CHARACTERISTICS) + sizeof(MacName) - 1];
+ PNDIS_MAC_CHARACTERISTICS Pc586Char = (PNDIS_MAC_CHARACTERISTICS)Tmp;
+ //
+ // Initialize the wrapper.
+ //
+
+ NdisInitializeWrapper(&NdisWrapperHandle,DriverObject,NULL,NULL);
+
+ //
+ // Initialize the MAC characteristics for the call to
+ // NdisRegisterMac.
+ //
+
+ Pc586Char->MajorNdisVersion = PC586_NDIS_MAJOR_VERSION;
+ Pc586Char->MinorNdisVersion = PC586_NDIS_MINOR_VERSION;
+ Pc586Char->OpenAdapterHandler = Pc586OpenAdapter;
+ Pc586Char->CloseAdapterHandler = Pc586CloseAdapter;
+ Pc586Char->SetPacketFilterHandler = Pc586SetPacketFilter;
+ Pc586Char->AddMulticastAddressHandler = Pc586AddMulticastAddress;
+ Pc586Char->DeleteMulticastAddressHandler = Pc586DeleteMulticastAddress;
+ Pc586Char->SendHandler = Pc586Send;
+ Pc586Char->TransferDataHandler = Pc586TransferData;
+ Pc586Char->QueryInformationHandler = Pc586QueryInformation;
+ Pc586Char->SetInformationHandler = Pc586SetInformation;
+ Pc586Char->ResetHandler = Pc586Reset;
+ Pc586Char->TestHandler = Pc586Test;
+ Pc586Char->NameLength = sizeof(MacName) - 1;
+
+ PC586_MOVE_MEMORY(
+ Pc586Char->Name,
+ MacName,
+ sizeof(MacName)
+ );
+
+ NdisRegisterMac(
+ &InitStatus,
+ &NdisMacHandle,
+ NdisWrapperHandle,
+ NULL,
+ Pc586Char,
+ sizeof(*Pc586Char)
+ );
+
+ if (InitStatus == NDIS_STATUS_SUCCESS) {
+
+ //
+ // We started our communication with the wrapper. We now
+ // call a routine which will attempt to allocate and register
+ // all of the adapters. It will return true if *any* of the
+ // adapters were able to start.
+ //
+
+ if (Pc586StartAdapters(NdisMacHandle)) {
+
+ return InitStatus;
+
+ }
+
+ }
+
+ //
+ // We can only get here if something went wrong with registering
+ // the mac or *all* of the adapters.
+ //
+
+ NdisDeregisterMac(
+ &InitStatus,
+ NdisMacHandle
+ );
+ NdisTerminateWrapper(DriverObject);
+
+ return NDIS_ADAPTER_NOT_FOUND;
+
+}
+
+
+extern
+BOOLEAN
+Pc586StartAdapters(
+ IN NDIS_HANDLE NdisMacHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to initialize each adapter card/chip.
+
+Arguments:
+
+ NdisMacHandle - The handle given by ndis when the mac was
+ registered.
+
+Return Value:
+
+ Returns false if *no* adatper was able to be initialized.
+
+--*/
+
+{
+
+ BOOLEAN Status = FALSE;
+
+ Status = Pc586RegisterAdapter(
+ NdisMacHandle,
+ (PSZ)"\\Device\\Pc586",
+ (PVOID)PC586_DEFAULT_STATIC_RAM,
+ (CCHAR)PC586_DEFAULT_INTERRUPT_VECTOR,
+ (KIRQL)PC586_DEFAULT_INTERRUPT_IRQL,
+ (UINT)16,
+ (UINT)32
+ ) || Status;
+
+ return Status;
+
+}
+
+extern
+BOOLEAN
+Pc586RegisterAdapter(
+ IN NDIS_HANDLE NdisMacHandle,
+ IN PSZ DeviceName,
+ IN PVOID Pc586BaseHardwareMemoryAddress,
+ IN CCHAR Pc586InterruptVector,
+ IN KIRQL Pc586InterruptIrql,
+ IN UINT MaximumMulticastAddresses,
+ IN UINT MaximumOpenAdapters
+ )
+
+/*++
+
+Routine Description:
+
+ This routine (and its interface) are not portable. They are
+ defined by the OS, the architecture, and the particular PC586
+ implementation.
+
+ This routine is responsible for the allocation of the datastructures
+ for the driver as well as any hardware specific details necessary
+ to talk with the device.
+
+Arguments:
+
+ NdisMacHandle - The handle given back to the mac from ndis when
+ the mac registered itself.
+
+ DeviceName - The zero terminated string containing the name
+ to give to the device adapter.
+
+ Pc586NetworkAddressAddress - The address containing the ethernet network
+ address.
+
+ Pc586BaseHardwareMemoryAddress - Given that this is an implementation
+ that uses dual ported memory this is the base of the memory for the
+ hardware.
+
+ Pc586InterruptVector - The interrupt vector to used for the adapter.
+
+ Pc586InterruptIrql - The interrupt request level to used for this
+ adapter.
+
+ MaximumMulticastAddresses - The maximum number of multicast
+ addresses to filter at any one time.
+
+ MaximumOpenAdatpers - The maximum number of opens at any one time.
+
+
+Return Value:
+
+ Returns false if anything occurred that prevents the initialization
+ of the adapter.
+
+--*/
+
+{
+
+ STRING Tmp;
+
+ UINT xx;
+
+ //
+ // Pointer for the adapter root.
+ //
+ PPC586_ADAPTER Adapter;
+ PUCHAR CmdPromPhys, StaticRamPhys;
+
+ //
+ // We put in this assertion to make sure that ushort are 2 bytes.
+ // if they aren't then the initialization block definition needs
+ // to be changed.
+ //
+ // Also all of the logic that deals with status registers assumes
+ // that control registers are only 2 bytes.
+ //
+
+ ASSERT(sizeof(USHORT) == 2);
+
+ //
+ // All of the code that manipulates physical addresses depends
+ // on the fact that physical addresses are 4 byte quantities.
+ //
+ ASSERT(sizeof(PHYSICAL_ADDRESS) == 4);
+
+ //
+ // Allocate the Adapter block.
+ //
+
+ if (Adapter = PC586_ALLOC_PHYS(sizeof(PC586_ADAPTER))) {
+DbgPrint("PC586 &Adapter == %lx\n", Adapter);
+
+ PC586_ZERO_MEMORY(
+ Adapter,
+ sizeof(PC586_ADAPTER)
+ );
+
+ Adapter->NdisMacHandle = NdisMacHandle;
+
+ //
+ // Allocate memory to hold the name of the device and initialize
+ // a STRING in the adapter block to hold it.
+ //
+
+ RtlInitString(
+ &Tmp,
+ DeviceName
+ );
+
+ Adapter->DeviceName = PC586_ALLOC_PHYS(Tmp.Length+1);
+
+ if (Adapter->DeviceName) {
+
+ {
+
+ PUCHAR S,D;
+
+ D = Adapter->DeviceName;
+ S = DeviceName;
+
+ while (*S) {
+
+ *D = *S;
+ D++;
+ S++;
+
+ }
+ *D = 0;
+
+ }
+ //
+ // initialize hardware.
+ //
+
+ CmdPromPhys = (PUCHAR)Pc586BaseHardwareMemoryAddress;
+ StaticRamPhys = (PUCHAR)Pc586BaseHardwareMemoryAddress;
+
+ Adapter->CmdProm = (PUCHAR)MmMapIoSpace(
+ (PHYSICAL_ADDRESS)CmdPromPhys, (ULONG)32*1024, FALSE);
+ Adapter->StaticRam = Adapter->CmdProm;
+ Adapter->Cb = (PCMD)(Adapter->StaticRam + OFFSETCU);
+ Adapter->Tbd = (PTBD)(Adapter->StaticRam + OFFSETTBD);
+ Adapter->Scp = (PSCP)(Adapter->StaticRam + OFFSETSCP);
+ Adapter->Iscp = (PISCP)(Adapter->StaticRam + OFFSETISCP);
+ Adapter->Scb = (PSCB)(Adapter->StaticRam + OFFSETSCB);
+ Adapter->CAAddr = (PUSHORT)(Adapter->StaticRam + OFFSETCHANATT);
+ Adapter->IntAddr = (PUSHORT)(Adapter->StaticRam + OFFSETINTENAB);
+ Adapter->CommandBuffer = (PUSHORT)(Adapter->StaticRam + OFFSETTBUF);
+
+ // hardware reset the 586
+ ShuvWord( (PUSHORT)(Adapter->CmdProm + OFFSETRESET), (USHORT)CMD1);
+ KeStallExecutionProcessor((ULONG)1000);
+ ShuvWord( (PUSHORT)(Adapter->CmdProm + OFFSETRESET), (USHORT)CMD0);
+ KeStallExecutionProcessor((ULONG)1000);
+
+ // test to see if board is really present
+ ShuvWord( (PUSHORT)(Adapter->StaticRam + OFFSETSCB), 0x5a5a);
+ xx = PullWord((PUSHORT)(Adapter->StaticRam + OFFSETSCB) );
+
+ // reset again to insure board in 8-bit mode (for reading PROM)
+ ShuvWord( (PUSHORT)(Adapter->CmdProm + OFFSETRESET), (USHORT)CMD1);
+ KeStallExecutionProcessor((ULONG)1000);
+ ShuvWord( (PUSHORT)(Adapter->CmdProm + OFFSETRESET), (USHORT)CMD0);
+ KeStallExecutionProcessor((ULONG)1000);
+
+ if (xx != 0x5a5a) {
+ DbgPrint("pc586 board not present\n");
+ return FALSE;
+ }
+ else DbgPrint("pc586 board was found \n");
+
+ // prom address should increment by one, however the pc586 board
+ // is STUCK in word mode thus ++ by two
+
+ Adapter->NetworkAddress[0] = (UCHAR)PromAddr(Adapter, 0);
+ Adapter->NetworkAddress[1] = (UCHAR)PromAddr(Adapter, 2);
+ Adapter->NetworkAddress[2] = (UCHAR)PromAddr(Adapter, 4);
+ Adapter->NetworkAddress[3] = (UCHAR)PromAddr(Adapter, 6);
+ Adapter->NetworkAddress[4] = (UCHAR)PromAddr(Adapter, 8);
+ Adapter->NetworkAddress[5] = (UCHAR)PromAddr(Adapter, 10);
+
+ DbgPrint("ethernet id = * %x %x %x %x %x %x * \n",
+ Adapter->NetworkAddress[0] ,
+ Adapter->NetworkAddress[1] ,
+ Adapter->NetworkAddress[2] ,
+ Adapter->NetworkAddress[3] ,
+ Adapter->NetworkAddress[4] ,
+ Adapter->NetworkAddress[5] );
+
+ DbgPrint("Pc586 is mapped at virtual address %lx \n",
+ Adapter->CmdProm);
+
+
+ //
+ // Initialize the interrupt.
+ //
+
+ KeInitializeInterrupt(
+ &Adapter->Interrupt,
+ Pc586ISR,
+ Adapter,
+ (PKSPIN_LOCK)NULL,
+ Pc586InterruptVector,
+ Pc586InterruptIrql,
+ Pc586InterruptIrql,
+ LevelSensitive,
+ TRUE,
+ 0,
+ TRUE
+ );
+
+ //
+ // Initialize our dpc.
+ //
+
+ KeInitializeDpc(
+ &Adapter->InterruptDPC,
+ Pc586StandardInterruptDPC,
+ Adapter
+ );
+
+ //
+ // Store the device name away
+ //
+
+ InitializeListHead(&Adapter->OpenBindings);
+ InitializeListHead(&Adapter->CloseList);
+ NdisAllocateSpinLock(&Adapter->Lock);
+
+ Adapter->DoingProcessing = FALSE;
+ Adapter->FirstLoopBack = NULL;
+ Adapter->LastLoopBack = NULL;
+ Adapter->FirstFinishTransmit = NULL;
+ Adapter->LastFinishTransmit = NULL;
+ Adapter->Stage4Open = TRUE;
+ Adapter->Stage3Open = TRUE;
+ Adapter->Stage2Open = TRUE;
+ Adapter->Stage1Open = TRUE;
+ Adapter->AlreadyProcessingStage4 = FALSE;
+ Adapter->AlreadyProcessingStage3 = FALSE;
+ Adapter->AlreadyProcessingStage2 = FALSE;
+ Adapter->FirstStage1Packet = NULL;
+ Adapter->LastStage1Packet = NULL;
+ Adapter->FirstStage2Packet = NULL;
+ Adapter->LastStage2Packet = NULL;
+ Adapter->FirstStage3Packet = NULL;
+ Adapter->LastStage3Packet = NULL;
+ Adapter->ResetInProgress = FALSE;
+ Adapter->ResettingOpen = NULL;
+
+ if (!MacCreateFilter(
+ MaximumMulticastAddresses,
+ MaximumOpenAdapters,
+ Pc586DeleteMulticast,
+ Pc586AddMulticast,
+ Pc586ChangeClass,
+ Pc586CloseAction,
+ &Adapter->Lock,
+ &Adapter->FilterDB
+ )) {
+
+ DbgPrint(
+ "Pc586Initialize - Unsuccessful filter create"
+ " for %s\n",
+ Adapter->DeviceName
+ );
+ PC586_FREE_PHYS(Adapter->DeviceName);
+ PC586_FREE_PHYS(Adapter);
+ return FALSE;
+
+ } else {
+
+ if (!Pc586InitialInit(Adapter)) {
+
+ DbgPrint(
+ "Pc586Initialize - %s is unloading.\n",
+ Adapter->DeviceName
+ );
+ MacDeleteFilter(Adapter->FilterDB);
+ PC586_FREE_PHYS(Adapter->DeviceName);
+ PC586_FREE_PHYS(Adapter);
+ return FALSE;
+
+ } else {
+
+ return TRUE;
+
+ }
+
+ }
+
+ } else {
+
+ DbgPrint(
+ "Pc586Initialize - Unsuccesful allocation of"
+ "name for %s.",
+ DeviceName
+ );
+ PC586_FREE_PHYS(Adapter);
+ return FALSE;
+
+ }
+
+ } else {
+
+ DbgPrint(
+ "Pc586Intialize -- Unsucssful allocation of adapter block"
+ " for %s.\n",
+ DeviceName
+ );
+ return FALSE;
+
+ }
+
+}
+
+extern
+BOOLEAN
+Pc586InitialInit(
+ IN PPC586_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets up the initial init of the driver.
+
+ ZZZ This routine is *not* portable. It is specific to NT.
+
+Arguments:
+
+ Adapter - The adapter for the hardware.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ LARGE_INTEGER Time;
+ //
+ // First we make sure that the device is stopped.
+ //
+ Pc586IntOff(Adapter);
+ ShuvWord( (PUSHORT)(Adapter->CmdProm + OFFSETRESET), (USHORT)CMD1);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ SetInitBlockAndInit(Adapter);
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ //
+ // Delay execution for 1/2 second to give the pc586
+ // time to initialize.
+ //
+
+ Time.QuadPart = Int32x32To64( -5 * 1000 * 1000 , 1);
+
+ if (KeDelayExecutionThread(
+ KernelMode,
+ FALSE,
+ (PLARGE_INTEGER)&Time
+ ) != STATUS_SUCCESS) {
+
+ DbgPrint(
+ "PC586 - Couldn't delay to start %s.\n",
+ Adapter->DeviceName);
+ return FALSE;
+
+ } else {
+
+ STRING Name;
+
+ RtlInitString(
+ &Name,
+ Adapter->DeviceName
+ );
+
+ //
+ // start the chip after NdisRegister... We may not
+ // have any bindings to indicate to but this
+ // is unimportant.
+ //
+
+ if (NdisRegisterAdapter(
+ &Adapter->NdisAdapterHandle,
+ Adapter->NdisMacHandle,
+ Adapter,
+ &Name
+ ) != NDIS_STATUS_SUCCESS) {
+
+ DbgPrint(
+ "Pc586Initialize -- Unsuccessful "
+ "status from NdisRegisterAdapter for %s.\n",
+ Adapter->DeviceName
+ );
+ return FALSE;
+
+ } else {
+ if (!KeConnectInterrupt(&Adapter->Interrupt)) {
+ DbgPrint(
+ "Pc586Initialize - Unsuccessful connect "
+ "to interrupt for %s.\n",Adapter->DeviceName
+ );
+ return FALSE;
+ }
+
+ Pc586IntOn(Adapter);
+ return TRUE;
+ }
+ }
+}
+
+extern
+BOOLEAN
+Pc586ISR(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ Interrupt service routine for the pc586. It's main job is
+ to get the value of ScbStatus and record the changes in the
+ adapters own list of interrupt reasons.
+
+ ZZZ This routine is *not* portable. It is specific to NT and
+ to the pc586 card.
+
+Arguments:
+
+ Interrupt - Interrupt object for the Pc586.
+
+ Context - Really a pointer to the adapter.
+
+Return Value:
+
+ Returns true if the CX|FR|CNA|RNR bit of of the pc586 was.
+
+--*/
+
+{
+
+ //
+ // Holds the pointer to the adapter.
+ //
+ PPC586_ADAPTER Adapter = Context;
+
+
+ if (Adapter->Scb->ScbStatus & SCBINTMSK) {
+
+ //
+ // Insert the normal interrupt processing DPC.
+ //
+
+ KeInsertQueueDpc(
+ &Adapter->InterruptDPC,
+ NULL,
+ NULL
+ );
+
+ return TRUE;
+
+ } else {
+
+ return FALSE;
+
+ }
+
+}
+
+static
+VOID
+Pc586StandardInterruptDPC(
+ IN PKDPC Dpc,
+ IN PVOID Context,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+
+/*++
+
+Routine Description:
+
+ This DPC routine is queued by the interrupt service routine
+ and other routines within the driver that notice that
+ some deferred processing needs to be done. It's main
+ job is to call the interrupt processing code.
+
+ ZZZ This routine is *not* portable. It is specific to NT.
+
+Arguments:
+
+ DPC - The control object associated with this routine.
+
+ Context - Really a pointer to the adapter.
+
+ SystemArgument1(2) - Neither of these arguments used.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ProcessInterrupt(Context);
+
+}
+
+static
+NDIS_STATUS
+Pc586OpenAdapter(
+ OUT NDIS_HANDLE *MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_HANDLE MacAdapterContext,
+ IN PSTRING AddressingInformation OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to create an open instance of an adapter, in effect
+ creating a binding between an upper-level module and the MAC module over
+ the adapter.
+
+Arguments:
+
+ MacBindingHandle - A pointer to a location in which the MAC stores
+ a context value that it uses to represent this binding.
+
+ RequestHandle - A value supplied by the NDIS interface that the MAC
+ must use when completing this request with the NdisCompleteRequest
+ service, if the MAC completes this request asynchronously.
+
+ NdisBindingContext - A value to be recorded by the MAC and passed as
+ context whenever an indication is delivered by the MAC for this binding.
+
+ MacAdapterContext - The value associated with the adapter that is being
+ opened when the MAC registered the adapter with NdisRegisterAdapter.
+
+ AddressingInformation - An optional pointer to a variable length string
+ containing hardware-specific information that can be used to program the
+ device. (This is not used by this MAC.)
+
+Return Value:
+
+ The function value is the status of the operation. If the MAC does not
+ complete this request synchronously, the value would be
+ NDIS_STATUS_PENDING.
+
+
+--*/
+
+{
+
+ //
+ // The PC586_ADAPTER that this open binding should belong too.
+ //
+ PPC586_ADAPTER Adapter;
+
+ //
+ // Holds the status that should be returned to the caller.
+ //
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+
+
+ Adapter = PPC586_ADAPTER_FROM_CONTEXT_HANDLE(MacAdapterContext);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ if (!Adapter->ResetInProgress) {
+
+ //
+ // Pointer to the space allocated for the binding.
+ //
+ PPC586_OPEN NewOpen;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ //
+ // Allocate the space for the open binding. Fill in the fields.
+ //
+
+ NewOpen = PC586_ALLOC_PHYS(sizeof(PC586_OPEN));
+
+ *MacBindingHandle = BINDING_HANDLE_FROM_PPC586_OPEN(NewOpen);
+ InitializeListHead(&NewOpen->OpenList);
+ NewOpen->NdisBindingContext = NdisBindingContext;
+ NewOpen->References = 0;
+ NewOpen->BindingShuttingDown = FALSE;
+ NewOpen->OwningPc586 = Adapter;
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ if (Adapter->ResetInProgress || !MacNoteFilterOpenAdapter(
+ NewOpen->OwningPc586->FilterDB,
+ NewOpen,
+ NdisBindingContext,
+ &NewOpen->FilterIndex
+ )) {
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+ PC586_FREE_PHYS(NewOpen);
+
+ StatusToReturn = NDIS_STATUS_FAILURE;
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ } else {
+
+ //
+ // Everything has been filled in. Synchronize access to the
+ // adapter block and link the new open adapter in and increment
+ // the opens reference count to account for the fact that the
+ // filter routines have a "reference" to the open.
+ //
+
+ InsertTailList(&Adapter->OpenBindings,&NewOpen->OpenList);
+ NewOpen->References++;
+
+ }
+
+ } else {
+
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ }
+
+ PC586_DO_DEFERRED(Adapter);
+ return StatusToReturn;
+}
+
+static
+NDIS_STATUS
+Pc586CloseAdapter(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine causes the MAC to close an open handle (binding).
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality it is a PPC586_OPEN.
+
+ RequestHandle - A value supplied by the NDIS interface that the
+ MAC must use when completing this request with the NdisCompleteRequest
+ service, if the MAC completes this request asynchronously.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+
+{
+
+ PPC586_ADAPTER Adapter;
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ Adapter = PPC586_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ //
+ // Hold the lock while we update the reference counts for the
+ // adapter and the open.
+ //
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ if (!Adapter->ResetInProgress) {
+
+ PPC586_OPEN Open;
+
+ Open = PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ if (!Open->BindingShuttingDown) {
+
+ Open->References++;
+ StatusToReturn = MacDeleteFilterOpenAdapter(
+ Adapter->FilterDB,
+ Open->FilterIndex,
+ RequestHandle
+ );
+
+ //
+ // If the status is successful that merely implies that
+ // we were able to delete the reference to the open binding
+ // from the filtering code. If we have a successful status
+ // at this point we still need to check whether the reference
+ // count to determine whether we can close.
+ //
+ //
+ // The delete filter routine can return a "special" status
+ // that indicates that there is a current NdisIndicateReceive
+ // on this binding. See below.
+ //
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS) {
+
+ //
+ // Check whether the reference count is two. If
+ // it is then we can get rid of the memory for
+ // this open.
+ //
+ // A count of two indicates one for this routine
+ // and one for the filter which we *know* we can
+ // get rid of.
+ //
+
+ if (Open->References == 2) {
+
+ RemoveEntryList(&Open->OpenList);
+ //
+ // We are the only reference to the open. Remove
+ // it from the open list and delete the memory.
+ //
+
+ RemoveEntryList(&Open->OpenList);
+ PC586_FREE_PHYS(Open);
+
+ } else {
+
+ Open->CloseHandle = RequestHandle;
+ Open->BindingShuttingDown = TRUE;
+
+ //
+ // Remove the open from the open list and put it on
+ // the closing list.
+ //
+
+ RemoveEntryList(&Open->OpenList);
+ InsertTailList(&Adapter->CloseList,&Open->OpenList);
+
+ //
+ // Account for this routines reference to the open
+ // as well as reference because of the filtering.
+ //
+
+ Open->References -= 2;
+
+ //
+ // Change the status to indicate that we will
+ // be closing this later.
+ //
+
+ StatusToReturn = NDIS_STATUS_PENDING;
+
+ }
+
+ } else if (StatusToReturn == NDIS_STATUS_PENDING) {
+
+ Open->CloseHandle = RequestHandle;
+ Open->BindingShuttingDown = TRUE;
+
+ //
+ // Remove the open from the open list and put it on
+ // the closing list.
+ //
+
+ RemoveEntryList(&Open->OpenList);
+ InsertTailList(&Adapter->CloseList,&Open->OpenList);
+
+ //
+ // Account for this routines reference to the open
+ // as well as reference because of the filtering.
+ //
+
+ Open->References -= 2;
+
+ } else if (StatusToReturn == NDIS_STATUS_CLOSING_INDICATING) {
+
+ //
+ // When we have this status it indicates that the filtering
+ // code was currently doing an NdisIndicateReceive. It
+ // would not be wise to delete the memory for the open at
+ // this point. The filtering code will call our close action
+ // routine upon return from NdisIndicateReceive and that
+ // action routine will decrement the reference count for
+ // the open.
+ //
+
+ Open->CloseHandle = RequestHandle;
+ Open->BindingShuttingDown = TRUE;
+
+ //
+ // This status is private to the filtering routine. Just
+ // tell the caller the the close is pending.
+ //
+
+ StatusToReturn = NDIS_STATUS_PENDING;
+
+ //
+ // Remove the open from the open list and put it on
+ // the closing list.
+ //
+
+ RemoveEntryList(&Open->OpenList);
+ InsertTailList(&Adapter->CloseList,&Open->OpenList);
+
+ //
+ // Account for this routines reference to the open.
+ //
+
+ Open->References--;
+
+ } else {
+
+ //
+ // Account for this routines reference to the open.
+ //
+
+ Open->References--;
+
+ }
+
+ } else {
+
+ StatusToReturn = NDIS_CLOSING;
+
+ }
+
+ } else {
+
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ }
+
+ PC586_DO_DEFERRED(Adapter);
+ return StatusToReturn;
+
+}
+
+static
+NDIS_STATUS
+Pc586SetPacketFilter(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN UINT PacketFilter
+ )
+
+/*++
+
+Routine Description:
+
+ The Pc586SetPacketFilter request allows a protocol to control the types
+ of packets that it receives from the MAC.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to PC586_OPEN.
+
+ RequestHandle - A value supplied by the NDIS interface that the MAC
+ must use when completing this request with the NdisCompleteRequest
+ service, if the MAC completes this request asynchronously.
+
+ PacketFilter - A bit mask that contains flags that correspond to specific
+ classes of received packets. If a particular bit is set in the mask,
+ then packet reception for that class of packet is enabled. If the
+ bit is clear, then packets that fall into that class are not received
+ by the client. A single exception to this rule is that if the promiscuous
+ bit is set, then the client receives all packets on the network, regardless
+ of the state of the other flags.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+ //
+ // Keeps track of the *MAC's* status. The status will only be
+ // reset if the filter change action routine is called.
+ //
+ NDIS_STATUS StatusOfFilterChange = NDIS_STATUS_SUCCESS;
+
+ //
+ // Points to the adapter that this request is coming through.
+ //
+ PPC586_ADAPTER Adapter;
+
+ Adapter = PPC586_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ if (!Adapter->ResetInProgress) {
+
+ //
+ // Pointer to the open that is changing the packet filters.
+ //
+ PPC586_OPEN Open = PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ if (!Open->BindingShuttingDown) {
+
+ //
+ // Increment the open while it is going through the filtering
+ // routines.
+ //
+
+ Open->References++;
+ StatusOfFilterChange = MacFilterAdjust(
+ Adapter->FilterDB,
+ Open->FilterIndex,
+ RequestHandle,
+ PacketFilter,
+ TRUE
+ );
+ Open->References--;
+
+ } else {
+
+ StatusOfFilterChange = NDIS_CLOSING;
+
+ }
+
+ } else {
+
+ StatusOfFilterChange = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ }
+
+ PC586_DO_DEFERRED(Adapter);
+ return StatusOfFilterChange;
+}
+
+static
+NDIS_STATUS
+Pc586AddMulticastAddress(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN PSTRING MulticastAddress
+ )
+
+/*++
+
+Routine Description:
+
+ The Pc586AddMulticastAddress request adds a multicast address
+ to the list of multicast/functional addresses that are enabled
+ for packet reception. The address may subsequently be deleted
+ using the Pc586DeleteMulticastAddress request.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to PC586_OPEN.
+
+ RequestHandle - A value supplied by the NDIS interface that the MAC
+ must use when completing this request with the NdisCompleteRequest
+ service, if the MAC completes this request asynchronously.
+
+ MulticastAddress - A pointer to a variable-length counted string
+ containing the multicast or functional address as it appears in storage
+ when received from the adapter. When specifying multicast or functional
+ addresses, the multicast/functional address bit is automatically provided
+ by the MAC itself; it is not necessary, by it is acceptable, to specify
+ the string.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+
+{
+
+ //
+ // We call the filter database to add the address. If the
+ // address was already in the database then the call can be
+ // completed right away. If the address wasn't in the database then
+ // the action routine will be called. The action routine will be
+ // responsible for setting up any deferred processing.
+ //
+
+ NDIS_STATUS StatusOfAdd;
+
+ //
+ // Points to the adapter that this request is coming through.
+ //
+ PPC586_ADAPTER Adapter;
+
+ Adapter = PPC586_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ if (!Adapter->ResetInProgress) {
+
+ PPC586_OPEN Open;
+
+ Open = PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ if (!Open->BindingShuttingDown) {
+
+ Open->References++;
+ StatusOfAdd = MacAddFilterAddress(
+ Open->OwningPc586->FilterDB,
+ Open->FilterIndex,
+ RequestHandle,
+ MulticastAddress->Buffer
+ );
+ Open->References--;
+
+ } else {
+
+ StatusOfAdd = NDIS_CLOSING;
+
+ }
+
+ } else {
+
+ StatusOfAdd = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ }
+
+ PC586_DO_DEFERRED(Adapter);
+ return StatusOfAdd;
+}
+
+static
+NDIS_STATUS
+Pc586DeleteMulticastAddress(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN PSTRING MulticastAddress
+ )
+
+/*++
+
+Routine Description:
+
+ The MacDeleteMulticastAddress request removes a multicast or functional
+ address from the list of multicast/functional addresses that are enabled
+ for packet reception. Once an address is removed from the list, packets
+ will no longer be received by the binding when they are directed to that
+ address.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to PC586_OPEN.
+
+ RequestHandle - A value supplied by the NDIS interface that the MAC
+ must use when completing this request with the NdisCompleteRequest
+ service, if the MAC completes this request asynchronously.
+
+ MulticastAddress - A pointer to a variable-length counted string
+ containing the multicast or functional address as it appears in storage
+ when received from the adapter. When specifying multicast or functional
+ addresses, the multicast/functional address bit is automatically provided
+ by the MAC itself; it is not necessary, by it is acceptable, to specify
+ the string.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+
+{
+ //
+ // We call the filter database to delete the address. If this
+ // is the last reference to the address then the delete address
+ // action routine is called.
+ //
+
+ NDIS_STATUS StatusOfDelete;
+
+ //
+ // Points to the adapter that this request is coming through.
+ //
+ PPC586_ADAPTER Adapter;
+
+ Adapter = PPC586_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ if (!Adapter->ResetInProgress) {
+
+ PPC586_OPEN Open;
+
+ Open = PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ if (!Open->BindingShuttingDown) {
+
+ Open->References++;
+ StatusOfDelete = MacDeleteFilterAddress(
+ Open->OwningPc586->FilterDB,
+ Open->FilterIndex,
+ RequestHandle,
+ MulticastAddress->Buffer
+ );
+ Open->References--;
+
+ } else {
+
+ StatusOfDelete = NDIS_CLOSING;
+
+ }
+
+ } else {
+
+ StatusOfDelete = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ }
+
+ PC586_DO_DEFERRED(Adapter);
+ return StatusOfDelete;
+}
+
+static
+NDIS_STATUS
+Pc586QueryInformation(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN NDIS_INFORMATION_CLASS InformationClass,
+ OUT PVOID Buffer,
+ IN UINT BufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ The Pc586QueryInformation request allows a protocol to inspect
+ the MAC's capabilities and current status. See the description
+ of NdisQueryInformation for a detailed description of this request.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to PC586_OPEN.
+
+ RequestHandle - A value supplied by the NDIS interface that the MAC
+ must use when completing this request with the NdisCompleteRequest
+ service, if the MAC completes this request asynchronously.
+
+ InformationClass - A value indicating the class of the information
+ to be queried. See the description of NdisQueryInformation for valid
+ values.
+
+ Buffer - A pointer to a buffer into which the MAC copies the information.
+ See the description of NdisQueryInformation for buffer formats.
+
+ BufferLength - An unsigned integer specifying the maximum length of
+ the information buffer, in bytes.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+
+{
+
+ PPC586_ADAPTER Adapter;
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ Adapter = PPC586_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ //
+ // Get and hold the lock while we update the reference counts.
+ //
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ if (!Adapter->ResetInProgress) {
+
+ PPC586_OPEN Open;
+
+ Open = PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ if (!Open->BindingShuttingDown) {
+
+ Open->References++;
+
+ //
+ // The only information request that we actually support
+ // is the info identification service.
+ //
+
+ switch(InformationClass) {
+
+ case NdisInfoStationAddress:
+ case NdisInfoFunctionalAddress:
+
+ //
+ // Ensure that we have enough room to return the
+ // information.
+ //
+
+ if (BufferLength < MAC_LENGTH_OF_ADDRESS) {
+
+ StatusToReturn = NDIS_STATUS_FAILURE;
+
+ } else {
+
+ MAC_COPY_NETWORK_ADDRESS(
+ (PCHAR)Buffer,
+ (PCHAR)Adapter->NetworkAddress
+ );
+
+ }
+
+ break;
+
+ case NdisInfoIdentification:
+
+ //
+ // Let the protocol know that we adhere
+ // to the IEEE 802.3 communications standard.
+ //
+ // In addition return the ndis version.
+ //
+
+ if (BufferLength < sizeof(NDIS_INFO_IDENTIFICATION)) {
+
+ StatusToReturn = NDIS_STATUS_FAILURE;
+ break;
+
+ }
+
+ ((PNDIS_INFO_IDENTIFICATION)Buffer)->NdisVersion = 3;
+ ((PNDIS_INFO_IDENTIFICATION)Buffer)->MediumType =
+ NdisMedium802_3;
+
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ break;
+
+ default:
+
+ //
+ // ZZZ Need to implement query information services.
+ //
+ DbgPrint("PC586 - Information not yet implemented.\n");
+ StatusToReturn = NDIS_STATUS_FAILURE;
+ break;
+
+ }
+ Open->References--;
+
+ } else {
+
+ StatusToReturn = NDIS_CLOSING;
+
+ }
+
+ } else {
+
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ }
+
+ PC586_DO_DEFERRED(Adapter);
+ return StatusToReturn;
+}
+
+static
+NDIS_STATUS
+Pc586SetInformation(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN NDIS_INFORMATION_CLASS InformationClass,
+ IN PVOID Buffer,
+ IN UINT BufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ The Pc586SetInformation request allows a protocol to control the MAC
+ by changing information maintained by the MAC. See the description
+ of NdisSetInformation for a detailed description of this request.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to PC586_OPEN.
+
+ RequestHandle - A value supplied by the NDIS interface that the MAC
+ must use when completing this request with the NdisCompleteRequest
+ service, if the MAC completes this request asynchronously.
+
+ InformationClass - A value indicating the class of the information
+ to be set. See the description of NdisSetInformation for valid
+ values.
+
+ Buffer - A pointer to a buffer containg the information for the specified
+ class. See the description of NdisSetInformation for buffer formats.
+
+ BufferLength - An unsigned integer specifying the maximum length of
+ the information buffer, in bytes.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+
+{
+
+ PPC586_ADAPTER Adapter;
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ Adapter = PPC586_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ //
+ // Hold the lock while we update the reference counts for the
+ // adapter and the open.
+ //
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ if (!Adapter->ResetInProgress) {
+
+ PPC586_OPEN Open;
+
+ Open = PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ if (!Open->BindingShuttingDown) {
+
+ //
+ // ZZZ Need to implement set information services.
+ //
+ DbgPrint("PC586 - MacSetInformation not yet implemented.\n");
+ StatusToReturn = NDIS_STATUS_FAILURE;
+
+ } else {
+
+ StatusToReturn = NDIS_CLOSING;
+
+ }
+
+ } else {
+
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ }
+
+ PC586_DO_DEFERRED(Adapter);
+ return StatusToReturn;
+
+}
+
+static
+NDIS_STATUS
+Pc586Reset(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle
+ )
+
+/*++
+
+Routine Description:
+
+ The Pc586Reset request instructs the MAC to issue a hardware reset
+ to the network adapter. The MAC also resets its software state. See
+ the description of NdisReset for a detailed description of this request.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to PC586_OPEN.
+
+ RequestHandle - A value supplied by the NDIS interface that the MAC
+ must use when completing this request with the NdisCompleteRequest
+ service, if the MAC completes this request asynchronously.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+
+{
+
+ //
+ // Holds the status that should be returned to the caller.
+ //
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_PENDING;
+
+ PPC586_ADAPTER Adapter =
+ PPC586_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ //
+ // Hold the locks while we update the reference counts on the
+ // adapter and the open.
+ //
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ if (!Adapter->ResetInProgress) {
+
+ PPC586_OPEN Open;
+
+ Open = PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ if (!Open->BindingShuttingDown) {
+
+ Open->References++;
+ SetupForReset(
+ Adapter,
+ PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle),
+ RequestHandle,
+ NdisRequestReset
+ );
+ Open->References--;
+
+ } else {
+
+ StatusToReturn = NDIS_CLOSING;
+
+ }
+
+ } else {
+
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ }
+
+ PC586_DO_DEFERRED(Adapter);
+ return StatusToReturn;
+
+}
+
+static
+NDIS_STATUS
+Pc586Test(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle
+ )
+
+/*++
+
+Routine Description:
+
+ The Pc586Test request instructs the MAC to run hardware diagnostics
+ on the underlying network adapter without resetting the adapter.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to PC586_OPEN.
+
+ RequestHandle - A value supplied by the NDIS interface that the MAC
+ must use when completing this request with the NdisCompleteRequest
+ service, if the MAC completes this request asynchronously.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+
+{
+
+ PPC586_ADAPTER Adapter;
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ Adapter = PPC586_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ //
+ // Hold the lock while we update the reference counts for the
+ // adapter and the open.
+ //
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ if (!Adapter->ResetInProgress) {
+
+ PPC586_OPEN Open;
+
+ Open = PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ if (!Open->BindingShuttingDown) {
+
+ //
+ // ZZZ Need to implement test information service.
+ //
+
+ StatusToReturn = NDIS_STATUS_NOT_TESTABLE;
+
+ } else {
+
+ StatusToReturn = NDIS_CLOSING;
+
+ }
+
+ } else {
+
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ }
+
+ PC586_DO_DEFERRED(Adapter);
+ return StatusToReturn;
+
+}
+
+static
+NDIS_STATUS
+Pc586ChangeClass(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when a particular filter
+ class is first used or last cleared.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ OldFilterClasses - The values of the class filter before it
+ was changed.
+
+ NewFilterClasses - The current value of the class filter
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to PC586_OPEN.
+
+ RequestHandle - A value supplied by the NDIS interface that the MAC
+ must use when completing this request with the NdisCompleteRequest
+ service, if the MAC completes this request asynchronously.
+
+ Set - If true the change resulted from a set, otherwise the
+ change resulted from a open closing.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+
+
+ PPC586_ADAPTER Adapter = PPC586_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ //
+ // Holds the change that should be returned to the filtering package.
+ //
+ NDIS_STATUS StatusOfChange;
+
+ if (Adapter->ResetInProgress) {
+
+ StatusOfChange = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ } else {
+
+ //
+ // This local will hold the actual changes that occurred
+ // in the packet filtering that are of real interest.
+ //
+ UINT PacketChanges;
+
+
+ //
+ // The whole purpose of this routine is to determine whether
+ // the filtering changes need to result in the hardware being
+ // reset.
+ //
+
+ ASSERT(OldFilterClasses != NewFilterClasses);
+
+ //
+ // We only need to reset if there is a change of "state" with
+ // multicast, all multicast, or promiscuous.
+ //
+
+ PacketChanges = (OldFilterClasses ^ NewFilterClasses) &
+ (NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_ALL_MULTICAST |
+ NDIS_PACKET_TYPE_MULTICAST);
+
+ StatusOfChange = NDIS_STATUS_SUCCESS;
+ if (PacketChanges) {
+
+ //
+ // We had some "important" change. We first check to see if
+ // promiscuous filtering or all multicast has changed.
+ //
+ // Otherwise multicast addressing is changing. We only need
+ // to reset the hardware if somebody isn't already filtering for
+ // all multicast or promiscuous (which the above tests do
+ // *NOT* test for) and there are any multicast addresses.
+ //
+
+ if ((PacketChanges & NDIS_PACKET_TYPE_PROMISCUOUS) ||
+ (PacketChanges & NDIS_PACKET_TYPE_ALL_MULTICAST) ||
+ ((!(NewFilterClasses & (NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_ALL_MULTICAST))) &&
+ MAC_NUMBER_OF_FILTER_ADDRESSES(Adapter->FilterDB)
+ )) {
+
+ SetupForReset(
+ Adapter,
+ PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle),
+ RequestHandle,
+ NdisRequestSetPacketFilter
+ );
+ StatusOfChange = NDIS_STATUS_PENDING;
+
+ }
+
+ }
+
+ }
+
+ return StatusOfChange;
+
+}
+
+static
+NDIS_STATUS
+Pc586AddMulticast(
+ IN UINT CurrentAddressCount,
+ IN CHAR CurrentAddresses[][MAC_LENGTH_OF_ADDRESS],
+ IN UINT NewAddress,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when an address is added to
+ the filter that wasn't referenced by any other open binding.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ CurrentAddressCount - The number of addresses in the address array.
+
+ CurrentAddresses - An array of multicast addresses. Note that this
+ array already contains the new address.
+
+ NewAddress - The index in the array where the new address can be
+ located.
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to PC586_OPEN.
+
+ RequestHandle - A value supplied by the NDIS interface that the MAC
+ must use when completing this request with the NdisCompleteRequest
+ service, if the MAC completes this request asynchronously.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+
+ PPC586_ADAPTER Adapter = PPC586_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ //
+ // Holds the status that should be returned to the filtering package.
+ //
+ NDIS_STATUS StatusOfAdd;
+
+ //
+ // Check to see if the device is already resetting. If it is
+ // then reject this add.
+ //
+
+ if (Adapter->ResetInProgress) {
+
+ StatusOfAdd = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ } else {
+
+ UINT PacketFilters;
+
+ PacketFilters = MAC_QUERY_FILTER_CLASSES(Adapter->FilterDB);
+
+ //
+ // We don't need to do a reset if an open is promiscuous or
+ // an open is already accepting all multicast addresses.
+ //
+
+ if ((PacketFilters & NDIS_PACKET_TYPE_PROMISCUOUS) ||
+ (PacketFilters & NDIS_PACKET_TYPE_ALL_MULTICAST)) {
+
+ StatusOfAdd = NDIS_STATUS_SUCCESS;
+
+ } else {
+
+ //
+ // Make sure that multicast addresses are actually enabled.
+ // If not then there is no point in resetting.
+ //
+
+ if (PacketFilters & NDIS_PACKET_TYPE_MULTICAST) {
+
+ //
+ // We need to add this to the hardware multicast filtering.
+ //
+
+ SetupForReset(
+ Adapter,
+ PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle),
+ RequestHandle,
+ NdisRequestAddMulticast
+ );
+ StatusOfAdd = NDIS_STATUS_PENDING;
+
+ } else {
+
+ StatusOfAdd = NDIS_STATUS_SUCCESS;
+
+ }
+
+ }
+
+ }
+
+ return StatusOfAdd;
+
+}
+
+static
+NDIS_STATUS
+Pc586DeleteMulticast(
+ IN UINT CurrentAddressCount,
+ IN CHAR CurrentAddresses[][MAC_LENGTH_OF_ADDRESS],
+ IN CHAR OldAddress[MAC_LENGTH_OF_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when a particular multicast
+ address is deleted for the last time.
+
+ NOTE: This routine assumes that it is called with the lock acquired.
+
+Arguments:
+
+ CurrentAddressCount - The number of addresses in the address array.
+
+ CurrentAddresses - An array of multicast addresses. Note that this
+ array does not contain the old address.
+
+ OldAddress - The address that was deleted from the address filter.
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to PC586_OPEN.
+
+ RequestHandle - A value supplied by the NDIS interface that the MAC
+ must use when completing this request with the NdisCompleteRequest
+ service, if the MAC completes this request asynchronously.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+
+ PPC586_ADAPTER Adapter = PPC586_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ //
+ // Holds the status that should be returned to the filtering
+ // package.
+ //
+ NDIS_STATUS StatusOfDelete;
+
+ //
+ // Check to see if the device is already resetting. If it is
+ // then reject this delete if the reset isn't coming from
+ // this MacBindingHandle. The reason we care about the binding
+ // handle is that when an open closes we may getting rid of multiple
+ // multicast addresses at one time.
+ //
+
+ if (Adapter->ResetInProgress) {
+
+ if (Adapter->ResettingOpen !=
+ PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle)) {
+
+ StatusOfDelete = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ } else {
+
+ //
+ // If this open is causing the reset then any further deletes
+ // can only be pending (as was the first delete).
+ //
+
+ StatusOfDelete = NDIS_STATUS_PENDING;
+
+ }
+
+ } else {
+
+ UINT PacketFilters;
+
+ PacketFilters = MAC_QUERY_FILTER_CLASSES(Adapter->FilterDB);
+
+ //
+ // We don't need to do a reset if an open is promiscuous or
+ // an open is already accepting all multicast addresses.
+ //
+
+ if ((PacketFilters & NDIS_PACKET_TYPE_PROMISCUOUS) ||
+ (PacketFilters & NDIS_PACKET_TYPE_ALL_MULTICAST)) {
+
+ StatusOfDelete = NDIS_STATUS_SUCCESS;
+
+ } else {
+
+ //
+ // Make sure that multicast filtering is actually enabled
+ // since if multicast isn't then there is not point in
+ // resetting since nobody wants multicast addresses.
+ //
+
+ if (PacketFilters & NDIS_PACKET_TYPE_MULTICAST) {
+
+ //
+ // We need to delete this from the hardware multicast
+ // filtering.
+ //
+
+ SetupForReset(
+ Adapter,
+ PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle),
+ RequestHandle,
+ NdisRequestDeleteMulticast
+ );
+ StatusOfDelete = NDIS_STATUS_PENDING;
+
+ } else {
+
+ StatusOfDelete = NDIS_STATUS_SUCCESS;
+
+ }
+
+ }
+
+ }
+
+ return StatusOfDelete;
+
+}
+
+static
+VOID
+Pc586CloseAction(
+ IN NDIS_HANDLE MacBindingHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when a particular binding
+ was closed while it was indicating through NdisIndicateReceive
+
+ All this routine needs to do is to decrement the reference count
+ of the binding.
+
+ NOTE: This routine assumes that it is called with the lock acquired.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to PC586_OPEN.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+
+ PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle)->References--;
+
+}
+
+static
+VOID
+ProcessInterrupt(
+ IN PPC586_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Main routine for processing interrupts.
+
+Arguments:
+
+ Adapter - The Adapter to process interrupts for.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ while (TRUE) {
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ if (Adapter->DoingProcessing) {
+
+ break;
+
+ } else {
+
+ //
+ // Check the interrupt source and other reasons
+ // for processing. If there are no reasons to
+ // process then exit this loop.
+ //
+ // Note that when we check the for processing sources
+ // that we "carefully" check to see if we are already
+ // processing one of the stage queues. We do this
+ // by checking the "AlreadyProcessingStageX" variables
+ // in the adapter. If any of these are true then
+ // we let whoever set that boolean take care of pushing
+ // the packet through the stage queues.
+ //
+ // By checking the "AlreadyProcessingStageX" variables
+ // we can prevent a possible priority inversion where
+ // we get "stuck" behind something that is processing
+ // at a lower priority level.
+ //
+
+ if (
+ (Adapter->Scb->ScbStatus &
+ (SCBINTMSK)) ||
+ Adapter->FirstLoopBack ||
+ (Adapter->ResetInProgress && (!Adapter->References)) ||
+ ((!(Adapter->AlreadyProcessingStage4 ||
+ Adapter->AlreadyProcessingStage3 ||
+ Adapter->AlreadyProcessingStage2)
+ ) &&
+ ((Adapter->FirstStage3Packet && Adapter->Stage4Open) ||
+ (Adapter->FirstStage2Packet && Adapter->Stage3Open) ||
+ (Adapter->FirstStage1Packet && Adapter->Stage2Open)
+ )
+ ) || (!IsListEmpty(&Adapter->CloseList))) {
+
+ Adapter->References++;
+ Adapter->DoingProcessing = TRUE;
+
+ } else {
+
+ break;
+
+ }
+
+ }
+
+ //
+ // Note that the following code depends on the fact that
+ // code above left the spinlock held.
+ //
+
+ //
+ // If we have a reset in progress and the adapters reference
+ // count is 1 (meaning no routine is in the interface and
+ // we are the only "active" interrupt processing routine) then
+ // it is safe to start the reset.
+ //
+
+ if (Adapter->ResetInProgress && (Adapter->References == 1)) {
+
+ StartAdapterReset(Adapter);
+ goto LoopBottom;
+
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ //
+ // note -- need to check for non-packet related errors.
+ //
+ //
+
+
+ // Check the interrupt vector and see if there are any
+ // more receives to process. After we process any
+ // other interrupt source we always come back to the top
+ // of the loop to check if any more receive packets have
+ // come in. This is to lessen the probability that we
+ // drop a receive.
+ //
+
+ if ( Adapter->Scb->ScbStatus & (SCBINTFR|SCBINTRNR) ) {
+
+ ProcessReceiveInterrupts(Adapter);
+
+ //
+ // We need to signal every open binding that the
+ // receives are complete. We increment the reference
+ // count on the open binding while we're doing indications
+ // so that the open can't be deleted out from under
+ // us while we're indicating (recall that we can't own
+ // the lock during the indication).
+ //
+
+ {
+
+ PPC586_OPEN Open;
+ PLIST_ENTRY CurrentLink;
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ CurrentLink = Adapter->OpenBindings.Flink;
+
+ while (CurrentLink != &Adapter->OpenBindings) {
+
+ Open = CONTAINING_RECORD(
+ CurrentLink,
+ PC586_OPEN,
+ OpenList
+ );
+
+ Open->References++;
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisIndicateReceiveComplete(Open->NdisBindingContext);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Open->References--;
+
+ CurrentLink = CurrentLink->Flink;
+
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ }
+
+ }
+
+ //
+ // Process the transmit interrupts if there are any.
+ //
+
+ if ( Adapter->Scb->ScbStatus & (SCBINTCX|SCBINTCNA) ) {
+
+ ProcessTransmitInterrupts(Adapter);
+
+ Adapter->Scb->ScbCmd =
+ (USHORT)(Adapter->Scb->ScbStatus & (SCBINTCX|SCBINTCNA));
+ if (Adapter->Scb->ScbCmd) ChanAttn(Adapter);
+ }
+
+ //
+ // Only try to push a packet through the stage queues
+ // if somebody else isn't already doing it and
+ // there is some hope of moving some packets
+ // ahead.
+ //
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ if ((!(Adapter->AlreadyProcessingStage4 ||
+ Adapter->AlreadyProcessingStage3 ||
+ Adapter->AlreadyProcessingStage2)
+ ) &&
+ ((Adapter->FirstStage3Packet && Adapter->Stage4Open) ||
+ (Adapter->FirstStage2Packet && Adapter->Stage3Open) ||
+ (Adapter->FirstStage1Packet && Adapter->Stage2Open)
+ )
+ ) {
+
+ Pc586StagedAllocation(Adapter);
+
+ }
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ //
+ // Process the loopback queue.
+ //
+ // NOTE: Incase anyone ever figures out how to make this
+ // loop more reentriant, special care needs to be taken that
+ // loopback packets and regular receive packets are NOT being
+ // indicated at the same time. While the filter indication
+ // routines can handle this, I doubt that the transport can.
+ //
+
+ Pc586ProcessLoopback(Adapter);
+
+ //
+ // If there are any opens on the closing list and their
+ // reference counts are zero then complete the close and
+ // delete them from the list.
+ //
+ // ZZZ This really needs to be improved. Currently if
+ // there are any outstanding sends, they are not canceled.
+ //
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ if (!IsListEmpty(&Adapter->CloseList)) {
+
+ PPC586_OPEN Open;
+
+ Open = CONTAINING_RECORD(
+ Adapter->CloseList.Flink,
+ PC586_OPEN,
+ OpenList
+ );
+
+ if (!Open->References) {
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteRequest(
+ Open->NdisBindingContext,
+ Open->CloseHandle,
+ NdisRequestCloseAdapter,
+ NDIS_STATUS_SUCCESS
+ );
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ RemoveEntryList(&Open->OpenList);
+ PC586_FREE_PHYS(Open);
+
+ }
+
+ }
+
+ //
+ // NOTE: This code assumes that the above code left
+ // the spinlock acquired.
+ //
+ // Bottom of the interrupt processing loop. Another dpc
+ // could be coming in at this point to process interrupts.
+ // We clear the flag that says we're processing interrupts
+ // so that some invocation of the DPC can grab it and process
+ // any further interrupts.
+ //
+
+LoopBottom:;
+ Adapter->DoingProcessing = FALSE;
+ Adapter->References--;
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ }
+
+ //
+ // The only way to get out of the loop (via the break above) is
+ // while we're still holding the spin lock.
+ //
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+}
+
+
+
+
+static
+VOID
+ProcessReceiveInterrupts(
+ IN PPC586_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Process the packets that have finished receiving.
+
+ NOTE: This routine assumes that no other thread of execution
+ is processing receives!
+ Get all the enet packets the 586 has for the CPU and put them in
+ in NDIS buffers
+
+Arguments:
+
+ Adapter - The adapter to indicate to.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PFD Fd;
+ PRBD LastRbd, FirstRbd;
+ UINT PacketLength;
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+r1:
+ for(Fd = Adapter->BeginFd; ; Fd = Adapter->BeginFd ) {
+
+ if (Fd == NULL) {
+ DbgPrint("RcvPacket(): Fd == NULL\n");
+ KeBugCheck(9);
+ }
+ if (Fd->FdStatus & CSCMPLT)
+ {
+ Adapter->BeginFd =
+ (PFD)Pc586ToVirt(Adapter, Fd->FdNxtOfst);
+ FirstRbd = (PRBD)Pc586ToVirt(Adapter, Fd->FdRbdOfst);
+
+ if (Fd->FdRbdOfst != 0xffff) {
+ // scan for the end of the rbd's connected to the Fd
+
+ PacketLength = 14; // 6 source, 6 dest, 2 length bytes
+
+ for( LastRbd = FirstRbd; ; LastRbd = (PRBD)
+ Pc586ToVirt(Adapter, LastRbd->RbdNxtOfst)) {
+
+ PacketLength += (LastRbd->RbdStatus & CSRBDCNTMSK);
+
+if ( (LastRbd->RbdSize & 0x3fff) != RCVBUFSIZE) DbgPrint("PC586->ProcessReceiveInterrupts(): LastRbd->RbdSize = 0x%lx, H/W alignment problem\n", LastRbd->RbdSize);
+
+ if (((LastRbd->RbdStatus & CSEOF) == CSEOF) ||
+ ((LastRbd->RbdSize & CSEL) == CSEL)) break;
+ }
+
+ Adapter->BeginRbd =
+ (PRBD)Pc586ToVirt(Adapter, LastRbd->RbdNxtOfst);
+
+ if (Fd->FdStatus & CSOK) {
+ NdisReleaseSpinLock(&Adapter->Lock);
+ PutPacket(Adapter, Fd, PacketLength);
+ NdisAcquireSpinLock(&Adapter->Lock);
+ }
+ else BadRcvCount++;
+
+ }
+ if (Fd->FdCmd & CSEL) {
+ ReQFd(Adapter, Fd);
+ break;
+ }
+ else ReQFd(Adapter, Fd);
+ }
+ else break;
+ }
+
+
+ // ack the rcv status bits
+ WaitScb(Adapter);
+ Adapter->Scb->ScbCmd =
+ (USHORT)(Adapter->Scb->ScbStatus & (SCBINTFR | SCBINTRNR));
+ if (Adapter->Scb->ScbCmd) ChanAttn(Adapter);
+
+ WaitScb(Adapter);
+ RuStart(Adapter);
+ WaitScb(Adapter);
+
+ if ( Adapter->Scb->ScbStatus & (SCBINTFR | SCBINTRNR) ) goto r1;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+}
+
+
+VOID
+PutPacket(
+ IN PPC586_ADAPTER Adapter,
+ IN PFD Fd,
+ IN UINT PacketLength
+ )
+/*++
+
+Routine Description:
+
+ Takes one packet off of the 586's receive ring and "Indicates"
+ it to upper layer network software.
+
+Arguments:
+ Adapter - The adapter that a packet came in on.
+
+Return Value:
+ None.
+
+--*/
+
+{
+ PUSHORT ShortAddr;
+ PUSHORT Buffer;
+ PRBD Rbd;
+ USHORT xx;
+ USHORT ByteCount, LookaheadIndex;
+ PC586_RECEIVE_CONTEXT Context;
+
+ Rbd = (PRBD)Pc586ToVirt(Adapter, Fd->FdRbdOfst);
+ if (Rbd == NULL) return;
+ Buffer = (PUSHORT)Pc586ToVirt(Adapter, Rbd->RbdBuff);
+ if (Buffer == NULL) return;
+
+ ByteCount = (USHORT)(Rbd->RbdStatus & CSRBDCNTMSK);
+
+ // Ndis wants a) destination address, b) source address
+ // c) length field and d) the data, all contiguous
+
+ LookaheadIndex = 0;
+ ShortAddr = (PUSHORT)Fd->FdDest;
+ Adapter->LookaheadBufferNdis[LookaheadIndex++] = *ShortAddr++;
+ Adapter->LookaheadBufferNdis[LookaheadIndex++] = *ShortAddr++;
+ Adapter->LookaheadBufferNdis[LookaheadIndex++] = *ShortAddr++;
+
+ ShortAddr = (PUSHORT)Fd->FdSrc;
+ Adapter->LookaheadBufferNdis[LookaheadIndex++] = *ShortAddr++;
+ Adapter->LookaheadBufferNdis[LookaheadIndex++] = *ShortAddr++;
+ Adapter->LookaheadBufferNdis[LookaheadIndex++] = *ShortAddr++;
+
+ Adapter->LookaheadBufferNdis[LookaheadIndex++] = Fd->FdLength;
+
+if (ww_put == 0) { /*88888888888*/
+
+ for (xx=0; xx < (USHORT)(Rbd->RbdStatus & CSRBDCNTMSK); xx+=2)
+ Adapter->LookaheadBufferNdis[LookaheadIndex++] = *Buffer++;
+
+} else { /*88888888888*/
+
+ for (xx=0; xx < (USHORT)(Rbd->RbdStatus & CSRBDCNTMSK); xx+=4) {
+ *(PULONG)(&(Adapter->LookaheadBufferNdis[LookaheadIndex])) =
+ *(PULONG)(Buffer);
+ LookaheadIndex += 2;
+ Buffer += 2;
+ }
+} /*88888888888*/
+ //
+ // Check just before we do indications that we aren't
+ // resetting.
+ //
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ if (Adapter->ResetInProgress) {
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+ return;
+ }
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ // set lsb to indicate nonloopback packet
+ Context.a.FrameDescriptor = (UINT)Fd | 0x01;
+
+ MacFilterIndicateReceive(
+ Adapter->FilterDB,
+ (NDIS_HANDLE)Context.a.WholeThing,
+ (PCHAR)Adapter->LookaheadBufferNdis,
+ (PVOID)Adapter->LookaheadBufferNdis,
+ (UINT)(LOOKAHEADBUFFERSIZE * 2),
+ PacketLength
+ );
+
+}
+
+
+
+VOID
+ReQFd(
+ IN PPC586_ADAPTER Adapter,
+ IN PFD Fd
+ )
+
+/*++
+
+Routine Description:
+ requeue frame
+
+Arguments:
+
+ Adapter - the net card the packet came in on.
+
+ Fd - The 586 frame descriptor that holds the enet packet
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRBD LastRbd, FirstRbd;
+
+ FirstRbd = (PRBD)Pc586ToVirt(Adapter, Fd->FdRbdOfst);
+
+ Fd->FdStatus = 0;
+ Fd->FdCmd = CSEL | CSSUSPND; // will be the last fd on the list
+ Fd->FdRbdOfst = 0xffff;
+
+ Adapter->EndFd->FdCmd = 0; // no longer the last
+
+ Adapter->EndFd = Fd;
+
+ if (FirstRbd != NULL) {
+ for(
+ LastRbd = FirstRbd;
+
+ (LastRbd->RbdStatus & CSEOF) != CSEOF &&
+ (LastRbd->RbdSize & CSEL) != CSEL;
+
+ LastRbd = (PRBD)Pc586ToVirt(Adapter, LastRbd->RbdNxtOfst)
+ )
+ LastRbd->RbdStatus = 0;
+
+
+ LastRbd->RbdStatus = 0;
+ LastRbd->RbdSize |= CSEL; // new end of rbd list
+
+ Adapter->EndRbd->RbdSize &= ~CSEL;
+if ( (Adapter->EndRbd->RbdSize & 0x3fff) != RCVBUFSIZE) DbgPrint("PC586-> ReQFd: Adapter->EndRbd->RbdSize = 0x%lx, H/W alignment problems\n", LastRbd->RbdSize);
+ Adapter->EndRbd = LastRbd;
+ }
+
+}
+
+
+VOID
+RuStart(
+ IN PPC586_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+ restart the receive unit if necessary
+
+Arguments:
+
+ Adapter - the net card from which a bunch of packets were rcv'd.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PSCB Scb;
+ PFD BeginFd;
+
+ Scb = (PSCB)(Adapter->StaticRam + OFFSETSCB);
+
+ BeginFd = Adapter->BeginFd;
+
+ // if RU already running - leave it alone
+ if ((Scb->ScbStatus & SCBRUSMSK) == SCBRUSREADY) return;
+
+ if ((Scb->ScbStatus & SCBRUSMSK) == SCBRUSSUSPND) {
+ RcvSuspendCount++;
+ WaitScb(Adapter);
+ Scb->ScbCmd = SCBRUCRSUM;
+ ChanAttn(Adapter);
+ return;
+ }
+
+
+ if (BeginFd->FdStatus & CSCMPLT)
+ // The RU is not ready but it just completed an Fd
+ // do NOT restart RU -- this will wipe out the just completed Fd
+ // There will be a second interrupt that will remove the Fd via
+ // RcvPacket()
+ return;
+
+ // if we get here, then RU is not ready and no completed fd's are
+ // available therefore "start" not "resume" the RU
+
+ RcvRestartCount++;
+ BeginFd->FdRbdOfst = VirtToPc586(Adapter,
+ (PCHAR)Adapter->BeginRbd);
+
+ WaitScb(Adapter);
+
+ Scb->ScbCmd = SCBRUCSTRT;
+ Scb->ScbRfaOfst = VirtToPc586(Adapter, (PCHAR)BeginFd);
+ ChanAttn(Adapter);
+
+ return;
+}
+
+
+
+static
+VOID
+StartAdapterReset(
+ IN PPC586_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This is the first phase of resetting the adapter hardware.
+
+ It makes the following assumptions:
+
+ 1) That the hardware has been stopped.
+
+ 2) That it can not be preempted.
+
+ 3) That no other adapter activity can occur.
+
+ When this routine is finished all of the adapter information
+ will be as if the driver was just initialized.
+
+Arguments:
+
+ Adapter - The adapter whose hardware is to be reset.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+
+ Adapter->Stage4Open = TRUE;
+ Adapter->Stage3Open = TRUE;
+ Adapter->Stage2Open = TRUE;
+ Adapter->Stage1Open = TRUE;
+
+ Adapter->AlreadyProcessingStage4 = FALSE;
+ Adapter->AlreadyProcessingStage3 = FALSE;
+ Adapter->AlreadyProcessingStage2 = FALSE;
+
+ //
+ // Go through the various transmit lists and abort every packet.
+ //
+
+ {
+
+ UINT i;
+ PNDIS_PACKET Packet;
+ PPC586_RESERVED Reserved;
+ PPC586_OPEN Open;
+ PNDIS_PACKET Next;
+
+ for (
+ i = 0;
+ i < 5;
+ i++
+ ) {
+
+ switch (i) {
+
+ case 0:
+ Next = Adapter->FirstLoopBack;
+ break;
+ case 1:
+ Next = Adapter->FirstFinishTransmit;
+ break;
+ case 2:
+ Next = Adapter->FirstStage3Packet;
+ break;
+ case 3:
+ Next = Adapter->FirstStage2Packet;
+ break;
+ case 4:
+ Next = Adapter->FirstStage1Packet;
+ break;
+
+ }
+
+
+ while (Next) {
+
+ Packet = Next;
+ Reserved = PPC586_RESERVED_FROM_PACKET(Packet);
+ Next = Reserved->Next;
+ Open =
+ PPC586_OPEN_FROM_BINDING_HANDLE(Reserved->MacBindingHandle);
+
+ //
+ // The completion of the packet is one less reason
+ // to keep the open around.
+ //
+
+ ASSERT(Open->References);
+
+ Open->References--;
+
+ NdisCompleteSend(
+ Open->NdisBindingContext,
+ Reserved->RequestHandle,
+ NDIS_STATUS_REQUEST_ABORTED
+ );
+
+ }
+
+ }
+
+ Adapter->FirstLoopBack = NULL;
+ Adapter->LastLoopBack = NULL;
+ Adapter->FirstFinishTransmit = NULL;
+ Adapter->LastFinishTransmit = NULL;
+ Adapter->FirstStage3Packet = NULL;
+ Adapter->LastStage3Packet = NULL;
+ Adapter->FirstStage2Packet = NULL;
+ Adapter->LastStage2Packet = NULL;
+ Adapter->FirstStage1Packet = NULL;
+ Adapter->LastStage1Packet = NULL;
+
+ }
+
+ SetInitBlockAndInit(Adapter);
+ Pc586IntOn(Adapter);
+
+}
+
+static
+VOID
+SetInitBlockAndInit(
+ IN PPC586_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ It is this routines responsibility to make sure that the
+ initialization block is filled and the chip is initialized
+ *but not* started.
+
+ NOTE: ZZZ This routine is NT specific.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired OR that only a single thread of execution is working
+ with this particular adapter.
+
+Arguments:
+
+ Adapter - The adapter whose hardware is to be initialized.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+
+
+ //
+ // Fill in the adapters initialization block.
+ //
+
+ PISCP Iscp;
+ ULONG xx;
+ PSCB Scb;
+ PPC586_OPEN ResettingOpen;
+ NDIS_REQUEST_TYPE ResetRequestType;
+ PPC586_OPEN Open;
+ PLIST_ENTRY CurrentLink;
+
+
+ //
+ // Possibly undefined request handle for the reset request.
+ //
+ NDIS_HANDLE ResetRequestHandle;
+
+
+ ResetCount++;
+
+
+ // shut off interrupts
+ Pc586IntOff(Adapter);
+
+ // drop chan attn -- even though it should not be raised at this point
+ ShuvWord( (PUSHORT)(Adapter->CmdProm + OFFSETCHANATT) , CMD0);
+
+ // hardware reset the 586
+ ShuvWord( (PUSHORT)(Adapter->CmdProm + OFFSETRESET), (USHORT)CMD1);
+ KeStallExecutionProcessor((ULONG)1000);
+ ShuvWord( (PUSHORT)(Adapter->CmdProm + OFFSETRESET), CMD0);
+ KeStallExecutionProcessor((ULONG)1000);
+
+ // esi loopback - until diagnostics are run
+ ShuvWord( (PUSHORT)(Adapter->CmdProm + OFFSETNORMMODE),
+ (USHORT)CMD1);
+
+ //16 bit for AT bus
+ ShuvWord( (PUSHORT)(Adapter->CmdProm + OFFSET16BXFER),
+ (USHORT)CMD1);
+
+ BuildCu(Adapter); // inits scp, iscp, scb, db, tdb and tbuf
+ BuildRu(Adapter); // inits scb, fd's, rbd's rbufs
+
+ Iscp = (PISCP) (Adapter->StaticRam + OFFSETISCP);
+ Iscp->IscpBusy = 1; // per user man. reset protocol
+
+ // chan attn to feed 586 its data structs
+ ChanAttn(Adapter);
+
+ Scb = (PSCB)(Adapter->StaticRam + OFFSETSCB);
+
+ for(xx=0; xx<0xffff; xx++)
+ if ( Scb->ScbStatus==(SCBINTCX | SCBINTCNA) ) goto SIB1;
+
+ DbgPrint("pc586 SetInitBlockAndInit(): first chan attn failed\n");
+ return;
+
+SIB1:
+ Scb->ScbCmd = SCBACKCX | SCBACKCNA;
+
+ ChanAttn(Adapter); // to clear the reset's ack
+
+ // diag cmd (no. 7) will busy wait for completion
+
+ if (Diagnose586(Adapter) == FALSE) {
+ DbgPrint("pc586 Diagnose586() failed\n");
+ return;
+ }
+ if (Config586(Adapter) == FALSE) {
+ DbgPrint("pc586 Config586() failed\n");
+ return;
+ }
+ LoadMCAddress(Adapter);
+
+ // now turn esi loopback off, rcv started
+
+ ShuvWord( (PUSHORT)(Adapter->CmdProm + OFFSETNORMMODE),
+ (USHORT)CMD1);
+ WaitScb(Adapter);
+ RuStart(Adapter);
+
+ //
+ // This initialization is from either a
+ // reset or test. ZZZ Test not yet implemented.
+ //
+
+ //
+ // This will point (possibly null) to the open that
+ // initiated the reset.
+ //
+
+
+
+ Adapter->ResetInProgress = FALSE;
+
+ //
+ // We save off the open that caused this reset incase
+ // we get *another* reset while we're indicating the
+ // last reset is done.
+ //
+
+ ResettingOpen = Adapter->ResettingOpen;
+ ResetRequestType = Adapter->ResetRequestType;
+ ResetRequestHandle = Adapter->ResetRequestHandle;
+
+ //
+ // We need to signal every open binding that the
+ // reset is complete. We increment the reference
+ // count on the open binding while we're doing indications
+ // so that the open can't be deleted out from under
+ // us while we're indicating (recall that we can't own
+ // the lock during the indication).
+ //
+
+ CurrentLink = Adapter->OpenBindings.Flink;
+
+ while (CurrentLink != &Adapter->OpenBindings) {
+
+ Open = CONTAINING_RECORD(
+ CurrentLink,
+ PC586_OPEN,
+ OpenList
+ );
+
+ Open->References++;
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisIndicateStatus(
+ Open->NdisBindingContext,
+ NDIS_STATUS_RESET,
+ 0
+ );
+
+ NdisIndicateStatusComplete(Open->NdisBindingContext);
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ Open->References--;
+
+ CurrentLink = CurrentLink->Flink;
+
+ }
+
+ //
+ // Look to see which open initiated the reset.
+ //
+ // If the reset was initiated by an open because it
+ // was closing we will let the closing binding loop
+ // further on in this routine indicate that the
+ // request was complete. ZZZ (Still need to code
+ // this part.)
+ //
+ // If the reset was initiated for some obscure hardware
+ // reason that can't be associated with a particular
+ // open (e.g. memory error on receiving a packet) then
+ // we won't have an initiating request so we can't
+ // indicate. (The ResettingOpen pointer will be
+ // NULL in this case.)
+ //
+
+ if (ResettingOpen &&
+ (ResetRequestType != NdisRequestCloseAdapter)) {
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+ NdisCompleteRequest(
+ ResettingOpen->NdisBindingContext,
+ ResetRequestHandle,
+ ResetRequestType,
+ NDIS_STATUS_SUCCESS
+ );
+ NdisAcquireSpinLock(&Adapter->Lock);
+ ResettingOpen->References--;
+ }
+
+}
+
+
+
+static
+VOID
+SetupForReset(
+ IN PPC586_ADAPTER Adapter,
+ IN PPC586_OPEN Open,
+ IN NDIS_HANDLE RequestHandle,
+ IN NDIS_REQUEST_TYPE RequestType
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to fill in the who and why a reset is
+ being set up as well as setting the appropriate fields in the
+ adapter.
+
+ NOTE: This routine must be called with the lock acquired.
+
+Arguments:
+
+ Adapter - The adapter whose hardware is to be initialized.
+
+ Open - A (possibly NULL) pointer to an pc586 open structure.
+ The reason it could be null is if the adapter is initiating the
+ reset on its own.
+
+ RequestHandle - If open is not null then the request handle of the
+ request that is causing the reset.
+
+ RequestType - If the open is not null then the request type that
+ is causing the reset.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ //
+ // Shut down the chip. We won't be doing any more work until
+ // the reset is complete.
+ //
+
+ Pc586IntOff(Adapter);
+
+ //
+ // Once the chip is stopped we can't get any more interrupts.
+ // Any interrupts that are "queued" for processing could
+ // only possibly service this reset.
+ //
+
+
+ Adapter->ResetInProgress = TRUE;
+
+ //
+ // Shut down all of the transmit queues so that the
+ // transmit portion of the chip will eventually calm down.
+ //
+
+ Adapter->Stage4Open = FALSE;
+ Adapter->Stage3Open = FALSE;
+ Adapter->Stage2Open = FALSE;
+ Adapter->Stage1Open = FALSE;
+
+ Adapter->ResetRequestHandle = RequestHandle;
+ Adapter->ResettingOpen = Open;
+ Adapter->ResetRequestType = RequestType;
+
+ //
+ // If there is a valid open we should up the reference count
+ // so that the open can't be deleted before we indicate that
+ // their request is finished.
+ //
+
+ if (Open) {
+
+ Open->References++;
+
+ }
+
+}
+
+
+
+static
+BOOLEAN
+ProcessTransmitInterrupts(
+ IN PPC586_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Process the packets that have finished transmitting.
+
+ NOTE: This routine assumes that it is being executed in a
+ single thread of execution.
+
+Arguments:
+
+ Adapter - The adapter that was sent from.
+
+Return Value:
+
+ This function will return TRUE if it finished up the
+ send on a packet. It will return FALSE if for some
+ reason there was no packet to process.
+
+--*/
+
+{
+
+ //
+ // Pointer to the packet that started this transmission.
+ //
+ PNDIS_PACKET OwningPacket;
+
+ //
+ // Points to the reserved part of the OwningPacket.
+ //
+ PPC586_RESERVED Reserved;
+
+
+
+ //
+ // Get a pointer to the owning packet and the reserved part of
+ // the packet.
+ //
+
+ OwningPacket = Adapter->OwningPacket;
+
+ if (OwningPacket == NULL) return FALSE;
+
+ Reserved = PPC586_RESERVED_FROM_PACKET(OwningPacket);
+
+ //
+ // Check that the host does indeed own this entire packet.
+ //
+
+ if ( !(Adapter->Cb->CmdStatus & CSCMPLT) ||
+ (Adapter->Cb->CmdStatus & CSBUSY) ) {
+
+ //
+ // We don't own the command block. We return FALSE to indicate
+ // that we don't have any more packets to work on.
+ //
+
+ return FALSE;
+
+ } else {
+
+ ReturnAdapterResources(Adapter);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->OwningPacket = NULL;
+
+ if (Reserved->STAGE.STAGE4.ReadyToComplete) {
+
+ //
+ // The binding that is submitting this packet.
+ //
+ PPC586_OPEN Open =
+ PPC586_OPEN_FROM_BINDING_HANDLE(Reserved->MacBindingHandle);
+
+
+ //
+ // While we're indicating we increment the reference
+ // count so that the open can't be deleted out
+ // from under us.
+ //
+
+ Open->References++;
+
+ //
+ // Along with at least one reference because of the coming
+ // indication there should be a reference because of the
+ // packet to indicate.
+ //
+
+ ASSERT(Open->References > 1);
+
+ //
+ // Either the packet is done with loopback or
+ // the packet didn't need to be loopbacked. In
+ // any case we can let the protocol know that the
+ // send is complete after we remove the packet from
+ // the finish transmit queue.
+ //
+
+ Pc586RemovePacketOnFinishTrans(
+ Adapter,
+ OwningPacket
+ );
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteSend(
+ Open->NdisBindingContext,
+ Reserved->RequestHandle,
+ NDIS_STATUS_SUCCESS
+ );
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ //
+ // We reduce the count by two to account for the fact
+ // that we aren't indicating to the open and that one
+ // less packet is owned by this open.
+ //
+
+ Open->References -= 2;
+
+ } else {
+
+ //
+ // Let the loopback queue know that the hardware
+ // is finished with the packet, and record whether
+ // it could transmit or not.
+ //
+
+ Reserved->STAGE.STAGE4.ReadyToComplete = TRUE;
+ Reserved->STAGE.STAGE4.SuccessfulTransmit = TRUE;
+
+ //
+ // Decrement the reference count by one since it
+ // was incremented by one when the packet was given
+ // to be transmitted.
+ //
+
+ PPC586_OPEN_FROM_BINDING_HANDLE(
+ Reserved->MacBindingHandle
+ )->References--;
+
+ }
+
+ //
+ // Since we've given back some ring entries we should
+ // open of stage3 if it was closed and we are not resetting.
+ //
+
+ if ((!Adapter->Stage3Open) && (!Adapter->ResetInProgress)) {
+
+ Adapter->Stage3Open = TRUE;
+
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+ return TRUE;
+ }
+
+}
+
+
+static
+VOID
+ReturnAdapterResources(
+ IN PPC586_ADAPTER Adapter
+ )
+
+/*++
+Routine Description
+ Return staged resources.
+
+Arguments:
+ Adapter - The adapter that the packet came through
+
+Return Value:
+ None.
+
+--*/
+
+{
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ //
+ // If stage 2 as closed and we aren't resetting then open
+ // it back up.
+ //
+
+ if ((!Adapter->Stage2Open) && (!Adapter->ResetInProgress)) {
+ Adapter->Stage2Open = TRUE;
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+}
+
+
+
+VOID
+LoadMCAddress(
+ IN PPC586_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Download multicast addresses to 82586 chip by using a 586 command.
+
+Arguments:
+
+ Adapter - the network chip to be loaded with multicast addresses.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+
+ PSCB Scb;
+ PCMD Cb;
+ ULONG xx;
+ UINT PacketFilters;
+
+ Scb = Adapter->Scb;
+ Cb = Adapter->Cb;
+
+ // first ack the status bits
+ WaitScb(Adapter);
+ Scb->ScbCmd = (USHORT)(Scb->ScbStatus & SCBINTMSK);
+ if (Scb->ScbCmd) ChanAttn(Adapter);
+
+ //
+ // Set up the address filtering.
+ //
+ // First get hold of the combined packet filter.
+ //
+
+ PacketFilters = MAC_QUERY_FILTER_CLASSES(Adapter->FilterDB);
+
+ if (PacketFilters & NDIS_PACKET_TYPE_PROMISCUOUS) {
+
+ DbgPrint("PC586 driver - promiscuous mode not supported\n");
+
+ } else if (PacketFilters & NDIS_PACKET_TYPE_ALL_MULTICAST) {
+
+ DbgPrint("PC586 driver - all multicast mode not supported\n");
+
+ } else if (PacketFilters & NDIS_PACKET_TYPE_MULTICAST) {
+
+ //
+ // At least one open binding wants multicast addresses.
+ //
+
+ USHORT MulticastAddresses[MAX_MULTICAST_ADDRESS]
+ [ MAC_LENGTH_OF_ADDRESS / 2 ];
+ UINT NumberOfAddresses;
+
+ MacQueryFilterAddresses(
+ Adapter->FilterDB,
+ &NumberOfAddresses,
+ (PCHAR)MulticastAddresses
+ );
+
+ ASSERT(sizeof(UINT) == 4);
+
+ if (NumberOfAddresses == 0) return;
+
+ for (
+ xx = 0;
+ xx < NumberOfAddresses;
+ xx++
+ ) {
+
+ Cb->PRMTR.PrmMcSet.McAddress[xx][0] =
+ MulticastAddresses[xx][0];
+ Cb->PRMTR.PrmMcSet.McAddress[xx][1] =
+ MulticastAddresses[xx][1];
+ Cb->PRMTR.PrmMcSet.McAddress[xx][2] =
+ MulticastAddresses[xx][2];
+
+/* 8888
+ yy.c.b = MulticastAddresses[xx][2];
+ zz.c.a[0] = yy.c.a[1];
+ zz.c.a[1] = yy.c.a[0];
+ Cb->PRMTR.PrmMcSet.McAddress[xx][0] = zz.c.b;
+
+ yy.c.b = MulticastAddresses[xx][1];
+ zz.c.a[0] = yy.c.a[1];
+ zz.c.a[1] = yy.c.a[0];
+ Cb->PRMTR.PrmMcSet.McAddress[xx][1] = zz.c.b;
+
+ yy.c.b = MulticastAddresses[xx][0];
+ zz.c.a[0] = yy.c.a[1];
+ zz.c.a[1] = yy.c.a[0];
+ Cb->PRMTR.PrmMcSet.McAddress[xx][2] = zz.c.b;
+8888 */
+ }
+
+ // McCnt is the total number of bytes in the McAddress[] field
+ Cb->PRMTR.PrmMcSet.McCnt = (USHORT)NumberOfAddresses * 6;
+
+
+ // now do the multicast address command
+ WaitScb(Adapter);
+ Cb->CmdStatus = 0;
+ Cb->CmdCmd = CSCMDMCSET | CSEL;
+ Scb->ScbCmd = SCBCUCSTRT;
+ ChanAttn(Adapter);
+ WaitScb(Adapter);
+ for(xx=0; xx<0xfffff; xx++)
+ if (Cb->CmdStatus & CSOK) {
+ Scb->ScbCmd = (USHORT)(Scb->ScbStatus & SCBINTMSK);
+ if (Scb->ScbCmd) ChanAttn(Adapter);
+ return;
+ }
+
+ DbgPrint("pc586 LoadMCAddress() mc command failed\n");
+ return;
+
+ }
+}
+
+
+VOID
+ShuvWord(
+ IN PUSHORT VirtAddr,
+ IN USHORT Value
+ )
+
+/*++
+
+Routine Description:
+
+ Utility to write to pc586 memory mapped hardware.
+
+Arguments:
+
+ VirtAddr - virtual address of the memory mapped item.
+
+ Value - what's to be written at memory mapped address.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ *VirtAddr = Value;
+}
+
+
+VOID
+ShuvByte(
+ IN PUCHAR VirtAddr,
+ IN UCHAR Value
+ )
+/*++
+
+Routine Description:
+
+ Same as ShuvWord only for 8-bit quantity.
+
+Arguments:
+
+ See ShuvWord
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ *VirtAddr = Value;
+}
+
+
+USHORT
+PullWord(
+ IN PUSHORT VirtAddr
+ )
+/*++
+
+Routine Description:
+
+ Gets a 16-bit quantity at a given pc586 memory mapped hardware address.
+
+Arguments:
+
+ VirtAddr - address at which to retrieve a value.
+
+Return Value:
+
+ The data at VirtAddr address.
+
+--*/
+{
+ USHORT Value;
+ return (Value = *VirtAddr);
+}
+
+
+
+
+VOID
+BuildCu(
+ IN PPC586_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ Sets up 586 command unit data structures.
+
+Arguments:
+
+ Adapter - points to the memory map of the net card to be set up.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PCMD Cb;
+ PTBD Tbd;
+ PSCP Scp;
+ PISCP Iscp;
+ PSCB Scb;
+
+ Cb = Adapter->Cb;
+ Tbd = Adapter->Tbd;
+ Scp = Adapter->Scp;
+ Iscp = Adapter->Iscp;
+ Scb = Adapter->Scb;
+
+ Scp->ScpSysBus = 0;
+ Scp->ScpIscp = OFFSETISCP;
+ Scp->ScpIscpBase = 0;
+
+ Iscp->IscpBusy = 1;
+ Iscp->IscpScbOfst = OFFSETSCB;
+ Iscp->IscpScbBase = 0;
+
+ Scb->ScbStatus = 0;
+ Scb->ScbCmd = 0;
+ Scb->ScbCblOfst = OFFSETCU;
+ Scb->ScbRfaOfst = OFFSETRU;
+ Scb->ScbCrcErr = 0;
+ Scb->ScbAlnErr = 0;
+ Scb->ScbRscErr = 0;
+ Scb->ScbOvrnErr = 0;
+
+ Cb->CmdStatus = 0;
+ Cb->CmdCmd = CSEL;
+ Cb->CmdNxtOfst = OFFSETCU;
+
+ Tbd->TbdCount = 0;
+ Tbd->TbdNxtOfst = 0xffff;
+ Tbd->TbdBuff = 0;
+ Tbd->TbdBuffBase = 0;
+}
+
+
+
+
+VOID
+BuildRu(
+ IN PPC586_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ Sets up the receive data structures for 586 receive unit.
+
+Arguments:
+
+ Adapter - points to net card's memory map to be written on.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PFD Fd;
+ ULONG xx;
+
+ typedef struct _RUBUF {
+ RBD r;
+ CHAR RbdPad[2]; // puts RBuffer on 4 byte boundry
+ UCHAR RBuffer[RCVBUFSIZE];
+ } RUBUF, *PRUBUF;
+
+ PRUBUF Rbd;
+
+
+// FIRST BUILD THE FRAME DESCRIPTOR LIST
+
+ Fd = (PFD)(Adapter->StaticRam + OFFSETRU);
+
+ for (xx=0; xx<NFD; xx++) {
+ Fd->FdStatus = 0;
+ Fd->FdCmd = 0;
+ // point to the next fd
+ Fd->FdNxtOfst = VirtToPc586(Adapter, (PUCHAR)(Fd +1));
+ Fd->FdRbdOfst = 0xffff; // must be 0xffff, see manual
+ Fd++;
+ }
+ Adapter->EndFd = --Fd;
+ Fd->FdNxtOfst = OFFSETRU; // Fd's are now in a circular list
+ Fd->FdCmd = CSEL | CSSUSPND; // end of receive Fd list
+
+ Fd = Adapter->BeginFd =(PFD)(Adapter->StaticRam + OFFSETRU);
+
+ // SECOND BUILD THE RECEIVE BUFFER DESCRIPTOR LIST
+
+ Rbd = (PRUBUF)(Adapter->StaticRam + OFFSETRBD);
+ Adapter->BeginRbd = (PRBD)(Adapter->StaticRam + OFFSETRBD);
+
+ // make the first Fd point to the first Rbd
+ Fd->FdRbdOfst = VirtToPc586(Adapter, (PUCHAR)Rbd);
+
+ for(xx=0; xx<NRBD; xx++) {
+ Rbd->r.RbdStatus = 0;
+ Rbd->r.RbdNxtOfst = VirtToPc586(Adapter, (PUCHAR)(Rbd+1) );
+ Rbd->r.RbdBuff = VirtToPc586(Adapter, (PUCHAR)Rbd->RBuffer);
+ Rbd->r.RbdBuffBase = 0;
+ Rbd->r.RbdSize = RCVBUFSIZE;
+ Rbd++;
+ }
+
+ // fixup very last Rbd on the list
+ Rbd--;
+ Adapter->EndRbd = (PRBD)(Rbd);
+ Rbd->r.RbdNxtOfst = OFFSETRBD;
+ Rbd->r.RbdSize |= CSEL;
+
+}
+
+
+BOOLEAN
+Diagnose586(
+ IN PPC586_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Runs 82586 diagnostics to see if chip is functioning.
+
+Arguments:
+
+ Adapter - points to net card in question.
+
+Return Value:
+
+ True - if card checks out ok.
+
+--*/
+{
+ PSCB Scb;
+ PCMD Cb;
+ ULONG xx;
+
+ Scb = Adapter->Scb;
+ Cb = Adapter->Cb;
+
+ // first ack the status bits
+ WaitScb(Adapter);
+ Scb->ScbCmd = (USHORT)(Scb->ScbStatus & SCBINTMSK);
+ if (Scb->ScbCmd) ChanAttn(Adapter);
+
+ // now do the diagnose
+ WaitScb(Adapter);
+ Cb->CmdStatus = 0;
+ Cb->CmdCmd = CSCMDDGNS | CSEL;
+ Scb->ScbCmd = SCBCUCSTRT;
+ ChanAttn(Adapter);
+ WaitScb(Adapter);
+ for(xx=0; xx<0xfff; xx++)
+ if (Cb->CmdStatus & CSOK) {
+ Scb->ScbCmd = (USHORT)(Scb->ScbStatus & SCBINTMSK);
+ if (Scb->ScbCmd) ChanAttn(Adapter);
+ return TRUE;
+ }
+
+ return FALSE;
+
+}
+
+
+
+BOOLEAN
+Config586(
+ IN PPC586_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ Configures 586 network chip for standard configuration.
+
+Arguments:
+
+ Adapter - points to the netcard that holds 586 to be configured.
+
+
+Return Value:
+
+ TRUE - if configuration went well.
+
+--*/
+{
+ PSCB Scb;
+ PCMD Cb;
+ ULONG xx;
+ PUSHORT Addr, Addr2;
+
+ Scb = Adapter->Scb;
+ Cb = Adapter->Cb;
+
+ // first ack the status bits
+ WaitScb(Adapter);
+ Scb->ScbCmd = (USHORT)(Scb->ScbStatus & SCBINTMSK);
+ if (Scb->ScbCmd) ChanAttn(Adapter);
+
+ // now do configuration
+ WaitScb(Adapter);
+ Cb->CmdStatus = 0;
+ Cb->CmdCmd = CSCMDCONF | CSEL;
+
+ Cb->PRMTR.PrmConf.CnfFifoByte = 0x080c;
+ Cb->PRMTR.PrmConf.CnfAddMode = 0x2600;
+ Cb->PRMTR.PrmConf.CnfPriData = 0x6000;
+ Cb->PRMTR.PrmConf.CnfSlot = 0xf200;
+ Cb->PRMTR.PrmConf.CnfHrdwr = 0x0000;
+ Cb->PRMTR.PrmConf.CnfMinLen = 0x0040;
+
+ Scb->ScbCmd = SCBCUCSTRT;
+ ChanAttn(Adapter);
+ WaitScb(Adapter);
+ for(xx=0; xx<0xfff; xx++)
+ if (Cb->CmdStatus & CSOK) goto c1;
+ return FALSE;
+
+c1:
+ Scb->ScbCmd = (USHORT)(Scb->ScbStatus & SCBINTMSK);
+ if (Scb->ScbCmd) ChanAttn(Adapter);
+
+ // next, download ethernet address to 586 chip
+
+ WaitScb(Adapter);
+ Cb->CmdStatus = 0;
+ Cb->CmdCmd = CSCMDIASET | CSEL;
+
+
+ Addr = (PUSHORT)Adapter->NetworkAddress;
+ Addr2 = (PUSHORT)Cb->PRMTR.PrmIaSet;
+
+ for(xx=0; xx<MAC_LENGTH_OF_ADDRESS/2; xx++) {
+ *Addr2 = *Addr;
+ *Addr2++;
+ *Addr++;
+ }
+
+ Scb->ScbCmd = SCBCUCSTRT;
+ ChanAttn(Adapter);
+
+ for(xx=0; xx<0xfff; xx++)
+ if (Cb->CmdStatus & CSOK) goto c2;
+ return FALSE;
+
+c2:
+ Scb->ScbCmd = (USHORT)(Scb->ScbStatus & SCBINTMSK);
+ ChanAttn(Adapter);
+ return TRUE;
+}
+
+
+
+USHORT
+PromAddr(
+ IN PPC586_ADAPTER Adapter,
+ IN ULONG Index
+ )
+/*++
+
+Routine Description:
+
+ Pulls the unique enet id out of the netcard's special eprom.
+
+Arguments:
+
+ Adapter - points to the card to get the address from.
+
+ Index - index of which byte of enet address to get.
+
+Return Value:
+
+ Bytes of e-net address.
+
+--*/
+
+{
+ PUCHAR CmdProm;
+
+ CmdProm = Adapter->CmdProm;
+ CmdProm += OFFSETADDRPROM;
+ CmdProm += Index;
+ return *CmdProm;
+}
+
+
+
+VOID
+ChanAttn(
+ IN PPC586_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ Tickles the network card to get the 82586's attention.
+
+Arguments:
+
+ Adapter - points to the card in question.
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ // first byte of word is 1 - this sets the CA
+ // second byte of word is 0 - this clears the CA
+
+ ShuvWord(Adapter->CAAddr, 0x01);
+}
+
+
+VOID
+WaitScb(
+ IN PPC586_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine waits a reasonable length of time for the 586 to
+ read and dispatch a previous command.
+
+Arguments:
+
+ Adapter - points to net card in question
+
+Return Value:
+
+ TRUE - if 586 failed.
+
+ FALSE - if 586 dispatched previous command within time limit.
+
+--*/
+
+{
+ PSCB Scb;
+ ULONG xx;
+
+ Scb = Adapter->Scb;
+ for (xx=0; xx<0xffff; xx++)
+ if (Scb->ScbCmd == 0) return;
+ DbgPrint("pc586 WaitScb() - timed out\n");
+ return;
+}
+
+
+
+USHORT
+VirtToPc586(
+ IN PPC586_ADAPTER Adapter,
+ IN PUCHAR KernelVirtAddr
+ )
+/*++
+
+Routine Description:
+
+ The CPU's 32-bit addresses are converted to 16-bit addresses that are
+ compatible with 82586.
+
+Arguments:
+
+ Adapter - points to net card in question.
+
+ KernelVirtAddr - the address to be converted.
+
+Return Value:
+
+ 586 style address.
+
+--*/
+
+{
+ USHORT Addr586;
+
+ // 586 uses 0xffff for null as "c" uses zero for null
+ if (KernelVirtAddr == NULL)
+ return 0xffff;
+
+ if ( (KernelVirtAddr > Adapter->StaticRam + 32*1024 ) ||
+ (KernelVirtAddr < Adapter->StaticRam -1 ) ) {
+
+ DbgPrint("VirtToPc586(): wild kernel virt addr of 0x%x\n",
+ KernelVirtAddr);
+ return 0xffff;
+ }
+ Addr586 = (USHORT)(KernelVirtAddr - Adapter->StaticRam);
+ return Addr586;
+}
+
+PUCHAR
+Pc586ToVirt(
+ IN PPC586_ADAPTER Adapter,
+ IN USHORT Addr586
+ )
+/*++
+
+Routine Description:
+
+ Converts from 82586 style 16-bit address to flat 32-bit CPU address.
+
+Arguments:
+
+ Adapter - points to network card in question.
+
+ Addr586 - 586 16-bit address to be converted.
+
+Return Value:
+
+ A flat 32-bit CPU address.
+
+--*/
+{
+ if (Addr586 == 0xffff) return NULL;
+
+ if (Addr586 > 0x7fff) {
+ DbgPrint("Pc586ToVirt(): wild 586 pointer of 0x%x\n", Addr586);
+ return NULL;
+ }
+
+ return (Adapter->StaticRam + Addr586);
+
+}
+
+
+
+static
+VOID
+Pc586IntOn(
+ IN PPC586_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ Flips a switch on the network card to connect 586 interrupts to host CPU.
+
+Arguments:
+
+ Adapter - points to network card in question.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ ShuvWord( (PUSHORT)(Adapter->IntAddr),
+ (USHORT)CMD1 );
+}
+
+static
+VOID
+Pc586IntOff(
+ IN PPC586_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ Flips switch on network card to disconnect 586 interrupts from
+ host CPU.
+
+Arguments:
+
+ Adapter - points to netcard in question.
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ShuvWord( (PUSHORT)(Adapter->IntAddr),
+ (USHORT)CMD0 );
+}
diff --git a/private/ntos/ndis/pc586e/pc586e.c b/private/ntos/ndis/pc586e/pc586e.c
new file mode 100644
index 000000000..31a1276fd
--- /dev/null
+++ b/private/ntos/ndis/pc586e/pc586e.c
@@ -0,0 +1,119 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ pc586e.c
+
+Abstract:
+
+ THIS MODULE IS TEMPORARY. It is here simply to test the build
+ procedures for the NDIS driver directories.
+
+Author:
+
+ Chuck Lenzmeier (chuckl) 10-Jul-1990
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+
+--*/
+
+#include <ntos.h>
+
+#include <ndis.h>
+
+static
+NTSTATUS
+Pc586eDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+
+VOID
+Pc586eInitialize(
+ IN PDRIVER_OBJECT DriverObject
+ )
+
+/*++
+
+Routine Description:
+
+ This is the initialization routine for the driver. It is invoked once
+ when the driver is loaded into the system. Its job is to initialize all
+ the structures which will be used by the FSD.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CLONG i;
+
+ //
+ // Initialize the driver object with this driver's entry points.
+ //
+
+ for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
+ DriverObject->MajorFunction[i] = Pc586eDispatch;
+ }
+
+ //
+ // Initialize the wrapper. (This is here to verify that we can pull
+ // in the wrapper library.)
+ //
+
+ NdisInitializeWrapper( );
+
+}
+
+
+static
+NTSTATUS
+Pc586eDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the main dispatch routine for the FSD. This routine
+ accepts an I/O Request Packet (IRP) and either performs the request
+ itself, or it passes it to the FSP for processing.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+
+{
+ KIRQL oldIrql;
+
+ KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
+ IoCompleteRequest( Irp, 0 );
+ KeLowerIrql( oldIrql );
+
+ return STATUS_NOT_IMPLEMENTED;
+}
diff --git a/private/ntos/ndis/pc586e/pc586hrd.h b/private/ntos/ndis/pc586e/pc586hrd.h
new file mode 100644
index 000000000..6de7e66f5
--- /dev/null
+++ b/private/ntos/ndis/pc586e/pc586hrd.h
@@ -0,0 +1,438 @@
+
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ pc586hrd.h
+
+Abstract:
+
+ This header file is broken into two halves, 82586 specific first and
+ pc586 netcard second.
+
+Author:
+
+ Weldon Washburn (o-weldo, Intel) 11/11/90
+
+Environment:
+
+
+Notes:
+
+
+Revision History:
+
+
+--*/
+
+#define static
+
+// the below #defines were transformed into static USHORTS to workaround
+// a compiler optimization that does not agree with pc586 hardware. See
+// ushort.c for current definitions.
+
+#if 0
+// 82586 header file
+
+
+#define SCBINTMSK 0xf000 // SCB STAT bit mask
+#define SCBINTCX 0x8000 // CX bit, CU finished a command with "I" set
+#define SCBINTFR 0x4000 // FR bit, RU finished receiving a frame
+#define SCBINTCNA 0x2000 // CNA bit, CU not active
+#define SCBINTRNR 0x1000 // RNR bit, RU not ready
+
+// command unit status bits
+
+#define SCBCUSMSK 0x0700 // SCB CUS bit mask
+#define SCBCUSIDLE 0x0000 // CU idle
+#define SCBCUSSUSPND 0x0100 // CU suspended
+#define SCBCUSACTV 0x0200 // CU active
+
+// receive unit status bits
+
+#define SCBRUSMSK 0x0070 // SCB RUS bit mask
+#define SCBRUSIDLE 0x0000 // RU idle
+#define SCBRUSSUSPND 0x0010 // RU suspended
+#define SCBRUSNORESRC 0x0020 // RU no resource
+#define SCBRUSREADY 0x0040 // RU ready
+
+// bits used to acknowledge an interrupt from 586
+
+#define SCBACKMSK 0xf000 // SCB ACK bit mask
+#define SCBACKCX 0x8000 // ACKCX, acknowledge a completed cmd
+#define SCBACKFR 0x4000 // ACKFR, acknowledge a frame reception
+#define SCBACKCNA 0x2000 // ACKCNA, acknowledge CU not active
+#define SCBACKRNR 0x1000 // ACKRNR, acknowledge RU not ready
+
+// 586 CU commands
+
+#define SCBCUCMSK 0x0700 // SCB CUC bit mask
+#define SCBCUCSTRT 0x0100 // start CU
+#define SCBCUCRSUM 0x0200 // resume CU
+#define SCBCUCSUSPND 0x0300 // suspend CU
+#define SCBCUCABRT 0x0400 // abort CU
+
+// 586 RU commands
+
+#define SCBRUCMSK 0x0070 // SCB RUC bit mask
+#define SCBRUCSTRT 0x0010 // start RU
+#define SCBRUCRSUM 0x0020 // resume RU
+#define SCBRUCSUSPND 0x0030 // suspend RU
+#define SCBRUCABRT 0x0040 // abort RU
+
+#define SCBRESET 0x0080 // software reset of 586
+
+// #define's for the command and descriptor blocks
+
+#define CSCMPLT 0x8000 // C bit, completed
+#define CSBUSY 0x4000 // B bit, Busy
+#define CSOK 0x2000 // OK bit, error free
+#define CSABORT 0x1000 // A bit, abort
+#define CSEL 0x8000 // EL bit, end of list
+#define CSSUSPND 0x4000 // S bit, suspend
+#define CSINT 0x2000 // I bit, interrupt
+#define CSSTATMSK 0x3fff // Command status mask
+#define CSEOL 0xffff // set for fdrbdofst on unattached FDs
+#define CSEOF 0x8000 // EOF (End Of Frame) in the TBD and RBD
+#define CSRBDCNTMSK 0x3fff // actual count mask in RBD
+
+// second level commands
+
+#define CSCMDMSK 0x07 // command bits mask
+#define CSCMDNOP 0x00 // NOP
+#define CSCMDIASET 0x01 // Individual Address Set up
+#define CSCMDCONF 0x02 // Configure
+#define CSCMDMCSET 0x03 // Multi-Cast Setup
+#define CSCMDXMIT 0x04 // transmit
+#define CSCMDTDR 0x05 // Time Domain Reflectomete
+#define CSCMDDUMP 0x06 // dump
+#define CSCMDDGNS 0x07 // diagnose
+
+#endif // 0
+
+extern SCBINTMSK;
+extern SCBINTCX;
+extern SCBINTFR;
+extern SCBINTCNA;
+extern SCBINTRNR;
+
+// command unit status bits
+
+extern SCBCUSMSK;
+extern SCBCUSIDLE;
+extern SCBCUSSUSPND;
+extern SCBCUSACTV;
+
+// receive unit status bits
+
+extern SCBRUSMSK;
+extern SCBRUSIDLE;
+extern SCBRUSSUSPND;
+extern SCBRUSNORESRC;
+extern SCBRUSREADY;
+
+// bits used to acknowledge an interrupt from 586
+
+extern SCBACKMSK;
+extern SCBACKCX;
+extern SCBACKFR;
+extern SCBACKCNA;
+extern SCBACKRNR;
+
+// 586 CU commands
+
+extern SCBCUCMSK;
+extern SCBCUCSTRT;
+extern SCBCUCRSUM;
+extern SCBCUCSUSPND;
+extern SCBCUCABRT;
+
+// 586 RU commands
+
+extern SCBRUCMSK;
+extern SCBRUCSTRT;
+extern SCBRUCRSUM;
+extern SCBRUCSUSPND;
+extern SCBRUCABRT;
+
+extern SCBRESET;
+
+// extern's for the command and descriptor blocks
+
+extern CSCMPLT;
+extern CSBUSY;
+extern CSOK;
+extern CSABORT;
+extern CSEL;
+extern CSSUSPND;
+extern CSINT;
+extern CSSTATMSK;
+extern CSEOL;
+extern CSEOF;
+extern CSRBDCNTMSK;
+
+// second level commands
+
+extern CSCMDMSK;
+extern CSCMDNOP;
+extern CSCMDIASET;
+extern CSCMDCONF;
+extern CSCMDMCSET;
+extern CSCMDXMIT;
+extern CSCMDTDR;
+extern CSCMDDUMP;
+extern CSCMDDGNS;
+
+
+
+#define MAX_MULTICAST_ADDRESS ((UINT)16)
+typedef UCHAR NETADDR[6];
+
+// at address 0xfffff6 the 586 sees the following data structure
+
+typedef struct SCP {
+ USHORT ScpSysBus; // system bus width
+ USHORT ScpUnused[2]; // unused area
+ USHORT ScpIscp; // points to iscpt
+ USHORT ScpIscpBase; // points to iscpt
+} SCP, *PSCP;
+
+typedef struct ISCP {
+ USHORT IscpBusy; // 1 means 82586 is initializing
+ // only the first 8 bit are used
+ USHORT IscpScbOfst; // offset of the scb in the shared memory
+ PVOID IscpScbBase; // base of shared memory
+} ISCP, *PISCP;
+
+// System Control Block
+typedef struct SCB {
+ USHORT ScbStatus; // STAT, CUS, RUS
+ USHORT ScbCmd; // ACK, CUC, RUC
+ USHORT ScbCblOfst; // CBL (Command Block List) offset
+ USHORT ScbRfaOfst; // RFA (Receive Frame Area) offset
+ USHORT ScbCrcErr; // count of CRC errors.
+ USHORT ScbAlnErr; // count of alignment errors
+ USHORT ScbRscErr; // count of no resource errors
+ USHORT ScbOvrnErr; // count of overrun errors
+} SCB, *PSCB;
+
+
+// config command sub-block
+
+typedef struct CONF {
+ USHORT CnfFifoByte; // BYTE CNT, FIFO LIM (TXFIFO)
+ USHORT CnfAddMode; // SRDY, SAVBF, ADDRLEN, ALLOC, PREAMLEN
+ // INTLPBCK, EXTLPBK
+ USHORT CnfPriData; // LINPRIO, ACR, BOFMET, INTERFRAMESPACING
+ USHORT CnfSlot; // SLOTTIME, RETRY NUMBER
+ USHORT CnfHrdwr; // PRM, BCDIS, MANCH/NRZ, TONOCRS, NCRCINS
+ // CRC, BTSTF, PAD,CRSF,CRSSRC,CDTF,CDTSRC
+ USHORT CnfMinLen; // MinFRMLEN
+} CONF, *PCONF;
+
+// xmt command sub-block
+
+typedef struct TRANSMIT {
+ USHORT XmtTbdOfst; // Transmit Buffer Descriptor offset
+ NETADDR XmtDest; // Destination Address
+ USHORT XmtLength; // length of the frame
+} TRANSMIT, *PTRANSMIT;
+
+// dump command sub-block
+
+typedef struct DUMP {
+ USHORT DmpBufOfst; // dump buffer offset
+} DUMP, *PDUMP;
+
+typedef struct MCADDR {
+ USHORT McCnt;
+ USHORT McAddress[MAX_MULTICAST_ADDRESS][MAC_LENGTH_OF_ADDRESS / 2];
+} MCADDR, *PMCADDR;
+
+
+// command block and sub-blocks
+
+typedef struct CMD {
+ USHORT CmdStatus, // C, B, command specific status
+ CmdCmd, // EL, S, I, opcode
+ CmdNxtOfst; // pointer to the next command block
+ union {
+ DUMP PrmDump; // dump
+ TRANSMIT PrmXmit; // transmit
+ CONF PrmConf; // configure
+ NETADDR PrmIaSet; // individual address setup
+ MCADDR PrmMcSet; // multicast command
+ } PRMTR; // parameters
+} CMD, *PCMD;
+
+// xmt buffer descriptor
+
+typedef struct TBD {
+ USHORT TbdCount; // End Of Frame(EOF), Actual count(ACTCOUNT)
+ USHORT TbdNxtOfst; // offset of next TBD
+ USHORT TbdBuff; // tbd address
+ USHORT TbdBuffBase; // tbd address
+} TBD, *PTBD;
+
+// rcv buffer descriptor
+
+typedef struct RBD {
+ USHORT RbdStatus; // EOF, ACTCOUNT feild valid (F), ACTCOUNT
+ USHORT RbdNxtOfst; // offset of next RBD
+ USHORT RbdBuff; // rbd address
+ USHORT RbdBuffBase; // rbd address
+ USHORT RbdSize; // EL, size of the buffer
+} RBD, *PRBD;
+
+// frame descriptor
+
+typedef struct _FD {
+ USHORT FdStatus; // C, B, OK, S6-S11
+ USHORT FdCmd; // End of List (EL), Suspend (S)
+ USHORT FdNxtOfst; // offset of next FD
+ USHORT FdRbdOfst; // offset of the RBD
+ NETADDR FdDest; // destination address
+ NETADDR FdSrc; // source address
+ USHORT FdLength; // length of the received frame
+} FD, *PFD;
+
+// dump buffer definition
+
+typedef struct DUMPBUF {
+USHORT
+ Dmpfifobyte, // same as in conf. cmd, except for
+ Dmpaddmode, // bit 6 of fifobyte
+ Dmppridata,
+ Dmpslot,
+ Dmphware,
+ Dmpminlen,
+ Dmpiar10, // Individual address bytes
+ Dmpiar32,
+ Dmpiar54,
+ Dmplaststat, // status word of last cmd
+ Dmptxcr10, // xmit CRC generator
+ Dmptxcr32,
+ Dmprxcr10, // rcv CRC generator
+ Dmprxcr32,
+ Dmptmp10, // Internal temporaries
+ Dmptmp32,
+ Dmptmp54,
+ Dmprsr, // receive status register
+ Dmphash10, // Hash table
+ Dmphash32,
+ Dmphash54,
+ Dmphash76,
+ Dmplasttdr, // Status of last TDR command
+ Dmpfill [8], // Mostly 0 (!)
+ Dmpaddrlen,
+ Dmpnrbsz, // Size of next receive buffer
+ Dmpnrbhi, // High byte of next RB address
+ Dmpnrblo, // Lo byte of " " "
+ Dmpcrbsz, // # of bytes in last buff used
+ Dmplarbd, // Look ahead buff. des. (N+2)
+ Dmpnrbd, // Next RBD address
+ Dmpcrbd, // Current (last filled) rbd
+ Dmpcrbebc, // current rb empty byte count
+ Dmpnfdaddr, // next + 1 free frame descriptor
+ Dmpcfdaddr, // next free frame descriptor
+ Dmptmp,
+ Dmpntbcnt, // last tb cnt of completed cmd
+ Dmpdbufaddr, // Address of buffer in dump cmd
+ Dmpntbaddr, // Next Xmit buff address
+ Dmpltbdaddr, // next xmit buff descriptor
+ Dmpntbdaddr, // current xmit buff descriptor
+ Dmptmp1,
+ Dmpncbaddr, // next command block address
+ Dmpccbaddr, // current cmd blk address
+ Dmptmp2,
+ Dmpscbaddr, // Address of SCB
+ Dmpfill2 [6],
+ Dmpfifolim,
+ Dmpfill3 [3],
+ Dmprusreq,
+ Dmpcusreq,
+ Dmprus,
+ Dmpfill4 [6],
+ Dmpbuffhi, // High address of dump buffer
+ Dmpbufflo, // Lo address of dump buffer
+ Dmpdmabc, // Receive dma byte count
+ Dmpbrbuff, // Base + buffer
+ Dmprdmahi, // receive dma address
+ Dmprdmalo, // " " "
+ Dmpfill5 [7];
+} DUMPBUF, *PDUMPBUF;
+
+
+
+// BOARD SPECIFIC #DEFINES
+
+#define OFFSETNORMMODE 0x3000 // 0=esi loopback, 1 normal data xfer
+#define OFFSETCHANATT 0x3002 // 0=clear 586 channel attention, 1 = set
+#define OFFSETRESET 0x3004 // 0=clear 586 h/w reset, 1=set
+#define OFFSETINTENAB 0x3006 // 0=disable board interrupts 1=enable
+#define OFFSET16BXFER 0x3008 // 0=8bit xfer, 1=16bit xfer (for at)
+#define OFFSETSYSTYPE 0x300a // 0=pc or pc/xt, 1=at
+#define OFFSETINTSTAT 0x300c // 0=board's interrupt active, 1=inactive
+#define OFFSETADDRPROM 0x2000 // first byte of on-board ethernet id
+
+#define EXTENDEDADDRESS 0x20000 // used when board addr is above 1 meg
+#define OFFSETSCP 0x7ff6 // 586's scp points to the iscp
+#define OFFSETISCP 0x7fee // this points to the system control block
+#define OFFSETSCB 0x7fde // points to rcv frame and command unit areas
+#define OFFSETRU 0x4000 // the RAM for frame descriptors, receive
+ // buffer descriptors & rcv buffers is fixed at
+ // 0x4000 to 0x7800 on the half-card
+#define OFFSETRBD 0x4228 // rbd+rbuf must start on 32 bit boundry
+#define OFFSETCU 0x7814 // RAM offset for CBLs, TBDs, etc
+ // xmt area is from 0x7814 to 0x7f00
+ // from 0x7f01 to 0x7fff is scp, iscp, scb
+#define OFFSETTBD 0x7914 // allows 256 bytes for command block
+#define OFFSETTBUF 0x7924 // start of user data to send
+#define NFD 25 // 856 frame descriptor
+#define NRBD 25 // 586 rcv buffer descriptor
+
+#define RCVBUFSIZE 532 // 532 * 2 = max size used by tcp
+#define PC586_SIZE_OF_RECEIVE_BUFFERS 532 // 532 * 2 = max size used by tcp
+
+#define DLDEAD 0xffff // suppliments 82586.h datalink states
+
+#define CMD0 0 // used on 586 half-card command registers
+#define CMD1 0xffff // the mate of the above
+
+
+
+// all accesses to RAM on the pc586 board M*U*S*T be 16 bit accesses.
+// therefore the following struct is used to pack and unpack unsigned short
+
+typedef struct { union { UCHAR a[2];
+ USHORT b; } c; } PACKUSHORTT;
+
+
+typedef struct { union { UCHAR AChar[4];
+ ULONG ALong; } u; } PACKLONGT;
+
+
+
+//
+// Following def'ns are for PC586 set at IRQ = 5:
+// #define PC586_VECTOR 05
+// #define PC586_IRQL 30
+
+//
+// Following allow PC586 to run at whatever IRQL and memory you set below.
+// PC586 at IRQ 10 and memory at 0xC800 in current configuration.
+// (nt\public\spec\nt386\intmgr.txt for details of IRQL/IRQ/VECTOR assignments)
+//
+
+#define PC586_DEFAULT_INTERRUPT_VECTOR ((CCHAR)10)
+#define PC586_DEFAULT_INTERRUPT_IRQL ((CCHAR)25)
+#define PC586_DEFAULT_STATIC_RAM 0xC8000
+
+//
+//ZZZ Get from configuration file.
+//
+#define MAX_ADAPTERS ((UINT)4)
+#define PC586_LARGE_BUFFER_SIZE 1514
+
diff --git a/private/ntos/ndis/pc586e/pc586sft.h b/private/ntos/ndis/pc586e/pc586sft.h
new file mode 100644
index 000000000..0bc450df8
--- /dev/null
+++ b/private/ntos/ndis/pc586e/pc586sft.h
@@ -0,0 +1,889 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ pc586sft.h
+
+Abstract:
+
+ The main header for a PC586 (Local Area Network Controller
+ Intel pc586) MAC driver.
+
+Author:
+
+ Weldon Washburn (o-weldo) creation-date 10-29-90 adapted from...
+
+ Anthony V. Ercolano (tonye) creation-date 19-Jun-1990
+
+Environment:
+
+ This driver is expected to work in DOS, OS2 and NT at the equivalent
+ of kernal mode.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+
+--*/
+
+#ifndef _PC586SFT_
+#define _PC586SFT_
+
+#define PC586_NDIS_MAJOR_VERSION 3
+#define PC586_NDIS_MINOR_VERSION 0
+
+//
+// ZZZ These macros are peculiar to NT.
+//
+#define PC586_ALLOC_PHYS(s) ExAllocatePool(NonPagedPool,(s))
+#define PC586_FREE_PHYS(s) ExFreePool((s))
+#define PC586_MOVE_MEMORY(Destination,Source,Length) RtlMoveMemory(Destination,Source,Length)
+#define PC586_ZERO_MEMORY(Destination,Length) RtlZeroMemory(Destination,Length)
+
+// = 6 bytes src addr, 6 dest, 2 length and RCVBUFSIZE (Rbd->RbdSize) data
+#define LOOKAHEADBUFFERSIZE (RCVBUFSIZE + 6 + 6 + 2) / 2
+
+//
+// This record type is inserted into the MacReserved portion
+// of the packet header when the packet is going through the
+// staged allocation of buffer space prior to the actual send.
+//
+typedef struct _PC586_RESERVED {
+
+ //
+ // Points to the next packet in the chain of queued packets
+ // being allocated, loopbacked, or waiting for the finish
+ // of transmission.
+ //
+ // The packet will either be on the stage list for allocation,
+ // the loopback list for loopback processing, on an adapter
+ // wide doubly linked list (see below) for post transmission
+ // processing.
+ //
+ // We always keep the packet on a list so that in case the
+ // the adapter is closing down or resetting, all the packets
+ // can easily be located and "canceled".
+ //
+ PNDIS_PACKET Next;
+
+ //
+ // This field holds the binding handle of the open binding
+ // that submitted this packet for send.
+ //
+ NDIS_HANDLE MacBindingHandle;
+
+ //
+ // The particular request handle for the send of this packet.
+ //
+ NDIS_HANDLE RequestHandle;
+
+ //
+ // The following union elements are adjusted at each stage
+ // of the allocation. Each union element should only be accessed
+ // during it's own stage.
+ //
+
+ union _STAGE {
+ UINT ClearStage;
+ struct _STAGE1 {
+
+ //
+ // A value of zero indicates that the packet needs
+ // no adjustment.
+ //
+ // A value of 1 means it only requires a small packet.
+ //
+ // A value of 2 means it only requires a medium packet.
+ //
+ // A value of 3 means it must use a large packet.
+ //
+ UINT MinimumBufferRequirements:2;
+
+ //
+ // The number of ndis buffers to copy into the buffer.
+ //
+ UINT NdisBuffersToMove:14;
+
+ } STAGE1;
+ struct _STAGE2 {
+
+ //
+ // If TRUE then the packet caused an adapter buffer to
+ // be allocated.
+ //
+ UINT UsedPc586Buffer:1;
+
+ //
+ // If the previous field was TRUE then this gives the
+ // index into the array of adapter buffer descriptors that
+ // contains the old packet information.
+ //
+ UINT Pc586BuffersIndex:15;
+
+ //
+ // If UsedPc586Buffer is true then this field contains the
+ // number of *physical* ndis buffers contained in the adapter
+ // buffer.
+ //
+ UINT PhysicalBuffersContained:16;
+
+ } STAGE2;
+ struct _STAGE3 {
+
+ //
+ // If TRUE then the packet caused an adapter buffer to
+ // be allocated.
+ //
+ UINT UsedPc586Buffer:1;
+
+ //
+ // If the previous field was TRUE then this gives the
+ // index into the array of adapter buffer descriptors that
+ // contains the old packet information.
+ //
+ UINT Pc586BuffersIndex:15;
+
+ //
+ // Gives the index into the ring to packet structure as well
+ // as the ring descriptors.
+ //
+ UINT RingIndex:16;
+ } STAGE3;
+
+ //
+ // When the packet is submitted to the hardware and/or
+ // placed on the loopback queue these two fields of the
+ // union are used.
+ //
+ // It is always desired to keep the packet linked on
+ // one list.
+ //
+ // Here's how the fields are used.
+ //
+ // If the packet is just going on the hardware transmit
+ // or it is just going on the loopback then the ReadyToComplete
+ // flag will be set TRUE immediately. If it is just going on the
+ // loopback it also sets the status field in stage4 to successful.
+ //
+ // In the above situations, if the packet just went on the
+ // loopback queue, when the packet was finished with loopback
+ // the code would see that it was ready to complete. It would
+ // also know that it is in loopback processing. Since the packet
+ // can only be on one queue at a time it could simply remove
+ // the packet from the loopback queue and indicate the send
+ // as complete.
+ //
+ // If the packet not going on the loopback queue it would
+ // be placed on an adapter wide queue. It would use as a
+ // forward pointer the Next field. As a backward pointer it
+ // would overlay the stage 4 field with the backward pointer.
+ // Note that this is safe since no PNDIS_PACKET is ever odd
+ // byte aligned, and therefore the low bit would always be clear.
+ //
+ // We put the packet on a doubly linked list since we could
+ // never be quite sure of the order that we would remove packets
+ // from this list. (This will be clear shortly.)
+ //
+ // If the packet needs to be transmitted as well as loopbacked
+ // then the following occurs.
+ //
+ // The packets buffers are relinquished to the hardware. At the
+ // same time the packet is placed on the loopback queue. The
+ // stage4 field ReadyToComplete is set to false.
+ //
+ // If the packet finishes transmission and the ReadyToComplete
+ // flag is false that means it still hasn't finished loopback
+ // and therefore is still on the loopback list. The code
+ // simply sets ReadyToComplete to true and the status of the
+ // operation to true or false (depending on the result.)
+ // When that packet does finish loopback it notes that the
+ // ready to complete is true. It recovers that status from stage
+ // 4. It can then remove the packet from the loopback list and
+ // signal completion for that packet.
+ //
+ // If the packet finishes transmission and ReadyToComplete is true
+ // it simply removes it from the doubly linked adapter wide queue
+ // and signals its completion with the status that has been
+ // determined in the trasmission complete code.
+ //
+ // If the loopback code finishes processing the packet and it finds
+ // the ReadyToComplete TRUE it simply removes it from the loopback
+ // list and signals with the saved status in STAGE4.
+ //
+ // If the loopback code finishes processing the packet and it finds
+ // the ReadyToComplete FALSE it simply puts the packet on the adapter
+ // wide doubly linked list with ReadyToComplete set to TRUE.
+ //
+ // The main reason this is a doubly linked list is that there is no
+ // real way to predict when a packet will finish loopback and no
+ // real way to predict whether a packet even will be loopbacked.
+ // With this lack of knowledge, and the fact that the above packets
+ // may end up on the same list, the packet at the front of that
+ // list may not be the first packet to complete first. With
+ // a doubly linked list it is much easier to pull a packet out of
+ // the middle of that list.
+ //
+
+ struct _STAGE4 {
+
+ //
+ // Under the protection of the transmit queue lock
+ // this value will be examined by both the loopback
+ // completion code and the hardware send completion
+ // code. If either of them find the value to be true
+ // they will send the transmit complete.
+ //
+ // Note that if the packet didn't have to be loopbacked
+ // or if the packet didn't need to go out on the wire
+ // the this value will be initialized to true. Otherwise
+ // this value will be set to false just before it is
+ // relinquished to the hardware and to the loopback queue.
+ //
+ UINT ReadyToComplete:1;
+
+ //
+ // When the hardware send is done this will record whether
+ // the send was successful or not. It is only used if
+ // ReadyToComplete is FALSE.
+ //
+ // By definition loopback can never fail.
+ //
+ UINT SuccessfulTransmit:1;
+
+ } STAGE4;
+
+ //
+ // Used as a back pointer in a doubly linked list if the
+ // packet needs to go on an adapter wide queue to finish
+ // processing.
+ //
+ PNDIS_PACKET BackPointer;
+
+ } STAGE;
+
+} PC586_RESERVED,*PPC586_RESERVED;
+
+//
+// This macro will return a pointer to the pc586 reserved portion
+// of a packet given a pointer to a packet.
+//
+#define PPC586_RESERVED_FROM_PACKET(Packet) \
+ ((PPC586_RESERVED)((PVOID)(&(Packet)->MacReserved)))
+
+typedef struct _PC586_ADAPTER {
+
+ //
+ // OS Dependant fields of the adapter.
+ //
+
+ //
+ // Holds the interrupt object for this adapter.
+ //
+ KINTERRUPT Interrupt;
+
+ //
+ // Normal processing DPC.
+ //
+ KDPC InterruptDPC;
+
+ //
+ // Non OS fields of the adapter.
+ //
+
+ //
+ // Zero terminated string that holds the name of the particular device
+ // adapter. This is set at initialization.
+ //
+ PSZ DeviceName;
+
+ //
+ // This boolean is used as a gate to ensure that only one thread
+ // of execution is actually processing interrupts or some other
+ // source of deferred processing.
+ //
+ BOOLEAN DoingProcessing;
+
+ //
+ // The network address from the hardware.
+ //
+ UCHAR NetworkAddress[MAC_LENGTH_OF_ADDRESS];
+
+ //
+ // Keeps a reference count on the current number of uses of
+ // this adapter block. Uses is defined to be the number of
+ // routines currently within the "external" interface.
+ //
+ UINT References;
+
+ //
+ // List head for all open bindings for this adapter.
+ //
+ LIST_ENTRY OpenBindings;
+
+ //
+ // List head for all opens that had outstanding references
+ // when an attempt was made to close them.
+ //
+ LIST_ENTRY CloseList;
+
+ //
+ // Spinlock to protect fields in this structure..
+ //
+ NDIS_SPIN_LOCK Lock;
+
+ //
+ // Handle given by NDIS when the MAC registered itself.
+ //
+ NDIS_HANDLE NdisMacHandle;
+
+ //
+ // Handle given by NDIS when the adapter was registered.
+ //
+ NDIS_HANDLE NdisAdapterHandle;
+
+ //
+ // Pointer to the filter database for the MAC.
+ //
+ PMAC_FILTER FilterDB;
+
+ //
+ // Pointer to the first packet on the loopback list.
+ //
+ // Can only be accessed when the adapter lock
+ // is held.
+ //
+ PNDIS_PACKET FirstLoopBack;
+
+ //
+ // Pointer to the last packet on the loopback list.
+ //
+ // Can only be accessed when the adapter lock
+ // is held.
+ //
+ PNDIS_PACKET LastLoopBack;
+
+ //
+ // Pointer to the first transmitting packet that is actually
+ // sending, or done with the living on the loopback queue.
+ //
+ // Can only be accessed when the adapter lock
+ // is held.
+ //
+ PNDIS_PACKET FirstFinishTransmit;
+
+ //
+ // Pointer to the last transmitting packet that is actually
+ // sending, or done with the living on the loopback queue.
+ //
+ // Can only be accessed when the adapter lock
+ // is held.
+ //
+ PNDIS_PACKET LastFinishTransmit;
+
+ //
+ // These fields let the send allocation code know that it's
+ // futile to even try to move a packet along to that stage.
+ //
+ // Stage2 and Stage3 Open would be set to false in StagedAllocation
+ // and set to true by the interrupt processing code.
+ //
+ // Stage4Open could be set to false by any number of routines
+ // if they wish to close down the sending of packets. It
+ // would be set to true to turn back sending of packets.
+ //
+ // All of the stages would be closed to close a binding
+ // or to reset the adapter.
+ //
+ // These variables can only be accessed when the adapter
+ // lock is held.
+ //
+ BOOLEAN Stage4Open;
+ BOOLEAN Stage3Open;
+ BOOLEAN Stage2Open;
+ BOOLEAN Stage1Open;
+
+ //
+ // These AlreadyProcessingStageX variables are set up to keep
+ // more than one thread from accessing a particular thread
+ // a one time.
+ //
+ // These variables can only be accessed when the adapter
+ // lock is held.
+ //
+ BOOLEAN AlreadyProcessingStage4;
+ BOOLEAN AlreadyProcessingStage3;
+ BOOLEAN AlreadyProcessingStage2;
+
+ //
+ // Pointers to the first and last packets at a particular stage
+ // of allocation. All packets in transmit are linked
+ // via there next field.
+ //
+ // Can only be accessed when the adapter lock
+ // is held.
+ //
+ PNDIS_PACKET FirstStage1Packet;
+ PNDIS_PACKET LastStage1Packet;
+
+ PNDIS_PACKET FirstStage2Packet;
+ PNDIS_PACKET LastStage2Packet;
+
+ PNDIS_PACKET FirstStage3Packet;
+ PNDIS_PACKET LastStage3Packet;
+
+ //
+ // Flag that when enabled lets routines know that a reset
+ // is in progress.
+ //
+ BOOLEAN ResetInProgress;
+
+ //
+ // Pointer to the binding that initiated the reset. This
+ // will be null if the reset is initiated by the MAC itself.
+ //
+ struct _PC586_OPEN *ResettingOpen;
+
+ //
+ // RequestHandle of the request that initiated the reset. This
+ // value is undefined if the reset is initiated by the MAC itself.
+ //
+ NDIS_HANDLE ResetRequestHandle;
+
+ //
+ // The type of the request that caused the adapter to reset.
+ //
+ NDIS_REQUEST_TYPE ResetRequestType;
+
+ USHORT LookaheadBufferNdis [LOOKAHEADBUFFERSIZE];
+
+ // The transmit packet that currently "owns" the 586 xmt cmd block
+
+ PNDIS_PACKET OwningPacket;
+
+
+//
+// 82586 specific part of PC586_ADAPTER
+//
+
+// pointers used in receiveing a packet
+
+ PFD BeginFd, EndFd;
+ PRBD BeginRbd, EndRbd;
+
+// pointers to 82586 control structures
+
+ PSCP Scp;
+ PISCP Iscp;
+ PSCB Scb;
+ PCMD Cb;
+ PTBD Tbd;
+ PUSHORT CommandBuffer;
+
+//
+// pc586 netcard specific part of PC586_ADAPTER
+//
+ PUSHORT CAAddr;
+ PUSHORT IntAddr;
+ PUCHAR StaticRam, CmdProm;
+
+} PC586_ADAPTER,*PPC586_ADAPTER;
+
+//
+// Given a MacBindingHandle this macro returns a pointer to the
+// PC586_ADAPTER.
+//
+#define PPC586_ADAPTER_FROM_BINDING_HANDLE(Handle) \
+ (((PPC586_OPEN)((PVOID)(Handle)))->OwningPc586)
+
+//
+// Given a MacContextHandle return the PPC586_ADAPTER
+// it represents.
+//
+#define PPC586_ADAPTER_FROM_CONTEXT_HANDLE(Handle) \
+ ((PPC586_ADAPTER)((PVOID)(Handle)))
+
+//
+// Given a pointer to a PC586_ADAPTER return the
+// proper MacContextHandle.
+//
+#define CONTEXT_HANDLE_FROM_PPC586_ADAPTER(Ptr) \
+ ((NDIS_HANDLE)((PVOID)(Ptr)))
+
+//
+// One of these structures is created on each MacOpenAdapter.
+//
+typedef struct _PC586_OPEN {
+
+ //
+ // Linking structure for all of the open bindings of a particular
+ // adapter.
+ //
+ LIST_ENTRY OpenList;
+
+ //
+ // The Adapter that requested this open binding.
+ //
+ PPC586_ADAPTER OwningPc586;
+
+ //
+ // Index of this adapter in the filter database.
+ //
+ UINT FilterIndex;
+
+ //
+ // Given by NDIS when the adapter was opened.
+ //
+ NDIS_HANDLE NdisBindingContext;
+
+ //
+ // Counter of all the different reasons that a open binding
+ // couldn't be closed. This would be incremented each time
+ // for:
+ //
+ // While a particular interface routine is accessing this open
+ //
+ // During an indication.
+ //
+ // When the open causes a reset.
+ //
+ // A packet currently being sent.
+ //
+ // (Basically the above two mean any time the open has left
+ // some processing around to be accomplished later.)
+ //
+ // This field should only be accessed when the adapter lock is held.
+ //
+ UINT References;
+
+ //
+ // A flag indicating that this binding is in the process of closing.
+ //
+ BOOLEAN BindingShuttingDown;
+
+ //
+ // Request handle of the close request for this binding.
+ //
+ NDIS_HANDLE CloseHandle;
+
+} PC586_OPEN,*PPC586_OPEN;
+
+//
+// This macro returns a pointer to a PPC586_OPEN given a MacBindingHandle.
+//
+#define PPC586_OPEN_FROM_BINDING_HANDLE(Handle) \
+ ((PPC586_OPEN)((PVOID)Handle))
+
+//
+// This macro returns a NDIS_HANDLE from a PPC586_OPEN
+//
+#define BINDING_HANDLE_FROM_PPC586_OPEN(Open) \
+ ((NDIS_HANDLE)((PVOID)Open))
+
+
+//
+// This macro will act a "epilogue" to every routine in the
+// *interface*. It will check whether there any requests needed
+// to defer there processing. It will also decrement the reference
+// count on the adapter. If the reference count is zero and there
+// is deferred work to do it will insert the interrupt processing
+// routine in the DPC queue.
+//
+// Note that we don't need to include checking for blocked receives
+// since blocked receives imply that there will eventually be an
+// interrupt.
+//
+// NOTE: This macro assumes that it is called with the lock acquired.
+//
+// ZZZ This routine is NT specific.
+//
+#define PC586_DO_DEFERRED(Adapter) \
+{ \
+ PPC586_ADAPTER _A = (Adapter); \
+ _A->References--; \
+ if ((!_A->References) && \
+ (_A->ResetInProgress || \
+ _A->FirstLoopBack || \
+ (!IsListEmpty(&_A->CloseList)))) { \
+ NdisReleaseSpinLock(&_A->Lock); \
+ KeInsertQueueDpc( \
+ &_A->InterruptDPC, \
+ NULL, \
+ NULL \
+ ); \
+ } else { \
+ NdisReleaseSpinLock(&_A->Lock); \
+ } \
+}
+
+//
+// This structure is passed as context from the receive interrupt
+// processor. Eventually it will be used as a parameter to
+// Pc586TransferData. Pc586TransferData can get two kinds of
+// context. It will receive either an ndis packet or it will
+// receive a PC586_RECEIVE_CONTEXT. It will be able to tell
+// the difference since the PC586_RECEIVE_CONTEXT will have
+// its low bit set. No pointer to an ndis packet can have its low
+// bit set.
+//
+typedef struct { union {
+
+ UINT WholeThing;
+ UINT FrameDescriptor; } a;
+
+} PC586_RECEIVE_CONTEXT,*PPC586_RECEIVE_CONTEXT;
+
+//
+// We define the external interfaces to the pc586 driver.
+// These routines are only external to permit separate
+// compilation. Given a truely fast compiler they could
+// all reside in a single file and be static.
+//
+
+extern
+NDIS_STATUS
+Pc586TransferData(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+extern
+NDIS_STATUS
+Pc586Send(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN PNDIS_PACKET Packet
+ );
+
+extern
+BOOLEAN
+Pc586StartAdapters(
+ IN NDIS_HANDLE NdisMacHandle
+ );
+
+extern
+VOID
+Pc586StagedAllocation(
+ IN PPC586_ADAPTER Adapter
+ );
+
+extern
+VOID
+Pc586CopyFromPacketToBuffer(
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ IN UINT BytesToCopy,
+ OUT PCHAR Buffer,
+ OUT PUINT BytesCopied
+ );
+
+extern
+VOID
+Pc586CopyFromPacketToPacket(
+ IN PNDIS_PACKET Destination,
+ IN UINT DestinationOffset,
+ IN UINT BytesToCopy,
+ IN PNDIS_PACKET Source,
+ IN UINT SourceOffset,
+ OUT PUINT BytesCopied
+ );
+
+extern
+VOID
+Pc586ProcessLoopback(
+ IN PPC586_ADAPTER Adapter
+ );
+
+extern
+VOID
+Pc586RemovePacketFromLoopBack(
+ IN PPC586_ADAPTER Adapter
+ );
+
+extern
+VOID
+Pc586PutPacketOnLoopBack(
+ IN PPC586_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet,
+ IN BOOLEAN ReadyToComplete
+ );
+
+extern
+VOID
+Pc586RemovePacketOnFinishTrans(
+ IN PPC586_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet
+ );
+
+extern
+VOID
+Pc586PutPacketOnFinishTrans(
+ IN PPC586_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet
+ );
+
+extern
+VOID
+Pc586HardwareDetails(
+ IN PPC586_ADAPTER Adapter,
+ IN PVOID Specific
+ );
+
+extern
+VOID
+Pc586StopChip(
+ IN PPC586_ADAPTER Adapter
+ );
+
+extern
+BOOLEAN
+Pc586RegisterAdapter(
+ IN NDIS_HANDLE NdisMacHandle,
+ IN PSZ DeviceName,
+ IN PVOID Pc586BaseHardwareMemoryAddress,
+ IN CCHAR Pc586InterruptVector,
+ IN KIRQL Pc586InterruptIrql,
+ IN UINT MaximumMulticastAddresses,
+ IN UINT MaximumOpenAdapters,
+ );
+
+#endif // _PC586SFT_
+
+
+static
+VOID
+ReQFd(
+ IN PPC586_ADAPTER Adapter,
+ IN PFD Fd
+ );
+
+
+static
+VOID
+RuStart(
+ IN PPC586_ADAPTER Adapter
+ );
+
+
+static
+VOID
+ShuvWord(
+ IN PUSHORT VirtAddr,
+ IN USHORT Value
+ );
+
+static
+USHORT
+PullWord(
+ IN PUSHORT VirtAddr
+ );
+
+static
+VOID
+BuildCu(
+ IN PPC586_ADAPTER Adapter
+ );
+
+static
+VOID
+BuildRu(
+ IN PPC586_ADAPTER Adapter
+ );
+
+static
+BOOLEAN
+Diagnose586(
+ IN PPC586_ADAPTER Adapter
+ );
+
+static
+BOOLEAN
+Config586(
+ IN PPC586_ADAPTER Adapter
+ );
+
+
+static
+USHORT
+PromAddr(
+ IN PPC586_ADAPTER Adapter,
+ IN ULONG Index
+ );
+
+static
+VOID
+ChanAttn(
+ IN PPC586_ADAPTER Adapter
+ );
+
+static
+VOID
+WaitScb(
+ IN PPC586_ADAPTER Adapter
+ );
+
+static
+USHORT
+VirtToPc586(
+ IN PPC586_ADAPTER Adapter,
+ IN PUCHAR KernelVirtAddr
+ );
+
+static
+PUCHAR
+Pc586ToVirt(
+ IN PPC586_ADAPTER Adapter,
+ IN USHORT Addr586
+ );
+
+static
+VOID
+PutPacket(
+ IN PPC586_ADAPTER Adapter,
+ IN PFD Fd,
+ IN UINT PacketLength
+ );
+
+static
+VOID
+Pc586IntOn(
+ IN PPC586_ADAPTER Adapter
+);
+
+static
+VOID
+Pc586IntOff(
+ IN PPC586_ADAPTER Adapter
+ );
+
+static
+Pc586TimeOut(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PLONG TimerCounter
+ );
+
+static
+VOID
+Pc586MoveToHost(
+ IN PVOID DestinationVirtualAddress,
+ IN PVOID SourceVirtualAddress,
+ IN UINT AmountToMove
+ );
+
+
+static
+VOID
+Pc586MoveToAdapter(
+ IN PVOID DestinationVirtualAddress,
+ IN PVOID SourceVirtualAddress,
+ IN UINT AmountToMove
+ );
diff --git a/private/ntos/ndis/pc586e/pc586snd.c b/private/ntos/ndis/pc586e/pc586snd.c
new file mode 100644
index 000000000..f8fb2f002
--- /dev/null
+++ b/private/ntos/ndis/pc586e/pc586snd.c
@@ -0,0 +1,1300 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ pc586snd.c
+
+Abstract:
+
+ This file contains the code for putting a packet through the
+ staged allocation for transmission.
+
+ This is a process of
+
+ 1) Calculating the what would need to be done to the
+ packet so that the packet can be transmitted on the hardware.
+
+ 2) Potentially allocating adapter buffers and copying user data
+ to those buffers so that the packet data is transmitted under
+ the hardware constraints.
+
+ 3) Allocating enough hardware ring entries so that the packet
+ can be transmitted.
+
+ 4) Relinquish thos ring entries to the hardware.
+
+ NOTE: ZZZ There is a potential priority inversion problem when
+ allocating the packet. For nt it looks like we need to raise
+ the irql to dpc when we start the allocation.
+
+Author:
+
+ Anthony V. Ercolano (Tonye) 12-Sept-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+
+--*/
+
+#include <ntos.h>
+#include <ndis.h>
+#include <filter.h>
+#include <pc586hrd.h>
+#include <pc586sft.h>
+
+
+
+
+//
+// ZZZ This macro implementation is peculiar to NT. It will poke the
+// pc586 hardware into noticing that there is a packet available
+// for transmit.
+//
+// Note that there is the assumption that the register address
+// port (RAP) is already set to zero.
+//
+#define PROD_TRANSMIT(A) \
+ PC586_WRITE_RDP( \
+ A->RDP, \
+ PC586_CSR0_TRANSMIT_DEMAND | PC586_CSR0_INTERRUPT_ENABLE \
+ );
+
+
+static
+BOOLEAN
+PacketShouldBeSent(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_PACKET Packet
+ );
+
+static
+VOID
+SetupAllocate(
+ IN PPC586_ADAPTER Adapter,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN PNDIS_PACKET Packet
+ );
+
+static
+VOID
+StagedAllocation(
+ IN PPC586_ADAPTER Adapter
+ );
+
+static
+BOOLEAN
+AcquireTransmitRingEntries(
+ IN PPC586_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet,
+ OUT PUINT RingIndex
+ );
+
+static
+VOID
+AssignPacketToRings(
+ IN PPC586_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet,
+ IN UINT RingIndex
+ );
+
+static
+VOID
+MovePacketToStage2(
+ IN PPC586_ADAPTER Adapter
+ );
+
+static
+VOID
+MovePacketToStage3(
+ IN PPC586_ADAPTER Adapter
+ );
+
+static
+VOID
+RemovePacketFromStage3(
+ IN PPC586_ADAPTER Adapter
+ );
+
+static
+VOID
+RelinquishPacket(
+ IN PPC586_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet,
+ );
+
+static
+VOID
+CalculatePacketConstraints(
+ IN PPC586_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet
+ );
+
+static
+BOOLEAN
+ConstrainPacket(
+ IN PPC586_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet
+ );
+
+
+extern
+NDIS_STATUS
+Pc586Send(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN PNDIS_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ The Pc586Send request instructs a MAC to transmit a packet through
+ the adapter onto the medium.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to PC586_OPEN.
+
+ RequestHandle - A value supplied by the NDIS interface that the MAC
+ must use when completing this request with the NdisCompleteRequest
+ service, if the MAC completes this request asynchronously.
+
+ Packet - A pointer to a descriptor for the packet that is to be
+ transmitted.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+
+{
+
+ //
+ // Holds the status that should be returned to the caller.
+ //
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_PENDING;
+
+ //
+ // Pointer to the adapter.
+ //
+ PPC586_ADAPTER Adapter;
+
+ Adapter = PPC586_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ if (!Adapter->ResetInProgress) {
+
+ PPC586_OPEN Open;
+
+ Open = PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ if (!Open->BindingShuttingDown) {
+
+ UINT TotalPacketSize;
+
+ //
+ // Increment the references on the open while we are
+ // accessing it in the interface.
+ //
+
+ Open->References++;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ //
+ // It is reasonable to do a quick check and fail if the packet
+ // is larger than the maximum an ethernet can handle.
+ //
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ NULL,
+ NULL,
+ &TotalPacketSize
+ );
+
+ if ((!TotalPacketSize) ||
+ (TotalPacketSize > PC586_LARGE_BUFFER_SIZE)) {
+
+ StatusToReturn = NDIS_INSUFFICIENT_RESOURCES;
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ } else {
+
+ //
+ // NOTE NOTE NOTE !!!!!!
+ //
+ // There is an assumption in the code that no pointer
+ // (which are really handles) to an ndis packet will have
+ // its low bit set. (Always have even byte alignment.)
+ //
+
+ ASSERT(!((UINT)Packet & 1));
+
+ //
+ // Check to see if the packet should even make it out to
+ // the media. The primary reason this shouldn't *actually*
+ // be sent is if the destination is equal to the source
+ // address.
+ //
+ // If it doesn't need to be placed on the wire then we can
+ // simply put it onto the loopback queue.
+ //
+
+ if (PacketShouldBeSent(
+ MacBindingHandle,
+ Packet
+ )) {
+
+ //
+ // The packet needs to be placed out on the wire.
+ //
+
+ SetupAllocate(
+ Adapter,
+ MacBindingHandle,
+ RequestHandle,
+ Packet
+ );
+
+ //
+ // Only try to push it through the stage queues
+ // if somebody else isn't already doing it and
+ // there is some hope of moving some packets
+ // ahead.
+ //
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ while ((!(Adapter->AlreadyProcessingStage4 ||
+ Adapter->AlreadyProcessingStage3 ||
+ Adapter->AlreadyProcessingStage2)
+ ) &&
+ ((Adapter->FirstStage3Packet &&
+ Adapter->Stage4Open) ||
+ (Adapter->FirstStage2Packet &&
+ Adapter->Stage3Open) ||
+ (Adapter->FirstStage1Packet &&
+ Adapter->Stage2Open)
+ )
+ ) {
+
+ Pc586StagedAllocation(Adapter);
+
+ }
+
+ } else {
+
+ PPC586_RESERVED Reserved;
+
+ Reserved = PPC586_RESERVED_FROM_PACKET(Packet);
+ Reserved->MacBindingHandle = MacBindingHandle;
+ Reserved->RequestHandle = RequestHandle;
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ Pc586PutPacketOnLoopBack(
+ Adapter,
+ Packet,
+ TRUE
+ );
+
+ }
+
+ }
+
+ //
+ // The interface is no longer referencing the open.
+ //
+
+ Open->References--;
+
+ } else {
+
+ StatusToReturn = NDIS_CLOSING;
+
+ }
+
+ } else {
+
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ }
+
+ PC586_DO_DEFERRED(Adapter);
+ return StatusToReturn;
+}
+
+static
+BOOLEAN
+PacketShouldBeSent(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ Determines whether the packet should go out on the wire at all.
+ The way it does this is to see if the destination address is
+ equal to the source address.
+
+Arguments:
+
+ MacBindingHandle - Is a pointer to the open binding.
+
+ Packet - Packet whose source and destination addresses are tested.
+
+Return Value:
+
+ Returns FALSE if the source is equal to the destination.
+
+
+--*/
+
+{
+
+ //
+ // Holds the source address from the packet.
+ //
+ CHAR Source[MAC_LENGTH_OF_ADDRESS];
+
+ //
+ // Holds the destination address from the packet.
+ //
+ CHAR Destination[MAC_LENGTH_OF_ADDRESS];
+
+ //
+ // variable to hold the length of the source address.
+ //
+ UINT AddressLength;
+
+ //
+ // Will hold the result of the comparasion of the two MAC_NETWORD_ADDRESSes.
+ //
+ INT Result;
+
+ Pc586CopyFromPacketToBuffer(
+ Packet,
+ 0,
+ MAC_LENGTH_OF_ADDRESS,
+ Destination,
+ &AddressLength
+ );
+ ASSERT(AddressLength == MAC_LENGTH_OF_ADDRESS);
+
+
+ Pc586CopyFromPacketToBuffer(
+ Packet,
+ MAC_LENGTH_OF_ADDRESS,
+ MAC_LENGTH_OF_ADDRESS,
+ Source,
+ &AddressLength
+ );
+ ASSERT(AddressLength == MAC_LENGTH_OF_ADDRESS);
+
+ MAC_COMPARE_NETWORK_ADDRESSES(
+ Source,
+ Destination,
+ &Result
+ );
+
+ //
+ // If the result is 0 then the two addresses are equal and the
+ // packet shouldn't go out on the wire.
+ //
+
+ return ((!Result)?(FALSE):(TRUE));
+
+}
+
+static
+VOID
+SetupAllocate(
+ IN PPC586_ADAPTER Adapter,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN PNDIS_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This sets up the MAC reserved portion of the packet so that
+ later allocation routines can determine what is left to be
+ done in the allocation cycle.
+
+Arguments:
+
+ Adapter - The adapter that this packet is coming through.
+
+ MacBindingHandle - Points to the open binding structure.
+
+ RequestHandle - Protocol supplied value. It is saved so that when
+ the send finnaly completes it can be used to indicate to the protocol.
+
+ Packet - The packet that is to be transmitted.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Points to the MAC reserved portion of this packet. This
+ // interpretation of the reserved section is only valid during
+ // the allocation phase of the packet.
+ //
+ PPC586_RESERVED Reserved = PPC586_RESERVED_FROM_PACKET(Packet);
+
+
+ ASSERT(sizeof(PC586_RESERVED) <=
+ sizeof(Packet->MacReserved));
+
+ Reserved->STAGE.ClearStage = 0;
+ Reserved->MacBindingHandle = MacBindingHandle;
+ Reserved->RequestHandle = RequestHandle;
+
+ //
+ // Determine if and how much adapter space would need to be allocated
+ // to meet hardware constraints.
+ //
+
+ CalculatePacketConstraints(
+ Adapter,
+ Packet
+ );
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ //
+ // Put on the stage 1 queue.
+ //
+
+ if (!Adapter->LastStage1Packet) {
+
+ Adapter->FirstStage1Packet = Packet;
+
+ } else {
+
+ PPC586_RESERVED_FROM_PACKET(Adapter->LastStage1Packet)->Next = Packet;
+
+ }
+
+ Adapter->LastStage1Packet = Packet;
+
+ Reserved->Next = NULL;
+
+ //
+ // Increment the reference on the open since it
+ // will be leaving this packet around on the transmit
+ // queues.
+ //
+
+ PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle)->References++;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+}
+
+extern
+VOID
+Pc586StagedAllocation(
+ IN PPC586_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine attempts to take a packet through a stage of allocation.
+
+Arguments:
+
+ Adapter - The adapter that the packets are coming through.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // For each stage, we check to see that it is open,
+ // that somebody else isn't already processing,
+ // and that there is some work from the previous
+ // stage to do.
+ //
+
+ if (Adapter->Stage2Open &&
+ !Adapter->AlreadyProcessingStage2 &&
+ Adapter->FirstStage1Packet) {
+
+ //
+ // Holds whether the packet has been constrained
+ // to the hardware requirements.
+ //
+ BOOLEAN SuitableForHardware;
+
+ PNDIS_PACKET FirstPacket = Adapter->FirstStage1Packet;
+
+ Adapter->AlreadyProcessingStage2 = TRUE;
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ SuitableForHardware = ConstrainPacket(
+ Adapter,
+ FirstPacket
+ );
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ if (SuitableForHardware) {
+
+ MovePacketToStage2(Adapter);
+ Adapter->Stage2Open = FALSE;
+ }
+
+ Adapter->AlreadyProcessingStage2 = FALSE;
+
+ }
+ if (Adapter->Stage3Open &&
+ !Adapter->AlreadyProcessingStage3 &&
+ Adapter->FirstStage2Packet) {
+
+
+
+
+
+
+
+ PNDIS_PACKET FirstPacket = Adapter->FirstStage2Packet;
+
+ Adapter->AlreadyProcessingStage3 = TRUE;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ //
+ // We look to see if there are enough ring entries.
+ // If there aren't then stage 3 will close.
+ //
+ // AcquireTransmitRingEntries will hold a spin lock
+ // for a short time.
+ //
+
+// the Acquire/Assign procs below may be used later for 586 command chaining
+
+// if (AcquireTransmitRingEntries(
+// Adapter,
+// FirstPacket,
+// &RingIndex
+// )) {
+
+ //
+ // We have the number of buffers that we need.
+ // We assign all of the buffers to the ring entries.
+ //
+
+// AssignPacketToRings(
+// Adapter,
+// FirstPacket,
+// RingIndex
+// );
+
+ //
+ // We need exclusive access to the tranmit ring so
+ // that we can move this packet on to the next stage.
+ //
+
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ MovePacketToStage3(Adapter);
+
+
+// } else {
+//
+// Adapter->Stage3Open = FALSE;
+//
+// }
+
+ Adapter->AlreadyProcessingStage3 = FALSE;
+
+ }
+ if (Adapter->Stage4Open &&
+ !Adapter->AlreadyProcessingStage4 &&
+ Adapter->FirstStage3Packet) {
+
+ //
+ // Holds a pointer to packet at the head of the
+ // stage 3.
+ //
+ PNDIS_PACKET Packet = Adapter->FirstStage3Packet;
+
+ //
+ // We have a packet to work with.
+ //
+ // Take the packet off of the transmit work queue.
+ //
+
+ RemovePacketFromStage3(Adapter);
+
+ Adapter->AlreadyProcessingStage4 = TRUE;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ RelinquishPacket(
+ Adapter,
+ Packet
+ );
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ Adapter->AlreadyProcessingStage4 = FALSE;
+
+ }
+
+}
+
+static
+BOOLEAN
+ConstrainPacket(
+ IN PPC586_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ Given a packet and if necessary attempt to acquire adapter
+ buffer resources so that the packet meets pc586 hardware
+ contraints.
+
+Arguments:
+
+ Adapter - The adapter the packet is coming through.
+
+ Packet - The packet whose buffers are to be constrained.
+ The packet reserved section is filled with information
+ detailing how the packet needs to be adjusted.
+
+Return Value:
+
+ Returns TRUE if the packet is suitable for the hardware.
+
+--*/
+
+{
+
+ //
+ // Pointer to the reserved section of the packet to be contrained.
+ //
+ PPC586_RESERVED Reserved = PPC586_RESERVED_FROM_PACKET(Packet);
+
+
+ if (Reserved->STAGE.STAGE1.MinimumBufferRequirements) {
+
+ //
+ // Will point into the virtual address space addressed
+ // by the adapter buffer if one was successfully allocated.
+ //
+ PCHAR CurrentDestination;
+
+ //
+ // used to clear padding bytes in short packets
+ //
+ PUSHORT Clearing;
+
+ //
+ // Will hold the total amount of data copied to the
+ // adapter buffer.
+ //
+ UINT TotalDataMoved = 0;
+
+
+ //
+ // Will point to the current source buffer.
+ //
+ PNDIS_BUFFER SourceBuffer;
+
+ //
+ // Points to the virtual address of the source buffers data.
+ //
+ PUCHAR SourceData;
+
+ //
+ // Will point to the number of bytes of data in the source
+ // buffer.
+ //
+ UINT SourceLength;
+
+ //
+ // Simple iteration variable.
+ //
+ INT i;
+
+ //
+ // the number of ndis buffers in an ndis packet
+ //
+ UINT BufferCount;
+
+ // the 586 can only be touched on 16-bit boundries
+
+ PUSHORT ShortAddr1, ShortAddr2;
+
+ WaitScb(Adapter);
+
+ if ( (Adapter->Cb->CmdStatus & CSBUSY) ||
+ !(Adapter->Cb->CmdStatus & CSCMPLT) ) return FALSE;
+
+ //
+ // Fill in the adapter buffer with the data from the users
+ // buffers.
+ //
+ // FIRST FILL IN THE 586 COMMAND BLOCK
+
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ &BufferCount,
+ &SourceBuffer,
+ NULL
+ );
+
+ NdisQueryBuffer(
+ SourceBuffer,
+ NULL,
+ &(PVOID)SourceData,
+ &SourceLength
+ );
+
+ if (SourceLength < 14) {
+ DbgPrint("pc586 ConstrainPacket(): can't handle fragmented xmt buffers\n");
+ SourceLength = 14; // ???
+ }
+ Adapter->Cb->CmdStatus = 0;
+ Adapter->Cb->CmdCmd = CSEL | CSCMDXMIT | CSINT;
+ Adapter->Cb->CmdNxtOfst = OFFSETCU; // only one Cb, points to self
+
+ Adapter->Cb->PRMTR.PrmXmit.XmtTbdOfst = OFFSETTBD;
+
+ ShortAddr2 = (PUSHORT)(Adapter->Cb->PRMTR.PrmXmit.XmtDest);
+ ShortAddr1 = (PUSHORT)SourceData;
+
+ *ShortAddr2++ = *ShortAddr1++;
+ *ShortAddr2++ = *ShortAddr1++;
+ *ShortAddr2++ = *ShortAddr1++;
+
+ SourceData+=12; // skip over dest and source addresses
+ SourceLength-=12;
+
+ ShortAddr1 = (PUSHORT)SourceData;
+
+ Adapter->Cb->PRMTR.PrmXmit.XmtLength = *ShortAddr1;
+
+ SourceData+=2; // skip over length field
+ SourceLength-=2;
+
+ // SECOND FILL IN XMT BUFFER DESCRIPTOR
+
+ Adapter->Tbd->TbdNxtOfst = 0xffff;
+ Adapter->Tbd->TbdBuff = OFFSETTBUF;
+ Adapter->Tbd->TbdBuffBase = 0;
+
+
+ // THIRD FILL IN XMT DATA
+
+
+ // 64 is minimum packet length, incl 6 source, 6 dest addr, 2 len
+ if (SourceLength < 64 - 14) {
+ Clearing = (PUSHORT)(Adapter->CommandBuffer);
+ for (i = 0; i <= 64 - 14; i +=2)
+ *Clearing++ = 0;
+ }
+
+ CurrentDestination = (PCHAR)(Adapter->CommandBuffer);
+
+ for (
+ i = Reserved->STAGE.STAGE1.NdisBuffersToMove;
+ i;
+ i--
+ ) {
+
+
+ Pc586MoveToAdapter(
+ (PVOID)CurrentDestination,
+ (PVOID)SourceData,
+ SourceLength
+ );
+
+ CurrentDestination = (PCHAR)(CurrentDestination + SourceLength);
+
+ TotalDataMoved += SourceLength;
+
+ if (i > 1) {
+
+ NdisGetNextBuffer(
+ SourceBuffer,
+ &SourceBuffer
+ );
+
+ if (SourceBuffer == NULL) {
+ DbgPrint("PC586 ConstrainPacket(): NULL NDIS BUFFER\n");
+ break;
+ }
+
+ NdisQueryBuffer(
+ SourceBuffer,
+ NULL,
+ &(PVOID)SourceData,
+ &SourceLength
+ );
+
+ }
+
+ }
+ if (TotalDataMoved < 64 - 14 ) TotalDataMoved = 64 - 14; //required by 802.3
+ Adapter->Tbd->TbdCount = (USHORT)TotalDataMoved | (USHORT)CSEOF;
+
+ // Reserved->STAGE.STAGE2.UsedPc586Buffer = TRUE; might be used later
+ Reserved->STAGE.ClearStage = 0;
+ Adapter->OwningPacket = Packet;
+
+ }
+
+ return TRUE;
+}
+
+static
+VOID
+CalculatePacketConstraints(
+ IN PPC586_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ Given a packet calculate how the packet will have to be
+ adjusted to meet with hardware constraints.
+
+Arguments:
+
+ Adapter - The adapter the packet is coming through.
+
+ Packet - The packet whose buffers are to be reallocated.
+ The packet reserved section is filled with information
+ detailing how the packet needs to be adjusted.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // ZZZ This is not a portable routine. The MDLs that make
+ // up the physical address are not available on OS/2 and
+ // DOS.
+ //
+
+
+ //
+ // A basic principle here is that the reallocation of some or
+ // all of the user buffers to adapter buffers will only allocate
+ // a single adapter buffer.
+ //
+
+ //
+ // Points to the reserved portion of the packet.
+ //
+ PPC586_RESERVED Reserved = PPC586_RESERVED_FROM_PACKET(Packet);
+
+ //
+ // The number of ndis buffers in the packet.
+ //
+ UINT NdisBufferCount;
+
+ //
+ // The number of physical buffers in the entire packet.
+ //
+ UINT PhysicalBufferCount;
+
+ //
+ // Points to the current ndis buffer being walked.
+ //
+ PNDIS_BUFFER CurrentBuffer;
+
+ //
+ // Points to the mdl for the current ndis buffer.
+ //
+ NDIS_PHYSICAL_ADDRESS PointerToMdl;
+
+ //
+ // The virtual address of the current ndis buffer.
+ //
+ PVOID VirtualAddress;
+
+ //
+ // The length in bytes of the current ndis buffer.
+ //
+ UINT CurrentVirtualLength;
+
+ //
+ // The total amount of data contained within the ndis packet.
+ //
+ UINT TotalVirtualLength;
+
+ //
+ // Pointer into an array of physical pages numbers for the mdl.
+ //
+ PULONG PhysicalAddressElement;
+
+ //
+ // An actual physical address.
+ //
+ PHYSICAL_ADDRESS PhysicalAddress;
+
+ //
+ // The amount of memory used in the current physical
+ // page for the buffer.
+ //
+ UINT LengthOfPhysicalBuffer;
+
+ //
+ // Holds the number of Ndis buffers that we have queried.
+ //
+ UINT NdisBuffersExamined;
+
+ //
+ // The total amount of virtual memory in bytes contained in all of the
+ // ndis buffers examined.
+ //
+ UINT VirtualMemoryPassed;
+
+
+ //
+ // Get the first buffer.
+ //
+
+ NdisQueryPacket(
+ Packet,
+ &PhysicalBufferCount,
+ &NdisBufferCount,
+ &CurrentBuffer,
+ &TotalVirtualLength
+ );
+
+ NdisQueryBuffer(
+ CurrentBuffer,
+ &PointerToMdl,
+ &VirtualAddress,
+ &CurrentVirtualLength
+ );
+
+//
+// Certain hardware implementation (Decstation) use a dual ported
+// memory to communicate with the hardware. This is reasonable since
+// it reduces bus contention. When using the dual ported memory, all
+// send data must be moved to buffers allocated from the dual ported
+// memory.
+//
+// #ifdef PC586_USE_HARDWARE_MEMORY
+
+ VirtualMemoryPassed = TotalVirtualLength;
+ NdisBuffersExamined = NdisBufferCount;
+
+// #else // PC586_USE_HARDWARE_MEMORY
+
+//
+// In the interests of keeping silo underflow from occuring
+// we might want to disable data chaining. In this case the
+// only time we don't copy to the adapters buffers is if there
+// is only one physical buffer in the packet and it is greater
+// than the minimum single buffer length.
+
+// #endif // PC586_USE_HARDDWARE_MEMORY
+
+ Reserved->STAGE.STAGE1.MinimumBufferRequirements = 3;
+
+ Reserved->STAGE.STAGE1.NdisBuffersToMove = NdisBuffersExamined;
+
+}
+
+
+static
+VOID
+MovePacketToStage2(
+ IN PPC586_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Move a packet from the stage 1 allocation to stage 2 allocation.
+
+Arguments:
+
+ Adapter - The adapter that the packets are coming through.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNDIS_PACKET PacketToMove = Adapter->FirstStage1Packet;
+
+ //
+ // First remove it from the stage 1 queue;
+ //
+
+ Adapter->FirstStage1Packet =
+ PPC586_RESERVED_FROM_PACKET(PacketToMove)->Next;
+
+ if (!Adapter->FirstStage1Packet) {
+
+ Adapter->LastStage1Packet = NULL;
+
+ }
+
+ //
+ // Now put it on the stage 2 queue.
+ //
+
+ if (!Adapter->FirstStage2Packet) {
+
+ Adapter->FirstStage2Packet = PacketToMove;
+
+ } else {
+
+ PPC586_RESERVED_FROM_PACKET(Adapter->LastStage2Packet)->Next =
+ PacketToMove;
+
+
+ }
+
+ Adapter->LastStage2Packet = PacketToMove;
+ PPC586_RESERVED_FROM_PACKET(PacketToMove)->Next = NULL;
+}
+
+static
+VOID
+MovePacketToStage3(
+ IN PPC586_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Move a packet from the stage 2 allocation to stage 3 allocation.
+
+Arguments:
+
+ Adapter - The adapter that the packets are coming through.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNDIS_PACKET PacketToMove = Adapter->FirstStage2Packet;
+
+ //
+ // First remove it from the stage 2 queue.
+ //
+
+ Adapter->FirstStage2Packet =
+ PPC586_RESERVED_FROM_PACKET(PacketToMove)->Next;
+
+ if (!Adapter->FirstStage2Packet) {
+
+ Adapter->LastStage2Packet = NULL;
+
+ }
+
+ //
+ // Now put it on the stage 3 queue.
+ //
+
+ if (!Adapter->FirstStage3Packet) {
+
+ Adapter->FirstStage3Packet = PacketToMove;
+
+ } else {
+
+ PPC586_RESERVED_FROM_PACKET(Adapter->LastStage3Packet)->Next =
+ PacketToMove;
+
+
+ }
+
+ Adapter->LastStage3Packet = PacketToMove;
+ PPC586_RESERVED_FROM_PACKET(PacketToMove)->Next = NULL;
+
+}
+
+static
+VOID
+RemovePacketFromStage3(
+ IN PPC586_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Removes a the packet from the from of the stage 3 allocation
+ list.
+
+Arguments:
+
+ Adapter - The adapter that the packets are coming through.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNDIS_PACKET PacketToRemove = Adapter->FirstStage3Packet;
+
+ //
+ // Holds the destination address of the packet.
+ //
+ CHAR Address[MAC_LENGTH_OF_ADDRESS];
+
+ //
+ // Holds the length of data we got from getting the
+ // address from the packet.
+ //
+ UINT AddressLength;
+
+
+ //
+ // First remove it from stage 3.
+ //
+
+ Adapter->FirstStage3Packet =
+ PPC586_RESERVED_FROM_PACKET(PacketToRemove)->Next;
+
+ if (!Adapter->FirstStage3Packet) {
+
+ Adapter->LastStage3Packet = NULL;
+
+ }
+
+ //
+ // Do a quick check to see if the packet has a high likelyhood
+ // of needing to loopback. (NOTE: This means that if the packet
+ // must be loopbacked then this function will return true. If
+ // the packet doesn't need to be loopbacked then the function
+ // will probably return false.)
+ //
+
+ Pc586CopyFromPacketToBuffer(
+ PacketToRemove,
+ 0,
+ MAC_LENGTH_OF_ADDRESS,
+ Address,
+ &AddressLength
+ );
+ ASSERT(AddressLength == MAC_LENGTH_OF_ADDRESS);
+
+ if (MacShouldAddressLoopBack(
+ Adapter->FilterDB,
+ Address
+ )) {
+
+ Pc586PutPacketOnLoopBack(
+ Adapter,
+ PacketToRemove,
+ FALSE
+ );
+
+ } else {
+
+ Pc586PutPacketOnFinishTrans(
+ Adapter,
+ PacketToRemove
+ );
+
+ }
+
+ return;
+
+}
+
+static
+VOID
+RelinquishPacket(
+ IN PPC586_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet,
+ )
+
+/*++
+
+Routine Description:
+
+ Relinquish the ring entries owned by the packet to the chip.
+ We also update the first uncommitted ring pointer.
+
+Arguments:
+
+ Adapter - The adapter that points to the ring entry structures.
+
+ Packet - The packet contains the ring index of the first ring
+ entry for the packet.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ // FOURTH MAKE 586 DO A TRANSMIT
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ WaitScb(Adapter);
+
+ Adapter->Scb->ScbCmd = SCBCUCSTRT;
+ ChanAttn(Adapter);
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+}
+
+
diff --git a/private/ntos/ndis/pc586e/pc586xfr.c b/private/ntos/ndis/pc586e/pc586xfr.c
new file mode 100644
index 000000000..c47d3dd52
--- /dev/null
+++ b/private/ntos/ndis/pc586e/pc586xfr.c
@@ -0,0 +1,620 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ pc586xfr.c - modeled after transfer.c of lance driver
+
+Abstract:
+
+ This file contains the code to implement the MacTransferData
+ API for the ndis 3.0 interface.
+
+Author:
+
+ Weldon Washburn, 10-30-90 adapted from...
+ Anthony V. Ercolano (Tonye) 12-Sept-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+
+--*/
+
+#include <ntos.h>
+#include <ndis.h>
+#include <filter.h>
+#include <pc586hrd.h>
+#include <pc586sft.h>
+
+UINT ww_tohost = 0xff; // set != 0 for 4 byte xfer in MoveToHost
+UINT ww_toadapter = 0xff; // set != 0 for 4 byte xfer in MoveToAdapter
+
+extern
+NDIS_STATUS
+Pc586TransferData(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ )
+
+/*++
+
+Routine Description:
+
+ A protocol calls the Pc586TransferData request (indirectly via
+ NdisTransferData) from within its Receive event handler
+ to instruct the MAC to copy the contents of the received packet
+ a specified paqcket buffer.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality this is a pointer to PC586_OPEN.
+
+ RequestHandle - A value supplied by the NDIS interface that the MAC
+ must use when completing this request with the NdisCompleteRequest
+ service, if the MAC completes the request asynchronously.
+ NOTE: This call will always be synchronous.
+
+ MacReceiveContext - The context value passed by the MAC on its call
+ to NdisIndicateReceive. The MAC can use this value to determine
+ which packet, on which adapter, is being received.
+
+ ByteOffset - An unsigned integer specifying the offset within the
+ received packet at which the copy is to begin. If the entire packet
+ is to be copied, ByteOffset must be zero.
+
+ BytesToTransfer - An unsigned integer specifying the number of bytes
+ to copy. It is legal to transfer zero bytes; this has no effect. If
+ the sum of ByteOffset and BytesToTransfer is greater than the size
+ of the received packet, then the remainder of the packet (starting from
+ ByteOffset) is transferred, and the trailing portion of the receive
+ buffer is not modified.
+
+ Packet - A pointer to a descriptor for the packet storage into which
+ the MAC is to copy the received packet.
+
+ BytesTransfered - A pointer to an unsigned integer. The MAC writes
+ the actual number of bytes transferred into this location. This value
+ is not valid if the return status is STATUS_PENDING.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+
+{
+
+ PPC586_ADAPTER Adapter;
+
+ NDIS_STATUS StatusToReturn;
+
+ Adapter = PPC586_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ if (!Adapter->ResetInProgress) {
+
+ PPC586_OPEN Open = PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ if (!Open->BindingShuttingDown) {
+
+ Open->References++;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ //
+ // The MacReceive context can be either of two things.
+ //
+ // If the low bit is != 1 then it is a pointer to the users
+ // ndis packet. It would typically be the packet when the
+ // packet has been delivered via loopback.
+ //
+ // If the value has a 1 in the low bit, the value holds the
+ // first and last receive ring descriptor indices.
+ //
+
+ if (!((UINT)MacReceiveContext & 1)) {
+
+ Pc586CopyFromPacketToPacket(
+ Packet,
+ 0,
+ BytesToTransfer,
+ (PNDIS_PACKET)((PVOID)MacReceiveContext),
+ ByteOffset,
+ BytesTransferred
+ );
+
+ } else {
+
+ //
+ // The code in this section is quite similar to the
+ // code in CopyFromPacketToPacket. It could easily go
+ // into its own routine, except that it is not likely
+ // to be used in any other implementation.
+ //
+
+ //
+ // Used for only a short time to extract the context
+ // information from the parameter.
+ //
+ PC586_RECEIVE_CONTEXT C;
+
+
+
+
+ //
+ // Holds the count of the number of ndis buffers comprising
+ // the destination packet.
+ //
+ UINT DestinationBufferCount;
+
+ //
+ // Points to the buffer into which we are putting data.
+ //
+ PNDIS_BUFFER DestinationCurrentBuffer;
+
+ //
+ // Holds the virtual address of the current destination
+ // buffer.
+ //
+ PVOID DestinationVirtualAddress;
+
+ //
+ // Holds the virtual address of the current source buffer.
+ //
+ PVOID SourceVirtualAddress;
+
+ //
+ // Holds the length of the current destination buffer.
+ //
+ UINT DestinationCurrentLength;
+
+ //
+ // Holds the length of the current source buffer.
+ //
+ UINT SourceCurrentLength;
+
+ //
+ // Keep a local variable of BytesTransferred so we aren't
+ // referencing through a pointer.
+ //
+ UINT LocalBytesTransferred = 0;
+
+ //
+ // The frame , receive buff descriptor in question
+ //
+ PFD Fd;
+ PRBD Rbd;
+
+
+ //
+ // Take care of boundary condition of zero length copy.
+ //
+
+ *BytesTransferred = 0;
+
+ ASSERT(sizeof(UINT) >= 2);
+ ASSERT(sizeof(UINT) == sizeof(NDIS_HANDLE));
+
+ C.a.WholeThing = (UINT)MacReceiveContext;
+ Fd = (PFD)((UINT)C.a.FrameDescriptor & 0xfffffffe);
+ Rbd = (PRBD)Pc586ToVirt(Adapter, Fd->FdRbdOfst);
+ if (Rbd == NULL) {
+ DbgPrint("Pc586TransferData(): Rbd == NULL\n");
+ goto Xfr1;
+ }
+
+ //
+ // Get the first buffer of the destination.
+ //
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ &DestinationBufferCount,
+ &DestinationCurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet.
+ //
+
+ if (DestinationBufferCount) {
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ NULL,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+
+ //
+ // Get the information for the first buffer of the source.
+ //
+
+ // the src addr, dest addr and length field plus first rbd
+ // were already transfered to Adapter->LookaheadNdis during
+ // PutPacket(). Thus use ...Lookahead... as starting data
+
+ SourceVirtualAddress = Adapter->LookaheadBufferNdis;
+ SourceCurrentLength = (Rbd->RbdStatus & CSRBDCNTMSK)
+ + 6 +6 +2 ;
+
+
+ while (LocalBytesTransferred < BytesToTransfer) {
+
+ //
+ // Check to see whether we've exhausted the current
+ // destination buffer. If so, move onto the next one.
+ //
+
+ if (!DestinationCurrentLength) {
+
+ NdisGetNextBuffer(
+ DestinationCurrentBuffer,
+ &DestinationCurrentBuffer
+ );
+
+ if (!DestinationCurrentBuffer) {
+
+ //
+ // We've reached the end of the packet. We
+ // return with what we've done so far. (Which
+ // must be shorter than requested.)
+ //
+
+ break;
+
+ }
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ NULL,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+ continue;
+
+ }
+
+
+ //
+ // Check to see whether we've exhausted the current
+ // source buffer. If so, move onto the next one.
+ //
+
+ if (!SourceCurrentLength) {
+
+ if ((Rbd->RbdStatus & CSEOF) ||
+ (Rbd->RbdSize & CSEL) ||
+ (Rbd->RbdStatus & CSBUSY) != CSBUSY ) {
+
+ //
+ // We've reached the end of the packet. We
+ // return with what we've done so far. (Which
+ // must be shorter than requested.)
+ //
+
+ break;
+
+ }
+
+ Rbd = (PRBD)Pc586ToVirt(Adapter, Rbd->RbdNxtOfst);
+ if (Rbd == NULL) break;
+ SourceCurrentLength=(Rbd->RbdStatus & CSRBDCNTMSK);
+ SourceVirtualAddress =
+ (PULONG)Pc586ToVirt(Adapter, Rbd->RbdBuff);
+ continue;
+
+ }
+
+ //
+ // Try to get us up to the point to start the copy.
+ //
+
+ if (ByteOffset) {
+
+ if (ByteOffset > SourceCurrentLength) {
+
+ //
+ // What we want isn't in this buffer.
+ //
+
+ ByteOffset -= SourceCurrentLength;
+ SourceCurrentLength = 0;
+ continue;
+
+ } else {
+
+ SourceVirtualAddress =
+ (PCHAR)SourceVirtualAddress + ByteOffset;
+ SourceCurrentLength -= ByteOffset;
+ ByteOffset = 0;
+
+ }
+
+ }
+
+ //
+ // Copy the data.
+ //
+
+ {
+
+ //
+ // Holds the amount of data to move.
+ //
+ UINT AmountToMove;
+
+ //
+ // Holds the amount desired remaining.
+ //
+ UINT Remaining = BytesToTransfer
+ - LocalBytesTransferred;
+
+ if (SourceCurrentLength <= DestinationCurrentLength)
+ AmountToMove = SourceCurrentLength;
+ else AmountToMove = DestinationCurrentLength;
+
+ if (Remaining < AmountToMove)
+ AmountToMove = Remaining;
+
+/* 88888888 compiler bug, use the above approach
+ AmountToMove =
+ ((SourceCurrentLength <= DestinationCurrentLength)?
+ (SourceCurrentLength):(DestinationCurrentLength));
+
+ AmountToMove = ((Remaining < AmountToMove)?
+ (Remaining):(AmountToMove));
+88888 */
+
+
+ Pc586MoveToHost(
+ DestinationVirtualAddress,
+ SourceVirtualAddress,
+ AmountToMove
+ );
+
+ DestinationVirtualAddress =
+ (PCHAR)DestinationVirtualAddress + AmountToMove;
+ SourceVirtualAddress =
+ (PCHAR)SourceVirtualAddress + AmountToMove;
+
+ LocalBytesTransferred += AmountToMove;
+ SourceCurrentLength -= AmountToMove;
+ DestinationCurrentLength -= AmountToMove;
+
+ }
+
+ }
+
+ *BytesTransferred = LocalBytesTransferred;
+
+ }
+
+ }
+
+Xfr1:
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Open->References--;
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ } else {
+
+ StatusToReturn = NDIS_STATUS_REQUEST_ABORTED;
+
+ }
+
+ } else {
+
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ }
+
+ PC586_DO_DEFERRED(Adapter);
+
+ if (StatusToReturn != NDIS_STATUS_SUCCESS)
+ DbgPrint("Pc586TransferData(): StatusToReturn = %lx\n", StatusToReturn);
+ if (*BytesTransferred != BytesToTransfer)
+ DbgPrint("Pc586TransferData(): BytesTransferred = %lx, BytesToTransfer = %lx \n", *BytesTransferred, BytesToTransfer);
+
+ return StatusToReturn;
+}
+
+
+VOID
+Pc586MoveToHost(
+ IN PVOID DestinationVirtualAddress,
+ IN PVOID SourceVirtualAddress,
+ IN UINT AmountToMove
+ )
+
+/*++
+
+Routine Description:
+
+ This routine copies data from pc586 network adapter card to host RAM in
+ a special way. This is because pc586 RAM can only be accessed on
+ 2-byte boundries.
+
+
+Arguments:
+
+ IN PVOID DestinationVirtualAddress - host RAM address
+
+ IN PVOID SourceVirtualAddress - pc586 adapter RAM address
+
+ IN UINT AmountToMove - just as it says
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PACKUSHORTT zz;
+ PUCHAR DVA, SVA;
+
+ if (!AmountToMove) return;
+
+ DVA = (PUCHAR)DestinationVirtualAddress;
+ SVA = (PUCHAR)SourceVirtualAddress;
+
+ if ((UINT)SVA & 1) {
+ SVA = SVA - 1;
+ zz.c.b = *(PUSHORT)SVA;
+ SVA = SVA + 2;
+ *DVA++ = zz.c.a[1];
+ AmountToMove--;
+ }
+
+if (ww_tohost == 0) { /*88888888888*/
+
+ for( ; AmountToMove; AmountToMove -= 2 ) {
+
+ if (AmountToMove == 1) {
+ zz.c.b = *(PUSHORT)SVA;
+ *DVA = zz.c.a[0];
+ break;
+ }
+ *(PUSHORT)(DVA) = *(PUSHORT)(SVA);
+ DVA+=2;
+ SVA+=2;
+ }
+} else { /*88888888888*/
+
+ for( ; AmountToMove; ) {
+
+ if (AmountToMove == 1) {
+ zz.c.b = *(PUSHORT)SVA;
+ *DVA = zz.c.a[0];
+ break;
+ }
+ if ( (((UINT)SVA & 0x03) == 0) && (AmountToMove > 4) ) {
+
+ for ( ; AmountToMove; ) {
+ *(PULONG)(DVA) = *(PULONG)(SVA);
+ DVA += 4;
+ SVA += 4;
+ AmountToMove -= 4;
+ if (AmountToMove < 4) break;
+ }
+ } else {
+ *(PUSHORT)(DVA) = *(PUSHORT)(SVA);
+ DVA+=2;
+ SVA+=2;
+ AmountToMove -= 2;
+ }
+ }
+
+} /*88888888888*/
+}
+
+
+
+VOID
+Pc586MoveToAdapter(
+ IN PVOID DestinationVirtualAddress,
+ IN PVOID SourceVirtualAddress,
+ IN UINT AmountToMove
+ )
+
+/*++
+
+Routine Description:
+
+ This routine copies data to pc586 network adapter card from host RAM in
+ a special way. This is because pc586 RAM can only be accessed on
+ 2-byte boundries.
+
+
+Arguments:
+
+ IN PVOID DestinationVirtualAddress - adapter RAM address
+
+ IN PVOID SourceVirtualAddress - host RAM address
+
+ IN UINT AmountToMove - just as it says
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PACKUSHORTT zz;
+ PUCHAR DVA, SVA;
+
+ if (!AmountToMove) return;
+
+ DVA = (PUCHAR)DestinationVirtualAddress;
+ SVA = (PUCHAR)SourceVirtualAddress;
+
+ if ((UINT)DVA & 1) {
+ DVA = DVA -1;
+ zz.c.b = *(PUSHORT)DVA;
+ zz.c.a[1] = *SVA++;
+ *(PUSHORT)DVA = zz.c.b;
+ DVA+=2;
+ AmountToMove--;
+ }
+
+if (ww_toadapter == 0) { /*88888888888*/
+ for( ; AmountToMove; AmountToMove -= 2 ) {
+
+ if (AmountToMove == 1) {
+ zz.c.b = *(PUSHORT)DVA;
+ zz.c.a[0] = *SVA;
+ *(PUSHORT)DVA = zz.c.b;
+ break;
+ }
+ *(PUSHORT)(DVA) = *(PUSHORT)(SVA);
+ DVA+=2;
+ SVA+=2;
+ }
+} else { /*88888888888*/
+
+ for( ; AmountToMove; ) {
+
+ if (AmountToMove == 1) {
+ zz.c.b = *(PUSHORT)DVA;
+ zz.c.a[0] = *SVA;
+ *(PUSHORT)DVA = zz.c.b;
+ break;
+ }
+ if ( (((UINT)DVA & 0x03) == 0) && (AmountToMove > 4) ) {
+
+ for( ; AmountToMove; ) {
+ *(PULONG)(DVA) = *(PULONG)(SVA);
+ DVA += 4;
+ SVA += 4;
+ AmountToMove -= 4;
+ if (AmountToMove < 4) break;
+ }
+ } else {
+ *(PUSHORT)(DVA) = *(PUSHORT)(SVA);
+ DVA+=2;
+ SVA+=2;
+ AmountToMove -= 2;
+ }
+ }
+
+} /*88888888888*/
+}
+
diff --git a/private/ntos/ndis/pc586e/sources b/private/ntos/ndis/pc586e/sources
new file mode 100644
index 000000000..383eccf93
--- /dev/null
+++ b/private/ntos/ndis/pc586e/sources
@@ -0,0 +1,47 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=pc586
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+INCLUDES=..\..\inc
+
+SOURCES=pc586.c \
+ pc586snd.c \
+ packet.c \
+ pc586xfr.c \
+ loopback.c \
+ filter.c \
+ ushort.c
+
+RELATIVE_DEPTH=..\..
+
+MSC_WARNING_LEVEL=/W3 /WX
+
diff --git a/private/ntos/ndis/pc586e/ushort.c b/private/ntos/ndis/pc586e/ushort.c
new file mode 100644
index 000000000..e728f4dec
--- /dev/null
+++ b/private/ntos/ndis/pc586e/ushort.c
@@ -0,0 +1,98 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ushort.c
+
+Abstract:
+
+ The following is a workaround for 386 cc optimization. The 386 cc generates
+ code that will optimize out one of the bytes of a 16-bit "OR" operation
+ if the constant that is part of the "OR" has a byte equal to zero. For
+ instance, "(USHORT)xx |= SCBINTCX;" will generate code that will "OR"
+ 0x80 with (UCHAR)((PUCHAR)&xx +1) which causes hardware problems with
+ pc586 card.
+
+ The workaround is to replace #defines in pc586hrd.h with the following
+ USHORTS
+
+--*/
+
+#include <ntos.h>
+#include <ndis.h>
+
+USHORT SCBINTMSK = 0xf000; // SCB STAT bit mask
+USHORT SCBINTCX = 0x8000; // CX bit, CU finished a command with "I" set
+USHORT SCBINTFR = 0x4000; // FR bit, RU finished receiving a frame
+USHORT SCBINTCNA = 0x2000; // CNA bit, CU not active
+USHORT SCBINTRNR = 0x1000; // RNR bit, RU not ready
+
+// command unit status bits
+
+USHORT SCBCUSMSK = 0x0700; // SCB CUS bit mask
+USHORT SCBCUSIDLE = 0x0000; // CU idle
+USHORT SCBCUSSUSPND= 0x0100; // CU suspended
+USHORT SCBCUSACTV = 0x0200; // CU active
+
+// receive unit status bits
+
+USHORT SCBRUSMSK = 0x0070; // SCB RUS bit mask
+USHORT SCBRUSIDLE = 0x0000; // RU idle
+USHORT SCBRUSSUSPND = 0x0010; // RU suspended
+USHORT SCBRUSNORESRC = 0x0020; // RU no resource
+USHORT SCBRUSREADY = 0x0040; // RU ready
+
+// bits used to acknowledge an interrupt from 586
+
+USHORT SCBACKMSK = 0xf000; // SCB ACK bit mask
+USHORT SCBACKCX = 0x8000; // ACKCX, acknowledge a completed cmd
+USHORT SCBACKFR = 0x4000; // ACKFR, acknowledge a frame reception
+USHORT SCBACKCNA = 0x2000; // ACKCNA, acknowledge CU not active
+USHORT SCBACKRNR = 0x1000; // ACKRNR, acknowledge RU not ready
+
+// 586 CU commands
+
+USHORT SCBCUCMSK = 0x0700; // SCB CUC bit mask
+USHORT SCBCUCSTRT = 0x0100; // start CU
+USHORT SCBCUCRSUM = 0x0200; // resume CU
+USHORT SCBCUCSUSPND= 0x0300; // suspend CU
+USHORT SCBCUCABRT = 0x0400; // abort CU
+
+// 586 RU commands
+
+USHORT SCBRUCMSK = 0x0070; // SCB RUC bit mask
+USHORT SCBRUCSTRT = 0x0010; // start RU
+USHORT SCBRUCRSUM = 0x0020; // resume RU
+USHORT SCBRUCSUSPND = 0x0030; // suspend RU
+USHORT SCBRUCABRT = 0x0040; // abort RU
+
+USHORT SCBRESET = 0x0080; // software reset of 586
+
+// USHORT's for the command and descriptor blocks
+
+USHORT CSCMPLT = 0x8000; // C bit, completed
+USHORT CSBUSY = 0x4000; // B bit, Busy
+USHORT CSOK = 0x2000; // OK bit, error free
+USHORT CSABORT = 0x1000; // A bit, abort
+USHORT CSEL = 0x8000; // EL bit, end of list
+USHORT CSSUSPND = 0x4000; // S bit, suspend
+USHORT CSINT = 0x2000; // I bit, interrupt
+USHORT CSSTATMSK = 0x3fff; // Command status mask
+USHORT CSEOL = 0xffff; // set for fdrbdofst on unattached FDs
+USHORT CSEOF = 0x8000; // EOF (End Of Frame) in the TBD and RBD
+USHORT CSRBDCNTMSK = 0x3fff; // actual count mask in RBD
+
+// second level commands
+
+USHORT CSCMDMSK = 0x07; // command bits mask
+USHORT CSCMDNOP = 0x00; // NOP
+USHORT CSCMDIASET = 0x01; // Individual Address Set up
+USHORT CSCMDCONF = 0x02; // Configure
+USHORT CSCMDMCSET = 0x03; // Multi-Cast Setup
+USHORT CSCMDXMIT = 0x04; // transmit
+USHORT CSCMDTDR = 0x05; // Time Domain Reflectomete
+USHORT CSCMDDUMP = 0x06; // dump
+USHORT CSCMDDGNS = 0x07; // diagnose
+
diff --git a/private/ntos/ndis/pcimac/adapter.h b/private/ntos/ndis/pcimac/adapter.h
new file mode 100644
index 000000000..673a01082
--- /dev/null
+++ b/private/ntos/ndis/pcimac/adapter.h
@@ -0,0 +1,230 @@
+/*
+ * ADAPTER.H - NDIS Adapter Interface, main include file
+ */
+
+
+#ifndef _ADAPTER_
+#define _ADAPTER_
+
+#define PCIMAC_KEY_BOARDTYPE "BoardType"
+#define PCIMAC_KEY_BASEIO "IOBaseAddress"
+#define PCIMAC_KEY_BASEMEM "MemoryMappedBaseAddress"
+#define PCIMAC_KEY_BOARDNAME "BoardName"
+#define PCIMAC_KEY_LINENAME "LineName"
+#define PCIMAC_KEY_NUMLINES "NumberOfLines"
+#define PCIMAC_KEY_IDPFILENAME "IDPImageFileName"
+#define PCIMAC_KEY_SWITCHSTYLE "SwitchStyle"
+#define PCIMAC_KEY_TERMINALMANAGEMENT "TerminalManagement"
+#define PCIMAC_KEY_NUMLTERMS "LogicalTerminals"
+#define PCIMAC_KEY_TEI "TEI"
+#define PCIMAC_KEY_SPID "SPID"
+#define PCIMAC_KEY_ADDRESS "Address"
+#define PCIMAC_KEY_LINE "Line"
+#define PCIMAC_KEY_LTERM "LTerm"
+#define PCIMAC_KEY_WAITFORL3 "WaitForL3"
+#define PCIMAC_KEY_GENERICDEFINES "GenericDefines"
+
+/* global driver obect */
+typedef struct tagDRIVER_BLOCK
+{
+ NDIS_HANDLE NdisMacHandle;
+ NDIS_HANDLE NdisWrapperHandle;
+ struct _ADAPTER* AdapterTbl[MAX_ADAPTERS_IN_SYSTEM];
+ ULONG InDriverFlag;
+ ULONG NumberOfAdaptersInSystem;
+ ULONG NextAdapterToPoll;
+ struct _ADAPTER* CurrentAdapter;
+ NDIS_SPIN_LOCK lock;
+} DRIVER_BLOCK;
+
+typedef struct _ADAPTER
+{
+ NDIS_HANDLE Handle;
+// ULONG InDriverFlag;
+// NDIS_SPIN_LOCK InDriverLock;
+ CHAR Name[64];
+ ULONG BaseIO;
+ PVOID VBaseIO;
+ ULONG BaseMem;
+ PVOID VBaseMem;
+ ULONG BoardType;
+ ULONG TapiBaseID;
+ ULONG NumberOfIddOnAdapter;
+ ULONG LastIddPolled;
+ VOID *TapiLineInfo[MAX_CM_PER_ADAPTER]; // 8
+ VOID *IddTbl[MAX_IDD_PER_ADAPTER]; // 4
+ VOID *CmTbl[MAX_CM_PER_ADAPTER]; // 8
+ VOID *MtlTbl[MAX_MTL_PER_ADAPTER]; // 8
+ NDIS_MINIPORT_TIMER IddPollTimer; // idd polling timer
+ NDIS_MINIPORT_TIMER MtlPollTimer; // mtl polling timer
+ NDIS_MINIPORT_TIMER CmPollTimer; // cm polling timer
+}ADAPTER;
+
+typedef struct _CONFIGPARAM
+{
+ INT ParamType;
+ CHAR String[512];
+ ULONG StringLen;
+ ULONG Value;
+ ULONG MustBePresent;
+ NDIS_HANDLE ConfigHandle;
+ NDIS_HANDLE AdapterHandle;
+} CONFIGPARAM;
+
+VOID StopTimers(ADAPTER* Adapter);
+VOID StartTimers(ADAPTER* Adapter);
+
+//VOID
+//SetInDriverFlag(
+// ADAPTER *Adapter
+// );
+//
+//VOID
+//ClearInDriverFlag(
+// ADAPTER *Adapter
+// );
+//
+//ULONG
+//CheckInDriverFlag(
+// ADAPTER *Adapter
+// );
+
+VOID
+SetInDriverFlag(
+ ADAPTER *Adapter
+ );
+
+VOID
+ClearInDriverFlag(
+ ADAPTER *Adapter
+ );
+
+ULONG
+CheckInDriverFlag(
+ ADAPTER *Adapter
+ );
+
+BOOLEAN
+PcimacCheckForHang(
+ NDIS_HANDLE AdapterContext
+ );
+
+VOID
+PcimacDisableInterrupts(
+ NDIS_HANDLE AdapterContext
+ );
+
+VOID
+PcimacEnableInterrupts(
+ NDIS_HANDLE AdapterContext
+ );
+
+VOID
+PcimacHalt(
+ NDIS_HANDLE AdapterContext
+ );
+
+VOID
+PcimacHandleInterrupt(
+ NDIS_HANDLE AdapterContext
+ );
+
+NDIS_STATUS
+PcimacInitialize(
+ PNDIS_STATUS OpenErrorStatus,
+ PUINT SelectMediumIndex,
+ PNDIS_MEDIUM MediumArray,
+ UINT MediumArraySize,
+ NDIS_HANDLE AdapterHandle,
+ NDIS_HANDLE WrapperConfigurationContext
+ );
+
+VOID
+PcimacISR(
+ PBOOLEAN InterruptRecognized,
+ PBOOLEAN QueueMiniportHandleInterrupt,
+ NDIS_HANDLE AdapterContext
+ );
+
+NDIS_STATUS
+PcimacSetQueryInfo(
+ NDIS_HANDLE AdapterContext,
+ NDIS_OID Oid,
+ PVOID InfoBuffer,
+ ULONG InfoBufferLen,
+ PULONG BytesWritten,
+ PULONG BytesNeeded
+ );
+
+NDIS_STATUS
+PcimacReconfigure(
+ PNDIS_STATUS OpenErrorStatus,
+ NDIS_HANDLE AdapterContext,
+ NDIS_HANDLE WrapperConfigurationContext
+ );
+
+NDIS_STATUS
+PcimacReset(
+ PBOOLEAN AddressingReset,
+ NDIS_HANDLE AdapterContext
+ );
+
+NDIS_STATUS
+PcimacSend(
+ NDIS_HANDLE MacBindingHandle,
+ NDIS_HANDLE LinkContext,
+ PNDIS_WAN_PACKET WanPacket
+ );
+
+INT
+IoEnumAdapter(
+ VOID *cmd_1
+ );
+
+ULONG
+EnumAdaptersInSystem(
+ VOID
+ );
+
+ADAPTER*
+GetNextAdapter(
+ ADAPTER *Adapter
+ );
+
+VOID
+AdapterDestroy(
+ ADAPTER *Adapter
+ );
+
+NDIS_STATUS
+WanOidProc(
+ NDIS_HANDLE AdapterContext,
+ NDIS_OID Oid,
+ PVOID InfoBuffer,
+ ULONG InfoBufferLen,
+ PULONG BytesReadWritten,
+ PULONG BytesNeeded
+ );
+
+NDIS_STATUS
+TapiOidProc(
+ NDIS_HANDLE AdapterContext,
+ NDIS_OID Oid,
+ PVOID InfoBuffer,
+ ULONG InfoBufferLen,
+ PULONG BytesWritten,
+ PULONG BytesNeeded
+ );
+
+NDIS_STATUS
+LanOidProc(
+ NDIS_HANDLE AdapterContext,
+ NDIS_OID Oid,
+ PVOID InfoBuffer,
+ ULONG InfoBufferLen,
+ PULONG BytesReadWritten,
+ PULONG BytesNeeded
+ );
+
+
+#endif /* _ADAPTER_ */
diff --git a/private/ntos/ndis/pcimac/adp.bin b/private/ntos/ndis/pcimac/adp.bin
new file mode 100644
index 000000000..fd0b403b2
--- /dev/null
+++ b/private/ntos/ndis/pcimac/adp.bin
Binary files differ
diff --git a/private/ntos/ndis/pcimac/cm.h b/private/ntos/ndis/pcimac/cm.h
new file mode 100644
index 000000000..4478d0b1e
--- /dev/null
+++ b/private/ntos/ndis/pcimac/cm.h
@@ -0,0 +1,162 @@
+/*
+ * CM.H - definitions for connection manager
+ */
+
+#ifndef _CM_
+#define _CM_
+
+#include <ndistapi.h>
+#include <cm_pub.h>
+
+/* error codes */
+#define CM_E_SUCC 0 /* success, ok */
+#define CM_E_NOSLOT 1 /* no slot available error */
+#define CM_E_BUSY 2 /* cm context is busy */
+#define CM_E_NOSUCH 3 /* no such object */
+#define CM_E_BADCHAN 4 /* bad channel argument */
+#define CM_E_IDD 5 /* idd command errored */
+#define CM_E_NOMEM 6 /* ran out of memory */
+#define CM_E_NOTIMPL 7 /* functionalit not implemented yet */
+#define CM_E_BADPARAM 8 /* bad parameter */
+#define CM_E_BADSTATE 9 /* bad state */
+#define CM_E_BADUUS 10 /* bad user-to-user signalling packet */
+#define CM_E_BADPORT 11 /* bad nai given */
+
+//
+// q931 switch styles
+//
+#define CM_SWITCHSTYLE_NONE 0 // no style
+#define CM_SWITCHSTYLE_AUTO 1 // auto detect
+#define CM_SWITCHSTYLE_NI1 2 // national isdn 1
+#define CM_SWITCHSTYLE_ATT 3 // at&t 5ess
+#define CM_SWITCHSTYLE_NTI 4 // northern telecom dms100
+#define CM_SWITCHSTYLE_NET3 5 // net3 (europe)
+#define CM_SWITCHSTYLE_1TR6 6 // 1tr6 (german)
+#define CM_SWITCHSTYLE_VN3 7 // vn3 (france)
+#define CM_SWITCHSTYLE_INS64 8 // ins64 (japan)
+
+//
+// local cm def's
+//
+/* map a channel to signaling idd port */
+#define CM_PORT(_chan) ((_chan)->lterm + IDD_PORT_CM0_TX)
+
+/* user to user signaling structure (!must be byte alligned!) */
+#pragma pack(2)
+typedef struct
+{
+ CHAR dst_addr[6]; /* destination address */
+ CHAR src_addr[6]; /* source address */
+ USHORT pkt_type; /* packet type field */
+#define CM_PKT_TYPE 0x5601 /* - private packet type */
+ UCHAR prot_desc; /* protocol descriptor field */
+#define CM_PROT_DESC 0x78 /* - private protoocl descriptor */
+ UCHAR opcode; /* opcode fields */
+#define CM_ASSOC_RQ 0x01 /* - request for chan/conn assoc */
+#define CM_ASSOC_ACK 0x02 /* - assoc ack'ed */
+#define CM_ASSOC_NACK 0x03 /* - assoc not ack'ed */
+ UCHAR cause; /* cause value, to assist in diag */
+#define CM_NO_PROF 0x01 /* - no matching profile */
+#define CM_NO_CONN 0x02 /* - no connection slot avail */
+#define CM_NO_CHAN 0x03 /* - no channel slot avail */
+#define CM_DUP_CONN 0x04 /* - dup conn name */
+ UCHAR conn; /* connection index */
+ UCHAR channum; /* # of channels in connections */
+ UCHAR chan; /* channel index */
+ CHAR lname[24]; /* local profile name */
+ ULONG option_0; // uus option fields
+#define UUS_0_COMPRESSION 0x00004000
+#define COMP_TX_ENA 0x01
+#define COMP_RX_ENA 0x02
+ ULONG option_1;
+ CHAR rname[24]; /* remote profile name */
+ ULONG option_2;
+ ULONG option_3;
+ UCHAR chksum; /* zero checksum field */
+} CM_UUS;
+#pragma pack()
+
+/* C compiler fails go generate odd sized structures!, must defined by self */
+#define CM_UUS_SIZE (sizeof(CM_UUS) - 1)
+
+/* special channel ustates */
+#define CM_US_UNDEF (USHORT)(-1) /* undefined, not known yet */
+#define CM_US_WAIT_CID (USHORT)(-2) /* waiting for a cid */
+#define CM_US_GAVE_UP (USHORT)(-4) /* gave up on this channel */
+#define CM_US_WAIT_CONN 50 /* connected, waiting on other */
+#define CM_US_UUS_SEND 51 /* sending uus now */
+#define CM_US_UUS_OKED 52 /* uus oked by side, wait on other */
+#define CM_US_CONN 53 /* connected */
+
+
+/* CM class operation prototypes */
+INT cm_init(VOID);
+INT cm_term(VOID);
+INT cm_register_idd(VOID* idd);
+INT cm_deregister_idd(VOID* idd);
+
+/* CM object operation prototypes */
+INT cm_create(VOID** cm_1, NDIS_HANDLE AdapterHandle);
+INT cm_destroy(VOID* cm_1);
+INT cm_set_profile(VOID* cm_1, CM_PROF* prof);
+INT cm_get_profile(VOID* cm_1, CM_PROF* prof);
+INT cm_listen(VOID* cm_1);
+INT cm_connect(VOID* cm_1);
+INT cm_disconnect(VOID* cm_1);
+INT cm_get_status(VOID* cm_1, CM_STATUS* stat);
+INT cm_report_frame(VOID* cm_1, BOOL is_rx, CHAR* buf, ULONG len);
+
+/* prototypes for internal functions */
+VOID cm__q931_handler(IDD* idd, USHORT chan, ULONG Reserved, IDD_MSG* msg);
+VOID cm__q931_bchan_handler(VOID* idd, USHORT chan, ULONG RxFrameType, IDD_XMSG* msg);
+VOID cm__q931_cmpl_handler(VOID* idd, USHORT chan, IDD_MSG* msg);
+INT cm__elem_rq(VOID* idd, USHORT port, CHAR* elem, USHORT elem_num);
+INT cm__initiate_conn(CM* cm);
+INT cm__disc_rq(CM_CHAN* chan);
+INT cm__est_rq(CM_CHAN* chan);
+INT cm__est_rsp(CM_CHAN* chan);
+INT cm__est_ignore(PVOID idd, USHORT cid, USHORT lterm);
+INT cm__deactivate_conn(CM* cm, BOOL by_idle_timer);
+INT cm__activate_conn(CM* cm, ULONG CompressionFlag);
+INT cm__bchan_ctrl(CM_CHAN* chan, BOOL turn_on);
+INT cm__bchan_ctrl_comp(CM_CHAN *chan, ULONG CompressionFlag);
+CM_CHAN* cm__map_chan(VOID* idd, USHORT lterm, USHORT cid);
+CM_CHAN* cm__map_bchan_chan(VOID* idd, USHORT port);
+INT cm__ans_est_ind(CM_CHAN* chan, IDD_MSG* msg, VOID* idd, USHORT lterm);
+INT cm__org_cid_ind(CM_CHAN* chan, IDD_MSG* msg);
+INT cm__org_state_ind(CM_CHAN* chan, IDD_MSG* msg);
+INT cm__ans_state_ind(CM_CHAN* chan, IDD_MSG* msg);
+INT cm__org_elem_ind(CM_CHAN* chan, IDD_MSG* msg);
+INT cm__org_data_ind(CM_CHAN* chan, IDD_MSG* msg);
+INT cm__ans_data_ind(CM_CHAN* chan, IDD_MSG* msg);
+UCHAR cm__calc_chksum(VOID* buf_1, INT len);
+CM* cm__get_conn(ULONG conn_index);
+INT cm__get_next_chan(CM_CHAN* chan);
+INT cm__tx_uus_pkt(CM_CHAN *chan, UCHAR opcode, UCHAR cause);
+INT cm__get_bchan(IDD_MSG* msg, USHORT* bchan);
+INT cm__get_type(IDD_MSG* msg, USHORT* type);
+INT cm__get_addr(IDD_MSG* msg, CHAR addr[32]);
+ULONG cm__type2speed(USHORT type);
+UCHAR *cm__q931_elem(VOID* ptr_1, INT len, UCHAR elem);
+INT cm__timer_tick(CM* cm);
+CM_CHAN *cm__chan_alloc(VOID);
+VOID cm__chan_free(CM_CHAN* chan);
+BOOL cm__chan_foreach(BOOL (*func)(), VOID* a1, VOID* a2);
+BOOL cm__inc_chan_num(CM_CHAN* chan, CM_CHAN* ref_chan, ULONG *chan_num);
+BOOL cm__add_chan(CM_CHAN* chan, CM_CHAN* ref_chan, CM* cm);
+CM* cm__find_listen_conn(CHAR* lname, CHAR* rname, CHAR* addr, VOID*);
+VOID ChannelInit(VOID);
+VOID ChannelTerm(VOID);
+VOID cm__ppp_conn(VOID *idd, USHORT port);
+INT WanLineup(VOID* cm_1, NDIS_HANDLE Endpoint);
+INT WanLinedown(VOID* cm_1);
+ULONG EnumCmInSystem(VOID);
+ULONG EnumCmPerAdapter(ADAPTER*);
+INT IoEnumCm(VOID* cmd_1);
+VOID* CmGetMtl(VOID* cm_1);
+UCHAR* GetDstAddr(VOID *cm_1);
+UCHAR* GetSrcAddr(VOID *cm_1);
+VOID CmPollFunction(VOID *a1, ADAPTER *Adapter, VOID *a3, VOID *a4);
+VOID CmSetSwitchStyle(CHAR *SwitchStyle);
+
+#endif /* _CM_ */
diff --git a/private/ntos/ndis/pcimac/cm_chan.c b/private/ntos/ndis/pcimac/cm_chan.c
new file mode 100644
index 000000000..81edb9709
--- /dev/null
+++ b/private/ntos/ndis/pcimac/cm_chan.c
@@ -0,0 +1,107 @@
+/*
+ * CM_CHAN.C - channel allocation (for incoming) code
+ */
+
+#include <ndis.h>
+//#include <ndismini.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+
+CM_CHAN *chan_tbl;
+BOOL chan_used[MAX_CHAN_IN_SYSTEM];
+
+
+#pragma NDIS_INIT_FUNCTION(ChannelInit)
+
+//
+// Allocate free channel pool
+//
+VOID
+ChannelInit(VOID)
+{
+ NDIS_PHYSICAL_ADDRESS pa = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
+
+ /* allocate memory object */
+ NdisAllocateMemory((PVOID*)&chan_tbl, sizeof(CM_CHAN) * MAX_CHAN_IN_SYSTEM, 0, pa);
+ if ( chan_tbl == NULL )
+ {
+ D_LOG(D_ALWAYS, ("ChannelInit: memory allocate failed!"));
+ return;
+ }
+ D_LOG(D_ALWAYS, ("ChannelInit: chan_tbl: 0x%x", chan_tbl));
+ NdisZeroMemory (chan_tbl, sizeof(CM_CHAN) * MAX_CHAN_IN_SYSTEM);
+ NdisZeroMemory (chan_used, sizeof(chan_used));
+}
+
+VOID
+ChannelTerm(VOID)
+{
+ /* free memory */
+ NdisFreeMemory(chan_tbl, sizeof(CM_CHAN) * MAX_CHAN_IN_SYSTEM, 0);
+}
+
+/* allocate a channel */
+CM_CHAN*
+cm__chan_alloc(VOID)
+{
+ CM_CHAN *chan = NULL;
+ INT n;
+
+ D_LOG(D_ENTRY, ("cm__chan_alloc: entry"));
+
+ for ( n = 0 ; n < MAX_CHAN_IN_SYSTEM ; n++ )
+ if ( !chan_used[n] )
+ {
+ chan_used[n] = TRUE;
+ chan = chan_tbl + n;
+ break;
+ }
+
+ D_LOG(D_EXIT, ("cm__alloc_chan: exit, chan: 0x%p", chan));
+ return(chan);
+}
+
+/* free a channel */
+VOID
+cm__chan_free(CM_CHAN *chan)
+{
+ D_LOG(D_ENTRY, ("cm__chan_free: entry, chan: 0x%p", chan));
+
+ chan_used[chan - chan_tbl] = FALSE;
+}
+
+/* call a callback function for each used channel */
+BOOL
+cm__chan_foreach(BOOL (*func)(), VOID *a1, VOID *a2)
+{
+ INT n;
+ BOOL ret = TRUE;
+
+ D_LOG(D_ENTRY, ("cm__chan_foreach: entry, func: %p, a1: 0x%p, a2: 0x%p", \
+ func, a1, a2));
+
+ for ( n = 0 ; n < MAX_CHAN_IN_SYSTEM ; n++ )
+ if ( chan_used[n] )
+ {
+ CM_CHAN *chan = chan_tbl + n;
+
+ D_LOG(D_ALWAYS, ("cm__chan_foreach: calling for chan# %d, channel: %p", n, chan));
+
+ ret = (*func)(chan, a1, a2);
+
+ D_LOG(D_ALWAYS, ("cm__chan_foreach: returned %d", ret));
+
+ if ( !ret )
+ break;
+ }
+
+ return(ret);
+}
diff --git a/private/ntos/ndis/pcimac/cm_conn.c b/private/ntos/ndis/pcimac/cm_conn.c
new file mode 100644
index 000000000..7420b3d0a
--- /dev/null
+++ b/private/ntos/ndis/pcimac/cm_conn.c
@@ -0,0 +1,324 @@
+/*
+ * CM_CONN.C - connection managment code
+ */
+
+#include <ndis.h>
+//#include <ndismini.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+
+/* mark connection as ready to accept calls (listening mode) */
+INT
+cm_listen(VOID *cm_1)
+{
+ CM *cm = (CM*)cm_1;
+ D_LOG(D_ENTRY, ("cm_listen: entry, cm: 0x%p", cm));
+
+ /* connection must be idle */
+ if ( cm->state != CM_ST_IDLE )
+ return(CM_E_BUSY);
+
+ /* mark & return */
+ cm->dprof = cm->oprof;
+ cm->state = CM_ST_LISTEN;
+ cm->StateChangeFlag = TRUE;
+ cm->PPPToDKF = 0;
+ return(CM_E_SUCC);
+}
+
+/* initiate a connection */
+INT
+cm_connect(VOID *cm_1)
+{
+#define ABORT(_ret) { ret = _ret; goto aborting; }
+ CM *cm = (CM*)cm_1;
+ ULONG n;
+ INT ret = CM_E_SUCC;
+
+ D_LOG(D_ENTRY, ("cm_connect: entry, cm: 0x%p", cm));
+
+ /* connection must be idle or listening */
+ if ( (cm->state != CM_ST_IDLE) && (cm->state != CM_ST_LISTEN) )
+ return(CM_E_BUSY);
+
+ /* switch connection state to waiting for activation for now */
+ cm->state = CM_ST_WAIT_ACT;
+ cm->StateChangeFlag = TRUE;
+
+ /* copy original profile to dynamic */
+ cm->dprof = cm->oprof;
+
+
+ /* initialize other fields */
+ cm->was_listen = 0;
+ cm->active_chan_num = 0;
+ cm->speed = 0;
+ cm->rx_last_frame_time = cm->tx_last_frame_time = ut_time_now();
+ cm->timeout = cm->rx_last_frame_time;
+ cm->remote_conn_index = 0xff;
+ cm->CauseValue = 0x7F;
+ cm->SignalValue = 0xFF;
+ cm->NoActiveLine = 0;
+ cm->PPPToDKF = 0;
+ NdisZeroMemory(cm->DstAddr, sizeof(cm->DstAddr));
+ NdisZeroMemory(cm->remote_name, sizeof(cm->remote_name));
+
+ /* init & check channel vector */
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++ )
+ {
+ CM_CHAN *chan = cm->dprof.chan_tbl + n;
+
+ /* assign index */
+ chan->num = (USHORT)n;
+ chan->cm = cm;
+ chan->ustate = 0;
+ chan->active = 0;
+ chan->gave_up = 0;
+
+ /* if connection is nailed, channal must be explicit */
+ if ( cm->dprof.nailed && !CM_BCHAN_ASSIGNED(chan->bchan) )
+ ABORT(CM_E_BADCHAN);
+ }
+
+ /* if connection is to be activated by frame, exit here */
+ if ( cm->dprof.frame_activated )
+ return(CM_E_SUCC);
+
+ /* if here, connection has to be activated now! */
+ cm->state = CM_ST_IN_ACT;
+ cm->StateChangeFlag = TRUE;
+ if ( (ret = cm__initiate_conn(cm)) == CM_E_SUCC )
+ return(CM_E_SUCC);
+
+ /* if here, aborting connection */
+ aborting:
+ cm->state = CM_ST_IDLE;
+ cm->StateChangeFlag = TRUE;
+ return(ret);
+}
+
+/* disconnect a connection, back to idle state */
+INT
+cm_disconnect(VOID *cm_1)
+{
+ CM *cm = (CM*)cm_1;
+ ULONG n;
+
+ D_LOG(D_ENTRY, ("cm_disconnect: entry, cm: 0x%p", cm));
+
+ /* branch on connection state */
+ switch ( cm->state )
+ {
+ case CM_ST_IDLE : /* already idle, do nothing */
+ default :
+ break;
+
+ case CM_ST_LISTEN : /* waiting for a connection, cancel */
+ case CM_ST_WAIT_ACT : /* waiting for activation, cancel */
+ case CM_ST_DEACT : /* deactivated, cancel */
+ cm->state = CM_ST_IDLE;
+ cm->StateChangeFlag = TRUE;
+ break;
+
+ case CM_ST_IN_ACT : /* in activation */
+ case CM_ST_IN_SYNC : /* syncronizing */
+ case CM_ST_ACTIVE : /* is active */
+ case CM_ST_IN_ANS : /* in answering process */
+
+ /* scan channel, issue a disconnect */
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++)
+ {
+ CM_CHAN *chan = cm->dprof.chan_tbl + n;
+
+ /* check is channel is used in this connection */
+ if ( chan->gave_up || !chan->ustate )
+ continue;
+
+ /* disconnect it */
+ cm__disc_rq(chan);
+ chan->cid = 0;
+ }
+
+ /* deactivate connection (not by idle timer) */
+ cm__deactivate_conn(cm, 0);
+ break;
+ }
+
+ return(CM_E_SUCC);
+}
+
+/* initiate a connection waiting for activation */
+INT
+cm__initiate_conn(CM *cm)
+{
+ ULONG n;
+
+ D_LOG(D_ENTRY, ("cm__initiate_conn: entry, cm: 0x%p", cm));
+
+ /* if connection is nailed, handle here */
+ if ( cm->dprof.nailed )
+ return(cm__activate_conn(cm, cm->dprof.HWCompression));
+
+ /* if here, connection is on demand, initate call setup on all chans */
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++)
+ {
+ CM_CHAN *chan = cm->dprof.chan_tbl + n;
+ USHORT my_cid = MAKEWORD(chan->num, cm->local_conn_index);
+
+ chan->cid = my_cid;
+ chan->ustate = CM_US_WAIT_CID;
+ chan->timeout = ut_time_now();
+
+
+ cm__est_rq(chan);
+
+ }
+
+ return(CM_E_SUCC);
+}
+
+/* activate a connection */
+INT
+cm__activate_conn(CM *cm, ULONG CompressionFlag)
+{
+ ULONG n;
+
+ D_LOG(D_ENTRY, ("cm__activate_conn: entry, cm: 0x%p", cm));
+
+ /* mark change of state & time */
+ cm->state = CM_ST_ACTIVE;
+ cm->StateChangeFlag = TRUE;
+ cm->rx_last_frame_time = cm->tx_last_frame_time = cm->timeout = ut_time_now();
+
+ /* scan active channel, notify mtl, etc. */
+ cm->active_chan_num = 0;
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++)
+ {
+ CM_CHAN *chan = cm->dprof.chan_tbl + n;
+
+ /* check is channel is used in this connection */
+ if ( chan->gave_up )
+ continue;
+
+ // Give Compression command for this channel
+ cm__bchan_ctrl_comp(chan, CompressionFlag);
+
+ /* turn channel on (may be redundant in demand connections */
+ cm__bchan_ctrl(chan, 1);
+
+ /* notify mtl of channel */
+ mtl_add_chan(cm->mtl,
+ chan->idd,
+ chan->bchan,
+ chan->speed,
+ cm->ConnectionType);
+
+ /* accumulate */
+ cm->active_chan_num++;
+ }
+
+
+ /* get speed from mtl, tell mtl is connected now! */
+ mtl_get_conn_speed(cm->mtl, &cm->speed);
+
+ return(CM_E_SUCC);
+}
+
+/* deactivate a connection */
+INT
+cm__deactivate_conn(CM *cm, BOOL by_idle_timer)
+{
+ ULONG n;
+
+ D_LOG(D_ENTRY, ("cm__deactivate_conn: entry, cm: 0x%p", cm));
+
+// DbgPrint ("DeactivateConn\n");
+ /* mark change of state & time */
+ cm->state = CM_ST_DEACT;
+ cm->StateChangeFlag = TRUE;
+ cm->rx_last_frame_time = cm->tx_last_frame_time = cm->timeout = ut_time_now();
+
+ /* tell mtl not connected now */
+ mtl_set_conn_state(cm->mtl, cm->dprof.chan_num, 0);
+
+ /* scan active channel, notify mtl, etc. */
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++)
+ {
+ CM_CHAN *chan = cm->dprof.chan_tbl + n;
+
+ /* check is channel is used in this connection */
+ if ( chan->gave_up )
+ continue;
+
+ /* turn channel off */
+ cm__bchan_ctrl(chan, 0);
+
+ /* notify mtl of channel */
+ mtl_del_chan(cm->mtl, chan->idd, chan->bchan);
+
+ /* clear channel state */
+ chan->ustate = 0;
+ chan->active = 0;
+ }
+
+ /* if connection originated as listening, back to idle here */
+ if ( cm->was_listen )
+ {
+ make_idle:
+ cm->state = CM_ST_IDLE;
+ cm->StateChangeFlag = TRUE;
+ return(CM_E_SUCC);
+ }
+
+ /* if connection is not persistant, back to idle */
+ if ( !cm->dprof.persist )
+ goto make_idle;
+
+ /* if deactivate not by idle timer, back to idle */
+ if ( !by_idle_timer )
+ goto make_idle;
+
+ /* if here, connection reverts to waiting for activation */
+ cm->state = CM_ST_WAIT_ACT;
+ cm->StateChangeFlag = TRUE;
+ return(CM_E_SUCC);
+}
+
+/* calc next channel, not implemented yet */
+INT
+cm__get_next_chan(CM_CHAN *chan)
+{
+ CM *cm = (CM*)chan->cm;
+
+ /* restore modified fields */
+ chan->bchan = cm->oprof.chan_tbl[chan->num].bchan;
+
+ /* step to next channel type */
+ switch ( chan->type )
+ {
+ case CM_CT_D64 :
+ chan->type = CM_CT_D56;
+ break;
+
+ case CM_CT_D56 :
+ chan->type = CM_CT_VOICE;
+ break;
+
+ case CM_CT_VOICE :
+ default:
+ return(CM_E_NOSUCH);
+ }
+
+ /* if here, succ */
+ return(CM_E_SUCC);
+}
+
+
diff --git a/private/ntos/ndis/pcimac/cm_init.c b/private/ntos/ndis/pcimac/cm_init.c
new file mode 100644
index 000000000..79ae7fe81
--- /dev/null
+++ b/private/ntos/ndis/pcimac/cm_init.c
@@ -0,0 +1,489 @@
+/*
+ * CM_INIT.H - initialization code for CM objects
+ */
+
+#include <ndis.h>
+//#include <ndismini.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+#include <trc.h>
+#include <io.h>
+#include <tapioid.h>
+
+/* local data structures */
+typedef struct
+{
+ VOID *idd;
+ USHORT lterm;
+ USHORT cid;
+ CM_CHAN *chan;
+} CM_FIND_CHAN;
+
+typedef struct
+{
+ VOID *idd;
+ USHORT bchan;
+ CM_CHAN *chan;
+} CM_FIND_BCHAN;
+
+/* local connection table */
+CM *cm_tbl[MAX_CM_IN_SYSTEM]; /* table of connection managers */
+BOOL cm_used[MAX_CM_IN_SYSTEM]; /* flags for used cm's */
+BOOL cm_terminated = FALSE;
+
+BOOL cm__find_chan(CM_CHAN* chan, CM_FIND_CHAN *fc, VOID* a2);
+BOOL cm__find_bchan(CM_CHAN* chan, CM_FIND_BCHAN *fc, VOID* a2);
+BOOL cm__match_str(CHAR* s1, CHAR* s2);
+
+/* driver global vars */
+extern DRIVER_BLOCK Pcimac;
+
+//
+// added to support the new switch styles
+//
+ULONG SwitchStyle = CM_SWITCHSTYLE_NONE;
+
+
+ULONG
+EnumCmInSystem()
+{
+ ULONG n;
+
+ for (n = 0; n < MAX_CM_IN_SYSTEM; n++)
+ {
+ if (cm_tbl[n] == NULL)
+ break;
+ }
+ return(n);
+}
+
+ULONG
+EnumCmPerAdapter(
+ ADAPTER *Adapter
+ )
+{
+ ULONG n;
+
+ for (n = 0; n < MAX_CM_PER_ADAPTER; n++)
+ {
+ if (Adapter->CmTbl[n] == NULL)
+ break;
+ }
+ return(n);
+}
+
+INT
+IoEnumCm(IO_CMD *cmd)
+{
+ ULONG n;
+
+ cmd->val.enum_cm.num = (USHORT)EnumCmInSystem();
+
+ for (n = 0; n < cmd->val.enum_cm.num; n++)
+ {
+ CM *cm = cm_tbl[n];
+
+ strcpy(cmd->val.enum_cm.name[n], cm->name);
+ cmd->val.enum_cm.tbl[n] = cm;
+ }
+
+ return(0);
+}
+
+VOID*
+CmGetMtl(
+ VOID *cm_1
+ )
+{
+ CM *cm = (CM*)cm_1;
+
+ return(cm->mtl);
+}
+
+
+//
+// added to support the new switch styles
+//
+VOID
+CmSetSwitchStyle(CHAR *StyleName)
+{
+ if (!strcmp(StyleName, "ni1"))
+ SwitchStyle = CM_SWITCHSTYLE_NI1;
+ else if (!strcmp(StyleName, "att"))
+ SwitchStyle = CM_SWITCHSTYLE_ATT;
+ else if (!strcmp(StyleName, "nti"))
+ SwitchStyle = CM_SWITCHSTYLE_NTI;
+ else if (!strcmp(StyleName, "net3"))
+ SwitchStyle = CM_SWITCHSTYLE_NET3;
+ else if (!strcmp(StyleName, "1tr6"))
+ SwitchStyle = CM_SWITCHSTYLE_1TR6;
+ else if (!strcmp(StyleName, "vn3"))
+ SwitchStyle = CM_SWITCHSTYLE_VN3;
+ else if (!strcmp(StyleName, "ins64"))
+ SwitchStyle = CM_SWITCHSTYLE_INS64;
+ else
+ SwitchStyle = CM_SWITCHSTYLE_NONE;
+}
+
+#pragma NDIS_INIT_FUNCTION(cm_init)
+
+/* initialize cm class */
+INT
+cm_init(VOID)
+{
+ NDIS_PHYSICAL_ADDRESS pa = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
+ D_LOG(D_ENTRY, ("cm_init: entry"));
+
+ NdisZeroMemory(cm_tbl, sizeof(cm_tbl));
+ NdisZeroMemory(cm_used, sizeof(cm_used));
+
+ ChannelInit();
+
+ return(CM_E_SUCC);
+}
+
+/* terminate cm class */
+cm_term()
+{
+ D_LOG(D_ENTRY, ("cm_term: entry"));
+
+ cm_terminated = TRUE;
+
+ // Release Channel Table
+ ChannelTerm();
+
+ return(CM_E_SUCC);
+}
+
+/* register an available idd */
+cm_register_idd(VOID *idd)
+{
+ D_LOG(D_ENTRY, ("cm_register_idd: entry, idd: 0x%p", idd));
+
+ /* add handles to idd cm/bchan receivers (cm1 may failed!) */
+ idd_attach(idd, IDD_PORT_CM0_RX, (VOID*)cm__q931_handler, idd);
+ idd_attach(idd, IDD_PORT_CM1_RX, (VOID*)cm__q931_handler, idd);
+ idd_attach(idd, IDD_PORT_B1_RX, (VOID*)cm__q931_bchan_handler, idd);
+ idd_attach(idd, IDD_PORT_B2_RX, (VOID*)cm__q931_bchan_handler, idd);
+
+ /* ask idp cm to deliver elements */
+ cm__elem_rq(idd, IDD_PORT_CM0_TX, "\x08\x34\x18", 3);
+ cm__elem_rq(idd, IDD_PORT_CM1_TX, "\x08\x34\x18", 3);
+
+ return(CM_E_SUCC);
+}
+
+/* deregister an available idd */
+cm_deregister_idd(VOID *idd)
+{
+ D_LOG(D_ENTRY, ("cm_deregister_idd: entry, idd: 0x%p", idd));
+
+ /* remove handle from idd cm receivers */
+ idd_detach(idd, IDD_PORT_CM0_RX, (VOID*)cm__q931_handler, idd);
+ idd_detach(idd, IDD_PORT_CM1_RX, (VOID*)cm__q931_handler, idd);
+ idd_detach(idd, IDD_PORT_B1_RX, (VOID*)cm__q931_bchan_handler, idd);
+ idd_detach(idd, IDD_PORT_B2_RX, (VOID*)cm__q931_bchan_handler, idd);
+
+ return(CM_E_SUCC);
+}
+
+#pragma NDIS_INIT_FUNCTION(cm_create)
+
+/* create a new cm object */
+cm_create(VOID **ret_cm, NDIS_HANDLE AdapterHandle)
+{
+ NDIS_PHYSICAL_ADDRESS pa = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
+ INT n;
+
+ D_LOG(D_ENTRY, ("cm_create: entry, ret_cm: 0x%p", ret_cm));
+
+ /* allocate memory object */
+ NdisAllocateMemory((PVOID*)ret_cm, sizeof(CM), 0, pa);
+ if ( *ret_cm == NULL )
+ {
+ D_LOG(D_ALWAYS, ("cm_create: memory allocate failed!"));
+ NdisWriteErrorLogEntry (AdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0);
+ return(CM_E_NOMEM);
+ }
+ D_LOG(D_ALWAYS, ("cm_create: cm: 0x%x", *ret_cm));
+ NdisZeroMemory(*ret_cm, sizeof(CM));
+
+ /* allocate connection out of local table */
+ for ( n = 0 ; n < MAX_CM_IN_SYSTEM ; n++ )
+ if ( !cm_used[n] )
+ break;
+ if ( n >= MAX_CM_IN_SYSTEM )
+ {
+ /* free memory */
+ NdisFreeMemory(*ret_cm, sizeof(CM), 0);
+ return(CM_E_NOSLOT);
+ }
+
+
+ /* initialize */
+ cm_used[n] = 1;
+ cm_tbl[n] = *ret_cm;
+ ((CM*)*ret_cm)->local_conn_index = n;
+
+ /* return */
+ return(CM_E_SUCC);
+}
+
+/* destory a cm object */
+cm_destroy(VOID *cm_1)
+{
+ CM* cm = (CM*)cm_1;
+ D_LOG(D_ENTRY, ("cm_destory: entry, cm: 0x%p", cm));
+
+ cm_used[cm->local_conn_index] = 0;
+ cm_tbl[cm->local_conn_index] = NULL;
+
+ //
+ // disconnect this connection object
+ //
+ cm_disconnect (cm);
+
+// added for dynamic allocation of cm
+ /* free memory */
+ NdisFreeMemory(cm, sizeof(*cm), 0);
+
+ return(CM_E_SUCC);
+}
+
+/* find a channel from an <idd,lterm,cid> */
+CM_CHAN*
+cm__map_chan(VOID* idd, USHORT lterm, USHORT cid)
+{
+ CM *cm;
+ CM_CHAN *chan;
+ ULONG n, m;
+ CM_FIND_CHAN fc;
+
+ D_LOG(D_ENTRY, ("cm__map_chan: entry: idd: 0x%p, lterm: 0x%x, cid: 0x%p", idd,lterm,cid));
+
+ /* scan incoming channel table first */
+ fc.idd = idd;
+ fc.lterm = lterm;
+ fc.cid = cid;
+ fc.chan = NULL;
+ cm__chan_foreach(cm__find_chan, &fc, NULL);
+ if ( fc.chan )
+ return(fc.chan);
+
+ /* scan connection table */
+ for ( n = 0; n < MAX_CM_IN_SYSTEM ; n++)
+ if ( cm_used[n] )
+ {
+ cm = cm_tbl[n];
+ switch ( cm->state )
+ {
+ case CM_ST_IN_ACT :
+ case CM_ST_IN_SYNC :
+ case CM_ST_ACTIVE :
+ case CM_ST_IN_ANS :
+ for ( m = 0, chan = cm->dprof.chan_tbl ;
+ m < cm->dprof.chan_num ; m++, chan++ )
+ if ( (idd == chan->idd) &&
+ (lterm == chan->lterm) &&
+ (cid == chan->cid) )
+ return(chan);
+ break;
+ }
+ }
+
+ /* if here, failed! */
+ return(NULL);
+}
+
+/* find a bchannel from an <idd,bchan> */
+CM_CHAN*
+cm__map_bchan_chan(VOID *idd, USHORT bchan)
+{
+ CM *cm;
+ CM_CHAN *chan;
+ ULONG n, m;
+ CM_FIND_BCHAN fc;
+
+ D_LOG(D_ENTRY, ("cm__map_bchan_chan: idd: 0x%p, bchan: 0x%x", \
+ idd,bchan));
+
+ /* scan incoming channel table first */
+ fc.idd = idd;
+ fc.bchan = bchan;
+ fc.chan = NULL;
+ cm__chan_foreach(cm__find_bchan, &fc, NULL);
+ if ( fc.chan )
+ return(fc.chan);
+
+ /* scan connection table */
+ for ( n = 0; n < MAX_CM_IN_SYSTEM ; n++)
+ if ( cm_used[n] )
+ {
+ cm = cm_tbl[n];
+ switch ( cm->state )
+ {
+ case CM_ST_IN_ACT :
+ case CM_ST_IN_SYNC :
+ case CM_ST_ACTIVE :
+ case CM_ST_IN_ANS :
+ for ( m = 0, chan = cm->dprof.chan_tbl ;
+ m < cm->dprof.chan_num ; m++, chan++ )
+ if ( (idd == chan->idd) &&
+ (bchan == chan->bchan) &&
+ (chan->ustate >= 10) )
+ return(chan);
+ break;
+ }
+ }
+
+ /* if here, failed! */
+ return(NULL);
+}
+
+/* return connection by index */
+CM*
+cm__get_conn(ULONG index)
+{
+ /* check range */
+ if ( index >= MAX_CM_IN_SYSTEM )
+ return(NULL);
+
+ /* check used */
+ if ( !cm_used[index] )
+ return(NULL);
+
+ /* return it */
+ return(cm_tbl[index]);
+}
+
+/* find a matching listening connection */
+CM*
+cm__find_listen_conn(CHAR *lname, CHAR *rname, CHAR *addr, VOID *Idd)
+{
+ CM *cm;
+ ULONG n;
+
+ D_LOG(D_ENTRY, ("cm__find_listen_conn: entry, lname: [%s], rname: [%s], addr: [%s]", \
+ lname, rname, addr));
+
+ /* scan connection table */
+ for ( n = 0; n < MAX_CM_IN_SYSTEM ; n++)
+ {
+ cm = cm_tbl[n];
+ if ( cm_used[n] && (cm->idd == Idd) && (cm->state == CM_ST_LISTEN) )
+ {
+ D_LOG(D_ENTRY, ("cm__find_listen_conn: comparing to: name: [%s], remote_name: [%s]", \
+ cm->dprof.name, cm->dprof.remote_name));
+ if ( cm__match_str(cm->dprof.name, rname) &&
+ cm__match_str(cm->dprof.remote_name, lname) )
+ return(cm);
+ }
+ }
+
+ return(NULL);
+}
+
+/* 1 second timer tick, poll active cm's */
+VOID
+CmPollFunction(VOID *a1, ADAPTER *Adapter, VOID *a3, VOID *a4)
+{
+ ULONG n;
+
+ /* if terminated, ignore */
+ if ( cm_terminated )
+ return;
+
+ /* poll active cm's */
+ for ( n = 0; n < MAX_CM_PER_ADAPTER ; n++)
+ {
+ CM *cm = Adapter->CmTbl[n];
+
+ if (cm)
+ {
+ cm__timer_tick(cm);
+ if (cm->PrevState != cm->state || cm->StateChangeFlag == TRUE)
+ {
+ cm->PrevState = cm->state;
+ cm->StateChangeFlag = FALSE;
+ DoTapiStateCheck(cm);
+ }
+ }
+ }
+
+ /* rearm timer */
+ NdisMSetTimer(&Adapter->CmPollTimer, CM_POLL_T);
+}
+
+/* assist routine for finding a channel. stop scan when found */
+BOOL
+cm__find_chan(CM_CHAN *chan, CM_FIND_CHAN *fc, VOID *a2)
+{
+ if ( (chan->idd == fc->idd) && (chan->lterm == fc->lterm) &&
+ (chan->cid == fc->cid) )
+ {
+ fc->chan = chan;
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+/* assist routine for finding a channel by bchan. stop scan when found */
+BOOL
+cm__find_bchan(CM_CHAN *chan, CM_FIND_BCHAN *fc, VOID *a2)
+{
+ if ( (chan->idd == fc->idd) && (chan->bchan == fc->bchan) )
+ {
+ fc->chan = chan;
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+/* match two strings. allow for wild characters */
+BOOL
+cm__match_str(CHAR *s1, CHAR *s2)
+{
+ /* march on strings, process wild characters '*' and '?' */
+ for ( ; *s1 && *s2 ; s1++, s2++ )
+ if ( (*s1 == '*') || (*s2 == '*') )
+ return(TRUE);
+ else if ( (*s1 == '?') || (*s2 == '?') )
+ continue;
+ else if ( *s1 != *s2 )
+ return(FALSE);
+
+ /* if here, atleast one string ended, other must end here */
+ return( (*s1 | *s2) ? FALSE : TRUE );
+}
+
+UCHAR*
+GetDstAddr(
+ VOID *cm_1
+ )
+{
+ CM *cm = (CM*)cm_1;
+
+ return(&cm->DstAddr[0]);
+}
+
+UCHAR*
+GetSrcAddr(
+ VOID *cm_1
+ )
+{
+ CM *cm = (CM*)cm_1;
+
+ return(&cm->SrcAddr[0]);
+}
diff --git a/private/ntos/ndis/pcimac/cm_prof.c b/private/ntos/ndis/pcimac/cm_prof.c
new file mode 100644
index 000000000..f8c1e4432
--- /dev/null
+++ b/private/ntos/ndis/pcimac/cm_prof.c
@@ -0,0 +1,52 @@
+/*
+ * CM_PROF.C - profile related code
+ */
+
+#include <ndis.h>
+//#include <ndismini.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+
+/* set profile in cm */
+INT
+cm_set_profile(VOID *cm_1, CM_PROF *prof)
+{
+ CM *cm = (CM*)cm_1;
+ D_LOG(D_ENTRY, ("cm_set_prof: entry, cm: 0x%p, prof: 0x%p", cm, prof));
+
+ /* connection must be idle to change profile! */
+ if ( cm->state != CM_ST_IDLE )
+ return(CM_E_BUSY);
+
+ /* set & return */
+ cm->oprof = *prof;
+
+ return(CM_E_SUCC);
+}
+
+/* get profile from cm */
+INT
+cm_get_profile(VOID *cm_1, CM_PROF *prof)
+{
+ CM *cm = (CM*)cm_1;
+ D_LOG(D_ENTRY, ("cm_get_prof: entry, cm: 0x%p, prof: 0x%p", cm, prof));
+
+ /* connection must has a profile */
+ if ( !cm->oprof.name[0] )
+ return(CM_E_NOSUCH);
+
+ /* set & return */
+ *prof = cm->dprof;
+
+ return(CM_E_SUCC);
+}
+
+
diff --git a/private/ntos/ndis/pcimac/cm_pub.h b/private/ntos/ndis/pcimac/cm_pub.h
new file mode 100644
index 000000000..a58af5eb0
--- /dev/null
+++ b/private/ntos/ndis/pcimac/cm_pub.h
@@ -0,0 +1,134 @@
+/*
+ * CM_PUB.H - definitions for connection manager
+ */
+
+#ifndef _CM_PUB_
+#define _CM_PUB_
+
+//
+// global cm def's
+//
+/* a channel descriptor */
+typedef struct
+{
+ VOID* idd; /* related idd */
+ USHORT lterm; /* logical terminal in idd */
+ CHAR addr[32]; /* address to used - phone no. */
+
+ USHORT bchan; /* related b channel */
+#define CM_BCHAN_B1 0 /* - b1 */
+#define CM_BCHAN_B2 1 /* - b2 */
+#define CM_BCHAN_ANY 2 /* - any */
+#define CM_BCHAN_NONE 3 /* - no bchannel related */
+#define CM_BCHAN_ASSIGNED(_b) \
+ ((_b) < 3) /* check for 'assigned' b channel */
+
+ USHORT type; /* channel type */
+#define CM_CT_D64 0 /* - digital 64 kbps */
+#define CM_CT_D56 1 /* - digital 56 kbps */
+#define CM_CT_VOICE 2 /* - digital voice/56 kbps */
+ ULONG speed; /* channel speed, in bps */
+
+ USHORT ustate; /* ustate (q.931) of channel */
+ USHORT cid; /* connection id, idp allocated */
+
+ USHORT num; /* channel number within connection */
+ VOID *cm; /* related connection manager */
+
+ UCHAR DstAddr[6]; /* ethernet address of remote side */
+ UCHAR remote_conn_index; /* connection # of remote connection */
+
+ ULONG timeout; /* used for dead-man timeouts */
+
+ BOOL active; /* channel is active? */
+ BOOL gave_up; /* gave-up on channel? */
+
+ ULONG flag; /* general purpose flag */
+} CM_CHAN;
+
+/* a profile descriptor */
+typedef struct
+{
+ BOOL nailed; /* nailed/demand access */
+ BOOL persist; /* connection persistance */
+ BOOL permanent; /* connection is permanent? */
+ BOOL frame_activated; /* connection activate by frame? */
+ BOOL fallback; /* fallback on channels */
+ BOOL HWCompression; // Compression negotiation on/off
+
+ ULONG rx_idle_timer; /* idle timer for rx side */
+ ULONG tx_idle_timer; /* idle timer for tx side */
+
+ USHORT chan_num; /* # of channels requested */
+ CM_CHAN chan_tbl[MAX_CHAN_PER_CONN]; /* requested channel descriptor */
+
+ CHAR name[32]; /* name of this profile */
+ CHAR remote_name[32]; /* name of remote profile */
+} CM_PROF;
+
+/* connection status descriptor */
+typedef struct _CM
+{
+ CHAR name[64]; /* name for this object */
+
+ CHAR LocalAddress[32]; /* address in format NetCard#-Line#-EndPoint */
+
+ USHORT state; /* connection state */
+#define CM_ST_IDLE 0 /* - idle */
+#define CM_ST_WAIT_ACT 1 /* - waiting for frame activation */
+#define CM_ST_IN_ACT 2 /* - in activation */
+#define CM_ST_IN_SYNC 3 /* - in syncronization */
+#define CM_ST_ACTIVE 4 /* - connection is active! */
+#define CM_ST_LISTEN 5 /* - is listening */
+#define CM_ST_IN_ANS 6 /* - in answering process */
+#define CM_ST_DEACT 7 /* - in deactivation process */
+
+ USHORT PrevState; /* used to track event signal states */
+ USHORT StateChangeFlag; /* used to signal state changes */
+
+ CM_PROF dprof; /* related profile - dynamic copy */
+ CM_PROF oprof; /* related profile - original copy */
+
+ BOOL was_listen; /* connection started as a listener? */
+ ULONG active_chan_num; /* # of active channels */
+ ULONG speed; /* connection speed, bps */
+ ULONG ConnectionType; /* 0/1 - ppp/dkf */
+
+ ULONG rx_last_frame_time; /* last time rx frame recorded */
+ ULONG tx_last_frame_time; /* last time tx frame recorded */
+
+ UCHAR local_conn_index; /* local connection # */
+ UCHAR SrcAddr[6]; /* local side ethernet address */
+
+ UCHAR remote_conn_index; /* remote side connection # */
+ UCHAR DstAddr[6]; /* remote side ethernet address */
+ CHAR remote_name[32]; /* name of remote profile */
+
+ ULONG timeout; /* dead-man timeout */
+
+ VOID *mtl; /* related mtl, internal */
+ VOID *idd; /* related idd */
+ VOID *Adapter; /* related adapter, internal */
+
+ VOID *TapiLineInfo; // back pointer to owning line
+
+ NDIS_HANDLE LinkHandle; // assigned during lineup
+
+ ULONG htCall; // tapi's handle to the call
+
+ ULONG TapiCallState; // tapi's call state
+
+ ULONG CallState; // our call state
+
+ ULONG AppSpecific; // app specific storage
+
+ UCHAR CauseValue; // Cause Value in Disc or Rel Messages
+ UCHAR SignalValue; // Signal Value in CallProc or CallProg Messages
+ UCHAR CalledAddress[32]; // Address that was called
+ UCHAR CallingAddress[32]; // Address of caller
+ ULONG PPPToDKF; // Flag to signal a change from PPP to DKF
+ ULONG NoActiveLine; // Flag to indicate when no line is detected
+} CM_STATUS, CM;
+
+#endif /* _CM_PUB_ */
+
diff --git a/private/ntos/ndis/pcimac/cm_q931.c b/private/ntos/ndis/pcimac/cm_q931.c
new file mode 100644
index 000000000..4bd3ef014
--- /dev/null
+++ b/private/ntos/ndis/pcimac/cm_q931.c
@@ -0,0 +1,950 @@
+/*
+ * CM_Q931.C - q931 handling module. mainly outgoing side
+ */
+
+#include <ndis.h>
+//#include <ndismini.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+
+extern ULONG SwitchStyle;
+
+/* local assist, copy data into buffer & advance pointer */
+#define adv_ptr(_p, _buf, _len) \
+ { \
+ NdisMoveMemory((_p), _buf, _len); \
+ (_p) += _len; \
+ }
+
+/* format an establish request */
+INT
+cm__est_rq(CM_CHAN *chan)
+{
+ IDD_MSG msg;
+ UCHAR *p;
+
+ D_LOG(D_ENTRY, ("cm__est_rq: entry, chan: 0x%p", chan));
+
+ /* clear outgoing message */
+ NdisZeroMemory(&msg, sizeof(msg));
+
+ /* allocate a local buffer */
+ if ( !(msg.bufptr = p = ut_get_buf()) )
+ goto give_up;
+
+ //
+ // added to support the new switch styles
+ // TB 03/14
+ //
+ if (SwitchStyle != CM_SWITCHSTYLE_1TR6)
+ {
+ /* build bearer capabilities element */
+ switch ( chan->type )
+ {
+ case CM_CT_VOICE :
+ adv_ptr(p, ((SwitchStyle == CM_SWITCHSTYLE_NET3) ?
+ "\x04\x03\x80\x90\xA3" :
+ "\x04\x03\x80\x90\xA2"), 5);
+ chan->speed = 56000;
+ break;
+
+//
+// changed to make 56K Data calls in Europe get established with a bearer
+// capability of 64K Data (8 bits) but we will actually do
+// 56K Data (7 bits) on the line
+// TB 09/20
+//
+// case CM_CT_D56 :
+// adv_ptr(p, "\x04\x04\x88\x90\x21\x8F", 6);
+// chan->speed = 56000;
+// break;
+//
+ case CM_CT_D56 :
+ if (SwitchStyle == CM_SWITCHSTYLE_NET3)
+ {
+ adv_ptr(p, "\x04\x02\x88\x90", 4);
+ }
+ else
+ {
+ adv_ptr(p, "\x04\x04\x88\x90\x21\x8F", 6);
+ }
+
+ chan->speed = 56000;
+ break;
+
+ default :
+ case CM_CT_D64 :
+ adv_ptr(p, "\x04\x02\x88\x90", 4);
+ chan->speed = 64000;
+ break;
+ }
+ }
+
+ /* channel id element */
+ switch ( chan->bchan )
+ {
+ case CM_BCHAN_B1 : adv_ptr(p, "\x18\x01\x89", 3);
+ break;
+ case CM_BCHAN_B2 : adv_ptr(p, "\x18\x01\x8A", 3);
+ break;
+ default :
+ case CM_BCHAN_ANY : adv_ptr(p, "\x18\x01\x83", 3);
+ break;
+ }
+
+ //
+ // added to support the new switch styles
+ // TB 03/14
+ //
+ if (SwitchStyle != CM_SWITCHSTYLE_1TR6
+ && SwitchStyle != CM_SWITCHSTYLE_NET3)
+ {
+ /* called number/address */
+ *p++ = 0x2C;
+ *p++ = strlen(chan->addr);
+ adv_ptr(p, chan->addr, p[-1]);
+ }
+ else
+ {
+ //
+ // added to support the new switch styles
+ // TB 03/14
+ //
+ *p++ = 0x70;
+ *p++ = strlen(chan->addr) + 1;
+ *p++ = (SwitchStyle == CM_SWITCHSTYLE_1TR6) ? 0x81 : 0x80;
+ adv_ptr(p, chan->addr, strlen(chan->addr));
+ }
+
+ //
+ // added for net3 fix
+ // TB 04/13
+ //
+ if (SwitchStyle == CM_SWITCHSTYLE_NET3)
+ *p++ = 0xA1; // Sending Complete
+
+ //
+ // added to support the new switch styles
+ // TB 03/14
+ //
+ if (SwitchStyle == CM_SWITCHSTYLE_1TR6)
+ {
+ *p++ = 0x96;
+ *p++ = 0x01;
+ switch (chan->type)
+ {
+ case CM_CT_VOICE:
+ adv_ptr(p, "\x02\x01\x01", 3);
+ break;
+
+ case CM_CT_D56:
+ case CM_CT_D64:
+ default:
+ adv_ptr(p, "\x02\x07\x00", 3);
+ break;
+ }
+ }
+
+ /* fillin message structure */
+ msg.opcode = Q931_EST_RQ;
+ msg.buflen = p - msg.bufptr;
+ msg.bufid = MAKELONG(chan->cid, 0);
+ chan->cid = 0;
+
+ /* send to idd */
+ if ( idd_send_msg(chan->idd, &msg, (USHORT)CM_PORT(chan),
+ (VOID*)cm__q931_cmpl_handler, chan) != IDD_E_SUCC )
+ {
+ /* failed, give up on channel */
+ give_up:
+ chan->gave_up = 1;
+ ut_free_buf(msg.bufptr);
+ return(CM_E_IDD);
+ }
+
+ D_LOG(D_EXIT, ("cm__est_rq: exit"));
+ return(CM_E_SUCC);
+}
+
+/* format an establish response */
+INT
+cm__est_rsp(CM_CHAN *chan)
+{
+ IDD_MSG msg;
+
+ D_LOG(D_ENTRY, ("cm__est_rsp: entry, chan: 0x%p", chan));
+
+ /* clear outgoing message */
+ NdisZeroMemory(&msg, sizeof(msg));
+
+ /* fillin message structure */
+ msg.opcode = Q931_EST_RSP;
+ msg.bufid = MAKELONG(0, chan->cid);
+ msg.bufptr = ut_get_buf();
+ msg.buflen = 0;
+
+
+ /* send to idd */
+ if (idd_send_msg(chan->idd, &msg, (USHORT)CM_PORT(chan), (VOID*)cm__q931_cmpl_handler, NULL) != IDD_E_SUCC)
+ ut_free_buf(msg.bufptr);
+
+ return(CM_E_SUCC);
+}
+
+/* format a call ignore response */
+INT
+cm__est_ignore(
+ PVOID idd,
+ USHORT cid,
+ USHORT lterm)
+{
+ IDD_MSG msg;
+
+ D_LOG(D_ENTRY, ("cm__est_ignore: entry, idd: 0x%p, cid: 0x%x, lterm: 0x%x", idd, cid, lterm));
+
+ /* clear outgoing message */
+ NdisZeroMemory(&msg, sizeof(msg));
+
+ /* fillin message structure */
+ msg.opcode = Q931_EST_IGNORE;
+ msg.bufid = MAKELONG(0, cid);
+ msg.bufptr = ut_get_buf();
+ msg.buflen = 0;
+
+
+ /* send to idd */
+ if (idd_send_msg(idd, &msg, (USHORT)(lterm + IDD_PORT_CM0_TX), (VOID*)cm__q931_cmpl_handler, NULL) != IDD_E_SUCC)
+ ut_free_buf(msg.bufptr);
+
+ return(CM_E_SUCC);
+}
+
+/* format a disconenct request */
+INT
+cm__disc_rq(CM_CHAN *chan)
+{
+ IDD_MSG msg;
+
+ D_LOG(D_ENTRY, ("cm__disc_rq: entry, chan: 0x%p", chan));
+
+ /* clear outgoing message */
+ NdisZeroMemory(&msg, sizeof(msg));
+
+ /* fillin message structure */
+ msg.opcode = Q931_REL_RQ;
+ msg.bufid = MAKELONG(0, chan->cid);
+ msg.bufptr = ut_get_buf();
+ msg.buflen = 0;
+
+ /* send to idd */
+ if (idd_send_msg(chan->idd, &msg, (USHORT)CM_PORT(chan), (VOID*)cm__q931_cmpl_handler, NULL) != IDD_E_SUCC)
+ ut_free_buf(msg.bufptr);
+
+
+ /* turn off channel */
+ cm__bchan_ctrl(chan, 0);
+ return(CM_E_SUCC);
+}
+
+/* control data transfer on a bchannel */
+INT
+cm__bchan_ctrl(CM_CHAN *chan, BOOL turn_on)
+{
+ USHORT is_ans, subchan, op;
+ IDD_MSG msg;
+ CM *cm = chan->cm;
+ ULONG IddFramingType = IDD_FRAME_DETECT;
+
+ D_LOG(D_ENTRY, ("cm__bchan_ctrl: entry, chan: 0x%p, state: %d", \
+ chan, turn_on));
+
+ //
+ // check for a redundant operation
+ //
+ if ((!chan->active && !turn_on) ||
+ (chan->active && turn_on))
+ return(CM_E_SUCC);
+
+ /* channel must be assigned */
+ if ( !CM_BCHAN_ASSIGNED(chan->bchan) )
+ return(CM_E_BADCHAN);
+
+ /* find out if on answering side */
+ if ( cm )
+ is_ans = cm->was_listen ? 0x0100 : 0x0000;
+ else
+ is_ans = 0x0100;
+
+ /* map channel type to operation */
+ if ( !turn_on )
+ op = CMD_BCHAN_OFF;
+ else
+ {
+ switch ( chan->type )
+ {
+ case CM_CT_VOICE : op = CMD_BCHAN_VOICE; break;
+ case CM_CT_D56 : op = CMD_BCHAN_56; break;
+ default :
+ case CM_CT_D64 : op = CMD_BCHAN_HDLC; break;
+ }
+
+ chan->speed = cm__type2speed(chan->type);
+ }
+
+ /* build subchannel descriptor */
+ subchan = 0x1717;
+
+ /* build msg */
+ NdisZeroMemory(&msg, sizeof(msg));
+ msg.opcode = op;
+ msg.bufid = MAKELONG(is_ans | chan->bchan | (subchan << 1), 0);
+
+ /* send it */
+ idd_send_msg(chan->idd, &msg, IDD_PORT_CMD_TX, NULL, NULL);
+
+ //
+ // Set rx framing mode
+ //
+ // if channel is being turned off
+ //
+ // channel off - rxmode = IDD_FRAME_DONTCARE
+ //
+ if (!turn_on)
+ IddFramingType = IDD_FRAME_DONTCARE;
+
+ IddSetRxFraming(chan->idd, chan->bchan, IddFramingType);
+
+ /* mark channel active state */
+ chan->active = turn_on;
+
+ return(CM_E_SUCC);
+}
+
+
+/* control data transfer on a bchannel */
+INT
+cm__bchan_ctrl_comp(CM_CHAN *chan, ULONG CompressionFlag)
+{
+ IDD_MSG msg;
+ USHORT Enable = 0;
+
+ D_LOG(D_ENTRY, ("cm__bchan_ctrl_comp: entry, chan: 0x%p, state: %d", \
+ chan, CompressionFlag));
+
+ /* channel must be assigned */
+ if ( !CM_BCHAN_ASSIGNED(chan->bchan) )
+ return(CM_E_BADCHAN);
+
+ /* map channel type to operation */
+ if ( CompressionFlag )
+ Enable = COMP_TX_ENA | COMP_RX_ENA;
+
+ /* build msg */
+ NdisZeroMemory(&msg, sizeof(msg));
+ msg.opcode = CMD_COMPRESS;
+ msg.bufid = MAKELONG( chan->bchan | ( Enable << 8 ), 0);
+
+ /* send it */
+ idd_send_msg(chan->idd, &msg, IDD_PORT_CMD_TX, NULL, NULL);
+
+ return(CM_E_SUCC);
+}
+
+
+/* issue an element request to idp cm port */
+INT
+cm__elem_rq(VOID *idd, USHORT port, CHAR *elem_buf, USHORT elem_len)
+{
+ IDD_MSG msg;
+ CHAR *p;
+
+ D_LOG(D_ENTRY, ("cm__elem_rq: entry, idd: 0x%p, port: 0x%d, elem_buf: 0x%p, elem_len: 0x%d", \
+ idd, port, elem_buf, elem_len));
+
+ /* clear outgoing message */
+ NdisZeroMemory(&msg, sizeof(msg));
+
+ /* allocate a local buffer */
+ if ( !(msg.bufptr = p = ut_get_buf()) )
+ return(CM_E_NOMEM);
+
+ /* copy buffer */
+ adv_ptr(p, elem_buf, (INT)elem_len);
+
+ /* fillin message structure */
+ msg.opcode = Q931_ELEM_RQ;
+ msg.buflen = p - msg.bufptr;
+
+ /* send to idd */
+ if ( idd_send_msg(idd, &msg, port,
+ (VOID*)cm__q931_cmpl_handler, NULL) != IDD_E_SUCC )
+ {
+ ut_free_buf(msg.bufptr);
+ return(CM_E_IDD);
+ }
+
+ return(CM_E_SUCC);
+}
+
+/* completion handler for q931 command with attached local buffers */
+VOID
+cm__q931_cmpl_handler(VOID *arg, USHORT port, IDD_MSG *msg)
+{
+ D_LOG(D_ENTRY, ("cm__q931_cmpl_handler: arg: 0x%p, port: 0x%d, msg: 0x%p", \
+ arg, port, msg));
+
+ /* free attached buffer */
+ ut_free_buf(msg->bufptr);
+}
+
+/* handler for q931 events */
+VOID
+cm__q931_handler(IDD *idd, USHORT port, ULONG Reserved, IDD_MSG *msg)
+{
+ USHORT lterm;
+ CM_CHAN *chan;
+ CM *cm;
+ extern BOOL cm_terminated;
+
+ D_LOG(D_ENTRY, ("cm__q931_handler: entry, idd: 0x%p, port: %d, msg: 0x%p", \
+ idd, port, msg));
+ D_LOG(D_ALWAYS, ("cm_q931_handler: msg->opcode: 0x%x", msg->opcode));
+
+ /* ignore if already terminated */
+ if ( cm_terminated )
+ return;
+
+ /* convert port to logical terminal */
+ lterm = port - IDD_PORT_CM0_RX;
+
+ /* try resolving idd/lterm/cid into a channel */
+ if ( chan = cm__map_chan(idd, lterm, HIWORD(msg->bufid)) )
+ cm = chan->cm;
+ else
+ cm = NULL;
+
+ D_LOG(D_ALWAYS, ("cm_q931_handler: chan: 0x%p, cm: 0x%p", chan, cm));
+
+ //
+ // since q.931 stuff touches this so much it is easier to
+ // copy locally then to keep track of adapter memory access
+ //
+ NdisZeroMemory(idd->RxBuffer, sizeof(idd->RxBuffer));
+ IddGetDataFromAdapter(idd,
+ (PUCHAR)idd->RxBuffer,
+ (PUCHAR)msg->bufptr,
+ (USHORT)MIN(IDP_MAX_RX_BUFFER, msg->buflen));
+
+ msg->bufptr = idd->RxBuffer;
+
+ /* switch to message handler */
+ switch ( msg->opcode )
+ {
+ case Q931_EST_IND :
+ cm__ans_est_ind(chan, (IDD_MSG*)msg, idd, lterm);
+ break;
+
+ case Q931_CID_IND :
+ cm__org_cid_ind(chan, (IDD_MSG*)msg);
+ break;
+
+ case Q931_P_STATE_IND:
+ D_LOG(D_ALWAYS, ("cm_q931_handler: ProtocolStateInd"));
+ break;
+
+ case Q931_STATE_IND :
+ if ( !chan || cm )
+ cm__org_state_ind(chan, (IDD_MSG*)msg);
+ else if ( chan )
+ cm__ans_state_ind(chan, (IDD_MSG*)msg);
+ break;
+
+ case Q931_ELEM_IND :
+ if ( cm && !cm->was_listen )
+ cm__org_elem_ind(chan, (IDD_MSG*)msg);
+ break;
+
+ default :
+ break;
+ }
+}
+
+VOID
+cm__ppp_conn(VOID *idd, USHORT port)
+{
+ CM_CHAN *chan;
+ CM *cm;
+ ULONG n, CompressionFlag;
+ IDD_MSG msg1;
+
+ /* try resolving idd/bchan into a channel */
+ if ( !(chan = cm__map_bchan_chan(idd, port)) )
+ return;
+
+ //
+ // if this channel is already connected no need to do this stuff
+ //
+ if (chan->ustate == CM_US_CONN)
+ return;
+
+ //
+ // kill dead man timer for this channel
+ //
+ NdisZeroMemory(&msg1, sizeof(IDD_MSG));
+ msg1.opcode = Q931_CAN_TU10_RQ;
+ msg1.bufptr = ut_get_buf();
+ msg1.buflen = 0;
+ msg1.bufid = MAKELONG(0, chan->cid);
+
+ /* send to idd */
+ if (idd_send_msg(chan->idd, &msg1, (USHORT)CM_PORT(chan), (VOID*)cm__q931_cmpl_handler, NULL) != IDD_E_SUCC)
+ ut_free_buf(msg1.bufptr);
+
+ NdisZeroMemory(chan->DstAddr, sizeof(chan->DstAddr));
+
+ /* last channel, find matching connection/profile */
+ if ( !(cm = cm__find_listen_conn("*", "*", "*", idd)) )
+ {
+ /* none found, reject */
+ D_LOG(D_ALWAYS, ("cm__ppp_con: no listener found"));
+ return;
+ }
+
+ /* matching connection found!, fillin */
+ D_LOG(D_ALWAYS, ("cm__ppp_conn: matching connection: cm: 0x%p", cm));
+
+ chan->remote_conn_index = 1;
+
+ cm->state = CM_ST_IN_ANS;
+ cm->StateChangeFlag = TRUE;
+ cm->was_listen = TRUE;
+ cm->active_chan_num = 1;
+ cm->remote_conn_index = chan->remote_conn_index;
+ cm->ConnectionType = CM_PPP;
+ NdisMoveMemory(cm->DstAddr, chan->DstAddr, 6);
+ NdisZeroMemory(cm->remote_name, sizeof(cm->remote_name));
+
+ cm->timeout = cm->rx_last_frame_time = cm->tx_last_frame_time =
+ ut_time_now();
+
+ /* accept channel here */
+ chan->ustate = CM_US_UUS_OKED;
+ chan->timeout = ut_time_now();
+ chan->cm = cm;
+
+ /* collect channels info local vector */
+ cm->dprof.chan_num = 0;
+ cm__chan_foreach(cm__add_chan, chan, cm);
+
+ /* init channel fields */
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++)
+ {
+ CM_CHAN *chan1 = cm->dprof.chan_tbl + n;
+
+ chan1->ustate = CM_US_CONN;
+ chan1->timeout = ut_time_now();
+ chan1->num = (USHORT)n;
+ chan1->cm = cm;
+ chan1->active = TRUE;
+ }
+
+ /* make connection active */
+ cm->state = CM_ST_ACTIVE;
+ cm->StateChangeFlag = TRUE;
+
+ // Set compression Flag
+ CompressionFlag = 0;
+
+ cm__activate_conn(cm, CompressionFlag);
+
+ return;
+}
+
+
+/* handler for bchannel data */
+VOID
+cm__q931_bchan_handler(
+ IDD *idd,
+ USHORT port,
+ ULONG RxFrameType,
+ IDD_XMSG *msg
+ )
+{
+ CM_CHAN *chan;
+ IDD_MSG msg1;
+ UCHAR DetectBytes[2];
+ extern BOOL cm_terminated;
+
+ D_LOG(D_ENTRY, ("cm__q931_bchan_handler: entry, idd: 0x%p, port: %d, msg: 0x%p", \
+ idd, port, msg));
+
+ /* ignore if terminated */
+ if ( cm_terminated )
+ return;
+
+ //
+ // check to see if this port is servicing DKF or PPP
+ //
+ if (RxFrameType != IDD_FRAME_DKF)
+ return;
+
+ //
+ // see if this is really uus or dror data
+ // if not uus we don't want to do all of the copying that we
+ // would do for uus
+ //
+ IddGetDataFromAdapter(idd,
+ (PUCHAR)&DetectBytes,
+ (PUCHAR)msg->bufptr,
+ 2);
+
+// NdisMoveMemory((PUCHAR)&DetectBytes, (PUCHAR)msg->bufptr, 2 * sizeof(UCHAR));
+
+ if ( (msg->buflen < 4) || DetectBytes[0] != DKF_UUS_SIG || DetectBytes[1])
+ return;
+
+ //
+ // since uus stuff touches this so much it is easier to
+ // copy locally then to keep track of adapter memory access
+ //
+ NdisZeroMemory(idd->RxBuffer, sizeof(idd->RxBuffer));
+ IddGetDataFromAdapter(idd,
+ (PUCHAR)idd->RxBuffer,
+ (PUCHAR)msg->bufptr,
+ (USHORT)MIN(IDP_MAX_RX_BUFFER, msg->buflen));
+
+ msg->bufptr = idd->RxBuffer;
+
+ D_LOG(D_ALWAYS, ("cm__q931_bchan_handler: msg->buflen: 0x%x, DetectByte[0]: 0x%x", \
+ msg->buflen, DetectBytes[0]));
+
+ /* try resolving idd/bchan into a channel */
+ if ( !(chan = cm__map_bchan_chan(idd, port)) )
+ return;
+
+ //
+ // make a copy of the message without the header or
+ // fragmentation flags
+ //
+ NdisMoveMemory(&msg1, msg, sizeof(IDD_MSG));
+ msg1.bufptr += 4;
+ msg1.buflen -= 4;
+
+ /* call handler */
+ if ( chan->cm && !((CM*)(chan->cm))->was_listen )
+ cm__org_data_ind(chan, &msg1);
+ else
+ cm__ans_data_ind(chan, &msg1);
+}
+
+/* transmit a uus packet */
+INT
+cm__tx_uus_pkt(CM_CHAN *chan, UCHAR opcode, UCHAR cause)
+{
+ CHAR *p;
+ IDD_MSG msg;
+ CM_UUS *uus;
+ CM *cm = chan->cm;
+
+ /* must have a channel at this time */
+ if ( !CM_BCHAN_ASSIGNED(chan->bchan) )
+ return(CM_E_BADCHAN);
+
+ /* allocate a buffer for uus */
+ if ( !(p = ut_get_buf()) )
+ return(CM_E_NOMEM);
+
+ /* init messages structure */
+ NdisZeroMemory(&msg, sizeof(msg));
+ msg.bufptr = p;
+ msg.buflen = 4 + CM_UUS_SIZE;
+
+ /* build frame header */
+ *p++ = 0x50;
+ *p++ = 0x00;
+ *p++ = 0x00;
+ *p++ = 0x00;
+ uus = (CM_UUS*)p;
+
+ /* init uus */
+ NdisZeroMemory(uus, sizeof(*uus));
+ NdisMoveMemory(uus->dst_addr, "\xff\xff\xff\xff\xff\xff", 6);
+
+ if ( cm )
+ NdisMoveMemory(uus->src_addr, cm->SrcAddr, sizeof(uus->src_addr));
+ uus->pkt_type = CM_PKT_TYPE;
+ uus->prot_desc = CM_PROT_DESC;
+ uus->opcode = opcode;
+ uus->cause = cause;
+ uus->option_0 = 0;
+
+ if (cm)
+ if (cm->dprof.HWCompression)
+ uus->option_0 = UUS_0_COMPRESSION;
+
+ /* install connection fields */
+ uus->conn = cm ? cm->local_conn_index : 0;
+ uus->channum = cm ? (UCHAR)cm->dprof.chan_num : 0;
+ uus->chan = (UCHAR)chan->num;
+ if ( cm )
+ {
+ NdisMoveMemory(uus->lname, cm->dprof.name, sizeof(uus->lname));
+ NdisMoveMemory(uus->rname, cm->dprof.remote_name, sizeof(uus->rname));
+ cm->tx_last_frame_time = ut_time_now();
+ }
+
+ /* calc chksum */
+ uus->chksum = 256 - cm__calc_chksum(uus, CM_UUS_SIZE);
+
+ /* send message to idd */
+ if ( idd_send_msg(chan->idd, &msg, chan->bchan, (VOID*)cm__q931_cmpl_handler, chan)
+ != IDD_E_SUCC )
+ ut_free_buf(msg.bufptr);
+
+ return(CM_E_SUCC);
+}
+
+/* get channel identification out of q931 element buffer */
+INT
+cm__get_bchan(IDD_MSG *msg, USHORT *bchan)
+{
+ UCHAR *elem;
+
+
+ /* locate channel id element */
+ if ( !(elem = cm__q931_elem(msg->bufptr, msg->buflen, 0x18)) )
+ return(CM_E_NOSUCH);
+ else
+ elem++;
+
+ /* verify length */
+ if ( *elem++ != 0x1 )
+ return(CM_E_NOSUCH);
+
+ /* extract b channel */
+ if ( *elem == 0x89 )
+ *bchan = CM_BCHAN_B1;
+ else if ( *elem == 0x8A )
+ *bchan = CM_BCHAN_B2;
+ else
+ return(CM_E_NOSUCH);
+
+ /* if here, succ */
+ return(CM_E_SUCC);
+}
+
+/* get channel type out of q931 element buffer */
+INT
+cm__get_type(IDD_MSG *msg, USHORT *type)
+{
+ UCHAR *elem, elem_len;
+
+ /* locate type element */
+ if ( !(elem = cm__q931_elem(msg->bufptr, msg->buflen, 0x04)) )
+ return(CM_E_NOSUCH);
+ else
+ elem++;
+ elem_len = *elem++;
+
+ //
+ // added to support the new switch styles
+ // TB 03/14
+ //
+ if (SwitchStyle == CM_SWITCHSTYLE_1TR6)
+ {
+ switch (*elem)
+ {
+ case 0x01:
+ *type = CM_CT_VOICE;
+ return(CM_E_SUCC);
+
+ case 0x07:
+ *type = CM_CT_D64;
+ return(CM_E_SUCC);
+
+ default:
+ return(CM_E_BADPARAM);
+ }
+ }
+
+ /* if information transfer type is speech, -> voice */
+ if ( (*elem++ & 0x1F) == 0 )
+ {
+ *type = CM_CT_VOICE;
+ return(CM_E_SUCC);
+ }
+
+ /* trasnfer mode & type must be 64 */
+ if ( (*elem++ & 0x7F) != 0x10 )
+ return(CM_E_BADPARAM);
+
+ /* if end of element here, must be 64 */
+ if ( elem_len == 2 )
+ {
+ *type = CM_CT_D64;
+ return(CM_E_SUCC);
+ }
+
+ /* check for 56 */
+ if ( (elem_len >= 4) &&
+ ((*elem++ & 0x7F) == 0x21) &&
+ ((*elem++ & 0x7F) == 0x0F) )
+ {
+ *type = CM_CT_D56;
+ return(CM_E_SUCC);
+ }
+
+ /* if here, unknown */
+ return(CM_E_BADPARAM);
+}
+
+/* get caller address out of q931 element buffer */
+INT
+cm__get_addr(IDD_MSG *msg, CHAR addr[32])
+{
+ UCHAR *elem, elem_len;
+
+ /* locate type element */
+ if ( !(elem = cm__q931_elem(msg->bufptr, msg->buflen, 0x6C)) )
+ return(CM_E_NOSUCH);
+ else
+ elem++;
+
+// Subtracting 1 looks like a mistake
+// TB 11.09.93
+// if ( (elem_len = *elem++ - 1) > 32 )
+// elem_len = 31;
+ if ( (elem_len = *elem++) > 32 )
+ elem_len = 31;
+
+ if (elem_len < 2)
+ return(CM_E_NOSUCH);
+
+ elem += 2;
+ elem_len -= 2;
+
+ /* copy in & terminate */
+ NdisMoveMemory (addr, elem, elem_len);
+ addr[elem_len] = '\0';
+
+ return(CM_E_SUCC);
+}
+
+/* scan q931 element buffer for a specific element */
+UCHAR*
+cm__q931_elem(VOID *ptr_1, INT len, UCHAR elem)
+{
+ UCHAR *ptr = (UCHAR*)ptr_1;
+ CHAR codeset = 0; /* starting with code set 0 */
+ CHAR prev_codeset; /* saving area for prev. codeset */
+ CHAR locked = 1; /* locked/nonlocked codeset shift */
+
+ /* loop while length left */
+ while ( len > 0 )
+ {
+ /* handle shifting codesets */
+ if ( (*ptr & 0xF0) == 0x90 /*Q931_IE0_SHIFT*/ )
+ {
+ prev_codeset = codeset; /* save current code set */
+ codeset = *ptr & 0x07; /* extract new codeset */
+ locked = !(*ptr & 0x08); /* ... and locking status */
+ ptr++; /* move past shift element */
+ len--;
+ continue;
+ }
+
+ /* check for codeset 0 */
+ if ( codeset != 0 ) /* non codeset0 elements, just skip */
+ {
+ if ( *ptr & 0x80 )
+ {
+ ptr++;
+ len--;
+ }
+ //
+ // added to support the new switch styles
+ // TB 03/14
+ //
+ else if (SwitchStyle == CM_SWITCHSTYLE_1TR6 &&
+ elem == 0x04 &&
+ *ptr == 0x01)
+ {
+ return(ptr);
+ }
+ else
+ {
+ len -= (2 + ptr[1]);
+ ptr += (ptr[1] + 2);
+ }
+
+ if ( !locked )
+ {
+ codeset = prev_codeset;
+ locked = 1;
+ }
+
+ continue; /* move to next element */
+ }
+
+ /* try to match elem from codeset 0 */
+ if ( *ptr & 0x80 ) /* single octet elem? */
+ { /* yes */
+ if ( (((elem & 0xF0) == 0xA0) && (elem == (UCHAR)*ptr)) ||
+ (((elem & 0x80) == 0x80) && (elem == (UCHAR)(*ptr & 0xF0))) )
+ { /* element found */
+ return(ptr);
+ }
+ else
+ {
+ ptr++; /* skip this elem */
+ len--;
+ }
+ }
+ else
+ {
+ if ( *ptr == elem )
+ { /* multi byte elem match */
+ return(ptr);
+ }
+ else
+ {
+ len -= (2 + ptr[1]);
+ ptr += (ptr[1] + 2);
+ }
+ }
+
+ /* resert codeset if not locked */
+ if ( !locked )
+ {
+ codeset = prev_codeset;
+ locked = 1;
+ }
+ }
+
+ /* if here, not found */
+ return(NULL);
+}
+
+/* convert channel type to speed */
+ULONG
+cm__type2speed(USHORT type)
+{
+ switch ( type )
+ {
+ case CM_CT_VOICE :
+ case CM_CT_D56 :
+ return(56000);
+
+ case CM_CT_D64 :
+ default :
+ return(64000);
+ }
+}
diff --git a/private/ntos/ndis/pcimac/cm_stat.c b/private/ntos/ndis/pcimac/cm_stat.c
new file mode 100644
index 000000000..fefdeaa30
--- /dev/null
+++ b/private/ntos/ndis/pcimac/cm_stat.c
@@ -0,0 +1,32 @@
+/*
+ * CM_STAT.C - status related code
+ */
+
+#include <ndis.h>
+//#include <ndismini.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+
+/* get status from cm (note that CM == CM_STATUS for now!) */
+INT
+cm_get_status(VOID *cm_1, CM_STATUS *stat)
+{
+ CM* cm = (CM*)cm_1;
+
+ D_LOG(D_ENTRY, ("cm_get_status: entry, cm: 0x%p, stat: 0x%p", cm, stat));
+
+ /* set & return */
+ *stat = *cm;
+ return(CM_E_SUCC);
+}
+
+
+
diff --git a/private/ntos/ndis/pcimac/cm_state.c b/private/ntos/ndis/pcimac/cm_state.c
new file mode 100644
index 000000000..aab2b74c0
--- /dev/null
+++ b/private/ntos/ndis/pcimac/cm_state.c
@@ -0,0 +1,755 @@
+/*
+ * CM_STATE.C - q931 state managment code
+ */
+
+#include <ndis.h>
+//#include <ndismini.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+
+/* (ans) process incoming connections */
+INT
+cm__ans_est_ind(CM_CHAN *chan, IDD_MSG *msg, VOID *idd, USHORT lterm)
+{
+ USHORT bchan, type, cid;
+ INT RetCode;
+
+ D_LOG(D_ENTRY, ("cm__ans_est_ind: entry, chan: 0x%p, msg: 0x%p", \
+ chan, msg));
+
+ cid = HIWORD(msg->bufid);
+
+ /* must not have a channel at this time */
+ if ( chan )
+ {
+ D_LOG(D_ALWAYS, ("cm__ans_est_ind: on used channel, ignored!"));
+
+ RetCode = CM_E_BADPARAM;
+
+ //
+ // we need to let the adapter know that we are not processing
+ // this incoming call indication
+ //
+ ignored:
+
+ /* answer channel */
+ cm__est_ignore(idd, cid, lterm);
+
+ return(RetCode);
+ }
+
+ /* extract info out of message, must have bchan/type */
+ if ( (cm__get_bchan(msg, &bchan) != CM_E_SUCC) ||
+ (cm__get_type(msg, &type) != CM_E_SUCC) )
+ {
+ D_LOG(D_ALWAYS, ("cm__ans_est_ind: bchan or type missing, ignored!"));
+
+ RetCode = CM_E_BADPARAM;
+ goto ignored;
+ }
+
+ if ( !CM_BCHAN_ASSIGNED(bchan) )
+ {
+ D_LOG(D_ALWAYS, ("cm__ans_est_ind: bchan: %d, unassigned, ignored!",\
+ bchan));
+ RetCode = CM_E_BADPARAM;
+ goto ignored;
+ }
+
+ D_LOG(D_ALWAYS, ("cm__ans_est_ind: cid: 0x%x, bchan: %d, type: 0x%d",\
+ cid, bchan, type));
+
+ /* channel will be answered only if a listening profile exists */
+ if ( !cm__find_listen_conn("*", "*", "*", idd) )
+ {
+ D_LOG(D_ALWAYS, ("cm__ans_est_ind: not listening profile, ignored!"));
+ RetCode = CM_E_NOSUCH;
+ goto ignored;
+ }
+
+ /* allocate a channel out of incoming channel poll */
+ if ( !(chan = cm__chan_alloc()) )
+ {
+ D_LOG(D_ALWAYS, ("cm__ans_est_ind: no channel slot, ignored!"));
+ RetCode = CM_E_NOSLOT;
+ goto ignored;
+ }
+
+ /* fillup channel structure */
+ NdisZeroMemory(chan, sizeof(*chan));
+ chan->idd = idd;
+ chan->lterm = lterm;
+ chan->bchan = bchan;
+ chan->type = type;
+ chan->speed = cm__type2speed(type);
+ chan->ustate = CM_US_UNDEF;
+ chan->cid = cid;
+ chan->timeout = ut_time_now();
+
+ /* extract caller address, if present */
+ if ( cm__get_addr(msg, chan->addr) != CM_E_SUCC )
+ strcpy(chan->addr, "<unknown>");
+ D_LOG(D_ALWAYS, ("cm__ans_est_ind: caller address is: %s", \
+ chan->addr));
+
+ /* answer channel */
+ cm__est_rsp(chan);
+
+ /* return succ */
+ return(CM_E_SUCC);
+}
+
+/* (ans) process state indications */
+INT
+cm__ans_state_ind(CM_CHAN *chan, IDD_MSG *msg)
+{
+ D_LOG(D_ENTRY, ("cm__ans_state_ind: entry, chan: 0x%p, msg: 0x%p", \
+ chan, msg));
+
+ /* log state change */
+ chan->ustate = LOWORD(msg->bufid);
+ D_LOG(D_ALWAYS, ("cm__ans_state_ind: ustate: %d", chan->ustate));
+
+ /* if changed to U0, has been released */
+ if ( !chan->ustate )
+ {
+ cm__bchan_ctrl(chan, 0);
+ cm__chan_free(chan);
+ return(CM_E_SUCC);
+ }
+
+ /* if changed to U10, just got connected, open data path */
+ if ( chan->ustate == 10 )
+ {
+ cm__bchan_ctrl(chan, 1);
+ chan->timeout = ut_time_now();
+ return(CM_E_SUCC);
+ }
+
+ /* else ignore */
+ return(CM_E_SUCC);
+}
+
+/* (ans) process data indications */
+INT
+cm__ans_data_ind(CM_CHAN *chan, IDD_MSG *msg)
+{
+ CM_UUS *uus;
+ ULONG chan_num, n;
+ UCHAR cause;
+ CM *cm;
+ ULONG CompressionFlag = 0;
+ IDD_MSG msg1;
+
+ D_LOG(D_ENTRY, ("cm__ans_data_ind: entry, chan: 0x%p, msg: 0x%p", \
+ chan, msg));
+
+ /* assign UUS pointer & do some basic checks */
+ uus = (CM_UUS*)msg->bufptr;
+ if ( msg->buflen < CM_UUS_SIZE )
+ return(CM_E_BADUUS);
+
+ if ( (uus->pkt_type != CM_PKT_TYPE) ||
+ (uus->prot_desc != CM_PROT_DESC) ||
+ (cm__calc_chksum(uus, CM_UUS_SIZE) != 0) )
+ return(CM_E_BADUUS);
+
+ /* channel must be atleast connected */
+ if ( chan->ustate < 10 )
+ return(CM_E_BADSTATE);
+
+ /* if channel already accepted assoc, accept again (other side lost) */
+ if ( chan->ustate == CM_US_UUS_OKED )
+ {
+ D_LOG(D_ALWAYS, ("cm__ans_data_ind: chan_num->ustate: %d", chan->ustate));
+ accept:
+ chan->ustate = CM_US_UUS_OKED;
+ chan->timeout = ut_time_now();
+ cm__tx_uus_pkt(chan, CM_ASSOC_ACK, 0);
+ return(CM_E_SUCC);
+ }
+
+ /* record information from uus */
+ NdisMoveMemory (chan->DstAddr, uus->src_addr, 6);
+
+ chan->remote_conn_index = uus->conn;
+
+ //
+ // kill dead man timer for this channel
+ //
+ NdisZeroMemory(&msg1, sizeof(IDD_MSG));
+ msg1.opcode = Q931_CAN_TU10_RQ;
+ msg1.bufptr = ut_get_buf();
+ msg1.buflen = 0;
+ msg1.bufid = MAKELONG(0, chan->cid);
+
+ /* send to idd */
+ if (idd_send_msg(chan->idd, &msg1, (USHORT)CM_PORT(chan), (VOID*)cm__q931_cmpl_handler, NULL) != IDD_E_SUCC)
+ ut_free_buf(msg1.bufptr);
+
+
+ /* if not last channel, accept */
+ chan_num = 0;
+ cm__chan_foreach(cm__inc_chan_num, chan, &chan_num);
+ if ( (UCHAR)chan_num < uus->channum )
+ {
+ D_LOG(D_ALWAYS, ("cm__ans_data_ind: chan_num: %d, uus->channum: %d", chan_num, uus->channum));
+ goto accept;
+ }
+
+
+ /* last channel, find matching connection/profile */
+ if ( !(cm = cm__find_listen_conn(uus->lname, uus->rname, chan->addr, chan->idd)) )
+ {
+ /* none found, reject */
+ cause = CM_NO_PROF;
+ D_LOG(D_ALWAYS, ("cm__ans_data_ind: rejected, cause: %d", cause));
+ cm__tx_uus_pkt(chan, CM_ASSOC_NACK, cause);
+ return(CM_E_NOSUCH);
+ }
+
+ /* matching connection found!, fillin */
+ D_LOG(D_ALWAYS, ("cm__ans_data_ind: matching connection: cm: 0x%p", cm));
+
+ cm->state = CM_ST_IN_ANS;
+ cm->StateChangeFlag = TRUE;
+ cm->was_listen = TRUE;
+ cm->active_chan_num = chan_num;
+ cm->remote_conn_index = chan->remote_conn_index;
+ cm->ConnectionType = CM_DKF;
+ NdisMoveMemory(cm->DstAddr, chan->DstAddr, 6);
+ NdisMoveMemory (cm->remote_name, uus->rname, sizeof(cm->remote_name));
+
+ cm->timeout = cm->rx_last_frame_time = cm->tx_last_frame_time =
+ ut_time_now();
+
+ /* accept channel here */
+ chan->ustate = CM_US_UUS_OKED;
+ chan->timeout = ut_time_now();
+ chan->cm = cm;
+ cm__tx_uus_pkt(chan, CM_ASSOC_ACK, 0);
+
+
+ /* collect channels info local vector */
+ cm->dprof.chan_num = 0;
+ cm__chan_foreach(cm__add_chan, chan, cm);
+
+ /* init channel fields */
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++)
+ {
+ CM_CHAN *chan = cm->dprof.chan_tbl + n;
+
+ chan->ustate = CM_US_CONN;
+ chan->timeout = ut_time_now();
+ chan->num = (USHORT)n;
+ chan->cm = cm;
+ chan->active = TRUE;
+ }
+
+ /* make connection active */
+ cm->state = CM_ST_ACTIVE;
+ cm->StateChangeFlag = TRUE;
+
+ // Set compression Flag
+ if (cm->dprof.HWCompression && (uus->option_0 & UUS_0_COMPRESSION))
+ CompressionFlag = 1;
+ else
+ CompressionFlag = 0;
+
+ D_LOG(D_ALWAYS, ("cm__ans_data_ind: Activating connection for cm: 0x%p", cm));
+ return(cm__activate_conn(cm, CompressionFlag));
+}
+
+/* (org) new cid indicated on outgoing channel */
+INT
+cm__org_cid_ind(CM_CHAN *chan, IDD_MSG *msg)
+{
+ CM *cm;
+ USHORT conn_num, chan_num, cid;
+
+ D_LOG(D_ENTRY, ("cm__org_cid_ind: entry, chan: 0x%p, msg: 0x%p", \
+ chan, msg));
+
+ /* extract conn_num/chan_num out of param 3, get cid */
+ conn_num = HIBYTE(LOWORD(msg->bufid));
+ chan_num = LOBYTE(LOWORD(msg->bufid));
+ cid = HIWORD(msg->bufid);
+ D_LOG(D_ALWAYS, ("cm__org_cid_ind: conn_num: %d, chan_num: %d, cid: 0x%x", conn_num, chan_num, cid));
+
+// DbgPrint("cid_ind: conn_num: %d, chan_num: %d, cid: 0x%x\n",
+// conn_num, chan_num, cid);
+
+ /* get related connection */
+ if ( !(cm = cm__get_conn(conn_num)) )
+ {
+// DbgPrint("cid_ind: cm__get_conn failed!\n");
+ return(CM_E_BADPARAM);
+ }
+
+ /* get related channel */
+ if ( chan_num >= cm->dprof.chan_num )
+ {
+// DbgPrint("cid_ind: invalid chan_num!\n");
+ return(CM_E_BADPARAM);
+ }
+ else
+ chan = cm->dprof.chan_tbl + chan_num;
+
+ /* check channel ustate */
+ if ( chan->ustate != CM_US_WAIT_CID )
+ {
+// DbgPrint("cid_ind: invalid ustate (%d)!\n", chan->ustate);
+ return(CM_E_BADSTATE);
+ }
+
+ /* cid == 0, no free slots at idp, simulate state change to 0 */
+ if ( !cid )
+ {
+ cm->NoActiveLine = 1;
+ return(cm__org_state_ind(chan, NULL));
+ }
+
+ /* assign params */
+ chan->ustate = CM_US_UNDEF;
+ chan->cid = cid;
+// DbgPrint("cid_ind: ustate: %d, cid: 0x%x assigned\n", chan->ustate, chan->cid);
+
+ return(CM_E_SUCC);
+}
+
+/* (org) process state indications */
+INT
+cm__org_state_ind(CM_CHAN *chan, IDD_MSG *msg)
+{
+ CM *cm;
+ ULONG n;
+ USHORT gave_up_num, chan_num;
+ ULONG CompressionFlag;
+
+ D_LOG(D_ENTRY, ("cm__org_state_ind: entry, chan: 0x%p, msg: 0x%p", \
+ chan, msg));
+
+ /* check for change of state at protocol level */
+ if ( !chan )
+ {
+ /* not used for now */
+ return(CM_E_NOTIMPL);
+ }
+
+ /* log change */
+ cm = chan->cm;
+
+ chan->ustate = msg ? LOWORD(msg->bufid) : 0;
+
+ D_LOG(D_ALWAYS,("cm__org_state_ind: cm 0x%p, ustate: 0x%x", \
+ cm, chan->ustate));
+
+ /* if changed to U0, has been released, may retry connection here */
+ if ( !chan->ustate )
+ {
+ /* turn off bchannel */
+ cm__bchan_ctrl(chan, 0);
+
+ /* if not in activation, this is a fatal error, disconnect */
+ if ( cm->state != CM_ST_IN_ACT )
+ {
+ disc_all:
+
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++ )
+ {
+ CM_CHAN *chan1 = cm->dprof.chan_tbl + n;
+
+ if ( chan1->ustate > 0 )
+ cm__disc_rq(chan1);
+ }
+
+ /* deactivate connection */
+ cm__deactivate_conn(cm, 0);
+
+ return(CM_E_SUCC);
+ }
+
+ /* attampt to retry */
+ if ( !cm->dprof.fallback ||
+ (cm->CauseValue == 0x11 || cm->SignalValue == 0x04) ||
+ (cm__get_next_chan(chan) != CM_E_SUCC) )
+ {
+ chan->ustate = CM_US_GAVE_UP;
+ chan->gave_up = 1;
+ }
+ else
+ {
+ /* if here, retrying */
+ chan->cid = MAKEWORD(chan->num, cm->local_conn_index);
+ chan->ustate = CM_US_WAIT_CID;
+ chan->timeout = ut_time_now();
+
+ cm__est_rq(chan);
+ }
+
+ /* find out how many channels gave up (or connected) */
+ check_chan:
+ for ( n = gave_up_num = 0 ; n < cm->dprof.chan_num ; n++ )
+ if ( cm->dprof.chan_tbl[n].gave_up )
+ gave_up_num++;
+ else if ( cm->dprof.chan_tbl[n].ustate != CM_US_WAIT_CONN )
+ break;
+
+ /* if broke out of loop before hitting chan_num, some channels
+ are still in progress */
+ if ( n < cm->dprof.chan_num )
+ return(CM_E_SUCC);
+
+ /* if all gave up, give up conn */
+ if ( gave_up_num >= cm->dprof.chan_num )
+ {
+ cm__deactivate_conn(cm, 0);
+ return(CM_E_SUCC);
+ }
+
+ /* if here, some channels connected and some gave up, continue */
+ chan_num = cm->dprof.chan_num - gave_up_num;
+
+ /* if fallback set to no, must match */
+ if ( !cm->dprof.fallback && (chan_num != cm->dprof.chan_num) )
+ goto disc_all;
+
+ /* connection enters in_sync state */
+ cm->state = CM_ST_IN_SYNC;
+ cm->StateChangeFlag = TRUE;
+ cm->timeout = ut_time_now();
+
+ /* compact channel table & renumber */
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++ )
+ {
+ CM_CHAN *chan1 = cm->dprof.chan_tbl + n;
+
+ if ( chan1->gave_up )
+ {
+ NdisMoveMemory(cm->dprof.chan_tbl + n,
+ cm->dprof.chan_tbl + n + 1,
+ sizeof(CM_CHAN) * (cm->dprof.chan_num - n - 1));
+ cm->dprof.chan_num--;
+ n--;
+ }
+ }
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++ )
+ cm->dprof.chan_tbl[n].num = (USHORT)n;
+
+ if (cm->ConnectionType == CM_DKF)
+ {
+ //
+ // if this is a uus connnection tx uus frames
+ //
+ /* send initial uus_rq on all active channels */
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++ )
+ {
+ CM_CHAN *chan1 = cm->dprof.chan_tbl + n;
+
+ if ( chan1->gave_up )
+ continue;
+
+ chan1->timeout = ut_time_now();
+ chan1->ustate = CM_US_UUS_SEND;
+
+ cm__tx_uus_pkt(chan1, CM_ASSOC_RQ, 0);
+ }
+ }
+ else
+ {
+ //
+ // if this is a ppp connection mark channels
+ // as being connected and activate the connection
+ //
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++ )
+ {
+ CM_CHAN *chan1 = cm->dprof.chan_tbl + n;
+
+ if ( chan1->gave_up )
+ continue;
+
+ chan1->ustate = CM_US_CONN;
+ chan1->timeout = ut_time_now();
+ chan1->remote_conn_index = 1;
+ }
+ NdisZeroMemory(cm->DstAddr, sizeof(cm->DstAddr));
+ NdisZeroMemory(cm->remote_name, sizeof(cm->remote_name));
+
+ /* make connection active now */
+ cm->state = CM_ST_ACTIVE;
+ cm->StateChangeFlag = TRUE;
+ CompressionFlag = 0;
+
+ return (cm__activate_conn(cm, CompressionFlag));
+ }
+
+ return(CM_E_SUCC);
+ }
+
+ /* if change state to U10 just connected */
+ if ( chan->ustate == 10 )
+ {
+ /* start data transfer on channel */
+ cm__bchan_ctrl(chan, 1);
+ chan->ustate = CM_US_WAIT_CONN;
+ chan->timeout = ut_time_now();
+
+ /* see if all channels are connected, continue as a change to U0 */
+ goto check_chan;
+ }
+}
+
+/* (org) process data indications */
+INT
+cm__org_data_ind(CM_CHAN *chan, IDD_MSG *msg)
+{
+ CM_UUS *uus;
+ CM *cm = chan->cm;
+ ULONG n, first;
+ ULONG CompressionFlag;
+
+ D_LOG(D_ENTRY, ("cm__org_data_ind: entry, chan: 0x%p, msg: 0x%p", \
+ chan, msg));
+
+
+ /* assign UUS pointer & do some basic checks */
+ uus = (CM_UUS*)msg->bufptr;
+ if ( msg->buflen < CM_UUS_SIZE )
+ return(CM_E_BADUUS);
+ if ( (uus->pkt_type != CM_PKT_TYPE) ||
+ (uus->prot_desc != CM_PROT_DESC) ||
+ (cm__calc_chksum(uus, CM_UUS_SIZE) != 0) )
+ return(CM_E_BADUUS);
+
+ /* channel must be atleast connected */
+ if ( chan->ustate < 10 )
+ return(CM_E_BADSTATE);
+
+ /* if is a request, channel is part of a listening conn */
+ if ( uus->opcode == CM_ASSOC_RQ )
+ {
+ cm__tx_uus_pkt(chan, CM_ASSOC_ACK, 0);
+ return(CM_E_SUCC);
+ }
+
+ /* if nack detected, connection is torn down */
+ if ( uus->opcode == CM_ASSOC_NACK )
+ {
+// disc_all:
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++ )
+ {
+ CM_CHAN *chan1 = cm->dprof.chan_tbl + n;
+
+ if ( chan1->ustate > 0 )
+ cm__disc_rq(chan1);
+ }
+
+ /* deactivate connection */
+ cm__deactivate_conn(cm, 0);
+
+ return(CM_E_SUCC);
+ }
+
+ /* if here must be an ack */
+ if ( uus->opcode != CM_ASSOC_ACK )
+ return(CM_E_BADUUS);
+
+ /* if channel already connected and uus ack'ed - ignore */
+ if ( chan->ustate > CM_US_UUS_OKED )
+ return(CM_E_SUCC);
+
+ //
+ // if this flag is set then we originally had a PPP connection
+ // this means that all of the connection stuff is taken care of and
+ // we just need to satisfy the remote ends uus requirements.
+ // there should be only one channel in this case!
+ //
+ if (cm->PPPToDKF)
+ {
+ chan->ustate = CM_US_CONN;
+ NdisMoveMemory (chan->DstAddr, uus->src_addr, 6);
+ NdisMoveMemory(cm->DstAddr, chan->DstAddr, 6);
+ cm->remote_conn_index = cm->dprof.chan_tbl[0].remote_conn_index;
+ NdisMoveMemory(cm->remote_name, uus->lname, sizeof(cm->remote_name));
+ cm->PPPToDKF = 0;
+ return(CM_E_SUCC);
+ }
+
+ /* if here, it is an ack */
+ chan->ustate = CM_US_UUS_OKED;
+ chan->timeout = ut_time_now();
+
+ NdisMoveMemory (chan->DstAddr, uus->src_addr, 6);
+
+ chan->remote_conn_index = uus->conn;
+
+ /* proceed only if all channels ok'ed */
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++ )
+ if ( !cm->dprof.chan_tbl[n].gave_up &&
+ (cm->dprof.chan_tbl[n].ustate != CM_US_UUS_OKED) )
+ return(CM_E_SUCC);
+
+ /* verify all channel got connected to the same eaddr/conn */
+ for ( first = 0 ; first < cm->dprof.chan_num ; first++ )
+ if ( !cm->dprof.chan_tbl[n].gave_up )
+ break;
+
+ /* move all channels to connected state */
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++ )
+ if ( !cm->dprof.chan_tbl[n].gave_up )
+ {
+ cm->dprof.chan_tbl[n].ustate = CM_US_CONN;
+ cm->dprof.chan_tbl[n].timeout = ut_time_now();
+ }
+
+// Hack to get around no cm for all channels < the last channel received
+ NdisMoveMemory(cm->DstAddr, chan->DstAddr, 6);
+
+ /* store some values on a connection level */
+ cm->remote_conn_index = cm->dprof.chan_tbl[first].remote_conn_index;
+ NdisMoveMemory(cm->remote_name, uus->lname, sizeof(cm->remote_name));
+
+ /* make connection active now */
+ cm->state = CM_ST_ACTIVE;
+ cm->StateChangeFlag = TRUE;
+
+ // Set compression Flag
+ if (cm->dprof.HWCompression && (uus->option_0 & UUS_0_COMPRESSION))
+ CompressionFlag = 1;
+ else
+ CompressionFlag = 0;
+
+ return(cm__activate_conn(cm, CompressionFlag));
+}
+
+/* (org) process element indications */
+INT
+cm__org_elem_ind(CM_CHAN *chan, IDD_MSG *msg)
+{
+ USHORT bchan;
+ int auto_disc = 0;
+ CHAR *elem;
+
+ D_LOG(D_ENTRY, ("cm__org_elem_ind: entry, chan: 0x%p, msg: 0x%p", \
+ chan, msg));
+
+ /* must have a valid channel to proceed */
+ if ( !chan )
+ return(CM_E_SUCC);
+
+ /* check if bchannel reported */
+ if ( cm__get_bchan(msg, &bchan) == CM_E_SUCC )
+ {
+ D_LOG(D_ALWAYS, ("cm__org_elem_ind: bchan: %d", bchan));
+
+ if ( !CM_BCHAN_ASSIGNED(chan->bchan) )
+ auto_disc |= 1;
+ else
+ chan->bchan = bchan;
+ }
+
+ /* scan for cause */
+ if ( (elem = cm__q931_elem(msg->bufptr, msg->buflen, 0x08)) &&
+ (elem[1] >= 2) && !(elem[2] & 0x78) )
+ {
+ static CHAR disc_vals[] = { 0x01, 0x11, 0x12 };
+
+ D_LOG(D_ALWAYS, ("cm__org_elem_ind: cause: 0x%x", elem[3] & 0x7F));
+
+ if ( memchr(disc_vals, elem[3] & 0x7F, sizeof(disc_vals)) )
+ {
+ CM *cm = (CM*)chan->cm;
+
+ cm->CauseValue = elem[3] & 0x7F;
+ auto_disc |= 2;
+ }
+ }
+
+ /* scan for signal */
+ if ( (elem = cm__q931_elem(msg->bufptr, msg->buflen, 0x34)) &&
+ (elem[1] == 1) )
+ {
+// static CHAR signal_vals[] = { 0x00, 0x03, 0x04, 0x0C };
+ static CHAR signal_vals[] = { 0x03, 0x04, 0x0C };
+
+ D_LOG(D_ALWAYS, ("cm__org_elem_ind: signal: 0x%x", elem[2]));
+
+ if ( memchr(signal_vals, elem[2], sizeof(signal_vals)) )
+ {
+ CM *cm = (CM*)chan->cm;
+
+ cm->SignalValue = elem[2];
+ auto_disc |= 4;
+ }
+ }
+
+ /* check if need to disconnect */
+ if ( auto_disc )
+ {
+ D_LOG(D_ALWAYS, ("cm__org_elem_ind: auto_disc: 0x%x", auto_disc));
+ cm__disc_rq(chan);
+ }
+
+ return(CM_E_SUCC);
+}
+
+/* calc a checksum for a buffer */
+UCHAR
+cm__calc_chksum(VOID *buf_1, INT len)
+{
+ UCHAR *buf = (UCHAR *)buf_1;
+ UCHAR sum;
+
+ for ( sum = 0 ; len ; len-- )
+ sum += *buf++;
+
+ return(sum);
+}
+
+/* increment a channel count */
+BOOL
+cm__inc_chan_num(CM_CHAN *chan, CM_CHAN *ref_chan, ULONG *chan_num)
+{
+ /* find if this channel is part of same connection as ref_chan */
+ if ( memcmp(chan->DstAddr, ref_chan->DstAddr, 6) ||
+ (chan->remote_conn_index != ref_chan->remote_conn_index) )
+ return(TRUE);
+
+ /* inrement here */
+ *chan_num += 1;
+ return(TRUE);
+}
+
+/* add a channel to a connection */
+BOOL
+cm__add_chan(CM_CHAN *chan, CM_CHAN *ref_chan, CM *cm)
+{
+ CM_CHAN *chan1;
+
+ /* if connection already full, stop here */
+ if ( cm->dprof.chan_num >= cm->active_chan_num )
+ return(FALSE);
+
+ /* find if this channel is part of same connection as ref_chan */
+ if ( memcmp(chan->DstAddr, ref_chan->DstAddr, 6) ||
+ (chan->remote_conn_index != ref_chan->remote_conn_index) )
+ return(TRUE);
+
+ /* add this channel */
+ chan1 = &cm->dprof.chan_tbl[cm->dprof.chan_num++];
+ *chan1 = *chan;
+ cm__chan_free(chan);
+ return(TRUE);
+}
+
+
+
+
diff --git a/private/ntos/ndis/pcimac/cm_timer.c b/private/ntos/ndis/pcimac/cm_timer.c
new file mode 100644
index 000000000..383d8244d
--- /dev/null
+++ b/private/ntos/ndis/pcimac/cm_timer.c
@@ -0,0 +1,79 @@
+/*
+ * CM_TIMER.C - time code for cm module
+ */
+
+#include <ndis.h>
+//#include <ndismini.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+
+/* timer values defined here */
+#define T1 30 /* 30 seconds to leave connection transient state */
+#define T2 4 /* 4 seconds to activate permanent connection */
+
+/* timer tick entry point. called no faster then once a second! */
+INT
+cm__timer_tick(CM *cm)
+{
+ ULONG n;
+ BOOL disc_by_idle_timer = FALSE;
+
+ /* check for dead-man time in transient state */
+ if ( (cm->state == CM_ST_IN_SYNC) || (cm->state == CM_ST_IN_ACT) )
+ {
+ if ( (ut_time_now() - cm->timeout) > T1 )
+ {
+ disc_all:
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++ )
+ if ( !cm->dprof.chan_tbl[n].gave_up )
+ cm__disc_rq(cm->dprof.chan_tbl + n);
+
+ return(cm__deactivate_conn(cm, disc_by_idle_timer));
+ }
+ }
+
+ /* if active now, check for idle timers */
+ if ( cm->state == CM_ST_ACTIVE )
+ {
+ if ( (cm->dprof.rx_idle_timer &&
+ ((ut_time_now() - cm->rx_last_frame_time) > cm->dprof.rx_idle_timer)) ||
+ (cm->dprof.tx_idle_timer &&
+ ((ut_time_now() - cm->tx_last_frame_time) > cm->dprof.tx_idle_timer)) )
+ {
+ disc_by_idle_timer = TRUE;
+ goto disc_all;
+ }
+ }
+
+ /* check if connection has to activate as being permanent */
+ if ( (cm->state == CM_ST_WAIT_ACT) && cm->dprof.permanent )
+ {
+ if ( (ut_time_now() - cm->timeout) > T2 )
+ {
+ cm->state = CM_ST_IN_ACT;
+ cm->timeout = ut_time_now();
+ return(cm__initiate_conn(cm));
+ }
+ }
+
+ /* if in_sync, resend uus on channels requiring it */
+ //
+ // if we are stuck in sync state the resend uus on all channels requiring it
+ // if we are in an ACTIVE state and the PPPToDKF Flag is set we need to send
+ // uus until they acknowledged
+ //
+ if ( cm->state == CM_ST_IN_SYNC || (cm->state == CM_ST_ACTIVE && cm->PPPToDKF))
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++ )
+ if ( cm->dprof.chan_tbl[n].ustate == CM_US_UUS_SEND )
+ cm__tx_uus_pkt(cm->dprof.chan_tbl + n, CM_ASSOC_RQ, 0);
+}
+
+
diff --git a/private/ntos/ndis/pcimac/cnf.h b/private/ntos/ndis/pcimac/cnf.h
new file mode 100644
index 000000000..a897e0b22
--- /dev/null
+++ b/private/ntos/ndis/pcimac/cnf.h
@@ -0,0 +1,13 @@
+/*
+ * CNF_PUB.H - config module public defs
+ */
+
+/* class operations */
+BOOL cnf_get_long(CHAR* path, CHAR* key,
+ ULONG* ret_val, ULONG def_val);
+BOOL cnf_get_str(CHAR* path, CHAR* key,
+ CHAR* ret_val, ULONG maxlen, CHAR* def_val);
+BOOL cnf_get_multi_str(CHAR* path, CHAR* key,
+ CHAR* store_buf, ULONG store_len,
+ CHAR** str_vec, ULONG str_max, ULONG* str_num,
+ CHAR** def_vec, ULONG def_num);
diff --git a/private/ntos/ndis/pcimac/disp.c b/private/ntos/ndis/pcimac/disp.c
new file mode 100644
index 000000000..8696e9f96
--- /dev/null
+++ b/private/ntos/ndis/pcimac/disp.c
@@ -0,0 +1,132 @@
+/*
+ * DISP.C - debug display routines for NDIS environment
+ */
+
+#include <ndis.h>
+//#include <ndismini.h>
+#include <ndiswan.h>
+#include <mydefs.h>
+#include <mytypes.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <util.h>
+#include <adapter.h>
+#include <idd.h>
+#include <cm.h>
+#include <mtl.h>
+#include <trc.h>
+#include <io.h>
+
+#if DBG
+#define DISP_DEBUG 1
+#endif
+#ifdef DISP_DEBUG
+
+INT d_level = -1; /* current debug level */
+INT d_mode = 0; /* display mode: 0-dbg, 1-msg */
+INT d_cmplen = 0; /* lenght of filename string for compare */
+CHAR d_filestr[8]; /* filename string for compare */
+NDIS_SPIN_LOCK DebugLock;
+
+VOID
+d_log_init (VOID)
+{
+ NdisAllocateSpinLock (&DebugLock);
+}
+
+VOID
+d_log_term (VOID)
+{
+ NdisFreeSpinLock (&DebugLock);
+}
+
+
+/* check if logging enabled on file,line,level (for now, always on) */
+INT
+d_log_on(CHAR *file, INT line, INT level)
+{
+ CHAR *fname;
+
+ if ( level > d_level )
+ return(0);
+
+ if ( fname = strrchr(file, '\\') )
+ fname++;
+ else
+ fname = file;
+
+ if(d_cmplen && _strnicmp(fname,d_filestr,d_cmplen))
+ return(0);
+
+ NdisAcquireSpinLock(&DebugLock);
+ DbgPrint("PCIMAC.SYS: ");
+
+ return(1);
+}
+
+/* do output processing for logging */
+VOID
+d_log_out(CHAR* fmt, ...)
+{
+ static CHAR buf[256];
+ va_list marker;
+
+ va_start (marker, fmt);
+ vsprintf (buf, fmt, marker);
+ va_end (marker);
+ DbgPrint ("%s\n",buf);
+
+ NdisReleaseSpinLock(&DebugLock);
+
+}
+
+VOID
+InternalSetDebugLevel (INT DebugLevel)
+{
+ d_level = DebugLevel;
+}
+
+
+VOID
+SetDebugLevel (VOID *cmd1)
+{
+ IO_CMD *cmd = (IO_CMD*)cmd1;
+ d_level = (INT)cmd->arg[0];
+ d_cmplen = (INT)cmd->val.dbg_level.cmplen;
+ if(d_cmplen)
+ NdisMoveMemory(d_filestr,cmd->val.dbg_level.filestr,d_cmplen);
+
+ if ( d_level != -1 )
+ {
+ d_mode = d_level / 1000;
+ d_level = d_level % 1000;
+ }
+}
+#else
+
+
+VOID
+SetDebugLevel(VOID *cmd_1)
+{
+ IO_CMD *cmd = (IO_CMD*)cmd_1;
+}
+
+VOID
+d_log_init()
+{
+ return;
+}
+
+VOID
+d_log_term()
+{
+ return;
+}
+
+VOID
+InternalSetDebugLevel(INT DebugLevel)
+{
+
+}
+#endif
+
diff --git a/private/ntos/ndis/pcimac/disp.h b/private/ntos/ndis/pcimac/disp.h
new file mode 100644
index 000000000..4cbeab3b2
--- /dev/null
+++ b/private/ntos/ndis/pcimac/disp.h
@@ -0,0 +1,42 @@
+/*
+ * DISP.H - debug display macro's under NDIS
+ */
+
+#ifndef _DISP_
+#define _DISP_
+
+#if DBG
+#define DISP_DEBUG 1
+#endif
+#ifdef DISP_DEBUG
+
+/* main macro to be used for logging */
+#define D_LOG(level, args) \
+ { \
+ if ( d_log_on(__FILE__, __LINE__, level) ) \
+ d_log_out args; \
+ }
+#else
+
+#define D_LOG(level, args)
+#endif
+
+/* prototypes */
+VOID d_log_init(VOID);
+VOID d_log_term(VOID);
+INT d_log_on(CHAR* file, INT line, INT level);
+VOID d_log_out(CHAR* fmt, ...);
+VOID SetDebugLevel (VOID *);
+VOID InternalSetDebugLevel (INT);
+
+/* log levels */
+#define D_ALWAYS 0
+#define D_ENTRY 5
+#define D_EXIT 6
+#define D_RARE 51
+#define D_NEVER 101
+
+
+#endif /* _DISP_ */
+
+
diff --git a/private/ntos/ndis/pcimac/event.h b/private/ntos/ndis/pcimac/event.h
new file mode 100644
index 000000000..5f4b55387
--- /dev/null
+++ b/private/ntos/ndis/pcimac/event.h
@@ -0,0 +1,31 @@
+/*
+ * EVENT.H - IDP Device Driver public header for PCIMAC/ISA
+ */
+
+#ifndef _EVENT_
+#define _EVENT_
+
+typedef struct
+{
+ ULONG Used;
+ struct _CM *cm;
+ ULONG Type;
+ ULONG State;
+ VOID (*Callback)();
+ IRP *Irp;
+} EVENTOBJECT;
+
+#define MAX_EVENTS 10
+
+
+ULONG EventInit (VOID);
+VOID EventTerm (VOID);
+UCHAR EventSet (CM *cm, CMD_EVENT *Event, IRP *Irp);
+VOID EventComplete (IRP *Irp);
+VOID EventCancel (DEVICE_OBJECT *DeviceObject, IRP *Irp);
+VOID StateEventCheck (VOID *cm_1);
+
+#define EVENT_E_SUCC 0
+
+
+#endif /* _EVENT_ */
diff --git a/private/ntos/ndis/pcimac/frame.h b/private/ntos/ndis/pcimac/frame.h
new file mode 100644
index 000000000..44c5cd04b
--- /dev/null
+++ b/private/ntos/ndis/pcimac/frame.h
@@ -0,0 +1,196 @@
+//
+// to build a version that does not support compression, commen out
+// this define.
+//
+#define COMPRESSION 1
+
+// when we pick up a frame, the coherency layer tells us
+// about the frame...
+// !!!!! NOTE: This is NOT an enumeration !!!!!!
+// Look carefully at the code before you change these values.
+#define FRAME_NOT_COMPRESSED 0
+#define FRAME_IS_FLUSH_FRAME 1
+#define FRAME_NEEDS_DECOMPRESSION 2
+#define FRAME_NEEDS_DECOMPRESSION_FLUSHING 3
+
+//
+// Set LSB if SW compression is ON
+//
+#define COMPRESSION_V1 1
+
+typedef UCHAR FRAME_TYPE;
+typedef UCHAR FRAME_TICKET;
+
+//
+// ISDN pads to 60, so we need 60-14 worth of data
+// before it is worth it to compress it! probably even more than that!
+//
+#define MINIMUM_COMPRESSED_PACKET_SIZE (60-14)
+
+#define COMPRESSED_HAS_REFERENCES 1
+#define COMPRESSED_NO_REFERENCES 2
+#define UNCOMPRESSED 3
+#define COMPRESSED 4 // generic compressed
+
+// BUG BUG should probably read this value from coherency code.
+// we give one byte to coherency
+#define COHERENCY_LENGTH 1
+
+typedef ULONG FRAME_ID;
+
+// !!!! NOTE !!!!
+// TransmittedUncompressed are the number of bytes that the compressor
+// saw BEFORE attempting to compress the data (top end)
+// TransmitCompressed is the bottom end of the compressor which
+// is equal to the amount of bytes the compressor spat out (after compression)
+// This only counts bytes that went THROUGH the compression mechanism
+// Small frames and multi-cast frames (typically) do not get compressed.
+typedef struct COMPRESSION_STATS COMPRESSION_STATS, *PCOMPRESSION_STATS;
+struct COMPRESSION_STATS {
+ ULONG BytesTransmittedUncompressed; // Compression info only
+ ULONG BytesReceivedUncompressed; // Compression info only
+ ULONG BytesTransmittedCompressed; // Compression info only
+ ULONG BytesReceivedCompressed; // Compression info only
+};
+
+typedef struct ASYNC_CONNECTION ASYNC_CONNECTION, *PASYNC_CONNECTION;
+typedef struct ASYNC_FRAME ASYNC_FRAME, *PASYNC_FRAME;
+
+typedef
+VOID
+(*PCOHERENT_DONE_FUNC) (
+ IN PASYNC_CONNECTION pAsyncConnection,
+ IN PASYNC_FRAME pAsyncFrame);
+
+
+struct ASYNC_CONNECTION {
+ // For me..
+ PVOID pAsyncInfo; // Back ptr.
+
+ // For compression
+ ULONG CompressionLength; // Length of Compression struct
+ PVOID CompressionContext; // Ptr to the Compression struct
+
+ COMPRESSION_STATS CompressionStats;
+
+ // For coherency
+ ULONG CoherencyLength; // Length of coherency struct
+ PVOID CoherencyContext; // Ptr to coherency struct
+
+ NDIS_SPIN_LOCK CompMutex; // Non-paged pool mutex
+
+ // These two values hold the size requested by the compression
+ // and coherent modules for their internal structures.
+ ULONG CompressStructSize;
+ ULONG CoherentStructSize;
+
+
+};
+
+struct ASYNC_FRAME {
+//---------------------------------------------------------------------------
+ // !!!!!!!! NOTE !!!!!!!!
+ // The FrameListEntry field must be first to
+ // dequeue things up properly so don't put anything
+ // in front of it or suffer severe crashes.
+ LIST_ENTRY FrameListEntry; // Used to queue up frames from
+ // the soon to be famous frame pool
+ // this frame's ID
+ FRAME_ID FrameID;
+
+ // For Dougie
+ // Should Decompressed Frame can be non-paged??
+ // i.e. Should I queue a worker thred to decompress??
+ UINT DecompressedFrameLength;// Length of decompressed frame
+ PUCHAR DecompressedFrame; // Ptr to the decompressed 'frame'
+ // valid only after decompression
+
+ // NOTE: If the frame is not compressed, the compressed fields
+ // are still valid when passed to Dave.
+ UINT CompressedFrameLength; // Length of compressed frame
+ PUCHAR CompressedFrame; // Ptr to the compressed 'frame'
+ // valid only after compression
+ // or just before decompression
+
+ PNDIS_PACKET CompressionPacket; // Valid just before compression
+ // this is the packet passed down.
+ // Use NdisQueryPacket.
+
+ PASYNC_CONNECTION Connection; // back ptr to connection struct
+
+ // For Coherency
+ PUCHAR CoherencyFrame; // Ptr to coherency frame
+ PCOHERENT_DONE_FUNC CoherentDone; // function ptr to call when done
+ // sending frame
+
+};
+
+// APIs to Compressor
+VOID
+CoherentDeliverFrame(
+ PASYNC_CONNECTION pConnection,
+ PASYNC_FRAME pFrame,
+ FRAME_TYPE FrameType);
+
+VOID
+CoherentGetPipeline(
+ PASYNC_CONNECTION pConnection,
+ PULONG plUnsent);
+
+
+// APIs to Transport/Network layer
+VOID
+CoherentSendFrame(
+ PASYNC_CONNECTION pConnection,
+ PASYNC_FRAME pFrame,
+ FRAME_TYPE FrameType);
+
+
+ULONG
+CoherentSizeOfStruct( );
+
+VOID
+CoherentInitStruct(
+ PVOID pCoherentStruct);
+
+// upcalls API's from Transport/Network layer
+VOID
+CoherentReceiveFrame(
+ PASYNC_CONNECTION pConnection,
+ PASYNC_FRAME pFrame);
+
+VOID
+CoherentDeliverFrameDone(
+ PASYNC_CONNECTION pConnection,
+ PASYNC_FRAME pFrame);
+
+
+
+ULONG
+CompressSizeOfStruct(
+ IN ULONG SendMode, // Compression
+ IN ULONG RecvMode, // Decompression
+ IN ULONG lfsz, // Largest frame size
+ OUT PULONG lcfsz); // Size of compression into buffer
+
+VOID
+CompressInitStruct(
+ ULONG SendMode, // Compression
+ ULONG RecvMode, // Decompression
+ PUCHAR memptr,
+ PNDIS_SPIN_LOCK pMutex); // Must be in non-paged pool
+
+VOID
+CompressFlush(
+ PASYNC_CONNECTION pAsyncConnection);
+
+VOID
+CompressFrame(
+ PASYNC_FRAME pAsyncFrame);
+
+VOID
+DecompressFrame(
+ PASYNC_CONNECTION pAsyncConnection,
+ PASYNC_FRAME pAsyncFrame,
+ BOOLEAN FlushBuffer);
+
diff --git a/private/ntos/ndis/pcimac/idd.h b/private/ntos/ndis/pcimac/idd.h
new file mode 100644
index 000000000..592ee8270
--- /dev/null
+++ b/private/ntos/ndis/pcimac/idd.h
@@ -0,0 +1,440 @@
+/*
+ * IDD.H - IDP Device Driver header
+ */
+
+#ifndef _IDD_
+#define _IDD_
+
+#include <idd_pub.h>
+
+
+/* idd error codes */
+#define IDD_E_SUCC 0
+#define IDD_E_NOMEM 1
+#define IDD_E_MEMERR 2
+#define IDD_E_NOSUCH 3
+#define IDD_E_NOROOM 4
+#define IDD_E_BADPORT 5
+#define IDD_E_IORERR 6
+#define IDD_E_IOWERR 7
+#define IDD_E_FMAPERR 8
+#define IDD_E_RUNERR 9
+#define IDD_E_PORTMAPERR 10
+#define IDD_E_PORTBINDERR 11
+#define IDD_E_PARTQINIT 12
+#define IDD_E_FAILINSTALL 13
+#define IDD_E_BUSY 14
+#define IDD_E_AREA 15
+
+//
+// Idd receive data framing types
+//
+#define DKF_UUS_SIG 0x50
+#define PPP_SIG_0 0xFF
+#define PPP_SIG_1 0x03
+
+/* IDD ports, rx/tx overlap! */
+#define IDD_PORT_B1_RX 0 /* recieve b1 data */
+#define IDD_PORT_B1_TX 0 /* trasmit b1 data */
+#define IDD_PORT_B2_RX 1 /* recieve b1 data */
+#define IDD_PORT_B2_TX 1 /* trasmit b1 data */
+#define IDD_PORT_U_RX 2 /* receive uart data */
+#define IDD_PORT_U_TX 2 /* trasmit uart data */
+#define IDD_PORT_CMD_RX 3 /* receive control messages */
+#define IDD_PORT_CMD_TX 3 /* trasmit control commands */
+#define IDD_PORT_CM0_RX 4 /* receive connection mgr events */
+#define IDD_PORT_CM0_TX 4 /* transmit connection mgr events */
+#define IDD_PORT_CM1_RX 5 /* ... on secondary tei (opt) */
+#define IDD_PORT_CM1_TX 5 /* ... on secondary tei (opt) */
+
+
+//
+// local idd def's
+//
+/* some max values */
+#define IDD_FNAME_LEN 128 /* size of a filename (path) */
+#define IDD_DEF_SIZE 1000 /* size of definition database */
+#define IDD_MAX_SEND (6*32) /* max # of pending send allowed */
+#define IDD_MAX_RECEIVE (6*32) /* max # of pending receives on adapter*/
+#define IDD_MAX_HAND (6*6) /* max # of receive handles allowed */
+#define IDD_RX_PORTS 6 /* # of recieve ports defined */
+#define IDD_TX_PORTS 6 /* # of transmit ports defined */
+#define IDD_TX_PARTQ 4 /* # of (buffer) partition queues for tx */
+#define IDD_PAGE_NONE (UCHAR)0xFF /* no page arg for idd__cpage */
+#define IDP_MAX_RX_BUFFER 350 /* stupid double buffer buffer */
+
+/* memory banks */
+#define IDD_BANK_BUF 0
+#define IDD_BANK_DATA 1
+#define IDD_BANK_CODE 2
+
+/* representation of physical hardware */
+typedef struct
+{
+ ULONG base_io; /* base i/o address */
+ ULONG base_mem; /* base memory address */
+ CHAR idp_bin[IDD_FNAME_LEN]; /* binary image filename */
+ NDIS_HANDLE fbin; /* idp bin file handle */
+ UINT fbin_len; /* length in bytes of idp bin file */
+} IDD_PHW;
+
+/* virualization of hardware, in os (ndis) terms */
+typedef struct
+{
+ ULONG vbase_io; // virtual i/o base
+ CHAR *vmem; /* virtual address for memory */
+} IDD_VHW;
+
+/* descriptor for a message to be sent on a port */
+typedef struct
+{
+ IDD_MSG msg; /* copy of user's message */
+ VOID (*handler)(); /* user's completion handler */
+ VOID *handler_arg; /* handler's argument */
+} IDD_SMSG;
+
+/* a queue for messages waiting to be sent */
+typedef struct
+{
+ IDD_SMSG *tbl; /* send message table address */
+ INT num; /* # of entries in queue */
+ INT max; /* max # of entries allowed/alloc */
+ INT put; /* put/insert index */
+ INT get; /* get/remove index */
+ NDIS_SPIN_LOCK lock; /* spin lock guarding access */
+} IDD_SENDQ;
+
+/* a descriptor for user's handler for a receiver port */
+typedef struct
+{
+ VOID (*handler)(); /* user's handler */
+ VOID *handler_arg; /* handler's argument */
+} IDD_RHAND;
+
+/* a table of user's handlers on a reciever port */
+typedef struct
+{
+ IDD_RHAND *tbl; /* table of receiver handlers */
+ ULONG RxFrameType; /* current receive framining mode */
+ INT num; /* # of entries in table */
+ INT max; /* max # of entries allowed/alloc */
+ NDIS_SPIN_LOCK lock; /* spin lock guarding access */
+} IDD_RECIT;
+
+/* idp low level (shared memory) command interface structure */
+#pragma pack(2)
+typedef struct
+{
+ UCHAR opcode; /* command opcode */
+#define IDP_L_MAP 0 /* - map a port name to id */
+#define IDP_L_READ 1 /* - read from a port */
+#define IDP_L_WRITE 2 /* - write to a port */
+#define IDP_L_BIND 3 /* - bind a port to a status bit */
+#define IDP_L_UNBIND 4 /* - unbind a port from a status bit */
+#define IDP_L_POLL 5 /* - poll a prot (check for read) */
+#define IDP_L_GET_WBUF 6 /* - get a write buffer */
+#define IDP_L_PUT_RBUF 7 /* - put (free) a read buffer */
+
+ UCHAR status; /* command status */
+#define IDP_S_PEND 0xFF /* - command pending */
+#define IDP_S_EXEC 0xFE /* - command is executing */
+#define IDP_S_OK 0x00 /* - command complted succ */
+#define IDP_S_NOPORT 0x01 /* - no such port error */
+#define IDP_S_NOMSG 0x02 /* - no messages error */
+#define IDP_S_NOBUF 0x03 /* - no local buffer error */
+#define IDP_S_NOBIT 0x04 /* - no status bit left error */
+#define IDP_S_BOUND 0x05 /* - port already bound error */
+#define IDP_S_NOTBOUND 0x06 /* - port not bound error */
+#define IDP_S_TIMEOUT 0x07 /* - command timed out error */
+#define IDP_S_DONE(s) (!(s & 0x80)) /* -command execution done (<0x80) */
+
+ USHORT port_id; /* related port identifier */
+ CHAR port_name[16]; /* related port name */
+ USHORT port_bitpatt; /* related port bit pattern */
+
+ UCHAR res[8]; /* 8 bytes of reserved area */
+
+ USHORT msg_opcode; /* message opcode (type) */
+ USHORT msg_buflen; /* related buffer length */
+ ULONG msg_bufptr; /* related buffer pointer (0=none) */
+ ULONG msg_bufid; /* related buffer id */
+ ULONG msg_param; /* parameter area */
+} IDP_CMD;
+#pragma pack()
+
+
+/* adp low level (shared memory) command interface structure */
+#pragma pack(2)
+typedef struct
+{
+ UCHAR opcode; /* command opcode */
+#define ADP_L_MAP 0 /* - map a port name to id */
+#define ADP_L_READ 1 /* - read from a port */
+#define ADP_L_WRITE 2 /* - write to a port */
+#define ADP_L_BIND 3 /* - bind a port to a status bit */
+#define ADP_L_UNBIND 4 /* - unbind a port from a status bit */
+#define ADP_L_POLL 5 /* - poll a prot (check for read) */
+#define ADP_L_GET_WBUF 6 /* - get a write buffer */
+#define ADP_L_PUT_RBUF 7 /* - put (free) a read buffer */
+
+ UCHAR status; /* command status */
+#define ADP_S_PEND 0xFF /* - command pending */
+#define ADP_S_EXEC 0xFE /* - command is executing */
+#define ADP_S_OK 0x00 /* - command complted succ */
+#define ADP_S_NOPORT 0x01 /* - no such port error */
+#define ADP_S_NOMSG 0x02 /* - no messages error */
+#define ADP_S_NOBUF 0x03 /* - no local buffer error */
+#define ADP_S_NOBIT 0x04 /* - no status bit left error */
+#define ADP_S_BOUND 0x05 /* - port already bound error */
+#define ADP_S_NOTBOUND 0x06 /* - port not bound error */
+#define ADP_S_TIMEOUT 0x07 /* - command timed out error */
+#define ADP_S_DONE(s) (!(s & 0x80)) /* -command execution done (<0x80) */
+
+ USHORT port_id; /* related port identifier */
+ CHAR port_name[8]; /* related port name */
+ USHORT port_bitpatt; /* related port bit pattern */
+
+ USHORT msg_opcode; /* message opcode (type) */
+ USHORT msg_buflen; /* related buffer length */
+ CHAR *msg_bufptr; /* related buffer pointer (0=none) */
+ ULONG msg_bufid; /* related buffer id */
+ ULONG msg_param; /* parameter area */
+} ADP_CMD;
+#pragma pack()
+
+typedef struct tagIDD_LINESTATE
+{
+ ULONG LineActive; /* is this idd's line active */
+ ULONG L1TxState; /* Layer 1 Tx state */
+ ULONG L1RxState; /* Layer 1 Rx state */
+ ULONG L2State; /* Layer 2 State */
+ ULONG L3State; /* Layer 3 State */
+ ULONG L3ServiceState; /* Layer 3 Service State */
+}IDD_LINESTATE;
+
+typedef struct tagIDD_CALLINFO
+{
+ ULONG ChannelsUsed; /* # of bchans used on this idd */
+ ULONG NumLTerms; /* # of lterms 1/2 */
+ VOID* cm[2]; /* cm that is using an lterm */
+}IDD_CALLINFO;
+
+#ifdef DBG
+typedef struct
+{
+ INT Count;
+ ULONG Put;
+ ULONG Get;
+ ULONG TxState;
+ ULONG FragsSinceBegin;
+ ULONG Buffer[32];
+}BUFFER_MANAGER;
+#endif
+
+/* IDD object */
+typedef struct _IDD
+{
+ USHORT state; /* IDD object state */
+#define IDD_S_INIT 0 /* - initial state */
+#define IDD_S_CHECK 1 /* - in check hardware phase */
+#define IDD_S_STARTUP 2 /* - in startup */
+#define IDD_S_RUN 3 /* - now running */
+#define IDD_S_SHUTDOWN 4 /* - in shutdown */
+
+#ifdef DBG
+ BUFFER_MANAGER BufferStuff[4];
+#endif
+
+ ULONG WaitCounter;
+ ULONG MaxWaitCounter;
+
+ USHORT AbortReason;
+
+ NDIS_SPIN_LOCK lock; /* spin lock guarding access to obj */
+
+ NDIS_HANDLE adapter_handle; /* related adapter handle */
+
+ IDD_PHW phw; /* physical hardware */
+ IDD_VHW vhw; /* virtualization of hardware */
+
+ IDD_SENDQ sendq[IDD_TX_PORTS]; /* send queues for tx ports */
+ IDD_SMSG smsg_pool[IDD_MAX_SEND]; /* pool of smsgs for sendqs */
+
+ IDD_RECIT recit[IDD_RX_PORTS]; /* receive table for rx ports */
+ IDD_RHAND rhand_pool[IDD_MAX_HAND]; /* pool or rhand for recit table */
+
+ USHORT rx_port[IDD_RX_PORTS]; /* port id's in idp terms for rx */
+ USHORT tx_port[IDD_TX_PORTS]; /* ... for tx */
+ ULONG rx_buf; /* id for last received (old) buffer from idp */
+ ULONG tx_buf[IDD_TX_PARTQ]; /* (new) tx buffer as idp bufids */
+ USHORT tx_partq[IDD_TX_PORTS]; /* related memory parition queues */
+
+ IDP_CMD volatile *IdpCmd; /* pointer to idp command struct */
+ USHORT volatile *IdpStat; /* pointer to status register */
+ UCHAR volatile *IdpEnv; /* pointer to status register */
+
+ ADP_CMD AdpCmd; /* pointer to adp command struct */
+ USHORT AdpStat; /* pointer to status register */
+
+ SEMA proc_sema; /* processing sema */
+
+ CHAR name[64]; /* name (device name?) */
+ USHORT btype; /* board type idd related to */
+ USHORT bnumber; /* board number of this idd */
+ USHORT bline; /* line index inside board */
+
+ IDD_CALLINFO CallInfo; /* information about active calls */
+
+ IDD_LINESTATE LineState; /* structure of idd state info */
+
+ VOID *res_mem; /* resource mgr handle for memory */
+ VOID *res_io; /* resource mgr handle for i/o */
+
+ ULONG (*CheckIO)(); /* Check Base I/O */
+ ULONG (*CheckMem)(); /* Check Base Mem */
+ VOID (*SetBank)(); /* set memory bank */
+ VOID (*SetPage)(); /* set memory page - or none */
+ VOID (*SetBasemem)(); /* set base memory address */
+ INT (*LoadCode)(); /* load the adapter */
+ ULONG (*PollTx)(); /* poll the adapter for xmits*/
+ ULONG (*PollRx)(); /* poll the adapter for recvs */
+ UCHAR (*Execute)(); /* Execute a command */
+ VOID (*OutToPort)(); /* Write Char to port*/
+ UCHAR (*InFromPort)(); /* Read Char from port*/
+ USHORT (*ApiGetPort)(); /* Get Port ID from adapter*/
+ INT (*ApiBindPort)(); /* Bind a Port to a status bit*/
+ ULONG (*ApiAllocBuffer)(); /* Get a buffer from the adapter*/
+ VOID (*ResetAdapter)(); /* Reset the adapter*/
+ USHORT (*NVRamRead)(); /* Read Adapters NVRam*/
+ VOID (*ChangePage)(); /* Change Memory Page on Adapter*/
+
+ IDD_AREA Area; /* idd area storage */
+
+ VOID *trc; /* related trace object */
+
+ UCHAR DefinitionTable[IDD_DEF_SIZE]; /* init definition database */
+ USHORT DefinitionTableLength; /* length of definition database */
+
+ UCHAR RxBuffer[IDP_MAX_RX_BUFFER]; /* receive storage */
+} IDD;
+
+
+/* IDD object operation prototypes */
+INT idd_create(VOID** ret_idd, USHORT btype);
+INT idd_destroy(VOID* idd_1);
+INT idd_set_base_io(VOID* idd_1, USHORT base_io);
+INT idd_set_base_mem(VOID* idd_1, ULONG base_mem, CHAR* vmem);
+INT idd_set_idp_bin(VOID* idd_1, CHAR* idp_bin);
+INT idd_add_def(IDD *idd, CHAR* name, CHAR* val);
+INT idd_get_nvram(VOID *idd_1, USHORT addr, USHORT* val);
+INT idd_check(VOID* idd_1);
+INT idd_startup(VOID* idd_1);
+INT idd_shutdown(VOID* idd_1);
+ULONG idd_process(IDD* idd, UCHAR TxOnly);
+INT idd_send_msg(VOID* idd_1, IDD_MSG *msg, USHORT port,
+ VOID (*handler)(), VOID* handler_arg);
+INT idd_attach(VOID* idd_1, USHORT port,
+ VOID (*handler)(), VOID* handler_arg);
+INT idd_detach(VOID* idd_1, USHORT port,
+ VOID (*handler)(), VOID* handler_arg);
+CHAR* idd_get_name(VOID* idd_1);
+ULONG idd_get_baseio(VOID* idd_1);
+ULONG idd_get_basemem(VOID* idd_1);
+USHORT idd_get_btype(VOID* idd_1);
+USHORT idd_get_bline(VOID* idd_1);
+VOID* idd_get_trc(VOID *idd_1);
+VOID idd_set_trc(VOID *idd_1, VOID *Trace);
+INT idd_install(NDIS_HANDLE adapter_handle);
+INT idd_remove(NDIS_HANDLE adapter_handle);
+VOID idd_start_timers(VOID* Adapter_1);
+INT idd_reset_area(VOID* idd_1);
+INT idd_get_area(VOID* idd_1, ULONG area_id, VOID(*handler)(), VOID*handler_arg);
+INT idd_get_area_stat(VOID* idd_1, IDD_AREA *IddStat);
+VOID IddSetRxFraming(VOID* idd_1, USHORT port, ULONG FrameType);
+
+VOID IddPollFunction(VOID* a1, VOID* Adapter_1, VOID* a3, VOID* a4);
+VOID LineStateTimerTick(VOID* a1, VOID* Adapter_1, VOID* a3, VOID *a4);
+VOID idd__cmd_handler(IDD *idd, USHORT chan, ULONG Reserved, IDD_MSG* msg);
+VOID DetectFramingHandler(IDD *idd, USHORT chan, ULONG IddRxFrameType, IDD_XMSG *msg);
+
+ULONG EnumIddInSystem(VOID);
+ULONG EnumIddPerAdapter(VOID *Adapter_1);
+IDD* GetIddByIndex(ULONG);
+INT IoEnumIdd(VOID *cmd);
+ULONG idd_init(VOID);
+
+INT IdpLoadCode(IDD* idd);
+INT AdpLoadCode(IDD* idd);
+INT IdpBindPort(IDD* idd, USHORT port, USHORT bitpatt);
+INT AdpBindPort(IDD* idd, USHORT port, USHORT bitpatt);
+INT IdpResetBoard(IDD* idd);
+INT AdpResetBoard(IDD* idd);
+ULONG IdpAllocBuf(IDD*, INT);
+ULONG AdpAllocBuf(IDD*, INT);
+USHORT IdpGetPort(IDD *idd, CHAR name[8]);
+USHORT AdpGetPort(IDD *idd, CHAR name[8]);
+ULONG IdpCheckIO(IDD*);
+ULONG AdpCheckIO(IDD*);
+ULONG IdpCheckMem(IDD*);
+ULONG AdpCheckMem(IDD*);
+
+/* board specific routines */
+VOID IdpPcSetBank(IDD* idd, UCHAR bank, UCHAR run);
+VOID IdpPc4SetBank(IDD* idd, UCHAR bank, UCHAR run);
+VOID IdpMcSetBank(IDD* idd, UCHAR bank, UCHAR run);
+VOID AdpSetBank(IDD* idd, UCHAR bank, UCHAR run);
+VOID IdpPcSetPage(IDD* idd, UCHAR page);
+VOID IdpPc4SetPage(IDD* idd, UCHAR page);
+VOID IdpMcSetPage(IDD* idd, UCHAR page);
+VOID AdpSetPage(IDD* idd, UCHAR page);
+VOID IdpPcSetBasemem(IDD* idd, ULONG basemem);
+VOID IdpPc4SetBasemem(IDD* idd, ULONG basemem);
+VOID IdpMcSetBasemem(IDD* idd, ULONG basemem);
+VOID AdpSetBasemem(IDD* idd, ULONG basemem);
+
+UCHAR IdpInp(IDD* idd, USHORT port);
+UCHAR AdpInp(IDD* idd, USHORT port);
+VOID IdpOutp(IDD* idd, USHORT port, UCHAR val);
+VOID AdpOutp(IDD* idd, USHORT port, UCHAR val);
+ULONG IdpPollTx(IDD* idd);
+ULONG AdpPollTx(IDD* idd);
+ULONG IdpPollRx(IDD* idd);
+ULONG AdpPollRx(IDD* idd);
+UCHAR IdpExec(IDD *idd, UCHAR opcode);
+UCHAR AdpExec(IDD *idd, UCHAR opcode);
+VOID IdpCPage(IDD *idd, UCHAR page);
+VOID AdpCPage(IDD *idd, UCHAR page);
+USHORT IdpNVRead(IDD* idd, USHORT addr);
+USHORT AdpNVRead(IDD* idd, USHORT addr);
+VOID IdpNVWrite(IDD* idd, USHORT addr, USHORT val);
+VOID AdpNVWrite(IDD* idd, USHORT addr, USHORT val);
+VOID IdpNVErase(IDD* idd);
+VOID AdpNVErase(IDD* idd);
+VOID IdpMemset(UCHAR* dst, USHORT val, int size);
+VOID AdpMemset(UCHAR* dst, USHORT val, int size);
+VOID IdpMemcpy(UCHAR* dst, UCHAR* src, int size);
+VOID AdpMemcpy(UCHAR* dst, UCHAR* src, int size);
+USHORT IdpCopyin(IDD* idd, UCHAR* dst, UCHAR* src, USHORT src_len);
+USHORT AdpCopyin(IDD* idd, UCHAR* src, USHORT src_len);
+
+VOID AdpWriteControlBit (IDD *idd, UCHAR Bit, UCHAR Value);
+VOID AdpPutBuffer (IDD *idd, ULONG Destination, PUCHAR Source, USHORT Length);
+VOID AdpGetBuffer (IDD *idd, PUCHAR Destination, ULONG Source, USHORT Length);
+VOID AdpWriteCommandStatus(IDD *idd, UCHAR Value);
+UCHAR AdpReadCommandStatus(IDD *idd);
+VOID AdpSetAddress(IDD *idd, ULONG Address);
+VOID AdpPutUByte(IDD *idd, ULONG Address, UCHAR Value);
+VOID AdpPutUShort(IDD *idd, ULONG Address, USHORT Value);
+VOID AdpPutULong(IDD *idd, ULONG Address, ULONG Value);
+UCHAR AdpGetUByte(IDD *idd, ULONG Address);
+USHORT AdpGetUShort(IDD *idd, ULONG Address);
+ULONG AdpGetULong(IDD *idd, ULONG Address);
+UCHAR AdpReadReceiveStatus(IDD *idd);
+UCHAR IdpGetUByteIO(IDD* idd, USHORT port);
+VOID IdpGetBuffer(IDD* idd, ULONG Bank, ULONG Page, ULONG Address, USHORT Length, PUCHAR Buffer);
+VOID IdpPutUByteIO(IDD* idd, USHORT Port, UCHAR Value);
+VOID IdpPutBuffer(IDD* idd, ULONG Bank, ULONG Page, ULONG Address, USHORT Length, PUCHAR Buffer);
+VOID IddGetDataFromAdapter(VOID *idd_1, PUCHAR Destination, PUCHAR Source, USHORT Length);
+VOID LineStateHandler(VOID* idd_1, ULONG AreaId, CHAR* AreaBuffer, ULONG BufferLen);
+
+#endif /* _IDD_ */
diff --git a/private/ntos/ndis/pcimac/idd_init.c b/private/ntos/ndis/pcimac/idd_init.c
new file mode 100644
index 000000000..998b73a72
--- /dev/null
+++ b/private/ntos/ndis/pcimac/idd_init.c
@@ -0,0 +1,909 @@
+/*
+ * IDD_INIT.C - IDD initialization
+ */
+
+#include <ndis.h>
+//#include <ndismini.h>
+#include <ndiswan.h>
+#include <ndistapi.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+#include <res.h>
+#include <trc.h>
+#include <io.h>
+
+//IDD* IddTbl[MAX_IDD_IN_SYSTEM];
+typedef struct
+{
+ NDIS_SPIN_LOCK lock;
+ ULONG NumberOfIddsInSystem;
+ ULONG LastIddPolled;
+ ADAPTER *CurrentAdapter;
+ ADAPTER *LastAdapter;
+ IDD* Idd[MAX_IDD_IN_SYSTEM];
+}IDD_TABLE;
+
+IDD_TABLE IddTbl;
+
+BOOLEAN IsThisAdapterNext(ADAPTER *Adapter);
+
+/* driver global vars */
+extern DRIVER_BLOCK Pcimac;
+
+#ifdef OLD
+ULONG
+EnumIddInSystem()
+{
+ ULONG n;
+
+ for (n = 0; n < MAX_IDD_IN_SYSTEM; n++)
+ {
+ if (IddTbl[n] == NULL)
+ break;
+ }
+ return(n);
+}
+
+IDD*
+GetIddByIndex(
+ ULONG Index
+ )
+{
+ return(IddTbl[Index]);
+}
+
+#endif
+
+ULONG
+EnumIddInSystem()
+{
+ ULONG NumberOfIddsInSystem;
+
+ NdisAcquireSpinLock(&IddTbl.lock);
+
+ NumberOfIddsInSystem = IddTbl.NumberOfIddsInSystem;
+
+ NdisReleaseSpinLock(&IddTbl.lock);
+
+ return(NumberOfIddsInSystem);
+}
+
+IDD*
+GetIddByIndex(
+ ULONG Index
+ )
+{
+ IDD *idd;
+
+ NdisAcquireSpinLock(&IddTbl.lock);
+
+ idd = IddTbl.Idd[Index];
+
+ NdisReleaseSpinLock(&IddTbl.lock);
+
+ return(idd);
+}
+
+ULONG
+EnumIddPerAdapter(
+ VOID *Adapter_1
+ )
+{
+ ADAPTER *Adapter = (ADAPTER*)Adapter_1;
+
+ return(Adapter->NumberOfIddOnAdapter);
+}
+
+
+INT
+IoEnumIdd(VOID *cmd_1)
+{
+ ULONG n;
+ IO_CMD *cmd = (IO_CMD*)cmd_1;
+
+ NdisAcquireSpinLock(&IddTbl.lock);
+
+ cmd->val.enum_idd.num = (USHORT)IddTbl.NumberOfIddsInSystem;
+
+ for (n = 0; n < IddTbl.NumberOfIddsInSystem; n++)
+ {
+ IDD *idd;
+
+ idd = cmd->val.enum_idd.tbl[n] = IddTbl.Idd[n];
+
+ NdisMoveMemory(&cmd->val.enum_idd.name[n],
+ idd->name,
+ sizeof(cmd->val.enum_idd.name[n]));
+ }
+
+ NdisReleaseSpinLock(&IddTbl.lock);
+
+ return(0);
+}
+
+#pragma NDIS_INIT_FUNCTION(idd_init)
+
+ULONG
+idd_init(VOID)
+{
+ //
+ // clear out idd table
+ //
+ NdisZeroMemory(&IddTbl, sizeof(IDD_TABLE));
+
+ NdisAllocateSpinLock(&IddTbl.lock);
+
+ return(IDD_E_SUCC);
+}
+
+#pragma NDIS_INIT_FUNCTION(idd_create)
+
+/* allocate & initialize an idd object */
+INT
+idd_create(VOID **ret_idd, USHORT btype)
+{
+ IDD *idd;
+ INT n;
+ NDIS_PHYSICAL_ADDRESS pa = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
+
+ D_LOG(D_ENTRY, ("idd_create: BoardType: %d", btype));
+
+ /* allocate memory object */
+ NdisAllocateMemory((PVOID*)&idd, sizeof(IDD), 0, pa);
+ if ( !idd )
+ {
+ D_LOG(D_ALWAYS, ("idd_create: memory allocate failed!"));
+ return(IDD_E_NOMEM);
+ }
+
+ NdisAcquireSpinLock(&IddTbl.lock);
+
+ //
+ // store idd in system idd table
+ //
+ for (n = 0; n < MAX_IDD_IN_SYSTEM; n++)
+ if (!IddTbl.Idd[n])
+ break;
+
+ if (n >= MAX_IDD_IN_SYSTEM)
+ {
+ /* free memory for idd */
+ NdisFreeMemory(idd, sizeof(*idd), 0);
+
+ NdisReleaseSpinLock(&IddTbl.lock);
+
+ return(IDD_E_NOROOM);
+ }
+
+ IddTbl.Idd[n] = idd;
+ IddTbl.NumberOfIddsInSystem++;
+
+ NdisReleaseSpinLock(&IddTbl.lock);
+
+ D_LOG(D_ALWAYS, ("idd_create: idd: 0x%p", idd));
+ NdisZeroMemory(idd, sizeof(IDD));
+
+ /* setup init state, adapter handle */
+ idd->state = IDD_S_INIT;
+ idd->trc = NULL;
+
+ /* allocate root spinlock */
+ NdisAllocateSpinLock(&idd->lock);
+
+ /* initialize send queues */
+ for ( n = 0 ; n < IDD_TX_PORTS ; n++ )
+ {
+ INT max;
+ /* initialize queue */
+ idd->sendq[n].max = max = IDD_MAX_SEND / IDD_TX_PORTS;
+
+ idd->sendq[n].tbl = idd->smsg_pool + max * n;
+
+ /* allocate spin lock */
+ NdisAllocateSpinLock(&idd->sendq[n].lock);
+ }
+
+ /* initialize receiver tables */
+ for ( n = 0 ; n < IDD_RX_PORTS ; n++ )
+ {
+ INT max;
+
+ /* initialize table */
+ idd->recit[n].max = max = IDD_MAX_HAND / IDD_RX_PORTS;
+ idd->recit[n].tbl = idd->rhand_pool + max * n;
+
+ /* allocate spin lock */
+ NdisAllocateSpinLock(&idd->recit[n].lock);
+ }
+
+ /* initialize board specific functions */
+ switch ( btype )
+ {
+ case IDD_BT_PCIMAC :
+ idd->CheckIO = (VOID*)IdpCheckIO;
+ idd->CheckMem = (VOID*)IdpCheckMem;
+ idd->SetBank = (VOID*)IdpPcSetBank;
+ idd->SetPage = (VOID*)IdpPcSetPage;
+ idd->SetBasemem = (VOID*)IdpPcSetBasemem;
+ idd->LoadCode = (VOID*)IdpLoadCode;
+ idd->PollTx = (VOID*)IdpPollTx;
+ idd->PollRx = (VOID*)IdpPollRx;
+ idd->Execute = (VOID*)IdpExec;
+ idd->OutToPort = (VOID*)IdpOutp;
+ idd->InFromPort = (VOID*)IdpInp;
+ idd->ApiGetPort = (VOID*)IdpGetPort;
+ idd->ApiBindPort = (VOID*)IdpBindPort;
+ idd->ApiAllocBuffer = (VOID*)IdpAllocBuf;
+ idd->ResetAdapter = (VOID*)IdpResetBoard;
+ idd->NVRamRead = (VOID*)IdpNVRead;
+ idd->ChangePage = (VOID*)IdpCPage;
+ break;
+
+ case IDD_BT_PCIMAC4 :
+ idd->SetBank = (VOID*)IdpPc4SetBank;
+ idd->SetPage = (VOID*)IdpPc4SetPage;
+ idd->SetBasemem = (VOID*)IdpPc4SetBasemem;
+ idd->CheckIO = (VOID*)IdpCheckIO;
+ idd->CheckMem = (VOID*)IdpCheckMem;
+ idd->LoadCode = (VOID*)IdpLoadCode;
+ idd->PollTx = (VOID*)IdpPollTx;
+ idd->PollRx = (VOID*)IdpPollRx;
+ idd->Execute = (VOID*)IdpExec;
+ idd->OutToPort = (VOID*)IdpOutp;
+ idd->InFromPort = (VOID*)IdpInp;
+ idd->ApiGetPort = (VOID*)IdpGetPort;
+ idd->ApiBindPort = (VOID*)IdpBindPort;
+ idd->ApiAllocBuffer = (VOID*)IdpAllocBuf;
+ idd->ResetAdapter = (VOID*)IdpResetBoard;
+ idd->NVRamRead = (VOID*)IdpNVRead;
+ idd->ChangePage = (VOID*)IdpCPage;
+ break;
+
+ case IDD_BT_MCIMAC :
+ idd->SetBank = (VOID*)IdpMcSetBank;
+ idd->SetPage = (VOID*)IdpMcSetPage;
+ idd->SetBasemem = (VOID*)IdpMcSetBasemem;
+ idd->CheckIO = (VOID*)IdpCheckIO;
+ idd->CheckMem = (VOID*)IdpCheckMem;
+ idd->LoadCode = (VOID*)IdpLoadCode;
+ idd->PollTx = (VOID*)IdpPollTx;
+ idd->PollRx = (VOID*)IdpPollRx;
+ idd->Execute = (VOID*)IdpExec;
+ idd->OutToPort = (VOID*)IdpOutp;
+ idd->InFromPort = (VOID*)IdpInp;
+ idd->ApiGetPort = (VOID*)IdpGetPort;
+ idd->ApiBindPort = (VOID*)IdpBindPort;
+ idd->ApiAllocBuffer = (VOID*)IdpAllocBuf;
+ idd->ResetAdapter = (VOID*)IdpResetBoard;
+ idd->NVRamRead = (VOID*)IdpNVRead;
+ idd->ChangePage = (VOID*)IdpCPage;
+ break;
+
+ case IDD_BT_DATAFIREU :
+ idd->SetBank = (VOID*)AdpSetBank;
+ idd->SetPage = (VOID*)AdpSetPage;
+ idd->SetBasemem = (VOID*)AdpSetBasemem;
+ idd->CheckIO = (VOID*)AdpCheckIO;
+ idd->CheckMem = (VOID*)AdpCheckMem;
+ idd->LoadCode = (VOID*)AdpLoadCode;
+ idd->PollTx = (VOID*)AdpPollTx;
+ idd->PollRx = (VOID*)AdpPollRx;
+ idd->Execute = (VOID*)AdpExec;
+ idd->OutToPort = (VOID*)AdpOutp;
+ idd->InFromPort = (VOID*)AdpInp;
+ idd->ApiGetPort = (VOID*)AdpGetPort;
+ idd->ApiBindPort = (VOID*)AdpBindPort;
+ idd->ApiAllocBuffer = (VOID*)AdpAllocBuf;
+ idd->ResetAdapter = (VOID*)AdpResetBoard;
+ idd->NVRamRead = (VOID*)AdpNVRead;
+ idd->ChangePage = (VOID*)AdpCPage;
+ break;
+ }
+
+
+ /* init sema */
+ sema_init(&idd->proc_sema);
+
+ //
+ // attach idd frame detection handlers
+ // these must be attached 1st for all data handlers
+ //
+ idd_attach(idd, IDD_PORT_B1_RX, (VOID*)DetectFramingHandler, idd);
+ idd_attach(idd, IDD_PORT_B2_RX, (VOID*)DetectFramingHandler, idd);
+
+ // attach a command handler to get area info from idp
+ idd_attach (idd, IDD_PORT_CMD_RX, (VOID*)idd__cmd_handler, idd);
+
+ /* return address & success */
+ *ret_idd = idd;
+ D_LOG(D_EXIT, ("idd_create: exit"));
+ return(IDD_E_SUCC);
+}
+
+/* free idd object */
+INT
+idd_destroy(VOID *idd_1)
+{
+ IDD *idd = (IDD*)idd_1;
+ INT n;
+
+ D_LOG(D_ENTRY, ("idd_destroy: entry, idd: 0x%p", idd));
+
+ // detach command handler from this idd
+ idd_detach (idd, IDD_PORT_CMD_RX, (VOID*)idd__cmd_handler, idd);
+
+ /* perform a shutdown (maybe null) */
+ idd_shutdown(idd);
+
+ /* if file handle for binary file open, close it */
+ if ( idd->phw.fbin )
+ NdisCloseFile(idd->phw.fbin);
+
+ /* free spin locks for send queue */
+ for ( n = 0 ; n < IDD_TX_PORTS ; n++ )
+ NdisFreeSpinLock(&idd->sendq[n].lock);
+
+ /* free spin locks for reciever tables */
+ for ( n = 0 ; n < IDD_RX_PORTS ; n++ )
+ NdisFreeSpinLock(&idd->recit[n].lock);
+
+ /* free resource handles */
+ if ( idd->res_io != NULL)
+ res_destroy(idd->res_io);
+
+ if ( idd->res_mem != NULL)
+ res_destroy(idd->res_mem);
+
+ // free trc object
+ if (idd->trc != NULL)
+ {
+ trc_deregister_idd(idd);
+ trc_destroy (idd->trc);
+ }
+
+ /* term sema */
+ sema_term(&idd->proc_sema);
+
+ /* free spinlock (while allocated!) */
+ NdisFreeSpinLock(&idd->lock);
+
+ NdisAcquireSpinLock(&IddTbl.lock);
+
+ //
+ // store idd in system idd table
+ //
+ for (n = 0; n < MAX_IDD_IN_SYSTEM; n++)
+ if (IddTbl.Idd[n] == idd)
+ break;
+
+ if (n < MAX_IDD_IN_SYSTEM)
+ IddTbl.Idd[n] = NULL;
+
+ IddTbl.NumberOfIddsInSystem--;
+
+ NdisReleaseSpinLock(&IddTbl.lock);
+
+ /* free memory for idd */
+ NdisFreeMemory(idd, sizeof(*idd), 0);
+
+
+ /* return success */
+ D_LOG(D_EXIT, ("idd_destroy: exit"));
+ return(IDD_E_SUCC);
+}
+
+
+//#ifdef PERADAPTER
+
+VOID
+IddPollFunction(
+ VOID *a1,
+ VOID *Adapter_1,
+ VOID *a3,
+ VOID *a4
+ )
+{
+#define MAX_EVENTS 1000
+ ULONG i, j, EventNum, TotalEventNum = 0;
+ ULONG FirstIdd, NumberOfIddOnAdapter;
+ ADAPTER *Adapter = (ADAPTER*)Adapter_1;
+ IDD *idd;
+
+ //
+ // check to see if there is someone else already polling
+ // an adapter that has the same shared memory window
+ // as this adapter. if someone is then get out so that we
+ // don't burn up this processor waiting for the other to complete
+ // if this adapter is supposed to be the next adapter to be polled
+ // only send him away for awhile, else send him away for normal polling
+ // time
+ //
+ if (CheckInDriverFlag(Adapter))
+ {
+ if (IsThisAdapterNext(Adapter))
+ {
+ //
+ // we want to come back asap
+ //
+ NdisMSetTimer(&Adapter->IddPollTimer, 0);
+ }
+ else
+ {
+ //
+ // we want to come back at our regular time
+ //
+ NdisMSetTimer(&Adapter->IddPollTimer, IDD_POLL_T);
+ }
+ return;
+ }
+
+ SetInDriverFlag(Adapter);
+
+ //
+ // this will be the first idd that we will poll
+ //
+ FirstIdd = Adapter->LastIddPolled;
+
+ //
+ // this will be the number of idds that we will poll
+ //
+ NumberOfIddOnAdapter = Adapter->NumberOfIddOnAdapter;
+
+ do
+ {
+ EventNum = 0;
+
+ //
+ // we will service all of the idd's in the system
+ // first lets do some receives
+ //
+
+ for (i = FirstIdd, j = FirstIdd + NumberOfIddOnAdapter; i < j; i++)
+ {
+ idd = Adapter->IddTbl[i % NumberOfIddOnAdapter];
+
+ if (idd && (idd->state == IDD_S_RUN))
+ EventNum += idd->PollRx(idd);
+ }
+
+
+ //
+ // we will service all of the idd's in the system
+ // now lets do the send queue
+ //
+ for (i = FirstIdd, j = FirstIdd + NumberOfIddOnAdapter; i < j; i++)
+ {
+ idd = Adapter->IddTbl[i % NumberOfIddOnAdapter];
+
+ if (idd && (idd->state == IDD_S_RUN))
+ {
+ EventNum += idd->PollTx(idd);
+ EventNum += idd->PollRx(idd);
+ }
+ }
+
+ TotalEventNum += EventNum;
+
+ } while (EventNum && (TotalEventNum < MAX_EVENTS) );
+
+ //
+ // bump so we start at next idd next time
+ //
+ Adapter->LastIddPolled++;
+
+ if (Adapter->LastIddPolled == NumberOfIddOnAdapter)
+ Adapter->LastIddPolled = 0;
+
+ ClearInDriverFlag(Adapter);
+
+ NdisMSetTimer(&Adapter->IddPollTimer, IDD_POLL_T);
+
+ //
+ // lets go ahead and give some of this data up to the wrapper
+ // hopefully this will keep us from running out of room in our
+ // assembly descriptor table
+ //
+ TryToIndicateMtlReceives(Adapter);
+}
+
+//#endif
+
+BOOLEAN
+IsThisAdapterNext(
+ ADAPTER *Adapter
+ )
+{
+ BOOLEAN ThisIsIt = FALSE;
+
+ NdisAcquireSpinLock(&Pcimac.lock);
+
+ if (Adapter == Pcimac.AdapterTbl[Pcimac.NextAdapterToPoll])
+ ThisIsIt = TRUE;
+
+ NdisReleaseSpinLock(&Pcimac.lock);
+
+ return(ThisIsIt);
+}
+
+
+#ifdef ALLADAPTERS
+VOID
+IddPollFunction(
+ VOID *a1,
+ VOID *Adapter_1,
+ VOID *a3,
+ VOID *a4
+ )
+{
+#define MAX_EVENTS 1000
+ ULONG i, j, EventNum, TotalEventNum = 0;
+ ULONG FirstIdd, NumberOfIddsInSystem;
+ ADAPTER *Adapter = (ADAPTER*)Adapter_1;
+ IDD *idd;
+
+
+ NdisAcquireSpinLock(&IddTbl.lock);
+
+ IddTbl.LastAdapter = IddTbl.CurrentAdapter;
+
+ IddTbl.CurrentAdapter = Adapter;
+
+ //
+ // this will be the first idd that we will poll
+ //
+ FirstIdd = IddTbl.LastIddPolled;
+
+ //
+ // this will be the number of idds that we will poll
+ //
+ NumberOfIddsInSystem = IddTbl.NumberOfIddsInSystem;
+
+ do
+ {
+ EventNum = 0;
+
+ //
+ // we will service all of the idd's in the system
+ // first lets do some receives
+ //
+ for (i = FirstIdd, j = FirstIdd + NumberOfIddsInSystem; i < j; i++)
+ {
+ idd = IddTbl.Idd[i % NumberOfIddsInSystem];
+
+ if (idd->state == IDD_S_RUN)
+ EventNum += idd->PollRx(idd);
+ }
+
+ //
+ // we will service all of the idd's in the system
+ // now lets do the send queue
+ //
+ for (i = FirstIdd, j = FirstIdd + NumberOfIddsInSystem; i < j; i++)
+ {
+ idd = IddTbl.Idd[i % NumberOfIddsInSystem];
+
+ if (idd->state == IDD_S_RUN)
+ {
+ EventNum += idd->PollTx(idd);
+ EventNum += idd->PollRx(idd);
+ }
+ }
+
+ TotalEventNum += EventNum;
+
+ } while (EventNum && (TotalEventNum < MAX_EVENTS) );
+
+ IddTbl.LastIddPolled++;
+
+ if (IddTbl.LastIddPolled == NumberOfIddsInSystem)
+ IddTbl.LastIddPolled = 0;
+
+ NdisReleaseSpinLock(&IddTbl.lock);
+
+ //
+ // lets go ahead and give some of this data up to the wrapper
+ // hopefully this will keep us from running out of room in our
+ // assembly descriptor table
+ //
+// TryToIndicateMtlReceives(Adapter);
+
+ NdisMSetTimer(&Adapter->IddPollTimer, IDD_POLL_T);
+}
+
+#endif
+
+#ifdef OLD
+VOID
+IddPollFunction(
+ VOID *a1,
+ VOID *Adapter_1,
+ VOID *a3,
+ VOID *a4
+ )
+{
+#define MAX_EVENTS 1000
+ ULONG n, EventNum, TotalEventNum = 0;
+
+ ADAPTER *Adapter = (ADAPTER*)Adapter_1;
+
+ do
+ {
+ EventNum = 0;
+
+ //
+ // we will service all of the idd's in the system
+ // first lets do some receives
+ //
+ for (n = 0; n < MAX_IDD_IN_SYSTEM; n++)
+ {
+ IDD *idd = IddTbl[n];
+
+ if (idd && (idd->state == IDD_S_RUN))
+ EventNum += idd->PollRx(idd);
+ }
+
+ //
+ // we will service all of the idd's in the system
+ // now lets do the send queue
+ //
+ for (n = 0; n < MAX_IDD_IN_SYSTEM; n++)
+ {
+ IDD *idd = IddTbl[n];
+
+ if (idd && (idd->state == IDD_S_RUN))
+ EventNum += idd->PollTx(idd);
+ }
+
+ TotalEventNum += EventNum;
+
+ } while (EventNum && (TotalEventNum < MAX_EVENTS) );
+
+ //
+ // lets go ahead and give some of this data up to the wrapper
+ // hopefully this will keep us from running out of room in our
+ // assembly descriptor table
+ //
+// TryToIndicateMtlReceives(Adapter);
+
+ NdisMSetTimer(&Adapter->IddPollTimer, IDD_POLL_T);
+}
+#endif
+
+/* get idd name */
+CHAR*
+idd_get_name(VOID *idd_1)
+{
+ IDD *idd = (IDD*)idd_1;
+ return(idd->name);
+}
+
+USHORT
+idd_get_bline(VOID *idd_1)
+{
+ IDD *idd = (IDD*)idd_1;
+ return(idd->bline);
+}
+
+USHORT
+idd_get_btype(VOID *idd_1)
+{
+ IDD *idd = (IDD*)idd_1;
+ return(idd->btype);
+}
+
+VOID*
+idd_get_trc (VOID *idd_1)
+{
+ IDD *idd = (IDD*)idd_1;
+ return(idd->trc);
+}
+
+VOID
+idd_set_trc (VOID *idd_1, TRC* Trace)
+{
+ IDD *idd = (IDD*)idd_1;
+ idd->trc = Trace;
+}
+
+INT
+idd_reset_area (VOID* idd_1)
+{
+ IDD *idd = (IDD*)idd_1;
+
+ idd->Area.area_state = AREA_ST_IDLE;
+
+ return(IDD_E_SUCC);
+}
+
+INT
+idd_get_area_stat (VOID *idd_1, IDD_AREA *IddStat)
+{
+ IDD *idd = (IDD*)idd_1;
+
+ *IddStat = idd->Area;
+
+ return(IDD_E_SUCC);
+}
+
+
+/* get an idd area (really start operation, complete on handler callback) */
+INT
+idd_get_area(VOID *idd_1, ULONG area_id, VOID (*handler)(), VOID *handler_arg)
+{
+ IDD *idd = (IDD*)idd_1;
+ IDD_MSG msg;
+
+ D_LOG(D_ENTRY, ("idd_get_area: entry, idd: 0x%p, area_id: %ld", idd, area_id));
+ D_LOG(D_ENTRY, ("idd_get_area: handler: 0x%p, handler_arg: 0x%p", handler, handler_arg));
+
+ /* check if area is not busy */
+ if ( idd->Area.area_state == AREA_ST_PEND )
+ return(IDD_E_BUSY);
+
+ /* mark area is pending, store arguments */
+ idd->Area.area_state = AREA_ST_PEND;
+ idd->Area.area_id = area_id;
+ idd->Area.area_idd = idd;
+ idd->Area.area_len = 0;
+ idd->Area.area_handler = handler;
+ idd->Area.area_handler_arg = handler_arg;
+
+ /* issue idd command to get area */
+ NdisZeroMemory(&msg, sizeof(msg));
+ msg.opcode = CMD_DUMP_PARAM;
+ msg.param = msg.bufid = area_id;
+ if ( idd_send_msg(idd, &msg, IDD_PORT_CMD_TX, NULL, NULL) != IDD_E_SUCC )
+ {
+ /* idd op failed! */
+ idd->Area.area_state = AREA_ST_IDLE;
+ return(IDD_E_AREA);
+ }
+
+ /* succ here */
+ return(IDD_E_SUCC);
+}
+
+VOID
+IddSetRxFraming(
+ IDD *idd,
+ USHORT bchan,
+ ULONG FrameType
+ )
+{
+ idd->recit[bchan].RxFrameType = FrameType;
+}
+
+VOID
+DetectFramingHandler(
+ IDD *idd,
+ USHORT port,
+ ULONG RxFrameType,
+ IDD_XMSG *msg
+ )
+{
+ UCHAR DetectBytes[2];
+
+ if (RxFrameType & IDD_FRAME_DETECT)
+ {
+ //
+ // get detection bytes
+ //
+ IddGetDataFromAdapter(idd,
+ (PUCHAR)&DetectBytes,
+ (PUCHAR)msg->bufptr,
+ 2);
+
+// NdisMoveMemory ((PUCHAR)&DetectBytes, (PUCHAR)msg->bufptr, 2);
+
+ D_LOG(D_ENTRY, ("DetectRxFraming: 0x%x, 0x%x\n",DetectBytes[0], DetectBytes[1]));
+
+ if ((DetectBytes[0] == DKF_UUS_SIG) && (!DetectBytes[1]))
+ idd->recit[port].RxFrameType = IDD_FRAME_DKF;
+
+ else if ((DetectBytes[0] == PPP_SIG_0) && (DetectBytes[1] == PPP_SIG_1))
+ {
+ idd->recit[port].RxFrameType = IDD_FRAME_PPP;
+ cm__ppp_conn(idd, port);
+ }
+ }
+}
+
+VOID
+idd__cmd_handler(IDD *idd, USHORT chan, ULONG Reserved, IDD_MSG *msg)
+{
+ ULONG bytes;
+
+ /* check for show area more/last frames (3/4) */
+ if ( msg->bufid >= 2 )
+ {
+ if ( (idd->Area.area_state == AREA_ST_PEND) &&
+ (idd->Area.area_idd == idd) )
+ {
+ /* copy frame data, as much as possible */
+ bytes = MIN(msg->buflen, (sizeof(idd->Area.area_buf) - idd->Area.area_len));
+
+ IddGetDataFromAdapter(idd,
+ (PUCHAR)idd->Area.area_buf + idd->Area.area_len,
+ (PUCHAR)msg->bufptr,
+ (USHORT)bytes);
+
+// NdisMoveMemory (idd->Area.area_buf + idd->Area.area_len, msg->bufptr, bytes);
+
+ idd->Area.area_len += bytes;
+
+ /* if last, complete */
+ if ( msg->bufid == 3 )
+ {
+ idd->Area.area_state = AREA_ST_DONE;
+ if ( idd->Area.area_handler )
+ (*idd->Area.area_handler)(idd->Area.area_handler_arg,
+ idd->Area.area_id,
+ idd->Area.area_buf,
+ idd->Area.area_len);
+ }
+ }
+ }
+}
+
+#pragma NDIS_INIT_FUNCTION(idd_add_def)
+
+/* add a definition to initialization definition database */
+INT
+idd_add_def(IDD *idd, CHAR *name, CHAR *val)
+{
+ INT name_len = strlen(name) + 1;
+ INT val_len = strlen(val) + 1;
+
+ D_LOG(D_ENTRY, ("idd_add_def: entry"));
+
+ _strlwr(name);
+
+ _strlwr(val);
+
+ D_LOG(D_ENTRY, ("idd_add_def: name: [%s], val: [%s]", name, val));
+ /* check for room */
+
+ if ( (idd->DefinitionTableLength + name_len + val_len) > IDD_DEF_SIZE )
+ {
+ D_LOG(D_ALWAYS, ("idd_add_def: no room in definition table!"));
+ return(IDD_E_NOROOM);
+ }
+
+ /* enter into table */
+ NdisMoveMemory(idd->DefinitionTable + idd->DefinitionTableLength, name, name_len);
+ idd->DefinitionTableLength += name_len;
+
+ NdisMoveMemory(idd->DefinitionTable + idd->DefinitionTableLength, val, val_len);
+ idd->DefinitionTableLength += val_len;
+
+ /* return success */
+ return(IDD_E_SUCC);
+}
+
+#pragma NDIS_INIT_FUNCTION(idd_get_nvram)
+
+/* get an nvram location */
+INT
+idd_get_nvram(VOID *idd_1, USHORT addr, USHORT *val)
+{
+ IDD *idd = (IDD*)idd_1;
+ D_LOG(D_ENTRY, ("idd_get_nvram: entry, idd: 0x%p, addr: 0x%x", idd, addr));
+
+ /* lock card */
+ NdisAcquireSpinLock(&idd->lock);
+
+ /* do the read */
+ *val = idd->NVRamRead(idd, addr);
+
+ /* release card & return */
+ NdisReleaseSpinLock(&idd->lock);
+ D_LOG(D_EXIT, ("idd_get_nvram: exit, val: 0x%x", *val));
+ return(IDD_E_SUCC);
+}
diff --git a/private/ntos/ndis/pcimac/idd_io.c b/private/ntos/ndis/pcimac/idd_io.c
new file mode 100644
index 000000000..2bb565560
--- /dev/null
+++ b/private/ntos/ndis/pcimac/idd_io.c
@@ -0,0 +1,593 @@
+ /*
+ * IDD_IO.C - do inp/outp ops for idd modules
+ */
+
+#include <ndis.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <idd.h>
+#include <res.h>
+
+typedef union
+{
+ UCHAR uc[4];
+ ULONG ul;
+}ULONG_UNION;
+
+typedef union
+{
+ UCHAR uc[2];
+ USHORT us;
+}USHORT_UNION;
+
+/* output to a port */
+VOID
+IdpOutp(
+ IDD *idd,
+ USHORT port,
+ UCHAR val)
+{
+ NdisRawWritePortUchar((ULONG)idd->vhw.vbase_io + port, val);
+}
+
+/* input from a port */
+UCHAR
+IdpInp(
+ IDD *idd,
+ USHORT port)
+{
+ UCHAR val;
+
+ NdisRawReadPortUchar((ULONG)idd->vhw.vbase_io + port, &val);
+
+ return(val);
+}
+
+/* output to a port */
+VOID
+AdpOutp(
+ IDD *idd,
+ USHORT port,
+ UCHAR val
+ )
+{
+ NdisRawWritePortUchar((ULONG)idd->vhw.vbase_io + port, val);
+}
+
+/* input from a port */
+UCHAR
+AdpInp(
+ IDD *idd,
+ USHORT port
+ )
+{
+ UCHAR val;
+
+ NdisRawReadPortUchar((ULONG)idd->vhw.vbase_io + port, &val);
+
+ return(val);
+}
+
+VOID
+AdpWriteControlBit (
+ IDD *idd,
+ UCHAR Bit,
+ UCHAR Value
+ )
+{
+ UCHAR Data = 0;
+
+ Data &= ~Bit;
+ Data |= (Value ? Bit : 0);
+ idd->OutToPort(idd, ADP_REG_CTRL, Data);
+}
+
+UCHAR
+AdpReadReceiveStatus(
+ IDD *idd
+ )
+{
+ return(AdpGetUByte(idd, ADP_STS_WINDOW));
+}
+
+//
+// this function should be updated to use NdisRawWritePortBufferUshort
+// when the datarat is capable of handling it!!!!
+//
+VOID
+AdpPutBuffer (
+ IDD *idd,
+ ULONG Destination,
+ PUCHAR Source,
+ USHORT Length
+ )
+{
+ USHORT WordLength = Length >> 1;
+ PUCHAR OddData = (PUCHAR)(Source + (Length - 1));
+
+ D_LOG(D_ENTRY, ("AdpPutBuffer: idd: 0x%p, Destination: 0x%p, Source: 0x%p, Length: %d", \
+ idd, Destination, Source, Length));
+
+ AdpSetAddress(idd, Destination);
+
+ //
+ // if WordLength has gone to zero with the shift this macro is just a nop
+ //
+ NdisRawWritePortBufferUshort((ULONG)(idd->vhw.vbase_io + ADP_REG_DATA_INC),
+ (PUSHORT)Source,
+ WordLength);
+
+ //
+ // if the length is odd write the last odd byte to adapter
+ //
+ if (Length & 0x0001)
+ NdisRawWritePortUchar((ULONG)idd->vhw.vbase_io + ADP_REG_DATA_INC, *OddData);
+
+// NdisRawWritePortBufferUchar((ULONG)idd->vhw.vbase_io + ADP_REG_DATA_INC,
+// Buffer,
+// Length);
+}
+
+//
+// this function should be updated to use NdisRawReadPortBufferUshort
+// when the datarat is capable of handling it!!!!
+//
+VOID
+AdpGetBuffer (
+ IDD *idd,
+ PUCHAR Destination,
+ ULONG Source,
+ USHORT Length
+ )
+{
+ USHORT WordLength = Length >> 1;
+ PUCHAR OddData = (PUCHAR)(Destination + (Length - 1));
+
+ D_LOG(D_ENTRY, ("AdpGetBuffer: idd: 0x%p, Destination: 0x%p, Source: 0x%p, Length: %d", \
+ idd, Destination, Source, Length));
+
+ AdpSetAddress(idd, Source);
+
+ //
+ // if WordLength has gone to zero with the shift this macro is just a nop
+ //
+ NdisRawReadPortBufferUshort((ULONG)(idd->vhw.vbase_io + ADP_REG_DATA_INC),
+ (PUSHORT)Destination,
+ WordLength);
+
+ //
+ // if the length is odd read the last odd byte from adapter
+ //
+ if (Length & 0x0001)
+ NdisRawReadPortUchar((ULONG)idd->vhw.vbase_io + ADP_REG_DATA_INC, OddData);
+
+// NdisRawReadPortBufferUchar((ULONG)idd->vhw.vbase_io + ADP_REG_DATA_INC,
+// Buffer,
+// Length);
+}
+
+VOID
+AdpPutUByte(
+ IDD *idd,
+ ULONG Address,
+ UCHAR Value
+ )
+{
+ AdpSetAddress(idd, Address);
+ idd->OutToPort(idd, ADP_REG_DATA_INC, Value);
+}
+
+VOID
+AdpPutUShort(
+ IDD *idd,
+ ULONG Address,
+ USHORT Value
+ )
+{
+ USHORT_UNION us;
+
+ us.us = Value;
+ AdpSetAddress(idd, Address);
+ idd->OutToPort(idd, ADP_REG_DATA_INC, us.uc[1]);
+ idd->OutToPort(idd, ADP_REG_DATA_INC, us.uc[0]);
+}
+
+VOID
+AdpPutULong(
+ IDD *idd,
+ ULONG Address,
+ ULONG Value
+ )
+{
+ ULONG_UNION ul;
+
+ ul.ul = Value;
+ AdpSetAddress(idd, Address);
+ idd->OutToPort(idd, ADP_REG_DATA_INC, ul.uc[3]);
+ idd->OutToPort(idd, ADP_REG_DATA_INC, ul.uc[2]);
+ idd->OutToPort(idd, ADP_REG_DATA_INC, ul.uc[1]);
+ idd->OutToPort(idd, ADP_REG_DATA_INC, ul.uc[0]);
+}
+
+UCHAR
+AdpGetUByte(
+ IDD *idd,
+ ULONG Address
+ )
+{
+ UCHAR Value;
+
+ AdpSetAddress(idd, Address);
+
+ Value = idd->InFromPort(idd, ADP_REG_DATA_INC);
+
+ return(Value);
+}
+
+USHORT
+AdpGetUShort(
+ IDD *idd,
+ ULONG Address
+ )
+{
+ USHORT_UNION us;
+
+ AdpSetAddress(idd, Address);
+ us.uc[1] = idd->InFromPort(idd, ADP_REG_DATA_INC);
+ us.uc[0] = idd->InFromPort(idd, ADP_REG_DATA_INC);
+
+ return(us.us);
+}
+
+ULONG
+AdpGetULong(
+ IDD *idd,
+ ULONG Address
+ )
+{
+ ULONG_UNION ul;
+
+ AdpSetAddress(idd, Address);
+ ul.uc[3] = idd->InFromPort(idd, ADP_REG_DATA_INC);
+ ul.uc[2] = idd->InFromPort(idd, ADP_REG_DATA_INC);
+ ul.uc[1] = idd->InFromPort(idd, ADP_REG_DATA_INC);
+ ul.uc[0] = idd->InFromPort(idd, ADP_REG_DATA_INC);
+
+ return(ul.ul);
+}
+
+VOID
+AdpWriteCommandStatus(
+ IDD *idd,
+ UCHAR Value
+ )
+{
+ //
+ // setup the address
+ //
+ AdpSetAddress(idd, ADP_CMD_WINDOW + 1);
+
+ //
+ // put out the value
+ //
+ idd->OutToPort(idd, ADP_REG_DATA_INC, Value);
+}
+
+UCHAR
+AdpReadCommandStatus(
+ IDD *idd
+ )
+{
+ UCHAR Status;
+
+ //
+ // setup the address
+ //
+ AdpSetAddress(idd, ADP_CMD_WINDOW + 1);
+
+ //
+ // get status
+ //
+ Status = idd->InFromPort(idd, ADP_REG_DATA_INC);
+
+ return(Status);
+}
+
+VOID
+AdpSetAddress(
+ IDD *idd,
+ ULONG Address
+ )
+{
+ ULONG_UNION ul;
+
+ D_LOG(D_NEVER, ("AdpSetAddress: idd: 0x%p, Address: 0x%p", \
+ idd, Address));
+ //
+ // setup address
+ //
+ ul.ul = Address;
+ idd->OutToPort(idd, ADP_REG_ADDR_LO, ul.uc[0]);
+ idd->OutToPort(idd, ADP_REG_ADDR_MID, ul.uc[1]);
+ idd->OutToPort(idd, ADP_REG_ADDR_HI, ul.uc[2]);
+}
+
+UCHAR
+IdpGetUByteIO(
+ IDD* idd,
+ USHORT port
+ )
+{
+ UCHAR Value;
+
+ Value = idd->InFromPort(idd, port);
+
+ return(Value);
+}
+
+VOID
+IdpGetBuffer(
+ IDD* idd,
+ ULONG Bank,
+ ULONG Page,
+ ULONG Address,
+ USHORT Length,
+ PUCHAR Buffer
+ )
+{
+ //
+ // address from offset 0 on the bank and page described
+ //
+ PUCHAR VirtualAddress = idd->vhw.vmem + Address;
+
+ DbgPrint("IdpGetBuffer: idd: 0x%x, Bank: 0x%x, Page: 0x%x, Address: 0x%x, VirtAddres: 0x%x, Length: 0x%x\n",
+ idd, Bank, Page, Address, VirtualAddress, Length);
+
+
+ if (Length > IDP_RAM_PAGE_SIZE)
+ Length = IDP_RAM_PAGE_SIZE;
+
+ //
+ // set the bank to the desired bank
+ //
+ idd->SetBank(idd, (UCHAR)Bank, 1);
+
+ //
+ // set the page to the desired page
+ //
+ idd->ChangePage(idd, (UCHAR)Page);
+
+ //
+ // get the stuff
+ //
+ NdisMoveFromMappedMemory((PVOID)Buffer, (PVOID)VirtualAddress, Length);
+}
+
+VOID
+IdpPutUByteIO(
+ IDD* idd,
+ USHORT Port,
+ UCHAR Value
+ )
+{
+
+}
+
+VOID
+IdpPutBuffer(
+ IDD* idd,
+ ULONG Bank,
+ ULONG Page,
+ ULONG Address,
+ USHORT Length,
+ PUCHAR Buffer
+ )
+{
+
+}
+
+/*
+ * IDD_MC.C - IDD board specific functions for MCIMAC
+ */
+
+/* set active bank, control reset state */
+VOID
+IdpMcSetBank(IDD *idd, UCHAR bank, UCHAR run)
+{
+ static UCHAR reset_map[] = { 4, 5, 7 };
+ static UCHAR run_map[] = { 0, 1, 3 };
+
+ idd->OutToPort(idd, 1, (UCHAR)(run ? run_map[bank] : reset_map[bank]));
+}
+
+/* set active page, control memory mapping */
+VOID
+IdpMcSetPage(IDD *idd, UCHAR page)
+{
+ if ( page == IDD_PAGE_NONE )
+ idd->OutToPort(idd, 2, 0);
+ else
+ idd->OutToPort(idd, 2, (UCHAR)(0x80 | page));
+}
+
+/* set base memory window, redundent! - already stored by POS */
+VOID
+IdpMcSetBasemem(IDD *idd, ULONG basemem)
+{
+
+}
+
+
+/*
+ * IDD_PC.C - IDD board specific functions for ARIZONA
+ */
+
+/* set active bank, control reset state */
+VOID
+AdpSetBank(IDD *idd, UCHAR bank, UCHAR run)
+{
+
+}
+
+/* set active page, control memory mapping */
+VOID
+AdpSetPage(IDD *idd, UCHAR page)
+{
+
+}
+
+/* set base memory window, redundent! - already stored by POS */
+VOID
+AdpSetBasemem(IDD *idd, ULONG basemem)
+{
+
+}
+
+/*
+ * IDD_PC.C - IDD board specific functions for PCIMAC
+ */
+
+/* set active bank, control reset state */
+VOID
+IdpPcSetBank(IDD *idd, UCHAR bank, UCHAR run)
+{
+ //
+ // reset map means that the reset bit is held in the bank select register
+ //
+ static UCHAR reset_map[] = { 4, 5, 7 };
+
+ //
+ // run map means that the reset bit is not set in the bank select register
+ //
+ static UCHAR run_map[] = { 0, 1, 3 };
+
+ idd->OutToPort(idd, 4, (UCHAR)(run ? run_map[bank] : reset_map[bank]));
+}
+
+/* set active page, control memory mapping */
+VOID
+IdpPcSetPage(IDD *idd, UCHAR page)
+{
+ if ( page == IDD_PAGE_NONE )
+ idd->OutToPort(idd, 5, 0);
+ else
+ idd->OutToPort(idd, 5, (UCHAR)(0x80 | page));
+}
+
+/* set base memory window, over-writes IRQ to 0! */
+VOID
+IdpPcSetBasemem(IDD *idd, ULONG basemem)
+{
+ idd->OutToPort(idd, 6, (UCHAR)(basemem >> 8));
+ idd->OutToPort(idd, 7, (UCHAR)(basemem >> 16));
+}
+
+
+/*
+ * IDD_PC4.C - IDD board specific functions for PCIMAC\4
+ */
+
+/*
+ * set active bank, control reset state
+ *
+ * this routine makes use of the local data attached to the i/o resource.
+ * as local dta is a long, it is used as an image of registers 3,4,x,x
+ */
+VOID
+IdpPc4SetBank(IDD *idd, UCHAR bank, UCHAR run)
+{
+ static UCHAR reset_map[] = { 4, 5, 7 };
+ static UCHAR run_map[] = { 0, 1, 3 };
+ ULONG lreg;
+ UCHAR *reg = (UCHAR*)&lreg;
+ UCHAR val = run ? run_map[bank] : reset_map[bank];
+
+ D_LOG(D_ENTRY, ("idd__pc4_set_bank: entry, idd: 0x%p, bank: 0x%x, run: 0x%x", idd, bank, run));
+
+ /* lock i/o resource, get local data - which is register image */
+ res_own(idd->res_io, idd);
+ res_get_data(idd->res_io, &lreg);
+
+ /* the easy way is to switch on bline & write bline specific code */
+ switch ( idd->bline )
+ {
+ case 0 :
+ reg[0] = (reg[0] & 0xF0) | val;
+ idd->OutToPort(idd, 3, reg[0]);
+ break;
+
+ case 1 :
+ reg[0] = (val << 4) | (reg[0] & 0x0F);
+ idd->OutToPort(idd, 3, reg[0]);
+ break;
+
+ case 2 :
+ reg[1] = (reg[1] & 0xF0) | val;
+ idd->OutToPort(idd, 4, reg[1]);
+ break;
+
+ case 3 :
+ reg[1] = (val << 4) | (reg[1] & 0x0F);
+ idd->OutToPort(idd, 4, reg[1]);
+ break;
+ }
+
+ /* return local data, release resource */
+ res_set_data(idd->res_io, lreg);
+ res_unown(idd->res_io, idd);
+
+ D_LOG(D_EXIT, ("idd__pc4_set_bank: exit"));
+}
+
+/* set active page, control memory mapping */
+VOID
+IdpPc4SetPage(IDD *idd, UCHAR page)
+{
+ if ( page == IDD_PAGE_NONE )
+ idd->OutToPort(idd, 5, 0);
+ else
+ idd->OutToPort(idd, 5, (UCHAR)(0x80 | page | (UCHAR)(idd->bline << 5)));
+}
+
+/* set base memory window, over-writes IRQ to 0! */
+VOID
+IdpPc4SetBasemem(IDD *idd, ULONG basemem)
+{
+ idd->OutToPort(idd, 6, (UCHAR)(basemem >> 8));
+ idd->OutToPort(idd, 7, (UCHAR)(basemem >> 16));
+}
+
+
+/*
+ * IDD_MEM.C - some memory handling routines
+ */
+
+
+/* fill a memory block using word moves */
+VOID
+IdpMemset(UCHAR*dst, USHORT val, INT size)
+{
+ D_LOG(D_ENTRY, ("idd__memwset: entry, dst: 0x%p, val: 0x%x, size: 0x%x", dst, val, size));
+
+// for ( size /= sizeof(USHORT) ; size ; size--, dst++ )
+// NdisMoveToMappedMemory((PVOID)dst, (PVOID)&val, sizeof(USHORT));
+ NdisZeroMappedMemory((PVOID)dst, size);
+}
+
+/* copy a memory block using word moves */
+VOID
+IdpMemcpy(UCHAR *dst, UCHAR *src, INT size)
+{
+ D_LOG(D_ENTRY, ("idd__memwcpy: entry, dst: 0x%p, src: 0x%p, size: 0x%x", dst, src, size));
+
+// for ( size /= sizeof(USHORT) ; size ; size--, dst++, src++ )
+// NdisMoveToMappedMemory((PVOID)dst, (PVOID)src, sizeof(USHORT));
+
+ NdisMoveToMappedMemory((PVOID)dst, (PVOID)src, size);
+}
+
+
+
diff --git a/private/ntos/ndis/pcimac/idd_msg.c b/private/ntos/ndis/pcimac/idd_msg.c
new file mode 100644
index 000000000..4dafd8ce4
--- /dev/null
+++ b/private/ntos/ndis/pcimac/idd_msg.c
@@ -0,0 +1,163 @@
+/*
+ * IDD_MSG.C - message handling code
+ */
+
+#include <ndis.h>
+#include <mytypes.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <idd.h>
+
+/* send a message down a port. only really queues message for transmittion */
+INT
+idd_send_msg(VOID *idd_1, IDD_MSG *msg, USHORT port, VOID (*handler)(), VOID *handler_arg)
+{
+ IDD *idd = (IDD*)idd_1;
+ INT ret = IDD_E_SUCC;
+ IDD_SENDQ *sq;
+
+ D_LOG(D_ENTRY, ("idd_send_msg: entry, idd: 0x%p, msg: 0x%p", idd, msg));
+ D_LOG(D_ENTRY, ("idd_send_msg: port: %u, handler: 0x%p, handler_arg: 0x%p", \
+ port, handler, handler_arg));
+ D_LOG(D_ENTRY, ("idd_send_msg: opcode: 0x%x, buflen: 0x%x, bufptr: 0x%p", \
+ msg->opcode, msg->buflen, msg->bufptr));
+ D_LOG(D_ENTRY, ("idd_send_msg: bufid: 0x%x, param: 0x%x", \
+ msg->bufid, msg->param));
+
+ /* check port */
+ if ( port >= IDD_TX_PORTS )
+ {
+ D_LOG(D_ALWAYS, ("idd_send_msg: invalid port!"));
+ return(IDD_E_BADPORT);
+ }
+ sq = idd->sendq + port;
+
+ /* lock port queue */
+ NdisAcquireSpinLock(&sq->lock);
+
+ /* check for space */
+ if ( sq->num >= sq->max )
+ {
+ DbgPrint("sq->num: %d, sq->max: %d\n", sq->num, sq->max);
+ ret = IDD_E_NOROOM;
+ }
+ else
+ {
+ /* space avail, fill in entry */
+ sq->tbl[sq->put].msg = *msg;
+ sq->tbl[sq->put].handler = handler;
+ sq->tbl[sq->put].handler_arg = handler_arg;
+ /* update queue vars */
+ if ( (sq->put += 1) >= sq->max )
+ sq->put = 0;
+ sq->num++;
+ }
+
+ /* release lock */
+ NdisReleaseSpinLock(&sq->lock);
+
+
+// /* (maybe) trigger processing */
+// if ( ret == IDD_E_SUCC )
+// idd_process(idd, 1);
+
+ if (ret == IDD_E_SUCC)
+ idd->PollTx(idd);
+
+ /* return here */
+ D_LOG(D_EXIT, ("idd_send_msg: exit, ret=0x%x", ret));
+ return(ret);
+}
+
+/* attach a user handler to a port */
+//
+INT
+idd_attach(VOID *idd_1, USHORT port, VOID (*handler)(), VOID *handler_arg)
+{
+ INT ret = IDD_E_SUCC;
+ IDD_RECIT *rt;
+ IDD *idd = (IDD*)idd_1;
+
+ D_LOG(D_ENTRY, ("idd_attach: entry, idd: 0x%p", idd));
+ D_LOG(D_ENTRY, ("idd_attach: port: %u, handler: 0x%p, handler_arg: 0x%p", \
+ port, handler, handler_arg));
+
+ /* check port */
+ if ( port >= IDD_RX_PORTS )
+ {
+ D_LOG(D_ALWAYS, ("idd_attach: invalid port!"));
+ return(IDD_E_BADPORT);
+ }
+ rt = idd->recit + port;
+
+ /* lock port table */
+ NdisAcquireSpinLock(&rt->lock);
+
+ /* check for space */
+ if ( rt->num >= rt->max )
+ ret = IDD_E_NOROOM;
+ else
+ {
+ /* space avail, fill in entry */
+ rt->tbl[rt->num].handler = handler;
+ rt->tbl[rt->num].handler_arg = handler_arg;
+
+ /* update table vars */
+ rt->num++;
+ }
+
+ /* release lock */
+ NdisReleaseSpinLock(&rt->lock);
+
+ /* return here */
+ D_LOG(D_EXIT, ("idd_attach: exit, ret=0x%x", ret));
+ return(ret);
+}
+
+/* detach a user handler to a port */
+INT
+idd_detach(VOID *idd_1, USHORT port, VOID (*handler)(), VOID *handler_arg)
+{
+
+ INT ret = IDD_E_SUCC;
+ IDD_RECIT *rt;
+ INT n;
+ IDD *idd = (IDD*)idd_1;
+
+ D_LOG(D_ENTRY, ("idd_detach: entry, idd: 0x%p", idd));
+ D_LOG(D_ENTRY, ("idd_detach: port: %u, handler: 0x%p, handler_arg: 0x%p", \
+ port, handler, handler_arg));
+
+ /* check port */
+ if ( port >= IDD_RX_PORTS )
+ {
+ D_LOG(D_ALWAYS, ("idd_detach: invalid port!"));
+ return(IDD_E_BADPORT);
+ }
+ rt = idd->recit + port;
+
+ /* lock port table */
+ NdisAcquireSpinLock(&rt->lock);
+
+ /* scan table for handler/handler_arg */
+ for ( n = 0 ; n < rt->num ; n++ )
+ if ( (rt->tbl[n].handler == handler) && (rt->tbl[n].handler_arg == handler_arg) )
+ break;
+ if ( n >= rt->num )
+ ret = IDD_E_NOSUCH;
+ else
+ {
+ /* found, shrink table */
+ NdisMoveMemory(rt->tbl + n, rt->tbl + n + 1, sizeof(rt->tbl[0]) * (rt->num - n - 1));
+ rt->num--;
+ }
+
+ /* release lock */
+ NdisReleaseSpinLock(&rt->lock);
+
+ /* return here */
+ D_LOG(D_EXIT, ("idd_detach: exit, ret=0x%x", ret));
+ return(ret);
+}
+
diff --git a/private/ntos/ndis/pcimac/idd_nv.c b/private/ntos/ndis/pcimac/idd_nv.c
new file mode 100644
index 000000000..0f4fb40fd
--- /dev/null
+++ b/private/ntos/ndis/pcimac/idd_nv.c
@@ -0,0 +1,140 @@
+/*
+ * IDD_NV.C - nvram handling routines
+ */
+
+#include <ndis.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <idd.h>
+#include <res.h>
+
+static USHORT nv_op (IDD*, SHORT, USHORT, USHORT, USHORT);
+static INT nv_clk (IDD*, USHORT);
+
+/* clock one nvram bit in/out */
+static INT
+nv_clk(IDD *idd, USHORT dat)
+{
+ INT ret;
+
+ dat &= 1; /* make sure dat is one bit only */
+
+ idd->OutToPort(idd, 0, (UCHAR)(0x04 | dat)); /* setup data */
+ idd->OutToPort(idd, 0, (UCHAR)(0x06 | dat)); /* clock high */
+ idd->OutToPort(idd, 0, (UCHAR)(0x04 | dat)); /* clock low */
+ ret = idd->InFromPort(idd, 0) & 0x01; /* return out bit */
+
+ return(ret);
+}
+
+/* perform a basic nvram operation */
+static USHORT
+nv_op(IDD *idd, SHORT op, USHORT addr, USHORT val, USHORT has_val)
+{
+ INT n;
+ USHORT word = 0;
+
+ D_LOG(D_ENTRY, ("nv_op: entry, idd: 0x%p op: %d, addr: 0x%x, val: 0x%x, has_val: %d", \
+ idd, op, addr, val, has_val));
+
+ /* own i/o resource */
+ res_own(idd->res_io, idd);
+
+ /* set CS */
+ idd->OutToPort(idd, 0, 0x4);
+
+ /* if waiting for chip to be done, stay here */
+ if ( op < 0 )
+ {
+ while ( !(idd->InFromPort(idd, 0) & 0x01) )
+ ;
+ /* remove ownership of i/o */
+ res_unown(idd->res_io, idd);
+ return(0);
+ }
+
+ /* clock in SB + opcode */
+ nv_clk(idd, (USHORT)1);
+ nv_clk(idd, (USHORT)(op >> 1));
+ nv_clk(idd, (USHORT)(op & 1));
+
+ /* clock in address */
+ for ( n = 5 ; n >= 0 ; n-- )
+ nv_clk(idd, (USHORT)(addr >> n));
+
+ if ( has_val )
+ {
+ /* clock data/val in/out */
+ for ( n = 15 ; n >= 0 ; n-- )
+ word = (word << 1) | nv_clk(idd, (USHORT)(val >> n));
+ }
+
+ /* remove CS */
+ idd->OutToPort(idd, 0, 0x00);
+
+ /* remove ownership of i/o */
+ res_unown(idd->res_io, idd);
+
+
+ D_LOG(D_EXIT, ("nv_op: exit, word: 0x%x", word));
+ return(word);
+}
+
+/* read a nvram location */
+USHORT
+IdpNVRead(IDD *idd, USHORT addr)
+{
+ /* a basic op */
+ return(nv_op(idd, 2, addr, 0, 1));
+}
+
+
+/* read a nvram location */
+USHORT
+AdpNVRead(IDD *idd, USHORT addr)
+{
+ return(AdpGetUShort(idd, ADP_NVRAM_WINDOW + addr));
+}
+
+/* write a nvram location */
+VOID
+IdpNVWrite(IDD *idd, USHORT addr, USHORT val)
+{
+ /* enable writes */
+ nv_op(idd, 0, 0x30, 0, 0);
+
+ /* do the write */
+ nv_op(idd, 1, addr, val, 1);
+
+ /* wait for part to be done */
+ nv_op(idd, -1, 0, 0, 0);
+}
+
+/* write a nvram location */
+VOID
+AdpNVWrite(IDD *idd, USHORT addr, USHORT val)
+{
+
+}
+
+
+/* erase all nvram */
+VOID
+IdpNVErase(IDD *idd)
+{
+ /* enable writes */
+ nv_op(idd, 0, 0x30, 0, 0);
+
+ /* erase */
+ nv_op(idd, 0, 0x20, 0, 0);
+}
+
+/* erase all nvram */
+VOID
+AdpNVErase(IDD *idd)
+{
+
+}
diff --git a/private/ntos/ndis/pcimac/idd_proc.c b/private/ntos/ndis/pcimac/idd_proc.c
new file mode 100644
index 000000000..8b514e518
--- /dev/null
+++ b/private/ntos/ndis/pcimac/idd_proc.c
@@ -0,0 +1,947 @@
+/*
+ * IDD_PROC.C - do real tx/rx processing
+ */
+
+
+#include <ndis.h>
+//#include <ndismini.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+#include <res.h>
+
+#if DBG
+#define AddBufferToList(_idd, _Part, _Buffer) \
+{ \
+ BUFFER_MANAGER *IdpBufferStuff = &(_idd)->BufferStuff[_Part]; \
+ ULONG *PutBuffer = &IdpBufferStuff->Buffer[IdpBufferStuff->Put % 32]; \
+ ASSERT(!*PutBuffer); \
+ *PutBuffer = _Buffer; \
+ IdpBufferStuff->Put++; \
+ IdpBufferStuff->Count++; \
+ ASSERT(IdpBufferStuff->Count < 32); \
+}
+
+#define RemoveBufferFromList(_idd, _Part) \
+{ \
+ BUFFER_MANAGER *IdpBufferStuff = &(_idd)->BufferStuff[_Part]; \
+ ULONG *GetBuffer = &IdpBufferStuff->Buffer[IdpBufferStuff->Get % 32]; \
+ ASSERT(*GetBuffer); \
+ *GetBuffer = 0; \
+ IdpBufferStuff->Get++; \
+ ASSERT(IdpBufferStuff->Count > 0); \
+ IdpBufferStuff->Count--; \
+}
+#endif
+
+/* poll (process) trasmitter side */
+ULONG
+IdpPollTx(IDD *idd)
+{
+ INT n, has_msg;
+ ULONG EventNum = 0;
+ IDD_SMSG smsg;
+ USHORT buf_len = 0, TxFlags = 0, TempUshort;
+ UCHAR status;
+ ULONG msg_bufptr, TempUlong;
+
+ D_LOG(D_NEVER, ("IdpPollTx: entry, idd: 0x%p", idd));
+
+ /* must get semaphore */
+ if ( !sema_get(&idd->proc_sema) )
+ return(IDD_E_SUCC);
+
+ /* lock idd */
+ NdisAcquireSpinLock(&idd->lock);
+
+ if (!GetResourceSem (idd->res_mem))
+ {
+ NdisReleaseSpinLock(&idd->lock);
+ sema_free(&idd->proc_sema);
+ return(IDD_E_SUCC);
+ }
+
+ IdpCPage(idd, 0);
+
+ /* loop on all tx ports */
+ for ( n = 0 ; n < IDD_TX_PORTS ; n++ )
+ {
+ USHORT part = idd->tx_partq[n];
+
+ /* skip non existent ports */
+ if ( !idd->tx_port[n] )
+ continue;
+
+ /* check if port is blocked on a buffer */
+ if ( !idd->tx_buf[part] )
+ {
+ /* try to get a buffer for this partition */
+ IdpCPage(idd, 0);
+
+ TempUlong = (ULONG)(part + 4);
+ NdisMoveToMappedMemory((PVOID)&idd->IdpCmd->msg_param, (PVOID)&TempUlong, sizeof (ULONG));
+
+ status = idd->Execute(idd, IDP_L_GET_WBUF);
+
+ if ( status != IDP_S_OK)
+ continue;
+
+ /* if here, buffer allocated, register it */
+ NdisMoveFromMappedMemory( (PVOID)&idd->tx_buf[part], (PVOID)&idd->IdpCmd->msg_bufptr, sizeof (ULONG));
+
+#if DBG
+ AddBufferToList(idd, part, idd->tx_buf[part]);
+#endif
+
+ }
+
+ /* check if a message is waiting to be sent on a port */
+ NdisAcquireSpinLock(&idd->sendq[n].lock);
+ if ( has_msg = idd->sendq[n].num )
+ {
+ /* extract message off queue */
+ smsg = idd->sendq[n].tbl[idd->sendq[n].get];
+ if ( ++idd->sendq[n].get >= idd->sendq[n].max )
+ idd->sendq[n].get = 0;
+ idd->sendq[n].num--;
+ }
+ NdisReleaseSpinLock(&idd->sendq[n].lock);
+
+ /* if no message, escape here */
+ if ( !has_msg )
+ continue;
+
+ /* debug print message */
+ D_LOG(D_ALWAYS, ("poll_tx: smsg: opcode: 0x%x, buflen: 0x%x, bufptr: 0x%p", \
+ smsg.msg.opcode, smsg.msg.buflen, smsg.msg.bufptr));
+ D_LOG(D_ALWAYS, ("poll_tx: bufid: 0x%x, param: 0x%x, handler: 0x%p, arg: 0x%p", \
+ smsg.msg.bufid, smsg.msg.param, smsg.handler, smsg.handler_arg));
+
+ //
+ // save xmitflags clearing out dkf fragment indicator
+ // they are in most significant nible
+ // Bits - xxxx
+ // ||||__ fragment indicator
+ // |||___ tx flush flag
+ // ||____ !tx end flag
+ // |_____ !tx begin flag
+ //
+ TxFlags = smsg.msg.buflen & TX_FLAG_MASK;
+
+
+#if DBG
+ switch (idd->BufferStuff[part].TxState)
+ {
+ case TX_BEGIN:
+ case TX_END:
+ if (TxFlags & H_TX_N_BEG)
+ {
+ DbgPrint("Missed a begining buffer! idd: 0x%x, part: %d\n", idd, part);
+ DbgPrint("TxFlags: 0x%x, State: 0x%x\n", TxFlags, idd->BufferStuff[part].TxState);
+ DbgBreakPoint();
+ }
+ else if (TxFlags & H_TX_N_END)
+ {
+ idd->BufferStuff[part].TxState = TX_MIDDLE;
+ idd->BufferStuff[part].FragsSinceBegin = 0;
+ }
+ break;
+
+ case TX_MIDDLE:
+ if (TxFlags & H_TX_N_BEG)
+ break;
+ else
+ {
+ DbgPrint("Missed an ending buffer! idd: 0x%x, part: %d\n", idd, part);
+ DbgPrint("TxFlags: 0x%x, State: 0x%x\n", TxFlags, idd->BufferStuff[part].TxState);
+ DbgBreakPoint();
+ }
+ break;
+
+ default:
+ DbgPrint("Unknown State! idd: 0x%x, part: %d\n", idd, part);
+ DbgPrint("TxFlags: 0x%x, State: 0x%x\n", TxFlags, idd->BufferStuff[part].TxState);
+ DbgBreakPoint();
+ idd->BufferStuff[part].TxState = TX_BEGIN;
+ idd->BufferStuff[part].FragsSinceBegin = 0;
+ break;
+ }
+
+ idd->BufferStuff[part].FragsSinceBegin++;
+ if (!(TxFlags & H_RX_N_END))
+ idd->BufferStuff[part].TxState = TX_END;
+
+#endif
+ /* check for buffer, if has one, copyin */
+
+ IdpCPage(idd, 0);
+
+ NdisMoveToMappedMemory((PVOID)&idd->IdpCmd->msg_bufptr, (PVOID)&idd->tx_buf[part], sizeof (ULONG));
+
+#if DBG
+ RemoveBufferFromList(idd, part);
+#endif
+
+ if ( smsg.msg.bufptr )
+ buf_len = IdpCopyin(idd, (char*)idd->tx_buf[part],
+ smsg.msg.bufptr, smsg.msg.buflen);
+ else
+ buf_len = 0;
+
+ IdpCPage(idd, 0);
+
+ TempUshort = (USHORT)(buf_len | TxFlags);
+ NdisMoveToMappedMemory((PVOID)&idd->IdpCmd->msg_buflen, (PVOID)&TempUshort, sizeof(USHORT));
+
+ /* copy rest of command area */
+ NdisMoveToMappedMemory((PVOID)&idd->IdpCmd->msg_opcode, (PVOID)&smsg.msg.opcode, sizeof(USHORT));
+
+ NdisMoveToMappedMemory((PVOID)&idd->IdpCmd->msg_bufid, (PVOID)&smsg.msg.bufid, sizeof (ULONG));
+
+ TempUlong = (ULONG)(part + 4);
+ NdisMoveToMappedMemory((PVOID)&idd->IdpCmd->msg_param, (PVOID)&TempUlong, sizeof (ULONG));
+
+ NdisMoveToMappedMemory((PVOID)&idd->IdpCmd->port_id, (PVOID)&idd->tx_port[n], sizeof(USHORT));
+
+ /* execute the command, mark an event */
+
+ status = idd->Execute(idd, IDP_L_WRITE);
+
+ EventNum++;
+
+ /* if came back with no buffer, mark it - else store buffer */
+ if ( status != IDP_S_OK )
+ {
+ idd->tx_buf[part] = 0;
+ D_LOG(D_RARE, ("poll_tx: no buffer!, part: %d", part));
+ }
+ else
+ {
+ NdisMoveFromMappedMemory((PVOID)&msg_bufptr, (PVOID)&idd->IdpCmd->msg_bufptr, sizeof (ULONG));
+
+ if ( msg_bufptr )
+ {
+ idd->tx_buf[part] = msg_bufptr;
+
+#if DBG
+ AddBufferToList(idd, part, idd->tx_buf[part]);
+#endif
+
+ D_LOG(D_RARE, ("poll_tx: new buffer, part: %d, buf: 0x%p", \
+ part, idd->tx_buf[part]));
+ }
+ else
+ {
+ idd->tx_buf[part] = 0;
+ }
+ }
+
+ /* call user's handler */
+ if ( smsg.handler ) {
+ (*smsg.handler)(smsg.handler_arg, n, &smsg);
+ }
+
+ }
+
+ /* unset page, free memory window */
+ IdpCPage(idd, IDD_PAGE_NONE);
+
+ FreeResourceSem (idd->res_mem);
+
+ NdisReleaseSpinLock(&idd->lock);
+
+ sema_free(&idd->proc_sema);
+
+ return(EventNum);
+}
+
+/* poll (process) trasmitter side */
+ULONG
+AdpPollTx(IDD *idd)
+{
+ USHORT buf_len = 0, TxFlags = 0;
+ UCHAR status;
+ ULONG n, part, has_msg, EventNum = 0;
+ IDD_SMSG smsg;
+
+ D_LOG(D_NEVER, ("AdpPollTx: entry, idd: 0x%p", idd));
+
+ /* must get semaphore */
+ if ( !sema_get(&idd->proc_sema) )
+ return(IDD_E_SUCC);
+
+ /* lock idd */
+ NdisAcquireSpinLock(&idd->lock);
+
+ //
+ // for all tx ports
+ //
+ for (n = 0; n < IDD_TX_PORTS; n++)
+ {
+ //
+ // skip non existent ports
+ //
+ if (!idd->tx_port[n])
+ continue;
+
+ //
+ // clear command structure
+ //
+ NdisZeroMemory(&idd->AdpCmd, sizeof(ADP_CMD));
+
+ //
+ // see if port is blocked needing a buffer
+ //
+ if ( !idd->tx_buf[part = idd->tx_partq[n]] )
+ {
+
+ //
+ // fill port id and status bit
+ //
+ idd->AdpCmd.msg_param = (UCHAR)part + 4;
+ //
+ // execute command
+ //
+ status = idd->Execute(idd, ADP_L_GET_WBUF);
+
+ //
+ // if no buffer then go to next port
+ //
+ if (status != ADP_S_OK)
+ continue;
+
+ //
+ // if here, buffer was allocate, register it
+ //
+ idd->tx_buf[part] = (ULONG)idd->AdpCmd.msg_bufptr;
+
+ }
+
+ //
+ // see if there is a message waiting to be sent
+ //
+ NdisAcquireSpinLock(&idd->sendq[n].lock);
+ if ( has_msg = idd->sendq[n].num )
+ {
+ /* extract message off queue */
+ smsg = idd->sendq[n].tbl[idd->sendq[n].get];
+ if ( ++idd->sendq[n].get >= idd->sendq[n].max )
+ idd->sendq[n].get = 0;
+ idd->sendq[n].num--;
+ }
+ NdisReleaseSpinLock(&idd->sendq[n].lock);
+
+ //
+ // if no message go to next port
+ //
+ if (!has_msg)
+ continue;
+
+ /* debug print message */
+ D_LOG(D_ALWAYS, ("AdpPollTx: smsg: opcode: 0x%x, buflen: 0x%x, bufptr: 0x%p", \
+ smsg.msg.opcode, smsg.msg.buflen, smsg.msg.bufptr));
+ D_LOG(D_ALWAYS, ("AdpPollTx: bufid: 0x%x, param: 0x%x, handler: 0x%p, arg: 0x%p", \
+ smsg.msg.bufid, smsg.msg.param, smsg.handler, smsg.handler_arg));
+
+
+ //
+ // save xmitflags clearing out dkf fragment indicator
+ // they are in most significant nible
+ // Bits - xxxx
+ // ||||__ fragment indicator
+ // |||___ tx flush flag
+ // ||____ !tx end flag
+ // |_____ !tx begin flag
+ //
+ TxFlags = smsg.msg.buflen & TX_FLAG_MASK;
+
+ //
+ // see if there is a buffer to be copied
+ //
+ (ULONG)idd->AdpCmd.msg_bufptr = idd->tx_buf[part];
+
+ if ( smsg.msg.bufptr )
+ buf_len = AdpCopyin(idd, smsg.msg.bufptr, smsg.msg.buflen);
+ else
+ buf_len = 0;
+
+ idd->AdpCmd.msg_buflen = buf_len | TxFlags;
+ idd->AdpCmd.msg_opcode = smsg.msg.opcode;
+ idd->AdpCmd.msg_bufid = smsg.msg.bufid;
+ idd->AdpCmd.msg_param = (ULONG)(part + 4);
+ idd->AdpCmd.port_id = idd->tx_port[n];
+
+ status = idd->Execute(idd, ADP_L_WRITE);
+
+ EventNum++;
+
+ if (status != ADP_S_OK)
+ {
+ idd->tx_buf[part] = 0;
+ D_LOG(D_RARE, ("poll_tx: no buffer!, part: %d", part));
+ }
+ else
+ {
+ if (idd->AdpCmd.msg_bufptr)
+ {
+ idd->tx_buf[part] = (ULONG)idd->AdpCmd.msg_bufptr;
+ D_LOG(D_RARE, ("poll_tx: new buffer, part: %d, buf: 0x%p", \
+ part, idd->tx_buf[part]));
+
+ }
+ }
+ /* call user's handler */
+ if ( smsg.handler )
+ (*smsg.handler)(smsg.handler_arg, n, &smsg);
+ }
+
+ NdisReleaseSpinLock(&idd->lock);
+
+ sema_free(&idd->proc_sema);
+
+ return(EventNum);
+}
+
+/* poll (process) reciever ports */
+ULONG
+IdpPollRx(IDD *idd)
+{
+ INT n, m;
+ USHORT stat, ofs;
+ IDD_XMSG msg;
+ UCHAR status, Page;
+ ULONG TempUlong, EventNum = 0;
+
+ /* must get semaphore */
+ if ( !sema_get(&idd->proc_sema) )
+ return(IDD_E_SUCC);
+
+ /* lock idd */
+ NdisAcquireSpinLock(&idd->lock);
+
+ if (!GetResourceSem (idd->res_mem))
+ {
+ NdisReleaseSpinLock(&idd->lock);
+ sema_free(&idd->proc_sema);
+ return(IDD_E_SUCC);
+ }
+
+ /* get status port */
+ IdpCPage(idd, 0);
+
+ NdisMoveFromMappedMemory((PVOID)&stat, (PVOID)idd->IdpStat, sizeof(USHORT));
+
+ D_LOG(D_NEVER, ("poll_rx: stat: 0x%x (@0x%p)", stat, idd->IdpStat));
+
+ /* make one pass on all rx ports which have a status bit on */
+ for ( n = 0 ; n < IDD_RX_PORTS ; n++, stat >>= 1 )
+ if ( stat & 1 )
+ {
+ //
+ // skip non existent ports
+ //
+ if (!idd->rx_port[n])
+ continue;
+
+ /* install returned read buffer */
+ IdpCPage(idd, 0);
+
+ TempUlong = MAKELONG(HIWORD(idd->rx_buf), 0);
+ NdisMoveToMappedMemory((PVOID)&idd->IdpCmd->msg_bufid, (PVOID)&TempUlong, sizeof (ULONG));
+
+ idd->rx_buf = 0;
+
+ /* install port & execute a read */
+ D_LOG(D_ALWAYS, ("poll_rx: index: %d, ReadPort 0x%x", n, idd->rx_port[n]));
+
+ NdisMoveToMappedMemory((PVOID)&idd->IdpCmd->port_id, (PVOID)&idd->rx_port[n], sizeof(USHORT));
+
+ status = idd->Execute(idd, IDP_L_READ);
+
+ if ( status != IDP_S_OK )
+ {
+ continue;
+ }
+
+ EventNum++;
+
+ /* copy message out */
+ NdisMoveFromMappedMemory((PVOID)&msg.opcode, (PVOID)&idd->IdpCmd->msg_opcode, sizeof(USHORT));
+
+ NdisMoveFromMappedMemory((PVOID)&msg.buflen, (PVOID)&idd->IdpCmd->msg_buflen, sizeof(USHORT));
+
+ // save receive fragment flags
+ // they are in most significant nible
+ // Bits - xxxx
+ // ||||__ reserved
+ // |||___ reserved
+ // ||____ !rx end flag
+ // |_____ !rx begin flag
+ //
+ msg.FragmentFlags = msg.buflen & RX_FLAG_MASK;
+
+ //
+ // get real buffer length
+ //
+ msg.buflen &= H_RX_LEN_MASK;
+
+ NdisMoveFromMappedMemory((PVOID)&msg.bufptr, (PVOID)&idd->IdpCmd->msg_bufptr, sizeof (ULONG));
+
+ NdisMoveFromMappedMemory((PVOID)&msg.bufid, (PVOID)&idd->IdpCmd->msg_bufid, sizeof (ULONG));
+
+ NdisMoveFromMappedMemory((PVOID)&msg.param, (PVOID)&idd->IdpCmd->msg_param, sizeof (ULONG));
+
+ /* save rx buffer */
+ idd->rx_buf = (ULONG)msg.bufptr;
+ D_LOG(D_ALWAYS, ("poll_rx: 0x%x 0x%x %p %p %p", \
+ msg.opcode, \
+ msg.buflen, \
+ msg.bufptr, \
+ msg.bufid, \
+ msg.param));
+
+ if ( msg.bufptr)
+ {
+ ofs = LOWORD(msg.bufptr);
+ Page = (UCHAR)(ofs >> 14) & 3;
+#if DBG
+ if (Page > 1 )
+ {
+ DbgPrint("Page changed to %d on idd 0x%p!\n", Page, idd);
+ DbgBreakPoint();
+ }
+#endif
+ msg.bufptr = idd->vhw.vmem + (ofs & 0x3FFF);
+ IdpCPage(idd, Page);
+ }
+
+ /* loop on rx handler, call user to copyout buffer */
+ for ( m = 0 ; m < idd->recit[n].num ; m++ )
+ (*idd->recit[n].tbl[m].handler)(idd->recit[n].tbl[m].handler_arg,
+ n,
+ idd->recit[n].RxFrameType,
+ &msg);
+ }
+
+ /* unset page, free memory window */
+ IdpCPage(idd, IDD_PAGE_NONE);
+
+ FreeResourceSem (idd->res_mem);
+
+ NdisReleaseSpinLock(&idd->lock);
+
+ sema_free(&idd->proc_sema);
+
+ return(EventNum);
+}
+
+/* poll (process) receiver side */
+ULONG
+AdpPollRx(IDD *idd)
+{
+ INT n, m;
+ UCHAR status;
+ ULONG EventNum = 0;
+ USHORT stat = 0;
+ IDD_XMSG msg;
+
+ /* must get semaphore */
+ if ( !sema_get(&idd->proc_sema) )
+ return(IDD_E_SUCC);
+
+ /* lock idd */
+ NdisAcquireSpinLock(&idd->lock);
+
+ stat = AdpReadReceiveStatus(idd);
+
+ for (n = 0; n < IDD_RX_PORTS; n++, stat >>= 1)
+ if (stat & 1)
+ {
+ //
+ // clear command structure
+ //
+ NdisZeroMemory(&idd->AdpCmd, sizeof(ADP_CMD));
+
+ D_LOG(D_ALWAYS, ("poll_rx: index: %d, ReadPort 0x%x", n, idd->rx_port[n]));
+ //
+ // return read buffer
+ //
+ idd->AdpCmd.msg_bufid = MAKELONG(HIWORD(idd->rx_buf), 0);
+ idd->rx_buf = 0;
+
+ idd->AdpCmd.port_id = idd->rx_port[n];
+
+ status = idd->Execute(idd, ADP_L_READ);
+
+ if (status != ADP_S_OK)
+ continue;
+
+ EventNum++;
+
+ msg.opcode = idd->AdpCmd.msg_opcode;
+ msg.buflen = idd->AdpCmd.msg_buflen;
+
+ // save receive fragment flags
+ // they are in most significant nible
+ // Bits - xxxx
+ // ||||__ reserved
+ // |||___ reserved
+ // ||____ !rx end flag
+ // |_____ !rx begin flag
+ //
+ msg.FragmentFlags = msg.buflen & RX_FLAG_MASK;
+
+ //
+ // get real buffer length
+ //
+ msg.buflen &= H_RX_LEN_MASK;
+
+ msg.bufptr = (UCHAR*)LOWORD(idd->AdpCmd.msg_bufptr);
+ idd->rx_buf = (ULONG)idd->AdpCmd.msg_bufptr;
+ msg.bufid = idd->AdpCmd.msg_bufid;
+ msg.param = idd->AdpCmd.msg_param;
+
+
+ D_LOG(D_ALWAYS, ("AdpPollRx: Opcode: 0x%x, BufLen: 0x%x, BufPtr: 0x%x", \
+ msg.opcode, \
+ msg.buflen, \
+ msg.bufptr));
+ D_LOG(D_ALWAYS, ("AdpPollRx: FragmentFlags: 0x%x, BufId: 0x%x, Param: 0x%x", \
+ msg.FragmentFlags,\
+ msg.bufid, \
+ msg.param));
+
+ /* loop on rx handler, call user to copyout buffer */
+ for ( m = 0 ; m < idd->recit[n].num ; m++ )
+ (*idd->recit[n].tbl[m].handler)(idd->recit[n].tbl[m].handler_arg,
+ n,
+ idd->recit[n].RxFrameType,
+ &msg);
+ }
+
+ NdisReleaseSpinLock(&idd->lock);
+
+ sema_free(&idd->proc_sema);
+
+ return(EventNum);
+}
+
+/* execute an idp command. assumes cpage=0 */
+UCHAR
+IdpExec(IDD *idd, UCHAR opcode)
+{
+ UCHAR status = IDP_S_PEND;
+ ULONG TempWaitCounter;
+
+#if DBG
+ USHORT IdpCounter1 = 0;
+ ULONG IdpCounter2 = 0;
+#endif
+
+ D_LOG(D_ENTRY, ("IdpExec: entry, idd: 0x%p, opcode=%d", idd, opcode));
+
+ /* install opcode, get command started */
+ NdisMoveToMappedMemory((PVOID)&idd->IdpCmd->opcode, (PVOID)&opcode, sizeof(UCHAR));
+
+ NdisMoveToMappedMemory((PVOID)&idd->IdpCmd->status, (PVOID)&status, sizeof(UCHAR));
+
+ status = IDP_S_EXEC;
+
+#if DBG
+ NdisMoveFromMappedMemory((PVOID)&IdpCounter1, (PVOID)(idd->vhw.vmem + 0x804), sizeof(USHORT));
+ NdisMoveFromMappedMemory((PVOID)&IdpCounter2, (PVOID)(idd->vhw.vmem + 0x808), sizeof(ULONG));
+#endif
+
+ idd->WaitCounter = 0;
+
+ while ( idd->state != IDD_S_SHUTDOWN )
+ {
+ NdisMoveFromMappedMemory((PVOID)&TempWaitCounter, (PVOID)(idd->vhw.vmem + 0x80C), sizeof(ULONG));
+ NdisMoveFromMappedMemory((PVOID)&status, (PVOID)&idd->IdpCmd->status, sizeof(UCHAR));
+
+ if ( IDP_S_DONE(status) )
+ break;
+
+ //
+ // wait for 1ms
+ // the ddk says that this function uses milliseconds but it
+ // actually takes microseconds
+ //
+ NdisStallExecution(1000L);
+
+ idd->WaitCounter++;
+ NdisMoveToMappedMemory((PVOID)(idd->vhw.vmem + 0x80C), (PVOID)&idd->WaitCounter, sizeof(ULONG));
+
+ //
+ // this should wait for about one second
+ //
+ if (idd->WaitCounter > 1000)
+ {
+
+ idd->state = IDD_S_SHUTDOWN;
+#if DBG
+ DbgPrint("Shutdown! idd: 0x%p, Status: 0x%x\n", idd, status);
+ DbgPrint("Original: IdpCounter1: 0x%x, IdpCounter2: 0x%x\n", IdpCounter1, IdpCounter2);
+ NdisMoveFromMappedMemory((PVOID)&IdpCounter1, (PVOID)(idd->vhw.vmem + 0x804), sizeof(USHORT));
+ NdisMoveFromMappedMemory((PVOID)&IdpCounter2, (PVOID)(idd->vhw.vmem + 0x808), sizeof(ULONG));
+ DbgPrint("Current: IdpCounter1: 0x%x, IdpCounter2: 0x%x\n", IdpCounter1, IdpCounter2);
+ NdisMoveFromMappedMemory((PVOID)&status, (PVOID)&idd->IdpCmd->status, sizeof(UCHAR));
+ DbgPrint("CurrentStatus: 0x%x\n",status);
+ DbgBreakPoint();
+#endif
+ break;
+ }
+ else
+ status = IDP_S_EXEC;
+ }
+
+ D_LOG(D_EXIT, ("IdpExec: exit, IdpCmd->status: 0x%x", status));
+
+#if DBG
+ if (status && (status != IDP_S_NOBUF)
+ && (status != IDP_S_NOMSG))
+ {
+ USHORT MsgOpcode;
+ USHORT MsgBuflen;
+ UCHAR *MsgBufPtr;
+ ULONG MsgBufId;
+ ULONG MsgParam;
+
+ DbgPrint("Idd 0x%p error executing opcode: 0x%x, status: 0x%x\n", idd, opcode, status);
+ NdisMoveFromMappedMemory((PVOID)&MsgOpcode, (PVOID)&idd->IdpCmd->msg_opcode, sizeof(USHORT));
+ NdisMoveFromMappedMemory((PVOID)&MsgBuflen, (PVOID)&idd->IdpCmd->msg_buflen, sizeof(USHORT));
+ NdisMoveFromMappedMemory( (PVOID)&MsgBufPtr, (PVOID)&idd->IdpCmd->msg_bufptr, sizeof (ULONG));
+ NdisMoveFromMappedMemory((PVOID)&MsgBufId, (PVOID)&idd->IdpCmd->msg_bufid, sizeof (ULONG));
+ NdisMoveFromMappedMemory((PVOID)&MsgParam, (PVOID)&idd->IdpCmd->msg_param, sizeof (ULONG));
+ DbgPrint("IdpExec: MsgOpcode: 0x%x, MsgBufLen: 0x%x, MsgBufPtr: 0x%x\n", MsgOpcode, MsgBuflen, MsgBufPtr);
+ DbgPrint("IdpExec: MsgBufId: 0x%x, MsgParam: 0x%x\n", MsgBufId, MsgParam);
+ }
+#endif
+
+ if (idd->WaitCounter > idd->MaxWaitCounter)
+ idd->MaxWaitCounter = idd->WaitCounter;
+
+ return(status);
+}
+
+/* execute an Adp command. assumes cpage=0 */
+UCHAR
+AdpExec(IDD *idd, UCHAR opcode)
+{
+ UCHAR status = ADP_S_PEND;
+ ULONG TempWaitCounter;
+
+ //
+ // set opcode
+ //
+ idd->AdpCmd.opcode = opcode;
+
+ D_LOG(D_ENTRY, ("AdpExec: entry, idd: 0x%p, opcode: %d", idd, opcode));
+ D_LOG(D_ENTRY, ("status: 0x%x, port_id: 0x%x", idd->AdpCmd.status, idd->AdpCmd.port_id));
+ D_LOG(D_ENTRY, ("msg_opcode: 0x%x, msg_buflen: 0x%x", idd->AdpCmd.msg_opcode, idd->AdpCmd.msg_buflen));
+ D_LOG(D_ENTRY, ("msg_bufptr: 0x%x, msg_bufid: 0x%x", idd->AdpCmd.msg_bufptr, idd->AdpCmd.msg_bufid));
+ D_LOG(D_ENTRY, ("msg_param: 0x%x", idd->AdpCmd.msg_param));
+
+ //
+ // copy in command buffer
+ //
+ AdpPutBuffer(idd, ADP_CMD_WINDOW, (PUCHAR)&idd->AdpCmd, sizeof(ADP_CMD));
+
+ //
+ // start operation
+ //
+ AdpWriteCommandStatus(idd, ADP_S_PEND);
+
+ idd->WaitCounter = 0;
+
+ while ( idd->state != IDD_S_SHUTDOWN )
+ {
+ TempWaitCounter = AdpGetULong(idd, 0x50C);
+
+ status = AdpReadCommandStatus(idd);
+
+ if ( ADP_S_DONE(status) )
+ break;
+
+ //
+ // wait for 1ms
+ // the ddk says that this function uses milliseconds but it
+ // actually takes microseconds
+ //
+ NdisStallExecution(1000L);
+
+ idd->WaitCounter++;
+ AdpPutULong(idd, 0x50C, idd->WaitCounter);
+
+ //
+ // this should wait for about one second
+ //
+ if (idd->WaitCounter > 1000)
+ {
+ idd->state = IDD_S_SHUTDOWN;
+ idd->AbortReason = AdpGetUShort(idd, ADP_STS_WINDOW + 12);
+ }
+ }
+
+ AdpGetBuffer(idd, (PUCHAR)&idd->AdpCmd, ADP_CMD_WINDOW, sizeof(ADP_CMD));
+
+ if (idd->WaitCounter > idd->MaxWaitCounter)
+ idd->MaxWaitCounter = idd->WaitCounter;
+
+ D_LOG(D_EXIT, ("AdpExec: exit, AdpCmd.status: 0x%x", status));
+
+ return(status);
+}
+
+/* map current idp page in */
+VOID
+IdpCPage(IDD *idd, UCHAR page)
+{
+ D_LOG(D_RARE, ("IdpCPage: entry, idd: 0x%p, page: 0x%x", idd, page));
+
+ /* if page is IDD_PAGE_NONE, idd is releasing ownership of the page */
+ if ( page == IDD_PAGE_NONE )
+ {
+ idd->SetPage(idd, IDD_PAGE_NONE);
+ res_unown(idd->res_mem, idd);
+ }
+ else
+ {
+ page &= 3;
+
+ /* real mapping required, lock memory resource */
+ res_own(idd->res_mem, idd);
+ idd->SetPage(idd, page);
+ }
+}
+
+/* map current Adp page in */
+VOID
+AdpCPage(IDD *idd, UCHAR page)
+{
+
+}
+
+/* copy data from user buffer to idp */
+USHORT
+IdpCopyin(IDD *idd, UCHAR *dst, UCHAR *src, USHORT src_len)
+{
+ USHORT ofs, copylen;
+ UCHAR Page;
+ UINT tot_len, frag_num;
+ IDD_FRAG *frag;
+
+ D_LOG(D_RARE, ("Idpcopyin: entry, idd: 0x%p, dst: 0x%p, src: 0x%p, src_len: 0x%x", \
+ idd, dst, src, src_len));
+
+ /* convert destination pointer to address & map in */
+ ofs = LOWORD((long)dst);
+ Page = (UCHAR)(ofs >> 14) & 3;
+
+#if DBG
+ if (Page > 1 )
+ DbgPrint("Page changed to %d on idd 0x%p!\n", Page, idd);
+#endif
+
+ dst = idd->vhw.vmem + (ofs & 0x3FFF);
+
+ IdpCPage(idd, Page);
+
+ //
+ // mask out various flags to get length to copy
+ //
+ copylen = src_len & H_TX_LEN_MASK;
+
+ /* check for a simple copy, real easy - doit here */
+ if ( !(src_len & TX_FRAG_INDICATOR) )
+ {
+ NdisMoveToMappedMemory (dst, src, copylen);
+ return(copylen);
+ }
+
+ /* if here, its a fragment descriptor */
+ tot_len = 0;
+ frag_num = (copylen) / sizeof(IDD_FRAG);
+ frag = (IDD_FRAG*)src;
+
+ /* copy fragments */
+ for ( ; frag_num ; frag_num--, frag++ )
+ {
+ NdisMoveToMappedMemory (dst, frag->ptr, frag->len);
+ dst += frag->len;
+ tot_len += frag->len;
+ }
+
+ /* read total length */
+ return(tot_len);
+}
+
+/* copy data from user buffer to idp */
+USHORT
+AdpCopyin(IDD *idd, UCHAR *src, USHORT src_len)
+{
+ USHORT Destination, CopyLength;
+ UINT tot_len, frag_num;
+ IDD_FRAG *frag;
+
+ D_LOG(D_RARE, ("Adpcopyin: entry, idd: 0x%p, src: 0x%p, src_len: 0x%x", \
+ idd, src, src_len));
+
+ /* convert destination pointer to address & map in */
+ Destination = LOWORD(idd->AdpCmd.msg_bufptr);
+
+ //
+ // mask out various flags to get length to copy
+ //
+ CopyLength = src_len & H_TX_LEN_MASK;
+
+ /* check for a simple copy, real easy - doit here */
+ if ( !(src_len & TX_FRAG_INDICATOR) )
+ {
+ AdpPutBuffer(idd, Destination, src, CopyLength);
+ return(CopyLength);
+ }
+
+ /* if here, its a fragment descriptor */
+ tot_len = 0;
+ frag_num = (CopyLength) / sizeof(IDD_FRAG);
+ frag = (IDD_FRAG*)src;
+
+ /* copy fragments */
+ for ( ; frag_num ; frag_num--, frag++ )
+ {
+ AdpPutBuffer(idd, Destination, frag->ptr, frag->len);
+ Destination += frag->len;
+ tot_len += frag->len;
+ }
+
+ /* read total length */
+ return(tot_len);
+}
+
+VOID
+IddGetDataFromAdapter(
+ VOID *idd_1,
+ PUCHAR Destination,
+ PUCHAR Source,
+ USHORT Length
+ )
+{
+ IDD *idd = (IDD*)idd_1;
+
+ if (idd->btype != IDD_BT_DATAFIREU)
+ {
+ NdisMoveFromMappedMemory(Destination, Source, Length);
+ }
+ else
+ {
+ AdpGetBuffer(idd, Destination, (ULONG)Source, Length);
+ }
+}
diff --git a/private/ntos/ndis/pcimac/idd_pub.h b/private/ntos/ndis/pcimac/idd_pub.h
new file mode 100644
index 000000000..da43ee2b4
--- /dev/null
+++ b/private/ntos/ndis/pcimac/idd_pub.h
@@ -0,0 +1,59 @@
+/*
+ * IDD_PUB.H - IDP Device Driver public header for PCIMAC/ISA
+ */
+
+#ifndef _IDD_PUB_
+#define _IDD_PUB_
+
+#define IDD_MAX_AREA 512 /* max size of area got in get_area */
+
+//
+// global idd def's
+//
+/* IDD message descriptor */
+typedef struct
+{
+ USHORT opcode; /* message opcode (type) */
+ USHORT buflen; /* related buffer length */
+ UCHAR *bufptr; /* related buffer pointer (0=none) */
+ ULONG bufid; /* related buffer id */
+ ULONG param; /* parameter area */
+} IDD_MSG;
+
+/* IDD extended message descriptor */
+typedef struct
+{
+ USHORT opcode; /* message opcode (type) */
+ USHORT buflen; /* related buffer length */
+ UCHAR *bufptr; /* related buffer pointer (0=none) */
+ ULONG bufid; /* related buffer id */
+ ULONG param; /* parameter area */
+ USHORT FragmentFlags; /* fragmentation flags */
+} IDD_XMSG;
+
+/* IDD fragment descriptor */
+typedef struct
+{
+ USHORT len; /* fragment length */
+ CHAR *ptr; /* fragment buffer pointer */
+} IDD_FRAG;
+
+typedef struct
+{
+ VOID (*area_handler)(); /* handler for get_area */
+ VOID *area_handler_arg; /* argument for handler */
+
+ ULONG area_state; /* state of last/current get_area command */
+#define AREA_ST_IDLE 0 /* - idle, no area defined */
+#define AREA_ST_PEND 1 /* - pending, get_area in progress */
+#define AREA_ST_DONE 2 /* - done, results ready */
+
+ ULONG area_id; /* area id (number) pend/done */
+
+ VOID *area_idd; /* related idd (from which area is retreived) */
+ UCHAR area_buf[IDD_MAX_AREA]; /* buffer receiving/containing area data */
+ ULONG area_len; /* length of actual data */
+}IDD_AREA;
+
+#endif /* _IDD_PUB_ */
+
diff --git a/private/ntos/ndis/pcimac/idd_run.c b/private/ntos/ndis/pcimac/idd_run.c
new file mode 100644
index 000000000..585bbeb51
--- /dev/null
+++ b/private/ntos/ndis/pcimac/idd_run.c
@@ -0,0 +1,777 @@
+/*
+ * IDD_RUN.C - run (startup) and shutdown idd object
+ */
+
+#include <ndis.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <idd.h>
+#include <res.h>
+
+/* a port descriptor */
+typedef struct
+{
+ char *name; /* port name */
+ INT must; /* mast map this port? */
+} PORT;
+
+/* port tables */
+static PORT api_rx_port_tbl[] =
+{
+ { "b1_rx ", 1 },
+ { "b2_rx ", 1 },
+ { "uart_rx ", 0 },
+ { "tdat ", 1 },
+ { "Cm.0 ", 1 },
+ { "Cm.1 ", 0 },
+ { NULL }
+};
+static PORT api_tx_port_tbl[] =
+{
+ { "b1_tx ", 1 },
+ { "b2_tx ", 1 },
+ { "uart_tx ", 0 },
+ { "cmd ", 1 },
+ { "Q931.0 ", 1 },
+ { "Q931.1 ", 0 },
+ { NULL }
+};
+
+/* partition queue table */
+
+static INT api_tx_partq_tbl[] =
+{
+ 0, 1, 2, 3, 3, 3
+};
+
+/* local prototypes */
+INT api_setup(IDD* idd);
+INT api_map_ports(IDD* idd);
+INT api_bind_ports(IDD* idd);
+INT api_setup_partq(IDD* idd);
+INT api_alloc_partq(IDD* idd);
+
+#pragma NDIS_INIT_FUNCTION(idd_startup)
+
+/* startup (run) an idd object */
+INT
+idd_startup(VOID *idd_1)
+{
+ IDD *idd = (IDD*)idd_1;
+ INT ret;
+ D_LOG(D_ENTRY, ("idd_startup: entry, idd: 0x%p", idd));
+
+ /* lock idd */
+ NdisAcquireSpinLock(&idd->lock);
+
+ /* mark starting */
+ idd->state = IDD_S_STARTUP;
+
+ if (idd->btype != IDD_BT_DATAFIREU)
+ while(!GetResourceSem (idd->res_mem));
+
+ /* do the startup */
+ if ( (ret = idd->LoadCode(idd)) != IDD_E_SUCC )
+ {
+ /* release idd */
+ FreeResourceSem (idd->res_mem);
+ NdisReleaseSpinLock(&idd->lock);
+ D_LOG(D_EXIT, ("idd_startup: error exit, ret=0x%x", ret));
+ return(ret);
+
+ }
+
+ /* initialize api level - talks to memory! */
+ ret = api_setup(idd);
+
+ /* change state */
+ idd->state = IDD_S_RUN;
+
+ if (idd->btype != IDD_BT_DATAFIREU)
+ FreeResourceSem (idd->res_mem);
+
+ /* release idd */
+ NdisReleaseSpinLock(&idd->lock);
+
+ /* return result */
+ D_LOG(D_EXIT, ("idd_startup: exit, ret=0x%x", ret));
+ return(ret);
+}
+
+/* shutdown an idd object, not implemented yet */
+INT
+idd_shutdown(VOID *idd_1)
+{
+ IDD *idd = (IDD*)idd_1;
+ D_LOG(D_ENTRY, ("idd_shutdown: idd: 0x%p", idd));
+
+ idd->state = IDD_S_SHUTDOWN;
+
+ idd->ResetAdapter(idd);
+
+ return(IDD_E_SUCC);
+}
+
+#pragma NDIS_INIT_FUNCTION(IdpLoadCode)
+
+/* load idp code in & run it */
+INT
+IdpLoadCode(IDD *idd)
+{
+ ULONG CurrentTime = 0, TimeOut = 0;
+ USHORT bank, page, n, NumberOfBanks;
+ UCHAR *fbin_data;
+ NDIS_STATUS stat;
+ UCHAR status = IDP_S_PEND;
+ NDIS_PHYSICAL_ADDRESS pa = NDIS_PHYSICAL_ADDRESS_CONST(0xffffffff, 0xffffffff);
+
+ D_LOG(D_ENTRY, ("load_code: entry, idd=0x%p", idd));
+
+ /* setup pointers into shared memory */
+ idd->IdpStat = (USHORT*)(idd->vhw.vmem + IDP_STS_WINDOW);
+ idd->IdpCmd = (IDP_CMD*)(idd->vhw.vmem + IDP_CMD_WINDOW);
+ idd->IdpEnv = (UCHAR*)(idd->vhw.vmem + IDP_ENV_WINDOW);
+
+ /* setup base memory address registers */
+ idd->SetBasemem(idd, idd->phw.base_mem);
+
+ /* while in reset, clear all idp banks/pages */
+ for ( bank = 0 ; bank < 3 ; bank++ )
+ {
+ /* setup bank */
+ idd->SetBank(idd, (UCHAR)bank, 0);
+
+ /* loop on pages */
+ for ( page = 0 ; page < 4 ; page++ )
+ {
+ /* setup page */
+ idd->ChangePage (idd, (UCHAR)page);
+
+ /* zero out (has to be a word fill!) */
+ IdpMemset((UCHAR*)idd->vhw.vmem, 0, 0x4000);
+ }
+ }
+ //free page
+ idd->ChangePage (idd, (UCHAR)IDD_PAGE_NONE);
+
+ /* set idp to code bank, keep in reset */
+ idd->SetBank(idd, IDD_BANK_CODE, 0);
+
+ /* map file data in */
+ NdisMapFile(&stat, (PVOID*)&fbin_data, idd->phw.fbin);
+
+ if ( stat != NDIS_STATUS_SUCCESS )
+ {
+ D_LOG(D_ALWAYS, ("load_code: file mapping failed!, stat: 0x%x", stat));
+ return(IDD_E_FMAPERR);
+ }
+
+// code to check for filelength greater than 64K
+ if (idd->phw.fbin_len > 0x10000)
+ NumberOfBanks = 2;
+ else
+ NumberOfBanks = 1;
+
+ for (n = 0; n < NumberOfBanks; n++)
+ {
+ /* copy data in (must be a word operation) */
+ for ( page = 0 ; page < 4 ; page++ )
+ {
+ idd->ChangePage(idd, (UCHAR)page);
+
+ IdpMemcpy((UCHAR*)idd->vhw.vmem,
+ (UCHAR*)(fbin_data + (page * 0x4000) + (n * 0x10000)), 0x4000);
+
+// DbgPrint ("Load: Src: 0x%p, Dst: 0x%p, Page: %d\n",
+// (fbin_data + (page*0x4000) + (n * 0x10000)), idd->vhw.vmem, page);
+
+ }
+
+ /* set idp to data bank, keep in reset */
+ idd->SetBank(idd, IDD_BANK_DATA, 0);
+ }
+
+ /* map file data out */
+ NdisUnmapFile(idd->phw.fbin);
+
+ /* switch back to buffer bank */
+ idd->ChangePage(idd, 0);
+ idd->SetBank(idd, IDD_BANK_BUF, 0);
+
+ /* add 'no_uart' definition */
+ NdisMoveMemory(idd->DefinitionTable + idd->DefinitionTableLength,
+ "no_uart\0any\0",
+ 12);
+
+ idd->DefinitionTableLength += 12;
+
+ /* load initial environment */
+ NdisMoveToMappedMemory((PVOID)idd->IdpEnv, (PVOID)idd->DefinitionTable, idd->DefinitionTableLength);
+
+ /* install startup byte signal */
+ NdisMoveToMappedMemory((PVOID)&idd->IdpCmd->status, (PVOID)&status, sizeof(UCHAR));
+
+ /* start idp running, wait for 1 second to complete */
+ idd->SetBank(idd, IDD_BANK_BUF, 1);
+
+ while ( !TimeOut )
+ {
+ NdisMoveFromMappedMemory((PVOID)&status, (PVOID)&idd->IdpCmd->status, sizeof(UCHAR));
+
+ if ( !status )
+ break;
+
+ //
+ // stall for a 1 millisecond
+ //
+ NdisStallExecution(1000L);
+
+ //
+ // add 1 millisecond to timeout counter
+ //
+ CurrentTime += 1;
+
+ //
+ // if timeout counter is greater the 2 seconds we have a problem
+ //
+ if ( CurrentTime > 2000)
+ TimeOut = 1;
+ }
+
+ if (TimeOut)
+ {
+ D_LOG(D_ALWAYS, ("load_code: idp didn't start!"));
+
+ idd->state = IDD_S_SHUTDOWN;
+
+ /* unset page, free memory window */
+ idd->ChangePage(idd, IDD_PAGE_NONE);
+
+ return(IDD_E_RUNERR);
+ }
+
+
+ /* unset page, free memory window */
+ idd->ChangePage(idd, IDD_PAGE_NONE);
+
+ /* if here, idp runs now! */
+ D_LOG(D_EXIT, ("load_code: exit, idp running"));
+ return(IDD_E_SUCC);
+}
+
+
+#pragma NDIS_INIT_FUNCTION(AdpLoadCode)
+
+/* load idp code in & run it */
+INT
+AdpLoadCode(IDD *idd)
+{
+ UCHAR *Zero;
+ UCHAR *fbin_data, status;
+ NDIS_STATUS stat;
+ ADP_BIN_HEADER *Header;
+ ADP_BIN_BLOCK *Block, *FirstBlock;
+ ULONG CurrentTime = 0, TimeOut = 0;
+ USHORT BlockCount = 0;
+ ULONG n;
+
+ NDIS_PHYSICAL_ADDRESS HighestAcceptableMax = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
+
+ D_LOG(D_ENTRY, ("AdpLoadCode: entry, idd: 0x%p", idd));
+
+ //
+ // reset the adapter
+ //
+ AdpWriteControlBit(idd, ADP_RESET_BIT, 1);
+
+ //
+ // clear adapter memory
+ //
+ D_LOG(D_ENTRY, ("AdpLoadCode: Clear Memory"));
+
+ NdisAllocateMemory((PVOID*)&Zero,
+ 0xFFFF,
+ 0,
+ HighestAcceptableMax);
+
+
+ NdisZeroMemory(Zero, 1024);
+
+ for (n = 0; n < ADP_RAM_SIZE; n += 0xFFFF)
+ AdpPutBuffer(idd, n, Zero, (USHORT)0xFFFF);
+
+ NdisFreeMemory(Zero, 0xFFFF, 0);
+
+ //
+ // map file data into memory
+ //
+ NdisMapFile(&stat, (PVOID*)&fbin_data, idd->phw.fbin);
+
+ if ( stat != NDIS_STATUS_SUCCESS )
+ {
+ D_LOG(D_ALWAYS, ("AdpLoadCode: file mapping failed!, stat: 0x%x", stat));
+ return(IDD_E_FMAPERR);
+ }
+
+ //
+ // Get bin file header
+ //
+ (UCHAR*)Header = fbin_data;
+
+ if (Header->Format != ADP_BIN_FORMAT)
+ return(IDD_E_FMAPERR);
+
+ //
+ // Check file size
+ //
+ if (Header->ImageSize > ADP_RAM_SIZE)
+ return(IDD_E_FMAPERR);
+
+ BlockCount = Header->BlockCount;
+ (UCHAR*)FirstBlock = fbin_data + sizeof(ADP_BIN_HEADER);
+
+ for (n = 0; n < BlockCount; n++)
+ {
+ Block = FirstBlock + n;
+
+ AdpPutBuffer(idd, Block->Address, Block->Data, ADP_BIN_BLOCK_SIZE);
+ }
+
+ //
+ // unmap file data
+ //
+ NdisUnmapFile(idd->phw.fbin);
+
+ //
+ // add initial enviornment
+ //
+ /* add 'no_uart' definition */
+ NdisMoveMemory(idd->DefinitionTable + idd->DefinitionTableLength, "no_uart\0any\0", 12);
+ idd->DefinitionTableLength += 12;
+
+ D_LOG(D_ENTRY, ("AdpLoadCode: Add Enviornment"));
+
+ AdpPutBuffer(idd, ADP_ENV_WINDOW, idd->DefinitionTable, idd->DefinitionTableLength);
+
+ //
+ // write startup byte
+ //
+ AdpWriteCommandStatus(idd, ADP_S_PEND);
+
+ //
+ // release processor from reset
+ //
+ AdpWriteControlBit(idd, ADP_RESET_BIT, 0);
+
+ while ( !TimeOut )
+ {
+ status = AdpReadCommandStatus(idd);
+
+ if ( !status )
+ break;
+
+ //
+ // stall for a 1 millisecond
+ //
+ NdisStallExecution(1000L);
+
+ //
+ // add 1 millisecond to timeout counter
+ //
+ CurrentTime += 1;
+
+ //
+ // if timeout counter is greater the 2 seconds we have a problem
+ //
+ if ( CurrentTime > 2000)
+ TimeOut = 1;
+ }
+
+ if (TimeOut)
+ {
+ D_LOG(D_ALWAYS, ("AdpLodeCode: Adp didn't start!"));
+ return(IDD_E_RUNERR);
+ }
+
+ /* if here, Adp runs now! */
+ D_LOG(D_EXIT, ("AdpLoadCode: exit, Adp running"));
+
+ return(IDD_E_SUCC);
+}
+
+
+#pragma NDIS_INIT_FUNCTION(api_setup)
+
+/* setup idp api related fields */
+INT
+api_setup(IDD *idd)
+{
+ INT ret;
+
+ D_LOG(D_ENTRY, ("api_setup: entry, idd: 0x%p", idd));
+
+ /* map port names */
+ if ( (ret = api_map_ports(idd)) != IDD_E_SUCC )
+ return(ret);
+
+ /* bind ports to status bits */
+ if ( (ret = api_bind_ports(idd)) != IDD_E_SUCC )
+ return(ret);
+
+ /* setup partition queues */
+ if ( (ret = api_setup_partq(idd)) != IDD_E_SUCC )
+ return(ret);
+
+ /* allocate initial buffers off partition queues */
+ if ( (ret = api_alloc_partq(idd)) != IDD_E_SUCC )
+ return(ret);
+
+ D_LOG(D_EXIT, ("api_setup: exit, success"));
+
+ return(IDD_E_SUCC);
+}
+
+#pragma NDIS_INIT_FUNCTION(api_map_ports)
+
+/* map port names to ids */
+INT
+api_map_ports(IDD *idd)
+{
+ INT n;
+
+ D_LOG(D_ENTRY, ("api_map_ports: entry, idd: 0x%p", idd));
+
+ /* map rx ports */
+ for ( n = 0 ; api_rx_port_tbl[n].name ; n++ )
+ {
+ idd->rx_port[n] = idd->ApiGetPort(idd, api_rx_port_tbl[n].name);
+
+ D_LOG(D_ALWAYS, ("api_map_ports: RxPorts: PortName: %s, PortId: 0x%x", api_rx_port_tbl[n].name, idd->rx_port[n]));
+
+ if ( !idd->rx_port[n] && api_rx_port_tbl[n].must )
+ {
+ D_LOG(D_ALWAYS, ("api_map_ports: failed to map rx port [%s]", \
+ api_rx_port_tbl[n].name));
+ return(IDD_E_PORTMAPERR);
+ }
+ }
+
+ /* map tx ports */
+ for ( n = 0 ; api_tx_port_tbl[n].name ; n++ )
+ {
+ idd->tx_port[n] = idd->ApiGetPort(idd, api_tx_port_tbl[n].name);
+
+ D_LOG(D_ALWAYS, ("api_map_ports: TxPorts: PortName: %s, PortId: 0x%x", api_tx_port_tbl[n].name, idd->tx_port[n]));
+
+ if ( !idd->tx_port[n] && api_tx_port_tbl[n].must )
+ {
+ D_LOG(D_ALWAYS, ("api_map_ports: failed to map tx port [%s]", \
+ api_tx_port_tbl[n].name));
+ return(IDD_E_PORTMAPERR);
+ }
+ }
+ return(IDD_E_SUCC);
+}
+
+#pragma NDIS_INIT_FUNCTION(api_bind_ports)
+
+/* bind ports to status bits */
+INT
+api_bind_ports(IDD *idd)
+{
+ INT n;
+
+ D_LOG(D_ENTRY, ("api_bind_ports: entry, idd: 0x%p", idd));
+
+ /* bind rx ports */
+ for ( n = 0 ; api_rx_port_tbl[n].name; n++ )
+ {
+ if (idd->rx_port[n])
+ if ( idd->ApiBindPort(idd, idd->rx_port[n], (USHORT)(1 << n)) < 0 )
+ {
+ D_LOG(D_ALWAYS, ("api_bind_ports: failed to bind status bit on port [%s]", \
+ api_rx_port_tbl[n].name));
+ return(IDD_E_PORTBINDERR);
+ }
+ }
+
+ return(IDD_E_SUCC);
+}
+
+#pragma NDIS_INIT_FUNCTION(api_setup_partq)
+
+/* setup partition queues */
+INT
+api_setup_partq(IDD *idd)
+{
+ INT n;
+
+ D_LOG(D_ENTRY, ("api_setup_partq: entry, idd: 0x%p", idd));
+
+ /* simply copy table */
+ for ( n = 0 ; n < IDD_TX_PORTS ; n++ )
+ idd->tx_partq[n] = api_tx_partq_tbl[n];
+
+ return(IDD_E_SUCC);
+}
+
+#pragma NDIS_INIT_FUNCTION(api_alloc_partq)
+
+/* allocate initial buffers off partition queues */
+INT
+api_alloc_partq(IDD *idd)
+{
+ INT n, part;
+
+ D_LOG(D_ENTRY, ("api_alloc_partq: entry, idd: 0x%p", idd));
+
+ /* scan using partq_tbl as a refrence. allocate only once per partq */
+ for ( n = 0 ; n < IDD_TX_PORTS ; n++ )
+ if ( !idd->tx_buf[part = api_tx_partq_tbl[n]] )
+ {
+ if ( !(idd->tx_buf[part] = idd->ApiAllocBuffer(idd, part)) )
+ {
+ D_LOG(D_ALWAYS, ("api_alloc_partq: failed to alloc initial buffer, part: %d", part));
+ DbgPrint("api_alloc_partq: failed to alloc initial buffer, part: %d\n", part);
+ return(IDD_E_PARTQINIT);
+ }
+#if DBG
+ ASSERT(!idd->BufferStuff[part].Buffer[0]);
+ idd->BufferStuff[part].Buffer[0] = idd->tx_buf[part];
+ idd->BufferStuff[part].Count++;
+ idd->BufferStuff[part].Put++;
+ idd->BufferStuff[part].Get = 0;
+ ASSERT(idd->BufferStuff[part].Count < 32);
+#endif
+ }
+
+ return(IDD_E_SUCC);
+}
+
+#pragma NDIS_INIT_FUNCTION(IdpGetPort)
+
+/* get port id from a name */
+USHORT
+IdpGetPort(IDD *idd, CHAR name[8])
+{
+ UCHAR status;
+ USHORT port_id;
+
+ D_LOG(D_ENTRY, ("IdpGetPort: entry, idd: 0x%p, name: [%s]", idd, name));
+
+ idd->ChangePage(idd, 0);
+
+ /* install target name & execute a map */
+ NdisMoveToMappedMemory ((CHAR *)idd->IdpCmd->port_name, (CHAR *)name, 8);
+
+ status = idd->Execute(idd, IDP_L_MAP);
+
+ NdisMoveFromMappedMemory((PVOID)&port_id, (PVOID)&idd->IdpCmd->port_id, sizeof(USHORT));
+
+ idd->ChangePage(idd, IDD_PAGE_NONE);
+
+ D_LOG(D_EXIT, ("IdpGetPort: exit, port_id: 0x%x", port_id));
+
+ return( (status == IDP_S_OK) ? port_id : 0);
+}
+
+#pragma NDIS_INIT_FUNCTION(AdpGetPort)
+
+/* get port id from a name */
+USHORT
+AdpGetPort(IDD *idd, CHAR name[8])
+{
+ UCHAR status;
+ D_LOG(D_ENTRY, ("AdpGetPort: entry, idd: 0x%p, name: [%s]", idd, name));
+
+ //
+ // clear command structure
+ //
+ NdisZeroMemory(&idd->AdpCmd, sizeof(ADP_CMD));
+
+ //
+ // put port name in command structure
+ //
+ NdisMoveMemory((PVOID)&idd->AdpCmd.port_name, name, 8);
+
+ //
+ // execute command
+ //
+ status = idd->Execute(idd, ADP_L_MAP);
+
+ //
+ // check return status
+ //
+ if (status != ADP_S_OK)
+ return(0);
+
+ D_LOG(D_ALWAYS, ("AdpGetPort: PortId: 0x%x", idd->AdpCmd.port_id));
+ //
+ // return port
+ //
+ return(idd->AdpCmd.port_id);
+}
+
+
+#pragma NDIS_INIT_FUNCTION(IdpBindPort)
+
+/* bind a port to a status bit */
+INT
+IdpBindPort(IDD *idd, USHORT port, USHORT bitpatt)
+{
+ UCHAR status;
+
+ D_LOG(D_ENTRY, ("IdpBindPort: entry, idd: 0x%p, port: 0x%x, bitpatt: 0x%x",
+ idd, port, bitpatt));
+
+ idd->ChangePage(idd, 0);
+
+ /* fillup cmd & execute a bind */
+ NdisMoveToMappedMemory((PVOID)&idd->IdpCmd->port_id, (PVOID)&port, sizeof(USHORT));
+ NdisMoveToMappedMemory((PVOID)&idd->IdpCmd->port_bitpatt, (PVOID)&bitpatt, sizeof(USHORT));
+
+ status = idd->Execute(idd, IDP_L_BIND);
+
+ idd->ChangePage(idd, IDD_PAGE_NONE);
+
+ return( (status == IDP_S_OK) ? 0 : -1 );
+}
+
+#pragma NDIS_INIT_FUNCTION(AdpBindPort)
+
+/* bind a port to a status bit */
+INT
+AdpBindPort(IDD *idd, USHORT port, USHORT bitpatt)
+{
+ UCHAR status;
+
+ D_LOG(D_ENTRY, ("AdpBindPort: entry, idd: 0x%p, port: 0x%x, bitpatt: 0x%x",
+ idd, port, bitpatt));
+ //
+ // clear command structure
+ //
+ NdisZeroMemory(&idd->AdpCmd, sizeof(ADP_CMD));
+
+ //
+ // fill port id and status bit
+ //
+ idd->AdpCmd.port_id = port;
+ idd->AdpCmd.port_bitpatt = bitpatt;
+
+ //
+ // execute command
+ //
+ status = idd->Execute(idd, ADP_L_BIND);
+
+ D_LOG(D_ALWAYS, ("AdpBindPort: ExecuteStatus: 0x%x", status));
+
+ if (status != ADP_S_OK)
+ return(1);
+
+ return(0);
+}
+
+
+#pragma NDIS_INIT_FUNCTION(IdpAllocBuf)
+
+/* allocate a buffer off a partition */
+ULONG
+IdpAllocBuf(IDD *idd, INT part)
+{
+ UCHAR status;
+ ULONG msg_bufptr;
+ ULONG temp;
+
+ D_LOG(D_ENTRY, ("IdpAllocBuf: entry, idd: 0x%p, part: %d", idd, part));
+
+ idd->ChangePage(idd, 0);
+
+ /* fillup & execute */
+ temp = (ULONG)(part + 4);
+
+ NdisMoveToMappedMemory ((PVOID)&idd->IdpCmd->msg_param, (PVOID)&temp, sizeof (ULONG));
+
+ status = idd->Execute(idd, IDP_L_GET_WBUF);
+
+ NdisMoveFromMappedMemory((PVOID)&msg_bufptr, (PVOID)&idd->IdpCmd->msg_bufptr, (ULONG)sizeof (ULONG));
+
+ idd->ChangePage(idd, IDD_PAGE_NONE);
+
+ return( (status == IDP_S_OK) ? msg_bufptr : 0 );
+}
+
+#pragma NDIS_INIT_FUNCTION(AdpAllocBuf)
+
+/* allocate a buffer off a partition */
+ULONG
+AdpAllocBuf(IDD *idd, INT part)
+{
+ UCHAR status;
+
+ D_LOG(D_ENTRY, ("AdpAllocBuf: entry, idd: 0x%p, part: %d", idd, part));
+
+ //
+ // clear command structure
+ //
+ NdisZeroMemory(&idd->AdpCmd, sizeof(ADP_CMD));
+
+ //
+ // fill port id and status bit
+ //
+ idd->AdpCmd.msg_param = (UCHAR)part + 4;
+ //
+ // execute command
+ //
+ status = idd->Execute(idd, ADP_L_GET_WBUF);
+
+ D_LOG(D_ALWAYS, ("AdpAllocBuf: status: 0x%x, BufPtr: 0x%x", status, idd->AdpCmd.msg_bufptr));
+
+ return ((status == ADP_S_OK) ? (ULONG)idd->AdpCmd.msg_bufptr : 0);
+}
+
+/* reset idp board */
+INT
+IdpResetBoard(IDD *idd)
+{
+ USHORT bank, page;
+ D_LOG(D_ENTRY, ("reset_board: entry, idd: 0x%p", idd));
+
+ /* while in reset, clear all idp banks/pages */
+ for ( bank = 0 ; bank < 3 ; bank++ )
+ {
+ /* setup bank */
+ idd->SetBank(idd, (UCHAR)bank, 0);
+
+ /* loop on pages */
+ for ( page = 0 ; page < 4 ; page++ )
+ {
+ /* setup page */
+ idd->ChangePage (idd, (UCHAR)page);
+
+ /* zero out (has to be a word fill!) */
+ IdpMemset((UCHAR*)idd->vhw.vmem, 0, 0x4000);
+ }
+ }
+
+ idd->SetBank(idd, IDD_BANK_CODE, 0);
+
+ //free page
+ idd->ChangePage (idd, (UCHAR)IDD_PAGE_NONE);
+
+ return(IDD_E_SUCC);
+}
+
+/* reset idp board */
+INT
+AdpResetBoard(IDD *idd)
+{
+ //
+ // reset the adapter
+ //
+ AdpWriteControlBit(idd, ADP_RESET_BIT, 1);
+
+ return(IDD_E_SUCC);
+}
+
diff --git a/private/ntos/ndis/pcimac/idp_xfs.bin b/private/ntos/ndis/pcimac/idp_xfs.bin
new file mode 100644
index 000000000..1d197d24b
--- /dev/null
+++ b/private/ntos/ndis/pcimac/idp_xfs.bin
Binary files differ
diff --git a/private/ntos/ndis/pcimac/io.h b/private/ntos/ndis/pcimac/io.h
new file mode 100644
index 000000000..a8997c7de
--- /dev/null
+++ b/private/ntos/ndis/pcimac/io.h
@@ -0,0 +1,21 @@
+/*
+ * IO.H - include file for all IO modules
+ */
+
+#ifndef _IO_
+#define _IO_
+
+#include <io_pub.h>
+
+/* forward for ioctl filter function */
+NTSTATUS PcimacIoctl(DEVICE_OBJECT* DeviceObject, IRP* Irp);
+
+NTSTATUS ExecIrp(IRP *irp, IO_STACK_LOCATION *irpsp);
+
+
+/* ioctl opcode to executing commands */
+#define IO_IOCTL_PCIMAC_EXEC 0x160040/* temp!!! */
+
+INT io_execute(IO_CMD* cmd, VOID *Irp_1);
+
+#endif /* _IO_ */
diff --git a/private/ntos/ndis/pcimac/io_core.c b/private/ntos/ndis/pcimac/io_core.c
new file mode 100644
index 000000000..209adecd9
--- /dev/null
+++ b/private/ntos/ndis/pcimac/io_core.c
@@ -0,0 +1,322 @@
+/*
+ * IO_CORE.C - core routines for IO module
+ */
+
+#include <ndis.h>
+//#include <ndismini.h>
+#include <ndiswan.h>
+#include <mydefs.h>
+#include <mytypes.h>
+#include <util.h>
+#include <disp.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+#include <trc.h>
+#include <io.h>
+
+extern DRIVER_BLOCK Pcimac;
+
+/* store location for prev. ioctl handler */
+extern NTSTATUS (*PrevIoctl)(DEVICE_OBJECT* DeviceObject, IRP* Irp);
+
+/* ioctl filter */
+NTSTATUS
+PcimacIoctl(DEVICE_OBJECT *DeviceObject, IRP *Irp)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
+ NTSTATUS ini_exec_irp(IRP* irp, IO_STACK_LOCATION* irpsp);
+
+ /* must be an ioctl, else pass this one */
+ if ( irpSp->MajorFunction != IRP_MJ_DEVICE_CONTROL )
+ {
+ pass:
+ NdisReleaseSpinLock(&Pcimac.lock);
+
+ return(PrevIoctl(DeviceObject, Irp));
+ }
+
+ /* must be our own private ioctl code */
+ if (irpSp->Parameters.DeviceIoControl.IoControlCode != IO_IOCTL_PCIMAC_EXEC )
+ goto pass;
+
+ /* one of our own, execute */
+ Irp->IoStatus.Information = 0L;
+ ExecIrp(Irp, irpSp);
+
+ /* complete irp */
+ Irp->IoStatus.Status = status;
+ IoSetCancelRoutine (Irp, NULL);
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return(status);
+}
+
+/* execute ioctl irp */
+NTSTATUS
+ExecIrp(IRP *irp, IO_STACK_LOCATION *irpsp)
+{
+ UCHAR *in_buf, *out_buf;
+ ULONG in_len, out_len;
+ NTSTATUS stat;
+
+ /* establish in/out buffers */
+ out_len = irpsp->Parameters.DeviceIoControl.OutputBufferLength;
+ in_len = irpsp->Parameters.DeviceIoControl.InputBufferLength;
+ out_buf = irp->UserBuffer;
+ in_buf = irp->AssociatedIrp.SystemBuffer;
+
+
+ /* in/out length must be the same */
+ if ( in_len != out_len )
+ return(STATUS_UNSUCCESSFUL);
+
+ /* copy in buffer into output buffer */
+ NdisMoveMemory(out_buf, in_buf, out_len);
+
+ /* execute command in place */
+ if ( (stat = io_execute((IO_CMD*)out_buf,irp)) == IO_E_PENDING)
+ /* event added pend irp */
+ return (STATUS_PENDING);
+ else
+ /* return success */
+ return(STATUS_SUCCESS);
+}
+
+
+/* execute an io command */
+INT
+io_execute(IO_CMD *cmd, VOID *Irp_1)
+{
+ IRP *Irp = (IRP*)Irp_1;
+
+ D_LOG(D_ENTRY, ("io_execute: entry, cmd: 0x%p", cmd));
+
+ /* check signature & version */
+ if ( cmd->sig != IO_CMD_SIG )
+ return(IO_E_BADSIG);
+ if ( (cmd->ver_major != IO_VER_MAJOR) ||
+ (cmd->ver_minor != IO_VER_MINOR) )
+ return(IO_E_BADVER);
+
+ D_LOG(D_ALWAYS, ("io_execute: opcode: 0x%x, cm: 0x%p, idd: 0x%p", \
+ cmd->opcode, cmd->cm, cmd->idd));
+ D_LOG(D_ALWAYS, ("io_execute: args: 0x%x 0x%x 0x%x 0x%x", \
+ cmd->arg[0], cmd->arg[1], cmd->arg[2], cmd->arg[3]));
+
+
+ /* clear status, assume success */
+ cmd->status = IO_E_SUCC;
+
+ /* branch on opcode */
+ switch ( cmd->opcode )
+ {
+
+ case IO_CMD_ENUM_ADAPTERS :
+ cmd->status = IoEnumAdapter(cmd);
+ break;
+
+ case IO_CMD_ENUM_CM:
+ cmd->status = IoEnumCm(cmd);
+ break;
+
+ case IO_CMD_ENUM_IDD :
+ cmd->status = IoEnumIdd(cmd);
+ break;
+
+ case IO_CMD_TRC_RESET :
+ cmd->status = trc_control(cmd->idd,
+ TRC_OP_RESET, (ULONG)cmd->idd);
+ break;
+
+ case IO_CMD_TRC_STOP :
+ cmd->status = trc_control(cmd->idd,
+ TRC_OP_STOP, (ULONG)cmd->idd);
+ break;
+
+ case IO_CMD_TRC_START :
+ cmd->status = trc_control(cmd->idd,
+ TRC_OP_START, (ULONG)cmd->idd);
+ break;
+
+ case IO_CMD_TRC_SET_FILT :
+ cmd->status = trc_control(cmd->idd,
+ TRC_OP_SET_FILTER, cmd->arg[0]);
+ break;
+
+ case IO_CMD_IDD_RESET_AREA :
+ cmd->status = idd_reset_area(cmd->idd);
+ break;
+
+ case IO_CMD_IDD_GET_AREA :
+ cmd->status = idd_get_area(cmd->idd, cmd->arg[0], NULL, NULL);
+ break;
+
+ case IO_CMD_IDD_GET_STAT :
+ cmd->status = idd_get_area_stat(cmd->idd, &cmd->val.IddStat);
+ break;
+
+ case IO_CMD_TRC_CREATE:
+ cmd->status = trc_control(cmd->idd,
+ TRC_OP_CREATE, cmd->arg[0]);
+ break;
+
+ case IO_CMD_TRC_DESTROY:
+ cmd->status = trc_control(cmd->idd,
+ TRC_OP_DESTROY, cmd->arg[0]);
+ break;
+
+ case IO_CMD_TRC_GET_STAT :
+ cmd->status = trc_get_status(idd_get_trc(cmd->idd),
+ &cmd->val.trc_stat);
+ break;
+
+ case IO_CMD_TRC_GET_ENT :
+ cmd->status = trc_get_entry(idd_get_trc(cmd->idd),
+ cmd->arg[0], &cmd->val.trc_ent);
+ break;
+
+ case IO_CMD_DBG_LEVEL :
+ SetDebugLevel(cmd);
+ break;
+
+ case IO_CMD_DO_IDP_CMD:
+ DbgPrint("DoIdpCmd: Cmd: 0x%x\n", cmd->arg[0]);
+ if (cmd->idd && ((IDD*)cmd->idd)->btype != IDD_BT_DATAFIREU)
+ {
+ switch (cmd->arg[0])
+ {
+ case GET_IDP_IO_VALUE:
+ cmd->val.IdpRaw.uc = IdpGetUByteIO(cmd->idd,
+ cmd->val.IdpRaw.us);
+ cmd->status = IO_E_SUCC;
+ break;
+
+
+ case GET_IDP_BUFFER:
+ IdpGetBuffer(cmd->idd,
+ cmd->val.IdpRaw.Bank,
+ cmd->val.IdpRaw.Page,
+ cmd->val.IdpRaw.Address,
+ cmd->val.IdpRaw.Length,
+ cmd->val.IdpRaw.Buffer);
+
+ cmd->status = IO_E_SUCC;
+ break;
+
+ case SET_IDP_IO_VALUE:
+ IdpPutUByteIO(cmd->idd,
+ (USHORT)cmd->val.IdpRaw.Address,
+ cmd->val.IdpRaw.uc);
+ cmd->status = IO_E_SUCC;
+ break;
+
+ case SET_IDP_BUFFER:
+ IdpPutBuffer(cmd->idd,
+ cmd->val.IdpRaw.Bank,
+ cmd->val.IdpRaw.Page,
+ cmd->val.IdpRaw.Address,
+ cmd->val.IdpRaw.Length,
+ cmd->val.IdpRaw.Buffer);
+
+ cmd->status = IO_E_SUCC;
+ break;
+
+ default:
+ cmd->status = IO_E_BADCMD;
+ break;
+ }
+ }
+ else
+ cmd->status = IO_E_BADIDD;
+ break;
+
+ case IO_CMD_DO_ADP_CMD:
+ if (cmd->idd && ((IDD*)cmd->idd)->btype == IDD_BT_DATAFIREU)
+ {
+ switch (cmd->arg[0])
+ {
+ case GET_ADP_UCHAR:
+ cmd->val.AdpRaw.uc = AdpGetUByte(cmd->idd,
+ cmd->val.AdpRaw.Address);
+
+ cmd->status = IO_E_SUCC;
+ break;
+
+ case GET_ADP_USHORT:
+ cmd->val.AdpRaw.us = AdpGetUShort(cmd->idd,
+ cmd->val.AdpRaw.Address);
+
+ cmd->status = IO_E_SUCC;
+ break;
+
+ case GET_ADP_ULONG:
+ cmd->val.AdpRaw.ul = AdpGetULong(cmd->idd,
+ cmd->val.AdpRaw.Address);
+
+ cmd->status = IO_E_SUCC;
+ break;
+
+ case GET_ADP_BUFFER:
+ AdpGetBuffer(cmd->idd,
+ cmd->val.AdpRaw.Buffer,
+ cmd->val.AdpRaw.Address,
+ cmd->val.AdpRaw.Length
+ );
+
+ cmd->status = IO_E_SUCC;
+ break;
+
+ case SET_ADP_UCHAR:
+ AdpPutUByte(cmd->idd,
+ cmd->val.AdpRaw.Address,
+ cmd->val.AdpRaw.uc);
+
+ cmd->status = IO_E_SUCC;
+ break;
+
+ case SET_ADP_USHORT:
+ AdpPutUShort(cmd->idd,
+ cmd->val.AdpRaw.Address,
+ cmd->val.AdpRaw.us);
+
+ cmd->status = IO_E_SUCC;
+ break;
+
+ case SET_ADP_ULONG:
+ AdpPutULong(cmd->idd,
+ cmd->val.AdpRaw.Address,
+ cmd->val.AdpRaw.ul);
+
+ cmd->status = IO_E_SUCC;
+ break;
+
+ case SET_ADP_BUFFER:
+ AdpPutBuffer(cmd->idd,
+ cmd->val.AdpRaw.Address,
+ cmd->val.AdpRaw.Buffer,
+ cmd->val.AdpRaw.Length);
+
+ cmd->status = IO_E_SUCC;
+ break;
+
+ default:
+ cmd->status = IO_E_BADCMD;
+ break;
+ }
+ }
+ else
+ cmd->status = IO_E_BADIDD;
+
+ break;
+
+ default :
+ cmd->status = IO_E_BADCMD;
+ break;
+ }
+
+ /* return status code */
+ return((INT)cmd->status);
+}
diff --git a/private/ntos/ndis/pcimac/io_pub.h b/private/ntos/ndis/pcimac/io_pub.h
new file mode 100644
index 000000000..1c9c06f80
--- /dev/null
+++ b/private/ntos/ndis/pcimac/io_pub.h
@@ -0,0 +1,140 @@
+/*
+ * IO_PUB.H - include file for all IO modules
+ */
+
+#ifndef _IO_PUB_
+#define _IO_PUB_
+
+/* error codes */
+#define IO_E_SUCC 0 /* success */
+#define IO_E_NOROOM 1 /* no room in local tables */
+#define IO_E_NOSUCH 2 /* no such object */
+#define IO_E_BADSIG 3 /* bad signature */
+#define IO_E_BADVER 4 /* bad version */
+#define IO_E_BADCMD 5 /* bad command opcode */
+#define IO_E_BADIDD 6
+#define IO_E_BADCM 7
+#define IO_E_PENDING 0xFF /* command is pending */
+
+/* IO commands available listed here */
+#define IO_CMD_ENUM_ADAPTERS 0x100 /* enumerate network interfaces */
+#define IO_CMD_ENUM_IDD 0x101 /* enumerate isdn device drivers */
+#define IO_CMD_ENUM_CM 0x102 /* enumerate connection managers */
+
+#define IO_CMD_TRC_RESET 0x300 /* reset trace */
+#define IO_CMD_TRC_STOP 0x301 /* stop trace */
+#define IO_CMD_TRC_START 0x302 /* start trace */
+#define IO_CMD_TRC_SET_FILT 0x305 /* set filter for trace context */
+#define IO_CMD_TRC_GET_STAT 0x306 /* get status of trace context */
+#define IO_CMD_TRC_GET_ENT 0x307 /* get a trace entry */
+#define IO_CMD_TRC_CREATE 0x30A /* create trc object */
+#define IO_CMD_TRC_DESTROY 0x30B /* destroy trc object */
+
+#define IO_CMD_DO_ADP_CMD 0x400
+#define MAX_ADP_OPERATIONS 8
+#define GET_ADP_UCHAR 1
+#define GET_ADP_USHORT 2
+#define GET_ADP_ULONG 3
+#define GET_ADP_BUFFER 4
+#define SET_ADP_UCHAR 5
+#define SET_ADP_USHORT 6
+#define SET_ADP_ULONG 7
+#define SET_ADP_BUFFER 8
+
+#define IO_CMD_DO_IDP_CMD 0x401
+#define MAX_IDP_OPERATIONS 4
+#define GET_IDP_IO_VALUE 1
+#define GET_IDP_BUFFER 2
+#define SET_IDP_IO_VALUE 3
+#define SET_IDP_BUFFER 4
+
+#define IO_CMD_IDD_GET_AREA 0x900 /* get idd area */
+#define IO_CMD_IDD_RESET_AREA 0x901 /* reset idd area state */
+#define IO_CMD_IDD_GET_STAT 0x902 /* get area state */
+
+#define IO_CMD_DBG_LEVEL 0xF00 /* set debug level */
+
+/* master descriptor structure for ioctl commands to IO module */
+typedef struct
+{
+ ULONG sig; /* identifing signature */
+#define IO_CMD_SIG 0x321B71B7
+
+ USHORT ver_major, ver_minor; /* interface version (curr: 0.1) */
+#define IO_VER_MAJOR 0
+#define IO_VER_MINOR 1
+
+ ULONG opcode; /* command opcode, IO_CMD_* */
+
+ ULONG status; /* completion status, ok: 0 */
+
+ VOID *cm; /* related connection object */
+ VOID *idd; /* related idd */
+ ULONG arg[4]; /* 4 general purpose args */
+
+ union /* opcode specific data */
+ {
+ struct /* IO_CMD_ENUM_ADAPTERS */
+ {
+ USHORT num;
+ ULONG BaseIO[MAX_ADAPTERS_IN_SYSTEM];
+ ULONG BaseMem[MAX_ADAPTERS_IN_SYSTEM];
+ ULONG BoardType[MAX_ADAPTERS_IN_SYSTEM];
+ CHAR Name[MAX_ADAPTERS_IN_SYSTEM][64];
+ VOID *tbl[MAX_ADAPTERS_IN_SYSTEM];
+ } enum_adapters;
+
+ struct /* IO_CMD_ENUM_MTL */
+ {
+ USHORT num;
+ CHAR name[MAX_CM_IN_SYSTEM][64];
+ VOID *tbl[MAX_CM_IN_SYSTEM];
+ } enum_cm;
+
+ struct /* IO_CMD_ENUM_IDD */
+ {
+ USHORT num;
+ VOID *tbl[MAX_IDD_IN_SYSTEM];
+ CHAR name[MAX_IDD_IN_SYSTEM][64];
+ } enum_idd;
+
+ struct
+ {
+ INT cmplen;
+ CHAR filestr[9];
+ } dbg_level;
+
+ CM_STATUS cm_stat; /* IO_CMD_CM_GET_STAT */
+
+ TRC_STATUS trc_stat; /* IO_CMD_TRC_GET_STAT */
+ TRC_ENTRY trc_ent; /* IO_CMD_TRC_GET_ENT */
+ IDD_AREA IddStat; // IO_CMD_GET_IDD_STAT
+
+ struct
+ {
+ UCHAR uc;
+ USHORT us;
+ ULONG ul;
+ ULONG Address;
+ USHORT Length;
+ UCHAR Buffer[ADP_RAM_SIZE];
+ } AdpRaw;
+
+ struct
+ {
+ UCHAR uc;
+ USHORT us;
+ ULONG ul;
+ USHORT Bank;
+ USHORT Page;
+ ULONG Address;
+ USHORT Length;
+ UCHAR Buffer[IDP_RAM_PAGE_SIZE];
+ } IdpRaw;
+
+ } val;
+
+} IO_CMD;
+
+#endif /* _IO_PUB_ */
+
diff --git a/private/ntos/ndis/pcimac/lanoid.c b/private/ntos/ndis/pcimac/lanoid.c
new file mode 100644
index 000000000..90758ce8a
--- /dev/null
+++ b/private/ntos/ndis/pcimac/lanoid.c
@@ -0,0 +1,243 @@
+//#include <ntddk.h>
+#include <ndis.h>
+//#include <ndismini.h>
+#include <ndiswan.h>
+//#include <ntddndis.h>
+#include <stdio.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <adapter.h>
+#include <util.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+#include <res.h>
+#include <trc.h>
+#include <io.h>
+
+
+#define PCIMAC_MAJOR_VERSION 2
+#define PCIMAC_MINOR_VERSION 0
+
+//
+// Lan OID's
+//
+static UINT SupportedLanOids[] =
+ {
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ OID_802_3_RCV_ERROR_ALIGNMENT,
+ OID_802_3_XMIT_ONE_COLLISION,
+ OID_802_3_XMIT_MORE_COLLISIONS
+ };
+
+#define MAX_SUPPORTED_LAN_OIDS 31
+
+
+
+
+NDIS_STATUS
+LanOidProc(
+ NDIS_HANDLE AdapterContext,
+ NDIS_OID Oid,
+ PVOID InfoBuffer,
+ ULONG InfoBufferLen,
+ PULONG BytesReadWritten,
+ PULONG BytesNeeded
+ )
+{
+ ADAPTER *Adapter = (ADAPTER*)AdapterContext;
+ CM *cm = (CM*)Adapter->CmTbl[0];
+ ULONG GenericULong;
+ USHORT GenericUShort;
+ UCHAR GenericArray[6];
+ UINT MoveBytes = sizeof(ULONG);
+ PVOID MoveSource = (PVOID)(&GenericULong);
+ UINT BytesLeft = InfoBufferLen;
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+ NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady;
+ NDIS_MEDIUM Medium = NdisMedium802_3;
+ ULONG OidType = 0;
+ ULONG Filter;
+
+ switch (Oid)
+ {
+ case OID_802_3_MULTICAST_LIST:
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ MoveBytes = BytesLeft;
+ OidType = 1;
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ MoveBytes = BytesLeft;
+ OidType = 1;
+ NdisMoveMemory(&Filter, InfoBuffer, 4);
+
+ if (Filter & (NDIS_PACKET_TYPE_SOURCE_ROUTING |
+ NDIS_PACKET_TYPE_SMT |
+ NDIS_PACKET_TYPE_MAC_FRAME |
+ NDIS_PACKET_TYPE_FUNCTIONAL |
+ NDIS_PACKET_TYPE_ALL_FUNCTIONAL |
+ NDIS_PACKET_TYPE_GROUP
+ ))
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+
+ case OID_GEN_MAC_OPTIONS:
+ GenericULong = (ULONG)(NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
+ NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
+ NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
+ NDIS_MAC_OPTION_NO_LOOPBACK);
+
+ break;
+
+ case OID_GEN_SUPPORTED_LIST:
+ MoveSource = (PVOID)(SupportedLanOids);
+ MoveBytes = sizeof(SupportedLanOids);
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+ MoveSource = (PVOID)(&HardwareStatus);
+ MoveBytes = sizeof(NDIS_HARDWARE_STATUS);
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+ MoveSource = (PVOID)(&Medium);
+ MoveBytes = sizeof(NDIS_MEDIUM);
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+ GenericULong = (ULONG)1514;
+ break;
+
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+ GenericULong = (ULONG)1500;
+ break;
+
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+ GenericULong = (ULONG)1514;
+ break;
+
+ case OID_GEN_LINK_SPEED:
+ GenericULong = (ULONG)12800;
+ break;
+
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+ GenericULong = (ULONG)(1514 * 16);
+ break;
+
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+ GenericULong = (ULONG)(1514 * 16);
+ break;
+
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+ GenericULong = (ULONG)256;
+ break;
+
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+ GenericULong = (ULONG)256;
+ break;
+
+ case OID_GEN_VENDOR_ID:
+ NdisMoveMemory((PVOID)&GenericULong,
+ cm->SrcAddr,
+ 3);
+
+ GenericULong &= 0xFFFFFF00;
+ GenericULong |= 0x01;
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+ MoveSource = (PVOID)"DigiBoard Pcimac ISDN Adapter.";
+ MoveBytes = strlen("DigiBoard Pcimac ISDN Adapter.");
+ break;
+
+ case OID_GEN_DRIVER_VERSION:
+ GenericUShort = ((USHORT)PCIMAC_MAJOR_VERSION << 8) |
+ PCIMAC_MINOR_VERSION;
+ MoveSource = (PVOID)(&GenericUShort);
+ MoveBytes = sizeof(USHORT);
+ break;
+
+ case OID_802_3_PERMANENT_ADDRESS:
+ NdisMoveMemory((PVOID)GenericArray,
+ cm->SrcAddr,
+ 6);
+ MoveSource = (PVOID)GenericArray;
+ MoveBytes = 6;
+ break;
+
+ case OID_802_3_CURRENT_ADDRESS:
+ NdisMoveMemory((PVOID)GenericArray,
+ cm->SrcAddr,
+ 6);
+ MoveSource = (PVOID)GenericArray;
+ MoveBytes = 6;
+ break;
+
+ case OID_GEN_XMIT_OK:
+ case OID_GEN_RCV_OK:
+ case OID_GEN_XMIT_ERROR:
+ case OID_GEN_RCV_ERROR:
+ case OID_GEN_RCV_NO_BUFFER:
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+ case OID_802_3_XMIT_ONE_COLLISION:
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+ GenericULong = (ULONG)0;
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+ GenericULong = (ULONG)16;
+ break;
+
+ default:
+ StatusToReturn = NDIS_STATUS_INVALID_OID;
+ break;
+ }
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS)
+ {
+ *BytesNeeded = 0;
+ if (MoveBytes > BytesLeft)
+ {
+ *BytesNeeded = MoveBytes;
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+ }
+ else if (OidType == 0)
+ {
+ NdisMoveMemory(InfoBuffer, MoveSource, MoveBytes);
+ (*BytesReadWritten) = MoveBytes;
+ }
+ }
+ return(StatusToReturn);
+}
+
+
diff --git a/private/ntos/ndis/pcimac/makefile b/private/ntos/ndis/pcimac/makefile
new file mode 100644
index 000000000..677d610db
--- /dev/null
+++ b/private/ntos/ndis/pcimac/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/pcimac/mtl.h b/private/ntos/ndis/pcimac/mtl.h
new file mode 100644
index 000000000..06d71919c
--- /dev/null
+++ b/private/ntos/ndis/pcimac/mtl.h
@@ -0,0 +1,306 @@
+/*
+ * MTL.H - include file for all MTL modules
+ */
+
+#ifndef _MTL_
+#define _MTL_
+
+/* some constants values */
+// The value for mtl_max_chan has to be <= the value for
+// cm_max_chan in cm_pub.h
+
+//
+// I set the MTU to a large enough value to allow multi-link,
+// bridging and any other future expansion to occur.
+//
+#define MTL_MAC_MTU 1600 /* mac size mtu, fixed */
+
+#define MTL_IDD_MTU 260 /* idd size mtu, default value */
+
+//
+// a guess at how much receive space we will need this is 1514 * 16 wich seems
+// like alot to me
+//
+#define MTL_RX_BUFS 16 /* # of recieve buffers, must be 2^n */
+
+//
+// max local tx descriptor buffers based on the maximum number of
+// wanpackets we told the wrapper it could send (mydefs.h MAX_WANPACKET_XMITS)
+//
+#define MTL_TX_BUFS 8 /* # of transmit buffers */
+
+//
+// max fragments per packet
+//
+#define MTL_MAX_FRAG 16
+
+//
+// index into buffer where destination ethernet address starts
+//
+#define DST_ADDR_INDEX 0
+
+//
+// index into buffer where source ethernet address starts
+//
+#define SRC_ADDR_INDEX 6
+
+//
+// index into buffer where length of buffer starts
+//
+#define PKT_LEN_INDEX 12
+
+/* mtl error codes */
+#define MTL_E_SUCC 0
+#define MTL_E_NOMEM 1
+#define MTL_E_NOTIMPL 2
+#define MTL_E_NOROOM 3
+#define MTL_E_NOSUCH 4
+
+//
+// local mtl defs
+//
+/* packet receive/transmit assembly/disassembly descriptor */
+typedef struct
+{
+ LIST_ENTRY link;
+ ULONG Queued;
+ ULONG QueueOverRun;
+ UCHAR seq; /* recorded sequence number */
+ UCHAR tot; /* total # of fragments (0 free) */
+ UCHAR num; /* # of fragments received/transmitted */
+ ULONG ttl; /* time to live, in seconds */
+ USHORT len; /* accumulated packet length */
+ struct _MTL *mtl; /* back pointer to mtl */
+ USHORT State; /* State of current large frame */
+ UCHAR* DataPtr; /* current data index into buffer */
+ USHORT MaxRxLength; /* max frame receive length */
+ ULONG MissCount; /* rx miss count */
+ PUCHAR buf;
+} MTL_AS;
+
+typedef struct
+{
+ UCHAR NextFree;
+ NDIS_SPIN_LOCK lock; /* access spinlock */
+ ULONG DKFReceiveError1;
+ ULONG DKFReceiveError2;
+ ULONG DKFReceiveError3;
+ ULONG DKFReceiveError4;
+ ULONG DKFReceiveError5;
+ ULONG PPPReceiveError1;
+ ULONG PPPReceiveError2;
+ ULONG PPPReceiveError3;
+ ULONG PPPReceiveError4;
+ ULONG PPPReceiveError5;
+ ULONG IndicateReceiveError1;
+ ULONG IndicateReceiveError2;
+ ULONG IndicateReceiveError3;
+ ULONG TimeOutReceiveError1;
+ MTL_AS as_tbl[MTL_RX_BUFS];
+ PUCHAR Data;
+}MTL_RX_TBL;
+
+typedef struct
+{
+ LIST_ENTRY head;
+ NDIS_SPIN_LOCK lock;
+} MTL_AS_FIFO;
+
+//
+// Fifo for storing wan packets before fragment processing
+//
+typedef struct
+{
+ LIST_ENTRY head; /* head pointer, head==NULL -> empty */
+ NDIS_SPIN_LOCK lock; /* access lock */
+ ULONG Count;
+ ULONG Max;
+} MTL_WANPACKET_FIFO;
+
+/* idd packet header */
+typedef struct
+{
+ UCHAR sig_tot; /* signature + total fragments */
+ UCHAR seq; /* packet sequence number */
+ USHORT ofs; /* offset of fragment data into packet */
+} MTL_HDR;
+
+//
+// this structure is used for data this is fragmented in the DKF format
+//
+typedef struct
+{
+ IDD_FRAG IddFrag[2]; /* two fragments (hdr+data) required */
+ MTL_HDR MtlHeader; /* header storage */
+} DKF_FRAG;
+
+/* trasmit fragement descriptor */
+//
+// The DKF_FRAG member must be kept at the begining of this structure
+// !!!!!!!!!!!!!! mtl_tx.c relies on this !!!!!!!!!!!!!!!
+//
+typedef struct
+{
+ DKF_FRAG DkfFrag; /* frament descriptor for idd poll_tx */
+ IDD_MSG frag_msg; /* fragments waiting to be sent vector */
+ VOID *frag_idd; /* idd accepting fragments */
+ USHORT frag_bchan; /* destination bchannels */
+ VOID *frag_arg; /* argument to completion function */
+ ULONG FragSent; /* flag to indicate if this frag has been xmitted */
+} MTL_TX_FRAG;
+
+/* trasmit packet descriptor */
+typedef struct
+{
+ LIST_ENTRY TxPacketQueue;
+ NDIS_SPIN_LOCK lock;
+ ULONG InUse; /* this entry is in use */
+ USHORT NumberOfFrags; /* # of fragments in frag_tbl */
+ USHORT NumberOfFragsSent; /* # of fragments already sent */
+ USHORT FragReferenceCount; /* refrence count */
+ UCHAR *frag_buf; /* pointer to real data buffer */
+ NDIS_WAN_PACKET *WanPacket; /* related user packet */
+ struct _MTL *mtl; /* back pointer to mtl */
+ MTL_TX_FRAG frag_tbl[MTL_MAX_FRAG]; /* fragment table (assembled) */
+} MTL_TX_PKT;
+
+/* trasmit packet control table */
+typedef struct
+{
+ LIST_ENTRY head;
+ NDIS_SPIN_LOCK lock; /* access lock */
+ ULONG seq; /* packet sequence number (for next) */
+ ULONG NextFree; /* next available packet */
+ MTL_TX_PKT TxPacketTbl[MTL_TX_BUFS]; /* packet table */
+} MTL_TX_TBL;
+
+/* a channel descriptor */
+typedef struct
+{
+ VOID *idd; /* related idd object */
+ USHORT bchan; /* related channel within idd, b1=0, b2=1 */
+ ULONG speed; /* channel speed in bps */
+ struct _MTL *mtl; /* mtl back pointer */
+} MTL_CHAN;
+
+/* channel table */
+typedef struct
+{
+ MTL_CHAN tbl[MAX_CHAN_PER_CONN]; /* table of channels */
+ USHORT num; /* # of entries used */
+ NDIS_SPIN_LOCK lock; /* access spinlock */
+} MTL_CHAN_TBL;
+
+/* an MTL object */
+typedef struct _MTL
+{
+ ADAPTER *Adapter; /* adapter that owns this mtl */
+
+ NDIS_HANDLE LinkHandle; /* handle from wrapper for this link */
+
+ //statistics
+ ULONG FramesXmitted;
+ ULONG FramesReceived;
+ ULONG BytesXmitted;
+ ULONG BytesReceived;
+
+ NDIS_SPIN_LOCK lock; /* access lock */
+
+ VOID (*rx_handler)(); /* mgr receiver handler routine */
+ VOID *rx_handler_arg; /* ... handler argument */
+
+ VOID (*tx_handler)(); /* mgr transmitter handler routine */
+ VOID *tx_handler_arg; /* ... handler argument */
+
+ USHORT idd_mtu; /* idd max frame size */
+ BOOL is_conn; /* is connected now? */
+
+ ULONG IddTxFrameType; /* 0/1 - PPP/DKF */
+ ULONG IddRxFrameType; /* 0/1 - PPP/DKF */
+
+ MTL_CHAN_TBL chan_tbl; /* the channel table */
+
+ //
+ // Receive table
+ //
+ MTL_RX_TBL rx_tbl;
+
+ //
+ // Receive Completion Fifo
+ //
+ MTL_AS_FIFO RxIndicationFifo;
+
+ //
+ // fifo of wan packets to be transmitted
+ //
+ MTL_WANPACKET_FIFO WanPacketFifo;
+
+ //
+ // transmit table
+ //
+ MTL_TX_TBL tx_tbl;
+
+ //
+ // flag to show
+ //
+ BOOL RecvCompleteScheduled;
+
+ //
+ // backpointer to connection object
+ //
+ VOID *cm;
+
+ SEMA tx_sema; /* transmit processing sema */
+
+ //
+ // wan wrapper information
+ //
+ ULONG MaxSendFrameSize;
+ ULONG MaxRecvFrameSize;
+ ULONG PreamblePadding;
+ ULONG PostamblePadding;
+ ULONG SendFramingBits;
+ ULONG RecvFramingBits;
+ ULONG SendCompressionBits;
+ ULONG RecvCompressionBits;
+
+} MTL;
+
+//
+// public mtl defs
+//
+/* MTL object operations */
+INT mtl_create(VOID** mtl_1, NDIS_HANDLE AdapterHandle);
+INT mtl_destroy(VOID* mtl_1);
+INT mtl_set_rx_handler(VOID* mtl_1, VOID (*handler)(), VOID* handler_arg);
+INT mtl_set_tx_handler(VOID* mtl_1, VOID (*handler)(), VOID* handler_arg);
+INT mtl_set_idd_mtu(VOID* mtl_1, USHORT idd_mtu);
+INT mtl_set_conn_state(VOID* mtl_1, USHORT NumberOfChannels, BOOL is_conn);
+INT mtl_get_conn_speed(VOID* mtl_1, ULONG *speed);
+INT mtl_get_mac_mtu(VOID* mtl_1, ULONG* mtu);
+VOID mtl_tx_packet(VOID* mtl_1, PNDIS_WAN_PACKET pkt);
+INT mtl_add_chan(VOID* mtl_1, VOID* idd, USHORT chan, ULONG speed, ULONG ConnectionType);
+INT mtl_del_chan(VOID* mtl_1, VOID* idd, USHORT chan);
+INT GetStatistics (VOID*, VOID*);
+INT ClearStatistics (VOID*);
+INT MtlSetFramingType (VOID*, ULONG);
+
+
+/* prototypes for internal functions */
+VOID mtl__rx_bchan_handler(MTL_CHAN* chan, USHORT bchan, ULONG RxFrameType, IDD_XMSG* xmsg);
+VOID IndicateRxToWrapper(MTL*);
+VOID mtl__tx_cmpl_handler(MTL_TX_PKT *pkt, USHORT bchan, IDD_MSG* msg);
+VOID mtl__rx_tick(MTL* mtl);
+VOID mtl__tx_tick(MTL* mtl);
+VOID MtlPollFunction(VOID* a1, ADAPTER *Adapter, VOID* a3, VOID* a4);
+VOID MtlRecvCompleteFunction(ADAPTER *Adapter);
+BOOLEAN IsRxIndicationFifoEmpty(MTL*);
+MTL_AS* GetAssemblyFromRxIndicationFifo(MTL*);
+VOID QueueDescriptorForRxIndication(MTL*, MTL_AS*);
+VOID MtlSendCompleteFunction(ADAPTER *Adapter);
+VOID IndicateTxCompletionToWrapper(MTL*);
+VOID MtlFlushWanPacketTxQueue(MTL*);
+VOID mtl__tx_packet(MTL*, NDIS_WAN_PACKET*);
+VOID TryToIndicateMtlReceives(ADAPTER *Adapter);
+
+#endif /* _MTL_ */
diff --git a/private/ntos/ndis/pcimac/mtl_init.c b/private/ntos/ndis/pcimac/mtl_init.c
new file mode 100644
index 000000000..d5ae71903
--- /dev/null
+++ b/private/ntos/ndis/pcimac/mtl_init.c
@@ -0,0 +1,196 @@
+/*
+ * MTL_INIT.C - Media Translation Layer, initialization
+ */
+
+#include <ndis.h>
+//#include <ndismini.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+
+#pragma NDIS_INIT_FUNCTION(mtl_create)
+
+/* create an mtl object */
+mtl_create(VOID **mtl_1, NDIS_HANDLE AdapterHandle)
+{
+ MTL **ret_mtl = (MTL**)mtl_1;
+ MTL *mtl;
+ INT n;
+ NDIS_PHYSICAL_ADDRESS pa = NDIS_PHYSICAL_ADDRESS_CONST(0xffffffff, 0xffffffff);
+
+ D_LOG(D_ENTRY, ("mtl_create: entry, ret_mtl: 0x%p", ret_mtl));
+
+ //
+ // allocate memory for mtl object
+ //
+ NdisAllocateMemory((PVOID*)&mtl, sizeof(*mtl), 0, pa);
+ if ( !mtl )
+ {
+ D_LOG(D_ALWAYS, ("mtl_create: memory allocate failed!"));
+ NdisWriteErrorLogEntry (AdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0);
+ return(MTL_E_NOMEM);
+ }
+ D_LOG(D_ALWAYS, ("mtl_create: mtl: 0x%p", mtl));
+ NdisZeroMemory(mtl, sizeof(MTL));
+
+ //
+ // allocate rx table
+ //
+ NdisAllocateMemory((PVOID*)&mtl->rx_tbl.Data, (MTL_RX_BUFS * MTL_MAC_MTU), 0, pa);
+ if ( !mtl->rx_tbl.Data )
+ {
+ D_LOG(D_ALWAYS, ("mtl_create: RxData memory allocate failed!"));
+
+ NdisWriteErrorLogEntry (AdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0);
+
+ /* free memory */
+ NdisFreeMemory(mtl, sizeof(*mtl), 0);
+
+ return(MTL_E_NOMEM);
+ }
+ D_LOG(D_ALWAYS, ("mtl_create: RxData: 0x%p", mtl->rx_tbl.Data));
+ NdisZeroMemory(mtl->rx_tbl.Data, (MTL_RX_BUFS * MTL_MAC_MTU));
+
+ /* setup some simple fields */
+ mtl->idd_mtu = MTL_IDD_MTU;
+
+ /* allocate spinlock for mtl */
+ NdisAllocateSpinLock(&mtl->lock);
+
+ /* allocate spinlock for channel table */
+ NdisAllocateSpinLock(&mtl->chan_tbl.lock);
+
+ //
+ // create assembly descriptor pointers into rx table
+ //
+ for (n = 0; n < MTL_RX_BUFS; n++)
+ mtl->rx_tbl.as_tbl[n].buf = mtl->rx_tbl.Data + (n * MTL_MAC_MTU);
+
+ NdisAllocateSpinLock(&mtl->rx_tbl.lock);
+
+ //
+ // spinlock for RxIndicationFifo
+ //
+ NdisAllocateSpinLock(&mtl->RxIndicationFifo.lock);
+
+ //
+ // initialize assembly completion fifo
+ //
+ NdisAcquireSpinLock(&mtl->RxIndicationFifo.lock);
+
+ InitializeListHead(&mtl->RxIndicationFifo.head);
+
+ NdisReleaseSpinLock(&mtl->RxIndicationFifo.lock);
+
+ //
+ // tx packet table lock
+ //
+ NdisAllocateSpinLock(&mtl->tx_tbl.lock);
+
+ for (n = 0; n < MTL_TX_BUFS; n++)
+ {
+ MTL_TX_PKT *MtlTxPacket = &mtl->tx_tbl.TxPacketTbl[n];
+
+ NdisAllocateSpinLock(&MtlTxPacket->lock);
+ }
+
+ //
+ // initialize MtlTxPacket Queue
+ //
+ NdisAcquireSpinLock(&mtl->tx_tbl.lock);
+
+ InitializeListHead(&mtl->tx_tbl.head);
+
+ NdisReleaseSpinLock(&mtl->tx_tbl.lock);
+
+ //
+ // Tx WanPacket storage
+ //
+ NdisAllocateSpinLock(&mtl->WanPacketFifo.lock);
+
+ NdisAcquireSpinLock(&mtl->WanPacketFifo.lock);
+
+ InitializeListHead(&mtl->WanPacketFifo.head);
+
+ NdisReleaseSpinLock(&mtl->WanPacketFifo.lock);
+
+ //
+ // setup default wan link fields
+ //
+ mtl->MaxSendFrameSize = MTL_MAC_MTU;
+ mtl->MaxRecvFrameSize = MTL_MAC_MTU;
+ mtl->PreamblePadding = 14;
+ mtl->PostamblePadding = 0;
+ mtl->SendFramingBits = RAS_FRAMING |
+ PPP_FRAMING |
+ MEDIA_NRZ_ENCODING;
+ mtl->RecvFramingBits = RAS_FRAMING |
+ PPP_FRAMING |
+ MEDIA_NRZ_ENCODING;
+ mtl->SendCompressionBits = 0;
+ mtl->RecvCompressionBits = 0;
+
+ /* init sema */
+ sema_init(&mtl->tx_sema);
+
+ /* return success */
+ *ret_mtl = mtl;
+ D_LOG(D_EXIT, ("mtl_create: exit"));
+ return(MTL_E_SUCC);
+}
+
+/* destroy an mtl object */
+mtl_destroy(VOID* mtl_1)
+{
+ MTL *mtl = (MTL*)mtl_1;
+ INT n;
+
+ D_LOG(D_ENTRY, ("mtl_destroy: entry, mtl: 0x%p", mtl));
+
+ /* allocate spinlock for mtl */
+ NdisFreeSpinLock(&mtl->lock);
+
+ /* allocate spinlock for channel table */
+ NdisFreeSpinLock(&mtl->chan_tbl.lock);
+
+ /* allocate spin locks for receive table */
+// for ( n = 0 ; n < MTL_RX_BUFS ; n++ )
+// NdisFreeSpinLock(&mtl->rx_tbl.as_tbl[n].lock);
+
+ NdisFreeSpinLock(&mtl->rx_tbl.lock);
+
+ /* allocate spin lock for trasmit table & fifo */
+ NdisFreeSpinLock(&mtl->tx_tbl.lock);
+
+ for (n = 0; n < MTL_TX_BUFS; n++)
+ {
+ MTL_TX_PKT *MtlTxPacket = &mtl->tx_tbl.TxPacketTbl[n];
+
+ NdisFreeSpinLock(&MtlTxPacket->lock);
+ }
+
+ NdisFreeSpinLock(&mtl->WanPacketFifo.lock);
+ NdisFreeSpinLock(&mtl->RxIndicationFifo.lock);
+
+ /* term sema */
+ sema_term(&mtl->tx_sema);
+
+ NdisFreeMemory(mtl->rx_tbl.Data, (MTL_RX_BUFS * MTL_MAC_MTU), 0);
+
+ /* free memory */
+ NdisFreeMemory(mtl, sizeof(*mtl), 0);
+
+ D_LOG(D_EXIT, ("mtl_destroy: exit"));
+ return(MTL_E_SUCC);
+}
diff --git a/private/ntos/ndis/pcimac/mtl_rx.c b/private/ntos/ndis/pcimac/mtl_rx.c
new file mode 100644
index 000000000..054b88589
--- /dev/null
+++ b/private/ntos/ndis/pcimac/mtl_rx.c
@@ -0,0 +1,819 @@
+/*
+ * MTL_RX.C - Receive side processing for MTL
+ */
+
+#include <ndis.h>
+//#include <ndismini.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+
+/* main handler, called when data arrives at bchannels */
+VOID
+mtl__rx_bchan_handler
+ (
+ MTL_CHAN *chan,
+ USHORT bchan,
+ ULONG IddRxFrameType,
+ IDD_XMSG *msg
+ )
+{
+ MTL *mtl;
+ MTL_HDR hdr;
+ MTL_AS *as;
+ USHORT FragmentFlags, CopyLen;
+ MTL_RX_TBL *RxTable;
+ D_LOG(D_ENTRY, ("mtl__rx_bchan_handler: chan: 0x%p, bchan: %d, msg: 0x%p", chan, bchan, msg));
+
+ /* assigned mtl using back pointer */
+ mtl = chan->mtl;
+
+ //
+ // acquire the lock fot this mtl
+ //
+ NdisAcquireSpinLock(&mtl->lock);
+
+ /* if not connected, ignore */
+ if ( !mtl->is_conn )
+ {
+ D_LOG(D_ALWAYS, ("mtl__rx_bchan_handler: packet on non connected mtl, ignored"));
+ goto exit_code;
+ }
+
+ RxTable = &mtl->rx_tbl;
+ D_LOG(D_ENTRY, ("mtl__rx_bchan_handler: mtl: 0x%p, buflen: %d, bufptr: 0x%p", \
+ mtl, msg->buflen, msg->bufptr));
+ //
+ // if we are in detect mode
+ //
+ if (!mtl->RecvFramingBits)
+ {
+ UCHAR DetectData[3];
+
+ /* extract header, check for fields */
+ IddGetDataFromAdapter(chan->idd,
+ (PUCHAR)&hdr,
+ (PUCHAR)msg->bufptr,
+ sizeof(MTL_HDR));
+
+// NdisMoveMemory ((PUCHAR)&hdr, (PUCHAR)msg->bufptr, sizeof(MTL_HDR));
+
+ //
+ // this is used for inband signalling - ignore it
+ //
+ if (hdr.sig_tot == 0x50)
+ goto exit_code;
+
+ //
+ // if this is dkf we need offset of zero for detection to work
+ //
+ if ( ((hdr.sig_tot & 0xF0) == 0x50) && (hdr.ofs != 0) )
+ goto exit_code;
+
+ //
+ // extract some data from the frame
+ //
+ IddGetDataFromAdapter(chan->idd,
+ (PUCHAR)&DetectData,
+ (PUCHAR)&msg->bufptr[4],
+ 2);
+
+// NdisMoveMemory((PUCHAR)&DetectData, (PUCHAR)&msg->bufptr[4], 2);
+
+ D_LOG(D_ALWAYS, ("mtl__rx_bchan_handler: hdr: 0x%x 0x%x 0x%x", hdr.sig_tot, \
+ hdr.seq, hdr.ofs));
+
+ D_LOG(D_ALWAYS, ("mtl__rx_bchan_handler: DetectData: 0x%x 0x%x", DetectData[0], DetectData[1]));
+
+ if ( (IddRxFrameType & IDD_FRAME_PPP) ||
+ ((IddRxFrameType & IDD_FRAME_DKF) &&
+ ((DetectData[0] == 0xFF) && (DetectData[1] == 0x03))))
+ {
+ mtl->RecvFramingBits = PPP_FRAMING;
+ mtl->SendFramingBits = PPP_FRAMING;
+ RxTable->NextFree = 0;
+ }
+ else
+ {
+ mtl->RecvFramingBits = RAS_FRAMING;
+ mtl->SendFramingBits = RAS_FRAMING;
+ }
+
+ D_LOG(D_ALWAYS, ("mtl__rx_bchan_handler: Deteced WrapperFrameType: 0x%x", mtl->RecvFramingBits));
+
+ //
+ // don't pass up detected frame for now
+ //
+ goto exit_code;
+ }
+
+ if (IddRxFrameType & IDD_FRAME_DKF)
+ {
+ D_LOG(D_ALWAYS, ("mtl__rx_bchan_handler: Received IddFrameType: DKF"));
+
+ /* size of packet has to be atleast as size of header */
+ if ( msg->buflen < sizeof(hdr) )
+ {
+ D_LOG(D_ALWAYS, ("mtl__rx_bchan_handler: packet size too small, ignored"));
+ RxTable->DKFReceiveError1++;
+ goto exit_code;
+ }
+
+ /* extract header, check for fields */
+ IddGetDataFromAdapter(chan->idd,
+ (PUCHAR)&hdr,
+ (PUCHAR)msg->bufptr,
+ sizeof(MTL_HDR));
+
+ D_LOG(D_ALWAYS, ("mtl__rx_bchan_handler: hdr: 0x%x 0x%x 0x%x", hdr.sig_tot, \
+ hdr.seq, hdr.ofs));
+
+ //
+ // if this is not our header of if this is an inband uus
+ // ignore it
+ //
+ if ( (hdr.sig_tot & 0xF0) != 0x50 || hdr.sig_tot == 0x50)
+ {
+ D_LOG(D_ALWAYS, ("mtl__rx_bchan_handler: bad header signature, ignored"));
+ D_LOG(D_ALWAYS, ("mtl__rx_bchan_handler: mtl: 0x%p, [0]: 0x%x", mtl, hdr.sig_tot));
+ RxTable->DKFReceiveError2++;
+ goto exit_code;
+ }
+
+ if ( (hdr.ofs >= MTL_MAC_MTU) || ((hdr.ofs + msg->buflen - sizeof(hdr)) > MTL_MAC_MTU) )
+ {
+ D_LOG(D_ALWAYS, ("mtl__rx_bchan_handler: bad offset/buflen, ignored"));
+ D_LOG(D_ALWAYS, ("mtl: 0x%p, Offset: %d, BufferLength: %d", mtl, hdr.ofs, msg->buflen));
+ RxTable->DKFReceiveError3++;
+ goto exit_code;
+ }
+
+ NdisAcquireSpinLock(&RxTable->lock);
+
+ /* build pointer to assembly descriptor & lock it */
+ as = RxTable->as_tbl + (hdr.seq % MTL_RX_BUFS);
+
+ //
+ // if this assembly pointer is not free (queued) then
+ // just drop this fragment
+ //
+ if (as->Queued)
+ {
+ D_LOG(D_ALWAYS, ("DKFRx: AssemblyQueue Overrun! mtl: 0x%p, as: 0x%p, seq: %d", \
+ mtl, as, hdr.seq));
+
+ RxTable->DKFReceiveError4++;
+ as->QueueOverRun++;
+ NdisReleaseSpinLock(&RxTable->lock);
+ goto exit_code;
+ }
+
+ /* check for new slot */
+ if ( !as->tot )
+ {
+ new_slot:
+
+ /* new entry, fill-up */
+ as->seq = hdr.seq; /* record sequence number */
+ as->num = 1; /* just received 1'st fragment */
+ as->ttl = 1000; /* time to live init val */
+ as->len = msg->buflen - sizeof(hdr); /* record received length */
+ as->tot = hdr.sig_tot & 0x0F; /* record number of expected fragments */
+
+ /* copy received data into buffer */
+ copy_data:
+ IddGetDataFromAdapter(chan->idd,
+ (PUCHAR)as->buf + hdr.ofs,
+ (PUCHAR)msg->bufptr + sizeof(hdr),
+ (USHORT)(msg->buflen - sizeof(hdr)));
+// NdisMoveMemory (as->buf + hdr.ofs, msg->bufptr + sizeof(hdr), msg->buflen - sizeof(hdr));
+ }
+ else if ( as->seq == hdr.seq )
+ {
+ /* same_seq: */
+
+ /* same sequence number, accumulate */
+ as->num++;
+ as->len += (msg->buflen - sizeof(hdr));
+
+ goto copy_data;
+ }
+ else
+ {
+ /* bad_frag: */
+
+ /*
+ * if this case, an already taken slot is hit, but with a different
+ * sequence number. this indicates a wrap-around in as_tbl. prev
+ * entry is freed and then this fragment is recorded as first
+ */
+ D_LOG(D_ALWAYS, ("DKFRx: Bad Fragment! mtl: 0x%p, as: 0x%p, as->seq: %d, seq: %d", \
+ mtl, as, as->seq, hdr.seq));
+
+ D_LOG(D_ALWAYS, ("as->tot: %d, as->num: %d", as->tot, as->num));
+
+ RxTable->DKFReceiveError5++;
+ goto new_slot;
+ }
+
+ /* if all fragments recieved for packet, time to mail it up */
+ if ( as->tot == as->num )
+ {
+ D_LOG(D_ALWAYS, ("mtl__rx_bchan_handler: pkt mailed up, buf: 0x%p, len: 0x%x", \
+ as->buf, as->len));
+
+ QueueDescriptorForRxIndication(mtl, as);
+
+ //
+ // mark this guy as being queued
+ //
+ as->Queued = 1;
+ }
+
+ /* release assembly descriptor */
+ NdisReleaseSpinLock(&RxTable->lock);
+ }
+ else if (IddRxFrameType & IDD_FRAME_PPP)
+ {
+ D_LOG(D_ALWAYS, ("mtl__rx_bchan_handler: Received IddFrameType: PPP"));
+
+ NdisAcquireSpinLock(&RxTable->lock);
+
+ /* build pointer to assembly descriptor & lock it */
+ as = RxTable->as_tbl + (RxTable->NextFree % MTL_RX_BUFS);
+
+ //
+ // if this assembly pointer is not free (queued) then
+ // just drop this fragment
+ //
+ if (as->Queued)
+ {
+ D_LOG(D_ALWAYS, ("PPPRx: AssemblyQueue Overrun! mtl: 0x%p, as: 0x%p, NextFree: %d", \
+ mtl, as, RxTable->NextFree));
+
+ as->QueueOverRun++;
+
+ RxTable->PPPReceiveError1++;
+
+ NdisReleaseSpinLock(&RxTable->lock);
+
+ goto exit_code;
+ }
+
+ FragmentFlags = msg->FragmentFlags;
+
+ D_LOG(D_ALWAYS, ("mtl__rx_bchan_handler: FragmentFlags: 0x%x, CurrentRxState: 0x%x", FragmentFlags, as->State));
+
+ switch (as->State)
+ {
+ case RX_MIDDLE:
+ if (FragmentFlags & H_RX_N_BEG)
+ break;
+
+ as->MissCount++;
+
+ //
+ // missed an end buffer
+ //
+ D_LOG(D_ALWAYS, ("mtl__rx_bchan_handler: mtl: 0x%p, Miss in State: %d, FragmentFlags: 0x%x, MissCount: %d", \
+ mtl, as->State, FragmentFlags, as->MissCount));
+
+ RxTable->PPPReceiveError2++;
+
+ goto clearbuffer;
+
+ break;
+
+ case RX_BEGIN:
+ case RX_END:
+ if (FragmentFlags & H_RX_N_BEG)
+ {
+ //
+ // missed a begining buffer
+ //
+ as->MissCount++;
+
+ D_LOG(D_ALWAYS, ("mtl__rx_bchan_handler: mtl: 0x%p, Miss in State: %d, FragmentFlags: 0x%x, MissCount: %d", \
+ mtl, as->State, FragmentFlags, as->MissCount));
+
+ RxTable->PPPReceiveError3++;
+
+ goto done;
+ }
+clearbuffer:
+ //
+ // clear rx buffer
+ //
+ NdisZeroMemory(as->buf, sizeof(as->buf));
+
+ //
+ // start data at begin of buffer
+ //
+ as->DataPtr = as->buf;
+
+ //
+ // new buffer
+ //
+ as->len = 0;
+
+ //
+ // set rx state
+ //
+ as->State = RX_MIDDLE;
+
+ //
+ // set time to live
+ //
+ as->ttl = 1000;
+
+ //
+ // there is always only one fragment with PPP
+ // maybe a big one but still only one
+ //
+ as->tot = 1;
+
+ break;
+
+ default:
+ D_LOG(D_ALWAYS, ("Invalid PPP Rx State! mtl: 0x%p, as: 0x%p State: 0x%x", \
+ mtl, as, as->State));
+
+ as->State = RX_BEGIN;
+
+ as->tot = 0;
+
+ as->MissCount++;
+
+ goto done;
+
+ break;
+ }
+
+ //
+ // get the length to be copy
+ //
+ CopyLen = msg->buflen;
+
+
+ D_LOG(D_ALWAYS, ("mtl__rx_bchan_handler: CopyLen: %d", CopyLen));
+
+ if (FragmentFlags & H_RX_N_END)
+ {
+ //
+ // if this is not the last buffer and length is 0
+ // we are done
+ //
+ if (CopyLen == 0)
+ goto done_copy;
+
+ }
+ else
+ {
+ //
+ // if CopyLen = 0 buffer only contains 2 CRC bytes
+ //
+ if (CopyLen == 0)
+ {
+ goto done_copy;
+ }
+
+ //
+ // buffer contains only 1 CRC byte
+ //
+ else if (CopyLen == (-1 & H_RX_LEN_MASK))
+ {
+ //
+ // previous buffer had a crc byte in it so remove it
+ //
+ as->len -= 1;
+ goto done_copy;
+ }
+
+ //
+ // buffer contains no crc or data bytes
+ //
+ else if (CopyLen == (-2 & H_RX_LEN_MASK))
+ {
+ //
+ // previous buffer had 2 crc bytes in it so remove them
+ //
+ as->len -= 2;
+ goto done_copy;
+ }
+
+ }
+
+ //
+ // if larger than max rx size throw away
+ //
+ if (CopyLen > IDP_MAX_RX_LEN)
+ {
+ //
+ // buffer to big so dump it
+ //
+ as->State = RX_BEGIN;
+
+ as->MissCount++;
+
+ RxTable->PPPReceiveError4++;
+
+ /* mark as free now */
+ as->tot = 0;
+
+ D_LOG(D_ALWAYS, ("mtl__rx_bchan_handler: mtl: 0x%p, RxToLarge: RxSize: %d, MissCount: %d", mtl, CopyLen, as->MissCount));
+ goto done;
+ }
+
+ as->len += CopyLen;
+
+ if (as->len > MTL_MAC_MTU)
+ {
+ //
+ // Frame is to big so dump it
+ //
+ as->State = RX_BEGIN;
+
+ RxTable->PPPReceiveError5++;
+
+ as->MissCount++;
+
+ /* mark as free now */
+ as->tot = 0;
+
+ D_LOG(D_ALWAYS, ("mtl__rx_bchan_handler: AssembledRxToLarge: mtl: 0x%p, AsRxSize: %d, MissCount: %d", mtl, as->len, as->MissCount));
+ goto done;
+ }
+
+ //
+ // copy the data to rx descriptor
+ //
+ IddGetDataFromAdapter(chan->idd,
+ (PUCHAR)as->DataPtr,
+ (PUCHAR)msg->bufptr,
+ CopyLen);
+// NdisMoveMemory(as->DataPtr, msg->bufptr, CopyLen);
+
+ //
+ // update data ptr
+ //
+ as->DataPtr += CopyLen;
+
+
+done_copy:
+ if (!(FragmentFlags & H_RX_N_END))
+ {
+ //
+ // if this is the end of the frame indicate to wrapper
+ //
+ as->State = RX_END;
+
+ RxTable->NextFree++;
+
+ QueueDescriptorForRxIndication(mtl, as);
+
+ //
+ // mark this guy as being queued
+ //
+ as->Queued = 1;
+ }
+
+done:
+ /* release assembly descriptor */
+ NdisReleaseSpinLock(&RxTable->lock);
+ }
+ else
+ D_LOG(D_ALWAYS, ("mtl__rx_bchan_handler: Received IddFrameType: ??????!!!!!!"));
+
+ //
+ // exit code
+ // release spinlock and return
+ //
+ exit_code:
+
+ NdisReleaseSpinLock(&mtl->lock);
+}
+
+VOID
+IndicateRxToWrapper(
+ MTL *mtl
+ )
+{
+ UCHAR *BufferPtr;
+ USHORT BufferLength = 0;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ ADAPTER *Adapter;
+ MTL_AS *as;
+ MTL_RX_TBL *RxTable;
+
+ NdisAcquireSpinLock(&mtl->lock);
+
+ Adapter = mtl->Adapter;
+ RxTable = &mtl->rx_tbl;
+
+ while (!IsRxIndicationFifoEmpty(mtl))
+ {
+ NdisAcquireSpinLock(&RxTable->lock);
+
+ //
+ // get the next completed rx assembly
+ //
+ as = GetAssemblyFromRxIndicationFifo(mtl);
+
+ if (!as)
+ {
+ D_LOG(D_ALWAYS, ("IndicateRx: Got a NULL as from queue! mtl: 0x%p", mtl));
+ RxTable->IndicateReceiveError1++;
+ NdisReleaseSpinLock(&RxTable->lock);
+ goto exit_code;
+ }
+
+
+ //
+ // if this is an old ras frame then we must strip off
+ // the mac header Dst[6] + Src[6] + Length[2]
+ //
+ if (mtl->RecvFramingBits & RAS_FRAMING)
+ {
+ //
+ // pass over the mac header - tommyd does not want to see this
+ //
+ BufferPtr = as->buf + 14;
+
+ //
+ // indicate with the size of the ethernet packet not the received size
+ // this takes care of the old driver that does padding on small frames
+ //
+ BufferLength = as->buf[12];
+ BufferLength = BufferLength << 8;
+ BufferLength += as->buf[13];
+ D_LOG(D_ALWAYS, ("IndicateRxToWrapper: WrapperFrameType: RAS"));
+ D_LOG(D_ALWAYS, ("IndicateRxToWrapper: BufPtr: 0x%p, BufLen: %d", BufferPtr, BufferLength));
+ }
+ else if (mtl->RecvFramingBits & PPP_FRAMING)
+ {
+ //
+ // the received buffer is the data that needs to be inidcated
+ //
+ BufferPtr = as->buf;
+
+ //
+ // the received length is the length that needs to be indicated
+ //
+ BufferLength = as->len;
+ D_LOG(D_ALWAYS, ("IndicateRxToWrapper: WrapperFrameType: PPP"));
+ D_LOG(D_ALWAYS, ("IndicateRxToWrapper: BufPtr: 0x%p, BufLen: %d", BufferPtr, BufferLength));
+ }
+ else
+ {
+ //
+ // unknown framing - what to do what to do
+ // throw it away
+ //
+ D_LOG(D_ALWAYS, ("IndicateRxToWrapper: mtl: 0x%p, Unknown WrapperFramming: 0x%x", mtl, mtl->RecvFramingBits));
+ RxTable->IndicateReceiveError2++;
+ as->tot = 0;
+ as->Queued = 0;
+ NdisReleaseSpinLock(&RxTable->lock);
+ goto exit_code;
+ }
+
+ if (BufferLength > MTL_MAC_MTU)
+ {
+ D_LOG(D_ALWAYS, ("IndicateRxToWrapper: mtl: 0x%p, ReceiveLength > MAX ALLOWED (1514): RxLength: %d", mtl, as->len));
+ RxTable->IndicateReceiveError3++;
+ as->tot = 0;
+ as->Queued = 0;
+ NdisReleaseSpinLock(&RxTable->lock);
+ goto exit_code;
+ }
+
+ //
+ // send frame up
+ //
+ if (mtl->LinkHandle)
+ {
+ /* release assembly descriptor */
+ NdisReleaseSpinLock(&RxTable->lock);
+
+ NdisReleaseSpinLock(&mtl->lock);
+
+ NdisMWanIndicateReceive(&Status,
+ Adapter->Handle,
+ mtl->LinkHandle,
+ BufferPtr,
+ BufferLength);
+
+ NdisAcquireSpinLock(&mtl->lock);
+
+ NdisAcquireSpinLock(&RxTable->lock);
+
+ mtl->RecvCompleteScheduled = 1;
+ }
+
+
+ /* mark as free now */
+ as->tot = 0;
+
+ //
+ // mark this guy as being free
+ //
+ as->Queued = 0;
+
+ /* release assembly descriptor */
+ NdisReleaseSpinLock(&RxTable->lock);
+ }
+
+ //
+ // exit code
+ // release spinlock and return
+ //
+ exit_code:
+
+ NdisReleaseSpinLock(&mtl->lock);
+}
+
+//
+// this function checks all of the mtl's on this adapter to see if
+// the protocols need to be given a chance to do some work
+//
+VOID
+MtlRecvCompleteFunction(
+ ADAPTER *Adapter
+ )
+{
+ ULONG n;
+
+ for ( n = 0; n < MAX_MTL_PER_ADAPTER; n++)
+ {
+ MTL *mtl = Adapter->MtlTbl[n] ;
+
+ //
+ // if this is a valid mtl
+ //
+ if (mtl)
+ {
+ //
+ // get lock for this mtl
+ //
+ NdisAcquireSpinLock(&mtl->lock);
+
+ //
+ // is a receive complete scheduled on a valid link?
+ //
+ if (mtl->RecvCompleteScheduled && mtl->LinkHandle)
+ {
+ //
+ // release the lock
+ //
+ NdisReleaseSpinLock(&mtl->lock);
+
+ NdisMWanIndicateReceiveComplete(Adapter->Handle,
+ mtl->LinkHandle);
+
+ //
+ // reaquire the lock
+ //
+ NdisAcquireSpinLock(&mtl->lock);
+
+ //
+ // clear the schedule flag
+ //
+ mtl->RecvCompleteScheduled = 0;
+ }
+
+ //
+ // release the lock
+ //
+ NdisReleaseSpinLock(&mtl->lock);
+ }
+ }
+}
+
+BOOLEAN
+IsRxIndicationFifoEmpty(
+ MTL *mtl)
+{
+ BOOLEAN Ret = 0;
+
+ NdisAcquireSpinLock(&mtl->RxIndicationFifo.lock);
+
+ Ret = IsListEmpty(&mtl->RxIndicationFifo.head);
+
+ NdisReleaseSpinLock(&mtl->RxIndicationFifo.lock);
+
+ return(Ret);
+
+}
+
+MTL_AS*
+GetAssemblyFromRxIndicationFifo(
+ MTL *mtl
+ )
+{
+ MTL_AS *as = NULL;
+
+ NdisAcquireSpinLock(&mtl->RxIndicationFifo.lock);
+
+ if (!IsListEmpty(&mtl->RxIndicationFifo.head))
+ as = (MTL_AS*)RemoveHeadList(&mtl->RxIndicationFifo.head);
+
+ NdisReleaseSpinLock(&mtl->RxIndicationFifo.lock);
+
+ return(as);
+}
+
+VOID
+QueueDescriptorForRxIndication(
+ MTL *mtl,
+ MTL_AS *as
+ )
+{
+ NdisAcquireSpinLock(&mtl->RxIndicationFifo.lock);
+
+ InsertTailList(&mtl->RxIndicationFifo.head, &as->link);
+
+ NdisReleaseSpinLock(&mtl->RxIndicationFifo.lock);
+}
+
+/* do timer tick processing for rx side */
+VOID
+mtl__rx_tick(MTL *mtl)
+{
+ INT n;
+ MTL_AS *as;
+ MTL_RX_TBL *RxTable = &mtl->rx_tbl;
+
+ //
+ // see if there are any receives to give to wrapper
+ //
+ IndicateRxToWrapper(mtl);
+
+ NdisAcquireSpinLock(&mtl->lock);
+
+ NdisAcquireSpinLock(&RxTable->lock);
+
+ /* scan assembly table */
+ for ( n = 0, as = RxTable->as_tbl ; n < MTL_RX_BUFS ; n++, as++ )
+ {
+ /* update ttl & check */
+ if ( as->tot && !(as->ttl -= 25) )
+ {
+ D_LOG(D_ALWAYS, ("mtl__rx_bchan_handler: Pkt Kill ttl = 0: Slot: %d, mtl: 0x%p", n, mtl));
+
+ D_LOG(D_ALWAYS, ("AS Timeout! mtl: 0x%p, as: 0x%p, as->seq: 0x%x", mtl, as, as->seq));
+ D_LOG(D_ALWAYS, ("as->tot: %d, as->num: %d", as->tot, as->num));
+
+ RxTable->TimeOutReceiveError1++;
+
+ //
+ // if this guy was queued for indication to wrapper
+ // and was not indicated within a second something is wrong
+ //
+ if (as->Queued)
+ {
+ D_LOG(D_ALWAYS, ("AS Timeout while queued for indication! mtl: 0x%p, as: 0x%p", mtl, as));
+#if DBG
+ DbgBreakPoint();
+#endif
+ }
+
+ as->tot = 0;
+
+ //
+ // mark this guy as being free
+ //
+ as->Queued = 0;
+ }
+ }
+
+ NdisReleaseSpinLock(&RxTable->lock);
+
+ NdisReleaseSpinLock(&mtl->lock);
+}
+
+//
+// see if there are any receives to give to wrapper
+//
+VOID
+TryToIndicateMtlReceives(
+ ADAPTER *Adapter
+ )
+{
+ ULONG n;
+
+ for (n = 0; n < MAX_MTL_PER_ADAPTER; n++)
+ {
+ MTL *mtl = Adapter->MtlTbl[n];
+
+ if (mtl)
+ IndicateRxToWrapper(mtl);
+ }
+}
+
diff --git a/private/ntos/ndis/pcimac/mtl_set.c b/private/ntos/ndis/pcimac/mtl_set.c
new file mode 100644
index 000000000..a53fef8b3
--- /dev/null
+++ b/private/ntos/ndis/pcimac/mtl_set.c
@@ -0,0 +1,229 @@
+/*
+ * MTL_SET.C - set routines for MTL object
+ */
+
+#include <ndis.h>
+//#include <ndismini.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+#include <trc.h>
+#include <io.h>
+
+/* set rx handler */
+mtl_set_rx_handler (VOID *mtl_1, VOID (*handler)(), VOID *handler_arg)
+{
+ MTL *mtl = (MTL*)mtl_1;
+
+ D_LOG(D_ENTRY, ("mtl_set_rx_handler: entry, handler: 0x%p, handler_arg: 0x%p", \
+ handler, handler_arg));
+
+ /* get lock, set, release & return */
+ NdisAcquireSpinLock(&mtl->lock);
+ mtl->rx_handler = handler;
+ mtl->rx_handler_arg = handler_arg;
+ NdisReleaseSpinLock(&mtl->lock);
+ return(MTL_E_SUCC);
+}
+
+/* set tx handler */
+mtl_set_tx_handler(VOID *mtl_1, VOID (*handler)(), VOID *handler_arg)
+{
+ MTL *mtl = (MTL*)mtl_1;
+
+ D_LOG(D_ENTRY, ("mtl_set_tx_handler: entry, handler: 0x%p, handler_arg: 0x%p", \
+ handler, handler_arg));
+
+ /* get lock, set, release & return */
+ NdisAcquireSpinLock(&mtl->lock);
+ mtl->tx_handler = handler;
+ mtl->tx_handler_arg = handler_arg;
+ NdisReleaseSpinLock(&mtl->lock);
+ return(MTL_E_SUCC);
+}
+
+/* set idd mtu */
+mtl_set_idd_mtu(VOID *mtl_1, USHORT mtu)
+{
+ MTL *mtl = (MTL*)mtl_1;
+
+ D_LOG(D_ENTRY, ("mtl_set_idd_mtu: entry, mtu: 0x%x", mtu));
+
+ /* get lock, set, release & return */
+ NdisAcquireSpinLock(&mtl->lock);
+ mtl->idd_mtu = mtu;
+ NdisReleaseSpinLock(&mtl->lock);
+ return(MTL_E_SUCC);
+}
+
+/* set connection state */
+mtl_set_conn_state(
+ VOID *mtl_1,
+ USHORT NumberOfChannels,
+ BOOL is_conn)
+{
+ MTL *mtl = (MTL*)mtl_1;
+ ADAPTER *Adapter = mtl->Adapter;
+ NDIS_PHYSICAL_ADDRESS pa = NDIS_PHYSICAL_ADDRESS_CONST(0xffffffff, 0xffffffff);
+
+ D_LOG(D_ENTRY, ("mtl_set_conn_state: entry, is_conn: %d", is_conn));
+
+ /* get lock, set, release & return */
+ NdisAcquireSpinLock(&mtl->lock);
+
+ mtl->is_conn = is_conn;
+
+ //
+ // if we are being notified of a new connection we need to do some stuff
+ //
+ if (is_conn)
+ {
+ mtl->FramesXmitted = 0;
+ mtl->FramesReceived = 0;
+ mtl->BytesXmitted = 0;
+ mtl->BytesReceived = 0;
+ mtl->RecvFramingBits = 0;
+ mtl->tx_tbl.NextFree = 0;
+ mtl->rx_tbl.NextFree = 0;
+ }
+ NdisReleaseSpinLock(&mtl->lock);
+
+ return(MTL_E_SUCC);
+}
+
+/* get connection speed, add channels from chan_tbl */
+mtl_get_conn_speed(VOID *mtl_1, ULONG *speed)
+{
+ MTL *mtl = (MTL*)mtl_1;
+ USHORT n;
+
+ D_LOG(D_ENTRY, ("mtl_get_conn_speed: entry, mtk: 0x%p, @speed: 0x%p", mtl, speed));
+
+ /* get lock, count, release */
+ NdisAcquireSpinLock(&mtl->chan_tbl.lock);
+ for ( n = 0, *speed = 0 ; n < mtl->chan_tbl.num ; n++ )
+ *speed += mtl->chan_tbl.tbl[n].speed;
+ NdisReleaseSpinLock(&mtl->chan_tbl.lock);
+
+ D_LOG(D_EXIT, ("mtl_get_conn_speed: exit, speed: %ld bps", *speed));
+ return(MTL_E_SUCC);
+}
+
+/* get mac mtu on connection */
+mtl_get_mac_mtu(VOID *mtl_1, ULONG *mtu)
+{
+ MTL *mtl = (MTL*)mtl_1;
+
+ D_LOG(D_ENTRY, ("mtl_get_mac_mtu: entry, mtl: 0x%p, @mtu: 0x%p", mtl, mtu));
+
+ *mtu = MTL_MAC_MTU;
+
+ D_LOG(D_EXIT, ("mtl_get_mac_mtu: exit, mtu: %ld", *mtu));
+ return(MTL_E_SUCC);
+}
+
+/* add a channel to channel table */
+mtl_add_chan(VOID *mtl_1, VOID *idd, USHORT bchan, ULONG speed, ULONG ConnectionType)
+{
+ MTL *mtl = (MTL*)mtl_1;
+ INT ret = MTL_E_SUCC;
+ MTL_CHAN *chan;
+ INT n;
+
+ D_LOG(D_ENTRY, ("mtl_add_chan: entry, mtl: 0x%p, idd: 0x%p, bchan: %d, speed: 0x%x", \
+ mtl, idd, bchan, speed));
+
+ /* lock */
+ NdisAcquireSpinLock(&mtl->chan_tbl.lock);
+
+ /* check for space */
+ if ( mtl->chan_tbl.num >= MAX_CHAN_PER_CONN )
+ ret = MTL_E_NOROOM;
+ else
+ {
+ /* find free slot, MUST find! */
+ for ( chan = mtl->chan_tbl.tbl, n = 0 ; n < MAX_CHAN_PER_CONN ; n++, chan++ )
+ if ( !chan->idd )
+ break;
+ if ( n >= MAX_CHAN_PER_CONN )
+ {
+ D_LOG(D_ALWAYS, ("mtl_add_chan: not free slot when num < MAX!"));
+ ret = MTL_E_NOROOM;
+ }
+ else
+ {
+ /* slot found, fill it */
+ mtl->chan_tbl.num++;
+
+ if (ConnectionType == CM_DKF)
+ {
+ mtl->IddTxFrameType = IDD_FRAME_DKF;
+ mtl->SendFramingBits = RAS_FRAMING;
+ }
+ else
+ {
+ mtl->IddTxFrameType = IDD_FRAME_PPP;
+ mtl->SendFramingBits = PPP_FRAMING;
+ }
+
+ chan->idd = idd;
+ chan->bchan = bchan;
+ chan->speed = speed;
+ chan->mtl = mtl;
+
+ /* add handler for slot */
+ idd_attach(idd, bchan, (VOID*)mtl__rx_bchan_handler, chan);
+ }
+ }
+
+ /* release & return */
+ NdisReleaseSpinLock(&mtl->chan_tbl.lock);
+ D_LOG(D_EXIT, ("mtl_add_chan: exit, ret: %d", ret));
+ return(ret);
+}
+
+/* delete a channel from channel table */
+mtl_del_chan(VOID* mtl_1, VOID* idd, USHORT bchan)
+{
+ MTL *mtl = (MTL*)mtl_1;
+ INT ret = MTL_E_SUCC;
+ MTL_CHAN *chan;
+ INT n;
+
+ D_LOG(D_ENTRY, ("mtl_del_chan: entry, mtl: 0x%p, idd: 0x%p, bchan: %d", \
+ mtl, idd, bchan));
+
+ /* lock */
+ NdisAcquireSpinLock(&mtl->chan_tbl.lock);
+
+ /* scan table for a match */
+ for ( chan = mtl->chan_tbl.tbl, n = 0 ; n < MAX_CHAN_PER_CONN ; n++, chan++ )
+ if ( (chan->idd == idd) && (chan->bchan == bchan) )
+ break;
+
+ /* check for error */
+ if ( n >= MAX_CHAN_PER_CONN )
+ {
+ D_LOG(D_ALWAYS, ("mtl_del_chan: channel not found!"));
+ ret = MTL_E_NOSUCH;
+ }
+ else
+ {
+ /* found, delete handler & mark free it */
+ idd_detach(idd, bchan, (VOID*)mtl__rx_bchan_handler, chan);
+ chan->idd = NULL;
+ mtl->chan_tbl.num--;
+ }
+
+ /* release & return */
+ NdisReleaseSpinLock(&mtl->chan_tbl.lock);
+ D_LOG(D_EXIT, ("mtl_del_chan: exit, ret: %d", ret));
+ return(ret);
+}
diff --git a/private/ntos/ndis/pcimac/mtl_tick.c b/private/ntos/ndis/pcimac/mtl_tick.c
new file mode 100644
index 000000000..32226e313
--- /dev/null
+++ b/private/ntos/ndis/pcimac/mtl_tick.c
@@ -0,0 +1,48 @@
+/*
+ * MTL_TICK.C - tick (timer) processing for mtl
+ */
+
+#include <ndis.h>
+//#include <ndismini.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+
+/* driver global vars */
+extern DRIVER_BLOCK Pcimac;
+
+//
+// mtl polling function
+//
+//
+/* tick process */
+VOID
+MtlPollFunction(VOID *a1, ADAPTER *Adapter, VOID *a3, VOID *a4)
+{
+ ULONG n;
+
+ for (n = 0; n < MAX_MTL_PER_ADAPTER; n++)
+ {
+ MTL *mtl = Adapter->MtlTbl[n];
+
+ if (mtl)
+ {
+ mtl__rx_tick(mtl);
+
+ mtl__tx_tick(mtl);
+
+ MtlRecvCompleteFunction(Adapter);
+
+ MtlSendCompleteFunction(Adapter);
+ }
+ }
+
+ NdisMSetTimer(&Adapter->MtlPollTimer, MTL_POLL_T);
+}
diff --git a/private/ntos/ndis/pcimac/mtl_tx.c b/private/ntos/ndis/pcimac/mtl_tx.c
new file mode 100644
index 000000000..930ed9a8d
--- /dev/null
+++ b/private/ntos/ndis/pcimac/mtl_tx.c
@@ -0,0 +1,1066 @@
+ /*
+ * MTL_TX.C - trasmit side processing for MTL
+ */
+
+#include <ndis.h>
+//#include <ndismini.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+
+extern DRIVER_BLOCK Pcimac;
+
+/* local prototypes */
+BOOLEAN IsWanPacketTxFifoEmpty(MTL*);
+VOID AddToWanPacketTxFifo(MTL*, NDIS_WAN_PACKET*);
+MTL_TX_PKT* GetLocalTxDescriptor(MTL*);
+VOID FreeLocalTxDescriptor(MTL*, MTL_TX_PKT*);
+VOID TryToXmitFrags(MTL*);
+VOID SetTxDescriptorInWanPacket(MTL*,NDIS_WAN_PACKET*,MTL_TX_PKT*);
+VOID CheckWanPacketTimeToLive(MTL *mtl);
+VOID ReleaseTxDescriptor(MTL *mtl, MTL_TX_PKT *MtlTxPacket);
+
+#define IsWanPacketMarkedForCompletion(_WanPacket) \
+ ((_WanPacket)->MacReserved2 == (PVOID)TRUE)
+
+#define ClearTxDescriptorInWanPacket(_WanPacket) \
+ (_WanPacket)->MacReserved1 = (PVOID)NULL
+
+#define ClearReadyToCompleteInWanPacket(_WanPacket) \
+ (_WanPacket)->MacReserved2 = (PVOID)NULL
+
+#define SetTimeToLiveInWanPacket(_WanPacket, _TimeOut) \
+ (_WanPacket)->MacReserved3 = (PVOID)_TimeOut
+
+#define DecrementTimeToLiveForWanPacket(_WanPacket, _Decrement) \
+ (ULONG)((_WanPacket)->MacReserved3) -= (ULONG)_Decrement
+
+#define GetWanPacketTimeToLive(_WanPacket) \
+ (ULONG)((_WanPacket)->MacReserved3)
+
+#define GetTxDescriptorFromWanPacket(_WanPacket) \
+ ((MTL_TX_PKT*)((_WanPacket)->MacReserved1))
+
+#define MarkWanPacketForCompletion(_WanPacket) \
+ (_WanPacket)->MacReserved2 = (PVOID)TRUE
+
+#define SetTxDescriptorInWanPacket(_WanPacket, _TxDescriptor) \
+ (_WanPacket)->MacReserved1 = (PVOID)_TxDescriptor
+
+#define IncrementGlobalCount(_Counter) \
+{ \
+ NdisAcquireSpinLock(&Pcimac.lock); \
+ _Counter++; \
+ NdisReleaseSpinLock(&Pcimac.lock); \
+}
+
+ULONG GlobalSends = 0;
+ULONG GlobalSendsCompleted = 0;
+ULONG MtlSends1 = 0;
+ULONG MtlSends2 = 0;
+ULONG MtlSends3 = 0;
+ULONG MtlSends4 = 0;
+ULONG MtlSends5 = 0;
+
+/* trasmit side timer tick */
+VOID
+mtl__tx_tick(MTL *mtl)
+{
+ D_LOG(D_NEVER, ("mtl__tx_tick: entry, mtl: 0x%p", mtl));
+
+ NdisAcquireSpinLock(&mtl->lock);
+
+ //
+ // try to transmit frags to the adapter
+ //
+ TryToXmitFrags(mtl);
+
+ //
+ // Check time to live on wan packet tx fifo
+ //
+ CheckWanPacketTimeToLive(mtl);
+
+ NdisReleaseSpinLock(&mtl->lock);
+
+}
+
+VOID
+MtlSendCompleteFunction(
+ ADAPTER *Adapter
+ )
+{
+ ULONG n;
+
+ for ( n = 0; n < MAX_MTL_PER_ADAPTER; n++)
+ {
+ MTL *mtl = Adapter->MtlTbl[n] ;
+
+ if (mtl && !IsWanPacketTxFifoEmpty(mtl))
+ {
+ //
+ // try to complete any wan packets ready for completion
+ //
+ IndicateTxCompletionToWrapper(mtl);
+ }
+ }
+}
+
+//
+// process a wan packet for transmition to idd level
+//
+// all packets will stay on one queue and the MacReserved fields will be used
+// to indicate what state the packet is in
+//
+// we will use the MacReserved fields provided in the NdisWanPacket as follows:
+//
+// MacReserved1 - Store a pointer to our local tx descriptor
+// MacReserved2 - This will be a boolean flag that will be set when this packet
+// can be completed (NdisMWanSendComplete)
+// MacReserved3 - This will be the time to live counter for the wanpacket.
+// If it is not completed we will go ahead and complete it.
+//
+// MacReserved4
+//
+VOID
+mtl__tx_packet(
+ MTL *mtl,
+ NDIS_WAN_PACKET *WanPacket
+ )
+{
+ UINT BytesLeftToTx, FragDataLength, FragNumber, FragSize;
+ UINT TotalPacketLength;
+ UCHAR *FragDataPtr;
+ MTL_TX_PKT *MtlTxPacket;
+ MTL_HDR MtlHeader;
+ USHORT TxFlags;
+ ADAPTER *Adapter = mtl->Adapter;
+ PUCHAR MyStartBuffer;
+ CM *cm = (CM*)mtl->cm;
+
+ D_LOG(D_ENTRY, ("mtl_tx_packet: entry, mtl: 0x%p, WanPacket: 0x%p", mtl, WanPacket));
+
+ NdisAcquireSpinLock(&mtl->lock);
+
+ IncrementGlobalCount(GlobalSends);
+
+ //
+ // queue up the wanpacket
+ //
+ AddToWanPacketTxFifo(mtl, WanPacket);
+
+ //
+ // get a local packet descriptor
+ //
+ MtlTxPacket = GetLocalTxDescriptor(mtl);
+
+ //
+ // make sure this is a valid descriptor
+ //
+ if (!MtlTxPacket)
+ {
+ D_LOG(D_ALWAYS, ("mtl__tx_proc: Got a NULL Packet off of Local Descriptor Free List"));
+
+ //
+ // grab wan packet fifo lock
+ //
+ NdisAcquireSpinLock(&mtl->WanPacketFifo.lock);
+
+ MarkWanPacketForCompletion(WanPacket);
+
+ //
+ // release the wan packet fifo lock
+ //
+ NdisReleaseSpinLock(&mtl->WanPacketFifo.lock);
+
+ goto exit_code;
+ }
+
+ //
+ // grab wan packet fifo lock
+ //
+ NdisAcquireSpinLock(&mtl->WanPacketFifo.lock);
+
+ SetTxDescriptorInWanPacket(WanPacket, MtlTxPacket);
+
+ //
+ // release the wan packet fifo lock
+ //
+ NdisReleaseSpinLock(&mtl->WanPacketFifo.lock);
+
+ //
+ // grab the descriptor lock
+ //
+ NdisAcquireSpinLock(&MtlTxPacket->lock);
+
+ IncrementGlobalCount(MtlSends1);
+
+ /* if not connected, give up */
+ if ( !mtl->is_conn || cm->PPPToDKF)
+ {
+ D_LOG(D_ALWAYS, ("mtl__tx_proc: packet on non-connected mtl, ignored"));
+
+ IncrementGlobalCount(MtlSends2);
+
+ goto xmit_error;
+ }
+
+ D_LOG(D_ALWAYS, ("mtl__tx_proc: LocalPkt: 0x%p, WanPkt: 0x%p, WanPktLen: %d", MtlTxPacket, WanPacket, WanPacket->CurrentLength));
+
+ //
+ // get length of wan packet
+ //
+ TotalPacketLength = WanPacket->CurrentLength;
+
+ //
+ // my start buffer is WanPacket->CurrentBuffer - 14
+ //
+ MyStartBuffer = WanPacket->CurrentBuffer - 14;
+
+ if (mtl->SendFramingBits & RAS_FRAMING)
+ {
+ D_LOG(D_ALWAYS, ("mtl__tx_proc: Transmit WrapperFrameType: RAS"));
+
+ // add dest eaddr
+ // StartBuffer + 0
+ //
+ NdisMoveMemory (MyStartBuffer + DST_ADDR_INDEX,
+ cm->DstAddr,
+ 6);
+
+ //
+ // add source eaddr
+ // StartBuffer + 6
+ //
+ NdisMoveMemory (MyStartBuffer + SRC_ADDR_INDEX,
+ cm->SrcAddr,
+ 6);
+
+ //
+ // add new length to buffer
+ // StartBuffer + 12
+ //
+ MyStartBuffer[12] = TotalPacketLength >> 8;
+ MyStartBuffer[13] = TotalPacketLength & 0xFF;
+
+ //
+ // data now begins at MyStartBuffer
+ //
+ MtlTxPacket->frag_buf = MyStartBuffer;
+
+ //
+ // new transmit length is a mac header larger
+ //
+ TotalPacketLength += 14;
+ }
+ else if (mtl->SendFramingBits & PPP_FRAMING)
+ {
+ D_LOG(D_ALWAYS, ("mtl__tx_proc: Transmit WrapperFrameType: PPP"));
+
+ //
+ // data now begins at CurrentBuffer
+ //
+ MtlTxPacket->frag_buf = WanPacket->CurrentBuffer;
+ }
+ else
+ {
+ //
+ // unknown framing - what to do what to do
+ //
+ D_LOG(D_ALWAYS, ("mtl__tx_proc: Packet sent with uknown framing, ignored"));
+
+ IncrementGlobalCount(MtlSends3);
+
+ goto xmit_error;
+ }
+
+
+ if (TotalPacketLength > MTL_MAC_MTU)
+ {
+ D_LOG(D_ALWAYS, ("mtl__tx_proc: packet too long, TotalPacketLength: %d", TotalPacketLength));
+
+ IncrementGlobalCount(MtlSends4);
+
+ goto xmit_error;
+ }
+
+ /* step 4: calc number of fragments */
+ D_LOG(D_ALWAYS, ("mtl__tx_proc: calc frag num, TotalPacketLength: %d", TotalPacketLength));
+
+ MtlTxPacket->NumberOfFrags = (USHORT)(TotalPacketLength / mtl->chan_tbl.num / mtl->idd_mtu);
+
+ if ( TotalPacketLength != (USHORT)(MtlTxPacket->NumberOfFrags * mtl->chan_tbl.num * mtl->idd_mtu) )
+ MtlTxPacket->NumberOfFrags++;
+
+ MtlTxPacket->NumberOfFrags *= mtl->chan_tbl.num;
+
+ if ( MtlTxPacket->NumberOfFrags > MTL_MAX_FRAG )
+ {
+ D_LOG(D_ALWAYS, ("mtl__tx_proc: pkt has too many frags, NumberOfFrags: %d", \
+ MtlTxPacket->NumberOfFrags));
+
+ IncrementGlobalCount(MtlSends5);
+
+ goto xmit_error;
+ }
+
+ D_LOG(D_ALWAYS, ("mtl__tx_proc: NumberOfFrags: %d", MtlTxPacket->NumberOfFrags));
+
+ /* step 5: build generic header */
+ if (mtl->IddTxFrameType & IDD_FRAME_DKF)
+ {
+ MtlHeader.sig_tot = MtlTxPacket->NumberOfFrags | 0x50;
+ MtlHeader.seq = (UCHAR)(mtl->tx_tbl.seq++);
+ MtlHeader.ofs = 0;
+ }
+
+ /* step 6: build fragments */
+
+ //
+ // bytes left to send is initially the packet size
+ //
+ BytesLeftToTx = TotalPacketLength;
+
+ //
+ // FragDataPtr initially points to begining of frag buffer
+ //
+ FragDataPtr = MtlTxPacket->frag_buf;
+
+ //
+ // initial txflags are for a complete frame
+ //
+ TxFlags = 0;
+
+ for ( FragNumber = 0 ; FragNumber < MtlTxPacket->NumberOfFrags ; FragNumber++ )
+ {
+ MTL_TX_FRAG *FragPtr = &MtlTxPacket->frag_tbl[FragNumber];
+ IDD_MSG *FragMsg = &FragPtr->frag_msg;
+ MTL_CHAN *chan;
+
+ /* if it's first channel, establish next fragment size */
+ if ( !(FragNumber % mtl->chan_tbl.num) )
+ FragSize = MIN((BytesLeftToTx / mtl->chan_tbl.num), mtl->idd_mtu);
+
+ /* establish related channel */
+ chan = mtl->chan_tbl.tbl + (FragNumber % mtl->chan_tbl.num);
+
+ /* calc size of this fragment */
+ if ( FragNumber == (USHORT)(MtlTxPacket->NumberOfFrags - 1) )
+ FragDataLength = BytesLeftToTx;
+ else
+ FragDataLength = FragSize;
+
+ D_LOG(D_ALWAYS, ("mtl__proc_tx: FragNumber: %d, FragDataPtr: 0x%p, FragLength: %d", \
+ FragNumber, FragDataPtr, FragDataLength));
+
+ if (mtl->IddTxFrameType & IDD_FRAME_DKF)
+ {
+ DKF_FRAG *DkfFrag = &FragPtr->DkfFrag;
+ IDD_FRAG *IddFrag0 = &DkfFrag->IddFrag[0];
+ IDD_FRAG *IddFrag1 = &DkfFrag->IddFrag[1];
+
+ D_LOG(D_ALWAYS, ("mtl__tx_proc: Transmit IddFrameType: DKF"));
+
+ //
+ // setup fragment descriptor for DKF data
+ //
+ /* setup fragment header */
+ DkfFrag->MtlHeader = MtlHeader;
+
+ /* set pointer to header */
+ IddFrag0->len = sizeof(MTL_HDR);
+ IddFrag0->ptr = (CHAR*)(&DkfFrag->MtlHeader);
+
+ /* set pointer to data */
+ IddFrag1->len = FragDataLength;
+ IddFrag1->ptr = FragDataPtr;
+
+ //
+ // fill idd message
+ //
+ FragMsg->buflen = sizeof(DKF_FRAG) | TX_FRAG_INDICATOR;
+
+ //
+ // this assumes that the DKF_FRAG structure is the first
+ // member of the MTL_TX_FRAG structure !!!!!
+ //
+ FragMsg->bufptr = (UCHAR*)FragPtr;
+ }
+ else
+ {
+ D_LOG(D_ALWAYS, ("mtl__tx_proc: Transmit IddFrameType: PPP"));
+ //
+ // setup fragment descriptor for ppp frame
+ //
+
+ if (BytesLeftToTx <= mtl->idd_mtu )
+ {
+ //
+ // if all that is left can be sent this is the end
+ //
+ FragMsg->buflen = FragDataLength | TxFlags;
+ }
+ else
+ {
+ //
+ // if there is still more this is not end
+ //
+ FragMsg->buflen = FragDataLength | TxFlags | H_TX_N_END;
+ }
+
+ //
+ // setup data pointer
+ //
+ FragMsg->bufptr = (UCHAR*)FragDataPtr;
+ }
+
+ FragPtr->FragSent = 0;
+ FragPtr->frag_idd = chan->idd;
+ FragPtr->frag_bchan = chan->bchan;
+ FragPtr->frag_arg = MtlTxPacket;
+
+ /* update variables */
+ TxFlags = H_TX_N_BEG;
+ BytesLeftToTx -= FragDataLength;
+ FragDataPtr += FragDataLength;
+ MtlHeader.ofs += FragDataLength;
+ }
+ /* step 7: setup more fields */
+ MtlTxPacket->WanPacket = WanPacket;
+ MtlTxPacket->FragReferenceCount = MtlTxPacket->NumberOfFrags;
+ MtlTxPacket->mtl = mtl;
+ MtlTxPacket->NumberOfFragsSent = 0;
+
+ mtl->FramesXmitted++;
+ mtl->BytesXmitted += TotalPacketLength;
+
+ //
+ // release the lock befor xmitting
+ //
+ NdisReleaseSpinLock(&MtlTxPacket->lock);
+
+ //
+ // put this tx descriptor on list for transmition
+ //
+ NdisAcquireSpinLock(&mtl->tx_tbl.lock);
+
+ InsertTailList(&mtl->tx_tbl.head, &MtlTxPacket->TxPacketQueue);
+
+ NdisReleaseSpinLock(&mtl->tx_tbl.lock);
+
+ //
+ // Try to xmit some frags
+ //
+ TryToXmitFrags(mtl);
+
+ goto exit_code;
+
+ //
+ // error while setting up for transmition
+ //
+ xmit_error:
+
+ ClearTxDescriptorInWanPacket(WanPacket);
+
+ //
+ // free tx descriptor
+ //
+ FreeLocalTxDescriptor(mtl, MtlTxPacket);
+
+ //
+ // free descriptors lock
+ //
+ NdisReleaseSpinLock(&MtlTxPacket->lock);
+
+ //
+ // grab wan packet fifo lock
+ //
+ NdisAcquireSpinLock(&mtl->WanPacketFifo.lock);
+
+ //
+ // mark wan packet for completion
+ //
+ MarkWanPacketForCompletion(WanPacket);
+
+ //
+ // release the wan packet fifo lock
+ //
+ NdisReleaseSpinLock(&mtl->WanPacketFifo.lock);
+
+ //
+ // exit code
+ // release spinlock and return
+ //
+ exit_code:
+
+ NdisReleaseSpinLock(&mtl->lock);
+}
+
+//
+// Try to transmit fragments to idd
+//
+VOID
+TryToXmitFrags(
+ MTL *mtl
+ )
+{
+ LIST_ENTRY *MtlTxPacketQueueHead;
+ MTL_TX_TBL *MtlTxTbl = &mtl->tx_tbl;
+ MTL_TX_PKT *MtlTxPacket;
+ ULONG Ret = IDD_E_SUCC;
+ BOOLEAN WeCanXmit = 1;
+
+ //
+ // get tx table spin lock
+ //
+ NdisAcquireSpinLock(&MtlTxTbl->lock);
+
+ MtlTxPacketQueueHead = &MtlTxTbl->head;
+
+ //
+ // while we can still transmit and we are not at the end of the list
+ //
+ while (WeCanXmit && !IsListEmpty(MtlTxPacketQueueHead))
+ {
+ USHORT n, NumberOfFragsToSend;
+
+ MtlTxPacket = (MTL_TX_PKT*)MtlTxPacketQueueHead->Flink;
+
+ //
+ // get the number of frags we will try to send
+ //
+ NdisAcquireSpinLock(&MtlTxPacket->lock);
+
+ NumberOfFragsToSend = MtlTxPacket->NumberOfFrags;
+
+ NdisReleaseSpinLock(&MtlTxPacket->lock);
+
+ for (n = 0; n < NumberOfFragsToSend; n++)
+ {
+ MTL_TX_FRAG *FragToSend;
+
+ NdisAcquireSpinLock(&MtlTxPacket->lock);
+
+ FragToSend = &MtlTxPacket->frag_tbl[n];
+
+ NdisReleaseSpinLock(&MtlTxPacket->lock);
+
+ //
+ // if this frag has already been sent get the next one
+ //
+ if (FragToSend->FragSent)
+ continue;
+
+ D_LOG(D_ALWAYS, ("TryToXmitFrag: mtl: 0x%x", mtl));
+ D_LOG(D_ALWAYS, ("Next Packet To Xmit: MtlTxPacket: 0x%x", MtlTxPacket));
+ D_LOG(D_ALWAYS, ("Xmitting Packet: MtlTxPacket: 0x%x", MtlTxPacket));
+ D_LOG(D_ALWAYS, ("TryToXmitFrag: FragToSend: 0x%x", FragToSend));
+ D_LOG(D_ALWAYS, ("TryToXmitFrag: Idd: 0x%x, Msg: 0x%x, Bchan: 0x%x, Arg: 0x%x", \
+ FragToSend->frag_idd, &FragToSend->frag_msg, FragToSend->frag_bchan, \
+ FragToSend->frag_arg));
+
+ //
+ // Something was ready to send
+ // release all locks before sending
+ //
+ NdisReleaseSpinLock(&MtlTxTbl->lock);
+
+ Ret = idd_send_msg(FragToSend->frag_idd,
+ &FragToSend->frag_msg,
+ FragToSend->frag_bchan,
+ (VOID*)mtl__tx_cmpl_handler,
+ FragToSend->frag_arg);
+
+ //
+ // acquire Tx Tbl fifo lock
+ // exit code expects the lock to be held
+ //
+ NdisAcquireSpinLock(&MtlTxTbl->lock);
+
+ if (Ret == IDD_E_SUCC)
+ {
+ //
+ // this means frag was sent to idd
+ // all locks will be released before next frag is sent
+ //
+
+ //
+ // acquire descriptor lock
+ // exit code expects the lock to be held
+ //
+ NdisAcquireSpinLock(&MtlTxPacket->lock);
+
+ //
+ // message was queued or sent!
+ //
+ MtlTxPacket->NumberOfFragsSent++;
+
+ FragToSend->FragSent++;
+
+ if (MtlTxPacket->NumberOfFragsSent == MtlTxPacket->NumberOfFrags)
+ {
+ //
+ // if things are working ok this guy will be on top
+ //
+ ASSERT((PVOID)MtlTxPacketQueueHead->Flink == (PVOID)MtlTxPacket);
+
+ //
+ // take a guy off of the to be transmitted list
+ //
+ RemoveEntryList(&MtlTxPacket->TxPacketQueue);
+ }
+
+ //
+ // release the lock for this descriptor
+ //
+ NdisReleaseSpinLock(&MtlTxPacket->lock);
+ }
+ else
+ {
+ //
+ // if this frag is not sent to idd
+ // then stop xmitting
+ //
+ WeCanXmit = 0;
+ }
+ }
+
+ }
+
+ //
+ // release the tx tbl fifo lock
+ //
+ NdisReleaseSpinLock(&MtlTxTbl->lock);
+}
+
+/* trasmit completion routine */
+VOID
+mtl__tx_cmpl_handler(
+ MTL_TX_PKT *MtlTxPacket,
+ USHORT port,
+ IDD_MSG *msg
+ )
+{
+ MTL *mtl;
+ PNDIS_WAN_PACKET WanPacket;
+
+ D_LOG(D_ENTRY, ("mtl__tx_cmpl_handler: entry, MtlTxPacket: 0x%p, port: %d, msg: 0x%p", \
+ MtlTxPacket, port, msg));
+
+ NdisAcquireSpinLock(&MtlTxPacket->lock);
+
+ mtl = MtlTxPacket->mtl;
+
+ //
+ // if this guy was set free from a disconnect while he was
+ // on the idd tx queue. Just throw him away!
+ // if this is not the last reference to the packet get the hell out!!!
+ //
+ if (!MtlTxPacket->InUse || --MtlTxPacket->FragReferenceCount )
+ {
+ NdisReleaseSpinLock(&MtlTxPacket->lock);
+ return;
+ }
+
+ D_LOG(D_ALWAYS, ("mtl__tx_cmpl_handler: FragReferenceCount==0, mtl: 0x%p", mtl));
+
+ //
+ // Get hold of PNDIS_WAN_PACKET associated with this descriptor
+ //
+ WanPacket = MtlTxPacket->WanPacket;
+
+ if (!WanPacket)
+ {
+ ASSERT(WanPacket);
+ NdisReleaseSpinLock(&MtlTxPacket->lock);
+ return;
+ }
+
+ ClearTxDescriptorInWanPacket(WanPacket);
+
+ //
+ // return local packet descriptor to free list
+ //
+ FreeLocalTxDescriptor(mtl, MtlTxPacket);
+
+ NdisReleaseSpinLock(&MtlTxPacket->lock);
+
+ //
+ // grab wan packet fifo lock
+ //
+ NdisAcquireSpinLock(&mtl->WanPacketFifo.lock);
+
+ //
+ // mark wan packet as being ready for completion
+ //
+ MarkWanPacketForCompletion(WanPacket);
+
+ //
+ // release the wan packet fifo lock
+ //
+ NdisReleaseSpinLock(&mtl->WanPacketFifo.lock);
+}
+
+//
+// get a local packet descriptor off of the free list
+//
+MTL_TX_PKT*
+GetLocalTxDescriptor(
+ MTL *mtl
+ )
+{
+ MTL_TX_PKT* FreePkt = NULL;
+ MTL_TX_TBL* TxTbl = &mtl->tx_tbl;
+
+ NdisAcquireSpinLock (&mtl->tx_tbl.lock);
+
+ //
+ // get next available freepkt
+ //
+ FreePkt = TxTbl->TxPacketTbl + (TxTbl->NextFree % MTL_TX_BUFS);
+
+ //
+ // if still in use we have a wrap
+ //
+ if (FreePkt->InUse)
+ {
+ ASSERT(!FreePkt->InUse);
+ NdisReleaseSpinLock (&mtl->tx_tbl.lock);
+ return(NULL);
+ }
+
+ //
+ // mark as being used
+ //
+ FreePkt->InUse = 1;
+
+ //
+ // bump pointer to next free
+ //
+ TxTbl->NextFree++;
+
+ NdisReleaseSpinLock (&mtl->tx_tbl.lock);
+
+ return(FreePkt);
+}
+
+//
+// return a local packet descriptor to free pool
+// assumes that the MtlTxPacket lock is held
+//
+VOID
+FreeLocalTxDescriptor(
+ MTL *mtl,
+ MTL_TX_PKT *MtlTxPacket
+ )
+{
+
+ ASSERT(MtlTxPacket->InUse);
+
+ MtlTxPacket->InUse = 0;
+
+ MtlTxPacket->WanPacket = NULL;
+}
+
+//
+// see if wan packet fifo is empty
+//
+BOOLEAN
+IsWanPacketTxFifoEmpty(
+ MTL *mtl
+ )
+{
+ BOOLEAN Result;
+
+ NdisAcquireSpinLock (&mtl->WanPacketFifo.lock);
+
+ Result = IsListEmpty(&mtl->WanPacketFifo.head);
+
+ NdisReleaseSpinLock (&mtl->WanPacketFifo.lock);
+
+ return(Result);
+}
+
+//
+// add a wan packet to the wan packet fifo
+//
+VOID
+AddToWanPacketTxFifo(
+ MTL *mtl,
+ NDIS_WAN_PACKET *WanPacket
+ )
+{
+ MTL_WANPACKET_FIFO *WanPacketFifo = &mtl->WanPacketFifo;
+
+ D_LOG(D_ENTRY, ("AddToWanPacketTxFifo: mtl: 0x%x, head: 0x%x", mtl, WanPacketFifo->head));
+
+ NdisAcquireSpinLock (&WanPacketFifo->lock);
+
+ ClearReadyToCompleteInWanPacket(WanPacket);
+
+ SetTimeToLiveInWanPacket(WanPacket, 5000);
+
+ ClearTxDescriptorInWanPacket(WanPacket);
+
+ InsertTailList(&WanPacketFifo->head, &WanPacket->WanPacketQueue);
+
+ WanPacketFifo->Count++;
+
+ if (WanPacketFifo->Count > WanPacketFifo->Max)
+ WanPacketFifo->Max = WanPacketFifo->Count;
+
+ NdisReleaseSpinLock (&WanPacketFifo->lock);
+}
+
+//
+// indicate xmit completion of wan packet to wrapper
+//
+VOID
+IndicateTxCompletionToWrapper(
+ MTL *mtl
+ )
+{
+ ADAPTER *Adapter = (ADAPTER*)mtl->Adapter;
+ NDIS_WAN_PACKET *WanPacket;
+ LIST_ENTRY *WanPacketFifoHead;
+ MTL_WANPACKET_FIFO *WanPacketFifo = &mtl->WanPacketFifo;
+
+ //
+ // acquire wan packet fifo lock
+ //
+ NdisAcquireSpinLock(&WanPacketFifo->lock);
+
+ //
+ // get head of wan packet fifo
+ //
+ WanPacketFifoHead = &WanPacketFifo->head;
+
+ //
+ // visit the first packet on the tx list
+ //
+ WanPacket = (NDIS_WAN_PACKET*)WanPacketFifoHead->Flink;
+
+ //
+ // if the list is not empty and this packet is ready to be completed
+ //
+ while (((PVOID)WanPacket != (PVOID)WanPacketFifoHead) &&
+ IsWanPacketMarkedForCompletion(WanPacket))
+ {
+
+ WanPacket = (PNDIS_WAN_PACKET)RemoveHeadList(&WanPacketFifo->head);
+
+ WanPacketFifo->Count--;
+
+ if (!WanPacket)
+ break;
+
+ IncrementGlobalCount(GlobalSendsCompleted);
+
+ ClearReadyToCompleteInWanPacket(WanPacket);
+
+ //
+ // release wan packet fifo lock
+ //
+ NdisReleaseSpinLock(&WanPacketFifo->lock);
+
+ NdisMWanSendComplete(Adapter->Handle, WanPacket, NDIS_STATUS_SUCCESS);
+
+ //
+ // acquire wan packet fifo lock
+ //
+ NdisAcquireSpinLock(&WanPacketFifo->lock);
+
+ //
+ // visit the new head of the list
+ //
+ WanPacket = (NDIS_WAN_PACKET*)WanPacketFifoHead->Flink;
+ }
+
+ //
+ // release wan packet fifo lock
+ //
+ NdisReleaseSpinLock(&WanPacketFifo->lock);
+}
+
+VOID
+MtlFlushWanPacketTxQueue(
+ MTL *mtl
+ )
+{
+ LIST_ENTRY *WanPacketFifoHead;
+ MTL_WANPACKET_FIFO *WanPacketFifo = &mtl->WanPacketFifo;
+ NDIS_WAN_PACKET *WanPacket;
+ MTL_TX_PKT *MtlTxPacket;
+
+ //
+ // acquire wan packet fifo lock
+ //
+ NdisAcquireSpinLock(&WanPacketFifo->lock);
+
+ //
+ // get head of wan packet fifo
+ //
+ WanPacketFifoHead = &WanPacketFifo->head;
+
+ //
+ // visit the first packet on the tx list
+ //
+ WanPacket = (NDIS_WAN_PACKET*)WanPacketFifoHead->Flink;
+
+ //
+ // if the wan packet queue is not empty
+ // we need to drain it!
+ //
+ while ((PVOID)WanPacket != (PVOID)WanPacketFifoHead)
+ {
+ //
+ // get the associated MtlTxPacket
+ //
+ if (MtlTxPacket = GetTxDescriptorFromWanPacket(WanPacket))
+ ReleaseTxDescriptor(mtl, MtlTxPacket);
+
+ //
+ // mark wan packet for completion
+ //
+ MarkWanPacketForCompletion(WanPacket);
+
+ //
+ // get the next packet on the list
+ //
+ WanPacket = (NDIS_WAN_PACKET*)(WanPacket->WanPacketQueue).Flink;
+ }
+
+ //
+ // release wan packet fifo lock
+ //
+ NdisReleaseSpinLock(&WanPacketFifo->lock);
+}
+
+//
+// walk through the WanPacketFifo and see if anyone has been sitting there
+// too long! This could happen if there was some kind of xmit failure to
+// the adapter.
+//
+VOID
+CheckWanPacketTimeToLive(
+ MTL *mtl
+ )
+{
+ LIST_ENTRY *WanPacketFifoHead;
+ MTL_WANPACKET_FIFO *WanPacketFifo = &mtl->WanPacketFifo;
+ NDIS_WAN_PACKET *WanPacket;
+ MTL_TX_PKT *MtlTxPacket;
+
+ //
+ // acquire wan packet fifo lock
+ //
+ NdisAcquireSpinLock(&WanPacketFifo->lock);
+
+ //
+ // get head of wan packet fifo
+ //
+ WanPacketFifoHead = &WanPacketFifo->head;
+
+ //
+ // visit the first packet on the tx list
+ //
+ WanPacket = (NDIS_WAN_PACKET*)WanPacketFifoHead->Flink;
+
+ //
+ // if the wan packet is not empty
+ //
+ while ((PVOID)WanPacket != (PVOID)WanPacketFifoHead)
+ {
+
+ //
+ // decrement the count by 25ms
+ //
+ DecrementTimeToLiveForWanPacket(WanPacket, 25);
+
+ //
+ // if the count has gone to zero this guy has
+ // been waiting for more then 1sec so complete him
+ //
+ if (!GetWanPacketTimeToLive(WanPacket))
+ {
+
+// if (IsWanPacketMarkedForCompletion(WanPacket))
+// DbgPrint("PCIMAC.SYS: WanPacket was already marked for completion!\n");
+//
+// //
+// // get the associated MtlTxPacket and free
+// //
+// if (MtlTxPacket = GetTxDescriptorFromWanPacket(WanPacket))
+// ReleaseTxDescriptor(mtl, MtlTxPacket);
+//
+// //
+// // mark the packet for completion
+// //
+// MarkWanPacketForCompletion(WanPacket);
+ }
+
+ //
+ // get the next packet on the list
+ //
+ WanPacket = (NDIS_WAN_PACKET*)(WanPacket->WanPacketQueue).Flink;
+ }
+
+ //
+ // release wan packet fifo lock
+ //
+ NdisReleaseSpinLock(&WanPacketFifo->lock);
+}
+
+VOID
+ReleaseTxDescriptor(
+ MTL *mtl,
+ MTL_TX_PKT *MtlTxPacket
+ )
+{
+ LIST_ENTRY *MtlTxPacketQueueHead;
+ MTL_TX_TBL *MtlTxTbl = &mtl->tx_tbl;
+ MTL_TX_PKT *NextMtlTxPacket;
+
+ //
+ // act like this local descriptor was sent
+ // keeps desriptor table pointers in line
+ //
+ NdisAcquireSpinLock(&MtlTxTbl->lock);
+
+ MtlTxPacketQueueHead = &MtlTxTbl->head;
+
+ //
+ // get the descriptor lock
+ //
+ NdisAcquireSpinLock(&MtlTxPacket->lock);
+
+ //
+ // visit the first packet on the list
+ //
+ NextMtlTxPacket = (MTL_TX_PKT*)MtlTxPacketQueueHead->Flink;
+
+ //
+ // break if the list has been traversed or if we find the packet
+ //
+ while (((PVOID)NextMtlTxPacket != MtlTxPacketQueueHead) && (NextMtlTxPacket != MtlTxPacket))
+ NextMtlTxPacket = (MTL_TX_PKT*)(NextMtlTxPacket->TxPacketQueue).Flink;
+
+ //
+ // if this descriptor is marked for transmition
+ // we should remove it from the tx descriptor list
+ //
+ if (NextMtlTxPacket == MtlTxPacket)
+ RemoveEntryList(&MtlTxPacket->TxPacketQueue);
+
+ FreeLocalTxDescriptor(mtl, MtlTxPacket);
+
+ NdisReleaseSpinLock(&MtlTxPacket->lock);
+
+ NdisReleaseSpinLock(&MtlTxTbl->lock);
+}
diff --git a/private/ntos/ndis/pcimac/mydefs.h b/private/ntos/ndis/pcimac/mydefs.h
new file mode 100644
index 000000000..028ebd7ed
--- /dev/null
+++ b/private/ntos/ndis/pcimac/mydefs.h
@@ -0,0 +1,354 @@
+#ifndef _MYDEFS_
+#define _MYDEFS_
+
+//
+// maximum number of idd's per adapter
+// this is one pcimac/4 adapter
+//
+#define MAX_IDD_PER_ADAPTER 4
+
+//
+// maximum number of conection objects per adapter
+// this is one for each bchannel of a pcimac/4
+//
+#define MAX_CM_PER_ADAPTER 8
+
+// maximum number of mtl objects per adapter
+// this is one for each bchannel of a pcimac/4
+//
+#define MAX_MTL_PER_ADAPTER 8
+
+//
+// number of adapters in system
+//
+#define MAX_ADAPTERS_IN_SYSTEM 8
+
+//
+// maximum number of idd's in system
+// this is 5 pcimac/4 adapters
+//
+#define MAX_IDD_IN_SYSTEM 20
+
+//
+// maximum number of connection objects
+// in system
+// this is 5 pcimac/4 adpaters with a
+// connection object for each bchannel
+//
+#define MAX_CM_IN_SYSTEM 40
+
+//
+// maximum number of mtl objects
+// in system
+// this is 5 pcimac/4 adpaters with a
+// connection object for each bchannel
+//
+#define MAX_MTL_IN_SYSTEM 40
+
+//
+// maximum number of cm channel objects
+// in system
+// this is 5 pcimac/4 adpaters with a
+// connection object for each bchannel
+//
+#define MAX_CHAN_IN_SYSTEM 40
+
+//
+// maximum number of calls that can be made on
+// single line
+//
+//#define MAX_CALL_PER_LINE 2
+#define MAX_CALL_PER_LINE 1
+
+//
+// maximum number of channels supported by an idd
+//
+#define MAX_CHANNELS_PER_IDD 2
+
+//
+// maximum number of channels supported by an idd
+//
+#define MAX_LTERMS_PER_IDD 2
+
+#define MAX_WANPACKET_XMITS 3
+#define MAX_WANPACKET_BUFFERSIZE 1500
+#define MAX_WANPACKET_HEADERPADDING 14
+#define MAX_WANPACKET_TAILPADDING 0
+
+//
+// connection data type's
+//
+#define CM_PPP 0
+#define CM_DKF 1
+
+//
+// maximum number of channels allowed in a single connection
+//
+#define MAX_CHAN_PER_CONN 8
+
+//
+// defines for adapter boardtypes
+//
+#define IDD_BT_PCIMAC 0 /* - ISA, single channel */
+#define IDD_BT_PCIMAC4 1 /* - ISA, four channel */
+#define IDD_BT_MCIMAC 2 /* - MCA, single channel */
+#define IDD_BT_DATAFIREU 3 /* - ISA/U, single channel */
+
+//
+// Send window size
+//
+#define ISDN_WINDOW_SIZE 10
+
+//
+// Ndis Version Info
+//
+#define NDIS_MAJOR_VER 0x03
+#define NDIS_MINOR_VER 0x00
+
+//
+// OID Switch
+//
+#define OID_GEN_INFO 0x00000000
+#define OID_8023_INFO 0x01000000
+#define OID_WAN_INFO 0x04000000
+#define OID_TAPI_INFO 0x07000000
+
+//
+// idd polling timer value
+//
+#define IDD_POLL_T 25 // 25ms polling frequency (msec)
+
+//
+// cm polling timer
+//
+#define CM_POLL_T 1000 /* 1 second timer */
+
+//
+// mtl polling timer
+//
+#define MTL_POLL_T 25 // 25 ms timer
+
+//
+// flag to indicate this is not a beginning buffer
+//
+#define H_TX_N_BEG 0x8000
+#define H_RX_N_BEG 0x8000
+
+//
+// flag to indicate this is not an ending buffer
+//
+#define H_TX_N_END 0x4000
+#define H_RX_N_END 0x4000
+
+//
+// flag to cause an immediate send of queued tx buffers
+//
+#define H_TX_FLUSH 0x2000
+
+//
+// masks off tx flags to leave the tx length
+//
+#define H_TX_LEN_MASK 0x01FF
+#define H_RX_LEN_MASK 0x01FF
+
+//
+// mask off length leaving rx flags
+//
+#define RX_FLAG_MASK 0xF000
+
+//
+// mask off length and fragment indicator leaving tx flags
+//
+#define TX_FLAG_MASK 0xE000
+
+//
+// indicator that this tx is actually a fragment
+//
+#define TX_FRAG_INDICATOR 0x1000
+
+//
+// states for receive ppp state machine
+//
+#define RX_BEGIN 0
+#define RX_MIDDLE 1
+#define RX_END 2
+
+#ifdef DBG
+//
+// states for tx ppp state machine
+//
+#define TX_BEGIN 0
+#define TX_MIDDLE 1
+#define TX_END 2
+#endif
+
+//
+// idp tx and rx lengths
+//
+#define IDP_MAX_TX_LEN 280
+#define IDP_MAX_RX_LEN 280
+
+//
+// Idd frame type defines
+//
+#define IDD_FRAME_PPP 1 /* raw hdlc frames */
+#define IDD_FRAME_DKF 2 /* dror encapsulated frames */
+#define IDD_FRAME_DONTCARE 4 /* No data can pass yet */
+#define IDD_FRAME_DETECT 8 /* detect bchannel framing */
+
+//
+// ADP Stuff
+//
+
+//
+// ADP Register Defines
+//
+#define ADP_REG_ID 0
+#define ADP_REG_CTRL 1
+#define ADP_REG_ADDR_LO 2
+#define ADP_REG_ADDR_MID 3
+#define ADP_REG_ADDR_HI 4
+#define ADP_REG_DATA 5
+#define ADP_REG_DATA_INC 6
+
+//
+// ADP_REG_ID Bits
+//
+#define ADP_BT_ADP1 0xA1
+
+//
+// ADP_REG_CTRL Bits
+//
+#define ADP_RESET_BIT 0x80 // R/W 1 - Holds Adapter in reset
+#define ADP_PIRQ_BIT 0x40 // R 1 - Adapter to PC Interrupt Active
+ // W 1 - Clear Adapter to PC Interrupt
+#define ADP_AIRQ_BIT 0x20 // W 1 - PC to Adapter Interrupt Active
+ // R 0 - PC to Adapter Interrupt seen
+#define ADP_HLT_BIT 0x10 // R/W 1 - Holds Adapter in halt
+#define ADP_PIRQEN_BIT 0x08 // R/W 1 - Enables Adapter to PC Interrupt
+#define ADP_INT_SEL_BITS 0x07 // R/W Adapter to PC Interrupt select
+ // Code IRQ
+ // 000 0 (Disabled)
+ // 001 3
+ // 010 5
+ // 011 7
+ // 100 10
+ // 101 11
+ // 110 12
+ // 111 15
+
+//
+// ADP_REG_ADDR_LO Bits
+//
+// R/W Adapter Memory Address Bits A0..A7
+
+//
+// ADP_REG_ADDR_MID Bits
+//
+// R/W Adapter Memory Address Bits A8..A15
+
+//
+// ADP_REG_ADDR_HI Bits
+//
+// R/W Adapter Memory Address Bits A16..A23
+
+//
+// ADP_REG_DATA Bits
+//
+// R/W Adapter Memory Data Bits D0..D7
+// The 24 bit adapter memory address pointer remains constant
+// after each access to the data register.
+
+//
+// ADP_REG_DATA_INC Bits
+//
+// R/W Adapter Memory Data Bits D0..D7
+// The 24 bit adapter memory address pointer increments by one
+// after each access to the data register.
+
+//
+// Maxium Adapter RAM Size
+//
+#define ADP_RAM_SIZE 0x40000L
+
+//
+// Offset to message to PC pending status windows
+//
+#define ADP_STS_WINDOW 0x500L
+
+//
+// Offset to PC to adapter command window
+//
+#define ADP_CMD_WINDOW 0x510L
+
+//
+// Offset to adapter enviornment window
+//
+#define ADP_ENV_WINDOW 0x540L
+
+//
+// Offset to adapter NVRAM window (copy in adapter memory)
+//
+#define ADP_NVRAM_WINDOW 0x940L
+
+//
+// some Adp bin file stuff
+//
+#define ADP_BIN_BLOCK_SIZE 256
+#define ADP_BIN_FORMAT 1
+
+//
+// Adp Status
+//
+typedef struct
+{
+ UCHAR ReceiveStatus; // 0
+ UCHAR Reserved1; // 1
+ UCHAR MajorVersion; // 2
+ UCHAR MinorVersion; // 3
+ ULONG HeartBeat; // 4
+ ULONG IdleCount; // 8
+ USHORT AbortReason; // 12
+ USHORT SpuriousInterrupt; // 14
+} ADP_STATUS;
+
+//
+// Adp bin file header
+//
+typedef struct
+{
+ USHORT Format;
+ USHORT BlockCount;
+ ULONG ImageSize;
+}ADP_BIN_HEADER;
+
+//
+// Adp bin file data block
+//
+typedef struct
+{
+ ULONG Address;
+ UCHAR Data[ADP_BIN_BLOCK_SIZE];
+}ADP_BIN_BLOCK;
+
+//
+// NVRAM stuff
+//
+#define ADP_NVRAM_MAX 64
+
+typedef struct
+{
+ USHORT NVRamImage[ADP_NVRAM_MAX];
+}ADP_NVRAM;
+
+//
+// IDP Stuff
+//
+
+#define IDP_STS_WINDOW 0x800
+#define IDP_CMD_WINDOW 0x810
+#define IDP_ENV_WINDOW 0x910
+#define IDP_RAM_PAGE_SIZE 0x4000
+
+#endif /* _MYTYPES_ */
+
diff --git a/private/ntos/ndis/pcimac/mytypes.h b/private/ntos/ndis/pcimac/mytypes.h
new file mode 100644
index 000000000..c54295e4f
--- /dev/null
+++ b/private/ntos/ndis/pcimac/mytypes.h
@@ -0,0 +1,39 @@
+#ifndef _MYTYPES_
+#define _MYTPYES_
+
+#ifndef BOOL
+typedef int BOOL;
+#endif
+
+#ifndef DWORD
+typedef ULONG DWORD;
+#endif
+
+#ifndef WORD
+typedef USHORT WORD;
+#endif
+
+#ifndef BYTE
+typedef UCHAR BYTE;
+#endif
+
+#ifndef NOMINMAX
+
+#ifndef MAX
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#endif /* NOMINMAX */
+
+#define MAKEWORD(a, b) ((WORD)(((BYTE)(a)) | ((WORD)((BYTE)(b))) << 8))
+#define MAKELONG(a, b) ((LONG)(((WORD)(a)) | ((DWORD)((WORD)(b))) << 16))
+#define LOWORD(l) ((WORD)(l))
+#define HIWORD(l) ((WORD)(((DWORD)(l) >> 16) & 0xFFFF))
+#define LOBYTE(w) ((BYTE)(w))
+#define HIBYTE(w) ((BYTE)(((WORD)(w) >> 8) & 0xFF))
+
+#endif /* _MYTYPES_ */
diff --git a/private/ntos/ndis/pcimac/opcodes.h b/private/ntos/ndis/pcimac/opcodes.h
new file mode 100644
index 000000000..3393f7a79
--- /dev/null
+++ b/private/ntos/ndis/pcimac/opcodes.h
@@ -0,0 +1,152 @@
+/*
+ * OPCODES.H - This file defines opcodes for messages of K_MSG type
+ *
+ * opcodes are assigned to a specific module ans are a 16 bit quantity.
+ * upper 8 bits are designated as the module name. lower 8 bits are a
+ * running index of the messages within a module.
+ */
+
+#ifndef _OPCODES_
+#define _OPCODES_
+
+/* a general purpose macro to extract module name off an opcode */
+#define MOD_NAME(_op) (_op & 0xFF00)
+
+/* module names are defined here */
+#define DCH_MOD 0x100
+#define LAP_MOD 0x200
+#define LAPD_MOD 0x300
+#define Q931_MOD 0x400
+#define MDL_MOD 0x500
+#define UART_MOD 0x600
+#define SER_MOD 0x700
+#define HDLC_MOD 0x800
+#define CMD_MOD 0x900
+
+/* the different modules are defined here */
+#define DCH(_op) (_op | DCH_MOD) /* d channel control */
+#define LAP(_op) (_op | LAP_MOD) /* lap sub-protocol */
+#define LAPD(_op) (_op | LAPD_MOD) /* lap for d channel */
+#define Q931(_op) (_op | Q931_MOD) /* q931 network prot */
+#define MDL(_op) (_op | MDL_MOD) /* mdl protocol */
+#define UART(_op) (_op | UART_MOD) /* uart device driver */
+#define SER(_op) (_op | SER_MOD) /* serial channel device*/
+#define HDLC(_op) (_op | HDLC_MOD) /* hdlc formatter */
+#define CMD(_op) (_op | CMD_MOD) /* command module */
+
+
+/* d channel messages */
+#define DCH_ACT_RQ DCH(1) /* ph activation rq */
+#define DCH_DEACT_RQ DCH(2) /* ph deactivation rq */
+#define DCH_BCH_EN DCH(3) /* enable bch tx/rx */
+#define DCH_BCH_DIS DCH(4) /* disable bch tx/rx */
+#define DCH_FST_IND DCH(5) /* Fx state chg ind */
+#define DCH_DATA_RQ DCH(6) /* request for data send */
+#define DCH_DATA_IND DCH(7) /* new data indication */
+#define DCH_ASSOC_RQ DCH(8) /* assoc tei/sapi with mbx */
+#define DCH_DEASSOC_RQ DCH(9) /* deassoc tei/sapi from mbx */
+#define DCH_ASSOC_CNF DCH(10) /* assoc has succ */
+#define DCH_ASSOC_ERR DCH(11) /* assoc has failed */
+
+/* lap sub-protocol messages */
+#define LAP_MAKE_RQ LAP(1) /* make a new DLC */
+#define LAP_KILL_RQ LAP(2) /* kill a DLC */
+#define LAP_EST_RQ LAP(3) /* establish multi frame rq */
+#define LAP_REL_RQ LAP(4) /* release multi frame request */
+#define LAP_DATA_RQ LAP(5) /* send data request (ack info) */
+#define LAP_UI_RQ LAP(6) /* send unack info request */
+#define LAP_XID_RQ LAP(7) /* send XID info */
+#define LAP_T200_EXP LAP(8) /* internal: t200 expired */
+#define LAP_T203_EXP LAP(9) /* internal: t203 expired */
+#define LAP_QUEUED_UP LAP(10) /* internal: I frame queued up */
+#define LAP_SET_BUSY LAP(11) /* internal: set own busy */
+#define LAP_RESET_BUSY LAP(12) /* internal: reset own busy */
+#define LAP_ACK_PEND LAP(13) /* internal: ack pending */
+#define LAP_EST_IND LAP(14) /* MF establish, other side init*/
+#define LAP_EST_CNF LAP(15) /* MF establish, this side init */
+#define LAP_REL_IND LAP(16) /* MF released, other side init */
+#define LAP_REL_CNF LAP(17) /* MF released, this side init */
+#define LAP_DATA_IND LAP(18) /* data received indication */
+#define LAP_UI_IND LAP(19) /* unack info received ind */
+#define LAP_XID_IND LAP(20) /* XID received indication */
+#define LAP_ERR_IND LAP(21) /* error indication */
+#define LAP_PH_DATA_RQ LAP(22) /* send data down ph */
+#define LAP_PH_DATA_IND LAP(23) /* received data from ph */
+
+/* lap for d channel messages */
+#define LAPD_EST_RQ LAPD(1) /* establish dlc request */
+#define LAPD_EST_CNF LAPD(2) /* establish confirmed */
+#define LAPD_REL_RQ LAPD(3) /* release dlc request */
+#define LAPD_REL_IND LAPD(4) /* dlc release by other side */
+#define LAPD_REL_CNF LAPD(5) /* release confirmed */
+#define LAPD_PROC_IND LAPD(6) /* proceeding indication */
+#define LAPD_DATA_RQ LAPD(7) /* request to send data */
+#define LAPD_DATA_IND LAPD(8) /* new data indication */
+#define LAPD_ERROR_IND LAPD(9) /* error indication */
+
+/* q931 messages */
+#define Q931_EST_RQ Q931(1) /* outgoing conn request */
+#define Q931_EST_IND Q931(2) /* incoming oconn indication */
+#define Q931_EST_CNF Q931(3) /* outgoing conn confirmed */
+#define Q931_EST_RSP Q931(4) /* response to incoming conn */
+#define Q931_REL_RQ Q931(5) /* teardown conn reqeust */
+#define Q931_REL_IND Q931(6) /* teardown indicated by remote */
+#define Q931_REL_CNF Q931(7) /* teardown confired */
+#define Q931_REL_RSP Q931(8) /* respose to teardown */
+#define Q931_DATA_RQ Q931(9) /* send data on a conneciton */
+#define Q931_DATA_IND Q931(10) /* new data received on conn */
+#define Q931_TIMER_EXP Q931(11) /* internal: timer expired */
+#define Q931_RESTART_RQ Q931(12) /* request for line restart */
+#define Q931_RESTART_IND Q931(13) /* indication that line restarts*/
+#define Q931_RESTART_CNF Q931(14) /* confirmation of line restart */
+#define Q931_ERROR_IND Q931(15) /* error indcation */
+#define Q931_CID_IND Q931(16) /* cid indication */
+#define Q931_STATE_IND Q931(17) /* state transition indication */
+#define Q931_ELEM_RQ Q931(18) /* requesting elem notification */
+#define Q931_ELEM_IND Q931(19) /* element indication */
+#define Q931_TSPID_EXP Q931(20) /* internal: spid timer expired */
+#define Q931_P_STATE_IND Q931(21) /* protocol state indications */
+#define Q931_CAN_TU10_RQ Q931(22) /* cancel U10 deadman timer */
+#define Q931_EST_IGNORE Q931(23) /* cm code will ignore this new call */
+
+/* managment data link (mdl) messages */
+#define MDL_ASSIGN_RQ MDL(1) /* assign tei request */
+#define MDL_ASSIGN_CNF MDL(2) /* assign confirmed */
+#define MDL_REMOVE_RQ MDL(3) /* remove tei request */
+#define MDL_REMOVE_IND MDL(4) /* remove tei indicated */
+#define MDL_REMOVE_CNF MDL(5) /* remove tei confirmed */
+#define MDL_ERROR_IND MDL(6) /* error in mdl procedure */
+#define MDL_T202_EXP MDL(7) /* internal: T202 expired */
+
+/* uart device driver */
+#define UART_DATA_RQ UART(1) /* send bytes request */
+#define UART_DATA_IND UART(2) /* recieved bytes indication */
+
+/* serial channel device driver */
+#define SER_CONN_RX SER(1) /* connect receiver */
+#define SER_CONN_TX SER(2) /* connect transmitter */
+#define SER_DISC_RX SER(3) /* disconnect receiver */
+#define SER_DISC_TX SER(4) /* disconnect transmitter */
+
+/* hdlc formatter module */
+#define HDLC_CONN_RX HDLC(1) /* connect receiver */
+#define HDLC_CONN_TX HDLC(2) /* connect transmitter */
+#define HDLC_DISC_RX HDLC(3) /* disconnect receiver */
+#define HDLC_DISC_TX HDLC(4) /* disconnect transmitter */
+
+/* command module */
+#define CMD_TRC_ON CMD(1) /* turn dchan trace on */
+#define CMD_TRC_OFF CMD(2) /* turn dchan trace off */
+#define CMD_BCHAN_OFF CMD(3) /* turn transmission off */
+#define CMD_BCHAN_HDLC CMD(4) /* turn hdlc on a channel */
+#define CMD_BCHAN_56 CMD(5) /* force channel to run 7 bits */
+#define CMD_BCHAN_VOICE CMD(6) /* voice mode b channel */
+#define CMD_ENV_DEF CMD(7) /* env variable defined */
+#define CMD_ENV_UNDEF CMD(8) /* env variable undefined */
+#define CMD_GO CMD(9) /* start execution */
+#define CMD_LOOPBACK CMD(10) /* channel loopback control */
+#define CMD_TRACE_MASK CMD(11) /* set trace/debug mask */
+#define CMD_DUMP_PARAM CMD(12) /* dump parameter block */
+#define CMD_COMPRESS CMD(13) // control B channel compression
+
+#endif /* _OPCODES_ */
diff --git a/private/ntos/ndis/pcimac/pcimac.c b/private/ntos/ndis/pcimac/pcimac.c
new file mode 100644
index 000000000..0df476f94
--- /dev/null
+++ b/private/ntos/ndis/pcimac/pcimac.c
@@ -0,0 +1,2071 @@
+//
+// Pcimac.c - Main file for pcimac miniport wan driver
+//
+//
+//
+//
+//#include <ntddk.h>
+//#include <ntddndis.h>
+#include <ndis.h>
+//#include <ndismini.h>
+#include <ndiswan.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <opcodes.h>
+#include <disp.h>
+#include <adapter.h>
+#include <util.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+#include <tapioid.h>
+#include <res.h>
+#include <trc.h>
+#include <io.h>
+
+/* driver global vars */
+DRIVER_BLOCK Pcimac;
+
+/* store location for prev. ioctl handler */
+NTSTATUS (*PrevIoctl)(DEVICE_OBJECT* DeviceObject, IRP* Irp) = NULL;
+
+/* forward for external name manager */
+VOID BindName(ADAPTER *Adapter, BOOL create);
+
+//VOID RegistryInit (VOID);
+//VOID NdisTapiRequest(PNDIS_STATUS, NDIS_HANDLE, PNDIS_REQUEST);
+
+ULONG
+GetBaseConfigParams(
+ CONFIGPARAM *ConfigParam,
+ CHAR *Key
+ );
+
+
+ULONG
+GetLineConfigParams(
+ CONFIGPARAM *ConfigParam,
+ ULONG LineNumber,
+ CHAR *Key
+ );
+
+ULONG
+GetLTermConfigParams(
+ CONFIGPARAM *ConfigParam,
+ ULONG LineNumber,
+ ULONG LTermNumber,
+ CHAR *Key
+ );
+
+VOID
+IdpGetEaddrFromNvram(
+ IDD *idd,
+ CM *cm,
+ USHORT Line,
+ USHORT LineIndex
+ );
+
+VOID
+AdpGetEaddrFromNvram(
+ IDD *idd,
+ CM *cm,
+ USHORT Line,
+ USHORT LineIndex
+ );
+
+//
+// externals
+//
+extern IDD* IddTbl[];
+
+/* driver entry point */
+NTSTATUS
+DriverEntry(
+ DRIVER_OBJECT *DriverObject,
+ UNICODE_STRING *RegistryPath
+ )
+{
+ ULONG RetVal, n, m;
+
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ NDIS_HANDLE NdisWrapperHandle;
+
+ NDIS_WAN_MINIPORT_CHARACTERISTICS MiniportChars;
+ //
+ // Used for debugging at init time only
+ //
+// DbgBreakPoint();
+
+ NdisZeroMemory(&Pcimac, sizeof(DRIVER_BLOCK));
+
+ /* initialize ndis wrapper */
+ NdisMInitializeWrapper(&NdisWrapperHandle, DriverObject, RegistryPath, NULL);
+
+ /* initialize debug support */
+ D_LOG(D_ALWAYS, ("PCIMAC WanMiniport NT Driver, Copyright Digi Intl. Inc, 1992-1994"));
+ D_LOG(D_ALWAYS, ("Version 2.0.0 - Dror Kessler, Tony Bell"));
+ D_LOG(D_ALWAYS, ("DriverObject: 0x%x", DriverObject));
+ D_LOG(D_ALWAYS, ("RegisteryPath: 0x%x", RegistryPath));
+ D_LOG(D_ALWAYS, ("WrapperHandle: 0x%x", NdisWrapperHandle));
+
+ Pcimac.NdisWrapperHandle = NdisWrapperHandle;
+
+ NdisAllocateSpinLock (&Pcimac.lock);
+
+ /* initialize classes */
+ if ((RetVal = idd_init()) != IDD_E_SUCC)
+ goto exit_idd_error;
+
+ if ((RetVal = cm_init()) != CM_E_SUCC)
+ goto exit_cm_error;
+
+ if ((RetVal = res_init()) != RES_E_SUCC)
+ goto exit_res_error;
+
+ NdisZeroMemory(&MiniportChars,
+ sizeof(NDIS_MINIPORT_CHARACTERISTICS));
+
+ MiniportChars.MajorNdisVersion = NDIS_MAJOR_VER;
+ MiniportChars.MinorNdisVersion = NDIS_MINOR_VER;
+ MiniportChars.Reserved = NDIS_USE_WAN_WRAPPER;
+ MiniportChars.CheckForHangHandler = PcimacCheckForHang;
+ MiniportChars.DisableInterruptHandler = NULL;
+ MiniportChars.EnableInterruptHandler = NULL;
+ MiniportChars.HaltHandler = PcimacHalt;
+ MiniportChars.HandleInterruptHandler = NULL;
+ MiniportChars.InitializeHandler = PcimacInitialize;
+ MiniportChars.ISRHandler = NULL;
+ MiniportChars.QueryInformationHandler = PcimacSetQueryInfo;
+ MiniportChars.ReconfigureHandler = PcimacReconfigure;
+ MiniportChars.ResetHandler = PcimacReset;
+ MiniportChars.SendHandler = (WM_SEND_HANDLER)PcimacSend;
+ MiniportChars.SetInformationHandler = PcimacSetQueryInfo;
+ MiniportChars.TransferDataHandler = NULL;
+
+ NdisMRegisterMiniport (NdisWrapperHandle,
+ (PNDIS_MINIPORT_CHARACTERISTICS)&MiniportChars,
+ sizeof(MiniportChars));
+
+ if (!EnumAdaptersInSystem())
+ goto exit_event_error;
+
+ /* initialize ioctl filter */
+ PrevIoctl = DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL];
+ DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PcimacIoctl;
+
+ //
+ // get an adapter to create a binding I/O name binding to
+ //
+ for (n = 0; n < MAX_ADAPTERS_IN_SYSTEM; n++)
+ {
+ ADAPTER *Adapter = Pcimac.AdapterTbl[n];
+
+ if (Adapter)
+ {
+ /* create external name binding */
+ BindName(Adapter, TRUE);
+ break;
+ }
+ }
+
+ //
+ // turn off the trace on all idd's in the system
+ //
+ for (n = 0; n < MAX_ADAPTERS_IN_SYSTEM; n++)
+ {
+ ADAPTER *Adapter = Pcimac.AdapterTbl[n];
+ IDD_MSG msg;
+
+ if (Adapter)
+ {
+ for (m = 0; m < MAX_IDD_PER_ADAPTER; m++)
+ {
+ IDD *idd = Adapter->IddTbl[m];
+
+ if (idd)
+ {
+ /* issue idd command to stop trace */
+ NdisZeroMemory(&msg, sizeof(msg));
+ msg.opcode = CMD_TRC_OFF;
+ idd_send_msg(idd, &msg, IDD_PORT_CMD_TX, NULL, NULL);
+ }
+ }
+ }
+ }
+
+ D_LOG(D_EXIT, ("DriverEntry: exit success!"));
+
+ /* if successful here, done */
+ return(STATUS_SUCCESS);
+
+exit_event_error:
+ D_LOG(D_ALWAYS, ("EventError!"));
+ res_term();
+
+exit_res_error:
+ D_LOG(D_ALWAYS, ("ResError!"));
+ cm_term();
+
+exit_cm_error:
+exit_idd_error:
+ D_LOG(D_ALWAYS, ("CmIddError!"));
+
+ NdisFreeSpinLock(&Pcimac.lock);
+
+ NdisTerminateWrapper(Pcimac.NdisWrapperHandle, NULL);
+ return(NDIS_STATUS_FAILURE);
+}
+
+BOOLEAN
+PcimacCheckForHang(
+ NDIS_HANDLE AdapterContext
+ )
+{
+ ULONG n, IdpCounter = 0;
+ ADAPTER *Adapter = (ADAPTER *)AdapterContext;
+ BOOLEAN ReturnStatus = FALSE;
+
+ D_LOG(D_ENTRY, ("PcimacCheckForHang: Adapter: 0x%p", AdapterContext));
+
+ //
+ // for all idd's that belong to this adpater
+ //
+ for (n = 0; Adapter->IddTbl[n] && n < MAX_IDD_PER_ADAPTER; n++)
+ {
+ IDD *idd = Adapter->IddTbl[n];
+
+ //
+ // see if this idd is dead
+ //
+ if (!idd || idd->state == IDD_S_SHUTDOWN)
+ continue;
+
+ IdpCounter++;
+ }
+
+ //
+ // if there are no idps alive on this adapter tell the wrapper
+ //
+ if (!IdpCounter)
+ ReturnStatus = TRUE;
+
+ D_LOG(D_ALWAYS, ("PcimacCheckForHang: ReturnStatus: %d", ReturnStatus));
+
+ return(ReturnStatus);
+}
+
+VOID
+PcimacDisableInterrupts(
+ NDIS_HANDLE AdapterContext
+ )
+{
+ D_LOG(D_ENTRY, ("PcimacDisableInterrupts: Adapter: 0x%p", AdapterContext));
+
+ //
+ // if i used interrupts i should disable them for this
+ // adapter
+ //
+}
+
+VOID
+PcimacEnableInterrupts(
+ NDIS_HANDLE AdapterContext
+ )
+{
+ D_LOG(D_ENTRY, ("PcimacEnableInterrupts: Adapter: 0x%p", AdapterContext));
+ //
+ // if i used interrupts i should enable them for this
+ // adapter
+ //
+}
+
+VOID
+PcimacHalt(
+ NDIS_HANDLE AdapterContext
+ )
+{
+ ULONG n;
+ ADAPTER *Adapter = (ADAPTER*)AdapterContext;
+
+ D_LOG(D_ENTRY, ("PcimacHalt: Adapter: 0x%p", AdapterContext));
+ DbgPrint("PcimacHalt: Adapter: 0x%p\n", AdapterContext);
+
+ //
+ // destroy cm objects
+ //
+ for (n = 0; n < MAX_CM_PER_ADAPTER; n++)
+ {
+ CM *cm = Adapter->CmTbl[n];
+
+ Adapter->CmTbl[n] = NULL;
+
+ if (cm)
+ cm_destroy(cm);
+ }
+
+ //
+ // destroy mtl objects
+ //
+ for (n = 0; n < MAX_MTL_PER_ADAPTER; n++)
+ {
+ MTL *mtl = Adapter->MtlTbl[n];
+
+ Adapter->MtlTbl[n] = NULL;
+
+ if (mtl)
+ mtl_destroy(mtl);
+ }
+
+ //
+ // destroy idd objects
+ //
+ for (n = 0; n < MAX_IDD_PER_ADAPTER; n++)
+ {
+ IDD *idd = (IDD*)Adapter->IddTbl[n];
+
+ Adapter->IddTbl[n] = NULL;
+
+ if (idd)
+ idd_destroy(idd);
+ }
+
+ /* delete external name binding */
+ BindName(Adapter, FALSE);
+
+ //
+ // deregister adapter
+ //
+ AdapterDestroy(Adapter);
+}
+
+VOID
+PcimacHandleInterrupt(
+ NDIS_HANDLE AdapterContext
+ )
+{
+ D_LOG(D_ENTRY, ("PcimacHandleInterrupt: Adapter: 0x%p", AdapterContext));
+ //
+ // if i actually used interrupts i would service the
+ // adapters interrupt register and schedule someone to
+ // do some work
+ //
+}
+
+#pragma NDIS_INIT_FUNCTION(PcimacInitialize)
+
+NDIS_STATUS
+PcimacInitialize(
+ PNDIS_STATUS OpenErrorStatus,
+ PUINT SelectMediumIndex,
+ PNDIS_MEDIUM MediumArray,
+ UINT MediumArraySize,
+ NDIS_HANDLE AdapterHandle,
+ NDIS_HANDLE WrapperConfigurationContext)
+{
+ ADAPTER *Adapter;
+ USHORT BoardType, NumberOfLines, NumberOfLTerms, BoardNumber;
+ ULONG BaseMem, BaseIO, n, m, l, IddStarted = 0;
+ PVOID VBaseMem, VBaseIO;
+ ANSI_STRING AnsiStr;
+ NDIS_STRING NdisStr;
+ CHAR DefName[128];
+ NDIS_STATUS RetVal = NDIS_STATUS_SUCCESS;
+ CONFIGPARAM ConfigParam;
+ NDIS_PHYSICAL_ADDRESS MemPhyAddr;
+ NDIS_PHYSICAL_ADDRESS HighestAcceptableMax = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
+
+ D_LOG(D_ENTRY, ("PcimacInitialize: AdapterHandle: 0x%x", AdapterHandle));
+
+ for (n = 0; n < MediumArraySize; n++)
+ if (MediumArray[n] == NdisMediumWan)
+ break;
+
+ if (n == MediumArraySize)
+ return(NDIS_STATUS_UNSUPPORTED_MEDIA);
+
+ *SelectMediumIndex = n;
+
+ //
+ // allocate control block for this adapter
+ //
+ NdisAllocateMemory((PVOID*)&Adapter,
+ sizeof(ADAPTER),
+ 0,
+ HighestAcceptableMax);
+ if ( !Adapter)
+ {
+ D_LOG(D_ALWAYS, ("PcimacInitiailize: Adapter memory allocate failed!"));
+ return (NDIS_STATUS_ADAPTER_NOT_FOUND);
+ }
+ D_LOG(D_ALWAYS, ("PcimacInitialize: Allocated an Adapter: 0x%p", Adapter));
+ NdisZeroMemory(Adapter, sizeof(ADAPTER));
+
+ //
+ // store adapter in global structure
+ //
+ for (n = 0; n < MAX_ADAPTERS_IN_SYSTEM; n++)
+ {
+ if (!Pcimac.AdapterTbl[n])
+ {
+ Pcimac.AdapterTbl[n] = Adapter;
+ Pcimac.NumberOfAdaptersInSystem++;
+ BoardNumber = (USHORT)n;
+ break;
+ }
+ }
+
+ //
+ // if no room destroy and leave
+ //
+ if (n >= MAX_ADAPTERS_IN_SYSTEM)
+ {
+ D_LOG(D_ALWAYS, ("PcimacInitialize: No room in Adapter Table"));
+ NdisFreeMemory(Adapter, sizeof(ADAPTER), 0);
+ return (NDIS_STATUS_ADAPTER_NOT_FOUND);
+ }
+
+ //
+ // set in driver access lock
+ //
+// NdisAllocateSpinLock (&Adapter->InDriverLock);
+
+
+ //
+ // store adapter handle
+ //
+ Adapter->Handle = AdapterHandle;
+
+ //
+ // initialize adapter specific timers
+ //
+ NdisMInitializeTimer(&Adapter->IddPollTimer, Adapter->Handle, IddPollFunction, Adapter);
+ NdisMSetTimer(&Adapter->IddPollTimer, IDD_POLL_T);
+
+ NdisMInitializeTimer(&Adapter->MtlPollTimer, Adapter->Handle, MtlPollFunction, Adapter);
+ NdisMSetTimer(&Adapter->MtlPollTimer, MTL_POLL_T);
+
+ NdisMInitializeTimer(&Adapter->CmPollTimer, Adapter->Handle, CmPollFunction, Adapter);
+ NdisMSetTimer(&Adapter->CmPollTimer, CM_POLL_T);
+
+ ConfigParam.AdapterHandle = AdapterHandle;
+
+ //
+ // Open registry
+ //
+ NdisOpenConfiguration(&RetVal, &ConfigParam.ConfigHandle, WrapperConfigurationContext);
+
+ if (RetVal != NDIS_STATUS_SUCCESS)
+ {
+ D_LOG(D_ALWAYS, ("PcimacInitialize: Error Opening Config: RetVal: 0x%x", RetVal));
+ NdisWriteErrorLogEntry (AdapterHandle,
+ NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER,
+ 1,
+ 0);
+ goto InitErrorExit;
+ }
+
+ //
+ // read registry board type
+ //
+ ConfigParam.StringLen = sizeof(ConfigParam.String);
+ ConfigParam.ParamType = NdisParameterString;
+ ConfigParam.MustBePresent = TRUE;
+ if (!GetBaseConfigParams(&ConfigParam, PCIMAC_KEY_BOARDTYPE))
+ goto InitErrorExit;
+
+ if (!strncmp(ConfigParam.String, "PCIMAC4", 7))
+ BoardType = IDD_BT_PCIMAC4;
+ else if (!strncmp(ConfigParam.String, "PCIMAC - ISA", 12))
+ BoardType = IDD_BT_PCIMAC;
+ else if (!strncmp(ConfigParam.String, "PCIMAC - MC", 11))
+ BoardType = IDD_BT_MCIMAC;
+ else if (!strncmp(ConfigParam.String, "DATAFIRE - ISA1U", 16))
+ BoardType = IDD_BT_DATAFIREU;
+ else
+ {
+ D_LOG(D_ALWAYS, ("PcimacInitialize: Invalid BoardType: %s", ConfigParam.String));
+ goto InitErrorExit;
+ }
+
+ //
+ // save board type
+ //
+ Adapter->BoardType = BoardType;
+
+ //
+ // set miniport attributes (only isa for now)
+ //
+ NdisMSetAttributes(AdapterHandle, Adapter, FALSE, NdisInterfaceIsa);
+
+ //
+ // read registry base io
+ //
+ ConfigParam.StringLen = 0;
+ ConfigParam.ParamType = NdisParameterInteger;
+ ConfigParam.MustBePresent = TRUE;
+ if (!GetBaseConfigParams(&ConfigParam,PCIMAC_KEY_BASEIO))
+ goto InitErrorExit;
+
+ BaseIO = ConfigParam.Value;
+
+ //
+ // save base I/O for this adapter
+ //
+ Adapter->BaseIO = BaseIO;
+
+ //
+ // register I/O range
+ //
+ RetVal = NdisMRegisterIoPortRange(&VBaseIO,
+ AdapterHandle,
+ BaseIO,
+ 8);
+
+ if (RetVal != NDIS_STATUS_SUCCESS)
+ {
+ NdisWriteErrorLogEntry(AdapterHandle,
+ NDIS_ERROR_CODE_BAD_IO_BASE_ADDRESS,
+ 0);
+ goto InitErrorExit;
+ }
+ Adapter->VBaseIO = VBaseIO;
+
+ if (BoardType != IDD_BT_DATAFIREU)
+ {
+ //
+ // read registry base mem
+ //
+ ConfigParam.StringLen = 0;
+ ConfigParam.ParamType = NdisParameterInteger;
+ ConfigParam.MustBePresent = TRUE;
+ if (!GetBaseConfigParams(&ConfigParam, PCIMAC_KEY_BASEMEM))
+ goto InitErrorExit;
+
+ BaseMem = ConfigParam.Value;
+
+ //
+ // save base memory for this adapter
+ //
+ Adapter->BaseMem = BaseMem;
+
+ //
+ // since our adapters can share the same base memory we need to
+ // see if we have already mapped this memory range. if we have already
+ // mapped the memory once then save that previous value
+ //
+ for (n = 0; n < MAX_ADAPTERS_IN_SYSTEM; n++)
+ {
+ ADAPTER *PreviousAdapter = Pcimac.AdapterTbl[n];
+
+ //
+ // if this is a valid adapter, this is not the current adapter, and
+ // this adapter has the same shared memory address as the current
+ // adapter, then use this adapters mapped memory for the current
+ // adpaters mapped memory
+ //
+ if (PreviousAdapter &&
+ (PreviousAdapter != Adapter) &&
+ (PreviousAdapter->BaseMem == Adapter->BaseMem))
+ {
+ VBaseMem = PreviousAdapter->VBaseMem;
+ break;
+ }
+ }
+
+ //
+ // if we did not find a previous adapter with this memory range
+ // we need to map this memory range
+ //
+ if (n >= MAX_ADAPTERS_IN_SYSTEM)
+ {
+ //
+ // map our physical memory into virtual memory
+ //
+ NdisSetPhysicalAddressHigh(MemPhyAddr, 0);
+ NdisSetPhysicalAddressLow(MemPhyAddr, BaseMem);
+
+ RetVal = NdisMMapIoSpace(&VBaseMem,
+ AdapterHandle,
+ MemPhyAddr,
+ 0x4000);
+
+ if (RetVal != NDIS_STATUS_SUCCESS)
+ {
+ NdisWriteErrorLogEntry(AdapterHandle,
+ NDIS_ERROR_CODE_RESOURCE_CONFLICT,
+ 0);
+ goto InitErrorExit;
+ }
+
+ Adapter->VBaseMem = VBaseMem;
+ }
+ }
+
+ //
+ // read registry name
+ //
+ NdisZeroMemory(ConfigParam.String, sizeof(ConfigParam.String));
+ ConfigParam.StringLen = sizeof(Adapter->Name);
+ ConfigParam.ParamType = NdisParameterString;
+ ConfigParam.MustBePresent = TRUE;
+ if (!GetBaseConfigParams(&ConfigParam, PCIMAC_KEY_BOARDNAME))
+ goto InitErrorExit;
+
+ NdisMoveMemory(Adapter->Name,
+ ConfigParam.String,
+ ConfigParam.StringLen);
+ //
+ // read the number of lines for this board
+ //
+ ConfigParam.StringLen = 0;
+ ConfigParam.ParamType = NdisParameterInteger;
+ ConfigParam.MustBePresent = TRUE;
+ if (!GetBaseConfigParams(&ConfigParam, PCIMAC_KEY_NUMLINES))
+ NumberOfLines = (BoardType == IDD_BT_PCIMAC4) ? 4 : 1;
+ else
+ NumberOfLines = (USHORT)ConfigParam.Value;
+
+ //
+ // for number of lines
+ //
+ for (n = 0; n < NumberOfLines; n++)
+ {
+ IDD *idd;
+
+ //
+ // Create idd object
+ //
+ if (idd_create(&idd, BoardType) != IDD_E_SUCC)
+ {
+ NdisWriteErrorLogEntry (AdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0);
+
+ goto InitErrorExit;
+ }
+
+ //
+ // store idd in idd table
+ //
+ for (l = 0; l < MAX_IDD_PER_ADAPTER; l++)
+ {
+ if (!Adapter->IddTbl[l])
+ {
+ Adapter->IddTbl[l] = idd;
+ break;
+ }
+ }
+
+ Adapter->NumberOfIddOnAdapter++;
+
+ //
+ // set idd physical base i/o and memory
+ //
+ idd->phw.base_io = BaseIO;
+ idd->phw.base_mem = BaseMem;
+
+ //
+ // set idd virtual base i/o and memory
+ //
+ idd->vhw.vbase_io = (ULONG)VBaseIO;
+ idd->vhw.vmem = VBaseMem;
+
+ //
+ // create an i/o resource manager for this idd
+ //
+ idd->res_io = res_create(RES_CLASS_IO, (ULONG)BaseIO);
+
+ //
+ // create a memory resource manager for this idd
+ //
+ idd->res_mem = res_create(RES_CLASS_MEM, (ULONG)BaseMem);
+ res_set_data(idd->res_mem, (ULONG)VBaseMem);
+
+ //
+ // save adapter handle
+ //
+ idd->adapter_handle = AdapterHandle;
+
+ //
+ // save the board number of this idd
+ //
+ idd->bnumber = BoardNumber;
+
+ //
+ // save the line number of this idd
+ //
+ idd->bline = (USHORT)n;
+
+ //
+ // save the board type that this idd belongs to
+ //
+ idd->btype = BoardType;
+
+ if(idd->CheckIO(idd))
+ {
+ NdisWriteErrorLogEntry(AdapterHandle,
+ NDIS_ERROR_CODE_BAD_IO_BASE_ADDRESS,
+ 0);
+ goto InitErrorExit;
+ }
+
+ //
+ // read registry line name
+ //
+ NdisZeroMemory(ConfigParam.String, sizeof(ConfigParam.String));
+ ConfigParam.StringLen = sizeof(idd->name);
+ ConfigParam.ParamType = NdisParameterString;
+ ConfigParam.MustBePresent = TRUE;
+ if (!GetLineConfigParams(&ConfigParam, n, PCIMAC_KEY_LINENAME))
+ goto InitErrorExit;
+
+ sprintf(idd->name, "%s-%s", Adapter->Name, ConfigParam.String);
+
+// NdisMoveMemory(idd->name,
+// ConfigParam.String,
+// ConfigParam.StringLen);
+
+ //
+ // read registry idp file name
+ //
+ NdisZeroMemory(ConfigParam.String, sizeof(ConfigParam.String));
+ ConfigParam.StringLen = sizeof(idd->phw.idp_bin);
+ ConfigParam.ParamType = NdisParameterString;
+ ConfigParam.MustBePresent = TRUE;
+ if (!GetLineConfigParams(&ConfigParam, n, PCIMAC_KEY_IDPFILENAME))
+ goto InitErrorExit;
+
+ NdisMoveMemory(idd->phw.idp_bin,
+ ConfigParam.String,
+ ConfigParam.StringLen);
+
+
+ //
+ // Try to open idp bin file
+ //
+ RtlInitAnsiString(&AnsiStr, idd->phw.idp_bin);
+
+ //
+ // allocate buffer and turn ansi to unicode
+ //
+ RtlAnsiStringToUnicodeString(&NdisStr, &AnsiStr, TRUE);
+
+ NdisOpenFile(&RetVal,
+ &idd->phw.fbin,
+ &idd->phw.fbin_len,
+ &NdisStr,
+ HighestAcceptableMax);
+
+ //
+ // free up unicode string buffer
+ //
+ RtlFreeUnicodeString(&NdisStr);
+
+ if (RetVal != NDIS_STATUS_SUCCESS)
+ {
+ NdisWriteErrorLogEntry(AdapterHandle,
+ NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
+ 0);
+ goto InitErrorExit;
+ }
+
+ //
+ // read registry switch style
+ //
+ NdisZeroMemory(ConfigParam.String, sizeof(ConfigParam.String));
+ ConfigParam.StringLen = 128;
+ ConfigParam.ParamType = NdisParameterString;
+ ConfigParam.MustBePresent = TRUE;
+ if (!GetLineConfigParams(&ConfigParam, n, PCIMAC_KEY_SWITCHSTYLE))
+ goto InitErrorExit;
+
+ //
+ // added to support the new switch styles
+ //
+ CmSetSwitchStyle(ConfigParam.String);
+
+ idd_add_def(idd, "q931.style", ConfigParam.String);
+
+ //
+ // read registry terminal management
+ //
+ NdisZeroMemory(ConfigParam.String, sizeof(ConfigParam.String));
+ ConfigParam.StringLen = 128;
+ ConfigParam.ParamType = NdisParameterString;
+ ConfigParam.MustBePresent = TRUE;
+ if (!GetLineConfigParams(&ConfigParam, n,
+ PCIMAC_KEY_TERMINALMANAGEMENT))
+ goto InitErrorExit;
+
+ idd_add_def(idd, "q931.tm", ConfigParam.String);
+
+ //
+ // read WaitForL3 value
+ //
+ NdisZeroMemory(ConfigParam.String, sizeof(ConfigParam.String));
+ ConfigParam.StringLen = 128;
+ ConfigParam.ParamType = NdisParameterString;
+ ConfigParam.MustBePresent = FALSE;
+ if (!GetLineConfigParams(&ConfigParam, n,
+ PCIMAC_KEY_WAITFORL3))
+ strcpy(ConfigParam.String, "5");
+
+ idd_add_def(idd, "q931.wait_l3", ConfigParam.String);
+
+ //
+ // read registry logical terminals
+ //
+ ConfigParam.StringLen = 0;
+ ConfigParam.ParamType = NdisParameterInteger;
+ ConfigParam.MustBePresent = TRUE;
+ if (!GetLineConfigParams(&ConfigParam, n, PCIMAC_KEY_NUMLTERMS))
+ goto InitErrorExit;
+
+ NumberOfLTerms = (USHORT)ConfigParam.Value;
+
+ if (NumberOfLTerms > 1)
+ idd_add_def(idd, "dual_q931", "any");
+
+ //
+ // store number of lterms that this idd has
+ //
+ idd->CallInfo.NumLTerms = NumberOfLTerms;
+
+ //
+ // for each logical terminal
+ //
+ for (l = 0; l < NumberOfLTerms; l++)
+ {
+ //
+ // read registry tei
+ //
+ NdisZeroMemory(ConfigParam.String, sizeof(ConfigParam.String));
+ ConfigParam.StringLen = 128;
+ ConfigParam.ParamType = NdisParameterString;
+ ConfigParam.MustBePresent = FALSE;
+ if (!GetLTermConfigParams(&ConfigParam, n, l, PCIMAC_KEY_TEI))
+ strcpy(ConfigParam.String, "127");
+
+ NdisZeroMemory(DefName, sizeof(DefName));
+ sprintf(DefName, "q931.%d.tei", l);
+ idd_add_def(idd, DefName, ConfigParam.String);
+
+ //
+ // read registry spid
+ //
+ NdisZeroMemory(ConfigParam.String, sizeof(ConfigParam.String));
+ ConfigParam.StringLen = 128;
+ ConfigParam.ParamType = NdisParameterString;
+ ConfigParam.MustBePresent = FALSE;
+ if (GetLTermConfigParams(&ConfigParam, n, l, PCIMAC_KEY_SPID))
+ {
+ CHAR TempVal[64];
+ ULONG i, j;
+
+ //
+ // remove any non digits except # & *
+ //
+ NdisZeroMemory(TempVal, sizeof(TempVal));
+
+ for (i = 0, j = 0; i < ConfigParam.StringLen; i++)
+ {
+ if ((ConfigParam.String[i] >= '0' && ConfigParam.String[i] <= '9') ||
+ ConfigParam.String[i] == '*' ||
+ ConfigParam.String[i] == '#')
+ {
+ TempVal[j++] = ConfigParam.String[i];
+ }
+ }
+
+ NdisZeroMemory(DefName, sizeof(DefName));
+ sprintf(DefName, "q931.%d.spid", l);
+ idd_add_def(idd, DefName, TempVal);
+ idd_add_def(idd, "q931.multipoint", "any");
+ }
+
+ //
+ // read registry address
+ //
+ NdisZeroMemory(ConfigParam.String, sizeof(ConfigParam.String));
+ ConfigParam.StringLen = 128;
+ ConfigParam.ParamType = NdisParameterString;
+ ConfigParam.MustBePresent = FALSE;
+ if (GetLTermConfigParams(&ConfigParam, n, l, PCIMAC_KEY_ADDRESS))
+ {
+ CHAR TempVal[64];
+ ULONG i, j;
+
+ //
+ // remove any non digits except # & *
+ //
+ NdisZeroMemory(TempVal, sizeof(TempVal));
+
+ for (i = 0, j = 0; i < ConfigParam.StringLen; i++)
+ {
+ if ((ConfigParam.String[i] >= '0' && ConfigParam.String[i] <= '9') ||
+ ConfigParam.String[i] == '*' ||
+ ConfigParam.String[i] == '#')
+ {
+ TempVal[j++] = ConfigParam.String[i];
+ }
+ }
+
+ NdisZeroMemory(DefName, sizeof(DefName));
+ sprintf(DefName, "q931.%d.addr", l);
+ idd_add_def(idd, DefName, TempVal);
+ }
+
+ //
+ // add code to read generic multistring at the lterm level
+ // Key is "LTermDefinitions" these will be added to
+ // the enviornment database
+ // each string will look like "name=value\0" should
+ // remove "=" and replace with '\0'
+ //
+ }
+
+ //
+ // add code to read generic multistring at the board level
+ // Key is "GenericDefines"
+ // each string will look like "name=value\0" should
+ // remove "=" and replace with '\0'
+ //
+ NdisZeroMemory(ConfigParam.String, sizeof(ConfigParam.String));
+ ConfigParam.StringLen = sizeof(ConfigParam.String);
+ ConfigParam.ParamType = NdisParameterMultiString;
+ ConfigParam.MustBePresent = FALSE;
+ if (GetBaseConfigParams(&ConfigParam, PCIMAC_KEY_GENERICDEFINES))
+ {
+ CHAR Name[50] = {0};
+ CHAR Value[50] = {0};
+ CHAR *StringPointer = ConfigParam.String;
+
+ while (strlen(StringPointer))
+ {
+ //
+ // copy the name part of the generic define
+ //
+ strcpy(Name, StringPointer);
+
+ D_LOG(D_ALWAYS, ("PcimacInitialize: GenericDefines: Name: %s", Name));
+ //
+ // push pointer over the name
+ //
+ StringPointer += strlen(StringPointer);
+
+ //
+ // get over the null character
+ //
+ StringPointer += 1;
+
+ //
+ // copy the value part of the generic define
+ //
+ strcpy(Value, StringPointer);
+ D_LOG(D_ALWAYS, ("PcimacInitialize: GenericDefines: Value: %s", Value));
+
+ idd_add_def(idd, Name, Value);
+
+ //
+ // push pointer over the value
+ //
+ StringPointer += strlen(StringPointer);
+
+ //
+ // get over the null character
+ //
+ StringPointer += 1;
+ }
+ }
+
+ //
+ // startup idd
+ //
+ if (idd_startup(idd) != IDD_E_SUCC)
+ {
+ NdisWriteErrorLogEntry(AdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 2,
+ (ULONG)idd->bnumber,
+ (ULONG)idd->bline);
+ idd_destroy(idd);
+ for (m = 0; m < MAX_IDD_PER_ADAPTER; m++)
+ if (Adapter->IddTbl[m] == idd)
+ Adapter->IddTbl[m] = NULL;
+
+ Adapter->NumberOfIddOnAdapter--;
+ continue;
+ }
+
+ //
+ // register handlers for idd
+ //
+ cm_register_idd(idd);
+
+ IddStarted++;
+ }
+
+ if (!IddStarted)
+ goto InitErrorExit;
+
+
+ for (n = 0; n < IddStarted; n++)
+ {
+ CM *cm;
+ MTL *mtl;
+ IDD *idd;
+
+ idd = Adapter->IddTbl[n];
+
+ //
+ // build two cm's and two mtl's per line
+ //
+ for (l = 0; l < 2; l++)
+ {
+ ULONG m;
+
+ //
+ // Allocate memory for cm object
+ //
+ if (cm_create(&cm, AdapterHandle) != CM_E_SUCC)
+ goto InitErrorExit;
+
+ for (m = 0; m < MAX_CM_PER_ADAPTER; m++)
+ {
+ if (!Adapter->CmTbl[m])
+ {
+ Adapter->CmTbl[m] = cm;
+ break;
+ }
+ }
+
+ //
+ // back pointer to adapter structure
+ //
+ cm->Adapter = Adapter;
+
+ //
+ // pointer to idd that belongs to this cm
+ //
+ cm->idd = idd;
+
+ //
+ // name cm object format: AdapterName-LineName-chan#
+ //
+ sprintf(cm->name,"%s-%d", idd->name, l);
+
+ //
+ // set local address, format: NetCard#-idd#-chan#
+ //
+ sprintf(cm->LocalAddress, "%d-%d-%d", atoi(&Adapter->Name[6]), (idd->bline * 2) + l, 0);
+
+ //
+ // get ethernet addresses for this cm
+ //
+ if(idd->btype == IDD_BT_DATAFIREU)
+ AdpGetEaddrFromNvram(idd, cm, (USHORT)n, (USHORT)l);
+ else
+ IdpGetEaddrFromNvram(idd, cm, (USHORT)n, (USHORT)l);
+
+ //
+ // Allocate memory for mtl object
+ //
+ if (mtl_create(&mtl, AdapterHandle) != MTL_E_SUCC)
+ goto InitErrorExit;
+
+ for (m = 0; m < MAX_MTL_PER_ADAPTER; m++)
+ {
+ if (!Adapter->MtlTbl[m])
+ {
+ Adapter->MtlTbl[m] = mtl;
+ break;
+ }
+ }
+
+ //
+ // back pointer to adapter structure
+ //
+ mtl->Adapter = Adapter;
+
+ //
+ // link between cm and mtl
+ //
+ cm->mtl = mtl;
+ mtl->cm = cm;
+ }
+ }
+
+ NdisCloseConfiguration(ConfigParam.ConfigHandle);
+
+ //
+ // stuff to work with conn wrapper without wan wrapper
+ //
+// NdisTapiRegisterProvider ((NDIS_HANDLE)Adapter, NdisTapiRequest);
+
+ return (NDIS_STATUS_SUCCESS);
+
+InitErrorExit:
+ NdisCloseConfiguration(ConfigParam.ConfigHandle);
+
+ //
+ // clean up all idd's allocated
+ //
+ for (l = 0; l < MAX_IDD_PER_ADAPTER; l++)
+ {
+ IDD *idd = Adapter->IddTbl[l];
+
+ //
+ // if memory has been mapped release
+ //
+ if (idd)
+ {
+ idd_destroy(idd);
+ Adapter->IddTbl[l] = NULL;
+ }
+ }
+
+ //
+ // clean up all cm's allocated
+ //
+ for (l = 0; l < MAX_CM_PER_ADAPTER; l++)
+ {
+ CM *cm = Adapter->CmTbl[l];
+
+ if (cm)
+ {
+ cm_destroy(cm);
+ Adapter->CmTbl[l] = NULL;
+ }
+ }
+
+ //
+ // clean up all mtl's allocated
+ //
+ for (l = 0; l < MAX_MTL_PER_ADAPTER; l++)
+ {
+ MTL *mtl = Adapter->MtlTbl[l];
+
+ if (mtl)
+ {
+ mtl_destroy(mtl);
+ Adapter->MtlTbl[l] = NULL;
+ }
+ }
+
+ //
+ // clean up adapter block allocated
+ //
+ AdapterDestroy(Adapter);
+
+ return (NDIS_STATUS_ADAPTER_NOT_FOUND);
+}
+
+VOID
+PcimacISR(
+ PBOOLEAN InterruptRecognized,
+ PBOOLEAN QueueMiniportHandleInterrupt,
+ NDIS_HANDLE AdapterContext
+ )
+{
+ D_LOG(D_ENTRY, ("PcimacISR: Adapter: 0x%p", AdapterContext));
+ //
+ // if i actually used interrupts i should check to see
+ // if the adapter generated the interrupt and set InterruptRecognized
+ // accordingly.
+ //
+ *InterruptRecognized = FALSE;
+
+ //
+ // if i actually used interrupts and this interrupt was mine i
+ // would schedule a dpc to occur
+ //
+ *QueueMiniportHandleInterrupt = FALSE;
+}
+
+//
+// to make conn wrapper stuff work without wan wrapper
+//
+//VOID
+//NdisTapiRequest(
+// PNDIS_STATUS Status,
+// NDIS_HANDLE NdisBindingHandle,
+// PNDIS_REQUEST NdisRequest
+// )
+//{
+//
+// *Status = PcimacSetQueryInfo(NdisBindingHandle,
+// NdisRequest->DATA.SET_INFORMATION.Oid,
+// NdisRequest->DATA.SET_INFORMATION.InformationBuffer,
+// NdisRequest->DATA.SET_INFORMATION.InformationBufferLength,
+// &NdisRequest->DATA.SET_INFORMATION.BytesRead,
+// &NdisRequest->DATA.SET_INFORMATION.BytesNeeded
+// );
+//}
+
+
+NDIS_STATUS
+PcimacSetQueryInfo(
+ NDIS_HANDLE AdapterContext,
+ NDIS_OID Oid,
+ PVOID InfoBuffer,
+ ULONG InfoBufferLen,
+ PULONG BytesReadWritten,
+ PULONG BytesNeeded
+ )
+{
+ ULONG OidType;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ D_LOG(D_ENTRY, ("PcimacSetQueryInfo: Adapter: 0x%p, Oid: 0x%x", AdapterContext, Oid));
+
+ //
+ // get oid type
+ //
+ OidType = Oid & 0xFF000000;
+
+ switch (OidType)
+ {
+ case OID_WAN_INFO:
+ Status = WanOidProc(AdapterContext,
+ Oid,
+ InfoBuffer,
+ InfoBufferLen,
+ BytesReadWritten,
+ BytesNeeded);
+ break;
+
+ case OID_TAPI_INFO:
+ Status = TapiOidProc(AdapterContext,
+ Oid,
+ InfoBuffer,
+ InfoBufferLen,
+ BytesReadWritten,
+ BytesNeeded);
+ break;
+
+
+ case OID_GEN_INFO:
+ case OID_8023_INFO:
+ Status = LanOidProc(AdapterContext,
+ Oid,
+ InfoBuffer,
+ InfoBufferLen,
+ BytesReadWritten,
+ BytesNeeded);
+ break;
+
+ default:
+ Status = NDIS_STATUS_INVALID_OID;
+ break;
+ }
+
+ D_LOG(D_EXIT, ("PcimacSetQueryInfo: Status: 0x%x, BytesReadWritten: %d, BytesNeeded: %d", Status, *BytesReadWritten, *BytesNeeded));
+ return(Status);
+}
+
+NDIS_STATUS
+PcimacReconfigure(
+ PNDIS_STATUS OpenErrorStatus,
+ NDIS_HANDLE AdapterContext,
+ NDIS_HANDLE WrapperConfigurationContext
+ )
+{
+ D_LOG(D_ENTRY, ("PcimacReconfigure: Adapter: 0x%p", AdapterContext));
+ //
+ // not supported for now
+ //
+ return(NDIS_STATUS_FAILURE);
+}
+
+NDIS_STATUS
+PcimacReset(
+ PBOOLEAN AddressingReset,
+ NDIS_HANDLE AdapterContext
+ )
+{
+ D_LOG(D_ENTRY, ("PcimacReset: Adapter: 0x%p", AdapterContext));
+
+ return(NDIS_STATUS_HARD_ERRORS);
+}
+
+NDIS_STATUS
+PcimacSend(
+ NDIS_HANDLE MacBindingHandle,
+ NDIS_HANDLE LinkContext,
+ PNDIS_WAN_PACKET WanPacket
+ )
+{
+ MTL *mtl = (MTL*)LinkContext;
+
+ D_LOG(D_ENTRY, ("PcimacSend: Link: 0x%p", mtl));
+
+ /* send packet */
+ mtl__tx_packet(mtl, WanPacket);
+
+ return(NDIS_STATUS_PENDING);
+}
+
+/* create/delete external name binding */
+VOID
+BindName(ADAPTER *Adapter, BOOL create)
+{
+#define LINKNAME "\\DosDevices\\PCIMAC0"
+ UNICODE_STRING linkname, devname;
+ NTSTATUS stat;
+ ULONG n;
+ CHAR name[128];
+ ANSI_STRING aname;
+ ANSI_STRING lname;
+
+ if (Adapter)
+ sprintf(name,"\\Device\\%s",Adapter->Name);
+
+ if ( !name )
+ sprintf(name,"\\Device\\Pcimac69");
+
+ D_LOG(D_ENTRY, ("BindName: LinkName: %s, NdisName: %s", LINKNAME, name));
+
+ /* convert to unicode string */
+ RtlInitAnsiString(&lname, LINKNAME);
+ stat = RtlAnsiStringToUnicodeString(&linkname, &lname, TRUE);
+
+ /* convert to unicode string */
+ RtlInitAnsiString(&aname, name);
+ stat = RtlAnsiStringToUnicodeString(&devname, &aname, TRUE);
+
+ /* create? */
+ if ( create )
+ stat = IoCreateSymbolicLink (&linkname, &devname);
+ else /* delete */
+ stat = IoDeleteSymbolicLink (&linkname);
+
+ D_LOG(D_ENTRY, ("BindName: Operation: 0x%x, stat: 0x%x", create, stat));
+
+ RtlFreeUnicodeString(&devname);
+ RtlFreeUnicodeString(&linkname);
+}
+
+//
+// Function commented out for change in how RAS picks up tapi name and address info
+// This will help make the driver more portable.
+//
+//#pragma NDIS_INIT_FUNCTION(RegistryInit)
+//
+//VOID
+//RegistryInit(VOID)
+//{
+// UNICODE_STRING AddressUnicodeString;
+// UNICODE_STRING UnicodeString;
+// ANSI_STRING AnsiString;
+// PWCHAR AddressBuffer;
+// NDIS_PHYSICAL_ADDRESS HighestAcceptableMax = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
+// ULONG l, m;
+//
+// NdisAllocateMemory((PVOID)&AddressBuffer,
+// 1024,
+// 0,
+// HighestAcceptableMax);
+//
+// if (!AddressBuffer)
+// {
+// D_LOG(D_ALWAYS, ("RegistryInit: Memory Allocation Failed!"));
+// return;
+// }
+//
+// AddressUnicodeString.MaximumLength = 1024;
+// AddressUnicodeString.Length = 0;
+// NdisZeroMemory(AddressBuffer, 1024);
+// AddressUnicodeString.Buffer = AddressBuffer;
+//
+// //
+// // create tapi devices key
+// //
+// RtlCreateRegistryKey (RTL_REGISTRY_DEVICEMAP, L"Tapi Devices");
+//
+// //
+// // create pcimac service provider key
+// //
+// RtlCreateRegistryKey (RTL_REGISTRY_DEVICEMAP, L"Tapi Devices\\PCIMAC");
+//
+// //
+// // write media type - isdn for us
+// //
+// RtlInitAnsiString(&AnsiString, "ISDN");
+//
+// RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE);
+//
+// RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
+// L"Tapi Devices\\PCIMAC",
+// L"Media Type",
+// REG_SZ,
+// UnicodeString.Buffer,
+// UnicodeString.Length);
+//
+// RtlFreeUnicodeString(&UnicodeString);
+//
+// for (l = 0; l < MAX_ADAPTERS_IN_SYSTEM; l++)
+// {
+// ADAPTER *Adapter = (ADAPTER*)Pcimac.AdapterTbl[l];
+//
+// if (Adapter)
+// {
+// for (m = 0; m < MAX_CM_PER_ADAPTER; m++)
+// {
+// CM *cm = Adapter->CmTbl[m];
+//
+// if (cm)
+// {
+// RtlInitAnsiString(&AnsiString, cm->LocalAddress);
+//
+// RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE);
+//
+// RtlAppendUnicodeStringToString(&AddressUnicodeString, &UnicodeString);
+//
+// AddressUnicodeString.Buffer[AddressUnicodeString.Length + 1] = '\0';
+// AddressUnicodeString.Length += 2;
+//
+// RtlFreeUnicodeString(&UnicodeString);
+// }
+// }
+// }
+// }
+//
+// //
+// // write value
+// //
+// RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
+// L"Tapi Devices\\PCIMAC",
+// L"Address",
+// REG_MULTI_SZ,
+// AddressUnicodeString.Buffer,
+// AddressUnicodeString.Length);
+//
+// NdisFreeMemory(AddressBuffer, 1024, 0);
+//}
+
+#pragma NDIS_INIT_FUNCTION(GetBaseConfigParams)
+
+ULONG
+GetBaseConfigParams(
+ CONFIGPARAM *RetParam,
+ CHAR *Key
+ )
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ NDIS_STRING KeyWord;
+ ANSI_STRING AnsiKey;
+ ANSI_STRING AnsiRet;
+ ULONG n;
+ PNDIS_CONFIGURATION_PARAMETER ConfigParam;
+
+ D_LOG(D_ALWAYS, ("GetBaseConfigParams: Key: %s", Key));
+ //
+ // turn passed in key to an ansi string
+ //
+ RtlInitAnsiString(&AnsiKey, Key);
+
+ //
+ // allocate buffer and turn ansi to unicode
+ //
+ RtlAnsiStringToUnicodeString(&KeyWord, &AnsiKey, TRUE);
+
+ NdisReadConfiguration(&Status,
+ &ConfigParam,
+ RetParam->ConfigHandle,
+ &KeyWord,
+ RetParam->ParamType);
+
+ D_LOG(D_ALWAYS, ("GetBaseConfigParams: Status: 0x%x", Status));
+ //
+ // free up unicode string buffer
+ //
+ RtlFreeUnicodeString(&KeyWord);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ D_LOG(D_ALWAYS, ("GetBaseConfigParams: Error Reading Config: RetVal: 0x%x", Status));
+ if (RetParam->MustBePresent)
+ NdisWriteErrorLogEntry (RetParam->AdapterHandle,
+ NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER,
+ 0);
+ return(0);
+ }
+
+ D_LOG(D_ALWAYS, ("GetBaseConfigParams: StringLength: %d", ConfigParam->ParameterData.StringData.Length));
+ switch (ConfigParam->ParameterType)
+ {
+ case NdisParameterString:
+ RtlUnicodeStringToAnsiString(&AnsiRet, &ConfigParam->ParameterData.StringData, TRUE);
+ strncpy(RetParam->String, AnsiRet.Buffer, AnsiRet.Length);
+ RetParam->StringLen = AnsiRet.Length;
+ RtlFreeAnsiString(&AnsiRet);
+ D_LOG(D_ALWAYS, ("GetBaseConfigParams: String: %s, Length: %d", RetParam->String, RetParam->StringLen));
+ break;
+
+ case NdisParameterMultiString:
+ for (n = 0; n < RetParam->StringLen && n < ConfigParam->ParameterData.StringData.Length; n++)
+ RetParam->String[n] = (CHAR)ConfigParam->ParameterData.StringData.Buffer[n];
+
+ RetParam->StringLen = n/2;
+
+ for (n = 0; n < RetParam->StringLen; n++)
+ if (!_strnicmp((CHAR*)&RetParam->String[n], (CHAR*)"=", 1))
+ RetParam->String[n] = '\0';
+ D_LOG(D_ALWAYS, ("GetBaseConfigParams: String: %s, Length: %d", RetParam->String, RetParam->StringLen));
+ break;
+
+ case NdisParameterInteger:
+ case NdisParameterHexInteger:
+ RetParam->Value = ConfigParam->ParameterData.IntegerData;
+ D_LOG(D_ALWAYS, ("GetBaseConfigParams: Integer: 0x%x", RetParam->Value));
+ break;
+
+ default:
+ return(0);
+ }
+ return(1);
+}
+
+#pragma NDIS_INIT_FUNCTION(GetLineConfigParams)
+
+ULONG
+GetLineConfigParams(
+ CONFIGPARAM *RetParam,
+ ULONG LineNumber,
+ CHAR *Key
+ )
+{
+ ULONG n;
+ CHAR LinePath[64];
+ NDIS_STRING KeyWord;
+ ANSI_STRING AnsiKey;
+ ANSI_STRING AnsiRet;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PNDIS_CONFIGURATION_PARAMETER ConfigParam;
+
+ sprintf(LinePath,
+ "%s%d.%s",
+ PCIMAC_KEY_LINE,
+ LineNumber,
+ Key);
+
+ D_LOG(D_ALWAYS, ("GetLineConfigParams: LineNumber: %d, Key: %s", LineNumber, Key));
+ //
+ // turn passed in key to an ansi string
+ //
+ RtlInitAnsiString(&AnsiKey, LinePath);
+
+ //
+ // allocate buffer and turn ansi to unicode
+ //
+ RtlAnsiStringToUnicodeString(&KeyWord, &AnsiKey, TRUE);
+
+ NdisReadConfiguration(&Status,
+ &ConfigParam,
+ RetParam->ConfigHandle,
+ &KeyWord,
+ RetParam->ParamType);
+
+ //
+ // free up unicode string buffer
+ //
+ RtlFreeUnicodeString(&KeyWord);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ D_LOG(D_ALWAYS, ("GetLineConfigParams: Error Reading Config: RetVal: 0x%x", Status));
+ if (RetParam->MustBePresent)
+ NdisWriteErrorLogEntry (RetParam->AdapterHandle,
+ NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER,
+ 0);
+ return(0);
+ }
+
+ switch (ConfigParam->ParameterType)
+ {
+ case NdisParameterString:
+ RtlUnicodeStringToAnsiString(&AnsiRet, &ConfigParam->ParameterData.StringData, TRUE);
+ strncpy(RetParam->String, AnsiRet.Buffer, AnsiRet.Length);
+ RetParam->StringLen = AnsiRet.Length;
+ RtlFreeAnsiString(&AnsiRet);
+ D_LOG(D_ALWAYS, ("GetLineConfigParams: String: %s, Length: %d", RetParam->String, RetParam->StringLen));
+ break;
+
+ case NdisParameterMultiString:
+ for (n = 0; n < RetParam->StringLen && n < ConfigParam->ParameterData.StringData.Length; n++)
+ RetParam->String[n] = (CHAR)ConfigParam->ParameterData.StringData.Buffer[n];
+
+ RetParam->StringLen = n/2;
+
+ for (n = 0; n < RetParam->StringLen; n++)
+ if (!_strnicmp((CHAR*)&RetParam->String[n], (CHAR*)"=", 1))
+ RetParam->String[n] = '\0';
+ D_LOG(D_ALWAYS, ("GetBaseConfigParams: String: %s, Length: %d", RetParam->String, RetParam->StringLen));
+ break;
+
+ case NdisParameterInteger:
+ case NdisParameterHexInteger:
+ RetParam->Value = ConfigParam->ParameterData.IntegerData;
+ D_LOG(D_ALWAYS, ("GetLineConfigParams: Integer: 0x%x", RetParam->Value));
+ break;
+
+ default:
+ return(0);
+ }
+ return(1);
+}
+
+#pragma NDIS_INIT_FUNCTION(GetLTermConfigParams)
+
+ULONG
+GetLTermConfigParams(
+ CONFIGPARAM *RetParam,
+ ULONG LineNumber,
+ ULONG LTermNumber,
+ CHAR *Key
+ )
+{
+ ULONG n;
+ CHAR LTermPath[64];
+ NDIS_STRING KeyWord;
+ ANSI_STRING AnsiKey;
+ ANSI_STRING AnsiRet;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PNDIS_CONFIGURATION_PARAMETER ConfigParam;
+
+ D_LOG(D_ALWAYS, ("GetLTermConfigParams: LineNumber: %d, LTerm: %d, Key: %s", LineNumber, LTermNumber, Key));
+
+ sprintf(LTermPath,
+ "%s%d.%s%d.%s",
+ PCIMAC_KEY_LINE,
+ LineNumber,
+ PCIMAC_KEY_LTERM,
+ LTermNumber,
+ Key);
+
+ //
+ // turn passed in key to an ansi string
+ //
+ RtlInitAnsiString(&AnsiKey, LTermPath);
+
+ //
+ // allocate buffer and turn ansi to unicode
+ //
+ RtlAnsiStringToUnicodeString(&KeyWord, &AnsiKey, TRUE);
+
+ NdisReadConfiguration(&Status,
+ &ConfigParam,
+ RetParam->ConfigHandle,
+ &KeyWord,
+ RetParam->ParamType);
+
+ //
+ // free up unicode string buffer
+ //
+ RtlFreeUnicodeString(&KeyWord);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ D_LOG(D_ALWAYS, ("GetLTermConfigParams: Error Reading Config: RetVal: 0x%x", Status));
+ if (RetParam->MustBePresent)
+ NdisWriteErrorLogEntry (RetParam->AdapterHandle,
+ NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER,
+ 0);
+ return(0);
+ }
+
+ switch (ConfigParam->ParameterType)
+ {
+ case NdisParameterString:
+ RtlUnicodeStringToAnsiString(&AnsiRet, &ConfigParam->ParameterData.StringData, TRUE);
+ strncpy(RetParam->String, AnsiRet.Buffer, AnsiRet.Length);
+ RetParam->StringLen = AnsiRet.Length;
+ RtlFreeAnsiString(&AnsiRet);
+ D_LOG(D_ALWAYS, ("GetLTermConfigParams: String: %s, Length: %d", RetParam->String, RetParam->StringLen));
+ break;
+
+ case NdisParameterMultiString:
+ for (n = 0; n < RetParam->StringLen && n < ConfigParam->ParameterData.StringData.Length; n++)
+ RetParam->String[n] = (CHAR)ConfigParam->ParameterData.StringData.Buffer[n];
+
+ RetParam->StringLen = n/2;
+
+ for (n = 0; n < RetParam->StringLen; n++)
+ if (!_strnicmp((CHAR*)&RetParam->String[n], (CHAR*)"=", 1))
+ RetParam->String[n] = '\0';
+ D_LOG(D_ALWAYS, ("GetLTermConfigParams: String: %s, Length: %d", RetParam->String, RetParam->StringLen));
+ break;
+
+ case NdisParameterInteger:
+ case NdisParameterHexInteger:
+ RetParam->Value = ConfigParam->ParameterData.IntegerData;
+ D_LOG(D_ALWAYS, ("GetLTermConfigParams: Integer: 0x%x", RetParam->Value));
+ break;
+
+ default:
+ return(0);
+ }
+ return(1);
+}
+
+VOID
+SetInDriverFlag (
+ ADAPTER *Adapter
+ )
+{
+ NdisAcquireSpinLock(&Pcimac.lock);
+
+ Pcimac.InDriverFlag = 1;
+
+ Pcimac.CurrentAdapter = Adapter;
+
+ Pcimac.NextAdapterToPoll++;
+
+ if (Pcimac.NextAdapterToPoll == Pcimac.NumberOfAdaptersInSystem)
+ Pcimac.NextAdapterToPoll = 0;
+
+ NdisReleaseSpinLock(&Pcimac.lock);
+}
+
+VOID
+ClearInDriverFlag (
+ ADAPTER *Adapter
+)
+{
+ NdisAcquireSpinLock(&Pcimac.lock);
+
+ Pcimac.InDriverFlag = 0;
+
+ NdisReleaseSpinLock(&Pcimac.lock);
+}
+
+ULONG
+CheckInDriverFlag (
+ ADAPTER *Adapter
+)
+{
+ ADAPTER *CurrentAdapter;
+ INT RetVal = 0;
+
+ NdisAcquireSpinLock(&Pcimac.lock);
+
+ //
+ // get the current in driver adapter
+ //
+ CurrentAdapter = (ADAPTER*)Pcimac.CurrentAdapter;
+
+ //
+ // if someone is in the driver and they are using the same
+ // shared memory window as the new prospective user send them
+ // away unhappy
+ //
+ if (Pcimac.InDriverFlag && CurrentAdapter && (Adapter->VBaseMem == CurrentAdapter->VBaseMem))
+ RetVal = 1;
+
+ NdisReleaseSpinLock(&Pcimac.lock);
+
+ return(RetVal);
+}
+
+#pragma NDIS_INIT_FUNCTION(IdpGetEaddrFromNvram)
+
+/*
+ * get ethernet address(s) out on nvram & register
+ *
+ * note that line number inside board (bline) argument was added here.
+ * for each idd installed, this function is called to add two ethernet
+ * addresses associated with it (it's two B channels - or it's capability to
+ * handle two connections). All ethernet address are derived from the
+ * single address stored starting at nvram address 8. since the manufecturer
+ * code is the first 3 bytes, we must not modify these bytes. therefor,
+ * addresses are generated by indexing the 4'th byte by bline*2 (need two
+ * address - remember?).
+ */
+VOID
+IdpGetEaddrFromNvram(
+ IDD *idd,
+ CM *cm,
+ USHORT Line,
+ USHORT LineIndex
+ )
+{
+ UCHAR eaddr[6];
+ USHORT nvval;
+
+ /* extract original stored ethernet address */
+ idd_get_nvram(idd, (USHORT)(8), &nvval);
+ eaddr[0] = LOBYTE(nvval);
+ eaddr[1] = HIBYTE(nvval);
+ idd_get_nvram(idd, (USHORT)(9), &nvval);
+ eaddr[2] = LOBYTE(nvval);
+ eaddr[3] = HIBYTE(nvval);
+ idd_get_nvram(idd, (USHORT)(10), &nvval);
+ eaddr[4] = LOBYTE(nvval);
+ eaddr[5] = HIBYTE(nvval);
+
+ /* create derived address and store it */
+ eaddr[3] += (Line * 2) + LineIndex;
+
+ NdisMoveMemory(cm->SrcAddr, eaddr, sizeof(cm->SrcAddr));
+}
+
+#pragma NDIS_INIT_FUNCTION(AdpGetEaddrFromNvram)
+
+/*
+ * get ethernet address(s) out on nvram & register
+ *
+ * note that line number inside board (bline) argument was added here.
+ * for each idd installed, this function is called to add two ethernet
+ * addresses associated with it (it's two B channels - or it's capability to
+ * handle two connections). All ethernet address are derived from the
+ * single address stored starting at nvram address 8. since the manufecturer
+ * code is the first 3 bytes, we must not modify these bytes. therefor,
+ * addresses are generated by indexing the 4'th byte by bline*2 (need two
+ * address - remember?).
+ */
+VOID
+AdpGetEaddrFromNvram(
+ IDD *idd,
+ CM *cm,
+ USHORT Line,
+ USHORT LineIndex
+ )
+{
+ UCHAR eaddr[6];
+ USHORT nvval;
+
+ //
+ // the MAC address lines at offset 0x950 in the onboard memory
+ // this is NVRAM_WINDOW 0x940 + 0x10
+ //
+ idd_get_nvram(idd, (USHORT)(0x10), &nvval);
+ eaddr[0] = LOBYTE(nvval);
+ eaddr[1] = HIBYTE(nvval);
+ idd_get_nvram(idd, (USHORT)(0x12), &nvval);
+ eaddr[2] = LOBYTE(nvval);
+ eaddr[3] = HIBYTE(nvval);
+ idd_get_nvram(idd, (USHORT)(0x14), &nvval);
+ eaddr[4] = LOBYTE(nvval);
+ eaddr[5] = HIBYTE(nvval);
+
+ /* create derived address and store it */
+ eaddr[3] += (Line * 2) + LineIndex;
+
+ NdisMoveMemory(cm->SrcAddr, eaddr, sizeof(cm->SrcAddr));
+}
+
+#ifdef OLD
+ULONG
+EnumAdaptersInSystem()
+{
+ ULONG n, NumAdapters = 0;
+
+ for (n = 0; n < MAX_ADAPTERS_IN_SYSTEM; n++)
+ {
+ if (Pcimac.AdapterTbl[n])
+ NumAdapters++;
+ }
+ return(NumAdapters);
+}
+#endif
+
+ULONG
+EnumAdaptersInSystem()
+{
+ ULONG NumAdapters;
+
+ NdisAcquireSpinLock(&Pcimac.lock);
+
+ NumAdapters = Pcimac.NumberOfAdaptersInSystem;
+
+ NdisReleaseSpinLock(&Pcimac.lock);
+
+ return(NumAdapters);
+}
+
+ADAPTER*
+GetAdapterByIndex(
+ ULONG Index
+ )
+{
+ ADAPTER *Adapter;
+
+ NdisAcquireSpinLock(&Pcimac.lock);
+
+ Adapter = Pcimac.AdapterTbl[Index];
+
+ NdisReleaseSpinLock(&Pcimac.lock);
+
+ return(Adapter);
+}
+
+INT
+IoEnumAdapter(VOID *cmd_1)
+{
+ IO_CMD *cmd = (IO_CMD*)cmd_1;
+ ULONG n, m, NumberOfAdapters;
+
+ NumberOfAdapters = cmd->val.enum_adapters.num = (USHORT)EnumAdaptersInSystem();
+
+ for (n = 0, m = 0; n < NumberOfAdapters; n++)
+ {
+ ADAPTER *Adapter = GetAdapterByIndex(n);
+
+ if (Adapter)
+ {
+ cmd->val.enum_adapters.BaseIO[m] = Adapter->BaseIO;
+ cmd->val.enum_adapters.BaseMem[m] = Adapter->BaseMem;
+ cmd->val.enum_adapters.BoardType[m] = Adapter->BoardType;
+ NdisMoveMemory (&cmd->val.enum_adapters.Name[m], Adapter->Name, sizeof(cmd->val.enum_adapters.Name[n]));
+ cmd->val.enum_adapters.tbl[m] = Adapter;
+ m++;
+ }
+ }
+
+ return(0);
+}
+
+VOID
+AdapterDestroy(
+ ADAPTER *Adapter
+ )
+{
+ ULONG n;
+
+ for (n = 0; n < MAX_ADAPTERS_IN_SYSTEM; n++)
+ {
+ if (Adapter == Pcimac.AdapterTbl[n])
+ break;
+ }
+
+ if (n == MAX_ADAPTERS_IN_SYSTEM)
+ return;
+
+ //
+ // stop idd timers
+ //
+ StopTimers(Adapter);
+
+ Pcimac.AdapterTbl[n] = NULL;
+
+ Pcimac.NumberOfAdaptersInSystem--;
+
+ //
+ // if we have successfully mapped our base i/o then we need to release
+ //
+ if (Adapter->VBaseIO)
+ {
+ //
+ // deregister adapters I/O and memory
+ //
+ NdisMDeregisterIoPortRange((NDIS_HANDLE)Adapter->Handle,
+ Adapter->BaseIO,
+ 8,
+ Adapter->VBaseIO);
+ }
+
+ //
+ // if we have successfully mapped our base memory then we need to release
+ //
+ if (Adapter->VBaseMem)
+ {
+ NdisMUnmapIoSpace((NDIS_HANDLE)Adapter->Handle,
+ Adapter->VBaseMem,
+ 0x4000);
+ }
+
+// NdisFreeSpinLock(&Adapter->lock);
+
+ NdisFreeMemory(Adapter, sizeof(ADAPTER), 0);
+}
+
+#pragma NDIS_INIT_FUNCTION(StartTimers)
+
+VOID
+StartTimers(
+ ADAPTER *Adapter
+ )
+{
+ NdisMSetTimer(&Adapter->IddPollTimer, IDD_POLL_T);
+ NdisMSetTimer(&Adapter->MtlPollTimer, MTL_POLL_T);
+ NdisMSetTimer(&Adapter->CmPollTimer, CM_POLL_T);
+}
+
+VOID
+StopTimers(
+ ADAPTER *Adapter
+ )
+{
+ BOOLEAN TimerCanceled;
+
+ NdisMCancelTimer(&Adapter->IddPollTimer, &TimerCanceled);
+ NdisMCancelTimer(&Adapter->MtlPollTimer, &TimerCanceled);
+ NdisMCancelTimer(&Adapter->CmPollTimer, &TimerCanceled);
+}
+
+#pragma NDIS_INIT_FUNCTION(IdpCheckIO)
+
+ULONG
+IdpCheckIO(IDD *idd)
+{
+ ULONG ReturnValue = 1;
+
+ //
+ // check for board at this I/O address
+ //
+ if (idd->btype == IDD_BT_PCIMAC || idd->btype == IDD_BT_PCIMAC4)
+ {
+ UCHAR BoardID;
+
+ BoardID = (idd->InFromPort(idd, 5) & 0x0F);
+
+ if ( ((idd->btype == IDD_BT_PCIMAC) && (BoardID == 0x02)) ||
+ ((idd->btype == IDD_BT_PCIMAC4) && (BoardID == 0x04)))
+ ReturnValue = 0;
+ }
+
+ return(ReturnValue);
+}
+
+#pragma NDIS_INIT_FUNCTION(AdpCheckIO)
+
+ULONG
+AdpCheckIO(IDD *idd)
+{
+ D_LOG(D_ENTRY, ("AdpCheckIO: entry, idd: 0x%p BoardType: %d", idd, idd->btype));
+
+ if (idd->btype == IDD_BT_DATAFIREU)
+ {
+ UCHAR BoardId = idd->InFromPort(idd, ADP_REG_ID);
+
+ D_LOG(D_ALWAYS, ("AdpCheckIO: ADP_REG_ID: %d", BoardId));
+
+ if (BoardId != ADP_BT_ADP1)
+ return(1);
+
+ return(0);
+ }
+ return(1);
+}
+
+#pragma NDIS_INIT_FUNCTION(IdpCheckMem)
+
+ULONG
+IdpCheckMem(IDD *idd)
+{
+ return(0);
+}
+
+#pragma NDIS_INIT_FUNCTION(AdpCheckMem)
+
+ULONG
+AdpCheckMem(IDD *idd)
+{
+ return(0);
+
+}
+
+
diff --git a/private/ntos/ndis/pcimac/pcimac.rc b/private/ntos/ndis/pcimac/pcimac.rc
new file mode 100644
index 000000000..3dfd47087
--- /dev/null
+++ b/private/ntos/ndis/pcimac/pcimac.rc
@@ -0,0 +1,23 @@
+#include <winver.h>
+#include <ntverp.h>
+
+#ifdef VER_COMPANYNAME_STR
+#undef VER_COMPANYNAME_STR
+#endif
+#define VER_COMPANYNAME_STR "Digi International Inc."
+
+#define VER_LEGALCOPYRIGHT_YEARS "1992-1994"
+
+#define VER_LEGALCOPYRIGHT_STR "Copyright " VER_LEGALCOPYRIGHT_YEARS ", Digi International Inc. All rights reserved."
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "DigiBoard Telecommunications Group - ISDN Adapter Device Driver"
+#define VER_INTERNALNAME_STR "pcimac.sys"
+#define VER_ORIGINALFILENAME_STR "pcimac.sys"
+
+#define VER_FILEVERSION 2,1,0,000
+#define VER_FILEVERSION_STR "v2.1.0.000"
+
+#include "common.ver"
+
diff --git a/private/ntos/ndis/pcimac/res.h b/private/ntos/ndis/pcimac/res.h
new file mode 100644
index 000000000..15bd9f5d0
--- /dev/null
+++ b/private/ntos/ndis/pcimac/res.h
@@ -0,0 +1,52 @@
+/*
+ * RES.H - Resource ownership classe, master include file
+ */
+
+
+#ifndef _RES_
+#define _RES_
+
+/* resource classes */
+#define RES_CLASS_MEM 0
+#define RES_CLASS_IO 1
+
+/* return values */
+#define RES_E_SUCC 0
+#define RES_E_NOMEM 1
+
+// Return Values for GetResourceSem
+#define RES_BUSY 0
+#define RES_FREE 1
+
+/* resource structure */
+typedef struct _RES
+{
+ ULONG class; /* resource class */
+ ULONG id; /* resource id (value) */
+ ULONG data; /* resource attached data */
+
+ ULONG cre_ref; /* creation refrence */
+ ULONG own_ref; /* ownership refrence */
+
+ VOID *owner; /* current owner, NULL == none */
+
+ NDIS_SPIN_LOCK lock; /* scheduling lock */
+
+ SEMA proc_sema; /* processing sema */
+
+} RES;
+
+
+/* operations */
+INT res_init(VOID);
+VOID res_term(VOID);
+RES* res_create(ULONG class, ULONG id);
+INT res_destroy(VOID* res_1);
+VOID res_own(VOID* res_1, VOID *owner);
+VOID res_unown(VOID* res_1, VOID *owner);
+VOID res_get_data(VOID* res_1, ULONG* data);
+VOID res_set_data(VOID* res_1, ULONG data);
+INT GetResourceSem (VOID*);
+VOID FreeResourceSem (VOID*);
+
+#endif /* _RES_ */
diff --git a/private/ntos/ndis/pcimac/res_core.c b/private/ntos/ndis/pcimac/res_core.c
new file mode 100644
index 000000000..57d33ccc4
--- /dev/null
+++ b/private/ntos/ndis/pcimac/res_core.c
@@ -0,0 +1,262 @@
+/*
+ * RES_CORE.C - Resource ownership class, implementation
+ *
+ * as defined here, a resource has a class and an id (value). one ULONG
+ * of data may be attached to a resource.
+ *
+ * objects create a reference (handle) to the resource using res_create
+ * and free it using res_destroy. multiple objects may create references
+ * to the same object.
+ *
+ * ownership is aquired using res_own and released using res_unown. if
+ * an object already owns a resource, it may own it again (class keeps
+ * a refrence count). if an object (thread) asks for ownership of an
+ * already owned resource, if is suspended (using NdisAquireSpinLock)
+ */
+
+#include <ndis.h>
+//#include <ndismini.h>
+#include <ndiswan.h>
+#include <mydefs.h>
+#include <mytypes.h>
+#include <util.h>
+#include <adapter.h>
+#include <idd.h>
+#include <cm.h>
+#include <mtl.h>
+#include <res.h>
+#include <disp.h>
+
+/* system limits */
+#define MAX_RES 128
+
+/* assists */
+//#define LOCK NdisAcquireSpinLock(&res__lock)
+//#define UNLOCK NdisReleaseSpinLock(&res__lock)
+
+/* global variables */
+NDIS_SPIN_LOCK res__lock; /* management lock */
+RES *res__tbl;
+
+/* initialize support */
+INT
+res_init(VOID)
+{
+ NDIS_PHYSICAL_ADDRESS pa = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
+
+ /* allocate memory object */
+ NdisAllocateMemory((PVOID*)&res__tbl, (sizeof(RES) * MAX_RES), 0, pa);
+ if ( !res__tbl )
+ {
+ D_LOG(D_ALWAYS, ("res_init: memory allocate failed!"));
+ return(RES_E_NOMEM);
+ }
+ D_LOG(D_ALWAYS, ("res_init: res__tbl: 0x%p", res__tbl));
+
+ NdisZeroMemory (res__tbl, sizeof(RES) * MAX_RES);
+// NdisAllocateSpinLock(&res__lock);
+ return(RES_E_SUCC);
+}
+
+/* terminate support */
+VOID
+res_term(VOID)
+{
+// DbgPrint ("Resource Term: Entry\n");
+// NdisFreeSpinLock(&res__lock);
+ /* free memory */
+ NdisFreeMemory(res__tbl, (sizeof(RES) * MAX_RES), 0);
+}
+
+/* create a (refrence to a ) resource */
+RES*
+res_create(ULONG class, ULONG id)
+{
+ RES *res;
+ INT n;
+
+// LOCK;
+
+// DbgPrint ("Resource Create: class: 0x%x, id: 0x%x\n",class, id);
+// DbgPrint ("IRQL: 0x%x\n",KeGetCurrentIrql());
+ /* scan for a matching slot */
+ for ( n = 0 ; n < MAX_RES ; n++ )
+ {
+ res = res__tbl + n;
+
+ if ( res->cre_ref && (res->class == class) && (res->id == id) )
+ {
+ /* found an already existing resource */
+// DbgPrint ("Resource Create: resource already exists!\n");
+ res->cre_ref++;
+ break;
+ }
+ }
+
+ /* if no such, try to create a new one */
+ if (n >= MAX_RES)
+ for ( n = 0 ; n < MAX_RES ; n++ )
+ {
+ res = res__tbl + n;
+
+ if ( !res->cre_ref )
+ {
+// DbgPrint ("Resource Create: resource created!\n");
+ /* found a free slot, fill */
+ res->cre_ref++;
+ res->class = class;
+ res->id = id;
+ res->data = 0;
+ res->own_ref = 0;
+ NdisAllocateSpinLock(&res->lock);
+ /* init sema */
+ sema_init(&res->proc_sema);
+ break;
+ }
+ }
+
+// UNLOCK;
+// DbgPrint ("Resource Create exit: res: 0x%p refcount: %d\n",res, res->cre_ref);
+// DbgPrint (": IRQL: 0x%x\n",KeGetCurrentIrql());
+ return(res);
+}
+
+/* free (a refrence to) a resource, return 1 if really destroyed */
+INT
+res_destroy(VOID *res_1)
+{
+ RES *res = (RES*)res_1;
+ INT really = 0;
+
+// LOCK;
+
+// DbgPrint ("Resource Destroy: Entry res: 0x%p, refcount: %d\n",res, res->cre_ref);
+// DbgPrint (": IRQL: 0x%x\n",KeGetCurrentIrql());
+ /* decrement refrence count, if down to zero, free */
+ res->cre_ref--;
+ if ( !res->cre_ref )
+ {
+ NdisFreeSpinLock(&res->lock);
+ sema_term (&res->proc_sema);
+ really = 1;
+ }
+
+// UNLOCK;
+// DbgPrint ("Resource Destroy: Exit\n");
+// DbgPrint (": IRQL: 0x%x\n",KeGetCurrentIrql());
+ return(really);
+}
+
+/* establish owership for a resource */
+VOID
+res_own(VOID *res_1, VOID *owner)
+{
+ RES *res = (RES*)res_1;
+// LOCK;
+
+// DbgPrint("res_own: enter, res: 0x%p, owner: 0x%p, owner ref: %d\n", res, res->owner, res->own_ref);
+// DbgPrint (": IRQL: 0x%x\n",KeGetCurrentIrql());
+
+ /* if not owned, get it */
+ if ( !res->own_ref )
+ {
+ NdisAcquireSpinLock(&res->lock);
+ res->own_ref++;
+ res->owner = owner;
+ goto bye;
+ }
+
+ /* check if already owned by self */
+ if ( res->owner == owner )
+ goto bye;
+
+ /* else we have to wait for it */
+// UNLOCK;
+ NdisAcquireSpinLock(&res->lock);
+// LOCK;
+
+ /* no I have it, fill */
+ res->own_ref++;
+ res->owner = owner;
+
+ bye:
+// UNLOCK;
+// DbgPrint("res_own: exit, res: 0x%p, owner: 0x%p, owner ref: %d\n", res, res->owner, res->own_ref);
+// DbgPrint (": IRQL: 0x%x\n",KeGetCurrentIrql());
+ return;
+}
+
+/* release ownership of a resource, it is assumed that owner is releasing */
+VOID
+res_unown(VOID *res_1, VOID *owner)
+{
+ RES *res = (RES*)res_1;
+// LOCK;
+
+// DbgPrint("res_unown: entry, res: 0x%p, owner: 0x%p owner ref: %d\n", res, owner, res->own_ref);
+// DbgPrint (": IRQL: 0x%x\n",KeGetCurrentIrql());
+
+ if (!res->own_ref)
+ {
+ /* if free, onwership released */
+// UNLOCK;
+ return;
+ }
+
+ /* decrement ownership count, if not down to zero - still owned */
+ res->own_ref--;
+
+ if ( res->own_ref )
+ {
+// UNLOCK;
+ return;
+ }
+
+ res->owner = NULL;
+
+ NdisReleaseSpinLock(&res->lock);
+
+ /* if free, onwership released */
+// UNLOCK;
+
+// DbgPrint("res_unown: exit, res: 0x%p, owner ref: %d\n", res, res->own_ref);
+// DbgPrint (": IRQL: 0x%x\n",KeGetCurrentIrql());
+}
+
+
+
+/* get private data for a resource */
+VOID
+res_get_data(VOID *res_1, ULONG *data)
+{
+ RES *res = (RES*)res_1;
+ *data = res->data;
+}
+
+
+/* set private data for a resource */
+VOID
+res_set_data(VOID *res_1, ULONG data)
+{
+ RES *res = (RES*)res_1;
+ res->data = data;
+}
+
+INT
+GetResourceSem (VOID *Resource)
+{
+ RES *res = (RES*)Resource;
+
+ if ( !sema_get(&res->proc_sema) )
+ return(RES_BUSY);
+ else
+ return(RES_FREE);
+}
+
+VOID
+FreeResourceSem (VOID *Resource)
+{
+ RES *res = (RES*)Resource;
+ sema_free(&res->proc_sema);
+}
+
diff --git a/private/ntos/ndis/pcimac/sema.h b/private/ntos/ndis/pcimac/sema.h
new file mode 100644
index 000000000..97e70f200
--- /dev/null
+++ b/private/ntos/ndis/pcimac/sema.h
@@ -0,0 +1,8 @@
+/*
+ * SEMA.H - simple semaphores
+ */
+
+#ifndef _SEMA_
+#define _SEMA_
+
+#endif /* _SEMA */
diff --git a/private/ntos/ndis/pcimac/sources b/private/ntos/ndis/pcimac/sources
new file mode 100644
index 000000000..d7300dfc3
--- /dev/null
+++ b/private/ntos/ndis/pcimac/sources
@@ -0,0 +1,69 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=pcimac
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+INCLUDES=$(BASEDIR)\private\ntos\inc
+
+C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER -DBINARY_COMPATIBLE=0
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES= \
+ pcimac.c \
+ idd_init.c \
+ idd_nv.c \
+ idd_io.c \
+ idd_run.c \
+ idd_proc.c \
+ idd_msg.c \
+ mtl_tx.c \
+ mtl_init.c \
+ mtl_set.c \
+ mtl_rx.c \
+ mtl_tick.c \
+ cm_init.c \
+ cm_prof.c \
+ cm_stat.c \
+ cm_timer.c \
+ cm_state.c \
+ cm_q931.c \
+ cm_conn.c \
+ cm_chan.c \
+ res_core.c \
+ io_core.c \
+ disp.c \
+ wan_conn.c \
+ trc_core.c \
+ util.c \
+ wanoid.c \
+ tapioid.c \
+ lanoid.c \
+ pcimac.rc
+
+
+RELATIVE_DEPTH=..\..
diff --git a/private/ntos/ndis/pcimac/tapioid.c b/private/ntos/ndis/pcimac/tapioid.c
new file mode 100644
index 000000000..f08ec0998
--- /dev/null
+++ b/private/ntos/ndis/pcimac/tapioid.c
@@ -0,0 +1,2590 @@
+//
+// Tapioid.c - File contains all functions that handle NDIS_OID's that
+// come from the connection wrapper.
+//
+//
+//
+//
+//#include <ntddk.h>
+#include <ndis.h>
+//#include <ndismini.h>
+#include <ndiswan.h>
+//#include <ntddndis.h>
+#include <stdio.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <adapter.h>
+#include <util.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+#include <res.h>
+#include <trc.h>
+#include <io.h>
+#include <tapioid.h>
+
+typedef struct tagOID_DISPATCH
+{
+ ULONG Oid;
+ NDIS_STATUS (*FuncPtr)();
+}OID_DISPATCH;
+
+//
+// Tapi OID's
+//
+static OID_DISPATCH TapiOids[] =
+ {
+ {OID_TAPI_ACCEPT, TSPI_LineAccept},
+ {OID_TAPI_ANSWER, TSPI_LineAnswer},
+ {OID_TAPI_CLOSE, TSPI_LineClose},
+ {OID_TAPI_CLOSE_CALL, TSPI_LineCloseCall},
+ {OID_TAPI_CONDITIONAL_MEDIA_DETECTION, TSPI_LineConditionalMediaDetect},
+ {OID_TAPI_CONFIG_DIALOG, TSPI_LineConfigDialog},
+ {OID_TAPI_DEV_SPECIFIC, TSPI_LineDevSpecific},
+ {OID_TAPI_DIAL, TSPI_LineDial},
+ {OID_TAPI_DROP, TSPI_LineDrop},
+ {OID_TAPI_GET_ADDRESS_CAPS, TSPI_LineGetAddressCaps},
+ {OID_TAPI_GET_ADDRESS_ID, TSPI_LineGetAddressID},
+ {OID_TAPI_GET_ADDRESS_STATUS, TSPI_LineGetAddressStatus},
+ {OID_TAPI_GET_CALL_ADDRESS_ID, TSPI_LineGetCallAddressID},
+ {OID_TAPI_GET_CALL_INFO, TSPI_LineGetCallInfo},
+ {OID_TAPI_GET_CALL_STATUS, TSPI_LineGetCallStatus},
+ {OID_TAPI_GET_DEV_CAPS, TSPI_LineGetDevCaps},
+ {OID_TAPI_GET_DEV_CONFIG, TSPI_LineGetDevConfig},
+ {OID_TAPI_GET_EXTENSION_ID, TSPI_LineGetExtensionID},
+ {OID_TAPI_GET_ID, TSPI_LineGetID},
+ {OID_TAPI_GET_LINE_DEV_STATUS, TSPI_LineGetLineDevStatus},
+ {OID_TAPI_MAKE_CALL, TSPI_LineMakeCall},
+ {OID_TAPI_NEGOTIATE_EXT_VERSION, TSPI_LineNegotiateExtVersion},
+ {OID_TAPI_OPEN, TSPI_LineOpen},
+ {OID_TAPI_PROVIDER_INITIALIZE, TSPI_ProviderInit},
+ {OID_TAPI_PROVIDER_SHUTDOWN, TSPI_ProviderShutdown},
+ {OID_TAPI_SECURE_CALL, TSPI_LineSecureCall},
+ {OID_TAPI_SELECT_EXT_VERSION, TSPI_LineSelectExtVersion},
+ {OID_TAPI_SEND_USER_USER_INFO, TSPI_LineSendUserToUserInfo},
+ {OID_TAPI_SET_APP_SPECIFIC, TSPI_LineSetAppSpecific},
+ {OID_TAPI_SET_CALL_PARAMS, TSPI_LineSetCallParams},
+ {OID_TAPI_SET_DEFAULT_MEDIA_DETECTION, TSPI_LineSetDefaultMediaDetection},
+ {OID_TAPI_SET_DEV_CONFIG, TSPI_LineSetDevConfig},
+ {OID_TAPI_SET_MEDIA_MODE, TSPI_LineSetMediaMode},
+ {OID_TAPI_SET_STATUS_MESSAGES, TSPI_LineSetStatusMessage}
+ };
+
+#define MAX_TAPI_SUPPORTED_OIDS 34
+
+
+VOID
+(*CallStateProc[MAX_STATE][MAX_STATE])(CM*) =
+{
+ //
+ // LINE_ST_IDLE
+ //
+ {
+ NoSignal, // LINE_ST_IDLE
+ NoSignal, // LINE_ST_LISTEN
+ SignalCallProceeding, // LINE_ST_WAITCONN
+ SignalConnectSuccess, // LINE_ST_CONN
+ },
+
+ //
+ // LINE_ST_LISTEN
+ //
+ {
+ SignalListenFailure, // LINE_ST_IDLE
+ NoSignal, // LINE_ST_LISTEN
+ NoSignal, // LINE_ST_WAITCONN
+ SignalListenSuccess // LINE_ST_CONN
+ },
+
+ //
+ // LINE_ST_WAITCONN
+ //
+ {
+ SignalConnectFailure, // LINE_ST_IDLE
+ NoSignal, // LINE_ST_LISTEN
+ SignalCallProceeding, // LINE_ST_WAITCONN
+ SignalConnectSuccess // LINE_ST_CONN
+ },
+
+ //
+ // LINE_ST_CONN
+ //
+ {
+ SignalDisconnect, // LINE_ST_IDLE (only for incoming disconnect)
+ NoSignal, // LINE_ST_LISTEN
+ NoSignal, // LINE_ST_WAITCONN
+ NoSignal // LINE_ST_CONN
+ }
+};
+
+NDIS_STATUS
+TapiOidProc(
+ NDIS_HANDLE AdapterContext,
+ NDIS_OID Oid,
+ PVOID InfoBuffer,
+ ULONG InfoBufferLen,
+ PULONG BytesReadWritten,
+ PULONG BytesNeeded
+ )
+{
+ ADAPTER *Adapter = (ADAPTER*)AdapterContext;
+ ULONG n;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ for (n = 0; n < MAX_TAPI_SUPPORTED_OIDS; n++)
+ {
+ if (Oid == TapiOids[n].Oid)
+ {
+ Status = (*TapiOids[n].FuncPtr)(Adapter, InfoBuffer);
+ return(Status);
+ }
+ }
+ return(NDIS_STATUS_INVALID_OID);
+}
+
+
+NDIS_STATUS
+TSPI_LineAccept(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_ACCEPT TapiBuffer = (PNDIS_TAPI_ACCEPT)InfoBuffer;
+
+ D_LOG(D_ENTRY, ("LineAccept: hdCall: 0x%p", TapiBuffer->hdCall));
+
+// return(NDIS_STATUS_TAPI_OPERATIONUNAVAIL);
+ return(NDIS_STATUS_SUCCESS);
+
+}
+
+NDIS_STATUS
+TSPI_LineAnswer(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_ANSWER TapiBuffer = (PNDIS_TAPI_ANSWER)InfoBuffer;
+ TAPI_LINE_INFO* TapiLineInfo;
+ CM *cm;
+ CM_PROF *Prof;
+ ULONG Param1 = 0, Param2 = 0, Param3 = 0, m, n;
+
+ D_LOG(D_ENTRY, ("LineAnwser: hdCall: 0x%p", TapiBuffer->hdCall));
+ //
+ // validate call handle and get call pointer
+ //
+ cm = GetCallFromCallHandle(Adapter, TapiBuffer->hdCall);
+
+ if (cm == NULL)
+ return(NDIS_STATUS_TAPI_INVALCALLHANDLE);
+
+ //
+ // get the profile pointer for this call
+ //
+ Prof = (CM_PROF*)&cm->dprof;
+
+ TapiLineInfo = (TAPI_LINE_INFO*)cm->TapiLineInfo;
+
+ cm->TapiCallState = LINECALLSTATE_CONNECTED;
+
+ //
+ // indicate line event with callstate connected
+ //
+ Param1 = cm->TapiCallState;
+ Param3 = LINEMEDIAMODE_DIGITALDATA;
+ SendLineEvent(Adapter,
+ TapiLineInfo->htLine,
+ cm->htCall,
+ LINE_CALLSTATE,
+ &Param1,
+ &Param2,
+ &Param3);
+
+ mtl_set_conn_state(cm->mtl, Prof->chan_num, 1);
+
+ //
+ // indicate line up to wan wrapper
+ //
+ WanLineup(cm, NULL);
+
+ //
+ // mark idd resources as being in use
+ //
+ for (n = 0; n < Prof->chan_num; n++)
+ {
+ IDD *idd = Prof->chan_tbl[n].idd;
+
+ //
+ // this idd should not be busy yet
+ //
+ if (idd->CallInfo.ChannelsUsed < MAX_CHANNELS_PER_IDD)
+ {
+ //
+ // each idd can support two calls
+ //
+ for (m = 0; m < MAX_CHANNELS_PER_IDD; m++)
+ {
+ if (idd->CallInfo.cm[m] == NULL)
+ {
+ idd->CallInfo.cm[m] = cm;
+ idd->CallInfo.ChannelsUsed++;
+ break;
+ }
+ }
+ }
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineClose(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_CLOSE TapiBuffer = (PNDIS_TAPI_CLOSE)InfoBuffer;
+ TAPI_LINE_INFO* TapiLineInfo;
+ ULONG n;
+ CM *cm;
+
+ D_LOG(D_ENTRY, ("LineClose: hdLine: 0x%p", TapiBuffer->hdLine));
+
+ //
+ // validate line handle and get line pointer
+ //
+ TapiLineInfo = GetLineFromLineHandle(Adapter, TapiBuffer->hdLine);
+
+ if (TapiLineInfo == NULL)
+ return(NDIS_STATUS_FAILURE);
+
+ //
+ // store lineinfo pointer in line table
+ //
+// for (n = 0; n < MAX_IDD_PER_ADAPTER; n++)
+ for (n = 0; n < MAX_CM_PER_ADAPTER; n++)
+ {
+ if (Adapter->TapiLineInfo[n] == TapiLineInfo)
+ break;
+ }
+
+// if (n == MAX_IDD_PER_ADAPTER)
+ if (n == MAX_CM_PER_ADAPTER)
+ return(NDIS_STATUS_FAILURE);
+
+ Adapter->TapiLineInfo[n] = NULL;
+
+ //
+ // get backpointer to connection object
+ //
+ cm = TapiLineInfo->cm;
+
+ cm->TapiLineInfo = NULL;
+
+ //
+ // if call is active disconnect it
+ //
+ if (cm->TapiCallState != LINECALLSTATE_IDLE)
+ cm_disconnect(cm);
+
+ //
+ // destroy line object
+ //
+ NdisFreeMemory((PVOID)TapiLineInfo,
+ sizeof(TAPI_LINE_INFO),
+ 0);
+
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+TSPI_LineCloseCall(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_CLOSE_CALL TapiBuffer = (PNDIS_TAPI_CLOSE_CALL)InfoBuffer;
+ TAPI_LINE_INFO* TapiLineInfo;
+ CM* cm;
+
+ D_LOG(D_ENTRY, ("LineCloseCall: hdCall: 0x%p", TapiBuffer->hdCall));
+
+ //
+ // validate call handle and get call pointer
+ //
+ cm = GetCallFromCallHandle(Adapter, TapiBuffer->hdCall);
+
+ if (cm == NULL)
+ return(NDIS_STATUS_TAPI_INVALCALLHANDLE);
+
+ //
+ // get line info pointer
+ //
+ TapiLineInfo = (TAPI_LINE_INFO*)cm->TapiLineInfo;
+
+ //
+ // if call is active disconnect it
+ //
+ if (cm->TapiCallState != LINECALLSTATE_IDLE)
+ cm_disconnect(cm);
+
+ cm->TapiCallState = LINECALLSTATE_IDLE;
+ cm->htCall = (HTAPI_CALL)NULL;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineConditionalMediaDetect(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_CONDITIONAL_MEDIA_DETECTION TapiBuffer = (PNDIS_TAPI_CONDITIONAL_MEDIA_DETECTION)InfoBuffer;
+ TAPI_LINE_INFO* TapiLineInfo;
+
+ D_LOG(D_ENTRY, ("LineConditionalMediaDetect: hdLine: 0x%p, MediaModes: 0x%x", TapiBuffer->hdLine, TapiBuffer->ulMediaModes));
+
+ //
+ // validate line handle and get line pointer
+ //
+ TapiLineInfo = GetLineFromLineHandle(Adapter, TapiBuffer->hdLine);
+
+ if (TapiLineInfo == NULL)
+ return(NDIS_STATUS_TAPI_INVALLINEHANDLE);
+
+ if (TapiBuffer->ulMediaModes &
+ (TapiLineInfo->MediaModes ^ 0xFFFFFFFF))
+ return(NDIS_STATUS_TAPI_INVALMEDIAMODE);
+
+ if (TapiBuffer->LineCallParams.ulBearerMode &
+ (TapiLineInfo->BearerModes ^ 0xFFFFFFFF))
+ return(NDIS_STATUS_TAPI_RESOURCEUNAVAIL);
+
+ if ((TapiBuffer->LineCallParams.ulMinRate < 56000) ||
+ (TapiBuffer->LineCallParams.ulMaxRate > 64000))
+ return(NDIS_STATUS_TAPI_RESOURCEUNAVAIL);
+
+ if (TapiBuffer->LineCallParams.ulAddressMode != LINEADDRESSMODE_ADDRESSID)
+ return(NDIS_STATUS_TAPI_RESOURCEUNAVAIL);
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineConfigDialog(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_CONFIG_DIALOG TapiBuffer = (PNDIS_TAPI_CONFIG_DIALOG)InfoBuffer;
+
+ D_LOG(D_ENTRY, ("LineConfigDialog: DeviceID: 0x%x", TapiBuffer->ulDeviceID));
+
+ return(NDIS_STATUS_TAPI_OPERATIONUNAVAIL);
+}
+
+NDIS_STATUS
+TSPI_LineDevSpecific(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_DEV_SPECIFIC TapiBuffer = (PNDIS_TAPI_DEV_SPECIFIC)InfoBuffer;
+ TAPI_LINE_INFO* TapiLineInfo;
+
+ D_LOG(D_ENTRY, ("LineDevSpecific: hdLine: 0x%p, hdCall: 0x%p, AddressID: 0x%x", \
+ TapiBuffer->hdLine, TapiBuffer->hdCall, TapiBuffer->ulAddressID));
+ //
+ // validate line handle and get line pointer
+ //
+ TapiLineInfo = GetLineFromLineHandle(Adapter, TapiBuffer->hdLine);
+
+ if (TapiLineInfo == NULL)
+ return(NDIS_STATUS_TAPI_INVALLINEHANDLE);
+
+ return(NDIS_STATUS_TAPI_OPERATIONUNAVAIL);
+}
+
+NDIS_STATUS
+TSPI_LineDial(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_DIAL TapiBuffer = (PNDIS_TAPI_DIAL)InfoBuffer;
+ TAPI_LINE_INFO* TapiLineInfo;
+ CM_PROF* Prof;
+ CM* cm;
+
+ D_LOG(D_ENTRY, ("LineDial: hdCall: 0x%p", TapiBuffer->hdCall));
+
+ //
+ // validate call handle and get call pointer
+ //
+ cm = GetCallFromCallHandle(Adapter, TapiBuffer->hdCall);
+
+ if (cm == NULL)
+ return(NDIS_STATUS_TAPI_INVALCALLHANDLE);
+
+ if (cm->TapiCallState != LINECALLSTATE_IDLE)
+ return(NDIS_STATUS_TAPI_INVALCALLSTATE);
+
+ //
+ // get pointer to line
+ //
+ TapiLineInfo = (TAPI_LINE_INFO*)cm->TapiLineInfo;
+
+ //
+ // check address size if zero return error
+ //
+ if (TapiBuffer->ulDestAddressSize == 0)
+ return(NDIS_STATUS_TAPI_INVALADDRESS);
+
+ //
+ // get profile for this call
+ //
+ Prof = (CM_PROF*)&cm->oprof;
+
+ //
+ // parse address and put in cm
+ //
+ StashAddress(Prof, TapiBuffer->ulDestAddressSize, TapiBuffer->szDestAddress);
+
+ //
+ // get a line to call on
+ //
+ if (FindAndStashIdd(cm, Prof))
+ return(NDIS_STATUS_TAPI_RESOURCEUNAVAIL);
+
+ //
+ // set initial line state
+ //
+ cm->CallState = CALL_ST_WAITCONN;
+
+ //
+ // figure out call type
+ //
+ cm->ConnectionType = CM_PPP;
+
+ //
+ // attempt call
+ //
+ cm_connect(cm);
+
+ cm->TapiCallState = LINECALLSTATE_PROCEEDING;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineDrop(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_DROP TapiBuffer = (PNDIS_TAPI_DROP)InfoBuffer;
+ TAPI_LINE_INFO* TapiLineInfo;
+ CM* cm;
+ CM_PROF *Prof;
+ ULONG Param1 = 0, Param2 = 0, Param3 = 0;
+
+ D_LOG(D_ENTRY, ("LineDrop: hdCall: 0x%p", TapiBuffer->hdCall));
+
+ //
+ // validate call handle and get call pointer
+ //
+ cm = GetCallFromCallHandle(Adapter, TapiBuffer->hdCall);
+
+ if (cm == NULL)
+ return(NDIS_STATUS_TAPI_INVALCALLHANDLE);
+
+ //
+ // get line info pointer
+ //
+ TapiLineInfo = (TAPI_LINE_INFO*)cm->TapiLineInfo;
+
+ cm->CallState = CALL_ST_IDLE;
+
+ //
+ // disconnect the call
+ //
+ if (cm->TapiCallState != LINECALLSTATE_DISCONNECTED &&
+ cm->TapiCallState != LINECALLSTATE_BUSY)
+ cm_disconnect(cm);
+
+ //
+ // indicate linedown to wan wrapper
+ //
+ if (cm->LinkHandle)
+ WanLinedown(cm);
+
+ //
+ // send call state to idle
+ //
+ cm->TapiCallState = LINECALLSTATE_IDLE;
+
+ //
+ // send a call state idle message to the app
+ //
+ Param1 = cm->TapiCallState;
+ SendLineEvent(Adapter,
+ TapiLineInfo->htLine,
+ cm->htCall,
+ LINE_CALLSTATE,
+ &Param1,
+ &Param2,
+ &Param3);
+
+
+ //
+ // if this was a listening Line reissue a listen
+ //
+ if (TapiLineInfo->TapiLineWasListening)
+ {
+ Prof = (CM_PROF*)&cm->oprof;
+ SetDefaultListenProf(Prof, GetIDFromLine(Adapter, TapiLineInfo));
+ cm_listen(cm);
+ cm->CallState = CALL_ST_LISTEN;
+ }
+
+ FreeIddCallResources(cm);
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineGetAddressCaps(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_GET_ADDRESS_CAPS TapiBuffer = (PNDIS_TAPI_GET_ADDRESS_CAPS)InfoBuffer;
+ LINE_ADDRESS_CAPS* AddressCaps = &TapiBuffer->LineAddressCaps;
+ ULONG AddressLength, AvailMem;
+ CM *cm;
+
+ D_LOG(D_ENTRY, ("LineGetAddressCaps: DeviceID: 0x%x", TapiBuffer->ulDeviceID));
+ //
+ // Validate extension
+ //
+ VALIDATE_EXTENSION(TapiBuffer->ulExtVersion);
+
+ //
+ // only support two addresss per line
+ //
+ if (TapiBuffer->ulAddressID > MAX_CALL_PER_LINE)
+ return(NDIS_STATUS_TAPI_INVALADDRESSID);
+
+ //
+ // get conn object that is or would be attached to this line
+ //
+// cm = GetCmFromDeviceID (Adapter,
+// TapiBuffer->ulDeviceID,
+// TapiBuffer->ulAddressID);
+ cm = GetCmFromDeviceID (Adapter,
+ TapiBuffer->ulDeviceID);
+
+ if (cm == NULL)
+ return(NDIS_STATUS_TAPI_INVALADDRESSID);
+
+ //
+ // validate structure size
+ //
+ AddressLength = strlen(cm->LocalAddress);
+ AddressCaps->ulNeededSize = sizeof(LINE_ADDRESS_CAPS) + AddressLength;
+ AddressCaps->ulUsedSize = sizeof(LINE_ADDRESS_CAPS);
+
+ AvailMem = AddressCaps->ulTotalSize - AddressCaps->ulUsedSize;
+
+ if (AvailMem > 0)
+ {
+ ULONG SizeToCopy = (((ULONG)AvailMem > AddressLength) ?
+ AddressLength : AvailMem);
+
+ NdisMoveMemory(((LPSTR)AddressCaps) + AddressCaps->ulUsedSize,
+ cm->LocalAddress, SizeToCopy);
+
+ AddressCaps->ulAddressSize = SizeToCopy;
+ AddressCaps->ulAddressOffset = AddressCaps->ulUsedSize;
+ AddressCaps->ulUsedSize += SizeToCopy;
+ AvailMem -= SizeToCopy;
+ }
+
+ //
+ // fill structure
+ //
+ AddressCaps->ulLineDeviceID = TapiBuffer->ulDeviceID;
+
+ AddressCaps->ulDevSpecificSize = 0;
+ AddressCaps->ulDevSpecificOffset = 0;
+
+ AddressCaps->ulAddressSharing = LINEADDRESSSHARING_PRIVATE;
+ AddressCaps->ulAddressStates = LINEADDRESSSTATE_OTHER |
+ LINEADDRESSSTATE_INUSEZERO |
+ LINEADDRESSSTATE_INUSEONE |
+ LINEADDRESSSTATE_NUMCALLS;
+
+ AddressCaps->ulCallInfoStates = LINECALLINFOSTATE_CALLERID |
+ LINECALLINFOSTATE_CALLEDID;
+
+ AddressCaps->ulCallerIDFlags = LINECALLPARTYID_ADDRESS |
+ LINECALLPARTYID_UNAVAIL;
+
+ AddressCaps->ulCalledIDFlags = LINECALLPARTYID_ADDRESS |
+ LINECALLPARTYID_UNAVAIL;
+
+ AddressCaps->ulConnectedIDFlags = LINECALLPARTYID_UNAVAIL;
+
+ AddressCaps->ulRedirectionIDFlags = LINECALLPARTYID_UNAVAIL;
+
+ AddressCaps->ulRedirectingIDFlags = LINECALLPARTYID_UNAVAIL;
+
+ AddressCaps->ulCallStates = LINECALLSTATE_IDLE |
+ LINECALLSTATE_OFFERING |
+// LINECALLSTATE_BUSY |
+ LINECALLSTATE_CONNECTED |
+ LINECALLSTATE_PROCEEDING |
+ LINECALLSTATE_DISCONNECTED |
+ LINECALLSTATE_SPECIALINFO |
+ LINECALLSTATE_UNKNOWN;
+
+ AddressCaps->ulDialToneModes = LINEDIALTONEMODE_UNAVAIL;
+
+ AddressCaps->ulBusyModes = LINEBUSYMODE_UNAVAIL;
+
+ AddressCaps->ulSpecialInfo = LINESPECIALINFO_UNAVAIL;
+
+ AddressCaps->ulDisconnectModes = LINEDISCONNECTMODE_UNKNOWN;
+
+ AddressCaps->ulMaxNumActiveCalls = 1;
+ AddressCaps->ulMaxNumOnHoldCalls = 0;
+ AddressCaps->ulMaxNumOnHoldPendingCalls = 0;
+ AddressCaps->ulMaxNumConference = 0;
+ AddressCaps->ulMaxNumTransConf = 0;
+
+ AddressCaps->ulAddrCapFlags = LINEADDRCAPFLAGS_DIALED;
+
+ AddressCaps->ulCallFeatures = LINECALLFEATURE_ANSWER |
+ LINECALLFEATURE_DIAL |
+ LINECALLFEATURE_DROP;
+
+ AddressCaps->ulRemoveFromConfCaps = 0;
+ AddressCaps->ulRemoveFromConfState = 0;
+ AddressCaps->ulTransferModes = 0;
+ AddressCaps->ulParkModes = 0;
+
+ AddressCaps->ulForwardModes = 0;
+ AddressCaps->ulMaxForwardEntries = 0;
+ AddressCaps->ulMaxSpecificEntries = 0;
+ AddressCaps->ulMinFwdNumRings = 0;
+ AddressCaps->ulMaxFwdNumRings = 0;
+
+ AddressCaps->ulMaxCallCompletions = 0;
+ AddressCaps->ulCallCompletionConds = 0;
+ AddressCaps->ulCallCompletionModes = 0;
+ AddressCaps->ulNumCompletionMessages = 0;
+ AddressCaps->ulCompletionMsgTextEntrySize = 0;
+ AddressCaps->ulCompletionMsgTextSize = 0;
+ AddressCaps->ulCompletionMsgTextOffset = 0;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineGetAddressID(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_GET_ADDRESS_ID TapiBuffer = (PNDIS_TAPI_GET_ADDRESS_ID)InfoBuffer;
+ TAPI_LINE_INFO* TapiLineInfo;
+ CM *cm;
+ UCHAR *LocalAddress;
+
+ D_LOG(D_ENTRY, ("LineGetAddressID: hdLine: 0x%p, AddressMode: 0x%x", TapiBuffer->hdLine, TapiBuffer->ulAddressMode));
+
+ //
+ // validate line handle and get line pointer
+ //
+ TapiLineInfo = GetLineFromLineHandle(Adapter, TapiBuffer->hdLine);
+
+ if (TapiLineInfo == NULL)
+ return(NDIS_STATUS_TAPI_INVALLINEHANDLE);
+
+ cm = TapiLineInfo->cm;
+
+ LocalAddress = cm->LocalAddress;
+
+ //
+ // return address id
+ //
+ if (strncmp(LocalAddress, TapiBuffer->szAddress, TapiBuffer->ulAddressSize))
+ return(NDIS_STATUS_TAPI_INVALADDRESS);
+
+ TapiBuffer->ulAddressID = 0;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineGetAddressStatus(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_GET_ADDRESS_STATUS TapiBuffer = (PNDIS_TAPI_GET_ADDRESS_STATUS)InfoBuffer;
+ LINE_ADDRESS_STATUS* AddrStatus = &TapiBuffer->LineAddressStatus;
+ TAPI_LINE_INFO* TapiLineInfo;
+ CM *cm;
+
+ D_LOG(D_ENTRY, ("LineGetAddressStatus: hdLine: 0x%p, ulAddressID: 0x%x", TapiBuffer->hdLine, TapiBuffer->ulAddressID));
+
+ //
+ // validate line handle and get line pointer
+ //
+ TapiLineInfo = GetLineFromLineHandle(Adapter, TapiBuffer->hdLine);
+
+ if (TapiLineInfo == NULL)
+ return(NDIS_STATUS_TAPI_INVALLINEHANDLE);
+
+// if (TapiBuffer->ulAddressID > 1)
+// return(NDIS_STATUS_TAPI_INVALADDRESSID);
+
+ if (TapiBuffer->ulAddressID != 0)
+ return(NDIS_STATUS_TAPI_INVALADDRESSID);
+
+ AddrStatus->ulNeededSize = sizeof(LINE_ADDRESS_STATUS);
+
+ if (AddrStatus->ulNeededSize > AddrStatus->ulTotalSize)
+ return(NDIS_STATUS_TAPI_STRUCTURETOOSMALL);
+
+// cm = (CM*)TapiLineInfo->cm[TapiBuffer->ulAddressID];
+ cm = (CM*)TapiLineInfo->cm;
+
+ AddrStatus->ulUsedSize = AddrStatus->ulNeededSize;
+
+ AddrStatus->ulNumInUse = 1;
+
+ if (cm->TapiCallState == LINECALLSTATE_CONNECTED)
+ {
+ AddrStatus->ulNumActiveCalls = 1;
+ AddrStatus->ulAddressFeatures = 0;
+ }
+ else
+ {
+ AddrStatus->ulNumActiveCalls = 0;
+ AddrStatus->ulAddressFeatures = LINEADDRFEATURE_MAKECALL;
+ }
+
+ AddrStatus->ulNumOnHoldCalls = 0;
+ AddrStatus->ulNumOnHoldPendCalls = 0;
+ AddrStatus->ulNumRingsNoAnswer = 0;
+ AddrStatus->ulForwardNumEntries = 0;
+ AddrStatus->ulForwardSize = 0;
+ AddrStatus->ulForwardOffset = 0;
+ AddrStatus->ulTerminalModesSize = 0;
+ AddrStatus->ulTerminalModesOffset = 0;
+ AddrStatus->ulDevSpecificSize = 0;
+ AddrStatus->ulDevSpecificOffset = 0;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineGetCallAddressID(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_GET_CALL_ADDRESS_ID TapiBuffer = (PNDIS_TAPI_GET_CALL_ADDRESS_ID)InfoBuffer;
+ TAPI_LINE_INFO* TapiLineInfo;
+ CM *cm;
+
+ D_LOG(D_ENTRY, ("LineGetCallAddressID: hdCall: 0x%p", TapiBuffer->hdCall));
+
+ //
+ // validate call handle and get call pointer
+ //
+ cm = GetCallFromCallHandle(Adapter, TapiBuffer->hdCall);
+
+ if (cm == NULL)
+ return(NDIS_STATUS_TAPI_INVALCALLHANDLE);
+
+ TapiLineInfo = cm->TapiLineInfo;
+
+ if (TapiLineInfo->cm != cm)
+ return(NDIS_STATUS_FAILURE);
+
+ TapiBuffer->ulAddressID = 0;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineGetCallInfo(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_GET_CALL_INFO TapiBuffer = (PNDIS_TAPI_GET_CALL_INFO)InfoBuffer;
+ LINE_CALL_INFO* CallInfo = &TapiBuffer->LineCallInfo;
+ TAPI_LINE_INFO* TapiLineInfo;
+ CM* cm;
+
+ D_LOG(D_ENTRY, ("LineGetCallInfo: hdCall: 0x%p", TapiBuffer->hdCall));
+
+ //
+ // validate call handle and get call pointer
+ //
+ cm = GetCallFromCallHandle(Adapter, TapiBuffer->hdCall);
+
+ if (cm == NULL)
+ return(NDIS_STATUS_TAPI_INVALCALLHANDLE);
+
+ //
+ // get line handle
+ //
+ TapiLineInfo = cm->TapiLineInfo;
+
+ if (TapiLineInfo == NULL)
+ return(NDIS_STATUS_TAPI_INVALCALLHANDLE);
+
+ //
+ // validate structure size
+ //
+ CallInfo->ulNeededSize = sizeof(LINE_CALL_INFO);
+ CallInfo->ulUsedSize = 0;
+
+ if (CallInfo->ulNeededSize > CallInfo->ulTotalSize)
+ return(NDIS_STATUS_TAPI_STRUCTURETOOSMALL);
+
+ CallInfo->ulUsedSize = sizeof(LINE_CALL_INFO);
+
+ CallInfo->hLine = (ULONG)TapiLineInfo;
+ CallInfo->ulLineDeviceID = GetIDFromLine(Adapter, TapiLineInfo);
+
+ if (TapiLineInfo->cm != cm)
+ return(NDIS_STATUS_TAPI_INVALCALLHANDLE);
+
+ CallInfo->ulAddressID = 0;
+
+ D_LOG(D_ENTRY, ("LineGetCallInfo: AddressId: %d", CallInfo->ulAddressID));
+
+ CallInfo->ulBearerMode = TapiLineInfo->CurBearerMode;
+ CallInfo->ulRate = cm->speed;
+ CallInfo->ulMediaMode = TapiLineInfo->CurMediaMode;
+
+ CallInfo->ulAppSpecific = cm->AppSpecific;
+ CallInfo->ulCallID = 0;
+ CallInfo->ulRelatedCallID = 0;
+ CallInfo->ulCallParamFlags = 0;
+ CallInfo->ulCallStates = LINECALLSTATE_IDLE |
+ LINECALLSTATE_OFFERING |
+// LINECALLSTATE_BUSY |
+ LINECALLSTATE_CONNECTED |
+ LINECALLSTATE_DISCONNECTED |
+ LINECALLSTATE_SPECIALINFO |
+ LINECALLSTATE_UNKNOWN;
+
+
+ CallInfo->DialParams.ulDialPause = 0;
+ CallInfo->DialParams.ulDialSpeed = 0;
+ CallInfo->DialParams.ulDigitDuration = 0;
+ CallInfo->DialParams.ulWaitForDialtone = 0;
+
+ CallInfo->ulOrigin = (cm->was_listen) ? LINECALLORIGIN_EXTERNAL : LINECALLORIGIN_OUTBOUND;
+ CallInfo->ulReason = LINECALLREASON_UNAVAIL;
+ CallInfo->ulCompletionID = 0;
+
+ CallInfo->ulCountryCode = 0;
+ CallInfo->ulTrunk = (ULONG)-1;
+
+ //
+ // this should actually fill in called and
+ // calling address fields. we don't do this
+ // very well right now so I will defer this.
+ //
+ CallInfo->ulCallerIDFlags = LINECALLPARTYID_UNAVAIL;
+ CallInfo->ulCallerIDSize = 0;
+ CallInfo->ulCallerIDOffset = 0;
+ CallInfo->ulCallerIDNameSize = 0;
+ CallInfo->ulCallerIDNameOffset = 0;
+
+ CallInfo->ulCalledIDFlags = LINECALLPARTYID_UNAVAIL;
+ CallInfo->ulCalledIDSize = 0;
+ CallInfo->ulCalledIDOffset = 0;
+ CallInfo->ulCalledIDNameSize = 0;
+ CallInfo->ulCalledIDNameOffset = 0;
+
+ CallInfo->ulConnectedIDFlags = LINECALLPARTYID_UNAVAIL;
+ CallInfo->ulConnectedIDSize = 0;
+ CallInfo->ulConnectedIDOffset = 0;
+ CallInfo->ulConnectedIDNameSize = 0;
+ CallInfo->ulConnectedIDNameOffset = 0;
+
+ CallInfo->ulRedirectionIDFlags = LINECALLPARTYID_UNAVAIL;
+ CallInfo->ulRedirectionIDSize = 0;
+ CallInfo->ulRedirectionIDOffset = 0;
+ CallInfo->ulRedirectionIDNameSize = 0;
+ CallInfo->ulRedirectionIDNameOffset = 0;
+
+ CallInfo->ulRedirectingIDFlags = LINECALLPARTYID_UNAVAIL;
+ CallInfo->ulRedirectingIDSize = 0;
+ CallInfo->ulRedirectingIDOffset = 0;
+ CallInfo->ulRedirectingIDNameSize = 0;
+ CallInfo->ulRedirectingIDNameOffset = 0;
+
+ CallInfo->ulDisplaySize = 0;
+ CallInfo->ulDisplayOffset = 0;
+
+ CallInfo->ulUserUserInfoSize = 0;
+ CallInfo->ulUserUserInfoOffset = 0;
+
+ CallInfo->ulHighLevelCompSize = 0;
+ CallInfo->ulHighLevelCompOffset = 0;
+
+ CallInfo->ulLowLevelCompSize = 0;
+ CallInfo->ulLowLevelCompOffset = 0;
+
+ CallInfo->ulChargingInfoSize = 0;
+ CallInfo->ulChargingInfoOffset = 0;
+
+ CallInfo->ulTerminalModesSize = 0;
+ CallInfo->ulTerminalModesOffset = 0;
+
+ CallInfo->ulDevSpecificSize = 0;
+ CallInfo->ulDevSpecificOffset = 0;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineGetCallStatus(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_GET_CALL_STATUS TapiBuffer = (PNDIS_TAPI_GET_CALL_STATUS)InfoBuffer;
+ LINE_CALL_STATUS *CallStatus = &TapiBuffer->LineCallStatus;
+ CM *cm;
+
+ D_LOG(D_ENTRY, ("LineGetCallStatus: hdCall: 0x%p", TapiBuffer->hdCall));
+
+ //
+ // validate call handle and get call pointer
+ //
+ cm = GetCallFromCallHandle(Adapter, TapiBuffer->hdCall);
+
+ if (cm == NULL)
+ return(NDIS_STATUS_TAPI_INVALCALLHANDLE);
+
+ CallStatus->ulUsedSize = sizeof(LINE_CALL_STATUS);
+
+ CallStatus->ulCallState = cm->TapiCallState;
+
+ //
+ // fill the mode depending on the call state
+ // this should be done more intelligently
+ // i could find out more about why the call failed
+ // maybe later
+ //
+ switch (cm->TapiCallState)
+ {
+ case LINECALLSTATE_IDLE:
+ CallStatus->ulCallStateMode = 0;
+ CallStatus->ulCallFeatures = LINECALLFEATURE_DIAL;
+ break;
+
+ case LINECALLSTATE_CONNECTED:
+ CallStatus->ulCallStateMode = 0;
+ CallStatus->ulCallFeatures = LINECALLFEATURE_DROP;
+ break;
+
+ case LINECALLSTATE_OFFERING:
+ CallStatus->ulCallStateMode = 0;
+ CallStatus->ulCallFeatures = LINECALLFEATURE_ANSWER;
+ break;
+
+ case LINECALLSTATE_DISCONNECTED:
+ if (cm->CauseValue == 0x11 || cm->SignalValue == 0x04)
+ CallStatus->ulCallStateMode = LINEDISCONNECTMODE_BUSY;
+ else
+ CallStatus->ulCallStateMode = LINEDISCONNECTMODE_NOANSWER;
+ break;
+
+ case LINECALLSTATE_BUSY:
+ CallStatus->ulCallStateMode = LINEBUSYMODE_UNAVAIL;
+ break;
+
+ case LINECALLSTATE_SPECIALINFO:
+ if (cm->NoActiveLine)
+ CallStatus->ulCallStateMode = LINESPECIALINFO_NOCIRCUIT;
+ break;
+ }
+
+ CallStatus->ulDevSpecificSize = 0;
+ CallStatus->ulDevSpecificOffset = 0;
+
+ D_LOG(D_ENTRY, ("LineGetCallStatus: CallState: 0x%x, CallStateMode: 0x%x", CallStatus->ulCallState, CallStatus->ulCallStateMode));
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineGetDevCaps(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_GET_DEV_CAPS TapiBuffer = (PNDIS_TAPI_GET_DEV_CAPS)InfoBuffer;
+ ULONG ulProviderInfoSize, ulLineNameSize, ulTotalSize;
+ LINE_DEV_CAPS* DevCaps = &TapiBuffer->LineDevCaps;
+ ULONG AvailMem, LocalID;
+ CHAR LineName[32], ProviderName[32];
+
+
+ D_LOG(D_ENTRY, ("LineGetDevCaps: DeviceID: 0x%x", TapiBuffer->ulDeviceID));
+
+ //
+ // validate device ID
+ //
+
+ LocalID = TapiBuffer->ulDeviceID - Adapter->TapiBaseID;
+
+ //
+ // save size of buffer
+ //
+ ulTotalSize = DevCaps->ulTotalSize;
+
+ //
+ // clear buffer so all default params will be zero
+ //
+ NdisZeroMemory(DevCaps, ulTotalSize);
+
+ //
+ // restore total size
+ //
+ DevCaps->ulTotalSize = ulTotalSize;
+
+ DevCaps->ulUsedSize = sizeof(LINE_DEV_CAPS);
+
+//
+// Changed to support the new way that RAS is building TAPI names and
+// address's.
+//
+// sprintf(ProviderName,"DigiBoard Pcimac");
+// ulProviderInfoSize = strlen(ProviderName) + 1;
+
+ // Provider info is of the following format
+ // <media name>\0<device name>\0
+ // where - media name is - ISDN,
+ // device name is - Digiboard PCIMAC
+ //
+#define MEDIA_STR "ISDN"
+#define PROVIDER_STR "Pcimac"
+ sprintf(ProviderName,"%s%c%s%c", MEDIA_STR, '\0', PROVIDER_STR, '\0');
+ ulProviderInfoSize = strlen(MEDIA_STR) + strlen(PROVIDER_STR) + 2 ;
+
+ //
+ // should fill local id with something meaningfull
+ //
+ sprintf(LineName, "%s-%s%d", Adapter->Name,"Line", LocalID);
+ ulLineNameSize = strlen(LineName) + 1;
+
+ DevCaps->ulNeededSize = DevCaps->ulUsedSize +
+ ulProviderInfoSize +
+ ulLineNameSize;
+
+ AvailMem = DevCaps->ulTotalSize - DevCaps->ulUsedSize;
+
+ //
+ // fill provider info
+ //
+ if (AvailMem > 0)
+ {
+ ULONG SizeToCopy = (((ULONG)AvailMem > ulProviderInfoSize) ?
+ ulProviderInfoSize : AvailMem);
+
+ NdisMoveMemory(((LPSTR)DevCaps) + DevCaps->ulUsedSize,
+ ProviderName, SizeToCopy);
+
+ DevCaps->ulProviderInfoSize = SizeToCopy;
+ DevCaps->ulProviderInfoOffset = DevCaps->ulUsedSize;
+ DevCaps->ulUsedSize += SizeToCopy;
+ AvailMem -= SizeToCopy;
+ }
+
+ //
+ // fill line name info
+ //
+ if (AvailMem != 0)
+ {
+
+ ULONG SizeToCopy = (((ULONG)AvailMem > ulLineNameSize) ?
+ ulLineNameSize : AvailMem);
+
+ NdisMoveMemory(((LPSTR)DevCaps) + DevCaps->ulUsedSize,
+ Adapter->Name, SizeToCopy);
+
+ DevCaps->ulLineNameSize = SizeToCopy;
+ DevCaps->ulLineNameOffset = DevCaps->ulUsedSize;
+ DevCaps->ulUsedSize += SizeToCopy;
+ AvailMem -= SizeToCopy;
+ }
+
+ DevCaps->ulPermanentLineID = (ULONG)Adapter;
+ DevCaps->ulStringFormat = STRINGFORMAT_ASCII;
+ DevCaps->ulAddressModes = LINEADDRESSMODE_ADDRESSID;
+ DevCaps->ulNumAddresses = MAX_CALL_PER_LINE;
+ DevCaps->ulBearerModes = LINEBEARERMODE_VOICE |
+ LINEBEARERMODE_DATA;
+ DevCaps->ulMaxRate = 64000;
+ DevCaps->ulMediaModes = LINEMEDIAMODE_DIGITALDATA |
+ LINEMEDIAMODE_UNKNOWN;
+
+ DevCaps->ulMaxNumActiveCalls = MAX_CALL_PER_LINE;
+ DevCaps->ulLineStates = LINEDEVSTATE_CONNECTED |
+ LINEDEVSTATE_DISCONNECTED |
+ LINEDEVSTATE_OPEN |
+ LINEDEVSTATE_CLOSE |
+ LINEDEVSTATE_NUMCALLS |
+ LINEDEVSTATE_REINIT |
+ LINEDEVSTATE_INSERVICE |
+ LINEDEVSTATE_OUTOFSERVICE;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineGetDevConfig(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_GET_DEV_CONFIG TapiBuffer = (PNDIS_TAPI_GET_DEV_CONFIG)InfoBuffer;
+
+ D_LOG(D_ENTRY, ("LineGetDevConfig: DeviceID: 0x%x", TapiBuffer->ulDeviceID));
+
+ return(NDIS_STATUS_TAPI_OPERATIONUNAVAIL);
+}
+
+NDIS_STATUS
+TSPI_LineGetExtensionID(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_GET_EXTENSION_ID TapiBuffer = (PNDIS_TAPI_GET_EXTENSION_ID)InfoBuffer;
+
+ D_LOG(D_ENTRY, ("LineGetExtensionID: DeviceID: 0x%x", TapiBuffer->ulDeviceID));
+
+ //
+ // validate device ID
+ //
+ return(NDIS_STATUS_TAPI_OPERATIONUNAVAIL);
+}
+
+NDIS_STATUS
+TSPI_LineGetID(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_GET_ID TapiBuffer = (PNDIS_TAPI_GET_ID)InfoBuffer;
+ CHAR *DeviceClass = ((CHAR*)TapiBuffer) + TapiBuffer->ulDeviceClassOffset;
+ VAR_STRING *DeviceID = &TapiBuffer->DeviceID;
+ ULONG AvailMem, StringLength;
+ PVOID VarStringOffset;
+ TAPI_LINE_INFO* TapiLineInfo;
+ CM *cm;
+
+ D_LOG(D_ENTRY, ("LineGetID: Select: 0x%x, hdLine: 0x%p, AddressID: 0x%x, hdCall: 0x%p", \
+ TapiBuffer->ulSelect, TapiBuffer->hdLine, TapiBuffer->ulAddressID, TapiBuffer->hdCall));
+
+ switch (TapiBuffer->ulSelect)
+ {
+ case LINECALLSELECT_LINE:
+ //
+ // validate line handle and get line pointer
+ //
+ TapiLineInfo = GetLineFromLineHandle(Adapter, TapiBuffer->hdLine);
+
+ if (TapiLineInfo == NULL)
+ return(NDIS_STATUS_TAPI_INVALLINEHANDLE);
+
+ if (!_strnicmp(DeviceClass, "tapi/line", TapiBuffer->ulDeviceClassSize))
+ {
+ AvailMem = DeviceID->ulTotalSize - sizeof(VAR_STRING);
+ StringLength = (AvailMem > 4) ? 4 : AvailMem;
+ DeviceID->ulNeededSize = sizeof(VAR_STRING) + 4;
+ DeviceID->ulUsedSize = sizeof(VAR_STRING) + StringLength;
+ DeviceID->ulStringFormat = STRINGFORMAT_BINARY;
+ DeviceID->ulStringSize = StringLength;
+
+ VarStringOffset = ((CHAR*)&TapiBuffer->DeviceID) + sizeof(VAR_STRING);
+ NdisMoveMemory(VarStringOffset, &TapiLineInfo->LineID, StringLength);
+ DeviceID->ulStringOffset = sizeof(VAR_STRING);
+ return(NDIS_STATUS_SUCCESS);
+ }
+ break;
+
+ case LINECALLSELECT_ADDRESS:
+ if (TapiBuffer->ulAddressID > 1)
+ return(NDIS_STATUS_TAPI_INVALADDRESSID);
+ break;
+
+ case LINECALLSELECT_CALL:
+ //
+ // validate call handle and get call pointer
+ //
+ cm = GetCallFromCallHandle(Adapter, TapiBuffer->hdCall);
+
+ if (cm == NULL)
+ return(NDIS_STATUS_TAPI_INVALCALLHANDLE);
+
+ if (cm->TapiCallState != LINECALLSTATE_CONNECTED)
+ return(NDIS_STATUS_TAPI_INVALCALLHANDLE);
+
+ if (!_strnicmp(DeviceClass, "ndis", TapiBuffer->ulDeviceClassSize))
+ {
+ AvailMem = DeviceID->ulTotalSize - sizeof(VAR_STRING);
+ StringLength = (AvailMem > 4) ? 4 : AvailMem;
+ DeviceID->ulNeededSize = sizeof(VAR_STRING) + 4;
+ DeviceID->ulUsedSize = sizeof(VAR_STRING) + StringLength;
+ DeviceID->ulStringFormat = STRINGFORMAT_BINARY;
+ DeviceID->ulStringSize = StringLength;
+
+ VarStringOffset = ((CHAR*)TapiBuffer) + sizeof(NDIS_TAPI_GET_ID);
+ NdisMoveMemory(VarStringOffset, &cm->htCall, StringLength);
+ DeviceID->ulStringOffset = sizeof(VAR_STRING);
+ D_LOG(D_ALWAYS, ("LineGetID: Cookie: 0x%x", (ULONG)*(((CHAR*)TapiBuffer) + sizeof(NDIS_TAPI_GET_ID))));
+ return(NDIS_STATUS_SUCCESS);
+ }
+ }
+ return(NDIS_STATUS_TAPI_INVALDEVICECLASS);
+}
+
+NDIS_STATUS
+TSPI_LineGetLineDevStatus(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_GET_LINE_DEV_STATUS TapiBuffer = (PNDIS_TAPI_GET_LINE_DEV_STATUS)InfoBuffer;
+ TAPI_LINE_INFO *TapiLineInfo;
+ LINE_DEV_STATUS *DevStatus = (LINE_DEV_STATUS*)&TapiBuffer->LineDevStatus;
+ CM *cm;
+
+ D_LOG(D_ENTRY, ("LineGetLineDevStatus: hdLine: 0x%p", TapiBuffer->hdLine));
+
+ //
+ // validate line handle and get line pointer
+ //
+ TapiLineInfo = GetLineFromLineHandle(Adapter, TapiBuffer->hdLine);
+
+ if (TapiLineInfo == NULL)
+ return(NDIS_STATUS_TAPI_INVALLINEHANDLE);
+
+ DevStatus->ulNeededSize = 0;
+ DevStatus->ulUsedSize = sizeof (LINE_DEV_STATUS);
+
+ cm = (CM*)TapiLineInfo->cm;
+
+ if (cm->TapiCallState == LINECALLSTATE_CONNECTED)
+ DevStatus->ulNumActiveCalls++;
+
+ DevStatus->ulNumOnHoldCalls = 0;
+ DevStatus->ulNumOnHoldPendCalls = 0;
+ DevStatus->ulLineFeatures = LINEFEATURE_MAKECALL;
+ DevStatus->ulNumCallCompletions = 0;
+ DevStatus->ulRingMode = 0;
+
+ DevStatus->ulRoamMode = 0;
+
+ if (TapiLineInfo->TapiLineState == LINEDEVSTATE_INSERVICE)
+ {
+ DevStatus->ulDevStatusFlags = LINEDEVSTATUSFLAGS_CONNECTED |
+ LINEDEVSTATUSFLAGS_INSERVICE;
+ DevStatus->ulSignalLevel = 0xFFFF;
+ DevStatus->ulBatteryLevel = 0xFFFF;
+ }
+ else
+ {
+ DevStatus->ulDevStatusFlags = 0;
+ DevStatus->ulSignalLevel = 0;
+ DevStatus->ulBatteryLevel = 0;
+ }
+
+ DevStatus->ulTerminalModesSize = 0;
+ DevStatus->ulTerminalModesOffset = 0;
+
+ DevStatus->ulDevSpecificSize = 0;
+ DevStatus->ulDevSpecificOffset = 0;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineMakeCall(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_MAKE_CALL TapiBuffer = (PNDIS_TAPI_MAKE_CALL)InfoBuffer;
+ TAPI_LINE_INFO* TapiLineInfo;
+ LINE_CALL_PARAMS* CallParams = (LINE_CALL_PARAMS*)&TapiBuffer->LineCallParams;
+ CM_PROF* Prof;
+ PUCHAR DialAddress;
+ CM* cm = NULL;
+ INT Ret, n;
+ ULONG ChannelsFilled;
+
+ D_LOG(D_ENTRY, ("LineMakeCall: hdLine: 0x%p, htCall: 0x%p", \
+ TapiBuffer->hdLine, TapiBuffer->htCall));
+
+ //
+ // validate line handle and get line pointer
+ //
+ TapiLineInfo = GetLineFromLineHandle(Adapter, TapiBuffer->hdLine);
+
+ if (TapiLineInfo == NULL)
+ return(NDIS_STATUS_TAPI_INVALLINEHANDLE);
+
+ //
+ // get a device to call on
+ //
+ if (TapiBuffer->bUseDefaultLineCallParams)
+ cm = (CM*)TapiLineInfo->cm;
+ else
+ {
+ if (CallParams->ulAddressMode == LINEADDRESSMODE_ADDRESSID)
+ {
+ if (CallParams->ulAddressID < MAX_CALL_PER_LINE)
+ cm = (CM*)TapiLineInfo->cm;
+ else
+ return(NDIS_STATUS_TAPI_INVALADDRESSID);
+
+ }
+// else if (CallParams->ulAddressMode == LINEADDRESSMODE_DIALABLEADDR)
+ else
+ {
+ cm = (CM*)TapiLineInfo->cm;
+
+ if (strncmp(cm->LocalAddress,
+ ((PUCHAR)CallParams) + CallParams->ulOrigAddressOffset,
+ CallParams->ulOrigAddressSize))
+ return(NDIS_STATUS_TAPI_INVALADDRESS);
+ }
+// else
+// return(NDIS_STATUS_TAPI_INVALADDRESS);
+ }
+
+ if (cm == NULL)
+ return(NDIS_STATUS_TAPI_INVALADDRESS);
+
+ Prof = &cm->oprof;
+
+ //
+ // set default calling profile
+ //
+ SetDefaultCallingProf(Prof, GetIDFromLine(Adapter, TapiLineInfo));
+
+ if (!TapiBuffer->bUseDefaultLineCallParams)
+ {
+ //
+ // check address size if zero return error
+ //
+ if (TapiBuffer->ulDestAddressSize == 0)
+ return(NDIS_STATUS_TAPI_INVALADDRESS);
+
+ //
+ // check media mode and make sure we support it
+ //
+ if (CallParams->ulMediaMode &
+ (TapiLineInfo->MediaModes ^ 0xFFFFFFFF))
+ return(NDIS_STATUS_TAPI_INVALMEDIAMODE);
+
+ TapiLineInfo->CurMediaMode = CallParams->ulMediaMode;
+
+ //
+ // check bearer mode and make sure we support it
+ //
+ if (CallParams->ulBearerMode &
+ (TapiLineInfo->BearerModes ^ 0xFFFFFFFF))
+ return(NDIS_STATUS_TAPI_RESOURCEUNAVAIL);
+
+ TapiLineInfo->CurBearerMode = CallParams->ulBearerMode;
+
+ //
+ // check min-max rate
+ //
+ if ((CallParams->ulMinRate < 56000) ||
+ (CallParams->ulMaxRate > (8 * 64000)))
+ return(NDIS_STATUS_TAPI_RESOURCEUNAVAIL);
+
+ //
+ // how many channels is this for
+ //
+ Prof->chan_num = (USHORT)(CallParams->ulMaxRate / 64000);
+
+ if (CallParams->ulMaxRate > (ULONG)(Prof->chan_num * 64000))
+ Prof->chan_num++;
+
+ //
+ // figure out what the connection is for
+ // right now assume all single channel connections are PPP
+ //
+ if (Prof->chan_num == 1)
+ cm->ConnectionType = CM_PPP;
+ else
+ cm->ConnectionType = CM_DKF;
+
+ //
+ // if max and min are equal set fallback to off
+ //
+ if (CallParams->ulMinRate == CallParams->ulMaxRate)
+ Prof->fallback = 0;
+
+ //
+ // we need to set these params for all channels involved
+ //
+ for (n = 0; n < Prof->chan_num; n++)
+ {
+ //
+ // from bearer mode and min-max rate set channel type
+ //
+ if (CallParams->ulBearerMode & LINEBEARERMODE_VOICE)
+ Prof->chan_tbl[n].type = 2;
+ else
+ {
+ if ( 1 == (CallParams->ulMaxRate / (64000 * Prof->chan_num)))
+ Prof->chan_tbl[n].type = 0;
+ else
+ Prof->chan_tbl[n].type = 1;
+ }
+
+ //
+ // accept any bchannel that the switch will give us
+ //
+ Prof->chan_tbl[n].bchan = 2;
+ }
+ }
+
+ //
+ // get a line to call on
+ //
+ ChannelsFilled = FindAndStashIdd(cm, Prof);
+
+ D_LOG(D_ALWAYS, ("LineMakeCall: ChannelsFilled %d", ChannelsFilled));
+ //
+ // if there are no channels available we should report an error
+ //
+ if (!ChannelsFilled)
+ return(NDIS_STATUS_TAPI_INUSE);
+
+ if (ChannelsFilled < Prof->chan_num)
+ {
+ if(Prof->fallback)
+ Prof->chan_num = (USHORT)ChannelsFilled;
+ else
+ {
+ FreeIddCallResources(cm);
+ return(NDIS_STATUS_TAPI_INUSE);
+ }
+ }
+
+ //
+ // get pointer to dial address
+ //
+ DialAddress = ((PUCHAR)TapiBuffer) + TapiBuffer->ulDestAddressOffset;
+
+ //
+ // parse address and put in cm
+ //
+ StashAddress(Prof, TapiBuffer->ulDestAddressSize, DialAddress);
+
+ //
+ // set initial line state
+ //
+ cm->CallState = CALL_ST_WAITCONN;
+
+ //
+ // save tapi's call handle
+ //
+ cm->htCall = TapiBuffer->htCall;
+
+ //
+ // clear out link handle
+ //
+ cm->LinkHandle = NULL;
+
+ //
+ // clear the PPPToRas Flag
+ //
+ cm->PPPToDKF = 0;
+
+ //
+ // return our call handle
+ //
+ TapiBuffer->hdCall = (HDRV_CALL)cm;
+
+ D_LOG(D_ENTRY, ("LineMakeCall: hdLine: 0x%p", TapiLineInfo));
+
+ cm->TapiCallState = LINECALLSTATE_PROCEEDING;
+
+ //
+ // attempt call
+ //
+ D_LOG(D_ALWAYS, ("LineMakeCall"));
+
+ Ret = cm_connect(cm);
+
+ D_LOG(D_EXIT, ("LineMakeCall: Ret: 0x%x", Ret));
+
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineNegotiateExtVersion(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_NEGOTIATE_EXT_VERSION TapiBuffer = (PNDIS_TAPI_NEGOTIATE_EXT_VERSION)InfoBuffer;
+
+ D_LOG(D_ENTRY, ("LineNegotiateExtVersion: DeviceID: 0x%x", TapiBuffer->ulDeviceID));
+
+ return(NDIS_STATUS_TAPI_OPERATIONUNAVAIL);
+}
+
+NDIS_STATUS
+TSPI_LineOpen(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_OPEN TapiBuffer = (PNDIS_TAPI_OPEN)InfoBuffer;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ TAPI_LINE_INFO* TapiLineInfo;
+ NDIS_PHYSICAL_ADDRESS HighestAcceptableMax = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
+ CM *cm;
+ ULONG n;
+
+ D_LOG(D_ENTRY, ("LineOpen: DeviceID: 0x%x, htLine: 0x%p", \
+ TapiBuffer->ulDeviceID, TapiBuffer->htLine));
+
+ //
+ // verify device id
+ //
+ cm = GetCmFromDeviceID(Adapter, TapiBuffer->ulDeviceID);
+
+ if (cm == NULL)
+ return(NDIS_STATUS_FAILURE);
+
+ Status = NdisAllocateMemory((PVOID)&TapiLineInfo,
+ sizeof(TAPI_LINE_INFO),
+ 0,
+ HighestAcceptableMax);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ return(NDIS_STATUS_TAPI_RESOURCEUNAVAIL);
+
+ NdisZeroMemory(TapiLineInfo, sizeof(TAPI_LINE_INFO));
+
+ //
+ // store lineinfo pointer in line table
+ //
+ for (n = 0; n < MAX_CM_PER_ADAPTER; n++)
+ {
+ if (Adapter->TapiLineInfo[n] == NULL)
+ break;
+ }
+ if (n == MAX_CM_PER_ADAPTER)
+ return(NDIS_STATUS_FAILURE);
+
+ D_LOG(D_ENTRY, ("LineOpen: hdLine: 0x%p", TapiLineInfo));
+
+ TapiBuffer->hdLine = (ULONG)TapiLineInfo;
+
+ TapiLineInfo->cm = cm;
+ cm->TapiLineInfo = TapiLineInfo;
+ cm->CallState = CALL_ST_IDLE;
+
+ Adapter->TapiLineInfo[n] = TapiLineInfo;
+
+ TapiLineInfo->LineID = TapiBuffer->ulDeviceID;
+
+ TapiLineInfo->Adapter = Adapter;
+
+ TapiLineInfo->idd = cm->idd;
+
+ TapiLineInfo->htLine = TapiBuffer->htLine;
+
+ TapiLineInfo->MediaModes = LINEMEDIAMODE_DIGITALDATA |
+ LINEMEDIAMODE_UNKNOWN;
+
+ TapiLineInfo->BearerModes = LINEBEARERMODE_VOICE |
+ LINEBEARERMODE_DATA;
+
+ TapiLineInfo->TapiLineState = LINEDEVSTATE_INSERVICE |
+ LINEDEVSTATE_OPEN;
+
+ D_LOG(D_ENTRY, ("LineOpen: hdLine: 0x%p", TapiBuffer->hdLine));
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_ProviderInit(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_PROVIDER_INITIALIZE TapiBuffer = (PNDIS_TAPI_PROVIDER_INITIALIZE)InfoBuffer;
+
+ D_LOG(D_ENTRY, ("ProviderInit: Adapter: 0x%x, IDBase: 0x%x", Adapter, TapiBuffer->ulDeviceIDBase));
+
+ //
+ // save our Base ID
+ //
+ Adapter->TapiBaseID = TapiBuffer->ulDeviceIDBase;
+
+ //
+ // enumerate the number of lines for this adapter
+ // and return
+ //
+// TapiBuffer->ulNumLineDevs = EnumIddPerAdapter(Adapter);
+ TapiBuffer->ulNumLineDevs = EnumCmPerAdapter(Adapter);
+
+ //
+ // return our provider ID
+ //
+ TapiBuffer->ulProviderID = (ULONG)Adapter;
+
+ D_LOG(D_ALWAYS, ("NumLines: 0x%x, ProviderID: 0x%x", \
+ TapiBuffer->ulNumLineDevs, TapiBuffer->ulProviderID));
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_ProviderShutdown(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_PROVIDER_SHUTDOWN TapiBuffer = (PNDIS_TAPI_PROVIDER_SHUTDOWN)InfoBuffer;
+ ULONG n;
+
+ D_LOG(D_ENTRY, ("ProviderShutdown"));
+
+ for (n = 0; Adapter->CmTbl[n] && n < MAX_CM_PER_ADAPTER; n++)
+ {
+ CM* cm = Adapter->CmTbl[n];
+
+ //
+ // complete all outstanding async events
+ // terminate all calls
+ // close any open lines
+ //
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineSecureCall(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_SECURE_CALL TapiBuffer = (PNDIS_TAPI_SECURE_CALL)InfoBuffer;
+
+ D_LOG(D_ENTRY, ("LineSecureCall: hdCall: 0x%p", TapiBuffer->hdCall));
+
+ return(NDIS_STATUS_TAPI_OPERATIONUNAVAIL);
+}
+
+NDIS_STATUS
+TSPI_LineSelectExtVersion(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_SELECT_EXT_VERSION TapiBuffer = (PNDIS_TAPI_SELECT_EXT_VERSION)InfoBuffer;
+ TAPI_LINE_INFO* TapiLineInfo;
+
+ D_LOG(D_ENTRY, ("LineSelectExtVersion: hdLine: 0x%p", TapiBuffer->hdLine));
+
+ //
+ // validate line handle and get line pointer
+ //
+ TapiLineInfo = GetLineFromLineHandle(Adapter, TapiBuffer->hdLine);
+
+ if (TapiLineInfo == NULL)
+ return(NDIS_STATUS_TAPI_INVALLINEHANDLE);
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineSendUserToUserInfo(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_SEND_USER_USER_INFO TapiBuffer = (PNDIS_TAPI_SEND_USER_USER_INFO)InfoBuffer;
+
+ D_LOG(D_ENTRY, ("LineSendUserToUserInfo: hdCall: 0x%p", TapiBuffer->hdCall));
+
+ return(NDIS_STATUS_TAPI_OPERATIONUNAVAIL);
+}
+
+NDIS_STATUS
+TSPI_LineSetAppSpecific(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_SET_APP_SPECIFIC TapiBuffer = (PNDIS_TAPI_SET_APP_SPECIFIC)InfoBuffer;
+ CM *cm;
+
+ D_LOG(D_ENTRY, ("LineSetAppSpecific: hdCall: 0x%p", TapiBuffer->hdCall));
+
+ //
+ // validate call handle and get call pointer
+ //
+ cm = GetCallFromCallHandle(Adapter, TapiBuffer->hdCall);
+
+ if (cm == NULL)
+ return(NDIS_STATUS_TAPI_INVALCALLHANDLE);
+
+ cm->AppSpecific = TapiBuffer->ulAppSpecific;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineSetCallParams(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_SET_CALL_PARAMS TapiBuffer = (PNDIS_TAPI_SET_CALL_PARAMS)InfoBuffer;
+ CM *cm;
+
+ D_LOG(D_ENTRY, ("LineSetCallParams: hdCall: 0x%p", TapiBuffer->hdCall));
+ D_LOG(D_ENTRY, ("BearerMode: 0x%x, MinRate: 0x%x, MaxRate: 0x%x", \
+ TapiBuffer->ulBearerMode, TapiBuffer->ulMinRate, TapiBuffer->ulMaxRate));
+
+ //
+ // validate call handle and get call pointer
+ //
+ cm = GetCallFromCallHandle(Adapter, TapiBuffer->hdCall);
+
+ if (cm == NULL)
+ return(NDIS_STATUS_TAPI_INVALCALLHANDLE);
+
+ //
+ // should set some profile things here
+ //
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineSetDefaultMediaDetection(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION TapiBuffer = (PNDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION)InfoBuffer;
+ TAPI_LINE_INFO* TapiLineInfo;
+ CM *cm;
+ CM_PROF *Prof;
+
+ D_LOG(D_ENTRY, ("LineSetDefaultMediaDetection: hdLine: 0x%p, MediaModes: 0x%x", TapiBuffer->hdLine, TapiBuffer->ulMediaModes));
+
+ //
+ // validate line handle and get line pointer
+ //
+ TapiLineInfo = GetLineFromLineHandle(Adapter, TapiBuffer->hdLine);
+
+ if (TapiLineInfo == NULL)
+ return(NDIS_STATUS_TAPI_INVALLINEHANDLE);
+
+ //
+ // check for supported media mode
+ //
+// if (TapiBuffer->ulMediaModes != LINEMEDIAMODE_DIGITALDATA)
+// return(NDIS_STATUS_TAPI_INVALMEDIAMODE);
+
+ cm = TapiLineInfo->cm;
+ Prof = &cm->oprof;
+
+ cm->CallState = CALL_ST_LISTEN;
+
+ SetDefaultListenProf(Prof, GetIDFromLine(Adapter, TapiLineInfo));
+
+ //
+ // issue a listen
+ //
+ cm_listen(cm);
+
+ TapiLineInfo->TapiLineWasListening = 1;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+TSPI_LineSetDevConfig(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_SET_DEV_CONFIG TapiBuffer = (PNDIS_TAPI_SET_DEV_CONFIG)InfoBuffer;
+
+ D_LOG(D_ENTRY, ("LineSetDevConfig: DeviceID: 0x%x", TapiBuffer->ulDeviceID));
+
+ return(NDIS_STATUS_TAPI_OPERATIONUNAVAIL);
+}
+
+NDIS_STATUS
+TSPI_LineSetMediaMode(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_SET_MEDIA_MODE TapiBuffer = (PNDIS_TAPI_SET_MEDIA_MODE)InfoBuffer;
+ CM *cm;
+
+ D_LOG(D_ENTRY, ("LineSetMediaMode: hdCall: 0x%p, MediaMode: 0x%x", TapiBuffer->hdCall, TapiBuffer->ulMediaMode));
+
+ //
+ // validate call handle and get call pointer
+ //
+ cm = GetCallFromCallHandle(Adapter, TapiBuffer->hdCall);
+
+ if (cm == NULL)
+ return(NDIS_STATUS_TAPI_INVALCALLHANDLE);
+
+ return(NDIS_STATUS_TAPI_OPERATIONUNAVAIL);
+
+}
+
+NDIS_STATUS
+TSPI_LineSetStatusMessage(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ )
+{
+ PNDIS_TAPI_SET_STATUS_MESSAGES TapiBuffer = (PNDIS_TAPI_SET_STATUS_MESSAGES)InfoBuffer;
+ TAPI_LINE_INFO* TapiLineInfo;
+
+ D_LOG(D_ENTRY, ("LineSetStatusMessage: hdLine: 0x%p", TapiBuffer->hdLine));
+ D_LOG(D_ENTRY, ("LineStates: 0x%x, AddressStates: 0x%x", TapiBuffer->ulLineStates, TapiBuffer->ulAddressStates));
+
+ //
+ // validate line handle and get line pointer
+ //
+ TapiLineInfo = GetLineFromLineHandle(Adapter, TapiBuffer->hdLine);
+
+ if (TapiLineInfo == NULL)
+ return(NDIS_STATUS_TAPI_INVALLINEHANDLE);
+
+ TapiLineInfo->LineStates = TapiBuffer->ulLineStates;
+ TapiLineInfo->AddressStates = TapiBuffer->ulAddressStates;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+TAPI_LINE_INFO*
+GetLineFromLineHandle(
+ ADAPTER* Adapter,
+ HDRV_LINE hdLine
+ )
+{
+ ULONG n;
+ CM* cm;
+
+ for (n = 0; Adapter->CmTbl[n] && n < MAX_CM_PER_ADAPTER; n++)
+ {
+ cm = Adapter->CmTbl[n];
+
+ if (cm->TapiLineInfo == (TAPI_LINE_INFO*)hdLine)
+ break;
+ }
+ if (n >= MAX_CM_PER_ADAPTER)
+ return(NULL);
+
+ return((TAPI_LINE_INFO*)hdLine);
+}
+
+CM*
+GetCallFromCallHandle(
+ ADAPTER* Adapter,
+ HDRV_CALL hdCall
+ )
+{
+ ULONG n;
+ CM* cm;
+
+ for (n = 0; n < MAX_CM_PER_ADAPTER; n++)
+ {
+ cm = (CM*)Adapter->CmTbl[n];
+
+ if (cm == (CM*)hdCall)
+ break;
+ }
+ if (n == MAX_CM_PER_ADAPTER)
+ return(NULL);
+
+ return((CM*)hdCall);
+}
+
+IDD*
+GetIddFromDeviceID(
+ ADAPTER* Adapter,
+ ULONG DeviceID
+ )
+{
+ ULONG LocalID;
+
+ LocalID = DeviceID - Adapter->TapiBaseID;
+
+ return (Adapter->IddTbl[LocalID]);
+}
+
+
+//ULONG
+//GetIDFromLine(
+// ADAPTER *Adapter,
+// TAPI_LINE_INFO *TapiLineInfo
+// )
+//{
+// ULONG n;
+//
+// for (n = 0; n < MAX_CM_PER_ADAPTER; n++)
+// {
+// IDD *idd = Adapter->IddTbl[n];
+//
+// if (TapiLineInfo->idd == idd)
+// break;
+// }
+// return(Adapter->TapiBaseID + n);
+//}
+
+ULONG
+GetIDFromLine(
+ ADAPTER *Adapter,
+ TAPI_LINE_INFO *TapiLineInfo
+ )
+{
+ ULONG n;
+
+ for (n = 0; n < MAX_CM_PER_ADAPTER; n++)
+ {
+ CM *cm = Adapter->CmTbl[n];
+
+ if (TapiLineInfo->cm == cm)
+ break;
+ }
+ return(Adapter->TapiBaseID + n);
+}
+
+//CM*
+//GetCmFromDeviceID(
+// ADAPTER *Adapter,
+// ULONG DeviceID,
+// ULONG AddressID
+// )
+//{
+// ULONG LocalID;
+//
+// LocalID = DeviceID - Adapter->TapiBaseID;
+//
+// return(Adapter->CmTbl[(LocalID * 2) + AddressID]);
+//}
+
+CM*
+GetCmFromDeviceID(
+ ADAPTER* Adapter,
+ ULONG DeviceID
+ )
+{
+ ULONG LocalID;
+
+ LocalID = DeviceID - Adapter->TapiBaseID;
+
+ return (Adapter->CmTbl[LocalID]);
+}
+
+VOID
+DoTapiStateCheck(CM* cm)
+{
+ TAPI_LINE_INFO* TapiLineInfo = cm->TapiLineInfo;
+
+ D_LOG(D_ENTRY, ("DoTapiStateCheck: Line: 0x%p, call: 0x%p", TapiLineInfo, cm));
+
+ if (TapiLineInfo != NULL)
+ {
+ ULONG NewState = CALL_ST_DONTCARE;
+
+ if ((NewState = GetCallState(cm)) != CALL_ST_DONTCARE)
+ {
+ D_LOG(D_ENTRY, ("CallState: 0x%x, NewState: 0x%x", cm->CallState, NewState));
+ (*CallStateProc[cm->CallState][NewState])(cm);
+ cm->CallState = NewState;
+ }
+ }
+}
+
+ULONG
+GetCallState(
+ CM *cm
+ )
+{
+ switch (cm->state)
+ {
+ case CM_ST_IDLE:
+ return(CALL_ST_IDLE);
+
+ case CM_ST_LISTEN:
+ return(CALL_ST_LISTEN);
+
+ case CM_ST_ACTIVE:
+ return(CALL_ST_CONN);
+
+ case CM_ST_WAIT_ACT:
+ case CM_ST_IN_ACT:
+ case CM_ST_IN_SYNC:
+ return(CALL_ST_WAITCONN);
+ }
+ return(CALL_ST_DONTCARE);
+}
+
+VOID
+SignalCallProceeding(
+ CM *cm
+ )
+{
+ ADAPTER *Adapter = (ADAPTER*)cm->Adapter;
+ TAPI_LINE_INFO *TapiLineInfo = (TAPI_LINE_INFO*)cm->TapiLineInfo;
+ ULONG Param1 = 0, Param2 = 0, Param3 = 0;
+
+ D_LOG(D_ENTRY, ("SignalCallProceeding: Line: 0x%p, call: 0x%p", TapiLineInfo, cm));
+ cm->TapiCallState = LINECALLSTATE_PROCEEDING;
+
+ //
+ // indicate callstate event call connected
+ //
+ Param1 = cm->TapiCallState;
+ SendLineEvent(Adapter,
+ TapiLineInfo->htLine,
+ cm->htCall,
+ LINE_CALLSTATE,
+ &Param1,
+ &Param2,
+ &Param3);
+}
+
+VOID
+SignalListenFailure(
+ CM *cm
+ )
+{
+ ADAPTER *Adapter = (ADAPTER*)cm->Adapter;
+ TAPI_LINE_INFO *TapiLineInfo = (TAPI_LINE_INFO*)cm->TapiLineInfo;
+ CM_PROF *Prof = &cm->oprof;
+ ULONG Param1 = 0, Param2 = 0, Param3 = 0;
+
+ D_LOG(D_ENTRY, ("SignalListenFailure: hdLine: 0x%p, hdCall: 0x%p", TapiLineInfo, cm));
+
+ FreeIddCallResources(cm);
+
+ cm->TapiCallState = LINECALLSTATE_IDLE;
+
+ //
+ // signal callstate event call idle
+ //
+ Param1 = cm->TapiCallState;
+ SendLineEvent(Adapter,
+ TapiLineInfo->htLine,
+ cm->htCall,
+ LINE_CALLSTATE,
+ &Param1,
+ &Param2,
+ &Param3);
+
+ SetDefaultListenProf(Prof, GetIDFromLine(Adapter, TapiLineInfo));
+ cm_listen(cm);
+ cm->CallState = CALL_ST_LISTEN;
+}
+
+VOID
+SignalListenSuccess(
+ CM *cm
+ )
+{
+ ADAPTER *Adapter = (ADAPTER*)cm->Adapter;
+ TAPI_LINE_INFO *TapiLineInfo = (TAPI_LINE_INFO*)cm->TapiLineInfo;
+ ULONG Param1 = 0, Param2 = 0, Param3 = 0;
+
+ D_LOG(D_ENTRY, ("SignalListenSuccess: hdLine: 0x%p, hdcall: 0x%p", TapiLineInfo, cm));
+
+ cm->TapiCallState = LINECALLSTATE_OFFERING;
+
+ //
+ // indicate line_newcall
+ //
+ Param1 = (ULONG)cm;
+ SendLineEvent(Adapter,
+ TapiLineInfo->htLine,
+ (ULONG)NULL,
+ LINE_NEWCALL,
+ &Param1,
+ &Param2,
+ &Param3);
+
+ cm->htCall = Param2;
+
+ D_LOG(D_ENTRY, ("SignalListenSuccess: Got 0x%p as htCall from TAPI", cm->htCall));
+
+ //
+ // indicate callstate event call offering
+ //
+ Param1 = cm->TapiCallState;
+ Param2 = 0;
+ Param3 = LINEMEDIAMODE_DIGITALDATA;
+ SendLineEvent(Adapter,
+ TapiLineInfo->htLine,
+ cm->htCall,
+ LINE_CALLSTATE,
+ &Param1,
+ &Param2,
+ &Param3);
+}
+
+VOID
+SignalConnectFailure(
+ CM *cm
+ )
+{
+ ADAPTER *Adapter = (ADAPTER*)cm->Adapter;
+ TAPI_LINE_INFO *TapiLineInfo = (TAPI_LINE_INFO*)cm->TapiLineInfo;
+ ULONG CauseValue = (ULONG)cm->CauseValue;
+ ULONG SignalValue = (ULONG)cm->SignalValue;
+ CM_PROF *Prof = &cm->oprof;
+ ULONG Param1 = 0, Param2 = 0, Param3 = 0;
+
+ D_LOG(D_ENTRY, ("SignalConnectFailure: hdLine: 0x%p, hdCall: 0x%p", TapiLineInfo, cm));
+
+
+ FreeIddCallResources(cm);
+
+ //
+ // if this is set then the isdn line is not active
+ //
+ if (cm->NoActiveLine)
+ cm->TapiCallState = LINECALLSTATE_SPECIALINFO;
+ else
+ cm->TapiCallState = LINECALLSTATE_DISCONNECTED;
+
+ D_LOG(D_ALWAYS, ("SignalConnectFailure: CallState: 0x%x", cm->TapiCallState));
+//
+// currently gurdeep is only supporting the disconnect state
+// we will give busy notification in getcallstatus with the
+// disconnect mode
+//
+// else
+// {
+// //
+// // if this was a busy line
+// //
+// if (CauseValue == 0x11 || SignalValue == 0x04)
+// cm->TapiCallState = LINECALLSTATE_BUSY;
+// else
+// cm->TapiCallState = LINECALLSTATE_DISCONNECTED;
+// }
+
+ //
+ // indicate callstate event
+ //
+ Param1 = cm->TapiCallState;
+ SendLineEvent(Adapter,
+ TapiLineInfo->htLine,
+ cm->htCall,
+ LINE_CALLSTATE,
+ &Param1,
+ &Param2,
+ &Param3);
+}
+
+VOID
+SignalConnectSuccess(
+ CM *cm
+ )
+{
+ ADAPTER *Adapter = (ADAPTER*)cm->Adapter;
+ TAPI_LINE_INFO *TapiLineInfo = (TAPI_LINE_INFO*)cm->TapiLineInfo;
+ ULONG Param1 = 0, Param2 = 0, Param3 = 0;
+ CM_PROF *Prof = (CM_PROF*)&cm->dprof;
+
+ D_LOG(D_ENTRY, ("SignalConnectSuccess: hdLine: 0x%p, hdCall: 0x%p", TapiLineInfo, cm));
+ cm->TapiCallState = LINECALLSTATE_CONNECTED;
+
+ mtl_set_conn_state(cm->mtl, Prof->chan_num, 1);
+
+ //
+ // indicate line up to wan wrapper
+ //
+ WanLineup(cm, NULL);
+
+ //
+ // indicate callstate event call connected
+ //
+ Param1 = cm->TapiCallState;
+ SendLineEvent(Adapter,
+ TapiLineInfo->htLine,
+ cm->htCall,
+ LINE_CALLSTATE,
+ &Param1,
+ &Param2,
+ &Param3);
+}
+
+VOID
+SignalDisconnect(
+ CM *cm
+ )
+{
+ ADAPTER *Adapter = (ADAPTER*)cm->Adapter;
+ TAPI_LINE_INFO *TapiLineInfo = (TAPI_LINE_INFO*)cm->TapiLineInfo;
+ CM_PROF *Prof = &cm->oprof;
+ ULONG Param1 = 0, Param2 = 0, Param3 = 0;
+
+ D_LOG(D_ENTRY, ("SignalDisconnect: hdLine: 0x%p, hdCall: 0x%p", TapiLineInfo, cm));
+
+ cm->TapiCallState = LINECALLSTATE_DISCONNECTED;
+
+ FreeIddCallResources(cm);
+
+ //
+ // indicate callstate event call disconnected
+ //
+ Param1 = cm->TapiCallState;
+ Param3 = LINEMEDIAMODE_DIGITALDATA;
+ SendLineEvent(Adapter,
+ TapiLineInfo->htLine,
+ cm->htCall,
+ LINE_CALLSTATE,
+ &Param1,
+ &Param2,
+ &Param3);
+
+}
+
+VOID
+NoSignal(
+ CM *cm
+ )
+{
+ ADAPTER *Adapter = (ADAPTER*)cm->Adapter;
+ TAPI_LINE_INFO *TapiLineInfo = (TAPI_LINE_INFO*)cm->TapiLineInfo;
+ ULONG Param1 = 0, Param2 = 0, Param3 = 0;
+
+ D_LOG(D_ENTRY, ("NoSignal: hdLine: 0x%p, hdCall: 0x%p", TapiLineInfo, cm));
+
+}
+
+
+//
+// Send async line event to connection wrapper
+//
+VOID
+SendLineEvent(
+ ADAPTER *Adapter,
+ HTAPI_LINE htLine,
+ HTAPI_CALL htCall,
+ ULONG ulMsg,
+ PULONG Param1,
+ PULONG Param2,
+ PULONG Param3
+ )
+{
+ NDIS_TAPI_EVENT LineEvent;
+
+ LineEvent.htLine = htLine;
+ LineEvent.htCall = htCall;
+ LineEvent.ulMsg = ulMsg;
+ LineEvent.ulParam1 = *Param1;
+ LineEvent.ulParam2 = *Param2;
+ LineEvent.ulParam3 = *Param3;
+
+ D_LOG(D_ENTRY, ("SendLineEvent: TapiLine: 0x%p, TapiCall: 0x%p", htLine, htCall));
+
+
+ NdisMIndicateStatus(Adapter->Handle,
+ NDIS_STATUS_TAPI_INDICATION,
+ &LineEvent,
+ sizeof(NDIS_TAPI_EVENT));
+
+ NdisMIndicateStatusComplete(Adapter->Handle);
+
+ //
+ // stuff to work with conn wrapper without wan wrapper
+ //
+// NdisTapiIndicateStatus(Adapter,
+// &LineEvent,
+// sizeof(NDIS_TAPI_EVENT));
+
+ *Param1 = LineEvent.ulParam1;
+ *Param2 = LineEvent.ulParam2;
+ *Param3 = LineEvent.ulParam3;
+}
+
+
+//
+// set default params for outgoing call
+//
+VOID
+SetDefaultCallingProf(
+ CM_PROF *Profile,
+ ULONG DeviceID)
+{
+ CHAR ProfileName[24];
+
+ D_LOG(D_ENTRY, ("SetDefaultCallingProfile: Profile: 0x%p, DeviceID: %d", Profile, DeviceID));
+
+ Profile->nailed = 0;
+ Profile->persist = 0;
+ Profile->permanent = 0;
+ Profile->frame_activated = 0;
+ Profile->fallback = 1;
+ Profile->HWCompression = 0;
+ Profile->rx_idle_timer = 0;
+ Profile->tx_idle_timer = 0;
+ Profile->chan_num = 1;
+ Profile->chan_tbl[0].lterm = 0;
+ Profile->chan_tbl[0].bchan = 2;
+ Profile->chan_tbl[0].type = 0;
+ Profile->chan_tbl[0].idd = NULL;
+ sprintf(ProfileName,"Connect%d",DeviceID);
+ NdisMoveMemory(Profile->name, ProfileName, strlen(Profile->name) + 1);
+ sprintf(ProfileName, "*");
+ NdisMoveMemory(Profile->remote_name, ProfileName, strlen(Profile->remote_name) + 1);
+}
+
+//
+// set default params for outgoing call
+//
+VOID
+SetDefaultListenProf(
+ CM_PROF *Profile,
+ ULONG DeviceID)
+{
+ CHAR ProfileName[24];
+
+ D_LOG(D_ENTRY, ("SetDefaultListenProfile: Profile: 0x%p, DeviceID: %d", Profile, DeviceID));
+
+ Profile->nailed = 0;
+ Profile->persist = 0;
+ Profile->permanent = 0;
+ Profile->frame_activated = 0;
+ Profile->fallback = 1;
+ Profile->HWCompression = 0;
+ Profile->rx_idle_timer = 0;
+ Profile->tx_idle_timer = 0;
+ Profile->chan_num = 1;
+ Profile->chan_tbl[0].lterm = 0;
+ Profile->chan_tbl[0].bchan = 2;
+ Profile->chan_tbl[0].type = 0;
+ Profile->chan_tbl[0].idd = NULL;
+ sprintf(ProfileName,"Listen%d",DeviceID);
+ NdisMoveMemory(Profile->name, ProfileName, strlen(Profile->name) + 1);
+ sprintf(ProfileName, "*");
+ NdisMoveMemory(Profile->remote_name, ProfileName, strlen(Profile->remote_name) + 1);
+}
+
+//
+// parse address and store in profile
+//
+VOID
+StashAddress(
+ CM_PROF *Profile,
+ ULONG AddressLength,
+ PUCHAR Address
+ )
+{
+ ULONG TempAddressLen, AddressToParseLen, i, j;
+ UCHAR Temp[128], AddressToParse[128];
+ UCHAR *ChanDelim, *TempAddress;
+ USHORT n;
+
+ TempAddressLen = AddressLength;
+
+ NdisMoveMemory(Temp, Address, AddressLength);
+
+ TempAddress = Temp;
+
+ for (n = 0; n < Profile->chan_num; n++)
+ {
+ //
+ // : is the delimiter between channel address
+ //
+ if ( (ChanDelim = strstr(TempAddress, ":")) == NULL)
+ {
+ AddressToParseLen = TempAddressLen;
+ NdisMoveMemory(AddressToParse, TempAddress, AddressToParseLen);
+ }
+ else
+ {
+ AddressToParseLen = ChanDelim - TempAddress;
+ NdisMoveMemory (AddressToParse, TempAddress, AddressToParseLen);
+ (PUCHAR)TempAddress = ChanDelim + 1;
+ }
+
+ NdisZeroMemory(Profile->chan_tbl[n].addr, sizeof(Profile->chan_tbl[n].addr));
+
+ //
+ // only digits, *, or # are allowed in dialing number
+ //
+ for (i = 0, j = 0; i < AddressToParseLen; i++)
+ if (isdigit(AddressToParse[i]) ||
+ (AddressToParse[i] == '*') ||
+ (AddressToParse[i] == '#'))
+ Profile->chan_tbl[n].addr[j++] = AddressToParse[i];
+ }
+}
+
+VOID
+FreeIddCallResources(
+ CM *cm
+ )
+{
+ IDD *idd;
+ ULONG n, m;
+
+
+ for (n = 0; n < MAX_IDD_IN_SYSTEM; n++)
+ {
+ idd = GetIddByIndex(n);
+
+ for (m = 0; m < MAX_CHANNELS_PER_IDD; m++)
+ {
+ if (idd && (idd->CallInfo.cm[m] == cm))
+ {
+ idd->CallInfo.cm[m] = NULL;
+ idd->CallInfo.ChannelsUsed--;
+ }
+ }
+ }
+}
+
+//
+// check this cm's idd to see if in use
+// if available mark usage and exit
+// if not return error
+//
+ULONG
+FindAndStashIdd(
+ CM *cm,
+ CM_PROF *Profile
+ )
+{
+ ULONG m, ChannelsNeeded, ChannelsFound, ChannelsFilled;
+ IDD *idd;
+
+
+ ChannelsNeeded = Profile->chan_num;
+ ChannelsFound = ChannelsFilled = 0;
+
+ //
+ // first check the idd that we own
+ //
+ idd = (IDD*)cm->idd;
+
+ ChannelsFound = GetChannelsFromIdd(idd, cm, ChannelsFilled, ChannelsNeeded);
+
+ ChannelsFilled = ChannelsFound;
+
+ ChannelsNeeded -= ChannelsFound;
+
+ //
+ // we need to check other idd's to see if we can steal some channels
+ // this will go away when Microsoft does multilink
+ //
+ if (ChannelsNeeded)
+ {
+ for (m = 0; m < MAX_IDD_IN_SYSTEM; m++)
+ {
+ IDD *idd = GetIddByIndex(m);
+
+ if (idd && ChannelsNeeded)
+ {
+ ChannelsFound = GetChannelsFromIdd(idd,
+ cm,
+ ChannelsFilled,
+ ChannelsNeeded);
+
+ ChannelsFilled += ChannelsFound;
+
+ ChannelsNeeded -= ChannelsFound;
+ }
+ else
+ break;
+ }
+ }
+
+ return(ChannelsFilled);
+}
+
+ULONG
+GetChannelsFromIdd (
+ IDD* idd,
+ CM* cm,
+ ULONG BeginChannel,
+ ULONG ChannelsNeeded
+ )
+{
+ ULONG n, m, ChannelsFilled;
+ CM_PROF *Profile = (CM_PROF*)&cm->oprof;
+
+
+ ChannelsFilled = 0;
+
+ NdisAcquireSpinLock(&idd->lock);
+
+ for (n = BeginChannel; n < BeginChannel + ChannelsNeeded; n++)
+ {
+ //
+ // if not all channels have been used
+ //
+ if (idd->CallInfo.ChannelsUsed < MAX_CHANNELS_PER_IDD)
+ {
+ for (m = 0; m < MAX_CHANNELS_PER_IDD; m++)
+ {
+ if (idd->CallInfo.cm[m] == NULL)
+ {
+ idd->CallInfo.cm[m] = cm;
+ idd->CallInfo.ChannelsUsed++;
+ if (idd->CallInfo.NumLTerms < MAX_LTERMS_PER_IDD)
+ Profile->chan_tbl[n].lterm = 0;
+ else
+ Profile->chan_tbl[n].lterm = (USHORT)m;
+ Profile->chan_tbl[n].idd = idd;
+ ChannelsFilled++;
+ break;
+ }
+ }
+ }
+ }
+
+ NdisReleaseSpinLock(&idd->lock);
+ return(ChannelsFilled);
+}
diff --git a/private/ntos/ndis/pcimac/tapioid.h b/private/ntos/ndis/pcimac/tapioid.h
new file mode 100644
index 000000000..f42f601ef
--- /dev/null
+++ b/private/ntos/ndis/pcimac/tapioid.h
@@ -0,0 +1,440 @@
+//
+// Tapioid.h - file contains defs and protos for tapioid.c
+//
+//
+//
+//
+
+//
+// internal line states
+//
+#define CALL_ST_IDLE 0
+#define CALL_ST_LISTEN 1
+#define CALL_ST_WAITCONN 2
+#define CALL_ST_CONN 3
+#define CALL_ST_DONTCARE 0xFFFFFFFF
+#define MAX_STATE 4
+#define PCIMAC_SPI_VER 0x00000000
+
+//
+// structure for tapi used line information
+//
+typedef struct tagTAPI_LINE
+{
+ //
+ // id of this line
+ //
+ ULONG LineID;
+
+ //
+ // tapi's handle for this line
+ //
+ HTAPI_LINE htLine;
+
+ //
+ // pointers to connection objects
+ // these are our tapi call handles
+ //
+// VOID *cm[MAX_CALL_PER_LINE];
+ VOID *cm;
+
+ //
+ // async completion id
+ //
+ ULONG ulRequestPendingID;
+
+ //
+ // media modes supportd
+ //
+ ULONG MediaModes;
+
+ //
+ // bearer modes supported
+ //
+ ULONG BearerModes;
+
+ //
+ // line states
+ //
+ ULONG LineStates;
+
+ //
+ // address states
+ //
+ ULONG AddressStates;
+
+ //
+ // media mode currently being monitored
+ //
+ ULONG CurMediaMode;
+
+ //
+ // bearer mode of current call
+ //
+ ULONG CurBearerMode;
+
+ //
+ // line state
+ //
+ ULONG TapiLineState;
+
+ //
+ // line status
+ //
+ ULONG TapiLineStatus;
+
+ //
+ // the idd for this line
+ //
+ VOID *idd;
+
+ //
+ // the adapter for this line
+ //
+ VOID *Adapter;
+
+ //
+ // listening flag
+ //
+ ULONG TapiLineWasListening;
+
+}TAPI_LINE_INFO;
+
+
+#define VALIDATE_EXTENSION(version)
+
+NDIS_STATUS
+TSPI_LineAccept(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineAnswer(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineClose(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineCloseCall(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineConditionalMediaDetect(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineConfigDialog(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineDevSpecific(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineDial(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineDrop(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineGetAddressCaps(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineGetAddressID(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineGetAddressStatus(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineGetCallAddressID(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineGetCallInfo(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineGetCallStatus(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineGetDevCaps(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineGetDevConfig(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineGetExtensionID(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineGetID(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineGetLineDevStatus(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineMakeCall(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineNegotiateExtVersion(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineOpen(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_ProviderInit(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_ProviderShutdown(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineSecureCall(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineSelectExtVersion(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineSendUserToUserInfo(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineSetAppSpecific(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineSetCallParams(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineSetDefaultMediaDetection(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineSetDevConfig(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineSetMediaMode(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+NDIS_STATUS
+TSPI_LineSetStatusMessage(
+ ADAPTER *Adapter,
+ PVOID InfoBuffer
+ );
+
+VOID
+SignalCallProceeding(
+ CM *cm
+ );
+
+VOID
+SignalListenFailure(
+ CM *cm
+ );
+
+VOID
+SignalListenSuccess(
+ CM *cm
+ );
+
+VOID
+SignalConnectFailure(
+ CM *cm
+ );
+
+VOID
+SignalConnectSuccess(
+ CM *cm
+ );
+
+VOID
+SignalDisconnect(
+ CM *cm
+ );
+
+VOID
+NoSignal(
+ CM *cm
+ );
+
+IDD*
+GetIddFromDeviceID(
+ ADAPTER* Adapter,
+ ULONG DeviceID
+ );
+
+CM*
+GetCallFromCallHandle(
+ ADAPTER* Adapter,
+ HDRV_CALL hdCall
+ );
+
+TAPI_LINE_INFO*
+GetLineFromLineHandle(
+ ADAPTER* Adapter,
+ HDRV_LINE hdLine
+ );
+
+ULONG
+GetIDFromLine(
+ ADAPTER *Adapter,
+ TAPI_LINE_INFO *TapiLineInfo
+ );
+
+VOID
+DoTapiStateCheck(
+ CM* cm
+ );
+
+ULONG
+GetCallState(
+ CM *cm
+ );
+
+VOID
+SendLineEvent(
+ ADAPTER *Adapter,
+ HTAPI_LINE htLine,
+ HTAPI_CALL htCall,
+ ULONG ulMsg,
+ PULONG Param1,
+ PULONG Param2,
+ PULONG Param3
+ );
+
+VOID
+SetDefaultCallingProf(
+ CM_PROF *Profile,
+ ULONG DeviceID
+ );
+
+VOID
+SetDefaultListenProf(
+ CM_PROF *Profile,
+ ULONG DeviceID
+ );
+
+VOID
+StashAddress(
+ CM_PROF *Profile,
+ ULONG AddressLength,
+ PUCHAR Address
+ );
+
+VOID
+FreeIddCallResources(
+ CM *cm
+ );
+
+ULONG
+FindAndStashIdd(
+ CM *cm,
+ CM_PROF *Profile
+ );
+
+//CM*
+//GetCmFromDeviceID(
+// ADAPTER *Adapter,
+// ULONG DeviceID,
+// ULONG AddressID
+// );
+
+CM*
+GetCmFromDeviceID(
+ ADAPTER *Adapter,
+ ULONG DeviceID
+ );
+
+ULONG
+GetChannelsFromIdd (
+ IDD* idd,
+ CM* cm,
+ ULONG BeginChannel,
+ ULONG ChannelsNeeded
+ );
+
diff --git a/private/ntos/ndis/pcimac/trc.h b/private/ntos/ndis/pcimac/trc.h
new file mode 100644
index 000000000..05224c24f
--- /dev/null
+++ b/private/ntos/ndis/pcimac/trc.h
@@ -0,0 +1,71 @@
+/*
+ * TRC.H - include file for all TRC modules
+ */
+
+#ifndef _TRC_
+#define _TRC_
+
+#include <trc_pub.h>
+
+/* a trace context */
+typedef struct _TRC
+{
+ TRC_STATUS stat; /* status record */
+
+ TRC_ENTRY *ent_tbl; /* entry table (circ. buffer) */
+ ULONG ent_put; /* put pointer */
+ ULONG ent_get; /* get pointer */
+ ULONG ent_num; /* # of entries */
+ ULONG ent_seq; /* sequence # next to use */
+ ULONG create_ref; /* object creation reference */
+ ULONG start_ref; /* object start reference count */
+ IDD *idd; /* idd back pointer */
+} TRC;
+
+/* TRC class operations */
+INT trc_init(ULONG);
+INT trc_term(VOID);
+INT trc_register_idd(VOID* idd);
+INT trc_deregister_idd(VOID* idd);
+
+/* TRC context (object) operations */
+INT trc_create(VOID** ret_trc, ULONG depth);
+INT trc_destroy(VOID* trc);
+INT trc_control(VOID* idd, ULONG op, ULONG arg);
+INT trc_get_status(VOID* trc, TRC_STATUS* stat);
+INT trc_get_entry(VOID* trc, ULONG seq, TRC_ENTRY* ent);
+
+/* trace control opcodes */
+#define TRC_OP_RESET 0 /* reset trace */
+#define TRC_OP_STOP 1 /* stop tracing */
+#define TRC_OP_START 2 /* start tracing */
+
+#define TRC_OP_ADD_IDD 3 /* add idd to trace context */
+ /* arg: idd or NULL for all */
+#define TRC_OP_DEL_IDD 4 /* remove idd from trace context */
+ /* arg: idd or NULL for all */
+#define TRC_OP_SET_FILTER 5 /* set filter for tracing */
+ /* arg: filter type */
+#define TRC_OP_RESET_AREA 6 /* reset area state to idle */
+#define TRC_OP_CREATE 7 /* create trc object */
+#define TRC_OP_DESTROY 8 /* destroy trc object */
+
+/* error codes */
+#define TRC_E_SUCC 0 /* success */
+#define TRC_E_IDD 1 /* idd operation failed */
+#define TRC_E_NOMEM 2 /* not enough memory */
+#define TRC_E_NOSUCH 3 /* no such error */
+#define TRC_E_NOROOM 4 /* no room in a table */
+#define TRC_E_PARAM 5 /* parameter error */
+#define TRC_E_BUSY 6 /* trace context area busy */
+
+/*
+ * TRC_LOC.H - Line trace module, local definitions
+ */
+
+/* prototypes for internal functions */
+VOID trc__cmd_handler(VOID *idd_1, USHORT chan, ULONG Reserved, IDD_MSG *msg);
+INT trc__filter(ULONG filter, CHAR* data, ULONG len);
+
+
+#endif /* _TRC_ */
diff --git a/private/ntos/ndis/pcimac/trc_core.c b/private/ntos/ndis/pcimac/trc_core.c
new file mode 100644
index 000000000..fbec4fe4d
--- /dev/null
+++ b/private/ntos/ndis/pcimac/trc_core.c
@@ -0,0 +1,358 @@
+/*
+ * TRC_CORE.C - trace core module
+ */
+
+#include <ndis.h>
+//#include <ndismini.h>
+#include <ndiswan.h>
+#include <mydefs.h>
+#include <mytypes.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+#include <trc.h>
+#include <disp.h>
+
+/* local trace context table (NULL=free) */
+
+#define CheckNULLTrace(Trace) \
+ { \
+ if (Trace == NULL) \
+ break; \
+ }
+
+
+/* register an available idd */
+INT
+trc_register_idd(VOID *idd)
+{
+ IDD_MSG msg;
+
+ D_LOG(D_ENTRY, ("trc_register_idd: entry, idd: 0x%p", idd));
+
+ /* add handle to idd command receiver */
+ if ( idd_attach(idd, IDD_PORT_CMD_RX, (VOID*)trc__cmd_handler, idd) != IDD_E_SUCC )
+ return(TRC_E_IDD);
+
+ /* issue idd command to stop trace */
+ NdisZeroMemory(&msg, sizeof(msg));
+ msg.opcode = CMD_TRC_OFF;
+ if ( idd_send_msg(idd, &msg, IDD_PORT_CMD_TX, NULL, NULL) != IDD_E_SUCC )
+ return(TRC_E_IDD);
+
+ return(TRC_E_SUCC);
+}
+
+/* deregister an available idd */
+INT
+trc_deregister_idd(VOID *idd)
+{
+ IDD_MSG msg;
+
+ D_LOG(D_ENTRY, ("trc_deregister_idd: entry, idd: 0x%p", idd));
+
+ /* issue idd command to stop trace */
+ NdisZeroMemory(&msg, sizeof(msg));
+ msg.opcode = CMD_TRC_OFF;
+ if ( idd_send_msg(idd, &msg, IDD_PORT_CMD_TX, NULL, NULL) != IDD_E_SUCC )
+ return(TRC_E_IDD);
+
+ /* remove handle from idd command receiver */
+ if ( idd_detach(idd, IDD_PORT_CMD_RX, (VOID*)trc__cmd_handler, idd) != IDD_E_SUCC )
+ return(TRC_E_IDD);
+ else
+ return(TRC_E_SUCC);
+}
+
+/* create a trace object */
+INT
+trc_create(VOID **trc_1, ULONG depth)
+{
+ TRC **ret_trc = (TRC**)trc_1;
+ NDIS_PHYSICAL_ADDRESS pa = NDIS_PHYSICAL_ADDRESS_CONST(0xffffffff, 0xffffffff);
+ TRC *trc;
+
+ D_LOG(D_ENTRY, ("trc_create: entry, ret_trc: 0x%p, depth: %ld", ret_trc, depth));
+
+ /* allocate memory object */
+ NdisAllocateMemory((PVOID*)&trc, sizeof(*trc), 0, pa);
+ if ( !trc )
+ {
+ mem_alloc_failed:
+ D_LOG(D_ALWAYS, ("trc_create: memory allocate failed!"));
+ return(TRC_E_NOMEM);
+ }
+ D_LOG(D_ALWAYS, ("trc_create: trc: 0x%p", trc));
+ NdisZeroMemory(trc, sizeof(*trc));
+
+ /* allocate buffer memory */
+ NdisAllocateMemory((PVOID*)&trc->ent_tbl, sizeof(TRC_ENTRY) * depth,
+ 0, pa);
+ if ( !trc->ent_tbl )
+ goto mem_alloc_failed;
+ D_LOG(D_ALWAYS, ("trc_create: trc->ent_tbl: 0x%p", trc->ent_tbl));
+ NdisZeroMemory(trc->ent_tbl, sizeof(TRC_ENTRY) * depth);
+
+ /* setup initial field values */
+ trc->stat.state = TRC_ST_STOP;
+ trc->stat.filter = TRC_FT_NONE;
+ trc->stat.depth = depth;
+
+ /* return succ */
+ *ret_trc = trc;
+ return(TRC_E_SUCC);
+}
+
+/* delte a trace object */
+INT
+trc_destroy(VOID *trc_1)
+{
+ TRC *trc = (TRC*)trc_1;
+
+ D_LOG(D_ENTRY, ("trc_destroy: entry, trc: 0x%p", trc));
+
+ /* free memory */
+ NdisFreeMemory(trc->ent_tbl, sizeof(TRC_ENTRY) * trc->stat.depth, 0);
+ NdisFreeMemory(trc, sizeof(*trc), 0);
+
+ return(TRC_E_SUCC);
+}
+
+/* perform a trace control function */
+INT
+trc_control(VOID *idd, ULONG op, ULONG arg)
+{
+ IDD_MSG msg;
+ TRC *trc;
+ INT ret;
+
+
+ trc = idd_get_trc(idd);
+
+ D_LOG(D_ENTRY, ("trc_control: idd: 0x%p trc: 0x%p, op: 0x%x, arg: 0x%x", idd, trc, op, arg));
+
+ /* branch on opcode */
+ switch ( op )
+ {
+ case TRC_OP_CREATE:
+ D_LOG(D_ENTRY, ("trc_control: CreateTrace"));
+ // if no trace object for this idd yet
+ if (trc == NULL)
+ {
+ //create trace object
+ if ((ret = trc_create(&trc, arg)) != TRC_E_SUCC)
+ return(TRC_E_IDD);
+
+ // register trace for this idd
+ if ((ret = trc_register_idd (idd)) != TRC_E_SUCC)
+ {
+ trc_destroy(trc);
+ return(TRC_E_IDD);
+ }
+
+ idd_set_trc (idd, trc);
+
+ // set ref count
+ trc->create_ref = 0;
+
+ // set backpointer
+ trc->idd = idd;
+ }
+ // inc ref count
+ trc->create_ref++;
+ break;
+
+ case TRC_OP_DESTROY:
+ D_LOG(D_ENTRY, ("trc_control: DestroyTrace"));
+
+ // if trc == NULL break;
+ CheckNULLTrace (trc);
+
+ // dec ref count
+ if (--trc->create_ref)
+ break;
+
+ trc_deregister_idd(idd);
+ trc_destroy(trc);
+ idd_set_trc(idd, NULL);
+ break;
+
+ case TRC_OP_RESET :
+ D_LOG(D_ENTRY, ("trc_control: ResetTrace"));
+ // if trc == NULL break;
+ CheckNULLTrace (trc);
+
+ trc->stat.state = TRC_ST_STOP;
+ trc->stat.entries = trc->stat.seq_1st = 0;
+ trc->ent_put = trc->ent_get = trc->ent_num = trc->ent_seq = 0;
+ break;
+
+ case TRC_OP_STOP :
+ D_LOG(D_ENTRY, ("trc_control: StopTrace"));
+ // if trc == NULL break;
+ CheckNULLTrace (trc);
+
+ // check start flag
+ if (--trc->start_ref)
+ break;
+
+ trc->stat.state = TRC_ST_STOP;
+
+ /* issue idd command to stop trace */
+ NdisZeroMemory(&msg, sizeof(msg));
+ msg.opcode = CMD_TRC_OFF;
+ if ( idd_send_msg((VOID*)arg, &msg, IDD_PORT_CMD_TX, NULL, NULL) != IDD_E_SUCC )
+ return(TRC_E_IDD);
+ break;
+
+ case TRC_OP_START :
+ D_LOG(D_ENTRY, ("trc_control: StartTrace"));
+ // if trc == NULL break;
+ CheckNULLTrace (trc);
+
+ trc->stat.state = TRC_ST_RUN;
+
+ // check start flag
+ if (trc->start_ref++)
+ break;
+
+
+ /* issue idd command to start trace */
+ NdisZeroMemory(&msg, sizeof(msg));
+ msg.opcode = CMD_TRC_ON;
+ if ( idd_send_msg((VOID*)arg, &msg, IDD_PORT_CMD_TX, NULL, NULL) != IDD_E_SUCC )
+ return(TRC_E_IDD);
+ break;
+
+ case TRC_OP_SET_FILTER :
+ D_LOG(D_ENTRY, ("trc_control: SetTraceFilter"));
+ // if trc == NULL break;
+ CheckNULLTrace (trc);
+
+ trc->stat.filter = arg;
+ break;
+
+ default :
+ return(TRC_E_PARAM);
+ }
+
+ /* if here, was successful */
+ return(TRC_E_SUCC);
+}
+
+/* get status of a trace context */
+INT
+trc_get_status(VOID *trc_1, TRC_STATUS *stat)
+{
+ TRC *trc = (TRC*)trc_1;
+
+ D_LOG(D_ENTRY, ("trc_get_status: entry, trc: 0x%p, stat: 0x%p", trc, stat));
+
+ // if no obect exit
+ if (trc == NULL)
+ return (TRC_E_NOSUCH);
+
+ *stat = trc->stat;
+ stat->entries = trc->ent_num;
+ stat->seq_1st = trc->ent_seq;
+
+ return(TRC_E_SUCC);
+}
+
+/* get an entry by sequence number */
+INT
+trc_get_entry(VOID *trc_1, ULONG seq, TRC_ENTRY *ent)
+{
+ TRC *trc = (TRC*)trc_1;
+ ULONG n, index;
+
+ D_LOG(D_ENTRY, ("trc_get_entry: entry, trc: 0x%p, seq: %ld, ent: 0x%p", \
+ trc, seq, ent));
+
+ // if no obect exit
+ if (trc == NULL)
+ return(TRC_E_NOSUCH);
+
+ /* find requested sequence number, temp!!!, using search! */
+ for ( n = 0 ; n < trc->ent_num ; n++ )
+ {
+ index = (trc->ent_get + n) % trc->stat.depth;
+ if ( trc->ent_tbl[index].seq == seq )
+ {
+ /* found */
+ *ent = trc->ent_tbl[index];
+ return(TRC_E_SUCC);
+ }
+ }
+ /* if here not found */
+ return(TRC_E_NOSUCH);
+}
+
+/* handler for trace and dump area data packets */
+VOID
+trc__cmd_handler(VOID *idd_1, USHORT chan, ULONG Reserved, IDD_MSG *msg)
+{
+ TRC *trc;
+ TRC_ENTRY *ent;
+ IDD *idd = (IDD*)idd_1;
+
+
+ D_LOG(D_ENTRY, ("trc__cmd_handler: idd: %p, chan: %d, msg: %p", \
+ idd, chan, msg));
+ D_LOG(D_ENTRY, ("trc__cmd_handler: opcode: 0x%x, buflen: 0x%x, bufptr: %p", \
+ msg->opcode, msg->buflen, msg->bufptr));
+ D_LOG(D_ENTRY, ("trc__cmd_handler: bufid: %p, param: 0x%x", \
+ msg->bufid, msg->param));
+
+
+ // Get the trace object for this idd
+ trc = idd_get_trc(idd);
+
+ // if no obect exit
+ if (trc == NULL || msg->bufid >= 2)
+ return;
+
+ /* if here it is a trace frame. param is rx/tx attribute */
+ /* establish entry to insert into & update vars */
+
+ /* check if trace enabled */
+ if ( trc->stat.state == TRC_ST_STOP )
+ return;
+
+ D_LOG(D_ALWAYS, ("trc__cmd_handler: trc: %p", trc));
+ /* check if frame filters in */
+ if ( !trc__filter(trc->stat.filter, msg->bufptr, msg->buflen) )
+ return;
+
+ /* frames needs to be buffered, establish entry pointer */
+ ent = trc->ent_tbl + trc->ent_put;
+ trc->ent_put = (trc->ent_put + 1) % trc->stat.depth;
+ if ( trc->ent_num < trc->stat.depth )
+ trc->ent_num++;
+
+ /* fill up entry */
+ ent->seq = trc->ent_seq++;
+ KeQuerySystemTime(&ent->time_stamp);
+ ent->attr = msg->bufid;
+ ent->org_len = msg->buflen;
+ ent->len = MIN(msg->buflen, sizeof(ent->data));
+ IddGetDataFromAdapter(idd,
+ (PUCHAR)ent->data,
+ (PUCHAR)msg->bufptr,
+ (USHORT)ent->len);
+// NdisMoveMemory (ent->data, msg->bufptr, ent->len);
+}
+
+/* filter trace frame */
+INT
+trc__filter(ULONG filter, CHAR *buf, ULONG len)
+{
+ D_LOG(D_ENTRY, ("trc__filter: entry, filter: %ld, buf: 0x%p, len: %ld",\
+ filter, buf, len));
+
+ /* not implemented, all frames filter in */
+ return(1);
+}
diff --git a/private/ntos/ndis/pcimac/trc_pub.h b/private/ntos/ndis/pcimac/trc_pub.h
new file mode 100644
index 000000000..67655fcf1
--- /dev/null
+++ b/private/ntos/ndis/pcimac/trc_pub.h
@@ -0,0 +1,49 @@
+/*
+ * TRC_PUB.H - include file for all TRC modules
+ */
+
+#ifndef _TRC_PUB_
+#define _TRC_PUB_
+
+/* max values & constants */
+#define TRC_MAX_IDD 40 /* of number of idd's (lines) supported */
+#define TRC_MAX_DATA 256 /* max size of frame data buffered */
+
+/* status of trace buffer as reported to user */
+typedef struct
+{
+ ULONG state; /* state of trace */
+#define TRC_ST_STOP 0 /* - is stopped */
+#define TRC_ST_RUN 1 /* - is running */
+
+ ULONG filter; /* active filter type */
+#define TRC_FT_NONE 0 /* - no filter, all frames buffered */
+#define TRC_FT_L2 1 /* - only l2 frames accepted */
+#define TRC_FT_L3 2 /* - only l3 frames accepted */
+
+ ULONG depth; /* depth of trace buffer */
+
+
+ ULONG entries; /* # of entries in buffer now */
+ ULONG seq_1st; /* sequence number of first frame in buffer */
+
+} TRC_STATUS;
+
+/* descriptor for a trace entry */
+typedef struct
+{
+ ULONG seq; /* sequence number for frame */
+ LARGE_INTEGER time_stamp; /* some sort of timing information */
+
+ ULONG attr; /* attribute word */
+#define TRC_AT_RX 0 /* - received frame */
+#define TRC_AT_TX 1 /* - transmit frame */
+
+ ULONG org_len; /* original frame length */
+ ULONG len; /* length of buffered data */
+ UCHAR data[TRC_MAX_DATA]; /* frame data */
+
+} TRC_ENTRY;
+
+#endif /* _TRC_PUB_ */
+
diff --git a/private/ntos/ndis/pcimac/util.c b/private/ntos/ndis/pcimac/util.c
new file mode 100644
index 000000000..11cf6101b
--- /dev/null
+++ b/private/ntos/ndis/pcimac/util.c
@@ -0,0 +1,117 @@
+/*
+ * UTIL.C - some utility functions
+ */
+
+#include <ndis.h>
+//#include <ntddk.h>
+#include <mydefs.h>
+#include <mytypes.h>
+#include <util.h>
+
+// Total Memory Allocated
+ULONG TotalMemory = 0;
+
+/* constants */
+#define BUF_SIZE 512
+
+/* get current time, in seconds */
+ULONG
+ut_time_now(VOID)
+{
+ LARGE_INTEGER curr_time;
+ LARGE_INTEGER sec;
+ LARGE_INTEGER rem;
+ static LARGE_INTEGER base = {0, 0};
+ static BOOL first_call = TRUE;
+
+ /* get current system time */
+ KeQuerySystemTime(&curr_time);
+
+ /* on first call, store base */
+ if ( first_call )
+ {
+ base = curr_time;
+ first_call = FALSE;
+ }
+ /* make relative to base */
+ curr_time.QuadPart -= base.QuadPart;
+
+ /* convert to seconds */
+ sec.QuadPart = curr_time.QuadPart/10000000L;
+
+ /* return as a ULONG */
+ return((ULONG)sec.LowPart);
+}
+
+/* allocate a buffer */
+CHAR*
+ut_get_buf(VOID)
+{
+ CHAR *ret;
+
+ NDIS_PHYSICAL_ADDRESS pa = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
+
+ NdisAllocateMemory((PVOID*)&ret, BUF_SIZE, 0, pa);
+
+ return(ret);
+}
+
+/* free buffer */
+VOID
+ut_free_buf(CHAR *buf)
+{
+ if ( buf )
+ NdisFreeMemory(buf, BUF_SIZE, 0);
+}
+
+/* init */
+VOID
+sema_init(SEMA *s)
+{
+ s->signalled = FALSE;
+ NdisAllocateSpinLock (&s->lock);
+}
+
+VOID
+sema_term(SEMA *s)
+{
+ s->signalled = FALSE;
+ NdisFreeSpinLock (&s->lock);
+}
+
+/* try to get semaphore */
+BOOL
+sema_get(SEMA *s)
+{
+ BOOL ret;
+// KIRQL NewIrql, OldIrql;
+
+// NewIrql = HIGH_LEVEL;
+
+// KeRaiseIrql (NewIrql, &OldIrql);
+
+ NdisAcquireSpinLock (&s->lock);
+
+ if ( !s->signalled )
+ ret = s->signalled = TRUE;
+ else
+ ret = FALSE;
+
+ NdisReleaseSpinLock (&s->lock);
+
+// KeLowerIrql (OldIrql);
+
+ return(ret);
+}
+
+/* free semaphore */
+VOID
+sema_free(SEMA *s)
+{
+ NdisAcquireSpinLock (&s->lock);
+
+ s->signalled = FALSE;
+
+ NdisReleaseSpinLock (&s->lock);
+}
+
diff --git a/private/ntos/ndis/pcimac/util.h b/private/ntos/ndis/pcimac/util.h
new file mode 100644
index 000000000..629c49a71
--- /dev/null
+++ b/private/ntos/ndis/pcimac/util.h
@@ -0,0 +1,27 @@
+/*
+ * UTIL.H - utility module header
+ */
+
+#ifndef _UTIL_
+#define _UTIL_
+
+/* data structure */
+typedef struct
+{
+ BOOL signalled;
+ NDIS_SPIN_LOCK lock;
+} SEMA;
+
+/* prototypes */
+VOID sema_init(SEMA* s);
+VOID sema_term(SEMA* s);
+BOOL sema_get(SEMA* s);
+VOID sema_free(SEMA* s);
+
+ULONG ut_time_now(VOID);
+CHAR *ut_get_buf(VOID);
+VOID ut_free_buf(CHAR* buf);
+
+/* macros */
+
+#endif /* _UTIL_ */
diff --git a/private/ntos/ndis/pcimac/wan_conn.c b/private/ntos/ndis/pcimac/wan_conn.c
new file mode 100644
index 000000000..da640152d
--- /dev/null
+++ b/private/ntos/ndis/pcimac/wan_conn.c
@@ -0,0 +1,123 @@
+/*
+ * WAN_CONN.C - routines for ras connection and disconnection
+ */
+
+#include <ndis.h>
+//#include <ndismini.h>
+#include <ndiswan.h>
+#include <mydefs.h>
+#include <mytypes.h>
+#include <util.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+#include <tapioid.h>
+#include <disp.h>
+
+
+INT
+WanLineup(VOID *cm_1, NDIS_HANDLE Endpoint)
+{
+ CM *cm = (CM*)cm_1;
+ ADAPTER *Adapter = cm->Adapter;
+ NDIS_MAC_LINE_UP ISDNLineUp;
+ MTL *mtl = (MTL*)cm->mtl;
+ TAPI_LINE_INFO *TapiLineInfo = (TAPI_LINE_INFO*)(cm->TapiLineInfo);
+ ULONG LinkSpeed;
+
+ D_LOG(D_ENTRY, ("WanLineup: entry, cm: 0x%p", cm));
+
+ //
+ // Get the connection speed and fill
+ //
+ mtl_get_conn_speed (mtl, &LinkSpeed);
+
+ D_LOG(D_ALWAYS, ("cm_wanlineup: ConnectSpeed: [%d]", LinkSpeed));
+
+ ISDNLineUp.LinkSpeed = LinkSpeed / 100;
+
+ //
+ // fill line quality
+ //
+ ISDNLineUp.Quality = NdisWanReliable;
+
+ //
+ // fill send windows
+ //
+ ISDNLineUp.SendWindow = MAX_WANPACKET_XMITS;
+
+ //
+ // fill the connection wrapper id
+ // this will need to change (i'm not clear on what is needed here)
+ //
+ if (Endpoint)
+ ISDNLineUp.ConnectionWrapperID = Endpoint;
+ else
+ ISDNLineUp.ConnectionWrapperID = (NDIS_HANDLE)cm->htCall;
+
+ //
+ // fill the link context
+ //
+ ISDNLineUp.NdisLinkHandle = (NDIS_HANDLE)mtl;
+
+ //
+ // clear out link handle since this lineup is for a new connection
+ // will get back a link handle from wrapper
+ //
+ ISDNLineUp.NdisLinkContext = (NDIS_HANDLE)mtl->LinkHandle = NULL;
+
+ //
+ // Tell the wan wrapper that the connection is now up.
+ // We have a new link speed, frame size, quality of service.
+ //
+ NdisMIndicateStatus(
+ (NDIS_HANDLE)Adapter->Handle,
+ NDIS_STATUS_WAN_LINE_UP, // General Status
+ (PVOID)&ISDNLineUp, // Specific Status (baud rate in 100bps)
+ sizeof(ISDNLineUp));
+
+ NdisMIndicateStatusComplete(Adapter->Handle);
+
+ //
+ // save new link handle
+ //
+ cm->LinkHandle = mtl->LinkHandle = ISDNLineUp.NdisLinkContext;
+
+ return(CM_E_SUCC);
+}
+
+INT
+WanLinedown(VOID *cm_1)
+{
+ CM *cm = (CM*)cm_1;
+ ADAPTER *Adapter = cm->Adapter;
+ NDIS_MAC_LINE_DOWN ISDNLineDown;
+ MTL *mtl = (MTL*)cm->mtl;
+
+ D_LOG(D_ENTRY, ("cm_wanlinedown: entry, cm: 0x%p", cm));
+
+ ISDNLineDown.NdisLinkContext = mtl->LinkHandle;
+
+ NdisMIndicateStatus(
+ (NDIS_HANDLE)Adapter->Handle,
+ NDIS_STATUS_WAN_LINE_DOWN, // General Status
+ (PVOID)&ISDNLineDown, // Specific Status (baud rate in 100bps)
+ sizeof(ISDNLineDown));
+
+ NdisMIndicateStatusComplete(Adapter->Handle);
+
+ //
+ // clear out link handles
+ //
+ cm->LinkHandle = mtl->LinkHandle = NULL;
+
+ //
+ // flush the mtl's wan packet queue
+ //
+ MtlFlushWanPacketTxQueue(mtl);
+
+ return(CM_E_SUCC);
+}
+
+
diff --git a/private/ntos/ndis/pcimac/wanoid.c b/private/ntos/ndis/pcimac/wanoid.c
new file mode 100644
index 000000000..67ac36841
--- /dev/null
+++ b/private/ntos/ndis/pcimac/wanoid.c
@@ -0,0 +1,228 @@
+//#include <ntddk.h>
+#include <ndis.h>
+//#include <ndismini.h>
+#include <ndiswan.h>
+//#include <ntddndis.h>
+#include <stdio.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <adapter.h>
+#include <util.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+#include <res.h>
+#include <trc.h>
+#include <io.h>
+
+
+//
+// Wan OID's
+//
+static UINT SupportedWanOids[] =
+ {
+ OID_WAN_PERMANENT_ADDRESS,
+ OID_WAN_CURRENT_ADDRESS,
+ OID_WAN_QUALITY_OF_SERVICE,
+ OID_WAN_PROTOCOL_TYPE,
+ OID_WAN_MEDIUM_SUBTYPE,
+ OID_WAN_HEADER_FORMAT,
+ OID_WAN_GET_INFO,
+ OID_WAN_SET_LINK_INFO,
+ OID_WAN_GET_LINK_INFO,
+ OID_WAN_GET_COMP_INFO,
+ OID_WAN_SET_COMP_INFO,
+ };
+
+#define MAX_SUPPORTED_WAN_OIDS 11
+
+
+
+
+NDIS_STATUS
+WanOidProc(
+ NDIS_HANDLE AdapterContext,
+ NDIS_OID Oid,
+ PVOID InfoBuffer,
+ ULONG InfoBufferLen,
+ PULONG BytesReadWritten,
+ PULONG BytesNeeded
+ )
+{
+ NDIS_WAN_MEDIUM_SUBTYPE Medium = NdisWanMediumIsdn;
+ NDIS_WAN_HEADER_FORMAT HeaderFormat = NdisWanHeaderNative;
+ NDIS_WAN_QUALITY WanQuality = NdisWanReliable;
+ ADAPTER *Adapter = (ADAPTER*)AdapterContext;
+ PNDIS_WAN_INFO pWanInfo;
+ PNDIS_WAN_SET_LINK_INFO pLinkSetInfo;
+ PNDIS_WAN_GET_LINK_INFO pLinkGetInfo;
+ NDIS_PHYSICAL_ADDRESS HighestAcceptableMax = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
+ MTL* mtl;
+ CM* cm;
+ ULONG n, NumIddPerAdapter;
+
+ switch (Oid)
+ {
+ case OID_WAN_PERMANENT_ADDRESS:
+ case OID_WAN_CURRENT_ADDRESS:
+ if (InfoBufferLen < 6)
+ {
+ *BytesNeeded = 6;
+ return(NDIS_STATUS_INVALID_LENGTH);
+ }
+
+ cm = (CM*)Adapter->CmTbl[0];
+
+ NdisMoveMemory(InfoBuffer,
+ (PVOID)cm->SrcAddr,
+ 6);
+
+ *BytesNeeded = 0;
+ *BytesReadWritten = 6;
+ break;
+
+ case OID_WAN_QUALITY_OF_SERVICE:
+ NdisMoveMemory(InfoBuffer,
+ (PVOID)(&WanQuality),
+ sizeof(NDIS_WAN_QUALITY));
+ *BytesNeeded = 0;
+ *BytesReadWritten = sizeof(NDIS_WAN_QUALITY);
+ break;
+
+ case OID_WAN_PROTOCOL_TYPE:
+ break;
+
+ case OID_WAN_MEDIUM_SUBTYPE:
+ NdisMoveMemory(InfoBuffer,
+ (PVOID)(&Medium),
+ sizeof(NDIS_WAN_MEDIUM_SUBTYPE));
+ *BytesNeeded = 0;
+ *BytesReadWritten = sizeof(NDIS_WAN_MEDIUM_SUBTYPE);
+ break;
+
+ case OID_WAN_HEADER_FORMAT:
+ NdisMoveMemory(InfoBuffer,
+ (PVOID)(&HeaderFormat),
+ sizeof(NDIS_WAN_HEADER_FORMAT));
+ *BytesNeeded = 0;
+ *BytesReadWritten = sizeof(NDIS_WAN_HEADER_FORMAT);
+ break;
+
+ case OID_WAN_GET_INFO:
+ pWanInfo = (PNDIS_WAN_INFO)InfoBuffer;
+
+ NumIddPerAdapter = EnumIddPerAdapter(Adapter);
+ pWanInfo->Endpoints = 2 * NumIddPerAdapter;
+ pWanInfo->MemoryFlags = 0;
+ pWanInfo->HighestAcceptableAddress = HighestAcceptableMax;
+ pWanInfo->MaxTransmit = MAX_WANPACKET_XMITS;
+ pWanInfo->MaxFrameSize = MAX_WANPACKET_BUFFERSIZE;
+ pWanInfo->HeaderPadding = MAX_WANPACKET_HEADERPADDING;
+ pWanInfo->TailPadding = MAX_WANPACKET_TAILPADDING;
+ pWanInfo->FramingBits = RAS_FRAMING |
+ PPP_FRAMING |
+ PPP_COMPRESS_PROTOCOL_FIELD |
+ MEDIA_NRZ_ENCODING |
+ TAPI_PROVIDER;
+ pWanInfo->DesiredACCM = 0;
+ *BytesNeeded = 0;
+ *BytesReadWritten = sizeof(NDIS_WAN_INFO);
+ break;
+
+ case OID_WAN_SET_LINK_INFO:
+ //
+ // get pointer to link set info
+ //
+ pLinkSetInfo = (PNDIS_WAN_SET_LINK_INFO)InfoBuffer;
+
+ //
+ // get mtl (Link Context)
+ //
+ mtl = (MTL*)pLinkSetInfo->NdisLinkHandle;
+
+ if (!mtl->is_conn)
+ return (NDIS_STATUS_INVALID_DATA);
+
+ mtl->MaxSendFrameSize = pLinkSetInfo->MaxSendFrameSize;
+ mtl->MaxRecvFrameSize = pLinkSetInfo->MaxRecvFrameSize;
+ if (pLinkSetInfo->SendFramingBits)
+ mtl->SendFramingBits = pLinkSetInfo->SendFramingBits;
+ mtl->RecvFramingBits = pLinkSetInfo->RecvFramingBits;
+ mtl->SendCompressionBits = pLinkSetInfo->SendCompressionBits;
+ mtl->RecvCompressionBits = pLinkSetInfo->RecvCompressionBits;
+ D_LOG(D_ALWAYS, ("SetLinkInfo: mtl: 0x%p",mtl));
+ D_LOG(D_ALWAYS, ("SendFramingBits: 0x%x", mtl->SendFramingBits));
+ D_LOG(D_ALWAYS, ("RecvFramingBits: 0x%x", mtl->RecvFramingBits));
+ *BytesNeeded = 0;
+ *BytesReadWritten = sizeof(NDIS_WAN_SET_LINK_INFO);
+
+ //
+ // get cm (connection context)
+ //
+ cm = (CM*)mtl->cm;
+
+ //
+ // if this connection was originally a PPP connection
+ // and now framing has been backed off to RAS we need to
+ // do some uus negotiation
+ //
+ if ((cm->ConnectionType == CM_PPP) &&
+ (mtl->SendFramingBits & RAS_FRAMING))
+ {
+ //
+ // set flag that will block transmits on this mtl
+ //
+ cm->PPPToDKF = 1;
+
+ //
+ // for all channels (better only be one but???) do uus
+ //
+ for (n = 0; n < cm->dprof.chan_num; n++)
+ {
+ cm->dprof.chan_tbl[n].ustate = CM_US_UUS_SEND;
+ cm__tx_uus_pkt(cm->dprof.chan_tbl + n, CM_ASSOC_RQ, 0);
+ }
+ mtl->IddTxFrameType = IDD_FRAME_DKF;
+ }
+
+ break;
+
+ case OID_WAN_GET_LINK_INFO:
+ //
+ // get pointer to link set info
+ //
+ pLinkGetInfo = (PNDIS_WAN_GET_LINK_INFO)InfoBuffer;
+
+ //
+ // get mtl (Link Context)
+ //
+ mtl = (MTL*)pLinkGetInfo->NdisLinkHandle;
+
+ if (!mtl->is_conn)
+ return (NDIS_STATUS_INVALID_DATA);
+
+ pLinkGetInfo->MaxSendFrameSize = mtl->MaxSendFrameSize;
+ pLinkGetInfo->MaxRecvFrameSize = mtl->MaxRecvFrameSize;
+ pLinkGetInfo->HeaderPadding = mtl->PreamblePadding;
+ pLinkGetInfo->TailPadding = mtl->PostamblePadding;
+ pLinkGetInfo->SendFramingBits = mtl->SendFramingBits;
+ pLinkGetInfo->RecvFramingBits = mtl->RecvFramingBits;
+ pLinkGetInfo->SendCompressionBits = mtl->SendCompressionBits;
+ pLinkGetInfo->RecvCompressionBits = mtl->RecvCompressionBits;
+ D_LOG(D_ALWAYS, ("GetLinkInfo: mtl: 0x%p",mtl));
+ D_LOG(D_ALWAYS, ("SendFramingBits: 0x%x", mtl->SendFramingBits));
+ D_LOG(D_ALWAYS, ("RecvFramingBits: 0x%x", mtl->RecvFramingBits));
+ *BytesNeeded = 0;
+ *BytesReadWritten = sizeof(NDIS_WAN_GET_LINK_INFO);
+ break;
+
+ case OID_WAN_GET_COMP_INFO:
+ case OID_WAN_SET_COMP_INFO:
+ return(NDIS_STATUS_INVALID_OID);
+
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
diff --git a/private/ntos/ndis/sonic/alloc.c b/private/ntos/ndis/sonic/alloc.c
new file mode 100644
index 000000000..354461735
--- /dev/null
+++ b/private/ntos/ndis/sonic/alloc.c
@@ -0,0 +1,1137 @@
+/*++
+
+Copyright (c) 1990-1992 Microsoft Corporation
+
+Module Name:
+
+ alloc.c
+
+Abstract:
+
+ This file contains the code for allocating and freeing adapter
+ resources for the National Semiconductor SONIC Ethernet controller.
+ This driver conforms to the NDIS 3.0 miniport interface.
+
+Author:
+
+ Adam Barr (adamba) 14-Nov-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent.
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+#include <sonichrd.h>
+#include <sonicsft.h>
+
+
+
+STATIC
+PNDIS_BUFFER
+AllocateFlushBuffer(
+ IN PSONIC_ADAPTER Adapter,
+ IN PVOID VirtualAddress,
+ IN ULONG Length
+ );
+
+
+#pragma NDIS_INIT_FUNCTION(AllocateFlushBuffer)
+
+STATIC
+PNDIS_BUFFER
+AllocateFlushBuffer(
+ IN PSONIC_ADAPTER Adapter,
+ IN PVOID VirtualAddress,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ Allocates an NDIS_BUFFER for the specified address and length.
+ This function is intended to create NDIS_BUFFERs for flushing.
+
+Arguments:
+
+ Adapter - The adapter the buffer is for. It must have a
+ FlushBufferPoolHandle that points to a valid buffer pool.
+
+ VirtualAddress - A pointer to the buffer to describe.
+
+ Length - The length of the buffer.
+
+Return Value:
+
+ The NDIS_BUFFER if one was allocated.
+ NULL if an NDIS_BUFFER could not be allocated.
+
+--*/
+
+{
+ PNDIS_BUFFER ReturnBuffer;
+ NDIS_STATUS Status;
+
+ NdisAllocateBuffer(
+ &Status,
+ &ReturnBuffer,
+ Adapter->FlushBufferPoolHandle,
+ VirtualAddress,
+ Length
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+#if DBG
+ DbgPrint("SONIC: Could not allocate flush buffer, %x\n", Status);
+#endif
+ ReturnBuffer = (PNDIS_BUFFER)NULL;
+ }
+
+
+ return ReturnBuffer;
+}
+
+
+#pragma NDIS_INIT_FUNCTION(AllocateAdapterMemory)
+
+extern
+BOOLEAN
+AllocateAdapterMemory(
+ IN PSONIC_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates memory for:
+
+ - Transmit ring entries
+
+ - Receive ring entries
+
+ - Receive buffers
+
+ - Adapter buffers for use if user transmit buffers don't meet hardware
+ contraints
+
+ - Structures to map transmit ring entries back to the packets.
+
+Arguments:
+
+ Adapter - The adapter to allocate memory for.
+
+Return Value:
+
+ Returns FALSE if some memory needed for the adapter could not
+ be allocated. It does NOT call DeleteAdapterMemory in this
+ case.
+
+--*/
+
+{
+
+ //
+ // Pointer to a transmit ring entry. Used while initializing
+ // the TDA.
+ //
+ PSONIC_TRANSMIT_DESCRIPTOR CurrentTransmitDescriptor;
+
+ //
+ // Pointer to a receive buffer. Used while allocated the
+ // RBAs.
+ //
+ PVOID * CurrentReceiveBuffer;
+
+ //
+ // Pointer to a receive descriptor. Used while initialing
+ // the RDA.
+ //
+ PSONIC_RECEIVE_DESCRIPTOR CurrentReceiveDescriptor;
+
+ //
+ // Used for determining physical addresses.
+ //
+ SONIC_PHYSICAL_ADDRESS SonicPhysicalAdr;
+
+ //
+ // Used for NDIS allocation routines that return an NDIS_PHYSICAL_ADDRESS
+ //
+ NDIS_PHYSICAL_ADDRESS NdisPhysicalAdr;
+
+ //
+ // Simple iteration variable.
+ //
+ UINT i;
+
+ //
+ // Used to flush buffers that only need to be flushed once.
+ //
+ PNDIS_BUFFER FlushBuffer;
+
+ //
+ // The size of the buffer pool needed.
+ //
+ UINT PoolBuffersNeeded;
+
+ //
+ // Holds the result of calls to SONIC_ALLOC_MEMORY
+ //
+ NDIS_STATUS AllocStatus;
+
+
+
+ //
+ // We need some NDIS_BUFFERs to describe memory that we
+ // allocate (generally either to flush the buffer, or
+ // because we need its physical address). To do this
+ // we need a buffer pool, so we have to determine how
+ // many buffers we need.
+ //
+ PoolBuffersNeeded =
+ 1 + // for CamDescriptorArea
+ 1 + // for ReceiveResourceArea
+ 1 + // for BlankBuffer
+ Adapter->NumberOfReceiveBuffers + // for flushing cached receive buffers.
+ SONIC_NUMBER_OF_SMALL_BUFFERS +
+ SONIC_NUMBER_OF_MEDIUM_BUFFERS +
+ SONIC_NUMBER_OF_LARGE_BUFFERS ;
+
+ NdisAllocateBufferPool(
+ &AllocStatus,
+ &Adapter->FlushBufferPoolHandle,
+ PoolBuffersNeeded
+ );
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+
+#if DBG
+ DbgPrint("SONIC: Could not allocate flush buffer pool\n");
+#endif
+ return FALSE;
+
+ }
+
+
+
+ //
+ // Allocate the transmit ring descriptors.
+ //
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(SONIC_TRANSMIT_DESCRIPTOR)*
+ Adapter->NumberOfTransmitDescriptors,
+ FALSE, // non-cached
+ (PVOID *)&Adapter->TransmitDescriptorArea,
+ &Adapter->TransmitDescriptorAreaPhysical
+ );
+
+ if (Adapter->TransmitDescriptorArea == NULL) {
+
+#if DBG
+ DbgPrint("SONIC: TransmitDescriptorArea memory invalid\n");
+#endif
+ return FALSE;
+
+ }
+
+ if (NdisGetPhysicalAddressHigh(Adapter->TransmitDescriptorAreaPhysical) != 0) {
+
+#if DBG
+ DbgPrint("SONIC: TransmitDescriptorArea memory too high\n");
+#endif
+ return FALSE;
+ }
+
+
+
+ //
+ // Clean the above memory
+ //
+
+ SONIC_ZERO_MEMORY(
+ Adapter->TransmitDescriptorArea,
+ (sizeof(SONIC_TRANSMIT_DESCRIPTOR)*Adapter->NumberOfTransmitDescriptors)
+ );
+
+
+ //
+ // We have the transmit ring descriptors. Initialize the Link
+ // fields.
+ //
+
+ for (
+ i = 0, CurrentTransmitDescriptor = Adapter->TransmitDescriptorArea;
+ i < Adapter->NumberOfTransmitDescriptors;
+ i++,CurrentTransmitDescriptor++
+ ) {
+
+ SonicPhysicalAdr = NdisGetPhysicalAddressLow(Adapter->TransmitDescriptorAreaPhysical) +
+ (i * sizeof(SONIC_TRANSMIT_DESCRIPTOR));
+
+ if (i == 0) {
+
+ Adapter->TransmitDescriptorArea[Adapter->NumberOfTransmitDescriptors-1].Link = SonicPhysicalAdr;
+
+ } else {
+
+ (CurrentTransmitDescriptor-1)->Link = SonicPhysicalAdr;
+
+ }
+
+ }
+
+
+ //
+ // Allocate the ring to packet structure.
+ //
+
+ SONIC_ALLOC_MEMORY(
+ &AllocStatus,
+ &Adapter->DescriptorToPacket,
+ sizeof(SONIC_DESCRIPTOR_TO_PACKET)
+ *Adapter->NumberOfTransmitDescriptors
+ );
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+ return FALSE;
+ }
+
+
+ //
+ // We have to do this now. The PrevLinkPointer field is used
+ // to point to where the Link field of the previous transmit
+ // descriptor is; it is normally set when the previous
+ // transmit descriptor is filled. For the very first packet
+ // transmitted there will have been no previous transmit
+ // descriptor, so we fill it in ourselves. We use the
+ // Link field of the last transmit descriptor (the actual
+ // location used doesn't really matter, as long as it is
+ // a valid address).
+ //
+
+ Adapter->DescriptorToPacket->PrevLinkPointer =
+ &(Adapter->TransmitDescriptorArea[
+ Adapter->NumberOfTransmitDescriptors-1].Link);
+
+
+ //
+ // Allocate the receive resource area and the
+ // CAM descriptor area. These are allocated together
+ // since they must have the same high 16 bits in
+ // their addresses.
+ //
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ (sizeof(SONIC_RECEIVE_RESOURCE)*Adapter->NumberOfReceiveBuffers) +
+ sizeof(SONIC_CAM_DESCRIPTOR_AREA),
+ TRUE, // CACHED!
+ (PVOID *)&Adapter->ReceiveResourceArea,
+ &Adapter->ReceiveResourceAreaPhysical
+ );
+
+ if (Adapter->ReceiveResourceArea == NULL) {
+
+#if DBG
+ DbgPrint("SONIC: ReceiveResourceArea memory invalid\n");
+#endif
+ return FALSE;
+
+ }
+
+ if (NdisGetPhysicalAddressHigh(Adapter->ReceiveResourceAreaPhysical) != 0) {
+
+#if DBG
+ DbgPrint("SONIC: ReceiveResourceArea memory too high\n");
+#endif
+ return FALSE;
+
+ }
+
+
+ //
+ // The CAM Descriptor Area is immediately after the RRA.
+ //
+
+ Adapter->CamDescriptorArea = (PSONIC_CAM_DESCRIPTOR_AREA)
+ (Adapter->ReceiveResourceArea + Adapter->NumberOfReceiveBuffers);
+
+ Adapter->CamDescriptorAreaPhysical =
+ NdisGetPhysicalAddressLow(Adapter->ReceiveResourceAreaPhysical) +
+ ((PUCHAR)Adapter->CamDescriptorArea -
+ (PUCHAR)Adapter->ReceiveResourceArea);
+
+
+ //
+ // Allocate the NDIS_BUFFER to flush the CAM Descriptor Area.
+ //
+ Adapter->CamDescriptorAreaFlushBuffer = AllocateFlushBuffer(
+ Adapter,
+ Adapter->CamDescriptorArea,
+ sizeof(SONIC_CAM_DESCRIPTOR_AREA)
+ );
+
+ if (!Adapter->CamDescriptorAreaFlushBuffer) {
+ return FALSE;
+ }
+
+ SONIC_ZERO_MEMORY(
+ Adapter->CamDescriptorArea,
+ sizeof(SONIC_CAM_DESCRIPTOR_AREA)
+ );
+
+ SONIC_FLUSH_WRITE_BUFFER(Adapter->CamDescriptorAreaFlushBuffer);
+
+
+#if DBG
+ if (SonicDbg) {
+ DbgPrint("SONIC: Cam Descriptor Area: %lx physical: %lx\n",
+ Adapter->CamDescriptorArea,
+ Adapter->CamDescriptorAreaPhysical);
+ }
+#endif
+
+ //
+ // Allocate the array to hold pointers to the RBAs.
+ //
+
+ SONIC_ALLOC_MEMORY(
+ &AllocStatus,
+ &Adapter->ReceiveBufferArea,
+ sizeof(PVOID) * Adapter->NumberOfReceiveBuffers
+ );
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+
+ return FALSE;
+ }
+
+ //
+ // Allocate the array to hold pointers to the receive ndis
+ // (flush) buffers.
+ //
+
+ SONIC_ALLOC_MEMORY(
+ &AllocStatus,
+ &Adapter->ReceiveNdisBufferArea,
+ sizeof(PNDIS_BUFFER) * Adapter->NumberOfReceiveBuffers
+ );
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+
+ return FALSE;
+ }
+
+#if DBG
+ if (SonicDbg) {
+ DbgPrint("SONIC: Receive Buffer Area: %lx\n",
+ (ULONG)Adapter->ReceiveBufferArea);
+ }
+#endif
+
+
+ //
+ // We have the receive buffer pointers. Allocate the buffer
+ // for each entry and zero them.
+ //
+ // For each receive buffer, the Physical address and length
+ // will be in Adapter->ReceiveResourceArea[i], while the
+ // virtual address will be in Adapter->ReceiveBufferArea[i].
+ //
+
+ for (
+ i = 0, CurrentReceiveBuffer = Adapter->ReceiveBufferArea;
+ i < Adapter->NumberOfReceiveBuffers;
+ i++,CurrentReceiveBuffer++
+ ) {
+
+ //
+ // Allocate the next [cached] receive buffer.
+ //
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ SONIC_SIZE_OF_RECEIVE_BUFFERS,
+ TRUE, // CACHED!
+ CurrentReceiveBuffer,
+ &NdisPhysicalAdr
+ );
+
+ //
+ // Did the allocation fail?
+ //
+
+ if ( *CurrentReceiveBuffer == NULL ) {
+
+ return FALSE;
+ }
+
+ if ( NdisGetPhysicalAddressHigh(NdisPhysicalAdr) != 0) {
+
+ return FALSE;
+ }
+
+ //
+ // Zero the [cached] receive buffer.
+ //
+
+ SONIC_ZERO_MEMORY(
+ *CurrentReceiveBuffer,
+ SONIC_SIZE_OF_RECEIVE_BUFFERS
+ );
+
+
+ //
+ // Allocate an NDIS_BUFFER for this receive buffer.
+ //
+
+ Adapter->ReceiveNdisBufferArea[i] = AllocateFlushBuffer(
+ Adapter,
+ *CurrentReceiveBuffer,
+ SONIC_SIZE_OF_RECEIVE_BUFFERS
+ );
+
+ if ( Adapter->ReceiveNdisBufferArea[i] == NULL ) {
+
+ return FALSE;
+
+ }
+
+ SONIC_SET_RECEIVE_RESOURCE_ADDRESS(
+ &Adapter->ReceiveResourceArea[i],
+ NdisGetPhysicalAddressLow(NdisPhysicalAdr)
+ );
+
+ SONIC_SET_RECEIVE_RESOURCE_LENGTH(
+ &Adapter->ReceiveResourceArea[i],
+ SONIC_SIZE_OF_RECEIVE_BUFFERS
+ );
+ }
+
+
+ //
+ // The Receive Resource Area is set up, we can flush
+ // it now since it does not change.
+ //
+
+ FlushBuffer = AllocateFlushBuffer(
+ Adapter,
+ (PVOID)Adapter->ReceiveResourceArea,
+ (sizeof(SONIC_RECEIVE_RESOURCE)*Adapter->NumberOfReceiveBuffers)
+ );
+
+ if (!FlushBuffer) {
+ return FALSE;
+ }
+
+ SONIC_FLUSH_WRITE_BUFFER(FlushBuffer);
+
+ NdisFreeBuffer(FlushBuffer);
+
+ //
+ // Allocate memory to hold the receive descriptor pointers.
+ //
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(SONIC_RECEIVE_DESCRIPTOR) * Adapter->NumberOfReceiveDescriptors,
+ FALSE, // NON-CACHED!
+ (PVOID *)&Adapter->ReceiveDescriptorArea,
+ &Adapter->ReceiveDescriptorAreaPhysical
+ );
+
+
+ if (Adapter->ReceiveDescriptorArea == NULL) {
+
+#if DBG
+ DbgPrint("SONIC: ReceiveDescriptorArea memory invalid\n");
+#endif
+ return FALSE;
+
+ }
+
+ if (NdisGetPhysicalAddressHigh(Adapter->ReceiveDescriptorAreaPhysical) != 0) {
+
+#if DBG
+ DbgPrint("SONIC: ReceiveDescriptorArea memory too high\n");
+#endif
+ return FALSE;
+
+ }
+
+
+
+ //
+ // Clean the above memory
+ //
+
+ SONIC_ZERO_MEMORY(
+ Adapter->ReceiveDescriptorArea,
+ (sizeof(SONIC_RECEIVE_DESCRIPTOR)*Adapter->NumberOfReceiveDescriptors)
+ );
+
+
+ //
+ // Now set up the Link fields in the receive descriptors.
+ //
+
+ for (
+ i = 0, CurrentReceiveDescriptor = Adapter->ReceiveDescriptorArea;
+ i < Adapter->NumberOfReceiveDescriptors;
+ i++,CurrentReceiveDescriptor++
+ ) {
+
+ //
+ // belongs to SONIC.
+ //
+
+ CurrentReceiveDescriptor->InUse = SONIC_OWNED_BY_SONIC;
+
+ SonicPhysicalAdr = NdisGetPhysicalAddressLow(Adapter->ReceiveDescriptorAreaPhysical) +
+ (i * sizeof(SONIC_RECEIVE_DESCRIPTOR));
+
+ if (i == 0) {
+
+ Adapter->ReceiveDescriptorArea[
+ Adapter->NumberOfReceiveDescriptors-1].Link =
+ SonicPhysicalAdr | SONIC_END_OF_LIST;
+
+ } else {
+
+ Adapter->ReceiveDescriptorArea[i-1].Link = SonicPhysicalAdr;
+
+ }
+
+ }
+
+
+ //
+ // Allocate the array of buffer descriptors.
+ //
+
+ SONIC_ALLOC_MEMORY(
+ &AllocStatus,
+ &Adapter->SonicBuffers,
+ sizeof(SONIC_BUFFER_DESCRIPTOR)*
+ (SONIC_NUMBER_OF_SMALL_BUFFERS +
+ SONIC_NUMBER_OF_MEDIUM_BUFFERS +
+ SONIC_NUMBER_OF_LARGE_BUFFERS)
+ );
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+ return FALSE;
+ }
+
+ //
+ // Zero the memory of all the descriptors so that we can
+ // know which buffers wern't allocated incase we can't allocate
+ // them all.
+ //
+ SONIC_ZERO_MEMORY(
+ Adapter->SonicBuffers,
+ sizeof(SONIC_BUFFER_DESCRIPTOR)*
+ (SONIC_NUMBER_OF_SMALL_BUFFERS +
+ SONIC_NUMBER_OF_MEDIUM_BUFFERS +
+ SONIC_NUMBER_OF_LARGE_BUFFERS)
+ );
+
+
+ //
+ // Allocate space for the small sonic buffers and fill in the
+ // buffer descriptors.
+ //
+
+ Adapter->SonicBufferListHeads[0] = -1;
+ Adapter->SonicBufferListHeads[1] = 0;
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ SONIC_SMALL_BUFFER_SIZE * SONIC_NUMBER_OF_SMALL_BUFFERS,
+ TRUE, // CACHED!
+ &Adapter->SmallSonicBuffers,
+ &NdisPhysicalAdr
+ );
+
+ if (NdisGetPhysicalAddressHigh(NdisPhysicalAdr) != 0) {
+
+ return FALSE;
+ }
+
+ if ( Adapter->SmallSonicBuffers == NULL ) {
+
+ return FALSE;
+ }
+
+ for (
+ i = 0;
+ i < SONIC_NUMBER_OF_SMALL_BUFFERS;
+ i++
+ ) {
+
+ Adapter->SonicBuffers[i].VirtualSonicBuffer = (PVOID)
+ ((PUCHAR)Adapter->SmallSonicBuffers +
+ (i * SONIC_SMALL_BUFFER_SIZE));
+
+ NdisSetPhysicalAddressHigh(
+ Adapter->SonicBuffers[i].PhysicalSonicBuffer,
+ 0);
+
+ NdisSetPhysicalAddressLow(
+ Adapter->SonicBuffers[i].PhysicalSonicBuffer,
+ NdisGetPhysicalAddressLow(NdisPhysicalAdr) +
+ (i * SONIC_SMALL_BUFFER_SIZE));
+
+ Adapter->SonicBuffers[i].FlushBuffer =
+ AllocateFlushBuffer(
+ Adapter,
+ Adapter->SonicBuffers[i].VirtualSonicBuffer,
+ SONIC_SMALL_BUFFER_SIZE
+ );
+
+ if (!Adapter->SonicBuffers[i].FlushBuffer) {
+ return FALSE;
+ }
+
+ Adapter->SonicBuffers[i].Next = i+1;
+
+ }
+
+ //
+ // Make sure that the last buffer correctly terminates the free list.
+ //
+
+ Adapter->SonicBuffers[i-1].Next = -1;
+
+ //
+ // Do the medium buffers now.
+ //
+
+ Adapter->SonicBufferListHeads[2] = i;
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ SONIC_MEDIUM_BUFFER_SIZE * SONIC_NUMBER_OF_MEDIUM_BUFFERS,
+ TRUE, // CACHED!
+ &Adapter->MediumSonicBuffers,
+ &NdisPhysicalAdr
+ );
+
+
+ if (Adapter->MediumSonicBuffers == NULL) {
+ return FALSE;
+ }
+
+ if (NdisGetPhysicalAddressHigh(NdisPhysicalAdr) != 0) {
+ return FALSE;
+ }
+
+
+
+ for (
+ ;
+ i < SONIC_NUMBER_OF_SMALL_BUFFERS + SONIC_NUMBER_OF_MEDIUM_BUFFERS;
+ i++
+ ) {
+
+ Adapter->SonicBuffers[i].VirtualSonicBuffer = (PVOID)
+ ((PUCHAR)Adapter->MediumSonicBuffers +
+ ((i - SONIC_NUMBER_OF_SMALL_BUFFERS) * SONIC_MEDIUM_BUFFER_SIZE));
+
+ NdisSetPhysicalAddressHigh(
+ Adapter->SonicBuffers[i].PhysicalSonicBuffer,
+ 0);
+
+ NdisSetPhysicalAddressLow(
+ Adapter->SonicBuffers[i].PhysicalSonicBuffer,
+ NdisGetPhysicalAddressLow(NdisPhysicalAdr) +
+ ((i - SONIC_NUMBER_OF_SMALL_BUFFERS) * SONIC_MEDIUM_BUFFER_SIZE));
+
+
+ Adapter->SonicBuffers[i].FlushBuffer =
+ AllocateFlushBuffer(
+ Adapter,
+ Adapter->SonicBuffers[i].VirtualSonicBuffer,
+ SONIC_MEDIUM_BUFFER_SIZE
+ );
+
+ if (!Adapter->SonicBuffers[i].FlushBuffer) {
+ return FALSE;
+ }
+
+
+ Adapter->SonicBuffers[i].Next = i+1;
+
+ }
+
+ //
+ // Make sure that the last buffer correctly terminates the free list.
+ //
+
+ Adapter->SonicBuffers[i-1].Next = -1;
+
+ //
+ // Now do the large buffers; note that they have one
+ // Physical address per buffer.
+ //
+
+ Adapter->SonicBufferListHeads[3] = i;
+
+ for (
+ ;
+ i < SONIC_NUMBER_OF_SMALL_BUFFERS +
+ SONIC_NUMBER_OF_MEDIUM_BUFFERS +
+ SONIC_NUMBER_OF_LARGE_BUFFERS;
+ i++
+ ) {
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ SONIC_LARGE_BUFFER_SIZE,
+ TRUE, // CACHED!
+ (PVOID *)&Adapter->SonicBuffers[i].VirtualSonicBuffer,
+ &Adapter->SonicBuffers[i].PhysicalSonicBuffer
+ );
+
+ if (Adapter->SonicBuffers[i].VirtualSonicBuffer == NULL) {
+
+ return FALSE;
+ }
+
+ if (NdisGetPhysicalAddressHigh(Adapter->SonicBuffers[i].PhysicalSonicBuffer) != 0) {
+ return FALSE;
+ }
+
+ Adapter->SonicBuffers[i].FlushBuffer =
+ AllocateFlushBuffer(
+ Adapter,
+ Adapter->SonicBuffers[i].VirtualSonicBuffer,
+ SONIC_LARGE_BUFFER_SIZE
+ );
+
+ if (!Adapter->SonicBuffers[i].FlushBuffer) {
+ return FALSE;
+ }
+
+
+ Adapter->SonicBuffers[i].Next = i+1;
+
+ }
+
+ //
+ // Make sure that the last buffer correctly terminates the free list.
+ //
+
+ Adapter->SonicBuffers[i-1].Next = -1;
+
+
+ //
+ // Allocate the BlankBuffer
+ //
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ SONIC_SMALL_BUFFER_SIZE,
+ TRUE, // CACHED!
+ (PVOID *)&Adapter->BlankBuffer,
+ &Adapter->BlankBufferAddress
+ );
+
+ if (Adapter->BlankBuffer == NULL) {
+ return FALSE;
+ }
+
+ if (NdisGetPhysicalAddressHigh(Adapter->BlankBufferAddress) != 0) {
+ return FALSE;
+ }
+
+ for (i=0; i < SONIC_SMALL_BUFFER_SIZE; i++) {
+
+ Adapter->BlankBuffer[i] = ' ';
+
+ }
+
+
+ //
+ // Flush the blank buffer now, it never changes.
+ //
+
+ FlushBuffer = AllocateFlushBuffer(
+ Adapter,
+ Adapter->BlankBuffer,
+ SONIC_SMALL_BUFFER_SIZE
+ );
+
+ if (!FlushBuffer) {
+ return FALSE;
+ }
+
+ SONIC_FLUSH_WRITE_BUFFER(FlushBuffer);
+
+ //
+ // We are done with the FlushBuffer.
+ //
+
+ NdisFreeBuffer(FlushBuffer);
+
+
+ return TRUE;
+
+}
+
+
+extern
+VOID
+DeleteAdapterMemory(
+ IN PSONIC_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deallocates memory for:
+
+ - Transmit ring entries
+
+ - Receive ring entries
+
+ - Receive buffers
+
+ - Adapter buffers for use if user transmit buffers don't meet hardware
+ contraints
+
+ - Structures to map transmit ring entries back to the packets.
+
+Arguments:
+
+ Adapter - The adapter to deallocate memory for.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ if (Adapter->TransmitDescriptorArea) {
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(SONIC_TRANSMIT_DESCRIPTOR)*
+ Adapter->NumberOfTransmitDescriptors,
+ FALSE,
+ Adapter->TransmitDescriptorArea,
+ Adapter->TransmitDescriptorAreaPhysical
+ );
+
+ }
+
+ if (Adapter->CamDescriptorAreaFlushBuffer) {
+
+ NdisFreeBuffer(Adapter->CamDescriptorAreaFlushBuffer);
+
+ }
+
+ if (Adapter->ReceiveBufferArea) {
+
+ UINT i;
+ NDIS_PHYSICAL_ADDRESS PhysicalAddr;
+
+ for (
+ i = 0;
+ i < Adapter->NumberOfReceiveBuffers;
+ i++
+ ) {
+
+ //
+ // Free the receive flush buffer.
+ //
+
+ if ( Adapter->ReceiveNdisBufferArea[i] != NULL ) {
+
+ NdisFreeBuffer(Adapter->ReceiveNdisBufferArea[i]);
+
+ }
+
+ //
+ // Free the receive buffer.
+ //
+
+ if ( Adapter->ReceiveBufferArea[i] != NULL ) {
+
+ NdisSetPhysicalAddressHigh(PhysicalAddr, 0);
+
+ NdisSetPhysicalAddressLow(
+ PhysicalAddr,
+ SONIC_GET_RECEIVE_RESOURCE_ADDRESS(&Adapter->ReceiveResourceArea[i]));
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ SONIC_SIZE_OF_RECEIVE_BUFFERS,
+ TRUE, //... CACHED!
+ Adapter->ReceiveBufferArea[i],
+ PhysicalAddr
+ );
+ }
+ }
+
+ SONIC_FREE_MEMORY(
+ Adapter->ReceiveBufferArea,
+ sizeof(PVOID) * Adapter->NumberOfReceiveBuffers
+ );
+
+ SONIC_FREE_MEMORY(
+ Adapter->ReceiveNdisBufferArea,
+ sizeof(PNDIS_BUFFER) * Adapter->NumberOfReceiveBuffers
+ );
+ }
+
+ if (Adapter->ReceiveResourceArea) {
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ (sizeof(SONIC_RECEIVE_RESOURCE)*Adapter->NumberOfReceiveBuffers) +
+ sizeof(SONIC_CAM_DESCRIPTOR_AREA),
+ TRUE,
+ Adapter->ReceiveResourceArea,
+ Adapter->ReceiveResourceAreaPhysical
+ );
+
+ }
+
+ if (Adapter->ReceiveDescriptorArea) {
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(SONIC_RECEIVE_DESCRIPTOR) *
+ Adapter->NumberOfReceiveDescriptors,
+ FALSE,
+ Adapter->ReceiveDescriptorArea,
+ Adapter->ReceiveDescriptorAreaPhysical
+ );
+
+ }
+
+ if (Adapter->DescriptorToPacket) {
+
+ SONIC_FREE_MEMORY(Adapter->DescriptorToPacket,
+ sizeof(SONIC_DESCRIPTOR_TO_PACKET)
+ *Adapter->NumberOfTransmitDescriptors);
+
+ }
+
+
+ if (Adapter->SmallSonicBuffers) {
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ SONIC_SMALL_BUFFER_SIZE * SONIC_NUMBER_OF_SMALL_BUFFERS,
+ TRUE,
+ Adapter->SmallSonicBuffers,
+ Adapter->SonicBuffers[0].PhysicalSonicBuffer
+ );
+
+ }
+
+ if (Adapter->MediumSonicBuffers) {
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ SONIC_MEDIUM_BUFFER_SIZE * SONIC_NUMBER_OF_MEDIUM_BUFFERS,
+ TRUE,
+ Adapter->MediumSonicBuffers,
+ Adapter->SonicBuffers[SONIC_NUMBER_OF_SMALL_BUFFERS].PhysicalSonicBuffer
+ );
+
+ }
+
+ if (Adapter->SonicBuffers) {
+
+ UINT i;
+
+ //
+ // First free the large buffers.
+ //
+
+ for (
+ i = SONIC_NUMBER_OF_SMALL_BUFFERS +
+ SONIC_NUMBER_OF_MEDIUM_BUFFERS;
+ i < SONIC_NUMBER_OF_SMALL_BUFFERS +
+ SONIC_NUMBER_OF_MEDIUM_BUFFERS +
+ SONIC_NUMBER_OF_LARGE_BUFFERS;
+ i++) {
+
+ if (Adapter->SonicBuffers[i].VirtualSonicBuffer) {
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ SONIC_LARGE_BUFFER_SIZE,
+ TRUE,
+ Adapter->SonicBuffers[i].VirtualSonicBuffer,
+ Adapter->SonicBuffers[i].PhysicalSonicBuffer
+ );
+
+ } else {
+
+ break;
+
+ }
+
+ }
+
+ //
+ // Now free the flush buffers.
+ //
+
+ for (
+ i = 0;
+ i < SONIC_NUMBER_OF_SMALL_BUFFERS +
+ SONIC_NUMBER_OF_MEDIUM_BUFFERS +
+ SONIC_NUMBER_OF_LARGE_BUFFERS;
+ i++) {
+
+ if (Adapter->SonicBuffers[i].FlushBuffer) {
+ NdisFreeBuffer(Adapter->SonicBuffers[i].FlushBuffer);
+ }
+
+ }
+
+ SONIC_FREE_MEMORY(Adapter->SonicBuffers,
+ sizeof(SONIC_BUFFER_DESCRIPTOR)*
+ (SONIC_NUMBER_OF_SMALL_BUFFERS +
+ SONIC_NUMBER_OF_MEDIUM_BUFFERS +
+ SONIC_NUMBER_OF_LARGE_BUFFERS)
+ );
+
+ }
+
+
+ if (Adapter->BlankBuffer) {
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ SONIC_SMALL_BUFFER_SIZE,
+ TRUE,
+ Adapter->BlankBuffer,
+ Adapter->BlankBufferAddress
+ );
+
+ }
+
+
+ if (Adapter->FlushBufferPoolHandle) {
+
+ NdisFreeBufferPool(Adapter->FlushBufferPoolHandle);
+
+ }
+
+}
diff --git a/private/ntos/ndis/sonic/i386/sonicdet.h b/private/ntos/ndis/sonic/i386/sonicdet.h
new file mode 100644
index 000000000..e318ed667
--- /dev/null
+++ b/private/ntos/ndis/sonic/i386/sonicdet.h
@@ -0,0 +1,68 @@
+/*++
+
+Copyright (c) 1990-1992 Microsoft Corporation
+
+Module Name:
+
+ sonicdet.h
+
+Abstract:
+
+ This file has processor-specific definitions.
+
+ The overall structure is taken from the Lance driver
+ by Tony Ercolano.
+
+Author:
+
+ Anthony V. Ercolano (tonye) creation-date 19-Jun-1990
+ Adam Barr (adamba) 5-Nov-1991
+
+Environment:
+
+ This driver is expected at the equivalent of kernel mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Revision History:
+
+
+--*/
+
+
+//
+// Handy macros to read out of sonic ports.
+//
+// Because the use of PortShift makes the code more complicated,
+// we make some assumptions about when it is needed. On x86, we
+// only support the EISA card; on MIPS, we only support the
+// internal version unless MIPS_EISA_SONIC is defined.
+//
+// We define two constants, SONIC_EISA and SONIC_INTERNAL, if
+// that particular adapter type is supported by this driver.
+// This is to prevent unneeded code from being compiled in.
+//
+
+
+//
+// x86, only the EISA card is supported, the registers are always 16 bits.
+//
+
+#define SONIC_WRITE_PORT(_Adapter, _Port, _Value) \
+ NdisRawWritePortUshort((_Adapter)->SonicPortAddress + (_Port * 2), (USHORT)(_Value))
+
+#define SONIC_READ_PORT(_Adapter, _Port, _Value) \
+ NdisRawReadPortUshort((_Adapter)->SonicPortAddress + (_Port * 2), (PUSHORT)(_Value))
+
+
+#define SONIC_EISA
+#undef SONIC_INTERNAL
+#undef MIPS_EISA_SONIC // just in case it is defined
+
+
+//
+// The default adapter type is EISA
+//
+
+#define SONIC_ADAPTER_TYPE_DEFAULT SONIC_ADAPTER_TYPE_EISA
diff --git a/private/ntos/ndis/sonic/interrup.c b/private/ntos/ndis/sonic/interrup.c
new file mode 100644
index 000000000..f3034f80e
--- /dev/null
+++ b/private/ntos/ndis/sonic/interrup.c
@@ -0,0 +1,1694 @@
+/*++
+
+Copyright (c) 1990-1992 Microsoft Corporation
+
+Module Name:
+
+ interrup.c
+
+Abstract:
+
+ This is a part of the driver for the National Semiconductor SONIC
+ Ethernet controller. It contains the interrupt-handling routines.
+ This driver conforms to the NDIS 3.0 miniport interface.
+
+Author:
+
+ Adam Barr (adamba) 16-Jan-1991
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent.
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+
+#include <sonichrd.h>
+#include <sonicsft.h>
+
+#define REMOVE_EOL_AND_ACK(A,L) \
+{ \
+ PSONIC_ADAPTER _A = A; \
+ SONIC_REMOVE_END_OF_LIST(L); \
+ if ((_A)->ReceiveDescriptorsExhausted) { \
+ SONIC_WRITE_PORT((_A), SONIC_INTERRUPT_STATUS, \
+ SONIC_INT_RECEIVE_DESCRIPTORS \
+ ); \
+ (_A)->ReceiveDescriptorsExhausted = FALSE; \
+ } \
+}
+
+#define WRITE_RWP_AND_ACK(A,RWP) \
+{ \
+ PSONIC_ADAPTER _A = A; \
+ SONIC_WRITE_PORT((_A), SONIC_RESOURCE_WRITE, (RWP)); \
+ if ((_A)->ReceiveBuffersExhausted) { \
+ SONIC_WRITE_PORT((_A), SONIC_INTERRUPT_STATUS, \
+ SONIC_INT_RECEIVE_BUFFERS \
+ ); \
+ (_A)->ReceiveBuffersExhausted = FALSE; \
+ } \
+}
+
+
+VOID
+SonicDisableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to turn off all interrupts from the adapter.
+
+Arguments:
+
+ Context - A pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PSONIC_ADAPTER Adapter = PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ SONIC_WRITE_PORT(Adapter, SONIC_INTERRUPT_MASK,
+ 0
+ );
+
+}
+
+VOID
+SonicEnableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to turn on all interrupts from the adapter.
+
+Arguments:
+
+ Context - A pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PSONIC_ADAPTER Adapter = PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ SONIC_WRITE_PORT(Adapter, SONIC_INTERRUPT_MASK,
+ SONIC_INT_DEFAULT_VALUE
+ );
+
+}
+
+
+
+
+
+STATIC
+BOOLEAN
+ProcessReceiveInterrupts(
+ IN PSONIC_ADAPTER Adapter
+ );
+
+STATIC
+BOOLEAN
+ProcessTransmitInterrupts(
+ IN PSONIC_ADAPTER Adapter
+ );
+
+STATIC
+VOID
+ProcessInterrupt(
+ IN PSONIC_ADAPTER Adapter
+ );
+
+
+extern
+VOID
+SonicInterruptService(
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueDpc,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ Interrupt service routine for the sonic. This routine only gets
+ called during initial initialization of the adapter.
+
+Arguments:
+
+ InterruptRecognized - Boolean value which returns TRUE if the
+ ISR recognizes the interrupt as coming from this adapter.
+
+ QueueDpc - TRUE if a DPC should be queued.
+
+ Context - Really a pointer to the adapter.
+
+Return Value:
+
+ Returns true if the card ISR is non-zero.
+
+--*/
+
+{
+
+ //
+ // Will hold the value from the ISR.
+ //
+ USHORT LocalIsrValue;
+
+ //
+ // Holds the pointer to the adapter.
+ //
+ PSONIC_ADAPTER Adapter = Context;
+
+
+ SONIC_READ_PORT(Adapter, SONIC_INTERRUPT_STATUS, &LocalIsrValue);
+
+ if (LocalIsrValue != 0x0000) {
+
+#if DBG
+ if (SonicDbg) {
+ if (LocalIsrValue & (
+ SONIC_INT_BUS_RETRY |
+ SONIC_INT_LOAD_CAM_DONE |
+ SONIC_INT_PROG_INTERRUPT |
+ SONIC_INT_TRANSMIT_ERROR |
+ SONIC_INT_RECEIVE_DESCRIPTORS |
+ SONIC_INT_RECEIVE_BUFFERS |
+ SONIC_INT_RECEIVE_OVERFLOW |
+ SONIC_INT_CRC_TALLY_ROLLOVER |
+ SONIC_INT_FAE_TALLY_ROLLOVER |
+ SONIC_INT_MP_TALLY_ROLLOVER
+ )) {
+ DbgPrint("ISR %x\n", LocalIsrValue);
+ }
+ }
+#endif
+
+ //
+ // Check for exhausted receive descriptors.
+ //
+
+ if ( LocalIsrValue & SONIC_INT_RECEIVE_DESCRIPTORS ) {
+
+ Adapter->ReceiveDescriptorsExhausted = TRUE;
+
+ LocalIsrValue &= ~SONIC_INT_RECEIVE_DESCRIPTORS;
+ }
+
+ //
+ // Check for exhausted receive buffers.
+ //
+
+ if ( LocalIsrValue & SONIC_INT_RECEIVE_BUFFERS ) {
+
+ Adapter->ReceiveBuffersExhausted = TRUE;
+
+ LocalIsrValue &= ~SONIC_INT_RECEIVE_BUFFERS;
+ }
+
+ //
+ // It's our interrupt. Clear only those bits that we got
+ // in this read of ISR.
+ //
+
+ *InterruptRecognized = TRUE;
+
+ SONIC_WRITE_PORT(
+ Adapter,
+ SONIC_INTERRUPT_STATUS,
+ (USHORT)(LocalIsrValue)
+ );
+
+ //
+ // If we got a LOAD_CAM_DONE interrupt, it may be
+ // because our first initialization is complete.
+ // We check this here because on some systems the
+ // DeferredProcessing call might not interrupt
+ // the initialization process.
+ //
+
+ if (LocalIsrValue & SONIC_INT_LOAD_CAM_DONE) {
+
+ if (Adapter->FirstInitialization) {
+
+ Adapter->FirstInitialization = FALSE;
+
+#if DBG
+ {
+ USHORT PortValue;
+
+ SONIC_READ_PORT(Adapter, SONIC_SILICON_REVISION, &PortValue);
+ if (SonicDbg) {
+ DbgPrint("SONIC Initialized: Revision %d\n", PortValue);
+ }
+ }
+#endif
+
+ }
+ }
+
+ //
+ // No deferred processing is needed.
+ //
+ *QueueDpc = FALSE;
+
+ return;
+
+ } else {
+
+ *InterruptRecognized = FALSE;
+ *QueueDpc = FALSE;
+ return;
+
+ }
+
+}
+
+VOID
+SonicHandleInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ This DPR routine is queued by the wrapper after every interrupt
+ and also by other routines within the driver that notice that
+ some deferred processing needs to be done. It's main
+ job is to call the interrupt processing code.
+
+Arguments:
+
+ MiniportAdapterContext - Really a pointer to the adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // A pointer to the adapter object.
+ //
+ PSONIC_ADAPTER Adapter = (PSONIC_ADAPTER)MiniportAdapterContext;
+
+ //
+ // Holds a value of the Interrupt Status register.
+ //
+ USHORT Isr;
+ USHORT ThisIsrValue;
+
+ //
+ // TRUE if the main loop did something.
+ //
+ BOOLEAN DidSomething = TRUE;
+
+ //
+ // TRUE if ReceiveComplete needs to be indicated.
+ //
+ BOOLEAN IndicateReceiveComplete = FALSE;
+
+ //
+ // Grab any simulated interrupts
+ //
+ Isr = Adapter->SimulatedIsr;
+ Adapter->SimulatedIsr = 0;
+
+ //
+ // Loop until there are no more processing sources.
+ //
+
+#if DBG
+ if (SonicDbg) {
+
+ DbgPrint("In Dpr\n");
+ }
+#endif
+
+ //
+ // If the hardware has failed, do nothing until the reset completes
+ //
+ if (Adapter->HardwareFailure) {
+
+ return;
+
+ }
+
+ while (DidSomething) {
+
+ //
+ // Set this FALSE now, so if nothing happens we
+ // will exit.
+ //
+
+ DidSomething = FALSE;
+
+ //
+ // Read in all outstanding interrupt reasons.
+ //
+
+ SONIC_READ_PORT(Adapter, SONIC_INTERRUPT_STATUS, &ThisIsrValue);
+
+ //
+ // Check for exhausted receive descriptors.
+ //
+
+ if ( ThisIsrValue & SONIC_INT_RECEIVE_DESCRIPTORS ) {
+
+ Adapter->ReceiveDescriptorsExhausted = TRUE;
+
+ ThisIsrValue &= ~SONIC_INT_RECEIVE_DESCRIPTORS;
+ }
+
+ //
+ // Check for exhausted receive buffers.
+ //
+
+ if ( ThisIsrValue & SONIC_INT_RECEIVE_BUFFERS ) {
+
+ Adapter->ReceiveBuffersExhausted = TRUE;
+
+ ThisIsrValue &= ~SONIC_INT_RECEIVE_BUFFERS;
+ }
+
+ //
+ // Acknowledge these interrupts
+ //
+
+ SONIC_WRITE_PORT(Adapter, SONIC_INTERRUPT_STATUS, ThisIsrValue);
+
+ //
+ // Save these bits.
+ //
+ Isr |= ThisIsrValue;
+
+ //
+ // Check for receive interrupts.
+ //
+
+ if (Isr & SONIC_INT_PACKET_RECEIVED) {
+
+ DidSomething = TRUE;
+
+ } else {
+
+ goto DoneProcessingReceives;
+
+ }
+
+ //
+ // After we process any
+ // other interrupt source we always come back to the top
+ // of the loop to check if any more receive packets have
+ // come in. This is to lessen the probability that we
+ // drop a receive.
+ //
+ // ProcessReceiveInterrupts may exit early if it has
+ // processed too many receives in a row. In this case
+ // it returns FALSE, we don't clear the PACKET_RECEIVED
+ // bit, and we will loop through here again.
+ //
+
+ if (ProcessReceiveInterrupts(Adapter)) {
+ Isr &= ~SONIC_INT_PACKET_RECEIVED;
+ }
+
+ //
+ // If the hardware failed, then exit
+ //
+ if (Adapter->HardwareFailure) {
+ return;
+ }
+
+ IndicateReceiveComplete = TRUE;
+
+ //
+ // We set ProcessingReceiveInterrupt to FALSE here so
+ // that we can issue new receive indications while
+ // the rest of the loop is proceeding.
+ //
+
+DoneProcessingReceives:;
+
+ //
+ // Check the interrupt source and other reasons
+ // for processing. If there are no reasons to
+ // process then exit this loop.
+ //
+
+ if ((Isr & (SONIC_INT_LOAD_CAM_DONE |
+ SONIC_INT_PROG_INTERRUPT |
+ SONIC_INT_PACKET_TRANSMITTED |
+ SONIC_INT_TRANSMIT_ERROR |
+ SONIC_INT_CRC_TALLY_ROLLOVER |
+ SONIC_INT_FAE_TALLY_ROLLOVER |
+ SONIC_INT_MP_TALLY_ROLLOVER))) {
+
+ DidSomething = TRUE;
+
+ } else {
+
+ goto DoneProcessingGeneral;
+
+ }
+
+ //
+ // Check for a Load CAM completing.
+ //
+ // This can happen due to a change in the CAM, due to
+ // initialization (in which case we won't save the bit
+ // and will not come through this code), or a reset
+ // (in which case ResetInProgress will be TRUE).
+ //
+
+ //
+ // Check for non-packet related happenings.
+ //
+
+ if (Isr & SONIC_INT_LOAD_CAM_DONE) {
+
+ Isr &= ~SONIC_INT_LOAD_CAM_DONE;
+
+ if (Adapter->ResetInProgress) {
+
+ //
+ // This initialization is from a reset.
+ //
+
+ Adapter->ResetInProgress = FALSE;
+
+ //
+ // Restart the chip.
+ //
+
+ SonicStartChip(Adapter);
+
+ //
+ // Complete the reset.
+ //
+
+ NdisMResetComplete(
+ Adapter->MiniportAdapterHandle,
+ NDIS_STATUS_SUCCESS,
+ TRUE
+ );
+
+ } else { // ResetInProgress FALSE
+
+ NdisMSetInformationComplete(
+ Adapter->MiniportAdapterHandle,
+ NDIS_STATUS_SUCCESS);
+
+ }
+
+ }
+
+ //
+ // Now process any remaining interrupts.
+ //
+
+ if (Isr & (SONIC_INT_CRC_TALLY_ROLLOVER |
+ SONIC_INT_FAE_TALLY_ROLLOVER |
+ SONIC_INT_MP_TALLY_ROLLOVER)) {
+
+ //
+ // If any of the counters overflowed, then we update
+ // the counter by adding one to the high sixteen bits
+ // and reading the register for the low sixteen bits.
+ //
+
+ if (Isr & SONIC_INT_CRC_TALLY_ROLLOVER) {
+
+ USHORT CrcError;
+ SONIC_READ_PORT(Adapter, SONIC_CRC_ERROR, &CrcError);
+
+ Adapter->GeneralOptional[GO_RECEIVE_CRC - GO_ARRAY_START] =
+ (Adapter->GeneralOptional[GO_RECEIVE_CRC - GO_ARRAY_START] & 0xffff0000) +
+ 0x10000 +
+ CrcError;
+
+ }
+
+ if (Isr & SONIC_INT_FAE_TALLY_ROLLOVER) {
+
+ USHORT FaError;
+ SONIC_READ_PORT(Adapter, SONIC_FRAME_ALIGNMENT_ERROR, &FaError);
+
+ Adapter->MediaMandatory[MM_RECEIVE_ERROR_ALIGNMENT] =
+ (Adapter->MediaMandatory[MM_RECEIVE_ERROR_ALIGNMENT] & 0xffff0000) +
+ 0x10000 +
+ FaError;
+
+ }
+
+ if (Isr & SONIC_INT_MP_TALLY_ROLLOVER) {
+
+ USHORT MissedPacket;
+ SONIC_READ_PORT(Adapter, SONIC_MISSED_PACKET, &MissedPacket);
+
+ Adapter->GeneralMandatory[GM_RECEIVE_NO_BUFFER] =
+ (Adapter->GeneralMandatory[GM_RECEIVE_NO_BUFFER] & 0xffff0000) +
+ 0x10000 +
+ MissedPacket;
+
+ }
+
+ Isr &= ~(SONIC_INT_CRC_TALLY_ROLLOVER |
+ SONIC_INT_FAE_TALLY_ROLLOVER |
+ SONIC_INT_MP_TALLY_ROLLOVER);
+
+ }
+
+ //
+ // Process the transmit interrupts if there are any.
+ //
+
+ if (Isr & (SONIC_INT_PROG_INTERRUPT |
+ SONIC_INT_PACKET_TRANSMITTED |
+ SONIC_INT_TRANSMIT_ERROR)) {
+
+ {
+
+ if (!ProcessTransmitInterrupts(Adapter)) {
+
+ //
+ // Process interrupts returns false if it
+ // finds no more work to do. If this so we
+ // turn off the transmitter interrupt source.
+ //
+
+ Isr &= ~ (SONIC_INT_PROG_INTERRUPT |
+ SONIC_INT_PACKET_TRANSMITTED |
+ SONIC_INT_TRANSMIT_ERROR);
+
+ }
+
+ }
+
+ }
+
+
+DoneProcessingGeneral:;
+
+ }
+
+ if (IndicateReceiveComplete) {
+
+ //
+ // We have indicated at least one packet, we now
+ // need to signal that the receives are complete.
+ //
+
+ NdisMEthIndicateReceiveComplete(Adapter->MiniportAdapterHandle);
+
+ }
+
+}
+
+#define SONIC_RECEIVE_LIMIT 10
+
+
+STATIC
+BOOLEAN
+ProcessReceiveInterrupts(
+ IN PSONIC_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Process the packets that have finished receiving.
+
+Arguments:
+
+ Adapter - The adapter to indicate to.
+
+Return Value:
+
+ FALSE if we exit because we have indicated SONIC_RECEIVE_LIMIT
+ packets, TRUE if there are no more packets.
+
+--*/
+
+{
+
+ //
+ // We don't get here unless there was a receive. Loop through
+ // the receive descriptors starting at the last known descriptor
+ // owned by the hardware that begins a packet.
+ //
+ // Examine each receive ring descriptor for errors.
+ //
+ // We keep an array whose elements are indexed by the ring
+ // index of the receive descriptors. The arrays elements are
+ // the virtual addresses of the buffers pointed to by
+ // each ring descriptor.
+ //
+ // When we have the entire packet (and error processing doesn't
+ // prevent us from indicating it), we give the routine that
+ // processes the packet through the filter, the buffers virtual
+ // address (which is always the lookahead size) and as the
+ // MAC context the index to the first and last ring descriptors
+ // comprising the packet.
+ //
+
+
+ //
+ // Pointer to the receive descriptor being examined.
+ //
+ PSONIC_RECEIVE_DESCRIPTOR CurrentDescriptor =
+ &Adapter->ReceiveDescriptorArea[
+ Adapter->CurrentReceiveDescriptorIndex];
+
+ //
+ // Index of the RBA that the next packet should
+ // come out of.
+ //
+ UINT CurrentRbaIndex = Adapter->CurrentReceiveBufferIndex;
+
+ //
+ // Virtual address of the start of that RBA.
+ //
+ PVOID CurrentRbaVa = Adapter->ReceiveBufferArea[CurrentRbaIndex];
+
+ //
+ // Physical address of the start of that RBA.
+ //
+ SONIC_PHYSICAL_ADDRESS CurrentRbaPhysical =
+ SONIC_GET_RECEIVE_RESOURCE_ADDRESS(&Adapter->ReceiveResourceArea[CurrentRbaIndex]);
+
+ //
+ // The size of the packet.
+ //
+ UINT PacketSize;
+
+ //
+ // The amount of data received in the RBA (will be PacketSize +
+ // 4 for the CRC).
+
+ USHORT ByteCount;
+
+ //
+ // The amount of lookahead data to indicate.
+ //
+ UINT LookAheadSize;
+
+ //
+ // The offset of the start of the packet in its receive buffer.
+ //
+ UINT PacketOffsetInRba;
+
+ //
+ // The Physical address of the packet.
+ //
+ SONIC_PHYSICAL_ADDRESS PacketPhysical;
+
+ //
+ // A pointer to the link field at the end of the receive
+ // descriptor before the one we are processing.
+ //
+ PSONIC_PHYSICAL_ADDRESS PrevLinkFieldAddr;
+
+ //
+ // The virtual address of the packet.
+ //
+ PVOID PacketVa;
+
+ //
+ // The status of the packet.
+ //
+ USHORT ReceiveStatus;
+
+ //
+ // Is the descriptor in use by the sonic.
+ //
+ USHORT InUse;
+
+ //
+ // Used tempoerarily to determine PacketPhysical.
+ //
+ USHORT PacketAddress;
+
+ //
+ // How many packets we have indicated this time.
+ //
+ UINT PacketsIndicated = 0;
+
+ //
+ // Used with update shared memory.
+ //
+
+ NDIS_PHYSICAL_ADDRESS TempAddress;
+
+#if DBG
+ //
+ // For debugging, save the previous receive descriptor.
+ //
+ static SONIC_RECEIVE_DESCRIPTOR PreviousDescriptor;
+#endif
+
+
+ do {
+
+ //
+ // Ensure that the system memory copy of the
+ // receive descriptor is up-to-date.
+ //
+
+ NdisMUpdateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(SONIC_RECEIVE_DESCRIPTOR) *
+ Adapter->NumberOfReceiveDescriptors,
+ Adapter->ReceiveDescriptorArea,
+ Adapter->ReceiveDescriptorAreaPhysical
+ );
+
+
+ //
+ // Check to see whether we own the packet. If
+ // we don't then simply return to the caller.
+ //
+
+ NdisReadRegisterUshort(&CurrentDescriptor->InUse, &InUse);
+
+ if (InUse != SONIC_OWNED_BY_SYSTEM) {
+
+ return TRUE;
+ }
+
+ //
+ // Figure out the virtual address of the packet.
+ //
+
+ NdisReadRegisterUshort((PUSHORT)&CurrentDescriptor->LowPacketAddress,
+ (PUSHORT)&PacketAddress);
+ PacketPhysical = PacketAddress;
+ NdisReadRegisterUshort((PUSHORT)&CurrentDescriptor->HighPacketAddress,
+ (PUSHORT)&PacketAddress);
+ PacketPhysical += PacketAddress << 16;
+
+ if ((PacketPhysical < CurrentRbaPhysical) ||
+ (PacketPhysical > (CurrentRbaPhysical + SONIC_SIZE_OF_RECEIVE_BUFFERS)) ) {
+
+ //
+ // Something is wrong, the packet is not in the
+ // receive buffer that we expect it in.
+ //
+
+ SONIC_PHYSICAL_ADDRESS ResourcePhysical;
+ PSONIC_RECEIVE_RESOURCE CurrentReceiveResource;
+ UINT i;
+
+ if (Adapter->WrongRbaErrorLogCount++ < 5) {
+
+ //
+ // Log an error the first five times this happens.
+ //
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 6,
+ processReceiveInterrupts,
+ SONIC_ERRMSG_WRONG_RBA,
+ (ULONG)CurrentRbaPhysical,
+ (ULONG)PacketPhysical,
+ (ULONG)CurrentDescriptor,
+ (ULONG)Adapter->ReceiveDescriptorArea
+ );
+
+#if DBG
+ DbgPrint("SONIC: RBA at %lx [%lx], Packet at %lx\n", CurrentRbaPhysical, CurrentRbaVa, PacketPhysical);
+
+ DbgPrint("descriptor %lx, start %lx, prev %lx\n",
+ (ULONG)CurrentDescriptor,
+ (ULONG)Adapter->ReceiveDescriptorArea,
+ &PreviousDescriptor);
+#endif
+ }
+
+ //
+ // Attempt to recover by advancing the relevant pointers
+ // to where the SONIC thinks the packet is. First we need
+ // to find the receive buffer that matches the indicated
+ // physical address.
+ //
+
+ for (
+ i = 0, CurrentReceiveResource = Adapter->ReceiveResourceArea;
+ i < Adapter->NumberOfReceiveBuffers;
+ i++,CurrentReceiveResource++
+ ) {
+
+ ResourcePhysical = SONIC_GET_RECEIVE_RESOURCE_ADDRESS(CurrentReceiveResource);
+ if ((PacketPhysical >= ResourcePhysical) &&
+ (PacketPhysical <
+ (ResourcePhysical + SONIC_SIZE_OF_RECEIVE_BUFFERS))) {
+
+ //
+ // We found the receive resource.
+ //
+ break;
+
+ }
+
+ }
+
+ if (i == Adapter->NumberOfReceiveBuffers) {
+
+ //
+ // Quit now, there is a failure by the chip, and we
+ // cannot find the receive.
+ //
+
+ Adapter->HardwareFailure = TRUE;
+
+ return FALSE;
+ }
+
+ //
+ // Update our pointers.
+ //
+
+ Adapter->CurrentReceiveBufferIndex = i;
+
+ CurrentRbaIndex = i;
+
+ CurrentRbaVa = Adapter->ReceiveBufferArea[i];
+
+ CurrentRbaPhysical =
+ SONIC_GET_RECEIVE_RESOURCE_ADDRESS(&Adapter->ReceiveResourceArea[i]);
+
+ //
+ // Flush the receive buffer.
+ //
+
+ NdisFlushBuffer(
+ Adapter->ReceiveNdisBufferArea[i],
+ FALSE
+ );
+
+ //
+ // Ensure that we release buffers before this one
+ // back to the sonic.
+ //
+
+ WRITE_RWP_AND_ACK(
+ Adapter,
+ (USHORT)(CurrentRbaPhysical & 0xffff)
+ );
+
+ }
+
+
+ PacketOffsetInRba = PacketPhysical - CurrentRbaPhysical;
+
+
+ //
+ // Check that the packet was received correctly...note that
+ // we always compute PacketOffsetInRba and ByteCount,
+ // which are needed to skip the packet even if we do not
+ // indicate it.
+ //
+
+ NdisReadRegisterUshort(&CurrentDescriptor->ReceiveStatus, &ReceiveStatus);
+
+ NdisReadRegisterUshort(&CurrentDescriptor->ByteCount, &ByteCount);
+
+ if (!(ReceiveStatus & SONIC_RCR_PACKET_RECEIVED_OK)) {
+
+#if DBG
+ if (SonicDbg) {
+
+ DbgPrint("SONIC: Skipping %lx\n", ReceiveStatus);
+ }
+#endif
+
+ goto SkipIndication;
+
+ }
+
+ //
+ // Prepare to indicate the packet.
+ //
+
+ PacketSize = ByteCount - 4;
+
+ if ( PacketSize > 1514 ) {
+
+#if DBG
+ DbgPrint("SONIC: Skipping packet, length %d\n", PacketSize);
+#endif
+
+ goto SkipIndication;
+ }
+
+
+ if (PacketSize < SONIC_INDICATE_MAXIMUM) {
+
+ LookAheadSize = PacketSize;
+
+ } else {
+
+ LookAheadSize = SONIC_INDICATE_MAXIMUM;
+
+ }
+
+ PacketVa = (PUCHAR) CurrentRbaVa + PacketOffsetInRba;
+
+ //
+ // Ensure that the system memory version of this RBA is up-to-date.
+ //
+
+ NdisFlushBuffer(
+ Adapter->ReceiveNdisBufferArea[CurrentRbaIndex],
+ FALSE
+ );
+
+ NdisSetPhysicalAddressLow(
+ TempAddress,
+ SONIC_GET_RECEIVE_RESOURCE_ADDRESS(&Adapter->ReceiveResourceArea[CurrentRbaIndex])
+ );
+
+ NdisSetPhysicalAddressHigh(TempAddress, 0);
+
+ NdisMUpdateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ SONIC_SIZE_OF_RECEIVE_BUFFERS,
+ Adapter->ReceiveBufferArea[CurrentRbaIndex],
+ TempAddress
+ );
+
+ //
+ // Indicate the packet to the protocol.
+ //
+
+ if ( PacketSize < 14 ) {
+
+ //
+ // Must have at least the destination address
+ //
+
+ if (PacketSize >= ETH_LENGTH_OF_ADDRESS) {
+
+ //
+ // Runt packet
+ //
+
+ NdisMEthIndicateReceive(
+ Adapter->MiniportAdapterHandle,
+ (NDIS_HANDLE)((PUCHAR)PacketVa + 14), // context
+ PacketVa, // header buffer
+ PacketSize, // header buffer size
+ NULL, // lookahead buffer
+ 0, // lookahead buffer size
+ 0 // packet size
+ );
+
+ }
+
+ } else {
+
+ NdisMEthIndicateReceive(
+ Adapter->MiniportAdapterHandle,
+ (NDIS_HANDLE)((PUCHAR)PacketVa + 14), // context
+ PacketVa, // header buffer
+ 14, // header buffer size
+ (PUCHAR)PacketVa + 14, // lookahead buffer
+ LookAheadSize - 14, // lookahead buffer size
+ PacketSize - 14 // packet size
+ );
+
+ }
+
+SkipIndication:;
+
+#if DBG
+ SONIC_MOVE_MEMORY (&PreviousDescriptor, CurrentDescriptor, sizeof(SONIC_RECEIVE_DESCRIPTOR));
+#endif
+
+ //
+ // Give the packet back to the hardware.
+ //
+
+ NdisWriteRegisterUlong(&CurrentDescriptor->InUse, SONIC_OWNED_BY_SONIC);
+
+ //
+ // And re-set the EOL fields correctly.
+ //
+
+ SONIC_SET_END_OF_LIST(
+ &(CurrentDescriptor->Link)
+ );
+
+ if (CurrentDescriptor == Adapter->ReceiveDescriptorArea) {
+
+ //
+ // we are at the first one
+ //
+
+ PrevLinkFieldAddr = &(Adapter->LastReceiveDescriptor->Link);
+
+ } else {
+
+ PrevLinkFieldAddr = &((CurrentDescriptor-1)->Link);
+
+ }
+
+ REMOVE_EOL_AND_ACK(
+ Adapter,
+ PrevLinkFieldAddr
+ );
+
+ //
+ // Now figure out if the RBA is done with.
+ //
+
+ if (ReceiveStatus & SONIC_RCR_LAST_PACKET_IN_RBA) {
+
+ //
+ // Advance which RBA we are looking at.
+ //
+
+ ++CurrentRbaIndex;
+
+ if (CurrentRbaIndex == Adapter->NumberOfReceiveBuffers) {
+
+ CurrentRbaIndex = 0;
+
+ }
+
+ Adapter->CurrentReceiveBufferIndex = CurrentRbaIndex;
+
+ CurrentRbaVa = Adapter->ReceiveBufferArea[CurrentRbaIndex];
+
+ CurrentRbaPhysical =
+ SONIC_GET_RECEIVE_RESOURCE_ADDRESS(&Adapter->ReceiveResourceArea[CurrentRbaIndex]);
+
+ WRITE_RWP_AND_ACK(
+ Adapter,
+ (USHORT)(CurrentRbaPhysical & 0xffff)
+ );
+
+ }
+
+ //
+ // Update statistics now based on the receive status.
+ //
+
+ if (ReceiveStatus & SONIC_RCR_PACKET_RECEIVED_OK) {
+
+ ++Adapter->GeneralMandatory[GM_RECEIVE_GOOD];
+
+ if (ReceiveStatus & SONIC_RCR_BROADCAST_RECEIVED) {
+
+ ++Adapter->GeneralOptionalFrameCount[GO_BROADCAST_RECEIVES];
+ SonicAddUlongToLargeInteger(
+ &Adapter->GeneralOptionalByteCount[GO_BROADCAST_RECEIVES],
+ PacketSize);
+
+ } else if (ReceiveStatus & SONIC_RCR_MULTICAST_RECEIVED) {
+
+ ++Adapter->GeneralOptionalFrameCount[GO_MULTICAST_RECEIVES];
+ SonicAddUlongToLargeInteger(
+ &Adapter->GeneralOptionalByteCount[GO_MULTICAST_RECEIVES],
+ PacketSize);
+
+ } else {
+
+ ++Adapter->GeneralOptionalFrameCount[GO_DIRECTED_RECEIVES];
+ SonicAddUlongToLargeInteger(
+ &Adapter->GeneralOptionalByteCount[GO_DIRECTED_RECEIVES],
+ PacketSize);
+
+ }
+
+ } else {
+
+ ++Adapter->GeneralMandatory[GM_RECEIVE_BAD];
+
+ if (ReceiveStatus & SONIC_RCR_CRC_ERROR) {
+ ++Adapter->GeneralOptional[GO_RECEIVE_CRC - GO_ARRAY_START];
+ } else if (ReceiveStatus & SONIC_RCR_FRAME_ALIGNMENT) {
+ ++Adapter->MediaMandatory[MM_RECEIVE_ERROR_ALIGNMENT];
+ }
+
+ }
+
+ //
+ // Advance our pointers to the next packet.
+
+ if (CurrentDescriptor == Adapter->LastReceiveDescriptor) {
+
+ Adapter->CurrentReceiveDescriptorIndex = 0;
+
+ } else {
+
+ ++(Adapter->CurrentReceiveDescriptorIndex);
+
+ }
+
+ CurrentDescriptor = &Adapter->ReceiveDescriptorArea[
+ Adapter->CurrentReceiveDescriptorIndex];
+
+ ++PacketsIndicated;
+
+ } while (PacketsIndicated < SONIC_RECEIVE_LIMIT);
+
+ //
+ // Indicate that we returned because we indicated SONIC_RECEIVE_
+ // LIMIT packets, not because we ran out of packets to indicate.
+ //
+
+ return FALSE;
+
+}
+
+STATIC
+BOOLEAN
+ProcessTransmitInterrupts(
+ IN PSONIC_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Process the packets that have finished transmitting.
+
+Arguments:
+
+ Adapter - The adapter that was sent from.
+
+Return Value:
+
+ This function will return TRUE if it finished up the
+ send on a packet. It will return FALSE if for some
+ reason there was no packet to process.
+
+--*/
+
+{
+ //
+ // Index into the ring to packet structure. This index points
+ // to the first ring entry for the first buffer used for transmitting
+ // the packet.
+ //
+ UINT DescriptorIndex;
+
+ //
+ // The transmit desctiptor for the packet at Transmitting Descriptor
+ //
+ PSONIC_TRANSMIT_DESCRIPTOR TransmitDescriptor;
+
+ //
+ // Temporarily holds the transmit descriptor after TransmitDescriptor
+ //
+ PSONIC_TRANSMIT_DESCRIPTOR NextTransmitDescriptor;
+
+ //
+ // Pointer to the packet that started this transmission.
+ //
+ PNDIS_PACKET OwningPacket;
+
+ //
+ // Points to the reserved part of the OwningPacket.
+ //
+ PSONIC_PACKET_RESERVED Reserved;
+
+ //
+ // Used to hold the ring to packet mapping information so that
+ // we can release the ring entries as quickly as possible.
+ //
+ SONIC_DESCRIPTOR_TO_PACKET SavedDescriptorMapping;
+
+ //
+ // The status of the transmit.
+ //
+ USHORT TransmitStatus;
+
+ //
+ // Get hold of the first transmitted packet.
+ //
+
+ //
+ // First we check that this is a packet that was transmitted
+ // but not already processed. Recall that this routine
+ // will be called repeatedly until this tests false, Or we
+ // hit a packet that we don't completely own.
+ //
+
+ if (Adapter->TransmittingDescriptor !=
+ Adapter->FirstUncommittedDescriptor) {
+
+ DescriptorIndex =
+ Adapter->TransmittingDescriptor - Adapter->TransmitDescriptorArea;
+
+ } else {
+
+ return FALSE;
+
+ }
+
+ //
+ // We put the mapping into a local variable so that we
+ // can return the mapping as soon as possible.
+ //
+
+ SavedDescriptorMapping = Adapter->DescriptorToPacket[DescriptorIndex];
+
+ //
+ // Get a pointer to the transmit descriptor for this packet.
+ //
+
+ TransmitDescriptor = Adapter->TransmitDescriptorArea + DescriptorIndex;
+
+ //
+ // Get a pointer to the owning packet and the reserved part of
+ // the packet.
+ //
+
+ OwningPacket = SavedDescriptorMapping.OwningPacket;
+
+ Reserved = PSONIC_RESERVED_FROM_PACKET(OwningPacket);
+
+
+ //
+ // Check that status bits were written into the transmit
+ // descriptor.
+ //
+
+ NdisReadRegisterUshort((PUSHORT)&TransmitDescriptor->TransmitStatus, &TransmitStatus);
+
+ if (!(TransmitStatus & SONIC_TCR_STATUS_MASK)) {
+
+ //
+ // The transmit has not completed.
+ //
+
+ return FALSE;
+
+ } else {
+
+ //
+ // Holds whether the packet successfully transmitted or not.
+ //
+ BOOLEAN Successful = TRUE;
+
+ //
+ // Length of the packet
+ //
+ UINT PacketLength;
+
+ //
+ // Points to data in NDIS_BUFFER
+ //
+ PUCHAR BufferVa;
+
+ //
+ // Points to the current ndis buffer being walked.
+ //
+ PNDIS_BUFFER CurrentBuffer;
+
+ Adapter->WakeUpTimeout = FALSE;
+
+ if (SavedDescriptorMapping.UsedSonicBuffer) {
+
+ //
+ // This packet used adapter buffers. We can
+ // now return these buffers to the adapter.
+ //
+
+ //
+ // The adapter buffer descriptor that was allocated to this packet.
+ //
+ PSONIC_BUFFER_DESCRIPTOR BufferDescriptor = Adapter->SonicBuffers +
+ SavedDescriptorMapping.SonicBuffersIndex;
+
+ //
+ // Index of the listhead that heads the list that the adapter
+ // buffer descriptor belongs too.
+ //
+ INT ListHeadIndex = BufferDescriptor->Next;
+
+
+ //
+ // Put the adapter buffer back on the free list.
+ //
+
+ BufferDescriptor->Next = Adapter->SonicBufferListHeads[ListHeadIndex];
+ Adapter->SonicBufferListHeads[ListHeadIndex] = SavedDescriptorMapping.SonicBuffersIndex;
+
+ } else {
+
+ //
+ // Which map register we use for this buffer.
+ //
+ UINT CurMapRegister;
+
+ //
+ // The transmit is finished, so we can release
+ // the physical mapping used for it.
+ //
+
+ NdisQueryPacket(
+ OwningPacket,
+ NULL,
+ NULL,
+ &CurrentBuffer,
+ NULL
+ );
+
+ CurMapRegister = DescriptorIndex * SONIC_MAX_FRAGMENTS;
+
+ while (CurrentBuffer) {
+
+ NdisMCompleteBufferPhysicalMapping(
+ Adapter->MiniportAdapterHandle,
+ CurrentBuffer,
+ CurMapRegister
+ );
+
+ ++CurMapRegister;
+
+ NdisGetNextBuffer(
+ CurrentBuffer,
+ &CurrentBuffer
+ );
+
+ }
+
+ }
+
+
+ //
+ // Now release the transmit descriptor, since we have
+ // gotten all the information we need from it.
+ //
+
+ if (TransmitDescriptor == Adapter->LastTransmitDescriptor) {
+
+ NextTransmitDescriptor = Adapter->TransmitDescriptorArea;
+
+ } else {
+
+ NextTransmitDescriptor = Adapter->TransmittingDescriptor + 1;
+
+ }
+
+ if (TransmitStatus &
+ (SONIC_TCR_EXCESSIVE_DEFERRAL |
+ SONIC_TCR_EXCESSIVE_COLLISIONS |
+ SONIC_TCR_FIFO_UNDERRUN |
+ SONIC_TCR_BYTE_COUNT_MISMATCH)) {
+
+ //
+ // If the packet completed with an abort state, then we
+ // need to restart the transmitter unless we are the
+ // last transmit queued up. We set CTDA to point after
+ // this descriptor in any case.
+ //
+
+#if DBG
+ if (SonicDbg) {
+ DbgPrint ("SONIC: Advancing CTDA after abort\n");
+ }
+#endif
+
+ SONIC_WRITE_PORT(Adapter, SONIC_CURR_TRANSMIT_DESCRIPTOR,
+ SONIC_GET_LOW_PART_ADDRESS(
+ NdisGetPhysicalAddressLow(Adapter->TransmitDescriptorAreaPhysical) +
+ ((PUCHAR)NextTransmitDescriptor -
+ (PUCHAR)Adapter->TransmitDescriptorArea))
+ );
+
+ if (Adapter->FirstUncommittedDescriptor != NextTransmitDescriptor) {
+#if DBG
+ if (SonicDbg) {
+ DbgPrint ("SONIC: Restarting transmit after abort\n");
+ }
+#endif
+ SONIC_WRITE_PORT(Adapter, SONIC_COMMAND, SONIC_CR_TRANSMIT_PACKETS);
+ }
+
+ }
+
+ Adapter->TransmittingDescriptor = NextTransmitDescriptor;
+ Adapter->NumberOfAvailableDescriptors++;
+
+ //
+ // Check if the packet completed OK, and update statistics.
+ //
+
+ if (!(TransmitStatus & SONIC_TCR_PACKET_TRANSMITTED_OK)) {
+
+#if DBG
+ if (SonicDbg) {
+ DbgPrint("SONIC: Transmit failed: %lx\n", TransmitStatus);
+ }
+#endif
+ Successful = FALSE;
+
+ ++Adapter->GeneralMandatory[GM_TRANSMIT_BAD];
+
+ if (TransmitStatus & SONIC_TCR_EXCESSIVE_COLLISIONS) {
+ ++Adapter->MediaOptional[MO_TRANSMIT_MAX_COLLISIONS];
+ }
+
+ if (TransmitStatus & SONIC_TCR_FIFO_UNDERRUN) {
+ ++Adapter->MediaOptional[MO_TRANSMIT_UNDERRUN];
+ }
+
+ } else {
+
+ INT Collisions = (TransmitStatus & SONIC_TCR_COLLISIONS_MASK) >> SONIC_TCR_COLLISIONS_SHIFT;
+
+ UINT Tmp;
+
+ Successful = TRUE;
+
+ ++Adapter->GeneralMandatory[GM_TRANSMIT_GOOD];
+
+ if (Collisions > 0) {
+ if (Collisions == 1) {
+ ++Adapter->MediaMandatory[MM_TRANSMIT_ONE_COLLISION];
+ } else {
+ ++Adapter->MediaMandatory[MM_TRANSMIT_MORE_COLLISIONS];
+ }
+ }
+
+ if (TransmitStatus &
+ (SONIC_TCR_DEFERRED_TRANSMISSION |
+ SONIC_TCR_NO_CARRIER_SENSE |
+ SONIC_TCR_CARRIER_LOST |
+ SONIC_TCR_OUT_OF_WINDOW)) {
+
+ if (TransmitStatus & SONIC_TCR_DEFERRED_TRANSMISSION) {
+ ++Adapter->MediaOptional[MO_TRANSMIT_DEFERRED];
+ }
+ if (TransmitStatus & SONIC_TCR_NO_CARRIER_SENSE) {
+ ++Adapter->MediaOptional[MO_TRANSMIT_HEARTBEAT_FAILURE];
+ }
+ if (TransmitStatus & SONIC_TCR_CARRIER_LOST) {
+ ++Adapter->MediaOptional[MO_TRANSMIT_TIMES_CRS_LOST];
+ }
+ if (TransmitStatus & SONIC_TCR_OUT_OF_WINDOW) {
+ ++Adapter->MediaOptional[MO_TRANSMIT_LATE_COLLISIONS];
+ }
+ }
+
+ NdisQueryPacket(
+ OwningPacket,
+ NULL,
+ NULL,
+ &CurrentBuffer,
+ &PacketLength
+ );
+
+ NdisQueryBuffer(
+ CurrentBuffer,
+ (PVOID *)&BufferVa,
+ &Tmp
+ );
+
+ if (BufferVa[0] == 0xFF) {
+
+ ++Adapter->GeneralOptionalFrameCount[GO_BROADCAST_TRANSMITS];
+ SonicAddUlongToLargeInteger(
+ &Adapter->GeneralOptionalByteCount[GO_BROADCAST_TRANSMITS],
+ PacketLength);
+
+ } else if (BufferVa[0] & 0x01) {
+
+ ++Adapter->GeneralOptionalFrameCount[GO_MULTICAST_TRANSMITS];
+ SonicAddUlongToLargeInteger(
+ &Adapter->GeneralOptionalByteCount[GO_MULTICAST_TRANSMITS],
+ PacketLength);
+
+ } else {
+
+ ++Adapter->GeneralOptionalFrameCount[GO_DIRECTED_TRANSMITS];
+ SonicAddUlongToLargeInteger(
+ &Adapter->GeneralOptionalByteCount[GO_DIRECTED_TRANSMITS],
+ PacketLength);
+
+ }
+
+ }
+
+ //
+ // Remove packet from queue.
+ //
+
+ if (Adapter->LastFinishTransmit == OwningPacket) {
+
+ Adapter->FirstFinishTransmit = NULL;
+ Adapter->LastFinishTransmit = NULL;
+
+ } else {
+
+ Adapter->FirstFinishTransmit = Reserved->Next;
+ }
+
+#ifdef CHECK_DUP_SENDS
+ {
+ VOID SonicRemovePacketFromList(PSONIC_ADAPTER, PNDIS_PACKET);
+ SonicRemovePacketFromList(Adapter, OwningPacket);
+ }
+#endif
+
+ NdisMSendComplete(
+ Adapter->MiniportAdapterHandle,
+ OwningPacket,
+ ((Successful)?(NDIS_STATUS_SUCCESS):(NDIS_STATUS_FAILURE))
+ );
+
+ Adapter->PacketsSinceLastInterrupt = 0;
+
+ return TRUE;
+ }
+
+}
+
+BOOLEAN
+SonicCheckForHang(
+ IN PVOID MiniportAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine checks on the transmit descriptor ring. This is
+ to solve problems where no status is written into the currently
+ transmitting transmit descriptor, which hangs our transmit
+ completion processing. If we detect this state, we simulate
+ a transmit interrupt.
+
+Arguments:
+
+ MiniportAdapterContext - Really a pointer to the adapter.
+
+Return Value:
+
+ FALSE - This routine actually does a wake up, rather than having
+ the wrapper do it.
+
+--*/
+{
+ PSONIC_ADAPTER Adapter = (PSONIC_ADAPTER)MiniportAdapterContext;
+ UINT DescriptorIndex;
+ PSONIC_TRANSMIT_DESCRIPTOR TransmitDescriptor;
+ USHORT TransmitStatus;
+
+ //
+ // If hardware failed, then return now
+ //
+ if (Adapter->HardwareFailure) {
+ return(TRUE);
+ }
+
+ if (Adapter->WakeUpTimeout) {
+
+ //
+ // We had a pending send the last time we ran,
+ // and it has not been completed...we need to fake
+ // its completion.
+ //
+
+ ASSERT (Adapter->TransmittingDescriptor !=
+ Adapter->FirstUncommittedDescriptor);
+
+ DescriptorIndex =
+ Adapter->TransmittingDescriptor - Adapter->TransmitDescriptorArea;
+
+ TransmitDescriptor = Adapter->TransmitDescriptorArea + DescriptorIndex;
+ NdisReadRegisterUshort((PUSHORT)&TransmitDescriptor->TransmitStatus, &TransmitStatus);
+
+ if (!(TransmitStatus & SONIC_TCR_STATUS_MASK)) {
+
+ NdisWriteRegisterUshort ((PUSHORT)&TransmitDescriptor->TransmitStatus,
+ SONIC_TCR_PACKET_TRANSMITTED_OK);
+
+#if DBG
+ DbgPrint ("SONIC: Woke up descriptor at %lx\n", TransmitDescriptor);
+#endif
+
+ }
+
+ Adapter->SimulatedIsr |= SONIC_INT_PACKET_TRANSMITTED;
+
+ Adapter->WakeUpTimeout = FALSE;
+
+ if (Adapter->WakeUpErrorCount < 10) {
+
+ Adapter->WakeUpErrorCount++;
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 1,
+ (ULONG)0xFFFFFFFF
+ );
+ }
+
+ } else if (Adapter->TransmittingDescriptor !=
+ Adapter->FirstUncommittedDescriptor) {
+
+ DescriptorIndex =
+ Adapter->TransmittingDescriptor - Adapter->TransmitDescriptorArea;
+
+ TransmitDescriptor = Adapter->TransmitDescriptorArea + DescriptorIndex;
+ NdisReadRegisterUshort((PUSHORT)&TransmitDescriptor->TransmitStatus, &TransmitStatus);
+
+ if (!(TransmitStatus & SONIC_TCR_STATUS_MASK)) {
+
+ Adapter->WakeUpTimeout = TRUE;
+
+ }
+
+ }
+
+ return(FALSE);
+
+}
diff --git a/private/ntos/ndis/sonic/makefile b/private/ntos/ndis/sonic/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/sonic/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/sonic/mips/sonicdet.h b/private/ntos/ndis/sonic/mips/sonicdet.h
new file mode 100644
index 000000000..9325bec47
--- /dev/null
+++ b/private/ntos/ndis/sonic/mips/sonicdet.h
@@ -0,0 +1,89 @@
+/*++
+
+Copyright (c) 1990-1992 Microsoft Corporation
+
+Module Name:
+
+ sonicdet.h
+
+Abstract:
+
+ This file has processor-specific definitions.
+
+ The overall structure is taken from the Lance driver
+ by Tony Ercolano.
+
+Author:
+
+ Anthony V. Ercolano (tonye) creation-date 19-Jun-1990
+ Adam Barr (adamba) 5-Nov-1991
+
+Environment:
+
+ This driver is expected to work at the equivalent of kernel mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Revision History:
+
+
+--*/
+
+
+//
+// Handy macros to read out of sonic ports.
+//
+// Because the use of PortShift makes the code more complicated,
+// we make some assumptions about when it is needed. On MIPS, we
+// only support the internal version unless MIPS_EISA_SONIC
+// is defined, in which case we support both.
+//
+// We define two constants, SONIC_EISA and SONIC_INTERNAL, if
+// that particular adapter type is supported by this driver.
+// This is to prevent unneeded code from being compiled in.
+//
+
+
+#ifdef MIPS_EISA_SONIC
+
+
+//
+// mips, with support for the EISA card; we have to use PortShift.
+//
+
+#define SONIC_WRITE_PORT(_Adapter, _Port, _Value) \
+ NdisRawWritePortUshort((_Adapter)->SonicPortAddress + (_Port << (_Adapter)->PortShift), (USHORT)(_Value))
+
+#define SONIC_READ_PORT(_Adapter, _Port, _Value) \
+ NdisRawReadPortUshort((_Adapter)->SonicPortAddress + (_Port << (_Adapter)->PortShift), (PUSHORT)(_Value))
+
+#define SONIC_EISA
+#define SONIC_INTERNAL
+
+
+#else // MIPS_EISA_SONIC
+
+
+//
+// mips, internal support only, the registers are always 32 bits
+//
+
+#define SONIC_WRITE_PORT(_Adapter, _Port, _Value) \
+ NdisRawWritePortUshort((_Adapter)->SonicPortAddress + (_Port * 4), (USHORT)(_Value))
+
+#define SONIC_READ_PORT(_Adapter, _Port, _Value) \
+ NdisRawReadPortUshort((_Adapter)->SonicPortAddress + (_Port * 4), (PUSHORT)(_Value))
+
+#undef SONIC_EISA
+#define SONIC_INTERNAL
+
+
+#endif // MIPS_EISA_SONIC
+
+
+//
+// The default adapter type for mips is Internal
+//
+
+#define SONIC_ADAPTER_TYPE_DEFAULT SONIC_ADAPTER_TYPE_INTERNAL
diff --git a/private/ntos/ndis/sonic/request.c b/private/ntos/ndis/sonic/request.c
new file mode 100644
index 000000000..d17d67791
--- /dev/null
+++ b/private/ntos/ndis/sonic/request.c
@@ -0,0 +1,890 @@
+/*++
+
+Copyright (c) 1990-1992 Microsoft Corporation
+
+Module Name:
+
+ request.c
+
+Abstract:
+
+ This is the cose to handle requests for the National Semiconductor
+ SONIC Ethernet controller. This driver conforms to the NDIS 3.0
+ miniport interface.
+
+Author:
+
+ Adam Barr (adamba) 14-Nov-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent.
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+
+#include <sonichrd.h>
+#include <sonicsft.h>
+
+
+
+//
+// This macro determines if the directed address
+// filtering in the CAM is actually necessary given
+// the current filter.
+//
+
+#define CAM_DIRECTED_SIGNIFICANT(_Filter) \
+ ((((_Filter) & NDIS_PACKET_TYPE_DIRECTED) && \
+ (!((_Filter) & NDIS_PACKET_TYPE_PROMISCUOUS))) ? 1 : 0)
+
+
+//
+// This macro determines if the multicast filtering in
+// the CAM are actually necessary given the current filter.
+//
+
+#define CAM_MULTICAST_SIGNIFICANT(_Filter) \
+ ((((_Filter) & NDIS_PACKET_TYPE_MULTICAST) && \
+ (!((_Filter) & (NDIS_PACKET_TYPE_ALL_MULTICAST | \
+ NDIS_PACKET_TYPE_PROMISCUOUS)))) ? 1 : 0)
+
+
+STATIC
+NDIS_STATUS
+ChangeClassDispatch(
+ IN PSONIC_ADAPTER Adapter,
+ IN UINT NewFilterClasses
+ );
+
+STATIC
+NDIS_STATUS
+ChangeAddressDispatch(
+ IN PSONIC_ADAPTER Adapter,
+ IN UINT AddressCount,
+ IN CHAR Addresses[][ETH_LENGTH_OF_ADDRESS]
+ );
+
+
+
+
+extern
+NDIS_STATUS
+SonicQueryInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+ )
+
+/*++
+
+Routine Description:
+
+ SonicQueryInformation handles a query operation for a
+ single OID.
+
+Arguments:
+
+ MiniportAdapterContext - Context registered with the wrapper, really
+ a pointer to the adapter.
+
+ Oid - The OID of the query.
+
+ InformationBuffer - Holds the result of the query.
+
+ InformationBufferLength - The length of InformationBuffer.
+
+ BytesWritten - If the call is successful, returns the number
+ of bytes written to InformationBuffer.
+
+ BytesNeeded - If there is not enough room in InformationBuffer
+ to satisfy the OID, returns the amount of storage needed.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_PENDING
+ NDIS_STATUS_INVALID_LENGTH
+ NDIS_STATUS_INVALID_OID
+
+--*/
+
+{
+ PSONIC_ADAPTER Adapter = PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+ INT i;
+ INT SupportedOids;
+ NDIS_OID MaskOid;
+ PVOID SourceBuffer;
+ ULONG SourceBufferLength;
+ ULONG GenericUlong;
+ USHORT GenericUshort;
+ UCHAR VendorId[4];
+#ifdef SONIC_EISA
+ static const UCHAR EisaDescriptor[] = "SONIC EISA Bus Master Ethernet Adapter (DP83932EB-EISA)";
+#endif
+#ifdef SONIC_INTERNAL
+ static const UCHAR InternalDescriptor[] = "MIPS R4000 on-board network controller";
+#endif
+
+ static const NDIS_OID SonicSupportedOids[] = {
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+ OID_GEN_DIRECTED_BYTES_XMIT,
+ OID_GEN_DIRECTED_FRAMES_XMIT,
+ OID_GEN_MULTICAST_BYTES_XMIT,
+ OID_GEN_MULTICAST_FRAMES_XMIT,
+ OID_GEN_BROADCAST_BYTES_XMIT,
+ OID_GEN_BROADCAST_FRAMES_XMIT,
+ OID_GEN_DIRECTED_BYTES_RCV,
+ OID_GEN_DIRECTED_FRAMES_RCV,
+ OID_GEN_MULTICAST_BYTES_RCV,
+ OID_GEN_MULTICAST_FRAMES_RCV,
+ OID_GEN_BROADCAST_BYTES_RCV,
+ OID_GEN_BROADCAST_FRAMES_RCV,
+ OID_GEN_RCV_CRC_ERROR,
+ OID_GEN_TRANSMIT_QUEUE_LENGTH,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ OID_802_3_RCV_ERROR_ALIGNMENT,
+ OID_802_3_XMIT_ONE_COLLISION,
+ OID_802_3_XMIT_MORE_COLLISIONS,
+ OID_802_3_XMIT_DEFERRED,
+ OID_802_3_XMIT_MAX_COLLISIONS,
+ OID_802_3_RCV_OVERRUN,
+ OID_802_3_XMIT_UNDERRUN,
+ OID_802_3_XMIT_HEARTBEAT_FAILURE,
+ OID_802_3_XMIT_TIMES_CRS_LOST,
+ OID_802_3_XMIT_LATE_COLLISIONS
+ };
+
+ //
+ // Check that the OID is valid.
+ //
+
+ SupportedOids = sizeof(SonicSupportedOids)/sizeof(ULONG);
+
+ for (i=0; i<SupportedOids; i++) {
+ if (Oid == SonicSupportedOids[i]) {
+ break;
+ }
+ }
+
+ if (i == SupportedOids) {
+ *BytesWritten = 0;
+ return NDIS_STATUS_INVALID_OID;
+ }
+
+ //
+ // Initialize these once, since this is the majority
+ // of cases.
+ //
+
+ SourceBuffer = &GenericUlong;
+ SourceBufferLength = sizeof(ULONG);
+
+ switch (Oid & OID_TYPE_MASK) {
+
+ case OID_TYPE_GENERAL_OPERATIONAL:
+
+ switch (Oid) {
+
+ case OID_GEN_MAC_OPTIONS:
+
+ GenericUlong = (ULONG)(NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
+ NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
+ NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
+ NDIS_MAC_OPTION_NO_LOOPBACK
+ );
+
+ break;
+
+ case OID_GEN_SUPPORTED_LIST:
+
+ SourceBuffer = (PVOID)SonicSupportedOids;
+ SourceBufferLength = SupportedOids * sizeof(ULONG);
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+
+ GenericUlong = NdisHardwareStatusReady;
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+
+ GenericUlong = NdisMedium802_3;
+ break;
+
+ case OID_GEN_MEDIA_IN_USE:
+
+ GenericUlong = NdisMedium802_3;
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+
+ GenericUlong = (SONIC_INDICATE_MAXIMUM-14 < SONIC_LOOPBACK_MAXIMUM) ?
+ SONIC_INDICATE_MAXIMUM-14 : SONIC_LOOPBACK_MAXIMUM;
+ break;
+
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+
+ GenericUlong = 1500;
+ break;
+
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+
+ GenericUlong = 1514;
+ break;
+
+ case OID_GEN_LINK_SPEED:
+
+ GenericUlong = 100000; // 10 Mbps in 100 bps units
+ break;
+
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+
+ GenericUlong = SONIC_LARGE_BUFFER_SIZE * SONIC_NUMBER_OF_TRANSMIT_DESCRIPTORS;
+ break;
+
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+
+ GenericUlong = SONIC_LARGE_BUFFER_SIZE * SONIC_NUMBER_OF_RECEIVE_DESCRIPTORS;
+ break;
+
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+
+ GenericUlong = SONIC_LARGE_BUFFER_SIZE;
+ break;
+
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+
+ GenericUlong = SONIC_LARGE_BUFFER_SIZE;
+ break;
+
+ case OID_GEN_VENDOR_ID:
+
+ SONIC_MOVE_MEMORY(VendorId, Adapter->PermanentNetworkAddress, 3);
+ VendorId[3] = 0x0;
+ SourceBuffer = VendorId;
+ SourceBufferLength = sizeof(VendorId);
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+
+ switch (Adapter->AdapterType) {
+#ifdef SONIC_EISA
+ case SONIC_ADAPTER_TYPE_EISA:
+ SourceBuffer = (PVOID)EisaDescriptor;
+ SourceBufferLength = sizeof(EisaDescriptor);
+ break;
+#endif
+#ifdef SONIC_INTERNAL
+ case SONIC_ADAPTER_TYPE_INTERNAL:
+ SourceBuffer = (PVOID)InternalDescriptor;
+ SourceBufferLength = sizeof(InternalDescriptor);
+ break;
+#endif
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+ break;
+
+ case OID_GEN_DRIVER_VERSION:
+
+ GenericUshort = (SONIC_NDIS_MAJOR_VERSION << 8) + SONIC_NDIS_MINOR_VERSION;
+ SourceBuffer = &GenericUshort;
+ SourceBufferLength = sizeof(USHORT);
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ GenericUlong = Adapter->CurrentPacketFilter;
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ GenericUlong = (SONIC_INDICATE_MAXIMUM-14 < SONIC_LOOPBACK_MAXIMUM) ?
+ SONIC_INDICATE_MAXIMUM-14 : SONIC_LOOPBACK_MAXIMUM;
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+
+ break;
+
+ case OID_TYPE_GENERAL_STATISTICS:
+
+ MaskOid = (Oid & OID_INDEX_MASK) - 1;
+
+ switch (Oid & OID_REQUIRED_MASK) {
+
+ case OID_REQUIRED_MANDATORY:
+
+ ASSERT (MaskOid < GM_ARRAY_SIZE);
+
+ if (MaskOid == GM_RECEIVE_NO_BUFFER) {
+
+ //
+ // This one is read off the card, update unless our
+ // counter is more (which indicates an imminent
+ // overflow interrupt, so we don't update).
+ //
+
+ USHORT MissedPacket;
+ SONIC_READ_PORT(Adapter, SONIC_FRAME_ALIGNMENT_ERROR, &MissedPacket);
+
+ if ((Adapter->GeneralMandatory[GM_RECEIVE_NO_BUFFER] & 0xffff) <
+ MissedPacket) {
+
+ Adapter->GeneralMandatory[GM_RECEIVE_NO_BUFFER] =
+ (Adapter->GeneralMandatory[GM_RECEIVE_NO_BUFFER] & 0xffff0000) +
+ MissedPacket;
+
+ }
+ }
+
+ GenericUlong = Adapter->GeneralMandatory[MaskOid];
+ break;
+
+ case OID_REQUIRED_OPTIONAL:
+
+ ASSERT (MaskOid < GO_ARRAY_SIZE);
+
+ if (MaskOid == GO_RECEIVE_CRC) {
+
+ //
+ // This one is read off the card, update unless our
+ // counter is more (which indicates an imminent
+ // overflow interrupt, so we don't update).
+ //
+
+ USHORT CrcError;
+ SONIC_READ_PORT(Adapter, SONIC_FRAME_ALIGNMENT_ERROR, &CrcError);
+
+ if ((Adapter->GeneralOptional[GO_RECEIVE_CRC - GO_ARRAY_START] & 0xffff) <
+ CrcError) {
+
+ Adapter->GeneralOptional[GO_RECEIVE_CRC - GO_ARRAY_START] =
+ (Adapter->GeneralOptional[GO_RECEIVE_CRC - GO_ARRAY_START] & 0xffff0000) +
+ CrcError;
+
+ }
+ }
+
+ if ((MaskOid / 2) < GO_COUNT_ARRAY_SIZE) {
+
+ if (MaskOid & 0x01) {
+ // Frame count
+ GenericUlong = Adapter->GeneralOptionalFrameCount[MaskOid / 2];
+ } else {
+ // Byte count
+ SourceBuffer = &Adapter->GeneralOptionalByteCount[MaskOid / 2];
+ SourceBufferLength = sizeof(LARGE_INTEGER);
+ }
+
+ } else {
+
+ GenericUlong = Adapter->GeneralOptional[MaskOid - GO_ARRAY_START];
+
+ }
+
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+
+ break;
+
+ case OID_TYPE_802_3_OPERATIONAL:
+
+ switch (Oid) {
+
+ case OID_802_3_PERMANENT_ADDRESS:
+
+ SourceBuffer = Adapter->PermanentNetworkAddress;
+ SourceBufferLength = 6;
+ break;
+
+ case OID_802_3_CURRENT_ADDRESS:
+
+ SourceBuffer = Adapter->CurrentNetworkAddress;
+ SourceBufferLength = 6;
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+
+ GenericUlong = SONIC_CAM_ENTRIES - 1;
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+
+ break;
+
+ case OID_TYPE_802_3_STATISTICS:
+
+ MaskOid = (Oid & OID_INDEX_MASK) - 1;
+
+ switch (Oid & OID_REQUIRED_MASK) {
+
+ case OID_REQUIRED_MANDATORY:
+
+ ASSERT (MaskOid < MM_ARRAY_SIZE);
+
+ if (MaskOid == MM_RECEIVE_ERROR_ALIGNMENT) {
+
+ //
+ // This one is read off the card, update unless our
+ // counter is more (which indicates an imminent
+ // overflow interrupt, so we don't update).
+ //
+
+ USHORT FaError;
+ SONIC_READ_PORT(Adapter, SONIC_FRAME_ALIGNMENT_ERROR, &FaError);
+
+ if ((Adapter->MediaMandatory[MM_RECEIVE_ERROR_ALIGNMENT] & 0xffff) <
+ FaError) {
+
+ Adapter->MediaMandatory[MM_RECEIVE_ERROR_ALIGNMENT] =
+ (Adapter->MediaMandatory[MM_RECEIVE_ERROR_ALIGNMENT] & 0xffff0000) +
+ FaError;
+
+ }
+ }
+
+ GenericUlong = Adapter->MediaMandatory[MaskOid];
+ break;
+
+ case OID_REQUIRED_OPTIONAL:
+
+ ASSERT (MaskOid < MO_ARRAY_SIZE);
+ GenericUlong = Adapter->MediaOptional[MaskOid];
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+
+ break;
+
+ }
+
+ if (SourceBufferLength > InformationBufferLength) {
+ *BytesNeeded = SourceBufferLength;
+ return NDIS_STATUS_INVALID_LENGTH;
+ }
+
+ SONIC_MOVE_MEMORY (InformationBuffer, SourceBuffer, SourceBufferLength);
+ *BytesWritten = SourceBufferLength;
+
+ return NDIS_STATUS_SUCCESS;
+
+}
+
+
+STATIC
+NDIS_STATUS
+SonicSetInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ )
+
+/*++
+
+Routine Description:
+
+ SonicQueryInformation handles a set operation for a
+ single OID.
+
+Arguments:
+
+ MiniportAdapterContext - Context registered with the wrapper, really
+ a pointer to the adapter.
+
+ Oid - The OID of the set.
+
+ InformationBuffer - Holds the data to be set.
+
+ InformationBufferLength - The length of InformationBuffer.
+
+ BytesRead - If the call is successful, returns the number
+ of bytes read from InformationBuffer.
+
+ BytesNeeded - If there is not enough data in InformationBuffer
+ to satisfy the OID, returns the amount of storage needed.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_PENDING
+ NDIS_STATUS_INVALID_LENGTH
+ NDIS_STATUS_INVALID_OID
+
+--*/
+
+{
+
+ PSONIC_ADAPTER Adapter = PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+ NDIS_STATUS Status;
+ ULONG PacketFilter;
+
+ //
+ // Now check for the most common OIDs
+ //
+
+ switch (Oid) {
+
+ case OID_802_3_MULTICAST_LIST:
+
+ if (InformationBufferLength % ETH_LENGTH_OF_ADDRESS != 0) {
+
+ //
+ // The data must be a multiple of the Ethernet
+ // address size.
+ //
+
+ return NDIS_STATUS_INVALID_DATA;
+
+ }
+#if DBG
+ if (SonicDbg) {
+ DbgPrint("Processing Change Multicast List request\n");
+ }
+#endif
+
+ //
+ // Now make the change.
+ //
+
+ Status = ChangeAddressDispatch(
+ Adapter,
+ InformationBufferLength / ETH_LENGTH_OF_ADDRESS,
+ InformationBuffer
+ );
+
+ *BytesRead = InformationBufferLength;
+
+ return Status;
+
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ if (InformationBufferLength != 4) {
+
+ *BytesNeeded = 4;
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ }
+
+#if DBG
+ if (SonicDbg) {
+ DbgPrint("Processing Change Packet Filter request\n");
+ }
+#endif
+
+ //
+ // Now call the filter package to set the packet filter.
+ //
+
+ SONIC_MOVE_MEMORY ((PVOID)&PacketFilter, InformationBuffer, sizeof(ULONG));
+
+ //
+ // Verify bits
+ //
+
+ if (PacketFilter & (NDIS_PACKET_TYPE_SOURCE_ROUTING |
+ NDIS_PACKET_TYPE_SMT |
+ NDIS_PACKET_TYPE_MAC_FRAME |
+ NDIS_PACKET_TYPE_FUNCTIONAL |
+ NDIS_PACKET_TYPE_ALL_FUNCTIONAL |
+ NDIS_PACKET_TYPE_GROUP
+ )) {
+
+ *BytesRead = 4;
+ *BytesNeeded = 0;
+
+ return NDIS_STATUS_NOT_SUPPORTED;
+
+ }
+
+ Status = ChangeClassDispatch(
+ Adapter,
+ PacketFilter
+ );
+
+ *BytesRead = 4;
+ return Status;
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ //
+ // No need to record requested lookahead length since we
+ // always indicate the whole packet.
+ //
+
+ *BytesRead = 4;
+ return NDIS_STATUS_SUCCESS;
+ break;
+
+ default:
+
+ return NDIS_STATUS_INVALID_OID;
+ break;
+
+ }
+
+}
+
+STATIC
+NDIS_STATUS
+ChangeClassDispatch(
+ IN PSONIC_ADAPTER Adapter,
+ IN UINT NewFilterClasses
+ )
+
+/*++
+
+Routine Description:
+
+ Modifies the Receive Control Register and Cam Enable registers,
+ then re-loads the CAM if necessary.
+
+Arguments:
+
+ Adapter - The adapter.
+
+ NewFilterClasses - New set of filters.
+
+Return Value:
+
+ NDIS_STATUS_PENDING - if the CAM was reloaded.
+ NDIS_STATUS_SUCCESS - otherwise.
+
+--*/
+
+{
+ //
+ // The new value for the RCR.
+ //
+ USHORT NewReceiveControl = SONIC_RCR_DEFAULT_VALUE;
+
+ //
+ // First take care of the Receive Control Register.
+ //
+
+ if (NewFilterClasses & NDIS_PACKET_TYPE_PROMISCUOUS) {
+
+ NewReceiveControl |= SONIC_RCR_PROMISCUOUS_PHYSICAL |
+ SONIC_RCR_ACCEPT_BROADCAST |
+ SONIC_RCR_ACCEPT_ALL_MULTICAST;
+
+ } else {
+
+ if (NewFilterClasses & NDIS_PACKET_TYPE_ALL_MULTICAST) {
+
+ NewReceiveControl |= SONIC_RCR_ACCEPT_ALL_MULTICAST;
+
+ }
+
+ if (NewFilterClasses & NDIS_PACKET_TYPE_BROADCAST) {
+
+ NewReceiveControl |= SONIC_RCR_ACCEPT_BROADCAST;
+
+ }
+
+ }
+
+ Adapter->ReceiveControlRegister = NewReceiveControl;
+
+ SONIC_WRITE_PORT(Adapter, SONIC_RECEIVE_CONTROL,
+ Adapter->ReceiveControlRegister
+ );
+
+ if (CAM_DIRECTED_SIGNIFICANT(NewFilterClasses)) {
+
+ Adapter->CamDescriptorArea->CamEnable |= 1;
+
+ } else {
+
+ Adapter->CamDescriptorArea->CamEnable &= ~1;
+
+ }
+
+ if (CAM_MULTICAST_SIGNIFICANT(NewFilterClasses)) {
+
+ Adapter->CamDescriptorArea->CamEnable |=
+ Adapter->MulticastCamEnableBits;
+
+ } else {
+
+ Adapter->CamDescriptorArea->CamEnable &= 1;
+
+ }
+
+ //
+ // This will cause a LOAD_CAM interrupt when it is done.
+ //
+
+ SonicStartCamReload(Adapter);
+
+ Adapter->CurrentPacketFilter = NewFilterClasses;
+
+ return NDIS_STATUS_PENDING;
+
+}
+
+STATIC
+NDIS_STATUS
+ChangeAddressDispatch(
+ IN PSONIC_ADAPTER Adapter,
+ IN UINT AddressCount,
+ IN CHAR Addresses[][ETH_LENGTH_OF_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ Modifies the Receive Control Register and Cam Enable registers,
+ then re-loads the CAM if necessary.
+
+Arguments:
+
+ Adapter - The adapter.
+
+ AddressCount - The number of addresses in Addresses
+
+ Addresses - The new multicast address list.
+
+Return Value:
+
+ NDIS_STATUS_PENDING - if the CAM was reloaded.
+ NDIS_STATUS_SUCCESS - otherwise.
+
+--*/
+
+{
+
+ ULONG EnableBit;
+ NDIS_STATUS Status;
+ UINT i;
+
+ //
+ // The first entry in the CAM is for our address.
+ //
+
+ Adapter->MulticastCamEnableBits = 1;
+ EnableBit = 1;
+
+ //
+ // Loop through, copying the addresses into the CAM.
+ //
+
+ for (i=0; i<AddressCount; i++) {
+
+ EnableBit <<= 1;
+ Adapter->MulticastCamEnableBits |= EnableBit;
+
+ SONIC_LOAD_CAM_FRAGMENT(
+ &Adapter->CamDescriptorArea->CamFragments[i+1],
+ i+1,
+ Addresses[i]
+ );
+
+ }
+
+ Adapter->CamDescriptorAreaSize = AddressCount + 1;
+
+ //
+ // Now see if we have to worry about re-loading the
+ // CAM also.
+ //
+
+ if (CAM_MULTICAST_SIGNIFICANT(Adapter->CurrentPacketFilter)) {
+
+ Adapter->CamDescriptorArea->CamEnable = Adapter->MulticastCamEnableBits;
+
+ //
+ // This will cause a LOAD_CAM interrupt when it is done.
+ //
+
+ SonicStartCamReload(Adapter);
+
+#if DBG
+ if (SonicDbg) {
+ DbgPrint("Processing Address request pended\n");
+ }
+#endif
+
+
+ Status = NDIS_STATUS_PENDING;
+
+ } else {
+
+#if DBG
+ if (SonicDbg) {
+ DbgPrint("Processing Address request succeeded\n");
+ }
+#endif
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ }
+
+ return Status;
+
+}
+
diff --git a/private/ntos/ndis/sonic/send.c b/private/ntos/ndis/sonic/send.c
new file mode 100644
index 000000000..7f41a8f07
--- /dev/null
+++ b/private/ntos/ndis/sonic/send.c
@@ -0,0 +1,1305 @@
+/*++
+
+Copyright (c) 1990-1992 Microsoft Corporation
+
+Module Name:
+
+ send.c
+
+Abstract:
+
+ This file contains the code for putting a packet through the
+ allocation for transmission.
+
+ This is a process of
+
+ 1) Calculating the what would need to be done to the
+ packet so that the packet can be transmitted on the hardware.
+
+ 2) Potentially allocating adapter buffers and copying user data
+ to those buffers so that the packet data is transmitted under
+ the hardware constraints.
+
+ 3) Allocating enough hardware ring entries so that the packet
+ can be transmitted.
+
+ 4) Relinquish those ring entries to the hardware.
+
+Author:
+
+ Adam Barr (adamba) 16-Nov-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent.
+
+Revision History:
+
+
+--*/
+
+
+#include <ndis.h>
+
+#include <sonichrd.h>
+#include <sonicsft.h>
+
+
+
+//
+// This macro will poke the sonic hardware into noticing that
+// there is a packet available for transmit.
+//
+
+#define START_TRANSMIT(_Adapter) \
+ SONIC_WRITE_PORT(_Adapter, SONIC_COMMAND, SONIC_CR_TRANSMIT_PACKETS)
+
+
+STATIC
+VOID
+AssignPacketToDescriptor(
+ IN PSONIC_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet,
+ IN UINT DescriptorIndex
+ );
+
+STATIC
+VOID
+RelinquishPacket(
+ IN PSONIC_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet,
+ IN UINT RingIndex
+ );
+
+STATIC
+VOID
+CalculatePacketConstraints(
+ IN PSONIC_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet
+ );
+
+STATIC
+BOOLEAN
+ConstrainPacket(
+ IN PSONIC_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet
+ );
+
+
+#ifdef CHECK_DUP_SENDS
+
+#define PACKET_LIST_SIZE 20
+
+PNDIS_PACKET SonicPacketList[PACKET_LIST_SIZE];
+UINT SonicPacketListSize = 0;
+
+VOID
+SonicAddPacketToList(
+ PSONIC_ADAPTER Adapter,
+ PNDIS_PACKET NewPacket
+ )
+{
+ INT i;
+
+ for (i=0; i<SonicPacketListSize; i++) {
+
+ if (SonicPacketList[i] == NewPacket) {
+
+ DbgPrint("SONIC: dup send of %lx\n", NewPacket);
+
+ }
+
+ }
+
+ SonicPacketList[SonicPacketListSize] = NewPacket;
+ ++SonicPacketListSize;
+
+}
+
+VOID
+SonicRemovePacketFromList(
+ PSONIC_ADAPTER Adapter,
+ PNDIS_PACKET OldPacket
+ )
+{
+ INT i;
+
+ for (i=0; i<SonicPacketListSize; i++) {
+
+ if (SonicPacketList[i] == OldPacket) {
+
+ break;
+
+ }
+
+ }
+
+ if (i == SonicPacketListSize) {
+
+ DbgPrint("SONIC: bad remove of %lx\n", OldPacket);
+
+ } else {
+
+ --SonicPacketListSize;
+ SonicPacketList[i] = SonicPacketList[SonicPacketListSize];
+
+ }
+
+}
+#endif // CHECK_DUP_SENDS
+
+
+extern
+NDIS_STATUS
+SonicSend(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET Packet,
+ IN UINT SendFlags
+ )
+
+/*++
+
+Routine Description:
+
+ The SonicSend request instructs a driver to transmit a packet through
+ the adapter onto the medium.
+
+Arguments:
+
+ MiniportAdapterContext - Context registered with the wrapper, really
+ a pointer to the adapter.
+
+ Packet - A pointer to a descriptor for the packet that is to be
+ transmitted.
+
+ SendFlags - Optional send flags
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+ //
+ // Holds the status that should be returned to the caller.
+ //
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_PENDING;
+
+ //
+ // Pointer to the adapter.
+ //
+ PSONIC_ADAPTER Adapter = PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ PSONIC_PACKET_RESERVED Reserved;
+
+ //
+ // Holds whether the packet has been constrained
+ // to the hardware requirements.
+ //
+ BOOLEAN SuitableForHardware;
+
+ //
+ // If we successfully acquire some ring entries, this
+ // is the index of the first one.
+ //
+ UINT DescriptorIndex;
+
+#ifdef CHECK_DUP_SENDS
+ SonicAddPacketToList(Adapter, Packet);
+#endif
+
+
+ //
+ // Check to see if the packet should even make it out to
+ // the media. The primary reason this shouldn't *actually*
+ // be sent is if the destination is equal to the source
+ // address.
+ //
+
+ Reserved = PSONIC_RESERVED_FROM_PACKET(Packet);
+
+ //
+ // Determine if and how much adapter space would need to be allocated
+ // to meet hardware constraints.
+ //
+
+ CalculatePacketConstraints(
+ Adapter,
+ Packet
+ );
+
+ //
+ // We look to see if there are enough ring entries.
+ // If there aren't then fail this send.
+ //
+
+ if (Adapter->NumberOfAvailableDescriptors > 1) {
+
+ DescriptorIndex = Adapter->AllocateableDescriptor - Adapter->TransmitDescriptorArea;
+
+ if (Adapter->AllocateableDescriptor == Adapter->LastTransmitDescriptor) {
+
+ Adapter->AllocateableDescriptor = Adapter->TransmitDescriptorArea;
+
+ } else {
+
+ ++(Adapter->AllocateableDescriptor);
+
+ }
+
+ --(Adapter->NumberOfAvailableDescriptors);
+
+ if (Reserved->UsedSonicBuffer == TRUE) {
+
+ //
+ // ConstrainPacket returns FALSE if an adapter buffer
+ // is needed and none is available.
+ //
+
+ SuitableForHardware = ConstrainPacket(
+ Adapter,
+ Packet
+ );
+
+ if (!SuitableForHardware) {
+
+ //
+ // Return transmit descriptor
+ //
+
+ Adapter->AllocateableDescriptor = Adapter->TransmitDescriptorArea +
+ DescriptorIndex;
+
+
+ ++(Adapter->NumberOfAvailableDescriptors);
+
+ StatusToReturn = NDIS_STATUS_RESOURCES;
+
+ goto FinishWithSend;
+
+ }
+
+ }
+
+ //
+ // Put the packet on the finish transmit queue.
+ //
+
+ if (Adapter->FirstFinishTransmit == NULL) {
+
+ Adapter->FirstFinishTransmit = Packet;
+
+ } else {
+
+ PSONIC_RESERVED_FROM_PACKET(Adapter->LastFinishTransmit)->Next = Packet;
+
+ }
+
+ Adapter->LastFinishTransmit = Packet;
+
+ Reserved->Next = NULL;
+
+ //
+ // We have the number of buffers that we need.
+ // We assign all of the buffers to the ring entries.
+ //
+
+ AssignPacketToDescriptor(
+ Adapter,
+ Packet,
+ DescriptorIndex
+ );
+
+ RelinquishPacket(
+ Adapter,
+ Packet,
+ DescriptorIndex
+ );
+
+ } else {
+
+ StatusToReturn = NDIS_STATUS_RESOURCES;
+
+ }
+
+FinishWithSend:
+
+ return StatusToReturn;
+}
+
+STATIC
+BOOLEAN
+ConstrainPacket(
+ IN PSONIC_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ Given a packet and necessary attempt to acquire adapter
+ buffer resources so that the packet meets sonic hardware
+ contraints. If a buffer is needed and is not available then
+ return FALSE.
+
+ The constraints are that the packet must have SONIC_MAX_FRAGMENTS
+ or fewer physical pieces and no piece may be less than
+ SONIC_MIN_PIECE_SIZE bytes. The first constraint is based on
+ the size of the SONIC_TRANSMIT_DESCRIPTOR, and the second
+ is to prevent underflow in the Silo.
+
+ If a packet violates either of the constraints then it
+ will be copied in its entirety into an adapter buffer.
+
+Arguments:
+
+ Adapter - The adapter the packet is coming through.
+
+ Packet - The packet whose buffers are to be constrained.
+ The packet reserved section is filled with information
+ detailing how the packet needs to be adjusted.
+
+Return Value:
+
+ Returns TRUE if the packet is suitable for the hardware.
+
+--*/
+
+{
+
+ //
+ // Pointer to the reserved section of the packet to be contrained.
+ //
+ PSONIC_PACKET_RESERVED Reserved = PSONIC_RESERVED_FROM_PACKET(Packet);
+
+ //
+ // Holds the adapter buffer index available for allocation.
+ //
+ INT SonicBuffersIndex;
+
+ //
+ // Points to a successfully allocated adapter buffer descriptor.
+ //
+ PSONIC_BUFFER_DESCRIPTOR BufferDescriptor;
+
+ //
+ // Will point into the virtual address space addressed
+ // by the adapter buffer if one was successfully allocated.
+ //
+ PCHAR CurrentDestination;
+
+ //
+ // Will hold the total amount of data copied to the
+ // adapter buffer.
+ //
+ UINT TotalDataMoved = 0;
+
+ //
+ // Will point to the current source buffer.
+ //
+ PNDIS_BUFFER SourceBuffer;
+
+ //
+ // Points to the virtual address of the source buffers data.
+ //
+ PVOID SourceData;
+
+ //
+ // Will point to the number of bytes of data in the source
+ // buffer.
+ //
+ UINT SourceLength;
+
+ //
+ // Simple iteration variable.
+ //
+ INT i;
+
+ //
+ // Total length of the packet
+ //
+ UINT PacketLength;
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ NULL,
+ &SourceBuffer,
+ &PacketLength
+ );
+
+ if (PacketLength <= SONIC_SMALL_BUFFER_SIZE) {
+
+ i = 1;
+
+ } else if (PacketLength <= SONIC_MEDIUM_BUFFER_SIZE) {
+
+ i = 2;
+
+ } else {
+
+ i = 3;
+
+ }
+
+
+ for (
+ ;
+ i <= 3;
+ i++
+ ) {
+
+ if ((SonicBuffersIndex = Adapter->SonicBufferListHeads[i]) != -1) {
+
+ BufferDescriptor = Adapter->SonicBuffers + SonicBuffersIndex;
+ Adapter->SonicBufferListHeads[i] = BufferDescriptor->Next;
+ break;
+
+ }
+
+ }
+
+ if (SonicBuffersIndex == -1) {
+
+ //
+ // Nothing available for the packet.
+ //
+ return FALSE;
+
+ }
+
+ //
+ // Save the list head index in the buffer descriptor
+ // to permit easy deallocation later.
+ //
+
+ BufferDescriptor->Next = i;
+
+ //
+ // Fill in the adapter buffer with the data from the users
+ // buffers.
+ //
+
+ CurrentDestination = BufferDescriptor->VirtualSonicBuffer;
+
+ while (SourceBuffer) {
+
+ NdisQueryBuffer(
+ SourceBuffer,
+ &SourceData,
+ &SourceLength
+ );
+
+ SONIC_MOVE_MEMORY(
+ CurrentDestination,
+ SourceData,
+ SourceLength
+ );
+
+ CurrentDestination = (PCHAR)CurrentDestination + SourceLength;
+
+ TotalDataMoved += SourceLength;
+
+ NdisGetNextBuffer(
+ SourceBuffer,
+ &SourceBuffer
+ );
+
+ }
+
+ //
+ // If the packet is less then the minimum size then we
+ // need to zero out the rest of the packet.
+ //
+
+ if (TotalDataMoved < SONIC_MIN_PACKET_SIZE) {
+
+ SONIC_ZERO_MEMORY(
+ CurrentDestination,
+ SONIC_MIN_PACKET_SIZE - TotalDataMoved
+ );
+
+ BufferDescriptor->DataLength = SONIC_MIN_PACKET_SIZE;
+
+ } else {
+
+ BufferDescriptor->DataLength = TotalDataMoved;
+
+ }
+
+ //
+ // We need to save in the packet which adapter buffer descriptor
+ // it is using so that we can deallocate it later.
+ //
+
+ Reserved->SonicBuffersIndex = SonicBuffersIndex;
+
+ return TRUE;
+}
+
+STATIC
+VOID
+CalculatePacketConstraints(
+ IN PSONIC_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ Given a packet calculate how the packet will have to be
+ adjusted to meet with hardware constraints.
+
+ The constraints are that the packet must have SONIC_MAX_FRAGMENTS
+ or fewer physical pieces and no piece may be less than
+ SONIC_MIN_FRAGMENT_SIZE bytes. The first constraint is based on
+ the size of the SONIC_TRANSMIT_DESCRIPTOR, and the second
+ is to prevent underflow in the Silo (exception: the last
+ fragment in a packet may be smaller).
+
+ If the packet is found to violate the constraints, then
+ UsedSonicBuffer will be set to TRUE. This will cause the entire packet to
+ be copied into the adapter buffer (which is guaranteed
+ to be physically contiguous).
+
+Arguments:
+
+ Adapter - The adapter the packet is coming through.
+
+ Packet - The packet whose buffers are to be reallocated.
+ The packet reserved section is filled with information
+ detailing how the packet needs to be adjusted.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Points to the MacReserved portion of the packet.
+ //
+ PSONIC_PACKET_RESERVED Reserved = PSONIC_RESERVED_FROM_PACKET(Packet);
+
+ //
+ // The number of physical buffers in the entire packet.
+ //
+ UINT PacketPhysicalSegments;
+
+ //
+ // Points to the current ndis buffer being walked.
+ //
+ PNDIS_BUFFER CurrentBuffer;
+
+ //
+ // The virtual address of the current ndis buffer.
+ //
+ UINT BufferOffset;
+
+ //
+ // The length in bytes of the current ndis buffer.
+ //
+ UINT BufferVirtualLength;
+
+ //
+ // The total amount of data contained within the ndis packet.
+ //
+ UINT PacketVirtualLength;
+
+ //
+ // The number of physical buffers in a single buffer.
+ //
+ UINT BufferPhysicalSegments;
+
+ //
+ // TRUE once we find a constraint violation
+ //
+ BOOLEAN ViolatedConstraints = FALSE;
+
+#ifndef NO_CHIP_FIXUP
+ //
+ // Used to keep track of the total number of fragments
+ // that the packet will occupy when assigned to a
+ // transmit descriptor (may be more than PacketPhysicalSegments
+ // if we have to worry about packets starting or ending
+ // on non-longword boundaries.
+ //
+ UINT TotalTransmitSegments = 0;
+#endif
+
+
+
+ //
+ // Get the first buffer in the packet.
+ //
+
+ NdisQueryPacket(
+ Packet,
+ &PacketPhysicalSegments,
+ NULL,
+ &CurrentBuffer,
+ &PacketVirtualLength
+ );
+
+ //
+ // We only allow SONIC_MAX_FRAGMENTS physical pieces.
+ //
+
+ if (PacketPhysicalSegments > SONIC_MAX_FRAGMENTS) {
+ ViolatedConstraints = TRUE;
+ goto DoneExamining;
+ }
+
+ //
+ // For short packets we can only allow SONIC_MAX_FRAGMENTS-1
+ // (to allow for the blank padding buffer). Also, we can't
+ // allow the padding itself to be less than the minimum
+ // fragment size.
+ //
+
+ if (PacketVirtualLength < SONIC_MIN_PACKET_SIZE &&
+ ((PacketPhysicalSegments > (SONIC_MAX_FRAGMENTS-1)) ||
+ (PacketVirtualLength >
+ (SONIC_MIN_PACKET_SIZE - SONIC_MIN_FRAGMENT_SIZE)))) {
+ ViolatedConstraints = TRUE;
+ goto DoneExamining;
+ }
+
+
+ //
+ // Now loop making sure no fragment is less than
+ // SONIC_MIN_FRAGMENT_SIZE bytes unless it is the
+ // last one.
+ //
+
+ while (CurrentBuffer) {
+
+ NdisQueryBufferOffset(
+ CurrentBuffer,
+ &BufferOffset,
+ &BufferVirtualLength
+ );
+
+
+ //
+ // See if there is only one piece in the buffer.
+ //
+
+ NdisGetBufferPhysicalArraySize(
+ CurrentBuffer,
+ &BufferPhysicalSegments
+ );
+
+ if (BufferPhysicalSegments == 1) {
+
+ //
+ // Only one piece, make sure it is large enough or
+ // is the last fragment.
+ //
+
+ if ((BufferVirtualLength < SONIC_MIN_FRAGMENT_SIZE) &&
+ (NDIS_BUFFER_LINKAGE(CurrentBuffer) != NULL)) {
+ ViolatedConstraints = TRUE;
+ goto DoneExamining;
+ }
+
+#ifndef NO_CHIP_FIXUP
+
+ //
+ // See if the beginning AND end of this piece are
+ // not longword-aligned.
+ //
+
+ if (((ULONG)BufferOffset & 0x03) &&
+ (((ULONG)BufferOffset + BufferVirtualLength) & 0x03)) {
+
+ //
+ // Now see if this piece is large enough to
+ // be split into two.
+ //
+
+ if (BufferVirtualLength >
+ (UINT)(4 - ((ULONG)BufferOffset & 0x03) +
+ (2*SONIC_MIN_FRAGMENT_SIZE))) {
+
+ //
+ // Have enough to let the first fragment be
+ // SONIC_MIN_FRAGMENT_SIZE plus the extra
+ // few bytes at the beginning, and the
+ // second piece SONIC_MIN_FRAGMENT_SIZE.
+ //
+
+ TotalTransmitSegments += 2;
+
+ } else {
+
+ ViolatedConstraints = TRUE;
+ goto DoneExamining;
+
+ }
+
+ } else {
+
+ //
+ // This piece won't have to be split, so
+ // just count it as one.
+ //
+
+ TotalTransmitSegments += 1;
+
+ }
+
+#endif
+
+ } else {
+
+ //
+ // Multiple pieces. We assume that the relevant low bits
+ // will be the same in a physical and virtual address, so
+ // we can check using the virtual address whether a
+ // physical segment may be too short (we are being over-
+ // cautious here, but this allows us to avoid actually
+ // querying the physical addresses here.
+ //
+
+ //
+ // See if this buffer starts less than MIN_FRAGMENT_SIZE
+ // bytes before a page boundary.
+ //
+
+ if (PAGE_SIZE - ((ULONG)BufferOffset & (PAGE_SIZE-1)) <
+ SONIC_MIN_FRAGMENT_SIZE) {
+ ViolatedConstraints = TRUE;
+ goto DoneExamining;
+ }
+
+ //
+ // See if this buffer ends less than MIN_FRAGMENT_SIZE
+ // bytes after a page boundary.
+ //
+
+ if (((ULONG)BufferOffset + BufferVirtualLength) & (PAGE_SIZE-1) <
+ SONIC_MIN_FRAGMENT_SIZE) {
+ ViolatedConstraints = TRUE;
+ goto DoneExamining;
+ }
+
+#ifndef NO_CHIP_FIXUP
+
+ //
+ // Add the number of fragments in this piece.
+ // We assume that physical gaps will always be
+ // on at least a 4 byte boundary, so we won't
+ // need to split this piece.
+ //
+
+ TotalTransmitSegments += BufferPhysicalSegments;
+
+#endif
+
+ }
+
+
+ NdisGetNextBuffer(
+ CurrentBuffer,
+ &CurrentBuffer
+ );
+
+ }
+
+
+#ifndef NO_CHIP_FIXUP
+
+ //
+ // If the packet is short, we have to allow for the
+ // padding fragment at the end.
+ //
+
+ if (PacketVirtualLength < SONIC_MIN_PACKET_SIZE) {
+
+ TotalTransmitSegments += 1;
+
+ }
+
+#endif
+
+
+DoneExamining: ;
+
+#ifndef NO_CHIP_FIXUP
+ if (ViolatedConstraints || (TotalTransmitSegments > SONIC_MAX_FRAGMENTS)) {
+#else
+ if (ViolatedConstraints) {
+#endif
+
+ Reserved->UsedSonicBuffer = TRUE;
+
+ } else {
+
+ Reserved->UsedSonicBuffer = FALSE;
+
+ }
+
+}
+
+STATIC
+VOID
+AssignPacketToDescriptor(
+ IN PSONIC_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet,
+ IN UINT DescriptorIndex
+ )
+
+/*++
+
+Routine Description:
+
+ Given a packet and a ring index, assign all of the buffers
+ in the packet to ring entries.
+
+Arguments:
+
+ Adapter - The adapter that the packets are coming through.
+
+ Packet - The packet whose buffers are to be assigned
+ ring entries.
+
+ DescriptorIndex - The index of the start of the ring entries to
+ be assigned buffers.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Points to the reserved portion of the packet.
+ //
+ PSONIC_PACKET_RESERVED Reserved = PSONIC_RESERVED_FROM_PACKET(Packet);
+
+ //
+ // Pointer to the ring entry to be filled with buffer information.
+ //
+ PSONIC_TRANSMIT_DESCRIPTOR TransmitDescriptor = Adapter->TransmitDescriptorArea
+ + DescriptorIndex;
+
+ //
+ // Pointer to the ring to packet entry that records the info about
+ // this packet.
+ //
+ PSONIC_DESCRIPTOR_TO_PACKET DescriptorToPacket = Adapter->DescriptorToPacket + DescriptorIndex;
+
+ //
+ // The total amount of data in the ndis packet.
+ //
+ UINT TotalDataLength;
+
+ //
+ // Points to the current ndis buffer being walked.
+ //
+ PNDIS_BUFFER CurrentBuffer;
+
+ //
+ // The number of physical segments in this buffer.
+ //
+ UINT BufferPhysicalSegments;
+
+ //
+ // An array to hold the physical segments.
+ //
+ NDIS_PHYSICAL_ADDRESS_UNIT PhysicalSegmentArray[SONIC_MAX_FRAGMENTS];
+
+ //
+ // We record the owning packet information in the ring packet packet
+ // structure.
+ //
+
+
+ DescriptorToPacket->OwningPacket = Packet;
+ DescriptorToPacket->UsedSonicBuffer = (BOOLEAN)
+ Reserved->UsedSonicBuffer;
+ DescriptorToPacket->SonicBuffersIndex =
+ Reserved->SonicBuffersIndex;
+
+
+ //
+ // First initialize the fields that don't depend on
+ // how many fragments there are in the packet.
+ //
+
+ TransmitDescriptor->TransmitStatus = 0;
+
+ //
+ // Set the programmable interrupt if it has been a long
+ // time since transmit complete interrupts were processed.
+ //
+
+ if (Adapter->PacketsSinceLastInterrupt >=
+ (SONIC_NUMBER_OF_TRANSMIT_DESCRIPTORS/2)) {
+
+ TransmitDescriptor->TransmitConfiguration = (UINT)SONIC_TCR_PROG_INTERRUPT;
+ Adapter->PacketsSinceLastInterrupt = 0;
+
+ } else {
+
+ TransmitDescriptor->TransmitConfiguration = 0;
+ ++Adapter->PacketsSinceLastInterrupt;
+
+ }
+
+
+ //
+ // Now check to see if the packet has been copied into an
+ // adapter buffer.
+ //
+
+ if (Reserved->UsedSonicBuffer) {
+
+ //
+ // Points to the adapter buffer descriptor allocated
+ // for this packet.
+ //
+ PSONIC_BUFFER_DESCRIPTOR BufferDescriptor;
+
+ BufferDescriptor = Adapter->SonicBuffers
+ + Reserved->SonicBuffersIndex;
+
+ TransmitDescriptor->FragmentCount = 1;
+ TransmitDescriptor->PacketSize = (UINT)BufferDescriptor->DataLength;
+
+ SONIC_SET_TRANSMIT_FRAGMENT_ADDRESS(
+ &(TransmitDescriptor->Fragments[0]),
+ NdisGetPhysicalAddressLow(BufferDescriptor->PhysicalSonicBuffer)
+ );
+
+ SONIC_SET_TRANSMIT_FRAGMENT_LENGTH(
+ &(TransmitDescriptor->Fragments[0]),
+ BufferDescriptor->DataLength
+ );
+
+
+ //
+ // This sets end-of-list for this descriptor.
+ //
+
+ SONIC_SET_TRANSMIT_LINK(
+ &(TransmitDescriptor->Fragments[1]),
+ TransmitDescriptor->Link
+ );
+
+ DescriptorToPacket->LinkPointer = (SONIC_PHYSICAL_ADDRESS *)
+ &(TransmitDescriptor->Fragments[1]);
+
+
+ //
+ // Flush the buffer that contains the packet.
+ //
+
+ SONIC_FLUSH_WRITE_BUFFER(BufferDescriptor->FlushBuffer);
+
+ } else {
+
+ //
+ // The total length of the packet (including padding)
+ //
+ UINT TotalPacketLength;
+
+ //
+ // Which fragment we are filling;
+ //
+ UINT CurFragment;
+
+ //
+ // Which map register we use for this buffer.
+ //
+ UINT CurMapRegister;
+
+ //
+ // Simple iteration variable.
+ //
+ UINT i;
+
+
+ CurFragment = 0;
+ CurMapRegister = DescriptorIndex * SONIC_MAX_FRAGMENTS;
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ NULL,
+ &CurrentBuffer,
+ &TotalDataLength
+ );
+
+
+ while (CurrentBuffer) {
+
+ NdisMStartBufferPhysicalMapping(
+ Adapter->MiniportAdapterHandle,
+ CurrentBuffer,
+ CurMapRegister,
+ TRUE,
+ PhysicalSegmentArray,
+ &BufferPhysicalSegments
+ );
+
+ ++CurMapRegister;
+
+ //
+ // Put the physical segments for this buffer into
+ // the transmit descriptors.
+ //
+
+ for (i=0; i<BufferPhysicalSegments; i++) {
+
+ ASSERT (NdisGetPhysicalAddressHigh(PhysicalSegmentArray[i].PhysicalAddress) == 0);
+
+ SONIC_SET_TRANSMIT_FRAGMENT_ADDRESS(
+ &(TransmitDescriptor->Fragments[CurFragment]),
+ NdisGetPhysicalAddressLow(PhysicalSegmentArray[i].PhysicalAddress)
+ );
+
+ SONIC_SET_TRANSMIT_FRAGMENT_LENGTH(
+ &(TransmitDescriptor->Fragments[CurFragment]),
+ PhysicalSegmentArray[i].Length
+ );
+
+ ++CurFragment;
+
+#ifndef NO_CHIP_FIXUP
+
+ //
+ // If the fragment starts and ends not on a longword
+ // boundary, split it into two fragments, the first
+ // being SONIC_MIN_FRAGMENT_SIZE plus the extra bits
+ // at the beginning, the other the rest.
+ //
+
+ if ((NdisGetPhysicalAddressLow(PhysicalSegmentArray[i].PhysicalAddress) & 0x03) &&
+ ((NdisGetPhysicalAddressLow(PhysicalSegmentArray[i].PhysicalAddress) + PhysicalSegmentArray[i].Length) & 0x03)) {
+
+ UINT FirstSegmentLength;
+
+ FirstSegmentLength = (4 - ((NdisGetPhysicalAddressLow(PhysicalSegmentArray[i].PhysicalAddress) & 0x03))) +
+ SONIC_MIN_FRAGMENT_SIZE;
+
+ SONIC_SET_TRANSMIT_FRAGMENT_LENGTH(
+ &(TransmitDescriptor->Fragments[CurFragment-1]),
+ FirstSegmentLength
+ );
+
+ SONIC_SET_TRANSMIT_FRAGMENT_ADDRESS(
+ &(TransmitDescriptor->Fragments[CurFragment]),
+ SONIC_GET_TRANSMIT_FRAGMENT_ADDRESS(
+ &(TransmitDescriptor->Fragments[CurFragment-1])) +
+ FirstSegmentLength
+ );
+
+ SONIC_SET_TRANSMIT_FRAGMENT_LENGTH(
+ &(TransmitDescriptor->Fragments[CurFragment]),
+ PhysicalSegmentArray[i].Length - FirstSegmentLength
+ );
+
+ ++CurFragment;
+
+ }
+#endif
+ }
+
+
+ SONIC_FLUSH_WRITE_BUFFER (CurrentBuffer);
+
+ NdisGetNextBuffer(
+ CurrentBuffer,
+ &CurrentBuffer
+ );
+
+ }
+
+ if (TotalDataLength < SONIC_MIN_PACKET_SIZE) {
+
+ SONIC_SET_TRANSMIT_FRAGMENT_ADDRESS(
+ &(TransmitDescriptor->Fragments[CurFragment]),
+ NdisGetPhysicalAddressLow(Adapter->BlankBufferAddress)
+ );
+
+ SONIC_SET_TRANSMIT_FRAGMENT_LENGTH(
+ &(TransmitDescriptor->Fragments[CurFragment]),
+ SONIC_MIN_PACKET_SIZE - TotalDataLength
+ );
+
+ //
+ // Note that BlankBuffer has already been flushed.
+ //
+
+ ++CurFragment;
+
+ TotalPacketLength = SONIC_MIN_PACKET_SIZE;
+
+ } else {
+
+ TotalPacketLength = TotalDataLength;
+
+ }
+
+ //
+ // Make sure we didn't mess up and use up too
+ // many fragments.
+ //
+ ASSERT(CurFragment <= SONIC_MAX_FRAGMENTS);
+
+ TransmitDescriptor->FragmentCount = (UINT)CurFragment;
+ TransmitDescriptor->PacketSize = (UINT)TotalPacketLength;
+
+
+ //
+ // This sets end-of-list for this descriptor.
+ //
+
+ SONIC_SET_TRANSMIT_LINK(
+ &(TransmitDescriptor->Fragments[CurFragment]),
+ TransmitDescriptor->Link
+ );
+
+ DescriptorToPacket->LinkPointer = (SONIC_PHYSICAL_ADDRESS *)
+ &(TransmitDescriptor->Fragments[CurFragment]);
+
+ }
+
+ if (DescriptorIndex == (Adapter->NumberOfTransmitDescriptors-1)) {
+
+ Adapter->DescriptorToPacket->PrevLinkPointer = DescriptorToPacket->LinkPointer;
+
+ } else {
+
+ (DescriptorToPacket+1)->PrevLinkPointer = DescriptorToPacket->LinkPointer;
+
+ }
+
+ Reserved->DescriptorIndex = DescriptorIndex;
+
+}
+
+STATIC
+VOID
+RelinquishPacket(
+ IN PSONIC_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet,
+ IN UINT RingIndex
+ )
+
+/*++
+
+Routine Description:
+
+ Relinquish the ring entries owned by the packet to the chip.
+ We also update the first uncommitted ring pointer.
+
+Arguments:
+
+ Adapter - The adapter that points to the ring entry structures.
+
+ Packet - The packet contains the ring index of the ring
+ entry for the packet.
+
+ RingIndex - Holds the index of the ring entry used
+ by this packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Holds the previous link pointer, where we turn off
+ // end-of-list.
+ //
+
+ PSONIC_PHYSICAL_ADDRESS PrevLinkPointer;
+
+#if !BINARY_COMPATIBLE
+
+ //
+ // NOTE: We have to raise the IRQL to POWER_LEVEL around the
+ // calls to SONIC_REMOVE_END_OF_LIST and START_TRANSMIT.
+ // This is to prevent a delay between these two instructions.
+ // If a delay happens right after SONIC_REMOVE_END_OF_LIST, the
+ // Sonic could transmit the packet and stop, then the call
+ // to START_TRANSMIT would cause it to retransmit all the
+ // packets in the descriptor ring.
+ //
+ // [ChuckL 8/3/94]
+ // We believe that this is no longer necessary, but we are leaving
+ // it in for RISC builds for safety's sake. We are removing in from
+ // x86 builds in order to remain binary-compatible with Chicago.
+ //
+
+ KIRQL OldIrql;
+
+#endif
+
+ PrevLinkPointer = Adapter->DescriptorToPacket[RingIndex].PrevLinkPointer;
+
+#if !BINARY_COMPATIBLE
+
+ //
+ // See NOTE above.
+ //
+
+ KeRaiseIrql(POWER_LEVEL, &OldIrql);
+
+#endif
+
+ //
+ // Turn off END_OF_LIST for the last one.
+ //
+
+ SONIC_REMOVE_END_OF_LIST(PrevLinkPointer);
+
+ //
+ // This turns on the correct bit in the SONIC_CONTROL
+ // register.
+ //
+
+ START_TRANSMIT(Adapter);
+
+#if !BINARY_COMPATIBLE
+
+ //
+ // See NOTE above.
+ //
+
+ KeLowerIrql(OldIrql);
+
+#endif
+
+ //
+ // We want FirstUncommittedDescriptor to point to right after us.
+ //
+
+ if (RingIndex == (Adapter->NumberOfTransmitDescriptors-1)) {
+
+ Adapter->FirstUncommittedDescriptor = Adapter->TransmitDescriptorArea;
+
+ } else {
+
+ Adapter->FirstUncommittedDescriptor =
+ Adapter->TransmitDescriptorArea + (RingIndex + 1);
+
+ }
+
+}
+
+
diff --git a/private/ntos/ndis/sonic/sonic.c b/private/ntos/ndis/sonic/sonic.c
new file mode 100644
index 000000000..b8322cef4
--- /dev/null
+++ b/private/ntos/ndis/sonic/sonic.c
@@ -0,0 +1,2800 @@
+/*++
+
+Copyright (c) 1990-1992 Microsoft Corporation
+
+Module Name:
+
+ sonic.c
+
+Abstract:
+
+ This is the main file for the National Semiconductor SONIC
+ Ethernet controller. This driver conforms to the NDIS 3.0
+ miniport interface.
+
+Author:
+
+ Adam Barr (adamba) 14-Nov-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent.
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+
+#include <sonichrd.h>
+#include <sonicsft.h>
+
+
+
+//
+// This variable is used to control debug output.
+//
+
+#if DBG
+INT SonicDbg = 0;
+#endif
+
+
+STATIC
+VOID
+SonicHalt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+STATIC
+VOID
+SonicShutdown(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+STATIC
+NDIS_STATUS
+SonicInitalize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE ConfigurationHandle
+ );
+
+STATIC
+NDIS_STATUS
+SonicReset(
+ OUT PBOOLEAN AddressingReset,
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+STATIC
+BOOLEAN
+SonicSynchClearIsr(
+ IN PVOID Context
+ );
+
+STATIC
+VOID
+SonicStopChip(
+ IN PSONIC_ADAPTER Adapter
+ );
+
+STATIC
+BOOLEAN
+SetupRegistersAndInit(
+ IN PSONIC_ADAPTER Adapter
+ );
+
+STATIC
+BOOLEAN
+SonicInitialInit(
+ IN PSONIC_ADAPTER Adapter
+ );
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+
+STATIC
+NDIS_STATUS
+SonicRegisterAdapter(
+ IN NDIS_HANDLE NdisMacHandle,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PUCHAR NetworkAddress,
+ IN UCHAR AdapterType,
+ IN UINT SlotNumber,
+ IN UINT Controller,
+ IN UINT MultifunctionAdapter,
+ IN UINT SonicInterruptVector,
+ IN UINT SonicInterruptLevel,
+ IN NDIS_INTERRUPT_MODE SonicInterruptMode
+ );
+
+typedef enum {
+ SonicHardwareOk,
+ SonicHardwareChecksum,
+ SonicHardwareConfig
+} SONIC_HARDWARE_STATUS;
+
+STATIC
+SONIC_HARDWARE_STATUS
+SonicHardwareGetDetails(
+ IN PSONIC_ADAPTER Adapter,
+ IN UINT SlotNumber,
+ IN UINT Controller,
+ IN UINT MultifunctionAdapter,
+ OUT PULONG InitialPort,
+ OUT PULONG NumberOfPorts,
+ IN OUT PUINT InterruptVector,
+ IN OUT PUINT InterruptLevel,
+ OUT ULONG ErrorLogData[3]
+ );
+
+STATIC
+BOOLEAN
+SonicHardwareGetAddress(
+ IN PSONIC_ADAPTER Adapter,
+ OUT ULONG ErrorLogData[3]
+ );
+
+#ifdef SONIC_INTERNAL
+
+//
+// These routines are support reading the address for the
+// sonic internal implementation on the R4000 motherboards.
+//
+
+STATIC
+NTSTATUS
+SonicHardwareSaveInformation(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+STATIC
+BOOLEAN
+SonicHardwareVerifyChecksum(
+ IN PSONIC_ADAPTER Adapter,
+ IN PUCHAR EthernetAddress,
+ OUT ULONG ErrorLogData[3]
+ );
+
+#endif
+
+
+
+SONIC_DRIVER SonicDriver;
+
+#pragma NDIS_INIT_FUNCTION(DriverEntry)
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This is the primary initialization routine for the sonic driver.
+ It is simply responsible for the intializing the wrapper and registering
+ the MAC. It then calls a system and architecture specific routine that
+ will initialize and register each adapter.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+Return Value:
+
+ The status of the operation.
+
+--*/
+
+{
+
+ //
+ // Receives the status of the NdisRegisterMac operation.
+ //
+ NDIS_STATUS Status;
+
+ NDIS_HANDLE SonicWrapperHandle;
+
+ static const NDIS_STRING MacName = NDIS_STRING_CONST("SONIC");
+ NDIS_MINIPORT_CHARACTERISTICS SonicChar;
+
+#if NDIS_WIN
+ UCHAR pIds[sizeof (EISA_MCA_ADAPTER_IDS) + sizeof (ULONG)];
+#endif
+
+#if NDIS_WIN
+ ((PEISA_MCA_ADAPTER_IDS)pIds)->nEisaAdapters=1;
+ ((PEISA_MCA_ADAPTER_IDS)pIds)->nMcaAdapters=0;
+ *(PULONG)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray)=SONIC_COMPRESSED_ID;
+ (PVOID) DriverObject = (PVOID) pIds;
+#endif
+
+ //
+ // Initialize the wrapper.
+ //
+
+ NdisMInitializeWrapper(
+ &SonicWrapperHandle,
+ DriverObject,
+ RegistryPath,
+ NULL
+ );
+
+ SonicDriver.WrapperHandle = SonicWrapperHandle;
+
+ //
+ // Initialize the miniport characteristics for the call to
+ // NdisMRegisterMiniport.
+ //
+
+ SonicChar.MajorNdisVersion = SONIC_NDIS_MAJOR_VERSION;
+ SonicChar.MinorNdisVersion = SONIC_NDIS_MINOR_VERSION;
+ SonicChar.CheckForHangHandler = SonicCheckForHang;
+ SonicChar.DisableInterruptHandler = SonicDisableInterrupt;
+ SonicChar.EnableInterruptHandler = SonicEnableInterrupt;
+ SonicChar.HaltHandler = SonicHalt;
+ SonicChar.HandleInterruptHandler = SonicHandleInterrupt;
+ SonicChar.InitializeHandler = SonicInitialize;
+ SonicChar.ISRHandler = SonicInterruptService;
+ SonicChar.QueryInformationHandler = SonicQueryInformation;
+ SonicChar.ReconfigureHandler = NULL;
+ SonicChar.ResetHandler = SonicReset;
+ SonicChar.SendHandler = SonicSend;
+ SonicChar.SetInformationHandler = SonicSetInformation;
+ SonicChar.TransferDataHandler = SonicTransferData;
+
+ Status = NdisMRegisterMiniport(
+ SonicWrapperHandle,
+ &SonicChar,
+ sizeof(SonicChar)
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ return NDIS_STATUS_SUCCESS;
+
+ }
+
+
+ //
+ // We can only get here if something went wrong with registering
+ // the mac or *all* of the adapters.
+ //
+
+ NdisTerminateWrapper(SonicWrapperHandle, NULL);
+
+ return NDIS_STATUS_FAILURE;
+
+}
+
+#if DBG
+PVOID SonicAdapterAddress;
+#endif
+
+
+#pragma NDIS_INIT_FUNCTION(SonicRegisterAdapter)
+
+STATIC
+NDIS_STATUS
+SonicRegisterAdapter(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PUCHAR NetworkAddress,
+ IN UCHAR AdapterType,
+ IN UINT SlotNumber,
+ IN UINT Controller,
+ IN UINT MultifunctionAdapter,
+ IN UINT SonicInterruptVector,
+ IN UINT SonicInterruptLevel,
+ IN NDIS_INTERRUPT_MODE SonicInterruptMode
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is responsible for the allocation of the datastructures
+ for the driver as well as any hardware specific details necessary
+ to talk with the device.
+
+Arguments:
+
+ MiniportAdapterHandle - The handle given back to the driver from ndis when
+ the driver registered itself.
+
+ ConfigurationHandle - Config handle passed to MacAddAdapter.
+
+ NetworkAddress - The network address, or NULL if the default
+ should be used.
+
+ AdapterType - The type of the adapter; currently SONIC_ADAPTER_TYPE_EISA
+ and SONIC_ADAPTER_TYPE_INTERNAL are supported,
+
+ SlotNumber - The slot number for the EISA card.
+
+ Controller - The controller number for INTERNAL chips.
+
+ MultifunctionAdapter - The INTERNAL bus number for INTERNAL chips.
+
+ SonicInterruptVector - The interrupt vector to use for the adapter.
+
+ SonicInterruptLevel - The interrupt request level to use for this
+ adapter.
+
+ SonicInterruptMode - The interrupt mode to be use for this adapter.
+
+Return Value:
+
+ Returns a failure status if anything occurred that prevents the
+ initialization of the adapter.
+
+--*/
+
+{
+
+ //
+ // Pointer for the adapter root.
+ //
+ PSONIC_ADAPTER Adapter;
+
+ //
+ // Status of various NDIS calls.
+ //
+ NDIS_STATUS Status;
+
+ //
+ // Number of ports needed
+ //
+ ULONG InitialPort;
+ ULONG NumberOfPorts;
+
+ //
+ // Returned from SonicHardwareGetDetails; if it failed,
+ // we log an error and exit.
+ //
+ SONIC_HARDWARE_STATUS HardwareDetailsStatus;
+
+ //
+ // Used to store error log data from SonicHardwareGetDetails.
+ //
+ ULONG ErrorLogData[3];
+
+ //
+ // We put in this assertion to make sure that ushort are 2 bytes.
+ // if they aren't then the initialization block definition needs
+ // to be changed.
+ //
+ // Also all of the logic that deals with status registers assumes
+ // that control registers are only 2 bytes.
+ //
+
+ ASSERT(sizeof(USHORT) == 2);
+
+ //
+ // The Sonic uses four bytes four physical addresses, so we
+ // must ensure that this is the case (SONIC_PHYSICAL_ADDRESS)
+ // is defined as a ULONG).
+ //
+
+ ASSERT(sizeof(SONIC_PHYSICAL_ADDRESS) == 4);
+
+ //
+ // Allocate the Adapter block.
+ //
+
+ SONIC_ALLOC_MEMORY(&Status, &Adapter, sizeof(SONIC_ADAPTER));
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+#if DBG
+ SonicAdapterAddress = Adapter;
+#endif
+
+ SONIC_ZERO_MEMORY(
+ Adapter,
+ sizeof(SONIC_ADAPTER)
+ );
+
+ Adapter->MiniportAdapterHandle = MiniportAdapterHandle;
+
+ Adapter->AdapterType = AdapterType;
+ if (SonicInterruptMode == NdisInterruptLatched) {
+ Adapter->InterruptLatched = TRUE;
+ }
+ Adapter->PermanentAddressValid = FALSE;
+
+ //
+ // Set the attributes
+ //
+
+ NdisMSetAttributes(
+ MiniportAdapterHandle,
+ (NDIS_HANDLE)Adapter,
+ TRUE,
+ (AdapterType == SONIC_ADAPTER_TYPE_EISA) ?
+ NdisInterfaceEisa :
+ NdisInterfaceInternal
+ );
+
+
+ //
+ // Allocate the map registers
+ //
+
+ Status = NdisMAllocateMapRegisters(
+ MiniportAdapterHandle,
+ 0,
+ FALSE,
+ SONIC_MAX_FRAGMENTS * SONIC_NUMBER_OF_TRANSMIT_DESCRIPTORS,
+ SONIC_LARGE_BUFFER_SIZE
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER));
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ //
+ // This returns the I/O ports used by the Sonic and may
+ // modify SonicInterruptVector and SonicInterruptLevel,
+ // as well as modiying some fields in Adapter.
+ //
+
+ if ((HardwareDetailsStatus =
+ SonicHardwareGetDetails(
+ Adapter,
+ SlotNumber,
+ Controller,
+ MultifunctionAdapter,
+ &InitialPort,
+ &NumberOfPorts,
+ &SonicInterruptVector,
+ &SonicInterruptLevel,
+ ErrorLogData)) != SonicHardwareOk) {
+
+ //
+ // Error out.
+ //
+
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_NETWORK_ADDRESS,
+ 6,
+ hardwareDetails,
+ SONIC_ERRMSG_HARDWARE_ADDRESS,
+ NDIS_STATUS_FAILURE,
+ ErrorLogData[0],
+ ErrorLogData[1],
+ ErrorLogData[2]
+ );
+
+ NdisMFreeMapRegisters(MiniportAdapterHandle);
+ SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER));
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ //
+ // Register the port addresses.
+ //
+
+ Status = NdisMRegisterIoPortRange(
+ (PVOID *)(&(Adapter->SonicPortAddress)),
+ MiniportAdapterHandle,
+ InitialPort,
+ NumberOfPorts
+ );
+
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NdisMFreeMapRegisters(MiniportAdapterHandle);
+ SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER));
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ Adapter->NumberOfPorts = NumberOfPorts;
+ Adapter->InitialPort = InitialPort;
+
+ //
+ // Allocate memory for all of the adapter structures.
+ //
+
+ Adapter->NumberOfTransmitDescriptors =
+ SONIC_NUMBER_OF_TRANSMIT_DESCRIPTORS;
+ Adapter->NumberOfReceiveBuffers =
+ SONIC_NUMBER_OF_RECEIVE_BUFFERS;
+ Adapter->NumberOfReceiveDescriptors =
+ SONIC_NUMBER_OF_RECEIVE_DESCRIPTORS;
+
+
+ if (AllocateAdapterMemory(Adapter)) {
+
+ //
+ // Get the network address. This writes
+ // an error log entry if it fails. This routine
+ // may do nothing on some systems, if
+ // SonicHardwareGetDetails has already determined
+ // the network address.
+ //
+
+ if (!SonicHardwareGetAddress(Adapter, ErrorLogData)) {
+
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_NETWORK_ADDRESS,
+ 6,
+ hardwareDetails,
+ SONIC_ERRMSG_HARDWARE_ADDRESS,
+ NDIS_STATUS_FAILURE,
+ ErrorLogData[0],
+ ErrorLogData[1],
+ ErrorLogData[2]
+ );
+
+ DeleteAdapterMemory(Adapter);
+ NdisMFreeMapRegisters(MiniportAdapterHandle);
+ NdisMDeregisterIoPortRange(
+ MiniportAdapterHandle,
+ InitialPort,
+ NumberOfPorts,
+ (PVOID)Adapter->SonicPortAddress
+ );
+ SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER));
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ //
+ // Initialize the current hardware address.
+ //
+
+ SONIC_MOVE_MEMORY(
+ Adapter->CurrentNetworkAddress,
+ (NetworkAddress != NULL) ?
+ NetworkAddress :
+ Adapter->PermanentNetworkAddress,
+ ETH_LENGTH_OF_ADDRESS);
+
+ Adapter->LastTransmitDescriptor =
+ Adapter->TransmitDescriptorArea +
+ (Adapter->NumberOfTransmitDescriptors-1);
+ Adapter->NumberOfAvailableDescriptors =
+ Adapter->NumberOfTransmitDescriptors;
+ Adapter->AllocateableDescriptor =
+ Adapter->TransmitDescriptorArea;
+ Adapter->TransmittingDescriptor =
+ Adapter->TransmitDescriptorArea;
+ Adapter->FirstUncommittedDescriptor =
+ Adapter->TransmitDescriptorArea;
+ Adapter->PacketsSinceLastInterrupt = 0;
+
+ Adapter->CurrentReceiveBufferIndex = 0;
+ Adapter->CurrentReceiveDescriptorIndex = 0;
+ Adapter->LastReceiveDescriptor =
+ &Adapter->ReceiveDescriptorArea[
+ Adapter->NumberOfReceiveDescriptors-1];
+
+ //
+ // Flush the current receive buffer, which is the first one.
+ //
+
+ NdisFlushBuffer(
+ Adapter->ReceiveNdisBufferArea[0],
+ FALSE
+ );
+
+ Adapter->ReceiveDescriptorsExhausted = FALSE;
+ Adapter->ReceiveBuffersExhausted = FALSE;
+ Adapter->ReceiveControlRegister = SONIC_RCR_DEFAULT_VALUE;
+
+ Adapter->FirstFinishTransmit = NULL;
+ Adapter->LastFinishTransmit = NULL;
+
+ Adapter->ResetInProgress = FALSE;
+ Adapter->FirstInitialization = TRUE;
+
+ SONIC_ZERO_MEMORY (&Adapter->GeneralMandatory, GM_ARRAY_SIZE * sizeof(ULONG));
+ SONIC_ZERO_MEMORY (&Adapter->GeneralOptionalByteCount, GO_COUNT_ARRAY_SIZE * sizeof(SONIC_LARGE_INTEGER));
+ SONIC_ZERO_MEMORY (&Adapter->GeneralOptionalFrameCount, GO_COUNT_ARRAY_SIZE * sizeof(ULONG));
+ SONIC_ZERO_MEMORY (&Adapter->GeneralOptional, (GO_ARRAY_SIZE - GO_ARRAY_START) * sizeof(ULONG));
+ SONIC_ZERO_MEMORY (&Adapter->MediaMandatory, MM_ARRAY_SIZE * sizeof(ULONG));
+ SONIC_ZERO_MEMORY (&Adapter->MediaOptional, MO_ARRAY_SIZE * sizeof(ULONG));
+
+ //
+ // Initialize the CAM and associated things.
+ // At the beginning nothing is enabled since
+ // our filter is 0, although we do store
+ // our network address in the first slot.
+ //
+
+ Adapter->MulticastCamEnableBits = 0x0000;
+ Adapter->CurrentPacketFilter = 0;
+ Adapter->CamDescriptorArea->CamEnable = 0x0000;
+ Adapter->CamDescriptorsUsed = 0x0001;
+ Adapter->CamDescriptorAreaSize = 1;
+
+ SONIC_LOAD_CAM_FRAGMENT(
+ &Adapter->CamDescriptorArea->CamFragments[0],
+ 0,
+ Adapter->CurrentNetworkAddress
+ );
+
+ //
+ // Initialize the interrupt.
+ //
+
+ Status = NdisMRegisterInterrupt(
+ &Adapter->Interrupt,
+ MiniportAdapterHandle,
+ SonicInterruptVector,
+ SonicInterruptLevel,
+ FALSE,
+ FALSE,
+ SonicInterruptMode
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_INTERRUPT_CONNECT,
+ 2,
+ registerAdapter,
+ SONIC_ERRMSG_INIT_INTERRUPT
+ );
+
+ DeleteAdapterMemory(Adapter);
+ NdisMFreeMapRegisters(MiniportAdapterHandle);
+ NdisMDeregisterIoPortRange(
+ MiniportAdapterHandle,
+ InitialPort,
+ NumberOfPorts,
+ (PVOID)Adapter->SonicPortAddress
+ );
+ SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER));
+ return Status;
+
+ }
+
+ //
+ // Start the card up. This writes an error
+ // log entry if it fails.
+ //
+
+ if (!SonicInitialInit(Adapter)) {
+
+ NdisMDeregisterInterrupt(&Adapter->Interrupt);
+ DeleteAdapterMemory(Adapter);
+ NdisMFreeMapRegisters(MiniportAdapterHandle);
+ NdisMDeregisterIoPortRange(
+ MiniportAdapterHandle,
+ InitialPort,
+ NumberOfPorts,
+ (PVOID)Adapter->SonicPortAddress
+ );
+ SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER));
+ return NDIS_STATUS_FAILURE;
+
+ } else {
+
+ //
+ // Register our shutdown handler.
+ //
+
+ NdisMRegisterAdapterShutdownHandler(
+ Adapter->MiniportAdapterHandle, // miniport handle.
+ Adapter, // shutdown context.
+ SonicShutdown // shutdown handler.
+ );
+
+ //
+ // All done.
+ //
+ return NDIS_STATUS_SUCCESS;
+
+ }
+
+
+ } else {
+
+ //
+ // Call to AllocateAdapterMemory failed.
+ //
+
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ registerAdapter,
+ SONIC_ERRMSG_ALLOC_MEMORY
+ );
+
+ DeleteAdapterMemory(Adapter);
+ NdisMFreeMapRegisters(MiniportAdapterHandle);
+ NdisMDeregisterIoPortRange(
+ MiniportAdapterHandle,
+ InitialPort,
+ NumberOfPorts,
+ (PVOID)Adapter->SonicPortAddress
+ );
+ SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER));
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ } else {
+
+ //
+ // Couldn't allocate adapter object.
+ //
+
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+}
+
+
+#pragma NDIS_INIT_FUNCTION(SonicInitialInit)
+
+STATIC
+BOOLEAN
+SonicInitialInit(
+ IN PSONIC_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets up the initial init of the driver.
+
+Arguments:
+
+ Adapter - The adapter for the hardware.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ UINT Time = 50;
+
+ //
+ // First we make sure that the device is stopped.
+ //
+
+ SonicStopChip(Adapter);
+
+ //
+ // Set up the registers.
+ //
+
+ if (!SetupRegistersAndInit(Adapter)) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
+ 3,
+ registerAdapter,
+ SONIC_ERRMSG_INITIAL_INIT
+ );
+
+ return FALSE;
+
+ }
+
+
+ //
+ // Delay execution for 1/2 second to give the sonic
+ // time to initialize.
+ //
+
+ while (Time > 0) {
+
+ if (!Adapter->FirstInitialization) {
+ break;
+ }
+
+ NdisStallExecution(10000);
+ Time--;
+
+ }
+
+
+ //
+ // The only way that first initialization could have
+ // been turned off is if we actually initialized.
+ //
+
+ if (!Adapter->FirstInitialization) {
+
+ ULONG PortValue;
+
+ //
+ // We actually did get the initialization.
+ //
+ // We can start the chip. We may not
+ // have any bindings to indicate to but this
+ // is unimportant.
+ //
+
+ SonicStartChip(Adapter);
+
+ NdisStallExecution(25000);
+
+ SONIC_READ_PORT(Adapter, SONIC_COMMAND, &PortValue);
+
+ return TRUE;
+
+
+ } else {
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_TIMEOUT,
+ 2,
+ registerAdapter,
+ SONIC_ERRMSG_INITIAL_INIT
+ );
+
+ return FALSE;
+
+ }
+
+}
+
+
+STATIC
+BOOLEAN
+SonicSynchClearIsr(
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used during a reset. It ensures that no
+ interrupts will come through, and that any DPRs that run
+ will find no interrupts to process.
+
+Arguments:
+
+ Context - A pointer to a SONIC_ADAPTER structure.
+
+Return Value:
+
+ Always returns true.
+
+--*/
+
+{
+
+ PSONIC_ADAPTER Adapter = (PSONIC_ADAPTER)Context;
+
+ SONIC_WRITE_PORT(Adapter, SONIC_INTERRUPT_STATUS, 0xffff);
+ Adapter->SimulatedIsr = 0;
+
+ return TRUE;
+
+}
+
+extern
+VOID
+SonicStartChip(
+ IN PSONIC_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to start an already initialized sonic.
+
+Arguments:
+
+ Adapter - The adapter for the SONIC to start.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Take us out of reset mode if we are in it.
+ //
+
+ SONIC_WRITE_PORT(Adapter, SONIC_COMMAND,
+ 0x0000
+ );
+
+ SONIC_WRITE_PORT(Adapter, SONIC_COMMAND,
+ SONIC_CR_RECEIVER_ENABLE
+ );
+
+}
+
+STATIC
+VOID
+SonicStopChip(
+ IN PSONIC_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to stop a sonic.
+
+ This routine is *not* portable. It is specific to the 386
+ implementation of the sonic. On the bus master card the ACON bit
+ must be set in csr3, whereas on the decstation, csr3 remains clear.
+
+Arguments:
+
+ Adapter - The adapter for the SONIC to stop.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ SONIC_WRITE_PORT(Adapter, SONIC_COMMAND,
+ SONIC_CR_RECEIVER_DISABLE |
+ SONIC_CR_SOFTWARE_RESET
+ );
+
+}
+
+extern
+VOID
+SonicStartCamReload(
+ IN PSONIC_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine starts a CAM reload, which will cause an
+ interrupt when it is done.
+
+Arguments:
+
+ Adapter - The adapter for the SONIC to reload.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Move CAM Enable into the appropriate spot.
+ //
+
+ SONIC_LOAD_CAM_ENABLE(
+ &Adapter->CamDescriptorArea->CamFragments[
+ Adapter->CamDescriptorAreaSize],
+ Adapter->CamDescriptorArea->CamEnable
+ );
+
+
+ //
+ // Flush the CAM before we start the reload.
+ //
+
+ SONIC_FLUSH_WRITE_BUFFER(Adapter->CamDescriptorAreaFlushBuffer);
+
+
+ SONIC_WRITE_PORT(Adapter, SONIC_CAM_DESCRIPTOR,
+ SONIC_GET_LOW_PART_ADDRESS(Adapter->CamDescriptorAreaPhysical)
+ );
+
+ SONIC_WRITE_PORT(Adapter, SONIC_CAM_DESCRIPTOR_COUNT,
+ (USHORT)Adapter->CamDescriptorAreaSize
+ );
+
+
+ //
+ // Start the Load CAM, which will cause an interrupt
+ // when it is done.
+ //
+
+ SONIC_WRITE_PORT(Adapter, SONIC_COMMAND,
+ SONIC_CR_LOAD_CAM
+ );
+
+}
+
+STATIC
+VOID
+SonicHalt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ SonicUnload is called when the driver is to remove itself.
+
+Arguments:
+
+ MiniportAdapterContext - Context registered with the wrapper, really
+ a pointer to the adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSONIC_ADAPTER Adapter = PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ //
+ // Stop the chip.
+ //
+
+ SonicStopChip (Adapter);
+
+ NdisMDeregisterInterrupt(&Adapter->Interrupt);
+
+ DeleteAdapterMemory(Adapter);
+ NdisMFreeMapRegisters(Adapter->MiniportAdapterHandle);
+ NdisMDeregisterIoPortRange(
+ Adapter->MiniportAdapterHandle,
+ Adapter->InitialPort,
+ Adapter->NumberOfPorts,
+ (PVOID)Adapter->SonicPortAddress
+ );
+ SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER));
+
+ return;
+
+}
+
+
+
+STATIC
+VOID
+SonicShutdown(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ SonicShutdown is called when the system is shutdown or it bugchecks.
+
+Arguments:
+
+ MiniportAdapterContext - Context registered with the wrapper, really
+ a pointer to the adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSONIC_ADAPTER Adapter = PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ //
+ // Stop the chip.
+ //
+
+ SonicStopChip (Adapter);
+
+ return;
+
+}
+
+
+#pragma NDIS_INIT_FUNCTION(SonicInitialize)
+
+STATIC
+NDIS_STATUS
+SonicInitialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+
+/*++
+
+Routine Description:
+
+ SonicInitialize adds an adapter to the list supported
+ by this driver.
+
+Arguments:
+
+ OpenErrorStatus - Extra status bytes for opening token ring adapters.
+
+ SelectedMediumIndex - Index of the media type chosen by the driver.
+
+ MediumArray - Array of media types for the driver to chose from.
+
+ MediumArraySize - Number of entries in the array.
+
+ MiniportAdapterHandle - Handle for passing to the wrapper when
+ referring to this adapter.
+
+ ConfigurationHandle - A handle to pass to NdisOpenConfiguration.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_FAILURE
+
+--*/
+
+{
+
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ NDIS_HANDLE ConfigHandle;
+ NDIS_STRING AdapterTypeString = NDIS_STRING_CONST("AdapterType");
+#ifdef SONIC_INTERNAL
+ NDIS_STRING MultifunctionAdapterString = NDIS_STRING_CONST("MultifunctionAdapter");
+ NDIS_STRING NetworkControllerString = NDIS_STRING_CONST("NetworkController");
+#endif
+ PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
+ PUCHAR NetworkAddress;
+ UINT NetworkAddressLength;
+ UCHAR AdapterType;
+ UINT InterruptVector;
+ UINT InterruptLevel;
+ NDIS_INTERRUPT_MODE InterruptMode;
+ UINT SlotNumber;
+ UINT Controller = 0;
+ UINT MultifunctionAdapter = 0;
+ UINT i;
+
+ //
+ // Search for the 802.3 media type
+ //
+
+ for (i=0; i<MediumArraySize; i++) {
+
+ if (MediumArray[i] == NdisMedium802_3) {
+ break;
+ }
+
+ }
+
+ if (i == MediumArraySize) {
+
+ return NDIS_STATUS_UNSUPPORTED_MEDIA;
+
+ }
+
+ *SelectedMediumIndex = i;
+
+ //
+ // Open the configuration info.
+ //
+
+ NdisOpenConfiguration(
+ &Status,
+ &ConfigHandle,
+ ConfigurationHandle
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ return Status;
+ }
+
+
+ //
+ // Check that adapter type is supported.
+ // The default depends on the processor type.
+ //
+
+ AdapterType = SONIC_ADAPTER_TYPE_DEFAULT;
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &AdapterTypeString,
+ NdisParameterInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ //
+ // See if the adapter type is valid. We skip to AdapterTypeRecognized
+ // if the AdapterType is known to this driver.
+ //
+
+#ifdef SONIC_EISA
+ if (ReturnedValue->ParameterData.IntegerData == SONIC_ADAPTER_TYPE_EISA) {
+ goto AdapterTypeRecognized;
+ }
+#endif
+
+#ifdef SONIC_INTERNAL
+ if (ReturnedValue->ParameterData.IntegerData == SONIC_ADAPTER_TYPE_INTERNAL) {
+ goto AdapterTypeRecognized;
+ }
+#endif
+
+ //
+ // Card type not supported by this driver
+ //
+
+#if DBG
+ DbgPrint("SONIC: Error in adapter type: %lx\n", ReturnedValue->ParameterData.IntegerData);
+#endif
+ NdisCloseConfiguration(ConfigHandle);
+ return NDIS_STATUS_FAILURE;
+
+
+AdapterTypeRecognized:
+
+ AdapterType = (UCHAR)ReturnedValue->ParameterData.IntegerData;
+ }
+
+ switch (AdapterType) {
+
+#ifdef SONIC_EISA
+
+ case SONIC_ADAPTER_TYPE_EISA:
+ {
+
+ NDIS_EISA_FUNCTION_INFORMATION EisaData;
+ USHORT Portzc88;
+ UCHAR zc88Value;
+ UCHAR Mask;
+ UCHAR InitType;
+ UCHAR PortValue;
+ USHORT PortAddress;
+ PUCHAR CurrentChar;
+ BOOLEAN LastEntry;
+
+ NdisReadEisaSlotInformation(
+ &Status,
+ ConfigurationHandle,
+ &SlotNumber,
+ &EisaData
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+#if DBG
+ DbgPrint("SONIC: Could not read EISA data\n");
+#endif
+ NdisCloseConfiguration(ConfigHandle);
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ CurrentChar = EisaData.InitializationData;
+
+ Portzc88 = (SlotNumber << 12) + 0xc88;
+
+ LastEntry = FALSE;
+ while (!LastEntry) {
+ InitType = *(CurrentChar++);
+ PortAddress = *((USHORT UNALIGNED *)CurrentChar);
+ CurrentChar += sizeof(USHORT);
+
+ if ((InitType & 0x80) == 0) {
+ LastEntry = TRUE;
+ }
+
+ PortValue = *(CurrentChar++);
+
+ if (InitType & 0x40) {
+ Mask = *(CurrentChar++);
+ } else {
+ Mask = 0;
+ }
+
+ //
+ // The only port we care about is zc88 (z is the
+ // slot number) since it has the interrupt in it.
+ //
+
+ if (PortAddress != Portzc88) {
+ continue;
+ }
+
+ zc88Value &= Mask;
+ zc88Value |= PortValue;
+
+ }
+
+ switch ((zc88Value & 0x06) >> 1) {
+ case 0:
+ InterruptVector = 5; break;
+ case 1:
+ InterruptVector = 9; break;
+ case 2:
+ InterruptVector = 10; break;
+ case 3:
+ InterruptVector = 11; break;
+ }
+
+ InterruptLevel = InterruptVector;
+
+ if ((zc88Value & 0x01) != 0) {
+ InterruptMode = NdisInterruptLatched;
+ } else {
+ InterruptMode = NdisInterruptLevelSensitive;
+ }
+
+ break;
+
+ }
+
+#endif // SONIC_EISA
+
+#ifdef SONIC_INTERNAL
+
+ case SONIC_ADAPTER_TYPE_INTERNAL:
+ {
+
+ //
+ // For the internal adapter, we read the MultifunctionAdapter number
+ // and NetworkController number, which are both optional. For
+ // passing to SonicRegisterAdapter.
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &MultifunctionAdapterString,
+ NdisParameterInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ MultifunctionAdapter = ReturnedValue->ParameterData.IntegerData;
+
+ }
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &NetworkControllerString,
+ NdisParameterInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ Controller = ReturnedValue->ParameterData.IntegerData;
+
+ }
+
+ //
+ // These are filled in by SonicHardwareGetDetails.
+ //
+
+ InterruptVector = 0;
+ InterruptLevel = 0;
+
+ //
+ // The internal adapter is level-sensitive.
+ //
+
+ InterruptMode = NdisInterruptLevelSensitive;
+
+ break;
+
+ }
+
+#endif // SONIC_INTERNAL
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+
+
+ //
+ // Read network address
+ //
+
+ NdisReadNetworkAddress(
+ &Status,
+ (PVOID *)&NetworkAddress,
+ &NetworkAddressLength,
+ ConfigHandle);
+
+
+ //
+ // Make sure that the address is the right length asnd
+ // at least one of the bytes is non-zero.
+ //
+
+ if ((Status == NDIS_STATUS_SUCCESS) &&
+ (NetworkAddressLength == ETH_LENGTH_OF_ADDRESS) &&
+ ((NetworkAddress[0] |
+ NetworkAddress[1] |
+ NetworkAddress[2] |
+ NetworkAddress[3] |
+ NetworkAddress[4] |
+ NetworkAddress[5]) != 0)) {
+
+#if DBG
+ if (SonicDbg) {
+ DbgPrint("SONIC: New Address = %.2x-%.2x-%.2x-%.2x-%.2x-%.2x\n",
+ NetworkAddress[0],
+ NetworkAddress[1],
+ NetworkAddress[2],
+ NetworkAddress[3],
+ NetworkAddress[4],
+ NetworkAddress[5]);
+ }
+#endif
+
+ } else {
+
+ //
+ // Tells SonicRegisterAdapter to use the
+ // burned-in address.
+ //
+
+ NetworkAddress = NULL;
+
+ }
+
+ //
+ // Used passed-in adapter name to register.
+ //
+
+ Status = SonicRegisterAdapter(
+ MiniportAdapterHandle,
+ ConfigurationHandle,
+ NetworkAddress,
+ AdapterType,
+ SlotNumber,
+ Controller,
+ MultifunctionAdapter,
+ InterruptVector,
+ InterruptLevel,
+ InterruptMode
+ );
+
+
+ NdisCloseConfiguration(ConfigHandle);
+
+
+ return Status; // should be NDIS_STATUS_SUCCESS
+
+}
+
+STATIC
+NDIS_STATUS
+SonicReset(
+ OUT PBOOLEAN AddressingReset,
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+/*++
+
+Routine Description:
+
+ The SonicReset request instructs the driver to issue a hardware reset
+ to the network adapter. The driver also resets its software state. See
+ the description of MiniportMReset for a detailed description of this request.
+
+Arguments:
+
+ MiniportAdapterContext - Pointer to the adapter structure.
+
+ AddressingReset - Does the adapter need the addressing information reloaded.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+
+{
+ PSONIC_ADAPTER Adapter =
+ PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ *AddressingReset = FALSE;
+
+ SetupForReset(Adapter);
+ StartAdapterReset(Adapter);
+
+ return NDIS_STATUS_PENDING;
+
+}
+
+extern
+VOID
+StartAdapterReset(
+ IN PSONIC_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This is the first phase of resetting the adapter hardware.
+
+ It makes the following assumptions:
+
+ 1) That the hardware has been stopped.
+
+ 2) That it can not be preempted.
+
+ 3) That no other adapter activity can occur.
+
+ When this routine is finished all of the adapter information
+ will be as if the driver was just initialized.
+
+Arguments:
+
+ Adapter - The adapter whose hardware is to be reset.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ //
+ // These are used for cleaning the rings.
+ //
+
+ PSONIC_RECEIVE_DESCRIPTOR CurrentReceiveDescriptor;
+ PSONIC_TRANSMIT_DESCRIPTOR CurrentTransmitDescriptor;
+ UINT i;
+ SONIC_PHYSICAL_ADDRESS SonicPhysicalAdr;
+
+
+ //
+ // Shut down the chip. We won't be doing any more work until
+ // the reset is complete.
+ //
+
+ SonicStopChip(Adapter);
+
+ //
+ // Once the chip is stopped we can't get any more interrupts.
+ // Any interrupts that are "queued" for processing could
+ // only possibly service this reset. It is therefore safe for
+ // us to clear the adapter global csr value.
+ //
+ Adapter->SimulatedIsr = 0;
+
+
+ Adapter->LastTransmitDescriptor =
+ Adapter->TransmitDescriptorArea +
+ (Adapter->NumberOfTransmitDescriptors-1);
+ Adapter->NumberOfAvailableDescriptors =
+ Adapter->NumberOfTransmitDescriptors;
+ Adapter->AllocateableDescriptor =
+ Adapter->TransmitDescriptorArea;
+ Adapter->TransmittingDescriptor =
+ Adapter->TransmitDescriptorArea;
+ Adapter->FirstUncommittedDescriptor =
+ Adapter->TransmitDescriptorArea;
+ Adapter->PacketsSinceLastInterrupt = 0;
+
+ Adapter->CurrentReceiveBufferIndex = 0;
+ Adapter->CurrentReceiveDescriptorIndex = 0;
+ Adapter->LastReceiveDescriptor =
+ &Adapter->ReceiveDescriptorArea[
+ Adapter->NumberOfReceiveDescriptors-1];
+
+ //
+ // Flush the current receive buffer, which is the first one.
+ //
+
+ NdisFlushBuffer(
+ Adapter->ReceiveNdisBufferArea[0],
+ FALSE
+ );
+
+ Adapter->ReceiveDescriptorsExhausted = FALSE;
+ Adapter->ReceiveBuffersExhausted = FALSE;
+ Adapter->ReceiveControlRegister = SONIC_RCR_DEFAULT_VALUE;
+ Adapter->HardwareFailure = FALSE;
+
+ //
+ // Clean the receive descriptors and initialize the link
+ // fields.
+ //
+
+ SONIC_ZERO_MEMORY(
+ Adapter->ReceiveDescriptorArea,
+ (sizeof(SONIC_RECEIVE_DESCRIPTOR)*Adapter->NumberOfReceiveDescriptors)
+ );
+
+ for (
+ i = 0, CurrentReceiveDescriptor = Adapter->ReceiveDescriptorArea;
+ i < Adapter->NumberOfReceiveDescriptors;
+ i++,CurrentReceiveDescriptor++
+ ) {
+
+ CurrentReceiveDescriptor->InUse = SONIC_OWNED_BY_SONIC;
+
+ SonicPhysicalAdr = NdisGetPhysicalAddressLow(Adapter->ReceiveDescriptorAreaPhysical) +
+ (i * sizeof(SONIC_RECEIVE_DESCRIPTOR));
+
+ if (i == 0) {
+
+ Adapter->ReceiveDescriptorArea[
+ Adapter->NumberOfReceiveDescriptors-1].Link =
+ SonicPhysicalAdr | SONIC_END_OF_LIST;
+
+ } else {
+
+ Adapter->ReceiveDescriptorArea[i-1].Link = SonicPhysicalAdr;
+
+ }
+
+ }
+
+
+ //
+ // Clean the transmit descriptors and initialize the link
+ // fields.
+ //
+
+ SONIC_ZERO_MEMORY(
+ Adapter->TransmitDescriptorArea,
+ (sizeof(SONIC_TRANSMIT_DESCRIPTOR)*Adapter->NumberOfTransmitDescriptors)
+ );
+
+ for (
+ i = 0, CurrentTransmitDescriptor = Adapter->TransmitDescriptorArea;
+ i < Adapter->NumberOfTransmitDescriptors;
+ i++,CurrentTransmitDescriptor++
+ ) {
+
+ SonicPhysicalAdr = NdisGetPhysicalAddressLow(Adapter->TransmitDescriptorAreaPhysical) +
+ (i * sizeof(SONIC_TRANSMIT_DESCRIPTOR));
+
+ if (i == 0) {
+
+ Adapter->TransmitDescriptorArea[Adapter->NumberOfTransmitDescriptors-1].Link = SonicPhysicalAdr;
+
+ } else {
+
+ (CurrentTransmitDescriptor-1)->Link = SonicPhysicalAdr;
+
+ }
+
+ }
+
+
+ //
+ // Recover all of the adapter buffers.
+ //
+
+ {
+
+ UINT i;
+
+ for (
+ i = 0;
+ i < (SONIC_NUMBER_OF_SMALL_BUFFERS +
+ SONIC_NUMBER_OF_MEDIUM_BUFFERS +
+ SONIC_NUMBER_OF_LARGE_BUFFERS);
+ i++
+ ) {
+
+ Adapter->SonicBuffers[i].Next = i+1;
+
+ }
+
+ Adapter->SonicBufferListHeads[0] = -1;
+ Adapter->SonicBufferListHeads[1] = 0;
+ Adapter->SonicBuffers[SONIC_NUMBER_OF_SMALL_BUFFERS-1].Next = -1;
+ Adapter->SonicBufferListHeads[2] = SONIC_NUMBER_OF_SMALL_BUFFERS;
+ Adapter->SonicBuffers[(SONIC_NUMBER_OF_SMALL_BUFFERS+
+ SONIC_NUMBER_OF_MEDIUM_BUFFERS)-1].Next = -1;
+ Adapter->SonicBufferListHeads[3] = SONIC_NUMBER_OF_SMALL_BUFFERS +
+ SONIC_NUMBER_OF_MEDIUM_BUFFERS;
+ Adapter->SonicBuffers[(SONIC_NUMBER_OF_SMALL_BUFFERS+
+ SONIC_NUMBER_OF_MEDIUM_BUFFERS+
+ SONIC_NUMBER_OF_LARGE_BUFFERS)-1].Next = -1;
+
+ }
+
+ (VOID)SetupRegistersAndInit(Adapter);
+
+}
+
+STATIC
+BOOLEAN
+SetupRegistersAndInit(
+ IN PSONIC_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ It is this routines responsibility to make sure that the
+ initialization block is filled and the chip is initialized
+ *but not* started.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired OR that only a single thread of execution is working
+ with this particular adapter.
+
+Arguments:
+
+ Adapter - The adapter whose hardware is to be initialized.
+
+Return Value:
+
+ TRUE if the registers are initialized successfully.
+
+--*/
+{
+
+ USHORT CommandRegister;
+ UINT Time;
+
+
+ SONIC_WRITE_PORT(Adapter, SONIC_DATA_CONFIGURATION,
+ Adapter->DataConfigurationRegister
+ );
+
+ SONIC_WRITE_PORT(Adapter, SONIC_RECEIVE_CONTROL,
+ Adapter->ReceiveControlRegister
+ );
+
+ SONIC_WRITE_PORT(Adapter, SONIC_INTERRUPT_MASK,
+ SONIC_INT_DEFAULT_VALUE
+ );
+
+ SONIC_WRITE_PORT(Adapter, SONIC_INTERRUPT_STATUS,
+ (USHORT)0xffff
+ );
+
+
+
+ SONIC_WRITE_PORT(Adapter, SONIC_UPPER_TRANSMIT_DESCRIPTOR,
+ SONIC_GET_HIGH_PART_ADDRESS(
+ NdisGetPhysicalAddressLow(Adapter->TransmitDescriptorAreaPhysical))
+ );
+
+ SONIC_WRITE_PORT(Adapter, SONIC_CURR_TRANSMIT_DESCRIPTOR,
+ SONIC_GET_LOW_PART_ADDRESS(
+ NdisGetPhysicalAddressLow(Adapter->TransmitDescriptorAreaPhysical))
+ );
+
+
+ SONIC_WRITE_PORT(Adapter, SONIC_UPPER_RECEIVE_DESCRIPTOR,
+ SONIC_GET_HIGH_PART_ADDRESS(
+ NdisGetPhysicalAddressLow(Adapter->ReceiveDescriptorAreaPhysical))
+ );
+
+ SONIC_WRITE_PORT(Adapter, SONIC_CURR_RECEIVE_DESCRIPTOR,
+ SONIC_GET_LOW_PART_ADDRESS(
+ NdisGetPhysicalAddressLow(Adapter->ReceiveDescriptorAreaPhysical))
+ );
+
+
+ //
+ // The EOBC value cannot be odd (since the card register
+ // wants it in words); in addition it appears that the
+ // value in the register must be even, so this number
+ // has to be a multiple of 4.
+ //
+ ASSERT((SONIC_END_OF_BUFFER_COUNT & 0x3) == 0);
+
+ switch (Adapter->AdapterType) {
+
+#ifdef SONIC_EISA
+
+ case SONIC_ADAPTER_TYPE_EISA:
+
+ //
+ // For the EISA card, set EOBC to 2 words more than real
+ // size.
+ //
+ // Add the appropriate correction for the rev. C problem.
+ //
+
+ SONIC_WRITE_PORT(Adapter, SONIC_END_OF_BUFFER_WORD_COUNT,
+ ((SONIC_END_OF_BUFFER_COUNT+SONIC_EOBC_REV_C_CORRECTION) / 2) + 2
+ );
+ break;
+
+#endif // SONIC_EISA
+
+#ifdef SONIC_INTERNAL
+
+ case SONIC_ADAPTER_TYPE_INTERNAL:
+
+ //
+ // Add the appropriate correction for the rev. C problem.
+ //
+
+ SONIC_WRITE_PORT(Adapter, SONIC_END_OF_BUFFER_WORD_COUNT,
+ (SONIC_END_OF_BUFFER_COUNT+SONIC_EOBC_REV_C_CORRECTION) / 2
+ );
+ break;
+
+#endif // SONIC_INTERNAL
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+
+
+ SONIC_WRITE_PORT(Adapter, SONIC_UPPER_RECEIVE_RESOURCE,
+ SONIC_GET_HIGH_PART_ADDRESS(
+ NdisGetPhysicalAddressLow(Adapter->ReceiveResourceAreaPhysical))
+ );
+
+ SONIC_WRITE_PORT(Adapter, SONIC_RESOURCE_START,
+ SONIC_GET_LOW_PART_ADDRESS(
+ NdisGetPhysicalAddressLow(Adapter->ReceiveResourceAreaPhysical))
+ );
+
+ SONIC_WRITE_PORT(Adapter, SONIC_RESOURCE_END,
+ (USHORT)(SONIC_GET_LOW_PART_ADDRESS(
+ NdisGetPhysicalAddressLow(Adapter->ReceiveResourceAreaPhysical)) +
+ sizeof(SONIC_RECEIVE_RESOURCE) *
+ Adapter->NumberOfReceiveBuffers)
+ );
+
+ SONIC_WRITE_PORT(Adapter, SONIC_RESOURCE_READ,
+ SONIC_GET_LOW_PART_ADDRESS(
+ NdisGetPhysicalAddressLow(Adapter->ReceiveResourceAreaPhysical))
+ );
+
+ SONIC_WRITE_PORT(Adapter, SONIC_RESOURCE_WRITE,
+ SONIC_GET_LOW_PART_ADDRESS(
+ NdisGetPhysicalAddressLow(Adapter->ReceiveResourceAreaPhysical))
+ );
+
+
+ //
+ // Now take us out of reset mode...
+ //
+
+ SONIC_WRITE_PORT(Adapter, SONIC_COMMAND,
+ 0x0000
+ );
+
+ //
+ // ...and issue the Read RRA command.
+ //
+
+ SONIC_WRITE_PORT(Adapter, SONIC_COMMAND,
+ SONIC_CR_READ_RRA
+ );
+
+
+
+ //
+ // Wait for 1/5 second for Read RRA to finish.
+ //
+
+ Time = 20;
+
+ while (Time > 0) {
+
+ NdisStallExecution(10000);
+
+ SONIC_READ_PORT(Adapter, SONIC_COMMAND, &CommandRegister);
+ if ((CommandRegister & SONIC_CR_READ_RRA) == 0) {
+ break;
+ }
+
+ Time--;
+
+ }
+
+ if (Time == 0) {
+
+#if DBG
+ DbgPrint("SONIC: Could not read RRA\n");
+#endif
+ return FALSE;
+
+ }
+
+
+ //
+ // This will cause a LOAD_CAM interrupt when it is done.
+ //
+
+ SonicStartCamReload(Adapter);
+
+ return TRUE;
+
+}
+
+extern
+VOID
+SetupForReset(
+ IN PSONIC_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to fill in the who and why a reset is
+ being set up as well as setting the appropriate fields in the
+ adapter.
+
+Arguments:
+
+ Adapter - The adapter whose hardware is to be initialized.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Ndis buffer mapped
+ //
+ PNDIS_BUFFER CurrentBuffer;
+
+ //
+ // Map register that was used
+ //
+ UINT CurMapRegister;
+
+ //
+ // Packet to abort
+ //
+ PNDIS_PACKET Packet;
+
+ //
+ // Reserved Section of packet
+ //
+ PSONIC_PACKET_RESERVED Reserved;
+
+
+ //
+ // Shut down the chip. We won't be doing any more work until
+ // the reset is complete. We take it out of reset mode, however.
+ //
+
+ SonicStopChip(Adapter);
+
+ Adapter->ResetInProgress = TRUE;
+
+
+ //
+ // Once the chip is stopped we can't get any more interrupts.
+ // This call ensures that any ISR which is just about to run
+ // will find no bits in the ISR, and any DPR which fires will
+ // find nothing queued to do.
+ //
+
+ NdisMSynchronizeWithInterrupt(
+ &Adapter->Interrupt,
+ SonicSynchClearIsr,
+ (PVOID)Adapter);
+
+ //
+ // Un-map all outstanding transmits
+ //
+ while (Adapter->FirstFinishTransmit != NULL) {
+
+ //
+ // Remove first packet from the queue
+ //
+ Packet = Adapter->FirstFinishTransmit;
+ Reserved = PSONIC_RESERVED_FROM_PACKET(Packet);
+ Adapter->FirstFinishTransmit = Reserved->Next;
+
+ if (Reserved->UsedSonicBuffer) {
+ continue;
+ }
+
+ //
+ // The transmit is finished, so we can release
+ // the physical mapping used for it.
+ //
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ NULL,
+ &CurrentBuffer,
+ NULL
+ );
+
+ //
+ // Get starting map register
+ //
+ CurMapRegister = Reserved->DescriptorIndex * SONIC_MAX_FRAGMENTS;
+
+ //
+ // For each buffer
+ //
+ while (CurrentBuffer) {
+
+ //
+ // Finish the mapping
+ //
+ NdisMCompleteBufferPhysicalMapping(
+ Adapter->MiniportAdapterHandle,
+ CurrentBuffer,
+ CurMapRegister
+ );
+
+ ++CurMapRegister;
+
+ NdisGetNextBuffer(
+ CurrentBuffer,
+ &CurrentBuffer
+ );
+
+ }
+
+ }
+
+}
+
+#ifdef SONIC_INTERNAL
+
+//
+// The next routines are to support reading the registry to
+// obtain information about the internal sonic on the
+// MIPS R4000 motherboards.
+//
+
+//
+// This structure is used as the Context in the callbacks
+// to SonicHardwareSaveInformation.
+//
+
+typedef struct _SONIC_HARDWARE_INFO {
+
+ //
+ // These are read out of the "Configuration Data"
+ // data.
+ //
+
+ CCHAR InterruptVector;
+ KIRQL InterruptLevel;
+ USHORT DataConfigurationRegister;
+ LARGE_INTEGER PortAddress;
+ BOOLEAN DataValid;
+ UCHAR EthernetAddress[8];
+ BOOLEAN AddressValid;
+
+ //
+ // This is set to TRUE if "Identifier" is equal to
+ // "SONIC".
+ //
+
+ BOOLEAN SonicIdentifier;
+
+} SONIC_HARDWARE_INFO, *PSONIC_HARDWARE_INFO;
+
+
+#pragma NDIS_INIT_FUNCTION(SonicHardwareSaveInformation)
+
+STATIC
+NTSTATUS
+SonicHardwareSaveInformation(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues.
+ It is called back with the data for the "Identifier" value
+ and verifies that it is "SONIC", then is called back with
+ the resource list and records the ports, interrupt number,
+ and DCR value.
+
+Arguments:
+
+ ValueName - The name of the value ("Identifier" or "Configuration
+ Data").
+
+ ValueType - The type of the value (REG_SZ or REG_BINARY).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData (ignored).
+
+ Context - A pointer to the SONIC_HARDWARE_INFO structure.
+
+ EntryContext - FALSE for "Identifier", TRUE for "Configuration Data".
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PSONIC_HARDWARE_INFO HardwareInfo = (PSONIC_HARDWARE_INFO)Context;
+
+ if ((BOOLEAN)EntryContext) {
+
+ //
+ // This is the "Configuration Data" callback.
+ //
+
+ if ((ValueType == REG_BINARY || ValueType == REG_FULL_RESOURCE_DESCRIPTOR) &&
+ (ValueLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR))) {
+
+ BOOLEAN InterruptRead = FALSE;
+ BOOLEAN PortAddressRead = FALSE;
+ BOOLEAN DeviceSpecificRead = FALSE;
+ UINT i;
+
+ PCM_PARTIAL_RESOURCE_LIST ResourceList;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor;
+ PCM_SONIC_DEVICE_DATA SonicDeviceData;
+
+ ResourceList =
+ &((PCM_FULL_RESOURCE_DESCRIPTOR)ValueData)->PartialResourceList;
+
+ for (i = 0; i < ResourceList->Count; i++) {
+
+ ResourceDescriptor = &(ResourceList->PartialDescriptors[i]);
+
+ switch (ResourceDescriptor->Type) {
+
+ case CmResourceTypePort:
+
+ HardwareInfo->PortAddress = ResourceDescriptor->u.Port.Start;
+ PortAddressRead = TRUE;
+ break;
+
+ case CmResourceTypeInterrupt:
+
+ HardwareInfo->InterruptVector = (CCHAR)ResourceDescriptor->u.Interrupt.Vector;
+ HardwareInfo->InterruptLevel = (KIRQL)ResourceDescriptor->u.Interrupt.Level;
+ InterruptRead = TRUE;
+ break;
+
+ case CmResourceTypeDeviceSpecific:
+
+ if (i == ResourceList->Count-1) {
+
+ SonicDeviceData = (PCM_SONIC_DEVICE_DATA)
+ &(ResourceList->PartialDescriptors[ResourceList->Count]);
+
+ //
+ // Make sure we have enough room for each element we read.
+ //
+
+ if (ResourceDescriptor->u.DeviceSpecificData.DataSize >=
+ (ULONG)(FIELD_OFFSET (CM_SONIC_DEVICE_DATA, EthernetAddress[0]))) {
+
+ HardwareInfo->DataConfigurationRegister =
+ SonicDeviceData->DataConfigurationRegister;
+ DeviceSpecificRead = TRUE;
+
+ //
+ // Version.Revision later than 0.0 means that
+ // the ethernet address is there too.
+ //
+
+ if ((SonicDeviceData->Version != 0) ||
+ (SonicDeviceData->Revision != 0)) {
+
+ if (ResourceDescriptor->u.DeviceSpecificData.DataSize >=
+ (ULONG)(FIELD_OFFSET (CM_SONIC_DEVICE_DATA, EthernetAddress[0]) + 8)) {
+
+ SONIC_MOVE_MEMORY(
+ HardwareInfo->EthernetAddress,
+ SonicDeviceData->EthernetAddress,
+ 8);
+
+ HardwareInfo->AddressValid = TRUE;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ break;
+
+ }
+
+ }
+
+ //
+ // Make sure we got all we wanted.
+ //
+
+ if (PortAddressRead && InterruptRead && DeviceSpecificRead) {
+ HardwareInfo->DataValid = TRUE;
+ }
+
+ }
+
+ } else {
+
+ static const WCHAR SonicString[] = L"SONIC";
+
+ //
+ // This is the "Identifier" callback.
+ //
+
+ if ((ValueType == REG_SZ) &&
+ (ValueLength >= sizeof(SonicString)) &&
+ (RtlCompareMemory (ValueData, (PVOID)&SonicString, sizeof(SonicString)) == sizeof(SonicString))) {
+
+ HardwareInfo->SonicIdentifier = TRUE;
+
+ }
+
+ }
+
+ return STATUS_SUCCESS;
+
+}
+
+
+#pragma NDIS_INIT_FUNCTION(SonicHardwareVerifyChecksum)
+
+STATIC
+BOOLEAN
+SonicHardwareVerifyChecksum(
+ IN PSONIC_ADAPTER Adapter,
+ IN PUCHAR EthernetAddress,
+ OUT ULONG ErrorLogData[3]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine verifies that the checksum on the address
+ for an internal sonic on a MIPS R4000 system is correct.
+
+Arguments:
+
+ Adapter - The adapter which is being verified.
+
+ EthernetAddress - A pointer to the address, with the checksum
+ following it.
+
+ ErrorLogData - If the checksum is bad, returns the address
+ and the checksum we expected.
+
+Return Value:
+
+ TRUE if the checksum is correct.
+
+--*/
+
+{
+
+ //
+ // Iteration variable.
+ //
+ UINT i;
+
+ //
+ // Holds the checksum value.
+ //
+ USHORT CheckSum = 0;
+
+
+ //
+ // The network address is stored in the first 6 bytes of
+ // EthernetAddress. Following that is a zero byte followed
+ // by a value such that the sum of a checksum on the six
+ // bytes and this value is 0xff. The checksum is computed
+ // by adding together the six bytes, with the carry being
+ // wrapped back to the first byte.
+ //
+
+ for (i=0; i<6; i++) {
+
+ CheckSum += EthernetAddress[i];
+ if (CheckSum > 0xff) {
+ CheckSum -= 0xff;
+ }
+
+ }
+
+
+ if ((EthernetAddress[6] != 0x00) ||
+ ((EthernetAddress[7] + CheckSum) != 0xff)) {
+
+ ErrorLogData[0] = ((ULONG)(EthernetAddress[3]) << 24) +
+ ((ULONG)(EthernetAddress[2]) << 16) +
+ ((ULONG)(EthernetAddress[1]) << 8) +
+ ((ULONG)(EthernetAddress[0]));
+ ErrorLogData[1] = ((ULONG)(EthernetAddress[7]) << 24) +
+ ((ULONG)(EthernetAddress[6]) << 16) +
+ ((ULONG)(EthernetAddress[5]) << 8) +
+ ((ULONG)(EthernetAddress[4]));
+ ErrorLogData[2] = 0xff - CheckSum;
+
+ return FALSE;
+
+ }
+
+ return TRUE;
+
+}
+
+#endif // SONIC_INTERNAL
+
+
+#pragma NDIS_INIT_FUNCTION(SonicHardwareGetDetails)
+
+STATIC
+SONIC_HARDWARE_STATUS
+SonicHardwareGetDetails(
+ IN PSONIC_ADAPTER Adapter,
+ IN UINT SlotNumber,
+ IN UINT Controller,
+ IN UINT MultifunctionAdapter,
+ OUT PULONG InitialPort,
+ OUT PULONG NumberOfPorts,
+ IN OUT PUINT InterruptVector,
+ IN OUT PUINT InterruptLevel,
+ OUT ULONG ErrorLogData[3]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine gets the initial port and number of ports for
+ the Sonic. It also sets Adapter->PortShift. The ports are
+ numbered 0, 1, 2, etc. but may appear as 16- or 32-bit
+ ports, so PortShift will be 1 or 2 depending on how wide
+ the ports are.
+
+ It also sets the value of Adapter->DataConfigurationRegister,
+ and may modify InterruptVector, InterruptLevel, and
+ Adapter->PermanentNetworkAddress.
+
+Arguments:
+
+ Adapter - The adapter in question.
+
+ SlotNumber - For the EISA card this is the slot number that the
+ card is in.
+
+ Controller - For the internal version, it is the
+ NetworkController number.
+
+ MultifunctionAdapter - For the internal version, it is the adapter number.
+
+ InitialPort - The base of the Sonic ports.
+
+ NumberOfPorts - The number of bytes of ports to map.
+
+ InterruptVector - A pointer to the interrupt vector. Depending
+ on the card type, this may be passed in or returned by
+ this function.
+
+ InterruptLevel - A pointer to the interrupt level. Depending
+ on the card type, this may be passed in or returned by
+ this function.
+
+ ErrorLogData - If the return status is SonicHardwareChecksum,
+ this returns 3 longwords to be included in the error log.
+
+Return Value:
+
+ SonicHardwareOk if successful, SonicHardwareChecksum if the
+ checksum is bad, SonicHardwareConfig for other problems.
+
+--*/
+
+{
+
+ switch (Adapter->AdapterType) {
+
+#ifdef SONIC_EISA
+
+ case SONIC_ADAPTER_TYPE_EISA:
+
+ *InitialPort = (SlotNumber << 12);
+ *NumberOfPorts = 0xD00;
+ Adapter->PortShift = 1;
+ Adapter->DataConfigurationRegister =
+ SONIC_DCR_PROGRAMMABLE_OUTPUT_1 |
+ SONIC_DCR_USER_DEFINABLE_1 |
+ SONIC_DCR_3_WAIT_STATE |
+ SONIC_DCR_BLOCK_MODE_DMA |
+ SONIC_DCR_32_BIT_DATA_WIDTH |
+ SONIC_DCR_8_WORD_RECEIVE_FIFO |
+ SONIC_DCR_8_WORD_TRANSMIT_FIFO;
+
+ return SonicHardwareOk;
+ break;
+
+#endif // SONIC_EISA
+
+#ifdef SONIC_INTERNAL
+
+ case SONIC_ADAPTER_TYPE_INTERNAL:
+ {
+
+ //
+ // For MIPS R4000 systems, we have to query the registry to obtain
+ // information about ports, interrupts, and the value to be
+ // stored in the DCR register.
+ //
+
+ //
+ // NOTE: The following code is NT-specific, since that is
+ // currently the only system that runs on the MIPS R4000 hardware.
+ //
+ // We initialize an RTL_QUERY_TABLE to retrieve the Identifer
+ // and ConfigurationData strings from the registry.
+ //
+
+ PWSTR ConfigDataPath = L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter\\#\\NetworkController\\#";
+ PWSTR IdentifierString = L"Identifier";
+ PWSTR ConfigDataString = L"Configuration Data";
+ RTL_QUERY_REGISTRY_TABLE QueryTable[4];
+ SONIC_HARDWARE_INFO SonicHardwareInfo;
+ NTSTATUS Status;
+
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Call SonicSaveHardwareInformation for the "Identifier"
+ // value.
+ //
+
+ QueryTable[0].QueryRoutine = SonicHardwareSaveInformation;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[0].Name = IdentifierString;
+ QueryTable[0].EntryContext = (PVOID)FALSE;
+ QueryTable[0].DefaultType = REG_NONE;
+
+ //
+ // 2) Call SonicSaveHardwareInformation for the "Configuration Data"
+ // value.
+ //
+
+ QueryTable[1].QueryRoutine = SonicHardwareSaveInformation;
+ QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[1].Name = ConfigDataString;
+ QueryTable[1].EntryContext = (PVOID)TRUE;
+ QueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 3) Stop
+ //
+
+ QueryTable[2].QueryRoutine = NULL;
+ QueryTable[2].Flags = 0;
+ QueryTable[2].Name = NULL;
+
+
+ //
+ // Modify ConfigDataPath to replace the two # symbols with
+ // the MultifunctionAdapter number and NetworkController number.
+ //
+
+ ConfigDataPath[67] = (WCHAR)('0' + MultifunctionAdapter);
+ ConfigDataPath[87] = (WCHAR)('0' + Controller);
+
+ SonicHardwareInfo.DataValid = FALSE;
+ SonicHardwareInfo.AddressValid = FALSE;
+ SonicHardwareInfo.SonicIdentifier = FALSE;
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ ConfigDataPath,
+ QueryTable,
+ (PVOID)&SonicHardwareInfo,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint ("SONIC: Could not read hardware information\n");
+#endif
+ return SonicHardwareConfig;
+ }
+
+ if (SonicHardwareInfo.DataValid && SonicHardwareInfo.SonicIdentifier) {
+
+ *InterruptVector = (UINT)SonicHardwareInfo.InterruptVector;
+ *InterruptLevel = (UINT)SonicHardwareInfo.InterruptLevel;
+ *InitialPort = SonicHardwareInfo.PortAddress.LowPart;
+ *NumberOfPorts = 192;
+ Adapter->PortShift = 2;
+ Adapter->DataConfigurationRegister =
+ SonicHardwareInfo.DataConfigurationRegister;
+
+ if (SonicHardwareInfo.AddressValid) {
+
+ if (!SonicHardwareVerifyChecksum(Adapter, SonicHardwareInfo.EthernetAddress, ErrorLogData)) {
+#if DBG
+ DbgPrint("SONIC: Invalid registry network address checksum!!\n");
+#endif
+ return SonicHardwareChecksum;
+ }
+
+ SONIC_MOVE_MEMORY(
+ Adapter->PermanentNetworkAddress,
+ SonicHardwareInfo.EthernetAddress,
+ 8);
+ Adapter->PermanentAddressValid = TRUE;
+
+ }
+
+ return SonicHardwareOk;
+
+ } else {
+
+#if DBG
+ DbgPrint ("SONIC: Incorrect registry hardware information\n");
+#endif
+ return SonicHardwareConfig;
+
+ }
+
+ break;
+
+ }
+
+#endif // SONIC_INTERNAL
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+
+ return SonicHardwareConfig;
+
+}
+
+
+
+#pragma NDIS_INIT_FUNCTION(SonicHardwareGetAddress)
+
+STATIC
+BOOLEAN
+SonicHardwareGetAddress(
+ IN PSONIC_ADAPTER Adapter,
+ IN ULONG ErrorLogData[3]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine gets the network address from the hardware.
+
+Arguments:
+
+ Adapter - Where to store the network address.
+
+ ErrorLogData - If the checksum is bad, returns the address
+ and the checksum we expected.
+
+Return Value:
+
+ TRUE if successful.
+
+--*/
+
+{
+#define NVRAM_READ_ONLY_BASE 0x8000b000
+
+ //
+ // Iteration variable.
+ //
+ UINT i;
+
+
+ switch (Adapter->AdapterType) {
+
+#ifdef SONIC_EISA
+
+ case SONIC_ADAPTER_TYPE_EISA:
+
+ //
+ // The EISA card has the address stored at ports xC90 to xC95,
+ // where x is the slot number.
+ //
+
+ for (i = 0; i < 6; i++) {
+
+ NdisRawReadPortUchar(
+ Adapter->SonicPortAddress + 0xc90 + i,
+ &Adapter->PermanentNetworkAddress[i]);
+
+ }
+
+ break;
+
+#endif // SONIC_EISA
+
+#ifdef SONIC_INTERNAL
+
+ case SONIC_ADAPTER_TYPE_INTERNAL:
+ {
+
+ NDIS_STATUS Status;
+ USHORT SiliconRevision;
+
+ if (!Adapter->PermanentAddressValid) {
+
+ //
+ // Physical addresses for call to NdisMapIoSpace.
+ //
+
+ NDIS_PHYSICAL_ADDRESS NvRamPhysical =
+ NDIS_PHYSICAL_ADDRESS_CONST(NVRAM_READ_ONLY_BASE, 0);
+
+ //
+ // Temporarily maps the NVRAM into our address space.
+ //
+ PVOID NvRamMapping;
+
+
+
+ //
+ // If PermanentAddressValid is still FALSE then the address
+ // was not read by SonicHardwareGetDetails, so we must do it
+ // here.
+ //
+
+ Status = NdisMMapIoSpace (
+ &NvRamMapping,
+ Adapter->MiniportAdapterHandle,
+ NvRamPhysical,
+ 8
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_RESOURCE_CONFLICT,
+ 0
+ );
+
+ return(FALSE);
+
+ }
+
+ //
+ // Verify that the checksum matches.
+ //
+
+ if (!SonicHardwareVerifyChecksum(Adapter, (PUCHAR)NvRamMapping, ErrorLogData)) {
+
+#if DBG
+ DbgPrint("SONIC: Invalid NVRAM network address checksum!!\n");
+#endif
+ NdisMUnmapIoSpace(Adapter->MiniportAdapterHandle, NvRamMapping, 8);
+ return FALSE;
+
+ }
+
+ //
+ // Checksum is OK, save the address.
+ //
+
+ for (i=0; i<6; i++) {
+ Adapter->PermanentNetworkAddress[i] = *((PUCHAR)NvRamMapping+i);
+ }
+ Adapter->PermanentAddressValid = TRUE;
+
+ NdisMUnmapIoSpace(Adapter->MiniportAdapterHandle, NvRamMapping, 8);
+
+ }
+
+ //
+ // The Data Configuration Register is already set up, but we
+ // change the FIFO initialization for old revisions.
+ //
+
+ SONIC_READ_PORT(Adapter, SONIC_SILICON_REVISION, &SiliconRevision);
+
+ if (SiliconRevision < 4) {
+
+ Adapter->DataConfigurationRegister =
+ (Adapter->DataConfigurationRegister & SONIC_DCR_FIFO_MASK) |
+ SONIC_DCR_8_WORD_RECEIVE_FIFO |
+ SONIC_DCR_8_WORD_TRANSMIT_FIFO;
+
+ }
+
+ break;
+
+ }
+
+#endif // SONIC_INTERNAL
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+
+
+#if DBG
+ if (SonicDbg) {
+ DbgPrint("SONIC: ");
+ DbgPrint("[ %x-%x-%x-%x-%x-%x ]\n",
+ (UCHAR)Adapter->PermanentNetworkAddress[0],
+ (UCHAR)Adapter->PermanentNetworkAddress[1],
+ (UCHAR)Adapter->PermanentNetworkAddress[2],
+ (UCHAR)Adapter->PermanentNetworkAddress[3],
+ (UCHAR)Adapter->PermanentNetworkAddress[4],
+ (UCHAR)Adapter->PermanentNetworkAddress[5]);
+ DbgPrint("\n");
+ }
+#endif
+
+ return TRUE;
+
+}
diff --git a/private/ntos/ndis/sonic/sonic.rc b/private/ntos/ndis/sonic/sonic.rc
new file mode 100644
index 000000000..311a777c2
--- /dev/null
+++ b/private/ntos/ndis/sonic/sonic.rc
@@ -0,0 +1,39 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "ARC Built-In Ethernet network driver"
+#define VER_INTERNALNAME_STR "SONIC.SYS"
+#define VER_ORIGINALFILENAME_STR "SONIC.SYS"
+
+#include "common.ver"
+
diff --git a/private/ntos/ndis/sonic/sonichrd.h b/private/ntos/ndis/sonic/sonichrd.h
new file mode 100644
index 000000000..470f18383
--- /dev/null
+++ b/private/ntos/ndis/sonic/sonichrd.h
@@ -0,0 +1,791 @@
+/*++
+
+Copyright (c) 1990-1992 Microsoft Corporation
+
+Module Name:
+
+ sonichrd.h
+
+Abstract:
+
+ This file contains the hardware-related definitions for
+ the SONIC driver.
+
+ The overall structure is taken from the Lance driver
+ by Tony Ercolano.
+
+Author:
+
+ Anthony V. Ercolano (tonye) creation-date 19-Jun-1990
+ Adam Barr (adamba) 16-Nov-1990
+
+Environment:
+
+ This driver is expected to work in DOS, OS2 and NT at the equivalent
+ of kernel mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Revision History:
+
+
+--*/
+
+#ifndef _SONICHARDWARE_
+#define _SONICHARDWARE_
+
+
+//
+// Include processor-specific definitions needed by the sonic.
+// This defines the SONIC_READ_PORT and SONIC_WRITE_PORT macros,
+// as well as whether SONIC_EISA and SONIC_INTERNAL are defined.
+//
+
+#include <sonicdet.h>
+
+//
+// Compressed ID for the adapter
+//
+
+#define SONIC_COMPRESSED_ID 0x01109841
+
+
+//
+// Offsets from the base of the Sonic registers.
+//
+// All registers are 16 bits.
+//
+
+#define SONIC_COMMAND 0x00
+#define SONIC_DATA_CONFIGURATION 0x01
+#define SONIC_RECEIVE_CONTROL 0x02
+#define SONIC_TRANSMIT_CONTROL 0x03
+#define SONIC_INTERRUPT_MASK 0x04
+#define SONIC_INTERRUPT_STATUS 0x05
+
+#define SONIC_UPPER_TRANSMIT_DESCRIPTOR 0x06
+#define SONIC_CURR_TRANSMIT_DESCRIPTOR 0x07
+
+#define SONIC_UPPER_RECEIVE_DESCRIPTOR 0x0d
+#define SONIC_CURR_RECEIVE_DESCRIPTOR 0x0e
+#define SONIC_END_OF_BUFFER_WORD_COUNT 0x13
+#define SONIC_UPPER_RECEIVE_RESOURCE 0x14
+#define SONIC_RESOURCE_START 0x15
+#define SONIC_RESOURCE_END 0x16
+#define SONIC_RESOURCE_READ 0x17
+#define SONIC_RESOURCE_WRITE 0x18
+#define SONIC_RECEIVE_SEQUENCE 0x2b
+
+#define SONIC_CAM_ENTRY_POINTER 0x21
+#define SONIC_CAM_ADDRESS_PORT_2 0x22
+#define SONIC_CAM_ADDRESS_PORT_1 0x23
+#define SONIC_CAM_ADDRESS_PORT_0 0x24
+#define SONIC_CAM_ENABLE 0x25
+#define SONIC_CAM_DESCRIPTOR 0x26
+#define SONIC_CAM_DESCRIPTOR_COUNT 0x27
+
+#define SONIC_CRC_ERROR 0x2c
+#define SONIC_FRAME_ALIGNMENT_ERROR 0x2d
+#define SONIC_MISSED_PACKET 0x2e
+
+#define SONIC_WATCHDOG_TIMER_0 0x29
+#define SONIC_WATCHDOG_TIMER_1 0x2a
+
+#define SONIC_SILICON_REVISION 0x28
+
+
+//
+// Constants for the SONIC_COMMAND register.
+//
+
+#define SONIC_CR_LOAD_CAM ((USHORT)(0x0200))
+#define SONIC_CR_READ_RRA ((USHORT)(0x0100))
+#define SONIC_CR_SOFTWARE_RESET ((USHORT)(0x0080))
+#define SONIC_CR_START_TIMER ((USHORT)(0x0020))
+#define SONIC_CR_STOP_TIMER ((USHORT)(0x0010))
+#define SONIC_CR_RECEIVER_ENABLE ((USHORT)(0x0008))
+#define SONIC_CR_RECEIVER_DISABLE ((USHORT)(0x0004))
+#define SONIC_CR_TRANSMIT_PACKETS ((USHORT)(0x0002))
+#define SONIC_CR_HALT_TRANSMISSION ((USHORT)(0x0001))
+
+
+//
+// Constants for the SONIC_DATA_CONFIGURATION register.
+//
+
+#define SONIC_DCR_LATCHED_BUS_RETRY ((USHORT)(0x2000))
+#define SONIC_DCR_PROGRAMMABLE_OUTPUT_1 ((USHORT)(0x1000))
+#define SONIC_DCR_PROGRAMMABLE_OUTPUT_0 ((USHORT)(0x0800))
+#define SONIC_DCR_SYNCH_TERMINATION ((USHORT)(0x0400))
+#define SONIC_DCR_USER_DEFINABLE_1 ((USHORT)(0x0200))
+#define SONIC_DCR_USER_DEFINABLE_0 ((USHORT)(0x0100))
+#define SONIC_DCR_0_WAIT_STATE ((USHORT)(0x0000))
+#define SONIC_DCR_1_WAIT_STATE ((USHORT)(0x0040))
+#define SONIC_DCR_2_WAIT_STATE ((USHORT)(0x0080))
+#define SONIC_DCR_3_WAIT_STATE ((USHORT)(0x00c0))
+#define SONIC_DCR_32_BIT_DATA_WIDTH ((USHORT)(0x0020))
+#define SONIC_DCR_16_BIT_DATA_WIDTH ((USHORT)(0x0000))
+#define SONIC_DCR_BLOCK_MODE_DMA ((USHORT)(0x0010))
+#define SONIC_DCR_EMPTY_FILL_DMA ((USHORT)(0x0000))
+#define SONIC_DCR_FIFO_MASK ((USHORT)(0xfff0))
+#define SONIC_DCR_12_WORD_RECEIVE_FIFO ((USHORT)(0x000c))
+#define SONIC_DCR_8_WORD_RECEIVE_FIFO ((USHORT)(0x0008))
+#define SONIC_DCR_4_WORD_RECEIVE_FIFO ((USHORT)(0x0004))
+#define SONIC_DCR_2_WORD_RECEIVE_FIFO ((USHORT)(0x0000))
+#define SONIC_DCR_14_WORD_TRANSMIT_FIFO ((USHORT)(0x0003))
+#define SONIC_DCR_12_WORD_TRANSMIT_FIFO ((USHORT)(0x0002))
+#define SONIC_DCR_8_WORD_TRANSMIT_FIFO ((USHORT)(0x0001))
+#define SONIC_DCR_4_WORD_TRANSMIT_FIFO ((USHORT)(0x0000))
+
+
+//
+// Constants for the SONIC_RECEIVE_CONTROL register.
+//
+
+#define SONIC_RCR_ACCEPT_CRC_ERRORS ((USHORT)(0x8000))
+#define SONIC_RCR_ACCEPT_RUNT_PACKETS ((USHORT)(0x4000))
+#define SONIC_RCR_ACCEPT_BROADCAST ((USHORT)(0x2000))
+#define SONIC_RCR_PROMISCUOUS_PHYSICAL ((USHORT)(0x1000))
+#define SONIC_RCR_ACCEPT_ALL_MULTICAST ((USHORT)(0x0800))
+#define SONIC_RCR_TRANSCEIVER_LOOPBACK ((USHORT)(0x0600))
+#define SONIC_RCR_ENDEC_LOOPBACK ((USHORT)(0x0400))
+#define SONIC_RCR_MAC_LOOPBACK ((USHORT)(0x0200))
+#define SONIC_RCR_NO_LOOPBACK ((USHORT)(0x0000))
+
+#define SONIC_RCR_MULTICAST_RECEIVED ((USHORT)(0x0100))
+#define SONIC_RCR_BROADCAST_RECEIVED ((USHORT)(0x0080))
+#define SONIC_RCR_LAST_PACKET_IN_RBA ((USHORT)(0x0040))
+#define SONIC_RCR_CARRIER_SENSE ((USHORT)(0x0020))
+#define SONIC_RCR_COLLISION ((USHORT)(0x0010))
+#define SONIC_RCR_CRC_ERROR ((USHORT)(0x0008))
+#define SONIC_RCR_FRAME_ALIGNMENT ((USHORT)(0x0004))
+#define SONIC_RCR_LOOPBACK_RECEIVED ((USHORT)(0x0002))
+#define SONIC_RCR_PACKET_RECEIVED_OK ((USHORT)(0x0001))
+
+
+//
+// This is needed due to a problem with the SONIC while attempting
+// to ignore these packets.
+//
+
+#define SONIC_RCR_DEFAULT_VALUE ((USHORT) \
+ (SONIC_RCR_ACCEPT_CRC_ERRORS | \
+ SONIC_RCR_ACCEPT_RUNT_PACKETS))
+
+
+//
+// Constants for the SONIC_TRANSMIT_CONTROL register.
+//
+
+#define SONIC_TCR_PROG_INTERRUPT ((USHORT)(0x8000))
+#define SONIC_TCR_CRC_INHIBIT ((USHORT)(0x2000))
+#define SONIC_TCR_EXCESSIVE_DEFERRAL ((USHORT)(0x0400))
+#define SONIC_TCR_DEFERRED_TRANSMISSION ((USHORT)(0x0200))
+#define SONIC_TCR_NO_CARRIER_SENSE ((USHORT)(0x0100))
+#define SONIC_TCR_CARRIER_LOST ((USHORT)(0x0080))
+#define SONIC_TCR_EXCESSIVE_COLLISIONS ((USHORT)(0x0040))
+#define SONIC_TCR_OUT_OF_WINDOW ((USHORT)(0x0020))
+#define SONIC_TCR_FIFO_UNDERRUN ((USHORT)(0x0004))
+#define SONIC_TCR_BYTE_COUNT_MISMATCH ((USHORT)(0x0002))
+#define SONIC_TCR_PACKET_TRANSMITTED_OK ((USHORT)(0x0001))
+
+#define SONIC_TCR_STATUS_MASK ((USHORT)(0x07ff))
+#define SONIC_TCR_COLLISIONS_MASK ((USHORT)(0xf800))
+#define SONIC_TCR_COLLISIONS_SHIFT 11
+
+
+//
+// Constants for the SONIC_INTERRUPT_MASK and
+// SONIC_INTERRUPT_STATUS registers.
+//
+
+#define SONIC_INT_BUS_RETRY ((USHORT)(0x4000))
+#define SONIC_INT_HEARTBEAT_LOST ((USHORT)(0x2000))
+#define SONIC_INT_LOAD_CAM_DONE ((USHORT)(0x1000))
+#define SONIC_INT_PROG_INTERRUPT ((USHORT)(0x0800))
+#define SONIC_INT_PACKET_RECEIVED ((USHORT)(0x0400))
+#define SONIC_INT_PACKET_TRANSMITTED ((USHORT)(0x0200))
+#define SONIC_INT_TRANSMIT_ERROR ((USHORT)(0x0100))
+#define SONIC_INT_TIMER_COMPLETE ((USHORT)(0x0080))
+#define SONIC_INT_RECEIVE_DESCRIPTORS ((USHORT)(0x0040))
+#define SONIC_INT_RECEIVE_BUFFERS ((USHORT)(0x0020))
+#define SONIC_INT_RECEIVE_OVERFLOW ((USHORT)(0x0010))
+#define SONIC_INT_CRC_TALLY_ROLLOVER ((USHORT)(0x0008))
+#define SONIC_INT_FAE_TALLY_ROLLOVER ((USHORT)(0x0004))
+#define SONIC_INT_MP_TALLY_ROLLOVER ((USHORT)(0x0002))
+
+//
+// By default, the interrupts we unmask.
+//
+
+#define SONIC_INT_DEFAULT_VALUE ((USHORT) \
+ (SONIC_INT_BUS_RETRY | \
+ SONIC_INT_LOAD_CAM_DONE | \
+ SONIC_INT_PROG_INTERRUPT | \
+ SONIC_INT_PACKET_RECEIVED | \
+ SONIC_INT_PACKET_TRANSMITTED | \
+ SONIC_INT_TRANSMIT_ERROR | \
+ SONIC_INT_RECEIVE_DESCRIPTORS | \
+ SONIC_INT_RECEIVE_BUFFERS | \
+ SONIC_INT_RECEIVE_OVERFLOW | \
+ SONIC_INT_CRC_TALLY_ROLLOVER | \
+ SONIC_INT_FAE_TALLY_ROLLOVER | \
+ SONIC_INT_MP_TALLY_ROLLOVER))
+
+//
+// The interrupts we acknowledge immediately.
+//
+
+#define SONIC_INT_IMMEDIATE_ACK ((USHORT) \
+ (SONIC_INT_DEFAULT_VALUE & \
+ ~(SONIC_INT_RECEIVE_DESCRIPTORS | \
+ SONIC_INT_RECEIVE_BUFFERS)))
+
+
+
+//
+// The maximum number of fragments that a transmit descriptor
+// can hold. If a packet has more than this, we have to merge
+// it into a single buffer before we transmit it. Increasing
+// this will prevent us from merging packets with more fragments
+// (which are rare) but use more memory in our transmit descriptors
+// (which are permanently allocated). For every one that we
+// increase this, memory usage goes up by 12 bytes in each
+// descriptor.
+//
+
+#define SONIC_MAX_FRAGMENTS 4
+
+
+//
+// The smallest size that a fragment can be. This is due to
+// their potentially being underrun problems if a fragment
+// shorted than this is transmitted. If a packet has a fragment
+// that is too short, we merge it into a single buffer before
+// we transmit it. This should not change unless the hardware
+// changes in some way.
+//
+
+#define SONIC_MIN_FRAGMENT_SIZE 12
+
+
+//
+// The smallest Ethernet packet size. Packets smaller than this
+// have blanks appended to pad them out to this length.
+//
+
+#define SONIC_MIN_PACKET_SIZE 60
+
+
+//
+// The number of entries in the CAM. The CAM (Content Addressable
+// Memory) holds the directed and multicast addresses that we
+// monitor. We reserve one of these spots for our directed address,
+// allowing us SONIC_CAM_ENTRIES - 1 multicast addresses. Changing
+// this allows us to handle more multicast addresses without
+// forcing the protocol into "all multicast" mode, but allocates
+// more memory in the CAM (16 bytes per entry).
+//
+
+#define SONIC_CAM_ENTRIES 16
+
+
+//
+// The number of transmit descriptors in the ring we allocate,
+// each of which can hold SONIC_MAX_FRAGMENTS fragments.
+// The size of a transmit descriptor is ~100 bytes, varying
+// based on SONIC_MAX_FRAGMENTS.
+//
+
+#define SONIC_NUMBER_OF_TRANSMIT_DESCRIPTORS 5
+
+
+//
+// The number and size of the receive buffers we allocate,
+// which hold the actual data received off the network. Increasing
+// this allows us to receive more large packets, but the
+// number of receive descriptors also needs to be increased.
+//
+
+#define SONIC_NUMBER_OF_RECEIVE_BUFFERS 10
+#define SONIC_SIZE_OF_RECEIVE_BUFFERS 4000
+
+
+//
+// This seems to have to be a multiple of four
+// (not just two). When there is less than this
+// amount left in a Receive Buffer after packet
+// reception, the sonic will use the next
+// ReceiveBuffer for the next packet. We define it
+// larger than the maximum Ethernet packet size,
+// so we never get a buffer overflow.
+//
+
+#define SONIC_END_OF_BUFFER_COUNT 1520
+
+//
+// ERRATA: This is the amount we have to add to
+// the EOBC value to account for the bug in revision
+// C of the chip, which decrements the RBWC registers
+// by two words (four bytes) less than they should be
+// on each packet reception. To handle this we
+// overestimate EOBC by four bytes times the maximum
+// number of packets we could receive in a buffer.
+//
+
+#define SONIC_EOBC_REV_C_CORRECTION ((SONIC_SIZE_OF_RECEIVE_BUFFERS / 64) * 4)
+
+
+//
+// The number of receive descriptors we allocate, which hold
+// pointers to packets received in the receive buffers. This
+// is now kept at twice the number of receive buffers since
+// two full-size packets can be received into each receive
+// buffer.
+//
+
+#define SONIC_NUMBER_OF_RECEIVE_DESCRIPTORS 20
+
+
+//
+// The small, medium and large buffers are used for merging
+// packets that violate our constraints (two many fragments,
+// fragments too small). The packet is merged into the smallest
+// buffer that can hold it. These should not be increased unless
+// there is a problem with many packets being merged; in that
+// case it might be better to increase SONIC_MAX_FRAGMENTS
+// first (if the problem is too many fragments).
+//
+
+#define SONIC_SMALL_BUFFER_SIZE ((UINT)64)
+#define SONIC_MEDIUM_BUFFER_SIZE ((UINT)256)
+#define SONIC_LARGE_BUFFER_SIZE ((UINT)1514)
+
+#define SONIC_NUMBER_OF_SMALL_BUFFERS ((UINT)10)
+#define SONIC_NUMBER_OF_MEDIUM_BUFFERS ((UINT)10)
+#define SONIC_NUMBER_OF_LARGE_BUFFERS ((UINT)3)
+
+
+//
+// This bit in a link field signifies "end of list" to the
+// sonic.
+//
+
+#define SONIC_END_OF_LIST 0x01
+
+
+//
+// These are used in the InUse field of Receive Descriptors.
+//
+
+#define SONIC_OWNED_BY_SYSTEM 0x00
+#define SONIC_OWNED_BY_SONIC 0x01
+
+
+//
+// This type defines the physical addresses used by the Sonic
+// chip itself. This should always be four bytes.
+//
+
+typedef ULONG SONIC_PHYSICAL_ADDRESS, *PSONIC_PHYSICAL_ADDRESS;
+
+
+
+//
+// Describes a Receive Buffer Area; the Receive Resource
+// Area is an array of these structures. In 32-bit mode the
+// upper 16 bits of all the elements are not used.
+//
+
+typedef struct _SONIC_RECEIVE_RESOURCE {
+
+ //
+ // Pointer to the receive buffer. It must be
+ // longword (4 bytes) aligned.
+ //
+
+ SONIC_PHYSICAL_ADDRESS LowBufferAddress;
+ SONIC_PHYSICAL_ADDRESS HighBufferAddress;
+
+ //
+ // The number of WORDS in the receive buffer.
+ //
+
+ UINT LowBufferWordCount;
+ UINT HighBufferWordCount;
+
+} SONIC_RECEIVE_RESOURCE, * PSONIC_RECEIVE_RESOURCE;
+
+
+//
+// A receive descriptor; the Receive Descriptor Area is a
+// linked list of these structures.
+//
+
+typedef struct _SONIC_RECEIVE_DESCRIPTOR {
+
+ //
+ // After reception this field will contain the contents
+ // of the SONIC_RECEIVE_CONTROL register. Bits 8-0 are
+ // status bits.
+ //
+
+ UINT ReceiveStatus;
+
+ //
+ // The length of the packet (including the CRC field).
+ //
+
+ UINT ByteCount;
+
+ //
+ // A pointer to the location in the RBA where the packet
+ // resides. A packet is always received into a contiguous
+ // piece of memory.
+ //
+
+ SONIC_PHYSICAL_ADDRESS LowPacketAddress;
+ SONIC_PHYSICAL_ADDRESS HighPacketAddress;
+
+ //
+ // Contains the RBA and packet sequence number.
+ //
+
+ UINT SequenceNumber;
+
+ //
+ // A link to the next receive descriptor. This is set up
+ // at initialization and is not modified by the SONIC.
+ // The low bit is the EOL bit, indicating the end of
+ // the linked list of receive descriptors.
+ //
+
+ SONIC_PHYSICAL_ADDRESS Link;
+
+ //
+ // Denotes the ownership of this receive descriptor.
+ // 0 = driver, non-zero = SONIC.
+ //
+
+ UINT InUse;
+
+} SONIC_RECEIVE_DESCRIPTOR, * PSONIC_RECEIVE_DESCRIPTOR;
+
+
+
+//
+// Describes a fragment of a packet.
+//
+
+typedef struct _SONIC_TRANSMIT_FRAGMENT {
+
+ //
+ // A pointer to the fragment. May be aligned on any
+ // byte boundary.
+ //
+
+ SONIC_PHYSICAL_ADDRESS LowFragmentAddress;
+ SONIC_PHYSICAL_ADDRESS HighFragmentAddress;
+
+ //
+ // The size of the fragment.
+ //
+
+ UINT FragmentByteCount;
+
+} SONIC_TRANSMIT_FRAGMENT, * PSONIC_TRANSMIT_FRAGMENT;
+
+
+//
+// A transmit descriptor for a packet (containing up to
+// SONIC_MAX_PACKET_FRAGMENTS pieces); the Transmit
+// Descriptor Area is a linked list of these structures.
+// If there are fewer than SONIC_MAX_PACKET_FRAGMENTS
+// pieces, then the Link field will not be used and
+// the link value will instead be put in
+// PacketFragments[FragmentCount].FragmentPointerLsb;
+// however at initialization the value will be put in
+// Link and that is the value that must be used.
+//
+
+typedef struct _SONIC_TRANSMIT_DESCRIPTOR {
+
+ //
+ // Contains the status after transmission. The status
+ // is bits 10-0 of the SONIC_TRANSMIT_CONTROL register.
+ //
+
+ UINT TransmitStatus;
+
+ //
+ // Before transmission, bits 15-12 of this field are
+ // copied into the SONIC_TRANSMIT_CONTROL register.
+ //
+
+ UINT TransmitConfiguration;
+
+ //
+ // The size of the packet to be transmitted, in bytes.
+ //
+
+ UINT PacketSize;
+
+ //
+ // The number of fragments in the packet.
+ //
+
+ UINT FragmentCount;
+
+ //
+ // Location and size of each fragment.
+ //
+
+ SONIC_TRANSMIT_FRAGMENT Fragments[SONIC_MAX_FRAGMENTS];
+
+ //
+ // A pointer to the next Transmit Descriptor. This will
+ // be set at initialization time and will not change.
+ // However, its value will be copied into the beginning
+ // of the first unused Fragments[] structure if FragmentCount
+ // is less than SONIC_MAX_FRAGMENTS (since the Link field
+ // must follow the last fragment descriptor).
+ //
+
+ SONIC_PHYSICAL_ADDRESS Link;
+
+} SONIC_TRANSMIT_DESCRIPTOR, * PSONIC_TRANSMIT_DESCRIPTOR;
+
+
+
+//
+// Describes an entry in the CAM Descriptor Area.
+//
+
+typedef struct _SONIC_CAM_FRAGMENT {
+
+ //
+ // The index (0-15) of the CAM entry
+ //
+
+ UINT CamEntryPointer;
+
+ //
+ // The Ethernet address, divided into three pieces in
+ // order from most significant to least significant.
+ // In each piece only the low-order 16 bits are
+ // used. I.e., for an Ethernet address 01-02-03-04-05-06,
+ // CamAddressPort0 would be 0x0102, CamAddressPort1
+ // would be 0x0304, and CamAddressPort2 would be 0x0506.
+ //
+
+ UINT CamAddressPort0;
+ UINT CamAddressPort1;
+ UINT CamAddressPort2;
+
+} SONIC_CAM_FRAGMENT, * PSONIC_CAM_FRAGMENT;
+
+
+
+//
+// The entire CAM Descriptor Area. In general, the CamEnable
+// field is not needed; the value will be stored in the
+// CamEntryPointer of the SONIC_CAM_FRAGMENT after the last
+// one used. However, the current value will also be
+// maintained in CamEnable.
+//
+
+typedef struct _SONIC_CAM_DESCRIPTOR_AREA {
+
+ //
+ // Holds the index and value of each of the entries.
+ //
+
+ SONIC_CAM_FRAGMENT CamFragments[SONIC_CAM_ENTRIES];
+
+ //
+ // A bit mask indicating which of the entries are enabled
+ // (only the low 16 bits are used).
+ //
+
+ UINT CamEnable;
+
+} SONIC_CAM_DESCRIPTOR_AREA, * PSONIC_CAM_DESCRIPTOR_AREA;
+
+
+
+//
+// Identifies the AdapterType values that the driver supports.
+//
+
+#define SONIC_ADAPTER_TYPE_EISA 1
+#define SONIC_ADAPTER_TYPE_INTERNAL 2
+
+
+//
+// Macros to get MSB and LSB of an address.
+//
+
+#define SONIC_GET_LOW_PART_ADDRESS(Adr) ((USHORT)((Adr) & 0xffff))
+#define SONIC_GET_HIGH_PART_ADDRESS(Adr) ((USHORT)(((Adr) & 0xffff0000) >> 16))
+
+
+//
+// Set up a SONIC_CAM_FRAGMENT given the entry pointer and
+// Ethernet address.
+//
+// Cfp is a pointer to a CAM Fragment.
+//
+// Ep is the entry pointer.
+//
+// Addr is the Ethernet address.
+//
+
+#define SONIC_LOAD_CAM_FRAGMENT(Cfp, Ep, Addr) \
+{ \
+ PSONIC_CAM_FRAGMENT _Cfp = (Cfp); \
+ UINT _Ep = (Ep); \
+ PVOID _Addr = (Addr); \
+ _Cfp->CamEntryPointer = _Ep; \
+ NdisWriteRegisterUlong((PULONG)(&_Cfp->CamAddressPort0), (ULONG)(((PUSHORT)Addr)[0])); \
+ NdisWriteRegisterUlong((PULONG)(&_Cfp->CamAddressPort1), (ULONG)(((PUSHORT)Addr)[1])); \
+ NdisWriteRegisterUlong((PULONG)(&_Cfp->CamAddressPort2), (ULONG)(((PUSHORT)Addr)[2])); \
+}
+
+
+//
+// Set up a SONIC_CAM_FRAGMENT to hold the CamEnable value
+// in it.
+//
+// Cfp is a pointer to the CAM Fragment.
+//
+// Ce is the value for CAM Enable.
+//
+
+#define SONIC_LOAD_CAM_ENABLE(_Cfp, _Ce) \
+ NdisWriteRegisterUlong((PULONG)(&(_Cfp)->CamEntryPointer), (ULONG)(_Ce))
+
+
+//
+// Set a link field to be the end of a list.
+//
+// Plink is a pointer to a link field.
+//
+
+#define SONIC_SET_END_OF_LIST(Plink) \
+ { \
+ ULONG _Data; \
+ NdisReadRegisterUlong((PULONG)(Plink), (PULONG)(&_Data)); \
+ NdisWriteRegisterUlong((PULONG)(Plink),(ULONG)(_Data | SONIC_END_OF_LIST)); \
+ }
+
+//
+// Set a link field to not be the end of a list.
+//
+// Plink is a pointer to a link field.
+//
+
+#define SONIC_REMOVE_END_OF_LIST(Plink) \
+ { \
+ ULONG _Data; \
+ NdisReadRegisterUlong((PULONG)(Plink), (PULONG)(&_Data)); \
+ NdisWriteRegisterUlong((PULONG)(Plink), (ULONG)(_Data & ~SONIC_END_OF_LIST)); \
+ }
+
+//
+// Used to set the address of a transmit descriptor fragment.
+//
+// Tdf is a pointer to a transmit descriptor fragment.
+//
+// Adr is a *physical* address.
+//
+
+#define SONIC_SET_TRANSMIT_FRAGMENT_ADDRESS(Tdf,Adr) \
+{ \
+ SONIC_PHYSICAL_ADDRESS _Adr = (Adr); \
+ PSONIC_TRANSMIT_FRAGMENT _Tdf = (Tdf); \
+ _Tdf->LowFragmentAddress = (SONIC_PHYSICAL_ADDRESS)_Adr; \
+ _Tdf->HighFragmentAddress = (SONIC_PHYSICAL_ADDRESS)(SONIC_GET_HIGH_PART_ADDRESS(_Adr)); \
+}
+
+
+//
+// Used to retrieve the address of a transmit descriptor fragment.
+// It takes advantage of the fact that we store the entire address
+// at LowFragmentAddress, not just the low bits.
+//
+// Tdf is a pointer to a transmit descriptor fragment.
+//
+#define SONIC_GET_TRANSMIT_FRAGMENT_ADDRESS(Tdf) \
+ (Tdf)->LowFragmentAddress
+
+
+//
+// Used to set the length of the transmit descriptor fragment.
+//
+// Tdf is a pointer to a transmit descriptor fragment.
+//
+// Len is the unsigned short length of the buffer.
+//
+#define SONIC_SET_TRANSMIT_FRAGMENT_LENGTH(Tdf,Len) \
+ (Tdf)->FragmentByteCount = (UINT)(Len)
+
+
+//
+// Used to put the link field on top of a transmit descriptor
+// fragment.
+//
+// Tdf is a pointer to a transmit descriptor fragment.
+//
+// Link is the link field to copy.
+//
+#define SONIC_SET_TRANSMIT_LINK(Tdf,Link) \
+ NdisWriteRegisterUlong((PULONG)(&(Tdf)->LowFragmentAddress), (ULONG)((Link) | SONIC_END_OF_LIST))
+
+
+
+//
+// Used to set the address of a receive resource.
+//
+// Rrp is a pointer to a receive resource.
+//
+// Adr is a *physical* address.
+//
+#define SONIC_SET_RECEIVE_RESOURCE_ADDRESS(Rrp,Adr) \
+{ \
+ SONIC_PHYSICAL_ADDRESS _Adr = (Adr); \
+ PSONIC_RECEIVE_RESOURCE _Rrp = (Rrp); \
+ NdisWriteRegisterUlong((PULONG)(&_Rrp->LowBufferAddress), (ULONG)(_Adr)); \
+ NdisWriteRegisterUlong((PULONG)(&_Rrp->HighBufferAddress), (ULONG)(SONIC_GET_HIGH_PART_ADDRESS(_Adr))); \
+}
+
+
+//
+// Used to retrieve the address of a receive resource.
+// It takes advantage of the fact that we store the entire address
+// at LowBufferAddress, not just the low bits.
+//
+// Rrp is a pointer to a receive resource.
+//
+#define SONIC_GET_RECEIVE_RESOURCE_ADDRESS(Rrp) \
+ (Rrp)->LowBufferAddress
+
+
+//
+// Used to set the length of a receive resource.
+//
+// Rrp is a pointer to a receive resource.
+//
+// Len is the length of the buffer.
+//
+#define SONIC_SET_RECEIVE_RESOURCE_LENGTH(Rrp,Len) \
+{ \
+ ULONG _Len = (Len); \
+ PSONIC_RECEIVE_RESOURCE _Rrp = (Rrp); \
+ NdisWriteRegisterUlong((PULONG)(&_Rrp->LowBufferWordCount), (ULONG)(((_Len) & 0x1ffff) >> 1)); \
+ NdisWriteRegisterUlong((PULONG)(&_Rrp->HighBufferWordCount), (ULONG)((_Len) >> 17)); \
+}
+
+
+#endif // _SONICHARDWARE_
+
diff --git a/private/ntos/ndis/sonic/sonicsft.h b/private/ntos/ndis/sonic/sonicsft.h
new file mode 100644
index 000000000..24967e32c
--- /dev/null
+++ b/private/ntos/ndis/sonic/sonicsft.h
@@ -0,0 +1,1039 @@
+/*++
+
+Copyright (c) 1990-1992 Microsoft Corporation
+
+Module Name:
+
+ sonicsft.h
+
+Abstract:
+
+ The main header for a SONIC NDIS driver.
+
+ The overall structure is taken from the Lance driver
+ by Tony Ercolano.
+
+Author:
+
+ Anthony V. Ercolano (tonye) creation-date 19-Jun-1990
+ Adam Barr (adamba) 20-Nov-1990
+
+Environment:
+
+ This driver is expected to work in DOS, OS2 and NT at the equivalent
+ of kernel mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Revision History:
+
+
+--*/
+
+#ifndef _SONICSFT_
+#define _SONICSFT_
+
+
+//
+// We use STATIC to define procedures that will be static in the
+// final build but which we now make extern to allow them to be
+// debugged (breakpoints can be set on them).
+//
+
+#if DEVL
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+
+//
+// This variable is used to control debug output.
+//
+
+#if DBG
+extern INT SonicDbg;
+#endif
+
+
+
+//
+// Used when registering ourselves with NDIS.
+//
+
+#define SONIC_NDIS_MAJOR_VERSION 3
+#define SONIC_NDIS_MINOR_VERSION 0
+
+
+//
+// The maximum number of bytes that we will pass to an NDIS
+// indication (since we receive packets contiguously, there is
+// no reason to limit this). This number includes header and
+// data.
+//
+
+#define SONIC_INDICATE_MAXIMUM 1514
+
+//
+// The maximum number of bytes we will pass to a loopback
+// indication (unless it all is in one buffer). This number
+// includes only data, not the header.
+//
+
+#define SONIC_LOOPBACK_MAXIMUM 208
+
+//
+// Used for parsing OIDs
+//
+
+#define OID_TYPE_MASK 0xffff0000
+#define OID_TYPE_GENERAL_OPERATIONAL 0x00010000
+#define OID_TYPE_GENERAL_STATISTICS 0x00020000
+#define OID_TYPE_802_3_OPERATIONAL 0x01010000
+#define OID_TYPE_802_3_STATISTICS 0x01020000
+
+#define OID_REQUIRED_MASK 0x0000ff00
+#define OID_REQUIRED_MANDATORY 0x00000100
+#define OID_REQUIRED_OPTIONAL 0x00000200
+
+#define OID_INDEX_MASK 0x000000ff
+
+//
+// Indexes in the GeneralMandatory array.
+//
+
+#define GM_TRANSMIT_GOOD 0x00
+#define GM_RECEIVE_GOOD 0x01
+#define GM_TRANSMIT_BAD 0x02
+#define GM_RECEIVE_BAD 0x03
+#define GM_RECEIVE_NO_BUFFER 0x04
+#define GM_ARRAY_SIZE 0x05
+
+//
+// Indexes in the GeneralOptional array. There are
+// two sections, the ones up to COUNT_ARRAY_SIZE
+// have entries for number (4 bytes) and number of
+// bytes (8 bytes), the rest are a normal array.
+//
+
+#define GO_DIRECTED_TRANSMITS 0x00
+#define GO_MULTICAST_TRANSMITS 0x01
+#define GO_BROADCAST_TRANSMITS 0x02
+#define GO_DIRECTED_RECEIVES 0x03
+#define GO_MULTICAST_RECEIVES 0x04
+#define GO_BROADCAST_RECEIVES 0x05
+#define GO_COUNT_ARRAY_SIZE 0x06
+
+#define GO_ARRAY_START 0x0C
+#define GO_RECEIVE_CRC 0x0C
+#define GO_TRANSMIT_QUEUE_LENGTH 0x0D
+#define GO_ARRAY_SIZE 0x0E
+
+//
+// Indexes in the MediaMandatory array.
+//
+
+#define MM_RECEIVE_ERROR_ALIGNMENT 0x00
+#define MM_TRANSMIT_ONE_COLLISION 0x01
+#define MM_TRANSMIT_MORE_COLLISIONS 0x02
+#define MM_ARRAY_SIZE 0x03
+
+//
+// Indexes in the MediaOptional array.
+//
+
+#define MO_TRANSMIT_DEFERRED 0x00
+#define MO_TRANSMIT_MAX_COLLISIONS 0x01
+#define MO_RECEIVE_OVERRUN 0x02
+#define MO_TRANSMIT_UNDERRUN 0x03
+#define MO_TRANSMIT_HEARTBEAT_FAILURE 0x04
+#define MO_TRANSMIT_TIMES_CRS_LOST 0x05
+#define MO_TRANSMIT_LATE_COLLISIONS 0x06
+#define MO_ARRAY_SIZE 0x07
+
+
+
+//
+// Macros used for memory allocation and deallocation.
+//
+// Note that for regular memory we put no limit on the physical
+// address, but for contiguous and noncached we limit it to
+// 32 bits since that is all the card can handle (presumably
+// such memory will be DMAed to/from by the card).
+//
+
+#define SONIC_ALLOC_MEMORY(_Status, _Address, _Length) \
+ { \
+ NDIS_PHYSICAL_ADDRESS Temp = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1); \
+ *(_Status) = NdisAllocateMemory( \
+ (PVOID)(_Address), \
+ (_Length), \
+ 0, \
+ Temp \
+ ); \
+ }
+
+#define SONIC_FREE_MEMORY(_Address, _Length) \
+ NdisFreeMemory( \
+ (PVOID)(_Address), \
+ (_Length), \
+ 0 \
+ )
+
+
+#define SONIC_ALLOC_CONTIGUOUS_MEMORY(_Status, _Address, _Length) \
+ { \
+ NDIS_PHYSICAL_ADDRESS Temp = NDIS_PHYSICAL_ADDRESS_CONST(-1, 0); \
+ *(_Status) = NdisAllocateMemory( \
+ (PVOID)(_Address), \
+ (_Length), \
+ NDIS_MEMORY_CONTIGUOUS, \
+ Temp \
+ ); \
+ }
+
+#define SONIC_FREE_CONTIGUOUS_MEMORY(_Address, _Length) \
+ NdisFreeMemory( \
+ (PVOID)(_Address), \
+ (_Length), \
+ NDIS_MEMORY_CONTIGUOUS \
+ )
+
+
+#define SONIC_ALLOC_NONCACHED_MEMORY(_Status, _Address, _Length) \
+ { \
+ NDIS_PHYSICAL_ADDRESS Temp = NDIS_PHYSICAL_ADDRESS_CONST(-1, 0); \
+ *(_Status) = NdisAllocateMemory( \
+ (PVOID)(_Address), \
+ (_Length), \
+ NDIS_MEMORY_CONTIGUOUS | NDIS_MEMORY_NONCACHED, \
+ Temp \
+ ); \
+ }
+
+#define SONIC_FREE_NONCACHED_MEMORY(_Address, _Length) \
+ NdisFreeMemory( \
+ (PVOID)(_Address), \
+ (_Length), \
+ NDIS_MEMORY_CONTIGUOUS | NDIS_MEMORY_NONCACHED \
+ )
+
+
+
+//
+// Macros to move and zero memory.
+//
+
+#define SONIC_MOVE_MEMORY(Destination,Source,Length) NdisMoveMemory(Destination,Source,Length)
+#define SONIC_ZERO_MEMORY(Destination,Length) NdisZeroMemory(Destination,Length)
+
+
+//
+// Used to record the 8-byte counters.
+//
+
+typedef struct _SONIC_LARGE_INTEGER {
+ ULONG LowPart;
+ ULONG HighPart;
+} SONIC_LARGE_INTEGER, *PSONIC_LARGE_INTEGER;
+
+//
+// This initializes an 8-byte counter.
+//
+
+#define SonicZeroLargeInteger(LargeInteger) \
+{ \
+ LargeInteger.LowPart = 0L;\
+ LargeInteger.HighPart = 0L; \
+}
+
+//
+// This adds a longword to an 8-byte counter.
+//
+
+#define SonicAddUlongToLargeInteger(LargeInteger, Ulong) \
+{ \
+ PSONIC_LARGE_INTEGER TmpLarge = (LargeInteger); \
+ TmpLarge->LowPart += (ULONG)Ulong; \
+ if (TmpLarge->LowPart < (ULONG)Ulong) { \
+ ++TmpLarge->HighPart; \
+ } \
+}
+
+
+
+//
+// This flushes a buffer for write.
+//
+
+#define SONIC_FLUSH_WRITE_BUFFER(Buffer) \
+ NdisFlushBuffer( \
+ Buffer, \
+ TRUE \
+ )
+
+
+//
+// This record type is used to store sonic global data.
+//
+
+typedef struct _SONIC_DRIVER {
+
+ //
+ // The handle returned by NdisMInitializeWrapper.
+ //
+
+ NDIS_HANDLE WrapperHandle;
+
+} SONIC_DRIVER, *PSONIC_DRIVER;
+
+
+//
+// This identifies the type of the packet for quick reference
+// in the SONIC_PACKET_RESERVED.PacketType field.
+//
+
+#define SONIC_DIRECTED 1
+#define SONIC_MULTICAST 2
+#define SONIC_BROADCAST 3
+#define SONIC_LOOPBACK 4
+
+
+//
+// This record type is inserted into the MiniportReserved portion
+// of the packet header.
+//
+typedef struct _SONIC_PACKET_RESERVED {
+
+ //
+ // Points to the next packet in the chain of queued packets
+ // being allocated, or waiting for the finish of transmission.
+ //
+ // The packet will either be on the stage list for allocation,
+ // or on an adapter wide doubly linked list (see below) for
+ // post transmission processing.
+ //
+ PNDIS_PACKET Next;
+
+ //
+ // If TRUE then the packet caused an adapter buffer to
+ // be allocated.
+ //
+ BOOLEAN UsedSonicBuffer;
+
+ //
+ // If the previous field was TRUE then this gives the
+ // index into the array of adapter buffer descriptors that
+ // contains the old packet information.
+ //
+ UCHAR SonicBuffersIndex;
+
+ //
+ // Gives the index into the ring to packet structure as well
+ // as the ring descriptors.
+ //
+ USHORT DescriptorIndex;
+
+} SONIC_PACKET_RESERVED,*PSONIC_PACKET_RESERVED;
+
+
+//
+// This macro will return a pointer to the sonic reserved portion
+// of a packet given a pointer to a packet.
+//
+#define PSONIC_RESERVED_FROM_PACKET(Packet) \
+ ((PSONIC_PACKET_RESERVED)((PVOID)((Packet)->MiniportReserved)))
+
+
+//
+// The return code from a multicast operation.
+//
+typedef enum { CAM_LOADED, CAM_NOT_LOADED } MULTICAST_STATUS;
+
+
+//
+// This structure is used to map entries in the ring descriptors
+// back to the packets from which the data in the ring descriptor
+// originated.
+//
+
+typedef struct _SONIC_DESCRIPTOR_TO_PACKET {
+
+ //
+ // Points to the packet from which data is being transmitted
+ // through this ring entry.
+ //
+ PNDIS_PACKET OwningPacket;
+
+ //
+ // Location of our link field.
+ //
+ SONIC_PHYSICAL_ADDRESS * LinkPointer;
+
+ //
+ // Location of the previous link field.
+ //
+ SONIC_PHYSICAL_ADDRESS * PrevLinkPointer;
+
+ //
+ // When a packet is submitted to the hardware we record
+ // here whether it used adapter buffers and if so, the buffer
+ // index.
+ //
+ UINT SonicBuffersIndex;
+ BOOLEAN UsedSonicBuffer;
+
+} SONIC_DESCRIPTOR_TO_PACKET,*PSONIC_DESCRIPTOR_TO_PACKET;
+
+
+//
+// If an ndis packet does not meet the hardware contraints then
+// an adapter buffer will be allocated. Enough data will be copied
+// out of the ndis packet so that by using a combination of the
+// adapter buffer and remaining ndis buffers the hardware
+// constraints are satisfied.
+//
+// In the SONIC_ADAPTER structure three threaded lists are kept in
+// one array. One points to a list of SONIC_BUFFER_DESCRIPTORS
+// that point to small adapter buffers. Another is for medium sized
+// buffers and the last for full sized (large) buffers.
+//
+// The allocation is controlled via a free list head and
+// the free lists are "threaded" by a field in the adapter buffer
+// descriptor.
+//
+
+typedef struct _SONIC_BUFFER_DESCRIPTOR {
+
+ //
+ // A Physical pointer to a small, medium, or large buffer.
+ //
+ NDIS_PHYSICAL_ADDRESS PhysicalSonicBuffer;
+
+ //
+ // A virtual pointer to a small, medium, or large buffer.
+ //
+ PVOID VirtualSonicBuffer;
+
+ //
+ // This is used to flush the buffer when it is used.
+ //
+ PNDIS_BUFFER FlushBuffer;
+
+ //
+ // Threads the elements of an array of these descriptors into
+ // a free list. -1 implies no more entries in the list.
+ //
+ INT Next;
+
+ //
+ // Holds the length of data placed into the buffer. This
+ // can (and likely will) be less that the actual buffers
+ // length.
+ //
+ UINT DataLength;
+
+} SONIC_BUFFER_DESCRIPTOR,*PSONIC_BUFFER_DESCRIPTOR;
+
+
+//
+// This is the basic structure that defines the state of an
+// adapter. There is one of these allocate per adapter that
+// the sonic driver supports.
+//
+
+typedef struct _SONIC_ADAPTER {
+
+ //
+ // Will be true the first time that the hardware is initialized
+ // by the driver initialization.
+ //
+ BOOLEAN FirstInitialization;
+
+ //
+ // The type of the adapter; current supported values are:
+ //
+ // 1: EISA 9010E/B card from National Semiconductor
+ // 2: Sonic chip on the MIPS R4000 motherbaord.
+ //
+ UCHAR AdapterType;
+
+ //
+ // TRUE if the permanent address is valid. On some cards the
+ // permanent address is read by SonicHardwareGetDetails;
+ // if not, it is read later by SonicHardwareGetAddress.
+ //
+ BOOLEAN PermanentAddressValid;
+
+ //
+ // The burned-in network address from the hardware.
+ //
+ CHAR PermanentNetworkAddress[ETH_LENGTH_OF_ADDRESS];
+
+ //
+ // The current network address from the hardware.
+ //
+ CHAR CurrentNetworkAddress[ETH_LENGTH_OF_ADDRESS];
+
+ //
+ // This is the buffer pool used to allocate flush buffers
+ // out of.
+ //
+ NDIS_HANDLE FlushBufferPoolHandle;
+
+ //
+ // Holds the interrupt object for this adapter.
+ //
+ NDIS_MINIPORT_INTERRUPT Interrupt;
+
+ //
+ // TRUE if the adapter is latched, FALSE for level-sensitive.
+ //
+ BOOLEAN InterruptLatched;
+
+ //
+ // Holds a value for simulating an interrupt.
+ //
+ USHORT SimulatedIsr;
+
+ //
+ // The current value to put in the Receive Control Register.
+ //
+ USHORT ReceiveControlRegister;
+
+ //
+ // The value that the Data Configuration Register should be
+ // initialized to.
+ //
+ USHORT DataConfigurationRegister;
+
+ //
+ // Have we receive an unacknowledged Receive Buffers
+ // Exhausted interrupt.
+ //
+ BOOLEAN ReceiveBuffersExhausted;
+
+ //
+ // Have we receive an unacknowledged Receive Descriptors
+ // Exhausted interrupt.
+ //
+ BOOLEAN ReceiveDescriptorsExhausted;
+
+ //
+ // Flag used for checking if a transmit interrupt was dropped.
+ //
+ BOOLEAN WakeUpTimeout;
+
+ //
+ // Used to limit the number of error log entries written.
+ //
+ UCHAR WakeUpErrorCount;
+
+ //
+ // Location of the beginning of the SONIC ports.
+ //
+ ULONG SonicPortAddress;
+
+ //
+ // Number of ports in use
+ //
+ UINT NumberOfPorts;
+
+ //
+ // Hardware address of the first port.
+ //
+ UINT InitialPort;
+
+ //
+ // The number of bits that port numbers need to be shifted left
+ // before adding them to PortAddress (1 for 16-bit ports, 2
+ // for 32-bit ports).
+ //
+ UINT PortShift;
+
+ //
+ // The virtual address of the blank buffer used for padding.
+ //
+ PUCHAR BlankBuffer;
+
+ //
+ // The Physical address of the blank buffer used for padding.
+ //
+ NDIS_PHYSICAL_ADDRESS BlankBufferAddress;
+
+ //
+ // Handle given by NDIS when the adapter was registered.
+ //
+ NDIS_HANDLE MiniportAdapterHandle;
+
+ //
+ // The current packet filter.
+ //
+ UINT CurrentPacketFilter;
+
+ //
+ // The value of the bits in CamEnable, except for
+ // the first one (which is for our network address);
+ // as opposed to the value stored in the real CamEnable,
+ // which may have some bits off if multicast addresses
+ // are not included in the current packet filter.
+ //
+ UINT MulticastCamEnableBits;
+
+ //
+ // The number of transmit descriptors.
+ //
+ UINT NumberOfTransmitDescriptors;
+
+ //
+ // The number of receive buffers
+ //
+ UINT NumberOfReceiveBuffers;
+
+ //
+ // The number of receive descriptors
+ //
+ UINT NumberOfReceiveDescriptors;
+
+ //
+ // Pointer to the transmit descriptors (this is
+ // allocated to be of size NumberOfTransmitDescriptors).
+ //
+ PSONIC_TRANSMIT_DESCRIPTOR TransmitDescriptorArea;
+
+ //
+ // The physical address of the transmit descriptor area.
+ //
+ NDIS_PHYSICAL_ADDRESS TransmitDescriptorAreaPhysical;
+
+ //
+ // Pointer to the last transmit descriptor.
+ //
+ PSONIC_TRANSMIT_DESCRIPTOR LastTransmitDescriptor;
+
+ //
+ // Counter that records the number of transmit rings currently
+ // available for allocation.
+ //
+ UINT NumberOfAvailableDescriptors;
+
+ //
+ // This is used to determine whether to use the programmable
+ // interrupt on a packet or not.
+ //
+ UINT PacketsSinceLastInterrupt;
+
+ //
+ // Pointer to transmit descriptor ring entry that is the
+ // first ring entry available for allocation of transmit
+ // buffers.
+ //
+ // Can only be accessed when the adapter lock
+ // is held.
+ //
+ PSONIC_TRANSMIT_DESCRIPTOR AllocateableDescriptor;
+
+ //
+ // Pointer to a transmit descriptor ring entry that is the
+ // first ring entry that the MAC currently has made available
+ // for transmission.
+ //
+ // Can only be accessed when the adapter lock
+ // is held.
+ //
+ PSONIC_TRANSMIT_DESCRIPTOR TransmittingDescriptor;
+
+ //
+ // Pointer to the first packet that has been allocated to
+ // a transmit packet but has not yet been relinquished to
+ // the hardware. We need this pointer to keep the transmit
+ // post processing from running into a packet that has not
+ // been transmitted.
+ //
+ PSONIC_TRANSMIT_DESCRIPTOR FirstUncommittedDescriptor;
+
+ //
+ // Pointer to an array of structs that map transmit ring entries
+ // back to a packet (this is allocated to be of size
+ // NumberOfTransmitDescriptors).
+ //
+ PSONIC_DESCRIPTOR_TO_PACKET DescriptorToPacket;
+
+ //
+ // Pointer to the receive resource area (this is
+ // allocated to be of size NumberofReceiveBuffers).
+ //
+ PSONIC_RECEIVE_RESOURCE ReceiveResourceArea;
+
+ //
+ // The physical address of ReceiveResourceArea.
+ //
+ NDIS_PHYSICAL_ADDRESS ReceiveResourceAreaPhysical;
+
+ //
+ // Pointer to the array holding the receive buffers (this
+ // is allocated to be of size NumberofReceiveBuffers).
+ //
+
+ PVOID * ReceiveBufferArea;
+
+ PNDIS_BUFFER * ReceiveNdisBufferArea;
+
+ //
+ // The RBA which we are currently taking packets out of
+ // (will be one of the entries in the ReceiveBufferArea
+ // array).
+ //
+ UINT CurrentReceiveBufferIndex;
+
+ //
+ // Pointer to the receive descriptor area
+ // (this is allocated to be of size NumberOfReceiveDescriptors).
+ //
+ PSONIC_RECEIVE_DESCRIPTOR ReceiveDescriptorArea;
+
+ //
+ // The physical address of ReceiveDescriptorArea
+ //
+ NDIS_PHYSICAL_ADDRESS ReceiveDescriptorAreaPhysical;
+
+ //
+ // The last receive descriptor in the area.
+ //
+ PSONIC_RECEIVE_DESCRIPTOR LastReceiveDescriptor;
+
+ //
+ // The index receive descriptor we should look at next (will be
+ // one of the entries in ReceiveDescriptorArea).
+ //
+ UINT CurrentReceiveDescriptorIndex;
+
+ //
+ // Pointer to the CAM descriptor area. This will be
+ // located directly after the receive resource area,
+ // the separate pointer is for convenience.
+ //
+ PSONIC_CAM_DESCRIPTOR_AREA CamDescriptorArea;
+
+ //
+ // The physical address corresponding to CamDescriptorArea.
+ // This is stored as a 4-byte address since it is just
+ // a fixed offset from ReceiveResourceAreaPhysical and
+ // is not allocated with NdisAllocateSharedMemory.
+ //
+ SONIC_PHYSICAL_ADDRESS CamDescriptorAreaPhysical;
+
+ //
+ // This is used to flush the CAM descriptor area.
+ //
+ PNDIS_BUFFER CamDescriptorAreaFlushBuffer;
+
+ //
+ // The last entry in the CAM that is used.
+ //
+ UINT CamDescriptorAreaSize;
+
+ //
+ // An bitmask showing which entries in the CAM are
+ // used or reserved for use.
+ //
+ UINT CamDescriptorsUsed;
+
+ //
+ // Pointer to the first transmitting packet that is actually
+ // sending.
+ //
+ PNDIS_PACKET FirstFinishTransmit;
+
+ //
+ // Pointer to the last transmitting packet that is actually
+ // sending.
+ //
+ PNDIS_PACKET LastFinishTransmit;
+
+ //
+ // Listheads for the adapters buffers. If the list
+ // head is equal to -1 then there are no free elements
+ // on the list.
+ //
+ // The list heads must only be accessed when the
+ // adapter lock is held.
+ //
+ // Note that the listhead at index 0 will always be -1.
+ //
+ INT SonicBufferListHeads[4];
+
+ //
+ // Pointers to an array of adapter buffer descriptors.
+ // The array will actually be threaded together by
+ // three free lists. The lists will be for small,
+ // medium and full sized packets.
+ //
+ PSONIC_BUFFER_DESCRIPTOR SonicBuffers;
+
+ //
+ // This holds the actual memory used by the small
+ // sonic buffers (so that it can be a single piece
+ // of memory and therefore only use a single physical
+ // address.
+ //
+ PVOID SmallSonicBuffers;
+
+ //
+ // This holds the memory for the medium sonic buffers.
+ //
+ PVOID MediumSonicBuffers;
+
+ //
+ // Flag that when enabled lets routines know that a reset
+ // is in progress, for the purposes of blocking other
+ // requests (except other resets).
+ //
+ BOOLEAN ResetInProgress;
+
+ //
+ // Has there been a hardware failure
+ //
+ BOOLEAN HardwareFailure;
+
+ //
+ // Count how often we log an error from finding a packet in
+ // the wrong RBA.
+ //
+
+ USHORT WrongRbaErrorLogCount;
+
+ //
+ // These hold adapter statistics.
+ //
+ ULONG GeneralMandatory[GM_ARRAY_SIZE];
+ SONIC_LARGE_INTEGER GeneralOptionalByteCount[GO_COUNT_ARRAY_SIZE];
+ ULONG GeneralOptionalFrameCount[GO_COUNT_ARRAY_SIZE];
+ ULONG GeneralOptional[GO_ARRAY_SIZE - GO_ARRAY_START];
+ ULONG MediaMandatory[MM_ARRAY_SIZE];
+ ULONG MediaOptional[MO_ARRAY_SIZE];
+
+ //
+ // For indicating loopback packets.
+ //
+
+ UCHAR Loopback[SONIC_LOOPBACK_MAXIMUM];
+
+} SONIC_ADAPTER,*PSONIC_ADAPTER;
+
+
+//
+// Given a MacContextHandle return the PSONIC_ADAPTER
+// it represents.
+//
+
+#define PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(Handle) \
+ ((PSONIC_ADAPTER)((PVOID)(Handle)))
+
+
+//
+// procedures which do error logging
+//
+
+typedef enum _SONIC_PROC_ID{
+ registerAdapter,
+ openAdapter,
+ hardwareDetails,
+ handleDeferred,
+ processReceiveInterrupts
+} SONIC_PROC_ID;
+
+
+//
+// Error log values
+//
+
+#define SONIC_ERRMSG_INIT_INTERRUPT (ULONG)0x01
+#define SONIC_ERRMSG_CREATE_FILTER (ULONG)0x02
+#define SONIC_ERRMSG_ALLOC_MEMORY (ULONG)0x03
+#define SONIC_ERRMSG_REGISTER_ADAPTER (ULONG)0x04
+#define SONIC_ERRMSG_ALLOC_DEVICE_NAME (ULONG)0x05
+#define SONIC_ERRMSG_ALLOC_ADAPTER (ULONG)0x06
+#define SONIC_ERRMSG_INITIAL_INIT (ULONG)0x07
+#define SONIC_ERRMSG_OPEN_DB (ULONG)0x08
+#define SONIC_ERRMSG_ALLOC_OPEN (ULONG)0x09
+#define SONIC_ERRMSG_HARDWARE_ADDRESS (ULONG)0x0A
+#define SONIC_ERRMSG_WRONG_RBA (ULONG)0x0B
+
+
+
+
+//
+// Definitions of sonic functions which are used by multiple
+// source files.
+//
+
+
+//
+// alloc.c
+//
+
+extern
+BOOLEAN
+AllocateAdapterMemory(
+ IN PSONIC_ADAPTER Adapter
+ );
+
+extern
+VOID
+DeleteAdapterMemory(
+ IN PSONIC_ADAPTER Adapter
+ );
+
+
+//
+// interrup.c
+//
+
+extern
+VOID
+SonicDisableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+extern
+VOID
+SonicEnableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+extern
+VOID
+SonicHandleInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+extern
+VOID
+SonicInterruptService(
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueDpc,
+ IN PVOID Context
+ );
+
+extern
+BOOLEAN
+SonicCheckForHang(
+ IN PVOID MiniportAdapterContext
+ );
+
+//
+// request.c
+//
+
+extern
+NDIS_STATUS
+SonicQueryInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+ );
+
+extern
+NDIS_STATUS
+SonicSetInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ );
+
+extern
+NDIS_STATUS
+SonicChangeClass(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+extern
+NDIS_STATUS
+SonicChangeAddresses(
+ IN UINT OldAddressCount,
+ IN CHAR OldAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN UINT NewAddressCount,
+ IN CHAR NewAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+//
+// send.c
+//
+
+extern
+NDIS_STATUS
+SonicSend(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_PACKET Packet,
+ IN UINT SendFlags
+ );
+
+//
+// sonic.c
+//
+
+extern
+VOID
+SonicStartChip(
+ IN PSONIC_ADAPTER Adapter
+ );
+
+extern
+VOID
+StartAdapterReset(
+ IN PSONIC_ADAPTER Adapter
+ );
+
+extern
+VOID
+SetupForReset(
+ IN PSONIC_ADAPTER Adapter
+ );
+
+extern
+VOID
+SonicStartCamReload(
+ IN PSONIC_ADAPTER Adapter
+ );
+
+extern
+NDIS_STATUS
+SonicInitialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE ConfigurationHandle
+ );
+//
+// transfer.c
+//
+
+extern
+NDIS_STATUS
+SonicTransferData(
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+ );
+
+#endif // _SONICSFT_
diff --git a/private/ntos/ndis/sonic/sources b/private/ntos/ndis/sonic/sources
new file mode 100644
index 000000000..3f3e59baa
--- /dev/null
+++ b/private/ntos/ndis/sonic/sources
@@ -0,0 +1,61 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis2
+
+TARGETNAME=sonic
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER
+
+INCLUDES=..\inc;..\..\inc
+
+SOURCES=
+
+i386_SOURCES=alloc.c \
+ interrup.c \
+ request.c \
+ send.c \
+ sonic.c \
+ sonic.rc \
+ transfer.c
+
+MIPS_SOURCES=alloc.c \
+ interrup.c \
+ request.c \
+ send.c \
+ sonic.c \
+ sonic.rc \
+ transfer.c
+
+ALPHA_SOURCES=
+
+RELATIVE_DEPTH=..\..
+
+MSC_WARNING_LEVEL=/W3 /WX
+
diff --git a/private/ntos/ndis/sonic/transfer.c b/private/ntos/ndis/sonic/transfer.c
new file mode 100644
index 000000000..403e51ee8
--- /dev/null
+++ b/private/ntos/ndis/sonic/transfer.c
@@ -0,0 +1,247 @@
+/*++
+
+Copyright (c) 1990-1992 Microsoft Corporation
+
+Module Name:
+
+ transfer.c
+
+Abstract:
+
+ This file contains the code to implement the MacTransferData
+ API for the NDIS 3.0 miniport interface.
+
+Author:
+
+ Anthony V. Ercolano (Tonye) 12-Sept-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent.
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+
+#include <sonichrd.h>
+#include <sonicsft.h>
+
+
+extern
+NDIS_STATUS
+SonicTransferData(
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+ )
+
+/*++
+
+Routine Description:
+
+ A protocol calls the SonicTransferData request (indirectly via
+ NdisTransferData) from within its Receive event handler
+ to instruct the driver to copy the contents of the received packet
+ a specified paqcket buffer.
+
+Arguments:
+
+ MiniportAdapterContext - Context registered with the wrapper, really
+ a pointer to the adapter.
+
+ MiniportReceiveContext - The context value passed by the driver on its call
+ to NdisMEthIndicateReceive. The driver can use this value to determine
+ which packet, on which adapter, is being received.
+
+ ByteOffset - An unsigned integer specifying the offset within the
+ received packet at which the copy is to begin. If the entire packet
+ is to be copied, ByteOffset must be zero.
+
+ BytesToTransfer - An unsigned integer specifying the number of bytes
+ to copy. It is legal to transfer zero bytes; this has no effect. If
+ the sum of ByteOffset and BytesToTransfer is greater than the size
+ of the received packet, then the remainder of the packet (starting from
+ ByteOffset) is transferred, and the trailing portion of the receive
+ buffer is not modified.
+
+ Packet - A pointer to a descriptor for the packet storage into which
+ the MAC is to copy the received packet.
+
+ BytesTransfered - A pointer to an unsigned integer. The MAC writes
+ the actual number of bytes transferred into this location. This value
+ is not valid if the return status is STATUS_PENDING.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+
+{
+ //
+ // Buffer is the buffer to copy from.
+ //
+ PCHAR Buffer = (PCHAR)MiniportReceiveContext + ByteOffset;
+
+ //
+ // Holds the count of the number of ndis buffers comprising the
+ // destination packet.
+ //
+ UINT DestinationBufferCount;
+
+ //
+ // Points to the buffer into which we are putting data.
+ //
+ PNDIS_BUFFER DestinationCurrentBuffer;
+
+ //
+ // Points to the location in Buffer from which we are extracting data.
+ //
+ PUCHAR SourceCurrentAddress;
+
+ //
+ // Holds the virtual address of the current destination buffer.
+ //
+ PVOID DestinationVirtualAddress;
+
+ //
+ // Holds the length of the current destination buffer.
+ //
+ UINT DestinationCurrentLength;
+
+ //
+ // Keep a local variable of BytesTransferred so we aren't referencing
+ // through a pointer.
+ //
+ UINT LocalBytesTransferred = 0;
+
+ //
+ // MiniportAdapterContext is not referenced.
+ //
+ MiniportAdapterContext;
+
+ //
+ // Take care of boundary condition of zero length copy.
+ //
+
+ if (BytesToTransfer == 0) {
+ *BytesTransferred = 0;
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ //
+ // Get the first buffer of the destination.
+ //
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ &DestinationBufferCount,
+ &DestinationCurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet.
+ //
+
+ if (DestinationBufferCount == 0) {
+ *BytesTransferred = 0;
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+
+ //
+ // Set up the source address.
+ //
+
+ SourceCurrentAddress = Buffer;
+
+
+ while (LocalBytesTransferred < BytesToTransfer) {
+
+ //
+ // Check to see whether we've exhausted the current destination
+ // buffer. If so, move onto the next one.
+ //
+
+ if (DestinationCurrentLength == 0) {
+
+ NdisGetNextBuffer(
+ DestinationCurrentBuffer,
+ &DestinationCurrentBuffer
+ );
+
+ if (DestinationCurrentBuffer == NULL) {
+
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.)
+ //
+
+ break;
+
+ }
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+
+ continue;
+
+ }
+
+ //
+ // Copy the data.
+ //
+
+ {
+
+ //
+ // Holds the amount of data to move.
+ //
+ UINT AmountToMove;
+
+ //
+ // Holds the amount desired remaining.
+ //
+ UINT Remaining = BytesToTransfer - LocalBytesTransferred;
+
+
+ AmountToMove = DestinationCurrentLength;
+
+ AmountToMove = ((Remaining < AmountToMove)?
+ (Remaining):(AmountToMove));
+
+ SONIC_MOVE_MEMORY(
+ DestinationVirtualAddress,
+ SourceCurrentAddress,
+ AmountToMove
+ );
+
+ SourceCurrentAddress += AmountToMove;
+ LocalBytesTransferred += AmountToMove;
+ DestinationCurrentLength -= AmountToMove;
+
+ }
+
+ }
+
+ *BytesTransferred = LocalBytesTransferred;
+ return NDIS_STATUS_SUCCESS;
+}
diff --git a/private/ntos/ndis/testmac/makefile b/private/ntos/ndis/testmac/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/testmac/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/testmac/sources b/private/ntos/ndis/testmac/sources
new file mode 100644
index 000000000..e54919b71
--- /dev/null
+++ b/private/ntos/ndis/testmac/sources
@@ -0,0 +1,41 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=testmac
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+INCLUDES=..\..\inc
+
+SOURCES=testmac.c
+
+RELATIVE_DEPTH=..\..
+
+MSC_WARNING_LEVEL=/W3 /WX
+
diff --git a/private/ntos/ndis/testmac/testmac.c b/private/ntos/ndis/testmac/testmac.c
new file mode 100644
index 000000000..ad689ca82
--- /dev/null
+++ b/private/ntos/ndis/testmac/testmac.c
@@ -0,0 +1,1236 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ testmac.c
+
+Abstract:
+
+ simple MAC to test the NDIS wrapper.
+ Mostly taken from the Elnkii code spec.
+
+Author:
+
+ Adam Barr (adamba) 14-Jul-1990
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+
+--*/
+
+#include <ntos.h>
+
+#include <ndis.h>
+
+#include "testmac.h"
+
+
+/*++
+
+Routine Description:
+
+ This is the initialization routine for the driver. It is invoked once
+ when the driver is loaded into the system. Its job is to initialize all
+ the structures which will be used by the FSD.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+Return Value:
+
+ None.
+
+--*/
+
+
+
+static
+NTSTATUS
+TestMacDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the main dispatch routine for the FSD. This routine
+ accepts an I/O Request Packet (IRP) and either performs the request
+ itself, or it passes it to the FSP for processing.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+
+{
+ KIRQL oldIrql;
+
+ DeviceObject;
+
+ KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
+ IoCompleteRequest( Irp, 0 );
+ KeLowerIrql( oldIrql );
+
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+
+
+
+MAC_BLOCK GlobalMacBlock;
+UCHAR * AdapterNames[] = {
+ "\\Device\\TestMac0",
+ "\\Device\\TestMac1",
+ "\\Device\\TestMac2"
+ };
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject
+ )
+{
+ PMAC_BLOCK NewMacP = &GlobalMacBlock;
+ NDIS_STATUS Status;
+ CLONG i;
+ STRING AdapterName;
+
+ // Initialize the driver object with this driver's entry points.
+ for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
+ DriverObject->MajorFunction[i] = TestMacDispatch;
+ }
+
+ // Initialize the wrapper
+ NdisInitializeWrapper( (PVOID)DriverObject, NULL, NULL);
+
+ NewMacP->Debug = FALSE;
+
+ // set up driver object, etc.
+ NewMacP->DriverObject = DriverObject;
+ KeInitializePowerStatus(&NewMacP->PowerStatus);
+ NewMacP->PowerBoolean = FALSE;
+ KeInsertQueuePowerStatus(&NewMacP->PowerStatus, &NewMacP->PowerBoolean);
+ NdisAllocateSpinLock(&NewMacP->SpinLock);
+
+ NewMacP->NumAdapters = 0;
+ NewMacP->AdapterQueue = (PADAPTER_BLOCK)NULL;
+
+ // get ready to call NdisRegisterMac
+ NewMacP->MacCharacteristics.MajorNdisVersion = 3;
+ NewMacP->MacCharacteristics.MinorNdisVersion = 0;
+ NewMacP->MacCharacteristics.Reserved = 0;
+ NewMacP->MacCharacteristics.OpenAdapterHandler = TestMacOpenAdapter;
+ NewMacP->MacCharacteristics.CloseAdapterHandler = TestMacCloseAdapter;
+ NewMacP->MacCharacteristics.SetPacketFilterHandler = TestMacSetPacketFilter;
+ NewMacP->MacCharacteristics.AddMulticastAddressHandler =
+ TestMacAddMulticastAddress;
+ NewMacP->MacCharacteristics.DeleteMulticastAddressHandler =
+ TestMacDeleteMulticastAddress;
+ NewMacP->MacCharacteristics.SendHandler = TestMacSend;
+ NewMacP->MacCharacteristics.TransferDataHandler = TestMacTransferData;
+ NewMacP->MacCharacteristics.QueryInformationHandler =
+ TestMacQueryInformation;
+ NewMacP->MacCharacteristics.SetInformationHandler = TestMacSetInformation;
+ NewMacP->MacCharacteristics.ResetHandler = TestMacReset;
+ NewMacP->MacCharacteristics.TestHandler = TestMacTest;
+ NewMacP->MacCharacteristics.NameLength = sizeof("TESTMAC");
+ RtlMoveMemory(NewMacP->MacCharacteristics.Name, "TESTMAC", 8);
+
+ NdisRegisterMac(&Status,
+ &NewMacP->NdisMacHandle,
+ &NewMacP->MacCharacteristics,
+ sizeof(NewMacP->MacCharacteristics)+8);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ // NdisRegisterMac failed
+ if (NewMacP->Debug)
+ DbgPrint(" [ RegisterMac FAILURE %d ] ", Status);
+ KeRemoveQueuePowerStatus(&NewMacP->PowerStatus);
+ NdisFreeSpinLock(&NewMacP->SpinLock);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ for (i=0; i<3; i++) {
+ RtlInitString(&AdapterName, AdapterNames[i]);
+ if (TestMacRegisterAdapter(&AdapterName, i) != NDIS_STATUS_SUCCESS)
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+//
+// MacRegisterAdapter
+//
+// NT will call this function when a new adapter should be opened
+//
+// - allocates space for adapter block and open blocks
+// - initializes the open block
+// - calls NdisRegisterAdapter
+//
+
+static
+NDIS_STATUS
+TestMacRegisterAdapter(
+ IN PSTRING AdapterName,
+ IN UINT AdapterNumber
+ )
+{
+ PADAPTER_BLOCK NewAdaptP;
+ NDIS_STATUS Status;
+ UINT i;
+
+ // OK to allocate memory now
+ NewAdaptP = (PADAPTER_BLOCK)AllocPhys(sizeof(ADAPTER_BLOCK));
+ if (NewAdaptP == (PADAPTER_BLOCK)NULL)
+ return NDIS_STATUS_FAILURE;
+
+ NewAdaptP->AdapterName = AdapterName;
+ NewAdaptP->AdapterNumber = AdapterNumber;
+
+ NewAdaptP->MaxOpens = 4;
+ NewAdaptP->MulticastListMax = 8;
+ NewAdaptP->MulticastDontModify = FALSE;
+
+ // need to get this memory now
+ NewAdaptP->OpenBlocks =
+ (POPEN_BLOCK)AllocPhys(sizeof(OPEN_BLOCK) * NewAdaptP->MaxOpens);
+ if (NewAdaptP->OpenBlocks == (POPEN_BLOCK)NULL)
+ {
+ FreePhys((PVOID)NewAdaptP);
+ return NDIS_STATUS_FAILURE;
+ }
+
+ ++(NewAdaptP->MulticastListMax); // to allow for broadcast address
+ // need to get this memory now
+ NewAdaptP->MulticastList = (PMULTICAST_ENTRY)
+ AllocPhys(sizeof(MULTICAST_ENTRY) * (NewAdaptP->MulticastListMax));
+ if (NewAdaptP->MulticastList == (PMULTICAST_ENTRY)NULL) {
+ FreePhys((PVOID)NewAdaptP->OpenBlocks);
+ FreePhys((PVOID)NewAdaptP);
+ return NDIS_STATUS_FAILURE;
+ }
+ NdisAllocateSpinLock(&NewAdaptP->MulticastSpinLock);
+
+ // set up the broadcast address as first multicast list entry
+ NewAdaptP->MulticastListSize = 1;
+ RtlMoveMemory(NewAdaptP->MulticastList->Address,
+ BroadcastAddress, ADDRESS_LEN);
+ NewAdaptP->MulticastList->ProtocolMask = ~(MASK)0; // not really needed
+
+ NewAdaptP->LoopbackQueue = (PNDIS_PACKET)NULL;
+ NdisAllocateSpinLock(&NewAdaptP->LoopbackSpinLock);
+
+ NewAdaptP->NumOpens = 0;
+ NewAdaptP->OpenQueue = (POPEN_BLOCK)NULL;
+
+ // set up free list of open blocks
+ NewAdaptP->FreeOpenQueue = NewAdaptP->OpenBlocks;
+ for (i = 0; i < NewAdaptP->MaxOpens-1; i++)
+ NewAdaptP->OpenBlocks[i].NextOpen = &(NewAdaptP->OpenBlocks[i+1]);
+ NewAdaptP->OpenBlocks[i].NextOpen = (POPEN_BLOCK)NULL;
+
+ NewAdaptP->MacBlock = &GlobalMacBlock;
+
+ NdisAcquireSpinLock(&GlobalMacBlock.SpinLock);
+ NewAdaptP->NextAdapter = GlobalMacBlock.AdapterQueue;
+ GlobalMacBlock.AdapterQueue = NewAdaptP;
+ NdisReleaseSpinLock(&GlobalMacBlock.SpinLock);
+
+ NewAdaptP->Debug = GlobalMacBlock.Debug;
+
+ Status = NdisRegisterAdapter(&NewAdaptP->NdisAdapterHandle,
+ GlobalMacBlock.NdisMacHandle,
+ (NDIS_HANDLE)NewAdaptP,
+ AdapterName);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ if (NewAdaptP->Debug)
+ DbgPrint(" [ NdisRegisterAdapter FAILURE %d ] ", Status);
+ //*\\ take us out of GlobalMacBlock.AdapterQueue;
+ FreePhys((PVOID)NewAdaptP->OpenBlocks);
+ FreePhys((PVOID)NewAdaptP);
+ return NDIS_STATUS_FAILURE;
+ }
+
+ KeInitializeDpc(&NewAdaptP->IndicateDpc,
+ TestMacIndicateDpc, (PVOID)NewAdaptP);
+ NewAdaptP->DpcQueued = FALSE;
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+
+//
+// MacOpenAdapter
+//
+// NDIS function
+//
+
+static
+NDIS_STATUS
+TestMacOpenAdapter(
+ OUT NDIS_HANDLE * MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_HANDLE MacAdapterContext,
+ IN PSTRING AddressingInformation OPTIONAL
+ )
+{
+#define AdaptP ((PADAPTER_BLOCK)MacAdapterContext)
+ POPEN_BLOCK NewOpenP;
+
+ RequestHandle;
+
+ // take care of linking us in to the appropriate lists
+ NdisAcquireSpinLock(&AdaptP->MacBlock->SpinLock);
+ if (AdaptP->NumOpens == AdaptP->MaxOpens) {
+ NdisReleaseSpinLock(&AdaptP->MacBlock->SpinLock);
+ return NDIS_STATUS_FAILURE;
+ }
+ // rearrange free list
+ NewOpenP = AdaptP->FreeOpenQueue;
+ AdaptP->FreeOpenQueue = NewOpenP->NextOpen;
+
+ // and link us on to active list
+ NewOpenP->NextOpen = AdaptP->OpenQueue;
+ AdaptP->OpenQueue = NewOpenP;
+
+ ++(AdaptP->NumOpens);
+ NdisReleaseSpinLock(&AdaptP->MacBlock->SpinLock);
+
+ // set up the open block
+ NewOpenP->AdapterBlock = AdaptP;
+ NewOpenP->MacBlock = AdaptP->MacBlock;
+ NewOpenP->NdisBindingContext = NdisBindingContext;
+ NewOpenP->AddressingInformation = AddressingInformation;
+ // set nth bit of Multicast bit (where n is our index in AdaptP->OpenBlocks)
+ NewOpenP->MulticastBit = 1;
+ NewOpenP->MulticastBit <<= AdaptP->OpenBlocks - NewOpenP;
+
+ NewOpenP->Debug = AdaptP->Debug;
+
+ if (NewOpenP->Debug)
+ DbgPrint("--> TestMacOpenAdapter %d\n", AdaptP->AdapterNumber);
+
+ //*\\ initialize OpenData to zero
+
+ *MacBindingHandle = (NDIS_HANDLE)NewOpenP;
+ return NDIS_STATUS_SUCCESS;
+#undef AdaptP
+}
+
+
+
+//
+// MacCloseAdapter
+//
+// NDIS function
+//
+
+static
+NDIS_STATUS
+TestMacCloseAdapter(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle
+ )
+{
+#define OpenP ((POPEN_BLOCK)MacBindingHandle)
+ PADAPTER_BLOCK AdaptP = OpenP->AdapterBlock;
+ POPEN_BLOCK TmpOpenP;
+
+ RequestHandle;
+
+ if (OpenP->Debug)
+ DbgPrint("--> TestMacCloseAdapter %d\n", AdaptP->AdapterNumber);
+
+ // first zap us off the multicast address list
+ TestMacKillMulticastAddresses(AdaptP, OpenP->MulticastBit);
+
+ // now remove us from the list of opens for this adapter
+ NdisAcquireSpinLock(&AdaptP->MacBlock->SpinLock);
+
+ // take us off active list
+ if (OpenP == AdaptP->OpenQueue)
+ AdaptP->OpenQueue = OpenP->NextOpen;
+ else {
+ TmpOpenP = AdaptP->OpenQueue;
+ while (TmpOpenP->NextOpen != OpenP)
+ TmpOpenP = TmpOpenP->NextOpen;
+ TmpOpenP->NextOpen = OpenP->NextOpen;
+ }
+
+ // put us on free list
+ OpenP->NextOpen = AdaptP->FreeOpenQueue;
+ AdaptP->FreeOpenQueue = OpenP;
+
+ --(AdaptP->NumOpens);
+ NdisReleaseSpinLock(&AdaptP->MacBlock->SpinLock);
+
+ return NDIS_STATUS_SUCCESS;
+#undef OpenP
+}
+
+
+
+
+//
+// MacSetPacketFilter
+//
+// NDIS function
+//
+// - set appropriate bits in the adapter filters
+// - modify the card Receive Configuration Register if needed
+//
+
+static
+NDIS_STATUS
+TestMacSetPacketFilter(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN UINT PacketFilter
+ )
+{
+#define OpenP ((POPEN_BLOCK)MacBindingHandle)
+ PADAPTER_BLOCK AdaptP = OpenP->AdapterBlock;
+ MASK BitOn = OpenP->MulticastBit;
+ MASK BitOff = ~(OpenP->MulticastBit);
+
+ RequestHandle;
+
+ if (OpenP->Debug)
+ DbgPrint("--> TestMacSetPacketFilter %d\n", AdaptP->AdapterNumber);
+
+ // acquire AdaptP->MulticastSpinLock
+ TestMacGetMulticastAccess(AdaptP);
+
+ if (PacketFilter & NDIS_PACKET_TYPE_DIRECTED)
+ AdaptP->DirectedFilter |= BitOn;
+ else
+ AdaptP->DirectedFilter &= BitOff;
+
+ if (PacketFilter & NDIS_PACKET_TYPE_MULTICAST)
+ AdaptP->MulticastFilter |= BitOn;
+ else
+ AdaptP->MulticastFilter &= BitOff;
+
+ if (PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST)
+ AdaptP->AllMulticastFilter |= BitOn;
+ else
+ AdaptP->AllMulticastFilter &= BitOff;
+
+ if (PacketFilter & NDIS_PACKET_TYPE_BROADCAST)
+ AdaptP->BroadcastFilter |= BitOn;
+ else
+ AdaptP->BroadcastFilter &= BitOff;
+
+ if (PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS)
+ AdaptP->PromiscuousFilter |= BitOn;
+ else
+ AdaptP->PromiscuousFilter &= BitOff;
+
+ NdisReleaseSpinLock(&AdaptP->MulticastSpinLock);
+
+ return NDIS_STATUS_SUCCESS;
+#undef OpenP
+}
+
+
+
+//
+// MacAddMulticastAddress
+//
+// NDIS function
+//
+// - add the address to the list if needed
+// - modify the card multicast registers if needed
+//
+
+static
+NDIS_STATUS
+TestMacAddMulticastAddress(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN PSTRING MulticastAddress
+ )
+{
+#define OpenP ((POPEN_BLOCK)MacBindingHandle)
+ PADAPTER_BLOCK AdaptP = OpenP->AdapterBlock;
+ PMULTICAST_ENTRY MCSlot;
+
+ RequestHandle;
+
+ if (OpenP->Debug)
+ DbgPrint("--> TestMacAddMulticastAddress %d\n", AdaptP->AdapterNumber);
+
+ // acquire AdaptP->MulticastSpinLock
+ TestMacGetMulticastAccess(AdaptP);
+
+ // see if this address exists in our list
+ MCSlot = TestMacFindMulticastAddress(AdaptP->MulticastList,
+ AdaptP->MulticastListSize, MulticastAddress->Buffer);
+ if (MCSlot == (PMULTICAST_ENTRY)NULL) {
+ // see if our list is full
+ if (AdaptP->MulticastListSize == AdaptP->MulticastListMax) {
+ NdisReleaseSpinLock(&AdaptP->MulticastSpinLock);
+ return NDIS_MULTICAST_LIST_FULL;
+ }
+ // add us at the end
+ MCSlot = &(AdaptP->MulticastList[AdaptP->MulticastListSize]);
+ ++(AdaptP->MulticastListSize);
+ RtlMoveMemory(MCSlot->Address, MulticastAddress->Buffer, ADDRESS_LEN);
+ MCSlot->ProtocolMask = OpenP->MulticastBit; // so far, only us
+ } else {
+ if (MCSlot->ProtocolMask & OpenP->MulticastBit) {
+ NdisReleaseSpinLock(&AdaptP->MulticastSpinLock);
+ return NDIS_MULTICAST_EXISTS;
+ }
+ MCSlot->ProtocolMask |= OpenP->MulticastBit;
+ }
+
+ NdisReleaseSpinLock(&AdaptP->MulticastSpinLock);
+
+ return NDIS_STATUS_SUCCESS;
+#undef OpenP
+}
+
+
+//
+// GetMulticastAccess
+//
+// - acquire AdaptP->MulticastSpinLock in a lazy fashion
+//
+
+static
+VOID
+TestMacGetMulticastAccess(
+ IN PADAPTER_BLOCK AdaptP
+ )
+{
+ for (;;) {
+ NdisAcquireSpinLock(&AdaptP->MulticastSpinLock);
+ if (AdaptP->MulticastDontModify) {
+ NdisReleaseSpinLock(&AdaptP->MulticastSpinLock);
+ // wait a little bit..
+ } else
+ return;
+ }
+}
+
+
+// just hack this in
+static
+UINT
+ExCompareMemory(
+ PUCHAR s,
+ PUCHAR t,
+ UINT l
+ )
+{
+ UINT i;
+
+ for (i=0; i<l; i++) {
+ if (s[i] != t[i])
+ return -1;
+ }
+ return 0;
+}
+
+
+//
+// FindMulticastAddress
+//
+// finds a multicast address in a list
+//
+// - call this with a spin lock held
+//
+
+static
+PMULTICAST_ENTRY
+TestMacFindMulticastAddress(
+ IN PMULTICAST_ENTRY List,
+ IN UINT Size,
+ IN PUCHAR MulticastAddress
+ )
+{
+ PMULTICAST_ENTRY End = &List[Size];
+
+ for ( ; List<End; ++List) {
+ // thanks to HenrySa for this idea...
+ if (MulticastAddress[4] != List->Address[4])
+ continue;
+ if (ExCompareMemory(MulticastAddress, List->Address, ADDRESS_LEN) == 0)
+ return List;
+ }
+ return (PMULTICAST_ENTRY)NULL;
+}
+
+
+//
+// KillMulticastAddresses
+//
+// removes all multicast entries with MulticastBit on
+//
+// - called when an open is closed
+// - if this is the last reference to an entry, remove it
+//
+
+static
+VOID
+TestMacKillMulticastAddresses(
+ IN PADAPTER_BLOCK AdaptP,
+ IN MASK MulticastBit
+ )
+{
+ PMULTICAST_ENTRY List = AdaptP->MulticastList;
+ PMULTICAST_ENTRY End = &List[AdaptP->MulticastListSize];
+ PMULTICAST_ENTRY Dest;
+
+ // acquire AdaptP->MulticastSpinLock
+ TestMacGetMulticastAccess(AdaptP);
+
+ Dest = List;
+ while (List < End) {
+ List->ProtocolMask &= ~MulticastBit;
+ if (List->ProtocolMask != 0) {
+ if (Dest < List)
+ RtlMoveMemory(Dest, List, sizeof(MULTICAST_ENTRY));
+ ++Dest;
+ }
+ ++List;
+ }
+ AdaptP->MulticastListSize = Dest - AdaptP->MulticastList;
+
+ NdisReleaseSpinLock(&AdaptP->MulticastSpinLock);
+}
+
+
+
+//
+// MacDeleteMulticastAddress
+//
+// NDIS function
+//
+
+static
+NDIS_STATUS
+TestMacDeleteMulticastAddress(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN PSTRING MulticastAddress
+ )
+{
+#define OpenP ((POPEN_BLOCK)MacBindingHandle)
+ PADAPTER_BLOCK AdaptP = OpenP->AdapterBlock;
+ PMULTICAST_ENTRY MCSlot;
+
+ RequestHandle;
+
+ if (OpenP->Debug)
+ DbgPrint("--> TestMacDeleteMulticastAddress %d\n", AdaptP->AdapterNumber);
+
+ // acquire AdaptP->MulticastSpinLock
+ TestMacGetMulticastAccess(AdaptP);
+
+ MCSlot = TestMacFindMulticastAddress(AdaptP->MulticastList,
+ AdaptP->MulticastListSize, MulticastAddress->Buffer);
+ if (MCSlot == (PMULTICAST_ENTRY)NULL) {
+ NdisReleaseSpinLock(&AdaptP->MulticastSpinLock);
+ return NDIS_MULTICAST_NOT_FOUND;
+ } else {
+ if (!(MCSlot->ProtocolMask & OpenP->MulticastBit)) {
+ NdisReleaseSpinLock(&AdaptP->MulticastSpinLock);
+ return NDIS_MULTICAST_NOT_FOUND;
+ } else {
+ MCSlot->ProtocolMask &= ~(OpenP->MulticastBit);
+ if (MCSlot->ProtocolMask == 0) { // nobody using it
+ // remove this entry from the list
+ --(AdaptP->MulticastListSize);
+ if (MCSlot != &AdaptP->MulticastList[AdaptP->MulticastListSize])
+ RtlMoveMemory(MCSlot,
+ &AdaptP->MulticastList[AdaptP->MulticastListSize],
+ sizeof(MULTICAST_ENTRY));
+ }
+ }
+ }
+ NdisReleaseSpinLock(&AdaptP->MulticastSpinLock);
+
+ return NDIS_STATUS_SUCCESS;
+#undef OpenP
+}
+
+
+
+//
+// MacSend
+//
+// NDIS function
+//
+
+static
+NDIS_STATUS
+TestMacSend(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN PNDIS_PACKET Packet
+ )
+{
+#define OpenP ((POPEN_BLOCK)MacBindingHandle)
+ PADAPTER_BLOCK AdaptP = ((POPEN_BLOCK)MacBindingHandle)->AdapterBlock;
+ PMAC_RESERVED Reserved = RESERVED(Packet);
+
+ if (OpenP->Debug)
+ DbgPrint("--> TestMacSend %d\n", AdaptP->AdapterNumber);
+
+ if (OpenP->Debug) {
+ UCHAR Buf[80];
+ UINT Len;
+ Len = TestMacCopyOver(Buf, Packet, 0, 80);
+ DbgPrint("Message <%.*s>\n", Len, Buf);
+ }
+
+ Reserved->RequestHandle = RequestHandle;
+ Reserved->OpenBlock = (POPEN_BLOCK)MacBindingHandle;
+ Reserved->NextPacket = (PNDIS_PACKET)NULL;
+ TestMacSetLoopbackFlag(Packet);
+
+ if (Reserved->Loopback) {
+ Reserved->Status = 1;
+ NdisAcquireSpinLock(&AdaptP->LoopbackSpinLock);
+ TestMacLoopbackPacket(AdaptP, Packet);
+ NdisReleaseSpinLock(&AdaptP->LoopbackSpinLock);
+ }
+
+ return NDIS_STATUS_PENDING; // will complete when looped back
+#undef OpenP
+}
+
+
+//
+// SetLoopbackFlag
+//
+// sets the loopback flag in the reserved section of a packet
+// if it has a multicast destination address
+//
+
+static
+VOID
+TestMacSetLoopbackFlag(
+ IN OUT PNDIS_PACKET Packet
+ )
+{
+ UINT Dummy;
+ PNDIS_BUFFER FirstBuf;
+ PVOID BufVA;
+ PMAC_RESERVED Reserved = RESERVED(Packet);
+
+#if 0
+ NdisQueryPacket(Packet, NULL, &Dummy, &FirstBuf, NULL);
+ NdisQueryBuffer(FirstBuf, NULL, &BufVA, &Dummy);
+ Reserved->Loopback = (BOOLEAN)((((PUCHAR)BufVA)[0] & 1) != 0);
+#else
+ Dummy; FirstBuf; BufVA;
+ Reserved->Loopback = TRUE;
+#endif
+}
+
+
+//
+// LoopbackPacket
+//
+// put a packet on the loopback queue
+//
+// - call this with LoopbackSpinLock held
+//
+//
+
+static
+VOID
+TestMacLoopbackPacket(
+ IN PADAPTER_BLOCK AdaptP,
+ IN OUT PNDIS_PACKET Packet
+ )
+{
+ PMAC_RESERVED Reserved = RESERVED(Packet);
+
+ if (AdaptP->LoopbackQueue == (PNDIS_PACKET)NULL) {
+ AdaptP->LoopbackQueue = Packet;
+ AdaptP->LoopbackQTail = Packet;
+ } else {
+ PMAC_RESERVED Res2 = RESERVED(AdaptP->LoopbackQTail);
+ Res2->NextPacket = Packet;
+ AdaptP->LoopbackQTail = Packet;
+ }
+ Reserved->NextPacket = (PNDIS_PACKET)NULL;
+
+ if (!AdaptP->DpcQueued) {
+ AdaptP->DpcQueued = TRUE;
+ KeInsertQueueDpc(&AdaptP->IndicateDpc, NULL, NULL);
+ }
+}
+
+
+
+//
+// IndicateLoopbackPacket
+//
+// indicates a loopback packet to the protocols
+//
+// - the protocol must want to receive multicast/broadcast packets
+// - the address must be on his multicast list
+//
+
+static
+VOID
+TestMacIndicateLoopbackPacket(
+ IN PADAPTER_BLOCK AdaptP,
+ IN PNDIS_PACKET Packet
+ )
+{
+ PMULTICAST_ENTRY MCSlot;
+ POPEN_BLOCK CurOpen;
+ MASK EffectiveMask;
+ UINT IndicateLen;
+ UINT PacketLen;
+ NDIS_STATUS Status;
+
+ // copy destination address of packet into AdaptP->Lookahead
+ if (TestMacCopyOver(AdaptP->Lookahead, Packet, 0, ADDRESS_LEN) < ADDRESS_LEN) {
+ return;
+ // error, runt packet
+ }
+
+ NdisAcquireSpinLock(&AdaptP->MulticastSpinLock);
+ AdaptP->MulticastDontModify = TRUE;
+ NdisReleaseSpinLock(&AdaptP->MulticastSpinLock);
+
+ if (AdaptP->Lookahead[0] & 1) {
+ // if bit x in EffectiveMask is on, the protocol x wants this packet
+ MCSlot = TestMacFindMulticastAddress(AdaptP->MulticastList,
+ AdaptP->MulticastListSize, AdaptP->Lookahead);
+ if (MCSlot == (PMULTICAST_ENTRY)NULL)
+ EffectiveMask = AdaptP->MulticastFilter | AdaptP->PromiscuousFilter;
+ else if (MCSlot == &AdaptP->MulticastList[0]) // broadcast
+ EffectiveMask = AdaptP->BroadcastFilter | AdaptP->PromiscuousFilter;
+ else
+ EffectiveMask = MCSlot->ProtocolMask &
+ (AdaptP->MulticastFilter | AdaptP->AllMulticastFilter |
+ AdaptP->PromiscuousFilter);
+ } else {
+ EffectiveMask = AdaptP->DirectedFilter | AdaptP->PromiscuousFilter;
+ }
+
+ // as long as somebody wants it, indicate it
+ if (EffectiveMask != 0) {
+ PacketLen = TestMacPacketSize(Packet);
+ IndicateLen = (PacketLen > 256) ? 256 : PacketLen;
+ // copy the lookahead data into a contiguous buffer
+ TestMacCopyOver(AdaptP->Lookahead+ADDRESS_LEN,
+ Packet, ADDRESS_LEN, IndicateLen-ADDRESS_LEN);
+ CurOpen = AdaptP->OpenQueue;
+ while (CurOpen) {
+ if (CurOpen->MulticastBit & EffectiveMask) {
+ NdisIndicateReceive(&Status,
+ CurOpen->NdisBindingContext,
+ (NDIS_HANDLE)AdaptP,
+ AdaptP->Lookahead,
+ IndicateLen,
+ PacketLen);
+ }
+ CurOpen = CurOpen->NextOpen;
+ }
+ }
+
+ NdisAcquireSpinLock(&AdaptP->MulticastSpinLock);
+ AdaptP->MulticastDontModify = FALSE;
+ NdisReleaseSpinLock(&AdaptP->MulticastSpinLock);
+}
+
+
+//
+// PacketSize
+//
+// returns the number of bytes of data in a packet
+//
+
+static
+UINT
+TestMacPacketSize(
+ IN PNDIS_PACKET Packet
+ )
+{
+ PNDIS_BUFFER CurBuffer;
+ UINT Dummy;
+ UINT BufLen;
+ UINT TotLen;
+
+ TotLen = 0;
+ NdisQueryPacket(Packet, NULL, &Dummy, &CurBuffer, NULL);
+ while (CurBuffer != (PNDIS_BUFFER)NULL) {
+ NdisQueryBuffer(CurBuffer, NULL, NULL, &BufLen);
+ TotLen += BufLen;
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+ }
+ return TotLen;
+}
+
+
+//
+// CopyOver
+//
+// copy bytes from a packet into a buffer
+//
+// - returns the actual number of bytes copied
+//
+
+static
+UINT
+TestMacCopyOver(
+ OUT PUCHAR Buf, // destination
+ IN PNDIS_PACKET Packet, // source packet
+ IN UINT Offset, // offset in packet
+ IN UINT Length // number of bytes to copy
+ )
+{
+ PNDIS_BUFFER CurBuffer;
+ UINT Dummy;
+ UINT BytesCopied;
+ PUCHAR BufVA;
+ UINT BufLen;
+ UINT ToCopy;
+ UINT CurOffset;
+
+ BytesCopied = 0;
+ // first move to Offset bytes into the packet
+ CurOffset = 0;
+ NdisQueryPacket(Packet, NULL, &Dummy, &CurBuffer, NULL);
+ while (CurBuffer != (PNDIS_BUFFER)NULL) {
+ NdisQueryBuffer(CurBuffer, NULL, (PVOID *) &BufVA, &BufLen);
+ if (CurOffset + BufLen > Offset)
+ break;
+ CurOffset += BufLen;
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+ }
+ // see if we went off the end of the packet
+ if (CurBuffer == (PNDIS_BUFFER)NULL)
+ return 0;
+ // now copy over Length bytes
+ BufVA += (Offset - CurOffset);
+ BufLen -= (Offset - CurOffset);
+ for (;;) {
+ ToCopy = (BytesCopied+BufLen > Length) ? Length - BytesCopied : BufLen;
+ RtlMoveMemory(Buf+BytesCopied, BufVA, ToCopy);
+ BytesCopied += ToCopy;
+ if (BytesCopied == Length)
+ return BytesCopied;
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+ if (CurBuffer == (PNDIS_BUFFER)NULL)
+ break;
+ NdisQueryBuffer(CurBuffer, NULL, (PVOID *) &BufVA, &BufLen);
+ }
+ return BytesCopied;
+}
+
+
+
+//
+// NdisTransferData
+//
+// NDIS function
+//
+// - AdaptP->LoopbackPacket will be FALSE if this is for a normal
+// indication, otherwise it will point to a loopback packet
+//
+
+static
+NDIS_STATUS
+TestMacTransferData(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ )
+{
+#define OpenP ((POPEN_BLOCK)MacBindingHandle)
+#define AdaptP ((PADAPTER_BLOCK)MacReceiveContext)
+
+ RequestHandle; ByteOffset; BytesToTransfer; Packet; BytesTransferred;
+
+ if (OpenP->Debug)
+ DbgPrint("--> TestMacTransferData %d\n", AdaptP->AdapterNumber);
+
+ if (AdaptP->LoopbackPacket != (PNDIS_PACKET)NULL) {
+ PNDIS_BUFFER CurBuffer;
+ UINT Dummy;
+ PUCHAR BufVA;
+ UINT BufLen, Copied;
+ UINT CurOff;
+
+ // have to copy data from AdaptP->LoopbackPacket into Packet
+ NdisQueryPacket(Packet, NULL, &Dummy, &CurBuffer, NULL);
+ CurOff = ByteOffset;
+ while (CurBuffer != (PNDIS_BUFFER)NULL) {
+ NdisQueryBuffer(CurBuffer, NULL, (PVOID *) &BufVA, &BufLen);
+ Copied = TestMacCopyOver(BufVA, AdaptP->LoopbackPacket,
+ CurOff, BufLen);
+ CurOff += Copied;
+ if (Copied < BufLen)
+ break;
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+ }
+ *BytesTransferred = CurOff - ByteOffset;
+ }
+
+ return NDIS_STATUS_SUCCESS;
+#undef AdaptP
+#undef OpenP
+}
+
+
+
+//
+// MacQueryInformation
+//
+// NDIS function
+//
+
+static
+NDIS_STATUS
+TestMacQueryInformation(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN NDIS_INFORMATION_CLASS InformationClass,
+ OUT PVOID Buffer,
+ IN UINT BufferLength
+ )
+{
+#define OpenP ((POPEN_BLOCK)MacBindingHandle)
+ PADAPTER_BLOCK AdaptP = OpenP->AdapterBlock;
+ UINT i;
+ static UCHAR StationAddress[] = { 0x00, 0x00, 0x00, 0x01, 0x02, 0x03 };
+
+ RequestHandle; InformationClass; Buffer; BufferLength;
+
+ if (OpenP->Debug)
+ DbgPrint("--> TestMacQueryInformation %d\n", AdaptP->AdapterNumber);
+
+
+ switch (InformationClass) {
+
+ case NdisInfoStationAddress:
+ RtlMoveMemory(Buffer, StationAddress, 6);
+ break;
+
+ }
+
+#if 0
+ if ((UINT)InformationClass == 1) {
+ // show multicast list
+ PMULTICAST_ENTRY MCSlot, End;
+ POPEN_BLOCK CurOpen;
+ PUCHAR Tcp;
+
+ NdisAcquireSpinLock(&AdaptP->MulticastSpinLock);
+ AdaptP->MulticastDontModify = TRUE;
+ NdisReleaseSpinLock(&AdaptP->MulticastSpinLock);
+
+ MCSlot = AdaptP->MulticastList;
+ End = &AdaptP->MulticastList[AdaptP->MulticastListSize];
+ while (MCSlot < End) {
+ Tcp = MCSlot->Address;
+ for (i=0; i<6; i++) {
+ if (Tcp[i] >= ' ' && Tcp[i] <= 'z')
+ DbgPrint(" %c ", Tcp[i]);
+ else
+ DbgPrint("%2x ", Tcp[i]);
+ }
+ CurOpen = AdaptP->OpenQueue;
+ while (CurOpen != (POPEN_BLOCK)NULL) {
+ if (CurOpen->MulticastBit & MCSlot->ProtocolMask)
+ DbgPrint(CurOpen == OpenP ? " X" : " x");
+ else
+ DbgPrint(" ");
+ CurOpen = CurOpen->NextOpen;
+ }
+ DbgPrint("\n");
+ ++MCSlot;
+ }
+
+ NdisAcquireSpinLock(&AdaptP->MulticastSpinLock);
+ AdaptP->MulticastDontModify = FALSE;
+ NdisReleaseSpinLock(&AdaptP->MulticastSpinLock);
+ }
+#else
+ i;
+#endif
+
+ return NDIS_STATUS_SUCCESS;
+#undef OpenP
+}
+
+
+
+//
+// MacSetInformation
+//
+// NDIS function
+//
+
+static
+NDIS_STATUS
+TestMacSetInformation(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN NDIS_INFORMATION_CLASS InformationClass,
+ IN PVOID Buffer,
+ IN UINT BufferLength
+ )
+{
+#define OpenP ((POPEN_BLOCK)MacBindingHandle)
+ PADAPTER_BLOCK AdaptP = OpenP->AdapterBlock;
+
+ RequestHandle; InformationClass; Buffer; BufferLength;
+
+ if (OpenP->Debug)
+ DbgPrint("--> TestMacSetInformation %d\n", AdaptP->AdapterNumber);
+
+ // this will involve the OpenData and AdapterData structures
+
+ return NDIS_STATUS_SUCCESS;
+#undef OpenP
+}
+
+
+
+//
+// MacReset
+//
+// NDIS function
+//
+
+static
+NDIS_STATUS
+TestMacReset(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle
+ )
+{
+#define OpenP ((POPEN_BLOCK)MacBindingHandle)
+ PADAPTER_BLOCK AdaptP = OpenP->AdapterBlock;
+ POPEN_BLOCK TmpOpenP;
+
+ RequestHandle;
+
+ if (OpenP->Debug)
+ DbgPrint("--> TestMacReset %d\n", AdaptP->AdapterNumber);
+
+ TmpOpenP = AdaptP->OpenQueue;
+ while (TmpOpenP != (POPEN_BLOCK)NULL) {
+ NdisIndicateStatus(TmpOpenP->NdisBindingContext, NDIS_STATUS_RESET, 0);
+ TmpOpenP = TmpOpenP->NextOpen;
+ }
+
+ return NDIS_STATUS_SUCCESS;
+#undef OpenP
+}
+
+
+
+//
+// MacTest
+//
+// NDIS function
+//
+
+static
+NDIS_STATUS
+TestMacTest(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle
+ )
+{
+#define OpenP ((POPEN_BLOCK)MacBindingHandle)
+ PADAPTER_BLOCK AdaptP = OpenP->AdapterBlock;
+
+ RequestHandle;
+
+ if (OpenP->Debug)
+ DbgPrint("--> TestMacTest %d\n", AdaptP->AdapterNumber);
+
+ return NDIS_STATUS_SUCCESS;
+#undef OpenP
+}
+
+
+static
+VOID
+TestMacIndicateDpc(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+{
+#define AdaptP ((PADAPTER_BLOCK)DeferredContext)
+ PNDIS_PACKET LPacket;
+ PMAC_RESERVED Reserved;
+ POPEN_BLOCK CurOpen;
+
+ UNREFERENCED_PARAMETER(Dpc);
+ UNREFERENCED_PARAMETER(SystemArgument1);
+ UNREFERENCED_PARAMETER(SystemArgument2);
+
+ // loopback any waiting packets
+ NdisAcquireSpinLock(&AdaptP->LoopbackSpinLock);
+ while (AdaptP->LoopbackQueue) {
+ // take the first packet off the queue
+ LPacket = AdaptP->LoopbackQueue;
+ Reserved = RESERVED(LPacket);
+ AdaptP->LoopbackQueue = RESERVED(AdaptP->LoopbackQueue)->NextPacket;
+ NdisReleaseSpinLock(&AdaptP->LoopbackSpinLock);
+ AdaptP->LoopbackPacket = LPacket;
+ // actually indicate it
+ TestMacIndicateLoopbackPacket(AdaptP, AdaptP->LoopbackPacket);
+ NdisAcquireSpinLock(&AdaptP->LoopbackSpinLock);
+ // complete the packet if needed
+ if (Reserved->RequestHandle != 0) {
+ NdisCompleteSend(
+ Reserved->OpenBlock->NdisBindingContext,
+ Reserved->RequestHandle,
+ NDIS_STATUS_SUCCESS);
+ }
+ }
+ AdaptP->DpcQueued = FALSE;
+ NdisReleaseSpinLock(&AdaptP->LoopbackSpinLock);
+
+ // indicate ReceiveComplete
+ CurOpen = AdaptP->OpenQueue;
+ while (CurOpen) {
+ NdisIndicateReceiveComplete(CurOpen->NdisBindingContext);
+ CurOpen = CurOpen->NextOpen;
+ }
+
+#undef AdaptP
+}
diff --git a/private/ntos/ndis/testmac/testmac.h b/private/ntos/ndis/testmac/testmac.h
new file mode 100644
index 000000000..750bb213e
--- /dev/null
+++ b/private/ntos/ndis/testmac/testmac.h
@@ -0,0 +1,349 @@
+
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ testmac.h
+
+Abstract:
+
+ Definitions for test MAC.
+ Motsly taken from the Elnkii code spec.
+
+Author:
+
+ Adam Barr (adamba) 16-Jul-1990
+
+Revision History:
+
+--*/
+
+#define AllocPhys(s) ExAllocatePool(NonPagedPool, s)
+#define FreePhys(s) ExFreePool(s)
+
+#define ADDRESS_LEN 6
+
+typedef ULONG MASK;
+
+UCHAR BroadcastAddress[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+
+// only have one of these structures
+
+typedef struct _MAC_BLOCK {
+ // NDIS information
+ NDIS_HANDLE NdisMacHandle; // returned from NdisRegisterMac
+ NDIS_MAC_CHARACTERISTICS MacCharacteristics;
+ UCHAR MacName[8];
+ // adapters registered for us
+ UINT NumAdapters;
+ struct _ADAPTER_BLOCK * AdapterQueue;
+ // should we be verbose
+ BOOLEAN Debug;
+ // NT specific
+ PDRIVER_OBJECT DriverObject;
+ KPOWER_STATUS PowerStatus;
+ BOOLEAN PowerBoolean;
+ NDIS_SPIN_LOCK SpinLock; // guards NumAdapter and AdapterQueue
+} MAC_BLOCK, * PMAC_BLOCK;
+
+
+// the multicast address list consists of these
+typedef struct _MULTICAST_ENTRY {
+ UCHAR Address[ADDRESS_LEN];
+ MASK ProtocolMask; // determines which opens it applies to
+} MULTICAST_ENTRY, * PMULTICAST_ENTRY;
+
+// one of these per adapter registered
+
+typedef struct _ADAPTER_BLOCK {
+ // NDIS information
+ NDIS_HANDLE NdisAdapterHandle; // returned from NdisRegisterAdapter
+ PSTRING AdapterName;
+ // used to mark us
+ UINT AdapterNumber;
+ // links with our MAC
+ PMAC_BLOCK MacBlock;
+ struct _ADAPTER_BLOCK * NextAdapter; // used by MacBlock->OpenQueue
+ // opens for this adapter
+ UINT MaxOpens; // maximum number
+ struct _OPEN_BLOCK * OpenBlocks; // storage for MaxOpens OPEN_BLOCKs
+ UINT NumOpens;
+ struct _OPEN_BLOCK * OpenQueue;
+ struct _OPEN_BLOCK * FreeOpenQueue;
+ // should we be verbose
+ BOOLEAN Debug;
+ // PROTOCOL.INI information
+ UINT MulticastListMax;
+ // these are for the current packet
+ UCHAR PacketHeader[4];
+ UCHAR Lookahead[256];
+ UINT PacketLen;
+ // receive information
+ UINT MulticastListSize; // current size
+ PMULTICAST_ENTRY MulticastList;
+ NDIS_SPIN_LOCK MulticastSpinLock; // guards all data in this section
+ BOOLEAN MulticastDontModify; // an extended spinlock
+ MASK MulticastFilter; // these filters work as explained
+ MASK DirectedFilter; // in the design note
+ MASK BroadcastFilter;
+ MASK PromiscuousFilter;
+ MASK AllMulticastFilter;
+ // loopback information
+ PNDIS_PACKET LoopbackQueue;
+ PNDIS_PACKET LoopbackQTail;
+ NDIS_SPIN_LOCK LoopbackSpinLock;
+ PNDIS_PACKET LoopbackPacket;
+ // NT specific
+ PKINTERRUPT Interrupt;
+ KDPC IndicateDpc;
+ BOOLEAN DpcQueued;
+} ADAPTER_BLOCK, * PADAPTER_BLOCK;
+
+// general macros
+#define MSB(value) ((UCHAR)((value) << 8))
+#define LSB(value) ((UCHAR)((value) && 0xff))
+
+// one of these per open on the adapter
+
+typedef struct _OPEN_BLOCK {
+ // NDIS information
+ NDIS_HANDLE NdisBindingContext; // passed to MacOpenAdapter
+ PSTRING AddressingInformation; // not used currently
+ // links to our adapter
+ PADAPTER_BLOCK AdapterBlock;
+ struct _OPEN_BLOCK * NextOpen;
+ // links to our MAC
+ PMAC_BLOCK MacBlock; // faster than using AdapterBlock->MacBlock
+ // should we be verbose
+ BOOLEAN Debug;
+ // used for multicast addresses
+ MASK MulticastBit;
+} OPEN_BLOCK, * POPEN_BLOCK;
+
+
+
+// the reserved section of a packet
+
+typedef struct _MAC_RESERVED { // can't be more than 16 bytes
+ PNDIS_PACKET NextPacket; // used to in the transmit queue (4 bytes)
+ NDIS_HANDLE RequestHandle; // for async send completion (4 bytes)
+ POPEN_BLOCK OpenBlock; // so we know who to complete to (4 bytes)
+ USHORT Status; // completion status (2 bytes)
+ BOOLEAN Loopback; // is this a loopback packet (1 byte)
+ BOOLEAN ReadyToComplete; // is one out of xmit or loopback done (1 byte)
+} MAC_RESERVED, * PMAC_RESERVED;
+
+// macro to retrieve the MAC_RESERVED structure from a packet
+#define RESERVED(Packet) ((PMAC_RESERVED)((Packet)->MacReserved))
+
+extern MAC_BLOCK GlobalMacBlock;
+
+
+//
+// function prototypes
+//
+
+
+NTSTATUS
+TestMacInitialize(
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+
+static
+NTSTATUS
+TestMacDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+
+static
+NDIS_STATUS
+TestMacRegisterAdapter(
+ IN PSTRING AdapterName,
+ IN UINT AdapterNumber
+ );
+
+
+static
+NDIS_STATUS
+TestMacOpenAdapter(
+ OUT NDIS_HANDLE * MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_HANDLE MacAdapterContext,
+ IN PSTRING AddressingInformation OPTIONAL
+ );
+
+
+static
+NDIS_STATUS
+TestMacCloseAdapter(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle
+ );
+
+
+static
+NDIS_STATUS
+TestMacSetPacketFilter(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN UINT PacketFilter
+ );
+
+
+static
+NDIS_STATUS
+TestMacAddMulticastAddress(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN PSTRING MulticastAddress
+ );
+
+
+static
+VOID
+TestMacGetMulticastAccess(
+ IN PADAPTER_BLOCK AdaptP
+ );
+
+
+static
+PMULTICAST_ENTRY
+TestMacFindMulticastAddress(
+ IN PMULTICAST_ENTRY List,
+ IN UINT Size,
+ IN PUCHAR MulticastAddress
+ );
+
+
+static
+VOID
+TestMacKillMulticastAddresses(
+ IN PADAPTER_BLOCK AdaptP,
+ IN MASK MulticastBit
+ );
+
+
+static
+NDIS_STATUS
+TestMacDeleteMulticastAddress(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN PSTRING MulticastAddress
+ );
+
+
+static
+NDIS_STATUS
+TestMacSend(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN PNDIS_PACKET Packet
+ );
+
+
+static
+VOID
+TestMacSetLoopbackFlag(
+ IN OUT PNDIS_PACKET Packet
+ );
+
+
+static
+VOID
+TestMacLoopbackPacket(
+ IN PADAPTER_BLOCK AdaptP,
+ IN OUT PNDIS_PACKET Packet
+ );
+
+
+static
+VOID
+TestMacIndicateLoopbackPacket(
+ IN PADAPTER_BLOCK AdaptP,
+ IN PNDIS_PACKET Packet
+ );
+
+
+static
+UINT
+TestMacPacketSize(
+ IN PNDIS_PACKET Packet
+ );
+
+
+static
+UINT
+TestMacCopyOver(
+ OUT PUCHAR Buf,
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ IN UINT Length
+ );
+
+
+static
+NDIS_STATUS
+TestMacTransferData(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+
+static
+NDIS_STATUS
+TestMacQueryInformation(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN NDIS_INFORMATION_CLASS InformationClass,
+ OUT PVOID Buffer,
+ IN UINT BufferLength
+ );
+
+
+static
+NDIS_STATUS
+TestMacSetInformation(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle,
+ IN NDIS_INFORMATION_CLASS InformationClass,
+ IN PVOID Buffer,
+ IN UINT BufferLength
+ );
+
+
+static
+NDIS_STATUS
+TestMacReset(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle
+ );
+
+
+static
+NDIS_STATUS
+TestMacTest(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE RequestHandle
+ );
+
+
+static
+VOID
+TestMacIndicateDpc(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
diff --git a/private/ntos/ndis/testprot/dirs b/private/ntos/ndis/testprot/dirs
new file mode 100644
index 000000000..e348735d6
--- /dev/null
+++ b/private/ntos/ndis/testprot/dirs
@@ -0,0 +1,28 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=tplib \
+ tpdrvr \
+ tpctl \
+ tpdiff.new
+
+OPTIONAL_DIRS=tpkd
diff --git a/private/ntos/ndis/testprot/docs/arcnet.doc b/private/ntos/ndis/testprot/docs/arcnet.doc
new file mode 100644
index 000000000..db7a2302e
--- /dev/null
+++ b/private/ntos/ndis/testprot/docs/arcnet.doc
Binary files differ
diff --git a/private/ntos/ndis/testprot/docs/rfc1051 b/private/ntos/ndis/testprot/docs/rfc1051
new file mode 100644
index 000000000..7121f0019
--- /dev/null
+++ b/private/ntos/ndis/testprot/docs/rfc1051
@@ -0,0 +1,227 @@
+
+
+
+
+
+
+Network Working Group P. Prindeville
+Request for Comments: 1051 McGill University
+ March 1988
+
+
+ A Standard for the Transmission of IP Datagrams
+ and ARP Packets over ARCNET Networks
+
+
+Status of this Memo
+
+ This RFC specifies a standard protocol for the Internet community.
+ Distribution of this memo is unlimited.
+
+Introduction
+
+ This RFC specifies a standard method of encapsulating Internet
+ Protocol (IP) [1] and Address Resolution Protocol (ARP) [2] datagrams
+ on an ARCNET [3].
+
+Acknowledgements
+
+ The author wishes to express thanks to Robert Craig of the McGill
+ University Computing Centre and Bruce Hughes of Datapoint Corporation
+ for their generous support of facilities and information. I also
+ extend my gratitude to the readers of the PCIP mailing list for their
+ helpful ideas and comments.
+
+Frame Format
+
+ IP and ARP datagrams are transmitted in standard ARCNET packets. As
+ required by Datapoint Corporation, the first octet of the data field
+ is reserved for the network layer protocol identification (the
+ "system code" in Datapoint nomenclature), and must contain the value
+ 240 (F0 hex) for IP or 241 (F1 hex) for ARP. The ARP hardware
+ address type for ARCNET is 7 [9].
+
+ ARCNET supports packet formats containing 1-253 octets of data
+ (normal format) and 257-508 octets of data (extended format),
+ inclusive of system code. Note that there exists a range of data
+ lengths (254-256) which are 'forbidden'. IP packets within this
+ range should be padded (with octets of zero) to meet the minimum
+ extended packet size of 257 data octets. This padding is not part of
+ the IP packet and is not included in the total length field of the IP
+ header.
+
+
+
+
+
+
+Prindeville [Page 1]
+
+RFC 1051 IP and ARP on ARCNET March 1988
+
+
+ On networks where some hosts do not support extended packet format,
+ the IP Maximum Transmission Unit (MTU) should be set to 253, though
+ implementors are encouraged to support the extended packet format
+ mode of operation.
+
+ Because the ARCNET maximum packet length is less than the Internet
+ default MTU, implementations are strongly encouraged to support IP
+ level fragmentation and reassembly. Hosts not supporting this should
+ take steps to discourage others from sending fragmented packets, such
+ as using the TCP Maximum Segment Size option [4].
+
+ The frame format is:
+
+ Normal Packet Extended Packet
+ +----------------+ +----------------+
+ | ALERT* | | ALERT* |
+ +----------------+ +----------------+
+ | SOH (1) | | SOH (1) |
+ +----------------+ +----------------+
+ | SID | | SID |
+ +----------------+ +----------------+
+ | | | |
+ + DID + + DID +
+ | | | |
+ +----------------+ +----------------+
+ | COUNT | | NUL (0) |
+ +----------------+ + +
+ | SYSTEM CODE | | COUNT |
+ +----------------+ +----------------+
+ | | | SYSTEM CODE |
+ : DATA : +----------------+
+ | | | |
+ +----------------+ : DATA :
+ | | | |
+ + CRC + +----------------+
+ | | | |
+ +----------------+ + CRC +
+ | |
+ +----------------+
+
+ ALERT*: Six mark bits signifying the beginning of a frame.
+ SID: Sender's node ID.
+ DID: Receipient's node ID (repeated for reliability).
+ COUNT: Length of data and system code (one's complement).
+ SYSTEM CODE: 240 for IP, 241 for ARP (decimal).
+ DATA: Is either an IP or an ARP packet, padded with NULs so
+ as to not be between 254 and 256 octets long.
+ CRC: Cyclic redundancy check (CRC-16).
+
+
+
+Prindeville [Page 2]
+
+RFC 1051 IP and ARP on ARCNET March 1988
+
+
+Address Mappings
+
+ The mappings between 32-bit Internet addresses to 8-bit ARCNET
+ addresses can be done several ways, recommended are:
+
+ Host Number Extraction
+
+ The easiest thing to do is to use the last eight bits of host
+ number part of the Internet address as the host's node id. This
+ has been implemented on Experimental Ethernet [5] and ProNET-10
+ [6].
+
+ Dynamic Discovery
+
+ Mappings between 32-bit Internet addresses and 8-bit ARCNET node
+ ids could be accomplished through ARP. Internet addresses are
+ assigned arbitrarily on some Internet networks. All
+ implementations supporting ARP must have a means of disabling ARP
+ and using the above Host Number Extraction method of address
+ mapping so that systems may interoperate.
+
+ The use of ARP is optional. However, ARP is desirable when using
+ IP implementations that don't support subnetting [7], as in the
+ Proxy ARP scenario [8].
+
+Broadcast Address
+
+ The broadcast Internet address (the address on the network with a
+ host part of all binary ones) should be mapped to the broadcast node
+ id 0.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Prindeville [Page 3]
+
+RFC 1051 IP and ARP on ARCNET March 1988
+
+
+References
+
+ [1] Postel, J., "Internet Protocol", RFC-791, Network Information
+ Center, SRI, September 1981.
+
+ [2] Plummer, D., "An Ethernet Address Resolution Protocol", RFC- 826,
+ Network Information Center, SRI, November 1982.
+
+ [3] "ARCNET Designer's Handbook", Order Number 61610, Datapoint
+ Corporation, 1983.
+
+ [4] Postel, J., "The TCP Maximum Segment Size Option and Related
+ Topics", RFC-879, Network Information Center, SRI, November 1983.
+
+ [5] Postel, J., "A Standard for the Transmission of IP Datagrams over
+ Experimental Ethernet Networks", RFC-895, Network Information
+ Center, SRI, April 1984.
+
+ [6] "ProNET-10 Model p1300 IBM PC Interface System Installation and
+ Programming Guide", Version 4.0, Proteon Inc., July 1986.
+
+ [7] Mogul, J. and J. Postel, "Internet Standard Subnetting
+ Procedure", RFC-950, Network Information Center, SRI, October
+ 1984.
+
+ [8] Carl-Mitchell, S. and J.S. Quarterman, "Using ARP to Implement
+ Transparent Subnet Gateways", RFC-1027, Network Information
+ Center, SRI, October 1987.
+
+ [9] Reynolds, J., and J. Postel, "Assigned Numbers", RFC-1010,
+ Network Information Center, SRI, May 1987.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Prindeville [Page 4]
+
diff --git a/private/ntos/ndis/testprot/docs/rfc1201 b/private/ntos/ndis/testprot/docs/rfc1201
new file mode 100644
index 000000000..8f7d90890
--- /dev/null
+++ b/private/ntos/ndis/testprot/docs/rfc1201
@@ -0,0 +1,388 @@
+Network Working Group D. Provan
+Request for Comments: 1201 Novell, Inc.
+Obsoletes: RFC 1051 February 1991
+
+
+ Transmitting IP Traffic over ARCNET Networks
+
+Status of this Memo
+
+ This memo defines a protocol for the transmission of IP and ARP
+ packets over the ARCnet Local Area Network. This RFC specifies an
+ IAB standards track protocol for the Internet community, and requests
+ discussion and suggestions for improvements. Please refer to the
+ current edition of the "IAB Official Protocol Standards" for the
+ standardization state and status of this protocol. Distribution of
+ this memo is unlimited.
+
+1. Introduction
+
+ This memo specifies a method of encapsulating Internet Protocol (IP)
+ [1] and Address Resolution Protocol (ARP) [2] datagrams for
+ transmission across ARCNET [3] using the "ARCNET Packet Header
+ Definition Standard" [4]. This memo offers a replacement for RFC
+ 1051. RFC 1051 uses an ARCNET framing protocol which limits
+ unfragmented IP packets to 508 octets [5].
+
+2. ARCNET Packet Format
+
+ In 1989, Apple Computers, Novell, ACTINET Systems, Standard
+ Microsystems, and Pure Data Research agreed to use the ARCNET
+ datalink protocol defined in "ARCNET Packet Header Definition
+ Standard" [4]. We'll begin with a brief description of that
+ protocol.
+
+2.1. ARCNET Framing
+
+ ARCNET hardware supports two types of frames: short frames, which are
+ always 256 octets long, and long frames, which are always 512 octets
+ long. All frames begin with a hardware header and end with the
+ client's data preceded by a software header. Software places padding
+ in the middle of the packet between the hardware header and the
+ software header to make the frame the appropriate fixed length.
+ Unbeknown to the software, the hardware removes this padding during
+ transmission.
+
+ Short frames can hold from 0 to 249 octets of client data. Long
+ frames can hold from 253 to 504 octets of client data. To handle
+ frames with 250, 251, or 252 octets of data, the datalink protocol
+
+
+
+Provan [Page 1]
+
+RFC 1201 IP on ARCNET February 1991
+
+
+ introduces a third frame type: the exception frame.
+
+ These three frame formats are shown here. Except as noted, each
+ block represents one octet.
+
+
+ Short Frame Long Frame Exception Frame
+
+ +---------------+ +---------------+ +---------------+
+ | source | | source | | source |
+ +---------------+ +---------------+ +---------------+
+ | destination | | destination | | destination |
+ +---------------+ +---------------+ +---------------+
+ | offset | | 0 | | 0 |
+ +---------------+ +---------------+ +---------------+
+ . unused . | offset | | offset |
+ . (offset - 3 . +---------------+ +---------------+
+ . octets) . . unused . . unused .
+ +---------------+ . (offset - 4 . . (offset - 4 .
+ | protocol ID | . octets) . . octets) .
+ +---------------+ +---------------+ +---------------+
+ | split flag | | protocol ID | | protocol ID |
+ +---------------+ +---------------+ +---------------+
+ | sequence | | split flag | | flag: FF hex |
+ + number + +---------------+ +---------------+
+ | (2 octets) | | sequence | | padding: 0xFF |
+ +---------------+ + number + +---------------+
+ . . | (2 octets) | | padding: 0xFF |
+ . client data . +---------------+ +---------------+
+ . (256 - offset . . . | (protocol ID) |
+ . - 4 octets) . . . +---------------+
+ . . . . | split flag |
+ +---------------+ . . +---------------+
+ . . | sequence |
+ . client data . + number +
+ . (512 - offset . | (2 octets) |
+ . - 4 octets) . +---------------+
+ . . . .
+ . . . client data .
+ . . . (512 - offset .
+ . . . - 8 octets) .
+ . . . .
+ +---------------+ +---------------+
+
+ These packet formats are presented as software would see them
+ through ARCNET hardware. [3] refers to this as the "buffer
+ format". The actual format of packets on the wire is a little
+ different: the destination ID is duplicated, the padding between
+
+
+
+Provan [Page 2]
+
+RFC 1201 IP on ARCNET February 1991
+
+
+ the offset field and the protocol ID field is not transmitted, and
+ there's some hardware framing information. In addition, the
+ hardware transmits special packets for buffer allocation and
+ reception acknowledgement which are not described here [3].
+
+2.2. Datalink Layer Fragmentation
+
+ ARCNET hardware limits individual frames to 512 octets, which allows
+ 504 octets of client data. This ARCNET datalink protocol allows the
+ datalink layer to break packets into as many as 120 fragments for
+ transmission. This allows ARCNET clients to transmit up to 60,480
+ octets in each packet.
+
+ The "split flag" describes datalink layer packet fragments. There
+ are three cases: an unfragmented packet, the first fragment of a
+ fragmented packet, and any other fragment of a fragmented packet.
+
+ Unfragmented packets always have a split flag of zero.
+
+ The first fragment of a fragmented packet has a split flag equal to
+ ((T-2)*2)+1, where T is the total number of fragments to expect for
+ the packet.
+
+ Subsequent fragments of a fragmented packet have a split flag equal
+ to ((N-1)*2), where N is the number of this fragment. For example,
+ the fourth fragment of a packet will always have the split flag value
+ of six ( (4-1)*2 ).
+
+ The receiving station can identify the last fragment of a packet
+ because the value of its 8-bit split flag will be one greater than
+ the split flag of the first fragment of the packet.
+
+ A previous version of this ARCNET datalink protocol definition
+ only allowed packets which could be contained in two fragments.
+ In this older standard, the only legal split flags were 0, 1, and
+ 2. Compatibility with this older standard can be maintained by
+ configuring the maximum client data length to 1008 octets.
+
+ No more that 120 fragments are allowed. The highest legal split flag
+ value is EE hex. (Notice that the split flag value FF hex is used to
+ flag exception packets in what would otherwise be a long packet's
+ split flag field.)
+
+ All fragments of a single packet carry the same sequence number.
+
+2.3. Datalink Layer Reassembly
+
+ The previous section provides enough information to implement
+
+
+
+Provan [Page 3]
+
+RFC 1201 IP on ARCNET February 1991
+
+
+ datalink reassembly. To avoid buffer allocation problems during
+ reassembly, we recommend allocating enough space for the entire
+ reassembled packet when the first fragment arrives.
+
+ Since fragments are sent in order, the reassembly procedure can give
+ up on a packet if it receives a fragment out of order. There is one
+ exception, however. It is possible for successfully received
+ fragments to be retransmitted. Reassembly software should ignore
+ repetitious fragments without giving up on the packet.
+
+ Since fragments will be sent briskly, the reassembly procedure can
+ give up on a partially reassembled packet if no additional fragments
+ for it arrive within a few seconds.
+
+2.4. Datalink Layer Retransmission
+
+ For each unicast ARCNET packet, the hardware indicates to the sender
+ whether or not the receiver acknowledged the packet. To improve
+ reliability, datalink implementations are encouraged to retransmit
+ unacknowledged packets or packet fragments. Several retransmissions
+ may be necessary. Broadcast packets, however, are never acknowledged
+ and, therefore, they should never be retransmitted.
+
+ Packets which are successfully received may not be successfully
+ acknowledged. Consequently, retransmission by the datalink
+ implementation can cause duplicate packets or duplicate fragments.
+ Duplicate packets are not a problem for IP or ARP. As mentioned in
+ the previous section, ARCNET reassembly support should ignore any
+ redundant fragments.
+
+3. Transmitting IP and ARP Datagrams
+
+ IP and ARP datagrams are carried in the client data area of ARCNET
+ packets. Datalink support places each datagram in an appropriate
+ size ARCNET frame, fragmenting IP datagrams larger than 504 octets
+ into multiple frames as described in the previous section.
+
+4. IP Address Mappings
+
+ This section explains how each of the three basic 32-bit internet
+ address types are mapped to 8-bit ARCNET addresses.
+
+4.1. Unicast Addresses
+
+ A unicast IP address is mapped to an 8-bit ARCNET address using ARP
+ as specified in [2]. A later section covers the specific values
+ which should be used in ARP packets sent on ARCNET networks.
+
+
+
+
+Provan [Page 4]
+
+RFC 1201 IP on ARCNET February 1991
+
+
+ It is possible to assign IP addresses such that the last eight
+ bits are the same as the 8-bit ARCNET address. This would allow
+ direct mapping of IP address to ARCNET address without using a
+ discovery protocol. Some implementations might provide this as an
+ option, but it is not recommended practice. Although such hard-
+ wired mapping is initially appealing, experience shows that ARP is
+ a much more flexible and convenient approach which has a very
+ small cost.
+
+4.2. Broadcast Addresses
+
+ All IP broadcast addresses must be mapped to the ARCNET broadcast
+ address of 0.
+
+ Unlike unicast packets, ARCNET does not attempt to insure delivery
+ of broadcast packets, so they may be lost. This will not have a
+ major impact on IP since neither IP nor ARP expect all packets to
+ be delivered.
+
+4.3. Multicast Addresses
+
+ Since ARCNET provides no support for multicasts, all IP multicast
+ addresses must be mapped to the ARCNET broadcast address of 0.
+
+5. ARP
+
+ The hardware address length is 1 octet for ARP packets sent over
+ ARCNET networks. The ARP hardware type for ARCNET is 7. ARP request
+ packets are broadcast by directing them to ARCNET broadcast address,
+ which is 0.
+
+6. RARP
+
+ Reverse Address Resolution Protocol [6] packets can also be
+ transmitted over ARCNET. For the purposes of datalink transmission
+ and reception, RARP is identical to ARP and can be handled the same
+ way. There are a few differences to notice, however, between RARP
+ when running over ARCNET, which has a one octet hardware address, and
+ Ethernet, which has a six octet hardware address.
+
+ First, there are only 255 different hardware addresses for any given
+ ARCNET while there's an very large number of possible Ethernet
+ addresses. Second, ARCNET hardware addresses are more likely to be
+ duplicated on different ARCNET networks; Ethernet hardware addresses
+ will normally be globally unique. Third, an ARCNET hardware address
+ is not as constant as an Ethernet address: ARCNET hardware addresses
+ are set by switches, not fixed in ROM as they are on Ethernet.
+
+
+
+
+Provan [Page 5]
+
+RFC 1201 IP on ARCNET February 1991
+
+
+7. Maximum Transmission Unit
+
+ The maximum IP packet length possible using this encapsulation method
+ is 60,480 octets. Since this length is impractical, all ARCNET
+ implementations on a given ARCNET network will need to agree on a
+ smaller value. Therefore, the maximum packet size MUST be
+ configurable in implementations of this specification.
+
+ In any case, implementations must be able to send and receive IP
+ datagrams up to 576 octets in length, and are strongly encouraged to
+ handle IP datagrams up to 1500 octets in length.
+
+ Implementations may accept arriving IP datagrams which are larger
+ than their configured maximum transmission unit. They are not
+ required to discard such datagrams.
+
+ To minimize the amount of ARCNET fragmentation, implementations may
+ want to aim at an optimum IP packet size of 504 bytes. This avoids
+ the overhead of datalink fragmentation, but at the expense of
+ increasing the number of IP packets which must be handled by each
+ node in the path. In addition to encouraging local applications to
+ generate smaller packets, an implementation might also use the TCP
+ maximum segment size option to indicate a desire for 464 octet TCP
+ segments [7], or it might announce an IP MTU of 504 octets through
+ an MTU discovery mechanism such as [8]. These would inform non-
+ ARCNET nodes of the smaller optimum packet size.
+
+8. Assigned Numbers
+
+ Datapoint Corporation assigns ARCNET protocol IDs to identify
+ different protocols running on the same ARCNET medium. For
+ implementations of this specification, Datapoint has assigned 212
+ decimal to IP, 213 decimal to ARP, and 214 decimal to RARP. These
+ are not the numbers assigned to the IP encapsulation defined by RFC
+ 1051 [5]. Implementations of RFC 1051 can exist on the same ARCNET
+ as implementations of this specification, although the two would not
+ be able to communicate with each other.
+
+ The Internet Assigned Numbers Authority (IANA) assigns ARP hardware
+ type values. It has assigned ARCNET the ARP hardware type of 7 [9].
+
+Acknowledgements
+
+ Several people have reviewed this specification and provided useful
+ input. I'd like to thank Wesley Hardell at Datapoint and Troy Thomas
+ at Novell's Provo office for helping me figure out ARCNET. In
+ addition, I particularly appreciate the effort by James VanBokkelen
+ at FTP Software who picked on me until all the fuzzy edges were
+
+
+
+Provan [Page 6]
+
+RFC 1201 IP on ARCNET February 1991
+
+
+ smoothed out.
+
+ The pioneering work in transmitting IP traffic on ARCNET networks was
+ done by Philippe Prindeville.
+
+References
+
+ [1] Postel, J., "Internet Protocol", RFC 791, DARPA, September 1981.
+
+ [2] Plummer, D., "An Ethernet Address Resolution Protocol", RFC 826,
+ MIT, November 1982.
+
+ [3] Datapoint, Corp., "ARCNET Designer's Handbook", Document Number
+ 61610, 2nd Edition, Datapoint Corporation, 1988.
+
+ [4] Novell, Inc., "ARCNET Packet Header Definition Standard", Novell,
+ Inc., November 1989.
+
+ [5] Prindeville, P., "A Standard for the Transmission of IP Datagrams
+ and ARP Packets over ARCNET Networks", RFC 1051, McGill
+ University, March 1988.
+
+ [6] Finlayson, R., Mann, T., Mogul, J., and M. Theimer, "A Reverse
+ Address Resolution Protocol", RFC 903, Stanford, June 1984.
+
+ [7] Postel, J., "Transmission Control Protocol", RFC 793, DARPA,
+ September 1981.
+
+ [8] Mogul, J., Kent, C., Partridge, C., and K. McCloghrie, "IP MTU
+ Discovery Options", RFC 1063, DEC, BBN, TWG, July 1988.
+
+ [9] Reynolds, J., and J. Postel, "Assigned Numbers", RFC 1060,
+ USC/Information Sciences Institute, March 1990.
+
+Security Considerations
+
+ Security issues are not discussed in this memo.
+
+Author's Address
+
+ Don Provan
+ Novell, Inc.
+ 2180 Fortune Drive
+ San Jose, California, 95131
+
+ Phone: (408) 473-8440
+ EMail: donp@Novell.Com
+
+
+
+
+Provan [Page 7]
diff --git a/private/ntos/ndis/testprot/inc/common.h b/private/ntos/ndis/testprot/inc/common.h
new file mode 100644
index 000000000..eccf084b3
--- /dev/null
+++ b/private/ntos/ndis/testprot/inc/common.h
@@ -0,0 +1,835 @@
+// -------------------------------------
+//
+// Copyright (c) 1991 Microsoft Corporation
+//
+// Module Name:
+//
+// common.h
+//
+// Abstract:
+//
+// Common definitions for Test Protocol driver and its control application.
+//
+// Author:
+//
+// Tomad Adams (tomad) 11-Mar-1991
+//
+// Environment:
+//
+// Kernel mode, FSD
+//
+// Revision History:
+//
+// Sanjeev Katariya (sanjeevk)
+// 4-19-1993 Added support for varying address length dependent on the media type
+// Effected the structure CMD_ARGS
+//
+// Tim Wynsma (timothyw)
+// 4-27-1994 Added support for performance testing
+// 5-18-1994 1st round, global variable access
+// 6-08-1994 Client-server model for performance tests
+//
+// -----------------------------------
+
+
+#include "defaults.h"
+
+//
+// Define the type of member that the protocol will be running as.
+//
+// As a CLIENT the protocol is responsible for initiating the test,
+// controlling the flow of the test, and keeping results. A SERVER
+// merely loops packets back to the CLIENT in the manner specified
+// by the test arguments. A protocol may act as BOTH a CLIENT and a
+// Server.
+//
+
+typedef enum _MEMBER_TYPE {
+ TP_CLIENT,
+ TP_SERVER,
+ BOTH
+} MEMBER_TYPE;
+
+//
+// Define the size of packets to be used in a test.
+//
+// Fixedsize means the all packets in the test will be of a fixedsize
+// X, Randomsize means the all packets in the test will randomly range
+// between a minimum packetsize and X, Cyclical means that packets of
+// every size will be sent start at a minimum size and walking through
+// all sizes until the maximum packetsize for the given media type
+// has been reached.
+//
+
+typedef enum _PACKET_TYPE {
+ FIXEDSIZE,
+ RANDOMSIZE,
+ CYCLICAL
+} PACKET_TYPE;
+
+
+//
+// Define the different sizes of buffers a packet made be constructed with.
+//
+// Rand means the size of each buffer will be randomly selected from a
+// range of zero to a , Small means the size of each buffer will be randomly
+// selected from a range of zero to , Zeros and Ones mean that the size
+// of each buffer will be selected the same way as Rand, however the will
+// be a large number of zero or one byte buffers intersperced in each
+// packet. Known means the each buffer in the packet is the same size.
+//
+
+typedef enum _PACKET_MAKEUP {
+ RAND,
+ SMALL,
+ ZEROS,
+ ONES,
+ KNOWN
+} PACKET_MAKEUP;
+
+//
+// Define the method the Server will use to respond to each packet the
+// CLIENT sends.
+//
+// No Response means the Server will never respond to the packets from the
+// CLIENT, Full Response means the server will respond to every packet the
+// CLIENT sends with a packet of the same size and data, Ack Every means the
+// Server will send an acknowlegement packet after every from the CLIENT, Ack
+// Every 10 means the Server will send an acknowlegement packet after every
+// 10th packet from the CLIENT, Ack 10 Times means the Server will send 10
+// acknowlegement packets for every packet the CLIENT sends.
+//
+
+typedef enum _RESPONSE_TYPE {
+ FULL_RESPONSE,
+ ACK_EVERY,
+ ACK_10_TIMES,
+ NO_RESPONSE
+} RESPONSE_TYPE;
+
+//
+// Define the delay between two consecutive packet sends to a given Server.
+//
+// The delay will either be a fixed number of iterations, or a random
+// number of iterations. NOTE: That this will be changing to a fixed
+// or random length of time in the future.
+//
+
+typedef enum _INTERPACKET_DELAY {
+ FIXEDDELAY,
+ RANDOMDELAY
+} INTERPACKET_DELAY;
+
+
+//
+// Registry typedefs.
+//
+
+//
+// Define the operation being asked to execute on the registry
+//
+
+typedef enum _OPERATION {
+ ADD_KEY,
+ DELETE_KEY,
+ QUERY_KEY,
+ ADD_VALUE,
+ CHANGE_VALUE,
+ DELETE_VALUE,
+ QUERY_VALUE
+} OPERATION;
+
+//
+// Define the 4 possible registry DataBases
+//
+
+typedef enum _KEYDBASE {
+ CLASSES_ROOT,
+ CURRENT_USER,
+ LOCAL_MACHINE,
+ USERS
+} KEYDBASE;
+
+//
+// Define the various types a value can be
+//
+
+typedef enum _VALUETYPE {
+ BINARY,
+ DWORD_REGULAR,
+ DWORD_LITTLE_ENDIAN,
+ DWORD_BIG_ENDIAN,
+ EXPAND_SZ,
+ LINK,
+ MULTI_SZ,
+ NONE,
+ RESOURCE_LIST,
+ SZ
+} VALUETYPE;
+
+//
+// Tpctl Command Codes
+//
+
+#define CMD_ERR 0x00000000 // an invalid command was entered.
+#define GETSTATS 0x00000001 // get the test statistics.
+#define DISPSTATS 0x00000002 // continuously get test statistics.
+#define VERBOSE 0x00000003 // toggle verbose mode on and off.
+#define SETENV 0x00000004 // set the driver's test environment vars.
+#define READSCRIPT 0x00000005 // read a script file.
+#define BEGINLOGGING 0x00000006 // begin logging command line cmds.
+#define ENDLOGGING 0x00000007 // end logging command line cmds.
+#define WAIT 0x00000008 // wait for X msecs.
+#define GO 0x00000009 // Tell remote protocol to continue.
+#define PAUSE 0x0000000A // Pause the local protocol.
+#define LOAD 0x0000000B // call NtLoad to load a driver
+#define UNLOAD 0x0000000C // call NtUnload to unload a driver
+#define OPEN 0x0000000D // open a MAC adapter.
+#define CLOSE 0x0000000E // close a MAC adapter.
+#define SETPF 0x0000000F // set the packet filter on the MAC.
+#define SETLA 0x00000010 // set the lookahead buffer size.
+#define DELMA 0x00000011 // del a multicast address from the MAC.
+#define ADDMA 0x00000012 // add a multicast address to the MAC.
+#define SETFA 0x00000013 // set a functional address on the MAC.
+#define SETGA 0x00000014 // set a group address on the MAC.
+#define QUERYINFO 0x00000015 // query MAC information.
+#define QUERYSTATS 0x00000016 // query GLOBAL MAC information.
+#define SETINFO 0x00000017 // set MAC information.
+#define RESET 0x00000018 // reset the MAC adapter.
+#define SEND 0x00000019 // send a packet or packets.
+#define STOPSEND 0x0000001A // stop sending packets.
+#define WAITSEND 0x0000001B // wait for send to end, display results.
+#define RECEIVE 0x0000001C // start accepting packets.
+#define STOPREC 0x0000001D // stop accepting packets.
+#define GETEVENTS 0x0000001E // get events off the EVENT_QUEUE.
+#define STRESS 0x0000001F // run a stress test, (CLIENT or BOTH).
+#define STRESSSERVER 0x00000020 // act as a SERVER for a stress test.
+#define ENDSTRESS 0x00000021 // end a stress test.
+#define WAITSTRESS 0x00000022 // wait for stress to end, display results.
+#define CHECKSTRESS 0x00000023 // see if stress has ended, if so display
+#define BREAKPOINT 0x00000024 // call DbgBreakPoint.
+#define QUIT 0x00000025 // quit TPCTL.EXE.
+#define HELP 0x00000026 // print the help screen
+
+//
+// New Tpctl Command Codes
+//
+
+#define SHELL 0x00000027
+#define RECORDINGENABLE 0x00000028
+#define RECORDINGDISABLE 0x00000029
+#define DISABLE 0x0000002A
+#define ENABLE 0x0000002B
+#define REGISTRY 0x0000002C
+
+// performance testing
+
+#define PERFSERVER 0x0000002D
+#define PERFCLIENT 0x0000002E
+#define PERFABORT 0x0000002F // only used in TP_CONTROL_CODE call
+
+// globalvars
+
+#define SETGLOBAL 0x00000030
+
+
+#define CMD_COMPLETED 0xFFFFFFFF // skip the second half of cmd processing.
+
+
+
+//
+// NtDeviceIoControlFile IoControlCode values for this device.
+//
+// Warning: Remember that the low two bits of the code represent the
+// method, and specify how the input and output buffers are
+// passed to the driver via NtDeviceIoControlFile()
+//
+//
+
+#define IOCTL_METHOD 2
+
+#define IOCTL_TP_BASE FILE_DEVICE_TRANSPORT
+
+#define TP_CONTROL_CODE(request,method) \
+ ((IOCTL_TP_BASE)<<16 | (request<<2) | method)
+
+
+#define IOCTL_TP_GETSTATS TP_CONTROL_CODE( GETSTATS, IOCTL_METHOD )
+#define IOCTL_TP_DISPSTATS TP_CONTROL_CODE( DISPSTATS, IOCTL_METHOD )
+#define IOCTL_TP_SETENV TP_CONTROL_CODE( SETENV, IOCTL_METHOD )
+#define IOCTL_TP_GO TP_CONTROL_CODE( GO, IOCTL_METHOD )
+#define IOCTL_TP_PAUSE TP_CONTROL_CODE( PAUSE, IOCTL_METHOD )
+#define IOCTL_TP_OPEN TP_CONTROL_CODE( OPEN, IOCTL_METHOD )
+#define IOCTL_TP_CLOSE TP_CONTROL_CODE( CLOSE, IOCTL_METHOD )
+#define IOCTL_TP_SETPF TP_CONTROL_CODE( SETPF, IOCTL_METHOD )
+#define IOCTL_TP_SETLA TP_CONTROL_CODE( SETLA, IOCTL_METHOD )
+#define IOCTL_TP_ADDMA TP_CONTROL_CODE( ADDMA, IOCTL_METHOD )
+#define IOCTL_TP_DELMA TP_CONTROL_CODE( DELMA, IOCTL_METHOD )
+#define IOCTL_TP_SETFA TP_CONTROL_CODE( SETFA, IOCTL_METHOD )
+#define IOCTL_TP_SETGA TP_CONTROL_CODE( SETGA, IOCTL_METHOD )
+#define IOCTL_TP_QUERYINFO TP_CONTROL_CODE( QUERYINFO, IOCTL_METHOD )
+#define IOCTL_TP_QUERYSTATS TP_CONTROL_CODE( QUERYSTATS, IOCTL_METHOD )
+#define IOCTL_TP_SETINFO TP_CONTROL_CODE( SETINFO, IOCTL_METHOD )
+#define IOCTL_TP_RESET TP_CONTROL_CODE( RESET, IOCTL_METHOD )
+#define IOCTL_TP_SEND TP_CONTROL_CODE( SEND, IOCTL_METHOD )
+#define IOCTL_TP_STOPSEND TP_CONTROL_CODE( STOPSEND, IOCTL_METHOD )
+#define IOCTL_TP_RECEIVE TP_CONTROL_CODE( RECEIVE, IOCTL_METHOD )
+#define IOCTL_TP_STOPREC TP_CONTROL_CODE( STOPREC, IOCTL_METHOD )
+#define IOCTL_TP_GETEVENTS TP_CONTROL_CODE( GETEVENTS, IOCTL_METHOD )
+#define IOCTL_TP_STRESS TP_CONTROL_CODE( STRESS, IOCTL_METHOD )
+#define IOCTL_TP_STRESSSERVER TP_CONTROL_CODE( STRESSSERVER, IOCTL_METHOD )
+#define IOCTL_TP_ENDSTRESS TP_CONTROL_CODE( ENDSTRESS, IOCTL_METHOD )
+#define IOCTL_TP_BREAKPOINT TP_CONTROL_CODE( BREAKPOINT, IOCTL_METHOD )
+#define IOCTL_TP_TRANSFERDATA TP_CONTROL_CODE( TRANSFERDATA, IOCTL_METHOD )
+#define IOCTL_TP_QUIT TP_CONTROL_CODE( QUIT, IOCTL_METHOD )
+
+// performance testing
+
+#define IOCTL_TP_PERF_SERVER TP_CONTROL_CODE( PERFSERVER, IOCTL_METHOD)
+#define IOCTL_TP_PERF_CLIENT TP_CONTROL_CODE( PERFCLIENT, IOCTL_METHOD)
+#define IOCTL_TP_PERF_ABORT TP_CONTROL_CODE( PERFABORT, IOCTL_METHOD)
+
+//
+// The following structure contains the arguments passed
+// to the driver for each of the commands.
+//
+// NOTE: Any additions to arguments in this structure must
+// be mapped in the parse options structure TESTPARAMS for
+// the given command, and in the TpctlInitCommandBuffer
+// routine for the given command.
+//
+// Current types of addresses in use
+//
+// 1. STATION ADDRESS 2. STRESS MULTICAST ADDRESS
+// 3. PAUSE_GO REMOTE ADDRESS 4 MULTICAST ADDRESS
+// 5. GROUP ADDRESS 6. FUNCTIONAL ADDRESS
+// 7. DESTINATION ADDRESS 8. RESEND ADDRESS
+//
+// These can all be classified under two headings
+//
+// CURRENT ADDRESS LENGTHS(SOURCE, DESTINATION) and
+// FUNCTIONAL/GROUP ADDRESS LENGTHS which are dependencies of the first category.
+//
+// Functional address length will always be (CURRENT_ADDRESS_LEN*10)/15
+// e.g. When the address length is 6, FA's are 4
+// WHen the address length is 2, FA's are 1
+//
+#define TPCTL_OPTION_SIZE 14
+
+typedef struct _CMD_ARGS {
+
+ ULONG CmdCode;
+ ULONG OpenInstance;
+
+
+
+ union _ARGS {
+
+ //
+ // SETENV command environment variable arguments.
+ //
+
+ struct _ENV {
+
+ ULONG WindowSize;
+ ULONG RandomBufferNumber;
+ UCHAR StressAddress[ADDRESS_LENGTH];
+ UCHAR ResendAddress[ADDRESS_LENGTH];
+ ULONG StressDelayInterval;
+ ULONG UpForAirDelay;
+ ULONG StandardDelay;
+
+ } ENV;
+
+ //
+ // READSCRIPT script and logging file arguments.
+ //
+
+ struct _FILES {
+
+ UCHAR ScriptFile[MAX_FILENAME_LENGTH];
+ UCHAR LogFile[MAX_FILENAME_LENGTH];
+
+ } FILES;
+
+ //
+ // RECORDING script file
+ //
+
+ struct _RECORD {
+
+ UCHAR ScriptFile[MAX_FILENAME_LENGTH];
+
+ } RECORD;
+
+ //
+ // Registry operations
+ //
+
+ struct _REGISTRY_ENTRY {
+
+ UCHAR SubKey[MAX_KEYNAME_LENGTH] ;
+ UCHAR SubKeyClass[MAX_CLASS_LENGTH] ;
+ UCHAR SubKeyValueName[MAX_VALUENAME_LENGTH] ;
+ UCHAR SubKeyValue[MAX_VALUE_LENGTH] ;
+ OPERATION OperationType;
+ KEYDBASE KeyDatabase ;
+ VALUETYPE ValueType ;
+
+ } REGISTRY_ENTRY;
+
+ //
+ // PAUSE and GO protocol arguments.
+ //
+
+ struct _PAUSE_GO {
+
+ UCHAR RemoteAddress[ADDRESS_LENGTH];
+ ULONG TestSignature;
+ ULONG UniqueSignature;
+
+ } PAUSE_GO;
+
+ //
+ // OPEN command adapter name argument.
+ //
+
+ struct _OPEN_ADAPTER
+ {
+ UCHAR AdapterName[MAX_ADAPTER_NAME_LENGTH];
+ BOOLEAN NoArcNet;
+ } OPEN_ADAPTER;
+
+ UCHAR DriverName[MAX_ADAPTER_NAME_LENGTH];
+
+ //
+ // QUERYINFO command information OID.
+ //
+
+ struct _TPQUERY {
+
+ NDIS_OID OID;
+ //NDIS_REQUEST_TYPE RequestType;
+
+ } TPQUERY;
+
+ //
+ // QUERYSTATS command Device name and OID to query.
+ //
+
+ struct _TPQUERYSTATS {
+
+ UCHAR DeviceName[MAX_ADAPTER_NAME_LENGTH];
+ NDIS_OID OID;
+
+ } TPQUERYSTATS;
+
+ //
+ // SETINFO command information class and info.
+ //
+
+ struct _TPSET {
+
+ NDIS_OID OID;
+
+ union _U {
+
+ ULONG PacketFilter;
+ ULONG LookaheadSize;
+ UCHAR MulticastAddress[MAX_MULTICAST_ADDRESSES][ADDRESS_LENGTH];
+ UCHAR FunctionalAddress[FUNCTIONAL_ADDRESS_LENGTH];
+ UCHAR GroupAddress[FUNCTIONAL_ADDRESS_LENGTH];
+
+ } U;
+
+ ULONG NumberMultAddrs;
+
+ } TPSET;
+
+ //
+ // SEND command packet definitions.
+ //
+
+ struct _TPSEND {
+
+ UCHAR DestAddress[ADDRESS_LENGTH];
+ ULONG PacketSize;
+ ULONG NumberOfPackets;
+ UCHAR ResendAddress[ADDRESS_LENGTH];
+
+ } TPSEND;
+
+ //
+ // PERFSEND command packet definitions
+ //
+
+ struct _TPPERF
+ {
+ UCHAR PerfServerAddr[ADDRESS_LENGTH];
+ UCHAR PerfSendAddr[ADDRESS_LENGTH];
+ ULONG PerfPacketSize;
+ ULONG PerfNumPackets;
+ ULONG PerfDelay;
+ ULONG PerfMode;
+ } TPPERF;
+
+ //
+ // STRESS command test arguments.
+ //
+
+ struct _TPSTRESS {
+
+ MEMBER_TYPE MemberType;
+ PACKET_TYPE PacketType;
+ ULONG PacketSize;
+ PACKET_MAKEUP PacketMakeUp;
+ RESPONSE_TYPE ResponseType;
+ INTERPACKET_DELAY DelayType;
+ ULONG DelayLength;
+ ULONG TotalIterations;
+ ULONG TotalPackets;
+ ULONG WindowEnabled;
+ ULONG DataChecking;
+ ULONG PacketsFromPool;
+ UCHAR AdapterName[MAX_ADAPTER_NAME_LENGTH];
+
+ } TPSTRESS;
+
+ //
+ // HELP Command to print the help message for.
+ //
+
+ UCHAR CmdName[MAX_FILENAME_LENGTH];
+
+ } ARGS;
+
+
+ //
+ // STARTCHANGE
+ //
+ UCHAR CurrentAddressLength;
+ UCHAR CurrentFALength;
+
+ UCHAR TpctlOptions[TPCTL_OPTION_SIZE];
+ //
+ // STOPCHANGE
+ //
+
+} CMD_ARGS, *PCMD_ARGS;
+
+//
+// User App command data struct to hold per command info.
+//
+
+typedef struct _CMD_CODE {
+ ULONG CmdCode;
+ PSZ CmdName;
+ PSZ CmdAbbr;
+} CMD_CODE, * PCMD_CODE;
+
+#define NUM_COMMANDS sizeof( CommandCode ) / sizeof( CommandCode[0] )
+
+//
+// Set Environment Command Variables
+//
+
+typedef struct _ENVIRONMENT_VARIABLES {
+ ULONG WindowSize;
+ ULONG RandomBufferNumber;
+ UCHAR StressAddress[ADDRESS_LENGTH];
+ UCHAR ResendAddress[ADDRESS_LENGTH];
+ ULONG StressDelayInterval;
+ ULONG UpForAirDelay;
+ ULONG StandardDelay;
+ ULONG MulticastListSize;
+} ENVIRONMENT_VARIABLES, * PENVIRONMENT_VARIABLES;
+
+//
+// The pointers to these structures need to be defined as UNALIGNED for MIPS.
+//
+
+//
+// Counters used to measure performance and results of a test run.
+//
+
+typedef struct _GLOBAL_COUNTERS {
+ ULONG Sends;
+ ULONG SendComps;
+ ULONG Receives;
+ ULONG ReceiveComps;
+ ULONG CorruptRecs;
+ ULONG InvalidPacketRecs;
+} GLOBAL_COUNTERS;
+typedef GLOBAL_COUNTERS UNALIGNED *PGLOBAL_COUNTERS;
+
+//
+// Counters for a given Open Instance
+//
+
+typedef struct _INSTANCE_COUNTERS {
+ ULONG Sends;
+ ULONG SendPends;
+ ULONG SendComps;
+ ULONG SendFails;
+
+ ULONG Receives;
+ ULONG ReceiveComps;
+ ULONG CorruptRecs;
+ ULONG XferData;
+
+ ULONG XferDataPends;
+ ULONG XferDataComps;
+ ULONG XferDataFails;
+} INSTANCE_COUNTERS;
+typedef INSTANCE_COUNTERS UNALIGNED *PINSTANCE_COUNTERS;
+
+//
+// The following data structure are use to pass specific test results
+// up to the application from the driver.
+//
+
+typedef struct _SERVER_RESULTS {
+ ULONG Signature;
+ UCHAR Address[ADDRESS_LENGTH];
+ ULONG OpenInstance;
+ BOOLEAN StatsRcvd;
+ INSTANCE_COUNTERS Instance;
+ INSTANCE_COUNTERS S_Instance;
+ GLOBAL_COUNTERS S_Global;
+} SERVER_RESULTS, *PSERVER_RESULTS;
+
+#define MAX_SERVERS 10
+
+typedef struct _STRESS_RESULTS {
+ ULONG Signature;
+ UCHAR Address[ADDRESS_LENGTH];
+ ULONG OpenInstance;
+ ULONG NumServers;
+ ULONG PacketsPerSecond;
+ GLOBAL_COUNTERS Global;
+ SERVER_RESULTS Servers[MAX_SERVERS];
+} STRESS_RESULTS, *PSTRESS_RESULTS;
+
+typedef struct _SEND_RECEIVE_RESULTS {
+ ULONG Signature;
+ BOOLEAN ResultsExist;
+ INSTANCE_COUNTERS Counters;
+} SEND_RECEIVE_RESULTS, *PSEND_RECEIVE_RESULTS;
+
+typedef struct _PERF_RESULTS
+{
+ ULONG Signature;
+ BOOLEAN ResultsExist;
+ ULONG Mode;
+ ULONG PacketSize;
+ ULONG PacketCount;
+ ULONG Milliseconds;
+ ULONG Sends;
+ ULONG SendFails;
+ ULONG Receives;
+ ULONG Restarts;
+ ULONG SelfReceives;
+ ULONG S_Milliseconds;
+ ULONG S_Sends;
+ ULONG S_SendFails;
+ ULONG S_Receives;
+ ULONG S_Restarts;
+ ULONG S_SelfReceives;
+} PERF_RESULTS, *PPERF_RESULTS;
+
+
+typedef enum _TP_EVENT_TYPE {
+ CompleteOpen,
+ CompleteClose,
+ CompleteSend,
+ CompleteTransferData,
+ CompleteReset,
+ CompleteRequest,
+ IndicateReceive,
+ IndicateReceiveComplete,
+ IndicateStatus,
+ IndicateStatusComplete,
+ Unknown
+} TP_EVENT_TYPE;
+
+typedef struct _EVENT_RESULTS {
+ ULONG Signature;
+ TP_EVENT_TYPE TpEventType;
+ BOOLEAN QueueOverFlowed;
+ //TP_EVENT_INFO TpEventInfo;
+} EVENT_RESULTS, * PEVENT_RESULTS;
+
+typedef struct _REQUEST_RESULTS {
+ ULONG Signature;
+ ULONG IoControlCode;
+ BOOLEAN RequestPended;
+ NDIS_STATUS RequestStatus;
+ NDIS_REQUEST_TYPE NdisRequestType;
+ NDIS_OID OID;
+ UINT BytesReadWritten;
+ UINT BytesNeeded;
+ NDIS_STATUS OpenRequestStatus;
+ UINT InformationBufferLength;
+ UCHAR InformationBuffer[1];
+} REQUEST_RESULTS, *PREQUEST_RESULTS;
+
+#define IOCTL_BUFFER_SIZE 0x200
+
+#define OPEN_RESULTS_SIGNATURE 0x12345678
+#define CLOSE_RESULTS_SIGNATURE 0x23456789
+#define RESET_RESULTS_SIGNATURE 0x34567890
+#define REQUEST_RESULTS_SIGNATURE 0x45678901
+
+#define EVENT_RESULTS_SIGNATURE 0x56789012
+#define SENDREC_RESULTS_SIGNATURE 0x67890123
+#define STRESS_RESULTS_SIGNATURE 0x89012345
+#define PERF_RESULTS_SIGNATURE 0x90123456
+
+//
+// Create two sets of debug macros to allow printing of debug messages,
+// and enabling ASSERT that will be checking the values and pointers
+// returned by the various ndis indications, and completions.
+//
+
+#if DBG
+
+#define IF_TPDBG(flags) \
+ if ( TpDebug & ( flags ))
+
+#define TP_ASSERT(equality) { \
+ if (!(equality)) { \
+ TpPrint0("ASSERT: "); \
+ TpPrint0(#equality); \
+ TpBreakPoint(); } }
+//
+//
+// if ( TpAssert == TRUE ) {
+// ASSERT(equality);
+// }
+// }
+
+//
+// DEBUGGING SUPPORT. IF_TPDBG is a macro that is turned on at compile
+// time to enable debugging code in the system. If this is turned on, then
+// you can use the IF_TPDBG(flags) macro in the TP code to selectively
+// enable a piece of debugging code in the transport. This macro tests
+// TpDebug, a global ULONG defined in TPDRVR.C.
+//
+
+#define TP_DEBUG_NDIS_CALLS 0x00000001 // print Ndis Status returns
+#define TP_DEBUG_NDIS_ERROR 0x00000002 // print Ndis Error returns
+#define TP_DEBUG_STATISTICS 0x00000004 // print stress statistics
+#define TP_DEBUG_DATA 0x00000008 // print Data Corruption msgs
+
+#define TP_DEBUG_DISPATCH 0x00000010 // TpDispatch routines
+#define TP_DEBUG_IOCTL_ARGS 0x00000020 // print args from the ioctl
+
+#define TP_DEBUG_NT_STATUS 0x00000100 // print !success NT Status returns
+#define TP_DEBUG_DPC 0x00000200 // print DPC problem info
+#define TP_DEBUG_INITIALIZE 0x00000400 // print init error info
+#define TP_DEBUG_RESOURCES 0x00000800 // print resource allocation errors
+
+#define TP_DEBUG_BREAKPOINT 0x00001000 // enable and disable DbgBreakPoints
+
+#define TP_DEBUG_INFOLEVEL_1 0x00010000 // print information. Level 1
+#define TP_DEBUG_INFOLEVEL_2 0x00020000 // through 4 represent different
+#define TP_DEBUG_INFOLEVEL_3 0x00040000 // types of information where
+#define TP_DEBUG_INFOLEVEL_4 0x00080000 // Level 1 is purely informational
+ // Level 2 is corrective action information
+ // Level 3 is sequential action information
+ // Level 4 Reserved. Currently undefined.
+
+#define TP_DEBUG_ALL 0xFFFFFFFF // turns on all flags
+
+extern ULONG TpDebug; // in TPDRVR.C.
+extern BOOLEAN TpAssert; // in TPDRVR.C.
+
+#define TpPrint0(fmt) DbgPrint(fmt)
+#define TpPrint1(fmt,v1) DbgPrint(fmt,v1)
+#define TpPrint2(fmt,v1,v2) DbgPrint(fmt,v1,v2)
+#define TpPrint3(fmt,v1,v2,v3) DbgPrint(fmt,v1,v2,v3)
+#define TpPrint4(fmt,v1,v2,v3,v4) DbgPrint(fmt,v1,v2,v3,v4)
+#define TpPrint5(fmt,v1,v2,v3,v4,v5) DbgPrint(fmt,v1,v2,v3,v4,v5)
+#define TpPrint6(fmt,v1,v2,v3,v4,v5,v6) DbgPrint(fmt,v1,v2,v3,v4,v5,v6)
+
+#define TpBreakPoint() DbgBreakPoint()
+
+#else // NO DBG
+
+//
+// Disable debugging IFs and printing
+//
+
+#define IF_TPDBG(flags) \
+ if (0)
+
+#define TP_ASSERT(equality) \
+ if (0)
+
+#define TpPrint0(fmt)
+#define TpPrint1(fmt,v1)
+#define TpPrint2(fmt,v1,v2)
+#define TpPrint3(fmt,v1,v2,v3)
+#define TpPrint4(fmt,v1,v2,v3,v4)
+#define TpPrint5(fmt,v1,v2,v3,v4,v5)
+#define TpPrint6(fmt,v1,v2,v3,v4,v5,v6)
+
+#define TpBreakPoint()
+
+#endif // DBG
+
+//
+// define null packet type for command line interface
+//
+
+#define NDIS_PACKET_TYPE_NONE 0x00
+
+
+//
+// Test Protocol Status Returns
+//
+
+//
+// No stress servers found for a stress test.
+//
+
+#define TP_STATUS_NO_SERVERS ((NDIS_STATUS)0x4001FFFFL)
+
+//
+// No events on the event queue.
+//
+
+#define TP_STATUS_NO_EVENTS ((NDIS_STATUS)0x4001FFFEL)
+
+//
+// Go or Pause Timed out with out receiving correct response.
+//
+
+#define TP_STATUS_TIMEDOUT ((NDIS_STATUS)0x4001FFFDL)
+
+//
+// OID Info structure containing the size of the oid info and what
+// the valid uses of the structure are: i.e. querying and setting
+// info for that OID.
+//
+
+typedef struct _OID_INFO {
+ NDIS_OID Oid;
+ ULONG Length;
+ BOOLEAN QueryInfo;
+ BOOLEAN SetInfo;
+ BOOLEAN QueryStats;
+} OID_INFO, * POID_ONFO;
+
+extern OID_INFO OidArray[];
+
+#define NUM_OIDS sizeof( OidArray ) / sizeof( OidArray[0] )
+
+ULONG
+TpLookUpOidInfo(
+ IN NDIS_OID RequestOid
+ );
+
+
+
+
diff --git a/private/ntos/ndis/testprot/inc/defaults.h b/private/ntos/ndis/testprot/inc/defaults.h
new file mode 100644
index 000000000..19f9d6cd9
--- /dev/null
+++ b/private/ntos/ndis/testprot/inc/defaults.h
@@ -0,0 +1,193 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ defaults.h
+
+Abstract:
+
+ Default definitions for Test Protocol driver and its control application.
+
+Author:
+
+ Tomad Adams (tomad) 7-Nov-1991
+
+ Sanjeev Katariya (sanjeevk) 4-6-1993
+ Added support for native ARCNET
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+--*/
+
+//
+// The number of Open Instances the Test Protocol will support
+//
+
+#define NUM_OPEN_INSTANCES 8
+
+//
+//
+//
+
+static UCHAR NULL_ADDRESS[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+static UCHAR STRESS_MULTICAST[] = { 0x07, 0x07, 0x07, 0x07, 0x07, 0x07 };
+
+static UCHAR DEFAULT_MULTICAST[] = { 0x07, 0x12, 0x34, 0x56, 0x78, 0x90 };
+
+static UCHAR STRESS_FUNCTIONAL[] = { 0xC0, 0x00, 0x00, 0x01, 0x00, 0x00 };
+
+static UCHAR DEFAULT_FUNCTIONAL[] = { 0xC0, 0x00, 0x12, 0x23, 0x34, 0x45 };
+
+static UCHAR STRESS_ARCNET_BROADCAST[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+
+//
+// Device Name - this string is the name of the device. It is the name
+// that should be passed to NtOpenFile when accessing the device.
+//
+// Note: For devices that support multiple units, it should be suffixed
+// with the Ascii representation of the unit number.
+//
+
+#define DD_TP_DEVICE_NAME "\\Device\\TestProtocol"
+
+//
+// TPCTL Defaults
+//
+
+//
+// The symbolic link for the test protocol device driver
+// name for win32 apis
+//
+
+#define DEVICE_NAME "\\\\.\\Tpdrvr"
+
+#define TPCTL_CMDLINE_SIZE 0x200
+
+#define TPCTL_MAX_ARGC 20
+
+#define TPCTL_PROMPT "[TPCTL:]"
+
+#define TPCTL_MAX_PATHNAME_SIZE 256
+
+#define ADDRESS_LENGTH 6
+
+//
+// STARTCHANGE
+//
+#define ADDRESS_LENGTH_1_OCTET 1
+
+#define ADDRESS_LENGTH_2_OCTETS 2
+//
+// STOPCHANGE
+//
+
+
+#define MAX_MULTICAST_ADDRESSES 64
+
+#define FUNCTIONAL_ADDRESS_LENGTH 4
+
+#define GROUP_ADDRESS_LENGTH 4
+
+#define MAX_FILENAME_LENGTH 256
+
+#define MAX_ADAPTER_NAME_LENGTH 32
+
+#define MAX_DRIVER_NAME_LENGTH 32
+
+#define MAX_KEYNAME_LENGTH 256
+
+#define MAX_CLASS_LENGTH 80
+
+#define MAX_VALUENAME_LENGTH 256
+
+#define MAX_VALUE_LENGTH 1024
+
+
+
+//
+// STARTCHANGE
+//
+#define ARCNET_DEFAULT_PROTOCOLID 0xE7
+//
+// STOPCHANGE
+//
+
+//
+// Time definitions to be used by the driver in calls to KeSetTimer.
+// These times are hard coded in the driver in some cases, or passed
+// down to the driver via the SETENV call in others.
+//
+
+#define ONE_HUNDREDTH_SECOND 100000
+#define ONE_TENTH_SECOND ( 10 * ONE_HUNDREDTH_SECOND )
+#define ONE_SECOND ( 100 * ONE_HUNDREDTH_SECOND )
+#define ONE_MINUTE ( 600 * ONE_HUNDREDTH_SECOND )
+
+
+//
+// TPCTL default command argument values
+//
+
+#define OPEN_INSTANCE 1
+
+#define TPCTL_SCRIPTFILE "TESTPROT.TPS"
+
+#define TPCTL_LOGFILE "TESTPROT.LOG"
+
+#define TPCTL_CMDLINE_LOG "CMDLINE.LOG"
+
+#define TPCTL_CMDLINE_SCRIPT "CMDLINE.TPS"
+
+#define RESEND_ADDRESS "ResendAddress"
+
+#define LOCAL_ADDRESS "LocalAddress"
+
+#define ADAPTER_NAME "ELNKII"
+
+#define LOOKAHEADSIZE 0x64
+
+#define PACKET_SIZE 0x200
+
+#define DELAY_LENGTH 0
+
+#define STRESS_ITERATIONS -1
+
+#define STRESS_PACKETS -1
+
+#define WINDOWING_ENABLED "TRUE"
+
+#define DATA_CHECKING "TRUE"
+
+#define PACKETS_FROM_POOL "TRUE"
+
+
+//
+// TPCTL default environment variable values
+//
+
+#define WINDOW_SIZE 10
+
+#define BUFFER_NUMBER 5
+
+#define DELAY_INTERVAL 10
+
+#define UP_FOR_AIR_DELAY 100000
+
+#define STANDARD_DELAY 10000
+
+//
+// Window control defines
+//
+
+#define MAX_PACKET_DELAY 100 // XXX: is this the correct size?
+
+#define MAX_WINDOW_RESETS 3
+
diff --git a/private/ntos/ndis/testprot/tpctl/cmd.c b/private/ntos/ndis/testprot/tpctl/cmd.c
new file mode 100644
index 000000000..ec5ca1465
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpctl/cmd.c
@@ -0,0 +1,4160 @@
+// --------------------------------------------------------------------
+//
+// Copyright (c) 1991 Microsoft Corporation
+//
+// Module Name:
+//
+// cmd.c
+//
+// Abstract:
+//
+//
+//
+// Author:
+//
+// Tom Adams (tomad) 11-May-1991
+//
+// Revision History:
+//
+// 11-May-1991 tomad
+//
+// Created
+//
+//
+// Sanjeev Katariya (sanjeevk) 4-6-1993
+// Bug# 5203: The routine TpctlCopyAdapterAddress() needed modification to support
+// the offset introduced by the Media type being returned on an Adapter Open.
+// This was done in order to be able to correctly set the OID based on the
+// medium
+//
+// Added support for commands DISABLE, ENABLE, SHELL, RECORDINGENABLE, RECORDINGDISABLE,
+// Tpctl Options w,c and ?, fixed multicast address accounting
+//
+// Tim Wynsma (timothyw) 4-27-94
+// Added performance testing
+// 5-18-94
+// Added setglobal command; cleanup
+// 6-08-94
+// Chgd perf test to client/server model
+//
+// ---------------------------------------------------------------------
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+
+#include <windows.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "tpctl.h"
+#include "parse.h"
+
+
+extern CMD_CODE CommandCode[] = {
+
+ { CMD_ERR, "Unknown", "U" },
+ { VERBOSE, "Verbose", "V" },
+ { SETENV, "SetEnvironment", "SE" },
+ { READSCRIPT, "ReadScript", "RS" },
+ { BEGINLOGGING, "BeginLogging", "BL" },
+ { ENDLOGGING, "EndLogging", "EL" },
+ { WAIT, "Wait", "W" },
+ { GO, "Go", "G" },
+ { PAUSE, "Pause", "P" },
+ { LOAD, "Load", "L" },
+ { UNLOAD, "Unload", "U" },
+ { OPEN, "Open", "O" },
+ { CLOSE, "Close", "C" },
+ { SETPF, "SetPacketFilter", "SP" },
+ { SETLA, "SetLookAheadSize", "LA" },
+ { ADDMA, "AddMulticastAddress", "AM" },
+ { DELMA, "DeleteMulticastAddress", "DM" },
+ { SETFA, "SetFunctionalAddress", "SF" },
+ { SETGA, "SetGroupAddress", "SG" },
+ { QUERYINFO, "QueryInformation", "QI" },
+ { QUERYSTATS, "QueryStatistics", "QS" },
+ { SETINFO, "SetInformation", "SI" },
+ { RESET, "Reset", "R" },
+ { SEND, "Send", "S" },
+ { STOPSEND, "StopSend", "SS" },
+ { WAITSEND, "WaitSend", "WT" },
+ { RECEIVE, "Receive", "RC" },
+ { STOPREC, "StopReceive", "SR" },
+ { GETEVENTS, "GetEvents", "GE" },
+ { STRESS, "Stress", "ST" },
+ { STRESSSERVER, "StressServer", "SV" },
+ { ENDSTRESS, "EndStress", "ES" },
+ { WAITSTRESS, "WaitStress", "WS" },
+ { CHECKSTRESS, "CheckStress", "CS" },
+ { BREAKPOINT, "BreakPoint", "BP" },
+ { QUIT, "Quit", "Q" },
+ { HELP, "Help", "H" },
+ { SHELL, "Shell", "SH" },
+ { RECORDINGENABLE, "RecordingEnable", "RE" },
+ { RECORDINGDISABLE,"RecordingDisable", "RD" },
+ { DISABLE, "Disable", "DI" },
+ { ENABLE, "Enable", "EN" },
+ { REGISTRY, "Registry", "RG" },
+ { PERFSERVER, "PerformServer", "PS" },
+ { PERFCLIENT, "PerformClient", "PC" },
+ { SETGLOBAL, "SetGlobalVar", "SET"}
+};
+
+
+extern BOOL WriteThrough;
+extern BOOL ContinueOnError;
+
+
+DWORD
+TpctlParseCommandLine(
+ IN WORD argc,
+ IN LPSTR argv[]
+ )
+
+// -----------------
+//
+// Routine Description:
+//
+// This routine parses the command line arguments. If there is a
+// script file and or log file they are loaded, and will be read from
+// when that test actually starts. If there is an adapter to be loaded
+// it is written to the global var AdapterName and will be loaded
+// by a later routine.
+//
+// Arguments:
+//
+// argc - the number of arguments passed in at startup.
+//
+// argv - the argument vector containing the arguments passed in
+// from the command line.
+//
+// Return Value:
+//
+// DWORD - NO_ERROR if all the arguments are valid, and the
+// script and log file are opened and loaded correctly.
+// ERROR_INVALID_PARAMETER otherwise.
+//
+// --------------------
+
+{
+ DWORD Status;
+ CHAR *TmpArgv[4];
+ CHAR *TmpOptions = "/N";
+ INT i;
+
+ //
+ // Parameter validations
+ //
+ if ( ( argc < 1 ) || ( argc > 4 ) )
+ {
+ TpctlErrorLog("\n\tTpctl: Invalid Command Line Argument(s).\n",NULL);
+ TpctlUsage();
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Read the command line arguments into the global command buffer.
+ // We are going to temporarily "fake" that we are reading commands
+ // from a script so the parse agruments routine will not prompt
+ // the user for any additional info if all the arguments are not
+ // given. This will be disabled immediately following the call.
+ //
+
+ ScriptIndex++;
+
+ //
+ // This is very specific to this routine. The current method of parsing
+ // does not lead itself well to optionals
+ //
+ TmpArgv[0] = TmpArgv[1] = TmpArgv[2] = TmpArgv[3] = NULL;
+ for( i = 0; i < argc; i++ )
+ {
+ TmpArgv[i] = argv[i];
+ }
+
+ if ( ( argc >= 2 ) && ( argv[1][0] != '/' ) )
+ {
+ if ( argc == 4 )
+ {
+ TpctlErrorLog("\n\tTpctl: Invalid Command Line Argument(s).\n",NULL);
+ TpctlUsage();
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // We now shift things around. At this point we now that argc must be three
+ //
+ argc++;
+ TmpArgv[1] = TmpOptions;
+ TmpArgv[2] = argv[1];
+ TmpArgv[3] = argv[2];
+
+ }
+ else
+ {
+ if ( (argc >=2 ) && (argv[1][0] == '/') &&
+ (strlen( argv[1] ) > (TPCTL_OPTION_SIZE-1)) )
+ {
+ TpctlErrorLog("\n\tTpctl: Invalid Command Line Argument(s).\n",NULL);
+ TpctlUsage();
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ }
+
+ if ( TpctlParseArguments( CommandLineOptions,
+ Num_CommandLine_Params,
+ argc,
+ TmpArgv ) == -1 )
+ {
+ TpctlErrorLog("\n\tTpctl: Invalid Command Line Argument(s)\n",NULL);
+ TpctlUsage();
+ ScriptIndex--;
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ ScriptIndex--;
+
+ //
+ // Check the options
+ //
+
+ _strupr( GlobalCmdArgs.TpctlOptions );
+
+ if ( strchr( GlobalCmdArgs.TpctlOptions, '?' ) != NULL )
+ {
+ TpctlUsage();
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ if ( strchr( GlobalCmdArgs.TpctlOptions, 'W' ) != NULL )
+ {
+ WriteThrough = FALSE;
+ }
+
+ if ( strchr( GlobalCmdArgs.TpctlOptions, 'C' ) != NULL )
+ {
+ ContinueOnError = TRUE;
+ }
+
+
+ //
+ // If there is a script file to be opened.
+ //
+
+ if ( GlobalCmdArgs.ARGS.FILES.ScriptFile[0] != '\0' )
+ {
+ //
+ // Then open it and the log file if it exists.
+ //
+
+ Status = TpctlLoadFiles( GlobalCmdArgs.ARGS.FILES.ScriptFile,
+ GlobalCmdArgs.ARGS.FILES.LogFile );
+
+ if ( Status != NO_ERROR )
+ {
+ TpctlUsage();
+ return Status;
+ }
+
+ //
+ // Otherwise if there is only a logfile name with no script file
+ // name print the usage message and return an error.
+ //
+
+ }
+ else if ( GlobalCmdArgs.ARGS.FILES.LogFile[0] != '\0' )
+ {
+ TpctlErrorLog("\n\tTpctl: Invalid Command Line Argument(s).\n",NULL);
+ TpctlUsage();
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ return NO_ERROR;
+}
+
+
+
+VOID
+TpctlUsage (
+ VOID
+ )
+
+// ------------------
+//
+// Routine Description:
+//
+// This routine prints out a usage statement.
+//
+// Arguments:
+//
+// None
+//
+// Return Value:
+//
+// None.
+//
+// -- -------------
+
+{
+ printf("\n\tUSAGE: TPCTL [/[?|W|C]] [SCRIPT_FILE_NAME [LOG_FILE_NAME]]\n\n");
+
+ printf("\tWhere:\n\n");
+
+ printf("\tSCRIPT_FILE_NAME - is an OPTIONAL script file containing test\n");
+ printf("\t commands.\n\n");
+
+ printf("\tLOG_FILE_NAME - is an OPTIONAL log file for logging test results.\n");
+ printf("\t Defaults to TESTPROT.LOG. A SCRIPT_FILE_NAME must\n");
+ printf("\t precede a LOG_FILE_NAME.\n\n");
+
+ printf("\tOPTIONS:\n\n");
+ printf("\t W - Disables write through which speeds up TPCTL as\n");
+ printf("\t writes to the log files are now cached. Note that\n");
+ printf("\t this exposes the risk of the log file not being\n");
+ printf("\t updated should the system crash during a test.\n");
+ printf("\t WRITE_THROUGH is enabled by default.\n\n");
+
+ printf("\t C - Enables TPCTL to continue on errors encountered during\n");
+ printf("\t script testing. TPCTL will stop script processing on\n");
+ printf("\t script errors by default.\n\n");
+
+ printf("\t ? - Access command online help.\n\n");
+
+}
+
+
+
+
+VOID
+TpctlHelp(
+ LPSTR Command
+ )
+
+// ------------------
+//
+// Routine Description:
+//
+// This routine prints out help statements for each of the supported
+// commands.
+//
+// Arguments:
+//
+// Command - The command to give the help information for. If no command
+// is given then a list of all the commands that are supported
+// will be printed.
+//
+// Return Value:
+//
+// None.
+//
+// -----------------
+
+{
+ DWORD CmdCode;
+
+ if ( GlobalCmdArgs.ARGS.CmdName[0] == '\0' )
+ {
+ CmdCode = HELP;
+ }
+ else
+ {
+ CmdCode = TpctlGetCommandCode( Command );
+ }
+
+ printf("\n\tThe syntax of this command is:\n\n");
+
+ switch ( CmdCode )
+ {
+ case HELP:
+ printf("\tHELP [command]\n\n");
+ printf("\tHelp is available on the following FUNCTIONAL commands:\n\n");
+ printf("\t (AM) AddMulticastAddress (C) Close\n");
+ printf("\t (DM) DeleteMulticastAddress (GE) GetEvents\n");
+ printf("\t (O) Open (QI) QueryInformation\n");
+ printf("\t (QS) QueryStatistics (RC) Receive\n");
+ printf("\t (R) Reset (S) Send\n");
+ printf("\t (SF) SetFunctionalAddress (SG) SetGroupAddress\n");
+ printf("\t (SI) SetInformation (LA) SetLookAheadSize\n");
+ printf("\t (SP) SetPacketFilter (SR) StopReceive\n");
+ printf("\t (SS) StopSend (WT) WaitSend\n\n");
+ printf("\tHelp is available on the following STRESS commands:\n\n");
+ printf("\t (CS) CheckStress (ES) EndStress\n");
+ printf("\t (ST) Stress (SV) StressServer\n");
+ printf("\t (WS) WaitStress\n\n");
+ printf("\tHelp is available on the following test control commands:\n\n");
+ printf("\t (BL) BeginLogging (BP) BreakPoint\n");
+ printf("\t (EL) EndLogging (G) Go\n");
+ printf("\t (H) Help (P) Pause\n");
+ printf("\t (Q) Quit (RS) ReadScript\n");
+ printf("\t (SE) SetEnvirnoment (V) Verbose\n");
+ printf("\t (W) Wait (RE) RecordingEnable\n");
+ printf("\t (RD) RecordingDisable (SH) CommandShell\n");
+ printf("\t (DI) Disable (EN) Enable\n");
+ printf("\t (RG) Registry\n\n");
+ printf("\tThe command may be entered in either the short form or\n");
+ printf("\tthe long form. The short form is described by the letter\n");
+ printf("\tor letters in the parentheses, while the long form is the\n");
+ printf("\tword or phrase following.\n\n");
+ break;
+
+ case VERBOSE:
+ printf("\tVERBOSE\n\n");
+ printf("\tVerbose enables and disables the output of each command and its\n");
+ printf("\tresults to the screen. Errors will be printed to the screen\n");
+ printf("\tregardless of the state of the Verbose flag.\n\n");
+ printf("\t\"V\" - the short form of the command.\n");
+ break;
+
+ case SETENV:
+ printf("\tSETENVIRONMENT [Open_Instance] [Environment_Variable]\n\n");
+ printf("\tSetEnvironment allows the user to customize environment\n");
+ printf("\tvariables that effect the running of tests.\n\n");
+ printf("\tOpen_Instance - the open instance between the test driver\n");
+ printf("\t and the MAC adapter to set the environment variable\n");
+ printf("\t on. The default value is 1.\n\n");
+ printf("\tEnvironment_Variable - the variable(s) to set for a given call.\n\n");
+ printf("\t All variables are set back to their defaults\n");
+ printf("\t on each call unless otherwise specified.\n\n");
+ printf("\tEnvironment Variable values that may be set are:\n\n");
+ printf("\tWindowSize - the number of packets in the windows buffer of the\n");
+ printf("\t windowing algorithm. The default is 10 packets.\n\n");
+ printf("\tRandomBuffer - the maximum value passed to the rand routine to\n");
+ printf("\t determine the number of buffers in RAND_MAKEUP packets.\n");
+ printf("\t The default value is 5 which generates an average\n");
+ printf("\t buffer size of 1/5 of the packet size.\n\n");
+ printf("\tStressAddress - the multicast or functional address that will be\n");
+ printf("\t used to initialize a stress test. All machines in\n");
+ printf("\t a given stress test must use the same StressAddress.\n\n");
+ printf("\tStressDelay - the standard number of seconds to delay ecah loopp\n");
+ printf("\t through a stress test. The default is 1/1000 seconds.\n\n");
+ printf("\tUpForAirDelay - the number of seconds to delay on the loop through\n");
+ printf("\t a stress test after DelayInterval iterations have\n");
+ printf("\t occurred. The default is 1/100 seconds.\n");
+ printf("\tDelayInterval - the number of StressDelays between each UpForAirDelay\n");
+ printf("\t during a stress test. The default is 10 iterations.\n\n");
+ printf("\t\"SE\" - the short form of the command.\n");
+ break;
+
+ case READSCRIPT:
+ printf("\tREADSCRIPT [Script_File] [Log_File]\n\n");
+ printf("\tReadScript reads test commands from a script file, executes\n");
+ printf("\tthe commands and logs the results of the command to a log file.\n\n");
+ printf("\tScript_File - the name of the file containing the test\n");
+ printf("\t commands to execute. The default script file name is\n");
+ printf("\t \"TESTPROT.TPS\".\n\n");
+ printf("\tLog_File - the name of the file to log commands and results to. If\n");
+ printf("\t this file exists, it will be overwritten. The default\n");
+ printf("\t log file name is \"TESTPROT.LOG\".\n\n");
+ printf("\t\"RS\" - the short form of the command.\n");
+ break;
+
+ case BEGINLOGGING:
+ printf("\tBEGINLOGGING [Log_File]\n\n");
+ printf("\tBeginLogging enables the logging of commands and their results.\n");
+ printf("\tOnce logging is started any commands entered from the command line\n");
+ printf("\tare written to the Log_File. If commands are being read from\n");
+ printf("\ta script this function is disabled. (see also ENDLOGGING)\n\n");
+ printf("\tLog_File - the name of the file to log the commands and results to.\n");
+ printf("\t If this file exists, it will be overwritten. The default\n");
+ printf("\t log file name is \"CMDLINE.LOG\".\n\n");
+ printf("\t\"BL\" - the short form of the command.\n");
+ break;
+
+ case ENDLOGGING:
+ printf("\tENDLOGGING\n\n");
+ printf("\tEndLogging disables the logging of commands and their results.\n");
+ printf("\t(see also BEGINLOGGING)\n\n");
+ printf("\t\"EL\" - the short form of the command.\n");
+ break;
+
+ case RECORDINGENABLE:
+ printf("\tRECORDINGENABLE [ScriptFile]\n\n");
+ printf("\tRecordingEnable enables the recording of commands.\n");
+ printf("\tOnce recording is started any commands entered from the command line\n");
+ printf("\tare written to the ScriptFile. If commands are being read from\n");
+ printf("\ta script this function is disabled. (see also RECORDINGDISABLE)\n\n");
+ printf("\tScriptFile - the name of the file to record the commands and results to.\n");
+ printf("\t If this file exists, it will be overwritten. The default\n");
+ printf("\t script file name is \"CMDLINE.TPS\".\n\n");
+ printf("\t\"RE\" - the short form of the command.\n");
+ break;
+
+ case RECORDINGDISABLE:
+ printf("\tRECORDINGDISABLE\n\n");
+ printf("\tRecordingDisable disables the recording of commands.\n");
+ printf("\t(see also RECORDINGENABLE)\n\n");
+ printf("\t\"RD\" - the short form of the command.\n");
+ break;
+
+ case SHELL:
+ printf("\tSHELL [Argument_1 Argument2 ... Argument_N]\n\n");
+ printf("\tSHELL will from spawn a command shell from within TPCTL or execute\n");
+ printf("\tthe command arguments Argument_1 through Argument_N and return back\n");
+ printf("\tto the TPCTL command prompt. If using SHELL by itself, to return to\n");
+ printf("\tthe TPCTL prompt simply EXIT the command shell.\n\n");
+ printf("\t\"SH\" - the short form of the command.\n");
+ break;
+
+
+ case WAIT:
+ printf("\tWAIT [Wait_Time]\n\n");
+ printf("\tWait allows a script file to wait a given number of seconds prior\n");
+ printf("\tto continuing with the next command.\n\n");
+ printf("\tWait_Time - the time in seconds the call will wait before\n");
+ printf("\t returning control to command processing.\n\n");
+ printf("\t\"W\" - the short form of the command.\n");
+ break;
+
+ case GO:
+ printf("\tGO [Open_Instance] [Remote_Address] [Test_Signature]\n\n");
+ printf("\tGo sends a TP_GO packet to the Remote Address signalling\n");
+ printf("\ta Paused instance of the driver to continue processing its\n");
+ printf("\ttest script. Go continuously resends the packet, and will\n");
+ printf("\twait, retrying, until it is acknowledged or stopped with\n");
+ printf("\t<Ctrl-C>. (see also PAUSE)\n\n");
+ printf("\tOpen_Instance - the open instance between the test driver and\n");
+ printf("\t the MAC adapter that will send the TP_GO Packet.\n");
+ printf("\t The default value is 1.\n\n");
+ printf("\tRemote_Address - the address of a remote machine to send the TP_GO\n");
+ printf("\t packet to.\n\n");
+ printf("\tTest_Signature - a unique test signature used by both machines to\n");
+ printf("\t determine if the correct packets have been sent and\n");
+ printf("\t acknowledged. This value must match the Test\n");
+ printf("\t Signature value on the PAUSED machine.\n\n");
+ printf("\t\"G\" - the short form of the command.\n");
+ break;
+
+ case PAUSE:
+ printf("\tPAUSE [Open_Instance] [Remote_Address] [Test_Signature]\n\n");
+ printf("\tPause waits for the receipt of a TP_GO packet wit ha matching test\n");
+ printf("\tsignature and then acknowledges it6 by sending a TP_GO_ACKL packet.\n");
+ printf("\tPause will wait for the receipt of the TP_GO packlet until it arrives,\n");
+ printf("\tor the command is cancelled by <Ctrl-c>.\n\n");
+ printf("\tOpen_Instance - the open instance between the test driver and\n");
+ printf("\t the MAC adapter that will wait for the TP_GO Packet.\n");
+ printf("\t The default value is 1.\n\n");
+ printf("\tRemote_Address - the address of a remote machine to send the TP_GO_ACK\n");
+ printf("\t packet to.\n\n");
+ printf("\tTest_Signature - a unique test signature used by both machines to\n");
+ printf("\t determine if the correct packets have been sent and\n");
+ printf("\t acknowledged. This value must match the Test\n");
+ printf("\t Signature value on the machine sending the TP_GO\n");
+ printf("\t packet\n\n");
+ printf("\t\"P\" - the short form of the command.\n");
+ break;
+
+ case LOAD:
+ printf("\tLOAD [MAC_Driver_Name]\n\n");
+ printf("\tLoad issues a call to NtLoadDriver to unload the driver for\n");
+ printf("\tthe MAC adapter \"Adapter_Name\".\n\n");
+ printf("\tMAC_Driver_Name - the MAC adapter to be loaded. There is no default\n");
+ printf("\t value.\n\n");
+ printf("\t\"L\" - the short form of the command.\n");
+ break;
+
+ case UNLOAD:
+ printf("\tUNLOAD [MAC_Driver_Name]\n\n");
+ printf("\tUnload issues a call to NtUnloadDriver to unload the driver for\n");
+ printf("\tthe MAC adapter \"Adapter_Name\".\n\n");
+ printf("\tMAC_Driver_Name - the MAC adapter to be unloaded. There is no default\n");
+ printf("\t value.\n\n");
+ printf("\t\"U\" - the short form of the command.\n");
+ break;
+
+ case OPEN:
+ printf("\tOPEN [Open_Instance] [Adapter_Name]\n\n");
+ printf("\tOpen issues a call to NdisOpenAdapter to open the MAC adapter\n");
+ printf("\tAdapter_Name, and associates it with the given Open_Instance.\n");
+ printf("\tSubsequent calls to the Open_Instance will be directed to\n");
+ printf("\tthis adapter.\n\n");
+ printf("\tOpen_Instance - the open instance between the test driver\n");
+ printf("\t and the MAC adapter this open will be associated\n");
+ printf("\t with. The default value is 1.\n\n");
+ printf("\tAdapter_Name - the MAC adapter to be unloaded. There is no default\n");
+ printf("\t value.\n\n");
+ printf("\t\"O\" - the short form of the command.\n");
+ break;
+
+ case CLOSE:
+ printf("\tCLOSE [Open_Instance]\n\n");
+ printf("\tClose issues a call to NdisCloseAdapter to close the MAC adapter\n");
+ printf("\tassociated with the given Open_Instance.\n\n");
+ printf("\tOpen_Instance - the open instance between the test driver\n");
+ printf("\t and the MAC adapter to be closed. The default\n");
+ printf("\t value is 1.\n\n");
+ printf("\t\"C\" - the short form of the command.\n");
+ break;
+
+ case SETPF:
+ printf("\tSETPACKETFILTER [Open_Instance] [Packet_Filter]\n\n");
+ printf("\tSetPacketFilter issues a call to the MAC using NdisRequest\n");
+ printf("\tto set the card's packet filter to a given value.\n\n");
+ printf("\tOpen_Instance - the open instance between the test driver\n");
+ printf("\t and the MAC adapter to issue the request to. The\n");
+ printf("\t default value is 1.\n\n");
+ printf("\tPacket_Filter - the packet filter value to set on the MAC adapter.\n");
+ printf("\t Multiple filter values may be entered by seperating\n");
+ printf("\t each with the \"|\" character. Valid values for\n");
+ printf("\t Packet_Filter are:\n\n");
+ printf("\t Directed\n");
+ printf("\t Multicast\n");
+ printf("\t AllMulticast\n");
+ printf("\t Broadcast\n");
+ printf("\t SourceRouting\n");
+ printf("\t Promiscuous\n");
+ printf("\t Mac_Frame\n");
+ printf("\t Functional\n");
+ printf("\t AllFunctional\n");
+ printf("\t Group\n");
+ printf("\t None\n\n");
+ printf("\t The default value is \"Directed\".\n\n");
+ printf("\t\"SP\" - the short form of the command.\n");
+ break;
+
+ case SETLA:
+ printf("\tSETLOOKAHEADSIZE [Open_Instance] [LookAhead_Size]\n\n");
+ printf("\tSetLookAheadSize issues a call to the MAC using NdisRequest\n");
+ printf("\tto set the card's lookahead buffer to a given size.\n\n");
+ printf("\tOpen_Instance - the open instance between the test driver\n");
+ printf("\t and the MAC adapter to issue the request to. The\n");
+ printf("\t default value is 1.\n\n");
+ printf("\tLookAhead_Size - the new size of the card's lookahead buffer. The\n");
+ printf("\t default value is 100 bytes.\n\n");
+ printf("\t\"LA\" - the short form of the command.\n");
+ break;
+
+ case ADDMA:
+ printf("\tADDMULTICASTADDRESS [Open_Instance] [Multicast_Address]\n\n");
+ printf("\tAddMulticastAddress issues a call to the MAC using NdisRequest\n");
+ printf("\tto add a multicast address to the list of multicast addresses\n");
+ printf("\tcurrently set on the card.\n\n");
+ printf("\tOpen_Instance - the open instance between the test driver\n");
+ printf("\t and the MAC adapter to issue the request to. The\n");
+ printf("\t default value is 1.\n\n");
+ printf("\tMulticast_Address - the multicast address to add to the list.\n\n");
+ printf("\t\"AM\" - the short form of the command.\n");
+ break;
+
+ case DELMA:
+ printf("\tDELETEMULTICASTADDRESS [Open_Instance] [Multicast_Address]\n\n");
+ printf("\tDeleteMulticastAddress issues a call to the MAC using NdisRequest\n");
+ printf("\tto delete a multicast address from the list of multicast\n");
+ printf("\taddresses currently set on the card.\n\n");
+ printf("\tOpen_Instance - the open instance between the test driver\n");
+ printf("\t and the MAC adapter to issue the request to. The\n");
+ printf("\t default value is 1.\n\n");
+ printf("\tMulticast_Address - the multicast address to delete from the list.\n\n");
+ printf("\t\"DM\" - the short form of the command.\n");
+ break;
+
+ case SETFA:
+ printf("\tSETFUNCTIONALADDRESS [Open_Instance] [Functional_Address]\n\n");
+ printf("\tSetFunctionalAddress issues a call to the MAC using NdisRequest\n");
+ printf("\tto set a functional address on the card.\n\n");
+ printf("\tOpen_Instance - the open instance between the test driver\n");
+ printf("\t and the MAC adapter to issue the request to. The\n");
+ printf("\t default value is 1.\n\n");
+ printf("\tFunctional_Address - the functional address to set on the card.\n\n");
+ printf("\t\"SF\" - the short form of the command.\n");
+ break;
+
+ case SETGA:
+ printf("\tSETGROUPADDRESS [Open_Instance] [Group_Address]\n\n");
+ printf("\tSetGroupAddress issues a call to the MAC using NdisRequest\n");
+ printf("\tto set a group address on the card.\n\n");
+ printf("\tOpen_Instance - the open instance between the test driver\n");
+ printf("\t and the MAC adapter to issue the request to. The\n");
+ printf("\t default value is 1.\n\n");
+ printf("\tGroup_Address - the group address to set on the card.\n\n");
+ printf("\t\"SG\" - the short form of the command.\n");
+ break;
+
+ case QUERYINFO:
+ printf("\tQUERYINFORMATION [Open_Instance] [OID_Request]\n\n");
+ printf("\tQueryInformation issues a call to the MAC using NdisRequest\n");
+ printf("\tto query a given class of information from the MAC.\n\n");
+ printf("\tOpen_Instance - the open instance between the test driver\n");
+ printf("\t and the MAC adapter to issue the request to. The\n");
+ printf("\t default value is 1.\n\n");
+ printf("\tOID_Request - the information type to query. The default value\n");
+ printf("\t is \"SupportedOidList\".\n");
+ printf("\t\"QI\" - the short form of the command.\n");
+ break;
+
+ case QUERYSTATS:
+ printf("\tQUERYSTATISTICS [Device_Name] [OID_Request]\n\n");
+ printf("\tDevice_Name - the name of the device to issue the request\n");
+ printf("\t to. There is no default value.\n\n");
+ printf("\tOID_Request - the statistics type to query. The default value\n");
+ printf("\t is \"SupportedOidList\".\n");
+ printf("\t\"QS\" - the short form of the command.\n");
+ break;
+
+ case SETINFO:
+ printf("\tSETINFORMATION [Open_Instance] [OID_Request] [Type_Specific]\n\n");
+ printf("\tSetInformation issues a call to the MAC using NdisRequest\n");
+ printf("\tto set a given class of information in the MAC.\n\n");
+ printf("\tOpen_Instance - the open instance between the test driver\n");
+ printf("\t and the MAC adapter to issue the request to. The\n");
+ printf("\t default value is 1.\n\n");
+ printf("\tOID_Request - the information type to set. Valid values for\n");
+ printf("\t OID_Request are:\n\n");
+ printf("\t CurrentPacketFilter\n");
+ printf("\t CurrentLookAhead\n");
+ printf("\t CurrentMulticastList\n");
+ printf("\t CurrentFunctionalAddress\n");
+ printf("\t CurrentGroupAddress\n");
+ printf("\t The default value is \"CurrentPacketFilter\".\n");
+ printf("\tType_Specific - the information to set for a given OID_Request\n");
+ printf("\t\"SI\" - the short form of the command.\n");
+ break;
+
+ case RESET:
+ printf("\tRESET [Open_Instance]\n\n");
+ printf("\tReset issues a call to the MAC using NdisReset to reset the MAC.\n\n");
+ printf("\tOpen_Instance - the open instance between the test driver\n");
+ printf("\t and the MAC adapter to issue the request to. The\n");
+ printf("\t default value is 1.\n\n");
+ printf("\t\"R\" - the short form of the command.\n");
+ break;
+
+ case SEND:
+ printf("\tSEND [Open_Instance] [Destination_Address] [Packet_Size] [Number]\n");
+ printf("\t [Resend_Address]\n\n");
+ printf("\tSend issues a call to the MAC using NdisSend to send packets on the\n");
+ printf("\tnetwork. Sending more then one packet causes the command to return\n");
+ printf("\tasynchronously. If a Resend_Address argument is specified, then\n");
+ printf("\teach packet sent will contain a \"resend\" packet in the data field\n");
+ printf("\tthat is extracted from the packet by any receiving test and\n");
+ printf("\tresent to the address specified. (see also RECEIVE, STOPSEND and\n");
+ printf("\tWAITSEND)\n\n");
+ printf("\tOpen_Instance - the open instance between the test driver\n");
+ printf("\t and the MAC adapter to issue the request(s) to. The\n");
+ printf("\t default value is 1.\n\n");
+ printf("\tDestination_Address - the network address the packet(s) will be sent\n");
+ printf("\t to.\n\n");
+ printf("\tPacket_Size - the size of the packet(s) to send.\n\n");
+ printf("\tNumber - the number of packets to send. A value of \"-1\" will\n");
+ printf("\t cause the test to send packets continuously until\n");
+ printf("\t stopped by a call to STOPSEND.\n\n");
+ printf("\tResend_Address - OPTIONAL: the address that will be placed in the\n");
+ printf("\t destination address of the \"resend\" packet.\n\n");
+ printf("\t\"S\" - the short form of the command.\n");
+ break;
+
+ case STOPSEND:
+ printf("\tSTOPSEND [Open_Instance]\n\n");
+ printf("\tStopSend stops a previously started SEND command if it is still\n");
+ printf("\trunning, and prints the SEND command's results.\n\n");
+ printf("\tOpen_Instance - the open instance between the test driver\n");
+ printf("\t and the MAC adapter to stop the SEND command on.\n");
+ printf("\t The default value is 1.\n\n");
+ printf("\t\"SS\" - the short form of the command.\n");
+ break;
+
+ case WAITSEND:
+ printf("\tWAITSEND [Open_Instance]\n\n");
+ printf("\tWaitSend waits for a send test to end, and then displays the\n");
+ printf("\tsend test results. This command may be cancelled by entering\n");
+ printf("\tCtrl-C.\n\n");
+ printf("\tOpen_Instance - the open instance between the test driver\n");
+ printf("\t and the MAC adapter to wait for the send test to\n");
+ printf("\t end on. The default value is 1.\n\n");
+ printf("\t\"WT\" - the short form of the command.\n");
+ break;
+
+ case RECEIVE:
+ printf("\tRECEIVE [Open_Instance]\n\n");
+ printf("\tReceive sets the test up in a mode to \"expect\" to receive\n");
+ printf("\tpackets from other tests. Each packet will be inspected, and\n");
+ printf("\tcounted. If a test packet received contains a \"resend\"\n");
+ printf("\tpacket, the \"resend\" packet will be extracted from the packet,\n");
+ printf("\tand sent to the address contained within. (see also SEND and STOPRECEIVE)\n\n");
+ printf("\tOpen_Instance - the open instance between the test driver\n");
+ printf("\t and the MAC adapter to set up to expect packets.\n");
+ printf("\t The default value is 1.\n\n");
+ printf("\t\"RC\" - the short form of the command.\n");
+ break;
+
+ case STOPREC:
+ printf("\tSTOPRECEIVE [Open_Instance]\n\n");
+ printf("\tStopReceive resets a test which has previously had a\n");
+ printf("\tRECEIVE commmand issued to it, to no longer \"expect\" packets.\n\n");
+ printf("\tOpen_Instance - the open instance between the test driver\n");
+ printf("\t and the MAC adapter to reset. The default value\n");
+ printf("\t is 1.\n\n");
+ printf("\t\"SR\" - the short form of the command.\n");
+ break;
+
+ case GETEVENTS:
+ printf("\tGETEVENTS [Open_Instance]\n\n");
+ printf("\tGetEvents queries the test for information about \"unexpected\"\n");
+ printf("\tindications and completions.\n\n");
+ printf("\tOpen_Instance - the open instance between the test driver\n");
+ printf("\t and the MAC adapter to query the events from. The\n");
+ printf("\t default value is 1.\n\n");
+ printf("\t\"GE\" - the short form of the command.\n");
+ break;
+
+ case STRESS:
+ printf("\tSTRESS [Open_Instance] [Member_Type] [Packets] [Iterations]\n");
+ printf("\t [Packet_Type] [Packet_Size] [Packet_MakeUp] [Response_Type]\n");
+ printf("\t [Delay_Type] [Delay_Length] [Windowing] [Data_Checking]\n");
+ printf("\t [PacketsFromPool]\n\n");
+ printf("\tStress sets the test up to run a stress test. If the test\n");
+ printf("\tis started successfully the command will complete asynchronously.\n");
+ printf("\tThe test will run until finished or until stopped manually. (see also\n");
+ printf("\tENDSTRESS, STOPSTRESS, WAITSTRESS, and CHECKSTRESS)\n\n");
+ printf("\tOpen_Instance - the open instance between the test driver\n");
+ printf("\t and the MAC adapter to start a stress test on. The\n");
+ printf("\t default value is 1.\n\n");
+ printf("\tMember_Type - how the protocol will perform in the stress test; as\n");
+ printf("\t a client (CLIENT) or as a client and server (BOTH).\n");
+ printf("\t The default value is BOTH.\n\n");
+ printf("\tPackets - the number of packets that will be sent to each server prior\n");
+ printf("\t to the test completing. A value of -1 causes the test to\n");
+ printf("\t run forever unless a value is entered for Iterations. The\n");
+ printf("\t default value for packets is -1.\n\n");
+ printf("\tIterations - the number of iterations this test will run. A value\n");
+ printf("\t of -1 causes the test to run forever unless a value is\n");
+ printf("\t entered for Packet. The default value for Iterations\n");
+ printf("\t is -1.\n\n");
+ printf("\tPacket_Type - the type of packet size algorithm used to create the\n");
+ printf("\t packets for the test; FIXEDSIZE, RANDOMSIZE or CYCLICAL.\n");
+ printf("\t The default type is FIXED.\n\n");
+ printf("\tPacket_Size - with the Packet_Type value determines the size of packets\n");
+ printf("\t in the test. The default is 512 bytes.\n\n");
+ printf("\tPacket_MakeUp - the number and size of the buffers that makeup each\n");
+ printf("\t packet; RAND, SMALL, ZEROS, ONES and KNOWN. The\n");
+ printf("\t default makeup is RAND.\n\n");
+ printf("\tResponse_Type - the method the server will use when responding to test\n");
+ printf("\t packets; NO_RESPONSE, FULL_RESPONSE, ACK_EVERY,\n");
+ printf("\t or ACK_10_TIMES. The default value is FULL_RESPONSE.\n\n");
+ printf("\tDelay_Type - the method used to determine the next interpacket\n");
+ printf("\t delay; FIXEDDELAY or RANDOMDELAY. The default value\n");
+ printf("\t is FIXEDDELAY.\n\n");
+ printf("\tDelay_Length - the minimum number of iterations between two\n");
+ printf("\t consecutive sends to the same server in a test.\n");
+ printf("\t The default value is 0 iterations.\n\n");
+ printf("\tWindowing - a boolean used to determine whether a simple windowing\n");
+ printf("\t algorithm will be used between the client and each server.\n");
+ printf("\t the default value is TRUE.\n\n");
+ printf("\tData_Checking - a boolean used to determine whether data checking\n");
+ printf("\t will be performed on each packet received. The\n");
+ printf("\t default value is TRUE.\n\n");
+ printf("\tPacketsFromPool - a boolean used to determine whether a pool of\n");
+ printf("\t packets will be created prior to the test. The\n");
+ printf("\t default value is TRUE.\n\n");
+ printf("\t\"ST\" - the short form of the command.\n");
+ break;
+
+ case STRESSSERVER:
+ printf("\tSTRESSSERVER [Open_Instance]\n\n");
+ printf("\tStressServer sets the test up to participate in a stress\n");
+ printf("\ttest as a server receiving and responding to stress packets from\n");
+ printf("\tany clients running a stress test.\n\n");
+ printf("\tOpen_Instance - the open instance between the test driver\n");
+ printf("\t and the MAC adapter to start a stress server on. The\n");
+ printf("\t default value is 1.\n\n");
+ printf("\t\"SV\" - the short form of the command.\n");
+ break;
+
+ case ENDSTRESS:
+ printf("\tENDSTRESS [Open_Instance]\n\n");
+ printf("\tEndStress issues a command to the test to stop a currently\n");
+ printf("\trunning stress test, whether the protocol is acting as a client or\n");
+ printf("\tserver. If the protocol is acting as a client, once the test has\n");
+ printf("\tended, the result will be displayed.\n\n");
+ printf("\tOpen_Instance - the open instance between the test driver\n");
+ printf("\t and the MAC adapter to end the stress test on. The\n");
+ printf("\t default value is 1.\n\n");
+ printf("\t\"ES\" - the short form of the command.\n");
+ break;
+
+ case WAITSTRESS:
+ printf("\tWAITSTRESS [Open_Instance]\n\n");
+ printf("\tWaitStress waits for a stress test to end, and then displays the\n");
+ printf("\tstress test results. This command may be cancelled by entering\n");
+ printf("\tCtrl-C.\n\n");
+ printf("\tOpen_Instance - the open instance between the test driver\n");
+ printf("\t and the MAC adapter to wait for the stress test to\n");
+ printf("\t end on. The default value is 1.\n\n");
+ printf("\t\"WS\" - the short form of the command.\n");
+ break;
+
+ case CHECKSTRESS:
+ printf("\tCHECKSTRESS [Open_Instance]\n\n");
+ printf("\tCheckStress checks to see if a stress test has ended, and if so\n");
+ printf("\tdisplays the stress test results.\n\n");
+ printf("\tOpen_Instance - the open instance between the test driver\n");
+ printf("\t and the MAC adapter to check for the results of a\n");
+ printf("\t stress test on. The default value is 1.\n\n");
+ printf("\t\"CS\" - the short form of the command.\n");
+ break;
+
+ case BREAKPOINT:
+ printf("\tBREAKPOINT\n\n");
+ printf("\tBreakPoint causes an interrupt to break into the debugger.\n\n");
+ printf("\t\"BP\" - the short form of the command.\n");
+ break;
+
+ case QUIT:
+ printf("\tQUIT\n\n");
+ printf("\tQuit exits the control application. Any tests currently\n");
+ printf("\trunning are stopped and any opens to MACs are subsequently\n");
+ printf("\tclosed.\n\n");
+ printf("\t\"Q\" - the short form of the command.\n");
+ break;
+
+ case DISABLE:
+ printf("\tDISABLE [ENV_VAR_1] [ENV_VAR_2]...[ENV_VAR_N]\n\n");
+ printf("\tDisable will prevent the test tool from executing any commands\n");
+ printf("\tfollowing it UNLESS all the environment variables passed to it have\n");
+ printf("\tbeen declared OR if it encounters the special command ENABLE.\n");
+ printf("\tIn that event that all environments variables are set and passed as\n");
+ printf("\targuments to DISABLE, the command is ignored and TPCTL remains\n");
+ printf("\tactive. Disable by itself will also disable the tool\n\n");
+ printf("\t\"DI\" - the short form of the command.\n");
+ break;
+
+ case ENABLE:
+ printf("\tENABLE\n\n");
+ printf("\tEnable will enable the tool to accept commands\n\n");
+ printf("\t\"EN\" - the short form of the command.\n");
+ break;
+
+ case REGISTRY :
+ printf("\tREGISTRY [Operation_Type] [Key_DataBase] [SubKey] [SubKey_Class]\n");
+ printf("\t [SubKey_Value_Name] [SubKey_Value_Type] [SubKey_Value]\n\n");
+ printf("\tRegistry is responsible for adding, deleting, modifying and querying\n");
+ printf("\texisting registry key entries.\n\n");
+ printf("\tOperation_Type - The type of operation to be performed on the registry\n");
+ printf("\t key\n");
+ printf("\t Types : ADD_KEY, DELETE_KEY, QUERY_KEY, ADD_VALUE,\n");
+ printf("\t CHANGE_VALUE, DELETE_VALUE, QUERY_VALUE\n");
+ printf("\t Default: QUERY_KEY\n\n");
+ printf("\tKey_DataBase - The key database to be interacted with\n");
+ printf("\t Databases: CLASSES_ROOT, CURRENT_USER, LOCAL_MACHINE,\n");
+ printf("\t USER\n");
+ printf("\t Default : LOCAL_MACHINE\n\n");
+ printf("\tSubKey - The string value(name) of the subkey being interacted\n");
+ printf("\t with\n");
+ printf("\t Default:\n");
+ printf("\t \"System\\CurrenControlSet\\Services\\Elnkii01\\Parameters\"\n");
+ printf("\t NOTE : String values must be contained within double\n");
+ printf("\t quotes\n\n");
+ printf("\tSubKey_Class - The string value(class) to be associated with this\n");
+ printf("\t subkey\n");
+ printf("\t Default: \"Network Drivers\"\n");
+ printf("\t NOTE : String values must be contained within double\n");
+ printf("\t quotes\n\n");
+ printf("\tSubKey_Value_Name - The string value(ValueName) to be associated with\n");
+ printf("\t this subkey\n");
+ printf("\t Default: \"NetworkAddress\"\n");
+ printf("\t NOTE : String values must be contained within\n");
+ printf("\t double quotes\n\n");
+ printf("\tSubKey_Value_Type - The type of value being provided\n");
+ printf("\t Types : BINARY, DWORD_REGULAR,\n");
+ printf("\t DWORD_LITTLE_ENDIAN, DWORD_BIG_ENDIAN,\n");
+ printf("\t EXPAND_SZ, LINK, MULTI_SZ, NONE,\n");
+ printf("\t RESOURCE_LIST, SZ\n");
+ printf("\t Default: DWORD_REGULAR\n\n");
+ printf("\tSubKey_Value - The provided value to set the sub key to\n");
+ printf("\t NOTE : Multiple strings must be seperated by\n");
+ printf("\t commas. Hex values should be preceeded by 0x.\n");
+ printf("\t Octal values are preceded by 0. Decimal values\n");
+ printf("\t do not have a leading 0.By default the base\n");
+ printf("\t radix is 10\n\n");
+ printf("\t\"RG\" - the short form of the command.\n");
+ break;
+
+ case PERFSERVER:
+ printf("\tPERFORMSERVER [Open_Instance] \n\n");
+ printf("\tPerfServer starts a server to participate with the specified client in a\n");
+ printf("\tperformance test. This command always returns synchronously.\n\n");
+ printf("\tOpen_Instance - the open instance between the test driver and the MAC\n");
+ printf("\t adapter to issue the request to. Default value is 1.\n\n");
+ printf("\t\"PS\" - the short form of the command.\n");
+ break;
+
+ case PERFCLIENT:
+ printf("\tPERFORMRECEIVE [Open_Instance] [Server_Address] [Send_Address] ");
+ printf(" [Packet_Size] [Num_Packets] [Delay] [Mode] \n\n");
+ printf("\tPerfClient starts a client to participate with the specified server in a\n");
+ printf("\tperformance test. The specific test is indicated by the mode.\n");
+ printf("\tThis command always returns synchronously.\n\n");
+ printf("\tOpen_Instance - the open instance between the test driver and the MAC\n");
+ printf("\t adapter to issue the request to. Default value is 1.\n\n");
+ printf("\tServer_Address - the network address of the server card\n\n");
+ printf("\tSend_Address - the network address to which the server sends messages.\n\n");
+ printf("\tPacket_Size - total size of the test packets to be sent\n\n");
+ printf("\tNum_Packets - total number of test packets to be sent\n\n");
+ printf("\tDelay - how much to delay between sends\n\n");
+ printf("\tMode - which performance test to use:\n");
+ printf("\t 0 = client sends to any address (performance send test)\n");
+ printf("\t 1 = client sends to server (performance send test)\n");
+ printf("\t 2 = client sends to server, with server ACKs\n");
+ printf("\t 3 = two-way sends\n");
+ printf("\t 4 = server sends to client (performance receive test)\n");
+ printf("\t 5 = client sends REQ to server, server responds with sends\n");
+ printf("\t other = shut down server\n\n");
+ printf("\t\"PC\" - the short form of the command.\n");
+ break;
+
+ default:
+ printf("\tHELP [ ADDMULTICASTADDRESS | BEGINLOGGING | BREAKPOINT | CHECKSTRESS |\n");
+ printf("\t CLOSE | DELETEMULTICASTADDRESS | ENDLOGGING | ENDSTRESS |\n");
+ printf("\t GETEVENTS | GO | HELP | LOAD | OPEN | PAUSE | QUERYINFORMATION |\n");
+ printf("\t QUERYSTATISTICS | QUIT | READSCRIPT | RECEIVE | RESET | SEND |\n");
+ printf("\t SETENVIRONMENT | SETFUNCTIONALADDRESS | SETGROUPADDRESS |\n");
+ printf("\t SETINFORMATION | SETLOOKAHEADSIZE | SETPACKETFILTER |\n");
+ printf("\t STOPRECEIVE | STOPSEND | STRESS | STRESSSERVER | UNLOAD |\n");
+ printf("\t VERBOSE | WAIT | WAITSEND | WAITSTRESS | SHELL |\n");
+ printf("\t RECORDINGENABLE | RECORDINGDISABLE | REGISTRY |\n");
+ printf("\t PERFSERVER | PERFCLIENT\n\n");
+ printf("\tThe command \"%s\" is unknown.\n", _strupr( Command ));
+ break;
+
+ } // switch()
+
+ printf("\n");
+}
+
+
+
+DWORD
+TpctlLoadFiles(
+ LPSTR ScriptFile,
+ LPSTR LogFile
+ )
+
+// ---------------
+//
+// Routine Description:
+//
+// This routine loads a script file into a buffer, and opens a log
+// file for logging commands and results to.
+//
+// Arguments:
+//
+// IN LPSTR ScriptFile - the name of the script file to open and read.
+// IN LPSTR LogFile - the name of the log file to open.
+//
+// Return Value:
+//
+// DWORD - NO_ERROR if the script and log files are opened and
+// processed correctly, otherwise the error returned on the
+// failure from the win32 api that failed.
+//
+// NOTE: if this routine returns an error, then TpctlUnLoadFiles
+// MUST be called next to reset the script structures
+// correctly, and deallocate any resources that were
+// allocated during this routine.
+//
+// ---------------
+
+
+{
+ DWORD NextScriptIndex;
+ HANDLE FileHandle;
+ DWORD Status;
+ DWORD FileSize;
+
+ NextScriptIndex = ScriptIndex+1;
+
+ //
+ // First set the lowest level flag(s) in the scripts field to
+ // delineate which script is the lowest VALID script and should be
+ // unloaded. (necessary in case the next call to load files fails we
+ // will know where the high water mark is.)
+ //
+
+ if ( ScriptIndex >= 0 )
+ {
+ //
+ // if this is the first script we must ignore the reset of the
+ // "previous" script.
+ //
+
+ Scripts[ScriptIndex].IsLowestLevel = FALSE;
+ }
+
+ Scripts[NextScriptIndex].IsLowestLevel = TRUE;
+
+ //
+ // We have a script file, so increment the script index, and set the
+ // the index into the script buffer to zero. Make sure that we have
+ // not passed the maximum number of recursion in reading scripts.
+ //
+
+ if ( NextScriptIndex == TPCTL_MAX_SCRIPT_LEVELS )
+ {
+ TpctlErrorLog("\n\tTpctl: Too many levels of script reading recursion; level 0x%lx\n",
+ (PVOID)(NextScriptIndex+1));
+ return (DWORD)STATUS_UNSUCCESSFUL;
+ }
+
+ //
+ // First we allocate the memory to store the script file name in.
+ //
+
+ Scripts[NextScriptIndex].ScriptFile = GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT,
+ TPCTL_MAX_PATHNAME_SIZE );
+
+ if ( Scripts[NextScriptIndex].ScriptFile == NULL )
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctlLoadFiles: failed to alloc Script file name storage, returned 0x%lx.\n", (PVOID)Status);
+ return Status;
+ }
+
+ //
+ // Then determine what filename to write to it.
+ //
+
+ if ( ScriptFile[0] == '\0' )
+ {
+ //
+ // If no script file name was passed, then open the default
+ // script file TESTPROT.TPS.
+ //
+
+ strcpy( Scripts[NextScriptIndex].ScriptFile,TPCTL_SCRIPTFILE );
+ }
+ else
+ {
+ //
+ // Otherwise copy the filename passed into place.
+ //
+
+ strcpy( Scripts[NextScriptIndex].ScriptFile,ScriptFile );
+ }
+
+ //
+ // Open the script file, if it does not exist fail with an error msg.
+ //
+
+ FileHandle = CreateFile(Scripts[NextScriptIndex].ScriptFile,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL );
+
+ if ( FileHandle == (HANDLE)-1 )
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: failed to open script file \"%s\", ",
+ (PVOID)Scripts[NextScriptIndex].ScriptFile);
+ TpctlErrorLog("returned 0x%lx.\n",(PVOID)Status);
+ return Status;
+ }
+
+ //
+ // and find its size.
+ //
+
+ FileSize = GetFileSize( FileHandle,NULL );
+
+ if ( FileSize == -1 )
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: failed find file size - returned 0x%lx.\n",
+ (PVOID)Status);
+ return Status;
+ }
+
+ //
+ // If necessary allocate memory for the Buffer.
+ //
+
+ if ( Scripts[NextScriptIndex].Buffer == NULL )
+ {
+ Scripts[NextScriptIndex].Buffer = (LPBYTE)GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT,
+ FileSize );
+
+ if ( Scripts[NextScriptIndex].Buffer == NULL )
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctlLoadFiles: failed to alloc script buffer, returned 0x%lx.\n",
+ (PVOID)Status);
+ CloseHandle( FileHandle );
+ return Status;
+ }
+
+ }
+ else if ( FileSize > Scripts[NextScriptIndex].Length )
+ {
+ Scripts[NextScriptIndex].Buffer =
+ (LPBYTE)GlobalReAlloc( (HANDLE)Scripts[NextScriptIndex].Buffer,
+ FileSize,
+ GMEM_ZEROINIT | GMEM_MOVEABLE );
+
+ if ( Scripts[NextScriptIndex].Buffer == NULL )
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctlLoadFiles: failed to ReAlloc script buffer, returned 0x%lx.\n",
+ (PVOID)Status);
+ CloseHandle( FileHandle );
+ return Status;
+ }
+ }
+
+ //
+ // And read the script file into it.
+ //
+
+ Status = ReadFile( FileHandle,
+ Scripts[NextScriptIndex].Buffer,
+ FileSize,
+ &Scripts[NextScriptIndex].Length,
+ NULL );
+
+ if ( Status != TRUE )
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctlLoadFiles: failed to read script file \"%s\", ",(PVOID)ScriptFile);
+ TpctlErrorLog("returned 0x%lx.\n",(PVOID)Status);
+ CloseHandle( FileHandle );
+ return Status;
+ }
+
+ //
+ // We are done with script file now, so close it.
+ //
+
+ if (!CloseHandle(FileHandle))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctlLoadFiles: failed to close Script file \"%s\", ",(PVOID)ScriptFile);
+ TpctlErrorLog("returned 0x%lx.\n",(PVOID)Status);
+ }
+
+ //
+ // Now handle the log file. If we are not given a log file we need
+ // to determine the name of the log file we should use.
+ // First we allocate the memory to store the log file name in.
+ //
+
+ Scripts[NextScriptIndex].LogFile = GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT,
+ TPCTL_MAX_PATHNAME_SIZE );
+
+ if ( Scripts[NextScriptIndex].LogFile == NULL )
+ {
+ Status = GetLastError();
+ TpctlErrorLog(
+ "\n\tTpctlLoadFiles: failed to alloc Log file name storage, returned 0x%lx.\n",
+ (PVOID)Status);
+ return Status;
+ }
+
+ //
+ // Then determine what filename to write to it.
+ //
+
+ if (( LogFile == NULL ) || ( LogFile[0] == '\0' ))
+ {
+ if ( NextScriptIndex == 0 )
+ {
+ //
+ // If this is the first script file and no log file name was
+ // given, then use the default log file name.
+ //
+
+ strcpy( Scripts[NextScriptIndex].LogFile,TPCTL_LOGFILE );
+ }
+ else
+ {
+ //
+ // Otherwise, since no new log file name was given, and we are
+ // recursively reading script files we will use the log file
+ // used by the last level of script files.
+ //
+
+ strcpy( Scripts[NextScriptIndex].LogFile,Scripts[ScriptIndex].LogFile );
+ Scripts[NextScriptIndex].LogHandle = Scripts[ScriptIndex].LogHandle;
+ }
+
+ }
+ else
+ {
+ //
+ // We have a log file name so copy it into the scripts structure.
+ //
+
+ strcpy(Scripts[NextScriptIndex].LogFile,LogFile);
+ }
+
+ //
+ // Now, if the log file has not already been opened, then we must open
+ // it. If the logfile already exists it WILL be truncated on the open.
+ //
+
+ if (( LogFile != NULL ) && ( LogFile[0] != '\0' ) ||
+ ( NextScriptIndex == 0 ))
+ {
+ if ( WriteThrough )
+ {
+ Scripts[NextScriptIndex].LogHandle =
+ CreateFile( Scripts[NextScriptIndex].LogFile,
+ GENERIC_WRITE,
+ FILE_SHARE_WRITE | FILE_SHARE_READ,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
+ NULL );
+ }
+ else
+ {
+ Scripts[NextScriptIndex].LogHandle =
+ CreateFile( Scripts[NextScriptIndex].LogFile,
+ GENERIC_WRITE,
+ FILE_SHARE_WRITE | FILE_SHARE_READ,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL );
+ }
+
+ if ( Scripts[NextScriptIndex].LogHandle == (HANDLE)-1 )
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: failed to open log file \"%s\", ",
+ (PVOID)Scripts[NextScriptIndex].LogFile);
+ TpctlErrorLog("returned 0x%lx.\n",(PVOID)Status);
+ return Status;
+ }
+ }
+
+ //
+ // We have successfully opened the script and log files, and are now
+ // ready to read commands from the script buffer, set the flag stating
+ // that the commands are coming from the script file, and increment the
+ // scriptindex to point to the newly create script info.
+ //
+
+ CommandsFromScript = TRUE;
+
+ ScriptIndex = NextScriptIndex;
+
+ return NO_ERROR;
+}
+
+
+
+VOID
+TpctlFreeFileBuffers(
+ VOID
+ )
+
+// ---------------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+// --------------
+
+{
+ DWORD si = 0;
+ HANDLE tmpHandle;
+ DWORD Status;
+
+ for (si=0;si<TPCTL_MAX_SCRIPT_LEVELS;si++)
+ {
+ if ( Scripts[si].Buffer != NULL )
+ {
+ tmpHandle = GlobalFree( (HANDLE)Scripts[si].Buffer );
+
+ if ( tmpHandle != NULL )
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctlFreeFileBuffers: GlobalFree failed: returned 0x%lx.\n",
+ (PVOID)Status);
+ }
+ }
+
+ Scripts[si].Buffer = NULL;
+ Scripts[si].Length = 0;
+ }
+}
+
+
+
+VOID
+TpctlUnLoadFiles(
+ VOID
+ )
+
+// ---------------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+// --------------
+
+{
+ DWORD si;
+ HANDLE tmpHandle;
+ DWORD Status;
+
+ //
+ // TpctlUnloadFiles may be called to unload a file that is no longer
+ // needed, or a file that was not successfully loaded by TpctlLoadFiles.
+ // If the file to be unloaded is one that failed to load during the load
+ // files routine, then the ScriptIndex does not point to the correct
+ // field in the script array, so we must adjust the index pointer
+ // to the next field, otherwise just unload the file pointed by the
+ // ScriptIndex.
+ //
+
+ si = ScriptIndex;
+
+ if (( ScriptIndex < 0 ) || ( Scripts[si].IsLowestLevel == FALSE ))
+ {
+ si++;
+ }
+
+ //
+ // Free up the memory used to store the file names, and the
+ // script file commands.
+ //
+
+ if ( Scripts[si].ScriptFile != NULL )
+ {
+ tmpHandle = GlobalFree( Scripts[si].ScriptFile );
+
+ if ( tmpHandle != NULL )
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctlUnLoadFiles: GlobalFree failed: returned 0x%lx.\n",
+ (PVOID)Status);
+ }
+ }
+
+ if ( Scripts[si].LogFile != NULL )
+ {
+ tmpHandle = GlobalFree( Scripts[si].LogFile );
+
+ if ( tmpHandle != NULL )
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctlUnLoadFiles: GlobalFree failed: returned 0x%lx.\n",
+ (PVOID)Status);
+ }
+ }
+
+ //
+ // Do we have a unique log file, or was the log file opened by a higher
+ // order recursion of the TpctlLoadFiles routine?
+ //
+
+ if (( Scripts[si].LogHandle != (HANDLE)-1 ) && // log handle exists
+ (( si == 0 ) || // first level of recursion
+ ( Scripts[si].LogHandle != Scripts[si-1].LogHandle )))
+ {
+
+ //
+ // This level of the ReadScript command opened the log file, so
+ // we must close it now.
+ //
+
+ CloseHandle( Scripts[si].LogHandle );
+ }
+
+ //
+ // Now set all the fields to their intial state.
+ //
+
+ Scripts[si].ScriptFile = NULL;
+ Scripts[si].BufIndex = 0;
+ Scripts[si].LogHandle = (HANDLE)-1;
+ Scripts[si].LogFile = NULL;
+ Scripts[si].IsLowestLevel = FALSE;
+
+ //
+ // If we are simply unloading a script that we are finished with
+ // then decrement the index into the Scripts array to reference the
+ // next higher level, if it exists, in the ReadScript recursion.
+ // If we are unloading the highest level script file then reset
+ // the commandsfromscript flag to state that we no longer are
+ // reading the commands from a script file.
+ //
+
+ if ( si == ScriptIndex )
+ {
+ if ( --ScriptIndex == -1 )
+ {
+ CommandsFromScript = FALSE;
+ TpctlFreeFileBuffers();
+ }
+ }
+
+ if ( si != 0 )
+ {
+ Scripts[si-1].IsLowestLevel = TRUE;
+ }
+}
+
+
+
+HANDLE
+TpctlOpenLogFile(
+ VOID
+ )
+
+// -------------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// ------------
+
+{
+ HANDLE LogHandle;
+ DWORD Status;
+
+ if ( WriteThrough )
+ {
+ LogHandle = CreateFile( GlobalCmdArgs.ARGS.FILES.LogFile,
+ GENERIC_WRITE,
+ FILE_SHARE_WRITE | FILE_SHARE_READ,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
+ NULL );
+ }
+ else
+ {
+ LogHandle = CreateFile( GlobalCmdArgs.ARGS.FILES.LogFile,
+ GENERIC_WRITE,
+ FILE_SHARE_WRITE | FILE_SHARE_READ,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL );
+ }
+
+
+ if ( LogHandle == (HANDLE)-1 )
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: failed to open log file\"%s\", ",
+ (PVOID)GlobalCmdArgs.ARGS.FILES.LogFile);
+ TpctlErrorLog("returned 0x%lx.\n",(PVOID)Status);
+ }
+
+ return LogHandle;
+}
+
+
+
+VOID
+TpctlCloseLogFile(
+ VOID
+ )
+
+{
+ DWORD Status;
+
+ if (!CloseHandle( CommandLineLogHandle ))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctlCloseLogFile: failed to close Log file; returned 0x%lx.\n",
+ (PVOID)Status);
+ }
+
+ return;
+}
+
+
+
+HANDLE
+TpctlOpenScriptFile(
+ VOID
+ )
+
+// ----------------
+//
+// Routine Description:
+//
+// Created Sanjeevk 7-1-93
+//
+// This is a new function defined for the purpose of opening up a file
+// to which commands will be written
+//
+// Arguments:
+//
+// None
+//
+// Global Arguments effected:
+//
+// RecordScriptName
+//
+// Return Value:
+//
+// A HANDLE to the script file or NULL
+//
+// ---------------
+
+{
+ HANDLE ScriptHandle;
+ DWORD Status;
+
+
+ //
+ // 1. Clear the global variable and copy in the name of the file
+ // to be opened
+ //
+
+ memset( RecordScriptName, 0, (TPCTL_MAX_PATHNAME_SIZE*sizeof(CHAR)) );
+ strcpy( RecordScriptName, GlobalCmdArgs.ARGS.RECORD.ScriptFile );
+
+ if ( WriteThrough )
+ {
+ ScriptHandle = CreateFile( GlobalCmdArgs.ARGS.RECORD.ScriptFile,
+ GENERIC_WRITE,
+ FILE_SHARE_WRITE | FILE_SHARE_READ,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
+ NULL );
+ }
+ else
+ {
+ ScriptHandle = CreateFile( GlobalCmdArgs.ARGS.RECORD.ScriptFile,
+ GENERIC_WRITE,
+ FILE_SHARE_WRITE | FILE_SHARE_READ,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL );
+ }
+
+
+ if ( ScriptHandle == (HANDLE)-1 )
+ {
+ Status = GetLastError();
+ ZeroMemory( RecordScriptName, (TPCTL_MAX_PATHNAME_SIZE*sizeof(CHAR)) );
+ TpctlErrorLog("\n\tTpctl: failed to open script recording file\"%s\", ",
+ (PVOID)GlobalCmdArgs.ARGS.RECORD.ScriptFile);
+ TpctlErrorLog("returned 0x%lx.\n",(PVOID)Status);
+ }
+
+ return ScriptHandle;
+}
+
+
+
+VOID
+TpctlCloseScriptFile(
+ VOID
+ )
+
+// ---------------
+//
+// Routine Description:
+//
+// Created Sanjeevk 7-1-93
+//
+// This is a new function defined for the purpose of closing a file
+// to which commands were being written
+//
+// Arguments:
+//
+// None
+//
+// Global Arguments effected:
+//
+// RecordScriptName
+// ScriptRecordHandle
+//
+// Return Value:
+//
+// None
+//
+// ---------------
+
+{
+ DWORD Status;
+
+ ZeroMemory( RecordScriptName, (TPCTL_MAX_PATHNAME_SIZE*sizeof(CHAR)) );
+
+ if (!CloseHandle( ScriptRecordHandle ))
+ {
+ Status = GetLastError();
+ TpctlErrorLog(
+ "\n\tTpctlCloseScriptFile: failed to close script record file; returned 0x%lx.\n",
+ (PVOID)Status);
+ }
+
+ return;
+}
+
+
+
+
+DWORD
+TpctlReadCommand(
+ IN LPSTR Prompt,
+ OUT LPSTR Buffer,
+ IN DWORD MaximumResponse
+ )
+
+// --------------
+//
+// Routine Description:
+//
+// This routine reads from the debug port or the command file one command.
+//
+// Arguments:
+//
+// IN LPSTR Prompt,
+// OUT LPSTR Buffer,
+// IN DWORD MaximumResponse,
+//
+// Return Value:
+//
+// DWORD - NO_ERROR
+//
+// -------------
+
+{
+ DWORD Status = NO_ERROR;
+ LPSTR CmdBufPtr = Buffer;
+ DWORD i, j, k;
+ BYTE LineBuf[TPCTL_CMDLINE_SIZE];
+ BYTE TmpBuf[TPCTL_CMDLINE_SIZE];
+ LPBYTE EndOfCmd;
+ LPBYTE SBuf;
+ BOOL ContinueCommand = FALSE;
+ BOOL InitialCommand = TRUE;
+ BOOL FoundEnvVar;
+ LPSTR EnvVar;
+
+ //
+ // If the ScriptIndex equals -1 we are reading commands from the
+ // command line, so we will prompt the user to enter commands.
+ //
+
+ if ( ScriptIndex == -1 )
+ {
+ TpctlPrompt( Prompt,LineBuf,MaximumResponse );
+
+ i = 0; // LineBuf index
+ k = 0; // Buffer index
+
+ while (( i < TPCTL_CMDLINE_SIZE ) &&
+ (( LineBuf[i] != '\n' ) &&
+ ( LineBuf[i] != '\r' )))
+ {
+ //
+ // If we have found the beginning of an Environment
+ // Variable argument
+ //
+
+ if ( LineBuf[i] == '%' )
+ {
+ j = (DWORD)-1;
+ FoundEnvVar = FALSE;
+ i++;
+
+ //
+ // Copy it into a temp buffer.
+ //
+
+ while (( LineBuf[i] != '\n' ) &&
+ (( LineBuf[i] != ' ' ) &&
+ (( LineBuf[i] != '\t' ) &&
+ ( LineBuf[i] != '\r' ))))
+ {
+ TmpBuf[++j] = LineBuf[i++];
+
+ if ( TmpBuf[j] == '%')
+ {
+ TmpBuf[j] = '\0';
+ FoundEnvVar = TRUE;
+ break;
+ }
+ }
+
+ TmpBuf[j] = '\0';
+
+ //
+ // And find its true value in the process environment.
+ //
+
+ if ( FoundEnvVar == TRUE )
+ {
+ EnvVar = getenv( _strupr( TmpBuf ));
+
+ if ( EnvVar == NULL )
+ {
+ TpctlErrorLog("\n\tTpctl: Undefined Environment Variable \"%%%s%%\".\n",
+ TmpBuf);
+ return ERROR_ENVVAR_NOT_FOUND;
+ }
+
+ //
+ // and copy the value to the line buffer.
+ //
+
+ do
+ {
+ Buffer[k++] = *EnvVar++;
+ } while ( *EnvVar != '\0' );
+
+ }
+ else
+ {
+ TmpBuf[++j] = '\0';
+ TpctlErrorLog("\n\tTpctl: Invalid Environment Variable Format \"%%%s\".\n",
+ TmpBuf);
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Otherwise just copy the next character to the line buffer.
+ //
+
+ }
+ else
+ {
+ Buffer[k++] = LineBuf[i++];
+ }
+ }
+
+ //
+ // and then print the commands to the log file if necessary.
+ //
+
+ TpctlCmdLneLog(" %s\n", Buffer);
+
+ //
+ // Otherwise we are reading commands from a script file, so return
+ // the next command in the file.
+ //
+
+ }
+ else if ( Scripts[ScriptIndex].BufIndex >= Scripts[ScriptIndex].Length )
+ {
+ //
+ // We are at the end of this script file, clean up the script
+ // and log files.
+ //
+
+ TpctlUnLoadFiles();
+
+ //
+ // Set the return value in Buffer to null indicating that
+ // there was no command.
+ //
+
+ *Buffer = 0x0;
+
+ }
+ else
+ {
+ //
+ // Null out the Buffer buffer so that we don't use any garbage
+ // laying around from the last command.
+ //
+
+ ZeroMemory(Buffer, TPCTL_CMDLINE_SIZE);
+
+ SBuf = Scripts[ScriptIndex].Buffer;
+
+ while ((DWORD)(CmdBufPtr - Buffer) < MaximumResponse )
+ {
+ //
+ // and null out the temporary command buffer.
+ //
+
+ ZeroMemory(LineBuf, TPCTL_CMDLINE_SIZE);
+
+ //
+ // Read the next command line from the script file.
+ //
+
+ i = (DWORD)-1;
+
+ while ( Scripts[ScriptIndex].BufIndex <
+ Scripts[ScriptIndex].Length )
+ {
+ //
+ // If we have found the beginning of an Environment
+ // Variable argument...
+ //
+
+ if ( SBuf[Scripts[ScriptIndex].BufIndex] == '%' )
+ {
+ j = (DWORD)-1;
+ FoundEnvVar = FALSE;
+ Scripts[ScriptIndex].BufIndex++;
+
+ //
+ // Copy it into a temp buffer.
+ //
+
+ while (( SBuf[Scripts[ScriptIndex].BufIndex] != '\n' ) &&
+ (( SBuf[Scripts[ScriptIndex].BufIndex] != ' ' ) &&
+ (( SBuf[Scripts[ScriptIndex].BufIndex] != '\t' ) &&
+ ( SBuf[Scripts[ScriptIndex].BufIndex] != '\r' ))))
+ {
+ TmpBuf[++j] = SBuf[Scripts[ScriptIndex].BufIndex++];
+
+ if ( TmpBuf[j] == '%')
+ {
+ TmpBuf[j] = '\0';
+ FoundEnvVar = TRUE;
+ break;
+ }
+ }
+
+ //
+ // And find its true value in the process environment.
+ //
+
+ if ( FoundEnvVar == TRUE )
+ {
+ EnvVar = getenv( _strupr( TmpBuf ));
+
+ if ( EnvVar == NULL )
+ {
+ TpctlErrorLog("\n\tTpctl: Undefined Environment Variable \"%%%s%%\".\n",
+ TmpBuf);
+ return ERROR_ENVVAR_NOT_FOUND;
+ }
+
+ //
+ // and copy the value to the line buffer.
+ //
+
+ do
+ {
+ LineBuf[++i] = *EnvVar++;
+ } while ( *EnvVar != '\0' );
+
+ }
+ else
+ {
+ TmpBuf[++j] = '\0';
+ TpctlErrorLog("\n\tTpctl: Invalid Environment Variable Format \"%%%s\".\n",
+ TmpBuf);
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Otherwise just copy the next character to the line buffer.
+ //
+
+ }
+ else
+ {
+ LineBuf[++i] = SBuf[Scripts[ScriptIndex].BufIndex++];
+ }
+
+ if ( LineBuf[i] == '\n' )
+ {
+ break;
+ }
+ }
+
+ LineBuf[i] = '\0';
+
+ if ( InitialCommand == TRUE )
+ {
+ TpctlLog("%s ",Prompt);
+ InitialCommand = FALSE;
+ }
+ else
+ {
+ TpctlLog("\t ",NULL );
+ }
+
+ TpctlLog("%s\n",LineBuf);
+
+ if ( !Verbose )
+ {
+ if ( strstr( LineBuf,"TITLE:" ) != NULL )
+ {
+ TpctlErrorLog("\n%s ",Prompt);
+ TpctlErrorLog("%s\n\n",LineBuf);
+ }
+ }
+
+ // check for comment ending line
+
+ ContinueCommand = FALSE;
+ if ( (EndOfCmd = strchr( LineBuf, '#')) != NULL)
+ {
+ //
+ // We just have a comment, set the command continue
+ // flag to exit the command parsing, and null the
+ // command section of the string.
+ //
+ EndOfCmd[0] = '\0';
+ }
+
+ // check for a closing parenthesis on line. This is the end of any SETGLOBALS
+ // command that contains an expression. No other command uses parenthesis
+
+ if ( (EndOfCmd = strchr( LineBuf, ')' )) != NULL)
+ {
+ EndOfCmd[1] = '\0'; // closing parenthese is last thing on line
+ }
+ else if ( (EndOfCmd = strchr( LineBuf, '+' )) != NULL)
+ {
+ //
+ // This is a Cmd Continuation, set the flag to continue
+ // the while loop, and ignore the rest of the line.
+ //
+ ContinueCommand = TRUE;
+ EndOfCmd[0] = '\0';
+ }
+
+ i=0;
+
+ while ( LineBuf[i] != '\0' )
+ {
+ if ((( LineBuf[i] == ' ' ) ||
+ ( LineBuf[i] == '\t' )) ||
+ ( LineBuf[i] == '\r' ))
+ {
+ *CmdBufPtr++ = ' ';
+
+ while ((( LineBuf[i] == ' ' ) ||
+ ( LineBuf[i] == '\t' )) ||
+ ( LineBuf[i] == '\r' ))
+ {
+ i++;
+ }
+
+ }
+ else
+ {
+ *CmdBufPtr++ = LineBuf[i++];
+ }
+ }
+
+ if ( ContinueCommand == FALSE )
+ {
+ return Status;
+ }
+ }
+ }
+
+ return Status;
+}
+
+
+
+BOOL
+TpctlParseCommand(
+ IN LPSTR CommandLine,
+ OUT LPSTR Argv[],
+ OUT PDWORD Argc,
+ IN DWORD MaxArgc
+ )
+{
+ LPSTR cl = CommandLine;
+ DWORD ac = 0;
+ BOOL DoubleQuotesDetected, DetectedEndOfString, StartOfString;
+
+ while ( *cl && (ac < MaxArgc) )
+ {
+ //
+ // Skip to get to the lvalue
+ //
+ while ( *cl && (*cl <= ' ') ) // ignore leading blanks
+ {
+ cl++;
+ }
+
+ if ( !*cl )
+ {
+ break;
+ }
+
+ //
+ // Argument detected. Initialize the Argv and increment the counter
+ //
+
+ *Argv++ = cl;
+ ++ac;
+
+ DoubleQuotesDetected = DetectedEndOfString = FALSE;
+ StartOfString = TRUE;
+
+ while( !DetectedEndOfString )
+ {
+ while ( *cl > ' ')
+ {
+ if ( StartOfString && (*cl == '"') && (*(cl-1) == '=') )
+ {
+ DoubleQuotesDetected = TRUE;
+ StartOfString = FALSE;
+ }
+ cl++;
+ }
+
+ if ( DoubleQuotesDetected )
+ {
+ if ( ((*(cl-1) == '"') && (*(cl-2) != '\\')) ||
+ ( *cl != ' ' ) )
+ {
+ DetectedEndOfString = TRUE;
+ }
+ else
+ {
+ cl++;
+ }
+ }
+ else
+ {
+ DetectedEndOfString = TRUE;
+ }
+ }
+
+ if ( *cl )
+ {
+ *cl++ = '\0';
+ }
+
+ }
+
+ if ( ac < MaxArgc )
+ {
+ *Argv++ = NULL;
+ }
+ else if ( *cl )
+ {
+ TpctlErrorLog("\n\tTpctl: Too many tokens in command; \"%s\".\n",(PVOID)cl);
+ return FALSE;
+ }
+
+ *Argc = ac;
+
+ return TRUE;
+}
+
+
+
+VOID
+TpctlPrompt(
+ LPSTR Prompt,
+ LPSTR Buffer,
+ DWORD BufferSize
+ )
+
+// -----------
+//
+// Routine Description:
+//
+//
+// Arguments:
+//
+// Prompt -
+// Buffer -
+// BufferSize -
+//
+// Return Value:
+//
+// None.
+//
+// ----------
+
+{
+ LPSTR NewLine;
+ DWORD ReadAmount;
+
+ //
+ // print out the prompt command, and then read the user's input.
+ // We are using the TpctlErrorLog routine to print it to the
+ // screen and the log files because we know that verbose mode
+ //
+
+ TpctlErrorLog("%s ",Prompt);
+
+ ReadFile( GetStdHandle(STD_INPUT_HANDLE),
+ (LPVOID )Buffer,
+ BufferSize,
+ &ReadAmount,
+ NULL );
+
+ //
+ // If the user typed <CR>, then the buffer contains a single
+ // <CR> character. We want to remove this character, and replace it with
+ // a nul character.
+ //
+
+ if ( (NewLine = strchr(Buffer, '\r')) != NULL )
+ {
+ *NewLine = '\0';
+ }
+
+}
+
+
+
+VOID
+TpctlLoadLastEnvironmentVariables(
+ DWORD OpenInstance
+ )
+
+// --------------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// None.
+//
+// -------------
+
+{
+ GlobalCmdArgs.ARGS.ENV.WindowSize =
+ Open[OpenInstance].EnvVars->WindowSize;
+
+ GlobalCmdArgs.ARGS.ENV.RandomBufferNumber =
+ Open[OpenInstance].EnvVars->RandomBufferNumber;
+
+ GlobalCmdArgs.ARGS.ENV.StressDelayInterval =
+ Open[OpenInstance].EnvVars->StressDelayInterval;
+
+ GlobalCmdArgs.ARGS.ENV.UpForAirDelay =
+ Open[OpenInstance].EnvVars->UpForAirDelay;
+
+ GlobalCmdArgs.ARGS.ENV.StandardDelay =
+ Open[OpenInstance].EnvVars->StandardDelay;
+
+ strcpy( GlobalCmdArgs.ARGS.ENV.StressAddress,
+ Open[OpenInstance].EnvVars->StressAddress );
+
+ strcpy( GlobalCmdArgs.ARGS.ENV.ResendAddress,
+ Open[OpenInstance].EnvVars->ResendAddress );
+}
+
+
+
+VOID
+TpctlSaveNewEnvironmentVariables(
+ DWORD OpenInstance
+ )
+
+// ---------------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+// -------------
+
+{
+ Open[OpenInstance].EnvVars->WindowSize =
+ GlobalCmdArgs.ARGS.ENV.WindowSize;
+
+ Open[OpenInstance].EnvVars->WindowSize =
+ GlobalCmdArgs.ARGS.ENV.RandomBufferNumber;
+
+ Open[OpenInstance].EnvVars->StressDelayInterval =
+ GlobalCmdArgs.ARGS.ENV.StressDelayInterval;
+
+ Open[OpenInstance].EnvVars->UpForAirDelay =
+ GlobalCmdArgs.ARGS.ENV.UpForAirDelay;
+
+ Open[OpenInstance].EnvVars->StandardDelay =
+ GlobalCmdArgs.ARGS.ENV.StandardDelay;
+
+ strcpy( Open[OpenInstance].EnvVars->StressAddress,
+ GlobalCmdArgs.ARGS.ENV.StressAddress );
+
+ strcpy( Open[OpenInstance].EnvVars->ResendAddress,
+ GlobalCmdArgs.ARGS.ENV.ResendAddress );
+}
+
+
+// !!check calls here for WIN32!!
+
+VOID
+TpctlPerformRegistryOperation(
+ IN PCMD_ARGS CmdArgs
+ )
+{
+ DWORD Status,ValueType,ValueSize ;
+ DWORD ReadValueType, ReadValueSize;
+ DWORD Disposition , BytesWritten ;
+ PUCHAR ReadValue = NULL ;
+ UCHAR PrintStringBuffer[10], TmpChar;
+ HKEY DbaseHKey, KeyHandle ;
+ REGSAM SamDesired ;
+ LPSTR TmpBuf = GlobalBuf, StopString ;
+ LPSTR SubKeyName = &CmdArgs->ARGS.REGISTRY_ENTRY.SubKey[1] ;
+ LPSTR ValueName = &CmdArgs->ARGS.REGISTRY_ENTRY.SubKeyValueName[1];
+ LPSTR Value = CmdArgs->ARGS.REGISTRY_ENTRY.SubKeyValue ;
+ LPSTR DbaseName = KeyDbaseTable[CmdArgs->ARGS.REGISTRY_ENTRY.OperationType].FieldName;
+ LPSTR ClassName = &CmdArgs->ARGS.REGISTRY_ENTRY.SubKeyClass[1] ;
+ LPSTR Tmp = NULL;
+ BOOL CompleteQueryStatus;
+ INT i,j,k,Radix = 16,CopyLength = 2;
+
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tCommandCode = %s\n",
+ TpctlGetCmdCode( CmdArgs->CmdCode ));
+
+ //
+ // Initialize and allocate resources
+ //
+
+ if ( (ReadValue = calloc( 2, MAX_VALUE_LENGTH )) == NULL )
+ {
+ TpctlErrorLog( "\n\tTpctl: TpctlPeformRegistryOperation: Unable to allocate memory resources\n", NULL );
+ return;
+ }
+
+ //
+ // Clear and write the buffer responsible for extracting the values
+ //
+
+ ZeroMemory ( PrintStringBuffer, sizeof( PrintStringBuffer ) );
+ sprintf( PrintStringBuffer, "%%%d.%dx", sizeof(DWORD), sizeof(DWORD) );
+
+ //
+ // Set the appropriate DataBase key
+ //
+
+ switch( CmdArgs->ARGS.REGISTRY_ENTRY.KeyDatabase )
+ {
+ case CLASSES_ROOT :
+ DbaseHKey = HKEY_CLASSES_ROOT;
+ break;
+
+ case CURRENT_USER :
+ DbaseHKey = HKEY_CURRENT_USER;
+ break;
+
+ case LOCAL_MACHINE:
+ DbaseHKey = HKEY_LOCAL_MACHINE;
+ break;
+
+ case USERS:
+ DbaseHKey = HKEY_USERS;
+ break;
+
+ default:
+ TpctlErrorLog("\n\tTpctl: %d not a valid Key DataBase",
+ (PVOID)CmdArgs->ARGS.REGISTRY_ENTRY.KeyDatabase );
+ return;
+ }
+
+ //
+ // The SubKey Name
+ // The Value name
+ // The Class Name
+ //
+ if ( (Tmp = strrchr( SubKeyName, '"' )) != NULL )
+ {
+ *Tmp = '\0';
+ }
+ if ( (Tmp = strrchr( ValueName, '"' )) != NULL )
+ {
+ *Tmp = '\0';
+ }
+ if ( (Tmp = strrchr( ClassName, '"' )) != NULL )
+ {
+ *Tmp = '\0';
+ }
+
+ //
+ // The value type and the associated value
+ //
+
+ switch( CmdArgs->ARGS.REGISTRY_ENTRY.ValueType )
+ {
+ case BINARY :
+ ValueType = REG_BINARY;
+ i = 0;
+ j = 0; // Default begin extraction from String[j=0]:Value buffer starting point
+ k = 0; // Default:Input Value is in hex or binary - designator.
+ // 0 is HEX, 1 is BINARY
+ ValueSize = strlen( Value );
+ if( ValueSize >= 2 )
+ {
+ if ( toupper( Value[1] ) == 'B' )
+ {
+ j = 2;
+ k = 1;
+ Radix = 2;
+ CopyLength = 8;
+ }
+ }
+ {
+ UCHAR BitStream[9];
+ PUCHAR PTmpChar;
+ DWORD BytesToCopy;
+
+ while( j < (INT)ValueSize )
+ {
+ memset( BitStream, '\0', sizeof( BitStream ) );
+ memset( BitStream, '0' , sizeof(UCHAR)*CopyLength );
+ BytesToCopy = min( strlen( &Value[j] ), (DWORD)CopyLength );
+ memcpy( BitStream, &Value[j], BytesToCopy );
+ Value[i] = (UCHAR)strtoul( BitStream,&PTmpChar, Radix );
+ i++;
+ j += BytesToCopy;
+ }
+ ValueSize = i;
+ }
+ break;
+
+ case DWORD_REGULAR :
+ ValueType = REG_DWORD;
+ ValueSize = sizeof( DWORD );
+ *(LPDWORD)Value = strtoul( Value, &StopString, 0 );
+ break;
+
+ case DWORD_LITTLE_ENDIAN :
+ ValueType = REG_DWORD_LITTLE_ENDIAN;
+ ValueSize = sizeof( DWORD );
+ {
+ DWORD TmpValue = strtoul( Value, &StopString, 0 );
+ sprintf( Value, PrintStringBuffer, TmpValue );
+ }
+ // Reverse the array since this is Big Endian
+
+ for( i = 0, j = ValueSize-1; i < (INT)ValueSize; i++,j-- )
+ {
+ Value[i] -= '0';
+ Value[j] -= '0';
+ TmpChar = Value[i];
+ Value[i] = Value[j];
+ Value[j] = TmpChar;
+ }
+ break;
+
+ case DWORD_BIG_ENDIAN :
+ ValueType = REG_DWORD_BIG_ENDIAN;
+ ValueSize = sizeof( DWORD );
+ {
+ DWORD TmpValue = strtoul( Value, &StopString, 0 );
+ sprintf( Value, PrintStringBuffer, TmpValue );
+ }
+ break;
+
+ case EXPAND_SZ :
+ ValueType = REG_EXPAND_SZ;
+ ValueSize = strlen( Value );
+ break;
+
+ case LINK :
+ ValueType = REG_LINK;
+ ValueSize = strlen( Value );
+ break;
+
+ case MULTI_SZ :
+ ValueType = REG_MULTI_SZ;
+
+ //
+ // The string Value needs to be readjusted. Use ReadValue as a temporary
+ // buffer
+
+ memset( ReadValue, 0, 2*MAX_VALUE_LENGTH );
+ {
+ UCHAR CanCopy = 0x0;
+ BOOL IgnoreNext = FALSE;
+
+ for( i = 0, j = 0 ; i < (INT)strlen( Value ); i++ )
+ {
+ if ( ( Value[i] == '"' ) && ( IgnoreNext == FALSE ) )
+ {
+ CanCopy = ~CanCopy;
+ if ( !CanCopy )
+ {
+ ReadValue[j++] = '\0';
+ }
+ }
+ if ( Value[i] == '\\' )
+ {
+ IgnoreNext = TRUE;
+ }
+ else
+ {
+ IgnoreNext = FALSE;
+ }
+ if ( CanCopy )
+ {
+ ReadValue[j++] = Value[i];
+ }
+ }
+ }
+
+ //
+ // Fill the 2 nulls at the end of the array
+ //
+
+ ReadValue[j++] = '\0';ReadValue[j++] = '\0';
+ ValueSize = j;
+ memcpy( Value, ReadValue, j );
+ memset( ReadValue, 0, 2*MAX_VALUE_LENGTH );
+ break;
+
+ case NONE :
+ ValueType = REG_NONE;
+ ValueSize = strlen( Value );
+ break;
+
+ case RESOURCE_LIST :
+ ValueType = REG_RESOURCE_LIST;
+ ValueSize = strlen( Value );
+ break;
+
+ case SZ :
+ ValueType = REG_SZ;
+ ValueSize = strlen( Value );
+ break;
+
+ default :
+ break;
+
+ }
+
+ //
+ // Switch to the demanded operation
+ //
+
+ switch ( CmdArgs->ARGS.REGISTRY_ENTRY.OperationType )
+ {
+ case ADD_KEY:
+ TmpBuf += (BYTE)sprintf( TmpBuf, "\tSubCommandCode = ADD_KEY\n" );
+
+ SamDesired = KEY_ALL_ACCESS;
+
+ Status = RegCreateKeyEx( DbaseHKey, SubKeyName, (DWORD)0,
+ ClassName, REG_OPTION_NON_VOLATILE,
+ SamDesired, NULL, &KeyHandle, &Disposition );
+
+ if ( Status != ERROR_SUCCESS )
+ {
+ TmpBuf += (BYTE)sprintf( TmpBuf, "\tStatus = %ldL\n", Status );
+ TmpBuf += (BYTE)sprintf( TmpBuf,
+ "\n\tTpctl: Unable to create\n\tSubkey : %s\n\tClassName: %s\n\tDatabase : %s\n",
+ SubKeyName, ClassName, DbaseName );
+ break;
+
+ }
+
+ TmpBuf += (BYTE)sprintf( TmpBuf, "\tStatus = SUCCESS\n" );
+ TmpBuf += (BYTE)sprintf( TmpBuf, "\tDisposition = " );
+
+ if ( Disposition == REG_CREATED_NEW_KEY )
+ {
+ TmpBuf += (BYTE)sprintf( TmpBuf, "CREATED A NEW KEY\n" );
+ }
+ else
+ {
+ TmpBuf += (BYTE)sprintf( TmpBuf, "KEY ALREADY EXISTS\n" );
+ }
+ break;
+
+ case DELETE_KEY:
+ TmpBuf += (BYTE)sprintf( TmpBuf, "\tSubCommandCode = DELETE_KEY\n" );
+
+ Status = RegDeleteKey( DbaseHKey, SubKeyName );
+ if ( Status != ERROR_SUCCESS ) {
+
+ TmpBuf += (BYTE)sprintf( TmpBuf, "\tStatus = %ldL\n", Status );
+ TmpBuf += (BYTE)sprintf( TmpBuf,
+ "\n\tTpctl: Unable to delete\n\tSubkey : %s\n\tClassName: %s\n\tDatabase : %s\n",
+ SubKeyName, ClassName, DbaseName );
+ break;
+
+ }
+
+ TmpBuf += (BYTE)sprintf( TmpBuf, "\tStatus = SUCCESS\n" );
+ break;
+
+
+ case QUERY_KEY:
+
+ CompleteQueryStatus = TRUE;
+
+ TmpBuf += (BYTE)sprintf( TmpBuf, "\tSubCommandCode = QUERY_KEY\n" );
+
+ //
+ // Open the Registry Key
+ //
+
+ SamDesired = KEY_READ;
+
+ Status = RegOpenKeyEx( DbaseHKey, SubKeyName, (DWORD)0, SamDesired, &KeyHandle );
+ if ( Status != ERROR_SUCCESS )
+ {
+ TmpBuf += (BYTE)sprintf( TmpBuf, "\tStatus = %ldL\n", Status );
+ TmpBuf += (BYTE)sprintf( TmpBuf,
+ "\n\tTpctl: Unable to open\n\tSubkey : %s\n\tClassName: %s\n\tDatabase : %s\n",
+ SubKeyName, ClassName, DbaseName );
+ break;
+
+ }
+
+ {
+ LPSTR TmpKeyClassName = NULL, TmpSubKeyName = NULL, TmpValueName = NULL;
+ DWORD NumberOfSubKeys, NumberOfValues, TmpValueType, ClassNameSize;
+ DWORD TmpDwordVar, LongestSubKeyNameSize, LongestSubKeyClassNameSize;
+ DWORD LongestValueNameSize;
+ FILETIME LastWriteTime;
+ SYSTEMTIME SystemTime;
+ CHAR *DayOfWeek[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
+ "Friday", "Saturday" };
+
+ if ( (TmpKeyClassName = calloc( 1, MAX_PATH+1 )) == NULL )
+ {
+ TpctlErrorLog(
+ "\n\tTpctl: TpctlPeformRegistryOperation: QueryKey unable to allocate memory resources\n",
+ NULL );
+ return;
+ }
+
+ ClassNameSize = MAX_PATH+1;
+ Status = RegQueryInfoKey( KeyHandle, TmpKeyClassName, &ClassNameSize,
+ NULL, &NumberOfSubKeys, &LongestSubKeyNameSize,
+ &LongestSubKeyClassNameSize, &NumberOfValues,
+ &LongestValueNameSize,
+ &TmpDwordVar, &TmpDwordVar, &LastWriteTime );
+
+ if ( (Status == ERROR_MORE_DATA) || (Status == ERROR_INSUFFICIENT_BUFFER) )
+ {
+ free( TmpKeyClassName );
+ if ( (TmpKeyClassName = calloc( 1, ClassNameSize+2 )) == NULL )
+ {
+ TpctlErrorLog( "\n\tTpctl: TpctlPeformRegistryOperation: QueryKey unable to allocate memory resources\n", NULL );
+ return;
+ }
+ Status = RegQueryInfoKey( KeyHandle, TmpKeyClassName, &ClassNameSize,
+ NULL, &NumberOfSubKeys, &LongestSubKeyNameSize,
+ &LongestSubKeyClassNameSize, &NumberOfValues,
+ &LongestValueNameSize,
+ &TmpDwordVar, &TmpDwordVar, &LastWriteTime );
+ }
+ if ( Status != ERROR_SUCCESS )
+ {
+ TmpBuf += (BYTE)sprintf( TmpBuf,"\tStatus = %ldL\n", Status );
+ TmpBuf += (BYTE)sprintf( TmpBuf,
+ "\n\tTpctl: Unable to QueryInfo on\n\tSubkey : %s\n\tClassName: %s\n\tDatabase : %s\n",
+ SubKeyName, ClassName, DbaseName );
+ break;
+ }
+
+ TmpBuf += sprintf( TmpBuf,
+ "\tKey Class Name = %s\n\tNumber Of SubKeys = %ld\n\tNumber of Values = %ld\n",
+ TmpKeyClassName, NumberOfSubKeys, NumberOfValues );
+
+ if ( FileTimeToSystemTime( &LastWriteTime, &SystemTime ) )
+ {
+ TmpBuf += sprintf( TmpBuf,
+ "\tLast Write Time = %s %2.2d-%2.2d-%4.4d at %2.2d:%2.2d:%2.2d %s\n",
+ DayOfWeek[SystemTime.wDayOfWeek],
+ SystemTime.wMonth,
+ SystemTime.wDay,
+ SystemTime.wYear,
+ ((SystemTime.wHour > 12) ? (SystemTime.wHour-12)
+ : SystemTime.wHour),
+ SystemTime.wMinute,
+ SystemTime.wSecond,
+ ((SystemTime.wHour > 12) ? "AM" : "PM") );
+ }
+ else
+ {
+ TmpBuf += sprintf( TmpBuf, "\tLast Write Time = Undefined\n" );
+ }
+
+ free( TmpKeyClassName );
+
+ if ( (TmpSubKeyName = calloc( 1, LongestSubKeyNameSize+2 )) == NULL )
+ {
+ TpctlErrorLog( "\n\tTpctl: TpctlPeformRegistryOperation: QueryKey unable to allocate memory resources\n", NULL );
+ return;
+ }
+
+ TmpBuf += sprintf( TmpBuf, "\tSub Key Name(s)\n" );
+
+ for( i = 0; i < (INT)NumberOfSubKeys; i++ )
+ {
+ memset( TmpSubKeyName, 0, LongestSubKeyNameSize+2 );
+ Status = RegEnumKey( KeyHandle, i, TmpSubKeyName, LongestSubKeyNameSize+2 );
+ if ( Status != ERROR_SUCCESS )
+ {
+ TmpBuf += (BYTE)sprintf( TmpBuf,"\tStatus = %ldL\n", Status );
+ TmpBuf += (BYTE)sprintf( TmpBuf,
+ "\n\tTpctl: Unable to Enumerate Key Index %d from\n\tSubkey : %s\n\tClassName: %s\n\tDatabase : %s\n",
+ i, SubKeyName, ClassName, DbaseName );
+ CompleteQueryStatus = FALSE;
+ }
+ else
+ {
+ TmpBuf += sprintf( TmpBuf, "\t%2d.\t%s\n", i, TmpSubKeyName );
+ }
+ }
+
+ free( TmpSubKeyName );
+
+ if ( (TmpValueName = calloc( 1, LongestValueNameSize+2 )) == NULL )
+ {
+ TpctlErrorLog( "\n\tTpctl: TpctlPeformRegistryOperation: QueryKey unable to allocate memory resources\n", NULL );
+ return;
+ }
+
+ TmpBuf += sprintf( TmpBuf, "\tSub Key Value Name(s) and Associated Type(s)\n" );
+
+ for( i = 0; i < (INT)NumberOfValues; i++ )
+ {
+ memset( TmpValueName, 0, LongestValueNameSize+2 );
+ TmpDwordVar = LongestValueNameSize+2;
+ Status = RegEnumValue( KeyHandle, i, TmpValueName, &TmpDwordVar, NULL,
+ &TmpValueType, NULL, NULL );
+ if ( Status != ERROR_SUCCESS )
+ {
+ TmpBuf += (BYTE)sprintf( TmpBuf,"\tStatus = %ldL\n", Status );
+ TmpBuf += (BYTE)sprintf( TmpBuf,
+ "\n\tTpctl: Unable to Enumerate Value Index %d from\n\tSubkey : %s\n\tClassName: %s\n\tDatabase : %s\n",
+ i, SubKeyName, ClassName, DbaseName );
+ CompleteQueryStatus = FALSE;
+ }
+ else
+ {
+ TmpBuf += sprintf( TmpBuf,
+ "\t%2d.\t%-30s%-15s\n", i, TmpValueName, TpctlGetValueType( TmpValueType ) );
+
+ }
+ }
+
+ free( TmpValueName );
+
+ }
+
+ if ( CompleteQueryStatus )
+ {
+ TmpBuf += (BYTE)sprintf( TmpBuf, "\tComplete Query Status = SUCCESS\n" );
+ }
+ else
+ {
+ TmpBuf += (BYTE)sprintf( TmpBuf, "\tComplete Query Status = FAILURE\n" );
+ }
+ break;
+
+ case ADD_VALUE:
+ case CHANGE_VALUE:
+ if ( CmdArgs->ARGS.REGISTRY_ENTRY.OperationType == CHANGE_VALUE )
+ {
+ TmpBuf += (BYTE)sprintf( TmpBuf, "\tSubCommandCode = CHANGE_VALUE\n" );
+ SamDesired = KEY_WRITE|KEY_READ;
+ }
+ else
+ {
+ TmpBuf += (BYTE)sprintf( TmpBuf, "\tSubCommandCode = ADD_VALUE\n" );
+ SamDesired = KEY_ALL_ACCESS;
+ }
+
+
+ Status = RegOpenKeyEx( DbaseHKey, SubKeyName, (DWORD)0, SamDesired, &KeyHandle );
+ if ( Status != ERROR_SUCCESS )
+ {
+ TmpBuf += (BYTE)sprintf( TmpBuf,"\tStatus = %ldL\n", Status );
+ TmpBuf += (BYTE)sprintf( TmpBuf,
+ "\n\tTpctl: Unable to open\n\tSubkey : %s\n\tClassName: %s\n\tDatabase : %s\n",
+ SubKeyName, ClassName, DbaseName );
+ break;
+
+ }
+
+ //
+ // If this is a request to change a value, make sure that the value exists
+ //
+
+ if ( CmdArgs->ARGS.REGISTRY_ENTRY.OperationType == CHANGE_VALUE )
+ {
+ //
+ // Make sure the ValueName exist since this is a change request
+ //
+ ReadValueSize = 2*MAX_VALUE_LENGTH;
+ ReadValueType = ValueType;
+ Status = RegQueryValueEx( KeyHandle, ValueName, (DWORD)0, &ReadValueType,
+ ReadValue, &ReadValueSize );
+ if ( (Status != ERROR_SUCCESS) &&
+ (Status != ERROR_MORE_DATA) &&
+ (Status != ERROR_INSUFFICIENT_BUFFER) )
+ {
+ TmpBuf += (BYTE)sprintf( TmpBuf,"\tStatus = %ldL\n", Status );
+ TmpBuf += (BYTE)sprintf( TmpBuf,
+"\n\tTpctl: Unable to access\n\tValue : %s\n\tSubkey : %s\n\tClassName: %s\n\tDatabase : %s\n",
+ ValueName, SubKeyName, ClassName, DbaseName );
+ break;
+
+ }
+ }
+
+ //
+ // Now set the values as expected
+ //
+ Status = RegSetValueEx( KeyHandle, ValueName, (DWORD)0, ValueType, Value, ValueSize );
+ if ( Status != ERROR_SUCCESS )
+ {
+ TmpBuf += (BYTE)sprintf( TmpBuf,"\tStatus = %ldL\n", Status );
+ TmpBuf += (BYTE)sprintf( TmpBuf,
+"\n\tTpctl: Unable to change\n\tValue : %s\n\tSubkey : %s\n\tClassName: %s\n\tDatabase : %s\n",
+ ValueName, SubKeyName, ClassName, DbaseName );
+ break;
+
+ }
+ TmpBuf += (BYTE)sprintf( TmpBuf, "\tStatus = SUCCESS\n" );
+ break;
+
+
+ case DELETE_VALUE:
+ TmpBuf += (BYTE)sprintf( TmpBuf, "\tSubCommandCode = DELETE_VALUE\n" );
+
+ //
+ // Open the Registry Key
+ //
+ SamDesired = KEY_SET_VALUE;
+
+ Status = RegOpenKeyEx( DbaseHKey, SubKeyName, (DWORD)0, SamDesired, &KeyHandle );
+ if ( Status != ERROR_SUCCESS )
+ {
+ TmpBuf += (BYTE)sprintf( TmpBuf,"\tStatus = %ldL\n", Status );
+ TmpBuf += (BYTE)sprintf( TmpBuf,
+ "\n\tTpctl: Unable to open\n\tSubkey : %s\n\tClassName: %s\n\tDatabase : %s\n",
+ SubKeyName, ClassName, DbaseName );
+ break;
+
+ }
+
+ Status = RegDeleteValue( KeyHandle, ValueName );
+ if ( Status != ERROR_SUCCESS )
+ {
+ TmpBuf += (BYTE)sprintf( TmpBuf,"\tStatus = %ldL\n", Status );
+ TmpBuf += (BYTE)sprintf( TmpBuf,
+"\n\tTpctl: Unable to delete\n\tValue : %s\n\tSubkey : %s\n\tClassName: %s\n\tDatabase : %s\n",
+ ValueName, SubKeyName, ClassName, DbaseName );
+ break;
+
+ }
+
+ TmpBuf += (BYTE)sprintf( TmpBuf, "\tStatus = SUCCESS\n" );
+ break;
+
+ case QUERY_VALUE:
+ TmpBuf += (BYTE)sprintf( TmpBuf, "\tSubCommandCode = QUERY_VALUE\n" );
+
+ //
+ // Open the Registry Key
+ //
+ SamDesired = KEY_QUERY_VALUE;
+
+ Status = RegOpenKeyEx( DbaseHKey, SubKeyName, (DWORD)0, SamDesired, &KeyHandle );
+ if ( Status != ERROR_SUCCESS )
+ {
+ TmpBuf += (BYTE)sprintf( TmpBuf,"\tStatus = %ldL\n", Status );
+ TmpBuf += (BYTE)sprintf( TmpBuf,
+ "\n\tTpctl: Unable to open\n\tSubkey : %s\n\tClassName: %s\n\tDatabase : %s\n",
+ SubKeyName, ClassName, DbaseName );
+ break;
+ }
+
+ //
+ // Make sure the ValueName exist since this is a change request
+ //
+
+ ReadValueSize = 2*MAX_VALUE_LENGTH;
+ Status = RegQueryValueEx( KeyHandle, ValueName, (DWORD)0, &ReadValueType,
+ ReadValue, &ReadValueSize );
+
+ if ( (Status == ERROR_MORE_DATA) || (Status == ERROR_INSUFFICIENT_BUFFER) )
+ {
+ free( ReadValue );
+ ReadValue = NULL;
+ ReadValue = calloc( 1, ReadValueSize+1 );
+ if ( ReadValue == NULL )
+ {
+ TpctlErrorLog(
+ "\n\tTpctl: TpctlPeformRegistryOperation: QueryValue unable to allocate memory resources\n",
+ NULL );
+ return;
+ }
+ Status = RegQueryValueEx( KeyHandle, ValueName, (DWORD)0, &ReadValueType,
+ ReadValue, &ReadValueSize );
+ }
+
+ if ( Status != ERROR_SUCCESS )
+ {
+ TmpBuf += (BYTE)sprintf( TmpBuf,"\tStatus = %ldL\n", Status );
+ TmpBuf += (BYTE)sprintf( TmpBuf,
+"\n\tTpctl: Unable to access\n\tValue : %s\n\tSubkey : %s\n\tClassName: %s\n\tDatabase : %s\n",
+ ValueName, SubKeyName, ClassName, DbaseName );
+ break;
+
+ }
+
+ TmpBuf += (BYTE)sprintf( TmpBuf, "\tStatus = SUCCESS\n" );
+ TmpBuf = TpctlEnumerateRegistryInfo( TmpBuf, DbaseName, SubKeyName, ValueName,
+ ReadValueType, ReadValue, ReadValueSize );
+ break;
+
+
+ default:
+ break;
+
+ }
+
+ //
+ // Close any open keys and deallocate any allocated resources
+ //
+
+ RegCloseKey( KeyHandle );
+ free( ReadValue );
+
+
+ //
+ // Print the buffer
+ //
+
+ if ( Verbose )
+ {
+ if ( !WriteFile(GetStdHandle( STD_OUTPUT_HANDLE ),
+ GlobalBuf,
+ TmpBuf-GlobalBuf,
+ &BytesWritten,
+ NULL ))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: WriteFile to screen failed, returned 0x%lx\n",(PVOID)Status);
+ }
+ }
+
+ if ( CommandsFromScript )
+ {
+ if ( !WriteFile(Scripts[ScriptIndex].LogHandle,
+ GlobalBuf,
+ TmpBuf-GlobalBuf,
+ &BytesWritten,
+ NULL ))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: WriteFile to logfile failed, returned 0x%lx\n",(PVOID)Status);
+ }
+
+ }
+ else if ( CommandLineLogging )
+ {
+ if ( !WriteFile(CommandLineLogHandle,
+ GlobalBuf,
+ TmpBuf-GlobalBuf,
+ &BytesWritten,
+ NULL ))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: WriteFile to logfile failed, returned 0x%lx\n",(PVOID)Status);
+ }
+ }
+
+ //
+ // Free up resources
+ //
+ free( ReadValue );
+
+}
+
+
+
+BOOL
+TpctlInitCommandBuffer(
+ OUT PCMD_ARGS CmdArgs,
+ IN DWORD CmdCode
+ )
+
+// -------------------
+//
+// Routine Description:
+//
+// Initialize the cmd buffer to be passed to the driver with the arguments
+// read from the command line or the script file.
+//
+// Arguments:
+//
+// CmdArgs - The buffer to store the arguments in.
+//
+// CmdCode - The command that is being issued, and therefore the command
+// to write the arguments for into the buffer.
+// Return Value:
+//
+// BOOL - TRUE if the OpenInstance is valid and all the arguments are
+// written to the buffer, FALSE otherwise.
+//
+// ----------------
+
+{
+ LPBYTE p, q, s, t;
+ DWORD i, j;
+ DWORD OidIndex;
+
+ //
+ // If the OpenInstance is invalid return immediately.
+ //
+ switch ( CmdCode )
+ {
+ case SETENV :
+ case GO :
+ case PAUSE :
+ case OPEN :
+ case CLOSE :
+ case QUERYINFO :
+ case SETPF :
+ case SETLA :
+ case ADDMA :
+ case DELMA :
+ case SETFA :
+ case SETGA :
+ case SETINFO :
+ case RESET :
+ case STOPSEND :
+ case WAITSEND :
+ case RECEIVE :
+ case STOPREC :
+ case GETEVENTS :
+ case STRESSSERVER:
+ case ENDSTRESS :
+ case WAITSTRESS :
+ case CHECKSTRESS :
+ case SEND :
+ case STRESS :
+ case PERFSERVER:
+ case PERFCLIENT:
+ if (( GlobalCmdArgs.OpenInstance < 1 ) ||
+ ( GlobalCmdArgs.OpenInstance > NUM_OPEN_INSTANCES ))
+ {
+ TpctlErrorLog("\n\tTpctl: %d not a valid Open Instance Value ",
+ (PVOID)GlobalCmdArgs.OpenInstance);
+ TpctlErrorLog("(1-%d).\n", (PVOID)NUM_OPEN_INSTANCES);
+ return FALSE;
+ }
+
+ default:
+ break;
+
+ }
+
+
+ //
+ // Otherwise let's stuff the arguments into the buffer.
+ //
+
+ CmdArgs->CmdCode = CmdCode;
+ CmdArgs->OpenInstance = GlobalCmdArgs.OpenInstance;
+
+ //
+ // Now do the command dependant stuff.
+ //
+
+ switch( CmdCode )
+ {
+ case SETENV:
+
+ CmdArgs->ARGS.ENV.WindowSize =
+ GlobalCmdArgs.ARGS.ENV.WindowSize;
+
+ CmdArgs->ARGS.ENV.RandomBufferNumber =
+ GlobalCmdArgs.ARGS.ENV.RandomBufferNumber;
+
+ CmdArgs->ARGS.ENV.StressDelayInterval =
+ GlobalCmdArgs.ARGS.ENV.StressDelayInterval;
+
+ CmdArgs->ARGS.ENV.UpForAirDelay =
+ GlobalCmdArgs.ARGS.ENV.UpForAirDelay;
+
+ CmdArgs->ARGS.ENV.StandardDelay =
+ GlobalCmdArgs.ARGS.ENV.StandardDelay;
+
+ p = CmdArgs->ARGS.ENV.StressAddress;
+ q = GlobalCmdArgs.ARGS.ENV.StressAddress;
+
+ s = CmdArgs->ARGS.ENV.ResendAddress;
+ t = GlobalCmdArgs.ARGS.ENV.ResendAddress;
+
+ for( i=0;i<ADDRESS_LENGTH;i++ )
+ {
+ *p++ = *q++;
+ *s++ = *t++;
+ }
+ break;
+
+ case BEGINLOGGING:
+ strcpy( CmdArgs->ARGS.FILES.LogFile,GlobalCmdArgs.ARGS.FILES.LogFile );
+ break;
+
+ case RECORDINGENABLE:
+ strcpy( CmdArgs->ARGS.RECORD.ScriptFile,GlobalCmdArgs.ARGS.RECORD.ScriptFile );
+ break;
+
+ case GO:
+ case PAUSE:
+ p = CmdArgs->ARGS.PAUSE_GO.RemoteAddress;
+ q = GlobalCmdArgs.ARGS.PAUSE_GO.RemoteAddress;
+
+ for( i=0;i<ADDRESS_LENGTH;i++ )
+ {
+ *p++ = *q++;
+ }
+
+ CmdArgs->ARGS.PAUSE_GO.TestSignature =
+ GlobalCmdArgs.ARGS.PAUSE_GO.TestSignature;
+
+ srand(TpctlSeed);
+ CmdArgs->ARGS.PAUSE_GO.UniqueSignature = TpctlSeed = rand();
+ break;
+
+ case OPEN:
+ strcpy( CmdArgs->ARGS.OPEN_ADAPTER.AdapterName,
+ GlobalCmdArgs.ARGS.OPEN_ADAPTER.AdapterName );
+ CmdArgs->ARGS.OPEN_ADAPTER.NoArcNet = 0;
+ if (getenv( "NOARCNET" ))
+ {
+ CmdArgs->ARGS.OPEN_ADAPTER.NoArcNet = 1;
+ }
+ break;
+
+ case QUERYINFO:
+ OidIndex = TpLookUpOidInfo( GlobalCmdArgs.ARGS.TPQUERY.OID );
+
+ if (( OidIndex == -1 ) || ( OidArray[OidIndex].QueryInfo != TRUE ))
+ {
+ TpctlErrorLog("\n\tTpctl: 0x%08lX not a valid NdisRequestQueryInformation OID.\n",
+ (PVOID)GlobalCmdArgs.ARGS.TPQUERY.OID);
+ return FALSE;
+ }
+ CmdArgs->ARGS.TPQUERY.OID = GlobalCmdArgs.ARGS.TPQUERY.OID;
+ break;
+
+ case SETPF:
+ case SETLA:
+ case ADDMA:
+ case SETFA:
+ case SETGA:
+ case SETINFO:
+ CmdArgs->ARGS.TPSET.OID = 0x0;
+
+ //
+ // Sanjeevk: Performed a scrub on the multiple if. Bug #5203
+ //
+
+ switch ( CmdCode )
+ {
+ case SETINFO:
+ CmdArgs->ARGS.TPSET.OID = GlobalCmdArgs.ARGS.TPSET.OID;
+ break;
+
+ case SETPF:
+ CmdArgs->ARGS.TPSET.OID = OID_GEN_CURRENT_PACKET_FILTER;
+ break;
+
+ case SETLA:
+ CmdArgs->ARGS.TPSET.OID = OID_GEN_CURRENT_LOOKAHEAD;
+ break;
+ case ADDMA:
+ if ( Open[CmdArgs->OpenInstance-1].MediumType == NdisMedium802_3 )
+ {
+ CmdArgs->ARGS.TPSET.OID = OID_802_3_MULTICAST_LIST;
+ }
+ else
+ {
+ //
+ // Only FDDI and 802.3 permit multicast addressing. Since the
+ // medium is not 802.3, it must be FDDI
+ //
+ CmdArgs->ARGS.TPSET.OID = OID_FDDI_LONG_MULTICAST_LIST;
+ }
+ break;
+
+ case SETFA:
+ CmdArgs->ARGS.TPSET.OID = OID_802_5_CURRENT_FUNCTIONAL;
+ break;
+
+ case SETGA:
+ CmdArgs->ARGS.TPSET.OID = OID_802_5_CURRENT_GROUP;
+ break;
+
+ default:
+ break;
+ }
+
+ switch ( CmdArgs->ARGS.TPSET.OID )
+ {
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ CmdArgs->ARGS.TPSET.U.PacketFilter =
+ GlobalCmdArgs.ARGS.TPSET.U.PacketFilter;
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ CmdArgs->ARGS.TPSET.U.LookaheadSize =
+ GlobalCmdArgs.ARGS.TPSET.U.LookaheadSize;
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+ case OID_FDDI_LONG_MULTICAST_LIST:
+ {
+ PMULT_ADDR NextMultAddr;
+ DWORD OI = GlobalCmdArgs.OpenInstance - 1;
+
+ p = CmdArgs->ARGS.TPSET.U.MulticastAddress[0];
+ q = GlobalCmdArgs.ARGS.TPSET.U.MulticastAddress[0];
+
+ for ( i=0;i<ADDRESS_LENGTH;i++ )
+ {
+ *p++ = *q++;
+ }
+
+ NextMultAddr = Open[OI].MulticastAddresses;
+
+ //
+ // XXX: Should the stress tests be required to add and
+ // delete the stress multicast address to/from this list?
+ //
+
+ j = 1;
+
+ while ( NextMultAddr != NULL )
+ {
+ p = CmdArgs->ARGS.TPSET.U.MulticastAddress[j++];
+
+ for ( i=0;i<ADDRESS_LENGTH;i++ )
+ {
+ *p++ = NextMultAddr->MulticastAddress[i];
+ }
+
+ NextMultAddr = NextMultAddr->Next;
+ }
+ CmdArgs->ARGS.TPSET.NumberMultAddrs = Open[OI].NumberMultAddrs + 1;
+ break;
+ }
+
+ case OID_802_5_CURRENT_FUNCTIONAL:
+ case OID_802_5_CURRENT_GROUP:
+ p = CmdArgs->ARGS.TPSET.U.FunctionalAddress;
+ q = GlobalCmdArgs.ARGS.TPSET.U.FunctionalAddress;
+
+ for ( i=0;i<FUNCTIONAL_ADDRESS_LENGTH;i++ )
+ {
+ *p++ = *q++;
+ }
+ break;
+
+ default:
+ TpctlErrorLog("\n\tTpctl: 0x%08lX not a valid NdisRequestSetInformation OID.\n",
+ (PVOID)GlobalCmdArgs.ARGS.TPSET.OID);
+ return FALSE;
+ }
+ break;
+
+ case DELMA:
+ {
+ PMULT_ADDR NextMultAddr;
+ DWORD OI = CmdArgs->OpenInstance - 1;
+ BOOL AddressFound = FALSE;
+
+ j = 0;
+
+ //
+ // Copy the addresses that do not match the one to be deleted into
+ // the multicast list buffer to be reset.
+ //
+
+ //
+ // Sanjeevk: Another change point. Bug #5203
+ //
+ if ( Open[CmdArgs->OpenInstance-1].MediumType == NdisMedium802_3 )
+ {
+ CmdArgs->ARGS.TPSET.OID = OID_802_3_MULTICAST_LIST;
+ }
+ else
+ {
+ //
+ // Only FDDI and 802.3 permit multicast addressing. Since the
+ // medium is not 802.3, it must be FDDI
+ //
+ CmdArgs->ARGS.TPSET.OID = OID_FDDI_LONG_MULTICAST_LIST;
+ }
+
+ CmdArgs->ARGS.TPSET.NumberMultAddrs = 0;
+ NextMultAddr = Open[OI].MulticastAddresses;
+
+ while ( NextMultAddr != NULL )
+ {
+ if ( memcmp(GlobalCmdArgs.ARGS.TPSET.U.MulticastAddress[0],
+ NextMultAddr->MulticastAddress,
+ ADDRESS_LENGTH) != 0 )
+ {
+ p = CmdArgs->ARGS.TPSET.U.MulticastAddress[j++];
+
+ for ( i=0;i<ADDRESS_LENGTH;i++ )
+ {
+ *p++ = NextMultAddr->MulticastAddress[i];
+ }
+
+ CmdArgs->ARGS.TPSET.NumberMultAddrs++;
+
+ }
+ else
+ {
+ AddressFound = TRUE;
+ }
+
+ NextMultAddr = NextMultAddr->Next;
+ }
+
+ if ( AddressFound == FALSE )
+ {
+ TpctlErrorLog("\n\tTpctl: The multicast address %02X",
+ (PVOID)GlobalCmdArgs.ARGS.TPSET.U.MulticastAddress[0][0]);
+ TpctlErrorLog("-%02X",
+ (PVOID)GlobalCmdArgs.ARGS.TPSET.U.MulticastAddress[0][1]);
+ TpctlErrorLog("-%02X",
+ (PVOID)GlobalCmdArgs.ARGS.TPSET.U.MulticastAddress[0][2]);
+ TpctlErrorLog("-%02X",
+ (PVOID)GlobalCmdArgs.ARGS.TPSET.U.MulticastAddress[0][3]);
+ TpctlErrorLog("-%02X",
+ (PVOID)GlobalCmdArgs.ARGS.TPSET.U.MulticastAddress[0][4]);
+ TpctlErrorLog("-%02X has not been added.\n",
+ (PVOID)GlobalCmdArgs.ARGS.TPSET.U.MulticastAddress[0][5]);
+
+ //
+ // We will let the call go thru since we expect the driver to agree
+ // with our findings which is the MA which is being deleted is not present
+ //
+ //
+ }
+ break;
+ }
+
+ case SEND:
+ p = CmdArgs->ARGS.TPSEND.DestAddress;
+ q = GlobalCmdArgs.ARGS.TPSEND.DestAddress;
+ s = CmdArgs->ARGS.TPSEND.ResendAddress;
+ t = GlobalCmdArgs.ARGS.TPSEND.ResendAddress;
+
+ for ( i=0;i<ADDRESS_LENGTH;i++ )
+ {
+ *p++ = *q++;
+ *s++ = *t++;
+ }
+
+ CmdArgs->ARGS.TPSEND.PacketSize =
+ GlobalCmdArgs.ARGS.TPSEND.PacketSize;
+
+ CmdArgs->ARGS.TPSEND.NumberOfPackets =
+ GlobalCmdArgs.ARGS.TPSEND.NumberOfPackets;
+
+ break;
+
+ case STRESS:
+
+ CmdArgs->ARGS.TPSTRESS.MemberType =
+ GlobalCmdArgs.ARGS.TPSTRESS.MemberType;
+
+ CmdArgs->ARGS.TPSTRESS.PacketType =
+ GlobalCmdArgs.ARGS.TPSTRESS.PacketType;
+
+ CmdArgs->ARGS.TPSTRESS.PacketSize =
+ GlobalCmdArgs.ARGS.TPSTRESS.PacketSize;
+
+ CmdArgs->ARGS.TPSTRESS.PacketMakeUp =
+ GlobalCmdArgs.ARGS.TPSTRESS.PacketMakeUp;
+
+ CmdArgs->ARGS.TPSTRESS.ResponseType =
+ GlobalCmdArgs.ARGS.TPSTRESS.ResponseType;
+
+ CmdArgs->ARGS.TPSTRESS.DelayType =
+ GlobalCmdArgs.ARGS.TPSTRESS.DelayType;
+
+ CmdArgs->ARGS.TPSTRESS.DelayLength =
+ GlobalCmdArgs.ARGS.TPSTRESS.DelayLength;
+
+ CmdArgs->ARGS.TPSTRESS.TotalIterations =
+ GlobalCmdArgs.ARGS.TPSTRESS.TotalIterations;
+
+ CmdArgs->ARGS.TPSTRESS.TotalPackets =
+ GlobalCmdArgs.ARGS.TPSTRESS.TotalPackets;
+
+ CmdArgs->ARGS.TPSTRESS.WindowEnabled =
+ GlobalCmdArgs.ARGS.TPSTRESS.WindowEnabled;
+
+ CmdArgs->ARGS.TPSTRESS.DataChecking =
+ GlobalCmdArgs.ARGS.TPSTRESS.DataChecking;
+
+ CmdArgs->ARGS.TPSTRESS.PacketsFromPool =
+ GlobalCmdArgs.ARGS.TPSTRESS.PacketsFromPool;
+
+ break;
+
+
+ case REGISTRY :
+ CmdArgs->ARGS.REGISTRY_ENTRY.OperationType =
+ GlobalCmdArgs.ARGS.REGISTRY_ENTRY.OperationType ;
+ CmdArgs->ARGS.REGISTRY_ENTRY.KeyDatabase =
+ GlobalCmdArgs.ARGS.REGISTRY_ENTRY.KeyDatabase ;
+ CmdArgs->ARGS.REGISTRY_ENTRY.ValueType =
+ GlobalCmdArgs.ARGS.REGISTRY_ENTRY.ValueType ;
+
+ strcpy( CmdArgs->ARGS.REGISTRY_ENTRY.SubKey ,
+ GlobalCmdArgs.ARGS.REGISTRY_ENTRY.SubKey );
+ strcpy( CmdArgs->ARGS.REGISTRY_ENTRY.SubKeyClass ,
+ GlobalCmdArgs.ARGS.REGISTRY_ENTRY.SubKeyClass );
+
+ strcpy( CmdArgs->ARGS.REGISTRY_ENTRY.SubKeyValueName,
+ GlobalCmdArgs.ARGS.REGISTRY_ENTRY.SubKeyValueName );
+ strcpy( CmdArgs->ARGS.REGISTRY_ENTRY.SubKeyValue,
+ GlobalCmdArgs.ARGS.REGISTRY_ENTRY.SubKeyValue );
+
+ break;
+
+
+ case PERFCLIENT:
+ p = CmdArgs->ARGS.TPPERF.PerfServerAddr;
+ q = GlobalCmdArgs.ARGS.TPPERF.PerfServerAddr;
+ s = CmdArgs->ARGS.TPPERF.PerfSendAddr;
+ t = GlobalCmdArgs.ARGS.TPPERF.PerfSendAddr;
+
+ for ( i=0;i<ADDRESS_LENGTH;i++ )
+ {
+ *p++ = *q++;
+ *s++ = *t++;
+ }
+ CmdArgs->ARGS.TPPERF.PerfPacketSize = GlobalCmdArgs.ARGS.TPPERF.PerfPacketSize;
+ CmdArgs->ARGS.TPPERF.PerfNumPackets = GlobalCmdArgs.ARGS.TPPERF.PerfNumPackets;
+ CmdArgs->ARGS.TPPERF.PerfDelay = GlobalCmdArgs.ARGS.TPPERF.PerfDelay;
+ CmdArgs->ARGS.TPPERF.PerfMode = GlobalCmdArgs.ARGS.TPPERF.PerfMode;
+ break;
+
+ case CLOSE:
+ case RESET:
+ case STOPSEND:
+ case WAITSEND:
+ case RECEIVE:
+ case STOPREC:
+ case GETEVENTS:
+ case STRESSSERVER:
+ case ENDSTRESS:
+ case WAITSTRESS:
+ case CHECKSTRESS:
+ case WAIT:
+ case VERBOSE:
+ case BREAKPOINT:
+ case QUIT:
+ case HELP:
+ case SHELL:
+ case RECORDINGDISABLE:
+ case DISABLE:
+ case ENABLE:
+ case PERFSERVER:
+ break;
+
+ default:
+ TpctlErrorLog("TpctlInitCommandBuffer: Invalid Command code.\n",NULL);
+ break;
+
+ } // switch();
+
+ return TRUE;
+}
+
+
+
+LPSTR
+TpctlGetEventType(
+ TP_EVENT_TYPE TpEventType
+ )
+{
+ static TP_EVENT_TYPE Event[] = {
+ CompleteOpen,
+ CompleteClose,
+ CompleteSend,
+ CompleteTransferData,
+ CompleteReset,
+ CompleteRequest,
+ IndicateReceive,
+ IndicateReceiveComplete,
+ IndicateStatus,
+ IndicateStatusComplete,
+ Unknown
+ };
+
+#define EventCount (sizeof(Event)/sizeof(TP_EVENT_TYPE))
+
+ static LPSTR EventString[] = { // BUGUBUG Add new events open close...
+ "NdisCompleteOpen",
+ "NdisCompleteClose",
+ "NdisCompleteSend",
+ "NdisCompleteTransferData",
+ "NdisCompleteReset",
+ "NdisCompleteRequest",
+ "NdisIndicateReceive",
+ "NdisIndicateReceiveComplete",
+ "NdisIndicateStatus",
+ "NdisIndicateStatusComplete",
+ "Unknown Function"
+ };
+
+ static BYTE BadEvent[] = "UNDEFINED";
+ DWORD i;
+
+
+ for (i=0; i<EventCount; i++)
+ {
+ if (TpEventType == Event[i])
+ {
+ return EventString[i];
+ }
+ }
+
+ return BadEvent;
+
+#undef StatusCount
+}
+
+
+
+LPSTR
+TpctlGetStatus(
+ NDIS_STATUS GeneralStatus
+ )
+{
+
+ static NDIS_STATUS Status[] = {
+ NDIS_STATUS_SUCCESS,
+ NDIS_STATUS_PENDING,
+ NDIS_STATUS_NOT_RECOGNIZED,
+ NDIS_STATUS_NOT_COPIED,
+ NDIS_STATUS_ONLINE,
+ NDIS_STATUS_RESET_START,
+ NDIS_STATUS_RESET_END,
+ NDIS_STATUS_RING_STATUS,
+ NDIS_STATUS_CLOSED,
+
+ NDIS_STATUS_WAN_LINE_UP,
+ NDIS_STATUS_WAN_LINE_DOWN,
+ NDIS_STATUS_WAN_FRAGMENT,
+
+ NDIS_STATUS_NOT_RESETTABLE,
+ NDIS_STATUS_SOFT_ERRORS,
+ NDIS_STATUS_HARD_ERRORS,
+ NDIS_STATUS_FAILURE,
+ NDIS_STATUS_RESOURCES,
+ NDIS_STATUS_CLOSING,
+ NDIS_STATUS_BAD_VERSION,
+ NDIS_STATUS_BAD_CHARACTERISTICS,
+ NDIS_STATUS_ADAPTER_NOT_FOUND,
+ NDIS_STATUS_OPEN_FAILED,
+ NDIS_STATUS_DEVICE_FAILED,
+ NDIS_STATUS_MULTICAST_FULL,
+ NDIS_STATUS_MULTICAST_EXISTS,
+ NDIS_STATUS_MULTICAST_NOT_FOUND,
+ NDIS_STATUS_REQUEST_ABORTED,
+ NDIS_STATUS_RESET_IN_PROGRESS,
+ NDIS_STATUS_CLOSING_INDICATING,
+ NDIS_STATUS_NOT_SUPPORTED,
+ NDIS_STATUS_INVALID_PACKET,
+ NDIS_STATUS_OPEN_LIST_FULL,
+ NDIS_STATUS_ADAPTER_NOT_READY,
+ NDIS_STATUS_ADAPTER_NOT_OPEN,
+ NDIS_STATUS_NOT_INDICATING,
+ NDIS_STATUS_INVALID_LENGTH,
+ NDIS_STATUS_INVALID_DATA,
+ NDIS_STATUS_BUFFER_TOO_SHORT,
+ NDIS_STATUS_INVALID_OID,
+ NDIS_STATUS_ADAPTER_REMOVED,
+ NDIS_STATUS_UNSUPPORTED_MEDIA,
+ NDIS_STATUS_GROUP_ADDRESS_IN_USE,
+ NDIS_STATUS_FILE_NOT_FOUND,
+ NDIS_STATUS_ERROR_READING_FILE,
+ NDIS_STATUS_ALREADY_MAPPED,
+ NDIS_STATUS_RESOURCE_CONFLICT,
+ NDIS_STATUS_TOKEN_RING_OPEN_ERROR,
+ TP_STATUS_NO_SERVERS,
+ TP_STATUS_NO_EVENTS
+ };
+
+#define StatusCount (sizeof(Status)/sizeof(NDIS_STATUS))
+
+ static PUCHAR String[] = {
+ "NDIS_STATUS_SUCCESS",
+ "NDIS_STATUS_PENDING",
+ "NDIS_STATUS_NOT_RECOGNIZED",
+ "NDIS_STATUS_NOT_COPIED",
+ "NDIS_STATUS_ONLINE",
+ "NDIS_STATUS_RESET_START",
+ "NDIS_STATUS_RESET_END",
+ "NDIS_STATUS_RING_STATUS",
+ "NDIS_STATUS_CLOSED",
+ "NDIS_STATUS_WAN_LINE_UP",
+ "NDIS_STATUS_WAN_LINE_DOWN",
+ "NDIS_STATUS_WAN_FRAGMENT",
+ "NDIS_STATUS_NOT_RESETTABLE",
+ "NDIS_STATUS_SOFT_ERRORS",
+ "NDIS_STATUS_HARD_ERRORS",
+ "NDIS_STATUS_FAILURE",
+ "NDIS_STATUS_RESOURCES",
+ "NDIS_STATUS_CLOSING",
+ "NDIS_STATUS_BAD_VERSION",
+ "NDIS_STATUS_BAD_CHARACTERISTICS",
+ "NDIS_STATUS_ADAPTER_NOT_FOUND",
+ "NDIS_STATUS_OPEN_FAILED",
+ "NDIS_STATUS_DEVICE_FAILED",
+ "NDIS_STATUS_MULTICAST_FULL",
+ "NDIS_STATUS_MULTICAST_EXISTS",
+ "NDIS_STATUS_MULTICAST_NOT_FOUND",
+ "NDIS_STATUS_REQUEST_ABORTED",
+ "NDIS_STATUS_RESET_IN_PROGRESS",
+ "NDIS_STATUS_CLOSING_INDICATING",
+ "NDIS_STATUS_NOT_SUPPORTED",
+ "NDIS_STATUS_INVALID_PACKET",
+ "NDIS_STATUS_OPEN_LIST_FULL",
+ "NDIS_STATUS_ADAPTER_NOT_READY",
+ "NDIS_STATUS_ADAPTER_NOT_OPEN",
+ "NDIS_STATUS_NOT_INDICATING",
+ "NDIS_STATUS_INVALID_LENGTH",
+ "NDIS_STATUS_INVALID_DATA",
+ "NDIS_STATUS_BUFFER_TOO_SHORT",
+ "NDIS_STATUS_INVALID_OID",
+ "NDIS_STATUS_ADAPTER_REMOVED",
+ "NDIS_STATUS_UNSUPPORTED_MEDIA",
+ "NDIS_STATUS_GROUP_ADDRESS_IN_USE",
+ "NDIS_STATUS_FILE_NOT_FOUND",
+ "NDIS_STATUS_ERROR_READING_FILE",
+ "NDIS_STATUS_ALREADY_MAPPED",
+ "NDIS_STATUS_RESOURCE_CONFLICT",
+ "NDIS_STATUS_TOKEN_RING_OPEN_ERROR",
+ "TP_STATUS_NO_SERVERS",
+ "TP_STATUS_NO_EVENTS"
+ };
+
+ static BYTE BadStatus[] = "UNDEFINED";
+ DWORD i;
+
+ for (i=0; i<StatusCount; i++)
+ {
+ if (GeneralStatus == Status[i])
+ {
+ return String[i];
+ }
+ }
+ return BadStatus;
+
+#undef StatusCount
+}
+
+
+
+DWORD
+TpctlGetCommandCode(
+ LPSTR Argument
+ )
+
+{
+ DWORD i;
+
+ for ( i=1;i<NUM_COMMANDS;i++ )
+ {
+ if (_stricmp( Argument, CommandCode[i].CmdAbbr ) == 0 )
+ {
+ return CommandCode[i].CmdCode;
+ }
+
+ if (_stricmp( Argument, CommandCode[i].CmdName ) == 0 )
+ {
+ return CommandCode[i].CmdCode;
+ }
+ }
+ return CMD_ERR;
+}
+
+
+
+LPSTR
+TpctlGetCommandName(
+ LPSTR Command
+ )
+
+{
+ DWORD i;
+
+ for ( i=1;i<NUM_COMMANDS;i++ )
+ {
+ if (_stricmp(Command,CommandCode[i].CmdAbbr) == 0 )
+ {
+ return CommandCode[i].CmdName;
+ }
+ if (_stricmp(Command,CommandCode[i].CmdName) == 0 )
+ {
+ return CommandCode[i].CmdName;
+ }
+ }
+ return CommandCode[CMD_ERR].CmdName;
+}
+
+
+
+LPSTR
+TpctlGetCmdCode(
+ DWORD CmdCode
+ )
+{
+ static BYTE BadCmdCode[] = "UNDEFINED";
+
+ DWORD i;
+
+ for(i=1; i<NUM_COMMANDS; i++)
+ {
+ if ( CmdCode == CommandCode[i].CmdCode )
+ {
+ return(CommandCode[i].CmdName);
+ }
+ }
+ return BadCmdCode;
+}
+
+
+
+VOID
+TpctlCopyAdapterAddress(
+ DWORD OpenInstance,
+ PREQUEST_RESULTS Results
+ )
+{
+ DWORD i;
+ PUCHAR Source, Destination;
+
+ //
+ // Sanjeevk: Bug# 5203: This routine needed modification to support
+ // the additional NDIS_MEDIUM information sent
+ // back
+ //
+
+ Source = (PUCHAR)( Results->InformationBuffer + sizeof( NDIS_MEDIUM ) );
+ Destination = (PUCHAR)( Open[OpenInstance].AdapterAddress );
+
+ for (i=0;i<ADDRESS_LENGTH;i++)
+ {
+ *Destination++ = *Source++;
+ }
+}
+
+
+
+VOID
+TpctlRecordArguments(
+ IN TESTPARAMS Options[],
+ IN DWORD OptionTableSize,
+ IN DWORD argc,
+ IN LPSTR argv[TPCTL_MAX_ARGC]
+ )
+
+// -----------------
+//
+// Routine Description:
+//
+// Create Sanjeevk 7-1-93
+//
+// This function is responsible for creating the command in parts and records
+// it to the file accessed by ScriptRecordHandle
+//
+// Arguments:
+//
+// Options The TestParameter options from which the command is created
+//
+// OptionTableSize The size of the table for the option under consideration
+//
+// argc The number of arguments passed on the TPCTL command line
+// prompt
+//
+// argv The arguments passed on the TPCTL command line prompt
+//
+//
+// Return Value:
+//
+// None
+//
+// -------------------
+
+
+{
+ DWORD i;
+ CHAR TmpBuffer[256];
+ DWORD BytesWritten,Status ;
+ DWORD CmdCode = TpctlGetCommandCode( argv[0] );
+
+
+ //
+ // 1. Clear the temporary buffer which will be used to construct an option
+ // one at a time
+ //
+ ZeroMemory ( TmpBuffer, 256 );
+
+ //
+ // 2. Attempt to access the complete name of the command code.
+ //
+ if ( CmdCode == CMD_ERR )
+ {
+ sprintf( TmpBuffer, "%s", argv[0] );
+ }
+ else
+ {
+ sprintf( TmpBuffer, "%s", TpctlGetCommandName(argv[0]) );
+ }
+
+ //
+ // 3. Write the first argument accessed into the script file
+ //
+
+ if ( !WriteFile(ScriptRecordHandle,
+ TmpBuffer,
+ strlen( TmpBuffer ),
+ &BytesWritten,
+ NULL ))
+ {
+ Status = GetLastError();
+ printf("\n\tTpctlRecordArguments: write to script record file failed, returned 0x%lx\n",
+ Status);
+ return;
+ }
+
+ //
+ // 4. Set up the buffer for reuse
+ //
+ ZeroMemory ( TmpBuffer, 256 );
+
+ //
+ // 5. Now for the number of argument passed on the TPCTL command prompt, reconstruct
+ // each sub option one at a time
+ //
+ for( i = 1; i < argc; i++ )
+ {
+ //
+ // 5.a Check if a valid Option Table has been provided and if so get the
+ // the lvalue and rvalue and combine them to form an expression
+ //
+
+ if ( Options != NULL )
+ {
+ sprintf( TmpBuffer, "\t+\n %s=%s", Options[i-1].ArgName, argv[i] );
+ }
+ else
+ {
+ if ( CmdCode != CMD_ERR )
+ {
+ sprintf( TmpBuffer, "\t+\n %s", argv[i] );
+ }
+ else
+ {
+ sprintf( TmpBuffer, " %s", argv[i] );
+ }
+ }
+
+ //
+ // 5.b Write this reconstructed string which now signifies the complete
+ // sub-option into the script file
+ //
+
+ if ( !WriteFile(ScriptRecordHandle,
+ TmpBuffer,
+ strlen( TmpBuffer ),
+ &BytesWritten,
+ NULL ))
+ {
+ Status = GetLastError();
+ printf("\n\tTpctlRecordArguments: write to script record file failed, returned 0x%lx\n",
+ Status);
+ return;
+ }
+
+ //
+ // 5.c And clear the buffer for reuse(next sub-option)
+ //
+ ZeroMemory ( TmpBuffer, 256 );
+
+ }
+
+ //
+ // 6. Since it is possible to specifiy one or more suboptions and the command prompt
+ // we must dteremine all of the lvalues and rvalues of the current option
+ // Since we can also specify a semicolon to accept default values, we must
+ // carefully consider the various types of data associated with the rvalues
+ //
+ for( i = argc; i <= OptionTableSize; i++ )
+ {
+ PUCHAR p;
+
+ switch ( Options[i-1].TestType )
+ {
+ case Integer :
+ sprintf( TmpBuffer, "\t+\n %s=%ld", Options[i-1].ArgName,
+ *(PDWORD)Options[i-1].Destination );
+ break;
+
+ case String :
+ sprintf(TmpBuffer, "\t+\n %s=%s", Options[i-1].ArgName, Options[i-1].Destination);
+ break;
+
+ case Address4 :
+ p = Options[i-1].Destination;
+ sprintf( TmpBuffer, "\t+\n %s=%02x-%02x-%02x-%02x", Options[i-1].ArgName,
+ *p, *(p+1), *(p+2), *(p+3) );
+ break;
+
+ case Address6 :
+ p = Options[i-1].Destination;
+ sprintf( TmpBuffer, "\t+\n %s=%02x-%02x-%02x-%02x-%02x-%02x", Options[i-1].ArgName,
+ *p, *(p+1), *(p+2), *(p+3), *(p+4), *(p+5) );
+ break;
+
+ case ParsedInteger :
+ p = Options[i-1].Destination;
+ sprintf( TmpBuffer, "\t+\n %s=0x%4.4x", Options[i-1].ArgName, *(LPDWORD)p );
+ break;
+ }
+
+ if ( !WriteFile(ScriptRecordHandle,
+ TmpBuffer,
+ strlen( TmpBuffer ),
+ &BytesWritten,
+ NULL ))
+ {
+ Status = GetLastError();
+ printf("\n\tTpctlRecordArguments: write to script record file failed, returned 0x%lx\n", Status);
+ return;
+ }
+
+ ZeroMemory ( TmpBuffer, 256 );
+
+ }
+
+ //
+ // 7. Finally add the newline to end the command
+ //
+ sprintf( TmpBuffer, "\n\n" );
+ if ( !WriteFile(ScriptRecordHandle,
+ TmpBuffer,
+ strlen( TmpBuffer ),
+ &BytesWritten,
+ NULL ))
+ {
+ Status = GetLastError();
+ printf("\n\tTpctlRecordArguments: write to script record file failed, returned 0x%lx\n",
+ Status);
+ }
+
+}
+
+
+LPSTR
+TpctlEnumerateRegistryInfo(
+ IN PUCHAR TmpBuf,
+ IN PUCHAR DbaseName,
+ IN PUCHAR SubKeyName,
+ IN PUCHAR ValueName,
+ IN DWORD ReadValueType,
+ IN PUCHAR ReadValue,
+ IN DWORD ReadValueSize )
+{
+
+ INT i;
+
+ TmpBuf += sprintf( TmpBuf,
+ "\tDataBase Name = %s\n\tSub Key Name = %s\n\tValue Name = %s\n",
+ DbaseName, SubKeyName, ValueName );
+
+ TmpBuf += sprintf( TmpBuf, "\tValue Type = %s\n", TpctlGetValueType( ReadValueType ) );
+
+ switch( ReadValueType )
+ {
+ case REG_BINARY :
+ TmpBuf += sprintf( TmpBuf, "\tValue(IN HEX) = ");
+ for( i = 0; i < (INT)ReadValueSize; i++ )
+ {
+ if ( i%6 || (i == 0) )
+ {
+ TmpBuf += sprintf( TmpBuf, "%2.2x ", ReadValue[i] );
+ }
+ else
+ {
+ TmpBuf += sprintf( TmpBuf, "\n\t %2.2x ", ReadValue[i] );
+ }
+ }
+ TmpBuf += sprintf( TmpBuf, "\n" );
+ break;
+
+ case REG_DWORD :
+ TmpBuf += sprintf( TmpBuf, "\tValue = 0x%lx\n", *(LPDWORD)ReadValue );
+ break;
+
+ //
+ // This code section had to be commented out because the idiot who defined
+ // the types made LITTLE_ENDIAN = DWORD. If we were to port over to a
+ // BIG_ENDIAN system, we would have to comment out the code for BIG_ENDIAN
+ //
+ // case REG_DWORD_LITTLE_ENDIAN :
+ // TmpBuf += sprintf( TmpBuf, "\tValue = LITTLE_ENDIAN 0x" );
+ // for( i = 0 ; i < ReadValueSize ; i++ )
+ // {
+ // TmpBuf += sprintf( TmpBuf, "%2.2x", ReadValue[i] );
+ // }
+ // TmpBuf += sprintf( TmpBuf, " DWORD VALUE 0x%lx\n", *(LPDWORD)ReadValue );
+ // break;
+
+ case REG_DWORD_BIG_ENDIAN:
+ TmpBuf += sprintf( TmpBuf, "\tValue = BIG_ENDIAN 0x" );
+ for( i = 0 ; i < (INT)ReadValueSize ; i++ )
+ {
+ TmpBuf += sprintf( TmpBuf, "%2.2x", ReadValue[i] );
+ }
+ TmpBuf += sprintf( TmpBuf, " DWORD VALUE 0x" );
+ for( i = 0 ; i < (INT)ReadValueSize ; i++ )
+ {
+ TmpBuf += sprintf( TmpBuf, "%2.2x", ReadValue[i] );
+ }
+ TmpBuf += sprintf( TmpBuf, "\n" );
+ break;
+
+ case REG_LINK:
+ case REG_EXPAND_SZ:
+ TmpBuf += sprintf( TmpBuf, "\tValue = %s\n", ReadValue );
+ break;
+
+ case REG_MULTI_SZ:
+ TmpBuf += sprintf( TmpBuf, "\tValue(s)\n" );
+ {
+ PUCHAR Tmp1 = ReadValue;
+
+ while ( strlen( Tmp1 ) != 0 )
+ {
+ TmpBuf += sprintf( TmpBuf, "\t\t%s\n", Tmp1 );
+ Tmp1 += (strlen( Tmp1 ) + 1);
+ }
+ }
+ break;
+
+ case REG_NONE:
+ TmpBuf += sprintf( TmpBuf, "\tValue = %s\n", ReadValue );
+ break;
+
+ case REG_RESOURCE_LIST:
+ TmpBuf += sprintf( TmpBuf, "\tValue = %s\n", ReadValue );
+ break;
+
+ case REG_SZ:
+ TmpBuf += sprintf( TmpBuf, "\tValue = %s\n", ReadValue );
+ break;
+
+ default:
+ TmpBuf += sprintf( TmpBuf, "\tValue = UNKNOWN\n" );
+ break;
+
+ }
+
+ return TmpBuf;
+
+}
+
+
+LPSTR
+TpctlGetValueType(
+ IN DWORD ValueType
+ )
+{
+ static UCHAR ValueTypeString[20];
+
+ ZeroMemory( ValueTypeString, 20 );
+
+ switch ( ValueType )
+ {
+ case REG_BINARY :
+ strcpy( ValueTypeString, "REG_BINARY" );
+ break;
+
+ case REG_DWORD :
+ strcpy( ValueTypeString, "REG_DWORD" );
+ break;
+ //
+ // This code section had to be commented out because the idiot who defined
+ // the types made LITTLE_ENDIAN = DWORD. If we were to port over to a
+ // BIG_ENDIAN system, we would have to comment out the code for BIG_ENDIAN
+ //
+ // case REG_DWORD_LITTLE_ENDIAN :
+ // strcpy( ValueTypeString, "REG_DWORD_LITTLE_ENDIAN" );
+ // break;
+ //
+
+ case REG_DWORD_BIG_ENDIAN :
+ strcpy( ValueTypeString, "REG_DWORD_BIG_ENDIAN" );
+ break;
+
+ case REG_EXPAND_SZ :
+ strcpy( ValueTypeString, "REG_EXPAND_SZ" );
+ break;
+
+ case REG_LINK :
+ strcpy( ValueTypeString, "REG_LINK" );
+ break;
+
+ case REG_MULTI_SZ :
+ strcpy( ValueTypeString, "REG_MULTI_SZ" );
+ break;
+
+ case REG_NONE :
+ strcpy( ValueTypeString, "REG_NONE" );
+ break;
+
+ case REG_RESOURCE_LIST :
+ strcpy( ValueTypeString, "REG_RESOURCE_LIST" );
+ break;
+
+ case REG_SZ :
+ strcpy( ValueTypeString, "REG_SZ" );
+ break;
+
+ default :
+ strcpy( ValueTypeString, "UNDEFINED" );
+ break;
+ }
+
+ return ValueTypeString;
+
+}
+
+
diff --git a/private/ntos/ndis/testprot/tpctl/cpuperf.c b/private/ntos/ndis/testprot/tpctl/cpuperf.c
new file mode 100644
index 000000000..ebd92cb11
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpctl/cpuperf.c
@@ -0,0 +1,307 @@
+//
+// Include files
+//
+// #include <ntos.h>
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <ntexapi.h>
+
+#include <windows.h>
+
+extern VOID printf(UCHAR *,...);
+// extern LARGE_INTEGER KeQueryPerformanceCounter(PLARGE_INTEGER);
+
+#define MAX_CPUS 64 // supports maximum of 64 cpus...
+
+// #include "tpdefs.h"
+// #include "media.h"
+// #include "tpprocs.h"
+// #include "string.h"
+
+PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION pStartData;
+PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION pEndData;
+ULONG NumCpus;
+ULONG ProcessorBufSize;
+PULONG pKernelPercent;
+DWORD StartTestTime;
+
+// --------------------------------------------------
+//
+// Function: TpPerfInitCpuUsage
+//
+// Arguments: none
+//
+// Returns: none
+//
+// Descript: This function allocates and initializes all the structures
+// necessary for finding the %cpu usage during performance tests
+//
+// --------------------------------------------------
+
+
+VOID
+CpuUsageInit(VOID)
+{
+ if (!NumCpus) // if NumCpus is zero, need to do first pass initializations
+ { // (allocate all buffers, set NumCpus)
+
+ SYSTEM_BASIC_INFORMATION BasicInfo;
+
+ //
+ // First get the number of processors...
+ //
+
+ NtQuerySystemInformation(SystemBasicInformation,
+ &BasicInfo,
+ sizeof(SYSTEM_BASIC_INFORMATION),
+ NULL);
+
+ NumCpus = BasicInfo.NumberOfProcessors;
+ if ( (NumCpus < 1) || (NumCpus > MAX_CPUS) )
+ {
+ printf("CpuUsageInit: Illegal number of cpus\n");
+ goto init_abort;
+ }
+
+ //
+ // get the memory for the processor instance data
+ //
+
+ ProcessorBufSize = NumCpus * sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION);
+
+ if ( (pStartData = GlobalAlloc(GMEM_FIXED, ProcessorBufSize)) == NULL)
+ {
+ printf("CpuUsageInit: unable to allocate pStartData buffer\n");
+ goto init_abort;
+ }
+
+ if ( (pEndData = GlobalAlloc(GMEM_FIXED, ProcessorBufSize)) == NULL)
+ {
+ printf("CpuUsageInit: unable to allocate pEndData buffer\n");
+ goto init_abort;
+ }
+
+ if ( (pKernelPercent = GlobalAlloc(GMEM_FIXED , (NumCpus + 1) * sizeof(ULONG))) == NULL)
+ {
+ printf("CpuUsageInit: unable to allocate pKernelPercent buffer\n");
+init_abort:
+ if (pStartData)
+ {
+ GlobalFree(pStartData);
+// pStartData = NULL;
+ }
+ if (pEndData)
+ {
+ GlobalFree(pEndData);
+// pEndData = NULL
+ }
+ if (pKernelPercent)
+ {
+ GlobalFree(pKernelPercent);
+// pKernelPercent = NULL;
+ }
+ NumCpus = 0;
+ return;
+ }
+ }
+
+ NtQuerySystemInformation(SystemProcessorPerformanceInformation,
+ pStartData,
+ ProcessorBufSize,
+ NULL);
+ StartTestTime = GetTickCount();
+
+}
+
+
+// ------------------------------------------------
+//
+// Function: TpPerfGetCpuUsage
+//
+// Arguments: oldptr -- cpu processor performance data from time 0
+// ProcessorTime -- place to put processor times
+// KernelTime -- place to put kernel times
+//
+// Returns: number of processors--0 if error
+//
+// Descript: This function reads the performance counters
+// at the end of the test, stored them in an appropriate
+// location, and then cleans up the structures and exits
+//
+// -------------------------------------------------
+
+
+ULONG
+CpuUsageGetData(PULONG *ppKernPC,
+ ULONG TestTime)
+{
+ SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *pOldProcessorInformation;
+ SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *pNewProcessorInformation;
+ ULONG CurProc;
+ LARGE_INTEGER TotalProcessorTime;
+ LARGE_INTEGER TotalKernelTime;
+ LARGE_INTEGER TempUser;
+ LARGE_INTEGER TempKern;
+ LARGE_INTEGER TempIdle;
+ LARGE_INTEGER trash;
+ LARGE_INTEGER WholeTestTime;
+ DWORD EndTestTime;
+ ULONG flag;
+
+ if (!NumCpus)
+ {
+ printf("CpuUsageGetData: called before initialization\n");
+ return 0;
+ }
+
+
+ NtQuerySystemInformation(SystemProcessorPerformanceInformation,
+ pEndData,
+ ProcessorBufSize,
+ NULL);
+ //
+ // find the total time in milliseconds
+ //
+ EndTestTime = GetTickCount();
+// if (EndTestTime > StartTestTime)
+// {
+ WholeTestTime.LowPart = EndTestTime - StartTestTime;
+// }
+// else
+// {
+//
+// }
+// WholeTestTime.LowPart = GetTickCount() - StartTestTime;
+ WholeTestTime.HighPart = 0;
+// printf("Kludge factor = %d/%d\n", TestTime, WholeTestTime.LowPart);
+
+ TotalProcessorTime.HighPart = 0;
+ TotalProcessorTime.LowPart = 0;
+ TotalKernelTime.HighPart = 0;
+ TotalKernelTime.LowPart = 0;
+
+ //
+ // Total time = UserTime + KernelTime
+ // KernelTime = IdleTime + Priviledged time
+ // We need total time and priviledged time
+ //
+
+ pOldProcessorInformation = pStartData;
+ pNewProcessorInformation = pEndData;
+
+ for ( CurProc = 0; CurProc < NumCpus; CurProc++ )
+ {
+// DEBUG
+// printf("\nCpuUsageGetData: processor %d\n", CurProc);
+// printf("Initial Idletime = %08x%08x\n", pOldProcessorInformation->IdleTime.HighPart,
+// pOldProcessorInformation->IdleTime.LowPart);
+// printf("Initial Usertime = %08x%08x\n", pOldProcessorInformation->UserTime.HighPart,
+// pOldProcessorInformation->UserTime.LowPart);
+// printf("Initial Kerntime = %08x%08x\n\n", pOldProcessorInformation->KernelTime.HighPart,
+// pOldProcessorInformation->KernelTime.LowPart);
+//
+// printf("Final Idletime = %08x%08x\n", pNewProcessorInformation->IdleTime.HighPart,
+// pNewProcessorInformation->IdleTime.LowPart);
+// printf("Final Usertime = %08x%08x\n", pNewProcessorInformation->UserTime.HighPart,
+// pNewProcessorInformation->UserTime.LowPart);
+// printf("Final Kerntime = %08x%08x\n\n", pNewProcessorInformation->KernelTime.HighPart,
+// pNewProcessorInformation->KernelTime.LowPart);
+// END DEBUG
+
+ // first, find all the deltas...
+
+ TempUser = RtlLargeIntegerSubtract(pNewProcessorInformation->UserTime,
+ pOldProcessorInformation->UserTime);
+ TempKern = RtlLargeIntegerSubtract(pNewProcessorInformation->KernelTime,
+ pOldProcessorInformation->KernelTime);
+ TempIdle = RtlLargeIntegerSubtract(pNewProcessorInformation->IdleTime,
+ pOldProcessorInformation->IdleTime);
+ // check for wrapping
+// if (pOldProcessor->UserTime.HighPart > pNewProcessorInformation->UserTime.HighPart)
+// {
+//
+// }
+
+// printf("Delta IdleTime = %08x%08x\n", TempIdle.HighPart, TempIdle.LowPart);
+// printf("Delta UserTime = %08x%08x\n", TempUser.HighPart, TempUser.LowPart);
+// printf("Delta KernTime = %08x%08x\n", TempKern.HighPart, TempKern.LowPart);
+
+ // now find the total processor time = UserTime + KernelTime
+
+ TempUser = RtlLargeIntegerAdd(TempUser, TempKern);
+
+// printf("Total ProcTime = %08x%08x\n", TempUser.HighPart, TempUser.LowPart);
+
+ // adjust by kludge factor -- TestTime/WholeTestTime
+
+ TempUser = RtlExtendedIntegerMultiply(TempUser, TestTime);
+ TempUser = RtlLargeIntegerDivide(TempUser, WholeTestTime, &trash);
+
+ if ((TempUser.HighPart == 0) && (TempUser.LowPart < 10)) // sanity check
+ {
+ flag = 0;
+ printf("Kludge factor = %d/%d\n", TestTime, WholeTestTime.LowPart);
+ printf("Adjusted ProcTime = %08x%08x\n", TempUser.HighPart, TempUser.LowPart);
+ }
+ else
+ {
+ flag = 1;
+ }
+
+ TotalProcessorTime = RtlLargeIntegerAdd(TotalProcessorTime, TempUser);
+
+ // now find the true kernel time = KernelTime - IdleTime
+
+ TempKern = RtlLargeIntegerSubtract(TempKern, TempIdle);
+
+// printf("True KernTime = %08x%08x\n", TempKern.HighPart, TempKern.LowPart);
+
+ if (TempKern.HighPart < 0)
+ {
+ TempKern.HighPart = 0;
+ TempKern.LowPart = 0;
+ }
+ TotalKernelTime = RtlLargeIntegerAdd(TotalKernelTime, TempKern);
+
+ //
+ // finally, calc the percent kernel is of total
+ //
+
+ if (flag)
+ {
+ TempKern = RtlExtendedIntegerMultiply(TempKern, 1000);
+ TempKern = RtlLargeIntegerDivide(TempKern, TempUser, &trash);
+ }
+ else
+ {
+ TempKern.LowPart = 0;
+ }
+ pKernelPercent[CurProc+1] = TempKern.LowPart;
+
+ // move to info for next processor
+
+ pNewProcessorInformation++;
+ pOldProcessorInformation++;
+ }
+
+ //
+ // last of all, calc the percent kernel is of total
+ //
+ if ((TotalProcessorTime.HighPart == 0) && (TotalProcessorTime.LowPart < 10))
+ {
+ TempKern.LowPart = 0;
+ }
+ else
+ {
+ TempKern = RtlExtendedIntegerMultiply(TotalKernelTime, 1000);
+ TempKern = RtlLargeIntegerDivide(TempKern, TotalProcessorTime, &trash);
+ }
+ pKernelPercent[0] = TempKern.LowPart;
+
+ *ppKernPC = pKernelPercent;
+
+ return NumCpus;
+}
+
diff --git a/private/ntos/ndis/testprot/tpctl/globals.c b/private/ntos/ndis/testprot/tpctl/globals.c
new file mode 100644
index 000000000..49f9c5d6e
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpctl/globals.c
@@ -0,0 +1,390 @@
+// ******************************************************************
+//
+// Copyright (c) 1991 Microsoft Corporation
+//
+// Module Name:
+//
+// globals.c
+//
+// Abstract:
+//
+// This module contains the routines for parsing global variables entered from
+// the command line or read from script files.
+//
+// Author:
+//
+// Tim Wynsma (timothyw) 5-18-94
+//
+// Revision History:
+//
+// ******************************************************************
+
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+
+#include <windows.h>
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "tpctl.h"
+#include "parse.h"
+
+typedef struct _GLOBALS
+{
+ // String variables
+
+ UCHAR TestCard[64];
+ UCHAR TrustedCard[64];
+
+ // Address6 variables
+
+ UCHAR TestCardAddress[6];
+ UCHAR TrustedCardAddress[6];
+ UCHAR MulticastAddress[6];
+ UCHAR MulticastAddress2[6];
+ UCHAR BroadcastAddress[6];
+ UCHAR RandomAddress[6];
+ UCHAR RemoteTestCardAddress[6];
+ UCHAR RemoteTrustedCardAddress[6];
+
+ // Address4 variables
+
+ UCHAR FunctionalAddress[4];
+ UCHAR FunctionalAddress2[4];
+
+ // Integer variables
+
+ ULONG MaxFrameSize;
+ ULONG MaxLookaheadSize;
+
+} GLOBALS;
+
+GLOBALS glob;
+
+typedef struct _GLOBALVAR
+{
+ PUCHAR varname;
+ PARAMTYPES vartype;
+ PVOID varaddress;
+} GLOBALVAR, *PGLOBALVAR;
+
+
+GLOBALVAR globalvars[] =
+ { { "test_card", String, glob.TestCard },
+ { "trusted_card", String, glob.TrustedCard },
+ { "test_card_address", Address6, glob.TestCardAddress },
+ { "trusted_card_address", Address6, glob.TrustedCardAddress },
+ { "multicast_address", Address6, glob.MulticastAddress },
+ { "multicast_address2", Address6, glob.MulticastAddress2 },
+ { "broadcast_address", Address6, glob.BroadcastAddress },
+ { "random_address", Address6, glob.RandomAddress },
+ { "rem_test_card_address", Address6, glob.RemoteTestCardAddress },
+ { "rem_trusted_card_address", Address6, glob.RemoteTrustedCardAddress },
+ { "functional_address", Address4, glob.FunctionalAddress },
+ { "functional_address2", Address4, glob.FunctionalAddress2 },
+ { "max_frame_size", Integer, &glob.MaxFrameSize },
+ { "max_lookahead_size", Integer, &glob.MaxLookaheadSize }
+ };
+
+
+DWORD
+NumGlobalVars = sizeof(globalvars) / sizeof(globalvars[0]);
+
+
+
+DWORD
+ParseGlobalArgs(OUT PUCHAR commandline,
+ OUT LPSTR tokenptr[],
+ IN DWORD ArgC,
+ IN LPSTR ArgV[]);
+
+
+
+PVOID
+TpctlParseGlobalVariable(
+ IN BYTE Buffer[],
+ IN PARAMTYPES reqtype
+ )
+
+// -------------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// ------------
+
+{
+ BYTE TmpBuffer[100];
+ LPSTR EndOfVar = Buffer; // Anything that isn't NULL.
+ ULONG count;
+
+
+ //
+ // make sure that there is actually something passed in..
+ //
+
+ if ( Buffer == NULL)
+ {
+ return NULL;
+ }
+
+ //
+ // copy the variable into a temp buffer.
+ //
+
+ strcpy( TmpBuffer,&Buffer[1] );
+
+ //
+ // Now null out the '$' symbol if it exists to allow the querying
+ // of the global variable.
+ //
+
+ EndOfVar = strchr( TmpBuffer,'$' );
+
+ if ( EndOfVar == NULL )
+ {
+ return NULL;
+ }
+
+ *EndOfVar = '\0';
+
+ //
+ // Search for the named global variable
+ //
+
+ for (count=0; count < NumGlobalVars; count++)
+ {
+ if (!_stricmp(TmpBuffer, globalvars[count].varname))
+ {
+ //
+ // Make sure the required type matched the type of the global
+ //
+ if (globalvars[count].vartype != reqtype)
+ {
+ return NULL;
+ }
+ return globalvars[count].varaddress;
+
+ }
+ }
+
+ return NULL;
+}
+
+VOID
+TpctlInitGlobalVariables(VOID)
+{
+ ULONG count;
+ UCHAR NameBuf[128];
+ PUCHAR varptr;
+ LPBYTE NextToken;
+
+
+ //
+ // first, initialize those globals that will always have a certain value...
+ // (all others should already be zero)
+ //
+
+ glob.MulticastAddress[0] = 0x01;
+ glob.MulticastAddress[1] = 0x02;
+ glob.MulticastAddress[2] = 0x03;
+ glob.MulticastAddress[3] = 0x04;
+ glob.MulticastAddress[4] = 0x05;
+ glob.MulticastAddress[5] = 0x00;
+
+ glob.MulticastAddress2[0] = 0x01;
+ glob.MulticastAddress2[1] = 0x02;
+ glob.MulticastAddress2[2] = 0x03;
+ glob.MulticastAddress2[3] = 0x04;
+ glob.MulticastAddress2[4] = 0x05;
+ glob.MulticastAddress2[5] = 0x01;
+
+ glob.BroadcastAddress[0] = 0xFF;
+ glob.BroadcastAddress[1] = 0xFF;
+ glob.BroadcastAddress[2] = 0xFF;
+ glob.BroadcastAddress[3] = 0xFF;
+ glob.BroadcastAddress[4] = 0xFF;
+ glob.BroadcastAddress[5] = 0xFF;
+
+ glob.RandomAddress[0] = 0x00;
+ glob.RandomAddress[1] = 0x02;
+ glob.RandomAddress[2] = 0x04;
+ glob.RandomAddress[3] = 0x06;
+ glob.RandomAddress[4] = 0x08;
+ glob.RandomAddress[5] = 0x0A;
+
+ glob.FunctionalAddress[0] = 0xC0;
+ glob.FunctionalAddress[1] = 0x02;
+ glob.FunctionalAddress[2] = 0x03;
+ glob.FunctionalAddress[3] = 0x04;
+
+ glob.FunctionalAddress2[0] = 0x00;
+ glob.FunctionalAddress2[1] = 0x00;
+ glob.FunctionalAddress2[2] = 0x00;
+ glob.FunctionalAddress2[3] = 0x00;
+
+
+ //
+ // now, loop thru all the global vars, checking for an associated environment variable
+ // If the env variable is found, then set that global variable accordingly.
+ //
+
+ for (count=0; count < NumGlobalVars; count++)
+ {
+ strcpy(NameBuf, "tp_");
+ strcat(NameBuf, globalvars[count].varname);
+ varptr = getenv( _strupr( NameBuf ));
+ if (varptr != NULL)
+ {
+ switch ( globalvars[count].vartype )
+ {
+ case Integer:
+ *(PDWORD)globalvars[count].varaddress = strtol( varptr,&NextToken,0 );
+ break;
+
+ case String:
+ strcpy( (LPSTR)globalvars[count].varaddress,varptr );
+ break;
+
+ case Address4:
+ TpctlParseAddress( varptr,
+ (PDWORD)globalvars[count].varaddress,
+ 0,
+ FUNCTIONAL_ADDRESS_LENGTH );
+ break;
+
+ case Address6:
+ TpctlParseAddress( varptr,
+ (PDWORD)globalvars[count].varaddress,
+ 0,
+ ADDRESS_LENGTH ) ;
+ break;
+ }
+ }
+ }
+}
+
+
+DWORD
+TpctlParseSet(
+ IN DWORD ArgC,
+ IN LPSTR ArgV[]
+ )
+
+{
+ DWORD count;
+ UCHAR commandline[120];
+ LPSTR tokenptr[20];
+ DWORD numstrings;
+
+ printf("\nIn TpctlParseSet\n");
+
+ if (ArgC < 2)
+ {
+ printf("Error in setglobalvar command: no arguments\n");
+ return 0;
+ }
+
+ numstrings = ParseGlobalArgs(commandline,tokenptr,ArgC, ArgV);
+
+ for (count=0; count < numstrings; count++)
+ {
+ printf("token %d equals \"%s\".\n",count, tokenptr[count]);
+ }
+ printf("\n");
+
+ // now that they are all parsed into separate strings
+ return 0;
+}
+
+
+DWORD
+ParseGlobalArgs(OUT PUCHAR clptr,
+ OUT LPSTR tokenptr[],
+ IN DWORD ArgC,
+ IN LPSTR ArgV[])
+
+{
+
+ DWORD count;
+ DWORD tokencnt = 0;
+ LPSTR srcptr;
+ DWORD state;
+ DWORD chtype;
+ UCHAR ch;
+
+ // parse into legal strings. For our purposes, the following are legal strings:
+ // 1) Global variable. Must start and end with a '$'. Legal characters are 'A-Z', 'a-z',
+ // '0-9', and '_'. Lowercase are converted to uppercase
+ // 2) Environment variable. Same as global, except must start and end with a '%'
+ // 3) Number. Must contain only digits '0' thru '9'
+ // 4) Address. Must start and end with a '&'. Fields are in hex, separated by '-'.
+ // For example, &00-03-a3-f1-07-54&
+ // 5) Comparisons Legal strings are "=", "<", ">", "<>", "<=", ">="
+ // 6) Operators. Legal strings are '+', '-', '*', '/'
+
+
+ for(count=1; count < ArgC; count++)
+ {
+ srcptr = ArgV[count];
+ state = 0;
+
+ while ( (ch = *srcptr++) != 0)
+ {
+ if ((ch >= '0') && (ch <= '9'))
+ {
+ chtype = 1;
+ }
+ else if ((ch == '%') || (ch == '$') || ((ch >= 'A') && (ch <= 'Z')))
+ {
+ chtype = 2;
+ }
+ else if ((ch >= 'a') && (ch <= 'z'))
+ {
+ chtype = 2;
+ ch = toupper(ch);
+ }
+ else if ((ch == '(') || (ch == ')') || (ch == '+') || (ch = '-') ||
+ (ch == '*') || (ch == '/') || (ch == '='))
+ {
+ chtype = 3;
+ }
+ else
+ {
+ printf("Error in setglobalvar command--illegal char\n");
+ return 0;
+ }
+
+ if (chtype != state)
+ {
+ if (state != 0)
+ {
+ *clptr++ = 0;
+ }
+ tokenptr[tokencnt++] = clptr;
+ if (chtype == 3)
+ {
+ state = 4;
+ }
+ else
+ {
+ state = chtype;
+ }
+ }
+ *clptr++ = ch;
+ }
+ *clptr++ = 0;
+ }
+
+ return tokencnt;
+}
+
diff --git a/private/ntos/ndis/testprot/tpctl/info.c b/private/ntos/ndis/testprot/tpctl/info.c
new file mode 100644
index 000000000..96acecd09
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpctl/info.c
@@ -0,0 +1,1497 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ info.c
+
+Abstract:
+
+ This module handles the printing of the results of the Query and
+ Set commands.
+
+Author:
+
+ Tom Adams (tomad) 2-Dec-1991
+
+Revision History:
+
+ 2-Apr-1991 tomad
+
+ created
+
+ Sanjeev Katariya (sanjeevk)
+ 4-12-1993 Added Arcnet support
+ 4-15-1993 Added additional OIDS
+
+
+--*/
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+
+#include <windows.h>
+
+//#include <ndis.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tpctl.h"
+#include "parse.h"
+
+
+#define CHAR_SP 0x20
+#define INDENT 12
+#define MAX_STR_LEN 80
+
+
+/*++
+
+VOID
+TpctlDumpNewLine(
+ LPSTR Buffer
+ );
+
+--*/
+
+
+#define TpctlDumpNewLine( Buffer ) { \
+ Buffer += (BYTE)sprintf( Buffer,"\n" ); \
+}
+
+/*++
+
+VOID
+TpctlDumpLabel(
+ LPSTR Buffer,
+ PBYTE Label
+ );
+
+--*/
+
+#define TpctlDumpLabel( Buffer,Label ) { \
+ DWORD i; \
+ DWORD Length; \
+ BYTE _Str[MAX_STR_LEN]; \
+ \
+ for ( i=0;i<INDENT;i++ ) { \
+ _Str[i] = CHAR_SP; \
+ } \
+ Length = strlen( Label ); \
+ strncpy( &_Str[INDENT],#Label,Length+2 ); \
+ \
+ for ( i=strlen( _Str ) ; i<MAX_STR_LEN ; i++ ) { \
+ _Str[i] = CHAR_SP; \
+ } \
+ _Str[INDENT+Length+2] = '\0'; \
+ Buffer += (BYTE)sprintf( Buffer,"%s",_Str ); \
+ \
+ TpctlDumpNewLine( Buffer ); \
+}
+
+/*++
+
+VOID
+TpctlDumpEquality(
+ LPSTR Buffer,
+ DWORD Value,
+ DWORD String
+ );
+
+--*/
+
+#define TpctlDumpEquality( Buffer,Value,String ) { \
+ \
+ if ( Value == String ) { \
+ TpctlDumpLabel( Buffer,#String ); \
+ return; \
+ } \
+}
+
+/*++
+
+VOID
+TpctlDumpBitField(
+ LPSTR Buffer,
+ DWORD PacketFilter,
+ DWORD BitField
+ );
+
+--*/
+
+#define TpctlDumpBitfield( Buffer,Value,BitField ) { \
+ \
+ if (( Value ) & BitField ) { \
+ TpctlDumpLabel( Buffer,#BitField ); \
+ } \
+}
+
+VOID
+TpctlDumpOID(
+ LPSTR *B,
+ DWORD OID
+ )
+{
+ //
+ // General Objects
+ //
+
+ TpctlDumpEquality( *B,OID,OID_GEN_SUPPORTED_LIST );
+ TpctlDumpEquality( *B,OID,OID_GEN_HARDWARE_STATUS );
+ TpctlDumpEquality( *B,OID,OID_GEN_MEDIA_SUPPORTED );
+ TpctlDumpEquality( *B,OID,OID_GEN_MEDIA_IN_USE );
+ TpctlDumpEquality( *B,OID,OID_GEN_MAXIMUM_LOOKAHEAD );
+ TpctlDumpEquality( *B,OID,OID_GEN_MAXIMUM_FRAME_SIZE );
+ TpctlDumpEquality( *B,OID,OID_GEN_LINK_SPEED );
+ TpctlDumpEquality( *B,OID,OID_GEN_TRANSMIT_BUFFER_SPACE );
+ TpctlDumpEquality( *B,OID,OID_GEN_RECEIVE_BUFFER_SPACE );
+ TpctlDumpEquality( *B,OID,OID_GEN_TRANSMIT_BLOCK_SIZE );
+ TpctlDumpEquality( *B,OID,OID_GEN_RECEIVE_BLOCK_SIZE );
+ TpctlDumpEquality( *B,OID,OID_GEN_VENDOR_ID );
+ TpctlDumpEquality( *B,OID,OID_GEN_VENDOR_DESCRIPTION );
+ TpctlDumpEquality( *B,OID,OID_GEN_CURRENT_PACKET_FILTER );
+ TpctlDumpEquality( *B,OID,OID_GEN_CURRENT_LOOKAHEAD );
+ TpctlDumpEquality( *B,OID,OID_GEN_DRIVER_VERSION );
+ TpctlDumpEquality( *B,OID,OID_GEN_MAXIMUM_TOTAL_SIZE );
+ TpctlDumpEquality( *B,OID,OID_GEN_PROTOCOL_OPTIONS );
+ TpctlDumpEquality( *B,OID,OID_GEN_MAC_OPTIONS );
+
+ TpctlDumpEquality( *B,OID,OID_GEN_XMIT_OK );
+ TpctlDumpEquality( *B,OID,OID_GEN_RCV_OK );
+ TpctlDumpEquality( *B,OID,OID_GEN_XMIT_ERROR );
+ TpctlDumpEquality( *B,OID,OID_GEN_RCV_ERROR );
+ TpctlDumpEquality( *B,OID,OID_GEN_RCV_NO_BUFFER );
+
+ TpctlDumpEquality( *B,OID,OID_GEN_DIRECTED_BYTES_XMIT );
+ TpctlDumpEquality( *B,OID,OID_GEN_DIRECTED_FRAMES_XMIT );
+ TpctlDumpEquality( *B,OID,OID_GEN_MULTICAST_BYTES_XMIT );
+ TpctlDumpEquality( *B,OID,OID_GEN_MULTICAST_FRAMES_XMIT );
+ TpctlDumpEquality( *B,OID,OID_GEN_BROADCAST_BYTES_XMIT );
+ TpctlDumpEquality( *B,OID,OID_GEN_BROADCAST_FRAMES_XMIT );
+ TpctlDumpEquality( *B,OID,OID_GEN_DIRECTED_BYTES_RCV );
+ TpctlDumpEquality( *B,OID,OID_GEN_DIRECTED_FRAMES_RCV );
+ TpctlDumpEquality( *B,OID,OID_GEN_MULTICAST_BYTES_RCV );
+ TpctlDumpEquality( *B,OID,OID_GEN_MULTICAST_FRAMES_RCV );
+ TpctlDumpEquality( *B,OID,OID_GEN_BROADCAST_BYTES_RCV );
+ TpctlDumpEquality( *B,OID,OID_GEN_BROADCAST_FRAMES_RCV );
+
+ TpctlDumpEquality( *B,OID,OID_GEN_RCV_CRC_ERROR );
+ TpctlDumpEquality( *B,OID,OID_GEN_TRANSMIT_QUEUE_LENGTH );
+
+ //
+ // 802.3 Objects
+ //
+
+ TpctlDumpEquality( *B,OID,OID_802_3_PERMANENT_ADDRESS );
+ TpctlDumpEquality( *B,OID,OID_802_3_CURRENT_ADDRESS );
+ TpctlDumpEquality( *B,OID,OID_802_3_MULTICAST_LIST );
+ TpctlDumpEquality( *B,OID,OID_802_3_MAXIMUM_LIST_SIZE );
+
+ TpctlDumpEquality( *B,OID,OID_802_3_RCV_ERROR_ALIGNMENT );
+ TpctlDumpEquality( *B,OID,OID_802_3_XMIT_ONE_COLLISION );
+ TpctlDumpEquality( *B,OID,OID_802_3_XMIT_MORE_COLLISIONS );
+
+ TpctlDumpEquality( *B,OID,OID_802_3_XMIT_DEFERRED);
+ TpctlDumpEquality( *B,OID,OID_802_3_XMIT_MAX_COLLISIONS );
+ TpctlDumpEquality( *B,OID,OID_802_3_RCV_OVERRUN );
+ TpctlDumpEquality( *B,OID,OID_802_3_XMIT_UNDERRUN );
+ TpctlDumpEquality( *B,OID,OID_802_3_XMIT_HEARTBEAT_FAILURE );
+ TpctlDumpEquality( *B,OID,OID_802_3_XMIT_TIMES_CRS_LOST );
+ TpctlDumpEquality( *B,OID,OID_802_3_XMIT_LATE_COLLISIONS );
+
+ //
+ // 802.5 Objects
+ //
+
+ TpctlDumpEquality( *B,OID,OID_802_5_PERMANENT_ADDRESS );
+ TpctlDumpEquality( *B,OID,OID_802_5_CURRENT_ADDRESS );
+ TpctlDumpEquality( *B,OID,OID_802_5_CURRENT_FUNCTIONAL );
+ TpctlDumpEquality( *B,OID,OID_802_5_CURRENT_GROUP );
+ TpctlDumpEquality( *B,OID,OID_802_5_LAST_OPEN_STATUS );
+ TpctlDumpEquality( *B,OID,OID_802_5_CURRENT_RING_STATUS );
+ TpctlDumpEquality( *B,OID,OID_802_5_CURRENT_RING_STATE );
+
+ TpctlDumpEquality( *B,OID,OID_802_5_LINE_ERRORS );
+ TpctlDumpEquality( *B,OID,OID_802_5_LOST_FRAMES );
+
+ TpctlDumpEquality( *B,OID,OID_802_5_BURST_ERRORS );
+ TpctlDumpEquality( *B,OID,OID_802_5_AC_ERRORS );
+ TpctlDumpEquality( *B,OID,OID_802_5_ABORT_DELIMETERS );
+ TpctlDumpEquality( *B,OID,OID_802_5_FRAME_COPIED_ERRORS );
+ TpctlDumpEquality( *B,OID,OID_802_5_FREQUENCY_ERRORS );
+ TpctlDumpEquality( *B,OID,OID_802_5_TOKEN_ERRORS );
+ TpctlDumpEquality( *B,OID,OID_802_5_INTERNAL_ERRORS );
+
+ //
+ // Fddi object
+ //
+
+ TpctlDumpEquality( *B,OID,OID_FDDI_LONG_PERMANENT_ADDR );
+ TpctlDumpEquality( *B,OID,OID_FDDI_LONG_CURRENT_ADDR );
+ TpctlDumpEquality( *B,OID,OID_FDDI_LONG_MULTICAST_LIST );
+ TpctlDumpEquality( *B,OID,OID_FDDI_LONG_MAX_LIST_SIZE );
+ TpctlDumpEquality( *B,OID,OID_FDDI_SHORT_PERMANENT_ADDR );
+ TpctlDumpEquality( *B,OID,OID_FDDI_SHORT_CURRENT_ADDR );
+ TpctlDumpEquality( *B,OID,OID_FDDI_SHORT_MULTICAST_LIST );
+ TpctlDumpEquality( *B,OID,OID_FDDI_SHORT_MAX_LIST_SIZE);
+
+ TpctlDumpEquality( *B,OID,OID_FDDI_ATTACHMENT_TYPE );
+ TpctlDumpEquality( *B,OID,OID_FDDI_UPSTREAM_NODE_LONG );
+ TpctlDumpEquality( *B,OID,OID_FDDI_DOWNSTREAM_NODE_LONG );
+ TpctlDumpEquality( *B,OID,OID_FDDI_FRAME_ERRORS );
+ TpctlDumpEquality( *B,OID,OID_FDDI_FRAMES_LOST );
+ TpctlDumpEquality( *B,OID,OID_FDDI_RING_MGT_STATE );
+ TpctlDumpEquality( *B,OID,OID_FDDI_LCT_FAILURES );
+ TpctlDumpEquality( *B,OID,OID_FDDI_LEM_REJECTS );
+ TpctlDumpEquality( *B,OID,OID_FDDI_LCONNECTION_STATE );
+
+ //
+ // STARTCHANGE
+ //
+ TpctlDumpEquality( *B,OID,OID_ARCNET_PERMANENT_ADDRESS );
+ TpctlDumpEquality( *B,OID,OID_ARCNET_CURRENT_ADDRESS ) ;
+ TpctlDumpEquality( *B,OID,OID_ARCNET_RECONFIGURATIONS ) ;
+ //
+ // STOPCHANGE
+ //
+
+ //
+ // Async Objects
+ //
+
+/* Not currently supported.
+
+ TpctlDumpEquality( *B,OID,OID_ASYNC_PERMANENT_ADDRESS );
+ TpctlDumpEquality( *B,OID,OID_ASYNC_CURRENT_ADDRESS );
+ TpctlDumpEquality( *B,OID,OID_ASYNC_QUALITY_OF_SERVICE );
+ TpctlDumpEquality( *B,OID,OID_ASYNC_PROTOCOL_TYPE );
+*/
+ //
+ // LocalTalk Objects
+ //
+
+/* Not currently supported.
+
+ TpctlDumpEquality( *B,OID,OID_LTALK_CURRENT_NODE_ID );
+
+ TpctlDumpEquality( *B,OID,OID_LTALK_IN_BROADCASTS );
+ TpctlDumpEquality( *B,OID,OID_LTALK_IN_LENGTH_ERRORS );
+
+ TpctlDumpEquality( *B,OID,OID_LTALK_OUT_NO_HANDLERS );
+ TpctlDumpEquality( *B,OID,OID_LTALK_COLLISIONS );
+ TpctlDumpEquality( *B,OID,OID_LTALK_DEFERS );
+ TpctlDumpEquality( *B,OID,OID_LTALK_NO_DATA_ERRORS );
+ TpctlDumpEquality( *B,OID,OID_LTALK_RANDOM_CTS_ERRORS );
+ TpctlDumpEquality( *B,OID,OID_LTALK_FCS_ERRORS );
+*/
+}
+
+
+VOID
+TpctlDumpHardWareStatus(
+ LPSTR *B,
+ DWORD Status
+ )
+{
+ TpctlDumpNewLine( *B );
+ TpctlDumpEquality( *B,Status,NdisHardwareStatusClosing );
+ TpctlDumpEquality( *B,Status,NdisHardwareStatusInitializing );
+ TpctlDumpEquality( *B,Status,NdisHardwareStatusNotReady );
+ TpctlDumpEquality( *B,Status,NdisHardwareStatusReady );
+ TpctlDumpEquality( *B,Status,NdisHardwareStatusReset );
+ TpctlDumpNewLine( *B );
+}
+
+VOID
+TpctlDumpPacketFilter(
+ LPSTR *B,
+ DWORD PacketFilter
+ )
+{
+ TpctlDumpNewLine( *B );
+ TpctlDumpBitfield( *B,PacketFilter,NDIS_PACKET_TYPE_DIRECTED );
+ TpctlDumpBitfield( *B,PacketFilter,NDIS_PACKET_TYPE_MULTICAST );
+ TpctlDumpBitfield( *B,PacketFilter,NDIS_PACKET_TYPE_ALL_MULTICAST );
+ TpctlDumpBitfield( *B,PacketFilter,NDIS_PACKET_TYPE_BROADCAST );
+ TpctlDumpBitfield( *B,PacketFilter,NDIS_PACKET_TYPE_SOURCE_ROUTING );
+ TpctlDumpBitfield( *B,PacketFilter,NDIS_PACKET_TYPE_PROMISCUOUS );
+ TpctlDumpBitfield( *B,PacketFilter,NDIS_PACKET_TYPE_MAC_FRAME );
+ TpctlDumpBitfield( *B,PacketFilter,NDIS_PACKET_TYPE_GROUP );
+ TpctlDumpBitfield( *B,PacketFilter,NDIS_PACKET_TYPE_FUNCTIONAL );
+ TpctlDumpBitfield( *B,PacketFilter,NDIS_PACKET_TYPE_ALL_FUNCTIONAL );
+ TpctlDumpNewLine( *B );
+}
+
+VOID
+TpctlDumpNdisMedium(
+ LPSTR *B,
+ DWORD NdisMedium
+ )
+{
+ TpctlDumpEquality( *B,NdisMedium,NdisMedium802_3 );
+ TpctlDumpEquality( *B,NdisMedium,NdisMedium802_5 );
+ TpctlDumpEquality( *B,NdisMedium,NdisMediumFddi );
+ //
+ // STARTCHANGE ARCNET
+ //
+ TpctlDumpEquality( *B,NdisMedium,NdisMediumArcnet878_2 );
+ //
+ // STOPCHANGE ARCNET
+ //
+
+}
+
+
+VOID
+TpctlPrintQueryInfoResults(
+ PREQUEST_RESULTS Results,
+ DWORD CmdCode,
+ NDIS_OID OID
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ DWORD Status;
+ LPSTR TmpBuf;
+ LPBYTE Address;
+ LPDWORD Counters;
+ DWORD BytesWritten;
+ DWORD i;
+ DWORD Number;
+ LPDWORD Supported;
+
+
+ //ASSERT( Results->Signature == REQUEST_RESULTS_SIGNATURE );
+ //ASSERT(( Results->NdisRequestType == NdisRequestQueryInformation ) ||
+ // ( Results->NdisRequestType == NdisRequestQueryStatistics ));
+ //ASSERT( Results->OID == OID );
+
+ TmpBuf = GlobalBuf;
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tCmdCode = %s\n\n",
+ TpctlGetCmdCode( CmdCode ));
+
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\t OID = 0x%08lX\n",OID);
+ TpctlDumpOID( &TmpBuf,OID );
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tReturn Status = %s\n",
+ TpctlGetStatus( Results->RequestStatus ));
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tRequest Pended = %s",
+ Results->RequestPended ? "TRUE" : "FALSE");
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ if (( Results->RequestStatus != NDIS_STATUS_SUCCESS ) &&
+ ( Results->RequestStatus != NDIS_STATUS_NOT_SUPPORTED )) {
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tBytesWritten = %d\n",
+ Results->BytesReadWritten);
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tBytesNeeded = %d\n\n",
+ Results->BytesNeeded);
+
+ } else if ( Results->RequestStatus == NDIS_STATUS_SUCCESS ) {
+
+ switch ( Results->OID ) {
+
+ //
+ // GENERAL OBJECTS
+ //
+
+ //
+ // General Operational Characteristics
+ //
+
+ case OID_GEN_SUPPORTED_LIST: // 0x00010101
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tSupported OIDs are:\n\n");
+
+ Number = Results->BytesReadWritten / sizeof( DWORD );
+
+ Supported = (LPDWORD)Results->InformationBuffer;
+
+ for ( i=0;i<Number;i++ ) {
+ TpctlDumpOID( &TmpBuf,*Supported++ );
+ }
+
+ ADD_DIFF_FLAG( TmpBuf, "\t MAY_DIFFER" );
+
+ break;
+
+ case OID_GEN_HARDWARE_STATUS: // 0x00010102
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tHardware Status = 0x%lx\n",
+ *(LPDWORD)Results->InformationBuffer);
+
+ TpctlDumpHardWareStatus( &TmpBuf,*(LPDWORD)Results->InformationBuffer );
+
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED: // 0x00010103
+ case OID_GEN_MEDIA_IN_USE: // 0x00010104
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tMedia Types Supported are:\n\n");
+
+ Number = Results->BytesReadWritten / sizeof( DWORD );
+ Supported = (LPDWORD)Results->InformationBuffer;
+
+ for ( i=0;i<Number;i++ ) {
+
+ TpctlDumpNdisMedium( &TmpBuf,*Supported++ );
+ }
+
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD: // 0x00010105
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tMaximum Lookahead Size = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_GEN_MAXIMUM_FRAME_SIZE: // 0x00010106
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tMaximum Frame Size = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+ case OID_GEN_LINK_SPEED: // 0x00010107
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tLink Speed (bps) = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_GEN_TRANSMIT_BUFFER_SPACE: // 0x00010108
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tTransmit Buffer Space = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_GEN_RECEIVE_BUFFER_SPACE: // 0x00010109
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tReceive Buffer Space = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_GEN_TRANSMIT_BLOCK_SIZE: // 0x0001010A
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tTransmit Block Size = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_GEN_RECEIVE_BLOCK_SIZE: // 0x0001010B
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tReceive Block Size = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_GEN_VENDOR_ID: // 0x0001010C
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tVendor ID = %u",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION: // 0x0001010D
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tVendor Description = %s",
+ (PCHAR)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER");
+
+ break;
+
+ case OID_GEN_DRIVER_VERSION: // 0x00010110
+ {
+ LPBYTE Version = (LPBYTE)&Results->InformationBuffer;
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tDriver Version Number = %d.%d\n",
+ Version[1],Version[0]);
+ break;
+ }
+ case OID_GEN_CURRENT_PACKET_FILTER: // 0x0001010E
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tCurrent Packet Filter = 0x%lx\n",
+ *(LPDWORD)Results->InformationBuffer);
+
+ TpctlDumpPacketFilter( &TmpBuf,*(LPDWORD)Results->InformationBuffer );
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD: // 0x0001010F
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tCurrent Lookahead Size = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_GEN_MAXIMUM_TOTAL_SIZE: // 0x00010111
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tMaximum Total Size = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_GEN_PROTOCOL_OPTIONS: // 0x00010112
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tGeneral Protocol Options = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_GEN_MAC_OPTIONS: // 0x00010113
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tGeneral MAC Options = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ //
+ // General Statitics - Mandatory
+ //
+
+ case OID_GEN_XMIT_OK: // 0x00020101
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tFrame Transmits - OK = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_GEN_RCV_OK: // 0x00020102
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tFrame Receives - OK = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_GEN_XMIT_ERROR: // 0x00020103
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tFrame Tranmsits With Error = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_GEN_RCV_ERROR: // 0x00020104
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tFrame Receives With Error = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_GEN_RCV_NO_BUFFER: // 0x00020105
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tFrames Missed, No Buffers = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ //
+ // General Statitics - Optional
+ //
+
+ case OID_GEN_DIRECTED_BYTES_XMIT: // 0x00020201
+
+ Counters = (LPDWORD)&Results->InformationBuffer;
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tDirected Bytes Transmitted - OK = 0x%08lX - 0x%08lX",
+ Counters[1],Counters[0]);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_GEN_DIRECTED_FRAMES_XMIT: // 0x00020202
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tDirected Frames Transmitted - OK = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_GEN_MULTICAST_BYTES_XMIT: // 0x00020203
+
+ Counters = (LPDWORD)&Results->InformationBuffer;
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tMulticast Bytes Transmitted - OK = 0x%08lX - 0x%08lX",
+ Counters[1],Counters[0]);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_GEN_MULTICAST_FRAMES_XMIT: // 0x00020204
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tMulticast Frames Transmitted - OK = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_GEN_BROADCAST_BYTES_XMIT: // 0x00020205
+
+ Counters = (LPDWORD)&Results->InformationBuffer;
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tBroadcast Bytes Transmitted - OK = 0x%08lX - 0x%08lX",
+ Counters[1],Counters[0]);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_GEN_BROADCAST_FRAMES_XMIT: // 0x00020206
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tBroadcast Frames Transmitted - OK = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_GEN_DIRECTED_BYTES_RCV: // 0x00020207
+
+ Counters = (LPDWORD)&Results->InformationBuffer;
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tDirected Bytes Received - OK = 0x%08lX - 0x%08lX",
+ Counters[1],Counters[0]);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_GEN_DIRECTED_FRAMES_RCV: // 0x00020208
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tDirected Frames Received - OK = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_GEN_MULTICAST_BYTES_RCV: // 0x00020209
+
+ Counters = (LPDWORD)&Results->InformationBuffer;
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tMulticast Bytes Received - OK = 0x%08lX - 0x%08lX",
+ Counters[1],Counters[0]);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_GEN_MULTICAST_FRAMES_RCV: // 0x0002020A
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tMulticast Frames Received - OK = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_GEN_BROADCAST_BYTES_RCV: // 0x0002020B
+
+ Counters = (LPDWORD)&Results->InformationBuffer;
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tBroadcast Bytes Received - OK = 0x%08lX - 0x%08lX",
+ Counters[1],Counters[0]);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_GEN_BROADCAST_FRAMES_RCV: // 0x0002020C
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tBroadcast Frames Received - OK = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_GEN_RCV_CRC_ERROR: // 0x0002020D
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tFrames Received With CRC/FCS Errors = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_GEN_TRANSMIT_QUEUE_LENGTH: // 0x0002020E
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tLength of Tramsit Queue = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ //
+ // 802.3 OBJECTS
+ //
+
+ //
+ // 802.3 Operation Characteristics
+ //
+
+ case OID_802_3_PERMANENT_ADDRESS: // 0x01010101
+
+ Address = (LPBYTE)&Results->InformationBuffer;
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tPermanent Station Address = %02X-%02X-%02X-%02X-%02X-%02X",
+ Address[0],Address[1],Address[2],Address[3],Address[4],Address[5]);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_802_3_CURRENT_ADDRESS: // 0x01010102
+
+ Address = (LPBYTE)&Results->InformationBuffer;
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tCurrent Station Address = %02X-%02X-%02X-%02X-%02X-%02X\n",
+ Address[0],Address[1],Address[2],Address[3],Address[4],Address[5]);
+
+ break;
+
+ case OID_802_3_MULTICAST_LIST: // 0x01010103
+
+ Number = Results->BytesReadWritten / ADDRESS_LENGTH;
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tMulticast Address List:\n\n");
+
+ if ( Number == 0 ) {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\t\tNone.\n");
+ } else {
+
+ Address = (LPBYTE)&Results->InformationBuffer;
+
+ for ( i=0;i<Number;i++ ) {
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\t\t%02X-%02X-%02X-%02X-%02X-%02X\n",
+ Address[0],Address[1],Address[2],Address[3],Address[4],Address[5]);
+
+ Address += (BYTE)ADDRESS_LENGTH;
+ }
+ }
+
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE: // 0x01010104
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tMaximum Multicast List Size = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ //
+ // 802.3 Statitics - Mandatory
+ //
+
+ case OID_802_3_RCV_ERROR_ALIGNMENT: // 0x01020101
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tFrames Received With Alignment Error = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_802_3_XMIT_ONE_COLLISION: // 0x01020102
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tFrames Transmitted With One Collision = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_802_3_XMIT_MORE_COLLISIONS: // 0x01020103
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tFrames Transmitted With Greater Than One Collision = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ //
+ // 802.3 Statitics - Optional
+ //
+
+ case OID_802_3_XMIT_DEFERRED: // 0x01020201
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tFrames Transmitted After Deferral = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_802_3_XMIT_MAX_COLLISIONS: // 0x01020202
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tFrames Not Transmitted Due To Collisions = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_802_3_RCV_OVERRUN: // 0x01020203
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tFrames Not Received Due To Overrun = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_802_3_XMIT_UNDERRUN: // 0x01020204
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tFrames Not Transmitted Due To Underrun = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_802_3_XMIT_HEARTBEAT_FAILURE: // 0x01020205
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tFrames Transmitted With Heartbeat Failure = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_802_3_XMIT_TIMES_CRS_LOST: // 0x01020206
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tTimes CRC Lost During Transmit = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_802_3_XMIT_LATE_COLLISIONS: // 0x01020207
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tLate Collisions Detected = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ //
+ // 802.5 OBJECTS
+ //
+
+ //
+ // 802.5 Operation Characteristics
+ //
+
+ case OID_802_5_PERMANENT_ADDRESS: // 0x02010101
+
+ Address = (LPBYTE)&Results->InformationBuffer;
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tPermanent Station Address = %02X-%02X-%02X-%02X-%02X-%02X",
+ Address[0],Address[1],Address[2],Address[3],Address[4],Address[5]);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_802_5_CURRENT_ADDRESS: // 0x02010102
+
+ Address = (LPBYTE)&Results->InformationBuffer;
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tCurrent Station Address = %02X-%02X-%02X-%02X-%02X-%02X\n",
+ Address[0],Address[1],Address[2],Address[3],Address[4],Address[5]);
+
+ break;
+
+ case OID_802_5_CURRENT_FUNCTIONAL: // 0x02010103
+
+ Address = (LPBYTE)&Results->InformationBuffer;
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tCurrent Functional Address = %02X-%02X-%02X-%02X\n",
+ Address[0],Address[1],Address[2],Address[3]);
+
+ break;
+
+ case OID_802_5_CURRENT_GROUP: // 0x02010104
+
+ Address = (LPBYTE)&Results->InformationBuffer;
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tCurrent Group Address = %02X-%02X-%02X-%02X\n",
+ Address[0],Address[1],Address[2],Address[3]);
+
+ break;
+
+ case OID_802_5_LAST_OPEN_STATUS: // 0x02010105
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tLast Open Status = %d",
+ *(LPWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_802_5_CURRENT_RING_STATUS: // 0x02010106
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tCurrent Ring Status = %d",
+ *(LPWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_802_5_CURRENT_RING_STATE: // 0x02010107
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tCurrent Ring State = %d",
+ *(LPWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ //
+ // 802.5 Statitics - Mandatory
+ //
+
+ case OID_802_5_LINE_ERRORS: // 0x02020101
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tLine Errors Detected= %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_802_5_LOST_FRAMES: // 0x02020102
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tLost Frames = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ //
+ // 802.5 Statitics - Optional
+ //
+
+ case OID_802_5_BURST_ERRORS: // 0x02020201
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tBurst Errors Detected = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_802_5_AC_ERRORS: // 0x02020202
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tA/C Errors = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_802_5_ABORT_DELIMETERS: // 0x02020203
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tAbort Delimeter Detected = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_802_5_FRAME_COPIED_ERRORS: // 0x02020204
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tFrame Copied Errors = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_802_5_FREQUENCY_ERRORS: // 0x02020205
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tFrequency Errors Detected = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_802_5_TOKEN_ERRORS: // 0x02020206
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tToken Errors = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_802_5_INTERNAL_ERRORS: // 0x02020207
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tInternal Errors = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ //
+ // FDDI
+ //
+
+ case OID_FDDI_LONG_PERMANENT_ADDR : // 0x03010101
+
+ Address = (LPBYTE)&Results->InformationBuffer;
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tLong Permanent Station Address = %02X-%02X-%02X-%02X-%02X-%02X",
+ Address[0],Address[1],Address[2],Address[3],Address[4],Address[5]);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_FDDI_LONG_CURRENT_ADDR : // 0x03010102
+
+ Address = (LPBYTE)&Results->InformationBuffer;
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tLong Current Station Address = %02X-%02X-%02X-%02X-%02X-%02X\n",
+ Address[0],Address[1],Address[2],Address[3],Address[4],Address[5]);
+
+ break;
+
+ case OID_FDDI_LONG_MULTICAST_LIST : // 0x03010103
+
+ Number = Results->BytesReadWritten / ADDRESS_LENGTH;
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tLong Multicast Address List:\n\n");
+
+ if ( Number == 0 ) {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\t\tNone.\n");
+ } else {
+
+ Address = (LPBYTE)&Results->InformationBuffer;
+
+ for ( i=0;i<Number;i++ ) {
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\t\t%02X-%02X-%02X-%02X-%02X-%02X\n",
+ Address[0],Address[1],Address[2],Address[3],Address[4],Address[5]);
+
+ Address += (BYTE)ADDRESS_LENGTH;
+ }
+ }
+
+ break;
+
+ case OID_FDDI_LONG_MAX_LIST_SIZE : // 0x03010104
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tLong Maximum Multicast List Size = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_FDDI_SHORT_PERMANENT_ADDR : // 0x03010105
+
+ Address = (LPBYTE)&Results->InformationBuffer;
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tShort Permanent Station Address = %02X-%02X",
+ Address[0],Address[1]);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_FDDI_SHORT_CURRENT_ADDR : // 0x03010106
+
+ Address = (LPBYTE)&Results->InformationBuffer;
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tShort Current Station Address = %02X-%02X\n",
+ Address[0],Address[1]);
+
+ break;
+
+ case OID_FDDI_SHORT_MULTICAST_LIST : // 0x03010107
+
+ Number = Results->BytesReadWritten / ADDRESS_LENGTH;
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tShort Multicast Address List:\n\n");
+
+ if ( Number == 0 ) {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\t\tNone.\n");
+ } else {
+
+ Address = (LPBYTE)&Results->InformationBuffer;
+
+ for ( i=0;i<Number;i++ ) {
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\t\t%02X-%02X\n",
+ Address[0],Address[1]);
+
+ Address += (BYTE)ADDRESS_LENGTH;
+ }
+ }
+
+ break;
+
+ case OID_FDDI_SHORT_MAX_LIST_SIZE: // 0x03010108
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tShort Maximum Multicast List Size = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_FDDI_ATTACHMENT_TYPE: // 0x03020101
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tAttachment Type = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_FDDI_UPSTREAM_NODE_LONG: // 0x03020102
+
+ Address = (LPBYTE)&Results->InformationBuffer;
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tLong Upstream Node Address = %02X-%02X-%02X-%02X-%02X-%02X",
+ Address[0],Address[1],Address[2],Address[3],Address[4],Address[5]);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_FDDI_DOWNSTREAM_NODE_LONG: // 0x03020103
+
+ Address = (LPBYTE)&Results->InformationBuffer;
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tLong Downstream Node Address = %02X-%02X-%02X-%02X-%02X-%02X",
+ Address[0],Address[1],Address[2],Address[3],Address[4],Address[5]);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_FDDI_FRAME_ERRORS: // 0x03020104
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tFrame Errors = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_FDDI_FRAMES_LOST: // 0x03020105
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tFrames Lost = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_FDDI_RING_MGT_STATE: // 0x03020106
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tRing Management State = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_FDDI_LCT_FAILURES: // 0x03020107
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tLCT Failures = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_FDDI_LEM_REJECTS: // 0x03020108
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tLEM Rejects = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_FDDI_LCONNECTION_STATE: // 0x03020109
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tL Connection State = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ //
+ // STARTCHANGE ARCNET
+ //
+ case OID_ARCNET_PERMANENT_ADDRESS: // 0x06010101
+
+ Address = (LPBYTE)&Results->InformationBuffer;
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tPermanent Station Address = %02X", Address[0]);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ case OID_ARCNET_CURRENT_ADDRESS: // 0x06010102
+
+ Address = (LPBYTE)&Results->InformationBuffer;
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tCurrent Station Address = %02X\n", Address[0]);
+
+ break;
+
+ case OID_ARCNET_RECONFIGURATIONS: // 0x06010103
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tReconfigurations = %d",
+ *(LPDWORD)Results->InformationBuffer);
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ break;
+
+ //
+ // STOPCHANGE ARCNET
+ //
+
+ default:
+
+ TmpBuf +=(BYTE)sprintf(TmpBuf,"\tInvalid OID or OID not yet supported.\n");
+ break;
+ }
+ }
+
+ if (( CommandsFromScript ) || ( CommandLineLogging )) {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\t**********************************");
+ }
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n");
+
+ if ( Verbose ) {
+
+ if ( !WriteFile(
+ GetStdHandle( STD_OUTPUT_HANDLE ),
+ GlobalBuf,
+ (TmpBuf-GlobalBuf),
+ &BytesWritten,
+ NULL
+ )) {
+
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: WriteFile to screen failed, returned 0x%lx\n",(PVOID)Status);
+ }
+ }
+
+ if ( CommandsFromScript ) {
+
+ if ( !WriteFile(
+ Scripts[ScriptIndex].LogHandle,
+ GlobalBuf,
+ (TmpBuf-GlobalBuf),
+ &BytesWritten,
+ NULL
+ )) {
+
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: WriteFile to logfile failed, returned 0x%lx\n",(PVOID)Status);
+ }
+
+ } else if ( CommandLineLogging ) {
+
+ if ( !WriteFile(
+ CommandLineLogHandle,
+ GlobalBuf,
+ (TmpBuf-GlobalBuf),
+ &BytesWritten,
+ NULL
+ )) {
+
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: WriteFile to logfile failed, returned 0x%lx\n",(PVOID)Status);
+ }
+ }
+}
+
+
+VOID
+TpctlPrintSetInfoResults(
+ PREQUEST_RESULTS Results,
+ DWORD CmdCode,
+ NDIS_OID OID
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ DWORD Status;
+ LPSTR TmpBuf;
+ DWORD BytesWritten;
+ BOOL ErrorReturned = FALSE;
+
+
+ //ASSERT( Results->Signature == REQUEST_RESULTS_SIGNATURE );
+ //ASSERT( Results->NdisRequestType == NdisRequestSetInformation );
+ //ASSERT( Results->OID == OID );
+
+ TmpBuf = GlobalBuf;
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tCmdCode = %s\n\n",
+ TpctlGetCmdCode( CmdCode ));
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\t OID = 0x%08lX\n",OID);
+ TpctlDumpOID( &TmpBuf,OID );
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tReturn Status = %s\n",
+ TpctlGetStatus( Results->RequestStatus ));
+
+ if ( Results->RequestStatus != STATUS_SUCCESS ) {
+ ErrorReturned = TRUE;
+ }
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tRequest Pended = %s",
+ Results->RequestPended ? "TRUE" : "FALSE");
+
+ ADD_DIFF_FLAG( TmpBuf, "\tMAY_DIFFER" );
+
+ if ( Results->RequestStatus != NDIS_STATUS_SUCCESS ) {
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tBytesRead = %d\n",
+ Results->BytesReadWritten);
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tBytesNeeded = %d\n",
+ Results->BytesNeeded);
+ }
+
+ if (( CommandsFromScript ) || ( CommandLineLogging )) {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\t**********************************");
+ }
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n");
+
+ if ( Verbose ) {
+
+ if ( !WriteFile(
+ GetStdHandle( STD_OUTPUT_HANDLE ),
+ GlobalBuf,
+ (TmpBuf-GlobalBuf),
+ &BytesWritten,
+ NULL
+ )) {
+
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: WriteFile to screen failed, returned 0x%lx\n",(PVOID)Status);
+ }
+ }
+
+ if (( CommandsFromScript ) &&
+ ((( !Verbose ) && ( ErrorReturned )) || ( Verbose ))) {
+
+ if( !WriteFile(
+ Scripts[ScriptIndex].LogHandle,
+ GlobalBuf,
+ (TmpBuf-GlobalBuf),
+ &BytesWritten,
+ NULL
+ )) {
+
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: WriteFile to logfile failed, returned 0x%lx\n",(PVOID)Status);
+ }
+
+ } else if ( CommandLineLogging ) {
+
+ if( !WriteFile(
+ CommandLineLogHandle,
+ GlobalBuf,
+ (TmpBuf-GlobalBuf),
+ &BytesWritten,
+ NULL
+ )) {
+
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: WriteFile to logfile failed, returned 0x%lx\n",(PVOID)Status);
+ }
+ }
+}
diff --git a/private/ntos/ndis/testprot/tpctl/init.c b/private/ntos/ndis/testprot/tpctl/init.c
new file mode 100644
index 000000000..99a289c1a
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpctl/init.c
@@ -0,0 +1,1098 @@
+// ********************************
+//
+// Copyright (c) 1990 Microsoft Corporation
+//
+// Module Name:
+//
+// tpctl.c
+//
+// Abstract:
+//
+// This is the main component of the NDIS 3.0 MAC Tester control program.
+//
+// Author:
+//
+// Tom Adams (tomad) 2-Apr-1991
+//
+// Revision History:
+//
+// 2-Apr-1991 tomad
+//
+// created
+//
+// 7-1-1993 SanjeevK
+//
+// Added support for recording of sessions to a script file
+// Added support for write through and error handling conditions
+//
+// 5-18-1994 timothyw
+// added hooks for global variable access; cleanup
+// 6-08-1994 timothyw
+// changed to client/server model for perf tests
+//
+// *********************************
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+
+#include <windows.h>
+//#include <ndis.h>
+#include <ntddndis.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tpctl.h"
+#include "parse.h"
+
+BOOL Verbose = TRUE;
+
+BOOL CommandsFromScript = FALSE;
+
+BOOL CommandLineLogging = FALSE;
+
+BOOL RecordToScript = FALSE;
+
+HANDLE CommandLineLogHandle;
+
+HANDLE ScriptRecordHandle;
+
+BOOL ExitFlag = FALSE;
+
+SCRIPTCONTROL Scripts[TPCTL_MAX_SCRIPT_LEVELS+1];
+
+DWORD ScriptIndex;
+
+CHAR RecordScriptName[TPCTL_MAX_PATHNAME_SIZE];
+
+OPEN_BLOCK Open[NUM_OPEN_INSTANCES];
+
+CMD_ARGS GlobalCmdArgs;
+
+LPSTR GlobalBuf = NULL;
+
+BOOL ContinueLooping = TRUE;
+
+BOOL WriteThrough = TRUE;
+
+BOOL ContinueOnError = FALSE;
+
+INT TpctlSeed = 0;
+
+//
+// the MAIN routine
+//
+
+
+VOID _cdecl
+main(
+ IN WORD argc,
+ IN LPSTR argv[]
+ )
+
+// ---------
+//
+// Routine Description:
+//
+// This routine initializes the TPCTL control structures, opens the
+// TPDRVR driver, and send it a wakeup ioctl. Once this has completed
+// the user is presented with the test prompt to enter commands,
+// or if a script file was entered at the command line, it is opened,
+// and the commands are read from the file.
+//
+// Arguments:
+//
+// IN WORD argc - Supplies the number of parameters
+// IN LPSTR argv[] - Supplies the parameter list.
+//
+// Return Value:
+//
+// None.
+//
+// ----------
+
+{
+ HANDLE TpdrvrHandle;
+ DWORD Status;
+
+
+ //
+ // Adding this for version control recognition
+ //
+ printf( "\nMAC NDIS 3.0 Tester - Test Control Tool Version 1.5.3\n\n" );
+
+
+ //
+ // First we will disable Ctrl-C by installing a handler.
+ //
+
+ if ( !SetConsoleCtrlHandler( TpctlCtrlCHandler,TRUE ))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: failed to install Ctrl-C handler, returned 0x%lx.\n",
+ (PVOID)Status);
+ ExitProcess(Status);
+ }
+
+ //
+ // Initialize the Scripts control structure before we check to
+ // see if there are any scripts on the command line to be read.
+ //
+
+ TpctlInitializeScripts();
+
+ //
+ // Initialize the script-accessible global variables
+ //
+
+ TpctlInitGlobalVariables();
+
+ //
+ // Check the command line parameters, and if there is a script file
+ // and log file open each.
+ //
+
+ Status = TpctlParseCommandLine( argc,argv );
+
+ if ( Status != NO_ERROR )
+ {
+ ExitProcess((DWORD)Status);
+ }
+
+ //
+ // Initialize the Open Block Structure and Environment Variables.
+ //
+
+ Status = TpctlInitializeOpenArray();
+
+ if ( Status != NO_ERROR )
+ {
+ TpctlFreeOpenArray();
+ TpctlCloseScripts();
+ ExitProcess((DWORD)Status);
+ }
+
+ //
+ // Open the first instance of the Test Protocol driver.
+ //
+
+ Status = TpctlOpenTpdrvr( &TpdrvrHandle );
+
+ if ( Status != NO_ERROR )
+ {
+ TpctlFreeOpenArray();
+ TpctlCloseScripts();
+ ExitProcess((DWORD)Status);
+ }
+
+ //
+ // Start the actual tests, TpctlRunTest prompts for the commands or
+ // reads the script files and then drives the tests.
+ //
+
+ Status = TpctlRunTest( TpdrvrHandle );
+
+ if ( Status != NO_ERROR )
+ {
+ TpctlCloseTpdrvr( TpdrvrHandle );
+ TpctlFreeOpenArray();
+ TpctlCloseScripts();
+ ExitProcess((DWORD)Status);
+ }
+
+ //
+ // Close the Test Protocol driver, and free the Open Array data structs.
+ //
+
+ TpctlCloseTpdrvr( TpdrvrHandle );
+
+ TpctlFreeOpenArray();
+
+ TpctlCloseScripts();
+
+ if ( !SetConsoleCtrlHandler( TpctlCtrlCHandler,FALSE ))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: failed to remove Ctrl-C handler, returned 0x%lx.\n",
+ (PVOID)Status);
+ ExitProcess(Status);
+ }
+
+ ExitProcess((DWORD)NO_ERROR);
+}
+
+
+DWORD
+TpctlInitializeOpenArray(
+ VOID
+ )
+
+// ----------------
+//
+// Routine Description:
+//
+//
+// Arguments:
+//
+//
+// Return Value:
+//
+// ---------------
+
+{
+ DWORD Status;
+ DWORD i;
+
+ ZeroMemory( Open,NUM_OPEN_INSTANCES * sizeof( OPEN_BLOCK ));
+
+ for ( i=0;i<NUM_OPEN_INSTANCES;i++ )
+ {
+ Open[i].Signature = OPEN_BLOCK_SIGNATURE;
+ Open[i].OpenInstance = 0xFF;
+ Open[i].AdapterOpened = FALSE;
+
+ Open[i].MediumType = 0;
+ Open[i].NdisVersion = 0;
+
+ Open[i].AdapterName = GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT,
+ MAX_ADAPTER_NAME_LENGTH );
+
+ if ( Open[i].AdapterName == NULL )
+ {
+ Status = GetLastError();
+ TpctlErrorLog(
+ "\n\tTpctlInitializeOpenArray: failed to alloc Adapter Name, returned 0x%lx.\n",
+ (PVOID)Status);
+ return Status;
+ }
+
+ Open[i].AdapterName[0] = '\0';
+ Open[i].LookaheadSize = 0;
+ Open[i].PacketFilter = NDIS_PACKET_TYPE_NONE;
+ Open[i].MulticastAddresses = NULL;
+ Open[i].NumberMultAddrs = 0;
+
+ Open[i].EnvVars = GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT,
+ sizeof( ENVIRONMENT_VARIABLES ) );
+
+ if ( Open[i].EnvVars == NULL )
+ {
+ Status = GetLastError();
+ TpctlErrorLog(
+ "\n\tTpctlInitializeOpenArray: failed to alloc EnvVars structure, returned 0x%lx.\n",
+ (PVOID)Status);
+ return Status;
+ }
+
+ Open[i].EnvVars->WindowSize = WINDOW_SIZE;
+ Open[i].EnvVars->RandomBufferNumber = BUFFER_NUMBER;
+ Open[i].EnvVars->StressDelayInterval = DELAY_INTERVAL;
+ Open[i].EnvVars->UpForAirDelay = UP_FOR_AIR_DELAY;
+ Open[i].EnvVars->StandardDelay = STANDARD_DELAY;
+
+ strcpy( Open[i].EnvVars->StressAddress,STRESS_MULTICAST );
+ strcpy( Open[i].EnvVars->ResendAddress,NULL_ADDRESS );
+
+ Open[i].EventThreadStarted = FALSE;
+ Open[i].Events[TPCONTROL] = CreateEvent( NULL,FALSE,FALSE,NULL );
+ Open[i].Events[TPSTRESS] = CreateEvent( NULL,FALSE,FALSE,NULL );
+ Open[i].Events[TPSEND] = CreateEvent( NULL,FALSE,FALSE,NULL );
+ Open[i].Events[TPRECEIVE] = CreateEvent( NULL,FALSE,FALSE,NULL );
+ Open[i].Events[TPPERF] = CreateEvent( NULL,FALSE,FALSE,NULL );
+
+ Open[i].Stressing = FALSE;
+ Open[i].StressEvent = CreateEvent( NULL,FALSE,FALSE,NULL );
+ Open[i].StressResultsCompleted = FALSE;
+ Open[i].StressClient = FALSE;
+
+ Open[i].StressResults = GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
+ sizeof( STRESS_RESULTS ) );
+
+ if ( Open[i].StressResults == NULL )
+ {
+ Status = GetLastError();
+ TpctlErrorLog(
+ "\n\tTpctlInitializeOpenArray: failed to alloc Stress Results structure, returned 0x%lx.\n",
+ (PVOID)Status);
+ return Status;
+ }
+
+ Open[i].StressArgs = GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT,
+ sizeof( CMD_ARGS ) );
+
+ if ( Open[i].StressArgs == NULL )
+ {
+ Status = GetLastError();
+ TpctlErrorLog(
+ "\n\tTpctlInitializeOpenArray: failed to alloc Stress Args structure, returned 0x%lx.\n",
+ (PVOID)Status);
+ return Status;
+ }
+
+ Open[i].Sending = FALSE;
+ Open[i].SendEvent = CreateEvent( NULL,FALSE,FALSE,NULL );
+ Open[i].SendResultsCompleted = FALSE;
+
+ Open[i].SendResults = GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT,
+ sizeof( SEND_RECEIVE_RESULTS ) );
+
+ if ( Open[i].SendResults == NULL )
+ {
+ Status = GetLastError();
+ TpctlErrorLog(
+ "\n\tTpctlInitializeOpenArray: failed to alloc Send Results structure, returned 0x%lx.\n",
+ (PVOID)Status);
+ return Status;
+ }
+
+ Open[i].SendArgs = GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT,
+ sizeof( CMD_ARGS ) );
+
+ if ( Open[i].SendArgs == NULL )
+ {
+ Status = GetLastError();
+ TpctlErrorLog(
+ "\n\tTpctlInitializeOpenArray: failed to alloc Send Args structure, returned 0x%lx.\n",
+ (PVOID)Status);
+ return Status;
+ }
+
+ Open[i].Receiving = FALSE;
+ Open[i].ReceiveEvent = CreateEvent( NULL,FALSE,FALSE,NULL );
+ Open[i].ReceiveResultsCompleted = FALSE;
+
+ Open[i].ReceiveResults = GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT,
+ sizeof( SEND_RECEIVE_RESULTS ) );
+
+ if ( Open[i].ReceiveResults == NULL )
+ {
+ Status = GetLastError();
+ TpctlErrorLog(
+ "\n\tTpctlInitializeOpenArray: failed to alloc Receive Results structure, returned 0x%lx.\n",
+ (PVOID)Status);
+ return Status;
+ }
+
+ Open[i].PerfEvent = CreateEvent( NULL, FALSE, FALSE, NULL);
+ Open[i].PerfResultsCompleted = FALSE;
+ Open[i].PerfResults = GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT,
+ sizeof (PERF_RESULTS) );
+
+ if ( Open[i].PerfResults == NULL )
+ {
+ Status = GetLastError();
+ TpctlErrorLog(
+ "\n\tTpctlInitializeOpenArray: failed to alloc Perf Results structure, returned 0x%lx.\n",
+ (PVOID)Status);
+ return Status;
+ }
+
+ Status = TpctlStartEventHandlerThread( &Open[i] );
+
+ if ( Status != NO_ERROR )
+ {
+ TpctlErrorLog(
+ "\n\tTpctlInitializeOpenArray: failed to start EventHandler thread, returned 0x%lx.\n",
+ (PVOID)Status);
+ return Status;
+ }
+ else
+ {
+ Open[i].EventThreadStarted = TRUE;
+ }
+ }
+
+ GlobalBuf = GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
+ 0x1000 + ( MAX_SERVERS * 0x400 ) );
+
+ if ( GlobalBuf == NULL )
+ {
+ Status = GetLastError();
+ TpctlErrorLog(
+ "\n\tTpctlInitializeOpenArray: failed to alloc Global Statistics buffer, returned 0x%lx.\n",
+ (PVOID)Status);
+ return Status;
+ }
+
+ return NO_ERROR;
+}
+
+
+DWORD
+TpctlResetOpenState(
+ IN POPEN_BLOCK Open,
+ IN HANDLE FileHandle
+ )
+
+// -------------
+//
+// Routine Description:
+//
+// This routine reset the state of an open to its initial state.
+//
+// Arguments:
+//
+// IN POPEN_BLOCK Open - the open block to reset to it initial state.
+// IN HANDLE FileHandle - the handle to the driver to close the open
+// iff already opened.
+//
+// Return Value:
+//
+// DWORD - NO_ERROR if the adapter was closed successfully or was never
+// opened. Otherwise, the result of the close if it fails.
+//
+// -----------
+
+{
+ DWORD Status = NO_ERROR;
+ PMULT_ADDR MultAddr = NULL;
+ PMULT_ADDR NextMultAddr = NULL;
+
+ //
+ // If the adapter is closed attempt to close it, and then
+ // set the opened flag to FALSE.
+ //
+
+ if ( Open->AdapterOpened == TRUE )
+ {
+ HANDLE Event;
+ IO_STATUS_BLOCK IoStatusBlock;
+ PBYTE InputBuffer[0x100];
+ DWORD InputBufferSize = 0x100;
+ PBYTE OutputBuffer[0x100];
+ DWORD OutputBufferSize = 0x100;
+ PCMD_ARGS CmdArgs;
+
+ Event = CreateEvent( NULL,FALSE,FALSE,NULL );
+
+ if (Event == NULL)
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tCreateEvent failed: returned 0x%lx.\n",(PVOID)Status);
+ }
+
+ CmdArgs = (PCMD_ARGS)InputBuffer;
+
+ CmdArgs->CmdCode = CLOSE;
+ CmdArgs->OpenInstance = Open->OpenInstance + 1;
+
+// !!NOT WIN32!!
+
+ Status = NtDeviceIoControlFile( FileHandle,
+ Event,
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock,
+ TP_CONTROL_CODE( CLOSE,IOCTL_METHOD ),
+ InputBuffer,
+ InputBufferSize,
+ OutputBuffer,
+ OutputBufferSize );
+
+ if (( Status != STATUS_SUCCESS ) && ( Status != STATUS_PENDING ))
+ {
+ TpctlErrorLog("\n\tTpctl: NtDeviceIoControlFile failed: returned 0x%lx.\n",
+ (PVOID)Status);
+ ExitFlag = TRUE;
+
+ }
+ else
+ {
+ if (( Status == STATUS_PENDING ) && ( Event != NULL ))
+ {
+ //
+ // If the ioctl pended, then wait for it to complete.
+ //
+
+ Status = WaitForSingleObject( Event,60000 ); // ONE_MINUTE
+
+ if ( Status == WAIT_TIMEOUT )
+ {
+ //
+ // The wait timed out, this probable means there
+ // was a failure in the MAC not completing the
+ // close.
+ //
+
+ TpctlErrorLog(
+ "\n\tTpctl: WARNING - WaitForSingleObject unexpectedly timed out.\n",NULL);
+ TpctlErrorLog(
+ "\t IRP was never completed in protocol driver.\n",NULL);
+ }
+ else if ( Status != NO_ERROR )
+ {
+ //
+ // If the wait for single object failed, then exit
+ // the test app with the error.
+ //
+
+ TpctlErrorLog(
+ "\n\tTpctl: ERROR - WaitForSingleObject failed: returned 0x%lx.\n",
+ (PVOID)Status);
+ ExitFlag = TRUE;
+ }
+ else if ( IoStatusBlock.Status != STATUS_SUCCESS )
+ {
+ //
+ // else if the pending ioctl returned failure again
+ // exit the test app with the error.
+ //
+
+ TpctlErrorLog("\n\tTpctl: NtDeviceIoControlFile pended.\n",NULL);
+ TpctlErrorLog("\n\t NtDeviceIoControlFile failed: returned 0x%lx.\n",
+ (PVOID)IoStatusBlock.Status);
+ ExitFlag = TRUE;
+ Status = IoStatusBlock.Status;
+ }
+ }
+ }
+
+ Open->AdapterOpened = FALSE;
+ }
+
+ //
+ // Then reset the various card and test specific flags to their
+ // original state.
+ //
+
+ Open->OpenInstance = 0xFF;
+ Open->MediumType = 0;
+ Open->NdisVersion = 0;
+
+ Open->AdapterName = NULL;
+ Open->LookaheadSize = 0;
+ Open->PacketFilter = NDIS_PACKET_TYPE_NONE;
+ Open->MulticastAddresses = NULL;
+ Open->NumberMultAddrs = 0;
+
+ // Environment variables.
+
+ Open->EnvVars->WindowSize = WINDOW_SIZE;
+ Open->EnvVars->RandomBufferNumber = BUFFER_NUMBER;
+ Open->EnvVars->StressDelayInterval = DELAY_INTERVAL;
+ Open->EnvVars->UpForAirDelay = UP_FOR_AIR_DELAY;
+ Open->EnvVars->StandardDelay = STANDARD_DELAY;
+
+ strcpy( Open->EnvVars->StressAddress,STRESS_MULTICAST );
+ strcpy( Open->EnvVars->ResendAddress,NULL_ADDRESS );
+
+ // Stress test flags.
+
+ Open->Stressing = FALSE;
+ Open->StressResultsCompleted = FALSE;
+ Open->StressClient = FALSE;
+
+ // Send test flags.
+
+ Open->Sending = FALSE;
+ Open->SendResultsCompleted = FALSE;
+
+ // Receive test flags.
+
+ Open->Receiving = FALSE;
+ Open->ReceiveResultsCompleted = FALSE;
+
+ // performance test flags
+
+ Open->PerfResultsCompleted = FALSE;
+
+ // Card state variables and structures.
+
+ MultAddr = Open->MulticastAddresses;
+
+ while ( MultAddr != NULL )
+ {
+ NextMultAddr = MultAddr->Next;
+ GlobalFree( MultAddr );
+ MultAddr = NextMultAddr;
+ }
+
+ Open->MulticastAddresses = NULL;
+ Open->NumberMultAddrs = 0;
+
+ ZeroMemory(Open->FunctionalAddress, FUNCTIONAL_ADDRESS_LENGTH);
+ ZeroMemory(Open->GroupAddress, FUNCTIONAL_ADDRESS_LENGTH);
+
+ return Status;
+}
+
+
+
+VOID
+TpctlFreeOpenArray(
+ VOID
+ )
+
+// -------------
+//
+// Routine Description:
+//
+//
+// Arguments:
+//
+//
+// Return Value:
+//
+// ---------------
+
+{
+ DWORD i;
+
+ for ( i=0;i<NUM_OPEN_INSTANCES;i++ )
+ {
+ //
+ // First free up all of the allocated data structs,
+ //
+
+ if ( Open[i].AdapterName != NULL )
+ {
+ GlobalFree( Open[i].AdapterName );
+ }
+
+ if ( Open[i].EnvVars != NULL )
+ {
+ GlobalFree( Open[i].EnvVars );
+ }
+
+ if ( Open[i].StressResults != NULL )
+ {
+ GlobalFree( Open[i].StressResults );
+ }
+
+ if ( Open[i].StressArgs != NULL )
+ {
+ GlobalFree( Open[i].StressArgs );
+ }
+
+ if ( Open[i].SendResults != NULL )
+ {
+ GlobalFree( Open[i].SendResults );
+ }
+
+ if ( Open[i].StressArgs != NULL )
+ {
+ GlobalFree( Open[i].SendArgs );
+ }
+
+ if ( Open[i].ReceiveResults != NULL )
+ {
+ GlobalFree( Open[i].ReceiveResults );
+ }
+
+ if ( Open[i].PerfResults != NULL )
+ {
+ GlobalFree( Open[i].PerfResults );
+ }
+
+ //
+ // Then stop the EventHandler thread,
+ //
+
+ TpctlStopEventHandlerThread( &Open[i] );
+
+ //
+ // And finally close all of the event handles.
+ //
+
+ if ( Open[i].Events[TPCONTROL] != NULL )
+ {
+ CloseHandle( Open[i].Events[TPCONTROL] );
+ }
+
+ if ( Open[i].Events[TPCONTROL] != NULL )
+ {
+ CloseHandle( Open[i].Events[TPSTRESS] );
+ }
+
+ if ( Open[i].Events[TPSEND] != NULL )
+ {
+ CloseHandle( Open[i].Events[TPSEND] );
+ }
+
+ if ( Open[i].Events[TPRECEIVE] != NULL )
+ {
+ CloseHandle( Open[i].Events[TPRECEIVE] );
+ }
+
+ if ( Open[i].Events[TPPERF] != NULL )
+ {
+ CloseHandle( Open[i].Events[TPPERF] );
+ }
+
+ if ( Open[i].StressEvent != NULL )
+ {
+ CloseHandle( Open[i].StressEvent );
+ }
+
+ if ( Open[i].SendEvent != NULL )
+ {
+ CloseHandle( Open[i].SendEvent );
+ }
+
+ if ( Open[i].ReceiveEvent != NULL )
+ {
+ CloseHandle( Open[i].ReceiveEvent );
+ }
+
+ if ( Open[i].PerfEvent != NULL )
+ {
+ CloseHandle( Open[i].PerfEvent );
+ }
+ }
+
+ GlobalFree( GlobalBuf );
+}
+
+
+DWORD
+TpctlOpenTpdrvr(
+ IN OUT PHANDLE lphFileHandle
+ )
+
+// -------------
+//
+// Routine Description:
+//
+// This routine calls CreateFile to open the TPDRVR.SYS device driver.
+//
+// Arguments:
+//
+// lphFileHandle - the file handle of the file to be opened.
+//
+// Return Value:
+//
+// lphFileHandle contains a positive value if successful, -1 if not.
+//
+// -------------
+
+{
+ DWORD Status = NO_ERROR;
+
+ *lphFileHandle = CreateFile(DEVICE_NAME,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, // lpSecurityAttirbutes
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+ NULL); // lpTemplateFile
+
+ if ( *lphFileHandle == (HANDLE)-1 )
+ {
+ Status = GetLastError();
+ if ( Status == STATUS_DEVICE_ALREADY_ATTACHED )
+ {
+ TpctlErrorLog("\n\tTpctl: Tpdrvr.sys already opened by another instance of\n",NULL);
+ TpctlErrorLog("\t the control application. Only one open allowed.\n",NULL);
+ }
+ else
+ {
+ TpctlErrorLog("\n\tTpctlOpenTpdrvr: CreateFile failed: returned 0x%lx.\n",
+ (PVOID)Status);
+ }
+ }
+
+ return Status;
+}
+
+
+
+VOID
+TpctlCloseTpdrvr(
+ IN HANDLE hFileHandle
+ )
+
+// ----------------
+//
+// Routine Description:
+//
+// This routine calls CloseHandle to close the first instance of the
+// TPDRVR.EXE driver.
+//
+// Arguments:
+//
+// hFileHandle - the file handle returned from the call to OpenFile.
+//
+// Return Value:
+//
+// STATUS - the status of the CloseHandle call.
+//
+// -----------------
+
+{
+ DWORD Status;
+
+ if ( !CloseHandle( hFileHandle ))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctlCloseTpdrvr: CloseHandle failed: returned 0x%lx.\n",
+ (PVOID)Status);
+ }
+
+ return;
+}
+
+
+
+DWORD
+TpctlStartEventHandlerThread(
+ POPEN_BLOCK Open
+ )
+
+// -----------
+//
+// Routine Description:
+//
+//
+// Arguments:
+//
+//
+// Return Value:
+//
+// --------------
+
+{
+ DWORD Status = NO_ERROR;
+ DWORD StackSize = 0x1000;
+ DWORD ThreadId;
+ HANDLE EventThread;
+
+
+ EventThread = CreateThread( NULL,
+ StackSize,
+ TpctlEventHandler,
+ (LPVOID)Open,
+ 0,
+ &ThreadId );
+
+ if ( EventThread == NULL )
+ {
+ Status = GetLastError();
+ TpctlErrorLog("TpctlStartEventHandlerThread: CreateThread failed; returned 0x%lx.\n",
+ (PVOID)Status);
+ }
+ else
+ {
+ //
+ // the CreateT succeeded, we don't need the handle so close it.
+ //
+
+ if ( !CloseHandle( EventThread ) )
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctlStartEventHandlerThread: CloseHandle failed; returned 0x%lx\n",
+ (PVOID)Status);
+ }
+ }
+
+ return Status;
+}
+
+
+
+DWORD
+TpctlEventHandler(
+ LPVOID Open
+ )
+
+// --------------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// ----------
+
+{
+ BOOL Continue = TRUE;
+ DWORD EventNumber;
+ DWORD Status;
+
+ while ( Continue == TRUE )
+ {
+ EventNumber = WaitForMultipleObjects( 5,
+ (LPHANDLE)((POPEN_BLOCK)Open)->Events,
+ FALSE,
+ INFINITE );
+
+ switch ( EventNumber )
+ {
+ case TPCONTROL: // ResetWaitEvent;
+ Continue = FALSE;
+ break;
+
+ case TPSTRESS: // StressEvent
+ //
+ // Set the Stressing flag to false to indicate that we have
+ // finished the STRESS test, and the ResultsCompleted flag to
+ // true to indicate that the results are ready to be displayed.
+ //
+
+ ((POPEN_BLOCK)Open)->Stressing = FALSE;
+
+ if (((POPEN_BLOCK)Open)->StressClient == TRUE )
+ {
+ ((POPEN_BLOCK)Open)->StressResultsCompleted = TRUE;
+ }
+
+ //
+ // And then signal the app that we have finished.
+ //
+
+ if (!SetEvent(((POPEN_BLOCK)Open)->StressEvent))
+ {
+ Status = GetLastError();
+ OutputDebugString("TpctlEventHandler: failed to signal Stress Event 0x%lx.\n");
+ }
+ break;
+
+ case TPSEND: // SendEvent
+ //
+ // Set the Sending flag to false to indicate that we have
+ // finished the SEND test, and the ResultsCompleted flag to
+ // true to indicate that the results are ready to be displayed.
+ //
+
+ ((POPEN_BLOCK)Open)->Sending = FALSE;
+ ((POPEN_BLOCK)Open)->SendResultsCompleted = TRUE;
+
+ //
+ // And then signal the app that we have finished.
+ //
+
+ if (!SetEvent( ((POPEN_BLOCK)Open)->SendEvent ))
+ {
+ Status = GetLastError();
+ OutputDebugString("TpctlEventHandler: failed to signal Send Event 0x%lx.\n");
+ }
+ break;
+
+ case TPRECEIVE: // ReceiveEvent
+ //
+ // Set the Receiving flag to false to indicate that we have
+ // finished the RECEIVE test, and the ResultsCompleted flag to
+ // true to indicate that the results are ready to be displayed.
+ //
+
+ ((POPEN_BLOCK)Open)->Receiving = FALSE;
+ ((POPEN_BLOCK)Open)->ReceiveResultsCompleted = TRUE;
+
+ //
+ // And then signal the app that we have finished.
+ //
+
+ if (!SetEvent( ((POPEN_BLOCK)Open)->ReceiveEvent ))
+ {
+ Status = GetLastError();
+ OutputDebugString("TpctlEventHandler: failed to signal Receive Event.\n");
+ }
+ break;
+
+ case TPPERF: // PerfEvent
+ //
+ // Set the PerfResultsCompleted flag to
+ // true to indicate that the results are ready to be displayed.
+ //
+
+ ((POPEN_BLOCK)Open)->PerfResultsCompleted = TRUE;
+
+ //
+ // And then signal the app that we have finished.
+ //
+
+ if (!SetEvent( ((POPEN_BLOCK)Open)->PerfEvent ))
+ {
+ Status = GetLastError();
+ OutputDebugString("TpctlEventHandler: failed to signal Perf Event.\n");
+ }
+ break;
+ }
+ }
+
+ return EventNumber;
+}
+
+
+
+VOID
+TpctlStopEventHandlerThread(
+ POPEN_BLOCK Open
+ )
+
+// ----------------
+//
+// Routine Description:
+//
+//
+// Arguments:
+//
+//
+// Return Value:
+//
+// ----------------
+
+{
+ DWORD Status;
+
+ //
+ // First signal the thread to stop the Wait call.
+ //
+
+ if ( Open->EventThreadStarted == TRUE )
+ {
+ if ( !SetEvent( Open->Events[TPCONTROL] ))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctlStopEventHandlerThread: SetEvent failed; returned 0x%lx.\n",
+ (PVOID)Status);
+ }
+ }
+}
+
+
+
+BOOL
+TpctlCtrlCHandler(
+ IN DWORD CtrlType
+ )
+
+// --------------
+//
+// Routine Description:
+//
+// This routine catches any instances of Ctrl-C and sets the
+// ContinueLooping flag to FALSE. WaitStress, WaitSend, GetEvents,
+// Pause and Go, and parsing of script file commands will halt
+// when this flag is set to true.
+//
+// Arguments:
+//
+// DWORD CtrlType - the event passed in by the system.
+//
+// Return Value:
+//
+// BOOL - TRUE if this event should be ignored by the system, FALSE
+// otherwise.
+//
+// --------------
+
+
+{
+ if ( CtrlType == CTRL_BREAK_EVENT )
+ {
+ return FALSE;
+ }
+ else if ( CtrlType == CTRL_C_EVENT )
+ {
+ if ( ContinueLooping == TRUE )
+ {
+ ContinueLooping = FALSE;
+ }
+ }
+ return TRUE;
+}
+
+
diff --git a/private/ntos/ndis/testprot/tpctl/makefile b/private/ntos/ndis/testprot/tpctl/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpctl/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/testprot/tpctl/parse.c b/private/ntos/ndis/testprot/tpctl/parse.c
new file mode 100644
index 000000000..613e10473
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpctl/parse.c
@@ -0,0 +1,2526 @@
+// ******************************************************************
+//
+// Copyright (c) 1991 Microsoft Corporation
+//
+// Module Name:
+//
+// parse.c
+//
+// Abstract:
+//
+// This module contains the routines for parsing commands entered from
+// the command line or read from script files.
+//
+// Author:
+//
+// Tom Adams (tomad) 11-May-1991
+//
+// Revision History:
+//
+//
+// Sanjeev Katariya (sanjeevk)
+// 4-12-1993 Added ARCNET support
+// 4-15-1993 Added additional OIDS
+// 7-01-1993 Added suppport for recoring sessions and spawning
+// command shells within tpctl
+// Tim Wynsma (timothyw)
+// 4-27-94 added performance testing
+// 5-16-94 added globvars hooks; cleanup
+// 6-08-94 chgd to client/server model for perf test
+//
+// ******************************************************************
+
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+
+#include <windows.h>
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "tpctl.h"
+#include "parse.h"
+
+
+VOID
+TpctlFixBuffer(
+ IN BYTE Buffer[]
+ );
+
+
+DWORD
+TpctlParseInteger(
+ IN BYTE Buffer[],
+ IN PARSETABLE ParseTable[],
+ IN DWORD ParseTableSize,
+ OUT PDWORD Ret
+ );
+
+
+BOOL
+TpctlParseArgumentPairs(
+ IN LPSTR Argument,
+ OUT LPSTR *ArgName,
+ OUT LPSTR *ArgValue
+ );
+
+
+BOOL
+TpctlParseSetInfoArguments(
+ IN OUT DWORD *ArgC,
+ IN OUT LPSTR ArgV[],
+ IN OUT DWORD *tmpArgC,
+ IN OUT LPSTR tmpArgV[]
+ );
+
+
+BOOL
+TpctlParseEnvironmentVariable(
+ IN BYTE Buffer[]
+ );
+
+
+BOOL
+TpctlFirstChar(
+ IN BYTE Buffer[],
+ IN BYTE Char
+ );
+
+
+DWORD
+TpctlGetOptionNumber(
+ IN PTESTPARAMS Options,
+ IN DWORD TestSize,
+ IN LPSTR ArgName
+ );
+
+
+DWORD
+TpctlGetOpenInstance(
+ IN DWORD ArgC,
+ IN LPSTR ArgV[]
+ );
+
+
+
+PARSETABLE
+BooleanTable[] = {
+ NamedField( TRUE ),
+ NamedField( FALSE ),
+ { "T", TRUE },
+ { "F", FALSE }
+};
+
+
+
+PARSETABLE
+PacketFilterTable [] = {
+ NamedField( NDIS_PACKET_TYPE_DIRECTED ),
+ NamedField( NDIS_PACKET_TYPE_MULTICAST ),
+ NamedField( NDIS_PACKET_TYPE_ALL_MULTICAST ),
+ NamedField( NDIS_PACKET_TYPE_BROADCAST ),
+ NamedField( NDIS_PACKET_TYPE_SOURCE_ROUTING ),
+ NamedField( NDIS_PACKET_TYPE_PROMISCUOUS ),
+ NamedField( NDIS_PACKET_TYPE_MAC_FRAME ),
+ NamedField( NDIS_PACKET_TYPE_GROUP ),
+ NamedField( NDIS_PACKET_TYPE_FUNCTIONAL ),
+ NamedField( NDIS_PACKET_TYPE_ALL_FUNCTIONAL ),
+ NamedField( NDIS_PACKET_TYPE_NONE ),
+
+ { "Directed", NDIS_PACKET_TYPE_DIRECTED },
+ { "Multicast", NDIS_PACKET_TYPE_MULTICAST },
+ { "AllMulticast", NDIS_PACKET_TYPE_ALL_MULTICAST },
+ { "Broadcast", NDIS_PACKET_TYPE_BROADCAST },
+ { "SourceRouting", NDIS_PACKET_TYPE_SOURCE_ROUTING },
+ { "Promiscuous", NDIS_PACKET_TYPE_PROMISCUOUS },
+ { "MacFrame", NDIS_PACKET_TYPE_MAC_FRAME },
+ { "Group", NDIS_PACKET_TYPE_GROUP },
+ { "Functional", NDIS_PACKET_TYPE_FUNCTIONAL },
+ { "AllFunctional", NDIS_PACKET_TYPE_ALL_FUNCTIONAL },
+ { "None", NDIS_PACKET_TYPE_NONE }
+};
+
+
+PARSETABLE
+QueryInfoOidTable [] = {
+
+ //
+ // General Objects
+ //
+
+ NamedField( OID_GEN_SUPPORTED_LIST ),
+ NamedField( OID_GEN_HARDWARE_STATUS ),
+ NamedField( OID_GEN_MEDIA_SUPPORTED ),
+ NamedField( OID_GEN_MEDIA_IN_USE ),
+ NamedField( OID_GEN_MAXIMUM_LOOKAHEAD ),
+ NamedField( OID_GEN_MAXIMUM_FRAME_SIZE ),
+ NamedField( OID_GEN_LINK_SPEED ),
+ NamedField( OID_GEN_TRANSMIT_BUFFER_SPACE ),
+ NamedField( OID_GEN_RECEIVE_BUFFER_SPACE ),
+ NamedField( OID_GEN_TRANSMIT_BLOCK_SIZE ),
+ NamedField( OID_GEN_RECEIVE_BLOCK_SIZE ),
+ NamedField( OID_GEN_VENDOR_ID ),
+ NamedField( OID_GEN_VENDOR_DESCRIPTION ),
+ NamedField( OID_GEN_CURRENT_PACKET_FILTER ),
+ NamedField( OID_GEN_CURRENT_LOOKAHEAD ),
+ NamedField( OID_GEN_DRIVER_VERSION ),
+ NamedField( OID_GEN_MAXIMUM_TOTAL_SIZE ),
+ NamedField( OID_GEN_PROTOCOL_OPTIONS ),
+ NamedField( OID_GEN_MAC_OPTIONS ),
+
+ NamedField( OID_GEN_XMIT_OK ),
+ NamedField( OID_GEN_RCV_OK ),
+ NamedField( OID_GEN_XMIT_ERROR ),
+ NamedField( OID_GEN_RCV_ERROR ),
+ NamedField( OID_GEN_RCV_NO_BUFFER ),
+
+ NamedField( OID_GEN_DIRECTED_BYTES_XMIT ),
+ NamedField( OID_GEN_DIRECTED_FRAMES_XMIT ),
+ NamedField( OID_GEN_MULTICAST_BYTES_XMIT ),
+ NamedField( OID_GEN_MULTICAST_FRAMES_XMIT ),
+ NamedField( OID_GEN_BROADCAST_BYTES_XMIT ),
+ NamedField( OID_GEN_BROADCAST_FRAMES_XMIT ),
+ NamedField( OID_GEN_DIRECTED_BYTES_RCV ),
+ NamedField( OID_GEN_DIRECTED_FRAMES_RCV ),
+ NamedField( OID_GEN_MULTICAST_BYTES_RCV ),
+ NamedField( OID_GEN_MULTICAST_FRAMES_RCV ),
+ NamedField( OID_GEN_BROADCAST_BYTES_RCV ),
+ NamedField( OID_GEN_BROADCAST_FRAMES_RCV ),
+
+ NamedField( OID_GEN_RCV_CRC_ERROR ),
+ NamedField( OID_GEN_TRANSMIT_QUEUE_LENGTH ),
+
+ //
+ // 802.3 Objects
+ //
+
+ NamedField( OID_802_3_PERMANENT_ADDRESS ),
+ NamedField( OID_802_3_CURRENT_ADDRESS ),
+ NamedField( OID_802_3_MULTICAST_LIST ),
+ NamedField( OID_802_3_MAXIMUM_LIST_SIZE ),
+
+ NamedField( OID_802_3_RCV_ERROR_ALIGNMENT ),
+ NamedField( OID_802_3_XMIT_ONE_COLLISION ),
+ NamedField( OID_802_3_XMIT_MORE_COLLISIONS ),
+
+ NamedField( OID_802_3_XMIT_DEFERRED ),
+ NamedField( OID_802_3_XMIT_MAX_COLLISIONS ),
+ NamedField( OID_802_3_RCV_OVERRUN ),
+ NamedField( OID_802_3_XMIT_UNDERRUN ),
+ NamedField( OID_802_3_XMIT_HEARTBEAT_FAILURE ),
+ NamedField( OID_802_3_XMIT_TIMES_CRS_LOST ),
+ NamedField( OID_802_3_XMIT_LATE_COLLISIONS ),
+
+ //
+ // 802.5 Objects
+ //
+
+ NamedField( OID_802_5_PERMANENT_ADDRESS ),
+ NamedField( OID_802_5_CURRENT_ADDRESS ),
+ NamedField( OID_802_5_CURRENT_FUNCTIONAL ),
+ NamedField( OID_802_5_CURRENT_GROUP ),
+ NamedField( OID_802_5_LAST_OPEN_STATUS ),
+ NamedField( OID_802_5_CURRENT_RING_STATUS ),
+ NamedField( OID_802_5_CURRENT_RING_STATE ),
+
+ NamedField( OID_802_5_LINE_ERRORS ),
+ NamedField( OID_802_5_LOST_FRAMES ),
+
+ NamedField( OID_802_5_BURST_ERRORS ),
+ NamedField( OID_802_5_AC_ERRORS ),
+ NamedField( OID_802_5_ABORT_DELIMETERS ),
+ NamedField( OID_802_5_FRAME_COPIED_ERRORS ),
+ NamedField( OID_802_5_FREQUENCY_ERRORS ),
+ NamedField( OID_802_5_TOKEN_ERRORS ),
+ NamedField( OID_802_5_INTERNAL_ERRORS ),
+
+ //
+ // Fddi objects
+ //
+
+ NamedField( OID_FDDI_LONG_PERMANENT_ADDR ),
+ NamedField( OID_FDDI_LONG_CURRENT_ADDR ),
+ NamedField( OID_FDDI_LONG_MULTICAST_LIST ),
+ NamedField( OID_FDDI_LONG_MAX_LIST_SIZE ),
+ NamedField( OID_FDDI_SHORT_PERMANENT_ADDR ),
+ NamedField( OID_FDDI_SHORT_CURRENT_ADDR ),
+ NamedField( OID_FDDI_SHORT_MULTICAST_LIST ),
+ NamedField( OID_FDDI_SHORT_MAX_LIST_SIZE ),
+
+ NamedField( OID_FDDI_ATTACHMENT_TYPE ),
+ NamedField( OID_FDDI_UPSTREAM_NODE_LONG ),
+ NamedField( OID_FDDI_DOWNSTREAM_NODE_LONG ),
+ NamedField( OID_FDDI_FRAME_ERRORS ),
+ NamedField( OID_FDDI_FRAMES_LOST ),
+ NamedField( OID_FDDI_RING_MGT_STATE ),
+ NamedField( OID_FDDI_LCT_FAILURES ),
+ NamedField( OID_FDDI_LEM_REJECTS ),
+ NamedField( OID_FDDI_LCONNECTION_STATE ),
+
+ //
+ // STARTCHANGE
+ //
+ // ARCNET objects
+ //
+ NamedField( OID_ARCNET_PERMANENT_ADDRESS ),
+ NamedField( OID_ARCNET_CURRENT_ADDRESS ),
+ NamedField( OID_ARCNET_RECONFIGURATIONS ),
+ //
+ // STOPCHANGE
+ //
+
+ //
+ // Async Objects
+ //
+
+#if 0
+
+// Not currently supported.
+
+ NamedField( OID_ASYNC_PERMANENT_ADDRESS ),
+ NamedField( OID_ASYNC_CURRENT_ADDRESS ),
+ NamedField( OID_ASYNC_QUALITY_OF_SERVICE ),
+ NamedField( OID_ASYNC_PROTOCOL_TYPE ),
+
+#endif
+
+ //
+ // LocalTalk Objects
+ //
+
+#if 0
+
+// Not currently supported.
+
+ NamedField( OID_LTALK_CURRENT_NODE_ID ),
+
+ NamedField( OID_LTALK_IN_BROADCASTS ),
+ NamedField( OID_LTALK_IN_LENGTH_ERRORS ),
+
+ NamedField( OID_LTALK_OUT_NO_HANDLERS ),
+ NamedField( OID_LTALK_COLLISIONS ),
+ NamedField( OID_LTALK_DEFERS ),
+ NamedField( OID_LTALK_NO_DATA_ERRORS ),
+ NamedField( OID_LTALK_RANDOM_CTS_ERRORS ),
+ NamedField( OID_LTALK_FCS_ERRORS ),
+
+#endif
+
+ //
+ // General Objects
+ //
+
+ { "SupportedOIDList", OID_GEN_SUPPORTED_LIST },
+ { "HardwareStatus", OID_GEN_HARDWARE_STATUS },
+ { "MediaTypeSupported", OID_GEN_MEDIA_SUPPORTED },
+ { "MediaTypeInUse", OID_GEN_MEDIA_IN_USE },
+ { "MaximumLookahead", OID_GEN_MAXIMUM_LOOKAHEAD },
+ { "MaximumFrameSize", OID_GEN_MAXIMUM_FRAME_SIZE },
+ { "LinkSpeed", OID_GEN_LINK_SPEED },
+ { "TransmitBufferSpace", OID_GEN_TRANSMIT_BUFFER_SPACE },
+ { "ReceiveBufferSpace", OID_GEN_RECEIVE_BUFFER_SPACE },
+ { "TransmitBlockSize", OID_GEN_TRANSMIT_BLOCK_SIZE },
+ { "ReceiveBlockSize", OID_GEN_RECEIVE_BLOCK_SIZE },
+ { "VendorID", OID_GEN_VENDOR_ID },
+ { "VendorDescription", OID_GEN_VENDOR_DESCRIPTION },
+ { "CurrentPacketFilter", OID_GEN_CURRENT_PACKET_FILTER },
+ { "CurrentLookahead", OID_GEN_CURRENT_LOOKAHEAD },
+ { "DriverVersion", OID_GEN_DRIVER_VERSION },
+ { "MaximumTotalSize", OID_GEN_MAXIMUM_TOTAL_SIZE },
+
+ { "TransmitGood", OID_GEN_XMIT_OK },
+ { "ReceiveGood", OID_GEN_RCV_OK },
+ { "TransmitBad", OID_GEN_XMIT_ERROR },
+ { "ReceiveBad", OID_GEN_RCV_ERROR },
+ { "ReciveNoBuffer", OID_GEN_RCV_NO_BUFFER },
+
+ { "DirectedBytesTransmits", OID_GEN_DIRECTED_BYTES_XMIT },
+ { "DirectedFramesTransmits", OID_GEN_DIRECTED_FRAMES_XMIT },
+ { "MulticastBytesTransmits", OID_GEN_MULTICAST_BYTES_XMIT },
+ { "MulticastFramesTransmits", OID_GEN_MULTICAST_FRAMES_XMIT },
+ { "BroadcastBytesTransmits", OID_GEN_BROADCAST_BYTES_XMIT },
+ { "BroadcastFramesTransmits", OID_GEN_BROADCAST_FRAMES_XMIT },
+ { "DirectedBytesReceives", OID_GEN_DIRECTED_BYTES_RCV },
+ { "DirectedFramesReceives", OID_GEN_DIRECTED_FRAMES_RCV },
+ { "MulticastBytesReceives", OID_GEN_MULTICAST_BYTES_RCV },
+ { "MulticastFramesReceives", OID_GEN_MULTICAST_FRAMES_RCV },
+ { "BroadcastBytesReceives", OID_GEN_BROADCAST_BYTES_RCV },
+ { "BroadcastFramesReceives", OID_GEN_BROADCAST_FRAMES_RCV },
+
+ { "ReceiveCRC", OID_GEN_RCV_CRC_ERROR },
+ { "TransmitQueueLength", OID_GEN_TRANSMIT_QUEUE_LENGTH },
+
+ //
+ // 802.3 Objects
+ //
+
+ { "EthPermanentAddress", OID_802_3_PERMANENT_ADDRESS },
+ { "EthCurrentAddress", OID_802_3_CURRENT_ADDRESS },
+ { "CurrentMulticastList", OID_802_3_MULTICAST_LIST },
+ { "MaxMulticastListSize", OID_802_3_MAXIMUM_LIST_SIZE },
+
+ { "ReceiveErrorAlignment", OID_802_3_RCV_ERROR_ALIGNMENT },
+ { "TransmitOneCollsion", OID_802_3_XMIT_ONE_COLLISION },
+ { "TransmitMoreCollostions", OID_802_3_XMIT_MORE_COLLISIONS },
+
+ { "TransmitDeferred", OID_802_3_XMIT_DEFERRED },
+ { "TransmitMaxCollisions", OID_802_3_XMIT_MAX_COLLISIONS },
+ { "ReceiveOverrun", OID_802_3_RCV_OVERRUN },
+ { "TransmitUnderrun", OID_802_3_XMIT_UNDERRUN },
+ { "TransmitHeartbeatFailure", OID_802_3_XMIT_HEARTBEAT_FAILURE },
+ { "TransmitTimesCRSLost", OID_802_3_XMIT_TIMES_CRS_LOST },
+ { "TransmitLateCollisions", OID_802_3_XMIT_LATE_COLLISIONS },
+
+ //
+ // 802.5 Objects
+ //
+
+ { "TRPermanentAddress", OID_802_5_PERMANENT_ADDRESS },
+ { "TRCurrentAddress", OID_802_5_CURRENT_ADDRESS },
+ { "CurrentFunctionalAddress", OID_802_5_CURRENT_FUNCTIONAL },
+ { "CurrentGroupAddress", OID_802_5_CURRENT_GROUP },
+ { "LastOpenStatus", OID_802_5_LAST_OPEN_STATUS },
+ { "CurrentRingStatus", OID_802_5_CURRENT_RING_STATUS },
+ { "CurrentRingState", OID_802_5_CURRENT_RING_STATE },
+
+ { "LineErrors", OID_802_5_LINE_ERRORS },
+ { "LostFrames", OID_802_5_LOST_FRAMES },
+
+ { "BurstErrors", OID_802_5_BURST_ERRORS },
+ { "ACErrors", OID_802_5_AC_ERRORS },
+ { "AbortDelimeters", OID_802_5_ABORT_DELIMETERS },
+ { "FrameCopiedErrors", OID_802_5_FRAME_COPIED_ERRORS },
+ { "FrequencyErrors", OID_802_5_FREQUENCY_ERRORS },
+ { "TokenErrors", OID_802_5_TOKEN_ERRORS },
+ { "InternalErrors", OID_802_5_INTERNAL_ERRORS },
+
+ //
+ // Fddi objects
+ //
+
+ { "FddiLongPermanentAddress", OID_FDDI_LONG_PERMANENT_ADDR },
+ { "FddiLongCurrentAddress", OID_FDDI_LONG_CURRENT_ADDR },
+ { "FddiLongMulticastList", OID_FDDI_LONG_MULTICAST_LIST },
+ { "FddiLongMaxListSize", OID_FDDI_LONG_MAX_LIST_SIZE },
+ { "FddiShortPermanentAddress", OID_FDDI_SHORT_PERMANENT_ADDR },
+ { "FddiShortCurrentAddress", OID_FDDI_SHORT_CURRENT_ADDR },
+ { "FddiShortMulticastList", OID_FDDI_SHORT_MULTICAST_LIST },
+ { "FddiShortMaxListSize", OID_FDDI_SHORT_MAX_LIST_SIZE },
+
+ //
+ // STARTCHANGE
+ //
+ // ARCNET objects
+ //
+ { "ArcPermanentAddress", OID_ARCNET_PERMANENT_ADDRESS },
+ { "ArcCurrentAddress", OID_ARCNET_CURRENT_ADDRESS },
+ { "ArcReconfigurations", OID_ARCNET_RECONFIGURATIONS },
+ //
+ // STOPCHANGE
+ //
+
+ //
+ // Async Objects
+ //
+
+#if 0
+
+// Not currently supported.
+
+ { "AsyncPermanentAddress", OID_ASYNC_PERMANENT_ADDRESS },
+ { "AsyncCurrentAddress", OID_ASYNC_CURRENT_ADDRESS },
+ { "AsyncQualityOfService", OID_ASYNC_QUALITY_OF_SERVICE },
+ { "AsyncProtocolType", OID_ASYNC_PROTOCOL_TYPE },
+
+#endif
+
+ //
+ // LocalTalk Objects
+ //
+
+#if 0
+
+// Not currently supported.
+
+ { "LTalkCurrentNodeId", OID_LTALK_CURRENT_NODE_ID },
+
+ { "LTalkInBroadcasts", OID_LTALK_IN_BROADCASTS },
+ { "LTalkInLengthErrors", OID_LTALK_IN_LENGTH_ERRORS },
+
+ { "LTalkOutNoHandlers", OID_LTALK_OUT_NO_HANDLERS },
+ { "LTalkCollisions", OID_LTALK_COLLISIONS },
+ { "LTalkDefers", OID_LTALK_DEFERS },
+ { "LTalkNoDataErrors", OID_LTALK_NO_DATA_ERRORS },
+ { "LTalkRandomCTSErrors", OID_LTALK_RANDOM_CTS_ERRORS },
+ { "LTalkFCSErrors", OID_LTALK_FCS_ERRORS }
+
+#endif
+
+};
+
+
+PARSETABLE
+SetInfoOidTable [] = {
+ NamedField( OID_GEN_CURRENT_PACKET_FILTER ),
+ NamedField( OID_GEN_CURRENT_LOOKAHEAD ),
+ NamedField( OID_802_3_MULTICAST_LIST ),
+ NamedField( OID_802_5_CURRENT_FUNCTIONAL ),
+ NamedField( OID_802_5_CURRENT_GROUP ),
+ NamedField( OID_FDDI_LONG_CURRENT_ADDR ),
+ NamedField( OID_FDDI_LONG_MULTICAST_LIST ),
+ NamedField( OID_FDDI_SHORT_CURRENT_ADDR ),
+ NamedField( OID_FDDI_SHORT_MULTICAST_LIST ),
+
+ //
+ // STARTCHANGE
+ //
+ NamedField( OID_ARCNET_CURRENT_ADDRESS ),
+ //
+ // STOPCHANGE
+ //
+
+ { "CurrentPacketFilter", OID_GEN_CURRENT_PACKET_FILTER },
+ { "CurrentLookAhead", OID_GEN_CURRENT_LOOKAHEAD },
+ { "CurrentMulticastList", OID_802_3_MULTICAST_LIST },
+ { "CurrentFunctionalAddress", OID_802_5_CURRENT_FUNCTIONAL },
+ { "CurrentGroupAddress", OID_802_5_CURRENT_GROUP },
+ { "FddiLongCurrentAddress", OID_FDDI_LONG_CURRENT_ADDR },
+ { "FddiLongMulticastList", OID_FDDI_LONG_MULTICAST_LIST },
+ { "FddiShortCurrentAddress", OID_FDDI_SHORT_CURRENT_ADDR },
+ { "FddiShortMulticastList", OID_FDDI_SHORT_MULTICAST_LIST },
+
+ //
+ // STARTCHANGE
+ //
+ { "ArcCurrentAddress", OID_ARCNET_CURRENT_ADDRESS }
+ //
+ // STOPCHANGE
+ //
+
+
+};
+
+
+PARSETABLE
+MemberTypeTable [] = {
+ NamedField( TP_CLIENT ),
+ NamedField( TP_SERVER ),
+ NamedField( BOTH ),
+
+ { "Client", TP_CLIENT },
+ { "Server", TP_SERVER },
+ { "Both", BOTH }
+};
+
+
+PARSETABLE
+PacketTypeTable [] = {
+ NamedField( FIXEDSIZE ),
+ NamedField( RANDOMSIZE ),
+ NamedField( CYCLICAL ),
+
+ { "Fixed", FIXEDSIZE },
+ { "Random", RANDOMSIZE },
+ { "Cyclic", CYCLICAL }
+};
+
+
+PARSETABLE
+PacketMakeUpTable [] = {
+ NamedField( RAND ),
+ NamedField( SMALL ),
+ NamedField( ZEROS ),
+ NamedField( ONES ),
+ NamedField( KNOWN ),
+
+ { "Random_MakeUp", RAND },
+ { "Small_MakeUp", SMALL },
+ { "Zeros_MakeUp", ZEROS },
+ { "Ones_MakeUp", ONES },
+ { "Known_MakeUp", KNOWN }
+};
+
+
+PARSETABLE
+ResponseTypeTable [] = {
+ NamedField( NO_RESPONSE ),
+ NamedField( FULL_RESPONSE ),
+ NamedField( ACK_EVERY ),
+ NamedField( ACK_10_TIMES ),
+
+ { "No Response", NO_RESPONSE },
+ { "Response", FULL_RESPONSE },
+ { "ACK", ACK_EVERY },
+ { "ACK10", ACK_10_TIMES }
+};
+
+
+PARSETABLE
+DelayTable [] = {
+ NamedField( FIXEDDELAY ),
+ NamedField( RANDOMDELAY ),
+
+ { "Fixed", FIXEDDELAY },
+ { "Random", RANDOMDELAY }
+};
+
+
+PARSETABLE
+OperationTypeTable[] = {
+ NamedField( ADD_KEY ),
+ NamedField( DELETE_KEY ),
+ NamedField( QUERY_KEY ),
+ NamedField( ADD_VALUE ),
+ NamedField( CHANGE_VALUE ),
+ NamedField( DELETE_VALUE ),
+ NamedField( QUERY_VALUE ),
+
+ { "Add Key" , ADD_KEY },
+ { "Delete Key" , DELETE_KEY },
+ { "Query Key" , QUERY_KEY },
+ { "Add Value" , ADD_VALUE },
+ { "Change Value" , CHANGE_VALUE },
+ { "Delete Value" , DELETE_VALUE },
+ { "Query Value" , QUERY_VALUE }
+};
+
+
+PARSETABLE
+KeyDbaseTable [] = {
+ NamedField( CLASSES_ROOT ),
+ NamedField( CURRENT_USER ),
+ NamedField( LOCAL_MACHINE ),
+ NamedField( USERS ),
+
+ { "HKEY_CLASSES_ROOT" , CLASSES_ROOT },
+ { "HKEY_CURRENT_USER" , CURRENT_USER },
+ { "HKEY_LOCAL_MACHINE", LOCAL_MACHINE },
+ { "HKEY_USERS" , USERS }
+};
+
+
+PARSETABLE
+ValueTypeTable[] = {
+ NamedField( BINARY ),
+ NamedField( DWORD_REGULAR ),
+ NamedField( DWORD_LITTLE_ENDIAN ),
+ NamedField( DWORD_BIG_ENDIAN ),
+ NamedField( EXPAND_SZ ),
+ NamedField( LINK ),
+ NamedField( MULTI_SZ ),
+ NamedField( NONE ),
+ NamedField( RESOURCE_LIST ),
+ NamedField( SZ ),
+
+ { "Binary", BINARY },
+ { "Double Word", DWORD_REGULAR },
+ { "Double Word Litlle Endian", DWORD_LITTLE_ENDIAN },
+ { "Double Word Big Endian", DWORD_BIG_ENDIAN },
+ { "String with unexpanded environment references", EXPAND_SZ },
+ { "Symbolic Link", LINK },
+ { "Array of strings", MULTI_SZ },
+ { "None", NONE },
+ { "Resource List", RESOURCE_LIST },
+ { "String", SZ }
+
+};
+
+//
+// The Test Parameters Structure and command parameter definitions.
+//
+// typedef struct _TestOptions {
+// DWORD OptionNumber;
+// LPSTR TestPrompt;
+// LPSTR ArgName;
+// LPSTR ArgNameAbbr;
+//
+// BOOL ArgValueSet;
+// PARAMTYPES TestType;
+// DWORD IntegerDefault;
+// LPSTR StringDefault;
+//
+// PPARSETABLE ParsedIntTable;
+// DWORD ParsedIntTableSize;
+// PVOID Destination;
+// } TESTPARAMS, *PTESTPARAMS;
+//
+//
+
+TESTPARAMS
+CommandLineOptions[] = {
+
+
+ { 1, "Options", "Options", "OP", FALSE, String,
+ 0, NULL, NULL, 0, GlobalCmdArgs.TpctlOptions },
+
+ { 2, "ScriptFile Name", "ScriptFile", "SF", FALSE, String,
+ 0, NULL, NULL, 0, GlobalCmdArgs.ARGS.FILES.ScriptFile },
+
+ { 3, "LogFile Name", "LogFile", "LF", FALSE, String, 0,
+ NULL, NULL, 0, GlobalCmdArgs.ARGS.FILES.LogFile }
+};
+
+
+DWORD
+Num_CommandLine_Params = sizeoftable( CommandLineOptions );
+
+
+TESTPARAMS
+SetEnvOptions[] = {
+
+ { 1, "Open Instance", "OpenInstance", "OI", FALSE, Integer,
+ OPEN_INSTANCE, NULL, NULL, 0, &GlobalCmdArgs.OpenInstance },
+
+ { 2, "Window Size", "WindowSize", "WS", FALSE, Integer, WINDOW_SIZE,
+ NULL, NULL, 0, &GlobalCmdArgs.ARGS.ENV.WindowSize },
+
+ { 3, "Random Buffer", "RandomBuffer", "RB", FALSE, Integer, BUFFER_NUMBER,
+ NULL, NULL, 0, &GlobalCmdArgs.ARGS.ENV.RandomBufferNumber },
+
+ { 4, "Stress Address", "StressAddress" , "SA", FALSE, Address6, 0,
+ STRESS_MULTICAST, NULL, 0, GlobalCmdArgs.ARGS.ENV.StressAddress },
+
+ { 5, "Resend Address", "ResendAddress" , "RA", FALSE, Address6, 0,
+ NULL_ADDRESS, NULL, 0, GlobalCmdArgs.ARGS.ENV.ResendAddress },
+
+ { 6, "Stress Delay", "StressDelay", "SD", FALSE, Integer,
+ STANDARD_DELAY, NULL, NULL, 0, &GlobalCmdArgs.ARGS.ENV.StandardDelay },
+
+ { 7, "Up-For-Air Delay", "UpForAirDelay", "UD", FALSE, Integer,
+ UP_FOR_AIR_DELAY, NULL, NULL, 0, &GlobalCmdArgs.ARGS.ENV.UpForAirDelay },
+
+ { 8, "Delay Interval", "DelayInterval", "I", FALSE, Integer, DELAY_INTERVAL,
+ NULL, NULL, 0, &GlobalCmdArgs.ARGS.ENV.StressDelayInterval }
+};
+
+
+DWORD
+Num_SetEnv_Params = sizeoftable( SetEnvOptions );
+
+
+TESTPARAMS ReadScriptOptions[] = {
+
+ { 1, "ScriptFile Name", "ScriptFile", "SF", FALSE, String, 0,
+ NULL, NULL, 0, GlobalCmdArgs.ARGS.FILES.ScriptFile },
+
+ { 2, "LogFile Name", "LogFile", "LF", FALSE, String, 0, NULL,
+ NULL, 0, GlobalCmdArgs.ARGS.FILES.LogFile }
+};
+
+
+DWORD
+Num_ReadScript_Params = sizeoftable( ReadScriptOptions );
+
+
+TESTPARAMS
+LoggingOptions[] = {
+
+ { 1, "LogFile Name", "LogFile", "LF", FALSE, String, 0,
+ TPCTL_CMDLINE_LOG, NULL, 0, GlobalCmdArgs.ARGS.FILES.LogFile }
+};
+
+
+DWORD
+Num_Logging_Params = sizeoftable( LoggingOptions );
+
+
+TESTPARAMS
+RecordingOptions[] = {
+
+ { 1, "ScriptFile Name", "ScriptFile", "SF", FALSE, String, 0,
+ TPCTL_CMDLINE_SCRIPT, NULL, 0, GlobalCmdArgs.ARGS.RECORD.ScriptFile }
+};
+
+
+DWORD
+Num_Recording_Params = sizeoftable( RecordingOptions );
+
+
+TESTPARAMS
+PauseGoOptions[] = {
+
+ { 1, "Open Instance", "OpenInstance", "OI", FALSE, Integer,
+ OPEN_INSTANCE, NULL, NULL, 0, &GlobalCmdArgs.OpenInstance },
+
+ { 2, "Remote Address", "RemoteAddress" , "RA", FALSE, Address6, 0,
+ NULL_ADDRESS, NULL, 0, GlobalCmdArgs.ARGS.PAUSE_GO.RemoteAddress },
+
+ { 3, "Test Signature", "TestSignature", "TS", FALSE, Integer,
+ 0, NULL, NULL, 0, &GlobalCmdArgs.ARGS.PAUSE_GO.TestSignature },
+
+ { 4, "Unique Signature", "UniqueSig", "UI", FALSE, Integer, 0, NULL,
+ NULL, 0, &GlobalCmdArgs.ARGS.PAUSE_GO.UniqueSignature },
+};
+
+
+DWORD
+Num_PauseGo_Params = sizeoftable( PauseGoOptions );
+
+
+TESTPARAMS
+LoadUnloadOptions[] = {
+
+ { 1, "Driver Name", "DriverName", "DN", FALSE, String, 0,
+ NULL, NULL, 0, GlobalCmdArgs.ARGS.DriverName }
+};
+
+
+DWORD
+Num_LoadUnload_Params = sizeoftable( LoadUnloadOptions );
+
+
+TESTPARAMS
+OpenOptions[] = {
+
+ { 1, "Open Instance", "OpenInstance", "OI", FALSE, Integer,
+ OPEN_INSTANCE, NULL, NULL, 0, &GlobalCmdArgs.OpenInstance },
+
+ { 2, "Adapter Name", "AdapterName", "AN", FALSE, String, 0,
+ NULL, NULL, 0, GlobalCmdArgs.ARGS.OPEN_ADAPTER.AdapterName }
+};
+
+
+DWORD
+Num_Open_Params = sizeoftable( OpenOptions );
+
+
+TESTPARAMS
+SetPacketFilterOptions[] = {
+
+ { 1, "Open Instance", "OpenInstance", "OI", FALSE, Integer,
+ OPEN_INSTANCE, NULL, NULL, 0, &GlobalCmdArgs.OpenInstance },
+
+ { 2, "Packet Filter", "PacketFilter", "PF", FALSE, ParsedInteger,
+ 0, "DIRECTED", PacketFilterTable, sizeoftable( PacketFilterTable ),
+ &GlobalCmdArgs.ARGS.TPSET.U.PacketFilter }
+};
+
+
+DWORD
+Num_SetPacketFilter_Params = sizeoftable( SetPacketFilterOptions );
+
+
+TESTPARAMS
+SetLookaheadOptions[] = {
+
+ { 1, "Open Instance", "OpenInstance", "OI", FALSE, Integer,
+ OPEN_INSTANCE, NULL, NULL, 0, &GlobalCmdArgs.OpenInstance },
+
+ { 2, "Lookahead Buffer Size", "Lookahead", "LA", FALSE,
+ Integer, LOOKAHEADSIZE, NULL, NULL, 0,
+ &GlobalCmdArgs.ARGS.TPSET.U.LookaheadSize }
+};
+
+
+DWORD
+Num_SetLookahead_Params = sizeoftable( SetLookaheadOptions );
+
+
+TESTPARAMS
+MulticastAddrOptions[] = {
+
+ { 1, "Open Instance", "OpenInstance", "OI", FALSE, Integer,
+ OPEN_INSTANCE, NULL, NULL, 0, &GlobalCmdArgs.OpenInstance },
+
+ { 2, "Multicast Address", "MulticastAddress", "MA",
+ FALSE, Address6, 0, DEFAULT_MULTICAST, NULL, 0,
+ GlobalCmdArgs.ARGS.TPSET.U.MulticastAddress[0] }
+};
+
+
+DWORD
+Num_MulticastAddr_Params = sizeoftable( MulticastAddrOptions );
+
+
+TESTPARAMS
+FunctionalAddrOptions[] = {
+
+ { 1, "Open Instance", "OpenInstance", "OI", FALSE, Integer,
+ OPEN_INSTANCE, NULL, NULL, 0, &GlobalCmdArgs.OpenInstance },
+
+ { 2, "Functional Address", "FunctionalAddress", "FA",
+ FALSE, Address4, 0, &DEFAULT_FUNCTIONAL[2], NULL, 0,
+ GlobalCmdArgs.ARGS.TPSET.U.FunctionalAddress }
+};
+
+
+DWORD
+Num_FunctionalAddr_Params = sizeoftable( FunctionalAddrOptions );
+
+
+TESTPARAMS
+GroupAddrOptions[] = {
+
+ { 1, "Open Instance", "OpenInstance", "OI", FALSE, Integer,
+ OPEN_INSTANCE, NULL, NULL, 0, &GlobalCmdArgs.OpenInstance },
+
+ { 2, "Group Address", "GroupAddress", "GA",
+ FALSE, Address4, 0, &DEFAULT_FUNCTIONAL[2], NULL, 0,
+ GlobalCmdArgs.ARGS.TPSET.U.FunctionalAddress }
+};
+
+
+DWORD
+Num_GroupAddr_Params = sizeoftable( GroupAddrOptions );
+
+
+TESTPARAMS
+QueryInfoOptions[] = {
+
+ { 1, "Open Instance", "OpenInstance", "OI", FALSE, Integer,
+ OPEN_INSTANCE, NULL, NULL, 0, &GlobalCmdArgs.OpenInstance },
+
+ { 2, "OID Request", "ObjectIdentifier", "OID", FALSE, ParsedInteger,
+ 0x00010101, "SupportedOidList", QueryInfoOidTable,
+ sizeoftable( QueryInfoOidTable ), &GlobalCmdArgs.ARGS.TPQUERY.OID },
+};
+
+
+DWORD
+Num_QueryInfo_Params = sizeoftable( QueryInfoOptions );
+
+
+TESTPARAMS
+QueryStatsOptions[] = {
+
+
+ { 1, "Device Name", "DeviceName", "DN", FALSE, String, 0, NULL,
+ NULL, 0, GlobalCmdArgs.ARGS.TPQUERYSTATS.DeviceName },
+
+ { 2, "OID Request", "ObjectIdentifier", "OID", FALSE, ParsedInteger,
+ 0x00010101, "SupportedOidList", QueryInfoOidTable,
+ sizeoftable( QueryInfoOidTable ), &GlobalCmdArgs.ARGS.TPQUERYSTATS.OID },
+};
+
+
+DWORD
+Num_QueryStats_Params = sizeoftable( QueryStatsOptions );
+
+
+TESTPARAMS
+SetInfoOptions[] = {
+
+ { 1, "Open Instance", "OpenInstance", "OI", FALSE, Integer,
+ OPEN_INSTANCE, NULL, NULL, 0, &GlobalCmdArgs.OpenInstance },
+
+ { 2, "OID Request", "ObjectIdentifier", "OID", FALSE, ParsedInteger,
+ 0x0001010e, "CurrentPacketFilter", SetInfoOidTable,
+ sizeoftable( SetInfoOidTable ), &GlobalCmdArgs.ARGS.TPSET.OID }
+};
+
+
+DWORD
+Num_SetInfo_Params = sizeoftable( SetInfoOptions );
+
+
+TESTPARAMS
+SetInfoPFOptions[] = {
+
+ { 1, "Packet Filter", "PacketFilter", "PF", FALSE, ParsedInteger,
+ 0, "DIRECTED", PacketFilterTable, sizeoftable( PacketFilterTable ),
+ &GlobalCmdArgs.ARGS.TPSET.U.PacketFilter }
+};
+
+
+DWORD
+Num_SetInfoPF_Params = sizeoftable( SetInfoPFOptions );
+
+
+TESTPARAMS
+SetInfoLAOptions[] = {
+
+ { 1, "Lookahead Buffer Size", "Lookahead", "LA",
+ FALSE, Integer, LOOKAHEADSIZE, NULL, NULL, 0,
+ &GlobalCmdArgs.ARGS.TPSET.U.LookaheadSize }
+};
+
+
+DWORD
+Num_SetInfoLA_Params = sizeoftable( SetInfoLAOptions );
+
+
+TESTPARAMS
+SetInfoMAOptions[] = {
+
+ { 1, "Multicast Address", "MulticastAddress", "MA",
+ FALSE, Address6, 0, DEFAULT_MULTICAST, NULL, 0,
+ GlobalCmdArgs.ARGS.TPSET.U.MulticastAddress[0] }
+};
+
+
+DWORD
+Num_SetInfoMA_Params = sizeoftable( SetInfoMAOptions );
+
+TESTPARAMS
+SetInfoFAOptions[] = {
+
+ { 1, "Functional Address", "FunctionalAddress", "FA",
+ FALSE, Address4, 0, &DEFAULT_FUNCTIONAL[2], NULL, 0,
+ GlobalCmdArgs.ARGS.TPSET.U.FunctionalAddress }
+};
+
+
+DWORD
+Num_SetInfoFA_Params = sizeoftable( SetInfoFAOptions );
+
+
+TESTPARAMS
+SetInfoGAOptions[] = {
+
+ { 1, "Group Address", "GroupAddress", "GA", FALSE,
+ Address4, 0, &DEFAULT_FUNCTIONAL[2], NULL, 0,
+ GlobalCmdArgs.ARGS.TPSET.U.FunctionalAddress }
+};
+
+
+DWORD
+Num_SetInfoGA_Params = sizeoftable( SetInfoGAOptions );
+
+
+TESTPARAMS
+SendOptions[] = {
+
+ { 1, "Open Instance", "OpenInstance", "OI", FALSE, Integer,
+ OPEN_INSTANCE, NULL, NULL, 0, &GlobalCmdArgs.OpenInstance },
+
+ { 2, "Destination Address", "DestinationAddress", "DA", FALSE, Address6,
+ 0, NULL_ADDRESS, NULL, 0, GlobalCmdArgs.ARGS.TPSEND.DestAddress },
+
+ { 3, "Packet Size", "PacketSize", "PS", FALSE, Integer, PACKET_SIZE,
+ NULL, NULL, 0, &GlobalCmdArgs.ARGS.TPSEND.PacketSize },
+
+ { 4, "Number to Send", "Number", "N", FALSE, Integer, 1, NULL, NULL,
+ 0, &GlobalCmdArgs.ARGS.TPSEND.NumberOfPackets },
+
+ { 5, "Resend Address", "ResendAddress", "RA", FALSE, Address6, 0,
+ NULL_ADDRESS, NULL, 0, GlobalCmdArgs.ARGS.TPSEND.ResendAddress }
+
+ //
+ // Both Resend and Dest address will default to the local address
+ // which must be queried and then stored in the application somewhere?
+ //
+};
+
+
+DWORD
+Num_Send_Params = sizeoftable( SendOptions );
+
+
+TESTPARAMS
+PerfClntOptions[] = {
+
+ { 1, "Open Instance", "OpenInstance", "OI", FALSE, Integer,
+ OPEN_INSTANCE, NULL, NULL, 0, &GlobalCmdArgs.OpenInstance },
+
+ { 2, "Server Address", "ServerAddress", "SVA", FALSE, Address6,
+ 0, NULL_ADDRESS, NULL, 0, GlobalCmdArgs.ARGS.TPPERF.PerfServerAddr },
+
+ { 3, "Send Address", "SendAddress", "SA", FALSE, Address6,
+ 0, NULL_ADDRESS, NULL, 0, GlobalCmdArgs.ARGS.TPPERF.PerfSendAddr },
+
+ { 4, "Packet Size", "PacketSize", "PS", FALSE, Integer, PACKET_SIZE,
+ NULL, NULL, 0, &GlobalCmdArgs.ARGS.TPPERF.PerfPacketSize },
+
+ { 5, "Number to Send", "Number", "N", FALSE, Integer, 100000, NULL, NULL,
+ 0, &GlobalCmdArgs.ARGS.TPPERF.PerfNumPackets },
+
+ { 6, "Delay", "Delay", "D", FALSE, Integer, 0, NULL, NULL,
+ 0, &GlobalCmdArgs.ARGS.TPPERF.PerfDelay },
+
+ { 7, "Mode", "Mode", "M", FALSE, Integer, 0, NULL, NULL,
+ 0, &GlobalCmdArgs.ARGS.TPPERF.PerfMode }
+};
+
+
+DWORD
+Num_PerfClnt_Params = sizeoftable( PerfClntOptions );
+
+
+TESTPARAMS
+StressOptions[] = {
+
+ { 1, "Open Instance", "OpenInstance", "OI", FALSE, Integer,
+ OPEN_INSTANCE, NULL, NULL, 0, &GlobalCmdArgs.OpenInstance },
+
+ { 2, "Stress Member Type", "MemberType", "MT", FALSE, ParsedInteger,
+ 0, "TP_CLIENT", MemberTypeTable, sizeoftable( MemberTypeTable ),
+ &GlobalCmdArgs.ARGS.TPSTRESS.MemberType },
+
+ { 3, "Total Number of Packets", "Packets", "P", FALSE, Integer,
+ (DWORD)STRESS_PACKETS, NULL, NULL, 0, &GlobalCmdArgs.ARGS.TPSTRESS.TotalPackets },
+
+ { 4, "Total Number of Iterations", "Iterations", "I", FALSE, Integer,
+ (DWORD)STRESS_ITERATIONS, NULL, NULL, 0, &GlobalCmdArgs.ARGS.TPSTRESS.TotalIterations },
+
+ { 5, "Packet Type", "PacketType", "PT", FALSE, ParsedInteger, 0,
+ "FIXEDSIZE", PacketTypeTable, sizeoftable( PacketTypeTable ),
+ &GlobalCmdArgs.ARGS.TPSTRESS.PacketType },
+
+ { 6, "Packet Size", "PacketSize", "PS", FALSE, Integer, PACKET_SIZE,
+ NULL, NULL, 0, &GlobalCmdArgs.ARGS.TPSTRESS.PacketSize },
+
+ { 7, "Packet MakeUp", "PacketMakeUp", "PM", FALSE, ParsedInteger,
+ 0, "RAND", PacketMakeUpTable, sizeoftable( PacketMakeUpTable ),
+ &GlobalCmdArgs.ARGS.TPSTRESS.PacketMakeUp },
+
+ { 8, "Response Type", "ResponseType", "RT", FALSE, ParsedInteger, 0,
+ "FULL_RESPONSE", ResponseTypeTable, sizeoftable( ResponseTypeTable ),
+ &GlobalCmdArgs.ARGS.TPSTRESS.ResponseType },
+
+ { 9, "Interpacket Delay Type", "DelayType", "DT", FALSE,
+ ParsedInteger, 0, "FIXEDDELAY", DelayTable, sizeoftable( DelayTable ),
+ &GlobalCmdArgs.ARGS.TPSTRESS.DelayType },
+
+ { 10, "Interpacket Delay Length", "DelayLength", "DL", FALSE, Integer,
+ 0, NULL, NULL, DELAY_LENGTH, &GlobalCmdArgs.ARGS.TPSTRESS.DelayLength },
+
+ { 11, "Windowing Enabled","WindowEnabled","WE", FALSE, ParsedInteger, 0,
+ WINDOWING_ENABLED, BooleanTable, sizeoftable( BooleanTable ),
+ &GlobalCmdArgs.ARGS.TPSTRESS.WindowEnabled },
+
+ { 12, "Data Checking Enabled", "DataChecking", "DC", FALSE, ParsedInteger,
+ 0, DATA_CHECKING, BooleanTable, sizeoftable( BooleanTable ),
+ &GlobalCmdArgs.ARGS.TPSTRESS.DataChecking },
+
+ { 13, "Packets from Pool", "PacketPool", "PP", FALSE, ParsedInteger,
+ 0, PACKETS_FROM_POOL, BooleanTable, sizeoftable( BooleanTable ),
+ &GlobalCmdArgs.ARGS.TPSTRESS.PacketsFromPool }
+};
+
+
+DWORD
+Num_Stress_Params = sizeoftable( StressOptions );
+
+
+TESTPARAMS
+OpenInstanceOptions[] = {
+
+ { 1, "Open Instance", "OpenInstance", "OI", FALSE, Integer,
+ OPEN_INSTANCE, NULL, NULL, 0, &GlobalCmdArgs.OpenInstance }
+};
+
+
+DWORD
+Num_OpenInstance_Params = sizeoftable( OpenInstanceOptions );
+
+
+TESTPARAMS
+HelpOptions[] = {
+
+ { 1, "Command Name", "CommandName", "CN", FALSE, String, 0,
+ NULL, NULL, 0, GlobalCmdArgs.ARGS.CmdName }
+};
+
+
+DWORD
+Num_Help_Params = sizeoftable( HelpOptions );
+
+
+TESTPARAMS
+RegistryOptions[] = {
+
+ { 1, "Operation Type", "Operation", "OP", FALSE, ParsedInteger, 0,
+ "QUERY_KEY", OperationTypeTable, sizeoftable( OperationTypeTable ),
+ &GlobalCmdArgs.ARGS.REGISTRY_ENTRY.OperationType },
+
+ { 2, "Key Database", "KeyDatabase", "KD", FALSE, ParsedInteger, 0,
+ "LOCAL_MACHINE", KeyDbaseTable, sizeoftable( KeyDbaseTable ),
+ &GlobalCmdArgs.ARGS.REGISTRY_ENTRY.KeyDatabase },
+
+ { 3, "Sub Key Name", "SubKey", "SK", FALSE, String, 0,
+ "\"System\\CurrentControlSet\\Services\\Sonic01\\Parameters\"", NULL, 0,
+ GlobalCmdArgs.ARGS.REGISTRY_ENTRY.SubKey },
+
+ {4, "Sub Key Class", "SubKeyClass", "SC", FALSE, String, 0,
+ "\"Network Drivers\"", NULL, 0,
+ GlobalCmdArgs.ARGS.REGISTRY_ENTRY.SubKeyClass },
+
+ {5, "Sub Key Value Name", "SubKeyValueName", "SN", FALSE, String, 0,
+ "\"NetworkAddress\"", NULL, 0,
+ GlobalCmdArgs.ARGS.REGISTRY_ENTRY.SubKeyValueName },
+
+ {6, "Sub Key Value Type", "SubKeyValueType", "ST", FALSE, ParsedInteger, 0,
+ "DWORD_REGULAR", ValueTypeTable, sizeoftable( ValueTypeTable ),
+ &GlobalCmdArgs.ARGS.REGISTRY_ENTRY.ValueType },
+
+ {7, "Sub Key Value", "SubKeyValue", "SV", FALSE, String, 0,
+ "\0", NULL, 0,
+ GlobalCmdArgs.ARGS.REGISTRY_ENTRY.SubKeyValue }
+
+};
+
+
+DWORD
+Num_Registry_Params = sizeoftable( RegistryOptions );
+
+
+
+
+
+DWORD
+TpctlParseArguments (
+ IN TESTPARAMS Options[],
+ IN DWORD TestSize,
+ IN DWORD ArgC,
+ IN LPSTR ArgV[]
+ )
+
+// ---------------------
+//
+// Routine Description:
+//
+// This routine parses a table
+//
+// Arguments:
+//
+// IN PARSE_PARAMS Option, - [Supplies | Returns] description-of-argument
+// IN DWORD ArgC, - [Supplies | Returns] description-of-argument
+// IN LPSTR ArgV[] - [Supplies | Returns] description-of-argument
+//
+// Return Value:
+//
+// DWORD = -1 if there was a parse error.
+// = The number of parameters "eaten" otherwise.
+//
+// --------------------
+
+{
+ DWORD i, j;
+ BYTE Buffer[TPCTL_CMDLINE_SIZE];
+ LPSTR ArgName, ArgValue;
+ BYTE ArgPrompt[TPCTL_CMDLINE_SIZE];
+ LPBYTE NextToken;
+ DWORD RetVal;
+ BOOL Reparse;
+ BOOL Error;
+ BOOL ParsedArgumentsYet;
+ BOOL ArgNameValuePair;
+ DWORD OptionNumber;
+ DWORD OpenInstance;
+ LPBYTE p, q;
+
+ //
+ // First determine the Open Instance, we may need it later.
+ //
+
+ OpenInstance = TpctlGetOpenInstance( ArgC,ArgV );
+
+ //
+ // Lower the argument count thus ignoring the command itself,
+ // we don't care about that here.
+ //
+
+ if ( ArgC )
+ {
+ ArgC -= 1; // Don't count command in args.
+ }
+
+ RetVal = min( ArgC, TestSize );
+
+ if ( ArgC > TestSize )
+ {
+ ArgC = TestSize;
+ }
+
+ //
+ // Load the defaults for each of the arguments into the Destination
+ // field.
+ //
+
+ for ( i=0;i<TestSize;i++ )
+ {
+ Options[i].ArgValueSet = FALSE;
+
+ switch ( Options[i].TestType )
+ {
+ case Integer:
+ *(PDWORD)Options[i].Destination = Options[i].IntegerDefault;
+ break;
+
+ case String:
+ if ( Options[i].StringDefault != NULL )
+ {
+ strcpy( (LPSTR)Options[i].Destination, Options[i].StringDefault );
+ }
+ else
+ {
+ ((LPSTR)Options[i].Destination)[0] = '\0';
+ }
+ break;
+
+ case Address4:
+ p = Options[i].Destination;
+ q = Options[i].StringDefault;
+
+ for ( j=0;j<FUNCTIONAL_ADDRESS_LENGTH;j++ )
+ {
+ *p++ = *q++;
+ }
+ break;
+
+ case Address6:
+ p = Options[i].Destination;
+ q = Options[i].StringDefault;
+
+ for ( j=0;j<ADDRESS_LENGTH;j++ )
+ {
+ *p++ = *q++;
+ }
+ break;
+
+
+ case ParsedInteger:
+ TpctlParseInteger( Options[i].StringDefault,
+ Options[i].ParsedIntTable,
+ Options[i].ParsedIntTableSize,
+ Options[i].Destination);
+
+ break;
+
+ default:
+ TpctlErrorLog("\nTpctl: ParseArguments: Invalid TestType\n",NULL);
+ return (DWORD)-1;
+ }
+ }
+
+ //
+ // Now parse the input command line, and determine if any arguments
+ // exist on the command line. The command line may be made up in one
+ // of the following ways:
+ //
+ // 1) nothing, prompt the user for all of the arguments to the given
+ // command.
+ //
+ // 2) argument name=value pairs, parse each pair and set up the options
+ // structure. if the line ends with a semicolon ';' then return the
+ // options structure to the caller, otherwise prompt the user for the
+ // remainder of the commands for the given command then return.
+ //
+ // 3) arguments values only, parse each value and place in the options
+ // structure. if the line ends with a semicolon ';' then return the
+ // options structure to the caller, otherwise prompt the user for the
+ // remainder of the commands for the given command then return.
+ //
+ // NOTE: a command line may not contain name=value pairs, and values, it
+ // may only contain one type or the other.
+ //
+
+ ArgNameValuePair = FALSE;
+ ParsedArgumentsYet = FALSE;
+
+ for( i=1;i<=ArgC;i++ )
+ {
+ if ( ArgV[i][0] == ';' )
+ {
+ return RetVal;
+ }
+
+ if ( TpctlParseArgumentPairs( ArgV[i],&ArgName,&ArgValue ))
+ {
+ if ( ParsedArgumentsYet == FALSE )
+ {
+ //
+ // We have an argument name/value pair, and this is the
+ // first argument in the command line, all the rest of the
+ // arguments MUST have an arguments name-value pairing, set
+ // the flags appropriately, and continue.
+ //
+
+ ArgNameValuePair = TRUE;
+ ParsedArgumentsYet = TRUE;
+
+ }
+ else if ( ArgNameValuePair == FALSE )
+ {
+
+ //
+ // The first argument was an argument value only, and now
+ // we have an argument name=value pair. This is an illegal
+ // entry on the command line, report the error, and return.
+ // if we are running a script file end it now reporting an
+ // error.
+ //
+
+ TpctlErrorLog("\n\tTpctl: ERROR - \"%s",ArgName);
+ TpctlErrorLog("=%s\"\n",ArgValue);
+ TpctlErrorLog("\n\tArgument values and argument name-value pairs\n",NULL);
+ TpctlErrorLog("\tmay not be combined in the same command.\n",NULL);
+ return (DWORD)-1;;
+ }
+
+ }
+ else // We have only a Argument Value.
+ {
+ if ( ParsedArgumentsYet == FALSE )
+ {
+
+ //
+ // This is the first arugment, set the flags appropriately,
+ // and continue.
+ //
+
+ ParsedArgumentsYet = TRUE;
+
+ }
+ else if ( ArgNameValuePair == TRUE )
+ {
+
+ //
+ // The first argument was an argument name=value pair, and
+ // now we have an argument value only. This is an illegal
+ // entry on the command line, report the error, and return.
+ // if we are running a script file end it now reporting an
+ // error.
+ //
+
+ TpctlErrorLog("\n\tTpctl: ERROR - \"%s\"\n",ArgValue);
+ TpctlErrorLog("\n\tArgument name-value pairs and argument values\n",NULL);
+ TpctlErrorLog("\tmay not be combined in the same command.\n",NULL);
+ return (DWORD)-1;;
+ }
+ }
+
+ if ( ArgNameValuePair == TRUE )
+ {
+
+ OptionNumber = TpctlGetOptionNumber( Options,TestSize,ArgName );
+
+ if ( OptionNumber == -1 )
+ {
+
+ //
+ // This is an invalid option number report the error, and return.
+ // if we are running a script file end it now reporting an error.
+ //
+
+ TpctlErrorLog("\n\tTpctl: Invalid Argument Name: \"%s\"",ArgName);
+ TpctlErrorLog("\n\tThis argument does not exist for this command\n",NULL);
+ return (DWORD)-1;;
+ }
+ }
+ else
+ {
+ OptionNumber = i;
+ }
+
+ { // ParsePtr scope.
+
+ PTESTPARAMS ParsePtr = &Options[OptionNumber-1];
+
+ Error = FALSE;
+
+ //
+ // If the argument passed in from the command line is the
+ // '*' symbol, the user wants to use the default argument for
+ // this variable, set the argument value and set flag to TRUE
+ // indicating that we do not need to prompt for it further, and
+ // continue with the next argument.
+ //
+
+ if ( ArgValue[0] == '*' )
+ {
+ ParsePtr->ArgValueSet = TRUE;
+ continue;
+ }
+
+// globvars access
+
+ if ( ArgValue[0] == '$')
+ {
+ PVOID valptr = TpctlParseGlobalVariable(ArgValue, ParsePtr->TestType);
+ LPBYTE s,d;
+ ULONG i;
+
+ if (valptr != NULL)
+ {
+ switch ( ParsePtr->TestType)
+ {
+ case Integer:
+ *(PDWORD)ParsePtr->Destination = *(PDWORD)valptr;
+ break;
+
+ case String:
+ strcpy( (LPSTR)ParsePtr->Destination, (LPSTR)valptr);
+ break;
+
+ case Address4:
+ s = (LPBYTE)valptr;
+ d = (LPBYTE)ParsePtr->Destination;
+ for (i=0; i < FUNCTIONAL_ADDRESS_LENGTH; i++)
+ {
+ *d++ = *s++;
+ }
+ break;
+
+ case Address6:
+ s = (LPBYTE)valptr;
+ d = (LPBYTE)ParsePtr->Destination;
+ for (i=0; i < ADDRESS_LENGTH; i++)
+ {
+ *d++ = *s++;
+ }
+ break;
+ }
+ }
+ continue;
+ }
+
+// end of globvars access
+
+ switch( ParsePtr->TestType )
+ {
+
+ case Integer:
+ *(PDWORD)ParsePtr->Destination = strtoul( ArgValue,&NextToken,0 );
+ break;
+
+ case String:
+ strcpy( (LPSTR)ParsePtr->Destination,ArgValue );
+ break;
+
+ case Address4:
+ if ( TpctlParseAddress( ArgValue,
+ ParsePtr->Destination,
+ OpenInstance - 1,
+ FUNCTIONAL_ADDRESS_LENGTH ) != 0 )
+ {
+ Error = TRUE;
+ }
+
+ break;
+
+ case Address6:
+ if ( TpctlParseAddress( ArgValue,
+ ParsePtr->Destination,
+ OpenInstance - 1,
+ ADDRESS_LENGTH ) != 0 )
+ {
+ Error = TRUE;
+ }
+ break;
+
+ case ParsedInteger:
+ if ( TpctlParseInteger( ArgValue,
+ ParsePtr->ParsedIntTable,
+ ParsePtr->ParsedIntTableSize,
+ ParsePtr->Destination ) != 0 )
+ {
+ Error = TRUE;
+ }
+
+ break;
+
+ default:
+ TpctlErrorLog("ParseArguments: Invalid TestType\n",NULL);
+ Error = TRUE;
+ }
+
+ if ( Error == TRUE )
+ {
+ TpctlErrorLog("\n\tTpctl: Invalid Argument Value\n",NULL);
+ return (DWORD)-1;;
+ }
+
+ //
+ // We have set this options new value from the command line, so
+ // set the flag stating not to prompt the user again if necessary.
+ //
+
+ ParsePtr->ArgValueSet = TRUE;
+
+ } // end of ParsePtr for now.
+ }
+
+ //
+ // Set Up the "ArgPrompt" to request the new value for the argument.
+ //
+
+ for ( i=1;i<=TestSize;i++ )
+ {
+
+ PTESTPARAMS ParsePtr = &Options[i-1];
+ PTESTPARAMS OIParsePtr = &Options[0];
+
+ if (ScriptIndex != -1)
+ {
+
+ //
+ // We are reading from a script file, so there is no prompting
+ // required.
+
+ break;
+ }
+
+ if ( ParsePtr->ArgValueSet != TRUE )
+ {
+
+ //
+ // If there was a command line argument, use it for the
+ // argument, otherwise prompt for the argument.
+ //
+
+ Reparse = TRUE;
+
+ strcpy( ArgPrompt, "\t" );
+ strcat( ArgPrompt, ParsePtr->TestPrompt );
+ strcat( ArgPrompt, " [" );
+
+ switch ( ParsePtr->TestType )
+ {
+ case Integer:
+ {
+ BYTE Int[20];
+ _ltoa( ParsePtr->IntegerDefault, Int , 10 );
+ strcat( ArgPrompt, Int );
+ }
+ break;
+
+ case ParsedInteger:
+ case String:
+ if ( ParsePtr->StringDefault!=NULL )
+ {
+ strcat( ArgPrompt,ParsePtr->StringDefault );
+ }
+ break;
+
+ case Address4:
+ if ( ParsePtr->StringDefault != NULL )
+ {
+ p = ArgPrompt + strlen( ArgPrompt );
+ q = ParsePtr->StringDefault;
+
+ for( j=0;j<FUNCTIONAL_ADDRESS_LENGTH;j++ )
+ {
+ p += (BYTE)sprintf(p,"%02X",*q++);
+
+ if ( j < ( FUNCTIONAL_ADDRESS_LENGTH - 1 ))
+ {
+ *p++ = '-';
+ }
+ }
+ *p = '\0';
+ }
+ break;
+
+ case Address6:
+ if ( ParsePtr->StringDefault!=NULL )
+ {
+ p = ArgPrompt + strlen( ArgPrompt );
+ q = ParsePtr->StringDefault;
+
+ for( j=0;j<ADDRESS_LENGTH;j++ )
+ {
+ p += (BYTE)sprintf(p,"%02X",*q++);
+
+ if ( j < ( ADDRESS_LENGTH - 1 ))
+ {
+ *p++ = '-';
+ }
+ }
+ *p = '\0';
+ }
+ break;
+
+ } // switch
+
+ //
+ // Now prompt the user for the new value.
+ //
+
+ strcat( ArgPrompt,"] >" );
+
+ TpctlPrompt( ArgPrompt,Buffer,TPCTL_CMDLINE_SIZE );
+
+ //
+ // and print the response to the log file if requested.
+ //
+
+ TpctlCmdLneLog( Buffer, NULL );
+ TpctlCmdLneLog( "\n", NULL );
+
+
+ while ( Reparse )
+ {
+
+ //
+ // Clean up the buffer, removing any unnecessary spaces.
+ //
+
+ TpctlFixBuffer( Buffer );
+
+ //
+ // If the user entered a ';' meaning all desired values
+ // have been entered, use the defaults for the rest.
+ //
+
+ if ( TpctlFirstChar( Buffer,';' ))
+ {
+ i = TestSize;
+ break;
+ }
+
+ //
+ // If the user simply hit enter meaning that we should
+ // use the default value for this argument, then do so.
+ //
+
+ if ( TpctlFirstChar( Buffer,'\0' ))
+ {
+ break;
+ }
+
+ //
+ // If the argument starts with '%' then it is an Environment
+ // variable, and we need to find out its actual value and
+ // replace it.
+ //
+
+ if ( Buffer[0] == '%' )
+ {
+ if ( !TpctlParseEnvironmentVariable( Buffer ))
+ {
+ return (DWORD)-1;;
+ }
+ }
+
+ //
+ // Now put the newly entered value in its destination.
+ //
+
+
+ Error = FALSE;
+
+ switch ( ParsePtr->TestType )
+ {
+ case Integer:
+ *(PDWORD)ParsePtr->Destination =
+ strtol( Buffer,&NextToken,0 );
+ Reparse = FALSE;
+ break;
+
+ case String:
+ strcpy( (LPSTR)ParsePtr->Destination,Buffer );
+ Reparse = FALSE;
+ break;
+
+ case Address4:
+ if ( OpenInstance == -1 )
+ {
+ OpenInstance = *(PDWORD)OIParsePtr->Destination;
+ }
+
+ if ( TpctlParseAddress( Buffer,
+ ParsePtr->Destination,
+ OpenInstance - 1,
+ FUNCTIONAL_ADDRESS_LENGTH) != 0)
+ {
+ Error = TRUE;
+ }
+ Reparse = FALSE;
+ break;
+
+ case Address6:
+ if ( OpenInstance == -1 )
+ {
+ OpenInstance = *(PDWORD)OIParsePtr->Destination;
+ }
+
+ if ( TpctlParseAddress( Buffer,
+ ParsePtr->Destination,
+ OpenInstance - 1,
+ ADDRESS_LENGTH ) != 0 )
+ {
+ Error = TRUE;
+ }
+ Reparse = FALSE;
+ break;
+
+ case ParsedInteger:
+ if ( TpctlParseInteger( Buffer,
+ ParsePtr->ParsedIntTable,
+ ParsePtr->ParsedIntTableSize,
+ ParsePtr->Destination ) != 0 )
+ {
+ Error = TRUE;
+ }
+ Reparse = FALSE;
+ break;
+ }
+
+ if ( Error )
+ {
+
+ //
+ // A bad value was entered for the last variable, see if
+ // the user would like to enter a new value.
+ //
+
+ TpctlPrompt("\tTpctl: Argument Error, Re-enter? [Y]",
+ Buffer, TPCTL_CMDLINE_SIZE);
+
+ //
+ // and print the response to the log file if requested.
+ //
+
+ TpctlCmdLneLog( Buffer, NULL);
+ TpctlCmdLneLog( "\n", NULL);
+
+ if ((( Buffer[0] == '\0' ) ||
+ ( Buffer[0] == 'Y' )) ||
+ ( Buffer[0] == 'y' ))
+ {
+
+ //
+ // if so, reprompt the user for a new value.
+ //
+
+ TpctlPrompt( ArgPrompt,Buffer,TPCTL_CMDLINE_SIZE );
+
+ //
+ // and print the response to the log file if requested.
+ //
+
+ TpctlCmdLneLog( Buffer, NULL);
+ TpctlCmdLneLog( "\n", NULL);
+ Reparse = TRUE;
+
+ }
+ else
+ {
+
+ //
+ // Otherwise return an error.
+ //
+
+ return (DWORD)-1;;
+ }
+ }
+ }
+ }
+ }
+
+ return RetVal;
+}
+
+
+VOID
+TpctlFixBuffer(
+ IN BYTE Buffer[]
+ )
+
+// ---------------------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// -------------------
+
+{
+ LPSTR Token = Buffer;
+ LPSTR NextToken = Buffer; // Anything that isn't NULL.
+
+ if ( Buffer == NULL )
+ {
+ return;
+ }
+
+ while (( *Token != '\0' ) && ( *Token <= ' ' ))
+ {
+ Token++; // ignore leading blanks
+ }
+
+ NextToken = strchr( Token,' ' ); // now see if there are any spaces.
+
+ if ( NextToken != NULL ) // and if so, null them out.
+ {
+ *NextToken++ = '\0';
+ }
+}
+
+
+DWORD
+TpctlParseInteger (
+ IN BYTE Buffer[],
+ IN PPARSETABLE ParseTable,
+ IN DWORD ParseTableSize,
+ OUT PDWORD Ret
+ )
+
+// ---------------------
+//
+// Routine Description:
+//
+// This routine parses a "parsed integer" and returns it to the caller.
+//
+// Arguments:
+//
+// IN BYTE Buffer[], - [Supplies | Returns] description-of-argument
+// IN PPARSETABLE ParseTable, - [Supplies | Returns] description-of-argument
+// IN DWORD ParseTableSize - [Supplies | Returns] description-of-argument
+// OUT PDWORD Ret
+//
+// Return Value:
+//
+// DWORD
+//
+// --------------------
+
+{
+ LPSTR Token = Buffer;
+ LPSTR NextToken = Buffer; // Anything that isn't NULL.
+ LPBYTE savePointer = NULL;
+ BYTE saveToken;
+ DWORD i;
+
+ if ( Buffer == NULL )
+ {
+ *Ret = 0;
+ return 0;
+ }
+
+ //
+ // If the user specified an absolute number, return that.
+ //
+
+ if ( isdigit( *Token ))
+ {
+ *Ret = strtoul( Token,&NextToken,0 );
+ return 0;
+ }
+
+ //
+ // Nope, the user passed in a string, parse that.
+ //
+
+ //
+ // Initialize the initial value of the returned value to NULL.
+ //
+
+ *Ret = 0;
+
+ while ( NextToken != NULL )
+ {
+ NextToken = strchr( Token,'|' );
+
+ if ( NextToken != NULL )
+ {
+ saveToken = *NextToken;
+ savePointer = NextToken;
+ *NextToken++ = '\0';
+ }
+
+ for ( i=0;i<ParseTableSize;i++ )
+ {
+ if ( _stricmp( Token,ParseTable[i].FieldName ) == 0 )
+ {
+ *Ret |= ParseTable[i].FieldValue;
+ break;
+ }
+ }
+
+ if ( i == ParseTableSize )
+ {
+ TpctlErrorLog("\n\tTpctl: Unknown option \"%s\" entered.\n",
+ (PVOID)Token);
+ TpctlErrorLog("\n\t\tValid options are:\n\n",NULL);
+
+ for ( i=0;i<ParseTableSize;i++ )
+ {
+ TpctlErrorLog("\t\t\t%s\n", (PVOID)ParseTable[i].FieldName);
+ }
+
+ TpctlErrorLog("\n",NULL);
+ return (DWORD)-1;;
+ }
+
+ if ( savePointer != NULL )
+ {
+ *savePointer = saveToken; // Restore byte trompled on.
+ }
+
+ Token = NextToken;
+ }
+
+ return 0;
+}
+
+
+
+DWORD
+TpctlParseAddress(
+ IN BYTE Buffer[],
+ OUT PDWORD RetAddr,
+ IN DWORD OpenInstance,
+ IN DWORD AddressLength
+ )
+
+// -----------------
+//
+// Routine Description:
+//
+// This routine parses a network address and returns it to the caller.
+//
+// Arguments:
+//
+// IN BYTE Buffer[], - [Supplies | Returns] description-of-argument
+// OUT PDWORD RetAddr
+//
+// Return Value:
+//
+// DWORD
+//
+// ----------------
+
+{
+ BYTE TmpBuf[100];
+ PBYTE TmpAddr;
+ BYTE digit;
+ DWORD i, j;
+ BYTE n[2];
+ LPBYTE p;
+
+
+ if ( Buffer == NULL )
+ {
+ *RetAddr = 0;
+ return 0;
+ }
+
+ TmpAddr = (PBYTE)RetAddr;
+
+ //
+ // See if the user entered one of the text string addresses at the
+ // command line.
+ //
+
+ if ( _stricmp( Buffer,RESEND_ADDRESS ) == 0 )
+ {
+
+ //
+ // If the user has entered "resendaddress" at the command line,
+ // then we will use the resend address stored in the ResendAddress
+ // environment variable.
+ //
+
+ p = (LPBYTE)Open[OpenInstance].EnvVars->ResendAddress;
+
+ for ( i=0 ; i < AddressLength ; i++ )
+ {
+ *TmpAddr++ = *p++;
+ }
+ return 0;
+
+ }
+ else if ( _stricmp( Buffer,LOCAL_ADDRESS ) == 0 )
+ {
+
+ //
+ // If the user has entered "localaddress" at the command line
+ // then we will use the local address stored in the Open Block.
+ //
+
+ p = (LPBYTE)Open[OpenInstance].AdapterAddress;
+
+ for ( i=0 ; i < AddressLength ; i++ )
+ {
+ *TmpAddr++ = *p++;
+ }
+ return 0;
+ }
+
+ i = j = 0;
+
+ //
+ // Remove any spaces or hyphens from the address.
+ //
+
+ while ( i < ( AddressLength * 2 ))
+ {
+ if (( Buffer[j] != ' ' ) && ( Buffer[j] != '-' ))
+ {
+ TmpBuf[i++] = Buffer[j];
+ }
+
+ //
+ // If we run of the end of the buffer return with an error.
+ //
+
+ if ( ++j==100 )
+ {
+ return (DWORD)-1;;
+ }
+ }
+
+ //
+ // Now parse the "packed" address and turn the characters into numbers.
+ //
+
+ for( i=0 ; i < AddressLength ; i++ )
+ {
+ digit = '\0';
+
+ for( j=0;j<2;j++ )
+ {
+ if (( TmpBuf[i*2+j] >= '0' ) && ( TmpBuf[i*2+j] <= '9' ))
+ {
+ n[0] = TmpBuf[i*2+j];
+ n[1] = '\0';
+ digit += (BYTE)(atoi( n ));
+
+ }
+ else if (( TmpBuf[i*2+j] >= 'a' ) && ( TmpBuf[i*2+j] <= 'f' ))
+ {
+ digit += (BYTE)(( TmpBuf[i*2+j] - 'a' ) + 10 );
+ }
+ else if (( TmpBuf[i*2+j] >= 'A' ) && ( TmpBuf[i*2+j] <= 'F' ))
+ {
+ digit += (BYTE)(( TmpBuf[i*2+j] - 'A' ) + 10 );
+ }
+ else
+ {
+
+ //
+ // We have an invalid Address; return error.
+ //
+
+ return (DWORD)-1;;
+ }
+
+ //
+ // Raise the high half by 0xf.
+ //
+
+ if ( j==0 )
+ {
+ digit *= 16;
+ }
+ }
+
+ *TmpAddr++ = (BYTE)digit;
+ }
+
+ return 0;
+}
+
+
+
+BOOL
+TpctlParseArgumentPairs(
+ IN LPSTR Argument,
+ OUT LPSTR *ArgName,
+ OUT LPSTR *ArgValue
+ )
+
+// ---------------------
+//
+// Routine Description:
+//
+// This routine parses an argument string to determine if it contains
+// an argument name/value pair, or just an argument value.
+//
+// Arguments:
+//
+// Argument - The argument string.
+//
+// ArgName - The name of the argument if there is one.
+//
+// ArgValue - The argument value.
+//
+// Return Value:
+//
+// BOOL - TRUE if there is a name/value pair, FALSE otherwise.
+//
+// -------------------
+
+{
+ LPSTR temp;
+ BOOL EqualsSign;
+
+ temp = Argument;
+ EqualsSign = FALSE;
+
+ if ( strchr(Argument,'=') != NULL )
+ {
+ EqualsSign = TRUE ;
+ }
+
+ //
+ // If there is an equals sign, then we have an argument name/value
+ // pair. Get each, and put them in their respective return strings.
+ //
+
+ if (EqualsSign)
+ {
+ *ArgName = Argument;
+ temp = Argument;
+
+ //
+ // Search for the end of the argument name, and null terminate it.
+ //
+
+ while ((*temp != '=') && (*temp != ' '))
+ {
+ temp++;
+ }
+
+ *temp++ = '\0';
+
+ //
+ // Then search for the beginning of the argument value, and return
+ // it in ArgValue.
+ //
+
+ while ((*temp == '=') || (*temp == ' '))
+ {
+ temp++;
+ }
+
+ *ArgValue = temp;
+
+ }
+ else
+ {
+
+ //
+ // There is only an argument value so null out the ArgName, and
+ // return the value in ArgValue.
+ //
+
+ ArgName = '\0';
+ *ArgValue = Argument;
+ }
+
+ return EqualsSign;
+}
+
+
+
+BOOL
+TpctlParseSetInfoArguments(
+ IN OUT DWORD *ArgC,
+ IN OUT LPSTR ArgV[],
+ IN OUT DWORD *tmpArgC,
+ IN OUT LPSTR tmpArgV[]
+ )
+
+// --------------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// BOOL -
+//
+// -------------
+
+{
+ DWORD i;
+
+ *tmpArgC = 1;
+ tmpArgV[0] = '\0';
+
+ //
+ // See if the arguments are name-value pairs, or just the
+ // argument values, if there is an equal sign in the first
+ // argument then they are name-value paired arguments.
+ //
+
+ if ( strchr(ArgV[1],'=') != NULL )
+ {
+ //
+ // We have name value pairs
+ //
+
+ for (i=1;i<*ArgC;i++)
+ {
+
+ //
+ // So search the ArgV for the correct argument name, and
+ // if it is found have tmpArgV refernce it.
+ //
+
+ if (( _strnicmp(ArgV[i],"PacketFilter",12) == 0 ) ||
+ ( _strnicmp(ArgV[i],"StationAddress",14) == 0 ) ||
+ ( _strnicmp(ArgV[i],"FunctionalAddress",17) == 0 ) ||
+ ( _strnicmp(ArgV[i],"GroupAddress",17) == 0 ) ||
+ ( _strnicmp(ArgV[i],"Lookahead",9) == 0 ) ||
+ ( _strnicmp(ArgV[i],"PF",2) == 0 ) ||
+ ( _strnicmp(ArgV[i],"SA",2) == 0 ) ||
+ ( _strnicmp(ArgV[i],"FA",2) == 0 ) ||
+ ( _strnicmp(ArgV[i],"GA",2) == 0 ) ||
+ ( _strnicmp(ArgV[i],"LA",2) == 0 ))
+ {
+
+ //
+ // We have found what we are looking for. Set the tmpArgC,
+ // and set tmpArgV[i] to point to it.
+ //
+
+ ++*tmpArgC;
+ tmpArgV[1] = ArgV[i];
+
+ //
+ // then make sure that it is at the end of the ArgV.
+ // This is required by ParseArguments to successfully
+ // handle parsing the OpenInstance and InfoClass
+ // arguments first.
+ //
+
+ if ( i != *ArgC - 1 )
+ {
+ ArgV[i] = ArgV[*ArgC-1];
+ //ArgV[*ArgC-1] = //tmpArgV[1];
+ }
+
+ ArgV[*ArgC-1] = NULL;
+ --*ArgC;
+
+ return TRUE;
+ }
+ }
+
+ }
+ else
+ {
+
+ //
+ // If there are no name-value pairings for the arguments, then
+ // we know the commands must be in the correct order, and the
+ // Class Specific Info argument MUST be last or 4th in ArgV.
+ //
+
+ if ( *ArgC >= 4 )
+ {
+
+ //
+ // We have found the argument, have tmpArgV reference it and
+ // return.
+ //
+
+ *tmpArgC = 2;
+ tmpArgV[1] = ArgV[3];
+
+ --*ArgC;
+ ArgV[3] = NULL;
+
+ return TRUE;
+
+ }
+ }
+
+ //
+ // Otherwise there are not enough arguments on the command
+ // line to include the Class Specific Info, or it simply does
+ // not exist on the command line, if it is needed, ti will
+ // have to be prompted for later.
+ //
+
+ return FALSE;
+}
+
+
+BOOL
+TpctlParseEnvironmentVariable(
+ IN BYTE Buffer[]
+ )
+
+// -------------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// ------------
+
+{
+ BYTE TmpBuffer[100];
+ LPSTR EndOfVar = Buffer; // Anything that isn't NULL.
+ LPSTR Variable;
+
+ //
+ // If the environment variable passed in is null, return false now.
+ //
+
+ if ( Buffer == NULL )
+ {
+ TpctlErrorLog("\n\tTpctl: Invalid Environment Variable Format \"%%\".\n",NULL);
+ return FALSE;
+ }
+
+ //
+ // Otherwise copy the variable into a temp buffer.
+ //
+
+ strcpy( TmpBuffer,&Buffer[1] );
+
+ //
+ // Now null out the '%' symbol if it exists to allow the querying
+ // of the environment variable.
+ //
+
+ EndOfVar = strchr( TmpBuffer,'%' );
+
+ if ( EndOfVar == NULL )
+ {
+ TpctlErrorLog("\n\tTpctl: Invalid Environment Variable Format \"%%%s\".\n",TmpBuffer);
+ return FALSE;
+ }
+ else
+ {
+ *EndOfVar = '\0';
+ }
+
+ //
+ // and then query the environment variable.
+ //
+
+ Variable = getenv( _strupr( TmpBuffer ));
+
+ if ( Variable == NULL )
+ {
+ TpctlErrorLog("\n\tTpctl: Undefined Environment Variable \"%%%s%%\".\n",TmpBuffer);
+ return FALSE;
+ }
+
+ strcpy( Buffer,Variable);
+
+ return TRUE;
+}
+
+
+
+BOOL
+TpctlFirstChar(
+ IN BYTE Buffer[],
+ IN BYTE Char
+ )
+{
+ LPSTR Token = Buffer;
+
+ if ( Buffer == NULL )
+ {
+ return FALSE;
+ }
+
+ while (( *Token != '\0' ) && ( *Token == ' ' ))
+ {
+ Token++; // ignore leading blanks
+ }
+
+ if ( *Token == (CHAR)Char )
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+DWORD
+TpctlGetOptionNumber(
+ IN PTESTPARAMS Options,
+ IN DWORD TestSize,
+ IN LPSTR ArgName
+ )
+
+// ------------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// -----------
+
+{
+ DWORD i;
+
+ for(i=0; i<TestSize; i++)
+ {
+ if (_stricmp(ArgName,Options[i].ArgName) == 0 )
+ {
+ return Options[i].OptionNumber;
+ }
+ if (_stricmp(ArgName,Options[i].ArgNameAbbr) == 0 )
+ {
+ return Options[i].OptionNumber;
+ }
+ }
+ return (DWORD)-1;;
+}
+
+
+DWORD
+TpctlGetOpenInstance(
+ IN DWORD ArgC,
+ IN LPSTR ArgV[]
+ )
+
+{
+ DWORD i;
+ LPSTR EqualSign;
+ LPBYTE NextToken;
+
+ //
+ // If we have no arguments, only the command, then return an error.
+ //
+
+ if ( ArgC <= 0 )
+ {
+ return (DWORD)-1;
+ }
+
+ //
+ // Otherwise walk the argument vector looking for an instance of either
+ // an OpenInstance = Value or simply return the first argument.
+ //
+
+ for (i=1; i<ArgC; i++)
+ {
+ if (( EqualSign = strchr(ArgV[i],'=')) == NULL ) // no = sign.
+ {
+ //
+ // Since there is no equal sign we know that the Open Instance
+ // must be the first argument, so simply return it.
+ //
+
+ return (strtoul(ArgV[i], &NextToken, 0));
+
+ }
+ else
+ {
+
+ //
+ // we have an argument value pair, check if its the
+ // Open Instance.
+ //
+
+ if ((_strnicmp(ArgV[i],"OI",2) == 0 ) ||
+ (_strnicmp(ArgV[i],"OpenInstance",12)))
+ {
+
+ //
+ // It is the open instance so return the value.
+ //
+
+ ++(EqualSign);
+ return ( strtoul( EqualSign,&NextToken,0 ));
+ }
+ }
+ }
+
+ return (DWORD)-1;;
+}
diff --git a/private/ntos/ndis/testprot/tpctl/parse.h b/private/ntos/ndis/testprot/tpctl/parse.h
new file mode 100644
index 000000000..c3206263a
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpctl/parse.h
@@ -0,0 +1,312 @@
+// ---------------------------------------------------
+//
+// Copyright (c) 1991 Microsoft Corporation
+//
+// Module Name:
+//
+// parse.h
+//
+// Abstract:
+//
+//
+// Author:
+//
+// Tom Adams (tomad) 11-May-1991
+//
+// Revision History:
+//
+// 11-May-1991 tomad
+// Created
+//
+// 4-27-94 timothyw
+// added externs for performance test
+// 6-8-94 timothyw
+// changes for client/server model, perf tests
+//
+// -------------------------------------------------
+
+#define sizeoftable(TableName) (sizeof(TableName) / sizeof(TableName[0]))
+
+#define NamedField(Flag) {#Flag, Flag}
+
+
+//
+// external declarations of the Command Option Argument Parse
+// Tables and their sizes.
+//
+
+
+extern
+PARSETABLE
+BooleanTable[];
+
+extern
+PARSETABLE
+PacketFilterTable [];
+
+extern
+PARSETABLE
+QueryInfoOidTable [];
+
+extern
+PARSETABLE
+SetInfoOidTable [];
+
+extern
+PARSETABLE
+MemberTypeTable [];
+
+extern
+PARSETABLE
+PacketTypeTable [];
+
+extern
+PARSETABLE
+PacketMakeUpTable [];
+
+extern
+PARSETABLE
+ResponseTypeTable [];
+
+extern
+PARSETABLE
+DelayTable [];
+
+extern
+PARSETABLE
+TestDurationTable [];
+
+extern
+PARSETABLE
+OperationTypeTable[];
+
+extern
+PARSETABLE
+KeyDbaseTable [];
+
+extern
+PARSETABLE
+ValueTypeTable[];
+
+
+//
+// external declarations of the Test Parameter Arrays and their sizes.
+//
+
+extern
+TESTPARAMS
+CommandLineOptions[];
+
+extern
+DWORD
+Num_CommandLine_Params;
+
+extern
+TESTPARAMS
+SetEnvOptions[];
+
+extern
+DWORD
+Num_SetEnv_Params;
+
+extern
+TESTPARAMS
+ReadScriptOptions[];
+
+extern
+DWORD
+Num_ReadScript_Params;
+
+extern
+TESTPARAMS
+LoggingOptions[];
+
+extern
+DWORD
+Num_Logging_Params;
+
+extern
+TESTPARAMS
+RecordingOptions[];
+
+extern
+DWORD
+Num_Recording_Params;
+
+extern
+TESTPARAMS
+PauseGoOptions[];
+
+extern
+DWORD
+Num_PauseGo_Params;
+
+extern
+TESTPARAMS
+LoadUnloadOptions[];
+
+extern
+DWORD
+Num_LoadUnload_Params;
+
+extern
+TESTPARAMS
+OpenOptions[];
+
+extern
+DWORD
+Num_Open_Params;
+
+extern
+TESTPARAMS
+SetPacketFilterOptions[];
+
+extern
+DWORD
+Num_SetPacketFilter_Params;
+
+extern
+TESTPARAMS
+SetLookaheadOptions[];
+
+extern
+DWORD
+Num_SetLookahead_Params;
+
+extern
+TESTPARAMS
+MulticastAddrOptions[];
+
+extern
+DWORD
+Num_MulticastAddr_Params;
+
+extern
+TESTPARAMS
+FunctionalAddrOptions[];
+
+extern
+DWORD
+Num_FunctionalAddr_Params;
+
+extern
+TESTPARAMS
+GroupAddrOptions[];
+
+extern
+DWORD
+Num_GroupAddr_Params;
+
+extern
+TESTPARAMS
+QueryInfoOptions[];
+
+extern
+DWORD
+Num_QueryInfo_Params;
+
+extern
+TESTPARAMS
+QueryStatsOptions[];
+
+extern
+DWORD
+Num_QueryStats_Params;
+
+extern
+TESTPARAMS
+SetInfoOptions[];
+
+extern
+DWORD
+Num_SetInfo_Params;
+
+extern
+TESTPARAMS
+SetInfoPFOptions[];
+
+extern
+DWORD
+Num_SetInfoPF_Params;
+
+extern
+TESTPARAMS
+SetInfoLAOptions[];
+
+extern
+DWORD
+Num_SetInfoLA_Params;
+
+extern
+TESTPARAMS
+SetInfoMAOptions[];
+
+extern
+DWORD
+Num_SetInfoMA_Params;
+
+extern
+TESTPARAMS
+SetInfoFAOptions[];
+
+extern
+DWORD
+Num_SetInfoFA_Params;
+
+extern
+TESTPARAMS
+SetInfoGAOptions[];
+
+extern
+DWORD
+Num_SetInfoGA_Params;
+
+extern
+TESTPARAMS
+SendOptions[];
+
+extern
+DWORD
+Num_Send_Params;
+
+extern
+TESTPARAMS
+PerfClntOptions[];
+
+extern
+DWORD
+Num_PerfClnt_Params;
+
+extern
+TESTPARAMS
+StressOptions[];
+
+extern
+DWORD
+Num_Stress_Params;
+
+extern
+TESTPARAMS
+OpenInstanceOptions[];
+
+extern
+DWORD
+Num_OpenInstance_Params;
+
+extern
+TESTPARAMS
+HelpOptions[];
+
+extern
+DWORD
+Num_Help_Params;
+
+extern
+TESTPARAMS
+RegistryOptions[];
+
+extern
+DWORD
+Num_Registry_Params;
+
+
diff --git a/private/ntos/ndis/testprot/tpctl/results.c b/private/ntos/ndis/testprot/tpctl/results.c
new file mode 100644
index 000000000..02665bf03
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpctl/results.c
@@ -0,0 +1,1312 @@
+// --------------------------------------------
+//
+// Copyright (c) 1990 Microsoft Corporation
+//
+// Module Name:
+//
+// results.c
+//
+// Abstract:
+//
+// This module handles the printing of the results of a given command.
+//
+// Author:
+//
+// Tom Adams (tomad) 2-Apr-1991
+//
+// Revision History:
+//
+// 2-Apr-1991 tomad
+//
+// created
+//
+// Sanjeev Katariya (sanjeevk)
+// 4-12-1993 #5963 Events printed out are not being used/tested for one to one
+// correspondence The IndicationStatus. Thereby I am adding a
+// MAY_DIFFER flag to the event
+//
+// Tim Wynsma (timothyw) 4-27-94
+// Added performance testing
+// 5-18-94
+// Revised output format for performance tests; cleanup
+// 6-08-94
+// Chgd perf output format for client/server model
+//
+// --------------------------------------------
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+
+#include <windows.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tpctl.h"
+#include "parse.h"
+
+
+
+VOID
+TpctlPrintResults(
+ PREQUEST_RESULTS Results,
+ DWORD CmdCode,
+ NDIS_OID OID
+ )
+
+// ----------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// ---------
+
+{
+ DWORD Status;
+ LPSTR TmpBuf;
+ DWORD BytesWritten;
+ BOOL ErrorReturned = FALSE;
+
+ TmpBuf = GlobalBuf;
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tCmdCode = %s\n",
+ TpctlGetCmdCode( CmdCode ));
+
+ if ( CmdCode == SETINFO )
+ {
+ //ASSERT( Results->OID == OID );
+ //ASSERT( Results->NdisRequestType == NdisRequestSetInformation );
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tOID = %d\n",OID);
+ }
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tReturn Status = %s\n",
+ TpctlGetStatus( Results->RequestStatus ));
+
+ if ( Results->RequestStatus != STATUS_SUCCESS )
+ {
+ ErrorReturned = TRUE;
+ }
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tRequest Pended = %s",
+ Results->RequestPended ? "TRUE" : "FALSE");
+
+ ADD_DIFF_FLAG( TmpBuf, "MAY_DIFFER" );
+
+ if ( CmdCode == OPEN )
+ {
+ if ( Results->OpenRequestStatus != NDIS_STATUS_SUCCESS )
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tWARNING: Secondary Open Request failed.\n");
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tRequest OID = 0x%08lX\n",Results->OID);
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tRequest Returned Status = %s\n",
+ TpctlGetStatus( Results->OpenRequestStatus ));
+
+ if ( Results->OpenRequestStatus != STATUS_SUCCESS )
+ {
+ ErrorReturned = TRUE;
+ }
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tBytesWritten = %d\n",
+ Results->BytesReadWritten);
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tBytesNeeded = %d\n\n",
+ Results->BytesNeeded);
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tThe open instance exists but some tests may not\n");
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\twork properly due to this failure.\n");
+ }
+ }
+
+ if ( Verbose )
+ {
+ if ( !WriteFile(GetStdHandle( STD_OUTPUT_HANDLE ),
+ GlobalBuf,
+ TmpBuf-GlobalBuf,
+ &BytesWritten,
+ NULL ))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: WriteFile to screen failed, returned 0x%lx\n",(PVOID)Status);
+ }
+ }
+
+ if ( CommandsFromScript )
+ {
+ if ( !WriteFile(Scripts[ScriptIndex].LogHandle,
+ GlobalBuf,
+ TmpBuf-GlobalBuf,
+ &BytesWritten,
+ NULL ))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: WriteFile to logfile failed, returned 0x%lx\n",(PVOID)Status);
+ }
+
+ }
+ else if ( CommandLineLogging )
+ {
+ if( !WriteFile( CommandLineLogHandle,
+ GlobalBuf,
+ (TmpBuf-GlobalBuf),
+ &BytesWritten,
+ NULL ))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: WriteFile to logfile failed, returned 0x%lx\n",(PVOID)Status);
+ }
+ }
+}
+
+
+
+VOID
+TpctlPrintStressResults(
+ IN PSTRESS_RESULTS Results,
+ IN BOOL Ack10
+ )
+
+// ---------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// --------
+
+{
+ PGLOBAL_COUNTERS gc;
+ PINSTANCE_COUNTERS ic;
+ DWORD i;
+ DWORD Status;
+ LPSTR TmpBuf;
+ DWORD BytesWritten;
+
+
+ //ASSERT( Results->Signature == STRESS_RESULTS_SIGNATURE );
+
+ TmpBuf = GlobalBuf;
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\nCLIENT STRESS STATISTICS:\n\n");
+ TmpBuf += (BYTE)sprintf(TmpBuf,"Client Address %02X-%02X-%02X-%02X-%02X-%02X - ",
+ Results->Address[0],Results->Address[1],Results->Address[2],
+ Results->Address[3],Results->Address[4],Results->Address[5]);
+ TmpBuf += (BYTE)sprintf(TmpBuf,"OpenInstance %d",Results->OpenInstance);
+
+ ADD_DIFF_FLAG( TmpBuf, "MAY_DIFFER\n" );
+ gc = &Results->Global;
+
+ for ( i=0;i<Results->NumServers;i++ )
+ {
+ ic = &Results->Servers[i].Instance;
+ gc->Sends += ic->Sends;
+ gc->Receives += ic->Receives;
+ gc->CorruptRecs = ic->CorruptRecs;
+ }
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"Total Packets Sent:\t\t%10lu\n",
+ gc->Sends);
+ TmpBuf += (BYTE)sprintf(TmpBuf,"Total Packets Received:\t\t%10lu\n",
+ gc->Receives);
+
+ if ( Ack10 == TRUE )
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"Total Packets Lost:\t\t%10lu\n\n",
+ (( 10 * gc->Sends ) - gc->Receives ));
+ }
+ else
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"Total Packets Lost:\t\t%10lu\n\n",
+ ( gc->Sends - gc->Receives ));
+ }
+
+ if ( gc->CorruptRecs > 0 )
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"Corrupted Packet Receives:\t%10lu\n\n",
+ gc->CorruptRecs);
+ }
+
+ if ( gc->InvalidPacketRecs > 0 )
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"Invalid Packet Receives:\t%10lu\n\n",
+ gc->InvalidPacketRecs);
+ }
+
+ //
+ // Display the number of packets sent/received per second.
+ //
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"Packets Per Second:\t\t%10lu",
+ Results->PacketsPerSecond );
+
+ ADD_DIFF_FLAG( TmpBuf, "MAY_DIFFER\n" );
+
+ //
+ // And then print out the information about each of the Servers
+ // involved in the test.
+ //
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"The Client had %d Server(s) for this test as follows:",
+ Results->NumServers);
+
+ ADD_DIFF_FLAG( TmpBuf, "MAY_DIFFER\n" );
+
+ for ( i=0;i<Results->NumServers;i++ )
+ {
+ //ASSERT( Results->Servers[i].Signature == STRESS_RESULTS_SIGNATURE );
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"Server # %d - ",i+1);
+ TmpBuf += (BYTE)sprintf(TmpBuf,"Address %02X-%02X-%02X-%02X-%02X-%02X - ",
+ Results->Servers[i].Address[0],Results->Servers[i].Address[1],
+ Results->Servers[i].Address[2],Results->Servers[i].Address[3],
+ Results->Servers[i].Address[4],Results->Servers[i].Address[5]);
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"OpenInstance %d",
+ Results->Servers[i].OpenInstance);
+
+ ADD_DIFF_FLAG( TmpBuf, "MAY_DIFFER" );
+ }
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\nSERVER STRESS STATISTICS:\n\n");
+ TmpBuf += (BYTE)sprintf(TmpBuf,"Server Instance Counters collected on the Client:\n\n");
+ TmpBuf += (BYTE)sprintf(TmpBuf,"Server #");
+
+ for ( i=0;i<Results->NumServers;i++ )
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"%10lu",i+1);
+ }
+ ADD_DIFF_FLAG( TmpBuf, "MAY_DIFFER\n" );
+
+ // Number of packets sent to the server.
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"S:\t");
+
+ for ( i=0;i<Results->NumServers;i++ )
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"%10lu",
+ Results->Servers[i].Instance.Sends);
+ }
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n");
+
+ // Number of packets received from the server.
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"R:\t");
+
+ for ( i=0;i<Results->NumServers;i++ )
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"%10lu",
+ Results->Servers[i].Instance.Receives);
+ }
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n");
+
+ // Number of packets lost in transit to the server and back.
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"L:\t");
+
+ for ( i=0;i<Results->NumServers;i++ )
+ {
+ if ( Ack10 == TRUE )
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"%10lu",
+ (( 10 * Results->Servers[i].Instance.Sends ) -
+ Results->Servers[i].Instance.Receives ));
+ }
+ else
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"%10lu",
+ ( Results->Servers[i].Instance.Sends -
+ Results->Servers[i].Instance.Receives ));
+ }
+ }
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n");
+
+ // Number of packet sends that pended.
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"SP:\t");
+
+ for ( i=0;i<Results->NumServers;i++ )
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"%10lu",
+ Results->Servers[i].Instance.SendPends);
+ }
+ ADD_DIFF_FLAG( TmpBuf, "MAY_DIFFER" );
+
+ // Number of packet sends pending that completed.
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"SC:\t");
+ for ( i=0;i<Results->NumServers;i++ )
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"%10lu",
+ Results->Servers[i].Instance.SendComps);
+ }
+ ADD_DIFF_FLAG( TmpBuf, "EQUAL_LAST" );
+
+ // Number of packet sends that failed.
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"SF:\t");
+ for ( i=0;i<Results->NumServers;i++ )
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"%10lu",
+ Results->Servers[i].Instance.SendFails);
+ }
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n");
+
+ // Number of corrupted packets received.
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"CR:\t");
+ for ( i=0;i<Results->NumServers;i++ )
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"%10lu",
+ Results->Servers[i].Instance.CorruptRecs);
+ }
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n");
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\nServer Instance Counters collected on the Server:\n\n");
+
+ // Number of packets received from the server.
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"R:\t");
+ for ( i=0;i<Results->NumServers;i++ )
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"%10lu",
+ Results->Servers[i].S_Instance.Receives);
+ }
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n");
+
+ // Number of packets sent to the server.
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"S:\t");
+ for ( i=0;i<Results->NumServers;i++ )
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"%10lu",
+ Results->Servers[i].S_Instance.Sends);
+ }
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n");
+
+ // Number of packets lost in transit to the server and back.
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"L:\t");
+ for ( i=0;i<Results->NumServers;i++ )
+ {
+ if ( Ack10 == TRUE )
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"%10lu",
+ (( 10 * Results->Servers[i].S_Instance.Receives ) -
+ Results->Servers[i].S_Instance.Sends ));
+ }
+ else
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"%10lu",
+ ( Results->Servers[i].S_Instance.Receives -
+ Results->Servers[i].S_Instance.Sends ));
+ }
+ }
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n");
+
+ // Number of packets sends that failed.
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"SF:\t");
+ for ( i=0;i<Results->NumServers;i++ )
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"%10lu",
+ Results->Servers[i].S_Instance.SendFails);
+ }
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n");
+
+ // Number of packets sends that pended.
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"SP:\t");
+ for ( i=0;i<Results->NumServers;i++ )
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"%10lu",
+ Results->Servers[i].S_Instance.SendPends);
+ }
+ ADD_DIFF_FLAG( TmpBuf, "MAY_DIFFER" );
+
+ // Number of packets sends pending that completed.
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"SC:\t");
+ for ( i=0;i<Results->NumServers;i++ )
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"%10lu",
+ Results->Servers[i].S_Instance.SendComps);
+ }
+ ADD_DIFF_FLAG( TmpBuf, "EQUAL_LAST" );
+
+ // Number of transfer datas on packets.
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"TD:\t");
+ for ( i=0;i<Results->NumServers;i++ )
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"%10lu",
+ Results->Servers[i].S_Instance.XferData);
+ }
+ ADD_DIFF_FLAG( TmpBuf, "MAY_DIFFER" );
+
+ // Number of transfer datas on packets that pended.
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"TDP:\t");
+ for ( i=0;i<Results->NumServers;i++ )
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"%10lu",
+ Results->Servers[i].S_Instance.XferDataPends);
+ }
+ ADD_DIFF_FLAG( TmpBuf, "MAY_DIFFER" );
+
+ // Number of transfer datas on packets that completed.
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"TDC:\t");
+ for ( i=0;i<Results->NumServers;i++ )
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"%10lu",
+ Results->Servers[i].S_Instance.XferDataComps);
+ }
+ ADD_DIFF_FLAG( TmpBuf, "EQUAL_LAST" );
+
+ // Number of transfer datas on packets that failed.
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"TDF:\t");
+ for ( i=0;i<Results->NumServers;i++ )
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"%10lu",
+ Results->Servers[i].S_Instance.XferDataFails);
+ }
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n");
+
+ if ( Verbose )
+ {
+ if ( !WriteFile(GetStdHandle( STD_OUTPUT_HANDLE ),
+ GlobalBuf,
+ TmpBuf-GlobalBuf,
+ &BytesWritten,
+ NULL ))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: WriteFile to screen failed, returned 0x%lx\n",(PVOID)Status);
+ }
+ }
+
+ if ( CommandsFromScript )
+ {
+ if ( !WriteFile(Scripts[ScriptIndex].LogHandle,
+ GlobalBuf,
+ TmpBuf-GlobalBuf,
+ &BytesWritten,
+ NULL ))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: WriteFile to logfile failed, returned 0x%lx\n",(PVOID)Status);
+ }
+
+ }
+ else if ( CommandLineLogging )
+ {
+ if ( !WriteFile(CommandLineLogHandle,
+ GlobalBuf,
+ TmpBuf-GlobalBuf,
+ &BytesWritten,
+ NULL ))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: WriteFile to logfile failed, returned 0x%lx\n",(PVOID)Status);
+ }
+ }
+
+ TpctlZeroStressStatistics( Results );
+}
+
+
+
+VOID
+TpctlPrintSendResults(
+ PSEND_RECEIVE_RESULTS Results
+ )
+
+// ----
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// -----
+
+{
+ DWORD Status;
+ LPSTR TmpBuf;
+ DWORD BytesWritten;
+
+
+ //ASSERT( Results->Signature == SENDREC_RESULTS_SIGNATURE );
+
+ TmpBuf = GlobalBuf;
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tPacket Sends = %10lu\n",
+ Results->Counters.Sends);
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tPacket Pends = %10lu",
+ Results->Counters.SendPends);
+
+ ADD_DIFF_FLAG( TmpBuf, "MAY_DIFFER" );
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tPacket Send Completes = %10lu",
+ Results->Counters.SendComps);
+
+ ADD_DIFF_FLAG( TmpBuf, "EQUAL_LAST" );
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tPacket Send Fails = %10lu\n",
+ Results->Counters.SendFails);
+
+ if ( Verbose )
+ {
+ if ( !WriteFile(GetStdHandle( STD_OUTPUT_HANDLE ),
+ GlobalBuf,
+ TmpBuf-GlobalBuf,
+ &BytesWritten,
+ NULL ))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: WriteFile to screen failed, returned 0x%lx\n",(PVOID)Status);
+ }
+ }
+
+ if ( CommandsFromScript )
+ {
+ if ( !WriteFile(Scripts[ScriptIndex].LogHandle,
+ GlobalBuf,
+ TmpBuf-GlobalBuf,
+ &BytesWritten,
+ NULL ))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: WriteFile to logfile failed, returned 0x%lx\n",(PVOID)Status);
+ }
+
+ }
+ else if ( CommandLineLogging )
+ {
+ if ( !WriteFile(CommandLineLogHandle,
+ GlobalBuf,
+ TmpBuf-GlobalBuf,
+ &BytesWritten,
+ NULL ))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: WriteFile to logfile failed, returned 0x%lx\n",(PVOID)Status);
+ }
+ }
+}
+
+
+
+VOID
+TpctlPrintReceiveResults(
+ PSEND_RECEIVE_RESULTS Results
+ )
+
+// ------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// ----
+
+{
+ DWORD Status;
+ LPSTR TmpBuf;
+ DWORD BytesWritten;
+
+ //ASSERT( Results->Signature == SENDREC_RESULTS_SIGNATURE );
+
+ TmpBuf = GlobalBuf;
+
+ // Receive statistics
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tPacket Receives = %10lu\n",
+ Results->Counters.Receives);
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tPacket Receive Completes = %10lu",
+ Results->Counters.ReceiveComps);
+
+ ADD_DIFF_FLAG( TmpBuf, "MAY_DIFFER" );
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tCorrupt Receives = %10lu\n",
+ Results->Counters.CorruptRecs);
+
+
+ // RESEND initiated statistics
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tRESEND initiated Packet Sends = %10lu\n",
+ Results->Counters.Sends);
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tRESEND initiated Packet Send Pends = %10lu",
+ Results->Counters.SendPends);
+
+ ADD_DIFF_FLAG( TmpBuf, "MAY_DIFFER" );
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tRESEND initiated Packet Send Completes = %10lu",
+ Results->Counters.SendComps);
+
+ ADD_DIFF_FLAG( TmpBuf, "EQUAL_LAST" );
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tRESEND initiated Packet Send Fails = %10lu\n",
+ Results->Counters.SendFails);
+
+ // Transfer Data statistics
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tPacket Transfer Data = %10lu\n",
+ Results->Counters.XferData);
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tPacket Transfer Data Pends = %10lu",
+ Results->Counters.XferDataPends);
+
+ ADD_DIFF_FLAG( TmpBuf, "MAY_DIFFER" );
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tPacket Transfer Data Completes = %10lu",
+ Results->Counters.XferDataComps);
+
+ ADD_DIFF_FLAG( TmpBuf, "EQUAL_LAST" );
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tPacket Transfer Data Fails = %10lu\n",
+ Results->Counters.XferDataFails);
+
+ if ( Verbose )
+ {
+ if ( !WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),
+ GlobalBuf,
+ TmpBuf-GlobalBuf,
+ &BytesWritten,
+ NULL ))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: WriteFile to screen failed, returned 0x%lx\n",(PVOID)Status);
+ }
+ }
+
+ if ( CommandsFromScript )
+ {
+ if ( !WriteFile(Scripts[ScriptIndex].LogHandle,
+ GlobalBuf,
+ TmpBuf-GlobalBuf,
+ &BytesWritten,
+ NULL ))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: WriteFile to logfile failed, returned 0x%lx\n",(PVOID)Status);
+ }
+
+ }
+ else if ( CommandLineLogging )
+ {
+ if ( !WriteFile(CommandLineLogHandle,
+ GlobalBuf,
+ TmpBuf-GlobalBuf,
+ &BytesWritten,
+ NULL ))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: WriteFile to logfile failed, returned 0x%lx\n",(PVOID)Status);
+ }
+ }
+}
+
+
+VOID
+TpctlPrintPerformResults(
+ PPERF_RESULTS Results
+ )
+
+// ----
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// -----
+
+{
+ DWORD Status;
+ LPSTR TmpBuf;
+ DWORD BytesWritten;
+ ULONG speed;
+ double d_speed;
+ PULONG KernelPercent;
+ ULONG NumCpus;
+
+ ASSERT( Results->Signature == PERF_RESULTS_SIGNATURE );
+ if (!Results->ResultsExist)
+ {
+ return;
+ }
+
+ if (Results->Mode < 4)
+ {
+ NumCpus = CpuUsageGetData(&KernelPercent, Results->Milliseconds);
+ }
+ else if (Results->Mode < 6)
+ {
+ NumCpus = CpuUsageGetData(&KernelPercent, Results->S_Milliseconds);
+ }
+ TmpBuf = GlobalBuf;
+
+ switch(Results->Mode)
+ {
+ case 0: // client -> address
+ TmpBuf += (BYTE)sprintf(TmpBuf, "\n\nPerformance Test 0: Client -> Address\n\n");
+ break;
+
+ case 1: // client -> server
+ TmpBuf += (BYTE)sprintf(TmpBuf, "\n\nPerformance Test 1: Client -> Server\n\n");
+ break;
+
+ case 2: // client -> server, server ACKS
+ TmpBuf += (BYTE)sprintf(TmpBuf, "\n\nPerformance Test 2: Client -> Server with ACKS\n\n");
+ break;
+
+ case 3: // client -> server, server -> client
+ TmpBuf += (BYTE)sprintf(TmpBuf, "\n\nPerformance Test 3: Client <-> Server\n\n");
+ break;
+
+ case 4: // server -> client
+ TmpBuf += (BYTE)sprintf(TmpBuf, "\n\nPerformance Test 4: Server -> Client\n\n");
+ break;
+
+ case 5: // client REQS, server -> client
+ TmpBuf += (BYTE)sprintf(TmpBuf, "\n\nPerformance Test 5: Server -> Client with REQS\n\n");
+ break;
+
+ default:
+ printf("\n\nUnknown performance Test: %d\n\n", Results->Mode);
+ return;
+
+ }
+ if (!NumCpus)
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf, "Cpu usage information not available\n\n");
+ }
+ else if (NumCpus == 1)
+ {
+ if (KernelPercent[0] > 1000)
+ {
+ KernelPercent[0] = 1000;
+ }
+ TmpBuf += (BYTE)sprintf(TmpBuf, "Cpu usage = %d.%d%%\n\n",KernelPercent[0]/10, KernelPercent[0]%10);
+ }
+ else
+ {
+ ULONG cpucnt;
+ ULONG *procPercent;
+
+ procPercent = &KernelPercent[1];
+ TmpBuf += (BYTE)sprintf(TmpBuf, "Cpu usage per processor: ");
+
+ for(cpucnt=0; cpucnt < NumCpus; cpucnt++)
+ {
+ if ( (cpucnt != 0) && ((cpucnt % 4) == 0) )
+ {
+ ADD_SKIP_FLAG( TmpBuf, "SKIP_LINE" );
+ TmpBuf += (BYTE)sprintf(TmpBuf, " ");
+ }
+ if (*procPercent > 1000)
+ {
+ *procPercent = 1000;
+ }
+ TmpBuf += (BYTE)sprintf(TmpBuf, "#%d - %d.%d%% ",
+ cpucnt, *procPercent/10, *procPercent%10);
+ }
+ ADD_SKIP_FLAG( TmpBuf, "SKIP_LINE" );
+ ADD_SKIP_FLAG( TmpBuf, "SKIP_LINE" );
+ TmpBuf += (BYTE)sprintf(TmpBuf, "Average cpu usage = %d.%d%%\n\n",
+ KernelPercent[0]/10, KernelPercent[0]%10);
+ }
+
+
+ TmpBuf += (BYTE)sprintf(TmpBuf, "Sending %d packets of %d bytes each\n\n",
+ Results->PacketCount, Results->PacketSize);
+
+ if (Results->Mode < 4)
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf, "Client transmission statistics\n\n");
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tPackets Sent = %10lu\n", Results->Sends);
+ if (Results->SendFails)
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tPacket Send Failures = %10lu\n",
+ Results->SendFails);
+ }
+ if (Results -> Restarts)
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tRestarts Required = %10lu\n",
+ Results->Restarts);
+ }
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tElapsed time = %10lu milliseconds\n",
+ Results->Milliseconds);
+
+ d_speed = (1.0 * Results->Sends) / Results->Milliseconds;
+ speed = (ULONG)((1000.0 * d_speed) + 0.5);
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tTransmit Rate = %10lu packets per second\n",
+ speed);
+
+ d_speed *= Results->PacketSize;
+ speed = (ULONG)(d_speed + 0.5);
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\t = %10lu Kbytes per second\n\n",
+ speed);
+
+ if (NumCpus && (Results->Mode < 2))
+ {
+ d_speed *= 100.0;
+ d_speed /= KernelPercent[0];
+ speed = (ULONG)(d_speed + 0.5);
+ TmpBuf += (BYTE)sprintf(TmpBuf, "\tSend KB/sec/cpu = %8lu.%u\n\n", speed/10, speed%10);
+ }
+
+ if (Results->Mode > 0)
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf, "Server reception statistics\n\n");
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tPackets Received = %10lu\n",
+ Results->S_Receives);
+ if (Results->S_Receives != Results->PacketCount)
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tPackets Lost = %10lu\n",
+ Results->PacketCount - Results->S_Receives);
+ }
+ if (Results->S_SelfReceives)
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tOwn Packets Received = %10lu\n",
+ Results->S_SelfReceives);
+ }
+ }
+ }
+
+ if (Results->Mode > 2)
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf, "\nServer transmission statistics\n\n");
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tPackets Sent = %10lu\n", Results->S_Sends);
+ if (Results->S_SendFails)
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tPacket Send Failures = %10lu\n",
+ Results->S_SendFails);
+ }
+ if (Results -> S_Restarts)
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tRestarts Required = %10lu\n",
+ Results->S_Restarts);
+ }
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tElapsed time = %10lu milliseconds\n",
+ Results->S_Milliseconds);
+
+ d_speed = (1.0 * Results->S_Sends) / Results->S_Milliseconds;
+ speed = (ULONG)((1000.0 * d_speed) + 0.5);
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tTransmit Rate = %10lu packets per second\n",
+ speed);
+
+ d_speed *= Results->PacketSize;
+ speed = (ULONG)(d_speed + 0.5);
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\t = %10lu Kbytes per second\n\n",
+ speed);
+
+
+ TmpBuf += (BYTE)sprintf(TmpBuf, "Client reception statistics\n\n");
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n\tPackets Received = %10lu\n",
+ Results->Receives);
+
+ if (NumCpus && (Results->Mode == 4))
+ {
+ d_speed *= 100.0;
+ d_speed /= KernelPercent[0];
+ speed = (ULONG)(d_speed + 0.5);
+ TmpBuf += (BYTE)sprintf(TmpBuf, "\tReceive KB/sec/cpu = %8lu.%u\n\n", speed/10, speed%10);
+ }
+
+ if (Results->Receives != Results->PacketCount)
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tPackets Lost = %10lu",
+ Results->PacketCount - Results->Receives);
+ ADD_SKIP_FLAG( TmpBuf, "SKIP_LINE" );
+ }
+ if (Results->SelfReceives)
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tOwn Packets Received = %10lu",
+ Results->SelfReceives);
+ ADD_SKIP_FLAG( TmpBuf, "SKIP_LINE" );
+ }
+
+ }
+
+ TmpBuf += (BYTE)sprintf(TmpBuf, "\n\n\n");
+
+
+ if ( Verbose )
+ {
+ if ( !WriteFile(GetStdHandle( STD_OUTPUT_HANDLE ),
+ GlobalBuf,
+ TmpBuf-GlobalBuf,
+ &BytesWritten,
+ NULL ))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: WriteFile to screen failed, returned 0x%lx\n",(PVOID)Status);
+ }
+ }
+
+ if ( CommandsFromScript )
+ {
+ if ( !WriteFile(Scripts[ScriptIndex].LogHandle,
+ GlobalBuf,
+ TmpBuf-GlobalBuf,
+ &BytesWritten,
+ NULL ))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: WriteFile to logfile failed, returned 0x%lx\n",(PVOID)Status);
+ }
+
+ }
+}
+
+
+
+VOID
+TpctlPrintEventResults(
+ PEVENT_RESULTS Event
+ )
+
+// ----
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// ---
+
+{
+ DWORD Status;
+ LPSTR TmpBuf;
+ DWORD BytesWritten;
+
+
+ //ASSERT( Event->Signature == EVENT_RESULTS_SIGNATURE );
+
+ TmpBuf = GlobalBuf;
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tEvent Type = %s",
+ TpctlGetEventType( Event->TpEventType ));
+
+ //
+ // SanjeevK : #5963
+ // #11324 Enhancement
+ //
+
+ if ( ( Event->TpEventType == IndicateStatusComplete ) ||
+ ( Event->TpEventType == IndicateStatus ) )
+ {
+ ADD_SKIP_FLAG( TmpBuf, "SKIP_LINE" );
+ }
+ else
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n" );
+ }
+
+ if ( Event->QueueOverFlowed == TRUE )
+ {
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\tEvent Queue Overflowed.");
+ //
+ // SanjeevK : #5963
+ //
+ // Note: This flag was added since all this does is cause an
+ // this line to be ignored. The event however gets
+ // reported which is the primary aim of this statement.
+ //
+ ADD_SKIP_FLAG( TmpBuf, "SKIP_LINE" );
+ }
+
+ if ( Verbose )
+ {
+ if ( !WriteFile(GetStdHandle( STD_OUTPUT_HANDLE ),
+ GlobalBuf,
+ TmpBuf-GlobalBuf,
+ &BytesWritten,
+ NULL ))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: WriteFile to screen failed, returned 0x%lx\n",(PVOID)Status);
+ }
+ }
+
+ if ( CommandsFromScript )
+ {
+ if ( !WriteFile(Scripts[ScriptIndex].LogHandle,
+ GlobalBuf,
+ TmpBuf-GlobalBuf,
+ &BytesWritten,
+ NULL ))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: WriteFile to logfile failed, returned 0x%lx\n",(PVOID)Status);
+ }
+
+ }
+ else if ( CommandLineLogging )
+ {
+ if ( !WriteFile(CommandLineLogHandle,
+ GlobalBuf,
+ TmpBuf-GlobalBuf,
+ &BytesWritten,
+ NULL ))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: WriteFile to logfile failed, returned 0x%lx\n",(PVOID)Status);
+ }
+ }
+}
+
+
+
+VOID
+TpctlZeroStressStatistics(
+ PSTRESS_RESULTS Results
+ )
+
+// ----
+//
+// Routine Description:
+//
+// This routine zeros out the stress results buffer.
+//
+// Arguments:
+//
+// Results - the buffer to zero out the contents of.
+//
+// Return Value:
+//
+// None.
+//
+// ----
+
+{
+ DWORD i;
+
+ ZeroMemory (Results->Address, ADDRESS_LENGTH);
+
+ Results->OpenInstance = 0xFFFFFFFF;
+ Results->NumServers = 0;
+
+ Results->Global.Sends = 0;
+ Results->Global.Receives = 0;
+ Results->Global.CorruptRecs = 0;
+ Results->Global.InvalidPacketRecs = 0;
+
+ for ( i=0;i<MAX_SERVERS;i++ )
+ {
+ ZeroMemory (Results->Servers[i].Address, ADDRESS_LENGTH);
+
+ Results->Servers[i].OpenInstance = 0xFFFFFFFF;
+ Results->Servers[i].StatsRcvd = FALSE;
+
+ Results->Servers[i].Instance.Sends = 0;
+ Results->Servers[i].Instance.SendPends = 0;
+ Results->Servers[i].Instance.SendComps = 0;
+ Results->Servers[i].Instance.SendFails = 0;
+ Results->Servers[i].Instance.Receives = 0;
+ Results->Servers[i].Instance.CorruptRecs = 0;
+
+ Results->Servers[i].S_Instance.Sends = 0;
+ Results->Servers[i].S_Instance.SendPends = 0;
+ Results->Servers[i].S_Instance.SendComps = 0;
+ Results->Servers[i].S_Instance.SendFails = 0;
+ Results->Servers[i].S_Instance.Receives = 0;
+ Results->Servers[i].S_Instance.CorruptRecs = 0;
+
+ Results->Servers[i].S_Global.Sends = 0;
+ Results->Servers[i].S_Global.Receives = 0;
+ Results->Servers[i].S_Global.CorruptRecs = 0;
+ Results->Servers[i].S_Global.InvalidPacketRecs = 0;
+ }
+}
+
+
+
+DWORD
+TpctlLog(
+ LPSTR String,
+ PVOID Input
+ )
+{
+ DWORD Status;
+
+ //
+ // If we are in verbose mode, then print the string to the screen.
+ //
+
+ if ( Verbose )
+ {
+ printf( String,Input );
+
+ //
+ // If we are reading commands from a script write the string to
+ // the script log file.
+ //
+
+ if ( CommandsFromScript )
+ {
+ Status = TpctlScriptLog( String, Input );
+ }
+
+ //
+ // Otherwise if we are logging commands entered by hand write
+ // the string to the commandline log file.
+ //
+
+ else if ( CommandLineLogging )
+ {
+ Status = TpctlCmdLneLog( String,Input );
+ }
+ }
+
+ return NO_ERROR;
+}
+
+
+
+DWORD
+TpctlErrorLog(
+ LPSTR String,
+ PVOID Input
+ )
+{
+ DWORD Status;
+
+ //
+ // First print the error message to the screen.
+ //
+
+ printf( String,Input );
+
+ //
+ // If we are reading commands from a script write the string to
+ // the script log file.
+ //
+
+ if ( CommandsFromScript )
+ {
+ Status = TpctlScriptLog( String, Input );
+ }
+
+ //
+ // Otherwise we are logging commands entered by hand write the
+ // string to the commandline log file.
+ //
+
+ else if ( CommandLineLogging )
+ {
+ Status = TpctlCmdLneLog( String,Input );
+ }
+
+ return NO_ERROR;
+}
+
+
+
+DWORD
+TpctlScriptLog(
+ LPSTR String,
+ PVOID Input
+ )
+{
+ DWORD Status;
+ BYTE Buffer[0x100];
+ DWORD BytesWritten;
+
+ //
+ // If we are reading commands from a script write the string to
+ // the script's log file.
+ //
+
+ if ( CommandsFromScript )
+ {
+ //
+ // set up the buffer that will print it to the logfile, and write
+ // it out.
+ //
+
+ sprintf( Buffer,String,Input );
+
+ if ( !WriteFile(Scripts[ScriptIndex].LogHandle,
+ Buffer,
+ strlen( Buffer ),
+ &BytesWritten,
+ NULL ))
+ {
+ Status = GetLastError();
+ printf("\n\tTpctlScriptLog: write to logfile failed, returned 0x%lx\n",Status);
+ return Status;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+
+
+DWORD
+TpctlCmdLneLog(
+ LPSTR String,
+ PVOID Input
+ )
+{
+ DWORD Status;
+ BYTE Buffer[0x100];
+ DWORD BytesWritten;
+
+ //
+ // If we are logging commands entered by hand write the
+ // string to that log file. We will not do this if we are
+ // already logging commands to a scriptfile log file..
+ //
+
+ if (( CommandLineLogging ) && ( !CommandsFromScript ))
+ {
+ //
+ // Then set up the buffer that will print it to the logfile
+ //
+
+ sprintf( Buffer,String,Input );
+
+ //
+ // and print it.
+ //
+
+ if ( !WriteFile(CommandLineLogHandle,
+ Buffer,
+ strlen( Buffer ),
+ &BytesWritten,
+ NULL ))
+ {
+ Status = GetLastError();
+ printf("\n\tTpctlCmdLneLog: write to command logging file failed, returned 0x%lx\n",
+ Status);
+ return Status;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+
diff --git a/private/ntos/ndis/testprot/tpctl/sources b/private/ntos/ndis/testprot/tpctl/sources
new file mode 100644
index 000000000..a1cbfb202
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpctl/sources
@@ -0,0 +1,49 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+UMLIBS=obj\*\tpctl.lib ..\tplib\obj\*\tplib.lib \nt\public\sdk\lib\*\setargv.obj
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=testprot
+MINORCOMP=tpctl
+
+TARGETNAME=tpctl
+TARGETPATH=obj
+TARGETTYPE=PROGRAM
+
+INCLUDES=..\inc;..\..\..\inc
+
+SOURCES=init.c \
+ cmd.c \
+ parse.c \
+ results.c \
+ globals.c \
+ info.c \
+ cpuperf.c \
+ tpctl.c
+
+RELATIVE_DEPTH=..\..\..
+
+UMTYPE=console
+UMLIBS=..\tplib\obj\*\tplib.lib \
+ $(BASEDIR)\public\sdk\lib\*\setargv.obj \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib
diff --git a/private/ntos/ndis/testprot/tpctl/tp_ndis.h b/private/ntos/ndis/testprot/tpctl/tp_ndis.h
new file mode 100644
index 000000000..ac633213a
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpctl/tp_ndis.h
@@ -0,0 +1,180 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ tpc_ndis.h
+
+Abstract:
+
+ This module defines NDIS 3.0 specific DEFINE for the TPCTL app.
+
+Author:
+
+ Tom Adams (tomad) 20-Nov-1992
+
+Revision History:
+
+ 20-Nov-1992 tomad
+
+ Created
+
+--*/
+
+#include <ntddndis.h>
+
+typedef int NDIS_STATUS, *PNDIS_STATUS; // note default size
+
+//
+// Request types used by NdisRequest; constants are added for
+// all entry points in the MAC, for those that want to create
+// their own internal requests.
+//
+
+typedef enum _NDIS_REQUEST_TYPE {
+ NdisRequestQueryInformation,
+ NdisRequestSetInformation,
+ NdisRequestQueryStatistics,
+ NdisRequestOpen,
+ NdisRequestClose,
+ NdisRequestSend,
+ NdisRequestTransferData,
+ NdisRequestReset,
+ NdisRequestGeneric1,
+ NdisRequestGeneric2,
+ NdisRequestGeneric3,
+ NdisRequestGeneric4
+} NDIS_REQUEST_TYPE, *PNDIS_REQUEST_TYPE;
+
+
+/*
+ * Medium Ndis Driver is running on
+ *
+ *
+ * typedef enum _NDIS_MEDIUM {
+ * NdisMedium802_3,
+ * NdisMedium802_5,
+ * NdisMediumFddi,
+ * NdisMediumAsync,
+ * NdisMediumLocalTalk,
+ * NdisMediumDix
+ * } NDIS_MEDIUM, *PNDIS_MEDIUM
+ *
+ * SanjeevK: Took out this definition since this structure is now defined in
+ * NTDDNDIS.H
+ *
+ */
+
+//
+// NDIS_STATUS values
+//
+
+#define NDIS_STATUS_SUCCESS ((NDIS_STATUS) STATUS_SUCCESS)
+#define NDIS_STATUS_PENDING ((NDIS_STATUS) STATUS_PENDING)
+#define NDIS_STATUS_NOT_RECOGNIZED ((NDIS_STATUS)0x00010001L)
+#define NDIS_STATUS_NOT_COPIED ((NDIS_STATUS)0x00010002L)
+
+#define NDIS_STATUS_ONLINE ((NDIS_STATUS)0x40010003L)
+#define NDIS_STATUS_RESET_START ((NDIS_STATUS)0x40010004L)
+#define NDIS_STATUS_RESET_END ((NDIS_STATUS)0x40010005L)
+#define NDIS_STATUS_RING_STATUS ((NDIS_STATUS)0x40010006L)
+#define NDIS_STATUS_CLOSED ((NDIS_STATUS)0x40010007L)
+#define NDIS_STATUS_WAN_LINE_UP ((NDIS_STATUS)0x40010008L)
+#define NDIS_STATUS_WAN_LINE_DOWN ((NDIS_STATUS)0x40010009L)
+#define NDIS_STATUS_WAN_FRAGMENT ((NDIS_STATUS)0x4001000AL)
+
+#define NDIS_STATUS_NOT_RESETTABLE ((NDIS_STATUS)0x80010001L)
+#define NDIS_STATUS_SOFT_ERRORS ((NDIS_STATUS)0x80010003L)
+#define NDIS_STATUS_HARD_ERRORS ((NDIS_STATUS)0x80010004L)
+
+#define NDIS_STATUS_FAILURE ((NDIS_STATUS) STATUS_UNSUCCESSFUL)
+#define NDIS_STATUS_RESOURCES ((NDIS_STATUS) \
+ STATUS_INSUFFICIENT_RESOURCES)
+#define NDIS_STATUS_CLOSING ((NDIS_STATUS)0xC0010002L)
+#define NDIS_STATUS_BAD_VERSION ((NDIS_STATUS)0xC0010004L)
+#define NDIS_STATUS_BAD_CHARACTERISTICS ((NDIS_STATUS)0xC0010005L)
+#define NDIS_STATUS_ADAPTER_NOT_FOUND ((NDIS_STATUS)0xC0010006L)
+#define NDIS_STATUS_OPEN_FAILED ((NDIS_STATUS)0xC0010007L)
+#define NDIS_STATUS_DEVICE_FAILED ((NDIS_STATUS)0xC0010008L)
+#define NDIS_STATUS_MULTICAST_FULL ((NDIS_STATUS)0xC0010009L)
+#define NDIS_STATUS_MULTICAST_EXISTS ((NDIS_STATUS)0xC001000AL)
+#define NDIS_STATUS_MULTICAST_NOT_FOUND ((NDIS_STATUS)0xC001000BL)
+#define NDIS_STATUS_REQUEST_ABORTED ((NDIS_STATUS)0xC001000CL)
+#define NDIS_STATUS_RESET_IN_PROGRESS ((NDIS_STATUS)0xC001000DL)
+#define NDIS_STATUS_CLOSING_INDICATING ((NDIS_STATUS)0xC001000EL)
+#define NDIS_STATUS_NOT_SUPPORTED ((NDIS_STATUS)STATUS_NOT_SUPPORTED)
+#define NDIS_STATUS_INVALID_PACKET ((NDIS_STATUS)0xC001000FL)
+#define NDIS_STATUS_OPEN_LIST_FULL ((NDIS_STATUS)0xC0010010L)
+#define NDIS_STATUS_ADAPTER_NOT_READY ((NDIS_STATUS)0xC0010011L)
+#define NDIS_STATUS_ADAPTER_NOT_OPEN ((NDIS_STATUS)0xC0010012L)
+#define NDIS_STATUS_NOT_INDICATING ((NDIS_STATUS)0xC0010013L)
+#define NDIS_STATUS_INVALID_LENGTH ((NDIS_STATUS)0xC0010014L)
+#define NDIS_STATUS_INVALID_DATA ((NDIS_STATUS)0xC0010015L)
+#define NDIS_STATUS_BUFFER_TOO_SHORT ((NDIS_STATUS)0xC0010016L)
+#define NDIS_STATUS_INVALID_OID ((NDIS_STATUS)0xC0010017L)
+#define NDIS_STATUS_ADAPTER_REMOVED ((NDIS_STATUS)0xC0010018L)
+#define NDIS_STATUS_UNSUPPORTED_MEDIA ((NDIS_STATUS)0xC0010019L)
+#define NDIS_STATUS_GROUP_ADDRESS_IN_USE ((NDIS_STATUS)0xC001001AL)
+#define NDIS_STATUS_FILE_NOT_FOUND ((NDIS_STATUS)0xC001001BL)
+#define NDIS_STATUS_ERROR_READING_FILE ((NDIS_STATUS)0xC001001CL)
+#define NDIS_STATUS_ALREADY_MAPPED ((NDIS_STATUS)0xC001001DL)
+#define NDIS_STATUS_RESOURCE_CONFLICT ((NDIS_STATUS)0xC001001EL)
+
+#define NDIS_STATUS_TOKEN_RING_OPEN_ERROR ((NDIS_STATUS)0xC0011000L)
+
+
+//
+// used in error logging
+//
+
+#define NDIS_ERROR_CODE ULONG
+
+#define NDIS_ERROR_CODE_RESOURCE_CONFLICT EVENT_NDIS_RESOURCE_CONFLICT
+#define NDIS_ERROR_CODE_OUT_OF_RESOURCES EVENT_NDIS_OUT_OF_RESOURCE
+#define NDIS_ERROR_CODE_HARDWARE_FAILURE EVENT_NDIS_HARDWARE_FAILURE
+#define NDIS_ERROR_CODE_ADAPTER_NOT_FOUND EVENT_NDIS_ADAPTER_NOT_FOUND
+#define NDIS_ERROR_CODE_INTERRUPT_CONNECT EVENT_NDIS_INTERRUPT_CONNECT
+#define NDIS_ERROR_CODE_DRIVER_FAILURE EVENT_NDIS_DRIVER_FAILURE
+#define NDIS_ERROR_CODE_BAD_VERSION EVENT_NDIS_BAD_VERSION
+#define NDIS_ERROR_CODE_TIMEOUT EVENT_NDIS_TIMEOUT
+#define NDIS_ERROR_CODE_NETWORK_ADDRESS EVENT_NDIS_NETWORK_ADDRESS
+#define NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION EVENT_NDIS_UNSUPPORTED_CONFIGURATION
+#define NDIS_ERROR_CODE_INVALID_VALUE_FROM_ADAPTER EVENT_NDIS_INVALID_VALUE_FROM_ADAPTER
+#define NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER EVENT_NDIS_MISSING_CONFIGURATION_PARAMETER
+#define NDIS_ERROR_CODE_BAD_IO_BASE_ADDRESS EVENT_NDIS_BAD_IO_BASE_ADDRESS
+#define NDIS_ERROR_CODE_RECEIVE_SPACE_SMALL EVENT_NDIS_RECEIVE_SPACE_SMALL
+#define NDIS_ERROR_CODE_ADAPTER_DISABLED EVENT_NDIS_ADAPTER_DISABLED
+
+
+
+//
+// Ndis Packet Filter Bits
+//
+
+#define NDIS_PACKET_TYPE_DIRECTED 0x0001
+#define NDIS_PACKET_TYPE_MULTICAST 0x0002
+#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x0004
+#define NDIS_PACKET_TYPE_BROADCAST 0x0008
+#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x0010
+#define NDIS_PACKET_TYPE_PROMISCUOUS 0x0020
+#define NDIS_PACKET_TYPE_MAC_FRAME 0x8000
+#define NDIS_PACKET_TYPE_FUNCTIONAL 0x4000
+#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x2000
+#define NDIS_PACKET_TYPE_GROUP 0x1000
+
+//
+// Ndis Token-Ring Ring Status Codes
+//
+
+#define NDIS_RING_SIGNAL_LOSS 0x00008000
+#define NDIS_RING_HARD_ERROR 0x00004000
+#define NDIS_RING_SOFT_ERROR 0x00002000
+#define NDIS_RING_TRANSMIT_BEACON 0x00001000
+#define NDIS_RING_LOBE_WIRE_FAULT 0x00000800
+#define NDIS_RING_AUTO_REMOVAL_ERROR 0x00000400
+#define NDIS_RING_REMOVE_RECEIVED 0x00000200
+#define NDIS_RING_COUNTER_OVERFLOW 0x00000100
+#define NDIS_RING_SINGLE_STATION 0x00000080
+#define NDIS_RING_RING_RECOVERY 0x00000040
+
diff --git a/private/ntos/ndis/testprot/tpctl/tpctl.c b/private/ntos/ndis/testprot/tpctl/tpctl.c
new file mode 100644
index 000000000..83b75b1a5
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpctl/tpctl.c
@@ -0,0 +1,3852 @@
+// --------------------------------------
+//
+// Copyright (c) 1990 Microsoft Corporation
+//
+// Module Name:
+//
+// tpctl.c
+//
+// Abstract:
+//
+// This is the main component of the NDIS 3.0 MAC Tester control program.
+//
+// Author:
+//
+// Tom Adams (tomad) 2-Apr-1991
+//
+// Revision History:
+//
+// 2-Apr-1991 tomad
+//
+// created
+//
+// Sanjeev Katariya (sanjeevk) 4-6-1993
+//
+// Bug #5203: Changed the routine TpRunTest() at the point where the OPEN returns
+// and the InformationBuffer contains information about the address and
+// the Medium Type. This was made in order to satisfy the correct setting
+// of the OID on multicast addresses(FDDI, 802.3).
+// Added support for commands DISABLE, ENABLE, SHELL, RECORDINGENABLE, RECORDINGDISABLE,
+// Tpctl Options w,c and ?, fixed multicast address accounting
+//
+// Tim Wynsma (timothyw) 4-27-94
+// Added performance testing
+// 5-18-94
+// Added hooks for globvars; cleanup
+// 6-08-94
+// Chgd perf test to client/server model
+//
+// --------------------------------
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+
+#include <windows.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tpctl.h"
+#include "parse.h"
+
+BOOL ToolActive = TRUE;
+
+extern BOOL WriteThrough ;
+extern BOOL ContinueOnError;
+
+
+
+DWORD
+TpctlRunTest(
+ IN HANDLE hFileHandle
+ )
+
+// -----
+//
+// Routine Description:
+//
+// This routine is the main funciton of the TPCTL program. It
+// prompts the user for commands, or reads them from the script
+// file, and then issues the call to NtDeviceIoControlFile.
+//
+// Arguments:
+//
+// IN HANDLE hFileHandle - Supplies the handle to the Test Protocol
+// driver where the IOCTLs will be directed.
+//
+// Return Value:
+//
+// DWORD - the status of the last call to take place.
+//
+// -----
+
+{
+ BYTE Buffer[TPCTL_CMDLINE_SIZE];
+ LPSTR localArgv[TPCTL_MAX_ARGC];
+ DWORD localArgc;
+ DWORD CmdCode;
+ DWORD Status = NO_ERROR;
+ NTSTATUS NtStatus;
+ HANDLE Event;
+ HANDLE Event1;
+ IO_STATUS_BLOCK IoStatusBlock;
+ IO_STATUS_BLOCK IoStatusBlock2;
+ HANDLE InputBuffer;
+ DWORD InputBufferSize = 8*IOCTL_BUFFER_SIZE;
+ HANDLE OutputBuffer;
+ HANDLE OutputBuffer2;
+ DWORD OutputBufferSize = 8*IOCTL_BUFFER_SIZE;
+ DWORD OutputBufferSize2;
+ DWORD WaitTime;
+ BOOL IoctlCommand = FALSE;
+ PCMD_ARGS CmdArgs;
+ DWORD OpenInstance;
+
+
+ InputBuffer = GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT,InputBufferSize );
+
+ if ( InputBuffer == NULL )
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tGlobalAlloc failed to alloc InputBuffer: returned 0x%lx.\n",
+ (PVOID)Status);
+ return Status;
+ }
+
+ CmdArgs = (PCMD_ARGS)InputBuffer;
+
+ OutputBuffer = GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT,OutputBufferSize );
+
+ if ( OutputBuffer == NULL )
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tGlobalAlloc failed to alloc OutputBuffer: returned 0x%lx.\n",
+ (PVOID)Status);
+ GlobalFree( InputBuffer );
+ return Status;
+ }
+
+ Event = CreateEvent( NULL,FALSE,FALSE,NULL );
+
+ if (Event == NULL)
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tCreateEvent failed: returned 0x%lx.\n",(PVOID)Status);
+ GlobalFree( InputBuffer );
+ GlobalFree( OutputBuffer );
+ return Status;
+ }
+
+ while ( ExitFlag == FALSE )
+ {
+ if ( ContinueLooping == FALSE )
+ {
+ //
+ // A Ctrl-c has been entered, If we are reading commands
+ // from a script file then reset all the open blocks, and
+ // close the script files.
+ //
+
+ TpctlResetAllOpenStates( hFileHandle );
+ TpctlCloseScripts();
+
+ ContinueLooping = TRUE;
+ }
+
+ Status = TpctlReadCommand( TPCTL_PROMPT,Buffer,TPCTL_CMDLINE_SIZE );
+
+ if ( Status != NO_ERROR )
+ {
+ printf("STATUS == Some error\n");
+
+ //
+ // there was an error in the last command entered. If we
+ // are reading commands from a script file then reset all
+ // the open blocks, and close the script files.
+ //
+ if ( !ContinueOnError )
+ {
+ TpctlResetAllOpenStates( hFileHandle );
+ TpctlCloseScripts();
+ }
+ continue;
+ }
+ else if (( !TpctlParseCommand( Buffer,
+ localArgv,
+ &localArgc,
+ TPCTL_MAX_ARGC )) &&
+ ( CommandsFromScript == TRUE ))
+ {
+ printf("which means parse command failed.\n");
+
+ if ( !ContinueOnError )
+ {
+ TpctlResetAllOpenStates( hFileHandle );
+ TpctlCloseScripts();
+ }
+ continue;
+ }
+
+ if (( localArgc <= 0 ) || ( localArgv[0][0] == ';' ))
+ {
+ continue;
+ }
+
+ CmdCode = TpctlGetCommandCode( localArgv[0] );
+
+ switch( CmdCode )
+ {
+ case VERBOSE:
+ if ( ToolActive )
+ {
+ Verbose = ( Verbose ) ? FALSE : TRUE;
+ TpctlLog("\n\tTpctl: Verbose Mode enabled.\n",NULL);
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( NULL,
+ 0,
+ 1,
+ localArgv );
+
+ }
+
+ }
+ CmdCode = CMD_COMPLETED;
+ break;
+
+ case SETENV:
+ if ( ToolActive )
+ {
+ if ( TpctlParseArguments( SetEnvOptions,
+ Num_SetEnv_Params,
+ localArgc,
+ localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( SetEnvOptions,
+ Num_SetEnv_Params,
+ localArgc,
+ localArgv );
+ }
+
+ if ( !TpctlInitCommandBuffer( CmdArgs,CmdCode ))
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ OpenInstance = CmdArgs->OpenInstance - 1;
+
+ if ( Open[OpenInstance].AdapterOpened == FALSE )
+ {
+ TpctlErrorLog(
+ "\n\tTpctl: The adapter has not been opened for Open Instance %lu.\n",
+ (PVOID)(CmdArgs->OpenInstance));
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ TpctlSaveNewEnvironmentVariables( CmdArgs->OpenInstance - 1 );
+
+ }
+ CmdCode = CMD_COMPLETED;
+ break;
+
+ case READSCRIPT:
+ if ( ToolActive )
+ {
+ if ( TpctlParseArguments( ReadScriptOptions,
+ Num_ReadScript_Params,
+ localArgc,
+ localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( ReadScriptOptions,
+ Num_ReadScript_Params,
+ localArgc,
+ localArgv );
+ }
+
+ Status = TpctlLoadFiles(GlobalCmdArgs.ARGS.FILES.ScriptFile,
+ GlobalCmdArgs.ARGS.FILES.LogFile );
+
+ if ( Status != NO_ERROR )
+ {
+ if ( !ContinueOnError )
+ {
+ TpctlResetAllOpenStates( hFileHandle );
+ TpctlCloseScripts();
+ }
+ }
+ }
+ CmdCode = CMD_COMPLETED;
+ break;
+
+ case BEGINLOGGING:
+ if( ToolActive )
+ {
+ if ( CommandsFromScript == TRUE )
+ {
+ TpctlErrorLog("\n\tTpctl: Already logging results to \"%s\".\n",
+ (PVOID)Scripts[ScriptIndex].LogFile);
+ }
+ else if ( CommandLineLogging == TRUE )
+ {
+ TpctlErrorLog("\n\tTpctl: Command Line Logging is already enabled.\n",NULL);
+ }
+ else
+ {
+ if ( TpctlParseArguments( LoggingOptions,
+ Num_Logging_Params,
+ localArgc,
+ localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( LoggingOptions,
+ Num_Logging_Params,
+ localArgc,
+ localArgv );
+ }
+
+ CommandLineLogHandle = TpctlOpenLogFile();
+
+ if ( CommandLineLogHandle == (HANDLE)-1 )
+ {
+ TpctlErrorLog("\n\tTpctl: failed to open Log File.\n",NULL);
+ }
+ else
+ {
+ CommandLineLogging = TRUE;
+ }
+ }
+ }
+ CmdCode = CMD_COMPLETED;
+ break;
+
+ case ENDLOGGING:
+ if ( ToolActive )
+ {
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( NULL,
+ 0,
+ 1,
+ localArgv );
+ }
+
+ if ( CommandLineLogging == TRUE )
+ {
+ TpctlCloseLogFile();
+ CommandLineLogging = FALSE;
+ }
+ else
+ {
+ TpctlErrorLog("\n\tTpctl: Logging is not enabled.\n\n",NULL);
+ }
+ }
+ CmdCode = CMD_COMPLETED;
+ break;
+
+ case RECORDINGENABLE:
+ if( ToolActive )
+ {
+ if ( RecordToScript == TRUE )
+ {
+ TpctlErrorLog("\n\tTpctl: Already recording commands to \"%s\".\n",
+ (PVOID)RecordScriptName );
+ }
+ else
+ {
+ if ( TpctlParseArguments( RecordingOptions,
+ Num_Recording_Params,
+ localArgc,
+ localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ ScriptRecordHandle = TpctlOpenScriptFile();
+
+ if ( ScriptRecordHandle == (HANDLE)-1 )
+ {
+ TpctlErrorLog("\n\tTpctl: failed to open script record File.\n",NULL);
+ }
+ else
+ {
+ RecordToScript = TRUE;
+ }
+ }
+ }
+ CmdCode = CMD_COMPLETED;
+ break;
+
+ case RECORDINGDISABLE:
+ if ( ToolActive )
+ {
+ if ( RecordToScript == TRUE )
+ {
+ TpctlCloseScriptFile();
+ RecordToScript = FALSE;
+ }
+ else
+ {
+ TpctlErrorLog("\n\tTpctl: Script Recording is not enabled.\n\n",NULL);
+ }
+ }
+ CmdCode = CMD_COMPLETED;
+ break;
+
+
+ case WAIT:
+ if ( ToolActive )
+ {
+ if ( localArgv[1] != NULL )
+ {
+ WaitTime = atol( localArgv[1] );
+ }
+ else
+ {
+ WaitTime = 0;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( NULL,
+ 0,
+ min(2,localArgc),
+ localArgv );
+ }
+
+ TpctlLog("\n\tTpctl: Waiting for %d seconds.\n",(PVOID)WaitTime);
+
+ //
+ // Multiply by 1000 to convert seconds to msecs for us by
+ // Sleep().
+ //
+
+ Sleep( WaitTime * 1000 );
+ }
+ CmdCode = CMD_COMPLETED;
+ break;
+
+ case GO:
+ case PAUSE:
+ if ( ToolActive )
+ {
+ if ( TpctlParseArguments( PauseGoOptions,
+ Num_PauseGo_Params - 1, // Ignore Unique Signature
+ // while parsing arguments.
+ localArgc,
+ localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( PauseGoOptions,
+ Num_PauseGo_Params,
+ localArgc,
+ localArgv );
+ }
+
+ if ( !TpctlInitCommandBuffer( CmdArgs,CmdCode ))
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ OpenInstance = CmdArgs->OpenInstance - 1;
+
+ if ( Open[OpenInstance].AdapterOpened == FALSE )
+ {
+ TpctlErrorLog(
+ "\n\tTpctl: The adapter has not been opened for Open Instance %lu.\n",
+ (PVOID)(CmdArgs->OpenInstance));
+ CmdCode = CMD_ERR;
+ break;
+ }
+ TpctlPauseGo( hFileHandle,CmdArgs,InputBufferSize,CmdCode );
+ }
+ CmdCode = CMD_COMPLETED;
+ break;
+
+ case LOAD:
+ case UNLOAD:
+ if ( ToolActive )
+ {
+ if ( TpctlParseArguments( LoadUnloadOptions,
+ Num_LoadUnload_Params,
+ localArgc,
+ localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( LoadUnloadOptions,
+ Num_LoadUnload_Params,
+ localArgc,
+ localArgv );
+ }
+ TpctlLoadUnload( CmdCode );
+ }
+ CmdCode = CMD_COMPLETED;
+ break;
+
+ case OPEN: // NdisOpenAdapter
+ if ( ToolActive )
+ {
+ if ( TpctlParseArguments( OpenOptions,
+ Num_Open_Params,
+ localArgc,
+ localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( OpenOptions,
+ Num_Open_Params,
+ localArgc,
+ localArgv );
+ }
+
+ if ( !TpctlInitCommandBuffer( CmdArgs,CmdCode ))
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ OpenInstance = CmdArgs->OpenInstance - 1;
+
+ if ( Open[OpenInstance].AdapterOpened == TRUE )
+ {
+ TpctlErrorLog(
+ "\n\tTpctl: The adapter is already opened for Open Instance %lu.\n",
+ (PVOID)(CmdArgs->OpenInstance));
+ CmdCode = CMD_ERR;
+ break;
+ }
+ }
+ else
+ {
+ CmdCode = CMD_COMPLETED;
+ }
+ break;
+
+ case CLOSE: // NdisCloseAdapter
+ if ( ToolActive )
+ {
+ if ( TpctlParseArguments( OpenInstanceOptions,
+ Num_OpenInstance_Params,
+ localArgc,
+ localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( OpenInstanceOptions,
+ Num_OpenInstance_Params,
+ localArgc,
+ localArgv );
+ }
+
+ if ( !TpctlInitCommandBuffer( CmdArgs,CmdCode ))
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ OpenInstance = CmdArgs->OpenInstance - 1;
+
+ if ( Open[OpenInstance].AdapterOpened == FALSE )
+ {
+ TpctlErrorLog(
+ "\n\tTpctl: The adapter has not been opened for Open Instance %lu.\n",
+ (PVOID)(CmdArgs->OpenInstance));
+ CmdCode = CMD_COMPLETED;
+ break;
+ }
+ }
+ else
+ {
+ CmdCode = CMD_COMPLETED;
+ }
+ break;
+
+ case SETPF:
+ if ( ToolActive )
+ {
+ if ( TpctlParseArguments( SetPacketFilterOptions,
+ Num_SetPacketFilter_Params,
+ localArgc,
+ localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( SetPacketFilterOptions,
+ Num_SetPacketFilter_Params,
+ localArgc,
+ localArgv );
+ }
+
+ if ( !TpctlInitCommandBuffer( CmdArgs,CmdCode ))
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ OpenInstance = CmdArgs->OpenInstance - 1;
+
+ if ( Open[OpenInstance].AdapterOpened == FALSE )
+ {
+ TpctlErrorLog(
+ "\n\tTpctl: The adapter has not been opened for Open Instance %lu.\n",
+ (PVOID)(CmdArgs->OpenInstance));
+ CmdCode = CMD_ERR;
+ break;
+ }
+ }
+ else
+ {
+ CmdCode = CMD_COMPLETED;
+ }
+ break;
+
+ case SETLA:
+ if ( ToolActive )
+ {
+ if ( TpctlParseArguments( SetLookaheadOptions,
+ Num_SetLookahead_Params,
+ localArgc,
+ localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( SetLookaheadOptions,
+ Num_SetLookahead_Params,
+ localArgc,
+ localArgv );
+ }
+
+ if ( !TpctlInitCommandBuffer( CmdArgs,CmdCode ))
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ OpenInstance = CmdArgs->OpenInstance - 1;
+
+ if ( Open[OpenInstance].AdapterOpened == FALSE )
+ {
+ TpctlErrorLog(
+ "\n\tTpctl: The adapter has not been opened for Open Instance %lu.\n",
+ (PVOID)(CmdArgs->OpenInstance));
+ CmdCode = CMD_ERR;
+ break;
+ }
+ }
+ else
+ {
+ CmdCode = CMD_COMPLETED;
+ }
+ break;
+
+ case ADDMA:
+ case DELMA:
+ if ( ToolActive )
+ {
+ if ( TpctlParseArguments( MulticastAddrOptions,
+ Num_MulticastAddr_Params,
+ localArgc,
+ localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( MulticastAddrOptions,
+ Num_MulticastAddr_Params,
+ localArgc,
+ localArgv );
+ }
+
+ if ( !TpctlInitCommandBuffer( CmdArgs,CmdCode ))
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ OpenInstance = CmdArgs->OpenInstance - 1;
+
+ if ( Open[OpenInstance].AdapterOpened == FALSE )
+ {
+ TpctlErrorLog(
+ "\n\tTpctl: The adapter has not been opened for Open Instance %lu.\n",
+ (PVOID)(CmdArgs->OpenInstance));
+ CmdCode = CMD_ERR;
+ break;
+ }
+ }
+ else
+ {
+ CmdCode = CMD_COMPLETED;
+ }
+ break;
+
+ case SETFA:
+ if ( ToolActive )
+ {
+ if ( TpctlParseArguments( FunctionalAddrOptions,
+ Num_FunctionalAddr_Params,
+ localArgc,
+ localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( FunctionalAddrOptions,
+ Num_FunctionalAddr_Params,
+ localArgc,
+ localArgv );
+ }
+
+ if ( !TpctlInitCommandBuffer( CmdArgs,CmdCode ))
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ OpenInstance = CmdArgs->OpenInstance - 1;
+
+ if ( Open[OpenInstance].AdapterOpened == FALSE )
+ {
+ TpctlErrorLog(
+ "\n\tTpctl: The adapter has not been opened for Open Instance %lu.\n",
+ (PVOID)(CmdArgs->OpenInstance));
+ CmdCode = CMD_ERR;
+ break;
+ }
+ }
+ else
+ {
+ CmdCode = CMD_COMPLETED;
+ }
+ break;
+
+ case SETGA:
+ if ( ToolActive )
+ {
+ if ( TpctlParseArguments( GroupAddrOptions,
+ Num_GroupAddr_Params,
+ localArgc,
+ localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( GroupAddrOptions,
+ Num_GroupAddr_Params,
+ localArgc,
+ localArgv );
+ }
+
+ if ( !TpctlInitCommandBuffer( CmdArgs,CmdCode ))
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ OpenInstance = CmdArgs->OpenInstance - 1;
+
+ if ( Open[OpenInstance].AdapterOpened == FALSE )
+ {
+ TpctlErrorLog(
+ "\n\tTpctl: The adapter has not been opened for Open Instance %lu.\n",
+ (PVOID)(CmdArgs->OpenInstance));
+ CmdCode = CMD_ERR;
+ break;
+ }
+ }
+ else
+ {
+ CmdCode = CMD_COMPLETED;
+ }
+ break;
+
+ case SETINFO: // NdisSetInformation
+ if ( ToolActive )
+ {
+ DWORD tmpArgc = 1;
+ LPSTR tmpArgv[2];
+
+ if ( localArgc > 1 )
+ {
+ TpctlParseSetInfoArguments( &localArgc,
+ localArgv,
+ &tmpArgc,
+ tmpArgv );
+ }
+
+ if ( TpctlParseArguments( SetInfoOptions,
+ Num_SetInfo_Params,
+ localArgc,
+ localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( SetInfoOptions,
+ Num_SetInfo_Params,
+ localArgc,
+ localArgv );
+ }
+
+ //
+ // If the information class argument is one of Station Address,
+ // Functional Address, or Lookahead Size, then we need to
+ // continue parsing the arguments because we have not found
+ // the class specific argument needed in these three cases.
+ //
+
+ switch ( GlobalCmdArgs.ARGS.TPSET.OID )
+ {
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ if ( TpctlParseArguments( SetInfoPFOptions,
+ Num_SetInfoPF_Params,
+ tmpArgc,
+ tmpArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ }
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( SetInfoPFOptions,
+ Num_SetInfoPF_Params,
+ tmpArgc,
+ tmpArgv );
+ }
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ if ( TpctlParseArguments( SetInfoLAOptions,
+ Num_SetInfoLA_Params,
+ tmpArgc,
+ tmpArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ }
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( SetInfoLAOptions,
+ Num_SetInfoLA_Params,
+ tmpArgc,
+ tmpArgv );
+ }
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+ if ( TpctlParseArguments( SetInfoMAOptions,
+ Num_SetInfoMA_Params,
+ tmpArgc,
+ tmpArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ }
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( SetInfoMAOptions,
+ Num_SetInfoMA_Params,
+ tmpArgc,
+ tmpArgv );
+ }
+ break;
+
+ case OID_FDDI_LONG_MULTICAST_LIST :
+ if ( TpctlParseArguments( SetInfoMAOptions,
+ Num_SetInfoMA_Params,
+ tmpArgc,
+ tmpArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ }
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( SetInfoMAOptions,
+ Num_SetInfoMA_Params,
+ tmpArgc,
+ tmpArgv );
+ }
+ break;
+
+ case OID_FDDI_SHORT_CURRENT_ADDR :
+
+ //
+ // Not implemented yet
+ //
+
+ break;
+
+ case OID_FDDI_LONG_CURRENT_ADDR :
+
+ //
+ // Not implemented yet
+ //
+
+ break;
+
+ case OID_FDDI_SHORT_MULTICAST_LIST :
+
+ //
+ // Not implemented yet
+ //
+
+ break;
+
+ case OID_802_5_CURRENT_FUNCTIONAL:
+ if ( TpctlParseArguments( SetInfoFAOptions,
+ Num_SetInfoFA_Params,
+ tmpArgc,
+ tmpArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ }
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( SetInfoFAOptions,
+ Num_SetInfoFA_Params,
+ tmpArgc,
+ tmpArgv );
+ }
+ break;
+
+ case OID_802_5_CURRENT_GROUP:
+ if ( TpctlParseArguments( SetInfoGAOptions,
+ Num_SetInfoGA_Params,
+ tmpArgc,
+ tmpArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ }
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( SetInfoGAOptions,
+ Num_SetInfoGA_Params,
+ tmpArgc,
+ tmpArgv );
+ }
+ break;
+
+ } // end switch
+
+ if ( CmdCode == CMD_ERR )
+ {
+ break;
+ }
+
+ if ( !TpctlInitCommandBuffer(CmdArgs,SETINFO))
+ {
+ CmdCode = CMD_COMPLETED;
+ break;
+ }
+
+ OpenInstance = CmdArgs->OpenInstance - 1;
+
+ if ( Open[OpenInstance].AdapterOpened == FALSE )
+ {
+ TpctlErrorLog(
+ "\n\tTpctl: The adapter has not been opened for Open Instance %lu.\n",
+ (PVOID)(CmdArgs->OpenInstance));
+ CmdCode = CMD_ERR;
+ break;
+ }
+ break;
+ }
+ else
+ {
+ CmdCode = CMD_COMPLETED;
+ }
+ break;
+
+ case QUERYINFO:
+ if ( ToolActive )
+ {
+ if ( TpctlParseArguments( QueryInfoOptions,
+ Num_QueryInfo_Params,
+ localArgc,
+ localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( QueryInfoOptions,
+ Num_QueryInfo_Params,
+ localArgc,
+ localArgv );
+ }
+
+ if ( !TpctlInitCommandBuffer( CmdArgs,CmdCode ))
+ {
+ CmdCode = CMD_COMPLETED;
+ break;
+ }
+
+ OpenInstance = CmdArgs->OpenInstance - 1;
+
+ if ( Open[OpenInstance].AdapterOpened == FALSE )
+ {
+ TpctlErrorLog(
+ "\n\tTpctl: The adapter has not been opened for Open Instance %lu.\n",
+ (PVOID)(CmdArgs->OpenInstance));
+ CmdCode = CMD_ERR;
+ break;
+ }
+ }
+ else
+ {
+ CmdCode = CMD_COMPLETED;
+ }
+ break;
+
+ case QUERYSTATS:
+ if ( ToolActive )
+ {
+ if ( TpctlParseArguments( QueryStatsOptions,
+ Num_QueryStats_Params,
+ localArgc,
+ localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( QueryStatsOptions,
+ Num_QueryStats_Params,
+ localArgc,
+ localArgv );
+ }
+
+ TpctlQueryStatistics( GlobalCmdArgs.ARGS.TPQUERYSTATS.DeviceName,
+ GlobalCmdArgs.ARGS.TPQUERYSTATS.OID,
+ NULL, //StatsBuffer,
+ 0); //BufLen
+
+ }
+ CmdCode = CMD_COMPLETED;
+ break;
+
+ case RESET: // NdisReset
+ if ( ToolActive )
+ {
+ if ( TpctlParseArguments( OpenInstanceOptions,
+ Num_OpenInstance_Params,
+ localArgc,
+ localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( OpenInstanceOptions,
+ Num_OpenInstance_Params,
+ localArgc,
+ localArgv );
+ }
+
+ if ( !TpctlInitCommandBuffer( CmdArgs,CmdCode ))
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ OpenInstance = CmdArgs->OpenInstance - 1;
+
+ if ( Open[OpenInstance].AdapterOpened == FALSE )
+ {
+ TpctlErrorLog(
+ "\n\tTpctl: The adapter has not been opened for Open Instance %lu.\n",
+ (PVOID)(CmdArgs->OpenInstance));
+ CmdCode = CMD_ERR;
+ break;
+ }
+ }
+ else
+ {
+ CmdCode = CMD_COMPLETED;
+ }
+ break;
+
+ case SEND: // NdisSend
+ if ( ToolActive )
+ {
+ if ( TpctlParseArguments( SendOptions,
+ Num_Send_Params,
+ localArgc,
+ localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( SendOptions,
+ Num_Send_Params,
+ localArgc,
+ localArgv );
+ }
+
+ if ( !TpctlInitCommandBuffer( CmdArgs,CmdCode ))
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ OpenInstance = CmdArgs->OpenInstance - 1;
+
+ if ( Open[OpenInstance].AdapterOpened == FALSE )
+ {
+ TpctlErrorLog(
+ "\n\tTpctl: The adapter has not been opened for Open Instance %lu.\n",
+ (PVOID)(CmdArgs->OpenInstance));
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ //
+ // Is this Open Instance already sending packets?
+ //
+
+ if ( Open[OpenInstance].Sending == TRUE )
+ {
+ //
+ // If so, print an error message and prompt for next command.
+ //
+
+ TpctlErrorLog(
+ "\n\tTpctl: Packets are currently being sent on Open Instance %lu.\n",
+ (PVOID)(CmdArgs->OpenInstance));
+ CmdCode = CMD_ERR;
+ break;
+ }
+ else if ( Open[OpenInstance].SendResultsCompleted == TRUE )
+ {
+ //
+ // A previous SEND test has left some results in the SEND
+ // RESULTS buffer, and they have not been printed.
+ //
+
+ TpctlLog("\n\tTpctl: Results exist for a prior SEND test.\n",NULL);
+
+ TpctlPrintSendResults( Open[OpenInstance].SendResults );
+ Open[OpenInstance].SendResultsCompleted = FALSE;
+ }
+
+ //
+ // Set up the IoStatusBlock to point to this Open Instance's
+ // Send IoStatusBlock, and the OutputBuffer to point to its
+ // SendResults structure.
+ //
+
+ IoStatusBlock2 = Open[OpenInstance].SendStatusBlock;
+ OutputBuffer2 = Open[OpenInstance].SendResults;
+ OutputBufferSize2 = sizeof( SEND_RECEIVE_RESULTS );
+
+ //
+ // Set up the Send Event to wait on.
+ //
+
+ Event1 = Open[OpenInstance].Events[TPSEND];
+
+ if ( !ResetEvent( Open[OpenInstance].SendEvent ))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: failed to reset Send Event 0x%lx.\n",
+ (PVOID)Status);
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ //
+ // Finally set the Sending flag for this Open Instance,
+ //
+
+ Open[OpenInstance].Sending = TRUE;
+ }
+ else
+ {
+ CmdCode = CMD_COMPLETED;
+ }
+ break;
+
+ case STOPSEND:
+ if ( ToolActive )
+ {
+ if ( TpctlParseArguments( OpenInstanceOptions,
+ Num_OpenInstance_Params,
+ localArgc,
+ localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( OpenInstanceOptions,
+ Num_OpenInstance_Params,
+ localArgc,
+ localArgv );
+ }
+
+ if ( !TpctlInitCommandBuffer( CmdArgs,CmdCode ))
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ OpenInstance = CmdArgs->OpenInstance - 1;
+
+ //
+ // Is this Open Instance currently sending packets?
+ //
+
+ if ( Open[OpenInstance].Sending == FALSE )
+ {
+ //
+ // If not are the any results to report?
+ //
+
+ if ( Open[OpenInstance].SendResultsCompleted == FALSE )
+ {
+ //
+ // If not, print an error message and prompt for next
+ // command.
+ //
+
+ TpctlErrorLog(
+ "\n\tTpctl: A SEND test is not currently running for Open Instance %lu.\n",
+ (PVOID)(CmdArgs->OpenInstance));
+ CmdCode = CMD_COMPLETED;
+ break;
+ }
+ else // SendResultsCompleted == TRUE
+ {
+ //
+ // If there are results from a previous send, then print
+ // them, reset the flags, and prompt for the command.
+ //
+
+ TpctlPrintSendResults(Open[OpenInstance].SendResults);
+
+ Open[OpenInstance].SendResultsCompleted = FALSE;
+ Open[OpenInstance].Sending = FALSE;
+
+ CmdCode = CMD_COMPLETED;
+ break;
+ }
+ }
+ }
+ else
+ {
+ CmdCode = CMD_COMPLETED;
+ }
+ break;
+
+ case WAITSEND:
+ if ( ToolActive )
+ {
+ if ( TpctlParseArguments( OpenInstanceOptions,
+ Num_OpenInstance_Params,
+ localArgc,
+ localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( OpenInstanceOptions,
+ Num_OpenInstance_Params,
+ localArgc,
+ localArgv );
+ }
+
+ if ( !TpctlInitCommandBuffer( CmdArgs,CmdCode ))
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ OpenInstance = CmdArgs->OpenInstance - 1;
+
+ if ( Open[OpenInstance].AdapterOpened == FALSE )
+ {
+ TpctlErrorLog(
+ "\n\tTpctl: The adapter has not been opened for Open Instance %lu.\n",
+ (PVOID)(CmdArgs->OpenInstance));
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( Open[OpenInstance].SendResultsCompleted == TRUE )
+ {
+ TpctlPrintSendResults( Open[OpenInstance].SendResults );
+
+ Open[OpenInstance].SendResultsCompleted = FALSE;
+ Open[OpenInstance].Sending = FALSE;
+ }
+ else if ( Open[OpenInstance].Sending == TRUE )
+ {
+ ContinueLooping = TRUE;
+ do
+ {
+ Status = WaitForSingleObject( Open[OpenInstance].SendEvent,
+ 1000); // One_Second
+ if (( Status != NO_ERROR ) &&
+ ( Status != WAIT_TIMEOUT ))
+ {
+ TpctlErrorLog("\n\tWaitForSingleObject failed: returned 0x%lx.\n",
+ (PVOID)Status);
+ }
+ } while (( Status != NO_ERROR ) && ( ContinueLooping == TRUE ));
+
+ if ( ContinueLooping == FALSE )
+ {
+ TpctlLog("\n\tTpctl: Cancelling WaitSend command.\n",NULL);
+ }
+ else
+ {
+ TpctlPrintSendResults( Open[OpenInstance].SendResults );
+
+ Open[OpenInstance].SendResultsCompleted = FALSE;
+ Open[OpenInstance].Sending = FALSE;
+ }
+ }
+ else
+ {
+ TpctlErrorLog("\n\tTpctl: No Send results exist, and no Send test is\n",
+ NULL);
+ TpctlErrorLog("\t currently running for Open Instance %lu.\n",
+ (PVOID)CmdArgs->OpenInstance);
+ }
+ }
+ CmdCode = CMD_COMPLETED;
+ break;
+
+ case RECEIVE:
+ if ( ToolActive )
+ {
+ if ( TpctlParseArguments( OpenInstanceOptions,
+ Num_OpenInstance_Params,
+ localArgc,
+ localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( OpenInstanceOptions,
+ Num_OpenInstance_Params,
+ localArgc,
+ localArgv );
+ }
+
+ if ( !TpctlInitCommandBuffer( CmdArgs,CmdCode ))
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ OpenInstance = CmdArgs->OpenInstance - 1;
+
+ if ( Open[OpenInstance].AdapterOpened == FALSE )
+ {
+ TpctlErrorLog(
+ "\n\tTpctl: The adapter has not been opened for Open Instance %lu.\n",
+ (PVOID)(CmdArgs->OpenInstance));
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ //
+ // Is this Open Instance already receiveing packets?
+ //
+
+ if ( Open[OpenInstance].Receiving == TRUE )
+ {
+ //
+ // If so, print an error message and prompt for next command.
+ //
+
+ TpctlErrorLog(
+ "\n\tTpctl: Packets are currently being received on Open Instance %lu.\n",
+ (PVOID)(CmdArgs->OpenInstance));
+ CmdCode = CMD_ERR;
+ break;
+
+ }
+ else if ( Open[OpenInstance].ReceiveResultsCompleted == TRUE )
+ {
+ //
+ // A previous RECEIVE test has left some results in the RECEIVE
+ // RESULTS buffer, and they have not been printed.
+ //
+
+ TpctlLog("\n\tTpctl: Results exist for a prior RECEIVE test.\n",NULL);
+ TpctlPrintReceiveResults(Open[OpenInstance].ReceiveResults);
+ Open[OpenInstance].ReceiveResultsCompleted = FALSE;
+ }
+
+ //
+ // Set up the IoStatusBlock to point to this Open Instance's
+ // Send IoStatusBlock, and the OutputBuffer to point to its
+ // ReceiveResults structure.
+ //
+
+ IoStatusBlock2 = Open[OpenInstance].ReceiveStatusBlock;
+ OutputBuffer2 = Open[OpenInstance].ReceiveResults;
+ OutputBufferSize2 = sizeof( SEND_RECEIVE_RESULTS );
+
+ //
+ // Set up the Receive Event to wait on.
+ //
+
+ Event1 = Open[OpenInstance].Events[TPRECEIVE];
+
+ if (!ResetEvent(Open[OpenInstance].ReceiveEvent))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: failed to reset Receive Event 0x%lx.\n",
+ (PVOID)Status);
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ //
+ // Finally set the Receiving flag for this Open Instance,
+ //
+
+ Open[OpenInstance].Receiving = TRUE;
+ }
+ else
+ {
+ CmdCode = CMD_COMPLETED;
+ }
+ break;
+
+ case STOPREC:
+ if ( ToolActive )
+ {
+ if ( TpctlParseArguments( OpenInstanceOptions,
+ Num_OpenInstance_Params,
+ localArgc,
+ localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( OpenInstanceOptions,
+ Num_OpenInstance_Params,
+ localArgc,
+ localArgv );
+ }
+
+ if ( !TpctlInitCommandBuffer( CmdArgs,CmdCode ))
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ OpenInstance = CmdArgs->OpenInstance - 1;
+
+ //
+ // Is this Open Instance receiving packets?
+ //
+
+ if ( Open[OpenInstance].Receiving == FALSE )
+ {
+ //
+ // If not are the any results to report?
+ //
+
+ if ( Open[OpenInstance].ReceiveResultsCompleted == FALSE )
+ {
+ //
+ // If not, print an error message and prompt for next
+ // command.
+ //
+
+ TpctlErrorLog(
+ "\n\tTpctl: A RECEIVE test is not currently running for Open Instance %lu.\n",
+ (PVOID)(CmdArgs->OpenInstance));
+ CmdCode = CMD_ERR;
+ break;
+
+ }
+ else // ReceiveResultsCompleted == TRUE
+ {
+ TpctlPrintReceiveResults( Open[OpenInstance].ReceiveResults );
+
+ Open[OpenInstance].ReceiveResultsCompleted = FALSE;
+ Open[OpenInstance].Receiving = FALSE;
+
+ CmdCode = CMD_COMPLETED;
+ break;
+ }
+ }
+ }
+ else
+ {
+ CmdCode = CMD_COMPLETED;
+ }
+ break;
+
+ case GETEVENTS:
+ if ( ToolActive )
+ {
+ if ( TpctlParseArguments( OpenInstanceOptions,
+ Num_OpenInstance_Params,
+ localArgc,
+ localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( OpenInstanceOptions,
+ Num_OpenInstance_Params,
+ localArgc,
+ localArgv );
+ }
+
+ if ( !TpctlInitCommandBuffer( CmdArgs,CmdCode ))
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+ TpctlGetEvents( hFileHandle,CmdArgs,InputBufferSize );
+ }
+ CmdCode = CMD_COMPLETED;
+ break;
+
+ case STRESS:
+ if ( ToolActive )
+ {
+ if ( TpctlParseArguments( StressOptions,
+ Num_Stress_Params,
+ localArgc,
+ localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( StressOptions,
+ Num_Stress_Params,
+ localArgc,
+ localArgv );
+ }
+
+ if ( !TpctlInitCommandBuffer( CmdArgs,CmdCode ))
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ OpenInstance = CmdArgs->OpenInstance - 1;
+
+ if ( Open[OpenInstance].AdapterOpened == FALSE )
+ {
+ TpctlErrorLog(
+ "\n\tTpctl: The adapter has not been opened for Open Instance %lu.\n",
+ (PVOID)(CmdArgs->OpenInstance));
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ //
+ // Is this Open Instance already running a stress test?
+ //
+
+ if ( Open[OpenInstance].Stressing == TRUE )
+ {
+ //
+ // If so, print an error message and prompt for next command.
+ //
+
+ TpctlErrorLog(
+ "\n\tTpctl: A Stress test is currently running for Open Instance %lu.\n",
+ (PVOID)(CmdArgs->OpenInstance));
+ CmdCode = CMD_ERR;
+ break;
+ }
+ else if ( Open[OpenInstance].StressResultsCompleted == TRUE )
+ {
+ //
+ // A previous STRESS test has left some results in the STRESS
+ // RESULTS buffer, and they have not been printed.
+ //
+
+ TpctlLog("\n\tTpctl: Results exist for a prior STRESS test.\n",NULL);
+
+ TpctlPrintStressResults(Open[OpenInstance].StressResults,
+ Open[OpenInstance].Ack10 );
+
+ Open[OpenInstance].StressResultsCompleted = FALSE;
+ }
+
+ //
+ // Set up the IoStatusBlock to point to this Open Instance's
+ // Stress IoStatusBlock, and the OutputBuffer to point to its
+ // StressResults structure.
+ //
+
+ IoStatusBlock2 = Open[OpenInstance].StressStatusBlock;
+ OutputBuffer2 = Open[OpenInstance].StressResults;
+ OutputBufferSize2 = sizeof( STRESS_RESULTS );
+
+ //
+ // Set up the Stress Event to wait on.
+ //
+
+ Event1 = Open[OpenInstance].Events[TPSTRESS];
+
+ if (!ResetEvent(Open[OpenInstance].StressEvent))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: failed to reset Stress Event 0x%lx.\n",
+ (PVOID)Status);
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ //
+ // if we are running a stress test with a response type of
+ // ack 10 times for every packet, set the flag for displaying.
+ //
+
+ if ( CmdArgs->ARGS.TPSTRESS.ResponseType == ACK_10_TIMES )
+ {
+ Open[OpenInstance].Ack10 = TRUE;
+ }
+ else
+ {
+ Open[OpenInstance].Ack10 = FALSE;
+ }
+
+ //
+ // Finally set the Stressing flag for this Open Instance,
+ //
+
+ Open[OpenInstance].Stressing = TRUE;
+
+ //
+ // the flag indicating that a Client is running on this Open
+ // Instance,
+ //
+
+ Open[OpenInstance].StressClient = TRUE;
+
+ }
+ else
+ {
+ CmdCode = CMD_COMPLETED;
+ }
+ break;
+
+ case STRESSSERVER:
+ if ( ToolActive )
+ {
+ if ( TpctlParseArguments( OpenInstanceOptions,
+ Num_OpenInstance_Params,
+ localArgc,
+ localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( OpenInstanceOptions,
+ Num_OpenInstance_Params,
+ localArgc,
+ localArgv );
+ }
+
+ if ( !TpctlInitCommandBuffer( CmdArgs,CmdCode ))
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ OpenInstance = CmdArgs->OpenInstance - 1;
+
+ if ( Open[OpenInstance].AdapterOpened == FALSE )
+ {
+ TpctlErrorLog(
+ "\n\tTpctl: The adapter has not been opened for Open Instance %lu.\n",
+ (PVOID)(CmdArgs->OpenInstance));
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ //
+ // Is this Open Instance already running a stress test?
+ //
+
+ if ( Open[OpenInstance].Stressing == TRUE )
+ {
+ //
+ // If so, print an error message and prompt for next command.
+ //
+
+ TpctlErrorLog(
+ "\n\tTpctl: A Stress test is currently running for Open Instance %lu.\n",
+ (PVOID)(CmdArgs->OpenInstance));
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ //
+ // Set up the IoStatusBlock to point to this Open Instance's
+ // IoStatusBlock, and the OutputBuffer to point to its
+ // StressResults structure.
+ //
+
+ IoStatusBlock2 = Open[OpenInstance].StressStatusBlock;
+ OutputBuffer2 = Open[OpenInstance].StressResults;
+ OutputBufferSize2 = sizeof( STRESS_RESULTS );
+
+ //
+ // Set up the Stress Event to wait on.
+ //
+
+ Event1 = Open[OpenInstance].Events[TPSTRESS];
+
+ if (!ResetEvent(Open[OpenInstance].StressEvent))
+ {
+ Status = GetLastError();
+ TpctlErrorLog(
+ "\n\tTpctl: failed to reset Stress Event 0x%lx.\n",(PVOID)Status);
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ //
+ // Finally set the Stressing flag for this Open Instance,
+ //
+
+ Open[OpenInstance].Stressing = TRUE;
+ }
+ else
+ {
+ CmdCode = CMD_COMPLETED;
+ }
+ break;
+
+ case ENDSTRESS:
+ if ( ToolActive )
+ {
+ if ( TpctlParseArguments( OpenInstanceOptions,
+ Num_OpenInstance_Params,
+ localArgc,
+ localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( OpenInstanceOptions,
+ Num_OpenInstance_Params,
+ localArgc,
+ localArgv );
+ }
+
+ if ( !TpctlInitCommandBuffer( CmdArgs,CmdCode ))
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ OpenInstance = CmdArgs->OpenInstance - 1;
+
+ //
+ // Is this Open Instance running a stress test?
+ //
+
+ if ( Open[OpenInstance].Stressing == FALSE )
+ {
+ //
+ // If not, print an error message and prompt for next command.
+ //
+
+ TpctlErrorLog(
+ "\n\tTpctl: A Stress test is not currently running for Open Instance %lu.\n",
+ (PVOID)(CmdArgs->OpenInstance));
+ CmdCode = CMD_COMPLETED;
+ }
+
+ }
+ else
+ {
+ CmdCode = CMD_COMPLETED;
+ }
+ break;
+
+ case WAITSTRESS:
+ case CHECKSTRESS:
+ if ( ToolActive )
+ {
+ if ( TpctlParseArguments( OpenInstanceOptions,
+ Num_OpenInstance_Params,
+ localArgc,
+ localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( OpenInstanceOptions,
+ Num_OpenInstance_Params,
+ localArgc,
+ localArgv );
+ }
+
+ if ( !TpctlInitCommandBuffer( CmdArgs,CmdCode ))
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ OpenInstance = CmdArgs->OpenInstance - 1;
+
+ if ( Open[OpenInstance].AdapterOpened == FALSE )
+ {
+ TpctlErrorLog(
+ "\n\tTpctl: The adapter has not been opened for Open Instance %lu.\n",
+ (PVOID)(CmdArgs->OpenInstance));
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( Open[OpenInstance].StressResultsCompleted == TRUE )
+ {
+ TpctlPrintStressResults(Open[OpenInstance].StressResults,
+ Open[OpenInstance].Ack10 );
+
+ Open[OpenInstance].StressResultsCompleted = FALSE;
+ Open[OpenInstance].Stressing = FALSE;
+
+ }
+ else if ( Open[OpenInstance].Stressing == TRUE )
+ {
+ if ( Open[OpenInstance].StressClient != TRUE )
+ {
+ TpctlErrorLog("\n\tTpctl: %s command valid only for Stress Clients.\n",
+ TpctlGetCommandName( localArgv[0] ));
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( CmdCode == WAITSTRESS )
+ {
+ ContinueLooping = TRUE;
+
+ do
+ {
+ Status = WaitForSingleObject( Open[OpenInstance].StressEvent,
+ 1000); // One_Second
+ if (( Status != NO_ERROR ) &&
+ ( Status != WAIT_TIMEOUT ))
+ {
+ TpctlErrorLog(
+ "\n\tWaitForSingleObject failed: returned 0x%lx.\n",
+ (PVOID)Status);
+ }
+
+ } while (( Status != NO_ERROR ) &&
+ ( ContinueLooping == TRUE ));
+
+ if ( ContinueLooping == FALSE )
+ {
+ TpctlLog("\n\tTpctl: Cancelling WaitStress command.\n",NULL);
+ }
+ else
+ {
+ TpctlPrintStressResults(Open[OpenInstance].StressResults,
+ Open[OpenInstance].Ack10 );
+
+ Open[OpenInstance].StressResultsCompleted = FALSE;
+ Open[OpenInstance].Stressing = FALSE;
+ }
+ }
+ else
+ {
+ TpctlLog("\n\tTpctl: The Stress test is still running.\n",NULL);
+ }
+ }
+ else
+ {
+ TpctlErrorLog("\n\tTpctl: No Stress results exist, and no Stress test is\n",
+ NULL);
+ TpctlErrorLog("\t currently running for Open Instance %lu.\n",
+ (PVOID)CmdArgs->OpenInstance);
+ }
+ }
+ CmdCode = CMD_COMPLETED;
+ break;
+
+ case BREAKPOINT:
+ if ( !ToolActive )
+ {
+ CmdCode = CMD_COMPLETED;
+ }
+ else
+ {
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( NULL,
+ 0,
+ 1,
+ localArgv );
+ }
+ }
+ break;
+
+ case QUIT:
+ if ( ToolActive )
+ {
+ DWORD i;
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( NULL,
+ 0,
+ 1,
+ localArgv );
+ }
+
+ //
+ // If there are any outstanding ASYNC IRPs print a message
+ // to the user to wait patiently.
+ //
+
+ for (i=0;i<NUM_OPEN_INSTANCES;i++ )
+ {
+ if ((( Open[i].Stressing == TRUE ) ||
+ ( Open[i].Sending == TRUE )) ||
+ ( Open[i].Receiving == TRUE ))
+ {
+ TpctlErrorLog(
+ "\n\tTpctl: Cancelling outstanding IRPs, please wait...\n",NULL);
+ break;
+ }
+ }
+ ExitFlag = TRUE;
+ Status = NO_ERROR;
+ }
+ CmdCode = CMD_COMPLETED;
+ break;
+
+ case HELP:
+ if ( ToolActive )
+ {
+ DWORD TmpScriptIndex = ScriptIndex;
+
+ //
+ // We are going to temporarily override the script index
+ // to fool the TpctlParseArguments routine into not prompting
+ // for an argument if none is give with the help command.
+ //
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( NULL,
+ 0,
+ 1,
+ localArgv );
+ }
+
+ ScriptIndex = (DWORD)1;
+
+ if ( TpctlParseArguments( HelpOptions,
+ Num_Help_Params,
+ localArgc,
+ localArgv ) == -1 )
+ {
+ break;
+ }
+ TpctlHelp( GlobalCmdArgs.ARGS.CmdName );
+ ScriptIndex = TmpScriptIndex;
+ }
+ CmdCode = CMD_COMPLETED;
+ break;
+
+ case SHELL:
+ if ( ToolActive )
+ {
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( NULL,
+ 0,
+ 1,
+ localArgv );
+ }
+
+ {
+ CONSOLE_SCREEN_BUFFER_INFO ScreenBuffer;
+ HANDLE OutputHandle;
+ COORD Start;
+ BOOL NoErrorsAccessingConsole = FALSE;
+ DWORD CharactersWritten;
+
+ ZeroMemory( (PVOID)&ScreenBuffer, sizeof(CONSOLE_SCREEN_BUFFER_INFO));
+ Start.X = 0;
+ Start.Y = 0;
+
+ OutputHandle = GetStdHandle( STD_OUTPUT_HANDLE );
+ //
+ // Record the old console settings
+ //
+ if ( GetConsoleScreenBufferInfo( OutputHandle, &ScreenBuffer ) )
+ {
+ NoErrorsAccessingConsole = TRUE;
+ }
+
+ //
+ // Set the console foregrounds and background colors to the new settings
+ //
+ if( NoErrorsAccessingConsole )
+ {
+ WORD Colors;
+
+ if ( ScreenBuffer.wAttributes & BACKGROUND_BLUE )
+ {
+ Colors = FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE|
+ FOREGROUND_INTENSITY|BACKGROUND_RED;
+ }
+ else
+ {
+ Colors = FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE|
+ FOREGROUND_INTENSITY|BACKGROUND_BLUE;
+ }
+
+ SetConsoleTextAttribute( OutputHandle, Colors );
+ FillConsoleOutputAttribute( OutputHandle, Colors,
+ 0xFFFFFFFF, Start,
+ &CharactersWritten );
+ }
+
+ //
+ // And spawn the command shell
+ //
+ {
+ CHAR ShellCommand[256];
+ INT TmpCount;
+
+ ZeroMemory( ShellCommand, sizeof( ShellCommand ));
+ strcpy( ShellCommand, "CMD" );
+
+ if ( localArgc > 1 )
+ {
+ strcat( ShellCommand, " /C " );
+ for( TmpCount = 1; TmpCount < (INT)localArgc; TmpCount++ )
+ {
+ strcat( ShellCommand, localArgv[TmpCount] );
+ strcat( ShellCommand, " " );
+ }
+ }
+ system( ShellCommand );
+ }
+
+ //
+ // Reset the console foregrounds and background colors to the old settings
+ //
+ if( NoErrorsAccessingConsole )
+ {
+ SetConsoleTextAttribute( OutputHandle, ScreenBuffer.wAttributes );
+ FillConsoleOutputAttribute( OutputHandle, ScreenBuffer.wAttributes,
+ 0xFFFFFFFF, Start,
+ &CharactersWritten );
+ }
+ }
+ printf("\n");
+ }
+ CmdCode = CMD_COMPLETED;
+ break;
+
+ case DISABLE:
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( NULL,
+ 0,
+ localArgc,
+ localArgv );
+ }
+
+ if ( Disable( localArgc, localArgv ) )
+ {
+ printf( "\n\tDisabling TPCTL...\n\n" );
+ }
+ CmdCode = CMD_COMPLETED;
+ break;
+
+ case ENABLE:
+ ToolActive = TRUE;
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( NULL,
+ 0,
+ localArgc,
+ localArgv );
+ }
+ printf( "\n\tEnabling TPCTL...\n\n" );
+ CmdCode = CMD_COMPLETED;
+ break;
+
+ case REGISTRY:
+ if ( ToolActive )
+ {
+ if ( TpctlParseArguments( RegistryOptions,
+ Num_Registry_Params,
+ localArgc,
+ localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( RegistryOptions,
+ Num_Registry_Params,
+ localArgc,
+ localArgv );
+ }
+
+ if ( !TpctlInitCommandBuffer( CmdArgs,CmdCode ))
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+ TpctlPerformRegistryOperation( CmdArgs );
+ }
+ CmdCode = CMD_COMPLETED;
+ break;
+
+
+ case PERFSERVER:
+ if ( ToolActive )
+ {
+ if ( TpctlParseArguments( OpenInstanceOptions,
+ Num_OpenInstance_Params,
+ localArgc,
+ localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( OpenInstanceOptions,
+ Num_OpenInstance_Params,
+ localArgc,
+ localArgv );
+ }
+
+ if ( !TpctlInitCommandBuffer( CmdArgs,CmdCode ))
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ OpenInstance = CmdArgs->OpenInstance - 1;
+
+ if ( Open[OpenInstance].AdapterOpened == FALSE )
+ {
+ TpctlErrorLog(
+ "\n\tTpctl: The adapter has not been opened for Open Instance %lu.\n",
+ (PVOID)(CmdArgs->OpenInstance));
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ //
+ // Is this Open Instance already sending or receiving packets?
+ //
+
+ if ( (Open[OpenInstance].Sending == TRUE ) ||
+ (Open[OpenInstance].Receiving == TRUE ) ||
+ (Open[OpenInstance].ReceiveResultsCompleted == TRUE ) ||
+ (Open[OpenInstance].SendResultsCompleted == TRUE ) )
+ {
+ //
+ // If so, print an error message and prompt for next command.
+ //
+
+ TpctlErrorLog(
+ "\n\tTpctl: Packets are currently being sent or received on Open Instance %lu.\n",
+ (PVOID)(CmdArgs->OpenInstance));
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ //
+ // Set up the IoStatusBlock to point to this Open Instance's
+ // Send IoStatusBlock, and the OutputBuffer to point to its
+ // SendResults structure.
+ //
+
+ IoStatusBlock2 = Open[OpenInstance].PerfStatusBlock;
+ OutputBuffer2 = Open[OpenInstance].PerfResults;
+ OutputBufferSize2 = sizeof( PERF_RESULTS );
+
+ //
+ // Set up the Send Event to wait on.
+ //
+
+ Event1 = Open[OpenInstance].Events[TPPERF];
+
+ if ( !ResetEvent( Open[OpenInstance].PerfEvent ))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: failed to reset Perf Event 0x%lx.\n",
+ (PVOID)Status);
+ CmdCode = CMD_ERR;
+ break;
+ }
+ }
+ else
+ {
+ CmdCode = CMD_COMPLETED;
+ }
+ break;
+
+ case PERFCLIENT:
+ if ( ToolActive )
+ {
+ if ( TpctlParseArguments( PerfClntOptions,
+ Num_PerfClnt_Params,
+ localArgc,
+ localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( PerfClntOptions,
+ Num_PerfClnt_Params,
+ localArgc,
+ localArgv );
+ }
+
+ if ( !TpctlInitCommandBuffer( CmdArgs,CmdCode ))
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ OpenInstance = CmdArgs->OpenInstance - 1;
+
+ if ( Open[OpenInstance].AdapterOpened == FALSE )
+ {
+ TpctlErrorLog(
+ "\n\tTpctl: The adapter has not been opened for Open Instance %lu.\n",
+ (PVOID)(CmdArgs->OpenInstance));
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ //
+ //
+ // Is this Open Instance already sending or receiving packets?
+ //
+
+ if ( (Open[OpenInstance].Sending == TRUE ) ||
+ (Open[OpenInstance].Receiving == TRUE ) ||
+ (Open[OpenInstance].ReceiveResultsCompleted == TRUE ) ||
+ (Open[OpenInstance].SendResultsCompleted == TRUE ) )
+ {
+ //
+ // If so, print an error message and prompt for next command.
+ //
+
+ TpctlErrorLog(
+ "\n\tTpctl: Packets are currently being sent or received on Open Instance %lu.\n",
+ (PVOID)(CmdArgs->OpenInstance));
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ //
+ // Set up the IoStatusBlock to point to this Open Instance's
+ // Send IoStatusBlock, and the OutputBuffer to point to its
+ // ReceiveResults structure.
+ //
+
+ IoStatusBlock2 = Open[OpenInstance].PerfStatusBlock;
+ OutputBuffer2 = Open[OpenInstance].PerfResults;
+ OutputBufferSize2 = sizeof( PERF_RESULTS );
+
+ //
+ // Set up the Receive Event to wait on.
+ //
+
+ Event1 = Open[OpenInstance].Events[TPPERF];
+
+ if (!ResetEvent(Open[OpenInstance].PerfEvent))
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: failed to reset Perf Event 0x%lx.\n",
+ (PVOID)Status);
+ CmdCode = CMD_ERR;
+ break;
+ }
+ CpuUsageInit();
+ }
+ else
+ {
+ CmdCode = CMD_COMPLETED;
+ }
+ break;
+
+
+ case SETGLOBAL:
+ if (ToolActive)
+ {
+ if ( TpctlParseSet( localArgc, localArgv ) == -1 )
+ {
+ CmdCode = CMD_ERR;
+ break;
+ }
+
+ if ( RecordToScript )
+ {
+ TpctlRecordArguments( NULL,
+ 0,
+ min(2,localArgc),
+ localArgv );
+ }
+
+ }
+ CmdCode = CMD_COMPLETED;
+ break;
+
+ default:
+ CmdCode = CMD_COMPLETED;
+ if( ToolActive )
+ {
+ TpctlErrorLog("\n\tTpctl: Invalid Command Entered.\n",NULL);
+ CmdCode = CMD_ERR;
+ }
+ break;
+
+ } // switch();
+
+ //
+ // If we have a command to issue to the driver and the tool
+ // is active, do it now.
+ //
+
+ if ( ( CmdCode == STRESS ) || ( CmdCode == STRESSSERVER ) ||
+ ( CmdCode == SEND ) || ( CmdCode == RECEIVE ) ||
+ ( CmdCode == PERFSERVER ) || ( CmdCode == PERFCLIENT ) )
+ {
+
+//!!NOT WIN32!!
+
+ NtStatus = NtDeviceIoControlFile( hFileHandle,
+ Event1,
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock2,
+ TP_CONTROL_CODE( CmdCode,IOCTL_METHOD ),
+ (PVOID)InputBuffer,
+ InputBufferSize,
+ (PVOID)OutputBuffer2,
+ OutputBufferSize2 );
+
+ if (( NtStatus == STATUS_SUCCESS ) ||
+ ( NtStatus == STATUS_PENDING ))
+ {
+ TpctlLog("\n\tTpctl: The %s command has been issued.\n",
+ TpctlGetCommandName( localArgv[0] ));
+ }
+
+ }
+ else if (( CmdCode != CMD_ERR ) && ( CmdCode != CMD_COMPLETED ))
+ {
+// !!NOT WIN32!!
+
+ NtStatus = NtDeviceIoControlFile( hFileHandle,
+ Event,
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock,
+ TP_CONTROL_CODE( CmdCode,IOCTL_METHOD ),
+ (PVOID)InputBuffer,
+ InputBufferSize,
+ (PVOID)OutputBuffer,
+ OutputBufferSize );
+
+ if (( NtStatus != STATUS_SUCCESS ) &&
+ ( NtStatus != STATUS_PENDING ))
+ {
+ //
+ // If the IOCTL call failed then close any script files
+ // and break out of while loop by setting the ExitFlag
+ // to true.
+ //
+
+ TpctlErrorLog("\n\tTpctl: NtDeviceIoControlFile failed: returned 0x%lx.\n",
+ (PVOID)NtStatus);
+ ExitFlag = TRUE;
+ Status = NtStatus;
+ break;
+ }
+ else
+ {
+ TpctlLog("\n\tTpctl: The %s command has been issued.\n",
+ TpctlGetCommandName( localArgv[0] ));
+
+ if ( NtStatus == STATUS_PENDING )
+ {
+ //
+ // If the ioctl pended, then wait for it to complete.
+ //
+
+ Status = WaitForSingleObject( Event,60000 ); // ONE_MINUTE
+
+ if ( Status == WAIT_TIMEOUT )
+ {
+ //
+ // The wait timed out, this probable means there
+ // was a failure in the MAC not completing a
+ // request, because the IRP was never completed
+ // by the test protocol driver.
+ //
+
+ TpctlErrorLog(
+ "\n\tTpctl: WARNING - WaitForSingleObject unexpectedly timed out.\n",
+ NULL);
+ TpctlErrorLog(
+ "\t IRP was never completed in protocol driver.\n",
+ NULL);
+ CmdCode = CMD_ERR;
+ }
+ else if ( Status != NO_ERROR )
+ {
+ //
+ // If the wait for single object failed, then exit
+ // the test app with the error.
+ //
+
+ TpctlErrorLog(
+ "\n\tTpctl: ERROR - WaitForSingleObject failed: returned 0x%lx.\n",
+ (PVOID)Status);
+ ExitFlag = TRUE;
+ CmdCode = CMD_ERR;
+ }
+ else if ( IoStatusBlock.Status != STATUS_SUCCESS )
+ {
+ //
+ // else if the pending ioctl returned failure again
+ // exit the test app with the error.
+ //
+
+ TpctlErrorLog("\n\tTpctl: NtDeviceIoControlFile pended.\n",NULL);
+ TpctlErrorLog("\n\t NtDeviceIoControlFile failed: returned 0x%lx.\n",
+ (PVOID)IoStatusBlock.Status);
+ ExitFlag = TRUE;
+ Status = IoStatusBlock.Status;
+ }
+ }
+ }
+ }
+
+ switch ( CmdCode )
+ {
+ case CMD_ERR:
+ //
+ // NOTE: if commands are being read from a script file setting
+ // the CmdCode to CMD_ERR causes this routine to unload ALL
+ // script files, and wait at the prompt for the next command
+ // to process, use CMD_ERR wisely.
+ //
+
+ if( !ContinueOnError )
+ {
+ TpctlResetAllOpenStates( hFileHandle );
+ TpctlCloseScripts();
+ }
+ break;
+
+ case SETENV:
+ break;
+
+ case OPEN:
+ if (((PREQUEST_RESULTS)OutputBuffer)->RequestStatus == NDIS_STATUS_SUCCESS )
+ {
+ //
+ // The open request succeeded so mark this open instance
+ // as opened.
+ //
+
+ Open[OpenInstance].AdapterOpened = TRUE;
+
+ //
+ // if the open "initialization" requests all succeeded
+ // copy the adapter address into the open, and set the
+ // open instance.
+ //
+
+ if (((PREQUEST_RESULTS)OutputBuffer)->OpenRequestStatus ==
+ NDIS_STATUS_SUCCESS )
+ {
+ //
+ // STARTCHANGE
+ //
+ // Sanjeevk: Bug #5203
+ //
+ PNDIS_MEDIUM MediumType =
+ (PNDIS_MEDIUM)((PREQUEST_RESULTS)OutputBuffer)->InformationBuffer;
+
+ //
+ // Copy the Media Type
+ //
+ Open[OpenInstance].MediumType = *MediumType;
+
+ //
+ // STOPCHANGE
+ //
+
+ //
+ // Copy the address of the adapter
+ //
+ TpctlCopyAdapterAddress(OpenInstance,
+ (PREQUEST_RESULTS)OutputBuffer );
+
+ Open[OpenInstance].OpenInstance = (UCHAR)OpenInstance;
+ }
+ }
+
+ //
+ // Now print the Open request results regardless of success or
+ // failure.
+ //
+
+ TpctlPrintResults( (PREQUEST_RESULTS)OutputBuffer,CmdCode,0 );
+ break;
+
+ case CLOSE:
+ if (((PREQUEST_RESULTS)OutputBuffer)->RequestStatus ==
+ NDIS_STATUS_SUCCESS )
+ {
+ //
+ // The close request succeeded, set the flag stating so,
+ // and reset the open structure to its initial state.
+ //
+
+ Open[OpenInstance].AdapterOpened = FALSE;
+ Open[OpenInstance].OpenInstance = (UCHAR)-1;
+
+ TpctlResetOpenState( &Open[OpenInstance],hFileHandle );
+ }
+
+ //
+ // Now print the results regardless of success or failure.
+ //
+
+ TpctlPrintResults( (PREQUEST_RESULTS)OutputBuffer,CmdCode,0 );
+ break;
+
+ case SETPF:
+ case SETLA:
+ case ADDMA:
+ case SETFA:
+ case SETGA:
+ case SETINFO:
+ {
+ PMULT_ADDR MultAddr = NULL;
+ BOOL AddressFound = FALSE;
+ DWORD i;
+
+ if (((PREQUEST_RESULTS)OutputBuffer)->RequestStatus ==
+ NDIS_STATUS_SUCCESS )
+ {
+ //
+ // If the command succeeded, then update the local
+ // state to reflect the changed info.
+ //
+
+ switch ( CmdArgs->ARGS.TPSET.OID )
+ {
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ Open[OpenInstance].PacketFilter =
+ CmdArgs->ARGS.TPSET.U.PacketFilter;
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ Open[OpenInstance].LookaheadSize =
+ CmdArgs->ARGS.TPSET.U.LookaheadSize;
+ break;
+
+ case OID_FDDI_LONG_MULTICAST_LIST :
+ case OID_802_3_MULTICAST_LIST :
+ //
+ // We successfully added the multicast address to the
+ // card, if it is not in our local list already, then
+ // put it on the local multicast address list
+ // for accounting purposes.
+ //
+ // XXX: The stress tests be required to add and delete
+ // the stress multicast address to/from this list?
+ //
+
+ MultAddr = Open[OpenInstance].MulticastAddresses;
+
+ if ( MultAddr != NULL )
+ {
+ //
+ // if the list is not empty see if this addr is
+ // in it yet.
+ //
+
+ while ( MultAddr != NULL )
+ {
+ if ( memcmp(CmdArgs->ARGS.TPSET.U.MulticastAddress[0],
+ MultAddr->MulticastAddress,
+ ADDRESS_LENGTH ) == 0 )
+ {
+ //
+ // We found the address in the list already,
+ // so skip adding it in again.
+ //
+
+ AddressFound = TRUE;
+ break;
+ }
+
+ //
+ // Otherwise, get the next list entry.
+ //
+
+ MultAddr = MultAddr->Next;
+ }
+ }
+
+ if ( AddressFound == FALSE )
+ {
+ MultAddr = GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT,
+ sizeof( MULT_ADDR ) );
+
+ if ( MultAddr == NULL )
+ {
+ Status = GetLastError();
+ TpctlErrorLog(
+ "\n\tGlobalAlloc failed to alloc a MultAddr stuct: returned 0x%lx.\n",
+ (PVOID)Status);
+ break;
+ }
+
+ for ( i=0;i<ADDRESS_LENGTH;i++ )
+ {
+ MultAddr->MulticastAddress[i] =
+ CmdArgs->ARGS.TPSET.U.MulticastAddress[0][i];
+ }
+
+ MultAddr->Next = Open[OpenInstance].MulticastAddresses;
+ Open[OpenInstance].MulticastAddresses = MultAddr;
+
+ Open[OpenInstance].NumberMultAddrs++;
+ }
+ break;
+
+ case OID_802_5_CURRENT_FUNCTIONAL:
+ for (i=0;i<FUNCTIONAL_ADDRESS_LENGTH;i++)
+ {
+ Open[OpenInstance].FunctionalAddress[i] =
+ CmdArgs->ARGS.TPSET.U.FunctionalAddress[i];
+ }
+ break;
+
+ case OID_802_5_CURRENT_GROUP:
+ for (i=0;i<FUNCTIONAL_ADDRESS_LENGTH;i++)
+ {
+ Open[OpenInstance].GroupAddress[i] =
+ CmdArgs->ARGS.TPSET.U.GroupAddress[i];
+ }
+ break;
+ }
+ }
+
+ TpctlPrintSetInfoResults( (PREQUEST_RESULTS)OutputBuffer,
+ CmdCode,
+ CmdArgs->ARGS.TPSET.OID );
+ break;
+ }
+
+ case DELMA:
+ {
+ PMULT_ADDR MultAddr = NULL;
+ PMULT_ADDR BaseMultAddr = NULL;
+ //
+ // We successfully deleted the multicast address from the
+ // card, if it is in our local list already, then remove
+ // it from the local multicast address list for accounting
+ // purposes.
+ //
+ // The stress tests be required to add and delete the stress
+ // multicast address to/from this list?
+ //
+
+ MultAddr = Open[OpenInstance].MulticastAddresses;
+
+ if ( MultAddr != NULL )
+ {
+ //
+ // if the list is not empty see if this addr is
+ // in it, first check the initial entry.
+ //
+
+ if ( memcmp(GlobalCmdArgs.ARGS.TPSET.U.MulticastAddress[0],
+ MultAddr->MulticastAddress,
+ ADDRESS_LENGTH ) == 0 )
+ {
+ //
+ // and if found remove from list and free
+ //
+ Open[OpenInstance].MulticastAddresses = MultAddr->Next;
+ GlobalFree( MultAddr );
+ Open[OpenInstance].NumberMultAddrs--;
+ }
+ else
+ {
+ //
+ // Otherwise check the rest of the list.
+ //
+
+ while ( MultAddr->Next != NULL )
+ {
+ if (memcmp( GlobalCmdArgs.ARGS.TPSET.U.MulticastAddress[0],
+ MultAddr->Next->MulticastAddress,
+ ADDRESS_LENGTH ) == 0 )
+ {
+ //
+ // We found the address in the list, so remove
+ // it and deallocate the memory
+ //
+ MultAddr->Next = MultAddr->Next->Next;
+ GlobalFree( MultAddr->Next );
+ Open[OpenInstance].NumberMultAddrs--;
+ break;
+ }
+ //
+ // Otherwise, get the next list entry.
+ //
+
+ MultAddr = MultAddr->Next;
+ }
+ }
+ }
+
+ TpctlPrintSetInfoResults( (PREQUEST_RESULTS)OutputBuffer,
+ CmdCode,
+ CmdArgs->ARGS.TPSET.OID );
+
+ break;
+ }
+
+ case QUERYINFO:
+ TpctlPrintQueryInfoResults( (PREQUEST_RESULTS)OutputBuffer,
+ CmdCode,
+ CmdArgs->ARGS.TPQUERY.OID );
+ break;
+
+ case RESET:
+ TpctlPrintResults( (PREQUEST_RESULTS)OutputBuffer,CmdCode,0 );
+ break;
+
+ case SEND:
+ //
+ // If the IOCTL call failed then break out of while loop
+ // by setting the ExitFlag to true.
+ //
+
+ if (( NtStatus != STATUS_SUCCESS ) &&
+ ( NtStatus != STATUS_PENDING ))
+ {
+ TpctlErrorLog("\n\tTpctl: NtDeviceIoControlFile failed: returned 0x%lx.\n",
+ (PVOID)NtStatus);
+ ExitFlag = TRUE;
+ Status = NtStatus;
+ break;
+ }
+ //
+ // If we have only attempted to SEND one packet, then we will
+ // print the results here and now.
+ //
+
+ else if ( CmdArgs->ARGS.TPSEND.NumberOfPackets == 1 )
+ {
+ //
+ // Wait for the SEND event to be signaled telling us that
+ // the results are complete.
+ //
+
+ Status = WaitForSingleObject( Open[OpenInstance].SendEvent,
+ 0xFFFFFFFF );
+
+ if ( Status != NO_ERROR )
+ {
+ //
+ // If the wait for single object failed, then exit the
+ // test app with the error.
+ //
+
+ TpctlErrorLog("\n\tWaitForSingleObject failed: returned 0x%lx.\n",
+ (PVOID)Status);
+ ExitFlag = TRUE;
+ break;
+ }
+ else if ( IoStatusBlock2.Status != STATUS_SUCCESS )
+ {
+ //
+ // If the send did not completed successfully then
+ // exit the test app with the error.
+ //
+
+ TpctlErrorLog("\n\tTpctl: The SEND command failed, returned 0x%lx.\n",
+ (PVOID)IoStatusBlock2.Status);
+ ExitFlag = TRUE;
+ Status = IoStatusBlock2.Status;
+ break;
+ }
+ else
+ {
+ //
+ // Otherwise print the send test results.
+ //
+
+ TpctlPrintSendResults( Open[OpenInstance].SendResults );
+ }
+
+ //
+ // then reset the SEND control flags to the initial state
+ // and return.
+ //
+
+ Open[OpenInstance].SendResultsCompleted = FALSE;
+ Open[OpenInstance].Sending = FALSE;
+ }
+ break;
+
+ case STOPSEND:
+ //
+ // Wait for the SEND event to be signaled telling us that
+ // the results are complete.
+ //
+
+ Status = WaitForSingleObject( Open[OpenInstance].SendEvent,
+ 0xFFFFFFFF );
+
+ if ( Status != NO_ERROR )
+ {
+ //
+ // If the wait for single object failed, then exit the
+ // test app with the error.
+ //
+
+ TpctlErrorLog("\n\tWaitForSingleObject failed: returned 0x%lx.\n",
+ (PVOID)Status);
+ ExitFlag = TRUE;
+ break;
+ }
+ else if ( IoStatusBlock2.Status != STATUS_SUCCESS )
+ {
+ //
+ // If the send did not completed successfully then
+ // exit the test app with the error.
+ //
+
+ TpctlErrorLog("\n\tTpctl: The STOPSEND command failed, returned 0x%lx.\n",
+ (PVOID)IoStatusBlock2.Status);
+ ExitFlag = TRUE;
+ Status = IoStatusBlock2.Status;
+ break;
+ }
+ else
+ {
+ //
+ // Otherwise print the send test results.
+ //
+
+ TpctlPrintSendResults( Open[OpenInstance].SendResults );
+ }
+
+ //
+ // then reset the SEND control flags to the initial state
+ // and return.
+ //
+ Open[OpenInstance].SendResultsCompleted = FALSE;
+ Open[OpenInstance].Sending = FALSE;
+ break;
+
+ case RECEIVE:
+ //
+ // If the IOCTL call failed then break out of while loop
+ // by setting the ExitFlag to true.
+ //
+
+ if (( NtStatus != STATUS_SUCCESS ) &&
+ ( NtStatus != STATUS_PENDING ))
+ {
+ TpctlErrorLog("\n\tTpctl: NtDeviceIoControlFile failed: returned 0x%lx.\n",
+ (PVOID)NtStatus);
+ ExitFlag = TRUE;
+ Status = NtStatus;
+ }
+
+ //
+ // otherwise the RECEIVE test has been started successfully, and
+ // there is nothing more to do.
+ //
+ break;
+
+ case STOPREC:
+ //
+ // Wait for the RECEIVE event to be signaled telling us that
+ // the results are complete.
+ //
+
+ Status = WaitForSingleObject( Open[OpenInstance].ReceiveEvent,
+ 0xFFFFFFFF );
+
+ if ( Status != NO_ERROR )
+ {
+ //
+ // If the wait for single object failed, then exit the
+ // test app with the error.
+ //
+
+ TpctlErrorLog("\n\tWaitForSingleObject failed: returned 0x%lx.\n",
+ (PVOID)Status);
+ ExitFlag = TRUE;
+ break;
+ }
+ else if ( IoStatusBlock2.Status != STATUS_SUCCESS )
+ {
+ //
+ // If the receive did not completed successfully then
+ // exit the test app with the error.
+ //
+
+ TpctlErrorLog("\n\tTpctl: The STOPRECEIVE command failed, returned 0x%lx.\n",
+ (PVOID)IoStatusBlock2.Status);
+ ExitFlag = TRUE;
+ Status = IoStatusBlock2.Status;
+ break;
+ }
+ else
+ {
+ //
+ // Otherwise print the receive test results.
+ //
+ TpctlPrintReceiveResults( Open[OpenInstance].ReceiveResults );
+ }
+
+ //
+ // then reset the RECEIVE control flags to the initial state
+ // and return.
+ //
+
+ Open[OpenInstance].ReceiveResultsCompleted = FALSE;
+ Open[OpenInstance].Receiving = FALSE;
+ break;
+
+ case STRESS:
+ //
+ // If the Ioctl call failed then the attempt to start the
+ // stress test has failed, then break out of while loop by
+ // setting the ExitFlag to true.
+ //
+
+ if ((( NtStatus != TP_STATUS_NO_SERVERS ) &&
+ ( NtStatus != STATUS_SUCCESS )) &&
+ ( NtStatus != STATUS_PENDING ))
+ {
+ TpctlErrorLog("\n\tTpctl: NtDeviceIoControlFile failed: returned 0x%lx.\n",
+ (PVOID)NtStatus);
+ ExitFlag = TRUE;
+ Status = NtStatus;
+ }
+ else if ( NtStatus == TP_STATUS_NO_SERVERS )
+ {
+ //
+ // No Stress Servers where found to participate in the
+ // test, reset the Stress Test control flags to show that
+ // the test did not start properly.
+ //
+
+ Open[OpenInstance].Stressing = FALSE;
+ Open[OpenInstance].StressResultsCompleted = FALSE;
+ Open[OpenInstance].StressClient = FALSE;
+
+ //
+ // Then Display the error to the user.
+ //
+
+ TpctlErrorLog("\n\tTpctl: failed to start STRESS test, returned %s.\n",
+ (PVOID)TpctlGetStatus( NtStatus ));
+
+ //
+ // And, if we are reading commands from a script, assume
+ // that the failure should force the test to stop, therefore
+ // unload the script files.
+ //
+
+ if ( !ContinueOnError )
+ {
+ TpctlResetAllOpenStates( hFileHandle );
+ TpctlCloseScripts();
+ }
+
+ }
+ break;
+
+ case STRESSSERVER:
+ //
+ // If the IOCTL call failed then break out of while loop
+ // by setting the ExitFlag to true.
+ //
+
+ if (( NtStatus != STATUS_SUCCESS ) &&
+ ( NtStatus != STATUS_PENDING ))
+ {
+ TpctlErrorLog("\n\tTpctl: NtDeviceIoControlFile failed: returned 0x%lx.\n",
+ (PVOID)NtStatus);
+ ExitFlag = TRUE;
+ Status = NtStatus;
+ }
+
+ //
+ // otherwise the STRESS SERVER has been started successfully, and
+ // there is nothing more to do here.
+ //
+ break;
+
+ case ENDSTRESS:
+ //
+ // Wait for the STRESS event to be signaled telling us that
+ // the results are complete.
+ //
+
+ Status = WaitForSingleObject( Open[OpenInstance].StressEvent,
+ 0xFFFFFFFF );
+
+ if ( Status != NO_ERROR )
+ {
+ //
+ // If the wait for single object failed, then exit the
+ // test app with the error.
+ //
+
+ TpctlErrorLog("\n\tWaitForSingleObject failed: returned 0x%lx.\n",
+ (PVOID)Status);
+ ExitFlag = TRUE;
+ break;
+
+ }
+ else if ( IoStatusBlock2.Status != STATUS_SUCCESS )
+ {
+ //
+ // If the receive did not completed successfully then
+ // exit the test app with the error.
+ //
+
+ TpctlErrorLog("\n\tTpctl: The ENDSTRESS command failed, returned 0x%lx.\n",
+ (PVOID)IoStatusBlock2.Status);
+ ExitFlag = TRUE;
+ Status = IoStatusBlock2.Status;
+ break;
+ }
+ else if ( Open[OpenInstance].StressClient == TRUE )
+ {
+ TpctlPrintStressResults(Open[OpenInstance].StressResults,
+ Open[OpenInstance].Ack10 );
+
+ Open[OpenInstance].StressResultsCompleted = FALSE;
+ Open[OpenInstance].StressClient = FALSE;
+ Open[OpenInstance].Stressing = FALSE;
+ }
+ break;
+
+ case BREAKPOINT:
+ break;
+
+ case CMD_COMPLETED:
+ break;
+
+
+ case PERFSERVER:
+ //
+ // If the IOCTL call failed then break out of while loop
+ // by setting the ExitFlag to true.
+ //
+ Status = NtStatus;
+
+ if (( Status != STATUS_SUCCESS ) && ( Status != STATUS_PENDING ))
+ {
+ TpctlErrorLog("\n\tTpctl: NtDeviceIoControlFile failed: returned 0x%lx.\n",
+ (PVOID)NtStatus);
+ ExitFlag = TRUE;
+ break;
+ }
+ //
+ // Wait for the PERFSEND event to be signaled telling us that
+ // the results are complete.
+ //
+
+ if (Status == STATUS_PENDING)
+ {
+ for(;;)
+ {
+ Status = WaitForSingleObject( Open[OpenInstance].PerfEvent,
+ 2000 );
+ if (Status == WAIT_TIMEOUT)
+ {
+ if (!ContinueLooping) // ctl-C was pressed
+ {
+ ContinueLooping = TRUE; // just quit this command
+
+ NtStatus =
+ NtDeviceIoControlFile( hFileHandle,
+ Event,
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock,
+ IOCTL_TP_PERF_ABORT,
+ (PVOID)InputBuffer,
+ InputBufferSize,
+ (PVOID)OutputBuffer,
+ OutputBufferSize );
+
+ if (( NtStatus != STATUS_SUCCESS ) &&
+ ( NtStatus != STATUS_PENDING ))
+ {
+ TpctlErrorLog(
+ "\n\tTpctl: NtDeviceIoControlFile failed: returned 0x%lx.\n",
+ (PVOID)NtStatus);
+ Status = NtStatus;
+ }
+ ExitFlag = TRUE;
+ break;
+ }
+ }
+ else if ( Status != NO_ERROR )
+ {
+ //
+ // If the wait for single object failed, then exit the
+ // test app with the error.
+ //
+
+ TpctlErrorLog("\n\tWaitForSingleObject failed: returned 0x%lx.\n",
+ (PVOID)Status);
+ ExitFlag = TRUE;
+ break;
+ }
+ else if ( IoStatusBlock2.Status != STATUS_SUCCESS )
+ {
+ //
+ // If the command did not complete successfully then
+ // exit the test app with the error.
+ //
+
+ TpctlErrorLog(
+ "\n\tTpctl: The PERFSERVER command failed,returned 0x%lx.\n",
+ (PVOID)IoStatusBlock2.Status);
+ ExitFlag = TRUE;
+ Status = IoStatusBlock2.Status;
+ break;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ //
+ // then reset the SEND control flags to the initial state
+ // and return.
+ //
+ Open[OpenInstance].PerfResultsCompleted = FALSE;
+ break;
+
+
+ case PERFCLIENT:
+ //
+ // If the IOCTL call failed then break out of while loop
+ // by setting the ExitFlag to true.
+ //
+
+ if (( NtStatus != STATUS_SUCCESS ) && ( NtStatus != STATUS_PENDING ))
+ {
+ TpctlErrorLog("\n\tTpctl: NtDeviceIoControlFile failed: returned 0x%lx.\n",
+ (PVOID)NtStatus);
+ ExitFlag = TRUE;
+ Status = NtStatus;
+ break;
+ }
+ //
+ // Wait for the RECEIVE event to be signaled telling us that
+ // the results are complete.
+ //
+
+ for(;;)
+ {
+ Status = WaitForSingleObject( Open[OpenInstance].PerfEvent,
+ 2000 );
+ if (Status == WAIT_TIMEOUT)
+ {
+ if (!ContinueLooping) // ctl-C was pressed
+ {
+ ContinueLooping = TRUE; // just quit this command
+
+ NtStatus = NtDeviceIoControlFile( hFileHandle,
+ Event,
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock,
+ IOCTL_TP_PERF_ABORT,
+ (PVOID)InputBuffer,
+ InputBufferSize,
+ (PVOID)OutputBuffer,
+ OutputBufferSize );
+
+ if (( NtStatus != STATUS_SUCCESS ) &&
+ ( NtStatus != STATUS_PENDING ))
+ {
+ TpctlErrorLog(
+ "\n\tTpctl: NtDeviceIoControlFile failed: returned 0x%lx.\n",
+ (PVOID)NtStatus);
+ Status = NtStatus;
+ }
+ ExitFlag = TRUE;
+ break;
+ }
+ }
+
+ else if ( Status != NO_ERROR )
+ {
+ //
+ // If the wait for single object failed, then exit the
+ // test app with the error.
+ //
+
+ TpctlErrorLog("\n\tWaitForSingleObject failed: returned 0x%lx.\n",
+ (PVOID)Status);
+ ExitFlag = TRUE;
+ break;
+ }
+ else if ( IoStatusBlock2.Status != STATUS_SUCCESS )
+ {
+ //
+ // If the receive did not completed successfully then
+ // exit the test app with the error.
+ //
+
+ TpctlErrorLog("\n\tTpctl: The PERFCLIENT command failed, returned 0x%lx.\n",
+ (PVOID)IoStatusBlock2.Status);
+ ExitFlag = TRUE;
+ Status = IoStatusBlock2.Status;
+ break;
+ }
+
+ //
+ // If here, status was succes. Print the send test results.
+ //
+
+ else
+ {
+ TpctlPrintPerformResults( Open[OpenInstance].PerfResults);
+
+ //
+ // then reset the RECEIVE control flags to the initial state
+ // and return.
+ //
+
+ Open[OpenInstance].PerfResultsCompleted = FALSE;
+ break;
+ }
+ }
+ break;
+
+ default:
+ TpctlErrorLog("\n\tTpctl: Invalid Command Entered.\n",NULL);
+ break;
+
+ } // switch();
+
+ //
+ // Now zero out the input and output buffers to guarantee no
+ // random garbage on the next call.
+ //
+
+ ZeroMemory( InputBuffer,InputBufferSize );
+
+ if (((( CmdCode == STRESS ) || ( CmdCode == STRESSSERVER )) ||
+ ( CmdCode == SEND )) || ( CmdCode == RECEIVE ))
+ {
+ ZeroMemory( OutputBuffer2,OutputBufferSize2 );
+ }
+ else if (( CmdCode != CMD_ERR ) && ( CmdCode != CMD_COMPLETED ))
+ {
+ ZeroMemory( OutputBuffer,OutputBufferSize );
+ }
+ }
+
+ //
+ // The test has ended either successfully or not, close any opened
+ // script files, deallocate the memory buffers, and return status.
+ //
+
+ TpctlCloseScripts();
+
+ // Reset State
+
+ GlobalFree( InputBuffer );
+ GlobalFree( OutputBuffer );
+ CloseHandle( Event );
+
+ return Status;
+}
+
+
+
+VOID
+TpctlGetEvents(
+ IN HANDLE FileHandle,
+ IN HANDLE InputBuffer,
+ IN DWORD InputBufferSize
+ )
+{
+ DWORD Status;
+ HANDLE OutputBuffer;
+ DWORD OutputBufferSize = IOCTL_BUFFER_SIZE;
+ HANDLE Event;
+ IO_STATUS_BLOCK IoStatusBlock;
+ BOOL ReadFromEventQueue = FALSE;
+
+ ContinueLooping = TRUE;
+
+ OutputBuffer = GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT,OutputBufferSize );
+
+ if ( OutputBuffer == NULL )
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: GlobalAlloc failed to alloc OutputBuffer: returned 0x%lx.\n",
+ (PVOID)Status);
+ return;
+ }
+
+ Event = CreateEvent( NULL,FALSE,FALSE,NULL );
+
+ if ( Event == NULL )
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: CreateEvent failed: returned 0x%lx.\n",(PVOID)Status);
+ GlobalFree( OutputBuffer );
+ return;
+ }
+
+ TpctlLog("\n",NULL);
+
+ do
+ {
+ //
+ // We want to continuously call the driver for the
+ // event information, until the event queue is empty.
+ // this is represented by the IoStatusBlock.Status
+ // being STATUS_FAILURE.
+ //
+
+// !!NOT WIN32!!
+
+ Status = NtDeviceIoControlFile( FileHandle,
+ Event,
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock,
+ TP_CONTROL_CODE( GETEVENTS,IOCTL_METHOD ),
+ (PVOID)InputBuffer,
+ InputBufferSize,
+ (PVOID)OutputBuffer,
+ OutputBufferSize );
+
+ if ((( Status != TP_STATUS_NO_EVENTS ) &&
+ ( Status != STATUS_SUCCESS )) &&
+ ( Status != STATUS_PENDING ))
+ {
+ TpctlErrorLog("\n\tTpctl: NtDeviceIoControlFile failed: returned 0x%lx.\n",
+ (PVOID)Status);
+ }
+ else if ( Status == TP_STATUS_NO_EVENTS )
+ {
+ TpctlLog("\tTpctl: Event Queue is empty.\tMAY_DIFFER\n",NULL);
+ }
+ else
+ {
+ Status = WaitForSingleObject( Event,0xFFFFFFFF );
+
+ if ( Status != STATUS_SUCCESS )
+ {
+ TpctlErrorLog("\n\tTpctl: WaitForSingleObject failed: returned 0x%lx.\n",
+ (PVOID)Status);
+ }
+ else if ( IoStatusBlock.Status == TP_STATUS_NO_EVENTS )
+ {
+ TpctlLog("\tTpctl: Event Queue is empty.\tMAY_DIFFER\n",NULL);
+ }
+ else if ( IoStatusBlock.Status == STATUS_SUCCESS )
+ {
+ TpctlPrintEventResults( (PEVENT_RESULTS)OutputBuffer );
+ }
+ else
+ {
+ TpctlErrorLog("\tTpctl: Error getting events from driver.\n",NULL);
+ }
+ }
+ } while ((( IoStatusBlock.Status == STATUS_SUCCESS ) &&
+ ( ContinueLooping == TRUE )) &&
+ ( Status == STATUS_SUCCESS ));
+
+ GlobalFree( OutputBuffer );
+ CloseHandle( Event );
+
+ return;
+}
+
+
+
+VOID
+TpctlPauseGo(
+ IN HANDLE FileHandle,
+ IN HANDLE InputBuffer,
+ IN DWORD InputBufferSize,
+ IN DWORD CmdCode
+ )
+{
+ DWORD Status;
+ IO_STATUS_BLOCK IoStatusBlock;
+ HANDLE OutputBuffer;
+ DWORD OutputBufferSize = IOCTL_BUFFER_SIZE;
+ ULONG TimedOut = 0;
+
+ OutputBuffer = GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT,OutputBufferSize );
+
+ if ( OutputBuffer == NULL )
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: GlobalAlloc failed to alloc OutputBuffer: returned 0x%lx.\n",
+ (PVOID)Status);
+ return;
+ }
+
+ ContinueLooping = TRUE;
+
+ do
+ {
+ //
+ // We want to continuously call the driver for PAUSE or GO
+ // until a Go is received or the Pause is acknowledged.
+ //
+
+// !!NOT WIN32!!
+
+ Status = NtDeviceIoControlFile( FileHandle,
+ NULL, // Event,
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock,
+ TP_CONTROL_CODE( CmdCode,IOCTL_METHOD ),
+ (PVOID)InputBuffer,
+ InputBufferSize,
+ (PVOID)OutputBuffer,
+ OutputBufferSize );
+
+ if ( Status != STATUS_SUCCESS )
+ {
+ TpctlErrorLog("\n\tTpctl: NtDeviceIoControlFile failed: returned 0x%lx.\n",
+ (PVOID)Status);
+ }
+ else if (((PREQUEST_RESULTS)OutputBuffer)->RequestStatus == TP_STATUS_TIMEDOUT )
+ {
+ //
+ // The GO or PAUSE timed out, if we have looped ten times
+ // display the error to the user.
+ //
+
+ if (( ++TimedOut % 12 ) == 0 ) // Two Minutes
+ {
+ if ( CmdCode == GO )
+ {
+ printf("\n\tTpctl: GO timed out prior to receiving acknowledgment packet.\n",
+ NULL);
+ printf("\t Re-Sending...\n",NULL);
+ }
+ else
+ {
+ printf("\n\tTpctl: PAUSE timed out prior to receiving GO packet.\n",NULL);
+ printf("\t Re-Waiting...\n",NULL);
+ }
+ }
+ }
+ else if (((PREQUEST_RESULTS)OutputBuffer)->RequestStatus != NDIS_STATUS_SUCCESS )
+ {
+ //
+ // The call to send a GO or GO_ACK packet failed, display the
+ // error to the user.
+ //
+
+ if ( CmdCode == GO )
+ {
+ TpctlErrorLog("\n\tTpctl: Failed to send the GO packet: returned %s.\n",
+ (PVOID)TpctlGetStatus(((PREQUEST_RESULTS)OutputBuffer)->RequestStatus));
+ }
+ else
+ {
+ TpctlErrorLog("\n\tTpctl: Failed to send the acknowledgment packet: returned %s.\n",
+ (PVOID)TpctlGetStatus(((PREQUEST_RESULTS)OutputBuffer)->RequestStatus));
+ }
+
+ Status = ((PREQUEST_RESULTS)OutputBuffer)->RequestStatus;
+ }
+ else
+ {
+ //
+ // The GO or PAUSE has completed successfully, break
+ // out of the loop.
+ //
+ break;
+ }
+ } while (( ContinueLooping == TRUE ) && ( Status == NO_ERROR ));
+
+ if (( Status != NO_ERROR ) || ( ContinueLooping == FALSE ))
+ {
+ //
+ // If we are reading commands from a script, assume
+ // that the failure should force the test to stop,
+ // therefore unload the script files, and reset the
+ // state all opens back to the initial state.
+ //
+
+ if ( !ContinueOnError )
+ {
+ TpctlResetAllOpenStates( FileHandle );
+ TpctlCloseScripts();
+ }
+ }
+
+ GlobalFree( OutputBuffer );
+
+ return;
+}
+
+
+
+VOID
+TpctlLoadUnload(
+ IN DWORD CmdCode
+ )
+{
+ SERVICE_STATUS ServiceStatus ;
+ SC_HANDLE ServiceControlMgrHandle ;
+ SC_HANDLE ServiceHandle ;
+ NTSTATUS Status ;
+
+ //
+ // Open the service control manager
+ //
+ ServiceControlMgrHandle = OpenSCManager( NULL, NULL, GENERIC_EXECUTE );
+ ServiceHandle = OpenService(ServiceControlMgrHandle,
+ GlobalCmdArgs.ARGS.DriverName,
+ SERVICE_START|SERVICE_STOP );
+
+ if ( CmdCode == LOAD )
+ {
+ if ( !StartService( ServiceHandle, 0, NULL ) )
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: Failed to load MAC driver : %s\n",
+ (PVOID)GlobalCmdArgs.ARGS.DriverName);
+ TpctlErrorLog("\tError Code Status = %ldL.\n",(PVOID)Status);
+ }
+ else
+ {
+ TpctlLog( "\n\tLoaded driver %s successfully\tMAY_DIFFER\n",
+ GlobalCmdArgs.ARGS.DriverName );
+ }
+ }
+ else
+ {
+ if ( !ControlService( ServiceHandle, SERVICE_CONTROL_STOP, &ServiceStatus ) )
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tTpctl: Failed to unload MAC driver : %s\n",
+ (PVOID)GlobalCmdArgs.ARGS.DriverName);
+ TpctlErrorLog("\tError Code Status = %ldL with a Service State of ",(PVOID)Status);
+ TpctlErrorLog("%ld\n",(PVOID)ServiceStatus.dwCurrentState);
+ }
+ else
+ {
+ TpctlLog( "\n\tUnloaded driver %s successfully.\tMAY_DIFFER\n",
+ GlobalCmdArgs.ARGS.DriverName );
+ }
+ }
+
+}
+
+
+
+VOID
+TpctlQueryStatistics(
+ IN PUCHAR DriverName,
+ IN NDIS_OID OID,
+ IN PUCHAR StatsBuffer,
+ IN DWORD BufLen
+ )
+{
+ HANDLE FileHandle;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ IO_STATUS_BLOCK IoStatusBlock;
+ ANSI_STRING DrvrNameString;
+ UNICODE_STRING UnicodeDrvrName;
+ DWORD NameLength;
+ LPSTR NameBuffer;
+ NTSTATUS Status;
+ PUCHAR TmpBuf[265];
+
+ NameLength = strlen( DriverName ) + 1 + 8;
+
+ NameBuffer = (LPSTR)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
+ NameLength );
+
+ if ( NameBuffer == NULL )
+ {
+ Status = GetLastError();
+ TpctlErrorLog("\n\tGlobalAlloc failed to alloc NameBuffer: returned 0x%lx.\n",
+ (PVOID)Status);
+ return;
+ }
+
+ ZeroMemory( NameBuffer, NameLength );
+
+ memcpy( NameBuffer,"\\Device\\",8 );
+ memcpy( NameBuffer + 8, DriverName, NameLength - 8 );
+
+// !!NOT WIN32!!
+
+ RtlInitString( &DrvrNameString, NameBuffer );
+
+// !!NOT WIN32!!
+
+ RtlAnsiStringToUnicodeString( &UnicodeDrvrName, &DrvrNameString, TRUE );
+
+// !!NOT WIN32!!
+
+ InitializeObjectAttributes( &ObjectAttributes,
+ &UnicodeDrvrName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+// !!NOT WIN32!!
+
+ Status = NtOpenFile(&FileHandle,
+ SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_ALERT );
+
+ if (Status != STATUS_SUCCESS )
+ {
+ TpctlErrorLog("\n\tTpctl: NtOpenFile returned %lx\n\n", (PVOID)Status);
+ return;
+ }
+
+// !!NOT WIN32!!
+
+ Status = NtDeviceIoControlFile( FileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ IOCTL_NDIS_QUERY_GLOBAL_STATS,
+ (PVOID)&OID,
+ sizeof( NDIS_OID ),
+ (PVOID)TmpBuf, //StatsBuffer,
+ 256); //Buflen
+
+ if (( Status != STATUS_SUCCESS ) &&
+ ( IoStatusBlock.Status != STATUS_SUCCESS ))
+ {
+
+ TpctlErrorLog("\n\tTpctl: NtDeviceIoControlFile returned %lx\n\n",
+ (PVOID)IoStatusBlock.Status);
+ return;
+ }
+
+ TpctlLog("\n\tOID 0x%8.8lx ", (PVOID)OID);
+ TpctlLog("len %d ", (PVOID)IoStatusBlock.Information );
+ TpctlLog("value %u\tMAY_DIFFER\n\n", (PVOID)TmpBuf[0]);
+
+// !!NOT WIN32!!
+
+ RtlFreeUnicodeString( &UnicodeDrvrName );
+
+// !!NOT WIN32!!
+
+ Status = NtClose( FileHandle );
+}
+
+
+BOOL
+Disable(
+ IN DWORD argc,
+ IN LPSTR argv[]
+ )
+{
+ UINT EnvCounter1 = 0 , EnvCounter2 = 0 ;
+ DWORD i;
+ CHAR TmpBuffer[256];
+
+ ZeroMemory( TmpBuffer, 256 );
+
+ //
+ // Detected command Disable
+ //
+ for( i = 1; i < argc; i++ )
+ {
+ EnvCounter1++;
+
+ ZeroMemory ( TmpBuffer, sizeof( TmpBuffer ) );
+ strncpy( TmpBuffer, argv[i], strlen( argv[i] ) );
+
+ if ( getenv( TmpBuffer ) != NULL )
+ {
+ EnvCounter2++;
+ }
+ }
+
+ //
+ // If all the environment variables have been enabled
+ // we must re-enable the tool. Setting of all the
+ // enviornment variables indicates that all those
+ // modes are supported and there is no need to disable
+ // the tool. If has been disabled by a previous disable
+ // it would require an enable to activate the tool
+ //
+ if ( (EnvCounter1 == EnvCounter2) && (EnvCounter1 != 0) )
+ {
+ printf("\n\tSupport for ");
+ for( i = 1; i < argc; i++ )
+ {
+ if ( i == (argc-1) )
+ {
+ printf("%s ", argv[i] );
+ }
+ else
+ {
+ if ( (i%2) == 0 )
+ {
+ printf("\n\t");
+ }
+ printf("%s, ", argv[i] );
+ }
+ }
+ printf("modes has been detected.\n\tTPCTL has not been disabled.\n\n");
+ return FALSE;
+ }
+
+ //
+ // Disable TPCTL
+ //
+ ToolActive = FALSE;
+ return TRUE;
+}
+
+
diff --git a/private/ntos/ndis/testprot/tpctl/tpctl.h b/private/ntos/ndis/testprot/tpctl/tpctl.h
new file mode 100644
index 000000000..129562c1f
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpctl/tpctl.h
@@ -0,0 +1,751 @@
+// -----------------------------------
+//
+// Copyright (c) 1990 Microsoft Corporation
+//
+// Module Name:
+//
+// tpctl.h
+//
+// Abstract:
+//
+// This module defines the external definitions used for the MAC Tester
+//
+// Author:
+//
+// Tom Adams (tomad) 11-May-1991
+//
+// Revision History:
+//
+// 11-May-1991 tomad
+// Created
+//
+// 4-27-94 timothyw
+// Added performance test; CPP style comments
+// 5-18-94
+// Added globvars; fixed warnings
+// 6-08-94
+// chgs for client/server model, perf tests
+//
+// -----------------------------------
+
+#include "tp_ndis.h"
+#include "common.h"
+
+//
+//
+//
+
+extern CMD_ARGS GlobalCmdArgs;
+
+extern LPSTR GlobalBuf;
+
+extern BOOL Verbose;
+
+extern BOOL CommandsFromScript;
+
+extern BOOL CommandLineLogging;
+
+extern BOOL RecordToScript;
+
+extern HANDLE CommandLineLogHandle;
+
+extern HANDLE ScriptRecordHandle;
+
+extern CHAR RecordScriptName[TPCTL_MAX_PATHNAME_SIZE];
+
+extern BOOL ExitFlag;
+
+extern BOOL ContinueLooping;
+
+extern INT TpctlSeed;
+
+//
+// Script Control is used to keep track of where in a script file the
+// application is, and where to log the next set of results in the
+// respective log file.
+//
+
+typedef struct _SCRIPTCONTROL {
+ LPSTR ScriptFile;
+ BOOL IsLowestLevel;
+ LPBYTE Buffer;
+ DWORD Length;
+
+ DWORD BufIndex;
+ HANDLE LogHandle;
+ LPSTR LogFile;
+} SCRIPTCONTROL, * PSCRIPTCONTROL;
+
+//
+// Scripts is an array of 10 script control structures allowing recursion
+// of upto ten script files at any one time. Any more then 10 and an error
+// occurs resulting in the closing of all upper recursive levels of script
+// files.
+//
+
+#define TPCTL_MAX_SCRIPT_LEVELS 10
+
+extern SCRIPTCONTROL Scripts[TPCTL_MAX_SCRIPT_LEVELS+1];
+
+extern DWORD ScriptIndex;
+
+//
+// Initialize the script array.
+//
+
+// ------
+//
+// VOID
+// TpctlInitializeScripts(
+// VOID
+// );
+//
+// -----
+
+#define TpctlInitializeScripts() { \
+ DWORD i; \
+ ScriptIndex = 0xFFFFFFFF; \
+ for (i=0;i<TPCTL_MAX_SCRIPT_LEVELS+1;i++) { \
+ Scripts[i].ScriptFile = NULL; \
+ Scripts[i].IsLowestLevel = FALSE; \
+ Scripts[i].Buffer = NULL; \
+ Scripts[i].Length = 0; \
+ Scripts[i].BufIndex = 0; \
+ Scripts[i].LogHandle = (HANDLE)-1; \
+ Scripts[i].LogFile = NULL; \
+ } \
+}
+
+//
+// TPCTLCLOSESCRIPTS close any and all script files that
+// are currently opened.
+//
+
+// -----
+//
+// VOID
+// TpctlCloseScripts(
+// VOID
+// );
+//
+// -----
+
+#define TpctlCloseScripts() { \
+ if ( CommandsFromScript == TRUE ) { \
+ while ( ScriptIndex != (ULONG)-1 ) { \
+ TpctlUnLoadFiles(); \
+ } \
+ } \
+}
+
+//
+// PRINT_DIFF_FLAG will print the diff flag string S into the buffer B
+// if we are printing the results to a logfile.
+//
+
+// -----
+//
+// VOID
+// ADD_DIFF_FLAG(
+// LPSTR B
+// LPSTR S
+// );
+//
+// -----
+
+#define ADD_DIFF_FLAG( B,S ) { \
+ if (( CommandsFromScript ) || ( CommandLineLogging )) { \
+ B += (BYTE)sprintf(B,"\t%s",S); \
+ } \
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\n"); \
+}
+
+#define ADD_SKIP_FLAG( B,S ) ADD_DIFF_FLAG( B,S )
+
+//
+// Reset all opens to their initial state.
+//
+
+// -----
+//
+// VOID
+// TpctlResetAllOpenStates(
+// HANDLE fh
+// );
+//
+// -----
+
+#define TpctlResetAllOpenStates( fh ) { \
+ DWORD i; \
+ if ( CommandsFromScript ) { \
+ TpctlErrorLog("\n\tTpctl: Resetting the state of all Open Instances.\n",NULL); \
+ for ( i = 0 ; i < NUM_OPEN_INSTANCES ; i++ ) { \
+ TpctlResetOpenState( &Open[i],fh ); \
+ } \
+ } \
+}
+
+//
+// Parse Tables are the structures used to contain each of the possible
+// argument names for a given command, and their value.
+//
+
+typedef struct _ParsedIntTable {
+ LPSTR FieldName;
+ DWORD FieldValue;
+} PARSETABLE, *PPARSETABLE;
+
+//
+// Paramtypes are the different types of parameters that may be parsed
+// by the ParseOptions routine for each command.
+//
+
+//
+// STARTCHANGE
+//
+typedef enum {
+ Integer,
+ String,
+ ParsedInteger,
+// Address2, // Accomodate 802.3, 802.4, 802.5, FDDI addresses
+ Address4, // Accomodate 802.4, 802.5 addresses
+ Address6, // Accomodate 802.3, 802.4, 802.5, FDDI addresses
+// Address2or6 // Conjugate type in which addresses can be 2 or 6 octets
+} PARAMTYPES;
+//
+// STOPCHANGE
+//
+
+
+//
+// The Test Options structures is used by the ParseOptions routine to
+// load the default value for a given argument, set up the prompt for
+// the argument and prompt the user for the argument. If the command is
+// entered from a script file the Test Options structures is used to
+// determine the Argument names or abbreviations and then stores the
+// values in their proper destinations.
+//
+
+typedef struct _TestOptions {
+ DWORD OptionNumber;
+ LPSTR TestPrompt;
+ LPSTR ArgName;
+ LPSTR ArgNameAbbr;
+ BOOL ArgValueSet;
+ PARAMTYPES TestType;
+ DWORD IntegerDefault;
+ LPSTR StringDefault;
+ PPARSETABLE ParsedIntTable;
+ DWORD ParsedIntTableSize;
+ PVOID Destination;
+} TESTPARAMS, *PTESTPARAMS;
+
+//
+// Array entries for the Events in the Open Block
+//
+
+typedef enum {
+ TPCONTROL,
+ TPSTRESS,
+ TPSEND,
+ TPRECEIVE,
+ TPPERF
+} TPEVENT_TYPE;
+
+//
+// Multicast Address struct used to create a list of all the
+// address set on a given open.
+//
+
+typedef struct _MULT_ADDR {
+ struct _MULT_ADDR *Next;
+ BYTE MulticastAddress[ADDRESS_LENGTH];
+} MULT_ADDR, *PMULT_ADDR;
+
+//
+// the Open Block holding the info about the state of the open,
+// particulars about the card opened, and the control structs for
+// each of the given test types.
+//
+
+typedef struct _OPEN_BLOCK {
+ DWORD Signature;
+ UCHAR OpenInstance;
+ BOOL AdapterOpened;
+ NDIS_MEDIUM MediumType;
+ DWORD NdisVersion;
+
+ LPBYTE AdapterName;
+ BYTE AdapterAddress[ADDRESS_LENGTH];
+ PENVIRONMENT_VARIABLES EnvVars;
+
+ BOOL EventThreadStarted;
+ HANDLE Events[5];
+
+ BOOL Stressing;
+ PCMD_ARGS StressArgs;
+ IO_STATUS_BLOCK StressStatusBlock;
+ HANDLE StressEvent;
+ PSTRESS_RESULTS StressResults;
+ BOOL StressResultsCompleted;
+ BOOL StressClient;
+ BOOL Ack10;
+
+ BOOL Sending;
+ PCMD_ARGS SendArgs;
+ IO_STATUS_BLOCK SendStatusBlock;
+ HANDLE SendEvent;
+ PSEND_RECEIVE_RESULTS SendResults;
+ BOOL SendResultsCompleted;
+
+ BOOL Receiving;
+ IO_STATUS_BLOCK ReceiveStatusBlock;
+ HANDLE ReceiveEvent;
+ PSEND_RECEIVE_RESULTS ReceiveResults;
+ BOOL ReceiveResultsCompleted;
+
+ IO_STATUS_BLOCK PerfStatusBlock;
+ HANDLE PerfEvent;
+ PPERF_RESULTS PerfResults;
+ BOOL PerfResultsCompleted;
+
+ DWORD PacketFilter;
+
+ DWORD LookaheadSize;
+ PMULT_ADDR MulticastAddresses;
+ ULONG NumberMultAddrs;
+ BYTE FunctionalAddress[FUNCTIONAL_ADDRESS_LENGTH];
+
+ BYTE GroupAddress[FUNCTIONAL_ADDRESS_LENGTH];
+} OPEN_BLOCK, *POPEN_BLOCK;
+
+extern OPEN_BLOCK Open[NUM_OPEN_INSTANCES];
+
+#define OPEN_BLOCK_SIGNATURE 0x12121212
+
+//
+// TPCTL.C function prototypes
+//
+
+DWORD
+TpctlInitializeOpenArray(
+ VOID
+ );
+
+VOID
+TpctlFreeOpenArray(
+ VOID
+ );
+
+DWORD
+TpctlOpenTpdrvr(
+ IN OUT PHANDLE lphFileHandle
+ );
+
+VOID
+TpctlCloseTpdrvr(
+ IN HANDLE hFileHandle
+ );
+
+DWORD
+TpctlStartEventHandlerThread(
+ IN POPEN_BLOCK Open
+ );
+
+VOID
+TpctlStopEventHandlerThread(
+ IN POPEN_BLOCK Open
+ );
+
+DWORD
+TpctlEventHandler(
+ IN LPVOID Open
+ );
+
+BOOL
+TpctlCtrlCHandler(
+ IN DWORD CtrlType
+ );
+
+//
+//
+//
+
+DWORD
+TpctlRunTest(
+ IN HANDLE hFileHandle
+ );
+
+VOID
+TpctlGetEvents(
+ IN HANDLE FileHandle,
+ IN HANDLE InputBuffer,
+ IN DWORD InputBufferSize
+ );
+
+VOID
+TpctlPauseGo(
+ IN HANDLE FileHandle,
+ IN HANDLE InputBuffer,
+ IN DWORD InputBufferSize,
+ IN DWORD CmdCode
+ );
+
+DWORD
+TpctlResetOpenState(
+ IN POPEN_BLOCK Open,
+ IN HANDLE FileHandle
+ );
+
+VOID
+TpctlLoadUnload(
+ IN DWORD CmdCode
+ );
+
+VOID
+TpctlQueryStatistics(
+ IN PUCHAR DriverName,
+ IN NDIS_OID OID,
+ IN PUCHAR StatsBuffer,
+ IN DWORD BufLen
+ );
+
+BOOL
+Disable(
+ IN DWORD argc,
+ IN LPSTR argv[]
+ );
+
+//
+//
+//
+
+
+VOID
+TpctlPrintResults(
+ PREQUEST_RESULTS Results,
+ DWORD CmdCode,
+ NDIS_OID OID
+ );
+
+VOID
+TpctlPrintQueryInfoResults(
+ PREQUEST_RESULTS Results,
+ DWORD CmdCode,
+ NDIS_OID OID
+ );
+
+VOID
+TpctlPrintSetInfoResults(
+ PREQUEST_RESULTS Results,
+ DWORD CmdCode,
+ NDIS_OID OID
+ );
+
+VOID
+TpctlPrintSendResults(
+ PSEND_RECEIVE_RESULTS Results
+ );
+
+VOID
+TpctlPrintReceiveResults(
+ PSEND_RECEIVE_RESULTS Results
+ );
+
+VOID
+TpctlPrintPerformResults(
+ PPERF_RESULTS Results
+ );
+
+VOID
+TpctlPrintStressResults1(
+ IN PSTRESS_RESULTS Results,
+ IN BOOL Ack10
+ );
+
+VOID
+TpctlPrintStressResults(
+ PSTRESS_RESULTS Results,
+ IN BOOL Ack10
+ );
+
+VOID
+TpctlPrintEventResults(
+ PEVENT_RESULTS Event
+ );
+
+VOID
+TpctlZeroStressStatistics(
+ PSTRESS_RESULTS Results
+ );
+
+DWORD
+TpctlLog(
+ LPSTR String,
+ PVOID Input
+ );
+
+DWORD
+TpctlErrorLog(
+ LPSTR String,
+ PVOID Input
+ );
+
+DWORD
+TpctlScriptLog(
+ LPSTR String,
+ PVOID Input
+ );
+
+DWORD
+TpctlCmdLneLog(
+ LPSTR String,
+ PVOID Input
+ );
+
+//
+// CMD.C function prototypes
+//
+
+DWORD
+TpctlParseCommandLine(
+ IN WORD argc,
+ IN LPSTR argv[]
+ );
+
+VOID
+TpctlUsage(
+ VOID
+ );
+
+VOID
+TpctlHelp(
+ LPSTR Command
+ );
+
+DWORD
+TpctlLoadFiles(
+ IN LPSTR ScriptFile,
+ IN LPSTR LogFile
+ );
+
+
+VOID
+TpctlUnLoadFiles(
+ VOID
+ );
+
+
+HANDLE
+TpctlOpenLogFile(
+ VOID
+ );
+
+
+VOID
+TpctlCloseLogFile(
+ VOID
+ );
+
+
+HANDLE
+TpctlOpenScriptFile(
+ VOID
+ );
+
+
+VOID
+TpctlCloseScriptFile(
+ VOID
+ );
+
+DWORD
+TpctlReadCommand(
+ IN LPSTR Prompt,
+ OUT LPSTR Response,
+ IN DWORD MaximumResponse
+ );
+
+
+BOOL
+TpctlParseCommand(
+ IN LPSTR CommandLine,
+ OUT LPSTR Argv[],
+ OUT PDWORD Argc,
+ IN DWORD MaxArgc
+ );
+
+
+VOID
+TpctlPrompt(
+ LPSTR Prompt,
+ LPSTR Buffer,
+ DWORD BufferSize
+ );
+
+
+VOID
+TpctlLoadLastEnvironmentVariables(
+ DWORD OpenInstance
+ );
+
+
+VOID
+TpctlSaveNewEnvironmentVariables(
+ DWORD OpenInstance
+ );
+
+VOID
+TpctlPerformRegistryOperation(
+ IN PCMD_ARGS CmdArgs
+ );
+BOOL
+TpctlInitCommandBuffer(
+ IN OUT PCMD_ARGS CmdArgs,
+ IN DWORD CmdType
+ );
+
+
+LPSTR
+TpctlGetEventType(
+ TP_EVENT_TYPE TpEventType
+ );
+
+
+LPSTR
+TpctlGetStatus(
+ NDIS_STATUS GeneralStatus
+ );
+
+
+DWORD
+TpctlGetCommandCode(
+ LPSTR Argument
+ );
+
+
+LPSTR
+TpctlGetCommandName(
+ LPSTR Command
+ );
+
+LPSTR
+TpctlGetCmdCode(
+ DWORD CmdCode
+ );
+
+
+VOID
+TpctlCopyAdapterAddress(
+ DWORD OpenInstance,
+ PREQUEST_RESULTS Results
+ );
+
+VOID
+TpctlRecordArguments(
+ IN TESTPARAMS Options[],
+ IN DWORD OptionTableSize,
+ IN DWORD argc,
+ IN LPSTR argv[TPCTL_MAX_ARGC]
+ );
+
+LPSTR
+TpctlEnumerateRegistryInfo(
+ IN PUCHAR TmpBuf,
+ IN PUCHAR DbaseName,
+ IN PUCHAR SubKeyName,
+ IN PUCHAR ValueName,
+ IN DWORD ReadValueType,
+ IN PUCHAR ReadValue,
+ IN DWORD ReadValueSize
+ );
+
+LPSTR
+TpctlGetValueType(
+ IN DWORD ValueType
+ );
+
+
+//
+// PARSE.C Function Prototypes
+//
+
+DWORD
+TpctlParseArguments(
+ IN TESTPARAMS Options[],
+ IN DWORD TestSize,
+ IN DWORD ArgC,
+ IN LPSTR ArgV[]
+ );
+
+
+BOOL
+TpctlParseSetInfoArguments(
+ IN OUT DWORD *ArgC,
+ IN OUT LPSTR ArgV[],
+ IN OUT DWORD *tmpArgC,
+ IN OUT LPSTR tmpArgV[]
+ );
+
+
+DWORD
+TpctlParseAddress(
+ IN BYTE Buffer[],
+ OUT PDWORD Ret,
+ IN DWORD OpenInstance,
+ IN DWORD AddressLength
+ );
+
+
+VOID
+Dump_Desired_PacketFilter(
+ LPSTR Buffer,
+ DWORD PacketFilter
+ );
+
+
+VOID
+Dump_Information_Class(
+ LPSTR Buffer,
+ DWORD InfoClass
+ );
+
+
+VOID
+Dump_Ndis_Medium(
+ LPSTR Buffer,
+ DWORD Medium
+ );
+
+//
+// GLOBALS.C Function Prototypes
+//
+
+
+PVOID
+TpctlParseGlobalVariable(
+ IN BYTE Buffer[],
+ IN PARAMTYPES reqtype
+ );
+
+VOID
+TpctlInitGlobalVariables(
+ VOID
+ );
+
+
+DWORD
+TpctlParseSet(
+ IN DWORD ArgC,
+ IN LPSTR ArgV[]
+ );
+
+
+// functions from cpuperf.c
+
+
+VOID CpuUsageInit(VOID);
+
+
+ULONG CpuUsageGetData(PULONG *KernPercent,
+ ULONG NumCpus);
diff --git a/private/ntos/ndis/testprot/tpdiff.new/makefile b/private/ntos/ndis/testprot/tpdiff.new/makefile
new file mode 100644
index 000000000..99bdba8ee
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpdiff.new/makefile
@@ -0,0 +1,11 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
+
+
+cleanup:
+ if exist *.bak del *.bak
+ if exist build.* del build.*
diff --git a/private/ntos/ndis/testprot/tpdiff.new/sources b/private/ntos/ndis/testprot/tpdiff.new/sources
new file mode 100644
index 000000000..7667196a8
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpdiff.new/sources
@@ -0,0 +1,63 @@
+!IF 0
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+!ENDIF
+
+
+# COMMENT: The build "SOURCE" file follows the same syntax as a regular
+# makefile. BUILD includes the SOURCES file into the makefile.def
+# which is to be found in $(BASEDIR)\public\oak\bin. After that
+# has been completed, it passes it on to nmake
+
+
+MAJORCOMP=TESTPROT
+MINORCOMP=TPDIFF
+
+TARGETNAME=tpdiff
+TARGETPATH=obj
+TARGETTYPE=PROGRAM
+
+C_DEFINES=-DWIN32
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\libc.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib \
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib \
+
+
+SOURCES=tpdiff.c
+
+
+#
+# 386
+#
+386_WARNING_LEVEL=-W3
+386_STDCALL=1
+386_OPTIMIZATION=/Fc
+MAX_ID_LENGTH=/H128
+
+#
+# MIPS
+#
+MIPS_FLAGS=-D_stdcall=
+
+#
+# ALPHA
+#
+ALPHA_FLAGS=-D_stdcall=
+
+
+UMTYPE=console
+NTDEBUG=ntsd
diff --git a/private/ntos/ndis/testprot/tpdiff.new/tpdiff.c b/private/ntos/ndis/testprot/tpdiff.new/tpdiff.c
new file mode 100644
index 000000000..3141ef7c5
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpdiff.new/tpdiff.c
@@ -0,0 +1,2527 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ tpdiff.c
+
+Abstract:
+
+ This is the main component of the NDIS 3.0 MAC Tester log file program.
+
+Author:
+
+ Sanjeev Katariya (sanjeevk) 3-May-1993
+
+Revision History:
+
+ created
+
+--*/
+
+
+//
+// Includes
+//
+#include <windows.h>
+#include <stdio.h>
+#include <string.h>
+#include <process.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <math.h>
+#include "tpdiff.h"
+
+
+//
+// Global Variables
+//
+CHAR *Keywords[] = {
+ "-SECTION_START-",
+ "-SECTION_END-" ,
+ "-OPTIONALS-" ,
+ "-TOKEN_MATCH-" ,
+ "-SECTION_DESC-"
+};
+
+PCHAR SummaryBuffer;
+
+
+/*
+ ********************************************************************************
+ * *
+ * General Program Considerations: *
+ * *
+ * This program has been designed for generic section matching. However, since *
+ * the second file for its current use is marked GOLDEN, certain changes have *
+ * been introduced in line comparison and result printing to account for *
+ * special type of file. *
+ * *
+ * *
+ ********************************************************************************
+*/
+
+
+/********************************** main():start ***********************************************/
+
+
+VOID _cdecl
+main(
+ INT argc,
+ CHAR *argv[]
+ )
+{
+
+ FILE *IoFile;
+ FILE *DiffTxtFile;
+ PCHAR *FileList = &argv[1];
+ PCHAR Difference_FileName = ( argc == 4 ) ? argv[3] : "DIFF.TXT" ;
+ PCHAR TmpSummaryBuffer;
+ MFILE FirstFile, SecondFile;
+ UINT NumberOfComparisons = 0 ;
+ UINT NumberOfFilesCompared = 0;
+ UINT i,j;
+ ULONG TotalDifferenceCount = 0;
+ BOOL InputFromFile = FALSE;
+ ULONG FileOpenErrors = 0;
+
+
+ //
+ // 1. CHECK INCOMING ARGUMENT SYNTAX
+ //
+
+ if ( ( argc < 3 ) || ( argc > 4 ) ) {
+
+ Usage();
+ exit( -1 );
+
+ } else {
+
+ printf( "\nMAC NDIS 3.0 Tester - Comparator Tool Version 1.0.2\n\n" );
+
+ }
+
+
+ //
+ // 2. CHECK IF THE FILE LIST TO BE GENERATED IS TO BE EXTRACTED FROM THE COMMAND
+ // LINE OR FROM A FILE
+ //
+
+ if ( !strncmp( argv[1], "-f", 2 ) ||
+ !strncmp( argv[1], "-F", 2 ) ) {
+
+ CHAR Buffer[2*MAX_LINE_SIZE];
+
+ //
+ // 2.A INDICATE THE LIST IS TO BE GENERATED FROM A FILE
+ //
+ InputFromFile = TRUE;
+
+
+ //
+ // 2.B OPEN THE FILE
+ //
+
+ if ( (IoFile = fopen( argv[2], "r" )) == NULL ) {
+
+ printf( "Could not open the primary log list file: %s\n", argv[2] );
+ Usage();
+ exit( -1 );
+
+ }
+
+
+ //
+ // 2.C GENERATE THE FILE PAIRS TO BE ANALYZED
+ //
+
+ //
+ // 2.C.1 DETERMINE THE NUMBER OF VALID FILE PAIRS
+ //
+
+ while( !feof( IoFile ) ) {
+
+ memset( Buffer, 0, sizeof(Buffer) );
+ if ( ( fgets( Buffer, sizeof( Buffer ), IoFile ) != NULL ) &&
+ ( strlen( Buffer ) > 2 ) ) {
+ NumberOfComparisons++;
+ }
+
+ }
+
+
+ //
+ // 2.C.2 ALLOCATE THE APPROPRIATE SIZED BLOCK
+ //
+
+ FileList = (PCHAR *)malloc( (NumberOfComparisons*2)*sizeof( PCHAR ) );
+ if ( FileList == (PCHAR *)NULL ) {
+ printf("The system has run out of memory resources. Unable to run this program.\n");
+ exit( -1 );
+ } else {
+ memset( FileList, 0, (NumberOfComparisons*2)*sizeof( PCHAR ) );
+ }
+
+
+ //
+ // 2.C.2 AND BUILD THE FILE ARRAY LIST
+ //
+
+ i = j = 0;
+ fseek( IoFile, 0, SEEK_SET );
+ while ( !feof( IoFile ) ) {
+
+ //
+ // Get the next line out of the file list file
+ //
+ memset( Buffer, 0, sizeof(Buffer) );
+ if ( ( fgets( Buffer, sizeof( Buffer ), IoFile ) != NULL ) &&
+ ( strlen( Buffer ) > 2 ) ) {
+
+ //
+ // Replace the newline Character with a NULL Character
+ //
+ *(strchr( Buffer, '\n')) = '\0';
+
+ //
+ // Extract the log file name pairs
+ //
+ if ( !GetFilePair( &FileList[j*2], &FileList[(j*2)+1], Buffer ) ) {
+
+ printf("An error occurred determining the file pair at line %d in the file list: %s\n",
+ (i+1), argv[2] );
+ exit( -1 );
+
+ } else {
+
+ //
+ // Increment the file list array counter
+ //
+ j++;
+
+ }
+
+ }
+
+ //
+ // Increment the file line counter
+ //
+ i++;
+
+ }
+
+
+ //
+ // 2.C.3 CLOSE THE FILE
+ //
+ fclose( IoFile );
+
+
+ } else {
+
+ NumberOfComparisons = 1;
+
+ //
+ // The FileList is pre-initialized to the command line arguments and thus we
+ // simply need to set the file pair comparison count
+ //
+
+ }
+
+
+ //
+ // 3. INITIALIZE THE SUMMARY BUFFER
+ //
+ SummaryBuffer = calloc( NumberOfComparisons, MAX_LINE_SIZE );
+ if ( SummaryBuffer == (PCHAR)NULL ) {
+
+ printf("The system has run out of memory resources for this program\n");
+ exit( -1 );
+
+ } else {
+
+ TmpSummaryBuffer = SummaryBuffer ;
+
+ }
+
+ //
+ // 4. OBTAIN THE DIFFERENCE FILE NAME INTO WHICH THE RESULTS WILL BE LOGGED
+ // OR USE THE DEFAULT DIFF.TXT.
+ //
+
+ DiffTxtFile = fopen( Difference_FileName, "w+" );
+
+ if ( DiffTxtFile == (FILE *)NULL ) {
+
+ printf( "Unable to open the difference text file %s for logging the results.\n", Difference_FileName );
+ exit( -1 );
+
+ } else {
+
+ fprintf( DiffTxtFile, "\n\n" );
+
+ }
+
+
+ //
+ // 5. COMPARE THE FILE PAIRS
+ //
+
+ fprintf( DiffTxtFile, "__________DETAILS_LOG__________\n\n" );
+ fprintf( stdout, "__________DETAILS_LOG__________\n\n" );
+ for( i = 0; i < NumberOfComparisons; i++ ) {
+
+ memset( &FirstFile , 0, sizeof( MFILE ) );
+ memset( &SecondFile, 0, sizeof( MFILE ) );
+
+ FirstFile.FileName = FileList[2*i];
+ SecondFile.FileName = FileList[(2*i)+1];
+
+ fprintf( stdout, "Comparing files %s and %s\n", FirstFile.FileName, SecondFile.FileName );
+
+ //
+ // 5.A OPEN THE FILE PAIR
+ //
+ if ( OpenFiles( &FirstFile, FileList[2*i], &SecondFile, FileList[(2*i)+1] ) ) {
+
+ ULONG OldDifferenceCount = TotalDifferenceCount;
+
+ fprintf( DiffTxtFile, "\n\n**Comparing %s and %s\n\n", FirstFile.FileName, SecondFile.FileName );
+
+ NumberOfFilesCompared++;
+
+
+ //
+ // 5.B COMPARE THEM
+ //
+ CompareFiles( &FirstFile, &SecondFile, DiffTxtFile, &TotalDifferenceCount );
+
+
+ //
+ // 5.C LOG THE RESULTS OF THE COMPARISON INTO THE DIFFERENCE FILE
+ //
+ fprintf( DiffTxtFile, "\n\n--TPDIFF %s, %s ERROR(S): %u\n",
+ FirstFile.FileName, SecondFile.FileName, (TotalDifferenceCount-OldDifferenceCount) );
+
+ sprintf( TmpSummaryBuffer, "TPDIFF %s, %s ERROR(S): %u\n",
+ FirstFile.FileName, SecondFile.FileName, (TotalDifferenceCount-OldDifferenceCount) );
+ TmpSummaryBuffer += strlen( TmpSummaryBuffer );
+
+
+ } else {
+
+
+ fprintf( DiffTxtFile, "\n\n--TPDIFF %s, %s", FirstFile.FileName, SecondFile.FileName );
+
+ if ( FirstFile.FileP == (FILE *)NULL ) {
+
+ fprintf( DiffTxtFile, "\tUnable to open file %s\n", FirstFile.FileName );
+
+ }
+
+ if ( SecondFile.FileP == (FILE *)NULL ) {
+
+ fprintf( DiffTxtFile, "\tUnable to open file %s\n", SecondFile.FileName );
+
+ }
+
+
+ sprintf( TmpSummaryBuffer, "TPDIFF %s, %s resulted in a file open error\n",
+ FirstFile.FileName, SecondFile.FileName );
+
+ FileOpenErrors++;
+
+ TmpSummaryBuffer += strlen( TmpSummaryBuffer );
+
+ }
+
+ //
+ // 5.D CLOSE THE FILE PAIR
+ //
+ CloseFiles( FirstFile, SecondFile );
+ FirstFile.FileName = (PCHAR)NULL;
+ SecondFile.FileName = (PCHAR)NULL;
+ FirstFile.FileP = (FILE *)NULL;
+ SecondFile.FileP = (FILE *)NULL;
+
+ //
+ // 5.E FREE THE FILE PAIR FROM THE LIST
+ //
+ free( FileList[2*i] );
+ free( FileList[(2*i)+1] );
+
+
+ }
+ fprintf( DiffTxtFile, "\n__________END_DETAILS_LOG__________\n\n" );
+ fprintf( stdout, "\n__________END_DETAILS_LOG__________\n\n" );
+
+ //
+ // 6. LOG THE CUMMULATIVE RESULTS AND SUMMARY INTO THE DIFFERENCE FILE AND STDOUT
+ //
+
+ fprintf( DiffTxtFile, "\n\n__________SUMMARY_LOG__________\n\n" );
+ fprintf( DiffTxtFile, SummaryBuffer );
+ fprintf( DiffTxtFile, "\n__________END_SUMMARY_LOG__________\n\n" );
+ fprintf( DiffTxtFile, "\n\n__________CUMMALATIVE_RESULTS_LOG__________\n\n" );
+ fprintf( DiffTxtFile, "COMPARED %d FILE PAIR(S)\n" , NumberOfFilesCompared );
+ fprintf( DiffTxtFile, "TOTAL NUMBER OF DIFFERENCES ENCOUNTERED: %u\n", TotalDifferenceCount );
+ fprintf( DiffTxtFile, "TOTAL NUMBER OF FILE OPEN ERRORS : %u\n", FileOpenErrors );
+ fprintf( DiffTxtFile, "\n__________END_CUMMALATIVE_RESULTS_LOG__________\n\n" );
+
+ fprintf( stdout, "\n\n__________SUMMARY_LOG__________\n\n" );
+ fprintf( stdout, SummaryBuffer );
+ fprintf( stdout, "\n__________END_SUMMARY_LOG__________\n\n" );
+ fprintf( stdout, "\n\n__________CUMMALATIVE_RESULTS_LOG__________\n\n" );
+ fprintf( stdout, "COMPARED %d FILE PAIR(S)\n" , NumberOfFilesCompared );
+ fprintf( stdout, "TOTAL NUMBER OF DIFFERENCES ENCOUNTERED: %u\n", TotalDifferenceCount );
+ fprintf( stdout, "TOTAL NUMBER OF FILE OPEN ERRORS : %u\n", FileOpenErrors );
+ fprintf( stdout, "\n__________END_CUMMALATIVE_RESULTS_LOG__________\n\n" );
+
+
+ //
+ // 7. CLOSE THE DIFFERENCE FILE AND PERFORM ANY REMAINING CLEANUP
+ //
+
+ fclose( DiffTxtFile );
+ free( SummaryBuffer );
+ if ( InputFromFile ) {
+
+ free( FileList );
+
+ }
+
+}
+
+/********************************** main():end *************************************************/
+
+
+
+
+
+VOID
+Usage()
+{
+
+ printf( "\n\tUsage: TPDIFF LOG_FILE GOLDEN_LOG_FILE [DIFFS_FILE]\n\n" );
+
+
+ printf( "\tWhere:\n\n");
+
+
+ printf( "\tLOG_FILE - is the log file that is to be verified\n" );
+ printf( "\t for correctness.\n" );
+ printf( "\tKNOWN_LOG_FILE - is the known good log file that will be\n" );
+ printf( "\t used to verify the log file.\n" );
+ printf( "\tDIFFS_FILE - is the file the differences, if any exist,\n" );
+ printf( "\t between the log files and the known good log\n" );
+ printf( "\t files will be written to. If no file name is\n" );
+ printf( "\t given the differences will be printed to the\n" );
+ printf( "\t default file DIFF.TXT and the console.\n" );
+ printf( "\t\t- OR -\n\n" );
+
+
+ printf( "\tTPDIFF -F LOG_FILE_LIST [DIFFS_FILE]\n\n" );
+
+
+ printf( "\tWhere:\n\n" );
+
+
+ printf( "\tLOG_FILE_LIST - is a file containing pairs of log file\n" );
+ printf( "\t names and known good log file names. The\n" );
+ printf( "\t pairs of file names must be on the same line\n" );
+ printf( "\t in the file\n" );
+ printf( "\tDIFFS_FILE - is the file the differences, if any exist,\n" );
+ printf( "\t between the log files and the known good log\n" );
+ printf( "\t files will be written to. If no file name is\n" );
+ printf( "\t given the differences will be printed to the\n" );
+ printf( "\t default file DIFF.TXT and the console.\n" );
+
+}
+
+
+BOOLEAN
+GetFilePair(
+ PCHAR *FirstFile,
+ PCHAR *SecondFile,
+ PCHAR Buffer
+ )
+{
+
+ PCHAR Token[2] ;
+ PCHAR Seperators = " ,\t" ;
+ UINT TokenLength[2] ;
+
+
+ //
+ // Extract the log file names from the string buffer
+ //
+ Token[0] = strtok( Buffer, Seperators );
+
+ if ( Token[0] != (PCHAR)NULL ) {
+
+ Token[1] = strtok( NULL, Seperators );
+
+ if ( Token[1] == (PCHAR)NULL ) {
+
+ printf("The first log file name is:\t%s\nHowever the program was unable to determine the second log file name.\n",
+ Token[0]);
+ return FALSE;
+
+ } else {
+
+ TokenLength[0] = strlen( Token[0] );
+ TokenLength[1] = strlen( Token[1] );
+
+ }
+
+ } else {
+
+ printf("Unable to determine the first log file name.\n");
+ return FALSE;
+
+ }
+
+
+ //
+ // Create storage on the file list for the file names
+ //
+ *FirstFile = malloc( (TokenLength[0]+1)*sizeof(CHAR) );
+ *SecondFile = malloc( (TokenLength[1]+1)*sizeof(CHAR) );
+
+ if ( *FirstFile == (PCHAR)NULL || *SecondFile == (PCHAR)NULL ) {
+
+ printf("The system has run out of memory resources for this program\n");
+ free( *FirstFile );
+ free( *SecondFile );
+ exit( -1 );
+
+ }
+
+ //
+ // Copy the file names into the allocated storage
+ //
+ memset( *FirstFile, 0, TokenLength[0]+1 );
+ memset( *SecondFile, 0, TokenLength[1]+1 );
+ strncpy( *FirstFile, Token[0], TokenLength[0] );
+ strncpy( *SecondFile, Token[1], TokenLength[1] );
+
+ //
+ // And return success
+ //
+ return TRUE;
+
+}
+
+
+
+BOOLEAN
+OpenFiles(
+ PMFILE FirstFile,
+ PCHAR FirstFileName,
+ PMFILE SecondFile,
+ PCHAR SecondFileName
+ )
+{
+ //
+ // Open the two files
+ //
+ FirstFile->FileP = fopen( FirstFileName, "r" );
+ SecondFile->FileP = fopen( SecondFileName, "r" );
+
+ //
+ // If there was an error while opening functionally report it
+ //
+ if ( ( FirstFile->FileP == (FILE *)NULL ) ||
+ ( SecondFile->FileP == (FILE *)NULL ) ) {
+
+ return FALSE;
+
+ }
+
+ return TRUE;
+
+}
+
+
+
+BOOLEAN
+CompareFiles(
+ PMFILE FirstFile,
+ PMFILE SecondFile,
+ FILE *DifferenceFile,
+ PULONG TotalDifferenceCounter
+ )
+{
+
+ PSECTION SectionZero_FirstFile;
+ PSECTION SectionZero_SecondFile;
+ ULONG FileComparisonDifferences = 0 ;
+
+
+ //
+ // Create the two special sections.
+ // These sections indicate the beggining of the two files being compared
+ //
+ SectionZero_FirstFile = CreateSection();
+ SectionZero_SecondFile = CreateSection();
+
+ if ( SectionZero_FirstFile == (PSECTION)NULL) {
+ printf("The system has run out of memory resources for this program\n");
+ if ( SectionZero_SecondFile != (PSECTION)NULL) {
+ DestroySection( SectionZero_SecondFile );
+ }
+ exit( -1 );
+ } else if ( SectionZero_SecondFile == (PSECTION)NULL) {
+ printf("The system has run out of memory resources for this program\n");
+ DestroySection( SectionZero_FirstFile );
+ exit( -1 );
+ }
+
+
+
+ //
+ // Initialize the two sections
+ //
+ SectionZero_FirstFile->File = FirstFile ;
+ SectionZero_SecondFile->File = SecondFile;
+ strcpy( SectionZero_FirstFile->SectionDescription, FirstFile->FileName );
+ strcpy( SectionZero_SecondFile->SectionDescription, SecondFile->FileName );
+
+
+ //
+ // Now since the second file is also the GOLDEN file, set that as the
+ // base control section. Lines, sections will be compared AGAINST this control
+ // section. In the generic case however, this would not be true since either
+ // one can be marked as the base section. That requires this line to be remarked
+ // and changes made to the -TOKEN_MATCH-() keyword syntax to accept the variable
+ // BASE.
+ //
+ SectionZero_SecondFile->Control.BaseControlSection = TRUE;
+
+
+ //
+ // Proceed with the comparisons
+ //
+ CompareSections( SectionZero_FirstFile, SectionZero_SecondFile,
+ DifferenceFile, &FileComparisonDifferences );
+
+
+ //
+ // And indicate the completion of a successful comparison
+ //
+ *TotalDifferenceCounter += FileComparisonDifferences;
+ return TRUE;
+
+}
+
+
+BOOLEAN
+CompareSections(
+ PSECTION FirstSection,
+ PSECTION SecondSection,
+ FILE *DifferenceFile,
+ PULONG FileDifferenceCounter
+ )
+{
+
+ PFUNCTION_ELEMENTS FunctionElements;
+
+ //
+ // Initialize the lines used to store information extracted from the files
+ //
+ FunctionElements = CreateFunctionElements();
+ if ( FunctionElements == (PFUNCTION_ELEMENTS)NULL ) {
+ printf("The system has run out of memory resources for this program\n");
+ exit( -1 );
+ } else {
+ FunctionElements->SectionEndsNotSynchronized = TRUE;
+ }
+
+
+ //
+ // Indicate a sectional compare IF the section is not the base section 0.0
+ //
+ // fprintf( DifferenceFile, "\n\n__PERFORMING SECTIONAL ANALYSIS ON SECTION ID: %f__\n",
+ // SecondSection->Control.SectionIdentifier );
+
+ //
+ // Repeat until the section ends from the two files match
+ // and the section comparison completes
+ //
+ while ( FunctionElements->SectionEndsNotSynchronized ) {
+
+ //
+ // Get the next line from first section IFF sectional synchronization is not
+ // required
+ //
+ if ( FunctionElements->FirstSectionSynchronize == FALSE ) {
+
+ //
+ // Keep attempting to access the next line till we do not have to skip lines
+ //
+ FunctionElements->SkipLine = TRUE;
+ while ( FunctionElements->SkipLine ) {
+
+ ClearAndSetLine( FirstSection , &FunctionElements->FirstSectionCurrentLine );
+ if ( GetNextLine( FirstSection ) ) {
+
+ if ( DoNotSkipThisLine( FirstSection ) ) {
+
+ ExtractResults( FirstSection );
+ FunctionElements->SkipLine = FALSE;
+
+ }
+ FirstSection->Control.SectionLineCount++;
+ FirstSection->File->CurrentFileLine++;
+
+ } else {
+
+ //
+ // Mark this line as type SECTION_END. This is actually the EOF which
+ // is also the end of section 0.0(the file)
+ //
+ FirstSection->CurrentLine->LineType = LINE_TYPE_SECTION_END;
+ FunctionElements->SkipLine = FALSE ;
+
+ }
+
+ }
+
+
+ }
+
+ //
+ // Get the next line from second section IFF sectional synchronization is not
+ // required
+ //
+ if ( FunctionElements->SecondSectionSynchronize == FALSE ) {
+
+ //
+ // Keep attempting to access the next line till we do not have to skip lines
+ //
+ FunctionElements->SkipLine = TRUE;
+ while ( FunctionElements->SkipLine ) {
+
+ ClearAndSetLine( SecondSection, &FunctionElements->SecondSectionCurrentLine );
+ if ( GetNextLine( SecondSection ) ) {
+
+ if ( DoNotSkipThisLine( SecondSection ) ) {
+
+ //
+ // Since the second file section is the golden section
+ // we do not need to extract results from the line.
+ // However, if the program is changed for generic control
+ // the line should be included
+ //
+ // ExtractResults( FirstSection );
+ //
+ ExtractBetweenValues( SecondSection );
+ FunctionElements->SkipLine = FALSE;
+
+ }
+ SecondSection->Control.SectionLineCount++;
+ SecondSection->File->CurrentFileLine++;
+
+ } else {
+
+ //
+ // Mark this line as type SECTION_END. This is actually the EOF which
+ // is also the end of section 0.0(the file)
+ //
+ SecondSection->CurrentLine->LineType = LINE_TYPE_SECTION_END;
+ FunctionElements->SkipLine = FALSE ;
+
+ }
+
+ }
+
+ }
+
+
+ //
+ // Determine the line types of both sections.
+ // The line type indicate the beggining of a section, ending of a section,
+ // or a regular line
+ //
+ LineType( FirstSection );
+ LineType( SecondSection );
+
+
+ //
+ // Determine the variation to be examined. The variation is simply a combination
+ // of the two line types to indicate common behavior. e.g. if the first line was
+ // a section ending and the second line was a regular line, the behaviour of
+ // the program would be the same if the line types were reversed
+ //
+ CombinedVariation( FirstSection, SecondSection, &FunctionElements->CombinedLineVariation );
+
+ //
+ // And now operate on the deduced variation
+ //
+ switch( FunctionElements->CombinedLineVariation ) {
+
+ //
+ // If both lines are the beginning of new sections
+ //
+ case SECTIONHDR_SECTIONHDR:
+
+ //
+ // Examine both section ID's specified in the current lines match the
+ // following conditions
+ // 1. The two ID's are the same
+ // 2. The two ID do NOT match the current section ID's
+ //
+ if ( CheckSectionIDFromCurrentLines( FirstSection, SecondSection ) ) {
+
+
+ //
+ // Sections have been synchronized
+ //
+ FunctionElements->FirstSectionSynchronize = FALSE;
+ FunctionElements->SecondSectionSynchronize = FALSE;
+
+
+ //
+ // Create two new sections
+ //
+ FunctionElements->NewFirstSection = CreateSection();
+ FunctionElements->NewSecondSection = CreateSection();
+ if ( FunctionElements->NewFirstSection == (PSECTION)NULL ) {
+ printf("The system has run out of memory resources for this program\n");
+ if ( FunctionElements->NewSecondSection != (PSECTION)NULL ) {
+ DestroySection( FunctionElements->NewSecondSection );
+ }
+ exit( -1 );
+ } else if ( FunctionElements->NewSecondSection == (PSECTION)NULL ) {
+ printf("The system has run out of memory resources for this program\n");
+ DestroySection( FunctionElements->NewFirstSection );
+ exit( -1 );
+ }
+
+ //
+ // Initialize section control
+ //
+ if ( !InitializeSectionControl( FunctionElements->NewFirstSection, FirstSection ) ||
+ !InitializeSectionControl( FunctionElements->NewSecondSection, SecondSection ) ) {
+
+ //
+ // Once again this should not occur
+ //
+ fprintf( DifferenceFile, "\nA BAD SECTIONAL CONTROL SEGMENT HAS BEEN DETECTED\n");
+ fprintf( DifferenceFile, "\nCHECK FOR A SYNTAX ERROR\n" );
+ PrintSectionInformation( FirstSection, DifferenceFile );
+ PrintSectionInformation( SecondSection, DifferenceFile );
+ //
+ // Free up the resources allocates
+ //
+ DestroySection( FunctionElements->NewFirstSection );
+ DestroySection( FunctionElements->NewSecondSection );
+
+ //
+ // Reset and compare as regular lines
+ //
+ FirstSection->CurrentLine->LineType = LINE_TYPE_REGULAR;
+ SecondSection->CurrentLine->LineType = LINE_TYPE_REGULAR;
+
+ CompareLinesAndPrintResults( FirstSection,
+ SecondSection,
+ &FunctionElements->ErrorCount,
+ DifferenceFile );
+ } else {
+
+
+ //
+ // Compare the two new sections
+ //
+ CompareSections( FunctionElements->NewFirstSection,
+ FunctionElements->NewSecondSection,
+ DifferenceFile,
+ FileDifferenceCounter );
+
+ //
+ // Readjust the current line counters for the First and Second
+ // Sections
+ //
+ FirstSection->Control.SectionLineCount +=
+ FunctionElements->NewFirstSection->Control.SectionLineCount;
+
+ SecondSection->Control.SectionLineCount +=
+ FunctionElements->NewSecondSection->Control.SectionLineCount;
+
+ //
+ // Free up the resources allocates
+ //
+ DestroySection( FunctionElements->NewFirstSection );
+ DestroySection( FunctionElements->NewSecondSection );
+
+ }
+
+ } else {
+
+ //
+ // Force synchronize the sections
+ //
+ FunctionElements->FirstSectionSynchronize = FALSE;
+ FunctionElements->SecondSectionSynchronize = FALSE;
+
+ //
+ // switch them to regular lines.
+ // This condition should never be reached and if so treat these
+ // lines as regular lines
+ //
+ FirstSection->CurrentLine->LineType = LINE_TYPE_REGULAR;
+ SecondSection->CurrentLine->LineType = LINE_TYPE_REGULAR;
+
+ CompareLinesAndPrintResults( FirstSection,
+ SecondSection,
+ &FunctionElements->ErrorCount,
+ DifferenceFile );
+ }
+ break;
+
+
+ //
+ // If both lines are ends of sections
+ //
+ case SECTIONEND_SECTIONEND:
+
+ FunctionElements->FirstSectionID = ExtractSectionIDFromLine( FirstSection );
+ FunctionElements->SecondSectionID = ExtractSectionIDFromLine( SecondSection );
+
+ //
+ // Global section control. Ends section comparisons.
+ //
+ if ( FunctionElements->FirstSectionID > FunctionElements->SecondSectionID ) {
+
+ FunctionElements->FirstSectionSynchronize = FALSE;
+ FunctionElements->SecondSectionSynchronize = TRUE;
+
+ FirstSection->CurrentLine->LineType = LINE_TYPE_REGULAR;
+
+ CompareLinesAndPrintResults( FirstSection,
+ SecondSection,
+ &FunctionElements->ErrorCount,
+ DifferenceFile );
+
+ } else if ( FunctionElements->FirstSectionID < FunctionElements->SecondSectionID ) {
+
+ FunctionElements->FirstSectionSynchronize = TRUE;
+ FunctionElements->SecondSectionSynchronize = FALSE;
+
+ SecondSection->CurrentLine->LineType = LINE_TYPE_REGULAR;
+
+ CompareLinesAndPrintResults( FirstSection,
+ SecondSection,
+ &FunctionElements->ErrorCount,
+ DifferenceFile );
+ } else {
+
+ //
+ // Sections are synchronized
+ //
+ FunctionElements->FirstSectionSynchronize = FALSE;
+ FunctionElements->SecondSectionSynchronize = FALSE;
+
+
+ //
+ // Now make sure that the extracted section IDs match the
+ // current section ID
+ //
+ if ( FunctionElements->FirstSectionID == FirstSection->Control.SectionIdentifier ) {
+
+ //
+ // ALL TOKEN MATCHING IS DONE AT THE ENDS OF SECTIONS
+ //
+ if ( SecondSection->Control.TokenMatching == TRUE ) {
+
+ CompareTokensAndPrintResults( FirstSection,
+ SecondSection,
+ &FunctionElements->ErrorCount,
+ DifferenceFile );
+ }
+
+ FunctionElements->SectionEndsNotSynchronized = FALSE;
+
+ } else {
+
+ //
+ // Switch them to regular lines
+ //
+ FirstSection->CurrentLine->LineType = LINE_TYPE_REGULAR;
+ SecondSection->CurrentLine->LineType = LINE_TYPE_REGULAR;
+
+ CompareLinesAndPrintResults( FirstSection,
+ SecondSection,
+ &FunctionElements->ErrorCount,
+ DifferenceFile );
+
+ }
+
+ }
+
+ break;
+
+
+ //
+ // If one line is the beggining of a section
+ // and the other is the end of a section
+ //
+ case SECTIONHDR_SECTIONEND:
+
+ //
+ // We have come across the case where another section has been detected
+ // while another was ending.
+ //
+ if ( FirstSection->CurrentLine->LineType == LINE_TYPE_SECTION_END ) {
+
+ FunctionElements->FirstSectionSynchronize = TRUE;
+ SecondSection->CurrentLine->LineType = LINE_TYPE_REGULAR;
+
+ } else {
+
+ FunctionElements->SecondSectionSynchronize = TRUE;
+ FirstSection->CurrentLine->LineType = LINE_TYPE_REGULAR;
+
+ }
+
+ CompareLinesAndPrintResults( FirstSection,
+ SecondSection,
+ &FunctionElements->ErrorCount,
+ DifferenceFile );
+ break;
+
+
+ //
+ // If one line is the beggining of a section and the other
+ // is a regular line
+ //
+ case SECTIONHDR_REGLINE :
+
+ //
+ // We have come to a point where a section header has been detected
+ // in one section and a regular line in another
+ // This forces us to now attempt to re-synchronize the sections
+ //
+ if ( FirstSection->CurrentLine->LineType == LINE_TYPE_SECTION_START ) {
+
+ if ( ExtractSectionIDFromLine( FirstSection ) != (DOUBLE)0 ) {
+
+ FunctionElements->FirstSectionSynchronize = TRUE;
+
+ } else {
+
+ //
+ // Simply RESET this line as a regular line and compare
+ //
+ FirstSection->CurrentLine->LineType = LINE_TYPE_REGULAR;
+
+ }
+
+ } else {
+
+ if ( ExtractSectionIDFromLine( SecondSection ) != (DOUBLE)0 ) {
+
+ FunctionElements->SecondSectionSynchronize = TRUE;
+
+ } else {
+
+ //
+ // Simply RESET this line as a regular line and compare
+ //
+ SecondSection->CurrentLine->LineType = LINE_TYPE_REGULAR;
+
+ }
+
+
+ }
+
+ CompareLinesAndPrintResults( FirstSection,
+ SecondSection,
+ &FunctionElements->ErrorCount,
+ DifferenceFile );
+ break;
+
+
+ //
+ // If one line is the end of a section and
+ // the other is a regular line
+ //
+ case SECTIONEND_REGLINE :
+
+ //
+ // We have come to a point where a section end has been detected
+ // in one section and a regular line in another
+ // This forces us to now attempt to re-synchronize the sections
+ //
+ if ( FirstSection->CurrentLine->LineType == LINE_TYPE_SECTION_END ) {
+
+ FunctionElements->FirstSectionSynchronize = TRUE;
+
+ } else {
+
+ FunctionElements->SecondSectionSynchronize = TRUE;
+
+ }
+
+ CompareLinesAndPrintResults( FirstSection,
+ SecondSection,
+ &FunctionElements->ErrorCount,
+ DifferenceFile );
+ break;
+
+ //
+ // If both lines are regular lines
+ //
+ case REGLINE_REGLINE :
+
+ CompareLinesAndPrintResults( FirstSection,
+ SecondSection,
+ &FunctionElements->ErrorCount,
+ DifferenceFile );
+
+ break;
+
+
+ } // !switch{}
+
+
+ } // !while( FunctionElements->SectionEndsNotSynchronized )
+
+
+ //
+ // Print out the section comparison results
+ //
+ if ( FunctionElements->ErrorCount ) {
+
+ fprintf( DifferenceFile, "\n\n__SECTIONAL RESULTS FOR SECTION ID : %f ERROR(S): %u\n",
+ SecondSection->Control.SectionIdentifier,
+ FunctionElements->ErrorCount );
+
+ }
+
+ //
+ // Cleanup
+ //
+ *FileDifferenceCounter += FunctionElements->ErrorCount;
+ DestroyFunctionElements( FunctionElements );
+ return TRUE;
+
+
+}
+
+
+BOOLEAN
+GetNextLine(
+ PSECTION Section
+ )
+{
+ UINT i,j;
+ PCHAR Tmp;
+
+ //
+ // Get the normal line. Read in until MAX_LINE_SIZE-1. This is done to ensure that
+ // should the line be longer, only the first MAX_LINE_SIZE-1 bytes are read in and
+ // the last byte is 0.
+ //
+ if ( fgets( Section->CurrentLine->NormalLine,
+ (sizeof( Section->CurrentLine->NormalLine )-1),
+ Section->File->FileP
+ ) != NULL ) {
+
+ //
+ // Replace the first occurence of a new line with a null
+ //
+ Tmp = strchr( Section->CurrentLine->NormalLine, '\n');
+ if ( Tmp != (PCHAR)NULL ) {
+
+ *Tmp = '\0';
+
+ }
+
+ Section->CurrentLine->NormalLineSize = strlen( Section->CurrentLine->NormalLine );
+
+
+ //
+ // Obtain a compressed uppercase version of the line
+ //
+ for( i = 0, j = 0 ; i < strlen( Section->CurrentLine->NormalLine ); i++ ) {
+
+ if ( isspace( Section->CurrentLine->NormalLine[i] ) == 0 ) {
+
+ Section->CurrentLine->CompressedLine[j] = toupper( Section->CurrentLine->NormalLine[i] );
+
+ Section->CurrentLine->CompressedLineSize++;
+ j++;
+
+ }
+
+ }
+
+ //
+ // And return
+ //
+ return TRUE;
+
+ }
+
+ //
+ // This indicates an EOF has been reached
+ //
+ return FALSE;
+
+}
+
+
+VOID
+LineType(
+ PSECTION Section
+ )
+{
+ //
+ // If while entering the line type was marked as SECTION_END
+ // it indicates the EOF has been encountered. Since EOF is also
+ // the end of section ID 0.0, the line is premarked
+ // is read. This is the only special type which is premarked
+ //
+ if ( Section->CurrentLine->LineType == LINE_TYPE_SECTION_END ) {
+
+ return;
+
+ }
+
+ //
+ // If the line contains a MAY_DIFFER, irrespective of what the control
+ // is it is turned into a regular line
+ //
+ if ( strstr( Section->CurrentLine->CompressedLine, "MAY_DIFFER" ) != NULL ) {
+
+ Section->CurrentLine->LineType = LINE_TYPE_REGULAR;
+ return;
+ }
+
+ //
+ // Search for the special keyword -SECTION_START-
+ //
+ if ( strstr( Section->CurrentLine->CompressedLine, Keywords[SECTION_START] ) != NULL ) {
+
+ Section->CurrentLine->LineType = LINE_TYPE_SECTION_START;
+ return;
+ }
+
+ //
+ // Search for the special keyword -SECTION_END-
+ //
+ if ( strstr( Section->CurrentLine->CompressedLine, Keywords[SECTION_END] ) != NULL ) {
+
+ Section->CurrentLine->LineType = LINE_TYPE_SECTION_END;
+ return;
+ }
+
+ Section->CurrentLine->LineType = LINE_TYPE_REGULAR;
+ return;
+
+}
+
+
+BOOLEAN
+ExtractResults(
+ PSECTION Section
+ )
+{
+ PCHAR TmpBuf;
+ PCHAR Token ;
+ BOOLEAN ExtractMoreResults = TRUE;
+ CHAR Seperators[] = " ,\t";
+ ULONG i;
+ CHAR TmpLine[MAX_LINE_SIZE];
+
+ //
+ // First move the Current results into the Last results and clear the current results
+ // one at a time
+ //
+ for( i = 0; i < Section->NumberOfCurrentResults;i++ ) {
+
+ Section->LastResults[i] = Section->CurrentResults[i];
+ Section->CurrentResults[i] = 0 ;
+
+ }
+ Section->NumberOfLastResults = Section->NumberOfCurrentResults;
+ Section->NumberOfCurrentResults = 0;
+
+ //
+ // Clear the tmp variable and copy the Normal Line contents into it
+ // This is done to preserve the contents of the normal line since strtok
+ // changes the contents.
+ //
+ memset( TmpLine, 0, MAX_LINE_SIZE );
+ strcpy( TmpLine, Section->CurrentLine->NormalLine );
+
+
+ //
+ // Search for the right hand value of the expression. This is extracted
+ // by searching for the = or the : operator.
+ //
+ // NOTE
+ //
+ // We use strrchr to get to the last occurence of = or :
+ //
+
+ //
+ // Locate the = operator
+ //
+ TmpBuf = strrchr( TmpLine, '=' );
+
+ if ( TmpBuf == NULL ) {
+
+ //
+ // Locate the : operator
+ //
+ TmpBuf = strrchr( TmpLine, ':' );
+
+ if ( TmpBuf == NULL ) {
+
+ return FALSE;
+
+ }
+
+ }
+
+ //
+ // The fact that we are here indicates that one of the operator
+ // types was located
+ //
+ TmpBuf++;
+
+ Token = strtok( TmpBuf, Seperators );
+
+ while ( ( Section->NumberOfCurrentResults < MAX_RESULTS_COUNT ) &&
+ ( Token != NULL ) &&
+ ( ExtractMoreResults ) ) {
+
+ if ( (*Token >= '0') && (*Token <= '9') ) {
+
+ Section->CurrentResults[Section->NumberOfCurrentResults] = atol( Token );
+ Section->NumberOfCurrentResults++;
+ Token = strtok( NULL, Seperators );
+
+ } else {
+
+ ExtractMoreResults = FALSE;
+
+ }
+
+ }
+
+ if ( Section->NumberOfCurrentResults ) {
+
+ return TRUE;
+
+ }
+
+ return FALSE;
+
+}
+
+BOOLEAN
+ExtractBetweenValues(
+ PSECTION Section
+ )
+{
+ PCHAR Tmp, Tmp1;
+ ULONG SwapValue;
+
+ //
+ // Search for the AT_LEAST Keyword
+ //
+ Tmp = strstr( Section->CurrentLine->CompressedLine, "BETWEEN_VALUES" );
+
+ if ( Tmp != NULL ) {
+
+ Tmp += strlen( "BETWEEN_VALUES" );
+
+ //
+ // Extract the minimum-first value
+ //
+ Section->MinimumValue = atol( Tmp );
+
+ //
+ // Proceed to look for the maximum-second value
+ //
+ Tmp1 = strstr( Tmp, "," );
+
+ if ( Tmp1 != NULL ) {
+
+ Tmp1 += strlen( "," );
+
+ //
+ // Extract the minimum-first value
+ //
+ Section->MaximumValue = atol( Tmp1 );
+
+
+ } else {
+
+ Section->MaximumValue = 0xffffffff;
+
+ }
+
+ if ( Section->MinimumValue > Section->MaximumValue ) {
+
+ SwapValue = Section->MinimumValue;
+ Section->MinimumValue = Section->MaximumValue;
+ Section->MaximumValue = SwapValue ;
+
+
+ }
+
+ return TRUE;
+
+ }
+
+ //
+ // Could not locate AT_LEAST or no associated value was recovered
+ //
+ Section->MinimumValue = 0;
+ Section->MaximumValue = 0xffffffff;
+
+ return FALSE;
+
+}
+
+BOOLEAN
+CombinedVariation(
+ PSECTION FirstSection,
+ PSECTION SecondSection,
+ PUCHAR CombinedLineVariation
+ )
+{
+
+ //
+ // THERE ARE THE FOLLOWING POSSIBLE 6 COMBINATIONS
+ //
+ // START-START, START-REGLINE, START-END
+ // END-REGLINE, END-END
+ // REGLINE-REGLINE
+ //
+ if ( ( FirstSection->CurrentLine->LineType == LINE_TYPE_SECTION_START ) &&
+ ( SecondSection->CurrentLine->LineType == LINE_TYPE_SECTION_START ) ) {
+ *CombinedLineVariation = SECTIONHDR_SECTIONHDR;
+ return TRUE;
+ }
+
+ if ( ( FirstSection->CurrentLine->LineType == LINE_TYPE_SECTION_END ) &&
+ ( SecondSection->CurrentLine->LineType == LINE_TYPE_SECTION_END ) ) {
+ *CombinedLineVariation = SECTIONEND_SECTIONEND;
+ return TRUE;
+ }
+
+
+ if ( ( FirstSection->CurrentLine->LineType == LINE_TYPE_REGULAR ) &&
+ ( SecondSection->CurrentLine->LineType == LINE_TYPE_REGULAR ) ) {
+ *CombinedLineVariation = REGLINE_REGLINE;
+ return TRUE;
+ }
+
+ if ( (
+ ( FirstSection->CurrentLine->LineType == LINE_TYPE_SECTION_START ) &&
+ ( SecondSection->CurrentLine->LineType == LINE_TYPE_SECTION_END )
+ ) ||
+ (
+ ( FirstSection->CurrentLine->LineType == LINE_TYPE_SECTION_END ) &&
+ ( SecondSection->CurrentLine->LineType == LINE_TYPE_SECTION_START )
+ ) ) {
+ *CombinedLineVariation = SECTIONHDR_SECTIONEND;
+ return TRUE;
+ }
+
+ if ( (
+ ( FirstSection->CurrentLine->LineType == LINE_TYPE_SECTION_START ) &&
+ ( SecondSection->CurrentLine->LineType == LINE_TYPE_REGULAR )
+ ) ||
+ (
+ ( FirstSection->CurrentLine->LineType == LINE_TYPE_REGULAR ) &&
+ ( SecondSection->CurrentLine->LineType == LINE_TYPE_SECTION_START )
+ ) ) {
+ *CombinedLineVariation = SECTIONHDR_REGLINE;
+ return TRUE;
+ }
+
+ if ( (
+ ( FirstSection->CurrentLine->LineType == LINE_TYPE_SECTION_END ) &&
+ ( SecondSection->CurrentLine->LineType == LINE_TYPE_REGULAR )
+ ) ||
+ (
+ ( FirstSection->CurrentLine->LineType == LINE_TYPE_REGULAR ) &&
+ ( SecondSection->CurrentLine->LineType == LINE_TYPE_SECTION_END )
+ ) ) {
+ *CombinedLineVariation = SECTIONEND_REGLINE;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+RESULT
+CompareLines(
+ PSECTION FirstSection,
+ PSECTION SecondSection
+ )
+{
+
+ BOOLEAN ResultErrorsDiscovered = FALSE;
+ ULONG i;
+
+ //
+ // THIS IS ANOTHER VERY CRITICAL PIECE OF THE CODE SINCE BASED ON THE LINE TYPES
+ // COMPARISONS ARE MADE
+ //
+ // ON ENTERING THIS FUNCTION THERE ARE ONLY THREE COMBINATIONS A LINE COULD
+ // BE IN THE FOLLOWING STATES
+ //
+ // REGLINE-REGLINE
+ // REGLINE-SECTIONHDR
+ // REGLINE-SECTIONEND
+ //
+ // FURTHER SINCE THE SECTIONS ARE SYNCHRONIZED WE CAN USE THE CONTROL SETTINGS
+ // OF EITHER ONE
+ //
+
+
+ //
+ // COMMON COMPARISONS BETWEEN ALL LINE TYPES
+ //
+
+ //
+ // Possible MAY_DIFFER.
+ //
+ if ( MayDifferExistsInOneOrMoreLines( FirstSection, SecondSection ) ) {
+
+ return COMPARE_SUCCESS;
+
+ }
+
+ //
+ // Possible EQUAL_LAST
+ //
+ if ( strstr( FirstSection->CurrentLine->CompressedLine, "EQUAL_LAST" ) != NULL ) {
+
+ if ( SecondSection->Control.OptionalMatching == FALSE ) {
+
+
+ for( i = 1; i <= FirstSection->NumberOfCurrentResults; i++ ) {
+
+ if ( i > FirstSection->NumberOfLastResults ) {
+
+ FirstSection->ResultsError[i-1] = RESULTS_NOT_PRESENT;
+ ResultErrorsDiscovered = TRUE;
+
+ } else {
+
+ if ( FirstSection->CurrentResults[i-1] != FirstSection->LastResults[i-1] ) {
+
+ FirstSection->ResultsError[i-1] = RESULTS_UNEQUAL;
+ ResultErrorsDiscovered = TRUE;
+
+ } else {
+
+ FirstSection->ResultsError[i-1] = RESULTS_EQUAL;
+
+ }
+ }
+ }
+
+ if ( ResultErrorsDiscovered ) {
+
+ return COMPARE_EQUAL_LAST;
+
+ }
+
+ }
+
+ return COMPARE_SUCCESS;
+
+ }
+
+ //
+ // Possible BETWEEN_VALUES from the Golden log file
+ //
+ if ( strstr( SecondSection->CurrentLine->CompressedLine, "BETWEEN_VALUES" ) != NULL ) {
+
+ if ( SecondSection->Control.OptionalMatching == FALSE ) {
+
+ for( i = 1; i <= FirstSection->NumberOfCurrentResults; i++ ) {
+
+ if ( ( FirstSection->CurrentResults[i-1] < SecondSection->MinimumValue ) ||
+ ( FirstSection->CurrentResults[i-1] > SecondSection->MaximumValue ) ) {
+
+ FirstSection->ResultsError[i-1] = RESULTS_MINMAX;
+ ResultErrorsDiscovered = TRUE;
+
+ } else {
+
+ FirstSection->ResultsError[i-1] = RESULTS_EQUAL;
+
+ }
+
+
+ }
+
+ if ( ResultErrorsDiscovered ) {
+
+ return COMPARE_BETWEEN_VALUES;
+
+ }
+
+ }
+
+ return COMPARE_SUCCESS;
+
+ }
+
+
+ //
+ // REGLINE-SECTIONHDR
+ //
+ if ( ( FirstSection->CurrentLine->LineType == LINE_TYPE_REGULAR ) &&
+ ( SecondSection->CurrentLine->LineType == LINE_TYPE_SECTION_START ) ) {
+
+ if ( SecondSection->Control.OptionalMatching == TRUE ) {
+
+ return COMPARE_SUCCESS;
+
+ }
+
+ if ( SecondSection->Control.TokenMatching == TRUE ) {
+
+ TokenInsertInSection( FirstSection );
+ return COMPARE_SUCCESS;
+
+ }
+
+ return COMPARE_START;
+
+ }
+ if( ( SecondSection->CurrentLine->LineType == LINE_TYPE_REGULAR ) &&
+ ( FirstSection->CurrentLine->LineType == LINE_TYPE_SECTION_START ) ) {
+
+ if ( SecondSection->Control.OptionalMatching == TRUE ) {
+
+ return COMPARE_SUCCESS;
+
+ }
+
+ if ( SecondSection->Control.TokenMatching == TRUE ) {
+
+ TokenInsertInSection( SecondSection );
+ return COMPARE_SUCCESS;
+
+ }
+
+ return COMPARE_START;
+
+ }
+
+
+
+ //
+ // REGLINE-SECTIONEND
+ //
+ if ( ( FirstSection->CurrentLine->LineType == LINE_TYPE_REGULAR ) &&
+ ( SecondSection->CurrentLine->LineType == LINE_TYPE_SECTION_END ) ) {
+
+ if ( SecondSection->Control.OptionalMatching == TRUE ) {
+
+ return COMPARE_SUCCESS;
+
+ }
+
+ if ( SecondSection->Control.TokenMatching == TRUE ) {
+
+ TokenInsertInSection( FirstSection );
+ return COMPARE_SUCCESS;
+
+ }
+
+ return COMPARE_END;
+
+ }
+ if ( ( SecondSection->CurrentLine->LineType == LINE_TYPE_REGULAR ) &&
+ ( FirstSection->CurrentLine->LineType == LINE_TYPE_SECTION_END ) ) {
+
+ if ( SecondSection->Control.OptionalMatching == TRUE ) {
+
+ return COMPARE_SUCCESS;
+
+ }
+
+ if ( SecondSection->Control.TokenMatching == TRUE ) {
+
+ TokenInsertInSection( SecondSection );
+ return COMPARE_SUCCESS;
+
+ }
+
+ return COMPARE_END;
+
+ }
+
+
+
+
+ //
+ // REGLINE-REGLINE
+ //
+ if ( memcmp( FirstSection->CurrentLine->CompressedLine,
+ SecondSection->CurrentLine->CompressedLine,
+ max( FirstSection->CurrentLine->CompressedLineSize, SecondSection->CurrentLine->CompressedLineSize )
+ )
+ != 0 ) {
+
+ //
+ // Since we can only be at this point if the two section headers match,
+ // either control sections can be used
+ //
+ if ( SecondSection->Control.OptionalMatching == TRUE ) {
+
+ return COMPARE_SUCCESS;
+
+ }
+
+ if ( SecondSection->Control.TokenMatching == TRUE ) {
+
+ TokenInsertInSection( FirstSection );
+ TokenInsertInSection( SecondSection );
+ return COMPARE_SUCCESS;
+
+ }
+
+ return COMPARE_LINE;
+
+ }
+
+ return COMPARE_SUCCESS;
+
+
+}
+
+
+BOOLEAN
+InitializeSectionControl(
+ PSECTION NewSection,
+ PSECTION OldSection
+ )
+{
+
+ PCHAR TmpBuffer;
+ INT Length ;
+ CHAR EnvironmentVar[MAX_LINE_SIZE];
+ CHAR TmpLine[MAX_LINE_SIZE] ;
+
+ //
+ // Initialize the file pointers
+ //
+ // NOTE
+ //
+ // If you do not specify any control for the section and the section is nested
+ // it will inherit the options of the parent node
+ //
+ NewSection->File = OldSection->File;
+ NewSection->CurrentLine = (PLINE)NULL;
+
+ NewSection->Control.BaseControlSection = OldSection->Control.BaseControlSection;
+ NewSection->Control.OptionalMatching = OldSection->Control.OptionalMatching ;
+ NewSection->Control.TokenMatching = OldSection->Control.TokenMatching ;
+
+ NewSection->Control.TokenMatchStartLine = OldSection->Control.TokenMatchStartLine;
+ NewSection->Control.TokenMatchStopLine = OldSection->Control.TokenMatchStopLine ;
+
+ //
+ // Since we are going to use strtok to preserve the Normal and Compressed Lines
+ // we copy them into two local variables when required
+ //
+ memset( TmpLine, 0, MAX_LINE_SIZE );
+
+ //
+ // Initialize the section ID
+ //
+ // KEYWORD : -SECTION_START-
+ // USAGE : -SECTION_START-( SectionId )
+ //
+ //
+ NewSection->Control.SectionIdentifier = ExtractSectionIDFromLine( OldSection );
+ if ( NewSection->Control.SectionIdentifier == (DOUBLE)0 ) {
+
+ //
+ // A section without a section ID has ben defined. This is not acceptable
+ //
+ return FALSE;
+
+ }
+
+
+ //
+ // Initialize the section description
+ //
+ // KEYWORD : -SECTION_DESC-
+ // USAGE : -SECTION_DESC-( "Section for MACFRAME testing only" )
+ //
+ //
+ TmpBuffer = strstr( OldSection->CurrentLine->NormalLine, Keywords[SECTION_DESC] );
+ if ( TmpBuffer != NULL ) {
+
+ TmpBuffer = strchr( TmpBuffer, '"' )+1;
+ Length = strrchr( TmpBuffer, '"' ) - TmpBuffer;
+
+ if ( Length < 0 ) {
+ Length = 0;
+ }
+ strncpy( NewSection->SectionDescription, TmpBuffer, Length );
+ }
+
+ //
+ // Initialize any Optional control sectioning. This if detected without any
+ // parameters suggests that the section is under optional comparison. Else
+ // certain environment variables are checked and is found enabled, this
+ // section is matched
+ //
+ // KEYWORD : -OPTIONALS-
+ // USAGE : -OPTIONALS-( EnvironmentVar1, EnvironmentVar2...EnvironmentVarN )
+ //
+ //
+
+ strcpy( TmpLine, OldSection->CurrentLine->CompressedLine );
+
+ TmpBuffer = strstr( TmpLine, Keywords[OPTIONALS] );
+
+ if ( TmpBuffer != NULL ) {
+
+ UINT EnvCounter1 = 0 , EnvCounter2 = 0 ;
+ PCHAR Token ;
+ PCHAR Seperators = ",)" ;
+
+ //
+ // Weve detected an optional section
+ //
+ NewSection->Control.OptionalMatching = TRUE;
+
+ TmpBuffer += (strlen( Keywords[OPTIONALS] )+1);
+
+ //
+ // Now detect which Environment variables are enabled.
+ // If ALL are not enabled, the section remains an
+ // optional section
+ //
+ Token = strtok( TmpBuffer, Seperators );
+
+ while ( Token != NULL ) {
+
+ EnvCounter1++;
+
+ memset( EnvironmentVar, 0, sizeof( EnvironmentVar ) );
+ strncpy( EnvironmentVar, Token, strlen( Token ) );
+
+ if ( getenv( EnvironmentVar ) != NULL ) {
+
+ EnvCounter2++;
+
+ }
+
+ Token = strtok( NULL, Seperators );
+
+ }
+
+ //
+ // If all the environment variables have been enabled, this is
+ // no longer an optional section
+ //
+ if ( (EnvCounter1 == EnvCounter2) && (EnvCounter1 != 0) ) {
+
+ NewSection->Control.OptionalMatching = FALSE;
+
+ }
+
+ }
+
+ //
+ // Initialize any Token matching control within the sections.
+ //
+ // KEYWORD : -TOKEN_MATCH-
+ // USAGE : -TOKEN_MATCH-( StartLine, StopLine )
+ //
+ // NOTE: The StopLine is expressed as a relative offset from the start line
+ //
+ NewSection->Control.HeadUnmatchedTokens = NULL;
+ TmpBuffer = strstr( OldSection->CurrentLine->CompressedLine, Keywords[TOKEN_MATCH] );
+ if ( TmpBuffer != NULL ) {
+
+ //
+ // Weve detected an Token matching section
+ //
+ NewSection->Control.TokenMatching = TRUE;
+
+ TmpBuffer += (strlen( Keywords[TOKEN_MATCH] )+1);
+
+ NewSection->Control.TokenMatchStartLine = atol( TmpBuffer );
+ NewSection->Control.TokenMatchStopLine = atol( (strchr(TmpBuffer, ',')+1) );
+
+ if ( NewSection->Control.TokenMatchStopLine == 0 ) {
+
+ NewSection->Control.TokenMatchStopLine = TOKEN_MATCHING_ALL;
+
+ }
+
+ }
+
+ return TRUE;
+
+}
+
+
+VOID
+PrintComparisonResults(
+ PSECTION FirstSection,
+ PSECTION SecondSection,
+ RESULT ReturnResult,
+ ULONG ErrorCount,
+ FILE *DifferenceFile
+ )
+{
+
+ ULONG i;
+
+ switch ( ReturnResult ) {
+
+ case COMPARE_LINE :
+
+ //
+ // Report the difference in the difference file
+ //
+ fprintf( DifferenceFile, "\n\n__ERROR__ : %u\n", ErrorCount );
+
+ fprintf( DifferenceFile, "\nFOUND (COMP.FILE LINE CONTENTS) : %s\n",
+ FirstSection->CurrentLine->NormalLine );
+ fprintf( DifferenceFile, "EXPECTED (GOLDEN FILE LINE CONTENTS) : %s\n",
+ SecondSection->CurrentLine->NormalLine );
+
+ //
+ // Since this program is for the second file being the GOLDEN file
+ // It prints out information with reference to the GOLDEN file
+ //
+
+ fprintf( DifferenceFile, "\n\tERROR TYPE : LINE COMPARISON FAILURE\n" );
+ fprintf( DifferenceFile, "\tCURRENT SECTION ID : %f\n",
+ SecondSection->Control.SectionIdentifier );
+ fprintf( DifferenceFile, "\tCOMP. FILE : %s\n",
+ FirstSection->File->FileName );
+ fprintf( DifferenceFile, "\tCOMP. FILE SECTION LINE OFFSET : %u\n",
+ FirstSection->Control.SectionLineCount );
+ fprintf( DifferenceFile, "\tCOMP. FILE LINE OFFSET : %u\n",
+ FirstSection->File->CurrentFileLine );
+ fprintf( DifferenceFile, "\tGOLDEN FILE : %s\n",
+ SecondSection->File->FileName );
+ fprintf( DifferenceFile, "\tGOLDEN FILE SECTION LINE OFFSET: %u\n",
+ SecondSection->Control.SectionLineCount );
+ fprintf( DifferenceFile, "\tGOLDEN FILE LINE OFFSET : %u\n",
+ SecondSection->File->CurrentFileLine );
+
+ break;
+
+ case COMPARE_EQUAL_LAST:
+
+ //
+ // Report the difference in the difference file
+ //
+ fprintf( DifferenceFile, "\n\n__ERROR__ : %u\n", ErrorCount );
+
+ fprintf( DifferenceFile, "\nINDEX FOUND(CURRENT EXTRACTED RESULTS) EXPECTED(LAST EXTRACTED RESULTS)\n" );
+ for( i = 0; i < FirstSection->NumberOfCurrentResults; i++ ) {
+
+ if ( FirstSection->ResultsError[i] != RESULTS_EQUAL ) {
+
+ fprintf( DifferenceFile, "%5u %32u %32u\n",
+ (i+1),
+ FirstSection->CurrentResults[i],
+ FirstSection->LastResults[i]
+
+ );
+
+ }
+
+ }
+
+ fprintf( DifferenceFile, "\n\tERROR TYPE : CURRENT VALUE(S) FAILED TO EQUAL LAST\n" );
+ fprintf( DifferenceFile, "\tCURRENT SECTION ID : %f\n",
+ FirstSection->Control.SectionIdentifier );
+ fprintf( DifferenceFile, "\tCOMP. FILE : %s\n", FirstSection->File->FileName );
+ fprintf( DifferenceFile, "\tCOMP. FILE SECTION LINE OFFSET : %u\n",
+ FirstSection->Control.SectionLineCount );
+ fprintf( DifferenceFile, "\tCOMP. FILE LINE OFFSET : %u\n",
+ FirstSection->File->CurrentFileLine );
+
+
+ break;
+
+ case COMPARE_BETWEEN_VALUES:
+
+ //
+ // Report the difference in the difference file
+ //
+ fprintf( DifferenceFile, "\n\n__ERROR__ : %u\n", ErrorCount );
+
+ fprintf( DifferenceFile, "\nEXPECTED VALUES BETWEEN (EXTRACTED FROM GOLDEN) : %u, %u\n",
+ SecondSection->MinimumValue, SecondSection->MaximumValue );
+ fprintf( DifferenceFile, "\nFOUND RESULTS IN ERROR(EXTRACTED RESULTS)\n" );
+ fprintf( DifferenceFile, "INDEX RESULT\n" );
+
+ for( i = 0; i < FirstSection->NumberOfCurrentResults; i++ ) {
+
+ if ( FirstSection->ResultsError[i] != RESULTS_EQUAL ) {
+
+ fprintf( DifferenceFile, "%5u %23u\n",
+ (i+1),
+ FirstSection->CurrentResults[i]
+ );
+
+ }
+
+ }
+
+ fprintf( DifferenceFile, "\n\tERROR TYPE : CURRENT VALUE(S) IS(ARE) NOT BETWEEN THE EXPECTED VALUES\n" );
+ fprintf( DifferenceFile, "\tCURRENT SECTION ID : %f\n",
+ FirstSection->Control.SectionIdentifier );
+ fprintf( DifferenceFile, "\tCOMP. FILE : %s\n", FirstSection->File->FileName );
+ fprintf( DifferenceFile, "\tCOMP. FILE SECTION LINE OFFSET : %u\n",
+ FirstSection->Control.SectionLineCount );
+ fprintf( DifferenceFile, "\tCOMP. FILE LINE OFFSET : %u\n",
+ FirstSection->File->CurrentFileLine );
+
+ break;
+
+ case COMPARE_TOKEN :
+
+ //
+ // Report the difference in the difference file
+ //
+ fprintf( DifferenceFile, "\n\n__ERROR__ : %u\n", ErrorCount );
+
+ fprintf( DifferenceFile, "\nUNABLE TO LOCATE LINE IN THE COMP. FILE : %s\n",
+ SecondSection->Control.HeadUnmatchedTokens->NormalToken );
+
+ fprintf( DifferenceFile, "\n\tERROR TYPE : UNABLE TO LOCATE TOKEN\n" );
+ fprintf( DifferenceFile, "\tCURRENT SECTION ID : %f\n",
+ SecondSection->Control.SectionIdentifier );
+
+ fprintf( DifferenceFile, "\tCOMP. FILE : %s\n",
+ FirstSection->File->FileName );
+ fprintf( DifferenceFile, "\tGOLDEN FILE : %s\n",
+ SecondSection->File->FileName );
+ fprintf( DifferenceFile, "\tGOLDEN FILE SECTION LINE OFFSET: %u\n",
+ SecondSection->Control.HeadUnmatchedTokens->LinePosition );
+ fprintf( DifferenceFile, "\tGOLDEN FILE LINE OFFSET : %u\n",
+ SecondSection->Control.HeadUnmatchedTokens->FileLinePosition );
+
+ break;
+
+ case COMPARE_START :
+
+ //
+ // Report the difference in the difference file
+ //
+ fprintf( DifferenceFile, "\n\n__ERROR__ : %u\n", ErrorCount );
+
+ if ( FirstSection->CurrentLine->LineType != LINE_TYPE_SECTION_START ) {
+
+ fprintf( DifferenceFile, "\nEXTRA LINE DETECTED (COMP. FILE LINE CONTENTS) : %s\n",
+ FirstSection->CurrentLine->NormalLine );
+ fprintf( DifferenceFile, "GOLDEN FILE LINE CONTENTS (Expected to synchronize on): %s\n",
+ SecondSection->CurrentLine->NormalLine );
+
+ } else {
+
+ fprintf( DifferenceFile, "\nCOMP. FILE LINE CONTENTS (Expected to synchronize on) : %s\n",
+ FirstSection->CurrentLine->NormalLine );
+ fprintf( DifferenceFile, "LINE ABSENT IN COMP. FILE (GOLDEN FILE LINE CONTENTS) : %s\n",
+ SecondSection->CurrentLine->NormalLine );
+
+ }
+
+ fprintf( DifferenceFile, "\n\tERROR TYPE : NEW SECTION START SYNCHRONIZATION FAILURE\n" );
+ fprintf( DifferenceFile, "\tCURRENT SECTION ID : %f\n",
+ SecondSection->Control.SectionIdentifier );
+
+ fprintf( DifferenceFile, "\tCOMP. FILE : %s\n",
+ FirstSection->File->FileName );
+ fprintf( DifferenceFile, "\tCOMP. FILE SECTION LINE OFFSET : %u\n",
+ FirstSection->Control.SectionLineCount );
+ fprintf( DifferenceFile, "\tCOMP. FILE LINE OFFSET : %u\n",
+ FirstSection->File->CurrentFileLine );
+
+ fprintf( DifferenceFile, "\tGOLDEN FILE : %s\n",
+ SecondSection->File->FileName );
+ fprintf( DifferenceFile, "\tGOLDEN FILE SECTION LINE OFFSET: %u\n",
+ SecondSection->Control.SectionLineCount );
+ fprintf( DifferenceFile, "\tGOLDEN FILE LINE OFFSET : %u\n",
+ SecondSection->File->CurrentFileLine );
+
+ break;
+
+
+ case COMPARE_END :
+
+ //
+ // Report the difference in the difference file
+ //
+ fprintf( DifferenceFile, "\n\n__ERROR__ : %u\n", ErrorCount );
+
+ if ( FirstSection->CurrentLine->LineType != LINE_TYPE_SECTION_END ) {
+
+ fprintf( DifferenceFile, "\nEXTRA LINE DETECTED (COMP. FILE LINE CONTENTS) : %s\n",
+ FirstSection->CurrentLine->NormalLine );
+
+ if ( ( SecondSection->Control.SectionIdentifier == (DOUBLE)0 ) &&
+ ( strlen( SecondSection->CurrentLine->CompressedLine ) == 0 ) ) {
+
+ fprintf( DifferenceFile, "GOLDEN FILE LINE CONTENTS (Expected to synchronize on): END_OF_FILE\n" );
+
+ } else {
+
+ fprintf( DifferenceFile, "GOLDEN FILE LINE CONTENTS (Expected to synchronize on): %s\n",
+ SecondSection->CurrentLine->NormalLine );
+ }
+
+ } else {
+
+ if ( ( FirstSection->Control.SectionIdentifier == (DOUBLE)0 ) &&
+ ( strlen( FirstSection->CurrentLine->CompressedLine ) == 0 ) ) {
+
+ fprintf( DifferenceFile, "\nCOMP. FILE LINE CONTENTS (Expected to synchronize on) : END_OF_FILE\n" );
+
+ } else {
+
+ fprintf( DifferenceFile, "\nCOMP. FILE LINE CONTENTS (Expected to synchronize on) : %s\n",
+ FirstSection->CurrentLine->NormalLine );
+
+ }
+
+ fprintf( DifferenceFile, "LINE ABSENT IN COMP. FILE (GOLDEN FILE LINE CONTENTS) : %s\n",
+ SecondSection->CurrentLine->NormalLine );
+
+ }
+
+ fprintf( DifferenceFile, "\n\tERROR TYPE : CURRENT SECTION END SYNCH. FAILURE\n" );
+ fprintf( DifferenceFile, "\tCURRENT SECTION ID : %f\n",
+ SecondSection->Control.SectionIdentifier );
+
+ fprintf( DifferenceFile, "\tCOMP. FILE : %s\n",
+ FirstSection->File->FileName );
+ fprintf( DifferenceFile, "\tCOMP. FILE SECTION LINE OFFSET : %u\n",
+ FirstSection->Control.SectionLineCount );
+ fprintf( DifferenceFile, "\tCOMP. FILE LINE OFFSET : %u\n",
+ FirstSection->File->CurrentFileLine );
+
+ fprintf( DifferenceFile, "\tGOLDEN FILE : %s\n",
+ SecondSection->File->FileName );
+ fprintf( DifferenceFile, "\tGOLDEN FILE SECTION LINE OFFSET: %u\n",
+ SecondSection->Control.SectionLineCount );
+ fprintf( DifferenceFile, "\tGOLDEN FILE LINE OFFSET : %u\n",
+ SecondSection->File->CurrentFileLine );
+
+ break;
+
+
+ default :
+
+ fprintf( DifferenceFile, "\n\nUNKNOWN COMPARISON RESULT: %u\n", ReturnResult );
+ break;
+
+ }
+
+}
+
+
+VOID
+PrintSectionInformation(
+ PSECTION Section,
+ FILE *DifferenceFile
+ )
+{
+
+ fprintf( DifferenceFile, "FILE NAME : %s\n" , Section->File->FileName );
+ fprintf( DifferenceFile, "SECTION ID : %f\n" , Section->Control.SectionIdentifier );
+ fprintf( DifferenceFile, "SECTION OFFSET LINE# : %u\n", Section->Control.SectionLineCount );
+ fprintf( DifferenceFile, "SECTION LINE CONTENTS: %s\n" , Section->CurrentLine->NormalLine );
+
+}
+
+
+
+DOUBLE
+ExtractSectionIDFromLine(
+ PSECTION Section
+ )
+{
+ PCHAR TmpBuffer;
+
+ //
+ // Examine for -SECTION_START-
+ //
+ TmpBuffer = strstr( Section->CurrentLine->CompressedLine, Keywords[SECTION_START] );
+
+ if ( TmpBuffer != (PCHAR)NULL ) {
+
+ TmpBuffer += (strlen( Keywords[SECTION_START] )+1);
+ return (DOUBLE)(atof( TmpBuffer ));
+
+ }
+
+ //
+ // Examine for -SECTION_END-
+ //
+ TmpBuffer = strstr( Section->CurrentLine->CompressedLine, Keywords[SECTION_END] );
+
+ if ( TmpBuffer != (PCHAR)NULL ) {
+
+ TmpBuffer += (strlen( Keywords[SECTION_END] )+1);
+ return (DOUBLE)(atof( TmpBuffer ));
+
+ }
+
+ return (DOUBLE)0;
+
+}
+
+
+
+BOOLEAN
+CheckSectionIDFromCurrentLines(
+ PSECTION FirstSection,
+ PSECTION SecondSection )
+{
+
+ DOUBLE SectionID_1, SectionID_2;
+
+ SectionID_1 = ExtractSectionIDFromLine( FirstSection );
+ SectionID_2 = ExtractSectionIDFromLine( SecondSection );
+
+ if ( ( SectionID_1 != SectionID_2 ) ||
+ ( SectionID_1 == (DOUBLE)0 ) ||
+ ( SectionID_2 == (DOUBLE)0 ) ) {
+
+ return FALSE;
+
+ }
+
+ return TRUE;
+
+}
+
+
+BOOLEAN
+CompareLinesAndPrintResults(
+ PSECTION FirstSection,
+ PSECTION SecondSection,
+ PULONG ErrorCount,
+ FILE *DifferenceFile
+ )
+{
+
+ RESULT ComparisonResult;
+
+ ComparisonResult = CompareLines( FirstSection, SecondSection );
+
+ if ( ComparisonResult != COMPARE_SUCCESS ) {
+ //
+ // Increment the section error count
+ //
+ (*ErrorCount)++ ;
+
+ PrintComparisonResults( FirstSection,
+ SecondSection,
+ ComparisonResult,
+ *ErrorCount,
+ DifferenceFile );
+
+ }
+
+ return TRUE;
+
+}
+
+
+
+VOID
+TokenInsertInSection(
+ PSECTION Section
+ )
+{
+ PTOKEN_LIST Token;
+ ULONG MaxLineCount;
+ ULONG MinLineCount;
+
+ //
+ // A safe way of determining if the maximum line which will generate a valid token
+ // is <= 0xfffffff
+ //
+ if( Section->Control.TokenMatchStartLine > (TOKEN_MATCHING_ALL - Section->Control.TokenMatchStopLine ) ) {
+
+ MaxLineCount = TOKEN_MATCHING_ALL;
+
+ } else {
+
+ MaxLineCount = Section->Control.TokenMatchStartLine +
+ Section->Control.TokenMatchStopLine ;
+
+ }
+ MinLineCount = Section->Control.TokenMatchStartLine;
+
+
+ //
+ // First examine if the current line has not exceeded the Maximum StopLine AND is also greater
+ // than the minimum line count. Because of this condition, it becomes a valid token
+ //
+ if( ( Section->Control.SectionLineCount <= MaxLineCount ) &&
+ ( Section->Control.SectionLineCount >= MinLineCount ) ) {
+
+ //
+ // Create a TOKEN and link it into the section control
+ //
+ Token = (PTOKEN_LIST)calloc( 1, sizeof( TOKEN_LIST ) );
+
+ if ( Token == (PTOKEN_LIST)NULL ) {
+
+ printf( "The system has run out of memory resources\n" );
+ exit( -1 );
+
+ }
+
+ //
+ // Initialize this token and insert it into the unmatched list
+ //
+ strncpy( Token->NormalToken,
+ Section->CurrentLine->NormalLine,
+ Section->CurrentLine->NormalLineSize );
+ strncpy( Token->CompressedToken,
+ Section->CurrentLine->CompressedLine,
+ Section->CurrentLine->CompressedLineSize );
+
+ Token->LinePosition = Section->Control.SectionLineCount;
+ Token->FileLinePosition = Section->File->CurrentFileLine ;
+ Token->TokenState = TOKEN_UNMATCHED;
+ Token->NextToken = NULL;
+
+ InsertToken( Token, Section->Control.HeadUnmatchedTokens );
+
+ }
+
+}
+
+
+RESULT
+MatchTopToken(
+ PTOKEN_LIST BaseList,
+ PTOKEN_LIST ComparisonList
+ )
+{
+ PTOKEN_LIST CurrentToken ;
+ INT Length ;
+
+ CurrentToken = ComparisonList;
+
+ //
+ // Check if the Base Token under comparison is a possible MAY_DIFFER
+ //
+ if ( strstr( BaseList->CompressedToken, "MAY_DIFFER" ) != NULL ) {
+
+ return COMPARE_SUCCESS;
+
+ }
+
+ //
+ // Walk down the token chain list looking for a match. Note if the token has been
+ // matched before, it is marked so and hence cannot be reused
+ //
+ Length = strlen( BaseList->CompressedToken );
+
+ while ( CurrentToken != (PTOKEN_LIST )NULL ) {
+
+ if ( ( CurrentToken->TokenState == TOKEN_UNMATCHED ) &&
+ ( strncmp( BaseList->CompressedToken, CurrentToken->CompressedToken, Length ) == 0 )
+ ) {
+
+ //
+ // Found a match
+ //
+
+ CurrentToken->TokenState = TOKEN_MATCHED;
+ return COMPARE_SUCCESS;
+
+ }
+
+ CurrentToken = CurrentToken->NextToken;
+
+ }
+
+ return COMPARE_TOKEN;
+
+}
+
+
+VOID
+CompareTokensAndPrintResults(
+ PSECTION FirstSection,
+ PSECTION SecondSection,
+ PULONG ErrorCount,
+ FILE *DifferenceFile
+ )
+{
+ RESULT ComparisonResult;
+ PTOKEN_LIST Tmp;
+
+ //
+ // The base set for comparison will always come from the second file(golden file)
+ //
+
+ //
+ // And now search for matches for the individual tokens from the base set
+ //
+ while ( SecondSection->Control.HeadUnmatchedTokens != (PTOKEN_LIST)NULL ) {
+
+ ComparisonResult = MatchTopToken( SecondSection->Control.HeadUnmatchedTokens,
+ FirstSection->Control.HeadUnmatchedTokens );
+
+
+ if ( ComparisonResult != COMPARE_SUCCESS ) {
+
+ (*ErrorCount)++ ;
+
+ PrintComparisonResults( FirstSection,
+ SecondSection,
+ ComparisonResult,
+ *ErrorCount,
+ DifferenceFile );
+ }
+
+ //
+ // And now destroy this token from the base list
+ //
+ Tmp =
+ SecondSection->Control.HeadUnmatchedTokens;
+
+ SecondSection->Control.HeadUnmatchedTokens =
+ SecondSection->Control.HeadUnmatchedTokens->NextToken;
+
+ DestroyToken( Tmp );
+
+ }
+
+ //
+ // Finally cleanup the tokens on the compared section
+ //
+ while ( FirstSection->Control.HeadUnmatchedTokens != (PTOKEN_LIST)NULL ) {
+
+ Tmp =
+ FirstSection->Control.HeadUnmatchedTokens;
+
+ FirstSection->Control.HeadUnmatchedTokens =
+ FirstSection->Control.HeadUnmatchedTokens->NextToken;
+
+ DestroyToken( Tmp );
+
+ }
+
+}
+
+
+BOOLEAN
+MayDifferExistsInOneOrMoreLines(
+ PSECTION FirstSection,
+ PSECTION SecondSection
+ )
+{
+
+ if ( ( strstr( FirstSection->CurrentLine->CompressedLine, "MAY_DIFFER" ) != NULL ) ||
+ ( strstr( SecondSection->CurrentLine->CompressedLine, "MAY_DIFFER" ) != NULL ) ) {
+
+ //
+ // Token matching is a special case. Since we care only about the second
+ // section since that is the golden section, we make another exception
+ // and not check for the first section
+ //
+ if ( SecondSection->Control.TokenMatching == TRUE ) {
+
+ if ( strstr( SecondSection->CurrentLine->CompressedLine, "MAY_DIFFER" ) == NULL ) {
+ //
+ // This implies that the firstsection line had a MAY_DIFFER in it and the second
+ // section did not
+ //
+ // Now check the line type
+ //
+ TokenInsertInSection( FirstSection );
+
+ if ( SecondSection->CurrentLine->LineType == LINE_TYPE_REGULAR ) {
+
+ TokenInsertInSection( SecondSection );
+
+ }
+
+ } else {
+
+ //
+ // The secondsection had a MAY_DIFFER in it
+ //
+ TokenInsertInSection( SecondSection );
+
+ if ( strstr( FirstSection->CurrentLine->CompressedLine, "MAY_DIFFER" ) == NULL ) {
+ //
+ // The FirstSection did not have a MAY_DIFFER in it
+ //
+ if ( FirstSection->CurrentLine->LineType == LINE_TYPE_REGULAR ) {
+
+ TokenInsertInSection( FirstSection );
+
+ }
+
+ } else {
+ //
+ // At this point we have determined that both lines contained MAY_DIFFER
+ // in them
+ //
+ TokenInsertInSection( FirstSection );
+ }
+ }
+ }
+
+ return TRUE;
+
+ }
+
+ return FALSE;
+
+}
+
+
+BOOLEAN
+DoNotSkipThisLine(
+ PSECTION Section
+ )
+{
+ CHAR *SpecialLine = "[TPCTL:]";
+
+ //
+ // This function is responsible for informing the calling function to skip lines
+ // should it detect the presence of the keyword SKIP_LINE or match the compressed
+ // line with the special line. This can be later extented to cover special lines
+ //
+ if ( ( strstr( Section->CurrentLine->CompressedLine, "SKIP_LINE" ) == NULL ) &&
+ ( strcmp( Section->CurrentLine->CompressedLine, SpecialLine ) != 0 ) &&
+ ( strlen( Section->CurrentLine->CompressedLine ) != 0 ) ) {
+
+ return TRUE;
+
+ }
+
+ return FALSE;
+
+}
diff --git a/private/ntos/ndis/testprot/tpdiff.new/tpdiff.h b/private/ntos/ndis/testprot/tpdiff.new/tpdiff.h
new file mode 100644
index 000000000..a811a8a97
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpdiff.new/tpdiff.h
@@ -0,0 +1,213 @@
+#define MULTIPLIER sizeof(ULONG)
+#define MAX_LINE_SIZE 64*MULTIPLIER
+#define MAX_SECTION_DESC_SIZE 64*MULTIPLIER
+#define MAX_RESULTS_COUNT 32
+#define UCHAR_REMAINDER (MULTIPLIER-sizeof(UCHAR))
+
+
+#define SECTION_START 0
+#define SECTION_END 1
+#define OPTIONALS 2
+#define TOKEN_MATCH 3
+#define SECTION_DESC 4
+
+#define LINE_TYPE_SECTION_START ((UCHAR)1)
+#define LINE_TYPE_SECTION_END ((UCHAR)2)
+#define LINE_TYPE_REGULAR ((UCHAR)3)
+
+
+#define SECTIONHDR_SECTIONHDR ((UCHAR)1)
+#define SECTIONHDR_SECTIONEND ((UCHAR)2)
+#define SECTIONHDR_REGLINE ((UCHAR)3)
+#define SECTIONEND_SECTIONEND ((UCHAR)4)
+#define SECTIONEND_REGLINE ((UCHAR)5)
+#define REGLINE_REGLINE ((UCHAR)6)
+
+
+#define COMPARE_SUCCESS 0x0UL
+#define COMPARE_EQUAL_LAST 0x1UL
+#define COMPARE_LINE 0x2UL
+#define COMPARE_START 0x3UL
+#define COMPARE_END 0x4UL
+#define COMPARE_TOKEN 0x5UL
+#define COMPARE_BETWEEN_VALUES 0x6UL
+
+#define RESULTS_EQUAL ((UCHAR)0)
+#define RESULTS_UNEQUAL ((UCHAR)1)
+#define RESULTS_NOT_PRESENT ((UCHAR)2)
+#define RESULTS_MINMAX ((UCHAR)3)
+
+
+#define TOKEN_MATCHING_ALL 0xFFFFFFFF
+#define TOKEN_UNMATCHED 0x0UL
+#define TOKEN_MATCHED 0x1UL
+
+
+#if !( defined(lint) || defined(_lint) )
+#if i386
+#pragma warning(disable:4103)
+#endif
+#pragma pack(1)
+#endif
+
+
+typedef ULONG RESULT;
+typedef double DOUBLE;
+
+typedef struct _MFILE {
+
+ ULONG CurrentFileLine;
+ PCHAR FileName;
+ FILE *FileP ;
+
+} MFILE, *PMFILE;
+
+
+typedef struct _LINE {
+
+ UINT NormalLineSize ;
+ UINT CompressedLineSize ;
+
+ CHAR NormalLine[MAX_LINE_SIZE] ;
+ CHAR CompressedLine[MAX_LINE_SIZE];
+
+ UCHAR LineType ;
+ UCHAR Padding[UCHAR_REMAINDER] ;
+
+} LINE, *PLINE;
+
+
+typedef struct _TOKEN_LIST {
+
+ ULONG LinePosition ;
+ ULONG FileLinePosition ;
+ ULONG TokenState ;
+
+ struct _TOKEN_LIST *NextToken ;
+
+ CHAR NormalToken[MAX_LINE_SIZE] ;
+ CHAR CompressedToken[MAX_LINE_SIZE];
+
+} TOKEN_LIST, *PTOKEN_LIST;
+
+typedef struct _SECTION_CONTROL {
+
+ ULONG SectionLineCount ;
+ ULONG TokenMatchStartLine;
+ ULONG TokenMatchStopLine ;
+
+ PTOKEN_LIST HeadUnmatchedTokens;
+
+ DOUBLE SectionIdentifier ;
+
+ BOOLEAN OptionalMatching ;
+ BOOLEAN TokenMatching ;
+ BOOLEAN BaseControlSection ;
+ BOOLEAN Padding ;
+
+} SECTION_CONTROL, *PSECTION_CONTROL;
+
+typedef struct _SECTION {
+
+ RESULT LastResults[MAX_RESULTS_COUNT] ;
+ RESULT CurrentResults[MAX_RESULTS_COUNT] ;
+ ULONG NumberOfLastResults ;
+ ULONG NumberOfCurrentResults ;
+ UCHAR ResultsError[MAX_RESULTS_COUNT] ;
+
+ RESULT MinimumValue ;
+ RESULT MaximumValue ;
+
+ PMFILE File;
+ PLINE CurrentLine;
+
+ SECTION_CONTROL Control;
+
+ CHAR SectionDescription[MAX_SECTION_DESC_SIZE];
+
+
+} SECTION, *PSECTION;
+
+
+typedef struct _FUNCTION_ELEMENTS {
+
+ ULONG ErrorCount ;
+
+ PSECTION NewFirstSection ;
+ PSECTION NewSecondSection ;
+
+ DOUBLE FirstSectionID ;
+ DOUBLE SecondSectionID ;
+
+ BOOLEAN FirstSectionSynchronize ;
+ BOOLEAN SecondSectionSynchronize ;
+ BOOLEAN SectionEndsNotSynchronized;
+ BOOLEAN SkipLine ;
+
+ LINE FirstSectionCurrentLine ;
+ LINE SecondSectionCurrentLine ;
+
+ UCHAR CombinedLineVariation ;
+ UCHAR Padding[UCHAR_REMAINDER] ;
+
+} FUNCTION_ELEMENTS, *PFUNCTION_ELEMENTS;
+
+#if !( defined(lint) || defined(_lint) )
+#if i386
+#pragma warning(disable:4103)
+#endif
+#pragma pack()
+#endif
+
+
+
+
+//
+// MACROS
+//
+#define CloseFiles( a, b ) { \
+ if ( a.FileP != (FILE *)NULL ) fclose( a.FileP ); \
+ if ( b.FileP != (FILE *)NULL ) fclose( b.FileP ); \
+ }
+
+#define CreateSection() calloc( 1, sizeof( SECTION ) )
+#define DestroySection( a ) free( a )
+#define ClearAndSetLine( a, b ) { memset( (b), 0, sizeof( LINE ) ); (a)->CurrentLine = (b); }
+#define CreateFunctionElements() calloc( 1, sizeof( FUNCTION_ELEMENTS ) )
+#define DestroyFunctionElements( a ) free( a )
+
+#define InsertToken( a, b ) { \
+ a->NextToken = b; \
+ b = a; \
+ }
+#define DestroyToken( a ) free( a )
+
+
+
+//
+// Function definitions
+//
+VOID _cdecl main ( INT , CHAR ** );
+VOID Usage ( VOID );
+BOOLEAN GetFilePair ( PCHAR * , PCHAR * , PCHAR );
+BOOLEAN CompareFiles ( PMFILE , PMFILE , FILE * , ULONG * );
+BOOLEAN OpenFiles ( PMFILE , PCHAR , PMFILE , PCHAR );
+BOOLEAN CompareFiles ( PMFILE , PMFILE , FILE * , PULONG );
+BOOLEAN CompareSections ( PSECTION, PSECTION, FILE * , PULONG );
+BOOLEAN GetNextLine ( PSECTION );
+BOOLEAN DoNotSkipThisLine ( PSECTION );
+VOID LineType ( PSECTION );
+BOOLEAN ExtractResults ( PSECTION );
+BOOLEAN ExtractBetweenValues ( PSECTION );
+BOOLEAN CombinedVariation ( PSECTION, PSECTION, PUCHAR );
+RESULT CompareLines ( PSECTION, PSECTION );
+BOOLEAN InitializeSectionControl ( PSECTION, PSECTION );
+VOID PrintComparisonResults ( PSECTION, PSECTION, RESULT , ULONG , FILE * );
+VOID PrintSectionInformation ( PSECTION, FILE * );
+DOUBLE ExtractSectionIDFromLine ( PSECTION );
+BOOLEAN CheckSectionIDFromCurrentLines ( PSECTION, PSECTION );
+BOOLEAN CompareLinesAndPrintResults ( PSECTION, PSECTION, PULONG , FILE * );
+VOID TokenInsertInSection ( PSECTION );
+RESULT MatchTopToken ( PTOKEN_LIST, PTOKEN_LIST );
+VOID CompareTokensAndPrintResults ( PSECTION, PSECTION, PULONG , FILE * );
+BOOLEAN MayDifferExistsInOneOrMoreLines( PSECTION, PSECTION );
diff --git a/private/ntos/ndis/testprot/tpdiff/makefile b/private/ntos/ndis/testprot/tpdiff/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpdiff/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/testprot/tpdiff/sources b/private/ntos/ndis/testprot/tpdiff/sources
new file mode 100644
index 000000000..ca52757fa
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpdiff/sources
@@ -0,0 +1,48 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=testprot
+MINORCOMP=tpdiff
+
+TARGETNAME=tpdiff
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+INCLUDES=..\..\wrapper;..\inc;..\..\..\inc
+
+SOURCES=tpdiff.c
+
+i860_SOURCES=
+
+i386_SOURCES=
+
+MIPS_SOURCES=
+
+RELATIVE_DEPTH=..\..\..
+NTTEST=
+OPTIONAL_NTTEST=
+
+UMTYPE=console
+UMAPPL=tpdiff
+UMLIBS=$(BASEDIR)\public\sdk\lib\*\setargv.obj
diff --git a/private/ntos/ndis/testprot/tpdiff/tpdiff.c b/private/ntos/ndis/testprot/tpdiff/tpdiff.c
new file mode 100644
index 000000000..739227889
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpdiff/tpdiff.c
@@ -0,0 +1,1749 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ tpdiff.c
+
+Abstract:
+
+ This is the main component of the NDIS 3.0 MAC Tester log file program.
+
+Author:
+
+ Tom Adams (tomad) 2-Apr-1992
+
+Revision History:
+
+ 2-Apr-1992 tomad
+
+ created
+
+--*/
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+
+#include <windows.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+
+//
+// TpDiff function prototypes
+//
+
+DWORD
+TpDiffInitializeFiles(
+ IN WORD argc,
+ IN LPSTR argv[]
+ );
+
+VOID
+TpDiffFreeFiles(
+ VOID
+ );
+
+
+DWORD
+TpDiffInitLogFileList(
+ IN LPSTR LogFileList
+ );
+
+VOID
+TpDiffFreeLogFileList(
+ VOID
+ );
+
+DWORD
+TpDiffLoadNextLogFilePair(
+ VOID
+ );
+
+DWORD
+TpDiffOpenLogFiles(
+ VOID
+ );
+
+VOID
+TpDiffFreeLogFiles(
+ VOID
+ );
+
+DWORD
+TpDiffInitDiffFile(
+ IN LPSTR DiffFile
+ );
+
+DWORD
+TpDiffWriteToDiffFile(
+ IN LPSTR Buffer
+ );
+
+DWORD
+TpDiffWriteErrorToDiffFile(
+ IN LPSTR Buffer
+ );
+
+
+VOID
+TpDiffFreeDiffFile(
+ VOID
+ );
+
+DWORD
+TpDiffCompareLogFiles(
+ VOID
+ );
+
+DWORD
+TpDiffGetNextLine(
+ IN PBYTE Buffer,
+ IN PDWORD BufOffSet,
+ IN DWORD BufSize,
+ IN PDWORD LineNumber,
+ OUT PBYTE Line
+ );
+
+DWORD
+TpDiffGetResults(
+ IN PBYTE Buffer
+ );
+
+BOOL
+TpDiffMayValuesDiffer(
+ IN PBYTE Buffer
+ );
+
+BOOL
+TpDiffMustLastTwoValuesEqual(
+ IN PBYTE Buffer
+ );
+
+VOID
+TpDiffUsage (
+ VOID
+ );
+
+//
+// TpDiff Global variables
+//
+
+BYTE LogFileListName[256];
+BYTE LogFileName[256];
+BYTE KnownLogFileName[256];
+BYTE DiffFileName[256];
+
+HANDLE DiffFileHandle = NULL;
+
+PBYTE LogFileListBuffer = NULL;
+DWORD LogFileListSize = 0;
+DWORD LogFileListOffset = 0;
+
+PBYTE LogFileBuffer = NULL;
+DWORD LogFileSize = 0;
+DWORD LogFileOffset;
+DWORD LogFileLineNumber;
+
+PBYTE KnownLogFileBuffer = NULL;
+DWORD KnownLogFileSize = 0;
+DWORD KnownLogFileOffset;
+DWORD KnownLogFileLineNumber;
+
+PBYTE DiffBuffer = NULL;
+BOOL LoggingToScreen = FALSE;
+
+BOOL MoreFilesToDiff = FALSE;
+
+BYTE LogFileLine[256];
+BYTE KnownLogFileLine[265];
+
+DWORD ResultsValue = 0;
+DWORD LastResultsValue = 0;
+
+DWORD LogFileDifferences = 0;
+DWORD TotalDifferences = 0;
+
+//
+// the main routine for TpDiff.
+//
+
+
+VOID _cdecl
+main(
+ IN WORD argc,
+ IN LPSTR argv[]
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ IN WORD argc - Supplies the number of parameters
+ IN LPSTR argv[] - Supplies the parameter list.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DWORD Status;
+
+ //
+ // Read the command line, and open the requested files and set
+ // them up to be processed.
+ //
+
+ Status = TpDiffInitializeFiles( argc,argv );
+
+ if ( Status != NO_ERROR ) {
+ ExitProcess( Status );
+ }
+
+ //
+ // We have at least two files to compare so ...
+ //
+
+ do {
+
+ //
+ // Compare the LOG_FILE and KNOWN_LOG_FILE.
+ //
+
+ Status = TpDiffCompareLogFiles();
+
+ if ( Status != NO_ERROR ) {
+ break;
+ }
+
+ //
+ // Then see if there are any more files to compare.
+ //
+
+ Status = TpDiffLoadNextLogFilePair();
+
+ if ( Status != NO_ERROR ) {
+ break;
+ }
+
+ //
+ // and if so open them, and set up their respective buffers
+ // to be compared.
+ //
+
+ Status = TpDiffOpenLogFiles();
+
+ if (( Status == ERROR_FILE_NOT_FOUND ) &&
+ ( MoreFilesToDiff == TRUE )) {
+
+ //
+ // We failed to open one of the logs files due to the fact
+ // that it did not exist, AND we are reading from a list of
+ // log/known log file pairs. We should get the next pair
+ // and try to open them.
+ //
+
+ do {
+
+ Status = TpDiffLoadNextLogFilePair();
+
+ if ( Status != NO_ERROR ) {
+ break;
+ }
+
+ Status = TpDiffOpenLogFiles();
+
+ if (( Status != NO_ERROR ) &&
+ ( Status != ERROR_FILE_NOT_FOUND )) {
+ break;
+ }
+
+ } while (( MoreFilesToDiff == TRUE ) &&
+ ( Status == ERROR_FILE_NOT_FOUND ));
+
+ if ( Status != NO_ERROR ) {
+ break;
+ }
+ } else if ( Status != NO_ERROR ) {
+ break;
+ }
+
+ } while ( MoreFilesToDiff == TRUE );
+
+ printf("\n\tTpDiff Pass Contained %d Total Differences.\n",TotalDifferences);
+
+ if ( LoggingToScreen == FALSE ) {
+
+ LPSTR TmpBuf = DiffBuffer;
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\nTpDiff: Contained %d Total Differences.\n",
+ TotalDifferences);
+
+ Status = TpDiffWriteToDiffFile( TmpBuf );
+
+ if ( Status != NO_ERROR ) {
+ printf("\n\tTpDiff: failed to write statistics to logfile, return %d\n",
+ Status);
+ }
+ }
+
+ //
+ // Free all the files handles, and buffers previously allocated.
+ //
+
+ TpDiffFreeFiles();
+
+ ExitProcess( (DWORD)NO_ERROR );
+}
+
+
+DWORD
+TpDiffInitializeFiles(
+ IN WORD argc,
+ IN LPSTR argv[]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine parses the command line arguments, and opens the files
+ that are passed in on the command line.
+
+Arguments:
+
+ IN WORD argc - Supplies the number of arguments passed in at startup.
+
+ IN LPTSTR argv[] - Supplies the argument vector containing the arguments
+ passed in from the command line.
+
+Return Value:
+
+ DWORD - NO_ERROR if all the arguments are valid and the files are opened
+ successfully. If the files fail to open, then the error returned
+ from the open routines are returned. ERROR_INALID_PARAMETER
+ otherwise.
+
+--*/
+
+{
+ DWORD Status;
+
+ //
+ // See if we have enough arguments on the commmand line.
+ //
+
+ if ( argc == 1 ) {
+ TpDiffUsage();
+ return ERROR_INVALID_PARAMETER;
+ } else if (( argc != 4 ) && ( argc != 3 )) {
+ printf("\n\tTpDiff: ERROR - Invalid number of arguments\n");
+ TpDiffUsage();
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Is the first argument a LOG_FILE_NAME or the LOG_FILES_LIST switch ?
+ //
+
+ if (!strcmp(argv[1],"-f")) {
+
+ //
+ // It is the LOG_FILES_LIST switch. We need four arguments for
+ // this case, so make sure we have them.
+
+ if ( argc != 4 ) {
+ printf("\n\tTpDiff: ERROR - Invalid number of arguments\n");
+ TpDiffUsage();
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // It is the LOG_FILES_LIST switch. First set the flag indicating
+ // that there are possible more then one pair of files to diff.
+ //
+
+ MoreFilesToDiff = TRUE;
+
+ //
+ // We have a file containing the logfile/knownlogfile name pairs.
+ // Set up the name to be opened, and then open it now and read
+ // the contents.
+ //
+
+ Status = TpDiffInitLogFileList( argv[2] );
+
+ if ( Status != NO_ERROR ) {
+ return Status;
+ }
+
+ //
+ // Now read the first file pair from the list. The names
+ // will be stored in the global vars LogFileName and
+ // KnownLogFileName.
+ //
+
+ Status = TpDiffLoadNextLogFilePair();
+
+ if ( Status != NO_ERROR ) {
+ return Status;
+ }
+ } else {
+
+ //
+ // We have been passed two files to diff. set up the names to
+ // be opened.
+ //
+
+ strcpy( LogFileName,argv[1] );
+ strcpy( KnownLogFileName,argv[2] );
+ }
+
+ //
+ // Now open the first two log files to diff. The file handles will be
+ // stored in the global vars LogFileNameHandle and KnownLogFileNameHandle.
+ //
+
+ Status = TpDiffOpenLogFiles();
+
+ if (( Status == ERROR_FILE_NOT_FOUND ) &&
+ ( MoreFilesToDiff == TRUE )) {
+
+ //
+ // We failed to open one of the logs files due to the fact
+ // that it did not exist, AND we are reading from a list of
+ // log/known log file pairs. We should get the next pair
+ // and try to open them.
+ //
+
+ do {
+
+ Status = TpDiffLoadNextLogFilePair();
+
+ if ( Status != NO_ERROR ) {
+ break;
+ }
+
+ Status = TpDiffOpenLogFiles();
+
+ if (( Status != NO_ERROR ) &&
+ ( Status != ERROR_FILE_NOT_FOUND )) {
+ break;
+ }
+
+ } while (( MoreFilesToDiff == TRUE ) &&
+ ( Status == ERROR_FILE_NOT_FOUND ));
+
+ if ( Status != NO_ERROR ) {
+ return Status;
+ }
+ } else if ( Status != NO_ERROR ) {
+ return Status;
+ }
+
+ //
+ // Finally setup the results file name and open it. This is the file
+ // any differences between the two log files will be written to.
+ //
+
+ Status = TpDiffInitDiffFile( argv[3] );
+
+ if ( Status != NO_ERROR ) {
+ return Status;
+ }
+
+ return NO_ERROR;
+}
+
+
+VOID
+TpDiffFreeFiles(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine closes all open file handles and frees any corresponding
+ buffers.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Free the LOG_FILE_LIST resources.
+ //
+
+ TpDiffFreeLogFileList();
+
+ //
+ // Free the LOG_FILE and KNOWN_LOG_FILE resources.
+ //
+
+ TpDiffFreeLogFiles();
+
+ //
+ // Free the DIFF_FILE resources.
+ //
+
+ TpDiffFreeDiffFile();
+}
+
+
+DWORD
+TpDiffInitLogFileList(
+ IN LPSTR LogFileList
+ )
+
+/*++
+
+Routine Description:
+
+ This routine opens and reads the LOG_FILE_LIST file into a newly
+ allocated buffer. The handle, buffer and filename are all attached
+ to global LOG_FILE_LIST variables.
+
+Arguments:
+
+ IN LPSTR LogFileList - Supplies the name of the LOG_FILE_LIST file
+ to open.
+
+Return Value:
+
+ DWORD - If NO_ERROR the file was opened and read into the buffer.
+ otherwise there was a failure that will cause the application
+ to un-initialize and exit.
+
+--*/
+
+{
+ DWORD Status;
+ HANDLE LogFileListHandle = NULL;
+ HANDLE LogFileListMapHandle = NULL;
+
+ //
+ // First Open the LOG_FILE_LIST file.
+ //
+
+ strcpy( LogFileListName,LogFileList );
+
+ LogFileListHandle = CreateFile(
+ LogFileListName,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL
+ );
+
+ if ( LogFileListHandle == (HANDLE)-1 ) {
+ Status = GetLastError();
+ printf("\n\tTpDiff: Failed to open LOG_FILE_LIST \"%s\", returned %ld.\n",
+ LogFileListName,Status);
+ return Status;
+ }
+
+ //
+ // then find its size.
+ //
+
+ LogFileListSize = GetFileSize( LogFileListHandle,NULL );
+
+ if ( LogFileListSize == -1 ) {
+ Status = GetLastError();
+ printf("\n\tTpDiff: failed find LOG_FILE_LIST size, returned %ld.\n",Status);
+ CloseHandle( LogFileListHandle );
+ return Status;
+ } else if ( LogFileListSize == 0 ) {
+ printf("\n\tTpDiff: LOG_FILE_LIST is empty, nothing to compare.\n");
+ CloseHandle( LogFileListHandle );
+ return ERROR_FILE_NOT_FOUND;
+ }
+
+ //
+ // and create a file mapping.
+ //
+
+ LogFileListMapHandle = CreateFileMapping(
+ LogFileListHandle,
+ NULL,
+ PAGE_READONLY,
+ 0,
+ LogFileListSize,
+ NULL
+ );
+
+ if ( LogFileListMapHandle == NULL ) {
+ Status = GetLastError();
+ printf("\n\tTpDiff: Unable to map LOG_FILE_LIST \"%s\", returned %d",
+ LogFileListName,Status);
+ CloseHandle( LogFileListHandle );
+ return Status;
+ }
+
+ //
+ // We're done with the file handle so close it now.
+ //
+
+ CloseHandle( LogFileListHandle );
+
+ //
+ // Now create a View of the mapped file.
+ //
+
+ LogFileListBuffer = MapViewOfFile(
+ LogFileListMapHandle,
+ FILE_MAP_READ,
+ 0,
+ 0,
+ LogFileListSize
+ );
+
+ if ( LogFileListBuffer == NULL ) {
+ Status = GetLastError();
+ printf("\n\tTpDiff: Unable to map view of LOG_FILE_LIST \"%s\", returned %d",
+ LogFileListName,Status);
+ CloseHandle( LogFileListMapHandle );
+ return Status;
+ }
+
+ //
+ // We're done with the map handle so close it now.
+ //
+
+ CloseHandle( LogFileListMapHandle );
+
+ return NO_ERROR;
+}
+
+
+VOID
+TpDiffFreeLogFileList(
+ VOID
+ )
+{
+ //
+ // Simply UnMap the log file list buffer and null it out.
+ //
+
+ if ( LogFileListBuffer != NULL ) {
+ UnmapViewOfFile( LogFileListBuffer );
+ LogFileListBuffer = NULL;
+ }
+}
+
+
+DWORD
+TpDiffLoadNextLogFilePair(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads the next two log file names from the log file list
+ buffer and moves the log file list pointer past them. The format of
+ the log file list is pairs of LOG_FILE_NAME KNOWN_LOG_FILE_NAME with
+ each pair residing on the same line in the file.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ DWORD - NO_ERROR if the next two files are found, ERROR_INVALID_PARAMETER
+ if the log file list is the wrong format.
+
+--*/
+
+{
+ DWORD TmpOffset;
+ DWORD Length;
+
+ //
+ // If we are not reading files from a loglistfile the MoreFilesToDiff
+ // flag will be set to FALSE, so just return.
+ //
+
+ if ( MoreFilesToDiff == FALSE ) {
+ return ERROR_NO_MORE_FILES;
+ }
+
+ //
+ // Move the LOG_FILE_LIST pointer to the beginning of the next
+ // file name in the list.
+ //
+
+ while ((((( LogFileListBuffer[LogFileListOffset] == ' ' ) ||
+ ( LogFileListBuffer[LogFileListOffset] == '\t')) ||
+ ( LogFileListBuffer[LogFileListOffset] == '\r')) ||
+ ( LogFileListBuffer[LogFileListOffset] == '\n')) &&
+ ( LogFileListOffset < LogFileListSize )) {
+
+ LogFileListOffset++;
+ }
+
+ if ( LogFileListOffset == LogFileListSize ) {
+ LogFileName[0] = '\0';
+ KnownLogFileName[0] = '\0';
+ return ERROR_NO_MORE_FILES;
+ }
+
+ //
+ // then find the length of the next file name.
+ //
+
+ Length = 0;
+ TmpOffset = LogFileListOffset;
+
+ while ((((( LogFileListBuffer[TmpOffset] != ' ' ) &&
+ ( LogFileListBuffer[TmpOffset] != '\t' )) &&
+ ( LogFileListBuffer[TmpOffset] != '\r')) &&
+ ( LogFileListBuffer[TmpOffset] != '\n')) &&
+ ( TmpOffset < LogFileListSize )) {
+
+ Length++;
+ TmpOffset++;
+ }
+
+ //
+ // copy it to the global var LogFileName, and null terminate it.
+ //
+
+ strncpy( LogFileName,&LogFileListBuffer[LogFileListOffset],Length );
+
+ LogFileName[Length] = '\0';
+
+ //
+ // then move the LOG_FILE_LIST pointer past the LogFileName
+ //
+
+ LogFileListOffset = TmpOffset + 1;
+
+ //
+ // and search to the beginning of the next file name
+ //
+
+ while ((( LogFileListBuffer[LogFileListOffset] == ' ' ) ||
+ ( LogFileListBuffer[LogFileListOffset] == '\t' )) &&
+ ( LogFileListOffset < LogFileListSize )) {
+
+ LogFileListOffset++;
+
+ if (( LogFileListBuffer[LogFileListOffset] == '\n' ) ||
+ ( LogFileListBuffer[LogFileListOffset] == '\r' )) {
+
+ KnownLogFileName[0] = '\0';
+
+ MoreFilesToDiff = FALSE;
+
+ printf("\tTpDiff: ERROR - LOG_FILE_LIST must have filename pairs on\n");
+ printf("\t same line in file.\n");
+
+ return ERROR_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // then find the length of the next file name.
+ //
+
+ Length = 0;
+ TmpOffset = LogFileListOffset;
+
+ while ((((( LogFileListBuffer[TmpOffset] != ' ' ) &&
+ ( LogFileListBuffer[TmpOffset] != '\t' )) &&
+ ( LogFileListBuffer[TmpOffset] != '\r')) &&
+ ( LogFileListBuffer[TmpOffset] != '\n')) &&
+ ( TmpOffset < LogFileListSize )) {
+
+ Length++;
+ TmpOffset++;
+ }
+
+ //
+ // copy it to the global var KnownLogFileName, and null terminate it.
+ //
+
+ strncpy( KnownLogFileName,&LogFileListBuffer[LogFileListOffset],Length );
+
+ KnownLogFileName[Length] = '\0';
+
+ //
+ // then move the LOG_FILE_LIST pointer past the KnownLogFileName
+ //
+
+ LogFileListOffset = TmpOffset + 1;
+
+ return NO_ERROR;
+}
+
+
+DWORD
+TpDiffOpenLogFiles(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine opens the file names stored in the global variables
+ LogFileName and KnownLogFile name, creates a buffer for each and
+ reads the file contents into the respective buffer.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ DWORD - If NO_ERROR the files were opened and read into the buffers.
+ otherwise there was a failure that will cause the application
+ to un-initialize and exit.
+
+--*/
+
+{
+ DWORD Status;
+ HANDLE LogFileHandle = NULL;
+ HANDLE LogFileMapHandle = NULL;
+ HANDLE KnownLogFileHandle = NULL;
+ HANDLE KnownLogFileMapHandle = NULL;
+
+ //
+ // First open the LOG_FILE file.
+ //
+
+ if (( LogFileName[0] == '\0' ) || ( KnownLogFileName[0] == '\0' )) {
+ return ERROR_NO_MORE_FILES;
+ }
+
+ LogFileHandle = CreateFile(
+ LogFileName,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL
+ );
+
+ if ( LogFileHandle == (HANDLE)-1 ) {
+ Status = GetLastError();
+
+ if ( Status == ERROR_FILE_NOT_FOUND ) {
+ TpDiffWriteErrorToDiffFile( "Tpdiff: WARNING - Failed to open LOG_FILE \"" );
+ TpDiffWriteErrorToDiffFile( LogFileName );
+ TpDiffWriteErrorToDiffFile( "\".\n");
+ }
+
+ printf("\n\tTpDiff: Failed to open LOG_FILE \"%s\", returned %ld.\n",
+ LogFileName,Status);
+ return Status;
+ }
+
+ //
+ // then find its size.
+ //
+
+ LogFileSize = GetFileSize( LogFileHandle,NULL );
+
+ if ( LogFileSize == -1 ) {
+ Status = GetLastError();
+ printf("\n\tTpDiff: failed find LOG_FILE size - returned %ld.\n",Status);
+ CloseHandle( LogFileHandle );
+ return Status;
+ } else if ( LogFileSize == 0 ) {
+ printf("\n\tTpDiff: LOG_FILE \"%s\" is empty, nothing to compare.\n",LogFileName);
+ CloseHandle( LogFileHandle );
+ return ERROR_NO_MORE_FILES;
+
+ }
+
+ //
+ // and create a file mapping.
+ //
+
+ LogFileMapHandle = CreateFileMapping(
+ LogFileHandle,
+ NULL,
+ PAGE_READONLY,
+ 0,
+ LogFileSize,
+ NULL
+ );
+
+ if ( LogFileMapHandle == NULL ) {
+ Status = GetLastError();
+ printf("\n\tTpDiff: Unable to map LOG_FILE \"%s\", returned %d",
+ LogFileName,Status);
+ CloseHandle( LogFileHandle );
+ return Status;
+ }
+
+ //
+ // We're done with the file handle so close it now.
+ //
+
+ CloseHandle( LogFileHandle );
+
+ //
+ // Now create a View of the mapped file.
+ //
+
+ LogFileBuffer = MapViewOfFile(
+ LogFileMapHandle,
+ FILE_MAP_READ,
+ 0,
+ 0,
+ LogFileSize
+ );
+
+ if ( LogFileBuffer == NULL ) {
+ Status = GetLastError();
+ printf("\n\tTpDiff: Unable to map view of LOG_FILE \"%s\", returned %d",
+ LogFileName,Status);
+ CloseHandle( LogFileMapHandle );
+ return Status;
+ }
+
+ //
+ // We're done with the map handle so close it now.
+ //
+
+ CloseHandle( LogFileMapHandle );
+
+ //
+ // Now reset the offset into the LogFilebuffer and the line number
+ // counter to zero.
+ //
+
+ LogFileOffset = 0;
+ LogFileLineNumber = 1;
+
+ //
+ // Then open the KNOWN_LOG_FILE file.
+ //
+
+ KnownLogFileHandle = CreateFile(
+ KnownLogFileName,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL
+ );
+
+ if ( KnownLogFileHandle == (HANDLE)-1 ) {
+ Status = GetLastError();
+
+ if ( Status == ERROR_FILE_NOT_FOUND ) {
+ TpDiffWriteErrorToDiffFile("TpDiff: WARNING Failed to open KNOWN_LOG_FILE \"");
+ TpDiffWriteErrorToDiffFile(KnownLogFileName);
+ TpDiffWriteErrorToDiffFile("\".\n");
+ }
+
+ printf("\n\tTpDiff: Failed to open KNOWN_LOG_FILE \"%s\", returned %ld.\n",
+ KnownLogFileName,Status);
+ return Status;
+ }
+
+ //
+ // then find its size.
+ //
+
+ KnownLogFileSize = GetFileSize( KnownLogFileHandle,NULL );
+
+ if ( KnownLogFileSize == -1 ) {
+ Status = GetLastError();
+ printf("\n\tTpDiff: failed find KNOWN_LOG_FILE size - returned %ld.\n",Status);
+ CloseHandle( KnownLogFileHandle );
+ return Status;
+ } else if ( KnownLogFileSize == 0 ) {
+ printf("\n\tTpDiff: KNOWN_LOG_FILE \"%s\" is empty, nothing to compare.\n",KnownLogFileName);
+ CloseHandle( KnownLogFileHandle );
+ return ERROR_NO_MORE_FILES;
+ }
+
+ //
+ // and create a file mapping.
+ //
+
+ KnownLogFileMapHandle = CreateFileMapping(
+ KnownLogFileHandle,
+ NULL,
+ PAGE_READONLY,
+ 0,
+ KnownLogFileSize,
+ NULL
+ );
+
+ if ( KnownLogFileMapHandle == NULL ) {
+ Status = GetLastError();
+ printf("\n\tTpDiff: Unable to map KNOWN_LOG_FILE \"%s\", returned %d",
+ KnownLogFileName,Status);
+ CloseHandle( KnownLogFileHandle );
+ return Status;
+ }
+
+ //
+ // We're done with the file handle so close it now.
+ //
+
+ CloseHandle( KnownLogFileHandle );
+
+ //
+ // Now create a View of the mapped file.
+ //
+
+ KnownLogFileBuffer = MapViewOfFile(
+ KnownLogFileMapHandle,
+ FILE_MAP_READ,
+ 0,
+ 0,
+ KnownLogFileSize
+ );
+
+ if ( KnownLogFileBuffer == NULL ) {
+ Status = GetLastError();
+ printf("\n\tTpDiff: Unable to map view of KNOWN_LOG_FILE \"%s\", returned %d",
+ KnownLogFileName,Status);
+ CloseHandle( KnownLogFileMapHandle );
+ return Status;
+ }
+
+ //
+ // We're done with the map handle so close it now.
+ //
+
+ CloseHandle( KnownLogFileMapHandle );
+
+ //
+ // Now reset the offset into the KnownLogFilebuffer to zero.
+ // and return.
+ //
+
+ KnownLogFileOffset = 0;
+ KnownLogFileLineNumber = 1;
+
+ return NO_ERROR;
+}
+
+
+VOID
+TpDiffFreeLogFiles(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees the LOG_FILE and KNOWN_LOG_FILE buffers and
+ nulls their respective pointers.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if ( LogFileBuffer != NULL ) {
+ UnmapViewOfFile( LogFileBuffer );
+ LogFileBuffer = NULL;
+ }
+
+ if ( KnownLogFileBuffer != NULL ) {
+ UnmapViewOfFile( KnownLogFileBuffer );
+ KnownLogFileBuffer = NULL;
+ }
+}
+
+
+DWORD
+TpDiffInitDiffFile(
+ IN LPSTR DiffFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine opens the DIFF_FILE. The handle and file name are
+ attached to global DIFF_FILE variables. A buffer is also allocated
+ that is used to any output to the DIFF_FILE.
+
+Arguments:
+
+ IN LPSTR DiffFile - Supplies the name of the DIFF_FILE to open.
+
+Return Value:
+
+ DWORD - The Status of the OPEN.
+
+--*/
+
+{
+ DWORD Status;
+
+ //
+ // If a Diff file name was passed in on the command line,
+ // Open the DIFF_FILE file.
+ //
+
+ if ( DiffFile != NULL ) {
+
+ strcpy( DiffFileName,DiffFile );
+
+ DiffFileHandle = CreateFile(
+ DiffFileName,
+ GENERIC_WRITE,
+ FILE_SHARE_READ,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL
+ );
+
+ if ( DiffFileHandle == (HANDLE)-1 ) {
+ Status = GetLastError();
+ printf("\n\tTpDiff: Failed to open DIFFS_FILE \"%s\", returned %ld.\n",
+ DiffFileName,Status);
+ return Status;
+ }
+
+ } else { // We will just write the DIFFS to the console.
+
+ DiffFileHandle = GetStdHandle(STD_OUTPUT_HANDLE);
+ LoggingToScreen = TRUE;
+ }
+
+ DiffBuffer = GlobalAlloc(
+ GMEM_FIXED | GMEM_ZEROINIT,
+ 0x1000
+ );
+
+ if ( DiffBuffer == NULL ) {
+ Status = GetLastError();
+ printf("\n\tTpDiff: failed to alloc DIFF_FILE buffer, returned %ld.\n",
+ Status);
+
+ if ( strlen( DiffFile ) != 0 ) { // close the diff file
+ CloseHandle( DiffFileHandle );
+ }
+
+ DiffFileHandle = NULL;
+ return Status;
+ }
+
+ return NO_ERROR;
+}
+
+
+DWORD
+TpDiffWriteToDiffFile(
+ IN LPSTR Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine simply writes a string to the DIFF_FILE.
+
+Arguments:
+
+ IN LPSTR Buffer - Supplies the string to write to the DIFF_FILE.
+
+Return Value:
+
+ DWORD - The Status of the call to WriteFile.
+
+--*/
+
+
+{
+ DWORD Status;
+ DWORD BytesWritten;
+
+ if ( !WriteFile(
+ DiffFileHandle,
+ DiffBuffer,
+ (Buffer-DiffBuffer),
+ &BytesWritten,
+ NULL
+ )) {
+
+ Status = GetLastError();
+ printf("\n\tTpDiff: Write to DIFFS_FILE failed, returned %ld\n",Status);
+ return Status;
+ }
+
+ return NO_ERROR;
+}
+
+
+DWORD
+TpDiffWriteErrorToDiffFile(
+ IN LPSTR Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine simply writes a string to the DIFF_FILE.
+
+Arguments:
+
+ IN LPSTR Buffer - Supplies the string to write to the DIFF_FILE.
+
+Return Value:
+
+ DWORD - The Status of the call to WriteFile.
+
+--*/
+
+
+{
+ DWORD Status;
+ DWORD BytesWritten;
+ DWORD BufLength = 0;
+
+ BufLength = strlen( Buffer );
+
+ if ( !WriteFile(
+ DiffFileHandle,
+ Buffer,
+ BufLength,
+ &BytesWritten,
+ NULL
+ )) {
+
+ Status = GetLastError();
+ printf("\n\tTpDiff: Write to DIFFS_FILE failed, returned %ld\n",Status);
+ return Status;
+ }
+
+ return NO_ERROR;
+}
+
+
+VOID
+TpDiffFreeDiffFile(
+ VOID
+ )
+{
+ //
+ // Close the DIFF_FILE, deallocate the diff buffer, and null out
+ // their pointers.
+ //
+
+ if ( DiffFileHandle != NULL ) {
+
+ if ( strlen( DiffFileName ) != 0 ) {
+ CloseHandle( DiffFileHandle );
+ }
+
+ DiffFileHandle = NULL;
+ }
+
+ if ( DiffBuffer != NULL ) {
+ GlobalFree( DiffBuffer );
+ DiffBuffer = NULL;
+ }
+}
+
+
+DWORD
+TpDiffCompareLogFiles(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This is the main compare routine of the TpDiff utility. It compares the
+ log file and known log file line by line for diffences.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DWORD Status;
+ DWORD Length;
+ DWORD KnownLength;
+ DWORD CmpLength;
+ LPSTR TmpBuf = DiffBuffer;
+
+ printf("\n\tTpDiff: comparing %s and %s ...\n",
+ LogFileName,KnownLogFileName);
+ do {
+
+ //
+ // Get the next line of the Log File.
+ //
+
+ Length = TpDiffGetNextLine(
+ LogFileBuffer,
+ &LogFileOffset,
+ LogFileSize,
+ (PDWORD)&LogFileLineNumber,
+ (PBYTE)&LogFileLine
+ );
+
+ if ( Length != 0 ) {
+
+ //
+ // Get the value of the Statitics results for that line,
+ // first storing away the last lines value.
+ //
+
+ LastResultsValue = ResultsValue;
+
+ ResultsValue = TpDiffGetResults( LogFileLine );
+ }
+
+ //
+ // And the next line of the Known Log File.
+ //
+
+ KnownLength = TpDiffGetNextLine(
+ KnownLogFileBuffer,
+ &KnownLogFileOffset,
+ KnownLogFileSize,
+ (PDWORD)&KnownLogFileLineNumber,
+ (PBYTE)&KnownLogFileLine
+ );
+
+ //
+ // Compare them with respect to the length of the longer of the
+ // two lines.
+ //
+
+ if ( Length >= KnownLength ) {
+ CmpLength = Length;
+ } else {
+ CmpLength = KnownLength;
+ }
+
+ if (( CmpLength != 0 ) &&
+ ( memcmp( LogFileLine,KnownLogFileLine,CmpLength ) != 0 )) {
+
+ if (( TpDiffMayValuesDiffer( LogFileLine )) ||
+ ( TpDiffMayValuesDiffer( KnownLogFileLine ))) {
+
+ //
+ // The line contains a MAY_DIFFER flag, so ignore the
+ // differences.
+ //
+
+ } else if (( TpDiffMustLastTwoValuesEqual( LogFileLine )) &&
+ ( LastResultsValue == ResultsValue )) {
+ } else {
+
+ LogFileDifferences++;
+
+ //
+ // If lines did not match, and the line does not contain the
+ // MAY_DIFFER string, or It contained EQUAL_LAST, but the
+ // stats value weren't equal, then write the info to the
+ // diff file.
+ //
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"Logfile: %s - Line Number: %ld\n",
+ LogFileName,LogFileLineNumber);
+ TmpBuf += (BYTE)sprintf(TmpBuf,"Found: %s\n",LogFileLine);
+ TmpBuf += (BYTE)sprintf(TmpBuf,"Expected: %s\n\n",KnownLogFileLine);
+
+ if (( TpDiffMustLastTwoValuesEqual( LogFileLine )) &&
+ ( LastResultsValue != ResultsValue )) {
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"TpDiff: ERROR - The last two test values (%ld) and (%ld) did not equal.\n\n",
+ LastResultsValue,ResultsValue);
+ }
+
+ Status = TpDiffWriteToDiffFile( TmpBuf );
+
+ if ( Status != NO_ERROR ) {
+ printf("\n\tTpDiff: failed to write difference to logfile, return %d\n",
+ Status);
+ return Status;
+ }
+
+ //
+ // and then reset the TmpBuf for the next go round.
+ //
+
+ TmpBuf = DiffBuffer;
+ }
+ }
+
+ } while (( Length != 0 ) || ( KnownLength != 0 ));
+
+ //
+ // We have finished this log file, print the number of differences
+ // to the log, and to the screen, update the total errors counter,
+ // and reset the script error counter.
+ //
+
+ printf("\n\tLogFile %s Contained %d Differences.\n",
+ LogFileName,LogFileDifferences);
+
+ if ( LoggingToScreen == FALSE ) {
+
+ TmpBuf += (BYTE)sprintf(TmpBuf,"\nLogFile %s Contained %d Differences.\n",
+ LogFileName,LogFileDifferences);
+
+ Status = TpDiffWriteToDiffFile( TmpBuf );
+
+ if ( Status != NO_ERROR ) {
+ printf("\n\tTpDiff: failed to write statistics to logfile, return %d\n",
+ Status);
+ return Status;
+ }
+ }
+
+ TotalDifferences += LogFileDifferences;
+ LogFileDifferences = 0;
+
+ return NO_ERROR;
+}
+
+
+DWORD
+TpDiffGetNextLine(
+ IN PBYTE Buffer,
+ IN PDWORD BufOffset,
+ IN DWORD BufSize,
+ IN PDWORD LineNumber,
+ OUT PBYTE Line
+ )
+
+/*++
+
+Routine Description:
+
+ This routine take a file buffer and writes the next line of the
+ file into a line buffer.
+
+Arguments:
+
+ IN PBYTE FileBuffer - Supplies the buffer to read the next line from.
+ IN PDWORD *BufOffset - Supplies the current offset in to the file buffer.
+ IN DWORD BufSize - Supplies the size of the file buffer.
+ OUT PBYTE FileLine - Returns the next line of the buffer.
+
+Return Value:
+
+ DWORD - The length of the line written into the buffer. Zero if the
+ file is empty.
+
+--*/
+
+{
+ DWORD Length = 0;
+ DWORD i;
+ DWORD Offset = (DWORD)*BufOffset;
+ PBYTE TmpLine;
+
+ TmpLine = Line;
+
+ //
+ // Ignore any empty lines, and the last lines carriage
+ // returns/line feed pair.
+ //
+
+ while (((( Buffer[Offset] == '\n' ) ||
+ ( Buffer[Offset] == '\r' )) ||
+ ( Buffer[Offset] == 0x1a )) && // my editor quirk
+ ( Offset < BufSize )) {
+
+ if ( Buffer[Offset] == '\n' ) {
+ (*LineNumber)++;
+ }
+
+ Offset++;
+
+ if ( Offset >= BufSize ) {
+
+ //
+ // We have run off the end of this log file.
+ // Null terminate the Line buffer.
+ //
+
+ Line[0] = '\0';
+
+ //
+ // Update the Buffer Offset with the new offset value.
+ //
+
+ *BufOffset = (DWORD)Offset;
+
+ //
+ // and return a length of zero for the Line buffer.
+ //
+
+ return Length;
+ }
+ }
+
+ //
+ // while we are on the same line, copy the characters to the
+ // Line buffer.
+ //
+
+ while ((((( Buffer[Offset] != EOF ) &&
+ ( Buffer[Offset] != '\n' )) &&
+ ( Buffer[Offset] != '\r' )) &&
+ ( Buffer[Offset] != 0x1a )) && // my editor quirk
+ ( Offset <= BufSize )) {
+
+ *Line++ = Buffer[Offset++];
+ Length++;
+ }
+
+ //
+ // Now Null terminate the Line buffer, and then null out any spaces,
+ // tabs or carriage returns and line feeds that may exist at the
+ // end of the string.
+ //
+
+ *Line = '\0';
+ i = Length;
+
+ while ( --i > 0 ) {
+
+ if (( TmpLine[i] == 0x20 ) || // Space
+ ( TmpLine[i] == 0x09 )) { // Tab
+
+ TmpLine[i] = '\0';
+ Length--;
+ } else {
+ break;
+ }
+ }
+
+ //
+ // Update the Buffer Offset with the new offset value.
+ //
+
+ *BufOffset = (DWORD)Offset;
+
+ //
+ // and return the length of the Line buffer.
+ //
+
+ return Length;
+}
+
+
+DWORD
+TpDiffGetResults(
+ IN PBYTE Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine finds the string result value in the buffer, converts
+ it to an integer, and returns the integer value.
+
+Arguments:
+
+ IN PBYTE Buffer - Supplies a null terminated buffer containing
+ the possible string value.
+
+Return Value:
+
+ DWORD - the integer result value found in the string. -1 otherwise.
+
+--*/
+
+{
+ DWORD Results = 0xFFFFFFFF;
+ LPSTR Char = (LPSTR)Buffer;
+ LPSTR NextChar = (LPSTR)Buffer; // Anything that isn't NULL.
+
+ if ( Buffer == NULL ) {
+ return Results;
+ }
+
+ NextChar = strpbrk( Char,"=" );
+
+ if ( NextChar != NULL ) {
+ *NextChar++;
+ } else {
+ return Results;
+ }
+
+ while (( *NextChar == ' ' ) || ( *NextChar == '\t' )) {
+ *NextChar++;
+ }
+
+ Results = atol( NextChar ) ;
+
+ return Results;
+}
+
+
+BOOL
+TpDiffMayValuesDiffer(
+ IN PBYTE Buffer
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ IN PBYTE Buffer - Supplies a null terminated buffer containing the
+ possible text string "EQUAL_LAST" value.
+
+Return Value:
+
+ BOOL - TRUE if "MAY_DIFFER" exists in the string, FALSE otherwise.
+
+--*/
+
+{
+ LPSTR String;
+
+ String = strstr( Buffer,"MAY_DIFFER" );
+
+ if ( String == NULL ) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+BOOL
+TpDiffMustLastTwoValuesEqual(
+ IN PBYTE Buffer
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ IN PBYTE Buffer - Supplies a null terminated buffer containing the
+ possible text string "EQUAL_LAST" value.
+
+Return Value:
+
+ BOOL - TRUE if "EQUAL_LAST" exists in the string, FALSE otherwise.
+
+--*/
+
+{
+ LPSTR String;
+
+ String = strstr( Buffer,"EQUAL_LAST" );
+
+ if ( String == NULL ) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+VOID
+TpDiffUsage (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine prints out the TpDiff Usage statement.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ printf("\n\tUSAGE: TPDIFF [LOG_FILE] [KNOWN_LOG_FILE] [DIFFS_FILE]\n\n");
+
+ printf("\tWhere:\n\n");
+
+ printf("\tLOG_FILE - is the log file that is to be verified\n");
+ printf("\t for correctness.\n");
+
+ printf("\tKNOWN_LOG_FILE - is the known good log file that will be\n");
+ printf("\t used to verify the log file.\n");
+
+ printf("\tDIFFS_FILE - is the file the differences, if any exist,\n");
+ printf("\t between the log files and the known good log\n");
+ printf("\t files will be written to. If no file name is\n");
+ printf("\t given the differences will be printed to the\n");
+ printf("\t console.\n");
+
+ printf("\t\t- OR -\n\n");
+
+ printf("\tTPDIFF -F [LOG_FILE_LIST] [DIFFS_FILE]\n\n");
+
+ printf("\tWhere:\n\n");
+
+ printf("\tLOG_FILE_LIST - is a file containing pairs of log file\n");
+ printf("\t names and known good log file names. The\n");
+ printf("\t pairs of file names must be on the same line\n");
+ printf("\t in the file\n");
+
+ printf("\tDIFFS_FILE - is the file the differences, if any exist,\n");
+ printf("\t between the log files and the known good log\n");
+ printf("\t files will be written to.\n");
+}
+
+
diff --git a/private/ntos/ndis/testprot/tpdrvr/buffer.c b/private/ntos/ndis/testprot/tpdrvr/buffer.c
new file mode 100644
index 000000000..34ac561f8
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpdrvr/buffer.c
@@ -0,0 +1,313 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ buffer.c
+
+Abstract:
+
+ This module implements the buffer manipulation routines for
+ Test Protocol.
+
+Author:
+
+ Tom Adams (tomad) 15-Dec-1990
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ Sanjeev Katariya (sanjeevk) 3-24-1993
+ 1. Added function to free MDL's associated with Data block with the stress block
+ Effected Function: TpStressFreeDataBufferMdls()
+ 2. Changed functions TpStressInitDataBuffer() and TpStressFreeDataBuffers() to
+ handle two data buffer locations
+
+--*/
+
+#include <ndis.h>
+#include "tpdefs.h"
+#include "tpprocs.h"
+
+
+PNDIS_BUFFER
+TpAllocateBuffer(
+ PUCHAR TmpBuf,
+ INT BufSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates an NDIS_BUFFER. An NDIS_BUFFER is merely an
+ MDL that may be chained to other NDIS_BUFFERs to form an MDL chain.
+ This chain contains the actual contents of the NDIS frame that
+ will be sent on the wire. If the size of the buffer to be created
+ is zero, the size is temporarily set to one to be valid for
+ IoAllocateMdl.
+
+Arguments:
+
+ TmpBuf - A pointer to the memory to be placed in the NDIS_BUFFER.
+
+ BufSize - The size of TmpBuf.
+
+Return Value:
+
+ PNDIS_BUFFER - A pointer to the new MDL that references the TmpBuf.
+
+--*/
+
+{
+ PMDL TmpMdl;
+ BOOLEAN Reset;
+
+ Reset = FALSE;
+
+ //
+ // IoAllocateMdl must be called with a positive value for the
+ // buffer size, so if TmpBuf is zero bytes long set the size to
+ // one temporarily.
+ //
+
+ if ( BufSize == 0 ) {
+ BufSize = 1;
+ Reset = TRUE;
+ }
+
+ //
+ // Allocate the MDL and set the various fields.
+ //
+
+ TmpMdl = IoAllocateMdl(
+ TmpBuf,
+ BufSize,
+ TRUE,
+ FALSE,
+ NULL
+ );
+
+ if ( TmpMdl == NULL ) {
+ TpPrint0("TpAllocateBuffer: failed to allocate TmpMdl\n");
+ return (PNDIS_BUFFER)NULL;
+ }
+
+ MmBuildMdlForNonPagedPool( TmpMdl );
+
+ //
+ // if this is to be a zero by NDIS_BUFFER we must reset the MDL.
+ //
+
+ if ( Reset == TRUE ) {
+ TmpMdl->ByteCount = 0;
+ }
+
+ return (PNDIS_BUFFER)TmpMdl;
+}
+
+
+VOID
+TpFreeBuffer(
+ PNDIS_BUFFER Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine simply deallocates the MDL that was built in the routine
+ TpBuildBuffer.
+
+Arguments:
+
+ Buffer - The PNDIS_BUFFER (PMDL) that is to be destroyed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IoFreeMdl( Buffer );
+}
+
+
+VOID
+TpStressInitDataBuffer(
+ POPEN_BLOCK OpenP,
+ INT BufferSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the Data Buffers that will be referenced by
+ all packets as their data. It is twice as long as the maximum packet
+ allowable for the media in question, and contains an ascending sequence
+ of characters from 0x00 to 0xff repeating. This routine also allocates
+ the MDLs which reference these buffers. The MDLs are used by the packet
+ creation routines in the call IoBuildPartialMdl();
+
+Arguments:
+
+ OpenP - The Open Block to allocate the Data Buffer and MDL for.
+
+ BufferSize - The size of the Data Buffer to allocate and initialize.
+
+Return Value:
+
+ None - if successful two DataBuffers and two MDLs are referenced by this Open
+ Block
+
+--*/
+
+{
+ INT i, j;
+
+ //
+ // Allocate the data buffers
+ //
+ NdisAllocateMemory(
+ (PVOID *)&OpenP->Stress->DataBuffer[0],
+ BufferSize,
+ 0,
+ HighestAddress
+ );
+ NdisAllocateMemory(
+ (PVOID *)&OpenP->Stress->DataBuffer[1],
+ BufferSize,
+ 0,
+ HighestAddress
+ );
+
+ //
+ // Verify creation of data buffers
+ //
+ if ( OpenP->Stress->DataBuffer[0] == (PUCHAR)NULL ||
+ OpenP->Stress->DataBuffer[1] == (PUCHAR)NULL ) {
+ TpPrint0("TpStressInitDataBuffer: failed to allocate Data Buffers\n");
+ TpStressFreeDataBuffers( OpenP );
+ return;
+ }
+
+
+ //
+ // Clear the two buffers
+ //
+ NdisZeroMemory( OpenP->Stress->DataBuffer[0],BufferSize );
+ NdisZeroMemory( OpenP->Stress->DataBuffer[1],BufferSize );
+
+
+ //
+ // And now initialize them 0x00 thru 0xff repeating
+ //
+ for ( j = 0; j < MAX_NUMBER_BUFFERS; j++ ) {
+ for ( i=0 ; i < BufferSize ; i++ ) {
+ OpenP->Stress->DataBuffer[j][i] = (UCHAR)(i % 256);
+ }
+ }
+
+ //
+ // Now create the MDLs which reference these two data buffers
+ //
+ OpenP->Stress->DataBufferMdl[0] = (PMDL)TpAllocateBuffer(
+ OpenP->Stress->DataBuffer[0],
+ BufferSize
+ );
+ OpenP->Stress->DataBufferMdl[1] = (PMDL)TpAllocateBuffer(
+ OpenP->Stress->DataBuffer[1],
+ BufferSize
+ );
+ //
+ // Verify creation of the MDLs
+ //
+ if ( OpenP->Stress->DataBufferMdl[0] == NULL ||
+ OpenP->Stress->DataBufferMdl[1] == NULL ) {
+ TpPrint0("TpStressInitDataBuffer: failed to create the DataBufferMdls\n");
+ TpStressFreeDataBuffers( OpenP );
+ TpStressFreeDataBufferMdls( OpenP );
+ }
+
+}
+
+
+
+VOID
+TpStressFreeDataBuffers(
+ POPEN_BLOCK OpenP
+ )
+
+/*++
+
+Routine Description:
+
+ This routine simply frees the DataBuffers
+
+Arguments:
+
+ OpenP - The Open to free the DataBuffers from.
+
+Return Value:
+
+ None - if successful the data buffers are deallocated.
+
+--*/
+
+{
+
+ //
+ // CHANGED: SanjeevK
+ //
+
+ if ( OpenP->Stress->DataBuffer[0] != NULL ) NdisFreeMemory( OpenP->Stress->DataBuffer[0],0,0 );
+ if ( OpenP->Stress->DataBuffer[1] != NULL ) NdisFreeMemory( OpenP->Stress->DataBuffer[1],0,0 );
+
+ OpenP->Stress->DataBuffer[0] = NULL;
+ OpenP->Stress->DataBuffer[1] = NULL;
+
+}
+
+
+VOID
+TpStressFreeDataBufferMdls(
+ POPEN_BLOCK OpenP
+ )
+
+/*++
+
+Routine Description:
+
+ This routines simply frees DataBuffer MDLs.
+
+Arguments:
+
+ OpenP - The Open to free the DataBuffer MDLs from.
+
+Return Value:
+
+ None - if successful the data buffer MDLs are deallocated.
+
+--*/
+
+{
+
+ //
+ // ADDED: SanjeevK
+ //
+ if( OpenP->Stress->DataBufferMdl[0] != (PMDL)NULL )
+ TpFreeBuffer( (PNDIS_BUFFER)OpenP->Stress->DataBufferMdl[0] );
+
+ if( OpenP->Stress->DataBufferMdl[1] != (PMDL)NULL )
+ TpFreeBuffer( (PNDIS_BUFFER)OpenP->Stress->DataBufferMdl[1] );
+
+ OpenP->Stress->DataBufferMdl[0] = NULL;
+ OpenP->Stress->DataBufferMdl[1] = NULL;
+
+}
diff --git a/private/ntos/ndis/testprot/tpdrvr/makefile b/private/ntos/ndis/testprot/tpdrvr/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpdrvr/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/testprot/tpdrvr/media.c b/private/ntos/ndis/testprot/tpdrvr/media.c
new file mode 100644
index 000000000..8bdeff293
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpdrvr/media.c
@@ -0,0 +1,385 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ media.c
+
+Abstract:
+
+ Functions used to determine information about a specific MAC, it's
+ packet size, and other media specifici information.
+
+Author:
+
+ Tom Adams (tomad) 14-Jul-1990
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ Tom Adams (tomad) 03-Jan-1991 Changed to support all MAC types.
+
+ Sanjeev Katariya (sanjeevk) 04-6-1993
+ Added native ARCNET support
+--*/
+
+#include <ndis.h>
+
+#include "tpdefs.h"
+#include "media.h"
+
+//
+// Medium array is used during NdisOpenAdapter to determine the
+// media being supported by the card.
+//
+
+//
+// STARTCHANGE
+//
+NDIS_MEDIUM NdisMediumArray[NDIS_MEDIUM_ARRAY_SIZE] = {
+ NdisMedium802_3,
+ NdisMedium802_5,
+ NdisMediumDix,
+ NdisMediumFddi,
+ NdisMediumArcnet878_2
+};
+//
+// STOPCHANGE
+//
+
+
+NDIS_STATUS
+TpInitMedia(
+ POPEN_BLOCK OpenP,
+ ULONG FrameSize
+ )
+
+/*++
+
+Routine Description:
+
+ TpInitMedia initializes the media data structure with information
+ specific to the media type that will be test on. The information
+ descibes the size of various elements of a packet for the media in
+ question, and is used when creating and destroying packets, etc.
+
+Arguments:
+
+ MediumType - the specific NDIS Media that is being used in this test.
+
+Return Value:
+
+ PTP_MEDIA_INFO - a pointer to the media information structure for
+ the Media being used in this test.
+
+--*/
+
+{
+ NDIS_STATUS Status;
+
+ Status = NdisAllocateMemory(
+ (PVOID *)&OpenP->Media,
+ sizeof( TP_MEDIA_INFO ),
+ 0,
+ HighestAddress
+ );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_RESOURCES )
+ {
+ TpPrint0("TpInitMedia: failed to allocate Media buffer.\n");
+ }
+ return NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( OpenP->Media,sizeof( TP_MEDIA_INFO ) );
+ }
+
+ OpenP->Media->MediumType = NdisMediumArray[OpenP->MediumIndex];
+ OpenP->Media->MaxPacketLen = FrameSize;
+
+ switch( NdisMediumArray[OpenP->MediumIndex] )
+ {
+
+ case NdisMedium802_5: // TokenRing
+
+ OpenP->Media->HeaderSize = TOKENRING_HEADER_SIZE;
+ OpenP->Media->Padding = TOKENRING_PADDING;
+ OpenP->Media->AddressLen = TOKENRING_ADDRESS_LEN;
+ OpenP->Media->DestAddrOffset = TOKENRING_DEST_ADDRESS_OFFSET;
+ OpenP->Media->SrcAddrOffset = TOKENRING_SRC_ADDRESS_OFFSET;
+ break;
+
+ case NdisMedium802_3: // Ethernet
+ case NdisMediumDix:
+
+ OpenP->Media->HeaderSize = ETHERNET_HEADER_SIZE;
+ OpenP->Media->Padding = ETHERNET_PADDING;
+ OpenP->Media->AddressLen = ETHERNET_ADDRESS_LEN;
+ OpenP->Media->DestAddrOffset = ETHERNET_DEST_ADDRESS_OFFSET;
+ OpenP->Media->SrcAddrOffset = ETHERNET_SRC_ADDRESS_OFFSET;
+ break;
+
+ case NdisMediumFddi:
+
+ OpenP->Media->HeaderSize = FDDI_HEADER_SIZE;
+ OpenP->Media->Padding = FDDI_PADDING;
+ OpenP->Media->AddressLen = FDDI_ADDRESS_LEN;
+ OpenP->Media->DestAddrOffset = FDDI_DEST_ADDRESS_OFFSET;
+ OpenP->Media->SrcAddrOffset = FDDI_SRC_ADDRESS_OFFSET;
+ break;
+
+ //
+ // STARTCHANGE
+ //
+
+ case NdisMediumArcnet878_2:
+
+ OpenP->Media->HeaderSize = ARCNET_HEADER_SIZE;
+ OpenP->Media->Padding = ARCNET_PADDING;
+ OpenP->Media->AddressLen = ARCNET_ADDRESS_LEN;
+ OpenP->Media->DestAddrOffset = ARCNET_DEST_ADDRESS_OFFSET;
+ OpenP->Media->SrcAddrOffset = ARCNET_SRC_ADDRESS_OFFSET;
+ break;
+ //
+ // STOPCHANGE
+ //
+
+ default:
+ IF_TPDBG ( TP_DEBUG_RESOURCES )
+ {
+ TpPrint0("TpInitMedia: Invalid media type.\n");
+ }
+
+ return NDIS_STATUS_NOT_SUPPORTED;
+ }
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+BOOLEAN
+TpInitMediaHeader(
+ PFUNC1_PACKET F1Packet,
+ PTP_MEDIA_INFO Media,
+ PUCHAR DestAddr,
+ PUCHAR SrcAddr,
+ INT PacketSize
+ )
+{
+ PUCHAR p;
+ PUCHAR q;
+ USHORT DataSizeShort;
+ SHORT i;
+
+// DestAddr += (ADDRESS_LENGTH - Media->AddressLen);
+// SrcAddr += (ADDRESS_LENGTH - Media->AddressLen);
+
+ switch( Media->MediumType )
+ {
+ case NdisMediumDix:
+ case NdisMedium802_3:
+
+ p = (PUCHAR)&F1Packet->media.e.DestAddress[0];
+ q = (PUCHAR)&F1Packet->media.e.SrcAddress[0];
+
+ for ( i = 0 ; i < Media->AddressLen ; i++ )
+ {
+ *p++ = *DestAddr++;
+ *q++ = *SrcAddr++;
+ }
+
+ DataSizeShort = (USHORT)( PacketSize - Media->HeaderSize );
+
+ F1Packet->media.e.PacketSize_Hi = (UCHAR)( DataSizeShort >> 8 );
+ F1Packet->media.e.PacketSize_Lo = (UCHAR)DataSizeShort;
+
+ break;
+
+
+ case NdisMedium802_5:
+
+ F1Packet->media.tr.AC = 0x10;
+ F1Packet->media.tr.FC = 0x40;
+
+ p = (PUCHAR)&F1Packet->media.tr.DestAddress[0];
+ q = (PUCHAR)&F1Packet->media.tr.SrcAddress[0];
+
+ for ( i = 0 ; i < Media->AddressLen ; i++ )
+ {
+ *p++ = *DestAddr++;
+ *q++ = *SrcAddr++;
+ }
+
+ break;
+
+
+ case NdisMediumFddi:
+
+ F1Packet->media.fddi.FC = 0x57;
+
+ p = (PUCHAR)&F1Packet->media.fddi.DestAddress[0];
+ q = (PUCHAR)&F1Packet->media.fddi.SrcAddress[0];
+
+ for ( i = 0 ; i < Media->AddressLen ; i++ )
+ {
+ *p++ = *DestAddr++;
+ *q++ = *SrcAddr++;
+ }
+
+ break;
+
+ //
+ // STARTCHANGE
+ //
+ case NdisMediumArcnet878_2:
+
+ F1Packet->media.a.ProtocolID = ARCNET_DEFAULT_PROTOCOLID;
+
+ p = (PUCHAR)&F1Packet->media.a.DestAddress[0];
+ q = (PUCHAR)&F1Packet->media.a.SrcAddress[0];
+
+ for ( i = 0 ; i < Media->AddressLen ; i++ )
+ {
+ *p++ = *DestAddr++;
+ *q++ = *SrcAddr++;
+ }
+
+ break;
+ //
+ // STOPCHANGE
+ //
+
+ default:
+ IF_TPDBG ( TP_DEBUG_RESOURCES )
+ {
+ TpPrint0("TpStressInitPacketHeader: Unsupported MAC Type\n");
+ }
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+VOID
+TpInitPoolMediaHeader(
+ PFUNC1_PACKET F1Packet,
+ PTP_MEDIA_INFO Media,
+ PUCHAR DestAddr
+ )
+{
+ USHORT i;
+
+// DestAddr += (ADDRESS_LENGTH - Media->AddressLen);
+
+ switch( Media->MediumType )
+ {
+ case NdisMediumDix:
+ case NdisMedium802_3:
+ for ( i = 0 ; i < (USHORT)Media->AddressLen ; i++ )
+ {
+ F1Packet->media.e.DestAddress[i] = *DestAddr++;
+ }
+ break;
+ case NdisMedium802_5:
+ for ( i = 0 ; i < (USHORT)Media->AddressLen ; i++ )
+ {
+ F1Packet->media.tr.DestAddress[i] = *DestAddr++;
+ }
+ break;
+ case NdisMediumFddi:
+ for ( i = 0 ; i < (USHORT)Media->AddressLen ; i++ )
+ {
+ F1Packet->media.fddi.DestAddress[i] = *DestAddr++;
+ }
+ break;
+ //
+ // STARTCHANGE
+ //
+ case NdisMediumArcnet878_2:
+ for ( i = 0 ; i < (USHORT)Media->AddressLen ; i++ )
+ {
+ F1Packet->media.a.DestAddress[i] = *DestAddr++;
+ }
+ break;
+ //
+ // STOPCHANGE
+ //
+ default:
+ IF_TPDBG ( TP_DEBUG_RESOURCES )
+ {
+ TpPrint0("TpStressSetPoolPacketInfo: Unsupported MAC Type\n");
+ }
+ break;
+ }
+}
+
+
+VOID
+TpInitTruncatedMediaHeader(
+ PFUNC1_PACKET F1Packet,
+ PTP_MEDIA_INFO Media,
+ PUCHAR DestAddr,
+ INT PacketSize
+ )
+{
+ USHORT DataSizeShort;
+ USHORT i;
+
+// DestAddr += (ADDRESS_LENGTH - Media->AddressLen);
+
+ switch( Media->MediumType )
+ {
+ case NdisMediumDix:
+ case NdisMedium802_3:
+
+ DataSizeShort = (USHORT)( PacketSize - Media->HeaderSize );
+
+ F1Packet->media.e.PacketSize_Hi = (UCHAR)( DataSizeShort >> 8 );
+ F1Packet->media.e.PacketSize_Lo = (UCHAR)DataSizeShort;
+
+ for ( i=0;i<(USHORT)Media->AddressLen;i++ )
+ {
+ F1Packet->media.e.DestAddress[i] = *DestAddr++;
+ }
+ break;
+
+ case NdisMedium802_5:
+ for ( i=0;i<(USHORT)Media->AddressLen;i++ )
+ {
+ F1Packet->media.tr.DestAddress[i] = *DestAddr++;
+ }
+ break;
+
+ case NdisMediumFddi:
+ for ( i=0;i<(USHORT)Media->AddressLen;i++ )
+ {
+ F1Packet->media.fddi.DestAddress[i] = *DestAddr++;
+ }
+ break;
+ //
+ // STARTCHANGE
+ //
+ case NdisMediumArcnet878_2:
+ for ( i = 0 ; i < (USHORT)Media->AddressLen ; i++ )
+ {
+ F1Packet->media.a.DestAddress[i] = *DestAddr++;
+ }
+ break;
+ //
+ // STOPCHANGE
+ //
+ default:
+ IF_TPDBG ( TP_DEBUG_RESOURCES )
+ {
+ TpPrint0("TpStressSetTruncatedPacketInfo: Unsupported MAC Type\n");
+ }
+ break;
+ }
+}
diff --git a/private/ntos/ndis/testprot/tpdrvr/media.h b/private/ntos/ndis/testprot/tpdrvr/media.h
new file mode 100644
index 000000000..8bc1e5677
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpdrvr/media.h
@@ -0,0 +1,350 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ media.h
+
+Abstract:
+
+ Functions used to determine information about a specific MAC, it's
+ packet size, and other media specifici information.
+
+Author:
+
+ Tom Adams (tomad) 14-Jul-1990
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ Tom Adams (tomad) 03-Jan-1991 Changed to support all MAC types.
+
+ SanjeevK (sanjeevk) 04-06-1993
+ 1. Added Arcnet support
+
+--*/
+
+//
+// Medium array is used during NdisOpenAdapter to determine the
+// media being supported by the card.
+//
+#define NDIS_MEDIUM_ARRAY_SIZE 5
+
+extern NDIS_MEDIUM NdisMediumArray[NDIS_MEDIUM_ARRAY_SIZE];
+
+//
+// Media Specific Information used to describe the form of a packet and
+// the device being used in this instance.
+//
+// The Media of interest are
+//
+// 802.3
+// 802.5 (TokenRing)
+// FDDI
+// ARCNET
+//
+// No special differentiation will be made between 802.3 and DIX
+//
+
+typedef struct _TP_MEDIA_INFO {
+ NDIS_MEDIUM MediumType; // MAC type being used
+ USHORT HeaderSize; // Packet Header size if (exists)
+ USHORT Padding; // Pad to align TP_PACKET_HEADER
+ USHORT AddressLen; // Address length for the Media
+ USHORT SrcAddrOffset;
+ USHORT DestAddrOffset;
+ ULONG MaxPacketLen; // Maximum packet length for Media
+} TP_MEDIA_INFO, *PTP_MEDIA_INFO;
+
+//
+// Ethernet Specific Information
+//
+// The Ethernet Packet Header is constructed as follows:
+//
+// +------------------------------------------+
+// | Dest | Src | Sz | Data |
+// +------------------------------------------+
+//
+// The Src and Dest fields represent the source and destination addresses
+// and are 6 bytes long each, the Sz field represents represents the size
+// of the Data, and finally there is the Data area itself.
+//
+
+#define ETHERNET_ADDRESS_LEN 6
+
+#define ETHERNET_SRC_ADDRESS_OFFSET ETHERNET_ADDRESS_LEN
+
+#define ETHERNET_DEST_ADDRESS_OFFSET 0
+
+#define ETHERNET_DATASIZE_LEN 2
+
+#define ETHERNET_DATA_LEN 1500
+
+#define ETHERNET_HEADER_SIZE (( ETHERNET_ADDRESS_LEN * 2 ) + \
+ ETHERNET_DATASIZE_LEN )
+
+#define ETHERNET_PACKET_SIZE ( ETHERNET_HEADER_SIZE + \
+ ETHERNET_DATA_LEN )
+
+#define ETHERNET_MIN_DATA_LEN 46
+
+#define ETHERNET_MIN_PACKET_SIZE ( ETHERNET_HEADER_SIZE + \
+ ETHERNET_MIN_DATA_LEN )
+
+#define ETHERNET_PADDING 2
+
+//
+// Default Adapter name to be input from Configuration Manager
+//
+//#define ETHERNET_ADAPTER_NAME "\\device\\elnkii"
+
+//
+// TokenRing Specific Information
+//
+//
+// The Token Ring Packet Header is constructed as follows:
+//
+// +---------------------------------------------------+
+// | AC | FC | Dest | Src | Data |
+// +---------------------------------------------------+
+//
+// The AC and FC fields are used to store tokenring information, each is
+// one byte long. The Src and Dest fields represent the source and
+// destination addresses and are 6 bytes long each, and finally there
+// is the Data area itself.
+//
+
+#define TOKENRING_ACFC_SIZE 2
+
+#define TOKENRING_ADDRESS_LEN 6
+
+#define TOKENRING_SRC_ADDRESS_OFFSET ( TOKENRING_ADDRESS_LEN + \
+ TOKENRING_ACFC_SIZE )
+
+#define TOKENRING_DEST_ADDRESS_OFFSET TOKENRING_ACFC_SIZE
+
+#define TOKENRING_HEADER_SIZE (( TOKENRING_ADDRESS_LEN * 2) + \
+ TOKENRING_ACFC_SIZE )
+
+#define TOKENRING_DATA_LEN ( 8192 - TOKENRING_HEADER_SIZE )
+// 17K if 16MB or 8K if 4MB
+
+#define TOKENRING_PACKET_SIZE ( TOKENRING_HEADER_SIZE + \
+ TOKENRING_DATA_LEN )
+
+#define TOKENRING_PADDING 2
+
+//
+// FDDI Specific Information
+//
+//
+// The FDDI Packet Header is constructed as follows:
+//
+// +----------------------------------------------+
+// | XX | Dest | Src | Data |
+// +----------------------------------------------+
+//
+// The XX field is used to store fddi information, it is one byte
+// long. The Src and Dest fields represent the source and destination
+// addresses and are 6 bytes long each, and finally there is the
+// Data area itself.
+//
+
+#define FDDI_XX_SIZE 1
+
+#define FDDI_ADDRESS_LEN 6
+
+#define FDDI_SRC_ADDRESS_OFFSET ( FDDI_ADDRESS_LEN + FDDI_XX_SIZE )
+
+#define FDDI_DEST_ADDRESS_OFFSET FDDI_XX_SIZE
+
+#define FDDI_HEADER_SIZE (( FDDI_ADDRESS_LEN * 2) + FDDI_XX_SIZE )
+
+#define FDDI_DATA_LEN 8192 // 17K if 16MB or 8K if 4MB
+
+#define FDDI_PACKET_SIZE ( FDDI_HEADER_SIZE + FDDI_DATA_LEN )
+
+#define FDDI_PADDING 2
+
+
+
+//
+// STARTCHANGE
+//
+
+//
+// ARCNET Specific Information
+//
+//
+// The ARCNET Software Packet Header is constructed as follows:
+//
+// +----------------------------------------------------------+
+// | Source | Destination | ProtocolID | Data |
+// +----------------------------------------------------------+
+// 1 1 1 0 - 120*504 or 60480
+//
+// CURRENT ARCNET SOFTWARE HEADER
+//
+// The ARCNET Software Packet Header is constructed as follows:
+//
+// +----------------------------------------------------------+
+// | Source | Destination | ProtocolID | Data |
+// +----------------------------------------------------------+
+// 1 1 1 0 - 3*504 or 1512
+//
+//
+// The Src and Dest fields represent the source and destination
+// addresses and are 1 byte long each. The ProtocolID represent
+// the ID of the protocol communicating with the Arcnet MAC driver
+// And finally there is Data area itself.
+//
+// An actual Arcnet Software packet looks like the following. The current provisions
+// for the native ARCNET driver will be responsible for handling these type internally
+// thereby providing ease of packet exchange between the MAC(N) and the layer above the MAC(N+1)
+//
+// SHORT PACKET (Octet)
+// +---+
+// Source | 1 |
+// +---+
+// Destination | 1 |
+// +---+
+// ByteOffset | 1 |
+// +---------+
+// Unused | 0 - 249 | PACKET CONSTANT LENGTH = 256 octets
+// +---------+ MAXIMUM # of FRAGEMENTS = 120
+// ProcolID | 1 |
+// +---+
+// Split Flag | 1 |
+// +---+---+
+// Seqence # | 2 |
+// +----------+
+// Data | 0 - 249 |
+// +----------+
+//
+// EXCEPTION PACKET (Octet)
+// +---+
+// Source | 1 |
+// +---+
+// Destination | 1 |
+// +---+
+// Long Packet Flag | 1 | = 0
+// +---+
+// ByteOffset | 1 |
+// +-----------+
+// Unused | 248 - 250 | PACKET CONSTANT LENGTH = 512 octets
+// +-----------+ MAXIMUM # of FRAGEMENTS = 120
+// Pad1 ProcolID | 1 |
+// +---+
+// Pad2 Split Flag | 1 | = FF
+// +---+
+// Pad3 | 1 |
+// +---+
+// Pad4 | 1 |
+// +---+
+// ProcolID | 1 |
+// +---+
+// Split Flag | 1 |
+// +---+---+
+// Seqence # | 2 |
+// +-----------+
+// Data | 250 - 252 |
+// +-----------+
+//
+//
+// LONG PACKET (Octet)
+// +---+
+// Source | 1 |
+// +---+
+// Destination | 1 |
+// +---+
+// Long Packet Flag | 1 | = 0
+// +---+
+// ByteOffset | 1 |
+// +---------+
+// Unused | 0 - 251 | PACKET CONSTANT LENGTH = 512 octets
+// +---------+ MAXIMUM # of FRAGEMENTS = 120
+// ProcolID | 1 |
+// +---+
+// Split Flag | 1 |
+// +---+---+
+// Seqence # | 2 |
+// +-----------+
+// Data | 253 - 504 |
+// +-----------+
+//
+// The software packet is further broken down into 5 different categories on the wire
+// The frame formats are:
+//
+// INVITATION TO TRANSMIT (ASCII EOT)
+// FREE BUFFER ENQUIRY (ASCII ENQ)
+// PACKET-DATA (ASCII SOH)
+// ACK (ASCII ACK)
+// NACK (ASCII NAK)
+// The Destination octet is duplicated on the wire, the unused data buffer is not transmitted
+// and a 2 octect CRC is generated with the PACKET-DATA format.
+//
+
+#define ARCNET_ADDRESS_LEN 1
+
+#define ARCNET_SRC_ADDRESS_OFFSET 0
+
+#define ARCNET_DEST_ADDRESS_OFFSET ARCNET_ADDRESS_LEN
+
+#define ARCNET_PROTID_OFFSET ARCNET_DEST_ADDRESS_OFFSET + ARCNET_ADDRESS_LEN
+
+#define ARCNET_PROTID_LEN 1
+
+#define ARCNET_HEADER_SIZE (( ARCNET_ADDRESS_LEN * 2) + ARCNET_PROTID_LEN )
+
+#define ARCNET_DATA_LEN 1512
+
+#define ARCNET_PACKET_SIZE ( ARCNET_HEADER_SIZE + ARCNET_DATA_LEN )
+
+#define ARCNET_MIN_DATA_LEN 0
+
+#define ARCNET_MIN_PACKET_SIZE ( ARCNET_HEADER_SIZE + ARCNET_MIN_DATA_LEN )
+
+#define ARCNET_PADDING 0
+
+//
+// STOPCHANGE
+//
+
+
+//
+// Media Initialization routine.
+//
+
+NDIS_STATUS
+TpInitMedia(
+ POPEN_BLOCK OpenP,
+ ULONG FrameSize
+ );
+
+BOOLEAN
+TpInitMediaHeader(
+ PFUNC1_PACKET F1Packet,
+ PTP_MEDIA_INFO Media,
+ PUCHAR DestAddr,
+ PUCHAR SrcAddr,
+ INT PacketSize
+ );
+
+VOID
+TpInitPoolMediaHeader(
+ PFUNC1_PACKET F1Packet,
+ PTP_MEDIA_INFO Media,
+ PUCHAR DestAddr
+ );
+
+VOID
+TpInitTruncatedMediaHeader(
+ PFUNC1_PACKET F1Packet,
+ PTP_MEDIA_INFO Media,
+ PUCHAR DestAddr,
+ INT PacketSize
+ );
diff --git a/private/ntos/ndis/testprot/tpdrvr/packet.c b/private/ntos/ndis/testprot/tpdrvr/packet.c
new file mode 100644
index 000000000..72a27edef
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpdrvr/packet.c
@@ -0,0 +1,2164 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ packet.c
+
+Abstract:
+
+ simple protocol to test the NDIS wrapper.
+
+Author:
+
+ Tom Adams (tomad) 14-Jul-1990
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ Sanjeev Katariya (sanjeevk) 3-24-1993
+ 1. Corrected TpStressCreatePacket() to allocate the first buffer in a packet of correct
+ size. Added functionality to work with discontiguous physical data(Buffer chains)
+ 2. Changed functions to reflect the data structure change in
+ STRESS_BLOCK
+ a. TpStressCreateTruncatedPacket()
+ b. TpStressSetTruncatedPacketInfo()
+
+--*/
+
+#include <ndis.h>
+#include <stdlib.h>
+
+#include "tpdefs.h"
+#include "media.h"
+#include "tpprocs.h"
+
+
+
+VOID
+TpSetRandom(
+ VOID
+ )
+{
+ LARGE_INTEGER TmpTime;
+
+ //
+ // Uses the system clock to return a random number.
+ // The randomness of the number is subject to some debate.
+ // The time increments in exact intervals; for example on
+ // a 386 it is 300000. We want to shift over enough that
+ // the LSB changes rapidly, but not too much so that we
+ // can only handle a small Range.
+ //
+
+ KeQuerySystemTime( &TmpTime );
+ srand( TmpTime.LowTime >> 10 );
+}
+
+
+UINT
+TpGetRandom(
+ IN UINT Low,
+ IN UINT High
+ )
+{
+ UINT Range = High - Low + 1;
+
+ return (UINT)(( rand() % Range ) + Low );
+}
+
+
+PTP_PACKET
+TpStressInitPacketHeader(
+ IN POPEN_BLOCK OpenP,
+ IN INT TmpBufSize,
+ IN INT PacketSize,
+ IN PUCHAR DestAddr,
+ IN PUCHAR SrcAddr,
+ IN UCHAR DestInstance,
+ IN UCHAR SrcInstance,
+ IN UCHAR PacketProtocol,
+ IN UCHAR ResponseType,
+ IN ULONG DataBufOffset,
+ IN ULONG SequenceNumber,
+ IN ULONG MaxSequenceNumber,
+ IN UCHAR ClientReference,
+ IN UCHAR ServerReference,
+ IN BOOLEAN DataChecking
+ )
+{
+ NDIS_STATUS Status;
+ PTP_PACKET TmpBuffer;
+
+ //
+ // Allocate a buffer to hold the packet header information.
+ //
+
+ Status = NdisAllocateMemory(
+ (PVOID *)&TmpBuffer,
+ TmpBufSize,
+ 0,
+ HighestAddress
+ );
+
+ if ( Status != NDIS_STATUS_SUCCESS ) {
+ IF_TPDBG ( TP_DEBUG_RESOURCES ) {
+ TpPrint0("TpStressInitPacketHeader: failed to allocate TmpBuffer\n");
+ }
+ return NULL;
+ } else {
+ NdisZeroMemory( (PVOID)TmpBuffer,TmpBufSize );
+ }
+
+ //
+ // and stuff the packet header info into it.
+ //
+
+ if ( !TpInitMediaHeader(
+ &TmpBuffer->u.S.hdr,
+ OpenP->Media,
+ DestAddr,
+ SrcAddr,
+ PacketSize
+ )) {
+ NdisFreeMemory( TmpBuffer,0,0 );
+ return NULL;
+ }
+
+ //
+ // initialize the Stress header information.
+ //
+
+ TmpBuffer->u.S.hdr.info.Signature = STRESS_PACKET_SIGNATURE;
+ TmpBuffer->u.S.hdr.info.PacketSize = PacketSize;
+ TmpBuffer->u.S.hdr.info.DestInstance = DestInstance;
+ TmpBuffer->u.S.hdr.info.SrcInstance = SrcInstance;
+ TmpBuffer->u.S.hdr.info.PacketType = STRESS_PACKET_TYPE;
+ TmpBuffer->u.S.hdr.info.u.PacketProtocol = PacketProtocol;
+ TmpBuffer->u.S.hdr.info.CheckSum = 0xFFFFFFFF;
+
+ TmpBuffer->u.S.sc.DataBufOffset = DataBufOffset;
+ TmpBuffer->u.S.sc.SequenceNumber = SequenceNumber;
+ TmpBuffer->u.S.sc.MaxSequenceNumber = MaxSequenceNumber;
+ TmpBuffer->u.S.sc.ResponseType = ResponseType;
+ TmpBuffer->u.S.sc.ClientReference = ClientReference;
+ TmpBuffer->u.S.sc.ServerReference = ServerReference;
+ TmpBuffer->u.S.sc.DataChecking = DataChecking;
+
+ return TmpBuffer;
+}
+
+
+PNDIS_PACKET
+TpStressCreatePacket(
+ IN POPEN_BLOCK OpenP,
+ IN NDIS_HANDLE PacketHandle,
+ IN PACKET_MAKEUP PacketMakeUp,
+ IN UCHAR DestInstance,
+ IN UCHAR SrcInstance,
+ IN UCHAR PacketProtocol,
+ IN UCHAR ResponseType,
+ IN PUCHAR DestAddr,
+ IN INT PacketSize,
+ IN INT BufferSize,
+ IN ULONG SequenceNumber,
+ IN ULONG MaxSequenceNumber,
+ IN UCHAR ClientReference,
+ IN UCHAR ServerReference,
+ IN BOOLEAN DataChecking
+ )
+
+{
+ NDIS_STATUS Status ;
+ PNDIS_PACKET Packet ;
+ PNDIS_BUFFER Buffer ;
+ PPROTOCOL_RESERVED ProtRes ;
+ PUCHAR DataBufOffset1 ;
+ PUCHAR DataBufOffset2 ;
+ PUCHAR TmpBuf ;
+ PUCHAR TmpBufDataOffset ;
+ ULONG RandomOffset ;
+ INT TmpBufSize ;
+ INT TmpBufDataSize ;
+ INT MdlSize ;
+ INT NumBuffers ;
+ INT i ;
+ INT RemainingHdr ;
+ INT RemainingPkt ;
+ BOOLEAN FirstBuffer = TRUE ;
+ BOOLEAN Pulse = TRUE ;
+
+ //
+ // Using a DISCONTIGUOUS allocation scheme in the CLIENT pool case
+ //
+
+ //
+ // Comments : SanjeevK
+ //
+ // BRIEF WORKING
+ //
+ // This function simply allocates a packet from the packet pool and
+ // is reponsible for putting the packet together. The data portion of the
+ // packet is directly used from the the DataBuffers associated with the
+ // stress block. The packet creation is given the option of using
+ // a known buffer size mapping(which generates a definite number of buffers
+ // since the packet size is known) or can simply randomly choose how big
+ // or small it would like to make the buffer sizes. This option is characterized
+ // by the parameter KNOWN.
+ // The packet is created by created an initial header, setting the appropriate fields
+ // and then linking in the data buffers. The total length of the created packet is
+ // controlled by the PacketSize
+ //
+ // The variables and their boundary sizes are given below:
+ //
+ // <-------------------- PacketSize ------------------->[STRESS_PACKET,MAX_PACKET_LENGTH]
+ //
+ // <------ TmpBufSize ---->[STRESS_PACKET,max(2*STRESS_PACKET,PacketSize)]
+ // for PacketMakeUp != KNOWN
+ //
+ // MEDIA_FRAME,PacketSize]
+ //
+ // ----------------------------------------------------
+ // | STRESS_PACKET+ | Additional DATA |
+ // | Random Data Size | |
+ // ----------------------- ----------------------------
+ //
+ // ---.....-----....----....---
+ // | |
+ // |
+ // ---.....-----....----....---
+ //
+ // <-------- BufferSize -------->[MediaHeaderSize, max(STRESS_PACKET,PacketSize)]
+ //
+ //
+
+
+
+ //
+ // Make sure that this is a legal packetsize, and buffersize if
+ // PacketMakeUp = KNOWN, if not use a default smallest or largest
+ // size allowable.
+ //
+ if ( PacketSize < sizeof( STRESS_PACKET )) {
+ PacketSize = sizeof( STRESS_PACKET );
+ } else if ( PacketSize > (INT)OpenP->Media->MaxPacketLen ) {
+ PacketSize = OpenP->Media->MaxPacketLen;
+ }
+
+
+ //
+ // Check the condition for KNOWN packet type.
+ // If TRUE ensure that the BufferSize is between
+ // MediaHeaderSize and max(STRESS_PACKET,PacketSize).
+ //
+ if ( PacketMakeUp == KNOWN ) {
+ if ( BufferSize < OpenP->Media->HeaderSize ) {
+ BufferSize = OpenP->Media->HeaderSize ;
+ } else if ( BufferSize > PacketSize ) {
+ BufferSize = PacketSize;
+ }
+ }
+
+
+
+
+ //
+ // Allocate a PACKET out of the packet pool
+ //
+ NdisAllocatePacket( &Status,&Packet,PacketHandle );
+
+ if ( Status != NDIS_STATUS_SUCCESS ) {
+
+ IF_TPDBG ( TP_DEBUG_RESOURCES ) {
+
+ if( OpenP->Stress->Arguments != NULL ) {
+
+ //
+ // This is the special case where we realize that we will run out
+ // of packets very quickly since the packet pool is 200 only. ONLY
+ // in this case will we not issue a debug message to the screen
+ //
+ if ( (OpenP->Stress->Arguments->WindowEnabled == FALSE ) &&
+ (OpenP->Stress->Arguments->ResponseType == ACK_10_TIMES )
+ ) return NULL;
+
+ }
+
+ TpPrint1("TpStressCreatePacket: NdisAllocatePacket failed %s\n",
+ TpGetStatus( Status ));
+
+ }
+
+ return NULL;
+
+ }
+
+
+ //
+ // Mark the Packet's protocol reserved section to NULL to indicate
+ // that this packet was not allocated from a TP_TRANSMIT_POOL, and set
+ // the InstanceCounters to NULL. TpStressCreateTransmitPool and the
+ // Packet Set Info routines will set them if applicable.
+ //
+
+ ProtRes = PROT_RES( Packet );
+ ProtRes->Pool.TransmitPool = NULL;
+ ProtRes->InstanceCounters = NULL;
+
+ //
+ // Now select the random size of the header buffer which will be used to
+ // hold the Frame Header, the Test Protocol Packet Header, and a random
+ // chunk of the actual frame data.
+ //
+ // TmpBufSize = The random size of the header buffer
+ // where
+ // Header buffer = Frame Header +
+ // Test Protocol Packet Header +
+ // A random chunk of the actual frame data.
+ //
+ //
+ if ( PacketMakeUp != KNOWN ) { // ( PacketMakeUp == RAND|ONES|ZEROS|SMALL )
+
+ //
+ // Sanjeevk : Comment
+ //
+ // The TmpBufSize being within the bounds, STRESS_PACKET and 2*STRESS_PACKET
+ // will quite comfortably accomodate the MEDIA_HEADER. This restriction must
+ // be followed closely since this is the first buffer in the packet chain
+ //
+
+ TmpBufSize = TpGetRandom(
+ sizeof( STRESS_PACKET ),
+ ( 2 * sizeof( STRESS_PACKET ))
+ );
+
+ if ( TmpBufSize > PacketSize ) {
+ TmpBufSize = PacketSize;
+ }
+
+
+ } else {
+
+ //
+ // Packet_MakeUp is KNOWN, i.e. we can calculate the number of buffers
+ // from the size of the packet and the given buffersize
+ // We must however determine the number of buffers that
+ // will fit in the TP_PACKET_HEADER section of the packet, and how
+ // large that header will actually be.
+ //
+ // At this point BufferSize is between MediaHeaderSize
+ // and max(PacketSize,STRESS_PACKET)
+ //
+ if ( BufferSize >= sizeof( STRESS_PACKET ) ) {
+
+ //
+ // If the BufferSize is greater than the size needed to fit the
+ // packet header then we will just allocate one chunk of memory
+ // of that size, and tack on some additional data at the the end.
+ //
+
+ TmpBufSize = BufferSize;
+ RemainingPkt = PacketSize % BufferSize;
+ RemainingHdr = 0;
+ NumBuffers = 1;
+
+ } else {
+
+ //
+ // The BufferSize is smaller that then packet header, so we must
+ // determine the number of buffers that will fit in the header,
+ // and, if there is any remainder, how big it is.
+ //
+
+ NumBuffers = sizeof( STRESS_PACKET ) / BufferSize;
+ RemainingHdr = sizeof( STRESS_PACKET ) % BufferSize;
+ RemainingPkt = PacketSize % BufferSize;
+
+ //
+ // There are three possible cases here that must be handled.
+ //
+ // 1) only X buffers are needed to create the packet header
+ //
+ // 2) X buffers, and a remainder buffer are needed to create the
+ // packet header.
+ // a) the remainder is the rest of the actual packet.
+ //
+ // b) the remainder is the rest of the header. (and the
+ // packet)
+ //
+ // [-------------------------------------]
+ // packet header
+ //
+ // 1) [---------][---------][- -][---------]
+ // buf_1 buf_2 ... buf_X
+ //
+ // 2a) [-------][-------][- -][-------][--------------]
+ // buf_1 buf_2 ... buf_X remaining packet
+ //
+ // 2b) [-------][-------][- -][-------][---]
+ // buf_1 buf_2 ... buf_X remaining header
+ //
+
+ if (((NumBuffers+1) * BufferSize) <= PacketSize ) {
+
+ //
+ // The packet header can fit in NumBuffers+1 buffers.
+ //
+
+ TmpBufSize = (( NumBuffers + 1 ) * BufferSize );
+ NumBuffers++;
+ RemainingHdr = 0;
+
+ } else if ((( NumBuffers * BufferSize ) + RemainingPkt ) == PacketSize ) {
+
+ //
+ // The packet header can fit in a NumBuffers buffers plus the
+ // remainder of the packet. This is the entire packet.
+ //
+
+ TmpBufSize = ( NumBuffers * BufferSize ) + RemainingPkt ;
+ RemainingHdr = RemainingPkt;
+ RemainingPkt = 0;
+
+ } else {
+
+ //
+ // The packet header can fit in a NumBuffers buffers plus the
+ // remainder of the header. This is the entire packet.
+ //
+
+ TmpBufSize = (( NumBuffers * BufferSize ) + RemainingHdr );
+ TP_ASSERT( RemainingHdr != RemainingPkt );
+ RemainingPkt = 0;
+ }
+ }
+ }
+
+ RandomOffset = TpGetRandom( 0,OpenP->Media->MaxPacketLen );
+
+ TmpBuf = (PUCHAR)TpStressInitPacketHeader(
+ OpenP,
+ TmpBufSize,
+ PacketSize,
+ DestAddr,
+ OpenP->StationAddress,
+ DestInstance,
+ SrcInstance,
+ PacketProtocol,
+ ResponseType,
+ RandomOffset,
+ SequenceNumber,
+ MaxSequenceNumber,
+ ClientReference,
+ ServerReference,
+ DataChecking
+ );
+
+ if ( TmpBuf == NULL ) {
+ IF_TPDBG ( TP_DEBUG_RESOURCES ) {
+ TpPrint0("TpStressCreatePacket: failed to initialize Packet Header\n");
+ }
+ return NULL;
+ }
+
+ ((PTP_PACKET)TmpBuf)->u.S.sc.CheckSum =
+
+ TpSetCheckSum(
+ (PUCHAR)&((PTP_PACKET)TmpBuf)->u.S.hdr.info,
+ sizeof( STRESS_PACKET ) -
+// ( sizeof( ULONG ) + OpenP->Media->HeaderSize )
+ ( sizeof(ULONG) + sizeof(MEDIA_HEADER))
+ );
+
+ //
+ // Now setup the remainder of TmpBuf with a random amount of data
+ // from the data buffer.
+ //
+ // DataBufOffset1,2 is the random offset into the data buffer that will be
+ // used to fill the packet.
+ //
+
+ DataBufOffset1 = OpenP->Stress->DataBuffer[0] + RandomOffset;
+ DataBufOffset2 = OpenP->Stress->DataBuffer[1] + RandomOffset;
+
+ //
+ // TmpBufDataSize is the remainder of the TmpBuf that will be filled with
+ // data from the DataBuf
+ //
+
+ TmpBufDataSize = TmpBufSize - sizeof( STRESS_PACKET );
+
+ if ( TmpBufDataSize > 0 ) {
+
+ TmpBufDataOffset = TmpBuf + sizeof( STRESS_PACKET );
+
+ RtlMoveMemory(
+ TmpBufDataOffset,
+ DataBufOffset1,
+ TmpBufDataSize
+ );
+
+ DataBufOffset1 += TmpBufDataSize;
+ DataBufOffset2 += TmpBufDataSize;
+
+ } else {
+ TP_ASSERT( TmpBufDataSize >= 0 );
+ }
+
+
+ //
+ // Sanjeevk : Comment
+ //
+ // We now simply proceed to create the packet. We start of by using the TmpBuf we created
+ // and forming the header and then tack on the data buffer we allocated. MDL's are allocated
+ // as we go thru the data portions
+ //
+ // NOTE: To make the data discontiguous, we are using the following sheme
+ //
+ // We have allocated two data buffers and filled them in with identical contents
+ //
+ // LOC.A
+ // --------------------------------
+ // BUFFER 1 | 00 01 02 03 .....FF 00 01 ..... |
+ // --------------------------------
+ // LOC.B
+ // ---------------------------------
+ // BUFFER 2 | 00 01 02 03 .....FF 00 01 ..... |
+ // ---------------------------------
+ // ^
+ // |
+ // COMMON OFFSET
+ // We now maintain a common offset into both buffers and simply switch between the two
+ // locations.
+ //
+ // LOGIC
+ // 1. Get location A at COMMON OFFSET from buffer 1. Take length Y. Obtain a MDL
+ // and chain than buffer onto the packet
+ // 2. Increment the COMMON OFFSET by length Y
+ // 3. Get location B at COMMON OFFSET from buffer 2. Take length X. Obtain a MDL
+ // and chain than buffer onto the packet
+ // 4. Increment the COMMON OFFSET by length X
+ // 5. Repeat steps 1,2,3 and 4 till you have reached the end of the total packet
+ // length to be mapped(ie. incremental length = 0 )
+ //
+ // This makes the data verification an easy process since the sequence of data bytes
+ // stays the same although now the data areas are no longer contiguous.
+ //
+ switch( PacketMakeUp ) {
+
+ case RAND:
+
+ //
+ // Slice up the TmpBuf containing the Frame Header and the
+ // TP_PACKET_HEADER, and create the beginning of the PACKET.
+ //
+
+ while ( TmpBufSize > 0 ) {
+
+ MdlSize = TpGetRandom(
+ 0,
+ OpenP->Media->MaxPacketLen /
+ ( 2 * OpenP->Environment->RandomBufferNumber )
+ );
+
+ if ( MdlSize > TmpBufSize ) {
+ MdlSize = TmpBufSize;
+ }
+
+
+ //
+ // STARTCHANGE
+ //
+ //
+ // Ensure that the first buffer in the packet has length >= size
+ // of the media header. This is an NDIS 3.0 requirement for
+ // the sake of maintaining performance
+ //
+ if ( FirstBuffer ) {
+ if ( MdlSize < OpenP->Media->HeaderSize ) {
+ MdlSize = OpenP->Media->HeaderSize;
+ }
+ FirstBuffer = FALSE;
+ }
+ //
+ // STOPCHANGE
+ //
+
+ Buffer = TpAllocateBuffer( TmpBuf,MdlSize );
+
+ if ( Buffer == NULL ) {
+ IF_TPDBG ( TP_DEBUG_RESOURCES ) {
+ TpPrint0("TpStressCreatePacket: failed to create the MDL\n");
+ }
+ TpStressFreePacket( Packet );
+ return NULL;
+ }
+
+ NdisChainBufferAtBack( Packet,Buffer );
+
+ TmpBuf += MdlSize;
+ TmpBufSize -= MdlSize;
+ PacketSize -= MdlSize;
+ }
+
+ //
+ // Now convert the data section of the into NDIS_BUFFERs and add to the
+ // end of the PACKET.
+ //
+
+ while ( PacketSize > 0 ) {
+
+ MdlSize = TpGetRandom(
+ 0,
+ OpenP->Media->MaxPacketLen /
+ ( 2 * OpenP->Environment->RandomBufferNumber )
+ );
+
+ if ( MdlSize > PacketSize ) {
+ MdlSize = PacketSize;
+ }
+
+ //
+ // Using DISCONTIGUITY
+ //
+ if ( Pulse ) {
+ Buffer = TpAllocateBuffer( DataBufOffset1,MdlSize );
+ Pulse = FALSE;
+ } else {
+ Buffer = TpAllocateBuffer( DataBufOffset2,MdlSize );
+ Pulse = TRUE;
+ }
+
+
+ if ( Buffer == NULL ) {
+ IF_TPDBG ( TP_DEBUG_RESOURCES ) {
+ TpPrint0("TpStressCreatePacket: failed to create the MDL\n");
+ }
+ TpStressFreePacket( Packet );
+ return NULL;
+ }
+
+ NdisChainBufferAtBack( Packet,Buffer );
+
+ PacketSize -= MdlSize;
+ DataBufOffset1 += (ULONG)MdlSize;
+ DataBufOffset2 += (ULONG)MdlSize;
+ }
+ break;
+
+ case ZEROS:
+
+ //
+ // Slice up the TmpBuf containing the Frame Header and the
+ // TP_PACKET_HEADER, and create the beginning of the PACKET.
+ //
+
+ while (TmpBufSize > 0) {
+
+ if ( ( MdlSize = TpGetRandom( 0,3 ) ) != 0 ) {
+ MdlSize = TpGetRandom(
+ 0,
+ OpenP->Media->MaxPacketLen /
+ ( 2 * OpenP->Environment->RandomBufferNumber )
+ );
+ }
+ if ( MdlSize > TmpBufSize ) {
+ MdlSize = TmpBufSize;
+ }
+ //
+ // STARTCHANGE
+ //
+ //
+ // Ensure that the first buffer in the pakcet has length >= size
+ // of the media header. This is an NDIS 3.0 requirement for
+ // the sake of maintaining performance
+ //
+ if ( FirstBuffer ) {
+ if ( MdlSize < OpenP->Media->HeaderSize ) {
+ MdlSize = OpenP->Media->HeaderSize;
+ }
+ FirstBuffer = FALSE;
+ }
+ //
+ // STOPCHANGE
+ //
+ Buffer = TpAllocateBuffer( TmpBuf,MdlSize );
+
+ if ( Buffer == NULL ) {
+ IF_TPDBG ( TP_DEBUG_RESOURCES ) {
+ TpPrint0("TpStressCreatePacket: failed to create the MDL\n");
+ }
+ TpStressFreePacket( Packet );
+ return NULL;
+ }
+
+ NdisChainBufferAtBack( Packet,Buffer );
+
+ TmpBuf += MdlSize;
+ TmpBufSize -= MdlSize;
+ PacketSize -= MdlSize;
+ }
+
+ //
+ // Now convert the data section of the into NDIS_BUFFERs and add to the
+ // end of the PACKET.
+ //
+
+ while ( PacketSize > 0 ) {
+
+ if ( ( MdlSize = TpGetRandom( 0,3 ) ) != 0 ) {
+ MdlSize = TpGetRandom(
+ 0,
+ OpenP->Media->MaxPacketLen /
+ ( 2 * OpenP->Environment->RandomBufferNumber )
+ );
+ }
+
+ if ( MdlSize > PacketSize ) {
+ MdlSize = PacketSize;
+ }
+
+
+ //
+ // Using DISCONTIGUITY
+ //
+ if ( Pulse ) {
+ Buffer = TpAllocateBuffer( DataBufOffset1,MdlSize );
+ Pulse = FALSE;
+ } else {
+ Buffer = TpAllocateBuffer( DataBufOffset2,MdlSize );
+ Pulse = TRUE;
+ }
+
+
+ if ( Buffer == NULL ) {
+ IF_TPDBG ( TP_DEBUG_RESOURCES ) {
+ TpPrint0("TpStressCreatePacket: failed to create the MDL\n");
+ }
+ TpStressFreePacket( Packet );
+ return NULL;
+ }
+
+ NdisChainBufferAtBack( Packet,Buffer );
+
+ PacketSize -= MdlSize;
+ DataBufOffset1 += (ULONG)MdlSize;
+ DataBufOffset2 += (ULONG)MdlSize;
+ }
+ break;
+
+ case ONES:
+
+ //
+ // Slice up the TmpBuf containing the Frame Header and the
+ // TP_PACKET_HEADER, and create the beginning of the PACKET.
+ //
+
+ while ( TmpBufSize > 0 ) {
+
+ if ( ( MdlSize = TpGetRandom( 0,3 ) ) != 1 ) {
+ MdlSize = TpGetRandom(
+ 0,
+ OpenP->Media->MaxPacketLen /
+ ( 2 * OpenP->Environment->RandomBufferNumber )
+ );
+ }
+ if ( MdlSize > TmpBufSize ) {
+ MdlSize = TmpBufSize;
+ }
+
+ //
+ // STARTCHANGE
+ //
+ //
+ // Ensure that the first buffer in the pakcet has length >= size
+ // of the media header. This is an NDIS 3.0 requirement for
+ // the sake of maintaining performance
+ //
+ if ( FirstBuffer ) {
+ if ( MdlSize < OpenP->Media->HeaderSize ) {
+ MdlSize = OpenP->Media->HeaderSize;
+ }
+ FirstBuffer = FALSE;
+ }
+ //
+ // STOPCHANGE
+ //
+
+ Buffer = TpAllocateBuffer( TmpBuf,MdlSize );
+
+ if ( Buffer == NULL ) {
+ IF_TPDBG ( TP_DEBUG_RESOURCES ) {
+ TpPrint0("TpStressCreatePacket: failed to create the MDL\n");
+ }
+ TpStressFreePacket( Packet );
+ return NULL;
+ }
+
+ NdisChainBufferAtBack( Packet,Buffer );
+
+ TmpBuf += MdlSize;
+ TmpBufSize -= MdlSize;
+ PacketSize -= MdlSize;
+ }
+
+ //
+ // Now convert the data section of the into NDIS_BUFFERs and add to the
+ // end of the PACKET.
+ //
+
+ while ( PacketSize > 0 ) {
+
+ if ( ( MdlSize = TpGetRandom( 0,3 ) ) != 1 ) {
+ MdlSize = TpGetRandom(
+ 0,
+ OpenP->Media->MaxPacketLen /
+ ( 2 * OpenP->Environment->RandomBufferNumber )
+ );
+ }
+
+ if ( MdlSize > PacketSize ) {
+ MdlSize = PacketSize;
+ }
+
+ //
+ // Using DISCONTIGUITY
+ //
+ if ( Pulse ) {
+ Buffer = TpAllocateBuffer( DataBufOffset1,MdlSize );
+ Pulse = FALSE;
+ } else {
+ Buffer = TpAllocateBuffer( DataBufOffset2,MdlSize );
+ Pulse = TRUE;
+ }
+
+ if ( Buffer == NULL ) {
+ IF_TPDBG ( TP_DEBUG_RESOURCES ) {
+ TpPrint0("TpStressCreatePacket: failed to create the MDL\n");
+ }
+ TpStressFreePacket( Packet );
+ return NULL;
+ }
+
+ NdisChainBufferAtBack( Packet,Buffer );
+
+ PacketSize -= MdlSize;
+ DataBufOffset1 += (ULONG)MdlSize;
+ DataBufOffset2 += (ULONG)MdlSize;
+
+ }
+ break;
+
+ case SMALL:
+
+ //
+ // Slice up the TmpBuf containing the Frame Header and the
+ // TP_PACKET_HEADER, and create the beginning of the PACKET.
+ //
+
+ while ( TmpBufSize > 0 ) {
+
+ MdlSize = TpGetRandom( 0,OpenP->Media->MaxPacketLen/50 );
+
+ if ( MdlSize > TmpBufSize ) {
+ MdlSize = TmpBufSize;
+ }
+
+ //
+ // STARTCHANGE
+ //
+ //
+ // Ensure that the first buffer in the pakcet has length >= size
+ // of the media header. This is an NDIS 3.0 requirement for
+ // the sake of maintaining performance
+ //
+ if ( FirstBuffer ) {
+ if ( MdlSize < OpenP->Media->HeaderSize ) {
+ MdlSize = OpenP->Media->HeaderSize;
+ }
+ FirstBuffer = FALSE;
+ }
+ //
+ // STOPCHANGE
+ //
+
+ Buffer = TpAllocateBuffer( TmpBuf,MdlSize );
+
+ if ( Buffer == NULL ) {
+ IF_TPDBG ( TP_DEBUG_RESOURCES) {
+ TpPrint0("TpStressCreatePacket: failed to create the MDL\n");
+ }
+ TpStressFreePacket( Packet );
+ return NULL;
+ }
+
+ NdisChainBufferAtBack( Packet,Buffer );
+
+ TmpBuf += MdlSize;
+ TmpBufSize -= MdlSize;
+ PacketSize -= MdlSize;
+ }
+
+ //
+ // Now convert the data section of the into NDIS_BUFFERs and add to the
+ // end of the PACKET.
+ //
+
+ while ( PacketSize > 0 ) {
+
+ MdlSize = TpGetRandom( 0,OpenP->Media->MaxPacketLen/50 );
+
+ if ( MdlSize > PacketSize ) {
+ MdlSize = PacketSize;
+ }
+
+ //
+ // Using DISCONTIGUITY
+ //
+ if ( Pulse ) {
+ Buffer = TpAllocateBuffer( DataBufOffset1,MdlSize );
+ Pulse = FALSE;
+ } else {
+ Buffer = TpAllocateBuffer( DataBufOffset2,MdlSize );
+ Pulse = TRUE;
+ }
+
+ if ( Buffer == NULL ) {
+ IF_TPDBG ( TP_DEBUG_RESOURCES ) {
+ TpPrint0("TpStressCreatePacket: failed to create the MDL\n");
+ }
+ TpStressFreePacket( Packet );
+ return NULL;
+ }
+
+ NdisChainBufferAtBack( Packet,Buffer );
+
+ PacketSize -= MdlSize;
+ DataBufOffset1 += (ULONG)MdlSize;
+ DataBufOffset2 += (ULONG)MdlSize;
+ }
+ break;
+
+ case KNOWN:
+
+
+ for ( i=0;i<NumBuffers;i++ ) {
+
+ Buffer = TpAllocateBuffer( TmpBuf,BufferSize );
+
+ if ( Buffer == NULL ) {
+ IF_TPDBG ( TP_DEBUG_RESOURCES ) {
+ TpPrint0("TpStressCreatePacket: failed to create the MDL\n");
+ }
+ TpStressFreePacket( Packet );
+ return NULL;
+ }
+
+ NdisChainBufferAtBack( Packet,Buffer );
+
+ TmpBuf += BufferSize;
+ PacketSize -= BufferSize;
+ }
+
+ if ( RemainingHdr > 0 ) {
+
+ Buffer = TpAllocateBuffer( TmpBuf,RemainingHdr );
+
+ if ( Buffer == NULL ) {
+ IF_TPDBG ( TP_DEBUG_RESOURCES ) {
+ TpPrint0("TpStressCreatePacket: failed to create the MDL\n");
+ }
+ TpStressFreePacket( Packet );
+ return NULL;
+ }
+
+ NdisChainBufferAtBack( Packet,Buffer );
+
+ PacketSize -= RemainingHdr;
+ }
+
+ if ( PacketSize > 0 ) {
+
+ //
+ // Determine the number of remaining buffers, and if it exists,
+ // the size of the last buffer.
+ //
+
+ NumBuffers = PacketSize / BufferSize;
+
+ for (i=0;i<NumBuffers;i++ ) {
+
+ //
+ // Using DISCONTIGUITY
+ //
+ if ( Pulse ) {
+ Buffer = TpAllocateBuffer( DataBufOffset1,BufferSize );
+ Pulse = FALSE;
+ } else {
+ Buffer = TpAllocateBuffer( DataBufOffset2,BufferSize );
+ Pulse = TRUE;
+ }
+
+ if ( Buffer == NULL ) {
+ IF_TPDBG ( TP_DEBUG_RESOURCES ) {
+ TpPrint0("TpStressCreatePacket: failed to create the MDL\n");
+ }
+ TpStressFreePacket( Packet );
+ return NULL;
+ }
+
+ NdisChainBufferAtBack( Packet,Buffer );
+
+ DataBufOffset1 += (ULONG)BufferSize;
+ DataBufOffset2 += (ULONG)BufferSize;
+ }
+
+ if ( RemainingPkt > 0 ) {
+
+ //
+ // Using DISCONTIGUITY
+ //
+ if ( Pulse ) {
+ Buffer = TpAllocateBuffer( DataBufOffset1,RemainingPkt );
+ Pulse = FALSE;
+ } else {
+ Buffer = TpAllocateBuffer( DataBufOffset2,RemainingPkt );
+ Pulse = TRUE;
+ }
+
+ if ( Buffer == NULL ) {
+ IF_TPDBG ( TP_DEBUG_RESOURCES ) {
+ TpPrint0("TpStressCreatePacket: failed to create the MDL\n");
+ }
+ TpStressFreePacket( Packet );
+ return NULL;
+ }
+
+ NdisChainBufferAtBack( Packet,Buffer );
+ }
+ }
+ break;
+
+ default:
+ IF_TPDBG ( TP_DEBUG_RESOURCES ) {
+ TpPrint0("TpStressCreatePacket: unknown packet makeup\n");
+ }
+ return NULL;
+ }
+ return Packet;
+}
+
+
+PNDIS_PACKET
+TpStressCreateTruncatedPacket(
+ IN POPEN_BLOCK OpenP,
+ IN NDIS_HANDLE PacketHandle,
+ IN UCHAR PacketProtocol,
+ IN UCHAR ResponseType
+ )
+{
+ NDIS_STATUS Status;
+ PNDIS_PACKET Packet;
+ PNDIS_BUFFER Buffer;
+ PUCHAR TmpBuf;
+ PPROTOCOL_RESERVED ProtRes;
+
+ //
+ // Using a CONTIGUOUS allocation scheme in the SERVER pool
+ //
+ NdisAllocatePacket( &Status,&Packet,PacketHandle );
+
+ if ( Status != NDIS_STATUS_SUCCESS ) {
+ IF_TPDBG ( TP_DEBUG_RESOURCES ) {
+ TpPrint1("TpStressCreatePacket: NdisAllocatePacket failed %s\n",
+ TpGetStatus( Status ));
+ }
+ return NULL;
+ }
+
+ //
+ // Mark the Protocol's reserved section to NULL to indicate that
+ // this packet was not allocated from a TP_TRANSMIT_POOL, and set
+ // the InstanceCounters to NULL. TpStressCreateTransmitPool and the
+ // Packet Set Info routines will set them if applicable.
+ //
+
+ ProtRes = PROT_RES( Packet );
+ ProtRes->Pool.TransmitPool = NULL;
+ ProtRes->InstanceCounters = NULL;
+
+ TmpBuf = (PUCHAR)TpStressInitPacketHeader(
+ OpenP,
+ ( 2 * sizeof( STRESS_PACKET ) ),
+ sizeof( STRESS_PACKET ),
+ NULL_ADDRESS,
+ OpenP->StationAddress,
+ 0, //DestInstance
+ 0, //SrcInstance
+ PacketProtocol,
+ ResponseType,
+ 0, //RandomOffset
+ 0L, //SequenceNumber
+ 0L, //MaxSequenceNumber
+ 0, //ClientReference
+ 0, //ServerReference
+ FALSE // DataChecking
+ );
+
+ if ( TmpBuf == NULL ) {
+ IF_TPDBG ( TP_DEBUG_RESOURCES ) {
+ TpPrint0("TpStressCreateTruncatedPacket: failed to initialize Packet Header\n");
+ }
+ return NULL;
+ }
+
+ Buffer = TpAllocateBuffer( TmpBuf,sizeof( STRESS_PACKET ) );
+
+ if ( Buffer == NULL ) {
+ IF_TPDBG ( TP_DEBUG_RESOURCES ) {
+ TpPrint0("TpStressCreatePacket: failed to create the MDL\n");
+ }
+ TpStressFreePacket( Packet );
+ return NULL;
+ }
+
+ NdisChainBufferAtBack( Packet,Buffer );
+
+ Buffer = TpAllocateBuffer(
+ OpenP->Stress->DataBuffer[0],
+ OpenP->Media->MaxPacketLen*2
+ );
+
+ if ( Buffer == NULL ) {
+ IF_TPDBG ( TP_DEBUG_RESOURCES ) {
+ TpPrint0("TpStressCreatePacket: failed to create the MDL\n");
+ }
+ TpStressFreePacket( Packet );
+ return NULL;
+ }
+
+ NdisChainBufferAtBack( Packet,Buffer );
+
+ //
+ // STOPCHANGE
+ //
+
+ return Packet;
+}
+
+
+ULONG
+TpGetPacketSignature(
+ IN PNDIS_PACKET Packet
+ )
+
+{
+ NDIS_STATUS Status;
+ PUCHAR TmpBuf;
+ PUCHAR TmpBuf1;
+ UINT TmpBufSize = sizeof( STRESS_PACKET );
+ PNDIS_BUFFER Buffer;
+ PUCHAR Memory;
+ UINT MemoryLength;
+ ULONG Signature;
+ BOOLEAN GotWholeTpPacket;
+
+ if ( Packet == NULL ) {
+ return 0xffffffff;
+ }
+
+ Status = NdisAllocateMemory(
+ (PVOID *)&TmpBuf,
+ TmpBufSize,
+ 0,
+ HighestAddress
+ );
+
+ if ( Status != NDIS_STATUS_SUCCESS ) {
+ IF_TPDBG ( TP_DEBUG_RESOURCES ) {
+ TpPrint0("TpGetPacketSignature: unable to allocate tmp buffer\n");
+ }
+ return 0xffffffff;
+ } else {
+ NdisZeroMemory( TmpBuf,TmpBufSize );
+ }
+
+ TmpBuf1 = TmpBuf;
+
+ NdisQueryPacket( Packet,NULL,NULL,&Buffer,NULL );
+
+ GotWholeTpPacket = FALSE;
+
+ while ( Buffer != NULL ) {
+
+ NdisQueryBuffer(
+ Buffer,
+ (PVOID *)&Memory,
+ &MemoryLength
+ );
+
+ if ( MemoryLength > TmpBufSize ) {
+ MemoryLength = TmpBufSize;
+ }
+
+ RtlMoveMemory( TmpBuf1,Memory,MemoryLength );
+
+ TmpBufSize -= MemoryLength;
+ TmpBuf1 += MemoryLength;
+
+ if (TmpBufSize == 0 ) {
+ GotWholeTpPacket = TRUE;
+ break;
+ }
+
+ NdisGetNextBuffer( Buffer,&Buffer );
+ }
+
+ if ( GotWholeTpPacket == TRUE ) {
+ Signature = ((PSTRESS_PACKET)TmpBuf)->hdr.info.Signature;
+ } else {
+ Signature = 0xffffffff;
+ }
+
+ NdisFreeMemory( TmpBuf,0,0 );
+
+ return Signature;
+}
+
+
+VOID
+TpStressFreePacket(
+ IN PNDIS_PACKET Packet
+ )
+{
+ PNDIS_BUFFER HeadBuffer;
+ PNDIS_BUFFER Buffer;
+ PPROTOCOL_RESERVED ProtRes;
+
+
+ if ( Packet == NULL ) {
+ return;
+ }
+
+ NdisUnchainBufferAtFront( Packet,&HeadBuffer );
+
+ if ( HeadBuffer != NULL ) {
+
+ NdisUnchainBufferAtFront( Packet,&Buffer );
+
+ while ( Buffer != NULL ) {
+ TpFreeBuffer( Buffer );
+ NdisUnchainBufferAtFront( Packet,&Buffer );
+ }
+
+ //
+ // Due to the method used to create the header buffer this
+ // size is now invalid, but will work.
+ //
+
+ HeadBuffer->ByteCount = ( sizeof( STRESS_PACKET ) * 2 );
+
+ NdisFreeMemory( MmGetMdlVirtualAddress( HeadBuffer ),0,0 );
+
+ TpFreeBuffer( HeadBuffer );
+ }
+
+ ProtRes = PROT_RES( Packet );
+
+ ProtRes->Pool.TransmitPool = NULL;
+ ProtRes->InstanceCounters = NULL;
+
+ NdisFreePacket( Packet );
+
+ Packet = NULL;
+}
+
+
+PTP_TRANSMIT_POOL
+TpStressCreateTransmitPool(
+ IN POPEN_BLOCK OpenP,
+ IN NDIS_HANDLE PacketHandle,
+ IN PACKET_MAKEUP PacketMakeUp,
+ IN UCHAR PacketProtocol,
+ IN UCHAR ResponseType,
+ IN INT PacketSize,
+ IN INT NumPackets,
+ IN BOOLEAN ServerPool
+ )
+{
+ NDIS_STATUS Status;
+ PTP_TRANSMIT_POOL TmpPool;
+ PNDIS_PACKET Packet;
+ PPROTOCOL_RESERVED ProtRes;
+ ULONG SequenceNumber = 0;
+ ULONG MaxSequenceNumber = 0;
+ INT NextPacketSize;
+ INT i;
+ UCHAR DestInstance = 0;
+ UCHAR SrcInstance = 0;
+ UCHAR ClientReference = 0;
+ UCHAR ServerReference = 0;
+
+ //
+ // Allocate the Packet Pool Structure
+ //
+
+ Status = NdisAllocateMemory(
+ (PVOID *)&TmpPool,
+ sizeof( TP_TRANSMIT_POOL ),
+ 0,
+ HighestAddress
+ );
+
+ if ( Status != NDIS_STATUS_SUCCESS ) {
+ IF_TPDBG ( TP_DEBUG_RESOURCES ) {
+ TpPrint0("TpStressCreateTransmitPool: failed to allocate TmpPool\n");
+ }
+ return NULL;
+ } else {
+ NdisZeroMemory( TmpPool,sizeof( TP_TRANSMIT_POOL ));
+ }
+
+ //
+ // and allocate it's SpinLock
+ //
+
+ TmpPool->SpinLockAllocated = FALSE;
+
+ NdisAllocateSpinLock( &TmpPool->SpinLock );
+
+ TmpPool->SpinLockAllocated = TRUE;
+
+ //
+ // Set the Packet Pool Chain to empty
+ //
+
+ TmpPool->Head = NULL;
+ TmpPool->Tail = NULL;
+
+ for ( i=0;i<NumPackets-1;i++ ) {
+
+ if ( ServerPool == TRUE ) {
+
+ Packet = TpStressCreateTruncatedPacket(
+ OpenP,
+ PacketHandle,
+ PacketProtocol,
+ ResponseType
+ );
+ } else {
+
+ if ( OpenP->Stress->Arguments->PacketType == RANDOMSIZE ) {
+
+ NextPacketSize = TpGetRandom(
+ sizeof( STRESS_PACKET ),
+ PacketSize
+ );
+
+ } else { // ( OpenP->Arguments->Packet_Size == FIXEDSIZE )
+
+ NextPacketSize = PacketSize;
+ }
+
+ Packet = TpStressCreatePacket(
+ OpenP,
+ PacketHandle,
+ PacketMakeUp,
+ DestInstance,
+ SrcInstance,
+ PacketProtocol,
+ ResponseType,
+ NULL_ADDRESS,
+ NextPacketSize,
+ 0, // BufferSize
+ SequenceNumber,
+ MaxSequenceNumber,
+ ClientReference,
+ ServerReference,
+ FALSE
+ );
+ }
+
+ if ( Packet == NULL ) {
+ IF_TPDBG ( TP_DEBUG_RESOURCES ) {
+ TpPrint0("TpStressCreateTransmitPool: could not allocate packet for pool.\n");
+ }
+ TpStressFreeTransmitPool( TmpPool );
+ return NULL;
+ }
+
+ ProtRes = PROT_RES( Packet );
+ ProtRes->Pool.NextPacket = TmpPool->Head;
+ TmpPool->Head = Packet;
+
+ if ( i == 0 ) {
+ TmpPool->Tail = Packet;
+ }
+ }
+
+ //
+ // Initialize the NumPackets var and the allocation counters
+ //
+
+ TmpPool->Allocated = 0;
+ TmpPool->Deallocated = 0;
+
+ return TmpPool;
+}
+
+
+VOID
+TpStressFreeTransmitPool(
+ IN PTP_TRANSMIT_POOL TpTransmitPool
+ )
+{
+ PNDIS_PACKET Packet;
+ PPROTOCOL_RESERVED ProtRes;
+
+ if ( TpTransmitPool == NULL ) {
+ return;
+ }
+
+ //
+ // If the spin lock was allocated free it.
+ //
+
+ if ( TpTransmitPool->SpinLockAllocated == TRUE ) {
+ NdisFreeSpinLock( &TpTransmitPool->SpinLock );
+ }
+
+ //
+ // Unchain and destroy the packets chained in the Packet Pool.
+ //
+
+ while ( TpTransmitPool->Head != NULL ) {
+ Packet = TpTransmitPool->Head;
+
+ ProtRes = PROT_RES( TpTransmitPool->Head );
+ TpTransmitPool->Head = ProtRes->Pool.NextPacket;
+
+ TpStressFreePacket( Packet );
+ }
+
+ //
+ // And free the Packet Pool Structure.
+ //
+
+ NdisFreeMemory( TpTransmitPool,0,0 );
+}
+
+
+PNDIS_PACKET
+TpStressAllocatePoolPacket(
+ IN PTP_TRANSMIT_POOL TpTransmitPool,
+ IN PINSTANCE_COUNTERS Counters
+ )
+{
+ PPROTOCOL_RESERVED ProtRes;
+ PNDIS_PACKET Packet;
+
+ NdisAcquireSpinLock( &TpTransmitPool->SpinLock );
+
+ if ( TpTransmitPool->Head == NULL ) {
+ NdisReleaseSpinLock( &TpTransmitPool->SpinLock );
+ return NULL;
+ }
+
+ Packet = TpTransmitPool->Head;
+
+ ProtRes = PROT_RES( Packet );
+ TpTransmitPool->Head = ProtRes->Pool.NextPacket;
+
+ if ( TpTransmitPool->Head == NULL ) {
+ TpTransmitPool->Tail = NULL;
+ }
+
+ TpTransmitPool->Allocated++;
+
+ NdisReleaseSpinLock( &TpTransmitPool->SpinLock );
+
+ ProtRes->Pool.TransmitPool = TpTransmitPool;
+ ProtRes->InstanceCounters = Counters;
+
+ return Packet;
+}
+
+
+VOID
+TpStressSetPoolPacketInfo(
+ IN POPEN_BLOCK OpenP,
+ IN OUT PNDIS_PACKET Packet,
+ IN PUCHAR DestAddr,
+ IN UCHAR DestInstance,
+ IN UCHAR SrcInstance,
+ IN ULONG SequenceNumber,
+ IN ULONG MaxSequenceNumber,
+ IN UCHAR ClientReference,
+ IN UCHAR ServerReference
+ )
+{
+ PNDIS_BUFFER Buffer;
+ PUCHAR Memory;
+ UINT Length;
+ PSTRESS_PACKET StrPacket;
+
+ NdisQueryPacket( Packet,NULL,NULL,&Buffer,NULL );
+
+ NdisQueryBuffer( Buffer,(PVOID *)&Memory,&Length );
+
+ StrPacket = (PSTRESS_PACKET)Memory;
+
+ StrPacket->hdr.info.DestInstance = DestInstance;
+ StrPacket->hdr.info.SrcInstance = SrcInstance;
+ StrPacket->hdr.info.CheckSum = 0xFFFFFFFF;
+
+ StrPacket->sc.SequenceNumber = SequenceNumber;
+ StrPacket->sc.MaxSequenceNumber = MaxSequenceNumber;
+ StrPacket->sc.ClientReference = ClientReference;
+ StrPacket->sc.ServerReference = ServerReference;
+
+ TpInitPoolMediaHeader( &StrPacket->hdr,OpenP->Media,DestAddr );
+
+
+ StrPacket->sc.CheckSum = TpSetCheckSum(
+ (PUCHAR)&StrPacket->hdr.info,
+ sizeof( STRESS_PACKET ) -
+ ( sizeof( ULONG ) +
+ OpenP->Media->HeaderSize )
+ );
+
+}
+
+
+VOID
+TpStressSetTruncatedPacketInfo(
+ IN POPEN_BLOCK OpenP,
+ IN OUT PNDIS_PACKET Packet,
+ IN PUCHAR DestAddr,
+ IN INT PacketSize,
+ IN UCHAR DestInstance,
+ IN UCHAR SrcInstance,
+ IN ULONG SequenceNumber,
+ IN ULONG MaxSequenceNumber,
+ IN UCHAR ClientReference,
+ IN UCHAR ServerReference,
+ IN ULONG DataBufferOffset
+ )
+{
+ PNDIS_BUFFER Buffer;
+ PNDIS_BUFFER NextBuffer;
+ PUCHAR Memory;
+ UINT Length;
+ LONG DataBufferSize;
+ PSTRESS_PACKET TpPacket;
+ BOOLEAN Reset;
+ static BOOLEAN IntroduceFalsePageInfo;
+ register UINT PageCount1;
+ register UINT PageCount2;
+
+ Reset = FALSE;
+
+ NdisQueryPacket( Packet,NULL,NULL,&Buffer,NULL );
+
+ NdisQueryBuffer(
+ Buffer,
+ (PVOID *)&Memory,
+ &Length
+ );
+
+ TpPacket = (PSTRESS_PACKET)Memory;
+
+ TpPacket->hdr.info.PacketSize = PacketSize;
+ TpPacket->hdr.info.DestInstance = DestInstance;
+ TpPacket->hdr.info.SrcInstance = SrcInstance;
+ TpPacket->hdr.info.CheckSum = 0xFFFFFFFF;
+
+ TpPacket->sc.SequenceNumber = SequenceNumber;
+ TpPacket->sc.MaxSequenceNumber = MaxSequenceNumber;
+ TpPacket->sc.ClientReference = ClientReference;
+ TpPacket->sc.ServerReference = ServerReference;
+ TpPacket->sc.DataBufOffset = DataBufferOffset;
+
+ TpInitTruncatedMediaHeader(
+ &TpPacket->hdr,
+ OpenP->Media,
+ DestAddr,
+ PacketSize
+ );
+
+ TpPacket->sc.CheckSum = TpSetCheckSum(
+ (PUCHAR)&TpPacket->hdr.info,
+ sizeof( STRESS_PACKET ) -
+ ( sizeof( ULONG ) +
+ OpenP->Media->HeaderSize )
+ );
+
+ NdisGetNextBuffer( Buffer,&NextBuffer );
+
+ DataBufferSize = PacketSize - sizeof( STRESS_PACKET );
+
+ TP_ASSERT( DataBufferSize >= 0 );
+
+ if ( DataBufferSize == 0 ) {
+ DataBufferSize = 1;
+ Reset = TRUE;
+ }
+
+ // test
+ {
+ PMDL TmpMdl;
+ ULONG TmpSize;
+ PVOID VirtualAddress;
+
+ TmpMdl = (PMDL)NextBuffer;
+ VirtualAddress = OpenP->Stress->DataBuffer[0]+DataBufferOffset;
+
+ TmpSize = COMPUTE_PAGES_SPANNED(VirtualAddress, DataBufferSize);
+ if (((TmpMdl->Size - sizeof(MDL)) >> 2L) < TmpSize)
+ {
+ TpPrint0("TpStressSetTruncatePacketInfo: bad mdl size\n");
+ TpPrint1("New Mdl size = %d\n", TmpMdl->Size);
+ TpPrint1("DataBufferSize = %d\n", DataBufferSize);
+ TpPrint1("PagesSpanned = %d\n", TmpSize);
+ TpPrint1("MdlPages = %d\n", (TmpMdl->Size - sizeof(MDL)) >> 2L);
+ TpBreakPoint();
+ }
+ }
+
+ IoBuildPartialMdl(
+ OpenP->Stress->DataBufferMdl[0],
+ (PMDL)NextBuffer,
+ (PVOID)(OpenP->Stress->DataBuffer[0]+DataBufferOffset),
+ DataBufferSize
+ );
+
+ if ( Reset == TRUE ) {
+ NextBuffer->ByteCount = 0;
+ }
+
+ Packet->Private.TotalLength = PacketSize;
+
+
+
+
+ PageCount1 = ADDRESS_AND_SIZE_TO_SPAN_PAGES( MmGetMdlVirtualAddress( NextBuffer ), MmGetMdlByteCount( NextBuffer ) );
+ PageCount2 = ADDRESS_AND_SIZE_TO_SPAN_PAGES( MmGetMdlVirtualAddress( Buffer ), MmGetMdlByteCount( Buffer ) );
+
+
+ if ( IntroduceFalsePageInfo ) {
+ IntroduceFalsePageInfo = FALSE;
+ Packet->Private.PhysicalCount = (PageCount1 + PageCount2) | 0x08000000 ;
+ } else {
+ IntroduceFalsePageInfo = TRUE;
+ Packet->Private.PhysicalCount = PageCount1 + PageCount2;
+ }
+
+}
+
+
+
+VOID
+TpStressFreePoolPacket(
+ IN OUT PNDIS_PACKET Packet
+ )
+{
+ PPROTOCOL_RESERVED ProtRes;
+ PTP_TRANSMIT_POOL TpTransmitPool;
+
+ //
+ // Determine the location of the Test Protocol Packet Pool to return
+ // this packet to.
+ //
+
+ ProtRes = PROT_RES( Packet );
+ TpTransmitPool = ProtRes->Pool.TransmitPool;
+
+ //
+ // Null out the Packets NextPacket pointer. It will be placed the
+ // end of the Packet Pool chain.
+ //
+
+ ProtRes->Pool.TransmitPool = NULL;
+ ProtRes->InstanceCounters = NULL;
+
+ //
+ // Take the SpinLock which guards the Packet Pool
+ //
+
+ NdisAcquireSpinLock( &TpTransmitPool->SpinLock );
+
+ //
+ // If the Packet Pool's Head pointer is NULL the poll is
+ // empty, and this packet is at the Head and the Tail.
+ //
+
+ if ( TpTransmitPool->Head == NULL ) {
+
+ //
+ // Chain the packet to the head of the Packet Pool Chain.
+ //
+
+ TpTransmitPool->Head = Packet;
+
+ } else {
+
+ //
+ // Else chain the packet to the end of the Packet Pool Chain.
+ //
+
+ ProtRes = PROT_RES( TpTransmitPool->Tail );
+ ProtRes->Pool.NextPacket = Packet;
+ }
+
+ //
+ // Finally point the Packet Pool Struct Tail pointer at this packet,
+ // and incremented the Deallocated Packets counter.
+ //
+
+ TpTransmitPool->Tail = Packet;
+ TpTransmitPool->Deallocated++;
+
+ //
+ // And release the Packet Pool SpinLock.
+ //
+
+ NdisReleaseSpinLock( &TpTransmitPool->SpinLock );
+}
+
+//
+// Functional Packet Routines
+//
+
+
+PTP_PACKET
+TpFuncInitPacketHeader(
+ IN POPEN_BLOCK OpenP,
+ IN INT PacketSize
+ )
+
+// ---------------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// ----------------
+
+{
+ NDIS_STATUS Status;
+ PTP_PACKET TmpBuffer;
+ PUCHAR DataField;
+ INT DataFieldSize;
+ USHORT i;
+
+ Status = NdisAllocateMemory((PVOID *)&TmpBuffer,
+ PacketSize,
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_RESOURCES )
+ {
+ TpPrint0("TpFuncInitPacketHeader: failed to allocate TmpBuffer\n");
+ }
+ return NULL;
+
+ }
+ else
+ {
+ NdisZeroMemory( (PVOID)TmpBuffer,PacketSize );
+ }
+
+ if ( !TpInitMediaHeader(&TmpBuffer->u.F2.hdr1,
+ OpenP->Media,
+ OpenP->Send->DestAddress,
+ OpenP->StationAddress,
+ PacketSize))
+ {
+ NdisFreeMemory( TmpBuffer,0,0 );
+ return NULL;
+ }
+
+
+ //
+ // initialize the packet information header
+ //
+
+ TmpBuffer->u.F2.hdr1.info.Signature = FUNC1_PACKET_SIGNATURE;
+ TmpBuffer->u.F2.hdr1.info.DestInstance = OpenP->OpenInstance;
+ TmpBuffer->u.F2.hdr1.info.SrcInstance = 0;
+ TmpBuffer->u.F2.hdr1.info.PacketSize = PacketSize;
+ TmpBuffer->u.F2.hdr1.info.PacketType = FUNC1_PACKET_TYPE;
+ TmpBuffer->u.F2.hdr1.info.u.PacketNumber = (UCHAR)OpenP->Send->PacketsSent;
+
+ //
+ // and set the checksum in the header.
+ //
+
+ TmpBuffer->u.F2.hdr1.info.CheckSum =TpSetCheckSum((PUCHAR)&TmpBuffer->u.F2.hdr1.info,
+ sizeof( PACKET_INFO ) - sizeof( ULONG ));
+
+
+ if ( OpenP->Send->ResendPackets == TRUE )
+ {
+ //
+ // We are building a resend packet, fill in the FUNC_PACKET info
+ // for the internal packet, and determine the start of the test
+ // data field.
+ //
+
+ if ( !TpInitMediaHeader(&TmpBuffer->u.F2.hdr2,
+ OpenP->Media,
+ OpenP->Send->ResendAddress,
+ OpenP->Send->DestAddress,
+ ( PacketSize - sizeof( FUNC1_PACKET))))
+ {
+ NdisFreeMemory( TmpBuffer,0,0 );
+ return NULL;
+ }
+
+
+ TmpBuffer->u.F2.hdr2.info.Signature = FUNC2_PACKET_SIGNATURE;
+ TmpBuffer->u.F2.hdr2.info.DestInstance = OpenP->OpenInstance;
+ TmpBuffer->u.F2.hdr2.info.SrcInstance = 0;
+ TmpBuffer->u.F2.hdr2.info.PacketSize = PacketSize - sizeof( FUNC1_PACKET );
+ TmpBuffer->u.F2.hdr2.info.PacketType = FUNC2_PACKET_TYPE;
+ TmpBuffer->u.F2.hdr2.info.u.PacketNumber = (UCHAR)OpenP->Send->PacketsSent;
+
+ DataField = (PUCHAR)((PUCHAR)TmpBuffer + (ULONG)sizeof( FUNC2_PACKET ));
+
+ //
+ // Now set the checksum value for the header.
+ //
+
+ TmpBuffer->u.F2.hdr2.info.CheckSum = TpSetCheckSum((PUCHAR)&TmpBuffer->u.F2.hdr2.info,
+ sizeof( PACKET_INFO ) - sizeof( ULONG ));
+
+ }
+ else
+ {
+ //
+ // Otherwise this is just a standard packet with no resend
+ // packet contained within. Mark it as such, a set the data field
+ // pointer to the beginning of the data field.
+ //
+
+ DataField = (PUCHAR)((PUCHAR)TmpBuffer + (ULONG)sizeof( FUNC1_PACKET ) );
+
+ }
+
+ DataFieldSize = PacketSize - (ULONG)( DataField - (PUCHAR)TmpBuffer );
+
+ for ( i = 0 ; i < (USHORT)DataFieldSize ; i++ )
+ {
+ DataField[i] = (UCHAR)( i % 256 );
+ }
+
+ return TmpBuffer;
+}
+
+
+ULONG
+TpSetCheckSum(
+ IN PUCHAR Buffer,
+ IN ULONG BufLen
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ PUCHAR TmpBuffer = Buffer;
+ ULONG TmpCheckSum = 0;
+ ULONG i;
+
+ for ( i = 0 ; i < BufLen ; i++ ) {
+ TmpCheckSum += (ULONG)*TmpBuffer++;
+ }
+
+ return ~TmpCheckSum;
+}
+/*
+
+VOID
+TpSetCheckSum(
+ IN PUCHAR Buffer,
+ IN ULONG BufLen,
+ IN PULONG CheckSum
+ )
+
+/ *++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--* /
+
+{
+ PUCHAR TmpBuffer = Buffer;
+ ULONG TmpCheckSum = 0;
+ ULONG i;
+
+ return;
+
+ for ( i = 0 ; i < BufLen ; i++ ) {
+ TmpCheckSum += (ULONG)*TmpBuffer++;
+ }
+
+ *CheckSum = ~TmpCheckSum;
+}
+*/
+
+
+BOOLEAN
+TpCheckSum(
+ IN PUCHAR Buffer,
+ IN ULONG BufLen,
+ IN PULONG CheckSum
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ PUCHAR TmpBuffer = Buffer;
+ ULONG TmpCheckSum = 0;
+ ULONG i;
+
+ return TRUE;
+
+ for ( i = 0 ; i < BufLen ; i++ ) {
+ TmpCheckSum += (ULONG)*TmpBuffer++;
+ }
+
+ if (( *CheckSum + TmpCheckSum ) != -1 ) {
+ TP_ASSERT( FALSE );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+PNDIS_PACKET
+TpFuncAllocateSendPacket(
+ IN POPEN_BLOCK OpenP
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+--*/
+
+{
+ NDIS_STATUS Status;
+ PPROTOCOL_RESERVED ProtRes;
+ PNDIS_PACKET Packet;
+ PNDIS_BUFFER Buffer;
+ PUCHAR TmpBuf;
+ INT TmpBufSize;
+ INT MdlSize;
+ INT i;
+
+ //
+ // Make sure that this is a legal packetsize, and if it isn't,
+ // then set it to the nearest valid size.
+ //
+
+ if (( OpenP->Send->ResendPackets == FALSE ) &&
+ ( OpenP->Send->PacketSize < sizeof( FUNC1_PACKET ))) {
+
+ OpenP->Send->PacketSize = sizeof( FUNC1_PACKET );
+
+ TpPrint0("TpFuncAllocateSendPacket: PacketSize to small for packet type.\n");
+ TpPrint1("TpFuncAllocateSendPacket: Using %d\n",OpenP->Send->PacketSize);
+
+
+ } else if (( OpenP->Send->ResendPackets == TRUE ) &&
+ ( OpenP->Send->PacketSize < sizeof( FUNC2_PACKET ))) {
+
+ OpenP->Send->PacketSize = sizeof( FUNC2_PACKET );
+
+ TpPrint0("TpFuncAllocateSendPacket: Invalid PacketSize for packet type.\n");
+ TpPrint1("TpFuncAllocateSendPacket: Using %d\n",OpenP->Send->PacketSize);
+
+ } else if ( OpenP->Send->PacketSize >
+ (ULONG)OpenP->Media->MaxPacketLen ) {
+
+ OpenP->Send->PacketSize = (ULONG)OpenP->Media->MaxPacketLen;
+
+ TpPrint0("TpFuncAllocateSendPacket: PacketSize to large for media.\n");
+ TpPrint1("TpFuncAllocateSendPacket: Using %d\n",OpenP->Send->PacketSize);
+ }
+
+ NdisAllocatePacket(
+ &Status,
+ &Packet,
+ OpenP->Send->PacketHandle
+ );
+
+ if ( Status != NDIS_STATUS_SUCCESS ) {
+
+ TpPrint1("TpFuncAllocateSendPacket: NdisAllocatePacket failed %s\n",
+ TpGetStatus( Status ));
+ return NULL;
+ }
+
+ ProtRes = PROT_RES( Packet );
+ ProtRes->Pool.PacketHandle = &OpenP->Send->PacketHandle;
+ ProtRes->InstanceCounters = OpenP->Send->Counters;
+
+ TmpBufSize = OpenP->Send->PacketSize;
+
+ TmpBuf = (PUCHAR)TpFuncInitPacketHeader( OpenP,TmpBufSize );
+
+ if ( TmpBuf == NULL ) {
+ TpPrint0("TpFuncAllocateSendPacket: failed to initialize Packet Header\n");
+ return NULL;
+ }
+
+ //
+ // Functional packets are made up of two small buffers at the beginning
+ // of the MDL chain followed by one large buffer at the end of the chain.
+ // If there is not enough room in the packet the buffer chain will be
+ // affected accordingly.
+ //
+
+ for ( i=0;i<2;i++ ) {
+
+ //
+ // Select the size of the first and second buffer.
+ //
+
+ MdlSize = TpGetRandom( OpenP->Media->HeaderSize,0x64 );
+
+ if ( MdlSize > TmpBufSize ) {
+
+ //
+ // If it is larger than the remaining packet size, then
+ // we will use only the remaining packet.
+ //
+
+ MdlSize = TmpBufSize;
+ }
+
+ //
+ // Create a buffer (MDL) using this portion of the packet.
+ //
+
+ Buffer = TpAllocateBuffer( TmpBuf,MdlSize );
+
+ if ( Buffer == NULL ) {
+ TpPrint0("TpFuncAllocateSendPacket: failed to create the MDL\n");
+ TpFuncFreePacket( Packet,OpenP->Send->PacketSize );
+ return (PNDIS_PACKET)NULL;
+ }
+
+ //
+ // And chain it to the back of the packet.
+ //
+
+ NdisChainBufferAtBack( Packet,Buffer );
+
+ //
+ // reset the packet size counters and see if we are out of packet.
+ //
+
+ TmpBuf += MdlSize;
+ TmpBufSize -= MdlSize;
+
+ if ( TmpBufSize == 0 ) {
+
+ //
+ // if so, then return the packet we have made.
+ //
+
+ return Packet;
+ }
+ }
+
+ //
+ // Otherwise tack on the remainder of the buffer as the last mdl
+ // in the chain.
+ //
+
+ Buffer = TpAllocateBuffer( TmpBuf,TmpBufSize );
+
+ NdisChainBufferAtBack( Packet,Buffer );
+
+ if ( Buffer == NULL ) {
+ TpPrint0("TpFuncAllocateSendPacket: failed to create the MDL\n");
+ TpFuncFreePacket( Packet,OpenP->Send->PacketSize );
+ return NULL;
+ }
+
+ return Packet;
+}
+
+
+
+VOID
+TpFuncFreePacket(
+ PNDIS_PACKET Packet,
+ ULONG PacketSize
+ )
+
+{
+ PNDIS_BUFFER HeadBuffer;
+ PNDIS_BUFFER Buffer;
+
+ if ( Packet == NULL ) {
+ return;
+ }
+
+ NdisUnchainBufferAtFront( Packet,&HeadBuffer );
+
+ if ( HeadBuffer != NULL ) {
+
+ NdisUnchainBufferAtFront( Packet,&Buffer );
+
+ while ( Buffer != NULL ) {
+ TpFreeBuffer( Buffer );
+ NdisUnchainBufferAtFront( Packet,&Buffer );
+ }
+
+ HeadBuffer->ByteCount = PacketSize;
+
+ NdisFreeMemory( MmGetMdlVirtualAddress( HeadBuffer ),0,0 );
+
+ TpFreeBuffer( HeadBuffer );
+ }
+
+ NdisFreePacket( Packet );
+}
diff --git a/private/ntos/ndis/testprot/tpdrvr/perf.c b/private/ntos/ndis/testprot/tpdrvr/perf.c
new file mode 100644
index 000000000..255494430
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpdrvr/perf.c
@@ -0,0 +1,2162 @@
+// ------------------------------------------------
+//
+// Copyright (c) 1990 Microsoft Corporation
+//
+// Module Name:
+//
+// perf.c
+//
+// Abstract:
+//
+// This file contains the source for the netcard performance tests
+//
+// Author:
+//
+// Tim Wynsma (timothyw) 4-27-1994
+//
+// Environment:
+//
+// Kernel mode
+//
+//
+// Changes:
+// 5-18-1994 (timothyw)
+// Requested changes to performance function and output (part 1)
+// 6-08-1994 (timothyw)
+// Changed perf tests to client/server model (part 2)
+//
+// --------------------------------------------------
+
+
+#include <ndis.h>
+
+#include "tpdefs.h"
+#include "media.h"
+#include "tpprocs.h"
+#include "string.h"
+
+
+//
+// local constants..
+//
+
+#define MINIMUM_PERF_PACKET 60
+#define PACKETS_PER_BURST 5
+
+#define PERFMODE_SEND 0 // client sends to any address
+#define PERFMODE_SENDTOSRV 1 // client sends to server
+#define PERFMODE_SENDWITHACK 2 // client sends to server, server ACKS
+#define PERFMODE_SENDANDRCV 3 // client sends to server, server sends to client
+#define PERFMODE_RECEIVE 4 // server sends to client
+#define PERFMODE_REQANDRCV 5 // server sends to client when get REQ message
+#define PERFMODE_SHUTDOWN 6 // client shuts down server
+
+#define REQ_DATA 0
+#define REQ_INITGO 1
+#define REQ_ACK 2
+#define REQ_RES 3
+
+//
+// defines for the packet signature of each type, and for the packet
+// types themselves
+//
+
+// "ID" portion of packet signature. This is added to base to get actual signature
+
+#define PERF_DATA_ID 0x00000000 // test data message
+#define PERF_ACKREQ_ID 0x00000001 // ACK or REQ message
+#define PERF_START_ID 0x00000002 // INIT or GO message
+#define PERF_DONE_ID 0x00000003 // REQRES or SRVDONE message
+#define PERF_STOP_ID 0x00000004 // STOPSRV or SRVDOWN message
+#define PERF_NOGO_ID 0x00000005 // NOGO message
+#define PERF_RESULTS_ID 0x00000006 // RETRES message
+#define PERF_ID_MASK 0x00000007 // mask for ID
+
+#define PERF_BASE 0x76543210 // base signature
+#define PERF_SERVER 0x00000008 // offset from base of server ids
+
+// signatures used by client (messages sent to server)
+
+#define PERF_CLTDATA_SIGNATURE (PERF_BASE + PERF_DATA_ID)
+#define PERF_REQ_SIGNATURE (PERF_BASE + PERF_ACKREQ_ID)
+#define PERF_INIT_SIGNATURE (PERF_BASE + PERF_START_ID)
+#define PERF_REQRES_SIGNATURE (PERF_BASE + PERF_DONE_ID)
+#define PERF_STOPSRV_SIGNATURE (PERF_BASE + PERF_STOP_ID)
+
+// signatures used by server (messages sent to client)
+
+#define PERF_SRVDATA_SIGNATURE (PERF_BASE + PERF_SERVER + PERF_DATA_ID)
+#define PERF_ACK_SIGNATURE (PERF_BASE + PERF_SERVER + PERF_ACKREQ_ID)
+#define PERF_GO_SIGNATURE (PERF_BASE + PERF_SERVER + PERF_START_ID)
+#define PERF_SRVDONE_SIGNATURE (PERF_BASE + PERF_SERVER + PERF_DONE_ID)
+#define PERF_SRVDOWN_SIGNATURE (PERF_BASE + PERF_SERVER + PERF_STOP_ID)
+#define PERF_NOGO_SIGNATURE (PERF_BASE + PERF_SERVER + PERF_NOGO_ID)
+#define PERF_RETRES_SIGNATURE (PERF_BASE + PERF_SERVER + PERF_RESULTS_ID)
+
+//
+// structures of special (info) packet types used by performance tests
+// structures MUST be packed
+
+#include <packon.h>
+
+typedef struct _INFO_PACKET_INFO
+{
+ ULONG Signature;
+ ULONG PacketSize;
+ ULONG Mode;
+ ULONG Length;
+ ULONG Count;
+ ULONG Delay;
+ UCHAR Address[ADDRESS_LENGTH];
+ ULONG CheckSum;
+} INFO_PACKET_INFO;
+
+typedef INFO_PACKET_INFO UNALIGNED *PINFO_PACKET_INFO;
+
+
+typedef struct _RESULTS_PACKET_INFO
+{
+ ULONG Signature;
+ ULONG PacketSize;
+ ULONG PacketsSent;
+ ULONG SendErrors;
+ ULONG PacketsReceived;
+ ULONG ElapsedTime;
+ ULONG SelfReceives;
+ ULONG Restarts;
+ ULONG CheckSum;
+} RESULTS_PACKET_INFO;
+typedef RESULTS_PACKET_INFO UNALIGNED *PRESULTS_PACKET_INFO;
+
+
+typedef struct _DATA_PACKET_INFO
+{
+ ULONG Signature;
+ ULONG PacketSize;
+ ULONG CheckSum;
+} DATA_PACKET_INFO;
+
+typedef DATA_PACKET_INFO UNALIGNED *PDATA_PACKET_INFO;
+
+typedef struct _PERF_PACKET
+{
+ MEDIA_HEADER media;
+ union
+ {
+ INFO_PACKET_INFO info;
+ DATA_PACKET_INFO data;
+ RESULTS_PACKET_INFO results;
+ } u;
+} PERF_PACKET;
+typedef PERF_PACKET UNALIGNED *PPERF_PACKET;
+
+#include <packoff.h>
+
+//
+// local functions
+//
+
+PTP_REQUEST_HANDLE
+TpPerfAllocatePacket( IN POPEN_BLOCK OpenP,
+ IN ULONG PacketSize );
+
+NDIS_STATUS
+TpPerfInitialize( IN OUT POPEN_BLOCK OpenP);
+
+VOID
+TpPerfDeallocate( IN OUT POPEN_BLOCK OpenP);
+
+
+NDIS_STATUS
+TpPerfSend( IN POPEN_BLOCK OpenP );
+
+VOID
+TpPerfSendDpc( IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SysArg1,
+ IN PVOID SysArg2 );
+
+VOID
+TpPerfRestart( IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SysArg1,
+ IN PVOID SysArg2 );
+
+VOID
+TpPerformEndDpc( IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SysArg1,
+ IN PVOID SysArg2 );
+
+VOID
+TpPerfWriteResults( IN PPERF_BLOCK Perform,
+ IN PRESULTS_PACKET_INFO Info);
+
+
+VOID
+TpPerfSetPacketData(POPEN_BLOCK OpenP,
+ PUCHAR TmpBuf,
+ ULONG Signature,
+ PUCHAR DestAddr,
+ ULONG PacketSize);
+
+VOID
+TpPerfTestCompleted(PPERF_BLOCK Perform);
+
+
+NDIS_STATUS
+TpPerfLowPriorityReceive( POPEN_BLOCK OpenP,
+ PINFO_PACKET_INFO ReceivePacketInfo,
+ ULONG MessageId);
+
+
+// ---------------------------------------------------------------
+//
+// Function: TpPerfServer
+//
+// Arguments: OpenP -- pointer to open block for instance
+//
+// Returns: Completion status
+//
+// Descript: This function starts up the PerformServer command
+//
+// ---------------------------------------------------------------
+
+NDIS_STATUS
+TpPerfServer( POPEN_BLOCK OpenP )
+{
+ NDIS_STATUS Status;
+ PTP_REQUEST_HANDLE RequestHandle;
+
+ //
+ // Allocate the performance structure, and do necessary initializations
+ //
+
+ Status = TpPerfInitialize(OpenP);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ return Status;
+ }
+ OpenP->Perform->IsServer = TRUE;
+ OpenP->Perform->MaskId = PERF_BASE;
+
+ //
+ // yes, I know that OpenP->Perform->ServerAddress is 00-00-00-00-00-00
+ // at this point
+ //
+ RequestHandle = TpPerfAllocatePacket( OpenP, MINIMUM_PERF_PACKET);
+ if (RequestHandle == NULL)
+ {
+ TpPerfDeallocate(OpenP);
+ return NDIS_STATUS_RESOURCES;
+ }
+ OpenP->Perform->GoInitReq = RequestHandle;
+
+ RequestHandle = TpPerfAllocatePacket( OpenP, MINIMUM_PERF_PACKET);
+ if (RequestHandle == NULL)
+ {
+ TpPerfDeallocate(OpenP);
+ return NDIS_STATUS_RESOURCES;
+ }
+ OpenP->Perform->AckReq = RequestHandle;
+
+ RequestHandle = TpPerfAllocatePacket( OpenP, MINIMUM_PERF_PACKET);
+ if (RequestHandle == NULL)
+ {
+ TpPerfDeallocate(OpenP);
+ return NDIS_STATUS_RESOURCES;
+ }
+ OpenP->Perform->ResReq = RequestHandle;
+
+ TpAddReference( OpenP );
+
+ return NDIS_STATUS_PENDING;
+}
+
+
+// ---------------------------------------------------------------
+//
+// Function: TpPerfClient
+//
+// Arguments: OpenP -- pointer to open block for instance
+// CmdArgs -- Arguments given in tpctl to PerformClient command
+//
+// Returns: Completion status
+//
+// Descript: This function starts up the PerformClient command
+//
+// ---------------------------------------------------------------
+
+
+NDIS_STATUS
+TpPerfClient( POPEN_BLOCK OpenP,
+ PCMD_ARGS CmdArgs )
+{
+ PUCHAR p, q, s, t;
+ ULONG i;
+ PTP_REQUEST_HANDLE RequestHandle;
+ NDIS_STATUS Status;
+ PPERF_BLOCK Perform;
+ PPERF_RESULTS OutputBuffer;
+
+ //
+ // Allocate the performance structure, and do necessary initializations
+ //
+
+ Status = TpPerfInitialize(OpenP);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ return Status;
+ }
+ Perform = OpenP->Perform;
+ Perform->IsServer = FALSE;
+ Perform->MaskId = PERF_BASE + PERF_SERVER;
+
+ //
+ // set so no data is avail if aborted
+ //
+ OutputBuffer = MmGetSystemAddressForMdl( Perform->PerformIrp->MdlAddress );
+ OutputBuffer->ResultsExist = FALSE;
+
+ // Now, deal with the arguments..
+
+ Perform->NumberOfPackets = CmdArgs->ARGS.TPPERF.PerfNumPackets;
+ Perform->PacketDelay = CmdArgs->ARGS.TPPERF.PerfDelay;
+ Perform->PerformMode = CmdArgs->ARGS.TPPERF.PerfMode;
+
+ if ( CmdArgs->ARGS.TPPERF.PerfPacketSize > OpenP->Media->MaxPacketLen )
+ {
+ Perform->PacketSize = OpenP->Media->MaxPacketLen;
+ IF_TPDBG ( TP_DEBUG_IOCTL_ARGS )
+ {
+ TpPrint1("TpPerfClient: Invalid PacketSize, using %d\n", Perform->PacketSize);
+ }
+ }
+ else if ( CmdArgs->ARGS.TPPERF.PerfPacketSize < MINIMUM_PERF_PACKET )
+ {
+ Perform->PacketSize = MINIMUM_PERF_PACKET;
+ IF_TPDBG ( TP_DEBUG_IOCTL_ARGS )
+ {
+ TpPrint1("TpPerfClient: Invalid PacketSize, using %d\n", Perform->PacketSize);
+ }
+ }
+ else
+ {
+ Perform->PacketSize = CmdArgs->ARGS.TPPERF.PerfPacketSize;
+ }
+
+ p = Perform->ServerAddress;
+ q = CmdArgs->ARGS.TPPERF.PerfServerAddr;
+ s = Perform->ClientAddress;
+ t = CmdArgs->ARGS.TPPERF.PerfSendAddr;
+
+
+ for ( i=0 ; i < OpenP->Media->AddressLen; i++ )
+ {
+ *p++ = *q++;
+ *s++ = *t++;
+ }
+
+ //
+ // only PERFMODE_SEND does not use a info packet (it assumes its sending to
+ // never-never land)
+ //
+
+ if (Perform->PerformMode != PERFMODE_SEND)
+ {
+ //
+ // NULL_ADDRESS is not a valid server address
+ //
+ if ( RtlCompareMemory( Perform->ServerAddress,
+ NULL_ADDRESS,
+ OpenP->Media->AddressLen ) == OpenP->Media->AddressLen )
+ {
+ TpPrint0("TpPerfClient: server address may not equal NULL_ADDRESS\n");
+ TpPerfDeallocate(OpenP);
+ return NDIS_STATUS_FAILURE;
+ }
+
+ Perform->WhichReq = REQ_INITGO;
+
+ //
+ // Set up the info send packet and request.
+ //
+
+ RequestHandle = TpPerfAllocatePacket( OpenP, MINIMUM_PERF_PACKET);
+ if (RequestHandle == NULL)
+ {
+ TpPerfDeallocate(OpenP);
+ return NDIS_STATUS_RESOURCES;
+ }
+ Perform->GoInitReq = RequestHandle;
+
+ TpPerfSetPacketData(OpenP,
+ RequestHandle->u.PERF_REQ.Buffer,
+ ((Perform->PerformMode < PERFMODE_SHUTDOWN)
+ ? PERF_INIT_SIGNATURE
+ : PERF_STOPSRV_SIGNATURE),
+ Perform->ServerAddress,
+ MINIMUM_PERF_PACKET);
+
+ //
+ // if needed, Set up the data request send packet and request.
+ //
+ if (Perform->PerformMode == PERFMODE_REQANDRCV)
+ {
+ RequestHandle = TpPerfAllocatePacket( OpenP, MINIMUM_PERF_PACKET);
+ if (RequestHandle == NULL)
+ {
+ TpPerfDeallocate(OpenP);
+ return NDIS_STATUS_RESOURCES;
+ }
+ Perform->AckReq = RequestHandle;
+
+ TpPerfSetPacketData(OpenP,
+ RequestHandle->u.PERF_REQ.Buffer,
+ PERF_REQ_SIGNATURE,
+ Perform->ServerAddress,
+ MINIMUM_PERF_PACKET);
+ }
+
+ //
+ // If needed, set up the request server results send packet and request.
+ //
+
+ if (Perform->PerformMode < PERFMODE_SHUTDOWN)
+ {
+ RequestHandle = TpPerfAllocatePacket( OpenP, MINIMUM_PERF_PACKET);
+ if (RequestHandle == NULL)
+ {
+ TpPerfDeallocate(OpenP);
+ return NDIS_STATUS_RESOURCES;
+ }
+ Perform->ResReq = RequestHandle;
+
+ TpPerfSetPacketData(OpenP,
+ RequestHandle->u.PERF_REQ.Buffer,
+ PERF_REQRES_SIGNATURE,
+ Perform->ServerAddress,
+ MINIMUM_PERF_PACKET);
+ }
+ }
+ else
+ {
+ Perform->WhichReq = REQ_DATA;
+ }
+
+ //
+ // if necessary, set up the data send packet and request
+ //
+
+ if (Perform->PerformMode <= PERFMODE_SENDANDRCV)
+ {
+ RequestHandle = TpPerfAllocatePacket( OpenP, Perform->PacketSize);
+ if (RequestHandle == NULL)
+ {
+ TpPerfDeallocate(OpenP);
+ return NDIS_STATUS_RESOURCES;
+ }
+ Perform->DataReq = RequestHandle;
+
+ TpPerfSetPacketData(OpenP,
+ RequestHandle->u.PERF_REQ.Buffer,
+ PERF_CLTDATA_SIGNATURE,
+ Perform->ServerAddress,
+ Perform->PacketSize);
+
+ if (Perform->PerformMode == PERFMODE_SENDWITHACK)
+ {
+ Perform->SendBurstCount = PACKETS_PER_BURST;
+ }
+ else
+ {
+ Perform->SendBurstCount = Perform->NumberOfPackets+1;
+ }
+ Perform->ReceiveBurstCount = Perform->NumberOfPackets+1;
+ }
+ else if (Perform->PerformMode == PERFMODE_REQANDRCV)
+ {
+ Perform->ReceiveBurstCount = PACKETS_PER_BURST;
+ }
+ else
+ {
+ Perform->ReceiveBurstCount = Perform->NumberOfPackets+1;
+ }
+
+ TpAddReference( OpenP );
+
+ //
+ // We will be probably be sending more than one packet, so queue TpPerfSendDpc
+ // and return Pending to the user, the DPC will send the packets,
+ // and after all the packets have been sent complete the request.
+ //
+
+ if ( !KeInsertQueueDpc( &Perform->PerformSendDpc, NULL, NULL ))
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0("TpPerfSend failed to queue the TpPerfSendDpc.\n");
+ }
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ if ( Perform->PerformIrp != NULL )
+ {
+ Perform->PerformIrp->IoStatus.Status = NDIS_STATUS_FAILURE;
+ }
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ TpPerfDeallocate(OpenP);
+ return NDIS_STATUS_FAILURE;
+ }
+ return NDIS_STATUS_PENDING;
+}
+
+
+
+// ---------------------------------------------
+//
+// Function: TpPerfInitialize
+//
+// Arguments: OpenP -- ptr to current open instance
+//
+// Returns: Status
+//
+// Descript: This function allocates the PERF_BLOCK structure, and initializes
+// necessary components of it..
+//
+// ---------------------------------------------
+
+NDIS_STATUS
+TpPerfInitialize( IN OUT POPEN_BLOCK OpenP)
+{
+ NDIS_STATUS Status;
+
+ // Sanity check
+
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ if (OpenP->Perform != NULL)
+ {
+ TpPrint0("TpPerfInitialize: OpenP->Perform is not NULL !\n");
+ TpBreakPoint();
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ //
+ // First allocate the Performance struct.
+ //
+
+ if ( (NdisAllocateMemory( (PVOID *)&OpenP->Perform,
+ sizeof( PERF_BLOCK ),
+ 0,
+ HighestAddress) ) != NDIS_STATUS_SUCCESS)
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpPerfInitialize: failed to allocate PERF_BLOCK struct\n");
+ }
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // zero everything for starters..
+ //
+
+ NdisZeroMemory( OpenP->Perform, sizeof( PERF_BLOCK ));
+
+ //
+ // Allocate the Send PacketPool.
+ //
+
+ NdisAllocatePacketPool( &Status,
+ &OpenP->Perform->PacketHandle,
+ NUMBER_OF_POOL_PACKETS,
+ sizeof( PROTOCOL_RESERVED ) );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpPerfInitialize: could not allocate Packet Pool\n");
+ }
+ NdisFreeMemory( OpenP->Perform,0,0 );
+ OpenP->Perform = NULL;
+ return Status;
+ }
+
+ //
+ // Initialize the Perform DPCs
+ //
+
+ KeInitializeDpc(&OpenP->Perform->PerformSendDpc, // performance send
+ TpPerfSendDpc,
+ (PVOID)OpenP );
+
+ KeInitializeDpc(&OpenP->Perform->PerformEndDpc,
+ TpPerformEndDpc,
+ (PVOID)OpenP );
+
+ KeInitializeDpc(&OpenP->Perform->PerformRestartDpc,
+ TpPerfRestart,
+ (PVOID)OpenP);
+
+
+ KeInitializeTimer( &OpenP->Perform->PerformTimer );
+
+ //
+ // other things we can initialize here
+ //
+
+ OpenP->Perform->PerformIrp = OpenP->Irp;
+ OpenP->Irp = NULL;
+
+ OpenP->Perform->Active = TRUE;
+ OpenP->PerformanceTest = TRUE;
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+
+// -------------------------------------------------
+//
+// Function: TpPerfDeallocate
+//
+// Arguments: OpenP -- ptr to current open instance
+//
+// Returns: none
+//
+// Descript: This function frees up everything if allocations fail, or when
+// we are ending performance testing
+//
+// -------------------------------------------------
+
+
+VOID
+TpPerfDeallocate( IN OUT POPEN_BLOCK OpenP)
+{
+ OpenP->PerformanceTest = FALSE;
+
+ if (OpenP->Perform->GoInitReq)
+ {
+ TpFuncFreePacket( OpenP->Perform->GoInitReq->u.SEND_REQ.Packet,
+ OpenP->Perform->GoInitReq->u.SEND_REQ.PacketSize );
+ NdisFreeMemory( OpenP->Perform->GoInitReq,0,0 );
+ }
+
+ if (OpenP->Perform->AckReq)
+ {
+ TpFuncFreePacket( OpenP->Perform->AckReq->u.SEND_REQ.Packet,
+ OpenP->Perform->AckReq->u.SEND_REQ.PacketSize );
+ NdisFreeMemory( OpenP->Perform->AckReq,0,0 );
+ }
+
+ if (OpenP->Perform->ResReq)
+ {
+ TpFuncFreePacket( OpenP->Perform->ResReq->u.SEND_REQ.Packet,
+ OpenP->Perform->ResReq->u.SEND_REQ.PacketSize );
+ NdisFreeMemory( OpenP->Perform->ResReq,0,0 );
+ }
+
+ if (OpenP->Perform->DataReq)
+ {
+ TpFuncFreePacket( OpenP->Perform->DataReq->u.SEND_REQ.Packet,
+ OpenP->Perform->DataReq->u.SEND_REQ.PacketSize );
+ NdisFreeMemory( OpenP->Perform->DataReq,0,0 );
+ }
+
+ NdisFreePacketPool( OpenP->Perform->PacketHandle );
+
+ NdisFreeMemory( OpenP->Perform,0,0 );
+ OpenP->Perform = NULL;
+}
+
+
+
+
+// ---------------------------------------------
+//
+// Function: TpPerfAllocatePacket
+//
+// Arguments: OpenP -- ptr to current open instance
+// PacketSize -- size of packet being allocated --
+// range is checked by caller
+//
+// Returns: ptr to request structure for packet if successful, else NULL
+//
+// Descript: This function allocates all send packets used in performance tests
+//
+// ---------------------------------------------
+
+
+PTP_REQUEST_HANDLE
+TpPerfAllocatePacket( IN POPEN_BLOCK OpenP,
+ IN ULONG PacketSize )
+
+{
+ NDIS_STATUS Status;
+ PPROTOCOL_RESERVED ProtRes;
+ PNDIS_PACKET Packet;
+ PNDIS_BUFFER Buffer;
+ PUCHAR TmpBuf;
+ PTP_REQUEST_HANDLE RequestHandle;
+
+ //
+ // first, check to make sure media type is ok.
+ // This makes sure that this check is done in "main" thread, not
+ // in a DPC somewhere
+
+ switch( OpenP->Media->MediumType )
+ {
+ case NdisMediumDix:
+ case NdisMedium802_3:
+ case NdisMedium802_5:
+ case NdisMediumFddi:
+ case NdisMediumArcnet878_2:
+ break;
+
+ default:
+ IF_TPDBG ( TP_DEBUG_RESOURCES )
+ {
+ TpPrint0("TpPerfAllocatePacket: Unsupported MAC Type\n");
+ }
+ return (PTP_REQUEST_HANDLE)NULL;
+ }
+
+
+ NdisAllocatePacket( &Status,
+ &Packet,
+ OpenP->Perform->PacketHandle );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ TpPrint1("TpPerfAllocatePacket: NdisAllocatePacket failed %s\n", TpGetStatus( Status ));
+ return (PTP_REQUEST_HANDLE)NULL;
+ }
+
+ ProtRes = PROT_RES( Packet );
+ ProtRes->Pool.PacketHandle = &OpenP->Perform->PacketHandle;
+ ProtRes->InstanceCounters = NULL;
+
+ //
+ // start of things partially copied from TpFuncInitPacketHeader
+ //
+
+
+ Status = NdisAllocateMemory((PVOID *)&TmpBuf,
+ PacketSize,
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_RESOURCES )
+ {
+ TpPrint0("TpFuncInitPacketHeader: failed to allocate TmpBuf\n");
+ }
+ return (PTP_REQUEST_HANDLE)NULL;
+ }
+ NdisZeroMemory( (PVOID)TmpBuf,PacketSize );
+
+ // data is in 2 or three buffers. The first is always 14 bytes, and the second is
+ // always 46 bytes. (giving a total of 60 bytes). If Packetsize > 60 bytes, the
+ // third buffer is created with a size of (Packetsize-60) bytes
+
+ // first, the "media header" = 14 bytes
+
+ NdisAllocateBuffer( &Status,
+ &Buffer,
+ NULL, // pool handle, not currently used in NT
+ TmpBuf,
+ sizeof (MEDIA_HEADER));
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ TpPrint0("TpPerfAllocatePacket: failed to create the MDL\n");
+ TpFuncFreePacket( Packet, PacketSize );
+ return (PTP_REQUEST_HANDLE)NULL;
+ }
+
+ //
+ // And chain it to the back of the packet.
+ //
+
+ NdisChainBufferAtBack( Packet,Buffer );
+
+ // next, the "protocol" info (plus some data) = 46 bytes (46+14=60)
+
+ NdisAllocateBuffer( &Status,
+ &Buffer,
+ NULL, // pool handle, not currently used in NT
+ TmpBuf+sizeof(MEDIA_HEADER),
+ MINIMUM_PERF_PACKET - sizeof(MEDIA_HEADER));
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ TpPrint0("TpPerfAllocatePacket: failed to create the MDL\n");
+ TpFuncFreePacket( Packet, PacketSize );
+ return (PTP_REQUEST_HANDLE)NULL;
+ }
+
+ //
+ // And chain it to the back of the packet.
+ //
+
+ NdisChainBufferAtBack( Packet,Buffer );
+
+ // finally, if we need more than 60 bytes, add a buffer with the rest..
+
+ if (PacketSize > MINIMUM_PERF_PACKET)
+ {
+ NdisAllocateBuffer( &Status,
+ &Buffer,
+ NULL, // pool handle, not currently used in NT
+ TmpBuf+MINIMUM_PERF_PACKET,
+ PacketSize-MINIMUM_PERF_PACKET);
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ TpPrint0("TpPerfAllocatePacket: failed to create the MDL\n");
+ TpFuncFreePacket( Packet, PacketSize );
+ return (PTP_REQUEST_HANDLE)NULL;
+ }
+
+ //
+ // And chain it to the back of the packet.
+ //
+
+ NdisChainBufferAtBack( Packet,Buffer );
+ }
+
+ Status = NdisAllocateMemory((PVOID *)&RequestHandle,
+ sizeof( TP_REQUEST_HANDLE ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ TpPrint0("TpPerfAllocatePacket: unable to allocate Request Handle.\n");
+ return (PTP_REQUEST_HANDLE)NULL;
+ }
+ else
+ {
+ NdisZeroMemory( RequestHandle,sizeof( TP_REQUEST_HANDLE ));
+ }
+
+ RequestHandle->Signature = SEND_REQUEST_HANDLE_SIGNATURE;
+ RequestHandle->Open = OpenP;
+ RequestHandle->RequestPended = TRUE;
+ RequestHandle->Irp = OpenP->Perform->PerformIrp;
+
+ RequestHandle->u.PERF_REQ.Packet = Packet;
+ RequestHandle->u.PERF_REQ.PacketSize = PacketSize;
+ RequestHandle->u.PERF_REQ.SendPacket = TRUE;
+ RequestHandle->u.PERF_REQ.Buffer = TmpBuf;
+
+ ProtRes = PROT_RES( Packet );
+ ProtRes->RequestHandle = RequestHandle;
+
+ //
+ // Set the check sum in the PROTOCOL RESERVED Section of the
+ // packet header to ensure it is not touched while the packet
+ // is in the hands of the MAC.
+ //
+
+ ProtRes->CheckSum = TpSetCheckSum( (PUCHAR)ProtRes,
+ sizeof( PROTOCOL_RESERVED ) - sizeof( ULONG ) );
+
+ return RequestHandle;
+
+}
+
+// -----------------------------------------------------
+//
+// Function: TpPerfSetPacketData
+//
+// Arguments: OpenP -- ptr to current open instance
+// TmpBuf -- ptr to memory allocated for packet data
+// Signature -- packet type signature to use
+// DestAddr -- address to which packet will be sent
+// PacketSize -- bytes allocated for packet
+//
+// Returns: None
+//
+// Descript: stuffs data into a packet
+//
+// -----------------------------------------------------
+
+VOID
+TpPerfSetPacketData(POPEN_BLOCK OpenP,
+ PUCHAR TmpBuf,
+ ULONG Signature,
+ PUCHAR DestAddr,
+ ULONG PacketSize)
+{
+ PPERF_PACKET TmpBuffer = (PPERF_PACKET)TmpBuf;
+ PUCHAR p;
+ PUCHAR q;
+ PUCHAR SrcAddr = OpenP->StationAddress;
+ USHORT DataSizeShort;
+ USHORT i;
+ PPERF_BLOCK Perform = OpenP->Perform;
+
+
+ if (DestAddr != NULL) // only do this on first pass
+ {
+ switch( OpenP->Media->MediumType )
+ {
+ case NdisMediumDix:
+ case NdisMedium802_3:
+ p = TmpBuffer->media.e.DestAddress;
+ q = TmpBuffer->media.e.SrcAddress;
+ DataSizeShort = (USHORT)( PacketSize - OpenP->Media->HeaderSize );
+ TmpBuffer->media.e.PacketSize_Hi = (UCHAR)( DataSizeShort >> 8 );
+ TmpBuffer->media.e.PacketSize_Lo = (UCHAR)DataSizeShort;
+ break;
+
+ case NdisMedium802_5:
+ TmpBuffer->media.tr.AC = 0x10;
+ TmpBuffer->media.tr.FC = 0x40;
+ p = TmpBuffer->media.tr.DestAddress;
+ q = TmpBuffer->media.tr.SrcAddress;
+ break;
+
+ case NdisMediumFddi:
+ TmpBuffer->media.fddi.FC = 0x57;
+ p = TmpBuffer->media.fddi.DestAddress;
+ q = TmpBuffer->media.fddi.SrcAddress;
+ break;
+
+ case NdisMediumArcnet878_2:
+ TmpBuffer->media.a.ProtocolID = ARCNET_DEFAULT_PROTOCOLID;
+ p = TmpBuffer->media.a.DestAddress;
+ q = TmpBuffer->media.a.SrcAddress;
+ break;
+
+ default:
+ TpBreakPoint();
+ }
+
+ for ( i = 0 ; i < OpenP->Media->AddressLen ; i++ )
+ {
+ *p++ = *DestAddr++;
+ *q++ = *SrcAddr++;
+ }
+ }
+
+ //
+ // initialize the packet information header
+ //
+
+ if ((Signature == PERF_SRVDATA_SIGNATURE) || (Signature == PERF_CLTDATA_SIGNATURE))
+ {
+ ULONG DataFieldSize;
+ PUCHAR DataField;
+
+ TmpBuffer->u.data.Signature = Signature;
+ TmpBuffer->u.data.PacketSize = PacketSize;
+ TmpBuffer->u.data.CheckSum = TpSetCheckSum( (PUCHAR)&TmpBuffer->u.data,
+ sizeof(DATA_PACKET_INFO) - sizeof(ULONG) );
+ DataField = TmpBuf + sizeof (MEDIA_HEADER) + sizeof (DATA_PACKET_INFO);
+ DataFieldSize = PacketSize - (sizeof (MEDIA_HEADER) + sizeof (DATA_PACKET_INFO) );
+ for ( i = 0 ; i < DataFieldSize ; i++ )
+ {
+ *DataField++ = (UCHAR)i;
+ }
+ }
+ else if (Signature == PERF_RETRES_SIGNATURE)
+ {
+ TmpBuffer->u.results.Signature = PERF_RETRES_SIGNATURE;
+ TmpBuffer->u.results.PacketSize = PacketSize;
+ TmpBuffer->u.results.PacketsSent = Perform->SendCount;
+ TmpBuffer->u.results.SendErrors = Perform->SendFailCount;
+ TmpBuffer->u.results.PacketsReceived = Perform->ReceiveCount;
+ TmpBuffer->u.results.ElapsedTime = Perform->PerfSendTotalTime.LowPart;
+ TmpBuffer->u.results.SelfReceives = Perform->SelfReceiveCount;
+ TmpBuffer->u.results.Restarts = Perform->RestartCount;
+
+ TmpBuffer->u.results.CheckSum = TpSetCheckSum( (PUCHAR)&TmpBuffer->u.results,
+ sizeof(RESULTS_PACKET_INFO) - sizeof(ULONG) );
+ }
+ else
+ {
+
+ TmpBuffer->u.info.Signature = Signature;
+ if (DestAddr != NULL)
+ {
+ ULONG i;
+ PUCHAR r,s;
+
+ TmpBuffer->u.info.PacketSize = PacketSize;
+ TmpBuffer->u.info.Mode = Perform->PerformMode;
+ TmpBuffer->u.info.Length = Perform->PacketSize;
+ TmpBuffer->u.info.Count = Perform->NumberOfPackets;
+ TmpBuffer->u.info.Delay = Perform->PacketDelay;
+ r = TmpBuffer->u.info.Address;
+ s = Perform->ClientAddress;
+ for (i=0; i < ADDRESS_LENGTH; i++)
+ {
+ *r++ = *s++;
+ }
+ }
+ TmpBuffer->u.info.CheckSum = TpSetCheckSum( (PUCHAR)&TmpBuffer->u.info,
+ sizeof(INFO_PACKET_INFO) - sizeof(ULONG) );
+ }
+}
+
+
+
+
+// ------------------------------------------
+//
+// Function: TpPerfSendDpc
+//
+// Arguments: Dpc -- ignored
+// DeferredContext -- actually ptr to open instance
+// SysArg1 -- ignored
+// SysArg2 -- ignored
+//
+// Returns: none
+//
+// Descript: This function is used to start the sending of packets
+// Further packets are sent via TpPerfSendComplete
+//
+// -------------------------------------------
+
+
+VOID
+TpPerfSendDpc(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SysArg1,
+ IN PVOID SysArg2
+ )
+
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)DeferredContext);
+ NDIS_STATUS Status;
+ PTP_REQUEST_HANDLE RequestHandle;
+
+ UNREFERENCED_PARAMETER( Dpc );
+ UNREFERENCED_PARAMETER( SysArg1 );
+ UNREFERENCED_PARAMETER( SysArg2 );
+
+
+ switch(OpenP->Perform->WhichReq)
+ {
+ case REQ_DATA:
+ RequestHandle = OpenP->Perform->DataReq;
+ ++OpenP->Perform->SendCount;
+ OpenP->Perform->PerfSendTotalTime =
+ RtlLargeIntegerNegate(KeQueryPerformanceCounter(NULL));
+ break;
+ case REQ_INITGO:
+ RequestHandle = OpenP->Perform->GoInitReq;
+ break;
+ case REQ_ACK:
+ RequestHandle = OpenP->Perform->AckReq;
+ break;
+ case REQ_RES:
+ RequestHandle = OpenP->Perform->ResReq;
+ break;
+ }
+
+ ++OpenP->Perform->PacketsPending;
+
+ NdisSend( &Status,OpenP->NdisBindingHandle, RequestHandle->u.PERF_REQ.Packet );
+
+ if ( Status != NDIS_STATUS_PENDING )
+ {
+ TpPerfSendComplete( OpenP, RequestHandle->u.PERF_REQ.Packet, Status );
+ }
+
+}
+
+
+
+
+// -----------------------------------------------
+//
+// Function: TpPerfSendComplete
+//
+// Arguments: ProtocolBindingContext -- actually ptr to open instance
+// Packet -- the packet that was just sent
+// Status -- final status of the send operation
+//
+// Returns: none
+//
+// Descript: This function is called after the netcard driver actually
+// sends the packet. It is responsible for sending the next
+// packet (if there is one to be sent)
+//
+// -----------------------------------------------
+
+
+VOID
+TpPerfSendComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ )
+
+
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)ProtocolBindingContext);
+ PPERF_BLOCK Perform = OpenP->Perform;
+ PPROTOCOL_RESERVED ProtRes;
+ PTP_REQUEST_HANDLE RequestHandle;
+ PNDIS_BUFFER Buffer;
+ LARGE_INTEGER DueTime;
+ ULONG MessageId;
+
+
+
+ ProtRes = PROT_RES( Packet );
+ RequestHandle = ProtRes->RequestHandle;
+
+senddidnotpend:
+
+ if ( Perform->Active == TRUE )
+ {
+ //
+ // Make sure it is one of our packets
+ //
+ if (( RequestHandle->Signature == SEND_REQUEST_HANDLE_SIGNATURE ) &&
+ ( RequestHandle->u.PERF_REQ.SendPacket == TRUE ))
+ {
+ //
+ // Packet was sent by the PERF command, decrement the
+ // counter tracking the number of outstanding functional packets,
+ // and if the send succeeded increment the completion counter.
+ //
+
+ --Perform->PacketsPending;
+
+ //
+ // doesn't do any good to reverse logic here (at least for x86)
+ // so just put up with the 1 jump
+ //
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // If we are running on TokenRing the following two "failures"
+ // are not considered failures NDIS_STATUS_NOT_RECOGNIZED -
+ // no one on the ring recognized the address as theirs, or
+ // NDIS_STATUS_NOT_COPIED - no one on the ring copied the
+ // packet, so we need to special case this and not count
+ // these as failures.
+ //
+ // SanjeevK : Even FDDI returns the same errors as 802.5
+ //
+
+ if ( ( NdisMediumArray[OpenP->MediumIndex] == NdisMedium802_5 ) ||
+ ( NdisMediumArray[OpenP->MediumIndex] == NdisMediumFddi ) ||
+ ( NdisMediumArray[OpenP->MediumIndex] == NdisMediumArcnet878_2) )
+ {
+ if (( Status != NDIS_STATUS_NOT_RECOGNIZED ) &&
+ ( Status != NDIS_STATUS_NOT_COPIED ))
+ {
+ ++Perform->SendFailCount;
+ }
+ }
+ else
+ {
+ ++Perform->SendFailCount;
+ }
+ }
+
+ //
+ // not checking the checksum of the PROTOCOL_RESERVED section
+ // here, because that stuff was done in functional testing
+ //
+
+ MessageId = ((PPERF_PACKET)RequestHandle->u.PERF_REQ.Buffer)->u.info.Signature
+ - PERF_BASE;
+
+ //
+ // deal with performance test messages first
+ //
+
+ if ((MessageId & PERF_ID_MASK) == PERF_DATA_ID)
+ {
+ if ( ++Perform->PacketsSent < Perform->NumberOfPackets )
+ {
+ //
+ // if in a mode where never wait for ack or req, don't
+ // bother with spin-lock, etc, even though this causes
+ // repetitious code...
+ //
+ if ((Perform->PerformMode != PERFMODE_SENDWITHACK) &&
+ (Perform->PerformMode != PERFMODE_REQANDRCV))
+ {
+ ++Perform->PacketsPending;
+ ++Perform->SendCount;
+
+ if (!Perform->PacketDelay)
+ {
+ NdisSend( &Status,OpenP->NdisBindingHandle,Packet );
+ if ( Status == NDIS_STATUS_PENDING )
+ {
+ return;
+ }
+ goto senddidnotpend; // avoid recursion
+ }
+ //
+ // delay code
+ //
+ else
+ {
+ KeStallExecutionProcessor(10 * Perform->PacketDelay);
+ NdisSend( &Status,OpenP->NdisBindingHandle,Packet );
+ if ( Status == NDIS_STATUS_PENDING )
+ {
+ return;
+ }
+ goto senddidnotpend; // avoid recursion
+ }
+ }
+
+ //
+ // send another packet if SendBurstCount has not run out
+ // otherwise, wait for REQ or ACK (and setup timeout?)
+ //
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ if (--Perform->SendBurstCount != 0)
+ {
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ ++Perform->PacketsPending;
+ ++Perform->SendCount;
+
+ if (!Perform->PacketDelay)
+ {
+ NdisSend( &Status,OpenP->NdisBindingHandle,Packet );
+ if ( Status == NDIS_STATUS_PENDING )
+ {
+ return;
+ }
+ goto senddidnotpend; // avoid recursion
+ }
+ //
+ // delay code
+ //
+ else
+ {
+ KeStallExecutionProcessor(10 * Perform->PacketDelay);
+ NdisSend( &Status,OpenP->NdisBindingHandle,Packet );
+ if ( Status == NDIS_STATUS_PENDING )
+ {
+ return;
+ }
+ goto senddidnotpend; // avoid recursion
+ }
+ }
+ else
+ {
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ DueTime.HighPart = 0xFFFFFFFF; // So it will be relative.
+ DueTime.LowPart = (ULONG)(-(ONE_TENTH_SECOND));
+
+ if ( KeSetTimer(&Perform->PerformTimer,
+ DueTime,
+ &Perform->PerformRestartDpc ))
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0(
+ "TpPerfSendComplete: set PerformTimer while timer existed(4).\n");
+ }
+ }
+ }
+ }
+ else
+ {
+ TpPerfTestCompleted(Perform);
+ }
+ return;
+ }
+
+ //
+ // deal with all other messages
+ //
+ switch ( MessageId)
+ {
+ //
+ // info messages sent by server. Nothing special to do
+ // when send is complete
+ //
+ case PERF_ACKREQ_ID: // client: REQ message
+ case (PERF_ACKREQ_ID + PERF_SERVER): // server: ACK message
+ case PERF_START_ID: // client: INIT message
+ case PERF_DONE_ID: // client: REQRES message
+ case (PERF_DONE_ID + PERF_SERVER): // server: SRVDONE message
+ case PERF_STOP_ID: // client: STOPSRV message
+ case (PERF_NOGO_ID + PERF_SERVER): // server: NOGO message
+ return; // client waits for server message
+ // server waits for client response
+
+ //
+ // we are a server, and we just got done sending a GO message
+ // if we are a sender, send the first performance packet
+ //
+ case (PERF_START_ID + PERF_SERVER): // server: GO message
+ if (Perform->PerformMode >= PERFMODE_SENDANDRCV)
+ {
+ //
+ // server needs to send data to client. start it up
+ //
+ Perform->WhichReq = REQ_DATA;
+
+ DueTime.HighPart = 0xFFFFFFFF; // So it will be relative.
+ DueTime.LowPart = (ULONG)(-(ONE_HUNDREDTH_SECOND*2));
+
+ if ( KeSetTimer(&Perform->PerformTimer,
+ DueTime,
+ &Perform->PerformSendDpc ))
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0(
+ "TpPerfSendComplete: set PerformTimer while timer existed(1).\n");
+ }
+ }
+ }
+ return;
+
+ //
+ // we are a server, and we just got done sending the final results
+ // to the client. finish shutting down from this test
+ //
+
+ case (PERF_RESULTS_ID + PERF_SERVER): // server: sent results
+ if (Perform->DataReq) // clean up, then wait for INIT message
+ {
+ TpFuncFreePacket( Perform->DataReq->u.SEND_REQ.Packet,
+ Perform->DataReq->u.SEND_REQ.PacketSize );
+ NdisFreeMemory( Perform->DataReq,0,0 );
+ Perform->DataReq = NULL;
+ }
+ return;
+
+ //
+ // we are a server, and we just got done acknowledging a shut-down request
+ // from the client. finish up with the shutdown.
+ //
+ case (PERF_STOP_ID + PERF_SERVER): // server: acknowledged shutdown
+ // request cleansup, then exit
+ DueTime.HighPart = 0xFFFFFFFF; // So it will be relative.
+ DueTime.LowPart = (ULONG)(-(ONE_SECOND));
+
+ if ( KeSetTimer(&Perform->PerformTimer,
+ DueTime,
+ &Perform->PerformEndDpc ))
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0(
+ "TpPerfSendComplete: set PerformTimer while timer existed(2).\n");
+ }
+ }
+ return;
+
+ default: // illegal message
+ TpPrint0("TpPerfSendComplete: unknown message\n");
+ TpBreakPoint();
+ return;
+
+
+ }
+ } // if (RequestSignature == ..
+
+ else
+ {
+ //
+ // this is not one of ours. we should never, ever get here...
+ //
+ TpPrint0("TpPerfSendComplete: Not one of ours--why are we here?");
+ NdisUnchainBufferAtFront( Packet,&Buffer );
+ NdisFreeMemory( MmGetMdlVirtualAddress( Buffer ),0,0 );
+ TpFreeBuffer( Buffer );
+ NdisFreePacket( Packet );
+ NdisFreeMemory( RequestHandle,0,0 );
+ return;
+ }
+ } // if (Perform->Active)
+
+}
+
+
+// -----------------------------------------------------------
+//
+// TpPerfTestCompleted
+//
+// Arguments: OpenP -- ptr to current open instance
+//
+// Returns: none
+//
+// Descript: This code deals with cleanup that needs to be done at the
+// end of a send test
+//
+// ----------------------------------------------------------
+
+VOID
+TpPerfTestCompleted(PPERF_BLOCK Perform)
+{
+ LARGE_INTEGER scale;
+ LARGE_INTEGER ltemp;
+ LARGE_INTEGER DueTime;
+ PKDPC DpcPtr;
+
+ Perform->PerfSendTotalTime = RtlLargeIntegerAdd( Perform->PerfSendTotalTime,
+ KeQueryPerformanceCounter(&scale));
+
+ Perform->PerfSendTotalTime = RtlExtendedIntegerMultiply(Perform->PerfSendTotalTime, 1000);
+ Perform->PerfSendTotalTime = RtlLargeIntegerDivide(Perform->PerfSendTotalTime,
+ scale, &ltemp);
+
+ if (Perform->IsServer)
+ {
+ DpcPtr = &Perform->PerformSendDpc;
+ Perform->WhichReq = REQ_ACK; // SRVDONE message
+ }
+
+ //
+ // must be client..
+ //
+ else if (Perform->PerformMode == PERFMODE_SEND)
+ {
+ //
+ // Write the statistics to the send results outputbuffer.
+ //
+
+ TpPerfWriteResults( Perform, NULL );
+ DpcPtr = &Perform->PerformEndDpc;
+ }
+
+ else
+ {
+ if (Perform->PerformMode == PERFMODE_SENDANDRCV)
+ {
+ if (!Perform->Testing)
+ {
+ Perform->Testing = TRUE;
+ return;
+ }
+ }
+ Perform->WhichReq = REQ_RES;
+ DpcPtr = &Perform->PerformSendDpc;
+ }
+
+ DueTime.HighPart = 0xFFFFFFFF; // So it will be relative.
+ DueTime.LowPart = (ULONG)(-(ONE_SECOND));
+
+
+ if ( KeSetTimer(&Perform->PerformTimer,
+ DueTime,
+ DpcPtr ))
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0( "TpPerfTestCompleted: set PerformTimer while timer existed.\n");
+ }
+ }
+}
+
+// -------------------------------------------------------
+//
+// Function: TpPerfReceive
+//
+// Arguments: ProtocolBindingContext -- actually ptr to current open instance
+// LookaheadBuffer -- ptr to actual data received (after header)
+// LookaheadBufferSize -- valid bytes in LookaheadBuffer
+// PacketSize -- total size of packet (excluding header)
+//
+// Returns: Status
+//
+// Descript: This function deals with packets received by this netcard open instance
+// Some packets are counted, some just thrown away, some result in other
+// packets being sent
+//
+// -------------------------------------------------------
+
+
+
+NDIS_STATUS
+TpPerfReceive(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)ProtocolBindingContext);
+ PPERF_BLOCK Perform = OpenP->Perform;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PINFO_PACKET_INFO ReceivePacketInfo;
+ PNDIS_PACKET Packet;
+ ULONG MessageId;
+
+ //
+ // if we are not active (ie, shutting down) skip everything
+ //
+
+ if (Perform->Active)
+ {
+ //
+ // The LookAhead Buffer has been adjusted to point to the beginning of the
+ // PACKET_INFO structure
+ //
+ ReceivePacketInfo = (PINFO_PACKET_INFO)LookaheadBuffer;
+
+ //
+ // All valid messages have a signature of 0x7654321X.
+ // Using the MaskId, convert all valid messages to 0x0000000X.
+ // invalid messages will have other bits set. Messages that we
+ // managed to send to ourselves will be in range 0x08 to 0x0f.
+ // messages we expect will be in range 0x00 to 0x07
+ //
+ MessageId = ReceivePacketInfo->Signature ^ Perform->MaskId;
+ //
+ // trivially discard all unrecognized messages
+ //
+ if (MessageId < (PERF_SERVER + PERF_ID_MASK))
+ {
+ //
+ // first, deal with performance test messages which were received
+ //
+ if ( MessageId == PERF_DATA_ID)
+ {
+ ++Perform->ReceiveCount;
+
+ //
+ // Check to see if we need to send an ACK (or a REQ )
+ // note that the info packet will already be set up correctly
+ //
+ if (--Perform->ReceiveBurstCount != 0)
+ {
+ return NDIS_STATUS_SUCCESS;
+ }
+ else
+ {
+ Perform->ReceiveBurstCount = PACKETS_PER_BURST;
+ Packet = Perform->AckReq->u.PERF_REQ.Packet;
+ ++Perform->PacketsPending;
+
+ NdisSend( &Status,OpenP->NdisBindingHandle,Packet );
+ if ( Status == NDIS_STATUS_PENDING )
+ {
+ return NDIS_STATUS_SUCCESS;
+ }
+ TpPerfSendComplete( OpenP, Packet, Status );
+ return NDIS_STATUS_SUCCESS;
+ }
+ }
+ //
+ // second, deal with ACK and REQ messages
+ //
+ else if (MessageId == PERF_ACKREQ_ID)
+ {
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ if (Perform->SendBurstCount == 0)
+ {
+ Perform->SendBurstCount = PACKETS_PER_BURST;
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ KeCancelTimer(&Perform->PerformTimer);
+
+ Packet = Perform->DataReq->u.PERF_REQ.Packet;
+ ++Perform->SendCount;
+ ++Perform->PacketsPending;
+
+ NdisSend( &Status,OpenP->NdisBindingHandle,Packet );
+ if ( Status != NDIS_STATUS_PENDING )
+ {
+ TpPerfSendComplete( OpenP, Packet, Status );
+ }
+ }
+ else
+ {
+ Perform->SendBurstCount += PACKETS_PER_BURST;
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ }
+ return NDIS_STATUS_SUCCESS;
+ }
+ //
+ // deal with other valid messages
+ //
+ else if ((MessageId & PERF_SERVER) == 0) // check other valid messages
+ {
+ return TpPerfLowPriorityReceive(OpenP, ReceivePacketInfo, MessageId);
+ }
+ //
+ // deal with messages that we probably sent to ourselves
+ // while it it POSSIBLE that we got a random message that will
+ // fit this criteria, we are ignoring that for now
+ //
+ else
+ {
+ Perform->SelfReceiveCount++;
+ return NDIS_STATUS_SUCCESS;
+ }
+ }
+ }
+ return NDIS_STATUS_SUCCESS; // don't fail..
+}
+
+
+// ------------------------------------------------
+//
+// Function: TpPerfLowPriorityReceive
+//
+// Arguments: OpenP -- ptr to current open instance
+// ReceivePacketInfo -- data received from other end of wire
+// MessageId -- which message we received
+//
+// Returns: Status
+//
+// Descript: This function does the initialization required
+// when the server receives the PERF_INIT message
+//
+// -------------------------------------------------
+
+NDIS_STATUS
+TpPerfLowPriorityReceive( POPEN_BLOCK OpenP,
+ PINFO_PACKET_INFO ReceivePacketInfo,
+ ULONG MessageId)
+{
+ PPERF_BLOCK Perform = OpenP->Perform;
+ PUCHAR r,s;
+ ULONG i;
+ PTP_REQUEST_HANDLE RequestHandle;
+ PNDIS_PACKET Packet;
+ LARGE_INTEGER DueTime;
+ PKDPC DpcPtr;
+
+
+ switch(MessageId)
+ {
+ case PERF_DONE_ID: // REQRES or SRVDONE message
+ if (Perform->IsServer)
+ {
+ //
+ // client sent request for final results of test (on server side)
+ // test had better be complete. Shut down test and send message
+ // to client with those results
+ //
+ TpPerfSetPacketData(OpenP,
+ Perform->ResReq->u.PERF_REQ.Buffer,
+ PERF_RETRES_SIGNATURE,
+ NULL,
+ MINIMUM_PERF_PACKET);
+
+ Perform->WhichReq = REQ_RES;
+ DpcPtr = &Perform->PerformSendDpc;
+ DueTime.LowPart = (ULONG)(-(ONE_SECOND));
+ Perform->Testing = FALSE;
+ }
+ else
+ {
+ //
+ // server is done sending data. if only server was sending, get
+ // stats now . if both were sending, get stats now if we are also
+ // done. Otherwise, set flags to get data when we are done sending
+ //
+ if (Perform->PerformMode == PERFMODE_SENDANDRCV)
+ {
+ if (!Perform->Testing)
+ {
+ Perform->Testing = TRUE;
+ return NDIS_STATUS_SUCCESS;
+ }
+ }
+ Perform->WhichReq = REQ_RES;
+ DpcPtr = &Perform->PerformSendDpc;
+ DueTime.LowPart = (ULONG)(-(ONE_SECOND));
+ }
+ break;
+
+
+ case PERF_STOP_ID: // STOPSRV or SRVDOWN message
+ if (Perform->IsServer)
+ {
+ //
+ // client just sent message to server telling server to
+ // shut down, and go back to tpctl for next command
+ //
+ TpPerfSetPacketData(OpenP,
+ Perform->GoInitReq->u.PERF_REQ.Buffer,
+ PERF_SRVDOWN_SIGNATURE,
+ ReceivePacketInfo->Address,
+ MINIMUM_PERF_PACKET);
+
+ Perform->WhichReq = REQ_INITGO;
+ DpcPtr = &Perform->PerformSendDpc;
+ DueTime.LowPart = (ULONG)(-(ONE_SECOND));
+ }
+ else
+ {
+ //
+ // server is shutting down. We need to do the same
+ //
+ DpcPtr = &Perform->PerformEndDpc;
+ DueTime.LowPart = (ULONG)(-(ONE_SECOND));
+ }
+ break;
+
+
+ case PERF_NOGO_ID: // NOGO message
+ //
+ // server just sent message that it is unable to perform the
+ // requested test. Clean up and exit (to tpctl)
+ //
+ DpcPtr = &Perform->PerformEndDpc;
+ DueTime.LowPart = (ULONG)(-(ONE_SECOND));
+ break;
+
+
+ case PERF_RESULTS_ID: // RETRES message
+ //
+ // just received final results of this test from the server
+ // send data to tpctl, cleanup, and exit
+ //
+ //
+ // Write the statistics to the send results outputbuffer.
+ //
+
+ TpPerfWriteResults( Perform, (PRESULTS_PACKET_INFO)ReceivePacketInfo);
+ DpcPtr = &Perform->PerformEndDpc;
+ DueTime.LowPart = (ULONG)(-(ONE_SECOND));
+ break;
+
+ case PERF_START_ID: // INIT or GO message
+ if (!Perform->IsServer)
+ {
+ if (Perform->DataReq)
+ {
+ Perform->WhichReq = REQ_DATA;
+ DpcPtr = &Perform->PerformSendDpc;
+ DueTime.LowPart = (ULONG)(-(ONE_HUNDREDTH_SECOND));
+ break;
+ }
+ return NDIS_STATUS_SUCCESS;
+ }
+ else
+ {
+ if (Perform->Testing) // Got 2nd request, not done with 1st
+ {
+ TpPrint0("TpPerfReceive: Server got INIT while already running!\n");
+ if (Perform->DataReq)
+ {
+ TpFuncFreePacket( Perform->DataReq->u.SEND_REQ.Packet,
+ Perform->DataReq->u.SEND_REQ.PacketSize );
+ NdisFreeMemory( Perform->DataReq,0,0 );
+ }
+ }
+ //
+ // copy info we will need from message
+ //
+ Perform->PerformMode = ReceivePacketInfo->Mode;
+ Perform->PacketSize = ReceivePacketInfo->Length;
+ Perform->NumberOfPackets = ReceivePacketInfo->Count;
+ Perform->PacketDelay = ReceivePacketInfo->Delay;
+ r = Perform->ClientAddress;
+ s = ReceivePacketInfo->Address;
+ for (i=0; i < ADDRESS_LENGTH; i++)
+ {
+ *r++ = *s++;
+ }
+ //
+ // initialize counters
+ //
+ Perform->SendCount = 0;
+ Perform->SendFailCount = 0;
+ Perform->ReceiveCount = 0;
+ Perform->PacketsSent = 0;
+ Perform->PerformEndDpcCount = 0;
+ Perform->PacketsPending = 0;
+ Perform->Testing = FALSE;
+ Perform->SelfReceiveCount = 0;
+ Perform->SendBurstCount = 0;
+ Perform->ReceiveBurstCount = 0;
+ Perform->RestartCount = 0;
+ //
+ // if we will be sending test data (not just info messages), then
+ // set up the necessary buffer. If it fails, send a NOGO message
+ //
+ if (Perform->PerformMode >= PERFMODE_SENDANDRCV)
+ {
+ RequestHandle = TpPerfAllocatePacket( OpenP, Perform->PacketSize);
+ if (RequestHandle == NULL)
+ {
+ TpPrint0("TpPerfReceive: Server unable to allocate data packet\n");
+ RequestHandle = Perform->GoInitReq;
+ Packet = RequestHandle->u.PERF_REQ.Packet;
+
+ TpPerfSetPacketData(OpenP,
+ RequestHandle->u.PERF_REQ.Buffer,
+ PERF_NOGO_SIGNATURE,
+ Perform->ClientAddress,
+ MINIMUM_PERF_PACKET);
+
+ Perform->WhichReq = REQ_INITGO;
+ DpcPtr = &Perform->PerformSendDpc;
+ DueTime.LowPart = (ULONG)(-(ONE_SECOND));
+ break;
+ }
+ Perform->DataReq = RequestHandle;
+
+ TpPerfSetPacketData(OpenP,
+ RequestHandle->u.PERF_REQ.Buffer,
+ PERF_SRVDATA_SIGNATURE,
+ Perform->ClientAddress,
+ Perform->PacketSize);
+
+ if (Perform->PerformMode == PERFMODE_REQANDRCV)
+ {
+ Perform->SendBurstCount = PACKETS_PER_BURST;
+ }
+ else
+ {
+ Perform->SendBurstCount = Perform->NumberOfPackets+1;
+ }
+ Perform->ReceiveBurstCount = Perform->NumberOfPackets+1;
+ }
+
+ else if (Perform->PerformMode == PERFMODE_SENDWITHACK)
+ {
+ Perform->ReceiveBurstCount = PACKETS_PER_BURST;
+ }
+ else
+ {
+ Perform->ReceiveBurstCount = Perform->NumberOfPackets+1;
+ }
+
+ //
+ // all set--initialize the AckReq message, and
+ // send the client the GO message
+ //
+ Perform->Testing = TRUE;
+
+ switch(Perform->PerformMode)
+ {
+ case PERFMODE_SENDTOSRV:
+ case PERFMODE_SENDWITHACK:
+ TpPerfSetPacketData(OpenP,
+ Perform->AckReq->u.PERF_REQ.Buffer,
+ PERF_ACK_SIGNATURE,
+ Perform->ClientAddress,
+ MINIMUM_PERF_PACKET);
+ break;
+ default:
+ TpPerfSetPacketData(OpenP,
+ Perform->AckReq->u.PERF_REQ.Buffer,
+ PERF_SRVDONE_SIGNATURE,
+ Perform->ClientAddress,
+ MINIMUM_PERF_PACKET);
+ break;
+ }
+ TpPerfSetPacketData(OpenP,
+ Perform->ResReq->u.PERF_REQ.Buffer,
+ PERF_RETRES_SIGNATURE,
+ Perform->ClientAddress,
+ MINIMUM_PERF_PACKET);
+
+ TpPerfSetPacketData(OpenP,
+ Perform->GoInitReq->u.PERF_REQ.Buffer,
+ PERF_GO_SIGNATURE,
+ Perform->ClientAddress,
+ MINIMUM_PERF_PACKET);
+
+ DpcPtr = &Perform->PerformSendDpc;
+ DueTime.LowPart = (ULONG)(-(ONE_SECOND));
+ Perform->WhichReq = REQ_INITGO;
+ break;
+ }
+
+ default:
+ TpPrint0("TpPerfReceive: Client received unrecognized message\n");
+ return NDIS_STATUS_NOT_RECOGNIZED;
+ }
+
+ //
+ // drop thru to here if need to fire something off with the timer...
+ //
+
+ DueTime.HighPart = 0xFFFFFFFF; // So it will be relative.
+
+ if ( KeSetTimer(&Perform->PerformTimer,
+ DueTime,
+ DpcPtr ))
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0( "TpPerfLowPriorityReceive: set PerformTimer while timer existed.\n");
+ }
+ }
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+// --------------------------------------------
+//
+// Function: TpPerformEndDpc
+//
+// Arguments: Dpc -- not used
+// DeferredContext -- actually ptr to current open instance
+// SysArg1 -- not used
+// SysArg2 -- not used
+//
+// Returns: none
+//
+// Descript: This function is called when it is time to shut down
+// the current performance command
+//
+// -------------------------------------------
+
+VOID
+TpPerformEndDpc(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SysArg1,
+ IN PVOID SysArg2
+ )
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)DeferredContext);
+ PPERF_BLOCK Perform = OpenP->Perform;
+ LARGE_INTEGER DueTime;
+
+ UNREFERENCED_PARAMETER( Dpc );
+ UNREFERENCED_PARAMETER( SysArg1 );
+ UNREFERENCED_PARAMETER( SysArg2 );
+
+ //
+ // See if we have any outstanding packets left to complete. If we do,
+ // then we will reset the time to queue this dpc routine again in one
+ // second, if after ten requeue the packet has still no completed we
+ // assume it will never complete and return the results and finish.
+ //
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ if ((( Perform->PerformIrp != NULL ) &&
+ ( Perform->PerformIrp->Cancel == FALSE )) &&
+ (( Perform->PacketsPending != 0 ) &&
+ ( Perform->PerformEndDpcCount++ < 10 )))
+ {
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ DueTime.HighPart = -1; // So it will be relative.
+ DueTime.LowPart = (ULONG)(-(ONE_SECOND));
+
+ if ( KeSetTimer(&Perform->PerformTimer,
+ DueTime,
+ &Perform->PerformEndDpc ))
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0("TpPerformEndDpc: set PerformTimer while timer existed.\n");
+ }
+ }
+ return;
+ }
+
+
+ //
+ // and if the IoStatus.Status has not been set, then set it.
+ //
+
+ if ( (Perform->PerformIrp != NULL) &&
+ (Perform->PerformIrp->IoStatus.Status == NDIS_STATUS_PENDING ))
+ {
+ Perform->PerformIrp->IoStatus.Status = NDIS_STATUS_SUCCESS;
+ }
+
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ //
+ // Now set the sending flag to indicate that we are no longer
+ // SENDing packets.
+ //
+
+ Perform->Active = FALSE;
+
+ //
+ // and decrement the reference count on the OpenBlock stating this
+ // instance of an async test is no longer running, and the adapter
+ // may be closed if requested.
+ //
+
+
+ if (Perform->PerformIrp != NULL)
+ {
+ TpRemoveReference( OpenP );
+ IoMarkIrpPending( Perform->PerformIrp );
+
+ IoAcquireCancelSpinLock( &Perform->PerformIrp->CancelIrql );
+ IoSetCancelRoutine( Perform->PerformIrp,NULL );
+ IoReleaseCancelSpinLock( Perform->PerformIrp->CancelIrql );
+
+ IoCompleteRequest( Perform->PerformIrp,IO_NETWORK_INCREMENT );
+
+ Perform->PerformIrp = NULL;
+ }
+ TpPerfDeallocate(OpenP);
+}
+
+// --------------------------------------------
+//
+// Function: TpPerfRestart
+//
+// Arguments: Dpc -- not used
+// DeferredContext -- actually ptr to current open instance
+// SysArg1 -- not used
+// SysArg2 -- not used
+//
+// Returns: none
+//
+// Descript: This function is called when it is necessary to restart
+// a send without there having been a REQ or ACK received
+//
+// -------------------------------------------
+
+VOID
+TpPerfRestart(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SysArg1,
+ IN PVOID SysArg2
+ )
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)DeferredContext);
+ PPERF_BLOCK Perform = OpenP->Perform;
+ NDIS_STATUS Status;
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ if (Perform->SendBurstCount == 0)
+ {
+ Perform->SendBurstCount = 1;
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ Perform->RestartCount++;
+ ++Perform->SendCount;
+ ++Perform->PacketsPending;
+
+ NdisSend( &Status,OpenP->NdisBindingHandle, Perform->DataReq->u.PERF_REQ.Packet );
+ if ( Status != NDIS_STATUS_PENDING )
+ {
+ TpPerfSendComplete( OpenP, Perform->DataReq->u.PERF_REQ.Packet, Status );
+ }
+ }
+}
+
+
+// -----------------------------------------------------------------
+//
+// Function: TpPerfWriteResults
+//
+// Arguments: Perform -- ptr to perform block structure
+// Info -- ptr to data received from server (may be NULL)
+//
+// Returns: none
+//
+// Descript: This function writes the Performance test statistics into the
+// output buffer passed in by the ioctl call. NOTE: the
+// OpenP->SpinLock must be held when making this call
+//
+// ------------------------------------------------------------------
+
+
+VOID
+TpPerfWriteResults( IN PPERF_BLOCK Perform,
+ IN PRESULTS_PACKET_INFO Info)
+{
+ PPERF_RESULTS OutputBuffer;
+
+ //
+ // Get the output buffer out of the MDL stored in the IRP, and map
+ // it so we may write the statistics to it.
+ //
+
+ if (( Perform->PerformIrp != NULL ) &&
+ ( Perform->PerformIrp->Cancel == FALSE ))
+ {
+ OutputBuffer = MmGetSystemAddressForMdl( Perform->PerformIrp->MdlAddress );
+
+ //
+ // Write the statistics to the outbuffer
+ //
+
+ OutputBuffer->Signature = PERF_RESULTS_SIGNATURE;
+ OutputBuffer->ResultsExist = TRUE;
+ OutputBuffer->Mode = Perform->PerformMode;
+ OutputBuffer->PacketSize = Perform->PacketSize;
+ OutputBuffer->PacketCount = Perform->NumberOfPackets;
+ OutputBuffer->Milliseconds = Perform->PerfSendTotalTime.LowPart;
+ OutputBuffer->Sends = Perform->SendCount;
+ OutputBuffer->SendFails = Perform->SendFailCount;
+ OutputBuffer->Receives = Perform->ReceiveCount;
+ OutputBuffer->SelfReceives = Perform->SelfReceiveCount;
+ OutputBuffer->Restarts = Perform->RestartCount;
+
+ if (Info != NULL)
+ {
+ OutputBuffer->S_Milliseconds = Info->ElapsedTime;
+ OutputBuffer->S_Sends = Info->PacketsSent;
+ OutputBuffer->S_SendFails = Info->SendErrors;
+ OutputBuffer->S_Receives = Info->PacketsReceived;
+ OutputBuffer->S_SelfReceives = Info->SelfReceives;
+ OutputBuffer->S_Restarts = Info->Restarts;
+ }
+ }
+}
+
+
+NDIS_STATUS
+TpPerfAbort(POPEN_BLOCK OpenP)
+{
+ LARGE_INTEGER DueTime;
+ PPERF_BLOCK Perform = OpenP->Perform;
+
+ //
+ // We want to stop any active client and/or server on this open
+ // instance from running the performance routines, so clear the
+ // Active flag, queue up the EndDpc function, and wait for it
+ // to finish
+ //
+
+ Perform->Active = FALSE;
+
+ DueTime.HighPart = 0xFFFFFFFF; // So it will be relative.
+ DueTime.LowPart = (ULONG)(-(ONE_SECOND));
+
+ for(;;)
+ {
+ KeCancelTimer(&Perform->PerformTimer);
+ if ( KeSetTimer(&Perform->PerformTimer,
+ DueTime,
+ &Perform->PerformEndDpc ))
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0( "TpPerfAbort: set PerformTimer while timer existed.\n");
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ //
+ // And wait for them to finish.
+ //
+
+ while ( OpenP->PerformanceTest == TRUE )
+ {
+ /* NULL */ ;
+ }
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+
diff --git a/private/ntos/ndis/testprot/tpdrvr/protocol.c b/private/ntos/ndis/testprot/tpdrvr/protocol.c
new file mode 100644
index 000000000..e45f71b2c
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpdrvr/protocol.c
@@ -0,0 +1,442 @@
+// ----------------------------
+//
+// Copyright (c) 1990 Microsoft Corporation
+//
+// Module Name:
+//
+// protocol.c
+//
+// Abstract:
+//
+// Test Protocol Indication and Completion routines called by a MAC.
+//
+// Author:
+//
+// Tom Adams (tomad) 19-Nov-1991
+//
+// Environment:
+//
+// Kernel mode, FSD
+//
+// Revision History:
+//
+// Tim Wynsma (timothyw) 4-27-94
+// Performance tests
+// 5-18-94
+// Enhancements/improvements to performance tests
+// 6-08-94
+// Perf tests chgd to client/server model
+//
+// ---------------------------
+
+#include <ndis.h>
+
+#include "tpdefs.h"
+#include "media.h"
+#include "tpprocs.h"
+
+
+
+VOID
+TestProtocolOpenComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status,
+ IN NDIS_STATUS OpenErrorStatus
+ )
+{
+ TpFuncOpenComplete( ProtocolBindingContext,Status,OpenErrorStatus );
+}
+
+
+
+VOID
+TestProtocolCloseComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status
+ )
+{
+ TpFuncCloseComplete( ProtocolBindingContext,Status );
+}
+
+
+
+VOID
+TestProtocolSendComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ )
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)ProtocolBindingContext);
+ ULONG PacketSignature;
+
+ if (OpenP->PerformanceTest)
+ {
+ TpPerfSendComplete( ProtocolBindingContext,Packet,Status );
+ }
+ else
+ {
+ //
+ // First get the signature out of the packet if it is a test prot
+ // packet.
+ //
+
+ PacketSignature = TpGetPacketSignature( Packet );
+
+ if ((( OpenP->Stress->Stressing == TRUE ) &&
+ ( OpenP->Stress->StressEnded == FALSE )) &&
+ ( PacketSignature == STRESS_PACKET_SIGNATURE ))
+ {
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ OpenP->GlobalCounters->SendComps++;
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ //
+ // If this is a stress packet, then let the stress send complete
+ // routine handle it.
+ //
+
+ TpStressSendComplete( ProtocolBindingContext,Packet,Status );
+ }
+ else
+ {
+ TpFuncSendComplete( ProtocolBindingContext,Packet,Status );
+ }
+ }
+}
+
+
+
+VOID
+TestProtocolTransferDataComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ )
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)ProtocolBindingContext);
+ PPROTOCOL_RESERVED ProtRes;
+
+ ProtRes = PROT_RES( Packet );
+
+ if (OpenP->PerformanceTest)
+ {
+ TpPrint0("TestProtocolTransferDataComplete: called while in performance test\n");
+ return;
+ }
+
+ if ((( OpenP->Stress->Stressing == TRUE ) &&
+ ( OpenP->Stress->StressEnded == FALSE )) &&
+ ( ProtRes->RequestHandle->Signature == STRESS_REQUEST_HANDLE_SIGNATURE ))
+ {
+ //
+ // The transfer data was called by the stress routines, so
+ // let them complete it.
+ //
+
+ TpStressTransferDataComplete( ProtocolBindingContext,
+ Packet,
+ Status,
+ BytesTransferred );
+ }
+ else
+ {
+ TpFuncTransferDataComplete( ProtocolBindingContext,
+ Packet,
+ Status,
+ BytesTransferred );
+ }
+}
+
+
+
+VOID
+TestProtocolResetComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status
+ )
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)ProtocolBindingContext);
+
+ if ( OpenP->Stress->Resetting == TRUE )
+ {
+ TpStressResetComplete( ProtocolBindingContext,Status );
+ }
+ else
+ {
+ TpFuncResetComplete( ProtocolBindingContext,Status );
+ }
+}
+
+
+
+VOID
+TestProtocolRequestComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS Status
+ )
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)ProtocolBindingContext);
+ PTP_REQUEST_HANDLE ReqHndl;
+ BOOLEAN StressRequest = FALSE;
+
+ if ((( OpenP->Stress->Stressing == TRUE ) &&
+ ( OpenP->Stress->StressEnded == FALSE )) &&
+ ( OpenP->StressReqHndl != NULL ))
+ {
+ if ( OpenP->StressReqHndl->u.STRESS_REQ.Request == NdisRequest )
+ {
+ StressRequest = TRUE;
+ }
+ else
+ {
+ ReqHndl = OpenP->StressReqHndl;
+
+ do
+ {
+ if ( ReqHndl->u.STRESS_REQ.NextReqHndl->u.STRESS_REQ.Request == NdisRequest )
+ {
+ StressRequest = TRUE;
+ break;
+ }
+ else
+ {
+ ReqHndl = ReqHndl->u.STRESS_REQ.NextReqHndl;
+ }
+ } while ( ReqHndl->u.STRESS_REQ.NextReqHndl != NULL );
+ }
+
+ if ( StressRequest == TRUE )
+ {
+ TpStressRequestComplete( ProtocolBindingContext,NdisRequest,Status );
+ }
+ else
+ {
+ TpFuncRequestComplete( ProtocolBindingContext,NdisRequest,Status );
+ }
+ }
+ else
+ {
+ TpFuncRequestComplete( ProtocolBindingContext,NdisRequest,Status );
+ }
+}
+
+
+
+NDIS_STATUS
+TestProtocolReceive(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)ProtocolBindingContext);
+ PUCHAR Lookahead = (PUCHAR)LookaheadBuffer;
+ PPACKET_INFO PacketInfo;
+ //
+ // STARTCHANGE
+ //
+ UINT HeaderVariance = sizeof(MEDIA_HEADER)- HeaderBufferSize;
+ //
+ // STOPCHANGE
+ //
+
+
+ //
+ // SPECIAL ENTRY. THIS MUST BE REMOVED IF WE CREATE
+ // AND TEST FOR TRUE MAC FRAMES AND OTHER RESERVED TYPES
+ //
+ switch( OpenP->Media->MediumType )
+ {
+ case NdisMedium802_5:
+ //
+ // If the Frame Control indicates that this frames is anything other than
+ // an LLC frame, we will not accept since we are not responsible for
+ // generating this frame and this is not part of our control environment
+ //
+ // In Token Ring the bit Frame Control field
+ // F F Z Z Z Z Z Z
+ // where FF must be 0 1 for an LLC PDU
+ //
+
+ if ( (((PTR_802_5)HeaderBuffer)->FC & 0xC0) != 0x40 )
+ {
+ IF_TPDBG( TP_DEBUG_INFOLEVEL_2 )
+ {
+ TpPrint1(
+ "TestProtocolReceive: Dropping 802.5 frame as we received FC Control Frame set to : 0x%2.2x\n",
+ ((PTR_802_5)HeaderBuffer)->FC );
+ }
+ return NDIS_STATUS_NOT_RECOGNIZED;
+ }
+ break;
+
+ case NdisMediumFddi:
+ //
+ // If the Frame Control indicates that this frames is anything other than
+ // an LLC frame, we will not accept since we are not responsible for
+ // generating this frame and this is not part of our control environment
+ //
+ // In FDDI the bit Frame Control field
+ // C L F F Z Z Z Z
+ // where FF must be 0 1 for an LLC PDU
+ //
+
+ if ( (((PFDDI)HeaderBuffer)->FC & 0x30) != 0x10 )
+ {
+ IF_TPDBG( TP_DEBUG_INFOLEVEL_2 )
+ {
+ TpPrint1(
+ "TestProtocolReceive: Dropping FDDI frame as we received FC Control Frame set to : 0x%2.2x\n",
+ ((PFDDI)HeaderBuffer)->FC );
+ }
+ return NDIS_STATUS_NOT_RECOGNIZED;
+ }
+ break;
+
+ default:
+ break;
+
+ }
+
+ //
+ // STARTCHANGE
+ //
+ // Adjust the look ahead buffer so that it points to
+ // the beginning of PACKET_INFO structure
+ //
+ LookaheadBuffer = (PVOID)( (PUCHAR)LookaheadBuffer + HeaderVariance );
+ LookaheadBufferSize -= HeaderVariance;
+ //
+ // STOPCHANGE
+ //
+
+ if (OpenP->PerformanceTest)
+ {
+ return TpPerfReceive( ProtocolBindingContext,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize );
+ }
+
+ PacketInfo = LookaheadBuffer;
+
+ if ((( OpenP->Stress->Stressing == TRUE ) &&
+ ( OpenP->Stress->StressEnded == FALSE )) &&
+ ( PacketInfo->Signature == STRESS_PACKET_SIGNATURE ))
+ {
+ //
+ // if so pass it to the stress receive routine.
+ //
+
+ return TpStressReceive( ProtocolBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize );
+
+ }
+ else
+ {
+ //
+ // otherwise let the functional receive routine handle it.
+ //
+ return TpFuncReceive( ProtocolBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize );
+ }
+}
+
+
+
+VOID
+TestProtocolReceiveComplete(
+ IN NDIS_HANDLE ProtocolBindingContext
+ )
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)ProtocolBindingContext);
+
+ if (OpenP->PerformanceTest)
+ {
+ return;
+ }
+
+ if (( OpenP->Stress->Stressing == TRUE ) &&
+ ( OpenP->Stress->StressEnded == FALSE ))
+ {
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ OpenP->GlobalCounters->ReceiveComps++;
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ TpStressReceiveComplete( ProtocolBindingContext );
+ }
+ else
+ {
+ TpFuncReceiveComplete( ProtocolBindingContext );
+ }
+}
+
+
+
+VOID
+TestProtocolStatus(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ )
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)ProtocolBindingContext);
+
+ if ( OpenP->Stress->Stressing == FALSE )
+ {
+ UINT SpecificStatus;
+
+ //
+ // XXX: add an expecting flag for tpstressreset.
+ //
+ // ADAMBA: Assume the buffer has a four-byte specific status.
+ //
+
+ if ( StatusBufferSize == sizeof( SpecificStatus ))
+ {
+ SpecificStatus = *(PULONG)StatusBuffer;
+
+ TpFuncStatus( ProtocolBindingContext,
+ GeneralStatus,
+ StatusBuffer,
+ StatusBufferSize );
+ }
+ }
+}
+
+
+
+VOID
+TestProtocolStatusComplete(
+ IN NDIS_HANDLE ProtocolBindingContext
+ )
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)ProtocolBindingContext);
+
+ if ( OpenP->Stress->Stressing == FALSE )
+ {
+ // XXX: add an expecting flag for tpstressreset.
+
+ TpFuncStatusComplete( ProtocolBindingContext );
+ }
+}
+
+
+
diff --git a/private/ntos/ndis/testprot/tpdrvr/sources b/private/ntos/ndis/testprot/tpdrvr/sources
new file mode 100644
index 000000000..36f776cdf
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpdrvr/sources
@@ -0,0 +1,57 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=tpdrvr
+TARGETPATH=obj
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib \
+ ..\tplib\obj\*\tplib.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib
+
+INCLUDES=..\inc;..\..\..\inc;..\..\..\..\inc
+
+SOURCES=tpdrvr.c \
+ tpreq.c \
+ protocol.c \
+ tpfunc.c \
+ stress.c \
+ strrcv.c \
+ strfunc.c \
+ tputils.c \
+ media.c \
+ packet.c \
+ perf.c \
+ buffer.c
+
+RELATIVE_DEPTH=..\..\..
+
+!IFNDEF 386_WARNING_LEVEL
+386_WARNING_LEVEL=/W3
+!ENDIF
+
+UMTYPE=nt
diff --git a/private/ntos/ndis/testprot/tpdrvr/stress.c b/private/ntos/ndis/testprot/tpdrvr/stress.c
new file mode 100644
index 000000000..c19e6a0e3
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpdrvr/stress.c
@@ -0,0 +1,2503 @@
+// *****************************
+//
+// Copyright (c) 1990 Microsoft Corporation
+//
+// Module Name:
+//
+// tpstress.c
+//
+// Abstract:
+//
+// This module implements the Test Protocol Stress routines and the
+// basic controls for stressing the MAC.
+//
+// Author:
+//
+// Tom Adams (tomad) 15-Dec-1990
+//
+// Environment:
+//
+// Kernel mode
+//
+// Revision History:
+//
+// Sanjeev Katariya(sanjeevk)
+// 3-16-93 Bug#2874: TpStressFreeResources().
+// 4-8-93 Bug#2874: Added routine TpStressFreePostResetResources() to be able to
+// call it thru the routine and its associated completion routine.
+// 4-8-1993 Added ARCNET Support
+// 5-14-1993 Bug#6583 Re-arranged and cleaned up TpStressDpc for CYCLICAL testing
+//
+// Tim Wynsma (timothyw)
+// 5-18-94 Fixed warnings; general cleanup
+//
+// ****************************
+
+#include <ndis.h>
+#include <string.h>
+
+#include "tpdefs.h"
+#include "media.h"
+#include "tpprocs.h"
+
+//
+// Forward references
+//
+
+VOID
+TpStressDpc(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SysArg1,
+ IN PVOID SysArg2
+ );
+
+VOID
+TpStressServerDpc(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SysArg1,
+ IN PVOID SysArg2
+ );
+
+VOID
+TpStressStatsDpc(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SysArg1,
+ IN PVOID SysArg2
+ );
+
+VOID
+TpStressEndReqDpc(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SysArg1,
+ IN PVOID SysArg2
+ );
+
+VOID
+TpStressFinalDpc(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SysArg1,
+ IN PVOID SysArg2
+ );
+
+VOID
+TpStressFreeClient(
+ IN POPEN_BLOCK OpenP
+ );
+
+VOID
+TpStressFreeServer(
+ IN POPEN_BLOCK OpenP
+ );
+
+VOID
+TpStressFreePostResetResources(
+ IN POPEN_BLOCK OpenP
+ );
+
+VOID
+TpStressRegister2Dpc(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SysArg1,
+ IN PVOID SysArg2
+ );
+
+//
+// ********************
+//
+
+
+NDIS_STATUS
+TpStressStart(
+ IN POPEN_BLOCK OpenP,
+ IN PSTRESS_ARGUMENTS StressArguments
+ )
+
+// --------------------
+//
+// Routine Description:
+//
+// This is the main routine of the NDIS 3.0 Stress Tool. This routine
+// opens the proper MAC adapter, creates the data structures used to
+// control the test, runs the specific test, and then cleans up.
+//
+// The flow of an actual test is controlled through a series of packet
+// protocols sent from a Client machine to any responding Server machines.
+// Initially the Client sends a REGISTER_REQ packet to an agreed upon
+// address that all servers have registered as a multicast address. Any
+// Server receiving this packet responds directly to the Client with a
+// REGISTER_RESP packet stating that the Server will participate in the
+// test. At this point the Client begins to send the actual test packets,
+// TEST_REQ, to each registered Server, who in turn responds with a
+// TEST_RESP packet. At the end of a test run the Client sends each
+// Server a STATS_REQ packet requesting that the Server print it's test
+// statistic. Finally the Client sends a TEST_END packet which causes
+// each Server to tear down it's test control data structures and end
+// the test.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+// ----------------------
+
+{
+ NDIS_STATUS Status;
+ PNDIS_PACKET Packet = NULL;
+ PSTRESS_ARGUMENTS Args = NULL;
+ PSERVER_INFO Server = NULL;
+ INT i, j;
+ INT ClientNumPackets = 100; // put in environment.
+ INT ServerNumPackets = 100;
+ UINT PacketFilter;
+ LARGE_INTEGER DueTime;
+ PPENDING PPend;
+
+ //
+ // Set the StartStarted flag to true indicating that we are running
+ // a stress test, it will be set to false later if the initialization
+ // fails. Set the stress cleanup flags Final and Ended to false.
+ // This will disable any early unexpected cleanup.
+ //
+
+ OpenP->Stress->StressStarted = TRUE;
+ OpenP->Stress->StressFinal = FALSE;
+ OpenP->Stress->StressEnded = FALSE;
+
+ //
+ // Increment the reference count on the OpenBlock stating that an async
+ // test is running and must be ended prior to closing the adapter on this
+ // open.
+ //
+
+ TpAddReference( OpenP );
+
+ //
+ // Initialize the test arguments structure using the arguments passed
+ // in from the command line.
+ //
+
+ OpenP->Stress->Arguments = StressArguments;
+
+ //
+ // Set up new Args pointer for easier access to the arguments.
+ //
+
+ Args = OpenP->Stress->Arguments;
+
+ //
+ // Initialize the random number generator.
+ //
+
+ TpSetRandom();
+
+ //
+ // Initialize the data buffer used for the data in each packet.
+ //
+
+ TpStressInitDataBuffer( OpenP,2 * OpenP->Media->MaxPacketLen );
+
+ if ( OpenP->Stress->DataBuffer[0] == NULL ||
+ OpenP->Stress->DataBuffer[1] == NULL ||
+ OpenP->Stress->DataBufferMdl[0] == NULL ||
+ OpenP->Stress->DataBufferMdl[1] == NULL )
+ {
+ TpPrint0("TpStressStart: failed to init Data Buffer\n");
+ Status = NDIS_STATUS_RESOURCES;
+ goto clean_up;
+ }
+
+ //
+ // Allocate the global counter storage and zero the counters.
+ //
+
+ Status = NdisAllocateMemory((PVOID *)&OpenP->GlobalCounters,
+ sizeof( GLOBAL_COUNTERS ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpStressStart: failed to allocate counters.\n");
+ }
+ Status = NDIS_STATUS_RESOURCES;
+ goto clean_up;
+ }
+ else
+ {
+ NdisZeroMemory((PVOID)OpenP->GlobalCounters,sizeof( GLOBAL_COUNTERS ));
+ }
+
+ NdisAllocatePacketPool( &Status,
+ &OpenP->Stress->PacketHandle,
+ 50,
+ sizeof( PROTOCOL_RESERVED ) );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ TpPrint0("TpStressStart: could not allocate OpenP packet pool\n");
+ goto clean_up;
+ }
+ else
+ {
+ OpenP->Stress->PoolInitialized = TRUE;
+ }
+
+ //
+ // Then initialize the PPENDING buffer.
+ //
+
+ TpInitializePending( OpenP->Stress->Pend );
+
+ if (( Args->MemberType == TP_SERVER ) || ( Args->MemberType == BOTH ))
+ {
+ //
+ // Allocate memory for the server storage and packet pool, initialize
+ // it and the CLIENT_INFO array contained.
+ //
+
+ Status = NdisAllocateMemory((PVOID *)&OpenP->Stress->Server,
+ sizeof( SERVER_STORAGE ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ TpPrint0("TpStressStart: could not allocate Server storage memory\n");
+ Status = NDIS_STATUS_RESOURCES;
+ goto clean_up;
+ }
+ else
+ {
+ NdisZeroMemory( OpenP->Stress->Server,sizeof( SERVER_STORAGE ));
+ }
+
+ OpenP->Stress->Server->NumClients = 0 ;
+ OpenP->Stress->Server->ActiveClients = 0;
+ OpenP->Stress->Server->PoolInitialized = FALSE;
+ OpenP->Stress->Server->PadByte = 0xFF;
+ OpenP->Stress->Server->PacketHandle = NULL;
+ OpenP->Stress->Server->TransmitPool = NULL;
+ OpenP->Stress->Server->PadLong = 0xFFFFFFFF;
+
+ for ( i=0 ; i < MAX_CLIENTS ; i++ )
+ {
+ OpenP->Stress->Server->Clients[i].ClientInstance = 0xFF;
+ OpenP->Stress->Server->Clients[i].ClientReference = 0xFF;
+ OpenP->Stress->Server->Clients[i].DataChecking = FALSE;
+ OpenP->Stress->Server->Clients[i].TestEnding = FALSE;
+ OpenP->Stress->Server->Clients[i].ServerResponseType = -1;
+ OpenP->Stress->Server->Clients[i].LastSequenceNumber = 0;
+ OpenP->Stress->Server->Clients[i].Counters = NULL;
+ }
+
+ NdisAllocatePacketPool( &Status,
+ &OpenP->Stress->Server->PacketHandle,
+ 200, // should be environment.server...
+ sizeof( PROTOCOL_RESERVED ) );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ TpPrint0("TpStressStart: could not allocate server packet pool\n");
+ goto clean_up;
+ }
+ else
+ {
+ OpenP->Stress->Server->PoolInitialized = TRUE;
+ }
+
+ //
+ // The server always gets it's TEST_RESP packets from a transmit
+ // pool, so create it now.
+ //
+
+ OpenP->Stress->Server->TransmitPool =
+ TpStressCreateTransmitPool( OpenP,
+ OpenP->Stress->Server->PacketHandle,
+ Args->PacketMakeUp,
+ TEST_RESP,
+ Args->ResponseType,
+ Args->PacketSize,
+ ServerNumPackets,
+ TRUE );
+
+ if ( OpenP->Stress->Server->TransmitPool == NULL )
+ {
+ TpPrint0("TpStressStart: could not create server transmit pool\n");
+ Status = NDIS_STATUS_RESOURCES;
+ goto clean_up;
+ }
+
+ //
+ // Set the stressing flag, thus enabling the TpStress protocol
+ // handler routines, and the stopstress flag to allow the TpStress
+ // Dpc to be queued.
+ //
+
+ OpenP->Stress->Stressing = TRUE;
+ OpenP->Stress->StopStressing = FALSE;
+
+ //
+ // Now setup the card to receive packets.
+ //
+
+ //
+ // STARTCHANGE
+ //
+ if ( OpenP->Media->MediumType == NdisMedium802_5 ) // Tokenring
+ {
+ //
+ // add the stress functional address "C0-00-00-01-00-00"
+ //
+
+ Status = TpStressSetFunctionalAddress( OpenP,
+ (PUCHAR)&OpenP->Environment->StressAddress[2],
+ FALSE );
+
+ if (( Status != NDIS_STATUS_SUCCESS ) &&
+ ( Status != NDIS_STATUS_PENDING ))
+ {
+ TpPrint0("TpStressStart: failed to set Functional Address.\n");
+ goto clean_up;
+ }
+
+ PacketFilter = NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_FUNCTIONAL;
+
+ }
+ else if (OpenP->Media->MediumType == NdisMedium802_3) // Ethernet
+ {
+ //
+ // or the stress multicast address "07-07-07-07-07-07"
+ //
+
+ Status = TpStressAddMulticastAddress( OpenP,
+ (PUCHAR)OpenP->Environment->StressAddress,
+ FALSE );
+
+ if (( Status != NDIS_STATUS_SUCCESS ) &&
+ ( Status != NDIS_STATUS_PENDING ))
+ {
+ TpPrint0("TpStressStart: failed to add Test Multicast address.\n");
+ goto clean_up;
+ }
+
+ PacketFilter = NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_MULTICAST;
+
+ }
+ else if (OpenP->Media->MediumType == NdisMediumFddi) // Fddi
+ {
+ //
+ // or the stress multicast address "07-07-07-07-07-07"
+ //
+
+ Status = TpStressAddLongMulticastAddress( OpenP,
+ (PUCHAR)OpenP->Environment->StressAddress,
+ FALSE );
+
+ if (( Status != NDIS_STATUS_SUCCESS ) &&
+ ( Status != NDIS_STATUS_PENDING ))
+ {
+ TpPrint0("TpStressStart: failed to add Test Multicast address.\n");
+ goto clean_up;
+ }
+
+ PacketFilter = NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_MULTICAST;
+
+ }
+ else if (OpenP->Media->MediumType == NdisMediumArcnet878_2) // ARCNET
+ {
+ //
+ // ARCNET does not support the concept of multicast(group) addressing.
+ // It works it two modes only, either directed or broadcast. So will use
+ // the broadcast for setting up client server connections and thereafter
+ // use the directed addresses
+ //
+ PacketFilter = NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_BROADCAST;
+ }
+ //
+ // STOPCHANGE
+ //
+
+
+ //
+ // Set the packet filter to accept the following packet types.
+ //
+
+ Status = TpStressSetPacketFilter( OpenP,PacketFilter );
+
+ if (( Status != NDIS_STATUS_SUCCESS ) &&
+ ( Status != NDIS_STATUS_PENDING ))
+ {
+ TpPrint0("TpStressStart: failed to set packet filter.\n");
+ goto clean_up;
+ }
+
+ if ( Args->MemberType == TP_SERVER )
+ {
+ //
+ // Initialize the DPC used to call TpStressServerDpc, and
+ // TpStressFinalDpc.
+ //
+
+ KeInitializeDpc(&OpenP->Stress->TpStressDpc,
+ TpStressServerDpc,
+ (PVOID)OpenP );
+
+ KeInitializeDpc(&OpenP->Stress->TpStressFinalDpc,
+ TpStressFinalDpc,
+ (PVOID)OpenP );
+
+ //
+ // and then set the flag allowing the receive handler to
+ // accept and process test packets.
+ //
+
+ Args->BeginReceives = TRUE;
+
+ //
+ // The Server's main body of work is performed in the receive
+ // handler, TpStressReceive, and the receive completion routine,
+ // TpStressReceiveComplete. Once the Client sends the END_REQ
+ // packet the server will break out of the busy loop, clean up and
+ // exit. So, for now the server simply queues a DPC at which time
+ // the server examines the stop flags, and if true, cleans up and
+ // exits.
+ //
+
+ //
+ // Queue the first instance of the DPC and return.
+ //
+
+ if ( !KeInsertQueueDpc( &OpenP->Stress->TpStressDpc, NULL, NULL) )
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0("TpStressStart failed to queue the TpStressServerDpc.\n");
+ }
+ Status = NDIS_STATUS_FAILURE;
+ goto clean_up;
+ }
+ }
+ }
+
+ if (( Args->MemberType == TP_CLIENT ) || ( Args->MemberType == BOTH ))
+ {
+ //
+ // Allocate memory for the client storage and packet pool, initialize
+ // it and the SERVER_INFO array contained.
+ //
+
+ Status = NdisAllocateMemory((PVOID *)&OpenP->Stress->Client,
+ sizeof( CLIENT_STORAGE ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ TpPrint0("TpStressStart: could not allocate client storage.\n");
+ goto clean_up;
+ }
+ else
+ {
+ NdisZeroMemory( OpenP->Stress->Client,sizeof( CLIENT_STORAGE ));
+ }
+
+ OpenP->Stress->Client->NumServers = 0 ;
+ OpenP->Stress->Client->NextServer = 0 ;
+ OpenP->Stress->Client->ActiveServers = 0;
+ OpenP->Stress->Client->PoolInitialized = FALSE;
+ OpenP->Stress->Client->PacketHandle = NULL;
+ OpenP->Stress->Client->TransmitPool = NULL;
+ OpenP->Stress->Client->PacketSize = sizeof( STRESS_PACKET );
+ OpenP->Stress->Client->BufferSize = 1;
+ OpenP->Stress->Client->SizeIncrease = OpenP->Media->MaxPacketLen/150;
+
+ for ( i=0 ; i < MAX_SERVERS ; i++ )
+ {
+ OpenP->Stress->Client->Servers[i].ServerInstance = 0xFF;
+ OpenP->Stress->Client->Servers[i].ClientReference = 0xFF;
+ OpenP->Stress->Client->Servers[i].ServerReference = 0xFF;
+ OpenP->Stress->Client->Servers[i].ServerActive = FALSE;
+ OpenP->Stress->Client->Servers[i].WindowReset = 0;
+ OpenP->Stress->Client->Servers[i].SequenceNumber = 1;
+
+ if ( Args->WindowEnabled == TRUE )
+ {
+ OpenP->Stress->Client->Servers[i].MaxSequenceNumber =
+ OpenP->Environment->WindowSize;
+ }
+ else
+ {
+ OpenP->Stress->Client->Servers[i].MaxSequenceNumber = 0xFFFFFFFF;
+ }
+
+ OpenP->Stress->Client->Servers[i].LastSequenceNumber = 0;
+ OpenP->Stress->Client->Servers[i].PacketDelay = 0;
+ OpenP->Stress->Client->Servers[i].DelayLength = Args->DelayLength;
+ OpenP->Stress->Client->Servers[i].WindowReset = 0;
+ }
+
+ NdisAllocatePacketPool( &Status,
+ &OpenP->Stress->Client->PacketHandle,
+ 200, // 1000, // should 200 be environment...
+ sizeof( PROTOCOL_RESERVED ) );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ TpPrint0("TpStressStart: could not allocate client packet pool\n");
+ goto clean_up;
+ }
+ else
+ {
+ OpenP->Stress->Client->PoolInitialized = TRUE;
+ }
+
+ if ( Args->PacketsFromPool == TRUE )
+ {
+ OpenP->Stress->Client->TransmitPool =
+ TpStressCreateTransmitPool( OpenP,
+ OpenP->Stress->Client->PacketHandle,
+ Args->PacketMakeUp,
+ TEST_REQ,
+ Args->ResponseType,
+ Args->PacketSize,
+ ClientNumPackets,
+ FALSE );
+
+ if ( OpenP->Stress->Client->TransmitPool == NULL )
+ {
+ TpPrint0("TpStressStart: could not create TP packet pool\n");
+ Status = NDIS_STATUS_RESOURCES;
+ goto clean_up;
+ }
+ }
+
+ //
+ // Initialize the DPCs to call TpStressDpc, TpStressReg2Dpc,
+ // TpStressStatsDpc, TpStressEndReqDpc and TpStressFinalDpc.
+ //
+
+ KeInitializeDpc(&OpenP->Stress->TpStressDpc,
+ TpStressDpc,
+ (PVOID)OpenP );
+
+ KeInitializeDpc(&OpenP->Stress->TpStressReg2Dpc,
+ TpStressRegister2Dpc,
+ (PVOID)OpenP );
+
+ KeInitializeDpc(&OpenP->Stress->TpStressStatsDpc,
+ TpStressStatsDpc,
+ (PVOID)OpenP );
+
+ KeInitializeDpc(&OpenP->Stress->TpStressEndReqDpc,
+ TpStressEndReqDpc,
+ (PVOID)OpenP );
+
+ KeInitializeDpc(&OpenP->Stress->TpStressFinalDpc,
+ TpStressFinalDpc,
+ (PVOID)OpenP );
+
+ //
+ // and then set the flag to enable packets being received
+ // to be handled.
+ //
+
+ Args->BeginReceives = TRUE;
+
+ //
+ // Set the stressing flag, thus enabling the TpStress protocol
+ // handler routines, and the stopstress flag to allow the
+ // TpStress Dpc to be queued.
+ //
+
+ OpenP->Stress->Stressing = TRUE;
+ OpenP->Stress->StopStressing = FALSE;
+
+ if ( Args->MemberType == TP_CLIENT )
+ {
+ //
+ // Set the packet filter to accept directed packets only.
+ //
+
+ PacketFilter = NDIS_PACKET_TYPE_DIRECTED;
+
+ Status = TpStressSetPacketFilter( OpenP,PacketFilter );
+
+ if (( Status != NDIS_STATUS_SUCCESS ) &&
+ ( Status != NDIS_STATUS_PENDING ))
+ {
+ TpPrint0("TpStressStart: failed to set packet filter.\n");
+ goto clean_up;
+ }
+ }
+
+ //
+ // We are now ready to begin the test, send several instances
+ // of the REGISTER_REQ packet to the STRESS_MULTICAST/FUNCTIONAL
+ // address.
+ //
+
+ TpPrint0("TpStress: starting search for servers\n");
+
+ PPend = OpenP->Stress->Pend;
+
+ for ( j=0;j<10;j++ )
+ {
+ //
+ // Construct the REGISTER_REQ packet and send it.
+ //
+
+ Packet = TpStressCreatePacket( OpenP,
+ OpenP->Stress->Client->PacketHandle,
+ Args->PacketMakeUp,
+ 0, // ServerInstance
+ OpenP->OpenInstance,
+ REGISTER_REQ,
+ Args->ResponseType,
+ OpenP->Environment->StressAddress,
+ sizeof( STRESS_PACKET ),
+ sizeof( STRESS_PACKET ),
+ (ULONG)j,
+ 0L,0,0,
+ Args->DataChecking );
+
+ if ( Packet == NULL )
+ {
+ TpPrint1("TpStressStart: failed to build REGISTER_REQ packet #%d\n",j);
+ Status = NDIS_STATUS_RESOURCES;
+ goto clean_up;
+ }
+
+ TpStressSend( OpenP,Packet,NULL );
+
+ //
+ // Pause momentarily before sending the next packet.
+ //
+
+ for (;;)
+ {
+ DueTime.HighPart = -1; // So it will be relative.
+ DueTime.LowPart = (ULONG)(-4 * ONE_HUNDREDTH_SECOND );
+ KeDelayExecutionThread(KernelMode, TRUE, &DueTime);
+
+ NdisAcquireSpinLock( &PPend->SpinLock );
+ if (PPend->PendingPackets)
+ {
+ NdisReleaseSpinLock( &PPend->SpinLock );
+ }
+ else
+ {
+ NdisReleaseSpinLock( &PPend->SpinLock );
+ break;
+ }
+ }
+
+ }
+ TpPrint0("TpStress: done with search for servers\n");
+
+ //
+ // If no servers have registered there is no point in running
+ // the test, clean up and return.
+ //
+
+ if ( OpenP->Stress->Client->NumServers == 0 )
+ {
+ TpPrint0("TpStressStart: No servers registered, exiting\n");
+ Status = TP_STATUS_NO_SERVERS;
+ goto clean_up;
+ }
+
+ //
+ // Show what servers are registered.
+ //
+
+ for ( i=0;i<(INT)OpenP->Stress->Client->NumServers;i++ )
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint2("\nServer %d: open %d, ",
+ i, OpenP->Stress->Client->Servers[i].ServerInstance);
+
+ //
+ // STARTCHANGE
+ //
+ if ( OpenP->Media->MediumType == NdisMediumArcnet878_2 )
+ {
+ TpPrint1("address %02X\n", OpenP->Stress->Client->Servers[i].Address[0]);
+ }
+ else
+ {
+ TpPrint6("address %02X-%02X-%02X-%02X-%02X-%02X\n",
+ OpenP->Stress->Client->Servers[i].Address[0],
+ OpenP->Stress->Client->Servers[i].Address[1],
+ OpenP->Stress->Client->Servers[i].Address[2],
+ OpenP->Stress->Client->Servers[i].Address[3],
+ OpenP->Stress->Client->Servers[i].Address[4],
+ OpenP->Stress->Client->Servers[i].Address[5]);
+ }
+ //
+ // STOPCHANGE
+ //
+ }
+ }
+
+ //
+ // Initialize the multi-purpose counter used for the up-for-air
+ // delay, stats dpc and end dpc, and the Register_Req2 counter.
+ //
+
+ OpenP->Stress->FirstIteration = TRUE;
+ OpenP->Stress->Counter = 0;
+ OpenP->Stress->Reg2Counter = 0;
+
+ //
+ // Queue the first instance of the Stress DPC.
+ //
+
+ DueTime.HighPart = -1; // So it will be relative.
+ DueTime.LowPart = (ULONG)(- ( 5 * ONE_SECOND ));
+
+ if ( KeSetTimer(&OpenP->Stress->TpStressTimer,
+ DueTime,
+ &OpenP->Stress->TpStressDpc ))
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0("TpStressStart failed to queue the TpStressDpc.\n");
+ }
+ Status = NDIS_STATUS_FAILURE;
+ goto clean_up;
+ }
+
+ //
+ // Queue the first instance of the Register2 DPC and return.
+ //
+
+ if ( !KeInsertQueueDpc( &OpenP->Stress->TpStressReg2Dpc,
+ NULL,
+ NULL ))
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0("TpStressStart failed to queue the TpStressReg2Dpc.\n");
+ }
+ Status = NDIS_STATUS_FAILURE;
+ goto clean_up;
+ }
+ }
+ return NDIS_STATUS_PENDING;
+
+
+clean_up:
+
+ IF_TPDBG ( TP_DEBUG_DISPATCH )
+ {
+ TpPrint1("TpStressStart failed to start: returned %s\n", TpGetStatus( Status ));
+ }
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ if ( OpenP->Stress->StressIrp != NULL )
+ {
+ OpenP->Stress->StressIrp->IoStatus.Status = Status;
+ }
+
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ return Status;
+}
+
+
+
+VOID
+TpStressDpc(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SysArg1,
+ IN PVOID SysArg2
+ )
+
+// -------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// -----------
+
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)DeferredContext);
+ PSTRESS_ARGUMENTS Args;
+ PCLIENT_STORAGE Client;
+ NDIS_STATUS Status;
+ UCHAR ServerNum;
+ PSERVER_INFO Server;
+ BOOLEAN ContinueSending = TRUE;
+ LARGE_INTEGER DueTime;
+
+ UNREFERENCED_PARAMETER( Dpc );
+ UNREFERENCED_PARAMETER( SysArg1 );
+ UNREFERENCED_PARAMETER( SysArg2 );
+
+ Args = OpenP->Stress->Arguments;
+ Client = OpenP->Stress->Client;
+
+ //
+ // This is the main loop of a stress test, in this loop RANDOM or
+ // FIXED size packets are sent to each server depending on the delay
+ // intervals and window size. Packets are sent one to a server, as
+ // the client loops through each server, and then repeats, if a
+ // window is closed for a given server, or the packet delay has not
+ // been reached that server will be skipped over. The client will
+ // continue to loop thru the servers sending packets until either
+ // all the packets have been sent, or all the iterations have been
+ // iterated. NOTE: setting the ServerActive flag to false on all
+ // the servers will also result in the test ending.
+ //
+
+ //
+ // If this is the beginning of the test, get the Start Time
+ // for later statistics computation.
+ //
+
+ if ( OpenP->Stress->FirstIteration == TRUE )
+ {
+ KeQuerySystemTime( &OpenP->Stress->StartTime );
+ OpenP->Stress->FirstIteration = FALSE;
+ }
+
+ //
+ // If the Stress Irp has been cancelled then clean up and leave.
+ //
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ if (( OpenP->Stress->StressIrp == NULL ) ||
+ ( OpenP->Stress->StressIrp->Cancel == TRUE ))
+ {
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ OpenP->Stress->StopStressing = TRUE;
+ }
+ else if ( Client->ActiveServers <= 0 )
+ {
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ //
+ // There are no more active servers so just end the test here.
+ //
+
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint1("TpStressDpc: WARNING - Client Open Instance %d ending test.\n",
+ OpenP->OpenInstance);
+ TpPrint0("\tNo remaining active stress servers\n");
+ }
+
+ OpenP->Stress->StopStressing = TRUE;
+ }
+ else if (( Args->PacketType == RANDOMSIZE ) ||
+ ( Args->PacketType == FIXEDSIZE ))
+ {
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ //
+ // Start looping sending packets until one of the conditions
+ // is met for stopping and requeueing a new DPC to send later.
+ // The possible conditions are Packet Delay not met, Window for
+ // a given server is closed or there are no available packets.
+ //
+
+ while ( ContinueSending == TRUE )
+ {
+ //
+ // As long as there are still packets to send or loops to
+ // iterate continue sending packets.
+ //
+
+ if (( Args->Iterations++ >= Args->TotalIterations ) ||
+ ( Args->AllPacketsSent == TRUE ))
+ {
+ break;
+ }
+ else
+ {
+ //
+ // Set the packets sent flag to true, it will be reset to
+ // false later in the loop if there are really packets left
+ // to send.
+ //
+
+ Args->AllPacketsSent = TRUE;
+
+ //
+ // Now loop through each of the servers starting with the
+ // server we left of with at the end of the last DPC.
+ //
+
+ for ( ServerNum = Client->NextServer;
+ ServerNum < Client->NumServers;
+ ServerNum++ )
+ {
+ Server = &Client->Servers[ServerNum];
+
+ //
+ // If this server is still active and we have not sent all
+ // the packets required to this it, then continue with
+ // the send process.
+ //
+
+ if (( Server->ServerActive == TRUE ) &&
+ ( Server->SequenceNumber <= Args->TotalPackets ))
+ {
+ //
+ // Set the flag indicating there are more packets
+ // to be sent.
+ //
+
+ Args->AllPacketsSent = FALSE;
+
+ //
+ // Now check if the Client has waited long enough to
+ // send another packet to this server.
+ //
+
+ if (( Server->PacketDelay++ >= Server->DelayLength ) &&
+ ( Server->SequenceNumber <= Server->MaxSequenceNumber ))
+ {
+ //
+ // And if so, allocate a packet and send it to
+ // the server.
+ //
+
+ Status = TpStressClientSend(OpenP,
+ Client->PacketHandle,
+ Client->TransmitPool,
+ Server->Address,
+ OpenP->OpenInstance,
+ Server->ServerInstance,
+ TEST_REQ,
+ Server->SequenceNumber,
+ 0, // MaxSeqNum: not used in TEST_REQ pkts.
+ Server->ClientReference,
+ Server->ServerReference,
+ Client->PacketSize,
+ Client->BufferSize );
+
+ if ( Status == NDIS_STATUS_SUCCESS )
+ {
+ Server->SequenceNumber++;
+ Server->PacketDelay = 0;
+ if ( Args->DelayType == RANDOMDELAY )
+ {
+ Server->DelayLength = TpGetRandom(0,Args->DelayLength);
+ }
+ }
+ else
+ {
+ //
+ // No packets available to send now.
+ // Queue a new DPC and exit.
+ //
+
+ ContinueSending = FALSE;
+ break;
+ }
+
+ //
+ // If the window is not open, check to see if the
+ // server is presumed dead.
+ //
+
+ }
+ else if (( Args->WindowEnabled == TRUE ) &&
+ ( Server->PacketDelay > MAX_PACKET_DELAY ))
+ { // Put MaxPacketDelay in environment?
+ //
+ // We have reset this servers window the maximum
+ // number of times and it still is not responding
+ // so we will remove it from the active servers.
+ //
+
+ if ( Server->WindowReset >= MAX_WINDOW_RESETS )
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint2(
+ "TpStressDpc: WARNING - Client Open Instance %d marking Server %d as Inactive.\n",
+ OpenP->OpenInstance,Server->ServerInstance);
+ }
+
+ Server->ServerActive = FALSE;
+ Client->ActiveServers--;
+
+ //
+ // This server may still be alive, so reset the
+ // window to the initial state causing WINDOW_SIZE
+ // more packets to be sent to the server on the
+ // next pass through the loop.
+ //
+
+ }
+ else
+ {
+ //
+ // The packet delay for this server has exceeded
+ // the maximum packet delay, and we are sending
+ // with windowing enabled, so blast out Window
+ // Size more packets.
+ //
+
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint1("TpStressDpc: WARNING - Client Open Instance %d\n",
+ OpenP->OpenInstance);
+ TpPrint2("\tincreasing Server %d MaxSequenceNumber to %d\n",
+ Server->ServerInstance,
+ Server->MaxSequenceNumber +
+ OpenP->Environment->WindowSize );
+ }
+
+ Server->MaxSequenceNumber += OpenP->Environment->WindowSize;
+
+ Server->PacketDelay = 0;
+ Server->WindowReset++;
+ Client->NextServer++;
+
+ ContinueSending = FALSE;
+ break;
+ }
+ Client->NextServer++;
+ break;
+ }
+ else
+ {
+ //
+ // Either the window for this server is closed,
+ // or the delay has not expired. Queue a new DPC,
+ // and exit. We will start with the next server
+ // with the next DPC.
+ //
+
+ Client->NextServer++;
+ ContinueSending = FALSE;
+ break;
+ }
+ }
+ }
+
+ //
+ // We have come to the end of the server array, start again
+ // at the beginning on the next FOR loop.
+ //
+
+ Client->NextServer = 0;
+ }
+ }
+ }
+ else // PacketType == CYCLICAL
+ {
+ //
+ // STARTCHANGE
+ //
+ // SanjeevK
+ //
+ // This piece of code contain one too many nested loops. It needs to be cleaned
+ // The cleanup will be instituted at a later date. For the time being the
+ // loop control will be clearly marked with entry and exit conditions
+ //
+
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ if ( Client->PacketSize == 0 )
+ {
+ //
+ // We have just started the test, so set the PacketSize and
+ // BufferSize to their minimum startimg sizes.
+ //
+
+ Client->PacketSize = sizeof( STRESS_PACKET );
+ Client->BufferSize = 1;
+ }
+
+ //
+ // SanjeevK
+ //
+ // MARK EXTERIOR CONTROL
+ //
+ // NOTE
+ //
+ // All loops have control exit conditions. The code has been semi-cleaned
+ // for recognizable operation. Breaks of jumping between control loops
+ // has been minimized
+ //
+
+ //
+ // This condition if valid gets executed once. If the total iteration count
+ // is greater than 1, the work is DPCd and on re-entering takes on the
+ // values set in the control global arguments. That is why it is very important
+ // to not set the global control values on entry but on exit of a control
+ // since work can be DPC'd from any part within the control loops.
+ //
+
+ if ( Args->Iterations < Args->TotalIterations )
+ {
+ //
+ // FIRST CONTROL LOOP.
+ // Execute until we exceed MAX_PACKET_LENGTH.
+ //
+ while ( Client->PacketSize <= OpenP->Media->MaxPacketLen )
+ {
+ //
+ // SECOND CONTROL LOOP.
+ // Execute till the buffer size has gone
+ // thru a cycle of ( 1,Current Packet Size )
+ //
+ while ( Client->BufferSize <= Client->PacketSize )
+ {
+ //
+ // Disable the above while loop if...
+ //
+
+ if ( Args->PacketMakeUp != KNOWN )
+ {
+ Client->BufferSize = Client->PacketSize;
+ Client->SizeIncrease = 1;
+ }
+
+ //
+ // THIRD CONTROL LOOP
+ // Execute the same code path for all registered/valid stress servers
+ //
+ for (ServerNum=Client->NextServer;ServerNum < Client->NumServers;ServerNum++)
+ {
+ Server = &Client->Servers[ServerNum];
+
+ //
+ // If this server is still active then
+ // continue with the send process.
+ //
+
+ if ( Server->ServerActive == TRUE )
+ {
+ if (( Server->PacketDelay++ >= Server->DelayLength ) &&
+ ( Server->SequenceNumber <= Server->MaxSequenceNumber ))
+ {
+ Status = TpStressClientSend(OpenP,
+ Client->PacketHandle,
+ Client->TransmitPool,
+ Server->Address,
+ OpenP->OpenInstance,
+ Server->ServerInstance,
+ TEST_REQ,
+ Server->SequenceNumber,
+ 0, // MaxSeqNum: not used in TEST_REQ.
+ Server->ClientReference,
+ Server->ServerReference,
+ Client->PacketSize,
+ Client->BufferSize );
+
+ if ( Status == NDIS_STATUS_SUCCESS )
+ {
+ Server->SequenceNumber++;
+ Server->PacketDelay = 0;
+
+ if (Args->DelayType == RANDOMDELAY)
+ {
+ Server->DelayLength = TpGetRandom(0,Args->DelayLength);
+ }
+ }
+ else
+ {
+ //
+ // No packets are available to send now,
+ // So set the flag to queue a new DPC
+ // and exit.
+ //
+ goto breakout;
+ } // END of if ( Status == NDIS_STATUS_SUCCESS )
+ }
+ else if (( Args->WindowEnabled == TRUE ) &&
+ ( Server->PacketDelay > MAX_PACKET_DELAY ))
+ {
+ //
+ // We have reset this servers window the maximum
+ // number of times and it still is not responding
+ // so we will remove it from the active servers.
+ //
+
+ if ( Server->WindowReset >= MAX_WINDOW_RESETS )
+ {
+ //
+ // Since the window size for the server has exceeded
+ // the maximum times it could have been reset, mark this
+ // server as inactive and decrement the number of
+ // active servers by one
+ //
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint2(
+ "TpStressDpc: WARNING - Client Open Instance %d marking Server %d as Inactive.\n",
+ OpenP->OpenInstance,Server->ServerInstance);
+ }
+
+ Server->ServerActive = FALSE;
+ Client->ActiveServers--;
+ }
+ else
+ {
+ //
+ // This server may still be alive, so reset the
+ // window to the initial state causing WINDOW_SIZE
+ // more packets to be sent to the server on the
+ // next pass through the loop.
+
+ //
+ // The packet delay for this server has exceeded
+ // the maximum packet delay, and we are sending
+ // with windowing enabled, so blast out
+ // WindowSize more packets.
+ //
+
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint1("TpStressDpc: WARNING - Client Open Instance %d\n",
+ OpenP->OpenInstance);
+ TpPrint2("\tincreasing Server %d MaxSequenceNumber to %d\n",
+ Server->ServerInstance,
+ Server->MaxSequenceNumber +
+ OpenP->Environment->WindowSize );
+ }
+
+ Server->MaxSequenceNumber += OpenP->Environment->WindowSize;
+
+ Server->PacketDelay = 0;
+ Server->WindowReset++;
+
+ } // END of if ( Server->WindowReset >= MAX_WINDOW_RESETS )
+
+ Client->NextServer++;
+ goto breakout;
+ }
+ else
+ {
+ //
+ // Either the window for this server is closed
+ // or the delay has not expired yet. Queue a
+ // new DPC and exit. We will start with the
+ // next server with the next DPC.
+ //
+
+ Client->NextServer++;
+ ContinueSending = FALSE;
+ goto breakout;
+
+ } // END of if (( Args->WindowEnabled == TRUE ) &&
+ // ( Server->PacketDelay > MAX_PACKET_DELAY ))
+ } // END of if ( Server->ServerActive == TRUE )
+ } // END of FOR loop. Indicates we have dealt with all servers in the list
+
+ //
+ // CONTROL EXIT CONDITION
+ //
+ Client->NextServer = 0;
+
+ //
+ // SanjeevK
+ //
+ // NOTE
+ //
+ // This code section was badly nested within another looping section
+ // This simply needs to reside outside the loop
+ //
+ // ORIGINAL COMMENT
+ //
+ // If we have succesfully sent this packet
+ // to the last server in the list, then
+ // move on to the next packetsize/buffersize
+ // combination.
+ //
+ //
+ Client->BufferSize += Client->SizeIncrease;
+
+ } // END of while ( Client->BufferSize <= Client->PacketSize )
+
+ //
+ // CONTROL EXIT CONDITION
+ //
+ Client->BufferSize = 1;
+ Client->PacketSize += Client->SizeIncrease;
+
+ } // END of while ( Client->PacketSize <= OpenP->Media->MaxPacketLen )
+
+ //
+ // CONTROL EXIT CONDITION
+ //
+ Client->PacketSize = sizeof( STRESS_PACKET);
+
+ //
+ // We have completed one full iteration of CYCLICAL
+ // packets, inc the counter.
+ //
+
+ Args->Iterations++;
+
+ } // END of if ( Args->Iterations < Args->TotalIterations )
+
+ } // END of the else PacketType == CYCLICAL
+
+breakout:
+
+ //
+ // If the StopStress flag has been set by a command line call, or
+ // we have sent all the packets requested or completed the required
+ // number of iterations, then end the stress routine and clean up.
+ //
+
+ if (( OpenP->Stress->StopStressing == TRUE ) ||
+ ( Args->AllPacketsSent == TRUE ) ||
+ ( Args->Iterations >= Args->TotalIterations ))
+ {
+ //
+ // Set the stop stress flag to halt the Register2Dpc routine
+ // now, if it was already set this will do nothing.
+ //
+
+ OpenP->Stress->StopStressing = TRUE;
+ OpenP->Stress->Counter = 0;
+
+ //
+ // Set the time for when to queue the TpStressStatsDpc routine.
+ //
+
+ DueTime.HighPart = -1; // So it will be relative.
+ DueTime.LowPart = (ULONG)(- ( 5 * ONE_SECOND ));
+
+ if ( KeSetTimer(&OpenP->Stress->TpStressTimer,
+ DueTime,
+ &OpenP->Stress->TpStressStatsDpc ))
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0("TpStressDpc set StressEnd timer while timer existed.\n");
+ }
+ }
+ }
+ else
+ {
+ //
+ // Otherwise the test should continue, so insert the next timer in
+ // the timer queue and exit. This will queue the next instance of
+ // the TpStressDpc routine when the timer goes off.
+ //
+
+ if ( OpenP->Stress->Counter == OpenP->Environment->StressDelayInterval )
+ {
+ DueTime.HighPart = -1; // So it will be relative.
+ DueTime.LowPart = (ULONG) (- ((LONG) OpenP->Environment->UpForAirDelay ));
+ OpenP->Stress->Counter = 0;
+ }
+ else
+ {
+ DueTime.HighPart = -1; // So it will be relative.
+ DueTime.LowPart = (ULONG)(- ((LONG) OpenP->Environment->StandardDelay ));
+ OpenP->Stress->Counter++;
+ }
+
+ if ( KeSetTimer(&OpenP->Stress->TpStressTimer,
+ DueTime,
+ &OpenP->Stress->TpStressDpc ))
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0("TpStressDpc set Stress timer while timer existed.\n");
+ }
+ }
+ }
+}
+
+
+
+VOID
+TpStressServerDpc(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SysArg1,
+ IN PVOID SysArg2
+ )
+
+// ---------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// ---------
+
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)DeferredContext);
+ LARGE_INTEGER DueTime;
+
+
+ UNREFERENCED_PARAMETER( Dpc );
+ UNREFERENCED_PARAMETER( SysArg1 );
+ UNREFERENCED_PARAMETER( SysArg2 );
+
+ DueTime.HighPart = -1; // relative time.
+ DueTime.LowPart = (ULONG)(- ( ONE_SECOND ));
+
+ //
+ // If the Stress Irp has been cancelled then clean up and leave.
+ //
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ if (( OpenP->Stress->StressIrp == NULL ) ||
+ ( OpenP->Stress->StressIrp->Cancel == TRUE ))
+ {
+ OpenP->Stress->StopStressing = TRUE;
+ }
+
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ if ( OpenP->Stress->StopStressing == TRUE )
+ {
+ //
+ // Either we have received an END_TEST packet from the last
+ // Client we are stressing, or we have received a command from
+ // the user interface to stop the test, set the IoStatusBlock
+ // status field, and end it.
+ //
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ if ( OpenP->Stress->StressIrp != NULL )
+ {
+ OpenP->Stress->StressIrp->IoStatus.Status = NDIS_STATUS_SUCCESS;
+ }
+
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ if ( KeSetTimer(&OpenP->Stress->TpStressTimer,
+ DueTime,
+ &OpenP->Stress->TpStressFinalDpc ))
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0("TpStressServerDpc set Stress timer while timer existed.\n");
+ }
+ }
+ }
+ else
+ {
+ //
+ // Otherwise the test should continue, so insert the next timer in
+ // the timer queue and exit. This will queue the next instance of
+ // the TpStressServerDpc routine when the timer goes off.
+ //
+
+ if ( KeSetTimer(&OpenP->Stress->TpStressTimer,
+ DueTime,
+ &OpenP->Stress->TpStressDpc ))
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0("TpStressServerDpc set Stress timer while timer existed.\n");
+ }
+ }
+ }
+}
+
+
+
+VOID
+TpStressStatsDpc(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SysArg1,
+ IN PVOID SysArg2
+ )
+
+// ---------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// -----------
+
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)DeferredContext);
+ PSTRESS_ARGUMENTS Args;
+ PCLIENT_STORAGE Client;
+ UCHAR ServerNum;
+ LARGE_INTEGER DueTime;
+ PNDIS_PACKET Packet;
+
+
+ UNREFERENCED_PARAMETER( Dpc );
+ UNREFERENCED_PARAMETER( SysArg1 );
+ UNREFERENCED_PARAMETER( SysArg2 );
+
+ Args = OpenP->Stress->Arguments;
+ Client = OpenP->Stress->Client;
+
+ //
+ // If the Stress Irp has been cancelled then skip the stats requesting.
+ //
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ if (( OpenP->Stress->StressIrp != NULL ) &&
+ ( OpenP->Stress->StressIrp->Cancel == FALSE ))
+ {
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ //
+ // Write the client statistics to the Results buffer, and send
+ // STATS_REQ packets to each server request the servers test stats.
+ //
+
+ if ( OpenP->Stress->Counter == 0 )
+ {
+ KeQuerySystemTime( &OpenP->Stress->EndTime );
+ TpCopyClientStatistics( OpenP );
+ TpPrintClientStatistics( OpenP );
+ }
+
+ for ( ServerNum=0 ; ServerNum < Client->NumServers ; ServerNum++ )
+ {
+ Packet = TpStressCreatePacket( OpenP,
+ Client->PacketHandle,
+ Args->PacketMakeUp,
+ Client->Servers[ServerNum].ServerInstance,
+ OpenP->OpenInstance,
+ STATS_REQ,
+ Args->ResponseType,
+ Client->Servers[ServerNum].Address,
+ 64, 32,
+ OpenP->Stress->Counter,
+ OpenP->Stress->Counter,
+ Client->Servers[ServerNum].ClientReference,
+ Client->Servers[ServerNum].ServerReference,
+ Args->DataChecking );
+
+ if ( Packet == NULL )
+ {
+ IF_TPDBG( TP_DEBUG_RESOURCES )
+ {
+ TpPrint0("TpStressDpc: failed to create STATS_REQ Packet\n");
+ }
+ }
+ else
+ {
+ TpStressSend( OpenP,Packet,NULL );
+ }
+ }
+ }
+ else
+ {
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ OpenP->Stress->StopStressing = TRUE;
+ }
+
+ if ( OpenP->Stress->Counter++ < 10 )
+ {
+ //
+ // requeue the StatsDpc.
+ //
+
+ DueTime.HighPart = -1; // So it will be relative.
+ DueTime.LowPart = (ULONG)(- ( ONE_TENTH_SECOND ));
+
+ if ( KeSetTimer(&OpenP->Stress->TpStressTimer,
+ DueTime,
+ &OpenP->Stress->TpStressStatsDpc ))
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0("TpStressDpc set StressEnd timer while timer existed.\n");
+ }
+ }
+ }
+ else
+ {
+ //
+ // reset the multipurpose counter.
+ //
+
+ OpenP->Stress->Counter = 0;
+
+ //
+ // Then set the next timer for the EndDpc.
+ //
+
+ DueTime.HighPart = -1; // So it will be relative.
+ DueTime.LowPart = (ULONG)(- ( 5 * ONE_SECOND ));
+
+ if ( KeSetTimer(&OpenP->Stress->TpStressTimer,
+ DueTime,
+ &OpenP->Stress->TpStressEndReqDpc ))
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0("TpStressDpc set Stress timer while timer existed.\n");
+ }
+ }
+ }
+}
+
+
+
+VOID
+TpStressEndReqDpc(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SysArg1,
+ IN PVOID SysArg2
+ )
+
+// -------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// -------
+
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)DeferredContext);
+ PSTRESS_ARGUMENTS Args;
+ PCLIENT_STORAGE Client;
+ UCHAR ServerNum;
+ LARGE_INTEGER DueTime;
+ PNDIS_PACKET Packet;
+
+
+ UNREFERENCED_PARAMETER( Dpc );
+ UNREFERENCED_PARAMETER( SysArg1 );
+ UNREFERENCED_PARAMETER( SysArg2 );
+
+ Args = OpenP->Stress->Arguments;
+ Client = OpenP->Stress->Client;
+
+ //
+ // If the Stress Irp has been cancelled then skip the stats requesting.
+ //
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ if (( OpenP->Stress->StressIrp != NULL ) &&
+ ( OpenP->Stress->StressIrp->Cancel == FALSE ))
+ {
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ //
+ // Send an end request packet to each of the servers.
+ //
+
+ for ( ServerNum=0;ServerNum<Client->NumServers;ServerNum++ )
+ {
+ Packet = TpStressCreatePacket( OpenP,
+ Client->PacketHandle,
+ Args->PacketMakeUp,
+ Client->Servers[ServerNum].ServerInstance,
+ OpenP->OpenInstance,
+ END_REQ,
+ Args->ResponseType,
+ Client->Servers[ServerNum].Address,
+ 64, 32,
+ OpenP->Stress->Counter,
+ OpenP->Stress->Counter,
+ Client->Servers[ServerNum].ClientReference,
+ Client->Servers[ServerNum].ServerReference,
+ Args->DataChecking );
+
+ if ( Packet == NULL )
+ {
+ IF_TPDBG( TP_DEBUG_RESOURCES )
+ {
+ TpPrint0("TpStressDpc: failed to create END_REQ Packet\n");
+ }
+ }
+ else
+ {
+ TpStressSend( OpenP,Packet,NULL );
+ }
+ }
+ }
+ else
+ {
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ OpenP->Stress->StopStressing = TRUE;
+ }
+
+ if ( OpenP->Stress->Counter++ < 10 )
+ {
+ //
+ // requeue the StatsDpc.
+ //
+
+ DueTime.HighPart = -1; // So it will be relative.
+ DueTime.LowPart = (ULONG)(- ( ONE_TENTH_SECOND ));
+
+ if ( KeSetTimer(&OpenP->Stress->TpStressTimer,
+ DueTime,
+ &OpenP->Stress->TpStressEndReqDpc ))
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0("TpStressDpc set StressEnd timer while timer existed.\n");
+ }
+ }
+ }
+ else
+ {
+ //
+ // reset the multi-purpose counter.
+ //
+
+ OpenP->Stress->Counter = 0;
+
+ //
+ // Then set the next timer for the EndDpc.
+ //
+
+ DueTime.HighPart = -1; // So it will be relative.
+ DueTime.LowPart = (ULONG)(- ( 10 * ONE_SECOND ));
+
+ if ( KeSetTimer(&OpenP->Stress->TpStressTimer,
+ DueTime,
+ &OpenP->Stress->TpStressFinalDpc ))
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0("TpStressDpc set Stress timer while timer existed.\n");
+ }
+ }
+ }
+}
+
+
+
+VOID
+TpStressFinalDpc(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SysArg1,
+ IN PVOID SysArg2
+ )
+
+// --------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// --------
+
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)DeferredContext);
+ NDIS_STATUS Status;
+ PSTRESS_ARGUMENTS Args = NULL;
+ PSERVER_INFO Server = NULL;
+ UINT i;
+ LARGE_INTEGER DueTime;
+
+
+ UNREFERENCED_PARAMETER( Dpc );
+ UNREFERENCED_PARAMETER( SysArg1 );
+ UNREFERENCED_PARAMETER( SysArg2 );
+
+ Args = OpenP->Stress->Arguments;
+
+ //
+ // Check to see if all packets sent on this open have completed,
+ // If they have not all completed see if we have waited long
+ // enough. long enough being 10 one second delayed cycles
+ // through TpStressEndDcp.
+ //
+
+ if ((((( Args->MemberType == TP_CLIENT ) &&
+ ( Args->PacketsFromPool == FALSE )) &&
+ ( OpenP->Stress->Pend->PendingPackets != 0 ))
+
+ //
+ // We are a Client getting each packet from the NdisPacketPool and
+ // all the packets from the NdisPacketPool have not completed, or ...
+ //
+
+ ||
+
+ (( Args->PacketsFromPool == TRUE ) &&
+ ( OpenP->Stress->Pend->PacketPendNumber !=
+ OpenP->Stress->Pend->PacketCompleteNumber )))
+
+ //
+ // We are getting the packets from the TP_PACKET_POOL, and
+ // all the TpPoolPackets that pended have not completed and ...
+ //
+
+ &&
+
+ ( OpenP->Stress->Counter++ < 10 ))
+ {
+
+ //
+ // We have not waited through 10 cycles of TpStressFinalDpc
+ // Then reset the timer for this dpc to try again later.
+ //
+
+ DueTime.HighPart = -1; // So it will be relative.
+ DueTime.LowPart = (ULONG)(- ( 1 * ONE_SECOND ));
+
+ if ( KeSetTimer(&OpenP->Stress->TpStressTimer,
+ DueTime,
+ &OpenP->Stress->TpStressFinalDpc ))
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0("TpStressDpc set Stress timer while timer existed.\n");
+ }
+ }
+ }
+ else
+ {
+ //
+ // Time to clean up, so first check if there are any packets
+ // still in the pending queue representing packets that were
+ // sent, pended, and have not completed. We only do this if
+ // we are a Client, the server only part is handled at the
+ // End_Req packet receipt time.
+ //
+
+ if (( Args->MemberType != TP_SERVER ) &&
+ ( OpenP->Stress->Pend->PendingPackets != 0 ))
+ {
+ //
+ // There are packets in the pend queue, so print out there
+ // addresses, and break.
+ //
+
+ IF_TPDBG( TP_DEBUG_DPC )
+ {
+ TpPrint1("TpStressFinalDpc: The following %d packets are still in the\n",
+ OpenP->Stress->Pend->PendingPackets);
+ TpPrint1(" Client's Pend Queue for Open Instance %d.\n",
+ OpenP->OpenInstance);
+ TpPrint1(" Pend Queue = %lX\n\n", OpenP->Stress->Pend);
+
+ for ( i=0 ; i<NUM_PACKET_PENDS ; i++ )
+ {
+ if (( OpenP->Stress->Pend->Packets[i] != NULL ) &&
+ ( OpenP->Stress->Pend->Packets[i] != (PNDIS_PACKET)-1 ))
+ {
+ TpPrint1("\t\t%lX\n", OpenP->Stress->Pend->Packets[i]);
+ }
+ }
+// TpBreakPoint();
+ }
+ TpInitializePending( OpenP->Stress->Pend );
+ }
+
+ //
+ // Write the stress results into the ioctl buffer to be passed
+ // back to the user application.
+ //
+
+ TpStressWriteResults( OpenP );
+
+ //
+ // if we have set a functional address or added a multicast
+ // address then clear it now.
+ //
+
+ if ( Args->MemberType != TP_CLIENT )
+ {
+ if ( OpenP->Media->MediumType == NdisMedium802_5 ) // Token Ring
+ {
+ Status = TpStressSetFunctionalAddress( OpenP,
+ (PUCHAR)NULL_ADDRESS,
+ TRUE );
+
+ if (( Status != NDIS_STATUS_SUCCESS ) &&
+ ( Status != NDIS_STATUS_PENDING ))
+ {
+ IF_TPDBG( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1(
+ "TpStressServerCleanUp: failed to clear Functional Address--Status = %s\n",
+ TpGetStatus(Status));
+ }
+ }
+ }
+ else if (OpenP->Media->MediumType == NdisMedium802_3) // Ethernet
+ {
+ Status = TpStressAddMulticastAddress( OpenP,
+ (PUCHAR)NULL_ADDRESS,
+ TRUE );
+
+ if (( Status != NDIS_STATUS_SUCCESS ) &&
+ ( Status != NDIS_STATUS_PENDING ))
+ {
+ IF_TPDBG( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1(
+ "TpStressServerCleanUp: failed to delete Multicast Address--Status = %s\n",
+ TpGetStatus(Status));
+ }
+ }
+ }
+ else if (OpenP->Media->MediumType == NdisMediumFddi) // Fddi
+ {
+ Status = TpStressAddLongMulticastAddress( OpenP,
+ (PUCHAR)NULL_ADDRESS,
+ TRUE );
+
+ if (( Status != NDIS_STATUS_SUCCESS ) &&
+ ( Status != NDIS_STATUS_PENDING ))
+ {
+ IF_TPDBG( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1(
+ "TpStressServerCleanUp: failed to delete Multicast Address--Status = %s\n",
+ TpGetStatus(Status));
+ }
+ }
+ } // And if you are Arcnet, do nothing
+ }
+
+ OpenP->Stress->StressFinal = TRUE;
+
+ //
+ // And clear the packet filter on the card by setting it
+ // to null.
+ //
+
+ Status = TpStressSetPacketFilter( OpenP,0 );
+
+ if (( Status != NDIS_STATUS_SUCCESS ) &&
+ ( Status != NDIS_STATUS_PENDING ))
+ {
+ IF_TPDBG( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint0("TpStressFinalDpc: failed to reset packet filter.\n");
+ }
+ }
+ }
+}
+
+
+
+VOID
+TpStressCleanUp(
+ IN POPEN_BLOCK OpenP
+ )
+
+// ------
+//
+// Routine Description:
+//
+// This routine is used to clean up after a failed attempt to start a
+// stress test.
+//
+// Arguments:
+//
+// OpenP - a pointer to the OPEN_BLOCK containing the structures to be
+// deallocated.
+//
+// Return Value:
+//
+// None.
+//
+// ------
+
+{
+ PSTRESS_ARGUMENTS Args = NULL;
+ PSERVER_INFO Server = NULL;
+ NDIS_STATUS Status;
+
+ Args = OpenP->Stress->Arguments;
+
+ //
+ // Set the stop stress flag to halt the Register2Dpc routine
+ // now, if it was already set this will do nothing.
+ //
+
+ OpenP->Stress->StopStressing = TRUE;
+ OpenP->Stress->Stressing = FALSE;
+
+ //
+ // if we have set a functional address or added a multicast
+ // address then clear it now.
+ //
+
+ if ( Args->MemberType != TP_CLIENT )
+ {
+ if ( OpenP->Media->MediumType == NdisMedium802_5 )
+ {
+ Status = TpStressSetFunctionalAddress( OpenP,
+ (PUCHAR)NULL_ADDRESS,
+ TRUE );
+
+ if (( Status != NDIS_STATUS_SUCCESS ) &&
+ ( Status != NDIS_STATUS_PENDING ))
+ {
+ IF_TPDBG( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1(
+ "TpStressServerCleanUp: failed to clear Functional Address--Status = %s\n",
+ TpGetStatus(Status));
+ }
+ }
+ }
+ else if (OpenP->Media->MediumType == NdisMedium802_3)
+ {
+ Status = TpStressAddMulticastAddress( OpenP,
+ (PUCHAR)NULL_ADDRESS,
+ TRUE );
+
+ if (( Status != NDIS_STATUS_SUCCESS ) &&
+ ( Status != NDIS_STATUS_PENDING ))
+ {
+ IF_TPDBG( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1(
+ "TpStressServerCleanUp: failed to delete Multicast Address--Status = %s\n",
+ TpGetStatus(Status));
+ }
+ }
+ }
+ else if (OpenP->Media->MediumType == NdisMediumFddi)
+ {
+ Status = TpStressAddLongMulticastAddress( OpenP,
+ (PUCHAR)NULL_ADDRESS,
+ TRUE );
+
+ if (( Status != NDIS_STATUS_SUCCESS ) &&
+ ( Status != NDIS_STATUS_PENDING ))
+ {
+ IF_TPDBG( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1(
+ "TpStressServerCleanUp: failed to delete Multicast Address--Status = %s\n",
+ TpGetStatus(Status));
+ }
+ }
+ } // And if you are ARCNET do nothing
+ }
+
+ //
+ // And clear the packet filter on the card by setting it
+ // to null.
+ //
+
+ Status = TpStressSetPacketFilter( OpenP,0 );
+
+ if (( Status != NDIS_STATUS_SUCCESS ) &&
+ ( Status != NDIS_STATUS_PENDING ))
+ {
+ IF_TPDBG( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint0("TpStressFinalDpc: failed to reset packet filter.\n");
+ }
+ }
+
+ OpenP->Stress->StressFinal = TRUE;
+
+ //
+ // Clean up the various data structures allocated during initialization
+ //
+
+ TpStressFreeResources( OpenP );
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ if ( OpenP->Stress->StressIrp != NULL )
+ {
+ OpenP->Stress->StressIrp->IoStatus.Status = NDIS_STATUS_FAILURE;
+ }
+
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+}
+
+
+
+VOID
+TpStressFreeResources(
+ IN POPEN_BLOCK OpenP
+ )
+
+// -------------
+//
+// Changes in functionality: SanjeevK
+//
+// The RESET should occur prior to resource de-allocation. This is because
+// all requests to the adapter in question working over the OPEN_BLOCK should
+// be completed since they use the resources allocated by the open block in question.
+// After the RESET has completed, the resources are de-allocated
+//
+// Assumption
+//
+// OpenP cannot be a NULL at this point and time
+//
+// Descrption
+//
+// This function is responsible for clearing the adapter followed by dis-associating
+// any resources(memory blocks) which have been associated with an OPEN_BLOCK.
+//
+// -------------
+
+{
+ NDIS_STATUS Status;
+
+
+ // Sanjeevk : STARTCHANGE
+
+ //
+ // Initialize the Open block pointer for RESET
+ //
+ Status = NdisAllocateMemory((PVOID *)&OpenP->ResetReqHndl,
+ sizeof( TP_REQUEST_HANDLE ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpStressFreeResources: unable to allocate Reset Request Handle.\n");
+ }
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ if ( OpenP->Irp != NULL )
+ {
+ OpenP->Irp->IoStatus.Status = NDIS_STATUS_RESOURCES;
+ }
+
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ }
+ else
+ {
+ //
+ // Perform the RESET on the adapter
+ //
+ NdisZeroMemory( OpenP->ResetReqHndl,sizeof( TP_REQUEST_HANDLE ));
+
+ //
+ // And initialize the Reset Request block
+ //
+ OpenP->ResetReqHndl->Signature = FUNC_REQUEST_HANDLE_SIGNATURE;
+ OpenP->ResetReqHndl->Open = OpenP;
+ OpenP->ResetReqHndl->RequestPended = TRUE;
+
+ //
+ // Indicate that cleanup is required once the RESET completes
+ // This is to ensure that the either this routine or the completion
+ // routine will take care of the cleanup
+ OpenP->ResetReqHndl->u.RESET_REQ.PostResetStressCleanup = TRUE;
+
+ //
+ // And now issue the RESET
+ //
+ OpenP->Stress->Resetting = TRUE;
+
+ Status = TpStressReset( OpenP );
+
+ }
+
+
+ //
+ // If the RESET has not gotten pended in which case there is the possibility
+ // of a reset failure we will still proceed and free up the resources
+ //
+
+ if ( Status != NDIS_STATUS_PENDING )
+ {
+ //
+ // Indicate that we will take care of the post reset cleanup
+ // and that the completion routine does not have to take care of it
+ //
+ OpenP->ResetReqHndl->u.RESET_REQ.PostResetStressCleanup = FALSE;
+
+ TpStressResetComplete( OpenP,Status );
+
+ //
+ // Free up the various data structures allocated during the
+ // initialization phase.
+ //
+
+ OpenP->Stress->StressEnded = TRUE;
+
+ //
+ // Free up the resources associated with this instance of the stress test
+ //
+ TpStressFreePostResetResources( OpenP );
+
+
+ //
+ // Decrement the reference count on the OpenBlock stating this
+ // instance of an async test is no longer running, and the adapter
+ // may be closed if requested.
+ //
+ TpRemoveReference( OpenP );
+ }
+ // Sanjeevk : STOPCHANGE
+}
+
+
+
+VOID
+TpStressFreeClient(
+ IN POPEN_BLOCK OpenP
+ )
+{
+ UCHAR i;
+
+ if ( OpenP->Stress->Client != NULL )
+ {
+ if ( OpenP->Stress->Arguments->PacketsFromPool == TRUE )
+ {
+ TpStressFreeTransmitPool( OpenP->Stress->Client->TransmitPool );
+ }
+
+ if ( OpenP->Stress->Client->PoolInitialized == TRUE )
+ {
+ NdisFreePacketPool( OpenP->Stress->Client->PacketHandle );
+ OpenP->Stress->Client->PoolInitialized = FALSE;
+ }
+
+ for ( i=0;i<OpenP->Stress->Client->NumServers;i++ )
+ {
+ if ( OpenP->Stress->Client->Servers[i].Counters != NULL )
+ {
+ NdisFreeMemory( (PVOID)OpenP->Stress->Client->Servers[i].Counters,0,0 );
+ }
+ }
+
+ NdisFreeMemory( OpenP->Stress->Client,0,0 );
+ OpenP->Stress->Client = NULL;
+ }
+}
+
+
+
+VOID
+TpStressFreeServer(
+ IN POPEN_BLOCK OpenP
+ )
+{
+ UCHAR i;
+
+ if ( OpenP->Stress->Server != NULL )
+ {
+ TpStressFreeTransmitPool( OpenP->Stress->Server->TransmitPool );
+
+ if ( OpenP->Stress->Server->PoolInitialized == TRUE )
+ {
+ NdisFreePacketPool( OpenP->Stress->Server->PacketHandle );
+ OpenP->Stress->Server->PoolInitialized = FALSE;
+ }
+
+ for ( i=0;i<OpenP->Stress->Server->NumClients;i++ )
+ {
+ if ( OpenP->Stress->Server->Clients[i].Counters != NULL )
+ {
+ NdisFreeMemory( (PVOID)OpenP->Stress->Server->Clients[i].Counters,0,0 );
+ }
+ }
+
+ NdisFreeMemory( OpenP->Stress->Server,0,0 );
+ OpenP->Stress->Server = NULL;
+ }
+}
+
+
+
+VOID
+TpStressFreePostResetResources(
+ IN POPEN_BLOCK OpenP
+ )
+{
+
+ if (( OpenP != NULL ) && ( OpenP->Stress->Arguments != NULL ))
+ {
+ if (( OpenP->Stress->Arguments->MemberType == TP_CLIENT ) ||
+ ( OpenP->Stress->Arguments->MemberType == BOTH ))
+ {
+ TpStressFreeClient( OpenP );
+ }
+
+ if (( OpenP->Stress->Arguments->MemberType == TP_SERVER ) ||
+ ( OpenP->Stress->Arguments->MemberType == BOTH ))
+ {
+ TpStressFreeServer( OpenP );
+ }
+
+ if (OpenP->Stress->PoolInitialized == TRUE )
+ {
+ NdisFreePacketPool( OpenP->Stress->PacketHandle );
+ OpenP->Stress->PoolInitialized = FALSE;
+ }
+
+
+ //
+ // SanjeevK: Free up the data buffer and associated MDL resources
+ //
+ TpStressFreeDataBuffers( OpenP );
+ TpStressFreeDataBufferMdls( OpenP );
+
+
+ NdisFreeMemory( OpenP->Stress->Arguments,0,0 );
+ OpenP->Stress->Arguments = NULL;
+
+ //
+ // Deallocate the global counters, and their spinlock.
+ //
+
+ if ( OpenP->GlobalCounters != NULL )
+ {
+ NdisFreeMemory( (PVOID)OpenP->GlobalCounters,0,0 );
+ OpenP->GlobalCounters = NULL;
+ }
+ }
+}
+
+
+
+VOID
+TpStressRegister2Dpc(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SysArg1,
+ IN PVOID SysArg2
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)DeferredContext);
+ PSTRESS_ARGUMENTS Args;
+ LARGE_INTEGER DueTime;
+ PNDIS_PACKET Packet;
+
+
+ UNREFERENCED_PARAMETER( Dpc );
+ UNREFERENCED_PARAMETER( SysArg1 );
+ UNREFERENCED_PARAMETER( SysArg2 );
+
+ //
+ // If the Stress Irp has been cancelled then clean up and leave.
+ //
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ if (( OpenP->Stress->StressIrp == NULL ) ||
+ ( OpenP->Stress->StressIrp->Cancel == TRUE ))
+ {
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ OpenP->Stress->StopStressing = TRUE;
+ return;
+ }
+
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ if (( OpenP->Stress->StopStressing == FALSE ) &&
+ ( OpenP->Stress->Client->NumServers < MAX_SERVERS ))
+ {
+ Args = OpenP->Stress->Arguments;
+
+ if (( OpenP->Stress->Reg2Counter < 60 ) ||
+ (( OpenP->Stress->Reg2Counter % 60 ) == 0 ))
+ {
+ //
+ // We are now ready to begin the test, send a REGISTER_REQ
+ // packet to the STRESS_MULTICAST/FUNCTIONAL address.
+ //
+ // Construct the REGISTER_REQ2 packet and send it.
+ //
+
+ Packet = TpStressCreatePacket( OpenP,
+ OpenP->Stress->Client->PacketHandle,
+ Args->PacketMakeUp,
+ 0, // ServerInstance
+ OpenP->OpenInstance,
+ REGISTER_REQ2,
+ Args->ResponseType,
+ OpenP->Environment->StressAddress,
+ sizeof( STRESS_PACKET ),
+ sizeof( STRESS_PACKET ),
+ 0,0L,0,0,
+ Args->DataChecking );
+
+ if ( Packet == NULL )
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0("TpStressRegister2Dpc: failed to build REGISTER_REQ2 packet\n");
+ }
+ }
+ else
+ {
+ TpStressSend( OpenP,Packet,NULL );
+ }
+ }
+
+ //
+ // We will continue requeueing this Dpc for 6 minutes. The first
+ // minute we will send once every second then for the next five
+ // minutes send only one request each minute.
+ //
+
+ if ( OpenP->Stress->Reg2Counter++ < 360 )
+ {
+ //
+ // Now requeue the Dpc to run try again next time.
+ //
+
+ DueTime.HighPart = -1;
+ DueTime.LowPart = (ULONG)(- ( ONE_SECOND ));
+
+ if ( KeSetTimer(&OpenP->Stress->TpStressReg2Timer,
+ DueTime,
+ &OpenP->Stress->TpStressReg2Dpc ))
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0("TpStressRegister2Dpc set TpStressReg2Timer while timer existed.\n");
+ }
+ }
+ }
+ }
+}
+
+
diff --git a/private/ntos/ndis/testprot/tpdrvr/strfunc.c b/private/ntos/ndis/testprot/tpdrvr/strfunc.c
new file mode 100644
index 000000000..c9721cc42
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpdrvr/strfunc.c
@@ -0,0 +1,1858 @@
+// **********************
+//
+// Copyright (c) 1990 Microsoft Corporation
+//
+// Module Name:
+//
+// strfunc.
+//
+// Abstract:
+//
+// Tests to drive the NDIS wrapper and NDIS 3.0 MACs.
+//
+// Author:
+//
+// Tom Adams (tomad) 26-Nov-1990
+//
+// Environment:
+//
+// Kernel mode, FSD
+//
+// Revision History:
+//
+// Sanjeev Katariya(sanjeevk)
+// 3-16-1993 Change TpStressResetComplete() to accomodate for bug #2874
+// 4-14-1993 Changed error count check for Fddi also within TpStressSendComplete since
+// both 802.5 and Fddi work on tokens and hence the FS bits are the same
+// 5-10-1993 Fixed TpStressTransferDataComplete to not check the data in the event
+// that the transfer data failed. Bug#9244
+//
+// Tim Wynsma (timothyw)
+// 5-18-1994 Fixed warnings, improved debug, cleanup
+//
+// ******************
+
+#include <ndis.h>
+
+#include <string.h>
+
+#include "tpdefs.h"
+#include "media.h"
+#include "tpprocs.h"
+
+//
+// Forward references
+//
+extern VOID
+TpStressFreePostResetResources(
+ IN POPEN_BLOCK OpenP
+ );
+
+
+
+NDIS_STATUS
+TpStressAddMulticastAddress(
+ IN POPEN_BLOCK OpenP,
+ IN PUCHAR MulticastAddress,
+ IN BOOLEAN SetZeroTableSize
+ )
+
+// -----
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// ----
+
+{
+ NDIS_STATUS Status;
+ PNDIS_REQUEST Request;
+ PTP_REQUEST_HANDLE ReqHndl;
+ ULONG OidIndex;
+ PUCHAR InformationBuffer;
+
+
+ Status = NdisAllocateMemory((PVOID *)&ReqHndl,
+ sizeof( TP_REQUEST_HANDLE ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpStressAddMulticastAddress: unable to allocate ReqHndl.\n");
+ }
+ return NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( ReqHndl,sizeof( TP_REQUEST_HANDLE ));
+ }
+
+ ReqHndl->Signature = STRESS_REQUEST_HANDLE_SIGNATURE;
+ ReqHndl->Open = OpenP;
+ ReqHndl->RequestPended = TRUE;
+ ReqHndl->u.STRESS_REQ.NextReqHndl = NULL;
+
+ Status = NdisAllocateMemory((PVOID *)&Request,
+ sizeof( NDIS_REQUEST ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpStressAddMulticastAddress: unable to allocate Request.\n");
+ }
+ return NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( Request,sizeof( NDIS_REQUEST ));
+ }
+
+ Request->RequestType = NdisRequestSetInformation;
+
+ OidIndex = TpLookUpOidInfo( OID_802_3_MULTICAST_LIST );
+
+ Status = NdisAllocateMemory((PVOID *)&InformationBuffer,
+ OidArray[OidIndex].Length,
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpStressAddMulticastAddress: unable to allocate Information Buffer.\n");
+ }
+ return NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( InformationBuffer,OidArray[OidIndex].Length );
+ }
+
+ Request->DATA.SET_INFORMATION.Oid = OID_802_3_MULTICAST_LIST;
+ Request->DATA.SET_INFORMATION.InformationBuffer = InformationBuffer;
+ if ( SetZeroTableSize )
+ {
+ Request->DATA.SET_INFORMATION.InformationBufferLength = 0;
+ }
+ else
+ {
+ Request->DATA.SET_INFORMATION.InformationBufferLength = OidArray[OidIndex].Length;
+ }
+
+ RtlMoveMemory( InformationBuffer,MulticastAddress,ADDRESS_LENGTH );
+
+ ReqHndl->u.STRESS_REQ.Request = Request;
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ ReqHndl->u.STRESS_REQ.NextReqHndl = OpenP->StressReqHndl;
+ OpenP->StressReqHndl = ReqHndl;
+
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ NdisAcquireSpinLock( &OpenP->Stress->Pend->SpinLock );
+ ++OpenP->Stress->Pend->PendingRequests;
+ NdisReleaseSpinLock( &OpenP->Stress->Pend->SpinLock );
+
+ NdisRequest( &Status,OpenP->NdisBindingHandle,Request );
+
+ if ( Status == NDIS_STATUS_SUCCESS )
+ {
+ TP_ASSERT( Request->DATA.SET_INFORMATION.BytesRead <=
+ Request->DATA.SET_INFORMATION.InformationBufferLength );
+ }
+
+ //
+ // If the request did not pend, then free up the memory now.
+ //
+
+ if ( Status != NDIS_STATUS_PENDING )
+ {
+ TpStressRequestComplete( OpenP,Request,Status );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1("TpStressAddMulticastAddress: NdisRequest returned %s\n",
+ TpGetStatus(Status));
+ }
+ }
+ }
+
+ return Status;
+}
+
+
+
+NDIS_STATUS
+TpStressAddLongMulticastAddress(
+ IN POPEN_BLOCK OpenP,
+ IN PUCHAR MulticastAddress,
+ IN BOOLEAN SetZeroTableSize
+ )
+
+// -------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// ------
+
+{
+ NDIS_STATUS Status;
+ PNDIS_REQUEST Request;
+ PTP_REQUEST_HANDLE ReqHndl;
+ ULONG OidIndex;
+ PUCHAR InformationBuffer;
+
+
+ Status = NdisAllocateMemory((PVOID *)&ReqHndl,
+ sizeof( TP_REQUEST_HANDLE ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpStressAddMulticastAddress: unable to allocate ReqHndl.\n");
+ }
+ return NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( ReqHndl,sizeof( TP_REQUEST_HANDLE ));
+ }
+
+ ReqHndl->Signature = STRESS_REQUEST_HANDLE_SIGNATURE;
+ ReqHndl->Open = OpenP;
+ ReqHndl->RequestPended = TRUE;
+ ReqHndl->u.STRESS_REQ.NextReqHndl = NULL;
+
+ Status = NdisAllocateMemory((PVOID *)&Request,
+ sizeof( NDIS_REQUEST ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpStressAddMulticastAddress: unable to allocate Request.\n");
+ }
+ return NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( Request,sizeof( NDIS_REQUEST ));
+ }
+
+ Request->RequestType = NdisRequestSetInformation;
+
+ OidIndex = TpLookUpOidInfo( OID_FDDI_LONG_MULTICAST_LIST );
+
+ Status = NdisAllocateMemory((PVOID *)&InformationBuffer,
+ OidArray[OidIndex].Length,
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpStressAddMulticastAddress: unable to allocate Information Buffer.\n");
+ }
+ return NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( InformationBuffer,OidArray[OidIndex].Length );
+ }
+
+ Request->DATA.SET_INFORMATION.Oid = OID_FDDI_LONG_MULTICAST_LIST;
+ Request->DATA.SET_INFORMATION.InformationBuffer = InformationBuffer;
+
+ if ( SetZeroTableSize )
+ {
+ Request->DATA.SET_INFORMATION.InformationBufferLength = 0;
+ }
+ else
+ {
+ Request->DATA.SET_INFORMATION.InformationBufferLength = OidArray[OidIndex].Length;
+ }
+
+ RtlMoveMemory( InformationBuffer,MulticastAddress,ADDRESS_LENGTH );
+
+ ReqHndl->u.STRESS_REQ.Request = Request;
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ ReqHndl->u.STRESS_REQ.NextReqHndl = OpenP->StressReqHndl;
+ OpenP->StressReqHndl = ReqHndl;
+
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ NdisAcquireSpinLock( &OpenP->Stress->Pend->SpinLock );
+ ++OpenP->Stress->Pend->PendingRequests;
+ NdisReleaseSpinLock( &OpenP->Stress->Pend->SpinLock );
+
+ NdisRequest( &Status,OpenP->NdisBindingHandle,Request );
+
+ if ( Status == NDIS_STATUS_SUCCESS )
+ {
+ TP_ASSERT( Request->DATA.SET_INFORMATION.BytesRead <=
+ Request->DATA.SET_INFORMATION.InformationBufferLength );
+ }
+
+ //
+ // If the request did not pend, then free up the memory now.
+ //
+
+ if ( Status != NDIS_STATUS_PENDING )
+ {
+ TpStressRequestComplete( OpenP,Request,Status );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1("TpStressAddMulticastAddress: NdisRequest returned %s\n",
+ TpGetStatus(Status));
+ }
+ }
+ }
+
+ return Status;
+}
+
+
+
+NDIS_STATUS
+TpStressSetFunctionalAddress(
+ IN POPEN_BLOCK OpenP,
+ IN PUCHAR FunctionalAddress,
+ IN BOOLEAN SetZeroTableSize
+ )
+
+// ------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// ------
+
+{
+ NDIS_STATUS Status;
+ PTP_REQUEST_HANDLE ReqHndl;
+ PNDIS_REQUEST Request;
+ ULONG OidIndex;
+ PUCHAR InformationBuffer;
+
+
+ Status = NdisAllocateMemory((PVOID *)&ReqHndl,
+ sizeof( TP_REQUEST_HANDLE ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpStressSetFunctionalAddress: unable to allocate ReqHndl.\n");
+ }
+ return NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( ReqHndl,sizeof( TP_REQUEST_HANDLE ));
+ }
+
+ ReqHndl->Signature = STRESS_REQUEST_HANDLE_SIGNATURE;
+ ReqHndl->Open = OpenP;
+ ReqHndl->RequestPended = TRUE;
+ ReqHndl->u.STRESS_REQ.NextReqHndl = NULL;
+
+
+ Status = NdisAllocateMemory((PVOID *)&Request,
+ sizeof( NDIS_REQUEST ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpStressSetFunctionalAddress: unable to allocate Request.\n");
+ }
+ return NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( Request,sizeof( NDIS_REQUEST ));
+ }
+
+ Request->RequestType = NdisRequestSetInformation;
+
+ OidIndex = TpLookUpOidInfo( OID_802_5_CURRENT_FUNCTIONAL );
+
+ Status = NdisAllocateMemory((PVOID *)&InformationBuffer,
+ OidArray[OidIndex].Length,
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpStressSetFunctionalAddress: unable to allocate Information Buffer.\n");
+ }
+ return NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( InformationBuffer,OidArray[OidIndex].Length);
+ }
+
+ Request->DATA.SET_INFORMATION.Oid = OID_802_5_CURRENT_FUNCTIONAL;
+ Request->DATA.SET_INFORMATION.InformationBuffer = InformationBuffer;
+
+// Wrapper requires information buffer length to be 4 here--zero is not allowed
+
+// if ( SetZeroTableSize )
+// {
+// Request->DATA.SET_INFORMATION.InformationBufferLength = 0;
+// }
+// else
+// {
+ Request->DATA.SET_INFORMATION.InformationBufferLength = OidArray[OidIndex].Length;
+// }
+
+ RtlMoveMemory( InformationBuffer,
+ FunctionalAddress,
+ FUNCTIONAL_ADDRESS_LENGTH );
+
+ ReqHndl->u.STRESS_REQ.Request = Request;
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ ReqHndl->u.STRESS_REQ.NextReqHndl = OpenP->StressReqHndl;
+ OpenP->StressReqHndl = ReqHndl;
+
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ NdisAcquireSpinLock( &OpenP->Stress->Pend->SpinLock );
+ ++OpenP->Stress->Pend->PendingRequests;
+ NdisReleaseSpinLock( &OpenP->Stress->Pend->SpinLock );
+
+ NdisRequest( &Status,OpenP->NdisBindingHandle,Request );
+
+ //
+ // If the request did not pend, then free up the memory now.
+ //
+
+ if ( Status != NDIS_STATUS_PENDING )
+ {
+ TpStressRequestComplete( OpenP,Request,Status );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1("TpStressSetFunctionalAddress: NdisRequest returned %s\n",
+ TpGetStatus(Status));
+ }
+ }
+ }
+ return Status;
+}
+
+
+
+NDIS_STATUS
+TpStressSetPacketFilter(
+ IN POPEN_BLOCK OpenP,
+ IN UINT PacketFilter
+ )
+
+// ------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// ------
+
+{
+ NDIS_STATUS Status;
+ PTP_REQUEST_HANDLE ReqHndl;
+ PNDIS_REQUEST Request;
+ ULONG OidIndex;
+ PUCHAR InformationBuffer;
+
+
+ Status = NdisAllocateMemory((PVOID *)&ReqHndl,
+ sizeof( TP_REQUEST_HANDLE ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpStressSetPacketFilter: unable to allocate ReqHndl.\n");
+ }
+ return NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( ReqHndl,sizeof( TP_REQUEST_HANDLE ));
+ }
+
+ ReqHndl->Signature = STRESS_REQUEST_HANDLE_SIGNATURE;
+ ReqHndl->Open = OpenP;
+ ReqHndl->RequestPended = TRUE;
+ ReqHndl->u.STRESS_REQ.NextReqHndl = NULL;
+
+ Status = NdisAllocateMemory((PVOID *)&Request,
+ sizeof( NDIS_REQUEST ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpStressSetPacketFilter: unable to allocate Request.\n");
+ }
+ return NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( Request,sizeof( NDIS_REQUEST ));
+ }
+
+ Request->RequestType = NdisRequestSetInformation;
+
+ OidIndex = TpLookUpOidInfo( OID_GEN_CURRENT_PACKET_FILTER );
+
+ Status = NdisAllocateMemory((PVOID *)&InformationBuffer,
+ OidArray[OidIndex].Length,
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpStressSetPacketFilter: unable to allocate Information Buffer.\n");
+ }
+ return NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( InformationBuffer,OidArray[OidIndex].Length);
+ }
+
+ Request->DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
+ Request->DATA.SET_INFORMATION.InformationBuffer = InformationBuffer;
+ Request->DATA.SET_INFORMATION.InformationBufferLength =
+ OidArray[OidIndex].Length;
+
+ *((PULONG)InformationBuffer) = (ULONG)PacketFilter;
+
+ ReqHndl->u.STRESS_REQ.Request = Request;
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ ReqHndl->u.STRESS_REQ.NextReqHndl = OpenP->StressReqHndl;
+ OpenP->StressReqHndl = ReqHndl;
+
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ NdisAcquireSpinLock( &OpenP->Stress->Pend->SpinLock );
+ ++OpenP->Stress->Pend->PendingRequests;
+ NdisReleaseSpinLock( &OpenP->Stress->Pend->SpinLock );
+
+ NdisRequest( &Status,OpenP->NdisBindingHandle,Request );
+
+ //
+ // If the request did not pend, then free up the memory now.
+ //
+
+ if ( Status != NDIS_STATUS_PENDING )
+ {
+ TpStressRequestComplete( OpenP,Request,Status );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1("TpStressSetPacketFilter: NdisRequest returned %s\n",
+ TpGetStatus(Status));
+ }
+ }
+ }
+
+ return Status;
+}
+
+
+
+VOID
+TpStressRequestComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS Status
+ )
+
+// ---------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// ---------
+
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)ProtocolBindingContext);
+ PTP_REQUEST_HANDLE CorrectReqHndl = NULL;
+ PTP_REQUEST_HANDLE RH;
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ TP_ASSERT( OpenP->StressReqHndl != NULL );
+
+ if ( OpenP->StressReqHndl->u.STRESS_REQ.Request == NdisRequest )
+ {
+ CorrectReqHndl = OpenP->StressReqHndl;
+ OpenP->StressReqHndl = OpenP->StressReqHndl->u.STRESS_REQ.NextReqHndl;
+ }
+ else
+ {
+ RH = OpenP->StressReqHndl;
+
+ do
+ {
+ if ( RH->u.STRESS_REQ.NextReqHndl->u.STRESS_REQ.Request == NdisRequest )
+ {
+ CorrectReqHndl = RH->u.STRESS_REQ.NextReqHndl;
+
+ RH->u.STRESS_REQ.NextReqHndl =
+ RH->u.STRESS_REQ.NextReqHndl->u.STRESS_REQ.NextReqHndl;
+
+ break;
+ }
+ else
+ {
+ RH = RH->u.STRESS_REQ.NextReqHndl;
+ }
+ } while ( RH->u.STRESS_REQ.NextReqHndl != NULL );
+ }
+
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ TP_ASSERT( CorrectReqHndl != NULL );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG( TP_DEBUG_NDIS_ERROR )
+ {
+ TpPrint2("TpStressRequestComplete returned %s, request type %d\n",
+ TpGetStatus( Status ), NdisRequest->RequestType);
+ }
+ }
+
+ if ( NdisRequest->RequestType == NdisRequestSetInformation )
+ {
+ NdisFreeMemory( NdisRequest->DATA.SET_INFORMATION.InformationBuffer,0,0 );
+
+ }
+ else // NdisRequestQueryInformation
+ {
+ NdisFreeMemory( NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,0,0 );
+ }
+
+ NdisFreeMemory( NdisRequest,0,0 );
+ NdisFreeMemory( CorrectReqHndl,0,0 );
+
+ //
+ // Decrement the Pending Requests and set the stressing flag to
+ // stop all stressing if the time is right counter.
+ //
+
+ NdisAcquireSpinLock( &OpenP->Stress->Pend->SpinLock );
+ --OpenP->Stress->Pend->PendingRequests;
+
+ if (((( OpenP->Stress->StopStressing == TRUE ) &&
+ ( OpenP->Stress->StressFinal == TRUE )) &&
+ ( OpenP->Stress->Pend->PendingRequests == 0 )) &&
+ ( OpenP->Stress->Pend->PendingPackets == 0 ))
+ {
+ OpenP->Stress->Stressing = FALSE;
+ NdisReleaseSpinLock( &OpenP->Stress->Pend->SpinLock );
+ TpStressFreeResources( OpenP );
+ }
+ else
+ {
+ NdisReleaseSpinLock( &OpenP->Stress->Pend->SpinLock );
+ }
+
+ return;
+}
+
+
+
+NDIS_STATUS
+TpStressReset(
+ POPEN_BLOCK OpenP
+ )
+
+// -------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// -------
+
+{
+ NDIS_STATUS Status;
+
+ NdisReset( &Status,OpenP->NdisBindingHandle );
+
+ if (( Status != NDIS_STATUS_SUCCESS ) && ( Status != NDIS_STATUS_PENDING ))
+ {
+ IF_TPDBG ( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1("TpStressReset: NdisReset returned %s\n",
+ TpGetStatus(Status));
+ }
+ }
+ return Status;
+}
+
+
+
+VOID
+TpStressResetComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status
+ )
+
+// --------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// --------
+
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)ProtocolBindingContext);
+ ULONG NextEvent;
+
+ //
+ // Indicate RESET is over
+ //
+ OpenP->Stress->Resetting = FALSE;
+
+
+ // Sanjeevk : STARTCHANGE
+
+ if (( OpenP->ResetReqHndl != NULL ) &&
+ (( OpenP->ResetReqHndl->Signature == FUNC_REQUEST_HANDLE_SIGNATURE ) &&
+ ( OpenP->ResetReqHndl->Open == OpenP )))
+ {
+ IF_TPDBG(TP_DEBUG_DISPATCH)
+ {
+ TpPrint1("TpStressResetComplete Status = %s\n", TpGetStatus( Status ));
+ }
+
+ //
+ // Check if any stress cleanup is required
+ //
+ if ( OpenP->ResetReqHndl->u.RESET_REQ.PostResetStressCleanup )
+ {
+ OpenP->ResetReqHndl->u.RESET_REQ.PostResetStressCleanup = FALSE;
+
+ //
+ // Free up the resources associated with this instance of the stress test
+ //
+ TpStressFreePostResetResources( OpenP );
+
+ //
+ // Decrement the reference count on the OpenBlock stating this
+ // instance of an async test is no longer running, and the adapter
+ // may be closed if requested.
+ //
+ TpRemoveReference( OpenP );
+ }
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ if ( OpenP->Stress->StressIrp != NULL )
+ {
+ OpenP->Stress->StressIrp->IoStatus.Status = NDIS_STATUS_SUCCESS;
+
+ IoAcquireCancelSpinLock( &OpenP->Stress->StressIrp->CancelIrql );
+ IoSetCancelRoutine( OpenP->Stress->StressIrp,NULL );
+ IoReleaseCancelSpinLock( OpenP->Stress->StressIrp->CancelIrql );
+
+ if ( OpenP->Stress->StressStarted == TRUE )
+ {
+ IoCompleteRequest( OpenP->Stress->StressIrp,IO_NETWORK_INCREMENT );
+ }
+
+ OpenP->Stress->StressIrp = NULL;
+ }
+
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ //
+ // Free up the request handle block
+ //
+ NdisFreeMemory( OpenP->ResetReqHndl,0,0 );
+ OpenP->ResetReqHndl = NULL;
+ }
+ else
+ {
+ //
+ // We are not expecting any requests to complete at this
+ // point, so stick this on the Event Queue.
+ //
+
+ NdisAcquireSpinLock( &OpenP->EventQueue->SpinLock );
+
+ NextEvent = OpenP->EventQueue->Head + 1;
+ if ( NextEvent == MAX_EVENT )
+ {
+ NextEvent = 0;
+ }
+
+ if ( NextEvent != OpenP->EventQueue->Tail )
+ {
+ //
+ // There is room to add another event to the event queue.
+ //
+
+ OpenP->EventQueue->Events[NextEvent].TpEventType = CompleteReset;
+
+ OpenP->EventQueue->Head = NextEvent;
+
+ // we should also stick some interesting info like requesttype.
+ }
+ else
+ {
+ //
+ // The event queue is full, and this would have overflowed it, so
+ // mark the Head event overflow flag to show this.
+ //
+
+ OpenP->EventQueue->Events[OpenP->EventQueue->Head].Overflow = TRUE;
+ }
+
+ NdisReleaseSpinLock( &OpenP->EventQueue->SpinLock );
+ }
+
+ // Sanjeevk : STOPCHANGE
+}
+
+
+
+NDIS_STATUS
+TpStressClientSend(
+ POPEN_BLOCK OpenP,
+ NDIS_HANDLE PacketHandle,
+ PTP_TRANSMIT_POOL TpTransmitPool,
+ PUCHAR DestAddr,
+ UCHAR SrcInstance,
+ UCHAR DestInstance,
+ UCHAR PacketProtocol,
+ ULONG SequenceNumber,
+ ULONG MaxSequenceNumber,
+ UCHAR ClientReference,
+ UCHAR ServerReference,
+ INT PacketSize,
+ INT BufferSize
+ )
+
+// ---------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// ---------
+
+{
+ PNDIS_PACKET Packet;
+ PSTRESS_ARGUMENTS Args;
+ PINSTANCE_COUNTERS Counters;
+
+ Args = OpenP->Stress->Arguments;
+ Counters = OpenP->Stress->Client->Servers[ServerReference].Counters;
+
+ if ( Args->PacketsFromPool == TRUE )
+ {
+ Packet = TpStressAllocatePoolPacket(TpTransmitPool,
+ Counters );
+
+ if ( Packet != NULL )
+ {
+ TpStressSetPoolPacketInfo( OpenP,
+ Packet,
+ DestAddr,
+ DestInstance,
+ SrcInstance,
+ SequenceNumber,
+ MaxSequenceNumber,
+ ClientReference,
+ ServerReference );
+ }
+ else
+ {
+ return NDIS_STATUS_RESOURCES;
+ }
+ }
+ else
+ {
+ if ( Args->PacketType == RANDOMSIZE )
+ {
+ PacketSize = TpGetRandom( sizeof( STRESS_PACKET ),
+ Args->PacketSize );
+ }
+ else if (Args->PacketType == FIXEDSIZE)
+ {
+ PacketSize = Args->PacketSize;
+ } // else Args->PacketType == CYCLICAL
+
+ Packet = TpStressCreatePacket( OpenP,
+ PacketHandle,
+ Args->PacketMakeUp,
+ DestInstance,
+ SrcInstance,
+ PacketProtocol,
+ Args->ResponseType,
+ DestAddr,
+ PacketSize,
+ BufferSize,
+ SequenceNumber,
+ MaxSequenceNumber,
+ ClientReference,
+ ServerReference,
+ Args->DataChecking );
+
+ if ( Packet != NULL )
+ {
+ TpInitProtocolReserved( Packet,Counters );
+ }
+ else
+ {
+ return NDIS_STATUS_RESOURCES;
+ }
+ }
+
+ TpStressSend( OpenP,Packet,Counters );
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+
+VOID
+TpStressServerSend(
+ POPEN_BLOCK OpenP,
+ PTP_TRANSMIT_POOL TpTransmitPool,
+ PUCHAR DestAddr,
+ UCHAR DestInstance,
+ UCHAR SrcInstance,
+ ULONG SequenceNumber,
+ ULONG MaxSequenceNumber,
+ UCHAR ClientReference,
+ UCHAR ServerReference,
+ INT PacketSize,
+ ULONG DataBufferOffset
+ )
+
+// --------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// --------
+
+{
+ PNDIS_PACKET Packet;
+ PINSTANCE_COUNTERS Counters;
+
+ Counters = OpenP->Stress->Server->Clients[ClientReference].Counters;
+
+// -------
+// This does not work correctly if you are under severe stress
+// because we run out of packets and loop forever. However, there
+// needs to be done some work to handle the less severe case of
+// lower stress say for instance when the window is enabled, or
+// there is a large inter packet delay, giving the sends time to
+// complete and put the used packets back in the transmitpool.
+// Maybe if this fails here it should be handled in the completion
+// routine where it is allowed to loop continuously.
+//
+// do
+// {
+// Packet = TpStressAllocatePoolPacket( TpTransmitPool,Counters );
+// } while ( Packet == NULL );
+//
+// -------
+
+ Packet = TpStressAllocatePoolPacket( TpTransmitPool,Counters );
+
+ if ( Packet == NULL )
+ {
+ return;
+ }
+
+
+ TpStressSetTruncatedPacketInfo( OpenP,
+ Packet,
+ DestAddr,
+ PacketSize,
+ DestInstance,
+ SrcInstance,
+ SequenceNumber,
+ MaxSequenceNumber,
+ ClientReference,
+ ServerReference,
+ DataBufferOffset & 0x07FF );
+
+ TpStressSend( OpenP,Packet,Counters );
+}
+
+
+
+VOID
+TpStressSend(
+ POPEN_BLOCK OpenP,
+ PNDIS_PACKET Packet,
+ PINSTANCE_COUNTERS Counters OPTIONAL
+ )
+
+// -----
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// -----
+
+{
+ NDIS_STATUS Status;
+ PPROTOCOL_RESERVED ProtRes;
+ PPENDING PPend;
+ PSTRESS_ARGUMENTS Args;
+ ULONG TmpPendNumber;
+
+ Args = OpenP->Stress->Arguments;
+ ProtRes = PROT_RES( Packet );
+
+ //
+ // First allocate the Request Handle.
+ //
+
+ Status = NdisAllocateMemory((PVOID *)&ProtRes->RequestHandle,
+ sizeof( TP_REQUEST_HANDLE ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ //
+ // If we can't allocate the memory, then fail the send.
+ //
+
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpStressSend: unable to allocate RequestHandle\n");
+ }
+ Status = NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ //
+ // Otherwise zero the memory, and fill in the fields
+ //
+
+ NdisZeroMemory( ProtRes->RequestHandle,sizeof( TP_REQUEST_HANDLE ));
+
+ ProtRes->RequestHandle->Signature = STRESS_REQUEST_HANDLE_SIGNATURE;
+ ProtRes->RequestHandle->Open = OpenP;
+ ProtRes->RequestHandle->RequestPended = TRUE;
+ ProtRes->RequestHandle->u.SEND_REQ.Packet = Packet;
+
+ //
+ // Then Set the CheckSum in the Protocol Reserved section of the
+ // packet header.
+ //
+
+ ProtRes->CheckSum = TpSetCheckSum( (PUCHAR)ProtRes,
+ sizeof( PROTOCOL_RESERVED ) - sizeof( ULONG ) );
+
+ //
+ // and put the packet in the pending queue.
+ //
+
+ PPend = OpenP->Stress->Pend;
+
+ NdisAcquireSpinLock( &PPend->SpinLock );
+
+ //
+ // If the windowing mechanism is enabled, then add the packet
+ // to the pend queue. We don't add the packet to the pend queue
+ // when we are not windowing because a fast machine can quickly
+ // overrun the queue, and we don't support dynamically increasing
+ // the size of the queue yet.
+ //
+ if ( Args->WindowEnabled == TRUE )
+ {
+ TmpPendNumber = PPend->PacketPendNumber;
+
+ while ( PPend->Packets[TmpPendNumber] != NULL )
+ {
+ NdisReleaseSpinLock( &PPend->SpinLock );
+
+// IF_TPDBG ( TP_DEBUG_DPC )
+// {
+// TpPrint2("TpStressSend: Found packet 0x%lX at slot %d of Pendbuffer\n",
+// PPend->Packets[TmpPendNumber],
+// TmpPendNumber);
+// TpBreakPoint();
+// }
+ ++TmpPendNumber;
+ TmpPendNumber &= (NUM_PACKET_PENDS-1); // 2**n - 1
+
+ if (TmpPendNumber == PPend->PacketPendNumber)
+ {
+ TpPrint0("PPend buffer full -- no empty slots!\n");
+ TpBreakPoint();
+ }
+ NdisAcquireSpinLock( &PPend->SpinLock );
+ }
+
+ PPend->Packets[TmpPendNumber] = Packet;
+
+ PPend->PacketPendNumber = (TmpPendNumber + 1) & (NUM_PACKET_PENDS - 1); // 2**n - 1
+ }
+
+ //
+ // We will also increment the Pending Packets counter now in
+ // case the packet pends and completes before the actual call
+ // to ndis send returns. if the send does not pend, the counter
+ // will be decremented later.
+ //
+
+ ++PPend->PendingPackets;
+
+ NdisReleaseSpinLock( &PPend->SpinLock );
+
+ //
+ // Then send then packet
+ //
+
+ NdisSend( &Status,OpenP->NdisBindingHandle,Packet );
+
+ //
+ // and count the send.
+ //
+
+ if ( ARGUMENT_PRESENT( Counters ))
+ {
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ ++Counters->Sends;
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ }
+
+ if ( Status != NDIS_STATUS_PENDING )
+ {
+ TpStressSendComplete(OpenP, Packet, Status);
+ }
+ else // ( Status == NDIS_STATUS_PENDING )
+ {
+ //
+ // Otherwise the SEND pended so all of the clean up
+ // will be done in the Send Completion routine. Simply
+ // count the pend here.
+ //
+
+ if ( ARGUMENT_PRESENT( Counters ))
+ {
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ ++Counters->SendPends;
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ }
+ }
+ }
+}
+
+
+
+VOID
+TpStressSendComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ )
+
+// -------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// -------
+
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)ProtocolBindingContext);
+ PPROTOCOL_RESERVED ProtRes;
+ PTP_REQUEST_HANDLE SendReqHndl;
+ ULONG TmpCompleteNumber;
+ ULONG MaxCompleteNumber;
+ BOOLEAN CompletePacketCleared;
+ PPENDING PPend;
+ PSTRESS_ARGUMENTS Args;
+
+ TP_ASSERT( Packet != NULL );
+
+ Args = OpenP->Stress->Arguments;
+ ProtRes = PROT_RES( Packet );
+ SendReqHndl = ProtRes->RequestHandle;
+
+ TP_ASSERT( SendReqHndl->Signature == STRESS_REQUEST_HANDLE_SIGNATURE );
+ TP_ASSERT( SendReqHndl->Open == OpenP );
+ TP_ASSERT( SendReqHndl->RequestPended == TRUE );
+ TP_ASSERT( Packet == SendReqHndl->u.SEND_REQ.Packet );
+
+ //
+ // Now check the PROTOCOL_RESERVED section of the Packet header
+ // to ensure that it was not corrupted while in the hands of
+ // the MAC.
+ //
+
+ if ( !TpCheckSum( (PUCHAR)ProtRes,
+ sizeof( PROTOCOL_RESERVED ) - sizeof( ULONG ),
+ &ProtRes->CheckSum ))
+ {
+ //
+ // This could cause an access violation because we have
+ // just found that the PROTOCOL_RESERVED section of this
+ // packet header has been corrupted, and we are about to
+ // attempt to dereference a pointer stored in it. This
+ // should be changed to a try except.
+ //
+
+ if ( ARGUMENT_PRESENT( ProtRes->InstanceCounters ))
+ {
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ ++ProtRes->InstanceCounters->SendFails;
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ }
+ }
+
+ PPend = OpenP->Stress->Pend;
+
+ NdisAcquireSpinLock( &PPend->SpinLock );
+
+ //
+ // If the windowing mechinism is enabled, then find the packet in the
+ // pend queue and remove it.
+ //
+
+ if ( Args->WindowEnabled == TRUE )
+ {
+ TmpCompleteNumber = PPend->PacketCompleteNumber;
+ MaxCompleteNumber = TmpCompleteNumber;
+ CompletePacketCleared = FALSE;
+
+ do
+ {
+ if (CompletePacketCleared)
+ {
+ if (PPend->Packets[TmpCompleteNumber] != NULL)
+ {
+ break;
+ }
+ }
+ else
+ {
+ if ( Packet == PPend->Packets[TmpCompleteNumber] )
+ {
+ PPend->Packets[TmpCompleteNumber] = NULL;
+ CompletePacketCleared = TRUE;
+ TmpCompleteNumber = PPend->PacketCompleteNumber;
+ MaxCompleteNumber = PPend->PacketPendNumber;
+ continue;
+ }
+ }
+
+ ++TmpCompleteNumber;
+ TmpCompleteNumber &= (NUM_PACKET_PENDS - 1); // 2**n - 1
+ }
+ while ( TmpCompleteNumber != MaxCompleteNumber );
+
+ if (CompletePacketCleared)
+ {
+ PPend->PacketCompleteNumber = TmpCompleteNumber;
+ }
+ else
+ {
+ IF_TPDBG( TP_DEBUG_DPC )
+ {
+ TpPrint0("TpStressSendComplete: Pending Packet not found!!\n");
+ TpPrint2("Packet: 0x%lX, list: 0x%lX\n",Packet,PPend->Packets );
+ TpBreakPoint();
+ }
+ }
+ }
+
+ NdisReleaseSpinLock( &PPend->SpinLock );
+
+ if ( ARGUMENT_PRESENT( ProtRes->InstanceCounters ))
+ {
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ ++ProtRes->InstanceCounters->SendComps;
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ //
+ // If we are running on TokenRing the following to "failures"
+ // are not considered failures NDIS_STATUS_NOT_RECOGNIZED -
+ // no one on the ring recognized the address as theirs, or
+ // NDIS_STATUS_NOT_COPIED - no one on the ring copied the
+ // packet, so we need to special case this and not count
+ // these as failures.
+ //
+
+ //
+ // STARTCHANGE: Added FDDI problem catching
+ //
+ if ( ( NdisMediumArray[OpenP->MediumIndex] == NdisMedium802_5 ) ||
+ ( NdisMediumArray[OpenP->MediumIndex] == NdisMediumFddi ) ||
+ ( NdisMediumArray[OpenP->MediumIndex] == NdisMediumArcnet878_2) )
+ {
+ if (( Status != NDIS_STATUS_NOT_RECOGNIZED ) &&
+ ( Status != NDIS_STATUS_NOT_COPIED ))
+ {
+ ++ProtRes->InstanceCounters->SendFails;
+ }
+ }
+ else
+ {
+ ++ProtRes->InstanceCounters->SendFails;
+ }
+ //
+ // STOPCHANGE
+ //
+
+ }
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ }
+
+ if ( ProtRes->Pool.TransmitPool != NULL )
+ {
+ TpStressFreePoolPacket( (PNDIS_PACKET)Packet );
+ }
+ else
+ {
+ TpStressFreePacket( (PNDIS_PACKET)Packet );
+ }
+
+ //
+ // Decrement the counter representing the number of packets pending
+ // on this open instance.
+ //
+
+ NdisAcquireSpinLock( &PPend->SpinLock );
+ --PPend->PendingPackets;
+
+ if (((( OpenP->Stress->StopStressing == TRUE ) &&
+ ( OpenP->Stress->StressFinal == TRUE )) &&
+ ( OpenP->Stress->Pend->PendingRequests == 0 )) &&
+ ( OpenP->Stress->Pend->PendingPackets == 0 ))
+ {
+ OpenP->Stress->Stressing = FALSE;
+ NdisReleaseSpinLock( &PPend->SpinLock );
+ TpStressFreeResources( OpenP );
+ }
+ else
+ {
+ NdisReleaseSpinLock( &PPend->SpinLock );
+ }
+
+ //
+ // And free the Request Handle memory
+ //
+
+ NdisFreeMemory( SendReqHndl,0,0 );
+}
+
+
+
+VOID
+TpStressCheckPacketData(
+ POPEN_BLOCK OpenP,
+ NDIS_HANDLE MacReceiveContext,
+ ULONG DataOffset,
+ UINT PacketSize,
+ PINSTANCE_COUNTERS Counters
+ )
+
+// ------------
+//
+// Routine Description:
+//
+// TpStressCheckPacketData is used to verify the data of a stress packet.
+// It calls NdisTransferData to copy the packet into a NDIS_PACKET structure
+// and then verifies the data in the packet's buffer.
+//
+// Arguments:
+//
+// OpenP - The Open Instance that received this packet. We will use this
+// open instances resources.
+//
+// MacReceiveContext - Passed to NdisTransferData, the MAC way of
+// recognizing this Open Instance.
+//
+// DataOffset - the offset into the DataBuffer where the packet's data
+// should begin.
+//
+// PacketSize - The size of data of this packet to be verified.
+//
+// Counters - The specific client or server's counters used to track the
+// results of the data checking.
+//
+// Return Value:
+//
+// None.
+//
+// ------------
+
+{
+ NDIS_STATUS Status;
+ PNDIS_PACKET TransferPacket;
+ PNDIS_BUFFER TransferBuffer;
+ PUCHAR Memory;
+ PPROTOCOL_RESERVED ProtRes;
+ UINT BytesTransferred;
+ UINT DataStart;
+ UINT DataSize;
+ UINT i, j;
+
+ //
+ // Allocate a packet, and a buffer to use in the call to transfer
+ // the packet into.
+ //
+
+ NdisAllocatePacket( &Status,&TransferPacket,OpenP->Stress->PacketHandle );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1("TpStressCheckPacketData: NdisAllocatePacket failed: %s\n",
+ TpGetStatus(Status));
+ }
+ return;
+ }
+
+ //
+ // STARTCHANGE
+ //
+
+ //
+ // We are only going to transfer the data portion of the packet.
+ // NOTE:
+ // The PacketSize being used here is the COMPLETE packet size
+ // = HEADER + DATA
+ //
+ DataSize = PacketSize - sizeof(STRESS_PACKET);
+ DataStart = (UINT)sizeof( STRESS_PACKET ) - OpenP->Media->HeaderSize;
+
+ //
+ // STOPCHANGE
+ //
+
+ Status = NdisAllocateMemory((PVOID *)&Memory,DataSize,0,HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG( TP_DEBUG_RESOURCES )
+ {
+ TpPrint0("TpStressCheckPacketData: failed to allocate TransferBuffer\n");
+ }
+ NdisFreePacket( TransferPacket );
+ return;
+ }
+ else
+ {
+ NdisZeroMemory( Memory,DataSize );
+ }
+
+ TransferBuffer = IoAllocateMdl( Memory,DataSize,TRUE,FALSE,NULL );
+
+ if ( TransferBuffer == NULL )
+ {
+ IF_TPDBG( TP_DEBUG_RESOURCES )
+ {
+ TpPrint0("TpStressCheckPacketData: failed to allocate TransferBuffer Mdl\n");
+ }
+ NdisFreeMemory( Memory,0,0 );
+ NdisFreePacket( TransferPacket );
+ return;
+ }
+
+ MmBuildMdlForNonPagedPool((PMDL)TransferBuffer );
+
+ NdisChainBufferAtFront( TransferPacket,TransferBuffer );
+
+ //
+ // Now allocate a request handle structure and reference it in
+ // the packets protocol reserved section to pass info to the
+ // completion routine.
+ //
+
+ ProtRes = PROT_RES( TransferPacket );
+
+ Status = NdisAllocateMemory((PVOID *)&ProtRes->RequestHandle,
+ sizeof( TP_REQUEST_HANDLE ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_RESOURCES )
+ {
+ TpPrint0("TpStressCheckPacketData: unable to allocate RequestHandle\n");
+ }
+ IoFreeMdl( TransferBuffer );
+ NdisFreeMemory( Memory,0,0 );
+ NdisFreePacket( TransferPacket );
+ return;
+ }
+ else
+ {
+ NdisZeroMemory( ProtRes->RequestHandle,sizeof( TP_REQUEST_HANDLE ));
+ }
+
+ //
+ // and initialize the information in the request handle.
+ //
+
+ ProtRes->RequestHandle->Signature = STRESS_REQUEST_HANDLE_SIGNATURE;
+ ProtRes->RequestHandle->u.TRANS_REQ.Packet = TransferPacket;
+ ProtRes->RequestHandle->u.TRANS_REQ.DataOffset = DataOffset;
+ ProtRes->RequestHandle->u.TRANS_REQ.DataSize = DataSize;
+ ProtRes->RequestHandle->u.TRANS_REQ.InstanceCounters = Counters;
+
+ //
+ // Increment the transfer data counter, and make the call.
+ //
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ ++Counters->XferData;
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ NdisAcquireSpinLock( &OpenP->Stress->Pend->SpinLock );
+ ++OpenP->Stress->Pend->PendingRequests;
+ NdisReleaseSpinLock( &OpenP->Stress->Pend->SpinLock );
+
+ NdisTransferData( &Status,
+ OpenP->NdisBindingHandle,
+ MacReceiveContext,
+ DataStart,
+ DataSize,
+ TransferPacket,
+ &BytesTransferred );
+
+ if ( Status == NDIS_STATUS_SUCCESS )
+ {
+ //
+ // if the call succeeded, then verify the data now.
+ //
+
+ TP_ASSERT( BytesTransferred == DataSize );
+
+ i = 0;
+ j = DataOffset;
+
+ while ( i < DataSize )
+ {
+ if ( Memory[i++] != (UCHAR)(j++ % 256) )
+ {
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ ++Counters->CorruptRecs;
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ IF_TPDBG ( TP_DEBUG_DATA )
+ {
+ TpPrint1("TpStressCheckPacketData1: Data Error at offset %d in packet data\n",
+ i-1);
+ TpPrint2(" Found %02x, Expected %02x\n\n",
+ Memory[i-1],(( j - 1 ) % 256 ));
+ TpBreakPoint();
+ }
+ break;
+ }
+ }
+ }
+ else if ( Status != NDIS_STATUS_PENDING )
+ {
+ IF_TPDBG( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1("TpStressCheckPacketData: NdisTransferData returned %s\n",TpGetStatus(Status));
+ }
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ ++Counters->XferDataFails;
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ }
+ else // (Status == NDIS_STATUS_PENDING)
+ {
+ //
+ // The call to NdisTransferData pended, the completion routine will
+ // verify the data.
+ //
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ ++Counters->XferDataPends;
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ }
+
+ if ( Status != NDIS_STATUS_PENDING )
+ {
+ NdisAcquireSpinLock( &OpenP->Stress->Pend->SpinLock );
+
+ --OpenP->Stress->Pend->PendingRequests;
+
+ if (((( OpenP->Stress->StopStressing == TRUE ) &&
+ ( OpenP->Stress->StressFinal == TRUE )) &&
+ ( OpenP->Stress->Pend->PendingRequests == 0 )) &&
+ ( OpenP->Stress->Pend->PendingPackets == 0 ))
+ {
+ OpenP->Stress->Stressing = FALSE;
+ NdisReleaseSpinLock( &OpenP->Stress->Pend->SpinLock );
+ TpStressFreeResources( OpenP );
+ }
+ else
+ {
+ NdisReleaseSpinLock( &OpenP->Stress->Pend->SpinLock );
+ }
+
+ //
+ // If the routine did not pend, then deallocate the various resources,
+ // otherwise the completion routine will do this later.
+ //
+ IoFreeMdl( TransferBuffer );
+ NdisFreeMemory( Memory,0,0 );
+ NdisFreeMemory( ProtRes->RequestHandle,0,0 );
+ NdisFreePacket( TransferPacket );
+ }
+}
+
+
+
+VOID
+TpStressTransferDataComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ )
+
+// -----
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// -----
+
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)ProtocolBindingContext);
+ PPROTOCOL_RESERVED ProtRes;
+ PTP_REQUEST_HANDLE XferReqHndl;
+ PNDIS_BUFFER TransferBuffer;
+ PUCHAR Memory;
+ UINT i = 0;
+
+ TP_ASSERT( Packet != NULL );
+
+ ProtRes = PROT_RES( Packet );
+ XferReqHndl = ProtRes->RequestHandle;
+
+ TP_ASSERT( XferReqHndl->Signature == STRESS_REQUEST_HANDLE_SIGNATURE );
+ TP_ASSERT( Packet == XferReqHndl->u.SEND_REQ.Packet );
+
+ //
+ // Increment the NdisTransferData completion counter.
+ //
+ //
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ ++XferReqHndl->u.TRANS_REQ.InstanceCounters->XferDataComps;
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ //
+ // Now unchain the buffer from the packet...
+ //
+
+ NdisUnchainBufferAtFront( Packet,&TransferBuffer );
+
+ //
+ // get the actual packet data from the buffer...
+ //
+
+ Memory = MmGetMdlVirtualAddress( TransferBuffer );
+
+
+ //
+ // SanjeevK
+ //
+ // Fix for Bug# 9244
+ //
+
+ if ( ( Status != NDIS_STATUS_SUCCESS ) ||
+ ( BytesTransferred != XferReqHndl->u.TRANS_REQ.DataSize ) )
+ {
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1("TpStressTransferDataComplete: NdisTransferData failed: Returned %s\n",
+ TpGetStatus(Status));
+ }
+ }
+ else
+ {
+ IF_TPDBG ( TP_DEBUG_DATA )
+ {
+ TpPrint0("TpStressCheckPacketData: Data bytes transfered were incorrect: ");
+ TpPrint2("Expected: %ld\tTransfered:%ld\n",
+ XferReqHndl->u.TRANS_REQ.DataSize, BytesTransferred );
+ }
+ }
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ ++XferReqHndl->u.TRANS_REQ.InstanceCounters->XferDataFails;
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ }
+ else
+ {
+ //
+ // NdisTransferData completed successfully and thus proceed with
+ // checking the received data and see if it was corrupted.
+ //
+
+ while ( i < XferReqHndl->u.TRANS_REQ.DataSize )
+ {
+ if ( Memory[i++] != (UCHAR)( XferReqHndl->u.TRANS_REQ.DataOffset++ % 256 ))
+ {
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ ++XferReqHndl->u.TRANS_REQ.InstanceCounters->CorruptRecs;
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ IF_TPDBG ( TP_DEBUG_DATA )
+ {
+ TpPrint1("TpStressCheckPacketData2: Data Error at offset %d in packet data\n",
+ i-1);
+ TpPrint2(" Found %02x, Expected %02x\n\n",
+ Memory[i-1],(( XferReqHndl->u.TRANS_REQ.DataOffset - 1 ) % 256 ));
+ TpBreakPoint();
+ }
+ break;
+ } // End of the if
+ } // End of the while
+ } // End of the if-else
+
+ //
+ // Finally Free up the packet, buffer memory and finally the RequestHandle.
+ //
+
+ NdisFreeMemory( Memory,0,0 );
+ IoFreeMdl( TransferBuffer );
+ NdisFreePacket( Packet );
+ NdisFreeMemory( XferReqHndl,0,0 );
+
+ //
+ // Decrement the Pending Requests and set the stressing flag to
+ // stop all stressing if the time is right counter.
+ //
+
+ NdisAcquireSpinLock( &OpenP->Stress->Pend->SpinLock );
+ --OpenP->Stress->Pend->PendingRequests;
+
+ if (((( OpenP->Stress->StopStressing == TRUE ) &&
+ ( OpenP->Stress->StressFinal == TRUE )) &&
+ ( OpenP->Stress->Pend->PendingRequests == 0 )) &&
+ ( OpenP->Stress->Pend->PendingPackets == 0 ))
+ {
+ OpenP->Stress->Stressing = FALSE;
+ NdisReleaseSpinLock( &OpenP->Stress->Pend->SpinLock );
+ TpStressFreeResources( OpenP );
+ }
+ else
+ {
+ NdisReleaseSpinLock( &OpenP->Stress->Pend->SpinLock );
+ }
+}
+
+
+
+VOID
+TpStressDoNothing(
+ VOID
+ )
+{
+//
+// This function is used to ensure that busy loops don't
+// get completely optimized out by the compiler.
+//
+
+ return;
+}
+
+
+
diff --git a/private/ntos/ndis/testprot/tpdrvr/strrcv.c b/private/ntos/ndis/testprot/tpdrvr/strrcv.c
new file mode 100644
index 000000000..e7e8f1209
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpdrvr/strrcv.c
@@ -0,0 +1,1280 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ tpstress.c
+
+Abstract:
+
+ This module implements the Test Protocol Stress routines and the
+ basic controls for stressing the MAC.
+
+Author:
+
+ Tom Adams (tomad) 15-Dec-1990
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include <ndis.h>
+#include <string.h>
+
+#include "tpdefs.h"
+#include "media.h"
+#include "tpprocs.h"
+
+
+
+NDIS_STATUS
+TpStressReceive(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)ProtocolBindingContext);
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PNDIS_PACKET Packet;
+ PCLIENT_STORAGE Client;
+ PSERVER_STORAGE Server;
+ PSTRESS_ARGUMENTS Args;
+ PPACKET_INFO pi;
+ PSTRESS_CONTROL sc;
+ UCHAR NextClient;
+ UCHAR NextServer;
+ INT NewPacketSize;
+ INT NumResponses;
+ BOOLEAN NewClient;
+ BOOLEAN NewServer;
+ PUCHAR DestAddr;
+ PUCHAR SrcAddr;
+
+ DestAddr = (PUCHAR)HeaderBuffer + (ULONG)OpenP->Media->DestAddrOffset;
+ SrcAddr = (PUCHAR)HeaderBuffer + (ULONG)OpenP->Media->SrcAddrOffset;
+
+ //
+ // pi is the packet information section of the test prot packet header,
+ // sc is the stress control section of the testprot packet header. We
+ // will us pi and sc to quickly reference info in the header.
+ //
+
+ pi = (PPACKET_INFO)LookaheadBuffer;
+
+ sc = (PSTRESS_CONTROL)((PUCHAR)LookaheadBuffer +
+ (ULONG)sizeof( PACKET_INFO ));
+
+ if ( !TpCheckSum(
+ (PUCHAR)pi,
+ sizeof( STRESS_PACKET ) -
+ ( sizeof( ULONG ) + OpenP->Media->HeaderSize ),
+ (PULONG)&sc->CheckSum
+ )) {
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ ++OpenP->GlobalCounters->CorruptRecs;
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ Status = NDIS_STATUS_NOT_RECOGNIZED;
+ }
+
+ Client = OpenP->Stress->Client;
+ Server = OpenP->Stress->Server;
+ Args = OpenP->Stress->Arguments;
+
+ switch( pi->u.PacketProtocol ) {
+
+ //
+ // A REGISTER_REQ(2) packet is a request from a TP_CLIENT to
+ // participate in a stress test. If this packet is from a new
+ // client then a response packet will be set back to the client,
+ // the client will be added to the Clients array, and its counters
+ // and control structures for the test will be reset. If this is
+ // an old client, then we will just reset the counters and control
+ // structures.
+ //
+
+ case REGISTER_REQ:
+ case REGISTER_REQ2:
+
+ //
+ // Is this packet really destined for us, check that the
+ // destination address matches the stress address.
+ //
+
+ if ( RtlCompareMemory(
+ DestAddr,
+ OpenP->Environment->StressAddress,
+ OpenP->Media->AddressLen ) !=
+ OpenP->Media->AddressLen ) {
+
+ //
+ // the destination address does not match the stress
+ // address, we should never have received this packet!
+ //
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ ++OpenP->GlobalCounters->InvalidPacketRecs;
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ //
+ // This packet is a request from a Client to register.
+ // Are we a Server?
+ //
+
+ } else if ( Args->MemberType == TP_CLIENT ) {
+
+ //
+ // No! We are not a Server, ignore this packet.
+ //
+
+ Status = NDIS_STATUS_NOT_RECOGNIZED;
+
+ } else {
+
+ //
+ // If there is room, see if this is a new client and if so
+ // register it, and send a REGISTER_RESP packet.
+ //
+
+ if ( Server->NumClients < MAX_CLIENTS ) {
+
+ NextClient = 0;
+ NewClient = TRUE;
+
+ //
+ // See if we have already registered this client.
+ //
+
+ while ( NextClient < Server->NumClients ) {
+
+ //
+ // If the Src Address matches a previously registered
+ // Client, and the Open Instance of that Client matches
+ // the Src Instance then we have already registered
+ // this Client, reset the counters, send a response,
+ // but ignore it. Otherwise this is a new Client so
+ // register it properly.
+ //
+
+ if (( RtlCompareMemory(
+ SrcAddr,
+ Server->Clients[NextClient].Address,
+ OpenP->Media->AddressLen ) ==
+ (ULONG)OpenP->Media->AddressLen )
+
+ &&
+
+ ( pi->SrcInstance ==
+ Server->Clients[NextClient].ClientInstance )) {
+
+ //
+ // We have already registered with this client.
+ //
+
+ NewClient = FALSE;
+ break;
+
+ } else {
+
+ //
+ // This is not a match , try the next one.
+ //
+
+ NextClient++;
+ }
+ }
+ }
+
+ //
+ // This REGISTER_REQ(2) packet is from a New Client, and we
+ // have room for it, so register it.
+ //
+
+ if ( NewClient == TRUE ) {
+
+ IF_TPDBG ( TP_DEBUG_DPC ) {
+ TpPrint0("TpStressReceive: REGISTER_REQ(2) - Registering Client\n");
+ }
+
+ //
+ // set up the CLIENT_INFO data structure and initialize it.
+ //
+
+ NextClient = Server->NumClients++;
+ ++Server->ActiveClients;
+ Server->Clients[NextClient].ClientReference = NextClient;
+ Server->Clients[NextClient].ClientInstance = pi->SrcInstance;
+ Server->Clients[NextClient].ServerResponseType = sc->ResponseType;
+ Server->Clients[NextClient].DataChecking = sc->DataChecking;
+ Server->Clients[NextClient].LastSequenceNumber = 0;
+
+ RtlMoveMemory(
+ Server->Clients[NextClient].Address,
+ SrcAddr,
+ OpenP->Media->AddressLen
+ );
+
+ //
+ // Now allocate and initialize the instances counter
+ //
+
+ Status = NdisAllocateMemory(
+ (PVOID *)&Server->Clients[NextClient].Counters,
+ sizeof( INSTANCE_COUNTERS ),
+ 0,
+ HighestAddress
+ );
+
+ if ( Status != NDIS_STATUS_SUCCESS ) {
+ IF_TPDBG (TP_DEBUG_RESOURCES) {
+ TpPrint0("TpStressReceive: failed to allocate counters.\n");
+ }
+
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+
+ } else {
+
+ NdisZeroMemory(
+ (PVOID)Server->Clients[NextClient].Counters,
+ sizeof( INSTANCE_COUNTERS )
+ );
+ }
+ } else if ( pi->u.PacketProtocol == REGISTER_REQ ) {
+
+ NdisZeroMemory(
+ (PVOID)Server->Clients[NextClient].Counters,
+ sizeof( INSTANCE_COUNTERS )
+ );
+
+ Server->Clients[NextClient].ServerResponseType = sc->ResponseType;
+ Server->Clients[NextClient].DataChecking = sc->DataChecking;
+ Server->Clients[NextClient].LastSequenceNumber = 0;
+ }
+
+ if (( pi->u.PacketProtocol == REGISTER_REQ ) ||
+ ( NewClient == TRUE )) {
+
+ //
+ // Then build a REGISTER_RESP packet to register with, and
+ // send it to the Client.
+ //
+
+ do {
+ Packet = TpStressCreatePacket(
+ OpenP,
+ Server->PacketHandle,
+ Args->PacketMakeUp,
+ pi->SrcInstance,
+ OpenP->OpenInstance,
+ REGISTER_RESP,
+ Args->ResponseType,
+ SrcAddr,
+ sizeof( STRESS_PACKET ),
+ sizeof( STRESS_PACKET ),
+ sc->SequenceNumber,
+ sc->SequenceNumber +
+ OpenP->Environment->WindowSize,
+ NextClient,
+ 0,
+ Args->DataChecking
+ );
+
+ if ( Packet == NULL ) {
+ IF_TPDBG ( TP_DEBUG_RESOURCES ) {
+ TpPrint0("TpStressReceive: failed to create REGISTER_RESP Packet\n");
+ }
+ }
+ } while ( Packet == NULL );
+
+ //
+ // And send it.
+ //
+
+ TpStressSend( OpenP,Packet,NULL );
+ }
+ }
+
+ break;
+
+ //
+ // A REGISTER_RESP packet is a response from a TP_SERVER to a
+ // previously sent REGISTER_REQ(2) that the server will be
+ // participating in the next stress test. If this packet is from
+ // a new server then the server will be added to the Server array,
+ // and its counters and control structures for the test will be
+ // reset. If the response packet is from an old client, then we
+ // will just reset the counters.
+ //
+
+ case REGISTER_RESP:
+
+ //
+ // Is this packet really destined for us, check that the
+ // destination address matches the local card address we
+ // queried and stored in the OPEN_BLOCK.
+ //
+
+ if ( RtlCompareMemory(
+ DestAddr,
+ OpenP->StationAddress,
+ OpenP->Media->AddressLen ) !=
+ OpenP->Media->AddressLen ) {
+
+ //
+ // the destination address does not match the local card
+ // address, we should never have received this packet!
+ //
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ ++OpenP->GlobalCounters->InvalidPacketRecs;
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ //
+ // This packet is a response from a Server to register. Are we a Client?
+ //
+
+ } else if ( Args->MemberType == TP_SERVER ) {
+
+ //
+ // No! We are not a Client, ignore this packet.
+ //
+
+ Status = NDIS_STATUS_NOT_RECOGNIZED;
+
+ } else {
+
+ if ( Client->NumServers < MAX_SERVERS ) {
+
+ NextServer = 0;
+ NewServer = TRUE;
+
+ //
+ // See if this is a new server.
+ //
+
+ while ( NextServer < Client->NumServers ) {
+
+ if (( RtlCompareMemory(
+ SrcAddr,
+ Client->Servers[NextServer].Address,
+ OpenP->Media->AddressLen) ==
+ (ULONG)OpenP->Media->AddressLen )
+
+ &&
+
+ ( pi->SrcInstance ==
+ Client->Servers[NextServer].ServerInstance )) {
+
+ //
+ // This server has already registered, ignore it.
+ //
+
+ NewServer = FALSE;
+ break;
+
+ } else {
+
+ //
+ // Not this server, try the next one.
+ //
+
+ NextServer++;
+ }
+ }
+ }
+
+ if ( NewServer == TRUE ) {
+
+ IF_TPDBG ( TP_DEBUG_DPC ) {
+ TpPrint0("TpStressReceive: REGISTER_RESP - Registering Server\n");
+ }
+
+ //
+ // set up the SERVER_INFO data structure and initialize it.
+ //
+
+ NextServer = Client->NumServers++;
+ NextServer = Client->ActiveServers++;
+
+ Client->Servers[NextServer].ServerReference = NextServer;
+ Client->Servers[NextServer].ClientReference = sc->ClientReference;
+ Client->Servers[NextServer].ServerInstance = pi->SrcInstance;
+ Client->Servers[NextServer].ServerActive = TRUE;
+ Client->Servers[NextServer].LastSequenceNumber = 0;
+
+ RtlMoveMemory(
+ Client->Servers[NextServer].Address,
+ SrcAddr,
+ OpenP->Media->AddressLen
+ );
+
+ //
+ // Now allocate and initialize the instances counter
+ //
+
+ Status = NdisAllocateMemory(
+ (PVOID *)&Client->Servers[NextServer].Counters,
+ sizeof( INSTANCE_COUNTERS ),
+ 0,
+ HighestAddress
+ );
+
+ if ( Status != NDIS_STATUS_SUCCESS ) {
+ IF_TPDBG (TP_DEBUG_RESOURCES) {
+ TpPrint0("TpStressReceive: failed to allocate counters.\n");
+ }
+
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+
+ } else {
+
+ NdisZeroMemory(
+ (PVOID)Client->Servers[NextServer].Counters,
+ sizeof( INSTANCE_COUNTERS )
+ );
+ }
+
+ } else {
+
+ //
+ // Old Server, reset the statistics counters.
+ //
+
+ NdisZeroMemory(
+ (PVOID)Client->Servers[NextServer].Counters,
+ sizeof( INSTANCE_COUNTERS )
+ );
+
+ Client->Servers[NextServer].LastSequenceNumber = 0;
+ }
+ }
+
+ break;
+
+ //
+ // A TEST_REQ packet is the standard test packet sent from a the
+ // client to each of the servers participating in the test. This
+ // packet is evaluated for data integrity, counted, and the required
+ // response packet is returned to the client.
+ //
+
+ case TEST_REQ:
+
+ //
+ // Is this packet really destined for us, check that the
+ // destination address matches the local card address we
+ // queried and stored in the OPEN_BLOCK.
+ //
+
+ if ( RtlCompareMemory(
+ DestAddr,
+ OpenP->StationAddress,
+ OpenP->Media->AddressLen ) !=
+ OpenP->Media->AddressLen ) {
+
+ //
+ // the destination address does not match the local card
+ // address, we should never have received this packet!
+ //
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ ++OpenP->GlobalCounters->InvalidPacketRecs;
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ //
+ // This packet is a test request from a Client. Are we a Server?,
+ //
+
+ } else if ( Args->MemberType == TP_CLIENT ) {
+
+ //
+ // No! We are not a Server, ignore this packet.
+ //
+
+ Status = NDIS_STATUS_NOT_RECOGNIZED;
+
+ //
+ // Is this a client we have previously registered with?
+ //
+
+ } else if (( RtlCompareMemory(
+ SrcAddr,
+ Server->Clients[sc->ClientReference].Address,
+ OpenP->Media->AddressLen) !=
+ (ULONG)OpenP->Media->AddressLen )
+
+ ||
+
+ ( pi->SrcInstance !=
+ Server->Clients[sc->ClientReference].ClientInstance )) {
+
+ //
+ // No! We should ignore this packet.
+ //
+
+ Status = NDIS_STATUS_NOT_RECOGNIZED;
+
+ //
+ // Is this packet destined for our open instance or another
+ // open instance of the same card?
+ //
+
+ } else if (( RtlCompareMemory(
+ SrcAddr,
+ Server->Clients[sc->ClientReference].Address,
+ OpenP->Media->AddressLen) ==
+ (ULONG)OpenP->Media->AddressLen)
+
+ &&
+
+ ( pi->DestInstance != OpenP->OpenInstance )) {
+
+ //
+ // No, this packet is for some other open instance.
+ //
+
+ Status = NDIS_STATUS_NOT_RECOGNIZED;
+
+ } else {
+
+ if ( Args->BeginReceives == FALSE ) {
+
+ IF_TPDBG ( TP_DEBUG_DPC ) {
+ TpPrint0("TpStressReceive: received TEST_REQ packet, not initialized\n");
+ }
+ // Increment receive counter for accounting purposes.
+ break;
+ }
+
+ //
+ // Has this packet arrived out of order?
+ //
+
+ if ( sc->SequenceNumber <= Server->Clients[sc->ClientReference].LastSequenceNumber ) {
+ IF_TPDBG ( TP_DEBUG_NDIS_ERROR ) {
+ TpPrint0("\nTpStressReceive: PACKET ARRIVED OUT OF ORDER, OR ARRIVED TWICE !!!\n");
+ TpPrint3("TEST_REQ Packet: Sequence Number %d @ 0x%lX, expected greater than %d.\n\n",
+ sc->SequenceNumber, HeaderBuffer,
+ Server->Clients[sc->ClientReference].LastSequenceNumber);
+ TpBreakPoint();
+ }
+ } else {
+ Server->Clients[sc->ClientReference].LastSequenceNumber = sc->SequenceNumber;
+ }
+
+ if ( Server->Clients[sc->ClientReference].DataChecking == TRUE ) {
+
+ if (( pi->PacketSize - sizeof( STRESS_PACKET )) > 0 ) {
+
+ TpStressCheckPacketData(
+ OpenP,
+ MacReceiveContext,
+ sc->DataBufOffset,
+ pi->PacketSize,
+ Server->Clients[sc->ClientReference].Counters
+ );
+ }
+ }
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ ++Server->Clients[sc->ClientReference].Counters->Receives;
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ switch( Server->Clients[sc->ClientReference].ServerResponseType ) {
+
+ case NO_RESPONSE:
+
+ NumResponses = 0;
+ break;
+
+ case FULL_RESPONSE:
+
+ NumResponses = 1;
+ NewPacketSize = pi->PacketSize;
+ break;
+
+ case ACK_EVERY:
+
+ NumResponses = 1;
+ NewPacketSize = sizeof( STRESS_PACKET );
+ break;
+
+ case ACK_10_TIMES:
+
+ NumResponses = 10;
+ NewPacketSize = sizeof( STRESS_PACKET );
+ break;
+
+ default:
+ IF_TPDBG ( TP_DEBUG_DPC ) {
+ TpPrint0("TpStressReceive: Unknown Response Type\n");
+ }
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ ++OpenP->GlobalCounters->CorruptRecs;
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ Status = NDIS_STATUS_NOT_RECOGNIZED;
+ break;
+ }
+
+ while ( NumResponses-- > 0 ) {
+
+ //
+ // if send now, build and send a TEST_RESP packet
+ //
+
+ TpStressServerSend(
+ OpenP,
+ Server->TransmitPool,
+ SrcAddr,
+ pi->SrcInstance,
+ OpenP->OpenInstance,
+ sc->SequenceNumber,
+ sc->SequenceNumber +
+ OpenP->Environment->WindowSize,
+ sc->ClientReference,
+ sc->ServerReference,
+ NewPacketSize,
+ sc->DataBufOffset
+ );
+ }
+
+ //
+ // else queue send for TpStressReceiveComplete send
+ //
+ }
+
+ break;
+
+ //
+ // A TEST_RESP packet is the response from a server to a client's
+ // TEST_REQ packet. This packet is checked for data integrity,
+ // counted, and discarded.
+ //
+
+ case TEST_RESP:
+
+ //
+ // Is this packet really destined for us, check that the
+ // destination address matches the local card address we
+ // queried and stored in the OPEN_BLOCK.
+ //
+
+ if ( RtlCompareMemory(
+ DestAddr,
+ OpenP->StationAddress,
+ OpenP->Media->AddressLen ) !=
+ OpenP->Media->AddressLen ) {
+
+ //
+ // the destination address does not match the local card
+ // address, we should never have received this packet!
+ //
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ ++OpenP->GlobalCounters->InvalidPacketRecs;
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ //
+ // This packet is a test response from a Server. Are we a Client?
+ //
+
+ } else if ( Args->MemberType == TP_SERVER ) {
+
+ //
+ // No! We are not a Client, ignore this packet.
+ //
+
+ Status = NDIS_STATUS_NOT_RECOGNIZED;
+
+ //
+ // Is this a Server that has previously registered with us?
+ //
+
+ } else if (( RtlCompareMemory(
+ SrcAddr,
+ Client->Servers[sc->ServerReference].Address,
+ OpenP->Media->AddressLen) !=
+ (ULONG)OpenP->Media->AddressLen )
+
+ ||
+
+ ( pi->SrcInstance !=
+ Client->Servers[sc->ServerReference].ServerInstance )) {
+
+ //
+ // No! We should ignore this packet.
+ //
+
+ Status = NDIS_STATUS_NOT_RECOGNIZED;
+
+ //
+ // Is this packet destined for this open instance or another
+ // open instance of the same card?
+ //
+
+ } else if (( RtlCompareMemory(
+ SrcAddr,
+ Client->Servers[sc->ServerReference].Address,
+ OpenP->Media->AddressLen) ==
+ (ULONG)OpenP->Media->AddressLen)
+
+ &&
+
+ ( pi->DestInstance != OpenP->OpenInstance )) {
+
+ //
+ // This packet is for some other open instance, ignore it.
+ //
+
+ Status = NDIS_STATUS_NOT_RECOGNIZED;
+
+ } else {
+
+ //
+ // Has this packet arrived out of order?
+ //
+
+ if ( sc->SequenceNumber <= Client->Servers[sc->ServerReference].LastSequenceNumber ) {
+
+ if (( Args->ResponseType == ACK_10_TIMES ) &&
+ ( sc->SequenceNumber == Client->Servers[sc->ServerReference].LastSequenceNumber )) {
+ ; // This is okay, we expect 10 packets with same
+ // number ignore packet.
+ } else {
+
+ //
+ // A Packet has arrived out or order, PANIC!
+ //
+
+ IF_TPDBG ( TP_DEBUG_DPC ) {
+ TpPrint0("\nTpStressReceive: PACKET ARRIVED OUT OF ORDER, OR ARRIVED TWICE !!!\n");
+ TpPrint3("TEST_RESP Packet: Sequence Number %d @ 0x%lX, expected greater than %d.\n\n",
+ sc->SequenceNumber, HeaderBuffer,
+ Client->Servers[sc->ServerReference].LastSequenceNumber);
+ TpBreakPoint();
+ }
+ }
+ } else {
+ Client->Servers[sc->ServerReference].LastSequenceNumber = sc->SequenceNumber;
+ }
+
+ if ( Args->WindowEnabled == TRUE ) {
+ Client->Servers[sc->ServerReference].MaxSequenceNumber = sc->MaxSequenceNumber;
+ } else {
+ Client->Servers[sc->ServerReference].MaxSequenceNumber = 0xFFFFFFFF;
+ }
+
+ //
+ // We have received a packet from this server so zero its
+ // window resetting counter in case it has any strikes
+ // against it.
+ //
+
+ Client->Servers[sc->ServerReference].WindowReset = 0;
+
+ //
+ // Update the instance receive counters for the Server
+ //
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ ++Client->Servers[sc->ServerReference].Counters->Receives;
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ if ( Args->DataChecking == TRUE ) {
+
+ if (( pi->PacketSize - sizeof( STRESS_PACKET )) > 0 ) {
+
+ TpStressCheckPacketData(
+ OpenP,
+ MacReceiveContext,
+ sc->DataBufOffset,
+ pi->PacketSize,
+ Client->Servers[sc->ServerReference].Counters
+ );
+ }
+ }
+ }
+
+ break;
+
+ //
+ // A STATS_REQ packet is a request by the client at the end of
+ // a stress test for the server to return the statistics.
+ //
+
+ case STATS_REQ:
+
+ //
+ // Is this packet really destined for us, check that the
+ // destination address matches the local card address we
+ // queried and stored in the OPEN_BLOCK.
+ //
+
+ if ( RtlCompareMemory(
+ DestAddr,
+ OpenP->StationAddress,
+ OpenP->Media->AddressLen ) !=
+ OpenP->Media->AddressLen ) {
+
+ //
+ // the destination address does not match the local card
+ // address, we should never have received this packet!
+ //
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ ++OpenP->GlobalCounters->InvalidPacketRecs;
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ //
+ // This packet is a Statistics request from a Client.
+ // Are we a Server?,
+ //
+
+ } else if ( Args->MemberType == TP_CLIENT ) {
+
+ //
+ // No! We are not a Server, ignore this packet.
+ //
+
+ Status = NDIS_STATUS_NOT_RECOGNIZED;
+
+ //
+ // Is this a client we have previously registered with?
+ //
+
+ } else if (( RtlCompareMemory(
+ SrcAddr,
+ Server->Clients[sc->ClientReference].Address,
+ OpenP->Media->AddressLen ) !=
+ (ULONG)OpenP->Media->AddressLen )
+
+ ||
+
+ ( pi->SrcInstance !=
+ Server->Clients[sc->ClientReference].ClientInstance )) {
+
+ //
+ // No! We should ignore this packet.
+ //
+
+ Status = NDIS_STATUS_NOT_RECOGNIZED;
+
+ //
+ // Is this packet destined for our open instance or another
+ // open instance on the same card?
+ //
+
+ } else if (( pi->DestInstance != OpenP->OpenInstance )
+
+ &&
+
+ ( RtlCompareMemory(
+ SrcAddr,
+ Server->Clients[sc->ClientReference].Address,
+ OpenP->Media->AddressLen ) ==
+ (ULONG)OpenP->Media->AddressLen )) {
+
+ //
+ // This packet is for some other open instance, ignore it.
+ //
+
+ Status = NDIS_STATUS_NOT_RECOGNIZED;
+
+ } else {
+
+ //
+ // We need to respond to the client's request for the
+ // test statistics, so create a STATS_RESP packet,
+ //
+
+ Packet = TpStressCreatePacket(
+ OpenP,
+ Server->PacketHandle,
+ KNOWN,
+ pi->SrcInstance,
+ OpenP->OpenInstance,
+ STATS_RESP,
+ Args->ResponseType,
+ SrcAddr,
+
+ sizeof( STRESS_PACKET ) +
+ sizeof( INSTANCE_COUNTERS ) +
+ sizeof( GLOBAL_COUNTERS ), // PacketSize
+
+ sizeof( STRESS_PACKET ) +
+ sizeof( INSTANCE_COUNTERS ) +
+ sizeof( GLOBAL_COUNTERS ), // BufferSize
+
+ sc->SequenceNumber,
+ sc->SequenceNumber,
+ sc->ClientReference,
+ sc->ServerReference,
+ FALSE
+ );
+
+ if ( Packet == NULL ) {
+ IF_TPDBG(TP_DEBUG_RESOURCES) {
+ TpPrint0("TpStressReceive: failed to create STATS_RESP Packet\n");
+ }
+ } else {
+
+ //
+ // Write the statistics into the packet,
+ //
+
+ TpWriteServerStatistics(
+ OpenP,
+ Packet,
+ &Server->Clients[sc->ClientReference]
+ );
+
+ if ( sc->SequenceNumber == 0 ) {
+
+ //
+ // Maybe instead of checking the SequenceNumber is
+ // zero, the first packet, we should have a flag in
+ // the server for this in case we miss the first
+ // STATS_REQ packet.
+ //
+
+ TpPrintServerStatistics(
+ OpenP,
+ &Server->Clients[sc->ClientReference]
+ );
+ }
+
+ //
+ // And send it back to the Client.
+ //
+
+ TpStressSend( OpenP,Packet,NULL );
+ }
+ }
+
+ break;
+
+ //
+ // A STATS_RESP packet is the server responding to a clients
+ // request for stress statistics. The stats a bundled in the
+ // data field of the packet. The client will read them into
+ // the local buffer and discard the packet.
+ //
+
+ case STATS_RESP:
+
+ //
+ // Is this packet really destined for us, check that the
+ // destination address matches the local card address we
+ // queried and stored in the OPEN_BLOCK.
+ //
+
+ if ( RtlCompareMemory(
+ DestAddr,
+ OpenP->StationAddress,
+ OpenP->Media->AddressLen ) !=
+ OpenP->Media->AddressLen ) {
+
+ //
+ // the destination address does not match the local card
+ // address, we should never have received this packet!
+ //
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ ++OpenP->GlobalCounters->InvalidPacketRecs;
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ //
+ // This packet is a Statistics response from a Server.
+ // Are we a Client?
+ //
+
+ } else if ( Args->MemberType == TP_SERVER ) {
+
+ //
+ // No! We are not a Client, ignore this packet.
+ //
+
+ Status = NDIS_STATUS_NOT_RECOGNIZED;
+
+ //
+ // Is this a Server that has previously registered with us?
+ //
+
+ } else if (( RtlCompareMemory(
+ SrcAddr,
+ Client->Servers[sc->ServerReference].Address,
+ OpenP->Media->AddressLen) !=
+ (ULONG)OpenP->Media->AddressLen )
+
+ ||
+
+ ( pi->SrcInstance !=
+ Client->Servers[sc->ServerReference].ServerInstance )) {
+
+ //
+ // No! We should ignore this packet.
+ //
+
+ Status = NDIS_STATUS_NOT_RECOGNIZED;
+
+ //
+ // Is this packet destined for our open instance or another
+ // open instance on the same card?
+ //
+
+ } else if (( pi->DestInstance != OpenP->OpenInstance ) &&
+ ( RtlCompareMemory(
+ SrcAddr,
+ Client->Servers[sc->ServerReference].Address,
+ OpenP->Media->AddressLen) ==
+ (ULONG)OpenP->Media->AddressLen )) {
+
+ //
+ // This packet is for some other open instance, ignore it.
+ //
+
+ Status = NDIS_STATUS_NOT_RECOGNIZED;
+
+ } else {
+
+ //
+ // Copy the server's stats to the Stress Results buffer.
+ //
+
+ TpCopyServerStatistics(
+ OpenP,
+ LookaheadBuffer,
+ sc->ServerReference
+ );
+ }
+
+ break;
+
+ //
+ // AN END_REQ packet is a notification by a client that the stress
+ // test has completed. The server decrements the number of clients,
+ // and discards the packet.
+ //
+
+ case END_REQ:
+ {
+ UINT i;
+
+ //
+ // Is this packet really destined for us, check that the
+ // destination address matches the local card address we
+ // queried and stored in the OPEN_BLOCK.
+ //
+
+ if ( RtlCompareMemory(
+ DestAddr,
+ OpenP->StationAddress,
+ OpenP->Media->AddressLen ) !=
+ OpenP->Media->AddressLen ) {
+
+ //
+ // the destination address does not match the local card
+ // address, we should never have received this packet!
+ //
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ ++OpenP->GlobalCounters->InvalidPacketRecs;
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ //
+ // This packet is an end request from a Client. Are we a Server?,
+ //
+
+ } else if ( Args->MemberType == TP_CLIENT ) {
+
+ //
+ // No! We are not a Server, ignote this packet.
+ //
+
+ Status = NDIS_STATUS_NOT_RECOGNIZED;
+
+ //
+ // Is this a client we have previously registered with?
+ //
+
+ } else if (( RtlCompareMemory(
+ SrcAddr,
+ Server->Clients[sc->ClientReference].Address,
+ OpenP->Media->AddressLen) !=
+ (ULONG)OpenP->Media->AddressLen )
+
+ ||
+
+ ( pi->SrcInstance !=
+ Server->Clients[sc->ClientReference].ClientInstance )) {
+
+ //
+ // No! We should ignore this packet.
+ //
+
+ Status = NDIS_STATUS_NOT_RECOGNIZED;
+
+ //
+ // Is this packet destined for our open instance or another
+ // open instance on the same card?
+ //
+
+ } else if (( pi->DestInstance != OpenP->OpenInstance )
+
+ &&
+
+ ( RtlCompareMemory(
+ SrcAddr,
+ Server->Clients[sc->ClientReference].Address,
+ OpenP->Media->AddressLen) ==
+ (ULONG)OpenP->Media->AddressLen)) {
+
+ //
+ // This packet is for some other open instance, ignore it.
+ //
+
+ Status = NDIS_STATUS_NOT_RECOGNIZED;
+
+ } else {
+
+ if ( Server->Clients[sc->ClientReference].TestEnding == FALSE ) {
+ Server->Clients[sc->ClientReference].TestEnding = TRUE;
+ --Server->ActiveClients;
+ }
+
+ //
+ // If we are running as only a server, and there are packets
+ // remaining in the Pend Queue, display them to the debug
+ // screen.
+ //
+
+ if (( Args->MemberType == TP_SERVER ) &&
+ ( OpenP->Stress->Pend->PendingPackets != 0 )) {
+
+ //
+ // There are packets in the pend queue, so print out
+ // the packet addresses and break.
+ //
+
+ IF_TPDBG( TP_DEBUG_DPC ) {
+
+ TpPrint1("TpStressEndDpc: The following %d packets are still in the\n",
+ OpenP->Stress->Pend->PendingPackets);
+ TpPrint1(" Server's Pend Queue for Open Instance %d.\n",
+ OpenP->OpenInstance);
+ TpPrint1(" Pend Queue = %lX\n\n",
+ OpenP->Stress->Pend);
+
+ for ( i=0 ; i<NUM_PACKET_PENDS ; i++ ) {
+
+ if (( OpenP->Stress->Pend->Packets[i] != NULL ) &&
+ ( OpenP->Stress->Pend->Packets[i] != (PNDIS_PACKET)-1 )) {
+
+ TpPrint1("\t\t%lX\n", OpenP->Stress->Pend->Packets[i]);
+ }
+ }
+
+ TpBreakPoint();
+
+ //
+ // And set the PendingPackets counter to zero, so
+ // we will not print this message on the remainder
+ // of the END_REQ packets that we receive.
+ //
+
+ OpenP->Stress->Pend->PendingPackets = 0;
+ }
+
+ TpInitializePending( OpenP->Stress->Pend );
+ }
+ }
+ break;
+ }
+ default:
+ IF_TPDBG ( TP_DEBUG_DPC ) {
+ TpPrint0("TpStressReceive: Unknown Packet Protocol\n");
+ }
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ ++OpenP->GlobalCounters->CorruptRecs;
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ Status = NDIS_STATUS_NOT_RECOGNIZED;
+ }
+
+ return Status;
+}
+
+
+VOID
+TpStressReceiveComplete(
+ IN NDIS_HANDLE ProtocolBindingContext
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)ProtocolBindingContext);
+ ULONG i;
+
+ if (( OpenP->Stress != NULL ) &&
+ ( OpenP->Stress->Client != NULL )) {
+
+ for ( i=0;i<MAX_SERVERS;i++ ) {
+
+ if ( OpenP->Stress->Client->Servers[i].Counters != NULL ) {
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ ++OpenP->Stress->Client->Servers[i].Counters->ReceiveComps;
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ }
+ }
+ }
+
+ if (( OpenP->Stress != NULL ) &&
+ ( OpenP->Stress->Server != NULL )) {
+
+ for ( i=0;i<MAX_CLIENTS;i++ ) {
+
+ if ( OpenP->Stress->Server->Clients[i].Counters != NULL ) {
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ ++OpenP->Stress->Server->Clients[i].Counters->ReceiveComps;
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ }
+ }
+ }
+
+ return;
+}
diff --git a/private/ntos/ndis/testprot/tpdrvr/tpdefs.h b/private/ntos/ndis/testprot/tpdrvr/tpdefs.h
new file mode 100644
index 000000000..82ee3ce83
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpdrvr/tpdefs.h
@@ -0,0 +1,769 @@
+// -----------------------------------------
+//
+// Copyright (c) 1990 Microsoft Corporation
+//
+// Module Name:
+//
+// tpdefs.h
+//
+// Abstract:
+//
+// Definitions for stress and test sections of the Test Protocol.
+//
+// Author:
+//
+// Tom Adams (tomad) 16-Jul-1990
+//
+// Environment:
+//
+// Kernel mode, FSD
+//
+// Revision History:
+//
+//
+// Tom Adams (tomad) 27-Nov-1990
+// Divided the procedures and defintions into two seperate include files.
+// Added definitions for TpRunTest and support routines.
+//
+// Tom Adams (tomad) 30-Dec-1990
+// Added defintions for TpStress and support routines.
+//
+// Sanjeev Katariya 3-16-1993
+// Added structure for async RESET processing: Bug #2874
+// Added support for native ARCNET
+//
+// Tim Wynsma (timothyw) 4-27-94
+// Added performance tests
+// Chgs for performance tests -- 5-18-94
+// Chgd perf tests to client server -- 6-08-94
+//
+// Notes:
+//
+// 1. ARCNET Support. Most stress and other functional structures have fields
+// describing the addresses of lengths = ADDRESS_LENGTH(6 octects). This does
+// not need to be changed for arcnet since we will use only the first octect.
+// The rest can simply be set to 0 or any other preferred pad value. This is true
+// however for the tests formats and NOT the media header
+//
+// -----------------------------------------
+
+#include "common.h"
+
+struct _TP_MEDIA_INFO;
+
+//
+// Define the various packet protocols used in TpStress.
+//
+// REGISTER REQ and REQ2 are used to request Servers to assist in running
+// a test, REGISTER RESP is used to respond to a Client's register request.
+// TEST REQ and RESP are the actual test packets, STATS REQ and RESP are the
+// method of asking for and collecting statistics from all Servers. Finally
+// END REQ and RESP are the packets used to tell all Servers that the test
+// is over, and to clean up and end.
+//
+
+#define REGISTER_REQ 0x00
+#define REGISTER_REQ2 0x01
+#define REGISTER_RESP 0x02
+#define TEST_REQ 0x03
+#define TEST_RESP 0x04
+#define STATS_REQ 0x05
+#define STATS_RESP 0x06
+#define END_REQ 0x07
+#define END_RESP 0x08
+
+//
+// Test Packet headers used to describe the contents of the three seperate
+// types of packets; FUNC1_PACKET, FUNC2_PACKET, and STRESS_PACKET.
+//
+
+//
+// These structures need to be packed, and the pointers need to be
+// defined as UNALIGNED for MIPS.
+//
+
+#include <packon.h>
+
+//
+// Ethernet packet header description
+//
+
+typedef struct _E_802_3 {
+ UCHAR DestAddress[ADDRESS_LENGTH];
+ UCHAR SrcAddress[ADDRESS_LENGTH];
+ UCHAR PacketSize_Hi;
+ UCHAR PacketSize_Lo;
+} E_802_3;
+typedef E_802_3 UNALIGNED *PE_802_3;
+
+//
+// Token Ring packet header description
+//
+
+typedef struct _TR_802_5 {
+ UCHAR AC;
+ UCHAR FC;
+ UCHAR DestAddress[ADDRESS_LENGTH];
+ UCHAR SrcAddress[ADDRESS_LENGTH];
+} TR_802_5;
+typedef TR_802_5 UNALIGNED *PTR_802_5;
+
+//
+// FDDI packet header description
+//
+
+typedef struct _FDDI {
+ UCHAR FC;
+ UCHAR DestAddress[ADDRESS_LENGTH];
+ UCHAR SrcAddress[ADDRESS_LENGTH];
+} FDDI;
+typedef FDDI UNALIGNED *PFDDI;
+
+//
+// STARTCHANGE
+// Arcnet packet header description
+//
+typedef struct _ARCNET {
+ UCHAR SrcAddress[ADDRESS_LENGTH_1_OCTET] ;
+ UCHAR DestAddress[ADDRESS_LENGTH_1_OCTET];
+ UCHAR ProtocolID ;
+} ARCNET;
+typedef ARCNET UNALIGNED *PARCNET;
+
+//
+// All combined media into the all encompassing header
+//
+typedef union _MEDIA_HEADER {
+ E_802_3 e;
+ TR_802_5 tr;
+ FDDI fddi;
+ ARCNET a;
+} MEDIA_HEADER ;
+typedef MEDIA_HEADER UNALIGNED *PMEDIA_HEADER;
+//
+// STOPCHANGE
+//
+
+//
+// Defines for the packet signatures of each packet, and the packet type.
+//
+
+#define STRESS_PACKET_SIGNATURE 0x81818181
+#define FUNC1_PACKET_SIGNATURE 0x72727272
+#define FUNC2_PACKET_SIGNATURE 0x63636363
+#define GO_PACKET_SIGNATURE 0x54545454
+
+#define STRESS_PACKET_TYPE 0
+#define FUNC1_PACKET_TYPE 1
+#define FUNC2_PACKET_TYPE 2
+
+//
+// Test Protocol packet header info shared amongst each of the four
+// types of packets.
+//
+
+typedef struct _PACKET_INFO {
+ ULONG Signature;
+ ULONG PacketSize; // the total size of the packet
+ UCHAR DestInstance; // instance of the packet's dest ndis binding
+ UCHAR SrcInstance; // instance of the packet's src ndis binding
+ UCHAR PacketType; // type of packet; STRESS or FUNC
+ union {
+ UCHAR PacketProtocol; // for STRESS packets the actual protocol type.
+ UCHAR PacketNumber; // ranges from 0x00 to 0xff, for tracking FUNCs.
+ } u;
+ ULONG CheckSum; // functional packet header check sum
+} PACKET_INFO;
+typedef PACKET_INFO UNALIGNED *PPACKET_INFO;
+
+//
+// Control information for STRESS test packets.
+//
+
+typedef struct _STRESS_CONTROL {
+ ULONG DataBufOffset; // offset into databuf used to generate packet data
+ ULONG SequenceNumber; // packet's sequence in order of sending
+ ULONG MaxSequenceNumber; // server window sequence number
+ UCHAR ResponseType; // how the server should respond.
+ UCHAR ClientReference; // the number of the Client sending the packet
+ UCHAR ServerReference; // the number of the Server sending the packet
+ BOOLEAN DataChecking; //
+ ULONG CheckSum; // stress packet header check sum
+} STRESS_CONTROL;
+typedef STRESS_CONTROL UNALIGNED *PSTRESS_CONTROL;
+
+//
+// FUNC1_PACKET type format
+//
+
+//
+// STARTCHANGE
+//
+typedef struct _FUNC1_PACKET {
+ MEDIA_HEADER media;
+ PACKET_INFO info;
+} FUNC1_PACKET;
+typedef FUNC1_PACKET UNALIGNED *PFUNC1_PACKET;
+//
+// STOPCHANGE
+//
+
+
+//
+// FUNC2_PACKET type format, or the RESEND packet.
+//
+
+typedef struct _FUNC2_PACKET {
+ FUNC1_PACKET hdr1;
+ FUNC1_PACKET hdr2;
+} FUNC2_PACKET;
+typedef FUNC2_PACKET UNALIGNED *PFUNC2_PACKET;
+
+//
+// STRESS_PACKET format
+//
+
+typedef struct _STRESS_PACKET {
+ FUNC1_PACKET hdr;
+ STRESS_CONTROL sc;
+} STRESS_PACKET;
+typedef STRESS_PACKET UNALIGNED *PSTRESS_PACKET;
+
+typedef struct _TP_PACKET {
+ union {
+ FUNC1_PACKET F1;
+ FUNC2_PACKET F2;
+ STRESS_PACKET S;
+ } u;
+} TP_PACKET;
+typedef TP_PACKET UNALIGNED *PTP_PACKET;
+
+//
+// GO PAUSE protocol packet header info.
+//
+
+typedef struct _GO_PACKET_INFO {
+ ULONG Signature; // GO_PACKET_SIGNATURE
+ ULONG TestSignature; // Test Signature
+ ULONG UniqueSignature; // Unique Signature for this GO PAUSE instance
+ UCHAR PacketType; // type of packet; STRESS or FUNC
+ ULONG CheckSum; // functional packet header check sum
+} GO_PACKET_INFO;
+typedef GO_PACKET_INFO UNALIGNED *PGO_PACKET_INFO;
+
+//
+// STARTCHANGE
+//
+typedef struct _GO_PACKET {
+ MEDIA_HEADER go_media;
+ GO_PACKET_INFO info;
+} GO_PACKET;
+typedef GO_PACKET UNALIGNED *PGO_PACKET;
+//
+// STOPCHANGE
+//
+
+#include <packoff.h>
+
+//
+// Transmit Pool Header.
+//
+
+typedef struct _TP_TRANSMIT_POOL {
+ NDIS_SPIN_LOCK SpinLock;
+ BOOLEAN SpinLockAllocated;
+ ULONG Allocated;
+ ULONG Deallocated;
+ PNDIS_PACKET Head;
+ PNDIS_PACKET Tail;
+} TP_TRANSMIT_POOL, * PTP_TRANSMIT_POOL;
+
+//
+// Define the Request Handle structure used to track memory handed off
+// to the MAC.
+//
+
+struct _OPEN_BLOCK;
+
+typedef struct _TP_REQUEST_HANDLE {
+ ULONG Signature;
+ struct _OPEN_BLOCK * Open;
+ BOOLEAN RequestPended;
+ PIRP Irp;
+
+ union {
+
+ struct _OPEN_REQ {
+ NTSTATUS RequestStatus;
+ KEVENT OpenEvent;
+ } OPEN_REQ;
+
+//
+// SanjeevK : Bug #2874
+//
+
+ struct _RESET_REQ {
+ NTSTATUS RequestStatus;
+ BOOLEAN PostResetStressCleanup;
+ } RESET_REQ;
+
+ struct _INFO_REQ {
+ ULONG IoControlCode;
+ NDIS_REQUEST_TYPE NdisRequestType;
+ NDIS_OID OID;
+ PVOID InformationBuffer;
+ UINT InformationBufferLength;
+ } INFO_REQ;
+
+ struct _SEND_REQ {
+ PNDIS_PACKET Packet;
+ ULONG PacketSize;
+ BOOLEAN SendPacket;
+ } SEND_REQ;
+
+ struct _PERF_REQ {
+ PNDIS_PACKET Packet;
+ ULONG PacketSize;
+ BOOLEAN SendPacket;
+ PUCHAR Buffer;
+ } PERF_REQ;
+
+ struct _TRANS_REQ {
+ PNDIS_PACKET Packet;
+ ULONG DataOffset;
+ UINT DataSize;
+ PINSTANCE_COUNTERS InstanceCounters;
+ } TRANS_REQ;
+
+ struct _STRESS_REQ {
+ struct _TP_REQUEST_HANDLE * NextReqHndl;
+ PNDIS_REQUEST Request;
+ } STRESS_REQ;
+
+ } u;
+
+} TP_REQUEST_HANDLE, *PTP_REQUEST_HANDLE;
+
+//
+// The protocol's reserved section in the NDIS_PACKET header used to
+// store information about where the packet came from, and/or what
+// stress counters to increment.
+//
+
+typedef struct _PROTOCOL_RESERVED {
+ union {
+ NDIS_HANDLE PacketHandle;
+ PTP_TRANSMIT_POOL TransmitPool;
+ PNDIS_PACKET NextPacket;
+ } Pool;
+ PTP_REQUEST_HANDLE RequestHandle;
+ PINSTANCE_COUNTERS InstanceCounters;
+ ULONG CheckSum;
+} PROTOCOL_RESERVED, * PPROTOCOL_RESERVED;
+
+
+//
+// Retrieve the PROT_RESERVED structure from a packet.
+//
+
+#define PROT_RES(Packet) ((PPROTOCOL_RESERVED)((Packet)->ProtocolReserved))
+
+//
+// Macro used to initialize the fields in the protocol reserved structure
+// of a packet that will be linked into a transmit pool.
+//
+
+// ---
+//
+// VOID
+// TpInitProtocolReserved(
+// PNDIS_PACKET Packet,
+// PINSTANCE_COUNTERS Counters
+// );
+//
+// ---
+
+#define TpInitProtocolReserved(_Packet,_Counters) { \
+ PPROTOCOL_RESERVED ProtRes; \
+ ProtRes = PROT_RES( Packet ); \
+ ProtRes->Pool.TransmitPool = NULL; \
+ ProtRes->InstanceCounters = Counters; \
+}
+
+
+//
+// A client has one of these per server registered (up to MAX_SERVERS).
+//
+// The ServerReference is as assigned by the client; for each test
+// they will be numbered sequentially in the order that they register
+// themselves (therefore, ServerNumber is just this SERVER_INFOs
+// index in Client->Servers). Address is the Ethernet that this server
+// is at, and within addresses the OpenInstance is used to distinguish
+// between servers (in the case of two servers on the same card).
+// Responses and PacketStatus track which DIR_REQ packets have
+// had RESPONSE packets sent back for them.
+//
+
+typedef struct _SERVER_INFO {
+ UCHAR ServerInstance;
+ UCHAR ClientReference;
+ UCHAR ServerReference;
+ UCHAR Address[ADDRESS_LENGTH]; // will be the same for a given ServerReference
+ BOOLEAN ServerActive;
+ UCHAR WindowReset;
+ ULONG SequenceNumber;
+ ULONG MaxSequenceNumber;
+ ULONG LastSequenceNumber;
+ ULONG PacketDelay;
+ ULONG DelayLength;
+ PINSTANCE_COUNTERS Counters;
+} SERVER_INFO, * PSERVER_INFO;
+
+//
+// The structure a client references in OpenBlock->Client.
+//
+// NumServers is how many servers are registered, the number of
+// valid entries in Servers. NumPackets is how many packets are
+// being sent in this test.
+//
+
+typedef struct _CLIENT_STORAGE {
+ UCHAR NumServers;
+ UCHAR NextServer;
+ UCHAR ActiveServers;
+ BOOLEAN PoolInitialized;
+ NDIS_HANDLE PacketHandle;
+ PTP_TRANSMIT_POOL TransmitPool;
+ ULONG PacketSize;
+ ULONG BufferSize;
+ ULONG SizeIncrease;
+ SERVER_INFO Servers[MAX_SERVERS];
+} CLIENT_STORAGE, * PCLIENT_STORAGE;
+
+//
+// A server has one of these per client registered (up to MAX_CLIENTS).
+//
+// Address is the Card Address that this client is at
+// and within addresses the OpenInstance is used to distinguish
+// between client (in the case of two clients on the same card).
+//
+
+typedef struct _CLIENT_INFO {
+ UCHAR ClientInstance;
+ UCHAR ClientReference;
+ UCHAR Address[ADDRESS_LENGTH];
+ BOOLEAN DataChecking;
+ BOOLEAN TestEnding; // TRUE denotes that an END_REQ packet has been
+ // received, and to ignore any more END_REQ packets.
+ RESPONSE_TYPE ServerResponseType;
+ ULONG LastSequenceNumber;
+ PINSTANCE_COUNTERS Counters;
+} CLIENT_INFO, * PCLIENT_INFO;
+
+//
+// The structure a server reference in OpenBlock->Server.
+//
+// Each server has a packet pool, with the actual storage
+// pointed to by PacketPool and the result of InitializePacketPool
+// in PacketHandle. BufferHandle points to the "buffer pool"
+// that we create (a linked list of MDLs).
+//
+
+#define MAX_CLIENTS 10
+
+typedef struct _SERVER_STORAGE {
+ UCHAR NumClients;
+ UCHAR ActiveClients;
+ BOOLEAN PoolInitialized;
+ UCHAR PadByte;
+ NDIS_HANDLE PacketHandle;
+ PTP_TRANSMIT_POOL TransmitPool;
+ ULONG PadLong;
+ CLIENT_INFO Clients[MAX_CLIENTS];
+} SERVER_STORAGE, * PSERVER_STORAGE;
+
+//
+//
+//
+
+typedef struct _STRESS_ARGUMENTS {
+ MEMBER_TYPE MemberType;
+ PACKET_TYPE PacketType;
+ INT PacketSize;
+ PACKET_MAKEUP PacketMakeUp;
+
+ UCHAR ResponseType;
+ INTERPACKET_DELAY DelayType;
+ ULONG DelayLength;
+ ULONG Iterations;
+
+ ULONG TotalIterations;
+ ULONG TotalPackets;
+ BOOLEAN AllPacketsSent;
+ BOOLEAN WindowEnabled;
+ BOOLEAN DataChecking;
+ BOOLEAN PacketsFromPool;
+ BOOLEAN BeginReceives;
+ BOOLEAN ServerContinue;
+} STRESS_ARGUMENTS, * PSTRESS_ARGUMENTS;
+
+//
+// PENDING is used to track NDIS routines which pend, and their
+// subsequent completions, there must be a one to one relationship
+// between the number of pends for a specific calls and the number
+// of completions.
+//
+
+// Note that size is a power of 2, so can & with x-1 to deal with wrapping
+
+#define NUM_PACKET_PENDS 2048
+
+typedef struct _PENDING {
+ ULONG PendingPackets;
+ ULONG PendingRequests;
+ ULONG PacketPendNumber;
+ ULONG PacketCompleteNumber;
+ BOOLEAN PendingSpinLockAllocated;
+ NDIS_SPIN_LOCK SpinLock;
+ PNDIS_PACKET Packets[NUM_PACKET_PENDS];
+} PENDING, * PPENDING;
+
+//
+// The Stress Block holds the flags counters, and pointers to the client
+// storage, server storage and other control structures for the STRESS command.
+//
+
+#define MAX_NUMBER_BUFFERS 2
+
+typedef struct _STRESS_BLOCK {
+ volatile BOOLEAN Stressing;
+ BOOLEAN StressStarted;
+ BOOLEAN StopStressing;
+ BOOLEAN StressFinal;
+ BOOLEAN StressEnded;
+ BOOLEAN Resetting;
+ BOOLEAN FirstIteration;
+ PCLIENT_STORAGE Client;
+ PSERVER_STORAGE Server;
+
+ LARGE_INTEGER StartTime;
+ LARGE_INTEGER EndTime;
+
+ ULONG PacketsPerSecond;
+ PSTRESS_ARGUMENTS Arguments;
+ PPENDING Pend;
+
+ //
+ // Added buffers for allowing discontigous allocations
+ //
+ PUCHAR DataBuffer[MAX_NUMBER_BUFFERS];
+ PMDL DataBufferMdl[MAX_NUMBER_BUFFERS];
+
+ BOOLEAN PoolInitialized;
+ NDIS_HANDLE PacketHandle;
+ PSTRESS_RESULTS Results;
+
+ PIRP StressIrp;
+ ULONG Counter;
+ ULONG Reg2Counter;
+ KTIMER TpStressTimer;
+ KTIMER TpStressReg2Timer;
+ KDPC TpStressDpc;
+ KDPC TpStressReg2Dpc;
+ KDPC TpStressStatsDpc;
+ KDPC TpStressEndReqDpc;
+ KDPC TpStressFinalDpc;
+} STRESS_BLOCK, * PSTRESS_BLOCK;
+
+
+typedef struct _SEND_BLOCK {
+ volatile BOOLEAN Sending;
+ BOOLEAN StopSending;
+ BOOLEAN ResendPackets;
+ UCHAR PadByte;
+ UCHAR DestAddress[ADDRESS_LENGTH];
+ UCHAR ResendAddress[ADDRESS_LENGTH];
+ ULONG PacketSize;
+ ULONG NumberOfPackets;
+ ULONG PacketsSent;
+ ULONG PacketsPending;
+ ULONG SendEndDpcCount;
+ NDIS_HANDLE PacketHandle;
+ PINSTANCE_COUNTERS Counters;
+ PIRP SendIrp;
+ KTIMER SendTimer;
+ KDPC SendDpc;
+ KDPC SendEndDpc;
+} SEND_BLOCK, * PSEND_BLOCK;
+
+#define NUMBER_OF_POOL_PACKETS 30
+
+
+typedef struct _RECEIVE_BLOCK {
+ volatile BOOLEAN Receiving;
+ BOOLEAN StopReceiving;
+ ULONG PacketsPending;
+ ULONG ReceiveEndDpcCount;
+ NDIS_HANDLE PacketHandle;
+ PINSTANCE_COUNTERS Counters;
+ PIRP ReceiveIrp;
+ KTIMER ReceiveTimer;
+ KDPC ReceiveDpc;
+ KDPC ReceiveEndDpc;
+
+ ULONG ResendType; // 0 = normal, 1 = resending self-directed packet
+ KDPC ResendDpc;
+ PTP_REQUEST_HANDLE ResendReq; // request handle for resend packet
+ KTIMER ResendTimer;
+} RECEIVE_BLOCK, * PRECEIVE_BLOCK;
+
+typedef struct _PERF_BLOCK
+{
+ ULONG PerformMode;
+ PIRP PerformIrp;
+ ULONG NumberOfPackets;
+ ULONG PacketSize;
+ UCHAR ServerAddress[ADDRESS_LENGTH];
+ UCHAR ClientAddress[ADDRESS_LENGTH];
+ ULONG PacketDelay;
+ BOOLEAN IsServer;
+ ULONG WhichReq;
+ PTP_REQUEST_HANDLE GoInitReq; // req hand for GO, NOGO, or SRVDOWN(srv) and
+ // INIT or SHUTDOWN(cliet) packet
+ PTP_REQUEST_HANDLE AckReq; // req hand for ACK, HBEAT, or SRVDONE(srv) and
+ // REQ(client) packet
+ PTP_REQUEST_HANDLE ResReq; // req hand for RETRES(srv) and REQRES(clt) packet
+ PTP_REQUEST_HANDLE DataReq; // request handle for test data packet
+ ULONG SendCount;
+ ULONG SendFailCount;
+ ULONG ReceiveCount;
+ BOOLEAN Active;
+ ULONG PacketsSent;
+ ULONG PerformEndDpcCount;
+ KDPC PerformSendDpc;
+ KTIMER PerformTimer;
+ KDPC PerformEndDpc;
+ ULONG PacketsPending;
+ NDIS_HANDLE PacketHandle;
+ LARGE_INTEGER PerfSendTotalTime;
+ BOOLEAN Testing;
+ ULONG SelfReceiveCount;
+ ULONG SendBurstCount;
+ ULONG ReceiveBurstCount;
+ ULONG RestartCount;
+ KDPC PerformRestartDpc;
+ ULONG MaskId;
+} PERF_BLOCK, * PPERF_BLOCK;
+
+
+#define TP_GO 0x0
+#define TP_GO_ACK 0x1
+
+typedef struct _PAUSE_BLOCK {
+ volatile BOOLEAN GoReceived;
+ BOOLEAN PoolAllocated;
+ NDIS_HANDLE PacketHandle;
+ UCHAR RemoteAddress[ADDRESS_LENGTH];
+ ULONG TestSignature;
+ ULONG UniqueSignature;
+ UCHAR PacketType;
+ ULONG TimeOut;
+ NDIS_SPIN_LOCK SpinLock;
+} PAUSE_BLOCK, * PPAUSE_BLOCK;
+
+
+typedef struct _EVENTS {
+ TP_EVENT_TYPE TpEventType;
+ NDIS_STATUS Status;
+ BOOLEAN Overflow;
+ PVOID EventInfo;
+} EVENTS, * PEVENTS;
+
+#define MAX_EVENT 20
+
+typedef struct _EVENT_QUEUE {
+ NDIS_SPIN_LOCK SpinLock;
+ ULONG ReceiveIndicationCount;
+ ULONG StatusIndicationCount;
+ BOOLEAN ExpectReceiveComplete;
+ BOOLEAN ExpectStatusComplete;
+ ULONG Head;
+ ULONG Tail;
+ ULONG PadUlong;
+ EVENTS Events[MAX_EVENT];
+} EVENT_QUEUE, * PEVENT_QUEUE;
+
+//
+// Open Block used to desribe each open instance of an adapter
+//
+
+typedef struct _OPEN_BLOCK {
+ NDIS_HANDLE NdisBindingHandle;
+ NDIS_HANDLE NdisProtocolHandle;
+ UCHAR OpenInstance;
+ BOOLEAN Closing;
+ UCHAR StationAddress[ADDRESS_LENGTH];
+ PSZ AdapterName;
+ NDIS_SPIN_LOCK SpinLock;
+ volatile UCHAR ReferenceCount;
+ UINT MediumIndex;
+ struct _TP_MEDIA_INFO *Media;
+ PGLOBAL_COUNTERS GlobalCounters;
+ PENVIRONMENT_VARIABLES Environment;
+ PSTRESS_BLOCK Stress;
+ PSEND_BLOCK Send;
+ PRECEIVE_BLOCK Receive;
+ volatile BOOLEAN PerformanceTest;
+ PPERF_BLOCK Perform;
+ PEVENT_QUEUE EventQueue;
+ PPAUSE_BLOCK Pause;
+ PTP_REQUEST_HANDLE OpenReqHndl;
+ PTP_REQUEST_HANDLE CloseReqHndl;
+ PTP_REQUEST_HANDLE ResetReqHndl;
+ PTP_REQUEST_HANDLE RequestReqHndl;
+ PTP_REQUEST_HANDLE StressReqHndl;
+ BOOLEAN IrpCancelled;
+ PIRP Irp;
+ ULONG Signature;
+} OPEN_BLOCK, * POPEN_BLOCK;
+
+POPEN_BLOCK TpOpen;
+
+#define OPEN_BLOCK_SIGNATURE 0x12345678
+
+//
+// Device Driver data struct definition
+//
+// Device Context - hanging off the end of the DeviceObject for the
+// driver the device context contains the control structures used
+// to administer the ndis tests.
+//
+
+typedef struct _DEVICE_CONTEXT {
+ DEVICE_OBJECT DeviceObject; // the I/O system's device object.
+ PNDIS_PROTOCOL_CHARACTERISTICS ProtChars; // protocol characteristics
+ NDIS_HANDLE NdisProtocolHandle;
+ BOOLEAN Initialized; // TRUE if TP Init succeeded; FALSE otherwise
+ BOOLEAN Opened; // TRUE if device is opened;
+ ULONG OpenSignature;
+ OPEN_BLOCK Open[NUM_OPEN_INSTANCES];
+} DEVICE_CONTEXT, * PDEVICE_CONTEXT;
+
+//
+// Unique Signatures for Test Protocol data structures.
+//
+
+#define OPEN_REQUEST_HANDLE_SIGNATURE 0x81818181
+#define FUNC_REQUEST_HANDLE_SIGNATURE 0x18181818
+#define SEND_REQUEST_HANDLE_SIGNATURE 0x45454545
+#define STRESS_REQUEST_HANDLE_SIGNATURE 0x54545454
+#define GO_REQUEST_HANDLE_SIGNATURE 0x39393939
+
+//
+// Address argument passed to NdisAllocateMemory.
+//
+
+extern NDIS_PHYSICAL_ADDRESS HighestAddress;
+
+
+
diff --git a/private/ntos/ndis/testprot/tpdrvr/tpdrvr.c b/private/ntos/ndis/testprot/tpdrvr/tpdrvr.c
new file mode 100644
index 000000000..a40b385bc
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpdrvr/tpdrvr.c
@@ -0,0 +1,1656 @@
+// -------------
+//
+// Copyright (c) 1990 Microsoft Corporation
+//
+// Module Name:
+//
+// tpdrvr.c
+//
+// Abstract:
+//
+// This module contains code which defines the Test Protocol
+// device object.
+//
+// Author:
+//
+// Tom Adams (tomad) 19-Apr-1991
+//
+// Environment:
+//
+// Kernel mode, FSD
+//
+// Revision History:
+//
+// Sanjeev Katariya Forced unload of driver thru the control panel was not working
+// Effected function : TpUnloadDriver()
+//
+// Tim Wynsma (timothyw) 4-27-94
+// Added performance tests
+// Tim Wynsma (timothyw) 6-08-94
+// Chgd perf tests to use client/server model
+//
+// --------------
+
+#include <ndis.h>
+
+#include "tpdefs.h"
+#include "media.h"
+#include "tpprocs.h"
+
+// the following function is prototyped in public\oak\inc\zwapi.h, but including that file
+// produces MANY compile errors.
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+ZwCreateSymbolicLinkObject(
+ OUT PHANDLE LinkHandle,
+ IN ACCESS_MASK DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN PUNICODE_STRING LinkTarget
+ );
+
+
+POPEN_BLOCK TpOpen = NULL;
+HANDLE SymbolicLinkHandle;
+
+//
+// The debugging longword, containing a bitmask as defined in common.h
+// If a bit is set, then debugging is turned on for that component.
+//
+
+#if DBG
+
+ULONG TpDebug = TP_DEBUG_NDIS_CALLS|TP_DEBUG_NDIS_ERROR|TP_DEBUG_STATISTICS|
+ TP_DEBUG_DATA|TP_DEBUG_DISPATCH|TP_DEBUG_IOCTL_ARGS|
+ TP_DEBUG_NT_STATUS|TP_DEBUG_DPC|TP_DEBUG_INITIALIZE|
+ TP_DEBUG_RESOURCES|TP_DEBUG_BREAKPOINT|TP_DEBUG_INFOLEVEL_1;
+
+BOOLEAN TpAssert = TRUE;
+
+#endif // DBG
+
+NDIS_PHYSICAL_ADDRESS HighestAddress = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
+
+//
+// Driver Entry function
+//
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+// ----------
+//
+// Routine Description:
+//
+// This routine performs initialization of the Test Protocol driver.
+// It creates the device objects for the driver and performs
+// other driver initialization.
+//
+// Arguments:
+//
+// DriverObject - Pointer to driver object created by the system.
+//
+// Return Value:
+//
+// The function value is the final status from the initialization operation.
+//
+// ----------
+
+{
+ STRING nameString;
+ PDEVICE_CONTEXT DeviceContext;
+ NTSTATUS Status;
+
+ //
+ // General Version Information
+ //
+ IF_TPDBG( TP_DEBUG_ALL )
+ {
+ TpPrint0("\nMAC NDIS 3.0 Tester - Test Driver Version 1.5.1\n\n");
+ }
+
+ //
+ // First initialize the DeviceContext struct,
+ //
+
+ RtlInitString( &nameString, DD_TP_DEVICE_NAME );
+
+ Status = TpCreateDeviceContext (DriverObject,
+ nameString,
+ &DeviceContext );
+
+ if (!NT_SUCCESS (Status))
+ {
+ TpPrint1 ("TPDRVR: failed to create device context: Status = %s\n",
+ TpGetStatus(Status));
+ return Status;
+ }
+ else
+ {
+ TpOpen = &DeviceContext->Open[0];
+ }
+
+ //
+ // Create symbolic link between the Dos Device name and Nt
+ // Device name for the test protocol driver.
+ //
+
+ Status = TpCreateSymbolicLinkObject( );
+
+ if (!NT_SUCCESS (Status))
+ {
+ TpPrint1 ("TPDRVR: failed to create symbolic link. Status = %s\n", TpGetStatus(Status));
+ return Status;
+ }
+
+ //
+ // then set up the EventQueue for any spurious event, indications,
+ // or completions. This should be ready at all times, from the
+ // time the test protocol is registered to the time it is unloaded.
+ //
+
+ Status = TpInitializeEventQueue( DeviceContext );
+
+ if (!NT_SUCCESS (Status)) {
+ TpPrint1 ("TPDRVR: failed to create initialize Event Queue. Status = %s\n",
+ TpGetStatus(Status));
+ return Status;
+ }
+
+ //
+ // make ourselves known to the NDIS wrapper.
+ //
+
+ Status = TpRegisterProtocol ( DeviceContext, &nameString );
+
+ if (!NT_SUCCESS(Status))
+ {
+ DeviceContext->Initialized = FALSE;
+
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint1("TPDRVR: TpRegisterProtocol failed. Status= %s\n", TpGetStatus(Status));
+ }
+ }
+ return Status;
+}
+
+
+
+NTSTATUS
+TpCreateDeviceContext(
+ IN PDRIVER_OBJECT DriverObject,
+ IN STRING DeviceName,
+ PDEVICE_CONTEXT *DeviceContext
+ )
+
+// -----------
+//
+// Routine Description:
+//
+// This routine creates and initializes a device context structure.
+//
+// Arguments:
+//
+// DriverObject - pointer to the IO subsystem supplied driver object.
+//
+// DeviceContext - Pointer to a pointer to a transport device context object.
+//
+// DeviceName - pointer to the name of the device this device object points to.
+//
+// Return Value:
+//
+// STATUS_SUCCESS if all is well; STATUS_INSUFFICIENT_RESOURCES otherwise.
+//
+// ------------
+
+{
+ NTSTATUS Status;
+ UNICODE_STRING unicodeString;
+ PDEVICE_OBJECT deviceObject;
+ PDEVICE_CONTEXT deviceContext;
+
+ //
+ // Convert the input name string to Unicode until it is actually
+ // passed as a Unicode string.
+ //
+
+ Status = RtlAnsiStringToUnicodeString( &unicodeString,
+ &DeviceName,
+ TRUE );
+ if ( !NT_SUCCESS( Status ))
+ {
+ return Status;
+ }
+
+ //
+ // Create the device object for Test Protocol.
+ //
+
+ Status = IoCreateDevice(DriverObject,
+ sizeof (DEVICE_CONTEXT) - sizeof (DEVICE_OBJECT),
+ &unicodeString,
+ FILE_DEVICE_TRANSPORT,
+ 0,
+ FALSE,
+ &deviceObject );
+
+ RtlFreeUnicodeString( &unicodeString );
+
+ if ( !NT_SUCCESS( Status ))
+ {
+ return Status;
+ }
+
+ deviceObject->Flags |= DO_DIRECT_IO;
+
+ //
+ // Initialize the driver object with this driver's entry points.
+ //
+
+ DriverObject->MajorFunction [IRP_MJ_CREATE] = TpDispatch;
+ DriverObject->MajorFunction [IRP_MJ_CLOSE] = TpDispatch;
+ DriverObject->MajorFunction [IRP_MJ_CLEANUP] = TpDispatch;
+ DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL] = TpDispatch;
+ DriverObject->DriverUnload = TpUnloadDriver;
+
+ deviceContext = (PDEVICE_CONTEXT)deviceObject;
+
+ //
+ // Now initialize the Device Context structure Signatures.
+ //
+
+ deviceContext->OpenSignature = OPEN_BLOCK_SIGNATURE;
+
+ deviceContext->Initialized = TRUE;
+
+ *DeviceContext = deviceContext;
+
+ return STATUS_SUCCESS;
+}
+
+
+
+NTSTATUS
+TpCreateSymbolicLinkObject(
+ VOID
+ )
+{
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttr;
+ STRING DosString;
+ STRING NtString;
+ UNICODE_STRING DosUnicodeString;
+ UNICODE_STRING NtUnicodeString;
+
+ RtlInitAnsiString( &DosString, "\\DosDevices\\Tpdrvr" );
+
+ Status = RtlAnsiStringToUnicodeString( &DosUnicodeString,
+ &DosString,
+ TRUE );
+ if ( !NT_SUCCESS( Status ))
+ {
+ return Status;
+ }
+
+ RtlInitAnsiString( &NtString, DD_TP_DEVICE_NAME );
+
+ Status = RtlAnsiStringToUnicodeString( &NtUnicodeString,
+ &NtString,
+ TRUE );
+ if ( !NT_SUCCESS( Status ))
+ {
+ return Status;
+ }
+
+ //
+ // Removed the OBJ_PERMANENT attribute since we should be able to load and
+ // unload this driver and create the necessary links at will. Buf Fix# 13183
+ //
+ InitializeObjectAttributes( &ObjectAttr,
+ &DosUnicodeString,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL );
+
+ Status = ZwCreateSymbolicLinkObject(&SymbolicLinkHandle,
+ SYMBOLIC_LINK_ALL_ACCESS,
+ &ObjectAttr,
+ &NtUnicodeString );
+
+ if ( Status != STATUS_SUCCESS )
+ {
+ return Status;
+ }
+
+ RtlFreeUnicodeString( &DosUnicodeString );
+ RtlFreeUnicodeString( &NtUnicodeString );
+
+ return STATUS_SUCCESS;
+}
+
+
+
+NTSTATUS
+TpInitializeEventQueue(
+ IN PDEVICE_CONTEXT DeviceContext
+ )
+{
+ NTSTATUS Status;
+ ULONG i, j;
+
+ for ( i=0;i<NUM_OPEN_INSTANCES;i++ )
+ {
+ //
+ // Finally, allocate Event Queue header struct, and its spin lock.
+ //
+
+ Status = NdisAllocateMemory((PVOID *)&DeviceContext->Open[i].EventQueue,
+ sizeof( EVENT_QUEUE ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpInitializeEventQueue: failed to allocate EVENT_QUEUE struct\n");
+ }
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( (PVOID)DeviceContext->Open[i].EventQueue,
+ sizeof( EVENT_QUEUE ) );
+ }
+
+ NdisAllocateSpinLock( &DeviceContext->Open[i].EventQueue->SpinLock );
+
+ //
+ // Initialize the Event Queue header, and each of the seperate events
+ // in the Event Queue array.
+ //
+
+ DeviceContext->Open[i].EventQueue->ReceiveIndicationCount = 0;
+ DeviceContext->Open[i].EventQueue->StatusIndicationCount = 0;
+ DeviceContext->Open[i].EventQueue->ExpectReceiveComplete = FALSE;
+ DeviceContext->Open[i].EventQueue->ExpectStatusComplete = FALSE;
+ DeviceContext->Open[i].EventQueue->Head = 0;
+ DeviceContext->Open[i].EventQueue->Tail = 0;
+
+ for ( j=0;j<MAX_EVENT;j++ )
+ {
+ DeviceContext->Open[i].EventQueue->Events[j].TpEventType = Unknown;
+ DeviceContext->Open[i].EventQueue->Events[j].Status = NDIS_STATUS_SUCCESS;
+ DeviceContext->Open[i].EventQueue->Events[j].Overflow = FALSE;
+ DeviceContext->Open[i].EventQueue->Events[j].EventInfo = NULL;
+ }
+ }
+ return STATUS_SUCCESS;
+}
+
+
+
+NTSTATUS
+TpRegisterProtocol (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN STRING *NameString
+ )
+
+// -----
+//
+// Routine Description:
+//
+// This routine introduces this transport to the NDIS interface.
+//
+// Arguments:
+//
+// DeviceObject - Pointer to the device object for this driver.
+//
+// NameString - The name of the device to be registered.
+//
+// Return Value:
+//
+// The function value is the status of the operation.
+// STATUS_SUCCESS if all goes well,
+// STATUS_UNSUCCESSFUL if we tried to register and couldn't,
+// STATUS_INSUFFICIENT_RESOURCES if we couldn't even try to register.
+//
+// -------------
+
+{
+ NDIS_STATUS Status;
+ USHORT i;
+
+ //
+ // Set up the characteristics of this protocol
+ //
+
+
+ Status = NdisAllocateMemory((PVOID *)&DeviceContext->ProtChars,
+ sizeof( NDIS_PROTOCOL_CHARACTERISTICS ) + NameString->Length,
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_INITIALIZE)
+ {
+ TpPrint0 ("TpRegisterProtocol: insufficient memory to allocate Protocol descriptor.\n");
+ }
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( DeviceContext->ProtChars,
+ sizeof( NDIS_PROTOCOL_CHARACTERISTICS ) );
+ }
+
+ //
+ // Setup the Characteristics Block and register the protocol with
+ // the NDIS Wrapper.
+ //
+
+ DeviceContext->ProtChars->MajorNdisVersion = 3;
+ DeviceContext->ProtChars->MinorNdisVersion = 0;
+ DeviceContext->ProtChars->Name.Length = NameString->Length;
+ DeviceContext->ProtChars->Name.Buffer = (PVOID)NameString->Buffer;
+
+ DeviceContext->ProtChars->OpenAdapterCompleteHandler =
+ TestProtocolOpenComplete;
+ DeviceContext->ProtChars->CloseAdapterCompleteHandler =
+ TestProtocolCloseComplete;
+ DeviceContext->ProtChars->SendCompleteHandler = TestProtocolSendComplete;
+ DeviceContext->ProtChars->TransferDataCompleteHandler =
+ TestProtocolTransferDataComplete;
+ DeviceContext->ProtChars->ResetCompleteHandler =
+ TestProtocolResetComplete;
+ DeviceContext->ProtChars->RequestCompleteHandler =
+ TestProtocolRequestComplete;
+ DeviceContext->ProtChars->ReceiveHandler = TestProtocolReceive;
+ DeviceContext->ProtChars->ReceiveCompleteHandler =
+ TestProtocolReceiveComplete;
+ DeviceContext->ProtChars->StatusHandler = TestProtocolStatus;
+ DeviceContext->ProtChars->StatusCompleteHandler =
+ TestProtocolStatusComplete;
+
+ NdisRegisterProtocol ( &Status,
+ &DeviceContext->NdisProtocolHandle,
+ DeviceContext->ProtChars,
+ (UINT)sizeof( NDIS_PROTOCOL_CHARACTERISTICS ) + NameString->Length );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_INITIALIZE)
+ {
+ TpPrint1("TpRegisterProtocol: NdisRegisterProtocol failed: %s\n",
+ TpGetStatus( Status ));
+ }
+ NdisFreeMemory( DeviceContext->ProtChars,0,0 );
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ for ( i=0;i<NUM_OPEN_INSTANCES;i++ )
+ {
+ DeviceContext->Open[i].NdisProtocolHandle = DeviceContext->NdisProtocolHandle;
+ }
+ return STATUS_SUCCESS;
+}
+
+
+
+NTSTATUS
+TpDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+// -------
+//
+// Routine Description:
+//
+// This routine is the main dispatch routine for the Test Protocol
+// driver. It accepts an I/O Request Packet, performs the request,
+// and then returns with the appropriate status.
+//
+// Arguments:
+//
+// DeviceObject - Pointer to the device object for this driver.
+//
+// Irp - Pointer to the request packet representing the I/O request.
+//
+// Return Value:
+//
+// The function value is the status of the operation.
+//
+// -------
+
+{
+ NTSTATUS Status;
+ PIO_STACK_LOCATION IrpSp;
+ PDEVICE_CONTEXT DeviceContext;
+
+ //
+ // Check to see if TP has been initialized; if not, don't allow any use.
+ //
+
+ DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
+ if ( !DeviceContext->Initialized )
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ //
+ // Make sure status information is consistent every time.
+ //
+
+ Irp->IoStatus.Status = NDIS_STATUS_PENDING;
+ Irp->IoStatus.Information = 0;
+
+ //
+ // Get a pointer to the current stack location in the IRP. This is where
+ // the function codes and parameters are stored.
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ //
+ // Case on the function that is being performed by the requestor. If the
+ // operation is a valid one for this device, then make it look like it was
+ // successfully completed, where possible.
+ //
+
+ switch ( IrpSp->MajorFunction )
+ {
+ //
+ // The Create function opens the Test Protocol driver and initializes
+ // the OpenBlock and its various data structures used to control the
+ // tests. Only one instance of TPCTL.EXE may have the driver open at
+ // any given time, all other open requests will fail with the error
+ // STATUS_DEVICE_ALREADY_ATTACHED
+ //
+ case IRP_MJ_CREATE:
+ IF_TPDBG(TP_DEBUG_DISPATCH)
+ {
+ TpPrint0("TpDispatch: IRP_MJ_CREATE.\n");
+ }
+ Status = TpOpenDriver( DeviceContext );
+ Irp->IoStatus.Status = Status;
+ break;
+
+ //
+ // The Close function closes the Test Protocol driver and deallocates
+ // the various data structures attached to the OpenBlock.
+ //
+ case IRP_MJ_CLOSE:
+ IF_TPDBG(TP_DEBUG_DISPATCH)
+ {
+ TpPrint0("TpDispatch: IRP_MJ_CLOSE.\n");
+ }
+ TpCloseDriver( DeviceContext );
+ Status = Irp->IoStatus.Status = STATUS_SUCCESS;
+ break;
+
+ //
+ // The DeviceControl function is the main path to the test protocol
+ // driver interface. Every Test Protocol request is has an Io Control
+ // code that is used by this function to determine the routine to
+ // call.
+ //
+ case IRP_MJ_DEVICE_CONTROL:
+ IF_TPDBG(TP_DEBUG_DISPATCH)
+ {
+ TpPrint0("TpDispatch: IRP_MJ_DEVICE_CONTROL.\n");
+ }
+ Status = TpIssueRequest( DeviceContext,Irp,IrpSp );
+ break;
+
+ //
+ // Handle the two stage IRP for a file close operation. When the first
+ // stage hits,
+ //
+ case IRP_MJ_CLEANUP:
+ IF_TPDBG( TP_DEBUG_DISPATCH )
+ {
+ TpPrint0("TpDispatch: IRP_MJ_CLEANUP.\n");
+ }
+ Status = TpCleanUpDriver( DeviceContext,Irp );
+ Irp->IoStatus.Status = Status;
+ break;
+
+ default:
+ IF_TPDBG( TP_DEBUG_DISPATCH )
+ {
+ TpPrint0("TpDispatch: OTHER (DEFAULT).\n");
+ }
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+
+ } // major function switch
+
+ //
+ // If the request did not pend, the complete it now, otherwise it
+ // will be completed when the pending routine finishes.
+ //
+
+ if ( Status == STATUS_PENDING )
+ {
+ IF_TPDBG( TP_DEBUG_DISPATCH )
+ {
+ TpPrint0("TpDispatch: request PENDING in handler.\n");
+ }
+ }
+ else if ( Status == STATUS_CANCELLED )
+ {
+ IF_TPDBG( TP_DEBUG_DISPATCH )
+ {
+ TpPrint0("TpDispatch: request CANCELLED by handler.\n");
+ }
+ }
+ else
+ {
+ IF_TPDBG(TP_DEBUG_DISPATCH)
+ {
+ TpPrint0("TpDispatch: request COMPLETED by handler.\n");
+ }
+ IoAcquireCancelSpinLock( &Irp->CancelIrql );
+ IoSetCancelRoutine( Irp,NULL );
+ IoReleaseCancelSpinLock( Irp->CancelIrql );
+
+ IoCompleteRequest( Irp,IO_NETWORK_INCREMENT );
+ }
+
+ //
+ // Return the immediate status code to the caller.
+ //
+
+ return Status;
+}
+
+
+
+NTSTATUS
+TpOpenDriver(
+ IN PDEVICE_CONTEXT DeviceContext
+ )
+
+{
+ NTSTATUS Status;
+ USHORT i;
+
+ //
+ // If the Device did not successfully initialize at boot time than
+ // fail this open.
+ //
+
+ if( DeviceContext->Initialized != TRUE )
+ {
+ return STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ //
+ // if the device has already been opened by an instance of TPCTL.EXE
+ // then fail this open.
+ //
+
+ if ( DeviceContext->Opened == TRUE )
+ {
+ return STATUS_DEVICE_ALREADY_ATTACHED;
+ }
+
+ for ( i=0;i<NUM_OPEN_INSTANCES;i++ )
+ {
+ //
+ // Allocate each of the instances of the OpenBlock.
+ //
+
+ Status = TpAllocateOpenArray( &DeviceContext->Open[i] );
+
+ if ( Status != STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint1("TpCreateDeviceContext: failed to allocate Open Array. Status = %s\n",
+ TpGetStatus(Status));
+ }
+
+ //
+ // If one of the allocation calls fails deallocate any of
+ // the structs that were just successfully allocated.
+ //
+
+ while ( i >= 0 )
+ {
+ TpDeallocateOpenArray( &DeviceContext->Open[i--] );
+ }
+ return Status;
+ }
+ }
+ DeviceContext->Opened = TRUE;
+
+ return STATUS_SUCCESS;
+}
+
+
+
+NTSTATUS
+TpCleanUpDriver(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PIRP Irp
+ )
+
+// ----
+//
+// Routine Description:
+//
+//
+// Arguments:
+//
+//
+// Return Value:
+//
+// ----
+
+{
+ NDIS_STATUS Status;
+ USHORT i;
+
+ //
+ // Make this Irp Cancellable
+ //
+
+ NdisAcquireSpinLock( &DeviceContext->Open[0].SpinLock );
+
+ DeviceContext->Open[0].Irp = Irp;
+ DeviceContext->Open[0].IrpCancelled = FALSE;
+
+ IoAcquireCancelSpinLock( &Irp->CancelIrql );
+
+ if ( Irp->Cancel )
+ {
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+ return STATUS_CANCELLED;
+ }
+
+ IoSetCancelRoutine( Irp,(PDRIVER_CANCEL)TpCancelIrp );
+
+ IoReleaseCancelSpinLock( Irp->CancelIrql );
+
+ NdisReleaseSpinLock( &DeviceContext->Open[0].SpinLock );
+
+ for ( i=0;i<NUM_OPEN_INSTANCES;i++ )
+ {
+ if ( DeviceContext->Open[i].OpenInstance != (UCHAR)-1 )
+ {
+ //
+ // Set the open instance's closing flag to true, then signal
+ // all the async test protocol routines to end.
+ //
+
+ DeviceContext->Open[i].Closing = TRUE;
+
+ if ( DeviceContext->Open[i].Stress->Stressing == TRUE )
+ {
+ DeviceContext->Open[i].Stress->StopStressing = TRUE;
+ }
+
+ if ( DeviceContext->Open[i].Send->Sending == TRUE )
+ {
+ DeviceContext->Open[i].Send->StopSending = TRUE;
+ }
+
+ if ( DeviceContext->Open[i].Receive->Receiving == TRUE )
+ {
+ DeviceContext->Open[i].Receive->StopReceiving = TRUE;
+ }
+
+ if ( DeviceContext->Open[i].PerformanceTest == TRUE)
+ {
+ DeviceContext->Open[i].Perform->Active = FALSE;
+ }
+
+ //
+ // Wait for all of the four asynchronous routines STRESS,
+ // SEND, PERFORMANCE, and RECEIVE to finish, then close the adapter.
+ //
+
+ while (( DeviceContext->Open[i].ReferenceCount > 0 ) &&
+ ( DeviceContext->Open[0].IrpCancelled != TRUE ))
+ {
+ /* NULL */ ;
+ }
+
+ //
+ // Now close each of the existing OpenInstances.
+ //
+
+ NdisCloseAdapter( &Status,
+ DeviceContext->Open[i].NdisBindingHandle );
+
+ if (( Status != NDIS_STATUS_SUCCESS ) &&
+ ( Status != NDIS_STATUS_PENDING ))
+ {
+ IF_TPDBG ( TP_DEBUG_NDIS_ERROR )
+ {
+ TpPrint2(
+ "TpCleanUpDriver: failed to close adapter for instance #%d. Status = %s\n",
+ i, TpGetStatus(Status));
+ }
+ }
+ else
+ {
+ // XXX: handle the close pending.
+
+ DeviceContext->Open[i].NdisBindingHandle = NULL;
+ DeviceContext->Open[i].OpenInstance = (UCHAR)-1;
+ DeviceContext->Open[i].Closing = FALSE;
+
+ NdisFreeMemory( DeviceContext->Open[i].AdapterName,0,0 );
+ DeviceContext->Open[i].AdapterName = NULL;
+
+ //
+ // We will also free the media block at this point because
+ // the info it contains may not hold for the next adapter
+ // open on this instance.
+ //
+
+ NdisFreeMemory( DeviceContext->Open[i].Media,0,0 );
+ DeviceContext->Open[i].Media = NULL;
+ }
+ }
+ }
+
+ //
+ // If this Irp has been cancelled return now, otherwise make it
+ // non cancellable.
+ //
+
+ NdisAcquireSpinLock( &DeviceContext->Open[0].SpinLock );
+
+ if ( DeviceContext->Open[0].IrpCancelled == TRUE )
+ {
+ return STATUS_CANCELLED;
+ }
+ else
+ {
+ IoAcquireCancelSpinLock( &Irp->CancelIrql );
+ IoSetCancelRoutine( Irp,NULL );
+ IoReleaseCancelSpinLock( Irp->CancelIrql );
+ }
+
+ NdisReleaseSpinLock( &DeviceContext->Open[0].SpinLock );
+
+ //
+ // Deallocate each of the instances of the OpenBlock.
+ //
+
+ for ( i=0;i<NUM_OPEN_INSTANCES;i++ )
+ {
+ TpDeallocateOpenArray( &DeviceContext->Open[i] );
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+
+VOID
+TpCloseDriver(
+ IN PDEVICE_CONTEXT DeviceContext
+ )
+
+// ----
+//
+// Routine Description:
+//
+//
+// Arguments:
+//
+//
+// Return Value:
+//
+// ----
+
+{
+ DeviceContext->Opened = FALSE;
+}
+
+
+
+VOID
+TpUnloadDriver(
+ IN PDRIVER_OBJECT DriverObject
+ )
+{
+ USHORT i;
+ PDEVICE_CONTEXT DeviceContext = (PDEVICE_CONTEXT)DriverObject->DeviceObject;
+
+ TpPrint0("TpUnloadDriver called.\n");
+
+ //
+ // Fixed error for deallocation of memory contigent to having been opened
+ // Bug# 13183
+ //
+ if ( DeviceContext->Opened == TRUE )
+ {
+ //
+ // for each of the open instances in the open array.
+ //
+ for ( i=0;i<NUM_OPEN_INSTANCES;i++ )
+ {
+ //
+ // Deallocate each of the instances of the OpenBlock.
+ //
+ TpDeallocateOpenArray( &DeviceContext->Open[i] );
+ }
+ }
+
+ //
+ // Close the Dos Symbolic link to remove traces of the device
+ //
+ ZwClose( SymbolicLinkHandle );
+
+ //
+ // Then delete the device object from the system. Fixed for Bug#: 13183
+ //
+ IoDeleteDevice( (PDEVICE_OBJECT)DeviceContext );
+
+ TpPrint0("TpUnloadDriver completed.\n");
+}
+
+
+
+BOOLEAN
+TpAddReference(
+ IN POPEN_BLOCK OpenP
+ )
+
+// ---
+//
+// Routine Description:
+//
+// Add a reference to an open block, to prevent it being removed
+// by TpCloseDriver.
+//
+// Arguments:
+//
+// OpenP - The open block holding the adapter information to add the
+// reference to.
+//
+// Return Value:
+//
+// TRUE if the reference is added.
+// FALSE if the open is already closing.
+//
+// ----
+
+{
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ if ( OpenP->Closing )
+ {
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ return FALSE;
+ }
+ ++OpenP->ReferenceCount;
+
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ return TRUE;
+}
+
+
+
+VOID
+TpRemoveReference(
+ IN POPEN_BLOCK OpenP
+ )
+
+// --
+//
+// Routine Description:
+//
+// Remove a reference to an adapter. If the count goes to
+// zero, then the adapter may be closed if requested.
+//
+// Arguments:
+//
+// Argument - The open block holding the adapter information to
+// remove the reference from.
+//
+// Return Value:
+//
+// None.
+//
+// --
+
+{
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ --OpenP->ReferenceCount;
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+}
+
+
+
+NTSTATUS
+TpAllocateOpenArray(
+ POPEN_BLOCK OpenP
+ )
+
+// -----
+//
+// Routine Description:
+//
+// This routine allocates the various data structures and spinlocks
+// in the OpenBlock.
+//
+// Arguments:
+//
+// OpenP - a pointer to the OpenBlock containing the data structures which
+// will be allocated during this routine.
+//
+// Return Value:
+//
+// NTSTATUS - STATUS_SUCCESS if all the memory and spinlocks are allocated
+// else STATUS_INSUFFICIENT_RESOURCES if an allocation of memory
+// fails.
+//
+// ----------
+
+{
+ NDIS_STATUS Status;
+ ULONG i;
+
+ //
+ // Initialize the Open Block fields,
+ //
+
+ OpenP->NdisBindingHandle = NULL;
+ OpenP->OpenInstance = (UCHAR)-1;
+ OpenP->Closing = FALSE;
+ OpenP->AdapterName = NULL;
+ OpenP->ReferenceCount = 0;
+ OpenP->MediumIndex = 0xFFFFFFFF;
+
+ OpenP->Media = NULL;
+ OpenP->GlobalCounters = NULL;
+ OpenP->Environment = NULL;
+
+ OpenP->Stress = NULL;
+ OpenP->Send = NULL;
+ OpenP->Receive = NULL;
+
+ OpenP->OpenReqHndl = NULL;
+ OpenP->CloseReqHndl = NULL;
+ OpenP->ResetReqHndl = NULL;
+ OpenP->RequestReqHndl = NULL;
+ OpenP->StressReqHndl = NULL;
+
+ OpenP->IrpCancelled = FALSE;
+ OpenP->Irp = NULL;
+
+ OpenP->Signature = OPEN_BLOCK_SIGNATURE;
+ OpenP->PerformanceTest = FALSE;
+
+
+ //
+ // and set the station address for this open instance to nulls.
+ //
+
+ for ( i=0;i<ADDRESS_LENGTH;i++ )
+ {
+ OpenP->StationAddress[i] = 0x00;
+ }
+
+ //
+ // Allocate the Environment struct
+ //
+
+ Status = NdisAllocateMemory((PVOID *)&OpenP->Environment,
+ sizeof( ENVIRONMENT_VARIABLES ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpAllocateOpenArray: failed to allocate Environment struct\n");
+ }
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( OpenP->Environment,sizeof( ENVIRONMENT_VARIABLES ));
+ }
+
+ //
+ // Then initialize the Environment Variables to the default settings.
+ //
+
+ OpenP->Environment->WindowSize = WINDOW_SIZE;
+ OpenP->Environment->RandomBufferNumber = BUFFER_NUMBER;
+ OpenP->Environment->StressDelayInterval = DELAY_INTERVAL;
+ OpenP->Environment->UpForAirDelay = UP_FOR_AIR_DELAY;
+ OpenP->Environment->StandardDelay = STANDARD_DELAY;
+
+ //
+ // Allocate the Stress struct and the pend counters and stress results
+ // counters attached to it.
+ //
+
+ Status = NdisAllocateMemory((PVOID *)&OpenP->Stress,
+ sizeof( STRESS_BLOCK ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpAllocateOpenArray: failed to allocate STRESS_BLOCK struct\n");
+ }
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( OpenP->Stress,sizeof( STRESS_BLOCK ));
+ }
+
+ //
+ // Initialize the Stress Block and set the request pending counters
+ // and the stress results structs to null.
+ //
+
+ OpenP->Stress->Stressing = FALSE;
+ OpenP->Stress->StressStarted = FALSE;
+ OpenP->Stress->StopStressing = TRUE;
+ OpenP->Stress->StressFinal = FALSE;
+ OpenP->Stress->StressEnded = TRUE;
+ OpenP->Stress->Client = NULL;
+ OpenP->Stress->Server = NULL;
+ OpenP->Stress->Arguments = NULL;
+ OpenP->Stress->DataBuffer[0] = NULL;
+ OpenP->Stress->DataBuffer[1] = NULL;
+ OpenP->Stress->DataBufferMdl[0] = NULL;
+ OpenP->Stress->DataBufferMdl[1] = NULL;
+ OpenP->Stress->PoolInitialized = FALSE;
+ OpenP->Stress->PacketHandle = NULL;
+ OpenP->Stress->StressIrp = NULL;
+
+ //
+ // allocate the pend counter, we need to create this here because
+ // it will be used in starting all instances of the stress test.
+ //
+
+ Status = NdisAllocateMemory((PVOID *)&OpenP->Stress->Pend,
+ sizeof( PENDING ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpAllocateOpenArray: failed to allocate PEND_COUNTER struct\n");
+ }
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( OpenP->Stress->Pend,sizeof( PENDING ));
+ }
+
+ NdisAllocateSpinLock( &OpenP->Stress->Pend->SpinLock );
+
+ TpInitializePending( OpenP->Stress->Pend );
+
+ Status = NdisAllocateMemory((PVOID *)&OpenP->Stress->Results,
+ sizeof( STRESS_RESULTS ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpAllocateOpenArray: failed to allocate Stress Results struct\n");
+ }
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( OpenP->Stress->Results,sizeof( STRESS_RESULTS ));
+ TpInitializeStressResults( OpenP->Stress->Results );
+ }
+
+ //
+ // Initialize the timer to regulate when to call each of the routines.
+ //
+
+ KeInitializeTimer( &OpenP->Stress->TpStressTimer );
+ KeInitializeTimer( &OpenP->Stress->TpStressReg2Timer );
+
+ //
+ // Now allocate the Send and Receive structs.
+ //
+
+ Status = NdisAllocateMemory((PVOID *)&OpenP->Send,
+ sizeof( SEND_BLOCK ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpAllocateOpenArray: failed to allocate SEND_BLOCK struct\n");
+ }
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( OpenP->Send,sizeof( SEND_BLOCK ));
+ }
+
+ //
+ // Initialize the Send Block fields and set the SEND destination
+ // address and resend address to nulls.
+ //
+
+ OpenP->Send->Sending = FALSE;
+ OpenP->Send->StopSending = TRUE;
+ OpenP->Send->ResendPackets = FALSE;
+ OpenP->Send->PacketSize = 0;
+ OpenP->Send->NumberOfPackets = 0;
+ OpenP->Send->PacketsSent = 0;
+ OpenP->Send->PacketsPending = 0;
+ OpenP->Send->PacketHandle = NULL;
+ OpenP->Send->Counters = NULL;
+ OpenP->Send->SendIrp = NULL;
+
+ KeInitializeTimer( &OpenP->Send->SendTimer );
+
+ for ( i=0;i<ADDRESS_LENGTH;i++ )
+ {
+ OpenP->Send->DestAddress[i] = 0x00;
+ OpenP->Send->ResendAddress[i] = 0x00;
+ }
+
+ //
+ // Allocate the Send PacketPool.
+ //
+
+ NdisAllocatePacketPool( &Status,
+ &OpenP->Send->PacketHandle,
+ NUMBER_OF_POOL_PACKETS,
+ sizeof( PROTOCOL_RESERVED ) );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpAllocateOpenArray: could not allocate Packet Pool\n");
+ }
+ return Status;
+ }
+
+ //
+ // Now allocate the SEND Counters and initialize them to zero.
+ //
+
+ Status = NdisAllocateMemory((PVOID *)&OpenP->Send->Counters,
+ sizeof( INSTANCE_COUNTERS ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpAllocateOpenArray: failed to allocate counters.\n");
+ }
+ return NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( (PVOID)OpenP->Send->Counters,
+ sizeof( INSTANCE_COUNTERS ) );
+ }
+
+ //
+ // Initialize the DPC used to call SendDpc, and SendEndDpc.
+ //
+
+ KeInitializeDpc(&OpenP->Send->SendDpc,
+ TpFuncSendDpc,
+ (PVOID)OpenP );
+
+ KeInitializeDpc(&OpenP->Send->SendEndDpc,
+ TpFuncSendEndDpc,
+ (PVOID)OpenP );
+
+ Status = NdisAllocateMemory((PVOID *)&OpenP->Receive,
+ sizeof( RECEIVE_BLOCK ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpAllocateOpenArray: failed to allocate RECEIVE_BLOCK struct\n");
+ }
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory((PVOID)OpenP->Receive,sizeof( RECEIVE_BLOCK ));
+ }
+
+ //
+ // Initialize the Receive Block fields.
+ //
+
+ OpenP->Receive->Receiving = FALSE;
+ OpenP->Receive->StopReceiving = TRUE;
+ OpenP->Receive->PacketsPending = 0;
+ OpenP->Receive->PacketHandle = NULL;
+ OpenP->Receive->Counters = NULL;
+ OpenP->Receive->ReceiveIrp = NULL;
+
+ KeInitializeTimer( &OpenP->Receive->ReceiveTimer );
+ KeInitializeTimer( &OpenP->Receive->ResendTimer);
+
+ //
+ // Create a PacketPool, and initialize it, we will need this in case
+ // we receive any RESEND packets (FUNC2_PACKET).
+ //
+
+ NdisAllocatePacketPool( &Status,
+ &OpenP->Receive->PacketHandle,
+ NUMBER_OF_POOL_PACKETS,
+ sizeof( PROTOCOL_RESERVED ) );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint1("TpAllocateOpenArray: could not allocate Packet Pool: return %s.\n",
+ TpGetStatus(Status));
+ }
+ return Status;
+ }
+
+ //
+ // Now allocate the COUNTERS structure and set the counters to zero.
+ //
+
+ Status = NdisAllocateMemory((PVOID *)&OpenP->Receive->Counters,
+ sizeof( INSTANCE_COUNTERS ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_RESOURCES )
+ {
+ TpPrint0("TpAllocateOpenArray: failed to allocate counters.\n");
+ }
+ return NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( (PVOID)OpenP->Receive->Counters,
+ sizeof( INSTANCE_COUNTERS ) );
+ }
+
+ //
+ // Initialize the DPCs used to call ReceiveDpc and ReceiveEndDpc.
+ //
+
+ KeInitializeDpc(&OpenP->Receive->ReceiveDpc,
+ TpFuncReceiveDpc,
+ (PVOID)OpenP );
+
+ KeInitializeDpc(&OpenP->Receive->ReceiveEndDpc,
+ TpFuncReceiveEndDpc,
+ (PVOID)OpenP );
+
+ KeInitializeDpc(&OpenP->Receive->ResendDpc,
+ TpFuncResendDpc,
+ (PVOID)OpenP );
+
+ //
+ // the performance structure is not allocated here, but is allocated and freed
+ // within the performance functions themselves
+ //
+
+// OpenP->Perform = NULL;
+
+ //
+ // now deal with the PAUSE Block
+ //
+
+ Status = NdisAllocateMemory((PVOID *)&OpenP->Pause,
+ sizeof( PAUSE_BLOCK ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpAllocateOpenArray: failed to allocate PAUSE_BLOCK struct.\n");
+ }
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( (PVOID)OpenP->Pause,
+ sizeof( PAUSE_BLOCK ) );
+ }
+
+ //
+ // Initialize the Pause Block fields.
+ //
+
+ OpenP->Pause->GoReceived = FALSE;
+
+ for ( i=0;i<ADDRESS_LENGTH;i++ )
+ {
+ OpenP->Pause->RemoteAddress[i] = 0x00;
+ }
+
+ OpenP->Pause->TestSignature = 0xFFFFFFFF;
+ OpenP->Pause->PacketType = (UCHAR)-1;
+ OpenP->Pause->UniqueSignature = 0xFFFFFFFF;
+ OpenP->Pause->TimeOut = 0;
+
+ NdisAllocateSpinLock( &OpenP->Pause->SpinLock );
+ OpenP->Pause->PoolAllocated = FALSE;
+
+ //
+ // and Allocate the PacketPool.
+ //
+
+ NdisAllocatePacketPool( &Status,
+ &OpenP->Pause->PacketHandle,
+ 10,
+ sizeof( PROTOCOL_RESERVED ) );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpAllocateOpenArray: could not allocate Packet Pool.\n");
+ }
+ return Status;
+ }
+ else
+ {
+ OpenP->Pause->PoolAllocated = TRUE;
+ }
+
+ //
+ // Then allocate the Open Blocks open spin lock.
+ //
+
+ NdisAllocateSpinLock( &OpenP->SpinLock );
+
+ return STATUS_SUCCESS;
+}
+
+
+
+VOID
+TpDeallocateOpenArray(
+ POPEN_BLOCK OpenP
+ )
+
+// -------
+//
+// Routine Description:
+//
+// This routine deallocates the various data structures and spinlocks
+// in the OpenBlock that are used to control the tests.
+//
+// Arguments:
+//
+// OpenP - a pointer to the OpenBlock containing the data structures which
+// will be deallocated during this routine.
+//
+// Return Value:
+//
+// None.
+//
+// -------
+
+{
+ NdisFreeSpinLock( &OpenP->SpinLock );
+
+ if ( OpenP->AdapterName != NULL )
+ {
+ NdisFreeMemory( OpenP->AdapterName,0,0 );
+ }
+
+ if ( OpenP->Environment != NULL )
+ {
+ NdisFreeMemory( OpenP->Environment,0,0 );
+ }
+
+ if ( OpenP->Stress->Pend != NULL )
+ {
+ NdisFreeMemory( OpenP->Stress->Pend,0,0 );
+ NdisFreeSpinLock( &OpenP->Stress->Pend->SpinLock );
+ }
+
+ if ( OpenP->Stress->Results != NULL )
+ {
+ NdisFreeMemory( OpenP->Stress->Results,0,0 );
+ }
+
+ if ( OpenP->Send != NULL )
+ {
+ NdisFreePacketPool( OpenP->Send->PacketHandle );
+ NdisFreeMemory( (PVOID)OpenP->Send->Counters,0,0 );
+ NdisFreeMemory( OpenP->Send,0,0 );
+ }
+
+ if ( OpenP->Receive != NULL )
+ {
+ NdisFreePacketPool( OpenP->Receive->PacketHandle );
+ NdisFreeMemory( (PVOID)OpenP->Receive->Counters,0,0 );
+ NdisFreeMemory( OpenP->Receive,0,0 );
+ }
+
+ if ( OpenP->Pause != NULL )
+ {
+ if ( OpenP->Pause->PoolAllocated == TRUE )
+ {
+ NdisFreePacketPool( OpenP->Pause->PacketHandle );
+ }
+ NdisFreeSpinLock( &OpenP->Pause->SpinLock );
+ NdisFreeMemory( OpenP->Pause,0,0 );
+ }
+}
+
+
+
+VOID
+TpCancelIrp(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PIRP Irp
+ )
+
+// ----------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// DeviceObject - Pointer to device object for this driver.
+//
+// Irp - Pointer to the request packet representing the I/O request
+// to cancel.
+//
+// Return Value:
+//
+// None.
+//
+// ----------
+
+{
+ POPEN_BLOCK OpenP;
+ PIO_STACK_LOCATION IrpSp;
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ OpenP = (POPEN_BLOCK)Irp->IoStatus.Information;
+
+ IoSetCancelRoutine( Irp,NULL );
+
+ IoReleaseCancelSpinLock( Irp->CancelIrql );
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ if ((( Irp == OpenP->Stress->StressIrp ) ||
+ ( Irp == OpenP->Send->SendIrp )) ||
+ ( Irp == OpenP->Receive->ReceiveIrp ) ||
+ ( OpenP->PerformanceTest && (Irp == OpenP->Perform->PerformIrp)))
+ {
+ //
+ // These Irps will handle the cancel and clean up themselves
+ // so just return
+ //
+
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ return;
+ }
+ else if ( Irp == OpenP->Irp )
+ {
+ //
+ // We have found one of the General Case Irp to be cancelled.
+ // first set the flag that this Irp has been cancelled, them
+ // complete it.
+ //
+
+ OpenP->IrpCancelled = TRUE;
+ OpenP->Irp = NULL;
+
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
+ }
+ else
+ {
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ }
+}
+
+
+
diff --git a/private/ntos/ndis/testprot/tpdrvr/tpfunc.c b/private/ntos/ndis/testprot/tpdrvr/tpfunc.c
new file mode 100644
index 000000000..d94998c87
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpdrvr/tpfunc.c
@@ -0,0 +1,4639 @@
+// ------------------------
+//
+// Copyright (c) 1990 Microsoft Corporation
+//
+// Module Name:
+//
+// tpfunc.c
+//
+// Abstract:
+//
+//
+// Author:
+//
+// Tom Adams (tomad) 9-Jul-1991
+//
+// Environment:
+//
+// Kernel mode, FSD
+//
+// Revision History:
+//
+// Sanjeev Katariya (sanjeevk)
+//
+// 4-6-1993 Bug #5203: Changed the routine TpFuncOpenAdapter() to fill in the information
+// of the media type for use by the TPCTL. This was done in order
+// for TPCTL to make a decision on the OID to use when submitting
+// requests to add/change mulicast addresses.
+//
+// 4-9-1993 Bug #5886: Changed TpFuncSendComplete() to zero out the private section of the
+// NDIS_PACKET. Should the MAC access this section now after having made
+// a call and to NdisSendComplete(), it will be forced to deal with
+// or incorrect data
+//
+// 4-12-1993 Added ARCNET support
+//
+// Tim Wynsma (timothyw)
+// 4-27-94 Added performance tests
+// 5-18-94 Got rid of warnings; added some debug
+// 6-08-94 Chgd perf test to client/server
+//
+// -----------------------------
+
+
+#include <ndis.h>
+
+#include "tpdefs.h"
+#include "media.h"
+#include "tpprocs.h"
+#include "string.h"
+
+
+VOID
+TpFuncResend(POPEN_BLOCK OpenP,
+ PTP_REQUEST_HANDLE SendReqHndl);
+
+
+
+NDIS_STATUS
+TpFuncOpenAdapter(
+ IN POPEN_BLOCK OpenP,
+ IN UCHAR OpenInstance,
+ IN PCMD_ARGS CmdArgs
+ )
+
+// ------------
+//
+// Routine Description:
+//
+// This routine opens the request NDIS adapter and sets up the OpenBlock
+// accordingly. If the call to NdisOpenAdapter does not pend, then a call
+// will be made to TpFuncRequestComplete to complete the request and
+// signal the application that it has finished, otherwise this call will
+// be made the MAC itself once the request has finished.
+//
+// Arguments:
+//
+//
+// Return Value:
+//
+// NDIS_STATUS - This routine always returns NDIS_STATUS_PENDING as it
+// will either really pend and be completed later, or we
+// will fake a completion request that will complete it
+// at that time.
+//
+// ------------------
+
+
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ NDIS_STATUS DriverStatus = NDIS_STATUS_SUCCESS;
+ NDIS_STATUS RequestStatus = NDIS_STATUS_SUCCESS;
+ STRING AdapterString;
+ NDIS_STRING NdisAdapterString;
+ NDIS_STATUS OpenErrorStatus;
+ UINT NameLength;
+ PNDIS_REQUEST Request = NULL;
+ PUCHAR InformationBuffer = NULL;
+ ULONG OidIndex;
+ PUCHAR p, q;
+ ULONG i;
+ PREQUEST_RESULTS OutputBuffer;
+ BOOLEAN GotCardAddress = FALSE;
+ ULONG MediaArraySize;
+
+
+ //
+ // Determine determine whether this instance of the Adapter is already
+ // opened.
+ //
+
+ if ( OpenP->OpenInstance != (UCHAR)-1 )
+ {
+ //
+ // If it has, then we will fail this request, and continue. We will
+ // not create a new Open Instance overwriting an existing one.
+ //
+
+ IF_TPDBG ( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1("TpFuncOpenAdapter: An open already exists for this Open Instance %d\n",
+ OpenInstance);
+ }
+ Status = NDIS_STATUS_OPEN_FAILED;
+ }
+ else
+ {
+ //
+ // First allocate the request handle and set it up as if the request
+ // pended. If it does not pend we will reset the flags later; before
+ // calling the completion routine.
+ //
+
+ TP_ASSERT ( OpenP->OpenReqHndl == NULL );
+
+ Status = NdisAllocateMemory((PVOID *)&OpenP->OpenReqHndl,
+ sizeof( TP_REQUEST_HANDLE ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpFuncOpenAdapter: unable to allocate Request Handle.\n");
+ }
+ Status = NDIS_STATUS_RESOURCES;
+ goto cleanup;
+ }
+ else
+ {
+ NdisZeroMemory( OpenP->OpenReqHndl,sizeof( TP_REQUEST_HANDLE ));
+ }
+
+ OpenP->OpenReqHndl->Signature = OPEN_REQUEST_HANDLE_SIGNATURE;
+ OpenP->OpenReqHndl->Open = OpenP;
+ OpenP->OpenReqHndl->RequestPended = FALSE;
+
+ KeInitializeEvent( &OpenP->OpenReqHndl->u.OPEN_REQ.OpenEvent,
+ SynchronizationEvent,
+ FALSE );
+ //
+ // Otherwise initialize the adapter string for the call ...
+ //
+
+ TP_ASSERT( OpenP->AdapterName == NULL );
+
+ NameLength = strlen( CmdArgs->ARGS.OPEN_ADAPTER.AdapterName ) + 1;
+
+ Status = NdisAllocateMemory((PVOID *)&OpenP->AdapterName,
+ 8 + NameLength,
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpFuncOpenAdapter: failed to allocate adapter name buffer.\n");
+ }
+ Status = NDIS_STATUS_RESOURCES;
+ goto cleanup;
+ }
+ else
+ {
+ NdisZeroMemory( OpenP->AdapterName,8 + NameLength );
+ }
+
+ NdisMoveMemory( OpenP->AdapterName,"\\Device\\",8 );
+
+ NdisMoveMemory( OpenP->AdapterName + 8,
+ CmdArgs->ARGS.OPEN_ADAPTER.AdapterName,
+ NameLength );
+
+ RtlInitString( &AdapterString,(PSZ)OpenP->AdapterName );
+
+ Status = RtlAnsiStringToUnicodeString( (PUNICODE_STRING)&NdisAdapterString,
+ (PANSI_STRING)&AdapterString,
+ TRUE );
+
+ TP_ASSERT( NT_SUCCESS( Status ));
+
+ //
+ // And make the actual NdisOpenAdapter Call.
+ //
+
+ if (CmdArgs->ARGS.OPEN_ADAPTER.NoArcNet) // force encapsulated ethernet
+ {
+ MediaArraySize = NDIS_MEDIUM_ARRAY_SIZE - 1;
+ }
+ else
+ {
+ MediaArraySize = NDIS_MEDIUM_ARRAY_SIZE;
+ }
+
+
+ NdisOpenAdapter(&DriverStatus,
+ &OpenErrorStatus,
+ &OpenP->NdisBindingHandle,
+ &OpenP->MediumIndex,
+ NdisMediumArray,
+ MediaArraySize,
+ OpenP->NdisProtocolHandle,
+ (NDIS_HANDLE)OpenP,
+ &NdisAdapterString,
+ 0,
+ NULL );
+
+ RtlFreeUnicodeString( &NdisAdapterString );
+
+ if ( DriverStatus == NDIS_STATUS_PENDING )
+ {
+ Status = KeWaitForSingleObject( &OpenP->OpenReqHndl->u.OPEN_REQ.OpenEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL );
+
+ if ( Status != STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_NT_STATUS )
+ {
+ TpPrint1("TpFuncOpenAdapter: KeWaitForSingleObject returned %s\n",
+ TpGetStatus(Status) );
+ }
+ goto cleanup;
+ }
+
+ DriverStatus = OpenP->OpenReqHndl->u.OPEN_REQ.RequestStatus;
+
+ if ( DriverStatus != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1("TpFuncOpenAdapter: NdisOpenAdapter returned %s\n",
+ TpGetStatus( DriverStatus ));
+ }
+ goto cleanup;
+ }
+ }
+ else if ( DriverStatus != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1("TpFuncOpenAdapter: NdisOpenAdapter returned %s\n",
+ TpGetStatus( DriverStatus ));
+ }
+ goto cleanup;
+ }
+
+ //
+ // The open was a success, so set the open instance on
+ // the open block.
+ //
+
+ OpenP->OpenInstance = OpenInstance;
+
+ //
+ // and initialize the stress address depending on the medium type
+ // of the adapter opened.
+ //
+
+ switch ( NdisMediumArray[OpenP->MediumIndex] )
+ {
+ case NdisMedium802_5:
+ for ( i=0 ; i < ADDRESS_LENGTH ; i++ )
+ {
+ OpenP->Environment->StressAddress[i] = STRESS_FUNCTIONAL[i];
+ }
+ break;
+
+ case NdisMediumFddi:
+ case NdisMediumDix:
+ case NdisMedium802_3:
+ for ( i=0;i<ADDRESS_LENGTH;i++ )
+ {
+ OpenP->Environment->StressAddress[i] = STRESS_MULTICAST[i];
+ }
+ break;
+ //
+ // STARTCHANGE
+ //
+ case NdisMediumArcnet878_2:
+ TP_ASSERT (MediaArraySize == NDIS_MEDIUM_ARRAY_SIZE)
+
+ for ( i=0;i<ADDRESS_LENGTH;i++ )
+ {
+ OpenP->Environment->StressAddress[i] = STRESS_ARCNET_BROADCAST[i];
+ }
+ break;
+ //
+ // STOPCHANGE
+ //
+ default:
+ IF_TPDBG ( TP_DEBUG_RESOURCES )
+ {
+ TpPrint0("TpFuncOpenAdapter: Unsupported MAC Type\n");
+ }
+ DriverStatus = NDIS_STATUS_UNSUPPORTED_MEDIA;
+ goto cleanup;
+ }
+
+ //
+ // Now allocate the Ndis Request structure to hold the query
+ // information requests in.
+ //
+
+ Status = NdisAllocateMemory((PVOID *)&Request,
+ sizeof( NDIS_REQUEST ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpFuncOpenAdapter: unable to allocate Ndis Request buffer.\n");
+ }
+ Status = NDIS_STATUS_RESOURCES;
+ goto cleanup;
+ }
+ else
+ {
+ NdisZeroMemory( Request,sizeof( NDIS_REQUEST ));
+ }
+
+ Request->RequestType = NdisRequestQueryInformation;
+
+ //
+ // Now query the card address and the maximum frame size
+ // from the MAC. Determine the necessary size of the
+ // information buffer to fit the station address, and
+ // allocate it.
+ //
+
+ //
+ // STARTCHANGE
+ //
+ if ( NdisMediumArray[OpenP->MediumIndex] == NdisMedium802_3 )
+ {
+ OidIndex = TpLookUpOidInfo( OID_802_3_CURRENT_ADDRESS );
+ }
+ else if ( NdisMediumArray[OpenP->MediumIndex] == NdisMedium802_5 )
+ {
+ OidIndex = TpLookUpOidInfo( OID_802_5_CURRENT_ADDRESS );
+ }
+ else if ( NdisMediumArray[OpenP->MediumIndex] == NdisMediumFddi )
+ {
+ OidIndex = TpLookUpOidInfo( OID_FDDI_LONG_CURRENT_ADDR );
+ }
+ else if ( NdisMediumArray[OpenP->MediumIndex] == NdisMediumArcnet878_2 )
+ {
+ OidIndex = TpLookUpOidInfo( OID_ARCNET_CURRENT_ADDRESS );
+ }
+ //
+ // STOPCHANGE
+ //
+
+ Status = NdisAllocateMemory((PVOID *)&InformationBuffer,
+ OidArray[OidIndex].Length,
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpFuncOpenAdapter: unable to allocate Information Buffer.\n");
+ }
+ Status = NDIS_STATUS_RESOURCES;
+ goto cleanup;
+ }
+ else
+ {
+ NdisZeroMemory( InformationBuffer,OidArray[OidIndex].Length);
+ }
+
+ Request->DATA.QUERY_INFORMATION.Oid = OidArray[OidIndex].Oid;
+ Request->DATA.QUERY_INFORMATION.InformationBuffer = InformationBuffer;
+ Request->DATA.QUERY_INFORMATION.InformationBufferLength = OidArray[OidIndex].Length;
+
+ //
+ // and then make the request
+ //
+
+ NdisRequest( &RequestStatus,OpenP->NdisBindingHandle,Request );
+
+ if ( RequestStatus == NDIS_STATUS_PENDING )
+ {
+ Status = KeWaitForSingleObject( &OpenP->OpenReqHndl->u.OPEN_REQ.OpenEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL );
+
+ if ( Status != STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_NT_STATUS )
+ {
+ TpPrint1("TpFuncOpenAdapter: KeWaitForSingleObject returned %s\n",Status );
+ }
+ goto cleanup;
+ }
+
+ RequestStatus = OpenP->OpenReqHndl->u.OPEN_REQ.RequestStatus;
+
+ if ( RequestStatus != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1(
+ "TpFuncOpenAdapter: NdisRequest Query Station Address failed: returned %s\n",
+ TpGetStatus( RequestStatus ));
+ }
+ goto cleanup;
+ }
+ }
+ else if ( RequestStatus != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1(
+ "TpFuncOpenAdapter: NdisRequest Query Station Address failed returned %s\n",
+ TpGetStatus( RequestStatus ));
+ }
+ goto cleanup;
+ }
+
+ GotCardAddress = TRUE;
+
+ p = OpenP->StationAddress;
+ q = (PUCHAR)InformationBuffer;
+
+ //
+ // STARTCHANGE
+ //
+ for ( i=0;i<OidArray[OidIndex].Length;i++ )
+ {
+ *p++ = *q++;
+ }
+ //
+ // STOPCHANGE
+ //
+
+ //
+ // Then determine the necessary size of the information buffer
+ // to allocate, and allocate it.
+ //
+
+ OidIndex = TpLookUpOidInfo( OID_GEN_MAXIMUM_TOTAL_SIZE );
+
+ NdisZeroMemory( InformationBuffer,OidArray[OidIndex].Length );
+
+ Request->RequestType = NdisRequestQueryInformation;
+
+ Request->DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_TOTAL_SIZE;
+ Request->DATA.QUERY_INFORMATION.InformationBuffer = InformationBuffer;
+ Request->DATA.QUERY_INFORMATION.InformationBufferLength = OidArray[OidIndex].Length;
+ //
+ // and then make the request
+ //
+
+ NdisRequest( &RequestStatus,OpenP->NdisBindingHandle,Request );
+
+ if ( RequestStatus == NDIS_STATUS_PENDING )
+ {
+ Status = KeWaitForSingleObject( &OpenP->OpenReqHndl->u.OPEN_REQ.OpenEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL );
+
+ if ( Status != STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_NT_STATUS )
+ {
+ TpPrint1("TpFuncOpenAdapter: KeWaitForSingleObject returned %s\n",Status );
+ }
+ goto cleanup;
+ }
+
+ RequestStatus = OpenP->OpenReqHndl->u.OPEN_REQ.RequestStatus;
+
+ if ( RequestStatus != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1("TpFuncOpenAdapter: NdisRequest Max Frame Size failed: returned %s\n",
+ TpGetStatus( RequestStatus ));
+ }
+ goto cleanup;
+ }
+ }
+ else if ( RequestStatus != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1("TpFuncOpenAdapter: NdisRequest Max Frame Size failed: returned %s\n",
+ TpGetStatus( RequestStatus ));
+ }
+ goto cleanup;
+ }
+
+ Status = TpInitMedia( OpenP,*(PULONG)InformationBuffer );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_INITIALIZE )
+ {
+ TpPrint1("TpFuncOpenAdapter: TpInitMedia failed. returned %s\n",
+ TpGetStatus( Status ));
+ }
+ goto cleanup;
+ }
+
+
+ //
+ // SANJEEVK: NEW: BUG#2930 NTRAID\NTBUG
+ //
+
+ //
+ // Set the lookahead size to the max supported by the card
+ // Later on if we don't like it we can change it
+ //
+
+ //
+ // QUERY the OID_GEN_MAXIMUM_LOOKAHEAD
+ //
+ OidIndex = TpLookUpOidInfo( OID_GEN_MAXIMUM_LOOKAHEAD );
+
+ NdisZeroMemory( InformationBuffer,OidArray[OidIndex].Length );
+
+ Request->RequestType = NdisRequestQueryInformation;
+
+ Request->DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_LOOKAHEAD;
+ Request->DATA.QUERY_INFORMATION.InformationBuffer = InformationBuffer;
+ Request->DATA.QUERY_INFORMATION.InformationBufferLength = OidArray[OidIndex].Length;
+
+ //
+ // and then make the request
+ //
+
+ NdisRequest( &RequestStatus,OpenP->NdisBindingHandle,Request );
+
+ if ( RequestStatus == NDIS_STATUS_PENDING )
+ {
+ Status = KeWaitForSingleObject( &OpenP->OpenReqHndl->u.OPEN_REQ.OpenEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL );
+
+ if ( Status != STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_NT_STATUS )
+ {
+ TpPrint1("TpFuncOpenAdapter: KeWaitForSingleObject returned %s\n",Status );
+ }
+
+ goto cleanup;
+ }
+
+ RequestStatus = OpenP->OpenReqHndl->u.OPEN_REQ.RequestStatus;
+
+ if ( RequestStatus != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1(
+ "TpFuncOpenAdapter: NdisRequest QueryMaxLookAhead failed: returned %s\n",
+ TpGetStatus( RequestStatus ));
+ }
+ goto cleanup;
+ }
+ }
+ else if ( RequestStatus != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1("TpFuncOpenAdapter: NdisRequest QueryMaxLookAhead failed: returned %s\n",
+ TpGetStatus( RequestStatus ));
+ }
+ goto cleanup;
+ }
+
+
+ //
+ // And now set the card with the maximum value
+ //
+ OidIndex = TpLookUpOidInfo( OID_GEN_CURRENT_LOOKAHEAD );
+
+ Request->RequestType = NdisRequestSetInformation;
+
+ Request->DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_LOOKAHEAD;
+ Request->DATA.SET_INFORMATION.InformationBuffer = InformationBuffer;
+ Request->DATA.SET_INFORMATION.InformationBufferLength = OidArray[OidIndex].Length;
+
+ //
+ // and then make the request
+ //
+
+ NdisRequest( &RequestStatus,OpenP->NdisBindingHandle,Request );
+
+ if ( RequestStatus == NDIS_STATUS_PENDING )
+ {
+ Status = KeWaitForSingleObject( &OpenP->OpenReqHndl->u.OPEN_REQ.OpenEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL );
+
+ if ( Status != STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_NT_STATUS )
+ {
+ TpPrint1("TpFuncOpenAdapter: KeWaitForSingleObject returned %s\n",Status );
+ }
+ goto cleanup;
+ }
+ RequestStatus = OpenP->OpenReqHndl->u.OPEN_REQ.RequestStatus;
+
+ if ( RequestStatus != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1(
+ "TpFuncOpenAdapter: NdisRequest SetCurrentLookAhead to MAXLOOKAHEAD failed: returned %s\n",
+ TpGetStatus( RequestStatus ));
+ }
+ goto cleanup;
+ }
+ }
+ else if ( RequestStatus != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1(
+ "TpFuncOpenAdapter: NdisRequest SetCurrentLookAhead to MAXLOOKAHEAD failed: returned %s\n",
+ TpGetStatus( RequestStatus ));
+ }
+ goto cleanup;
+ }
+
+ //
+ // ENDNEW
+ //
+
+ //
+ // If we are on ethernet query the multicast list size for
+ // use in later tests.
+ //
+
+ if ( NdisMediumArray[OpenP->MediumIndex] == NdisMedium802_3 )
+ {
+ OidIndex = TpLookUpOidInfo( OID_802_3_MAXIMUM_LIST_SIZE );
+
+ NdisZeroMemory( InformationBuffer,OidArray[OidIndex].Length);
+
+ Request->RequestType = NdisRequestQueryInformation;
+
+ Request->DATA.QUERY_INFORMATION.Oid = OID_802_3_MAXIMUM_LIST_SIZE;
+ Request->DATA.QUERY_INFORMATION.InformationBuffer = InformationBuffer;
+ Request->DATA.QUERY_INFORMATION.InformationBufferLength = OidArray[OidIndex].Length;
+
+ //
+ // and then make the request
+ //
+
+ NdisRequest( &RequestStatus,OpenP->NdisBindingHandle,Request );
+
+ if ( RequestStatus == NDIS_STATUS_PENDING )
+ {
+ Status = KeWaitForSingleObject( &OpenP->OpenReqHndl->u.OPEN_REQ.OpenEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL );
+
+ if ( Status != STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_NT_STATUS )
+ {
+ TpPrint1("TpFuncOpenAdapter: KeWaitForSingleObject returned %s\n",Status );
+ }
+ goto cleanup;
+ }
+ RequestStatus = OpenP->OpenReqHndl->u.OPEN_REQ.RequestStatus;
+
+ if ( RequestStatus != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1(
+ "TpFuncOpenAdapter: NdisRequest Max Frame Size failed: returned %s\n",
+ TpGetStatus( RequestStatus ));
+ }
+ goto cleanup;
+ }
+ }
+ else if ( RequestStatus != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1("TpFuncOpenAdapter: NdisRequest Max Frame Size failed: returned %s\n",
+ TpGetStatus( RequestStatus ));
+ }
+ goto cleanup;
+ }
+ OpenP->Environment->MulticastListSize = *(PULONG)InformationBuffer;
+ }
+
+ if ( NdisMediumArray[OpenP->MediumIndex] == NdisMediumFddi )
+ {
+ OidIndex = TpLookUpOidInfo( OID_FDDI_LONG_MAX_LIST_SIZE );
+
+ NdisZeroMemory( InformationBuffer,OidArray[OidIndex].Length);
+
+ Request->RequestType = NdisRequestQueryInformation;
+
+ Request->DATA.QUERY_INFORMATION.Oid = OID_FDDI_LONG_MAX_LIST_SIZE;
+ Request->DATA.QUERY_INFORMATION.InformationBuffer = InformationBuffer;
+ Request->DATA.QUERY_INFORMATION.InformationBufferLength = OidArray[OidIndex].Length;
+
+ //
+ // and then make the request
+ //
+
+ NdisRequest( &RequestStatus,OpenP->NdisBindingHandle,Request );
+
+ if ( RequestStatus == NDIS_STATUS_PENDING )
+ {
+ Status = KeWaitForSingleObject( &OpenP->OpenReqHndl->u.OPEN_REQ.OpenEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL );
+
+ if ( Status != STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_NT_STATUS )
+ {
+ TpPrint1("TpFuncOpenAdapter: KeWaitForSingleObject returned %s\n",Status );
+ }
+ goto cleanup;
+ }
+
+ RequestStatus = OpenP->OpenReqHndl->u.OPEN_REQ.RequestStatus;
+
+ if ( RequestStatus != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1(
+ "TpFuncOpenAdapter: NdisRequest Max Frame Size failed: returned %s\n",
+ TpGetStatus( RequestStatus ));
+ }
+ goto cleanup;
+ }
+ }
+ else if ( RequestStatus != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1("TpFuncOpenAdapter: NdisRequest Max Frame Size failed: returned %s\n",
+ TpGetStatus( RequestStatus ));
+ }
+ goto cleanup;
+ }
+ OpenP->Environment->MulticastListSize = *(PULONG)InformationBuffer;
+ }
+ }
+
+
+cleanup:
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ if ( OpenP->Irp != NULL )
+ {
+ OutputBuffer = MmGetSystemAddressForMdl( OpenP->Irp->MdlAddress );
+
+ OutputBuffer->Signature = OPEN_RESULTS_SIGNATURE;
+ OutputBuffer->RequestPended = OpenP->OpenReqHndl->RequestPended;
+ OutputBuffer->RequestStatus = DriverStatus;
+
+ if (( Status == STATUS_SUCCESS ) &&
+ ( DriverStatus == NDIS_STATUS_SUCCESS ))
+ {
+ OutputBuffer->OpenRequestStatus = RequestStatus;
+
+ if ( RequestStatus != NDIS_STATUS_SUCCESS )
+ {
+ OutputBuffer->OID = Request->DATA.QUERY_INFORMATION.Oid;
+
+ OutputBuffer->BytesReadWritten = Request->DATA.QUERY_INFORMATION.BytesWritten;
+
+ OutputBuffer->BytesNeeded = Request->DATA.QUERY_INFORMATION.BytesNeeded;
+
+ //
+ // Since a portion of the call failed, i.e. one of the query
+ // info calls, we are failing the whole call, and need to
+ // reset the card open info.
+ //
+
+ OpenP->OpenInstance = 0xFF;
+
+ if ( OpenP->Media != NULL )
+ {
+ NdisFreeMemory( OpenP->Media,0,0 );
+ OpenP->Media = NULL;
+ }
+
+ }
+ else if ( GotCardAddress == TRUE )
+ {
+ PNDIS_MEDIUM MediumType = (PNDIS_MEDIUM)OutputBuffer->InformationBuffer;
+ //
+ // Sanjeevk: Bug #5203
+ //
+ // Comment
+ //
+ // This is where the user provided buffer thru the IOCTL
+ // is filled out with the address and the media type
+ //
+
+ //
+ // Copy the Media type into the buffer. The media type
+ // has been initialized by a call to TpInitMedia() earlier
+ // on in this function.
+ //
+ *MediumType = OpenP->Media->MediumType;
+
+ //
+ // Copy the adapter address into the buffer
+ //
+ p = OutputBuffer->InformationBuffer + sizeof( NDIS_MEDIUM );
+ q = OpenP->StationAddress;
+
+ for ( i=0;i<OpenP->Media->AddressLen;i++ )
+ {
+ *p++ = *q++;
+ }
+
+ }
+ }
+ }
+
+ OpenP->Irp->IoStatus.Status = Status;
+
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ if ( OpenP->OpenReqHndl != NULL )
+ {
+ NdisFreeMemory( OpenP->OpenReqHndl,0,0 );
+ OpenP->OpenReqHndl = NULL;
+ }
+
+ if ((( DriverStatus != NDIS_STATUS_SUCCESS ) ||
+ ( RequestStatus != NDIS_STATUS_SUCCESS )) &&
+ ( OpenP->AdapterName != NULL ))
+ {
+
+ NdisFreeMemory( OpenP->AdapterName,0,0 );
+ OpenP->AdapterName = NULL;
+ }
+
+ if ( Request != NULL )
+ {
+ NdisFreeMemory( Request,0,0 );
+ }
+
+ if ( InformationBuffer != NULL )
+ {
+ NdisFreeMemory( InformationBuffer,0,0 );
+ }
+
+ return Status;
+}
+
+
+
+VOID
+TpFuncOpenComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status,
+ IN NDIS_STATUS OpenErrorStatus
+ )
+
+{
+ POPEN_BLOCK OpenP = (POPEN_BLOCK)ProtocolBindingContext;
+ ULONG NextEvent;
+
+ TP_ASSERT( OpenP != NULL );
+
+ if (( OpenP->OpenReqHndl != NULL ) &&
+ (( OpenP->OpenReqHndl->Signature == OPEN_REQUEST_HANDLE_SIGNATURE ) &&
+ ( OpenP->OpenReqHndl->Open == OpenP )))
+ {
+ IF_TPDBG(TP_DEBUG_DISPATCH)
+ {
+ TpPrint1("TpFuncOpenComplete Status = %s\n", TpGetStatus( Status ));
+ }
+
+ OpenP->OpenReqHndl->RequestPended = TRUE;
+ OpenP->OpenReqHndl->u.OPEN_REQ.RequestStatus = Status;
+
+ KeSetEvent( &OpenP->OpenReqHndl->u.OPEN_REQ.OpenEvent,0,FALSE );
+
+ }
+ else
+ {
+ //
+ // We are not expecting any Open requests to complete at this
+ // point, so stick this on the Event Queue.
+ //
+
+ NdisAcquireSpinLock( &OpenP->EventQueue->SpinLock );
+
+ NextEvent = OpenP->EventQueue->Head + 1;
+
+ if ( NextEvent == MAX_EVENT )
+ {
+ NextEvent = 0;
+ }
+
+ if ( NextEvent != OpenP->EventQueue->Tail )
+ {
+ //
+ // There is room to add another event to the event queue.
+ //
+
+ OpenP->EventQueue->Events[NextEvent].TpEventType = CompleteOpen;
+ OpenP->EventQueue->Head = NextEvent;
+ }
+ else
+ {
+ //
+ // The event queue is full, and this would have overflowed it, so
+ // mark the Head event overflow flag to show this.
+ //
+
+ OpenP->EventQueue->Events[OpenP->EventQueue->Head].Overflow = TRUE;
+ }
+ NdisReleaseSpinLock( &OpenP->EventQueue->SpinLock );
+ }
+}
+
+
+
+NDIS_STATUS
+TpFuncCloseAdapter(
+ IN POPEN_BLOCK OpenP
+ )
+
+// --------
+//
+// Routine Description:
+//
+//
+// Arguments:
+//
+//
+// Return Value:
+//
+// Status -
+//
+// ------
+
+{
+ NDIS_STATUS Status;
+ LARGE_INTEGER TimeOut;
+
+ TP_ASSERT( OpenP->CloseReqHndl == NULL );
+
+ //
+ // First determine whether this instance of the Adapter is currently
+ // opened.
+ //
+
+ if ( OpenP->OpenInstance == (UCHAR)-1 )
+ {
+ //
+ // It is not already opened, so we will fail this call.
+ //
+ IF_TPDBG ( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint0("TpFuncCloseAdapter: An open does not exists for this Open Instance\n");
+ }
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ if ( OpenP->Irp != NULL )
+ {
+ OpenP->Irp->IoStatus.Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+ }
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ return NDIS_STATUS_ADAPTER_NOT_FOUND;
+ }
+ else
+ {
+ //
+ // Otherwise allocate the request handle and set it up as if
+ // the request pended. If it does not pend we will reset the
+ // flags later before calling the completion routine.
+ //
+
+ Status = NdisAllocateMemory((PVOID *)&OpenP->CloseReqHndl,
+ sizeof( TP_REQUEST_HANDLE ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpFuncOpenAdapter: unable to allocate Request Handle.\n");
+ }
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ if ( OpenP->Irp != NULL )
+ {
+ OpenP->Irp->IoStatus.Status = NDIS_STATUS_RESOURCES;
+ }
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ return NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( OpenP->CloseReqHndl,sizeof( TP_REQUEST_HANDLE ));
+ }
+
+ OpenP->CloseReqHndl->Signature = FUNC_REQUEST_HANDLE_SIGNATURE;
+ OpenP->CloseReqHndl->Open = OpenP;
+ OpenP->CloseReqHndl->RequestPended = TRUE;
+ OpenP->CloseReqHndl->Irp = OpenP->Irp;
+
+ //
+ // Then we will attempt to close it. First set the
+ // open instance's closing flag to true, then signal all
+ // the async test protocol routines that are currently
+ // running to end.
+ //
+
+ OpenP->Closing = TRUE;
+
+ if ( OpenP->Stress->Stressing == TRUE )
+ {
+ OpenP->Stress->StopStressing = TRUE;
+ }
+
+ if ( OpenP->Send->Sending == TRUE )
+ {
+ OpenP->Send->StopSending = TRUE;
+ }
+
+ if ( OpenP->Receive->Receiving == TRUE )
+ {
+ OpenP->Receive->StopReceiving = TRUE;
+ }
+
+ //
+ // Then wait for all of the three asynchronous routines;
+ // STRESS, SEND and RECEIVE to finish.
+ //
+
+ TimeOut.HighPart = -1; // so it will be relative.
+ TimeOut.LowPart = (ULONG)(-(ONE_TENTH_SECOND));
+
+ while ( OpenP->ReferenceCount > 0 )
+ {
+ // Status = KeDelayExecutionThread( KernelMode,FALSE,&TimeOut );
+ /* NULL */ ;
+ }
+
+ //
+ // finally we will attempt to close it.
+ //
+
+ NdisCloseAdapter( &Status,OpenP->NdisBindingHandle );
+
+ if (( Status != NDIS_STATUS_SUCCESS ) &&
+ ( Status != NDIS_STATUS_PENDING ))
+ {
+ IF_TPDBG ( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1("TpFuncCloseAdapter: NdisCloseAdapter returned %s\n", TpGetStatus(Status));
+ }
+ }
+
+ if ( Status != NDIS_STATUS_PENDING )
+ {
+ //
+ // If the request did not pend, we should reset the pend flag,
+ // and the status flag in the OpenP->CloseReqHndl, and then
+ // call the completion handler ourselves.
+ //
+
+ OpenP->CloseReqHndl->RequestPended = FALSE;
+ TpFuncCloseComplete( OpenP,Status );
+ }
+ }
+ return NDIS_STATUS_PENDING;
+}
+
+
+
+VOID
+TpFuncCloseComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status
+ )
+{
+ POPEN_BLOCK OpenP = (POPEN_BLOCK)ProtocolBindingContext;
+ PREQUEST_RESULTS OutputBuffer;
+ USHORT i;
+ ULONG NextEvent;
+
+ TP_ASSERT( OpenP != NULL );
+
+ if (( OpenP->CloseReqHndl != NULL ) &&
+ (( OpenP->CloseReqHndl->Signature == FUNC_REQUEST_HANDLE_SIGNATURE ) &&
+ ( OpenP->CloseReqHndl->Open == OpenP )))
+ {
+ IF_TPDBG(TP_DEBUG_DISPATCH)
+ {
+ TpPrint1("TpFuncCloseComplete Status = %s\n", TpGetStatus( Status ));
+ }
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ if ( OpenP->CloseReqHndl->Irp != NULL )
+ {
+ OutputBuffer = MmGetSystemAddressForMdl( OpenP->CloseReqHndl->Irp->MdlAddress );
+
+ OutputBuffer->Signature = CLOSE_RESULTS_SIGNATURE;
+ OutputBuffer->RequestPended = OpenP->CloseReqHndl->RequestPended;
+ OutputBuffer->RequestStatus = Status;
+
+ if ( Status == NDIS_STATUS_SUCCESS )
+ {
+ //
+ // The close of the adapter was a success so set the flags
+ // in the OpenBlock back to the initial state, and reset
+ // the StationAddress to NULL.
+ //
+
+ OpenP->NdisBindingHandle = NULL;
+ OpenP->OpenInstance = 0xFF;
+ OpenP->Closing = FALSE;
+
+ if ( OpenP->AdapterName != NULL )
+ {
+ NdisFreeMemory( OpenP->AdapterName,0,0 );
+ OpenP->AdapterName = NULL;
+ }
+
+ for ( i=0;i<OpenP->Media->AddressLen;i++ )
+ {
+ OpenP->StationAddress[i] = 0x00;
+ }
+
+ //
+ // We will also free the media block at this point because
+ // the info it contains may not hold for the next adapter
+ // open on this instance.
+ //
+
+ if ( OpenP->Media != NULL )
+ {
+ NdisFreeMemory( OpenP->Media,0,0 );
+ OpenP->Media = NULL;
+ }
+ }
+
+ TP_ASSERT(Status != NDIS_STATUS_PENDING);
+
+ OpenP->CloseReqHndl->Irp->IoStatus.Status = Status;
+
+ IoMarkIrpPending( OpenP->CloseReqHndl->Irp );
+
+ IoAcquireCancelSpinLock( &OpenP->CloseReqHndl->Irp->CancelIrql );
+ IoSetCancelRoutine( OpenP->CloseReqHndl->Irp,NULL );
+ IoReleaseCancelSpinLock( OpenP->CloseReqHndl->Irp->CancelIrql );
+
+ IoCompleteRequest( OpenP->CloseReqHndl->Irp,IO_NETWORK_INCREMENT );
+ }
+
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ NdisFreeMemory( OpenP->CloseReqHndl,0,0 );
+ OpenP->CloseReqHndl = NULL;
+ }
+ else
+ {
+ //
+ // We are not expecting any requests to complete at this
+ // point, so stick this on the Event Queue.
+ //
+
+ NdisAcquireSpinLock( &OpenP->EventQueue->SpinLock );
+
+ NextEvent = OpenP->EventQueue->Head + 1;
+
+ if ( NextEvent == MAX_EVENT )
+ {
+ NextEvent = 0;
+ }
+
+ if ( NextEvent != OpenP->EventQueue->Tail )
+ {
+ //
+ // There is room to add another event to the event queue.
+ //
+
+ OpenP->EventQueue->Events[NextEvent].TpEventType = CompleteClose;
+
+ OpenP->EventQueue->Head = NextEvent;
+
+ // we should also stick some interesting info likje requesttype.
+ }
+ else
+ {
+ //
+ // The event queue is full, and this would have overflowed it, so
+ // mark the Head event overflow flag to show this.
+ //
+ OpenP->EventQueue->Events[OpenP->EventQueue->Head].Overflow = TRUE;
+ }
+ NdisReleaseSpinLock( &OpenP->EventQueue->SpinLock );
+ }
+}
+
+
+
+NDIS_STATUS
+TpFuncReset(
+ IN POPEN_BLOCK OpenP
+ )
+
+// ------------
+//
+// Routine Description:
+//
+//
+// Arguments:
+//
+//
+// Return Value:
+//
+// Status -
+//
+// Change history:
+//
+// SanjeevK : During initial allocation during the reset, should the allocation fail, the spin
+// lock for the OPEN_BLOCK was being acquired twice instead of being acquired
+// and then released. Bug #3109
+//
+// ------------
+
+{
+ NDIS_STATUS Status;
+
+ TP_ASSERT( OpenP->ResetReqHndl == NULL );
+
+ Status = NdisAllocateMemory((PVOID *)&OpenP->ResetReqHndl,
+ sizeof( TP_REQUEST_HANDLE ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpFuncReset: unable to allocate Request Handle.\n");
+ }
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ if ( OpenP->Irp != NULL )
+ {
+ OpenP->Irp->IoStatus.Status = NDIS_STATUS_RESOURCES;
+ }
+
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ return NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( OpenP->ResetReqHndl,sizeof( TP_REQUEST_HANDLE ));
+ }
+
+ OpenP->ResetReqHndl->Signature = FUNC_REQUEST_HANDLE_SIGNATURE;
+ OpenP->ResetReqHndl->Open = OpenP;
+ OpenP->ResetReqHndl->RequestPended = TRUE;
+ OpenP->ResetReqHndl->Irp = OpenP->Irp;
+
+ //
+ // Then make the call to RESET the adapter.
+ //
+
+ NdisReset( &Status,OpenP->NdisBindingHandle );
+
+ if (( Status != NDIS_STATUS_SUCCESS ) &&
+ ( Status != NDIS_STATUS_PENDING ))
+ {
+ IF_TPDBG(TP_DEBUG_NDIS_ERROR)
+ {
+ TpPrint1("TpFuncReset: NdisReset failed: returned %s\n",
+ TpGetStatus( Status ));
+ }
+ }
+
+ if ( Status != NDIS_STATUS_PENDING )
+ {
+ //
+ // If the request did not pend, we should reset the pend flag,
+ // and the status flag in the RequestHandle, and call the
+ // completion handler ourselves.
+ //
+
+ OpenP->ResetReqHndl->RequestPended = FALSE;
+ TpFuncResetComplete( OpenP,Status );
+ }
+ return NDIS_STATUS_PENDING;
+}
+
+
+
+VOID
+TpFuncResetComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status
+ )
+{
+ POPEN_BLOCK OpenP = (POPEN_BLOCK)ProtocolBindingContext;
+ PREQUEST_RESULTS OutputBuffer;
+ ULONG NextEvent;
+
+ TP_ASSERT( OpenP != NULL );
+
+ if (( OpenP->ResetReqHndl != NULL ) &&
+ (( OpenP->ResetReqHndl->Signature == FUNC_REQUEST_HANDLE_SIGNATURE ) &&
+ ( OpenP->ResetReqHndl->Open == OpenP )))
+ {
+ IF_TPDBG(TP_DEBUG_DISPATCH)
+ {
+ TpPrint1("TpFuncResetComplete Status = %s\n",
+ TpGetStatus( Status ));
+ }
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ if ( OpenP->ResetReqHndl->Irp != NULL )
+ {
+ OutputBuffer = MmGetSystemAddressForMdl( OpenP->ResetReqHndl->Irp->MdlAddress );
+
+ OutputBuffer->Signature = RESET_RESULTS_SIGNATURE;
+ OutputBuffer->RequestPended = OpenP->ResetReqHndl->RequestPended;
+ OutputBuffer->RequestStatus = Status;
+
+ OpenP->ResetReqHndl->Irp->IoStatus.Status = Status;
+
+ TP_ASSERT( Status != NDIS_STATUS_PENDING );
+
+ IoMarkIrpPending( OpenP->ResetReqHndl->Irp );
+
+ IoAcquireCancelSpinLock( &OpenP->ResetReqHndl->Irp->CancelIrql );
+ IoSetCancelRoutine( OpenP->ResetReqHndl->Irp,NULL );
+ IoReleaseCancelSpinLock( OpenP->ResetReqHndl->Irp->CancelIrql );
+
+ IoCompleteRequest( OpenP->ResetReqHndl->Irp,IO_NETWORK_INCREMENT );
+ }
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ NdisFreeMemory( OpenP->ResetReqHndl,0,0 );
+ OpenP->ResetReqHndl = NULL;
+ }
+ else
+ {
+ //
+ // We are not expecting any requests to complete at this
+ // point, so stick this on the Event Queue.
+ //
+ NdisAcquireSpinLock( &OpenP->EventQueue->SpinLock );
+ NextEvent = OpenP->EventQueue->Head + 1;
+
+ if ( NextEvent == MAX_EVENT )
+ {
+ NextEvent = 0;
+ }
+
+ if ( NextEvent != OpenP->EventQueue->Tail )
+ {
+ //
+ // There is room to add another event to the event queue.
+ //
+
+ OpenP->EventQueue->Events[NextEvent].TpEventType = CompleteReset;
+ OpenP->EventQueue->Head = NextEvent;
+
+ // we should also stick some interesting info likje requesttype.
+ }
+ else
+ {
+ //
+ // The event queue is full, and this would have overflowed it, so
+ // mark the Head event overflow flag to show this.
+ //
+ OpenP->EventQueue->Events[OpenP->EventQueue->Head].Overflow = TRUE;
+ }
+
+ NdisReleaseSpinLock( &OpenP->EventQueue->SpinLock );
+ }
+}
+
+
+
+NDIS_STATUS
+TpFuncRequestQueryInfo(
+ IN POPEN_BLOCK OpenP,
+ IN PCMD_ARGS CmdArgs,
+ IN OUT PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+{
+ NDIS_STATUS Status;
+ PNDIS_REQUEST Request;
+ PUCHAR InformationBuffer;
+ ULONG OidIndex;
+ ULONG InfoBufLength;
+
+ //
+ // First allocate a request handle structure to hold the
+ // test information in.
+ //
+
+ TP_ASSERT( OpenP->RequestReqHndl == NULL );
+
+ Status = NdisAllocateMemory((PVOID *)&OpenP->RequestReqHndl,
+ sizeof( TP_REQUEST_HANDLE ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpFuncRequestQueryInfo: unable to allocate Request Handle.\n");
+ }
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ if ( OpenP->Irp != NULL )
+ {
+ Irp->IoStatus.Status = NDIS_STATUS_RESOURCES;
+ }
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ return NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( OpenP->RequestReqHndl,sizeof( TP_REQUEST_HANDLE ));
+ }
+
+ OpenP->RequestReqHndl->Signature = FUNC_REQUEST_HANDLE_SIGNATURE;
+ OpenP->RequestReqHndl->Open = OpenP;
+ OpenP->RequestReqHndl->RequestPended = TRUE;
+ OpenP->RequestReqHndl->Irp = Irp;
+
+ OpenP->RequestReqHndl->u.INFO_REQ.IoControlCode =
+ IrpSp->Parameters.DeviceIoControl.IoControlCode;
+
+ //
+ // Now allocate the Ndis Request structure to hold the
+ // query information request in.
+ //
+
+ Status = NdisAllocateMemory((PVOID *)&Request,
+ sizeof( NDIS_REQUEST ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpFuncRequestQueryInfo: unable to allocate Request.\n");
+ }
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ if ( OpenP->Irp != NULL )
+ {
+ Irp->IoStatus.Status = NDIS_STATUS_RESOURCES;
+ }
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ return NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( Request,sizeof( NDIS_REQUEST ));
+ }
+
+ OpenP->RequestReqHndl->u.INFO_REQ.NdisRequestType =
+ Request->RequestType = NdisRequestQueryInformation;
+
+ //
+ // Then determine the necessary size of the information buffer
+ // to allocate, and allocate it.
+ //
+
+ OidIndex = TpLookUpOidInfo( CmdArgs->ARGS.TPQUERY.OID );
+
+ //
+ // If the OID we are going to call is for the Multicast List, then
+ // we will need a buffer of size MaxMulticastList * sizeof(Multicast)
+ //
+
+ if (( CmdArgs->ARGS.TPQUERY.OID == OID_802_3_MULTICAST_LIST ) ||
+ ( CmdArgs->ARGS.TPQUERY.OID == OID_FDDI_LONG_MULTICAST_LIST ))
+ {
+ InfoBufLength = OpenP->Environment->MulticastListSize * ADDRESS_LENGTH;
+ }
+ else
+ {
+ InfoBufLength = OidArray[OidIndex].Length;
+ }
+
+ Status = NdisAllocateMemory((PVOID *)&InformationBuffer,
+ InfoBufLength,
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpFuncRequestQueryInfo: unable to allocate Information Buffer.\n");
+ }
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ if ( OpenP->Irp != NULL )
+ {
+ Irp->IoStatus.Status = NDIS_STATUS_RESOURCES;
+ }
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ return NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( InformationBuffer,InfoBufLength );
+ }
+
+ Request->DATA.QUERY_INFORMATION.Oid = CmdArgs->ARGS.TPQUERY.OID;
+ Request->DATA.QUERY_INFORMATION.InformationBuffer = InformationBuffer;
+ Request->DATA.QUERY_INFORMATION.InformationBufferLength = InfoBufLength;
+
+ OpenP->RequestReqHndl->u.INFO_REQ.OID = CmdArgs->ARGS.TPQUERY.OID;
+ OpenP->RequestReqHndl->u.INFO_REQ.InformationBuffer = InformationBuffer;
+ OpenP->RequestReqHndl->u.INFO_REQ.InformationBufferLength = InfoBufLength;
+
+ NdisRequest( &Status,OpenP->NdisBindingHandle,Request );
+
+ if (( Status != NDIS_STATUS_SUCCESS ) &&
+ ( Status != NDIS_STATUS_PENDING ))
+ {
+ IF_TPDBG ( TP_DEBUG_NDIS_ERROR )
+ {
+ TpPrint1("TpFuncRequestQueryInfo: NdisRequest failed: returned %s\n",
+ TpGetStatus(Status));
+ }
+ }
+
+ if ( Status != NDIS_STATUS_PENDING )
+ {
+ //
+ // If the request did not pend, we should reset the pend flag,
+ // and the status flag in the OpenP->RequestReqHndl, and call the
+ // completion handler ourselves.
+ //
+
+ OpenP->RequestReqHndl->RequestPended = FALSE;
+ TpFuncRequestComplete( OpenP,Request,Status );
+ }
+ return NDIS_STATUS_PENDING;
+}
+
+
+
+NDIS_STATUS
+TpFuncRequestSetInfo(
+ IN POPEN_BLOCK OpenP,
+ IN PCMD_ARGS CmdArgs,
+ IN OUT PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+// -----------
+//
+// Routine Description:
+//
+//
+// Arguments:
+//
+//
+// Return Value:
+//
+// Status -
+//
+// --------
+
+{
+ NDIS_STATUS Status;
+ PNDIS_REQUEST Request;
+ ULONG OidIndex;
+ PUCHAR InformationBuffer = NULL;
+ ULONG InfoBufLength = 0;
+
+ //
+ // First allocate a request handle structure to hold the
+ // test information in.
+ //
+
+ TP_ASSERT( OpenP->RequestReqHndl == NULL );
+
+ Status = NdisAllocateMemory((PVOID *)&OpenP->RequestReqHndl,
+ sizeof( TP_REQUEST_HANDLE ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpFuncRequestSetInfo: unable to allocate Request Handle.\n");
+ }
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ if ( OpenP->Irp != NULL )
+ {
+ Irp->IoStatus.Status = NDIS_STATUS_RESOURCES;
+ }
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ return NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( OpenP->RequestReqHndl,sizeof( TP_REQUEST_HANDLE ));
+ }
+ OpenP->RequestReqHndl->Signature = FUNC_REQUEST_HANDLE_SIGNATURE;
+ OpenP->RequestReqHndl->Open = OpenP;
+ OpenP->RequestReqHndl->RequestPended = TRUE;
+ OpenP->RequestReqHndl->Irp = Irp;
+
+ OpenP->RequestReqHndl->u.INFO_REQ.IoControlCode =
+ IrpSp->Parameters.DeviceIoControl.IoControlCode;
+
+ //
+ // Now allocate the Ndis Request structure to hold the request
+ // information in.
+ //
+
+ Status = NdisAllocateMemory((PVOID *)&Request,
+ sizeof( NDIS_REQUEST ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpFuncRequestSetInfo: unable to allocate Request.\n");
+ }
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ if ( OpenP->Irp != NULL )
+ {
+ Irp->IoStatus.Status = NDIS_STATUS_RESOURCES;
+ }
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ return NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( Request,sizeof( NDIS_REQUEST ));
+ }
+
+ Request->RequestType = OpenP->RequestReqHndl->u.INFO_REQ.NdisRequestType
+ = NdisRequestSetInformation;
+
+ OidIndex = TpLookUpOidInfo( CmdArgs->ARGS.TPSET.OID );
+
+ if (( CmdArgs->ARGS.TPSET.OID == OID_802_3_MULTICAST_LIST ) ||
+ ( CmdArgs->ARGS.TPSET.OID == OID_FDDI_LONG_MULTICAST_LIST))
+ {
+ InfoBufLength = OidArray[OidIndex].Length * CmdArgs->ARGS.TPSET.NumberMultAddrs;
+ }
+ else
+ {
+ InfoBufLength = OidArray[OidIndex].Length;
+ }
+
+ //
+ // Now if the infobuffer is larger than zero bytes allocate it.
+ // With a multicast list size of zero we will just pass a null
+ // pointer.
+ //
+
+ if ( InfoBufLength > 0 )
+ {
+ Status = NdisAllocateMemory((PVOID *)&InformationBuffer,
+ InfoBufLength,
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpFuncRequestSetInfo: unable to allocate Information Buffer.\n");
+ }
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ if ( OpenP->Irp != NULL )
+ {
+ Irp->IoStatus.Status = NDIS_STATUS_RESOURCES;
+ }
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ return NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( InformationBuffer,InfoBufLength);
+ }
+ }
+
+ //
+ // Now set the generic setinfo information in both the Request
+ // Handle, and in the SET_INFO portion of the Request struct.
+ //
+
+ OpenP->RequestReqHndl->u.INFO_REQ.OID = CmdArgs->ARGS.TPSET.OID;
+ OpenP->RequestReqHndl->u.INFO_REQ.InformationBuffer = InformationBuffer;
+ OpenP->RequestReqHndl->u.INFO_REQ.InformationBufferLength = InfoBufLength;
+
+ Request->DATA.SET_INFORMATION.Oid = CmdArgs->ARGS.TPSET.OID;
+ Request->DATA.SET_INFORMATION.InformationBuffer = InformationBuffer;
+ Request->DATA.SET_INFORMATION.InformationBufferLength = InfoBufLength;
+
+ switch( CmdArgs->ARGS.TPSET.OID )
+ {
+ //
+ // and then add the OID specific information to the information
+ // section of the OVB for this request.
+ //
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ *((PULONG)InformationBuffer) = (ULONG)CmdArgs->ARGS.TPSET.U.PacketFilter;
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+ case OID_FDDI_LONG_MULTICAST_LIST:
+ //
+ // Initialize the multicast address string to pass to the request.
+ //
+
+ NdisMoveMemory( InformationBuffer,
+ CmdArgs->ARGS.TPSET.U.MulticastAddress,
+ ADDRESS_LENGTH * CmdArgs->ARGS.TPSET.NumberMultAddrs );
+ break;
+
+ case OID_802_5_CURRENT_FUNCTIONAL:
+ case OID_802_5_CURRENT_GROUP:
+ //
+ // This is only valid if Driver Type is 802.5, should it be
+ // allowed if we are not working with a token ring driver ????
+ //
+
+ NdisMoveMemory( InformationBuffer,
+ &CmdArgs->ARGS.TPSET.U.FunctionalAddress,
+ FUNCTIONAL_ADDRESS_LENGTH );
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ *((PULONG)InformationBuffer) = (ULONG)CmdArgs->ARGS.TPSET.U.LookaheadSize;
+ break;
+
+ default:
+ IF_TPDBG(TP_DEBUG_NDIS_CALLS)
+ {
+ TpPrint0("TpFuncRequestSetInfo: invalid OID to be passed to NdisRequest\n");
+ }
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ if ( OpenP->Irp != NULL )
+ {
+ Irp->IoStatus.Status = NDIS_STATUS_INVALID_OID;
+ }
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ return NDIS_STATUS_INVALID_OID;
+
+ } // switch
+
+
+ //
+ // Now that the Request is set, make the actual call.
+ //
+
+ NdisRequest( &Status,OpenP->NdisBindingHandle,Request );
+
+ if (( Status != NDIS_STATUS_SUCCESS ) &&
+ ( Status != NDIS_STATUS_PENDING ))
+ {
+ IF_TPDBG(TP_DEBUG_NDIS_ERROR)
+ {
+ TpPrint1("TpFuncRequestSetInfo: NdisRequest failed: returned %s\n",
+ TpGetStatus(Status));
+ }
+ }
+
+ if ( Status != NDIS_STATUS_PENDING )
+ {
+ //
+ // If the request did not pend, we should reset the pend flag,
+ // and the status flag in the OpenP->RequestReqHndl, and call the
+ // completion handler ourselves.
+ //
+
+ OpenP->RequestReqHndl->RequestPended = FALSE;
+ TpFuncRequestComplete( OpenP,Request,Status );
+ }
+ return NDIS_STATUS_PENDING;
+}
+
+
+
+VOID
+TpFuncRequestComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS Status
+ )
+{
+ POPEN_BLOCK OpenP = (POPEN_BLOCK)ProtocolBindingContext;
+ PREQUEST_RESULTS OutputBuffer;
+ ULONG NextEvent;
+
+ TP_ASSERT( OpenP != NULL );
+ TP_ASSERT( NdisRequest != NULL );
+ TP_ASSERT( Status != NDIS_STATUS_PENDING );
+
+ if (( OpenP->RequestReqHndl != NULL ) &&
+ (( OpenP->RequestReqHndl->Signature == FUNC_REQUEST_HANDLE_SIGNATURE ) &&
+ ( OpenP->RequestReqHndl->Open == OpenP )))
+ {
+ IF_TPDBG(TP_DEBUG_DISPATCH)
+ {
+ TpPrint2("TpFuncRequestComplete RequestType = %d, Status = %s\n",
+ NdisRequest->RequestType, TpGetStatus( Status));
+ }
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ if ( OpenP->Irp != NULL )
+ {
+ OutputBuffer = MmGetSystemAddressForMdl( OpenP->RequestReqHndl->Irp->MdlAddress );
+
+ OutputBuffer->Signature = REQUEST_RESULTS_SIGNATURE;
+ OutputBuffer->IoControlCode = OpenP->RequestReqHndl->u.INFO_REQ.IoControlCode;
+ OutputBuffer->RequestPended = OpenP->RequestReqHndl->RequestPended;
+ OutputBuffer->RequestStatus = Status;
+
+ TP_ASSERT( NdisRequest->RequestType ==
+ OpenP->RequestReqHndl->u.INFO_REQ.NdisRequestType );
+
+ OutputBuffer->NdisRequestType = NdisRequest->RequestType;
+
+ if ( NdisRequest->RequestType == NdisRequestQueryInformation )
+ {
+ TP_ASSERT( NdisRequest->DATA.QUERY_INFORMATION.Oid ==
+ OpenP->RequestReqHndl->u.INFO_REQ.OID );
+
+ TP_ASSERT( NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer ==
+ OpenP->RequestReqHndl->u.INFO_REQ.InformationBuffer );
+
+ OutputBuffer->OID = NdisRequest->DATA.QUERY_INFORMATION.Oid;
+
+ TP_ASSERT( NdisRequest->DATA.QUERY_INFORMATION.BytesWritten <=
+ OpenP->RequestReqHndl->u.INFO_REQ.InformationBufferLength );
+
+ if ( Status == NDIS_STATUS_SUCCESS )
+ {
+ //
+ // Then we must copy the information returned into the
+ // OutputBuffer.
+ //
+
+ OutputBuffer->InformationBufferLength =
+ OpenP->RequestReqHndl->u.INFO_REQ.InformationBufferLength;
+
+// TP_ASSERT( NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength <=
+// IOCTL_BUFFER_SIZE - sizeof( REQUEST_RESULTS ));
+
+ NdisMoveMemory( OutputBuffer->InformationBuffer,
+ (PUCHAR)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength );
+ }
+
+ OutputBuffer->BytesReadWritten = NdisRequest->DATA.QUERY_INFORMATION.BytesWritten;
+ OutputBuffer->BytesNeeded = NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded;
+ }
+ else if ( NdisRequest->RequestType == NdisRequestSetInformation )
+ {
+ OutputBuffer->OID = OpenP->RequestReqHndl->u.INFO_REQ.OID;
+
+ TP_ASSERT( NdisRequest->DATA.SET_INFORMATION.BytesRead <=
+ OpenP->RequestReqHndl->u.INFO_REQ.InformationBufferLength );
+
+ OutputBuffer->BytesReadWritten = NdisRequest->DATA.SET_INFORMATION.BytesRead;
+ OutputBuffer->BytesNeeded = NdisRequest->DATA.SET_INFORMATION.BytesNeeded;
+ }
+ else
+ {
+ TP_ASSERT( FALSE );
+ }
+
+ //
+ // Now set the return status to SUCCESS and complete the request.
+ //
+ OpenP->RequestReqHndl->Irp->IoStatus.Status = NDIS_STATUS_SUCCESS;
+
+ IoMarkIrpPending( OpenP->RequestReqHndl->Irp );
+
+ IoAcquireCancelSpinLock( &OpenP->RequestReqHndl->Irp->CancelIrql );
+ IoSetCancelRoutine( OpenP->RequestReqHndl->Irp,NULL );
+ IoReleaseCancelSpinLock( OpenP->RequestReqHndl->Irp->CancelIrql );
+
+ IoCompleteRequest( OpenP->RequestReqHndl->Irp,IO_NETWORK_INCREMENT );
+ }
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ //
+ // Finally free the request handle
+ //
+
+ if (( NdisRequest->RequestType == NdisRequestQueryInformation ) ||
+ ( NdisRequest->RequestType == NdisRequestQueryStatistics ))
+ {
+ NdisFreeMemory( NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer, 0,0 );
+ }
+ else if ( NdisRequest->RequestType == NdisRequestSetInformation )
+ {
+ if ( NdisRequest->DATA.SET_INFORMATION.InformationBufferLength > 0 )
+ {
+ NdisFreeMemory( NdisRequest->DATA.SET_INFORMATION.InformationBuffer, 0,0 );
+ }
+ }
+ else
+ {
+ TP_ASSERT( FALSE );
+ }
+
+ NdisFreeMemory( NdisRequest,0,0 );
+ NdisFreeMemory( OpenP->RequestReqHndl,0,0 );
+ OpenP->RequestReqHndl = NULL;
+
+ }
+ else if (( OpenP->OpenReqHndl != NULL ) &&
+ (( OpenP->OpenReqHndl->Open == OpenP ) &&
+ ( OpenP->OpenReqHndl->Signature == OPEN_REQUEST_HANDLE_SIGNATURE )))
+ {
+ KeSetEvent( &OpenP->OpenReqHndl->u.OPEN_REQ.OpenEvent,0,FALSE );
+ }
+ else
+ {
+ //
+ // We are not expecting any requests to complete at this
+ // point, so stick this on the Event Queue.
+ //
+
+ NdisAcquireSpinLock( &OpenP->EventQueue->SpinLock );
+
+ NextEvent = OpenP->EventQueue->Head + 1;
+
+ if ( NextEvent == MAX_EVENT )
+ {
+ NextEvent = 0;
+ }
+
+ if ( NextEvent != OpenP->EventQueue->Tail )
+ {
+ //
+ // There is room to add another event to the event queue.
+ //
+
+ OpenP->EventQueue->Events[NextEvent].TpEventType = CompleteRequest;
+ OpenP->EventQueue->Head = NextEvent;
+
+ // we should also stick some interesting info like requesttype.
+ }
+ else
+ {
+ //
+ // The event queue is full, and this would have overflowed it, so
+ // mark the Head event overflow flag to show this.
+ //
+
+ OpenP->EventQueue->Events[OpenP->EventQueue->Head].Overflow = TRUE;
+ }
+
+ NdisReleaseSpinLock( &OpenP->EventQueue->SpinLock );
+ }
+}
+
+
+
+NDIS_STATUS
+TpFuncSend(
+ IN POPEN_BLOCK OpenP
+ )
+
+// ----------
+//
+// Routine Description:
+//
+//
+// Arguments:
+//
+//
+// Return Value:
+//
+// Status -
+//
+// ---------
+
+{
+ //
+ // Increment the reference count on the OpenBlock stating that
+ // an async test is running and must be ended prior to closing
+ // the adapter on this open. Sending of only one packet although
+ // handled differently still will increment the ref count.
+ //
+
+ TpAddReference( OpenP );
+
+ NdisZeroMemory( (PVOID)OpenP->Send->Counters,
+ sizeof( INSTANCE_COUNTERS ) );
+
+ //
+ // Initialize the SEND control flags, and reset the packet sending
+ // control counters.
+ //
+
+ OpenP->Send->Sending = TRUE;
+ OpenP->Send->StopSending = FALSE;
+ OpenP->Send->PacketsSent = 0;
+ OpenP->Send->PacketsPending = 0;
+ OpenP->Send->SendEndDpcCount = 0;
+
+ if ( OpenP->Send->NumberOfPackets == 1 )
+ {
+ //
+ // We are only sending one packet so just call the send
+ // routine, don't queue it as a DPC.
+ //
+ TpFuncSendDpc( NULL,OpenP,NULL,NULL );
+ }
+ else
+ {
+ //
+ // We will be sending more than one packet, so queue TpFuncSendDpc
+ // and return Pending to the user, the DPC will send the packets,
+ // and after all the packets have been sent complete the request.
+ //
+
+ if ( !KeInsertQueueDpc( &OpenP->Send->SendDpc, NULL, NULL ))
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0("TpFuncSend failed to queue the TpFuncSendDpc.\n");
+ }
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ if ( OpenP->Send->SendIrp != NULL )
+ {
+ OpenP->Send->SendIrp->IoStatus.Status = NDIS_STATUS_FAILURE;
+ }
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ return NDIS_STATUS_FAILURE;
+ }
+ }
+ return NDIS_STATUS_PENDING;
+}
+
+
+
+VOID
+TpFuncInitializeSendArguments(
+ POPEN_BLOCK OpenP,
+ PCMD_ARGS CmdArgs
+ )
+
+// ------------
+//
+// Routine Description:
+//
+// This routine simply copies the arguments for Send into the Send
+// struct on the Open Block. The send routines may then reference
+// the arguments there after an asynchrnous call has returned.
+//
+// Arguments:
+//
+// OpenP - The open block represent this open instance, the location
+// where the arguments will be stored.
+//
+// CmdArgs - The arguments passed in from the app for this test run.
+//
+// Return Value:
+//
+// None - the Send arguments are copied to the Open Block.
+//
+// -------------
+
+{
+ PUCHAR p, q, s, t;
+ ULONG i;
+
+ OpenP->Send->NumberOfPackets = CmdArgs->ARGS.TPSEND.NumberOfPackets;
+
+ if ( CmdArgs->ARGS.TPSEND.PacketSize > OpenP->Media->MaxPacketLen )
+ {
+ OpenP->Send->PacketSize = OpenP->Media->MaxPacketLen;
+ IF_TPDBG ( TP_DEBUG_IOCTL_ARGS )
+ {
+ TpPrint1("TpFuncInitializeSendArguments: Invalid PacketSize; using %d\n",
+ OpenP->Send->PacketSize);
+ }
+ }
+ else
+ {
+ OpenP->Send->PacketSize = CmdArgs->ARGS.TPSEND.PacketSize;
+ }
+
+ p = OpenP->Send->DestAddress;
+ q = CmdArgs->ARGS.TPSEND.DestAddress;
+ s = OpenP->Send->ResendAddress;
+ t = CmdArgs->ARGS.TPSEND.ResendAddress;
+
+ //
+ // STARTCHANGE
+ //
+ for ( i=0;i<OpenP->Media->AddressLen;i++ )
+ {
+ *p++ = *q++;
+ *s++ = *t++;
+ }
+
+ if (OpenP->Send->PacketSize < (sizeof(FUNC2_PACKET) + 4))
+ {
+ OpenP->Send->ResendPackets = FALSE;
+ }
+
+ else if ( OpenP->Media->MediumType == NdisMediumArcnet878_2 )
+ {
+ //
+ // Since there is no concept of a NULL address we have no choice but
+ // to always use a resend address
+ // Addresses in arcnet range from 0x00 to 0xff where 0x00 is a broadcast
+ // address
+ //
+ OpenP->Send->ResendPackets = TRUE;
+ }
+
+ else
+ {
+ if ( RtlCompareMemory( OpenP->Send->ResendAddress,
+ NULL_ADDRESS,
+ OpenP->Media->AddressLen ) != OpenP->Media->AddressLen )
+ {
+ OpenP->Send->ResendPackets = TRUE;
+ }
+ else
+ {
+ OpenP->Send->ResendPackets = FALSE;
+ }
+ }
+ //
+ // STOPCHANGE
+ //
+}
+
+
+
+VOID
+TpFuncSendDpc(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SysArg1,
+ IN PVOID SysArg2
+ )
+
+// -------------
+//
+// Routine Description:
+//
+//
+// Arguments:
+//
+//
+// Return Value:
+//
+// Status -
+//
+// -----------
+
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)DeferredContext);
+ PTP_REQUEST_HANDLE RequestHandle;
+ NDIS_STATUS Status;
+ PNDIS_PACKET Packet;
+ LARGE_INTEGER DueTime;
+ PPROTOCOL_RESERVED ProtRes;
+
+ UNREFERENCED_PARAMETER( Dpc );
+ UNREFERENCED_PARAMETER( SysArg1 );
+ UNREFERENCED_PARAMETER( SysArg2 );
+
+ Status = NdisAllocateMemory((PVOID *)&RequestHandle,
+ sizeof( TP_REQUEST_HANDLE ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpFuncSendDpc: unable to allocate Request Handle.\n");
+ }
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ if ( OpenP->Send->SendIrp != NULL )
+ {
+ OpenP->Send->SendIrp->IoStatus.Status = NDIS_STATUS_RESOURCES;
+ }
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ TpFuncSendEndDpc( NULL,OpenP,NULL,NULL );
+ return;
+ }
+ else
+ {
+ NdisZeroMemory( RequestHandle,sizeof( TP_REQUEST_HANDLE ));
+ }
+
+ RequestHandle->Signature = SEND_REQUEST_HANDLE_SIGNATURE;
+ RequestHandle->Open = OpenP;
+ RequestHandle->RequestPended = TRUE;
+ RequestHandle->Irp = OpenP->Send->SendIrp;
+
+ Packet = TpFuncAllocateSendPacket( OpenP );
+
+ if ( Packet == NULL )
+ {
+ IF_TPDBG( TP_DEBUG_RESOURCES )
+ {
+ TpPrint0("TpFuncSendDpc: Unable to create a Send packet\n");
+ }
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ if ( OpenP->Send->SendIrp != NULL )
+ {
+ OpenP->Send->SendIrp->IoStatus.Status = NDIS_STATUS_RESOURCES;
+ }
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ TpFuncSendEndDpc( NULL,OpenP,NULL,NULL );
+ return;
+ }
+
+ RequestHandle->u.SEND_REQ.Packet = Packet;
+ RequestHandle->u.SEND_REQ.PacketSize = OpenP->Send->PacketSize;
+ RequestHandle->u.SEND_REQ.SendPacket = TRUE;
+
+ ProtRes = PROT_RES( Packet );
+ ProtRes->RequestHandle = RequestHandle;
+
+ //
+ // Set the check sum in the PROTOCOL RESERVED Section of the
+ // packet header to ensure it is not touched while the packet
+ // is in the hands of the MAC.
+ //
+
+ ProtRes->CheckSum = TpSetCheckSum( (PUCHAR)ProtRes,
+ sizeof( PROTOCOL_RESERVED ) - sizeof( ULONG ) );
+ ++OpenP->Send->PacketsPending;
+ ++OpenP->Send->Counters->Sends;
+
+ NdisSend( &Status,OpenP->NdisBindingHandle,Packet );
+
+ if ( Status != NDIS_STATUS_PENDING )
+ {
+ --OpenP->Send->PacketsPending;
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ //
+ // If we are running on TokenRing the following to "failures"
+ // are not considered failures NDIS_STATUS_NOT_RECOGNIZED -
+ // no one on the ring recognized the address as theirs, or
+ // NDIS_STATUS_NOT_COPIED - no one on the ring copied the
+ // packet, so we need to special case this and not count
+ // these as failures.
+ //
+ // SanjeevK : Even FDDI returns the same errors as 802.5
+ //
+ // STARTCHANGE
+ //
+ if ( ( NdisMediumArray[OpenP->MediumIndex] == NdisMedium802_5 ) ||
+ ( NdisMediumArray[OpenP->MediumIndex] == NdisMediumFddi ) ||
+ ( NdisMediumArray[OpenP->MediumIndex] == NdisMediumArcnet878_2) )
+ {
+ if (( Status != NDIS_STATUS_NOT_RECOGNIZED ) &&
+ ( Status != NDIS_STATUS_NOT_COPIED ))
+ {
+ ++OpenP->Send->Counters->SendFails;
+ }
+ }
+ else
+ {
+ ++OpenP->Send->Counters->SendFails;
+ TpPrint1("Send failed: status = %s", TpGetStatus(Status));
+ }
+
+ //
+ // STOPCHANGE
+ //
+ }
+
+ RequestHandle->RequestPended = FALSE;
+
+ TpFuncSendComplete( OpenP,Packet,Status );
+ }
+ else
+ {
+ ++OpenP->Send->Counters->SendPends;
+ }
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ if ((( OpenP->Send->SendIrp != NULL ) &&
+ ( OpenP->Send->SendIrp->Cancel == FALSE )) &&
+ (( ++OpenP->Send->PacketsSent < OpenP->Send->NumberOfPackets ) &&
+ ( OpenP->Send->StopSending == FALSE )))
+ {
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ DueTime.HighPart = -1; // So it will be relative.
+ DueTime.LowPart = (ULONG)(-4 * (ONE_HUNDREDTH_SECOND));
+
+ if ( KeSetTimer(&OpenP->Send->SendTimer,
+ DueTime,
+ &OpenP->Send->SendDpc ))
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0("TpFuncSendDpc set SendTimer while timer existed.\n");
+ }
+ }
+ }
+ else
+ {
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ DueTime.HighPart = 0xFFFFFFFF; // So it will be relative.
+ DueTime.LowPart = (ULONG)(-(ONE_SECOND));
+
+ if ( KeSetTimer(&OpenP->Send->SendTimer,
+ DueTime,
+ &OpenP->Send->SendEndDpc ))
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0("TpFuncSendDpc set SendTimer while timer existed(2).\n");
+ }
+ }
+ }
+}
+
+
+
+VOID
+TpFuncSendEndDpc(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SysArg1,
+ IN PVOID SysArg2
+ )
+
+// -------------
+//
+// Routine Description:
+//
+//
+// Arguments:
+//
+//
+// Return Value:
+//
+// ------------
+
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)DeferredContext);
+ LARGE_INTEGER DueTime;
+
+ UNREFERENCED_PARAMETER( Dpc );
+ UNREFERENCED_PARAMETER( SysArg1 );
+ UNREFERENCED_PARAMETER( SysArg2 );
+
+ //
+ // See if we have any outstanding packets left to complete. If we do,
+ // then we will reset the time to queue this dpc routine again in one
+ // second, if after ten requeue the packet has still no completed we
+ // assume it will never complete and return the results and finish.
+ //
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ if ((( OpenP->Send->SendIrp != NULL ) &&
+ ( OpenP->Send->SendIrp->Cancel == FALSE )) &&
+ (( OpenP->Send->PacketsPending != 0 ) &&
+ ( OpenP->Send->SendEndDpcCount++ < 10 )))
+ {
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ DueTime.HighPart = -1; // So it will be relative.
+ DueTime.LowPart = (ULONG)(-(ONE_SECOND));
+
+ if ( KeSetTimer(&OpenP->Send->SendTimer,
+ DueTime,
+ &OpenP->Send->SendEndDpc ))
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0("TpFuncSendEndDpc set SendTimer while timer existed.\n");
+ }
+ }
+ return;
+ }
+
+ //
+ // Write the statistics to the send results outputbuffer.
+ //
+
+ if (( OpenP->Send->SendIrp != NULL ) &&
+ ( OpenP->Send->SendIrp->Cancel == FALSE ))
+ {
+ TpWriteSendReceiveResults( OpenP->Send->Counters,
+ OpenP->Send->SendIrp );
+ }
+
+ //
+ // and if the IoStatus.Status has not been set, then set it.
+ //
+
+ if ( (OpenP->Send->SendIrp != NULL) &&
+ (OpenP->Send->SendIrp->IoStatus.Status == NDIS_STATUS_PENDING ))
+ {
+ OpenP->Send->SendIrp->IoStatus.Status = NDIS_STATUS_SUCCESS;
+ }
+
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ //
+ // Now set the sending flag to indicate that we are no longer
+ // SENDing packets.
+ //
+
+ OpenP->Send->Sending = FALSE;
+
+ //
+ // and decrement the reference count on the OpenBlock stating this
+ // instance of an async test is no longer running, and the adapter
+ // may be closed if requested.
+ //
+
+
+ if (OpenP->Send->SendIrp != NULL)
+ {
+ TpRemoveReference( OpenP );
+ IoMarkIrpPending( OpenP->Send->SendIrp );
+
+ IoAcquireCancelSpinLock( &OpenP->Send->SendIrp->CancelIrql );
+ IoSetCancelRoutine( OpenP->Send->SendIrp,NULL );
+ IoReleaseCancelSpinLock( OpenP->Send->SendIrp->CancelIrql );
+
+ IoCompleteRequest( OpenP->Send->SendIrp,IO_NETWORK_INCREMENT );
+
+ OpenP->Send->SendIrp = NULL;
+ }
+}
+
+
+
+VOID
+TpFuncSendComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ )
+
+// ---------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// --------
+
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)ProtocolBindingContext);
+ PPROTOCOL_RESERVED ProtRes;
+ PTP_REQUEST_HANDLE SendReqHndl;
+ PNDIS_BUFFER Buffer;
+ ULONG NextEvent;
+
+ TP_ASSERT( Packet != NULL );
+
+ //
+ // Zero out the private section reserved for the MAC out of the NDIS packet
+ //
+ RtlZeroMemory( (PVOID)Packet->MacReserved, sizeof( Packet->MacReserved ) );
+
+ ProtRes = PROT_RES( Packet );
+ SendReqHndl = ProtRes->RequestHandle;
+
+ TP_ASSERT( Packet == SendReqHndl->u.SEND_REQ.Packet );
+
+ //
+ // Where did this packet originate from ?
+ //
+
+ if (( SendReqHndl->Signature == SEND_REQUEST_HANDLE_SIGNATURE ) &&
+ ( SendReqHndl->u.SEND_REQ.SendPacket == TRUE ))
+ {
+ //
+ // If the packet was sent by the SEND command, then decrement the
+ // counter tracking the number of outstanding functional packets,
+ // and if the send succeeded increment the completion counter.
+ //
+
+ if ( SendReqHndl->RequestPended )
+ {
+ --OpenP->Send->PacketsPending;
+
+ ++OpenP->Send->Counters->SendComps;
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ //
+ // If we are running on TokenRing the following to "failures"
+ // are not considered failures NDIS_STATUS_NOT_RECOGNIZED -
+ // no one on the ring recognized the address as theirs, or
+ // NDIS_STATUS_NOT_COPIED - no one on the ring copied the
+ // packet, so we need to special case this and not count
+ // these as failures.
+ //
+ // SanjeevK : Even FDDI returns the same errors as 802.5
+ //
+ // STARTCHANGE
+ //
+ if ( ( NdisMediumArray[OpenP->MediumIndex] == NdisMedium802_5 ) ||
+ ( NdisMediumArray[OpenP->MediumIndex] == NdisMediumFddi ) ||
+ ( NdisMediumArray[OpenP->MediumIndex] == NdisMediumArcnet878_2) )
+ {
+ if (( Status != NDIS_STATUS_NOT_RECOGNIZED ) &&
+ ( Status != NDIS_STATUS_NOT_COPIED ))
+ {
+ ++OpenP->Send->Counters->SendFails;
+ }
+ }
+ else
+ {
+ ++OpenP->Send->Counters->SendFails;
+ TpPrint1("Send failed: status = %s", TpGetStatus(Status));
+ }
+ }
+ }
+
+ //
+ // also check that the PROTOCOL_RESERVED section of the packet
+ // header was not touched.
+ //
+
+ if ( !TpCheckSum( (PUCHAR)ProtRes,
+ sizeof( PROTOCOL_RESERVED ) - sizeof( ULONG ),
+ &ProtRes->CheckSum ))
+ {
+ ++OpenP->Send->Counters->SendFails;
+ TP_ASSERT( FALSE );
+ }
+
+ //
+ // then break the packet down and release its memory.
+ //
+
+ TpFuncFreePacket( SendReqHndl->u.SEND_REQ.Packet,SendReqHndl->u.SEND_REQ.PacketSize );
+
+ NdisFreeMemory( SendReqHndl,0,0 );
+
+ }
+ else if (( SendReqHndl->Signature == SEND_REQUEST_HANDLE_SIGNATURE ) &&
+ ( SendReqHndl->u.SEND_REQ.SendPacket == FALSE ))
+ {
+ //
+ // This packet was sent by an invocation of the RECEIVE command from
+ // TpFuncReceive when a RESEND packet was received.
+ //
+
+ if ( SendReqHndl->RequestPended )
+ {
+ --OpenP->Receive->PacketsPending;
+
+ ++OpenP->Receive->Counters->SendComps;
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ //
+ // If we are running on TokenRing the following to "failures"
+ // are not considered failures NDIS_STATUS_NOT_RECOGNIZED -
+ // no one on the ring recognized the address as theirs, or
+ // NDIS_STATUS_NOT_COPIED - no one on the ring copied the
+ // packet, so we need to special case this and not count
+ // these as failures.
+ //
+ // SanjeevK : Even FDDI returns the same errors as 802.5
+ //
+ // STARTCHANGE
+ //
+
+ if ( ( NdisMediumArray[OpenP->MediumIndex] == NdisMedium802_5 ) ||
+ ( NdisMediumArray[OpenP->MediumIndex] == NdisMediumFddi ) ||
+ ( NdisMediumArray[OpenP->MediumIndex] == NdisMediumArcnet878_2) )
+ {
+ if (( Status != NDIS_STATUS_NOT_RECOGNIZED ) &&
+ ( Status != NDIS_STATUS_NOT_COPIED ))
+ {
+ ++OpenP->Send->Counters->SendFails;
+ }
+ }
+ else
+ {
+ ++OpenP->Send->Counters->SendFails;
+ }
+ }
+ }
+
+ //
+ // also check that the PROTOCOL_RESERVED section of the packet
+ // header was not touched.
+ //
+
+ if ( !TpCheckSum( (PUCHAR)ProtRes,
+ sizeof( PROTOCOL_RESERVED ) - sizeof( ULONG ),
+ &ProtRes->CheckSum ))
+ {
+ ++OpenP->Send->Counters->SendFails;
+ TP_ASSERT( FALSE );
+ }
+
+ //
+ // then break the packet down and release its memory.
+ //
+
+ NdisUnchainBufferAtFront( Packet,&Buffer );
+ NdisFreeMemory( MmGetMdlVirtualAddress( Buffer ),0,0 );
+ TpFreeBuffer( Buffer );
+ NdisFreePacket( Packet );
+ NdisFreeMemory( SendReqHndl,0,0 );
+
+ }
+ else if ( SendReqHndl->Signature == GO_REQUEST_HANDLE_SIGNATURE )
+ {
+ //
+ // check that the PROTOCOL_RESERVED section of the packet
+ // header was not touched.
+ //
+
+ // This is just a go packet, check that the PROTOCOL_RESERVED
+ // section of the packet header was not touched, then break
+ // the packet down and release its memory.
+ //
+
+ if ( !TpCheckSum( (PUCHAR)ProtRes,
+ sizeof( PROTOCOL_RESERVED ) - sizeof( ULONG ),
+ &ProtRes->CheckSum ))
+ {
+ TP_ASSERT( FALSE );
+ }
+
+ NdisUnchainBufferAtFront( Packet,&Buffer );
+ NdisFreeMemory( MmGetMdlVirtualAddress( Buffer ),0,0 );
+ TpFreeBuffer( Buffer );
+ NdisFreePacket( Packet );
+ NdisFreeMemory( SendReqHndl,0,0 );
+
+ }
+ else
+ {
+ //
+ // An unexpected call to the send completion routine has been made.
+ // Since we are not expecting it, stick the information on the
+ // Event Queue.
+ //
+
+ NdisAcquireSpinLock( &OpenP->EventQueue->SpinLock );
+
+ NextEvent = OpenP->EventQueue->Head + 1;
+
+ if ( NextEvent == MAX_EVENT )
+ {
+ NextEvent = 0;
+ }
+
+ if ( NextEvent != OpenP->EventQueue->Tail )
+ {
+ //
+ // There is room to add another event to the event queue.
+ //
+
+ OpenP->EventQueue->Events[NextEvent].TpEventType = CompleteSend;
+ OpenP->EventQueue->Head = NextEvent;
+ }
+ else
+ {
+ //
+ // The event queue is full, and this would overflow it.
+ //
+
+ OpenP->EventQueue->Events[OpenP->EventQueue->Head].Overflow = TRUE;
+ }
+
+ NdisReleaseSpinLock( &OpenP->EventQueue->SpinLock );
+ }
+
+}
+
+
+
+NDIS_STATUS
+TpFuncInitializeReceive(
+ IN POPEN_BLOCK OpenP
+ )
+
+// ---------
+//
+// Routine Description:
+//
+//
+// Arguments:
+//
+//
+// Return Value:
+//
+// Status -
+//
+// -------
+
+{
+ LARGE_INTEGER DueTime;
+
+ NdisZeroMemory( (PVOID)OpenP->Receive->Counters,
+ sizeof( INSTANCE_COUNTERS ) );
+
+ //
+ // Initialize the RECEIVE control flags, and reset the packet
+ // sending control counters.
+ //
+
+ OpenP->Receive->Receiving = TRUE;
+ OpenP->Receive->StopReceiving = FALSE;
+ OpenP->Receive->PacketsPending = 0;
+ OpenP->Receive->ReceiveEndDpcCount = 0;
+
+ //
+ // The zero out the receive counters.
+ //
+
+ NdisZeroMemory( (PVOID)OpenP->Receive->Counters,
+ sizeof( INSTANCE_COUNTERS ) );
+
+ //
+ // Initialize the DPCs used to call ReceiveDpc and ReceiveEndDpc.
+ //
+
+ KeInitializeDpc(&OpenP->Receive->ReceiveDpc,
+ TpFuncReceiveDpc,
+ (PVOID)OpenP );
+
+ KeInitializeDpc(&OpenP->Receive->ReceiveEndDpc,
+ TpFuncReceiveEndDpc,
+ (PVOID)OpenP );
+
+ //
+ // And finally set the timer for the ReceiveDpc to queue the
+ // routine later.
+ //
+
+ DueTime.HighPart = 0xFFFFFFFF; // So it will be relative.
+ DueTime.LowPart = (ULONG)(-(ONE_SECOND));
+
+ if ( KeSetTimer(&OpenP->Receive->ReceiveTimer,
+ DueTime,
+ &OpenP->Receive->ReceiveDpc ))
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0("TpFuncReceiveDpc set Receive timer while timer existed.\n");
+ }
+ }
+
+ //
+ // Increment the reference count on the OpenBlock stating that
+ // an async test is running and must be ended prior to closing
+ // the adapter on this open.
+ //
+
+ TpAddReference( OpenP );
+
+ return NDIS_STATUS_PENDING;
+}
+
+
+
+NDIS_STATUS
+TpFuncReceive(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+// -------------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// -----------
+
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)ProtocolBindingContext);
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PPACKET_INFO PacketInfo;
+ PTP_REQUEST_HANDLE RequestHandle;
+ PGO_PACKET_INFO GoPacketInfo;
+ PUCHAR Memory;
+ PUCHAR SrcAddr;
+ PNDIS_PACKET Packet;
+ PNDIS_BUFFER Buffer;
+ PPROTOCOL_RESERVED ProtRes;
+ UINT BytesTransferred;
+ UINT HeaderVariance = sizeof(MEDIA_HEADER)-HeaderBufferSize;
+ ULONG DataSize;
+ ULONG NextEvent;
+ ULONG i;
+
+ //
+ // The LookAhead Buffer has been adjusted to point to the beggining of the
+ // PACKET_INFO structure
+ //
+ PacketInfo = (PPACKET_INFO)LookaheadBuffer;
+
+ //
+ // Are we expecting to receive a packet at this time, and is this
+ // packet large enough to be a functional send packet, and is the
+ // signature in the packet header correct?
+ //
+
+ if ((( OpenP->Receive->Receiving == TRUE ) &&
+ ( PacketSize >= sizeof( PACKET_INFO ))) &&
+ (( PacketInfo->Signature == FUNC1_PACKET_SIGNATURE ) ||
+ ( PacketInfo->Signature == FUNC2_PACKET_SIGNATURE )))
+ {
+ if ( OpenP->Receive->StopReceiving == TRUE )
+ {
+ //
+ // The receive test is shutting down, so just count the packet.
+ //
+
+ ++OpenP->Receive->Counters->Receives;
+
+ if ( !TpCheckSum( (PUCHAR)PacketInfo,
+ sizeof( PACKET_INFO ) - sizeof( ULONG ),
+ (PULONG)&PacketInfo->CheckSum ))
+ {
+ ++OpenP->Receive->Counters->CorruptRecs;
+ }
+ }
+ else
+ {
+ //
+ // We are in the normal receiving mode, and have a good
+ // packet, so we will handle it as requested.
+ //
+
+ ++OpenP->Receive->Counters->Receives;
+
+ if ( !TpCheckSum( (PUCHAR)PacketInfo,
+ sizeof( PACKET_INFO ) - sizeof( ULONG ),
+ (PULONG)&PacketInfo->CheckSum ))
+ {
+ ++OpenP->Receive->Counters->CorruptRecs;
+ return NDIS_STATUS_NOT_RECOGNIZED;
+ }
+
+ //
+ // Is there any thing in the packet other than the header??
+ //
+
+ //
+ // STARTCHANGE
+ // Please note that this packet size is NOT the PacketSize which
+ // we receive in the TestProtocolReceive but is
+ //
+ // PacketSize we get with IndicateReceive + the size of the header
+ // = TRUE PACKET SIZE
+ //
+ DataSize = ((PPACKET_INFO)LookaheadBuffer)->PacketSize -
+ ( sizeof( PACKET_INFO ) + sizeof( MEDIA_HEADER ) );
+ //
+ // STOPCHANGE
+ //
+
+ if ( DataSize > 0 )
+ {
+ SrcAddr = (PUCHAR)HeaderBuffer + (ULONG)OpenP->Media->SrcAddrOffset;
+ OpenP->Receive->ResendType =
+ ( RtlCompareMemory(SrcAddr,
+ OpenP->StationAddress,
+ OpenP->Media->AddressLen) == OpenP->Media->AddressLen);
+
+ //
+ // Allocate the request handle and set it up as if the request
+ // pended. If it does not pend we will reset the flags later before
+ // calling the completion routine.
+ //
+
+ Status = NdisAllocateMemory((PVOID *)&RequestHandle,
+ sizeof( TP_REQUEST_HANDLE ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG( TP_DEBUG_RESOURCES )
+ {
+ TpPrint0("TpFuncReceive: unable to allocated request handle.\n");
+ }
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ if (OpenP->Receive->ReceiveIrp != NULL )
+ {
+ OpenP->Receive->ReceiveIrp->IoStatus.Status = NDIS_STATUS_RESOURCES;
+ }
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ return NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( RequestHandle,sizeof( TP_REQUEST_HANDLE ));
+ }
+
+ RequestHandle->Signature = FUNC_REQUEST_HANDLE_SIGNATURE;
+ RequestHandle->Open = OpenP;
+ RequestHandle->RequestPended = TRUE;
+ RequestHandle->u.TRANS_REQ.DataSize = DataSize;
+
+ //
+ // Now allocate the memory to copy the packet data into.
+ //
+
+ Status = NdisAllocateMemory((PVOID *)&Memory,
+ DataSize,
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG(TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpFuncReceive: unable to allocate resend buffer memory.\n");
+ }
+ NdisFreeMemory( RequestHandle,0,0 );
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ if (OpenP->Receive->ReceiveIrp != NULL )
+ {
+ OpenP->Receive->ReceiveIrp->IoStatus.Status = NDIS_STATUS_RESOURCES;
+ }
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ return NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( Memory,DataSize );
+ }
+
+ //
+ // Then allocate the buffer that will reference the memory,
+ //
+
+ Buffer = IoAllocateMdl( Memory,
+ DataSize,
+ TRUE,
+ FALSE,
+ NULL );
+
+ if ( Buffer == NULL )
+ {
+ IF_TPDBG(TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpFuncReceive: unable to allocate resend mdl buffer\n");
+ }
+ NdisFreeMemory( Memory,0,0 );
+ NdisFreeMemory( RequestHandle,0,0 );
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ if (OpenP->Receive->ReceiveIrp != NULL )
+ {
+ OpenP->Receive->ReceiveIrp->IoStatus.Status = NDIS_STATUS_RESOURCES;
+ }
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ MmBuildMdlForNonPagedPool( (PMDL)Buffer );
+
+ //
+ // and finally the NDIS_PACKET to pass to the NdisTransferData call.
+ //
+
+ NdisAllocatePacket( &Status,
+ &Packet,
+ OpenP->Receive->PacketHandle );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG(TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpFuncReceive: unable to allocate resend packet\n");
+ }
+ IoFreeMdl( Buffer );
+ NdisFreeMemory( Memory,0,0 );
+ NdisFreeMemory( RequestHandle,0,0 );
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+ if (OpenP->Receive->ReceiveIrp != NULL )
+ {
+ OpenP->Receive->ReceiveIrp->IoStatus.Status = Status;
+ }
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ return Status;
+ }
+ else
+ {
+ //
+ // Setup the protocol reserved portion of the packet so the
+ // completion routines know what and where to deallocate.
+ //
+
+ ProtRes = PROT_RES( Packet );
+ ProtRes->Pool.PacketHandle = OpenP->Receive->PacketHandle;
+ ProtRes->InstanceCounters = OpenP->Receive->Counters;
+ ProtRes->RequestHandle = RequestHandle;
+
+ ProtRes->CheckSum =
+ TpSetCheckSum( (PUCHAR)ProtRes,
+ sizeof( PROTOCOL_RESERVED ) - sizeof( ULONG ) );
+
+ //
+ // reference the packet in the request handle.
+ //
+
+ RequestHandle->u.TRANS_REQ.Packet = Packet;
+ }
+
+ //
+ // Now chain the buffer to the packet.
+ //
+
+ NdisChainBufferAtFront( Packet,Buffer );
+
+ //
+ // And transfer the data into the newly created packet.
+ //
+
+ ++OpenP->Receive->Counters->XferData;
+
+ //
+ // STARTCHANGE
+ //
+ NdisTransferData( &Status,
+ OpenP->NdisBindingHandle,
+ MacReceiveContext,
+ (sizeof(PACKET_INFO)+HeaderVariance),
+ DataSize,
+ Packet,
+ &BytesTransferred );
+ //
+ // STOPCHANGE
+ //
+
+ if ( Status == NDIS_STATUS_PENDING )
+ {
+ //
+ // The deallocation of resources and any resending will
+ // be handled by the completion routine, so just count
+ // the transfer pending and split.
+ //
+ ++OpenP->Receive->Counters->XferDataPends;
+ }
+ else
+ {
+ //
+ // If the request did not pend, we should reset the
+ // pend flag, and the status flag in the RequestHandle,
+ // and then call the completion handler ourselves.
+ //
+
+ RequestHandle->RequestPended = FALSE;
+
+ TpFuncTransferDataComplete( OpenP,
+ Packet,
+ Status,
+ BytesTransferred );
+ }
+ }
+ else
+ {
+ TpPrint2("Full packetsize = %d, true packetsize = %d\n",
+ ((PPACKET_INFO)LookaheadBuffer)->PacketSize, DataSize);
+ TpBreakPoint();
+ }
+ }
+ }
+ else if (( PacketSize >= sizeof( GO_PACKET_INFO )) &&
+ ( PacketInfo->Signature == GO_PACKET_SIGNATURE ))
+ {
+ GoPacketInfo = (PGO_PACKET_INFO)LookaheadBuffer;
+ SrcAddr = (PUCHAR)HeaderBuffer + (ULONG)OpenP->Media->SrcAddrOffset;
+
+ if ( !TpCheckSum( (PUCHAR)GoPacketInfo,
+ sizeof( GO_PACKET_INFO ) - sizeof( ULONG ),
+ (PULONG)&GoPacketInfo->CheckSum ))
+ {
+ Status = NDIS_STATUS_NOT_RECOGNIZED;
+ }
+ else
+ {
+ NdisAcquireSpinLock( &OpenP->Pause->SpinLock );
+
+ if ((( OpenP->Pause->GoReceived == TRUE ) ||
+
+ //
+ // We have not finished processing the last GO packet,
+ // and a new one has arrived. We can't accept it until
+ // the last GO has been handled. We will ignore this
+ // packet.
+ //
+
+ ((( GoPacketInfo->PacketType == TP_GO ) &&
+ ( GoPacketInfo->TestSignature == OpenP->Pause->TestSignature )) &&
+ ( GoPacketInfo->UniqueSignature == OpenP->Pause->UniqueSignature ))) ||
+
+ //
+ // Or we have finished handling the last GO packet, and
+ // received another one for the same PAUSE before the
+ // GO sender received and handled the GO_ACK packet.
+ // We will ignore this packet also.
+ //
+
+ ( RtlCompareMemory( SrcAddr,
+ OpenP->StationAddress,
+ OpenP->Media->AddressLen) == OpenP->Media->AddressLen ))
+ {
+
+ //
+ // Or this packet was sent by us, not another protocol
+ // on another machine, must have the packet filter set
+ // to promiscuous mode, ignore this packet also.
+ //
+
+ NdisReleaseSpinLock( &OpenP->Pause->SpinLock );
+ }
+ else
+ {
+ OpenP->Pause->GoReceived = TRUE;
+
+ switch ( OpenP->Media->MediumType )
+ {
+ case NdisMediumArcnet878_2:
+ case NdisMediumFddi :
+ case NdisMediumDix :
+ case NdisMedium802_3 :
+ case NdisMedium802_5 :
+ for ( i=0 ; i < OpenP->Media->AddressLen; i++ )
+ {
+ OpenP->Pause->RemoteAddress[i] = (CHAR)&SrcAddr[i];
+ }
+ break;
+
+ default:
+ IF_TPDBG ( TP_DEBUG_RESOURCES )
+ {
+ TpPrint0("TpFuncReceive: Unsupported MAC Media Type\n");
+ }
+ }
+
+ OpenP->Pause->TestSignature = GoPacketInfo->TestSignature;
+ OpenP->Pause->UniqueSignature = GoPacketInfo->UniqueSignature;
+ OpenP->Pause->PacketType = GoPacketInfo->PacketType;
+
+ NdisReleaseSpinLock( &OpenP->Pause->SpinLock );
+ }
+ }
+ }
+ else
+ {
+// TEMP -- Find out WHY we got here...
+
+// this one is valid--can get it during abort of performance test
+// if ( OpenP->Receive->Receiving != TRUE )
+// {
+// TpPrint0("Rcv--receiving == FALSE\n");
+// }
+
+ if ( PacketSize >= sizeof( PACKET_INFO ))
+ {
+ TpPrint1("Rcv--Psize >= PACKET_INFO, signature = %x\n", PacketInfo->Signature);
+ }
+ else if ( PacketSize >= sizeof( GO_PACKET_INFO ))
+ {
+ TpPrint1("Rcv--Psize >= GO_PACKET_INFO, signature = %x\n", PacketInfo->Signature);
+ }
+ else
+ {
+ TpPrint0("Rcv--Psize < GO_PACKET_INFO\n");
+ }
+// TpBreakPoint();
+
+//
+ //
+ // We are not expecting to receive packets, or this packet is not
+ // large enough to be a functional packet, or we are not expecting
+ // to receive this packet. so stick it on the Event Queue.
+ //
+
+ NdisAcquireSpinLock( &OpenP->EventQueue->SpinLock );
+
+ NextEvent = OpenP->EventQueue->Head + 1;
+
+ if ( NextEvent == MAX_EVENT )
+ {
+ NextEvent = 0;
+ }
+
+ if ( NextEvent != OpenP->EventQueue->Tail )
+ {
+ //
+ // There is room to add another event to the event queue.
+ //
+
+ OpenP->EventQueue->Events[NextEvent].TpEventType = IndicateReceive;
+ OpenP->EventQueue->Head = NextEvent;
+
+ //
+ // XXX: At this point we could stick the first X bytes (header)
+ // into the Events[head].EventInfo using xferdata.
+ //
+
+ }
+ else
+ {
+ //
+ // The event queue is full, and this would have overflowed it, so
+ // mark the Head event overflow flag to show this.
+ //
+
+ OpenP->EventQueue->Events[OpenP->EventQueue->Head].Overflow = TRUE;
+ }
+
+ ++OpenP->EventQueue->ReceiveIndicationCount;
+ OpenP->EventQueue->ExpectReceiveComplete = TRUE;
+
+ NdisReleaseSpinLock( &OpenP->EventQueue->SpinLock );
+
+ Status = NDIS_STATUS_NOT_RECOGNIZED;
+
+ }
+
+ return Status;
+}
+
+
+
+VOID
+TpFuncReceiveComplete(
+ IN NDIS_HANDLE ProtocolBindingContext
+ )
+
+// -------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// -----
+
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)ProtocolBindingContext);
+
+ if ( OpenP->Receive->Receiving == TRUE )
+ {
+ ++OpenP->Receive->Counters->ReceiveComps;
+ }
+ else
+ {
+ //
+ // We are not expecting this completion, so stick the
+ // info on the event queue.
+ //
+
+ NdisAcquireSpinLock( &OpenP->EventQueue->SpinLock );
+
+ //****************************************************************
+ //
+ // NOTE: Due to the fact that a MAC will complete all receive
+ // indications to EVERY transport that has it opened this
+ // completion is not entirely unexpected, and therefore will
+ // not be added to the Event Queue.
+ //
+ //****************************************************************
+
+#if 0
+ //
+ // We have received an unexpected Status Indication, so
+ // we are expecting (???) to receive the completion.
+ //
+
+ NextEvent = OpenP->EventQueue->Head + 1;
+
+ if ( NextEvent == MAX_EVENT )
+ {
+ NextEvent = 0;
+ }
+
+ if ( NextEvent != OpenP->EventQueue->Tail )
+ {
+ //
+ // There is room to add another event to the event queue.
+ //
+
+ OpenP->EventQueue->Events[NextEvent].TpEventType = IndicateReceiveComplete;
+ OpenP->EventQueue->Head = NextEvent;
+
+ // XXX: Was it expected ???
+ }
+ else
+ {
+ //
+ // The event queue is full, and this would overflow it.
+ //
+ OpenP->EventQueue->Events[OpenP->EventQueue->Head].Overflow = TRUE;
+ }
+#endif
+
+ //
+ // Reset the status indication counter to zero, and set the
+ // status completion expected flag to show that no completion
+ // routine is expected.
+ //
+
+ OpenP->EventQueue->ReceiveIndicationCount = 0;
+ OpenP->EventQueue->ExpectReceiveComplete = FALSE;
+
+ NdisReleaseSpinLock( &OpenP->EventQueue->SpinLock );
+ }
+}
+
+
+
+VOID
+TpFuncTransferDataComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ )
+
+// ----------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+// ---------
+
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)ProtocolBindingContext);
+ PNDIS_BUFFER Buffer;
+ PPROTOCOL_RESERVED ProtRes;
+ PTP_REQUEST_HANDLE XferReqHndl;
+ PTP_REQUEST_HANDLE SendReqHndl;
+ PTP_PACKET TpPacket;
+ PUCHAR BufMem;
+// NDIS_STATUS SendStatus;
+ ULONG NextEvent;
+ ULONG i;
+ LARGE_INTEGER DueTime;
+
+
+ TP_ASSERT( Packet != NULL );
+
+ ProtRes = PROT_RES( Packet );
+ XferReqHndl = ProtRes->RequestHandle;
+
+ TP_ASSERT( Status == NDIS_STATUS_SUCCESS );
+ TP_ASSERT( Packet == XferReqHndl->u.TRANS_REQ.Packet );
+
+ //
+ // Are we expecting to complete a Transfer Data at this time?
+ // First determine if we are running a RECEIVE test. If so,
+ // determine whether this is a legitimate completion, or a
+ // bug.
+ //
+
+ TP_ASSERT( OpenP != NULL );
+
+ if (( OpenP->Receive->StopReceiving == FALSE ) &&
+ (( XferReqHndl->Signature == FUNC_REQUEST_HANDLE_SIGNATURE ) &&
+ ( XferReqHndl->Open == (POPEN_BLOCK)ProtocolBindingContext )))
+ {
+ //
+ // If so then verfiy the PROTOCOL RESERVED section of the
+ // packet was not touched.
+ //
+
+ if ( !TpCheckSum( (PUCHAR)ProtRes,
+ sizeof( PROTOCOL_RESERVED ) - sizeof( ULONG ),
+ &ProtRes->CheckSum ))
+ {
+ ++OpenP->Receive->Counters->XferDataFails;
+ return;
+ }
+
+ //
+ // and then grab the pointer to the newly transferred packet,
+ // and the data stored in it.
+ //
+
+ NdisQueryPacket( Packet,NULL,NULL,&Buffer,NULL );
+
+ TpPacket = (PTP_PACKET)MmGetMdlVirtualAddress( Buffer );
+
+ TP_ASSERT( BytesTransferred == XferReqHndl->u.TRANS_REQ.DataSize );
+
+ //
+ // We are expecting it, so if the request truly pended, then
+ // count the completion now.
+ //
+
+ if ( XferReqHndl->RequestPended == TRUE )
+ {
+ ++OpenP->Receive->Counters->XferDataComps;
+ }
+
+ //
+ // We have a Func Packet, is it a resend packet or not?
+ //
+
+ if (( TpPacket->u.F1.info.Signature == FUNC2_PACKET_SIGNATURE ) &&
+ ( TpPacket->u.F1.info.PacketType == (UCHAR)FUNC2_PACKET_TYPE ))
+ {
+ if ( Status == NDIS_STATUS_SUCCESS )
+ {
+ //
+ // It is a resend packet, we need to resend it. first check
+ // the header and the data in the pacekt.
+ //
+
+ if ( !TpCheckSum( (PUCHAR)&TpPacket->u.F1.info,
+ sizeof( PACKET_INFO ) - sizeof( ULONG ),
+ (PULONG)&TpPacket->u.F1.info.CheckSum ))
+ {
+ ++OpenP->Receive->Counters->CorruptRecs;
+ }
+
+ // XXX: function for this
+ BufMem = (PUCHAR)((PUCHAR)TpPacket + (UCHAR)sizeof( FUNC1_PACKET ));
+
+ for ( i = 0 ; i < ( BytesTransferred - sizeof( FUNC1_PACKET )) ; i++ )
+ {
+ if ( BufMem[i] != (UCHAR)( i % 256 ))
+ {
+ IF_TPDBG( TP_DEBUG_DATA )
+ {
+ TpPrint1(
+ "TpFuncTransferDataComplete: Data Corruption in packet 0x%lX at\n",
+ Packet);
+ TpPrint3(
+ " offset %d into data. Expected 0x%X, found 0x%X.\n\n",
+ i,(i % 256),BufMem[i]);
+ }
+ ++OpenP->Receive->Counters->CorruptRecs;
+
+ IF_TPDBG( TP_DEBUG_BREAKPOINT )
+ {
+ TpBreakPoint();
+ }
+ break;
+ }
+ }
+
+ //
+ // Then copy the local adapter address into the source
+ // address in the packet header.
+ //
+
+ //
+ // STARTCHANGE
+ //
+ if ( NdisMediumArray[OpenP->MediumIndex] == NdisMedium802_5 ) // Tokenring
+ {
+ for ( i = 0 ; i < OpenP->Media->AddressLen ; i++ )
+ {
+ TpPacket->u.F1.media.tr.SrcAddress[i] = OpenP->StationAddress[i];
+ }
+ }
+ else if ( NdisMediumArray[OpenP->MediumIndex] == NdisMediumFddi ) // Fddi
+ {
+ for ( i = 0 ; i < OpenP->Media->AddressLen ; i++ )
+ {
+ TpPacket->u.F1.media.fddi.SrcAddress[i] = OpenP->StationAddress[i];
+ }
+ }
+ else if ( NdisMediumArray[OpenP->MediumIndex] == NdisMedium802_3 ) // Ethernet
+ {
+ for ( i = 0 ; i < OpenP->Media->AddressLen ; i++ )
+ {
+ TpPacket->u.F1.media.e.SrcAddress[i] = OpenP->StationAddress[i];
+ }
+ }
+ else if ( NdisMediumArray[OpenP->MediumIndex] == NdisMediumArcnet878_2 ) // Arcnet
+ {
+ for ( i = 0 ; i < OpenP->Media->AddressLen ; i++ )
+ {
+ TpPacket->u.F1.media.a.SrcAddress[i] = OpenP->StationAddress[i];
+ }
+ }
+ //
+ // STOPCHANGE
+ //
+
+ //
+ // if the NdisTransferData call completed successfully,
+ // then we can resend the packet now. Allocate the
+ // request handle and set it up as if the request
+ // pended. If it does not pend we will reset the
+ // flags later before calling the completion routine.
+ //
+
+ Status = NdisAllocateMemory((PVOID *)&SendReqHndl,
+ sizeof( TP_REQUEST_HANDLE ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG( TP_DEBUG_RESOURCES )
+ {
+ TpPrint0(
+ "TpFuncTransferDataComplete: unable to allocated request handle\n");
+ }
+ return;
+ }
+ else
+ {
+ NdisZeroMemory( SendReqHndl,sizeof( TP_REQUEST_HANDLE ));
+ }
+
+ SendReqHndl->Signature = SEND_REQUEST_HANDLE_SIGNATURE;
+ SendReqHndl->Open = OpenP;
+ SendReqHndl->RequestPended = TRUE;
+ SendReqHndl->u.SEND_REQ.Packet = Packet;
+
+ //
+ // STARTCHANGE
+ //
+ SendReqHndl->u.SEND_REQ.PacketSize = BytesTransferred + sizeof( MEDIA_HEADER );
+ //
+ // STOPCHANGE
+ //
+
+ SendReqHndl->u.SEND_REQ.SendPacket = FALSE;
+
+ //
+ // Now reset the packet to a FUNC1 packet type, and
+ // calculate the new checksum.
+ //
+
+ TpPacket->u.F1.info.PacketType = FUNC1_PACKET_TYPE;
+ TpPacket->u.F1.info.Signature = FUNC1_PACKET_SIGNATURE;
+
+ TpPacket->u.F1.info.CheckSum =
+ TpSetCheckSum( (PUCHAR)&TpPacket->u.F1.info,
+ sizeof( PACKET_INFO ) - sizeof( ULONG ) );
+
+ //
+ // Reference the new request handle off the reserved area.
+ //
+
+ ProtRes->RequestHandle = SendReqHndl;
+ //
+ // Set the check sum in the PROTOCOL RESERVED Section of the
+ // packet header to ensure it is not touched while the packet
+ // is in the hands of the MAC.
+ //
+
+ ProtRes->CheckSum = TpSetCheckSum( (PUCHAR)ProtRes,
+ sizeof( PROTOCOL_RESERVED ) -
+ sizeof( ULONG ) );
+
+ if (OpenP->Receive->ResendReq == NULL)
+ {
+ OpenP->Receive->ResendReq = SendReqHndl;
+
+ DueTime.HighPart = -1; // So it will be relative.
+ if (OpenP->Receive->ResendType)
+ {
+ DueTime.LowPart = (ULONG)(-2 * (ONE_HUNDREDTH_SECOND));
+ }
+ else
+ {
+ DueTime.LowPart = (ULONG)(-(ONE_HUNDREDTH_SECOND));
+ }
+
+ if ( KeSetTimer(&OpenP->Receive->ResendTimer,
+ DueTime,
+ &OpenP->Receive->ResendDpc ))
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0("TpFuncTransferDataComplete set SendTimer while timer existed.\n");
+ }
+ }
+ }
+ else
+ {
+ TpFuncResend(OpenP, SendReqHndl);
+ }
+ }
+ else // ( Status == Some Type Failure )
+ {
+ //
+ // The transfer data call failed, increment the counter,
+ // and deallocate the resources.
+ //
+
+ IF_TPDBG( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1("TpFuncTransferDataComplete: NdisTransferData failed: returned %s\n",
+ TpGetStatus(Status));
+ }
+ ++OpenP->Receive->Counters->XferDataFails;
+
+ //
+ // Now free up the transfer packet resources.
+ //
+
+ NdisUnchainBufferAtFront( Packet,&Buffer );
+ NdisFreeMemory( MmGetMdlVirtualAddress( Buffer ),0,0 );
+ TpFreeBuffer( Buffer );
+ NdisFreePacket( Packet );
+ }
+ }
+ else
+ {
+ //
+ // This is just a packet we should receive, count, and drop.
+ //
+
+ BufMem = (PUCHAR)TpPacket;
+
+ for ( i = 0 ; i < BytesTransferred ; i++ )
+ {
+ if ( BufMem[i] != (UCHAR)( i % 256 ))
+ {
+ IF_TPDBG( TP_DEBUG_DATA )
+ {
+ TpPrint1("TpFuncTransferDataComplete: Data Corruption in packet 0x%lX at\n",
+ Packet);
+ TpPrint3(
+ " offset %d into data. Expected 0x%X found 0x%X.\n",
+ i,(i % 256),BufMem[i]);
+ }
+ ++OpenP->Receive->Counters->CorruptRecs;
+
+ IF_TPDBG( TP_DEBUG_BREAKPOINT )
+ {
+ TpBreakPoint();
+ }
+ break;
+ }
+ }
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1("TpFuncReceive: NdisTransferData failed: returned %s\n",
+ TpGetStatus(Status));
+ }
+ ++OpenP->Receive->Counters->XferDataFails;
+ }
+
+ //
+ // Now free up the transfer packet resources.
+ //
+
+ NdisUnchainBufferAtFront( Packet,&Buffer );
+ NdisFreeMemory( MmGetMdlVirtualAddress( Buffer ),0,0 );
+ TpFreeBuffer( Buffer );
+ NdisFreePacket( Packet );
+ }
+
+ //
+ // And finally free up the Request Handle that was allocated
+ // in the Receive routine for the call to NdisTransferData.
+ //
+
+ NdisFreeMemory( XferReqHndl,0,0 );
+ }
+ else
+ {
+ //
+ // We are not expecting a transfer data to complete at this
+ // point, so stick this on the Event Queue.
+ //
+
+ NdisAcquireSpinLock( &OpenP->EventQueue->SpinLock );
+
+ NextEvent = OpenP->EventQueue->Head + 1;
+
+ if ( NextEvent == MAX_EVENT )
+ {
+ NextEvent = 0;
+ }
+
+ if ( NextEvent != OpenP->EventQueue->Tail )
+ {
+ //
+ // There is room to add another event to the event queue.
+ //
+
+ OpenP->EventQueue->Events[NextEvent].TpEventType = CompleteTransferData;
+ OpenP->EventQueue->Head = NextEvent;
+ }
+ else
+ {
+ //
+ // The event queue is full, and this would have overflowed it, so
+ // mark the Head event overflow flag to show this.
+ //
+ OpenP->EventQueue->Events[OpenP->EventQueue->Head].Overflow = TRUE;
+ }
+
+ //
+ // We have a resource, the packet, should we free it? to where?
+ // who really owns it?
+ //
+ NdisReleaseSpinLock( &OpenP->EventQueue->SpinLock );
+ }
+ return;
+}
+
+VOID
+TpFuncResend(POPEN_BLOCK OpenP,
+ PTP_REQUEST_HANDLE SendReqHndl)
+{
+ NDIS_STATUS Status;
+ PNDIS_PACKET Packet = SendReqHndl->u.SEND_REQ.Packet;
+
+ //
+ // Increment the send pending packet counter,
+ //
+
+ ++OpenP->Receive->PacketsPending;
+
+ //
+ // and the number of packets sent,
+ //
+
+ ++OpenP->Receive->Counters->Sends;
+
+ //
+ // and send it...
+ //
+
+ NdisSend( &Status,
+ OpenP->NdisBindingHandle,
+ Packet );
+
+ if ( Status != NDIS_STATUS_PENDING )
+ {
+ --OpenP->Receive->PacketsPending;
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG( TP_DEBUG_NDIS_CALLS )
+ {
+ TpPrint1("TpFuncResendDpc: NdisSend failed: returned %s\n", TpGetStatus(Status));
+ }
+ //
+ // If we are running on TokenRing the following to "failures"
+ // are not considered failures NDIS_STATUS_NOT_RECOGNIZED -
+ // no one on the ring recognized the address as theirs, or
+ // NDIS_STATUS_NOT_COPIED - no one on the ring copied the
+ // packet, so we need to special case this and not count
+ // these as failures.
+ //
+ if ( ( NdisMediumArray[OpenP->MediumIndex] == NdisMedium802_5 ) ||
+ ( NdisMediumArray[OpenP->MediumIndex] == NdisMediumFddi ) ||
+ ( NdisMediumArray[OpenP->MediumIndex] == NdisMediumArcnet878_2) )
+ {
+ if (( Status != NDIS_STATUS_NOT_RECOGNIZED ) &&
+ ( Status != NDIS_STATUS_NOT_COPIED ))
+ {
+ ++OpenP->Send->Counters->SendFails;
+ }
+ }
+ else
+ {
+ ++OpenP->Send->Counters->SendFails;
+ }
+ }
+ SendReqHndl->RequestPended = FALSE;
+ TpFuncSendComplete( OpenP,Packet,Status );
+ }
+ else
+ {
+ ++OpenP->Receive->Counters->SendPends;
+ }
+
+}
+
+
+VOID
+TpFuncResendDpc(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SysArg1,
+ IN PVOID SysArg2
+ )
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)DeferredContext);
+ PTP_REQUEST_HANDLE SendReqHndl = OpenP->Receive->ResendReq;
+
+
+ UNREFERENCED_PARAMETER( Dpc );
+ UNREFERENCED_PARAMETER( SysArg1 );
+ UNREFERENCED_PARAMETER( SysArg2 );
+
+ TpFuncResend(OpenP, SendReqHndl);
+
+ OpenP->Receive->ResendReq = NULL;
+}
+
+
+
+VOID
+TpFuncReceiveDpc(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SysArg1,
+ IN PVOID SysArg2
+ )
+
+// --------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// -------
+
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)DeferredContext);
+ LARGE_INTEGER DueTime;
+
+ UNREFERENCED_PARAMETER( Dpc );
+ UNREFERENCED_PARAMETER( SysArg1 );
+ UNREFERENCED_PARAMETER( SysArg2 );
+
+ DueTime.HighPart = -1; // So it will be relative.
+ DueTime.LowPart = (ULONG)(-(ONE_SECOND));
+
+ //
+ // If the Irp has been cancelled or the Stop Receive
+ // flag has been set then end the test.
+ //
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ if ((( OpenP->Receive->ReceiveIrp == NULL ) ||
+ ( OpenP->Receive->ReceiveIrp->Cancel == TRUE )) ||
+ (( OpenP->Receive->Receiving == TRUE ) &&
+ ( OpenP->Receive->StopReceiving == TRUE )))
+ {
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ //
+ // The receive test should now stop, so queue the Receive
+ // End dpc routine.
+ //
+
+ if ( KeSetTimer(&OpenP->Receive->ReceiveTimer,
+ DueTime,
+ &OpenP->Receive->ReceiveEndDpc ))
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0("TpFuncReceiveDpc set StressEnd timer while timer existed.\n");
+ }
+ }
+ }
+ else
+ {
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ //
+ // Otherwise the test should continue, so insert the next instance
+ // of the Receive Dpc in the timer queue and exit. This will queue
+ // the next instance of the TpFuncReceiveDpc routine when the
+ // timer goes off.
+ //
+
+ if ( KeSetTimer(&OpenP->Receive->ReceiveTimer,
+ DueTime,
+ &OpenP->Receive->ReceiveDpc ))
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0("TpFuncReceiveDpc set Receive timer while timer existed.\n");
+ }
+ }
+ }
+}
+
+
+
+VOID
+TpFuncReceiveEndDpc(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SysArg1,
+ IN PVOID SysArg2
+ )
+
+// ----------
+//
+// Routine Description:
+//
+//
+// Arguments:
+//
+//
+// Return Value:
+//
+//
+// --------
+
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)DeferredContext);
+ LARGE_INTEGER DueTime;
+
+ UNREFERENCED_PARAMETER( Dpc );
+ UNREFERENCED_PARAMETER( SysArg1 );
+ UNREFERENCED_PARAMETER( SysArg2 );
+
+ //
+ // See if we have any outstanding packets left to complete. If we do,
+ // then we will reset the time to queue this dpc routine again in one
+ // second, if after ten requeues the packet(s) has still no completed
+ // we assume it will never complete and return the results and finish.
+ //
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ if (((( OpenP->Receive->ReceiveIrp != NULL ) &&
+ ( OpenP->Receive->ReceiveIrp->Cancel == FALSE )) &&
+ ( OpenP->Receive->PacketsPending != 0 )) &&
+ ( OpenP->Receive->ReceiveEndDpcCount++ < 10 ))
+ {
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ DueTime.HighPart = -1; // So it will be relative.
+ DueTime.LowPart = (ULONG)(-(ONE_SECOND));
+
+ if ( KeSetTimer(&OpenP->Receive->ReceiveTimer,
+ DueTime,
+ &OpenP->Receive->ReceiveEndDpc ))
+ {
+ IF_TPDBG ( TP_DEBUG_DPC )
+ {
+ TpPrint0("TpFuncReceiveEndDpc set ReceiveTimer while timer existed.\n");
+ }
+ }
+ return;
+ }
+
+ //
+ // If the status has not been reset, then set it to success now.
+ //
+
+ if ( OpenP->Receive->ReceiveIrp->IoStatus.Status == NDIS_STATUS_PENDING )
+ {
+ OpenP->Receive->ReceiveIrp->IoStatus.Status = NDIS_STATUS_SUCCESS;
+ }
+
+ //
+ // Now write the RECEIVE results to the output buffer.
+ //
+
+ TpWriteSendReceiveResults( OpenP->Receive->Counters,
+ OpenP->Receive->ReceiveIrp );
+
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+
+ //
+ // Now set the receiving flag to indicate that we are no longer
+ // RECEIVEing packets.
+ //
+
+ OpenP->Receive->Receiving = FALSE;
+
+ //
+ // and decrement the reference count on the OpenBlock stating this
+ // instance of an async test is no longer running, and the adapter
+ // may be closed if requested.
+ //
+
+ TpRemoveReference( OpenP );
+
+ IoMarkIrpPending( OpenP->Receive->ReceiveIrp );
+
+ IoAcquireCancelSpinLock( &OpenP->Receive->ReceiveIrp->CancelIrql );
+ IoSetCancelRoutine( OpenP->Receive->ReceiveIrp,NULL );
+ IoReleaseCancelSpinLock( OpenP->Receive->ReceiveIrp->CancelIrql );
+
+ IoCompleteRequest( OpenP->Receive->ReceiveIrp,IO_NETWORK_INCREMENT );
+
+ OpenP->Receive->ReceiveIrp = NULL;
+
+ return;
+}
+
+
+
+NDIS_STATUS
+TpFuncGetEvent(
+ IN POPEN_BLOCK OpenP
+ )
+
+// ----
+//
+// Routine Description:
+//
+//
+// Arguments:
+//
+//
+// Return Value:
+//
+// Status -
+//
+// -----
+
+{
+ PEVENT_RESULTS OutputBuffer;
+ ULONG NextEvent;
+
+ OutputBuffer = MmGetSystemAddressForMdl( OpenP->Irp->MdlAddress );
+
+ OutputBuffer->Signature = EVENT_RESULTS_SIGNATURE;
+
+ NdisAcquireSpinLock( &OpenP->EventQueue->SpinLock );
+
+ if ( OpenP->EventQueue->Head == OpenP->EventQueue->Tail )
+ {
+ //
+ // There is nothing in the Event Queue.
+ //
+
+ OpenP->Irp->IoStatus.Status = TP_STATUS_NO_EVENTS;
+ }
+ else
+ {
+ if (( NextEvent = ++OpenP->EventQueue->Tail ) == MAX_EVENT )
+ {
+ NextEvent = OpenP->EventQueue->Tail = 0;
+ }
+
+ OutputBuffer->TpEventType = OpenP->EventQueue->Events[NextEvent].TpEventType;
+ OutputBuffer->QueueOverFlowed = OpenP->EventQueue->Events[NextEvent].Overflow;
+
+ OpenP->EventQueue->Events[NextEvent].TpEventType = Unknown;
+ OpenP->EventQueue->Events[NextEvent].EventInfo = NULL;
+ OpenP->EventQueue->Events[NextEvent].Overflow = FALSE;
+
+ OpenP->Irp->IoStatus.Status = STATUS_SUCCESS;
+ }
+
+ NdisReleaseSpinLock( &OpenP->EventQueue->SpinLock );
+
+ return OpenP->Irp->IoStatus.Status;
+}
+
+
+
+VOID
+TpFuncStatus(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ )
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)ProtocolBindingContext);
+ ULONG NextEvent;
+
+ //
+ // We have receive a Status indication, stick it on the
+ // Event Queue.
+ //
+
+ NdisAcquireSpinLock( &OpenP->EventQueue->SpinLock );
+
+ NextEvent = OpenP->EventQueue->Head + 1;
+
+ if ( NextEvent == MAX_EVENT )
+ {
+ NextEvent = 0;
+ }
+
+ if ( NextEvent != OpenP->EventQueue->Tail )
+ {
+ //
+ // There is room to add another event to the event queue.
+ //
+
+ OpenP->EventQueue->Events[NextEvent].TpEventType = IndicateStatus;
+ OpenP->EventQueue->Head = NextEvent;
+
+ //
+ // At this point we could stick the General Status
+ // into the EventInfo buffer.
+ //
+
+ }
+ else
+ {
+ //
+ // The event queue is full, and this would overflow it.
+ //
+ OpenP->EventQueue->Events[OpenP->EventQueue->Head].Overflow = TRUE;
+ }
+
+ //
+ // Increment the Status Indication counter and set the status
+ // completion flag to true to show that a completion is expected.
+ //
+
+ ++OpenP->EventQueue->StatusIndicationCount;
+
+ OpenP->EventQueue->ExpectStatusComplete = TRUE;
+
+ NdisReleaseSpinLock( &OpenP->EventQueue->SpinLock );
+}
+
+
+
+VOID
+TpFuncStatusComplete(
+ IN NDIS_HANDLE ProtocolBindingContext
+ )
+
+// ----------
+//
+// Routine Description:
+//
+// Print out the help message to the debugger screen.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+// ---------
+
+{
+ POPEN_BLOCK OpenP = ((POPEN_BLOCK)ProtocolBindingContext);
+ ULONG NextEvent;
+
+ NdisAcquireSpinLock( &OpenP->EventQueue->SpinLock );
+
+ //
+ // We have received an unexpected Status Completion, so
+ // we are expecting (???) to receive the completion.
+ //
+
+ NextEvent = OpenP->EventQueue->Head + 1;
+
+ if ( NextEvent == MAX_EVENT )
+ {
+ NextEvent = 0;
+ }
+
+ if ( NextEvent != OpenP->EventQueue->Tail )
+ {
+ //
+ // There is room to add another event to the event queue.
+ //
+
+ OpenP->EventQueue->Events[NextEvent].TpEventType = IndicateStatusComplete;
+ OpenP->EventQueue->Head = NextEvent;
+ }
+ else
+ {
+ //
+ // The event queue is full, and this would overflow it.
+ //
+
+ OpenP->EventQueue->Events[OpenP->EventQueue->Head].Overflow = TRUE;
+ }
+
+ //
+ // Reset the status indication counter to zero, and set the
+ // status completion expected flag to show that no completion
+ // routine is expected.
+ //
+
+ OpenP->EventQueue->StatusIndicationCount = 0;
+ OpenP->EventQueue->ExpectStatusComplete = FALSE;
+
+ NdisReleaseSpinLock( &OpenP->EventQueue->SpinLock );
+}
+
+
+
+NDIS_STATUS
+TpFuncSendGo(
+ IN POPEN_BLOCK OpenP,
+ IN PCMD_ARGS CmdArgs,
+ IN UCHAR PacketType
+ )
+
+// -----
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// ----
+
+{
+ NDIS_STATUS Status;
+ PTP_REQUEST_HANDLE RequestHandle;
+ PGO_PACKET GoPacket;
+ PUCHAR p, q;
+ USHORT DataSizeShort;
+ PNDIS_BUFFER Buffer;
+ PNDIS_PACKET Packet;
+ PPROTOCOL_RESERVED ProtRes;
+ PREQUEST_RESULTS OutputBuffer;
+ ULONG i;
+
+ OutputBuffer = MmGetSystemAddressForMdl( OpenP->Irp->MdlAddress );
+
+ //
+ // Allocate the request handle, and init the relevant fields
+ //
+
+ Status = NdisAllocateMemory((PVOID *)&RequestHandle,
+ sizeof( TP_REQUEST_HANDLE ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG( TP_DEBUG_RESOURCES )
+ {
+ TpPrint0("TpFuncSendGo: unable to allocated request handle.\n");
+ }
+ OpenP->Irp->IoStatus.Status = NDIS_STATUS_RESOURCES;
+ return NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( RequestHandle,sizeof( TP_REQUEST_HANDLE ));
+ }
+
+ RequestHandle->Signature = GO_REQUEST_HANDLE_SIGNATURE;
+ RequestHandle->Open = OpenP;
+
+ //
+ // Now allocate the GoPacket to copy the packet data into.
+ //
+
+ Status = NdisAllocateMemory((PVOID *)&GoPacket,
+ sizeof( GO_PACKET ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG(TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpFuncSendGo: unable to allocate buffer memory.\n");
+ }
+ OpenP->Irp->IoStatus.Status = NDIS_STATUS_RESOURCES;
+ return NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( (PUCHAR)GoPacket,sizeof( GO_PACKET ));
+ }
+
+ switch ( OpenP->Media->MediumType )
+ {
+ case NdisMedium802_5:
+ GoPacket->go_media.tr.AC = 0x10;
+ GoPacket->go_media.tr.FC = 0x40;
+
+ p = (PUCHAR)&GoPacket->go_media.tr.DestAddress[0];
+ q = (PUCHAR)&GoPacket->go_media.tr.SrcAddress[0];
+
+ for ( i=0;i<OpenP->Media->AddressLen;i++ )
+ {
+ *p++ = CmdArgs->ARGS.PAUSE_GO.RemoteAddress[i];
+ *q++ = OpenP->StationAddress[i];
+ }
+ break;
+
+ case NdisMediumDix:
+ case NdisMedium802_3:
+
+ p = (PUCHAR)&GoPacket->go_media.e.DestAddress[0];
+ q = (PUCHAR)&GoPacket->go_media.e.SrcAddress[0];
+
+ for ( i=0;i<OpenP->Media->AddressLen;i++ )
+ {
+ *p++ = CmdArgs->ARGS.PAUSE_GO.RemoteAddress[i];
+ *q++ = OpenP->StationAddress[i];
+ }
+
+ DataSizeShort = (USHORT)( sizeof( GO_PACKET ) - OpenP->Media->HeaderSize );
+
+ GoPacket->go_media.e.PacketSize_Hi = (UCHAR)(DataSizeShort >> 8 );
+ GoPacket->go_media.e.PacketSize_Lo = (UCHAR)DataSizeShort;
+ break;
+
+ case NdisMediumFddi:
+ GoPacket->go_media.fddi.FC = 0x57;
+
+ p = (PUCHAR)&GoPacket->go_media.fddi.DestAddress[0];
+ q = (PUCHAR)&GoPacket->go_media.fddi.SrcAddress[0];
+
+ for ( i=0;i<OpenP->Media->AddressLen;i++ )
+ {
+ *p++ = CmdArgs->ARGS.PAUSE_GO.RemoteAddress[i];
+ *q++ = OpenP->StationAddress[i];
+ }
+ break;
+
+ //
+ // STARTCHANGE
+ //
+ case NdisMediumArcnet878_2:
+ GoPacket->go_media.a.ProtocolID = ARCNET_DEFAULT_PROTOCOLID;
+
+ p = (PUCHAR)&GoPacket->go_media.a.DestAddress[0];
+ q = (PUCHAR)&GoPacket->go_media.a.SrcAddress[0];
+
+ for ( i=0;i<OpenP->Media->AddressLen;i++ )
+ {
+ *p++ = CmdArgs->ARGS.PAUSE_GO.RemoteAddress[i];
+ *q++ = OpenP->StationAddress[i];
+ }
+ break;
+ //
+ // STOPCHANGE
+ //
+
+ default:
+ IF_TPDBG ( TP_DEBUG_RESOURCES )
+ {
+ TpPrint0("TpFuncSendGo: Unsupported MAC Type\n");
+ }
+
+ OpenP->Irp->IoStatus.Status = NDIS_STATUS_RESOURCES;
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ GoPacket->info.Signature = GO_PACKET_SIGNATURE;
+ GoPacket->info.TestSignature = CmdArgs->ARGS.PAUSE_GO.TestSignature;
+ GoPacket->info.UniqueSignature = OpenP->Pause->UniqueSignature;
+ GoPacket->info.PacketType = PacketType;
+
+ GoPacket->info.CheckSum = TpSetCheckSum((PUCHAR)&GoPacket->info,
+ sizeof( GO_PACKET_INFO ) - sizeof( ULONG ) );
+
+ //
+ // Then allocate the buffer that will reference the memory,
+ //
+
+ Buffer = IoAllocateMdl( (PVOID)GoPacket,sizeof( GO_PACKET ),TRUE,FALSE,NULL );
+
+ if ( Buffer == NULL )
+ {
+ IF_TPDBG(TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpFuncSendGo: unable to allocate mdl buffer\n");
+ }
+ NdisFreeMemory( (PVOID)GoPacket,0,0 );
+ OpenP->Irp->IoStatus.Status = NDIS_STATUS_RESOURCES;
+ return NDIS_STATUS_RESOURCES;
+ }
+ MmBuildMdlForNonPagedPool( (PMDL)Buffer );
+
+ //
+ // and finally the NDIS_PACKET to pass to the NdisTransferData call.
+ //
+
+ NdisAllocatePacket( &Status,
+ &Packet,
+ OpenP->Pause->PacketHandle );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG(TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpFuncReceive: unable to allocate resend packet\n");
+ }
+ IoFreeMdl( Buffer );
+ NdisFreeMemory( (PVOID)GoPacket,0,0 );
+ OpenP->Irp->IoStatus.Status = Status;
+ return Status;
+ }
+ else
+ {
+ //
+ // Setup the protocol reserved portion of the packet so the
+ // completion routines know what and where to deallocate.
+ //
+
+ ProtRes = PROT_RES( Packet );
+ ProtRes->Pool.PacketHandle = OpenP->Pause->PacketHandle;
+ ProtRes->InstanceCounters = NULL;
+ ProtRes->RequestHandle = RequestHandle;
+ RequestHandle->u.SEND_REQ.Packet = Packet;
+ }
+
+ //
+ // Now chain the buffer to the packet.
+ //
+
+ NdisChainBufferAtFront( Packet,Buffer );
+
+ //
+ // Set the check sum in the PROTOCOL RESERVED Section of the
+ // packet header to ensure it is not touched while the packet
+ // is in the hands of the MAC.
+ //
+
+ ProtRes->CheckSum = TpSetCheckSum( (PUCHAR)ProtRes,
+ sizeof( PROTOCOL_RESERVED ) - sizeof( ULONG ) );
+ //
+ // And send it.
+ //
+
+ NdisSend( &Status,OpenP->NdisBindingHandle,Packet );
+
+ if ( Status != NDIS_STATUS_PENDING )
+ {
+ TpFuncSendComplete( OpenP,Packet,Status );
+ }
+ else
+ {
+ // NOTE: should we somehow handle sends failing , or will be catch
+ // that on the next iteration??? - this could cause us problems
+ // on the go response packet.
+ Status = NDIS_STATUS_SUCCESS;
+ }
+
+ OutputBuffer->RequestStatus = Status;
+ OpenP->Irp->IoStatus.Status = Status;
+ return Status;
+}
+
+
+
+NDIS_STATUS
+TpFuncPause(
+ IN POPEN_BLOCK OpenP,
+ IN PCMD_ARGS CmdArgs,
+ IN UCHAR PacketType
+ )
+
+// ----
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// ----
+
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ LARGE_INTEGER TimeOut;
+ PREQUEST_RESULTS OutputBuffer;
+
+ OpenP->Pause->TimeOut = 0;
+
+ OutputBuffer = MmGetSystemAddressForMdl( OpenP->Irp->MdlAddress );
+ OutputBuffer->RequestStatus = TP_STATUS_TIMEDOUT;
+
+ TimeOut.HighPart = -1; // so it will be relative.
+ TimeOut.LowPart = (ULONG)(-(ONE_SECOND));
+
+ do
+ {
+ NdisAcquireSpinLock( &OpenP->Pause->SpinLock );
+
+ if ( OpenP->Pause->GoReceived == FALSE )
+ {
+ NdisReleaseSpinLock( &OpenP->Pause->SpinLock );
+
+ //
+ // If the Go packet has not arrived stall for a moment
+ // waiting for it to arrive.
+ //
+
+ Status = KeDelayExecutionThread( KernelMode,FALSE,&TimeOut );
+ if ( Status != STATUS_SUCCESS )
+ {
+ break;
+ }
+ else
+ {
+ ++OpenP->Pause->TimeOut;
+ }
+ }
+ else
+ {
+ //
+ // Otherwise we have received a go packet, see if it
+ // is the one we are waiting for.
+ //
+
+ if (( CmdArgs->ARGS.PAUSE_GO.TestSignature == OpenP->Pause->TestSignature ) &&
+ ( OpenP->Pause->PacketType == PacketType ))
+ {
+ //
+ // It is, get out of here.
+ //
+ OpenP->Pause->GoReceived = FALSE;
+
+ NdisReleaseSpinLock( &OpenP->Pause->SpinLock );
+
+ OutputBuffer->RequestStatus = NDIS_STATUS_SUCCESS;
+ break;
+ }
+ else
+ {
+ //
+ // We received a GO packet with the wrong test signature.
+ //
+
+ OpenP->Pause->GoReceived = FALSE;
+ NdisReleaseSpinLock( &OpenP->Pause->SpinLock );
+ }
+ }
+
+ } while (( OpenP->Pause->TimeOut < 10 ) && ( OpenP->IrpCancelled == FALSE ));
+
+ OpenP->Irp->IoStatus.Status = Status;
+ return Status;
+}
+
+
+
diff --git a/private/ntos/ndis/testprot/tpdrvr/tpprocs.h b/private/ntos/ndis/testprot/tpdrvr/tpprocs.h
new file mode 100644
index 000000000..72cdd6290
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpdrvr/tpprocs.h
@@ -0,0 +1,841 @@
+// -------------------------------------
+//
+// Copyright (c) 1990 Microsoft Corporation
+//
+// Module Name:
+//
+// tpprocs.h
+//
+// Abstract:
+//
+// Function prototypes for test and stress sections of the Test Protocol.
+//
+// Author:
+//
+// Tom Adams (tomad) 16-Jul-1990
+//
+// Environment:
+//
+// Kernel mode, FSD
+//
+// Revision History:
+//
+// Tom Adams (tomad) 27-Nov-1990
+// Divided the procedures and defintions into two seperate include files.
+// Added definitions for TpRunTest and support routines.
+//
+// Tom Adams (tomad) 30-Dec-1990
+// Added defintions for TpStress and support routines.
+//
+// Tim Wynsma (timothyw) 4-27-94
+// Added performance tests
+//
+// Tim Wynsma (timothyw) 6-08-94
+// Chgd performance tests to client/server model
+//
+// ---------------------------------------
+
+//
+// driver initialization and open/close routines
+//
+
+NTSTATUS
+TpCreateDeviceContext(
+ IN PDRIVER_OBJECT DriverObject,
+ IN STRING DeviceName,
+ PDEVICE_CONTEXT *DeviceContext
+ );
+
+NTSTATUS
+TpCreateSymbolicLinkObject(
+ VOID
+ );
+
+NTSTATUS
+TpInitializeEventQueue(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+NTSTATUS
+TpRegisterProtocol(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN STRING *NameString
+ );
+
+NTSTATUS
+TpDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+TpOpenDriver(
+ IN PDEVICE_CONTEXT DeviceObject
+ );
+
+NTSTATUS
+TpCleanUpDriver(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PIRP Irp
+ );
+
+VOID
+TpCloseDriver(
+ IN PDEVICE_CONTEXT DeviceObject
+ );
+
+VOID
+TpUnloadDriver(
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+BOOLEAN
+TpAddReference(
+ IN POPEN_BLOCK OpenP
+ );
+
+VOID
+TpRemoveReference(
+ IN POPEN_BLOCK OpenP
+ );
+
+NTSTATUS
+TpAllocateOpenArray(
+ POPEN_BLOCK OpenP
+ );
+
+VOID
+TpDeallocateOpenArray(
+ POPEN_BLOCK OpenP
+ );
+
+VOID
+TpCancelIrp(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PIRP Irp
+ );
+
+
+//
+//
+//
+
+PUCHAR
+TpGetStatus(
+ IN NDIS_STATUS GeneralStatus
+ );
+
+//
+// functions exported to the MAC for phases 0 and 1 of the Test Protocol
+//
+
+VOID
+TestProtocolOpenComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status,
+ IN NDIS_STATUS OpenErrorStatus
+ );
+
+VOID
+TestProtocolCloseComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+TestProtocolSendComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+TestProtocolTransferDataComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ );
+
+VOID
+TestProtocolResetComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+TestProtocolRequestComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS Status
+ );
+
+NDIS_STATUS
+TestProtocolReceive(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+VOID
+TestProtocolReceiveComplete(
+ IN NDIS_HANDLE ProtocolBindingContext
+ );
+
+VOID
+TestProtocolStatus(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ );
+
+VOID
+TestProtocolStatusComplete(
+ IN NDIS_HANDLE ProtocolBindingContext
+ );
+
+//
+// Stress Function Prototypes
+//
+
+NDIS_STATUS
+TpStressStart(
+ IN POPEN_BLOCK OpenP,
+ IN PSTRESS_ARGUMENTS StressArguments
+ );
+
+VOID
+TpStressCleanUp(
+ IN POPEN_BLOCK OpenP
+ );
+
+VOID
+TpStressFreeResources(
+ IN POPEN_BLOCK OpenP
+ );
+
+NDIS_STATUS
+TpStressReceive(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+VOID
+TpStressReceiveComplete(
+ IN NDIS_HANDLE ProtocolBindingContext
+ );
+
+//
+// Test Protocol Ndis Stress Routines
+//
+
+NDIS_STATUS
+TpStressReset(
+ IN POPEN_BLOCK OpenP
+ );
+
+VOID
+TpStressResetComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status
+ );
+
+NDIS_STATUS
+TpStressAddMulticastAddress(
+ IN POPEN_BLOCK OpenP,
+ IN PUCHAR MulticastAddress,
+ IN BOOLEAN SetZeroTableSize
+ );
+
+NDIS_STATUS
+TpStressAddLongMulticastAddress(
+ IN POPEN_BLOCK OpenP,
+ IN PUCHAR MulticastAddress,
+ IN BOOLEAN SetZeroTableSize
+ );
+
+NDIS_STATUS
+TpStressSetFunctionalAddress(
+ IN POPEN_BLOCK OpenP,
+ IN PUCHAR FunctionalAddress,
+ IN BOOLEAN SetZeroTableSize
+ );
+
+NDIS_STATUS
+TpStressSetPacketFilter(
+ IN POPEN_BLOCK OpenP,
+ IN UINT PacketFilter
+ );
+
+VOID
+TpStressRequestComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS Status
+ );
+
+NDIS_STATUS
+TpStressClientSend(
+ IN POPEN_BLOCK OpenP,
+ IN OUT NDIS_HANDLE PacketHandle,
+ IN OUT PTP_TRANSMIT_POOL TpTransmitPool,
+ IN PUCHAR DestAddr,
+ IN UCHAR SrcInstance,
+ IN UCHAR DestInstance,
+ IN UCHAR PacketProtocol,
+ IN ULONG SequenceNumber,
+ IN ULONG MaxSequenceNumber,
+ IN UCHAR ClientReference,
+ IN UCHAR ServerReference,
+ IN INT PacketSize,
+ IN INT BufferSize
+ );
+
+VOID
+TpStressServerSend(
+ IN POPEN_BLOCK OpenP,
+ IN OUT PTP_TRANSMIT_POOL TpTransmitPool,
+ IN PUCHAR DestAddr,
+ IN UCHAR DestInstance,
+ IN UCHAR SrcInstance,
+ IN ULONG SequenceNumber,
+ IN ULONG MaxSequenceNumber,
+ IN UCHAR ClientReference,
+ IN UCHAR ServerReference,
+ IN INT PacketSize,
+ IN ULONG DataBufferOffset
+ );
+
+VOID
+TpStressSend(
+ IN POPEN_BLOCK OpenP,
+ IN PNDIS_PACKET Packet,
+ IN PINSTANCE_COUNTERS Counters
+ );
+
+VOID
+TpStressSendComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+TpStressCheckPacketData(
+ IN POPEN_BLOCK OpenP,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN ULONG DataOffset,
+ IN UINT PacketSize,
+ IN PINSTANCE_COUNTERS Counters
+ );
+
+VOID
+TpStressTransferDataComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ );
+
+VOID
+TpStressDoNothing(
+ VOID
+ );
+
+//
+// Function prototypes for packet.c
+//
+
+PNDIS_PACKET
+TpStressCreatePacket(
+ IN POPEN_BLOCK OpenP,
+ IN OUT NDIS_HANDLE PacketHandle,
+ IN OUT PACKET_MAKEUP PacketMakeUp,
+ IN UCHAR DestInstance,
+ IN UCHAR SrcInstance,
+ IN UCHAR PacketProtocol,
+ IN UCHAR ResponseType,
+ IN PUCHAR DestAddr,
+ IN INT PacketSize,
+ IN INT BufferSize,
+ IN ULONG SequenceNumber,
+ IN ULONG MaxSequenceNumber,
+ IN UCHAR ClientReference,
+ IN UCHAR ServerReference,
+ IN BOOLEAN DataChecking
+ );
+
+PNDIS_PACKET
+TpStressCreateTruncatedPacket(
+ IN POPEN_BLOCK OpenP,
+ IN NDIS_HANDLE PacketHandle,
+ IN UCHAR PacketProtocol,
+ IN UCHAR ResponseType
+ );
+
+ULONG
+TpGetPacketSignature(
+ IN PNDIS_PACKET Packet
+ );
+
+VOID
+TpStressFreePacket(
+ IN PNDIS_PACKET Packet
+ );
+
+PTP_TRANSMIT_POOL
+TpStressCreateTransmitPool(
+ IN POPEN_BLOCK OpenP,
+ IN NDIS_HANDLE PacketHandle,
+ IN PACKET_MAKEUP PacketMakeUp,
+ IN UCHAR PacketProtocol,
+ IN UCHAR ResponseType,
+ IN INT PacketSize,
+ IN INT NumPackets,
+ IN BOOLEAN ServerPool
+ );
+
+VOID
+TpStressFreeTransmitPool(
+ IN OUT PTP_TRANSMIT_POOL TpTransmitPool
+ );
+
+PNDIS_PACKET
+TpStressAllocatePoolPacket(
+ IN PTP_TRANSMIT_POOL TpTransmitPool,
+ IN PINSTANCE_COUNTERS Counters
+ );
+
+VOID
+TpStressSetPoolPacketInfo(
+ IN POPEN_BLOCK OpenP,
+ IN OUT PNDIS_PACKET Packet,
+ IN PUCHAR DestAddr,
+ IN UCHAR ClientInstance,
+ IN UCHAR ServerInstance,
+ IN ULONG SequenceNumber,
+ IN ULONG MaxSequenceNumber,
+ IN UCHAR ClientReference,
+ IN UCHAR ServerReference
+ );
+
+VOID
+TpStressSetTruncatedPacketInfo(
+ IN POPEN_BLOCK OpenP,
+ IN OUT PNDIS_PACKET Packet,
+ IN PUCHAR DestAddr,
+ IN INT PacketSize,
+ IN UCHAR DestInstance,
+ IN UCHAR SrcInstance,
+ IN ULONG SequenceNumber,
+ IN ULONG MaxSequenceNumber,
+ IN UCHAR ClientReference,
+ IN UCHAR ServerReference,
+ IN ULONG DataBufferOffset
+ );
+
+VOID
+TpStressFreePoolPacket(
+ IN OUT PNDIS_PACKET Packet
+ );
+
+PTP_PACKET
+TpFuncInitPacketHeader(
+ IN POPEN_BLOCK OpenP,
+ IN INT PacketSize
+ );
+
+BOOLEAN
+TpCheckSum(
+ IN PUCHAR Buffer,
+ IN ULONG BufLen,
+ IN PULONG CheckSum
+ );
+
+ULONG
+TpSetCheckSum(
+ IN PUCHAR Buffer,
+ IN ULONG BufLen
+ );
+
+PNDIS_PACKET
+TpFuncAllocateSendPacket(
+ POPEN_BLOCK OpenP
+ );
+
+VOID
+TpFuncFreePacket(
+ PNDIS_PACKET Packet,
+ ULONG PacketSize
+ );
+
+//
+// Functions prototypes to replace buffer management routines
+//
+
+PNDIS_BUFFER
+TpAllocateBuffer(
+ IN PUCHAR TmpBuf,
+ IN INT BufSize
+ );
+
+VOID
+TpFreeBuffer(
+ IN OUT PNDIS_BUFFER Buf
+ );
+
+VOID
+TpStressInitDataBuffer(
+ IN OUT POPEN_BLOCK OpenP,
+ IN INT BufferSize
+ );
+
+//
+// Sanjeevk : Renamed function
+//
+
+VOID
+TpStressFreeDataBuffers(
+ IN OUT POPEN_BLOCK OpenP
+ );
+
+//
+// Sanjeevk : Added new function
+//
+VOID
+TpStressFreeDataBufferMdls(
+ IN OUT POPEN_BLOCK OpenP
+ );
+
+//
+// Utility Function Prototypes for utils.c
+//
+
+NDIS_STATUS
+TpInitStressArguments(
+ PSTRESS_ARGUMENTS *StressArguments,
+ PCMD_ARGS CmdArgs
+ );
+
+NDIS_STATUS
+TpInitServerArguments(
+ PSTRESS_ARGUMENTS *StressArguments
+ );
+
+VOID
+TpPrintClientStatistics(
+ IN POPEN_BLOCK OpenP
+ );
+
+VOID
+TpStressWriteResults(
+ IN POPEN_BLOCK OpenP
+ );
+
+VOID
+TpCopyClientStatistics(
+ IN POPEN_BLOCK OpenP
+ );
+
+VOID
+TpWriteServerStatistics(
+ IN POPEN_BLOCK OpenP,
+ IN OUT PNDIS_PACKET Packet,
+ IN PCLIENT_INFO Client
+ );
+
+VOID
+TpCopyServerStatistics(
+ IN POPEN_BLOCK OpenP,
+ IN PVOID Buffer,
+ IN INT ServerReference
+ );
+
+VOID
+TpPrintServerStatistics(
+ IN POPEN_BLOCK OpenP,
+ IN PCLIENT_INFO Client
+ );
+
+VOID
+TpWriteSendReceiveResults(
+ PINSTANCE_COUNTERS Counters,
+ PIRP Irp
+ );
+
+VOID
+TpInitializePending(
+ PPENDING Pend
+ );
+
+VOID
+TpInitializeStressResults(
+ PSTRESS_RESULTS Results
+ );
+
+//
+// Function prototypes for Test Protocol utility routines
+//
+
+VOID
+TpSetRandom(
+ VOID
+ );
+
+UINT
+TpGetRandom(
+ UINT Low,
+ UINT High
+ );
+
+
+NTSTATUS
+TpIssueRequest(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NDIS_STATUS
+TpFuncSend(
+ IN POPEN_BLOCK OpenP
+ );
+
+VOID
+TpFuncSendDpc(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SysArg1,
+ IN PVOID SysArg2
+ );
+
+VOID
+TpFuncSendEndDpc(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SysArg1,
+ IN PVOID SysArg2
+ );
+
+VOID
+TpFuncInitializeSendArguments(
+ POPEN_BLOCK OpenP,
+ PCMD_ARGS CmdArgs
+ );
+
+NDIS_STATUS
+TpPerfClient(
+ POPEN_BLOCK OpenP,
+ PCMD_ARGS CmdArgs
+ );
+
+NDIS_STATUS
+TpPerfServer(
+ POPEN_BLOCK OpenP
+ );
+
+NDIS_STATUS
+TpPerfAbort(
+ POPEN_BLOCK OpenP
+ );
+
+VOID
+TpPerfSendComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ );
+
+NDIS_STATUS
+TpPerfReceive(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+NDIS_STATUS
+TpFuncGetEvent(
+ IN POPEN_BLOCK OpenP
+ );
+
+NDIS_STATUS
+TpFuncRequestQueryInfo(
+ POPEN_BLOCK OpenP,
+ PCMD_ARGS CmdArgs,
+ PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NDIS_STATUS
+TpFuncRequestSetInfo(
+ POPEN_BLOCK OpenP,
+ PCMD_ARGS CmdArgs,
+ PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NDIS_STATUS
+TpFuncOpenAdapter(
+ IN POPEN_BLOCK OpenP,
+ IN UCHAR OpenInstance,
+ IN PCMD_ARGS CmdArgs
+ );
+
+NDIS_STATUS
+TpFuncCloseAdapter(
+ IN POPEN_BLOCK OpenP
+ );
+
+NDIS_STATUS
+TpFuncReset(
+ IN POPEN_BLOCK OpenP
+ );
+
+NDIS_STATUS
+TpFuncAddMulticastAddress(
+ IN POPEN_BLOCK OpenP,
+ IN PUCHAR MulticastAddress,
+ IN PTP_REQUEST_HANDLE *RequestHandle
+ );
+
+NDIS_STATUS
+TpFuncDeleteMulticastAddress(
+ IN POPEN_BLOCK OpenP,
+ IN PUCHAR MulticastAddress,
+ IN PTP_REQUEST_HANDLE *RequestHandle
+ );
+
+VOID
+TpFuncOpenComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status,
+ IN NDIS_STATUS OpenErrorStatus
+ );
+
+VOID
+TpFuncCloseComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+TpFuncSendComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+TpFuncTransferDataComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ );
+
+VOID
+TpFuncResetComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+TpFuncRequestComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS Status
+ );
+
+NDIS_STATUS
+TpFuncInitializeReceive(
+ IN POPEN_BLOCK OpenP
+ );
+
+NDIS_STATUS
+TpFuncReceive(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+VOID
+TpFuncReceiveComplete(
+ IN NDIS_HANDLE ProtocolBindingContext
+ );
+
+VOID
+TpFuncReceiveDpc(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SysArg1,
+ IN PVOID SysArg2
+ );
+
+VOID
+TpFuncReceiveEndDpc(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SysArg1,
+ IN PVOID SysArg2
+ );
+
+VOID
+TpFuncResendDpc(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SysArg1,
+ IN PVOID SysArg2
+ );
+
+VOID
+TpFuncTransferDataComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ );
+
+VOID
+TpFuncStatus(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ );
+
+VOID
+TpFuncStatusComplete(
+ IN NDIS_HANDLE ProtocolBindingContext
+ );
+
+NDIS_STATUS
+TpFuncSendGo(
+ IN POPEN_BLOCK OpenP,
+ IN PCMD_ARGS CmdArgs,
+ IN UCHAR PacketType
+ );
+
+NDIS_STATUS
+TpFuncPause(
+ IN POPEN_BLOCK OpenP,
+ IN PCMD_ARGS CmdArgs,
+ IN UCHAR PacketType
+ );
+
+
+
diff --git a/private/ntos/ndis/testprot/tpdrvr/tpreq.c b/private/ntos/ndis/testprot/tpdrvr/tpreq.c
new file mode 100644
index 000000000..25bbe79b0
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpdrvr/tpreq.c
@@ -0,0 +1,952 @@
+// --------------------
+//
+// Copyright (c) 1990 Microsoft Corporation
+//
+// Module Name:
+//
+// tpreq.c
+//
+// Abstract:
+//
+// This module contains code which defines the Test Protocol
+// device object.
+//
+// Author:
+//
+// Tom Adams (tomad) 19-Apr-1991
+//
+// Environment:
+//
+// Kernel mode, FSD
+//
+// Revision History:
+//
+// Tim Wynsma (timothyw) 4-27-94
+// Added performance tests
+// Tim Wynsma (timothyw) 6-08-94
+// chgd perf tests to client/server model
+//
+// ------------------
+
+#include <ndis.h>
+
+#include "tpdefs.h"
+#include "tpprocs.h"
+#include "media.h"
+
+
+NTSTATUS
+TpIssueRequest(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+// ---
+//
+// Routine Description:
+//
+//
+// Arguments:
+//
+//
+// Return Value:
+//
+// ----
+
+{
+ NTSTATUS Status;
+ PVOID InputBuffer;
+ ULONG InputBufferLength;
+ PMDL OutputMdl;
+ ULONG OutputMdlLength;
+ UCHAR OpenInstance;
+ POPEN_BLOCK OpenP;
+ PCMD_ARGS CmdArgs;
+ PSTRESS_ARGUMENTS StressArguments;
+ ULONG i;
+ ULONG CmdCode;
+
+ //
+ // Get the Input and Output buffers for the Incoming commands,
+ // and the buffer to return the results in.
+ //
+
+ InputBuffer = Irp->AssociatedIrp.SystemBuffer;
+
+ InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+
+ OutputMdl = Irp->MdlAddress;
+
+ OutputMdlLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+
+ //
+ // Then find out which Open Instance we will be using.
+ //
+
+ OpenInstance = (UCHAR)(((PCMD_ARGS)InputBuffer)->OpenInstance - 1);
+
+ OpenP = (POPEN_BLOCK)&(DeviceContext->Open[OpenInstance]);
+
+ //
+ // Set the IoStatus.Information field to the value of the OpenInstance
+ // so that a Cancelled Irp may find the Open that it is required to
+ // cancel the irp for.
+ //
+
+ Irp->IoStatus.Information = (ULONG)OpenP;
+
+ //
+ // and reference the Irp, for the general case Irp Cancel.
+ //
+
+ OpenP->Irp = Irp;
+ OpenP->IrpCancelled = FALSE;
+
+ //
+ // Then set up the cancel routine for the Irp.
+ //
+
+ IoAcquireCancelSpinLock( &Irp->CancelIrql );
+
+ if ( Irp->Cancel )
+ {
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+ return STATUS_CANCELLED;
+ }
+
+ IoSetCancelRoutine( Irp,(PDRIVER_CANCEL)TpCancelIrp );
+
+ IoReleaseCancelSpinLock( Irp->CancelIrql );
+
+ //
+ // Now switch to the specific command to call.
+ //
+
+ CmdArgs = ((PCMD_ARGS)InputBuffer);
+ CmdCode = IrpSp->Parameters.DeviceIoControl.IoControlCode;
+
+ switch ( CmdCode )
+ {
+ case IOCTL_TP_SETENV:
+ {
+ PUCHAR p, q;
+
+ IF_TPDBG (TP_DEBUG_DISPATCH)
+ {
+ TpPrint0("IoControlCode is IOCTL_TP_SETENV.\n");
+ }
+
+ IF_TPDBG(TP_DEBUG_IOCTL_ARGS)
+ {
+ TpPrint1("\tOpenInstance = %lu\n",OpenInstance);
+ TpPrint1("\tWindowSize = %lu\n",CmdArgs->ARGS.ENV.WindowSize);
+ TpPrint1("\tRandomBufferNumber = %lu\n", CmdArgs->ARGS.ENV.RandomBufferNumber);
+ TpPrint1("\tStressDelayInterval = %lu\n", CmdArgs->ARGS.ENV.StressDelayInterval);
+ TpPrint1("\tUpForAirDelay = %lu\n", CmdArgs->ARGS.ENV.UpForAirDelay);
+ TpPrint1("\tStandardDelay = %lu\n", CmdArgs->ARGS.ENV.StandardDelay);
+
+ //
+ // STARTCHANGE
+ //
+ if ( OpenP->Media->MediumType == NdisMediumArcnet878_2 )
+ {
+ TpPrint1("\tStress Address = %02x\n", CmdArgs->ARGS.ENV.StressAddress[0]);
+ }
+ else
+ {
+ TpPrint6("\tStress Address = %02x-%02x-%02x-%02x-%02x-%02x\n",
+ CmdArgs->ARGS.ENV.StressAddress[0],
+ CmdArgs->ARGS.ENV.StressAddress[1],
+ CmdArgs->ARGS.ENV.StressAddress[2],
+ CmdArgs->ARGS.ENV.StressAddress[3],
+ CmdArgs->ARGS.ENV.StressAddress[4],
+ CmdArgs->ARGS.ENV.StressAddress[5]);
+ }
+ //
+ // STOPCHANGE
+ //
+ }
+
+ OpenP->Environment->WindowSize = CmdArgs->ARGS.ENV.WindowSize;
+
+ if ( CmdArgs->ARGS.ENV.RandomBufferNumber > OpenP->Media->MaxPacketLen )
+ {
+ OpenP->Environment->RandomBufferNumber = OpenP->Media->MaxPacketLen;
+
+ TpPrint2("RandomBufferNumber \"%d\"to large, using %d instead\n",
+ CmdArgs->ARGS.ENV.RandomBufferNumber,
+ OpenP->Media->MaxPacketLen);
+ }
+ else
+ {
+ OpenP->Environment->RandomBufferNumber = CmdArgs->ARGS.ENV.RandomBufferNumber;
+ }
+
+ OpenP->Environment->StressDelayInterval = CmdArgs->ARGS.ENV.StressDelayInterval;
+ OpenP->Environment->UpForAirDelay = CmdArgs->ARGS.ENV.UpForAirDelay;
+ OpenP->Environment->StandardDelay = CmdArgs->ARGS.ENV.StandardDelay;
+
+ p = OpenP->Environment->StressAddress;
+ q = (PUCHAR)(CmdArgs->ARGS.ENV.StressAddress);
+
+ //
+ // STARTCHANGE
+ //
+ for ( i=0;i<OpenP->Media->AddressLen;i++ )
+ {
+ *p++ = *q++ ;
+ }
+ //
+ // STOPCHANGE
+ //
+
+ Status = Irp->IoStatus.Status = STATUS_SUCCESS;
+ break;
+ }
+
+ case IOCTL_TP_GO:
+ IF_TPDBG (TP_DEBUG_DISPATCH)
+ {
+ TpPrint0("IoControlCode is IOCTL_TP_GO.\n");
+ }
+
+ IF_TPDBG(TP_DEBUG_IOCTL_ARGS)
+ {
+ TpPrint1("\tOpenInstance = %lu\n",OpenInstance);
+ //
+ // STARTCHANGE
+ //
+ if ( OpenP->Media->MediumType == NdisMediumArcnet878_2 )
+ {
+ TpPrint1("\tRemote Address = %02x\n", CmdArgs->ARGS.PAUSE_GO.RemoteAddress[0]);
+ }
+ else
+ {
+ TpPrint6("\tRemote Address = %02x-%02x-%02x-%02x-%02x-%02x\n",
+ CmdArgs->ARGS.PAUSE_GO.RemoteAddress[0],
+ CmdArgs->ARGS.PAUSE_GO.RemoteAddress[1],
+ CmdArgs->ARGS.PAUSE_GO.RemoteAddress[2],
+ CmdArgs->ARGS.PAUSE_GO.RemoteAddress[3],
+ CmdArgs->ARGS.PAUSE_GO.RemoteAddress[4],
+ CmdArgs->ARGS.PAUSE_GO.RemoteAddress[5]);
+ }
+ //
+ // STOPCHANGE
+ //
+ TpPrint1("\tTest Signature = %lu\n", CmdArgs->ARGS.PAUSE_GO.TestSignature);
+ TpPrint1("\tUnique Signature = %lu\n",CmdArgs->ARGS.PAUSE_GO.UniqueSignature);
+ }
+ OpenP->Pause->UniqueSignature = CmdArgs->ARGS.PAUSE_GO.UniqueSignature;
+
+ Status = TpFuncSendGo( OpenP,CmdArgs,TP_GO );
+
+ if ( Status == NDIS_STATUS_SUCCESS )
+ {
+ Status = TpFuncPause( OpenP,CmdArgs,TP_GO_ACK );
+ }
+ break;
+
+ case IOCTL_TP_PAUSE:
+ {
+ PREQUEST_RESULTS ResBuf;
+
+ ResBuf = MmGetSystemAddressForMdl( Irp->MdlAddress );
+
+ IF_TPDBG (TP_DEBUG_DISPATCH)
+ {
+ TpPrint0("IoControlCode is IOCTL_TP_PAUSE.\n");
+ }
+
+ IF_TPDBG(TP_DEBUG_IOCTL_ARGS)
+ {
+ TpPrint1("\tOpenInstance = %lu\n",OpenInstance);
+ //
+ // STARTCHANGE
+ //
+ if ( OpenP->Media->MediumType == NdisMediumArcnet878_2 )
+ {
+ TpPrint1("\tRemote Address = %02x\n", CmdArgs->ARGS.PAUSE_GO.RemoteAddress[0]);
+ }
+ else
+ {
+ TpPrint6("\tRemote Address = %02x-%02x-%02x-%02x-%02x-%02x\n",
+ CmdArgs->ARGS.PAUSE_GO.RemoteAddress[0],
+ CmdArgs->ARGS.PAUSE_GO.RemoteAddress[1],
+ CmdArgs->ARGS.PAUSE_GO.RemoteAddress[2],
+ CmdArgs->ARGS.PAUSE_GO.RemoteAddress[3],
+ CmdArgs->ARGS.PAUSE_GO.RemoteAddress[4],
+ CmdArgs->ARGS.PAUSE_GO.RemoteAddress[5]);
+ }
+ TpPrint1("\tTest Signature = %lu\n", CmdArgs->ARGS.PAUSE_GO.TestSignature);
+ }
+
+ Status = TpFuncPause( OpenP,CmdArgs,TP_GO );
+
+ if (( Status == NDIS_STATUS_SUCCESS ) &&
+ ( ResBuf->RequestStatus == NDIS_STATUS_SUCCESS ))
+ {
+ Status = TpFuncSendGo( OpenP,CmdArgs,TP_GO_ACK );
+ }
+ break;
+ }
+
+ case IOCTL_TP_OPEN: // NdisOpenAdapter
+ IF_TPDBG (TP_DEBUG_DISPATCH)
+ {
+ TpPrint0("IoControlCode is IOCTL_TP_OPEN.\n");
+ }
+
+ IF_TPDBG(TP_DEBUG_IOCTL_ARGS)
+ {
+ TpPrint1("\tOpenInstance = %lu\n",OpenInstance);
+ TpPrint1("\tAdapter_Name = %s\n",CmdArgs->ARGS.OPEN_ADAPTER.AdapterName);
+ TpPrint1("\tNoArcNetFlag = %lu\n",CmdArgs->ARGS.OPEN_ADAPTER.NoArcNet);
+ }
+ Status = TpFuncOpenAdapter( OpenP,OpenInstance,CmdArgs );
+ break;
+
+ case IOCTL_TP_CLOSE: // NdisCloseAdapter
+ IF_TPDBG (TP_DEBUG_DISPATCH)
+ {
+ TpPrint0("IoControlCode is IOCTL_TP_CLOSE.\n");
+ }
+
+ IF_TPDBG(TP_DEBUG_IOCTL_ARGS)
+ {
+ TpPrint1("\tOpenInstance = %lu\n",OpenInstance);
+ }
+ Status = TpFuncCloseAdapter( OpenP );
+ break;
+
+ case IOCTL_TP_SETPF:
+ IF_TPDBG (TP_DEBUG_DISPATCH)
+ {
+ TpPrint0("IoControlCode is IOCTL_TP_SETPF.\n");
+ }
+
+ IF_TPDBG(TP_DEBUG_IOCTL_ARGS)
+ {
+ TpPrint1("\tOpenInstance = %lu\n",OpenInstance);
+ TpPrint1("\tPacketFilter = %lu\n", CmdArgs->ARGS.TPSET.U.PacketFilter);
+ }
+ Status = TpFuncRequestSetInfo( OpenP,CmdArgs,Irp,IrpSp );
+ break;
+
+ case IOCTL_TP_SETLA:
+ IF_TPDBG (TP_DEBUG_DISPATCH)
+ {
+ TpPrint0("IoControlCode is IOCTL_TP_SETLA.\n");
+ }
+
+ IF_TPDBG(TP_DEBUG_IOCTL_ARGS)
+ {
+ TpPrint1("\tOpenInstance = %lu\n",OpenInstance);
+ TpPrint1("\tLookaheadSize = %lu\n", CmdArgs->ARGS.TPSET.U.LookaheadSize);
+ }
+ Status = TpFuncRequestSetInfo( OpenP,CmdArgs,Irp,IrpSp );
+ break;
+
+ case IOCTL_TP_ADDMA:
+ case IOCTL_TP_DELMA:
+ IF_TPDBG (TP_DEBUG_DISPATCH)
+ {
+ TpPrint0("IoControlCode is IOCTL_TP_ADDMA.\n");
+ }
+
+ IF_TPDBG(TP_DEBUG_IOCTL_ARGS)
+ {
+ TpPrint1("\tOpenInstance = %lu\n",OpenInstance);
+ TpPrint1("\tNumber MulticastAddresses = %d\n",
+ CmdArgs->ARGS.TPSET.NumberMultAddrs);
+
+ TpPrint0("\tMulticast Address List = \n");
+
+ for ( i=0;i<CmdArgs->ARGS.TPSET.NumberMultAddrs;i++ )
+ {
+ TpPrint6("\t\t%02x-%02x-%02x-%02x-%02x-%02x\n",
+ CmdArgs->ARGS.TPSET.U.MulticastAddress[i][0],
+ CmdArgs->ARGS.TPSET.U.MulticastAddress[i][1],
+ CmdArgs->ARGS.TPSET.U.MulticastAddress[i][2],
+ CmdArgs->ARGS.TPSET.U.MulticastAddress[i][3],
+ CmdArgs->ARGS.TPSET.U.MulticastAddress[i][4],
+ CmdArgs->ARGS.TPSET.U.MulticastAddress[i][5]);
+ }
+ }
+ Status = TpFuncRequestSetInfo( OpenP,CmdArgs,Irp,IrpSp );
+ break;
+
+ case IOCTL_TP_SETFA: // NdisSetInformation
+ IF_TPDBG (TP_DEBUG_DISPATCH)
+ {
+ TpPrint0("IoControlCode is IOCTL_TP_SETFA.\n");
+ }
+
+ IF_TPDBG(TP_DEBUG_IOCTL_ARGS)
+ {
+ TpPrint1("\tOpenInstance = %lu\n",OpenInstance);
+ TpPrint4("\tFunctional Address = %02x-%02x-%02x-%02x\n",
+ CmdArgs->ARGS.TPSET.U.FunctionalAddress[0],
+ CmdArgs->ARGS.TPSET.U.FunctionalAddress[1],
+ CmdArgs->ARGS.TPSET.U.FunctionalAddress[2],
+ CmdArgs->ARGS.TPSET.U.FunctionalAddress[3]);
+ }
+ Status = TpFuncRequestSetInfo( OpenP,CmdArgs,Irp,IrpSp );
+ break;
+
+ case IOCTL_TP_SETGA:
+ IF_TPDBG (TP_DEBUG_DISPATCH)
+ {
+ TpPrint0("IoControlCode is IOCTL_TP_SETFA.\n");
+ }
+
+ IF_TPDBG(TP_DEBUG_IOCTL_ARGS)
+ {
+ TpPrint1("\tOpenInstance = %lu\n",OpenInstance);
+ TpPrint4("\tGlobal Address = %02x-%02x-%02x-%02x\n",
+ CmdArgs->ARGS.TPSET.U.FunctionalAddress[0],
+ CmdArgs->ARGS.TPSET.U.FunctionalAddress[1],
+ CmdArgs->ARGS.TPSET.U.FunctionalAddress[2],
+ CmdArgs->ARGS.TPSET.U.FunctionalAddress[3]);
+ }
+ Status = TpFuncRequestSetInfo( OpenP,CmdArgs,Irp,IrpSp );
+ break;
+
+ case IOCTL_TP_QUERYINFO:
+ IF_TPDBG (TP_DEBUG_DISPATCH)
+ {
+ TpPrint0("IoControlCode is IOCTL_TP_QUERYINFO.\n");
+ }
+
+ IF_TPDBG(TP_DEBUG_IOCTL_ARGS)
+ {
+ TpPrint1("\tOpenInstance = %lu\n",OpenInstance);
+ TpPrint1("\tInformation OID = 0x%08lX\n", CmdArgs->ARGS.TPQUERY.OID);
+ }
+ Status = TpFuncRequestQueryInfo( OpenP,CmdArgs,Irp,IrpSp );
+ break;
+
+ case IOCTL_TP_SETINFO: // NdisSetInformation
+ IF_TPDBG (TP_DEBUG_DISPATCH)
+ {
+ TpPrint0("IoControlCode is IOCTL_TP_SETINFO.\n");
+ }
+
+ IF_TPDBG(TP_DEBUG_IOCTL_ARGS)
+ {
+ TpPrint1("\tOpenInstance = %lu\n",OpenInstance);
+ TpPrint1("\tInformation OID = 0x%08lX\n",CmdArgs->ARGS.TPSET.OID);
+
+ switch ( CmdArgs->ARGS.TPSET.OID )
+ {
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ TpPrint1("\tPacketFilter = %lu\n", CmdArgs->ARGS.TPSET.U.PacketFilter);
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ TpPrint1("\tLookAheadSize = %lu\n", CmdArgs->ARGS.TPSET.U.LookaheadSize);
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+ TpPrint0("\tMulticast Address List = \n");
+
+ for ( i=0;i<CmdArgs->ARGS.TPSET.NumberMultAddrs;i++ )
+ {
+ TpPrint6("\t\t%02x-%02x-%02x-%02x-%02x-%02x\n",
+ CmdArgs->ARGS.TPSET.U.MulticastAddress[i][0],
+ CmdArgs->ARGS.TPSET.U.MulticastAddress[i][1],
+ CmdArgs->ARGS.TPSET.U.MulticastAddress[i][2],
+ CmdArgs->ARGS.TPSET.U.MulticastAddress[i][3],
+ CmdArgs->ARGS.TPSET.U.MulticastAddress[i][4],
+ CmdArgs->ARGS.TPSET.U.MulticastAddress[i][5]);
+ }
+ break;
+
+ case OID_FDDI_LONG_MULTICAST_LIST:
+ TpPrint0("\tLong Multicast Address List = \n");
+
+ for ( i=0;i<CmdArgs->ARGS.TPSET.NumberMultAddrs;i++ )
+ {
+ TpPrint6("\t\t%02x-%02x-%02x-%02x-%02x-%02x\n",
+ CmdArgs->ARGS.TPSET.U.MulticastAddress[i][0],
+ CmdArgs->ARGS.TPSET.U.MulticastAddress[i][1],
+ CmdArgs->ARGS.TPSET.U.MulticastAddress[i][2],
+ CmdArgs->ARGS.TPSET.U.MulticastAddress[i][3],
+ CmdArgs->ARGS.TPSET.U.MulticastAddress[i][4],
+ CmdArgs->ARGS.TPSET.U.MulticastAddress[i][5]);
+ }
+ break;
+
+ case OID_802_5_CURRENT_FUNCTIONAL:
+ case OID_802_5_CURRENT_GROUP:
+ TpPrint4("\tAddress to Set = %02x-%02x-%02x-%02x\n",
+ CmdArgs->ARGS.TPSET.U.FunctionalAddress[0],
+ CmdArgs->ARGS.TPSET.U.FunctionalAddress[1],
+ CmdArgs->ARGS.TPSET.U.FunctionalAddress[2],
+ CmdArgs->ARGS.TPSET.U.FunctionalAddress[3]);
+ break;
+
+ default:
+ TpPrint0("\tInvalid Oid\n");
+ break;
+ }
+ }
+ Status = TpFuncRequestSetInfo( OpenP,CmdArgs,Irp,IrpSp );
+ break;
+
+ case IOCTL_TP_RESET: // NdisReset
+ IF_TPDBG (TP_DEBUG_DISPATCH)
+ {
+ TpPrint0("IoControlCode is IOCTL_TP_RESET.\n");
+ }
+
+ IF_TPDBG(TP_DEBUG_IOCTL_ARGS)
+ {
+ TpPrint1("\tOpenInstance = %lu\n",OpenInstance);
+ }
+ Status = TpFuncReset( OpenP );
+ break;
+
+ case IOCTL_TP_SEND: // NdisSend
+ IF_TPDBG (TP_DEBUG_DISPATCH)
+ {
+ TpPrint0("IoControlCode is IOCTL_TP_SEND.\n");
+ }
+
+ IF_TPDBG(TP_DEBUG_IOCTL_ARGS)
+ {
+ TpPrint1("\tOpenInstance = %lu\n",OpenInstance);
+ if ( OpenP->Media->MediumType == NdisMediumArcnet878_2 )
+ {
+ TpPrint1("\tDestination Address = %02x\n", CmdArgs->ARGS.TPSEND.DestAddress[0]);
+ }
+ else
+ {
+ TpPrint6("\tDestination Address = %02x-%02x-%02x-%02x-%02x-%02x\n",
+ CmdArgs->ARGS.TPSEND.DestAddress[0],
+ CmdArgs->ARGS.TPSEND.DestAddress[1],
+ CmdArgs->ARGS.TPSEND.DestAddress[2],
+ CmdArgs->ARGS.TPSEND.DestAddress[3],
+ CmdArgs->ARGS.TPSEND.DestAddress[4],
+ CmdArgs->ARGS.TPSEND.DestAddress[5]);
+ }
+ TpPrint1("\tPacket Size = %lu\n",CmdArgs->ARGS.TPSEND.PacketSize);
+ TpPrint1("\tNumber of Packets = %lu\n", CmdArgs->ARGS.TPSEND.NumberOfPackets);
+ if ( OpenP->Media->MediumType == NdisMediumArcnet878_2 )
+ {
+ TpPrint1("\tResend Address = %02x\n", CmdArgs->ARGS.TPSEND.ResendAddress[0]);
+ }
+ else
+ {
+ TpPrint6("\tResend Address = %02x-%02x-%02x-%02x-%02x-%02x\n",
+ CmdArgs->ARGS.TPSEND.ResendAddress[0],
+ CmdArgs->ARGS.TPSEND.ResendAddress[1],
+ CmdArgs->ARGS.TPSEND.ResendAddress[2],
+ CmdArgs->ARGS.TPSEND.ResendAddress[3],
+ CmdArgs->ARGS.TPSEND.ResendAddress[4],
+ CmdArgs->ARGS.TPSEND.ResendAddress[5]);
+ }
+ }
+
+ OpenP->Send->SendIrp = Irp;
+ OpenP->Irp = NULL;
+
+ TpFuncInitializeSendArguments( OpenP,CmdArgs );
+
+ Status = TpFuncSend( OpenP );
+
+ if (( Status != NDIS_STATUS_SUCCESS ) && ( Status != NDIS_STATUS_PENDING ))
+ {
+ IF_TPDBG ( TP_DEBUG_DISPATCH )
+ {
+ TpPrint1("TpIssueRequest: failed to start TpFuncNdisSend; returned %s\n",
+ TpGetStatus(Status));
+ }
+ }
+ break;
+
+ case IOCTL_TP_STOPSEND:
+ IF_TPDBG (TP_DEBUG_DISPATCH)
+ {
+ TpPrint0("IoControlCode is IOCTL_TP_STOPSEND.\n");
+ }
+
+ IF_TPDBG(TP_DEBUG_IOCTL_ARGS)
+ {
+ TpPrint1("\tOpenInstance = %lu\n",OpenInstance);
+ }
+
+ //
+ // We want to stop the TpFuncSendDpc from executing, so we set the
+ // StopSending flag to true. This will cause the TpFuncSendDpc to
+ // call the TpFuncSendEndDpc to clean up and
+ //
+
+ OpenP->Send->StopSending = TRUE;
+
+ //
+ // And then wait for it to finish.
+ //
+
+ while ( OpenP->Send->Sending == TRUE )
+ {
+ /* NULL */ ;
+ }
+
+ IF_TPDBG (TP_DEBUG_DISPATCH)
+ {
+ TpPrint0("STOPSEND finished waiting for TpFuncSendDpc to end.\n");
+ }
+ Status = Irp->IoStatus.Status = STATUS_SUCCESS;
+ break;
+
+ case IOCTL_TP_RECEIVE:
+ IF_TPDBG (TP_DEBUG_DISPATCH)
+ {
+ TpPrint0("IoControlCode is IOCTL_TP_RECEIVE.\n");
+ }
+
+ IF_TPDBG(TP_DEBUG_IOCTL_ARGS)
+ {
+ TpPrint1("\tOpenInstance = %lu\n",OpenInstance);
+ }
+
+ OpenP->Receive->ReceiveIrp = Irp;
+
+ OpenP->Irp = NULL;
+
+ Status = TpFuncInitializeReceive( OpenP );
+
+ if (( Status != NDIS_STATUS_SUCCESS ) && ( Status != NDIS_STATUS_PENDING ))
+ {
+ IF_TPDBG ( TP_DEBUG_DISPATCH )
+ {
+ TpPrint1(
+ "TpIssueRequest: failed to initilaize Receive structures: returned %s\n",
+ TpGetStatus(Status));
+ }
+ }
+ break;
+
+ case IOCTL_TP_STOPREC:
+ IF_TPDBG (TP_DEBUG_DISPATCH)
+ {
+ TpPrint0("IoControlCode is IOCTL_TP_STOPREC.\n");
+ }
+
+ IF_TPDBG(TP_DEBUG_IOCTL_ARGS)
+ {
+ TpPrint1("\tOpenInstance = %lu\n",OpenInstance);
+ }
+
+ //
+ // We want the functional receive routines to stop expecting
+ // packets, so we set the StopReceiving flag to TRUE.
+ //
+
+ OpenP->Receive->StopReceiving = TRUE;
+
+ //
+ // And then wait for it to finish.
+ //
+
+ while ( OpenP->Receive->Receiving == TRUE )
+ {
+ /* NULL */ ;
+ }
+ Status = Irp->IoStatus.Status = STATUS_SUCCESS;
+ break;
+
+ case IOCTL_TP_GETEVENTS:
+ IF_TPDBG (TP_DEBUG_DISPATCH)
+ {
+ TpPrint0("IoControlCode is IOCTL_TP_GETEVENTS.\n");
+ }
+
+ IF_TPDBG(TP_DEBUG_IOCTL_ARGS)
+ {
+ TpPrint1("\tOpenInstance = %lu\n",OpenInstance);
+ }
+ Status = TpFuncGetEvent( OpenP );
+ break;
+
+ case IOCTL_TP_STRESS:
+ IF_TPDBG (TP_DEBUG_DISPATCH )
+ {
+ TpPrint0("IoControlCode is IOCTL_TP_STRESS.\n");
+ }
+
+ IF_TPDBG(TP_DEBUG_IOCTL_ARGS)
+ {
+ TpPrint1("\tOpenInstance = %lu\n",OpenInstance);
+ TpPrint1("\tMember Type = %lu\n", CmdArgs->ARGS.TPSTRESS.MemberType);
+ TpPrint1("\tPacket Type = %lu\n", CmdArgs->ARGS.TPSTRESS.PacketType);
+ TpPrint1("\tPacket Size = %lu\n", CmdArgs->ARGS.TPSTRESS.PacketSize);
+ TpPrint1("\tPacket MakeUp = %lu\n", CmdArgs->ARGS.TPSTRESS.PacketMakeUp);
+ TpPrint1("\tResponse Type = %lu\n", CmdArgs->ARGS.TPSTRESS.ResponseType);
+ TpPrint1("\tInterpacket Delay Type = %lu\n", CmdArgs->ARGS.TPSTRESS.DelayType);
+ TpPrint1("\tInterpacket Delay Length = %lu\n", CmdArgs->ARGS.TPSTRESS.DelayLength);
+ TpPrint1("\tTotal Iterations = %lu\n", CmdArgs->ARGS.TPSTRESS.TotalIterations);
+ TpPrint1("\tTotal Packets = %lu\n", CmdArgs->ARGS.TPSTRESS.TotalPackets);
+ TpPrint1("\tWindowing Enabled = %lu\n", CmdArgs->ARGS.TPSTRESS.WindowEnabled);
+ TpPrint1("\tData Checking = %lu\n", CmdArgs->ARGS.TPSTRESS.DataChecking);
+ TpPrint1("\tPackets From Pool = %lu\n", CmdArgs->ARGS.TPSTRESS.PacketsFromPool);
+ }
+
+ Status = TpInitStressArguments( &StressArguments,CmdArgs );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_DISPATCH )
+ {
+ TpPrint1("TpIssueRequest: failed to initialize stress arguments; return %s\n",
+ TpGetStatus(Status));
+ }
+
+ Irp->IoStatus.Status = Status;
+
+ //
+ // BUGBUG: Bugfix #5492 NTRAID, NTBUG
+ //
+ IoAcquireCancelSpinLock( &Irp->CancelIrql );
+ IoSetCancelRoutine( Irp,NULL );
+ IoReleaseCancelSpinLock( Irp->CancelIrql );
+ IoCompleteRequest( Irp,IO_NETWORK_INCREMENT );
+ }
+ else
+ {
+ OpenP->Stress->StressIrp = Irp;
+ OpenP->Irp = NULL;
+
+ Status = TpStressStart( OpenP,StressArguments );
+
+ if (( Status != NDIS_STATUS_SUCCESS ) &&
+ ( Status != NDIS_STATUS_PENDING ))
+ {
+ IF_TPDBG ( TP_DEBUG_DISPATCH )
+ {
+ TpPrint1("TpIssueRequest: failed to start TpStress; returned %s\n",
+ TpGetStatus(Status));
+ }
+ OpenP->Stress->StressStarted = FALSE;
+ TpStressCleanUp( OpenP );
+ }
+ }
+ break;
+
+ case IOCTL_TP_STRESSSERVER:
+ IF_TPDBG (TP_DEBUG_DISPATCH)
+ {
+ TpPrint0("IoControlCode is IOCTL_TP_STRESSSERVER.\n");
+ }
+
+ IF_TPDBG(TP_DEBUG_IOCTL_ARGS)
+ {
+ TpPrint1("\tOpenInstance = %lu\n",OpenInstance);
+ }
+ Status = TpInitServerArguments( &StressArguments );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG ( TP_DEBUG_DISPATCH )
+ {
+ TpPrint1("TpIssueRequest: failed to initialize stress arguments; return %s\n",
+ TpGetStatus(Status));
+ }
+ Irp->IoStatus.Status = Status;
+
+ //
+ // BUGBUG: Bugfix #5492 NTRAID, NTBUG
+ //
+ IoAcquireCancelSpinLock( &Irp->CancelIrql );
+ IoSetCancelRoutine( Irp,NULL );
+ IoReleaseCancelSpinLock( Irp->CancelIrql );
+ IoCompleteRequest( Irp,IO_NETWORK_INCREMENT );
+ }
+ else
+ {
+ OpenP->Stress->StressIrp = Irp;
+ OpenP->Irp = NULL;
+
+ Status = TpStressStart( OpenP,StressArguments );
+
+ if (( Status != NDIS_STATUS_SUCCESS ) && ( Status != NDIS_STATUS_PENDING ))
+ {
+ IF_TPDBG ( TP_DEBUG_DISPATCH )
+ {
+ TpPrint1("TpIssueRequest: failed to start TpStressServer; returned %s\n",
+ TpGetStatus(Status));
+ }
+ OpenP->Stress->StressStarted = FALSE;
+ TpStressCleanUp( OpenP );
+ }
+ }
+ break;
+
+ case IOCTL_TP_ENDSTRESS:
+ IF_TPDBG (TP_DEBUG_DISPATCH)
+ {
+ TpPrint0("IoControlCode is IOCTL_TP_ENDSTRESS.\n");
+ }
+
+ IF_TPDBG(TP_DEBUG_IOCTL_ARGS)
+ {
+ TpPrint1("\tOpenInstance = %lu\n",OpenInstance);
+ }
+
+ //
+ // We want to stop any active client and/or server on this open
+ // instance from running the stress routines, so set the
+ // StopStressing flag.
+ //
+
+ OpenP->Stress->StopStressing = TRUE;
+
+ //
+ // And wait for them to finish.
+ //
+
+ while ( OpenP->Stress->Stressing == TRUE )
+ {
+ /* NULL */ ;
+ }
+
+ IF_TPDBG (TP_DEBUG_DISPATCH)
+ {
+ TpPrint0("ENDSTRESS finished waiting for TpStress to end.\n");
+ }
+ Status = Irp->IoStatus.Status = STATUS_SUCCESS;
+ break;
+
+ case IOCTL_TP_BREAKPOINT:
+ //
+ // This is a DbgBreakPoint and not a TpBreakPoint because we
+ // want it to remain in the nodebug builds. If this is called
+ // with out a debugger - tough!
+ //
+ DbgBreakPoint();
+ Status = Irp->IoStatus.Status = STATUS_SUCCESS;
+ break;
+
+ case IOCTL_TP_PERF_SERVER:
+ IF_TPDBG (TP_DEBUG_DISPATCH)
+ {
+ TpPrint0("IoControlCode is IOCTL_TP_PERF_SERVER.\n");
+ }
+
+ IF_TPDBG(TP_DEBUG_IOCTL_ARGS)
+ {
+ TpPrint1("\tOpenInstance = %lu\n",OpenInstance);
+ }
+
+ Status = TpPerfServer( OpenP );
+
+ if (( Status != NDIS_STATUS_SUCCESS ) && ( Status != NDIS_STATUS_PENDING ))
+ {
+ IF_TPDBG ( TP_DEBUG_DISPATCH )
+ {
+ TpPrint1("TpIssueRequest: failed to start TpPerfServer: returned %s\n",
+ TpGetStatus(Status));
+ }
+ }
+ break;
+
+
+ case IOCTL_TP_PERF_CLIENT:
+ IF_TPDBG (TP_DEBUG_DISPATCH)
+ {
+ TpPrint0("IoControlCode is IOCTL_TP_PERF_CLIENT.\n");
+ }
+
+ IF_TPDBG(TP_DEBUG_IOCTL_ARGS)
+ {
+ TpPrint1("\tOpenInstance = %lu\n",OpenInstance);
+ if ( OpenP->Media->MediumType == NdisMediumArcnet878_2 )
+ {
+ TpPrint1("\tServer Address = %02x\n",
+ CmdArgs->ARGS.TPPERF.PerfServerAddr[0]);
+ TpPrint1("\tSend Address = %02x\n",
+ CmdArgs->ARGS.TPPERF.PerfSendAddr[0]);
+ }
+ else
+ {
+ TpPrint6("\tServer Address = %02x-%02x-%02x-%02x-%02x-%02x\n",
+ CmdArgs->ARGS.TPPERF.PerfServerAddr[0],
+ CmdArgs->ARGS.TPPERF.PerfServerAddr[1],
+ CmdArgs->ARGS.TPPERF.PerfServerAddr[2],
+ CmdArgs->ARGS.TPPERF.PerfServerAddr[3],
+ CmdArgs->ARGS.TPPERF.PerfServerAddr[4],
+ CmdArgs->ARGS.TPPERF.PerfServerAddr[5]);
+ TpPrint6("\tSend Address = %02x-%02x-%02x-%02x-%02x-%02x\n",
+ CmdArgs->ARGS.TPPERF.PerfSendAddr[0],
+ CmdArgs->ARGS.TPPERF.PerfSendAddr[1],
+ CmdArgs->ARGS.TPPERF.PerfSendAddr[2],
+ CmdArgs->ARGS.TPPERF.PerfSendAddr[3],
+ CmdArgs->ARGS.TPPERF.PerfSendAddr[4],
+ CmdArgs->ARGS.TPPERF.PerfSendAddr[5]);
+ }
+ TpPrint1("\tPacket Size = %lu\n", CmdArgs->ARGS.TPPERF.PerfPacketSize);
+ TpPrint1("\tNumber of packets = %lu\n", CmdArgs->ARGS.TPPERF.PerfNumPackets);
+ TpPrint1("\tDelay = %lu\n", CmdArgs->ARGS.TPPERF.PerfDelay);
+ TpPrint1("\tMode = %lu\n", CmdArgs->ARGS.TPPERF.PerfMode);
+ }
+
+ Status = TpPerfClient( OpenP, CmdArgs);
+
+ if (( Status != NDIS_STATUS_SUCCESS ) && ( Status != NDIS_STATUS_PENDING ))
+ {
+ IF_TPDBG ( TP_DEBUG_DISPATCH )
+ {
+ TpPrint1(
+ "TpIssueRequest: failed to start TpPerfClient: returned %s\n",
+ TpGetStatus(Status));
+ }
+ }
+ break;
+
+ case IOCTL_TP_PERF_ABORT:
+ IF_TPDBG (TP_DEBUG_DISPATCH)
+ {
+ TpPrint0("IoControlCode is IOCTL_TP_PERF_ABORT.\n");
+ }
+
+ IF_TPDBG(TP_DEBUG_IOCTL_ARGS)
+ {
+ TpPrint1("\tOpenInstance = %lu\n",OpenInstance);
+ }
+ Status = TpPerfAbort(OpenP);
+ break;
+
+ default:
+ TpPrint0("Invalid Command Entered\n");
+ Status = Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ break;
+
+ } // switch();
+
+ if ( ( CmdCode != IOCTL_TP_STRESS ) &&
+ ( CmdCode != IOCTL_TP_STRESSSERVER ) &&
+ ( CmdCode != IOCTL_TP_SEND ) &&
+ ( CmdCode != IOCTL_TP_RECEIVE ) &&
+ ( CmdCode != IOCTL_TP_PERF_SERVER ) &&
+ ( CmdCode != IOCTL_TP_PERF_CLIENT ) )
+ {
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ if ( OpenP->IrpCancelled == TRUE )
+ {
+ return STATUS_CANCELLED;
+ }
+ else
+ {
+ IoAcquireCancelSpinLock( &OpenP->Irp->CancelIrql );
+ IoSetCancelRoutine( OpenP->Irp,NULL );
+ IoReleaseCancelSpinLock( OpenP->Irp->CancelIrql );
+ }
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+ }
+ return Status;
+}
+
+
+
diff --git a/private/ntos/ndis/testprot/tpdrvr/tputils.c b/private/ntos/ndis/testprot/tpdrvr/tputils.c
new file mode 100644
index 000000000..b16105ccf
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpdrvr/tputils.c
@@ -0,0 +1,1080 @@
+// *******************************
+//
+// Copyright (c) 1990 Microsoft Corporation
+//
+// Module Name:
+//
+// tputils.c
+//
+// Abstract:
+//
+// This module implements the utility functions for the NDIS 3.0
+// Test Protocol Tester.
+//
+// Author:
+//
+// Tom Adams (tomad) 14-Jul-1990
+//
+// Environment:
+//
+// Kernel mode
+//
+// Revision History:
+//
+// Tom Adams (tomad) 15-Dec-1990
+// seperate from testprot.c and add test control and statistics fcns.
+//
+// Tom Adams (tomad) 14-March-1991
+// add support for calling TpStress from command line with arguments.
+//
+// Tim Wynsma (timothyw) 5-18-94
+// Fixed warnings, some general cleanup
+//
+// ****************************
+
+#include <ndis.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tpdefs.h"
+#include "media.h"
+#include "tpprocs.h"
+
+
+PUCHAR
+TpGetStatus(
+ NDIS_STATUS GeneralStatus
+ )
+{
+ static NDIS_STATUS Status[] = {
+ NDIS_STATUS_SUCCESS,
+ NDIS_STATUS_PENDING,
+ NDIS_STATUS_NOT_RECOGNIZED,
+ NDIS_STATUS_NOT_COPIED,
+ NDIS_STATUS_ONLINE,
+ NDIS_STATUS_RESET_START,
+ NDIS_STATUS_RESET_END,
+ NDIS_STATUS_RING_STATUS,
+ NDIS_STATUS_CLOSED,
+
+ NDIS_STATUS_WAN_LINE_UP,
+ NDIS_STATUS_WAN_LINE_DOWN,
+ NDIS_STATUS_WAN_FRAGMENT,
+
+ NDIS_STATUS_NOT_RESETTABLE,
+ NDIS_STATUS_SOFT_ERRORS,
+ NDIS_STATUS_HARD_ERRORS,
+ NDIS_STATUS_FAILURE,
+ NDIS_STATUS_RESOURCES,
+ NDIS_STATUS_CLOSING,
+ NDIS_STATUS_BAD_VERSION,
+ NDIS_STATUS_BAD_CHARACTERISTICS,
+ NDIS_STATUS_ADAPTER_NOT_FOUND,
+ NDIS_STATUS_OPEN_FAILED,
+ NDIS_STATUS_DEVICE_FAILED,
+ NDIS_STATUS_MULTICAST_FULL,
+ NDIS_STATUS_MULTICAST_EXISTS,
+ NDIS_STATUS_MULTICAST_NOT_FOUND,
+ NDIS_STATUS_REQUEST_ABORTED,
+ NDIS_STATUS_RESET_IN_PROGRESS,
+ NDIS_STATUS_CLOSING_INDICATING,
+ NDIS_STATUS_NOT_SUPPORTED,
+ NDIS_STATUS_INVALID_PACKET,
+ NDIS_STATUS_OPEN_LIST_FULL,
+ NDIS_STATUS_ADAPTER_NOT_READY,
+ NDIS_STATUS_ADAPTER_NOT_OPEN,
+ NDIS_STATUS_NOT_INDICATING,
+ NDIS_STATUS_INVALID_LENGTH,
+ NDIS_STATUS_INVALID_DATA,
+ NDIS_STATUS_BUFFER_TOO_SHORT,
+ NDIS_STATUS_INVALID_OID,
+ NDIS_STATUS_ADAPTER_REMOVED,
+ NDIS_STATUS_UNSUPPORTED_MEDIA,
+ NDIS_STATUS_GROUP_ADDRESS_IN_USE,
+ NDIS_STATUS_FILE_NOT_FOUND,
+ NDIS_STATUS_ERROR_READING_FILE,
+ NDIS_STATUS_ALREADY_MAPPED,
+ NDIS_STATUS_RESOURCE_CONFLICT,
+ NDIS_STATUS_TOKEN_RING_OPEN_ERROR,
+ TP_STATUS_NO_SERVERS,
+ TP_STATUS_NO_EVENTS
+ };
+
+ static PUCHAR String[] = {
+ "NDIS_STATUS_SUCCESS",
+ "NDIS_STATUS_PENDING",
+ "NDIS_STATUS_NOT_RECOGNIZED",
+ "NDIS_STATUS_NOT_COPIED",
+ "NDIS_STATUS_ONLINE",
+ "NDIS_STATUS_RESET_START",
+ "NDIS_STATUS_RESET_END",
+ "NDIS_STATUS_RING_STATUS",
+ "NDIS_STATUS_CLOSED",
+ "NDIS_STATUS_WAN_LINE_UP",
+ "NDIS_STATUS_WAN_LINE_DOWN",
+ "NDIS_STATUS_WAN_FRAGMENT",
+ "NDIS_STATUS_NOT_RESETTABLE",
+ "NDIS_STATUS_SOFT_ERRORS",
+ "NDIS_STATUS_HARD_ERRORS",
+ "NDIS_STATUS_FAILURE",
+ "NDIS_STATUS_RESOURCES",
+ "NDIS_STATUS_CLOSING",
+ "NDIS_STATUS_BAD_VERSION",
+ "NDIS_STATUS_BAD_CHARACTERISTICS",
+ "NDIS_STATUS_ADAPTER_NOT_FOUND",
+ "NDIS_STATUS_OPEN_FAILED",
+ "NDIS_STATUS_DEVICE_FAILED",
+ "NDIS_STATUS_MULTICAST_FULL",
+ "NDIS_STATUS_MULTICAST_EXISTS",
+ "NDIS_STATUS_MULTICAST_NOT_FOUND",
+ "NDIS_STATUS_REQUEST_ABORTED",
+ "NDIS_STATUS_RESET_IN_PROGRESS",
+ "NDIS_STATUS_CLOSING_INDICATING",
+ "NDIS_STATUS_NOT_SUPPORTED",
+ "NDIS_STATUS_INVALID_PACKET",
+ "NDIS_STATUS_OPEN_LIST_FULL",
+ "NDIS_STATUS_ADAPTER_NOT_READY",
+ "NDIS_STATUS_ADAPTER_NOT_OPEN",
+ "NDIS_STATUS_NOT_INDICATING",
+ "NDIS_STATUS_INVALID_LENGTH",
+ "NDIS_STATUS_INVALID_DATA",
+ "NDIS_STATUS_BUFFER_TOO_SHORT",
+ "NDIS_STATUS_INVALID_OID",
+ "NDIS_STATUS_ADAPTER_REMOVED",
+ "NDIS_STATUS_UNSUPPORTED_MEDIA",
+ "NDIS_STATUS_GROUP_ADDRESS_IN_USE",
+ "NDIS_STATUS_FILE_NOT_FOUND",
+ "NDIS_STATUS_ERROR_READING_FILE",
+ "NDIS_STATUS_ALREADY_MAPPED",
+ "NDIS_STATUS_RESOURCE_CONFLICT",
+ "NDIS_STATUS_TOKEN_RING_OPEN_ERROR",
+ "TP_STATUS_NO_SERVERS",
+ "TP_STATUS_NO_EVENTS"
+ };
+
+ static UCHAR BadStatus[] = "UNDEFINED";
+
+#define StatusCount (sizeof(Status)/sizeof(NDIS_STATUS))
+
+ INT i;
+
+ for (i=0; i<StatusCount; i++)
+ {
+ if (GeneralStatus == Status[i])
+ {
+ return String[i];
+ }
+ }
+ return BadStatus;
+
+#undef StatusCount
+}
+
+
+
+NDIS_STATUS
+TpInitStressArguments(
+ PSTRESS_ARGUMENTS *StressArguments,
+ PCMD_ARGS CmdArgs
+ )
+
+// --------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// The arguments for the test to be run.
+//
+// Return Value:
+//
+// ------
+
+{
+ NDIS_STATUS Status;
+
+ Status = NdisAllocateMemory((PVOID *)StressArguments,
+ sizeof( STRESS_ARGUMENTS ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpInitStressArguments: unable to allocate Argument buffer.\n");
+ }
+ return NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( *StressArguments,sizeof( STRESS_ARGUMENTS ));
+ }
+
+
+ (*StressArguments)->MemberType = CmdArgs->ARGS.TPSTRESS.MemberType;
+ (*StressArguments)->PacketType = CmdArgs->ARGS.TPSTRESS.PacketType;
+ (*StressArguments)->PacketSize = CmdArgs->ARGS.TPSTRESS.PacketSize;
+ (*StressArguments)->PacketMakeUp = CmdArgs->ARGS.TPSTRESS.PacketMakeUp;
+ (*StressArguments)->ResponseType = CmdArgs->ARGS.TPSTRESS.ResponseType;
+ (*StressArguments)->Iterations = 0;
+ (*StressArguments)->TotalIterations = CmdArgs->ARGS.TPSTRESS.TotalIterations;
+ (*StressArguments)->TotalPackets = CmdArgs->ARGS.TPSTRESS.TotalPackets;
+ (*StressArguments)->AllPacketsSent = FALSE;
+ (*StressArguments)->DelayType = CmdArgs->ARGS.TPSTRESS.DelayType;
+ (*StressArguments)->DelayLength = CmdArgs->ARGS.TPSTRESS.DelayLength;
+ (*StressArguments)->WindowEnabled = (UCHAR)CmdArgs->ARGS.TPSTRESS.WindowEnabled;
+ (*StressArguments)->DataChecking = (UCHAR)CmdArgs->ARGS.TPSTRESS.DataChecking;
+ (*StressArguments)->PacketsFromPool = (UCHAR)CmdArgs->ARGS.TPSTRESS.PacketsFromPool;
+ (*StressArguments)->BeginReceives = FALSE;
+ (*StressArguments)->ServerContinue = TRUE;
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+
+NDIS_STATUS
+TpInitServerArguments(
+ PSTRESS_ARGUMENTS *StressArguments
+ )
+
+// -----------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// The arguments for the test to be run.
+//
+// Return Value:
+//
+// ----------------
+
+{
+ NDIS_STATUS Status;
+
+ Status = NdisAllocateMemory((PVOID *)StressArguments,
+ sizeof( STRESS_ARGUMENTS ),
+ 0,
+ HighestAddress );
+
+ if ( Status != NDIS_STATUS_SUCCESS )
+ {
+ IF_TPDBG (TP_DEBUG_RESOURCES)
+ {
+ TpPrint0("TpInitServerArguments: unable to allocate Argument buffer.\n");
+ }
+ return NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ NdisZeroMemory( *StressArguments,sizeof( STRESS_ARGUMENTS ));
+ }
+
+ (*StressArguments)->MemberType = TP_SERVER;
+ (*StressArguments)->PacketType = 0;
+ (*StressArguments)->PacketSize = 100;
+ (*StressArguments)->PacketMakeUp = RAND;
+ (*StressArguments)->ResponseType = ACK_EVERY;
+ (*StressArguments)->Iterations = 0;
+ (*StressArguments)->TotalIterations = 0;
+ (*StressArguments)->TotalPackets = 0;
+ (*StressArguments)->AllPacketsSent = FALSE;
+ (*StressArguments)->DelayType = 0;
+ (*StressArguments)->DelayLength = FIXEDDELAY;
+ (*StressArguments)->WindowEnabled = TRUE;
+ (*StressArguments)->DataChecking = FALSE;
+ (*StressArguments)->PacketsFromPool = TRUE;
+ (*StressArguments)->BeginReceives = FALSE;
+ (*StressArguments)->ServerContinue = TRUE;
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+
+VOID
+TpStressWriteResults(
+ IN POPEN_BLOCK OpenP
+ )
+
+// ---------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// None.
+//
+// ---------
+
+{
+ PSTRESS_RESULTS OutputBuffer;
+
+ NdisAcquireSpinLock( &OpenP->SpinLock );
+
+ OutputBuffer = MmGetSystemAddressForMdl( OpenP->Stress->StressIrp->MdlAddress );
+
+ RtlMoveMemory( OutputBuffer,
+ OpenP->Stress->Results,
+ sizeof( STRESS_RESULTS ) );
+
+ NdisReleaseSpinLock( &OpenP->SpinLock );
+}
+
+
+
+VOID
+TpCopyClientStatistics(
+ IN POPEN_BLOCK OpenP
+ )
+
+// --------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// None.
+//
+// ---------
+
+{
+ PSTRESS_RESULTS res;
+ PGLOBAL_COUNTERS gc;
+ PINSTANCE_COUNTERS ic;
+ PINSTANCE_COUNTERS lc;
+ PUCHAR p, q;
+ USHORT i;
+
+ p = OpenP->Stress->Results->Address;
+ q = OpenP->StationAddress;
+
+ for ( i=0;i<OpenP->Media->AddressLen;i++ )
+ {
+ *p++ = *q++;
+ }
+
+ res = OpenP->Stress->Results;
+ gc = OpenP->GlobalCounters;
+
+ res->OpenInstance = OpenP->OpenInstance;
+ res->NumServers = OpenP->Stress->Client->NumServers;
+
+ res->Global.Sends = gc->Sends;
+ res->Global.SendComps = gc->SendComps;
+ res->Global.Receives = gc->Receives;
+ res->Global.ReceiveComps = gc->ReceiveComps;
+ res->Global.CorruptRecs = gc->CorruptRecs;
+ res->Global.InvalidPacketRecs = gc->InvalidPacketRecs;
+
+ //
+ // Now calculate the Packets Per Second value.
+ //
+
+ // first find the total number of test packets sent.
+
+ gc->Sends = 0;
+ gc->Receives = 0;
+
+ for ( i = 0 ; i < OpenP->Stress->Client->NumServers ; i++ )
+ {
+ ic = OpenP->Stress->Client->Servers[i].Counters;
+ gc->Sends += ic->Sends;
+ gc->Receives += ic->Receives;
+ }
+
+ // find the total test time in Nanoseconds
+
+ OpenP->Stress->EndTime = RtlLargeIntegerSubtract( OpenP->Stress->EndTime,
+ OpenP->Stress->StartTime );
+ // convert it to seconds.
+
+ OpenP->Stress->EndTime = RtlExtendedLargeIntegerDivide( OpenP->Stress->EndTime,
+ 10000000,
+ NULL );
+
+ // then determine the packets per second value.
+ // NOTE: we are assuming that the high part of time is now 0.
+
+ res->PacketsPerSecond = OpenP->Stress->PacketsPerSecond =
+ (( gc->Sends + gc->Receives ) / OpenP->Stress->EndTime.LowPart );
+
+ //
+ // Now copy the Server stats into the buffer.
+ //
+
+ for( i=0;i<OpenP->Stress->Client->NumServers;i++ )
+ {
+ ic = OpenP->Stress->Client->Servers[i].Counters;
+ lc = &res->Servers[i].Instance;
+
+ lc->Sends = ic->Sends;
+ lc->SendPends = ic->SendPends;
+ lc->SendComps = ic->SendComps;
+ lc->SendFails = ic->SendFails;
+ lc->Receives = ic->Receives;
+ ic->ReceiveComps = ic->ReceiveComps;
+ lc->CorruptRecs = ic->CorruptRecs;
+ }
+}
+
+
+
+VOID
+TpCopyServerStatistics(
+ IN POPEN_BLOCK OpenP,
+ IN PVOID Buffer,
+ IN INT ServerReference
+ )
+
+// -----------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// None.
+//
+// -------------
+
+{
+ PSERVER_RESULTS res;
+ PINSTANCE_COUNTERS ic;
+ PGLOBAL_COUNTERS gc;
+ PUCHAR p, q;
+ USHORT i;
+
+ res = &OpenP->Stress->Results->Servers[ServerReference];
+
+ ic = (PINSTANCE_COUNTERS)((PUCHAR)Buffer +
+ (ULONG)sizeof( PACKET_INFO ) +
+ (ULONG)sizeof( STRESS_CONTROL ));
+
+ gc = (PGLOBAL_COUNTERS)((PUCHAR)Buffer +
+ (ULONG)( sizeof( PACKET_INFO ) +
+ sizeof( STRESS_CONTROL ) +
+ sizeof( INSTANCE_COUNTERS )));
+
+ res->OpenInstance = OpenP->Stress->Client->Servers[ServerReference].ServerInstance;
+
+ res->StatsRcvd = TRUE;
+
+ // p = res->Address;
+ p = OpenP->Stress->Results->Servers[ServerReference].Address;
+ q = OpenP->Stress->Client->Servers[ServerReference].Address;
+
+ for ( i=0;i<OpenP->Media->AddressLen;i++ )
+ {
+ *p++ = *q++;
+ }
+
+ //
+ // Now copy the servers instance counters into the results buffer array.
+ //
+
+ res->S_Instance.Sends = ic->Sends;
+ res->S_Instance.SendPends = ic->SendPends;
+ res->S_Instance.SendComps = ic->SendComps;
+ res->S_Instance.SendFails = ic->SendFails;
+
+ res->S_Instance.Receives = ic->Receives;
+ res->S_Instance.ReceiveComps = ic->ReceiveComps;
+ res->S_Instance.CorruptRecs = ic->CorruptRecs;
+
+ res->S_Instance.XferData = ic->XferData;
+ res->S_Instance.XferDataPends = ic->XferDataPends;
+ res->S_Instance.XferDataComps = ic->XferDataComps;
+ res->S_Instance.XferDataFails = ic->XferDataFails;
+
+ //
+ // and the servers global counters.
+ //
+
+ res->S_Global.Sends = gc->Sends;
+ res->S_Global.SendComps = gc->SendComps;
+ res->S_Global.Receives = gc->Receives;
+ res->S_Global.ReceiveComps = gc->ReceiveComps;
+
+ res->S_Global.CorruptRecs = gc->CorruptRecs;
+ res->S_Global.InvalidPacketRecs = gc->InvalidPacketRecs;
+}
+
+
+
+VOID
+TpWriteServerStatistics(
+ IN POPEN_BLOCK OpenP,
+ IN OUT PNDIS_PACKET Packet,
+ IN PCLIENT_INFO Client
+ )
+
+// -----------------
+//
+// Routine Description:
+//
+//
+// NOTE: This routine requires a packet with one single contiguous
+// buffer, it does not attempt to write to any other buffers.
+//
+// Arguments:
+//
+// OpenP - A pointer to the OPEN_BLOCK describing the Server.
+//
+// Return Value:
+//
+// None.
+//
+// -----------------
+
+{
+ PNDIS_BUFFER Buffer;
+ PUCHAR Memory;
+ UINT BufLen;
+
+
+ NdisQueryPacket(Packet,NULL,NULL,&Buffer,NULL);
+
+ NdisQueryBuffer( Buffer,(PVOID *)&Memory,&BufLen );
+
+ RtlMoveMemory( Memory + sizeof( STRESS_PACKET ),
+ (PVOID)Client->Counters,
+ sizeof( INSTANCE_COUNTERS ) );
+
+ RtlMoveMemory( Memory + (ULONG) ( sizeof( STRESS_PACKET ) +
+ sizeof( INSTANCE_COUNTERS )),
+ (PVOID)OpenP->GlobalCounters,
+ sizeof( GLOBAL_COUNTERS ) );
+}
+
+
+
+VOID
+TpPrintClientStatistics(
+ POPEN_BLOCK OpenP
+ )
+
+// --------------
+//
+// Routine Description:
+//
+// This routine dumps the interesting statistics held in the Client's
+// Test Protocol data structures at the end of the test.
+//
+// Arguments:
+//
+// OpenP - A pointer to the OPEN_BLOCK describing the Client.
+//
+// Return Value:
+//
+// None.
+//
+// --------------
+
+{
+ PGLOBAL_COUNTERS GCounters;
+ PINSTANCE_COUNTERS ICounters;
+ PSERVER_INFO Server;
+ USHORT i;
+
+ //
+ // Print out the Client Network Address and Test Counters.
+ //
+
+ IF_TPDBG ( TP_DEBUG_STATISTICS )
+ {
+ TpPrint0("\n\t****** CLIENT STATISTICS ******\n\n");
+ if ( OpenP->Media->MediumType == NdisMediumArcnet878_2 )
+ {
+ TpPrint1("\tLocal Address %x\t", OpenP->StationAddress[0]);
+ }
+ else
+ {
+ TpPrint6("\tLocal Address %x-%x-%x-%x-%x-%x\t",
+ OpenP->StationAddress[0],OpenP->StationAddress[1],
+ OpenP->StationAddress[2],OpenP->StationAddress[3],
+ OpenP->StationAddress[4],OpenP->StationAddress[5]);
+ }
+ TpPrint1("OpenInstance %d\n",OpenP->OpenInstance);
+
+ TpPrint0("\n\t****** Global Statistics ******\n\n");
+
+ GCounters = OpenP->GlobalCounters;
+
+ GCounters->Sends = 0;
+ GCounters->Receives = 0;
+
+ for (i=0;i<OpenP->Stress->Client->NumServers;i++)
+ {
+ ICounters = OpenP->Stress->Client->Servers[i].Counters;
+ GCounters->Sends += ICounters->Sends;
+ GCounters->Receives += ICounters->Receives;
+ }
+
+ TpPrint1("\tTotal Packets Sent:\t\t%8lu\n",GCounters->Sends);
+ TpPrint1("\tTotal Packets Received:\t\t%8lu\n",GCounters->Receives);
+ TpPrint1("\tTotal Packets Lost:\t\t%8lu\n\n", GCounters->Sends-GCounters->Receives);
+
+ TpPrint1("\tTotal Packet Sends Completed:\t%8lu\n", GCounters->SendComps);
+ TpPrint1("\tTotal Packet Receives Completed:%8lu\n\n", GCounters->ReceiveComps);
+
+ TpPrint1("\tCorrupted Packet Receives:\t%8lu\n", GCounters->CorruptRecs);
+ TpPrint1("\tInvalid Packet Receives:\t%8lu\n", GCounters->InvalidPacketRecs);
+
+ //
+ // And then print out the information about each of the Servers
+ // involved in the test.
+ //
+
+ TpPrint0("\n\t***** Remote Server Statistics ******\n\n");
+
+ TpPrint1("\tClient at this address has %d Server(s) as follows:\n",
+ OpenP->Stress->Client->NumServers);
+
+ for (i=0;i<OpenP->Stress->Client->NumServers;i++)
+ {
+ Server = &OpenP->Stress->Client->Servers[i];
+
+ if ( OpenP->Media->MediumType == NdisMediumArcnet878_2 )
+ {
+ TpPrint1("\n\tRemote Server Address %x, ", Server->Address[0]);
+ }
+ else
+ {
+ TpPrint6("\n\tRemote Server Address %x-%x-%x-%x-%x-%x, ",
+ Server->Address[0],Server->Address[1],Server->Address[2],
+ Server->Address[3],Server->Address[4],Server->Address[5]);
+ }
+
+ TpPrint1("OpenInstance %d\n\n",Server->ServerInstance);
+
+ ICounters = Server->Counters;
+
+ TpPrint1("\tTotal Packets Sent To:\t\t%8lu\n", ICounters->Sends);
+ TpPrint1("\tTotal Packets Received From:\t%8lu\n", ICounters->Receives);
+ TpPrint1("\tTotal Packets Lost:\t\t%8lu\n\n", ICounters->Sends-ICounters->Receives);
+
+ TpPrint1("\tPacket Sends Failed:\t\t%8lu\n", ICounters->SendFails);
+ TpPrint1("\tPacket Sends Pended:\t\t%8lu\n", ICounters->SendPends);
+ TpPrint1("\tPacket Sends Completed:\t\t%8lu\n\n", ICounters->SendComps);
+ }
+ }
+}
+
+
+
+VOID
+TpPrintServerStatistics(
+ POPEN_BLOCK OpenP,
+ PCLIENT_INFO Client
+ )
+
+// --------------
+//
+// Routine Description:
+//
+// This routine dumps the interesting statistics held in the Server's
+// Test Protocol data structures at the end of the test, and information
+// about the Client that the Server was cooperating with.
+//
+// Arguments:
+//
+// OpenP - A pointer to the OPEN_BLOCK describing the Server.
+//
+// Client - A pointer to the CLIENT_INFO structure describing the
+// Client this Server was responding to.
+//
+// Return Value:
+//
+// None.
+//
+// ----------------
+
+{
+ PINSTANCE_COUNTERS ICounters;
+
+ //
+ // Print out the Server's Network Address and Test Counters.
+ //
+ IF_TPDBG ( TP_DEBUG_STATISTICS )
+ {
+ TpPrint0("\t****** SERVER STATISTICS ******\n\n");
+
+ if ( OpenP->Media->MediumType == NdisMediumArcnet878_2 )
+ {
+ TpPrint1("\tLocal Address %x\t", OpenP->StationAddress[0]);
+ }
+ else
+ {
+ TpPrint6("\tLocal Address %x-%x-%x-%x-%x-%x\t",
+ OpenP->StationAddress[0],OpenP->StationAddress[1],
+ OpenP->StationAddress[2],OpenP->StationAddress[3],
+ OpenP->StationAddress[4],OpenP->StationAddress[5]);
+ }
+
+ TpPrint1("OpenInstance %d\n",OpenP->OpenInstance);
+
+ TpPrint0("\n\t****** Client Instance Statistics ******\n");
+
+ if ( OpenP->Media->MediumType == NdisMediumArcnet878_2 )
+ {
+ TpPrint1("\n\tRemote Client Address %x, ", Client->Address[0]);
+ }
+ else
+ {
+ TpPrint6("\n\tRemote Client Address %x-%x-%x-%x-%x-%x, ",
+ Client->Address[0],Client->Address[1],Client->Address[2],
+ Client->Address[3],Client->Address[4],Client->Address[5]);
+ }
+ TpPrint1("OpenInstance %d\n\n",Client->ClientInstance);
+
+ //
+ // And then print out the information about the Client involved
+ // in the test.
+ //
+
+ ICounters = Client->Counters;
+
+ TpPrint1("\tPackets Received:\t\t%8lu\n",ICounters->Receives);
+ TpPrint1("\tPackets Sent:\t\t\t%8lu\n",ICounters->Sends);
+ TpPrint1("\tPackets Not Responded To:\t%8lu\n\n", ICounters->Receives-ICounters->Sends);
+
+ TpPrint1("\tPacket Sends Failed:\t\t%8lu\n",ICounters->SendFails);
+ TpPrint1("\tPacket Sends Pended:\t\t%8lu\n",ICounters->SendPends);
+ TpPrint1("\tPacket Sends Completed:\t\t%8lu\n", ICounters->SendComps);
+ TpPrint1("\tPacket Receives Completed:\t%8lu\n\n", ICounters->ReceiveComps);
+ }
+}
+
+
+
+VOID
+TpWriteSendReceiveResults(
+ PINSTANCE_COUNTERS Counters,
+ PIRP Irp
+ )
+
+// ------------
+//
+// Routine Description:
+//
+// Write the SEND test statistics into the Output buffer passed
+// in by the IOCTL call. The buffer is in the Irp->MdlAddress.
+// NOTE: The OpenP->SpinLock must be held when making this call.
+//
+// Arguments:
+//
+// OpenP - The location of the Irp to find the Output buffer on.
+//
+// Counters - The counters to write into the Output buffer into.
+//
+// Return Value:
+//
+// None.
+//
+// -------------
+
+{
+ PSEND_RECEIVE_RESULTS OutputBuffer;
+
+ //
+ // Get the output buffer out of the MDL stored in the IRP, and map
+ // it so we may write the statistics to it.
+ //
+
+ OutputBuffer = MmGetSystemAddressForMdl( Irp->MdlAddress );
+
+ //
+ // Write the statistics to the outbuffer
+ //
+
+ OutputBuffer->Signature = SENDREC_RESULTS_SIGNATURE;
+ OutputBuffer->ResultsExist = TRUE;
+
+ OutputBuffer->Counters.Sends = Counters->Sends;
+ OutputBuffer->Counters.SendPends = Counters->SendPends;
+ OutputBuffer->Counters.SendComps = Counters->SendComps;
+ OutputBuffer->Counters.SendFails = Counters->SendFails;
+
+ OutputBuffer->Counters.Receives = Counters->Receives;
+ OutputBuffer->Counters.ReceiveComps = Counters->ReceiveComps;
+ OutputBuffer->Counters.CorruptRecs = Counters->CorruptRecs;
+
+ OutputBuffer->Counters.XferData = Counters->XferData;
+ OutputBuffer->Counters.XferDataPends = Counters->XferDataPends;
+ OutputBuffer->Counters.XferDataComps = Counters->XferDataComps;
+ OutputBuffer->Counters.XferDataFails = Counters->XferDataFails;
+}
+
+
+
+VOID
+TpInitializePending(
+ PPENDING Pend
+ )
+
+// ----------
+//
+// Routine Description:
+//
+// This routine zeroes the counters in a PENDING_WATCH structure, and
+// sets up the storage area for pending packets.
+//
+// Arguments:
+//
+// Pend - A pointer to the Pend Structure to be zeroed.
+//
+// Return Value:
+//
+// None.
+//
+// ----------
+
+{
+ INT i;
+
+ //
+ // set up the pending packet storage and counters.
+ //
+
+ Pend->PendingPackets = 0;
+ Pend->PendingRequests = 0;
+ Pend->PacketPendNumber = 0;
+ Pend->PacketCompleteNumber = 0;
+
+ for ( i=0 ; i<NUM_PACKET_PENDS ; i++ )
+ {
+ Pend->Packets[i] = NULL;
+ }
+}
+
+
+
+VOID
+TpInitializeStressResults(
+ PSTRESS_RESULTS Results
+ )
+
+// ---------
+//
+// Routine Description:
+//
+// Arguments:
+//
+// Return Value:
+//
+// None.
+//
+// ---------
+
+{
+ INT i;
+
+ NdisZeroMemory((PVOID)Results,sizeof( STRESS_RESULTS ));
+
+ Results->Signature = STRESS_RESULTS_SIGNATURE;
+
+ for ( i=0;i<MAX_SERVERS;i++ )
+ {
+ Results->Servers[i].Signature = STRESS_RESULTS_SIGNATURE;
+ }
+}
+
+
+#if 0
+
+// do it on a per open basis.
+
+
+VOID
+TpDumpInfo(
+ VOID
+ )
+
+// --------------
+//
+// Routine Description:
+//
+// TpDumpInfo is a debugging routine that may be called from the kernel
+// debugger by resetting EIP to the entry of TpDumpInfo to dump the state
+// for the Test Protocol at any given time.
+//
+// NOTE: This routine does not reset the stack so care must be used if
+// one wishes to continue running the Test Protocol after this
+// procedure has executed. This routine was designed to dump
+// the state of the Protocol after a system crash.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+// --------------
+
+{
+ static POPEN_BLOCK OpenP;
+ static PSTRESS_ARGUMENTS Args;
+ static PCLIENT_STORAGE Client;
+ static PSERVER_STORAGE Server;
+ static PGLOBAL_COUNTERS GCounters
+ static PINSTANCE_COUNTERS ICounters;
+ static INT i;
+
+ OpenP = OpenList;
+
+ TpPrint0("****** Open Block Structure ******\n\n");
+
+ TpPrint1("Ndis Handle\t\t%10lX\n",OpenP->NdisBindingHandle);
+ TpPrint1("Next Open Block\t\t%10lX\n",OpenP->Next);
+ TpPrint1("Open Instance\t\t%10ld\n",OpenP->OpenInstance);
+
+ if ( OpenP->Media->NdisMedium == NdisMediumArcnet878_2 )
+ {
+ TpPrint1("Machine Address \t%x\n\n", OpenP->StationAddress[0] );
+ }
+ else
+ {
+ TpPrint6("Machine Address \t%x-%x-%x-%x-%x-%x\n\n",
+ OpenP->StationAddress[0],OpenP->StationAddress[1],
+ OpenP->StationAddress[2],OpenP->StationAddress[3],
+ OpenP->StationAddress[4],OpenP->StationAddress[5]);
+ }
+
+ TpPrint0("****** Test Arguments Structure ******\n\n");
+
+ Args = OpenP->Arguments;
+
+ TpPrint1("MemberType\t\t%10d\n",Args->MemberType);
+ TpPrint1"PACKET_TYPE\t\t%10d\n",Args->PacketType);
+ TpPrint1("Packet Size Value\t%10d\n",Args->PacketSize);
+ TpPrint1("PACKET_MAKEUP\t\t%10d\n",Args->PacketMakeUp);
+ TpPrint1("RESPONSE_TYPE\t\t%10d\n",Args->ResponseType);
+ TpPrint1("Iterations So Far\t%10lu\n",Args->Iterations);
+ TpPrint1("Total Iterations\t%10lu\n",Args->TotalIterations);
+ TpPrint1("Total Packets\t\t%10lu\n",Args->TotalPackets);
+ TpPrint1("Interpacket Delay\t%10lu\n",Args->DelayLength);
+ TpPrint1("All Packets Sent?\t\t%s\n",(Args->AllPacketsSent) ? "TRUE" : "FALSE");
+ TpPrint1("Window Enabled?\t\t\t%s\n",(Args->WindowEnabled) ? "TRUE" : "FALSE");
+ TpPrint1("Data Checking?\t\t\t%s\n",(Args->DataChecking) ? "TRUE" : "FALSE");
+ TpPrint1("Packets From Pool?\t\t%s\n",(Args->PacketsFromPool) ? "TRUE" : "FALSE");
+ TpPrint1("Begin Receives?\t\t\t%s\n",(Args->BeginReceives) ? "TRUE" : "FALSE");
+ TpPrint1("Server Continue?\t\t\t%s\n\n",(Args->ServerContinue) ? "TRUE" : "FALSE");
+
+ TpPrint0("****** Global Counters Structure ******\n\n");
+
+ GCounters = OpenP->GlobalCounters;
+
+ TpPrint1("Packet Sends\t\t\t%10lu\n",GCounters->Sends);
+ TpPrint1("Packet Receives\t\t%10lu\n",GCounters->Receives);
+ TpPrint1("Corrupted Packet Receives\t%10lu\n",GCounters->CorruptRecs);
+ TpPrint1("Invalid Protocol Receives\t%10lu\n",GCounters->InvalidPacketRecs);
+
+ if (OpenP->Stress->Client != NULL)
+ {
+ TpPrint0("****** Client Storage Structure ******\n\n");
+
+ Client = OpenP->Stress->Client;
+
+ TpPrint1("Number of Servers\t\t%10ld\n",Client->NumServers);
+ TpPrint1("Packet Pool\t\t\t%10lX\n",Client->PacketPool);
+ TpPrint1("Transmit Pool\t\t\t%10lX\n",Client->TransmitPool);
+
+ TpPrint0("\n****** Servers with this Client ******\n\n");
+
+ for (i=0;i<Client->NumServers;i++)
+ {
+ TpPrint1("****** Server Number %d ******\n\n",i+1);
+ TpPrint1("Server Instance\t\t\t%10ld\n",Client->Servers[i].ServerInstance);
+ TpPrint1("Client Reference\t\t%10ld\n",Client->Servers[i].ClientReference);
+ TpPrint1("Server Reference\t\t\t%10ld\n",Client->Servers[i].ServerReference);
+
+ if ( OpenP->Media->NdisMedium == NdisMediumArcnet878_2 )
+ {
+ TpPrint1("Server[%d] Address\t%x\n",i, Client->Servers[i].Address[0]);
+ }
+ else
+ {
+ TpPrint6("Server[%d] Address\t%x-%x-%x-%x-%x-%x\n",i,
+ Client->Servers[i].Address[0],Client->Servers[i].Address[1],
+ Client->Servers[i].Address[2],Client->Servers[i].Address[3],
+ Client->Servers[i].Address[4],Client->Servers[i].Address[5]);
+ }
+
+ TpPrint1("Sequence Number\t\t\t%10lu\n",Client->Servers[i].SequenceNumber);
+ TpPrint1("Max Sequence Number\t\t%10lu\n",Client->Servers[i].MaxSequenceNumber);
+ TpPrint1("Packet Delay\t\t\t%10lu\n\n", Client->Servers[i].PacketDelay);
+
+ ICounters = Client->Servers[i].Counters;
+
+ TpPrint1("****** Server Number %d's Counters ******\n\n",i+1);
+ TpPrint1("Packet Sends\t\t\t%10lu\n",ICounters->Sends);
+ TpPrint1("Packet Send Pends\t\t%10lu\n",ICounters->SendPends);
+ TpPrint1("Packet Send Completes\t\t%10lu\n",ICounters->SendComps);
+ TpPrint1("Packet Send Fails\t\t%10lu\n",ICounters->SendFails);
+ TpPrint1("Packet Receives\t\t\t%10lu\n",ICounters->Receives);
+ TpPrint1("Corrupted Packet Receives\t%10lu\n",ICounters->CorruptRecs);
+ }
+ }
+
+ if (OpenP->Stress->Server != NULL)
+ {
+ TpPrint0("****** Server Storage Structure ******\n\n");
+
+ Server = OpenP->Stress->Server;
+
+ TpPrint1("Number of Clients\t%10ld\n",Server->NumClients);
+ TpPrint1("Number of Active Clients%10ld\n",Server->ActiveClients);
+ TpPrint1("Packet Pool\t\t%10lX\n",Server->PacketPool);
+ TpPrint1("Transmit Pool\t\t%10lX\n\n",Server->TransmitPool);
+
+ TpPrint0("******Clients with this Server******\n\n");
+
+ for (i=0;i<Server->NumClients;i++)
+ {
+ TpPrint1("****** Client Number %d ******\n\n",i+1);
+ TpPrint1("Client Instance\t\t%10ld\n",Server->Clients[i].ClientInstance);
+ TpPrint1("Client Reference\t%10ld\n",Server->Clients[i].ClientReference);
+ TpPrint1("Data Checking\t\t\t%s\n",
+ (Server->Clients[i].DataChecking) ? "TRUE" : "FALSE");
+
+ if ( OpenP->Media->NdisMedium == NdisMediumArcnet878_2 )
+ {
+ TpPrint1("Client[%d] Address\t%x\n\n",i, Server->Clients[i].Address[0]);
+ }
+ else
+ {
+ TpPrint6("Client[%d] Address\t%x-%x-%x-%x-%x-%x\n\n",i,
+ Server->Clients[i].Address[0],Server->Clients[i].Address[1],
+ Server->Clients[i].Address[2],Server->Clients[i].Address[3],
+ Server->Clients[i].Address[4],Server->Clients[i].Address[5]);
+ }
+
+ ICounters = Server->Clients[i].Counters;
+
+ TpPrint1("****** Client Number %d's ICountersers ******\n\n",i);
+ TpPrint1("Packet Sends\t\t\t%10lu\n",ICounters->Sends);
+ TpPrint1("Packet Send Pends\t\t%10lu\n",ICounters->SendPends);
+ TpPrint1("Packet Send Completes\t\t%10lu\n",ICounters->SendComps);
+ TpPrint1("Packet Send Fails\t\t%10lu\n",ICounters->SendFails);
+ TpPrint1("Packet Receives\t\t\t%10lu\n",ICounters->Receives);
+ TpPrint1("Corrupted Packet Receives\t%10lu\n",ICounters->CorruptRecs);
+ }
+ }
+
+ TpPrint0("\n\n\n");
+
+ ASSERT( FALSE );
+}
+
+#endif
+
diff --git a/private/ntos/ndis/testprot/tpkd/makefile b/private/ntos/ndis/testprot/tpkd/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpkd/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/testprot/tpkd/sources b/private/ntos/ndis/testprot/tpkd/sources
new file mode 100644
index 000000000..92652ad3e
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpkd/sources
@@ -0,0 +1,55 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=testprot
+
+TARGETNAME=tpkd
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\libc.lib \
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib
+
+DLLBASE=0x1010000
+
+INCLUDES=..\inc;..\..\inc;..\..\..\inc;..\..\..\..\inc
+
+SOURCES=tpkd.c
+
+i386_SOURCES=
+MIPS_SOURCES=
+
+386_STDCALL=1
+MIPS_FLAGS=-D_stdcall
+
+UMTYPE=console
+OPTIONAL_NTTEST=
+
+!IFNDEF 386_WARNING_LEVEL
+386_WARNING_LEVEL=/W3
+!ENDIF
+
+!IFNDEF MIPS_WARNINGS
+MIPS_WARNINGS=-std
+!ENDIF
diff --git a/private/ntos/ndis/testprot/tpkd/tpkd.c b/private/ntos/ndis/testprot/tpkd/tpkd.c
new file mode 100644
index 000000000..fb208dbc4
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpkd/tpkd.c
@@ -0,0 +1,450 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ kdndis.c
+
+Abstract:
+
+ Ndis Testprot Kernel Debugger extension
+
+ This module contains a set of useful kernel debugger extensions for the
+ NT MAC Tester
+
+Author:
+
+ Sanjeev Katariya May-6-1993
+
+Revision History:
+
+ Created
+
+--*/
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <windows.h>
+#include <ntkdexts.h>
+#include <stdlib.h>
+#include <malloc.h>
+
+#include "tpkd.h"
+
+
+VOID
+DumpNdisPacket(
+ PNTKD_OUTPUT_ROUTINE OutputRoutine,
+ PNTKD_READ_VIRTUAL_MEMORY ReadMemoryRoutine,
+ PNDIS_PACKET NdisPacket,
+ DWORD AddressNdisPacket
+ )
+{
+
+ NDIS_BUFFER NdisBuffer;
+ DWORD BufferAddress;
+ BOOL ReadMemory = FALSE;
+ INT i;
+
+ (OutputRoutine)( "\nNDIS_PACKET at Memory location: 0x%lx\n", AddressNdisPacket );
+
+ (OutputRoutine)( "\tNDIS_PACKET_PRIVATE\n" );
+ (OutputRoutine)( "\t\tPhysical Count : %ld\n" , NdisPacket->Private.PhysicalCount );
+ (OutputRoutine)( "\t\tTotal Length : %ld\n" , NdisPacket->Private.TotalLength );
+ (OutputRoutine)( "\t\tNdis Buffer Head Ptr : 0x%lx\n", NdisPacket->Private.Head );
+ (OutputRoutine)( "\t\tNdis Buffer Tail Ptr : 0x%lx\n", NdisPacket->Private.Tail );
+ (OutputRoutine)( "\t\tNdis Packet Pool Ptr : 0x%lx\n", NdisPacket->Private.Pool );
+ (OutputRoutine)( "\t\tCount : %ld\n" , NdisPacket->Private.Count );
+ (OutputRoutine)( "\t\tFlags : 0x%lx\n", NdisPacket->Private.Flags );
+ (OutputRoutine)( "\t\tValid Counts : %d\n" , NdisPacket->Private.ValidCounts );
+ (OutputRoutine)( "\t\tMacReserved : " );
+
+ for( i = 0; i < 16; i++ ) {
+ (OutputRoutine)( "0x%2.2x", NdisPacket->MacReserved[i] );
+ }
+ (OutputRoutine)( "\n\t\tProtocolReserved : 0x%2.2x\n", NdisPacket->ProtocolReserved[0] );
+
+
+ //
+ // And now the NDIS_BUFFER chain
+ //
+ BufferAddress = NdisPacket->Private.Head;
+
+ try {
+
+ ReadMemory = (ReadMemoryRoutine)( (LPVOID)BufferAddress,
+ &NdisBuffer,
+ sizeof( NDIS_BUFFER ),
+ NULL
+ );
+
+ } except ( EXCEPTION_ACCESS_VIOLATION ) {
+
+ (OutputRoutine)( "The routine was unable to access NDIS_BUFFER number of bytes.\n" );
+ (OutputRoutine)( "Possible bad NDIS_BUFFER address 0x%lx\n", BufferAddress );
+ return;
+
+ }
+
+ while ( ReadMemory ) {
+
+ DumpNdisBuffer( OutputRoutine, ReadMemoryRoutine, &NdisBuffer, BufferAddress );
+
+ BufferAddress = NdisBuffer.Next;
+ (OutputRoutine)( "\n\tNext NDIS_BUFFER at address 0x%lx\n", BufferAddress );
+
+ try {
+
+ ReadMemory = (ReadMemoryRoutine)( (LPVOID)BufferAddress,
+ &NdisBuffer,
+ sizeof( NDIS_BUFFER ),
+ NULL
+ );
+
+ } except ( EXCEPTION_ACCESS_VIOLATION ) {
+
+ (OutputRoutine)( "The routine was unable to access NDIS_BUFFER number of bytes.\n" );
+ (OutputRoutine)( "Possible bad NDIS_BUFFER address 0x%lx\n", BufferAddress );
+ return;
+
+ }
+ }
+
+}
+
+
+VOID
+DumpNdisBuffer(
+ PNTKD_OUTPUT_ROUTINE OutputRoutine,
+ PNTKD_READ_VIRTUAL_MEMORY ReadMemoryRoutine,
+ PNDIS_BUFFER NdisBuffer,
+ DWORD AddressNdisBuffer
+ )
+{
+ ULONG i;
+ BOOL ReadMemory = FALSE;
+ PUCHAR Buffer = calloc( NdisBuffer->ByteCount, sizeof( UCHAR ) );
+
+ (OutputRoutine)( "\n\tNDIS_BUFFER at Memory location: 0x%lx\n", AddressNdisBuffer );
+
+ (OutputRoutine)( "\t\tNext Buffer : 0x%lx\n", NdisBuffer->Next );
+ (OutputRoutine)( "\t\tSize : %d\n" , NdisBuffer->Size );
+ (OutputRoutine)( "\t\tMDL Flags : 0x%x\n" , NdisBuffer->MdlFlags );
+ (OutputRoutine)( "\t\tEPROCESS Ptr : 0x%lx\n", NdisBuffer->Process );
+ (OutputRoutine)( "\t\tMapped System VA : 0x%lx\n", NdisBuffer->MappedSystemVa );
+ (OutputRoutine)( "\t\tStart VA : 0x%lx\n", NdisBuffer->StartVa );
+ (OutputRoutine)( "\t\tByte Count : 0x%lx\n", NdisBuffer->ByteCount);
+ (OutputRoutine)( "\t\tByte Offset : 0x%lx\n", NdisBuffer->ByteOffset );
+ (OutputRoutine)( "\t\tVA Contents\n" );
+
+
+ if ( Buffer != NULL ) {
+
+ try {
+
+ ReadMemory = (ReadMemoryRoutine)( (LPVOID)NdisBuffer->StartVa,
+ Buffer,
+ NdisBuffer->ByteCount,
+ NULL
+ );
+
+ } except ( EXCEPTION_ACCESS_VIOLATION ) {
+
+ (OutputRoutine)( "The routine was unable to access Byte Count number of bytes.\n" );
+ (OutputRoutine)( "Possible bad StartVa address 0x%lx\n", NdisBuffer->StartVa );
+ ReadMemory = FALSE;
+
+ }
+
+ if ( ReadMemory ) {
+
+ for( i = 0; i < NdisBuffer->ByteCount ; i++ ) {
+
+ if ( (i%16) == 0 ) {
+
+ (OutputRoutine)( "\n\t\t%2x", Buffer[i] );
+
+ } else {
+
+ (OutputRoutine)( "-%2x", Buffer[i] );
+
+ }
+ }
+ (OutputRoutine)( "\n" );
+ free( Buffer );
+ return;
+
+ }
+
+ free( Buffer );
+
+ }
+
+ (OutputRoutine)( "Unable to access contents of StartVa: 0x%lx\n", NdisBuffer->StartVa );
+
+
+}
+
+
+VOID
+DumpOpenBuffer(
+ PNTKD_OUTPUT_ROUTINE OutputRoutine,
+ PNTKD_READ_VIRTUAL_MEMORY ReadMemoryRoutine,
+ POPEN_BLOCK OpenBuffer,
+ DWORD AddressOpenBuffer
+ )
+{
+ ULONG i;
+ BOOL ReadMemory = FALSE;
+
+ (OutputRoutine)( "\n\tOPEN_BLOCK at Memory location: 0x%lx\n\n", AddressOpenBuffer );
+
+ (OutputRoutine)( "\t\tNdisBindingHandle : 0x%lx\n", OpenBuffer->NdisBindingHandle );
+ (OutputRoutine)( "\t\tNdisProtocolHandle : 0x%lx\n", OpenBuffer->NdisProtocolHandle );
+ (OutputRoutine)( "\t\tOpenInstance : %d\n" , OpenBuffer->OpenInstance );
+ (OutputRoutine)( "\t\tClosing Status : %d\n" , OpenBuffer->Closing );
+ (OutputRoutine)( "\t\tStation Address : " );
+ for( i = 0 ; i < ADDRESS_LENGTH; i++ ) {
+ (OutputRoutine)( "%2.2x", OpenBuffer->StationAddress[i] );
+ }
+ (OutputRoutine)( "\n" );
+ (OutputRoutine)( "\t\tPtr to Adapter Name : 0x%lx\n", OpenBuffer->AdapterName );
+ (OutputRoutine)( "\t\tSpin Lock Resource : 0x%lx\n", OpenBuffer->SpinLock );
+ (OutputRoutine)( "\t\tReference Count : %d\n" , OpenBuffer->ReferenceCount );
+ (OutputRoutine)( "\t\tMedium Index : %d\n" , OpenBuffer->MediumIndex );
+ (OutputRoutine)( "\t\tPtr to Media Info : 0x%lx\n", OpenBuffer->Media );
+ (OutputRoutine)( "\t\tPtr to Global Counters : 0x%lx\n", OpenBuffer->GlobalCounters );
+ (OutputRoutine)( "\t\tPtr to Environment : 0x%lx\n", OpenBuffer->Environment );
+ (OutputRoutine)( "\t\tPtr to Stress Block : 0x%lx\n", OpenBuffer->Stress );
+ (OutputRoutine)( "\t\tPtr to Send Block : 0x%lx\n", OpenBuffer->Send );
+ (OutputRoutine)( "\t\tPtr to Receive Block : 0x%lx\n", OpenBuffer->Receive );
+ (OutputRoutine)( "\t\tPtr to Event Queue : 0x%lx\n", OpenBuffer->EventQueue );
+ (OutputRoutine)( "\t\tPtr to Pause Block : 0x%lx\n", OpenBuffer->Pause );
+ (OutputRoutine)( "\t\tPtr to Open Request Handle : 0x%lx\n", OpenBuffer->OpenReqHndl );
+ (OutputRoutine)( "\t\tPtr to Close Request Handle : 0x%lx\n", OpenBuffer->CloseReqHndl );
+ (OutputRoutine)( "\t\tPtr to Reset Request Handle : 0x%lx\n", OpenBuffer->ResetReqHndl );
+ (OutputRoutine)( "\t\tPtr to Request Request Handle: 0x%lx\n", OpenBuffer->RequestReqHndl );
+ (OutputRoutine)( "\t\tPtr to Stress Request Handle : 0x%lx\n", OpenBuffer->StressReqHndl );
+
+ (OutputRoutine)( "\t\tStatus IRP cancelled : %d\n" , OpenBuffer->IrpCancelled );
+ (OutputRoutine)( "\t\tPtr to IRP : 0x%lx\n", OpenBuffer->Irp );
+ (OutputRoutine)( "\t\tSignature : 0x%lx\n", OpenBuffer->Signature );
+
+}
+
+
+
+/*
+ ************************* Exported Routines **********************************
+ * *
+ * Method for invoking at debugger *
+ * *
+ * kd > !tpkd.ndispacket Address where Address is of type pointer *
+ * kd > !tpkd.ndisbuffer Address where Address is of type pointer *
+ * kd > !tpkd.openblock Address where Address is of type pointer *
+ * kd > !tpkd.help *
+ * *
+ *******************************************************************************
+*/
+
+
+VOID
+ndispacket(
+ DWORD CurrentPc,
+ PNTKD_EXTENSION_APIS ExtensionApis,
+ LPSTR ArgumentString
+ )
+{
+
+ PNTKD_OUTPUT_ROUTINE OutputRoutine ;
+ PNTKD_GET_EXPRESSION GetExpressionRoutine;
+ PNTKD_READ_VIRTUAL_MEMORY ReadMemoryRoutine ;
+ PNTKD_GET_SYMBOL GetSymbolRoutine ;
+ NDIS_PACKET Packet ;
+ DWORD AddressNdisPacket ;
+ BOOL ReadMemory = FALSE ;
+
+ OutputRoutine = ExtensionApis->lpOutputRoutine;
+ GetExpressionRoutine = ExtensionApis->lpGetExpressionRoutine;
+ GetSymbolRoutine = ExtensionApis->lpGetSymbolRoutine;
+ ReadMemoryRoutine = ExtensionApis->lpReadVirtualMemRoutine;
+
+ //
+ // Get the address of the NDIS_PACKET
+ AddressNdisPacket = (GetExpressionRoutine)(ArgumentString);
+ //
+ if ( !AddressNdisPacket ) {
+ return;
+ }
+
+ try {
+
+ //
+ // Now read the memory contents into our buffer area
+ //
+ ReadMemory = (ReadMemoryRoutine)( (LPVOID)AddressNdisPacket,
+ &Packet,
+ sizeof(NDIS_PACKET),
+ NULL
+ );
+ } except( EXCEPTION_ACCESS_VIOLATION ) {
+
+ (OutputRoutine)( "The routine was unable to access NDIS_PACKET size bytes.\n" );
+ (OutputRoutine)( "Possible bad NDIS_PACKET address 0x%lx\n", AddressNdisPacket );
+ ReadMemory = FALSE;
+
+ }
+
+ if ( !ReadMemory ) {
+ return;
+ }
+
+
+ DumpNdisPacket( OutputRoutine,
+ ReadMemoryRoutine,
+ &Packet,
+ AddressNdisPacket );
+
+}
+
+
+VOID
+ndisbuffer(
+ DWORD CurrentPc,
+ PNTKD_EXTENSION_APIS ExtensionApis,
+ LPSTR ArgumentString
+ )
+{
+
+ PNTKD_OUTPUT_ROUTINE OutputRoutine ;
+ PNTKD_GET_EXPRESSION GetExpressionRoutine;
+ PNTKD_READ_VIRTUAL_MEMORY ReadMemoryRoutine ;
+ PNTKD_GET_SYMBOL GetSymbolRoutine ;
+ NDIS_BUFFER NdisBuffer ;
+ DWORD AddressNdisBuffer ;
+ BOOL ReadMemory = FALSE ;
+
+ OutputRoutine = ExtensionApis->lpOutputRoutine;
+ GetExpressionRoutine = ExtensionApis->lpGetExpressionRoutine;
+ GetSymbolRoutine = ExtensionApis->lpGetSymbolRoutine;
+ ReadMemoryRoutine = ExtensionApis->lpReadVirtualMemRoutine;
+
+ //
+ // Get the address of the NDIS_PACKET
+ //
+
+ AddressNdisBuffer = (GetExpressionRoutine)(ArgumentString);
+ if ( !AddressNdisBuffer ) {
+ return;
+ }
+
+ try {
+
+ //
+ // Now read the memory contents into our buffer area
+ //
+ ReadMemory = (ReadMemoryRoutine)( (LPVOID)AddressNdisBuffer,
+ &NdisBuffer,
+ sizeof(NDIS_BUFFER),
+ NULL
+ );
+ } except( EXCEPTION_ACCESS_VIOLATION ) {
+
+ (OutputRoutine)( "The routine was unable to access NDIS_BUFFER size bytes.\n" );
+ (OutputRoutine)( "Possible bad NDIS_BUFFER address 0x%lx\n", AddressNdisBuffer );
+ ReadMemory = FALSE;
+
+ }
+
+ if ( !ReadMemory ) {
+ return;
+ }
+
+
+ DumpNdisBuffer( OutputRoutine,
+ ReadMemoryRoutine,
+ &NdisBuffer,
+ AddressNdisBuffer );
+
+}
+
+
+VOID
+openblock(
+ DWORD CurrentPc,
+ PNTKD_EXTENSION_APIS ExtensionApis,
+ LPSTR ArgumentString
+ )
+{
+
+ PNTKD_OUTPUT_ROUTINE OutputRoutine ;
+ PNTKD_GET_EXPRESSION GetExpressionRoutine;
+ PNTKD_READ_VIRTUAL_MEMORY ReadMemoryRoutine ;
+ PNTKD_GET_SYMBOL GetSymbolRoutine ;
+ OPEN_BLOCK OpenBuffer ;
+ DWORD AddressOpenBuffer ;
+ BOOL ReadMemory = FALSE ;
+
+ OutputRoutine = ExtensionApis->lpOutputRoutine;
+ GetExpressionRoutine = ExtensionApis->lpGetExpressionRoutine;
+ GetSymbolRoutine = ExtensionApis->lpGetSymbolRoutine;
+ ReadMemoryRoutine = ExtensionApis->lpReadVirtualMemRoutine;
+
+ //
+ // Get the address of the OPEN_BLOCK
+ //
+
+ AddressOpenBuffer = (GetExpressionRoutine)(ArgumentString);
+ if ( !AddressOpenBuffer ) {
+ return;
+ }
+
+ try {
+
+ //
+ // Now read the memory contents into our buffer area
+ //
+ ReadMemory = (ReadMemoryRoutine)( (LPVOID)AddressOpenBuffer,
+ &OpenBuffer,
+ sizeof(OPEN_BLOCK),
+ NULL
+ );
+ } except( EXCEPTION_ACCESS_VIOLATION ) {
+
+ (OutputRoutine)( "The routine was unable to access OPEN_BLOCK size bytes.\n" );
+ (OutputRoutine)( "Possible bad OPEN_BLOCK address 0x%lx\n", AddressOpenBuffer );
+ ReadMemory = FALSE;
+
+ }
+
+ if ( !ReadMemory ) {
+ return;
+ }
+
+
+ DumpOpenBuffer( OutputRoutine,
+ ReadMemoryRoutine,
+ &OpenBuffer,
+ AddressOpenBuffer );
+
+}
+
+VOID
+help(
+ DWORD CurrentPc,
+ PNTKD_EXTENSION_APIS ExtensionApis,
+ LPSTR ArgumentString
+ )
+{
+
+ PNTKD_OUTPUT_ROUTINE OutputRoutine;
+
+ OutputRoutine = ExtensionApis->lpOutputRoutine;
+
+ (OutputRoutine)( "The following commands are available\n" );
+ (OutputRoutine)( "\tndispacket <address>\n\tndisbuffer <address>\n\topenblock\n\thelp\n" );
+
+
+}
diff --git a/private/ntos/ndis/testprot/tpkd/tpkd.def b/private/ntos/ndis/testprot/tpkd/tpkd.def
new file mode 100644
index 000000000..9ee251527
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpkd/tpkd.def
@@ -0,0 +1,8 @@
+LIBRARY TPKD
+DESCRIPTION 'NDIS KD extensions'
+
+EXPORTS
+ ndispacket
+ ndisbuffer
+ openblock
+ help
diff --git a/private/ntos/ndis/testprot/tpkd/tpkd.h b/private/ntos/ndis/testprot/tpkd/tpkd.h
new file mode 100644
index 000000000..23942288d
--- /dev/null
+++ b/private/ntos/ndis/testprot/tpkd/tpkd.h
@@ -0,0 +1,781 @@
+//
+// I/O system definitions.
+//
+// Define a Memory Descriptor List (MDL)
+//
+// An MDL describes pages in a virtual buffer in terms of physical pages. The
+// pages associated with the buffer are described in an array that is allocated
+// just after the MDL header structure itself. In a future compiler this will
+// be placed at:
+//
+// ULONG Pages[];
+//
+// Until this declaration is permitted, however, one simply calculates the
+// base of the array by adding one to the base MDL pointer:
+//
+// Pages = (PULONG) (Mdl + 1);
+//
+// Notice that while in the context of the subject thread, the base virtual
+// address of a buffer mapped by an MDL may be referenced using the following:
+//
+// Mdl->StartVa | Mdl->ByteOffset
+//
+
+typedef struct _MDL {
+
+ struct _MDL *Next;
+ CSHORT Size;
+ CSHORT MdlFlags;
+ struct _EPROCESS *Process;
+ PVOID MappedSystemVa;
+ PVOID StartVa;
+ ULONG ByteCount;
+ ULONG ByteOffset;
+
+} MDL, *PMDL;
+
+typedef struct _IRP { ULONG Value; } IRP ;
+typedef struct _KEVENT { ULONG Value; } KEVENT;
+typedef struct _KDPC { ULONG Value; } KDPC ;
+typedef struct _KTIMER { ULONG Value; } KTIMER;
+
+typedef IRP *PIRP;
+typedef KEVENT *PKEVENT;
+typedef KDPC *PKDPC;
+typedef KTIMER *PKTIMER;
+
+
+//
+// NDIS DEFINITIONS
+//
+
+typedef MDL NDIS_BUFFER, * PNDIS_BUFFER;
+typedef ULONG NDIS_OID, *PNDIS_OID ;
+typedef PVOID NDIS_HANDLE, *PNDIS_HANDLE ;
+typedef NTSTATUS NDIS_STATUS ;
+
+
+typedef struct _NDIS_SPIN_LOCK {
+
+ KSPIN_LOCK SpinLock;
+ KIRQL OldIrql;
+
+} NDIS_SPIN_LOCK, * PNDIS_SPIN_LOCK;
+
+typedef struct _NDIS_PACKET_POOL {
+
+ NDIS_SPIN_LOCK SpinLock;
+ struct _NDIS_PACKET *FreeList; // linked list of free slots in pool
+ UINT PacketLength; // amount needed in each packet
+ UCHAR Buffer[1]; // actual pool memory
+
+} NDIS_PACKET_POOL, * PNDIS_PACKET_POOL;
+
+typedef struct _NDIS_PACKET_PRIVATE {
+
+ UINT PhysicalCount; // number of physical pages in packet.
+ UINT TotalLength; // Total amount of data in the packet.
+ PNDIS_BUFFER Head; // first buffer in the chain
+ PNDIS_BUFFER Tail; // last buffer in the chain
+ PNDIS_PACKET_POOL Pool; // so we know where to free it back to
+ UINT Count;
+ ULONG Flags;
+ BOOLEAN ValidCounts;
+
+} NDIS_PACKET_PRIVATE, * PNDIS_PACKET_PRIVATE;
+
+typedef struct _NDIS_PACKET {
+
+ NDIS_PACKET_PRIVATE Private;
+ UCHAR MacReserved[16];
+ UCHAR ProtocolReserved[1];
+
+} NDIS_PACKET, * PNDIS_PACKET;
+
+typedef enum _NDIS_REQUEST_TYPE {
+
+ NdisRequestQueryInformation,
+ NdisRequestSetInformation,
+ NdisRequestQueryStatistics,
+ NdisRequestOpen,
+ NdisRequestClose,
+ NdisRequestSend,
+ NdisRequestTransferData,
+ NdisRequestReset,
+ NdisRequestGeneric1,
+ NdisRequestGeneric2,
+ NdisRequestGeneric3,
+ NdisRequestGeneric4
+
+} NDIS_REQUEST_TYPE, *PNDIS_REQUEST_TYPE;
+
+typedef struct _NDIS_REQUEST {
+
+ UCHAR MacReserved[16];
+ NDIS_REQUEST_TYPE RequestType;
+ union _DATA {
+
+ struct _QUERY_INFORMATION {
+ NDIS_OID Oid;
+ PVOID InformationBuffer;
+ UINT InformationBufferLength;
+ UINT BytesWritten;
+ UINT BytesNeeded;
+ } QUERY_INFORMATION;
+
+ struct _SET_INFORMATION {
+ NDIS_OID Oid;
+ PVOID InformationBuffer;
+ UINT InformationBufferLength;
+ UINT BytesRead;
+ UINT BytesNeeded;
+ } SET_INFORMATION;
+
+ } DATA;
+
+} NDIS_REQUEST, *PNDIS_REQUEST;
+
+//
+// END OF NDIS DEFINITIONS
+//
+
+
+//
+// TPDEF DEFINITIONS
+//
+
+#define ADDRESS_LENGTH 6
+#define ADDRESS_LENGTH_1_OCTET 1
+#define MAX_SERVERS 10
+#define MAX_CLIENTS 10
+#define NUM_PACKET_PENDS 1000
+#define MAX_NUMBER_BUFFERS 2
+#define NUMBER_OF_POOL_PACKETS 10
+#define MAX_EVENT 20
+
+#include <packon.h>
+
+//
+// THE MEDIA HEADER
+//
+typedef struct _E_802_3 {
+
+ UCHAR DestAddress[ADDRESS_LENGTH];
+ UCHAR SrcAddress[ADDRESS_LENGTH];
+ UCHAR PacketSize_Hi;
+ UCHAR PacketSize_Lo;
+
+} E_802_3;
+
+typedef struct _TR_802_5 {
+
+ UCHAR AC;
+ UCHAR FC;
+ UCHAR DestAddress[ADDRESS_LENGTH];
+ UCHAR SrcAddress[ADDRESS_LENGTH];
+
+} TR_802_5;
+
+typedef struct _FDDI {
+
+ UCHAR FC;
+ UCHAR DestAddress[ADDRESS_LENGTH];
+ UCHAR SrcAddress[ADDRESS_LENGTH];
+
+} FDDI;
+
+typedef struct _ARCNET {
+
+ UCHAR SrcAddress[ADDRESS_LENGTH_1_OCTET] ;
+ UCHAR DestAddress[ADDRESS_LENGTH_1_OCTET];
+ UCHAR ProtocolID ;
+
+} ARCNET;
+
+typedef union _MEDIA_HEADER {
+
+ E_802_3 e;
+ TR_802_5 tr;
+ FDDI fddi;
+ ARCNET a;
+
+} MEDIA_HEADER ;
+
+//
+// THE TEST PROTOCOL HEADER
+//
+typedef struct _PACKET_INFO {
+
+ ULONG Signature;
+ ULONG PacketSize; // the total size of the packet
+ UCHAR DestInstance; // instance of the packet's dest ndis binding
+ UCHAR SrcInstance; // instance of the packet's src ndis binding
+ UCHAR PacketType; // type of packet; STRESS or FUNC
+ union {
+ UCHAR PacketProtocol; // for STRESS packets the actual protocol type.
+ UCHAR PacketNumber; // ranges from 0x00 to 0xff, for tracking FUNCs.
+ } u;
+ ULONG CheckSum; // functional packet header check sum
+
+} PACKET_INFO;
+
+//
+// THE FUNC1 PACKET HEADER
+//
+typedef struct _FUNC1_PACKET {
+
+ MEDIA_HEADER media;
+ PACKET_INFO info;
+
+} FUNC1_PACKET;
+
+//
+// THE FUNC2 PACKET HEADER
+//
+typedef struct _FUNC2_PACKET {
+
+ FUNC1_PACKET hdr1;
+ FUNC1_PACKET hdr2;
+
+} FUNC2_PACKET;
+
+//
+// THE STRESS PACKET CONTROL INFORMATION
+//
+typedef struct _STRESS_CONTROL {
+
+ ULONG DataBufOffset; // offset into databuf used to generate packet data
+ ULONG SequenceNumber; // packet's sequence in order of sending
+ ULONG MaxSequenceNumber; // server window sequence number
+ UCHAR ResponseType; // how the server should respond.
+ UCHAR ClientReference; // the number of the Client sending the packet
+ UCHAR ServerReference; // the number of the Server sending the packet
+ BOOLEAN DataChecking; //
+ ULONG CheckSum; // stress packet header check sum
+
+} STRESS_CONTROL;
+
+//
+// THE STRESS_PACKET
+//
+typedef struct _STRESS_PACKET {
+
+ FUNC1_PACKET hdr;
+ STRESS_CONTROL sc;
+
+} STRESS_PACKET;
+
+
+//
+// THE GO PAUSE HEADER INFORMATION
+//
+
+typedef struct _GO_PACKET_INFO {
+
+ ULONG Signature; // GO_PACKET_SIGNATURE
+ ULONG TestSignature; // Test Signature
+ ULONG UniqueSignature; // Unique Signature for this GO PAUSE instance
+ UCHAR PacketType; // type of packet; STRESS or FUNC
+ ULONG CheckSum; // functional packet header check sum
+
+} GO_PACKET_INFO;
+
+//
+// THE GO-PAUSE PACKET
+//
+typedef struct _GO_PACKET {
+
+ MEDIA_HEADER go_media;
+ GO_PACKET_INFO info;
+
+} GO_PACKET;
+
+
+//
+// IN TOTAL: 4 TYPES OF PACKETS EXIST
+//
+// 1. FUNC1
+// 2. FUNC2
+// 3. STRESS
+// 4. GO-PAUSE
+//
+#include <packoff.h>
+
+
+typedef struct _ENVIRONMENT_VARIABLES {
+
+ ULONG WindowSize;
+ ULONG RandomBufferNumber;
+ UCHAR StressAddress[ADDRESS_LENGTH];
+ UCHAR ResendAddress[ADDRESS_LENGTH];
+ ULONG StressDelayInterval;
+ ULONG UpForAirDelay;
+ ULONG StandardDelay;
+ ULONG MulticastListSize;
+
+} ENVIRONMENT_VARIABLES, * PENVIRONMENT_VARIABLES;
+
+typedef struct _GLOBAL_COUNTERS {
+
+ ULONG Sends;
+ ULONG SendComps;
+ ULONG Receives;
+ ULONG ReceiveComps;
+ ULONG CorruptRecs;
+ ULONG InvalidPacketRecs;
+
+} GLOBAL_COUNTERS, *PGLOBAL_COUNTERS;
+
+typedef struct _INSTANCE_COUNTERS {
+
+ ULONG Sends;
+ ULONG SendPends;
+ ULONG SendComps;
+ ULONG SendFails;
+ ULONG Receives;
+ ULONG ReceiveComps;
+ ULONG CorruptRecs;
+ ULONG XferData;
+ ULONG XferDataPends;
+ ULONG XferDataComps;
+ ULONG XferDataFails;
+
+} INSTANCE_COUNTERS, *PINSTANCE_COUNTERS;
+
+typedef enum _RESPONSE_TYPE {
+
+ FULL_RESPONSE,
+ ACK_EVERY,
+ ACK_10_TIMES,
+ NO_RESPONSE
+
+} RESPONSE_TYPE;
+
+typedef enum _INTERPACKET_DELAY {
+
+ FIXEDDELAY,
+ RANDOMDELAY
+
+} INTERPACKET_DELAY;
+
+typedef enum _PACKET_MAKEUP {
+
+ RAND,
+ SMALL,
+ ZEROS,
+ ONES,
+ KNOWN
+
+} PACKET_MAKEUP;
+
+typedef enum _MEMBER_TYPE {
+
+ TP_CLIENT,
+ TP_SERVER,
+ BOTH
+
+} MEMBER_TYPE;
+
+typedef enum _PACKET_TYPE {
+
+ FIXEDSIZE,
+ RANDOMSIZE,
+ CYCLICAL
+
+} PACKET_TYPE;
+
+typedef enum _TP_EVENT_TYPE {
+
+ CompleteOpen,
+ CompleteClose,
+ CompleteSend,
+ CompleteTransferData,
+ CompleteReset,
+ CompleteRequest,
+ IndicateReceive,
+ IndicateReceiveComplete,
+ IndicateStatus,
+ IndicateStatusComplete,
+ Unknown
+
+} TP_EVENT_TYPE;
+
+
+typedef struct _SERVER_RESULTS {
+
+ ULONG Signature;
+ UCHAR Address[ADDRESS_LENGTH];
+ ULONG OpenInstance;
+ BOOLEAN StatsRcvd;
+ INSTANCE_COUNTERS Instance;
+ INSTANCE_COUNTERS S_Instance;
+ GLOBAL_COUNTERS S_Global;
+
+} SERVER_RESULTS, *PSERVER_RESULTS;
+
+
+
+typedef struct _STRESS_RESULTS {
+
+ ULONG Signature;
+ UCHAR Address[ADDRESS_LENGTH];
+ ULONG OpenInstance;
+ ULONG NumServers;
+ ULONG PacketsPerSecond;
+ GLOBAL_COUNTERS Global;
+ SERVER_RESULTS Servers[MAX_SERVERS];
+
+} STRESS_RESULTS, *PSTRESS_RESULTS;
+
+typedef struct _TP_TRANSMIT_POOL {
+
+ NDIS_SPIN_LOCK SpinLock;
+ BOOLEAN SpinLockAllocated;
+ ULONG Allocated;
+ ULONG Deallocated;
+ PNDIS_PACKET Head;
+ PNDIS_PACKET Tail;
+
+} TP_TRANSMIT_POOL, *PTP_TRANSMIT_POOL;
+
+struct _OPEN_BLOCK;
+
+typedef struct _TP_REQUEST_HANDLE {
+
+ ULONG Signature;
+ struct _OPEN_BLOCK *Open;
+ BOOLEAN RequestPended;
+ PIRP Irp;
+
+ union {
+
+ struct _OPEN_REQ {
+
+ NTSTATUS RequestStatus;
+ KEVENT OpenEvent;
+
+ } OPEN_REQ;
+
+ struct _RESET_REQ {
+
+ NTSTATUS RequestStatus;
+ BOOLEAN PostResetStressCleanup;
+
+ } RESET_REQ;
+
+ struct _INFO_REQ {
+
+ ULONG IoControlCode;
+ NDIS_REQUEST_TYPE NdisRequestType;
+ NDIS_OID OID;
+ PVOID InformationBuffer;
+ UINT InformationBufferLength;
+
+ } INFO_REQ;
+
+ struct _SEND_REQ {
+
+ PNDIS_PACKET Packet;
+ ULONG PacketSize;
+ BOOLEAN SendPacket;
+
+ } SEND_REQ;
+
+ struct _TRANS_REQ {
+
+ PNDIS_PACKET Packet;
+ ULONG DataOffset;
+ UINT DataSize;
+ PINSTANCE_COUNTERS InstanceCounters;
+
+ } TRANS_REQ;
+
+ struct _STRESS_REQ {
+
+ struct _TP_REQUEST_HANDLE *NextReqHndl;
+ PNDIS_REQUEST Request;
+
+ } STRESS_REQ;
+
+ } u;
+
+} TP_REQUEST_HANDLE, *PTP_REQUEST_HANDLE;
+
+
+typedef struct _PROTOCOL_RESERVED {
+
+ union {
+ NDIS_HANDLE PacketHandle;
+ PTP_TRANSMIT_POOL TransmitPool;
+ PNDIS_PACKET NextPacket;
+ } Pool;
+ PTP_REQUEST_HANDLE RequestHandle;
+ PINSTANCE_COUNTERS InstanceCounters;
+ ULONG CheckSum;
+
+} PROTOCOL_RESERVED, * PPROTOCOL_RESERVED;
+
+
+typedef struct _SERVER_INFO {
+
+ UCHAR ServerInstance;
+ UCHAR ClientReference;
+ UCHAR ServerReference;
+ UCHAR Address[ADDRESS_LENGTH]; // will be the same for a given ServerReference
+ BOOLEAN ServerActive;
+ UCHAR WindowReset;
+ ULONG SequenceNumber;
+ ULONG MaxSequenceNumber;
+ ULONG LastSequenceNumber;
+ ULONG PacketDelay;
+ ULONG DelayLength;
+ PINSTANCE_COUNTERS Counters;
+
+} SERVER_INFO, * PSERVER_INFO;
+
+typedef struct _CLIENT_STORAGE {
+
+ UCHAR NumServers;
+ UCHAR NextServer;
+ UCHAR ActiveServers;
+ BOOLEAN PoolInitialized;
+ NDIS_HANDLE PacketHandle;
+ PTP_TRANSMIT_POOL TransmitPool;
+ ULONG PacketSize;
+ ULONG BufferSize;
+ ULONG SizeIncrease;
+ SERVER_INFO Servers[MAX_SERVERS];
+
+} CLIENT_STORAGE, * PCLIENT_STORAGE;
+
+typedef struct _CLIENT_INFO {
+
+ UCHAR ClientInstance;
+ UCHAR ClientReference;
+ UCHAR Address[ADDRESS_LENGTH];
+ BOOLEAN DataChecking;
+ BOOLEAN TestEnding;
+ RESPONSE_TYPE ServerResponseType;
+ ULONG LastSequenceNumber;
+ PINSTANCE_COUNTERS Counters;
+
+} CLIENT_INFO, * PCLIENT_INFO;
+
+
+
+typedef struct _SERVER_STORAGE {
+
+ UCHAR NumClients;
+ UCHAR ActiveClients;
+ BOOLEAN PoolInitialized;
+ UCHAR PadByte;
+ NDIS_HANDLE PacketHandle;
+ PTP_TRANSMIT_POOL TransmitPool;
+ ULONG PadLong;
+ CLIENT_INFO Clients[MAX_CLIENTS];
+
+} SERVER_STORAGE, * PSERVER_STORAGE;
+
+//
+//
+//
+
+typedef struct _STRESS_ARGUMENTS {
+
+ MEMBER_TYPE MemberType;
+ PACKET_TYPE PacketType;
+ INT PacketSize;
+ PACKET_MAKEUP PacketMakeUp;
+ UCHAR ResponseType;
+ INTERPACKET_DELAY DelayType;
+ ULONG DelayLength;
+ ULONG Iterations;
+ ULONG TotalIterations;
+ ULONG TotalPackets;
+ BOOLEAN AllPacketsSent;
+ BOOLEAN WindowEnabled;
+ BOOLEAN DataChecking;
+ BOOLEAN PacketsFromPool;
+ BOOLEAN BeginReceives;
+ BOOLEAN ServerContinue;
+
+} STRESS_ARGUMENTS, * PSTRESS_ARGUMENTS;
+
+
+
+
+typedef struct _PENDING {
+
+ ULONG PendingPackets;
+ ULONG PendingRequests;
+ ULONG PacketPendNumber;
+ ULONG PacketCompleteNumber;
+ BOOLEAN PendingSpinLockAllocated;
+ NDIS_SPIN_LOCK SpinLock;
+ PNDIS_PACKET Packets[NUM_PACKET_PENDS];
+
+} PENDING, * PPENDING;
+
+
+
+
+typedef struct _STRESS_BLOCK {
+
+ volatile BOOLEAN Stressing;
+ BOOLEAN StressStarted;
+ BOOLEAN StopStressing;
+ BOOLEAN StressFinal;
+ BOOLEAN StressEnded;
+ BOOLEAN Resetting;
+ BOOLEAN FirstIteration;
+ PCLIENT_STORAGE Client;
+ PSERVER_STORAGE Server;
+ LARGE_INTEGER StartTime;
+ LARGE_INTEGER EndTime;
+ ULONG PacketsPerSecond;
+ PSTRESS_ARGUMENTS Arguments;
+ PPENDING Pend;
+ PUCHAR DataBuffer[MAX_NUMBER_BUFFERS];
+ PMDL DataBufferMdl[MAX_NUMBER_BUFFERS];
+ BOOLEAN PoolInitialized;
+ NDIS_HANDLE PacketHandle;
+ PSTRESS_RESULTS Results;
+ PIRP StressIrp;
+ ULONG Counter;
+ ULONG Reg2Counter;
+ KTIMER TpStressTimer;
+ KTIMER TpStressReg2Timer;
+ KDPC TpStressDpc;
+ KDPC TpStressReg2Dpc;
+ KDPC TpStressStatsDpc;
+ KDPC TpStressEndReqDpc;
+ KDPC TpStressFinalDpc;
+
+} STRESS_BLOCK, * PSTRESS_BLOCK;
+
+
+typedef struct _SEND_BLOCK {
+
+ volatile BOOLEAN Sending;
+ BOOLEAN StopSending;
+ BOOLEAN ResendPackets;
+ UCHAR PadByte;
+ UCHAR DestAddress[ADDRESS_LENGTH];
+ UCHAR ResendAddress[ADDRESS_LENGTH];
+ ULONG PacketSize;
+ ULONG NumberOfPackets;
+ ULONG PacketsSent;
+ ULONG PacketsPending;
+ ULONG SendEndDpcCount;
+ NDIS_HANDLE PacketHandle;
+ PINSTANCE_COUNTERS Counters;
+ PIRP SendIrp;
+ KTIMER SendTimer;
+ KDPC SendDpc;
+ KDPC SendEndDpc;
+
+} SEND_BLOCK, * PSEND_BLOCK;
+
+
+
+typedef struct _RECEIVE_BLOCK {
+
+ volatile BOOLEAN Receiving;
+ BOOLEAN StopReceiving;
+ ULONG PacketsPending;
+ ULONG ReceiveEndDpcCount;
+ NDIS_HANDLE PacketHandle;
+ PINSTANCE_COUNTERS Counters;
+ PIRP ReceiveIrp;
+ KTIMER ReceiveTimer;
+ KDPC ReceiveDpc;
+ KDPC ReceiveEndDpc;
+
+} RECEIVE_BLOCK, * PRECEIVE_BLOCK;
+
+typedef struct _PAUSE_BLOCK {
+
+ volatile BOOLEAN GoReceived;
+ BOOLEAN PoolAllocated;
+ NDIS_HANDLE PacketHandle;
+ UCHAR RemoteAddress[ADDRESS_LENGTH];
+ ULONG TestSignature;
+ ULONG UniqueSignature;
+ UCHAR PacketType;
+ ULONG TimeOut;
+ NDIS_SPIN_LOCK SpinLock;
+
+} PAUSE_BLOCK, * PPAUSE_BLOCK;
+
+
+typedef struct _EVENTS {
+
+ TP_EVENT_TYPE TpEventType;
+ NDIS_STATUS Status;
+ BOOLEAN Overflow;
+ PVOID EventInfo;
+
+} EVENTS, * PEVENTS;
+
+
+
+
+typedef struct _EVENT_QUEUE {
+
+ NDIS_SPIN_LOCK SpinLock;
+ ULONG ReceiveIndicationCount;
+ ULONG StatusIndicationCount;
+ BOOLEAN ExpectReceiveComplete;
+ BOOLEAN ExpectStatusComplete;
+ ULONG Head;
+ ULONG Tail;
+ ULONG PadUlong;
+ EVENTS Events[MAX_EVENT];
+
+} EVENT_QUEUE, * PEVENT_QUEUE;
+
+
+typedef struct _OPEN_BLOCK {
+
+ NDIS_HANDLE NdisBindingHandle;
+ NDIS_HANDLE NdisProtocolHandle;
+ UCHAR OpenInstance;
+ BOOLEAN Closing;
+ UCHAR StationAddress[ADDRESS_LENGTH];
+ PSZ AdapterName;
+ NDIS_SPIN_LOCK SpinLock;
+ volatile UCHAR ReferenceCount;
+ UINT MediumIndex;
+ struct _TP_MEDIA_INFO *Media;
+ PGLOBAL_COUNTERS GlobalCounters;
+ PENVIRONMENT_VARIABLES Environment;
+ PSTRESS_BLOCK Stress;
+ PSEND_BLOCK Send;
+ PRECEIVE_BLOCK Receive;
+ PEVENT_QUEUE EventQueue;
+ PPAUSE_BLOCK Pause;
+ PTP_REQUEST_HANDLE OpenReqHndl;
+ PTP_REQUEST_HANDLE CloseReqHndl;
+ PTP_REQUEST_HANDLE ResetReqHndl;
+ PTP_REQUEST_HANDLE RequestReqHndl;
+ PTP_REQUEST_HANDLE StressReqHndl;
+ BOOLEAN IrpCancelled;
+ PIRP Irp;
+ ULONG Signature;
+
+} OPEN_BLOCK, * POPEN_BLOCK;
+
+
+
+
+
+//
+// Functions
+//
+VOID DumpNdisPacket( PNTKD_OUTPUT_ROUTINE, PNTKD_READ_VIRTUAL_MEMORY, PNDIS_PACKET, DWORD );
+VOID DumpNdisBuffer( PNTKD_OUTPUT_ROUTINE, PNTKD_READ_VIRTUAL_MEMORY, PNDIS_BUFFER, DWORD );
+VOID DumpOpenBuffer( PNTKD_OUTPUT_ROUTINE, PNTKD_READ_VIRTUAL_MEMORY, PNDIS_BUFFER, DWORD );
+VOID ndispacket ( DWORD, PNTKD_EXTENSION_APIS, LPSTR );
+VOID ndisbuffer ( DWORD, PNTKD_EXTENSION_APIS, LPSTR );
+VOID openblock ( DWORD, PNTKD_EXTENSION_APIS, LPSTR );
+VOID help ( DWORD, PNTKD_EXTENSION_APIS, LPSTR );
diff --git a/private/ntos/ndis/testprot/tplib/makefile b/private/ntos/ndis/testprot/tplib/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/testprot/tplib/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/testprot/tplib/oids.c b/private/ntos/ndis/testprot/tplib/oids.c
new file mode 100644
index 000000000..f69958aef
--- /dev/null
+++ b/private/ntos/ndis/testprot/tplib/oids.c
@@ -0,0 +1,206 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ oid.c
+
+Abstract:
+
+
+Author:
+
+ Tom Adams (tomad) 29-Nov-1991
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ Sanjeev Katariya (sanjeevk)
+
+ 4-6-1993 Added native ARCNET Support
+ 4-14-1993 Added additional OIDS
+
+--*/
+
+//#include <ntos.h>
+
+#include <ndis.h>
+
+#include "tpdefs.h"
+
+
+extern OID_INFO OidArray[] = {
+
+ { OID_GEN_SUPPORTED_LIST, 1024, TRUE, FALSE, TRUE },
+ { OID_GEN_HARDWARE_STATUS, 4, TRUE, FALSE, TRUE },
+ { OID_GEN_MEDIA_SUPPORTED, 4*8, TRUE, FALSE, TRUE },
+ { OID_GEN_MEDIA_IN_USE, 4*8, TRUE, FALSE, TRUE },
+ { OID_GEN_MAXIMUM_LOOKAHEAD, 4, TRUE, FALSE, TRUE },
+ { OID_GEN_MAXIMUM_FRAME_SIZE, 4, TRUE, FALSE, TRUE },
+ { OID_GEN_LINK_SPEED, 4, TRUE, FALSE, TRUE },
+ { OID_GEN_TRANSMIT_BUFFER_SPACE, 4, TRUE, FALSE, TRUE },
+ { OID_GEN_RECEIVE_BUFFER_SPACE, 4, TRUE, FALSE, TRUE },
+ { OID_GEN_TRANSMIT_BLOCK_SIZE, 4, TRUE, FALSE, TRUE },
+ { OID_GEN_RECEIVE_BLOCK_SIZE, 4, TRUE, FALSE, TRUE },
+ { OID_GEN_VENDOR_ID, 4, TRUE, FALSE, TRUE },
+ { OID_GEN_VENDOR_DESCRIPTION, 64, TRUE, FALSE, TRUE },
+ { OID_GEN_CURRENT_PACKET_FILTER, 4, TRUE, TRUE, TRUE },
+ { OID_GEN_CURRENT_LOOKAHEAD, 4, TRUE, TRUE, TRUE },
+ { OID_GEN_DRIVER_VERSION, 2, TRUE, FALSE, TRUE },
+ { OID_GEN_MAXIMUM_TOTAL_SIZE, 4, TRUE, FALSE, TRUE },
+ { OID_GEN_PROTOCOL_OPTIONS, 4, TRUE, TRUE, TRUE },
+ { OID_GEN_MAC_OPTIONS, 4, TRUE, TRUE, TRUE },
+
+
+ { OID_GEN_XMIT_OK, 4, FALSE, FALSE, TRUE },
+ { OID_GEN_RCV_OK, 4, FALSE, FALSE, TRUE },
+ { OID_GEN_XMIT_ERROR, 4, FALSE, FALSE, TRUE },
+ { OID_GEN_RCV_ERROR, 4, FALSE, FALSE, TRUE },
+ { OID_GEN_RCV_NO_BUFFER, 4, FALSE, FALSE, TRUE },
+
+ { OID_GEN_DIRECTED_BYTES_XMIT, 8, FALSE, FALSE, TRUE },
+ { OID_GEN_DIRECTED_FRAMES_XMIT, 4, FALSE, FALSE, TRUE },
+ { OID_GEN_MULTICAST_BYTES_XMIT, 8, FALSE, FALSE, TRUE },
+ { OID_GEN_MULTICAST_FRAMES_XMIT, 4, FALSE, FALSE, TRUE },
+ { OID_GEN_BROADCAST_BYTES_XMIT, 8, FALSE, FALSE, TRUE },
+ { OID_GEN_BROADCAST_FRAMES_XMIT, 4, FALSE, FALSE, TRUE },
+ { OID_GEN_DIRECTED_BYTES_RCV, 8, FALSE, FALSE, TRUE },
+ { OID_GEN_DIRECTED_FRAMES_RCV, 4, FALSE, FALSE, TRUE },
+ { OID_GEN_MULTICAST_BYTES_RCV, 8, FALSE, FALSE, TRUE },
+ { OID_GEN_MULTICAST_FRAMES_RCV, 4, FALSE, FALSE, TRUE },
+ { OID_GEN_BROADCAST_BYTES_RCV, 8, FALSE, FALSE, TRUE },
+ { OID_GEN_BROADCAST_FRAMES_RCV, 4, FALSE, FALSE, TRUE },
+ { OID_GEN_RCV_CRC_ERROR, 4, FALSE, FALSE, TRUE },
+ { OID_GEN_TRANSMIT_QUEUE_LENGTH, 4, FALSE, FALSE, TRUE },
+
+ { OID_802_3_PERMANENT_ADDRESS, 6, TRUE, FALSE, TRUE },
+ { OID_802_3_CURRENT_ADDRESS, 6, TRUE, FALSE, TRUE },
+ { OID_802_3_MULTICAST_LIST, 6, TRUE, TRUE, TRUE },
+ { OID_802_3_MAXIMUM_LIST_SIZE, 4, TRUE, FALSE, TRUE },
+
+ { OID_802_3_RCV_ERROR_ALIGNMENT, 4, FALSE, FALSE, TRUE },
+ { OID_802_3_XMIT_ONE_COLLISION, 4, FALSE, FALSE, TRUE },
+ { OID_802_3_XMIT_MORE_COLLISIONS, 4, FALSE, FALSE, TRUE },
+
+ { OID_802_3_XMIT_DEFERRED, 4, FALSE, FALSE, TRUE },
+ { OID_802_3_XMIT_MAX_COLLISIONS, 4, FALSE, FALSE, TRUE },
+ { OID_802_3_RCV_OVERRUN, 4, FALSE, FALSE, TRUE },
+ { OID_802_3_XMIT_UNDERRUN, 4, TRUE, FALSE, TRUE },
+ { OID_802_3_XMIT_HEARTBEAT_FAILURE, 4, TRUE, FALSE, TRUE },
+ { OID_802_3_XMIT_TIMES_CRS_LOST, 4, TRUE, FALSE, TRUE },
+ { OID_802_3_XMIT_LATE_COLLISIONS, 4, TRUE, FALSE, TRUE },
+
+ { OID_802_5_PERMANENT_ADDRESS, 6, TRUE, FALSE, TRUE },
+ { OID_802_5_CURRENT_ADDRESS, 6, TRUE, FALSE, TRUE },
+ { OID_802_5_CURRENT_FUNCTIONAL, 4, TRUE, TRUE, TRUE },
+ { OID_802_5_CURRENT_GROUP, 4, TRUE, TRUE, TRUE },
+ { OID_802_5_LAST_OPEN_STATUS, 4, TRUE, TRUE, TRUE },
+ { OID_802_5_CURRENT_RING_STATUS, 4, TRUE, TRUE, TRUE },
+ { OID_802_5_CURRENT_RING_STATE, 4, TRUE, TRUE, TRUE },
+
+ { OID_802_5_LINE_ERRORS, 4, FALSE, FALSE, TRUE },
+ { OID_802_5_LOST_FRAMES, 4, TRUE, FALSE, TRUE },
+
+ { OID_802_5_BURST_ERRORS, 4, TRUE, FALSE, TRUE },
+ { OID_802_5_AC_ERRORS, 4, TRUE, FALSE, TRUE },
+ { OID_802_5_ABORT_DELIMETERS, 4, TRUE, FALSE, TRUE },
+ { OID_802_5_FRAME_COPIED_ERRORS, 4, TRUE, FALSE, TRUE },
+ { OID_802_5_FREQUENCY_ERRORS, 4, TRUE, FALSE, TRUE },
+ { OID_802_5_TOKEN_ERRORS, 4, TRUE, FALSE, TRUE },
+ { OID_802_5_INTERNAL_ERRORS, 4, TRUE, FALSE, TRUE },
+
+ { OID_FDDI_LONG_PERMANENT_ADDR, 6, TRUE, FALSE, TRUE },
+ { OID_FDDI_LONG_CURRENT_ADDR, 6, TRUE, FALSE, TRUE },
+ { OID_FDDI_LONG_MULTICAST_LIST, 6, TRUE, TRUE, TRUE },
+ { OID_FDDI_LONG_MAX_LIST_SIZE, 4, TRUE, TRUE, TRUE },
+ { OID_FDDI_SHORT_PERMANENT_ADDR, 2, TRUE, FALSE, TRUE },
+ { OID_FDDI_SHORT_CURRENT_ADDR, 2, TRUE, FALSE, TRUE },
+ { OID_FDDI_SHORT_MULTICAST_LIST, 6, TRUE, TRUE, TRUE },
+ { OID_FDDI_SHORT_MAX_LIST_SIZE, 4, TRUE, TRUE, TRUE },
+
+ { OID_FDDI_ATTACHMENT_TYPE, 4, TRUE, FALSE, TRUE },
+ { OID_FDDI_UPSTREAM_NODE_LONG, 6, TRUE, FALSE, TRUE },
+ { OID_FDDI_DOWNSTREAM_NODE_LONG, 6, TRUE, FALSE, TRUE },
+ { OID_FDDI_FRAME_ERRORS, 4, TRUE, FALSE, TRUE },
+ { OID_FDDI_FRAMES_LOST, 4, TRUE, FALSE, TRUE },
+ { OID_FDDI_RING_MGT_STATE, 4, TRUE, FALSE, TRUE },
+ { OID_FDDI_LCT_FAILURES, 4, TRUE, FALSE, TRUE },
+ { OID_FDDI_LEM_REJECTS, 4, TRUE, FALSE, TRUE },
+ { OID_FDDI_LCONNECTION_STATE, 4, TRUE, FALSE, TRUE },
+
+ //
+ // STARTCHANGE
+ //
+ { OID_ARCNET_PERMANENT_ADDRESS, 1, TRUE, FALSE, TRUE },
+ { OID_ARCNET_CURRENT_ADDRESS, 1, TRUE, FALSE, TRUE },
+ { OID_ARCNET_RECONFIGURATIONS, 4, FALSE, FALSE, TRUE },
+ //
+ // STOPCHANGE
+ //
+
+ //
+ // Async Objects
+ //
+
+/* Not currently supported.
+
+ //
+ // XXX: the following must be verified for size and the set/query
+ // booleans. also are the correct OIDs defined?
+ //
+
+ { OID_ASYNC_PERMANENT_ADDRESS 4, TRUE, FALSE, TRUE },
+ { OID_ASYNC_CURRENT_ADDRESS 4, TRUE, FALSE, TRUE },
+ { OID_ASYNC_QUALITY_OF_SERVICE 4, TRUE, FALSE, TRUE },
+ { OID_ASYNC_PROTOCOL_TYPE 4, TRUE, FALSE, TRUE }
+
+ { OID_LTALK_CURRENT_NODE_ID 4, TRUE, FALSE, TRUE },
+
+ { OID_LTALK_IN_BROADCASTS 4, TRUE, FALSE, TRUE },
+ { OID_LTALK_IN_LENGTH_ERRORS 4, TRUE, FALSE, TRUE },
+
+ { OID_LTALK_OUT_NO_HANDLERS 4, TRUE, FALSE, TRUE },
+ { OID_LTALK_COLLISIONS 4, TRUE, FALSE, TRUE },
+ { OID_LTALK_DEFERS 4, TRUE, FALSE, TRUE },
+ { OID_LTALK_NO_DATA_ERRORS 4, TRUE, FALSE, TRUE },
+ { OID_LTALK_RANDOM_CTS_ERRORS 4, TRUE, FALSE, TRUE },
+ { OID_LTALK_FCS_ERRORS 4, TRUE, FALSE, TRUE }
+*/
+
+};
+
+
+
+ULONG
+TpLookUpOidInfo(
+ IN NDIS_OID RequestOid
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ The arguments for the test to be run.
+
+Return Value:
+
+
+--*/
+
+{
+ ULONG i;
+
+ for (i=0;i<NUM_OIDS;i++) {
+ if ( OidArray[i].Oid == RequestOid) {
+ return i;
+ }
+ }
+
+ return 0xFFFFFFFF;
+}
diff --git a/private/ntos/ndis/testprot/tplib/sources b/private/ntos/ndis/testprot/tplib/sources
new file mode 100644
index 000000000..8c30bbdd2
--- /dev/null
+++ b/private/ntos/ndis/testprot/tplib/sources
@@ -0,0 +1,47 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=tplib
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+# Dependent on the setting of the build path. It is assumed that the TESTPROT directory has been
+# set up under the dirs private\ntos\ndis
+# The following directories will be accessed:
+# private\ntos\ndis\testprot\inc private\ntos\inc \private\ntos\ndis\testprot\tpdrvr
+# private\inc
+INCLUDES=..\inc;..\..\..\inc;..\tpdrvr;..\..\..\..\inc
+
+SOURCES=oids.c
+
+i386_SOURCES=
+
+MIPS_SOURCES=
+
+RELATIVE_DEPTH=..\..\..
+NTTEST=
+OPTIONAL_NTTEST=
diff --git a/private/ntos/ndis/ubnei/card.c b/private/ntos/ndis/ubnei/card.c
new file mode 100644
index 000000000..59e41e335
--- /dev/null
+++ b/private/ntos/ndis/ubnei/card.c
@@ -0,0 +1,1910 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ card.c
+
+Abstract:
+
+ This is the mac ndis file for the Ungermann Bass Ethernet Controller.
+ This driver conforms to the NDIS 3.0 interface.
+
+ It is here that the NDIS3.0 functions defined in the MAC characteristic
+ table have been deinfed.
+
+Author:
+
+ Sanjeev Katariya (sanjeevk) 03-05-92
+
+Environment:
+
+ Kernel Mode Operating Systems : NT and other lesser OS's
+
+Revision History:
+
+ Brian Lieuallen BrianLie 07/21/92
+ Made it work.
+ Brian Lieuallen BrianLie 12/15/93
+ Made it a mini-port
+
+
+--*/
+
+
+
+// INCLUDES
+#include <ndis.h>
+#include <efilter.h>
+
+#include "niudata.h"
+#include "debug.h"
+
+#include "ubhard.h"
+#include "ubsoft.h"
+#include "ubnei.h"
+
+#include "map.h"
+
+
+
+
+// INCLUDES:END
+
+
+
+
+
+
+UCHAR
+CardMapRegisterValue(
+ IN PUBNEI_ADAPTER pAdapter,
+ IN ULONG SegAddress
+ );
+
+
+BOOLEAN
+Reset_GPCNIU(
+ OUT PUBNEI_ADAPTER pNewAdapt
+ );
+
+BOOLEAN
+Run_NIU_Diagnostics(
+ OUT PUBNEI_ADAPTER pNewAdapt
+ );
+
+BOOLEAN
+Halt_NIU(
+ OUT PUBNEI_ADAPTER pNewAdapt
+ );
+
+BOOLEAN
+Reset_OtherNIU(
+ OUT PUBNEI_ADAPTER pNewAdapt
+ );
+
+BOOLEAN
+ReadStationAddress(
+ OUT PUBNEI_ADAPTER pNewAdapt
+ );
+
+BOOLEAN
+CardTestMemory(
+ IN PUBNEI_ADAPTER pAdapter
+ );
+
+BOOLEAN
+CardCodeDataInit(
+ OUT PUBNEI_ADAPTER pAdapter
+ );
+
+USHORT
+CardSetMulticast(
+ PUBNEI_ADAPTER pAdapter,
+ PUCHAR MulticastList,
+ UINT ListSize
+ );
+
+
+#ifdef ALLOC_PRAGMA
+#pragma NDIS_INIT_FUNCTION(Reset_GPCNIU)
+#pragma NDIS_INIT_FUNCTION(Run_NIU_Diagnostics)
+#pragma NDIS_INIT_FUNCTION(Halt_NIU)
+#pragma NDIS_INIT_FUNCTION(Reset_OtherNIU)
+#pragma NDIS_INIT_FUNCTION(ReadStationAddress)
+#pragma NDIS_INIT_FUNCTION(CardTestMemory)
+#pragma NDIS_INIT_FUNCTION(CardCodeDataInit)
+#pragma NDIS_INIT_FUNCTION(CardTest)
+#pragma NDIS_INIT_FUNCTION(CardSetup)
+#pragma NDIS_INIT_FUNCTION(CardStartNIU)
+#pragma NDIS_INIT_FUNCTION(CardMapRegisterValue)
+#endif
+
+
+
+
+
+// GLOBAL VARIABLES
+extern UCHAR GPNIU_IRQ_Selections[];
+
+
+extern NIUDETAILS NiuDetails[6];
+
+
+
+
+
+
+BOOLEAN
+CardSetup (
+ OUT PUBNEI_ADAPTER pAdapter
+ )
+/*++
+
+ Routine Description:
+
+ Set up the receive buffers and the various descriptors
+ Set the various statistics and fields assocated with the
+ receive buffers
+
+ Set up the Transmit buffers and the various descriptors
+ Set the various statistics and fields assocated with the
+ transmit buffers
+
+
+ Arguments:
+
+
+ Return Value:
+
+
+--*/
+{
+ ULONG tempLong;
+
+
+/*
+ This set of code was used to make sure that the offsets to these structure
+ elements match the offsets that the assembler created for the data segments
+ of the down load code
+
+
+ PLOWNIUDATA pTest;
+ PHIGHNIUDATA pTest2;
+
+ pTest->sst.SST_MediaSpecificStatisticsPtr=0l;
+ pTest->mst.MST_TableSize=0;
+ pTest->dummy_RDB[0]=(UCHAR)0;
+ pTest->dummy_buffer[0]=(UCHAR)0;
+ pTest->Start_Here[0]=(UCHAR)0;
+
+ pTest2->System_State=0;
+ pTest2->Next_Unused_Location_in_1st_32K=0;
+ pTest2->Stack_Area[0]=0;
+ pTest2->NOP_command[0]=0;
+ pTest2->Configure_with_Loopback[0]=0;
+ pTest2->Dynamically_Allocated_Area[0]=0;
+*/
+
+ pAdapter->pDataWindow=(PHIGHNIUDATA)((PUCHAR)pAdapter->pCardRam+(0x8000 & pAdapter->WindowMask));
+ IF_INIT_LOUD (DbgPrint("Card Data segment is at 0x%lx\n",pAdapter->pDataWindow);)
+
+ pAdapter->pNIU_Control=(PNIU_CONTROL_AREA)((PUCHAR)pAdapter->pCardRam+(0xff00 & pAdapter->WindowMask));
+
+ IF_INIT_LOUD (DbgPrint("Card Control area is at 0x%lx\n",pAdapter->pNIU_Control);)
+
+ //
+ // Setting Initialization Window Base
+ //
+
+ switch ( NiuDetails[pAdapter->AdapterType].AdapterClass ) {
+
+ case CHAMELEON:
+
+
+ //
+ // Set the NIU base address of the shared memory window.
+ //
+ // NIUps memory window can be any where in first 16 Meg
+ //
+
+ if ( pAdapter->AdapterType == NIUPS) {
+ IF_INIT_LOUD( DbgPrint("Set Window base bits 23-20 to %02x\n",(UCHAR)((pAdapter->MemBaseAddr & 0x00F00000) >> 20));)
+
+ NdisRawWritePortUchar(
+ (PUCHAR)pAdapter->SetWindowBasePort+1,
+ (UCHAR)((pAdapter->MemBaseAddr & 0x00F00000) >> 20)
+ );
+ }
+
+ //
+ // Set the low bits for both NIUps and EOTP
+ //
+ IF_INIT_LOUD( DbgPrint("Set Window base bits 19-14 to %02x\n",(UCHAR)((pAdapter->MemBaseAddr & 0x000fc000) >> 12));)
+
+ NdisRawWritePortUchar(
+ pAdapter->SetWindowBasePort,
+ (UCHAR)((pAdapter->MemBaseAddr & 0x000Fc000) >> 12)
+ );
+
+
+
+ //
+ // Enable the GPCNIU adapter.
+ //
+ if ( pAdapter->AdapterType == GPCNIU ) {
+
+ IF_INIT_LOUD( DbgPrint("Enable the EOTP adapter\n");)
+ NdisRawWritePortUchar(
+ pAdapter->InterruptStatusPort,
+ 0x01
+ );
+ }
+ break;
+
+ default :
+ break;
+
+ }
+
+
+ //
+ // Set up the following 4 windows in the NIU Window area
+ //
+ // The Initialization
+ // The ReceiveData
+ // The TransmitData
+ // The Code Window
+ //
+
+
+
+ //
+ // InitWindow Page Map
+ //
+ tempLong=((((ULONG)NiuDetails[pAdapter->AdapterType].HighestRamSegment<<4)+0x10000)-pAdapter->WindowSize)>>4;
+
+ pAdapter->InitWindow_Page = CardMapRegisterValue(pAdapter,tempLong);
+
+ IF_INIT_LOUD (DbgPrint("Init page is 0x%x\n",pAdapter->InitWindow_Page );)
+
+ //
+ // ReceiveWindow Page
+ //
+
+ pAdapter->ReceiveDataWindow_Page =
+ CardMapRegisterValue(pAdapter,
+ NiuDetails[pAdapter->AdapterType].PrimaryDataSegment);
+
+
+ IF_INIT_LOUD (DbgPrint("Rec page is 0x%x\n",pAdapter->ReceiveDataWindow_Page );)
+ //
+ // DataWindow Page
+ //
+
+ pAdapter->DataWindow_Page =
+ CardMapRegisterValue(pAdapter,
+ NiuDetails[pAdapter->AdapterType].PrimaryDataSegment+0x800);
+
+
+ IF_INIT_LOUD (DbgPrint("data page is 0x%x\n",pAdapter->DataWindow_Page);)
+ //
+ // CodeWindow Page
+ //
+
+ pAdapter->CodeWindow_Page =
+ CardMapRegisterValue(pAdapter,
+ NiuDetails[pAdapter->AdapterType].OperationalCodeSegment);
+
+ IF_INIT_LOUD (DbgPrint("code page is 0x%x\n",pAdapter->CodeWindow_Page);)
+
+
+ //
+ // Final Map of the window pages on the 512K Adapter RAM
+ //
+ // (CONTROL REGISTER 1 WINDOW MAP)
+ // 00 08 10 18 20 28 30 38 40 48 50 58 60 68 70 78 80
+ // ---------------------------------------------------------------
+ // | | | | | | | | | | | | | |
+ // | | | | |CW |CW |RDW |DW | | | | |IW |
+ // | | | | | | | | | | | | | |
+ // ---------------------------------------------------------------
+ // 0 32 64 96 128 160 192 224 256 288 320 352 384 416 448 480 512
+ // (K)
+
+ return TRUE;
+
+
+
+}
+
+
+UCHAR
+CardMapRegisterValue(
+ IN PUBNEI_ADAPTER pAdapter,
+ IN ULONG SegAddress
+ )
+{
+ UCHAR tempByte;
+
+ tempByte=(UCHAR)((SegAddress<<4)/NiuDetails[pAdapter->AdapterType].MinimumWindowSize);
+ return NiuDetails[pAdapter->AdapterType].MappingTable[tempByte] & ~INTERRUPT_ENABLED;
+}
+
+
+
+
+
+
+
+BOOLEAN
+CardTest (
+ OUT PUBNEI_ADAPTER pAdapter
+ )
+/*++
+
+ Routine Description:
+
+
+ Arguments:
+
+
+ Return Value:
+
+
+--*/
+{
+
+
+ BOOLEAN bResult;
+
+ //
+ // Set up the Initialization area on the RAM
+ //
+
+ SET_INITWINDOW(pAdapter,0);
+
+
+ bResult=FALSE;
+ if (pAdapter->AdapterType==GPCNIU) {
+ if (!(bResult=Reset_GPCNIU(pAdapter))) {
+ IF_INIT_LOUD (DbgPrint("CardTest(): Reset_GPCNIU() failed trying one more time\n");)
+ if (!(bResult=Reset_GPCNIU(pAdapter))) {
+ IF_INIT_LOUD (DbgPrint("CardTest(): Reset_GPCNIU() failed again! all over\n");)
+ return FALSE;
+ }
+ }
+ }
+
+
+ if ( !bResult ||( pAdapter->AdapterType != GPCNIU )) {
+ Reset_OtherNIU(pAdapter);
+ }
+
+
+ //
+ // If this is an EOTP see if the user wants to run diagnostics
+ //
+ if ((pAdapter->AdapterType!=GPCNIU) ||
+ (pAdapter->Diagnostics)) {
+
+ if (!Run_NIU_Diagnostics(pAdapter))
+ return FALSE;
+ }
+
+
+ if (!Halt_NIU(pAdapter))
+ return FALSE;
+
+
+ if (!ReadStationAddress(pAdapter))
+ return FALSE;
+
+
+ if (!CardTestMemory(pAdapter))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+
+
+
+BOOLEAN
+Reset_GPCNIU(
+ OUT PUBNEI_ADAPTER pAdapter
+ )
+/*++
+
+ Routine Description:
+
+
+ Arguments:
+
+
+ Return Value:
+
+
+--*/
+
+{
+
+ PNIU_CONTROL_AREA volatile pNIU_Control = pAdapter->pNIU_Control;
+ ULONG i;
+ USHORT TmpUshort;
+
+
+ //
+ // Reset the NIU, to make it start running the PROM
+ // code. First hold the RESET line high
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MapPort,
+ RESET_SET
+ );
+
+ //
+ // Wait for 1 millisecond
+ //
+ NdisStallExecution( (UINT)2000 );
+
+
+ //
+ // Take RESET down
+ // Wait a while again.
+ NdisRawWritePortUchar(
+ pAdapter->MapPort,
+ RESET_CLEAR
+ );
+
+ NdisStallExecution( (UINT)2000 );
+
+
+ //
+ // GPCNIUs require handshaking with the PROM immediately
+ // after a reset. This is because the SIF chip *always*
+ // enables the RIPL window regardless of what the dip
+ // switches on the board are set to. To get around this,
+ // the RAMs are *disabled* completely until we do the
+ // following handshake to inform the PROM that we have
+ // now disabled the RIPL window from the PC's side.
+ //
+
+ //
+ // 1: Select "Interrupt B"
+ // We're about to write 10000001b to the GPCNIU's
+ // "Window Size, Interrupt Selection, and feature
+ // enables" register. This selects "IRQB", specifies
+ // 32K window size, disables the IPL, IBM 3278/9, and
+ // IRMA features, and leaves the adapter enabled.
+ //
+
+ NdisRawWritePortUchar(
+ pAdapter->InterruptStatusPort,
+ 0x81
+ );
+
+ //
+ // 2: Enable interrupts
+ //
+
+ //
+ // Set the cards window and our shadow register to match
+ // so the debug code won't break
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MapPort,
+ pAdapter->InitWindow_Page
+ );
+
+ pAdapter->MapRegSync.CurrentMapRegister=pAdapter->InitWindow_Page;
+
+ SET_INITWINDOW(pAdapter,INTERRUPT_ENABLED);
+
+ //
+ // 3: Wait for the PROM to ack with HWresult2 = 0xAA
+ // We wait up to 1 second. Trials seem to show that
+ // the actual time required is between 650 and 700
+ // milliseconds.
+
+ //
+ // Wait for the transmission to complete, for about a second.
+ //
+
+ UBNEI_MOVE_SHARED_RAM_TO_USHORT(&TmpUshort, &(pNIU_Control->us_HWresult2));
+
+ for (i=0;(i<1500) && (TmpUshort != (USHORT)0xAA);i++) {
+
+ NdisStallExecution( 1000 );
+
+ UBNEI_MOVE_SHARED_RAM_TO_USHORT(&TmpUshort, &(pNIU_Control->us_HWresult2));
+
+ }
+
+ if (TmpUshort != (USHORT)0xAA) {
+
+ IF_INIT_LOUD (DbgPrint("Reset_GPCNIU: Timer expired waiting for reset\n");)
+ goto fail00;
+
+ }
+
+
+ //
+ // 4: Give the PROM a Halt Command.
+ //
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pNIU_Control->us_HWcommand), 0x1);
+
+
+ //
+ // 5: Wait for the PROM to ack with HWresult2 = 0x55
+ //
+
+ UBNEI_MOVE_SHARED_RAM_TO_USHORT(&TmpUshort, &(pNIU_Control->us_HWresult2));
+
+ for (i=0;(i<500) && (TmpUshort != (USHORT)0x55);i++) {
+
+ NdisStallExecution( 1000 );
+ UBNEI_MOVE_SHARED_RAM_TO_USHORT(&TmpUshort, &(pNIU_Control->us_HWresult2));
+
+ }
+
+ if (TmpUshort != (USHORT)0x55) {
+ IF_INIT_LOUD (DbgPrint("Reset_GPCNIU: Timer expired waiting for halt\n");)
+ goto fail00;
+ }
+
+
+ //
+ // 6: Clear the interrupt (that never really happened)
+ //
+
+ SET_INITWINDOW(pAdapter,INTERRUPT_DISABLED);
+
+ //
+ // 7: Select "Interrupt A"
+ //
+
+ NdisRawWritePortUchar(
+ pAdapter->InterruptStatusPort,
+ 0x01
+ );
+
+
+ return TRUE;
+
+fail00:
+ // clear the interrupt
+ SET_INITWINDOW(pAdapter,INTERRUPT_DISABLED);
+
+ // enable IRQA
+
+ NdisRawWritePortUchar(
+ pAdapter->InterruptStatusPort,
+ 0x01
+ );
+
+ return FALSE;
+
+}
+
+
+
+BOOLEAN
+Reset_OtherNIU(
+ OUT PUBNEI_ADAPTER pAdapter
+ )
+/*++
+
+ Routine Description:
+
+
+ Arguments:
+
+
+ Return Value:
+
+
+--*/
+
+{
+
+ PNIU_CONTROL_AREA volatile pNIU_Control = pAdapter->pNIU_Control;
+ PUSHORT POD_Status_Address;
+
+
+ POD_Status_Address = (PUSHORT)((PUCHAR)pAdapter->pCardRam+
+ (NiuDetails[pAdapter->AdapterType].POD_Status_Address & pAdapter->WindowMask));
+
+ SET_INITWINDOW(pAdapter,0);
+
+ //
+ // Zero out a couple of locations in which the
+ // PROM code will report the results of its
+ // initialization and diagnostics.
+ //
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(POD_Status_Address, 0x0);
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pNIU_Control->us_HWcommand), 0x0);
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pNIU_Control->us_HWresult1), 0x0);
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pNIU_Control->us_HWresult2), 0x0);
+
+ //
+ // We reset the NIU, to make it start running the
+ // PROM code. First we hold the RESET line high
+ // (or whatever it is ) for a while.
+ //
+
+
+ SET_INITWINDOW(pAdapter,RESET_SET);
+
+
+ NdisStallExecution( (UINT)1000 );
+
+ //
+ // Take RESET down (or whatever it is), and wait
+ // a while again.
+ //
+
+ SET_INITWINDOW(pAdapter,RESET_CLEAR);
+
+
+ NdisStallExecution( (UINT)500000 );
+
+ return TRUE;
+}
+
+
+
+
+
+BOOLEAN
+Run_NIU_Diagnostics(
+ OUT PUBNEI_ADAPTER pAdapter
+ )
+/*++
+
+ Routine Description:
+
+
+ Arguments:
+
+
+ Return Value:
+
+
+--*/
+
+{
+
+ PNIU_CONTROL_AREA volatile pNIU_Control = pAdapter->pNIU_Control;
+ PUCHAR POD_status_address;
+
+ UCHAR PODStatus;
+ ULONG i;
+ ULONG ulPassesNeeded;
+ ULONG ulDiagnosticPass;
+
+ UCHAR TmpUchar;
+ USHORT HWResult1;
+
+ POD_status_address = (PUCHAR)pAdapter->pCardRam+
+ (NiuDetails[pAdapter->AdapterType].POD_Status_Address & pAdapter->WindowMask);
+
+ //
+ // Some NIUs will run all their diagnostics as a result of the reset
+ // we just did. Others do some initialization but don't run their full
+ // set of tests. For these latter, we first wait for them to respond
+ // to the reset then we tell them to run their diagnostics, and wait
+ // again for them to report the results.
+ //
+
+ //
+ // We re-map, and wait for the PROM code to finish and report its result.
+ // We wait for up to 20 seconds. The way the PROM diagnostic test progress
+ // and result is reported is different for different kinds of NIUs.
+ // The test codes are all less than 80h (i.e., no code has the high order
+ // bit set). If a test fails, either
+ // (a) the test is repeated indefinitely or
+ // (b) a failure code
+ // is stored into 3FEF8h, replacing the test code, and diagnostics are
+ // terminated.
+ // In case (a), we'll know that the diagnostics failed because
+ // our timer will expire. Failure codes all have the 80h bit set, so we
+ // can detect case (b) by checking the 80h bit in location 3FEF8h. If all
+ // the diagnostic tests run successfully, the success code, AAh, will be
+ // stored in 3FEF8h and also in the "HWresult1" byte (at 3FF94). For NIUs
+ // other than the Atlanta cards, the bytes in which the diagnostic status
+ // and result codes are reported are at different addresses. They are in
+ // different segments, and the "FEF8" one is at different offsets.
+
+
+ IF_INIT_LOUD (DbgPrint("Begin adapter diag\n");)
+
+ ulPassesNeeded=1;
+
+ if ( NiuDetails[pAdapter->AdapterType].AdapterFlags & TWO_PASS_DIAGNOSTICS ) {
+
+ ulPassesNeeded++;
+ }
+
+ ulDiagnosticPass=0;
+
+ SET_INITWINDOW(pAdapter,0);
+
+ for (i=0; i < 20000; i++) {
+
+
+
+ UBNEI_MOVE_SHARED_RAM_TO_UCHAR(&PODStatus, (PUCHAR)(POD_status_address));
+ UBNEI_MOVE_SHARED_RAM_TO_USHORT(&HWResult1, &(pNIU_Control->us_HWresult1));
+
+ if ( (PODStatus & 0x80) &&
+ ( PODStatus != 0xff ) &&
+ ( PODStatus == (UCHAR)HWResult1 )) {
+
+
+ // Final check
+
+ UBNEI_MOVE_SHARED_RAM_TO_UCHAR(&TmpUchar, (PUCHAR)(POD_status_address));
+
+ if ( PODStatus == TmpUchar ) {
+
+ if (PODStatus==0xaa) {
+ ulDiagnosticPass++;
+
+ IF_INIT_LOUD ( DbgPrint("Run_NIU_Diag: Adapter competed first pass pod=%02x HwR=%02x\n",PODStatus,HWResult1);)
+
+ if (ulDiagnosticPass==ulPassesNeeded) {
+
+ IF_INIT_LOUD ( DbgPrint("Run_NIU_Diag: Adapter competed second pass\n");)
+ return TRUE;
+
+ } else {
+ //
+ // Requires second set of diagnostics to be run
+ //
+
+ //
+ // Give the PROM code an "INTERRUPT" command
+ //
+
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM((PUCHAR)(POD_status_address), 0x0);
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pNIU_Control->us_HWcommand), 14);
+
+ //
+ // Wait for it to respond.
+ //
+ NdisStallExecution ( (UINT)250000 );
+
+ //
+ // Issue the DIAG command to the prom
+ //
+
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM((PUCHAR)(POD_status_address), 0xFF);
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pNIU_Control->us_HWresult1), 0);
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pNIU_Control->us_HWcommand), 3);
+
+ }
+
+ } else {
+ IF_INIT_LOUD ( DbgPrint("Run_NIU_DIAG: Adapter returned fail code\n");)
+ return FALSE;
+
+ }
+
+ }
+
+ } else {
+ //
+ // Not a complete status, wait some more
+ //
+
+ NdisStallExecution( 1000 );
+ }
+
+ }
+
+ IF_INIT_LOUD ( DbgPrint("Run_NIU_Diag: Adapter failed to complete Diag\n");)
+ return FALSE;
+
+}
+
+
+BOOLEAN
+Halt_NIU(
+ OUT PUBNEI_ADAPTER pAdapter
+ )
+/*++
+
+ Routine Description:
+
+
+ Arguments:
+
+
+ Return Value:
+
+
+--*/
+
+{
+ PNIU_CONTROL_AREA volatile pNIU_Control = pAdapter->pNIU_Control;
+ ULONG i, LoopLimit;
+ USHORT TmpUshort;
+
+
+ switch ( NiuDetails[pAdapter->AdapterType].AdapterClass ) {
+
+ case CHAMELEON:
+
+ SET_INITWINDOW(pAdapter,0);
+
+ LoopLimit = 5000;
+
+ //
+ // issue attention command
+ //
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pNIU_Control->us_HWcommand), 13);
+
+ break;
+
+ case ATLANTA:
+ SET_INITWINDOW(pAdapter,0);
+ LoopLimit = 500;
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(
+ (PUSHORT)((PUCHAR)pAdapter->pCardRam+(0xfefa & pAdapter->WindowMask)),
+ 0x5A5A);
+
+ break;
+
+
+ default :
+ break;
+ }
+
+ UBNEI_MOVE_SHARED_RAM_TO_USHORT(&TmpUshort, &(pNIU_Control->us_HWcommand));
+
+ for (i=0;(i<LoopLimit) && ( TmpUshort != 1 );i++) {
+
+ NdisStallExecution( 1000 );
+
+ UBNEI_MOVE_SHARED_RAM_TO_USHORT(&TmpUshort, &(pNIU_Control->us_HWcommand));
+
+ }
+
+ if ( TmpUshort != 1 ) {
+ //
+ // NIU Failed to halt
+ //
+ IF_INIT_LOUD (DbgPrint("Halt_NIU: The Adapter Failed to halt\n");)
+ return FALSE;
+
+ } else {
+ IF_INIT_LOUD (DbgPrint("Halt_NIU: The Adapter halted properly\n");)
+ return TRUE;
+ }
+
+
+
+}
+
+
+BOOLEAN
+ReadStationAddress(
+ OUT PUBNEI_ADAPTER pAdapter
+ )
+/*++
+
+ Routine Description:
+ Read the station address from the NIU control data at the top of
+ the cards RAM
+
+
+ Arguments:
+
+
+ Return Value:
+
+
+--*/
+
+{
+
+ PNIU_CONTROL_AREA pNIU_Control = pAdapter->pNIU_Control;
+
+ SET_INITWINDOW(pAdapter,0);
+
+ // while we are looking at the init window, we will get the station address
+
+ IF_INIT_LOUD( DbgPrint("The Station address is ");)
+
+ UBNEI_MOVE_SHARED_RAM_TO_MEM(pAdapter->PermanentAddress,
+ (PUCHAR)pNIU_Control->uc_node_id,
+ ETH_LENGTH_OF_ADDRESS
+ );
+
+#if DBG
+
+ {
+ UINT i;
+
+ for (i=0;i<ETH_LENGTH_OF_ADDRESS;i++) {
+
+ IF_INIT_LOUD( DbgPrint(" %02X",pAdapter->PermanentAddress[i]); )
+
+ }
+ }
+
+#endif
+
+ IF_INIT_LOUD( DbgPrint("\n");)
+
+ //
+ // One time the card initialized with the wrong station address
+ // so as a little extra check we will make sure the card has a UB OEM #
+ //
+
+ if (!(pAdapter->PermanentAddress[0]==0x00 &&
+ pAdapter->PermanentAddress[1]==0xdd &&
+ (pAdapter->PermanentAddress[2]==0x01 ||
+ pAdapter->PermanentAddress[2]==0x00))) {
+ IF_INIT_LOUD( DbgPrint("The Station address does not match a UB address\n");)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+CardTestMemory(
+ IN PUBNEI_ADAPTER pAdapter
+ )
+/*++
+
+ Routine Description:
+ Tests the card memory to try to see if there are any mapping
+ conflicts with the map window. Basically it makes sure the
+ is ram for the whole map window
+
+ Arguments:
+
+
+ Return Value:
+
+
+--*/
+
+{
+ PULONG p;
+ UINT i;
+ BOOLEAN Result=TRUE;
+ ULONG TmpUlong;
+
+ IF_INIT_LOUD(DbgPrint("UBNEI: CardTestMemory\n");)
+
+ //
+ // first switch to the code window and write our pattern
+ //
+ SET_CODEWINDOW(pAdapter,0);
+
+ p=(PULONG)pAdapter->pCardRam;
+ for (i=0;i<(pAdapter->WindowSize/4);i++) {
+
+ UBNEI_MOVE_DWORD_TO_SHARED_RAM(p+i, 0x0F55CCF0);
+
+ }
+
+ //
+ // switch to the data window and zero it out.
+ //
+ SET_RECDWINDOW(pAdapter,0);
+
+ for (i=0;i<(pAdapter->WindowSize/4);i++) {
+
+ UBNEI_MOVE_DWORD_TO_SHARED_RAM(p+i, 0x0);
+
+ }
+
+ //
+ // Back to the code window and make sure the pattern is still there
+ //
+ SET_CODEWINDOW(pAdapter,0);
+
+ for (i=0;i<(pAdapter->WindowSize/4);i++) {
+
+ UBNEI_MOVE_SHARED_RAM_TO_DWORD(&TmpUlong, p+i);
+
+ if (TmpUlong != 0x0F55CCF0) {
+
+ IF_INIT_LOUD(DbgPrint("UBNEI: CardTestMemory() Failed @ %0x Found %0lx\n",i,*(p+i));)
+
+ Result = FALSE;
+
+ break;
+
+ }
+
+ }
+
+ return Result;
+
+}
+
+
+BOOLEAN
+CardCodeDataInit(
+ OUT PUBNEI_ADAPTER pAdapter
+ )
+
+/*++
+
+ Routine Description:
+ This routine initializes various things in the NIU codes
+ data segment and actaully copies the NIU code to the card
+
+ Arguments:
+
+
+ Return Value:
+
+
+--*/
+{
+ PLOWNIUDATA pRcvDWindow = (PLOWNIUDATA) pAdapter->pCardRam;
+ PHIGHNIUDATA pDataWindow = (PHIGHNIUDATA) pAdapter->pDataWindow;
+ PNIU_CONTROL_AREA pNIU_Control = pAdapter->pNIU_Control;
+ UINT AdapterType = pAdapter->AdapterType;
+ UCHAR uc_Byte;
+ USHORT TmpUshort;
+
+ NDIS_HANDLE FileHandle;
+ UINT FileLength;
+ NDIS_STATUS Status;
+ PVOID ImageBuffer;
+
+
+ NDIS_STRING FileName=NDIS_STRING_CONST("ubnei.bin");
+
+
+ //
+ // Set the RcvDataWindow Page in place.
+ //
+
+ SET_RECDWINDOW(pAdapter,INTERRUPT_DISABLED);
+
+
+ // Zero out the first "page" of the lower 32k of the NIU code's main
+ // data segment. if there's room).
+ //
+ NdisZeroMappedMemory ( pAdapter->pCardRam, pAdapter->WindowSize);
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pRcvDWindow->mst.MST_TableSize), sizeof(MediaStatistics));
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pRcvDWindow->mst.MST_StructureVersionLevel), 1);
+
+ UBNEI_MOVE_DWORD_TO_SHARED_RAM(&(pRcvDWindow->mst.MST_LateCollisions), 0xFFFFFFFF);
+ UBNEI_MOVE_DWORD_TO_SHARED_RAM(&(pRcvDWindow->mst.MST_JabberErrors), 0xFFFFFFFF);
+ UBNEI_MOVE_DWORD_TO_SHARED_RAM(&(pRcvDWindow->mst.MST_CarrierSenseLostDuringTransmission), 0xFFFFFFFF);
+
+ UBNEI_MOVE_DWORD_TO_SHARED_RAM(&(pRcvDWindow->sst.SST_FramesSmallerThanMinimumSize), 0xFFFFFFFF);
+ UBNEI_MOVE_DWORD_TO_SHARED_RAM(&(pRcvDWindow->sst.SST_MediaSpecificStatisticsPtr), 0);
+
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pRcvDWindow->InterruptDisabled), 0xFF);
+
+ //
+ // Now switch to the DataWindow Page
+ //
+ SET_DATAWINDOW(pAdapter,INTERRUPT_DISABLED);
+
+
+ //
+ // Zero out up til end of Data Window
+ //
+ NdisZeroMappedMemory ( pAdapter->pCardRam, sizeof(HIGHNIUDATA));
+
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pDataWindow->NIU_AdapterType), AdapterType);
+
+ if ( NiuDetails[AdapterType].AdapterFlags & ASYNCHRONOUS_READY ) {
+
+ UBNEI_MOVE_SHARED_RAM_TO_USHORT(&TmpUshort, &(pDataWindow->System_Modes));
+
+ TmpUshort |= INTERNAL_READY_SYNC;
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pDataWindow->System_Modes), TmpUshort);
+
+ }
+
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pDataWindow->LED_Off_12Volts_DoParityCheck),
+ NiuDetails[AdapterType].LED_Off_12Volts_DoParityCheck
+ );
+
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pDataWindow->LED_On_12Volts_DoParityCheck),
+ NiuDetails[AdapterType].LED_On_12Volts_DoParityCheck
+ );
+
+ uc_Byte=0;
+
+ if (AdapterType == GPCNIU)
+ uc_Byte=GPNIU_IRQ_Selections[pAdapter->IrqLevel];
+
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pDataWindow->LED_Off_and_IRQ_Select),
+ uc_Byte
+ );
+
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pDataWindow->LED_On_and_IRQ_Select),
+ uc_Byte | 1
+ );
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pDataWindow->HostWindowMask),
+ (USHORT)(pAdapter->WindowMask)
+ );
+
+ UBNEI_MOVE_DWORD_TO_SHARED_RAM(&(pDataWindow->HostWindowSize),
+ (ULONG)(pAdapter->WindowSize)
+ );
+
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pDataWindow->_82586_CA_Address),
+ (USHORT)(NiuDetails[AdapterType]._82586_CA_Port)
+ );
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pDataWindow->_82586_RESET_Address),
+ (USHORT)(NiuDetails[AdapterType]._82586_RESET_Port)
+ );
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pDataWindow->HostInterruptPort),
+ (USHORT)(NiuDetails[AdapterType].HostInterruptPort)
+ );
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pDataWindow->AdapterControlPort),
+ (USHORT)(NiuDetails[AdapterType].AdapterControlPort)
+ );
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pDataWindow->IRQ_Select_and_LED_Port),
+ (USHORT)(NiuDetails[AdapterType].IRQ_Select_And_LED_Port)
+ );
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pDataWindow->DeadmanTimerPort),
+ (USHORT)(NiuDetails[AdapterType].DeadManTimerPort)
+ );
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pDataWindow->Xmt_Timeout), 1000);
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pDataWindow->Diagnostic_Timeout), 2000);
+ // UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pDataWindow->Xmt_Buffer_Start), 80);
+
+
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM((&pDataWindow->Default_Address_Base.u.SegOff.Segment),
+ (NiuDetails[AdapterType].SCPSegment)
+ );
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pDataWindow->Default_Address_Base.u.SegOff.Offset),
+ (0xfff0)
+ );
+
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM((&pDataWindow->SCP_Base.u.SegOff.Offset),
+ 0xfff6
+ );
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM((&pDataWindow->SCP_Base.u.SegOff.Segment),
+ (NiuDetails[AdapterType].SCPSegment)
+ );
+
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pDataWindow->Max_Multicast_Addresses),
+ pAdapter->MaxMultiCastTableSize
+ );
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pDataWindow->Max_General_Requests),
+ pAdapter->MaxRequests
+ );
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pDataWindow->Rcv_Buffer_Size),
+ pAdapter->ReceiveBufSize
+ );
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pDataWindow->Code_and_Xmt_Segment),
+ NiuDetails[AdapterType].OperationalCodeSegment
+ );
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pDataWindow->Xmt_Buffer_Size), 1514);
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pDataWindow->Max_Receive_Size), 1514);
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pDataWindow->Min_Receive_Size), 60);
+
+ //
+ // user definable things from dos driver, using the defaults
+ //
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pDataWindow->Rcv_Timeout), 10000);
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pDataWindow->user_FIFO_Threshold), 15);
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pDataWindow->user_PreambleLength), 2);
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pDataWindow->user_CRC_Polynomial), 0);
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pDataWindow->user_InterframeSpacing), 96);
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pDataWindow->user_SlotTime), 512);
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pDataWindow->user_MaxRetries), 15);
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pDataWindow->Max_Collisions), 16);
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pDataWindow->user_LinearPriority), 0);
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pDataWindow->user_ACR_Priority), 0);
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pDataWindow->user_BackoffMethod), 0);
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pDataWindow->user_CRS_Filter), 0);
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pDataWindow->user_CDT_Filter), 0);
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pDataWindow->user_Min_Frame_Length), 60);
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pDataWindow->MinimumHostWindowSize),
+ NiuDetails[AdapterType].MinimumWindowSize
+ );
+
+
+ NdisMoveToMappedMemory((PUCHAR)pDataWindow->Map_Table,NiuDetails[AdapterType].MappingTable,32);
+
+
+
+ NdisOpenFile(
+ &Status,
+ &FileHandle,
+ &FileLength,
+ &FileName,
+ HighestAcceptableMax
+ );
+
+ if (Status==NDIS_STATUS_SUCCESS) {
+
+ NdisMapFile(
+ &Status,
+ &ImageBuffer,
+ FileHandle
+ );
+
+ if (Status==NDIS_STATUS_SUCCESS) {
+
+ SET_CODEWINDOW(pAdapter,0);
+
+ NdisMoveToMappedMemory(pAdapter->pCardRam,ImageBuffer,FileLength);
+
+ SET_DATAWINDOW(pAdapter,INTERRUPT_DISABLED);
+
+ NdisUnmapFile(FileHandle);
+
+ NdisCloseFile(FileHandle);
+
+ return TRUE;
+
+ } else {
+
+ NdisCloseFile(FileHandle);
+
+ return FALSE;
+ }
+
+ }
+
+
+ return FALSE;
+
+}
+
+
+
+BOOLEAN
+CardStartNIU(
+ OUT PUBNEI_ADAPTER pAdapter
+ )
+
+/*++
+
+ Routine Description:
+
+
+ Arguments:
+
+
+ Return Value:
+
+
+--*/
+{
+ PLOWNIUDATA pRcvDWindow = (PLOWNIUDATA) pAdapter->pCardRam;
+ PHIGHNIUDATA pDataWindow = (PHIGHNIUDATA) pAdapter->pDataWindow;
+ PNIU_CONTROL_AREA volatile pNIU_Control = pAdapter->pNIU_Control;
+ ULONG i;
+ BOOLEAN ReturnStatus= TRUE;
+ USHORT TmpUshort;
+
+ USHORT NumberOfXmtBuffers;
+ USHORT SizeOfXmtBuffers;
+
+ USHORT NumberOfRcvBuffers;
+ USHORT SizeOfRcvBuffers;
+
+ //
+ // With interrupts disabled at the card set the flag
+ //
+ NdisMSynchronizeWithInterrupt(
+ &pAdapter->NdisInterrupt,
+ UbneiSetInitInterruptSync,
+ pAdapter
+ );
+
+ //
+ // Init NIU code and data
+ //
+
+ ReturnStatus=CardCodeDataInit(pAdapter);
+
+ if (!ReturnStatus) {
+
+ return FALSE;
+
+ }
+
+
+ SET_DATAWINDOW(pAdapter,INTERRUPT_DISABLED);
+
+ //
+ // This x86 assembly is copied to the data segment of the
+ // niu code. The segment portion of the far jump is fixed up
+ // with the correct segment. The PROM CS:IP in the top of
+ // the init code segment is set to point to the code in the
+ // data segment
+ //
+ // We wait for two things to happen before we decide the the card
+ // has success fully started. One the system state flag must indicated
+ // that the card has initialized and we have to receive and interrupt
+ // from the card. If we do not get an interrupt then the incorrect
+ // interrupt has been selected
+
+
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pDataWindow->Startup_Code[0]), 0x8C ); // mov ax,cs
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pDataWindow->Startup_Code[1]), 0xC8 );
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pDataWindow->Startup_Code[2]), 0x8E ); // mov ds,ax
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pDataWindow->Startup_Code[3]), 0xD8 );
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pDataWindow->Startup_Code[4]), 0x90 ); // nop
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pDataWindow->Startup_Code[5]), 0xEA ); // jmp far ptr
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pDataWindow->Startup_Code[6]), 0x00 );
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pDataWindow->Startup_Code[7]), 0x00 );
+
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pDataWindow->Startup_Code_CS_fixup),
+ (USHORT)NiuDetails[pAdapter->AdapterType].OperationalCodeSegment
+ );
+
+ pAdapter->uInterruptCount=0;
+
+ SET_INITWINDOW(pAdapter,0);
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pNIU_Control->us_CS_value),
+ NiuDetails[pAdapter->AdapterType].PrimaryDataSegment
+ );
+
+ TmpUshort = (USHORT)(((PUCHAR)pDataWindow->Startup_Code)-(PUCHAR)pDataWindow)+0x8000;
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pNIU_Control->us_IP_value), TmpUshort);
+
+ IF_INIT_LOUD(DbgPrint("UBNEI: down load cs:ip %04x:%04x\n",NiuDetails[pAdapter->AdapterType].PrimaryDataSegment, TmpUshort);)
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pNIU_Control->us_HWcommand), 2);
+
+ SET_DATAWINDOW(pAdapter,INTERRUPT_ENABLED);
+
+ //
+ // Wait until the system state is initialized and the interrupt has come
+ // through
+ //
+
+ UBNEI_MOVE_SHARED_RAM_TO_USHORT(&TmpUshort, &(pDataWindow->System_State));
+
+ for (i=0;(i<1000) && !((TmpUshort & INITIALIZED) && (pAdapter->uInterruptCount!=0)); i++) {
+ NdisStallExecution(1000);
+ UBNEI_MOVE_SHARED_RAM_TO_USHORT(&TmpUshort, &(pDataWindow->System_State));
+ }
+
+ if (!((TmpUshort & INITIALIZED) )) {
+ IF_INIT_LOUD( DbgPrint("CardStartNIU: NIU code did not init sys=%04x\n",TmpUshort);)
+ ReturnStatus=FALSE;
+ } else {
+ IF_INIT_LOUD (DbgPrint("CardStartNIU: NIU code Initialized sys=%04x\n",TmpUshort);)
+ }
+
+
+ SET_DATAWINDOW(pAdapter,INTERRUPT_DISABLED);
+
+ NdisMSynchronizeWithInterrupt(
+ &pAdapter->NdisInterrupt,
+ UbneiSetNormalInterruptSync,
+ pAdapter
+ );
+
+ if (pAdapter->uInterruptCount==0) {
+
+ IF_INIT_LOUD( DbgPrint("Did not get interrupt from NIU code\n");)
+
+ NdisWriteErrorLogEntry(pAdapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_INTERRUPT_CONNECT,
+ 1,
+ (ULONG)pAdapter->IrqLevel
+ );
+
+ ReturnStatus=FALSE;
+ }
+
+ if (ReturnStatus) {
+ //
+ // Calulate some statistics from info filled in by the NIU code
+ //
+
+ SET_DATAWINDOW(pAdapter,INTERRUPT_ENABLED);
+
+ UBNEI_MOVE_SHARED_RAM_TO_USHORT(&NumberOfXmtBuffers, &pDataWindow->Number_of_Xmt_Buffers);
+
+ UBNEI_MOVE_SHARED_RAM_TO_USHORT(&SizeOfXmtBuffers, &pDataWindow->Xmt_Buffer_Size);
+
+ pAdapter->TransmitBufferSpace=NumberOfXmtBuffers * SizeOfXmtBuffers;
+
+ IF_INIT_LOUD(DbgPrint("TransmitBufferSpace %d\n",pAdapter->TransmitBufferSpace);)
+
+ UBNEI_MOVE_SHARED_RAM_TO_USHORT(&NumberOfRcvBuffers, &pDataWindow->Number_of_Rcv_Buffers);
+
+ UBNEI_MOVE_SHARED_RAM_TO_USHORT(&SizeOfRcvBuffers, &pDataWindow->Rcv_Buffer_Size);
+
+
+ pAdapter->ReceiveBufferSpace=NumberOfRcvBuffers * SizeOfRcvBuffers;
+
+ IF_INIT_LOUD(DbgPrint("ReceiveBufferSpace %d\n",pAdapter->ReceiveBufferSpace);)
+
+ pAdapter->TransmitBlockSize=SizeOfXmtBuffers;
+
+ pAdapter->ReceiveBlockSize=SizeOfRcvBuffers;
+
+ }
+
+ SET_RECDWINDOW(pAdapter,INTERRUPT_ENABLED);
+
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pRcvDWindow->InterruptDisabled),0x00);
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pRcvDWindow->InterruptActive),0x00);
+
+ return ReturnStatus;
+
+}
+
+
+
+
+
+
+
+
+BOOLEAN
+NIU_General_Request3(
+ IN NIU_GEN_REQ_DPC pDPCCallback,
+ IN PVOID pContext,
+ IN USHORT RequestCode,
+ IN USHORT param1,
+ IN PUCHAR param2
+ )
+
+/*++
+
+ Routine Description:
+ This routine adds a general request to a general request queue
+ for later processing. During the interrupt DPC the request will actually
+ be sent to the card for processing. Also during the interrupt DPC
+ the requests that the card has completed will indicated.
+
+ NOTE: This code assumes that the spin lock is held
+
+ Arguments:
+
+
+ Return Value:
+
+
+--*/
+{
+ PUBNEI_ADAPTER pAdapt = pContext;
+ PLOWNIUDATA pRcvDWindow = (PLOWNIUDATA) pAdapt->pCardRam;
+ PHIGHNIUDATA pDataWindow = (PHIGHNIUDATA) pAdapt->pDataWindow;
+
+
+ USHORT RequestID,i;
+ PNIUREQUEST pRequestBlock;
+
+ IF_REQ_LOUD (DbgPrint("NIU_General_Request cmd=%d\n",RequestCode);)
+
+ IF_LOG('3');
+
+ IF_LOG((UCHAR)(RequestCode+'0'));
+
+ if (pAdapt->NIU_Requests_Pending >= pAdapt->MaxRequests) {
+ IF_REQ_LOUD (DbgPrint("NIU_General_Request: Fail--Too many request pending\n");)
+ return FALSE;
+ }
+
+
+ RequestID=pAdapt->NIU_Request_Head;
+
+ pRequestBlock=&pAdapt->NiuRequest[RequestID];
+
+ pAdapt->NIU_Requests_Pending++;
+ pAdapt->NIU_Request_Head=(pAdapt->NIU_Request_Head+1)%pAdapt->MaxRequests;
+
+
+ pRequestBlock->pContext=(PVOID) pContext;
+ pRequestBlock->pDPCFunc=pDPCCallback;
+
+ pRequestBlock->AddressList=param2;
+
+ pRequestBlock->rrbe.RequestCode=RequestCode;
+ pRequestBlock->rrbe.RequestParam1=param1;
+
+
+
+ if (RequestCode==3 || RequestCode==9) {
+ //
+ // Set station address
+ //
+ for (i=0;i<6;i++) {
+
+ pRequestBlock->rrbe.RequestData[i]=((UCHAR*)param2)[i];
+
+ }
+ }
+
+
+ NIU_Send_Request_To_Card(pAdapt);
+
+ IF_LOG('3');
+
+ ASSERT_INTERRUPT_ENABLED(pAdapt);
+
+ return TRUE;
+}
+
+
+
+
+
+VOID
+NIU_Send_Request_To_Card(
+ IN PUBNEI_ADAPTER pAdapt
+ )
+/*++
+
+ Routine Description:
+ This routine is called by the interrupt handler DPC to see if any
+ if any general request have been placed on the queue. If there request
+ they are actaully sent to the NIU by manipulating the request ring
+ buffer.
+
+ NOTE: This is called with the lock held!!!
+
+ Arguments:
+
+
+ Return Value:
+
+
+--*/
+
+{
+
+ PLOWNIUDATA pRcvDWindow = (PLOWNIUDATA) pAdapt->pCardRam;
+ PHIGHNIUDATA pDataWindow = (PHIGHNIUDATA) pAdapt->pDataWindow;
+ PORB pORB;
+ PRRBE pRRBE;
+ UCHAR ucTemp,ucTemp2;
+ USHORT usTemp;
+
+ USHORT ORBOffset;
+ USHORT BufferBase;
+ UCHAR WritePtr;
+ UCHAR ElementSize;
+
+ USHORT RequestID,i;
+ PNIUREQUEST pRequestBlock;
+
+ IF_LOG('r');
+
+ while (pAdapt->NIU_Next_Request!=pAdapt->NIU_Request_Head) {
+
+ RequestID=pAdapt->NIU_Next_Request;
+
+ pRequestBlock=&pAdapt->NiuRequest[RequestID];
+
+ // Check to see if a multicast change is already pending
+
+
+ pAdapt->NIU_Next_Request=(pAdapt->NIU_Next_Request+1)%pAdapt->MaxRequests;
+
+ SET_DATAWINDOW_SYNC(pAdapt,INTERRUPT_ENABLED);
+
+ UBNEI_MOVE_SHARED_RAM_TO_USHORT(&ORBOffset, &(pDataWindow->Request_RingBuffer));
+
+ pORB=(PORB)((PUCHAR) pAdapt->pCardRam+
+ (ORBOffset & pAdapt->WindowMask));
+
+ UBNEI_MOVE_SHARED_RAM_TO_USHORT(&BufferBase, &(pORB->ORB_BufferBase));
+
+ UBNEI_MOVE_SHARED_RAM_TO_UCHAR(&WritePtr, &(pORB->ORB_WritePtr_Byte));
+
+ UBNEI_MOVE_SHARED_RAM_TO_UCHAR(&ElementSize, &(pORB->ORB_ElementSize));
+
+
+ pRRBE=(PRRBE)((PUCHAR)pAdapt->pCardRam+
+ (WritePtr*ElementSize+
+ (BufferBase & pAdapt->WindowMask)));
+
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&pRRBE->RequestCode,pRequestBlock->rrbe.RequestCode);
+
+ IF_REQ_LOUD (DbgPrint("NIU_Send_Request_To_Card cmd=%d\n",pRequestBlock->rrbe.RequestCode);)
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&pRRBE->RequestID, RequestID);
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&pRRBE->RequestParam1, pRequestBlock->rrbe.RequestParam1);
+
+ if (pRequestBlock->rrbe.RequestCode==8) {
+
+ usTemp=CardSetMulticast(
+ pAdapt,
+ pRequestBlock->AddressList,
+ pRequestBlock->rrbe.RequestParam1
+ );
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&pRRBE->RequestParam1, usTemp);
+
+ }
+
+
+ if (pRequestBlock->rrbe.RequestCode==3 ||
+ pRequestBlock->rrbe.RequestCode==9) {
+
+ for (i=0;i<6;i++) {
+
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&pRRBE->RequestData[i], pRequestBlock->rrbe.RequestData[i]);
+
+ }
+ }
+
+ UBNEI_MOVE_SHARED_RAM_TO_UCHAR(&ucTemp,&pORB->ORB_WritePtr_Byte);
+
+ UBNEI_MOVE_SHARED_RAM_TO_UCHAR(&ucTemp2,&pORB->ORB_PtrLimit);
+
+ ucTemp++;
+ if (ucTemp>ucTemp2) {
+
+ ucTemp=0;
+ }
+
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&pORB->ORB_WritePtr_Byte,ucTemp);
+
+ SET_RECDWINDOW_SYNC(pAdapt,INTERRUPT_ENABLED);
+
+ }
+
+ SET_RECDWINDOW_SYNC(pAdapt,INTERRUPT_ENABLED);
+ return;
+
+}
+
+
+
+VOID
+NIU_General_Req_Result_Hand(
+ IN PUBNEI_ADAPTER pAdapt
+ )
+/*++
+
+ Routine Description:
+ This routine is called by the interrupt handler DPC to see if any
+ if any general request have completed. If they have then the
+ DPC will be called
+
+ NOTE: This is called with the lock held!!!
+
+ Arguments:
+
+
+ Return Value:
+
+
+--*/
+
+{
+ PHIGHNIUDATA pDataWindow = (PHIGHNIUDATA) pAdapt->pDataWindow;
+ PORB pORB;
+ PRESULTRBE pRRBE;
+ UCHAR ucTemp;
+ USHORT TmpUshort;
+ UCHAR TmpUchar1, TmpUchar2;
+
+ USHORT ResultID,RequestCode;
+ NDIS_STATUS status;
+ PNIUREQUEST pRequestBlock;
+
+
+
+ if (pAdapt->NIU_Request_Tail==pAdapt->NIU_Next_Request) {
+ //
+ // There aren't any request that have not been completed
+ //
+ IF_REQ_LOUD(DbgPrint("NIU_General_Req_Result_Hand: Nothing to Do\n");)
+ return;
+ }
+
+ //
+ // Now see if any of the requests have completed
+ //
+
+ IF_LOG('h');
+
+ SET_DATAWINDOW(pAdapt,INTERRUPT_ENABLED);
+
+ UBNEI_MOVE_SHARED_RAM_TO_USHORT(&TmpUshort, &(pDataWindow->Result_RingBuffer));
+
+ pORB=(PORB)((PUCHAR) pAdapt->pCardRam + (TmpUshort & pAdapt->WindowMask));
+
+
+ while (1) {
+
+ SET_DATAWINDOW(pAdapt,INTERRUPT_ENABLED);
+
+ UBNEI_MOVE_SHARED_RAM_TO_UCHAR(&TmpUchar1, &(pORB->ORB_ReadPtr_Byte));
+ UBNEI_MOVE_SHARED_RAM_TO_UCHAR(&TmpUchar2, &(pORB->ORB_ElementSize));
+ UBNEI_MOVE_SHARED_RAM_TO_USHORT(&TmpUshort, &(pORB->ORB_BufferBase));
+
+ pRRBE=(PRESULTRBE)((PUCHAR)pAdapt->pCardRam+
+ (TmpUchar1 * TmpUchar2 +
+ (TmpUshort & pAdapt->WindowMask)));
+
+ UBNEI_MOVE_SHARED_RAM_TO_UCHAR(&TmpUchar2, &(pORB->ORB_WritePtr_Byte));
+
+ IF_REQ_LOUD(DbgPrint("UBNEI: NIU_General_Req_Result_Hand: read=%d write=%d\n",TmpUchar1,TmpUchar2);)
+
+ if (TmpUchar1 == TmpUchar2) {
+ //
+ // There aren't any results in the ring buffer, so nothing to do
+ //
+ SET_RECDWINDOW(pAdapt,INTERRUPT_ENABLED);
+ IF_REQ_LOUD(DbgPrint("UBNEI: NIU_General_Req_Result_Hand: No results.\n");)
+ IF_LOG('H');
+ return;
+ }
+
+ //
+ // We found a result in the ring buffer
+ //
+
+ UBNEI_MOVE_SHARED_RAM_TO_USHORT(&TmpUshort, &(pRRBE->ResultCode));
+
+ if (TmpUshort == 0) {
+ status=NDIS_STATUS_SUCCESS;
+ } else {
+ IF_REQ_LOUD(DbgPrint("NIU Gen Req failed\n");)
+ status=NDIS_STATUS_FAILURE;
+ }
+
+ //
+ // The ID is an index into our request array memory block
+ //
+
+
+ UBNEI_MOVE_SHARED_RAM_TO_USHORT(&ResultID, &(pRRBE->ResultID));
+
+#if DBG
+ if (ResultID != pAdapt->NIU_Request_Tail) {
+ IF_REQ_LOUD (DbgPrint("ResultID != Request_Tail\n");)
+ }
+#endif
+
+ //
+ // We remove the result from the ring buffer
+ //
+
+ UBNEI_MOVE_SHARED_RAM_TO_UCHAR(&ucTemp, &(pORB->ORB_ReadPtr_Byte));
+
+ ucTemp++;
+
+ UBNEI_MOVE_SHARED_RAM_TO_UCHAR(&TmpUchar1, &(pORB->ORB_PtrLimit));
+
+ if (ucTemp > TmpUchar1)
+
+ ucTemp=0;
+
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pORB->ORB_ReadPtr_Byte), ucTemp);
+
+ SET_RECDWINDOW(pAdapt,INTERRUPT_ENABLED);
+
+ pRequestBlock=&pAdapt->NiuRequest[ResultID];
+ RequestCode=pRequestBlock->rrbe.RequestCode;
+
+ IF_REQ_LOUD (DbgPrint("NIU_General_Request_Result_Handler cmd=%d\n",RequestCode);)
+
+ (*pRequestBlock->pDPCFunc)(status,pRequestBlock->pContext);
+
+ pAdapt->NIU_Requests_Pending--;
+ pAdapt->NIU_Request_Tail=(pAdapt->NIU_Request_Tail+1)%pAdapt->MaxRequests;
+
+
+ IF_LOG('c');
+
+ }
+
+ IF_LOG('H');
+
+ return;
+}
+
+
+
+
+USHORT
+CardSetMulticast(
+ PUBNEI_ADAPTER pAdapter,
+ PUCHAR MulticastList,
+ UINT ListSize
+ )
+/*++
+
+ Routine Description:
+ This routine copies the multicast list into the card memory.
+ We copy the list to an area of memory just below the actual
+ multicast address list. When the card code actually processes
+ the request it will copy the list from the location up to the
+ actual location
+
+ Arguments:
+
+
+ Return Value:
+
+
+--*/
+
+{
+ PHIGHNIUDATA pDataWindow = (PHIGHNIUDATA) pAdapter->pDataWindow;
+
+ UINT NumberOfAddress,i;
+ UCHAR TmpUchar;
+
+
+
+ NdisMoveToMappedMemory(
+ (PUCHAR)&pDataWindow->Dynamically_Allocated_Area[pAdapter->MaxMultiCastTableSize],
+ MulticastList,
+ ListSize
+ );
+
+ NumberOfAddress= ListSize / 6;
+
+ // The 82586 seems to have a problem with 3 multicast addresses,
+ // so if the list is 3 long we copy the third one into the forth
+ // place in the list also
+
+ if (NumberOfAddress==3) {
+
+ IF_INIT_LOUD (DbgPrint("CardSetMulticast() padding list to 4 from 3\n");)
+
+ for (i=0;i<6;i++) {
+
+ UBNEI_MOVE_SHARED_RAM_TO_UCHAR(
+ &TmpUchar,
+ &(pDataWindow->Dynamically_Allocated_Area[pAdapter->MaxMultiCastTableSize+2][i])
+ );
+
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(
+ &(pDataWindow->Dynamically_Allocated_Area[pAdapter->MaxMultiCastTableSize+3][i]),
+ TmpUchar
+ );
+
+
+ }
+
+ NumberOfAddress+=1;
+
+ }
+
+ return (NumberOfAddress*ETH_LENGTH_OF_ADDRESS);
+}
diff --git a/private/ntos/ndis/ubnei/config.c b/private/ntos/ndis/ubnei/config.c
new file mode 100644
index 000000000..a63692eb5
--- /dev/null
+++ b/private/ntos/ndis/ubnei/config.c
@@ -0,0 +1,532 @@
+ /*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ config.c
+
+Abstract:
+
+ This file handles retrieving configration parameters for the card
+ from the registry and from the POS register on an MCA card.
+
+ The following parameters are currently used
+
+ AdapterType= 2,3,4
+
+ if (AdapterType=3) // MCA card
+ SlotNumber = Slot number
+
+ else // ISA card
+ IOAddress = Starting IO base address 350,358,360,368
+ Interrupt = 2,3,4,5,7,9,12 depending on card
+ MemoryWindow = ( c8000, d8000) other valid but not likely
+
+ All adapters
+
+ MaximumMulticastList
+ ReceiveBufferSize (256 >= X >= 1514)
+ MaxOpens
+
+
+
+Author:
+ Brian Lieuallen (BrianLie) 07/02/92
+
+Environment:
+
+ Kernel Mode Operating Systems : NT and other lesser OS's
+
+Revision History:
+
+ Brian Lieuallen BrianLie 12/15/93
+ Made it a mini-port
+
+
+
+--*/
+
+
+
+#include <ndis.h>
+#include <efilter.h>
+
+#include "niudata.h"
+#include "debug.h"
+#include "ubhard.h"
+#include "ubsoft.h"
+#include "ubnei.h"
+#include "keywords.h"
+
+
+
+extern ULONG MemoryWindows[];
+
+extern ULONG MemoryBases[];
+
+extern USHORT PortBases[];
+
+
+
+#ifdef ALLOC_PRAGMA
+#pragma NDIS_INIT_FUNCTION(UbneiReadRegistry)
+#endif
+
+
+
+
+NDIS_STATUS
+UbneiReadRegistry(
+ IN PUBNEI_ADAPTER pAdapter,
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+
+{
+
+
+ NDIS_HANDLE ConfigHandle;
+ PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
+ NDIS_STRING IOAddressStr = IOADDRESS;
+ NDIS_STRING InterruptStr = INTERRUPT;
+ NDIS_STRING AdapterTypeStr = CARDTYPE;
+ NDIS_STRING MaxMulticastListStr = MAX_MULTICAST_LIST;
+ NDIS_STRING MemWindBaseStr = MEMMAPPEDBASE;
+ NDIS_STRING ReceiveBuffSizeStr = RCVBUFSIZE;
+ NDIS_STRING DiagStr = NDIS_STRING_CONST("Diagnostics");
+ BOOLEAN ConfigError = FALSE;
+ ULONG ConfigErrorValue = 0;
+
+ NDIS_STATUS Status;
+ NDIS_MCA_POS_DATA McaData;
+ UCHAR tempByte;
+ UCHAR NetworkAddress[ETH_LENGTH_OF_ADDRESS] = {0};
+
+ //
+ // These are used when calling UbneiRegisterAdapter.
+ //
+
+
+
+ UINT ChannelNumber = 0;
+ ULONG WindowSize = 0x8000;
+ ULONG IoBaseAddr = DEFAULT_IO_BASEADDRESS;
+ ULONG MemWindBase = DEFAULT_MEMORY_WINDOW;
+ CCHAR InterruptNumber = DEFAULT_INTERRUPT_NUMBER;
+ UINT MaxMulticastList = DEFAULT_MULTICAST_SIZE;
+ UINT ReceiveBuffSize = DEFAULT_RECEIVE_BUFFER_SIZE;
+ UINT MaxRequests = DEFAULT_MAXIMUM_REQUESTS;
+ UINT AdapterType = DEFAULT_ADAPTER_TYPE;
+ UINT MaxOpens = 10;
+ BOOLEAN Diagnostics = TRUE;
+ PVOID NetAddress;
+ ULONG Length;
+ NDIS_INTERRUPT_MODE InterruptMode=NdisInterruptLatched;
+
+ NdisOpenConfiguration(
+ &Status,
+ &ConfigHandle,
+ ConfigurationHandle
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ return NDIS_STATUS_FAILURE;
+ }
+
+ //
+ // Read net address
+ //
+
+ NdisReadNetworkAddress(
+ &Status,
+ &NetAddress,
+ &Length,
+ ConfigHandle
+ );
+
+ if ((Length == ETH_LENGTH_OF_ADDRESS) && (Status == NDIS_STATUS_SUCCESS)) {
+
+ ETH_COPY_NETWORK_ADDRESS(
+ NetworkAddress,
+ NetAddress
+ );
+ }
+
+ //
+ // Read Card type
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &AdapterTypeStr,
+ NdisParameterHexInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ AdapterType = (ReturnedValue->ParameterData.IntegerData);
+ if (AdapterType>4 || AdapterType<0) AdapterType=4;
+
+ }
+
+ if (AdapterType==NIUPS) {
+
+ //
+ // The user seems to think that this is an MCA machine
+ //
+
+ IF_LOUD(DbgPrint("The card is an MCA NIUps, reading POS info\n");)
+
+ NdisReadMcaPosInformation(
+ &Status,
+ ConfigurationHandle,
+ &ChannelNumber,
+ &McaData
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ //
+ // Info read failed
+ //
+ IF_LOUD(DbgPrint("Failed to read POS information for card, slot# %d\n",ChannelNumber);)
+ goto Fail00;
+ }
+
+ if (McaData.AdapterId!=0x7012) {
+ //
+ // Not an NIUps adapter in this position
+ //
+ IF_LOUD(DbgPrint("The card found is not an NIUps\n");)
+ goto Fail00;
+ }
+
+ if (!(McaData.PosData1 & 0x01)) {
+ //
+ // Bit 0 is set if the adapter is enabled
+ //
+ IF_LOUD(DbgPrint("The NIUps is not enabled\n");)
+ goto Fail00;
+ }
+
+
+ //
+ // We have found an NIUps in the specified slot
+ //
+
+
+ if (McaData.PosData1 & 0x80) {
+ //
+ // Bit 7 is set so adpater is using IRQ 12
+ //
+ InterruptNumber=12;
+ } else {
+ //
+ // Otherwise it is using IRQ 3
+ //
+ InterruptNumber=3;
+ }
+
+ //
+ // The NIUps has a level triggered interrupt, as compared to
+ // the other two which do not
+ //
+
+ InterruptMode=NdisInterruptLevelSensitive;
+
+
+
+ //
+ // Bit 6 and 5 specify window size
+ //
+
+ tempByte= (McaData.PosData1 & 0x60) >> 5;
+ if (tempByte==3) {
+ //
+ // 3 is and illegal value for memory window size
+ //
+ goto Fail00;
+ }
+ WindowSize=MemoryWindows[tempByte];
+
+ //
+ // Bits 3-0 specify MemoryWindow base addresses
+ //
+
+ MemWindBase=MemoryBases[(McaData.PosData2 & 0x0f)];
+
+ //
+ // Bits 3-0 specify MemoryWindow base addresses
+ //
+
+ IoBaseAddr=PortBases[(McaData.PosData4 & 0x0f)];
+
+
+
+ } else {
+
+ //
+ // No MCA card, read registery for config info
+ //
+
+
+ //
+ // Read I/O Address
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &IOAddressStr,
+ NdisParameterHexInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ IoBaseAddr = (ReturnedValue->ParameterData.IntegerData);
+
+ }
+
+ //
+ // Confirm value
+ //
+
+ {
+ UCHAR Count;
+
+ static ULONG IoBases[] = { 0x350, 0x358,
+ 0x360, 0x368};
+
+ for (Count = 0 ; Count < 4; Count++) {
+
+ if (IoBaseAddr == IoBases[Count]) {
+
+ break;
+
+ }
+
+ }
+
+ if (Count == 4) {
+ //
+ // Error
+ //
+ goto Fail00;
+ }
+
+ }
+
+ //
+ // Read Memory base window
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &MemWindBaseStr,
+ NdisParameterHexInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ MemWindBase = (ReturnedValue->ParameterData.IntegerData);
+
+ }
+
+ //
+ // Confirm value
+ //
+
+
+ if (AdapterType==GPCNIU) {
+
+ //
+ // This is an EOTP card that can start on any 32k boundary
+ // from 80000h to e8000h
+ //
+
+ if ( MemWindBase< 0x80000 ||
+ MemWindBase> 0xe8000 ||
+ ((MemWindBase & 0x07fff)!=0)) {
+
+ goto Fail00;
+ }
+
+ } else {
+
+ //
+ // This is an NIUpc card
+ //
+
+ if ( MemWindBase< 0x88000 ||
+ MemWindBase> 0xe8000 ||
+ (((MemWindBase+0x8000) & 0xffff)!=0)) {
+
+ goto Fail00;
+
+ }
+
+ }
+
+
+
+
+ //
+ // Read interrupt number
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &InterruptStr,
+ NdisParameterHexInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ InterruptNumber = (CCHAR)(ReturnedValue->ParameterData.IntegerData);
+
+ }
+
+
+ //
+ // Confirm value
+ //
+
+ {
+ UCHAR Count;
+
+ static CCHAR InterruptValues[] = { 2, 3, 4, 5, 7, 9, 12 };
+
+ for (Count = 0 ; Count < 7; Count++) {
+
+ if (InterruptNumber == InterruptValues[Count]) {
+
+ break;
+
+ }
+
+ }
+
+ if (Count == 7) {
+ //
+ // Error
+ //
+ goto Fail00;
+ }
+
+ }
+
+ } // non MCA
+
+
+ //
+ // Read MaxMulticastList
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &MaxMulticastListStr,
+ NdisParameterInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ MaxMulticastList = ReturnedValue->ParameterData.IntegerData;
+
+ }
+
+ //
+ // Read ReceiveBuffSize
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &ReceiveBuffSizeStr,
+ NdisParameterInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ ReceiveBuffSize = ReturnedValue->ParameterData.IntegerData;
+ if ((ReceiveBuffSize<256) || (ReceiveBuffSize>1514)) {
+ ReceiveBuffSize=256;
+ }
+
+ }
+
+
+
+ //
+ // Read Diagnostics value
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &DiagStr,
+ NdisParameterHexInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ Diagnostics = (BOOLEAN)(ReturnedValue->ParameterData.IntegerData);
+
+ }
+
+
+ NdisCloseConfiguration(ConfigHandle);
+
+
+
+ //
+ // Set up the parameters.
+ //
+
+ if (MaxMulticastList==3) {
+ IF_LOUD(DbgPrint("Multicast size ==3 Setting to 4 to avoid 82586 bug\n");)
+ MaxMulticastList=4;
+ }
+
+
+ pAdapter->IoPortBaseAddr = (UINT)IoBaseAddr;
+ pAdapter->IrqLevel = InterruptNumber;
+ pAdapter->MemBaseAddr = (UINT)MemWindBase;
+ pAdapter->AdapterType = AdapterType;
+ pAdapter->InterruptMode = InterruptMode;
+ pAdapter->WindowSize = WindowSize;
+ pAdapter->MaxMultiCastTableSize = MaxMulticastList;
+ pAdapter->MaxRequests = MaxRequests;
+ pAdapter->MaxTransmits = DEFAULT_MAXIMUM_TRANSMITS;
+ pAdapter->ReceiveBuffers = DEFAULT_RECEIVE_BUFFERS;
+ pAdapter->ReceiveBufSize = ReceiveBuffSize;
+ pAdapter->Diagnostics = Diagnostics;
+ ETH_COPY_NETWORK_ADDRESS(pAdapter->StationAddress, NetworkAddress);
+
+
+ IF_LOUD( DbgPrint( "Registering adapter type %d\n"
+ "I/O base addr 0x%lx\ninterrupt number %ld\n"
+ "Mem Window base 0x%05lx\nWindowSize %lx\nmax multicast %ld\n"
+ "ReceiveBufferSize %ld\nMaxOpens %d\n", AdapterType,
+ IoBaseAddr, InterruptNumber,MemWindBase,WindowSize,MaxMulticastList,
+ ReceiveBuffSize,MaxOpens );)
+
+
+ return NDIS_STATUS_SUCCESS;
+
+
+Fail00:
+
+ NdisCloseConfiguration(ConfigHandle);
+ return NDIS_STATUS_FAILURE;
+}
diff --git a/private/ntos/ndis/ubnei/debug.h b/private/ntos/ndis/ubnei/debug.h
new file mode 100644
index 000000000..e3a84409b
--- /dev/null
+++ b/private/ntos/ndis/ubnei/debug.h
@@ -0,0 +1,90 @@
+
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ debug.h
+
+Abstract:
+
+ This is the debug header file for the Ungermann Bass Ethernet Controller.
+
+ It contains the various debug definitions and macros used in displaying
+ debugging information on the kernel debugger.
+
+Author:
+
+ Sanjeev Katariya (sanjeevk) 03-05-92
+
+Environment:
+
+ Kernel Mode Operating Systems : NT and other lesser OS's(dos)
+
+Revision History:
+
+ Brian Lieuallen BrianLie 12/15/93
+ Made it a mini-port
+
+--*/
+
+
+#if DBG
+
+#define IF_UBNEIDEBUG(f) if (UbneiDebugFlag & (f))
+extern ULONG UbneiDebugFlag;
+
+extern UCHAR UbneiLog[257];
+extern UCHAR LogPlace;
+
+#define IF_LOG(A) { \
+UbneiLog[LogPlace] = (A); \
+UbneiLog[LogPlace+1] = ' '; \
+UbneiLog[LogPlace+2] = ' '; \
+LogPlace++; \
+}
+
+
+#define UBNEI_DEBUG_LOUD 0x00000001 // debugging info
+#define UBNEI_DEBUG_VERY_LOUD 0x00000002 // excessive debugging info
+#define UBNEI_DEBUG_LOG 0x00000004 // enable UbneiLog
+#define UBNEI_DEBUG_CHECK_DUP_SENDS 0x00000008 // check for duplicate sends
+#define UBNEI_DEBUG_TRACK_PACKET_LENS 0x00000010 // track directed packet lens
+#define UBNEI_DEBUG_WORKAROUND1 0x00000020 // drop DFR/DIS packets
+#define UBNEI_DEBUG_CARD_BAD 0x00000040 // dump data if CARD_BAD
+#define UBNEI_DEBUG_CARD_TESTS 0x00000080 // print reason for failing
+
+#define UBNEI_DEBUG_INIT 0x00000100 // init debugging info
+
+#define UBNEI_DEBUG_SEND 0x00000200 // init debugging info
+#define UBNEI_DEBUG_RCV 0x00000400
+#define UBNEI_DEBUG_REQ 0x00000800
+#define UBNEI_DEBUG_BAD 0x00001000
+
+//
+// Macro for deciding whether to dump lots of debugging information.
+//
+
+#define IF_LOUD(A) IF_UBNEIDEBUG( UBNEI_DEBUG_LOUD ) { A }
+#define IF_VERY_LOUD(A) IF_UBNEIDEBUG( UBNEI_DEBUG_VERY_LOUD ) { A }
+#define IF_INIT_LOUD(A) IF_UBNEIDEBUG( UBNEI_DEBUG_INIT ) { A }
+#define IF_SEND_LOUD(A) IF_UBNEIDEBUG( UBNEI_DEBUG_SEND ) { A }
+#define IF_RCV_LOUD(A) IF_UBNEIDEBUG( UBNEI_DEBUG_RCV ) { A }
+#define IF_REQ_LOUD(A) IF_UBNEIDEBUG( UBNEI_DEBUG_REQ ) { A }
+
+#define IF_BAD_LOUD(A) IF_UBNEIDEBUG( UBNEI_DEBUG_BAD ) { A }
+
+#else
+
+#define IF_LOUD(A)
+#define IF_VERY_LOUD(A)
+#define IF_INIT_LOUD(A)
+#define IF_LOG(A)
+#define IF_SEND_LOUD(A)
+#define IF_RCV_LOUD(A)
+#define IF_REQ_LOUD(A)
+
+#define IF_BAD_LOUD(A)
+
+#endif
diff --git a/private/ntos/ndis/ubnei/init.c b/private/ntos/ndis/ubnei/init.c
new file mode 100644
index 000000000..6d97bf741
--- /dev/null
+++ b/private/ntos/ndis/ubnei/init.c
@@ -0,0 +1,770 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ init.c
+
+Abstract:
+
+ This is the init file for the Ungermann Bass Ethernet Controller.
+ This driver conforms to the NDIS 3.0 interface.
+
+Author:
+
+ Sanjeev Katariya (sanjeevk) 03-05-92
+
+Environment:
+
+ Kernel Mode Operating Systems : NT and other lesser OS's
+
+Revision History:
+
+ Brian Lieuallen BrianLie 07/21/92
+ Made it work.
+ Brian Lieuallen BrianLie 12/15/93
+ Made it a mini-port
+
+
+--*/
+
+
+
+#include <ndis.h>
+#include <efilter.h>
+
+#include "niudata.h"
+#include "debug.h"
+#include "ubhard.h"
+#include "ubsoft.h"
+#include "ubnei.h"
+
+
+#include "map.h"
+
+
+
+#if DBG
+
+UCHAR UbneiLog[257] = {0};
+UCHAR LogPlace = 0;
+
+#endif
+
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+
+NDIS_STATUS
+UbneiInitializeAdapter(
+ IN PUBNEI_ADAPTER pAdapter
+ );
+
+
+
+#ifdef ALLOC_PRAGMA
+#pragma NDIS_INIT_FUNCTION(DriverEntry)
+#pragma NDIS_INIT_FUNCTION(UbneiInitialize)
+#pragma NDIS_INIT_FUNCTION(UbneiInitializeAdapter)
+#endif
+
+
+#if DBG
+
+ULONG UbneiDebugFlag;
+
+#endif
+
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+
+/*++
+
+Routine Description:
+
+ This is the transfer address of the driver. It initializes all the
+ appropriate variables used and calls NdisInitializeWrapper() and
+ NdisRegisterMac().
+
+
+Arguments:
+
+Return Value:
+
+ Indicates the success or failure of the initialization.
+
+--*/
+
+{
+ NDIS_STATUS InitStatus;
+ NDIS_MINIPORT_CHARACTERISTICS Characteristics;
+ NDIS_HANDLE WrapperHandle;
+
+
+
+#if DBG
+
+ UbneiDebugFlag = 0;
+ UbneiDebugFlag|= UBNEI_DEBUG_LOG;
+ UbneiDebugFlag|= UBNEI_DEBUG_BAD;
+ UbneiDebugFlag|= UBNEI_DEBUG_LOUD;
+ UbneiDebugFlag|= UBNEI_DEBUG_INIT;
+// UbneiDebugFlag|= UBNEI_DEBUG_REQ;
+// UbneiDebugFlag|= UBNEI_DEBUG_RCV;
+// UbneiDebugFlag|= UBNEI_DEBUG_SEND;
+
+
+#endif
+
+ IF_INIT_LOUD(DbgPrint("UBNEI: DriverEntry\n");)
+
+ IF_INIT_LOUD(DbgPrint("UBNEI: size of HIGHNIUDATA is %d\n",sizeof(HIGHNIUDATA));)
+ ASSERT(sizeof(HIGHNIUDATA)==2712);
+
+ IF_INIT_LOUD(DbgPrint("UBNEI: size of LOWNIUDATA is %d\n",sizeof(LOWNIUDATA));)
+ ASSERT(sizeof(LOWNIUDATA)==294);
+
+ IF_INIT_LOUD(DbgPrint("UBNEI: size of NIU_CONTROL_AREA is %d\n",sizeof(NIU_CONTROL_AREA));)
+ ASSERT(sizeof(NIU_CONTROL_AREA)==249);
+
+
+ NdisMInitializeWrapper(
+ &WrapperHandle,
+ DriverObject,
+ RegistryPath,
+ NULL
+ );
+
+
+
+ //
+ // Prepare to call NdisRegisterMac.
+ //
+
+ Characteristics.MajorNdisVersion = UBNEI_NDIS_MAJOR_VERSION;
+ Characteristics.MinorNdisVersion = UBNEI_NDIS_MINOR_VERSION;
+ Characteristics.Reserved = 0;
+ Characteristics.CheckForHangHandler = UbneiCheckForHang;
+ Characteristics.DisableInterruptHandler = NULL; // UbneiDisableInterrupts;
+ Characteristics.EnableInterruptHandler = NULL; // UbneiEnableInterrupts;
+ Characteristics.SendHandler = UbneiMacSend;
+ Characteristics.TransferDataHandler = UbneiTransferData;
+ Characteristics.ResetHandler = UbneiReset;
+ Characteristics.SetInformationHandler = UbneiSetInformation;
+ Characteristics.QueryInformationHandler = UbneiQueryInformation;
+ Characteristics.InitializeHandler = UbneiInitialize;
+ Characteristics.HaltHandler = UbneiHalt;
+ Characteristics.ISRHandler = UbneiIsr;
+ Characteristics.HandleInterruptHandler = UbneiIsrDpc;
+ Characteristics.ReconfigureHandler = UbneiReconfigure;
+
+ InitStatus=NdisMRegisterMiniport(
+ WrapperHandle,
+ &Characteristics,
+ sizeof(Characteristics)
+ );
+
+
+#if DBG
+
+ if (InitStatus != NDIS_STATUS_SUCCESS) {
+
+ IF_LOUD(DbgPrint("UBNEI: NdisMRegisterMiniport failed with code 0x%x\n", InitStatus );)
+
+ } else {
+
+ IF_INIT_LOUD (DbgPrint("UBNEI: NdisMRegisterMiniport succeeded\n" );)
+
+
+ }
+
+#endif
+
+ return InitStatus;
+
+}
+
+
+
+
+
+
+NDIS_STATUS
+UbneiInitialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE AdapterHandle,
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+/*++
+Routine Description:
+
+ This is the UBNEI MacAddAdapter routine. The system calls this routine
+ to add support for particular UB adapter. This routine extracts
+ configuration information from the configuration data base and registers
+ the adapter with NDIS.
+
+
+Arguments:
+
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS - Adapter was successfully added.
+ NDIS_STATUS_FAILURE - Adapter was not added
+
+--*/
+{
+
+ PUBNEI_ADAPTER pAdapter;
+ NDIS_STATUS status;
+
+
+
+
+ *OpenErrorStatus=NDIS_STATUS_SUCCESS;
+
+ IF_LOUD (DbgPrint("UBNEI: Initialize\n");)
+
+ //
+ // Scan the media list for our media type (802.3)
+ //
+
+ *SelectedMediumIndex =(UINT) -1;
+
+ while (MediumArraySize > 0) {
+
+ if (MediumArray[--MediumArraySize] == NdisMedium802_3 ) {
+
+ *SelectedMediumIndex = MediumArraySize;
+
+ break;
+ }
+ }
+
+
+ if (*SelectedMediumIndex == -1) {
+
+ return NDIS_STATUS_UNSUPPORTED_MEDIA;
+
+ }
+
+
+
+ status = NdisAllocateMemory(
+ (PVOID *)&pAdapter,
+ sizeof(UBNEI_ADAPTER),
+ 0,
+ HighestAcceptableMax
+ );
+
+ if (status != NDIS_STATUS_SUCCESS) {
+
+ IF_LOUD (DbgPrint("UBNEIAddAdapter():NdisAllocateMemory() failed\n");)
+
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ NdisZeroMemory(pAdapter,sizeof(UBNEI_ADAPTER));
+
+ pAdapter->NdisAdapterHandle=AdapterHandle;
+
+
+ //
+ // Read Registery information into Adapter structure
+ //
+
+ if (UbneiReadRegistry(pAdapter,ConfigurationHandle)==NDIS_STATUS_SUCCESS) {
+ //
+ // We got the registry info try to register the adpater
+ //
+
+
+ if (UbneiInitializeAdapter(
+ pAdapter)== NDIS_STATUS_SUCCESS) {
+
+
+ return NDIS_STATUS_SUCCESS;
+
+ }
+
+ } else {
+ IF_LOUD(DbgPrint("Failed to get config info, probably bad Slot number\n");)
+ }
+
+ //
+ // We failed to register the adapter for some reason, so free the
+ // memory for the adapter block and return failure
+
+ NdisFreeMemory(pAdapter,
+ sizeof(UBNEI_ADAPTER),
+ 0);
+
+ return NDIS_STATUS_FAILURE;
+
+}
+
+
+
+
+
+
+NDIS_STATUS
+UbneiInitializeAdapter(
+ IN PUBNEI_ADAPTER pAdapter
+ )
+
+/*++
+
+Routine Description:
+
+ Called when a new adapter should be registered.
+ Initializes the adapter block, and calls NdisRegisterAdapter().
+
+Arguments:
+
+ AdapterName - The name that the system will refer to the adapter by.
+ ConfigurationHandle - Handle passed to MacAddAdapter.
+ Others - Adapter-specific parameters as defined in defaults.h.
+
+Return Value:
+
+ Indicates the success or failure of the registration.
+
+--*/
+
+{
+ NDIS_STATUS Status;
+ NDIS_PHYSICAL_ADDRESS PhysicalAddress;
+
+ NDIS_INTERFACE_TYPE InterfaceType;
+
+ BOOLEAN ConfigError = FALSE;
+ NDIS_ERROR_CODE ConfigErrorCode;
+
+ //
+ // First things first, We only support the following adapter types
+ //
+ // GPCNIU--EOTP
+ // NIUpc --Old long 16-bit card
+ // NIUps --Basically a MicroChannel EOTP
+ //
+
+ if ((pAdapter->AdapterType!=NIUPC) &&
+ (pAdapter->AdapterType!=NIUPS) &&
+ (pAdapter->AdapterType!=GPCNIU)) {
+
+ IF_LOUD(DbgPrint("Sorry, Unsupported UB adapter type %d\n",
+ pAdapter->AdapterType);)
+
+ ConfigError = TRUE;
+ ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION;
+ goto RegisterAdapter;
+
+ }
+
+
+
+ pAdapter->MaxRequests=DEFAULT_MAXIMUM_REQUESTS;
+
+ pAdapter->MapRegSync.pAdapter=pAdapter;
+
+
+ pAdapter->WindowMask=pAdapter->WindowSize-1;
+ pAdapter->NotWindowMask=~pAdapter->WindowMask;
+
+
+RegisterAdapter:
+
+ //
+ // Set up the AdapterInformation structure; zero it
+ // first in case it is extended later.
+ //
+
+ if (pAdapter->AdapterType==NIUPS) {
+
+ InterfaceType = NdisInterfaceMca;
+
+ } else {
+
+ InterfaceType = NdisInterfaceIsa;
+
+ }
+
+
+ NdisMSetAttributes(
+ pAdapter->NdisAdapterHandle,
+ pAdapter,
+ FALSE,
+ InterfaceType
+ );
+
+ Status=NdisMRegisterIoPortRange(
+ &pAdapter->TranslatedIoBase,
+ pAdapter->NdisAdapterHandle,
+ pAdapter->IoPortBaseAddr,
+ 4
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ IF_INIT_LOUD (DbgPrint("UBNEI: Failed to register ports\n");)
+
+ NdisWriteErrorLogEntry(
+ pAdapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_RESOURCE_CONFLICT,
+ 1,
+ (ULONG)pAdapter->MemBaseAddr
+ );
+
+ goto fail1;
+
+ }
+
+
+ pAdapter->MapPort = (PUCHAR)pAdapter->TranslatedIoBase + 0;
+
+ IF_INIT_LOUD (DbgPrint("Map port is 0x%x\n",pAdapter->MapPort);)
+
+ pAdapter->InterruptStatusPort = (PUCHAR)pAdapter->TranslatedIoBase + 1;
+
+ IF_INIT_LOUD (DbgPrint("Interrupt port is 0x%x\n",pAdapter->InterruptStatusPort);)
+
+ pAdapter->SetWindowBasePort = (PUCHAR)pAdapter->TranslatedIoBase + 2;
+
+ IF_INIT_LOUD (DbgPrint("Window base port is 0x%x\n",pAdapter->SetWindowBasePort);)
+
+
+
+
+ //
+ // Map the memory Window into the host address space
+ //
+
+ NdisSetPhysicalAddressHigh(PhysicalAddress, 0);
+ NdisSetPhysicalAddressLow(PhysicalAddress, pAdapter->MemBaseAddr);
+
+
+ Status=NdisMMapIoSpace(
+ &pAdapter->pCardRam,
+ pAdapter->NdisAdapterHandle,
+ PhysicalAddress,
+ pAdapter->WindowSize
+ );
+
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NdisWriteErrorLogEntry(
+ pAdapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_RESOURCE_CONFLICT,
+ 1,
+ (ULONG)pAdapter->MemBaseAddr
+ );
+
+ goto fail3;
+
+ }
+
+
+
+ IF_LOUD (DbgPrint("UBNEI: Card mem is at 0x%lx\n",pAdapter->pCardRam);)
+
+ //
+ // Given the memory window and parameters, we now have to setup the
+ // various data units related to ports and memory address in the adapter
+ // block accordingly
+ //
+
+ if (!CardSetup(pAdapter)) {
+
+ //
+ // The NIC and its structures could not be poperly initialized
+ //
+
+ IF_LOUD (DbgPrint("UbneiRegisterAdapter(): CardSetup() Failed\n");)
+
+ Status = NDIS_STATUS_FAILURE;
+
+ NdisWriteErrorLogEntry(
+ pAdapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
+ 0
+ );
+
+ goto fail4;
+ }
+
+
+
+ //
+ // Perform card tests.
+ //
+ if (!CardTest(pAdapter) ) {
+ IF_LOUD ( DbgPrint("CardTest() failed trying again\n");)
+ if (!CardTest(pAdapter) ) {
+
+ IF_LOUD ( DbgPrint("CardTest() failed a second time, game over\n");)
+
+ Status = NDIS_STATUS_FAILURE;
+
+ NdisWriteErrorLogEntry(pAdapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
+ 4,
+ (ULONG)pAdapter->AdapterType,
+ (ULONG)pAdapter->IrqLevel,
+ (ULONG)pAdapter->IoPortBaseAddr,
+ (ULONG)pAdapter->MemBaseAddr
+ );
+
+ goto fail4;
+ }
+ }
+
+
+ //
+ // Copy in permanent address if necessary
+ //
+
+ if (!(pAdapter->StationAddress[0] |
+ pAdapter->StationAddress[1] |
+ pAdapter->StationAddress[2] |
+ pAdapter->StationAddress[3] |
+ pAdapter->StationAddress[4] |
+ pAdapter->StationAddress[5])) {
+
+ ETH_COPY_NETWORK_ADDRESS(pAdapter->StationAddress,
+ pAdapter->PermanentAddress
+ );
+ }
+
+
+
+
+ //
+ // Set up the interrupt handlers.
+ //
+ // It seems that during the reset of an EOTP card it generates and interrupt
+ // on IRQ 5. Note the card has not been told to use IRQ 5, it simply seems to
+ // do this by default.
+ //
+ // If we are initializing IRQ 5 then we will get an interrupt imediatly upon
+ // initializing the IRQ
+ //
+ // If we aren't using 5 then anything that is will get an extra interrupt!!!
+ //
+ // Fine UB engineering
+ //
+ //
+
+ SET_INITWINDOW(pAdapter,INTERRUPT_DISABLED);
+ SET_INITWINDOW(pAdapter,INTERRUPT_ENABLED);
+
+ pAdapter->InInit = TRUE;
+
+ Status=NdisMRegisterInterrupt(
+ &pAdapter->NdisInterrupt, // interrupt info str
+ pAdapter->NdisAdapterHandle, // NDIS adapter handle
+ (UINT)pAdapter->IrqLevel, // vector or int number
+ (UINT)pAdapter->IrqLevel, // level or priority
+ TRUE,
+ FALSE, // NOT shared
+ pAdapter->InterruptMode
+ );
+
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ IF_LOUD (DbgPrint("UBNEI: NdisInitializeInterruptFailed\n");)
+ NdisWriteErrorLogEntry(
+ pAdapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_INTERRUPT_CONNECT,
+ 1,
+ (ULONG)pAdapter->IrqLevel
+ );
+
+
+ goto fail3;
+ }
+
+ IF_INIT_LOUD(DbgPrint("UBNEI: Pause for spurious ISR\n");)
+
+ NdisStallExecution(2000);
+
+
+ //
+ // Here we actaully start the down load code running on the card
+ //
+
+
+ if (!CardStartNIU(pAdapter)) {
+
+ //
+ // The NIU code failed to start.
+ //
+
+ IF_LOUD ( DbgPrint("CardStartNIU() : Failed \n");)
+
+ Status = NDIS_STATUS_FAILURE;
+
+ NdisWriteErrorLogEntry(
+ pAdapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 0
+ );
+
+ goto fail7;
+ }
+
+
+ NIU_OPEN_ADAPTER(pAdapter,DummyDPC);
+
+ NIU_SET_STATION_ADDRESS(pAdapter,DummyDPC,pAdapter->StationAddress);
+
+
+
+ //
+ // Initialization completed successfully.
+ //
+
+ IF_LOUD (DbgPrint("UbneiRegisterAdapter() Succeeded\n");)
+
+ return NDIS_STATUS_SUCCESS;
+
+
+ //
+ // IF WE ARE HERE SOME INITIALIZATION FAILURE OCCURRED
+ //
+
+
+
+ //
+ // Code to unwind what has already been set up when a part of
+ // initialization fails, which is jumped into at various
+ // points based on where the failure occured. Jumping to
+ // a higher-numbered failure point will execute the code
+ // for that block and all lower-numbered ones.
+ //
+
+fail7:
+ NdisMDeregisterInterrupt(&pAdapter->NdisInterrupt);
+
+
+
+fail4:
+ NdisMUnmapIoSpace(
+ pAdapter->NdisAdapterHandle,
+ pAdapter->pCardRam,
+ pAdapter->WindowSize
+ );
+fail3:
+ NdisMDeregisterIoPortRange(
+ pAdapter->NdisAdapterHandle,
+ pAdapter->IoPortBaseAddr,
+ 4,
+ pAdapter->TranslatedIoBase
+ );
+
+fail1:
+
+
+ IF_LOUD (DbgPrint("UbneiRegisterAdapter() Failed\n");)
+//fail0:
+ return Status;
+}
+
+
+
+
+
+
+
+
+
+VOID
+UbneiHalt(
+ IN NDIS_HANDLE MiniportHandle
+ )
+
+{
+
+ PUBNEI_ADAPTER pAdapter=MiniportHandle;
+
+ IF_LOG('q')
+
+ IF_INIT_LOUD(DbgPrint("UBNEI: Halt\n");)
+
+ NdisMDeregisterInterrupt(&pAdapter->NdisInterrupt);
+
+ IF_INIT_LOUD(DbgPrint("UBNEI: Halt: reseting adapter\n");)
+
+ NdisRawWritePortUchar(
+ pAdapter->MapPort,
+ INTERRUPT_DISABLED | RESET_SET
+ );
+
+
+ if ( pAdapter->AdapterType == GPCNIU ) {
+
+ IF_INIT_LOUD( DbgPrint("UBNEI: Disabling the EOTP adapter\n");)
+
+ NdisRawWritePortUchar(
+ pAdapter->InterruptStatusPort,
+ 0x00
+ );
+ }
+
+
+ NdisMUnmapIoSpace(
+ pAdapter->NdisAdapterHandle,
+ pAdapter->pCardRam,
+ pAdapter->WindowSize
+ );
+
+ NdisMDeregisterIoPortRange(
+ pAdapter->NdisAdapterHandle,
+ pAdapter->IoPortBaseAddr,
+ 4,
+ pAdapter->TranslatedIoBase
+ );
+
+ NdisFreeMemory(
+ pAdapter,
+ sizeof(UBNEI_ADAPTER),
+ 0
+ );
+
+ IF_LOG('Q')
+
+}
+
+
+NDIS_STATUS
+UbneiReconfigure(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+
+{
+
+ IF_INIT_LOUD(DbgPrint("UBNEI: Reconfigure\n");)
+
+ return NDIS_STATUS_NOT_SUPPORTED;
+
+}
diff --git a/private/ntos/ndis/ubnei/initdata.c b/private/ntos/ndis/ubnei/initdata.c
new file mode 100644
index 000000000..3d3130b1b
--- /dev/null
+++ b/private/ntos/ndis/ubnei/initdata.c
@@ -0,0 +1,223 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ card.c
+
+Abstract:
+
+ This is the mac ndis file for the Ungermann Bass Ethernet Controller.
+ This driver conforms to the NDIS 3.0 interface.
+
+ It is here that the NDIS3.0 functions defined in the MAC characteristic
+ table have been deinfed.
+
+Author:
+
+ Sanjeev Katariya (sanjeevk) 03-05-92
+
+Environment:
+
+ Kernel Mode Operating Systems : NT and other lesser OS's
+
+Revision History:
+
+ Brian Lieuallen BrianLie 07/21/92
+ Made it work.
+ Brian Lieuallen BrianLie 12/15/93
+ Made it a mini-port
+
+
+
+--*/
+
+
+
+// INCLUDES
+#include <ndis.h>
+#include <efilter.h>
+
+#include "niudata.h"
+#include "debug.h"
+
+#include "ubhard.h"
+#include "ubsoft.h"
+#include "ubnei.h"
+
+#include "map.h"
+
+#ifdef NDIS_NT
+#ifdef ALLOC_DATA_PRAGMA
+
+#pragma data_seg("INIT")
+
+#endif
+#endif
+
+
+
+
+NIUDETAILS NiuDetails[6]={
+// PCNIU--Not supported
+ {0},
+
+// Cost_Reduced-PCNIU-- Not Supported
+ {0},
+
+// NIUpc(long 16-bit card)
+ { { 0x02, 0x12, 0x06, 0x16,
+ 0x0A, 0x1A, 0x0E, 0x1E
+ },
+
+ ATLANTA,
+ NIUPC_MINIMUM_WINDOW_SIZE,
+ NIUPC_OPERATIONAL_CS,
+ NIUPC_PRIMARY_DS,
+ NIUPC_TX_BUFFER_SEGS,
+ NIUPC_HIGHEST_RAM_SEGS,
+ NIUPC_SCSP_SEGS,
+
+ NIUPC_POD_STATUS_ADDR,
+
+ NIUPC_HOST_INTR_PORT,
+ NIUPC_82586_CA_PORT,
+ NIUPC_82586_RESET_PORT,
+ NIUPC_ADAPTER_CTRL_PORT,
+
+ NIUPC_LEDOFF_12V_DOPARCHK,
+ NIUPC_LEDON_12V_DOPARCHK,
+
+ NIUPC_IRQSEL_LEDPORT,
+ NIUPC_DEADMAN_TIMERPORT,
+
+ { NIUPC_CLI_OFFSET,
+ NIUPC_MAP_OFFSET,
+ NIUPC_INTR_STATUS_OFFSET,
+ NIUPC_SETWINBASE_OFFSET
+ },
+
+ NIUPC_ADAPTER_FLAGS,
+ NIUPC_ADAPTER_CODE
+ },
+
+// NIUps (MCA EOTP)
+ { { 0x02, 0x06, 0x0A, 0x0E,
+ 0x12, 0x16, 0x1A, 0x1E,
+ 0x22, 0x26, 0x2A, 0x2E,
+ 0x32, 0x36, 0x3A, 0x3E,
+ 0x42, 0x46, 0x4A, 0x4E,
+ 0x52, 0x56, 0x5A, 0x5E,
+ 0x62, 0x66, 0x6A, 0x6E,
+ 0x72, 0x76, 0x7A, 0x7E
+ },
+
+ CHAMELEON,
+ GPCNIU_MINIMUM_WINDOW_SIZE,
+ GPCNIU_OPERATIONAL_CS,
+ GPCNIU_PRIMARY_DS,
+ GPCNIU_TX_BUFFER_SEGS,
+ GPCNIU_HIGHEST_RAM_SEGS,
+ GPCNIU_SCSP_SEGS,
+
+ GPCNIU_POD_STATUS_ADDR,
+
+ GPCNIU_HOST_INTR_PORT,
+ GPCNIU_82586_CA_PORT,
+ GPCNIU_82586_RESET_PORT,
+ GPCNIU_ADAPTER_CTRL_PORT,
+
+ GPCNIU_LEDOFF_12V_DOPARCHK,
+ GPCNIU_LEDON_12V_DOPARCHK,
+
+ GPCNIU_IRQSEL_LEDPORT,
+ GPCNIU_DEADMAN_TIMERPORT,
+
+ { GPCNIU_CLI_OFFSET,
+ GPCNIU_MAP_OFFSET,
+ GPCNIU_INTR_STATUS_OFFSET,
+ GPCNIU_SETWINBASE_OFFSET
+ },
+
+ GPCNIU_ADAPTER_FLAGS,
+ NIUPS_ADAPTER_CODE
+ },
+
+
+// GPCNIU (EOTP)
+ { { 0x02, 0x06, 0x0A, 0x0E,
+ 0x12, 0x16, 0x1A, 0x1E,
+ 0x22, 0x26, 0x2A, 0x2E,
+ 0x32, 0x36, 0x3A, 0x3E,
+ 0x42, 0x46, 0x4A, 0x4E,
+ 0x52, 0x56, 0x5A, 0x5E,
+ 0x62, 0x66, 0x6A, 0x6E,
+ 0x72, 0x76, 0x7A, 0x7E
+ },
+
+ CHAMELEON,
+ GPCNIU_MINIMUM_WINDOW_SIZE,
+ GPCNIU_OPERATIONAL_CS,
+ GPCNIU_PRIMARY_DS,
+ GPCNIU_TX_BUFFER_SEGS,
+ GPCNIU_HIGHEST_RAM_SEGS,
+ GPCNIU_SCSP_SEGS,
+
+ GPCNIU_POD_STATUS_ADDR,
+
+ GPCNIU_HOST_INTR_PORT,
+ GPCNIU_82586_CA_PORT,
+ GPCNIU_82586_RESET_PORT,
+ GPCNIU_ADAPTER_CTRL_PORT,
+
+ GPCNIU_LEDOFF_12V_DOPARCHK,
+ GPCNIU_LEDON_12V_DOPARCHK,
+
+ GPCNIU_IRQSEL_LEDPORT,
+ GPCNIU_DEADMAN_TIMERPORT,
+
+ { GPCNIU_CLI_OFFSET,
+ GPCNIU_MAP_OFFSET,
+ GPCNIU_INTR_STATUS_OFFSET,
+ GPCNIU_SETWINBASE_OFFSET
+ },
+
+ GPCNIU_ADAPTER_FLAGS,
+ GPCNIU_ADAPTER_CODE
+ },
+
+// PCNIUex -- Not Supported
+ {0},
+
+ };
+
+
+UCHAR GPNIU_IRQ_Selections[13]={0,0,0x10,0x20,0x30,0x40,0,0x50,0,0x10,0,0,0x60};
+
+
+
+
+ULONG MemoryWindows[4]={0x08000,0x10000,0x04000,0x0};
+
+ULONG MemoryBases[16]={0x0c0000,0x0c4000,0x0c8000,0x0cc000,
+ 0x0d0000,0x0d4000,0x0d8000,0x0dc000,
+ 0xe28000,0x0c4000,0x0c8000,0x0cc000,
+ 0x0d0000,0x0d4000,0x0d8000,0x0dc000};
+
+USHORT PortBases[16]={ 0x350,0x350,0x358,0x358,
+ 0x360,0x360,0x368,0x368,
+ 0x368,0x368,0x368,0x368,
+ 0x368,0x368,0x368,0x368};
+
+
+
+
+
+#ifdef NDIS_NT
+#ifdef ALLOC_DATA_PRAGMA
+
+#pragma data_seg()
+
+#endif
+#endif
diff --git a/private/ntos/ndis/ubnei/interrup.c b/private/ntos/ndis/ubnei/interrup.c
new file mode 100644
index 000000000..392eed154
--- /dev/null
+++ b/private/ntos/ndis/ubnei/interrup.c
@@ -0,0 +1,337 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ macndis.c
+
+Abstract:
+
+ This is the mac ndis file for the Ungermann Bass Ethernet Controller.
+ This driver conforms to the NDIS 3.0 interface.
+
+ It is here that the NDIS3.0 functions defined in the MAC characteristic
+ table have been deinfed.
+
+Author:
+
+ Sanjeev Katariya (sanjeevk) 03-05-92
+
+Environment:
+
+ Kernel Mode Operating Systems : NT and other lesser OS's(dos)
+
+Revision History:
+
+ Brian Lieuallen BrianLie 12/15/93
+ Made it a mini-port
+
+--*/
+
+
+
+
+#include <ndis.h>
+#include <efilter.h>
+
+#include "niudata.h"
+#include "debug.h"
+#include "ubhard.h"
+#include "ubsoft.h"
+#include "ubnei.h"
+
+#include "map.h"
+
+
+// GLOBAL VARIABLES
+
+
+
+
+VOID
+UbneiIsr(
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueDpc,
+ IN NDIS_HANDLE Context
+ )
+
+
+/*++
+
+Routine Description:
+ This is the interrupt service routine for the driver.
+ All it does is disable interrupts from the NIU code and dismiss the
+ interrupt from the card. Interrupts will remain disabled until the
+ DPC runs.
+
+ Any time that interrupts are enabled, the receive window will be
+ the one that is mapped in. This is done beacuse in order to dismiss
+ the interrupt from the card you must write a value to the map port
+ with zero bit clear and then set.
+
+
+Arguments:
+
+ ServiceContext - pointer to the adapter object
+
+Return Value:
+
+ TRUE, if the DPC is to be executed, otherwise FALSE.
+
+--*/
+
+{
+ PUBNEI_ADAPTER pAdapter = ((PUBNEI_ADAPTER)Context);
+ PLOWNIUDATA pRcvDWindow = (PLOWNIUDATA) pAdapter->pCardRam;
+
+ *InterruptRecognized=TRUE;
+ *QueueDpc=TRUE;
+
+ IF_VERY_LOUD(DbgPrint("Ubnei: ISR\n");)
+
+
+ IF_LOG('i');
+
+ if (pAdapter->InInit) {
+
+ IF_LOUD(DbgPrint("UBNEI: Isr durring init\n");)
+
+ pAdapter->uInterruptCount++;
+
+ SET_DATAWINDOW(pAdapter,INTERRUPT_DISABLED);
+ SET_DATAWINDOW(pAdapter,INTERRUPT_ENABLED);
+ SET_DATAWINDOW(pAdapter,INTERRUPT_DISABLED);
+
+ IF_LOG('|');
+
+ *QueueDpc=FALSE;
+
+ return;
+ }
+
+
+ if (pAdapter->WaitingForDPC) {
+ //
+ // Spurious interrupt???
+ //
+
+ IF_LOG('!');
+
+ IF_LOUD (DbgPrint("UBNEI: Isr ran while in DPC\n");)
+
+ *InterruptRecognized=FALSE;
+
+ *QueueDpc=FALSE;
+
+ return;
+ }
+
+ //
+ // Dismiss the interrupt from the card.
+ // To do this we need to write a zero to bit 1 of the
+ // the map port followed by a one to bit 1
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MapPort,
+ pAdapter->MapRegSync.CurrentMapRegister & ~(INTERRUPT_ENABLED | RESET_SET)
+ );
+
+
+ NdisRawWritePortUchar(
+ pAdapter->MapPort,
+ pAdapter->MapRegSync.CurrentMapRegister | INTERRUPT_ENABLED
+ );
+
+
+ pAdapter->WaitingForDPC=TRUE;
+
+
+ IF_LOG('I');
+
+ return;
+
+}
+
+
+
+
+
+VOID
+UbneiIsrDpc(
+ IN NDIS_HANDLE Context
+ )
+
+/*++
+
+Routine Description:
+ This is the Interrupt DPC routine. This routine is the workhorse of
+ this driver. The only code that changes the map register is called
+ by this rountine. While this routine is running interrupts are disabled
+ from the card. This code enables them on exit.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PUBNEI_ADAPTER pAdapter = ((PUBNEI_ADAPTER)Context);
+ PLOWNIUDATA pRcvDWindow = (PLOWNIUDATA) pAdapter->pCardRam;
+
+ ASSERT_RECEIVE_WINDOW( pAdapter);
+
+ IF_VERY_LOUD (DbgPrint("UBNEI: DPC called\n");)
+
+ IF_LOG('p');
+
+ //
+ // The down load code will not generate interrupts if the
+ // interrupt disable flag is set. We also leave the InterruptActive
+ // set which also prevents additional interrupts.
+ //
+//
+// Since the Interreupt active flag is set, there is really no reason
+// to set the interrupt disabled flag to. One fewer access across the isa bus
+//
+// UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pRcvDWindow->InterruptDisabled), 0xff);
+
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pRcvDWindow->WorkForHost), 0x0);
+
+
+
+ //
+ // This rountine will indicate all receives that are in the receive
+ // buffers on the card. It does not return until it has indicated all
+ // of the receives.
+ //
+ CheckForReceives(pAdapter);
+
+ //
+ // If we filled up all the cards send buffer, then we would have queue
+ // the packet and ask the card to generate an interrupt when there was
+ // room. If the queue isn't empty, try to send some packet to the card.
+ //
+
+ if (pAdapter->WaitingForXmitInterrupt) {
+
+ pAdapter->WaitingForXmitInterrupt=FALSE;
+
+ IF_LOUD(DbgPrint("UBNEI: Xmt interrupt\n");)
+
+ IF_LOG('O');
+
+ NdisMSendResourcesAvailable(pAdapter->NdisAdapterHandle);
+
+ }
+
+
+ //
+ // This routine handles completeing NIU requests
+ //
+ if (pAdapter->NIU_Request_Tail!=pAdapter->NIU_Next_Request) {
+ //
+ // We have an outstanding request see if it has completed
+ //
+ NIU_General_Req_Result_Hand(pAdapter);
+
+ }
+
+
+ //
+ // Re-enable interrupts from the NIU code.
+ //
+
+ pAdapter->DpcHasRun=TRUE;
+
+ pAdapter->WaitingForDPC=FALSE;
+
+ ASSERT_RECEIVE_WINDOW( pAdapter);
+
+ //
+ // Allow the card to generate an interrupt to us
+ //
+ // The download code will not interrupt us if either of these
+ // memory locations are non zero.
+ //
+ // Before the down load code generates an interrupt to us
+ // it will set the InterruptActive flag. This will prevent it
+ // from generating any more until we clear it.
+ //
+ //
+
+//
+// Combine these two writes to the shared ram to one word write
+//
+// UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pRcvDWindow->InterruptActive), 0x0);
+//
+// UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pRcvDWindow->InterruptDisabled), 0x0);
+//
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM((PUSHORT)&(pRcvDWindow->InterruptDisabled), 0x0);
+
+
+
+ IF_LOG('P');
+
+// ASSERT_INTERRUPT_ENABLED(pAdapter);
+
+ return;
+}
+
+
+BOOLEAN
+UbneiSetInitInterruptSync(
+ PVOID Context
+ )
+/*++
+
+Routine Description:
+ This routine is called by the init code to set the flag to
+ cause the interrupt to handled by the init code.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PUBNEI_ADAPTER pAdapter = ((PUBNEI_ADAPTER)Context);
+
+ pAdapter->InInit=TRUE;
+ return TRUE;
+}
+
+
+
+BOOLEAN
+UbneiSetNormalInterruptSync(
+ PVOID Context
+ )
+/*++
+
+Routine Description:
+ This routine is called by the init code to set the flag to
+ cause the interrupt to handled by the normal runtime code.
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PUBNEI_ADAPTER pAdapter = ((PUBNEI_ADAPTER)Context);
+
+ pAdapter->InInit=FALSE;
+ return TRUE;
+}
diff --git a/private/ntos/ndis/ubnei/keywords.h b/private/ntos/ndis/ubnei/keywords.h
new file mode 100644
index 000000000..963325196
--- /dev/null
+++ b/private/ntos/ndis/ubnei/keywords.h
@@ -0,0 +1,57 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ keywords.h
+
+Abstract:
+
+ Contains all Ndis2 and Ndis3 mac-specific keywords.
+
+Author:
+
+ Bob Noradki
+
+Environment:
+
+ This driver is expected to work in DOS, OS2 and NT at the equivalent
+ of kernal mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+
+
+--*/
+#ifndef NDIS2
+#define NDIS2 0
+#endif
+
+#if NDIS2
+
+#define IOADDRESS NDIS_STRING_CONST("IO_Port")
+#define INTERRUPT NDIS_STRING_CONST("IRQ_Level")
+#define MAX_MULTICAST_LIST NDIS_STRING_CONST("MaxMulticast")
+#define CARDTYPE NDIS_STRING_CONST("AdapterType")
+#define MEMMAPPEDBASE NDIS_STRING_CONST("MemoryWindow")
+#define RCVBUFSIZE NDIS_STRING_CONST("ReceiveBufSize")
+
+#else // NDIS3
+
+
+#define CARDTYPE NDIS_STRING_CONST("CardType")
+#define MEMMAPPEDBASE NDIS_STRING_CONST("MemoryMappedBaseAddress")
+#define IOADDRESS NDIS_STRING_CONST("IoBaseAddress")
+#define INTERRUPT NDIS_STRING_CONST("InterruptNumber")
+#define MAX_MULTICAST_LIST NDIS_STRING_CONST("MaximumMulticastList")
+#define RCVBUFSIZE NDIS_STRING_CONST("ReceiveBufferSize")
+
+#endif
diff --git a/private/ntos/ndis/ubnei/makefile b/private/ntos/ndis/ubnei/makefile
new file mode 100644
index 000000000..677d610db
--- /dev/null
+++ b/private/ntos/ndis/ubnei/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/ubnei/makefile.inc b/private/ntos/ndis/ubnei/makefile.inc
new file mode 100644
index 000000000..8c67f2e22
--- /dev/null
+++ b/private/ntos/ndis/ubnei/makefile.inc
@@ -0,0 +1,5 @@
+ubnei.bin: $(TARGETEXEFILES)
+ chmode -r ubnei.bin
+ binplace ubnei.bin
+ touch ubnei.bin
+ chmode +r ubnei.bin
diff --git a/private/ntos/ndis/ubnei/map.c b/private/ntos/ndis/ubnei/map.c
new file mode 100644
index 000000000..e0901061a
--- /dev/null
+++ b/private/ntos/ndis/ubnei/map.c
@@ -0,0 +1,256 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ init.c
+
+Abstract:
+
+ This is the init file for the Ungermann Bass Ethernet Controller.
+ This driver conforms to the NDIS 3.0 interface.
+
+Author:
+
+ Brian Lieuallen BrianLie 11/21/93
+
+Environment:
+
+ Kernel Mode Operating Systems : NT and other lesser OS's
+
+Revision History:
+
+ Brian Lieuallen BrianLie 12/15/93
+ Made it a mini-port
+
+
+--*/
+
+#include <ndis.h>
+//#include <efilter.h>
+
+#include "niudata.h"
+#include "debug.h"
+#include "ubhard.h"
+#include "ubsoft.h"
+#include "ubnei.h"
+
+#include "map.h"
+
+
+VOID
+UbneiMapRegisterChangeSync(
+ PSYNC_CONTEXT Context
+ )
+
+{
+ PUBNEI_ADAPTER pAdapter=(PUBNEI_ADAPTER) Context->pAdapter;
+
+#if DBG
+
+ UCHAR MapByte;
+
+ if (pAdapter->AdapterType==GPCNIU) {
+
+ NdisRawReadPortUchar(
+ pAdapter->MapPort,
+ &MapByte
+ );
+
+
+ if ((MapByte & 0xfc) != Context->CurrentMapRegister & 0xfc) {
+ IF_BAD_LOUD(
+ DbgPrint("UBNEI: BOOM! Wrong window mapped is %02x should be %02x\n",MapByte,Context->CurrentMapRegister);
+ DbgBreakPoint();
+ )
+ }
+ }
+
+#endif
+
+ NdisRawWritePortUchar(
+ pAdapter->MapPort,
+ Context->NewMapRegister
+ );
+
+
+ Context->CurrentMapRegister=Context->NewMapRegister;
+
+ return;
+}
+
+
+
+
+
+#if DBG
+//
+// We declare these macros as functions to simplify debugging with
+// the kd
+
+
+
+VOID
+ASSERT_INTERRUPT_ENABLED(
+ PUBNEI_ADAPTER pAdapter
+ )
+
+{
+
+ UCHAR MapByte;
+
+ if (pAdapter->AdapterType==GPCNIU) {
+
+ NdisRawReadPortUchar(
+ (ULONG)pAdapter->MapPort,
+ &MapByte
+ );
+
+ if ((MapByte & INTERRUPT_ENABLED) == 0) {
+
+ IF_LOUD(
+ DbgPrint("Ubnei: Interrupt not enabled value=%02x\n",MapByte);
+ DbgBreakPoint();
+ )
+
+ }
+
+ }
+ return;
+
+}
+
+
+
+VOID ASSERT_RECEIVE_WINDOW(PUBNEI_ADAPTER pNewAdapt)
+ {
+ UCHAR Map_Byte;
+ if (pNewAdapt->AdapterType==GPCNIU) {
+
+ NdisRawReadPortUchar(
+ (ULONG)pNewAdapt->MapPort,
+ &Map_Byte
+ );
+ if ((Map_Byte & ~INTERRUPT_ENABLED)!=(pNewAdapt->ReceiveDataWindow_Page)) {
+ IF_BAD_LOUD(
+ DbgPrint("UBNEI: Receive window not mapped in %02x\n",Map_Byte);
+ DbgBreakPoint();
+ )
+ }
+ }
+ return;
+ }
+
+
+VOID SET_RECDWINDOW(PUBNEI_ADAPTER pAdapter,UCHAR intflag)
+ {
+ IF_VERY_LOUD (DbgPrint( "-->Set to recd window\n" );)
+ IF_LOG('R');
+
+ pAdapter->MapRegSync.NewMapRegister=(pAdapter->ReceiveDataWindow_Page | ((UCHAR)intflag));
+
+ UbneiMapRegisterChangeSync(&pAdapter->MapRegSync);
+ }
+
+VOID SET_INITWINDOW(PUBNEI_ADAPTER pAdapter,UCHAR intflag)
+ {
+ IF_VERY_LOUD (DbgPrint( "-->Set to init window\n" );)
+ IF_LOG('N');
+
+ pAdapter->MapRegSync.NewMapRegister=(pAdapter->InitWindow_Page | ((UCHAR)intflag));
+
+ UbneiMapRegisterChangeSync(&pAdapter->MapRegSync);
+
+ }
+
+VOID SET_DATAWINDOW(PUBNEI_ADAPTER pAdapter,UCHAR intflag)
+ {
+ IF_VERY_LOUD (DbgPrint( "-->Set to data window\n" );)
+ IF_LOG('D');
+
+ pAdapter->MapRegSync.NewMapRegister=(pAdapter->DataWindow_Page | ((UCHAR)intflag));
+
+ UbneiMapRegisterChangeSync(&pAdapter->MapRegSync);
+
+ }
+
+VOID SET_CODEWINDOW(PUBNEI_ADAPTER pAdapter,UCHAR intflag)
+ {
+ IF_VERY_LOUD (DbgPrint( "-->Set to code window\n" );)
+ IF_LOG('C');
+
+ pAdapter->MapRegSync.NewMapRegister=(pAdapter->CodeWindow_Page | ((UCHAR)intflag));
+
+ UbneiMapRegisterChangeSync(&pAdapter->MapRegSync);
+
+ }
+
+
+
+
+VOID SET_RECDWINDOW_SYNC(PUBNEI_ADAPTER pAdapter,UCHAR intflag)
+ {
+ IF_VERY_LOUD (DbgPrint( "-->Set to recd window\n" );)
+ IF_LOG('R');
+
+ pAdapter->MapRegSync.NewMapRegister=(pAdapter->ReceiveDataWindow_Page | ((UCHAR)intflag));
+
+ NdisMSynchronizeWithInterrupt(
+ &pAdapter->NdisInterrupt,
+ UbneiMapRegisterChangeSync,
+ &pAdapter->MapRegSync
+ );
+
+ }
+
+VOID SET_INITWINDOW_SYNC(PUBNEI_ADAPTER pAdapter,UCHAR intflag)
+ {
+ IF_VERY_LOUD (DbgPrint( "-->Set to init window\n" );)
+ IF_LOG('N');
+
+ pAdapter->MapRegSync.NewMapRegister=(pAdapter->InitWindow_Page | ((UCHAR)intflag));
+
+ NdisMSynchronizeWithInterrupt(
+ &pAdapter->NdisInterrupt,
+ UbneiMapRegisterChangeSync,
+ &pAdapter->MapRegSync
+ );
+
+
+ }
+
+VOID SET_DATAWINDOW_SYNC(PUBNEI_ADAPTER pAdapter,UCHAR intflag)
+ {
+ IF_VERY_LOUD (DbgPrint( "-->Set to data window\n" );)
+ IF_LOG('D');
+
+ pAdapter->MapRegSync.NewMapRegister=(pAdapter->DataWindow_Page | ((UCHAR)intflag));
+
+ NdisMSynchronizeWithInterrupt(
+ &pAdapter->NdisInterrupt,
+ UbneiMapRegisterChangeSync,
+ &pAdapter->MapRegSync
+ );
+
+
+ }
+
+VOID SET_CODEWINDOW_SYNC(PUBNEI_ADAPTER pAdapter,UCHAR intflag)
+ {
+ IF_VERY_LOUD (DbgPrint( "-->Set to code window\n" );)
+ IF_LOG('C');
+
+ pAdapter->MapRegSync.NewMapRegister=(pAdapter->CodeWindow_Page | ((UCHAR)intflag));
+
+ NdisMSynchronizeWithInterrupt(
+ &pAdapter->NdisInterrupt,
+ UbneiMapRegisterChangeSync,
+ &pAdapter->MapRegSync
+ );
+
+
+ }
+
+
+#endif
diff --git a/private/ntos/ndis/ubnei/map.h b/private/ntos/ndis/ubnei/map.h
new file mode 100644
index 000000000..171fd5dec
--- /dev/null
+++ b/private/ntos/ndis/ubnei/map.h
@@ -0,0 +1,164 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ init.c
+
+Abstract:
+
+ This is the init file for the Ungermann Bass Ethernet Controller.
+ This driver conforms to the NDIS 3.0 interface.
+
+Author:
+
+ Brian Lieuallen BrianLie 11/21/93
+
+Environment:
+
+ Kernel Mode Operating Systems : NT and other lesser OS's
+
+Revision History:
+
+ Brian Lieuallen BrianLie 12/15/93
+ Made it a mini-port
+
+
+--*/
+
+
+
+#if DBG
+
+// declared in init.c
+
+VOID
+ASSERT_INTERRUPT_ENABLED(
+ PUBNEI_ADAPTER pAdapter
+ );
+
+
+
+VOID ASSERT_RECEIVE_WINDOW(PUBNEI_ADAPTER pNewAdapt);
+
+VOID SET_RECDWINDOW(PUBNEI_ADAPTER pNewAdapt,UCHAR intflag);
+
+VOID SET_INITWINDOW(PUBNEI_ADAPTER pNewAdapt,UCHAR intflag);
+
+VOID SET_DATAWINDOW(PUBNEI_ADAPTER pNewAdapt,UCHAR intflag);
+
+VOID SET_CODEWINDOW(PUBNEI_ADAPTER pNewAdapt,UCHAR intflag);
+
+VOID SET_RECDWINDOW_SYNC(PUBNEI_ADAPTER pNewAdapt,UCHAR intflag);
+
+VOID SET_INITWINDOW_SYNC(PUBNEI_ADAPTER pNewAdapt,UCHAR intflag);
+
+VOID SET_DATAWINDOW_SYNC(PUBNEI_ADAPTER pNewAdapt,UCHAR intflag);
+
+VOID SET_CODEWINDOW_SYNC(PUBNEI_ADAPTER pNewAdapt,UCHAR intflag);
+
+
+#else
+
+#define ASSERT_INTERRUPT_ENABLED(pAdapter)
+
+#define ASSERT_RECEIVE_WINDOW(pNewAdapt)
+
+
+#define SET_RECDWINDOW(pAdapter,intflag) { \
+ \
+ pAdapter->MapRegSync.CurrentMapRegister=pAdapter->ReceiveDataWindow_Page | (intflag);\
+ \
+ NdisRawWritePortUchar ( \
+ (ULONG)pAdapter->MapPort, \
+ pAdapter->MapRegSync.CurrentMapRegister \
+ ); \
+ }
+
+#define SET_INITWINDOW(pAdapter,intflag) { \
+ \
+ pAdapter->MapRegSync.CurrentMapRegister=(pAdapter->InitWindow_Page | ((UCHAR)(intflag))); \
+ \
+ NdisRawWritePortUchar ( \
+ (ULONG)pAdapter->MapPort, \
+ pAdapter->MapRegSync.CurrentMapRegister \
+ ); \
+ }
+
+
+#define SET_DATAWINDOW(pAdapter,intflag) { \
+ \
+ pAdapter->MapRegSync.CurrentMapRegister=pAdapter->DataWindow_Page | (intflag);\
+ \
+ NdisRawWritePortUchar ( \
+ (ULONG)pAdapter->MapPort, \
+ pAdapter->MapRegSync.CurrentMapRegister \
+ ); \
+ }
+
+
+#define SET_CODEWINDOW(pAdapter,intflag) { \
+ \
+ pAdapter->MapRegSync.CurrentMapRegister=(pAdapter->CodeWindow_Page | ((UCHAR)(intflag))); \
+ \
+ NdisRawWritePortUchar ( \
+ (ULONG)pAdapter->MapPort, \
+ pAdapter->MapRegSync.CurrentMapRegister \
+ ); \
+ }
+
+
+
+#define SET_RECDWINDOW_SYNC(pAdapter,intflag) { \
+ \
+ pAdapter->MapRegSync.NewMapRegister=(pAdapter->ReceiveDataWindow_Page | ((UCHAR)intflag)); \
+ \
+ NdisMSynchronizeWithInterrupt( \
+ &pAdapter->NdisInterrupt, \
+ UbneiMapRegisterChangeSync, \
+ &pAdapter->MapRegSync \
+ ); \
+ \
+ }
+
+#define SET_INITWINDOW_SYNC(pAdapter, intflag) { \
+ \
+ pAdapter->MapRegSync.NewMapRegister=(pAdapter->InitWindow_Page | ((UCHAR)intflag)); \
+ \
+ NdisMSynchronizeWithInterrupt( \
+ &pAdapter->NdisInterrupt, \
+ UbneiMapRegisterChangeSync, \
+ &pAdapter->MapRegSync \
+ ); \
+ \
+ }
+
+#define SET_DATAWINDOW_SYNC(pAdapter, intflag) { \
+ \
+ pAdapter->MapRegSync.NewMapRegister=(pAdapter->DataWindow_Page | ((UCHAR)intflag)); \
+ \
+ NdisMSynchronizeWithInterrupt( \
+ &pAdapter->NdisInterrupt, \
+ UbneiMapRegisterChangeSync, \
+ &pAdapter->MapRegSync \
+ ); \
+ \
+ }
+
+#define SET_CODEWINDOW_SYNC( pAdapter, intflag) { \
+ \
+ pAdapter->MapRegSync.NewMapRegister=(pAdapter->CodeWindow_Page | ((UCHAR)intflag)); \
+ \
+ NdisMSynchronizeWithInterrupt( \
+ &pAdapter->NdisInterrupt, \
+ UbneiMapRegisterChangeSync, \
+ &pAdapter->MapRegSync \
+ ); \
+ \
+ }
+
+
+
+
+#endif
diff --git a/private/ntos/ndis/ubnei/niudata.h b/private/ntos/ndis/ubnei/niudata.h
new file mode 100644
index 000000000..1721bbbcf
--- /dev/null
+++ b/private/ntos/ndis/ubnei/niudata.h
@@ -0,0 +1,562 @@
+
+#include "packon.h"
+
+
+typedef struct _X86ADDRESS {
+ union {
+ ULONG dword;
+ struct {
+ USHORT Offset;
+ USHORT Segment;
+ } SegOff;
+ } u;
+} X86ADDRESS;
+
+typedef struct tagServiceStatus {
+ USHORT SST_TableSize;
+ ULONG SST_LastDiagnosticsTime;
+ ULONG SST_Mac_Status;
+ USHORT SST_CurrentPacketFilter;
+ ULONG SST_MediaSpecificStatisticsPtr;
+ ULONG SST_LastClearStatisticsTime;
+
+
+
+ ULONG SST_TotalFramesReceived ;
+ ULONG SST_FramesWithCRCError ;
+ ULONG SST_TotalBytesReceived ;
+ ULONG SST_FramesDiscarded_NoBufferSpace ;
+ ULONG SST_MulticastFramesReceived ;
+ ULONG SST_BroadcastFramesReceived ;
+ ULONG SST_FramesReceivedWithErrors ;
+ ULONG SST_FramesExceedingMaximumSize ;
+ ULONG SST_FramesSmallerThanMinimumSize ;
+ ULONG SST_MulticastBytesReceived ;
+ ULONG SST_BroadcastBytesReceived ;
+ ULONG SST_FramesDiscarded_HardwareError ;
+ ULONG SST_TotalFramesTransmitted ;
+ ULONG SST_TotalBytesTransmitted ;
+ ULONG SST_MulticastFramesTransmitted ;
+ ULONG SST_BroadcastFramesTransmitted ;
+ ULONG SST_BroadcastBytesTransmitted ;
+ ULONG SST_MulticastBytesTransmitted ;
+ ULONG SST_FramesNotTransmitted_Timeout ;
+ ULONG SST_FramesNotTransmitted_HardwareError ;
+ ULONG res[3];
+ } ServiceStatus;
+
+typedef struct tagMediaStatistics {
+ USHORT MST_TableSize ;
+ USHORT MST_StructureVersionLevel ;
+ ULONG MST_FramesWithAlignmentError ;
+ ULONG MST_ReceiveErrorFailureMask ;
+ ULONG MST_FramesWithOverrunError ;
+ ULONG MST_FramesTransmittedAfterAnyCollisions;
+ ULONG MST_FramesTransmittedAfterDeferring ;
+ ULONG MST_FramesNotTransmitted_MaxCollisions ;
+ ULONG MST_TotalCollisions ;
+ ULONG MST_LateCollisions ;
+ ULONG MST_FramesTransmittedAfterJustOneCollision ;
+ ULONG MST_FramesTransmittedAfterMultipleCollisions ;
+ ULONG MST_FramesTransmitted_CD_Heartbeat ;
+ ULONG MST_JabberErrors ;
+ ULONG MST_CarrierSenseLostDuringTransmission ;
+ ULONG MST_TransmitErrorFailureMask ;
+ ULONG MST_NumberOfUnderruns ;
+ } MediaStatistics;
+
+typedef volatile struct tagNIUData {
+ char szSST[16];
+ ServiceStatus sst;
+
+ char szMST[16];
+ MediaStatistics mst;
+
+// d0-d7
+ char szRFD[6];
+ USHORT RFD_Start;
+
+// d8-df
+ char szRBD[6];
+ USHORT RBD_Start;
+
+// e0-ef
+
+ UCHAR InterruptDisabled ;
+ UCHAR InterruptActive ;
+ UCHAR WorkForHost ;
+ UCHAR HostWantsInterrupt ;
+ USHORT HostQueuedTransmits ;
+ USHORT RU_Start_Count ;
+ USHORT res ;
+ USHORT Xmts_InProgress ;
+ USHORT CU_Starts ;
+ USHORT Xmt_Completes ;
+
+// [ RAM locations 00F0-00FF ]
+
+ ULONG Up_Time ;
+ USHORT missing_EOFs ;
+ USHORT Transmitter_Hangs ;
+ USHORT Receiver_Hangs ;
+ USHORT reset_anomaly_count ;
+ USHORT res2[2] ;
+
+// [ RAM locations 0100-010F ]
+
+ USHORT SCB[8];
+
+//SCB LABEL WORD ; The 82586's "System Control Block".
+// dw 0 ; STAT, CUS, and RUS.
+// dw 0 ; ACK, CUC, RESET, and RUC.
+// dw 0FFFFh ; Command Block List.
+// dw 0FFFFh ; Receive Frame Area.
+// dw 0 ; Cyclic Redundancy Check errors.
+// dw 0 ; Alignment errors.
+// dw 0 ; No Receive Resources errors.
+// dw 0 ; Receive Unit Bus Overrun errors.
+
+//; [ RAM locations 0110-011F ]
+
+ UCHAR dummy_RDB [10];
+
+//dummy_RBD dw 0 ; EOF, F, and Actual Count.
+// dw 0FFFFh ; Pointer to next RBD.
+// dw dummy_buffer-SegmentBase ; 16 LSBs of buffer
+// ; address.
+// db 0 ; 4 MSBs of buffer address.
+// db 0 ; Unused.
+// dw 8002h ; EOL and buffer size.
+
+ USHORT dummy_buffer [6];
+
+//dummy_buffr dw 0 ; The 2-byte dummy buffer.
+// dw 2 dup (0) ; [Unused.]
+//
+
+// [ RAM locations 0120-7FFF (or 3FFF) ]
+
+ UCHAR Start_Here[];
+
+ } LOWNIUDATA, *PLOWNIUDATA;
+
+
+typedef struct _SimpleRingBufferDesc {
+ UCHAR SRB_WritePtr[2];
+ UCHAR SRB_ReadPtr[2];
+ UCHAR SRB_ObjectMap;
+ UCHAR pad[11];
+ USHORT SRB_Offsets[256];
+ } SimpleRingBufferDescriptor;
+
+
+
+
+
+
+typedef volatile struct tagUpNIUData {
+// [ RAM locations 8000-800F ]
+ UCHAR szFreeTBDs[14];
+ USHORT FreeTBDs_RingBuffer;
+
+// [ RAM locations 8010-801F ]
+ UCHAR szXmitFrames[14];
+ USHORT XmtFrames_RingBuffer;
+
+
+// [ RAM locations 8020-802F ]
+ UCHAR szRcvFrames[14];
+ USHORT RcvFrames_RingBuffer;
+
+
+// [ RAM locations 8030-803F ]
+ UCHAR szReturnedRBD[14];
+ USHORT ReturnedRBDs_RingBuffer;
+
+// [ RAM locations 8040-804F ]
+ UCHAR szRequests[14];
+ USHORT Request_RingBuffer;
+
+// [ RAM locations 8050-805F ]
+ UCHAR szResult[14];
+ USHORT Result_RingBuffer;
+
+
+// [ RAM locations 8060-826F ]
+ SimpleRingBufferDescriptor RcvFrames;
+
+//RcvFrames SimpleRingBufferDescriptor <>
+// dw 256 dup (0)
+
+
+// [ RAM locations 8270-847F ]
+ SimpleRingBufferDescriptor ReturnedRBDs;
+
+//ReturnedRBDs SimpleRingBufferDescriptor <>
+// dw 256 dup (0)
+
+
+// [ RAM locations 8480-868F ]
+ SimpleRingBufferDescriptor FreeTDBs;
+
+//FreeTBDs SimpleRingBufferDescriptor <>
+// dw 256 dup (0)
+
+
+// [ RAM locations 8690-889F ]
+ SimpleRingBufferDescriptor XmtFrames;
+
+//XmtFrames SimpleRingBufferDescriptor <>
+// dw 256 dup (0)
+
+
+// [ RAM locations 88A0-8xxx ]
+
+ USHORT System_State ;
+ USHORT System_Modes ;
+ USHORT Last_Timer_0_Count ;
+ USHORT RU_Start_Timeouts ;
+ USHORT _82586_CA_Address ;
+ USHORT _82586_RESET_Address ;
+ USHORT HostInterruptPort ;
+ USHORT AdapterControlPort ;
+ USHORT IRQ_Select_and_LED_Port ;
+ USHORT DeadmanTimerPort ;
+ USHORT HostInterruptLevel ;
+ USHORT HostWindowMask ;
+ USHORT NOT_HostWindowMask ;
+
+ USHORT MinimumHostWindowSize ;
+
+ ULONG HostWindowSize ;
+
+ UCHAR HostOpSys ;
+ UCHAR NIU_AdapterType ;
+ USHORT check_RU_counters_delay ;
+ USHORT Timeout_TCB ;
+ USHORT Xmt_Timestamp ;
+ USHORT Xmt_Timeout ;
+ USHORT initial_RcvFrames_pointer ;
+ USHORT Rcv_Timestamp ;
+ USHORT Rcv_Timeout ;
+ USHORT Diagnostic_Hangs ;
+ USHORT Diagnostic_Timestamp ;
+ USHORT Diagnostic_Timeout ;
+ USHORT Loopback_1st_RBD ;
+ USHORT Loopback_Frame_Length ;
+ USHORT Loopback_Frame_Failures ;
+ ULONG Loopback_Frame_Count ;
+
+ USHORT Max_Multicast_Addresses ;
+ USHORT Max_Multicast_Count ;
+ USHORT Multicast_Padding ;
+ USHORT Max_General_Requests ;
+
+ USHORT Code_and_Xmt_Segment ;
+ USHORT RcvBufferSeg ;
+ USHORT XmtBufferSeg ;
+ USHORT Rcv_Buffer_Size ;
+ USHORT Number_of_Rcv_Buffers ;
+ USHORT Xmt_Buffer_Size ;
+ USHORT Number_of_Xmt_Buffers ;
+ USHORT Rcv_Buffer_Start ;
+ USHORT TCB_Start ;
+ USHORT TBD_Start ;
+ USHORT Xmt_Buffer_Start ;
+ USHORT Room_Left_in_1st_32K ;
+ UCHAR Map_Table[32] ;
+ USHORT Max_Receive_Size ;
+ USHORT Min_Receive_Size ;
+ USHORT Max_Collisions ;
+
+ UCHAR user_FIFO_Threshold ;
+ UCHAR user_PreambleLength ;
+ UCHAR user_CRC_Polynomial ;
+ UCHAR user_InterframeSpacing ;
+ USHORT user_SlotTime ;
+ UCHAR user_MaxRetries ;
+ UCHAR user_LinearPriority ;
+ UCHAR user_ACR_Priority ;
+ UCHAR user_BackoffMethod ;
+ UCHAR user_CRS_Filter ;
+ UCHAR user_CDT_Filter ;
+ UCHAR user_Min_Frame_Length ;
+
+ UCHAR LED_Off_12Volts_DoParityCheck ;
+ UCHAR LED_On_12Volts_DoParityCheck ;
+ UCHAR LED_Off_and_IRQ_Select ;
+ UCHAR LED_On_and_IRQ_Select ;
+
+ UCHAR LED_Status; // added to blink LED. brianlie 12/23/93
+
+// EVEN
+ UCHAR pad00[2];
+
+ USHORT Next_Unused_Location_in_1st_32K ;
+ USHORT Next_Unused_Location_in_2nd_32K ;
+
+ USHORT RFD_Queue[2] ; //head=0, tail=1
+ USHORT Free_RDB_Queue[2] ;
+ USHORT TCB_Queue[2] ;
+
+ X86ADDRESS Default_Address_Base ;
+ X86ADDRESS SCP_Base ;
+
+
+ USHORT Last_CRCERRS ;
+ USHORT Last_ALNERRS ;
+ USHORT Last_RSCERRS ;
+ USHORT Last_OVRNERRS ;
+
+// ALIGN 16
+ UCHAR pad01[22];
+
+ UCHAR ISCP[8];
+
+//ISCP LABEL WORD ; The 82586's "Intermediate System
+// ; Configuration Pointer".
+// db 0 ; Initialization-in-progress flag.
+// db 0 ; [Unused.]
+// dw 0 ; Offset of SCB from SCB Base.
+// dw 0 ; Low order bits of SCB base address.
+// db 0 ; High order bits of SCB base address.
+// db 0 ; [Unused.]
+
+// ALIGN 16
+ UCHAR pad02[24];
+
+ UCHAR szStack[16];
+ USHORT Stack_Area[64];
+
+
+
+
+// ;************************************************
+// ;* Initial Entry Point code *
+// ;************************************************
+ UCHAR Startup_Code[8];
+ USHORT Startup_Code_CS_fixup;
+
+//Startup_Code LABEL BYTE
+// dw 0 ; MOV AX,CS ; These instructions
+// dw 0 ; MOV DS,AX ; are put here during
+// db 0 ; JMP ; initialization.
+// dw 0 ; 0000
+//Startup_Code_CS_fixup LABEL WORD
+// dw 0 ; NIU Code Segment
+
+//;;;;; debugging
+// EVEN
+ UCHAR pad03[2];
+
+//LogStart EQU 0A000h
+//LogEnd EQU 0A000h+(16*1024)
+ USHORT LogFlg;
+ USHORT LopPtr;
+
+//;;;;; debugging
+
+// ALIGN 16
+
+
+// ;************************************************
+// ;* 82586 Runtime Diagnostic Commands *
+// ;************************************************
+
+//; This is the list of commands we give to the 82586 when we perform
+//; the "InitiateDiagnostics" request from the Protocol driver.
+
+//RuntimeDiagnosticCommands LABEL WORD
+
+ USHORT NOP_command[3];
+//NOP_command LABEL WORD
+// dw 0 ; C, B, and other status bits.
+// dw 0000h ; CMD = NOP.
+// dw DIAGNOSE_command-SegmentBase
+
+ USHORT DIAGNOSE_Command[3];
+//DIAGNOSE_command LABEL WORD
+// dw 0 ; C, B, and other status bits.
+// dw 0007h ; CMD = DIAGNOSE.
+// dw TDR_command-SegmentBase
+
+ USHORT TDR_command[3];
+//TDR_command LABEL WORD
+// dw 0 ; C, B, and other status bits.
+// dw 8005h ; EOL = 1 and CMD = TDR.
+// dw 0000h ; This is the last command.
+
+ USHORT TDR_result;
+
+//; Bits in the high byte of "TDR_result":
+
+#define TDR_LinkOK 80h
+#define TDR_TransceiverCableProblem 40h
+#define TDR_Open 20h
+#define TDR_Short 10h
+
+
+
+// ALIGN 16
+ UCHAR pad04[28];
+
+// ;************************************************
+// ;* 82586 Initialization Commands *
+// ;************************************************
+
+//; This is the list of commands we give to the 82586 when we first
+//; start it, when we restart it after we have detected that it is hung,
+//; and when we restart it in performing certain of the "GeneralRequest"s.
+//; There are 4 commands, linked together through their "CB_Link" fields.
+//; The first and third commands are "Configure" commands, and the second
+//; one is an "Individual Address Set Up" command. The two "Configure"
+//; commands specify the same configuration parameters, except that the first
+//; one turns on "internal loopback" mode and the last one turns it off.
+//; We put the 82586 in "internal loopback" mode while it processes the
+//; "Individual Address Set Up" command because it may otherwise not process
+//; it correctly. The fourth command is a "Multicast Address Set Up" command.
+//; NOTE that these command blocks get initialized at run time (by the
+//; "_82586_Initialization" routine). The initial values in the following
+//; declarations are effectively just comments.
+
+//_82586_Initialization_Commands LABEL WORD
+
+ USHORT Configure_with_Loopback[9];
+ USHORT individual_Address[3];
+ UCHAR Our_Address[6];
+ USHORT Operation_Configure[4];
+ USHORT Save_Bad_Frames[3];
+ USHORT Promiscuous_ect[2];
+ USHORT Multicast_Setup[3];
+ USHORT Multicast_Byte_Count;
+ CHAR Dynamically_Allocated_Area[][6];
+
+
+//Configure_with_Loopback LABEL WORD
+// dw 0 ; C, B, and other status bits.
+// dw 0002h ; CMD = Configure.
+// dw Individual_Address-SegmentBase
+// db 12 ; Byte count of this block.
+// db 15 ; FIFO limit = 15.
+// db 40h ; Don't save bad frames; External READY sync.
+// db 40h+2Eh ; Internal loopback; 8-byte preamble; Address
+// ; and Type in data buffer; 6 address bytes.
+// db 0 ; IEEE 802.3 exponential backoff method.
+// db 96 ; Interframe spacing = 96.
+// dw 0F200h ; 15 retries on collisions; Slot time = 512.
+// db 0 ; Non-promiscuous; Broadcasts accepted.
+// db 0 ; Externally generated Carrier Sense (CRS) and
+// ; Collision Detect (CDT); CRS filter and CDT
+// ; filter = 0.
+// dw 12 ; Minimum frame length.
+//
+//Individual_Address LABEL WORD
+// dw 0 ; C, B, and other status bits.
+// dw 0001h ; CMD = Individual Address Set Up.
+// dw Operational_Configure-SegmentBase
+//Our_Address LABEL BYTE
+// dw 3 dup (0) ; The address is filled in at initialization.
+//
+//Operational_Configure LABEL WORD
+// dw 0 ; C, B, and other status bits.
+// dw 0002h ; CMD = Configure.
+// dw Multicast_Setup-SegmentBase
+// db 12 ; Byte count of this block.
+// db 15 ; FIFO limit = 15.
+//Save_Bad_Frames_etc LABEL BYTE
+// db 40h ; Don't save bad frames; External READY sync.
+// db 2Eh ; 8-byte preamble; Address and Type in data
+// ; buffer; 6 address bytes.
+// db 0 ; IEEE 802.3 exponential backoff method.
+// db 96 ; Interframe spacing = 96.
+// dw 0F200h ; 15 retries on collisions; Slot time = 512.
+//Promiscuous_etc LABEL BYTE
+// db 08h ; Non-promiscuous; Broadcasts accepted;
+// ; TONO-CRS.
+// db 0 ; Externally generated Carrier Sense (CRS) and
+// ; Collision Detect (CDT); CRS filter and CDT
+// ; filter = 0.
+// dw 12 ; Minimum frame length.
+//
+//Multicast_Setup LABEL WORD
+// dw 0 ; C, B, and other status bits.
+// dw 8003h ; End-of-List=1; CMD=Multicast Address Setup.
+// dw 0 ; [This is the last initialization command.]
+// dw 0 ; This 0 means disable multicast addresses.
+//
+//Dynamically_Allocated_Area LABEL BYTE
+//
+//; The RAM from here up is allocated by "Initialize_Data". It is used for
+//; (a) the Multicast-Setup Command Block's list of multicast addresses;
+//; (b) the RFDs (Receive Frame Descriptors), if they won't fit in the
+//; first 32K;
+//; (c) the TCBs (Transmit Command Blocks);
+//; (d) the TBDs (Transmit Buffer Descriptors);
+//; (e) the "Request" ring buffer; and
+//; (f) the "Result" ring buffer;
+//; NOTE that the Multicast-Setup Command Block's header must immediately
+//; precede this area, and the space for the list of multicast addresses must
+//; be the first thing allocated, because the list must be contiguous with the
+//; header.
+//
+//
+//;NIU_DataSegment ENDS
+//
+
+
+
+ } HIGHNIUDATA, *PHIGHNIUDATA;
+
+
+typedef volatile struct _NIU_CONTROL_AREA {
+
+ USHORT us_POD_SCB[8]; // xFF00 - 586 SCB (if Ethernet).
+ UCHAR uc_Aux_port; // xFF10 - Aux Control port value last output.
+ UCHAR uc_Aux_reserved;
+ UCHAR uc_ADP_port; // xFF12 - Adapter Control port value.
+ UCHAR uc_ADP_reserved;
+ UCHAR uc_UnusedInfo1[108]; // uninteresting stuff.
+ USHORT us_pod_status; // xFF80 - current Power-On Diag (POD) status.
+ USHORT us_sif_test; // xFF82 - request to test SIF chip.
+ UCHAR uc_UnusedInfo2[12];
+ USHORT us_HWstatus; // xFF90 - status results of POD.
+ USHORT us_HWcommand; // xFF92 - command from PC to PROM.
+ USHORT us_HWresult1; // xFF94 - results of last command from PC.
+ USHORT us_HWresult2; // xFF96 - more results of last command.
+ USHORT us_HWparameter1; // xFF98 - command parameter 1.
+ USHORT us_HWparameter2; // xFF9A - command parameter 2.
+ UCHAR uc_rsrvd_for_PCuse[36];
+ USHORT us_DI_value; // xFFC0 - value of PROM's DI.
+ USHORT us_SI_value; // xFFC2 - value of PROM's SI.
+ USHORT us_BP_value; // xFFC4 - value of PROM's BP.
+ UCHAR uc_unknown1[2]; // xFFC6 - reserved.
+ USHORT us_BX_value; // xFFC8 - value of PROM's BX.
+ USHORT us_DX_value; // xFFCA - value of PROM's DX.
+ USHORT us_CX_value; // xFFCC - value of PROM's CX.
+ USHORT us_AX_value; // xFFCE - value of PROM's AX.
+ USHORT us_ES_value; // xFFD0 - value of PROM's ES.
+ USHORT us_DS_value; // xFFD2 - value of PROM's DS.
+ USHORT us_SP_value; // xFFD4 - value of PROM's SP.
+ USHORT us_SS_value; // xFFD6 - value of PROM's SS.
+ USHORT us_IP_value; // xFFD8 - value of PROM's IP.
+ USHORT us_CS_value; // xFFDA - value of PROM's CS.
+ USHORT us_Flags_value; // xFFDC - value of PROM's Flags.
+ UCHAR uc_interrupt_type; // xFFDE - Interrupt type (?).
+ UCHAR uc_reserved1;
+ UCHAR uc_board_rev; // xFFE0 - board revision level.
+ UCHAR uc_board_sub_rev; // xFFE1 - board sub-revision level.
+ UCHAR uc_banks_of_RAM; // xFFE2 - number of 64k banks of RAM.
+ UCHAR uc_host_type; // xFFE3 - type of host.
+ UCHAR uc_media_type; // xFFE4 - type of media interface:
+ UCHAR uc_product_type; // xFFE5 - type of product.
+ USHORT us_clock_speed; // xFFE6 - NIU CPU clock rate.
+ UCHAR uc_POD_ISCP[8]; // xFFE8 - 586 ISCP (if Ethernet).
+ UCHAR uc_node_id[6]; // xFFF0 - the NIU's 48-bit node address.
+ USHORT us_POD_SCP; // xFFF6 - 586 SCP (if Ethernet).
+ UCHAR uc_hdlc_flag; // xFFF8 - HDLC flag (if Ethernet).
+} NIU_CONTROL_AREA, *PNIU_CONTROL_AREA;
+
+
+
+
+#include "packoff.h"
diff --git a/private/ntos/ndis/ubnei/receive.c b/private/ntos/ndis/ubnei/receive.c
new file mode 100644
index 000000000..6cfb38a29
--- /dev/null
+++ b/private/ntos/ndis/ubnei/receive.c
@@ -0,0 +1,482 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ receive.c
+
+Abstract:
+
+ This file handles received packets the Ungermann Bass Ethernet Controller.
+ This driver conforms to the NDIS 3.0 interface.
+
+ Based on the elnkii drivers for the most part
+
+Author:
+ Brian Lieuallen (BrianLie) 07/02/92
+
+Environment:
+
+ Kernel Mode Operating Systems : NT and other lesser OS's
+
+Revision History:
+
+ Brian Lieuallen BrianLie 12/15/93
+ Made it a mini-port
+
+
+--*/
+
+
+
+#include <ndis.h>
+#include <efilter.h>
+
+#include "niudata.h"
+#include "debug.h"
+#include "ubhard.h"
+#include "ubsoft.h"
+#include "ubnei.h"
+
+#include "map.h"
+
+
+
+
+
+BOOLEAN
+CheckForReceives(
+ IN PUBNEI_ADAPTER pAdapter
+ )
+/*++
+
+Routine Description:
+
+ This routine is called from the interrupt DPC to check the card for
+ received packets. If it finds one then it calls the ethfilter indicate
+ it to the correct protocols
+
+
+Arguments:
+
+
+Notes:
+
+
+
+--*/
+
+
+{
+
+ PHIGHNIUDATA pDataWindow = (PHIGHNIUDATA) pAdapter->pDataWindow;
+ PRBD pRBD;
+ UINT PacketLength,LookAheadSize;
+ PUCHAR pBuffer;
+ USHORT rbdtemp;
+ USHORT TmpUshort;
+ UCHAR TmpUchar1, TmpUchar2;
+ PUCHAR LookaheadBuffer;
+
+
+ SET_DATAWINDOW(pAdapter,INTERRUPT_ENABLED);
+
+ // NumberOfPackets=pDataWindow->RcvFrames.SRB_WritePtr[0]-
+ // pDataWindow->RcvFrames.SRB_ReadPtr[0];
+
+ //
+ // Check to see if the are any recieved frames in the ring buffer
+ //
+
+ UBNEI_MOVE_SHARED_RAM_TO_UCHAR(&TmpUchar1, &(pDataWindow->RcvFrames.SRB_ReadPtr[0]));
+ UBNEI_MOVE_SHARED_RAM_TO_UCHAR(&TmpUchar2, &(pDataWindow->RcvFrames.SRB_WritePtr[0]));
+
+ if (TmpUchar1 == TmpUchar2) {
+ SET_RECDWINDOW(pAdapter,INTERRUPT_ENABLED);
+ return FALSE;
+ }
+
+ //
+ // There is at least one packet to indicate
+ //
+
+ // SRB- stands for Simple Ring Buffer
+ // The main components of interest are the Read and Write pointers
+ // and the offset array.
+ //
+ // The value in the R/W ptr is actually an index into the Offset
+ // array. The values in the offset array are offsets to RBD's
+ //
+ // RDB- Receive Buffer Descriptor
+ // The structure holds the address of the actual receive data, its
+ // its length and perhaps a link to the next RDB that makes up
+ // a given packet
+ //
+ // The RDB's and the actual receive buffers are all in the first
+ // half of the 64k data segment. If the window size is only 16k then
+ // only 16k will be used, otherwise the whole 32k will be used
+ //
+
+
+ //
+ // We do receive indications until there are no more or reset starts
+ //
+
+ while ((TmpUchar1 != TmpUchar2)) {
+
+
+ //
+ // Get the offset of the first RBD, used in freeing the RBD chain
+ // when the receive is complete
+ //
+
+ UBNEI_MOVE_SHARED_RAM_TO_USHORT(&rbdtemp,
+ &(pDataWindow->RcvFrames.SRB_Offsets[TmpUchar1])
+ );
+
+ //
+ // Get a pointer to the RBD the data window
+ //
+
+ pRBD=(PRBD)((PUCHAR)pAdapter->pCardRam+rbdtemp);
+
+ SET_RECDWINDOW(pAdapter,INTERRUPT_ENABLED);
+
+ //
+ // Get the address of the first buffer pointed to by this RBD
+ // All of the receive buffers are in the receive segment
+ //
+
+ UBNEI_MOVE_SHARED_RAM_TO_USHORT(&TmpUshort, &(pRBD->RBD_Buffer));
+
+ pBuffer=(PUCHAR)pAdapter->pCardRam+TmpUshort;
+
+ UBNEI_MOVE_SHARED_RAM_TO_USHORT(&TmpUshort, &(pRBD->RBD_Frame_Length));
+
+ PacketLength=TmpUshort;
+
+ LookAheadSize=PacketLength < pAdapter->ReceiveBufSize ?
+ PacketLength : pAdapter->ReceiveBufSize;
+
+ IF_LOG('y');
+
+ if (PacketLength >= 14) {
+
+ NdisCreateLookaheadBufferFromSharedMemory(
+ pBuffer,
+ LookAheadSize,
+ &LookaheadBuffer
+ );
+
+ if (LookaheadBuffer != NULL) {
+
+ //
+ // We save this information in the Adapter block for use of the
+ // TransferData
+ //
+ pAdapter->pIndicatedRBD=pRBD;
+ pAdapter->PacketLen=PacketLength;
+
+ //
+ // Save this for transfer data, so probably won't have to get this out
+ // of the shared ram again
+ //
+ pAdapter->FirstCardBuffer=pBuffer;
+
+
+ NdisMEthIndicateReceive(
+ pAdapter->NdisAdapterHandle,
+ NULL,
+ LookaheadBuffer,
+ 14,
+ (PUCHAR)LookaheadBuffer + 14,
+ LookAheadSize -14,
+ PacketLength-14
+ );
+
+
+
+ NdisDestroyLookaheadBufferFromSharedMemory(LookaheadBuffer);
+
+ }
+
+ }
+
+ IF_LOG('Y');
+
+ SET_DATAWINDOW(pAdapter,INTERRUPT_ENABLED);
+
+ //
+ // Free the RBDs by placing the the first RBD in the returned RBDs
+ // ring buffer
+ //
+
+ TmpUchar1++;
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pDataWindow->RcvFrames.SRB_ReadPtr[0]), TmpUchar1);
+
+ UBNEI_MOVE_SHARED_RAM_TO_UCHAR(&TmpUchar2,
+ &(pDataWindow->ReturnedRBDs.SRB_WritePtr[0])
+ );
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pDataWindow->ReturnedRBDs.SRB_Offsets[TmpUchar2]),
+ rbdtemp
+ );
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pDataWindow->ReturnedRBDs.SRB_WritePtr[0]),
+ TmpUchar2 + 1
+ );
+ //
+ // read the ring pointers again for the main while loop
+ //
+// UBNEI_MOVE_SHARED_RAM_TO_UCHAR(&TmpUchar1, &(pDataWindow->RcvFrames.SRB_ReadPtr[0]));
+ UBNEI_MOVE_SHARED_RAM_TO_UCHAR(&TmpUchar2, &(pDataWindow->RcvFrames.SRB_WritePtr[0]));
+
+ }
+
+ SET_RECDWINDOW(pAdapter,INTERRUPT_ENABLED);
+
+ IF_LOG('z');
+
+
+ //
+ // If we get here we know that at least one packet was indicated
+ //
+
+ NdisMEthIndicateReceiveComplete(pAdapter->NdisAdapterHandle);
+
+
+ IF_LOG('Z');
+
+ return TRUE;
+}
+
+
+
+
+
+
+NDIS_STATUS
+UbneiTransferData(
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+ )
+
+
+/*++
+
+Routine Description:
+
+ NDIS function.
+
+Arguments:
+
+ see NDIS 3.0 spec.
+
+Notes:
+
+ This routine uses two elements in the Adapter structure to pass
+ information about the current indication. This will only work because
+ there can be only one indication going on at a time.
+
+
+--*/
+
+{
+ UINT BytesLeft, BytesNow, BytesWanted;
+ PNDIS_BUFFER CurBuffer;
+ PUCHAR BufStart;
+ UINT BufLen;
+ UINT BufferIndex, i;
+ PUCHAR pBuffer;
+ PUBNEI_ADAPTER pAdapter = MacBindingHandle;
+ PRBD pRBD = pAdapter->pIndicatedRBD;
+ UINT CardBufferSize = pAdapter->ReceiveBufSize;
+ USHORT TmpUshort;
+
+ UINT BytesLeftInCardBuffer;
+
+
+
+ ByteOffset += 14;
+
+
+
+ //
+ // See how much data there is to transfer.
+ //
+
+
+ if (ByteOffset+BytesToTransfer > pAdapter->PacketLen) {
+
+ IF_LOUD(DbgPrint("TD() Protocol asked for too much data\n");)
+ BytesWanted = pAdapter->PacketLen - ByteOffset;
+
+ } else {
+
+ BytesWanted = BytesToTransfer;
+
+ }
+
+ BytesLeft = BytesWanted;
+
+
+ //
+ // Determine where the copying should start.
+ //
+
+
+ IF_LOG('t');
+
+ ASSERT_RECEIVE_WINDOW( pAdapter);
+
+// SET_RECDWINDOW(pAdapter,INTERRUPT_ENABLED);
+
+
+ ByteOffset=ByteOffset;
+
+ BytesLeftInCardBuffer=CardBufferSize-ByteOffset;
+
+ pBuffer=pAdapter->FirstCardBuffer;
+
+ pBuffer+=ByteOffset;
+
+ if (ByteOffset>CardBufferSize) {
+ //
+ // The transfer start point is not in the first card buffer.
+ // Move the correct one.
+ //
+ // The is definitly the exception case
+ //
+ BufferIndex=ByteOffset/CardBufferSize;
+
+ for (i=0;i<BufferIndex;i++) {
+
+ UBNEI_MOVE_SHARED_RAM_TO_USHORT(&TmpUshort, &(pRBD->RBD_next_RBD));
+
+ pRBD=(PRBD)((PUCHAR)pAdapter->pCardRam+ TmpUshort);
+
+ ByteOffset-=CardBufferSize;
+
+ }
+
+ UBNEI_MOVE_SHARED_RAM_TO_USHORT(&TmpUshort, &(pRBD->RBD_Buffer));
+
+ BytesLeftInCardBuffer=CardBufferSize-ByteOffset;
+
+ pBuffer=(PUCHAR)pAdapter->pCardRam+TmpUshort;
+
+ pBuffer+=ByteOffset;
+
+ }
+
+
+ NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, NULL);
+
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufStart, &BufLen);
+
+ //
+ // Loop, filling each buffer in the packet until there
+ // are no more buffers or the data has all been copied.
+ //
+
+ while (BytesLeft > 0) {
+
+ BytesNow = BytesLeft;
+
+ //
+ // See how much room is in the current ndis buffer
+ //
+ if (BufLen < BytesLeft) {
+
+ BytesNow = BufLen;
+
+ }
+
+ //
+ // See how much room is left in the current card buffer
+ //
+ if (BytesNow > BytesLeftInCardBuffer) {
+
+ BytesNow = BytesLeftInCardBuffer;
+
+ }
+
+ //
+ // Copy up the data.
+ //
+ UBNEI_MOVE_SHARED_RAM_TO_MEM(BufStart, pBuffer, BytesNow);
+
+ BufStart += BytesNow;
+
+ BufLen -= BytesNow;
+
+
+ pBuffer += BytesNow;
+
+ BytesLeftInCardBuffer -= BytesNow;
+
+
+ BytesLeft -= BytesNow;
+
+
+ //
+ // Is the transfer done now?
+ //
+
+ if (BytesLeft == 0) {
+
+ break;
+
+ }
+
+
+ //
+ // Did we use up the card buffer?
+ //
+ if (BytesLeftInCardBuffer == 0) {
+
+ UBNEI_MOVE_SHARED_RAM_TO_USHORT(&TmpUshort, &(pRBD->RBD_next_RBD));
+
+ pRBD=(PRBD)((PUCHAR)pAdapter->pCardRam+TmpUshort);
+
+ UBNEI_MOVE_SHARED_RAM_TO_USHORT(&TmpUshort, &(pRBD->RBD_Buffer));
+
+
+ pBuffer=(PUCHAR)pAdapter->pCardRam+TmpUshort;
+
+ BytesLeftInCardBuffer=CardBufferSize;
+
+ }
+
+
+ //
+ // Was the end of this packet buffer reached?
+ //
+ if (BufLen==0) {
+
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+
+ if (CurBuffer == (PNDIS_BUFFER)NULL) {
+
+ break;
+
+ }
+
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufStart, &BufLen);
+
+ }
+
+ }
+
+
+ *BytesTransferred = BytesWanted - BytesLeft;
+
+ IF_LOG('T');
+
+
+ return NDIS_STATUS_SUCCESS;
+
+}
diff --git a/private/ntos/ndis/ubnei/request.c b/private/ntos/ndis/ubnei/request.c
new file mode 100644
index 000000000..b3c937719
--- /dev/null
+++ b/private/ntos/ndis/ubnei/request.c
@@ -0,0 +1,713 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ request.c
+
+Abstract:
+
+ Ndis 3.0 MAC driver for the UB card
+
+ This file handles NdisRequest. The module was for the most part extracted
+ from the elnkii driver
+
+Author:
+
+ Brian Lieuallen (BrianLie) 07/02/92
+
+Environment:
+
+ Kernel Mode Operating Systems : NT and other lesser OS's
+
+Revision History:
+
+ Brian Lieuallen BrianLie 12/15/93
+ Made it a mini-port
+
+
+
+--*/
+
+
+
+
+
+#include <ndis.h>
+//#include <efilter.h>
+
+
+
+#include "niudata.h"
+#include "debug.h"
+#include "ubhard.h"
+#include "ubsoft.h"
+#include "ubnei.h"
+
+
+
+
+
+
+
+NDIS_STATUS
+UbneiFilterChangeAction(
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+
+
+
+
+//
+// If you add to this, make sure to add the
+// a case in UbneiFillInGlobalData() and in
+// UbneiQueryGlobalStatistics() if global
+// information only or
+// UbneiQueryProtocolStatistics() if it is
+// protocol queriable information.
+//
+STATIC UINT UbneiGlobalSupportedOids[] = {
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ OID_802_3_RCV_ERROR_ALIGNMENT,
+ OID_802_3_XMIT_ONE_COLLISION,
+ OID_802_3_XMIT_MORE_COLLISIONS
+ };
+
+
+
+
+
+
+NDIS_STATUS
+UbneiQueryInformation(
+ IN NDIS_HANDLE MiniportContext,
+ IN NDIS_OID Oid,
+ IN PVOID InfoBuffer,
+ IN ULONG BytesLeft,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+ )
+
+/*++
+
+Routine Description:
+
+ The UbneiQueryProtocolInformation process a Query request for
+ NDIS_OIDs that are specific to a binding about the MAC. Note that
+ some of the OIDs that are specific to bindings are also queryable
+ on a global basis. Rather than recreate this code to handle the
+ global queries, I use a flag to indicate if this is a query for the
+ global data or the binding specific data.
+
+Arguments:
+
+ Adapter - a pointer to the adapter.
+
+ Oid - the NDIS_OID to process.
+
+ PlaceInInfoBuffer - a pointer into the NdisRequest->InformationBuffer
+ into which store the result of the query.
+
+ BytesLeft - the number of bytes left in the InformationBuffer.
+
+ BytesNeeded - If there is not enough room in the information buffer
+ then this will contain the number of bytes needed to complete the
+ request.
+
+ BytesWritten - a pointer to the number of bytes written into the
+ InformationBuffer.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+
+ NDIS_MEDIUM Medium = NdisMedium802_3;
+ ULONG GenericULong = 0;
+ USHORT GenericUShort = 0;
+ UCHAR GenericArray[6];
+
+ PUBNEI_ADAPTER pAdapter=MiniportContext;
+
+ PLOWNIUDATA pRcvDWindow = (PLOWNIUDATA) pAdapter->pCardRam;
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ //
+ // Common variables for pointing to result of query
+ //
+
+ PVOID MoveSource;
+ ULONG MoveBytes;
+
+ NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady;
+
+ //
+ // General Algorithm:
+ //
+ // Switch(Request)
+ // Get requested information
+ // Store results in a common variable.
+ // Copy result in common variable to result buffer.
+ //
+
+ //
+ // Make sure that ulong is 4 bytes. Else GenericULong must change
+ // to something of size 4.
+ //
+ ASSERT(sizeof(ULONG) == 4);
+
+
+ IF_REQ_LOUD(DbgPrint("UBNEI: QueryProtocol %08lx\n",Oid);)
+
+ MoveSource = (PVOID)(&GenericULong);
+ MoveBytes = sizeof(GenericULong);
+
+
+ //
+ // Switch on request type
+ //
+
+ switch (Oid) {
+
+ case OID_GEN_MAC_OPTIONS:
+
+
+
+
+ GenericULong = (
+ NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
+ NDIS_MAC_OPTION_NO_LOOPBACK |
+ NDIS_MAC_OPTION_RECEIVE_SERIALIZED);
+
+
+ break;
+
+ case OID_GEN_SUPPORTED_LIST:
+
+
+ MoveSource = (PVOID)(&UbneiGlobalSupportedOids);
+ MoveBytes = sizeof(UbneiGlobalSupportedOids);
+
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+
+ HardwareStatus = NdisHardwareStatusReady;
+
+
+ MoveSource = (PVOID)(&HardwareStatus);
+ MoveBytes = sizeof(NDIS_HARDWARE_STATUS);
+
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+
+ MoveSource = (PVOID) (&Medium);
+ MoveBytes = sizeof(NDIS_MEDIUM);
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+
+ GenericULong = pAdapter->ReceiveBufSize-14;
+
+ break;
+
+
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+
+ GenericULong = (ULONG)(1514 - 14);
+
+ break;
+
+
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+
+ GenericULong = (ULONG)(1514);
+
+ break;
+
+
+ case OID_GEN_LINK_SPEED:
+
+ GenericULong = (ULONG)(100000);
+
+ break;
+
+
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+
+ GenericULong = pAdapter->TransmitBufferSpace;
+
+ break;
+
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+
+ GenericULong = pAdapter->ReceiveBufferSpace;
+
+ break;
+
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+
+ GenericULong = pAdapter->TransmitBlockSize;
+
+ break;
+
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+
+ GenericULong = pAdapter->ReceiveBlockSize;
+
+ break;
+
+ case OID_GEN_VENDOR_ID:
+
+ NdisMoveMemory(
+ (PVOID)&GenericULong,
+ pAdapter->PermanentAddress,
+ 3
+ );
+ GenericULong &= 0xFFFFFF00;
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+
+ MoveSource = (PVOID)"UBNEI Ethernet Adapter.";
+ MoveBytes = 24;
+
+ break;
+
+ case OID_GEN_DRIVER_VERSION:
+
+ GenericUShort = ((USHORT)UBNEI_NDIS_MAJOR_VERSION << 8) |
+ UBNEI_NDIS_MINOR_VERSION;
+
+ MoveSource = (PVOID)(&GenericUShort);
+ MoveBytes = sizeof(GenericUShort);
+ break;
+
+
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+
+ GenericULong = (ULONG)(pAdapter->MaxLookAhead);
+
+
+
+ IF_REQ_LOUD(DbgPrint("Querying LookAhead: %d\n,GenericULong");)
+
+ break;
+
+ case OID_802_3_PERMANENT_ADDRESS:
+
+ IF_REQ_LOUD(DbgPrint("Querying Permanent address\n");)
+
+ NdisMoveMemory((PCHAR)GenericArray,
+ pAdapter->PermanentAddress,
+ ETH_LENGTH_OF_ADDRESS);
+
+ MoveSource = (PVOID)(GenericArray);
+ MoveBytes = sizeof(pAdapter->PermanentAddress);
+ break;
+
+
+ case OID_802_3_CURRENT_ADDRESS:
+
+ IF_REQ_LOUD(DbgPrint("Querying Current address\n");)
+
+ NdisMoveMemory(
+ (PCHAR)GenericArray,
+ pAdapter->StationAddress,
+ ETH_LENGTH_OF_ADDRESS
+ );
+
+ MoveSource = (PVOID)(GenericArray);
+ MoveBytes = sizeof(pAdapter->StationAddress);
+ break;
+
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+
+ GenericULong = (ULONG) DEFAULT_MULTICAST_SIZE;
+
+
+ break;
+
+
+
+
+
+ case OID_GEN_XMIT_OK:
+
+ NdisReadRegisterUlong(
+ &pRcvDWindow->sst.SST_TotalFramesTransmitted,
+ &GenericULong
+ );
+
+ break;
+
+ case OID_GEN_RCV_OK:
+
+ NdisReadRegisterUlong(
+ (PUCHAR)&pRcvDWindow->sst.SST_TotalFramesReceived,
+ &GenericULong
+ );
+
+ break;
+
+ case OID_GEN_XMIT_ERROR:
+
+
+ GenericULong = pAdapter->FramesXmitBad;
+
+
+ break;
+
+ case OID_GEN_RCV_ERROR:
+
+ NdisReadRegisterUlong(
+ (PUCHAR)&pRcvDWindow->sst.SST_FramesReceivedWithErrors,
+ &GenericULong
+ );
+
+ break;
+
+ case OID_GEN_RCV_NO_BUFFER:
+
+ GenericULong = (UINT)(pAdapter->MissedPackets);
+
+ break;
+
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+
+ GenericULong = (UINT)pAdapter->FrameAlignmentErrors;
+
+ break;
+
+ case OID_802_3_XMIT_ONE_COLLISION:
+
+ GenericULong = (UINT)pAdapter->FramesXmitOneCollision;
+
+
+ break;
+
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+
+ GenericULong = (UINT)pAdapter->FramesXmitManyCollisions;
+
+
+ break;
+
+
+
+ default:
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS) {
+
+ if (MoveBytes > BytesLeft) {
+
+ //
+ // Not enough room in InformationBuffer. Punt
+ //
+
+ *BytesNeeded = MoveBytes;
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ } else {
+
+ //
+ // Store result.
+ //
+
+ NdisMoveMemory(InfoBuffer, MoveSource, MoveBytes);
+
+ (*BytesWritten) = MoveBytes;
+
+ }
+ }
+
+
+#if DBG
+
+ if (StatusToReturn != NDIS_STATUS_SUCCESS) {
+
+ IF_REQ_LOUD(DbgPrint("Out QueryInfo oid=%08lx failed\n",Oid);)
+ }
+#endif
+
+
+ IF_VERY_LOUD( DbgPrint("Out QueryProtocol\n");)
+
+ return StatusToReturn;
+}
+
+
+NDIS_STATUS
+UbneiSetInformation(
+ IN NDIS_HANDLE MiniportContext,
+ IN NDIS_OID Oid,
+ IN PVOID InfoBuffer,
+ IN ULONG BytesLeft,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ )
+
+/*++
+
+Routine Description:
+
+ The UbneiSetInformation is used by UbneiRequest to set information
+ about the MAC.
+
+Arguments:
+
+ Adapter - A pointer to the adapter.
+
+ Open - A pointer to an open instance.
+
+ NdisRequest - A structure which contains the request type (Set),
+ an array of operations to perform, and an array for holding
+ the results of the operations.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+ //
+ // General Algorithm:
+ //
+ // Verify length
+ // Switch(Request)
+ // Process Request
+ //
+
+ //
+ // Variables for a particular request
+ //
+
+ PUBNEI_ADAPTER pAdapter=MiniportContext;
+
+ UINT OidLength;
+
+ //
+ // Variables for holding the new values to be used.
+ //
+
+ ULONG LookAhead;
+ ULONG Filter;
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+
+ IF_REQ_LOUD( DbgPrint("Ubnei: SetInfo %08lx %0d\n",(UINT)Oid,BytesLeft);)
+
+ //
+ // Get Oid and Length of request
+ //
+
+
+ OidLength = BytesLeft;
+
+ switch (Oid) {
+
+
+ case OID_802_3_MULTICAST_LIST:
+
+ //
+ // Verify length
+ //
+
+ if ((OidLength % ETH_LENGTH_OF_ADDRESS) != 0){
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ *BytesRead = 0;
+ *BytesNeeded = 0;
+
+ break;
+
+ }
+
+#if DBG
+ {
+ UINT j;
+ PUCHAR Address;
+
+ Address=InfoBuffer;
+
+ for (j=0; j<(OidLength / ETH_LENGTH_OF_ADDRESS); j++) {
+
+ IF_REQ_LOUD(DbgPrint(" %02x-%02x-%02x-%02x-%02x-%02x\n",
+ Address[j*6],
+ Address[j*6+1],
+ Address[j*6+2],
+ Address[j*6+3],
+ Address[j*6+4],
+ Address[j*6+5]);)
+ }
+ }
+#endif
+
+ StatusToReturn=UbneiAddressChangeAction(
+ OidLength,
+ (PUCHAR)InfoBuffer,
+ pAdapter
+ );
+
+ break;
+
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ //
+ // Verify length
+ //
+
+ if (OidLength != 4 ) {
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ *BytesRead = 0;
+ *BytesNeeded = 0;
+
+ break;
+
+ }
+
+
+
+ NdisMoveMemory(&Filter, InfoBuffer, 4);
+
+
+ StatusToReturn=UbneiFilterChangeAction(
+ Filter,
+ pAdapter
+ );
+
+
+
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ //
+ // Verify length
+ //
+ if (OidLength != 4) {
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ *BytesRead = 0;
+ *BytesNeeded = 0;
+
+ break;
+
+ }
+
+ NdisMoveMemory(
+ &LookAhead,
+ InfoBuffer,
+ 4
+ );
+
+ IF_REQ_LOUD(DbgPrint("Setting LookAhead: %d\n",LookAhead);)
+
+
+ if (LookAhead <= pAdapter->ReceiveBufSize-14) {
+
+ pAdapter->MaxLookAhead=LookAhead;
+
+
+ } else {
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ }
+
+ break;
+
+
+ case OID_GEN_PROTOCOL_OPTIONS:
+
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ break;
+
+
+ default:
+
+ StatusToReturn = NDIS_STATUS_INVALID_OID;
+
+ *BytesRead = 0;
+ *BytesNeeded = 0;
+
+ break;
+
+ }
+
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS) {
+
+ *BytesRead = BytesLeft;
+ *BytesNeeded = 0;
+
+ }
+
+
+#if DBG
+
+ if ((StatusToReturn != NDIS_STATUS_SUCCESS)
+ &&
+ (StatusToReturn != NDIS_STATUS_PENDING)) {
+
+ IF_REQ_LOUD(DbgPrint("Out SetInfo oid=%08lx failed\n",Oid);)
+ }
+#endif
+
+ return StatusToReturn;;
+}
diff --git a/private/ntos/ndis/ubnei/send.c b/private/ntos/ndis/ubnei/send.c
new file mode 100644
index 000000000..ecadbca4d
--- /dev/null
+++ b/private/ntos/ndis/ubnei/send.c
@@ -0,0 +1,369 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ send.c
+
+Abstract:
+
+ This file handles sending packets the Ungermann Bass Ethernet Controller.
+ This driver conforms to the NDIS 3.0 interface.
+
+
+Author:
+
+ Brian Lieuallen (BrianLie) 07/02/92
+
+
+Environment:
+
+ Kernel Mode Operating Systems : NT and other lesser OS's
+
+Revision History:
+
+ Brian Lieuallen BrianLie 12/15/93
+ Made it a mini-port
+
+
+--*/
+
+
+
+#include <ndis.h>
+#include <efilter.h>
+
+#include "niudata.h"
+#include "debug.h"
+
+#include "ubhard.h"
+#include "ubsoft.h"
+#include "ubnei.h"
+
+#include "map.h"
+
+
+BOOLEAN
+CardSend(
+ IN PUBNEI_ADAPTER pAdapter,
+ IN PNDIS_PACKET pPacket,
+ IN UINT PacketLength
+ );
+
+
+
+BOOLEAN
+UbneiMapSendBufferSync(
+ PSEND_SYNC_CONTEXT pSync
+ );
+
+BOOLEAN
+UbneiGiveSendBufferToCardSync(
+ PSEND_SYNC_CONTEXT pSync
+ );
+
+
+
+
+NDIS_STATUS
+UbneiMacSend(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_PACKET pPacket,
+ IN UINT Flags
+ )
+/*++
+
+Routine Description:
+ MacSend
+
+
+Arguments:
+ See NDIS 3.0 spec
+
+Return Value:
+
+
+--*/
+
+
+ {
+ PUBNEI_ADAPTER pAdapter = MacBindingHandle;
+ UINT PacketLength;
+ BOOLEAN SendResult;
+
+ IF_LOG('s');
+
+ ASSERT_RECEIVE_WINDOW( pAdapter);
+
+ IF_SEND_LOUD(DbgPrint("MacSend called Packets\n");)
+
+ NdisQueryPacket(pPacket, NULL, NULL, NULL, &PacketLength);
+
+ //
+ // Here we check to make sure the packet meets some size constraints
+ //
+
+ if (PacketLength < 14 || PacketLength > 1514) {
+
+ IF_LOUD(DbgPrint("MovePacketToCard: Packet too long or too short\n");)
+
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+
+ // No packets queued, so we have a good chance
+ // being able to complete this send right now.
+ // After all the card has enough buffers for
+ // ~32 full size frames.
+ //
+
+ SendResult=CardSend(pAdapter, pPacket, PacketLength);
+
+ if (SendResult) {
+ //
+ // It's gone, were out of here!
+ //
+ // Since we sent it down to the card we don't need the card
+ // to generate an interrupt
+ //
+ ASSERT_RECEIVE_WINDOW( pAdapter);
+
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(((PLOWNIUDATA)(pAdapter->pCardRam))->HostQueuedTransmits),0);
+
+ NdisMSendResourcesAvailable(pAdapter->NdisAdapterHandle);
+
+ return NDIS_STATUS_SUCCESS;
+
+ } else {
+ //
+ // No card buffers left, queue it and tell the card
+ // to interrupt us when there is room.
+ //
+ IF_LOUD(DbgPrint("UBNEI: No card send resources\n");)
+
+ IF_LOG('o');
+
+ pAdapter->WaitingForXmitInterrupt=TRUE;
+
+ ASSERT_RECEIVE_WINDOW( pAdapter);
+
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(((PLOWNIUDATA)(pAdapter->pCardRam))->HostQueuedTransmits),1);
+
+ return NDIS_STATUS_RESOURCES;
+ }
+
+
+
+}
+
+
+
+
+
+
+
+BOOLEAN
+CardSend(
+ IN PUBNEI_ADAPTER pAdapter,
+ IN PNDIS_PACKET pPacket,
+ IN UINT PacketLength
+ )
+
+/*++
+
+Routine Description:
+ This routine checks the cards transmit ring buffer to see if
+ a send can take place. If it can then it removes the buffer
+ from the free transmit buffer ring buffer and places it on
+ the to be transimitted ring buffer.
+
+
+Arguments:
+
+ pAdapt - pointer to the adapter block
+
+Return Value:
+ returns TRUE if it was able to copy the send data to the card
+
+ FALSE indicates that there are no free transmit buffers currently
+
+
+--*/
+
+{
+
+ SEND_SYNC_CONTEXT SyncContext;
+
+ BOOLEAN OkToSend;
+
+ SyncContext.pAdapter=pAdapter;
+
+
+ if (PacketLength<60) {
+
+ PacketLength=60;
+
+ }
+
+ SyncContext.PacketLength=PacketLength;
+
+ OkToSend=NdisMSynchronizeWithInterrupt(
+ &pAdapter->NdisInterrupt,
+ UbneiMapSendBufferSync,
+ &SyncContext
+ );
+
+ if (OkToSend) {
+ //
+ // If we can send now the sync routine left the correct
+ // window mapped in for us to copy to the send buffer
+ //
+ {
+ PUCHAR CurAddress, BufAddress;
+ UINT Len;
+ PNDIS_BUFFER CurBuffer;
+
+ //
+ // Memory mapped, just copy each buffer over.
+ //
+
+ NdisQueryPacket(pPacket, NULL, NULL, &CurBuffer, NULL);
+
+ CurAddress = SyncContext.SendBuffer;
+
+ while (CurBuffer) {
+
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufAddress, &Len);
+
+ UBNEI_MOVE_MEM_TO_SHARED_RAM(CurAddress, BufAddress, Len);
+
+ CurAddress += Len;
+
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+
+ }
+
+ }
+
+
+ NdisMSynchronizeWithInterrupt(
+ &pAdapter->NdisInterrupt,
+ UbneiGiveSendBufferToCardSync,
+ &SyncContext
+ );
+
+
+ }
+
+
+ return OkToSend;
+
+
+}
+
+
+BOOLEAN
+UbneiMapSendBufferSync(
+ PSEND_SYNC_CONTEXT pSync
+ )
+
+{
+ PUBNEI_ADAPTER pAdapter=pSync->pAdapter;
+ PHIGHNIUDATA pDataWindow = (PHIGHNIUDATA) pAdapter->pDataWindow;
+
+ PTBD pTBD;
+
+ UCHAR TmpUchar2;
+ UCHAR MapWindow;
+
+ USHORT TbdOffset;
+ USHORT BufferOffset;
+
+
+ SET_DATAWINDOW(pAdapter,INTERRUPT_ENABLED);
+
+ //
+ // Check to see if there are any free TBD descriptors. If not then
+ // we can't do any sends now
+ //
+
+ UBNEI_MOVE_SHARED_RAM_TO_UCHAR(&pSync->TbdIndex, &(pDataWindow->FreeTDBs.SRB_ReadPtr[0]));
+ UBNEI_MOVE_SHARED_RAM_TO_UCHAR(&TmpUchar2, &(pDataWindow->FreeTDBs.SRB_WritePtr[0]));
+
+ if (pSync->TbdIndex == TmpUchar2 ) {
+ SET_RECDWINDOW(pAdapter,INTERRUPT_ENABLED);
+ return FALSE;
+ }
+
+ //
+ // Get the address of the TBD in the NIU data segment
+ //
+
+ UBNEI_MOVE_SHARED_RAM_TO_USHORT(&TbdOffset,
+ &(pDataWindow->FreeTDBs.SRB_Offsets[pSync->TbdIndex])
+ );
+
+ pTBD=(PTBD)((PUCHAR)pAdapter->pCardRam+TbdOffset);
+
+ //
+ // Set the length of the frame to be sent in the TBD
+ //
+
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pTBD->TBD_Frame_Length), (USHORT)pSync->PacketLength);
+ UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pTBD->TBD_EOF_and_Length), (USHORT)pSync->PacketLength | 0x8000);
+
+ //
+ // Get a pointer to the TBD buffer located in the NIU code segment
+ // Under the current version of download code the transmit buffer is
+ // is 1514 bytes long, so this makes things easy
+ //
+
+ UBNEI_MOVE_SHARED_RAM_TO_USHORT(&BufferOffset, &(pTBD->TBD_Buffer_offset));
+
+ pSync->SendBuffer=(PUCHAR)pAdapter->pCardRam + BufferOffset;
+
+ //
+ // Set the map register to point to the correct window to access
+ // the send buffer
+ //
+
+ UBNEI_MOVE_SHARED_RAM_TO_UCHAR(&MapWindow, &(pTBD->TBD_Buffer_Map));
+
+ pAdapter->MapRegSync.NewMapRegister=MapWindow | INTERRUPT_ENABLED;
+
+ UbneiMapRegisterChangeSync(&pAdapter->MapRegSync);
+
+ return TRUE;
+
+}
+
+BOOLEAN
+UbneiGiveSendBufferToCardSync(
+ PSEND_SYNC_CONTEXT pSync
+ )
+
+{
+ PUBNEI_ADAPTER pAdapter=pSync->pAdapter;
+ PHIGHNIUDATA pDataWindow = (PHIGHNIUDATA) pAdapter->pDataWindow;
+
+ UCHAR TmpUchar1;
+
+
+ SET_DATAWINDOW(pAdapter,INTERRUPT_ENABLED);
+
+ //
+ // To actually give the data to the NIU to send, we remove the this
+ // TBD from the FreeTDB buffer and add it to XmtFrames buffer
+ //
+
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pDataWindow->FreeTDBs.SRB_ReadPtr[0]), pSync->TbdIndex + 1);
+
+ UBNEI_MOVE_SHARED_RAM_TO_UCHAR(&TmpUchar1, &(pDataWindow->XmtFrames.SRB_WritePtr[0]));
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pDataWindow->XmtFrames.SRB_WritePtr[0]), TmpUchar1 + 1);
+
+ SET_RECDWINDOW(pAdapter,INTERRUPT_ENABLED);
+
+ return TRUE;
+}
diff --git a/private/ntos/ndis/ubnei/sources b/private/ntos/ndis/ubnei/sources
new file mode 100644
index 000000000..c5932c81d
--- /dev/null
+++ b/private/ntos/ndis/ubnei/sources
@@ -0,0 +1,55 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=ubnei
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER
+
+INCLUDES=..\..\inc;..\..\..\inc
+
+SOURCES= ubnei.rc \
+ initdata.c \
+ init.c\
+ ubnei.c\
+ interrup.c\
+ card.c\
+ request.c \
+ send.c\
+ receive.c\
+ config.c \
+ map.c
+
+
+RELATIVE_DEPTH=..\..
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+NTTARGETFILES=ubnei.bin
+
diff --git a/private/ntos/ndis/ubnei/ubhard.h b/private/ntos/ndis/ubnei/ubhard.h
new file mode 100644
index 000000000..8823a6822
--- /dev/null
+++ b/private/ntos/ndis/ubnei/ubhard.h
@@ -0,0 +1,303 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ init.h
+
+Abstract:
+
+ This is the init header file for the Ungermann Bass Ethernet Controller.
+
+ This file contains definitions and macros used in initializing various
+ variables at driver entry (or init ) time.
+
+Author:
+
+ Sanjeev Katariya (sanjeevk) 03-05-92
+
+Environment:
+
+ Kernel Mode Operating Systems : NT and other lesser OS's(dos)
+
+Revision History:
+
+ Brian Lieuallen BrianLie 12/15/93
+ Made it a mini-port
+
+
+--*/
+
+
+#include "packon.h"
+
+
+
+//
+// ADAPTER TYPES
+//
+#define PCNIU 0
+#define COST_REDUCED_PCNIU 1
+#define NIUPC 2
+#define NIUPS 3
+#define GPCNIU 4 // Ungermann Bass NIUpc/EOTP
+#define PCNIUEX 5
+
+//
+// ADAPTER CLASSES
+//
+#define PHOENIX 0
+#define ATLANTA 1
+#define CHAMELEON 2
+
+
+//
+// BITS IN ADAPTER CONTROL PORT DATA
+//
+#define DO_PARITY_CHECK_BIT 4
+#define x12V_BIT 2
+#define LED_BIT 1
+
+//
+//
+//
+//#define INTERRUPT_CONTROL_BIT 0x2
+
+//
+// BITS IN ADAPTER FLAGS
+//
+#define TWO_PASS_DIAGNOSTICS 0x80
+#define USE_INTERFACE_PORT 0x40
+#define ASYNCHRONOUS_READY 0x20
+
+
+//
+// ADAPTER DESCRIPTIONS
+//
+#define PCNIU_DESCRIPTION "Ungermann-Bass Personal NIU"
+#define NIUPC_DESCRIPTION "Ungermann-Bass NIUpc"
+#define NIUPS_DESCRIPTION "Ungermann-Bass NIUps or NIUps/EOTP"
+#define GPCNIU_DESCRIPTION "Ungermann-Bass NIUpc/EOTP"
+#define PCNIUEX_DESCRIPTION "Ungermann-Bass Personal NIU/ex"
+
+
+
+
+// DEFAULT HARDWARE SETTINGS
+
+
+//
+// Default hardware settings for ANY Ungermann Bass card
+// supported by this driver
+//
+#define DEFAULT_IO_BASEADDRESS (UINT)0x368
+#define DEFAULT_ADAPTER_TYPE GPCNIU
+#define DEFAULT_INTERRUPT_NUMBER 5
+#define DEFAULT_MEMORY_WINDOW (UINT)0xD8000
+
+
+
+#define NIU_CONTROL_AREA_OFFSET (USHORT)0xFF00
+
+
+//
+// Default hardware settings for specific Ungermann Bass cards
+//
+
+
+//
+// GPCNIU CARD
+//
+
+//
+// Settings of I/O Base Address jumper on the NIUpc/EOTP card.
+// Choices are 0x300, 0x310, 0x330, 0x350, 0x250, 0x280, 0x2a0, and 0x2e0.
+//
+#define DEFAULT_GPCNIU_IO_BASEADDRESS (UINT)0x360
+
+//
+// Setting for the interrupt number the NIUpc/EOTP board is using.
+// Choices are 2, 3, 4, 5, 7 or 12.
+//
+#define DEFAULT_GPCNIU_INTERRUPT_NUMBER 3
+
+//
+// Shared memory setting for the NIUpc/EOTP adapter.
+// are 0xd8000,
+//
+#define DEFAULT_GPCNIU_MEMORY_WINDOW 0xD8000
+
+
+#define GPCNIU_MINIMUM_WINDOW_SIZE 0x4000
+#define GPCNIU_OPERATIONAL_CS 0x2000
+#define GPCNIU_PRIMARY_DS 0x3000
+#define GPCNIU_TX_BUFFER_SEGS 0x3000
+#define GPCNIU_HIGHEST_RAM_SEGS 0x7000
+#define GPCNIU_SCSP_SEGS 0x7000
+#define GPCNIU_POD_STATUS_ADDR 0xFF80
+#define GPCNIU_HOST_INTR_PORT 0x3000
+#define GPCNIU_82586_CA_PORT 0x0080
+#define GPCNIU_82586_RESET_PORT 0x0280
+#define GPCNIU_ADAPTER_CTRL_PORT 0x0200
+#define GPCNIU_IRQSEL_LEDPORT 0x0180
+#define GPCNIU_DEADMAN_TIMERPORT 0x1006
+#define GPCNIU_LEDOFF_12V_DOPARCHK x12V_BIT
+#define GPCNIU_LEDON_12V_DOPARCHK x12V_BIT+LED_BIT
+#define GPCNIU_ADAPTER_FLAGS TWO_PASS_DIAGNOSTICS+ASYNCHRONOUS_READY
+#define GPCNIU_ADAPTER_CODE 'G'
+#define NIUPS_ADAPTER_CODE 'Y'
+#define GPCNIU_CLI_OFFSET 0x0
+#define GPCNIU_MAP_OFFSET 0x0
+#define GPCNIU_INTR_STATUS_OFFSET 0x1
+#define GPCNIU_SETWINBASE_OFFSET 0x2
+
+#define GPCNIU_NEXT_RAM_PAGE ((UCHAR)(WINDOWSIZE >> 8*3))
+
+
+
+#define NIUPC_MINIMUM_WINDOW_SIZE 0x8000
+#define NIUPC_OPERATIONAL_CS 0x2000
+#define NIUPC_PRIMARY_DS 0x3000
+#define NIUPC_TX_BUFFER_SEGS 0x3000
+#define NIUPC_HIGHEST_RAM_SEGS 0x3000
+#define NIUPC_SCSP_SEGS 0x3000
+#define NIUPC_POD_STATUS_ADDR 0xFEF8
+#define NIUPC_HOST_INTR_PORT 0x0100
+#define NIUPC_82586_CA_PORT 0x0080
+#define NIUPC_82586_RESET_PORT 0x0280
+#define NIUPC_ADAPTER_CTRL_PORT 0x0200
+#define NIUPC_IRQSEL_LEDPORT 0x0000
+#define NIUPC_DEADMAN_TIMERPORT 0x0018
+#define NIUPC_LEDOFF_12V_DOPARCHK x12V_BIT+DO_PARITY_CHECK_BIT+LED_BIT
+#define NIUPC_LEDON_12V_DOPARCHK x12V_BIT+DO_PARITY_CHECK_BIT
+#define NIUPC_ADAPTER_FLAGS 0
+#define NIUPC_ADAPTER_CODE 'V'
+#define NIUPC_CLI_OFFSET 0x0
+#define NIUPC_MAP_OFFSET 0x0
+#define NIUPC_INTR_STATUS_OFFSET 0x0
+#define NIUPC_SETWINBASE_OFFSET 0x0
+
+
+
+
+
+// DEFAULT HARDWARE SETTINGS:END
+
+
+
+//
+// The NIU control area in the InitWindowPage.
+// Starts at offset:
+//
+// (MemMapped)SharedMemBase + NIU_CONTROL_AREA_OFFSET(0xFF00)
+//
+
+
+
+typedef struct _NIUDETAILS {
+ UCHAR MappingTable[0x20];
+ USHORT AdapterClass;
+ USHORT MinimumWindowSize;
+ USHORT OperationalCodeSegment;
+ USHORT PrimaryDataSegment;
+ USHORT TransmitBufferSegment;
+ USHORT HighestRamSegment;
+ USHORT SCPSegment;
+ USHORT POD_Status_Address;
+ USHORT HostInterruptPort;
+ USHORT _82586_CA_Port;
+ USHORT _82586_RESET_Port;
+ USHORT AdapterControlPort;
+ UCHAR LED_Off_12Volts_DoParityCheck;
+ UCHAR LED_On_12Volts_DoParityCheck;
+ USHORT IRQ_Select_And_LED_Port;
+ USHORT DeadManTimerPort;
+ UCHAR IO_PortOffset[4];
+ UCHAR AdapterFlags;
+ UCHAR AdapterCode;
+ } NIUDETAILS, *PNIUDETAILS;
+
+
+
+
+
+
+
+typedef struct tagOtherRingBufferDesc {
+ UCHAR ORB_WritePtr_Byte;
+ UCHAR res1;
+ UCHAR ORB_ReadPtr_Byte;
+ UCHAR res2;
+ UCHAR ORB_PtrLimit;
+ UCHAR ORB_ElementSize;
+ USHORT ORB_BufferBase;
+ USHORT ORB_Windowed_BufferBase;
+ UCHAR ORB_ObjectMap;
+ UCHAR ORB_pad[5];
+ } ORB, *PORB;
+
+
+typedef struct tagRequest_RingBuffer_Entry {
+ USHORT RequestCode;
+ USHORT RequestID;
+ USHORT RequestParam1;
+ UCHAR RequestData[6];
+ } RRBE, *PRRBE;
+
+typedef struct tagResult_RingBuffer_Entry {
+ USHORT ResultID;
+ USHORT ResultCode;
+ } RESULTRBE, *PRESULTRBE;
+
+
+typedef struct tagTBD {
+ USHORT TBD_EOF_and_Length;
+ USHORT TBD_next_TBD;
+ USHORT TBD_Buffer;
+ UCHAR TBD_Buffer_MSB;
+ UCHAR TBD_Buffer_Map;
+ USHORT TBD_Frame_Length;
+ UCHAR TBD_Unused;
+ UCHAR TBD_Flags;
+ USHORT TBD_next_TDB_offset;
+ USHORT TBD_Buffer_offset;
+ } TBD, *PTBD;
+
+typedef struct tagRBD {
+ USHORT RBD_EOF_F_and_Length;
+ USHORT RBD_next_RBD;
+ USHORT RBD_Buffer;
+ UCHAR RBD_Buffer_MSB;
+ UCHAR RBD_Owner;
+ USHORT RBD_EOL_and_Size;
+ USHORT RBD_Buffer_Segment;
+ USHORT RBD_Frame_Length;
+ UCHAR RBD_Flags;
+ UCHAR RBD_unused;
+ } RBD, *PRBD;
+
+
+typedef struct tagMCB {
+ UCHAR res;
+ UCHAR MCB_Status;
+ USHORT MCB_Command;
+ USHORT next_CB;
+ USHORT MCB_Count;
+ } MCB, *PMCB;
+
+
+
+
+// SYSTEM mode Bits
+
+#define BROADBAND_MODE 0x8000
+#define INTERNAL_READY_SYNC 0x4000
+
+
+// System_State bits
+
+#define INITIALIZED 0x8000
+
+
+#include "packoff.h"
diff --git a/private/ntos/ndis/ubnei/ubnei.bin b/private/ntos/ndis/ubnei/ubnei.bin
new file mode 100644
index 000000000..f70090471
--- /dev/null
+++ b/private/ntos/ndis/ubnei/ubnei.bin
Binary files differ
diff --git a/private/ntos/ndis/ubnei/ubnei.c b/private/ntos/ndis/ubnei/ubnei.c
new file mode 100644
index 000000000..9d489f4a1
--- /dev/null
+++ b/private/ntos/ndis/ubnei/ubnei.c
@@ -0,0 +1,567 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ macndis.c
+
+Abstract:
+
+ This is the mac ndis file for the Ungermann Bass Ethernet Controller.
+ This driver conforms to the NDIS 3.0 interface.
+
+
+ This driver currently supports three UB Network cards.
+
+ NIUpc -- Old 16-bit long cards
+ 256k of on board memory
+ jumpers to set i/o base, memory window, interrupt level
+ Memory window size is 32k
+
+ NIUpc/EOTP -- New short 16-bit cards
+ 512k of memory
+ i/o base set by jumpers
+ Interrupt level, memory window base and size software
+ configurable
+ Memory window size is 16k, 32k
+
+ NIUps -- Basically an MCA EOTP card.
+ 512k of memory
+ i/o base, interrupt level, memory window determined
+ by MCA POS mechanism
+ Memory window size is 16k, 32k, 64k
+
+ All of the UB card are composed of an 80186 and an Intel 82586 lan
+ coprocessor.
+
+ The Download code that is copied to the card and run is a slightly
+ modified version of the down load code from UB NDIS 2.01 driver.
+
+ This download load code was basically designed to the least common
+ denominator of there older net cards. It only makes use of 128k
+ of the cards memory no matter what type of card.
+
+ The card memory is laided out as a 64k data segment and 64k code segment
+ The data segment is further divided into to parts. The lower 32k
+ of the data segment holds all of the receive buffers and receive buffer
+ descriptors. It also holds various statistics for ease of access.
+ The upper 32k is used to store various items of which the ring buffers
+ are of primary interest. If the Memory window size is 16k then only
+ the first 16k of both 32k halfs is used.
+
+ The code segment holds the all of the download code. The remainder of
+ the 64k (~48k) is used for the transmit buffers.
+
+ The i/o register of most interest is the map register. This register
+ is at offset 0 from the I/O base. The register has three functions.
+ 1) The upper 6 bits of this register determines which section
+ of the cards memory is currently viewable in the memory window.
+
+ 2) Bit #1 is used to enable and disable interrupts from the card.
+ This bit is also used to clear and interrupt from the card.
+ In order to clear and interrupt, the bit must be set to zero and
+ the set 1. This little fact is what makes things interresting
+ in handling interrupts. To dismiss the interrupt you must write
+ some value to this port, But this port also controls the window
+ map so you need to be careful about just what you write to this
+ port. On the old 16-bit card this port is not readable.
+ Obviously bad things would happen on an MP if one processor
+ set the map to one thing and second came along and set it to
+ something else. Spin locks will work to protect the port
+ for normal accesses, but they can not be used to protect it from
+ access from the ISR which must clear the interrupt.
+
+ I had originally planned to not do anything in the ISR and let
+ the DPC handle clearing the interrupt. This works fine on
+ the NON-MCA cards, but this one is LEVEL TRIGGERED so I need
+ to clear the interrupt by writing something to the port in the ISR.
+
+ The way I have currently implemented this is to only have the
+ reeceive window mapped in when interrupts are enabled. I do this
+ by disabling interrupts from the card and clearing the interrupt
+ in the ISR and returning. Now when the DPC runs it knows that
+ interrutps are disabled, and can change the map port as it wishes.
+ The code call by protocols to handle request does not ever
+ access any thing that is not in the receive page.
+
+ 3) Bit #0 is used to reset the card. Setting this bit resets the card.
+ This bit reamins 0 except during init.
+
+
+
+
+
+
+
+
+
+
+
+Author:
+
+ Sanjeev Katariya (sanjeevk) 03-05-92
+
+Environment:
+
+ Kernel Mode Operating Systems : NT and other lesser OS's(dos)
+
+Revision History:
+
+ Brian Lieuallen BrianLie 07/21/92
+ Made it work.
+
+ Brian Lieuallen BrianLie 12/15/93
+ Made it a mini-port
+
+--*/
+
+
+
+#include <ndis.h>
+#include <efilter.h>
+
+#include "niudata.h"
+#include "debug.h"
+
+#include "ubhard.h"
+#include "ubsoft.h"
+#include "ubnei.h"
+
+#include "map.h"
+
+//
+// This constant is used for places where NdisAllocateMemory
+// needs to be called and the HighestAcceptableAddress does
+// not matter.
+//
+
+NDIS_PHYSICAL_ADDRESS HighestAcceptableMax =
+ NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
+
+
+
+
+
+NDIS_STATUS
+UbneiAddressChangeAction(
+ IN UINT NewFilterCount,
+ IN PUCHAR NewAddresses,
+ IN NDIS_HANDLE MacBindingHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when a particular filter
+ class is first used or last cleared.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+
+ NewFilterCount - The number of addresses that should now be on the card.
+
+ NewAddresses - A list of addresses that should be put on the card.
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to ELNKII_OPEN.
+
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ PUBNEI_ADAPTER pAdapt = MacBindingHandle;
+
+
+ //
+ // Holds the status that should be returned to the filtering package.
+ //
+ NDIS_STATUS StatusOfAdd;
+ IF_REQ_LOUD(DbgPrint("UBNEI: AddressChangeAction called\n");)
+
+
+ if (NIU_SET_MULTICAST_LIST(pAdapt,
+ ChangeAddressDPC,
+ (PUCHAR)NewAddresses,
+ (USHORT)NewFilterCount
+ )) {
+
+ StatusOfAdd=NDIS_STATUS_PENDING;
+ } else {
+ //
+ // The adapter has failed, It doesn't really matter
+ // what we return since the card has stopped working
+ //
+ StatusOfAdd=NDIS_STATUS_FAILURE;
+ }
+
+
+
+ return StatusOfAdd;
+
+}
+
+
+
+VOID
+ChangeAddressDPC(
+ IN NDIS_STATUS Status,
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ This routine is called when the NIU completes a multicast or filter
+ change request. It in turn completes the pended request from the protocol
+
+Arguments:
+
+ Context is actually a pointer to the an NDIS_REQUEST
+
+
+--*/
+
+{
+ PUBNEI_ADAPTER pAdapter=Context;
+
+ IF_REQ_LOUD (DbgPrint("FilterActionDPC called\n");)
+
+ NdisMSetInformationComplete(
+ pAdapter->NdisAdapterHandle,
+ Status
+ );
+
+
+
+}
+
+
+
+
+VOID
+DummyDPC(
+ IN NDIS_STATUS status,
+ IN PVOID pContext
+ )
+/*++
+
+Routine Description:
+
+ This routine is called when the NIU completes a request and nothing
+ needs to be completed to a protocol. This routine is passed as the
+ callback address passed to filter functions during a close and also
+ used during a Reset which is restarting the adapter.
+
+Arguments:
+
+
+
+--*/
+
+{
+ IF_REQ_LOUD (DbgPrint("UBNEI: DummyDPC called for filter action routine called at close\n");)
+ return;
+
+}
+
+
+
+
+
+
+NDIS_STATUS
+UbneiFilterChangeAction(
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle
+ )
+
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when an address is added to
+ the filter that wasn't referenced by any other open binding.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ OldFilterClasses - A bit mask that is currently on the card telling
+ which packet types to accept.
+
+ NewFilterClasses - A bit mask that should be put on the card telling
+ which packet types to accept.
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to ELNKII_OPEN.
+
+ NdisRequest - The NDIS_REQUEST which submitted the filter change command.
+
+ Set - A flag telling if the command is a result of a close or not.
+
+Return Value:
+
+ Status of the change (successful or pending).
+
+
+--*/
+
+{
+ PUBNEI_ADAPTER pAdapt = MacBindingHandle;
+ USHORT NewFilter=0;
+
+ //
+ // Holds the status that should be returned to the filtering package.
+ //
+ NDIS_STATUS StatusOfAdd;
+ IF_REQ_LOUD(DbgPrint("UBNEI: FilterChangeAction called\n");)
+
+ if (NewFilterClasses & ~(NDIS_PACKET_TYPE_DIRECTED |
+ NDIS_PACKET_TYPE_MULTICAST |
+ NDIS_PACKET_TYPE_ALL_MULTICAST |
+ NDIS_PACKET_TYPE_BROADCAST |
+ NDIS_PACKET_TYPE_PROMISCUOUS )) {
+
+ IF_REQ_LOUD(DbgPrint("UBNEI: Stupid protocol set bogus filter\n");)
+ return NDIS_STATUS_NOT_SUPPORTED;
+ }
+
+
+ if (NewFilterClasses & ( NDIS_PACKET_TYPE_DIRECTED |
+ NDIS_PACKET_TYPE_MULTICAST
+ )) {
+
+ NewFilter|=0x0001;
+ }
+
+ if (NewFilterClasses & NDIS_PACKET_TYPE_BROADCAST) {
+ NewFilter|=0x0002;
+ }
+
+ //
+ // 82586 does not support all multicast so we set to promiscuous
+ //
+
+ if (NewFilterClasses & NDIS_PACKET_TYPE_ALL_MULTICAST) {
+ NewFilter|=0x0007;
+ }
+
+ if (NewFilterClasses & NDIS_PACKET_TYPE_PROMISCUOUS) {
+ NewFilter|=0x0007;
+ }
+
+
+
+ pAdapt->PacketFilter=NewFilter;
+
+
+ if (NIU_SET_FILTER(pAdapt,
+ ChangeAddressDPC,
+ NewFilter)) {
+
+
+ StatusOfAdd=NDIS_STATUS_PENDING;
+ } else {
+ //
+ // The adapter has failed, It doesn't really matter
+ // what we return since the card has stopped working
+ //
+ StatusOfAdd=NDIS_STATUS_FAILURE;
+ }
+
+
+
+ return StatusOfAdd;
+
+}
+
+
+
+
+
+
+
+
+BOOLEAN
+UbneiCheckForHang(
+ IN NDIS_HANDLE Context
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ DeferredContext - will be a pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PUBNEI_ADAPTER pAdapter = ((PUBNEI_ADAPTER)Context);
+
+ PLOWNIUDATA pRcvDWindow = (PLOWNIUDATA) pAdapter->pCardRam;
+
+ UCHAR InterruptActive;
+
+
+// IF_LOG('w');
+
+ if (!pAdapter->WaitingForDPC) {
+ //
+ // We are not waiting on a DPC
+ //
+ ASSERT_RECEIVE_WINDOW( pAdapter);
+
+ UBNEI_MOVE_SHARED_RAM_TO_UCHAR(&InterruptActive,&(pRcvDWindow->InterruptActive));
+
+ if (InterruptActive != 0) {
+ //
+ // The card has generated an interrupt
+ //
+ if (pAdapter->WakeUpState==0) {
+ //
+ // This is first time here
+ //
+ pAdapter->DpcHasRun=FALSE;
+
+ pAdapter->WakeUpState=1;
+
+ } else {
+ //
+ // This is the second time in here, check to see if the DPC ran
+ //
+ if (pAdapter->DpcHasRun) {
+ //
+ // The dpc has run so things must be ok
+ //
+ pAdapter->WakeUpState=0;
+
+ } else {
+ //
+ // The dpc has not run, ask the card to do it again.
+ //
+ IF_LOUD(DbgPrint("UBNEI: CheckForHang: Lost an interrupt?!?\n");)
+
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pRcvDWindow->InterruptActive), 0x0);
+
+ UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pRcvDWindow->HostWantsInterrupt), 0xFF);
+
+ pAdapter->WakeUpState=0;
+
+ }
+
+ }
+
+ } else {
+ //
+ // The has not generated an interrupt
+ //
+ pAdapter->WakeUpState=0;
+ }
+
+ } else {
+ //
+ // A dpc is pending
+ //
+ }
+
+
+ return FALSE;
+
+
+
+}
+
+
+
+
+NDIS_STATUS
+UbneiReset(
+ OUT PBOOLEAN AddressResetting,
+ IN NDIS_HANDLE MacBindingHandle
+ )
+
+/*++
+
+Routine Description:
+
+ NDIS function.
+
+Arguments:
+
+ See NDIS 3.0 spec.
+
+--*/
+
+{
+ PUBNEI_ADAPTER pAdapter = ((PUBNEI_ADAPTER)MacBindingHandle);
+
+ IF_INIT_LOUD(DbgPrint("UbneiReset() Called\n");)
+
+ NIU_RESET_ADAPTER(
+ pAdapter,
+ ResetAdapterDPC
+ );
+
+ *AddressResetting=FALSE;
+
+ return NDIS_STATUS_PENDING;
+
+
+}
+
+
+
+
+
+VOID
+ResetAdapterDPC(
+ IN NDIS_STATUS status,
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ This routine is called when the NIU completes a request and nothing
+ needs to be completed to a protocol. This routine is passed as the
+ callback address passed to filter functions during a close and also
+ used during a Reset which is restarting the adapter.
+
+Arguments:
+
+
+
+--*/
+
+{
+ PUBNEI_ADAPTER pAdapter = ((PUBNEI_ADAPTER)Context);
+
+ IF_INIT_LOUD (DbgPrint("Ubnei: ResetAdapterDpc\n");)
+
+ NdisMResetComplete(
+ pAdapter->NdisAdapterHandle,
+ NDIS_STATUS_SUCCESS,
+ FALSE
+ );
+
+ return;
+
+}
diff --git a/private/ntos/ndis/ubnei/ubnei.h b/private/ntos/ndis/ubnei/ubnei.h
new file mode 100644
index 000000000..d2799faeb
--- /dev/null
+++ b/private/ntos/ndis/ubnei/ubnei.h
@@ -0,0 +1,332 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ndis.h
+
+Abstract:
+
+ This is the ndis header file for the Ungermann Bass Ethernet Controller.
+
+ It contains the various definitions, macros and function declarations
+ of the NDIS3.0 specification implemented in the Ungermann Bass Ethernet
+ Controller.
+
+Author:
+
+ Sanjeev Katariya (sanjeevk) 03-05-92
+
+Environment:
+
+ Kernel Mode Operating Systems : NT and other lesser OS's
+
+Revision History:
+
+ Brian Lieuallen BrianLie 07/21/92
+ Made it work.
+
+ Brian Lieuallen BrianLie 12/15/93
+ Made it a mini-port
+
+
+
+--*/
+
+
+
+
+
+#define STATIC static
+
+
+//
+// This constant is used for places where NdisAllocateMemory
+// needs to be called and the HighestAcceptableAddress does
+// not matter.
+//
+
+extern NDIS_PHYSICAL_ADDRESS HighestAcceptableMax;
+
+//
+// NDIS 3.0 entry functions
+//
+
+
+
+VOID
+UbneiAdjustMaxLookAhead(
+ IN PUBNEI_ADAPTER pAdapter
+ );
+
+
+
+
+BOOLEAN
+Ubnei_InterruptServiceRoutine(
+ IN PVOID DefferedContext
+ );
+
+BOOLEAN
+UbneiSetInitInterruptSync(
+ PVOID Context
+ );
+
+BOOLEAN
+UbneiSetNormalInterruptSync(
+ PVOID Context
+ );
+
+
+//
+// Contained in CARD.C
+//
+
+BOOLEAN
+CardTest (
+ OUT PUBNEI_ADAPTER pAdapter
+ );
+
+BOOLEAN
+CardSetup (
+ OUT PUBNEI_ADAPTER pAdapter
+ );
+
+
+BOOLEAN
+CardStartNIU(
+ OUT PUBNEI_ADAPTER pNewAdapt
+ );
+
+BOOLEAN
+NIU_General_Request3(
+ IN NIU_GEN_REQ_DPC pDPCCallback,
+ IN PVOID pContext,
+ IN USHORT RequestCode,
+ IN USHORT param1,
+ IN PUCHAR param2
+ );
+
+
+
+
+VOID
+NIU_General_Req_Result_Hand(
+ IN PUBNEI_ADAPTER pAdapt
+ );
+
+VOID
+NIU_Send_Request_To_Card(
+ IN PUBNEI_ADAPTER pAdapt
+ );
+
+VOID
+NIU_Abort_General_Req(
+ IN PUBNEI_ADAPTER pAdapter
+ );
+
+
+
+VOID
+OpenAdapterDPC(
+ IN NDIS_STATUS status,
+ IN PVOID pContext
+ );
+
+VOID
+ChangeAddressDPC(
+ IN NDIS_STATUS status,
+ IN PVOID pContext
+ );
+
+VOID
+ResetAdapterDPC(
+ IN NDIS_STATUS status,
+ IN PVOID pContext
+ );
+
+VOID
+DummyDPC(
+ IN NDIS_STATUS status,
+ IN PVOID pContext
+ );
+
+VOID
+CloseAdapterDPC(
+ IN NDIS_STATUS status,
+ IN PVOID pContext
+ );
+
+
+
+
+//
+// Contained in send.c
+//
+
+VOID
+CheckForSends(
+ PUBNEI_ADAPTER pAdapt
+ );
+
+
+//
+// Contained in receive.c
+//
+
+BOOLEAN
+CheckForReceives(
+ IN PUBNEI_ADAPTER pAdapter
+ );
+
+
+
+//
+// Contained in registry.c
+//
+
+NDIS_STATUS
+UbneiReadRegistry(
+ IN PUBNEI_ADAPTER pAdapter,
+ IN NDIS_HANDLE ConfigurationHandle
+ );
+
+
+
+
+
+
+
+
+
+
+BOOLEAN
+UbneiCheckForHang(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+
+
+NDIS_STATUS
+UbneiQueryInformation(
+ IN NDIS_HANDLE MiniportContext,
+ IN NDIS_OID Oid,
+ IN PVOID InfoBuffer,
+ IN ULONG BytesLeft,
+ OUT PULONG BytesNeeded,
+ OUT PULONG BytesWritten
+ );
+
+
+
+NDIS_STATUS
+UbneiSetInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ );
+
+NDIS_STATUS
+UbneiInitialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ );
+
+VOID
+UbneiHalt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+
+NDIS_STATUS
+UbneiReset(
+ OUT PBOOLEAN AddressResetting,
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+NDIS_STATUS
+UbneiMacSend(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_PACKET pPacket,
+ IN UINT Flags
+ );
+
+NDIS_STATUS
+UbneiTransferData(
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+ );
+
+
+NDIS_STATUS
+UbneiReconfigure(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE ConfigurationHanel
+ );
+
+
+
+
+VOID
+UbneiIsr(
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueDpc,
+ IN NDIS_HANDLE Context
+ );
+
+
+
+VOID
+UbneiIsrDpc(
+ IN NDIS_HANDLE DeferredContext // will be a pointer to the adapter block
+ );
+
+
+
+VOID
+UbneiEnableInterrupts(
+ IN NDIS_HANDLE Context
+ );
+
+
+VOID
+UbneiDisableInterrupts(
+ IN NDIS_HANDLE Context
+ );
+
+
+
+
+VOID
+UbneiMapRegisterChangeSync(
+ PSYNC_CONTEXT Context
+ );
+
+
+
+NDIS_STATUS
+UbneiAddressChangeAction(
+ IN UINT NewFilterCount,
+ IN PUCHAR NewAddresses,
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+
+NDIS_STATUS
+UbneiFilterChangeAction(
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle
+ );
diff --git a/private/ntos/ndis/ubnei/ubnei.rc b/private/ntos/ndis/ubnei/ubnei.rc
new file mode 100644
index 000000000..545f76cd3
--- /dev/null
+++ b/private/ntos/ndis/ubnei/ubnei.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+#define VER_FILEDESCRIPTION_STR "Ungerman-Bass network driver"
+#define VER_INTERNALNAME_STR "UBNEI.SYS"
+#define VER_ORIGINALFILENAME_STR "UBNEI.SYS"
+
+#include "common.ver"
+
diff --git a/private/ntos/ndis/ubnei/ubsoft.h b/private/ntos/ndis/ubnei/ubsoft.h
new file mode 100644
index 000000000..90ac2240d
--- /dev/null
+++ b/private/ntos/ndis/ubnei/ubsoft.h
@@ -0,0 +1,381 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ software.h
+
+Abstract:
+
+ This is the software definitions header file for the Ungermann Bass
+ Ethernet Controller.
+
+ This file contains definitions and macros used in
+
+Author:
+
+ Sanjeev Katariya (sanjeevk) 03-05-92
+
+Environment:
+
+ Kernel Mode Operating Systems : NT and other lesser OS's(dos)
+
+Revision History:
+
+ Brian Lieuallen BrianLie 12/15/93
+ Made it a mini-port
+
+--*/
+
+
+
+
+
+// DEFINES
+
+//
+// Default software settings for ANY Ungermann Bass card
+// supported by this driver
+//
+
+#define DEFAULT_MULTICAST_SIZE 16
+#define DEFAULT_MAXIMUM_REQUESTS 4
+#define DEFAULT_MAXIMUM_TRANSMITS 6
+#define DEFAULT_RECEIVE_BUFFER_SIZE 512
+#define DEFAULT_RECEIVE_BUFFERS 64
+
+
+#define UBNEI_NDIS_MAJOR_VERSION 3
+#define UBNEI_NDIS_MINOR_VERSION 0
+
+
+#define UBNEI_ETHERNET_HEADER_SIZE 14
+
+//
+// Default software settings for specific Ungermann Bass cards
+//
+//#define DEFAULT_GPCNIU_MAXMCAST_SIZE 16
+
+
+
+
+
+#define UBNEI_MOVE_MEM(dest,src,size) NdisMoveMemory(dest,src,size)
+
+#define UBNEI_MOVE_SHARED_RAM_TO_MEM(dest,src,size) NdisMoveFromMappedMemory(dest,src,size)
+#define UBNEI_MOVE_MEM_TO_SHARED_RAM(dest,src,size) NdisMoveToMappedMemory(dest,src,size)
+
+#define UBNEI_MOVE_UCHAR_TO_SHARED_RAM(dest, src) NdisWriteRegisterUchar((PUCHAR)dest, (UCHAR)(src))
+//#define UBNEI_MOVE_USHORT_TO_SHARED_RAM(dest, src) NdisWriteRegisterUshort((PUSHORT)dest, (USHORT)(src))
+//#define UBNEI_MOVE_DWORD_TO_SHARED_RAM(dest, src) NdisWriteRegisterUlong((PULONG)dest, (ULONG)(src))
+
+#define UBNEI_MOVE_SHARED_RAM_TO_UCHAR(dest, src) NdisReadRegisterUchar((PUCHAR)src, (PUCHAR)(dest))
+#define UBNEI_MOVE_SHARED_RAM_TO_USHORT(dest, src) NdisReadRegisterUshort((PUSHORT)src, (PUSHORT)(dest))
+#define UBNEI_MOVE_SHARED_RAM_TO_DWORD(dest, src) NdisReadRegisterUlong((PULONG)src, (PULONG)(dest))
+
+
+
+
+#if 0
+
+#define UBNEI_MOVE_USHORT_TO_SHARED_RAM(dest, src) { \
+ \
+ if ((ULONG)(dest) & 1) { \
+ DbgPrint("UBNEI: Unaligned word write to shared ram %08x\n",dest); \
+ DbgBreakPoint(); \
+ } \
+ NdisWriteRegisterUshort((PUSHORT)(dest), (USHORT)(src)); \
+}
+
+#define UBNEI_MOVE_DWORD_TO_SHARED_RAM(dest, src) { \
+ \
+ if ((ULONG)(dest) & 3) { \
+ DbgPrint("UBNEI: Unaligned dword write to shared ram %08x\n",dest); \
+ DbgBreakPoint(); \
+ } \
+ \
+ NdisWriteRegisterUlong((PULONG)(dest), (ULONG)(src)); \
+}
+
+#else
+
+#define UBNEI_MOVE_USHORT_TO_SHARED_RAM(dest, src) NdisWriteRegisterUshort((PUSHORT)dest, (USHORT)(src))
+#define UBNEI_MOVE_DWORD_TO_SHARED_RAM(dest, src) NdisWriteRegisterUlong((PULONG)dest, (ULONG)(src))
+
+#endif
+
+
+//
+// Macros
+//
+#define MACRO_ASSERTALL() { \
+ ASSERT ( sizeof(CHAR) = 1 ); \
+ ASSERT ( sizeof(UCHAR) = 1 ); \
+ ASSERT ( sizeof(USHORT) = 2 ); \
+ ASSERT ( sizeof(UINT) = 4 ); \
+ ASSERT ( sizeof(ULONG) = 4 ); \
+ }
+
+
+
+typedef struct _PACKET_QUEUE {
+ PNDIS_PACKET QIn;
+ PNDIS_PACKET QOut;
+ } PACKET_QUEUE, *PPACKET_QUEUE;
+
+
+
+
+typedef struct _SYNC_CONTEXT {
+ struct _UBNEI_ADAPTER * pAdapter;
+ UCHAR CurrentMapRegister;
+ UCHAR NewMapRegister;
+ } SYNC_CONTEXT, * PSYNC_CONTEXT;
+
+typedef struct _SEND_SYNC_CONTEXT {
+ struct _UBNEI_ADAPTER * pAdapter;
+ PVOID SendBuffer;
+ UINT PacketLength;
+ UCHAR TbdIndex;
+ } SEND_SYNC_CONTEXT, *PSEND_SYNC_CONTEXT;
+
+typedef
+VOID
+(*NIU_GEN_REQ_DPC)(
+ IN NDIS_STATUS status,
+ IN PVOID pContext
+ );
+
+typedef struct _NIUREQUEST {
+ PVOID pContext;
+ NIU_GEN_REQ_DPC pDPCFunc;
+ PUCHAR AddressList;
+ UINT ListSize;
+ RRBE rrbe;
+ } NIUREQUEST, *PNIUREQUEST;
+
+
+
+//
+// One of these structures per adapter registered.
+//
+
+
+typedef struct _UBNEI_ADAPTER {
+
+ SYNC_CONTEXT MapRegSync;
+
+ //
+ // Window mapping values used to map in various pages
+ //
+
+ UCHAR InitWindow_Page;
+ UCHAR ReceiveDataWindow_Page;
+ UCHAR DataWindow_Page;
+ UCHAR CodeWindow_Page;
+
+
+ //
+ // Ports
+ //
+ PVOID InterruptMaskPort;
+ PVOID MapPort;
+ PVOID InterruptStatusPort;
+ PVOID SetWindowBasePort;
+
+
+ //
+ // NDIS wrapper information.
+ //
+
+ NDIS_HANDLE NdisAdapterHandle; // returned from NdisRegisterAdapter
+
+
+
+ //
+ // NDIS Interrupt information
+ //
+ NDIS_MINIPORT_INTERRUPT NdisInterrupt;
+ NDIS_INTERRUPT_MODE InterruptMode;
+ volatile UINT uInterruptCount;
+ BOOLEAN InInit;
+
+ volatile BOOLEAN WaitingForDPC;
+ BOOLEAN DpcHasRun;
+
+ BOOLEAN WaitingForXmitInterrupt;
+
+ //
+ // Registry information
+ //
+
+ PVOID TranslatedIoBase;
+
+ UINT IoPortBaseAddr;
+ UINT MemBaseAddr;
+ UINT MaxMultiCastTableSize;
+ UINT MaxRequests;
+ UINT MaxTransmits;
+ UINT ReceiveBuffers;
+ UINT ReceiveBufSize;
+ UINT AdapterType;
+ BOOLEAN Diagnostics;
+ CHAR IrqLevel;
+ ULONG WindowSize;
+ ULONG WindowMask;
+ ULONG NotWindowMask;
+
+
+ UCHAR StationAddress[ETH_LENGTH_OF_ADDRESS]; // filled in at init time
+ UCHAR PermanentAddress[ETH_LENGTH_OF_ADDRESS]; // filled in at init time
+
+ //
+ // Statistics used by Set/QueryInformation.
+ //
+
+ UINT TransmitBufferSpace;
+ UINT ReceiveBufferSpace;
+ UINT TransmitBlockSize;
+ UINT ReceiveBlockSize;
+
+
+ ULONG FramesXmitGood; // Good Frames Transmitted
+ ULONG FramesRcvGood; // Good Frames Received
+ ULONG FramesXmitBad; // Bad Frames Transmitted
+ ULONG FramesXmitOneCollision; // Frames Transmitted with one collision
+ ULONG FramesXmitManyCollisions; // Frames Transmitted with > 1 collision
+ ULONG FrameAlignmentErrors; // FAE errors counted
+ ULONG CrcErrors; // CRC errors counted
+ ULONG MissedPackets; // missed packet counted
+
+
+ //
+ // Look Ahead information.
+ //
+
+ ULONG MaxLookAhead;
+
+
+
+ //
+ // Adapter specific Infomation
+ //
+
+ USHORT PacketFilter;
+
+
+
+ //
+ // Timer functions/objects
+ //
+ UINT WakeUpState;
+
+ //
+ // Memory mapped pointers
+ //
+ PVOID pCardRam;
+ PHIGHNIUDATA pDataWindow;
+ PNIU_CONTROL_AREA pNIU_Control;
+
+ //
+ // NIU general requests
+ //
+ USHORT NIU_Requests_Pending;
+ USHORT NIU_Request_Head,NIU_Request_Tail,NIU_Next_Request;
+
+ NIUREQUEST NiuRequest[DEFAULT_MAXIMUM_REQUESTS];
+
+ //
+ // Recieve stuff
+ //
+ PRBD pIndicatedRBD;
+ UINT PacketLen;
+
+ PUCHAR FirstCardBuffer;
+
+
+ //
+ // Init stuff
+ //
+
+
+} UBNEI_ADAPTER, * PUBNEI_ADAPTER;
+
+
+
+
+
+
+
+
+//
+// NIU general request
+//
+#define NIU_Cmd_Set_Multicast 8
+#define NIU_Cmd_Set_Filter 7
+#define NIU_Cmd_Open 4
+#define NIU_Cmd_Close 5
+#define NIU_Cmd_Reset 6
+
+
+#define NIU_SET_MULTICAST_LIST(_pAdapter,CallBack,_List,_Size) \
+ NIU_General_Request3( \
+ CallBack, \
+ (PVOID)_pAdapter, \
+ 8, \
+ _Size, \
+ _List)
+
+#define NIU_SET_FILTER(_pAdapter,CallBack,Filter) \
+ NIU_General_Request3( \
+ CallBack, \
+ (PVOID)_pAdapter, \
+ 7, \
+ Filter, \
+ NULL)
+
+#define NIU_OPEN_ADAPTER(_pAdapter,CallBack) \
+ NIU_General_Request3( \
+ CallBack, \
+ (PVOID)_pAdapter, \
+ 4, \
+ 0, \
+ NULL)
+
+#define NIU_CLOSE_ADAPTER(_pAdapter,CallBack) \
+ NIU_General_Request3( \
+ CallBack, \
+ (PVOID)_pAdapter, \
+ 5, \
+ 0, \
+ NULL)
+
+#define NIU_RESET_ADAPTER(_pAdapter,CallBack) \
+ NIU_General_Request3( \
+ CallBack, \
+ (PVOID)_pAdapter, \
+ 6, \
+ 0, \
+ NULL) \
+
+#define NIU_SET_STATION_ADDRESS(_pAdapter,CallBack,Address)\
+ NIU_General_Request3( \
+ CallBack, \
+ (PVOID)_pAdapter, \
+ 3, \
+ 0, \
+ Address) \
+
+
+
+
+
+
+
+
+
+#define INTERRUPT_ENABLED 0x02
+#define INTERRUPT_DISABLED 0x00
+#define RESET_SET 0x01
+#define RESET_CLEAR 0x00
diff --git a/private/ntos/ndis/wd/keywords.h b/private/ntos/ndis/wd/keywords.h
new file mode 100644
index 000000000..35896713e
--- /dev/null
+++ b/private/ntos/ndis/wd/keywords.h
@@ -0,0 +1,54 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ keywords.h
+
+Abstract:
+
+ Contains all Ndis2 and Ndis3 mac-specific keywords.
+
+Author:
+
+ Bob Noradki
+
+Environment:
+
+ This driver is expected to work in DOS, OS2 and NT at the equivalent
+ of kernal mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+
+
+--*/
+#ifndef NDIS2
+#define NDIS2 0
+#endif
+
+#if NDIS2
+
+#define IOBASE NDIS_STRING_CONST("IOBASE")
+#define MAXMULTICASTLIST NDIS_STRING_CONST("MAXMULTICAST")
+#define NETADDRESS NDIS_STRING_CONST("NETADDRESS")
+#define INTERRUPT NDIS_STRING_CONST("IRQ")
+#define MEMMAPPEDBASEADDRESS NDIS_STRING_CONST("RAMADDRESS")
+
+#else // NDIS3
+
+#define IOBASE NDIS_STRING_CONST("IoBaseAddress")
+#define MAXMULTICASTLIST NDIS_STRING_CONST("MaximumMulticastList")
+#define NETADDRESS NDIS_STRING_CONST("NetworkAddress")
+#define INTERRUPT NDIS_STRING_CONST("InterruptNumber")
+#define MEMMAPPEDBASEADDRESS NDIS_STRING_CONST("MemoryMappedBaseAddress")
+
+#endif
diff --git a/private/ntos/ndis/wd/lmi.c b/private/ntos/ndis/wd/lmi.c
new file mode 100644
index 000000000..e41581ef9
--- /dev/null
+++ b/private/ntos/ndis/wd/lmi.c
@@ -0,0 +1,5854 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ lmi.c
+
+Abstract:
+
+ Lower MAC Interface functions for the NDIS 3.0 Western Digital driver.
+
+Author:
+
+ Sean Selitrennikoff (seanse) 15-Jan-92
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+#include <efilter.h>
+#include "wdlmireg.h"
+#include "wdlmi.h"
+#include "wdhrd.h"
+#include "wdsft.h"
+#include "wdumi.h"
+
+extern MAC_BLOCK WdMacBlock;
+
+#if DBG
+
+extern UCHAR WdDebugLog[];
+extern UCHAR WdDebugLogPlace;
+
+UCHAR LmiDebugLogPlace = 0;
+ULONG LmiDebugLog[256] = {0};
+
+#define IF_LOG(A) A
+
+extern
+VOID
+LOG (UCHAR A);
+
+#else
+
+#define IF_LOG(A)
+
+#endif
+
+
+
+#if DBG
+
+#define LMI_LOUD 0x01
+
+UCHAR LmiDebugFlag = 0x00;
+
+#define IF_LMI_LOUD(A) {if (LmiDebugFlag & LMI_LOUD){ A; }}
+
+#else
+
+#define IF_LMI_LOUD(A)
+
+#endif
+
+
+
+
+
+
+VOID
+CardGetBoardId(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN UINT BaseAddr,
+ IN BOOLEAN Mca,
+ OUT PULONG BoardIdMask
+ );
+
+
+VOID
+CardGetBaseInfo(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN UINT BaseAddr,
+ IN BOOLEAN Mca,
+ OUT PULONG BoardIdMask
+ );
+
+
+VOID
+CardGetEepromInfo(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN UINT BaseAddr,
+ IN BOOLEAN Mca,
+ OUT PULONG BoardIdMask
+ );
+
+VOID
+CardGetRamSize(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN UINT BaseAddr,
+ IN BOOLEAN Mca,
+ IN UINT RevNumber,
+ OUT PULONG BoardIdMask
+ );
+
+BOOLEAN
+CardCheckFor690(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN UINT BaseAddr
+ );
+
+UINT
+CardGetConfig(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN UINT BaseAddr,
+ IN BOOLEAN Mca,
+ OUT PCNFG_Adapter Config
+ );
+
+VOID
+CardSendPacket(
+ IN Ptr_Adapter_Struc Adapter
+ );
+
+
+VOID
+CardCopyDown(
+ IN Ptr_Adapter_Struc Adapter,
+ IN PNDIS_PACKET Packet
+ );
+
+BOOLEAN
+SyncGetCurrent(
+ IN PVOID Context
+ );
+
+BOOLEAN
+SyncSetAllMulticast(
+ IN PVOID Context
+ );
+
+BOOLEAN
+SyncClearMulticast(
+ IN PVOID Context
+ );
+
+
+
+#pragma NDIS_INIT_FUNCTION(CardGetBoardId)
+
+VOID
+CardGetBoardId(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN UINT BaseAddr,
+ IN BOOLEAN Mca,
+ OUT PULONG BoardIdMask
+ )
+/*++
+
+Routine Description:
+
+ This routine will determine which WD80xx card is installed and set the
+ BoardIdMask to the feature bits.
+
+Arguments:
+
+ NdisAdapterHandle - Handle returned by Ndis after NdisRegisterAdapter call.
+
+ BaseAddr - The base address for I/O to the board.
+
+ Mca - TRUE if the machine is micro-channel, else the machine is AT.
+
+ BoardIdMask - Returns the feature mask of the installed board.
+
+
+Return:
+
+ none.
+
+--*/
+{
+ UCHAR IdByte;
+ UINT RevNumber;
+
+ //
+ // Init mask.
+ //
+
+ *BoardIdMask = 0;
+
+ //
+ // GetBoardRevNumber(Mca);
+ //
+
+ IF_LMI_LOUD(DbgPrint("Getting BoardId\n"));
+
+
+ NdisReadPortUchar(NdisAdapterHandle,
+ BaseAddr + WD_ID_BYTE,
+ &IdByte
+ );
+
+
+ IF_LMI_LOUD(DbgPrint("Idbyte is 0x%x\n",IdByte));
+
+ RevNumber = IdByte & WD_BOARD_REV_MASK;
+
+ RevNumber >>= 1;
+
+
+ //
+ // Check rev is valid.
+ //
+
+ if (RevNumber == 0) {
+
+ return;
+
+ }
+
+
+
+ //
+ // if (Mca) AddFeatureBits(MCA);
+ //
+
+ if (Mca) {
+
+ *BoardIdMask |= MICROCHANNEL;
+ }
+
+
+
+ //
+ // GetBaseInfo(BaseAddr, Mca, BoardIdMask);
+ //
+
+ CardGetBaseInfo(NdisAdapterHandle, BaseAddr, Mca, BoardIdMask);
+
+
+ IF_LMI_LOUD(DbgPrint("GetBaseInfo: Id is now 0x%x\n",*BoardIdMask));
+
+
+ //
+ // GetMediaType(BaseAddr, Mca, BoardIdMask);
+ //
+
+ if (IdByte & WD_MEDIA_TYPE_BIT) {
+
+ *BoardIdMask |= ETHERNET_MEDIA;
+
+ } else {
+
+ if (RevNumber != 1) {
+
+ *BoardIdMask |= TWISTED_PAIR_MEDIA;
+
+ } else {
+
+ *BoardIdMask |= STARLAN_MEDIA;
+
+ }
+
+ }
+
+ IF_LMI_LOUD(DbgPrint("GetMediaType: Id is now 0x%x\n",*BoardIdMask));
+
+ //
+ // if (RevNumber >= 2) then
+ // GetIdByteInfo(BaseAddr, Mca, RevNumber, BoardIdMask);
+ //
+
+ if (RevNumber >= 2) {
+
+ if (IdByte & WD_BUS_TYPE_BIT) {
+
+ ASSERT(Mca);
+
+ }
+
+ //
+ // For two cards this bit means use alternate IRQ
+ //
+
+ if (IdByte & WD_SOFT_CONFIG_BIT) {
+
+ if (((*BoardIdMask & WD8003EB) == WD8003EB) ||
+ ((*BoardIdMask & WD8003W) == WD8003W)) {
+
+ *BoardIdMask |= ALTERNATE_IRQ_BIT;
+
+ }
+
+ }
+
+ }
+
+
+
+ IF_LMI_LOUD(DbgPrint("Rev > 2: Id is now 0x%x\n",*BoardIdMask));
+
+ //
+ // if (RevNumber >= 3) then
+ // if (!Mca) then
+ // AddFeatureBits(EEPROM_OVERRIDE, 584_CHIP, EXTRA_EEPROM_OVERRIDE);
+ // GetEepromInfo(BaseAddr, Mca, RevNumber, EEPromBoardIdMask);
+ // AddFeatureBits(EEPromBoardIdMask);
+ // else
+ // AddFeatureBits(594_CHIP);
+ // GetRamSize(BaseAddr, Mca, RevNumber, BoardIdMask);
+ // else
+ // GetRamSize(BaseAddr, Mca, RevNumber, BoardIdMask);
+ //
+
+ if (RevNumber >= 3) {
+
+ ULONG EEPromMask;
+
+ if (!Mca) {
+
+ *BoardIdMask &= (WD_584_ID_EEPROM_OVERRIDE |
+ WD_584_EXTRA_EEPROM_OVERRIDE);
+
+ *BoardIdMask |= INTERFACE_584_CHIP;
+
+ CardGetEepromInfo(NdisAdapterHandle, BaseAddr, Mca, &EEPromMask);
+
+ *BoardIdMask |= EEPromMask;
+
+ IF_LMI_LOUD(DbgPrint("GetEEPromInfo: Id is now 0x%x\n",*BoardIdMask));
+
+ } else {
+
+ *BoardIdMask |= INTERFACE_594_CHIP;
+
+ CardGetRamSize(NdisAdapterHandle, BaseAddr, Mca, RevNumber, BoardIdMask);
+
+ IF_LMI_LOUD(DbgPrint("CardGetRamSize: Id is now 0x%x\n",*BoardIdMask));
+
+ }
+
+ } else {
+
+ CardGetRamSize(NdisAdapterHandle, BaseAddr, Mca, RevNumber, BoardIdMask);
+
+ IF_LMI_LOUD(DbgPrint("CardGetRamSize2: Id is now 0x%x\n",*BoardIdMask));
+
+ }
+
+
+ //
+ // if (RevNumber >= 4) then
+ // AddFeatureBits(ADVANCED_FEATURES);
+ //
+
+ if (RevNumber >= 4) {
+
+ *BoardIdMask |= ADVANCED_FEATURES;
+
+ }
+
+ //
+ // if (CheckFor690(BaseAddr)) then
+ // AddFeatureBits(690_CHIP);
+ //
+
+
+ if (CardCheckFor690(NdisAdapterHandle, BaseAddr)) {
+
+ *BoardIdMask |= NIC_690_BIT;
+
+ }
+
+ IF_LMI_LOUD(DbgPrint("CheckFor690: Id is now 0x%x\n",*BoardIdMask));
+
+}
+
+
+
+#pragma NDIS_INIT_FUNCTION(CardGetBaseInfo)
+
+VOID
+CardGetBaseInfo(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN UINT BaseAddr,
+ IN BOOLEAN Mca,
+ OUT PULONG BoardIdMask
+ )
+/*++
+
+Routine Description:
+
+ This routine will get the following information about the card:
+ Is there an interface chip,
+ Are some registers aliased,
+ Is the board 16 bit,
+ Is the board in a 16 bit slot.
+
+
+
+Arguments:
+
+ NdisAdapterHandle - Handle returned by Ndis after NdisRegisterAdapter call.
+
+ BaseAddr - The base address for I/O to the board.
+
+ Mca - TRUE if the machine is micro-channel, else the machine is AT.
+
+ BoardIdMask - Returns the feature mask of the installed board.
+
+
+Return:
+
+ none.
+
+--*/
+{
+ UCHAR RegValue;
+ UCHAR SaveValue;
+ UCHAR TmpValue;
+ ULONG Register;
+
+ BOOLEAN ExistsAnInterfaceChip = FALSE;
+
+ //
+ // Does there exist and interface chip?
+ //
+ //
+ // Get original value
+ //
+
+ NdisReadPortUchar(NdisAdapterHandle, BaseAddr + WD_REG_7, &SaveValue);
+
+ //
+ // Put something into chip (if it exists).
+ //
+
+ NdisWritePortUchar(NdisAdapterHandle, BaseAddr + WD_REG_7, 0x35);
+
+ //
+ // Swamp bus with something else.
+ //
+
+ NdisReadPortUchar(NdisAdapterHandle, BaseAddr, &RegValue);
+
+ //
+ // Read from chip
+ //
+
+ NdisReadPortUchar(NdisAdapterHandle, BaseAddr + WD_REG_7, &RegValue);
+
+ //
+ // Was the value saved on the chip??
+ //
+
+ if (RegValue == 0x35) {
+
+ //
+ // Try it again just for kicks.
+ //
+
+ NdisWritePortUchar(NdisAdapterHandle, BaseAddr + WD_REG_7, 0x3A);
+
+ //
+ // Swamp bus with something else.
+ //
+
+ NdisReadPortUchar(NdisAdapterHandle, BaseAddr, &RegValue);
+
+ //
+ // Read from chip
+ //
+
+ NdisReadPortUchar(NdisAdapterHandle, BaseAddr + WD_REG_7, &RegValue);
+
+ //
+ // Was the value saved on the chip??
+ //
+
+ if (RegValue == 0x3A) {
+
+ ExistsAnInterfaceChip = TRUE;
+
+ }
+
+ }
+
+ //
+ // Write back original value.
+ //
+
+ NdisWritePortUchar(NdisAdapterHandle, BaseAddr + WD_REG_7, SaveValue);
+
+
+
+
+
+
+ //
+ // if (Mca) then
+ //
+ // if (ExistsAnInterfaceChip) then
+ //
+ // AddFeatureBits(INTERFACE_CHIP)
+ //
+ // return;
+ //
+
+ if (Mca) {
+
+ if (ExistsAnInterfaceChip) {
+
+ *BoardIdMask |= INTERFACE_CHIP;
+
+ }
+
+ return;
+
+ }
+
+
+
+
+ //
+ //
+ // if (BoardUsesAliasing(BaseAddr)) then
+ //
+ // return;
+ //
+
+
+ for (Register = WD_REG_1; Register < WD_REG_6; Register++) {
+
+ NdisReadPortUchar(NdisAdapterHandle, BaseAddr + Register, &RegValue);
+
+ NdisReadPortUchar(NdisAdapterHandle, BaseAddr + Register + WD_LAN_OFFSET, &SaveValue);
+
+ if (RegValue != SaveValue) {
+
+ break;
+
+ }
+
+ }
+
+ if (Register == WD_REG_6) {
+
+ //
+ // Check register 7
+ //
+
+ NdisReadPortUchar(NdisAdapterHandle, BaseAddr + Register, &RegValue);
+
+ NdisReadPortUchar(NdisAdapterHandle, BaseAddr + Register + WD_LAN_OFFSET, &SaveValue);
+
+ }
+
+ if (RegValue == SaveValue) {
+
+ return;
+
+ }
+
+
+
+
+ //
+ //
+ // if (ExistsAnInterfaceChip) then
+ //
+ // AddFeatureBits(INTERFACE_CHIP);
+ //
+ // else
+ //
+ // if (BoardIs16Bit(BaseAddr)) then
+ //
+ // AddFeatureBits(BOARD_16BIT);
+ //
+ // if (InA16BitSlot(BaseAddr)) then
+ //
+ // AddFeatureBits(SLOT_16BIT);
+ //
+ //
+ //
+ //
+
+
+ if (ExistsAnInterfaceChip) {
+
+ *BoardIdMask |= INTERFACE_CHIP;
+
+ } else {
+
+ //
+ // Save original value.
+ //
+
+ NdisReadPortUchar(NdisAdapterHandle, BaseAddr + WD_REG_1, &SaveValue);
+
+ //
+ // Now flip 16 bit value and write it back.
+ //
+
+ RegValue = (SaveValue & (UCHAR)WD_SIXTEEN_BIT);
+
+ NdisWritePortUchar(NdisAdapterHandle,
+ BaseAddr + WD_REG_1,
+ (UCHAR)(SaveValue ^ WD_SIXTEEN_BIT));
+
+ //
+ // Swamp bus with something else.
+ //
+
+ NdisReadPortUchar(NdisAdapterHandle, BaseAddr, &TmpValue);
+
+ //
+ // Read back value.
+ //
+
+ NdisReadPortUchar(NdisAdapterHandle, BaseAddr + WD_REG_1, &TmpValue);
+
+ if ((TmpValue & (UCHAR)WD_SIXTEEN_BIT) == RegValue) {
+
+ //
+ // If the flip stayed, we have a 16 bit chip.
+ //
+
+ //
+ // Put back orginal value.
+ //
+
+ NdisWritePortUchar(NdisAdapterHandle,
+ BaseAddr + WD_REG_1,
+ (UCHAR)(SaveValue & 0xFE)
+ );
+
+
+ *BoardIdMask |= BOARD_16BIT;
+
+
+
+ //
+ // Now check if it is a 16 bit slot....
+ //
+
+
+ NdisReadPortUchar(NdisAdapterHandle,
+ BaseAddr + WD_REG_1,
+ &RegValue
+ );
+
+ if (RegValue & WD_SIXTEEN_BIT) {
+
+ *BoardIdMask |= SLOT_16BIT;
+
+ }
+
+ } else {
+
+ //
+ // Put back original value.
+ //
+
+ NdisWritePortUchar(NdisAdapterHandle,
+ BaseAddr + WD_REG_1,
+ SaveValue
+ );
+ }
+
+ }
+
+}
+
+
+
+#pragma NDIS_INIT_FUNCTION(CardGetEepromInfo)
+
+VOID
+CardGetEepromInfo(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN UINT BaseAddr,
+ IN BOOLEAN Mca,
+ OUT PULONG BoardIdMask
+ )
+/*++
+
+Routine Description:
+
+ This routine will get the following information about the card:
+ Bus type,
+ Bus size,
+ Media type,
+ IRQ - primary or alternate,
+ RAM size
+
+
+ In this case All other information in the top 16 bits of the BoardIdMask
+ are zeroed and replaced with these values since EEProm values are
+ overriding old values.
+
+
+
+Arguments:
+
+ NdisAdapterHandle - Handle returned by Ndis after NdisRegisterAdapter call.
+
+ BaseAddr - The base address for I/O to the board.
+
+ Mca - TRUE if the machine is micro-channel, else the machine is AT.
+
+ BoardIdMask - Returns the feature mask of the installed board.
+
+
+Return:
+
+ none.
+
+--*/
+{
+ UCHAR RegValue;
+
+
+ //
+ // *BoardIdMask = 0;
+ //
+
+ *BoardIdMask = 0;
+
+ //
+ // RecallEEPromData(NdisAdapterHandle, BaseAddr, Mca);
+ //
+
+ IF_LMI_LOUD(DbgPrint("Recalling EEPromData\n"));
+
+ NdisReadPortUchar(NdisAdapterHandle, BaseAddr + WD_REG_1, &RegValue);
+
+ RegValue &= WD_584_ICR_MASK;
+
+ RegValue |= WD_584_OTHER_BIT;
+
+ NdisWritePortUchar(NdisAdapterHandle, BaseAddr + WD_REG_1, RegValue);
+
+
+ NdisReadPortUchar(NdisAdapterHandle, BaseAddr + WD_REG_3, &RegValue);
+
+ RegValue &= WD_584_EAR_MASK;
+
+ RegValue |= WD_584_ENGR_PAGE;
+
+ NdisWritePortUchar(NdisAdapterHandle, BaseAddr + WD_REG_3, RegValue);
+
+
+ NdisReadPortUchar(NdisAdapterHandle, BaseAddr + WD_REG_1, &RegValue);
+
+ RegValue &= WD_584_ICR_MASK;
+
+ RegValue |= (WD_584_RLA | WD_584_OTHER_BIT);
+
+ NdisWritePortUchar(NdisAdapterHandle, BaseAddr + WD_REG_1, RegValue);
+
+
+ NdisReadPortUchar(NdisAdapterHandle, BaseAddr + WD_REG_1, &RegValue);
+
+ while (RegValue & WD_584_RECALL_DONE) {
+
+ NdisReadPortUchar(NdisAdapterHandle, BaseAddr + WD_REG_1, &RegValue);
+
+ }
+
+
+
+ //
+ // if (Mca) then AddFeatureBits(MICROCHANNEL);
+ //
+
+ if (Mca) {
+
+ *BoardIdMask |= MICROCHANNEL;
+
+ }
+
+
+ NdisReadPortUchar(NdisAdapterHandle, BaseAddr + WD_584_EEPROM_1, &RegValue);
+
+ IF_LMI_LOUD(DbgPrint("RegValue is 0x%x\n",RegValue));
+
+
+ //
+ // if (RamPaging) then
+ //
+ // AddFeatureBits(PAGED_RAM);
+ //
+
+ if ((RegValue & WD_584_EEPROM_PAGING_MASK) == WD_584_EEPROM_RAM_PAGING) {
+
+ *BoardIdMask |= PAGED_RAM;
+
+ }
+
+
+ //
+ // if (RomPaging) then
+ //
+ // AddFeatureBits(PAGED_ROM);
+ //
+
+ if ((RegValue & WD_584_EEPROM_PAGING_MASK) == WD_584_EEPROM_ROM_PAGING) {
+
+ *BoardIdMask |= PAGED_ROM;
+
+ }
+
+
+
+
+
+ //
+ // if (16BitBus) then
+ //
+ // AddFeatureBits(BOARD_16BIT);
+ //
+ // if (16BitSlot) then
+ //
+ // AddFeatureBits(SLOT_16BIT);
+ //
+
+ if ((RegValue & WD_584_EEPROM_BUS_SIZE_MASK) == WD_584_EEPROM_BUS_SIZE_16BIT) {
+
+ *BoardIdMask |= BOARD_16BIT;
+
+
+ //
+ // Now check if it is a 16 bit slot....
+ //
+
+
+ NdisReadPortUchar(NdisAdapterHandle,
+ BaseAddr + WD_REG_1,
+ &RegValue
+ );
+
+ IF_LMI_LOUD(DbgPrint("RegValue is 0x%x\n",RegValue));
+
+ if (RegValue & WD_SIXTEEN_BIT) {
+
+ *BoardIdMask |= SLOT_16BIT;
+
+ }
+
+ }
+
+
+ IF_LMI_LOUD(DbgPrint("16 Bit : Id is now 0x%x\n",*BoardIdMask));
+
+ //
+ // if (StarLanMedia) then
+ //
+ // AddFeatureBits(STARLAN_MEDIA);
+ //
+ // else
+ //
+ // if (TpMedia) then
+ //
+ // AddFeatureBits(TWISTED_PAIR_MEDIA);
+ //
+ // else
+ //
+ // if (EwMedia) then
+ //
+ // AddFeatureBits(EW_MEDIA);
+ //
+ // else
+ //
+ // AddFeatureBits(ETHERNET_MEDIA);
+ //
+ //
+
+ NdisReadPortUchar(NdisAdapterHandle, BaseAddr + WD_584_EEPROM_0, &RegValue);
+
+ IF_LMI_LOUD(DbgPrint("RegValue is 0x%x\n",RegValue));
+
+ if ((RegValue & WD_584_EEPROM_MEDIA_MASK) == WD_584_STARLAN_TYPE) {
+
+ *BoardIdMask |= STARLAN_MEDIA;
+
+ } else if ((RegValue & WD_584_EEPROM_MEDIA_MASK) == WD_584_TP_TYPE) {
+
+ *BoardIdMask |= TWISTED_PAIR_MEDIA;
+
+ } else if ((RegValue & WD_584_EEPROM_MEDIA_MASK) == WD_584_EW_TYPE) {
+
+ *BoardIdMask |= EW_MEDIA;
+
+ } else {
+
+ *BoardIdMask |= ETHERNET_MEDIA;
+
+ }
+
+
+ IF_LMI_LOUD(DbgPrint("MediaType: Id is now 0x%x\n",*BoardIdMask));
+
+
+ //
+ // if (AlternateIrq) then AddFeatureBits(ALTERNATE_IRQ_BIT);
+ //
+
+ if ((RegValue & WD_584_EEPROM_IRQ_MASK) != WD_584_PRIMARY_IRQ) {
+
+ *BoardIdMask |= ALTERNATE_IRQ_BIT;
+
+ }
+
+
+
+ IF_LMI_LOUD(DbgPrint("AltIrq: Id is now 0x%x\n",*BoardIdMask));
+
+ //
+ // GetRamSize(BaseAddr + EEPROM_1);
+ //
+ //
+
+
+ if ((RegValue & WD_584_EEPROM_RAM_SIZE_MASK) == WD_584_EEPROM_RAM_SIZE_8K) {
+
+ *BoardIdMask |= RAM_SIZE_8K;
+
+ } else {
+
+ if ((RegValue & WD_584_EEPROM_RAM_SIZE_MASK) == WD_584_EEPROM_RAM_SIZE_16K) {
+
+ if (!(*BoardIdMask & BOARD_16BIT)) {
+
+ *BoardIdMask |= RAM_SIZE_16K;
+
+ } else if (!(*BoardIdMask & SLOT_16BIT)) {
+
+ *BoardIdMask |= RAM_SIZE_8K;
+
+ } else {
+
+ *BoardIdMask |= RAM_SIZE_16K;
+
+ }
+
+ } else {
+
+ if ((RegValue & WD_584_EEPROM_RAM_SIZE_MASK) ==
+ WD_584_EEPROM_RAM_SIZE_32K) {
+
+ *BoardIdMask |= RAM_SIZE_32K;
+
+ } else {
+
+ if ((RegValue & WD_584_EEPROM_RAM_SIZE_MASK) ==
+ WD_584_EEPROM_RAM_SIZE_64K) {
+
+ if (!(*BoardIdMask & BOARD_16BIT)) {
+
+ *BoardIdMask |= RAM_SIZE_64K;
+
+ } else {
+
+ if (!(*BoardIdMask & SLOT_16BIT)) {
+
+ *BoardIdMask |= RAM_SIZE_32K;
+
+ } else {
+
+ *BoardIdMask |= RAM_SIZE_64K;
+
+ }
+
+ }
+
+ } else {
+
+ *BoardIdMask |= RAM_SIZE_UNKNOWN;
+
+ }
+
+ }
+
+ }
+
+ }
+
+
+ IF_LMI_LOUD(DbgPrint("RamSize: Id is now 0x%x\n",*BoardIdMask));
+
+ //
+ // RecallLanAddressFromEEProm(NdisAdapterHandle, BaseAddr);
+ //
+
+
+
+ NdisReadPortUchar(NdisAdapterHandle, BaseAddr + WD_REG_1, &RegValue);
+
+ RegValue &= WD_584_ICR_MASK;
+
+ RegValue |= WD_584_OTHER_BIT;
+
+ NdisWritePortUchar(NdisAdapterHandle, BaseAddr + WD_REG_1, RegValue);
+
+
+ NdisReadPortUchar(NdisAdapterHandle, BaseAddr + WD_REG_3, &RegValue);
+
+ RegValue &= WD_584_EAR_MASK;
+
+ RegValue |= WD_584_EA6;
+
+ NdisWritePortUchar(NdisAdapterHandle, BaseAddr + WD_REG_3, RegValue);
+
+
+ NdisReadPortUchar(NdisAdapterHandle, BaseAddr + WD_REG_1, &RegValue);
+
+ RegValue &= WD_584_ICR_MASK;
+
+ RegValue |= WD_584_RLA;
+
+ NdisWritePortUchar(NdisAdapterHandle, BaseAddr + WD_REG_1, RegValue);
+
+ NdisReadPortUchar(NdisAdapterHandle, BaseAddr + WD_REG_1, &RegValue);
+
+ while (RegValue & WD_584_RECALL_DONE) {
+
+ NdisReadPortUchar(NdisAdapterHandle, BaseAddr + WD_REG_1, &RegValue);
+
+ }
+
+ IF_LMI_LOUD(DbgPrint("Exiting GetEEPromInfo: Id is now 0x%x\n",*BoardIdMask));
+
+}
+
+
+#pragma NDIS_INIT_FUNCTION(CardGetRamSize)
+
+VOID
+CardGetRamSize(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN UINT BaseAddr,
+ IN BOOLEAN Mca,
+ IN UINT RevNumber,
+ OUT PULONG BoardIdMask
+ )
+/*++
+
+Routine Description:
+
+ This routine will get the following information about the card:
+ Ram size.
+
+ The card must be either Mca and have a RevNumber > 2, or any kind of
+ bus and a RevNumber < 3 for this routine to work.
+
+Arguments:
+
+ NdisAdapterHandle - Handle returned by Ndis after NdisRegisterAdapter call.
+
+ BaseAddr - The base address for I/O to the board.
+
+ Mca - TRUE if the machine is micro-channel, else the machine is AT.
+
+ RevNumber - The reversion number of the board.
+
+ BoardIdMask - Returns the feature mask of the installed board.
+
+
+Return:
+
+ none.
+
+--*/
+{
+ UCHAR RegValue;
+
+ //
+ // if (RevNumber < 2) then
+ //
+ // if (Mca) then
+ //
+ // AddFeatureBits(RAM_SIZE_16K);
+ //
+ // else
+ //
+ // if (16BitBus) then
+ //
+ // if (16BitSlot) then
+ //
+ // AddFeatureBits(RAM_SIZE_16K);
+ //
+ // else
+ //
+ // AddFeatureBits(RAM_SIZE_8K);
+ //
+ // else
+ //
+ // if (!HaveInterfaceChip) then
+ //
+ // AddFeatureBits(RAM_SIZE_UNKNOWN);
+ //
+ // else
+ //
+ // ReadFromChipRamSize();
+ // else
+ //
+ // switch (CardType)
+ //
+ // case WD8003E:
+ // case WD8003S:
+ // case WD8003WT:
+ // case WD8003W:
+ // case WD8003EB:
+ //
+ // if (CardSaysLargeRam) then
+ //
+ // AddFeatureBits(RAM_SIZE_32K);
+ //
+ // else
+ //
+ // AddFeatureBits(RAM_SIZE_8K);
+ //
+ // break;
+ //
+ // case MICROCHANNEL:
+ //
+ // if (CardSaysLargeRam) then
+ //
+ // AddFeatureBits(RAM_SIZE_64K);
+ //
+ // else
+ //
+ // AddFeatureBits(RAM_SIZE_16K);
+ //
+ // break;
+ //
+ // case WD8013EBT:
+ //
+ // if (16BitSlot) then
+ //
+ //
+ // if (CardSaysLargeRam) then
+ //
+ // AddFeatureBits(RAM_SIZE_64K);
+ //
+ // else
+ //
+ // AddFeatureBits(RAM_SIZE_16K);
+ //
+ // else
+ //
+ // if (CardSaysLargeRam) then
+ //
+ // AddFeatureBits(RAM_SIZE_32K);
+ //
+ // else
+ //
+ // AddFeatureBits(RAM_SIZE_8K);
+ //
+ // break;
+ //
+ // default:
+ //
+ // AddFeatureBits(RAM_SIZE_UNKNOWN);
+ //
+
+
+
+
+
+ if (RevNumber < 2) {
+
+ if (Mca) {
+
+ *BoardIdMask |= RAM_SIZE_16K;
+
+ } else {
+
+ if (*BoardIdMask & BOARD_16BIT) {
+
+ if (*BoardIdMask & SLOT_16BIT) {
+
+ *BoardIdMask |= RAM_SIZE_16K;
+
+ } else {
+
+ *BoardIdMask |= RAM_SIZE_8K;
+
+ }
+
+ } else {
+
+ if (!(*BoardIdMask & INTERFACE_CHIP)) {
+
+ *BoardIdMask |= RAM_SIZE_8K;
+
+ } else {
+
+ NdisReadPortUchar(NdisAdapterHandle,
+ BaseAddr + WD_REG_1,
+ &RegValue
+ );
+
+ if (RegValue & WD_MSB_583_BIT) {
+
+ *BoardIdMask |= RAM_SIZE_32K;
+
+ } else {
+
+ *BoardIdMask |= RAM_SIZE_8K;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ } else {
+
+
+ NdisReadPortUchar(NdisAdapterHandle,
+ BaseAddr + WD_ID_BYTE,
+ &RegValue
+ );
+
+ if (*BoardIdMask & MICROCHANNEL) {
+
+ if (RegValue & WD_RAM_SIZE_BIT) {
+
+ *BoardIdMask |= RAM_SIZE_64K;
+
+ } else {
+
+ *BoardIdMask |= RAM_SIZE_16K;
+
+ }
+
+ } else {
+
+ switch (*BoardIdMask & STATIC_ID_MASK) {
+
+ case WD8003E:
+ case WD8003S:
+ case WD8003WT:
+ case WD8003W:
+ case WD8003EB:
+
+ if (RegValue & WD_RAM_SIZE_BIT) {
+
+ *BoardIdMask |= RAM_SIZE_32K;
+
+ } else {
+
+ *BoardIdMask |= RAM_SIZE_8K;
+
+ }
+
+ break;
+
+ case WD8013EBT:
+
+ if (*BoardIdMask & SLOT_16BIT) {
+
+ if (RegValue & WD_RAM_SIZE_BIT) {
+
+ *BoardIdMask |= RAM_SIZE_64K;
+
+ } else {
+
+ *BoardIdMask |= RAM_SIZE_16K;
+
+ }
+
+ } else {
+
+ if (RegValue & WD_RAM_SIZE_BIT) {
+
+ *BoardIdMask |= RAM_SIZE_32K;
+
+ } else {
+
+ *BoardIdMask |= RAM_SIZE_8K;
+
+ }
+ }
+
+ break;
+
+ default:
+
+ *BoardIdMask |= RAM_SIZE_UNKNOWN;
+
+ }
+
+ }
+
+ }
+
+}
+
+
+#pragma NDIS_INIT_FUNCTION(CardCheckFor690)
+
+BOOLEAN
+CardCheckFor690(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN UINT BaseAddr
+ )
+/*++
+
+Routine Description:
+
+ This routine will determine if there the card has a 690 chip or the
+ older 8390 chips.
+
+Arguments:
+
+ NdisAdapterHandle - Handle returned by Ndis after NdisRegisterAdapter call.
+
+ BaseAddr - The base address for I/O to the board.
+
+
+Return:
+
+ TRUE if there is a 690, else FALSE (it is 8390 chip).
+
+--*/
+
+{
+
+ //
+ // Old register values.
+ //
+
+ UCHAR NICSave;
+ UCHAR TCRSave;
+
+
+ UCHAR TCRValue;
+
+
+ //
+ // NICSave = GetCurrentRegisterValue(NICRegister);
+ //
+
+ NdisReadPortUchar(NdisAdapterHandle, BaseAddr + WD_690_CR, &NICSave);
+
+ NICSave = NICSave & (UCHAR)(~(UCHAR)WD_690_TXP);
+
+
+ //
+ // SwitchToPage2();
+ //
+
+
+ NdisWritePortUchar(NdisAdapterHandle,
+ BaseAddr + WD_690_CR,
+ (UCHAR)((NICSave & WD_690_PSMASK) | WD_690_PS2)
+ );
+
+
+ //
+ // TCRSave = GetCurrentRegisterValue(TCRRegister);
+ //
+
+ NdisReadPortUchar(NdisAdapterHandle,
+ BaseAddr + WD_690_CR + WD_690_TCR,
+ &TCRSave
+ );
+
+
+ //
+ // SwitchToPage0();
+ //
+
+ NdisWritePortUchar(NdisAdapterHandle,
+ BaseAddr + WD_690_CR,
+ (UCHAR)((NICSave & WD_690_PSMASK) | WD_690_PS0)
+ );
+
+
+ //
+ // WriteRegister(TCRRegister, TestValue);
+ //
+
+ NdisWritePortUchar(NdisAdapterHandle,
+ BaseAddr + WD_690_CR + WD_690_TCR,
+ WD_690_TCR_TEST_VAL
+ );
+
+
+ //
+ // SwitchToPage2();
+ //
+
+ NdisWritePortUchar(NdisAdapterHandle,
+ BaseAddr + WD_690_CR,
+ (UCHAR)((NICSave & WD_690_PSMASK) | WD_690_PS2)
+ );
+
+ //
+ // TCRValue = GetCurrentRegisterValue(TCRRegister);
+ //
+
+ NdisReadPortUchar(NdisAdapterHandle,
+ BaseAddr + WD_690_CR + WD_690_TCR,
+ &TCRValue
+ );
+
+
+ //
+ // SwitchToPage0();
+ //
+
+ NdisWritePortUchar(NdisAdapterHandle,
+ BaseAddr + WD_690_CR,
+ (UCHAR)((NICSave & WD_690_PSMASK) | WD_690_PS0)
+ );
+
+ //
+ // WriteRegister(TCRRegister, TCRSave);
+ //
+
+ NdisWritePortUchar(NdisAdapterHandle,
+ BaseAddr + WD_690_CR + WD_690_TCR,
+ TCRSave
+ );
+
+ //
+ // WriteRegister(NICRegister, NICSave);
+ //
+
+ NdisWritePortUchar(NdisAdapterHandle,
+ BaseAddr + WD_690_CR,
+ NICSave
+ );
+
+ return((TCRValue & WD_690_TCR_TEST_VAL) != (UCHAR)WD_690_TCR_TEST_VAL);
+
+}
+
+
+
+#pragma NDIS_INIT_FUNCTION(CardGetConfig)
+
+UINT
+CardGetConfig(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN UINT BaseAddr,
+ IN BOOLEAN Mca,
+ OUT PCNFG_Adapter Config
+ )
+/*++
+
+Routine Description:
+
+ This routine will get the configuration information about the card.
+
+
+Arguments:
+
+ NdisAdapterHandle - Handle returned by Ndis after NdisRegisterAdapter call.
+
+ BaseAddr - The base address for I/O to the board.
+
+ Mca - TRUE if the machine is micro-channel, else the machine is AT.
+
+ Config - a structure with the configuration info.
+
+
+Return:
+
+ 0, if found board and configuration information retrieved.
+ 1, if found board and no configuration.
+ -1, if board not found.
+
+--*/
+{
+ UCHAR RegValue1, RegValue2;
+ USHORT RegValue;
+
+ UNREFERENCED_PARAMETER(BaseAddr);
+
+ if (Mca) {
+
+ //
+ // Get McaConfig
+ //
+
+
+
+ Config->cnfg_bus = 1;
+
+ //
+ // if (594Group()) then
+ //
+ // ReturnValue = Get594ConfigInfo();
+ //
+ // else if (593Group()) then
+ //
+ // ReturnValue = Get593ConfigInfo();
+ //
+ // else
+ //
+ // return(-1);
+ //
+
+ RegValue = Config->PosData.AdapterId;
+
+ Config->cnfg_pos_id = RegValue;
+
+ switch (RegValue) {
+
+ case CNFG_ID_8003E:
+ case CNFG_ID_8003S:
+ case CNFG_ID_8003W:
+ case CNFG_ID_BISTRO03E:
+
+ Config->cnfg_bic_type = BIC_593_CHIP;
+
+ //
+ // Get593Io();
+ //
+
+ RegValue1 = Config->PosData.PosData1;
+
+ RegValue1 &= 0xFE;
+
+ Config->cnfg_base_io = (USHORT)(RegValue1 << 4);
+
+
+
+ //
+ // Get593Irq();
+ //
+
+ RegValue1 = Config->PosData.PosData4;
+
+ RegValue1 &= 0x3;
+
+ if (RegValue1 == 0) {
+
+ Config->cnfg_irq_line = 3;
+
+ } else if (RegValue1 == 1) {
+
+ Config->cnfg_irq_line = 4;
+
+ } else if (RegValue1 == 2) {
+
+ Config->cnfg_irq_line = 10;
+
+ } else {
+
+ Config->cnfg_irq_line = 15;
+
+ }
+
+
+
+ //
+ // Get593RamBase();
+ //
+
+ RegValue1 = Config->PosData.PosData2;
+
+ RegValue1 = (RegValue1 & (UCHAR)0xFC);
+
+ Config->cnfg_ram_base = (ULONG)RegValue1 << 12;
+
+
+
+ //
+ // Get593RamSize();
+ //
+
+ Config->cnfg_ram_size = CNFG_SIZE_16KB;
+ Config->cnfg_ram_usable = CNFG_SIZE_16KB;
+
+
+
+ //
+ // Get593RomBase();
+ //
+
+ RegValue1 = Config->PosData.PosData3;
+
+ RegValue1 = (RegValue1 & (UCHAR)0xFC);
+
+ Config->cnfg_rom_base = (ULONG)RegValue1 << 12;
+
+
+ //
+ // Get593RomSize();
+ //
+
+ RegValue1 = Config->PosData.PosData3;
+
+ RegValue1 &= 0x03;
+
+ if (RegValue1 == 0) {
+
+ Config->cnfg_rom_size = CNFG_SIZE_16KB;
+
+ } else if (RegValue1 == 1) {
+
+ Config->cnfg_rom_size = CNFG_SIZE_32KB;
+
+ } else if (RegValue1 == 2) {
+
+ Config->cnfg_rom_size = ROM_DISABLE;
+
+ } else {
+
+ Config->cnfg_rom_size = CNFG_SIZE_64KB;
+
+ }
+
+
+ break;
+
+ case CNFG_ID_8013E:
+ case CNFG_ID_8013W:
+ case CNFG_ID_8115TRA:
+ case CNFG_ID_BISTRO13E:
+ case CNFG_ID_BISTRO13W:
+
+
+ Config->cnfg_bic_type = BIC_594_CHIP;
+
+ //
+ // Get594Io();
+ //
+
+ RegValue1 = Config->PosData.PosData1;
+
+ RegValue1 &= 0xF0;
+
+ Config->cnfg_base_io = ((USHORT)RegValue1 << 8) | (USHORT)0x800;
+
+
+
+ //
+ // Get594Irq();
+ //
+
+ RegValue1 = Config->PosData.PosData4;
+
+ RegValue1 &= 0xC;
+
+ if (RegValue1 == 0) {
+
+ Config->cnfg_irq_line = 3;
+
+ } else if (RegValue1 == 0x4) {
+
+ Config->cnfg_irq_line = 4;
+
+ } else if (RegValue1 == 0x8) {
+
+ Config->cnfg_irq_line = 10;
+
+ } else {
+
+ Config->cnfg_irq_line = 14;
+
+ }
+
+
+
+ //
+ // Get594RamBase();
+ //
+
+ RegValue1 = Config->PosData.PosData2;
+
+ if (RegValue1 & 0x8) { // Above cseg
+
+ if (RegValue1 & 0x80) { // above 1 meg
+
+ Config->cnfg_ram_base = ((ULONG)(RegValue1 & 0x7) << 13)
+ + 0xFD0000;
+
+ } else {
+
+ Config->cnfg_ram_base = ((ULONG)(RegValue1 & 0x7) << 13)
+ + 0x0D0000;
+
+
+ }
+
+ } else {
+
+ if (RegValue1 & 0x80) { // above 1 meg
+
+ Config->cnfg_ram_base = ((ULONG)(RegValue1 & 0x7) << 13)
+ + 0xFC0000;
+
+ } else {
+
+ Config->cnfg_ram_base = ((ULONG)(RegValue1 & 0x7) << 13)
+ + 0x0C0000;
+
+
+ }
+
+ }
+
+
+ //
+ // Get594RamSize();
+ //
+
+ RegValue1 &= 0x30;
+
+ RegValue1 >>= 4;
+
+ Config->cnfg_ram_usable = (USHORT)CNFG_SIZE_8KB << RegValue1;
+
+
+ if (RegValue == CNFG_ID_8115TRA) {
+
+ Config->cnfg_ram_size = (USHORT)CNFG_SIZE_64KB;
+
+ } else {
+
+ Config->cnfg_ram_size = Config->cnfg_ram_usable;
+
+ }
+
+
+
+
+ //
+ // Get594RomBase();
+ //
+
+ RegValue1 = Config->PosData.PosData3;
+
+ if (RegValue1 & 0x8) { // Above cseg
+
+ Config->cnfg_rom_base = ((ULONG)(RegValue1 & 0x7) << 13)
+ + 0xD0000;
+
+ } else {
+
+ Config->cnfg_rom_base = ((ULONG)(RegValue1 & 0x7) << 13)
+ + 0x0C0000;
+
+ }
+
+
+
+
+ //
+ // Get594RomSize();
+ //
+
+ RegValue1 >>= 4;
+
+ if (RegValue1 == 0) {
+
+ Config->cnfg_rom_size = CNFG_SIZE_8KB;
+
+ } else if (RegValue1 == 1) {
+
+ Config->cnfg_rom_size = CNFG_SIZE_16KB;
+
+ } else if (RegValue1 == 2) {
+
+ Config->cnfg_rom_size = CNFG_SIZE_32KB;
+
+ } else {
+
+ Config->cnfg_rom_size = ROM_DISABLE;
+
+ }
+
+
+
+
+ //
+ // Get594MediaType();
+ //
+
+ RegValue1 = Config->PosData.PosData4;
+
+ RegValue1 &= CNFG_MEDIA_TYPE_MASK;
+
+ Config->cnfg_media_type = RegValue1;
+
+ break;
+
+ default:
+
+ return((UINT)-1);
+
+ }
+
+ //
+ // GetBoardId();
+ //
+
+ CardGetBoardId(NdisAdapterHandle,
+ Config->cnfg_base_io,
+ Mca,
+ &(Config->cnfg_bid));
+
+ return(0);
+
+ } else {
+
+ //
+ // Get AtConfig
+ //
+
+ Config->cnfg_bus = 0;
+
+ //
+ // if (!BoardIsThere()) then
+ //
+ // return(-1);
+ //
+
+ RegValue2 = 0;
+
+ for (RegValue = 0; RegValue < 8; RegValue++) {
+
+ NdisReadPortUchar(NdisAdapterHandle,
+ Config->cnfg_base_io + 0x8 + RegValue,
+ &RegValue1
+ );
+
+ IF_LMI_LOUD(DbgPrint("First number is 0x%x\n", RegValue1));
+
+ RegValue2 += RegValue1;
+
+ }
+
+ if (RegValue2 != 0xFF) {
+
+ IF_LMI_LOUD(DbgPrint("The sum was 0x%x\n", RegValue2));
+
+ return((UINT)-1);
+
+ }
+
+
+
+ //
+ // GetBoardId();
+ //
+
+ CardGetBoardId(NdisAdapterHandle,
+ Config->cnfg_base_io,
+ Mca,
+ &(Config->cnfg_bid));
+
+
+ IF_LMI_LOUD(DbgPrint("Got Board Id. Mask is 0x%x\n", Config->cnfg_bid));
+
+ //
+ // CopyRamSize();
+ //
+
+ if (((Config->cnfg_bid & RAM_SIZE_MASK) != RAM_SIZE_8K) &&
+ ((Config->cnfg_bid & RAM_SIZE_MASK) != RAM_SIZE_64K)) {
+
+ IF_LMI_LOUD(DbgPrint("here\n"));
+
+ Config->cnfg_ram_size = (USHORT)CNFG_SIZE_8KB <<
+ (((Config->cnfg_bid & (ULONG)RAM_SIZE_MASK) >> 16) - 2);
+
+ if (Config->cnfg_bid & PAGED_RAM) {
+
+ Config->cnfg_ram_usable = CNFG_SIZE_16KB;
+
+ } else {
+
+ Config->cnfg_ram_usable = Config->cnfg_ram_size;
+
+ }
+
+ } else {
+
+ Config->cnfg_ram_usable = Config->cnfg_ram_size;
+
+ }
+
+ //
+ // if (ThereIsAnInterfaceChip) then
+ //
+ // GetChipConfigInfo();
+ // return(0);
+ //
+ // else
+ //
+ // VerifyLanAddrIsWd();
+ // return(1);
+ //
+
+
+ if (!(Config->cnfg_bid & INTERFACE_CHIP)) {
+
+ Config->cnfg_bic_type = BIC_NO_CHIP;
+
+ NdisReadPortUchar(NdisAdapterHandle,
+ Config->cnfg_base_io + 0x8,
+ &RegValue1
+ );
+
+ if (RegValue1 != 0x00) {
+
+ return((UINT)-1);
+
+ }
+
+ NdisReadPortUchar(NdisAdapterHandle,
+ Config->cnfg_base_io + 0x9,
+ &RegValue1
+ );
+
+ if (RegValue1 != 0x00) {
+
+ return((UINT)-1);
+
+ }
+
+ NdisReadPortUchar(NdisAdapterHandle,
+ Config->cnfg_base_io + 0xA,
+ &RegValue1
+ );
+
+ if (RegValue1 != 0xC0) {
+
+ return((UINT)-1);
+
+ }
+
+ return(1);
+
+ }
+
+ //
+ // Store BIC type.
+ //
+
+
+ if ((Config->cnfg_bid & INTERFACE_CHIP_MASK) == INTERFACE_5X3_CHIP) {
+
+ Config->cnfg_bic_type = BIC_583_CHIP;
+
+ } else {
+
+ Config->cnfg_bic_type = BIC_584_CHIP;
+
+ }
+
+ //
+ // Get58xIrq();
+ //
+
+ RegValue1 = 0;
+
+ if ((Config->cnfg_bid & INTERFACE_CHIP_MASK) != INTERFACE_5X3_CHIP) {
+
+ NdisReadPortUchar(NdisAdapterHandle,
+ Config->cnfg_base_io + CNFG_ICR_583,
+ &RegValue1
+ );
+
+ IF_LMI_LOUD(DbgPrint("When reading for IRQ, I got 0x%x for RegValue1\n", RegValue1));
+
+ RegValue1 &= CNFG_ICR_IR2_584;
+
+ }
+
+ NdisReadPortUchar(NdisAdapterHandle,
+ Config->cnfg_base_io + CNFG_IRR_583,
+ &RegValue2
+ );
+
+ IF_LMI_LOUD(DbgPrint("When reading for IRQ, I got 0x%x for RegValue2\n", RegValue2));
+
+ RegValue2 &= CNFG_IRR_IRQS;
+
+ IF_LMI_LOUD(DbgPrint("RegValue2 is now 0x%x\n", RegValue2));
+
+ RegValue2 >>= 5;
+
+ IF_LMI_LOUD(DbgPrint("RegValue2 is now 0x%x\n", RegValue2));
+
+ if (RegValue2 == 0) {
+
+ if (RegValue1 == 0) {
+
+ Config->cnfg_irq_line = 2;
+
+ } else {
+
+ Config->cnfg_irq_line = 10;
+
+ }
+
+ } else if (RegValue2 == 1) {
+
+ if (RegValue1 == 0) {
+
+ Config->cnfg_irq_line = 3;
+
+ } else {
+
+ Config->cnfg_irq_line = 11;
+
+ }
+
+ } else if (RegValue2 == 2) {
+
+ if (RegValue1 == 0) {
+
+ if (Config->cnfg_bid & ALTERNATE_IRQ_BIT) {
+
+ Config->cnfg_irq_line = 5;
+
+ } else {
+
+ Config->cnfg_irq_line = 4;
+
+ }
+
+ } else {
+
+ Config->cnfg_irq_line = 15;
+
+ }
+
+ } else if (RegValue2 == 3) {
+
+ if (RegValue1 == 0) {
+
+ Config->cnfg_irq_line = 7;
+
+ } else {
+
+ Config->cnfg_irq_line = 4;
+
+ }
+
+ } else {
+
+ //
+ // ERROR! Choose 3.
+ //
+
+ IF_LMI_LOUD(DbgPrint("Error, could not find IRQL. Choosing 3.\n"));
+
+ Config->cnfg_irq_line = 3;
+
+ }
+
+
+ //
+ // Get58xIrqStatus();
+ //
+
+ NdisReadPortUchar(NdisAdapterHandle,
+ Config->cnfg_base_io + CNFG_IRR_583,
+ &RegValue1
+ );
+
+ Config->cnfg_mode_bits1 &= (~INTERRUPT_STATUS_BIT);
+
+ if (RegValue1 & INTERRUPT_STATUS_BIT) {
+
+ Config->cnfg_mode_bits1 |= INTERRUPT_STATUS_BIT;
+
+ }
+
+
+ //
+ // Get58xRamBase();
+ //
+
+ NdisReadPortUchar(NdisAdapterHandle, Config->cnfg_base_io, &RegValue1);
+
+ IF_LMI_LOUD(DbgPrint("When reading for RAM base, I got 0x%x for RegValue1\n", RegValue1));
+
+ RegValue1 &= 0x3F;
+
+ if ((Config->cnfg_bid & INTERFACE_CHIP_MASK) == INTERFACE_5X3_CHIP) {
+
+ RegValue1 |= 0x40;
+
+ Config->cnfg_ram_base = (ULONG)RegValue1 << 13;
+
+ } else {
+
+ NdisReadPortUchar(NdisAdapterHandle,
+ Config->cnfg_base_io + CNFG_LAAR_584,
+ &RegValue2
+ );
+
+ RegValue2 &= CNFG_LAAR_MASK;
+
+ RegValue2 <<= 3;
+
+ RegValue2 |= ((RegValue1 & 0x38) >> 3);
+
+ Config->cnfg_ram_base = ((ULONG)RegValue2 << 16) + (((ULONG)(RegValue1 & 0x7)) << 13);
+
+ }
+
+ //
+ // Get58xRomBase();
+ //
+
+ NdisReadPortUchar(NdisAdapterHandle,
+ Config->cnfg_base_io + CNFG_BIO_583,
+ &RegValue1
+ );
+
+ IF_LMI_LOUD(DbgPrint("When reading for ROM base, I got 0x%x for RegValue1\n", RegValue1));
+
+ RegValue1 &= 0x3E;
+
+ RegValue1 |= 0x40;
+
+ Config->cnfg_rom_base = (ULONG)RegValue1 << 13;
+
+
+
+
+ //
+ // Get58xRomSize();
+ //
+
+ NdisReadPortUchar(NdisAdapterHandle,
+ Config->cnfg_base_io + CNFG_BIO_583,
+ &RegValue1
+ );
+
+ IF_LMI_LOUD(DbgPrint("When reading for ROM size, I got 0x%x for RegValue1\n", RegValue1));
+
+ RegValue1 &= 0xC0;
+
+ if (RegValue1 == 0) {
+
+ Config->cnfg_rom_size = ROM_DISABLE;
+
+ } else {
+
+ RegValue1 >>= 6;
+
+ Config->cnfg_rom_size = (USHORT)CNFG_SIZE_8KB << RegValue1;
+
+ }
+
+
+
+
+
+
+ //
+ // Get58xBootStatus();
+ //
+
+ NdisReadPortUchar(NdisAdapterHandle,
+ Config->cnfg_base_io + CNFG_GP2,
+ &RegValue1
+ );
+
+ IF_LMI_LOUD(DbgPrint("When reading for Boot Status, I got 0x%x for RegValue1\n", RegValue1));
+
+ IF_LMI_LOUD(DbgPrint("Config mode bits are 0x%x\n", Config->cnfg_mode_bits1));
+
+ Config->cnfg_mode_bits1 &= (~BOOT_STATUS_MASK);
+
+ if (RegValue1 & CNFG_GP2_BOOT_NIBBLE) {
+
+ Config->cnfg_mode_bits1 |= BOOT_TYPE_1;
+
+ }
+
+
+
+ //
+ // Get58xZeroWaitState();
+ //
+
+ NdisReadPortUchar(NdisAdapterHandle,
+ Config->cnfg_base_io + CNFG_IRR_583,
+ &RegValue1
+ );
+
+ IF_LMI_LOUD(DbgPrint("When reading for ZWS, I got 0x%x for RegValue1\n", RegValue1));
+
+ Config->cnfg_mode_bits1 &= (~ZERO_WAIT_STATE_MASK);
+
+ if (RegValue1 & CNFG_IRR_ZWS) {
+
+ Config->cnfg_mode_bits1 |= ZERO_WAIT_STATE_8_BIT;
+
+ }
+
+ if (Config->cnfg_bid & BOARD_16BIT) {
+
+ NdisReadPortUchar(NdisAdapterHandle,
+ Config->cnfg_base_io + CNFG_LAAR_584,
+ &RegValue1
+ );
+
+ IF_LMI_LOUD(DbgPrint("When reading for ZWS16, I got 0x%x for RegValue1\n", RegValue1));
+
+ if (RegValue1 & CNFG_LAAR_ZWS) {
+
+ Config->cnfg_mode_bits1 |= ZERO_WAIT_STATE_16_BIT;
+
+ }
+
+ }
+
+
+ //
+ // GetAdvancedFeatures();
+ //
+
+ NdisReadPortUchar(NdisAdapterHandle,
+ Config->cnfg_base_io + CNFG_IRR_583,
+ &RegValue1
+ );
+
+ Config->cnfg_mode_bits1 &= (~CNFG_INTERFACE_TYPE_MASK);
+
+ if (Config->cnfg_bid & ADVANCED_FEATURES) {
+
+ Config->cnfg_mode_bits1 |= ZERO_WAIT_STATE_8_BIT;
+
+ }
+
+ if ((RegValue1 & 0x6) == 2) {
+
+ Config->cnfg_mode_bits1 |= STARLAN_10_INTERFACE;
+ Config->cnfg_media_type = MEDIA_S10;
+
+ } else if ((RegValue1 & 0x6) == 4) {
+
+ Config->cnfg_mode_bits1 |= BNC_INTERFACE;
+ Config->cnfg_media_type = MEDIA_BNC;
+
+ } else {
+
+ Config->cnfg_mode_bits1 |= AUI_10BT_INTERFACE;
+ Config->cnfg_media_type = MEDIA_AUI_UTP;
+
+ }
+
+
+ return(0);
+
+ }
+
+}
+
+
+BOOLEAN
+CardSetup(
+ Ptr_Adapter_Struc Adapt
+ )
+/*++
+
+Routine Description:
+
+ This routine will setup the Receive and transmit spaces of the card.
+
+
+Arguments:
+
+ Adapt - A pointer to an LMI adapter structure.
+
+Return:
+
+ TRUE if successful, else FALSE
+
+--*/
+{
+ ULONG i;
+ UCHAR SaveValue;
+ UCHAR RegValue;
+ BOOLEAN NoLoad;
+
+
+
+ //
+ // Reset IC
+ //
+
+ NdisReadPortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + MEMORY_SELECT_REG,
+ &SaveValue
+ );
+
+ RegValue = SaveValue | (UCHAR)RESET;
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + MEMORY_SELECT_REG,
+ RegValue
+ );
+
+ //
+ // Wait for reset to complete. (2 ms)
+ //
+
+ UM_Delay(2000);
+
+ //
+ // Put back original value
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + MEMORY_SELECT_REG,
+ (UCHAR)(SaveValue & (~RESET))
+ );
+
+
+
+ //
+ // Enable Ram
+ //
+
+
+ if (Adapt->board_id & (MICROCHANNEL | INTERFACE_CHIP)) {
+
+ NdisReadPortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + MEMORY_ENABLE_RESET_REG,
+ &RegValue
+ );
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + MEMORY_ENABLE_RESET_REG,
+ (UCHAR)((RegValue & ~RESET) | MEMORY_ENABLE)
+ );
+
+ } else {
+
+ RegValue = (((UCHAR)(((PUSHORT)Adapt->ram_base) + 2) << 3) |
+ (UCHAR)(Adapt->ram_base >> 13)
+ );
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + MEMORY_ENABLE_RESET_REG,
+ (UCHAR)(RegValue | MEMORY_ENABLE)
+ );
+
+ }
+
+
+
+ //
+ // Load LAN Address
+ //
+
+ NoLoad = FALSE;
+
+
+ for (i=0; i < 6; i++) {
+
+ if (Adapt->node_address[i] != (UCHAR)0) {
+
+ NoLoad = TRUE;
+
+ }
+
+ }
+
+
+ for (i=0; i < 6; i++) {
+
+ //
+ // Read from IC
+ //
+
+ NdisReadPortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + LAN_ADDRESS_REG + i,
+ &(Adapt->permanent_node_address[i])
+ );
+
+
+ }
+
+ if (!NoLoad) {
+
+ for (i=0; i < 6 ; i++) {
+
+ Adapt->node_address[i] = Adapt->permanent_node_address[i];
+ }
+
+
+ }
+
+
+
+
+
+ //
+ // Init NIC
+ //
+
+ //
+ // Maintain reset
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + COMMAND_REG,
+ STOP | REMOTE_ABORT_COMPLETE
+ );
+
+ //
+ // Reset Remote_byte_count registers
+ //
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + REMOTE_BYTE_COUNT_REG0,
+ 0
+ );
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + REMOTE_BYTE_COUNT_REG1,
+ 0
+ );
+
+
+ //
+ // Make sure reset is bit is set
+ //
+
+ NdisReadPortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + INTERRUPT_STATUS_REG,
+ &RegValue
+ );
+
+ if (!(RegValue & RESET)) {
+
+ //
+ // Wait 1600 ms
+ //
+
+ UM_Delay(1600000);
+
+ }
+
+
+ RegValue = RECEIVE_FIFO_THRESHOLD_8 |
+ BURST_DMA_SELECT; // Fifo depth | DMA Burst select
+
+ if (Adapt->board_id & (MICROCHANNEL | SLOT_16BIT)) {
+
+ // Allow 16 bit transfers
+
+ RegValue |= WORD_TRANSFER_SELECT;
+
+ }
+
+ IF_LMI_LOUD(DbgPrint("Writing 0x%x to DCON\n", RegValue));
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + DATA_CONFIG_REG,
+ RegValue
+ );
+
+
+ //
+ // Set Receive Mask
+ //
+
+ LM_Set_Receive_Mask(Adapt);
+
+
+ //
+ // loopback operation while setting up rings.
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + TRANSMIT_CONFIG_REG,
+ LOOPBACK_MODE2
+ );
+
+ //
+ // Write first Receive ring buffer number
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + PAGE_START_REG,
+ Adapt->StartBuffer
+ );
+
+ //
+ // Write last Receive ring buffer number
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + PAGE_STOP_REG,
+ Adapt->LastBuffer
+ );
+
+
+ //
+ // Write buffer number where the card cannot write beyond.
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + BOUNDARY_REG,
+ Adapt->StartBuffer
+ );
+
+ //
+ // Clear all interrupt status bits
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + INTERRUPT_STATUS_REG,
+ 0xFF
+ );
+
+
+ //
+ // Set Interrupt Mask
+ //
+
+ Adapt->InterruptMask = PACKET_RECEIVE_ENABLE |
+ PACKET_TRANSMIT_ENABLE |
+ RECEIVE_ERROR_ENABLE |
+ TRANSMIT_ERROR_ENABLE |
+ OVERWRITE_WARNING_ENABLE |
+ COUNTER_OVERFLOW_ENABLE;
+
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + INTERRUPT_MASK_REG,
+ Adapt->InterruptMask
+ );
+
+ //
+ // Maintain reset and select page 1
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + COMMAND_REG,
+ STOP | REMOTE_ABORT_COMPLETE | PAGE_SELECT_1
+ );
+
+
+
+
+ //
+ // Write physical address
+ //
+
+ for (i = 0; i < 6; i++) {
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + PHYSICAL_ADDRESS_REG0 + i,
+ Adapt->node_address[i]
+ );
+ }
+
+
+ //
+ // Load next pointer.
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + CURRENT_BUFFER_REG,
+ (UCHAR)(Adapt->StartBuffer + 1)
+ );
+
+
+ //
+ // Clear out shared memory.
+ //
+
+ NdisZeroMappedMemory((PVOID)(Adapt->ram_access), (Adapt->ram_usable * 1024));
+
+ //
+ // Init Command Register again.
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + COMMAND_REG,
+ STOP | REMOTE_ABORT_COMPLETE
+ );
+
+
+ //
+ // If this is an MCA card then we need to set the EIL (Enable Interrupt
+ // Line) on the BIC. We will use the NIC Interrupt Mask Register
+ // to control which interrupts get through.
+ //
+
+ if (((Adapt->board_id & MICROCHANNEL) &&
+ ((Adapt->board_id & INTERFACE_CHIP_MASK) == INTERFACE_5X3_CHIP))
+ ||
+ ((Adapt->board_id & INTERFACE_CHIP_MASK) == INTERFACE_594_CHIP)) {
+
+ //
+ // Enable 59x Chip
+ //
+
+ NdisReadPortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + COMMUNICATION_CONTROL_REG,
+ &RegValue
+ );
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + COMMUNICATION_CONTROL_REG,
+ (UCHAR)(RegValue | CCR_INTERRUPT_ENABLE)
+ );
+
+ }
+
+
+ if (!(Adapt->board_id & BOARD_16BIT)) {
+
+ return(TRUE);
+
+ }
+
+
+
+ //
+ // Init LAAR register
+ //
+
+ IF_LMI_LOUD(DbgPrint("Board_id is 0x%x\n",Adapt->board_id));
+
+ if (Adapt->board_id & MICROCHANNEL) {
+
+ Adapt->LaarHold = 0;
+
+ } else {
+
+ if (Adapt->board_id & INTERFACE_CHIP) {
+
+
+ NdisReadPortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + LA_ADDRESS_REG,
+ &RegValue
+ );
+
+ RegValue &= LAAR_MASK;
+
+ RegValue |= ((Adapt->ram_base + 2) >> 3);
+
+ Adapt->LaarHold = RegValue;
+
+ } else {
+
+ Adapt->LaarHold = INIT_LAAR_VALUE;
+
+ }
+
+ if (Adapt->board_id & SLOT_16BIT) {
+
+ Adapt->LaarHold |= LAN_16BIT_ENABLE;
+
+ }
+
+ IF_LMI_LOUD(DbgPrint("Writing 0x%x to LAAR\n",Adapt->LaarHold));
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + LA_ADDRESS_REG,
+ Adapt->LaarHold
+ );
+
+ }
+
+ return(TRUE);
+
+}
+
+VOID
+CardSendPacket(
+ IN Ptr_Adapter_Struc Adapt
+ )
+/*++
+
+Routine Description:
+
+ This will fire off the packet in the NextBufToXmit field.
+
+Arguments:
+
+ Adapt - A pointer to an LMI adapter structure.
+
+Return:
+
+--*/
+{
+ PUCHAR BufferAddress;
+ USHORT BufferSize;
+
+ ASSERT(Adapt->TransmitInterruptPending == FALSE);
+
+ ASSERT(Adapt->CurBufXmitting == (XMIT_BUF)-1);
+
+ ASSERT(Adapt->NextBufToXmit != (XMIT_BUF)-1);
+
+ ASSERT(Adapt->BufferStatus[Adapt->NextBufToXmit] == FULL);
+
+
+
+ Adapt->CurBufXmitting = Adapt->NextBufToXmit;
+
+
+ //
+ // Update NextBufToXmit counter.
+ //
+
+ Adapt->NextBufToXmit++;
+
+ if (Adapt->NextBufToXmit == (XMIT_BUF)(Adapt->num_of_tx_buffs)) {
+
+ Adapt->NextBufToXmit = 0;
+
+ }
+
+
+
+ if (Adapt->BufferStatus[Adapt->NextBufToXmit] != FULL) {
+
+ Adapt->NextBufToXmit = (XMIT_BUF)-1;
+
+ }
+
+
+
+
+ BufferAddress = ((PUCHAR)Adapt->ram_base) +
+ (Adapt->CurBufXmitting * Adapt->xmit_buf_size);
+
+ BufferSize = (USHORT)(Adapt->PacketLens[Adapt->CurBufXmitting]);
+
+ //
+ // Write Buffer Address
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + TRANSMIT_PAGE_START_REG,
+ (UCHAR)(((ULONG)BufferAddress) >> 8)
+ );
+
+ //
+ // Write size of buffer
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + TRANSMIT_BYTE_COUNT_REG0,
+ (UCHAR)(BufferSize & 0xFF)
+ );
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + TRANSMIT_BYTE_COUNT_REG1,
+ (UCHAR)(BufferSize >> 8)
+ );
+
+ if (Adapt->OverWriteHandling && !(Adapt->board_id & NIC_690_BIT)) {
+
+ Adapt->OverWriteStartTransmit = TRUE;
+
+ return;
+
+ } else {
+
+ Adapt->TransmitInterruptPending = TRUE;
+
+ IF_LOG(LOG('!'));
+
+ }
+
+ //
+ // Start transmit
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + COMMAND_REG,
+ START | TRANSMIT_PACKET | REMOTE_ABORT_COMPLETE
+ );
+
+}
+
+VOID
+CardCopyDown(
+ IN Ptr_Adapter_Struc Adapt,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+ This routine will copy down the data in a packet onto the card.
+
+Arguments:
+
+ Adapt - A pointer to an LMI adapter structure.
+
+ Packet - The packet to copy down.
+
+Return:
+
+--*/
+{
+ PUCHAR BufferAddress;
+ UINT UNALIGNED *NdisBufAddress;
+ UCHAR UNALIGNED *NdisBufRest;
+ PNDIS_BUFFER CurrentBuffer;
+ ULONG DataToTransfer;
+ UINT CurrentLength;
+ UINT NdisBufLength;
+
+ //
+ // if (Slot16Bit) then
+ //
+ // Enable 16Bit Memory Access;
+ //
+
+ if (Adapt->board_id & SLOT_16BIT) {
+
+ IF_LMI_LOUD(DbgPrint("Writing 0x%x to LAAR\n",Adapt->LaarHold | MEMORY_16BIT_ENABLE));
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + LA_ADDRESS_REG,
+ (UCHAR)(Adapt->LaarHold | MEMORY_16BIT_ENABLE)
+ );
+
+ }
+
+
+
+ //
+ // GetVirtualAddressOfXmitBuffer();
+ //
+
+ BufferAddress = ((PUCHAR)(Adapt->ram_access)) +
+ (Adapt->NextBufToFill * Adapt->xmit_buf_size);
+
+ //
+ // Copy each buffer over.
+ //
+
+ NdisQueryPacket(Packet, NULL, NULL, &CurrentBuffer, NULL);
+
+ CurrentLength = 0;
+
+ while (CurrentBuffer) {
+
+ NdisQueryBuffer(CurrentBuffer, (PVOID *)&NdisBufAddress, &NdisBufLength);
+
+ if ((Adapt->board_id & MICROCHANNEL) &&
+ (!(Adapt->board_id & INTERFACE_594_CHIP))) {
+
+ //
+ // Then we have a bogon card which can only handle evenly
+ // aligned WORD transfers... do it by hand.
+ //
+
+ ULONG i, BytesToCopy, NumberToCopy;
+ UCHAR MissedBy;
+ PUINT AdapterAddress;
+ UINT UNALIGNED *NdisBufAddressSave = NdisBufAddress;
+
+ //
+ // Do first part to get the destination aligned.
+ //
+
+ MissedBy = (UCHAR)(((ULONG)BufferAddress) % sizeof(UINT));
+
+ AdapterAddress = (PUINT)(BufferAddress - MissedBy);
+
+ //
+ // Get current value of this word.
+ //
+
+ DataToTransfer = *AdapterAddress;
+
+
+ //
+ // OR in the bytes for the new part of this WORD.
+ //
+
+ NdisBufRest = (UCHAR UNALIGNED *)NdisBufAddress;
+
+ BytesToCopy = sizeof(UINT) - MissedBy;
+
+ if (NdisBufLength < BytesToCopy) {
+
+ BytesToCopy = NdisBufLength;
+
+ }
+
+ for (i = 0; i < BytesToCopy; i++) {
+
+ //
+ // Clear old value in this byte
+ //
+
+ DataToTransfer &= ~(0x00FF << ((MissedBy + i) * 8));
+
+
+ //
+ // Store new value - no sign extension plz.
+ //
+
+ DataToTransfer |= (((UINT)(*NdisBufRest)) << ((MissedBy + i) * 8) &
+ (0x00FF << ((MissedBy + i) * 8)));
+
+ NdisBufRest++;
+
+ }
+
+
+ //
+ // Store previous WORD
+ //
+
+ WD_MOVE_DWORD_TO_SHARED_RAM(AdapterAddress, DataToTransfer);
+
+ AdapterAddress++;
+
+
+
+
+
+ //
+ // Update location and bytes left to copy
+ //
+
+ NdisBufAddress = (UINT UNALIGNED *)NdisBufRest;
+
+ BytesToCopy = NdisBufLength - BytesToCopy;
+
+ ASSERT((((ULONG)AdapterAddress) % sizeof(UINT)) == 0);
+
+ //
+ // Now copy Dwords across.
+ //
+
+ NumberToCopy = BytesToCopy / sizeof(UINT);
+
+ for (i=0; i < NumberToCopy; i++) {
+
+ WD_MOVE_DWORD_TO_SHARED_RAM(AdapterAddress, *((PULONG)(NdisBufAddress)));
+
+ AdapterAddress++;
+
+ NdisBufAddress++;
+
+ }
+
+ if ((BytesToCopy % sizeof(UINT)) != 0){
+
+ //
+ // We have some residual to copy.
+ //
+
+ MissedBy = (UCHAR)(BytesToCopy % sizeof(UINT));
+
+ NdisBufRest = (UCHAR UNALIGNED *)NdisBufAddress;
+
+ DataToTransfer = 0;
+
+ for (i = 0; i < MissedBy; i++) {
+
+ DataToTransfer |= ((UINT)(*NdisBufRest)) << (i * 8);
+
+ NdisBufRest++;
+
+ }
+
+ WD_MOVE_DWORD_TO_SHARED_RAM(AdapterAddress, DataToTransfer);
+
+ }
+
+ NdisBufAddress = NdisBufAddressSave;
+
+ } else {
+
+ WD_MOVE_MEM_TO_SHARED_RAM(BufferAddress, (PUCHAR)NdisBufAddress, NdisBufLength);
+
+ }
+
+ BufferAddress += NdisBufLength;
+
+ CurrentLength += NdisBufLength;
+
+ NdisGetNextBuffer(CurrentBuffer, &CurrentBuffer);
+
+ }
+
+
+ //
+ // if (Slot16Bit) then
+ //
+ // TurnOff16BitMemoryAccess;
+ //
+
+ if (Adapt->board_id & SLOT_16BIT) {
+
+ IF_LMI_LOUD(DbgPrint("Writing 0x%x to LAAR\n",Adapt->LaarHold));
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + LA_ADDRESS_REG,
+ Adapt->LaarHold
+ );
+
+ }
+
+ //
+ // if (PacketLength < MIN_PACKET_SIZE) then
+ //
+ // StoreSize = MIN_PACKET_SIZE;
+ //
+ // else
+ //
+ // StoreSize = PacketLength;
+ //
+
+ if (CurrentLength < 60) {
+
+ Adapt->PacketLens[Adapt->NextBufToFill] = 60;
+
+ } else {
+
+ Adapt->PacketLens[Adapt->NextBufToFill] = CurrentLength;
+
+ }
+
+}
+
+VOID
+CardHandleReceive(
+ IN Ptr_Adapter_Struc Adapt
+ )
+/*++
+
+Routine Description:
+
+ This will clear the receive ring of all received packets.
+
+Arguments:
+
+ Adapt - A pointer to an LMI adapter structure.
+
+Return:
+
+--*/
+{
+
+ UCHAR Current;
+ UCHAR Boundary;
+
+ PUCHAR BufferAddress;
+
+ UINT PacketSize;
+ UCHAR PacketStatus;
+ UCHAR NextPacket;
+
+ LM_STATUS Status;
+
+ NdisSynchronizeWithInterrupt(
+ &(Adapt->NdisInterrupt),
+ SyncGetCurrent,
+ Adapt
+ );
+
+ Current = Adapt->Current;
+
+
+ //
+ // Get BOUNDARY + 1 buffer pointer
+ //
+
+ NdisReadPortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + BOUNDARY_REG,
+ &Boundary
+ );
+
+
+ IF_LMI_LOUD(DbgPrint("Current Starts at 0x%x, Boundary at 0x%x\n",Current,Boundary));
+
+ Boundary++;
+
+ if (Boundary >= Adapt->LastBuffer) {
+
+ Boundary = Adapt->StartBuffer;
+
+ }
+
+ //
+ // DoReceives:
+ //
+ // while (BOUNDARY != CURRENT) then
+ //
+
+DoReceives:
+
+ while (Boundary != Current) {
+
+ //
+ // if (STARLAN) then
+ //
+
+ if ((Adapt->board_id & MEDIA_MASK) == STARLAN_MEDIA) {
+
+ //
+ // MapCURRENTToLocalAddressSpace();
+ //
+
+ BufferAddress = ((PUCHAR)(Adapt->ram_access)) +
+ Boundary * Adapt->buffer_page_size;
+
+ //
+ // GetReceiveStatus();
+ //
+
+ WD_MOVE_SHARED_RAM_TO_UCHAR(&PacketStatus, BufferAddress);
+
+ //
+ // GetNextPacketBufferNumber();
+ //
+
+ WD_MOVE_SHARED_RAM_TO_UCHAR(&NextPacket, BufferAddress + 1);
+
+ //
+ // GetPacketLength();
+ //
+
+ PacketSize = 0;
+
+ WD_MOVE_SHARED_RAM_TO_USHORT(&PacketSize, BufferAddress + 2);
+
+ PacketSize = PacketSize - (UINT)BufferAddress;
+
+ if (((INT)PacketSize) < 0) {
+
+ UINT Tmp;
+
+ PacketSize = (UINT)((Adapt->LastBuffer *
+ Adapt->buffer_page_size
+ )
+ - (UINT)BufferAddress);
+
+ Tmp = (NextPacket - Adapt->StartBuffer) - 1;
+
+ PacketSize += (Tmp * Adapt->buffer_page_size);
+
+ }
+
+ if ((PacketSize & 0xFF) > 0xFC) {
+
+ PacketSize += Adapt->buffer_page_size;
+ }
+
+ } else {
+
+ //
+ // if (Slot16Bit) then
+ //
+ // Enable16BitLAAR();
+ //
+
+ if (Adapt->board_id & SLOT_16BIT) {
+
+ IF_LMI_LOUD(DbgPrint("Writing 0x%x to LAAR\n",Adapt->LaarHold | MEMORY_16BIT_ENABLE));
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + LA_ADDRESS_REG,
+ (UCHAR)(Adapt->LaarHold | MEMORY_16BIT_ENABLE)
+ );
+
+ }
+
+ //
+ // MapCURRENTToLocalAddressSpace();
+ //
+
+ BufferAddress = ((PUCHAR)(Adapt->ram_access)) +
+ Boundary * Adapt->buffer_page_size;
+
+ //
+ // GetPacketLength();
+ //
+
+ PacketSize = 0;
+
+ WD_MOVE_SHARED_RAM_TO_USHORT(&PacketSize, BufferAddress + 2);
+
+ //
+ // GetReceiveStatus();
+ //
+
+ WD_MOVE_SHARED_RAM_TO_UCHAR(&PacketStatus, BufferAddress);
+
+ //
+ // GetNextPacketBufferNumber();
+ //
+
+ WD_MOVE_SHARED_RAM_TO_UCHAR(&NextPacket, BufferAddress + 1);
+
+ IF_LOG(LOG('V'));
+
+ IF_LOG(LmiDebugLog[LmiDebugLogPlace++] = (ULONG)BufferAddress);
+ IF_LOG(LmiDebugLog[LmiDebugLogPlace++] = (ULONG)NextPacket);
+
+ IF_LMI_LOUD(DbgPrint("This packet starts at 0x%x, size 0x%x, next 0x%x\n", BufferAddress, PacketSize, NextPacket));
+
+ if (!((NextPacket >= Adapt->StartBuffer) && (NextPacket <= Adapt->LastBuffer))) {
+
+ //
+ // Next pointer appears hosed. This has occured once on an MP
+ // machine such that it looked like we hit a moment in time
+ // where the card had updated CURRENT, but had not updated the
+ // shared ram yet. If we get in here we will just skip ahead
+ // to the end of the receive ring.
+ //
+
+#if DBG
+
+ //
+ // I want to see the system where this happens again.
+ //
+
+ NdisSynchronizeWithInterrupt(
+ &(Adapt->NdisInterrupt),
+ SyncGetCurrent,
+ Adapt
+ );
+
+ Current = Adapt->Current;
+
+ {
+
+ ULONG p0, p1, p2, p3;
+ ULONG p;
+
+ p = LmiDebugLog[(char)LmiDebugLogPlace - 4];
+
+ if ((p < (ULONG)(Adapt->ReceiveStart)) ||
+ (p > (ULONG)(Adapt->ReceiveStop))) {
+
+ p0 = p1 = p2 = p3 = 0;
+
+ } else {
+
+ p0 = *((PULONG)(p));
+ p1 = *((PULONG)(p+4));
+ p2 = *((PULONG)(p+8));
+ p3 = *((PULONG)(p+12));
+
+ }
+
+ DbgPrint("WDLAN : 0x%x, 0x%x, 0x%x, 0x%x: 0x%x 0x%x 0x%x 0x%x\n",
+ Boundary,
+ NextPacket,
+ Current,
+ BufferAddress,
+ *((PULONG)(BufferAddress)),
+ *((PULONG)(BufferAddress + 4)),
+ *((PULONG)(BufferAddress + 8)),
+ *((PULONG)(BufferAddress + 12))
+ );
+
+ DbgPrint("WDLAN : 0x%x: 0x%x 0x%x 0x%x 0x%x\n",
+ p, p0, p1, p2, p3
+ );
+
+ }
+#endif
+
+ Boundary = NextPacket = Current;
+
+ if (Boundary > Adapt->LastBuffer) {
+
+ Boundary = ((Boundary - Adapt->LastBuffer) + Adapt->StartBuffer);
+
+ }
+
+ IF_LMI_LOUD(DbgPrint("Boundary updated to 0x%x because of bad NextPointer\n",
+ (Boundary == Adapt->StartBuffer) ? Adapt->LastBuffer - 1 : Boundary-1));
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + BOUNDARY_REG,
+ (UCHAR)((Boundary == Adapt->StartBuffer) ?
+ Adapt->LastBuffer - 1 :
+ Boundary - 1)
+ );
+
+
+ break;
+
+ }
+
+ //
+ // if (Slot16Bit) then
+ //
+ // TurnOff16BitLAAR();
+ //
+
+ if (Adapt->board_id & SLOT_16BIT) {
+
+ IF_LMI_LOUD(DbgPrint("Writing 0x%x to LAAR\n",Adapt->LaarHold));
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + LA_ADDRESS_REG,
+ Adapt->LaarHold
+ );
+
+ }
+
+ }
+
+ //
+ // Skip over NIC header
+ //
+
+ Adapt->IndicatingPacket = BufferAddress + 4;
+
+ Adapt->PacketLen = PacketSize - 4;
+
+
+ //
+ // UM_Receive_Packet();
+ //
+
+ Status = UM_Receive_Packet(PacketSize - 4, Adapt);
+
+ //
+ // UpdateBOUNDARY();
+ //
+
+ Boundary = NextPacket;
+
+ if (Boundary > Adapt->LastBuffer) {
+
+ Boundary = ((Boundary - Adapt->LastBuffer) + Adapt->StartBuffer);
+
+ }
+
+ IF_LMI_LOUD(DbgPrint("Boundary updated to 0x%x\n",
+ (Boundary == Adapt->StartBuffer) ? Adapt->LastBuffer - 1 : Boundary-1));
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + BOUNDARY_REG,
+ (UCHAR)((Boundary == Adapt->StartBuffer) ?
+ Adapt->LastBuffer - 1 :
+ Boundary - 1)
+ );
+
+
+
+ //
+ // if (UMReturnStatus == EVENTS_DISABLED) then
+ //
+ // return;
+ //
+ //
+
+ if (Status == EVENTS_DISABLED) {
+
+ return;
+
+ }
+
+ }
+
+
+ //
+ // ClearReceiveInterrupt();
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + INTERRUPT_STATUS_REG,
+ PACKET_RECEIVED_NO_ERROR
+ );
+
+
+
+ NdisSynchronizeWithInterrupt(
+ &(Adapt->NdisInterrupt),
+ SyncGetCurrent,
+ Adapt
+ );
+
+ Current = Adapt->Current;
+
+ //
+ // Get BOUNDARY + 1 buffer pointer
+ //
+
+ NdisReadPortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + BOUNDARY_REG,
+ &Boundary
+ );
+
+ IF_LMI_LOUD(DbgPrint("Current restarts at 0x%x, Boundary at 0x%x\n",Current,Boundary));
+
+ Boundary++;
+
+ if (Boundary >= Adapt->LastBuffer) {
+
+ Boundary = Adapt->StartBuffer;
+
+ }
+
+ //
+ // MapCURRENTToLocalAddressSpace();
+ //
+
+ BufferAddress = ((PUCHAR)(Adapt->ram_access)) + Boundary * Adapt->buffer_page_size;
+
+
+
+ //
+ // if (BOUNDARY + 1 != CURRENT) then
+ //
+ // goto DoReceive;
+ //
+
+ if (Boundary != Current) {
+
+ goto DoReceives;
+ }
+
+
+
+
+ //
+ // Ring is empty!
+ //
+
+
+
+
+ //
+ // if (DoingOverWriteHandling) then
+ //
+
+ if (Adapt->OverWriteHandling) {
+
+
+ IF_LOG(LOG('%'));
+
+ //
+ // ClearOverWriteBit();
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + INTERRUPT_STATUS_REG,
+ OVERWRITE_WARNING
+ );
+
+ //
+ // ClearOverWriteFlag();
+ //
+
+ Adapt->OverWriteHandling = FALSE;
+
+
+ //
+ // if (NIC_690) then
+ //
+
+ if (Adapt->board_id & NIC_690_BIT) {
+
+ //
+ // ReadBOUNDARY();
+ //
+
+ NdisReadPortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + BOUNDARY_REG,
+ &Boundary
+ );
+
+ //
+ // WriteBOUNDARY();
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + BOUNDARY_REG,
+ Boundary
+ );
+
+ } else {
+
+ //
+ // Acknowledge All interrupts so far.
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + INTERRUPT_STATUS_REG,
+ 0xFF
+ );
+
+
+ //
+ // TakeNICOutOfLoopbackMode();
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + TRANSMIT_CONFIG_REG,
+ 0
+ );
+
+ //
+ // WriteNewInterruptBits();
+ //
+
+ Current = START | REMOTE_ABORT_COMPLETE;
+
+ if (Adapt->OverWriteStartTransmit) {
+
+ Adapt->OverWriteStartTransmit = FALSE;
+
+ Current |= TRANSMIT_PACKET;
+
+ }
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + COMMAND_REG,
+ Current
+ );
+
+ }
+
+ }
+
+ return;
+
+}
+
+
+
+#pragma NDIS_INIT_FUNCTION(LM_Get_Mca_Io_Base_Address)
+
+LM_STATUS
+LM_Get_Mca_Io_Base_Address(
+ IN Ptr_Adapter_Struc Adapt,
+ IN NDIS_HANDLE ConfigurationHandle,
+ OUT USHORT *IoBaseAddress
+ )
+/*++
+
+Routine Description:
+
+ This routine will get the configuration information about the card.
+
+
+Arguments:
+
+ Adapt - A pointer to an LMI adapter structure.
+
+Return:
+
+ 0 for success, else -1.
+
+--*/
+{
+ NDIS_STATUS Status;
+ UCHAR RegValue1, RegValue2;
+ USHORT RegValue;
+ ULONG SlotNumber;
+
+ //
+ // Get slot info
+ //
+
+ NdisReadMcaPosInformation(
+ &Status,
+ ConfigurationHandle,
+ &SlotNumber,
+ &Adapt->PosData
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ *IoBaseAddress = 0;
+ return((LM_STATUS)-1);
+
+ }
+
+ Adapt->mc_slot_num = (UCHAR)SlotNumber;
+
+ //
+ // GetPosId();
+ //
+
+ RegValue1 = Adapt->PosData.PosData2;
+
+ RegValue2 = Adapt->PosData.PosData1;
+
+ //
+ // if (594Group()) then
+ //
+ // ReturnValue = Get594ConfigInfo();
+ //
+ // else if (593Group()) then
+ //
+ // ReturnValue = Get593ConfigInfo();
+ //
+ // else
+ //
+ // return(-1);
+ //
+
+ RegValue = Adapt->PosData.AdapterId;
+
+ switch (RegValue) {
+
+ case CNFG_ID_8003E:
+ case CNFG_ID_8003S:
+ case CNFG_ID_8003W:
+ case CNFG_ID_BISTRO03E:
+
+ //
+ // Get593Io();
+ //
+
+ RegValue1 = Adapt->PosData.PosData1;
+
+ RegValue1 &= 0xFE;
+
+ *IoBaseAddress = ((USHORT)RegValue1) << 4;
+
+ break;
+
+ case CNFG_ID_8013E:
+ case CNFG_ID_8013W:
+ case CNFG_ID_8115TRA:
+ case CNFG_ID_BISTRO13E:
+ case CNFG_ID_BISTRO13W:
+
+
+ //
+ // Get594Io();
+ //
+
+ RegValue1 = Adapt->PosData.PosData1;
+
+ RegValue1 &= 0xF0;
+
+ *IoBaseAddress = ((USHORT)RegValue1 << 8) | (USHORT)0x800;
+
+ break;
+
+ default:
+
+ //
+ // Not a recognized card
+ //
+
+ *IoBaseAddress = 0;
+
+ return((LM_STATUS)-1);
+
+ }
+
+ return(0);
+
+}
+
+#pragma NDIS_INIT_FUNCTION(LM_Get_Config)
+
+LM_STATUS
+LM_Get_Config(
+ Ptr_Adapter_Struc Adapt
+ )
+/*++
+
+Routine Description:
+
+ This routine will get the configuration information about the card.
+
+
+Arguments:
+
+ Adapt - A pointer to an LMI adapter structure.
+
+Return:
+
+ ADAPTER_AND_CONFIG,
+ ADAPTER_NO_CONFIG,
+ ADAPTER_NOT_FOUND
+
+--*/
+{
+
+ CNFG_Adapter Config;
+ UINT ReturnValue;
+
+ //
+ // Set Defaults
+ //
+
+ Config.cnfg_mode_bits1 = 0;
+ Config.cnfg_bic_type = 0;
+ Config.cnfg_nic_type = 0;
+ Config.cnfg_bus = Adapt->bus_type;
+ Config.cnfg_ram_base = 0xD0000;
+ Config.cnfg_irq_line = 3;
+ Config.cnfg_base_io = Adapt->io_base;
+ Config.cnfg_ram_size = CNFG_SIZE_8KB;
+ Config.cnfg_slot = Adapt->mc_slot_num;
+ Config.PosData = Adapt->PosData;
+
+ //
+ // Turn Off interrupts
+ //
+
+ LM_Disable_Adapter(Adapt);
+
+
+ ReturnValue = CardGetConfig(Adapt->NdisAdapterHandle,
+ (UINT)(Adapt->io_base),
+ (BOOLEAN)((Adapt->bus_type == (UCHAR)1)? TRUE : FALSE),
+ &Config
+ );
+
+ //
+ // Set defaults for LM
+ //
+
+ Adapt->num_of_tx_buffs = 1;
+
+ Adapt->xmit_buf_size = 0x600; // A multiple of 256 > 1514.
+
+
+ //
+ // Turn On interrupts
+ //
+
+ LM_Enable_Adapter(Adapt);
+
+ Adapt->board_id = Config.cnfg_bid;
+
+ Adapt->adapter_text_ptr = (ULONG)NULL;
+
+
+ Adapt->io_base = Config.cnfg_base_io;
+ Adapt->irq_value = Config.cnfg_irq_line;
+ Adapt->ram_base = Config.cnfg_ram_base;
+ Adapt->ram_size = Config.cnfg_ram_size;
+ Adapt->ram_usable = Config.cnfg_ram_usable;
+ Adapt->rom_base = Config.cnfg_rom_base;
+ Adapt->rom_size = Config.cnfg_rom_size;
+ Adapt->media_type = Config.cnfg_media_type;
+ Adapt->mc_slot_num = (UCHAR)Config.cnfg_slot;
+ Adapt->mode_bits = Config.cnfg_mode_bits1;
+ Adapt->bic_type = Config.cnfg_bic_type;
+ Adapt->nic_type = Config.cnfg_nic_type;
+ Adapt->pos_id = Config.cnfg_pos_id;
+
+ IF_LMI_LOUD(DbgPrint("Io 0x%x, Irq 0x%x, RamBase 0x%x, RamSize 0x%x\n",
+ Adapt->io_base,
+ Adapt->irq_value,
+ Adapt->ram_base,
+ Adapt->ram_size
+ ));
+
+
+ if (ReturnValue == 0) {
+
+ return(ADAPTER_AND_CONFIG);
+
+ } else if (ReturnValue == 1) {
+
+ return(ADAPTER_NO_CONFIG);
+
+ }
+
+ return(ADAPTER_NOT_FOUND);
+
+}
+
+
+
+LM_STATUS
+LM_Free_Resources(
+ Ptr_Adapter_Struc Adapt
+ )
+/*++
+
+Routine Description:
+
+ This routine will free up any resources for this adapter.
+
+Arguments:
+
+ Adapt - A pointer to an LMI adapter structure.
+
+
+Return:
+
+ SUCCESS
+ FAILURE
+
+--*/
+{
+ if (Adapt->State == REMOVED) {
+
+ return(SUCCESS);
+
+ }
+
+ Adapt->State == REMOVED;
+
+ return(SUCCESS);
+}
+
+LM_STATUS
+LM_Initialize_Adapter(
+ Ptr_Adapter_Struc Adapt
+ )
+/*++
+
+Routine Description:
+
+ This routine will do a hardware reset, self test, and initialization of
+ the adapter.
+
+ The node_address field (if non-zero) is copied to the card, and if
+ zero, is copied from the card. The following fields must be set by
+ the UM : base_io, ram_size, ram_access, node_address, max_packet_size,
+ buffer_page_size, num_of_tx_buffs, and receive_mask.
+
+
+Arguments:
+
+ Adapt - A pointer to an LMI adapter structure.
+
+
+Return:
+
+ SUCCESS
+ ADAPTER_HARDWARE_FAILED
+ INITIALIZE_FAILED
+
+--*/
+{
+
+ ULONG i;
+
+ //
+ // Disable interrupts.
+ //
+
+ LM_Disable_Adapter(Adapt);
+
+
+ //
+ // Initialize the transmit buffer control.
+ //
+
+ Adapt->CurBufXmitting = (XMIT_BUF)-1;
+ Adapt->NextBufToFill = (XMIT_BUF)0;
+ Adapt->NextBufToXmit = (XMIT_BUF)-1;
+ Adapt->TransmitInterruptPending = FALSE;
+ Adapt->OverWriteStartTransmit = FALSE;
+ IF_LOG(LOG('?'));
+
+ for (i=0; i<Adapt->num_of_tx_buffs; i++) {
+
+ Adapt->BufferStatus[i] = EMPTY;
+ Adapt->PacketLens[i] = 0;
+
+ }
+
+ //
+ // The start of the receive space.
+ //
+
+ Adapt->Current = 0;
+
+ Adapt->ReceiveStart = ((PUCHAR)(Adapt->ram_access)) +
+ (Adapt->num_of_tx_buffs * Adapt->xmit_buf_size);
+
+
+ //
+ // The end of the receive space.
+ //
+
+ Adapt->ReceiveStop = ((PUCHAR)(Adapt->ram_access)) + (Adapt->ram_size * 1024);
+
+
+
+ //
+ // Set receive info
+ //
+
+
+ Adapt->StartBuffer = (UCHAR)(((PUCHAR)(Adapt->ReceiveStart) -
+ (PUCHAR)(Adapt->ram_access)) / Adapt->buffer_page_size);
+
+
+ Adapt->LastBuffer = (UCHAR)(((Adapt->ram_size * 1024) == 0x10000) ? 0xFF :
+ ((Adapt->ram_size * 1024) / WD_BUFFER_PAGE_SIZE) & 0xFF);
+
+
+ IF_LMI_LOUD(DbgPrint("Ring info: Base Addr 0x%lx; ReceiveStart 0x%lx; ReceiveStop 0x%lx\n",
+ Adapt->ram_access, Adapt->ReceiveStart, Adapt->ReceiveStop));
+ IF_LMI_LOUD(DbgPrint(" Start Rcv Ring 0x%x; Last Rcv Ring 0x%x\n",
+ Adapt->StartBuffer, Adapt->LastBuffer));
+
+ //
+ // Set card up
+ //
+
+
+ if (!CardSetup(Adapt)) {
+
+ Adapt->State = REMOVED;
+
+ return(INITIALIZE_FAILED);
+
+ }
+
+ Adapt->State = INITIALIZED;
+
+ return(SUCCESS);
+}
+
+
+
+LM_STATUS
+LM_Enable_Adapter(
+ Ptr_Adapter_Struc Adapt
+ )
+/*++
+
+Routine Description:
+
+ This routine will enable interrupts on the card.
+
+Arguments:
+
+ Adapt - A pointer to an LMI adapter structure.
+
+
+Return:
+
+ SUCCESS
+
+--*/
+{
+ ULONG BoardInterface = (Adapt->board_id & INTERFACE_CHIP_MASK);
+
+ if (Adapt->State != OPEN) {
+
+ return(SUCCESS);
+
+ }
+
+ IF_LOG(LOG('Z'));
+
+ //
+ // Enable NIC; Select Page 0, write Mask
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + COMMAND_REG,
+ REMOTE_ABORT_COMPLETE
+ );
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + INTERRUPT_MASK_REG,
+ Adapt->InterruptMask
+ );
+
+ return(SUCCESS);
+}
+
+LM_STATUS
+LM_Disable_Adapter(
+ Ptr_Adapter_Struc Adapt
+ )
+/*++
+
+Routine Description:
+
+ This routine will disable interrupts on the card.
+
+Arguments:
+
+ Adapt - A pointer to an LMI adapter structure.
+
+
+Return:
+
+ SUCCESS
+
+--*/
+{
+
+ ULONG BoardInterface = (Adapt->board_id & INTERFACE_CHIP_MASK);
+
+ IF_LOG(LOG('z'));
+
+ //
+ // Disable board interrupts...
+ //
+
+ //
+ // disable NIC; Select Page 0, write Mask
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + COMMAND_REG,
+ REMOTE_ABORT_COMPLETE
+ );
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + INTERRUPT_MASK_REG,
+ 0
+ );
+
+ return(SUCCESS);
+
+}
+
+
+LM_STATUS
+LM_Open_Adapter(
+ Ptr_Adapter_Struc Adapt
+ )
+/*++
+
+Routine Description:
+
+ This routine will open the adapter, initializing it if necessary.
+
+Arguments:
+
+ Adapt - A pointer to an LMI adapter structure.
+
+
+Return:
+
+ SUCCESS
+ OPEN_FAILED
+ ADAPTER_HARDWARE_FAILED
+
+--*/
+{
+ LM_STATUS Status;
+
+ if (Adapt->State == OPEN) {
+
+ return(SUCCESS);
+
+ }
+
+ if (Adapt->State == CLOSED) {
+
+ Status = LM_Initialize_Adapter(Adapt);
+
+ if (Status != SUCCESS) {
+
+ return(Status);
+
+ }
+
+ }
+
+
+ if (Adapt->State != INITIALIZED) {
+
+ return(OPEN_FAILED);
+
+ }
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + COMMAND_REG,
+ START | REMOTE_ABORT_COMPLETE
+ );
+
+ if (Adapt->mode_bits & MANUAL_CRC) {
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + TRANSMIT_CONFIG_REG,
+ MANUAL_CRC_GENERATION
+ );
+
+ } else {
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + TRANSMIT_CONFIG_REG,
+ 0
+ );
+
+ }
+
+ Adapt->State = OPEN;
+
+ LM_Enable_Adapter(Adapt);
+
+ return(SUCCESS);
+
+}
+
+LM_STATUS
+LM_Close_Adapter(
+ Ptr_Adapter_Struc Adapt
+ )
+/*++
+
+Routine Description:
+
+ This routine will close the adapter, stopping the card.
+
+Arguments:
+
+ Adapt - A pointer to an LMI adapter structure.
+
+
+Return:
+
+ SUCCESS
+ CLOSE_FAILED
+ ADAPTER_HARDWARE_FAILED
+
+--*/
+{
+
+ if (Adapt->State != OPEN) {
+
+ return(CLOSE_FAILED);
+
+ }
+
+ LM_Disable_Adapter(Adapt);
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + COMMAND_REG,
+ STOP | REMOTE_ABORT_COMPLETE
+ );
+
+ UM_Delay(1600000);
+
+ Adapt->State = CLOSED;
+
+ return(SUCCESS);
+
+}
+
+LM_STATUS
+LM_Set_Receive_Mask(
+ Ptr_Adapter_Struc Adapt
+ )
+/*++
+
+Routine Description:
+
+ This routine will set the adapter to the receive mask in the filter
+ package.
+
+Arguments:
+
+ Adapt - A pointer to an LMI adapter structure.
+
+
+Return:
+
+ SUCCESS
+ INVALID_FUNCTION
+
+--*/
+{
+ UCHAR RegValue = 0;
+ UINT FilterClasses;
+
+ //
+ // Select Page 0
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + COMMAND_REG,
+ REMOTE_ABORT_COMPLETE
+ );
+
+
+ //
+ // Set the card's mask
+ //
+
+ if (Adapt->FilterDB != NULL) {
+
+ FilterClasses = ETH_QUERY_FILTER_CLASSES(Adapt->FilterDB);
+
+ } else {
+
+ FilterClasses = 0;
+
+ }
+
+ if ((FilterClasses & NDIS_PACKET_TYPE_MULTICAST) ||
+ (FilterClasses & NDIS_PACKET_TYPE_ALL_MULTICAST)) {
+
+ if (!(Adapt->board_id & NIC_690_BIT)) {
+
+ NdisSynchronizeWithInterrupt(
+ &(Adapt->NdisInterrupt),
+ SyncSetAllMulticast,
+ Adapt
+ );
+
+ }
+
+ RegValue |= 0x8;
+
+ } else {
+
+ if (!(Adapt->board_id & NIC_690_BIT)) {
+
+ NdisSynchronizeWithInterrupt(
+ &(Adapt->NdisInterrupt),
+ SyncClearMulticast,
+ Adapt
+ );
+
+ }
+
+ }
+
+
+ if (FilterClasses & NDIS_PACKET_TYPE_BROADCAST) {
+
+ RegValue |= 0x4;
+
+ }
+
+
+ if (FilterClasses & NDIS_PACKET_TYPE_PROMISCUOUS) {
+
+ RegValue |= 0x1C;
+
+ }
+
+
+ //
+ // Write mask to card
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + RECEIVE_STATUS_REG,
+ RegValue
+ );
+
+ return(SUCCESS);
+}
+
+LM_STATUS
+LM_Service_Receive_Events(
+ Ptr_Adapter_Struc Adapt
+ )
+/*++
+
+Routine Description:
+
+ This routine will handle all interrupts from the adapter.
+
+Arguments:
+
+ Adapt - A pointer to an LMI adapter structure.
+
+
+Return:
+
+ SUCCESS
+ REQUEUE_LATER
+ NOT_MY_INTERRUPT
+
+--*/
+{
+ UCHAR InterruptStatus;
+ BOOLEAN NoEventsServiced = TRUE;
+ ULONG ReceivePacketCount = 0;
+
+ //
+ // Get Interrupt Status
+ //
+
+ NdisReadPortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + INTERRUPT_STATUS_REG,
+ &InterruptStatus
+ );
+
+ //
+ // Consider only the relevant bits.
+ //
+
+ InterruptStatus &= (OVERWRITE_WARNING |
+ ISR_COUNTER_OVERFLOW |
+ PACKET_RECEIVED_NO_ERROR |
+ RECEIVE_ERROR
+ );
+
+
+ while (InterruptStatus != 0) {
+
+ NoEventsServiced = FALSE;
+
+ if (ReceivePacketCount > 10) {
+
+ return(REQUEUE_LATER);
+
+ }
+
+ ReceivePacketCount++;
+
+ //
+ // if (RingOverFlowed) then
+ //
+ // if (BoardNICIsNot690) then
+ //
+ // ResetNIC();
+ //
+ // HandleReceive();
+ //
+ // Continue;
+ //
+
+ if (InterruptStatus & OVERWRITE_WARNING) {
+
+ IF_LOG(LOG('o'));
+
+ Adapt->OverWriteHandling = TRUE;
+
+ //
+ // if (BoardNICIsNot690) then
+ //
+ // ResetNIC();
+ //
+ // HandleReceive();
+ //
+
+ if (!(Adapt->board_id & NIC_690_BIT)) {
+
+ //
+ // Stop the NIC
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + COMMAND_REG,
+ STOP | REMOTE_ABORT_COMPLETE
+ );
+
+ //
+ // Reset Remote_byte_count registers
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + REMOTE_BYTE_COUNT_REG0,
+ 0
+ );
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + REMOTE_BYTE_COUNT_REG1,
+ 0
+ );
+
+ //
+ // Wait for reset to complete
+ //
+
+ NdisReadPortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + INTERRUPT_STATUS_REG,
+ &InterruptStatus
+ );
+
+ if (!(InterruptStatus & RESET)) {
+
+ UM_Delay(1600000);
+
+ }
+
+
+ //
+ // Put in loopback mode 1
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + TRANSMIT_CONFIG_REG,
+ LOOPBACK_MODE1
+ );
+
+ //
+ // Restart NIC
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + COMMAND_REG,
+ START | REMOTE_ABORT_COMPLETE
+ );
+
+
+ //
+ // If we started a packet transmitting and we reached here,
+ // we never got the interrupt for it. Assume it made it
+ // and complete the send.
+ //
+
+ if (Adapt->TransmitInterruptPending) {
+
+ ASSERT(Adapt->CurBufXmitting != (XMIT_BUF)-1);
+
+ Adapt->TransmitInterruptPending = FALSE;
+
+ Adapt->BufferStatus[Adapt->CurBufXmitting] = EMPTY;
+
+ IF_LOG(LOG('?'));
+
+ Adapt->CurBufXmitting = (XMIT_BUF)-1;
+
+ if (Adapt->NextBufToXmit != (XMIT_BUF)-1) {
+
+ //
+ // Start next xmit (this will really only set up
+ // for the xmit, and CardHandleReceive will issue
+ // the xmit command.)
+ //
+
+ CardSendPacket(Adapt);
+
+ }
+
+ UM_Send_Complete(SUCCESS, Adapt);
+
+ }
+
+ }
+
+ //
+ // Clear Receive Rings
+ //
+
+ CardHandleReceive(Adapt);
+
+ goto LoopBottom;
+
+ }
+
+
+
+
+
+
+
+
+
+ //
+ // if (CounterOverflow) then
+ //
+ // HandleOverflow();
+ //
+
+
+ if (InterruptStatus & ISR_COUNTER_OVERFLOW) {
+
+ UCHAR Count;
+
+ //
+ // Update Alignment count
+ //
+
+ NdisReadPortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + ALIGNMENT_ERROR_REG,
+ &Count
+ );
+
+ (*(Adapt->ptr_rx_align_errors)) += Count;
+
+ //
+ // Update CRC Count
+ //
+
+ NdisReadPortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + CRC_ERROR_REG,
+ &Count
+ );
+
+ (*(Adapt->ptr_rx_CRC_errors)) += Count;
+
+
+ //
+ // Update MissedPacket Count
+ //
+
+ NdisReadPortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + MISSED_PACKET_REG,
+ &Count
+ );
+
+ (*(Adapt->ptr_rx_lost_pkts)) += Count;
+
+ //
+ // Write ISR
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + INTERRUPT_STATUS_REG,
+ ISR_COUNTER_OVERFLOW
+ );
+
+ goto LoopBottom;
+
+ }
+
+
+
+
+
+
+
+
+ //
+ // if (PacketWasReceived) then
+ //
+ // HandleReceive();
+ //
+
+ if (InterruptStatus & PACKET_RECEIVED_NO_ERROR) {
+
+ CardHandleReceive(Adapt);
+
+ goto LoopBottom;
+
+ }
+
+
+
+
+
+
+
+
+
+ //
+ // if (ReceiveError) then
+ //
+ // HandleReceiveError();
+ //
+
+ if (InterruptStatus & RECEIVE_ERROR) {
+
+ //
+ // Get receive status
+ //
+
+ NdisReadPortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + RECEIVE_STATUS_REG,
+ &InterruptStatus
+ );
+
+ //
+ // if (CRCError) then
+ //
+ // UpdateCRCCounter();
+ //
+
+ if (InterruptStatus & RECEIVE_CRC_ERROR) {
+
+ (*(Adapt->ptr_rx_CRC_errors))++;
+
+ }
+
+
+ //
+ // if (FrameAlignmentError) then
+ //
+ // UpdateFrameAlignmentCounter();
+ //
+
+ if (InterruptStatus & RECEIVE_ALIGNMENT_ERROR) {
+
+ UCHAR AlignmentCount;
+
+ NdisReadPortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + ALIGNMENT_ERROR_REG,
+ &AlignmentCount
+ );
+
+ (*(Adapt->ptr_rx_align_errors)) += AlignmentCount;
+
+ }
+
+
+
+
+ //
+ // if (FIFOUnderrunError) then
+ //
+ // UpdateFIFOCounter();
+ //
+
+ if (InterruptStatus & RECEIVE_FIFO_UNDERRUN) {
+
+ (*(Adapt->ptr_rx_overruns))++;
+
+ }
+
+
+
+
+ //
+ // if (LostPacketError) then
+ //
+ // UpdateLostPacketCounter();
+ //
+
+ if (InterruptStatus & RECEIVE_MISSED_PACKET) {
+
+ UCHAR MissedPacketCount;
+
+ NdisReadPortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + MISSED_PACKET_REG,
+ &MissedPacketCount
+ );
+
+ (*(Adapt->ptr_rx_lost_pkts)) += MissedPacketCount;
+
+ }
+
+
+ //
+ // Write ISR
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + INTERRUPT_STATUS_REG,
+ RECEIVE_ERROR
+ );
+
+ goto LoopBottom;
+
+ }
+
+
+LoopBottom:
+
+
+
+
+ //
+ // Get Interrupt Status
+ //
+
+ NdisReadPortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + INTERRUPT_STATUS_REG,
+ &InterruptStatus
+ );
+
+ //
+ // Consider only the relevant bits.
+ //
+
+ InterruptStatus &= (OVERWRITE_WARNING |
+ ISR_COUNTER_OVERFLOW |
+ PACKET_RECEIVED_NO_ERROR |
+ RECEIVE_ERROR
+ );
+
+ }
+
+
+ //
+ //
+ // if (UMRequestedInterrupt) then
+ //
+ // UM_Interrupt();
+ //
+ // return (SUCCESS);
+
+ if (Adapt->UMRequestedInterrupt) {
+
+ Adapt->UMRequestedInterrupt = FALSE;
+
+ UM_Interrupt(Adapt);
+
+ return(SUCCESS);
+
+ }
+
+
+
+ //
+ // if (NoEventsServiced) then
+ //
+ // return (NOT_MY_INTERRUPT);
+ //
+
+
+ if (NoEventsServiced) {
+
+ return(NOT_MY_INTERRUPT);
+
+ }
+
+ //
+ // return(SUCCESS);
+ //
+
+ return(SUCCESS);
+}
+
+
+LM_STATUS
+LM_Service_Transmit_Events(
+ Ptr_Adapter_Struc Adapt
+ )
+/*++
+
+Routine Description:
+
+ This routine will handle all interrupts from the adapter.
+
+Arguments:
+
+ Adapt - A pointer to an LMI adapter structure.
+
+
+Return:
+
+ SUCCESS
+ NOT_MY_INTERRUPT
+
+--*/
+{
+ UCHAR InterruptStatus;
+
+ //
+ // Get Interrupt Status
+ //
+
+ NdisReadPortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + INTERRUPT_STATUS_REG,
+ &InterruptStatus
+ );
+
+ //
+ // Consider only the relevant bits.
+ //
+
+ InterruptStatus &= (OVERWRITE_WARNING |
+ PACKET_TRANSMITTED_NO_ERROR |
+ TRANSMIT_ERROR
+ );
+
+ while ((InterruptStatus & (PACKET_TRANSMITTED_NO_ERROR | TRANSMIT_ERROR))
+ != 0) {
+
+ if ((InterruptStatus & OVERWRITE_WARNING) && !(Adapt->board_id & NIC_690_BIT)) {
+
+ Adapt->TransmitInterruptPending = FALSE;
+
+ IF_LOG(LOG('?'));
+ IF_LOG(LOG('O'));
+
+ break;
+
+ }
+
+ //
+ // if (PacketWasTransmitted) then
+ //
+ // HandleTransmit();
+ //
+
+ if (InterruptStatus & PACKET_TRANSMITTED_NO_ERROR) {
+
+ if (Adapt->CurBufXmitting == (XMIT_BUF)-1) {
+
+ //
+ // We have seen a bad card where this occurred once. So, here is
+ // some code to recover from such a bad state.
+ //
+ // Reset the card and hope that solves the problem. NOTE: This
+ // code is cut and pasted from LM_Open_Adapter().
+ //
+
+ LM_Initialize_Adapter(Adapt);
+
+ if (Adapt->State != INITIALIZED) {
+
+ //
+ // Init failed, we are really hosed. Break and exit
+ //
+
+ break;
+
+ }
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + COMMAND_REG,
+ START | REMOTE_ABORT_COMPLETE
+ );
+
+ if (Adapt->mode_bits & MANUAL_CRC) {
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + TRANSMIT_CONFIG_REG,
+ MANUAL_CRC_GENERATION
+ );
+
+ } else {
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + TRANSMIT_CONFIG_REG,
+ 0
+ );
+
+ }
+
+ Adapt->State = OPEN;
+
+ LM_Enable_Adapter(Adapt);
+
+ //
+ // On DBG builds I want to see if the recovery works, since we
+ // cannot reproduce this problem.
+ //
+
+ ASSERT(Adapt->CurBufXmitting != (XMIT_BUF)-1);
+
+ break;
+
+ }
+
+
+ //
+ // Write ISR
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + INTERRUPT_STATUS_REG,
+ PACKET_TRANSMITTED_NO_ERROR
+ );
+
+ Adapt->TransmitInterruptPending = FALSE;
+
+ IF_LOG(LOG('?'));
+
+ Adapt->BufferStatus[Adapt->CurBufXmitting] = EMPTY;
+
+ Adapt->CurBufXmitting = (XMIT_BUF)-1;
+
+ if (Adapt->NextBufToXmit != (XMIT_BUF)-1) {
+
+ //
+ // Start next xmit
+ //
+
+ CardSendPacket(Adapt);
+
+ }
+
+ if (UM_Send_Complete(SUCCESS, Adapt) != EVENTS_DISABLED) {
+
+ goto LoopBottom;
+
+ } else {
+
+ break;
+
+ }
+
+ }
+
+
+
+
+
+
+ //
+ // if (TransmitError) then
+ //
+ // HandleTransmitError();
+ //
+
+ if (InterruptStatus & TRANSMIT_ERROR) {
+
+ //
+ // Write ISR
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + INTERRUPT_STATUS_REG,
+ TRANSMIT_ERROR
+ );
+
+ //
+ // Get Transmit Status
+ //
+
+ NdisReadPortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + TRANSMIT_STATUS_REG,
+ &InterruptStatus
+ );
+
+ //
+ // Check error type and update counter
+ //
+
+ if (InterruptStatus & TRANSMIT_ABORT) {
+
+ (*(Adapt->ptr_tx_max_collisions))++;
+
+ } else if (InterruptStatus & TRANSMIT_FIFO_UNDERRUN) {
+
+ (*(Adapt->ptr_tx_underruns))++;
+
+ }
+
+ ASSERT(Adapt->CurBufXmitting != (XMIT_BUF)-1);
+
+ Adapt->TransmitInterruptPending = FALSE;
+
+ IF_LOG(LOG('?'));
+
+ Adapt->BufferStatus[Adapt->CurBufXmitting] = EMPTY;
+
+ Adapt->CurBufXmitting = (XMIT_BUF)-1;
+
+ if (Adapt->NextBufToXmit != (XMIT_BUF)-1) {
+
+ //
+ // Start next xmit
+ //
+
+ CardSendPacket(Adapt);
+
+ }
+
+ if (UM_Send_Complete((LM_STATUS)((InterruptStatus & TRANSMIT_ABORT) ?
+ MAX_COLLISIONS : FIFO_UNDERRUN),
+ Adapt
+ ) == EVENTS_DISABLED) {
+
+ break;
+
+ }
+
+ }
+
+
+
+
+
+LoopBottom:
+
+
+
+
+ //
+ // Get Interrupt Status
+ //
+
+ NdisReadPortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + INTERRUPT_STATUS_REG,
+ &InterruptStatus
+ );
+
+ //
+ // Consider only the relevant bits.
+ //
+
+ InterruptStatus &= (OVERWRITE_WARNING |
+ PACKET_TRANSMITTED_NO_ERROR |
+ TRANSMIT_ERROR
+ );
+
+
+ }
+
+
+ //
+ // return(SUCCESS);
+ //
+
+ return(SUCCESS);
+}
+
+LM_STATUS
+LM_Send(
+ PNDIS_PACKET Packet,
+ Ptr_Adapter_Struc Adapt
+ )
+/*++
+
+Routine Description:
+
+ This routine will copy a packet to the card and start a transmit if
+ possible
+
+Arguments:
+
+ Packet - The packet to put on the wire.
+
+ Adapt - A pointer to an LMI adapter structure.
+
+
+Return:
+
+ SUCCESS
+ OUT_OF_RESOURCES
+
+--*/
+{
+ XMIT_BUF Buffer = Adapt->NextBufToFill;
+
+ //
+ // if (NoBufferToFill) then
+ //
+ // return OUT_OF_RESOURCES;
+ //
+
+ if (Adapt->BufferStatus[Buffer] != EMPTY) {
+
+ return(OUT_OF_RESOURCES);
+
+ }
+
+ //
+ // Update current buffer status
+ //
+
+ Adapt->BufferStatus[Buffer] = FILLING;
+
+ //
+ // Copy down data
+ //
+
+ CardCopyDown(Adapt, Packet);
+
+ //
+ // Move NextBufToFill
+ //
+
+ Adapt->NextBufToFill++;
+
+ if (Adapt->NextBufToFill == MAX_XMIT_BUFS) {
+
+ Adapt->NextBufToFill = 0;
+
+ }
+
+
+ //
+ // Update current buffer status
+ //
+
+ Adapt->BufferStatus[Buffer] = FULL;
+
+
+ //
+ // Check if o.k. to send packet
+ //
+
+ if (Adapt->NextBufToXmit == (XMIT_BUF)-1) {
+
+ Adapt->NextBufToXmit = Buffer;
+
+ if (Adapt->CurBufXmitting == (XMIT_BUF)-1) {
+
+ IF_LOG(LOG('X'));
+
+ CardSendPacket(Adapt);
+
+ }
+
+ }
+
+ //
+ // return success
+ //
+
+ return(SUCCESS);
+
+}
+
+
+extern
+LM_STATUS
+LM_Receive_Copy(
+ PULONG Bytes_Transferred,
+ ULONG Byte_Count,
+ ULONG Offset,
+ PNDIS_PACKET Packet,
+ Ptr_Adapter_Struc Adapt
+ )
+/*++
+
+Routine Description:
+
+ This routine will copy from the card into the Packet.
+
+Arguments:
+
+ Bytes_Transferred - The number of bytes transferred.
+
+ Byte_Count - The number of bytes to transfer.
+
+ Offset - Offset into the receive buffer from which to receive
+
+ Packet - The packet to put on the wire.
+
+ Adapt - A pointer to an LMI adapter structure.
+
+
+Return:
+
+ SUCCESS
+ OUT_OF_RESOURCES
+
+--*/
+{
+ UINT BytesLeft, BytesWanted, BytesNow;
+ PUCHAR CurrentCardLoc;
+ UINT UNALIGNED *BufferVA;
+ UINT BufferLength, BufferOffset;
+ PNDIS_BUFFER CurrentBuffer;
+
+ *Bytes_Transferred = 0;
+
+ //
+ // See how much data there is to transfer.
+ //
+
+ if (Offset + Byte_Count > Adapt->PacketLen) {
+
+ BytesWanted = Adapt->PacketLen - Offset;
+
+ } else {
+
+ BytesWanted = Byte_Count;
+
+ }
+
+ BytesLeft = BytesWanted;
+
+
+ //
+ // Determine where the copying should start.
+ //
+
+ CurrentCardLoc = (PUCHAR)(Adapt->IndicatingPacket) + Offset;
+ if (CurrentCardLoc > Adapt->ReceiveStop) {
+ CurrentCardLoc = Adapt->ReceiveStart + (CurrentCardLoc - Adapt->ReceiveStop);
+ }
+
+ NdisQueryPacket(Packet, NULL, NULL, &CurrentBuffer, NULL);
+
+ NdisQueryBuffer(CurrentBuffer, (PVOID *)&BufferVA, &BufferLength);
+
+ BufferOffset = 0;
+
+
+ //
+ // Enable 16 bit memory access if possible
+ //
+
+ if (Adapt->board_id & SLOT_16BIT) {
+
+ IF_LMI_LOUD(DbgPrint("Writing 0x%x to LAAR\n",Adapt->LaarHold | MEMORY_16BIT_ENABLE));
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + LA_ADDRESS_REG,
+ (UCHAR)(Adapt->LaarHold | MEMORY_16BIT_ENABLE)
+ );
+
+ }
+
+
+ //
+ // Loop, filling each buffer in the packet until there
+ // are no more buffers or the data has all been copied.
+ //
+
+ while (BytesLeft > 0) {
+
+ //
+ // See how much data to read into this buffer.
+ //
+
+ if ((BufferLength - BufferOffset) > BytesLeft) {
+
+ BytesNow = BytesLeft;
+
+ } else {
+
+ BytesNow = (BufferLength - BufferOffset);
+
+ }
+
+
+ //
+ // See if the data for this buffer wraps around the end
+ // of the receive buffers (if so filling this buffer
+ // will use two iterations of the loop).
+ //
+
+ if (CurrentCardLoc + BytesNow > Adapt->ReceiveStop) {
+
+ BytesNow = Adapt->ReceiveStop - CurrentCardLoc;
+
+ }
+
+
+ //
+ // Copy up the data.
+ //
+
+ if ((Adapt->board_id & MICROCHANNEL) &&
+ (!(Adapt->board_id & NIC_690_BIT))) {
+
+
+ //
+ // Then we have a bogon card which can only handle evenly
+ // aligned WORD transfers... do it by hand.
+ //
+
+ ULONG i, BytesToCopy, NumberToCopy;
+ UCHAR MissedBy;
+ PUINT AdapterAddress;
+ UINT DataToTransfer;
+ UCHAR UNALIGNED *NdisBufRest;
+ UINT UNALIGNED *NdisBufAddressSave = BufferVA;
+
+ //
+ // Do first part to get the source aligned.
+ //
+
+ MissedBy = (UCHAR)(((ULONG)CurrentCardLoc) % sizeof(UINT));
+
+ AdapterAddress = (PUINT)(CurrentCardLoc - MissedBy);
+
+ WD_MOVE_SHARED_RAM_TO_DWORD(&DataToTransfer, AdapterAddress);
+
+ //
+ // Get first few bytes.
+ //
+
+ NdisBufRest = (UCHAR UNALIGNED *)BufferVA;
+
+ BytesToCopy = sizeof(UINT) - MissedBy;
+
+ if (BytesNow < BytesToCopy) {
+
+ BytesToCopy = BytesNow;
+
+ }
+
+ for (i = 0; i < BytesToCopy; i++) {
+
+ //
+ // Store new value.
+ //
+
+ *NdisBufRest = (UCHAR)(DataToTransfer >> ((MissedBy + i) * 8));
+
+ NdisBufRest++;
+
+ }
+
+
+ AdapterAddress++;
+
+
+
+
+ //
+ // Update location and bytes left to copy
+ //
+
+ BufferVA = (UINT UNALIGNED *)NdisBufRest;
+
+ BytesToCopy = BytesNow - BytesToCopy;
+
+ ASSERT((((ULONG)AdapterAddress) % sizeof(UINT)) == 0);
+
+ //
+ // Now copy Dwords across.
+ //
+
+ NumberToCopy = BytesToCopy / sizeof(UINT);
+
+ for (i=0; i < NumberToCopy; i++) {
+
+ WD_MOVE_SHARED_RAM_TO_DWORD(BufferVA, AdapterAddress);
+
+ AdapterAddress++;
+
+ BufferVA++;
+
+ }
+
+ if ((BytesToCopy % sizeof(UINT)) != 0){
+
+ //
+ // We have some residual to copy.
+ //
+
+ MissedBy = (UCHAR)(BytesToCopy % sizeof(UINT));
+
+ NdisBufRest = (UCHAR UNALIGNED *)BufferVA;
+
+ WD_MOVE_SHARED_RAM_TO_DWORD(&DataToTransfer, AdapterAddress);
+
+ for (i = 0; i < MissedBy; i++) {
+
+ *NdisBufRest = ((UCHAR)(DataToTransfer >> (i * 8)));
+
+ NdisBufRest++;
+
+ }
+
+ }
+
+ BufferVA = NdisBufAddressSave;
+
+ } else {
+
+ WD_MOVE_SHARED_RAM_TO_MEM((PUCHAR)BufferVA, CurrentCardLoc, BytesNow);
+
+ }
+
+ CurrentCardLoc += BytesNow;
+
+ BytesLeft -= BytesNow;
+
+ *Bytes_Transferred += BytesNow;
+
+
+ //
+ // Is the transfer done now?
+ //
+
+ if (BytesLeft == 0) {
+
+ break;
+
+ }
+
+
+ //
+ // Wrap around the end of the receive buffers?
+ //
+
+ if (CurrentCardLoc == Adapt->ReceiveStop) {
+
+ CurrentCardLoc = Adapt->ReceiveStart;
+
+ }
+
+
+ //
+ // Was the end of this packet buffer reached?
+ //
+
+ BufferVA = (UINT UNALIGNED *)(((UCHAR UNALIGNED *)BufferVA) + BytesNow);
+
+ BufferOffset += BytesNow;
+
+ if (BufferOffset == BufferLength) {
+
+ NdisGetNextBuffer(CurrentBuffer, &CurrentBuffer);
+
+ if (CurrentBuffer == (PNDIS_BUFFER)NULL) {
+
+ break;
+
+ }
+
+ NdisQueryBuffer(CurrentBuffer, (PVOID *)&BufferVA, &BufferLength);
+
+ BufferOffset = 0;
+
+ }
+
+ }
+
+ //
+ // Turn off 16 bit memory access
+ //
+
+ if (Adapt->board_id & SLOT_16BIT) {
+
+ IF_LMI_LOUD(DbgPrint("Writing 0x%x to LAAR\n",Adapt->LaarHold));
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + LA_ADDRESS_REG,
+ Adapt->LaarHold
+ );
+ }
+
+
+ return SUCCESS;
+
+}
+
+extern
+LM_STATUS
+LM_Receive_Lookahead(
+ ULONG Byte_Count,
+ ULONG Offset,
+ PUCHAR Buffer,
+ Ptr_Adapter_Struc Adapt
+ )
+/*++
+
+Routine Description:
+
+ This routine will copy from the card into a single contiguous buffer.
+
+Arguments:
+
+ Byte_Count - The number of bytes to transfer.
+
+ Offset - Offset into the receive buffer from which to receive
+
+ Packet - The packet to put on the wire.
+
+ Adapt - A pointer to an LMI adapter structure.
+
+
+Return:
+
+ SUCCESS
+ OUT_OF_RESOURCES
+
+--*/
+{
+ UINT BytesLeft, BytesWanted, BytesNow;
+ PUCHAR CurrentCardLoc;
+ UINT UNALIGNED *BufferVA = (UINT UNALIGNED *)Buffer;
+
+ //
+ // See how much data there is to transfer.
+ //
+
+ if (Offset + Byte_Count > Adapt->PacketLen) {
+
+ BytesWanted = Adapt->PacketLen - Offset;
+
+ } else {
+
+ BytesWanted = Byte_Count;
+
+ }
+
+ BytesLeft = BytesWanted;
+
+
+ //
+ // Determine where the copying should start.
+ //
+
+ CurrentCardLoc = Adapt->IndicatingPacket;
+
+
+ //
+ // Enable 16 bit memory access if possible
+ //
+
+ if (Adapt->board_id & SLOT_16BIT) {
+
+ IF_LMI_LOUD(DbgPrint("Writing 0x%x to LAAR\n",Adapt->LaarHold | MEMORY_16BIT_ENABLE));
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + LA_ADDRESS_REG,
+ (UCHAR)(Adapt->LaarHold | MEMORY_16BIT_ENABLE)
+ );
+
+ }
+
+
+ //
+ // Loop, filling each buffer in the packet until there
+ // are no more buffers or the data has all been copied.
+ //
+
+ while (BytesLeft > 0) {
+
+ BytesNow = BytesLeft;
+
+ //
+ // See if the data for this buffer wraps around the end
+ // of the receive buffers (if so filling this buffer
+ // will use two iterations of the loop).
+ //
+
+ if (CurrentCardLoc + BytesNow > Adapt->ReceiveStop) {
+
+ BytesNow = Adapt->ReceiveStop - CurrentCardLoc;
+
+ }
+
+
+ //
+ // Copy up the data.
+ //
+
+ if ((Adapt->board_id & MICROCHANNEL) &&
+ (!(Adapt->board_id & NIC_690_BIT))) {
+
+
+ //
+ // Then we have a bogon card which can only handle evenly
+ // aligned WORD transfers... do it by hand.
+ //
+
+ ULONG i, BytesToCopy, NumberToCopy;
+ UCHAR MissedBy;
+ PUINT AdapterAddress;
+ UINT DataToTransfer;
+ UCHAR UNALIGNED *NdisBufRest;
+ UINT UNALIGNED *NdisBufAddressSave = BufferVA;
+
+ //
+ // Do first part to get the source aligned.
+ //
+
+ MissedBy = (UCHAR)(((ULONG)CurrentCardLoc) % sizeof(UINT));
+
+ AdapterAddress = (PUINT)(CurrentCardLoc - MissedBy);
+
+ WD_MOVE_SHARED_RAM_TO_DWORD(&DataToTransfer, AdapterAddress);
+
+ //
+ // Get first few bytes.
+ //
+
+ NdisBufRest = (UCHAR UNALIGNED *)BufferVA;
+
+ BytesToCopy = sizeof(UINT) - MissedBy;
+
+ if (BytesNow < BytesToCopy) {
+
+ BytesToCopy = BytesNow;
+
+ }
+
+ for (i = 0; i < BytesToCopy; i++) {
+
+ //
+ // Store new value.
+ //
+
+ *NdisBufRest = (UCHAR)(DataToTransfer >> ((MissedBy + i) * 8));
+
+ NdisBufRest++;
+
+ }
+
+
+ AdapterAddress++;
+
+
+
+
+ //
+ // Update location and bytes left to copy
+ //
+
+ BufferVA = (UINT UNALIGNED *)NdisBufRest;
+
+ BytesToCopy = BytesNow - BytesToCopy;
+
+ ASSERT((((ULONG)AdapterAddress) % sizeof(UINT)) == 0);
+
+ //
+ // Now copy Dwords across.
+ //
+
+ NumberToCopy = BytesToCopy / sizeof(UINT);
+
+ for (i=0; i < NumberToCopy; i++) {
+
+ WD_MOVE_SHARED_RAM_TO_DWORD(BufferVA, AdapterAddress);
+
+ AdapterAddress++;
+
+ BufferVA++;
+
+ }
+
+ if ((BytesToCopy % sizeof(UINT)) != 0){
+
+ //
+ // We have some residual to copy.
+ //
+
+ MissedBy = (UCHAR)(BytesToCopy % sizeof(UINT));
+
+ NdisBufRest = (UCHAR UNALIGNED *)BufferVA;
+
+ WD_MOVE_SHARED_RAM_TO_DWORD(&DataToTransfer, AdapterAddress);
+
+ for (i = 0; i < MissedBy; i++) {
+
+ *NdisBufRest = ((UCHAR)(DataToTransfer >> (i * 8)));
+
+ NdisBufRest++;
+
+ }
+
+ }
+
+ BufferVA = NdisBufAddressSave;
+
+ } else {
+
+ WD_MOVE_SHARED_RAM_TO_MEM((PUCHAR)BufferVA, CurrentCardLoc, BytesNow);
+
+ }
+
+ CurrentCardLoc += BytesNow;
+
+ Buffer += BytesNow;
+
+ BytesLeft -= BytesNow;
+
+
+ //
+ // Is the transfer done now?
+ //
+
+ if (BytesLeft == 0) {
+
+ break;
+
+ }
+
+
+ //
+ // Wrap around the end of the receive buffers?
+ //
+
+ if (CurrentCardLoc == Adapt->ReceiveStop) {
+
+ CurrentCardLoc = Adapt->ReceiveStart;
+
+ }
+
+
+ }
+
+ //
+ // Turn off 16 bit memory access
+ //
+
+ if (Adapt->board_id & SLOT_16BIT) {
+
+ IF_LMI_LOUD(DbgPrint("Writing 0x%x to LAAR\n",Adapt->LaarHold));
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + LA_ADDRESS_REG,
+ Adapt->LaarHold
+ );
+
+ }
+
+
+ return SUCCESS;
+
+}
+
+BOOLEAN
+SyncGetCurrent(
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ This function is used to synchronize with the interrupt, switching
+ to page 1 to get the current pointer and then switching back to page 0.
+
+Arguments:
+
+ see NDIS 3.0 spec.
+
+Notes:
+
+ returns TRUE on success, else FALSE.
+
+--*/
+{
+ Ptr_Adapter_Struc Adapt = (Ptr_Adapter_Struc)Context;
+
+ //
+ // Select Page 1
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + COMMAND_REG,
+ REMOTE_ABORT_COMPLETE | PAGE_SELECT_1
+ );
+
+ //
+ // Get CURRENT buffer pointer
+ //
+
+ NdisReadPortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + CURRENT_BUFFER_REG,
+ &(Adapt->Current)
+ );
+
+ //
+ // Select Page 0
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + COMMAND_REG,
+ REMOTE_ABORT_COMPLETE
+ );
+
+ return(TRUE);
+}
+
+BOOLEAN
+SyncSetAllMulticast(
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ This function is used to synchronize with the interrupt, switching
+ to page 1 to set the mulitcast filter then switching back to page 0.
+
+Arguments:
+
+ see NDIS 3.0 spec.
+
+Notes:
+
+ returns TRUE on success, else FALSE.
+
+--*/
+{
+ Ptr_Adapter_Struc Adapt = (Ptr_Adapter_Struc)Context;
+ UCHAR i;
+
+
+ //
+ // Select Page 1
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + COMMAND_REG,
+ REMOTE_ABORT_COMPLETE | PAGE_SELECT_1
+ );
+
+ //
+ // Set Filter to accept all multicast packets and we let
+ // the filter package figure it all out. (690 does not
+ // have these registers, 8390 does.)
+ //
+
+ for (i = MULTICAST_ADDRESS_REG0; i <= MULTICAST_ADDRESS_REG7; i++) {
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + i,
+ 0xFF
+ );
+
+ }
+
+
+ //
+ // Select Page 0
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + COMMAND_REG,
+ REMOTE_ABORT_COMPLETE
+ );
+
+ return(TRUE);
+}
+
+
+BOOLEAN
+SyncClearMulticast(
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ This function is used to synchronize with the interrupt, switching
+ to page 1 to set the mulitcast filter then switching back to page 0.
+
+Arguments:
+
+ see NDIS 3.0 spec.
+
+Notes:
+
+ returns TRUE on success, else FALSE.
+
+--*/
+{
+ Ptr_Adapter_Struc Adapt = (Ptr_Adapter_Struc)Context;
+ UCHAR i;
+
+
+ //
+ // Select Page 1
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + COMMAND_REG,
+ REMOTE_ABORT_COMPLETE | PAGE_SELECT_1
+ );
+
+ //
+ // Accept no mulitcast addresses.
+ //
+
+ for (i = MULTICAST_ADDRESS_REG0; i <= MULTICAST_ADDRESS_REG7; i++) {
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + i,
+ 0x00
+ );
+
+ }
+
+
+ //
+ // Select Page 0
+ //
+
+ NdisWritePortUchar(Adapt->NdisAdapterHandle,
+ Adapt->io_base + COMMAND_REG,
+ REMOTE_ABORT_COMPLETE
+ );
+
+ return(TRUE);
+}
+
diff --git a/private/ntos/ndis/wd/makefile b/private/ntos/ndis/wd/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/wd/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/wd/sources b/private/ntos/ndis/wd/sources
new file mode 100644
index 000000000..02968a4f2
--- /dev/null
+++ b/private/ntos/ndis/wd/sources
@@ -0,0 +1,44 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=smcisa
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+INCLUDES=..\..\inc
+
+SOURCES=wd.c \
+ umi.c \
+ lmi.c \
+ wdlan.rc
+
+RELATIVE_DEPTH=..\..
+
+MSC_WARNING_LEVEL=/W3 /WX
+
diff --git a/private/ntos/ndis/wd/umi.c b/private/ntos/ndis/wd/umi.c
new file mode 100644
index 000000000..2fcf9ed2c
--- /dev/null
+++ b/private/ntos/ndis/wd/umi.c
@@ -0,0 +1,347 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ umi.c
+
+Abstract:
+
+ Upper MAC Interface functions for the NDIS 3.0 Western Digital driver.
+
+Author:
+
+ Sean Selitrennikoff (seanse) 15-Jan-92
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+#include <efilter.h>
+#include "wdlmi.h"
+#include "wdhrd.h"
+#include "wdsft.h"
+#include "wdumi.h"
+
+
+
+#if DBG
+
+extern UCHAR WdDebugLog[];
+extern UCHAR WdDebugLogPlace;
+
+#define IF_LOG(A) A
+
+extern
+VOID
+LOG (UCHAR A);
+
+#else
+
+#define IF_LOG(A)
+
+#endif
+
+
+LM_STATUS
+UM_Send_Complete(
+ LM_STATUS Status,
+ Ptr_Adapter_Struc Adapt
+ )
+/*++
+
+Routine Description:
+
+ This routine is called back when the packet on the front of
+ PacketsOnCard has been fully transmitted by the Lower MAC.
+
+
+ NOTE: The lock is held before the LM_ routines are called and
+ therefore held at the beginning of this call.
+
+Arguments:
+
+ Status - Status of the send.
+
+ Adapt - A pointer to an LMI adapter structure.
+
+Return:
+
+ SUCCESS
+ EVENTS_DISABLED
+
+--*/
+{
+
+ PWD_ADAPTER Adapter = PWD_ADAPTER_FROM_Ptr_Adapter_Struc(Adapt);
+ PWD_OPEN Open;
+ PNDIS_PACKET Packet;
+
+ //
+ // Remove packet from front of queue. If the complete queue is empty
+ // then we have nothing to complete. This shouldn't really happen but
+ // there is a window where it could.
+ //
+
+ IF_LOG(LOG('c'));
+
+ if ( (Packet = Adapter->PacketsOnCard) != NULL ) {
+
+ Adapter->WakeUpTimeout = FALSE;
+
+ Adapter->PacketsOnCard = RESERVED(Packet)->NextPacket;
+
+ if ( Adapter->PacketsOnCard == NULL ) {
+
+ Adapter->PacketsOnCardTail = NULL;
+
+ }
+
+ Open = RESERVED(Packet)->Open;
+
+ IF_LOUD( DbgPrint("Completing send for open 0x%lx\n",Open);)
+
+ if ( RESERVED(Packet)->Loopback ) {
+
+ //
+ // Put packet on loopback
+ //
+
+ if ( Adapter->LoopbackQueue == NULL ) {
+
+ Adapter->LoopbackQueue = Adapter->LoopbackQTail = Packet;
+
+ } else {
+
+ RESERVED(Adapter->LoopbackQTail)->NextPacket = Packet;
+
+ Adapter->LoopbackQTail = Packet;
+
+ }
+
+ RESERVED(Packet)->NextPacket = NULL;
+
+ } else {
+
+ IF_LOUD( DbgPrint("Not a loopback packet\n");)
+
+ //
+ // Complete send
+ //
+
+ if ( Status == SUCCESS ) {
+
+ Adapter->FramesXmitGood++;
+
+ } else {
+
+ Adapter->FramesXmitBad++;
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteSend(Open->NdisBindingContext,
+ Packet,
+ (Status == SUCCESS ? NDIS_STATUS_SUCCESS
+ : NDIS_STATUS_FAILURE)
+ );
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ WdRemoveReference(Open);
+
+ }
+ }
+
+ //
+ // If there are any sends waiting and there is not a reset to be
+ // done, queue them up
+ //
+
+ if ( (Adapter->XmitQueue != NULL) && !(Adapter->ResetRequested) ) {
+
+ //
+ // Remove packet from front.
+ //
+
+ Packet = Adapter->XmitQueue;
+
+ Adapter->XmitQueue = RESERVED(Packet)->NextPacket;
+
+ if (Adapter->XmitQueue == NULL) {
+
+ Adapter->XmitQTail = NULL;
+
+ }
+
+ //
+ // Start packet send.
+ //
+
+ IF_LOG(LOG('t'));
+
+ Status = LM_Send(Packet, Adapt);
+
+ if (Status == OUT_OF_RESOURCES) {
+
+ IF_LOG(LOG('2'));
+
+ //
+ // Put packet back on xmit queue.
+ //
+
+ if (Adapter->XmitQueue != NULL) {
+
+ RESERVED(Packet)->NextPacket = Adapter->XmitQueue;
+
+ Adapter->XmitQueue = Packet;
+
+ } else {
+
+ Adapter->XmitQueue = Packet;
+
+ Adapter->XmitQTail = Packet;
+
+ }
+
+ } else if (Status == SUCCESS) {
+
+ //
+ // Put packet at end of card list.
+ //
+
+ IF_LOG(LOG('3'));
+
+ if (Adapter->PacketsOnCard == NULL) {
+
+ Adapter->PacketsOnCard = Adapter->PacketsOnCardTail = Packet;
+
+ } else {
+
+ RESERVED(Adapter->PacketsOnCardTail)->NextPacket = Packet;
+
+ Adapter->PacketsOnCardTail = Packet;
+
+ }
+
+ ASSERT(Adapter->PacketsOnCard != NULL);
+
+ RESERVED(Packet)->NextPacket = NULL;
+
+ }
+
+ }
+
+ IF_LOG(LOG('C'));
+
+ return(SUCCESS);
+}
+
+
+LM_STATUS
+UM_Receive_Packet(
+ ULONG PacketSize,
+ Ptr_Adapter_Struc Adapt
+ )
+/*++
+
+Routine Description:
+
+ This routine is called whenever the lower MAC receives a packet.
+
+
+Arguments:
+
+ PacketSize - Total size of the packet
+
+ Adapt - A pointer to an LMI adapter structure.
+
+Return:
+
+ SUCCESS
+ EVENTS_DISABLED
+
+--*/
+{
+ PWD_ADAPTER Adapter = PWD_ADAPTER_FROM_Ptr_Adapter_Struc(Adapt);
+ ULONG IndicateLen;
+
+ Adapter->WakeUpTimeout = FALSE;
+
+ //
+ // Setup for indication
+ //
+
+ Adapter->IndicatedAPacket = TRUE;
+
+ Adapter->IndicatingPacket = (PNDIS_PACKET)NULL;
+
+ IndicateLen = ((Adapter->MaxLookAhead + WD_HEADER_SIZE) > PacketSize ?
+ PacketSize :
+ Adapter->MaxLookAhead + WD_HEADER_SIZE
+ );
+
+ if (LM_Receive_Lookahead(
+ IndicateLen,
+ 0,
+ Adapter->LookAhead,
+ &(Adapter->LMAdapter)) != SUCCESS) {
+
+ return(SUCCESS);
+
+ }
+
+ //
+ // Indicate packet
+ //
+
+ Adapter->FramesRcvGood++;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ if (PacketSize < WD_HEADER_SIZE) {
+
+ if (PacketSize >= ETH_LENGTH_OF_ADDRESS) {
+
+ //
+ // Runt packet
+ //
+
+ EthFilterIndicateReceive(
+ Adapt->FilterDB,
+ (NDIS_HANDLE)Adapter,
+ (PCHAR)Adapter->LookAhead,
+ Adapter->LookAhead,
+ PacketSize,
+ NULL,
+ 0,
+ 0
+ );
+
+ }
+
+ } else {
+
+ EthFilterIndicateReceive(
+ Adapt->FilterDB,
+ (NDIS_HANDLE)Adapter,
+ (PCHAR)Adapter->LookAhead,
+ Adapter->LookAhead,
+ WD_HEADER_SIZE,
+ Adapter->LookAhead + WD_HEADER_SIZE,
+ IndicateLen - WD_HEADER_SIZE,
+ PacketSize - WD_HEADER_SIZE
+ );
+ }
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ return(SUCCESS);
+}
diff --git a/private/ntos/ndis/wd/wd.c b/private/ntos/ndis/wd/wd.c
new file mode 100644
index 000000000..289770e76
--- /dev/null
+++ b/private/ntos/ndis/wd/wd.c
@@ -0,0 +1,4599 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ wd.c
+
+Abstract:
+
+ This is the main file for the Western Digital
+ Ethernet controller. This driver conforms to the NDIS 3.1 interface.
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 15-Jan-1992
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+#include <efilter.h>
+#include <wdhrd.h>
+#include <wdlmireg.h>
+#include <wdlmi.h>
+#include <wdsft.h>
+#include "keywords.h"
+
+#if DBG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+static UCHAR WdBroadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+#if DBG
+
+
+#define LOGSIZE 512
+
+extern UCHAR WdDebugLog[LOGSIZE] = {0};
+extern UINT WdDebugLogPlace = 0;
+
+
+extern
+VOID
+LOG (UCHAR A) {
+ WdDebugLog[WdDebugLogPlace++] = A;
+ WdDebugLog[(WdDebugLogPlace + 4) % LOGSIZE] = '\0';
+ if (WdDebugLogPlace >= LOGSIZE) WdDebugLogPlace = 0;
+}
+
+
+ULONG WdDebugFlag= WD_DEBUG_LOG; // WD_DEBUG_LOG | WD_DEBUG_LOUD | WD_DEBUG_VERY_LOUD;
+
+#define IF_LOG(A) A
+
+#else
+
+#define IF_LOG(A)
+
+#endif
+
+
+//
+// This constant is used for places where NdisAllocateMemory
+// needs to be called and the HighestAcceptableAddress does
+// not matter.
+//
+
+NDIS_PHYSICAL_ADDRESS HighestAcceptableMax =
+ NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
+
+
+
+//
+// The global MAC block.
+//
+
+extern MAC_BLOCK WdMacBlock={0};
+
+
+
+//
+// If you add to this, make sure to add the
+// a case in WdFillInGlobalData() and in
+// WdQueryGlobalStatistics() if global
+// information only or
+// WdQueryProtocolStatistics() if it is
+// protocol queriable information.
+//
+UINT WdGlobalSupportedOids[] = {
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ OID_802_3_RCV_ERROR_ALIGNMENT,
+ OID_802_3_XMIT_ONE_COLLISION,
+ OID_802_3_XMIT_MORE_COLLISIONS
+ };
+
+//
+// If you add to this, make sure to add the
+// a case in WdQueryGlobalStatistics() and in
+// WdQueryProtocolInformation()
+//
+UINT WdProtocolSupportedOids[] = {
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE
+ };
+
+
+
+
+
+
+
+UINT
+WdCopyOver(
+ OUT PUCHAR Buf, // destination
+ IN PNDIS_PACKET Packet, // source packet
+ IN UINT Offset, // offset in packet
+ IN UINT Length // number of bytes to copy
+ );
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+
+
+#pragma NDIS_INIT_FUNCTION(DriverEntry)
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+/*++
+
+Routine Description:
+
+ This is the transfer address of the driver. It initializes
+ WdMacBlock and calls NdisInitializeWrapper() and
+ NdisRegisterMac().
+
+Arguments:
+
+Return Value:
+
+ Indicates the success or failure of the initialization.
+
+--*/
+
+{
+ PMAC_BLOCK NewMacP = &WdMacBlock;
+ NDIS_STATUS Status;
+ NDIS_HANDLE NdisWrapperHandle;
+
+#ifdef NDIS_NT
+ NDIS_STRING MacName = NDIS_STRING_CONST("Smc8000n");
+#endif
+
+#ifdef NDIS_WIN
+ NDIS_STRING MacName = NDIS_STRING_CONST("SMC8000W");
+#endif
+
+#if NDIS_WIN
+ UCHAR pIds[sizeof (EISA_MCA_ADAPTER_IDS) + 8 * sizeof (USHORT)];
+#endif
+
+#if NDIS_WIN
+ ((PEISA_MCA_ADAPTER_IDS)pIds)->nEisaAdapters=0;
+ ((PEISA_MCA_ADAPTER_IDS)pIds)->nMcaAdapters=9;
+
+ *((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 0)=CNFG_ID_8003E;
+ *((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 1)=CNFG_ID_8003S;
+ *((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 2)=CNFG_ID_8003W;
+ *((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 3)=CNFG_ID_BISTRO03E;
+ *((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 4)=CNFG_ID_8013E;
+ *((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 5)=CNFG_ID_8013W;
+ *((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 6)=CNFG_ID_BISTRO13E;
+ *((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 7)=CNFG_ID_BISTRO13W;
+
+
+ (PVOID) DriverObject = (PVOID) pIds;
+#endif
+
+ //
+ // Ensure that the MAC_RESERVED structure will fit in the
+ // MacReserved section of a packet.
+ //
+
+ ASSERT(sizeof(MAC_RESERVED) <= sizeof(((PNDIS_PACKET)NULL)->MacReserved));
+
+
+ //
+ // Pass the wrapper a pointer to the device object.
+ //
+
+ NdisInitializeWrapper(&NdisWrapperHandle,
+ DriverObject,
+ RegistryPath,
+ NULL
+ );
+
+ //
+ // Set up the driver object.
+ //
+
+ NewMacP->DriverObject = DriverObject;
+
+ NdisAllocateSpinLock(&NewMacP->SpinLock);
+
+ NewMacP->NdisWrapperHandle = NdisWrapperHandle;
+ NewMacP->Unloading = FALSE;
+ NewMacP->NumAdapters = 0;
+ NewMacP->AdapterQueue = (PWD_ADAPTER)NULL;
+
+
+ //
+ // Prepare to call NdisRegisterMac.
+ //
+
+ NewMacP->MacCharacteristics.MajorNdisVersion = WD_NDIS_MAJOR_VERSION;
+ NewMacP->MacCharacteristics.MinorNdisVersion = WD_NDIS_MINOR_VERSION;
+ NewMacP->MacCharacteristics.Reserved = 0;
+ NewMacP->MacCharacteristics.OpenAdapterHandler = WdOpenAdapter;
+ NewMacP->MacCharacteristics.CloseAdapterHandler = WdCloseAdapter;
+ NewMacP->MacCharacteristics.SendHandler = WdSend;
+ NewMacP->MacCharacteristics.TransferDataHandler = WdTransferData;
+ NewMacP->MacCharacteristics.ResetHandler = WdReset;
+ NewMacP->MacCharacteristics.RequestHandler = WdRequest;
+ NewMacP->MacCharacteristics.QueryGlobalStatisticsHandler =
+ WdQueryGlobalStatistics;
+ NewMacP->MacCharacteristics.UnloadMacHandler = WdUnload;
+ NewMacP->MacCharacteristics.AddAdapterHandler = WdAddAdapter;
+ NewMacP->MacCharacteristics.RemoveAdapterHandler = WdRemoveAdapter;
+
+ NewMacP->MacCharacteristics.Name = MacName;
+
+ NdisRegisterMac(&Status,
+ &NewMacP->NdisMacHandle,
+ NdisWrapperHandle,
+ (NDIS_HANDLE)&WdMacBlock,
+ &NewMacP->MacCharacteristics,
+ sizeof(NewMacP->MacCharacteristics));
+
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ //
+ // NdisRegisterMac failed.
+ //
+
+ NdisFreeSpinLock(&NewMacP->SpinLock);
+ NdisTerminateWrapper(NdisWrapperHandle, NULL);
+ IF_LOUD( DbgPrint( "NdisRegisterMac failed with code 0x%x\n", Status );)
+ return Status;
+ }
+
+
+ IF_LOUD( DbgPrint( "NdisRegisterMac succeeded\n" );)
+
+ IF_LOUD( DbgPrint("Adapter Initialization Complete\n");)
+
+ return Status;
+
+}
+
+
+
+#pragma NDIS_INIT_FUNCTION(WdAddAdapter)
+
+NDIS_STATUS
+WdAddAdapter(
+ IN NDIS_HANDLE MacMacContext,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING AdapterName
+ )
+/*++
+Routine Description:
+
+ This is the Wd MacAddAdapter routine. The system calls this routine
+ to add support for a particular WD adapter. This routine extracts
+ configuration information from the configuration data base and registers
+ the adapter with NDIS.
+
+Arguments:
+
+ see NDIS 3.0 spec...
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS - Adapter was successfully added.
+ NDIS_STATUS_FAILURE - Adapter was not added, also MAC deregistered.
+
+--*/
+{
+
+ LM_STATUS LmStatus;
+ NDIS_HANDLE ConfigHandle;
+ PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
+ NDIS_STRING IOAddressStr = IOBASE;
+ NDIS_STRING MaxMulticastListStr = MAXMULTICASTLIST;
+ NDIS_STRING NetworkAddressStr = NETADDRESS;
+ NDIS_STRING BusTypeStr = NDIS_STRING_CONST("BusType");
+ NDIS_STRING MediaTypeStr = NDIS_STRING_CONST("MediaType");
+ NDIS_STRING MaxPacketSizeStr = NDIS_STRING_CONST("MaximumPacketSize");
+ NDIS_STRING InterruptStr = INTERRUPT;
+ NDIS_STRING MemoryBaseAddrStr = MEMMAPPEDBASEADDRESS;
+
+ ULONG ConfigErrorValue = 0;
+ BOOLEAN ConfigError = FALSE;
+
+ USHORT WdIoBaseAddr = DEFAULT_IOBASEADDR;
+ UCHAR WdBusType = 0; // AT bus, 1 == MCA;
+ UCHAR CurrentAddress[ETH_LENGTH_OF_ADDRESS] = {0x00};
+ PVOID NetAddress;
+ ULONG Length;
+ UINT MaxMulticastList = DEFAULT_MULTICASTLISTMAX;
+
+ PMAC_BLOCK NewMacP = &WdMacBlock;
+ NDIS_STATUS Status;
+ PWD_ADAPTER Adapter;
+ NDIS_ADAPTER_INFORMATION AdapterInformation; // needed to register adapter
+
+
+ UNREFERENCED_PARAMETER(MacMacContext);
+
+ NdisOpenConfiguration(
+ &Status,
+ &ConfigHandle,
+ ConfigurationHandle
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ //
+ // Read MaxMulticastList
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &MaxMulticastListStr,
+ NdisParameterInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ MaxMulticastList = ReturnedValue->ParameterData.IntegerData;
+
+ }
+
+ //
+ // Read Bus Type
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &BusTypeStr,
+ NdisParameterHexInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ if (ReturnedValue->ParameterData.IntegerData == NdisInterfaceMca) {
+
+ WdBusType = 1;
+
+ } else {
+
+ WdBusType = 0;
+
+ }
+
+ }
+
+
+ //
+ // Read Io Base Address (if Appropriate)
+ //
+
+ if (WdBusType != 1) {
+
+ //
+ // Read I/O Address
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &IOAddressStr,
+ NdisParameterHexInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ WdIoBaseAddr = (USHORT)(ReturnedValue->ParameterData.IntegerData);
+
+ }
+
+ }
+
+ //
+ // Read net address
+ //
+
+ NdisReadNetworkAddress(
+ &Status,
+ &NetAddress,
+ &Length,
+ ConfigHandle
+ );
+
+ if ((Length == ETH_LENGTH_OF_ADDRESS) && (Status == NDIS_STATUS_SUCCESS)) {
+
+ ETH_COPY_NETWORK_ADDRESS(
+ CurrentAddress,
+ NetAddress
+ );
+
+ }
+
+RegisterAdapter:
+
+ //
+ // Allocate memory for the adapter block now.
+ //
+
+ Status = NdisAllocateMemory( (PVOID *)&Adapter, sizeof(WD_ADAPTER), 0, HighestAcceptableMax);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ ConfigError = TRUE;
+ ConfigErrorValue = NDIS_ERROR_CODE_OUT_OF_RESOURCES;
+
+ goto RegisterAdapter;
+
+ }
+
+
+ NdisZeroMemory(Adapter,sizeof(WD_ADAPTER));
+
+ if (!ConfigError && (WdBusType == 1)) {
+
+ if (LM_Get_Mca_Io_Base_Address(
+ &(Adapter->LMAdapter),
+ ConfigurationHandle,
+ &WdIoBaseAddr
+ )) {
+
+ WdIoBaseAddr = 0;
+ ConfigError = TRUE;
+ ConfigErrorValue = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION;
+
+ }
+
+ }
+
+ //
+ // The adapter is initialized, register it with NDIS.
+ // This must occur before interrupts are enabled since the
+ // InitializeInterrupt routine requires the NdisAdapterHandle
+ //
+
+ //
+ // Set up the AdapterInformation structure; zero it
+ // first in case it is extended later.
+ //
+
+ NdisZeroMemory (&AdapterInformation, sizeof(NDIS_ADAPTER_INFORMATION));
+ AdapterInformation.AdapterType = (WdBusType == 1)?
+ NdisInterfaceMca:
+ NdisInterfaceIsa;
+ AdapterInformation.NumberOfPortDescriptors = 1;
+ AdapterInformation.PortDescriptors[0].InitialPort = (ULONG)WdIoBaseAddr;
+ AdapterInformation.PortDescriptors[0].NumberOfPorts = 0x20;
+
+
+ Status = NdisRegisterAdapter(&Adapter->LMAdapter.NdisAdapterHandle,
+ WdMacBlock.NdisMacHandle,
+ (NDIS_HANDLE)Adapter,
+ ConfigurationHandle,
+ AdapterName,
+ &AdapterInformation
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ //
+ // NdisRegisterAdapter failed.
+ //
+
+ NdisCloseConfiguration(ConfigHandle);
+
+ NdisFreeMemory(Adapter, sizeof(WD_ADAPTER), 0);
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+
+ if (ConfigError) {
+
+ //
+ // Log Error and exit.
+ //
+
+ NdisWriteErrorLogEntry(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ ConfigErrorValue,
+ 1
+ );
+
+ NdisCloseConfiguration(ConfigHandle);
+
+ NdisDeregisterAdapter(Adapter->LMAdapter.NdisAdapterHandle);
+
+ NdisFreeMemory(Adapter, sizeof(WD_ADAPTER), 0);
+
+ return(NDIS_STATUS_FAILURE);
+
+ }
+
+ Adapter->LMAdapter.io_base = WdIoBaseAddr;
+ Adapter->LMAdapter.bus_type = WdBusType;
+
+ LmStatus = LM_Get_Config(&(Adapter->LMAdapter));
+
+ if (LmStatus == ADAPTER_NOT_FOUND) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
+ 0
+ );
+
+ NdisCloseConfiguration(ConfigHandle);
+
+ NdisDeregisterAdapter(Adapter->LMAdapter.NdisAdapterHandle);
+ NdisFreeMemory(Adapter, sizeof(WD_ADAPTER), 0);
+
+ return(NDIS_STATUS_FAILURE);
+
+ }
+
+ if (LmStatus == ADAPTER_NO_CONFIG) {
+
+ //
+ // Read any information from the registry which might help
+ //
+
+
+ //
+ // Read Interrupt
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &InterruptStr,
+ NdisParameterInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ Adapter->LMAdapter.irq_value = (USHORT)(ReturnedValue->ParameterData.IntegerData);
+
+ }
+
+
+
+ //
+ // Read MemoryBaseAddress
+ //
+
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &MemoryBaseAddrStr,
+ NdisParameterHexInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+#if NDIS_NT
+ Adapter->LMAdapter.ram_base = (ULONG)(ReturnedValue->ParameterData.IntegerData);
+#else
+ Adapter->LMAdapter.ram_base = (ULONG)((ReturnedValue->ParameterData.IntegerData) << 4);
+#endif
+
+ }
+
+
+ }
+
+ NdisCloseConfiguration(ConfigHandle);
+
+
+ if (WdRegisterAdapter(Adapter,
+ DEFAULT_NUMBUFFERS,
+ MaxMulticastList,
+ CurrentAddress
+ )
+ != NDIS_STATUS_SUCCESS) {
+
+
+
+ //
+ // WdRegisterAdapter failed.
+ //
+
+ NdisDeregisterAdapter(Adapter->LMAdapter.NdisAdapterHandle);
+ NdisFreeMemory(Adapter, sizeof(WD_ADAPTER), 0);
+ return NDIS_STATUS_FAILURE;
+ }
+
+
+
+ IF_LOUD( DbgPrint( "WdRegisterAdapter succeeded\n" );)
+
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+
+#pragma NDIS_INIT_FUNCTION(WdRegisterAdapter)
+
+NDIS_STATUS
+WdRegisterAdapter(
+ IN PWD_ADAPTER Adapter,
+ IN UINT NumBuffers,
+ IN UINT MulticastListMax,
+ IN UCHAR NodeAddress[ETH_LENGTH_OF_ADDRESS]
+ )
+
+/*++
+
+
+Routine Description:
+
+ Called when a new adapter should be registered. It allocates space for
+ the adapter and open blocks, initializes the adapters block, and
+ calls NdisRegisterAdapter().
+
+Arguments:
+
+ Adapter - A pointer to the adapter structure.
+ NumBuffers - Number of transmit buffers.
+ MulticastListMax - Number of multicast list addresses allowed.
+ NodeAddress - Ethernet address for this adapter. if all 0x00 then the
+ permanent address on the card is used.
+
+Return Value:
+
+ Indicates the success or failure of the registration.
+
+--*/
+
+{
+ UINT i;
+ CHAR KernelInterrupt;
+ NDIS_PHYSICAL_ADDRESS PhysicalAddress;
+
+ NDIS_STATUS status; //general purpose return from NDIS calls
+
+
+ Adapter->MulticastListMax = MulticastListMax;
+
+ //
+ // check that NumBuffers <= MAX_XMIT_BUFS
+ //
+
+ if (NumBuffers > MAX_XMIT_BUFS) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+
+ status = NDIS_STATUS_RESOURCES;
+
+ goto fail1;
+
+ }
+
+
+ Adapter->OpenQueue = (PWD_OPEN)NULL;
+
+ //
+ // Allocate the Spin lock.
+ //
+ NdisAllocateSpinLock(&Adapter->Lock);
+
+
+ //
+ // Initialize Transmit information
+ //
+
+ Adapter->DeferredDpc = (PVOID) WdInterruptDpc;
+
+ //
+ // Initialize References.
+ //
+
+ NdisInitializeTimer(&(Adapter->DeferredTimer),
+ Adapter->DeferredDpc,
+ Adapter);
+
+ //
+ // Link us on to the chain of adapters for this MAC.
+ //
+
+ Adapter->MacBlock = &WdMacBlock;
+ NdisAcquireSpinLock(&WdMacBlock.SpinLock);
+ Adapter->NextAdapter = WdMacBlock.AdapterQueue;
+ WdMacBlock.AdapterQueue = Adapter;
+ NdisReleaseSpinLock(&WdMacBlock.SpinLock);
+
+ //
+ // Set up the interrupt handlers.
+ //
+
+ KernelInterrupt = (CCHAR)(Adapter->LMAdapter.irq_value);
+
+ NdisInitializeInterrupt(&status, // status of call
+ &(Adapter->LMAdapter.NdisInterrupt), // interrupt info str
+ Adapter->LMAdapter.NdisAdapterHandle,
+ (PNDIS_INTERRUPT_SERVICE) WdInterruptHandler,
+ Adapter, // context for ISR, DPC
+ (PNDIS_DEFERRED_PROCESSING) WdInterruptDpc,
+ KernelInterrupt, // int #
+ KernelInterrupt, // IRQL
+ FALSE, // NOT shared
+ (Adapter->LMAdapter.bus_type == 0) ?
+ NdisInterruptLatched : // ATBus
+ NdisInterruptLevelSensitive // MCA
+ );
+
+
+ if (status != NDIS_STATUS_SUCCESS) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ NDIS_ERROR_CODE_INTERRUPT_CONNECT,
+ 0
+ );
+
+ goto fail3;
+ }
+
+ IF_LOUD( DbgPrint("Interrupt Connected\n");)
+
+ //
+ // Map the memory mapped portion of the card.
+ //
+ //
+
+ NdisSetPhysicalAddressHigh(PhysicalAddress, 0);
+ NdisSetPhysicalAddressLow(PhysicalAddress, (ULONG)(Adapter->LMAdapter.ram_base));
+
+ NdisMapIoSpace(&status,
+ &Adapter->LMAdapter.ram_access,
+ Adapter->LMAdapter.NdisAdapterHandle,
+ PhysicalAddress,
+ Adapter->LMAdapter.ram_size * 1024);
+
+ if (status != NDIS_STATUS_SUCCESS) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ NDIS_ERROR_CODE_RESOURCE_CONFLICT,
+ 0
+ );
+
+ goto failmap;
+
+ }
+
+
+ //
+ // Now Initialize the card.
+ //
+
+ //
+ // Set Relevant variables first...
+ //
+ // base_io and ram_size are set from LM_Get_Config.
+ //
+ //
+ //
+ // ram_access, node_address, max_packet_size, buffer_page_size,
+ // num_of_tx_buffs and receive_mask need to be set.
+ //
+
+ for (i = 0; i < 6 ; i ++) {
+
+ Adapter->LMAdapter.node_address[i] = NodeAddress[i];
+
+ }
+
+ Adapter->LMAdapter.max_packet_size = WD_MAX_PACKET_SIZE;
+ Adapter->LMAdapter.buffer_page_size= WD_BUFFER_PAGE_SIZE;
+ Adapter->LMAdapter.num_of_tx_buffs = (USHORT)NumBuffers;
+
+ Adapter->LMAdapter.ptr_rx_CRC_errors = &(Adapter->CrcErrors);
+ Adapter->LMAdapter.ptr_rx_too_big = &(Adapter->TooBig);
+ Adapter->LMAdapter.ptr_rx_lost_pkts = &(Adapter->MissedPackets);
+ Adapter->LMAdapter.ptr_rx_align_errors = &(Adapter->FrameAlignmentErrors);
+ Adapter->LMAdapter.ptr_rx_overruns = &(Adapter->Overruns);
+
+ Adapter->LMAdapter.ptr_tx_deferred = &(Adapter->FramesXmitDeferred);
+ Adapter->LMAdapter.ptr_tx_max_collisions = &(Adapter->FramesXmitBad);
+ Adapter->LMAdapter.ptr_tx_one_collision = &(Adapter->FramesXmitOneCollision);
+ Adapter->LMAdapter.ptr_tx_mult_collisions = &(Adapter->FramesXmitManyCollisions);
+ Adapter->LMAdapter.ptr_tx_ow_collision = &(Adapter->FramesXmitOverWrite);
+ Adapter->LMAdapter.ptr_tx_CD_heartbeat = &(Adapter->FramesXmitHeartbeat);
+ Adapter->LMAdapter.ptr_tx_underruns = &(Adapter->FramesXmitUnderruns);
+ Adapter->LMAdapter.FilterDB = NULL;
+
+ if (LM_Initialize_Adapter(&(Adapter->LMAdapter)) != SUCCESS){
+
+ //
+ // The Card could not be written to.
+ //
+
+ Adapter->HardwareFailure = TRUE;
+
+ NdisWriteErrorLogEntry(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 0
+ );
+
+ status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+
+ goto fail6;
+ }
+
+
+ //
+ // Initialize Filter Database
+ //
+
+ if (!EthCreateFilter(MulticastListMax,
+ WdChangeMulticastAddresses,
+ WdChangeFilterClasses,
+ WdCloseAction,
+ Adapter->LMAdapter.node_address,
+ &Adapter->Lock,
+ &Adapter->LMAdapter.FilterDB
+ )) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+
+ status = NDIS_STATUS_FAILURE;
+
+ goto fail6;
+
+ }
+
+ //
+ // Initialize the wake up timer to catch interrupts that
+ // don't complete. It fires continuously
+ // every 5 seconds, and we check if there are any
+ // uncompleted operations from the previous two-second
+ // period.
+ //
+
+ Adapter->WakeUpDpc = (PVOID)WdWakeUpDpc;
+
+ NdisInitializeTimer(&Adapter->WakeUpTimer,
+ (PVOID)(Adapter->WakeUpDpc),
+ Adapter );
+
+ NdisSetTimer(
+ &Adapter->WakeUpTimer,
+ 5000
+ );
+
+ //
+ // Initialization completed successfully.
+ //
+
+ IF_LOUD( { DbgPrint(" WdLan: [OK]\n");})
+
+ return NDIS_STATUS_SUCCESS;
+
+
+ //
+ // Code to unwind what has already been set up when a part of
+ // initialization fails, which is jumped into at various
+ // points based on where the failure occured. Jumping to
+ // a higher-numbered failure point will execute the code
+ // for that block and all lower-numbered ones.
+ //
+
+fail6:
+
+ NdisUnmapIoSpace(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ Adapter->LMAdapter.ram_access,
+ Adapter->LMAdapter.ram_size * 1024);
+
+failmap:
+
+ NdisRemoveInterrupt(&(Adapter->LMAdapter.NdisInterrupt));
+
+ NdisAcquireSpinLock(&WdMacBlock.SpinLock);
+
+ //
+ // Take us out of the AdapterQueue.
+ //
+
+ if (WdMacBlock.AdapterQueue == Adapter) {
+
+ WdMacBlock.AdapterQueue = Adapter->NextAdapter;
+
+ } else {
+
+ PWD_ADAPTER TmpAdapter = WdMacBlock.AdapterQueue;
+
+ while (TmpAdapter->NextAdapter != Adapter) {
+
+ TmpAdapter = TmpAdapter->NextAdapter;
+
+ }
+
+ TmpAdapter->NextAdapter = TmpAdapter->NextAdapter->NextAdapter;
+ }
+
+ NdisReleaseSpinLock(&WdMacBlock.SpinLock);
+
+fail3:
+ NdisFreeSpinLock(&Adapter->Lock);
+
+fail1:
+
+ return status;
+}
+
+
+#pragma NDIS_PAGABLE_FUNCTION(WdOpenAdapter)
+
+
+NDIS_STATUS
+WdOpenAdapter(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT NDIS_HANDLE * MacBindingHandle,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_HANDLE MacAdapterContext,
+ IN UINT OpenOptions,
+ IN PSTRING AddressingInformation OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ NDIS function. It initializes the open block and links it in
+ the appropriate lists.
+
+Arguments:
+
+ See NDIS 3.0 spec.
+
+--*/
+
+{
+ PWD_ADAPTER Adapter = ((PWD_ADAPTER)MacAdapterContext);
+ PWD_OPEN NewOpen;
+ NDIS_STATUS Status;
+
+ //
+ // Don't use extended error or OpenOptions for Wd
+ //
+
+ UNREFERENCED_PARAMETER(OpenOptions);
+
+ *OpenErrorStatus=NDIS_STATUS_SUCCESS;
+
+ IF_LOUD( DbgPrint("In Open Adapter\n");)
+
+ //
+ // Scan the media list for our media type (802.3)
+ //
+
+ *SelectedMediumIndex = (UINT)(-1);
+
+ while (MediumArraySize > 0) {
+
+ if (MediumArray[--MediumArraySize] == NdisMedium802_3 ) {
+
+ *SelectedMediumIndex = MediumArraySize;
+
+ break;
+ }
+ }
+
+
+ if (*SelectedMediumIndex == -1) {
+
+ return NDIS_STATUS_UNSUPPORTED_MEDIA;
+
+ }
+
+ //
+ // Link this open to the appropriate lists.
+ //
+
+ if (Adapter->HardwareFailure) {
+
+ return(NDIS_STATUS_FAILURE);
+
+ }
+
+ //
+ // Allocate memory for the open.
+ //
+
+
+ Status = NdisAllocateMemory((PVOID *)&NewOpen, sizeof(WD_OPEN), 0, HighestAcceptableMax);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+
+ return(NDIS_STATUS_RESOURCES);
+
+ }
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ Adapter->References++;
+
+ //
+ // Link this open to the appropriate lists.
+ //
+
+ if (Adapter->OpenQueue == NULL) {
+
+ //
+ // The first open on this adapter.
+ //
+
+ if (LM_Open_Adapter(&(Adapter->LMAdapter)) != SUCCESS) {
+
+ IF_LOUD( DbgPrint("OpenFailed!\n");)
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisWriteErrorLogEntry(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 0
+ );
+
+ return(NDIS_STATUS_FAILURE);
+
+ }
+
+ IF_LOUD( DbgPrint("OpenSuccess!\n");)
+
+ }
+
+ NewOpen->NextOpen = Adapter->OpenQueue;
+ Adapter->OpenQueue = NewOpen;
+
+ if (!EthNoteFilterOpenAdapter(
+ Adapter->LMAdapter.FilterDB,
+ NewOpen,
+ NdisBindingContext,
+ &NewOpen->NdisFilterHandle
+ )) {
+
+ Adapter->References--;
+
+ Adapter->OpenQueue = NewOpen->NextOpen;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisWriteErrorLogEntry(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+
+ return NDIS_STATUS_FAILURE;
+
+
+ }
+
+ //
+ // Set up the open block.
+ //
+
+ NewOpen->Adapter = Adapter;
+ NewOpen->MacBlock = Adapter->MacBlock;
+ NewOpen->NdisBindingContext = NdisBindingContext;
+ NewOpen->AddressingInformation = AddressingInformation;
+ NewOpen->Closing = FALSE;
+ NewOpen->LookAhead = WD_MAX_LOOKAHEAD;
+ NewOpen->ProtOptionFlags = 0;
+
+ Adapter->MaxLookAhead = WD_MAX_LOOKAHEAD;
+
+ NewOpen->ReferenceCount = 1;
+
+ *MacBindingHandle = (NDIS_HANDLE)NewOpen;
+
+ WD_DO_DEFERRED(Adapter);
+
+ IF_LOUD( DbgPrint("Out Open Adapter\n");)
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+
+VOID
+WdAdjustMaxLookAhead(
+ IN PWD_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine finds the open with the maximum lookahead value and
+ stores that in the adapter block.
+
+ NOTE: THIS ROUTINE MUST BE CALLED WITH THE SPINLOCK HELD.
+
+Arguments:
+
+ Adapter - A pointer to the adapter block.
+
+Returns:
+
+ None.
+
+--*/
+{
+ ULONG CurrentMax = 0;
+ PWD_OPEN CurrentOpen;
+
+ CurrentOpen = Adapter->OpenQueue;
+
+ while (CurrentOpen != NULL) {
+
+ if (CurrentOpen->LookAhead > CurrentMax) {
+
+ CurrentMax = CurrentOpen->LookAhead;
+
+ }
+
+ CurrentOpen = CurrentOpen->NextOpen;
+ }
+
+ if (CurrentMax == 0) {
+
+ CurrentMax = WD_MAX_LOOKAHEAD;
+
+ }
+
+ Adapter->MaxLookAhead = CurrentMax;
+
+}
+
+NDIS_STATUS
+WdCloseAdapter(
+ IN NDIS_HANDLE MacBindingHandle
+ )
+
+/*++
+
+Routine Description:
+
+ NDIS function. Unlinks the open block and frees it.
+
+Arguments:
+
+ See NDIS 3.0 spec.
+
+--*/
+
+{
+ PWD_OPEN Open = ((PWD_OPEN)MacBindingHandle);
+ PWD_ADAPTER Adapter = Open->Adapter;
+ PWD_OPEN TmpOpen;
+ NDIS_STATUS StatusToReturn;
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ if (Open->Closing) {
+
+ //
+ // The open is already being closed.
+ //
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ return NDIS_STATUS_CLOSING;
+ }
+
+ Adapter->References++;
+
+ Open->ReferenceCount++;
+
+ //
+ // Remove this open from the list for this adapter.
+ //
+
+ if (Open == Adapter->OpenQueue) {
+
+ Adapter->OpenQueue = Open->NextOpen;
+
+ } else {
+
+ TmpOpen = Adapter->OpenQueue;
+
+ while (TmpOpen->NextOpen != Open) {
+
+ TmpOpen = TmpOpen->NextOpen;
+
+ }
+
+ TmpOpen->NextOpen = Open->NextOpen;
+ }
+
+
+
+ //
+ // Remove from Filter package to block all receives.
+ //
+
+ StatusToReturn = EthDeleteFilterOpenAdapter(
+ Adapter->LMAdapter.FilterDB,
+ Open->NdisFilterHandle,
+ NULL
+ );
+
+ //
+ // If the status is successful that merely implies that
+ // we were able to delete the reference to the open binding
+ // from the filtering code. If we have a successful status
+ // at this point we still need to check whether the reference
+ // count to determine whether we can close.
+ //
+ //
+ // The delete filter routine can return a "special" status
+ // that indicates that there is a current NdisIndicateReceive
+ // on this binding. See below.
+ //
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS) {
+
+ //
+ // Check whether the reference count is two. If
+ // it is then we can get rid of the memory for
+ // this open.
+ //
+ // A count of two indicates one for this routine
+ // and one for the filter which we *know* we can
+ // get rid of.
+ //
+
+ if (Open->ReferenceCount != 2) {
+
+ //
+ // We are not the only reference to the open. Remove
+ // it from the open list and delete the memory.
+ //
+
+
+ Open->Closing = TRUE;
+
+ //
+ // Account for this routines reference to the open
+ // as well as reference because of the original open.
+ //
+
+ Open->ReferenceCount -= 2;
+
+ //
+ // Change the status to indicate that we will
+ // be closing this later.
+ //
+
+ StatusToReturn = NDIS_STATUS_PENDING;
+
+ } else {
+
+ Open->ReferenceCount -= 2;
+
+ }
+
+ } else if (StatusToReturn == NDIS_STATUS_PENDING) {
+
+ Open->Closing = TRUE;
+
+ //
+ // Account for this routines reference to the open
+ // as well as reference because of the original open.
+ //
+
+ Open->ReferenceCount -= 2;
+
+ } else if (StatusToReturn == NDIS_STATUS_CLOSING_INDICATING) {
+
+ //
+ // When we have this status it indicates that the filtering
+ // code was currently doing an NdisIndicateReceive. It
+ // would not be wise to delete the memory for the open at
+ // this point. The filtering code will call our close action
+ // routine upon return from NdisIndicateReceive and that
+ // action routine will decrement the reference count for
+ // the open.
+ //
+
+ Open->Closing = TRUE;
+
+ //
+ // This status is private to the filtering routine. Just
+ // tell the caller the the close is pending.
+ //
+
+ StatusToReturn = NDIS_STATUS_PENDING;
+
+ //
+ // Account for this routines reference to the open.
+ //
+
+ Open->ReferenceCount--;
+
+ } else {
+
+ //
+ // Account for this routines reference to the open.
+ //
+
+ Open->ReferenceCount--;
+
+ }
+
+ //
+ // See if this is the last reference to this open.
+ //
+
+ if (Open->ReferenceCount == 0) {
+
+ //
+ // Check if the MaxLookAhead needs adjustment.
+ //
+
+ if (Open->LookAhead == Adapter->MaxLookAhead) {
+
+ WdAdjustMaxLookAhead(Adapter);
+
+ }
+
+
+ if (Adapter->OpenQueue == NULL) {
+
+ //
+ // We can disable the card.
+ //
+
+ if (NdisSynchronizeWithInterrupt(
+ &(Adapter->LMAdapter.NdisInterrupt),
+ (PVOID)WdSyncCloseAdapter,
+ (PVOID)(&(Adapter->LMAdapter))
+ ) == FALSE) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 0
+ );
+
+ IF_LOUD( DbgPrint("CloseAdapter FAILED!\n");)
+
+ } else {
+
+
+ IF_LOUD( DbgPrint("CloseAdapter Success!\n");)
+
+ }
+
+ }
+
+ } else {
+
+ //
+ // Will get removed when count drops to zero.
+ //
+
+ StatusToReturn = NDIS_STATUS_PENDING;
+
+ }
+
+
+ WD_DO_DEFERRED(Adapter);
+
+ return(StatusToReturn);
+
+}
+
+NDIS_STATUS
+WdRequest(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allows a protocol to query and set information
+ about the MAC.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to PWD_OPEN.
+
+ NdisRequest - A structure which contains the request type (Set or
+ Query), an array of operations to perform, and an array for holding
+ the results of the operations.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ PWD_OPEN Open = (PWD_OPEN)(MacBindingHandle);
+ PWD_ADAPTER Adapter = (Open->Adapter);
+
+
+ IF_LOUD( DbgPrint("In Request\n");)
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ //
+ // Ensure that the open does not close while in this function.
+ //
+
+ Open->ReferenceCount++;
+
+ Adapter->References++;
+
+ //
+ // Process request
+ //
+
+ if (Open->Closing) {
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ StatusToReturn = NDIS_STATUS_CLOSING;
+
+ } else if (NdisRequest->RequestType == NdisRequestQueryInformation) {
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ StatusToReturn = WdQueryInformation(Adapter, Open, NdisRequest);
+
+ } else if (NdisRequest->RequestType == NdisRequestSetInformation) {
+
+ if (Adapter->HardwareFailure) {
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ StatusToReturn = NDIS_STATUS_FAILURE;
+
+ } else {
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ StatusToReturn = WdSetInformation(Adapter,Open,NdisRequest);
+
+ }
+
+ } else {
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ StatusToReturn = NDIS_STATUS_NOT_RECOGNIZED;
+
+ }
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ WdRemoveReference(Open);
+
+ WD_DO_DEFERRED(Adapter);
+
+ IF_LOUD( DbgPrint("Out Request\n");)
+
+ return(StatusToReturn);
+
+}
+
+NDIS_STATUS
+WdQueryProtocolInformation(
+ IN PWD_ADAPTER Adapter,
+ IN PWD_OPEN Open,
+ IN NDIS_OID Oid,
+ IN BOOLEAN GlobalMode,
+ IN PVOID InfoBuffer,
+ IN UINT BytesLeft,
+ OUT PUINT BytesNeeded,
+ OUT PUINT BytesWritten
+)
+
+/*++
+
+Routine Description:
+
+ The WdQueryProtocolInformation process a Query request for
+ NDIS_OIDs that are specific to a binding about the MAC. Note that
+ some of the OIDs that are specific to bindings are also queryable
+ on a global basis. Rather than recreate this code to handle the
+ global queries, I use a flag to indicate if this is a query for the
+ global data or the binding specific data.
+
+Arguments:
+
+ Adapter - a pointer to the adapter.
+
+ Open - a pointer to the open instance.
+
+ Oid - the NDIS_OID to process.
+
+ GlobalMode - Some of the binding specific information is also used
+ when querying global statistics. This is a flag to specify whether
+ to return the global value, or the binding specific value.
+
+ PlaceInInfoBuffer - a pointer into the NdisRequest->InformationBuffer
+ into which store the result of the query.
+
+ BytesLeft - the number of bytes left in the InformationBuffer.
+
+ BytesNeeded - If there is not enough room in the information buffer
+ then this will contain the number of bytes needed to complete the
+ request.
+
+ BytesWritten - a pointer to the number of bytes written into the
+ InformationBuffer.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NDIS_MEDIUM Medium = NdisMedium802_3;
+ ULONG GenericULong;
+ USHORT GenericUShort;
+ UCHAR GenericArray[6];
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ //
+ // Common variables for pointing to result of query
+ //
+
+ PVOID MoveSource = (PVOID)(&GenericULong);
+ ULONG MoveBytes = sizeof(ULONG);
+
+ NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady;
+
+ //
+ // General Algorithm:
+ //
+ // Switch(Request)
+ // Get requested information
+ // Store results in a common variable.
+ // Copy result in common variable to result buffer.
+ //
+
+ //
+ // Make sure that ulong is 4 bytes. Else GenericULong must change
+ // to something of size 4.
+ //
+ ASSERT(sizeof(ULONG) == 4);
+
+
+ IF_LOUD( DbgPrint("In QueryProtocol\n");)
+
+ //
+ // Make sure no changes occur while processing.
+ //
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ //
+ // Switch on request type
+ //
+
+ switch (Oid) {
+
+ case OID_GEN_MAC_OPTIONS:
+
+ GenericULong = (ULONG)(NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
+ NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
+ NDIS_MAC_OPTION_NO_LOOPBACK
+ );
+
+ break;
+
+ case OID_GEN_SUPPORTED_LIST:
+
+ if (!GlobalMode) {
+
+ MoveSource = (PVOID)(WdProtocolSupportedOids);
+ MoveBytes = sizeof(WdProtocolSupportedOids);
+
+ } else {
+
+ MoveSource = (PVOID)(WdGlobalSupportedOids);
+ MoveBytes = sizeof(WdGlobalSupportedOids);
+
+ }
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+
+ if (Adapter->HardwareFailure) {
+
+ HardwareStatus = NdisHardwareStatusNotReady;
+
+ } else {
+
+ HardwareStatus = NdisHardwareStatusReady;
+
+ }
+
+ MoveSource = (PVOID)(&HardwareStatus);
+ MoveBytes = sizeof(NDIS_HARDWARE_STATUS);
+
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+
+ MoveSource = (PVOID) (&Medium);
+ MoveBytes = sizeof(NDIS_MEDIUM);
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+
+ GenericULong = WD_MAX_LOOKAHEAD;
+
+ break;
+
+
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+
+ GenericULong = (ULONG)(WD_MAX_PACKET_SIZE - WD_HEADER_SIZE);
+
+ break;
+
+
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+
+ GenericULong = (ULONG)(WD_MAX_PACKET_SIZE);
+
+ break;
+
+
+ case OID_GEN_LINK_SPEED:
+
+ GenericULong = (ULONG)(100000);
+
+ break;
+
+
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+
+ GenericULong = (ULONG)(Adapter->LMAdapter.num_of_tx_buffs
+ * Adapter->LMAdapter.xmit_buf_size);
+
+ break;
+
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+
+ GenericULong = (ULONG)((Adapter->LMAdapter.ram_size * 1024) -
+ (Adapter->LMAdapter.num_of_tx_buffs
+ * Adapter->LMAdapter.xmit_buf_size));
+
+ break;
+
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+
+ GenericULong = (ULONG)(Adapter->LMAdapter.buffer_page_size);
+
+ break;
+
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+
+ GenericULong = (ULONG)(Adapter->LMAdapter.buffer_page_size);
+
+ break;
+
+ case OID_GEN_VENDOR_ID:
+
+ NdisMoveMemory(
+ (PVOID)&GenericULong,
+ Adapter->LMAdapter.permanent_node_address,
+ 3
+ );
+ GenericULong &= 0xFFFFFF00;
+ MoveSource = (PVOID)(&GenericULong);
+ MoveBytes = sizeof(GenericULong);
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+
+ MoveSource = (PVOID)"SMC Adapter.";
+ MoveBytes = 13;
+
+ break;
+
+ case OID_GEN_DRIVER_VERSION:
+
+ GenericUShort = ((USHORT)WD_NDIS_MAJOR_VERSION << 8) |
+ WD_NDIS_MINOR_VERSION;
+
+ MoveSource = (PVOID)(&GenericUShort);
+ MoveBytes = sizeof(GenericUShort);
+ break;
+
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ if (GlobalMode) {
+
+ UINT Filter;
+
+ Filter = ETH_QUERY_FILTER_CLASSES(Adapter->LMAdapter.FilterDB);
+
+ GenericULong = (ULONG)(Filter);
+
+ } else {
+
+ UINT Filter = 0;
+
+ Filter = ETH_QUERY_PACKET_FILTER(Adapter->LMAdapter.FilterDB,
+ Open->NdisFilterHandle);
+
+ GenericULong = (ULONG)(Filter);
+
+ }
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ if ( GlobalMode ) {
+
+ GenericULong = (ULONG)(Adapter->MaxLookAhead);
+
+ } else {
+
+ GenericULong = Open->LookAhead;
+
+ }
+
+ break;
+
+ case OID_802_3_PERMANENT_ADDRESS:
+
+ WD_MOVE_MEM((PCHAR)GenericArray,
+ Adapter->LMAdapter.permanent_node_address,
+ ETH_LENGTH_OF_ADDRESS);
+
+ MoveSource = (PVOID)(GenericArray);
+ MoveBytes = sizeof(Adapter->LMAdapter.permanent_node_address);
+ break;
+
+ case OID_802_3_CURRENT_ADDRESS:
+
+ WD_MOVE_MEM((PCHAR)GenericArray,
+ Adapter->LMAdapter.node_address,
+ ETH_LENGTH_OF_ADDRESS);
+
+ MoveSource = (PVOID)(GenericArray);
+ MoveBytes = sizeof(Adapter->LMAdapter.node_address);
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+
+ {
+ UINT NumAddresses;
+
+
+ if (GlobalMode) {
+
+ NumAddresses = ETH_NUMBER_OF_GLOBAL_FILTER_ADDRESSES(Adapter->LMAdapter.FilterDB);
+
+ if ((NumAddresses * ETH_LENGTH_OF_ADDRESS) > BytesLeft) {
+
+ *BytesNeeded = (NumAddresses * ETH_LENGTH_OF_ADDRESS);
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ break;
+
+ }
+
+ EthQueryGlobalFilterAddresses(
+ &StatusToReturn,
+ Adapter->LMAdapter.FilterDB,
+ BytesLeft,
+ &NumAddresses,
+ InfoBuffer
+ );
+
+ *BytesWritten = NumAddresses * ETH_LENGTH_OF_ADDRESS;
+
+ //
+ // Should not be an error since we held the spinlock
+ // nothing should have changed.
+ //
+
+ ASSERT(StatusToReturn == NDIS_STATUS_SUCCESS);
+
+ } else {
+
+ NumAddresses = EthNumberOfOpenFilterAddresses(
+ Adapter->LMAdapter.FilterDB,
+ Open->NdisFilterHandle
+ );
+
+ if ((NumAddresses * ETH_LENGTH_OF_ADDRESS) > BytesLeft) {
+
+ *BytesNeeded = (NumAddresses * ETH_LENGTH_OF_ADDRESS);
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ break;
+
+ }
+
+ EthQueryOpenFilterAddresses(
+ &StatusToReturn,
+ Adapter->LMAdapter.FilterDB,
+ Open->NdisFilterHandle,
+ BytesLeft,
+ &NumAddresses,
+ InfoBuffer
+ );
+
+ //
+ // Should not be an error since we held the spinlock
+ // nothing should have changed.
+ //
+
+ ASSERT(StatusToReturn == NDIS_STATUS_SUCCESS);
+
+ *BytesWritten = NumAddresses * ETH_LENGTH_OF_ADDRESS;
+
+ }
+
+ }
+
+
+
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+
+ GenericULong = (ULONG) (Adapter->MulticastListMax);
+
+ break;
+
+
+
+ default:
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if ((StatusToReturn == NDIS_STATUS_SUCCESS) &&
+ (Oid != OID_802_3_MULTICAST_LIST)) {
+
+ if (MoveBytes > BytesLeft) {
+
+ //
+ // Not enough room in InformationBuffer. Punt
+ //
+
+ *BytesNeeded = MoveBytes - BytesLeft;
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ } else {
+
+ //
+ // Store result.
+ //
+
+ WD_MOVE_MEM(InfoBuffer, MoveSource, MoveBytes);
+
+ (*BytesWritten) += MoveBytes;
+
+ }
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ IF_LOUD( DbgPrint("Out QueryProtocol\n");)
+
+ return(StatusToReturn);
+}
+
+NDIS_STATUS
+WdQueryInformation(
+ IN PWD_ADAPTER Adapter,
+ IN PWD_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest
+ )
+/*++
+
+Routine Description:
+
+ The WdQueryInformation is used by WdRequest to query information
+ about the MAC.
+
+Arguments:
+
+ Adapter - A pointer to the adapter.
+
+ Open - A pointer to a particular open instance.
+
+ NdisRequest - A structure which contains the request type (Query),
+ an array of operations to perform, and an array for holding
+ the results of the operations.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+ UINT BytesWritten = 0;
+ UINT BytesNeeded = 0;
+ UINT BytesLeft = NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength;
+ PUCHAR InfoBuffer = (PUCHAR)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+
+ IF_LOUD( DbgPrint("In QueryInfor\n");)
+
+ StatusToReturn = WdQueryProtocolInformation(
+ Adapter,
+ Open,
+ NdisRequest->DATA.QUERY_INFORMATION.Oid,
+ FALSE,
+ InfoBuffer,
+ BytesLeft,
+ &BytesNeeded,
+ &BytesWritten
+ );
+
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesWritten = BytesWritten;
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = BytesNeeded;
+
+ IF_LOUD( DbgPrint("Out QueryInfor\n");)
+
+ return(StatusToReturn);
+}
+
+NDIS_STATUS
+WdSetInformation(
+ IN PWD_ADAPTER Adapter,
+ IN PWD_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest
+ )
+/*++
+
+Routine Description:
+
+ The WdSetInformation is used by WdRequest to set information
+ about the MAC.
+
+Arguments:
+
+ Adapter - A pointer to the adapter.
+
+ Open - A pointer to an open instance.
+
+ NdisRequest - A structure which contains the request type (Set),
+ an array of operations to perform, and an array for holding
+ the results of the operations.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+ //
+ // General Algorithm:
+ //
+ // Verify length
+ // Switch(Request)
+ // Process Request
+ //
+
+ UINT BytesRead = 0;
+ UINT BytesNeeded = 0;
+ UINT BytesLeft = NdisRequest->DATA.SET_INFORMATION.InformationBufferLength;
+ PUCHAR InfoBuffer = (PUCHAR)(NdisRequest->DATA.SET_INFORMATION.InformationBuffer);
+
+ //
+ // Variables for a particular request
+ //
+
+ NDIS_OID Oid;
+ UINT OidLength;
+
+ //
+ // Variables for holding the new values to be used.
+ //
+
+ ULONG LookAhead;
+ ULONG Filter;
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+
+ IF_LOUD( DbgPrint("In SetInfo\n");)
+
+
+
+ //
+ // Get Oid and Length of request
+ //
+
+ Oid = NdisRequest->DATA.SET_INFORMATION.Oid;
+
+ OidLength = BytesLeft;
+
+ switch (Oid) {
+
+
+ case OID_802_3_MULTICAST_LIST:
+
+ //
+ // Verify length
+ //
+
+ if ((OidLength % ETH_LENGTH_OF_ADDRESS) != 0){
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ break;
+
+ }
+
+ StatusToReturn = WdSetMulticastAddresses(
+ Adapter,
+ Open,
+ NdisRequest,
+ (UINT)(OidLength / ETH_LENGTH_OF_ADDRESS),
+ (PVOID)InfoBuffer
+ );
+ break;
+
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ //
+ // Verify length
+ //
+
+ if (OidLength != 4 ) {
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ break;
+
+ }
+
+
+ WD_MOVE_MEM(&Filter, InfoBuffer, 4);
+
+ //
+ // Verify bits
+ //
+
+ if (Filter & (NDIS_PACKET_TYPE_SOURCE_ROUTING |
+ NDIS_PACKET_TYPE_SMT |
+ NDIS_PACKET_TYPE_MAC_FRAME |
+ NDIS_PACKET_TYPE_FUNCTIONAL |
+ NDIS_PACKET_TYPE_ALL_FUNCTIONAL |
+ NDIS_PACKET_TYPE_GROUP
+ )) {
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 4;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ break;
+
+ }
+
+ StatusToReturn = WdSetPacketFilter(Adapter,
+ Open,
+ NdisRequest,
+ Filter
+ );
+
+
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ //
+ // Verify length
+ //
+
+ if (OidLength != 4) {
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ break;
+
+ }
+
+ WD_MOVE_MEM(&LookAhead, InfoBuffer, 4);
+
+ if (LookAhead <= (WD_MAX_LOOKAHEAD)) {
+
+ if (LookAhead > Adapter->MaxLookAhead) {
+
+ Adapter->MaxLookAhead = LookAhead;
+
+ Open->LookAhead = LookAhead;
+
+ } else {
+
+ if ((Open->LookAhead == Adapter->MaxLookAhead) &&
+ (LookAhead < Open->LookAhead)) {
+
+ Open->LookAhead = LookAhead;
+
+ WdAdjustMaxLookAhead(Adapter);
+
+ } else {
+
+ Open->LookAhead = LookAhead;
+
+ }
+
+ }
+
+
+ } else {
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ }
+
+ break;
+
+ case OID_GEN_PROTOCOL_OPTIONS:
+
+ //
+ // Verify length
+ //
+
+ if (OidLength != 4) {
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ break;
+
+ }
+
+ WD_MOVE_MEM(&Open->ProtOptionFlags, InfoBuffer, 4);
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ break;
+
+ default:
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ break;
+
+ }
+
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS) {
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = BytesLeft;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ }
+
+
+ IF_LOUD( DbgPrint("Out SetInfo\n");)
+
+ return(StatusToReturn);
+}
+
+
+STATIC
+NDIS_STATUS
+WdSetPacketFilter(
+ IN PWD_ADAPTER Adapter,
+ IN PWD_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT PacketFilter
+ )
+
+/*++
+
+Routine Description:
+
+ The WdSetPacketFilter request allows a protocol to control the types
+ of packets that it receives from the MAC.
+
+Arguments:
+
+ Adapter - A pointer to the adapter structure.
+
+ Open - A pointer to the open block giving the request.
+
+ NdisRequest - The NDIS_REQUEST with the set packet filter command in it.
+
+ PacketFilter - A bit mask that contains flags that correspond to specific
+ classes of received packets. If a particular bit is set in the mask,
+ then packet reception for that class of packet is enabled. If the
+ bit is clear, then packets that fall into that class are not received
+ by the client. A single exception to this rule is that if the promiscuous
+ bit is set, then the client receives all packets on the network, regardless
+ of the state of the other flags.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ //
+ // Keeps track of the *MAC's* status. The status will only be
+ // reset if the filter change action routine is called.
+ //
+ NDIS_STATUS StatusOfFilterChange = NDIS_STATUS_SUCCESS;
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ IF_LOUD( DbgPrint("In SetFilter\n");)
+
+ if (!Open->Closing) {
+
+ //
+ // Increment the open while it is going through the filtering
+ // routines.
+ //
+
+ Open->ReferenceCount++;
+
+ StatusOfFilterChange = EthFilterAdjust(
+ Adapter->LMAdapter.FilterDB,
+ Open->NdisFilterHandle,
+ NdisRequest,
+ PacketFilter,
+ TRUE
+ );
+
+ Open->ReferenceCount--;
+
+ } else {
+
+ StatusOfFilterChange = NDIS_STATUS_CLOSING;
+
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ IF_LOUD( DbgPrint("Out SetFilter\n");)
+
+ return StatusOfFilterChange;
+}
+
+
+
+
+STATIC
+NDIS_STATUS
+WdSetMulticastAddresses(
+ IN PWD_ADAPTER Adapter,
+ IN PWD_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT NumAddresses,
+ IN CHAR AddressList[][ETH_LENGTH_OF_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ This function calls into the filter package in order to set the
+ multicast address list for the card to the specified list.
+
+Arguments:
+
+ Adapter - A pointer to the adapter block.
+
+ Open - A pointer to the open block submitting the request.
+
+ NdisRequest - The NDIS_REQUEST with the set multicast address list command
+ in it.
+
+ NumAddresses - A count of the number of addresses in the addressList.
+
+ AddressList - An array of multicast addresses that this open instance
+ wishes to accept.
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+ //
+ // Keeps track of the *MAC's* status. The status will only be
+ // reset if the filter change action routine is called.
+ //
+ NDIS_STATUS StatusOfFilterChange = NDIS_STATUS_SUCCESS;
+
+ IF_LOUD( DbgPrint("In SetMulticast\n");)
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ if (!Open->Closing) {
+
+ //
+ // Increment the open while it is going through the filtering
+ // routines.
+ //
+
+ Open->ReferenceCount++;
+
+ StatusOfFilterChange = EthChangeFilterAddresses(
+ Adapter->LMAdapter.FilterDB,
+ Open->NdisFilterHandle,
+ NdisRequest,
+ NumAddresses,
+ AddressList,
+ TRUE
+ );
+ Open->ReferenceCount--;
+
+ } else {
+
+ StatusOfFilterChange = NDIS_STATUS_CLOSING;
+
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ IF_LOUD( DbgPrint("Out SetMulticast\n");)
+
+ return StatusOfFilterChange;
+}
+
+
+
+NDIS_STATUS
+WdFillInGlobalData(
+ IN PWD_ADAPTER Adapter,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ This routine completes a GlobalStatistics request. It is critical that
+ if information is needed from the Adapter->* fields, they have been
+ updated before this routine is called.
+
+Arguments:
+
+ Adapter - A pointer to the Adapter.
+
+ NdisRequest - A structure which contains the request type (Global
+ Query), an array of operations to perform, and an array for holding
+ the results of the operations.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ //
+ // General Algorithm:
+ //
+ // Switch(Request)
+ // Get requested information
+ // Store results in a common variable.
+ // default:
+ // Try protocol query information
+ // If that fails, fail query.
+ //
+ // Copy result in common variable to result buffer.
+ // Finish processing
+
+ UINT BytesWritten = 0;
+ UINT BytesNeeded = 0;
+ UINT BytesLeft = NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength;
+ PUCHAR InfoBuffer = (PUCHAR)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ //
+ // This variable holds result of query
+ //
+
+ ULONG GenericULong;
+
+ //
+ // Make sure that long is 4 bytes. Else GenericULong must change
+ // to something of size 4.
+ //
+ ASSERT(sizeof(ULONG) == 4);
+
+
+ StatusToReturn = WdQueryProtocolInformation(
+ Adapter,
+ NULL,
+ NdisRequest->DATA.QUERY_INFORMATION.Oid,
+ TRUE,
+ InfoBuffer,
+ BytesLeft,
+ &BytesNeeded,
+ &BytesWritten
+ );
+
+
+ if (StatusToReturn == NDIS_STATUS_NOT_SUPPORTED) {
+
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ //
+ // Switch on request type
+ //
+
+ switch (NdisRequest->DATA.QUERY_INFORMATION.Oid) {
+
+ case OID_GEN_XMIT_OK:
+
+ GenericULong = (ULONG)(Adapter->FramesXmitGood);
+
+ break;
+
+ case OID_GEN_RCV_OK:
+
+ GenericULong = (ULONG)(Adapter->FramesRcvGood);
+
+ break;
+
+ case OID_GEN_XMIT_ERROR:
+
+ GenericULong = (ULONG)(Adapter->FramesXmitBad);
+
+ break;
+
+ case OID_GEN_RCV_ERROR:
+
+ GenericULong = (ULONG)(Adapter->CrcErrors);
+
+ break;
+
+ case OID_GEN_RCV_NO_BUFFER:
+
+ GenericULong = (ULONG)(Adapter->MissedPackets);
+
+ break;
+
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+
+ GenericULong = (ULONG)(Adapter->FrameAlignmentErrors);
+
+ break;
+
+ case OID_802_3_XMIT_ONE_COLLISION:
+
+ GenericULong = (ULONG)(Adapter->FramesXmitOneCollision);
+
+ break;
+
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+
+ GenericULong = (ULONG)(Adapter->FramesXmitManyCollisions);
+
+ break;
+
+
+ default:
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+
+ break;
+
+ }
+
+
+ //
+ // Check to make sure there is enough room in the
+ // buffer to store the result.
+ //
+
+ if (BytesLeft >= sizeof(ULONG)) {
+
+ //
+ // Store the result.
+ //
+
+ WD_MOVE_MEM(
+ (PVOID)InfoBuffer,
+ (PVOID)(&GenericULong),
+ sizeof(ULONG)
+ );
+
+ BytesWritten += sizeof(ULONG);
+
+ }
+
+ }
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesWritten = BytesWritten;
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = BytesNeeded;
+
+ return(StatusToReturn);
+}
+
+NDIS_STATUS
+WdQueryGlobalStatistics(
+ IN NDIS_HANDLE MacAdapterContext,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ The WdQueryGlobalStatistics is used by the protocol to query
+ global information about the MAC.
+
+Arguments:
+
+ MacAdapterContext - The value associated with the adapter that is being
+ opened when the MAC registered the adapter with NdisRegisterAdapter.
+
+ NdisRequest - A structure which contains the request type (Query),
+ an array of operations to perform, and an array for holding
+ the results of the operations.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+ //
+ // General Algorithm:
+ //
+ //
+ // Check if a request is going to pend...
+ // If so, pend the entire operation.
+ //
+ // Else
+ // Fill in the request block.
+ //
+ //
+
+ PWD_ADAPTER Adapter = (PWD_ADAPTER)(MacAdapterContext);
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ //
+ // Check if a request is valid and going to pend...
+ // If so, pend the entire operation.
+ //
+
+
+ //
+ // Switch on request type
+ //
+
+ switch (NdisRequest->DATA.QUERY_INFORMATION.Oid) {
+ case OID_GEN_SUPPORTED_LIST:
+ case OID_GEN_HARDWARE_STATUS:
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+ case OID_GEN_MAC_OPTIONS:
+ case OID_GEN_LINK_SPEED:
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+ case OID_GEN_VENDOR_ID:
+ case OID_GEN_VENDOR_DESCRIPTION:
+ case OID_GEN_DRIVER_VERSION:
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ case OID_GEN_XMIT_OK:
+ case OID_GEN_RCV_OK:
+ case OID_GEN_XMIT_ERROR:
+ case OID_GEN_RCV_ERROR:
+
+ break;
+
+ case OID_802_3_PERMANENT_ADDRESS:
+ case OID_802_3_CURRENT_ADDRESS:
+ case OID_GEN_RCV_NO_BUFFER:
+ case OID_802_3_MULTICAST_LIST:
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+ case OID_802_3_XMIT_ONE_COLLISION:
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+
+ break;
+
+ default:
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+
+ break;
+ }
+
+ NdisInterlockedAddUlong(&Adapter->References, 1, &Adapter->Lock);
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS) {
+
+ StatusToReturn = WdFillInGlobalData(Adapter, NdisRequest);
+
+ }
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ WD_DO_DEFERRED(Adapter);
+
+ return(StatusToReturn);
+}
+
+
+VOID
+WdRemoveAdapter(
+ IN PVOID MacAdapterContext
+ )
+/*++
+
+Routine Description:
+
+ WdRemoveAdapter removes an adapter previously registered
+ with NdisRegisterAdapter.
+
+Arguments:
+
+ MacAdapterContext - The context value that the MAC passed
+ to NdisRegisterAdapter; actually as pointer to an
+ WD_ADAPTER.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PWD_ADAPTER Adapter;
+ BOOLEAN Canceled;
+
+ Adapter = PWD_ADAPTER_FROM_CONTEXT_HANDLE(MacAdapterContext);
+
+ LM_Free_Resources(&Adapter->LMAdapter);
+
+ ASSERT(Adapter->OpenQueue == (PWD_OPEN)NULL);
+
+ //
+ // There are no opens left, so remove ourselves.
+ //
+
+ NdisCancelTimer(&Adapter->WakeUpTimer, &Canceled);
+
+ if ( !Canceled ) {
+ NdisStallExecution(500000);
+ }
+
+ //
+ // Take us out of the AdapterQueue.
+ //
+
+ NdisAcquireSpinLock(&WdMacBlock.SpinLock);
+
+ Adapter->Removed = TRUE;
+
+ if (WdMacBlock.AdapterQueue == Adapter) {
+
+ WdMacBlock.AdapterQueue = Adapter->NextAdapter;
+
+ } else {
+
+ PWD_ADAPTER TmpAdaptP = WdMacBlock.AdapterQueue;
+
+ while (TmpAdaptP->NextAdapter != Adapter) {
+
+ TmpAdaptP = TmpAdaptP->NextAdapter;
+
+ }
+
+ TmpAdaptP->NextAdapter = TmpAdaptP->NextAdapter->NextAdapter;
+ }
+
+ NdisReleaseSpinLock(&WdMacBlock.SpinLock);
+
+ NdisRemoveInterrupt(&(Adapter->LMAdapter.NdisInterrupt));
+
+ NdisUnmapIoSpace(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ Adapter->LMAdapter.ram_access,
+ Adapter->LMAdapter.ram_size * 1024);
+
+ EthDeleteFilter(Adapter->LMAdapter.FilterDB);
+
+ NdisDeregisterAdapter(Adapter->LMAdapter.NdisAdapterHandle);
+
+ NdisFreeSpinLock(&Adapter->Lock);
+
+ NdisFreeMemory(Adapter, sizeof(WD_ADAPTER), 0);
+
+ return;
+}
+
+VOID
+WdUnload(
+ IN NDIS_HANDLE MacMacContext
+ )
+
+/*++
+
+Routine Description:
+
+ WdUnload is called when the MAC is to unload itself.
+
+Arguments:
+
+ MacMacContext - actually a pointer to WdMacBlock.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS InitStatus;
+
+ UNREFERENCED_PARAMETER(MacMacContext);
+
+ NdisDeregisterMac(
+ &InitStatus,
+ WdMacBlock.NdisMacHandle
+ );
+
+ NdisFreeSpinLock(&WdMacBlock.SpinLock);
+
+ NdisTerminateWrapper(
+ WdMacBlock.NdisWrapperHandle,
+ NULL
+ );
+
+ return;
+}
+
+NDIS_STATUS
+WdSend(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+ NDIS function. Sends a packet on the wire
+
+Arguments:
+
+ See NDIS 3.0 spec.
+
+--*/
+
+{
+ PWD_OPEN Open = PWD_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+ PWD_ADAPTER Adapter = Open->Adapter;
+ PMAC_RESERVED Reserved = RESERVED(Packet);
+ UINT PacketLength;
+ NDIS_STATUS Status;
+
+
+ //
+ // Check that the packet is not too short or too long.
+ //
+
+ NdisQueryPacket(Packet, NULL, NULL, NULL, &PacketLength);
+
+ if (PacketLength < (ETH_LENGTH_OF_ADDRESS*2) || PacketLength > 1514) {
+
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+
+
+
+ if (Adapter->HardwareFailure) {
+
+ return(NDIS_STATUS_FAILURE);
+
+ }
+
+ if (Adapter->ResetInProgress) {
+
+ return(NDIS_STATUS_RESET_IN_PROGRESS);
+
+ }
+
+ //
+ // Ensure that the open won't close during this function.
+ //
+
+ if (Open->Closing) {
+
+ return NDIS_STATUS_CLOSING;
+
+ }
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ IF_LOG(LOG('s'));
+
+ Open->ReferenceCount++;
+
+ Adapter->References++;
+
+ //
+ // Set up the MacReserved section of the packet.
+ //
+
+ Reserved->Open = Open;
+
+ Reserved->NextPacket = (PNDIS_PACKET)NULL;
+
+
+
+
+ //
+ // Set Reserved->Loopback
+ //
+
+ WdSetLoopbackFlag(Adapter, Open, Packet);
+
+
+
+
+ IF_LOUD( DbgPrint("Sending a packet for Open 0x%lx\n", Reserved->Open);)
+
+
+ //
+ // We do not Open->ReferenceCount-- because that will be done when
+ // then send completes.
+ //
+
+
+ if (Reserved->Directed) {
+
+ //
+ // Put it directly on loopback queue.
+ //
+
+ IF_VERY_LOUD( DbgPrint("Putting Packet 0x%lx on Loopback queue\n",Packet);)
+
+ IF_LOG(LOG('l'));
+
+ if (Adapter->LoopbackQueue == NULL) {
+
+ Adapter->LoopbackQueue = Adapter->LoopbackQTail = Packet;
+
+ } else {
+
+ RESERVED(Adapter->LoopbackQTail)->NextPacket = Packet;
+
+ Adapter->LoopbackQTail = Packet;
+
+ }
+
+ Status = NDIS_STATUS_PENDING;
+
+ } else {
+
+ //
+ // Put Packet on queue to hit the wire.
+ //
+
+ if (Adapter->XmitQueue != NULL) {
+
+ IF_LOG(LOG('q'));
+
+ RESERVED(Adapter->XmitQTail)->NextPacket = Packet;
+
+ Adapter->XmitQTail = Packet;
+
+ Adapter->WakeUpTimeout = FALSE;
+
+ } else {
+
+ PNDIS_PACKET PreviousTail;
+
+ //
+ // We have to assume it will be sent. In case the send completes
+ // before we have time to add it.
+ //
+
+ ASSERT(Packet != NULL);
+
+ if (Adapter->PacketsOnCard == NULL) {
+
+ PreviousTail = NULL;
+
+ Adapter->PacketsOnCard = Adapter->PacketsOnCardTail = Packet;
+
+ } else {
+
+ PreviousTail = Adapter->PacketsOnCardTail;
+
+ RESERVED(Adapter->PacketsOnCardTail)->NextPacket = Packet;
+
+ Adapter->PacketsOnCardTail = Packet;
+
+ }
+
+ Adapter->WakeUpTimeout = FALSE;
+
+ IF_LOG(LOG('t'));
+
+ if (LM_Send(Packet, &Adapter->LMAdapter) == OUT_OF_RESOURCES) {
+
+ IF_LOG(LOG('Q'));
+
+ ASSERT(Packet != NULL);
+
+ //
+ // Remove it from list of packets on card and add it to xmit
+ // queue.
+ //
+
+ if (PreviousTail == NULL) {
+
+ Adapter->PacketsOnCard = Adapter->PacketsOnCardTail = NULL;
+
+ } else {
+
+ Adapter->PacketsOnCardTail = PreviousTail;
+
+ RESERVED(Adapter->PacketsOnCardTail)->NextPacket = NULL;
+
+ ASSERT(Adapter->PacketsOnCard != NULL);
+
+ }
+
+ Adapter->XmitQueue = Packet;
+
+ Adapter->XmitQTail = Packet;
+
+ Adapter->WakeUpTimeout = FALSE;
+
+ }
+
+ }
+
+ Status = NDIS_STATUS_PENDING;
+
+ }
+
+
+ WD_DO_DEFERRED(Adapter);
+
+ IF_LOG(LOG('S'));
+
+ return Status;
+
+}
+
+UINT
+WdCompareMemory(
+ IN PUCHAR String1,
+ IN PUCHAR String2,
+ IN UINT Length
+ )
+/*++
+
+Routine Description:
+
+ Determines if two arrays of bytes are equal.
+
+Arguments:
+
+ String1, String2 - the two arrays to check.
+
+ Length - the first length bytes to compare.
+
+Return Value:
+
+ 0 if equal, -1 if not.
+
+--*/
+{
+ UINT i;
+
+ for (i=0; i<Length; i++) {
+ if (String1[i] != String2[i]) {
+ return (UINT)(-1);
+ }
+ }
+ return 0;
+}
+
+VOID
+WdSetLoopbackFlag(
+ IN PWD_ADAPTER Adapter,
+ IN PWD_OPEN Open,
+ IN PNDIS_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the loopback flag in the reserved section of the packet
+ to indicate if it should be looped back.
+
+Arguments:
+
+ Packet - the packet to check.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PMAC_RESERVED Reserved = RESERVED(Packet);
+ UCHAR AddrBuf[ETH_LENGTH_OF_ADDRESS];
+ UINT Filter;
+
+
+ Reserved->Directed = FALSE;
+ Reserved->Loopback = FALSE;
+
+ //
+ // Check the destination address to see which filter to use.
+ //
+
+ WdCopyOver(AddrBuf, Packet, 0, ETH_LENGTH_OF_ADDRESS);
+
+ Filter = ETH_QUERY_FILTER_CLASSES(Adapter->LMAdapter.FilterDB);
+
+ if (WdAddressEqual(Adapter->LMAdapter.node_address, AddrBuf)) {
+
+ //
+ // Packet directed to this adapter.
+ //
+
+ Reserved->Directed = (BOOLEAN)(Filter & NDIS_PACKET_TYPE_DIRECTED);
+
+ }
+
+ if (Open->ProtOptionFlags & NDIS_PROT_OPTION_NO_LOOPBACK) {
+
+ Reserved->Loopback = FALSE;
+
+ } else if (Filter & NDIS_PACKET_TYPE_PROMISCUOUS) {
+
+ //
+ // Somebody is promiscuous, everything is looped back.
+ //
+
+ Reserved->Loopback = TRUE;
+
+ } else {
+
+ if (WdAddressEqual(WdBroadcastAddress, AddrBuf)) {
+
+ //
+ // Broadcast packet.
+ //
+
+ Reserved->Loopback = (BOOLEAN)(Filter & NDIS_PACKET_TYPE_BROADCAST);
+
+ } else if ((AddrBuf[0] & 1) != 0) {
+
+ //
+ // Multicast packet.
+ //
+
+ Reserved->Loopback = (BOOLEAN)(Filter &
+ (NDIS_PACKET_TYPE_MULTICAST |
+ NDIS_PACKET_TYPE_ALL_MULTICAST));
+
+ } else if (Reserved->Directed) {
+
+ Reserved->Loopback = TRUE;
+
+ } else {
+
+ //
+ // Packet directed to another adapter.
+ //
+
+ Reserved->Loopback = FALSE;
+ }
+
+ }
+
+}
+
+
+NDIS_STATUS
+WdReset(
+ IN NDIS_HANDLE MacBindingHandle
+ )
+
+/*++
+
+Routine Description:
+
+ NDIS function.
+
+Arguments:
+
+ See NDIS 3.0 spec.
+
+--*/
+
+{
+ PWD_OPEN Open = ((PWD_OPEN)MacBindingHandle);
+ PWD_ADAPTER Adapter = Open->Adapter;
+
+
+ if (Open->Closing) {
+
+ return(NDIS_STATUS_CLOSING);
+
+ }
+
+ if (Adapter->ResetRequested) {
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ IF_LOUD( DbgPrint("In WdReset\n");)
+
+ IF_LOG(LOG('r'));
+
+ //
+ // Ensure that the open does not close while in this function.
+ //
+
+ Open->ReferenceCount++;
+
+ Adapter->References++;
+
+
+ Adapter->ResetRequested = TRUE;
+
+ //
+ // Needed in case the reset pends somewhere along the line.
+ //
+
+ Adapter->ResetOpen = Open;
+
+ WD_DO_DEFERRED(Adapter);
+
+ IF_LOUD( DbgPrint("Out WdReset\n");)
+
+ return(NDIS_STATUS_PENDING);
+
+}
+
+STATIC
+NDIS_STATUS
+WdChangeMulticastAddresses(
+ IN UINT OldFilterCount,
+ IN CHAR OldAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN UINT NewFilterCount,
+ IN CHAR NewAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when a particular filter
+ class is first used or last cleared.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+
+ OldFilterCount - The number of addresses that used to be on the card.
+
+ OldAddresses - A list of all the addresses that used to be on the card.
+
+ NewFilterCount - The number of addresses that should now be on the card.
+
+ NewAddresses - A list of addresses that should be put on the card.
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to WD_OPEN.
+
+ NdisRequest - The request which submitted the filter change.
+ Must use when completing this request with the NdisCompleteRequest
+ service, if the MAC completes this request asynchronously.
+
+ Set - If true the change resulted from a set, otherwise the
+ change resulted from a open closing.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+
+
+ PWD_ADAPTER Adapter = PWD_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ UNREFERENCED_PARAMETER(Set);
+ UNREFERENCED_PARAMETER(NdisRequest);
+ UNREFERENCED_PARAMETER(OldAddresses);
+ UNREFERENCED_PARAMETER(OldFilterCount);
+
+ if (LM_Set_Multi_Address(NewAddresses, NewFilterCount, &Adapter->LMAdapter)
+ != SUCCESS) {
+
+ return(NDIS_STATUS_FAILURE);
+
+ } else {
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+}
+
+STATIC
+NDIS_STATUS
+WdChangeFilterClasses(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when an address is added to
+ the filter that wasn't referenced by any other open binding.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ OldFilterClasses - A bit mask that is currently on the card telling
+ which packet types to accept.
+
+ NewFilterClasses - A bit mask that should be put on the card telling
+ which packet types to accept.
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to WD_OPEN.
+
+ NdisRequest - The NDIS_REQUEST which submitted the filter change command.
+
+ Set - A flag telling if the command is a result of a close or not.
+
+Return Value:
+
+ Status of the change (successful or pending).
+
+
+--*/
+
+{
+
+ PWD_ADAPTER Adapter = PWD_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ UNREFERENCED_PARAMETER(Set);
+ UNREFERENCED_PARAMETER(OldFilterClasses);
+ UNREFERENCED_PARAMETER(NewFilterClasses);
+ UNREFERENCED_PARAMETER(NdisRequest);
+
+
+ if (LM_Set_Receive_Mask(&(Adapter->LMAdapter)) != SUCCESS) {
+
+ return(NDIS_STATUS_FAILURE);
+
+ } else {
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+}
+
+STATIC
+VOID
+WdCloseAction(
+ IN NDIS_HANDLE MacBindingHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when a particular binding
+ was closed while it was indicating through NdisIndicateReceive
+
+ All this routine needs to do is to decrement the reference count
+ of the binding.
+
+ NOTE: This routine assumes that it is called with the lock acquired.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to WD_OPEN.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+
+ PWD_OPEN_FROM_BINDING_HANDLE(MacBindingHandle)->ReferenceCount--;
+
+}
+
+BOOLEAN
+WdInterruptHandler(
+ IN PVOID ServiceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This is the interrupt handler which is registered with the operating
+ system. Only one interrupt is handled at one time, even if several
+ are pending (i.e. transmit complete and receive).
+
+Arguments:
+
+ ServiceContext - pointer to the adapter object
+
+Return Value:
+
+ TRUE, if the DPC is to be executed, otherwise FALSE.
+
+--*/
+
+{
+ PWD_ADAPTER Adapter = ((PWD_ADAPTER)ServiceContext);
+
+ IF_LOUD( DbgPrint("In WdISR\n");)
+
+ IF_LOG(LOG('i'));
+
+ //
+ // Force the INT signal from the chip low. When the
+ // interrupt is acknowledged interrupts will be unblocked,
+ // which will cause a rising edge on the interrupt line
+ // if there is another interrupt pending on the card.
+ //
+
+ IF_LOUD( DbgPrint( " blocking interrupts\n" );)
+
+ LM_Disable_Adapter(&Adapter->LMAdapter);
+
+ IF_LOG(LOG('I'));
+
+ return(TRUE);
+
+}
+
+VOID
+WdInterruptDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+/*++
+
+Routine Description:
+
+ This is the deffered processing routine for interrupts, it examines the
+ global 'InterruptReg' to determine what deffered processing is necessary
+ and dispatches control to the Rcv and Xmt handlers.
+
+Arguments:
+ SystemSpecific1, SystemSpecific2, SystemSpecific3 - not used
+ InterruptContext - a handle to the adapter block.
+
+Return Value:
+
+ NONE.
+
+--*/
+{
+ PWD_ADAPTER Adapter = ((PWD_ADAPTER)InterruptContext);
+ BOOLEAN RequeueRcv = FALSE;
+
+ UNREFERENCED_PARAMETER(SystemSpecific1);
+ UNREFERENCED_PARAMETER(SystemSpecific2);
+ UNREFERENCED_PARAMETER(SystemSpecific3);
+
+ IF_LOG(LOG('d'));
+
+
+ IF_LOUD( DbgPrint("==>IntDpc\n");)
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ if ( Adapter->ProcessingDpc ) {
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ return;
+ }
+
+ Adapter->ProcessingDpc = TRUE;
+ Adapter->References++;
+
+ do {
+
+ Adapter->WakeUpTimeout = FALSE;
+
+ RequeueRcv = WdReceiveEvents(Adapter);
+
+ WdTransmitEvents(Adapter);
+
+ //
+ // This causes any transmit that may have caused a tranmitted packet
+ // to loopback and indicate the packet.
+ //
+
+ } while ( Adapter->LoopbackQueue != (PNDIS_PACKET) NULL || RequeueRcv );
+
+ //
+ // We're done with this DPC.
+ //
+
+ Adapter->ProcessingDpc = FALSE;
+
+ //
+ // Reenable interrupts
+ //
+
+ Adapter->LMAdapter.InterruptMask = PACKET_RECEIVE_ENABLE |
+ PACKET_TRANSMIT_ENABLE |
+ RECEIVE_ERROR_ENABLE |
+ TRANSMIT_ERROR_ENABLE |
+ OVERWRITE_WARNING_ENABLE |
+ COUNTER_OVERFLOW_ENABLE;
+
+ NdisSynchronizeWithInterrupt(
+ &(Adapter->LMAdapter.NdisInterrupt),
+ LM_Enable_Adapter,
+ &Adapter->LMAdapter
+ );
+
+ WD_DO_DEFERRED(Adapter);
+
+ IF_LOUD( DbgPrint("<==IntDpc\n");)
+
+ IF_LOG(LOG('D'));
+
+}
+
+
+VOID
+WdIndicateLoopbackPacket(
+ IN PWD_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+ This routine indicates a packet to the current host.
+
+ NOTE: THIS ROUTINE MUST BE CALLED WITH THE SPINLOCK HELD.
+
+Arguments:
+
+ Adapter - Pointer to the adapter structure.
+
+ Packet - Pointer to the packet to indicate.
+
+Return Value:
+
+ NONE.
+
+--*/
+{
+ UINT IndicateLen;
+ UINT PacketLen;
+
+ //
+ // Store that we are indicating a loopback packet
+ //
+
+ Adapter->IndicatingPacket = Packet;
+ Adapter->IndicatedAPacket = TRUE;
+
+ //
+ // Indicate packet.
+ //
+
+ IF_LOUD( DbgPrint("Indicating loopback packet\n");)
+
+ //
+ // Indicate up to 252 bytes.
+ //
+
+ NdisQueryPacket(Packet, NULL, NULL, NULL, &PacketLen);
+
+ if (PacketLen >= ETH_LENGTH_OF_ADDRESS) {
+
+ IndicateLen = (PacketLen > (Adapter->MaxLookAhead + WD_HEADER_SIZE) ?
+ (Adapter->MaxLookAhead + WD_HEADER_SIZE) :
+ PacketLen
+ );
+
+ //
+ // Copy the lookahead data into a contiguous buffer.
+ //
+
+ WdCopyOver(Adapter->LookAhead,
+ Packet,
+ 0,
+ IndicateLen
+ );
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+
+ //
+ // Indicate packet
+ //
+
+ if (PacketLen < WD_HEADER_SIZE) {
+
+ //
+ // Runt packet
+ //
+
+ EthFilterIndicateReceive(
+ Adapter->LMAdapter.FilterDB,
+ (NDIS_HANDLE)Adapter,
+ (PCHAR)Adapter->LookAhead,
+ Adapter->LookAhead,
+ PacketLen,
+ NULL,
+ 0,
+ 0
+ );
+
+ } else {
+
+ EthFilterIndicateReceive(
+ Adapter->LMAdapter.FilterDB,
+ (NDIS_HANDLE)Adapter,
+ (PCHAR)Adapter->LookAhead,
+ Adapter->LookAhead,
+ WD_HEADER_SIZE,
+ Adapter->LookAhead + WD_HEADER_SIZE,
+ IndicateLen - WD_HEADER_SIZE,
+ PacketLen - WD_HEADER_SIZE
+ );
+
+ }
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ }
+
+}
+
+
+BOOLEAN
+WdReceiveEvents(
+ IN PWD_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine handles all Receive deferred processing, this includes any
+ packets that never went through the XmitQueue and need to be indicated
+ (Loopbacked), and all card events.
+
+ NOTE: THIS ROUTINE MUST BE CALLED WITH THE SPINLOCK HELD.
+
+ NOTE: The Adapter->ProcessingReceiveEvents MUST be set upon entry and
+ with the spinlock held.
+
+Arguments:
+
+ Context - a handle to the adapter block.
+
+Return Value:
+
+ Do we need to requeue this Rcv.
+
+--*/
+{
+ PNDIS_PACKET Packet;
+ PWD_OPEN TmpOpen;
+ NDIS_STATUS Status;
+ BOOLEAN RequeueRcv;
+
+ IF_LOG(LOG('e'));
+
+ RequeueRcv = (BOOLEAN)(LM_Service_Receive_Events(&Adapter->LMAdapter) ==
+ REQUEUE_LATER);
+
+ while (Adapter->LoopbackQueue != NULL) {
+
+ //
+ // Take packet off queue.
+ //
+
+ Packet = Adapter->LoopbackQueue;
+
+ if (Packet == Adapter->LoopbackQTail) {
+
+ Adapter->LoopbackQTail = NULL;
+
+ }
+
+ Adapter->LoopbackQueue = RESERVED(Packet)->NextPacket;
+
+ //
+ // Indicate the packet
+ //
+
+ WdIndicateLoopbackPacket(Adapter,Packet);
+
+
+ //
+ // Complete the packet send.
+ //
+
+ Adapter->FramesXmitGood++;
+
+ //
+ // Save this, since once we complete the send
+ // Reserved is no longer valid.
+ //
+
+ TmpOpen = RESERVED(Packet)->Open;
+
+ IF_VERY_LOUD( DbgPrint("Completing send for packet 0x%x\n",Packet);)
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteSend(TmpOpen->NdisBindingContext,
+ Packet,
+ NDIS_STATUS_SUCCESS
+ );
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ WdRemoveReference(TmpOpen);
+
+ }
+
+ //
+ // If any indications done, then
+ //
+ // CompleteIndications();
+ //
+
+ if (Adapter->IndicatedAPacket) {
+
+ Adapter->IndicatedAPacket = FALSE;
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ EthFilterIndicateReceiveComplete(Adapter->LMAdapter.FilterDB);
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ }
+
+ if ((Adapter->ResetRequested) && (Adapter->References == 1)) {
+
+ PNDIS_PACKET Packet;
+ PWD_OPEN TmpOpen;
+
+ IF_LOG(LOG('R'));
+ IF_VERY_LOUD( DbgPrint("Starting Reset\n");)
+
+ Adapter->ResetInProgress = TRUE;
+
+ NdisSynchronizeWithInterrupt(
+ &(Adapter->LMAdapter.NdisInterrupt),
+ LM_Disable_Adapter,
+ &Adapter->LMAdapter
+ );
+
+ //
+ // Indicate Status to all opens
+ //
+
+ IF_VERY_LOUD( DbgPrint("Indicating status\n");)
+
+ TmpOpen = Adapter->OpenQueue;
+
+ while (TmpOpen != (PWD_OPEN)NULL) {
+
+ AddRefWhileHoldingSpinLock(Adapter, TmpOpen);
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ NdisIndicateStatus(TmpOpen->NdisBindingContext,
+ NDIS_STATUS_RESET_START,
+ NULL,
+ 0
+ );
+
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ WdRemoveReference(TmpOpen);
+
+ TmpOpen = TmpOpen->NextOpen;
+
+ }
+
+ //
+ // Reset the Card.
+ //
+
+ IF_VERY_LOUD( DbgPrint("Resetting the card\n");)
+
+ if (LM_Initialize_Adapter(&Adapter->LMAdapter) != SUCCESS) {
+
+ Adapter->HardwareFailure = TRUE;
+
+ NdisWriteErrorLogEntry(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 0
+ );
+
+ } else {
+
+ Adapter->HardwareFailure = FALSE;
+
+ }
+
+
+
+ //
+ // Put packets that were on the card on to the front of the xmit
+ // queue.
+ //
+
+ if (Adapter->PacketsOnCard != NULL) {
+
+ IF_VERY_LOUD( DbgPrint("Moving Packets On card\n");)
+
+ RESERVED(Adapter->PacketsOnCardTail)->NextPacket = Adapter->XmitQueue;
+
+ Adapter->XmitQueue = Adapter->PacketsOnCard;
+
+ Adapter->PacketsOnCard = Adapter->PacketsOnCardTail = NULL;
+
+ }
+
+
+ //
+ // Put packets on loopback queue on xmit queue
+ //
+
+ if (Adapter->LoopbackQueue != NULL) {
+
+ RESERVED(Adapter->LoopbackQTail)->NextPacket = Adapter->XmitQueue;
+
+ Adapter->XmitQueue = Adapter->LoopbackQueue;
+
+ }
+
+
+ //
+ // Wipe out loopback queue.
+ //
+
+ Adapter->LoopbackQueue = Adapter->LoopbackQTail = (PNDIS_PACKET)NULL;
+
+
+ //
+ // Abort all xmits
+ //
+
+ IF_VERY_LOUD( DbgPrint("Killing Xmits\n");)
+
+ while (Adapter->XmitQueue != NULL) {
+
+ Packet = Adapter->XmitQueue;
+
+ Adapter->XmitQueue = RESERVED(Packet)->NextPacket;
+
+ TmpOpen = RESERVED(Packet)->Open;
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteSend(TmpOpen->NdisBindingContext,
+ Packet,
+ NDIS_STATUS_REQUEST_ABORTED
+ );
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ WdRemoveReference(TmpOpen);
+
+ }
+
+ Adapter->XmitQTail = NULL;
+
+ if (!Adapter->HardwareFailure) {
+
+ LM_Open_Adapter(&Adapter->LMAdapter);
+
+ }
+
+ Adapter->ResetInProgress = FALSE;
+
+ IF_VERY_LOUD( DbgPrint("Indicating Done\n");)
+
+ //
+ // Indicate Reset is done
+ //
+
+ //
+ // Indicate Status to all opens
+ //
+
+ IF_VERY_LOUD( DbgPrint("Indicating status\n");)
+
+ TmpOpen = Adapter->OpenQueue;
+
+ while (TmpOpen != (PWD_OPEN)NULL) {
+
+ AddRefWhileHoldingSpinLock(Adapter, TmpOpen);
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ if (Adapter->HardwareFailure) {
+
+ NdisIndicateStatus(TmpOpen->NdisBindingContext,
+ NDIS_STATUS_CLOSED,
+ NULL,
+ 0
+ );
+
+ }
+
+ Status = (Adapter->HardwareFailure) ?
+ NDIS_STATUS_FAILURE :
+ NDIS_STATUS_SUCCESS;
+
+
+ NdisIndicateStatus(TmpOpen->NdisBindingContext,
+ NDIS_STATUS_RESET_END,
+ &Status,
+ sizeof(Status)
+ );
+
+ NdisIndicateStatusComplete(TmpOpen->NdisBindingContext);
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ WdRemoveReference(TmpOpen);
+
+ TmpOpen = TmpOpen->NextOpen;
+
+ }
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteReset(Adapter->ResetOpen->NdisBindingContext,
+ (Adapter->HardwareFailure) ?
+ NDIS_STATUS_FAILURE :
+ NDIS_STATUS_SUCCESS
+ );
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ WdRemoveReference(Adapter->ResetOpen);
+
+ //
+ // Reset the flag
+ //
+
+
+ IF_VERY_LOUD( DbgPrint("Restarting Adapter\n");)
+
+ Adapter->ResetRequested = FALSE;
+
+ LM_Open_Adapter(&Adapter->LMAdapter);
+
+ }
+
+#if DBG
+
+ else if (Adapter->ResetRequested) {
+
+ IF_LOUD( DbgPrint("No reset because count is... 0x%x\n", Adapter->References);)
+
+ }
+
+#endif
+
+ IF_LOG(LOG('E'));
+
+ return RequeueRcv;
+}
+
+
+VOID
+WdTransmitEvents(
+ IN PWD_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine handles all transmit deferred processing.
+
+ NOTE : Called with lock held!!
+
+Arguments:
+
+ Adapter - pointer to the adapter structure.
+
+Return Value:
+
+ NONE.
+
+--*/
+{
+
+ if (Adapter->ResetInProgress) {
+
+ return;
+
+ }
+
+ IF_LOG(LOG('w'));
+
+ LM_Service_Transmit_Events(&Adapter->LMAdapter);
+
+ IF_LOG(LOG('W'));
+
+}
+
+UINT
+WdCopyOver(
+ OUT PUCHAR Buf, // destination
+ IN PNDIS_PACKET Packet, // source packet
+ IN UINT Offset, // offset in packet
+ IN UINT Length // number of bytes to copy
+ )
+
+/*++
+
+Routine Description:
+
+ Copies bytes from a packet into a buffer. Used to copy data
+ out of a packet during loopback indications.
+
+Arguments:
+
+ Buf - the destination buffer
+ Packet - the source packet
+ Offset - the offset in the packet to start copying at
+ Length - the number of bytes to copy
+
+Return Value:
+
+ The actual number of bytes copied; will be less than Length if
+ the packet length is less than Offset+Length.
+
+--*/
+
+{
+ PNDIS_BUFFER CurBuffer;
+ UINT BytesCopied;
+ PUCHAR BufVA;
+ UINT BufLen;
+ UINT ToCopy;
+ UINT CurOffset;
+
+
+ BytesCopied = 0;
+
+ //
+ // First find a spot Offset bytes into the packet.
+ //
+
+ CurOffset = 0;
+
+ NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, NULL);
+
+ while (CurBuffer != (PNDIS_BUFFER)NULL) {
+
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufVA, &BufLen);
+
+ if (CurOffset + BufLen > Offset) {
+
+ break;
+
+ }
+
+ CurOffset += BufLen;
+
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+
+ }
+
+
+ //
+ // See if the end of the packet has already been passed.
+ //
+
+ if (CurBuffer == (PNDIS_BUFFER)NULL) {
+
+ return 0;
+
+ }
+
+
+ //
+ // Now copy over Length bytes.
+ //
+
+ BufVA += (Offset - CurOffset);
+
+ BufLen -= (Offset - CurOffset);
+
+ for (;;) {
+
+ ToCopy = (BytesCopied+BufLen > Length) ? Length - BytesCopied : BufLen;
+
+ WD_MOVE_MEM(Buf+BytesCopied, BufVA, ToCopy);
+
+ BytesCopied += ToCopy;
+
+
+ if (BytesCopied == Length) {
+
+ return BytesCopied;
+
+ }
+
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+
+ if (CurBuffer == (PNDIS_BUFFER)NULL) {
+
+ break;
+
+ }
+
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufVA, &BufLen);
+
+ }
+
+ return BytesCopied;
+
+}
+
+
+
+NDIS_STATUS
+WdTransferData(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ )
+
+/*++
+
+Routine Description:
+
+ NDIS function.
+
+Arguments:
+
+ see NDIS 3.0 spec.
+
+Notes:
+
+ - The MacReceiveContext will be a pointer to the open block for
+ the packet.
+ - The LoopbackPacket field in the adapter block will be NULL if this
+ is a call for a normal packet, otherwise it will be set to point
+ to the loopback packet.
+
+--*/
+{
+ PWD_OPEN Open = PWD_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+ PWD_ADAPTER Adapter = Open->Adapter;
+ PNDIS_BUFFER CurrentBuffer;
+ PUCHAR BufferVA;
+ UINT BufferLength, Copied;
+ UINT CurrentOffset;
+
+ UNREFERENCED_PARAMETER(MacReceiveContext);
+
+ ByteOffset += WD_HEADER_SIZE;
+
+ if (Adapter->IndicatingPacket != NULL) {
+
+ IF_LOUD( DbgPrint("Transferring data for loopback packet\n");)
+
+ //
+ // It is a loopback packet
+ //
+
+ NdisQueryPacket(Packet, NULL, NULL, &CurrentBuffer, NULL);
+
+ CurrentOffset = ByteOffset;
+
+ while (CurrentBuffer != (PNDIS_BUFFER)NULL) {
+
+ NdisQueryBuffer(CurrentBuffer, (PVOID *)&BufferVA, &BufferLength);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ Copied =
+ WdCopyOver(BufferVA,
+ Adapter->IndicatingPacket,
+ CurrentOffset,
+ BufferLength
+ );
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ CurrentOffset += Copied;
+
+ if (Copied < BufferLength) {
+
+ break;
+
+ }
+
+ NdisGetNextBuffer(CurrentBuffer, &CurrentBuffer);
+
+ }
+
+ //
+ // We are done, return.
+ //
+
+ *BytesTransferred = CurrentOffset - ByteOffset;
+
+ if ( *BytesTransferred > BytesToTransfer ) {
+
+ *BytesTransferred = BytesToTransfer;
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+
+ } else if (Adapter->IndicatedAPacket) {
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ IF_LOUD( DbgPrint("Transferring data for card packet\n");)
+
+ if (LM_Receive_Copy(
+ BytesTransferred,
+ BytesToTransfer,
+ ByteOffset,
+ Packet,
+ &(Adapter->LMAdapter)) != SUCCESS) {
+
+ //
+ // Copy failed.
+ //
+
+ *BytesTransferred = 0;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ return(NDIS_STATUS_FAILURE);
+
+ } else {
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+ } else {
+
+ return(NDIS_STATUS_NOT_INDICATING);
+
+ }
+
+}
+
+BOOLEAN
+WdSyncCloseAdapter(
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ This function is used to synchronize with the lower MAC layer close
+ calls that may access the same areas of the LM that are accessed in
+ the ISR.
+
+Arguments:
+
+ see NDIS 3.0 spec.
+
+Notes:
+
+ returns TRUE on success, else FALSE.
+
+--*/
+{
+
+ if (LM_Close_Adapter((Ptr_Adapter_Struc)Context) == SUCCESS) {
+
+ return(TRUE);
+
+ } else {
+
+ return(FALSE);
+
+ }
+
+}
+
+
+VOID
+WdWakeUpDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID Context,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+
+/*++
+
+Routine Description:
+
+ This DPC routine is queued every 5 seconds to check on the
+ queues. If an interrupt was not received
+ in the last 5 seconds and there should have been one,
+ then we abort all operations.
+
+Arguments:
+
+ Context - Really a pointer to the adapter.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PWD_ADAPTER Adapter = (PWD_ADAPTER)Context;
+ PWD_OPEN TmpOpen;
+ PNDIS_PACKET TransmitPacket;
+ PMAC_RESERVED Reserved;
+
+ UNREFERENCED_PARAMETER(SystemSpecific1);
+ UNREFERENCED_PARAMETER(SystemSpecific2);
+ UNREFERENCED_PARAMETER(SystemSpecific3);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ if ((Adapter->WakeUpTimeout) &&
+ Adapter->LMAdapter.TransmitInterruptPending) {
+
+ //
+ // We had a pending operation the last time we ran,
+ // and it has not been completed...we need to complete
+ // it now.
+
+ Adapter->WakeUpTimeout = FALSE;
+
+ Adapter->HardwareFailure = TRUE;
+
+ //
+ // Disable adapter
+ //
+ IF_LOG(LOG('*'));
+ LM_Disable_Adapter(&Adapter->LMAdapter);
+
+ if (Adapter->WakeUpErrorCount < 10) {
+
+ Adapter->WakeUpErrorCount++;
+
+ NdisWriteErrorLogEntry(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 0
+ );
+
+ }
+
+ while (Adapter->PacketsOnCard != NULL) {
+
+ TransmitPacket = Adapter->PacketsOnCard;
+
+ Reserved = RESERVED(TransmitPacket);
+
+ Adapter->PacketsOnCard = Reserved->NextPacket;
+
+ if (Adapter->PacketsOnCard == NULL) {
+
+ Adapter->PacketsOnCardTail = NULL;
+
+ }
+
+ TmpOpen = Reserved->Open;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteSend(
+ TmpOpen->NdisBindingContext,
+ TransmitPacket,
+ NDIS_STATUS_SUCCESS
+ );
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ TmpOpen->ReferenceCount--;
+
+ }
+
+ while (Adapter->XmitQueue != NULL) {
+
+ TransmitPacket = Adapter->XmitQueue;
+
+ Reserved = RESERVED(TransmitPacket);
+
+ //
+ // Remove the packet from the queue.
+ //
+
+ Adapter->XmitQueue = Reserved->NextPacket;
+
+ if (Adapter->XmitQueue == NULL) {
+
+ Adapter->XmitQTail = NULL;
+
+ }
+
+ TmpOpen = Reserved->Open;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteSend(
+ TmpOpen->NdisBindingContext,
+ TransmitPacket,
+ NDIS_STATUS_SUCCESS
+ );
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ TmpOpen->ReferenceCount--;
+
+ }
+
+ Adapter->WakeUpTimeout = FALSE;
+
+ Adapter->LMAdapter.TransmitInterruptPending = FALSE;
+
+ //
+ // reinitialize the card
+ //
+
+ if (LM_Initialize_Adapter(&Adapter->LMAdapter) != SUCCESS) {
+
+ Adapter->HardwareFailure = TRUE;
+
+ NdisWriteErrorLogEntry(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 0
+ );
+
+ } else {
+
+ Adapter->HardwareFailure = FALSE;
+
+ }
+
+ //
+ // reenable interrupts
+ //
+
+ LM_Enable_Adapter(&Adapter->LMAdapter);
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ } else {
+
+ if ((Adapter->PacketsOnCard != NULL) ||
+ (Adapter->XmitQueue != NULL)) {
+
+ Adapter->WakeUpTimeout = TRUE;
+
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+
+ }
+
+ //
+ // Fire off another Dpc to execute after 5 seconds
+ //
+
+ NdisSetTimer(
+ &Adapter->WakeUpTimer,
+ 5000
+ );
+
+}
diff --git a/private/ntos/ndis/wd/wdhrd.h b/private/ntos/ndis/wd/wdhrd.h
new file mode 100644
index 000000000..6574d6e07
--- /dev/null
+++ b/private/ntos/ndis/wd/wdhrd.h
@@ -0,0 +1,915 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ wdhrd.h
+
+Abstract:
+
+ The main program for an Western Digital MAC driver.
+
+Author:
+
+ Anthony V. Ercolano (tonye) creation-date 19-Jun-1990 (Driver model)
+
+ Orginal Elnkii code by AdamBa.
+
+ Modified for WD by SeanSe.
+
+Environment:
+
+ This driver is expected to work in DOS, OS2 and NT at the equivalent
+ of kernal mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+
+--*/
+
+#ifndef _WDHARDWARE_
+#define _WDHARDWARE_
+
+
+
+// Adapter->IoBaseAddr
+//
+// must match the setting of I/O Base Address jumper on
+// the card. Choices are 0x300 and 0x280
+//
+
+#define DEFAULT_IOBASEADDR (USHORT)0x280
+
+
+
+// Adapter->MaxOpens
+//
+// the maximum number of protocols that may be bound to this
+// adapter at one time.
+
+#define DEFAULT_MAXOPENS 4
+
+
+
+// Adapter->MulticastListMax
+//
+// the maximum number of different multicast addresses that
+// may be specified to this adapter (the list is global for
+// all protocols).
+
+#define DEFAULT_MULTICASTLISTMAX 16
+
+
+//
+// The maximum packet transmittable.
+//
+
+#define WD_MAX_PACKET_SIZE 1514
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//
+// Offsets from Adapter->IoPAddr of the ports used to access
+// the 8390 NIC registers.
+//
+// The names in parenthesis are the abbreviations by which
+// the registers are referred to in the 8390 data sheet.
+//
+// Some of the offsets appear more than once
+// because they have have relevant page 0 and page 1 values,
+// or they are different registers when read than they are
+// when written. The notation MSB indicates that only the
+// MSB can be set for this register, the LSB is assumed 0.
+//
+
+#define NIC_COMMAND 0x0 // (CR)
+#define NIC_PAGE_START 0x1 // (PSTART) MSB, write-only
+#define NIC_PHYS_ADDR 0x1 // (PAR0) page 1
+#define NIC_PAGE_STOP 0x2 // (PSTOP) MSB, write-only
+#define NIC_BOUNDARY 0x3 // (BNRY) MSB
+#define NIC_XMIT_START 0x4 // (TPSR) MSB, write-only
+#define NIC_XMIT_STATUS 0x4 // (TSR) read-only
+#define NIC_XMIT_COUNT_LSB 0x5 // (TBCR0) write-only
+#define NIC_XMIT_COUNT_MSB 0x6 // (TBCR1) write-only
+#define NIC_FIFO 0x6 // (FIFO) read-only
+#define NIC_INTR_STATUS 0x7 // (ISR)
+#define NIC_CURRENT 0x7 // (CURR) page 1
+#define NIC_MC_ADDR 0x8 // (MAR0) page 1
+#define NIC_RMT_COUNT_LSB 0xa // (RBCR0) write-only
+#define NIC_RMT_COUNT_MSB 0xb // (RBCR1) write-only
+#define NIC_RCV_CONFIG 0xc // (RCR) write-only
+#define NIC_RCV_STATUS 0xc // (RSR) read-only
+#define NIC_XMIT_CONFIG 0xd // (TCR) write-only
+#define NIC_FAE_ERR_CNTR 0xd // (CNTR0) read-only
+#define NIC_DATA_CONFIG 0xe // (DCR) write-only
+#define NIC_CRC_ERR_CNTR 0xe // (CNTR1) read-only
+#define NIC_INTR_MASK 0xf // (IMR) write-only
+#define NIC_MISSED_CNTR 0xf // (CNTR2) read-only
+
+
+//
+// Constants for the NIC_COMMAND register.
+//
+// Start/stop the card, start transmissions, and select
+// which page of registers was seen through the ports.
+//
+
+#define CR_STOP (UCHAR)0x01 // reset the card
+#define CR_START (UCHAR)0x02 // start the card
+#define CR_XMIT (UCHAR)0x04 // begin transmission
+#define CR_NO_DMA (UCHAR)0x20 // stop remote DMA
+
+#define CR_PS0 (UCHAR)0x40 // low bit of page number
+#define CR_PS1 (UCHAR)0x80 // high bit of page number
+#define CR_PAGE0 (UCHAR)0x00 // select page 0
+#define CR_PAGE1 CR_PS0 // select page 1
+#define CR_PAGE2 CR_PS1 // select page 2
+
+
+//
+// Constants for the NIC_XMIT_STATUS register.
+//
+// Indicate the result of a packet transmission.
+//
+
+#define TSR_XMIT_OK (UCHAR)0x01 // transmit with no errors
+#define TSR_COLLISION (UCHAR)0x04 // collided at least once
+#define TSR_ABORTED (UCHAR)0x08 // too many collisions
+#define TSR_NO_CARRIER (UCHAR)0x10 // carrier lost
+#define TSR_NO_CDH (UCHAR)0x40 // no collision detect heartbeat
+
+
+//
+// Constants for the NIC_INTR_STATUS register.
+//
+// Indicate the cause of an interrupt.
+//
+
+#define ISR_RCV (UCHAR)0x01 // packet received with no errors
+#define ISR_XMIT (UCHAR)0x02 // packet transmitted with no errors
+#define ISR_RCV_ERR (UCHAR)0x04 // error on packet reception
+#define ISR_XMIT_ERR (UCHAR)0x08 // error on packet transmission
+#define ISR_OVERFLOW (UCHAR)0x10 // receive buffer overflow
+#define ISR_COUNTER (UCHAR)0x20 // MSB set on tally counter
+#define ISR_RESET (UCHAR)0x80 // (not an interrupt) card is reset
+
+
+//
+// Constants for the NIC_RCV_CONFIG register.
+//
+// Configure what type of packets are received.
+//
+
+#define RCR_REJECT_ERR (UCHAR)0x00 // reject error packets
+#define RCR_BROADCAST (UCHAR)0x04 // receive broadcast packets
+#define RCR_MULTICAST (UCHAR)0x08 // receive multicast packets
+#define RCR_ALL_PHYS (UCHAR)0x10 // receive ALL directed packets
+
+
+//
+// Constants for the NIC_RCV_STATUS register.
+//
+// Indicate the status of a received packet.
+//
+// These are also used to interpret the status byte in the
+// packet header of a received packet.
+//
+
+#define RSR_PACKET_OK (UCHAR)0x01 // packet received with no errors
+#define RSR_CRC_ERROR (UCHAR)0x02 // packet received with CRC error
+#define RSR_MULTICAST (UCHAR)0x20 // packet received was multicast
+#define RSR_DISABLED (UCHAR)0x40 // received is disabled
+#define RSR_DEFERRING (UCHAR)0x80 // receiver is deferring
+
+
+//
+// Constants for the NIC_XMIT_CONFIG register.
+//
+// Configures how packets are transmitted.
+//
+
+#define TCR_NO_LOOPBACK (UCHAR)0x00 // normal operation
+#define TCR_LOOPBACK (UCHAR)0x02 // loopback (set when NIC is stopped)
+
+#define TCR_INHIBIT_CRC (UCHAR)0x01 // inhibit appending of CRC
+
+#define TCR_NIC_LBK (UCHAR)0x02 // loopback through the NIC
+#define TCR_SNI_LBK (UCHAR)0x04 // loopback through the SNI
+#define TCR_COAX_LBK (UCHAR)0x06 // loopback to the coax
+
+
+//
+// Constants for the NIC_DATA_CONFIG register.
+//
+// Set data transfer sizes.
+//
+
+#define DCR_BYTE_WIDE (UCHAR)0x00 // byte-wide DMA transfers
+#define DCR_WORD_WIDE (UCHAR)0x01 // word-wide DMA transfers
+
+#define DCR_LOOPBACK (UCHAR)0x00 // loopback mode (TCR must be set)
+#define DCR_NORMAL (UCHAR)0x08 // normal operation
+
+#define DCR_FIFO_8_BYTE (UCHAR)0x40 // 8-byte FIFO threshhold
+
+
+//
+// Constants for the NIC_INTR_MASK register.
+//
+// Configure which ISR settings actually cause interrupts.
+//
+
+#define IMR_RCV (UCHAR)0x01 // packet received with no errors
+#define IMR_XMIT (UCHAR)0x02 // packet transmitted with no errors
+#define IMR_RCV_ERR (UCHAR)0x04 // error on packet reception
+#define IMR_XMIT_ERR (UCHAR)0x08 // error on packet transmission
+#define IMR_OVERFLOW (UCHAR)0x10 // receive buffer overflow
+#define IMR_COUNTER (UCHAR)0x20 // MSB set on tally counter
+
+
+
+//
+// Offsets from Adapter->GaPAddr (which is Adapter->IoPAddr+0x400)
+// of the ports used to access the Elnkii Gate Array registers.
+//
+// The names in parenthesis are the abbreviations by which
+// the registers are referred to in the Elnkii Technical
+// Reference.
+//
+
+#define GA_PAGE_START 0x0 // (PSTR) MSB
+#define GA_PAGE_STOP 0x1 // (PSPR) MSB
+#define GA_DRQ_TIMER 0x2 // (DQTR)
+#define GA_IO_BASE 0x3 // (BCFR) read-only
+#define GA_MEM_BASE 0x4 // (PCFR) read-only
+#define GA_CONFIG 0x5 // (GACFR)
+#define GA_CONTROL 0x6 // (CTRL)
+#define GA_STATUS 0x7 // (STREG) read-only
+#define GA_INT_DMA_CONFIG 0x8 // (IDCFR)
+#define GA_DMA_ADDR_MSB 0x9 // (DAMSB)
+#define GA_DMA_ADDR_LSB 0xa // (DALSB)
+#define GA_REG_FILE_MSB 0xe // (RFMSB)
+#define GA_REG_FILE_LSB 0xf // (RFLSB)
+
+
+//
+// Constants for the GA_DRQ_TIMER register.
+//
+
+#define DQTR_16_BYTE (UCHAR)0x10 // 16-byte programmed I/O bursts
+#define DQTR_8_BYTE (UCHAR)0x08 // 8-byte programmed I/O bursts
+
+
+//
+// Constants for the GA_CONFIG register.
+//
+
+#define GACFR_TC_MASK (UCHAR)0x40 // block DMA complete interrupts
+#define GACFR_RAM_SEL (UCHAR)0x08 // allow memory-mapped mode
+#define GACFR_MEM_BANK1 (UCHAR)0x01 // select window for 8K buffer
+
+
+//
+// Constants for the GA_CONTROL register.
+//
+
+#define CTRL_START (UCHAR)0x80 // start the DMA controller
+#define CTRL_STOP (UCHAR)0x00 // stop the DMA controller
+
+#define CTRL_DIR_DOWN (UCHAR)0x40 // system->board transfers
+#define CTRL_DIR_UP (UCHAR)0x00 // board->system transfers
+
+#define CTRL_DB_SEL (UCHAR)0x20 // connect FIFOs serially
+
+#define CTRL_PROM_SEL (UCHAR)0x04 // window PROM into GaPAddr ports
+#define CTRL_GA_SEL (UCHAR)0x00 // window GA into GaPAddr ports
+
+#define CTRL_BNC (UCHAR)0x02 // internal tranceiver
+#define CTRL_DIX (UCHAR)0x00 // external tranceiver
+
+#define CTRL_RESET (UCHAR)0x01 // emulate power up reset
+
+
+//
+// Constants for the GA_STATUS register.
+//
+
+#define STREG_DP_READY (UCHAR)0x80 // ready for programmed I/O transfer
+#define STREG_UNDERFLOW (UCHAR)0x40 // register file underflow
+#define STREG_OVERFLOW (UCHAR)0x20 // register file overflow
+#define STREG_IN_PROG (UCHAR)0x08 // programmed I/O in progress
+
+
+
+
+//++
+//
+// VOID
+// CardStartXmit(
+// IN PELNKII_ADAPTER Adapter
+// )
+//
+// Routine Description:
+//
+// Starts a packet transmission. The transmit buffer number is
+// taken from Adapter->CurBufXmitting and the length of the packet
+// is taken from Adapter->PacketLens[Adapter->CurBufXmitting].
+// Calls SyncCardStartXmit.
+//
+// Arguments:
+//
+// Adapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardStartXmit(Adapter) \
+ NdisSynchronizeWithInterrupt(&(Adapter)->NdisInterrupt, \
+ SyncCardStartXmit, (PVOID)(Adapter))
+
+
+//++
+//
+// VOID
+// CardWriteMulticast(
+// IN PELNKII_ADAPTER Adapter,
+// IN UCHAR Byte
+// )
+//
+// Routine Description:
+//
+// Writes a single byte to the multicast address register bit mask.
+// Calls SyncCardWriteMulticast. Byte indicates which byte to
+// write (0-7); the actual value to write is taken from
+// Adapter->NicMulticastRegs[Byte].
+//
+// Arguments:
+//
+// Adapter - The adapter block.
+// Byte - Which multicast byte to write.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardWriteMulticast(Adapter, Byte) \
+ (Adapter)->ByteToWrite = Byte, \
+ NdisSynchronizeWithInterrupt(&(Adapter)->NdisInterrupt, \
+ SyncCardWriteMulticast, (PVOID)(Adapter))
+
+
+//++
+//
+// VOID
+// CardSetAllMulticast(
+// IN PELNKII_ADAPTER Adapter
+// )
+//
+// Routine Description:
+//
+// Enables every bit in the card multicast bit mask.
+// Calls SyncCardSetAllMulticast.
+//
+// Arguments:
+//
+// Adapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardSetAllMulticast(Adapter) \
+ NdisSynchronizeWithInterrupt(&(Adapter)->NdisInterrupt, \
+ SyncCardSetAllMulticast, (PVOID)(Adapter))
+
+
+//++
+//
+// VOID
+// CardCopyMulticastRegs(
+// IN PELNKII_ADAPTER Adapter
+// )
+//
+// Routine Description:
+//
+// Writes out the entire multicast bit mask to the card from
+// Adapter->NicMulticastRegs. Calls SyncCardCopyMulticastRegs.
+//
+// Arguments:
+//
+// Adapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardCopyMulticastRegs(Adapter) \
+ NdisSynchronizeWithInterrupt(&(Adapter)->NdisInterrupt, \
+ SyncCardCopyMulticastRegs, (PVOID)(Adapter))
+
+
+//++
+//
+// VOID
+// CardCopyPhysicalAddress(
+// IN PELNKII_ADAPTER Adapter
+// )
+//
+// Routine Description:
+//
+// Writes out the physical address to the card. The value is
+// read from Adapter->StationAddress. Calls SyncCardCopyPhysicalAddress.
+//
+// Arguments:
+//
+// Adapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardCopyPhysicalAddress(Adapter) \
+ NdisSynchronizeWithInterrupt(&(Adapter)->NdisInterrupt, \
+ SyncCardCopyPhysicalAddress, (PVOID)(Adapter))
+
+
+//++
+//
+// VOID
+// CardGetInterruptStatus(
+// IN PELNKII_ADAPTER Adapter,
+// OUT PUCHAR InterrupStatus
+// )
+//
+// Routine Description:
+//
+// Reads the interrupt status (ISR) register from the card. Only
+// called at IRQL INTERRUPT_LEVEL.
+//
+// Arguments:
+//
+// Adapter - The adapter block.
+//
+// InterruptStatus - Returns the value of ISR.
+//
+// Return Value:
+//
+//--
+
+#define CardGetInterruptStatus(Adapter,InterruptStatus) \
+ NdisReadPortUchar((Adapter)->NdisAdapterHandle, (Adapter)->IoPAddr+NIC_INTR_STATUS, (InterruptStatus))
+
+
+//++
+//
+// UCHAR
+// CardGetXmitStatus(
+// IN PELNKII_ADAPTER Adapter
+// )
+//
+// Routine Description:
+//
+// Reads the transmit status (TSR) register from the card.
+// Calls SyncCardGetXmitStatus.
+//
+// Arguments:
+//
+// Adapter - The adapter block.
+//
+// Return Value:
+//
+// The value of TSR.
+//
+//--
+
+#define CardGetXmitStatus(Adapter) \
+ NdisSynchronizeWithInterrupt(&(Adapter)->NdisInterrupt, \
+ SyncCardGetXmitStatus, (PVOID)(Adapter))
+
+
+//++
+//
+// UCHAR
+// CardGetCurrent(
+// IN PELNKII_ADAPTER Adapter
+// )
+//
+// Routine Description:
+//
+// Reads the current (CURR) register from the card.
+// Calls SyncCardGetCurrent.
+//
+// Arguments:
+//
+// Adapter - The adapter block.
+//
+// Return Value:
+//
+// The value of CURR.
+//
+//--
+
+#define CardGetCurrent(Adapter) \
+ NdisSynchronizeWithInterrupt(&(Adapter)->NdisInterrupt, \
+ SyncCardGetCurrent, (PVOID)(Adapter))
+
+
+//++
+//
+// VOID
+// CardSetBoundary(
+// IN PELNKII_ADAPTER Adapter
+// )
+//
+// Routine Description:
+//
+// Sets the boundary (BNRY) register on the card. The value used
+// is one before Adapter->NicNextPacket. Calls SyncCardSetBoundary.
+//
+// Arguments:
+//
+// Adapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardSetBoundary(Adapter) \
+ NdisSynchronizeWithInterrupt(&(Adapter)->NdisInterrupt, \
+ SyncCardSetBoundary, (PVOID)(Adapter))
+
+
+//++
+//
+// VOID
+// CardSetReceiveConfig(
+// IN PELNKII_ADAPTER Adapter
+// )
+//
+// Routine Description:
+//
+// Sets the receive configuration (RCR) register on the card.
+// The value used is Adapter->NicReceiveConfig. Calls
+// SyncCardSetReceiveConfig.
+//
+// Arguments:
+//
+// Adapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardSetReceiveConfig(Adapter) \
+ NdisSynchronizeWithInterrupt(&(Adapter)->NdisInterrupt, \
+ SyncCardSetReceiveConfig, (PVOID)(Adapter))
+
+
+//++
+//
+// VOID
+// CardBlockInterrupts(
+// IN PELNKII_ADAPTER Adapter
+// )
+//
+// Routine Description:
+//
+// Blocks all interrupts from the card by clearing the
+// interrupt mask (IMR) register. Only called from
+// IRQL INTERRUPT_LEVEL.
+//
+// Arguments:
+//
+// Adapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardBlockInterrupts(Adapter) \
+ NdisWritePortUchar((Adapter)->NdisAdapterHandle, (Adapter)->IoPAddr+NIC_INTR_MASK, 0)
+
+
+//++
+//
+// VOID
+// CardUnblockInterrupts(
+// IN PELNKII_ADAPTER Adapter
+// )
+//
+// Routine Description:
+//
+// Unblocks all interrupts from the card by setting the
+// interrupt mask (IMR) register. Only called from IRQL
+// INTERRUPT_LEVEL.
+//
+// Arguments:
+//
+// Adapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardUnblockInterrupts(Adapter) \
+ NdisWritePortUchar((Adapter)->NdisAdapterHandle, \
+ (Adapter)->IoPAddr+NIC_INTR_MASK, \
+ (Adapter)->NicInterruptMask)
+
+
+//++
+//
+// VOID
+// CardDisableReceiveInterrupt(
+// IN PELNKII_ADAPTER Adapter
+// )
+//
+// Routine Description:
+//
+// Turns off the receive bit in Adapter->NicInterruptMask.
+// This function is only called when CardBlockInterrupts have
+// been called; it ensures that receive interrupts are not
+// reenabled until CardEnableReceiveInterrupt is called, even
+// if CardUnblockInterrupts is called.
+//
+// Arguments:
+//
+// Adapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardDisableReceiveInterrupt(Adapter) \
+ (Adapter)->NicInterruptMask &= (UCHAR)~IMR_RCV
+
+
+//++
+//
+// VOID
+// CardEnableReceiveInterrupt(
+// IN PELNKII_ADAPTER Adapter
+// )
+//
+// Routine Description:
+//
+// Reenables receive interrupts by setting the receive bit ibn
+// Adapter->NicInterruptMask, and also writes the new value to
+// the card. Calls SyncCardSetInterruptMask.
+//
+// Arguments:
+//
+// Adapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardEnableReceiveInterrupt(Adapter) \
+ (Adapter)->NicInterruptMask |= (UCHAR)IMR_RCV, \
+ NdisSynchronizeWithInterrupt(&(Adapter)->NdisInterrupt, \
+ SyncCardSetInterruptMask, (PVOID)(Adapter))
+
+
+//++
+//
+// VOID
+// CardAcknowledgeReceiveInterrupt(
+// IN PELNKII_ADAPTER Adapter
+// )
+//
+// Routine Description:
+//
+// Acknowledges a receive interrupt by setting the bit in
+// the interrupt status (ISR) register. Calls
+// SyncCardAcknowledgeReceive.
+//
+// Arguments:
+//
+// Adapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardAcknowledgeReceiveInterrupt(Adapter) \
+ NdisSynchronizeWithInterrupt(&(Adapter)->NdisInterrupt, \
+ SyncCardAcknowledgeReceive, (PVOID)(Adapter))
+
+
+//++
+//
+// VOID
+// CardAcknowledgeOverflowInterrupt(
+// IN PELNKII_ADAPTER Adapter
+// )
+//
+// Routine Description:
+//
+// Acknowledges an overflow interrupt by setting the bit in
+// the interrupt status (ISR) register. Calls
+// SyncCardAcknowledgeOverflow.
+//
+// Arguments:
+//
+// Adapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardAcknowledgeOverflowInterrupt(Adapter) \
+ NdisSynchronizeWithInterrupt(&(Adapter)->NdisInterrupt, \
+ SyncCardAcknowledgeOverflow, (PVOID)(Adapter))
+
+
+//++
+//
+// VOID
+// CardAcknowledgeTransmitInterrupt(
+// IN PELNKII_ADAPTER Adapter
+// )
+//
+// Routine Description:
+//
+// Acknowledges a transmit interrupt by setting the bit in
+// the interrupt status (ISR) register. Calls
+// SyncCardAcknowledgeTransmit.
+//
+// Arguments:
+//
+// Adapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardAcknowledgeTransmitInterrupt(Adapter) \
+ NdisSynchronizeWithInterrupt(&(Adapter)->NdisInterrupt, \
+ SyncCardAcknowledgeTransmit, (PVOID)(Adapter))
+
+
+//++
+//
+// VOID
+// CardAcknowledgeCounterInterrupt(
+// IN PELNKII_ADAPTER Adapter
+// )
+//
+// Routine Description:
+//
+// Acknowledges a counter interrupt by setting the bit in
+// the interrupt status (ISR) register.
+//
+// Arguments:
+//
+// Adapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardAcknowledgeCounterInterrupt(Adapter) \
+ NdisWritePortUchar((Adapter)->NdisAdapterHandle, (Adapter)->IoPAddr+NIC_INTR_STATUS, ISR_COUNTER)
+
+
+//++
+//
+// VOID
+// CardAckAndGetCurrent(
+// IN PELNKII_ADAPTER Adapter
+// )
+//
+// Routine Description:
+//
+// Performs the function of CardAcknowledgeReceive followed by
+// CardGetCurrent (since the two are always called
+// one after the other). Calls SyncCardAckAndGetCurrent.
+//
+// Arguments:
+//
+// Adapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardAckAndGetCurrent(Adapter) \
+ NdisSynchronizeWithInterrupt(&(Adapter)->NdisInterrupt, \
+ SyncCardAckAndGetCurrent, (PVOID)(Adapter))
+
+
+//++
+//
+// VOID
+// CardGetXmitStatusAndAck(
+// IN PELNKII_ADAPTER Adapter
+// )
+//
+// Routine Description:
+//
+// Performs the function of CardGetXmitStatus followed by
+// CardAcknowledgeTransmit (since the two are always called
+// one after the other). Calls SyncCardGetXmitStatusAndAck.
+//
+// Arguments:
+//
+// Adapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardGetXmitStatusAndAck(Adapter) \
+ NdisSynchronizeWithInterrupt(&(Adapter)->NdisInterrupt, \
+ SyncCardGetXmitStatusAndAck, (PVOID)(Adapter))
+
+
+//++
+//
+// VOID
+// CardUpdateCounters(
+// IN PELNKII_ADAPTER Adapter
+// )
+//
+// Routine Description:
+//
+// Updates the values of the three counters (frame alignment
+// errors, CRC errors, and missed packets) by reading in their
+// current values from the card and adding them to the ones
+// stored in the Adapter structure. Calls SyncCardUpdateCounters.
+//
+// Arguments:
+//
+// Adapter - The adapter block.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define CardUpdateCounters(Adapter) \
+ NdisSynchronizeWithInterrupt(&(Adapter)->NdisInterrupt, \
+ SyncCardUpdateCounters, (PVOID)(Adapter))
+
+
+#endif // _ELNKIIHARDWARE_
diff --git a/private/ntos/ndis/wd/wdlan.rc b/private/ntos/ndis/wd/wdlan.rc
new file mode 100644
index 000000000..d4f7d4aa0
--- /dev/null
+++ b/private/ntos/ndis/wd/wdlan.rc
@@ -0,0 +1,39 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "SMC/WD Ethernet network driver"
+#define VER_INTERNALNAME_STR "SMCISA.SYS"
+#define VER_ORIGINALFILENAME_STR "SMCISA.SYS"
+
+#include "common.ver"
+
diff --git a/private/ntos/ndis/wd/wdlmi.h b/private/ntos/ndis/wd/wdlmi.h
new file mode 100644
index 000000000..614cf0056
--- /dev/null
+++ b/private/ntos/ndis/wd/wdlmi.h
@@ -0,0 +1,865 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ wdlmi.h
+
+Abstract:
+
+ Lower MAC Interface functions for the NDIS 3.0 Western Digital driver.
+
+Author:
+
+ Sean Selitrennikoff (seanse) 15-Jan-92
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+
+--*/
+
+#if DBG
+
+#define LOG(A) LOG(A)
+
+#else
+
+#define LOG(A)
+
+#endif
+
+
+#define WD_ETHERNET 0x01
+
+
+//
+// A transmit buffer (usually 0 or 1).
+//
+
+typedef SHORT XMIT_BUF;
+
+
+
+//
+// Maximum number of transmit buffers on the card.
+//
+
+#define MAX_XMIT_BUFS 2
+
+
+
+
+//
+// The status of transmit buffers.
+//
+
+typedef enum { EMPTY, FILLING, FULL } BUFFER_STATUS;
+
+//
+// Result of WdIndicate[Loopback]Packet().
+//
+
+typedef enum { INDICATE_OK, SKIPPED, ABORT, CARD_BAD } INDICATE_STATUS;
+
+
+//
+// Stages in a reset.
+//
+
+typedef enum { NONE, MULTICAST_RESET, XMIT_STOPPED, BUFFERS_EMPTY } RESET_STAGE;
+
+
+
+
+typedef struct _CNFG_Adapter {
+ ULONG cnfg_bid; /* Board ID from GetBoardID */
+ ULONG cnfg_ram_base; /* 32-Bit Phys Address of Shared RAM */
+ ULONG cnfg_rom_base; /* 32-Bit Phys Address of Adapter ROM */
+ USHORT cnfg_bus; /* 0=AT...1=MCA */
+ USHORT cnfg_base_io; /* Adapter Base I/O Address */
+ USHORT cnfg_slot; /* Micro Channel Slot Number */
+ USHORT cnfg_ram_size; /* Shared RAM Size (# of 1KB blocks) */
+ USHORT cnfg_ram_usable; /* Amount of RAM that can be accessed at once */
+ USHORT cnfg_irq_line; /* Adapter IRQ Interrupt Line */
+ USHORT cnfg_rom_size; /* Adapter ROM Size (# of 1KB blocks) */
+ USHORT cnfg_mode_bits1; /* Mode bits for adapter (see below) */
+ USHORT cnfg_pos_id;
+ UCHAR cnfg_media_type; /* Media type */
+ UCHAR cnfg_bic_type; /* Board Interface Chip number */
+ UCHAR cnfg_nic_type; /* Network Interface Chip number */
+ NDIS_MCA_POS_DATA PosData;
+} CNFG_Adapter, *PCNFG_Adapter;
+
+
+
+typedef struct _ADAPTER_STRUC{
+
+ UCHAR bus_type; // 0 = ISA, 1 = MCA
+
+ UCHAR mc_slot_num; // MCA bus only
+
+ USHORT pos_id; // Adapter POS ID (Mca only)
+
+ USHORT io_base; // Adapter I/O Base
+
+ PUCHAR adapter_text_ptr; // See LM_Get_Config
+
+ USHORT irq_value; // IRQ line used by hardware
+
+ USHORT rom_size; // num of 1K blocks
+
+ ULONG rom_base; // physical address of ROM
+
+ PVOID rom_access; // Pointer into VM of rom_base
+
+ USHORT ram_size; // num of 1K blocks
+
+ ULONG ram_base; // physical address of RAM
+
+ PVOID ram_access; // Pointer into VM of ram_base
+
+ USHORT ram_usable; // num of 1K blocks that can be accessed at once
+
+ USHORT io_base_new; // new i/o base addr for LM_Put_Config
+
+ UCHAR node_address[6]; // network address
+
+ UCHAR permanent_node_address[6]; // network address burned into card.
+
+ UCHAR multi_address[6]; // multicase address
+
+ USHORT max_packet_size; // for this MAC driver
+
+ USHORT buffer_page_size; // size of adapters RAM TX/RX buffer pages.
+
+ USHORT num_of_tx_buffs; // TX bufss in adapter RAM
+
+ USHORT receive_lookahead_size;
+
+ USHORT receive_mask;
+
+ USHORT adapter_status;
+
+ USHORT media_type;
+
+ USHORT bic_type;
+
+ USHORT nic_type;
+
+ USHORT adapter_type;
+
+ NDIS_HANDLE NdisAdapterHandle;
+
+ NDIS_MCA_POS_DATA PosData;
+
+ //
+ // These counters must be initialized by the upper layer.
+ //
+
+
+ //
+ // Common counters...
+ //
+
+ PULONG ptr_rx_CRC_errors;
+
+ PULONG ptr_rx_lost_pkts;
+
+
+ //
+ // Ethernet specific counters. Must be initialized by upper layer.
+ //
+
+ PULONG ptr_rx_too_big;
+
+ PULONG ptr_rx_align_errors;
+
+ PULONG ptr_rx_overruns;
+
+ PULONG ptr_tx_deferred;
+
+ PULONG ptr_tx_max_collisions;
+
+ PULONG ptr_tx_one_collision;
+
+ PULONG ptr_tx_mult_collisions;
+
+ PULONG ptr_tx_ow_collision;
+
+ PULONG ptr_tx_CD_heartbeat;
+
+ PULONG ptr_tx_carrier_lost;
+
+ PULONG ptr_tx_underruns;
+
+
+
+
+ ULONG board_id;
+
+ USHORT mode_bits;
+
+ USHORT status_bits;
+
+ USHORT xmit_buf_size;
+
+ USHORT config_mode; // 1 == Store config in EEROM
+
+
+
+
+ UCHAR State;
+
+ BOOLEAN BufferOverflow; // does an overflow need to be handled
+
+ UCHAR InterruptMask;
+
+ BOOLEAN UMRequestedInterrupt; // Has LM_Interrupt() been called.
+
+
+
+ NDIS_INTERRUPT NdisInterrupt; // interrupt info used by wrapper
+
+ UCHAR Current;
+
+ //
+ // Transmit information.
+ //
+
+ XMIT_BUF NextBufToFill; // where to copy next packet to
+ XMIT_BUF NextBufToXmit; // valid if CurBufXmitting is -1
+ XMIT_BUF CurBufXmitting; // -1 if none is
+ BOOLEAN TransmitInterruptPending; // transmit interrupt and overwrite error?
+ UINT PacketLens[MAX_XMIT_BUFS];
+ BUFFER_STATUS BufferStatus[MAX_XMIT_BUFS];
+
+ PUCHAR ReceiveStart; // start of card receive area
+ PUCHAR ReceiveStop; // end of card receive area
+
+
+ //
+ // Loopback information
+ //
+
+ PNDIS_PACKET LoopbackQueue; // queue of packets to loop back
+ PNDIS_PACKET LoopbackQTail;
+ PNDIS_PACKET LoopbackPacket; // current one we are looping back
+
+ //
+ // Receive information
+ //
+
+ PUCHAR IndicatingPacket;
+ BOOLEAN OverWriteHandling; // Currently handling an overwrite
+ BOOLEAN OverWriteStartTransmit;
+ UCHAR StartBuffer; // Start buffer number to receive into
+ UCHAR LastBuffer; // Last buffer number + 1
+ UINT PacketLen;
+
+ //
+ // Interrupt Information
+ //
+
+ UCHAR LaarHold;
+
+ //
+ // Pointer to the filter database for the MAC.
+ //
+ PETH_FILTER FilterDB;
+
+}Adapter_Struc, *Ptr_Adapter_Struc;
+
+
+
+
+//
+// LMI Status and Return codes
+//
+
+typedef USHORT LM_STATUS;
+
+#define SUCCESS 0x0
+#define ADAPTER_AND_CONFIG 0x1 // Adapter found and config info gotten
+#define ADAPTER_NO_CONFIG 0x2 // Adapter found, no config info found
+#define NOT_MY_INTERRUPT 0x3 // No interrupt found in LM_Service_Events
+#define FRAME_REJECTED 0x4
+#define EVENTS_DISABLED 0x5 // Disables LM_Service_Events from reporting
+ // any further interrupts.
+#define OUT_OF_RESOURCES 0x6
+#define OPEN_FAILED 0x7
+#define HARDWARE_FAILED 0x8
+#define INITIALIZE_FAILED 0x9
+#define CLOSE_FAILED 0xA
+#define MAX_COLLISIONS 0xB
+#define FIFO_UNDERRUN 0xC
+#define BUFFER_TOO_SMALL 0xD
+#define ADAPTER_CLOSED 0xE
+#define FAILURE 0xF
+
+#define REQUEUE_LATER 0x12
+
+
+#define INVALID_FUNCTION 0x80
+#define INVALID_PARAMETER 0x81
+
+#define ADAPTER_NOT_FOUND 0xFFFF
+
+
+//
+// Valid states for the adapter
+//
+
+#define OPEN 0x1
+#define INITIALIZED 0x2
+#define CLOSED 0x3
+#define REMOVED 0x4
+
+
+//
+// Error code places
+//
+
+#define getBoardId 0x01
+#define cardGetConfig 0x02
+
+
+
+//
+// Media type masks (for LMAdapter.media_type)
+//
+
+
+#define MEDIA_S10 0x00 // Ethernet, TP
+#define MEDIA_AUI_UTP 0x01 // Ethernet, AUI
+#define MEDIA_BNC 0x02 // Ethernet, BNC
+#define MEDIA_UNKNOWN 0xFFFF
+
+
+
+//
+// BIC codes (for the bic_type field)
+//
+
+#define BIC_NO_CHIP 0x00
+#define BIC_583_CHIP 0x01
+#define BIC_584_CHIP 0x02
+#define BIC_585_CHIP 0x03
+#define BIC_593_CHIP 0x04
+#define BIC_594_CHIP 0x05
+#define BIC_790_CHIP 0x07
+
+
+//
+// NIC codes (for the nic_type field)
+//
+
+#define NIC_UNKNOWN_CHIP 0x00
+#define NIC_8390_CHIP 0x01
+#define NIC_690_CHIP 0x02
+#define NIC_825_CHIP 0x03
+#define NIC_790_CHIP 0x07
+
+//
+// Adapter type codes (for the adapter_type field)
+//
+
+#define BUS_UNKNOWN_TYPE 0x00
+#define BUS_ISA16_TYPE 0x01
+#define BUS_ISA8_TYPE 0x02
+#define BUS_MCA_TYPE 0x03
+#define BUS_EISA32M_TYPE 0x04
+#define BUS_EIST32S_TYPE 0x05
+
+
+
+
+//
+// UM_RingStatus_Change codes
+//
+
+
+#define SIGNAL_LOSS 0x14
+#define HARD_ERROR 0x15
+#define SOFT_ERROR 0x16
+#define TRANSMIT_BEACON 0x17
+#define LOBE_WIRE_FAULT 0x18
+#define AUTO_REMOVAL_ERROR_1 0x19
+#define REMOVE_RECEIVED 0x1A
+#define COUNTER_OVERFLOW 0x1B
+#define SINGLE_STATION 0x1C
+#define RING_RECOVERY 0x1D
+
+
+
+
+//++
+//
+// XMIT_BUF
+// NextBuf(
+// IN PWD_ADAPTER AdaptP,
+// IN XMIT_BUF XmitBuf
+// )
+//
+// Routine Description:
+//
+// NextBuf "increments" a transmit buffer number. The next
+// buffer is returned; the number goes back to 0 when it
+// reaches AdaptP->NumBuffers.
+//
+// Arguments:
+//
+// AdaptP - The adapter block.
+// XmitBuf - The current transmit buffer number.
+//
+// Return Value:
+//
+// The next transmit buffer number.
+//
+//--
+
+#define NextBuf(AdaptP, XmitBuf) \
+ ((XMIT_BUF)(((XmitBuf)+1)%(AdaptP)->NumBuffers))
+
+
+
+
+
+
+//
+// Function Definitions.
+//
+
+
+extern
+LM_STATUS
+LM_Send(
+ PNDIS_PACKET Packet,
+ Ptr_Adapter_Struc Adapter
+ );
+
+
+
+extern
+LM_STATUS
+LM_Interrupt_req(
+ Ptr_Adapter_Struc Adapter
+ );
+
+
+extern
+LM_STATUS
+LM_Service_Receive_Events(
+ Ptr_Adapter_Struc Adapter
+ );
+
+extern
+LM_STATUS
+LM_Service_Transmit_Events(
+ Ptr_Adapter_Struc Adapter
+ );
+
+
+extern
+LM_STATUS
+LM_Receive_Copy(
+ PULONG Bytes_Transferred,
+ ULONG Byte_Count,
+ ULONG Offset,
+ PNDIS_PACKET Packet,
+ Ptr_Adapter_Struc Adapter
+ );
+
+
+extern
+LM_STATUS
+LM_Receive_Lookahead(
+ ULONG Byte_Count,
+ ULONG Offset,
+ PUCHAR Buffer,
+ Ptr_Adapter_Struc Adapter
+ );
+
+extern
+LM_STATUS
+LM_Get_Mca_Io_Base_Address(
+ IN Ptr_Adapter_Struc Adapt,
+ IN NDIS_HANDLE ConfigurationHandle,
+ OUT USHORT *IoBaseAddress
+ );
+
+extern
+LM_STATUS
+LM_Get_Config(
+ Ptr_Adapter_Struc Adapter
+ );
+
+extern
+LM_STATUS
+LM_Free_Resources(
+ Ptr_Adapter_Struc Adapt
+ );
+
+extern
+LM_STATUS
+LM_Initialize_Adapter(
+ Ptr_Adapter_Struc Adapter
+ );
+
+
+extern
+LM_STATUS
+LM_Open_Adapter(
+ Ptr_Adapter_Struc Adapter
+ );
+
+
+extern
+LM_STATUS
+LM_Close_Adapter(
+ Ptr_Adapter_Struc Adapter
+ );
+
+
+extern
+LM_STATUS
+LM_Disable_Adapter(
+ Ptr_Adapter_Struc Adapter
+ );
+
+extern
+LM_STATUS
+LM_Disable_Adapter_Receives(
+ Ptr_Adapter_Struc Adapt
+ );
+
+extern
+LM_STATUS
+LM_Disable_Adapter_Transmits(
+ Ptr_Adapter_Struc Adapt
+ );
+
+extern
+LM_STATUS
+LM_Enable_Adapter(
+ Ptr_Adapter_Struc Adapter
+ );
+
+
+extern
+LM_STATUS
+LM_Enable_Adapter_Receives(
+ Ptr_Adapter_Struc Adapt
+ );
+
+extern
+LM_STATUS
+LM_Enable_Adapter_Transmits(
+ Ptr_Adapter_Struc Adapt
+ );
+
+#define LM_Set_Multi_Address(Addresses, Count, Adapter) (SUCCESS)
+
+
+extern
+LM_STATUS
+LM_Set_Receive_Mask(
+ Ptr_Adapter_Struc Adapter
+ );
+
+
+
+
+//
+//
+// Below here is LM Specific codes and structures..
+//
+//
+
+
+
+
+/******************************************************************************
+ Definitions for the field:
+ cnfg_mode_bits1
+******************************************************************************/
+
+
+#define INTERRUPT_STATUS_BIT 0x8000 /* PC Interrupt Line: 0 = Not Enabled */
+#define BOOT_STATUS_MASK 0x6000 /* Mask to isolate BOOT_STATUS */
+#define BOOT_INHIBIT 0x0000 /* BOOT_STATUS is 'inhibited' */
+#define BOOT_TYPE_1 0x2000 /* Unused BOOT_STATUS value */
+#define BOOT_TYPE_2 0x4000 /* Unused BOOT_STATUS value */
+#define BOOT_TYPE_3 0x6000 /* Unused BOOT_STATUS value */
+#define ZERO_WAIT_STATE_MASK 0x1800 /* Mask to isolate Wait State flags */
+#define ZERO_WAIT_STATE_8_BIT 0x1000 /* 0 = Disabled (Inserts Wait States) */
+#define ZERO_WAIT_STATE_16_BIT 0x0800 /* 0 = Disabled (Inserts Wait States) */
+#define BNC_INTERFACE 0x0400
+#define AUI_10BT_INTERFACE 0x0200
+#define STARLAN_10_INTERFACE 0x0100
+#define INTERFACE_TYPE_MASK 0x0700
+#define MANUAL_CRC 0x0010
+
+
+
+
+
+
+#define CNFG_ID_8003E 0x6FC0
+#define CNFG_ID_8003S 0x6FC1
+#define CNFG_ID_8003W 0x6FC2
+#define CNFG_ID_8013E 0x61C8
+#define CNFG_ID_8013W 0x61C9
+#define CNFG_ID_8115TRA 0x6FC6
+#define CNFG_ID_BISTRO03E 0xEFE5
+#define CNFG_ID_BISTRO13E 0xEFD5
+#define CNFG_ID_BISTRO13W 0xEFD4
+
+#define CNFG_MSR_583 MEMORY_SELECT_REG
+#define CNFG_ICR_583 INTERFACE_CONFIG_REG
+#define CNFG_IAR_583 IO_ADDRESS_REG
+#define CNFG_BIO_583 BIOS_ROM_ADDRESS_REG
+#define CNFG_IRR_583 INTERRUPT_REQUEST_REG
+#define CNFG_LAAR_584 LA_ADDRESS_REG
+#define CNFG_GP2 GENERAL_PURPOSE_REG2
+#define CNFG_LAAR_MASK LAAR_MASK
+#define CNFG_LAAR_ZWS LAAR_ZERO_WAIT_STATE
+#define CNFG_ICR_IR2_584 IR2
+#define CNFG_IRR_IRQS (INTERRUPT_REQUEST_BIT1 | INTERRUPT_REQUEST_BIT0)
+#define CNFG_IRR_IEN INTERRUPT_ENABLE
+#define CNFG_IRR_ZWS ZERO_WAIT_STATE_ENABLE
+#define CNFG_GP2_BOOT_NIBBLE 0xF
+
+#define CNFG_SIZE_8KB 8
+#define CNFG_SIZE_16KB 16
+#define CNFG_SIZE_32KB 32
+#define CNFG_SIZE_64KB 64
+
+#define ROM_DISABLE 0x0
+
+#define CNFG_SLOT_ENABLE_BIT 0x8
+
+#define CNFG_MEDIA_TYPE_MASK 0x07
+
+#define CNFG_INTERFACE_TYPE_MASK 0x700
+#define CNFG_POS_CONTROL_REG 0x96
+#define CNFG_POS_REG0 0x100
+#define CNFG_POS_REG1 0x101
+#define CNFG_POS_REG2 0x102
+#define CNFG_POS_REG3 0x103
+#define CNFG_POS_REG4 0x104
+#define CNFG_POS_REG5 0x105
+
+
+
+
+
+
+
+
+//
+//
+// General Register types
+//
+//
+
+#define WD_REG_0 0x00
+#define WD_REG_1 0x01
+#define WD_REG_2 0x02
+#define WD_REG_3 0x03
+#define WD_REG_4 0x04
+#define WD_REG_5 0x05
+#define WD_REG_6 0x06
+#define WD_REG_7 0x07
+
+#define WD_LAN_OFFSET 0x08
+
+#define WD_LAN_0 0x08
+#define WD_LAN_1 0x09
+#define WD_LAN_2 0x0A
+#define WD_LAN_3 0x0B
+#define WD_LAN_4 0x0C
+#define WD_LAN_5 0x0D
+
+#define WD_ID_BYTE 0x0E
+
+#define WD_CHKSUM 0x0F
+
+#define WD_MSB_583_BIT 0x08
+
+#define WD_SIXTEEN_BIT 0x01
+
+#define WD_BOARD_REV_MASK 0x1E
+
+//
+// Definitions for board Rev numbers greater than 1
+//
+
+#define WD_MEDIA_TYPE_BIT 0x01
+#define WD_SOFT_CONFIG_BIT 0x20
+#define WD_RAM_SIZE_BIT 0x40
+#define WD_BUS_TYPE_BIT 0x80
+
+
+//
+// Definitions for the 690 board
+//
+
+#define WD_690_CR 0x10 // command register
+
+#define WD_690_TXP 0x04 // transmit packet command
+#define WD_690_TCR 0x0D // transmit configuration register
+#define WD_690_TCR_TEST_VAL 0x18 // Value to test 8390 or 690
+
+#define WD_690_PS0 0x00 // Page Select 0
+#define WD_690_PS1 0x40 // Page Select 1
+#define WD_690_PS2 0x80 // Page Select 2
+#define WD_690_PSMASK 0x3F // For masking off the page select bits
+
+
+//
+// Definitions for the 584 board
+//
+
+#define WD_584_EEPROM_0 0x08
+#define WD_584_EEPROM_1 0x09
+#define WD_584_EEPROM_2 0x0A
+#define WD_584_EEPROM_3 0x0B
+#define WD_584_EEPROM_4 0x0C
+#define WD_584_EEPROM_5 0x0D
+#define WD_584_EEPROM_6 0x0E
+#define WD_584_EEPROM_7 0x0F
+
+#define WD_584_OTHER_BIT 0x02
+#define WD_584_ICR_MASK 0x0C
+#define WD_584_EAR_MASK 0x0F
+#define WD_584_ENGR_PAGE 0xA0
+#define WD_584_RLA 0x10
+#define WD_584_EA6 0x80
+#define WD_584_RECALL_DONE 0x10
+
+#define WD_584_ID_EEPROM_OVERRIDE 0x0000FFB0
+#define WD_584_EXTRA_EEPROM_OVERRIDE 0xFFD00000
+
+#define WD_584_EEPROM_MEDIA_MASK 0x07
+#define WD_584_STARLAN_TYPE 0x00
+#define WD_584_ETHERNET_TYPE 0x01
+#define WD_584_TP_TYPE 0x02
+#define WD_584_EW_TYPE 0x03
+
+#define WD_584_EEPROM_IRQ_MASK 0x18
+#define WD_584_PRIMARY_IRQ 0x00
+#define WD_584_ALT_IRQ_1 0x08
+#define WD_584_ALT_IRQ_2 0x10
+#define WD_584_ALT_IRQ_3 0x18
+
+#define WD_584_EEPROM_PAGING_MASK 0xC0
+#define WD_584_EEPROM_RAM_PAGING 0x40
+#define WD_584_EEPROM_ROM_PAGING 0x80
+
+#define WD_584_EEPROM_RAM_SIZE_MASK 0xE0
+#define WD_584_EEPROM_RAM_SIZE_RES1 0x00
+#define WD_584_EEPROM_RAM_SIZE_RES2 0x20
+#define WD_584_EEPROM_RAM_SIZE_8K 0x40
+#define WD_584_EEPROM_RAM_SIZE_16K 0x60
+#define WD_584_EEPROM_RAM_SIZE_32K 0x80
+#define WD_584_EEPROM_RAM_SIZE_64K 0xA0
+#define WD_584_EEPROM_RAM_SIZE_RES3 0xC0
+#define WD_584_EEPROM_RAM_SIZE_RES4 0xE0
+
+#define WD_584_EEPROM_BUS_TYPE_MASK 0x07
+#define WD_584_EEPROM_BUS_TYPE_AT 0x00
+#define WD_584_EEPROM_BUS_TYPE_MCA 0x01
+#define WD_584_EEPROM_BUS_TYPE_EISA 0x02
+
+#define WD_584_EEPROM_BUS_SIZE_MASK 0x18
+#define WD_584_EEPROM_BUS_SIZE_8BIT 0x00
+#define WD_584_EEPROM_BUS_SIZE_16BIT 0x08
+#define WD_584_EEPROM_BUS_SIZE_32BIT 0x10
+#define WD_584_EEPROM_BUS_SIZE_64BIT 0x18
+
+//
+// For the 594 Chip
+//
+
+
+
+//
+// BOARD ID MASK DEFINITIONS
+//
+// 32 Bits of information are returned by 'GetBoardID ()'.
+//
+// The low order 16 bits correspond to the Feature Bits which make
+// up a unique ID for a given class of boards.
+//
+// e.g. STARLAN MEDIA, INTERFACE_CHIP, MICROCHANNEL
+//
+// note: board ID should be ANDed with the STATIC_ID_MASK
+// before comparing to a specific board ID
+//
+//
+// The high order 16 bits correspond to the Extra Bits which do not
+// change the boards ID.
+//
+// e.g. INTERFACE_584_CHIP, 16 BIT SLOT, ALTERNATE IRQ
+//
+
+
+#define STARLAN_MEDIA 0x00000001 /* StarLAN */
+#define ETHERNET_MEDIA 0x00000002 /* Ethernet */
+#define TWISTED_PAIR_MEDIA 0x00000003 /* Twisted Pair */
+#define EW_MEDIA 0x00000004 /* Ethernet and Twisted Pair */
+#define TOKEN_MEDIA 0x00000005 /* Token Ring */
+
+#define MICROCHANNEL 0x00000008 /* MicroChannel Adapter */
+#define INTERFACE_CHIP 0x00000010 /* Soft Config Adapter */
+#define ADVANCED_FEATURES 0x00000020 /* Advance netw interface features */
+#define BOARD_16BIT 0x00000040 /* 16 bit capability */
+#define PAGED_RAM 0x00000080 /* Is there RAM paging? */
+#define PAGED_ROM 0x00000100 /* Is there ROM paging? */
+#define RAM_SIZE_UNKNOWN 0x00000000 /* 000 => Unknown RAM Size */
+#define RAM_SIZE_RESERVED_1 0x00010000 /* 001 => Reserved */
+#define RAM_SIZE_8K 0x00020000 /* 010 => 8k RAM */
+#define RAM_SIZE_16K 0x00030000 /* 011 => 16k RAM */
+#define RAM_SIZE_32K 0x00040000 /* 100 => 32k RAM */
+#define RAM_SIZE_64K 0x00050000 /* 101 => 64k RAM */
+#define RAM_SIZE_RESERVED_6 0x00060000 /* 110 => Reserved */
+#define RAM_SIZE_RESERVED_7 0x00070000 /* 111 => Reserved */
+#define SLOT_16BIT 0x00080000 /* 16 bit board - 16 bit slot */
+#define NIC_690_BIT 0x00100000 /* NIC is 690 */
+#define ALTERNATE_IRQ_BIT 0x00200000 /* Alternate IRQ is used */
+#define INTERFACE_5X3_CHIP 0x00000000 /* 0000 = 583 or 593 chips */
+#define INTERFACE_584_CHIP 0x00400000 /* 0100 = 584 chip */
+#define INTERFACE_594_CHIP 0x00800000 /* 1000 = 594 chip */
+
+#define MEDIA_MASK 0x00000007 /* Isolates Media Type */
+#define RAM_SIZE_MASK 0x00070000 /* Isolates RAM Size */
+#define STATIC_ID_MASK 0x0000FFFF /* Isolates Board ID */
+#define INTERFACE_CHIP_MASK 0x03C00000 /* Isolates Intfc Chip Type */
+
+/* Word definitions for board types */
+
+#define WD8003E ETHERNET_MEDIA
+#define WD8003EBT WD8003E /* functionally identical to WD8003E */
+#define WD8003S STARLAN_MEDIA
+#define WD8003SH WD8003S /* functionally identical to WD8003S */
+#define WD8003WT TWISTED_PAIR_MEDIA
+#define WD8003W (TWISTED_PAIR_MEDIA | INTERFACE_CHIP)
+#define WD8003EB (ETHERNET_MEDIA | INTERFACE_CHIP)
+#define WD8003EP WD8003EB /* with INTERFACE_584_CHIP */
+#define WD8003EW (EW_MEDIA | INTERFACE_CHIP)
+#define WD8003ETA (ETHERNET_MEDIA | MICROCHANNEL)
+#define WD8003STA (STARLAN_MEDIA | MICROCHANNEL)
+#define WD8003EA (ETHERNET_MEDIA | MICROCHANNEL | INTERFACE_CHIP)
+#define WD8003EPA WD8003EA /* with INTERFACE_594_CHIP */
+#define WD8003SHA (STARLAN_MEDIA | MICROCHANNEL | INTERFACE_CHIP)
+#define WD8003WA (TWISTED_PAIR_MEDIA | MICROCHANNEL | INTERFACE_CHIP)
+#define WD8003WPA WD8003WA /* with INTERFACE_594_CHIP */
+#define WD8013EBT (ETHERNET_MEDIA | BOARD_16BIT)
+#define WD8013EB (ETHERNET_MEDIA | BOARD_16BIT | INTERFACE_CHIP)
+#define WD8013W (TWISTED_PAIR_MEDIA | BOARD_16BIT | INTERFACE_CHIP)
+#define WD8013EW (EW_MEDIA | BOARD_16BIT | INTERFACE_CHIP)
diff --git a/private/ntos/ndis/wd/wdlmireg.h b/private/ntos/ndis/wd/wdlmireg.h
new file mode 100644
index 000000000..f20b345fb
--- /dev/null
+++ b/private/ntos/ndis/wd/wdlmireg.h
@@ -0,0 +1,424 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ wdlmireg.h
+
+Abstract:
+
+ Register definitions and values for the many cards
+
+Author:
+
+ Sean Selitrennikoff (seanse) 15-Jan-92
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+
+--*/
+
+
+
+
+//
+// Microchannel Bus registers
+//
+
+#define CHANNEL_SELECT_REG 0x96
+#define LSB_ID_POS_REG 0x100
+#define MSB_ID_POS_REG 0x101
+#define IO_BASE_POS_REG 0x102
+#define RAM_BASE_POS_REG 0x103
+#define BIOS_ROM_POS_REG 0x104
+#define IRQ_POS_REG 0x105
+
+
+
+//
+// Microchannel 83c593 Registers.
+//
+
+#define MEMORY_ENABLE_RESET_REG 0x00
+#define EEPROM_CONTROL_REG 0x01
+#define BOARD_ID_REG0 0x02
+#define BOARD_ID_REG1 0x03
+#define INTERRUPT_CONTROL_AND_STATUS_REG 0x04
+#define COMMUNICATION_CONTROL_REG 0x05
+#define FIFO_ENTRY_EXIT_REG 0x06
+#define GENERAL_PURPOSE_REG 0x07
+
+
+//
+// Microchannel 83c594 Registers
+
+#define REVISION_REG 0x07
+
+
+
+
+
+
+
+//
+// AT Bus Registers
+//
+
+//
+// 83c583 registers
+//
+
+#define BASE_REG 0x00
+#define MEMORY_SELECT_REG 0x00 // MSR
+#define INTERFACE_CONFIG_REG 0x01 // ICR
+#define BUS_SIZE_REG 0x01 // BSR (read only)
+#define IO_ADDRESS_REG 0x02 // IAR
+#define BIOS_ROM_ADDRESS_REG 0x03 // BIO (583, 584)
+#define EEPROM_ADDRESS_REG 0x03 // EAR (584)
+#define INTERRUPT_REQUEST_REG 0x04 // IRR
+#define GENERAL_PURPOSE_REG1 0x05 // GP1
+#define LA_ADDRESS_REG 0x05 // LAAR (write only)
+#define IO_DATA_LATCH_REG 0x06 // IOD (583)
+#define INITIALIZE_JUMPER_REG 0x06 // IJR (584)
+#define GENERAL_PURPOSE_REG2 0x07 // GP2
+#define LAN_ADDRESS_REG 0x08 // LAR
+#define LAN_ADDRESS_REG2 0x09 // LAR2
+#define LAN_ADDRESS_REG3 0x0A // LAR3
+#define LAN_ADDRESS_REG4 0x0B // LAR4
+#define LAN_ADDRESS_REG5 0x0C // LAR5
+#define LAN_ADDRESS_REG6 0x0D // LAR6
+#define LAN_ADDRESS_REG7 0x0E // LAR7
+#define LAN_ADDRESS_REG8 0x0F // LAR8
+
+
+//
+// 8390 Registers
+//
+
+#define OFF_8390_REG 0x10 // offset of the 8390 chip
+
+// page 0, reading
+
+#define COMMAND_REG OFF_8390_REG + 0x00
+#define DMA_ADDRESS_0_REG OFF_8390_REG + 0x01
+#define DMA_ADDRESS_1_REG OFF_8390_REG + 0x02
+#define BOUNDARY_REG OFF_8390_REG + 0x03
+#define TRANSMIT_STATUS_REG OFF_8390_REG + 0x04
+#define NUM_COLLISIONS_REG OFF_8390_REG + 0x05
+#define FIFO_REG OFF_8390_REG + 0x06
+#define INTERRUPT_STATUS_REG OFF_8390_REG + 0x07
+#define REMOTE_DMA_ADDRESS_0_REG OFF_8390_REG + 0x08
+#define REMOTE_DMA_ADDRESS_1_REG OFF_8390_REG + 0x09
+#define RECEIVE_STATUS_REG OFF_8390_REG + 0x0C
+#define ALIGNMENT_ERROR_REG OFF_8390_REG + 0x0D
+#define CRC_ERROR_REG OFF_8390_REG + 0x0E
+#define MISSED_PACKET_REG OFF_8390_REG + 0x0F
+
+// page 0, writing
+
+#define COMMAND_REG OFF_8390_REG + 0x00
+#define PAGE_START_REG OFF_8390_REG + 0x01
+#define PAGE_STOP_REG OFF_8390_REG + 0x02
+#define TRANSMIT_PAGE_START_REG OFF_8390_REG + 0x04
+#define TRANSMIT_BYTE_COUNT_REG0 OFF_8390_REG + 0x05
+#define TRANSMIT_BYTE_COUNT_REG1 OFF_8390_REG + 0x06
+#define REMOTE_START_ADDRESS_REG0 OFF_8390_REG + 0x08
+#define REMOTE_START_ADDRESS_REG1 OFF_8390_REG + 0x09
+#define REMOTE_BYTE_COUNT_REG0 OFF_8390_REG + 0x0A
+#define REMOTE_BYTE_COUNT_REG1 OFF_8390_REG + 0x0B
+#define RECEIVE_CONFIG_REG OFF_8390_REG + 0x0C
+#define TRANSMIT_CONFIG_REG OFF_8390_REG + 0x0D
+#define DATA_CONFIG_REG OFF_8390_REG + 0x0E
+#define INTERRUPT_MASK_REG OFF_8390_REG + 0x0F
+
+
+// page 1, reading and writing
+
+#define CONTROL_REG OFF_8390_REG + 0x00
+#define PHYSICAL_ADDRESS_REG0 OFF_8390_REG + 0x01
+#define PHYSICAL_ADDRESS_REG1 OFF_8390_REG + 0x02
+#define PHYSICAL_ADDRESS_REG2 OFF_8390_REG + 0x03
+#define PHYSICAL_ADDRESS_REG3 OFF_8390_REG + 0x04
+#define PHYSICAL_ADDRESS_REG4 OFF_8390_REG + 0x05
+#define PHYSICAL_ADDRESS_REG5 OFF_8390_REG + 0x06
+#define CURRENT_BUFFER_REG OFF_8390_REG + 0x07
+#define MULTICAST_ADDRESS_REG0 OFF_8390_REG + 0x08
+#define MULTICAST_ADDRESS_REG1 OFF_8390_REG + 0x09
+#define MULTICAST_ADDRESS_REG2 OFF_8390_REG + 0x0A
+#define MULTICAST_ADDRESS_REG3 OFF_8390_REG + 0x0B
+#define MULTICAST_ADDRESS_REG4 OFF_8390_REG + 0x0C
+#define MULTICAST_ADDRESS_REG5 OFF_8390_REG + 0x0D
+#define MULTICAST_ADDRESS_REG6 OFF_8390_REG + 0x0E
+#define MULTICAST_ADDRESS_REG7 OFF_8390_REG + 0x0F
+
+// page 2, reading and writing
+
+#define BLOCK_ADDRESS_REG OFF_8390_REG + 0x06
+#define ENHANCEMENT_REG OFF_8390_REG + 0x07
+
+
+
+
+
+
+
+
+//
+// Register Bit Definitions
+//
+
+
+
+
+
+//
+// Microchannel Registers
+//
+
+
+
+#define NUMBER_OF_CHANNELS 8
+
+
+#define DISABLE_BIOS 0x02
+#define DISABLE_SETUP 0x00
+#define SELECT_CHANNEL_1 0x08
+#define ADAPTER_ID_MSB 0x6F
+#define ADAPTER_ID_LSB0 0xC0
+#define ADAPTER_ID_LSB1 0xC1
+#define ADAPTER_ID_LSB2 0xC2
+#define ADAPTER_ID_LSB3 0xC3
+#define ADAPTER_ID_LSB4 0xC4
+#define ADAPTER_ID_LSB5 0xC5
+#define ADAPTER_ID_LSB6 0xC6
+
+//
+// BISTRO ID BYTES
+//
+
+#define BISTRO_ID_MSB 0xEF
+#define BISTRO_ID_LSB 0xE5
+#define ALT_BISTRO_ID_LSB 0xD5
+
+
+//
+// COMMUNICATION_CONTROL_REG
+//
+
+#define CCR_INTERRUPT_ENABLE 0x04
+
+
+
+
+
+
+//
+// AT bus Registers
+//
+
+//
+// MSR
+//
+
+#define RESET 0x80 // 1 == reset
+#define MEMORY_ENABLE 0x40 // 1 == enabled
+#define ADDRESS_BIT18 0x20 // Top bits for shared memory address
+#define ADDRESS_BIT17 0x10 // Assume bit 19 == 1
+#define ADDRESS_BIT16 0x08
+#define ADDRESS_BIT15 0x04
+#define ADDRESS_BIT14 0x02
+#define ADDRESS_BIT13 0x01
+
+
+//
+// ICR
+//
+
+#define STORE 0x80 // Store into EEProm
+#define RECALL 0x40 // Recall from EEProm
+#define RECALL_ALL_BUT_IO 0x20 // Recall all but IO and LAN Address
+#define RECALL_LAN 0x10 // Recall LAN Address
+#define MEMORY_SIZE 0x08 // Shared Memory size
+#define DMA_ENABLE 0x04 // DMA Enable (583)
+#define IR2 0x04 // IRQ index MSB (584)
+#define IO_PORT_ENABLE 0x02 // (583)
+#define OTHER 0x02 // (584)
+#define WORD_TRANSFER_SELECT 0x01
+
+
+
+//
+// BIO
+//
+
+#define BIOS_SIZE_BIT1 0x80
+#define BIOS_SIZE_BIT0 0x40
+#define BIOS_ROM_ADDRESS_BIT18 0x20
+#define BIOS_ROM_ADDRESS_BIT17 0x10
+#define BIOS_ROM_ADDRESS_BIT16 0x08
+#define BIOS_ROM_ADDRESS_BIT15 0x04
+#define BIOS_ROM_ADDRESS_BIT14 0x02
+#define W8003_INTERRUPT 0x01
+
+
+//
+// IRR
+//
+
+#define INTERRUPT_ENABLE 0x80
+#define INTERRUPT_REQUEST_BIT1 0x40
+#define INTERRUPT_REQUEST_BIT0 0x20
+#define ALTERNATE_MODE 0x10
+#define ALTERNATE_INTERRUPT 0x08
+#define BIOS_WAIT_STATE_BIT1 0x04
+#define BIOS_WAIT_STATE_BIT0 0x02
+#define ZERO_WAIT_STATE_ENABLE 0x01
+
+
+//
+// BSR
+//
+
+#define BUS_16_BIT 0x01
+
+
+//
+// LAAR
+//
+
+#define MEMORY_16BIT_ENABLE 0x80
+#define LAN_16BIT_ENABLE 0x40
+#define LAAR_ZERO_WAIT_STATE 0x20
+#define LAN_ADDRESS_BIT23 0x10
+#define LAN_ADDRESS_BIT22 0x08
+#define LAN_ADDRESS_BIT21 0x04
+#define LAN_ADDRESS_BIT20 0x02
+#define LAN_ADDRESS_BIT19 0x01
+
+#define LAAR_MASK 0x1F
+#define INIT_LAAR_VALUE 0x01 // To set bit 19 to 1
+
+
+//
+// 8390 Register Bit definitions
+//
+
+//
+// COMMAND_REG
+//
+
+#define STOP 0x01 // software reset
+#define START 0x02
+#define TRANSMIT_PACKET 0x04
+#define READ_0 0x08
+#define READ_1 0x10
+#define READ_2 0x20
+
+#define REMOTE_READ 0x08 // Remote DMA Command
+#define REMOTE_WRITE 0x10 // Remote DMA Command
+#define REMOTE_SEND_PACKET 0x18 // Remote DMA Command
+#define REMOTE_ABORT_COMPLETE 0x20 // Remote DMA Command
+
+#define PAGE_SELECT_0 0x00
+#define PAGE_SELECT_1 0x40
+#define PAGE_SELECT_2 0x80
+
+#define PAGE_SELECT_0_START 0x22
+#define PAGE_SELECT_1_START 0x62
+#define PAGE_SELECT_2_START 0xA2
+
+//
+// INTERRUPT_STATUS_REG
+//
+
+#define PACKET_RECEIVED_NO_ERROR 0x01
+#define PACKET_TRANSMITTED_NO_ERROR 0x02
+#define RECEIVE_ERROR 0x04
+#define TRANSMIT_ERROR 0x08
+#define OVERWRITE_WARNING 0x10
+#define ISR_COUNTER_OVERFLOW 0x20
+#define REMOTE_DMA_COMPLETE 0x40
+#define RESET_DONE 0x80
+
+
+
+//
+// INTERRUPT_MASK_REG
+//
+
+#define PACKET_RECEIVE_ENABLE 0x01
+#define PACKET_TRANSMIT_ENABLE 0x02
+#define RECEIVE_ERROR_ENABLE 0x04
+#define TRANSMIT_ERROR_ENABLE 0x08
+#define OVERWRITE_WARNING_ENABLE 0x10
+#define COUNTER_OVERFLOW_ENABLE 0x20
+#define REMOTE_DMA_COMPLETE_ENABLE 0x40
+
+
+//
+// DATA_CONFIG_REG
+//
+
+#define WORD_TRANSFER_SELECT 0x01
+#define BYTE_ORDER_SELECT 0x02
+#define LONG_ADDRESS_SELECT 0x04
+#define BURST_DMA_SELECT 0x08
+#define AUTO_INITIALIZE_REMOTE 0x10
+#define RECEIVE_FIFO_THRESHOLD_2 0x00
+#define RECEIVE_FIFO_THRESHOLD_4 0x20
+#define RECEIVE_FIFO_THRESHOLD_8 0x40
+#define RECEIVE_FIFO_THRESHOLD_12 0x80
+
+//
+// TRANSMIT_CONFIG_REG
+//
+
+#define MANUAL_CRC_GENERATION 0x01
+#define LOOPBACK_MODE1 0x02 // mode 1, no loopback
+#define LOOPBACK_MODE2 0x04 // mode 2, loopback
+#define LOOPBACK_MODE3 0x06 // mode 3, no loopback
+#define AUTO_TRANSMIT_DISABLE 0x08
+#define COLLISION_OFFSET_ENABLE 0x10
+
+//
+// TRANSMIT_STATUS_REG
+//
+
+#define TRANSMIT_NO_ERROR 0x01
+#define TRANSMIT_COLLISION 0x04
+#define TRANSMIT_ABORT 0x08
+#define TRANSMIT_LOST_CARRIER 0x10
+#define TRANSMIT_FIFO_UNDERRUN 0x20
+#define TRANSMIT_HEARTBEAT 0x40
+#define TRANSMIT_OUT_OF_WINDOW 0x80
+
+
+//
+// RECEIVE_CONFIG_REG
+//
+
+#define SAVE_ERROR_PACKETS 0x01
+#define SAVE_RUNT_PACKETS 0x02
+#define SAVE_BROADCAST_PACKETS 0x04
+#define SAVE_MULTICAST_PACKETS 0x08
+#define PROMISCUOUS_MODE 0x10
+#define MONITOR_MODE 0x20
+
+//
+// RECEIVE_STATUS_REG
+
+#define RECEIVE_NO_ERROR 0x01
+#define RECEIVE_CRC_ERROR 0x02
+#define RECEIVE_ALIGNMENT_ERROR 0x04
+#define RECEIVE_FIFO_UNDERRUN 0x08
+#define RECEIVE_MISSED_PACKET 0x10
+#define RECEIVE_PHYSICAL_ADDRESS 0x20
+#define RECEIVE_DISABLED 0x40
+#define RECEIVE_DEFERRING 0x80
+
+
diff --git a/private/ntos/ndis/wd/wdsft.h b/private/ntos/ndis/wd/wdsft.h
new file mode 100644
index 000000000..3ea3f8d17
--- /dev/null
+++ b/private/ntos/ndis/wd/wdsft.h
@@ -0,0 +1,852 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ wdsft.h
+
+Abstract:
+
+ The main header for an Western Digital MAC driver.
+
+Author:
+
+ Anthony V. Ercolano (tonye) creation-date 19-Jun-1990 (Driver Model)
+
+ Sean Selitrennikoff (seanse) original WD code.
+
+Environment:
+
+ This driver is expected to work in DOS, OS2 and NT at the equivalent
+ of kernal mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Notes:
+
+ optional-notes
+
+Revision History:
+
+
+--*/
+
+#ifndef _WDSFT_
+#define _WDSFT_
+
+#define WD_NDIS_MAJOR_VERSION 3
+#define WD_NDIS_MINOR_VERSION 0
+
+//
+// This macro is used along with the flags to selectively
+// turn on debugging.
+//
+
+#if DBG
+
+#define IF_WDDEBUG(f) if (WdDebugFlag & (f))
+
+extern ULONG WdDebugFlag;
+
+#define WD_DEBUG_LOUD 0x00000001 // debugging info
+#define WD_DEBUG_VERY_LOUD 0x00000002 // excessive debugging info
+#define WD_DEBUG_LOG 0x00000004 // enable WdLog
+#define WD_DEBUG_CHECK_DUP_SENDS 0x00000008 // check for duplicate sends
+#define WD_DEBUG_TRACK_PACKET_LENS 0x00000010 // track directed packet lens
+#define WD_DEBUG_WORKAROUND1 0x00000020 // drop DFR/DIS packets
+#define WD_DEBUG_CARD_BAD 0x00000040 // dump data if CARD_BAD
+#define WD_DEBUG_CARD_TESTS 0x00000080 // print reason for failing
+
+
+
+//
+// Macro for deciding whether to dump lots of debugging information.
+//
+
+#define IF_LOUD(A) IF_WDDEBUG( WD_DEBUG_LOUD ) { A }
+#define IF_VERY_LOUD(A) IF_WDDEBUG( WD_DEBUG_VERY_LOUD ) { A }
+
+#else
+
+#define IF_LOUD(A)
+#define IF_VERY_LOUD(A)
+
+#endif
+
+
+//
+// Macros for services that differ between DOS and NT, we may consider adding these
+// into the NDIS spec.
+//
+
+
+//
+// controls the number of transmit buffers on the packet.
+// Choices are 1 or 2.
+//
+
+#define DEFAULT_NUMBUFFERS 2
+
+
+//
+// Macros for moving memory around
+//
+
+#define WD_MOVE_MEM(dest,src,size) NdisMoveMemory(dest,src,size)
+#define WD_MOVE_MEM_TO_SHARED_RAM(dest,src,size) NdisMoveToMappedMemory(dest,src,size)
+#define WD_MOVE_SHARED_RAM_TO_MEM(dest,src,size) NdisMoveFromMappedMemory(dest,src,size)
+
+#define WD_MOVE_DWORD_TO_SHARED_RAM(dest,src) NdisWriteRegisterUlong((PULONG)(dest),(ULONG)(src))
+#define WD_MOVE_SHARED_RAM_TO_DWORD(dest,src) NdisReadRegisterUlong((PULONG)(src),(PULONG)(dest))
+
+#define WD_MOVE_UCHAR_TO_SHARED_RAM(dest,src) NdisWriteRegisterUchar((PUCHAR)(dest),(UCHAR)(src))
+#define WD_MOVE_SHARED_RAM_TO_UCHAR(dest,src) NdisReadRegisterUchar((PUCHAR)(src),(PUCHAR)(dest))
+
+#define WD_MOVE_USHORT_TO_SHARED_RAM(dest,src) NdisWriteRegisterUshort((PUSHORT)(dest),(USHORT)(src))
+#define WD_MOVE_SHARED_RAM_TO_USHORT(dest,src) NdisReadRegisterUshort((PUSHORT)(src),(PUSHORT)(dest))
+
+
+
+
+//
+// A broadcast address (for comparing with other addresses).
+//
+
+extern UCHAR WdBroadcastAddress[];
+
+
+//
+// Number of bytes in an ethernet header
+//
+
+#define WD_HEADER_SIZE 14
+
+
+//
+// Number of bytes allowed in a lookahead (max)
+//
+
+#define WD_MAX_LOOKAHEAD (252 - WD_HEADER_SIZE)
+
+
+//
+// Buffer page size - WD MUST BE 256!!! Internal counters on the card
+// depend on it.
+//
+
+#define WD_BUFFER_PAGE_SIZE 256
+
+
+//
+// Only have one of these structures.
+//
+
+typedef struct _MAC_BLOCK {
+
+ //
+ // NDIS wrapper information.
+ //
+
+ NDIS_HANDLE NdisMacHandle; // returned from NdisRegisterMac
+ NDIS_HANDLE NdisWrapperHandle; // returned from NdisInitializeWrapper
+ NDIS_MAC_CHARACTERISTICS MacCharacteristics;
+
+ //
+ // Adapters registered for this MAC.
+ //
+
+ UINT NumAdapters;
+ struct _WD_ADAPTER * AdapterQueue;
+ NDIS_SPIN_LOCK SpinLock; // guards NumAdapter and AdapterQueue
+
+ //
+ // driver object.
+ //
+
+ PDRIVER_OBJECT DriverObject;
+
+ BOOLEAN Unloading;
+
+} MAC_BLOCK, * PMAC_BLOCK;
+
+
+
+
+
+
+//
+// One of these structures per adapter registered.
+//
+
+typedef struct _WD_ADAPTER {
+
+ //
+ // Adapter structure for LMI.
+ // This must occur first in the adapter structure.
+ //
+
+ Adapter_Struc LMAdapter;
+
+ //
+ // Spin lock for adapter structure
+ //
+ NDIS_SPIN_LOCK Lock;
+
+
+ //
+ // Links with our MAC.
+ //
+
+ PMAC_BLOCK MacBlock;
+ struct _WD_ADAPTER * NextAdapter; // used by MacBlock->OpenQueue
+
+ //
+ // Opens for this adapter.
+ //
+
+ struct _WD_OPEN * OpenQueue;
+
+
+ //
+ // Number of references to the adapter.
+ //
+ ULONG References;
+
+ UINT MulticastListMax;
+
+ //
+ // Transmit queue.
+ //
+
+ PNDIS_PACKET XmitQueue; // packets waiting to be transmitted
+ PNDIS_PACKET XmitQTail;
+
+ PNDIS_PACKET PacketsOnCard; // List of packets that the card is
+ // is currently transmitting
+ PNDIS_PACKET PacketsOnCardTail;
+
+ //
+ // Loopback queue;
+ //
+
+ PNDIS_PACKET LoopbackQueue; // directed packets waiting to be received
+ PNDIS_PACKET LoopbackQTail;
+ PNDIS_PACKET IndicatingPacket;
+ BOOLEAN IndicatedAPacket;
+
+ //
+ // These are for the current packet being indicated.
+ //
+
+ UCHAR PacketHeader[4]; // the NIC appended header
+ UINT PacketLen; // the overall length of the packet
+
+
+
+ //
+ // Statistics used by Set/QueryInformation.
+ //
+
+ ULONG FramesXmitGood; // Good Frames Transmitted
+ ULONG FramesRcvGood; // Good Frames Received
+
+ ULONG FramesXmitBad; // Bad Frames Transmitted
+ ULONG FramesXmitOneCollision; // Frames Transmitted with one collision
+ ULONG FramesXmitManyCollisions; // Frames Transmitted with > 1 collision
+ ULONG FramesXmitDeferred; // Frames where xmit was deferred
+ ULONG FramesXmitOverWrite; // Frames where xmit was overwritten
+ ULONG FramesXmitHeartbeat; // Frames lost heartbeat
+ ULONG FramesXmitUnderruns; // Frames where FIFO underran
+
+ ULONG FrameAlignmentErrors; // FAE errors counted
+ ULONG CrcErrors; // CRC errors counted
+ ULONG MissedPackets; // missed packet counted
+ ULONG TooBig; // received packets too large counted
+ ULONG Overruns; // received packets with FIFO overrun
+
+ //
+ // Reset information.
+ //
+
+ BOOLEAN HardwareFailure; // Did the hardware fail in some way
+ BOOLEAN ResetRequested; // TRUE if a reset is needed
+ BOOLEAN ResetInProgress; // TRUE if a reset is in progress
+ struct _WD_OPEN * ResetOpen; // who called WdReset
+
+ UINT ByteToWrite; // temp storage
+
+
+ //
+ // Look Ahead information.
+ //
+
+ ULONG MaxLookAhead;
+
+
+ //
+ // Handling deferred events
+ //
+
+ NDIS_TIMER DeferredTimer;
+ PVOID DeferredDpc;
+
+ UCHAR LookAhead[WD_MAX_LOOKAHEAD + WD_HEADER_SIZE];
+
+ BOOLEAN Removed;
+
+ //
+ // For handling missing interrupts (caused by user mis-configs)
+ //
+
+ PVOID WakeUpDpc;
+ NDIS_TIMER WakeUpTimer;
+ BOOLEAN WakeUpTimeout;
+ UCHAR WakeUpErrorCount;
+
+ BOOLEAN ProcessingDpc;
+} WD_ADAPTER, * PWD_ADAPTER;
+
+
+
+
+//
+// Given a MacBindingHandle this macro returns a pointer to the
+// WD_ADAPTER.
+//
+#define PWD_ADAPTER_FROM_BINDING_HANDLE(Handle) \
+ (((PWD_OPEN)(Handle))->Adapter)
+
+//
+// Given a MacContextHandle return the PWD_ADAPTER
+// it represents.
+//
+#define PWD_ADAPTER_FROM_CONTEXT_HANDLE(Handle) \
+ ((PWD_ADAPTER)(Handle))
+
+//
+// Given a pointer to a WD_ADAPTER return the
+// proper MacContextHandle.
+//
+#define CONTEXT_HANDLE_FROM_PWD_ADAPTER(Ptr) \
+ ((NDIS_HANDLE)(Ptr))
+
+
+//
+// Given a pointer to a WD_ADAPTER, return the
+// pointer to the LMAdapter.
+//
+#define Ptr_Adapter_Struc_FROM_PWD_ADAPTER(P)\
+ (&((P)->LMAdapter))
+
+//
+// Given a pointer to a LMAdapter, return the
+// pointer to the WD_ADAPTER.
+//
+#define PWD_ADAPTER_FROM_Ptr_Adapter_Struc(P)\
+ ((PWD_ADAPTER)(P))
+
+
+
+
+//
+// Macros to extract high and low bytes of a word.
+//
+
+#define MSB(Value) ((UCHAR)(((Value) >> 8) & 0xff))
+#define LSB(Value) ((UCHAR)((Value) & 0xff))
+
+
+//
+// One of these per open on an adapter.
+//
+
+typedef struct _WD_OPEN {
+
+ //
+ // NDIS wrapper information.
+ //
+
+ NDIS_HANDLE NdisBindingContext; // passed to MacOpenAdapter
+ PSTRING AddressingInformation; // not used currently
+
+ //
+ // Links to our adapter.
+ //
+
+ PWD_ADAPTER Adapter;
+ struct _WD_OPEN * NextOpen;
+
+ //
+ // Links to our MAC.
+ //
+
+ PMAC_BLOCK MacBlock; // faster than using AdapterBlock->MacBlock
+
+
+ //
+ // Handle of this adapter in the filter database.
+ //
+ NDIS_HANDLE NdisFilterHandle;
+
+ //
+ // Indication information
+ //
+
+ UINT LookAhead;
+
+ //
+ // Reset/Close information.
+ //
+
+ UINT ReferenceCount; // number of reasons this open can't close
+ BOOLEAN Closing; // is a close pending
+
+ NDIS_REQUEST CloseFilterRequest; // Holds Requests for pending close op
+ NDIS_REQUEST CloseAddressRequest;// Holds Requests for pending close op
+
+ UINT ProtOptionFlags;
+
+} WD_OPEN, * PWD_OPEN;
+
+
+//
+// This macro returns a pointer to a PWD_OPEN given a MacBindingHandle.
+//
+#define PWD_OPEN_FROM_BINDING_HANDLE(Handle) \
+ ((PWD_OPEN)(Handle))
+
+//
+// This macro returns a NDIS_HANDLE from a PWD_OPEN
+//
+#define BINDING_HANDLE_FROM_PWD_OPEN(Open) \
+ ((NDIS_HANDLE)(Open))
+
+
+
+
+
+//
+// What we map into the reserved section of a packet.
+// Cannot be more than 16 bytes (see ASSERT in wd.c).
+//
+
+typedef struct _MAC_RESERVED {
+ PNDIS_PACKET NextPacket; // used to link in the queues (4 bytes)
+ PWD_OPEN Open; // open that called WdSend (4 bytes)
+ BOOLEAN Loopback; // is this a loopback packet (1 byte)
+ BOOLEAN Directed; // is this a directed packet (1 byte)
+} MAC_RESERVED, * PMAC_RESERVED;
+
+
+//
+// These appear in the status field of MAC_RESERVED; they are
+// used because there is not enough room for a full NDIS_HANDLE.
+//
+
+#define RESERVED_SUCCESS ((USHORT)0)
+#define RESERVED_FAILURE ((USHORT)1)
+
+
+//
+// Retrieve the MAC_RESERVED structure from a packet.
+//
+
+#define RESERVED(Packet) ((PMAC_RESERVED)((Packet)->MacReserved))
+
+
+//
+// Procedures which log errors.
+//
+
+typedef enum _WD_PROC_ID {
+ openAdapter,
+ cardReset,
+ cardCopyDownPacket,
+ cardCopyDownBuffer,
+ cardCopyUp
+} WD_PROC_ID;
+
+
+#define WD_ERRMSG_CARD_SETUP (ULONG)0x01
+#define WD_ERRMSG_DATA_PORT_READY (ULONG)0x02
+#define WD_ERRMSG_MAX_OPENS (ULONG)0x03
+
+
+
+
+
+//
+// This macro will act a "epilogue" to every routine in the
+// *interface*. It will check whether any requests need
+// to defer their processing. It will also decrement the reference
+// count on the adapter. If the reference count is zero and there
+// is deferred work to do it will insert the interrupt processing
+// routine in the DPC queue.
+//
+// Note that we don't need to include checking for blocked receives
+// since blocked receives imply that there will eventually be an
+// interrupt.
+//
+// NOTE: This macro assumes that it is called with the lock acquired.
+//
+//
+#define WD_DO_DEFERRED(Adapter) \
+{ \
+ PWD_ADAPTER _A = (Adapter); \
+ _A->References--; \
+ if ((!_A->References) && \
+ ((_A->ResetRequested && (!_A->ProcessingDpc)) || \
+ ((_A->LoopbackQueue != NULL) && (!_A->ProcessingDpc)))) \
+ {\
+ NdisReleaseSpinLock(&_A->Lock); \
+ NdisSetTimer(&_A->DeferredTimer, 0);\
+ } else { \
+ NdisReleaseSpinLock(&_A->Lock); \
+ } \
+}
+
+
+
+
+//
+// Declarations for functions in wd.c.
+//
+
+NDIS_STATUS
+WdRegisterAdapter(
+ IN PWD_ADAPTER Adapter,
+ IN UINT NumBuffers,
+ IN UINT MulticastListMax,
+ IN UCHAR NodeAddress[ETH_LENGTH_OF_ADDRESS]
+ );
+
+
+BOOLEAN
+WdInterruptHandler(
+ IN PVOID ServiceContext // will be a pointer to the adapter block
+ );
+
+VOID
+WdInterruptDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+NDIS_STATUS
+WdOpenAdapter(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT NDIS_HANDLE * MacBindingHandle,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_HANDLE MacAdapterContext,
+ IN UINT OpenOptions,
+ IN PSTRING AddressingInformation OPTIONAL
+ );
+
+
+NDIS_STATUS
+WdCloseAdapter(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+
+BOOLEAN
+WdAddReference(
+ IN PWD_OPEN OpenP
+ );
+
+
+#define WdRemoveReference(_Open) \
+{ \
+ PWD_ADAPTER _Adapter = _Open->Adapter; \
+ PWD_OPEN _TmpOpen = _Open; \
+ --_TmpOpen->ReferenceCount; \
+ if (_TmpOpen->ReferenceCount == 0) { \
+ if (_TmpOpen == _Adapter->OpenQueue) { \
+ _Adapter->OpenQueue = _TmpOpen->NextOpen; \
+ } else { \
+ _TmpOpen = _Adapter->OpenQueue; \
+ while (_TmpOpen->NextOpen != _Open) { \
+ _TmpOpen = _TmpOpen->NextOpen; \
+ } \
+ _TmpOpen->NextOpen = _Open->NextOpen; \
+ _TmpOpen = _Open; \
+ } \
+ if (_TmpOpen->LookAhead == _Adapter->MaxLookAhead) {\
+ WdAdjustMaxLookAhead(_Adapter); \
+ } \
+ NdisReleaseSpinLock(&_Adapter->Lock); \
+ NdisCompleteCloseAdapter (_TmpOpen->NdisBindingContext, NDIS_STATUS_SUCCESS); \
+ NdisFreeMemory(_TmpOpen, sizeof(WD_OPEN), 0); \
+ NdisAcquireSpinLock(&_Adapter->Lock); \
+ if (_Adapter->OpenQueue == NULL) { \
+ NdisSynchronizeWithInterrupt( \
+ &(_Adapter->LMAdapter.NdisInterrupt), \
+ (PVOID)WdSyncCloseAdapter, \
+ (PVOID)(&(_Adapter->LMAdapter)) \
+ ); \
+ } \
+ } \
+}
+
+VOID
+WdAdjustMaxLookAhead(
+ IN PWD_ADAPTER Adapter
+ );
+
+NDIS_STATUS
+WdReset(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+NDIS_STATUS
+WdRequest(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+NDIS_STATUS
+WdQueryInformation(
+ IN PWD_ADAPTER Adapter,
+ IN PWD_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+NDIS_STATUS
+WdSetInformation(
+ IN PWD_ADAPTER Adapter,
+ IN PWD_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+NDIS_STATUS
+WdSetMulticastAddresses(
+ IN PWD_ADAPTER Adapter,
+ IN PWD_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT NumAddresses,
+ IN CHAR AddressList[][ETH_LENGTH_OF_ADDRESS]
+ );
+
+NDIS_STATUS
+WdSetPacketFilter(
+ IN PWD_ADAPTER Adapter,
+ IN PWD_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT PacketFilter
+ );
+
+NDIS_STATUS
+WdQueryGlobalStatistics(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+VOID
+WdUnload(
+ IN NDIS_HANDLE MacMacContext
+ );
+
+NDIS_STATUS
+WdAddAdapter(
+ IN NDIS_HANDLE NdisMacContext,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING AdaptName
+ );
+
+VOID
+WdRemoveAdapter(
+ IN PVOID MacAdapterContext
+ );
+
+VOID
+WdInterruptDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+NDIS_STATUS
+WdChangeMulticastAddresses(
+ IN UINT OldFilterCount,
+ IN CHAR OldAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN UINT NewFilterCount,
+ IN CHAR NewAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+NDIS_STATUS
+WdChangeFilterClasses(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+
+VOID
+WdCloseAction(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+
+UINT
+WdPacketSize(
+ IN PNDIS_PACKET Packet
+ );
+
+
+INDICATE_STATUS
+WdIndicatePacket(
+ IN PWD_ADAPTER Adapter
+ );
+
+
+NDIS_STATUS
+WdTransferData(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+
+BOOLEAN
+WdReceiveEvents(
+ IN PWD_ADAPTER Adapter
+ );
+
+BOOLEAN
+WdReceiveEventsDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID Context,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+VOID
+WdTransmitEvents(
+ IN PWD_ADAPTER Adapter
+ );
+
+NDIS_STATUS
+WdSend(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_PACKET Packet
+ );
+
+UINT
+WdCompareMemory(
+ IN PUCHAR String1,
+ IN PUCHAR String2,
+ IN UINT Length
+ );
+
+VOID
+WdSetLoopbackFlag(
+ IN PWD_ADAPTER Adapter,
+ IN PWD_OPEN Open,
+ IN OUT PNDIS_PACKET Packet
+ );
+
+VOID
+WdIndicateLoopbackPacket(
+ IN PWD_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet
+ );
+
+BOOLEAN
+WdSyncCloseAdapter(
+ IN PVOID Context
+ );
+
+BOOLEAN
+WdSyncSend(
+ IN PVOID Context
+ );
+
+BOOLEAN
+WdSyncSetMulticastAddress(
+ IN PVOID Context
+ );
+
+VOID
+WdWakeUpDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID Context,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+//++
+//
+// VOID
+// AddRefWhileHoldingSpinLock(
+// IN PWD_ADAPTER Adapter,
+// IN PWD_OPEN OpenP
+// )
+//
+// Routine Description:
+//
+// Adds a reference to an open. Similar to AddReference, but
+// called with Adapter->Lock held.
+//
+// Arguments:
+//
+// Adapter - The adapter block of OpenP.
+// OpenP - The open block that is being referenced.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define AddRefWhileHoldingSpinLock(Adapter, OpenP) { \
+ ++((OpenP)->ReferenceCount); \
+}
+
+
+
+//++
+//
+// BOOLEAN
+// WdAddressEqual(
+// IN UCHAR Address1[ETH_LENGTH_OF_ADDRESS],
+// IN UCHAR Address2[ETH_LENGTH_OF_ADDRESS]
+// )
+//
+// Routine Description:
+//
+// Compares two Ethernet addresses.
+//
+// Arguments:
+//
+// Address1 - The first address.
+// Address2 - The second address.
+//
+// Return Value:
+//
+// TRUE if the addresses are equal.
+// FALSE if they are not.
+//
+//--
+
+#define WdAddressEqual(Address1, Address2) \
+ ((Address1)[4] == (Address2)[4] && \
+ WdCompareMemory((Address1), (Address2), ETH_LENGTH_OF_ADDRESS) == 0)
+
+
+#endif // WdSFT
diff --git a/private/ntos/ndis/wd/wdumi.h b/private/ntos/ndis/wd/wdumi.h
new file mode 100644
index 000000000..60f752e73
--- /dev/null
+++ b/private/ntos/ndis/wd/wdumi.h
@@ -0,0 +1,45 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ wdlmi.h
+
+Abstract:
+
+ Upper MAC Interface functions for the NDIS 3.0 Western Digital driver.
+
+Author:
+
+ Sean Selitrennikoff (seanse) 15-Jan-92
+n
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+
+--*/
+
+
+
+#define UM_Delay(A) NdisStallExecution(A)
+
+#define UM_Interrupt(A) (SUCCESS)
+
+extern
+LM_STATUS
+UM_Send_Complete(
+ LM_STATUS Status,
+ Ptr_Adapter_Struc Adapt
+ );
+
+extern
+LM_STATUS
+UM_Receive_Packet(
+ ULONG PacketSize,
+ Ptr_Adapter_Struc Adapt
+ );
+